Merge tag 'suspend-to-idle-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull suspend-to-idle updates from Rafael Wysocki:
 "Suspend-to-idle timer quiescing support for v3.20-rc1

  Until now suspend-to-idle has not been able to save much more energy
  than runtime PM because of timer interrupts that periodically bring
  CPUs out of idle while they are waiting for a wakeup interrupt.  Of
  course, the timer interrupts are not wakeup ones, so the handling of
  them can be deferred until a real wakeup interrupt happens, but at the
  same time we don't want to mass-expire timers at that point.

  The solution is to suspend the entire timekeeping when the last CPU is
  entering an idle state and resume it when the first CPU goes out of
  idle.  That has to be done with care, though, so as to avoid accessing
  suspended clocksources etc.  end we need extra support from idle
  drivers for that.

  This series of commits adds support for quiescing timers during
  suspend-to-idle and adds the requisite callbacks to intel_idle and the
  ACPI cpuidle driver"

* tag 'suspend-to-idle-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI / idle: Implement ->enter_freeze callback routine
  intel_idle: Add ->enter_freeze callbacks
  PM / sleep: Make it possible to quiesce timers during suspend-to-idle
  timekeeping: Make it safe to use the fast timekeeper while suspended
  timekeeping: Pass readout base to update_fast_timekeeper()
  PM / sleep: Re-implement suspend-to-idle handling
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc
new file mode 100644
index 0000000..2f4a005
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc
@@ -0,0 +1,265 @@
+What:		/config/usb-gadget/gadget/functions/uvc.name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	UVC function directory
+
+		streaming_maxburst	- 0..15 (ss only)
+		streaming_maxpacket	- 1..1023 (fs), 1..3072 (hs/ss)
+		streaming_interval	- 1..16
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Control descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/class
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/ss
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Super speed control class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/class/fs
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Full speed control class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Terminal descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/output
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Output terminal descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Default output terminal descriptors
+
+		All attributes read only:
+		iTerminal	- index of string descriptor
+		bSourceID 	- id of the terminal to which this terminal
+				is connected
+		bAssocTerminal	- id of the input terminal to which this output
+				terminal is associated
+		wTerminalType	- terminal type
+		bTerminalID	- a non-zero id of this terminal
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Camera terminal descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Default camera terminal descriptors
+
+		All attributes read only:
+		bmControls		- bitmap specifying which controls are
+					supported for the video stream
+		wOcularFocalLength	- the value of Locular
+		wObjectiveFocalLengthMax- the value of Lmin
+		wObjectiveFocalLengthMin- the value of Lmax
+		iTerminal		- index of string descriptor
+		bAssocTerminal		- id of the output terminal to which
+					this terminal is connected
+		wTerminalType		- terminal type
+		bTerminalID		- a non-zero id of this terminal
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/processing
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Processing unit descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/processing/default
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Default processing unit descriptors
+
+		All attributes read only:
+		iProcessing	- index of string descriptor
+		bmControls	- bitmap specifying which controls are
+				supported for the video stream
+		wMaxMultiplier	- maximum digital magnification x100
+		bSourceID	- id of the terminal to which this unit is
+				connected
+		bUnitID		- a non-zero id of this unit
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/header
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Control header descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/control/header/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific control header descriptors
+
+dwClockFrequency
+bcdUVC
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Streaming descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Streaming class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Super speed streaming class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	High speed streaming class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Full speed streaming class descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Color matching descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Default color matching descriptors
+
+		All attributes read only:
+		bMatrixCoefficients	- matrix used to compute luma and
+					chroma values from the color primaries
+		bTransferCharacteristics- optoelectronic transfer
+					characteristic of the source picutre,
+					also called the gamma function
+		bColorPrimaries		- color primaries and the reference
+					white
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	MJPEG format descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific MJPEG format descriptors
+
+		All attributes read only,
+		except bmaControls and bDefaultFrameIndex:
+		bmaControls		- this format's data for bmaControls in
+					the streaming header
+		bmInterfaceFlags	- specifies interlace information,
+					read-only
+		bAspectRatioY		- the X dimension of the picture aspect
+					ratio, read-only
+		bAspectRatioX		- the Y dimension of the picture aspect
+					ratio, read-only
+		bmFlags			- characteristics of this format,
+					read-only
+		bDefaultFrameIndex	- optimum frame index for this stream
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific MJPEG frame descriptors
+
+		dwFrameInterval		- indicates how frame interval can be
+					programmed; a number of values
+					separated by newline can be specified
+		dwDefaultFrameInterval	- the frame interval the device would
+					like to use as default
+		dwMaxVideoFrameBufferSize- the maximum number of bytes the
+					compressor will produce for a video
+					frame or still image
+		dwMaxBitRate		- the maximum bit rate at the shortest
+					frame interval in bps
+		dwMinBitRate		- the minimum bit rate at the longest
+					frame interval in bps
+		wHeight			- height of decoded bitmap frame in px
+		wWidth			- width of decoded bitmam frame in px
+		bmCapabilities		- still image support, fixed frame-rate
+					support
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Uncompressed format descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific uncompressed format descriptors
+
+		bmaControls		- this format's data for bmaControls in
+					the streaming header
+		bmInterfaceFlags	- specifies interlace information,
+					read-only
+		bAspectRatioY		- the X dimension of the picture aspect
+					ratio, read-only
+		bAspectRatioX		- the Y dimension of the picture aspect
+					ratio, read-only
+		bDefaultFrameIndex	- optimum frame index for this stream
+		bBitsPerPixel		- number of bits per pixel used to
+					specify color in the decoded video
+					frame
+		guidFormat		- globally unique id used to identify
+					stream-encoding format
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific uncompressed frame descriptors
+
+		dwFrameInterval		- indicates how frame interval can be
+					programmed; a number of values
+					separated by newline can be specified
+		dwDefaultFrameInterval	- the frame interval the device would
+					like to use as default
+		dwMaxVideoFrameBufferSize- the maximum number of bytes the
+					compressor will produce for a video
+					frame or still image
+		dwMaxBitRate		- the maximum bit rate at the shortest
+					frame interval in bps
+		dwMinBitRate		- the minimum bit rate at the longest
+					frame interval in bps
+		wHeight			- height of decoded bitmap frame in px
+		wWidth			- width of decoded bitmam frame in px
+		bmCapabilities		- still image support, fixed frame-rate
+					support
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/header
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Streaming header descriptors
+
+What:		/config/usb-gadget/gadget/functions/uvc.name/streaming/header/name
+Date:		Dec 2014
+KernelVersion:	3.20
+Description:	Specific streaming header descriptors
+
+		All attributes read only:
+		bTriggerUsage		- how the host software will respond to
+					a hardware trigger interrupt event
+		bTriggerSupport		- flag specifying if hardware
+					triggering is supported
+		bStillCaptureMethod	- method of still image caputre
+					supported
+		bTerminalLink		- id of the output terminal to which
+					the video endpoint of this interface
+					is connected
+		bmInfo			- capabilities of this video streaming
+					interface
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 117521d..9a70c31 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -92,6 +92,18 @@
 		is required is a consistent labeling.  Units after application
 		of scale and offset are millivolts.
 
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
+KernelVersion:	3.17
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no bias removal etc.) current measurement from
+		channel Y. In special cases where the channel does not
+		correspond to externally available input one of the named
+		versions may be used. The number must always be specified and
+		unique to allow association with event codes. Units after
+		application of scale and offset are milliamps.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
 KernelVersion:	3.2
 Contact:	linux-iio@vger.kernel.org
@@ -234,6 +246,8 @@
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_tempY_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_temp_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@@ -262,9 +276,14 @@
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_energy_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_distance_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
@@ -276,6 +295,7 @@
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressure_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -323,6 +343,44 @@
 		production inaccuracies).  If shared across all channels,
 		<type>_calibscale is used.
 
+What:		/sys/bus/iio/devices/iio:deviceX/in_activity_calibgender
+What:		/sys/bus/iio/devices/iio:deviceX/in_energy_calibgender
+What:		/sys/bus/iio/devices/iio:deviceX/in_distance_calibgender
+What:		/sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Gender of the user (e.g.: male, female) used by some pedometers
+		to compute the stride length, distance, speed and activity
+		type.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_activity_calibgender_available
+What:		/sys/bus/iio/devices/iio:deviceX/in_energy_calibgender_available
+What:		/sys/bus/iio/devices/iio:deviceX/in_distance_calibgender_available
+What:		/sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender_available
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Lists all available gender values (e.g.: male, female).
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_activity_calibheight
+What:		/sys/bus/iio/devices/iio:deviceX/in_energy_calibheight
+What:		/sys/bus/iio/devices/iio:deviceX/in_distance_calibheight
+What:		/sys/bus/iio/devices/iio:deviceX/in_velocity_calibheight
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Height of the user (in meters) used by some pedometers
+		to compute the stride length, distance, speed and activity
+		type.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_energy_calibweight
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Weight of the user (in kg). It is needed by some pedometers
+		to compute the calories burnt by the user.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
 What:		/sys/.../iio:deviceX/in_voltageX_scale_available
 What:		/sys/.../iio:deviceX/in_voltage-voltage_scale_available
@@ -783,6 +841,14 @@
 What:		/sys/.../events/in_accel_x&y&z_mag_falling_period
 What:		/sys/.../events/in_intensity0_thresh_period
 What:		/sys/.../events/in_proximity0_thresh_period
+What:		/sys/.../events/in_activity_still_thresh_rising_period
+What:		/sys/.../events/in_activity_still_thresh_falling_period
+What:		/sys/.../events/in_activity_walking_thresh_rising_period
+What:		/sys/.../events/in_activity_walking_thresh_falling_period
+What:		/sys/.../events/in_activity_jogging_thresh_rising_period
+What:		/sys/.../events/in_activity_jogging_thresh_falling_period
+What:		/sys/.../events/in_activity_running_thresh_rising_period
+What:		/sys/.../events/in_activity_running_thresh_falling_period
 KernelVersion:	2.6.37
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -790,6 +856,40 @@
 		met before an event is generated. If direction is not
 		specified then this period applies to both directions.
 
+What:		/sys/.../events/in_activity_still_thresh_rising_en
+What:		/sys/.../events/in_activity_still_thresh_falling_en
+What:		/sys/.../events/in_activity_walking_thresh_rising_en
+What:		/sys/.../events/in_activity_walking_thresh_falling_en
+What:		/sys/.../events/in_activity_jogging_thresh_rising_en
+What:		/sys/.../events/in_activity_jogging_thresh_falling_en
+What:		/sys/.../events/in_activity_running_thresh_rising_en
+What:		/sys/.../events/in_activity_running_thresh_falling_en
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Enables or disables activitity events. Depending on direction
+		an event is generated when sensor ENTERS or LEAVES a given state.
+
+What:		/sys/.../events/in_activity_still_thresh_rising_value
+What:		/sys/.../events/in_activity_still_thresh_falling_value
+What:		/sys/.../events/in_activity_walking_thresh_rising_value
+What:		/sys/.../events/in_activity_walking_thresh_falling_value
+What:		/sys/.../events/in_activity_jogging_thresh_rising_value
+What:		/sys/.../events/in_activity_jogging_thresh_falling_value
+What:		/sys/.../events/in_activity_running_thresh_rising_value
+What:		/sys/.../events/in_activity_running_thresh_falling_value
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Confidence value (in units as percentage) to be used
+		for deciding when an event should be generated. E.g for
+		running: If the confidence value reported by the sensor
+		is greater than in_activity_running_thresh_rising_value
+		then the sensor ENTERS running state. Conversely, if the
+		confidence value reported by the sensor is lower than
+		in_activity_running_thresh_falling_value then the sensor
+		is LEAVING running state.
+
 What:		/sys/.../iio:deviceX/events/in_accel_mag_en
 What:		/sys/.../iio:deviceX/events/in_accel_mag_rising_en
 What:		/sys/.../iio:deviceX/events/in_accel_mag_falling_en
@@ -822,6 +922,25 @@
 		number or direction is not specified, applies to all channels of
 		this type.
 
+What:		/sys/.../events/in_steps_change_en
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Event generated when channel passes a threshold on the absolute
+		change in value. E.g. for steps: a step change event is
+		generated each time the user takes N steps, where N is set using
+		in_steps_change_value.
+
+What:		/sys/.../events/in_steps_change_value
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the value of change threshold that the
+		device is comparing against for the events enabled by
+		<type>[Y][_name]_roc[_rising|falling|]_en. E.g. for steps:
+		if set to 3, a step change event will be generated every 3
+		steps.
+
 What:		/sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
@@ -956,6 +1075,16 @@
 		and the relevant _type attributes to establish the data storage
 		format.
 
+What:		/sys/.../iio:deviceX/in_activity_still_input
+What:		/sys/.../iio:deviceX/in_activity_walking_input
+What:		/sys/.../iio:deviceX/in_activity_jogging_input
+What:		/sys/.../iio:deviceX/in_activity_running_input
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the confidence for an activity
+		expressed in units as percentage.
+
 What:		/sys/.../iio:deviceX/in_anglvel_z_quadrature_correction_raw
 KernelVersion:	2.6.38
 Contact:	linux-iio@vger.kernel.org
@@ -973,6 +1102,24 @@
 		For a list of available output power modes read
 		in_accel_power_mode_available.
 
+What:		/sys/.../iio:deviceX/in_energy_input
+What:		/sys/.../iio:deviceX/in_energy_raw
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the energy value reported by the
+		device (e.g.: human activity sensors report energy burnt by the
+		user). Units after application of scale are Joules.
+
+What:		/sys/.../iio:deviceX/in_distance_input
+What:		/sys/.../iio:deviceX/in_distance_raw
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the distance covered by the user
+		since the last reboot while activated. Units after application
+		of scale are meters.
+
 What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
 KernelVersion:	3.4.0
 Contact:	linux-iio@vger.kernel.org
@@ -992,7 +1139,9 @@
 		reflectivity of infrared or ultrasound emitted.
 		Often these sensors are unit less and as such conversion
 		to SI units is not possible.  Where it is, the units should
-		be meters.
+		be meters.  If such a conversion is not possible, the reported
+		values should behave in the same way as a distance, i.e. lower
+		values indicate something is closer to the sensor.
 
 What:		/sys/.../iio:deviceX/in_illuminanceY_input
 What:		/sys/.../iio:deviceX/in_illuminanceY_raw
@@ -1024,6 +1173,12 @@
 		This attribute is used to get/set the integration time in
 		seconds.
 
+What:		/sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Number of seconds in which to compute speed.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_rot_quaternion_raw
 KernelVersion:	3.15
 Contact:	linux-iio@vger.kernel.org
@@ -1051,3 +1206,46 @@
 		after application of scale and offset. If no offset or scale is
 		present, output should be considered as processed with the
 		unit in milliamps.
+
+What:		/sys/.../iio:deviceX/in_energy_en
+What:		/sys/.../iio:deviceX/in_distance_en
+What:		/sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en
+What:		/sys/.../iio:deviceX/in_steps_en
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Activates a device feature that runs in firmware/hardware.
+		E.g. for steps: the pedometer saves power while not used;
+		when activated, it will count the steps taken by the user in
+		firmware and export them through in_steps_input.
+
+What:		/sys/.../iio:deviceX/in_steps_input
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the number of steps taken by the user
+		since the last reboot while activated.
+
+What:		/sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_input
+What:		/sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_raw
+KernelVersion:	3.19
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to read the current speed value of the
+		user (which is the norm or magnitude of the velocity vector).
+		Units after application of scale are m/s.
+
+What:		/sys/.../iio:deviceX/in_steps_debounce_count
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the number of steps that must occur within
+		in_steps_filter_debounce_time for the pedometer to decide the
+		consumer is making steps.
+
+What:		/sys/.../iio:deviceX/in_steps_debounce_time
+KernelVersion:	3.20
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies number of seconds in which we compute the steps
+		that occur in order to decide if the consumer is making steps.
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 4b592ff..03f1985 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -239,6 +239,14 @@
               Driver supports dedicated render nodes.
             </para></listitem>
           </varlistentry>
+          <varlistentry>
+            <term>DRIVER_ATOMIC</term>
+            <listitem><para>
+              Driver supports atomic properties.  In this case the driver
+              must implement appropriate obj->atomic_get_property() vfuncs
+              for any modeset objects with driver specific properties.
+            </para></listitem>
+          </varlistentry>
         </variablelist>
       </sect3>
       <sect3>
@@ -1377,7 +1385,7 @@
       <itemizedlist>
         <listitem>
         DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.  Primary
-        planes are the planes operated upon by by CRTC modesetting and flipping
+        planes are the planes operated upon by CRTC modesetting and flipping
         operations described in <xref linkend="drm-kms-crtcops"/>.
         </listitem>
         <listitem>
@@ -2362,6 +2370,7 @@
     </sect2>
     <sect2>
       <title>Modeset Helper Functions Reference</title>
+!Iinclude/drm/drm_crtc_helper.h
 !Edrivers/gpu/drm/drm_crtc_helper.c
 !Pdrivers/gpu/drm/drm_crtc_helper.c overview
     </sect2>
@@ -2564,8 +2573,8 @@
 	<td valign="top" >Description/Restrictions</td>
 	</tr>
 	<tr>
-	<td rowspan="25" valign="top" >DRM</td>
-	<td rowspan="4" valign="top" >Generic</td>
+	<td rowspan="36" valign="top" >DRM</td>
+	<td rowspan="5" valign="top" >Connector</td>
 	<td valign="top" >“EDID”</td>
 	<td valign="top" >BLOB | IMMUTABLE</td>
 	<td valign="top" >0</td>
@@ -2594,7 +2603,14 @@
 	<td valign="top" >Contains tiling information for a connector.</td>
 	</tr>
 	<tr>
-	<td rowspan="1" valign="top" >Plane</td>
+	<td valign="top" >“CRTC_ID”</td>
+	<td valign="top" >OBJECT</td>
+	<td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+	<td valign="top" >Connector</td>
+	<td valign="top" >CRTC that connector is attached to (atomic)</td>
+	</tr>
+	<tr>
+	<td rowspan="11" valign="top" >Plane</td>
 	<td valign="top" >“type”</td>
 	<td valign="top" >ENUM | IMMUTABLE</td>
 	<td valign="top" >{ "Overlay", "Primary", "Cursor" }</td>
@@ -2602,6 +2618,76 @@
 	<td valign="top" >Plane type</td>
 	</tr>
 	<tr>
+	<td valign="top" >“SRC_X”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“SRC_Y”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“SRC_W”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“SRC_H”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CRTC_X”</td>
+	<td valign="top" >SIGNED_RANGE</td>
+	<td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CRTC_Y”</td>
+	<td valign="top" >SIGNED_RANGE</td>
+	<td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CRTC_W”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout CRTC (destination) width (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CRTC_H”</td>
+	<td valign="top" >RANGE</td>
+	<td valign="top" >Min=0, Max=UINT_MAX</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout CRTC (destination) height (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“FB_ID”</td>
+	<td valign="top" >OBJECT</td>
+	<td valign="top" >DRM_MODE_OBJECT_FB</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >Scanout framebuffer (atomic)</td>
+	</tr>
+	<tr>
+	<td valign="top" >“CRTC_ID”</td>
+	<td valign="top" >OBJECT</td>
+	<td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+	<td valign="top" >Plane</td>
+	<td valign="top" >CRTC that plane is attached to (atomic)</td>
+	</tr>
+	<tr>
 	<td rowspan="2" valign="top" >DVI-I</td>
 	<td valign="top" >“subconnector”</td>
 	<td valign="top" >ENUM</td>
@@ -3883,6 +3969,7 @@
         <title>Runtime Power Management</title>
 !Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
 !Idrivers/gpu/drm/i915/intel_runtime_pm.c
+!Idrivers/gpu/drm/i915/intel_uncore.c
       </sect2>
       <sect2>
         <title>Interrupt Handling</title>
@@ -3932,6 +4019,11 @@
         </para>
       </sect2>
       <sect2>
+        <title>Atomic Plane Helpers</title>
+!Pdrivers/gpu/drm/i915/intel_atomic_plane.c atomic plane helpers
+!Idrivers/gpu/drm/i915/intel_atomic_plane.c
+      </sect2>
+      <sect2>
         <title>Output Probing</title>
         <para>
 	  This section covers output probing and related infrastructure like the
@@ -3951,6 +4043,11 @@
 !Idrivers/gpu/drm/i915/intel_psr.c
       </sect2>
       <sect2>
+	<title>Frame Buffer Compression (FBC)</title>
+!Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
+!Idrivers/gpu/drm/i915/intel_fbc.c
+      </sect2>
+      <sect2>
         <title>DPIO</title>
 !Pdrivers/gpu/drm/i915/i915_reg.h DPIO
 	<table id="dpiox2">
@@ -4054,10 +4151,31 @@
 !Idrivers/gpu/drm/i915/i915_cmd_parser.c
       </sect2>
       <sect2>
+        <title>Batchbuffer Pools</title>
+!Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool
+!Idrivers/gpu/drm/i915/i915_gem_batch_pool.c
+      </sect2>
+      <sect2>
         <title>Logical Rings, Logical Ring Contexts and Execlists</title>
 !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
 !Idrivers/gpu/drm/i915/intel_lrc.c
       </sect2>
+      <sect2>
+        <title>Global GTT views</title>
+!Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
+!Idrivers/gpu/drm/i915/i915_gem_gtt.c
+      </sect2>
+      <sect2>
+        <title>Buffer Object Eviction</title>
+	<para>
+	  This section documents the interface function for evicting buffer
+	  objects to make space available in the virtual gpu address spaces.
+	  Note that this is mostly orthogonal to shrinking buffer objects
+	  caches, which has the goal to make main memory (shared with the gpu
+	  through the unified memory architecture) available.
+	</para>
+!Idrivers/gpu/drm/i915/i915_gem_evict.c
+      </sect2>
     </sect1>
 
     <sect1>
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index 1fdc246..cd0e452 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -719,7 +719,7 @@
 	</para>
 </sect1>
 
-<sect1 id="using uio_dmem_genirq">
+<sect1 id="using-uio_dmem_genirq">
 <title>Using uio_dmem_genirq for platform devices</title>
 	<para>
 	In addition to statically allocated memory ranges, they may also be
@@ -746,16 +746,16 @@
 	following elements:
 	</para>
 	<itemizedlist>
-	<listitem><varname>struct uio_info uioinfo</varname>: The same
+	<listitem><para><varname>struct uio_info uioinfo</varname>: The same
 	structure used as the  <varname>uio_pdrv_genirq</varname> platform
-	data</listitem>
-	<listitem><varname>unsigned int *dynamic_region_sizes</varname>:
+	data</para></listitem>
+	<listitem><para><varname>unsigned int *dynamic_region_sizes</varname>:
 	Pointer to list of sizes of dynamic memory regions to be mapped into
 	user space.
-	</listitem>
-	<listitem><varname>unsigned int num_dynamic_regions</varname>:
+	</para></listitem>
+	<listitem><para><varname>unsigned int num_dynamic_regions</varname>:
 	Number of elements in <varname>dynamic_region_sizes</varname> array.
-	</listitem>
+	</para></listitem>
 	</itemizedlist>
 	<para>
 	The dynamic regions defined in the platform data will be appended to
diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README
new file mode 100644
index 0000000..c53a19b
--- /dev/null
+++ b/Documentation/arm/Atmel/README
@@ -0,0 +1,124 @@
+ARM Atmel SoCs (aka AT91)
+=========================
+
+
+Introduction
+------------
+This document gives useful information about the ARM Atmel SoCs that are
+currently supported in Linux Mainline (you know, the one on kernel.org).
+
+It is important to note that the Atmel | SMART ARM-based MPU product line is
+historically named "AT91" or "at91" throughout the Linux kernel development
+process even if this product prefix has completely disappeared from the
+official Atmel product name. Anyway, files, directories, git trees,
+git branches/tags and email subject always contain this "at91" sub-string.
+
+
+AT91 SoCs
+---------
+Documentation and detailled datasheet for each product are available on
+the Atmel website: http://www.atmel.com.
+
+  Flavors:
+    * ARM 920 based SoC
+      - at91rm9200
+        + Datasheet
+          http://www.atmel.com/Images/doc1768.pdf
+
+    * ARM 926 based SoCs
+      - at91sam9260
+        + Datasheet
+          http://www.atmel.com/Images/doc6221.pdf
+
+      - at91sam9xe
+        + Datasheet
+          http://www.atmel.com/Images/Atmel-6254-32-bit-ARM926EJ-S-Embedded-Microprocessor-SAM9XE_Datasheet.pdf
+
+      - at91sam9261
+        + Datasheet
+          http://www.atmel.com/Images/doc6062.pdf
+
+      - at91sam9263
+        + Datasheet
+          http://www.atmel.com/Images/Atmel_6249_32-bit-ARM926EJ-S-Microcontroller_SAM9263_Datasheet.pdf
+
+      - at91sam9rl
+        + Datasheet
+          http://www.atmel.com/Images/doc6289.pdf
+
+      - at91sam9g20
+        + Datasheet
+          http://www.atmel.com/Images/doc6384.pdf
+
+      - at91sam9g45 family
+        - at91sam9g45
+        - at91sam9g46
+        - at91sam9m10
+        - at91sam9m11 (device superset)
+        + Datasheet
+          http://www.atmel.com/Images/Atmel-6437-32-bit-ARM926-Embedded-Microprocessor-SAM9M11_Datasheet.pdf
+
+      - at91sam9x5 family (aka "The 5 series")
+        - at91sam9g15
+        - at91sam9g25
+        - at91sam9g35
+        - at91sam9x25
+        - at91sam9x35
+        + Datasheet (can be considered as covering the whole family)
+          http://www.atmel.com/Images/Atmel_11055_32-bit-ARM926EJ-S-Microcontroller_SAM9X35_Datasheet.pdf
+
+      - at91sam9n12
+        + Datasheet
+          http://www.atmel.com/Images/Atmel_11063_32-bit-ARM926EJ-S-Microcontroller_SAM9N12CN11CN12_Datasheet.pdf
+
+    * ARM Cortex-A5 based SoCs
+      - sama5d3 family
+        - sama5d31
+        - sama5d33
+        - sama5d34
+        - sama5d35
+        - sama5d36 (device superset)
+        + Datasheet
+          http://www.atmel.com/Images/Atmel-11121-32-bit-Cortex-A5-Microcontroller-SAMA5D3_Datasheet.pdf
+
+    * ARM Cortex-A5 + NEON based SoCs
+      - sama5d4 family
+        - sama5d41
+        - sama5d42
+        - sama5d43
+        - sama5d44 (device superset)
+        + Datasheet
+          http://www.atmel.com/Images/Atmel-11238-32-bit-Cortex-A5-Microcontroller-SAMA5D4_Datasheet.pdf
+
+
+Linux kernel information
+------------------------
+Linux kernel mach directory: arch/arm/mach-at91
+MAINTAINERS entry is: "ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES"
+
+
+Device Tree for AT91 SoCs and boards
+------------------------------------
+All AT91 SoCs are converted to Device Tree. Since Linux 3.19, these products
+must use this method to boot the Linux kernel.
+
+Work In Progress statement:
+Device Tree files and Device Tree bindings that apply to AT91 SoCs and boards are
+considered as "Unstable". To be completely clear, any at91 binding can change at
+any time. So, be sure to use a Device Tree Binary and a Kernel Image generated from
+the same source tree.
+Please refer to the Documentation/devicetree/bindings/ABI.txt file for a
+definition of a "Stable" binding/ABI.
+This statement will be removed by AT91 MAINTAINERS when appropriate.
+
+Naming conventions and best practice:
+- SoCs Device Tree Source Include files are named after the official name of
+  the product (at91sam9g20.dtsi or sama5d33.dtsi for instance).
+- Device Tree Source Include files (.dtsi) are used to collect common nodes that can be
+  shared across SoCs or boards (sama5d3.dtsi or at91sam9x5cm.dtsi for instance).
+  When collecting nodes for a particular peripheral or topic, the identifier have to
+  be placed at the end of the file name, separated with a "_" (at91sam9x5_can.dtsi
+  or sama5d3_gmac.dtsi for example).
+- board Device Tree Source files (.dts) are prefixed by the string "at91-" so
+  that they can be identified easily. Note that some files are historical exceptions
+  to this rule (sama5d3[13456]ek.dts, usb_a9g20.dts or animeo_ip.dts for example).
diff --git a/Documentation/arm/Samsung-S3C24XX/DMA.txt b/Documentation/arm/Samsung-S3C24XX/DMA.txt
deleted file mode 100644
index 3ed8238..0000000
--- a/Documentation/arm/Samsung-S3C24XX/DMA.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-			S3C2410 DMA
-			===========
-
-Introduction
-------------
-
-   The kernel provides an interface to manage DMA transfers
-   using the DMA channels in the CPU, so that the central
-   duty of managing channel mappings, and programming the
-   channel generators is in one place.
-
-
-DMA Channel Ordering
---------------------
-
-   Many of the range do not have connections for the DMA
-   channels to all sources, which means that some devices
-   have a restricted number of channels that can be used.
-
-   To allow flexibility for each CPU type and board, the
-   DMA code can be given a DMA ordering structure which
-   allows the order of channel search to be specified, as
-   well as allowing the prohibition of certain claims.
-
-   struct s3c24xx_dma_order has a list of channels, and
-   each channel within has a slot for a list of DMA
-   channel numbers. The slots are searched in order for
-   the presence of a DMA channel number with DMA_CH_VALID
-   or-ed in.
-
-   If the order has the flag DMA_CH_NEVER set, then after
-   checking the channel list, the system will return no
-   found channel, thus denying the request.
-
-   A board support file can call s3c24xx_dma_order_set()
-   to register a complete ordering set. The routine will
-   copy the data, so the original can be discarded with
-   __initdata.
-
-
-Authour
--------
-
-Ben Dooks,
-Copyright (c) 2007 Ben Dooks, Simtec Electronics
-Licensed under the GPL v2
diff --git a/Documentation/arm/sti/stih418-overview.txt b/Documentation/arm/sti/stih418-overview.txt
new file mode 100644
index 0000000..1cd8fc8
--- /dev/null
+++ b/Documentation/arm/sti/stih418-overview.txt
@@ -0,0 +1,20 @@
+			STiH418 Overview
+			================
+
+Introduction
+------------
+
+    The STiH418 is the new generation of SoC for UHDp60 set-top boxes
+    and server/connected client application for satellite, cable, terrestrial
+    and IP-STB markets.
+
+    Features
+    - ARM Cortex-A9 1.5 GHz quad core CPU (28nm)
+    - SATA2, USB 3.0, PCIe, Gbit Ethernet
+    - HEVC L5.1 Main 10
+    - VP9
+
+  Document Author
+  ---------------
+
+  Maxime Coquelin <maxime.coquelin@st.com>, (c) 2015 ST Microelectronics
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
index e68d163..1fe2d7f 100644
--- a/Documentation/arm/sunxi/README
+++ b/Documentation/arm/sunxi/README
@@ -50,7 +50,6 @@
           http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf
 
       - Allwinner A31s (sun6i)
-        + Not Supported
         + Datasheet
           http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf
         + User Manual
diff --git a/Documentation/devicetree/bindings/arm/armada-38x.txt b/Documentation/devicetree/bindings/arm/armada-38x.txt
index ad9f8ed..202953f 100644
--- a/Documentation/devicetree/bindings/arm/armada-38x.txt
+++ b/Documentation/devicetree/bindings/arm/armada-38x.txt
@@ -15,6 +15,13 @@
 
 compatible: must contain "marvell,armada385"
 
+In addition, boards using the Marvell Armada 388 SoC shall have the
+following property before the previous one:
+
+Required root node property:
+
+compatible: must contain "marvell,armada388"
+
 Example:
 
 compatible = "marvell,a385-rd", "marvell,armada385", "marvell,armada380";
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index 562cda9..ad319f8 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -24,6 +24,7 @@
     o "atmel,at91sam9g45"
     o "atmel,at91sam9n12"
     o "atmel,at91sam9rl"
+    o "atmel,at91sam9xe"
  * "atmel,sama5" for SoCs using a Cortex-A5, shall be extended with the specific
    SoC family:
     o "atmel,sama5d3" shall be extended with the specific SoC compatible:
@@ -136,3 +137,19 @@
 		compatible = "atmel,at91sam9260-rstc";
 		reg = <0xfffffd00 0x10>;
 	};
+
+Special Function Registers (SFR)
+
+Special Function Registers (SFR) manage specific aspects of the integrated
+memory, bridge implementations, processor and other functionality not controlled
+elsewhere.
+
+required properties:
+- compatible: Should be "atmel,<chip>-sfr", "syscon".
+  <chip> can be "sama5d3" or "sama5d4".
+- reg: Should contain registers location and length
+
+	sfr@f0038000 {
+		compatible = "atmel,sama5d3-sfr", "syscon";
+		reg = <0xf0038000 0x60>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index d790f49..a308935 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -38,8 +38,6 @@
 	  AMBA markee):
 		- "arm,coresight-replicator"
 
-	* id: a unique number that will identify this replicator.
-
 	* port or ports: same as above.
 
 * Optional properties for ETM/PTMs:
@@ -94,8 +92,6 @@
 		 * AMBA bus.  As such no need to add "arm,primecell".
 		 */
 		compatible = "arm,coresight-replicator";
-		/* this will show up in debugfs as "0.replicator" */
-		id = <0>;
 
 		ports {
 			#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/arm/digicolor.txt b/Documentation/devicetree/bindings/arm/digicolor.txt
new file mode 100644
index 0000000..658553f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/digicolor.txt
@@ -0,0 +1,6 @@
+Conexant Digicolor Platforms Device Tree Bindings
+
+Each device tree must specify which Conexant Digicolor SoC it uses.
+Must be the following compatible string:
+
+  cnxt,cx92755
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
index abde1ea..f4445e5 100644
--- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
@@ -23,7 +23,7 @@
 		devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
 		are supported currently.
 
-Node of a device using power domains must have a samsung,power-domain property
+Node of a device using power domains must have a power-domains property
 defined with a phandle to respective power domain.
 
 Example:
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 4e8b7df..a5462b6 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -75,6 +75,18 @@
 Required root node properties:
     - compatible = "fsl,imx6q";
 
+Freescale Vybrid Platform Device Tree Bindings
+----------------------------------------------
+
+For the Vybrid SoC familiy all variants with DDR controller are supported,
+which is the VF5xx and VF6xx series. Out of historical reasons, in most
+places the kernel uses vf610 to refer to the whole familiy.
+
+Required root node compatible property (one of them):
+    - compatible = "fsl,vf500";
+    - compatible = "fsl,vf510";
+    - compatible = "fsl,vf600";
+    - compatible = "fsl,vf610";
 
 Freescale LS1021A Platform Device Tree Bindings
 ------------------------------------------------
@@ -112,3 +124,11 @@
 		compatible = "fsl,ls1021a-dcfg";
 		reg = <0x0 0x1ee0000 0x0 0x10000>;
 	};
+
+Freescale LS2085A SoC Device Tree Bindings
+------------------------------------------
+
+LS2085A ARMv8 based Simulator model
+Required root node properties:
+    - compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
+
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 8112d0c..c97484b 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -32,12 +32,16 @@
   The 3rd cell is the flags, encoded as follows:
 	bits[3:0] trigger type and level flags.
 		1 = low-to-high edge triggered
-		2 = high-to-low edge triggered
+		2 = high-to-low edge triggered (invalid for SPIs)
 		4 = active high level-sensitive
-		8 = active low level-sensitive
+		8 = active low level-sensitive (invalid for SPIs).
 	bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of
 	the 8 possible cpus attached to the GIC.  A bit set to '1' indicated
 	the interrupt is wired to that CPU.  Only valid for PPI interrupts.
+	Also note that the configurability of PPI interrupts is IMPLEMENTATION
+	DEFINED and as such not guaranteed to be present (most SoC available
+	in 2014 seem to ignore the setting of this flag and use the hardware
+	default value).
 
 - reg : Specifies base physical address(s) and size of the GIC registers. The
   first region is the GIC distributor register base and size. The 2nd region is
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index f717c7b..35b1bd4 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -9,6 +9,10 @@
 Required root node properties:
 	- compatible = "hisilicon,hip04-d01";
 
+HiP01 ca9x2 Board
+Required root node properties:
+	- compatible = "hisilicon,hip01-ca9x2";
+
 
 Hisilicon system controller
 
@@ -37,6 +41,27 @@
 	};
 
 -----------------------------------------------------------------------
+Hisilicon HiP01 system controller
+
+Required properties:
+- compatible : "hisilicon,hip01-sysctrl"
+- reg : Register address and size
+
+The HiP01 system controller is mostly compatible with hisilicon
+system controller,but it has some specific control registers for
+HIP01 SoC family, such as slave core boot, and also some same
+registers located at different offset.
+
+Example:
+
+	/* for hip01-ca9x2 */
+	sysctrl: system-controller@10000000 {
+		compatible = "hisilicon,hip01-sysctrl", "hisilicon,sysctrl";
+		reg = <0x10000000 0x1000>;
+		reboot-offset = <0x4>;
+	};
+
+-----------------------------------------------------------------------
 Hisilicon CPU controller
 
 Required properties:
diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
index 3be4013..dd7550a 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek.txt
@@ -9,6 +9,7 @@
    "mediatek,mt6592"
    "mediatek,mt8127"
    "mediatek,mt8135"
+   "mediatek,mt8173"
 
 
 Supported boards:
@@ -25,3 +26,6 @@
 - MTK mt8135 tablet EVB:
     Required root node properties:
       - compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135";
+- MTK mt8173 tablet EVB:
+    Required root node properties:
+      - compatible = "mediatek,mt8173-evb", "mediatek,mt8173";
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt
index d680b07..4f5a535 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,sysirq.txt
@@ -5,8 +5,10 @@
 
 Required properties:
 - compatible: should be one of:
+	"mediatek,mt8173-sysirq"
 	"mediatek,mt8135-sysirq"
 	"mediatek,mt8127-sysirq"
+	"mediatek,mt6592-sysirq"
 	"mediatek,mt6589-sysirq"
 	"mediatek,mt6582-sysirq"
 	"mediatek,mt6577-sysirq"
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index eaa3d1a..6809e4e 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -9,6 +9,16 @@
     Required root node properties:
       - compatible = "mundoreader,bq-curie2", "rockchip,rk3066a";
 
+- ChipSPARK Rayeager PX2 board:
+    Required root node properties:
+      - compatible = "chipspark,rayeager-px2", "rockchip,rk3066a";
+
 - Radxa Rock board:
     Required root node properties:
       - compatible = "radxa,rock", "rockchip,rk3188";
+
+- Firefly Firefly-RK3288 board:
+    Required root node properties:
+      - compatible = "firefly,firefly-rk3288", "rockchip,rk3288";
+    or
+      - compatible = "firefly,firefly-rk3288-beta", "rockchip,rk3288";
diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt b/Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt
new file mode 100644
index 0000000..6b42fda
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rockchip/pmu-sram.txt
@@ -0,0 +1,16 @@
+Rockchip SRAM for pmu:
+------------------------------
+
+The sram of pmu is used to store the function of resume from maskrom(the 1st
+level loader). This is a common use of the "pmu-sram" because it keeps power
+even in low power states in the system.
+
+Required node properties:
+- compatible : should be "rockchip,rk3288-pmu-sram"
+- reg : physical base address and the size of the registers window
+
+Example:
+	sram@ff720000 {
+		compatible = "rockchip,rk3288-pmu-sram", "mmio-sram";
+		reg = <0xff720000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt
new file mode 100644
index 0000000..85c5dfd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.txt
@@ -0,0 +1,12 @@
+SAMSUNG Exynos SoCs Chipid driver.
+
+Required properties:
+- compatible : Should at least contain "samsung,exynos4210-chipid".
+
+- reg: offset and length of the register set
+
+Example:
+	chipid@10000000 {
+		compatible = "samsung,exynos4210-chipid";
+		reg = <0x10000000 0x100>;
+	};
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
index 1e1979b..67b2113 100644
--- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
@@ -10,6 +10,7 @@
 		   - "samsung,exynos5260-pmu" - for Exynos5260 SoC.
 		   - "samsung,exynos5410-pmu" - for Exynos5410 SoC,
 		   - "samsung,exynos5420-pmu" - for Exynos5420 SoC.
+		   - "samsung,exynos7-pmu" - for Exynos7 SoC.
 		second value must be always "syscon".
 
  - reg : offset and length of the register set.
diff --git a/Documentation/devicetree/bindings/arm/sirf.txt b/Documentation/devicetree/bindings/arm/sirf.txt
index c6ba6d3..7b28ee6 100644
--- a/Documentation/devicetree/bindings/arm/sirf.txt
+++ b/Documentation/devicetree/bindings/arm/sirf.txt
@@ -3,7 +3,9 @@
 
 Required root node properties:
     - compatible:
+    - "sirf,atlas6-cb" : atlas6 "cb" evaluation board
+    - "sirf,atlas6" : atlas6 device based board
+    - "sirf,atlas7-cb" : atlas7 "cb" evaluation board
+    - "sirf,atlas7" : atlas7 device based board
     - "sirf,prima2-cb" : prima2 "cb" evaluation board
-    - "sirf,marco-cb" : marco "cb" evaluation board
     - "sirf,prima2" : prima2 device based board
-    - "sirf,marco" : marco device based board
diff --git a/Documentation/devicetree/bindings/arm/sprd.txt b/Documentation/devicetree/bindings/arm/sprd.txt
new file mode 100644
index 0000000..31a629d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sprd.txt
@@ -0,0 +1,11 @@
+Spreadtrum SoC Platforms Device Tree Bindings
+----------------------------------------------------
+
+Sharkl64 is a Spreadtrum's SoC Platform which is based
+on ARM 64-bit processor.
+
+SC9836 openphone board with SC9836 SoC based on the
+Sharkl64 Platform shall have the following properties.
+
+Required root node properties:
+        - compatible = "sprd,sc9836-openphone", "sprd,sc9836";
diff --git a/Documentation/devicetree/bindings/arm/sti.txt b/Documentation/devicetree/bindings/arm/sti.txt
index 92f16c7..d70ec35 100644
--- a/Documentation/devicetree/bindings/arm/sti.txt
+++ b/Documentation/devicetree/bindings/arm/sti.txt
@@ -13,3 +13,7 @@
 Required root node property:
 compatible = "st,stih407";
 
+Boards with the ST STiH418 SoC shall have the following properties:
+Required root node property:
+compatible = "st,stih418";
+
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
index dd75b97..02c2700 100644
--- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
@@ -51,6 +51,23 @@
   sleep mode, the warm boot code will restore some PLLs, clocks and then
   bring up CPU0 for resuming the system.
 
+Hardware-triggered thermal reset:
+On Tegra30, Tegra114 and Tegra124, if the 'i2c-thermtrip' subnode exists,
+hardware-triggered thermal reset will be enabled.
+
+Required properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
+- nvidia,i2c-controller-id : ID of I2C controller to send poweroff command to. Valid values are
+                             described in section 9.2.148 "APBDEV_PMC_SCRATCH53_0" of the
+                             Tegra K1 Technical Reference Manual.
+- nvidia,bus-addr : Bus address of the PMU on the I2C bus
+- nvidia,reg-addr : I2C register address to write poweroff command to
+- nvidia,reg-data : Poweroff command to write to PMU
+
+Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
+- nvidia,pinmux-id : Pinmux used by the hardware when issuing poweroff command.
+                     Defaults to 0. Valid values are described in section 12.5.2
+                     "Pinmux Support" of the Tegra4 Technical Reference Manual.
+
 Example:
 
 / SoC dts including file
@@ -73,6 +90,15 @@
 / Tegra board dts file
 {
 	...
+	pmc@7000f400 {
+		i2c-thermtrip {
+			nvidia,i2c-controller-id = <4>;
+			nvidia,bus-addr = <0x40>;
+			nvidia,reg-addr = <0x36>;
+			nvidia,reg-data = <0x2>;
+		};
+	};
+	...
 	clocks {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/arm/versatile-sysreg.txt b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt
new file mode 100644
index 0000000..a4f1526
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/versatile-sysreg.txt
@@ -0,0 +1,10 @@
+ARM Versatile system registers
+--------------------------------------
+
+This is a system control registers block, providing multiple low level
+platform functions like board detection and identification, software
+interrupt generation, MMC and NOR Flash control etc.
+
+Required node properties:
+- compatible value : = "arm,versatile-sysreg", "syscon"
+- reg : physical base address and the size of the registers window
diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
index 5e16c3c..fa6cde4 100644
--- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
+++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
@@ -6,8 +6,8 @@
 - compatible:	 Should be set to one of the following:
 		 marvell,armada370-mbus
 		 marvell,armadaxp-mbus
-		 marvell,armada370-mbus
-		 marvell,armadaxp-mbus
+		 marvell,armada375-mbus
+		 marvell,armada380-mbus
 		 marvell,kirkwood-mbus
 		 marvell,dove-mbus
 		 marvell,orion5x-88f5281-mbus
diff --git a/Documentation/devicetree/bindings/clock/alphascale,acc.txt b/Documentation/devicetree/bindings/clock/alphascale,acc.txt
new file mode 100644
index 0000000..62e67e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/alphascale,acc.txt
@@ -0,0 +1,115 @@
+Alphascale Clock Controller
+
+The ACC (Alphascale Clock Controller) is responsible of choising proper
+clock source, setting deviders and clock gates.
+
+Required properties for the ACC node:
+ - compatible: must be "alphascale,asm9260-clock-controller"
+ - reg: must contain the ACC register base and size
+ - #clock-cells : shall be set to 1.
+
+Simple one-cell clock specifier format is used, where the only cell is used
+as an index of the clock inside the provider.
+It is encouraged to use dt-binding for clock index definitions. SoC specific
+dt-binding should be included to the device tree descriptor. For example
+Alphascale ASM9260:
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+This binding contains two types of clock providers:
+ _AHB_ - AHB gate;
+ _SYS_ - adjustable clock source. Not all peripheral have _SYS_ clock provider.
+All clock specific details can be found in the SoC documentation.
+CLKID_AHB_ROM		0
+CLKID_AHB_RAM		1
+CLKID_AHB_GPIO		2
+CLKID_AHB_MAC		3
+CLKID_AHB_EMI		4
+CLKID_AHB_USB0		5
+CLKID_AHB_USB1		6
+CLKID_AHB_DMA0		7
+CLKID_AHB_DMA1		8
+CLKID_AHB_UART0		9
+CLKID_AHB_UART1		10
+CLKID_AHB_UART2		11
+CLKID_AHB_UART3		12
+CLKID_AHB_UART4		13
+CLKID_AHB_UART5		14
+CLKID_AHB_UART6		15
+CLKID_AHB_UART7		16
+CLKID_AHB_UART8		17
+CLKID_AHB_UART9		18
+CLKID_AHB_I2S0		19
+CLKID_AHB_I2C0		20
+CLKID_AHB_I2C1		21
+CLKID_AHB_SSP0		22
+CLKID_AHB_IOCONFIG	23
+CLKID_AHB_WDT		24
+CLKID_AHB_CAN0		25
+CLKID_AHB_CAN1		26
+CLKID_AHB_MPWM		27
+CLKID_AHB_SPI0		28
+CLKID_AHB_SPI1		29
+CLKID_AHB_QEI		30
+CLKID_AHB_QUADSPI0	31
+CLKID_AHB_CAMIF		32
+CLKID_AHB_LCDIF		33
+CLKID_AHB_TIMER0	34
+CLKID_AHB_TIMER1	35
+CLKID_AHB_TIMER2	36
+CLKID_AHB_TIMER3	37
+CLKID_AHB_IRQ		38
+CLKID_AHB_RTC		39
+CLKID_AHB_NAND		40
+CLKID_AHB_ADC0		41
+CLKID_AHB_LED		42
+CLKID_AHB_DAC0		43
+CLKID_AHB_LCD		44
+CLKID_AHB_I2S1		45
+CLKID_AHB_MAC1		46
+
+CLKID_SYS_CPU		47
+CLKID_SYS_AHB		48
+CLKID_SYS_I2S0M		49
+CLKID_SYS_I2S0S		50
+CLKID_SYS_I2S1M		51
+CLKID_SYS_I2S1S		52
+CLKID_SYS_UART0		53
+CLKID_SYS_UART1		54
+CLKID_SYS_UART2		55
+CLKID_SYS_UART3		56
+CLKID_SYS_UART4		56
+CLKID_SYS_UART5		57
+CLKID_SYS_UART6		58
+CLKID_SYS_UART7		59
+CLKID_SYS_UART8		60
+CLKID_SYS_UART9		61
+CLKID_SYS_SPI0		62
+CLKID_SYS_SPI1		63
+CLKID_SYS_QUADSPI	64
+CLKID_SYS_SSP0		65
+CLKID_SYS_NAND		66
+CLKID_SYS_TRACE		67
+CLKID_SYS_CAMM		68
+CLKID_SYS_WDT		69
+CLKID_SYS_CLKOUT	70
+CLKID_SYS_MAC		71
+CLKID_SYS_LCD		72
+CLKID_SYS_ADCANA	73
+
+Example of clock consumer with _SYS_ and _AHB_ sinks.
+uart4: serial@80010000 {
+	compatible = "alphascale,asm9260-uart";
+	reg = <0x80010000 0x4000>;
+	clocks = <&acc CLKID_SYS_UART4>, <&acc CLKID_AHB_UART4>;
+	interrupts = <19>;
+	status = "disabled";
+};
+
+Clock consumer with only one, _AHB_ sink.
+timer0: timer@80088000 {
+	compatible = "alphascale,asm9260-timer";
+	reg = <0x80088000 0x4000>;
+	clocks = <&acc CLKID_AHB_TIMER0>;
+	interrupts = <29>;
+};
+
diff --git a/Documentation/devicetree/bindings/clock/renesas,sh73a0-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,sh73a0-cpg-clocks.txt
new file mode 100644
index 0000000..a8978ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/renesas,sh73a0-cpg-clocks.txt
@@ -0,0 +1,35 @@
+These bindings should be considered EXPERIMENTAL for now.
+
+* Renesas SH73A0 Clock Pulse Generator (CPG)
+
+The CPG generates core clocks for the SH73A0 SoC. It includes four PLLs
+and several fixed ratio dividers.
+
+Required Properties:
+
+  - compatible: Must be "renesas,sh73a0-cpg-clocks"
+
+  - reg: Base address and length of the memory resource used by the CPG
+
+  - clocks: Reference to the parent clocks ("extal1" and "extal2")
+
+  - #clock-cells: Must be 1
+
+  - clock-output-names: The names of the clocks. Supported clocks are "main",
+    "pll0", "pll1", "pll2", "pll3", "dsi0phy", "dsi1phy", "zg", "m3", "b",
+    "m1", "m2", "z", "zx", and "hp".
+
+
+Example
+-------
+
+        cpg_clocks: cpg_clocks@e6150000 {
+                compatible = "renesas,sh73a0-cpg-clocks";
+                reg = <0 0xe6150000 0 0x10000>;
+                clocks = <&extal1_clk>, <&extal2_clk>;
+                #clock-cells = <1>;
+                clock-output-names = "main", "pll0", "pll1", "pll2",
+                                     "pll3", "dsi0phy", "dsi1phy",
+                                     "zg", "m3", "b", "m1", "m2",
+                                     "z", "zx", "hp";
+        };
diff --git a/Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt
new file mode 100644
index 0000000..ebc1a91
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/atmel/hlcdc-dc.txt
@@ -0,0 +1,53 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
+
+The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
+See ../mfd/atmel-hlcdc.txt for more details.
+
+Required properties:
+ - compatible: value should be "atmel,hlcdc-display-controller"
+ - pinctrl-names: the pin control state names. Should contain "default".
+ - pinctrl-0: should contain the default pinctrl states.
+ - #address-cells: should be set to 1.
+ - #size-cells: should be set to 0.
+
+Required children nodes:
+ Children nodes are encoding available output ports and their connections
+ to external devices using the OF graph reprensentation (see ../graph.txt).
+ At least one port node is required.
+
+Example:
+
+	hlcdc: hlcdc@f0030000 {
+		compatible = "atmel,sama5d3-hlcdc";
+		reg = <0xf0030000 0x2000>;
+		interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+		clock-names = "periph_clk","sys_clk", "slow_clk";
+		status = "disabled";
+
+		hlcdc-display-controller {
+			compatible = "atmel,hlcdc-display-controller";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0>;
+
+				hlcdc_panel_output: endpoint@0 {
+					reg = <0>;
+					remote-endpoint = <&panel_input>;
+				};
+			};
+		};
+
+		hlcdc_pwm: hlcdc-pwm {
+			compatible = "atmel,hlcdc-pwm";
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_lcd_pwm>;
+			#pwm-cells = <3>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..a905c14
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,50 @@
+DesignWare HDMI bridge bindings
+
+Required properties:
+- compatible: platform specific such as:
+   * "snps,dw-hdmi-tx"
+   * "fsl,imx6q-hdmi"
+   * "fsl,imx6dl-hdmi"
+   * "rockchip,rk3288-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The HDMI interrupt number
+- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
+  as described in Documentation/devicetree/bindings/clock/clock-bindings.txt,
+  the clocks are soc specific, the clock-names should be "iahb", "isfr"
+-port@[X]: SoC specific port nodes with endpoint definitions as defined
+   in Documentation/devicetree/bindings/media/video-interfaces.txt,
+   please refer to the SoC specific binding document:
+    * Documentation/devicetree/bindings/drm/imx/hdmi.txt
+    * Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+
+Example:
+	hdmi: hdmi@0120000 {
+		compatible = "fsl,imx6q-hdmi";
+		reg = <0x00120000 0x9000>;
+		interrupts = <0 115 0x04>;
+		gpr = <&gpr>;
+		clocks = <&clks 123>, <&clks 124>;
+		clock-names = "iahb", "isfr";
+		ddc-i2c-bus = <&i2c2>;
+
+		port@0 {
+			reg = <0>;
+
+			hdmi_mux_0: endpoint {
+				remote-endpoint = <&ipu1_di0_hdmi>;
+			};
+		};
+
+		port@1 {
+			reg = <1>;
+
+			hdmi_mux_1: endpoint {
+				remote-endpoint = <&ipu1_di1_hdmi>;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
deleted file mode 100644
index 52b93b2..0000000
--- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-ptn3460 bridge bindings
-
-Required properties:
-	- compatible: "nxp,ptn3460"
-	- reg: i2c address of the bridge
-	- powerdown-gpio: OF device-tree gpio specification
-	- reset-gpio: OF device-tree gpio specification
-	- edid-emulation: The EDID emulation entry to use
-		+-------+------------+------------------+
-		| Value | Resolution | Description      |
-		|   0   |  1024x768  | NXP Generic      |
-		|   1   |  1920x1080 | NXP Generic      |
-		|   2   |  1920x1080 | NXP Generic      |
-		|   3   |  1600x900  | Samsung LTM200KT |
-		|   4   |  1920x1080 | Samsung LTM230HT |
-		|   5   |  1366x768  | NXP Generic      |
-		|   6   |  1600x900  | ChiMei M215HGE   |
-		+-------+------------+------------------+
-
-Example:
-	lvds-bridge@20 {
-		compatible = "nxp,ptn3460";
-		reg = <0x20>;
-		powerdown-gpio = <&gpy2 5 1 0 0>;
-		reset-gpio = <&gpx1 5 1 0 0>;
-		edid-emulation = <5>;
-	};
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi.txt b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
index aca917f..a29a55f 100644
--- a/Documentation/devicetree/bindings/drm/msm/hdmi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/hdmi.txt
@@ -2,6 +2,8 @@
 
 Required properties:
 - compatible: one of the following
+   * "qcom,hdmi-tx-8084"
+   * "qcom,hdmi-tx-8074"
    * "qcom,hdmi-tx-8660"
    * "qcom,hdmi-tx-8960"
 - reg: Physical base address and length of the controller's registers
diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
index c99eb34..6b1d75f 100644
--- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
+++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
@@ -83,6 +83,22 @@
   - clock-names: names of the clocks listed in clocks property in the same
     order.
 
+sti-dvo:
+  Required properties:
+  must be a child of sti-tvout
+  - compatible: "st,stih<chip>-dvo"
+  - reg: Physical base address of the IP registers and length of memory mapped region.
+  - reg-names: names of the mapped memory regions listed in regs property in
+    the same order.
+  - clocks: from common clock binding: handle hardware IP needed clocks, the
+    number of clocks may depend of the SoC type.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: names of the clocks listed in clocks property in the same
+    order.
+  - pinctrl-0: pin control handle
+  - pinctrl-name: names of the pin control to use
+  - sti,panel: phandle of the panel connected to the DVO output
+
 sti-hqvdp:
   must be a child of sti-display-subsystem
   Required properties:
@@ -198,6 +214,19 @@
 				clock-names	= "pix", "hddac";
 				clocks          = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
 			};
+
+			sti-dvo@8d00400 {
+				compatible	= "st,stih407-dvo";
+				reg		= <0x8d00400 0x200>;
+				reg-names	= "dvo-reg";
+				clock-names	= "dvo_pix", "dvo",
+						  "main_parent", "aux_parent";
+				clocks		= <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
+						  <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
+				pinctrl-names	= "default";
+				pinctrl-0	= <&pinctrl_dvo>;
+				sti,panel	= <&panel_dvo>;
+			};
 		};
 
 		sti-hqvdp@9c000000 {
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 9f41d05..4dcd88d 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -9,6 +9,7 @@
 
 Compatible		Vendor / Chip
 ==========		=============
+abracon,abb5zes3		AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface
 ad,ad7414		SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin
 ad,adm9240		ADM9240:  Complete System Hardware Monitor for uProcessor-Based Systems
 adi,adt7461		+/-1C TDM Extended Temp Range I.C
@@ -34,6 +35,7 @@
 atmel,24c1024		i2c serial eeprom  (24cxx)
 atmel,at97sc3204t	i2c trusted platform module (TPM)
 capella,cm32181		CM32181: Ambient Light Sensor
+capella,cm3232		CM3232: Ambient Light Sensor
 catalyst,24c32		i2c serial eeprom
 cirrus,cs42l51		Cirrus Logic CS42L51 audio codec
 dallas,ds1307		64 x 8, Serial, I2C Real-Time Clock
diff --git a/Documentation/devicetree/bindings/iio/adc/cc10001_adc.txt b/Documentation/devicetree/bindings/iio/adc/cc10001_adc.txt
new file mode 100644
index 0000000..904f76d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/cc10001_adc.txt
@@ -0,0 +1,22 @@
+* Cosmic Circuits - Analog to Digital Converter (CC-10001-ADC)
+
+Required properties:
+  - compatible: Should be "cosmic,10001-adc"
+  - reg: Should contain adc registers location and length.
+  - clock-names: Should contain "adc".
+  - clocks: Should contain a clock specifier for each entry in clock-names
+  - vref-supply: The regulator supply ADC reference voltage.
+
+Optional properties:
+  - adc-reserved-channels: Bitmask of reserved channels,
+    i.e. channels that cannot be used by the OS.
+
+Example:
+adc: adc@18101600 {
+	compatible = "cosmic,10001-adc";
+	reg = <0x18101600 0x24>;
+	adc-reserved-channels = <0x2>;
+	clocks = <&adc_clk>;
+	clock-names = "adc";
+	vref-supply = <&reg_1v8>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.txt
new file mode 100644
index 0000000..0fb4613
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.txt
@@ -0,0 +1,129 @@
+Qualcomm's SPMI PMIC voltage ADC
+
+SPMI PMIC voltage ADC (VADC) provides interface to clients to read
+voltage. The VADC is a 15-bit sigma-delta ADC.
+
+VADC node:
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,spmi-vadc".
+
+- reg:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: VADC base address and length in the SPMI PMIC register map.
+
+- #address-cells:
+    Usage: required
+    Value type: <u32>
+    Definition: Must be one. Child node 'reg' property should define ADC
+            channel number.
+
+- #size-cells:
+    Usage: required
+    Value type: <u32>
+    Definition: Must be zero.
+
+- #io-channel-cells:
+    Usage: required
+    Value type: <u32>
+    Definition: Must be one. For details about IIO bindings see:
+            Documentation/devicetree/bindings/iio/iio-bindings.txt
+
+- interrupts:
+    Usage: optional
+    Value type: <prop-encoded-array>
+    Definition: End of conversion interrupt.
+
+Channel node properties:
+
+- reg:
+    Usage: required
+    Value type: <u32>
+    Definition: ADC channel number.
+            See include/dt-bindings/iio/qcom,spmi-vadc.h
+
+- qcom,decimation:
+    Usage: optional
+    Value type: <u32>
+    Definition: This parameter is used to decrease ADC sampling rate.
+            Quicker measurements can be made by reducing decimation ratio.
+            Valid values are 512, 1024, 2048, 4096.
+            If property is not found, default value of 512 will be used.
+
+- qcom,pre-scaling:
+    Usage: optional
+    Value type: <u32 array>
+    Definition: Used for scaling the channel input signal before the signal is
+            fed to VADC. The configuration for this node is to know the
+            pre-determined ratio and use it for post scaling. Select one from
+            the following options.
+            <1 1>, <1 3>, <1 4>, <1 6>, <1 20>, <1 8>, <10 81>, <1 10>
+            If property is not found default value depending on chip will be used.
+
+- qcom,ratiometric:
+    Usage: optional
+    Value type: <empty>
+    Definition: Channel calibration type. If this property is specified
+            VADC will use the VDD reference (1.8V) and GND for channel
+            calibration. If property is not found, channel will be
+            calibrated with 0.625V and 1.25V reference channels, also
+            known as absolute calibration.
+
+- qcom,hw-settle-time:
+    Usage: optional
+    Value type: <u32>
+    Definition: Time between AMUX getting configured and the ADC starting
+            conversion. Delay = 100us * (value) for value < 11, and
+            2ms * (value - 10) otherwise.
+            Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800,
+            900 us and 1, 2, 4, 6, 8, 10 ms
+            If property is not found, channel will use 0us.
+
+- qcom,avg-samples:
+    Usage: optional
+    Value type: <u32>
+    Definition: Number of samples to be used for measurement.
+            Averaging provides the option to obtain a single measurement
+            from the ADC that is an average of multiple samples. The value
+            selected is 2^(value).
+            Valid values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
+            If property is not found, 1 sample will be used.
+
+NOTE:
+
+Following channels, also known as reference point channels, are used for
+result calibration and their channel configuration nodes should be defined:
+VADC_REF_625MV and/or VADC_SPARE1(based on PMIC version) VADC_REF_1250MV,
+VADC_GND_REF and VADC_VDD_VADC.
+
+Example:
+
+	/* VADC node */
+	pmic_vadc: vadc@3100 {
+		compatible = "qcom,spmi-vadc";
+		reg = <0x3100 0x100>;
+		interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#io-channel-cells = <1>;
+		io-channel-ranges;
+
+		/* Channel node */
+		usb_id_nopull {
+			reg = <VADC_LR_MUX10_USB_ID>;
+			qcom,decimation = <512>;
+			qcom,ratiometric;
+			qcom,hw-settle-time = <200>;
+			qcom,avg-samples = <1>;
+			qcom,pre-scaling = <1 3>;
+		};
+	};
+
+	/* IIO client node */
+	usb {
+		io-channels = <&pmic_vadc VADC_LR_MUX10_USB_ID>;
+		io-channel-names = "vadc";
+	};
diff --git a/Documentation/devicetree/bindings/iio/sensorhub.txt b/Documentation/devicetree/bindings/iio/sensorhub.txt
new file mode 100644
index 0000000..8d57571
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/sensorhub.txt
@@ -0,0 +1,25 @@
+Samsung Sensorhub driver
+
+Sensorhub is a MCU which manages several sensors and also plays the role
+of a virtual sensor device.
+
+Required properties:
+- compatible: "samsung,sensorhub-rinato" or "samsung,sensorhub-thermostat"
+- spi-max-frequency: max SPI clock frequency
+- interrupt-parent: interrupt parent
+- interrupts: communication interrupt
+- ap-mcu-gpios: [out] ap to sensorhub line - used during communication
+- mcu-ap-gpios: [in] sensorhub to ap - used during communication
+- mcu-reset-gpios: [out] sensorhub reset
+
+Example:
+
+	shub_spi: shub {
+		compatible = "samsung,sensorhub-rinato";
+		spi-max-frequency = <5000000>;
+		interrupt-parent = <&gpx0>;
+		interrupts = <2 0>;
+		ap-mcu-gpios = <&gpx0 0 0>;
+		mcu-ap-gpios = <&gpx0 4 0>;
+		mcu-reset-gpios = <&gpx0 5 0>;
+	};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/digicolor-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/digicolor-ic.txt
new file mode 100644
index 0000000..42d41ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/digicolor-ic.txt
@@ -0,0 +1,21 @@
+Conexant Digicolor Interrupt Controller
+
+Required properties:
+
+- compatible : should be "cnxt,cx92755-ic"
+- reg : Specifies base physical address and size of the interrupt controller
+  registers (IC) area
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 1.
+- syscon: A phandle to the syscon node describing UC registers
+
+Example:
+
+	intc: interrupt-controller@f0000040 {
+		compatible = "cnxt,cx92755-ic";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0xf0000040 0x40>;
+		syscon = <&uc_regs>;
+	};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
index c73acd0..4f7946a 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
@@ -9,6 +9,11 @@
     - "renesas,intc-irqpin-r8a7778" (R-Car M1A)
     - "renesas,intc-irqpin-r8a7779" (R-Car H1)
     - "renesas,intc-irqpin-sh73a0" (SH-Mobile AG5)
+
+- reg: Base address and length of each register bank used by the external
+  IRQ pins driven by the interrupt controller hardware module. The base
+  addresses, length and number of required register banks varies with soctype.
+
 - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
   interrupts.txt in this directory
 
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,omap-intc-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,omap-intc-irq.txt
new file mode 100644
index 0000000..38ce5d03
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,omap-intc-irq.txt
@@ -0,0 +1,28 @@
+Omap2/3 intc controller
+
+On TI omap2 and 3 the intc interrupt controller can provide
+96 or 128 IRQ signals to the ARM host depending on the SoC.
+
+Required Properties:
+- compatible: should be one of
+			"ti,omap2-intc"
+			"ti,omap3-intc"
+			"ti,dm814-intc"
+			"ti,dm816-intc"
+			"ti,am33xx-intc"
+
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode interrupt
+		     source, should be 1 for intc
+- interrupts: interrupt reference to primary interrupt controller
+
+Please refer to interrupts.txt in this directory for details of the common
+Interrupt Controllers bindings used by client devices.
+
+Example:
+	intc: interrupt-controller@48200000 {
+		compatible = "ti,omap3-intc";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0x48200000 0x1000>;
+	};
diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
index 6fa4c73..729543c 100644
--- a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
+++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
@@ -45,7 +45,7 @@
 	       Exynos4 SoCs, there needs no "master" clock.
 	       Exynos5 SoCs, some System MMUs must have "master" clocks.
 - clocks: Required if the System MMU is needed to gate its clock.
-- samsung,power-domain: Required if the System MMU is needed to gate its power.
+- power-domains: Required if the System MMU is needed to gate its power.
 	  Please refer to the following document:
 	  Documentation/devicetree/bindings/arm/exynos/power_domain.txt
 
@@ -54,7 +54,7 @@
 		compatible = "samsung,exynos5-gsc";
 		reg = <0x13e00000 0x1000>;
 		interrupts = <0 85 0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 		clocks = <&clock CLK_GSCL0>;
 		clock-names = "gscl";
 	};
@@ -66,5 +66,5 @@
 		interrupts = <2 0>;
 		clock-names = "sysmmu", "master";
 		clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 	};
diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt
index 3e3c5f3..2d5787e 100644
--- a/Documentation/devicetree/bindings/media/s5p-mfc.txt
+++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt
@@ -28,7 +28,7 @@
 		    for DMA contiguous memory allocation and its size.
 
 Optional properties:
-  - samsung,power-domain : power-domain property defined with a phandle
+  - power-domains : power-domain property defined with a phandle
 			   to respective power domain.
 
 Example:
@@ -38,7 +38,7 @@
 	compatible = "samsung,mfc-v5";
 	reg = <0x13400000 0x10000>;
 	interrupts = <0 94 0>;
-	samsung,power-domain = <&pd_mfc>;
+	power-domains = <&pd_mfc>;
 	clocks = <&clock 273>;
 	clock-names = "mfc";
 };
diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt b/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt
new file mode 100644
index 0000000..c64b792
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt
@@ -0,0 +1,44 @@
+DT bindings for Renesas R-Mobile and SH-Mobile memory controllers
+=================================================================
+
+Renesas R-Mobile and SH-Mobile SoCs contain one or more memory controllers.
+These memory controllers differ from one SoC variant to another, and are called
+by different names ("DDR Bus Controller (DBSC)", "DDR3 Bus State Controller
+(DBSC3)", "SDRAM Bus State Controller (SBSC)").
+
+Currently memory controller device nodes are used only to reference PM
+domains, and prevent these PM domains from being powered down, which would
+crash the system.
+
+As there exist no actual drivers for these controllers yet, these bindings
+should be considered EXPERIMENTAL for now.
+
+Required properties:
+  - compatible: Must be one of the following SoC-specific values:
+		  - "renesas,dbsc-r8a73a4" (R-Mobile APE6)
+		  - "renesas,dbsc3-r8a7740" (R-Mobile A1)
+		  - "renesas,sbsc-sh73a0" (SH-Mobile AG5)
+  - reg: Must contain the base address and length of the memory controller's
+	 registers.
+
+Optional properties:
+  - interrupts: Must contain a list of interrupt specifiers for memory
+		controller interrupts, if available.
+  - interrupts-names: Must contain a list of interrupt names corresponding to
+		      the interrupts in the interrupts property, if available.
+		      Valid interrupt names are:
+			- "sec" (secure interrupt)
+			- "temp" (normal (temperature) interrupt)
+  - power-domains: Must contain a reference to the PM domain that the memory
+		   controller belongs to, if available.
+
+Example:
+
+	sbsc1: memory-controller@fe400000 {
+		compatible = "renesas,sbsc-sh73a0";
+		reg = <0xfe400000 0x400>;
+		interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>,
+			     <0 36 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "sec", "temp";
+		power-domains = <&pd_a4bc0>;
+	};
diff --git a/Documentation/devicetree/bindings/mfd/atmel-matrix.txt b/Documentation/devicetree/bindings/mfd/atmel-matrix.txt
new file mode 100644
index 0000000..e3ef50c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-matrix.txt
@@ -0,0 +1,24 @@
+* Device tree bindings for Atmel Bus Matrix
+
+The Bus Matrix registers are used to configure Atmel SoCs internal bus
+behavior (master/slave priorities, undefined burst length type, ...)
+
+Required properties:
+- compatible:		Should be one of the following
+			"atmel,at91sam9260-matrix", "syscon"
+			"atmel,at91sam9261-matrix", "syscon"
+			"atmel,at91sam9263-matrix", "syscon"
+			"atmel,at91sam9rl-matrix", "syscon"
+			"atmel,at91sam9g45-matrix", "syscon"
+			"atmel,at91sam9n12-matrix", "syscon"
+			"atmel,at91sam9x5-matrix", "syscon"
+			"atmel,sama5d3-matrix", "syscon"
+- reg:			Contains offset/length value of the Bus Matrix
+			memory region.
+
+Example:
+
+matrix: matrix@ffffec00 {
+	compatible = "atmel,sama5d3-matrix", "syscon";
+	reg = <0xffffec00 0x200>;
+};
diff --git a/Documentation/devicetree/bindings/mfd/atmel-smc.txt b/Documentation/devicetree/bindings/mfd/atmel-smc.txt
new file mode 100644
index 0000000..26eeed3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-smc.txt
@@ -0,0 +1,19 @@
+* Device tree bindings for Atmel SMC (Static Memory Controller)
+
+The SMC registers are used to configure Atmel EBI (External Bus Interface)
+to interface with standard memory devices (NAND, NOR, SRAM or specialized
+devices like FPGAs).
+
+Required properties:
+- compatible:		Should be one of the following
+			"atmel,at91sam9260-smc", "syscon"
+			"atmel,sama5d3-smc", "syscon"
+- reg:			Contains offset/length value of the SMC memory
+			region.
+
+Example:
+
+smc: smc@ffffc000 {
+	compatible = "atmel,sama5d3-smc", "syscon";
+	reg = <0xffffc000 0x1000>;
+};
diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
new file mode 100644
index 0000000..c7a26ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
@@ -0,0 +1,40 @@
+* Freescale Management Complex
+
+The Freescale Management Complex (fsl-mc) is a hardware resource
+manager that manages specialized hardware objects used in
+network-oriented packet processing applications. After the fsl-mc
+block is enabled, pools of hardware resources are available, such as
+queues, buffer pools, I/O interfaces. These resources are building
+blocks that can be used to create functional hardware objects/devices
+such as network interfaces, crypto accelerator instances, L2 switches,
+etc.
+
+Required properties:
+
+    - compatible
+        Value type: <string>
+        Definition: Must be "fsl,qoriq-mc".  A Freescale Management Complex
+                    compatible with this binding must have Block Revision
+                    Registers BRR1 and BRR2 at offset 0x0BF8 and 0x0BFC in
+                    the MC control register region.
+
+    - reg
+        Value type: <prop-encoded-array>
+        Definition: A standard property.  Specifies one or two regions
+                    defining the MC's registers:
+
+                       -the first region is the command portal for the
+                        this machine and must always be present
+
+                       -the second region is the MC control registers. This
+                        region may not be present in some scenarios, such
+                        as in the device tree presented to a virtual machine.
+
+Example:
+
+        fsl_mc: fsl-mc@80c000000 {
+                compatible = "fsl,qoriq-mc";
+                reg = <0x00000008 0x0c000000 0 0x40>,    /* MC portal base */
+                      <0x00000000 0x08340000 0 0x40000>; /* MC control reg */
+        };
+
diff --git a/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt b/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt
new file mode 100644
index 0000000..b6f2f3e
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt
@@ -0,0 +1,7 @@
+Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
+
+Required properties:
+- compatible: should be "avic,tm070ddh03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt b/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt
new file mode 100644
index 0000000..24b0b62
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt
@@ -0,0 +1,7 @@
+GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "giantplus,gpg48273qs5"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
index 46a135d..89caa88 100644
--- a/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
+++ b/Documentation/devicetree/bindings/phy/phy-miphy28lp.txt
@@ -26,6 +26,7 @@
 		  filled in "reg". It can also contain the offset of the system configuration
 		  registers used as glue-logic to setup the device for SATA/PCIe or USB3
 		  devices.
+- st,syscfg	: Offset of the parent configuration register.
 - resets	: phandle to the parent reset controller.
 - reset-names	: Associated name must be "miphy-sw-rst".
 
@@ -54,18 +55,12 @@
 			phy_port0: port@9b22000 {
 				reg = <0x9b22000 0xff>,
 				      <0x9b09000 0xff>,
-				      <0x9b04000 0xff>,
-				      <0x114 0x4>, /* sysctrl MiPHY cntrl */
-				      <0x818 0x4>, /* sysctrl MiPHY status*/
-				      <0xe0  0x4>, /* sysctrl PCIe */
-				      <0xec  0x4>; /* sysctrl SATA */
+				      <0x9b04000 0xff>;
 				reg-names = "sata-up",
 					    "pcie-up",
-					    "pipew",
-					    "miphy-ctrl-glue",
-					    "miphy-status-glue",
-					    "pcie-glue",
-					    "sata-glue";
+					    "pipew";
+
+				st,syscfg = <0x114 0x818 0xe0 0xec>;
 				#phy-cells = <1>;
 				st,osc-rdy;
 				reset-names = "miphy-sw-rst";
@@ -75,18 +70,13 @@
 			phy_port1: port@9b2a000 {
 				reg = <0x9b2a000 0xff>,
 				      <0x9b19000 0xff>,
-				      <0x9b14000 0xff>,
-				      <0x118 0x4>,
-				      <0x81c 0x4>,
-				      <0xe4  0x4>,
-				      <0xf0  0x4>;
+				      <0x9b14000 0xff>;
 				reg-names = "sata-up",
 					    "pcie-up",
-					    "pipew",
-					    "miphy-ctrl-glue",
-					    "miphy-status-glue",
-					    "pcie-glue",
-					    "sata-glue";
+					    "pipew";
+
+				st,syscfg = <0x118 0x81c 0xe4 0xf0>;
+
 				#phy-cells = <1>;
 				st,osc-force-ext;
 				reset-names = "miphy-sw-rst";
@@ -95,13 +85,12 @@
 
 			phy_port2: port@8f95000 {
 				reg = <0x8f95000 0xff>,
-				      <0x8f90000 0xff>,
-				      <0x11c 0x4>,
-				      <0x820 0x4>;
+				      <0x8f90000 0xff>;
 				reg-names = "pipew",
-				    "usb3-up",
-				    "miphy-ctrl-glue",
-				    "miphy-status-glue";
+					    "usb3-up";
+
+				st,syscfg = <0x11c 0x820>;
+
 				#phy-cells = <1>;
 				reset-names = "miphy-sw-rst";
 				resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
@@ -125,4 +114,4 @@
 
 Macro definitions for the supported miphy configuration can be found in:
 
-include/dt-bindings/phy/phy-miphy28lp.h
+include/dt-bindings/phy/phy.h
diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
new file mode 100644
index 0000000..826454a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
@@ -0,0 +1,37 @@
+ROCKCHIP USB2 PHY
+
+Required properties:
+ - compatible: rockchip,rk3288-usb-phy
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - #address-cells: should be 1
+ - #size-cells: should be 0
+
+Sub-nodes:
+Each PHY should be represented as a sub-node.
+
+Sub-nodes
+required properties:
+- #phy-cells: should be 0
+- reg: PHY configure reg address offset in GRF
+		"0x320" - for PHY attach to OTG controller
+		"0x334" - for PHY attach to HOST0 controller
+		"0x348" - for PHY attach to HOST1 controller
+
+Optional Properties:
+- clocks : phandle + clock specifier for the phy clocks
+- clock-names: string, clock name, must be "phyclk"
+
+Example:
+
+usbphy: phy {
+	compatible = "rockchip,rk3288-usb-phy";
+	rockchip,grf = <&grf>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	usbphy0: usb-phy0 {
+		#phy-cells = <0>;
+		reg = <0x320>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index d5bad92..91e38cf 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -3,8 +3,8 @@
 
 Required properties:
 - compatible : should be "samsung,s5pv210-mipi-video-phy";
-- reg : offset and length of the MIPI DPHY register set;
 - #phy-cells : from the generic phy bindings, must be 1;
+- syscon - phandle to the PMU system controller;
 
 For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
 the PHY specifier identifies the PHY and its meaning is as follows:
diff --git a/Documentation/devicetree/bindings/power/renesas,sysc-rmobile.txt b/Documentation/devicetree/bindings/power/renesas,sysc-rmobile.txt
new file mode 100644
index 0000000..cc3b1f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/renesas,sysc-rmobile.txt
@@ -0,0 +1,99 @@
+DT bindings for the Renesas R-Mobile System Controller
+
+== System Controller Node ==
+
+The R-Mobile System Controller provides the following functions:
+  - Boot mode management,
+  - Reset generation,
+  - Power management.
+
+Required properties:
+- compatible: Should be "renesas,sysc-<soctype>", "renesas,sysc-rmobile" as
+	      fallback.
+	      Examples with soctypes are:
+		- "renesas,sysc-r8a7740" (R-Mobile A1)
+		- "renesas,sysc-sh73a0" (SH-Mobile AG5)
+- reg: Two address start and address range blocks for the device:
+         - The first block refers to the normally accessible registers,
+         - the second block refers to the registers protected by the HPB
+	   semaphore.
+
+Optional nodes:
+- pm-domains: This node contains a hierarchy of PM domain nodes, which should
+  match the Power Area Hierarchy in the Power Domain Specifications section of
+  the device's datasheet.
+
+
+== PM Domain Nodes ==
+
+Each of the PM domain nodes represents a PM domain, as documented by the
+generic PM domain bindings in
+Documentation/devicetree/bindings/power/power_domain.txt.
+
+The nodes should be named by the real power area names, and thus their names
+should be unique.
+
+Required properties:
+  - #power-domain-cells: Must be 0.
+
+Optional properties:
+- reg: If the PM domain is not always-on, this property must contain the bit
+       index number for the corresponding power area in the various Power
+       Control and Status Registers. The parent's node must contain the
+       following two properties:
+	 - #address-cells: Must be 1,
+	 - #size-cells: Must be 0.
+       If the PM domain is always-on, this property must be omitted.
+
+
+Example:
+
+This shows a subset of the r8a7740 PM domain hierarchy, containing the
+C5 "always-on" domain, 2 of its subdomains (A4S and A4SU), and the A3SP domain,
+which is a subdomain of A4S.
+
+	sysc: system-controller@e6180000 {
+		compatible = "renesas,sysc-r8a7740", "renesas,sysc-rmobile";
+		reg = <0xe6180000 0x8000>, <0xe6188000 0x8000>;
+
+		pm-domains {
+			pd_c5: c5 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				#power-domain-cells = <0>;
+
+				pd_a4s: a4s@10 {
+					reg = <10>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+					#power-domain-cells = <0>;
+
+					pd_a3sp: a3sp@11 {
+						reg = <11>;
+						#power-domain-cells = <0>;
+					};
+				};
+
+				pd_a4su: a4su@20 {
+					reg = <20>;
+					#power-domain-cells = <0>;
+				};
+			};
+		};
+	};
+
+
+== PM Domain Consumers ==
+
+Hardware blocks belonging to a PM domain should contain a "power-domains"
+property that is a phandle pointing to the corresponding PM domain node.
+
+Example:
+
+	tpu: pwm@e6600000 {
+		compatible = "renesas,tpu-r8a7740", "renesas,tpu";
+		reg = <0xe6600000 0x100>;
+		clocks = <&mstp3_clks R8A7740_CLK_TPU0>;
+		power-domains = <&pd_a3sp>;
+		#pwm-cells = <3>;
+	};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
index 3300fec..1c80fce 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
@@ -16,20 +16,28 @@
 			   "fsl,pq2-localbus";
 		#address-cells = <2>;
 		#size-cells = <1>;
-		reg = <f0010100 40>;
+		reg = <0xf0010100 0x40>;
 
-		ranges = <0 0 fe000000 02000000
-			  1 0 f4500000 00008000>;
+		ranges = <0x0 0x0 0xfe000000 0x02000000
+			  0x1 0x0 0xf4500000 0x00008000
+			  0x2 0x0 0xfd810000 0x00010000>;
 
 		flash@0,0 {
 			compatible = "jedec-flash";
-			reg = <0 0 2000000>;
+			reg = <0x0 0x0 0x2000000>;
 			bank-width = <4>;
 			device-width = <1>;
 		};
 
 		board-control@1,0 {
-			reg = <1 0 20>;
+			reg = <0x1 0x0 0x20>;
 			compatible = "fsl,mpc8272ads-bcsr";
 		};
+
+		simple-periph@2,0 {
+			compatible = "fsl,elbc-gpcm-uio";
+			reg = <0x2 0x0 0x10000>;
+			elbc-gpcm-br = <0xfd810800>;
+			elbc-gpcm-or = <0xffff09f7>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt b/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt
new file mode 100644
index 0000000..2eb9d4e
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt
@@ -0,0 +1,22 @@
+* Real Time Clock of the Armada 38x SoCs
+
+RTC controller for the Armada 38x SoCs
+
+Required properties:
+- compatible : Should be "marvell,armada-380-rtc"
+- reg: a list of base address and size pairs, one for each entry in
+  reg-names
+- reg names: should contain:
+  * "rtc" for the RTC registers
+  * "rtc-soc" for the SoC related registers and among them the one
+    related to the interrupt.
+- interrupts: IRQ line for the RTC.
+
+Example:
+
+rtc@a3800 {
+	compatible = "marvell,armada-380-rtc";
+	reg = <0xa3800 0x20>, <0x184a0 0x0c>;
+	reg-names = "rtc", "rtc-soc";
+	interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/isil,isl12057.txt b/Documentation/devicetree/bindings/rtc/isil,isl12057.txt
new file mode 100644
index 0000000..501c39c
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/isil,isl12057.txt
@@ -0,0 +1,78 @@
+Intersil ISL12057 I2C RTC/Alarm chip
+
+ISL12057 is a trivial I2C device (it has simple device tree bindings,
+consisting of a compatible field, an address and possibly an interrupt
+line).
+
+Nonetheless, it also supports an option boolean property
+("isil,irq2-can-wakeup-machine") to handle the specific use-case found
+on at least three in-tree users of the chip (NETGEAR ReadyNAS 102, 104
+and 2120 ARM-based NAS); On those devices, the IRQ#2 pin of the chip
+(associated with the alarm supported by the driver) is not connected
+to the SoC but to a PMIC. It allows the device to be powered up when
+RTC alarm rings. In order to mark the device has a wakeup source and
+get access to the 'wakealarm' sysfs entry, this specific property can
+be set when the IRQ#2 pin of the chip is not connected to the SoC but
+can wake up the device.
+
+Required properties supported by the device:
+
+ - "compatible": must be "isil,isl12057"
+ - "reg": I2C bus address of the device
+
+Optional properties:
+
+ - "isil,irq2-can-wakeup-machine": mark the chip as a wakeup source,
+   independently of the availability of an IRQ line connected to the
+   SoC.
+
+ - "interrupt-parent", "interrupts": for passing the interrupt line
+   of the SoC connected to IRQ#2 of the RTC chip.
+
+
+Example isl12057 node without IRQ#2 pin connected (no alarm support):
+
+	isl12057: isl12057@68 {
+		compatible = "isil,isl12057";
+		reg = <0x68>;
+	};
+
+
+Example isl12057 node with IRQ#2 pin connected to main SoC via MPP6 (note
+that the pinctrl-related properties below are given for completeness and
+may not be required or may be different depending on your system or
+SoC, and the main function of the MPP used as IRQ line, i.e.
+"interrupt-parent" and "interrupts" are usually sufficient):
+
+		    pinctrl {
+				...
+
+				rtc_alarm_pin: rtc_alarm_pin {
+					marvell,pins = "mpp6";
+					marvell,function = "gpio";
+				};
+
+				...
+
+		    };
+
+	...
+
+	isl12057: isl12057@68 {
+		compatible = "isil,isl12057";
+		reg = <0x68>;
+		pinctrl-0 = <&rtc_alarm_pin>;
+		pinctrl-names = "default";
+		interrupt-parent = <&gpio0>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+
+Example isl12057 node without IRQ#2 pin connected to the SoC but to a
+PMIC, allowing the device to be started based on configured alarm:
+
+	isl12057: isl12057@68 {
+		compatible = "isil,isl12057";
+		reg = <0x68>;
+		isil,irq2-can-wakeup-machine;
+	};
diff --git a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt
new file mode 100644
index 0000000..5cbc0b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt
@@ -0,0 +1,16 @@
+NXP PCF2123 SPI Real Time Clock
+
+Required properties:
+- compatible: should be: "nxp,rtc-pcf2123"
+- reg: should be the SPI slave chipselect address
+
+Optional properties:
+- spi-cs-high: PCF2123 needs chipselect high
+
+Example:
+
+rtc: nxp,rtc-pcf2123@3 {
+	compatible = "nxp,rtc-pcf2123"
+	reg = <3>
+	spi-cs-high;
+};
diff --git a/Documentation/devicetree/bindings/serial/digicolor-usart.txt b/Documentation/devicetree/bindings/serial/digicolor-usart.txt
new file mode 100644
index 0000000..2d3ede6
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/digicolor-usart.txt
@@ -0,0 +1,27 @@
+Binding for Conexant Digicolor USART
+
+Note: this binding is only applicable for using the USART peripheral as
+UART. USART also support synchronous serial protocols like SPI and I2S. Use
+the binding that matches the wiring of your system.
+
+Required properties:
+- compatible : should be "cnxt,cx92755-usart".
+- reg: Should contain USART controller registers location and length.
+- interrupts: Should contain a single USART controller interrupt.
+- clocks: Must contain phandles to the USART clock
+  See ../clocks/clock-bindings.txt for details.
+
+Note: Each UART port should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+	aliases {
+		serial0 = &uart0;
+	};
+
+	uart0: uart@f0000740 {
+		compatible = "cnxt,cx92755-usart";
+		reg = <0xf0000740 0x20>;
+		clocks = <&main_clk>;
+		interrupts = <44>;
+	};
diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
index 48358a3..4415226 100644
--- a/Documentation/devicetree/bindings/serial/mtk-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -2,9 +2,13 @@
 
 Required properties:
 - compatible should contain:
+  * "mediatek,mt8135-uart" for MT8135 compatible UARTS
+  * "mediatek,mt8127-uart" for MT8127 compatible UARTS
+  * "mediatek,mt8173-uart" for MT8173 compatible UARTS
   * "mediatek,mt6589-uart" for MT6589 compatible UARTS
   * "mediatek,mt6582-uart" for MT6582 compatible UARTS
-  * "mediatek,mt6577-uart" for all compatible UARTS (MT6589, MT6582, MT6577)
+  * "mediatek,mt6577-uart" for all compatible UARTS (MT8173, MT6589, MT6582, 
+	MT6577)
 
 - reg: The base address of the UART register bank.
 
diff --git a/Documentation/devicetree/bindings/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
index bea60ef..91d5ab0 100644
--- a/Documentation/devicetree/bindings/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/serial/of-serial.txt
@@ -19,6 +19,7 @@
 	- "altr,16550-FIFO64"
 	- "altr,16550-FIFO128"
 	- "fsl,16550-FIFO64"
+	- "fsl,ns16550"
 	- "serial" if the port type is unknown.
 - reg : offset and length of the register set for the device.
 - interrupts : should contain uart interrupt.
@@ -43,6 +44,17 @@
   driver is allowed to detect support for the capability even without this
   property.
 
+Note:
+* fsl,ns16550:
+  ------------
+  Freescale DUART is very similar to the PC16552D (and to a
+  pair of NS16550A), albeit with some nonstandard behavior such as
+  erratum A-004737 (relating to incorrect BRK handling).
+
+  Represents a single port that is compatible with the DUART found
+  on many Freescale chips (examples include mpc8349, mpc8548,
+  mpc8641d, p4080 and ls2085a).
+
 Example:
 
 	uart@80230000 {
diff --git a/Documentation/devicetree/bindings/serial/sirf-uart.txt b/Documentation/devicetree/bindings/serial/sirf-uart.txt
index 3acdd96..f0c3926 100644
--- a/Documentation/devicetree/bindings/serial/sirf-uart.txt
+++ b/Documentation/devicetree/bindings/serial/sirf-uart.txt
@@ -2,7 +2,7 @@
 
 Required properties:
 - compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
-		"sirf,marco-uart" or "sirf,marco-bt-uart" which means
+		"sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
 		uart located in BT module and used for BT.
 - reg : Offset and length of the register set for the device
 - interrupts : Should contain uart interrupt
@@ -37,7 +37,7 @@
 for uart use in BT module,
 uart6: uart@11000000 {
 	cell-index = <6>;
-	compatible = "sirf,marco-bt-uart", "sirf,marco-uart";
+	compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
 	reg = <0x11000000 0x1000>;
 	interrupts = <0 100 0>;
 	clocks = <&clks 138>, <&clks 140>, <&clks 141>;
diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.txt b/Documentation/devicetree/bindings/serial/sprd-uart.txt
new file mode 100644
index 0000000..2aff0f2
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/sprd-uart.txt
@@ -0,0 +1,7 @@
+* Spreadtrum serial UART
+
+Required properties:
+- compatible: must be "sprd,sc9836-uart"
+- reg: offset and length of the register set for the device
+- interrupts: exactly one interrupt specifier
+- clocks: phandles to input clocks.
diff --git a/Documentation/devicetree/bindings/sound/atmel_ac97c.txt b/Documentation/devicetree/bindings/sound/atmel_ac97c.txt
new file mode 100644
index 0000000..b151bd9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel_ac97c.txt
@@ -0,0 +1,20 @@
+* Atmel AC97 controller
+
+Required properties:
+  - compatible: "atmel,at91sam9263-ac97c"
+  - reg: Address and length of the register set for the device
+  - interrupts: Should contain AC97 interrupt
+  - ac97-gpios: Please refer to soc-ac97link.txt, only ac97-reset is used
+Optional properties:
+  - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
+
+Example:
+sound@fffa0000 {
+       compatible = "atmel,at91sam9263-ac97c";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_ac97>;
+       reg = <0xfffa0000 0x4000>;
+       interrupts = <18 IRQ_TYPE_LEVEL_HIGH 5>;
+
+       ac97-gpios = <&pioB 0 0 &pioB 2 0 &pioC 29 GPIO_ACTIVE_LOW>;
+};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index ee05dc3..3075377 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -12,9 +12,9 @@
                                property is not present, then the touchscreen is
                                disabled. 5 wires is valid for i.MX28 SoC only.
 - fsl,ave-ctrl: number of samples per direction to calculate an average value.
-                Allowed value is 1 ... 31, default is 4
+                Allowed value is 1 ... 32, default is 4
 - fsl,ave-delay: delay between consecutive samples. Allowed value is
-                 1 ... 2047. It is used if 'fsl,ave-ctrl' > 1, counts at
+                 2 ... 2048. It is used if 'fsl,ave-ctrl' > 1, counts at
                  2 kHz and its default is 2 (= 1 ms)
 - fsl,settling: delay between plate switch to next sample. Allowed value is
                 1 ... 2047. It counts at 2 kHz and its default is
diff --git a/Documentation/devicetree/bindings/timer/digicolor-timer.txt b/Documentation/devicetree/bindings/timer/digicolor-timer.txt
new file mode 100644
index 0000000..d1b659b
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/digicolor-timer.txt
@@ -0,0 +1,18 @@
+Conexant Digicolor SoCs Timer Controller
+
+Required properties:
+
+- compatible : should be "cnxt,cx92755-timer"
+- reg : Specifies base physical address and size of the "Agent Communication"
+  timer registers
+- interrupts : Contains 8 interrupts, one for each timer
+- clocks: phandle to the main clock
+
+Example:
+
+	timer@f0000fc0 {
+		compatible = "cnxt,cx92755-timer";
+		reg = <0xf0000fc0 0x40>;
+		interrupts = <19>, <31>, <34>, <35>, <52>, <53>, <54>, <55>;
+		clocks = <&main_clk>;
+	};
diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
new file mode 100644
index 0000000..87f0b00
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
@@ -0,0 +1,18 @@
+Rockchip rk3288 timer
+
+Required properties:
+- compatible: shall be "rockchip,rk3288-timer"
+- reg: base address of the timer register starting with TIMERS CONTROL register
+- interrupts: should contain the interrupts for Timer0
+- clocks : must contain an entry for each entry in clock-names
+- clock-names : must include the following entries:
+  "timer", "pclk"
+
+Example:
+	timer: timer@ff810000 {
+		compatible = "rockchip,rk3288-timer";
+		reg = <0xff810000 0x20>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&xin24m>, <&cru PCLK_TIMER>;
+		clock-names = "timer", "pclk";
+	};
diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt
index bc2222c..e180d56 100644
--- a/Documentation/devicetree/bindings/usb/atmel-usb.txt
+++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt
@@ -33,9 +33,17 @@
 AT91 USB device controller
 
 Required properties:
- - compatible: Should be "atmel,at91rm9200-udc"
+ - compatible: Should be one of the following
+	       "atmel,at91rm9200-udc"
+	       "atmel,at91sam9260-udc"
+	       "atmel,at91sam9261-udc"
+	       "atmel,at91sam9263-udc"
  - reg: Address and length of the register set for the device
  - interrupts: Should contain macb interrupt
+ - clocks: Should reference the peripheral and the AHB clocks
+ - clock-names: Should contains two strings
+		"pclk" for the peripheral clock
+		"hclk" for the AHB clock
 
 Optional properties:
  - atmel,vbus-gpio: If present, specifies a gpio that needs to be
@@ -51,7 +59,10 @@
 Atmel High-Speed USB device controller
 
 Required properties:
- - compatible: Should be "atmel,at91sam9rl-udc"
+ - compatible: Should be one of the following
+	       "at91sam9rl-udc"
+	       "at91sam9g45-udc"
+	       "sama5d3-udc"
  - reg: Address and length of the register set for the device
  - interrupts: Should contain usba interrupt
  - ep childnode: To specify the number of endpoints and their properties.
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt
index 482f815..fd132cb 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.txt
+++ b/Documentation/devicetree/bindings/usb/dwc2.txt
@@ -20,6 +20,10 @@
 Refer to phy/phy-bindings.txt for generic phy consumer properties
 - dr_mode: shall be one of "host", "peripheral" and "otg"
   Refer to usb/generic.txt
+- g-use-dma: enable dma usage in gadget driver.
+- g-rx-fifo-size: size of rx fifo size in gadget mode.
+- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
+- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
index b08c903..61b045b 100644
--- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
+++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt
@@ -14,6 +14,8 @@
 			 function should be enabled
   - phys: phandle + phy specifier pair
   - phy-names: must be "usb"
+  - dmas: Must contain a list of references to DMA specifiers.
+  - dma-names : Must contain a list of DMA names, "tx" or "rx".
 
 Example:
 	usbhs: usb@e6590000 {
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index 43c1a4e..0b04fdf 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -12,6 +12,7 @@
  - big-endian-regs : boolean, set this for hcds with big-endian registers
  - big-endian-desc : boolean, set this for hcds with big-endian descriptors
  - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+ - needs-reset-on-resume : boolean, set this to force EHCI reset after resume
  - clocks : a list of phandle + clock specifier pairs
  - phys : phandle + phy specifier pair
  - phy-names : "usb"
diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
index 1bd37fa..5be01c8 100644
--- a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -13,10 +13,15 @@
 - clock-frequency: the clock frequency (in Hz) that the PHY clock must
   be configured to.
 
-- vcc-supply: phandle to the regulator that provides RESET to the PHY.
+- vcc-supply: phandle to the regulator that provides power to the PHY.
 
 - reset-gpios: Should specify the GPIO for reset.
 
+- vbus-detect-gpio: should specify the GPIO detecting a VBus insertion
+                    (see Documentation/devicetree/bindings/gpio/gpio.txt)
+- vbus-regulator : should specifiy the regulator supplying current drawn from
+  the VBus line (see Documentation/devicetree/bindings/regulator/regulator.txt).
+
 Example:
 
 	hsusb1_phy {
@@ -26,8 +31,11 @@
 		clock-names = "main_clk";
 		vcc-supply = <&hsusb1_vcc_regulator>;
 		reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+		vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>;
+		vbus-regulator = <&vbus_regulator>;
 	};
 
 hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
 and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
 hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET.
+GPIO 13 detects VBus insertion, and accordingly notifies the vbus-regulator.
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 7075698..389ca13 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -4,6 +4,7 @@
 using them to avoid name-space collisions.
 
 abilis	Abilis Systems
+abcn	Abracon Corporation
 active-semi	Active-Semi International Inc
 ad	Avionic Design GmbH
 adapteva	Adapteva, Inc.
@@ -11,6 +12,7 @@
 adi	Analog Devices, Inc.
 aeroflexgaisler	Aeroflex Gaisler AB
 allwinner	Allwinner Technology Co., Ltd.
+alphascale	AlphaScale Integrated Circuits Systems, Inc.
 altr	Altera Corp.
 amcc	Applied Micro Circuits Corporation (APM, formally AMCC)
 amd	Advanced Micro Devices (AMD), Inc.
@@ -24,6 +26,7 @@
 atmel	Atmel Corporation
 auo	AU Optronics Corporation
 avago	Avago Technologies
+avic	Shanghai AVIC Optoelectronics Co., Ltd.
 bosch	Bosch Sensortec GmbH
 brcm	Broadcom Corporation
 buffalo	Buffalo, Inc.
@@ -32,11 +35,15 @@
 cavium	Cavium, Inc.
 cdns	Cadence Design Systems Inc.
 chipidea	Chipidea, Inc
+chipspark	ChipSPARK
 chrp	Common Hardware Reference Platform
 chunghwa	Chunghwa Picture Tubes Ltd.
 cirrus	Cirrus Logic, Inc.
+cloudengines	Cloud Engines, Inc.
 cnm	Chips&Media, Inc.
+cnxt	Conexant Systems, Inc.
 cortina	Cortina Systems, Inc.
+cosmic	Cosmic Circuits
 crystalfontz	Crystalfontz America, Inc.
 dallas	Maxim Integrated Products (formerly Dallas Semiconductor)
 davicom	DAVICOM Semiconductor, Inc.
@@ -61,10 +68,12 @@
 everspin	Everspin Technologies, Inc.
 excito	Excito
 fcs	Fairchild Semiconductor
+firefly	Firefly
 fsl	Freescale Semiconductor
 GEFanuc	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 gef	GE Fanuc Intelligent Platforms Embedded Systems, Inc.
 geniatech	Geniatech, Inc.
+giantplus	Giantplus Technology Co., Ltd.
 globalscale	Globalscale Technologies, Inc.
 gmt	Global Mixed-mode Technology, Inc.
 google	Google, Inc.
@@ -123,6 +132,7 @@
 opencores	OpenCores.org
 ovti	OmniVision Technologies
 panasonic	Panasonic Corporation
+parade	Parade Technologies Inc.
 pericom	Pericom Technology Inc.
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
@@ -160,6 +170,7 @@
 solidrun	SolidRun
 sony	Sony Corporation
 spansion	Spansion Inc.
+sprd	Spreadtrum Communications Inc.
 st	STMicroelectronics
 ste	ST-Ericsson
 stericsson	ST-Ericsson
diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
new file mode 100644
index 0000000..c989c38
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ps8622.txt
@@ -0,0 +1,31 @@
+ps8622-bridge bindings
+
+Required properties:
+	- compatible: "parade,ps8622" or "parade,ps8625"
+	- reg: first i2c address of the bridge
+	- sleep-gpios: OF device-tree gpio specification for PD_ pin.
+	- reset-gpios: OF device-tree gpio specification for RST_ pin.
+
+Optional properties:
+	- lane-count: number of DP lanes to use
+	- use-external-pwm: backlight will be controlled by an external PWM
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge@48 {
+		compatible = "parade,ps8622";
+		reg = <0x48>;
+		sleep-gpios = <&gpc3 6 1 0 0>;
+		reset-gpios = <&gpc3 1 1 0 0>;
+		lane-count = <1>;
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/video/bridge/ptn3460.txt b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
new file mode 100644
index 0000000..361971b
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt
@@ -0,0 +1,39 @@
+ptn3460 bridge bindings
+
+Required properties:
+	- compatible: "nxp,ptn3460"
+	- reg: i2c address of the bridge
+	- powerdown-gpio: OF device-tree gpio specification  for PD_N pin.
+	- reset-gpio: OF device-tree gpio specification for RST_N pin.
+	- edid-emulation: The EDID emulation entry to use
+		+-------+------------+------------------+
+		| Value | Resolution | Description      |
+		|   0   |  1024x768  | NXP Generic      |
+		|   1   |  1920x1080 | NXP Generic      |
+		|   2   |  1920x1080 | NXP Generic      |
+		|   3   |  1600x900  | Samsung LTM200KT |
+		|   4   |  1920x1080 | Samsung LTM230HT |
+		|   5   |  1366x768  | NXP Generic      |
+		|   6   |  1600x900  | ChiMei M215HGE   |
+		+-------+------------+------------------+
+
+	- video interfaces: Device node can contain video interface port
+			    nodes for panel according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+	lvds-bridge@20 {
+		compatible = "nxp,ptn3460";
+		reg = <0x20>;
+		powerdown-gpio = <&gpy2 5 1 0 0>;
+		reset-gpio = <&gpx1 5 1 0 0>;
+		edid-emulation = <5>;
+		ports {
+			port@0 {
+				bridge_out: endpoint {
+					remote-endpoint = <&panel_in>;
+				};
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..668091f
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,46 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: Physical base address and length of the controller's registers.
+- clocks: phandle to hdmi iahb and isfr clocks.
+- clock-names: should be "iahb" "isfr"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. For
+  vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+  rk3288 platform
+
+Optional properties
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec"
+
+Example:
+hdmi: hdmi@ff980000 {
+	compatible = "rockchip,rk3288-dw-hdmi";
+	reg = <0xff980000 0x20000>;
+	reg-io-width = <4>;
+	ddc-i2c-bus = <&i2c5>;
+	rockchip,grf = <&grf>;
+	interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+	clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+	clock-names = "iahb", "isfr";
+	status = "disabled";
+	ports {
+		hdmi_in: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			hdmi_in_vopb: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&vopb_out_hdmi>;
+			};
+			hdmi_in_vopl: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&vopl_out_hdmi>;
+			};
+		};
+	};
+};
diff --git a/Documentation/devicetree/bindings/video/exynos7-decon.txt b/Documentation/devicetree/bindings/video/exynos7-decon.txt
new file mode 100644
index 0000000..f5f9c8d
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos7-decon.txt
@@ -0,0 +1,68 @@
+Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON)
+
+DECON (Display and Enhancement Controller) is the Display Controller for the
+Exynos7 series of SoCs which transfers the image data from a video memory
+buffer to an external LCD interface.
+
+Required properties:
+- compatible: value should be "samsung,exynos7-decon";
+
+- reg: physical base address and length of the DECON registers set.
+
+- interrupt-parent: should be the phandle of the decon controller's
+		parent interrupt controller.
+
+- interrupts: should contain a list of all DECON IP block interrupts in the
+		 order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier
+		 format depends on the interrupt controller used.
+
+- interrupt-names: should contain the interrupt names: "fifo", "vsync",
+	"lcd_sys", in the same order as they were listed in the interrupts
+        property.
+
+- pinctrl-0: pin control group to be used for this controller.
+
+- pinctrl-names: must contain a "default" entry.
+
+- clocks: must include clock specifiers corresponding to entries in the
+         clock-names property.
+
+- clock-names: list of clock names sorted in the same order as the clocks
+               property. Must contain "pclk_decon0", "aclk_decon0",
+	       "decon0_eclk", "decon0_vclk".
+- i80-if-timings: timing configuration for lcd i80 interface support.
+
+Optional Properties:
+- samsung,power-domain: a phandle to DECON power domain node.
+- display-timings: timing settings for DECON, as described in document [1].
+		Can be used in case timings cannot be provided otherwise
+		or to override timings provided by the panel.
+
+[1]: Documentation/devicetree/bindings/video/display-timing.txt
+
+Example:
+
+SoC specific DT entry:
+
+	decon@13930000 {
+		compatible = "samsung,exynos7-decon";
+		interrupt-parent = <&combiner>;
+		reg = <0x13930000 0x1000>;
+		interrupt-names = "lcd_sys", "vsync", "fifo";
+		interrupts = <0 188 0>, <0 189 0>, <0 190 0>;
+		clocks = <&clock_disp PCLK_DECON_INT>,
+			 <&clock_disp ACLK_DECON_INT>,
+			 <&clock_disp SCLK_DECON_INT_ECLK>,
+			 <&clock_disp SCLK_DECON_INT_EXTCLKPLL>;
+		clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk",
+				"decon0_vclk";
+		status = "disabled";
+	};
+
+Board specific DT entry:
+
+	decon@13930000 {
+		pinctrl-0 = <&lcd_clk &pwm1_out>;
+		pinctrl-names = "default";
+		status = "okay";
+	};
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
index 53dbccf..7a3a9cd 100644
--- a/Documentation/devicetree/bindings/video/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -66,6 +66,10 @@
 		Hotplug detect GPIO.
 			Indicates which GPIO should be used for hotplug
 			detection
+	-video interfaces: Device node can contain video interface port
+			    nodes according to [1].
+
+[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
 
 Example:
 
@@ -105,4 +109,12 @@
 				vsync-len = <6>;
 			};
 		};
+
+		ports {
+			port@0 {
+				dp_out: endpoint {
+					remote-endpoint = <&bridge_in>;
+				};
+			};
+		};
 	};
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt
index ca2b4aa..802aa7e 100644
--- a/Documentation/devicetree/bindings/video/exynos_dsim.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt
@@ -21,7 +21,7 @@
     according to DSI host bindings (see MIPI DSI bindings [1])
 
 Optional properties:
-  - samsung,power-domain: a phandle to DSIM power domain node
+  - power-domains: a phandle to DSIM power domain node
 
 Child nodes:
   Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
@@ -53,7 +53,7 @@
 		phy-names = "dsim";
 		vddcore-supply = <&vusb_reg>;
 		vddio-supply = <&vmipi_reg>;
-		samsung,power-domain = <&pd_lcd0>;
+		power-domains = <&pd_lcd0>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		samsung,pll-clock-frequency = <24000000>;
diff --git a/Documentation/devicetree/bindings/video/exynos_mixer.txt b/Documentation/devicetree/bindings/video/exynos_mixer.txt
index 08b394b..3e38128 100644
--- a/Documentation/devicetree/bindings/video/exynos_mixer.txt
+++ b/Documentation/devicetree/bindings/video/exynos_mixer.txt
@@ -15,6 +15,7 @@
 	a) mixer: Gate of Mixer IP bus clock.
 	b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of
                mixer mux.
+	c) hdmi: Gate of HDMI IP bus clock, needed together with sclk_hdmi.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/video/renesas,du.txt b/Documentation/devicetree/bindings/video/renesas,du.txt
index 5102830..c902323 100644
--- a/Documentation/devicetree/bindings/video/renesas,du.txt
+++ b/Documentation/devicetree/bindings/video/renesas,du.txt
@@ -26,6 +26,10 @@
       per LVDS encoder. The functional clocks must be named "du.x" with "x"
       being the channel numerical index. The LVDS clocks must be named
       "lvds.x" with "x" being the LVDS encoder numerical index.
+    - In addition to the functional and encoder clocks, all DU versions also
+      support externally supplied pixel clocks. Those clocks are optional.
+      When supplied they must be named "dclkin.x" with "x" being the input
+      clock numerical index.
 
 Required nodes:
 
diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt
index cf1af63..a8bbbde 100644
--- a/Documentation/devicetree/bindings/video/samsung-fimd.txt
+++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt
@@ -38,7 +38,7 @@
                property. Must contain "sclk_fimd" and "fimd".
 
 Optional Properties:
-- samsung,power-domain: a phandle to FIMD power domain node.
+- power-domains: a phandle to FIMD power domain node.
 - samsung,invert-vden: video enable signal is inverted
 - samsung,invert-vclk: video clock signal is inverted
 - display-timings: timing settings for FIMD, as described in document [1].
@@ -97,7 +97,7 @@
 		interrupts = <11 0>, <11 1>, <11 2>;
 		clocks = <&clock 140>, <&clock 283>;
 		clock-names = "sclk_fimd", "fimd";
-		samsung,power-domain = <&pd_lcd0>;
+		power-domains = <&pd_lcd0>;
 		status = "disabled";
 	};
 
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index b5ab416..6d1e8ee 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -258,6 +258,8 @@
   devm_iio_device_free()
   devm_iio_device_register()
   devm_iio_device_unregister()
+  devm_iio_kfifo_allocate()
+  devm_iio_kfifo_free()
   devm_iio_trigger_alloc()
   devm_iio_trigger_free()
 
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index ac28149..9922939 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -34,6 +34,9 @@
 	- directory containing configfs documentation and example code.
 cramfs.txt
 	- info on the cram filesystem for small storage (ROMs etc).
+dax.txt
+	- info on avoiding the page cache for files stored on CPU-addressable
+	  storage devices.
 debugfs.txt
 	- info on the debugfs filesystem.
 devpts.txt
@@ -154,5 +157,3 @@
 	- info on XFS Self Describing Metadata.
 xfs.txt
 	- info and mount options for the XFS filesystem.
-xip.txt
-	- info on execute-in-place for file mappings.
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index b30753c..2ca3d17 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -199,8 +199,6 @@
 	int (*releasepage) (struct page *, int);
 	void (*freepage)(struct page *);
 	int (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
-	int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **,
-				unsigned long *);
 	int (*migratepage)(struct address_space *, struct page *, struct page *);
 	int (*launder_page)(struct page *);
 	int (*is_partially_uptodate)(struct page *, unsigned long, unsigned long);
@@ -225,7 +223,6 @@
 releasepage:		yes
 freepage:		yes
 direct_IO:
-get_xip_mem:					maybe
 migratepage:		yes (both)
 launder_page:		yes
 is_partially_uptodate:	yes
diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt
new file mode 100644
index 0000000..baf4111
--- /dev/null
+++ b/Documentation/filesystems/dax.txt
@@ -0,0 +1,94 @@
+Direct Access for files
+-----------------------
+
+Motivation
+----------
+
+The page cache is usually used to buffer reads and writes to files.
+It is also used to provide the pages which are mapped into userspace
+by a call to mmap.
+
+For block devices that are memory-like, the page cache pages would be
+unnecessary copies of the original storage.  The DAX code removes the
+extra copy by performing reads and writes directly to the storage device.
+For file mappings, the storage device is mapped directly into userspace.
+
+
+Usage
+-----
+
+If you have a block device which supports DAX, you can make a filesystem
+on it as usual.  When mounting it, use the -o dax option manually
+or add 'dax' to the options in /etc/fstab.
+
+
+Implementation Tips for Block Driver Writers
+--------------------------------------------
+
+To support DAX in your block driver, implement the 'direct_access'
+block device operation.  It is used to translate the sector number
+(expressed in units of 512-byte sectors) to a page frame number (pfn)
+that identifies the physical page for the memory.  It also returns a
+kernel virtual address that can be used to access the memory.
+
+The direct_access method takes a 'size' parameter that indicates the
+number of bytes being requested.  The function should return the number
+of bytes that can be contiguously accessed at that offset.  It may also
+return a negative errno if an error occurs.
+
+In order to support this method, the storage must be byte-accessible by
+the CPU at all times.  If your device uses paging techniques to expose
+a large amount of memory through a smaller window, then you cannot
+implement direct_access.  Equally, if your device can occasionally
+stall the CPU for an extended period, you should also not attempt to
+implement direct_access.
+
+These block devices may be used for inspiration:
+- axonram: Axon DDR2 device driver
+- brd: RAM backed block device driver
+- dcssblk: s390 dcss block device driver
+
+
+Implementation Tips for Filesystem Writers
+------------------------------------------
+
+Filesystem support consists of
+- adding support to mark inodes as being DAX by setting the S_DAX flag in
+  i_flags
+- implementing the direct_IO address space operation, and calling
+  dax_do_io() instead of blockdev_direct_IO() if S_DAX is set
+- implementing an mmap file operation for DAX files which sets the
+  VM_MIXEDMAP flag on the VMA, and setting the vm_ops to include handlers
+  for fault and page_mkwrite (which should probably call dax_fault() and
+  dax_mkwrite(), passing the appropriate get_block() callback)
+- calling dax_truncate_page() instead of block_truncate_page() for DAX files
+- calling dax_zero_page_range() instead of zero_user() for DAX files
+- ensuring that there is sufficient locking between reads, writes,
+  truncates and page faults
+
+The get_block() callback passed to the DAX functions may return
+uninitialised extents.  If it does, it must ensure that simultaneous
+calls to get_block() (for example by a page-fault racing with a read()
+or a write()) work correctly.
+
+These filesystems may be used for inspiration:
+- ext2: the second extended filesystem, see Documentation/filesystems/ext2.txt
+- ext4: the fourth extended filesystem, see Documentation/filesystems/ext4.txt
+
+
+Shortcomings
+------------
+
+Even if the kernel or its modules are stored on a filesystem that supports
+DAX on a block device that supports DAX, they will still be copied into RAM.
+
+The DAX code does not work correctly on architectures which have virtually
+mapped caches such as ARM, MIPS and SPARC.
+
+Calling get_user_pages() on a range of user memory that has been mmaped
+from a DAX file will fail as there are no 'struct page' to describe
+those pages.  This problem is being worked on.  That means that O_DIRECT
+reads/writes to those memory ranges from a non-DAX file will fail (note
+that O_DIRECT reads/writes _of a DAX file_ do work, it is the memory
+that is being accessed that is key here).  Other things that will not
+work include RDMA, sendfile() and splice().
diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index 67639f9..b971456 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -20,6 +20,9 @@
 check=none, nocheck	(*)	Don't do extra checking of bitmaps on mount
 				(check=normal and check=strict options removed)
 
+dax				Use direct access (no page cache).  See
+				Documentation/filesystems/dax.txt.
+
 debug				Extra debugging information is sent to the
 				kernel syslog.  Useful for developers.
 
@@ -56,8 +59,6 @@
 
 nobh				Do not attach buffer_heads to file pagecache.
 
-xip				Use execute in place (no caching) if possible
-
 grpquota,noquota,quota,usrquota	Quota options are silently ignored by ext2.
 
 
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 919a329..6c0108e 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -386,6 +386,10 @@
 i_version		Enable 64-bit inode version support. This option is
 			off by default.
 
+dax			Use direct access (no page cache).  See
+			Documentation/filesystems/dax.txt.  Note that
+			this option is incompatible with data=journal.
+
 Data Mode
 =========
 There are 3 different data modes:
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 43ce050..966b228 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -591,8 +591,6 @@
 	int (*releasepage) (struct page *, int);
 	void (*freepage)(struct page *);
 	ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
-	struct page* (*get_xip_page)(struct address_space *, sector_t,
-			int);
 	/* migrate the contents of a page to the specified target */
 	int (*migratepage) (struct page *, struct page *);
 	int (*launder_page) (struct page *);
@@ -748,11 +746,6 @@
         and transfer data directly between the storage and the
         application's address space.
 
-  get_xip_page: called by the VM to translate a block number to a page.
-	The page is valid until the corresponding filesystem is unmounted.
-	Filesystems that want to use execute-in-place (XIP) need to implement
-	it.  An example implementation can be found in fs/ext2/xip.c.
-
   migrate_page:  This is used to compact the physical memory usage.
         If the VM wants to relocate a page (maybe off a memory card
         that is signalling imminent failure) it will pass a new page
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
deleted file mode 100644
index b774729..0000000
--- a/Documentation/filesystems/xip.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-Execute-in-place for file mappings
-----------------------------------
-
-Motivation
-----------
-File mappings are performed by mapping page cache pages to userspace. In
-addition, read&write type file operations also transfer data from/to the page
-cache.
-
-For memory backed storage devices that use the block device interface, the page
-cache pages are in fact copies of the original storage. Various approaches
-exist to work around the need for an extra copy. The ramdisk driver for example
-does read the data into the page cache, keeps a reference, and discards the
-original data behind later on.
-
-Execute-in-place solves this issue the other way around: instead of keeping
-data in the page cache, the need to have a page cache copy is eliminated
-completely. With execute-in-place, read&write type operations are performed
-directly from/to the memory backed storage device. For file mappings, the
-storage device itself is mapped directly into userspace.
-
-This implementation was initially written for shared memory segments between
-different virtual machines on s390 hardware to allow multiple machines to
-share the same binaries and libraries.
-
-Implementation
---------------
-Execute-in-place is implemented in three steps: block device operation,
-address space operation, and file operations.
-
-A block device operation named direct_access is used to translate the
-block device sector number to a page frame number (pfn) that identifies
-the physical page for the memory.  It also returns a kernel virtual
-address that can be used to access the memory.
-
-The direct_access method takes a 'size' parameter that indicates the
-number of bytes being requested.  The function should return the number
-of bytes that can be contiguously accessed at that offset.  It may also
-return a negative errno if an error occurs.
-
-The block device operation is optional, these block devices support it as of
-today:
-- dcssblk: s390 dcss block device driver
-
-An address space operation named get_xip_mem is used to retrieve references
-to a page frame number and a kernel address. To obtain these values a reference
-to an address_space is provided. This function assigns values to the kmem and
-pfn parameters. The third argument indicates whether the function should allocate
-blocks if needed.
-
-This address space operation is mutually exclusive with readpage&writepage that
-do page cache read/write operations.
-The following filesystems support it as of today:
-- ext2: the second extended filesystem, see Documentation/filesystems/ext2.txt
-
-A set of file operations that do utilize get_xip_page can be found in
-mm/filemap_xip.c . The following file operation implementations are provided:
-- aio_read/aio_write
-- readv/writev
-- sendfile
-
-The generic file operations do_sync_read/do_sync_write can be used to implement
-classic synchronous IO calls.
-
-Shortcomings
-------------
-This implementation is limited to storage devices that are cpu addressable at
-all times (no highmem or such). It works well on rom/ram, but enhancements are
-needed to make it work with flash in read+write mode.
-Putting the Linux kernel and/or its modules on a xip filesystem does not mean
-they are not copied.
diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt
new file mode 100644
index 0000000..092fc10
--- /dev/null
+++ b/Documentation/kasan.txt
@@ -0,0 +1,170 @@
+Kernel address sanitizer
+================
+
+0. Overview
+===========
+
+Kernel Address sanitizer (KASan) is a dynamic memory error detector. It provides
+a fast and comprehensive solution for finding use-after-free and out-of-bounds
+bugs.
+
+KASan uses compile-time instrumentation for checking every memory access,
+therefore you will need a certain version of GCC > 4.9.2
+
+Currently KASan is supported only for x86_64 architecture and requires that the
+kernel be built with the SLUB allocator.
+
+1. Usage
+=========
+
+To enable KASAN configure kernel with:
+
+	  CONFIG_KASAN = y
+
+and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
+is compiler instrumentation types. The former produces smaller binary the
+latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
+latter.
+
+Currently KASAN works only with the SLUB memory allocator.
+For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
+at least 'slub_debug=U' in the boot cmdline.
+
+To disable instrumentation for specific files or directories, add a line
+similar to the following to the respective kernel Makefile:
+
+        For a single file (e.g. main.o):
+                KASAN_SANITIZE_main.o := n
+
+        For all files in one directory:
+                KASAN_SANITIZE := n
+
+1.1 Error reports
+==========
+
+A typical out of bounds access report looks like this:
+
+==================================================================
+BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
+Write of size 1 by task modprobe/1689
+=============================================================================
+BUG kmalloc-128 (Not tainted): kasan error
+-----------------------------------------------------------------------------
+
+Disabling lock debugging due to kernel taint
+INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689
+ __slab_alloc+0x4b4/0x4f0
+ kmem_cache_alloc_trace+0x10b/0x190
+ kmalloc_oob_right+0x3d/0x75 [test_kasan]
+ init_module+0x9/0x47 [test_kasan]
+ do_one_initcall+0x99/0x200
+ load_module+0x2cb3/0x3b20
+ SyS_finit_module+0x76/0x80
+ system_call_fastpath+0x12/0x17
+INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
+INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
+
+Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ
+Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
+Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
+Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc                          ........
+Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
+CPU: 0 PID: 1689 Comm: modprobe Tainted: G    B          3.18.0-rc1-mm1+ #98
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
+ ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78
+ ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8
+ ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558
+Call Trace:
+ [<ffffffff81cc68ae>] dump_stack+0x46/0x58
+ [<ffffffff811fd848>] print_trailer+0xf8/0x160
+ [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
+ [<ffffffff811ff0f5>] object_err+0x35/0x40
+ [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
+ [<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0
+ [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
+ [<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40
+ [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40
+ [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]
+ [<ffffffff8120a995>] __asan_store1+0x75/0xb0
+ [<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]
+ [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan]
+ [<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan]
+ [<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan]
+ [<ffffffff810002d9>] do_one_initcall+0x99/0x200
+ [<ffffffff811e4e5c>] ? __vunmap+0xec/0x160
+ [<ffffffff81114f63>] load_module+0x2cb3/0x3b20
+ [<ffffffff8110fd70>] ? m_show+0x240/0x240
+ [<ffffffff81115f06>] SyS_finit_module+0x76/0x80
+ [<ffffffff81cd3129>] system_call_fastpath+0x12/0x17
+Memory state around the buggy address:
+ ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
+ ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
+>ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc
+                                                 ^
+ ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+ ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb
+ ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+ ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+==================================================================
+
+First sections describe slub object where bad access happened.
+See 'SLUB Debug output' section in Documentation/vm/slub.txt for details.
+
+In the last section the report shows memory state around the accessed address.
+Reading this part requires some more understanding of how KASAN works.
+
+Each 8 bytes of memory are encoded in one shadow byte as accessible,
+partially accessible, freed or they can be part of a redzone.
+We use the following encoding for each shadow byte: 0 means that all 8 bytes
+of the corresponding memory region are accessible; number N (1 <= N <= 7) means
+that the first N bytes are accessible, and other (8 - N) bytes are not;
+any negative value indicates that the entire 8-byte word is inaccessible.
+We use different negative values to distinguish between different kinds of
+inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
+
+In the report above the arrows point to the shadow byte 03, which means that
+the accessed address is partially accessible.
+
+
+2. Implementation details
+========================
+
+From a high level, our approach to memory error detection is similar to that
+of kmemcheck: use shadow memory to record whether each byte of memory is safe
+to access, and use compile-time instrumentation to check shadow memory on each
+memory access.
+
+AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory
+(e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and
+offset to translate a memory address to its corresponding shadow address.
+
+Here is the function witch translate an address to its corresponding shadow
+address:
+
+static inline void *kasan_mem_to_shadow(const void *addr)
+{
+	return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
+		+ KASAN_SHADOW_OFFSET;
+}
+
+where KASAN_SHADOW_SCALE_SHIFT = 3.
+
+Compile-time instrumentation used for checking memory accesses. Compiler inserts
+function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
+access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
+valid or not by checking corresponding shadow memory.
+
+GCC 5.0 has possibility to perform inline instrumentation. Instead of making
+function calls GCC directly inserts the code to check the shadow memory.
+This option significantly enlarges kernel but it gives x1.1-x2 performance
+boost over outline instrumented kernel.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a89e326..bfcb1a6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -970,6 +970,18 @@
 
 		smh	Use ARM semihosting calls for early console.
 
+		s3c2410,<addr>
+		s3c2412,<addr>
+		s3c2440,<addr>
+		s3c6400,<addr>
+		s5pv210,<addr>
+		exynos4210,<addr>
+			Use early console provided by serial driver available
+			on Samsung SoCs, requires selecting proper type and
+			a correct base address of the selected UART port. The
+			serial port must already be setup and configured.
+			Options are not yet supported.
+
 	earlyprintk=	[X86,SH,BLACKFIN,ARM,M68k]
 			earlyprintk=vga
 			earlyprintk=efi
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index aee73e7..02f8331 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -32,18 +32,42 @@
  - If the patch covers files in net/ or drivers/net please follow netdev stable
    submission guidelines as described in
    Documentation/networking/netdev-FAQ.txt
- - Send the patch, after verifying that it follows the above rules, to
-   stable@vger.kernel.org.  You must note the upstream commit ID in the
-   changelog of your submission, as well as the kernel version you wish
-   it to be applied to.
- - To have the patch automatically included in the stable tree, add the tag
+ - Security patches should not be handled (solely) by the -stable review
+   process but should follow the procedures in Documentation/SecurityBugs.
+
+For all other submissions, choose one of the following procedures:
+
+   --- Option 1 ---
+
+   To have the patch automatically included in the stable tree, add the tag
      Cc: stable@vger.kernel.org
    in the sign-off area. Once the patch is merged it will be applied to
    the stable tree without anything else needing to be done by the author
    or subsystem maintainer.
- - If the patch requires other patches as prerequisites which can be
-   cherry-picked, then this can be specified in the following format in
-   the sign-off area:
+
+   --- Option 2 ---
+
+   After the patch has been merged to Linus' tree, send an email to
+   stable@vger.kernel.org containing the subject of the patch, the commit ID,
+   why you think it should be applied, and what kernel version you wish it to
+   be applied to.
+
+   --- Option 3 ---
+
+   Send the patch, after verifying that it follows the above rules, to
+   stable@vger.kernel.org.  You must note the upstream commit ID in the
+   changelog of your submission, as well as the kernel version you wish
+   it to be applied to.
+
+Option 1 is probably the easiest and most common. Options 2 and 3 are more
+useful if the patch isn't deemed worthy at the time it is applied to a public
+git tree (for instance, because it deserves more regression testing first).
+Option 3 is especially useful if the patch needs some special handling to apply
+to an older kernel (e.g., if API's have changed in the meantime).
+
+Additionally, some patches submitted via Option 1 may have additional patch
+prerequisites which can be cherry-picked. This can be specified in the following
+format in the sign-off area:
 
      Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
      Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
@@ -57,13 +81,13 @@
      git cherry-pick fd21073
      git cherry-pick <this commit>
 
+Following the submission:
+
  - The sender will receive an ACK when the patch has been accepted into the
    queue, or a NAK if the patch is rejected.  This response might take a few
    days, according to the developer's schedules.
  - If accepted, the patch will be added to the -stable queue, for review by
    other developers and by the relevant subsystem maintainer.
- - Security patches should not be sent to this alias, but instead to the
-   documented security@kernel.org address.
 
 
 Review cycle:
diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt
index bba7dbf..0236155 100644
--- a/Documentation/trace/coresight.txt
+++ b/Documentation/trace/coresight.txt
@@ -46,7 +46,7 @@
   | |   .        | !   | |   .        | !      | !        .   |      | SWD/
   | |   .        | !   | |   .        | !      | !        .   |      | JTAG
   *****************************************************************<-|
- *************************** AMBA Debug ABP ************************
+ *************************** AMBA Debug APB ************************
   *****************************************************************
    |    .          !         .          !        !        .    |
    |    .          *         .          *        *        .    |
@@ -79,7 +79,7 @@
           To trace port                       TPIU= Trace Port Interface Unit
                                               SWD = Serial Wire Debug
 
-While on target configuration of the components is done via the ABP bus,
+While on target configuration of the components is done via the APB bus,
 all trace data are carried out-of-band on the ATB bus.  The CTM provides
 a way to aggregate and distribute signals between CoreSight components.
 
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt
new file mode 100644
index 0000000..076ac7b
--- /dev/null
+++ b/Documentation/usb/gadget-testing.txt
@@ -0,0 +1,728 @@
+This file summarizes information on basic testing of USB functions
+provided by gadgets.
+
+1. ACM function
+2. ECM function
+3. ECM subset function
+4. EEM function
+5. FFS function
+6. HID function
+7. LOOPBACK function
+8. MASS STORAGE function
+9. MIDI function
+10. NCM function
+11. OBEX function
+12. PHONET function
+13. RNDIS function
+14. SERIAL function
+15. SOURCESINK function
+16. UAC1 function
+17. UAC2 function
+18. UVC function
+
+
+1. ACM function
+===============
+
+The function is provided by usb_f_acm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "acm".
+The ACM function provides just one attribute in its function directory:
+
+	port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+
+Testing the ACM function
+------------------------
+
+On the host: cat > /dev/ttyACM<X>
+On the device : cat /dev/ttyGS<Y>
+
+then the other way round
+
+On the device: cat > /dev/ttyGS<Y>
+On the host: cat /dev/ttyACM<X>
+
+2. ECM function
+===============
+
+The function is provided by usb_f_ecm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ecm".
+The ECM function provides these attributes in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+	qmult		- queue length multiplier for high and super speed
+	host_addr	- MAC address of host's end of this
+			Ethernet over USB link
+	dev_addr	- MAC address of device's end of this
+			Ethernet over USB link
+
+and after creating the functions/ecm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the ECM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device: ping <host's IP>
+On the host: ping <device's IP>
+
+3. ECM subset function
+======================
+
+The function is provided by usb_f_ecm_subset.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "geth".
+The ECM subset function provides these attributes in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+	qmult		- queue length multiplier for high and super speed
+	host_addr	- MAC address of host's end of this
+			Ethernet over USB link
+	dev_addr	- MAC address of device's end of this
+			Ethernet over USB link
+
+and after creating the functions/ecm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the ECM subset function
+-------------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device: ping <host's IP>
+On the host: ping <device's IP>
+
+4. EEM function
+===============
+
+The function is provided by usb_f_eem.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "eem".
+The EEM function provides these attributes in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+	qmult		- queue length multiplier for high and super speed
+	host_addr	- MAC address of host's end of this
+			Ethernet over USB link
+	dev_addr	- MAC address of device's end of this
+			Ethernet over USB link
+
+and after creating the functions/eem.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the EEM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device: ping <host's IP>
+On the host: ping <device's IP>
+
+5. FFS function
+===============
+
+The function is provided by usb_f_fs.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ffs".
+The function directory is intentionally empty and not modifiable.
+
+After creating the directory there is a new instance (a "device") of FunctionFS
+available in the system. Once a "device" is available, the user should follow
+the standard procedure for using FunctionFS (mount it, run the userspace
+process which implements the function proper). The gadget should be enabled
+by writing a suitable string to usb_gadget/<gadget>/UDC.
+
+Testing the FFS function
+------------------------
+
+On the device: start the function's userspace daemon, enable the gadget
+On the host: use the USB function provided by the device
+
+6. HID function
+===============
+
+The function is provided by usb_f_hid.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "hid".
+The HID function provides these attributes in its function directory:
+
+	protocol	- HID protocol to use
+	report_desc	- data to be used in HID reports, except data
+			passed with /dev/hidg<X>
+	report_length	- HID report length
+	subclass	- HID subclass to use
+
+For a keyboard the protocol and the subclass are 1, the report_length is 8,
+while the report_desc is:
+
+$ hd my_report_desc
+00000000  05 01 09 06 a1 01 05 07  19 e0 29 e7 15 00 25 01  |..........)...%.|
+00000010  75 01 95 08 81 02 95 01  75 08 81 03 95 05 75 01  |u.......u.....u.|
+00000020  05 08 19 01 29 05 91 02  95 01 75 03 91 03 95 06  |....).....u.....|
+00000030  75 08 15 00 25 65 05 07  19 00 29 65 81 00 c0     |u...%e....)e...|
+0000003f
+
+Such a sequence of bytes can be stored to the attribute with echo:
+
+$ echo -ne \\x05\\x01\\x09\\x06\\xa1.....
+
+Testing the HID function
+------------------------
+
+Device:
+- create the gadget
+- connect the gadget to a host, preferably not the one used
+to control the gadget
+- run a program which writes to /dev/hidg<N>, e.g.
+a userspace program found in Documentation/usb/gadget_hid.txt:
+
+$ ./hid_gadget_test /dev/hidg0 keyboard
+
+Host:
+- observe the keystrokes from the gadget
+
+7. LOOPBACK function
+====================
+
+The function is provided by usb_f_ss_lb.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "Loopback".
+The LOOPBACK function provides these attributes in its function directory:
+
+	qlen		- depth of loopback queue
+	bulk_buflen	- buffer length
+
+Testing the LOOPBACK function
+-----------------------------
+
+device: run the gadget
+host: test-usb
+
+http://www.linux-usb.org/usbtest/testusb.c
+
+8. MASS STORAGE function
+========================
+
+The function is provided by usb_f_mass_storage.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "mass_storage".
+The MASS STORAGE function provides these attributes in its directory:
+files:
+
+	stall		- Set to permit function to halt bulk endpoints.
+			Disabled on some USB devices known not to work
+			correctly. You should set it to true.
+	num_buffers	- Number of pipeline buffers. Valid numbers
+			are 2..4. Available only if
+			CONFIG_USB_GADGET_DEBUG_FILES is set.
+
+and a default lun.0 directory corresponding to SCSI LUN #0.
+
+A new lun can be added with mkdir:
+
+$ mkdir functions/mass_storage.0/partition.5
+
+Lun numbering does not have to be continuous, except for lun #0 which is
+created by default. A maximum of 8 luns can be specified and they all must be
+named following the <name>.<number> scheme. The numbers can be 0..8.
+Probably a good convention is to name the luns "lun.<number>",
+although it is not mandatory.
+
+In each lun directory there are the following attribute files:
+
+	file		- The path to the backing file for the LUN.
+			Required if LUN is not marked as removable.
+	ro		- Flag specifying access to the LUN shall be
+			read-only. This is implied if CD-ROM emulation
+			is enabled as well as when it was impossible
+			to open "filename" in R/W mode.
+	removable	- Flag specifying that LUN shall be indicated as
+			being removable.
+	cdrom		- Flag specifying that LUN shall be reported as
+			being a CD-ROM.
+	nofua		- Flag specifying that FUA flag
+			in SCSI WRITE(10,12)
+
+Testing the MASS STORAGE function
+---------------------------------
+
+device: connect the gadget, enable it
+host: dmesg, see the USB drives appear (if system configured to automatically
+mount)
+
+9. MIDI function
+================
+
+The function is provided by usb_f_midi.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "midi".
+The MIDI function provides these attributes in its function directory:
+
+	buflen		- MIDI buffer length
+	id		- ID string for the USB MIDI adapter
+	in_ports	- number of MIDI input ports
+	index		- index value for the USB MIDI adapter
+	out_ports	- number of MIDI output ports
+	qlen		- USB read request queue length
+
+Testing the MIDI function
+-------------------------
+
+There are two cases: playing a mid from the gadget to
+the host and playing a mid from the host to the gadget.
+
+1) Playing a mid from the gadget to the host
+host)
+
+$ arecordmidi -l
+ Port    Client name                      Port name
+ 14:0    Midi Through                     Midi Through Port-0
+ 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+$ arecordmidi -p 24:0 from_gadget.mid
+
+gadget)
+
+$ aplaymidi -l
+ Port    Client name                      Port name
+ 20:0    f_midi                           f_midi
+
+$ aplaymidi -p 20:0 to_host.mid
+
+2) Playing a mid from the host to the gadget
+gadget)
+
+$ arecordmidi -l
+ Port    Client name                      Port name
+ 20:0    f_midi                           f_midi
+
+$ arecordmidi -p 20:0 from_host.mid
+
+host)
+
+$ aplaymidi -l
+ Port    Client name                      Port name
+ 14:0    Midi Through                     Midi Through Port-0
+ 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+
+$ aplaymidi -p24:0 to_gadget.mid
+
+The from_gadget.mid should sound identical to the to_host.mid.
+The from_host.id should sound identical to the to_gadget.mid.
+
+MIDI files can be played to speakers/headphones with e.g. timidity installed
+
+$ aplaymidi -l
+ Port    Client name                      Port name
+ 14:0    Midi Through                     Midi Through Port-0
+ 24:0    MIDI Gadget                      MIDI Gadget MIDI 1
+128:0    TiMidity                         TiMidity port 0
+128:1    TiMidity                         TiMidity port 1
+128:2    TiMidity                         TiMidity port 2
+128:3    TiMidity                         TiMidity port 3
+
+$ aplaymidi -p 128:0 file.mid
+
+MIDI ports can be logically connected using the aconnect utility, e.g.:
+
+$ aconnect 24:0 128:0 # try it on the host
+
+After the gadget's MIDI port is connected to timidity's MIDI port,
+whatever is played at the gadget side with aplaymidi -l is audible
+in host's speakers/headphones.
+
+10. NCM function
+================
+
+The function is provided by usb_f_ncm.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "ncm".
+The NCM function provides these attributes in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+	qmult		- queue length multiplier for high and super speed
+	host_addr	- MAC address of host's end of this
+			Ethernet over USB link
+	dev_addr	- MAC address of device's end of this
+			Ethernet over USB link
+
+and after creating the functions/ncm.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+Testing the NCM function
+------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device: ping <host's IP>
+On the host: ping <device's IP>
+
+11. OBEX function
+=================
+
+The function is provided by usb_f_obex.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "obex".
+The OBEX function provides just one attribute in its function directory:
+
+	port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+Testing the OBEX function
+-------------------------
+
+On device: seriald -f /dev/ttyGS<Y> -s 1024
+On host: serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
+             -t<out endpoint addr> -r<in endpoint addr>
+
+where seriald and serialc are Felipe's utilities found here:
+
+https://git.gitorious.org/usb/usb-tools.git master
+
+12. PHONET function
+===================
+
+The function is provided by usb_f_phonet.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "phonet".
+The PHONET function provides just one attribute in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+
+Testing the PHONET function
+---------------------------
+
+It is not possible to test the SOCK_STREAM protocol without a specific piece
+of hardware, so only SOCK_DGRAM has been tested. For the latter to work,
+in the past I had to apply the patch mentioned here:
+
+http://www.spinics.net/lists/linux-usb/msg85689.html
+
+These tools are required:
+
+git://git.gitorious.org/meego-cellular/phonet-utils.git
+
+On the host:
+
+$ ./phonet -a 0x10 -i usbpn0
+$ ./pnroute add 0x6c usbpn0
+$./pnroute add 0x10 usbpn0
+$ ifconfig usbpn0 up
+
+On the device:
+
+$ ./phonet -a 0x6c -i upnlink0
+$ ./pnroute add 0x10 upnlink0
+$ ifconfig upnlink0 up
+
+Then a test program can be used:
+
+http://www.spinics.net/lists/linux-usb/msg85690.html
+
+On the device:
+
+$ ./pnxmit -a 0x6c -r
+
+On the host:
+
+$ ./pnxmit -a 0x10 -s 0x6c
+
+As a result some data should be sent from host to device.
+Then the other way round:
+
+On the host:
+
+$ ./pnxmit -a 0x10 -r
+
+On the device:
+
+$ ./pnxmit -a 0x6c -s 0x10
+
+13. RNDIS function
+==================
+
+The function is provided by usb_f_rndis.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "rndis".
+The RNDIS function provides these attributes in its function directory:
+
+	ifname		- network device interface name associated with this
+			function instance
+	qmult		- queue length multiplier for high and super speed
+	host_addr	- MAC address of host's end of this
+			Ethernet over USB link
+	dev_addr	- MAC address of device's end of this
+			Ethernet over USB link
+
+and after creating the functions/rndis.<instance name> they contain default
+values: qmult is 5, dev_addr and host_addr are randomly selected.
+Except for ifname they can be written to until the function is linked to a
+configuration. The ifname is read-only and contains the name of the interface
+which was assigned by the net core, e. g. usb0.
+
+By default there can be only 1 RNDIS interface in the system.
+
+Testing the RNDIS function
+--------------------------
+
+Configure IP addresses of the device and the host. Then:
+
+On the device: ping <host's IP>
+On the host: ping <device's IP>
+
+14. SERIAL function
+===================
+
+The function is provided by usb_f_gser.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "gser".
+The SERIAL function provides just one attribute in its function directory:
+
+	port_num
+
+The attribute is read-only.
+
+There can be at most 4 ACM/generic serial/OBEX ports in the system.
+
+Testing the SERIAL function
+---------------------------
+
+On host: insmod usbserial
+	 echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id
+On host: cat > /dev/ttyUSB<X>
+On target: cat /dev/ttyGS<Y>
+
+then the other way round
+
+On target: cat > /dev/ttyGS<Y>
+On host: cat /dev/ttyUSB<X>
+
+15. SOURCESINK function
+=======================
+
+The function is provided by usb_f_ss_lb.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "SourceSink".
+The SOURCESINK function provides these attributes in its function directory:
+
+	pattern		- 0 (all zeros), 1 (mod63), 2 (none)
+	isoc_interval	- 1..16
+	isoc_maxpacket	- 0 - 1023 (fs), 0 - 1024 (hs/ss)
+	isoc_mult	- 0..2 (hs/ss only)
+	isoc_maxburst	- 0..15 (ss only)
+	bulk_buflen	- buffer length
+
+Testing the SOURCESINK function
+-------------------------------
+
+device: run the gadget
+host: test-usb
+
+http://www.linux-usb.org/usbtest/testusb.c
+
+16. UAC1 function
+=================
+
+The function is provided by usb_f_uac1.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uac1".
+The uac1 function provides these attributes in its function directory:
+
+	audio_buf_size - audio buffer size
+	fn_cap - capture pcm device file name
+	fn_cntl - control device file name
+	fn_play - playback pcm device file name
+	req_buf_size - ISO OUT endpoint request buffer size
+	req_count - ISO OUT endpoint request count
+
+The attributes have sane default values.
+
+Testing the UAC1 function
+-------------------------
+
+device: run the gadget
+host: aplay -l # should list our USB Audio Gadget
+
+17. UAC2 function
+=================
+
+The function is provided by usb_f_uac2.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uac2".
+The uac2 function provides these attributes in its function directory:
+
+	chmask - capture channel mask
+	c_srate - capture sampling rate
+	c_ssize - capture sample size (bytes)
+	p_chmask - playback channel mask
+	p_srate - playback sampling rate
+	p_ssize - playback sample size (bytes)
+
+The attributes have sane default values.
+
+Testing the UAC2 function
+-------------------------
+
+device: run the gadget
+host: aplay -l # should list our USB Audio Gadget
+
+This function does not require real hardware support, it just
+sends a stream of audio data to/from the host. In order to
+actually hear something at the device side, a command similar
+to this must be used at the device side:
+
+$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
+
+e.g.:
+
+$ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \
+aplay -D default:CARD=OdroidU3
+
+18. UVC function
+================
+
+The function is provided by usb_f_uvc.ko module.
+
+Function-specific configfs interface
+------------------------------------
+
+The function name to use when creating the function directory is "uvc".
+The uvc function provides these attributes in its function directory:
+
+	streaming_interval - interval for polling endpoint for data transfers
+	streaming_maxburst - bMaxBurst for super speed companion descriptor
+	streaming_maxpacket - maximum packet size this endpoint is capable of
+			      sending or receiving when this configuration is
+			      selected
+
+There are also "control" and "streaming" subdirectories, each of which contain
+a number of their subdirectories. There are some sane defaults provided, but
+the user must provide the following:
+
+	control header - create in control/header, link from control/class/fs
+			and/or control/class/ss
+	streaming header - create in streaming/header, link from
+			streaming/class/fs and/or streaming/class/hs and/or
+			streaming/class/ss
+	format description - create in streaming/mjpeg and/or
+			streaming/uncompressed
+	frame description - create in streaming/mjpeg/<format> and/or in
+			streaming/uncompressed/<format>
+
+Each frame description contains frame interval specification, and each
+such specification consists of a number of lines with an inverval value
+in each line. The rules stated above are best illustrated with an example:
+
+# mkdir functions/uvc.usb0/control/header/h
+# cd functions/uvc.usb0/control/header/h
+# ln -s header/h class/fs
+# ln -s header/h class/ss
+# mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
+# cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
+666666
+1000000
+5000000
+EOF
+# cd $GADGET_CONFIGFS_ROOT
+# mkdir functions/uvc.usb0/streaming/header/h
+# cd functions/uvc.usb0/streaming/header/h
+# ln -s ../../uncompressed/u
+# cd ../../class/fs
+# ln -s ../../header/h
+# cd ../../class/hs
+# ln -s ../../header/h
+# cd ../../class/ss
+# ln -s ../../header/h
+
+
+Testing the UVC function
+------------------------
+
+device: run the gadget, modprobe vivid
+
+# uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>
+
+where uvc-gadget is this program:
+http://git.ideasonboard.org/uvc-gadget.git
+
+with these patches:
+http://www.spinics.net/lists/linux-usb/msg99220.html
+
+host: luvcview -f yuv
diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt
index 61e67f6..6b4a88a 100644
--- a/Documentation/usb/gadget_serial.txt
+++ b/Documentation/usb/gadget_serial.txt
@@ -236,8 +236,12 @@
 E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
 
-You must explicitly load the usbserial driver with parameters to
-configure it to recognize the gadget serial device, like this:
+You must load the usbserial driver and explicitly set its parameters
+to configure it to recognize the gadget serial device, like this:
+
+  echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id
+
+The legacy way is to use module parameters:
 
   modprobe usbserial vendor=0x0525 product=0xA4A6
 
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index 7587d84..28425f7 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -72,7 +72,7 @@
 
 # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
 
-This process will be reading until killed. Naturally, the output can be
+This process will read until it is killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.
 
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
index 006721e..7bd1b97 100644
--- a/Documentation/video4linux/v4l2-pci-skeleton.c
+++ b/Documentation/video4linux/v4l2-pci-skeleton.c
@@ -42,7 +42,6 @@
 MODULE_DESCRIPTION("V4L2 PCI Skeleton Driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
 
 /**
  * struct skeleton - All internal data for one instance of device
@@ -95,6 +94,7 @@
 	/* { PCI_DEVICE(PCI_VENDOR_ID_, PCI_DEVICE_ID_) }, */
 	{ 0, }
 };
+MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl);
 
 /*
  * HDTV: this structure has the capabilities of the HDTV receiver.
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
index 052ee64..05712ac 100644
--- a/Documentation/x86/x86_64/mm.txt
+++ b/Documentation/x86/x86_64/mm.txt
@@ -12,6 +12,8 @@
 ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
 ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
 ... unused hole ...
+ffffec0000000000 - fffffc0000000000 (=44 bits) kasan shadow memory (16TB)
+... unused hole ...
 ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
 ... unused hole ...
 ffffffff80000000 - ffffffffa0000000 (=512 MB)  kernel text mapping, from phys 0
diff --git a/MAINTAINERS b/MAINTAINERS
index debe74c..85024e2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -34,7 +34,7 @@
 	generalized kernel feature ready for next time.
 
 	PLEASE check your patch with the automated style checker
-	(scripts/checkpatch.pl) to catch trival style violations.
+	(scripts/checkpatch.pl) to catch trivial style violations.
 	See Documentation/CodingStyle for guidance here.
 
 	PLEASE CC: the maintainers and mailing lists that are generated
@@ -630,6 +630,8 @@
 T:      git git://people.freedesktop.org/~gabbayo/linux.git
 S:      Supported
 F:      drivers/gpu/drm/amd/amdkfd/
+F:	drivers/gpu/drm/amd/include/cik_structs.h
+F:	drivers/gpu/drm/amd/include/kgd_kfd_interface.h
 F:      drivers/gpu/drm/radeon/radeon_kfd.c
 F:      drivers/gpu/drm/radeon/radeon_kfd.h
 F:      include/uapi/linux/kfd_ioctl.h
@@ -893,6 +895,7 @@
 F:	arch/arm/boot/dts/at91*.dtsi
 F:	arch/arm/boot/dts/sama*.dts
 F:	arch/arm/boot/dts/sama*.dtsi
+F:	arch/arm/include/debug/at91.S
 
 ARM/ATMEL AT91 Clock Support
 M:	Boris Brezillon <boris.brezillon@free-electrons.com>
@@ -974,7 +977,7 @@
 F:	arch/arm/mach-prima2/
 F:	drivers/clk/sirf/
 F:	drivers/clocksource/timer-prima2.c
-F:	drivers/clocksource/timer-marco.c
+F:	drivers/clocksource/timer-atlas7.c
 N:	[^a-z]sirf
 
 ARM/EBSA110 MACHINE SUPPORT
@@ -1173,6 +1176,7 @@
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-mvebu/
+F:	drivers/rtc/armada38x-rtc
 
 ARM/Marvell Berlin SoC support
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@ -1306,10 +1310,13 @@
 
 ARM/QUALCOMM SUPPORT
 M:	Kumar Gala <galak@codeaurora.org>
+M:	Andy Gross <agross@codeaurora.org>
 M:	David Brown <davidb@codeaurora.org>
 L:	linux-arm-msm@vger.kernel.org
+L:	linux-soc@vger.kernel.org
 S:	Maintained
 F:	arch/arm/mach-qcom/
+F:	drivers/soc/qcom/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git
 
 ARM/RADISYS ENP2611 MACHINE SUPPORT
@@ -1411,7 +1418,6 @@
 F:	arch/arm/configs/armadillo800eva_defconfig
 F:	arch/arm/configs/bockw_defconfig
 F:	arch/arm/configs/kzm9g_defconfig
-F:	arch/arm/configs/lager_defconfig
 F:	arch/arm/configs/mackerel_defconfig
 F:	arch/arm/configs/marzen_defconfig
 F:	arch/arm/configs/shmobile_defconfig
@@ -2141,7 +2147,7 @@
 BROADCOM BCM63XX ARM ARCHITECTURE
 M:	Florian Fainelli <f.fainelli@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org
-T:	git git://git.github.com/brcm/linux.git
+T:	git git://github.com/broadcom/arm-bcm63xx.git
 S:	Maintained
 F:	arch/arm/mach-bcm/bcm63xx.c
 F:	arch/arm/include/debug/bcm63xx.S
@@ -2158,6 +2164,7 @@
 M:	Gregory Fong <gregory.0xf0@gmail.com>
 M:	Florian Fainelli <f.fainelli@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+T:	git git://github.com/broadcom/stblinux.git
 S:	Maintained
 F:	arch/arm/mach-bcm/*brcmstb*
 F:	arch/arm/boot/dts/bcm7*.dts*
@@ -2167,6 +2174,7 @@
 M:	Kevin Cernekee <cernekee@gmail.com>
 M:	Florian Fainelli <f.fainelli@gmail.com>
 L:	linux-mips@linux-mips.org
+T:	git git://github.com/broadcom/stblinux.git
 S:	Maintained
 F:	arch/mips/bmips/*
 F:	arch/mips/include/asm/mach-bmips/*
@@ -2209,7 +2217,7 @@
 M:	Scott Branden <sbranden@broadcom.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:	bcm-kernel-feedback-list@broadcom.com
-T:	git git://git.github.com/brcm/linux.git
+T:	git git://github.com/broadcom/cygnus-linux.git
 S:	Maintained
 N:	iproc
 N:	cygnus
@@ -2398,6 +2406,12 @@
 F:	security/commoncap.c
 F:	kernel/capability.c
 
+CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER
+M:	Kevin Tsai <ktsai@capellamicro.com>
+S:	Maintained
+F:	drivers/iio/light/cm*
+F:	Documentation/devicetree/bindings/i2c/trivial-devices.txt
+
 CC2520 IEEE-802.15.4 RADIO DRIVER
 M:	Varka Bhadram <varkabhadram@gmail.com>
 L:	linux-wpan@vger.kernel.org
@@ -2956,6 +2970,12 @@
 F:	drivers/input/touchscreen/cyttsp*
 F:	include/linux/input/cyttsp.h
 
+DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK
+M:	Joshua Kinard <kumba@gentoo.org>
+S:	Maintained
+F:	drivers/rtc/rtc-ds1685.c
+F:	include/linux/rtc/ds1685.h
+
 DAMA SLAVE for AX.25
 M:	Joerg Reuter <jreuter@yaina.de>
 W:	http://yaina.de/jreuter/
@@ -3032,6 +3052,7 @@
 
 DELL LAPTOP SMM DRIVER
 M:	Guenter Roeck <linux@roeck-us.net>
+S:	Maintained
 F:	drivers/char/i8k.c
 F:	include/uapi/linux/i8k.h
 
@@ -3047,7 +3068,7 @@
 F:	drivers/platform/x86/dell-wmi.c
 
 DESIGNWARE USB2 DRD IP DRIVER
-M:	Paul Zimmerman <paulz@synopsys.com>
+M:	John Youn <johnyoun@synopsys.com>
 L:	linux-usb@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:	Maintained
@@ -3143,6 +3164,12 @@
 S:	Maintained
 F:	drivers/i2c/busses/i2c-diolan-u2c.c
 
+DIRECT ACCESS (DAX)
+M:	Matthew Wilcox <willy@linux.intel.com>
+L:	linux-fsdevel@vger.kernel.org
+S:	Supported
+F:	fs/dax.c
+
 DIRECTORY NOTIFICATION (DNOTIFY)
 M:	Eric Paris <eparis@parisplace.org>
 S:	Maintained
@@ -3902,6 +3929,12 @@
 F:	Documentation/fault-injection/
 F:	lib/fault-inject.c
 
+FBTFT Framebuffer drivers
+M:	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+M:	Noralf Trønnes <noralf@tronnes.org>
+S:	Maintained
+F:	drivers/staging/fbtft/
+
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
 M:	Robert Love <robert.w.love@intel.com>
 L:	fcoe-devel@open-fcoe.org
@@ -4433,6 +4466,7 @@
 HARDWARE RANDOM NUMBER GENERATOR CORE
 M:	Matt Mackall <mpm@selenic.com>
 M:	Herbert Xu <herbert@gondor.apana.org.au>
+L:	linux-crypto@vger.kernel.org
 S:	Odd fixes
 F:	Documentation/hw_random.txt
 F:	drivers/char/hw_random/
@@ -6195,6 +6229,26 @@
 F:	drivers/power/max14577_charger.c
 F:	drivers/power/max77693_charger.c
 
+MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
+M:	Chanwoo Choi <cw00.choi@samsung.com>
+M:	Krzysztof Kozlowski <k.kozlowski@samsung.com>
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+F:	drivers/*/max14577.c
+F:	drivers/*/max77686.c
+F:	drivers/*/max77693.c
+F:	drivers/extcon/extcon-max14577.c
+F:	drivers/extcon/extcon-max77693.c
+F:	drivers/rtc/rtc-max77686.c
+F:	drivers/clk/clk-max77686.c
+F:	Documentation/devicetree/bindings/mfd/max14577.txt
+F:	Documentation/devicetree/bindings/mfd/max77686.txt
+F:	Documentation/devicetree/bindings/mfd/max77693.txt
+F:	Documentation/devicetree/bindings/clock/maxim,max77686.txt
+F:	include/linux/mfd/max14577*.h
+F:	include/linux/mfd/max77686*.h
+F:	include/linux/mfd/max77693*.h
+
 MAXIRADIO FM RADIO RECEIVER DRIVER
 M:	Hans Verkuil <hverkuil@xs4all.nl>
 L:	linux-media@vger.kernel.org
@@ -6995,6 +7049,12 @@
 S:	Maintained
 F:	arch/arm/mach-omap2/omap_hwmod.*
 
+OMAP HWMOD DATA
+M:	Paul Walmsley <paul@pwsan.com>
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	arch/arm/mach-omap2/omap_hwmod*data*
+
 OMAP HWMOD DATA FOR OMAP4-BASED DEVICES
 M:	Benoît Cousson <bcousson@baylibre.com>
 L:	linux-omap@vger.kernel.org
@@ -9259,6 +9319,14 @@
 S:	Maintained
 F:	drivers/staging/rtl8723au/
 
+STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER
+M:	Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+M:	Teddy Wang <teddy.wang@siliconmotion.com>
+M:	Sudip Mukherjee <sudip@vectorindia.org>
+L:	linux-fbdev@vger.kernel.org
+S:	Maintained
+F:	drivers/staging/sm7xxfb/
+
 STAGING - SLICOSS
 M:	Lior Dotan <liodot@gmail.com>
 M:	Christopher Harrer <charrer@alacritech.com>
@@ -9988,20 +10056,15 @@
 
 UNSORTED BLOCK IMAGES (UBI)
 M:	Artem Bityutskiy <dedekind1@gmail.com>
+M:	Richard Weinberger <richard@nod.at>
 W:	http://www.linux-mtd.infradead.org/
 L:	linux-mtd@lists.infradead.org
 T:	git git://git.infradead.org/ubifs-2.6.git
-S:	Maintained
+S:	Supported
 F:	drivers/mtd/ubi/
 F:	include/linux/mtd/ubi.h
 F:	include/uapi/mtd/ubi-user.h
 
-UNSORTED BLOCK IMAGES (UBI) Fastmap
-M:	Richard Weinberger <richard@nod.at>
-L:	linux-mtd@lists.infradead.org
-S:	Maintained
-F:	drivers/mtd/ubi/fastmap.c
-
 USB ACM DRIVER
 M:	Oliver Neukum <oliver@neukum.org>
 L:	linux-usb@vger.kernel.org
diff --git a/Makefile b/Makefile
index 5fa2e30..33cb15e 100644
--- a/Makefile
+++ b/Makefile
@@ -423,7 +423,7 @@
 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
 
 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
-export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
+export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -781,6 +781,7 @@
 	KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
 endif
 
+include $(srctree)/scripts/Makefile.kasan
 include $(srctree)/scripts/Makefile.extrawarn
 
 # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h
index ffed3b2..9615fe1 100644
--- a/arch/arc/include/asm/pgtable.h
+++ b/arch/arc/include/asm/pgtable.h
@@ -257,7 +257,8 @@
 #define pmd_clear(xp)			do { pmd_val(*(xp)) = 0; } while (0)
 
 #define pte_page(x) (mem_map + \
-		(unsigned long)(((pte_val(x) - PAGE_OFFSET) >> PAGE_SHIFT)))
+		(unsigned long)(((pte_val(x) - CONFIG_LINUX_LINK_BASE) >> \
+				PAGE_SHIFT)))
 
 #define mk_pte(page, pgprot)						\
 ({									\
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index 210fe97..4e54729 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -56,9 +56,6 @@
 /* Free all resources held by a thread */
 #define release_thread(thread) do { } while (0)
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)    do { } while (0)
-
 /*
  * A lot of busy-wait loops in SMP are based off of non-volatile data otherwise
  * get optimised away by gcc
diff --git a/arch/arc/include/asm/serial.h b/arch/arc/include/asm/serial.h
index 602b097..744a6ae 100644
--- a/arch/arc/include/asm/serial.h
+++ b/arch/arc/include/asm/serial.h
@@ -10,26 +10,13 @@
 #define _ASM_ARC_SERIAL_H
 
 /*
- * early-8250 requires BASE_BAUD to be defined and includes this header.
- * We put in a typical value:
- * 	(core clk / 16) - i.e. UART samples 16 times per sec.
- * Athough in multi-platform-image this might not work, specially if the
- * clk driving the UART is different.
- * We can't use DeviceTree as this is typically for early serial.
+ * early 8250 (now earlycon) requires BASE_BAUD to be defined in this header.
+ * However to still determine it dynamically (for multi-platform images)
+ * we do this in a helper by parsing the FDT early
  */
 
-#include <asm/clk.h>
+extern unsigned int __init arc_early_base_baud(void);
 
-#define BASE_BAUD	(arc_get_core_freq() / 16)
-
-/*
- * This is definitely going to break early 8250 consoles on multi-platform
- * images but hey, it won't add any code complexity for a debug feature of
- * one broken driver.
- */
-#ifdef CONFIG_ARC_PLAT_TB10X
-#undef BASE_BAUD
-#define BASE_BAUD	(arc_get_core_freq() / 16 / 3)
-#endif
+#define BASE_BAUD	arc_early_base_baud()
 
 #endif /* _ASM_ARC_SERIAL_H */
diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c
index fffdb5e..e32b54a 100644
--- a/arch/arc/kernel/devtree.c
+++ b/arch/arc/kernel/devtree.c
@@ -17,6 +17,28 @@
 #include <asm/clk.h>
 #include <asm/mach_desc.h>
 
+#ifdef CONFIG_SERIAL_EARLYCON
+
+static unsigned int __initdata arc_base_baud;
+
+unsigned int __init arc_early_base_baud(void)
+{
+	return arc_base_baud/16;
+}
+
+static void __init arc_set_early_base_baud(unsigned long dt_root)
+{
+	unsigned int core_clk = arc_get_core_freq();
+
+	if (of_flat_dt_is_compatible(dt_root, "abilis,arc-tb10x"))
+		arc_base_baud = core_clk/3;
+	else
+		arc_base_baud = core_clk;
+}
+#else
+#define arc_set_early_base_baud(dt_root)
+#endif
+
 static const void * __init arch_get_next_mach(const char *const **match)
 {
 	static const struct machine_desc *mdesc = __arch_info_begin;
@@ -56,5 +78,7 @@
 	if (clk)
 		arc_set_core_freq(of_read_ulong(clk, len/4));
 
+	arc_set_early_base_baud(dt_root);
+
 	return mdesc;
 }
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 83a046a..d868289 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -736,16 +736,20 @@
 	; put last task in scheduler queue
 	bl   @schedule_tail
 
-	; If kernel thread, jump to its entry-point
 	ld   r9, [sp, PT_status32]
 	brne r9, 0, 1f
 
-	jl.d [r14]
-	mov  r0, r13		; arg to payload
+	jl.d [r14]		; kernel thread entry point
+	mov  r0, r13		; (see PF_KTHREAD block in copy_thread)
 
 1:
-	; special case of kernel_thread entry point returning back due to
-	; kernel_execve() - pretend return from syscall to ret to userland
+	; Return to user space
+	; 1. Any forked task (Reach here via BRne above)
+	; 2. First ever init task (Reach here via return from JL above)
+	;    This is the historic "kernel_execve" use-case, to return to init
+	;    user mode, in a round about way since that is always done from
+	;    a kernel thread which is executed via JL above but always returns
+	;    out whenever kernel_execve (now inline do_fork()) is involved
 	b    ret_from_exception
 END(ret_from_fork)
 
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 252bf60..900f68a 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -412,6 +412,11 @@
 	char *str;
 	int cpu_id = ptr_to_cpu(v);
 
+	if (!cpu_online(cpu_id)) {
+		seq_printf(m, "processor [%d]\t: Offline\n", cpu_id);
+		goto done;
+	}
+
 	str = (char *)__get_free_page(GFP_TEMPORARY);
 	if (!str)
 		goto done;
@@ -429,7 +434,7 @@
 
 	free_page((unsigned long)str);
 done:
-	seq_printf(m, "\n\n");
+	seq_printf(m, "\n");
 
 	return 0;
 }
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 20ebb60..6a400b1 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -221,7 +221,7 @@
 	 * and read back old value
 	 */
 	do {
-		new = old = *ipi_data_ptr;
+		new = old = ACCESS_ONCE(*ipi_data_ptr);
 		new |= 1U << msg;
 	} while (cmpxchg(ipi_data_ptr, old, new) != old);
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0850fc0..9f1f09a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -860,6 +860,8 @@
 
 source "arch/arm/mach-davinci/Kconfig"
 
+source "arch/arm/mach-digicolor/Kconfig"
+
 source "arch/arm/mach-dove/Kconfig"
 
 source "arch/arm/mach-ep93xx/Kconfig"
@@ -1493,7 +1495,7 @@
 # selected platforms.
 config ARCH_NR_GPIO
 	int
-	default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
+	default 1024 if ARCH_SHMOBILE || ARCH_TEGRA || ARCH_ZYNQ
 	default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || \
 		SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210
 	default 416 if ARCH_SUNXI
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index a324ecd..970de75 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -115,16 +115,22 @@
 		    0x80024000      | 0xf0024000     | UART9
 
 	config AT91_DEBUG_LL_DBGU0
-		bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
-		depends on HAVE_AT91_DBGU0
+		bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10, 9rl, 9x5, 9n12"
+		select DEBUG_AT91_UART
+		depends on ARCH_AT91
+		depends on SOC_AT91RM9200 || SOC_AT91SAM9
 
 	config AT91_DEBUG_LL_DBGU1
-		bool "Kernel low-level debugging on 9263 and 9g45"
-		depends on HAVE_AT91_DBGU1
+		bool "Kernel low-level debugging on 9263, 9g45 and sama5d3"
+		select DEBUG_AT91_UART
+		depends on ARCH_AT91
+		depends on SOC_AT91SAM9 || SOC_SAMA5
 
 	config AT91_DEBUG_LL_DBGU2
 		bool "Kernel low-level debugging on sama5d4"
-		depends on HAVE_AT91_DBGU2
+		select DEBUG_AT91_UART
+		depends on ARCH_AT91
+		depends on SOC_SAMA5
 
 	config DEBUG_BCM2835
 		bool "Kernel low-level debugging on BCM2835 PL011 UART"
@@ -241,6 +247,13 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port in the DC21285 (Footbridge).
 
+	config DEBUG_DIGICOLOR_UA0
+		bool "Kernel low-level debugging messages via Digicolor UA0"
+		depends on ARCH_DIGICOLOR
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the UA0 serial port in the CX92755.
+
 	config DEBUG_FOOTBRIDGE_COM1
 		bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
 		depends on FOOTBRIDGE
@@ -272,6 +285,14 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the UART on Highbank based devices.
 
+	config DEBUG_HIP01_UART
+		bool "Hisilicon Hip01 Debug UART"
+		depends on ARCH_HIP01
+		select DEBUG_UART_8250
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on HIP01 UART.
+
 	config DEBUG_HIP04_UART
 		bool "Hisilicon HiP04 Debug UART"
 		depends on ARCH_HIP04
@@ -434,7 +455,7 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on MSM devices.
 
-		  ARCH                DEBUG_UART_PHYS   DEBUG_UART_BASE   #
+		  ARCH                DEBUG_UART_PHYS   DEBUG_UART_VIRT   #
 		  MSM7X00A, QSD8X50   0xa9a00000        0xe1000000        UART1
 		  MSM7X00A, QSD8X50   0xa9b00000        0xe1000000        UART2
 		  MSM7X00A, QSD8X50   0xa9c00000        0xe1000000        UART3
@@ -453,7 +474,8 @@
 		  Say Y here if you want the debug print routines to direct
 		  their output to the serial port on Qualcomm devices.
 
-		  ARCH      DEBUG_UART_PHYS   DEBUG_UART_BASE
+		  ARCH      DEBUG_UART_PHYS   DEBUG_UART_VIRT
+		  APQ8064   0x16640000        0xf0040000
 		  APQ8084   0xf995e000        0xfa75e000
 		  MSM8X60   0x19c40000        0xf0040000
 		  MSM8960   0x16440000        0xf0040000
@@ -462,13 +484,13 @@
 		  Please adjust DEBUG_UART_PHYS and DEBUG_UART_BASE configuration
 		  options based on your needs.
 
-	config DEBUG_MVEBU_UART
-		bool "Kernel low-level debugging messages via MVEBU UART (old bootloaders)"
+	config DEBUG_MVEBU_UART0
+		bool "Kernel low-level debugging messages via MVEBU UART0 (old bootloaders)"
 		depends on ARCH_MVEBU
 		select DEBUG_UART_8250
 		help
 		  Say Y here if you want kernel low-level debugging support
-		  on MVEBU based platforms.
+		  on MVEBU based platforms on UART0.
 
 		  This option should be used with the old bootloaders
 		  that left the internal registers mapped at
@@ -481,13 +503,28 @@
 		  when u-boot hands over to the kernel, the system
 		  silently crashes, with no serial output at all.
 
-	config DEBUG_MVEBU_UART_ALTERNATE
-		bool "Kernel low-level debugging messages via MVEBU UART (new bootloaders)"
+	config DEBUG_MVEBU_UART0_ALTERNATE
+		bool "Kernel low-level debugging messages via MVEBU UART0 (new bootloaders)"
 		depends on ARCH_MVEBU
 		select DEBUG_UART_8250
 		help
 		  Say Y here if you want kernel low-level debugging support
-		  on MVEBU based platforms.
+		  on MVEBU based platforms on UART0.
+
+		  This option should be used with the new bootloaders
+		  that remap the internal registers at 0xf1000000.
+
+		  If the wrong DEBUG_MVEBU_UART* option is selected,
+		  when u-boot hands over to the kernel, the system
+		  silently crashes, with no serial output at all.
+
+	config DEBUG_MVEBU_UART1_ALTERNATE
+		bool "Kernel low-level debugging messages via MVEBU UART1 (new bootloaders)"
+		depends on ARCH_MVEBU
+		select DEBUG_UART_8250
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on MVEBU based platforms on UART1.
 
 		  This option should be used with the new bootloaders
 		  that remap the internal registers at 0xf1000000.
@@ -978,16 +1015,28 @@
 	config DEBUG_SIRFPRIMA2_UART1
 		bool "Kernel low-level debugging messages via SiRFprimaII UART1"
 		depends on ARCH_PRIMA2
+		select DEBUG_SIRFSOC_UART
 		help
 		  Say Y here if you want the debug print routines to direct
 		  their output to the uart1 port on SiRFprimaII devices.
 
-	config DEBUG_SIRFMARCO_UART1
-		bool "Kernel low-level debugging messages via SiRFmarco UART1"
-		depends on ARCH_MARCO
+	config DEBUG_SIRFATLAS7_UART0
+		bool "Kernel low-level debugging messages via SiRFatlas7 UART0"
+		depends on ARCH_ATLAS7
+		select DEBUG_SIRFSOC_UART
 		help
 		  Say Y here if you want the debug print routines to direct
-		  their output to the uart1 port on SiRFmarco devices.
+		  their output to the uart0 port on SiRFATLAS7 devices.The uart0
+		  is used on SiRFATLAS7 as a extra debug port.sometimes an extra
+		  debug port can be very useful.
+
+	config DEBUG_SIRFATLAS7_UART1
+		bool "Kernel low-level debugging messages via SiRFatlas7 UART1"
+		depends on ARCH_ATLAS7
+		select DEBUG_SIRFSOC_UART
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the uart1 port on SiRFATLAS7 devices.
 
 	config STIH41X_DEBUG_ASC2
 		bool "Use StiH415/416 ASC2 UART for low-level debug"
@@ -1035,7 +1084,7 @@
 		  for Mediatek mt6589 based platforms on UART0.
 
 	config DEBUG_MT8127_UART0
-		bool "Mediatek mt8127 UART0"
+		bool "Mediatek mt8127/mt6592 UART0"
 		depends on ARCH_MEDIATEK
 		select DEBUG_UART_8250
 		help
@@ -1162,6 +1211,10 @@
 
 endchoice
 
+config DEBUG_AT91_UART
+	bool
+	depends on ARCH_AT91
+
 config DEBUG_EXYNOS_UART
 	bool
 
@@ -1214,10 +1267,15 @@
 	bool
 	depends on ARCH_STI
 
+config DEBUG_SIRFSOC_UART
+	bool
+	depends on ARCH_SIRF
+
 config DEBUG_LL_INCLUDE
 	string
 	default "debug/sa1100.S" if DEBUG_SA1100
 	default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250
+	default "debug/at91.S" if DEBUG_AT91_UART
 	default "debug/asm9260.S" if DEBUG_ASM9260_UART
 	default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
 	default "debug/meson.S" if DEBUG_MESON_UARTAO
@@ -1250,7 +1308,7 @@
 	default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4
 	default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART
 	default "debug/s5pv210.S" if DEBUG_S5PV210_UART
-	default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
+	default "debug/sirf.S" if DEBUG_SIRFSOC_UART
 	default "debug/sti.S" if DEBUG_STI_UART
 	default "debug/tegra.S" if DEBUG_TEGRA_UART
 	default "debug/ux500.S" if DEBUG_UX500_UART
@@ -1259,6 +1317,7 @@
 	default "debug/vt8500.S" if DEBUG_VT8500_UART0
 	default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
 	default "debug/bcm63xx.S" if DEBUG_UART_BCM63XX
+	default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0
 	default "mach/debug-macro.S"
 
 # Compatibility options for PL01x
@@ -1302,7 +1361,10 @@
 	default 0x11009000 if DEBUG_MT8135_UART3
 	default 0x16000000 if ARCH_INTEGRATOR
 	default 0x18000300 if DEBUG_BCM_5301X
+	default 0x18010000 if DEBUG_SIRFATLAS7_UART0
+	default 0x18020000 if DEBUG_SIRFATLAS7_UART1
 	default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
+	default 0x20001000 if DEBUG_HIP01_UART
 	default 0x20060000 if DEBUG_RK29_UART0
 	default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2
 	default 0x20068000 if DEBUG_RK29_UART2 || DEBUG_RK3X_UART3
@@ -1327,12 +1389,13 @@
 	default 0x808c0000 if ARCH_EP93XX
 	default 0x90020000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART
 	default 0xa9a00000 if DEBUG_MSM_UART
+	default 0xb0060000 if DEBUG_SIRFPRIMA2_UART1
 	default 0xb0090000 if DEBUG_VEXPRESS_UART0_CRX
 	default 0xc0013000 if DEBUG_U300_UART
 	default 0xc8000000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN
 	default 0xc8000003 if ARCH_IXP4XX && CPU_BIG_ENDIAN
 	default 0xd0000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
-	default 0xd0012000 if DEBUG_MVEBU_UART
+	default 0xd0012000 if DEBUG_MVEBU_UART0
 	default 0xc81004c0 if DEBUG_MESON_UARTAO
 	default 0xd4017000 if DEBUG_MMP_UART2
 	default 0xd4018000 if DEBUG_MMP_UART3
@@ -1346,7 +1409,8 @@
 	default 0xe8008000 if DEBUG_R7S72100_SCIF2
 	default 0xf0000be0 if ARCH_EBSA110
 	default 0xf040ab00 if DEBUG_BRCMSTB_UART
-	default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE
+	default 0xf1012000 if DEBUG_MVEBU_UART0_ALTERNATE
+	default 0xf1012100 if DEBUG_MVEBU_UART1_ALTERNATE
 	default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \
 				ARCH_ORION5X
 	default 0xf7fc9000 if DEBUG_BERLIN_UART
@@ -1375,7 +1439,8 @@
 		DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
 		DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
 		DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
-		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
+		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
+		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
 
 config DEBUG_UART_VIRT
 	hex "Virtual base address of debug UART"
@@ -1433,8 +1498,12 @@
 	default 0xfeb30c00 if DEBUG_KEYSTONE_UART0
 	default 0xfeb31000 if DEBUG_KEYSTONE_UART1
 	default 0xfec02000 if DEBUG_SOCFPGA_UART
-	default 0xfec12000 if DEBUG_MVEBU_UART || DEBUG_MVEBU_UART_ALTERNATE
+	default 0xfec12000 if DEBUG_MVEBU_UART0 || DEBUG_MVEBU_UART0_ALTERNATE
+	default 0xfec12100 if DEBUG_MVEBU_UART1_ALTERNATE
+	default 0xfec10000 if DEBUG_SIRFATLAS7_UART0
 	default 0xfec20000 if DEBUG_DAVINCI_DMx_UART0
+	default 0xfec20000 if DEBUG_SIRFATLAS7_UART1
+	default 0xfec60000 if DEBUG_SIRFPRIMA2_UART1
 	default 0xfec90000 if DEBUG_RK32_UART2
 	default 0xfed0c000 if DEBUG_DAVINCI_DA8XX_UART1
 	default 0xfed0d000 if DEBUG_DAVINCI_DA8XX_UART2
@@ -1453,12 +1522,14 @@
 	default 0xfefb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3
 	default 0xfefff700 if ARCH_IOP33X
 	default 0xff003000 if DEBUG_U300_UART
+	default 0xffd01000 if DEBUG_HIP01_UART
 	default DEBUG_UART_PHYS if !MMU
 	depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
 		DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
 		DEBUG_MSM_UART || DEBUG_NETX_UART || \
 		DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
-		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
+		DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
+		DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
 
 config DEBUG_UART_8250_SHIFT
 	int "Register offset shift for the 8250 debug UART"
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 91bd5bd..a1c776b 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -1,83 +1,91 @@
 ifeq ($(CONFIG_OF),y)
 
+dtb-$(CONFIG_MACH_ASM9260) += \
+	alphascale-asm9260-devkit.dtb
 # Keep at91 dtb files sorted alphabetically for each SoC
-# rm9200
-dtb-$(CONFIG_ARCH_AT91) += at91rm9200ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += mpa1600.dtb
-# sam9260
-dtb-$(CONFIG_ARCH_AT91) += animeo_ip.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91-qil_a9260.dtb
-dtb-$(CONFIG_ARCH_AT91) += aks-cdu.dtb
-dtb-$(CONFIG_ARCH_AT91) += ethernut5.dtb
-dtb-$(CONFIG_ARCH_AT91) += evk-pro3.dtb
-dtb-$(CONFIG_ARCH_AT91) += tny_a9260.dtb
-dtb-$(CONFIG_ARCH_AT91) += usb_a9260.dtb
-# sam9261
-dtb-$(CONFIG_ARCH_AT91) += at91sam9261ek.dtb
-# sam9263
-dtb-$(CONFIG_ARCH_AT91) += at91sam9263ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += tny_a9263.dtb
-dtb-$(CONFIG_ARCH_AT91) += usb_a9263.dtb
-# sam9g20
-dtb-$(CONFIG_ARCH_AT91) += at91-foxg20.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek_2mmc.dtb
-dtb-$(CONFIG_ARCH_AT91) += kizbox.dtb
-dtb-$(CONFIG_ARCH_AT91) += tny_a9g20.dtb
-dtb-$(CONFIG_ARCH_AT91) += usb_a9g20.dtb
-dtb-$(CONFIG_ARCH_AT91) += usb_a9g20_lpw.dtb
-# sam9g45
-dtb-$(CONFIG_ARCH_AT91) += at91sam9m10g45ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += pm9g45.dtb
-# sam9n12
-dtb-$(CONFIG_ARCH_AT91) += at91sam9n12ek.dtb
-# sam9rl
-dtb-$(CONFIG_ARCH_AT91) += at91sam9rlek.dtb
-# sam9x5
-dtb-$(CONFIG_ARCH_AT91) += at91-ariag25.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91-cosino_mega2560.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9g15ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9g25ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
-dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
-# sama5d3
-dtb-$(CONFIG_ARCH_AT91)	+= at91-sama5d3_xplained.dtb
-dtb-$(CONFIG_ARCH_AT91)	+= sama5d31ek.dtb
-dtb-$(CONFIG_ARCH_AT91)	+= sama5d33ek.dtb
-dtb-$(CONFIG_ARCH_AT91)	+= sama5d34ek.dtb
-dtb-$(CONFIG_ARCH_AT91)	+= sama5d35ek.dtb
-dtb-$(CONFIG_ARCH_AT91)	+= sama5d36ek.dtb
-# sama5d4
-dtb-$(CONFIG_ARCH_AT91)	+= at91-sama5d4ek.dtb
-
-dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
-dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
-dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
-dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b-plus.dtb
+dtb-$(CONFIG_SOC_SAM_V4_V5) += \
+	at91rm9200ek.dtb \
+	mpa1600.dtb \
+	animeo_ip.dtb \
+	at91-qil_a9260.dtb \
+	aks-cdu.dtb \
+	ethernut5.dtb \
+	evk-pro3.dtb \
+	tny_a9260.dtb \
+	usb_a9260.dtb \
+	at91sam9261ek.dtb \
+	at91sam9263ek.dtb \
+	tny_a9263.dtb \
+	usb_a9263.dtb \
+	at91-foxg20.dtb \
+	at91sam9g20ek.dtb \
+	at91sam9g20ek_2mmc.dtb \
+	kizbox.dtb \
+	tny_a9g20.dtb \
+	usb_a9g20.dtb \
+	usb_a9g20_lpw.dtb \
+	at91sam9m10g45ek.dtb \
+	pm9g45.dtb \
+	at91sam9n12ek.dtb \
+	at91sam9rlek.dtb \
+	at91-ariag25.dtb \
+	at91-cosino_mega2560.dtb \
+	at91sam9g15ek.dtb \
+	at91sam9g25ek.dtb \
+	at91sam9g35ek.dtb \
+	at91sam9x25ek.dtb \
+	at91sam9x35ek.dtb
+dtb-$(CONFIG_SOC_SAM_V7) += \
+	at91-sama5d3_xplained.dtb \
+	sama5d31ek.dtb \
+	sama5d33ek.dtb \
+	sama5d34ek.dtb \
+	sama5d35ek.dtb \
+	sama5d36ek.dtb \
+	at91-sama5d4ek.dtb
+dtb-$(CONFIG_ARCH_ATLAS6) += \
+	atlas6-evb.dtb
+dtb-$(CONFIG_ARCH_ATLAS7) += \
+	atlas7-evb.dtb
+dtb-$(CONFIG_ARCH_AXXIA) += \
+	axm5516-amarillo.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += \
+	bcm2835-rpi-b.dtb \
+	bcm2835-rpi-b-plus.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += \
 	bcm4708-buffalo-wzr-1750dhp.dtb \
+	bcm4708-luxul-xwc-1000.dtb \
 	bcm4708-netgear-r6250.dtb \
 	bcm4708-netgear-r6300-v2.dtb \
 	bcm47081-asus-rt-n18u.dtb \
-	bcm47081-buffalo-wzr-600dhp2.dtb
-dtb-$(CONFIG_ARCH_BCM_63XX) += bcm963138dvt.dtb
-dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb \
+	bcm47081-buffalo-wzr-600dhp2.dtb \
+	bcm47081-buffalo-wzr-900dhp.dtb
+dtb-$(CONFIG_ARCH_BCM_63XX) += \
+	bcm963138dvt.dtb
+dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
+	bcm911360_entphn.dtb \
 	bcm911360k.dtb \
 	bcm958300k.dtb
-dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
+dtb-$(CONFIG_ARCH_BCM_MOBILE) += \
+	bcm28155-ap.dtb \
 	bcm21664-garnet.dtb
 dtb-$(CONFIG_ARCH_BERLIN) += \
-	berlin2-sony-nsz-gs7.dtb	\
-	berlin2cd-google-chromecast.dtb	\
+	berlin2-sony-nsz-gs7.dtb \
+	berlin2cd-google-chromecast.dtb \
 	berlin2q-marvell-dmp.dtb
 dtb-$(CONFIG_ARCH_BRCMSTB) += \
 	bcm7445-bcm97445svmb.dtb
-dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \
+dtb-$(CONFIG_ARCH_DAVINCI) += \
+	da850-enbw-cmc.dtb \
 	da850-evm.dtb
-dtb-$(CONFIG_ARCH_EFM32) += efm32gg-dk3750.dtb
-dtb-$(CONFIG_ARCH_EXYNOS) += exynos3250-monk.dtb \
-	exynos3250-rinato.dtb \
+dtb-$(CONFIG_ARCH_DIGICOLOR) += \
+	cx92755_equinox.dtb
+dtb-$(CONFIG_ARCH_EFM32) += \
+	efm32gg-dk3750.dtb
+dtb-$(CONFIG_ARCH_EXYNOS3) += \
+	exynos3250-monk.dtb \
+	exynos3250-rinato.dtb
+dtb-$(CONFIG_ARCH_EXYNOS4) += \
 	exynos4210-origen.dtb \
 	exynos4210-smdkv310.dtb \
 	exynos4210-trats.dtb \
@@ -88,7 +96,8 @@
 	exynos4412-origen.dtb \
 	exynos4412-smdk4412.dtb \
 	exynos4412-tiny4412.dtb \
-	exynos4412-trats2.dtb \
+	exynos4412-trats2.dtb
+dtb-$(CONFIG_ARCH_EXYNOS5) += \
 	exynos5250-arndale.dtb \
 	exynos5250-smdk5250.dtb \
 	exynos5250-snow.dtb \
@@ -98,20 +107,31 @@
 	exynos5420-arndale-octa.dtb \
 	exynos5420-peach-pit.dtb \
 	exynos5420-smdk5420.dtb \
+	exynos5422-odroidxu3.dtb \
 	exynos5440-sd5v1.dtb \
 	exynos5440-ssdk5440.dtb \
 	exynos5800-peach-pi.dtb
-dtb-$(CONFIG_ARCH_HI3xxx) += hi3620-hi4511.dtb
-dtb-$(CONFIG_ARCH_HIX5HD2) += hisi-x5hd2-dkb.dtb
-dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
+dtb-$(CONFIG_ARCH_HI3xxx) += \
+	hi3620-hi4511.dtb
+dtb-$(CONFIG_ARCH_HIX5HD2) += \
+	hisi-x5hd2-dkb.dtb
+dtb-$(CONFIG_ARCH_HIGHBANK) += \
+	highbank.dtb \
 	ecx-2000.dtb
-dtb-$(CONFIG_ARCH_HIP04) += hip04-d01.dtb
-dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \
+dtb-$(CONFIG_ARCH_HIP01) += \
+	hip01-ca9x2.dtb
+dtb-$(CONFIG_ARCH_HIP04) += \
+	hip04-d01.dtb
+dtb-$(CONFIG_ARCH_INTEGRATOR) += \
+	integratorap.dtb \
 	integratorcp.dtb
-dtb-$(CONFIG_ARCH_KEYSTONE) += k2hk-evm.dtb \
+dtb-$(CONFIG_ARCH_KEYSTONE) += \
+	k2hk-evm.dtb \
 	k2l-evm.dtb \
 	k2e-evm.dtb
-dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-b3.dtb \
+dtb-$(CONFIG_MACH_KIRKWOOD) += \
+	kirkwood-b3.dtb \
+	kirkwood-blackarmor-nas220.dtb \
 	kirkwood-cloudbox.dtb \
 	kirkwood-d2net.dtb \
 	kirkwood-db-88f6281.dtb \
@@ -160,6 +180,7 @@
 	kirkwood-openrd-base.dtb \
 	kirkwood-openrd-client.dtb \
 	kirkwood-openrd-ultimate.dtb \
+	kirkwood-pogo_e02.dtb \
 	kirkwood-rd88f6192.dtb \
 	kirkwood-rd88f6281-z0.dtb \
 	kirkwood-rd88f6281-a.dtb \
@@ -174,37 +195,47 @@
 	kirkwood-ts219-6282.dtb \
 	kirkwood-ts419-6281.dtb \
 	kirkwood-ts419-6282.dtb
-dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
-dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb
-dtb-$(CONFIG_MACH_MESON6) += meson6-atv1200.dtb
-dtb-$(CONFIG_ARCH_MMP) += pxa168-aspenite.dtb \
+dtb-$(CONFIG_ARCH_LPC32XX) += \
+	ea3250.dtb phy3250.dtb
+dtb-$(CONFIG_MACH_MESON6) += \
+	meson6-atv1200.dtb
+dtb-$(CONFIG_ARCH_MMP) += \
+	pxa168-aspenite.dtb \
 	pxa910-dkb.dtb \
 	mmp2-brownstone.dtb
-dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb
-dtb-$(CONFIG_ARCH_MXC) += \
+dtb-$(CONFIG_ARCH_MOXART) += \
+	moxart-uc7112lx.dtb
+dtb-$(CONFIG_SOC_IMX1) += \
 	imx1-ads.dtb \
-	imx1-apf9328.dtb \
+	imx1-apf9328.dtb
+dtb-$(CONFIG_SOC_IMX25) += \
 	imx25-eukrea-mbimxsd25-baseboard.dtb \
 	imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dtb \
 	imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dtb \
 	imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dtb \
 	imx25-karo-tx25.dtb \
-	imx25-pdk.dtb \
+	imx25-pdk.dtb
+dtb-$(CONFIG_SOC_IMX31) += \
 	imx27-apf27.dtb \
 	imx27-apf27dev.dtb \
 	imx27-eukrea-mbimxsd27-baseboard.dtb \
 	imx27-pdk.dtb \
 	imx27-phytec-phycore-rdk.dtb \
-	imx27-phytec-phycard-s-rdk.dtb \
-	imx31-bug.dtb \
+	imx27-phytec-phycard-s-rdk.dtb
+dtb-$(CONFIG_SOC_IMX31) += \
+	imx31-bug.dtb
+dtb-$(CONFIG_SOC_IMX35) += \
 	imx35-eukrea-mbimxsd35-baseboard.dtb \
-	imx35-pdk.dtb \
-	imx50-evk.dtb \
+	imx35-pdk.dtb
+dtb-$(CONFIG_SOC_IMX50) += \
+	imx50-evk.dtb
+dtb-$(CONFIG_SOC_IMX51) += \
 	imx51-apf51.dtb \
 	imx51-apf51dev.dtb \
 	imx51-babbage.dtb \
 	imx51-digi-connectcore-jsk.dtb \
-	imx51-eukrea-mbimxsd51-baseboard.dtb \
+	imx51-eukrea-mbimxsd51-baseboard.dtb
+dtb-$(CONFIG_SOC_IMX53) += \
 	imx53-ard.dtb \
 	imx53-m53evk.dtb \
 	imx53-mba53.dtb \
@@ -213,7 +244,8 @@
 	imx53-smd.dtb \
 	imx53-tx53-x03x.dtb \
 	imx53-tx53-x13x.dtb \
-	imx53-voipac-bsb.dtb \
+	imx53-voipac-bsb.dtb
+dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6dl-aristainetos_4.dtb \
 	imx6dl-aristainetos_7.dtb \
 	imx6dl-cubox-i.dtb \
@@ -234,6 +266,7 @@
 	imx6dl-tx6dl-comtft.dtb \
 	imx6dl-tx6u-801x.dtb \
 	imx6dl-tx6u-811x.dtb \
+	imx6dl-udoo.dtb \
 	imx6dl-wandboard.dtb \
 	imx6dl-wandboard-revb1.dtb \
 	imx6q-arm2.dtb \
@@ -257,23 +290,29 @@
 	imx6q-sabresd.dtb \
 	imx6q-sbc6x.dtb \
 	imx6q-tbs2910.dtb \
-	imx6q-udoo.dtb \
-	imx6q-wandboard.dtb \
-	imx6q-wandboard-revb1.dtb \
 	imx6q-tx6q-1010.dtb \
 	imx6q-tx6q-1010-comtft.dtb \
 	imx6q-tx6q-1020.dtb \
 	imx6q-tx6q-1020-comtft.dtb \
 	imx6q-tx6q-1110.dtb \
-	imx6sl-evk.dtb \
-	imx6sx-sdb.dtb \
+	imx6q-udoo.dtb \
+	imx6q-wandboard.dtb \
+	imx6q-wandboard-revb1.dtb
+dtb-$(CONFIG_SOC_IMX6SL) += \
+	imx6sl-evk.dtb
+dtb-$(CONFIG_SOC_IMX6SX) += \
+	imx6sx-sabreauto.dtb \
+	imx6sx-sdb.dtb
+dtb-$(CONFIG_SOC_LS1021A) += \
 	ls1021a-qds.dtb \
-	ls1021a-twr.dtb \
+	ls1021a-twr.dtb
+dtb-$(CONFIG_SOC_VF610) += \
 	vf500-colibri-eval-v3.dtb \
 	vf610-colibri-eval-v3.dtb \
 	vf610-cosmic.dtb \
 	vf610-twr.dtb
-dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
+dtb-$(CONFIG_ARCH_MXS) += \
+	imx23-evk.dtb \
 	imx23-olinuxino.dtb \
 	imx23-stmp378x_devb.dtb \
 	imx28-apf28.dtb \
@@ -294,17 +333,21 @@
 	imx28-m28evk.dtb \
 	imx28-sps1.dtb \
 	imx28-tx28.dtb
-dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb \
+dtb-$(CONFIG_ARCH_NOMADIK) += \
+	ste-nomadik-s8815.dtb \
 	ste-nomadik-nhk15.dtb
-dtb-$(CONFIG_ARCH_NSPIRE) += nspire-cx.dtb \
+dtb-$(CONFIG_ARCH_NSPIRE) += \
+	nspire-cx.dtb \
 	nspire-tp.dtb \
 	nspire-clp.dtb
-dtb-$(CONFIG_ARCH_OMAP2) += omap2420-h4.dtb \
+dtb-$(CONFIG_ARCH_OMAP2) += \
+	omap2420-h4.dtb \
 	omap2420-n800.dtb \
 	omap2420-n810.dtb \
 	omap2420-n810-wimax.dtb \
 	omap2430-sdp.dtb
-dtb-$(CONFIG_ARCH_OMAP3) += am3517-craneboard.dtb \
+dtb-$(CONFIG_ARCH_OMAP3) += \
+	am3517-craneboard.dtb \
 	am3517-evm.dtb \
 	am3517_mt_ventoux.dtb \
 	omap3430-sdp.dtb \
@@ -348,7 +391,10 @@
 	omap3-sbc-t3730.dtb \
 	omap3-thunder.dtb \
 	omap3-zoom3.dtb
-dtb-$(CONFIG_SOC_AM33XX) += am335x-base0033.dtb \
+dtb-$(CONFIG_SOC_TI81XX) += \
+	dm8168-evm.dtb
+dtb-$(CONFIG_SOC_AM33XX) += \
+	am335x-base0033.dtb \
 	am335x-bone.dtb \
 	am335x-boneblack.dtb \
 	am335x-evm.dtb \
@@ -356,7 +402,8 @@
 	am335x-nano.dtb \
 	am335x-pepper.dtb \
 	am335x-lxm.dtb
-dtb-$(CONFIG_ARCH_OMAP4) += omap4-duovero-parlor.dtb \
+dtb-$(CONFIG_ARCH_OMAP4) += \
+	omap4-duovero-parlor.dtb \
 	omap4-panda.dtb \
 	omap4-panda-a4.dtb \
 	omap4-panda-es.dtb \
@@ -364,20 +411,26 @@
 	omap4-sdp-es23plus.dtb \
 	omap4-var-dvk-om44.dtb \
 	omap4-var-stk-om44.dtb
-dtb-$(CONFIG_SOC_AM43XX) += am43x-epos-evm.dtb \
+dtb-$(CONFIG_SOC_AM43XX) += \
+	am43x-epos-evm.dtb \
 	am437x-sk-evm.dtb \
+	am437x-idk-evm.dtb \
 	am437x-gp-evm.dtb
-dtb-$(CONFIG_SOC_OMAP5) += omap5-cm-t54.dtb \
+dtb-$(CONFIG_SOC_OMAP5) += \
+	omap5-cm-t54.dtb \
 	omap5-sbc-t54.dtb \
 	omap5-uevm.dtb
-dtb-$(CONFIG_SOC_DRA7XX) += dra7-evm.dtb \
+dtb-$(CONFIG_SOC_DRA7XX) += \
+	dra7-evm.dtb \
 	am57xx-beagle-x15.dtb \
 	dra72-evm.dtb
-dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-d2-network.dtb \
+dtb-$(CONFIG_ARCH_ORION5X) += \
+	orion5x-lacie-d2-network.dtb \
 	orion5x-lacie-ethernet-disk-mini-v2.dtb \
 	orion5x-maxtor-shared-storage-2.dtb \
 	orion5x-rd88f5182-nas.dtb
-dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb
+dtb-$(CONFIG_ARCH_PRIMA2) += \
+	prima2-evb.dtb
 dtb-$(CONFIG_ARCH_QCOM) += \
 	qcom-apq8064-cm-qs600.dtb \
 	qcom-apq8064-ifc6410.dtb \
@@ -388,17 +441,24 @@
 	qcom-msm8660-surf.dtb \
 	qcom-msm8960-cdp.dtb \
 	qcom-msm8974-sony-xperia-honami.dtb
-dtb-$(CONFIG_ARCH_REALVIEW) += arm-realview-pb1176.dtb
+dtb-$(CONFIG_ARCH_REALVIEW) += \
+	arm-realview-pb1176.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += \
 	rk3066a-bqcurie2.dtb \
 	rk3066a-marsboard.dtb \
+	rk3066a-rayeager.dtb \
 	rk3188-radxarock.dtb \
 	rk3288-evb-act8846.dtb \
-	rk3288-evb-rk808.dtb
-dtb-$(CONFIG_ARCH_S3C24XX) += s3c2416-smdk2416.dtb
-dtb-$(CONFIG_ARCH_S3C64XX) += s3c6410-mini6410.dtb \
+	rk3288-evb-rk808.dtb \
+	rk3288-firefly-beta.dtb \
+	rk3288-firefly.dtb
+dtb-$(CONFIG_ARCH_S3C24XX) += \
+	s3c2416-smdk2416.dtb
+dtb-$(CONFIG_ARCH_S3C64XX) += \
+	s3c6410-mini6410.dtb \
 	s3c6410-smdk6410.dtb
-dtb-$(CONFIG_ARCH_S5PV210) += s5pv210-aquila.dtb \
+dtb-$(CONFIG_ARCH_S5PV210) += \
+	s5pv210-aquila.dtb \
 	s5pv210-goni.dtb \
 	s5pv210-smdkc110.dtb \
 	s5pv210-smdkv210.dtb \
@@ -410,48 +470,61 @@
 	r8a7778-bockw.dtb \
 	r8a7778-bockw-reference.dtb \
 	r8a7779-marzen.dtb \
-	r8a7790-lager.dtb \
 	sh7372-mackerel.dtb \
 	sh73a0-kzm9g.dtb \
 	sh73a0-kzm9g-reference.dtb
-dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \
+dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
+	emev2-kzm9d.dtb \
 	r7s72100-genmai.dtb \
+	r8a73a4-ape6evm.dtb \
 	r8a7740-armadillo800eva.dtb \
 	r8a7779-marzen.dtb \
 	r8a7790-lager.dtb \
 	r8a7791-henninger.dtb \
 	r8a7791-koelsch.dtb \
 	r8a7794-alt.dtb
-dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_arria5_socdk.dtb \
+dtb-$(CONFIG_ARCH_SOCFPGA) += \
+	socfpga_arria5_socdk.dtb \
 	socfpga_arria10_socdk.dtb \
 	socfpga_cyclone5_socdk.dtb \
 	socfpga_cyclone5_sockit.dtb \
 	socfpga_cyclone5_socrates.dtb \
 	socfpga_vt.dtb
-dtb-$(CONFIG_ARCH_SPEAR13XX) += spear1310-evb.dtb \
+dtb-$(CONFIG_ARCH_SPEAR13XX) += \
+	spear1310-evb.dtb \
 	spear1340-evb.dtb
-dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
+dtb-$(CONFIG_ARCH_SPEAR3XX) += \
+	spear300-evb.dtb \
 	spear310-evb.dtb \
 	spear320-evb.dtb \
 	spear320-hmi.dtb
-dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
-dtb-$(CONFIG_ARCH_STI)+= stih407-b2120.dtb \
+dtb-$(CONFIG_ARCH_SPEAR6XX) += \
+	spear600-evb.dtb
+dtb-$(CONFIG_ARCH_STI) += \
+	stih407-b2120.dtb \
 	stih410-b2120.dtb \
 	stih415-b2000.dtb \
 	stih415-b2020.dtb \
 	stih416-b2000.dtb \
 	stih416-b2020.dtb \
-	stih416-b2020e.dtb
+	stih416-b2020e.dtb \
+	stih418-b2199.dtb
 dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-a1000.dtb \
 	sun4i-a10-ba10-tvbox.dtb \
+	sun4i-a10-chuwi-v7-cw0825.dtb \
 	sun4i-a10-cubieboard.dtb \
+	sun4i-a10-marsboard.dtb \
 	sun4i-a10-mini-xplus.dtb \
+	sun4i-a10-mk802.dtb \
+	sun4i-a10-mk802ii.dtb \
 	sun4i-a10-hackberry.dtb \
+	sun4i-a10-hyundai-a7hd.dtb \
 	sun4i-a10-inet97fv2.dtb \
 	sun4i-a10-olinuxino-lime.dtb \
 	sun4i-a10-pcduino.dtb
 dtb-$(CONFIG_MACH_SUN5I) += \
+	sun5i-a10s-mk802.dtb \
 	sun5i-a10s-olinuxino-micro.dtb \
 	sun5i-a10s-r7-tv-dongle.dtb \
 	sun5i-a13-hsg-h702.dtb \
@@ -461,9 +534,11 @@
 	sun6i-a31-app4-evb1.dtb \
 	sun6i-a31-colombus.dtb \
 	sun6i-a31-hummingbird.dtb \
-	sun6i-a31-m9.dtb
+	sun6i-a31-m9.dtb \
+	sun6i-a31s-cs908.dtb
 dtb-$(CONFIG_MACH_SUN7I) += \
 	sun7i-a20-bananapi.dtb \
+	sun7i-a20-bananapro.dtb \
 	sun7i-a20-cubieboard2.dtb \
 	sun7i-a20-cubietruck.dtb \
 	sun7i-a20-hummingbird.dtb \
@@ -474,10 +549,12 @@
 	sun7i-a20-olinuxino-micro.dtb \
 	sun7i-a20-pcduino3.dtb
 dtb-$(CONFIG_MACH_SUN8I) += \
-	sun8i-a23-ippo-q8h-v5.dtb
+	sun8i-a23-ippo-q8h-v5.dtb \
+	sun8i-a23-ippo-q8h-v1.2.dtb
 dtb-$(CONFIG_MACH_SUN9I) += \
 	sun9i-a80-optimus.dtb
-dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += \
+	tegra20-harmony.dtb \
 	tegra20-iris-512.dtb \
 	tegra20-medcom-wide.dtb \
 	tegra20-paz00.dtb \
@@ -486,34 +563,43 @@
 	tegra20-tec.dtb \
 	tegra20-trimslice.dtb \
 	tegra20-ventana.dtb \
-	tegra20-whistler.dtb \
+	tegra20-whistler.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += \
 	tegra30-apalis-eval.dtb \
 	tegra30-beaver.dtb \
 	tegra30-cardhu-a02.dtb \
 	tegra30-cardhu-a04.dtb \
-	tegra30-colibri-eval-v3.dtb \
+	tegra30-colibri-eval-v3.dtb
+dtb-$(CONFIG_ARCH_TEGRA_114_SOC) += \
 	tegra114-dalmore.dtb \
 	tegra114-roth.dtb \
-	tegra114-tn7.dtb \
+	tegra114-tn7.dtb
+dtb-$(CONFIG_ARCH_TEGRA_124_SOC) += \
 	tegra124-jetson-tk1.dtb \
 	tegra124-nyan-big.dtb \
 	tegra124-venice2.dtb
-dtb-$(CONFIG_ARCH_U300) += ste-u300.dtb
-dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \
+dtb-$(CONFIG_ARCH_U300) += \
+	ste-u300.dtb
+dtb-$(CONFIG_ARCH_U8500) += \
+	ste-snowball.dtb \
 	ste-hrefprev60-stuib.dtb \
 	ste-hrefprev60-tvk.dtb \
 	ste-hrefv60plus-stuib.dtb \
 	ste-hrefv60plus-tvk.dtb \
 	ste-ccu8540.dtb \
 	ste-ccu9540.dtb
-dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \
+dtb-$(CONFIG_ARCH_VERSATILE) += \
+	versatile-ab.dtb \
 	versatile-pb.dtb
-dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
+dtb-$(CONFIG_ARCH_VEXPRESS) += \
+	vexpress-v2p-ca5s.dtb \
 	vexpress-v2p-ca9.dtb \
 	vexpress-v2p-ca15-tc1.dtb \
 	vexpress-v2p-ca15_a7.dtb
-dtb-$(CONFIG_ARCH_VIRT) += xenvm-4.2.dtb
-dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
+dtb-$(CONFIG_ARCH_VIRT) += \
+	xenvm-4.2.dtb
+dtb-$(CONFIG_ARCH_VT8500) += \
+	vt8500-bv07.dtb \
 	wm8505-ref.dtb \
 	wm8650-mid.dtb \
 	wm8750-apc8750.dtb \
@@ -534,8 +620,10 @@
 dtb-$(CONFIG_MACH_ARMADA_375) += \
 	armada-375-db.dtb
 dtb-$(CONFIG_MACH_ARMADA_38X) += \
-	armada-385-db.dtb \
-	armada-385-rd.dtb
+	armada-385-db-ap.dtb \
+	armada-388-db.dtb \
+	armada-388-gp.dtb \
+	armada-388-rd.dtb
 dtb-$(CONFIG_MACH_ARMADA_XP) += \
 	armada-xp-axpwifiap.dtb \
 	armada-xp-db.dtb \
@@ -545,17 +633,18 @@
 	armada-xp-netgear-rn2120.dtb \
 	armada-xp-openblocks-ax3-4.dtb \
 	armada-xp-synology-ds414.dtb
-dtb-$(CONFIG_MACH_DOVE) += dove-cm-a510.dtb \
+dtb-$(CONFIG_MACH_DOVE) += \
+	dove-cm-a510.dtb \
 	dove-cubox.dtb \
 	dove-cubox-es.dtb \
 	dove-d2plug.dtb \
 	dove-d3plug.dtb \
 	dove-dove-db.dtb
-dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb \
+dtb-$(CONFIG_ARCH_MEDIATEK) += \
+	mt6589-aquaris5.dtb \
 	mt6592-evb.dtb \
 	mt8127-moose.dtb \
 	mt8135-evbp1.dtb
-
 endif
 
 always		:= $(dtb-y)
diff --git a/arch/arm/boot/dts/alphascale-asm9260-devkit.dts b/arch/arm/boot/dts/alphascale-asm9260-devkit.dts
new file mode 100644
index 0000000..c77e2c9
--- /dev/null
+++ b/arch/arm/boot/dts/alphascale-asm9260-devkit.dts
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Licensed under the X11 license or the GPL v2 (or later)
+ */
+
+/dts-v1/;
+#include "alphascale-asm9260.dtsi"
+
+/ {
+	model = "Alphascale asm9260 Development Kit";
+	compatible = "alphascale,asm9260devkit", "alphascale,asm9260";
+};
diff --git a/arch/arm/boot/dts/alphascale-asm9260.dtsi b/arch/arm/boot/dts/alphascale-asm9260.dtsi
new file mode 100644
index 0000000..907fc7b
--- /dev/null
+++ b/arch/arm/boot/dts/alphascale-asm9260.dtsi
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Licensed under the X11 license or the GPL v2 (or later)
+ */
+
+#include "skeleton.dtsi"
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+/ {
+	interrupt-parent = <&icoll>;
+
+	memory {
+		device_type = "memory";
+		reg = <0x20000000 0x2000000>;
+	};
+
+	cpus {
+		#address-cells = <0>;
+		#size-cells = <0>;
+
+		cpu {
+			compatible = "arm,arm926ej-s";
+			device_type = "cpu";
+			clocks = <&acc CLKID_SYS_CPU>;
+		};
+	};
+
+	osc24m: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24000000>;
+		clock-accuracy = <30000>;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		ranges;
+
+		acc: clock-controller@80040000 {
+			compatible = "alphascale,asm9260-clock-controller";
+			#clock-cells = <1>;
+			clocks = <&osc24m>;
+			reg = <0x80040000 0x204>;
+		};
+
+		icoll: interrupt-controller@80054000 {
+			compatible = "alphascale,asm9260-icoll";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			reg = <0x80054000 0x200>;
+		};
+
+		timer0: timer@80088000 {
+			compatible = "alphascale,asm9260-timer";
+			reg = <0x80088000 0x4000>;
+			clocks = <&acc CLKID_AHB_TIMER0>;
+			interrupts = <29>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index b62a1cd..1943fc3 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -948,6 +948,22 @@
 			interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
+
+		vpfe0: vpfe@48326000 {
+			compatible = "ti,am437x-vpfe";
+			reg = <0x48326000 0x2000>;
+			interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+			ti,hwmods = "vpfe0";
+			status = "disabled";
+		};
+
+		vpfe1: vpfe@48328000 {
+			compatible = "ti,am437x-vpfe";
+			reg = <0x48328000 0x2000>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+			ti,hwmods = "vpfe1";
+			status = "disabled";
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 7eaae4c..f84d971 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -268,6 +268,78 @@
 			0x184 (PIN_INPUT_PULLUP | MUX_MODE2)	/* uart1_txd.d_can1_rx */
 		>;
 	};
+
+	vpfe0_pins_default: vpfe0_pins_default {
+		pinctrl-single,pins = <
+			0x1B0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_hd mode 0*/
+			0x1B4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_vd mode 0*/
+			0x1C0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_pclk mode 0*/
+			0x1C4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data8 mode 0*/
+			0x1C8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data9 mode 0*/
+			0x208 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data0 mode 0*/
+			0x20C (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data1 mode 0*/
+			0x210 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data2 mode 0*/
+			0x214 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data3 mode 0*/
+			0x218 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data4 mode 0*/
+			0x21C (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data5 mode 0*/
+			0x220 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data6 mode 0*/
+			0x224 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data7 mode 0*/
+		>;
+	};
+
+	vpfe0_pins_sleep: vpfe0_pins_sleep {
+		pinctrl-single,pins = <
+			0x1B0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_hd mode 0*/
+			0x1B4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_vd mode 0*/
+			0x1C0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_pclk mode 0*/
+			0x1C4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data8 mode 0*/
+			0x1C8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data9 mode 0*/
+			0x208 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data0 mode 0*/
+			0x20C (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data1 mode 0*/
+			0x210 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data2 mode 0*/
+			0x214 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data3 mode 0*/
+			0x218 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data4 mode 0*/
+			0x21C (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data5 mode 0*/
+			0x220 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data6 mode 0*/
+			0x224 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam0_data7 mode 0*/
+		>;
+	};
+
+	vpfe1_pins_default: vpfe1_pins_default {
+		pinctrl-single,pins = <
+			0x1CC (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data9 mode 0*/
+			0x1D0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data8 mode 0*/
+			0x1D4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_hd mode 0*/
+			0x1D8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_vd mode 0*/
+			0x1DC (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_pclk mode 0*/
+			0x1E8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data0 mode 0*/
+			0x1EC (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data1 mode 0*/
+			0x1F0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data2 mode 0*/
+			0x1F4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data3 mode 0*/
+			0x1F8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data4 mode 0*/
+			0x1FC (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data5 mode 0*/
+			0x200 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data6 mode 0*/
+			0x204 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data7 mode 0*/
+		>;
+	};
+
+	vpfe1_pins_sleep: vpfe1_pins_sleep {
+		pinctrl-single,pins = <
+			0x1CC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data9 mode 0*/
+			0x1D0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data8 mode 0*/
+			0x1D4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_hd mode 0*/
+			0x1D8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_vd mode 0*/
+			0x1DC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_pclk mode 0*/
+			0x1E8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data0 mode 0*/
+			0x1EC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data1 mode 0*/
+			0x1F0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data2 mode 0*/
+			0x1F4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data3 mode 0*/
+			0x1F8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data4 mode 0*/
+			0x1FC (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data5 mode 0*/
+			0x200 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data6 mode 0*/
+			0x204 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)  /* cam1_data7 mode 0*/
+		>;
+	};
 };
 
 &i2c0 {
@@ -545,3 +617,37 @@
 	pinctrl-0 = <&dcan1_default>;
 	status = "okay";
 };
+
+&vpfe0 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&vpfe0_pins_default>;
+	pinctrl-1 = <&vpfe0_pins_sleep>;
+
+	port {
+		vpfe0_ep: endpoint {
+			/* remote-endpoint = <&sensor>; add once we have it */
+			ti,am437x-vpfe-interface = <0>;
+			bus-width = <8>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+	};
+};
+
+&vpfe1 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&vpfe1_pins_default>;
+	pinctrl-1 = <&vpfe1_pins_sleep>;
+
+	port {
+		vpfe1_ep: endpoint {
+			/* remote-endpoint = <&sensor>; add once we have it */
+			ti,am437x-vpfe-interface = <0>;
+			bus-width = <8>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
new file mode 100644
index 0000000..f9a17e2
--- /dev/null
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2014 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+
+#include "am4372.dtsi"
+#include <dt-bindings/pinctrl/am43xx.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "TI AM437x Industrial Development Kit";
+	compatible = "ti,am437x-idk-evm","ti,am4372","ti,am43";
+
+	v24_0d: fixed-regulator-v24_0d {
+		compatible = "regulator-fixed";
+		regulator-name = "V24_0D";
+		regulator-min-microvolt = <24000000>;
+		regulator-max-microvolt = <24000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	v3_3d: fixed-regulator-v3_3d {
+		compatible = "regulator-fixed";
+		regulator-name = "V3_3D";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v24_0d>;
+	};
+
+	vdd_corereg: fixed-regulator-vdd_corereg {
+		compatible = "regulator-fixed";
+		regulator-name = "VDD_COREREG";
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v24_0d>;
+	};
+
+	vdd_core: fixed-regulator-vdd_core {
+		compatible = "regulator-fixed";
+		regulator-name = "VDD_CORE";
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vdd_corereg>;
+	};
+
+	v1_8dreg: fixed-regulator-v1_8dreg{
+		compatible = "regulator-fixed";
+		regulator-name = "V1_8DREG";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v24_0d>;
+	};
+
+	v1_8d: fixed-regulator-v1_8d{
+		compatible = "regulator-fixed";
+		regulator-name = "V1_8D";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v1_8dreg>;
+	};
+
+	v1_5dreg: fixed-regulator-v1_5dreg{
+		compatible = "regulator-fixed";
+		regulator-name = "V1_5DREG";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v24_0d>;
+	};
+
+	v1_5d: fixed-regulator-v1_5d{
+		compatible = "regulator-fixed";
+		regulator-name = "V1_5D";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&v1_5dreg>;
+	};
+
+	gpio_keys: gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gpio_keys_pins_default>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		switch@0 {
+			label = "power-button";
+			linux,code = <KEY_POWER>;
+			gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+&am43xx_pinmux {
+	gpio_keys_pins_default: gpio_keys_pins_default {
+		pinctrl-single,pins = <
+			0x1b8 (PIN_INPUT | MUX_MODE7)	/* cam0_field.gpio4_2 */
+		>;
+	};
+
+	i2c0_pins_default: i2c0_pins_default {
+		pinctrl-single,pins = <
+			0x188 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+			0x18c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+		>;
+	};
+
+	i2c0_pins_sleep: i2c0_pins_sleep {
+		pinctrl-single,pins = <
+			0x188 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x18c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	i2c1_pins_default: i2c1_pins_default {
+		pinctrl-single,pins = <
+			0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_cs0.i2c1_scl */
+			0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2) /* spi0_d1.i2c1_sda */
+		>;
+	};
+
+	i2c1_pins_sleep: i2c1_pins_sleep {
+		pinctrl-single,pins = <
+			0x15c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_cs0.i2c1_scl */
+			0x158 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* spi0_d1.i2c1_sda */
+		>;
+	};
+
+	mmc1_pins_default: pinmux_mmc1_pins_default {
+		pinctrl-single,pins = <
+			0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+			0x104 (PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
+			0x1f0 (PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+			0x1f4 (PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+			0x1f8 (PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+			0x1fc (PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+			0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+		>;
+	};
+
+	mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
+		pinctrl-single,pins = <
+			0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x1f0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x1f4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x1f8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x1fc (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x160 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	ecap0_pins_default: backlight_pins_default {
+		pinctrl-single,pins = <
+			0x164 (PIN_OUTPUT | MUX_MODE0) /* ecap0_in_pwm0_out.ecap0_in_pwm0_out */
+		>;
+	};
+
+	cpsw_default: cpsw_default {
+		pinctrl-single,pins = <
+			0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txclk.rgmii1_tclk */
+			0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txen.rgmii1_tctl */
+			0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td0 */
+			0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td1 */
+			0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td2 */
+			0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td3 */
+			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxclk.rmii1_rclk */
+			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxdv.rgmii1_rctl */
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd0 */
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd1 */
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd2 */
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd3 */
+		>;
+	};
+
+	cpsw_sleep: cpsw_sleep {
+		pinctrl-single,pins = <
+			0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	davinci_mdio_default: davinci_mdio_default {
+		pinctrl-single,pins = <
+			/* MDIO */
+			0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+		>;
+	};
+
+	davinci_mdio_sleep: davinci_mdio_sleep {
+		pinctrl-single,pins = <
+			/* MDIO reset value */
+			0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	qspi_pins_default: qspi_pins_default {
+		pinctrl-single,pins = <
+			0x7c (PIN_OUTPUT_PULLUP | MUX_MODE3)	/* gpmc_csn0.qspi_csn */
+			0x88 (PIN_OUTPUT | MUX_MODE2)		/* gpmc_csn3.qspi_clk */
+			0x90 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_advn_ale.qspi_d0 */
+			0x94 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_oen_ren.qspi_d1 */
+			0x98 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_wen.qspi_d2 */
+			0x9c (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_be0n_cle.qspi_d3 */
+		>;
+	};
+
+	qspi_pins_sleep: qspi_pins_sleep{
+		pinctrl-single,pins = <
+			0x7c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x88 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x90 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x94 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x98 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x9c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+};
+
+&i2c0 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&i2c0_pins_default>;
+	pinctrl-1 = <&i2c0_pins_default>;
+	clock-frequency = <400000>;
+
+	at24@50 {
+		compatible = "at24,24c256";
+		pagesize = <64>;
+		reg = <0x50>;
+	};
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&i2c1_pins_default>;
+	pinctrl-1 = <&i2c1_pins_default>;
+	clock-frequency = <400000>;
+
+	tps: tps62362@60 {
+		compatible = "ti,tps62362";
+		regulator-name = "VDD_MPU";
+		regulator-min-microvolt = <950000>;
+		regulator-max-microvolt = <1330000>;
+		regulator-boot-on;
+		regulator-always-on;
+		ti,vsel0-state-high;
+		ti,vsel1-state-high;
+		vin-supply = <&v3_3d>;
+	};
+};
+
+&epwmss0 {
+	status = "okay";
+};
+
+&ecap0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&ecap0_pins_default>;
+};
+
+&gpio0 {
+	status = "okay";
+};
+
+&gpio1 {
+	status = "okay";
+};
+
+&gpio4 {
+	status = "okay";
+};
+
+&gpio5 {
+	status = "okay";
+};
+
+&mmc1 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mmc1_pins_default>;
+	pinctrl-1 = <&mmc1_pins_sleep>;
+	vmmc-supply = <&v3_3d>;
+	bus-width = <4>;
+	cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+};
+
+&qspi {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&qspi_pins_default>;
+	pinctrl-1 = <&qspi_pins_sleep>;
+
+	spi-max-frequency = <48000000>;
+	m25p80@0 {
+		compatible = "mx66l51235l";
+		spi-max-frequency = <48000000>;
+		reg = <0>;
+		spi-cpol;
+		spi-cpha;
+		spi-tx-bus-width = <1>;
+		spi-rx-bus-width = <4>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		/*
+		 * MTD partition table.  The ROM checks the first 512KiB for a
+		 * valid file to boot(XIP).
+		 */
+		partition@0 {
+			label = "QSPI.U_BOOT";
+			reg = <0x00000000 0x000080000>;
+		};
+		partition@1 {
+			label = "QSPI.U_BOOT.backup";
+			reg = <0x00080000 0x00080000>;
+		};
+		partition@2 {
+			label = "QSPI.U-BOOT-SPL_OS";
+			reg = <0x00100000 0x00010000>;
+		};
+		partition@3 {
+			label = "QSPI.U_BOOT_ENV";
+			reg = <0x00110000 0x00010000>;
+		};
+		partition@4 {
+			label = "QSPI.U-BOOT-ENV.backup";
+			reg = <0x00120000 0x00010000>;
+		};
+		partition@5 {
+			label = "QSPI.KERNEL";
+			reg = <0x00130000 0x0800000>;
+		};
+		partition@6 {
+			label = "QSPI.FILESYSTEM";
+			reg = <0x00930000 0x36D0000>;
+		};
+	};
+};
+
+&mac {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&cpsw_default>;
+	pinctrl-1 = <&cpsw_sleep>;
+	status = "okay";
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_default>;
+	pinctrl-1 = <&davinci_mdio_sleep>;
+	status = "okay";
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "rgmii";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&wdt {
+	status = "okay";
+};
+
+&cpu {
+	cpu0-supply = <&tps>;
+};
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 53bbfc9..832d243 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -153,20 +153,26 @@
 
 	i2c0_pins: i2c0_pins {
 		pinctrl-single,pins = <
-			0x188 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)  /* i2c0_sda.i2c0_sda */
-			0x18c (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)  /* i2c0_scl.i2c0_scl */
+			0x188 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0)  /* i2c0_sda.i2c0_sda */
+			0x18c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0)  /* i2c0_scl.i2c0_scl */
 		>;
 	};
 
 	i2c1_pins: i2c1_pins {
 		pinctrl-single,pins = <
-			0x15c (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)  /* spi0_cs0.i2c1_scl */
-			0x158 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)  /* spi0_d1.i2c1_sda  */
+			0x15c (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2)  /* spi0_cs0.i2c1_scl */
+			0x158 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE2)  /* spi0_d1.i2c1_sda  */
 		>;
 	};
 
 	mmc1_pins: pinmux_mmc1_pins {
 		pinctrl-single,pins = <
+			0x0f0 (PIN_INPUT | MUX_MODE0) /* mmc0_dat3.mmc0_dat3 */
+			0x0f4 (PIN_INPUT | MUX_MODE0) /* mmc0_dat2.mmc0_dat2 */
+			0x0f8 (PIN_INPUT | MUX_MODE0) /* mmc0_dat1.mmc0_dat1 */
+			0x0fc (PIN_INPUT | MUX_MODE0) /* mmc0_dat0.mmc0_dat0 */
+			0x100 (PIN_INPUT | MUX_MODE0) /* mmc0_clk.mmc0_clk */
+			0x104 (PIN_INPUT | MUX_MODE0) /* mmc0_cmd.mmc0_cmd */
 			0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
 		>;
 	};
@@ -184,35 +190,75 @@
 		>;
 	};
 
+	vpfe0_pins_default: vpfe0_pins_default {
+		pinctrl-single,pins = <
+			0x1b0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_hd mode 0*/
+			0x1b4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_vd mode 0*/
+			0x1b8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_field mode 0*/
+			0x1bc (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_wen mode 0*/
+			0x1c0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_pclk mode 0*/
+			0x1c4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data8 mode 0*/
+			0x1c8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data9 mode 0*/
+			0x208 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data0 mode 0*/
+			0x20c (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data1 mode 0*/
+			0x210 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data2 mode 0*/
+			0x214 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data3 mode 0*/
+			0x218 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data4 mode 0*/
+			0x21c (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data5 mode 0*/
+			0x220 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data6 mode 0*/
+			0x224 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam0_data7 mode 0*/
+		>;
+	};
+
+	vpfe0_pins_sleep: vpfe0_pins_sleep {
+		pinctrl-single,pins = <
+			0x1b0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1b4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1b8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1bc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1c0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1c4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x1c8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x208 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x20c (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x210 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x214 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x218 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x21c (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x220 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			0x224 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+		>;
+	};
+
 	cpsw_default: cpsw_default {
 		pinctrl-single,pins = <
 			/* Slave 1 */
-			0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txclk.rmii1_tclk */
-			0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txen.rgmii1_tctl */
-			0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td0 */
-			0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td1 */
-			0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td2 */
-			0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td3 */
-			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxclk.rmii1_rclk */
-			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxdv.rgmii1_rctl */
-			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd0 */
-			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd1 */
-			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd2 */
-			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd3 */
+			0x12c (PIN_OUTPUT | MUX_MODE2)	/* mii1_txclk.rmii1_tclk */
+			0x114 (PIN_OUTPUT | MUX_MODE2)	/* mii1_txen.rgmii1_tctl */
+			0x128 (PIN_OUTPUT | MUX_MODE2)	/* mii1_txd0.rgmii1_td0 */
+			0x124 (PIN_OUTPUT | MUX_MODE2)	/* mii1_txd1.rgmii1_td1 */
+			0x120 (PIN_OUTPUT | MUX_MODE2)	/* mii1_txd0.rgmii1_td2 */
+			0x11c (PIN_OUTPUT | MUX_MODE2)	/* mii1_txd1.rgmii1_td3 */
+			0x130 (PIN_INPUT | MUX_MODE2)	/* mii1_rxclk.rmii1_rclk */
+			0x118 (PIN_INPUT | MUX_MODE2)	/* mii1_rxdv.rgmii1_rctl */
+			0x140 (PIN_INPUT | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd0 */
+			0x13c (PIN_INPUT | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd1 */
+			0x138 (PIN_INPUT | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd2 */
+			0x134 (PIN_INPUT | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd3 */
 
 			/* Slave 2 */
-			0x58 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a6.rgmii2_tclk */
-			0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a0.rgmii2_tctl */
-			0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a5.rgmii2_td0 */
-			0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a4.rgmii2_td1 */
-			0x4c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a3.rgmii2_td2 */
-			0x48 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a2.rgmii2_td3 */
-			0x5c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a7.rgmii2_rclk */
-			0x44 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a1.rgmii2_rtcl */
-			0x6c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a11.rgmii2_rd0 */
-			0x68 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a10.rgmii2_rd1 */
-			0x64 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a9.rgmii2_rd2 */
-			0x60 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a8.rgmii2_rd3 */
+			0x58 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a6.rgmii2_tclk */
+			0x40 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a0.rgmii2_tctl */
+			0x54 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a5.rgmii2_td0 */
+			0x50 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a4.rgmii2_td1 */
+			0x4c (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a3.rgmii2_td2 */
+			0x48 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_a2.rgmii2_td3 */
+			0x5c (PIN_INPUT | MUX_MODE2)	/* gpmc_a7.rgmii2_rclk */
+			0x44 (PIN_INPUT | MUX_MODE2)	/* gpmc_a1.rgmii2_rtcl */
+			0x6c (PIN_INPUT | MUX_MODE2)	/* gpmc_a11.rgmii2_rd0 */
+			0x68 (PIN_INPUT | MUX_MODE2)	/* gpmc_a10.rgmii2_rd1 */
+			0x64 (PIN_INPUT | MUX_MODE2)	/* gpmc_a9.rgmii2_rd2 */
+			0x60 (PIN_INPUT | MUX_MODE2)	/* gpmc_a8.rgmii2_rd3 */
 		>;
 	};
 
@@ -251,8 +297,8 @@
 	davinci_mdio_default: davinci_mdio_default {
 		pinctrl-single,pins = <
 			/* MDIO */
-			0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
-			0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+			0x148 (PIN_INPUT | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			0x14c (PIN_OUTPUT | MUX_MODE0)			/* mdio_clk.mdio_clk */
 		>;
 	};
 
@@ -266,46 +312,46 @@
 
 	dss_pins: dss_pins {
 		pinctrl-single,pins = <
-			0x020 (PIN_OUTPUT_PULLUP | MUX_MODE1)	/* gpmc ad 8 -> DSS DATA 23 */
-			0x024 (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x028 (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x02c (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x030 (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x034 (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x038 (PIN_OUTPUT_PULLUP | MUX_MODE1)
-			0x03c (PIN_OUTPUT_PULLUP | MUX_MODE1)	/* gpmc ad 15 -> DSS DATA 16 */
-			0x0a0 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS DATA 0 */
-			0x0a4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0a8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0ac (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0b0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0b4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0b8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0bc (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0c0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0c4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0c8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0cc (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0d0 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0d4 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0d8 (PIN_OUTPUT_PULLUP | MUX_MODE0)
-			0x0dc (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS DATA 15 */
-			0x0e0 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS VSYNC */
-			0x0e4 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS HSYNC */
-			0x0e8 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS PCLK */
-			0x0ec (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* DSS AC BIAS EN */
+			0x020 (PIN_OUTPUT | MUX_MODE1)	/* gpmc ad 8 -> DSS DATA 23 */
+			0x024 (PIN_OUTPUT | MUX_MODE1)
+			0x028 (PIN_OUTPUT | MUX_MODE1)
+			0x02c (PIN_OUTPUT | MUX_MODE1)
+			0x030 (PIN_OUTPUT | MUX_MODE1)
+			0x034 (PIN_OUTPUT | MUX_MODE1)
+			0x038 (PIN_OUTPUT | MUX_MODE1)
+			0x03c (PIN_OUTPUT | MUX_MODE1)	/* gpmc ad 15 -> DSS DATA 16 */
+			0x0a0 (PIN_OUTPUT | MUX_MODE0)	/* DSS DATA 0 */
+			0x0a4 (PIN_OUTPUT | MUX_MODE0)
+			0x0a8 (PIN_OUTPUT | MUX_MODE0)
+			0x0ac (PIN_OUTPUT | MUX_MODE0)
+			0x0b0 (PIN_OUTPUT | MUX_MODE0)
+			0x0b4 (PIN_OUTPUT | MUX_MODE0)
+			0x0b8 (PIN_OUTPUT | MUX_MODE0)
+			0x0bc (PIN_OUTPUT | MUX_MODE0)
+			0x0c0 (PIN_OUTPUT | MUX_MODE0)
+			0x0c4 (PIN_OUTPUT | MUX_MODE0)
+			0x0c8 (PIN_OUTPUT | MUX_MODE0)
+			0x0cc (PIN_OUTPUT | MUX_MODE0)
+			0x0d0 (PIN_OUTPUT | MUX_MODE0)
+			0x0d4 (PIN_OUTPUT | MUX_MODE0)
+			0x0d8 (PIN_OUTPUT | MUX_MODE0)
+			0x0dc (PIN_OUTPUT | MUX_MODE0)	/* DSS DATA 15 */
+			0x0e0 (PIN_OUTPUT | MUX_MODE0)	/* DSS VSYNC */
+			0x0e4 (PIN_OUTPUT | MUX_MODE0)	/* DSS HSYNC */
+			0x0e8 (PIN_OUTPUT | MUX_MODE0)	/* DSS PCLK */
+			0x0ec (PIN_OUTPUT | MUX_MODE0)	/* DSS AC BIAS EN */
 
 		>;
 	};
 
 	qspi_pins: qspi_pins {
 		pinctrl-single,pins = <
-			0x7c (PIN_OUTPUT_PULLUP | MUX_MODE3)	/* gpmc_csn0.qspi_csn */
-			0x88 (PIN_OUTPUT | MUX_MODE2)		/* gpmc_csn3.qspi_clk */
-			0x90 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_advn_ale.qspi_d0 */
-			0x94 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_oen_ren.qspi_d1 */
-			0x98 (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_wen.qspi_d2 */
-			0x9c (PIN_INPUT_PULLUP | MUX_MODE3)	/* gpmc_be0n_cle.qspi_d3 */
+			0x7c (PIN_OUTPUT | MUX_MODE3)	/* gpmc_csn0.qspi_csn */
+			0x88 (PIN_OUTPUT | MUX_MODE2)	/* gpmc_csn3.qspi_clk */
+			0x90 (PIN_INPUT | MUX_MODE3)	/* gpmc_advn_ale.qspi_d0 */
+			0x94 (PIN_INPUT | MUX_MODE3)	/* gpmc_oen_ren.qspi_d1 */
+			0x98 (PIN_INPUT | MUX_MODE3)	/* gpmc_wen.qspi_d2 */
+			0x9c (PIN_INPUT | MUX_MODE3)	/* gpmc_be0n_cle.qspi_d3 */
 		>;
 	};
 
@@ -323,6 +369,18 @@
 			0x1c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpcm_ad7.gpio1_7 */
 		>;
 	};
+
+	usb1_pins: usb1_pins {
+		pinctrl-single,pins = <
+			0x2c0 (PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
+		>;
+	};
+
+	usb2_pins: usb2_pins {
+		pinctrl-single,pins = <
+			0x2c4 (PIN_OUTPUT | MUX_MODE0) /* usb0_drvvbus.usb0_drvvbus */
+		>;
+	};
 };
 
 &i2c0 {
@@ -386,6 +444,11 @@
 			regulator-always-on;
 		};
 
+		power-button {
+			compatible = "ti,tps65218-pwrbutton";
+			status = "okay";
+			interrupts = <3 IRQ_TYPE_EDGE_BOTH>;
+		};
 	};
 
 	at24@50 {
@@ -479,6 +542,8 @@
 &usb1 {
 	dr_mode = "peripheral";
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb1_pins>;
 };
 
 &usb2_phy2 {
@@ -488,6 +553,8 @@
 &usb2 {
 	dr_mode = "host";
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb2_pins>;
 };
 
 &qspi {
@@ -610,3 +677,25 @@
 &wdt {
 	status = "okay";
 };
+
+&cpu {
+	cpu0-supply = <&dcdc2>;
+};
+
+&vpfe0 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&vpfe0_pins_default>;
+	pinctrl-1 = <&vpfe0_pins_sleep>;
+
+	/* Camera port */
+	port {
+		vpfe0_ep: endpoint {
+			/* remote-endpoint = <&sensor>; add once we have it */
+			ti,am437x-vpfe-interface = <0>;
+			bus-width = <8>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 662261d..257c099 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -243,6 +243,42 @@
 				0x08C (PIN_OUTPUT_PULLUP | MUX_MODE7)
 			>;
 		};
+
+		vpfe1_pins_default: vpfe1_pins_default {
+			pinctrl-single,pins = <
+				0x1cc (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data9 mode 0 */
+				0x1d0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data8 mode 0 */
+				0x1d4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_hd mode 0 */
+				0x1d8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_vd mode 0 */
+				0x1dc (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_pclk mode 0 */
+				0x1e8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data0 mode 0 */
+				0x1ec (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data1 mode 0 */
+				0x1f0 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data2 mode 0 */
+				0x1f4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data3 mode 0 */
+				0x1f8 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data4 mode 0 */
+				0x1fc (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data5 mode 0 */
+				0x200 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data6 mode 0 */
+				0x204 (PIN_INPUT_PULLUP | MUX_MODE0)  /* cam1_data7 mode 0 */
+			>;
+		};
+
+		vpfe1_pins_sleep: vpfe1_pins_sleep {
+			pinctrl-single,pins = <
+				0x1cc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1d0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1d4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1d8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1dc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1e8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1ec (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1f0 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1f4 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1f8 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x1fc (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x200 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+				0x204 (DS0_PULL_UP_DOWN_EN | INPUT_EN | MUX_MODE7)
+			>;
+		};
 	};
 
 	matrix_keypad: matrix_keypad@0 {
@@ -634,3 +670,20 @@
 		};
 	};
 };
+
+&vpfe1 {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&vpfe1_pins_default>;
+	pinctrl-1 = <&vpfe1_pins_sleep>;
+
+	port {
+		vpfe1_ep: endpoint {
+			/* remote-endpoint = <&sensor>; add once we have it */
+			ti,am437x-vpfe-interface = <0>;
+			bus-width = <8>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index 49edbda..03750af 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -80,6 +80,28 @@
 			default-state = "off";
 		};
 	};
+
+	gpio_fan: gpio_fan {
+		/* Based on 5v 500mA AFB02505HHB */
+		compatible = "gpio-fan";
+		gpios =  <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>;
+		gpio-fan,speed-map = <0     0>,
+				     <13000 1>;
+	};
+
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&gpio7 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&extcon_usb1_pins>;
+	};
+
+	extcon_usb2: extcon_usb2 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&gpio7 24 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&extcon_usb2_pins>;
+	};
 };
 
 &dra7_pmx_core {
@@ -140,6 +162,86 @@
 		>;
 	};
 
+	cpsw_pins_default: cpsw_pins_default {
+		pinctrl-single,pins = <
+			/* Slave 1 */
+			0x250 (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_tclk */
+			0x254 (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_tctl */
+			0x258 (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_td3 */
+			0x25c (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_td2 */
+			0x260 (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_td1 */
+			0x264 (PIN_OUTPUT | MUX_MODE0)	/* rgmii1_td0 */
+			0x268 (PIN_INPUT | MUX_MODE0)	/* rgmii1_rclk */
+			0x26c (PIN_INPUT | MUX_MODE0)	/* rgmii1_rctl */
+			0x270 (PIN_INPUT | MUX_MODE0)	/* rgmii1_rd3 */
+			0x274 (PIN_INPUT | MUX_MODE0)	/* rgmii1_rd2 */
+			0x278 (PIN_INPUT | MUX_MODE0)	/* rgmii1_rd1 */
+			0x27c (PIN_INPUT | MUX_MODE0)	/* rgmii1_rd0 */
+
+			/* Slave 2 */
+			0x198 (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_tclk */
+			0x19c (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_tctl */
+			0x1a0 (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_td3 */
+			0x1a4 (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_td2 */
+			0x1a8 (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_td1 */
+			0x1ac (PIN_OUTPUT | MUX_MODE3)	/* rgmii2_td0 */
+			0x1b0 (PIN_INPUT | MUX_MODE3)	/* rgmii2_rclk */
+			0x1b4 (PIN_INPUT | MUX_MODE3)	/* rgmii2_rctl */
+			0x1b8 (PIN_INPUT | MUX_MODE3)	/* rgmii2_rd3 */
+			0x1bc (PIN_INPUT | MUX_MODE3)	/* rgmii2_rd2 */
+			0x1c0 (PIN_INPUT | MUX_MODE3)	/* rgmii2_rd1 */
+			0x1c4 (PIN_INPUT | MUX_MODE3)	/* rgmii2_rd0 */
+		>;
+
+	};
+
+	cpsw_pins_sleep: cpsw_pins_sleep {
+		pinctrl-single,pins = <
+			/* Slave 1 */
+			0x250 (PIN_INPUT | MUX_MODE15)
+			0x254 (PIN_INPUT | MUX_MODE15)
+			0x258 (PIN_INPUT | MUX_MODE15)
+			0x25c (PIN_INPUT | MUX_MODE15)
+			0x260 (PIN_INPUT | MUX_MODE15)
+			0x264 (PIN_INPUT | MUX_MODE15)
+			0x268 (PIN_INPUT | MUX_MODE15)
+			0x26c (PIN_INPUT | MUX_MODE15)
+			0x270 (PIN_INPUT | MUX_MODE15)
+			0x274 (PIN_INPUT | MUX_MODE15)
+			0x278 (PIN_INPUT | MUX_MODE15)
+			0x27c (PIN_INPUT | MUX_MODE15)
+
+			/* Slave 2 */
+			0x198 (PIN_INPUT | MUX_MODE15)
+			0x19c (PIN_INPUT | MUX_MODE15)
+			0x1a0 (PIN_INPUT | MUX_MODE15)
+			0x1a4 (PIN_INPUT | MUX_MODE15)
+			0x1a8 (PIN_INPUT | MUX_MODE15)
+			0x1ac (PIN_INPUT | MUX_MODE15)
+			0x1b0 (PIN_INPUT | MUX_MODE15)
+			0x1b4 (PIN_INPUT | MUX_MODE15)
+			0x1b8 (PIN_INPUT | MUX_MODE15)
+			0x1bc (PIN_INPUT | MUX_MODE15)
+			0x1c0 (PIN_INPUT | MUX_MODE15)
+			0x1c4 (PIN_INPUT | MUX_MODE15)
+		>;
+	};
+
+	davinci_mdio_pins_default: davinci_mdio_pins_default {
+		pinctrl-single,pins = <
+			/* MDIO */
+			0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* mdio_mclk */
+			0x240 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mdio_d */
+		>;
+	};
+
+	davinci_mdio_pins_sleep: davinci_mdio_pins_sleep {
+		pinctrl-single,pins = <
+			0x23c (PIN_INPUT | MUX_MODE15)
+			0x240 (PIN_INPUT | MUX_MODE15)
+		>;
+	};
+
 	tps659038_pins_default: tps659038_pins_default {
 		pinctrl-single,pins = <
 			0x418 (PIN_INPUT_PULLUP | MUX_MODE14)	/* wakeup0.gpio1_0 */
@@ -164,6 +266,17 @@
 		>;
 	};
 
+	extcon_usb1_pins: extcon_usb1_pins {
+		pinctrl-single,pins = <
+			0x3ec (PIN_INPUT_PULLUP | MUX_MODE14) /* uart1_rtsn.gpio7_25 */
+		>;
+	};
+
+	extcon_usb2_pins: extcon_usb2_pins {
+		pinctrl-single,pins = <
+			0x3e8 (PIN_INPUT_PULLUP | MUX_MODE14) /* uart1_ctsn.gpio7_24 */
+		>;
+	};
 };
 
 &i2c1 {
@@ -314,6 +427,12 @@
 			wakeup-source;
 			ti,palmas-long-press-seconds = <12>;
 		};
+
+		tps659038_gpio: tps659038_gpio {
+			compatible = "ti,palmas-gpio";
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
 	};
 
 	tmp102: tmp102@48 {
@@ -365,6 +484,32 @@
 	pinctrl-0 = <&uart3_pins_default>;
 };
 
+&mac {
+	status = "okay";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&cpsw_pins_default>;
+	pinctrl-1 = <&cpsw_pins_sleep>;
+	dual_emac;
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <1>;
+	phy-mode = "rgmii";
+	dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+	phy_id = <&davinci_mdio>, <2>;
+	phy-mode = "rgmii";
+	dual_emac_res_vlan = <2>;
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_pins_default>;
+	pinctrl-1 = <&davinci_mdio_pins_sleep>;
+};
+
 &mmc1 {
 	status = "okay";
 
@@ -403,3 +548,15 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&usb1_pins>;
 };
+
+&omap_dwc3_1 {
+	extcon = <&extcon_usb1>;
+};
+
+&omap_dwc3_2 {
+	extcon = <&extcon_usb2>;
+};
+
+&usb2 {
+	dr_mode = "peripheral";
+};
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 70b1943..e993c46 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -8,9 +8,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index e1b0eb6..b10ceb4 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -3,9 +3,43 @@
  *
  * Gregory CLEMENT <gregory.clement@free-electrons.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.
+ * 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 , 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/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index 4e24932..3f8cc38 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.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 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 , 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/;
@@ -87,6 +120,7 @@
 				isl12057: isl12057@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
+					isil,irq2-can-wakeup-machine;
 				};
 
 				g762: g762@3e {
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index 30586e47..99eb8a0 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.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 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 , 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/;
@@ -93,6 +126,7 @@
 				isl12057: isl12057@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
+					isil,irq2-can-wakeup-machine;
 				};
 
 				g762: g762@3e {
diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index 3943089..6ae36a3 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -6,9 +6,43 @@
  *
  *  Copyright (C) 2013 Florian Fainelli <florian@openwrt.org>
  *
- * 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.
+ * 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 , 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.
  *
  * Note: this Device Tree assumes that the bootloader has remapped the
  * internal registers to 0xf1000000 (instead of the default
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
index 70fecde..59f74e6 100644
--- a/arch/arm/boot/dts/armada-370-synology-ds213j.dts
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.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 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 , 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.
  *
  * Note: this Device Tree assumes that the bootloader has remapped the
  * internal registers to 0xf1000000 (instead of the old 0xd0000000).
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 1af4286..8a322ad 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -8,9 +8,43 @@
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  * Ben Dooks <ben.dooks@codethink.co.uk>
  *
- * 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.
+ * 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 , 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 contains the definitions that are common to the Armada
  * 370 and Armada XP SoC.
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index fdb3c12..27397f1 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -7,9 +7,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
  *
  * Contains definitions specific to the Armada 370 SoC that are not
  * common to all Armada SoCs.
diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts
index 929ae00..0440891 100644
--- a/arch/arm/boot/dts/armada-375-db.dts
+++ b/arch/arm/boot/dts/armada-375-db.dts
@@ -7,9 +7,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index 50096d3..ba3c57e 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -6,9 +6,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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 "skeleton.dtsi"
@@ -63,7 +97,7 @@
 	};
 
 	soc {
-		compatible = "marvell,armada375-mbus", "marvell,armada370-mbus", "simple-bus";
+		compatible = "marvell,armada375-mbus", "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <1>;
 		controller = <&mbusc>;
diff --git a/arch/arm/boot/dts/armada-380.dtsi b/arch/arm/boot/dts/armada-380.dtsi
index 4173a8a..5102d19 100644
--- a/arch/arm/boot/dts/armada-380.dtsi
+++ b/arch/arm/boot/dts/armada-380.dtsi
@@ -7,9 +7,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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-38x.dtsi"
@@ -32,9 +66,8 @@
 
 	soc {
 		internal-regs {
-			pinctrl {
+			pinctrl@18000 {
 				compatible = "marvell,mv88f6810-pinctrl";
-				reg = <0x18000 0x20>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
new file mode 100644
index 0000000..57b9119
--- /dev/null
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -0,0 +1,178 @@
+/*
+ * Device Tree file for Marvell Armada 385 Access Point Development board
+ * (DB-88F6820-AP)
+ *
+ *  Copyright (C) 2014 Marvell
+ *
+ * Nadav Haklai <nadavh@marvell.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 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.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "armada-385.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Marvell Armada 385 Access Point Development Board";
+	compatible = "marvell,a385-db-ap", "marvell,armada385", "marvell,armada38x";
+
+	chosen {
+		bootargs = "console=ttyS0,115200";
+		stdout-path = &uart1;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000>; /* 2GB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+		internal-regs {
+			spi1: spi@10680 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&spi1_pins>;
+				status = "okay";
+
+				spi-flash@0 {
+					#address-cells = <1>;
+					#size-cells = <1>;
+					compatible = "st,m25p128";
+					reg = <0>; /* Chip select 0 */
+					spi-max-frequency = <54000000>;
+				};
+			};
+
+			i2c0: i2c@11000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&i2c0_pins>;
+				status = "okay";
+
+				/*
+				 * This bus is wired to two EEPROM
+				 * sockets, one of which holding the
+				 * board ID used by the	bootloader.
+				 * Erasing this EEPROM's content will
+				 * brick the board.
+				 * Use this bus with caution.
+				 */
+			};
+
+			mdio@72004 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&mdio_pins>;
+
+				phy0: ethernet-phy@1 {
+					reg = <1>;
+				};
+
+				phy1: ethernet-phy@4 {
+					reg = <4>;
+				};
+
+				phy2: ethernet-phy@6 {
+					reg = <6>;
+				};
+			};
+
+			/* UART0 is exposed through the JP8 connector */
+			uart0: serial@12000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart0_pins>;
+				status = "okay";
+			};
+
+			/*
+			 * UART1 is exposed through a FTDI chip
+			 * wired to the mini-USB connector
+			 */
+			uart1: serial@12100 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart1_pins>;
+				status = "okay";
+			};
+
+			ethernet@30000 {
+				status = "okay";
+				phy = <&phy2>;
+				phy-mode = "sgmii";
+			};
+
+			ethernet@34000 {
+				status = "okay";
+				phy = <&phy1>;
+				phy-mode = "sgmii";
+			};
+
+			ethernet@70000 {
+				pinctrl-names = "default";
+
+				/*
+				 * The Reference Clock 0 is used to
+				 * provide a clock to the PHY
+				 */
+				pinctrl-0 = <&ge0_rgmii_pins>, <&ref_clk0_pins>;
+				status = "okay";
+				phy = <&phy0>;
+				phy-mode = "rgmii-id";
+			};
+		};
+
+		pcie-controller {
+			status = "okay";
+
+			/*
+			 * The three PCIe units are accessible through
+			 * standard mini-PCIe slots on the board.
+			 */
+			pcie@1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+
+			pcie@2,0 {
+				/* Port 1, Lane 0 */
+				status = "okay";
+			};
+
+			pcie@3,0 {
+				/* Port 2, Lane 0 */
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts
deleted file mode 100644
index 2aaa9d2..0000000
--- a/arch/arm/boot/dts/armada-385-db.dts
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Device Tree file for Marvell Armada 385 evaluation board
- * (DB-88F6820)
- *
- *  Copyright (C) 2014 Marvell
- *
- * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
- */
-
-/dts-v1/;
-#include "armada-385.dtsi"
-
-/ {
-	model = "Marvell Armada 385 Development Board";
-	compatible = "marvell,a385-db", "marvell,armada385", "marvell,armada380";
-
-	chosen {
-		bootargs = "console=ttyS0,115200 earlyprintk";
-	};
-
-	memory {
-		device_type = "memory";
-		reg = <0x00000000 0x10000000>; /* 256 MB */
-	};
-
-	soc {
-		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
-			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
-
-		internal-regs {
-			spi@10600 {
-				status = "okay";
-
-				spi-flash@0 {
-					#address-cells = <1>;
-					#size-cells = <1>;
-					compatible = "w25q32";
-					reg = <0>; /* Chip select 0 */
-					spi-max-frequency = <108000000>;
-				};
-			};
-
-			i2c@11000 {
-				status = "okay";
-				clock-frequency = <100000>;
-			};
-
-			i2c@11100 {
-				status = "okay";
-				clock-frequency = <100000>;
-			};
-
-			serial@12000 {
-				status = "okay";
-			};
-
-			ethernet@30000 {
-				status = "okay";
-				phy = <&phy1>;
-				phy-mode = "rgmii-id";
-			};
-
-			usb@50000 {
-				status = "ok";
-			};
-
-			ethernet@70000 {
-				status = "okay";
-				phy = <&phy0>;
-				phy-mode = "rgmii-id";
-			};
-
-			mdio {
-				phy0: ethernet-phy@0 {
-					reg = <0>;
-				};
-
-				phy1: ethernet-phy@1 {
-					reg = <1>;
-				};
-			};
-
-			sata@a8000 {
-				status = "okay";
-			};
-
-			sata@e0000 {
-				status = "okay";
-			};
-
-			flash@d0000 {
-				status = "okay";
-				num-cs = <1>;
-				marvell,nand-keep-config;
-				marvell,nand-enable-arbiter;
-				nand-on-flash-bbt;
-				nand-ecc-strength = <4>;
-				nand-ecc-step-size = <512>;
-
-				partition@0 {
-					label = "U-Boot";
-					reg = <0 0x800000>;
-				};
-				partition@800000 {
-					label = "Linux";
-					reg = <0x800000 0x800000>;
-				};
-				partition@1000000 {
-					label = "Filesystem";
-					reg = <0x1000000 0x3f000000>;
-				};
-			};
-
-			sdhci@d8000 {
-				broken-cd;
-				wp-inverted;
-				bus-width = <8>;
-				status = "okay";
-				no-1-8-v;
-			};
-
-			usb3@f0000 {
-				status = "okay";
-			};
-
-			usb3@f8000 {
-				status = "okay";
-			};
-		};
-
-		pcie-controller {
-			status = "okay";
-			/*
-			 * The two PCIe units are accessible through
-			 * standard PCIe slots on the board.
-			 */
-			pcie@1,0 {
-				/* Port 0, Lane 0 */
-				status = "okay";
-			};
-			pcie@2,0 {
-				/* Port 1, Lane 0 */
-				status = "okay";
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/armada-385-rd.dts b/arch/arm/boot/dts/armada-385-rd.dts
deleted file mode 100644
index aaca286..0000000
--- a/arch/arm/boot/dts/armada-385-rd.dts
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Device Tree file for Marvell Armada 385 Reference Design board
- * (RD-88F6820-AP)
- *
- *  Copyright (C) 2014 Marvell
- *
- * Gregory CLEMENT <gregory.clement@free-electrons.com>
- * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
- */
-
-/dts-v1/;
-#include "armada-385.dtsi"
-
-/ {
-	model = "Marvell Armada 385 Reference Design";
-	compatible = "marvell,a385-rd", "marvell,armada385", "marvell,armada380";
-
-	chosen {
-		bootargs = "console=ttyS0,115200 earlyprintk";
-	};
-
-	memory {
-		device_type = "memory";
-		reg = <0x00000000 0x10000000>; /* 256 MB */
-	};
-
-	soc {
-		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
-			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
-
-		internal-regs {
-			spi@10600 {
-				status = "okay";
-
-				spi-flash@0 {
-					#address-cells = <1>;
-					#size-cells = <1>;
-					compatible = "st,m25p128";
-					reg = <0>; /* Chip select 0 */
-					spi-max-frequency = <108000000>;
-				};
-			};
-
-			i2c@11000 {
-				status = "okay";
-				clock-frequency = <100000>;
-			};
-
-			serial@12000 {
-				status = "okay";
-			};
-
-			ethernet@30000 {
-				status = "okay";
-				phy = <&phy0>;
-				phy-mode = "rgmii-id";
-			};
-
-			ethernet@70000 {
-				status = "okay";
-				phy = <&phy1>;
-				phy-mode = "rgmii-id";
-			};
-
-
-			mdio {
-				phy0: ethernet-phy@0 {
-					reg = <0>;
-				};
-
-				phy1: ethernet-phy@1 {
-					reg = <1>;
-				};
-			};
-
-			usb3@f0000 {
-				status = "okay";
-			};
-		};
-
-		pcie-controller {
-			status = "okay";
-			/*
-			 * One PCIe units is accessible through
-			 * standard PCIe slot on the board.
-			 */
-			pcie@1,0 {
-				/* Port 0, Lane 0 */
-				status = "okay";
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/armada-385.dtsi b/arch/arm/boot/dts/armada-385.dtsi
index 6283d79..8e67d2c 100644
--- a/arch/arm/boot/dts/armada-385.dtsi
+++ b/arch/arm/boot/dts/armada-385.dtsi
@@ -7,9 +7,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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-38x.dtsi"
@@ -37,9 +71,8 @@
 
 	soc {
 		internal-regs {
-			pinctrl {
+			pinctrl@18000 {
 				compatible = "marvell,mv88f6820-pinctrl";
-				reg = <0x18000 0x20>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
new file mode 100644
index 0000000..16512ef
--- /dev/null
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -0,0 +1,186 @@
+/*
+ * Device Tree file for Marvell Armada 388 evaluation board
+ * (DB-88F6820)
+ *
+ *  Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@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 , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "armada-388.dtsi"
+
+/ {
+	model = "Marvell Armada 385 Development Board";
+	compatible = "marvell,a385-db", "marvell,armada388",
+		"marvell,armada385", "marvell,armada380";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>; /* 256 MB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+		internal-regs {
+			spi@10600 {
+				status = "okay";
+
+				spi-flash@0 {
+					#address-cells = <1>;
+					#size-cells = <1>;
+					compatible = "w25q32";
+					reg = <0>; /* Chip select 0 */
+					spi-max-frequency = <108000000>;
+				};
+			};
+
+			i2c@11000 {
+				status = "okay";
+				clock-frequency = <100000>;
+			};
+
+			i2c@11100 {
+				status = "okay";
+				clock-frequency = <100000>;
+			};
+
+			serial@12000 {
+				status = "okay";
+			};
+
+			ethernet@30000 {
+				status = "okay";
+				phy = <&phy1>;
+				phy-mode = "rgmii-id";
+			};
+
+			usb@50000 {
+				status = "ok";
+			};
+
+			ethernet@70000 {
+				status = "okay";
+				phy = <&phy0>;
+				phy-mode = "rgmii-id";
+			};
+
+			mdio@72004 {
+				phy0: ethernet-phy@0 {
+					reg = <0>;
+				};
+
+				phy1: ethernet-phy@1 {
+					reg = <1>;
+				};
+			};
+
+			sata@a8000 {
+				status = "okay";
+			};
+
+			sata@e0000 {
+				status = "okay";
+			};
+
+			flash@d0000 {
+				status = "okay";
+				num-cs = <1>;
+				marvell,nand-keep-config;
+				marvell,nand-enable-arbiter;
+				nand-on-flash-bbt;
+				nand-ecc-strength = <4>;
+				nand-ecc-step-size = <512>;
+
+				partition@0 {
+					label = "U-Boot";
+					reg = <0 0x800000>;
+				};
+				partition@800000 {
+					label = "Linux";
+					reg = <0x800000 0x800000>;
+				};
+				partition@1000000 {
+					label = "Filesystem";
+					reg = <0x1000000 0x3f000000>;
+				};
+			};
+
+			sdhci@d8000 {
+				broken-cd;
+				wp-inverted;
+				bus-width = <8>;
+				status = "okay";
+				no-1-8-v;
+			};
+
+			usb3@f0000 {
+				status = "okay";
+			};
+
+			usb3@f8000 {
+				status = "okay";
+			};
+		};
+
+		pcie-controller {
+			status = "okay";
+			/*
+			 * The two PCIe units are accessible through
+			 * standard PCIe slots on the board.
+			 */
+			pcie@1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+			pcie@2,0 {
+				/* Port 1, Lane 0 */
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
new file mode 100644
index 0000000..590b383
--- /dev/null
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -0,0 +1,414 @@
+/*
+ * Device Tree file for Marvell Armada 385 development board
+ * (RD-88F6820-GP)
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * 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 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.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "armada-388.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Marvell Armada 385 GP";
+	compatible = "marvell,a385-gp", "marvell,armada388", "marvell,armada380";
+
+	chosen {
+		bootargs = "console=ttyS0,115200";
+		stdout-path = &uart0;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000>; /* 2 GB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+		internal-regs {
+			spi@10600 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&spi0_pins>;
+				status = "okay";
+
+				spi-flash@0 {
+					#address-cells = <1>;
+					#size-cells = <1>;
+					compatible = "st,m25p128";
+					reg = <0>; /* Chip select 0 */
+					spi-max-frequency = <50000000>;
+					m25p,fast-read;
+				};
+			};
+
+			i2c@11000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&i2c0_pins>;
+				status = "okay";
+				clock-frequency = <100000>;
+				/*
+				 * The EEPROM located at adresse 54 is needed
+				 * for the boot - DO NOT ERASE IT -
+				 */
+
+				expander0: pca9555@20 {
+					compatible = "nxp,pca9555";
+					pinctrl-names = "default";
+					pinctrl-0 = <&pca0_pins>;
+					interrupt-parent = <&gpio0>;
+					interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+					reg = <0x20>;
+				};
+
+				expander1: pca9555@21 {
+					compatible = "nxp,pca9555";
+					pinctrl-names = "default";
+					interrupt-parent = <&gpio0>;
+					interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+					gpio-controller;
+					#gpio-cells = <2>;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+					reg = <0x21>;
+				};
+
+			};
+
+			serial@12000 {
+				/*
+				 * Exported on the micro USB connector CON16
+				 * through an FTDI
+				 */
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&uart0_pins>;
+				status = "okay";
+			};
+
+			/* GE1 CON15 */
+			ethernet@30000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&ge1_rgmii_pins>;
+				status = "okay";
+				phy = <&phy1>;
+				phy-mode = "rgmii-id";
+			};
+
+			/* CON4 */
+			usb@50000 {
+				vcc-supply = <&reg_usb2_0_vbus>;
+				status = "okay";
+			};
+
+			/* GE0 CON1 */
+			ethernet@70000 {
+				pinctrl-names = "default";
+				/*
+				 * The Reference Clock 0 is used to provide a
+				 * clock to the PHY
+				 */
+				pinctrl-0 = <&ge0_rgmii_pins>, <&ref_clk0_pins>;
+				status = "okay";
+				phy = <&phy0>;
+				phy-mode = "rgmii-id";
+			};
+
+
+			mdio@72004 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&mdio_pins>;
+
+				phy0: ethernet-phy@1 {
+					reg = <1>;
+				};
+
+				phy1: ethernet-phy@0 {
+					reg = <0>;
+				};
+			};
+
+			sata@a8000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&sata0_pins>, <&sata1_pins>;
+				status = "okay";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sata0: sata-port@0 {
+					reg = <0>;
+					target-supply = <&reg_5v_sata0>;
+				};
+
+				sata1: sata-port@1 {
+					reg = <1>;
+					target-supply = <&reg_5v_sata1>;
+				};
+			};
+
+			sata@e0000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&sata2_pins>, <&sata3_pins>;
+				status = "okay";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sata2: sata-port@0 {
+					reg = <0>;
+					target-supply = <&reg_5v_sata2>;
+				};
+
+				sata3: sata-port@1 {
+					reg = <1>;
+					target-supply = <&reg_5v_sata3>;
+				};
+			};
+
+			sdhci@d8000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&sdhci_pins>;
+				cd-gpios = <&expander0 5 GPIO_ACTIVE_LOW>;
+				no-1-8-v;
+				wp-inverted;
+				bus-width = <8>;
+				status = "okay";
+			};
+
+			/* CON5 */
+			usb3@f0000 {
+				vcc-supply = <&reg_usb2_1_vbus>;
+				status = "okay";
+			};
+
+			/* CON7 */
+			usb3@f8000 {
+				vcc-supply = <&reg_usb3_vbus>;
+				status = "okay";
+			};
+		};
+
+		pcie-controller {
+			status = "okay";
+			/*
+			 * One PCIe units is accessible through
+			 * standard PCIe slot on the board.
+			 */
+			pcie@1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+
+			/*
+			 * The two other PCIe units are accessible
+			 * through mini PCIe slot on the board.
+			 */
+			pcie@2,0 {
+				/* Port 1, Lane 0 */
+				status = "okay";
+			};
+			pcie@3,0 {
+				/* Port 2, Lane 0 */
+				status = "okay";
+			};
+		};
+
+		gpio-fan {
+			compatible = "gpio-fan";
+			gpios = <&expander1 3 GPIO_ACTIVE_HIGH>;
+			gpio-fan,speed-map = <	 0 0
+					      3000 1>;
+		};
+	};
+
+	reg_usb3_vbus: usb3-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb3-vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander1 15 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_usb2_0_vbus: v5-vbus0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-vbus0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander1 14 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_usb2_1_vbus: v5-vbus1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-vbus1";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander0 4 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_usb2_1_vbus: v5-vbus1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-vbus1";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander0 4 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_sata0: pwr-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "pwr_en_sata0";
+		enable-active-high;
+		regulator-always-on;
+
+	};
+
+	reg_5v_sata0: v5-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata0>;
+	};
+
+	reg_12v_sata0: v12-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata0";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata0>;
+	};
+
+	reg_sata1: pwr-sata1 {
+		regulator-name = "pwr_en_sata1";
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander0 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_5v_sata1: v5-sata1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata1";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata1>;
+	};
+
+	reg_12v_sata1: v12-sata1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata1";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata1>;
+	};
+
+	reg_sata2: pwr-sata2 {
+		compatible = "regulator-fixed";
+		regulator-name = "pwr_en_sata2";
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander0 11 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_5v_sata2: v5-sata2 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata2";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata2>;
+	};
+
+	reg_12v_sata2: v12-sata2 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata2";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata2>;
+	};
+
+	reg_sata3: pwr-sata3 {
+		compatible = "regulator-fixed";
+		regulator-name = "pwr_en_sata3";
+		enable-active-high;
+		regulator-always-on;
+		gpio = <&expander0 12 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_5v_sata3: v5-sata3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata3";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata3>;
+	};
+
+	reg_12v_sata3: v12-sata3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata3";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		vin-supply = <&reg_sata3>;
+	};
+};
+
+&pinctrl {
+	pca0_pins: pca0_pins {
+		marvell,pins = "mpp18";
+		marvell,function = "gpio";
+	};
+};
diff --git a/arch/arm/boot/dts/armada-388-rd.dts b/arch/arm/boot/dts/armada-388-rd.dts
new file mode 100644
index 0000000..d99baac
--- /dev/null
+++ b/arch/arm/boot/dts/armada-388-rd.dts
@@ -0,0 +1,132 @@
+/*
+ * Device Tree file for Marvell Armada 388 Reference Design board
+ * (RD-88F6820-AP)
+ *
+ *  Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ * Thomas Petazzoni <thomas.petazzoni@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 , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "armada-388.dtsi"
+
+/ {
+	model = "Marvell Armada 385 Reference Design";
+	compatible = "marvell,a385-rd", "marvell,armada388",
+		"marvell,armada385","marvell,armada380";
+
+	chosen {
+		bootargs = "console=ttyS0,115200 earlyprintk";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>; /* 256 MB */
+	};
+
+	soc {
+		ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+			  MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+
+		internal-regs {
+			spi@10600 {
+				status = "okay";
+
+				spi-flash@0 {
+					#address-cells = <1>;
+					#size-cells = <1>;
+					compatible = "st,m25p128";
+					reg = <0>; /* Chip select 0 */
+					spi-max-frequency = <108000000>;
+				};
+			};
+
+			i2c@11000 {
+				status = "okay";
+				clock-frequency = <100000>;
+			};
+
+			serial@12000 {
+				status = "okay";
+			};
+
+			ethernet@30000 {
+				status = "okay";
+				phy = <&phy0>;
+				phy-mode = "rgmii-id";
+			};
+
+			ethernet@70000 {
+				status = "okay";
+				phy = <&phy1>;
+				phy-mode = "rgmii-id";
+			};
+
+
+			mdio@72004 {
+				phy0: ethernet-phy@0 {
+					reg = <0>;
+				};
+
+				phy1: ethernet-phy@1 {
+					reg = <1>;
+				};
+			};
+
+			usb3@f0000 {
+				status = "okay";
+			};
+		};
+
+		pcie-controller {
+			status = "okay";
+			/*
+			 * One PCIe units is accessible through
+			 * standard PCIe slot on the board.
+			 */
+			pcie@1,0 {
+				/* Port 0, Lane 0 */
+				status = "okay";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-388.dtsi b/arch/arm/boot/dts/armada-388.dtsi
new file mode 100644
index 0000000..564fa59
--- /dev/null
+++ b/arch/arm/boot/dts/armada-388.dtsi
@@ -0,0 +1,70 @@
+/*
+ * Device Tree Include file for Marvell Armada 388 SoC.
+ *
+ * Copyright (C) 2015 Marvell
+ *
+ * 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 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.
+ *
+ * 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.
+ *
+ *
+ * The main difference with the Armada 385 is that the 388 can handle two more
+ * SATA ports. So we can reuse the dtsi of the Armada 385, override the pinctrl
+ * property and the name of the SoC, and add the second SATA host which control
+ * the 2 other ports.
+ */
+
+#include "armada-385.dtsi"
+
+/ {
+	model = "Marvell Armada 388 family SoC";
+	compatible = "marvell,armada388", "marvell,armada385",
+		"marvell,armada380";
+
+	soc {
+		internal-regs {
+			pinctrl@18000 {
+				compatible = "marvell,mv88f6828-pinctrl";
+			};
+
+			sata@e0000 {
+				compatible = "marvell,armada-380-ahci";
+				reg = <0xe0000 0x2000>;
+				interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&gateclk 30>;
+				status = "disabled";
+			};
+
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 74391da..1dff30a 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -7,9 +7,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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 "skeleton.dtsi"
@@ -31,8 +65,7 @@
 	};
 
 	soc {
-		compatible = "marvell,armada380-mbus", "marvell,armada370-mbus",
-			     "simple-bus";
+		compatible = "marvell,armada380-mbus", "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <1>;
 		controller = <&mbusc>;
@@ -173,7 +206,7 @@
 				status = "disabled";
 			};
 
-			serial@12000 {
+			uart0: serial@12000 {
 				compatible = "snps,dw-apb-uart";
 				reg = <0x12000 0x100>;
 				reg-shift = <2>;
@@ -193,9 +226,94 @@
 				status = "disabled";
 			};
 
-			pinctrl {
-				compatible = "marvell,mv88f6820-pinctrl";
+			pinctrl: pinctrl@18000 {
 				reg = <0x18000 0x20>;
+
+				ge0_rgmii_pins: ge-rgmii-pins-0 {
+					marvell,pins = "mpp6", "mpp7", "mpp8",
+						       "mpp9", "mpp10", "mpp11",
+						       "mpp12", "mpp13", "mpp14",
+						       "mpp15", "mpp16", "mpp17";
+					marvell,function = "ge0";
+				};
+
+				ge1_rgmii_pins: ge-rgmii-pins-1 {
+					marvell,pins = "mpp21", "mpp27", "mpp28",
+						       "mpp29", "mpp30", "mpp31",
+						       "mpp32", "mpp37", "mpp38",
+						       "mpp39", "mpp40", "mpp41";
+					marvell,function = "ge1";
+				};
+
+				i2c0_pins: i2c-pins-0 {
+					marvell,pins = "mpp2", "mpp3";
+					marvell,function = "i2c0";
+				};
+
+				mdio_pins: mdio-pins {
+					marvell,pins = "mpp4", "mpp5";
+					marvell,function = "ge";
+				};
+
+				ref_clk0_pins: ref-clk-pins-0 {
+					marvell,pins = "mpp45";
+					marvell,function = "ref";
+				};
+
+				ref_clk1_pins: ref-clk-pins-1 {
+					marvell,pins = "mpp46";
+					marvell,function = "ref";
+				};
+
+				spi0_pins: spi-pins-0 {
+					marvell,pins = "mpp22", "mpp23", "mpp24",
+						       "mpp25";
+					marvell,function = "spi0";
+				};
+
+				spi1_pins: spi-pins-1 {
+					marvell,pins = "mpp56", "mpp57", "mpp58",
+						       "mpp59";
+					marvell,function = "spi1";
+				};
+
+				uart0_pins: uart-pins-0 {
+					marvell,pins = "mpp0", "mpp1";
+					marvell,function = "ua0";
+				};
+
+				uart1_pins: uart-pins-1 {
+					marvell,pins = "mpp19", "mpp20";
+					marvell,function = "ua1";
+				};
+
+				sdhci_pins: sdhci-pins {
+					marvell,pins = "mpp48", "mpp49", "mpp50",
+						       "mpp52", "mpp53", "mpp54",
+						       "mpp55", "mpp57", "mpp58",
+						       "mpp59";
+					marvell,function = "sd0";
+				};
+
+				sata0_pins: sata-pins-0 {
+					marvell,pins = "mpp20";
+					marvell,function = "sata0";
+				};
+
+				sata1_pins: sata-pins-1 {
+					marvell,pins = "mpp19";
+					marvell,function = "sata1";
+				};
+
+				sata2_pins: sata-pins-2 {
+					marvell,pins = "mpp47";
+					marvell,function = "sata2";
+				};
+
+				sata3_pins: sata-pins-3 {
+					marvell,pins = "mpp44";
+					marvell,function = "sata3";
+				};
 			};
 
 			gpio0: gpio@18100 {
@@ -373,7 +491,7 @@
 				status = "disabled";
 			};
 
-			mdio {
+			mdio@72004 {
 				#address-cells = <1>;
 				#size-cells = <0>;
 				compatible = "marvell,orion-mdio";
@@ -381,6 +499,13 @@
 				clocks = <&gateclk 4>;
 			};
 
+			rtc@a3800 {
+				compatible = "marvell,armada-380-rtc";
+				reg = <0xa3800 0x20>, <0x184a0 0x0c>;
+				reg-names = "rtc", "rtc-soc";
+				interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
+			};
+
 			sata@a8000 {
 				compatible = "marvell,armada-380-ahci";
 				reg = <0xa8000 0x2000>;
diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
index ca0200e..c1fbab2 100644
--- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -3,16 +3,50 @@
  *
  * Note: this board is shipped with a new generation boot loader that
  * remaps internal registers at 0xf1000000. Therefore, if earlyprintk
- * is used, the CONFIG_DEBUG_MVEBU_UART_ALTERNATE option should be
- * used.
+ * is used, the CONFIG_DEBUG_MVEBU_UART0_ALTERNATE option or the
+ * CONFIG_DEBUG_MVEBU_UART1_ALTERNATE option should be used.
  *
  * Copyright (C) 2013 Marvell
  *
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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/;
@@ -60,10 +94,12 @@
 		};
 
 		internal-regs {
+			/* UART0 */
 			serial@12000 {
 				status = "okay";
 			};
 
+			/* UART1 */
 			serial@12100 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 42ddb28..48bdafe 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -8,9 +8,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
   *
  * Note: this Device Tree assumes that the bootloader has remapped the
  * internal registers to 0xf1000000 (instead of the default
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index ea86736..206aebb 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -8,9 +8,43 @@
  * Gregory CLEMENT <gregory.clement@free-electrons.com>
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
  *
  * Note: this Device Tree assumes that the bootloader has remapped the
  * internal registers to 0xf1000000 (instead of the default
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
index a2ef93c..5fb3c8b 100644
--- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2014, Benoit Masson <yahoo@perenite.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 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 , 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/arm/boot/dts/armada-xp-matrix.dts b/arch/arm/boot/dts/armada-xp-matrix.dts
index 7e291e2..56f958e 100644
--- a/arch/arm/boot/dts/armada-xp-matrix.dts
+++ b/arch/arm/boot/dts/armada-xp-matrix.dts
@@ -5,9 +5,43 @@
  *
  * Lior Amsalem <alior@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.
+ * 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 , 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/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index 281ccd2..6e6d0f0 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -5,9 +5,43 @@
  *
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
  *
  * Contains definitions specific to the Armada XP MV78230 SoC that are not
  * common to all Armada XP SoCs.
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index d7a8d0b..4a7cbed 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -5,9 +5,43 @@
  *
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
  *
  * Contains definitions specific to the Armada XP MV78260 SoC that are not
  * common to all Armada XP SoCs.
diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
index 9c40c13..36ce63a 100644
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -5,9 +5,43 @@
  *
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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.
  *
  * Contains definitions specific to the Armada XP MV78460 SoC that are not
  * common to all Armada XP SoCs.
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index d81430a..99cb9a8 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.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 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 , 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/;
@@ -100,6 +133,7 @@
 				isl12057: isl12057@68 {
 					compatible = "isil,isl12057";
 					reg = <0x68>;
+					isil,irq2-can-wakeup-machine;
 				};
 
 				/* Controller for rear fan #1 of 3 (Protechnic
diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index 6f6b091..0c76d9f 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -5,9 +5,43 @@
  *
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.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.
+ * 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 , 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/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
index 749fdba..e9fb225 100644
--- a/arch/arm/boot/dts/armada-xp-synology-ds414.dts
+++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -3,10 +3,43 @@
  *
  * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.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 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 , 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.
  *
  * Note: this Device Tree assumes that the bootloader has remapped the
  * internal registers to 0xf1000000 (instead of the old 0xd0000000).
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 62c3ba9..8291723 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -8,9 +8,43 @@
  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  * Ben Dooks <ben.dooks@codethink.co.uk>
  *
- * 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.
+ * 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 , 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.
  *
  * Contains definitions specific to the Armada XP SoC that are not
  * common to all Armada SoCs.
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 6c97d4a..21c2b50 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -66,6 +66,11 @@
 		};
 	};
 
+	sram: sram@00200000 {
+		compatible = "mmio-sram";
+		reg = <0x00200000 0x4000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -356,6 +361,13 @@
 				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
 			};
 
+			rtc: rtc@fffffe00 {
+				compatible = "atmel,at91rm9200-rtc";
+				reg = <0xfffffe00 0x40>;
+				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				status = "disabled";
+			};
+
 			tcb0: timer@fffa0000 {
 				compatible = "atmel,at91rm9200-tcb";
 				reg = <0xfffa0000 0x100>;
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
index 43eb779..2a5d212 100644
--- a/arch/arm/boot/dts/at91rm9200ek.dts
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -77,6 +77,10 @@
 			dbgu: serial@fffff200 {
 				status = "okay";
 			};
+
+			rtc: rtc@fffffe00 {
+				status = "okay";
+			};
 		};
 
 		usb0: ohci@00300000 {
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index dd1313c..fff0ee6 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -69,6 +69,11 @@
 		};
 	};
 
+	sram0: sram@002ff000 {
+		compatible = "mmio-sram";
+		reg = <0x002ff000 0x2000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi
index cdb9ed6..e247b0b 100644
--- a/arch/arm/boot/dts/at91sam9261.dtsi
+++ b/arch/arm/boot/dts/at91sam9261.dtsi
@@ -60,6 +60,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x28000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index e8c6c60..1f67bb4 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -62,6 +62,16 @@
 		};
 	};
 
+	sram0: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x14000>;
+	};
+
+	sram1: sram@00500000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x4000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -294,7 +304,7 @@
 						reg = <17>;
 					};
 
-					ac91_clk: ac97_clk {
+					ac97_clk: ac97_clk {
 						#clock-cells = <0>;
 						reg = <18>;
 					};
@@ -685,6 +695,16 @@
 					};
 				};
 
+				ac97 {
+					pinctrl_ac97: ac97-0 {
+						atmel,pins =
+							<AT91_PIOB 0 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PB12 periph A AC97FS pin */
+							 AT91_PIOB 1 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PB13 periph A AC97CK pin */
+							 AT91_PIOB 2 AT91_PERIPH_A AT91_PINCTRL_NONE	/* PB14 periph A AC97TX pin */
+							 AT91_PIOB 3 AT91_PERIPH_A AT91_PINCTRL_NONE>;	/* PB14 periph A AC97RX pin */
+					};
+				};
+
 				pioA: gpio@fffff200 {
 					compatible = "atmel,at91rm9200-gpio";
 					reg = <0xfffff200 0x200>;
@@ -813,6 +833,17 @@
 				status = "disabled";
 			};
 
+			ac97: sound@fffa0000 {
+				compatible = "atmel,at91sam9263-ac97c";
+				reg = <0xfffa0000 0x4000>;
+				interrupts = <18 IRQ_TYPE_LEVEL_HIGH 5>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_ac97>;
+				clocks = <&ac97_clk>;
+				clock-names = "ac97_clk";
+				status = "disabled";
+			};
+
 			macb0: ethernet@fffbc000 {
 				compatible = "cdns,at32ap7000-macb", "cdns,macb";
 				reg = <0xfffbc000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index a50ee58..f593016 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -16,6 +16,15 @@
 		reg = <0x20000000 0x08000000>;
 	};
 
+	sram0: sram@002ff000 {
+		status = "disabled";
+	};
+
+	sram1: sram@002fc000 {
+		compatible = "mmio-sram";
+		reg = <0x002fc000 0x8000>;
+	};
+
 	ahb {
 		apb {
 			i2c0: i2c@fffac000 {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 2a8da8a..ee80aa9 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -74,6 +74,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x10000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -1287,7 +1292,6 @@
 			compatible = "atmel,at91rm9200-ohci", "usb-ohci";
 			reg = <0x00700000 0x100000>;
 			interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-			//TODO
 			clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
 			clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
 			status = "disabled";
@@ -1297,7 +1301,6 @@
 			compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
 			reg = <0x00800000 0x100000>;
 			interrupts = <22 IRQ_TYPE_LEVEL_HIGH 2>;
-			//TODO
 			clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;
 			clock-names = "usb_clk", "ehci_clk", "hclk", "uhpck";
 			status = "disabled";
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 68eb9ad..c2666a7 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -64,6 +64,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x8000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -893,6 +898,13 @@
 				status = "disabled";
 			};
 
+			rtc@fffffeb0 {
+				compatible = "atmel,at91rm9200-rtc";
+				reg = <0xfffffeb0 0x40>;
+				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				status = "disabled";
+			};
+
 			pwm0: pwm@f8034000 {
 				compatible = "atmel,at91sam9rl-pwm";
 				reg = <0xf8034000 0x300>;
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index 13bb24e..9575c0d 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -54,7 +54,7 @@
 				status = "okay";
 
 				wm8904: codec@1a {
-					compatible = "wm8904";
+					compatible = "wlf,wm8904";
 					reg = <0x1a>;
 					clocks = <&pck0>;
 					clock-names = "mclk";
diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi
index 7242437..40f645b 100644
--- a/arch/arm/boot/dts/at91sam9rl.dtsi
+++ b/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -70,6 +70,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x10000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index bbb3ba6..818dabd 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -72,6 +72,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x8000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index 3a9f6fa..bd16bd3 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -53,6 +53,8 @@
 			};
 
 			usb2: gadget@f803c000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_board_usb2>;
 				atmel,vbus-gpio = <&pioB 16 GPIO_ACTIVE_HIGH>;
 				status = "okay";
 			};
@@ -80,6 +82,13 @@
 							<AT91_PIOD 14 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;	/* PD14 gpio CD pin pull up and deglitch */
 					};
 				};
+
+				usb2 {
+					pinctrl_board_usb2: usb2-board {
+						atmel,pins =
+							<AT91_PIOB 16 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;		/* PB16 gpio vbus sense, deglitch */
+					};
+				};
 			};
 
 			spi0: spi@f0000000 {
diff --git a/arch/arm/boot/dts/at91sam9xe.dtsi b/arch/arm/boot/dts/at91sam9xe.dtsi
new file mode 100644
index 0000000..0278f63
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9xe.dtsi
@@ -0,0 +1,60 @@
+/*
+ * at91sam9xe.dtsi - Device Tree Include file for AT91SAM9XE family SoC
+ *
+ *  Copyright (C) 2015 Atmel,
+ *                2015 Alexandre Belloni <alexandre.Belloni@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 "at91sam9260.dtsi"
+
+/ {
+	model = "Atmel AT91SAM9XE family SoC";
+	compatible = "atmel,at91sam9xe", "atmel,at91sam9260";
+
+	sram0: sram@002ff000 {
+		status = "disabled";
+	};
+
+	sram1: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x4000>;
+	};
+};
diff --git a/arch/arm/boot/dts/atlas7-evb.dts b/arch/arm/boot/dts/atlas7-evb.dts
new file mode 100644
index 0000000..49cf59a
--- /dev/null
+++ b/arch/arm/boot/dts/atlas7-evb.dts
@@ -0,0 +1,110 @@
+/*
+ * DTS file for CSR SiRFatlas7 Evaluation Board
+ *
+ * Copyright (c) 2014 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/dts-v1/;
+
+/include/ "atlas7.dtsi"
+
+/ {
+	model = "CSR SiRFatlas7 Evaluation Board";
+	compatible = "sirf,atlas7-cb", "sirf,atlas7";
+
+	chosen {
+		bootargs = "console=ttySiRF1,115200 earlyprintk";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x40000000 0x20000000>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		vpp_reserved: vpp_mem@5e800000 {
+			compatible = "sirf,reserved-memory";
+			reg = <0x5e800000 0x800000>;
+		};
+
+		nanddisk_reserved: nanddisk@46000000 {
+			reg = <0x46000000 0x200000>;
+			no-map;
+		};
+	};
+
+
+	noc {
+		mediam {
+			nand@17050000 {
+				memory-region = <&nanddisk_reserved>;
+			};
+		};
+
+		gnssm {
+			spi1: spi@18200000 {
+				status = "okay";
+				spiflash: macronix@0{
+					status = "okay";
+					compatible = "macronix,mx25l6405d";
+					reg = <0>;
+					spi-max-frequency = <37500000>;
+					spi-cpha;
+					spi-cpol;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					partitions@0 {
+						label = "myspiboot";
+						reg = <0x0 0x800000>;
+					};
+				};
+			};
+		};
+
+		btm {
+			uart6: uart@11000000 {
+				status = "okay";
+				sirf,uart-has-rtscts;
+			};
+		};
+
+		disp-iobg {
+			vpp@13110000 {
+				memory-region = <&vpp_reserved>;
+			};
+		};
+
+		display0: display@0 {
+			compatible = "lvds-panel";
+			source = "lvds.0";
+
+			bl-gpios = <&gpio_1 63 0>;
+			data-lines  = <24>;
+
+			display-timings {
+				native-mode = <&timing0>;
+				timing0: timing0 {
+					clock-frequency = <60000000>;
+					hactive = <1024>;
+					vactive = <600>;
+					hfront-porch = <220>;
+					hback-porch = <100>;
+					hsync-len = <1>;
+					vback-porch = <10>;
+					vfront-porch = <25>;
+					vsync-len = <1>;
+					hsync-active = <0>;
+					vsync-active = <0>;
+					de-active = <1>;
+					pixelclk-active = <1>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/atlas7.dtsi b/arch/arm/boot/dts/atlas7.dtsi
new file mode 100644
index 0000000..a753178
--- /dev/null
+++ b/arch/arm/boot/dts/atlas7.dtsi
@@ -0,0 +1,813 @@
+/*
+ * DTS file for CSR SiRFatlas7 SoC
+ *
+ * Copyright (c) 2014 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+/ {
+	compatible = "sirf,atlas7";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&gic>;
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+		serial5 = &uart5;
+		serial6 = &uart6;
+		serial9 = &usp2;
+	};
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0>;
+		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <1>;
+		};
+	};
+
+	noc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x10000000 0x10000000 0xc0000000>;
+
+		gic: interrupt-controller@10301000 {
+			compatible = "arm,cortex-a9-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x10301000 0x1000>,
+			     <0x10302000 0x0100>;
+		};
+
+		pmu_regulator: pmu_regulator@10E30020 {
+			compatible = "sirf,atlas7-pmu-ldo";
+			reg = <0x10E30020 0x4>;
+			ldo: ldo {
+				regulator-name = "ldo";
+			};
+		};
+
+		atlas7_codec: atlas7_codec@10E30000 {
+			#sound-dai-cells = <0>;
+			compatible = "sirf,atlas7-codec";
+			reg = <0x10E30000 0x400>;
+			clocks = <&car 62>;
+			ldo-supply = <&ldo>;
+		};
+
+		atlas7_iacc: atlas7_iacc@10D01000 {
+			#sound-dai-cells = <0>;
+			compatible = "sirf,atlas7-iacc";
+			reg = <0x10D01000 0x100>;
+			dmas = <&dmac3 0>, <&dmac3 7>, <&dmac3 8>,
+				<&dmac3 3>, <&dmac3 9>;
+			dma-names = "rx", "tx0", "tx1", "tx2", "tx3";
+			clocks = <&car 62>;
+		};
+
+		ipc@13240000 {
+			compatible = "sirf,atlas7-ipc";
+			ranges = <0x13240000 0x13240000 0x00010000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			hwspinlock {
+				compatible = "sirf,hwspinlock";
+				reg = <0x13240000 0x00010000>;
+
+				num-spinlocks = <30>;
+			};
+
+			ns_m3_rproc@0 {
+				compatible = "sirf,ns2m30-rproc";
+				reg = <0x13240000 0x00010000>;
+				interrupts = <0 123 0>;
+			};
+
+			ns_m3_rproc@1 {
+				compatible = "sirf,ns2m31-rproc";
+				reg = <0x13240000 0x00010000>;
+				interrupts = <0 126 0>;
+			};
+
+			ns_kal_rproc@0 {
+				compatible = "sirf,ns2kal0-rproc";
+				reg = <0x13240000 0x00010000>;
+				interrupts = <0 124 0>;
+			};
+
+			ns_kal_rproc@1 {
+				compatible = "sirf,ns2kal1-rproc";
+				reg = <0x13240000 0x00010000>;
+				interrupts = <0 127 0>;
+			};
+		};
+
+		pinctrl: ioc@18880000 {
+			compatible = "sirf,atlas7-ioc";
+			reg = <0x18880000 0x1000>,
+				<0x10E40000 0x1000>;
+		};
+
+		pmipc {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x13240000 0x13240000 0x00010000>;
+			pmipc@0x13240000 {
+				compatible = "sirf,atlas7-pmipc";
+				reg = <0x13240000 0x00010000>;
+			};
+		};
+
+		dramfw {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x10830000 0x10830000 0x18000>;
+			dramfw@10820000 {
+				compatible = "sirf,nocfw-dramfw";
+				reg = <0x10830000 0x18000>;
+			};
+		};
+
+		spramfw {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x10250000 0x10250000 0x3000>;
+			spramfw@10820000 {
+				compatible = "sirf,nocfw-spramfw";
+				reg = <0x10250000 0x3000>;
+			};
+		};
+
+		cpum {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x10200000 0x10200000 0x3000>;
+			cpum@10200000 {
+				compatible = "sirf,nocfw-cpum";
+				reg = <0x10200000 0x3000>;
+			};
+		};
+
+		cgum {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x18641000 0x18641000 0x3000>,
+					 <0x18620000 0x18620000 0x1000>;
+
+			cgum@18641000 {
+				compatible = "sirf,nocfw-cgum";
+				reg = <0x18641000 0x3000>;
+			};
+
+			car: clock-controller@18620000 {
+				compatible = "sirf,atlas7-car";
+				reg = <0x18620000 0x1000>;
+				#clock-cells = <1>;
+				#reset-cells = <1>;
+			};
+		};
+
+		gnssm {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x18000000 0x18000000 0x0000ffff>,
+				<0x18010000 0x18010000 0x1000>,
+				<0x18020000 0x18020000 0x1000>,
+				<0x18030000 0x18030000 0x1000>,
+				<0x18040000 0x18040000 0x1000>,
+				<0x18050000 0x18050000 0x1000>,
+				<0x18060000 0x18060000 0x1000>,
+				<0x18100000 0x18100000 0x3000>,
+				<0x18250000 0x18250000 0x10000>,
+				<0x18200000 0x18200000 0x1000>;
+
+			dmac0: dma-controller@18000000 {
+				cell-index = <0>;
+				compatible = "sirf,atlas7-dmac";
+				reg = <0x18000000 0x1000>;
+				interrupts = <0 12 0>;
+				clocks = <&car 89>;
+				dma-channels = <16>;
+				#dma-cells = <1>;
+			};
+
+			gnssmfw@0x18100000 {
+				compatible = "sirf,nocfw-gnssm";
+				reg = <0x18100000 0x3000>;
+			};
+
+			uart0: uart@18010000 {
+				cell-index = <0>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18010000 0x1000>;
+				interrupts = <0 17 0>;
+				clocks = <&car 90>;
+				fifosize = <128>;
+				dmas = <&dmac0 3>, <&dmac0 2>;
+				dma-names = "rx", "tx";
+			};
+
+			uart1: uart@18020000 {
+				cell-index = <1>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18020000 0x1000>;
+				interrupts = <0 18 0>;
+				clocks = <&car 88>;
+				fifosize = <32>;
+			};
+
+			uart2: uart@18030000 {
+				cell-index = <2>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18030000 0x1000>;
+				interrupts = <0 19 0>;
+				clocks = <&car 91>;
+				fifosize = <128>;
+				dmas = <&dmac0 6>, <&dmac0 7>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+			uart3: uart@18040000 {
+				cell-index = <3>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18040000 0x1000>;
+				interrupts = <0 66 0>;
+				clocks = <&car 92>;
+				fifosize = <128>;
+				dmas = <&dmac0 4>, <&dmac0 5>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+			uart4: uart@18050000 {
+				cell-index = <4>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18050000 0x1000>;
+				interrupts = <0 69 0>;
+				clocks = <&car 93>;
+				fifosize = <128>;
+				dmas = <&dmac0 0>, <&dmac0 1>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+			uart5: uart@18060000 {
+				cell-index = <5>;
+				compatible = "sirf,atlas7-uart";
+				reg = <0x18060000 0x1000>;
+				interrupts = <0 71 0>;
+				clocks = <&car 94>;
+				fifosize = <128>;
+				dmas = <&dmac0 8>, <&dmac0 9>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+			dspub@18250000 {
+				compatible = "dx,cc44p";
+				reg = <0x18250000 0x10000>;
+				interrupts = <0 27 0>;
+			};
+
+			spi1: spi@18200000 {
+				compatible = "sirf,prima2-spi";
+				reg = <0x18200000 0x1000>;
+				interrupts = <0 16 0>;
+				clocks = <&car 95>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				dmas = <&dmac0 12>, <&dmac0 13>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+		};
+
+
+		gpum {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x13000000 0x13000000 0x3000>;
+			gpum@0x13000000 {
+				compatible = "sirf,nocfw-gpum";
+				reg = <0x13000000 0x3000>;
+			};
+		};
+
+		mediam {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x16000000 0x16000000 0x00200000>,
+				<0x17020000 0x17020000 0x1000>,
+				<0x17030000 0x17030000 0x1000>,
+				<0x17040000 0x17040000 0x1000>,
+				<0x17050000 0x17050000 0x10000>,
+				<0x17060000 0x17060000 0x200>,
+				<0x17060200 0x17060200 0x100>,
+				<0x17070000 0x17070000 0x200>,
+				<0x17070200 0x17070200 0x100>,
+				<0x170A0000 0x170A0000 0x3000>;
+
+			mediam@170A0000 {
+				compatible = "sirf,nocfw-mediam";
+				reg = <0x170A0000 0x3000>;
+			};
+
+			gpio_0: gpio_mediam@17040000 {
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				compatible = "sirf,atlas7-gpio";
+				reg = <0x17040000 0x1000>;
+				interrupts = <0 13 0>, <0 14 0>;
+				clocks = <&car 107>;
+				clock-names = "gpio0_io";
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			nand@17050000 {
+				compatible = "sirf,atlas7-nand";
+				reg = <0x17050000 0x10000>;
+				interrupts = <0 41 0>;
+				clocks = <&car 108>, <&car 112>;
+				clock-names = "nand_io", "nand_nand";
+			};
+
+			sd0: sdhci@16000000 {
+				cell-index = <0>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x16000000 0x100000>;
+				interrupts = <0 38 0>;
+				clocks = <&car 109>, <&car 111>;
+				clock-names = "core", "iface";
+				wp-inverted;
+				non-removable;
+				status = "disabled";
+				bus-width = <8>;
+			};
+
+			sd1: sdhci@16100000 {
+				cell-index = <1>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x16100000 0x100000>;
+				interrupts = <0 38 0>;
+				clocks = <&car 109>, <&car 111>;
+				clock-names = "core", "iface";
+				non-removable;
+				status = "disabled";
+				bus-width = <8>;
+			};
+
+			usb0: usb@17060000 {
+				cell-index = <0>;
+				compatible = "sirf,atlas7-usb";
+				reg = <0x17060000 0x200>;
+				interrupts = <0 10 0>;
+				clocks = <&car 113>;
+				sirf,usbphy = <&usbphy0>;
+				phy_type = "utmi";
+				dr_mode = "otg";
+				maximum-speed = "high-speed";
+				status = "okay";
+			};
+
+			usb1: usb@17070000 {
+				cell-index = <1>;
+				compatible = "sirf,atlas7-usb";
+				reg = <0x17070000 0x200>;
+				interrupts = <0 11 0>;
+				clocks = <&car 114>;
+				sirf,usbphy = <&usbphy1>;
+				phy_type = "utmi";
+				dr_mode = "host";
+				maximum-speed = "high-speed";
+				status = "okay";
+			};
+
+			usbphy0: usbphy@0 {
+				compatible = "sirf,atlas7-usbphy";
+				reg = <0x17060200 0x100>;
+				clocks = <&car 115>;
+				status = "okay";
+			};
+
+			usbphy1: usbphy@1 {
+				compatible = "sirf,atlas7-usbphy";
+				reg = <0x17070200 0x100>;
+				clocks = <&car 116>;
+				status = "okay";
+			};
+
+			i2c0: i2c@17020000 {
+				cell-index = <0>;
+				compatible = "sirf,prima2-i2c";
+				reg = <0x17020000 0x1000>;
+				interrupts = <0 24 0>;
+				clocks = <&car 105>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+		};
+
+		vdifm {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x13290000 0x13290000 0x3000>,
+				<0x13300000 0x13300000 0x1000>,
+				<0x14200000 0x14200000 0x600000>;
+
+			vdifm@13290000 {
+				compatible = "sirf,nocfw-vdifm";
+				reg = <0x13290000 0x3000>;
+			};
+
+			gpio_1: gpio_vdifm@13300000 {
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				compatible = "sirf,atlas7-gpio";
+				reg = <0x13300000 0x1000>;
+				interrupts = <0 43 0>, <0 44 0>, <0 45 0>;
+				clocks = <&car 84>;
+				clock-names = "gpio1_io";
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			sd2: sdhci@14200000 {
+				cell-index = <2>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x14200000 0x100000>;
+				interrupts = <0 23 0>;
+				clocks = <&car 70>, <&car 75>;
+				clock-names = "core", "iface";
+				status = "disabled";
+				bus-width = <4>;
+				sd-uhs-sdr50;
+				vqmmc-supply = <&vqmmc>;
+				vqmmc: vqmmc@2 {
+					regulator-min-microvolt = <1650000>;
+					regulator-max-microvolt = <1950000>;
+					regulator-name = "vqmmc-ldo";
+					regulator-type = "voltage";
+					regulator-boot-on;
+					regulator-allow-bypass;
+				};
+			};
+
+			sd3: sdhci@14300000 {
+				cell-index = <3>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x14300000 0x100000>;
+				interrupts = <0 23 0>;
+				clocks = <&car 76>, <&car 81>;
+				clock-names = "core", "iface";
+				status = "disabled";
+				bus-width = <4>;
+			};
+
+			sd5: sdhci@14500000 {
+				cell-index = <5>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x14500000 0x100000>;
+				interrupts = <0 39 0>;
+				clocks = <&car 71>, <&car 76>;
+				clock-names = "core", "iface";
+				status = "disabled";
+				bus-width = <4>;
+				loop-dma;
+			};
+
+			sd6: sdhci@14600000 {
+				cell-index = <6>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x14600000 0x100000>;
+				interrupts = <0 98 0>;
+				clocks = <&car 72>, <&car 77>;
+				clock-names = "core", "iface";
+				status = "disabled";
+				bus-width = <4>;
+			};
+
+			sd7: sdhci@14700000 {
+				cell-index = <7>;
+				compatible = "sirf,atlas7-sdhc";
+				reg = <0x14700000 0x100000>;
+				interrupts = <0 98 0>;
+				clocks = <&car 72>, <&car 77>;
+				clock-names = "core", "iface";
+				status = "disabled";
+				bus-width = <4>;
+			};
+		};
+
+		audiom {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x10d50000 0x10d50000 0x0000ffff>,
+					<0x10d60000 0x10d60000 0x0000ffff>,
+					<0x10d80000 0x10d80000 0x0000ffff>,
+					<0x10d90000 0x10d90000 0x0000ffff>,
+					<0x10ED0000 0x10ED0000 0x3000>,
+					<0x10dc8000 0x10dc8000 0x1000>,
+					<0x10dc0000 0x10dc0000 0x1000>,
+					<0x10db0000 0x10db0000 0x4000>,
+					<0x10d40000 0x10d40000 0x1000>,
+					<0x10d30000 0x10d30000 0x1000>;
+
+			timer@10dc0000 {
+				compatible = "sirf,atlas7-tick";
+				reg = <0x10dc0000 0x1000>;
+				interrupts = <0 0 0>,
+					   <0 1 0>,
+					   <0 2 0>,
+					   <0 49 0>,
+					   <0 50 0>,
+					   <0 51 0>;
+				clocks = <&car 47>;
+			};
+
+			timerb@10dc8000 {
+					compatible = "sirf,atlas7-tick";
+					reg = <0x10dc8000 0x1000>;
+					interrupts = <0 74 0>,
+							   <0 75 0>,
+							   <0 76 0>,
+							   <0 77 0>,
+							   <0 78 0>,
+							   <0 79 0>;
+					clocks = <&car 47>;
+			};
+
+			vip0@10db0000 {
+				compatible = "sirf,atlas7-vip0";
+				reg = <0x10db0000 0x2000>;
+				interrupts = <0 85 0>;
+				sirf,vip_cma_size = <0xC00000>;
+			};
+
+			cvd@10db2000 {
+				compatible = "sirf,cvd";
+				reg = <0x10db2000 0x2000>;
+				clocks = <&car 46>;
+			};
+
+			dmac2: dma-controller@10d50000 {
+				cell-index = <2>;
+				compatible = "sirf,atlas7-dmac";
+				reg = <0x10d50000 0xffff>;
+				interrupts = <0 55 0>;
+				clocks = <&car 60>;
+				dma-channels = <16>;
+				#dma-cells = <1>;
+			};
+
+			dmac3: dma-controller@10d60000 {
+				cell-index = <3>;
+				compatible = "sirf,atlas7-dmac";
+				reg = <0x10d60000 0xffff>;
+				interrupts = <0 56 0>;
+				clocks = <&car 61>;
+				dma-channels = <16>;
+				#dma-cells = <1>;
+			};
+
+			adc: adc@10d80000 {
+				compatible = "sirf,atlas7-adc";
+				reg = <0x10d80000 0xffff>;
+				interrupts = <0 34 0>;
+				clocks = <&car 49>;
+				#io-channel-cells = <1>;
+			};
+
+			pulsec@10d90000 {
+				compatible = "sirf,prima2-pulsec";
+				reg = <0x10d90000 0xffff>;
+				interrupts = <0 42 0>;
+				clocks = <&car 54>;
+			};
+
+			audiom@10ED0000 {
+				compatible = "sirf,nocfw-audiom";
+				reg = <0x10ED0000 0x3000>;
+				interrupts = <0 102 0>;
+			};
+
+			usp1: usp@10d30000 {
+				cell-index = <1>;
+				reg = <0x10d30000 0x1000>;
+				fifosize = <512>;
+				clocks = <&car 58>;
+				dmas = <&dmac2 6>, <&dmac2 7>;
+				dma-names = "rx", "tx";
+			};
+
+			usp2: usp@10d40000 {
+				cell-index = <2>;
+				reg = <0x10d40000 0x1000>;
+				interrupts = <0 22 0>;
+				clocks = <&car 59>;
+				dmas = <&dmac2 12>, <&dmac2 13>;
+				dma-names = "rx", "tx";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+		};
+
+		ddrm {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x10820000 0x10820000 0x3000>,
+					<0x10800000 0x10800000 0x2000>;
+			ddrm@10820000 {
+				compatible = "sirf,nocfw-ddrm";
+				reg = <0x10820000 0x3000>;
+				interrupts = <0 105 0>;
+			};
+
+			memory-controller@0x10800000 {
+				compatible = "sirf,atlas7-memc";
+				reg = <0x10800000 0x2000>;
+			};
+
+		};
+
+		btm {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x11002000 0x11002000 0x0000ffff>,
+			       <0x11010000 0x11010000 0x3000>,
+			       <0x11000000 0x11000000 0x1000>,
+			       <0x11001000 0x11001000 0x1000>;
+
+			dmac4: dma-controller@11002000 {
+				cell-index = <4>;
+				compatible = "sirf,atlas7-dmac";
+				reg = <0x11002000 0x1000>;
+				interrupts = <0 99 0>;
+				clocks = <&car 130>;
+				dma-channels = <16>;
+				#dma-cells = <1>;
+			};
+			uart6: uart@11000000 {
+				cell-index = <6>;
+				compatible = "sirf,atlas7-bt-uart",
+						"sirf,atlas7-uart";
+				reg = <0x11000000 0x1000>;
+				interrupts = <0 100 0>;
+				clocks = <&car 131>, <&car 133>, <&car 134>;
+				clock-names = "uart", "general", "noc";
+				fifosize = <128>;
+				dmas = <&dmac4 12>, <&dmac4 13>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
+			usp3: usp@11001000 {
+				compatible = "sirf,atlas7-bt-usp",
+					   "sirf,prima2-usp-pcm";
+				cell-index = <3>;
+				reg = <0x11001000 0x1000>;
+				fifosize = <512>;
+				clocks = <&car 132>, <&car 129>, <&car 133>,
+					<&car 134>, <&car 135>;
+				clock-names = "usp3_io", "a7ca_btss", "a7ca_io",
+					"noc_btm_io", "thbtm_io";
+				dmas = <&dmac4 0>, <&dmac4 1>;
+				dma-names = "rx", "tx";
+			};
+
+			btm@11010000 {
+				compatible = "sirf,nocfw-btm";
+				reg = <0x11010000 0x3000>;
+			};
+		};
+
+		rtcm {
+			compatible = "arteris, flexnoc", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x18810000 0x18810000 0x3000>,
+				<0x18840000 0x18840000 0x1000>,
+				<0x18890000 0x18890000 0x1000>,
+				<0x188B0000 0x188B0000 0x10000>,
+				<0x188D0000 0x188D0000 0x1000>;
+			rtcm@18810000 {
+				compatible = "sirf,nocfw-rtcm";
+				reg = <0x18810000 0x3000>;
+				interrupts = <0 109 0>;
+			};
+
+			gpio_2: gpio_rtcm@18890000 {
+				#gpio-cells = <2>;
+				#interrupt-cells = <2>;
+				compatible = "sirf,atlas7-gpio";
+				reg = <0x18890000 0x1000>;
+				interrupts = <0 47 0>;
+				gpio-controller;
+				interrupt-controller;
+			};
+
+			rtc-iobg@18840000 {
+				compatible = "sirf,prima2-rtciobg",
+					"sirf-prima2-rtciobg-bus",
+					"simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x18840000 0x1000>;
+
+				sysrtc@2000 {
+					compatible = "sirf,prima2-sysrtc";
+					reg = <0x2000 0x100>;
+					interrupts = <0 52 0>;
+				};
+				pwrc@3000 {
+					compatible = "sirf,atlas7-pwrc";
+					reg = <0x3000 0x100>;
+				};
+			};
+
+			qspi: flash@188B0000 {
+				cell-index = <0>;
+				compatible = "sirf,atlas7-qspi-nor";
+				reg = <0x188B0000 0x10000>;
+				interrupts = <0 15 0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			retain@0x188D0000 {
+				compatible = "sirf,atlas7-retain";
+				reg = <0x188D0000 0x1000>;
+			};
+
+		};
+		disp-iobg {
+			/* lcdc0 */
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x13100000 0x13100000 0x20000>,
+				 <0x10e10000 0x10e10000 0x10000>;
+
+			lcd@13100000 {
+				compatible = "sirf,atlas7-lcdc";
+				reg = <0x13100000 0x10000>;
+				interrupts = <0 30 0>;
+				clocks = <&car 79>;
+			};
+			vpp@13110000 {
+				compatible = "sirf,atlas7-vpp";
+				reg = <0x13110000 0x10000>;
+				interrupts = <0 31 0>;
+				clocks = <&car 78>;
+				resets = <&car 29>;
+			};
+			lvds@10e10000 {
+				compatible = "sirf,atlas7-lvdsc";
+				reg = <0x10e10000 0x10000>;
+				interrupts = <0 64 0>;
+				clocks = <&car 54>;
+				resets = <&car 29>;
+			};
+
+		};
+
+		graphics-iobg {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x12000000 0x12000000 0x1000000>;
+
+			graphics@12000000 {
+				compatible = "powervr,sgx531";
+				reg = <0x12000000 0x1000000>;
+				interrupts = <0 6 0>;
+				clocks = <&car 126>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
new file mode 100644
index 0000000..c20cf53
--- /dev/null
+++ b/arch/arm/boot/dts/axp209.dtsi
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+/*
+ * AXP202/209 Integrated Power Management Chip
+ * http://www.x-powers.com/product/AXP20X.php
+ * http://dl.linux-sunxi.org/AXP/AXP209%20Datasheet%20v1.0_cn.pdf
+ */
+
+&axp209 {
+	compatible = "x-powers,axp209";
+	interrupt-controller;
+	#interrupt-cells = <1>;
+
+	regulators {
+		/* Default work frequency for buck regulators */
+		x-powers,dcdc-freq = <1500>;
+
+		reg_dcdc2: dcdc2 {
+			regulator-name = "dcdc2";
+		};
+
+		reg_dcdc3: dcdc3 {
+			regulator-name = "dcdc3";
+		};
+
+		reg_ldo1: ldo1 {
+			/* LDO1 is a fixed output regulator */
+			regulator-always-on;
+			regulator-min-microvolt = <1300000>;
+			regulator-max-microvolt = <1300000>;
+			regulator-name = "ldo1";
+		};
+
+		reg_ldo2: ldo2 {
+			regulator-name = "ldo2";
+		};
+
+		reg_ldo3: ldo3 {
+			regulator-name = "ldo3";
+		};
+
+		reg_ldo4: ldo4 {
+			regulator-name = "ldo4";
+		};
+
+		reg_ldo5: ldo5 {
+			regulator-name = "ldo5";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
index 5fc0fae..b359c1e 100644
--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
@@ -23,11 +23,77 @@
 		reg = <0x00000000 0x08000000>;
 	};
 
+	spi {
+		compatible = "spi-gpio";
+		num-chipselects = <1>;
+		gpio-sck = <&chipcommon 7 0>;
+		gpio-mosi = <&chipcommon 4 0>;
+		cs-gpios = <&chipcommon 6 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		hc595: gpio_spi@0 {
+			compatible = "fairchild,74hc595";
+			reg = <0>;
+			registers-number = <1>;
+			spi-max-frequency = <100000>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		power0 {
+			label = "bcm53xx:red:power";
+			gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		power1 {
+			label = "bcm53xx:white:power";
+			gpios = <&hc595 2 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		router0 {
+			label = "bcm53xx:blue:router";
+			gpios = <&hc595 3 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		router1 {
+			label = "bcm53xx:amber:router";
+			gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		wan {
+			label = "bcm53xx:blue:wan";
+			gpios = <&hc595 5 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		wireless0 {
+			label = "bcm53xx:blue:wireless";
+			gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		wireless1 {
+			label = "bcm53xx:amber:wireless";
+			gpios = <&hc595 7 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		poll-interval = <200>;
 
 		restart {
 			label = "Reset";
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
new file mode 100644
index 0000000..946c728
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
@@ -0,0 +1,60 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Luxul XWC-1000
+ *
+ * Copyright 2014 Luxul Inc.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+	compatible = "luxul,xwc-1000", "brcm,bcm4708";
+	model = "Luxul XWC-1000 (BCM4708)";
+
+	chosen {
+		bootargs = "console=ttyS0,115200";
+	};
+
+	memory {
+		reg = <0x00000000 0x08000000>;
+	};
+
+	axi@18000000 {
+		nand@28000 {
+			reg = <0x00028000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "ubi";
+				reg = <0x00000000 0x08000000>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		status {
+			label = "bcm53xx:green:status";
+			gpios = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "timer";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		restart {
+			label = "Reset";
+			linux,code = <KEY_RESTART>;
+			gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index 4ed7de1..f18c9d9 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -71,7 +71,6 @@
 		compatible = "gpio-keys";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		poll-interval = <200>;
 
 		wps {
 			label = "WPS";
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
index 12fc2a01..3991042 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
@@ -61,7 +61,6 @@
 		compatible = "gpio-keys";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		poll-interval = <200>;
 
 		wps {
 			label = "WPS";
diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
index fb76378..0ee85ea 100644
--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
@@ -61,7 +61,6 @@
 		compatible = "gpio-keys";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		poll-interval = <200>;
 
 		restart {
 			label = "Reset";
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
index bbb414f..db9131e 100644
--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
@@ -23,11 +23,77 @@
 		reg = <0x00000000 0x08000000>;
 	};
 
+	spi {
+		compatible = "spi-gpio";
+		num-chipselects = <1>;
+		gpio-sck = <&chipcommon 7 0>;
+		gpio-mosi = <&chipcommon 4 0>;
+		cs-gpios = <&chipcommon 6 0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		hc595: gpio_spi@0 {
+			compatible = "fairchild,74hc595";
+			reg = <0>;
+			registers-number = <1>;
+			spi-max-frequency = <100000>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		power0 {
+			label = "bcm53xx:green:power";
+			gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		power1 {
+			label = "bcm53xx:red:power";
+			gpios = <&hc595 2 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		router0 {
+			label = "bcm53xx:green:router";
+			gpios = <&hc595 3 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		router1 {
+			label = "bcm53xx:amber:router";
+			gpios = <&hc595 4 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		wan {
+			label = "bcm53xx:green:wan";
+			gpios = <&hc595 5 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		wireless0 {
+			label = "bcm53xx:green:wireless";
+			gpios = <&hc595 6 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+
+		wireless1 {
+			label = "bcm53xx:amber:wireless";
+			gpios = <&hc595 7 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-off";
+		};
+	};
+
 	gpio-keys {
 		compatible = "gpio-keys";
 		#address-cells = <1>;
 		#size-cells = <0>;
-		poll-interval = <200>;
 
 		aoss {
 			label = "AOSS";
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
new file mode 100644
index 0000000..7d6868a
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
@@ -0,0 +1,37 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Buffalo WZR-900DHP
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm47081.dtsi"
+
+/ {
+	compatible = "buffalo,wzr-900dhp", "brcm,bcm47081", "brcm,bcm4708";
+	model = "Buffalo WZR-900DHP (BCM47081)";
+
+	chosen {
+		bootargs = "console=ttyS0,115200";
+	};
+
+	memory {
+		reg = <0x00000000 0x08000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		restart {
+			label = "Reset";
+			linux,code = <KEY_RESTART>;
+			gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index 015a06c..63d00a6 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -104,7 +104,7 @@
 		local-timer@ad0600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
-			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
 			clocks = <&chip CLKID_TWD>;
 		};
 
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 230df3b..81b670a 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -45,6 +45,11 @@
 
 		ranges = <0 0xf7000000 0x1000000>;
 
+		pmu {
+			compatible = "arm,cortex-a9-pmu";
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		sdhci0: sdhci@ab0000 {
 			compatible = "mrvl,pxav3-mmc";
 			reg = <0xab0000 0x200>;
@@ -71,7 +76,7 @@
 		local-timer@ad0600 {
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
-			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;
 			clocks = <&chip CLKID_TWD>;
 		};
 
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index e2f61f2..be53972 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -63,6 +63,14 @@
 		ranges = <0 0xf7000000 0x1000000>;
 		interrupt-parent = <&gic>;
 
+		pmu {
+			compatible = "arm,cortex-a9-pmu";
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		sdhci0: sdhci@ab0000 {
 			compatible = "mrvl,pxav3-mmc";
 			reg = <0xab0000 0x200>;
@@ -105,7 +113,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0xad0600 0x20>;
 			clocks = <&chip CLKID_TWD>;
-			interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
 		gic: interrupt-controller@ad1000 {
diff --git a/arch/arm/boot/dts/cx92755.dtsi b/arch/arm/boot/dts/cx92755.dtsi
new file mode 100644
index 0000000..490c080
--- /dev/null
+++ b/arch/arm/boot/dts/cx92755.dtsi
@@ -0,0 +1,113 @@
+/*
+ * Device Tree Include file for the Conexant Digicolor CX92755 SoC
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ *  Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "cnxt,cx92755";
+
+	interrupt-parent = <&intc>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a8";
+			reg = <0x0>;
+		};
+	};
+
+	main_clk: main_clk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency  = <200000000>;
+	};
+
+	intc: interrupt-controller@f0000040 {
+		compatible = "cnxt,cx92755-ic";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0xf0000040 0x40>;
+		syscon = <&uc_regs>;
+	};
+
+	timer@f0000fc0 {
+		compatible = "cnxt,cx92755-timer";
+		reg = <0xf0000fc0 0x40>;
+		interrupts = <19>, <31>, <34>, <35>, <52>, <53>, <54>, <55>;
+		clocks = <&main_clk>;
+	};
+
+	uc_regs: syscon@f00003a0 {
+		compatible = "cnxt,cx92755-uc", "syscon";
+		reg = <0xf00003a0 0x10>;
+	};
+
+	uart0: uart@f0000740 {
+		compatible = "cnxt,cx92755-usart";
+		reg = <0xf0000740 0x20>;
+		clocks = <&main_clk>;
+		interrupts = <44>;
+		status = "disabled";
+	};
+
+	uart1: uart@f0000760 {
+		compatible = "cnxt,cx92755-usart";
+		reg = <0xf0000760 0x20>;
+		clocks = <&main_clk>;
+		interrupts = <45>;
+		status = "disabled";
+	};
+
+	uart2: uart@f0000780 {
+		compatible = "cnxt,cx92755-usart";
+		reg = <0xf0000780 0x20>;
+		clocks = <&main_clk>;
+		interrupts = <46>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/cx92755_equinox.dts b/arch/arm/boot/dts/cx92755_equinox.dts
new file mode 100644
index 0000000..f33bf56
--- /dev/null
+++ b/arch/arm/boot/dts/cx92755_equinox.dts
@@ -0,0 +1,74 @@
+/*
+ * Device Tree file for the Conexant Equinox CX92755 EVK
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ *  Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "cx92755.dtsi"
+
+/ {
+	model = "Conexant Equinox CX92755 EVK";
+	compatible = "cnxt,equinox", "cnxt,cx92755";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+	};
+
+	memory@0 {
+		reg = <0 0x8000000>;
+		device_type = "memory";
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200";
+		stdout-path = &uart0;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/dm8168-evm.dts b/arch/arm/boot/dts/dm8168-evm.dts
new file mode 100644
index 0000000..857d028
--- /dev/null
+++ b/arch/arm/boot/dts/dm8168-evm.dts
@@ -0,0 +1,129 @@
+/*
+ * 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 "dm816x.dtsi"
+
+/ {
+	model = "DM8168 EVM";
+	compatible = "ti,dm8168-evm", "ti,dm8168";
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x40000000	/* 1 GB */
+		       0xc0000000 0x40000000>;	/* 1 GB */
+	};
+
+	/* FDC6331L controlled by SD_POW pin */
+	vmmcsd_fixed: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vmmcsd_fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&dm816x_pinmux {
+	mcspi1_pins: pinmux_mcspi1_pins {
+		pinctrl-single,pins = <
+			DM816X_IOPAD(0x0a94, PIN_INPUT | MUX_MODE0)	/* SPI_SCLK */
+			DM816X_IOPAD(0x0a98, PIN_OUTPUT | MUX_MODE0)	/* SPI_SCS0 */
+			DM816X_IOPAD(0x0aa8, PIN_INPUT | MUX_MODE0)	/* SPI_D0 */
+			DM816X_IOPAD(0x0aac, PIN_INPUT | MUX_MODE0)	/* SPI_D1 */
+		>;
+	};
+};
+
+&i2c1 {
+	extgpio0: pcf8575@20 {
+		compatible = "nxp,pcf8575";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&i2c2 {
+	extgpio1: pcf8575@20 {
+		compatible = "nxp,pcf8575";
+		reg = <0x20>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
+
+&gpmc {
+	ranges = <0 0 0x04000000 0x01000000>;	/* CS0: 16MB for NAND */
+
+	nand@0,0 {
+		linux,mtd-name= "micron,mt29f2g16aadwp";
+		reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ti,nand-ecc-opt = "bch8";
+		nand-bus-width = <16>;
+		gpmc,device-width = <2>;
+		gpmc,sync-clk-ps = <0>;
+		gpmc,cs-on-ns = <0>;
+		gpmc,cs-rd-off-ns = <44>;
+		gpmc,cs-wr-off-ns = <44>;
+		gpmc,adv-on-ns = <6>;
+		gpmc,adv-rd-off-ns = <34>;
+		gpmc,adv-wr-off-ns = <44>;
+		gpmc,we-on-ns = <0>;
+		gpmc,we-off-ns = <40>;
+		gpmc,oe-on-ns = <0>;
+		gpmc,oe-off-ns = <54>;
+		gpmc,access-ns = <64>;
+		gpmc,rd-cycle-ns = <82>;
+		gpmc,wr-cycle-ns = <82>;
+		gpmc,wait-on-read = "true";
+		gpmc,wait-on-write = "true";
+		gpmc,bus-turnaround-ns = <0>;
+		gpmc,cycle2cycle-delay-ns = <0>;
+		gpmc,clk-activation-ns = <0>;
+		gpmc,wait-monitoring-ns = <0>;
+		gpmc,wr-access-ns = <40>;
+		gpmc,wr-data-mux-bus-ns = <0>;
+		partition@0 {
+			label = "X-Loader";
+			reg = <0 0x80000>;
+		};
+		partition@0x80000 {
+			label = "U-Boot";
+			reg = <0x80000 0x1c0000>;
+		};
+		partition@0x1c0000 {
+			label = "Environment";
+			reg = <0x240000 0x40000>;
+		};
+		partition@0x280000 {
+			label = "Kernel";
+			reg = <0x280000 0x500000>;
+		};
+		partition@0x780000 {
+			label = "Filesystem";
+			reg = <0x780000 0xf880000>;
+		};
+	};
+};
+
+&mcspi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcspi1_pins>;
+
+	m25p80@0 {
+		compatible = "w25x32";
+		spi-max-frequency = <48000000>;
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
diff --git a/arch/arm/boot/dts/dm816x-clocks.dtsi b/arch/arm/boot/dts/dm816x-clocks.dtsi
new file mode 100644
index 0000000..50d9d33
--- /dev/null
+++ b/arch/arm/boot/dts/dm816x-clocks.dtsi
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+&scrm {
+	main_fapll: main_fapll {
+		#clock-cells = <1>;
+		compatible = "ti,dm816-fapll-clock";
+		reg = <0x400 0x40>;
+		clocks = <&sys_clkin_ck &sys_clkin_ck>;
+		clock-indices = <1>, <2>, <3>, <4>, <5>,
+				<6>, <7>;
+		clock-output-names = "main_pll_clk1",
+				     "main_pll_clk2",
+				     "main_pll_clk3",
+				     "main_pll_clk4",
+				     "main_pll_clk5",
+				     "main_pll_clk6",
+				     "main_pll_clk7";
+	};
+
+	ddr_fapll: ddr_fapll {
+		#clock-cells = <1>;
+		compatible = "ti,dm816-fapll-clock";
+		reg = <0x440 0x30>;
+		clocks = <&sys_clkin_ck &sys_clkin_ck>;
+		clock-indices = <1>, <2>, <3>, <4>;
+		clock-output-names = "ddr_pll_clk1",
+				     "ddr_pll_clk2",
+				     "ddr_pll_clk3",
+				     "ddr_pll_clk4";
+	};
+
+	video_fapll: video_fapll {
+		#clock-cells = <1>;
+		compatible = "ti,dm816-fapll-clock";
+		reg = <0x470 0x30>;
+		clocks = <&sys_clkin_ck &sys_clkin_ck>;
+		clock-indices = <1>, <2>, <3>;
+		clock-output-names = "video_pll_clk1",
+				     "video_pll_clk2",
+				     "video_pll_clk3";
+	};
+
+	audio_fapll: audio_fapll {
+		#clock-cells = <1>;
+		compatible = "ti,dm816-fapll-clock";
+		reg = <0x4a0 0x30>;
+		clocks = <&main_fapll 7>, < &sys_clkin_ck>;
+		clock-indices = <1>, <2>, <3>, <4>, <5>;
+		clock-output-names = "audio_pll_clk1",
+				     "audio_pll_clk2",
+				     "audio_pll_clk3",
+				     "audio_pll_clk4",
+				     "audio_pll_clk5";
+	};
+};
+
+&scrm_clocks {
+	secure_32k_ck: secure_32k_ck {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	sys_32k_ck: sys_32k_ck {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	tclkin_ck: tclkin_ck {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	sys_clkin_ck: sys_clkin_ck {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <27000000>;
+	};
+};
+
+/* 0x48180000 */
+&prcm_clocks {
+	clkout_pre_ck: clkout_pre_ck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&main_fapll 5 &ddr_fapll 1 &video_fapll 1
+			  &audio_fapll 1>;
+		reg = <0x100>;
+	};
+
+	clkout_div_ck: clkout_div_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&clkout_pre_ck>;
+		ti,bit-shift = <3>;
+		ti,max-div = <8>;
+		reg = <0x100>;
+	};
+
+	clkout_ck: clkout_ck {
+		#clock-cells = <0>;
+		compatible = "ti,gate-clock";
+		clocks = <&clkout_div_ck>;
+		ti,bit-shift = <7>;
+		reg = <0x100>;
+	};
+
+	/* CM_DPLL clocks p1795 */
+	sysclk1_ck: sysclk1_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 1>;
+		ti,max-div = <7>;
+		reg = <0x0300>;
+	};
+
+	sysclk2_ck: sysclk2_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 2>;
+		ti,max-div = <7>;
+		reg = <0x0304>;
+	};
+
+	sysclk3_ck: sysclk3_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 3>;
+		ti,max-div = <7>;
+		reg = <0x0308>;
+	};
+
+	sysclk4_ck: sysclk4_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 4>;
+		ti,max-div = <1>;
+		reg = <0x030c>;
+	};
+
+	sysclk5_ck: sysclk5_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&sysclk4_ck>;
+		ti,max-div = <1>;
+		reg = <0x0310>;
+	};
+
+	sysclk6_ck: sysclk6_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 4>;
+		ti,dividers = <2>, <4>;
+		reg = <0x0314>;
+	};
+
+	sysclk10_ck: sysclk10_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&ddr_fapll 2>;
+		ti,max-div = <7>;
+		reg = <0x0324>;
+	};
+
+	sysclk24_ck: sysclk24_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&main_fapll 5>;
+		ti,max-div = <7>;
+		reg = <0x03b4>;
+	};
+
+	mpu_ck: mpu_ck {
+		#clock-cells = <0>;
+		compatible = "ti,gate-clock";
+		clocks = <&sysclk2_ck>;
+		ti,bit-shift = <1>;
+                reg = <0x15dc>;
+	};
+
+	audio_pll_a_ck: audio_pll_a_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&audio_fapll 1>;
+		ti,max-div = <7>;
+		reg = <0x035c>;
+	};
+
+	sysclk18_ck: sysclk18_ck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&sys_32k_ck>, <&audio_pll_a_ck>;
+		reg = <0x0378>;
+	};
+
+	timer1_fck: timer1_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x0390>;
+	};
+
+	timer2_fck: timer2_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x0394>;
+	};
+
+	timer3_fck: timer3_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x0398>;
+	};
+
+	timer4_fck: timer4_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x039c>;
+	};
+
+	timer5_fck: timer5_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x03a0>;
+	};
+
+	timer6_fck: timer6_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x03a4>;
+	};
+
+	timer7_fck: timer7_fck {
+		#clock-cells = <0>;
+		compatible = "ti,mux-clock";
+		clocks = <&tclkin_ck>, <&sysclk18_ck>, <&sys_clkin_ck>;
+		reg = <0x03a8>;
+	};
+};
diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi
new file mode 100644
index 0000000..d98d0f7
--- /dev/null
+++ b/arch/arm/boot/dts/dm816x.dtsi
@@ -0,0 +1,392 @@
+/*
+ * 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 <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/omap.h>
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "ti,dm816";
+	interrupt-parent = <&intc>;
+
+	aliases {
+		i2c0 = &i2c1;
+		i2c1 = &i2c2;
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+		ethernet0 = &eth0;
+		ethernet1 = &eth1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			compatible = "arm,cortex-a8";
+			device_type = "cpu";
+			reg = <0>;
+		};
+	};
+
+	pmu {
+		compatible = "arm,cortex-a8-pmu";
+		interrupts = <3>;
+	};
+
+	/*
+	 * The soc node represents the soc top level view. It is used for IPs
+	 * that are not memory mapped in the MPU view or for the MPU itself.
+	 */
+	soc {
+		compatible = "ti,omap-infra";
+		mpu {
+			compatible = "ti,omap3-mpu";
+			ti,hwmods = "mpu";
+		};
+	};
+
+	/*
+	 * XXX: Use a flat representation of the dm816x interconnect.
+	 * The real dm816x interconnect network is quite complex. Since
+	 * it will not bring real advantage to represent that in DT
+	 * for the moment, just use a fake OCP bus entry to represent
+	 * the whole bus hierarchy.
+	 */
+	ocp {
+		compatible = "ti,omap3-l3-smx", "simple-bus";
+		reg = <0x44000000 0x10000>;
+		interrupts = <9 10>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		ti,hwmods = "l3_main";
+
+		prcm: prcm@48180000 {
+			compatible = "ti,dm816-prcm";
+			reg = <0x48180000 0x4000>;
+
+			prcm_clocks: clocks {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			prcm_clockdomains: clockdomains {
+			};
+		};
+
+		scrm: scrm@48140000 {
+			compatible = "ti,dm816-scrm", "simple-bus";
+			reg = <0x48140000 0x21000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x48140000 0x21000>;
+
+			dm816x_pinmux: pinmux@800 {
+				compatible = "pinctrl-single";
+				reg = <0x800 0x50a>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				pinctrl-single,register-width = <16>;
+				pinctrl-single,function-mask = <0xf>;
+			};
+
+			/* Device Configuration Registers */
+			scm_conf: syscon@600 {
+				compatible = "syscon";
+				reg = <0x600 0x110>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+			};
+
+			scrm_clocks: clocks {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			scrm_clockdomains: clockdomains {
+			};
+		};
+
+		edma: edma@49000000 {
+			compatible = "ti,edma3";
+			ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2", "tptc3";
+			reg =   <0x49000000 0x10000>,
+			        <0x44e10f90 0x40>;
+			interrupts = <12 13 14>;
+			#dma-cells = <1>;
+		};
+
+		elm: elm@48080000 {
+			compatible = "ti,816-elm";
+			ti,hwmods = "elm";
+			reg = <0x48080000 0x2000>;
+			interrupts = <4>;
+		};
+
+		gpio1: gpio@48032000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio1";
+			reg = <0x48032000 0x1000>;
+			interrupts = <97>;
+		};
+
+		gpio2: gpio@4804c000 {
+			compatible = "ti,omap3-gpio";
+			ti,hwmods = "gpio2";
+			reg = <0x4804c000 0x1000>;
+			interrupts = <99>;
+		};
+
+		gpmc: gpmc@50000000 {
+			compatible = "ti,am3352-gpmc";
+			ti,hwmods = "gpmc";
+			reg = <0x50000000 0x2000>;
+			#address-cells = <2>;
+			#size-cells = <1>;
+			interrupts = <100>;
+			gpmc,num-cs = <6>;
+			gpmc,num-waitpins = <2>;
+		};
+
+		i2c1: i2c@48028000 {
+			compatible = "ti,omap4-i2c";
+			ti,hwmods = "i2c1";
+			reg = <0x48028000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <70>;
+			dmas = <&edma 58 &edma 59>;
+			dma-names = "tx", "rx";
+		};
+
+		i2c2: i2c@4802a000 {
+			compatible = "ti,omap4-i2c";
+			ti,hwmods = "i2c2";
+			reg = <0x4802a000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <71>;
+			dmas = <&edma 60 &edma 61>;
+			dma-names = "tx", "rx";
+		};
+
+		intc: interrupt-controller@48200000 {
+			compatible = "ti,dm816-intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			reg = <0x48200000 0x1000>;
+		};
+
+		mailbox: mailbox@480c8000 {
+			compatible = "ti,omap4-mailbox";
+			reg = <0x480c8000 0x2000>;
+			interrupts = <77>;
+			ti,hwmods = "mailbox";
+			ti,mbox-num-users = <4>;
+			ti,mbox-num-fifos = <12>;
+			mbox_dsp: mbox_dsp {
+				ti,mbox-tx = <3 0 0>;
+				ti,mbox-rx = <0 0 0>;
+			};
+		};
+
+		mdio: mdio@4a100800 {
+			compatible = "ti,davinci_mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x4a100800 0x100>;
+			ti,hwmods = "davinci_mdio";
+			bus_freq = <1000000>;
+			phy0: ethernet-phy@0 {
+				reg = <1>;
+			};
+			phy1: ethernet-phy@1 {
+				reg = <2>;
+			};
+		};
+
+		eth0: ethernet@4a100000 {
+			compatible = "ti,dm816-emac";
+			ti,hwmods = "emac0";
+			reg = <0x4a100000 0x800
+			       0x4a100900 0x3700>;
+			clocks = <&sysclk24_ck>;
+			syscon = <&scm_conf>;
+			ti,davinci-ctrl-reg-offset = <0>;
+			ti,davinci-ctrl-mod-reg-offset = <0x900>;
+			ti,davinci-ctrl-ram-offset = <0x2000>;
+			ti,davinci-ctrl-ram-size = <0x2000>;
+			interrupts = <40 41 42 43>;
+			phy-handle = <&phy0>;
+		};
+
+		eth1: ethernet@4a120000 {
+			compatible = "ti,dm816-emac";
+			ti,hwmods = "emac1";
+			reg = <0x4a120000 0x4000>;
+			clocks = <&sysclk24_ck>;
+			syscon = <&scm_conf>;
+			ti,davinci-ctrl-reg-offset = <0>;
+			ti,davinci-ctrl-mod-reg-offset = <0x900>;
+			ti,davinci-ctrl-ram-offset = <0x2000>;
+			ti,davinci-ctrl-ram-size = <0x2000>;
+			interrupts = <44 45 46 47>;
+			phy-handle = <&phy1>;
+		};
+
+		mcspi1: spi@48030000 {
+			compatible = "ti,omap4-mcspi";
+			reg = <0x48030000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <65>;
+			ti,spi-num-cs = <4>;
+			ti,hwmods = "mcspi1";
+			dmas = <&edma 16 &edma 17
+				&edma 18 &edma 19>;
+			dma-names = "tx0", "rx0", "tx1", "rx1";
+		};
+
+		mmc1: mmc@48060000 {
+			compatible = "ti,omap4-hsmmc";
+			reg = <0x48060000 0x11000>;
+			ti,hwmods = "mmc1";
+			interrupts = <64>;
+			dmas = <&edma 24 &edma 25>;
+			dma-names = "tx", "rx";
+		};
+
+		timer1: timer@4802e000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x4802e000 0x2000>;
+			interrupts = <67>;
+			ti,hwmods = "timer1";
+			ti,timer-alwon;
+		};
+
+		timer2: timer@48040000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x48040000 0x2000>;
+			interrupts = <68>;
+			ti,hwmods = "timer2";
+		};
+
+		timer3: timer@48042000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x48042000 0x2000>;
+			interrupts = <69>;
+			ti,hwmods = "timer3";
+		};
+
+		timer4: timer@48044000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x48044000 0x2000>;
+			interrupts = <92>;
+			ti,hwmods = "timer4";
+		};
+
+		timer5: timer@48046000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x48046000 0x2000>;
+			interrupts = <93>;
+			ti,hwmods = "timer5";
+		};
+
+		timer6: timer@48048000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x48048000 0x2000>;
+			interrupts = <94>;
+			ti,hwmods = "timer6";
+		};
+
+		timer7: timer@4804a000 {
+			compatible = "ti,dm816-timer";
+			reg = <0x4804a000 0x2000>;
+			interrupts = <95>;
+			ti,hwmods = "timer7";
+		};
+
+		uart1: uart@48020000 {
+			compatible = "ti,omap3-uart";
+			ti,hwmods = "uart1";
+			reg = <0x48020000 0x2000>;
+			clock-frequency = <48000000>;
+			interrupts = <72>;
+			dmas = <&edma 26 &edma 27>;
+			dma-names = "tx", "rx";
+		};
+
+		uart2: uart@48022000 {
+			compatible = "ti,omap3-uart";
+			ti,hwmods = "uart2";
+			reg = <0x48022000 0x2000>;
+			clock-frequency = <48000000>;
+			interrupts = <73>;
+			dmas = <&edma 28 &edma 29>;
+			dma-names = "tx", "rx";
+		};
+
+		uart3: uart@48024000 {
+			compatible = "ti,omap3-uart";
+			ti,hwmods = "uart3";
+			reg = <0x48024000 0x2000>;
+			clock-frequency = <48000000>;
+			interrupts = <74>;
+			dmas = <&edma 30 &edma 31>;
+			dma-names = "tx", "rx";
+		};
+
+		/* NOTE: USB needs a transceiver driver for phys to work */
+		usb: usb_otg_hs@47401000 {
+			compatible = "ti,am33xx-usb";
+			reg = <0x47401000 0x400000>;
+			ranges;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ti,hwmods = "usb_otg_hs";
+
+			usb0: usb@47401000 {
+				compatible = "ti,musb-am33xx";
+				reg = <0x47401400 0x400
+				       0x47401000 0x200>;
+				reg-names = "mc", "control";
+				interrupts = <18>;
+				interrupt-names = "mc";
+				dr_mode = "otg";
+				mentor,multipoint = <1>;
+				mentor,num-eps = <16>;
+				mentor,ram-bits = <12>;
+				mentor,power = <500>;
+			};
+
+			usb1: usb@47401800 {
+				compatible = "ti,musb-am33xx";
+				status = "disabled";
+				reg = <0x47401c00 0x400
+				       0x47401800 0x200>;
+				reg-names = "mc", "control";
+				interrupts = <19>;
+				interrupt-names = "mc";
+				dr_mode = "otg";
+				mentor,multipoint = <1>;
+				mentor,num-eps = <16>;
+				mentor,ram-bits = <12>;
+				mentor,power = <500>;
+			};
+		};
+
+		wd_timer2: wd_timer@480c2000 {
+			compatible = "ti,omap3-wdt";
+			ti,hwmods = "wd_timer";
+			reg = <0x480c2000 0x1000>;
+			interrupts = <0>;
+		};
+	};
+};
+
+#include "dm816x-clocks.dtsi"
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index ad4118f..746cddb 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -26,6 +26,16 @@
 		regulator-max-microvolt = <3300000>;
 	};
 
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	extcon_usb2: extcon_usb2 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>;
+	};
+
 	vtt_fixed: fixedregulator-vtt {
 		compatible = "regulator-fixed";
 		regulator-name = "vtt_fixed";
@@ -391,6 +401,19 @@
 			};
 		};
 	};
+
+	pcf_gpio_21: gpio@21 {
+		compatible = "ti,pcf8575";
+		reg = <0x21>;
+		lines-initial-states = <0x1408>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
 };
 
 &i2c2 {
@@ -520,6 +543,14 @@
 	};
 };
 
+&omap_dwc3_1 {
+	extcon = <&extcon_usb1>;
+};
+
+&omap_dwc3_2 {
+	extcon = <&extcon_usb2>;
+};
+
 &usb1 {
 	dr_mode = "peripheral";
 	pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 63f8b00..5827fed 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -1111,7 +1111,6 @@
 					      "wkupclk", "refclk",
 					      "div-clk", "phy-div";
 				#phy-cells = <0>;
-				id = <1>;
 				ti,hwmods = "pcie1-phy";
 			};
 
@@ -1132,7 +1131,6 @@
 					      "div-clk", "phy-div";
 				#phy-cells = <0>;
 				ti,hwmods = "pcie2-phy";
-				id = <2>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index 89085d0..4d87117 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include "dra72x.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "TI DRA722";
@@ -24,6 +25,16 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 	};
+
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>;
+	};
+
+	extcon_usb2: extcon_usb2 {
+		compatible = "linux,extcon-usb-gpio";
+		id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>;
+	};
 };
 
 &dra7_pmx_core {
@@ -121,6 +132,18 @@
 			0x418   (MUX_MODE15)	/* wakeup0.off */
 		>;
 	};
+
+	qspi1_pins: pinmux_qspi1_pins {
+		pinctrl-single,pins = <
+			0x74 (PIN_OUTPUT | MUX_MODE1)	/* gpmc_a13.qspi1_rtclk */
+			0x78 (PIN_INPUT | MUX_MODE1)	/* gpmc_a14.qspi1_d3 */
+			0x7c (PIN_INPUT | MUX_MODE1)	/* gpmc_a15.qspi1_d2 */
+			0x80 (PIN_INPUT | MUX_MODE1)	/* gpmc_a16.qspi1_d1 */
+			0x84 (PIN_INPUT | MUX_MODE1)	/* gpmc_a17.qspi1_d0 */
+			0x88 (PIN_OUTPUT | MUX_MODE1)	/* qpmc_a18.qspi1_sclk */
+			0xb8 (PIN_OUTPUT | MUX_MODE1)	/* gpmc_cs2.qspi1_cs0 */
+		>;
+	};
 };
 
 &i2c1 {
@@ -243,6 +266,18 @@
 			ti,palmas-long-press-seconds = <6>;
 		};
 	};
+
+	pcf_gpio_21: gpio@21 {
+		compatible = "ti,pcf8575";
+		reg = <0x21>;
+		lines-initial-states = <0x1408>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
 };
 
 &uart1 {
@@ -345,6 +380,14 @@
 	phy-supply = <&ldo4_reg>;
 };
 
+&omap_dwc3_1 {
+	extcon = <&extcon_usb1>;
+};
+
+&omap_dwc3_2 {
+	extcon = <&extcon_usb2>;
+};
+
 &usb1 {
 	dr_mode = "peripheral";
 	pinctrl-names = "default";
@@ -461,3 +504,68 @@
 	pinctrl-0 = <&dcan1_pins_default>;
 	pinctrl-1 = <&dcan1_pins_sleep>;
 };
+
+&qspi {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&qspi1_pins>;
+
+	spi-max-frequency = <48000000>;
+	m25p80@0 {
+		compatible = "s25fl256s1";
+		spi-max-frequency = <48000000>;
+		reg = <0>;
+		spi-tx-bus-width = <1>;
+		spi-rx-bus-width = <4>;
+		spi-cpol;
+		spi-cpha;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		/* MTD partition table.
+		 * The ROM checks the first four physical blocks
+		 * for a valid file to boot and the flash here is
+		 * 64KiB block size.
+		 */
+		partition@0 {
+			label = "QSPI.SPL";
+			reg = <0x00000000 0x000010000>;
+		};
+		partition@1 {
+			label = "QSPI.SPL.backup1";
+			reg = <0x00010000 0x00010000>;
+		};
+		partition@2 {
+			label = "QSPI.SPL.backup2";
+			reg = <0x00020000 0x00010000>;
+		};
+		partition@3 {
+			label = "QSPI.SPL.backup3";
+			reg = <0x00030000 0x00010000>;
+		};
+		partition@4 {
+			label = "QSPI.u-boot";
+			reg = <0x00040000 0x00100000>;
+		};
+		partition@5 {
+			label = "QSPI.u-boot-spl-os";
+			reg = <0x00140000 0x00080000>;
+		};
+		partition@6 {
+			label = "QSPI.u-boot-env";
+			reg = <0x001c0000 0x00010000>;
+		};
+		partition@7 {
+			label = "QSPI.u-boot-env.backup1";
+			reg = <0x001d0000 0x0010000>;
+		};
+		partition@8 {
+			label = "QSPI.kernel";
+			reg = <0x001e0000 0x0800000>;
+		};
+		partition@9 {
+			label = "QSPI.file-system";
+			reg = <0x009e0000 0x01620000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts
index 8f941c2..2430443 100644
--- a/arch/arm/boot/dts/ethernut5.dts
+++ b/arch/arm/boot/dts/ethernut5.dts
@@ -6,7 +6,7 @@
  * Licensed under GPLv2.
  */
 /dts-v1/;
-#include "at91sam9260.dtsi"
+#include "at91sam9xe.dtsi"
 
 / {
 	model = "Ethernut 5";
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 24822aa..1d483c1 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -15,6 +15,7 @@
 /dts-v1/;
 #include "exynos3250.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "Samsung Monk board";
@@ -37,9 +38,7 @@
 		compatible = "gpio-keys";
 
 		power_key {
-			interrupt-parent = <&gpx2>;
-			interrupts = <7 0>;
-			gpios = <&gpx2 7 1>;
+			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
 			linux,code = <KEY_POWER>;
 			label = "power key";
 			debounce-interval = <10>;
@@ -109,6 +108,13 @@
 			};
 		};
 	};
+
+	haptics {
+		compatible = "regulator-haptic";
+		haptic-supply = <&motor_reg>;
+		min-microvolt = <1100000>;
+		max-microvolt = <2700000>;
+	};
 };
 
 &adc {
@@ -134,6 +140,17 @@
 	};
 };
 
+&exynos_usbphy {
+	status = "okay";
+};
+
+&hsotg {
+	vusb_d-supply = <&ldo15_reg>;
+	vusb_a-supply = <&ldo12_reg>;
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
 &i2c_0 {
 	#address-cells = <1>;
 	#size-cells = <0>;
@@ -420,6 +437,46 @@
 	status = "okay";
 };
 
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &xusbxti {
 	clock-frequency = <24000000>;
 };
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 80aa8b4..0b99068 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -15,6 +15,7 @@
 /dts-v1/;
 #include "exynos3250.dtsi"
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "Samsung Rinato board";
@@ -37,9 +38,7 @@
 		compatible = "gpio-keys";
 
 		power_key {
-			interrupt-parent = <&gpx2>;
-			interrupts = <7 0>;
-			gpios = <&gpx2 7 1>;
+			gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
 			linux,code = <KEY_POWER>;
 			label = "power key";
 			debounce-interval = <10>;
@@ -100,6 +99,13 @@
 			};
 		};
 	};
+
+	haptics {
+		compatible = "regulator-haptic";
+		haptic-supply = <&motor_reg>;
+		min-microvolt = <1100000>;
+		max-microvolt = <2700000>;
+	};
 };
 
 &adc {
@@ -125,6 +131,87 @@
 	};
 };
 
+&exynos_usbphy {
+	status = "okay";
+};
+
+&hsotg {
+	vusb_d-supply = <&ldo15_reg>;
+	vusb_a-supply = <&ldo12_reg>;
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&dsi_0 {
+	vddcore-supply = <&ldo6_reg>;
+	vddio-supply = <&ldo6_reg>;
+	samsung,pll-clock-frequency = <24000000>;
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@1 {
+			reg = <1>;
+
+			dsi_out: endpoint {
+				remote-endpoint = <&dsi_in>;
+				samsung,burst-clock-frequency = <250000000>;
+				samsung,esc-clock-frequency = <20000000>;
+			};
+		};
+	};
+
+	panel@0 {
+		compatible = "samsung,s6e63j0x03";
+		reg = <0>;
+		vdd3-supply = <&ldo16_reg>;
+		vci-supply = <&ldo20_reg>;
+		reset-gpios = <&gpe0 1 0>;
+		te-gpios = <&gpx0 6 0>;
+		power-on-delay= <30>;
+		power-off-delay= <120>;
+		reset-delay = <5>;
+		init-delay = <100>;
+		flip-horizontal;
+		flip-vertical;
+		panel-width-mm = <29>;
+		panel-height-mm = <29>;
+
+		display-timings {
+			timing-0 {
+				clock-frequency = <0>;
+				hactive = <320>;
+				vactive = <320>;
+				hfront-porch = <1>;
+				hback-porch = <1>;
+				hsync-len = <1>;
+				vfront-porch = <150>;
+				vback-porch = <1>;
+				vsync-len = <2>;
+			};
+		};
+
+		port {
+			dsi_in: endpoint {
+				remote-endpoint = <&dsi_out>;
+			};
+		};
+	};
+};
+
+&fimd {
+	status = "okay";
+
+	i80-if-timings {
+		cs-setup = <0>;
+		wr-setup = <0>;
+		wr-act = <1>;
+		wr-hold = <0>;
+	};
+};
+
 &i2c_0 {
 	#address-cells = <1>;
 	#size-cells = <0>;
@@ -523,6 +610,46 @@
 	status = "okay";
 };
 
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &xusbxti {
 	clock-frequency = <24000000>;
 };
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 2246549..277b48b 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -141,26 +141,31 @@
 		pd_cam: cam-power-domain@10023C00 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10023C00 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_mfc: mfc-power-domain@10023C40 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10023C40 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_g3d: g3d-power-domain@10023C60 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10023C60 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_lcd0: lcd0-power-domain@10023C80 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10023C80 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_isp: isp-power-domain@10023CA0 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10023CA0 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		cmu: clock-controller@10030000 {
@@ -235,7 +240,7 @@
 			interrupts = <0 84 0>, <0 85 0>, <0 86 0>;
 			clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>;
 			clock-names = "sclk_fimd", "fimd";
-			samsung,power-domain = <&pd_lcd0>;
+			power-domains = <&pd_lcd0>;
 			samsung,sysreg = <&sys_reg>;
 			status = "disabled";
 		};
@@ -245,7 +250,7 @@
 			reg = <0x11C80000 0x10000>;
 			interrupts = <0 83 0>;
 			samsung,phy-type = <0>;
-			samsung,power-domain = <&pd_lcd0>;
+			power-domains = <&pd_lcd0>;
 			phys = <&mipi_phy 1>;
 			phy-names = "dsim";
 			clocks = <&cmu CLK_DSIM0>, <&cmu CLK_SCLK_MIPI0>;
@@ -255,6 +260,17 @@
 			status = "disabled";
 		};
 
+		hsotg: hsotg@12480000 {
+			compatible = "snps,dwc2";
+			reg = <0x12480000 0x20000>;
+			interrupts = <0 141 0>;
+			clocks = <&cmu CLK_USBOTG>;
+			clock-names = "otg";
+			phys = <&exynos_usbphy 0>;
+			phy-names = "usb2-phy";
+			status = "disabled";
+		};
+
 		mshc_0: mshc@12510000 {
 			compatible = "samsung,exynos5250-dw-mshc";
 			reg = <0x12510000 0x1000>;
@@ -279,6 +295,16 @@
 			status = "disabled";
 		};
 
+		exynos_usbphy: exynos-usbphy@125B0000 {
+			compatible = "samsung,exynos3250-usb2-phy";
+			reg = <0x125B0000 0x100>;
+			samsung,pmureg-phandle = <&pmu_system_controller>;
+			clocks = <&cmu CLK_USBOTG>, <&cmu CLK_SCLK_UPLL>;
+			clock-names = "phy", "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+
 		amba {
 			compatible = "arm,amba-bus";
 			#address-cells = <1>;
@@ -327,7 +353,7 @@
 			interrupts = <0 102 0>;
 			clock-names = "mfc", "sclk_mfc";
 			clocks = <&cmu CLK_MFC>, <&cmu CLK_SCLK_MFC>;
-			samsung,power-domain = <&pd_mfc>;
+			power-domains = <&pd_mfc>;
 			status = "disabled";
 		};
 
@@ -515,6 +541,80 @@
 			compatible = "arm,cortex-a7-pmu";
 			interrupts = <0 18 0>, <0 19 0>;
 		};
+
+		ppmu_dmc0: ppmu_dmc0@106a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106a0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_dmc1: ppmu_dmc1@106b0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106b0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_cpu: ppmu_cpu@106c0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106c0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_rightbus: ppmu_rightbus@112a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x112a0000 0x2000>;
+			clocks = <&cmu CLK_PPMURIGHT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_leftbus: ppmu_leftbus0@116a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x116a0000 0x2000>;
+			clocks = <&cmu CLK_PPMULEFT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_camif: ppmu_camif@11ac0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11ac0000 0x2000>;
+			clocks = <&cmu CLK_PPMUCAMIF>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_lcd0: ppmu_lcd0@11e40000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11e40000 0x2000>;
+			clocks = <&cmu CLK_PPMULCD0>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_fsys: ppmu_fsys@12630000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12630000 0x2000>;
+			clocks = <&cmu CLK_PPMUFILE>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_g3d: ppmu_g3d@13220000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13220000 0x2000>;
+			clocks = <&cmu CLK_PPMUG3D>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_mfc: ppmu_mfc@13660000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13660000 0x2000>;
+			clocks = <&cmu CLK_PPMUMFC_L>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index cb60010..76173ca 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -79,41 +79,49 @@
 		compatible = "samsung,s5pv210-mipi-video-phy";
 		reg = <0x10020710 8>;
 		#phy-cells = <1>;
+		syscon = <&pmu_system_controller>;
 	};
 
 	pd_mfc: mfc-power-domain@10023C40 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023C40 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_g3d: g3d-power-domain@10023C60 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023C60 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_lcd0: lcd0-power-domain@10023C80 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023C80 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_tv: tv-power-domain@10023C20 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023C20 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_cam: cam-power-domain@10023C00 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023C00 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_gps: gps-power-domain@10023CE0 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023CE0 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_gps_alive: gps-alive-power-domain@10023D00 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023D00 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	gic: interrupt-controller@10490000 {
@@ -150,7 +158,7 @@
 		compatible = "samsung,exynos4210-mipi-dsi";
 		reg = <0x11C80000 0x10000>;
 		interrupts = <0 79 0>;
-		samsung,power-domain = <&pd_lcd0>;
+		power-domains = <&pd_lcd0>;
 		phys = <&mipi_phy 1>;
 		phy-names = "dsim";
 		clocks = <&clock CLK_DSIM0>, <&clock CLK_SCLK_MIPI0>;
@@ -175,7 +183,7 @@
 			interrupts = <0 84 0>;
 			clocks = <&clock CLK_FIMC0>, <&clock CLK_SCLK_FIMC0>;
 			clock-names = "fimc", "sclk_fimc";
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			samsung,sysreg = <&sys_reg>;
 			status = "disabled";
 		};
@@ -186,7 +194,7 @@
 			interrupts = <0 85 0>;
 			clocks = <&clock CLK_FIMC1>, <&clock CLK_SCLK_FIMC1>;
 			clock-names = "fimc", "sclk_fimc";
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			samsung,sysreg = <&sys_reg>;
 			status = "disabled";
 		};
@@ -197,7 +205,7 @@
 			interrupts = <0 86 0>;
 			clocks = <&clock CLK_FIMC2>, <&clock CLK_SCLK_FIMC2>;
 			clock-names = "fimc", "sclk_fimc";
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			samsung,sysreg = <&sys_reg>;
 			status = "disabled";
 		};
@@ -208,7 +216,7 @@
 			interrupts = <0 87 0>;
 			clocks = <&clock CLK_FIMC3>, <&clock CLK_SCLK_FIMC3>;
 			clock-names = "fimc", "sclk_fimc";
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			samsung,sysreg = <&sys_reg>;
 			status = "disabled";
 		};
@@ -220,7 +228,7 @@
 			clocks = <&clock CLK_CSIS0>, <&clock CLK_SCLK_CSIS0>;
 			clock-names = "csis", "sclk_csis";
 			bus-width = <4>;
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			phys = <&mipi_phy 0>;
 			phy-names = "csis";
 			status = "disabled";
@@ -235,7 +243,7 @@
 			clocks = <&clock CLK_CSIS1>, <&clock CLK_SCLK_CSIS1>;
 			clock-names = "csis", "sclk_csis";
 			bus-width = <2>;
-			samsung,power-domain = <&pd_cam>;
+			power-domains = <&pd_cam>;
 			phys = <&mipi_phy 2>;
 			phy-names = "csis";
 			status = "disabled";
@@ -400,7 +408,7 @@
 		compatible = "samsung,mfc-v5";
 		reg = <0x13400000 0x10000>;
 		interrupts = <0 94 0>;
-		samsung,power-domain = <&pd_mfc>;
+		power-domains = <&pd_mfc>;
 		clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>;
 		clock-names = "mfc", "sclk_mfc";
 		status = "disabled";
@@ -650,8 +658,116 @@
 		interrupts = <11 0>, <11 1>, <11 2>;
 		clocks = <&clock CLK_SCLK_FIMD0>, <&clock CLK_FIMD0>;
 		clock-names = "sclk_fimd", "fimd";
-		samsung,power-domain = <&pd_lcd0>;
+		power-domains = <&pd_lcd0>;
 		samsung,sysreg = <&sys_reg>;
 		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_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_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_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_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_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_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";
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index f767c42..b811461 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -31,6 +31,7 @@
 
 	chosen {
 		bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
+		stdout-path = &serial_2;
 	};
 
 	regulators {
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts
index 676e6e0..86216ff 100644
--- a/arch/arm/boot/dts/exynos4210-smdkv310.dts
+++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts
@@ -27,6 +27,7 @@
 
 	chosen {
 		bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
+		stdout-path = &serial_1;
 	};
 
 	sdhci@12530000 {
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 7208362..3d6652a 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -28,6 +28,7 @@
 
 	chosen {
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
+		stdout-path = &serial_2;
 	};
 
 	regulators {
@@ -91,6 +92,7 @@
 	hsotg@12480000 {
 		vusb_d-supply = <&vusb_reg>;
 		vusb_a-supply = <&vusbdac_reg>;
+		dr_mode = "peripheral";
 		status = "okay";
 	};
 
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index aaf0cae..b57e6b8 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -26,6 +26,7 @@
 
 	chosen {
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rw rootwait earlyprintk panic=5 maxcpus=1";
+		stdout-path = &serial_2;
 	};
 
 	sysram@02020000 {
@@ -71,6 +72,7 @@
 	hsotg@12480000 {
 		vusb_d-supply = <&ldo3_reg>;
 		vusb_a-supply = <&ldo8_reg>;
+		dr_mode = "peripheral";
 		status = "okay";
 	};
 
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 8e45ea4..67c832c 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -79,6 +79,7 @@
 	pd_lcd1: lcd1-power-domain@10023CA0 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023CA0 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	l2c: l2-cache-controller@10502000 {
@@ -201,4 +202,12 @@
 			samsung,lcd-wb;
 		};
 	};
+
+	ppmu_lcd1: ppmu_lcd1@12240000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x12240000 0x2000>;
+		clocks = <&clock CLK_PPMULCD1>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index abd6336..de80b5b 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -12,6 +12,10 @@
 #include "exynos4412.dtsi"
 
 / {
+	chosen {
+		stdout-path = &serial_1;
+	};
+
 	firmware@0204F000 {
 		compatible = "samsung,secure-firmware";
 		reg = <0x0204F000 0x1000>;
@@ -398,6 +402,7 @@
 	};
 
 	hsotg@12480000 {
+		dr_mode = "peripheral";
 		status = "okay";
 		vusb_d-supply = <&ldo15_reg>;
 		vusb_a-supply = <&ldo12_reg>;
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index de15114..bd8b730 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -26,6 +26,7 @@
 
 	chosen {
 		bootargs ="console=ttySAC2,115200";
+		stdout-path = &serial_2;
 	};
 
 	firmware@0203F000 {
diff --git a/arch/arm/boot/dts/exynos4412-smdk4412.dts b/arch/arm/boot/dts/exynos4412-smdk4412.dts
index ded0b70..b9256af 100644
--- a/arch/arm/boot/dts/exynos4412-smdk4412.dts
+++ b/arch/arm/boot/dts/exynos4412-smdk4412.dts
@@ -25,6 +25,7 @@
 
 	chosen {
 		bootargs ="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
+		stdout-path = &serial_1;
 	};
 
 	g2d@10800000 {
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index ea6929d..d46fd4c 100644
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -18,6 +18,10 @@
 	model = "FriendlyARM TINY4412 board based on Exynos4412";
 	compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";
 
+	chosen {
+		stdout-path = &serial_0;
+	};
+
 	memory {
 		reg = <0x40000000 0x40000000>;
 	};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 29231b4..21f7480 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -15,6 +15,7 @@
 /dts-v1/;
 #include "exynos4412.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
 
 / {
 	model = "Samsung Trats 2 based on Exynos4412";
@@ -24,6 +25,7 @@
 		i2c9 = &i2c_ak8975;
 		i2c10 = &i2c_cm36651;
 		i2c11 = &i2c_max77693;
+		i2c12 = &i2c_max77693_fuel;
 	};
 
 	memory {
@@ -32,6 +34,7 @@
 
 	chosen {
 		bootargs = "console=ttySAC2,115200N8 root=/dev/mmcblk0p5 rootwait earlyprintk panic=5";
+		stdout-path = &serial_2;
 	};
 
 	firmware@0204F000 {
@@ -56,15 +59,6 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		vemmc_reg: regulator-0 {
-			compatible = "regulator-fixed";
-			regulator-name = "VMEM_VDD_2.8V";
-			regulator-min-microvolt = <2800000>;
-			regulator-max-microvolt = <2800000>;
-			gpio = <&gpk0 2 0>;
-			enable-active-high;
-		};
-
 		cam_io_reg: voltage-regulator-1 {
 			compatible = "regulator-fixed";
 			regulator-name = "CAM_SENSOR_A";
@@ -92,16 +86,6 @@
 			enable-active-high;
 		};
 
-		cam_isp_core_reg: voltage-regulator-4 {
-			compatible = "regulator-fixed";
-			regulator-name = "CAM_ISP_CORE_1.2V_EN";
-			regulator-min-microvolt = <1200000>;
-			regulator-max-microvolt = <1200000>;
-			gpio = <&gpm0 3 0>;
-			enable-active-high;
-			regulator-always-on;
-		};
-
 		ps_als_reg: voltage-regulator-5 {
 			compatible = "regulator-fixed";
 			regulator-name = "LED_A_3.0V";
@@ -203,6 +187,25 @@
 		};
 	};
 
+	i2c@138A0000 {
+		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@138D0000 {
 		samsung,i2c-sda-delay = <100>;
 		samsung,i2c-slave-addr = <0x10>;
@@ -225,7 +228,6 @@
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1000000>;
 					regulator-always-on;
-					regulator-mem-on;
 				};
 
 				ldo2_reg: ldo2 {
@@ -234,7 +236,9 @@
 					regulator-min-microvolt = <1200000>;
 					regulator-max-microvolt = <1200000>;
 					regulator-always-on;
-					regulator-mem-on;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				ldo3_reg: ldo3 {
@@ -243,7 +247,6 @@
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
 					regulator-always-on;
-					regulator-mem-on;
 				};
 
 				ldo4_reg: ldo4 {
@@ -252,7 +255,6 @@
 					regulator-min-microvolt = <2800000>;
 					regulator-max-microvolt = <2800000>;
 					regulator-always-on;
-					regulator-mem-on;
 				};
 
 				ldo5_reg: ldo5 {
@@ -261,7 +263,6 @@
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
 					regulator-always-on;
-					regulator-mem-on;
 				};
 
 				ldo6_reg: ldo6 {
@@ -270,7 +271,9 @@
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1000000>;
 					regulator-always-on;
-					regulator-mem-on;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				ldo7_reg: ldo7 {
@@ -279,7 +282,9 @@
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1000000>;
 					regulator-always-on;
-					regulator-mem-on;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				ldo8_reg: ldo8 {
@@ -287,7 +292,9 @@
 					regulator-name = "VMIPI_1.0V";
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1000000>;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				ldo9_reg: ldo9 {
@@ -295,7 +302,6 @@
 					regulator-name = "CAM_ISP_MIPI_1.2V";
 					regulator-min-microvolt = <1200000>;
 					regulator-max-microvolt = <1200000>;
-					regulator-mem-idle;
 				};
 
 				ldo10_reg: ldo10 {
@@ -303,7 +309,9 @@
 					regulator-name = "VMIPI_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				ldo11_reg: ldo11 {
@@ -312,7 +320,9 @@
 					regulator-min-microvolt = <1950000>;
 					regulator-max-microvolt = <1950000>;
 					regulator-always-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				ldo12_reg: ldo12 {
@@ -320,7 +330,9 @@
 					regulator-name = "VUOTG_3.0V";
 					regulator-min-microvolt = <3000000>;
 					regulator-max-microvolt = <3000000>;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				ldo13_reg: ldo13 {
@@ -328,7 +340,6 @@
 					regulator-name = "NFC_AVDD_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-idle;
 				};
 
 				ldo14_reg: ldo14 {
@@ -337,7 +348,9 @@
 					regulator-min-microvolt = <1950000>;
 					regulator-max-microvolt = <1950000>;
 					regulator-always-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				ldo15_reg: ldo15 {
@@ -345,7 +358,9 @@
 					regulator-name = "VHSIC_1.0V";
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1000000>;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				ldo16_reg: ldo16 {
@@ -353,7 +368,9 @@
 					regulator-name = "VHSIC_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				ldo17_reg: ldo17 {
@@ -361,7 +378,6 @@
 					regulator-name = "CAM_SENSOR_CORE_1.2V";
 					regulator-min-microvolt = <1200000>;
 					regulator-max-microvolt = <1200000>;
-					regulator-mem-idle;
 				};
 
 				ldo18_reg: ldo18 {
@@ -369,7 +385,6 @@
 					regulator-name = "CAM_ISP_SEN_IO_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-idle;
 				};
 
 				ldo19_reg: ldo19 {
@@ -377,7 +392,6 @@
 					regulator-name = "VT_CAM_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-idle;
 				};
 
 				ldo20_reg: ldo20 {
@@ -385,7 +399,6 @@
 					regulator-name = "VDDQ_PRE_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-idle;
 				};
 
 				ldo21_reg: ldo21 {
@@ -393,7 +406,7 @@
 					regulator-name = "VTF_2.8V";
 					regulator-min-microvolt = <2800000>;
 					regulator-max-microvolt = <2800000>;
-					regulator-mem-idle;
+					maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
 				};
 
 				ldo22_reg: ldo22 {
@@ -401,6 +414,7 @@
 					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 {
@@ -408,7 +422,6 @@
 					regulator-name = "TSP_AVDD_3.3V";
 					regulator-min-microvolt = <3300000>;
 					regulator-max-microvolt = <3300000>;
-					regulator-mem-idle;
 				};
 
 				ldo24_reg: ldo24 {
@@ -416,7 +429,6 @@
 					regulator-name = "TSP_VDD_1.8V";
 					regulator-min-microvolt = <1800000>;
 					regulator-max-microvolt = <1800000>;
-					regulator-mem-idle;
 				};
 
 				ldo25_reg: ldo25 {
@@ -424,7 +436,6 @@
 					regulator-name = "LCD_VCC_3.3V";
 					regulator-min-microvolt = <2800000>;
 					regulator-max-microvolt = <2800000>;
-					regulator-mem-idle;
 				};
 
 				ldo26_reg: ldo26 {
@@ -432,7 +443,6 @@
 					regulator-name = "MOTOR_VCC_3.0V";
 					regulator-min-microvolt = <3000000>;
 					regulator-max-microvolt = <3000000>;
-					regulator-mem-idle;
 				};
 
 				buck1_reg: buck1 {
@@ -442,7 +452,9 @@
 					regulator-max-microvolt = <1100000>;
 					regulator-always-on;
 					regulator-boot-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				buck2_reg: buck2 {
@@ -452,7 +464,9 @@
 					regulator-max-microvolt = <1500000>;
 					regulator-always-on;
 					regulator-boot-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-on-in-suspend;
+					};
 				};
 
 				buck3_reg: buck3 {
@@ -462,7 +476,9 @@
 					regulator-max-microvolt = <1150000>;
 					regulator-always-on;
 					regulator-boot-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				buck4_reg: buck4 {
@@ -471,7 +487,9 @@
 					regulator-min-microvolt = <850000>;
 					regulator-max-microvolt = <1150000>;
 					regulator-boot-on;
-					regulator-mem-off;
+					regulator-state-mem {
+						regulator-off-in-suspend;
+					};
 				};
 
 				buck5_reg: buck5 {
@@ -503,6 +521,7 @@
 					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 {
@@ -510,7 +529,7 @@
 					regulator-name = "CAM_ISP_CORE_1.2V";
 					regulator-min-microvolt = <1000000>;
 					regulator-max-microvolt = <1200000>;
-					regulator-mem-off;
+					maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>;
 				};
 			};
 		};
@@ -549,6 +568,32 @@
 				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>;
 		};
 	};
 
@@ -557,7 +602,7 @@
 		broken-cd;
 		non-removable;
 		card-detect-delay = <200>;
-		vmmc-supply = <&vemmc_reg>;
+		vmmc-supply = <&ldo22_reg>;
 		clock-frequency = <400000000>;
 		samsung,dw-mshc-ciu-div = <0>;
 		samsung,dw-mshc-sdr-timing = <2 3>;
@@ -721,8 +766,8 @@
 		status = "okay";
 		assigned-clocks = <&clock CLK_MOUT_CAM0>,
 				  <&clock CLK_MOUT_CAM1>;
-		assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>,
-					 <&clock CLK_MOUT_MPLL_USER_T>;
+		assigned-clock-parents = <&clock CLK_XUSBXTI>,
+					 <&clock CLK_XUSBXTI>;
 
 		fimc_0: fimc@11800000 {
 			status = "okay";
@@ -838,6 +883,24 @@
 		};
 	};
 
+	i2s0: i2s@03830000 {
+		pinctrl-0 = <&i2s0_bus>;
+		pinctrl-names = "default";
+		status = "okay";
+	};
+
+	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";
+	};
+
 	exynos-usbphy@125B0000 {
 		status = "okay";
 	};
@@ -845,6 +908,7 @@
 	hsotg@12480000 {
 		vusb_d-supply = <&ldo15_reg>;
 		vusb_a-supply = <&ldo12_reg>;
+		dr_mode = "peripheral";
 		status = "okay";
 	};
 
@@ -865,6 +929,51 @@
 	};
 };
 
+&pmu_system_controller {
+	assigned-clocks = <&pmu_system_controller 0>;
+	assigned-clock-parents =  <&clock CLK_XUSBXTI>;
+};
+
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &pinctrl_0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sleep0>;
diff --git a/arch/arm/boot/dts/exynos4415.dtsi b/arch/arm/boot/dts/exynos4415.dtsi
index c1c9b37..5caea99 100644
--- a/arch/arm/boot/dts/exynos4415.dtsi
+++ b/arch/arm/boot/dts/exynos4415.dtsi
@@ -131,36 +131,43 @@
 		pd_cam: cam-power-domain@10024000 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10024000 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_tv: tv-power-domain@10024020 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10024020 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_mfc: mfc-power-domain@10024040 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10024040 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_g3d: g3d-power-domain@10024060 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10024060 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_lcd0: lcd0-power-domain@10024080 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x10024080 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_isp0: isp0-power-domain@100240A0 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x100240A0 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		pd_isp1: isp1-power-domain@100240E0 {
 			compatible = "samsung,exynos4210-pd";
 			reg = <0x100240E0 0x20>;
+			#power-domain-cells = <0>;
 		};
 
 		cmu: clock-controller@10030000 {
@@ -234,6 +241,33 @@
 			interrupts = <0 240 0>;
 		};
 
+		fimd: fimd@11C00000 {
+			compatible = "samsung,exynos4415-fimd";
+			reg = <0x11C00000 0x30000>;
+			interrupt-names = "fifo", "vsync", "lcd_sys";
+			interrupts = <0 84 0>, <0 85 0>, <0 86 0>;
+			clocks = <&cmu CLK_SCLK_FIMD0>, <&cmu CLK_FIMD0>;
+			clock-names = "sclk_fimd", "fimd";
+			samsung,power-domain = <&pd_lcd0>;
+			samsung,sysreg = <&sysreg_system_controller>;
+			status = "disabled";
+		};
+
+		dsi_0: dsi@11C80000 {
+			compatible = "samsung,exynos4415-mipi-dsi";
+			reg = <0x11C80000 0x10000>;
+			interrupts = <0 83 0>;
+			samsung,phy-type = <0>;
+			samsung,power-domain = <&pd_lcd0>;
+			phys = <&mipi_phy 1>;
+			phy-names = "dsim";
+			clocks = <&cmu CLK_DSIM0>, <&cmu CLK_SCLK_MIPI0>;
+			clock-names = "bus_clk", "pll_clk";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		hsotg: hsotg@12480000 {
 			compatible = "samsung,s3c6400-hsotg";
 			reg = <0x12480000 0x20000>;
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 8bc97c4..f5e0ae7 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -52,6 +52,7 @@
 	pd_isp: isp-power-domain@10023CA0 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10023CA0 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	l2c: l2-cache-controller@10502000 {
@@ -209,7 +210,7 @@
 			compatible = "samsung,exynos4212-fimc-lite";
 			reg = <0x12390000 0x1000>;
 			interrupts = <0 105 0>;
-			samsung,power-domain = <&pd_isp>;
+			power-domains = <&pd_isp>;
 			clocks = <&clock CLK_FIMC_LITE0>;
 			clock-names = "flite";
 			status = "disabled";
@@ -219,7 +220,7 @@
 			compatible = "samsung,exynos4212-fimc-lite";
 			reg = <0x123A0000 0x1000>;
 			interrupts = <0 106 0>;
-			samsung,power-domain = <&pd_isp>;
+			power-domains = <&pd_isp>;
 			clocks = <&clock CLK_FIMC_LITE1>;
 			clock-names = "flite";
 			status = "disabled";
@@ -229,7 +230,7 @@
 			compatible = "samsung,exynos4212-fimc-is", "simple-bus";
 			reg = <0x12000000 0x260000>;
 			interrupts = <0 90 0>, <0 95 0>;
-			samsung,power-domain = <&pd_isp>;
+			power-domains = <&pd_isp>;
 			clocks = <&clock CLK_FIMC_LITE0>,
 				 <&clock CLK_FIMC_LITE1>, <&clock CLK_PPMUISPX>,
 				 <&clock CLK_PPMUISPMX>,
@@ -239,7 +240,7 @@
 				 <&clock CLK_DIV_ISP0>,<&clock CLK_DIV_ISP1>,
 				 <&clock CLK_DIV_MCUISP0>,
 				 <&clock CLK_DIV_MCUISP1>,
-				 <&clock CLK_SCLK_UART_ISP>,
+				 <&clock CLK_UART_ISP_SCLK>,
 				 <&clock CLK_ACLK200>, <&clock CLK_DIV_ACLK200>,
 				 <&clock CLK_ACLK400_MCUISP>,
 				 <&clock CLK_DIV_ACLK400_MCUISP>;
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index effaf2a..b9aeec4 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -33,6 +33,8 @@
 
 	gpio-keys {
 		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&power_key_irq &lid_irq>;
 
 		power {
 			label = "Power";
@@ -540,6 +542,13 @@
 };
 
 &pinctrl_0 {
+	power_key_irq: power-key-irq {
+		samsung,pins = "gpx1-3";
+		samsung,pin-function = <0xf>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	ec_irq: ec-irq {
 		samsung,pins = "gpx1-6";
 		samsung,pin-function = <0>;
@@ -575,6 +584,13 @@
 		samsung,pin-drv = <0>;
 	};
 
+	lid_irq: lid-irq {
+		samsung,pins = "gpx3-5";
+		samsung,pin-function = <0xf>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index d75c89d..9bb1b0b 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -93,11 +93,13 @@
 	pd_gsc: gsc-power-domain@10044000 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044000 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	pd_mfc: mfc-power-domain@10044040 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044040 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	clock: clock-controller@10010000 {
@@ -222,7 +224,7 @@
 		compatible = "samsung,mfc-v6";
 		reg = <0x11000000 0x10000>;
 		interrupts = <0 96 0>;
-		samsung,power-domain = <&pd_mfc>;
+		power-domains = <&pd_mfc>;
 		clocks = <&clock CLK_MFC>;
 		clock-names = "mfc";
 	};
@@ -682,7 +684,7 @@
 		compatible = "samsung,exynos5-gsc";
 		reg = <0x13e00000 0x1000>;
 		interrupts = <0 85 0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 		clocks = <&clock CLK_GSCL0>;
 		clock-names = "gscl";
 	};
@@ -691,7 +693,7 @@
 		compatible = "samsung,exynos5-gsc";
 		reg = <0x13e10000 0x1000>;
 		interrupts = <0 86 0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 		clocks = <&clock CLK_GSCL1>;
 		clock-names = "gscl";
 	};
@@ -700,7 +702,7 @@
 		compatible = "samsung,exynos5-gsc";
 		reg = <0x13e20000 0x1000>;
 		interrupts = <0 87 0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 		clocks = <&clock CLK_GSCL2>;
 		clock-names = "gscl";
 	};
@@ -709,7 +711,7 @@
 		compatible = "samsung,exynos5-gsc";
 		reg = <0x13e30000 0x1000>;
 		interrupts = <0 88 0>;
-		samsung,power-domain = <&pd_gsc>;
+		power-domains = <&pd_gsc>;
 		clocks = <&clock CLK_GSCL3>;
 		clock-names = "gscl";
 	};
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 9a050e1..c47bb70 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -13,6 +13,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/clock/maxim,max77802.h>
+#include <dt-bindings/regulator/maxim,max77802.h>
 #include "exynos5420.dtsi"
 
 / {
@@ -53,7 +54,7 @@
 		compatible = "gpio-keys";
 
 		pinctrl-names = "default";
-		pinctrl-0 = <&power_key_irq>;
+		pinctrl-0 = <&power_key_irq &lid_irq>;
 
 		power {
 			label = "Power";
@@ -61,6 +62,15 @@
 			linux,code = <KEY_POWER>;
 			gpio-key,wakeup;
 		};
+
+		lid-switch {
+			label = "Lid";
+			gpios = <&gpx3 4 GPIO_ACTIVE_LOW>;
+			linux,input-type = <5>; /* EV_SW */
+			linux,code = <0>; /* SW_LID */
+			debounce-interval = <1>;
+			gpio-key,wakeup;
+		};
 	};
 
 	memory {
@@ -192,6 +202,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck2_reg: BUCK2 {
@@ -201,6 +214,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck3_reg: BUCK3 {
@@ -210,6 +226,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck4_reg: BUCK4 {
@@ -219,6 +238,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck5_reg: BUCK5 {
@@ -227,6 +249,9 @@
 				regulator-max-microvolt = <1200000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck6_reg: BUCK6 {
@@ -236,6 +261,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck7_reg: BUCK7 {
@@ -244,6 +272,9 @@
 				regulator-max-microvolt = <1350000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			buck8_reg: BUCK8 {
@@ -252,6 +283,9 @@
 				regulator-max-microvolt = <2850000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck9_reg: BUCK9 {
@@ -260,6 +294,9 @@
 				regulator-max-microvolt = <2000000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			buck10_reg: BUCK10 {
@@ -268,6 +305,9 @@
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			ldo1_reg: LDO1 {
@@ -275,6 +315,10 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo2_reg: LDO2 {
@@ -288,6 +332,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			vqmmc_sdcard: ldo4_reg: LDO4 {
@@ -295,6 +343,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <2800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo5_reg: LDO5 {
@@ -302,6 +353,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo6_reg: LDO6 {
@@ -309,6 +363,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo7_reg: LDO7 {
@@ -322,6 +379,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo9_reg: LDO9 {
@@ -329,6 +389,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo10_reg: LDO10 {
@@ -336,6 +400,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo11_reg: LDO11 {
@@ -343,6 +410,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo12_reg: LDO12 {
@@ -350,6 +421,9 @@
 				regulator-min-microvolt = <3000000>;
 				regulator-max-microvolt = <3000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo13_reg: LDO13 {
@@ -357,6 +431,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo14_reg: LDO14 {
@@ -364,6 +442,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo15_reg: LDO15 {
@@ -371,6 +452,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo17_reg: LDO17 {
@@ -378,6 +462,9 @@
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1400000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo18_reg: LDO18 {
@@ -451,6 +538,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo32_reg: LDO32 {
@@ -658,6 +748,13 @@
 		samsung,pin-drv = <0>;
 	};
 
+	lid_irq: lid-irq {
+		samsung,pins = "gpx3-4";
+		samsung,pin-function = <0xf>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
@@ -815,6 +912,7 @@
 					};
 					tps65090_fet5: fet5 {
 						regulator-name = "camout";
+						regulator-always-on;
 					};
 					tps65090_fet6: fet6 {
 						regulator-name = "lcd_vdd";
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 6d38f8b..9dc2e97 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -178,7 +178,7 @@
 		interrupts = <0 96 0>;
 		clocks = <&clock CLK_MFC>;
 		clock-names = "mfc";
-		samsung,power-domain = <&mfc_pd>;
+		power-domains = <&mfc_pd>;
 	};
 
 	mmc_0: mmc@12200000 {
@@ -250,11 +250,13 @@
 	gsc_pd: power-domain@10044000 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044000 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	isp_pd: power-domain@10044020 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044020 0x20>;
+		#power-domain-cells = <0>;
 	};
 
 	mfc_pd: power-domain@10044060 {
@@ -263,11 +265,27 @@
 		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
 			<&clock CLK_MOUT_USER_ACLK333>;
 		clock-names = "oscclk", "pclk0", "clk0";
+		#power-domain-cells = <0>;
 	};
 
 	msc_pd: power-domain@10044120 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044120 0x20>;
+		#power-domain-cells = <0>;
+	};
+
+	disp_pd: power-domain@100440C0 {
+		compatible = "samsung,exynos4210-pd";
+		reg = <0x100440C0 0x20>;
+		#power-domain-cells = <0>;
+		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK200>,
+			 <&clock CLK_MOUT_USER_ACLK200_DISP1>,
+			 <&clock CLK_MOUT_SW_ACLK300>,
+			 <&clock CLK_MOUT_USER_ACLK300_DISP1>,
+			 <&clock CLK_MOUT_SW_ACLK400>,
+			 <&clock CLK_MOUT_USER_ACLK400_DISP1>;
+		clock-names = "oscclk", "pclk0", "clk0",
+			      "pclk1", "clk1", "pclk2", "clk2";
 	};
 
 	pinctrl_0: pinctrl@13400000 {
@@ -537,6 +555,7 @@
 	fimd: fimd@14400000 {
 		clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
 		clock-names = "sclk_fimd", "fimd";
+		power-domains = <&disp_pd>;
 	};
 
 	adc: adc@12D10000 {
@@ -710,6 +729,7 @@
 		phy = <&hdmiphy>;
 		samsung,syscon-phandle = <&pmu_system_controller>;
 		status = "disabled";
+		power-domains = <&disp_pd>;
 	};
 
 	hdmiphy: hdmiphy@145D0000 {
@@ -722,6 +742,7 @@
 		interrupts = <0 94 0>;
 		clocks = <&clock CLK_MIXER>, <&clock CLK_SCLK_HDMI>;
 		clock-names = "mixer", "sclk_hdmi";
+		power-domains = <&disp_pd>;
 	};
 
 	gsc_0: video-scaler@13e00000 {
@@ -730,7 +751,7 @@
 		interrupts = <0 85 0>;
 		clocks = <&clock CLK_GSCL0>;
 		clock-names = "gscl";
-		samsung,power-domain = <&gsc_pd>;
+		power-domains = <&gsc_pd>;
 	};
 
 	gsc_1: video-scaler@13e10000 {
@@ -739,7 +760,7 @@
 		interrupts = <0 86 0>;
 		clocks = <&clock CLK_GSCL1>;
 		clock-names = "gscl";
-		samsung,power-domain = <&gsc_pd>;
+		power-domains = <&gsc_pd>;
 	};
 
 	pmu_system_controller: system-controller@10040000 {
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
new file mode 100644
index 0000000..a519c86
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
@@ -0,0 +1,371 @@
+/*
+ * Hardkernel Odroid XU3 board device tree source
+ *
+ * Copyright (c) 2014 Collabora Ltd.
+ * Copyright (c) 2013 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.
+*/
+
+/dts-v1/;
+#include "exynos5800.dtsi"
+
+/ {
+	model = "Hardkernel Odroid XU3";
+	compatible = "hardkernel,odroid-xu3", "samsung,exynos5800", "samsung,exynos5";
+
+	memory {
+		reg = <0x40000000 0x7EA00000>;
+	};
+
+	chosen {
+		linux,stdout-path = &serial_2;
+	};
+
+	fimd@14400000 {
+		status = "okay";
+	};
+
+	firmware@02073000 {
+		compatible = "samsung,secure-firmware";
+		reg = <0x02073000 0x1000>;
+	};
+
+	fixed-rate-clocks {
+		oscclk {
+			compatible = "samsung,exynos5420-oscclk";
+			clock-frequency = <24000000>;
+		};
+	};
+
+	hsi2c_4: i2c@12CA0000 {
+		status = "okay";
+
+		s2mps11_pmic@66 {
+			compatible = "samsung,s2mps11-pmic";
+			reg = <0x66>;
+			s2mps11,buck2-ramp-delay = <12>;
+			s2mps11,buck34-ramp-delay = <12>;
+			s2mps11,buck16-ramp-delay = <12>;
+			s2mps11,buck6-ramp-enable = <1>;
+			s2mps11,buck2-ramp-enable = <1>;
+			s2mps11,buck3-ramp-enable = <1>;
+			s2mps11,buck4-ramp-enable = <1>;
+
+			s2mps11_osc: clocks {
+				#clock-cells = <1>;
+				clock-output-names = "s2mps11_ap",
+						"s2mps11_cp", "s2mps11_bt";
+			};
+
+			regulators {
+				ldo1_reg: LDO1 {
+					regulator-name = "vdd_ldo1";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				ldo3_reg: LDO3 {
+					regulator-name = "vdd_ldo3";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo5_reg: LDO5 {
+					regulator-name = "vdd_ldo5";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo6_reg: LDO6 {
+					regulator-name = "vdd_ldo6";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				ldo7_reg: LDO7 {
+					regulator-name = "vdd_ldo7";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo8_reg: LDO8 {
+					regulator-name = "vdd_ldo8";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo9_reg: LDO9 {
+					regulator-name = "vdd_ldo9";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+					regulator-always-on;
+				};
+
+				ldo10_reg: LDO10 {
+					regulator-name = "vdd_ldo10";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo11_reg: LDO11 {
+					regulator-name = "vdd_ldo11";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+					regulator-always-on;
+				};
+
+				ldo12_reg: LDO12 {
+					regulator-name = "vdd_ldo12";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo13_reg: LDO13 {
+					regulator-name = "vdd_ldo13";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				ldo15_reg: LDO15 {
+					regulator-name = "vdd_ldo15";
+					regulator-min-microvolt = <3100000>;
+					regulator-max-microvolt = <3100000>;
+					regulator-always-on;
+				};
+
+				ldo16_reg: LDO16 {
+					regulator-name = "vdd_ldo16";
+					regulator-min-microvolt = <2200000>;
+					regulator-max-microvolt = <2200000>;
+					regulator-always-on;
+				};
+
+				ldo17_reg: LDO17 {
+					regulator-name = "tsp_avdd";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				ldo19_reg: LDO19 {
+					regulator-name = "vdd_sd";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				ldo24_reg: LDO24 {
+					regulator-name = "tsp_io";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+				};
+
+				ldo26_reg: LDO26 {
+					regulator-name = "vdd_ldo26";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+					regulator-always-on;
+				};
+
+				buck1_reg: BUCK1 {
+					regulator-name = "vdd_mif";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1300000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck2_reg: BUCK2 {
+					regulator-name = "vdd_arm";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck3_reg: BUCK3 {
+					regulator-name = "vdd_int";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1400000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck4_reg: BUCK4 {
+					regulator-name = "vdd_g3d";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1400000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck5_reg: BUCK5 {
+					regulator-name = "vdd_mem";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1400000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck6_reg: BUCK6 {
+					regulator-name = "vdd_kfc";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck7_reg: BUCK7 {
+					regulator-name = "vdd_1.0v_ldo";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck8_reg: BUCK8 {
+					regulator-name = "vdd_1.8v_ldo";
+					regulator-min-microvolt = <800000>;
+					regulator-max-microvolt = <1500000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck9_reg: BUCK9 {
+					regulator-name = "vdd_2.8v_ldo";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3750000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				buck10_reg: BUCK10 {
+					regulator-name = "vdd_vmem";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+			};
+		};
+	};
+
+	i2c_2: i2c@12C80000 {
+		samsung,i2c-sda-delay = <100>;
+		samsung,i2c-max-bus-freq = <66000>;
+		status = "okay";
+
+		hdmiddc@50 {
+			compatible = "samsung,exynos4210-hdmiddc";
+			reg = <0x50>;
+		};
+	};
+
+	rtc@101E0000 {
+		status = "okay";
+	};
+};
+
+&hdmi {
+	status = "okay";
+	hpd-gpio = <&gpx3 7 0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_hpd_irq>;
+
+	vdd_osc-supply = <&ldo7_reg>;
+	vdd_pll-supply = <&ldo6_reg>;
+	vdd-supply = <&ldo6_reg>;
+};
+
+&mfc {
+	samsung,mfc-r = <0x43000000 0x800000>;
+	samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+	status = "okay";
+	broken-cd;
+	card-detect-delay = <200>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <0 4>;
+	samsung,dw-mshc-ddr-timing = <0 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+	bus-width = <8>;
+	cap-mmc-highspeed;
+};
+
+&mmc_2 {
+	status = "okay";
+	card-detect-delay = <200>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <0 4>;
+	samsung,dw-mshc-ddr-timing = <0 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+	bus-width = <4>;
+	cap-sd-highspeed;
+};
+
+&pinctrl_0 {
+	hdmi_hpd_irq: hdmi-hpd-irq {
+		samsung,pins = "gpx3-7";
+		samsung,pin-function = <0>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&usbdrd_dwc3_0 {
+	dr_mode = "host";
+};
+
+&usbdrd_dwc3_1 {
+	dr_mode = "otg";
+};
+
+&i2c_0 {
+	status = "okay";
+
+	/* A15 cluster: VDD_ARM */
+	ina231@40 {
+		compatible = "ti,ina231";
+		reg = <0x40>;
+		shunt-resistor = <10000>;
+	};
+
+	/* memory: VDD_MEM */
+	ina231@41 {
+		compatible = "ti,ina231";
+		reg = <0x41>;
+		shunt-resistor = <10000>;
+	};
+
+	/* GPU: VDD_G3D */
+	ina231@44 {
+		compatible = "ti,ina231";
+		reg = <0x44>;
+		shunt-resistor = <10000>;
+	};
+
+	/* A7 cluster: VDD_KFC */
+	ina231@45 {
+		compatible = "ti,ina231";
+		reg = <0x45>;
+		shunt-resistor = <10000>;
+	};
+};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index e8fdda8..06737c6 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -13,6 +13,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/clock/maxim,max77802.h>
+#include <dt-bindings/regulator/maxim,max77802.h>
 #include "exynos5800.dtsi"
 
 / {
@@ -52,7 +53,7 @@
 		compatible = "gpio-keys";
 
 		pinctrl-names = "default";
-		pinctrl-0 = <&power_key_irq>;
+		pinctrl-0 = <&power_key_irq &lid_irq>;
 
 		power {
 			label = "Power";
@@ -60,6 +61,16 @@
 			linux,code = <KEY_POWER>;
 			gpio-key,wakeup;
 		};
+
+		lid-switch {
+			label = "Lid";
+			gpios = <&gpx3 4 GPIO_ACTIVE_LOW>;
+			linux,input-type = <5>; /* EV_SW */
+			linux,code = <0>; /* SW_LID */
+			debounce-interval = <1>;
+			gpio-key,wakeup;
+		};
+
 	};
 
 	memory {
@@ -191,6 +202,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck2_reg: BUCK2 {
@@ -200,6 +214,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck3_reg: BUCK3 {
@@ -209,6 +226,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck4_reg: BUCK4 {
@@ -218,6 +238,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck5_reg: BUCK5 {
@@ -226,6 +249,9 @@
 				regulator-max-microvolt = <1200000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck6_reg: BUCK6 {
@@ -235,6 +261,9 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck7_reg: BUCK7 {
@@ -243,6 +272,9 @@
 				regulator-max-microvolt = <1350000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			buck8_reg: BUCK8 {
@@ -251,6 +283,9 @@
 				regulator-max-microvolt = <2850000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			buck9_reg: BUCK9 {
@@ -259,6 +294,9 @@
 				regulator-max-microvolt = <2000000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			buck10_reg: BUCK10 {
@@ -267,6 +305,9 @@
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
 				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			ldo1_reg: LDO1 {
@@ -274,6 +315,10 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo2_reg: LDO2 {
@@ -287,6 +332,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			vqmmc_sdcard: ldo4_reg: LDO4 {
@@ -294,6 +343,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <2800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo5_reg: LDO5 {
@@ -301,6 +353,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo6_reg: LDO6 {
@@ -308,6 +363,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo7_reg: LDO7 {
@@ -321,6 +379,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo9_reg: LDO9 {
@@ -328,6 +389,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo10_reg: LDO10 {
@@ -335,6 +400,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo11_reg: LDO11 {
@@ -342,6 +410,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo12_reg: LDO12 {
@@ -349,6 +421,9 @@
 				regulator-min-microvolt = <3000000>;
 				regulator-max-microvolt = <3000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo13_reg: LDO13 {
@@ -356,6 +431,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-mode = <MAX77802_OPMODE_LP>;
+				};
 			};
 
 			ldo14_reg: LDO14 {
@@ -363,6 +442,9 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo15_reg: LDO15 {
@@ -370,6 +452,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo17_reg: LDO17 {
@@ -377,6 +462,9 @@
 				regulator-min-microvolt = <900000>;
 				regulator-max-microvolt = <1400000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo18_reg: LDO18 {
@@ -450,6 +538,9 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-always-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			ldo32_reg: LDO32 {
@@ -646,6 +737,13 @@
 		samsung,pin-drv = <0>;
 	};
 
+	lid_irq: lid-irq {
+		samsung,pins = "gpx3-4";
+		samsung,pin-function = <0xf>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	hdmi_hpd_irq: hdmi-hpd-irq {
 		samsung,pins = "gpx3-7";
 		samsung,pin-function = <0>;
@@ -803,6 +901,7 @@
 					};
 					tps65090_fet5: fet5 {
 						regulator-name = "camout";
+						regulator-always-on;
 					};
 					tps65090_fet6: fet6 {
 						regulator-name = "lcd_vdd";
diff --git a/arch/arm/boot/dts/hip01-ca9x2.dts b/arch/arm/boot/dts/hip01-ca9x2.dts
new file mode 100644
index 0000000..eca5e42
--- /dev/null
+++ b/arch/arm/boot/dts/hip01-ca9x2.dts
@@ -0,0 +1,51 @@
+/*
+ * Hisilicon Ltd. HiP01 SoC
+ *
+ * Copyright (C) 2014 Hisilicon Ltd.
+ * Copyright (C) 2014 Huawei Ltd.
+ *
+ * Author: Wang Long <long.wanglong@huawei.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.
+ */
+
+/dts-v1/;
+
+/* First 8KB reserved for secondary core boot */
+/memreserve/ 0x80000000 0x00002000;
+
+#include "hip01.dtsi"
+
+/ {
+	model = "Hisilicon HIP01 Development Board";
+	compatible = "hisilicon,hip01-ca9x2", "hisilicon,hip01";
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "hisilicon,hip01-smp";
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x80000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/hip01.dtsi b/arch/arm/boot/dts/hip01.dtsi
new file mode 100644
index 0000000..33130f8
--- /dev/null
+++ b/arch/arm/boot/dts/hip01.dtsi
@@ -0,0 +1,110 @@
+/*
+ * Hisilicon Ltd. HiP01 SoC
+ *
+ * Copyright (c) 2014 Hisilicon Ltd.
+ * Copyright (c) 2014 Huawei Ltd.
+ *
+ * Author: Wang Long <long.wanglong@huawei.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 "skeleton.dtsi"
+
+/ {
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	gic: interrupt-controller@1e001000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x1a001000 0x1000>, <0x1a000100 0x1000>;
+	};
+
+	hisi_refclk144mhz: refclk144mkhz {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <144000000>;
+		clock-output-names = "hisi:refclk144khz";
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges = <0 0x10000000 0x20000000>;
+
+		amba {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "arm,amba-bus";
+			ranges;
+
+			uart0: uart@10001000 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x10001000 0x1000>;
+				clocks = <&hisi_refclk144mhz>;
+				clock-names = "apb_pclk";
+				reg-shift = <2>;
+				interrupts = <0 32 4>;
+				status = "disabled";
+			};
+
+			uart1: uart@10002000 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x10002000 0x1000>;
+				clocks = <&hisi_refclk144mhz>;
+				clock-names = "apb_pclk";
+				reg-shift = <2>;
+				interrupts = <0 33 4>;
+				status = "disabled";
+			};
+
+			uart2: uart@10003000 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x10003000 0x1000>;
+				clocks = <&hisi_refclk144mhz>;
+				clock-names = "apb_pclk";
+				reg-shift = <2>;
+				interrupts = <0 34 4>;
+				status = "disabled";
+			};
+
+			uart3: uart@10006000 {
+				compatible = "snps,dw-apb-uart";
+				reg = <0x10006000 0x1000>;
+				clocks = <&hisi_refclk144mhz>;
+				clock-names = "apb_pclk";
+				reg-shift = <2>;
+				interrupts = <0 4 4>;
+				status = "disabled";
+			};
+		};
+
+		system-controller@10000000 {
+			compatible = "hisilicon,hip01-sysctrl", "hisilicon,sysctrl";
+			reg = <0x10000000 0x1000>;
+			reboot-offset = <0x4>;
+		};
+
+		global_timer@0a000200 {
+			compatible = "arm,cortex-a9-global-timer";
+			reg = <0x0a000200 0x100>;
+			interrupts = <1 11 0xf04>;
+			clocks = <&hisi_refclk144mhz>;
+		};
+
+		local_timer@0a000600 {
+			compatible = "arm,cortex-a9-twd-timer";
+			reg = <0x0a000600 0x100>;
+			interrupts = <1 13 0xf04>;
+			clocks = <&hisi_refclk144mhz>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx27-apf27dev.dts b/arch/arm/boot/dts/imx27-apf27dev.dts
index da306c5..bba3f41 100644
--- a/arch/arm/boot/dts/imx27-apf27dev.dts
+++ b/arch/arm/boot/dts/imx27-apf27dev.dts
@@ -59,6 +59,21 @@
 			linux,default-trigger = "heartbeat";
 		};
 	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_max5821: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "max5821-reg";
+			regulator-min-microvolt = <2500000>;
+			regulator-max-microvolt = <2500000>;
+			regulator-always-on;
+		};
+	};
 };
 
 &cspi1 {
@@ -107,6 +122,12 @@
 		compatible = "dallas,ds1374";
 		reg = <0x68>;
 	};
+
+	max5821@38 {
+		compatible = "maxim,max5821";
+		reg = <0x38>;
+		vref-supply = <&reg_max5821>;
+	};
 };
 
 &i2c2 {
diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi
index 107d713..4b063b6 100644
--- a/arch/arm/boot/dts/imx27.dtsi
+++ b/arch/arm/boot/dts/imx27.dtsi
@@ -464,7 +464,7 @@
 			};
 
 			coda: coda@10023000 {
-				compatible = "fsl,imx27-vpu";
+				compatible = "fsl,imx27-vpu", "cnm,codadx6";
 				reg = <0x10023000 0x0200>;
 				interrupts = <53>;
 				clocks = <&clks IMX27_CLK_VPU_BAUD_GATE>,
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index 0e13b4b..279249b 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -182,7 +182,6 @@
 			};
 
 			lradc@80050000 {
-				fsl,lradc-touchscreen-wires = <4>;
 				status = "okay";
 				fsl,lradc-touchscreen-wires = <4>;
 				fsl,ave-ctrl = <4>;
diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts
index c5a9a24..93d3ea1 100644
--- a/arch/arm/boot/dts/imx51-apf51dev.dts
+++ b/arch/arm/boot/dts/imx51-apf51dev.dts
@@ -16,6 +16,14 @@
 	model = "Armadeus Systems APF51Dev docking/development board";
 	compatible = "armadeus,imx51-apf51dev", "armadeus,imx51-apf51", "fsl,imx51";
 
+	backlight@bl1{
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_backlight>;
+		compatible = "gpio-backlight";
+		gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+		default-on;
+	};
+
 	display@di1 {
 		compatible = "fsl,imx-parallel-display";
 		interface-pix-fmt = "bgr666";
@@ -114,6 +122,12 @@
 	pinctrl-0 = <&pinctrl_hog>;
 
 	imx51-apf51dev {
+		pinctrl_backlight: bl1grp {
+			fsl,pins = <
+				MX51_PAD_DI1_D1_CS__GPIO3_4 0x1F5
+			>;
+		};
+
 		pinctrl_hog: hoggrp {
 			fsl,pins = <
 				MX51_PAD_EIM_EB2__GPIO2_22   0x0C5
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index a30bddf..ff4fa7e 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -756,7 +756,7 @@
 			};
 
 			vpu: vpu@63ff4000 {
-				compatible = "fsl,imx53-vpu";
+				compatible = "fsl,imx53-vpu", "cnm,coda7541";
 				reg = <0x63ff4000 0x1000>;
 				interrupts = <9>;
 				clocks = <&clks IMX5_CLK_VPU_REFERENCE_GATE>,
@@ -765,6 +765,15 @@
 				resets = <&src 1>;
 				iram = <&ocram>;
 			};
+
+			sahara: crypto@63ff8000 {
+				compatible = "fsl,imx53-sahara";
+				reg = <0x63ff8000 0x4000>;
+				interrupts = <19 20>;
+				clocks = <&clks IMX5_CLK_SAHARA_IPG_GATE>,
+				         <&clks IMX5_CLK_SAHARA_IPG_GATE>;
+				clock-names = "ipg", "ahb";
+			};
 		};
 
 		ocram: sram@f8000000 {
diff --git a/arch/arm/boot/dts/imx6dl-udoo.dts b/arch/arm/boot/dts/imx6dl-udoo.dts
new file mode 100644
index 0000000..e3713f0
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-udoo.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.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.
+ *
+ */
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-udoo.dtsi"
+
+/ {
+	model = "Udoo i.MX6 Dual-lite Board";
+	compatible = "udoo,imx6dl-udoo", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 1ac2fe7..f94bf72 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -28,7 +28,7 @@
 			next-level-cache = <&L2>;
 			operating-points = <
 				/* kHz    uV */
-				996000  1275000
+				996000  1250000
 				792000  1175000
 				396000  1075000
 			>;
diff --git a/arch/arm/boot/dts/imx6q-udoo.dts b/arch/arm/boot/dts/imx6q-udoo.dts
index e3bff2a..c3e64ff 100644
--- a/arch/arm/boot/dts/imx6q-udoo.dts
+++ b/arch/arm/boot/dts/imx6q-udoo.dts
@@ -8,137 +8,15 @@
  * published by the Free Software Foundation.
  *
  */
-
 /dts-v1/;
 #include "imx6q.dtsi"
+#include "imx6qdl-udoo.dtsi"
 
 / {
 	model = "Udoo i.MX6 Quad Board";
 	compatible = "udoo,imx6q-udoo", "fsl,imx6q";
-
-	chosen {
-		stdout-path = &uart2;
-	};
-
-	memory {
-		reg = <0x10000000 0x40000000>;
-	};
-
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		reg_usb_h1_vbus: regulator@0 {
-			compatible = "regulator-fixed";
-			reg = <0>;
-			regulator-name = "usb_h1_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			enable-active-high;
-			startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
-			gpio = <&gpio7 12 0>;
-		};
-	};
-};
-
-&fec {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_enet>;
-	phy-mode = "rgmii";
-	status = "okay";
-};
-
-&hdmi {
-	ddc-i2c-bus = <&i2c2>;
-	status = "okay";
-};
-
-&i2c2 {
-	clock-frequency = <100000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c2>;
-	status = "okay";
-};
-
-&iomuxc {
-	imx6q-udoo {
-		pinctrl_enet: enetgrp {
-			fsl,pins = <
-				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_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_ENET_MDIO__ENET_MDIO		0x1b0b0
-				MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
-				MX6QDL_PAD_GPIO_16__ENET_REF_CLK	0x4001b0a8
-			>;
-		};
-
-		pinctrl_i2c2: i2c2grp {
-			fsl,pins = <
-				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
-				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
-			>;
-		};
-
-		pinctrl_uart2: uart2grp {
-			fsl,pins = <
-				MX6QDL_PAD_EIM_D26__UART2_TX_DATA	0x1b0b1
-				MX6QDL_PAD_EIM_D27__UART2_RX_DATA	0x1b0b1
-			>;
-		};
-
-		pinctrl_usbh: usbhgrp {
-			fsl,pins = <
-				MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
-				MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
-			>;
-		};
-
-		pinctrl_usdhc3: usdhc3grp {
-			fsl,pins = <
-				MX6QDL_PAD_SD3_CMD__SD3_CMD		0x17059
-				MX6QDL_PAD_SD3_CLK__SD3_CLK		0x10059
-				MX6QDL_PAD_SD3_DAT0__SD3_DATA0		0x17059
-				MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
-				MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
-				MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
-			>;
-		};
-	};
 };
 
 &sata {
 	status = "okay";
 };
-
-&uart2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart2>;
-	status = "okay";
-};
-
-&usbh1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usbh>;
-	vbus-supply = <&reg_usb_h1_vbus>;
-	clocks = <&clks 201>;
-	status = "okay";
-};
-
-&usdhc3 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usdhc3>;
-	non-removable;
-	status = "okay";
-};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 85f72e6..93ec79b 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -31,7 +31,7 @@
 				1200000 1275000
 				996000  1250000
 				852000  1250000
-				792000  1150000
+				792000  1175000
 				396000  975000
 			>;
 			fsl,soc-operating-points = <
@@ -95,6 +95,8 @@
 					clocks = <&clks IMX6Q_CLK_ECSPI5>,
 						 <&clks IMX6Q_CLK_ECSPI5>;
 					clock-names = "ipg", "per";
+					dmas = <&sdma 11 7 1>, <&sdma 12 7 2>;
+					dma-names = "rx", "tx";
 					status = "disabled";
 				};
 			};
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 0a36129..0b28a9d 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -173,6 +173,11 @@
 	status = "okay";
 };
 
+&hdmi {
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+};
+
 &i2c1 {
 	clock-frequency = <100000>;
 	pinctrl-names = "default";
@@ -188,6 +193,20 @@
 	};
 };
 
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
 &iomuxc {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_hog>;
@@ -265,6 +284,20 @@
 			>;
 		};
 
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_5__I2C3_SCL		0x4001b8b1
+				MX6QDL_PAD_GPIO_16__I2C3_SDA		0x4001b8b1
+			>;
+		};
+
 		pinctrl_pwm1: pwm1grp {
 			fsl,pins = <
 				MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
new file mode 100644
index 0000000..1211da8
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.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.
+ *
+ */
+
+/ {
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	memory {
+		reg = <0x10000000 0x40000000>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_usb_h1_vbus: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "usb_h1_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
+			gpio = <&gpio7 12 0>;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&hdmi {
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+};
+
+&iomuxc {
+	imx6q-udoo {
+		pinctrl_enet: enetgrp {
+			fsl,pins = <
+				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_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_ENET_MDIO__ENET_MDIO		0x1b0b0
+				MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
+				MX6QDL_PAD_GPIO_16__ENET_REF_CLK	0x4001b0a8
+			>;
+		};
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_uart2: uart2grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D26__UART2_TX_DATA	0x1b0b1
+				MX6QDL_PAD_EIM_D27__UART2_RX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_usbh: usbhgrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
+				MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD3_CMD__SD3_CMD		0x17059
+				MX6QDL_PAD_SD3_CLK__SD3_CLK		0x10059
+				MX6QDL_PAD_SD3_DAT0__SD3_DATA0		0x17059
+				MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
+				MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
+				MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
+			>;
+		};
+	};
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+&usbh1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbh>;
+	vbus-supply = <&reg_usb_h1_vbus>;
+	clocks = <&clks 201>;
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	non-removable;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 2109d07..d6c69ec 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -339,9 +339,8 @@
 					     <0 3 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-names = "bit", "jpeg";
 				clocks = <&clks IMX6QDL_CLK_VPU_AXI>,
-					 <&clks IMX6QDL_CLK_MMDC_CH0_AXI>,
-					 <&clks IMX6QDL_CLK_OCRAM>;
-				clock-names = "per", "ahb", "ocram";
+					 <&clks IMX6QDL_CLK_MMDC_CH0_AXI>;
+				clock-names = "per", "ahb";
 				resets = <&src 1>;
 				iram = <&ocram>;
 			};
diff --git a/arch/arm/boot/dts/imx6sx-sabreauto.dts b/arch/arm/boot/dts/imx6sx-sabreauto.dts
new file mode 100644
index 0000000..e3c0b63
--- /dev/null
+++ b/arch/arm/boot/dts/imx6sx-sabreauto.dts
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+/dts-v1/;
+
+#include "imx6sx.dtsi"
+
+/ {
+	model = "Freescale i.MX6 SoloX Sabre Auto Board";
+	compatible = "fsl,imx6sx-sabreauto", "fsl,imx6sx";
+
+	memory {
+		reg = <0x80000000 0x80000000>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vcc_sd3: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_vcc_sd3>;
+			regulator-name = "VCC_SD3";
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3000000>;
+			gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+	};
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	cd-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>;
+	wp-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	vmmc-supply = <&vcc_sd3>;
+	status = "okay";
+};
+
+&usdhc4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	bus-width = <8>;
+	cd-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	enable-sdio-wakup;
+	status = "okay";
+};
+
+&iomuxc {
+	imx6x-sabreauto {
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				MX6SX_PAD_GPIO1_IO04__UART1_TX		0x1b0b1
+				MX6SX_PAD_GPIO1_IO05__UART1_RX		0x1b0b1
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				MX6SX_PAD_SD3_CMD__USDHC3_CMD		0x17059
+				MX6SX_PAD_SD3_CLK__USDHC3_CLK		0x10059
+				MX6SX_PAD_SD3_DATA0__USDHC3_DATA0	0x17059
+				MX6SX_PAD_SD3_DATA1__USDHC3_DATA1	0x17059
+				MX6SX_PAD_SD3_DATA2__USDHC3_DATA2	0x17059
+				MX6SX_PAD_SD3_DATA3__USDHC3_DATA3	0x17059
+				MX6SX_PAD_SD3_DATA4__USDHC3_DATA4	0x17059
+				MX6SX_PAD_SD3_DATA5__USDHC3_DATA5	0x17059
+				MX6SX_PAD_SD3_DATA6__USDHC3_DATA6	0x17059
+				MX6SX_PAD_SD3_DATA7__USDHC3_DATA7	0x17059
+				MX6SX_PAD_KEY_COL0__GPIO2_IO_10		0x17059 /* CD */
+				MX6SX_PAD_KEY_ROW0__GPIO2_IO_15		0x17059 /* WP */
+			>;
+		};
+
+		pinctrl_usdhc3_100mhz: usdhc3grp-100mhz {
+			fsl,pins = <
+				MX6SX_PAD_SD3_CMD__USDHC3_CMD		0x170b9
+				MX6SX_PAD_SD3_CLK__USDHC3_CLK		0x100b9
+				MX6SX_PAD_SD3_DATA0__USDHC3_DATA0	0x170b9
+				MX6SX_PAD_SD3_DATA1__USDHC3_DATA1	0x170b9
+				MX6SX_PAD_SD3_DATA2__USDHC3_DATA2	0x170b9
+				MX6SX_PAD_SD3_DATA3__USDHC3_DATA3	0x170b9
+				MX6SX_PAD_SD3_DATA4__USDHC3_DATA4	0x170b9
+				MX6SX_PAD_SD3_DATA5__USDHC3_DATA5	0x170b9
+				MX6SX_PAD_SD3_DATA6__USDHC3_DATA6	0x170b9
+				MX6SX_PAD_SD3_DATA7__USDHC3_DATA7	0x170b9
+			>;
+		};
+
+		pinctrl_usdhc3_200mhz: usdhc3grp-200mhz {
+			fsl,pins = <
+				MX6SX_PAD_SD3_CMD__USDHC3_CMD		0x170f9
+				MX6SX_PAD_SD3_CLK__USDHC3_CLK		0x100f9
+				MX6SX_PAD_SD3_DATA0__USDHC3_DATA0	0x170f9
+				MX6SX_PAD_SD3_DATA1__USDHC3_DATA1	0x170f9
+				MX6SX_PAD_SD3_DATA2__USDHC3_DATA2	0x170f9
+				MX6SX_PAD_SD3_DATA3__USDHC3_DATA3	0x170f9
+				MX6SX_PAD_SD3_DATA4__USDHC3_DATA4	0x170f9
+				MX6SX_PAD_SD3_DATA5__USDHC3_DATA5	0x170f9
+				MX6SX_PAD_SD3_DATA6__USDHC3_DATA6	0x170f9
+				MX6SX_PAD_SD3_DATA7__USDHC3_DATA7	0x170f9
+			>;
+		};
+
+		pinctrl_usdhc4: usdhc4grp {
+			fsl,pins = <
+				MX6SX_PAD_SD4_CMD__USDHC4_CMD		0x17059
+				MX6SX_PAD_SD4_CLK__USDHC4_CLK		0x10059
+				MX6SX_PAD_SD4_DATA0__USDHC4_DATA0	0x17059
+				MX6SX_PAD_SD4_DATA1__USDHC4_DATA1	0x17059
+				MX6SX_PAD_SD4_DATA2__USDHC4_DATA2	0x17059
+				MX6SX_PAD_SD4_DATA3__USDHC4_DATA3	0x17059
+				MX6SX_PAD_SD4_DATA7__GPIO6_IO_21	0x17059 /* CD */
+				MX6SX_PAD_SD4_DATA6__GPIO6_IO_20	0x17059 /* WP */
+			>;
+		};
+
+		pinctrl_vcc_sd3: vccsd3grp {
+			fsl,pins = <
+				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059
+			>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts
index c108bb4..32f07d6 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dts
+++ b/arch/arm/boot/dts/imx6sx-sdb.dts
@@ -355,6 +355,28 @@
 	status = "okay";
 };
 
+&qspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi2>;
+	status = "okay";
+
+	flash0: s25fl128s@0 {
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spansion,s25fl128s";
+		spi-max-frequency = <66000000>;
+	};
+
+	flash1: s25fl128s@1 {
+		reg = <1>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spansion,s25fl128s";
+		spi-max-frequency = <66000000>;
+	};
+};
+
 &ssi2 {
 	status = "okay";
 };
@@ -539,6 +561,23 @@
 			>;
 		};
 
+		pinctrl_qspi2: qspi2grp {
+			fsl,pins = <
+				MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0     0x70f1
+				MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1  0x70f1
+				MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2    0x70f1
+				MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3    0x70f1
+				MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK        0x70f1
+				MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B       0x70f1
+				MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0   0x70f1
+				MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1   0x70f1
+				MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2     0x70f1
+				MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3     0x70f1
+				MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK     0x70f1
+				MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B    0x70f1
+			>;
+		};
+
 		pinctrl_vcc_sd3: vccsd3grp {
 			fsl,pins = <
 				MX6SX_PAD_KEY_COL1__GPIO2_IO_11		0x17059
diff --git a/arch/arm/boot/dts/kirkwood-6192.dtsi b/arch/arm/boot/dts/kirkwood-6192.dtsi
index dd81508..9e6e9e2 100644
--- a/arch/arm/boot/dts/kirkwood-6192.dtsi
+++ b/arch/arm/boot/dts/kirkwood-6192.dtsi
@@ -66,6 +66,8 @@
 			interrupts = <21>;
 			clocks = <&gate_clk 14>, <&gate_clk 15>;
 			clock-names = "0", "1";
+			phys = <&sata_phy0>, <&sata_phy1>;
+			phy-names = "port0", "port1";
 			status = "disabled";
 		};
 
diff --git a/arch/arm/boot/dts/kirkwood-blackarmor-nas220.dts b/arch/arm/boot/dts/kirkwood-blackarmor-nas220.dts
new file mode 100644
index 0000000..fa02a9a
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-blackarmor-nas220.dts
@@ -0,0 +1,173 @@
+/*
+ * Device Tree file for Seagate Blackarmor NAS220
+ *
+ * Copyright (C) 2014 Evgeni Dobrev <evgeni@studio-punkt.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "kirkwood.dtsi"
+#include "kirkwood-6192.dtsi"
+
+/ {
+	model = "Seagate Blackarmor NAS220";
+	compatible = "seagate,blackarmor-nas220","marvell,kirkwood-88f6192",
+		     "marvell,kirkwood";
+
+	memory { /* 128 MB */
+		device_type = "memory";
+		reg = <0x00000000 0x8000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+		stdout-path = &uart0;
+	};
+
+	gpio_poweroff {
+		compatible = "gpio-poweroff";
+		gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		button@1{
+			label = "Reset";
+			linux,code = <KEY_POWER>;
+			gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+		};
+
+		button@2{
+			label = "Power";
+			linux,code = <KEY_SLEEP>;
+			gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		blue-power {
+			label = "nas220:blue:power";
+			gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_power_sata0 &pmx_power_sata1>;
+		pinctrl-names = "default";
+
+		sata0_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "SATA0 Power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			gpio = <&gpio0 24 GPIO_ACTIVE_LOW>;
+		};
+
+		sata1_power: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "SATA1 Power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			gpio = <&gpio0 28 GPIO_ACTIVE_LOW>;
+		};
+	};
+};
+
+/*
+ * Serial port routed to connector CN5
+ *
+ * pin 1 - TX (CPU's TX)
+ * pin 4 - RX (CPU's RX)
+ * pin 6 - GND
+ */
+&uart0 {
+	status = "okay";
+};
+
+&pinctrl {
+	pinctrl-0 = <&pmx_button_reset &pmx_button_power>;
+	pinctrl-names = "default";
+
+	pmx_act_sata0: pmx-act-sata0 {
+		marvell,pins = "mpp15";
+		marvell,function = "sata0";
+	};
+
+	pmx_act_sata1: pmx-act-sata1 {
+		marvell,pins = "mpp16";
+		marvell,function = "sata1";
+	};
+
+	pmx_power_sata0: pmx-power-sata0 {
+		marvell,pins = "mpp24";
+		marvell,function = "gpio";
+	};
+
+	pmx_power_sata1: pmx-power-sata1 {
+		marvell,pins = "mpp28";
+		marvell,function = "gpio";
+	};
+
+	pmx_button_reset: pmx-button-reset {
+		marvell,pins = "mpp29";
+		marvell,function = "gpio";
+	};
+
+	pmx_button_power: pmx-button-power {
+		marvell,pins = "mpp26";
+		marvell,function = "gpio";
+	};
+};
+
+&sata {
+	status = "okay";
+	nr-ports = <2>;
+};
+
+&i2c0 {
+	status = "okay";
+
+	adt7476: thermal@2e {
+		compatible = "adi,adt7476";
+		reg = <0x2e>;
+	};
+};
+
+&nand {
+	status = "okay";
+};
+
+&mdio {
+	status = "okay";
+
+	ethphy0: ethernet-phy@8 {
+		 reg = <8>;
+	};
+};
+
+&eth0 {
+	status = "okay";
+
+	ethernet0-port@0 {
+		phy-handle = <&ethphy0>;
+	};
+};
diff --git a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
index 05291f3..8474bff 100644
--- a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
+++ b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
@@ -169,6 +169,10 @@
 			gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
 		};
 	};
+	gpio-poweroff {
+		compatible = "gpio-poweroff";
+		gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
+	};
 };
 
 &nand {
@@ -192,8 +196,8 @@
 	};
 
 	partition@400000 {
-		label = "uInitrd";
-		reg = <0x540000 0x1000000>;
+		label = "rootfs";
+		reg = <0x400000 0x1C00000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/kirkwood-pogo_e02.dts b/arch/arm/boot/dts/kirkwood-pogo_e02.dts
new file mode 100644
index 0000000..a190080
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-pogo_e02.dts
@@ -0,0 +1,134 @@
+/*
+ * kirkwood-pogo_e02.dts - Device tree file for Pogoplug E02
+ *
+ * Copyright (C) 2015 Christoph Junghans <ottxor@gentoo.org>
+ *
+ * based on information of dts files from
+ *  Arch Linux ARM by Oleg Rakhmanov <moonman.ca@gmail.com>
+ *  OpenWrt by Felix Kaechele <heffer@fedoraproject.org>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+
+/ {
+	model = "Cloud Engines Pogoplug E02";
+	compatible = "cloudengines,pogoe02", "marvell,kirkwood-88f6281",
+		     "marvell,kirkwood";
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x10000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8";
+		stdout-path = &uart0;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		health {
+			label = "pogo_e02:green:health";
+			gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
+			default-state = "keep";
+		};
+		fault {
+			label = "pogo_e02:orange:fault";
+			gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-0 = <&pmx_usb_power_enable>;
+		pinctrl-names = "default";
+
+		usb_power: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "USB Power";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-always-on;
+			regulator-boot-on;
+			gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&pinctrl {
+	pinctrl-0 = < &pmx_usb_power_enable &pmx_led_orange
+		      &pmx_led_green >;
+	pinctrl-names = "default";
+
+	pmx_usb_power_enable: pmx-usb-power-enable {
+		marvell,pins = "mpp29";
+		marvell,function = "gpio";
+	};
+
+	pmx_led_green: pmx-led-green {
+		marvell,pins = "mpp48";
+		marvell,function = "gpio";
+	};
+
+	pmx_led_orange: pmx-led-orange {
+		marvell,pins = "mpp49";
+		marvell,function = "gpio";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&nand {
+	chip-delay = <40>;
+	status = "okay";
+
+	partition@0 {
+		label = "u-boot";
+		reg = <0x0000000 0x100000>;
+		read-only;
+	};
+
+	partition@100000 {
+		label = "uImage";
+		reg = <0x0100000 0x400000>;
+	};
+
+	partition@500000 {
+		label = "pogoplug";
+		reg = <0x0500000 0x2000000>;
+	};
+
+	partition@2500000 {
+		label = "root";
+		reg = <0x02500000 0x5b00000>;
+	};
+};
+
+&mdio {
+	status = "okay";
+
+	ethphy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+};
+
+&eth0 {
+	status = "okay";
+	ethernet0-port@0 {
+		phy-handle = <&ethphy0>;
+	};
+};
diff --git a/arch/arm/boot/dts/marco-evb.dts b/arch/arm/boot/dts/marco-evb.dts
deleted file mode 100644
index 5130aea..0000000
--- a/arch/arm/boot/dts/marco-evb.dts
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * DTS file for CSR SiRFmarco Evaluation Board
- *
- * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-/dts-v1/;
-
-/include/ "marco.dtsi"
-
-/ {
-	model = "CSR SiRFmarco Evaluation Board";
-	compatible = "sirf,marco-cb", "sirf,marco";
-
-	memory {
-		reg = <0x40000000 0x60000000>;
-	};
-
-	axi {
-		peri-iobg {
-			uart1: uart@cc060000 {
-				status = "okay";
-			};
-			uart2: uart@cc070000 {
-				status = "okay";
-			};
-			i2c0: i2c@cc0e0000 {
-			      status = "okay";
-			      fpga-cpld@4d {
-				      compatible = "sirf,fpga-cpld";
-				      reg = <0x4d>;
-			      };
-			};
-			spi1: spi@cc170000 {
-				status = "okay";
-				pinctrl-names = "default";
-				pinctrl-0 = <&spi1_pins_a>;
-				spi@0 {
-					compatible = "spidev";
-					reg = <0>;
-					spi-max-frequency = <1000000>;
-				};
-			};
-			pci-iobg {
-				sd0: sdhci@cd000000 {
-					bus-width = <8>;
-					status = "okay";
-				};
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/marco.dtsi b/arch/arm/boot/dts/marco.dtsi
deleted file mode 100644
index fb35422..0000000
--- a/arch/arm/boot/dts/marco.dtsi
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * DTS file for CSR SiRFmarco SoC
- *
- * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-/include/ "skeleton.dtsi"
-/ {
-	compatible = "sirf,marco";
-	#address-cells = <1>;
-	#size-cells = <1>;
-	interrupt-parent = <&gic>;
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cpu@0 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a9";
-			reg = <0>;
-		};
-		cpu@1 {
-			device_type = "cpu";
-			compatible = "arm,cortex-a9";
-			reg = <1>;
-		};
-	};
-
-	axi {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges = <0x40000000 0x40000000 0xa0000000>;
-
-		l2-cache-controller@c0030000 {
-			compatible = "arm,pl310-cache";
-			reg = <0xc0030000 0x1000>;
-			interrupts = <0 59 0>;
-			arm,tag-latency = <1 1 1>;
-			arm,data-latency = <1 1 1>;
-			arm,filter-ranges = <0x40000000 0x80000000>;
-		};
-
-		gic: interrupt-controller@c0011000 {
-			compatible = "arm,cortex-a9-gic";
-			interrupt-controller;
-			#interrupt-cells = <3>;
-			reg = <0xc0011000 0x1000>,
-			      <0xc0010100 0x0100>;
-		};
-
-		rstc-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc2000000 0xc2000000 0x1000000>;
-
-			rstc: reset-controller@c2000000 {
-				compatible = "sirf,marco-rstc";
-				reg = <0xc2000000 0x10000>;
-				#reset-cells = <1>;
-			};
-		};
-
-		sys-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc3000000 0xc3000000 0x1000000>;
-
-			clock-controller@c3000000 {
-				compatible = "sirf,marco-clkc";
-				reg = <0xc3000000 0x1000>;
-				interrupts = <0 3 0>;
-			};
-
-			rsc-controller@c3010000 {
-				compatible = "sirf,marco-rsc";
-				reg = <0xc3010000 0x1000>;
-			};
-		};
-
-		mem-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc4000000 0xc4000000 0x1000000>;
-
-			memory-controller@c4000000 {
-				compatible = "sirf,marco-memc";
-				reg = <0xc4000000 0x10000>;
-				interrupts = <0 27 0>;
-			};
-		};
-
-		disp-iobg0 {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc5000000 0xc5000000 0x1000000>;
-
-			display0@c5000000 {
-				compatible = "sirf,marco-lcd";
-				reg = <0xc5000000 0x10000>;
-				interrupts = <0 30 0>;
-			};
-
-			vpp0@c5010000 {
-				compatible = "sirf,marco-vpp";
-				reg = <0xc5010000 0x10000>;
-				interrupts = <0 31 0>;
-			};
-		};
-
-		disp-iobg1 {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc6000000 0xc6000000 0x1000000>;
-
-			display1@c6000000 {
-				compatible = "sirf,marco-lcd";
-				reg = <0xc6000000 0x10000>;
-				interrupts = <0 62 0>;
-			};
-
-			vpp1@c6010000 {
-				compatible = "sirf,marco-vpp";
-				reg = <0xc6010000 0x10000>;
-				interrupts = <0 63 0>;
-			};
-		};
-
-		graphics-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc8000000 0xc8000000 0x1000000>;
-
-			graphics@c8000000 {
-				compatible = "powervr,sgx540";
-				reg = <0xc8000000 0x1000000>;
-				interrupts = <0 6 0>;
-			};
-		};
-
-		multimedia-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xc9000000 0xc9000000 0x1000000>;
-
-			multimedia@a0000000 {
-				compatible = "sirf,marco-video-codec";
-				reg = <0xc9000000 0x1000000>;
-				interrupts = <0 5 0>;
-			};
-		};
-
-		dsp-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xca000000 0xca000000 0x2000000>;
-
-			dspif@ca000000 {
-				compatible = "sirf,marco-dspif";
-				reg = <0xca000000 0x10000>;
-				interrupts = <0 9 0>;
-			};
-
-			gps@ca010000 {
-				compatible = "sirf,marco-gps";
-				reg = <0xca010000 0x10000>;
-				interrupts = <0 7 0>;
-			};
-
-			dsp@cb000000 {
-				compatible = "sirf,marco-dsp";
-				reg = <0xcb000000 0x1000000>;
-				interrupts = <0 8 0>;
-			};
-		};
-
-		peri-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xcc000000 0xcc000000 0x2000000>;
-
-			timer@cc020000 {
-				compatible = "sirf,marco-tick";
-				reg = <0xcc020000 0x1000>;
-				interrupts = <0 0 0>,
-					   <0 1 0>,
-					   <0 2 0>,
-					   <0 49 0>,
-					   <0 50 0>,
-					   <0 51 0>;
-			};
-
-			nand@cc030000 {
-				compatible = "sirf,marco-nand";
-				reg = <0xcc030000 0x10000>;
-				interrupts = <0 41 0>;
-			};
-
-			audio@cc040000 {
-				compatible = "sirf,marco-audio";
-				reg = <0xcc040000 0x10000>;
-				interrupts = <0 35 0>;
-			};
-
-			uart0: uart@cc050000 {
-				cell-index = <0>;
-				compatible = "sirf,marco-uart";
-				reg = <0xcc050000 0x1000>;
-				interrupts = <0 17 0>;
-				fifosize = <128>;
-				status = "disabled";
-			};
-
-			uart1: uart@cc060000 {
-				cell-index = <1>;
-				compatible = "sirf,marco-uart";
-				reg = <0xcc060000 0x1000>;
-				interrupts = <0 18 0>;
-				fifosize = <32>;
-				status = "disabled";
-			};
-
-			uart2: uart@cc070000 {
-				cell-index = <2>;
-				compatible = "sirf,marco-uart";
-				reg = <0xcc070000 0x1000>;
-				interrupts = <0 19 0>;
-				fifosize = <128>;
-				status = "disabled";
-			};
-
-			uart3: uart@cc190000 {
-				cell-index = <3>;
-				compatible = "sirf,marco-uart";
-				reg = <0xcc190000 0x1000>;
-				interrupts = <0 66 0>;
-				fifosize = <128>;
-				status = "disabled";
-			};
-
-			uart4: uart@cc1a0000 {
-				cell-index = <4>;
-				compatible = "sirf,marco-uart";
-				reg = <0xcc1a0000 0x1000>;
-				interrupts = <0 69 0>;
-				fifosize = <128>;
-				status = "disabled";
-			};
-
-			usp0: usp@cc080000 {
-				cell-index = <0>;
-				compatible = "sirf,marco-usp";
-				reg = <0xcc080000 0x10000>;
-				interrupts = <0 20 0>;
-				status = "disabled";
-			};
-
-			usp1: usp@cc090000 {
-				cell-index = <1>;
-				compatible = "sirf,marco-usp";
-				reg = <0xcc090000 0x10000>;
-				interrupts = <0 21 0>;
-				status = "disabled";
-			};
-
-			usp2: usp@cc0a0000 {
-				cell-index = <2>;
-				compatible = "sirf,marco-usp";
-				reg = <0xcc0a0000 0x10000>;
-				interrupts = <0 22 0>;
-				status = "disabled";
-			};
-
-			dmac0: dma-controller@cc0b0000 {
-				cell-index = <0>;
-				compatible = "sirf,marco-dmac";
-				reg = <0xcc0b0000 0x10000>;
-				interrupts = <0 12 0>;
-			};
-
-			dmac1: dma-controller@cc160000 {
-				cell-index = <1>;
-				compatible = "sirf,marco-dmac";
-				reg = <0xcc160000 0x10000>;
-				interrupts = <0 13 0>;
-			};
-
-			vip@cc0c0000 {
-				compatible = "sirf,marco-vip";
-				reg = <0xcc0c0000 0x10000>;
-			};
-
-			spi0: spi@cc0d0000 {
-				cell-index = <0>;
-				compatible = "sirf,marco-spi";
-				reg = <0xcc0d0000 0x10000>;
-				interrupts = <0 15 0>;
-				sirf,spi-num-chipselects = <1>;
-				cs-gpios = <&gpio 0 0>;
-				sirf,spi-dma-rx-channel = <25>;
-				sirf,spi-dma-tx-channel = <20>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				status = "disabled";
-			};
-
-			spi1: spi@cc170000 {
-				cell-index = <1>;
-				compatible = "sirf,marco-spi";
-				reg = <0xcc170000 0x10000>;
-				interrupts = <0 16 0>;
-				sirf,spi-num-chipselects = <1>;
-				cs-gpios = <&gpio 0 0>;
-				sirf,spi-dma-rx-channel = <12>;
-				sirf,spi-dma-tx-channel = <13>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				status = "disabled";
-			};
-
-			i2c0: i2c@cc0e0000 {
-				cell-index = <0>;
-				compatible = "sirf,marco-i2c";
-				reg = <0xcc0e0000 0x10000>;
-				interrupts = <0 24 0>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				status = "disabled";
-			};
-
-			i2c1: i2c@cc0f0000 {
-				cell-index = <1>;
-				compatible = "sirf,marco-i2c";
-				reg = <0xcc0f0000 0x10000>;
-				interrupts = <0 25 0>;
-				#address-cells = <1>;
-				#size-cells = <0>;
-				status = "disabled";
-			};
-
-			tsc@cc110000 {
-				compatible = "sirf,marco-tsc";
-				reg = <0xcc110000 0x10000>;
-				interrupts = <0 33 0>;
-			};
-
-			gpio: pinctrl@cc120000 {
-				#gpio-cells = <2>;
-				#interrupt-cells = <2>;
-				compatible = "sirf,marco-pinctrl";
-				reg = <0xcc120000 0x10000>;
-				interrupts = <0 43 0>,
-					   <0 44 0>,
-					   <0 45 0>,
-					   <0 46 0>,
-					   <0 47 0>;
-				gpio-controller;
-				interrupt-controller;
-
-				lcd_16pins_a: lcd0_0 {
-					lcd {
-						sirf,pins = "lcd_16bitsgrp";
-						sirf,function = "lcd_16bits";
-					};
-				};
-				lcd_18pins_a: lcd0_1 {
-					lcd {
-						sirf,pins = "lcd_18bitsgrp";
-						sirf,function = "lcd_18bits";
-					};
-				};
-				lcd_24pins_a: lcd0_2 {
-					lcd {
-						sirf,pins = "lcd_24bitsgrp";
-						sirf,function = "lcd_24bits";
-					};
-				};
-				lcdrom_pins_a: lcdrom0_0 {
-					lcd {
-						sirf,pins = "lcdromgrp";
-						sirf,function = "lcdrom";
-					};
-				};
-				uart0_pins_a: uart0_0 {
-					uart {
-						sirf,pins = "uart0grp";
-						sirf,function = "uart0";
-					};
-				};
-				uart1_pins_a: uart1_0 {
-					uart {
-						sirf,pins = "uart1grp";
-						sirf,function = "uart1";
-					};
-				};
-				uart2_pins_a: uart2_0 {
-					uart {
-						sirf,pins = "uart2grp";
-						sirf,function = "uart2";
-					};
-				};
-				uart2_noflow_pins_a: uart2_1 {
-					uart {
-						sirf,pins = "uart2_nostreamctrlgrp";
-						sirf,function = "uart2_nostreamctrl";
-					};
-				};
-				spi0_pins_a: spi0_0 {
-					spi {
-						sirf,pins = "spi0grp";
-						sirf,function = "spi0";
-					};
-				};
-				spi1_pins_a: spi1_0 {
-					spi {
-						sirf,pins = "spi1grp";
-						sirf,function = "spi1";
-					};
-				};
-				i2c0_pins_a: i2c0_0 {
-					i2c {
-						sirf,pins = "i2c0grp";
-						sirf,function = "i2c0";
-					};
-				};
-				i2c1_pins_a: i2c1_0 {
-					i2c {
-						sirf,pins = "i2c1grp";
-						sirf,function = "i2c1";
-					};
-				};
-				pwm0_pins_a: pwm0_0 {
-				        pwm {
-				                sirf,pins = "pwm0grp";
-				                sirf,function = "pwm0";
-				        };
-				};
-				pwm1_pins_a: pwm1_0 {
-				        pwm {
-				                sirf,pins = "pwm1grp";
-				                sirf,function = "pwm1";
-				        };
-				};
-				pwm2_pins_a: pwm2_0 {
-				        pwm {
-				                sirf,pins = "pwm2grp";
-				                sirf,function = "pwm2";
-				        };
-				};
-				pwm3_pins_a: pwm3_0 {
-				        pwm {
-				                sirf,pins = "pwm3grp";
-				                sirf,function = "pwm3";
-				        };
-				};
-				gps_pins_a: gps_0 {
-				        gps {
-				                sirf,pins = "gpsgrp";
-				                sirf,function = "gps";
-				        };
-				};
-				vip_pins_a: vip_0 {
-				        vip {
-				                sirf,pins = "vipgrp";
-				                sirf,function = "vip";
-				        };
-				};
-				sdmmc0_pins_a: sdmmc0_0 {
-				        sdmmc0 {
-				                sirf,pins = "sdmmc0grp";
-				                sirf,function = "sdmmc0";
-				        };
-				};
-				sdmmc1_pins_a: sdmmc1_0 {
-				        sdmmc1 {
-				                sirf,pins = "sdmmc1grp";
-				                sirf,function = "sdmmc1";
-				        };
-				};
-				sdmmc2_pins_a: sdmmc2_0 {
-				        sdmmc2 {
-				                sirf,pins = "sdmmc2grp";
-				                sirf,function = "sdmmc2";
-				        };
-				};
-				sdmmc3_pins_a: sdmmc3_0 {
-				        sdmmc3 {
-				                sirf,pins = "sdmmc3grp";
-				                sirf,function = "sdmmc3";
-				        };
-				};
-				sdmmc4_pins_a: sdmmc4_0 {
-				        sdmmc4 {
-				                sirf,pins = "sdmmc4grp";
-				                sirf,function = "sdmmc4";
-				        };
-				};
-				sdmmc5_pins_a: sdmmc5_0 {
-				        sdmmc5 {
-				                sirf,pins = "sdmmc5grp";
-				                sirf,function = "sdmmc5";
-				        };
-				};
-				i2s_pins_a: i2s_0 {
-				        i2s {
-				                sirf,pins = "i2sgrp";
-				                sirf,function = "i2s";
-				        };
-				};
-				ac97_pins_a: ac97_0 {
-				        ac97 {
-				                sirf,pins = "ac97grp";
-				                sirf,function = "ac97";
-				        };
-				};
-				nand_pins_a: nand_0 {
-				        nand {
-				                sirf,pins = "nandgrp";
-				                sirf,function = "nand";
-				        };
-				};
-				usp0_pins_a: usp0_0 {
-				        usp0 {
-				                sirf,pins = "usp0grp";
-				                sirf,function = "usp0";
-				        };
-				};
-				usp1_pins_a: usp1_0 {
-				        usp1 {
-				                sirf,pins = "usp1grp";
-				                sirf,function = "usp1";
-				        };
-				};
-				usp2_pins_a: usp2_0 {
-				        usp2 {
-				                sirf,pins = "usp2grp";
-				                sirf,function = "usp2";
-				        };
-				};
-				usb0_utmi_drvbus_pins_a: usb0_utmi_drvbus_0 {
-				        usb0_utmi_drvbus {
-				                sirf,pins = "usb0_utmi_drvbusgrp";
-				                sirf,function = "usb0_utmi_drvbus";
-				        };
-				};
-				usb1_utmi_drvbus_pins_a: usb1_utmi_drvbus_0 {
-				        usb1_utmi_drvbus {
-				                sirf,pins = "usb1_utmi_drvbusgrp";
-				                sirf,function = "usb1_utmi_drvbus";
-				        };
-				};
-				warm_rst_pins_a: warm_rst_0 {
-				        warm_rst {
-				                sirf,pins = "warm_rstgrp";
-				                sirf,function = "warm_rst";
-				        };
-				};
-				pulse_count_pins_a: pulse_count_0 {
-				        pulse_count {
-				                sirf,pins = "pulse_countgrp";
-				                sirf,function = "pulse_count";
-				        };
-				};
-				cko0_rst_pins_a: cko0_rst_0 {
-				        cko0_rst {
-				                sirf,pins = "cko0_rstgrp";
-				                sirf,function = "cko0_rst";
-				        };
-				};
-				cko1_rst_pins_a: cko1_rst_0 {
-				        cko1_rst {
-				                sirf,pins = "cko1_rstgrp";
-				                sirf,function = "cko1_rst";
-				        };
-				};
-			};
-
-			pwm@cc130000 {
-				compatible = "sirf,marco-pwm";
-				reg = <0xcc130000 0x10000>;
-			};
-
-			efusesys@cc140000 {
-				compatible = "sirf,marco-efuse";
-				reg = <0xcc140000 0x10000>;
-			};
-
-			pulsec@cc150000 {
-				compatible = "sirf,marco-pulsec";
-				reg = <0xcc150000 0x10000>;
-				interrupts = <0 48 0>;
-			};
-
-			pci-iobg {
-				compatible = "sirf,marco-pciiobg", "simple-bus";
-				#address-cells = <1>;
-				#size-cells = <1>;
-				ranges = <0xcd000000 0xcd000000 0x1000000>;
-
-				sd0: sdhci@cd000000 {
-					cell-index = <0>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd000000 0x100000>;
-					interrupts = <0 38 0>;
-					status = "disabled";
-				};
-
-				sd1: sdhci@cd100000 {
-					cell-index = <1>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd100000 0x100000>;
-					interrupts = <0 38 0>;
-					status = "disabled";
-				};
-
-				sd2: sdhci@cd200000 {
-					cell-index = <2>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd200000 0x100000>;
-					interrupts = <0 23 0>;
-					status = "disabled";
-				};
-
-				sd3: sdhci@cd300000 {
-					cell-index = <3>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd300000 0x100000>;
-					interrupts = <0 23 0>;
-					status = "disabled";
-				};
-
-				sd4: sdhci@cd400000 {
-					cell-index = <4>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd400000 0x100000>;
-					interrupts = <0 39 0>;
-					status = "disabled";
-				};
-
-				sd5: sdhci@cd500000 {
-					cell-index = <5>;
-					compatible = "sirf,marco-sdhc";
-					reg = <0xcd500000 0x100000>;
-					interrupts = <0 39 0>;
-					status = "disabled";
-				};
-
-				pci-copy@cd900000 {
-					compatible = "sirf,marco-pcicp";
-					reg = <0xcd900000 0x100000>;
-					interrupts = <0 40 0>;
-				};
-
-				rom-interface@cda00000 {
-					compatible = "sirf,marco-romif";
-					reg = <0xcda00000 0x100000>;
-				};
-			};
-		};
-
-		rtc-iobg {
-			compatible = "sirf,marco-rtciobg", "sirf-marco-rtciobg-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			reg = <0xc1000000 0x10000>;
-
-			gpsrtc@1000 {
-				compatible = "sirf,marco-gpsrtc";
-				reg = <0x1000 0x1000>;
-				interrupts = <0 55 0>,
-					   <0 56 0>,
-					   <0 57 0>;
-			};
-
-			sysrtc@2000 {
-				compatible = "sirf,marco-sysrtc";
-				reg = <0x2000 0x1000>;
-				interrupts = <0 52 0>,
-					   <0 53 0>,
-					   <0 54 0>;
-			};
-
-			pwrc@3000 {
-				compatible = "sirf,marco-pwrc";
-				reg = <0x3000 0x1000>;
-				interrupts = <0 32 0>;
-			};
-		};
-
-		uus-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xce000000 0xce000000 0x1000000>;
-
-			usb0: usb@ce000000 {
-				compatible = "chipidea,ci13611a-marco";
-				reg = <0xce000000 0x10000>;
-				interrupts = <0 10 0>;
-			};
-
-			usb1: usb@ce010000 {
-				compatible = "chipidea,ci13611a-marco";
-				reg = <0xce010000 0x10000>;
-				interrupts = <0 11 0>;
-			};
-
-			security@ce020000 {
-				compatible = "sirf,marco-security";
-				reg = <0xce020000 0x10000>;
-				interrupts = <0 42 0>;
-			};
-		};
-
-		can-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xd0000000 0xd0000000 0x1000000>;
-
-			can0: can@d0000000 {
-				compatible = "sirf,marco-can";
-				reg = <0xd0000000 0x10000>;
-			};
-
-			can1: can@d0010000 {
-				compatible = "sirf,marco-can";
-				reg = <0xd0010000 0x10000>;
-			};
-		};
-
-		lvds-iobg {
-			compatible = "simple-bus";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			ranges = <0xd1000000 0xd1000000 0x1000000>;
-
-			lvds@d1000000 {
-				compatible = "sirf,marco-lvds";
-				reg = <0xd1000000 0x10000>;
-				interrupts = <0 64 0>;
-			};
-		};
-	};
-};
diff --git a/arch/arm/boot/dts/mt6589-aquaris5.dts b/arch/arm/boot/dts/mt6589-aquaris5.dts
index 0da0470..594a6f3 100644
--- a/arch/arm/boot/dts/mt6589-aquaris5.dts
+++ b/arch/arm/boot/dts/mt6589-aquaris5.dts
@@ -21,10 +21,20 @@
 	compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589";
 
 	chosen {
-		bootargs = "earlyprintk";
+		bootargs = "console=ttyS0,921600n8 earlyprintk";
+		stdout-path = &uart0;
 	};
 
 	memory {
 		reg = <0x80000000 0x40000000>;
 	};
+
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
 };
diff --git a/arch/arm/boot/dts/mt6589.dtsi b/arch/arm/boot/dts/mt6589.dtsi
index e3c7600..106b61b 100644
--- a/arch/arm/boot/dts/mt6589.dtsi
+++ b/arch/arm/boot/dts/mt6589.dtsi
@@ -19,7 +19,7 @@
 
 / {
 	compatible = "mediatek,mt6589";
-	interrupt-parent = <&gic>;
+	interrupt-parent = <&sysirq>;
 
 	cpus {
 		#address-cells = <1>;
@@ -65,6 +65,12 @@
 			clock-frequency = <32000>;
 			#clock-cells = <0>;
 		};
+
+		uart_clk: dummy26m {
+			compatible = "fixed-clock";
+			clock-frequency = <26000000>;
+			#clock-cells = <0>;
+		};
 	};
 
 	soc {
@@ -76,19 +82,61 @@
 		timer: timer@10008000 {
 			compatible = "mediatek,mt6577-timer";
 			reg = <0x10008000 0x80>;
-			interrupts = <GIC_SPI 113 IRQ_TYPE_EDGE_RISING>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&system_clk>, <&rtc_clk>;
 			clock-names = "system-clk", "rtc-clk";
 		};
 
+		sysirq: interrupt-controller@10200100 {
+			compatible = "mediatek,mt6589-sysirq",
+				     "mediatek,mt6577-sysirq";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+			reg = <0x10200100 0x1c>;
+		};
+
 		gic: interrupt-controller@10211000 {
 			compatible = "arm,cortex-a7-gic";
 			interrupt-controller;
 			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
 			reg = <0x10211000 0x1000>,
 			      <0x10212000 0x1000>,
 			      <0x10214000 0x2000>,
 			      <0x10216000 0x2000>;
 		};
+
+		uart0: serial@11006000 {
+			compatible = "mediatek,mt6577-uart";
+			reg = <0x11006000 0x400>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart1: serial@11007000 {
+			compatible = "mediatek,mt6577-uart";
+			reg = <0x11007000 0x400>;
+			interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart2: serial@11008000 {
+			compatible = "mediatek,mt6577-uart";
+			reg = <0x11008000 0x400>;
+			interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart3: serial@11009000 {
+			compatible = "mediatek,mt6577-uart";
+			reg = <0x11009000 0x400>;
+			interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/mt6592.dtsi b/arch/arm/boot/dts/mt6592.dtsi
index 31e5a09..c69201f 100644
--- a/arch/arm/boot/dts/mt6592.dtsi
+++ b/arch/arm/boot/dts/mt6592.dtsi
@@ -18,7 +18,7 @@
 
 / {
 	compatible = "mediatek,mt6592";
-	interrupt-parent = <&gic>;
+	interrupt-parent = <&sysirq>;
 
 	cpus {
 		#address-cells = <1>;
@@ -78,21 +78,66 @@
 		#clock-cells = <0>;
 	};
 
+	uart_clk: dummy26m {
+		compatible = "fixed-clock";
+		clock-frequency = <26000000>;
+		#clock-cells = <0>;
+	};
+
 	timer: timer@10008000 {
 		compatible = "mediatek,mt6577-timer";
 		reg = <0x10008000 0x80>;
-		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_LOW>;
 		clocks = <&system_clk>, <&rtc_clk>;
 		clock-names = "system-clk", "rtc-clk";
 	};
 
+	sysirq: interrupt-controller@10200220 {
+		compatible = "mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		reg = <0x10200220 0x1c>;
+	};
+
 	gic: interrupt-controller@10211000 {
 		compatible = "arm,cortex-a7-gic";
 		interrupt-controller;
 		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
 		reg = <0x10211000 0x1000>,
 		      <0x10212000 0x1000>;
 	};
 
-};
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0x11002000 0x400>;
+		interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
 
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0x11003000 0x400>;
+		interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0x11004000 0x400>;
+		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart3: serial@11005000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0x11005000 0x400>;
+		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm/boot/dts/mt8127-moose.dts b/arch/arm/boot/dts/mt8127-moose.dts
index 13cba0e..073e295 100644
--- a/arch/arm/boot/dts/mt8127-moose.dts
+++ b/arch/arm/boot/dts/mt8127-moose.dts
@@ -23,3 +23,7 @@
 		reg = <0 0x80000000 0 0x40000000>;
 	};
 };
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/mt8127.dtsi b/arch/arm/boot/dts/mt8127.dtsi
index b24c0a2..aaa7862 100644
--- a/arch/arm/boot/dts/mt8127.dtsi
+++ b/arch/arm/boot/dts/mt8127.dtsi
@@ -18,7 +18,7 @@
 
 / {
 	compatible = "mediatek,mt8127";
-	interrupt-parent = <&gic>;
+	interrupt-parent = <&sysirq>;
 
 	cpus {
 		#address-cells = <1>;
@@ -64,6 +64,12 @@
 			clock-frequency = <32000>;
 			#clock-cells = <0>;
 		};
+
+		uart_clk: dummy26m {
+			compatible = "fixed-clock";
+			clock-frequency = <26000000>;
+			#clock-cells = <0>;
+                };
 	};
 
 	soc {
@@ -76,19 +82,61 @@
 			compatible = "mediatek,mt8127-timer",
 					"mediatek,mt6577-timer";
 			reg = <0 0x10008000 0 0x80>;
-			interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&system_clk>, <&rtc_clk>;
 			clock-names = "system-clk", "rtc-clk";
 		};
 
+		sysirq: interrupt-controller@10200100 {
+			compatible = "mediatek,mt8127-sysirq",
+				     "mediatek,mt6577-sysirq";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+			reg = <0 0x10200100 0 0x1c>;
+		};
+
 		gic: interrupt-controller@10211000 {
 			compatible = "arm,cortex-a7-gic";
 			interrupt-controller;
 			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
 			reg = <0 0x10211000 0 0x1000>,
 			      <0 0x10212000 0 0x1000>,
 			      <0 0x10214000 0 0x2000>,
 			      <0 0x10216000 0 0x2000>;
 		};
+
+		uart0: serial@11006000 {
+			compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
+			reg = <0 0x11002000 0 0x400>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart1: serial@11007000 {
+			compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
+			reg = <0 0x11003000 0 0x400>;
+			interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart2: serial@11008000 {
+			compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
+			reg = <0 0x11004000 0 0x400>;
+			interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart3: serial@11009000 {
+			compatible = "mediatek,mt8127-uart","mediatek,mt6577-uart";
+			reg = <0 0x11005000 0 0x400>;
+			interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/mt8135-evbp1.dts b/arch/arm/boot/dts/mt8135-evbp1.dts
index a5adf97..3667738 100644
--- a/arch/arm/boot/dts/mt8135-evbp1.dts
+++ b/arch/arm/boot/dts/mt8135-evbp1.dts
@@ -23,3 +23,7 @@
 		reg = <0 0x80000000 0 0x40000000>;
 	};
 };
+
+&uart3 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index 7d56a98..a161e99 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -18,7 +18,7 @@
 
 / {
 	compatible = "mediatek,mt8135";
-	interrupt-parent = <&gic>;
+	interrupt-parent = <&sysirq>;
 
 	cpu-map {
 		cluster0 {
@@ -86,6 +86,13 @@
 			clock-frequency = <32000>;
 			#clock-cells = <0>;
 		};
+
+		uart_clk: dummy26m {
+			compatible = "fixed-clock";
+			clock-frequency = <26000000>;
+			#clock-cells = <0>;
+		};
+
 	};
 
 	soc {
@@ -98,19 +105,62 @@
 			compatible = "mediatek,mt8135-timer",
 					"mediatek,mt6577-timer";
 			reg = <0 0x10008000 0 0x80>;
-			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&system_clk>, <&rtc_clk>;
 			clock-names = "system-clk", "rtc-clk";
 		};
 
+		sysirq: interrupt-controller@10200030 {
+			compatible = "mediatek,mt8135-sysirq",
+				     "mediatek,mt6577-sysirq";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+			reg = <0 0x10200030 0 0x1c>;
+		};
+
 		gic: interrupt-controller@10211000 {
 			compatible = "arm,cortex-a15-gic";
 			interrupt-controller;
 			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
 			reg = <0 0x10211000 0 0x1000>,
 			      <0 0x10212000 0 0x1000>,
 			      <0 0x10214000 0 0x2000>,
 			      <0 0x10216000 0 0x2000>;
 		};
+
+		uart0: serial@11006000 {
+			compatible = "mediatek,mt8135-uart","mediatek,mt6577-uart";
+			reg = <0 0x11006000 0 0x400>;
+			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart1: serial@11007000 {
+			compatible = "mediatek,mt8135-uart","mediatek,mt6577-uart";
+			reg = <0 0x11007000 0 0x400>;
+			interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart2: serial@11008000 {
+			compatible = "mediatek,mt8135-uart","mediatek,mt6577-uart";
+			reg = <0 0x11008000 0 0x400>;
+			interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart3: serial@11009000 {
+			compatible = "mediatek,mt8135-uart","mediatek,mt6577-uart";
+			reg = <0 0x11009000 0 0x400>;
+			interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
 	};
 };
diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
index 6ea6d46..4d091ca 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -259,3 +259,61 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&mcbsp2_pins>;
 };
+
+&gpmc {
+	ranges = <0 0 0x00000000 0x01000000>;
+
+	nand@0,0 {
+		reg = <0 0 4>;	/* CS0, offset 0, IO size 4 */
+		nand-bus-width = <8>;
+		gpmc,device-width = <1>;
+		ti,nand-ecc-opt = "sw";
+
+		gpmc,cs-on-ns = <0>;
+		gpmc,cs-rd-off-ns = <120>;
+		gpmc,cs-wr-off-ns = <120>;
+
+		gpmc,adv-on-ns = <0>;
+		gpmc,adv-rd-off-ns = <120>;
+		gpmc,adv-wr-off-ns = <120>;
+
+		gpmc,we-on-ns = <6>;
+		gpmc,we-off-ns = <90>;
+
+		gpmc,oe-on-ns = <6>;
+		gpmc,oe-off-ns = <90>;
+
+		gpmc,page-burst-access-ns = <6>;
+		gpmc,access-ns = <72>;
+		gpmc,cycle2cycle-delay-ns = <60>;
+
+		gpmc,rd-cycle-ns = <120>;
+		gpmc,wr-cycle-ns = <120>;
+		gpmc,wr-access-ns = <186>;
+		gpmc,wr-data-mux-bus-ns = <90>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "xloader";
+			reg = <0 0x80000>;
+		};
+		partition@0x80000 {
+			label = "uboot";
+			reg = <0x80000 0x1e0000>;
+		};
+		partition@0x260000 {
+			label = "uboot environment";
+			reg = <0x260000 0x40000>;
+		};
+		partition@0x2a0000 {
+			label = "linux";
+			reg = <0x2a0000 0x400000>;
+		};
+		partition@0x6a0000 {
+			label = "rootfs";
+			reg = <0x6a0000 0x1f880000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
index 9a4a3ab..d9e92b6 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
@@ -50,7 +50,8 @@
 #include "omap-gpmc-smsc911x.dtsi"
 
 &gpmc {
-	ranges = <5 0 0x2c000000 0x01000000>;
+	ranges = <5 0 0x2c000000 0x01000000>, /* CM-T3x30 SMSC9x Eth */
+		 <0 0 0x00000000 0x01000000>; /* CM-T3x NAND */
 
 	smsc1: ethernet@gpmc {
 		compatible = "smsc,lan9221", "smsc,lan9115";
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index 655d6e9..fb3a696 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -83,6 +83,41 @@
 		compatible = "usb-nop-xceiv";
 		reset-gpios = <&gpio6 14 GPIO_ACTIVE_LOW>;
 	};
+
+	tv0: connector@1 {
+		compatible = "svideo-connector";
+		label = "tv";
+
+		port {
+			tv_connector_in: endpoint {
+				remote-endpoint = <&opa_out>;
+			};
+		};
+	};
+
+	tv_amp: opa362 {
+		compatible = "ti,opa362";
+		enable-gpios = <&gpio1 23 0>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				opa_in: endpoint@0 {
+					remote-endpoint = <&venc_out>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				opa_out: endpoint@0 {
+					remote-endpoint = <&tv_connector_in>;
+				};
+			};
+		};
+	};
 };
 
 &omap3_pmx_core {
@@ -202,11 +237,18 @@
 		reg = <0x48>;
 		interrupts = <7>; /* SYS_NIRQ cascaded to intc */
 		interrupt-parent = <&intc>;
-	};
 
-	twl_audio: audio {
-		compatible = "ti,twl4030-audio";
-		codec {
+		twl_audio: audio {
+			compatible = "ti,twl4030-audio";
+			ti,enable-vibra = <1>;
+			codec {
+				ti,ramp_delay_value = <3>;
+			};
+		};
+
+		twl_power: power {
+			compatible = "ti,twl4030-power";
+			ti,use_poweroff;
 		};
 	};
 };
@@ -222,15 +264,23 @@
 		compatible = "bosch,bmp085";
 		reg = <0x77>;
 		interrupt-parent = <&gpio4>;
-		interrupts = <17 IRQ_TYPE_EDGE_RISING>;
+		interrupts = <17 IRQ_TYPE_EDGE_RISING>; /* GPIO_113 */
 	};
 
 	/* accelerometer */
 	bma180@41 {
 		compatible = "bosch,bma180";
 		reg = <0x41>;
-		interrupt-parent = <&gpio3>;
-		interrupts = <19 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; /* GPIO_115 */
+	};
+
+	/* gyroscope */
+	itg3200@68 {
+		compatible = "invensense,itg3200";
+		reg = <0x68>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <24 0>; /* GPIO_56 */
 	};
 
 	/* leds */
@@ -281,7 +331,7 @@
 		compatible = "ti,tsc2007";
 		reg = <0x48>;
 		interrupt-parent = <&gpio6>;
-		interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+		interrupts = <0 IRQ_TYPE_EDGE_FALLING>; /* GPIO_160 */
 		gpios = <&gpio6 0 GPIO_ACTIVE_LOW>;
 		ti,x-plate-ohms = <600>;
 	};
@@ -320,12 +370,17 @@
 	vmmc-supply = <&vaux4>;
 	bus-width = <4>;
 	ti,non-removable;
+	cap-power-off-card;
 };
 
 &mmc3 {
 	status = "disabled";
 };
 
+&twl_keypad {
+	status = "disabled";
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart1_pins>;
@@ -342,8 +397,8 @@
 };
 
 &charger {
-	bb_uvolt = <3200000>;
-	bb_uamp = <150>;
+	ti,bb-uvolt = <3200000>;
+	ti,bb-uamp = <150>;
 };
 
 /* spare */
@@ -377,16 +432,12 @@
 	regulator-max-microvolt = <3150000>;
 };
 
-/* Needed to power the DPI pins */
-&vpll2 {
-	regulator-always-on;
-};
-
 &dss {
 	pinctrl-names = "default";
 	pinctrl-0 = < &dss_dpi_pins >;
 
 	status = "okay";
+	vdds_dsi-supply = <&vpll2>;
 
 	port {
 		dpi_out: endpoint {
@@ -396,6 +447,20 @@
 	};
 };
 
+&venc {
+	status = "okay";
+
+	vdda-supply = <&vdac>;
+
+	port {
+		venc_out: endpoint {
+			remote-endpoint = <&opa_in>;
+			ti,channels = <2>;
+			ti,invert-polarity;
+		};
+	};
+};
+
 &gpmc {
 	ranges = <0 0 0x30000000 0x1000000>; /* CS0: 16MB for NAND */
 
@@ -449,3 +514,7 @@
 		};
 	};
 };
+
+&mcbsp2 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index b550c41..6040327 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -307,7 +307,7 @@
 	regulator-name = "V28";
 	regulator-min-microvolt = <2800000>;
 	regulator-max-microvolt = <2800000>;
-	regulator-always-on; /* due battery cover sensor */
+	regulator-always-on; /* due to battery cover sensor */
 };
 
 &vaux2 {
@@ -365,7 +365,6 @@
 	regulator-name = "VIO";
 	regulator-min-microvolt = <1800000>;
 	regulator-max-microvolt = <1800000>;
-
 };
 
 &vintana1 {
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 1e49dfe..c41db94 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -60,6 +60,11 @@
 
 &twl {
 	compatible = "ti,twl5031";
+
+	twl_power: power {
+		compatible = "ti,twl4030-power";
+		ti,use_poweroff;
+	};
 };
 
 &twl_gpio {
diff --git a/arch/arm/boot/dts/omap3-sbc-t3517.dts b/arch/arm/boot/dts/omap3-sbc-t3517.dts
index 1798653..c2d5c28 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3517.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3517.dts
@@ -69,3 +69,7 @@
 	};
 };
 
+&gpmc {
+	ranges = <4 0 0x2d000000 0x01000000>,	/* SB-T35 SMSC9x Eth */
+		 <0 0 0x00000000 0x01000000>;	/* CM-T3x NAND */
+};
diff --git a/arch/arm/boot/dts/omap3-sbc-t3530.dts b/arch/arm/boot/dts/omap3-sbc-t3530.dts
index c994f0f..834bc78 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3530.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3530.dts
@@ -26,14 +26,10 @@
 	};
 };
 
-/*
- * The following ranges correspond to SMSC9x eth chips on CM-T3530 CoM and
- * SB-T35 baseboard respectively.
- * This setting includes both chips in SBC-T3530 board device tree.
- */
 &gpmc {
-	ranges = <5 0 0x2c000000 0x01000000>,
-		 <4 0 0x2d000000 0x01000000>;
+	ranges = <5 0 0x2c000000 0x01000000>,	/* CM-T3x30 SMSC9x Eth */
+		 <4 0 0x2d000000 0x01000000>,	/* SB-T35 SMSC9x Eth */
+		 <0 0 0x00000000 0x01000000>;	/* CM-T3x NAND */
 };
 
 &mmc1 {
diff --git a/arch/arm/boot/dts/omap3-sbc-t3730.dts b/arch/arm/boot/dts/omap3-sbc-t3730.dts
index 5bdddf2..73c7bf4 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3730.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3730.dts
@@ -27,8 +27,9 @@
 };
 
 &gpmc {
-	ranges = <5 0 0x2c000000 0x01000000>,
-		 <4 0 0x2d000000 0x01000000>;
+	ranges = <5 0 0x2c000000 0x01000000>,	/* CM-T3x30 SMSC9x Eth */
+		 <4 0 0x2d000000 0x01000000>,	/* SB-T35 SMSC9x Eth */
+		 <0 0 0x00000000 0x01000000>;	/* CM-T3x NAND */
 };
 
 &dss {
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index b396c83..e641001 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -1,4 +1,5 @@
 #include "qcom-apq8064-v2.0.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "Qualcomm APQ8064/IFC6410";
@@ -12,6 +13,14 @@
 					function = "gsbi1";
 				};
 			};
+
+			card_detect: card_detect {
+				mux {
+					pins = "gpio26";
+					function = "gpio";
+					bias-disable;
+				};
+			};
 		};
 
 		gsbi@12440000 {
@@ -49,6 +58,9 @@
 			/* External micro SD card */
 			sdcc3: sdcc@12180000 {
 				status = "okay";
+				pinctrl-names	= "default";
+				pinctrl-0	= <&card_detect>;
+				cd-gpios	= <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
 			};
 			/* WLAN */
 			sdcc4: sdcc@121c0000 {
diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
index 63b2146..cb225da 100644
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -74,7 +74,7 @@
 			#gpio-cells = <2>;
 			interrupt-controller;
 			#interrupt-cells = <2>;
-			interrupts = <0 32 0x4>;
+			interrupts = <0 16 0x4>;
 		};
 
 		intc: interrupt-controller@2000000 {
diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index 1518c5b..a9da7a8 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -45,7 +45,7 @@
 };
 
 &mtu2 {
-	status = "ok";
+	status = "okay";
 };
 
 &i2c2 {
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
index 84e05f7..b3d8f84 100644
--- a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
+++ b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
@@ -67,7 +67,7 @@
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
-		ranges = <0 0 0 0x80000000>;
+		ranges = <0 0 0 0x20000000>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
index ce085fa..0d50bef 100644
--- a/arch/arm/boot/dts/r8a73a4-ape6evm.dts
+++ b/arch/arm/boot/dts/r8a73a4-ape6evm.dts
@@ -10,14 +10,20 @@
 
 /dts-v1/;
 #include "r8a73a4.dtsi"
-#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
 
 / {
 	model = "APE6EVM";
 	compatible = "renesas,ape6evm", "renesas,r8a73a4";
 
+	aliases {
+		serial0 = &scifa0;
+	};
+
 	chosen {
 		bootargs = "console=ttySC0,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
+		stdout-path = &scifa0;
 	};
 
 	memory@40000000 {
@@ -30,7 +36,35 @@
 		reg = <2 0x00000000 0 0x40000000>;
 	};
 
-	ape6evm_fixed_3v3: fixedregulator@0 {
+	vcc_mmc0: regulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "MMC0 Vcc";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-always-on;
+	};
+
+	vcc_sdhi0: regulator@1 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "SDHI0 Vcc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&pfc 76 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	/* Common 1.8V and 3.3V rails, used by several devices on APE6EVM */
+	ape6evm_fixed_1v8: regulator@2 {
+		compatible = "regulator-fixed";
+		regulator-name = "1V8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	ape6evm_fixed_3v3: regulator@3 {
 		compatible = "regulator-fixed";
 		regulator-name = "3V3";
 		regulator-min-microvolt = <3300000>;
@@ -39,11 +73,13 @@
 	};
 
 	lbsc {
+		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
+		ranges = <0 0 0 0x20000000>;
 
 		ethernet@8000000 {
-			compatible = "smsc,lan9118", "smsc,lan9115";
+			compatible = "smsc,lan9220", "smsc,lan9115";
 			reg = <0x08000000 0x1000>;
 			interrupt-parent = <&irqc1>;
 			interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
@@ -52,7 +88,75 @@
 			smsc,irq-active-high;
 			smsc,irq-push-pull;
 			vdd33a-supply = <&ape6evm_fixed_3v3>;
-			vddvario-supply = <&ape6evm_fixed_3v3>;
+			vddvario-supply = <&ape6evm_fixed_1v8>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		led1 {
+			gpios = <&pfc 28 GPIO_ACTIVE_LOW>;
+			label = "GNSS_EN";
+		};
+		led2 {
+			gpios = <&pfc 126 GPIO_ACTIVE_LOW>;
+			label = "NFC_NRST";
+		};
+		led3 {
+			gpios = <&pfc 132 GPIO_ACTIVE_LOW>;
+			label = "GNSS_NRST";
+		};
+		led4 {
+			gpios = <&pfc 232 GPIO_ACTIVE_LOW>;
+			label = "BT_WAKEUP";
+		};
+		led5 {
+			gpios = <&pfc 250 GPIO_ACTIVE_LOW>;
+			label = "STROBE";
+		};
+		led6 {
+			gpios = <&pfc 288 GPIO_ACTIVE_LOW>;
+			label = "BBRESETOUT";
+		};
+	};
+
+	keyboard {
+		compatible = "gpio-keys";
+
+		zero-key {
+			gpios = <&pfc 324 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_0>;
+			label = "S16";
+		};
+
+		menu-key {
+			gpios = <&pfc 325 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_MENU>;
+			label = "S17";
+		};
+
+		home-key {
+			gpios = <&pfc 326 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_HOME>;
+			label = "S18";
+		};
+
+		back-key {
+			gpios = <&pfc 327 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_BACK>;
+			label = "S19";
+		};
+
+		volup-key {
+			gpios = <&pfc 328 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_VOLUMEUP>;
+			label = "S20";
+		};
+
+		voldown-key {
+			gpios = <&pfc 329 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_VOLUMEDOWN>;
+			label = "S21";
 		};
 	};
 };
@@ -79,3 +183,64 @@
 	>;
 	voltage-tolerance = <1>; /* 1% */
 };
+
+&cmt1 {
+	status = "okay";
+};
+
+&pfc {
+	scifa0_pins: serial0 {
+		renesas,groups = "scifa0_data";
+		renesas,function = "scifa0";
+	};
+
+	mmc0_pins: mmc {
+		renesas,groups = "mmc0_data8", "mmc0_ctrl";
+		renesas,function = "mmc0";
+	};
+
+	sdhi0_pins: sd0 {
+		renesas,groups = "sdhi0_data4", "sdhi0_ctrl", "sdhi0_cd";
+		renesas,function = "sdhi0";
+	};
+
+	sdhi1_pins: sd1 {
+		renesas,groups = "sdhi1_data4", "sdhi1_ctrl";
+		renesas,function = "sdhi1";
+	};
+};
+
+&mmcif0 {
+	vmmc-supply = <&vcc_mmc0>;
+	bus-width = <8>;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins>;
+	status = "okay";
+};
+
+&scifa0 {
+	pinctrl-0 = <&scifa0_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+};
+
+&sdhi0 {
+	vmmc-supply = <&vcc_sdhi0>;
+	bus-width = <4>;
+	toshiba,mmc-wrprotect-disable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdhi0_pins>;
+	status = "okay";
+};
+
+&sdhi1 {
+	vmmc-supply = <&ape6evm_fixed_3v3>;
+	bus-width = <4>;
+	broken-cd;
+	toshiba,mmc-wrprotect-disable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdhi1_pins>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi
index 5ac57ba..38136d9 100644
--- a/arch/arm/boot/dts/r8a73a4.dtsi
+++ b/arch/arm/boot/dts/r8a73a4.dtsi
@@ -38,6 +38,16 @@
 			     <1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
 	};
 
+	dbsc1: memory-controller@e6790000 {
+		compatible = "renesas,dbsc-r8a73a4";
+		reg = <0 0xe6790000 0 0x10000>;
+	};
+
+	dbsc2: memory-controller@e67a0000 {
+		compatible = "renesas,dbsc-r8a73a4";
+		reg = <0 0xe67a0000 0 0x10000>;
+	};
+
 	dmac: dma-multiplexer {
 		compatible = "renesas,shdma-mux";
 		#dma-cells = <1>;
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index d4af4d8..9bd0cb4 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -172,7 +172,7 @@
 	pinctrl-names = "default";
 
 	phy-handle = <&phy0>;
-	status = "ok";
+	status = "okay";
 
 	phy0: ethernet-phy@0 {
 		reg = <0>;
@@ -193,7 +193,7 @@
 };
 
 &cmt1 {
-	status = "ok";
+	status = "okay";
 };
 
 &i2c0 {
diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
index a8a674b..8a09260 100644
--- a/arch/arm/boot/dts/r8a7740.dtsi
+++ b/arch/arm/boot/dts/r8a7740.dtsi
@@ -25,6 +25,7 @@
 			device_type = "cpu";
 			reg = <0x0>;
 			clock-frequency = <800000000>;
+			power-domains = <&pd_a3sm>;
 		};
 	};
 
@@ -36,17 +37,29 @@
 		      <0xc2000000 0x1000>;
 	};
 
+	dbsc3: memory-controller@fe400000 {
+		compatible = "renesas,dbsc3-r8a7740";
+		reg = <0xfe400000 0x400>;
+		power-domains = <&pd_a4s>;
+	};
+
 	pmu {
 		compatible = "arm,cortex-a9-pmu";
 		interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
+	ptm {
+		compatible = "arm,coresight-etm3x";
+		power-domains = <&pd_d4>;
+	};
+
 	cmt1: timer@e6138000 {
 		compatible = "renesas,cmt-48-r8a7740", "renesas,cmt-48";
 		reg = <0xe6138000 0x170>;
 		interrupts = <0 58 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_CMT1>;
 		clock-names = "fck";
+		power-domains = <&pd_c5>;
 
 		renesas,channels-mask = <0x3f>;
 
@@ -72,6 +85,7 @@
 			      0 149 IRQ_TYPE_LEVEL_HIGH
 			      0 149 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
+		power-domains = <&pd_a4s>;
 	};
 
 	/* irqpin1: IRQ8 - IRQ15 */
@@ -93,6 +107,7 @@
 			      0 149 IRQ_TYPE_LEVEL_HIGH
 			      0 149 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
+		power-domains = <&pd_a4s>;
 	};
 
 	/* irqpin2: IRQ16 - IRQ23 */
@@ -114,6 +129,7 @@
 			      0 149 IRQ_TYPE_LEVEL_HIGH
 			      0 149 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
+		power-domains = <&pd_a4s>;
 	};
 
 	/* irqpin3: IRQ24 - IRQ31 */
@@ -135,6 +151,7 @@
 			      0 149 IRQ_TYPE_LEVEL_HIGH
 			      0 149 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
+		power-domains = <&pd_a4s>;
 	};
 
 	ether: ethernet@e9a00000 {
@@ -143,6 +160,7 @@
 		      <0xe9a01800 0x800>;
 		interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_GETHER>;
+		power-domains = <&pd_a4s>;
 		phy-mode = "mii";
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -159,6 +177,7 @@
 			      0 203 IRQ_TYPE_LEVEL_HIGH
 			      0 204 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp1_clks R8A7740_CLK_IIC0>;
+		power-domains = <&pd_a4r>;
 		status = "disabled";
 	};
 
@@ -172,6 +191,7 @@
 			      0 72 IRQ_TYPE_LEVEL_HIGH
 			      0 73 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_IIC1>;
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -181,6 +201,7 @@
 		interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA0>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -190,6 +211,7 @@
 		interrupts = <0 101 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA1>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -199,6 +221,7 @@
 		interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA2>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -208,6 +231,7 @@
 		interrupts = <0 103 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA3>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -217,6 +241,7 @@
 		interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA4>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -226,6 +251,7 @@
 		interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA5>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -235,6 +261,7 @@
 		interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA6>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -244,6 +271,7 @@
 		interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFA7>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -253,6 +281,7 @@
 		interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp2_clks R8A7740_CLK_SCIFB>;
 		clock-names = "sci_ick";
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -271,12 +300,14 @@
 			<&irqpin2 4 0>, <&irqpin2 5 0>, <&irqpin2 6 0>, <&irqpin2 7 0>,
 			<&irqpin3 0 0>, <&irqpin3 1 0>, <&irqpin3 2 0>, <&irqpin3 3 0>,
 			<&irqpin3 4 0>, <&irqpin3 5 0>, <&irqpin3 6 0>, <&irqpin3 7 0>;
+		power-domains = <&pd_c5>;
 	};
 
 	tpu: pwm@e6600000 {
 		compatible = "renesas,tpu-r8a7740", "renesas,tpu";
 		reg = <0xe6600000 0x100>;
 		clocks = <&mstp3_clks R8A7740_CLK_TPU0>;
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 		#pwm-cells = <3>;
 	};
@@ -287,6 +318,7 @@
 		interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH
 			      0 57 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_MMC>;
+		power-domains = <&pd_a3sp>;
 		status = "disabled";
 	};
 
@@ -297,6 +329,7 @@
 			      0 118 IRQ_TYPE_LEVEL_HIGH
 			      0 119 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_SDHI0>;
+		power-domains = <&pd_a3sp>;
 		cap-sd-highspeed;
 		cap-sdio-irq;
 		status = "disabled";
@@ -309,6 +342,7 @@
 			      0 122 IRQ_TYPE_LEVEL_HIGH
 			      0 123 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp3_clks R8A7740_CLK_SDHI1>;
+		power-domains = <&pd_a3sp>;
 		cap-sd-highspeed;
 		cap-sdio-irq;
 		status = "disabled";
@@ -321,6 +355,7 @@
 			      0 126 IRQ_TYPE_LEVEL_HIGH
 			      0 127 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp4_clks R8A7740_CLK_SDHI2>;
+		power-domains = <&pd_a3sp>;
 		cap-sd-highspeed;
 		cap-sdio-irq;
 		status = "disabled";
@@ -332,6 +367,7 @@
 		reg = <0xfe1f0000 0x400>;
 		interrupts = <0 9 0x4>;
 		clocks = <&mstp3_clks R8A7740_CLK_FSI>;
+		power-domains = <&pd_a4mp>;
 		status = "disabled";
 	};
 
@@ -343,6 +379,7 @@
 			     <0 200 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp1_clks R8A7740_CLK_TMU0>;
 		clock-names = "fck";
+		power-domains = <&pd_a4r>;
 
 		#renesas,channels = <3>;
 
@@ -357,6 +394,7 @@
 			     <0 172 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&mstp1_clks R8A7740_CLK_TMU1>;
 		clock-names = "fck";
+		power-domains = <&pd_a4r>;
 
 		#renesas,channels = <3>;
 
@@ -453,7 +491,7 @@
 			reg = <0xe6150080 4>;
 			clocks = <&sub_clk>, <&sub_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7740_CLK_SUBCK R8A7740_CLK_SUBCK2
 			>;
 			clock-output-names =
@@ -468,7 +506,7 @@
 				 <&cpg_clocks R8A7740_CLK_HPP>, <&sub_clk>,
 				 <&cpg_clocks R8A7740_CLK_B>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7740_CLK_CEU21 R8A7740_CLK_CEU20 R8A7740_CLK_TMU0
 				R8A7740_CLK_LCDC1 R8A7740_CLK_IIC0 R8A7740_CLK_TMU1
 				R8A7740_CLK_LCDC0
@@ -489,7 +527,7 @@
 				 <&sub_clk>, <&sub_clk>, <&sub_clk>,
 				 <&sub_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7740_CLK_SCIFA6 R8A7740_CLK_INTCA
 				R8A7740_CLK_SCIFA7
 				R8A7740_CLK_DMAC1 R8A7740_CLK_DMAC2
@@ -518,7 +556,7 @@
 				 <&cpg_clocks R8A7740_CLK_HP>,
 				 <&cpg_clocks R8A7740_CLK_HP>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7740_CLK_CMT1 R8A7740_CLK_FSI R8A7740_CLK_IIC1
 				R8A7740_CLK_USBF R8A7740_CLK_SDHI0 R8A7740_CLK_SDHI1
 				R8A7740_CLK_MMC R8A7740_CLK_GETHER R8A7740_CLK_TPU0
@@ -535,7 +573,7 @@
 				 <&cpg_clocks R8A7740_CLK_HP>,
 				 <&cpg_clocks R8A7740_CLK_HP>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7740_CLK_USBH R8A7740_CLK_SDHI2
 				R8A7740_CLK_USBFUNC R8A7740_CLK_USBPHY
 			>;
@@ -543,4 +581,71 @@
 				"usbhost", "sdhi2", "usbfunc", "usphy";
 		};
 	};
+
+	sysc: system-controller@e6180000 {
+		compatible = "renesas,sysc-r8a7740", "renesas,sysc-rmobile";
+		reg = <0xe6180000 0x8000>, <0xe6188000 0x8000>;
+
+		pm-domains {
+			pd_c5: c5 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				#power-domain-cells = <0>;
+
+				pd_a4lc: a4lc@1 {
+					reg = <1>;
+					#power-domain-cells = <0>;
+				};
+
+				pd_a4mp: a4mp@2 {
+					reg = <2>;
+					#power-domain-cells = <0>;
+				};
+
+				pd_d4: d4@3 {
+					reg = <3>;
+					#power-domain-cells = <0>;
+				};
+
+				pd_a4r: a4r@5 {
+					reg = <5>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+					#power-domain-cells = <0>;
+
+					pd_a3rv: a3rv@6 {
+						reg = <6>;
+						#power-domain-cells = <0>;
+					};
+				};
+
+				pd_a4s: a4s@10 {
+					reg = <10>;
+					#address-cells = <1>;
+					#size-cells = <0>;
+					#power-domain-cells = <0>;
+
+					pd_a3sp: a3sp@11 {
+						reg = <11>;
+						#power-domain-cells = <0>;
+					};
+
+					pd_a3sm: a3sm@12 {
+						reg = <12>;
+						#power-domain-cells = <0>;
+					};
+
+					pd_a3sg: a3sg@13 {
+						reg = <13>;
+						#power-domain-cells = <0>;
+					};
+				};
+
+				pd_a4su: a4su@20 {
+					reg = <20>;
+					#power-domain-cells = <0>;
+				};
+			};
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi
index ede9a29..5c2219b 100644
--- a/arch/arm/boot/dts/r8a7779.dtsi
+++ b/arch/arm/boot/dts/r8a7779.dtsi
@@ -12,6 +12,7 @@
 /include/ "skeleton.dtsi"
 
 #include <dt-bindings/clock/r8a7779-clock.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
@@ -62,6 +63,14 @@
 		      <0xf0000100 0x100>;
 	};
 
+	timer@f0000600 {
+		compatible = "arm,cortex-a9-twd-timer";
+		reg = <0xf0000600 0x20>;
+		interrupts = <GIC_PPI 13
+			(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		clocks = <&cpg_clocks R8A7779_CLK_ZS>;
+	};
+
 	gpio0: gpio@ffc40000 {
 		compatible = "renesas,gpio-r8a7779", "renesas,gpio-rcar";
 		reg = <0xffc40000 0x2c>;
@@ -200,7 +209,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe40000 0x100>;
 		interrupts = <0 88 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF0>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -209,7 +218,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe41000 0x100>;
 		interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF1>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -218,7 +227,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe42000 0x100>;
 		interrupts = <0 90 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF2>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -227,7 +236,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe43000 0x100>;
 		interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF3>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -236,7 +245,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe44000 0x100>;
 		interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF4>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -245,7 +254,7 @@
 		compatible = "renesas,scif-r8a7779", "renesas,scif";
 		reg = <0xffe45000 0x100>;
 		interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cpg_clocks R8A7779_CLK_P>;
+		clocks = <&mstp0_clks R8A7779_CLK_SCIF5>;
 		clock-names = "sci_ick";
 		status = "disabled";
 	};
@@ -464,18 +473,18 @@
 				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_S>,
 				 <&cpg_clocks R8A7779_CLK_S>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
-				 <&cpg_clocks R8A7779_CLK_S1>,
+				 <&cpg_clocks R8A7779_CLK_P>,
+				 <&cpg_clocks R8A7779_CLK_P>,
+				 <&cpg_clocks R8A7779_CLK_P>,
+				 <&cpg_clocks R8A7779_CLK_P>,
+				 <&cpg_clocks R8A7779_CLK_P>,
+				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_P>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7779_CLK_HSPI R8A7779_CLK_TMU2
 				R8A7779_CLK_TMU1 R8A7779_CLK_TMU0
 				R8A7779_CLK_HSCIF1 R8A7779_CLK_HSCIF0
@@ -506,7 +515,7 @@
 				 <&cpg_clocks R8A7779_CLK_P>,
 				 <&cpg_clocks R8A7779_CLK_S>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7779_CLK_USB01 R8A7779_CLK_USB2
 				R8A7779_CLK_DU R8A7779_CLK_VIN2
 				R8A7779_CLK_VIN1 R8A7779_CLK_VIN0
@@ -527,7 +536,7 @@
 			clocks = <&s4_clk>, <&s4_clk>, <&s4_clk>, <&s4_clk>,
 				 <&s4_clk>, <&s4_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7779_CLK_SDHI3 R8A7779_CLK_SDHI2
 				R8A7779_CLK_SDHI1 R8A7779_CLK_SDHI0
 				R8A7779_CLK_MMC1 R8A7779_CLK_MMC0
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index 636d53b..0c3b678 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -47,12 +47,12 @@
 	compatible = "renesas,lager", "renesas,r8a7790";
 
 	aliases {
-		serial6 = &scifa0;
-		serial7 = &scifa1;
+		serial0 = &scifa0;
+		serial1 = &scifa1;
 	};
 
 	chosen {
-		bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+		bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
 		stdout-path = &scifa0;
 	};
 
@@ -355,7 +355,7 @@
 
 	phy-handle = <&phy1>;
 	renesas,ether-link-active-low;
-	status = "ok";
+	status = "okay";
 
 	phy1: ethernet-phy@1 {
 		reg = <1>;
@@ -366,7 +366,7 @@
 };
 
 &cmt0 {
-	status = "ok";
+	status = "okay";
 };
 
 &mmcif1 {
@@ -397,6 +397,8 @@
 		spi-max-frequency = <30000000>;
 		spi-tx-bus-width = <4>;
 		spi-rx-bus-width = <4>;
+		spi-cpha;
+		spi-cpol;
 		m25p,fast-read;
 
 		partition@0 {
@@ -470,17 +472,17 @@
 };
 
 &iic0	{
-	status = "ok";
+	status = "okay";
 };
 
 &iic1	{
-	status = "ok";
+	status = "okay";
 	pinctrl-0 = <&iic1_pins>;
 	pinctrl-names = "default";
 };
 
 &iic2	{
-	status = "ok";
+	status = "okay";
 	pinctrl-0 = <&iic2_pins>;
 	pinctrl-names = "default";
 
@@ -562,7 +564,7 @@
 	pinctrl-0 = <&vin1_pins>;
 	pinctrl-names = "default";
 
-	status = "ok";
+	status = "okay";
 
 	port {
 		#address-cells = <1>;
@@ -579,6 +581,7 @@
 	pinctrl-0 = <&sound_pins &sound_clk_pins>;
 	pinctrl-names = "default";
 
+	/* Single DAI */
 	#sound-dai-cells = <0>;
 
 	status = "okay";
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index af7e255..4b38fc9 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -1054,7 +1054,7 @@
 			reg = <0 0xe6150130 0 4>, <0 0xe6150030 0 4>;
 			clocks = <&mp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <R8A7790_CLK_MSIOF0>;
+			clock-indices = <R8A7790_CLK_MSIOF0>;
 			clock-output-names = "msiof0";
 		};
 		mstp1_clks: mstp1_clks@e6150134 {
@@ -1065,7 +1065,7 @@
 				 <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>,
 				 <&cp_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7790_CLK_VCP1 R8A7790_CLK_VCP0 R8A7790_CLK_VPC1
 				R8A7790_CLK_VPC0 R8A7790_CLK_JPU R8A7790_CLK_SSP1
 				R8A7790_CLK_TMU1 R8A7790_CLK_3DG R8A7790_CLK_2DDMAC
@@ -1087,7 +1087,7 @@
 				 <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>, <&zs_clk>,
 				 <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7790_CLK_SCIFA2 R8A7790_CLK_SCIFA1 R8A7790_CLK_SCIFA0
 				R8A7790_CLK_MSIOF2 R8A7790_CLK_SCIFB0 R8A7790_CLK_SCIFB1
 				R8A7790_CLK_MSIOF1 R8A7790_CLK_MSIOF3 R8A7790_CLK_SCIFB2
@@ -1106,7 +1106,7 @@
 				 <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>,
 				 <&hp_clk>, <&hp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7790_CLK_IIC2 R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
 				R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 R8A7790_CLK_MMCIF0
 				R8A7790_CLK_IIC0 R8A7790_CLK_PCIEC R8A7790_CLK_IIC1 R8A7790_CLK_SSUSB R8A7790_CLK_CMT1
@@ -1123,8 +1123,10 @@
 			reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
 			clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <R8A7790_CLK_AUDIO_DMAC0 R8A7790_CLK_AUDIO_DMAC1
-						 R8A7790_CLK_THERMAL R8A7790_CLK_PWM>;
+			clock-indices = <
+				R8A7790_CLK_AUDIO_DMAC0 R8A7790_CLK_AUDIO_DMAC1
+				R8A7790_CLK_THERMAL R8A7790_CLK_PWM
+			>;
 			clock-output-names = "audmac0", "audmac1", "thermal", "pwm";
 		};
 		mstp7_clks: mstp7_clks@e615014c {
@@ -1134,7 +1136,7 @@
 				 <&p_clk>, <&zx_clk>, <&zx_clk>, <&zx_clk>, <&zx_clk>,
 				 <&zx_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7790_CLK_EHCI R8A7790_CLK_HSUSB R8A7790_CLK_HSCIF1
 				R8A7790_CLK_HSCIF0 R8A7790_CLK_SCIF1 R8A7790_CLK_SCIF0
 				R8A7790_CLK_DU2 R8A7790_CLK_DU1 R8A7790_CLK_DU0
@@ -1147,16 +1149,17 @@
 		mstp8_clks: mstp8_clks@e6150990 {
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
-			clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>,
-				 <&zs_clk>, <&zs_clk>;
+			clocks = <&hp_clk>, <&zg_clk>, <&zg_clk>, <&zg_clk>,
+			         <&zg_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
-				R8A7790_CLK_VIN3 R8A7790_CLK_VIN2 R8A7790_CLK_VIN1
-				R8A7790_CLK_VIN0 R8A7790_CLK_ETHER R8A7790_CLK_SATA1
-				R8A7790_CLK_SATA0
+			clock-indices = <
+				R8A7790_CLK_MLB R8A7790_CLK_VIN3 R8A7790_CLK_VIN2
+				R8A7790_CLK_VIN1 R8A7790_CLK_VIN0 R8A7790_CLK_ETHER
+				R8A7790_CLK_SATA1 R8A7790_CLK_SATA0
 			>;
 			clock-output-names =
-				"vin3", "vin2", "vin1", "vin0", "ether", "sata1", "sata0";
+				"mlb", "vin3", "vin2", "vin1", "vin0", "ether",
+				"sata1", "sata0";
 		};
 		mstp9_clks: mstp9_clks@e6150994 {
 			compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1166,7 +1169,7 @@
 				 <&p_clk>, <&p_clk>, <&cpg_clocks R8A7790_CLK_QSPI>, <&cp_clk>,
 				 <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7790_CLK_GPIO5 R8A7790_CLK_GPIO4 R8A7790_CLK_GPIO3
 				R8A7790_CLK_GPIO2 R8A7790_CLK_GPIO1 R8A7790_CLK_GPIO0
 				R8A7790_CLK_RCAN1 R8A7790_CLK_RCAN0 R8A7790_CLK_QSPI_MOD R8A7790_CLK_IICDVFS
@@ -1397,8 +1400,13 @@
 	};
 
 	rcar_sound: rcar_sound@ec500000 {
-		#sound-dai-cells = <1>;
-		compatible =  "renesas,rcar_sound-r8a7790", "renesas,rcar_sound-gen2", "renesas,rcar_sound";
+		/*
+		 * #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 */
@@ -1432,16 +1440,16 @@
 		};
 
 		rcar_sound,src {
-			src0: src@0 { };
-			src1: src@1 { };
-			src2: src@2 { };
-			src3: src@3 { };
-			src4: src@4 { };
-			src5: src@5 { };
-			src6: src@6 { };
-			src7: src@7 { };
-			src8: src@8 { };
-			src9: src@9 { };
+			src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; };
+			src1: src@1 { interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; };
+			src2: src@2 { interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; };
+			src3: src@3 { interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; };
+			src4: src@4 { interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; };
+			src5: src@5 { interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; };
+			src6: src@6 { interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; };
+			src7: src@7 { interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; };
+			src8: src@8 { interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; };
+			src9: src@9 { interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; };
 		};
 
 		rcar_sound,ssi {
diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts
index 740e386..d2ebf11 100644
--- a/arch/arm/boot/dts/r8a7791-henninger.dts
+++ b/arch/arm/boot/dts/r8a7791-henninger.dts
@@ -156,7 +156,7 @@
 
 	phy-handle = <&phy1>;
 	renesas,ether-link-active-low;
-	status = "ok";
+	status = "okay";
 
 	phy1: ethernet-phy@1 {
 		reg = <1>;
@@ -293,7 +293,7 @@
 
 /* composite video input */
 &vin0 {
-	status = "ok";
+	status = "okay";
 	pinctrl-0 = <&vin0_pins>;
 	pinctrl-names = "default";
 
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index 990af16..a3c2780 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -48,8 +48,8 @@
 	compatible = "renesas,koelsch", "renesas,r8a7791";
 
 	aliases {
-		serial6 = &scif0;
-		serial7 = &scif1;
+		serial0 = &scif0;
+		serial1 = &scif1;
 	};
 
 	chosen {
@@ -366,7 +366,7 @@
 
 	phy-handle = <&phy1>;
 	renesas,ether-link-active-low;
-	status = "ok";
+	status = "okay";
 
 	phy1: ethernet-phy@1 {
 		reg = <1>;
@@ -377,7 +377,7 @@
 };
 
 &cmt0 {
-	status = "ok";
+	status = "okay";
 };
 
 &sata0 {
@@ -444,6 +444,8 @@
 		spi-max-frequency = <30000000>;
 		spi-tx-bus-width = <4>;
 		spi-rx-bus-width = <4>;
+		spi-cpha;
+		spi-cpol;
 		m25p,fast-read;
 
 		partition@0 {
@@ -452,13 +454,13 @@
 			read-only;
 		};
 		partition@80000 {
-			label = "bootenv";
-			reg = <0x00080000 0x00080000>;
+			label = "user";
+			reg = <0x00080000 0x00580000>;
 			read-only;
 		};
-		partition@100000 {
-			label = "data";
-			reg = <0x00100000 0x03f00000>;
+		partition@600000 {
+			label = "flash";
+			reg = <0x00600000 0x03a00000>;
 		};
 	};
 };
@@ -563,7 +565,7 @@
 
 /* composite video input */
 &vin1 {
-	status = "ok";
+	status = "okay";
 	pinctrl-0 = <&vin1_pins>;
 	pinctrl-names = "default";
 
@@ -582,6 +584,7 @@
 	pinctrl-0 = <&sound_pins &sound_clk_pins>;
 	pinctrl-names = "default";
 
+	/* Single DAI */
 	#sound-dai-cells = <0>;
 
 	status = "okay";
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 77c0bee..e35812a 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -78,7 +78,7 @@
 			<0 0xf1002000 0 0x1000>,
 			<0 0xf1004000 0 0x2000>,
 			<0 0xf1006000 0 0x2000>;
-		interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
 	};
 
 	gpio0: gpio@e6050000 {
@@ -186,10 +186,10 @@
 
 	timer {
 		compatible = "arm,armv7-timer";
-		interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+		interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
 	};
 
 	cmt0: timer@ffca0000 {
@@ -1062,7 +1062,7 @@
 			reg = <0 0xe6150130 0 4>, <0 0xe6150030 0 4>;
 			clocks = <&mp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <R8A7791_CLK_MSIOF0>;
+			clock-indices = <R8A7791_CLK_MSIOF0>;
 			clock-output-names = "msiof0";
 		};
 		mstp1_clks: mstp1_clks@e6150134 {
@@ -1073,7 +1073,7 @@
 				 <&p_clk>, <&rclk_clk>, <&cp_clk>, <&zs_clk>, <&zs_clk>,
 				 <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_VCP0 R8A7791_CLK_VPC0 R8A7791_CLK_JPU
 				R8A7791_CLK_SSP1 R8A7791_CLK_TMU1 R8A7791_CLK_3DG
 				R8A7791_CLK_2DDMAC R8A7791_CLK_FDP1_1 R8A7791_CLK_FDP1_0
@@ -1093,7 +1093,7 @@
 				 <&mp_clk>, <&mp_clk>, <&mp_clk>,
 				 <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_SCIFA2 R8A7791_CLK_SCIFA1 R8A7791_CLK_SCIFA0
 				R8A7791_CLK_MSIOF2 R8A7791_CLK_SCIFB0 R8A7791_CLK_SCIFB1
 				R8A7791_CLK_MSIOF1 R8A7791_CLK_SCIFB2
@@ -1111,7 +1111,7 @@
 				 <&mmc0_clk>, <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>,
 				 <&hp_clk>, <&hp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 R8A7791_CLK_SDHI0
 				R8A7791_CLK_MMCIF0 R8A7791_CLK_IIC0 R8A7791_CLK_PCIEC R8A7791_CLK_IIC1
 				R8A7791_CLK_SSUSB R8A7791_CLK_CMT1
@@ -1127,8 +1127,10 @@
 			reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
 			clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <R8A7791_CLK_AUDIO_DMAC0 R8A7791_CLK_AUDIO_DMAC1
-						 R8A7791_CLK_THERMAL R8A7791_CLK_PWM>;
+			clock-indices = <
+				R8A7791_CLK_AUDIO_DMAC0 R8A7791_CLK_AUDIO_DMAC1
+				R8A7791_CLK_THERMAL R8A7791_CLK_PWM
+			>;
 			clock-output-names = "audmac0", "audmac1", "thermal", "pwm";
 		};
 		mstp7_clks: mstp7_clks@e615014c {
@@ -1138,7 +1140,7 @@
 				 <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>,
 				 <&zx_clk>, <&zx_clk>, <&zx_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_EHCI R8A7791_CLK_HSUSB R8A7791_CLK_HSCIF2 R8A7791_CLK_SCIF5
 				R8A7791_CLK_SCIF4 R8A7791_CLK_HSCIF1 R8A7791_CLK_HSCIF0
 				R8A7791_CLK_SCIF3 R8A7791_CLK_SCIF2 R8A7791_CLK_SCIF1
@@ -1152,15 +1154,17 @@
 		mstp8_clks: mstp8_clks@e6150990 {
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
-			clocks = <&zg_clk>, <&zg_clk>, <&zg_clk>, <&p_clk>, <&zs_clk>,
-				 <&zs_clk>;
+			clocks = <&zg_clk>, <&hp_clk>, <&zg_clk>, <&zg_clk>,
+			         <&zg_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
+				R8A7791_CLK_IPMMU_SGX R8A7791_CLK_MLB
 				R8A7791_CLK_VIN2 R8A7791_CLK_VIN1 R8A7791_CLK_VIN0
 				R8A7791_CLK_ETHER R8A7791_CLK_SATA1 R8A7791_CLK_SATA0
 			>;
 			clock-output-names =
-				"vin2", "vin1", "vin0", "ether", "sata1", "sata0";
+				"ipmmu_sgx", "mlb", "vin2", "vin1", "vin0", "ether",
+				"sata1", "sata0";
 		};
 		mstp9_clks: mstp9_clks@e6150994 {
 			compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1171,7 +1175,7 @@
 				 <&cp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>,
 				 <&hp_clk>, <&hp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_GPIO7 R8A7791_CLK_GPIO6 R8A7791_CLK_GPIO5 R8A7791_CLK_GPIO4
 				R8A7791_CLK_GPIO3 R8A7791_CLK_GPIO2 R8A7791_CLK_GPIO1 R8A7791_CLK_GPIO0
 				R8A7791_CLK_RCAN1 R8A7791_CLK_RCAN0 R8A7791_CLK_QSPI_MOD R8A7791_CLK_I2C5
@@ -1221,7 +1225,7 @@
 			reg = <0 0xe615099c 0 4>, <0 0xe61509ac 0 4>;
 			clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7791_CLK_SCIFA3 R8A7791_CLK_SCIFA4 R8A7791_CLK_SCIFA5
 			>;
 			clock-output-names = "scifa3", "scifa4", "scifa5";
@@ -1381,8 +1385,13 @@
 	};
 
 	rcar_sound: rcar_sound@ec500000 {
-		#sound-dai-cells = <1>;
-		compatible =  "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2", "renesas,rcar_sound";
+		/*
+		 * #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 */
@@ -1416,16 +1425,16 @@
 		};
 
 		rcar_sound,src {
-			src0: src@0 { };
-			src1: src@1 { };
-			src2: src@2 { };
-			src3: src@3 { };
-			src4: src@4 { };
-			src5: src@5 { };
-			src6: src@6 { };
-			src7: src@7 { };
-			src8: src@8 { };
-			src9: src@9 { };
+			src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; };
+			src1: src@1 { interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; };
+			src2: src@2 { interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; };
+			src3: src@3 { interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; };
+			src4: src@4 { interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; };
+			src5: src@5 { interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; };
+			src6: src@6 { interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; };
+			src7: src@7 { interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; };
+			src8: src@8 { interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; };
+			src9: src@9 { interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; };
 		};
 
 		rcar_sound,ssi {
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index f2cf757..0d848e6 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -40,9 +40,9 @@
 };
 
 &cmt0 {
-	status = "ok";
+	status = "okay";
 };
 
 &scif2 {
-	status = "ok";
+	status = "okay";
 };
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 19c9de3..8f78da5 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -47,7 +47,7 @@
 			<0 0xf1002000 0 0x1000>,
 			<0 0xf1004000 0 0x2000>,
 			<0 0xf1006000 0 0x2000>;
-		interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
 	};
 
 	cmt0: timer@ffca0000 {
@@ -84,10 +84,10 @@
 
 	timer {
 		compatible = "arm,armv7-timer";
-		interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-			     <1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+		interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+			     <1 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
 	};
 
 	irqc0: interrupt-controller@e61c0000 {
@@ -293,6 +293,28 @@
 			clock-output-names = "main", "pll0", "pll1", "pll3",
 					     "lb", "qspi", "sdh", "sd0", "z";
 		};
+		/* Variable factor clocks */
+		sd1_clk: sd2_clk@e6150078 {
+			compatible = "renesas,r8a7794-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0 0xe6150078 0 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sd1";
+		};
+		sd2_clk: sd3_clk@e615007c {
+			compatible = "renesas,r8a7794-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0 0xe615007c 0 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sd2";
+		};
+		mmc0_clk: mmc0_clk@e6150240 {
+			compatible = "renesas,r8a7794-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0 0xe6150240 0 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "mmc0";
+		};
 
 		/* Fixed factor clocks */
 		pll1_div2_clk: pll1_div2_clk {
@@ -455,7 +477,7 @@
 			reg = <0 0xe6150130 0 4>, <0 0xe6150030 0 4>;
 			clocks = <&mp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <R8A7794_CLK_MSIOF0>;
+			clock-indices = <R8A7794_CLK_MSIOF0>;
 			clock-output-names = "msiof0";
 		};
 		mstp1_clks: mstp1_clks@e6150134 {
@@ -465,7 +487,7 @@
 				 <&zs_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>, <&cp_clk>,
 				 <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7794_CLK_VCP0 R8A7794_CLK_VPC0 R8A7794_CLK_TMU1
 				R8A7794_CLK_3DG R8A7794_CLK_2DDMAC R8A7794_CLK_FDP1_0
 				R8A7794_CLK_TMU3 R8A7794_CLK_TMU2 R8A7794_CLK_CMT0
@@ -479,41 +501,51 @@
 			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe6150138 0 4>, <0 0xe6150040 0 4>;
 			clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>,
-				 <&mp_clk>, <&mp_clk>, <&mp_clk>;
+				 <&mp_clk>, <&mp_clk>, <&mp_clk>,
+				 <&zs_clk>, <&zs_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7794_CLK_SCIFA2 R8A7794_CLK_SCIFA1 R8A7794_CLK_SCIFA0
 				R8A7794_CLK_MSIOF2 R8A7794_CLK_SCIFB0 R8A7794_CLK_SCIFB1
 				R8A7794_CLK_MSIOF1 R8A7794_CLK_SCIFB2
+				R8A7794_CLK_SYS_DMAC1 R8A7794_CLK_SYS_DMAC0
 			>;
 			clock-output-names =
 				"scifa2", "scifa1", "scifa0", "msiof2", "scifb0",
-				"scifb1", "msiof1", "scifb2";
+				"scifb1", "msiof1", "scifb2",
+				"sys-dmac1", "sys-dmac0";
 		};
 		mstp3_clks: mstp3_clks@e615013c {
 			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
-			clocks = <&rclk_clk>;
+			clocks = <&sd2_clk>, <&sd1_clk>, <&cpg_clocks R8A7794_CLK_SD0>,
+			         <&mmc0_clk>, <&rclk_clk>, <&hp_clk>, <&hp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
-				R8A7794_CLK_CMT1
+			clock-indices = <
+			        R8A7794_CLK_SDHI2 R8A7794_CLK_SDHI1 R8A7794_CLK_SDHI0
+				R8A7794_CLK_MMCIF0 R8A7794_CLK_CMT1
+				R8A7794_CLK_USBDMAC0 R8A7794_CLK_USBDMAC1
 			>;
 			clock-output-names =
-				"cmt1";
+			        "sdhi2", "sdhi1", "sdhi0",
+				"mmcif0", "cmt1", "usbdmac0", "usbdmac1";
 		};
 		mstp7_clks: mstp7_clks@e615014c {
 			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe615014c 0 4>, <0 0xe61501c4 0 4>;
-			clocks = <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
+			clocks = <&mp_clk>, <&mp_clk>,
+				 <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>,
 				 <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
+				R8A7794_CLK_EHCI R8A7794_CLK_HSUSB
 				R8A7794_CLK_HSCIF2 R8A7794_CLK_SCIF5
 				R8A7794_CLK_SCIF4 R8A7794_CLK_HSCIF1 R8A7794_CLK_HSCIF0
 				R8A7794_CLK_SCIF3 R8A7794_CLK_SCIF2 R8A7794_CLK_SCIF1
 				R8A7794_CLK_SCIF0
 			>;
 			clock-output-names =
+				"ehci", "hsusb",
 				"hscif2", "scif5", "scif4", "hscif1", "hscif0",
 				"scif3", "scif2", "scif1", "scif0";
 		};
@@ -522,18 +554,32 @@
 			reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
 			clocks = <&zg_clk>, <&zg_clk>, <&p_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7794_CLK_VIN1 R8A7794_CLK_VIN0 R8A7794_CLK_ETHER
 			>;
 			clock-output-names =
 				"vin1", "vin0", "ether";
 		};
+		mstp9_clks: mstp9_clks@e6150994 {
+			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
+			clocks = <&cpg_clocks R8A7794_CLK_QSPI>, <&hp_clk>, <&hp_clk>,
+				<&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
+			#clock-cells = <1>;
+			clock-indices = <
+				R8A7794_CLK_QSPI_MOD R8A7794_CLK_I2C5 R8A7794_CLK_I2C4
+				R8A7794_CLK_I2C3 R8A7794_CLK_I2C2 R8A7794_CLK_I2C1
+				R8A7794_CLK_I2C0
+			>;
+			clock-output-names =
+				"qspi_mod", "i2c5", "i2c4", "i2c3", "i2c2", "i2c1", "i2c0";
+		};
 		mstp11_clks: mstp11_clks@e615099c {
 			compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
 			reg = <0 0xe615099c 0 4>, <0 0xe61509ac 0 4>;
 			clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>;
 			#clock-cells = <1>;
-			renesas,clock-indices = <
+			clock-indices = <
 				R8A7794_CLK_SCIFA3 R8A7794_CLK_SCIFA4 R8A7794_CLK_SCIFA5
 			>;
 			clock-output-names = "scifa3", "scifa4", "scifa5";
diff --git a/arch/arm/boot/dts/rk3066a-rayeager.dts b/arch/arm/boot/dts/rk3066a-rayeager.dts
new file mode 100644
index 0000000..3ac1511
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a-rayeager.dts
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2014, 2015 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3066a.dtsi"
+
+/ {
+	model = "Rayeager PX2";
+	compatible = "chipspark,rayeager-px2", "rockchip,rk3066a";
+
+	memory {
+		reg = <0x60000000 0x40000000>;
+	};
+
+	ir: ir-receiver {
+		compatible = "gpio-ir-receiver";
+		gpios = <&gpio6 1 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ir_int>;
+	};
+
+	keys: gpio-keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@0 {
+			gpio-key,wakeup = <1>;
+			gpios = <&gpio6 2 GPIO_ACTIVE_LOW>;
+			label = "GPIO Power";
+			linux,code = <116>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwr_key>;
+		};
+	};
+
+	vsys: vsys-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vsys";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	/* input for 5V_STDBY is VSYS or DC5V, selectable by jumper J4 */
+	vcc_stdby: 5v-stdby-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "5v_stdby";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vcc_emmc: emmc-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "emmc_vccq";
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+		vin-supply = <&vsys>;
+	};
+
+	vcc_sata: sata-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sata_pwr>;
+		regulator-name = "usb_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&vcc_stdby>;
+	};
+
+	vcc_sd: sdmmc-regulator {
+		compatible = "regulator-fixed";
+		gpio = <&gpio3 7 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_pwr>;
+		regulator-name = "vcc_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		vin-supply = <&vcc_io>;
+	};
+
+	vcc_host: usb-host-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&host_drv>;
+		regulator-name = "host-pwr";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&vcc_stdby>;
+	};
+
+	vcc_otg: usb-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 5 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&otg_drv>;
+		regulator-name = "vcc_otg";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&vcc_stdby>;
+	};
+};
+
+&cpu0 {
+	cpu0-supply = <&vdd_arm>;
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&rmii_rst>;
+	phy = <&phy0>;
+	phy-supply = <&vcc_rmii>;
+	status = "okay";
+
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+};
+
+&emmc {
+	broken-cd;
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	disable-wp;
+	non-removable;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_rst>;
+	vmmc-supply = <&vcc_emmc>;
+	vqmmc-supply = <&vcc_emmc>;
+	status = "okay";
+};
+
+&i2c0 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	ak8963: ak8963@0d {
+		compatible = "asahi-kasei,ak8975";
+		reg = <0x0d>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <17 IRQ_TYPE_EDGE_RISING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&comp_int>;
+	};
+
+	mma8452: mma8452@1d {
+		compatible = "fsl,mma8452";
+		reg = <0x1d>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <16 IRQ_TYPE_EDGE_RISING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&gsensor_int>;
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	tps: tps@2d {
+		reg = <0x2d>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_int>, <&pwr_hold>;
+
+		vcc1-supply = <&vsys>;
+		vcc2-supply = <&vsys>;
+		vcc3-supply = <&vsys>;
+		vcc4-supply = <&vsys>;
+		vcc5-supply = <&vcc_io>;
+		vcc6-supply = <&vcc_io>;
+		vcc7-supply = <&vsys>;
+		vccio-supply = <&vsys>;
+
+		regulators {
+			vcc_rtc: regulator@0 {
+				regulator-name = "vcc_rtc";
+				regulator-always-on;
+			};
+
+			vcc_io: regulator@1 {
+				regulator-name = "vcc_io";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vdd_arm: regulator@2 {
+				regulator-name = "vdd_arm";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc_ddr: regulator@3 {
+				regulator-name = "vcc_ddr";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			vcc18: regulator@5 {
+				regulator-name = "vcc18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			vdd_11: regulator@6 {
+				regulator-name = "vdd_11";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+			};
+
+			vcc_25: regulator@7 {
+				regulator-name = "vcc_25";
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+				regulator-always-on;
+			};
+
+			vccio_wl: regulator@8 {
+				regulator-name = "vccio_wl";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			vcc25_hdmi: regulator@9 {
+				regulator-name = "vcc25_hdmi";
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+			};
+
+			vcca_33: regulator@10 {
+				regulator-name = "vcca_33";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vcc_rmii: regulator@11 {
+				regulator-name = "vcc_rmii";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vcc28_cif: regulator@12 {
+				regulator-name = "vcc28_cif";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+		};
+	};
+};
+
+#include "tps65910.dtsi"
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c3 {
+	status = "okay";
+};
+
+&i2c4 {
+	status = "okay";
+};
+
+&mmc0 {
+	bus-width = <4>;
+	disable-wp;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
+	vmmc-supply = <&vcc_sd>;
+	status = "okay";
+};
+
+&mmc1 {
+	broken-cd;
+	bus-width = <4>;
+	disable-wp;
+	non-removable;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd1_clk>, <&sd1_cmd>, <&sd1_bus4>;
+	vmmc-supply = <&vccio_wl>;
+	status = "okay";
+};
+
+&pinctrl {
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	ak8963 {
+		comp_int: comp-int {
+			rockchip,pins = <4 17 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	emac {
+		rmii_rst: rmii-rst {
+			rockchip,pins = <1 30 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	ir {
+		ir_int: ir-int {
+			rockchip,pins = <6 1 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	keys {
+		pwr_key: pwr-key {
+			rockchip,pins = <6 2 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	mma8452 {
+		gsensor_int: gsensor-int {
+			rockchip,pins = <4 16 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	mmc {
+		sdmmc_pwr: sdmmc-pwr {
+			rockchip,pins = <3 7 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	usb_host {
+		host_drv: host-drv {
+			rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+
+		hub_rst: hub-rst {
+			rockchip,pins = <1 31 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+
+		sata_pwr: sata-pwr {
+			rockchip,pins = <4 22 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+
+		sata_reset: sata-reset {
+			rockchip,pins = <0 13 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	usb_otg {
+		otg_drv: otg-drv {
+			rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+	};
+
+	tps {
+		pmic_int: pmic-int {
+			rockchip,pins = <6 4 RK_FUNC_GPIO &pcfg_pull_default>;
+		};
+
+		pwr_hold: pwr-hold {
+			rockchip,pins = <6 8 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+};
+
+&pwm1 {
+	status = "okay";
+};
+
+&pwm2 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcc_25>;
+	status = "okay";
+};
+
+&spi0 {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>;
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_xfer>, <&uart3_cts>, <&uart3_rts>;
+	status = "okay";
+};
+
+&usb_host {
+	pinctrl-names = "default";
+	pinctrl-0 = <&hub_rst>, <&sata_reset>;
+	status = "okay";
+};
+
+&usb_otg {
+	status = "okay";
+};
+
+&wdt {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rk3288-evb-act8846.dts
index a76dd44..d7b8bbc 100644
--- a/arch/arm/boot/dts/rk3288-evb-act8846.dts
+++ b/arch/arm/boot/dts/rk3288-evb-act8846.dts
@@ -17,7 +17,34 @@
 	compatible = "rockchip,rk3288-evb-act8846", "rockchip,rk3288";
 };
 
+&cpu0 {
+	cpu0-supply = <&vdd_cpu>;
+};
+
 &i2c0 {
+	clock-frequency = <400000>;
+
+	vdd_cpu: syr827@40 {
+		compatible = "silergy,syr827";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x40>;
+		regulator-name = "vdd_cpu";
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vdd_gpu: syr828@41 {
+		compatible = "silergy,syr828";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x41>;
+		regulator-name = "vdd_gpu";
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+	};
+
 	hym8563@51 {
 		compatible = "haoyu,hym8563";
 		reg = <0x51>;
diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index e1d3eeb..a1c294b 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -30,7 +30,6 @@
 
 &i2c0 {
 	clock-frequency = <400000>;
-	status = "okay";
 
 	rk808: pmic@1b {
 		compatible = "rockchip,rk808";
@@ -38,7 +37,7 @@
 		interrupt-parent = <&gpio0>;
 		interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
 		pinctrl-names = "default";
-		pinctrl-0 = <&pmic_int>;
+		pinctrl-0 = <&pmic_int &global_pwroff>;
 		rockchip,system-power-controller;
 		wakeup-source;
 		#clock-cells = <1>;
@@ -57,6 +56,9 @@
 				regulator-min-microvolt = <750000>;
 				regulator-max-microvolt = <1350000>;
 				regulator-name = "vdd_arm";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			vdd_gpu: DCDC_REG2 {
@@ -65,12 +67,19 @@
 				regulator-min-microvolt = <850000>;
 				regulator-max-microvolt = <1250000>;
 				regulator-name = "vdd_gpu";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1000000>;
+				};
 			};
 
 			vcc_ddr: DCDC_REG3 {
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-name = "vcc_ddr";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			vcc_io: DCDC_REG4 {
@@ -79,6 +88,10 @@
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-name = "vcc_io";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
 			};
 
 			vccio_pmu: LDO_REG1 {
@@ -87,6 +100,10 @@
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-name = "vccio_pmu";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
 			};
 
 			vcc_tp: LDO_REG2 {
@@ -95,6 +112,9 @@
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-name = "vcc_tp";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
 			};
 
 			vdd_10: LDO_REG3 {
@@ -103,6 +123,10 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-name = "vdd_10";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1000000>;
+				};
 			};
 
 			vcc18_lcd: LDO_REG4 {
@@ -111,6 +135,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-name = "vcc18_lcd";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
 			};
 
 			vccio_sd: LDO_REG5 {
@@ -119,6 +147,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-name = "vccio_sd";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
 			};
 
 			vdd10_lcd: LDO_REG6 {
@@ -127,6 +159,10 @@
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
 				regulator-name = "vdd10_lcd";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1000000>;
+				};
 			};
 
 			vcc_18: LDO_REG7 {
@@ -135,6 +171,10 @@
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
 				regulator-name = "vcc_18";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
 			};
 
 			vcca_codec: LDO_REG8 {
@@ -143,18 +183,28 @@
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-name = "vcca_codec";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
 			};
 
 			vcc_wl: SWITCH_REG1 {
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-name = "vcc_wl";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 
 			vcc_lcd: SWITCH_REG2 {
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-name = "vcc_lcd";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index 1c08eb0..5e895a5 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -117,6 +117,11 @@
 	status = "okay";
 };
 
+&hdmi {
+	ddc-i2c-bus = <&i2c5>;
+	status = "okay";
+};
+
 &sdmmc {
 	bus-width = <4>;
 	cap-mmc-highspeed;
@@ -133,6 +138,10 @@
 	status = "okay";
 };
 
+&i2c5 {
+	status = "okay";
+};
+
 &wdt {
 	status = "okay";
 };
@@ -236,3 +245,19 @@
 &usb_host1 {
 	status = "okay";
 };
+
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-firefly-beta.dts b/arch/arm/boot/dts/rk3288-firefly-beta.dts
new file mode 100644
index 0000000..75d77e3
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-firefly-beta.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2015 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3288-firefly.dtsi"
+
+/ {
+	model = "Firefly-RK3288 Beta";
+	compatible = "firefly,firefly-rk3288-beta", "rockchip,rk3288";
+};
+
+&ir {
+	gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
+};
+
+&pinctrl {
+	act8846 {
+		pmic_vsel: pmic-vsel {
+			rockchip,pins = <7 1 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+	};
+
+	ir {
+		ir_int: ir-int {
+			rockchip,pins = <7 5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+&pwm0 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-firefly.dts b/arch/arm/boot/dts/rk3288-firefly.dts
new file mode 100644
index 0000000..c07fe92
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-firefly.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, 2015 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3288-firefly.dtsi"
+
+/ {
+	model = "Firefly-RK3288";
+	compatible = "firefly,firefly-rk3288", "rockchip,rk3288";
+};
+
+&ir {
+	gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+};
+
+&pinctrl {
+	act8846 {
+		pmic_vsel: pmic-vsel {
+			rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+	};
+
+	ir {
+		ir_int: ir-int {
+			rockchip,pins = <7 0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+&pwm1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi
new file mode 100644
index 0000000..e6f873a
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2014, 2015 FUKAUMI Naoki <naobsd@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "rk3288.dtsi"
+
+/ {
+	memory {
+		reg = <0 0x80000000>;
+	};
+
+	ext_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+	};
+
+	ir: ir-receiver {
+		compatible = "gpio-ir-receiver";
+		pinctrl-names = "default";
+		pinctrl-0 = <&ir_int>;
+	};
+
+	keys: gpio-keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@0 {
+			gpio-key,wakeup = <1>;
+			gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
+			label = "GPIO Power";
+			linux,code = <116>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pwr_key>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		work {
+			gpios = <&gpio8 1 GPIO_ACTIVE_LOW>;
+			label = "firefly:blue:user";
+			linux,default-trigger = "rc-feedback";
+			pinctrl-names = "default";
+			pinctrl-0 = <&work_led>;
+		};
+
+		power {
+			gpios = <&gpio8 2 GPIO_ACTIVE_LOW>;
+			label = "firefly:green:power";
+			linux,default-trigger = "default-on";
+			pinctrl-names = "default";
+			pinctrl-0 = <&power_led>;
+		};
+	};
+
+	vcc_sys: vsys-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_sys";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vcc_sd: sdmmc-regulator {
+		compatible = "regulator-fixed";
+		gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc_pwr>;
+		regulator-name = "vcc_sd";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		vin-supply = <&vcc_io>;
+	};
+
+	vcc_flash: flash-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_flash";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&vcc_io>;
+	};
+
+	vcc_5v: usb-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vcc_host_5v: usb-host-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&host_vbus_drv>;
+		regulator-name = "vcc_host_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&vcc_5v>;
+	};
+
+	vcc_otg_5v: usb-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&otg_vbus_drv>;
+		regulator-name = "vcc_otg_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		vin-supply = <&vcc_5v>;
+	};
+};
+
+&cpu0 {
+	cpu0-supply = <&vdd_cpu>;
+};
+
+&emmc {
+	broken-cd;
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	disable-wp;
+	non-removable;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_pwr>, <&emmc_bus8>;
+	vmmc-supply = <&vcc_io>;
+	vqmmc-supply = <&vcc_flash>;
+	status = "okay";
+};
+
+&hdmi {
+	ddc-i2c-bus = <&i2c5>;
+	status = "okay";
+};
+
+&i2c0 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	vdd_cpu: syr827@40 {
+		compatible = "silergy,syr827";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x40>;
+		regulator-name = "vdd_cpu";
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vcc_sys>;
+	};
+
+	vdd_gpu: syr828@41 {
+		compatible = "silergy,syr828";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x41>;
+		regulator-name = "vdd_gpu";
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <1350000>;
+		regulator-always-on;
+		vin-supply = <&vcc_sys>;
+	};
+
+	hym8563: hym8563@51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		clock-output-names = "xin32k";
+		interrupt-parent = <&gpio7>;
+		interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+	};
+
+	act8846: act8846@5a {
+		compatible = "active-semi,act8846";
+		reg = <0x5a>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_vsel>, <&pwr_hold>;
+		system-power-controller;
+
+		regulators {
+			vcc_ddr: REG1 {
+				regulator-name = "vcc_ddr";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			vcc_io: REG2 {
+				regulator-name = "vcc_io";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vdd_log: REG3 {
+				regulator-name = "vdd_log";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+			};
+
+			vcc_20: REG4 {
+				regulator-name = "vcc_20";
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-always-on;
+			};
+
+			vccio_sd: REG5 {
+				regulator-name = "vccio_sd";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vdd10_lcd: REG6 {
+				regulator-name = "vdd10_lcd";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			vcca_18: REG7 {
+				regulator-name = "vcca_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			vcca_33: REG8 {
+				regulator-name = "vcca_33";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vcc_lan: REG9 {
+				regulator-name = "vcc_lan";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vdd_10: REG10 {
+				regulator-name = "vdd_10";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			vcc_18: REG11 {
+				regulator-name = "vcc_18";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			vcc18_lcd: REG12 {
+				regulator-name = "vcc18_lcd";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+};
+
+&i2c4 {
+	status = "okay";
+};
+
+&i2c5 {
+	status = "okay";
+};
+
+&pinctrl {
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	pcfg_output_low: pcfg-output-low {
+		output-low;
+	};
+
+	act8846 {
+		pwr_hold: pwr-hold {
+			rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	gmac {
+		phy_int: phy-int {
+			rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_pmeb: phy-pmeb {
+			rockchip,pins = <0 8 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_rst: phy-rst {
+			rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins = <7 4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	keys {
+		pwr_key: pwr-key {
+			rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	leds {
+		power_led: power-led {
+			rockchip,pins = <8 2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		work_led: work-led {
+			rockchip,pins = <8 1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	sdmmc {
+		sdmmc_pwr: sdmmc-pwr {
+			rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	usb_host {
+		host_vbus_drv: host-vbus-drv {
+			rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		usbhub_rst: usbhub-rst {
+			rockchip,pins = <8 3 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	usb_otg {
+		otg_vbus_drv: otg-vbus-drv {
+			rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&saradc {
+	vref-supply = <&vcc_18>;
+	status = "okay";
+};
+
+&sdio0 {
+	broken-cd;
+	bus-width = <4>;
+	disable-wp;
+	non-removable;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdio0_bus4>, <&sdio0_cmd>, <&sdio0_clk>;
+	vmmc-supply = <&vcc_18>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	card-detect-delay = <200>;
+	disable-wp;
+	num-slots = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
+	vmmc-supply = <&vcc_sd>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_clk>, <&spi0_cs0>, <&spi0_tx>, <&spi0_rx>, <&spi0_cs1>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>;
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&usb_host1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbhub_rst>;
+	status = "okay";
+};
+
+&usb_otg {
+	status = "okay";
+};
+
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
+&wdt {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 910dcad..d771f68 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -149,8 +149,22 @@
 		clock-frequency = <24000000>;
 	};
 
+	timer: timer@ff810000 {
+		compatible = "rockchip,rk3288-timer";
+		reg = <0xff810000 0x20>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&xin24m>, <&cru PCLK_TIMER>;
+		clock-names = "timer", "pclk";
+	};
+
+	display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vopl_out>, <&vopb_out>;
+	};
+
 	sdmmc: dwmmc@ff0c0000 {
 		compatible = "rockchip,rk3288-dw-mshc";
+		clock-freq-min-max = <400000 150000000>;
 		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>;
 		clock-names = "biu", "ciu";
 		fifo-depth = <0x100>;
@@ -161,6 +175,7 @@
 
 	sdio0: dwmmc@ff0d0000 {
 		compatible = "rockchip,rk3288-dw-mshc";
+		clock-freq-min-max = <400000 150000000>;
 		clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>;
 		clock-names = "biu", "ciu";
 		fifo-depth = <0x100>;
@@ -171,6 +186,7 @@
 
 	sdio1: dwmmc@ff0e0000 {
 		compatible = "rockchip,rk3288-dw-mshc";
+		clock-freq-min-max = <400000 150000000>;
 		clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>;
 		clock-names = "biu", "ciu";
 		fifo-depth = <0x100>;
@@ -181,6 +197,7 @@
 
 	emmc: dwmmc@ff0f0000 {
 		compatible = "rockchip,rk3288-dw-mshc";
+		clock-freq-min-max = <400000 150000000>;
 		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>;
 		clock-names = "biu", "ciu";
 		fifo-depth = <0x100>;
@@ -518,6 +535,11 @@
 		};
 	};
 
+	sram@ff720000 {
+		compatible = "rockchip,rk3288-pmu-sram", "mmio-sram";
+		reg = <0xff720000 0x1000>;
+	};
+
 	pmu: power-management@ff730000 {
 		compatible = "rockchip,rk3288-pmu", "syscon";
 		reg = <0xff730000 0x100>;
@@ -554,6 +576,7 @@
 	wdt: watchdog@ff800000 {
 		compatible = "rockchip,rk3288-wdt", "snps,dw-wdt";
 		reg = <0xff800000 0x100>;
+		clocks = <&cru PCLK_WDT>;
 		interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
 		status = "disabled";
 	};
@@ -573,6 +596,28 @@
 		status = "disabled";
 	};
 
+	vopb: vop@ff930000 {
+		compatible = "rockchip,rk3288-vop";
+		reg = <0xff930000 0x19c>;
+		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopb_mmu>;
+		status = "disabled";
+
+		vopb_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vopb_out_hdmi: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&hdmi_in_vopb>;
+			};
+		};
+	};
+
 	vopb_mmu: iommu@ff930300 {
 		compatible = "rockchip,iommu";
 		reg = <0xff930300 0x100>;
@@ -582,6 +627,28 @@
 		status = "disabled";
 	};
 
+	vopl: vop@ff940000 {
+		compatible = "rockchip,rk3288-vop";
+		reg = <0xff940000 0x19c>;
+		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopl_mmu>;
+		status = "disabled";
+
+		vopl_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			vopl_out_hdmi: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&hdmi_in_vopl>;
+			};
+		};
+	};
+
 	vopl_mmu: iommu@ff940300 {
 		compatible = "rockchip,iommu";
 		reg = <0xff940300 0x100>;
@@ -591,6 +658,32 @@
 		status = "disabled";
 	};
 
+	hdmi: hdmi@ff980000 {
+		compatible = "rockchip,rk3288-dw-hdmi";
+		reg = <0xff980000 0x20000>;
+		reg-io-width = <4>;
+		rockchip,grf = <&grf>;
+		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+		clock-names = "iahb", "isfr";
+		status = "disabled";
+
+		ports {
+			hdmi_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				hdmi_in_vopb: endpoint@0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_hdmi>;
+				};
+				hdmi_in_vopl: endpoint@1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_hdmi>;
+				};
+			};
+		};
+	};
+
 	gic: interrupt-controller@ffc01000 {
 		compatible = "arm,gic-400";
 		interrupt-controller;
@@ -746,6 +839,24 @@
 			drive-strength = <12>;
 		};
 
+		sleep {
+			global_pwroff: global-pwroff {
+				rockchip,pins = <0 0 RK_FUNC_1 &pcfg_pull_none>;
+			};
+
+			ddrio_pwroff: ddrio-pwroff {
+				rockchip,pins = <0 1 RK_FUNC_1 &pcfg_pull_none>;
+			};
+
+			ddr0_retention: ddr0-retention {
+				rockchip,pins = <0 2 RK_FUNC_1 &pcfg_pull_up>;
+			};
+
+			ddr1_retention: ddr1-retention {
+				rockchip,pins = <0 3 RK_FUNC_1 &pcfg_pull_up>;
+			};
+		};
+
 		i2c0 {
 			i2c0_xfer: i2c0-xfer {
 				rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>,
diff --git a/arch/arm/boot/dts/s5pv210-aquila.dts b/arch/arm/boot/dts/s5pv210-aquila.dts
index aa31b84..f00cea7 100644
--- a/arch/arm/boot/dts/s5pv210-aquila.dts
+++ b/arch/arm/boot/dts/s5pv210-aquila.dts
@@ -355,6 +355,7 @@
 &hsotg {
 	vusb_a-supply = <&ldo3_reg>;
 	vusb_d-supply = <&ldo8_reg>;
+	dr_mode = "peripheral";
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/s5pv210-goni.dts b/arch/arm/boot/dts/s5pv210-goni.dts
index 6387c77..a3d4643 100644
--- a/arch/arm/boot/dts/s5pv210-goni.dts
+++ b/arch/arm/boot/dts/s5pv210-goni.dts
@@ -333,6 +333,7 @@
 &hsotg {
 	vusb_a-supply = <&ldo3_reg>;
 	vusb_d-supply = <&ldo8_reg>;
+	dr_mode = "peripheral";
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/s5pv210-smdkv210.dts b/arch/arm/boot/dts/s5pv210-smdkv210.dts
index cb85218..da7d210 100644
--- a/arch/arm/boot/dts/s5pv210-smdkv210.dts
+++ b/arch/arm/boot/dts/s5pv210-smdkv210.dts
@@ -181,6 +181,7 @@
 };
 
 &hsotg {
+	dr_mode = "peripheral";
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 5f4144d..261311b 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -78,6 +78,11 @@
 		};
 	};
 
+	sram: sram@00300000 {
+		compatible = "mmio-sram";
+		reg = <0x00300000 0x20000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -214,7 +219,20 @@
 				compatible = "atmel,at91sam9g45-isi";
 				reg = <0xf0034000 0x4000>;
 				interrupts = <37 IRQ_TYPE_LEVEL_HIGH 5>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_isi_data_0_7>;
+				clocks = <&isi_clk>;
+				clock-names = "isi_clk";
 				status = "disabled";
+				port {
+					#address-cells = <1>;
+					#size-cells = <0>;
+				};
+			};
+
+			sfr: sfr@f0038000 {
+				compatible = "atmel,sama5d3-sfr", "syscon";
+				reg = <0xf0038000 0x60>;
 			};
 
 			mmc1: mmc@f8000000 {
@@ -545,7 +563,7 @@
 				};
 
 				isi {
-					pinctrl_isi: isi-0 {
+					pinctrl_isi_data_0_7: isi-0-data-0-7 {
 						atmel,pins =
 							<AT91_PIOA 16 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PA16 periph C ISI_D0, conflicts with LCDDAT16 */
 							 AT91_PIOA 17 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PA17 periph C ISI_D1, conflicts with LCDDAT17 */
@@ -557,13 +575,19 @@
 							 AT91_PIOA 23 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PA23 periph C ISI_D7, conflicts with LCDDAT23, PWML1 */
 							 AT91_PIOC 30 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC30 periph C ISI_PCK, conflicts with UTXD0 */
 							 AT91_PIOA 31 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PA31 periph C ISI_HSYNC, conflicts with TWCK0, UTXD1 */
-							 AT91_PIOA 30 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PA30 periph C ISI_VSYNC, conflicts with TWD0, URXD1 */
-							 AT91_PIOC 29 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC29 periph C ISI_PD8, conflicts with URXD0, PWMFI2 */
+							 AT91_PIOA 30 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* PA30 periph C ISI_VSYNC, conflicts with TWD0, URXD1 */
+					};
+
+					pinctrl_isi_data_8_9: isi-0-data-8-9 {
+						atmel,pins =
+							<AT91_PIOC 29 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC29 periph C ISI_PD8, conflicts with URXD0, PWMFI2 */
 							 AT91_PIOC 28 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* PC28 periph C ISI_PD9, conflicts with SPI1_NPCS3, PWMFI0 */
 					};
-					pinctrl_isi_pck_as_mck: isi_pck_as_mck-0 {
+
+					pinctrl_isi_data_10_11: isi-0-data-10-11 {
 						atmel,pins =
-							<AT91_PIOD 31 AT91_PERIPH_B AT91_PINCTRL_NONE>;	/* PD31 periph B ISI_MCK */
+							<AT91_PIOC 27 AT91_PERIPH_C AT91_PINCTRL_NONE	/* PC27 periph C ISI_PD10, conflicts with SPI1_NPCS2, TWCK1 */
+							 AT91_PIOC 26 AT91_PERIPH_C AT91_PINCTRL_NONE>;	/* PC26 periph C ISI_PD11, conflicts with SPI1_NPCS1, TWD1 */
 					};
 				};
 
diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi
index cfcd200..7d6babd 100644
--- a/arch/arm/boot/dts/sama5d3xcm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xcm.dtsi
@@ -122,6 +122,7 @@
 		d2 {
 			label = "d2";
 			gpios = <&pioE 25 GPIO_ACTIVE_LOW>;	/* PE25, conflicts with A25, RXD2 */
+			linux,default-trigger = "heartbeat";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi
index 77e0365..83bee7a 100644
--- a/arch/arm/boot/dts/sama5d3xmb.dtsi
+++ b/arch/arm/boot/dts/sama5d3xmb.dtsi
@@ -45,13 +45,36 @@
 			 */
 			i2c0: i2c@f0014000 {
 				wm8904: wm8904@1a {
-					compatible = "wm8904";
+					compatible = "wlf,wm8904";
 					reg = <0x1a>;
 					clocks = <&pck0>;
 					clock-names = "mclk";
 				};
 			};
 
+			i2c1: i2c@f0018000 {
+				ov2640: camera@0x30 {
+					compatible = "ovti,ov2640";
+					reg = <0x30>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_pck1_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>;
+					resetb-gpios = <&pioE 24 GPIO_ACTIVE_LOW>;
+					pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>;
+					/* use pck1 for the master clock of ov2640 */
+					clocks = <&pck1>;
+					clock-names = "xvclk";
+					assigned-clocks = <&pck1>;
+					assigned-clock-rates = <25000000>;
+
+					port {
+						ov2640_0: endpoint {
+							remote-endpoint = <&isi_0>;
+							bus-width = <8>;
+						};
+					};
+				};
+			};
+
 			usart1: serial@f0020000 {
 				dmas = <0>, <0>;	/*  Do not use DMA for usart1 */
 				pinctrl-names = "default";
@@ -60,8 +83,12 @@
 			};
 
 			isi: isi@f0034000 {
-				pinctrl-names = "default";
-				pinctrl-0 = <&pinctrl_isi &pinctrl_isi_pck_as_mck &pinctrl_isi_power &pinctrl_isi_reset>;
+				port {
+					isi_0: endpoint {
+						remote-endpoint = <&ov2640_0>;
+						bus-width = <8>;
+					};
+				};
 			};
 
 			mmc1: mmc@f8000000 {
@@ -117,12 +144,17 @@
 							<AT91_PIOD 30 AT91_PERIPH_B AT91_PINCTRL_NONE>;	/* PD30 periph B */
 					};
 
-					pinctrl_isi_reset: isi_reset-0 {
+					pinctrl_pck1_as_isi_mck: pck1_as_isi_mck-0 {
+						atmel,pins =
+							<AT91_PIOD 31 AT91_PERIPH_B AT91_PINCTRL_NONE>;	/* PD31 periph B ISI_MCK */
+					};
+
+					pinctrl_sensor_reset: sensor_reset-0 {
 						atmel,pins =
 							<AT91_PIOE 24 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;   /* PE24 gpio */
 					};
 
-					pinctrl_isi_power: isi_power-0 {
+					pinctrl_sensor_power: sensor_power-0 {
 						atmel,pins =
 							<AT91_PIOE 29 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>; /* PE29 gpio */
 					};
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index b94995d..d986b41 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -62,6 +62,7 @@
 		gpio0 = &pioA;
 		gpio1 = &pioB;
 		gpio2 = &pioC;
+		gpio3 = &pioD;
 		gpio4 = &pioE;
 		tcb0 = &tcb0;
 		tcb1 = &tcb1;
@@ -103,6 +104,11 @@
 		};
 	};
 
+	ns_sram: sram@00210000 {
+		compatible = "mmio-sram";
+		reg = <0x00210000 0x10000>;
+	};
+
 	ahb {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -267,7 +273,7 @@
 		};
 
 		nand0: nand@80000000 {
-			compatible = "atmel,at91rm9200-nand";
+			compatible = "atmel,sama5d4-nand", "atmel,at91rm9200-nand";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			ranges;
@@ -870,6 +876,11 @@
 				status = "disabled";
 			};
 
+			sfr: sfr@f8028000 {
+				compatible = "atmel,sama5d4-sfr", "syscon";
+				reg = <0xf8028000 0x60>;
+			};
+
 			mmc1: mmc@fc000000 {
 				compatible = "atmel,hsmci";
 				reg = <0xfc000000 0x600>;
@@ -1111,6 +1122,18 @@
 					clocks = <&pioC_clk>;
 				};
 
+				pioD: gpio@fc068000 {
+					compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+					reg = <0xfc068000 0x100>;
+					interrupts = <5 IRQ_TYPE_LEVEL_HIGH 1>;
+					#gpio-cells = <2>;
+					gpio-controller;
+					interrupt-controller;
+					#interrupt-cells = <2>;
+					clocks = <&pioD_clk>;
+					status = "disabled";
+				};
+
 				pioE: gpio@fc06d000 {
 					compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
 					reg = <0xfc06d000 0x100>;
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
index 939be12..6d32c87 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
@@ -179,7 +179,11 @@
 };
 
 &cmt1 {
-	status = "ok";
+	status = "okay";
+};
+
+&extal2_clk {
+	clock-frequency = <48000000>;
 };
 
 &i2c0 {
diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi
index d8def5a..2dfd5b4 100644
--- a/arch/arm/boot/dts/sh73a0.dtsi
+++ b/arch/arm/boot/dts/sh73a0.dtsi
@@ -10,6 +10,7 @@
 
 /include/ "skeleton.dtsi"
 
+#include <dt-bindings/clock/sh73a0-clock.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
@@ -42,6 +43,22 @@
 		      <0xf0000100 0x100>;
 	};
 
+	sbsc2: memory-controller@fb400000 {
+		compatible = "renesas,sbsc-sh73a0";
+		reg = <0xfb400000 0x400>;
+		interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>,
+			     <0 38 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "sec", "temp";
+	};
+
+	sbsc1: memory-controller@fe400000 {
+		compatible = "renesas,sbsc-sh73a0";
+		reg = <0xfe400000 0x400>;
+		interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>,
+			     <0 36 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "sec", "temp";
+	};
+
 	pmu {
 		compatible = "arm,cortex-a9-pmu";
 		interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>,
@@ -55,6 +72,8 @@
 
 		renesas,channels-mask = <0x3f>;
 
+		clocks = <&mstp3_clks SH73A0_CLK_CMT1>;
+		clock-names = "fck";
 		status = "disabled";
 	};
 
@@ -144,6 +163,7 @@
 			      0 168 IRQ_TYPE_LEVEL_HIGH
 			      0 169 IRQ_TYPE_LEVEL_HIGH
 			      0 170 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp1_clks SH73A0_CLK_IIC0>;
 		status = "disabled";
 	};
 
@@ -156,6 +176,7 @@
 			      0 52 IRQ_TYPE_LEVEL_HIGH
 			      0 53 IRQ_TYPE_LEVEL_HIGH
 			      0 54 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_IIC1>;
 		status = "disabled";
 	};
 
@@ -168,6 +189,7 @@
 			      0 172 IRQ_TYPE_LEVEL_HIGH
 			      0 173 IRQ_TYPE_LEVEL_HIGH
 			      0 174 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp0_clks SH73A0_CLK_IIC2>;
 		status = "disabled";
 	};
 
@@ -180,6 +202,7 @@
 			      0 184 IRQ_TYPE_LEVEL_HIGH
 			      0 185 IRQ_TYPE_LEVEL_HIGH
 			      0 186 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp4_clks SH73A0_CLK_IIC3>;
 		status = "disabled";
 	};
 
@@ -192,6 +215,7 @@
 			      0 188 IRQ_TYPE_LEVEL_HIGH
 			      0 189 IRQ_TYPE_LEVEL_HIGH
 			      0 190 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp4_clks SH73A0_CLK_IIC4>;
 		status = "disabled";
 	};
 
@@ -200,6 +224,7 @@
 		reg = <0xe6bd0000 0x100>;
 		interrupts = <0 140 IRQ_TYPE_LEVEL_HIGH
 			      0 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_MMCIF0>;
 		reg-io-width = <4>;
 		status = "disabled";
 	};
@@ -210,6 +235,7 @@
 		interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH
 			      0 84 IRQ_TYPE_LEVEL_HIGH
 			      0 85 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_SDHI0>;
 		cap-sd-highspeed;
 		status = "disabled";
 	};
@@ -220,6 +246,7 @@
 		reg = <0xee120000 0x100>;
 		interrupts = <0 88 IRQ_TYPE_LEVEL_HIGH
 			      0 89 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_SDHI1>;
 		toshiba,mmc-wrprotect-disable;
 		cap-sd-highspeed;
 		status = "disabled";
@@ -230,6 +257,7 @@
 		reg = <0xee140000 0x100>;
 		interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH
 			      0 105 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_SDHI2>;
 		toshiba,mmc-wrprotect-disable;
 		cap-sd-highspeed;
 		status = "disabled";
@@ -239,6 +267,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6c40000 0x100>;
 		interrupts = <0 72 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA0>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -246,6 +276,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6c50000 0x100>;
 		interrupts = <0 73 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA1>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -253,6 +285,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6c60000 0x100>;
 		interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA2>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -260,6 +294,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6c70000 0x100>;
 		interrupts = <0 75 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA3>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -267,6 +303,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6c80000 0x100>;
 		interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA4>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -274,6 +312,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6cb0000 0x100>;
 		interrupts = <0 79 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA5>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -281,6 +321,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6cc0000 0x100>;
 		interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp3_clks SH73A0_CLK_SCIFA6>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -288,6 +330,8 @@
 		compatible = "renesas,scifa-sh73a0", "renesas,scifa";
 		reg = <0xe6cd0000 0x100>;
 		interrupts = <0 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFA7>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -295,6 +339,8 @@
 		compatible = "renesas,scifb-sh73a0", "renesas,scifb";
 		reg = <0xe6c30000 0x100>;
 		interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&mstp2_clks SH73A0_CLK_SCIFB>;
+		clock-names = "sci_ick";
 		status = "disabled";
 	};
 
@@ -317,9 +363,337 @@
 
 	sh_fsi2: sound@ec230000 {
 		#sound-dai-cells = <1>;
-		compatible = "renesas,sh_fsi2";
+		compatible = "renesas,fsi2-sh73a0", "renesas,sh_fsi2";
 		reg = <0xec230000 0x400>;
 		interrupts = <0 146 0x4>;
 		status = "disabled";
 	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* External root clocks */
+		extalr_clk: extalr_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "extalr";
+		};
+		extal1_clk: extal1_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <26000000>;
+			clock-output-names = "extal1";
+		};
+		extal2_clk: extal2_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "extal2";
+		};
+		extcki_clk: extcki_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-output-names = "extcki";
+		};
+		fsiack_clk: fsiack_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <0>;
+			clock-output-names = "fsiack";
+		};
+		fsibck_clk: fsibck_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <0>;
+			clock-output-names = "fsibck";
+		};
+
+		/* Special CPG clocks */
+		cpg_clocks: cpg_clocks@e6150000 {
+			compatible = "renesas,sh73a0-cpg-clocks";
+			reg = <0xe6150000 0x10000>;
+			clocks = <&extal1_clk>, <&extal2_clk>;
+			#clock-cells = <1>;
+			clock-output-names = "main", "pll0", "pll1", "pll2",
+					     "pll3", "dsi0phy", "dsi1phy",
+					     "zg", "m3", "b", "m1", "m2",
+					     "z", "zx", "hp";
+		};
+
+		/* Variable factor clocks (DIV6) */
+		vclk1_clk: vclk1_clk@e6150008 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150008 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "vclk1";
+		};
+		vclk2_clk: vclk2_clk@e615000c {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe615000c 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "vclk2";
+		};
+		vclk3_clk: vclk3_clk@e615001c {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe615001c 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "vclk3";
+		};
+		zb_clk: zb_clk@e6150010 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150010 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "zb";
+		};
+		flctl_clk: flctl_clk@e6150014 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150014 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "flctlck";
+		};
+		sdhi0_clk: sdhi0_clk@e6150074 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150074 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sdhi0ck";
+		};
+		sdhi1_clk: sdhi1_clk@e6150078 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150078 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sdhi1ck";
+		};
+		sdhi2_clk: sdhi2_clk@e615007c {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe615007c 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sdhi2ck";
+		};
+		fsia_clk: fsia_clk@e6150018 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150018 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "fsia";
+		};
+		fsib_clk: fsib_clk@e6150090 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150090 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "fsib";
+		};
+		sub_clk: sub_clk@e6150080 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150080 4>;
+			clocks = <&extal2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sub";
+		};
+		spua_clk: spua_clk@e6150084 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150084 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "spua";
+		};
+		spuv_clk: spuv_clk@e6150094 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150094 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "spuv";
+		};
+		msu_clk: msu_clk@e6150088 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150088 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "msu";
+		};
+		hsi_clk: hsi_clk@e615008c {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe615008c 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "hsi";
+		};
+		mfg1_clk: mfg1_clk@e6150098 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150098 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "mfg1";
+		};
+		mfg2_clk: mfg2_clk@e615009c {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe615009c 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "mfg2";
+		};
+		dsit_clk: dsit_clk@e6150060 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150060 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "dsit";
+		};
+		dsi0p_clk: dsi0p_clk@e6150064 {
+			compatible = "renesas,sh73a0-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150064 4>;
+			clocks = <&pll1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "dsi0pck";
+		};
+
+		/* Fixed factor clocks */
+		main_div2_clk: main_div2_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks SH73A0_CLK_MAIN>;
+			#clock-cells = <0>;
+			clock-div = <2>;
+			clock-mult = <1>;
+			clock-output-names = "main_div2";
+		};
+		pll1_div2_clk: pll1_div2_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks SH73A0_CLK_PLL1>;
+			#clock-cells = <0>;
+			clock-div = <2>;
+			clock-mult = <1>;
+			clock-output-names = "pll1_div2";
+		};
+		pll1_div7_clk: pll1_div7_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks SH73A0_CLK_PLL1>;
+			#clock-cells = <0>;
+			clock-div = <7>;
+			clock-mult = <1>;
+			clock-output-names = "pll1_div7";
+		};
+		pll1_div13_clk: pll1_div13_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks SH73A0_CLK_PLL1>;
+			#clock-cells = <0>;
+			clock-div = <13>;
+			clock-mult = <1>;
+			clock-output-names = "pll1_div13";
+		};
+		twd_clk: twd_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks SH73A0_CLK_Z>;
+			#clock-cells = <0>;
+			clock-div = <4>;
+			clock-mult = <1>;
+			clock-output-names = "twd";
+		};
+
+		/* Gate clocks */
+		mstp0_clks: mstp0_clks@e6150130 {
+			compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe6150130 4>, <0xe6150030 4>;
+			clocks = <&cpg_clocks SH73A0_CLK_HP>;
+			#clock-cells = <1>;
+			clock-indices = <
+				SH73A0_CLK_IIC2
+			>;
+			clock-output-names =
+				"iic2";
+		};
+		mstp1_clks: mstp1_clks@e6150134 {
+			compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe6150134 4>, <0xe6150038 4>;
+			clocks = <&cpg_clocks SH73A0_CLK_B>,
+				 <&cpg_clocks SH73A0_CLK_B>,
+				 <&cpg_clocks SH73A0_CLK_B>,
+				 <&cpg_clocks SH73A0_CLK_B>,
+				 <&sub_clk>, <&cpg_clocks SH73A0_CLK_B>,
+				 <&cpg_clocks SH73A0_CLK_HP>,
+				 <&cpg_clocks SH73A0_CLK_ZG>,
+				 <&cpg_clocks SH73A0_CLK_B>;
+			#clock-cells = <1>;
+			clock-indices = <
+				SH73A0_CLK_CEU1 SH73A0_CLK_CSI2_RX1
+				SH73A0_CLK_CEU0 SH73A0_CLK_CSI2_RX0
+				SH73A0_CLK_TMU0	SH73A0_CLK_DSITX0
+				SH73A0_CLK_IIC0 SH73A0_CLK_SGX
+				SH73A0_CLK_LCDC0
+			>;
+			clock-output-names =
+				"ceu1", "csi2_rx1", "ceu0", "csi2_rx0",
+				"tmu0", "dsitx0", "iic0", "sgx", "lcdc0";
+		};
+		mstp2_clks: mstp2_clks@e6150138 {
+			compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe6150138 4>, <0xe6150040 4>;
+			clocks = <&sub_clk>, <&cpg_clocks SH73A0_CLK_HP>,
+				 <&cpg_clocks SH73A0_CLK_HP>, <&sub_clk>,
+				 <&sub_clk>, <&sub_clk>, <&sub_clk>, <&sub_clk>,
+				 <&sub_clk>, <&sub_clk>;
+			#clock-cells = <1>;
+			clock-indices = <
+				SH73A0_CLK_SCIFA7 SH73A0_CLK_SY_DMAC
+				SH73A0_CLK_MP_DMAC SH73A0_CLK_SCIFA5
+				SH73A0_CLK_SCIFB SH73A0_CLK_SCIFA0
+				SH73A0_CLK_SCIFA1 SH73A0_CLK_SCIFA2
+				SH73A0_CLK_SCIFA3 SH73A0_CLK_SCIFA4
+			>;
+			clock-output-names =
+				"scifa7", "sy_dmac", "mp_dmac", "scifa5",
+				"scifb", "scifa0", "scifa1", "scifa2",
+				"scifa3", "scifa4";
+		};
+		mstp3_clks: mstp3_clks@e615013c {
+			compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe615013c 4>, <0xe6150048 4>;
+			clocks = <&sub_clk>, <&extalr_clk>,
+				 <&cpg_clocks SH73A0_CLK_HP>, <&sub_clk>,
+				 <&cpg_clocks SH73A0_CLK_HP>,
+				 <&cpg_clocks SH73A0_CLK_HP>, <&flctl_clk>,
+				 <&sdhi0_clk>, <&sdhi1_clk>,
+				 <&cpg_clocks SH73A0_CLK_HP>, <&sdhi2_clk>,
+				 <&main_div2_clk>, <&main_div2_clk>,
+				 <&main_div2_clk>, <&main_div2_clk>,
+				 <&main_div2_clk>;
+			#clock-cells = <1>;
+			clock-indices = <
+				SH73A0_CLK_SCIFA6 SH73A0_CLK_CMT1
+				SH73A0_CLK_FSI SH73A0_CLK_IRDA
+				SH73A0_CLK_IIC1 SH73A0_CLK_USB SH73A0_CLK_FLCTL
+				SH73A0_CLK_SDHI0 SH73A0_CLK_SDHI1
+				SH73A0_CLK_MMCIF0 SH73A0_CLK_SDHI2
+				SH73A0_CLK_TPU0 SH73A0_CLK_TPU1
+				SH73A0_CLK_TPU2 SH73A0_CLK_TPU3
+				SH73A0_CLK_TPU4
+			>;
+			clock-output-names =
+				"scifa6", "cmt1", "fsi", "irda", "iic1",
+				"usb", "flctl", "sdhi0", "sdhi1", "mmcif0", "sdhi2",
+				"tpu0", "tpu1", "tpu2", "tpu3", "tpu4";
+		};
+		mstp4_clks: mstp4_clks@e6150140 {
+			compatible = "renesas,sh73a0-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe6150140 4>, <0xe615004c 4>;
+			clocks = <&cpg_clocks SH73A0_CLK_HP>,
+				 <&cpg_clocks SH73A0_CLK_HP>, <&extalr_clk>;
+			#clock-cells = <1>;
+			clock-indices = <
+				SH73A0_CLK_IIC3 SH73A0_CLK_IIC4
+				SH73A0_CLK_KEYSC
+			>;
+			clock-output-names =
+				"iic3", "iic4", "keysc";
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/stih407-b2120.dts b/arch/arm/boot/dts/stih407-b2120.dts
index 261d5e2..af48714 100644
--- a/arch/arm/boot/dts/stih407-b2120.dts
+++ b/arch/arm/boot/dts/stih407-b2120.dts
@@ -7,9 +7,8 @@
  * published by the Free Software Foundation.
  */
 /dts-v1/;
-#include "stih407-clock.dtsi"
-#include "stih407-family.dtsi"
 #include "stihxxx-b2120.dtsi"
+#include "stih407.dtsi"
 / {
 	model = "STiH407 B2120";
 	compatible = "st,stih407-b2120", "st,stih407";
diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
index d4a8f84..c06a546 100644
--- a/arch/arm/boot/dts/stih407-family.dtsi
+++ b/arch/arm/boot/dts/stih407-family.dtsi
@@ -283,5 +283,58 @@
 				 <&picophyreset STIH407_PICOPHY0_RESET>;
 			reset-names = "global", "port";
 		};
+
+		miphy28lp_phy: miphy28lp@9b22000 {
+			compatible = "st,miphy28lp-phy";
+			st,syscfg = <&syscfg_core>;
+			#address-cells	= <1>;
+			#size-cells	= <1>;
+			ranges;
+
+			phy_port0: port@9b22000 {
+				reg = <0x9b22000 0xff>,
+				      <0x9b09000 0xff>,
+				      <0x9b04000 0xff>;
+				reg-names = "sata-up",
+					    "pcie-up",
+					    "pipew";
+
+				st,syscfg = <0x114 0x818 0xe0 0xec>;
+				#phy-cells = <1>;
+
+				reset-names = "miphy-sw-rst";
+				resets = <&softreset STIH407_MIPHY0_SOFTRESET>;
+			};
+
+			phy_port1: port@9b2a000 {
+				reg = <0x9b2a000 0xff>,
+				      <0x9b19000 0xff>,
+				      <0x9b14000 0xff>;
+				reg-names = "sata-up",
+					    "pcie-up",
+					    "pipew";
+
+				st,syscfg = <0x118 0x81c 0xe4 0xf0>;
+
+				#phy-cells = <1>;
+
+				reset-names = "miphy-sw-rst";
+				resets = <&softreset STIH407_MIPHY1_SOFTRESET>;
+			};
+
+			phy_port2: port@8f95000 {
+				reg = <0x8f95000 0xff>,
+				      <0x8f90000 0xff>;
+				reg-names = "pipew",
+					    "usb3-up";
+
+				st,syscfg = <0x11c 0x820>;
+
+				#phy-cells = <1>;
+
+				reset-names = "miphy-sw-rst";
+				resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi
new file mode 100644
index 0000000..3efa3b2
--- /dev/null
+++ b/arch/arm/boot/dts/stih407.dtsi
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 STMicroelectronics Limited.
+ * Author: Gabriel Fernandez <gabriel.fernandez@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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih407-clock.dtsi"
+#include "stih407-family.dtsi"
+/ {
+	soc {
+		/* Display */
+		vtg_main: sti-vtg-main@8d02800 {
+			compatible = "st,vtg";
+			reg = <0x8d02800 0x200>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_NONE>;
+		};
+
+		vtg_aux: sti-vtg-aux@8d00200 {
+			compatible = "st,vtg";
+			reg = <0x8d00200 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_NONE>;
+		};
+
+		sti-display-subsystem {
+			compatible = "st,sti-display-subsystem";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			assigned-clocks	= <&clk_s_d2_quadfs 0>,
+					  <&clk_s_d2_quadfs 0>,
+					  <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
+					  <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP1>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP2>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP3>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP4>;
+
+			assigned-clock-parents = <0>,
+						 <0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>;
+
+			assigned-clock-rates = <297000000>, <297000000>;
+
+			ranges;
+
+			sti-compositor@9d11000 {
+				compatible = "st,stih407-compositor";
+				reg = <0x9d11000 0x1000>;
+
+				clock-names = "compo_main",
+					      "compo_aux",
+					      "pix_main",
+					      "pix_aux",
+					      "pix_gdp1",
+					      "pix_gdp2",
+					      "pix_gdp3",
+					      "pix_gdp4",
+					      "main_parent",
+					      "aux_parent";
+
+				clocks = <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+					 <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+					 <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
+					 <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP1>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP2>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP3>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP4>,
+					 <&clk_s_d2_quadfs 0>,
+					 <&clk_s_d2_quadfs 1>;
+
+				reset-names = "compo-main", "compo-aux";
+				resets = <&softreset STIH407_COMPO_SOFTRESET>,
+					 <&softreset STIH407_COMPO_SOFTRESET>;
+				st,vtg = <&vtg_main>, <&vtg_aux>;
+			};
+
+			sti-tvout@8d08000 {
+				compatible = "st,stih407-tvout";
+				reg = <0x8d08000 0x1000>;
+				reg-names = "tvout-reg";
+				reset-names = "tvout";
+				resets = <&softreset STIH407_HDTVOUT_SOFTRESET>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				assigned-clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
+						  <&clk_s_d2_flexgen CLK_TMDS_HDMI>,
+						  <&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
+						  <&clk_s_d0_flexgen CLK_PCM_0>,
+						  <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
+						  <&clk_s_d2_flexgen CLK_HDDAC>;
+
+				assigned-clock-parents = <&clk_s_d2_quadfs 0>,
+							 <&clk_tmdsout_hdmi>,
+							 <&clk_s_d2_quadfs 0>,
+							 <&clk_s_d0_quadfs 0>,
+							 <&clk_s_d2_quadfs 0>,
+							 <&clk_s_d2_quadfs 0>;
+				ranges;
+
+				sti-hdmi@8d04000 {
+					compatible = "st,stih407-hdmi";
+					reg = <0x8d04000 0x1000>;
+					reg-names = "hdmi-reg";
+					interrupts = <GIC_SPI 106 IRQ_TYPE_NONE>;
+					interrupt-names	= "irq";
+					clock-names = "pix",
+						      "tmds",
+						      "phy",
+						      "audio",
+						      "main_parent",
+						      "aux_parent";
+
+					clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
+						 <&clk_s_d2_flexgen CLK_TMDS_HDMI>,
+						 <&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
+						 <&clk_s_d0_flexgen CLK_PCM_0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 1>;
+
+					hdmi,hpd-gpio = <&pio5 3>;
+					reset-names = "hdmi";
+					resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
+					ddc = <&hdmiddc>;
+
+				};
+
+				sti-hda@8d02000 {
+					compatible = "st,stih407-hda";
+					reg = <0x8d02000 0x400>, <0x92b0120 0x4>;
+					reg-names = "hda-reg", "video-dacs-ctrl";
+					clock-names = "pix",
+						      "hddac",
+						      "main_parent",
+						      "aux_parent";
+					clocks = <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
+						 <&clk_s_d2_flexgen CLK_HDDAC>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 1>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
index 37995f4..208b5e8 100644
--- a/arch/arm/boot/dts/stih410.dtsi
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -80,5 +80,143 @@
 			phys = <&usb2_picophy2>;
 			phy-names = "usb";
 		};
+
+		/* Display */
+		vtg_main: sti-vtg-main@8d02800 {
+			compatible = "st,vtg";
+			reg = <0x8d02800 0x200>;
+			interrupts = <GIC_SPI 108 IRQ_TYPE_NONE>;
+		};
+
+		vtg_aux: sti-vtg-aux@8d00200 {
+			compatible = "st,vtg";
+			reg = <0x8d00200 0x100>;
+			interrupts = <GIC_SPI 109 IRQ_TYPE_NONE>;
+		};
+
+		sti-display-subsystem {
+			compatible = "st,sti-display-subsystem";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			assigned-clocks	= <&clk_s_d2_quadfs 0>,
+					  <&clk_s_d2_quadfs 0>,
+					  <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
+					  <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP1>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP2>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP3>,
+					  <&clk_s_d2_flexgen CLK_PIX_GDP4>;
+
+			assigned-clock-parents = <0>,
+						 <0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 0>;
+
+			assigned-clock-rates = <297000000>, <297000000>;
+
+			ranges;
+
+			sti-compositor@9d11000 {
+				compatible = "st,stih407-compositor";
+				reg = <0x9d11000 0x1000>;
+
+				clock-names = "compo_main",
+					      "compo_aux",
+					      "pix_main",
+					      "pix_aux",
+					      "pix_gdp1",
+					      "pix_gdp2",
+					      "pix_gdp3",
+					      "pix_gdp4",
+					      "main_parent",
+					      "aux_parent";
+
+				clocks = <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+					 <&clk_s_c0_flexgen CLK_COMPO_DVP>,
+					 <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>,
+					 <&clk_s_d2_flexgen CLK_PIX_AUX_DISP>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP1>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP2>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP3>,
+					 <&clk_s_d2_flexgen CLK_PIX_GDP4>,
+					 <&clk_s_d2_quadfs 0>,
+					 <&clk_s_d2_quadfs 1>;
+
+				reset-names = "compo-main", "compo-aux";
+				resets = <&softreset STIH407_COMPO_SOFTRESET>,
+					 <&softreset STIH407_COMPO_SOFTRESET>;
+				st,vtg = <&vtg_main>, <&vtg_aux>;
+			};
+
+			sti-tvout@8d08000 {
+				compatible = "st,stih407-tvout";
+				reg = <0x8d08000 0x1000>;
+				reg-names = "tvout-reg";
+				reset-names = "tvout";
+				resets = <&softreset STIH407_HDTVOUT_SOFTRESET>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				assigned-clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
+						  <&clk_s_d2_flexgen CLK_TMDS_HDMI>,
+						  <&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
+						  <&clk_s_d0_flexgen CLK_PCM_0>,
+						  <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
+						  <&clk_s_d2_flexgen CLK_HDDAC>;
+
+				assigned-clock-parents = <&clk_s_d2_quadfs 0>,
+							 <&clk_tmdsout_hdmi>,
+							 <&clk_s_d2_quadfs 0>,
+							 <&clk_s_d0_quadfs 0>,
+							 <&clk_s_d2_quadfs 0>,
+							 <&clk_s_d2_quadfs 0>;
+				ranges;
+
+				sti-hdmi@8d04000 {
+					compatible = "st,stih407-hdmi";
+					reg = <0x8d04000 0x1000>;
+					reg-names = "hdmi-reg";
+					interrupts = <GIC_SPI 106 IRQ_TYPE_NONE>;
+					interrupt-names	= "irq";
+					clock-names = "pix",
+						      "tmds",
+						      "phy",
+						      "audio",
+						      "main_parent",
+						      "aux_parent";
+
+					clocks = <&clk_s_d2_flexgen CLK_PIX_HDMI>,
+						 <&clk_s_d2_flexgen CLK_TMDS_HDMI>,
+						 <&clk_s_d2_flexgen CLK_REF_HDMIPHY>,
+						 <&clk_s_d0_flexgen CLK_PCM_0>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 1>;
+
+					hdmi,hpd-gpio = <&pio5 3>;
+					reset-names = "hdmi";
+					resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
+					ddc = <&hdmiddc>;
+
+				};
+
+				sti-hda@8d02000 {
+					compatible = "st,stih407-hda";
+					reg = <0x8d02000 0x400>, <0x92b0120 0x4>;
+					reg-names = "hda-reg", "video-dacs-ctrl";
+					clock-names = "pix",
+						      "hddac",
+						      "main_parent",
+						      "aux_parent";
+					clocks = <&clk_s_d2_flexgen CLK_PIX_HDDAC>,
+						 <&clk_s_d2_flexgen CLK_HDDAC>,
+						 <&clk_s_d2_quadfs 0>,
+						 <&clk_s_d2_quadfs 1>;
+				};
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
new file mode 100644
index 0000000..926235c
--- /dev/null
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 STMicroelectronics (R&D) Limited.
+ * Author: Maxime Coquelin <maxime.coquelin@st.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.
+ */
+/dts-v1/;
+#include "stih418.dtsi"
+/ {
+	model = "STiH418 B2199";
+	compatible = "st,stih418-b2199", "st,stih418";
+
+	chosen {
+		bootargs = "console=ttyAS0,115200 clk_ignore_unused";
+		linux,stdout-path = &sbc_serial0;
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x40000000 0xc0000000>;
+	};
+
+	aliases {
+		ttyAS0 = &sbc_serial0;
+	};
+
+	soc {
+		sbc_serial0: serial@9530000 {
+			status = "okay";
+		};
+
+		leds {
+			compatible = "gpio-leds";
+			red {
+				#gpio-cells = <2>;
+				label = "Front Panel LED";
+				gpios = <&pio4 1 0>;
+				linux,default-trigger = "heartbeat";
+			};
+			green {
+				#gpio-cells = <2>;
+				gpios = <&pio1 3 0>;
+				default-state = "off";
+			};
+		};
+
+		i2c@9842000 {
+			status = "okay";
+		};
+
+		i2c@9843000 {
+			status = "okay";
+		};
+
+		i2c@9844000 {
+			status = "okay";
+		};
+
+		i2c@9845000 {
+			status = "okay";
+		};
+
+		i2c@9540000 {
+			status = "okay";
+		};
+
+		/* SSC11 to HDMI */
+		i2c@9541000 {
+			status = "okay";
+			/* HDMI V1.3a supports Standard mode only */
+			clock-frequency = <100000>;
+			st,i2c-min-scl-pulse-width-us = <0>;
+			st,i2c-min-sda-pulse-width-us = <5>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih418-clock.dtsi b/arch/arm/boot/dts/stih418-clock.dtsi
new file mode 100644
index 0000000..0ab23da
--- /dev/null
+++ b/arch/arm/boot/dts/stih418-clock.dtsi
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2015 STMicroelectronics R&D Limited
+ *
+ * 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/clock/stih418-clks.h>
+/ {
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		compatible = "st,stih418-clk", "simple-bus";
+
+		/*
+		 * Fixed 30MHz oscillator inputs to SoC
+		 */
+		clk_sysin: clk-sysin {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <30000000>;
+			clock-output-names = "CLK_SYSIN";
+		};
+
+		/*
+		 * ARM Peripheral clock for timers
+		 */
+		arm_periph_clk: clk-m-a9-periphs {
+			#clock-cells = <0>;
+			compatible = "fixed-factor-clock";
+			clocks = <&clk_m_a9>;
+			clock-div = <2>;
+			clock-mult = <1>;
+		};
+
+		/*
+		 * A9 PLL.
+		 */
+		clockgen-a9@92b0000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x92b0000 0xffff>;
+
+			clockgen_a9_pll: clockgen-a9-pll {
+				#clock-cells = <1>;
+				compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+
+				clocks = <&clk_sysin>;
+
+				clock-output-names = "clockgen-a9-pll-odf";
+			};
+		};
+
+		/*
+		 * ARM CPU related clocks.
+		 */
+		clk_m_a9: clk-m-a9@92b0000 {
+			#clock-cells = <0>;
+			compatible = "st,stih407-clkgen-a9-mux", "st,clkgen-mux";
+			reg = <0x92b0000 0x10000>;
+
+			clocks = <&clockgen_a9_pll 0>,
+				 <&clockgen_a9_pll 0>,
+				 <&clk_s_c0_flexgen 13>,
+				 <&clk_m_a9_ext2f_div2>;
+		};
+
+		/*
+		 * ARM Peripheral clock for timers
+		 */
+		clk_m_a9_ext2f_div2: clk-m-a9-ext2f-div2s {
+			#clock-cells = <0>;
+			compatible = "fixed-factor-clock";
+
+			clocks = <&clk_s_c0_flexgen 13>;
+
+			clock-output-names = "clk-m-a9-ext2f-div2";
+
+			clock-div = <2>;
+			clock-mult = <1>;
+		};
+
+		/*
+		 * Bootloader initialized system infrastructure clock for
+		 * serial devices.
+		 */
+		clk_ext2f_a9: clockgen-c0@13 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <200000000>;
+			clock-output-names = "clk-s-icn-reg-0";
+		};
+
+		clockgen-a@090ff000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x90ff000 0x1000>;
+
+			clk_s_a0_pll: clk-s-a0-pll {
+				#clock-cells = <1>;
+				compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+
+				clocks = <&clk_sysin>;
+
+				clock-output-names = "clk-s-a0-pll-ofd-0";
+			};
+
+			clk_s_a0_flexgen: clk-s-a0-flexgen {
+				compatible = "st,flexgen";
+
+				#clock-cells = <1>;
+
+				clocks = <&clk_s_a0_pll 0>,
+					 <&clk_sysin>;
+
+				clock-output-names = "clk-ic-lmi0",
+						     "clk-ic-lmi1";
+			};
+		};
+
+		clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
+			#clock-cells = <1>;
+			compatible = "st,stih407-quadfs660-C", "st,quadfs";
+			reg = <0x9103000 0x1000>;
+
+			clocks = <&clk_sysin>;
+
+			clock-output-names = "clk-s-c0-fs0-ch0",
+					     "clk-s-c0-fs0-ch1",
+					     "clk-s-c0-fs0-ch2",
+					     "clk-s-c0-fs0-ch3";
+		};
+
+		clk_s_c0: clockgen-c@09103000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x9103000 0x1000>;
+
+			clk_s_c0_pll0: clk-s-c0-pll0 {
+				#clock-cells = <1>;
+				compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32";
+
+				clocks = <&clk_sysin>;
+
+				clock-output-names = "clk-s-c0-pll0-odf-0";
+			};
+
+			clk_s_c0_pll1: clk-s-c0-pll1 {
+				#clock-cells = <1>;
+				compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32";
+
+				clocks = <&clk_sysin>;
+
+				clock-output-names = "clk-s-c0-pll1-odf-0";
+			};
+
+			clk_s_c0_flexgen: clk-s-c0-flexgen {
+				#clock-cells = <1>;
+				compatible = "st,flexgen";
+
+				clocks = <&clk_s_c0_pll0 0>,
+					 <&clk_s_c0_pll1 0>,
+					 <&clk_s_c0_quadfs 0>,
+					 <&clk_s_c0_quadfs 1>,
+					 <&clk_s_c0_quadfs 2>,
+					 <&clk_s_c0_quadfs 3>,
+					 <&clk_sysin>;
+
+				clock-output-names = "clk-icn-gpu",
+						     "clk-fdma",
+						     "clk-nand",
+						     "clk-hva",
+						     "clk-proc-stfe",
+						     "clk-tp",
+						     "clk-rx-icn-dmu",
+						     "clk-rx-icn-hva",
+						     "clk-icn-cpu",
+						     "clk-tx-icn-dmu",
+						     "clk-mmc-0",
+						     "clk-mmc-1",
+						     "clk-jpegdec",
+						     "clk-icn-reg",
+						     "clk-proc-bdisp-0",
+						     "clk-proc-bdisp-1",
+						     "clk-pp-dmu",
+						     "clk-vid-dmu",
+						     "clk-dss-lpc",
+						     "clk-st231-aud-0",
+						     "clk-st231-gp-1",
+						     "clk-st231-dmu",
+						     "clk-icn-lmi",
+						     "clk-tx-icn-1",
+						     "clk-icn-sbc",
+						     "clk-stfe-frc2",
+						     "clk-eth-phyref",
+						     "clk-eth-ref-phyclk",
+						     "clk-flash-promip",
+						     "clk-main-disp",
+						     "clk-aux-disp",
+						     "clk-compo-dvp",
+						     "clk-tx-icn-hades",
+						     "clk-rx-icn-hades",
+						     "clk-icn-reg-16",
+						     "clk-pp-hevc",
+						     "clk-clust-hevc",
+						     "clk-hwpe-hevc",
+						     "clk-fc-hevc",
+						     "clk-proc-mixer",
+						     "clk-proc-sc",
+						     "clk-avsp-hevc";
+			};
+		};
+
+		clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
+			#clock-cells = <1>;
+			compatible = "st,stih407-quadfs660-D", "st,quadfs";
+			reg = <0x9104000 0x1000>;
+
+			clocks = <&clk_sysin>;
+
+			clock-output-names = "clk-s-d0-fs0-ch0",
+					     "clk-s-d0-fs0-ch1",
+					     "clk-s-d0-fs0-ch2",
+					     "clk-s-d0-fs0-ch3";
+		};
+
+		clockgen-d0@09104000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x9104000 0x1000>;
+
+			clk_s_d0_flexgen: clk-s-d0-flexgen {
+				#clock-cells = <1>;
+				compatible = "st,flexgen";
+
+				clocks = <&clk_s_d0_quadfs 0>,
+					 <&clk_s_d0_quadfs 1>,
+					 <&clk_s_d0_quadfs 2>,
+					 <&clk_s_d0_quadfs 3>,
+					 <&clk_sysin>;
+
+				clock-output-names = "clk-pcm-0",
+						     "clk-pcm-1",
+						     "clk-pcm-2",
+						     "clk-spdiff",
+						     "clk-pcmr10-master",
+						     "clk-usb2-phy";
+			};
+		};
+
+		clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
+			#clock-cells = <1>;
+			compatible = "st,stih407-quadfs660-D", "st,quadfs";
+			reg = <0x9106000 0x1000>;
+
+			clocks = <&clk_sysin>;
+
+			clock-output-names = "clk-s-d2-fs0-ch0",
+					     "clk-s-d2-fs0-ch1",
+					     "clk-s-d2-fs0-ch2",
+					     "clk-s-d2-fs0-ch3";
+		};
+
+		clk_tmdsout_hdmi: clk-tmdsout-hdmi {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		clockgen-d2@x9106000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x9106000 0x1000>;
+
+			clk_s_d2_flexgen: clk-s-d2-flexgen {
+				#clock-cells = <1>;
+				compatible = "st,flexgen";
+
+				clocks = <&clk_s_d2_quadfs 0>,
+					 <&clk_s_d2_quadfs 1>,
+					 <&clk_s_d2_quadfs 2>,
+					 <&clk_s_d2_quadfs 3>,
+					 <&clk_sysin>,
+					 <&clk_sysin>,
+					 <&clk_tmdsout_hdmi>;
+
+				clock-output-names = "clk-pix-main-disp",
+						     "",
+						     "",
+						     "",
+						     "",
+						     "clk-tmds-hdmi-div2",
+						     "clk-pix-aux-disp",
+						     "clk-denc",
+						     "clk-pix-hddac",
+						     "clk-hddac",
+						     "clk-sddac",
+						     "clk-pix-dvo",
+						     "clk-dvo",
+						     "clk-pix-hdmi",
+						     "clk-tmds-hdmi",
+						     "clk-ref-hdmiphy",
+						     "", "", "", "", "",
+						     "", "", "", "", "",
+						     "", "", "", "", "",
+						     "", "", "", "", "",
+						     "", "", "", "", "",
+						     "", "", "", "", "",
+						     "", "clk-vp9";
+			};
+		};
+
+		clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
+			#clock-cells = <1>;
+			compatible = "st,stih407-quadfs660-D", "st,quadfs";
+			reg = <0x9107000 0x1000>;
+
+			clocks = <&clk_sysin>;
+
+			clock-output-names = "clk-s-d3-fs0-ch0",
+					     "clk-s-d3-fs0-ch1",
+					     "clk-s-d3-fs0-ch2",
+					     "clk-s-d3-fs0-ch3";
+		};
+
+		clockgen-d3@9107000 {
+			compatible = "st,clkgen-c32";
+			reg = <0x9107000 0x1000>;
+
+			clk_s_d3_flexgen: clk-s-d3-flexgen {
+				#clock-cells = <1>;
+				compatible = "st,flexgen";
+
+				clocks = <&clk_s_d3_quadfs 0>,
+					 <&clk_s_d3_quadfs 1>,
+					 <&clk_s_d3_quadfs 2>,
+					 <&clk_s_d3_quadfs 3>,
+					 <&clk_sysin>;
+
+				clock-output-names = "clk-stfe-frc1",
+						     "clk-tsout-0",
+						     "clk-tsout-1",
+						     "clk-mchi",
+						     "clk-vsens-compo",
+						     "clk-frc1-remote",
+						     "clk-lpc-0",
+						     "clk-lpc-1";
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stih418.dtsi b/arch/arm/boot/dts/stih418.dtsi
new file mode 100644
index 0000000..354d90f
--- /dev/null
+++ b/arch/arm/boot/dts/stih418.dtsi
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics Limited.
+ * Author: Peter Griffin <peter.griffin@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
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih418-clock.dtsi"
+#include "stih407-family.dtsi"
+#include "stih410-pinctrl.dtsi"
+/ {
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <2>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a9";
+			reg = <3>;
+		};
+	};
+
+	soc {
+		usb2_picophy1: phy2 {
+			compatible = "st,stih407-usb2-phy";
+			#phy-cells = <0>;
+			st,syscfg = <&syscfg_core 0xf8 0xf4>;
+			resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
+				 <&picophyreset STIH407_PICOPHY0_RESET>;
+			reset-names = "global", "port";
+		};
+
+		usb2_picophy2: phy3 {
+			compatible = "st,stih407-usb2-phy";
+			#phy-cells = <0>;
+			st,syscfg = <&syscfg_core 0xfc 0xf4>;
+			resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
+				 <&picophyreset STIH407_PICOPHY1_RESET>;
+			reset-names = "global", "port";
+		};
+
+		ohci0: usb@9a03c00 {
+			compatible = "st,st-ohci-300x";
+			reg = <0x9a03c00 0x100>;
+			interrupts = <GIC_SPI 180 IRQ_TYPE_NONE>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
+				 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
+			reset-names = "power", "softreset";
+			phys = <&usb2_picophy1>;
+			phy-names = "usb";
+		};
+
+		ehci0: usb@9a03e00 {
+			compatible = "st,st-ehci-300x";
+			reg = <0x9a03e00 0x100>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb0>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			resets = <&powerdown STIH407_USB2_PORT0_POWERDOWN>,
+				 <&softreset STIH407_USB2_PORT0_SOFTRESET>;
+			reset-names = "power", "softreset";
+			phys = <&usb2_picophy1>;
+			phy-names = "usb";
+		};
+
+		ohci1: usb@9a83c00 {
+			compatible = "st,st-ohci-300x";
+			reg = <0x9a83c00 0x100>;
+			interrupts = <GIC_SPI 181 IRQ_TYPE_NONE>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
+				 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
+			reset-names = "power", "softreset";
+			phys = <&usb2_picophy2>;
+			phy-names = "usb";
+		};
+
+		ehci1: usb@9a83e00 {
+			compatible = "st,st-ehci-300x";
+			reg = <0x9a83e00 0x100>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_NONE>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb1>;
+			clocks = <&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>;
+			resets = <&powerdown STIH407_USB2_PORT1_POWERDOWN>,
+				 <&softreset STIH407_USB2_PORT1_SOFTRESET>;
+			reset-names = "power", "softreset";
+			phys = <&usb2_picophy2>;
+			phy-names = "usb";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index 0074bd4..c1d8590 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -48,12 +48,23 @@
 		};
 
 		/* SSC11 to HDMI */
-		i2c@9541000 {
+		hdmiddc: i2c@9541000 {
 			status = "okay";
 			/* HDMI V1.3a supports Standard mode only */
 			clock-frequency = <100000>;
 			st,i2c-min-scl-pulse-width-us = <0>;
 			st,i2c-min-sda-pulse-width-us = <5>;
 		};
+
+		miphy28lp_phy: miphy28lp@9b22000 {
+
+			phy_port0: port@9b22000 {
+				st,osc-rdy;
+			};
+
+			phy_port1: port@9b2a000 {
+				st,osc-force-ext;
+			};
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index 3bcfd818..b67e5be 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Mele A1000";
@@ -77,7 +80,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -112,15 +115,15 @@
 			emac_power_pin_a1000: emac_power_pin@0 {
 				allwinner,pins = "PH15";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_a1000: led_pins@0 {
 				allwinner,pins = "PH10", "PH20";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -159,12 +162,12 @@
 
 		red {
 			label = "a1000:red:usr";
-			gpios = <&pio 7 10 0>;
+			gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>;
 		};
 
 		blue {
 			label = "a1000:blue:usr";
-			gpios = <&pio 7 20 0>;
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -176,7 +179,7 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		enable-active-high;
-		gpio = <&pio 7 15 0>;
+		gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>;
 	};
 
 	reg_usb1_vbus: usb1-vbus {
diff --git a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
index f3f2974..490b77c 100644
--- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
+++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
@@ -46,8 +46,10 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "BA10 tvbox";
@@ -74,7 +76,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -140,7 +142,7 @@
 	};
 
 	reg_usb2_vbus: usb2-vbus {
-		gpio = <&pio 7 12 0>;
+		gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
 		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
new file mode 100644
index 0000000..58214f2
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Chuwi V7 CW0825";
+	compatible = "chuwi,v7-cw0825", "allwinner,sun4i-a10";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic@34 {
+		compatible = "x-powers,axp209";
+		reg = <0x34>;
+		interrupts = <0>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	cd-inverted;
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 6a310da..4260c2b 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -47,8 +47,11 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Cubietech Cubieboard";
@@ -75,7 +78,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -111,8 +114,8 @@
 			led_pins_cubieboard: led_pins@0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -134,12 +137,8 @@
 			status = "okay";
 
 			axp209: pmic@34 {
-				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupts = <0>;
-
-				interrupt-controller;
-				#interrupt-cells = <1>;
 			};
 		};
 
@@ -148,6 +147,12 @@
 			pinctrl-0 = <&i2c1_pins_a>;
 			status = "okay";
 		};
+
+		spi0: spi@01c05000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi0_pins_a>;
+			status = "okay";
+		};
 	};
 
 	leds {
@@ -157,12 +162,12 @@
 
 		blue {
 			label = "cubieboard:blue:usr";
-			gpios = <&pio 7 21 0>; /* LED1 */
+			gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>; /* LED1 */
 		};
 
 		green {
 			label = "cubieboard:green:usr";
-			gpios = <&pio 7 20 0>; /* LED2 */
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>; /* LED2 */
 			linux,default-trigger = "heartbeat";
 		};
 	};
@@ -179,3 +184,34 @@
 		status = "okay";
 	};
 };
+
+#include "axp209.dtsi"
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc2>;
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1450000>;
+	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-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index efc1162..d3f73ea 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Miniand Hackberry";
@@ -77,7 +80,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -111,15 +114,15 @@
 			hackberry_hogs: hogs@0 {
 				allwinner,pins = "PH19";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb2_vbus_pin_hackberry: usb2_vbus_pin@0 {
 					allwinner,pins = "PH12";
 					allwinner,function = "gpio_out";
-					allwinner,drive = <0>;
-					allwinner,pull = <0>;
+					allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+					allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -157,7 +160,7 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		enable-active-high;
-		gpio = <&pio 7 19 0>;
+		gpio = <&pio 7 19 GPIO_ACTIVE_HIGH>;
 	};
 
 	reg_usb1_vbus: usb1-vbus {
@@ -166,7 +169,7 @@
 
 	reg_usb2_vbus: usb2-vbus {
 		pinctrl-0 = <&usb2_vbus_pin_hackberry>;
-		gpio = <&pio 7 12 0>;
+		gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
new file mode 100644
index 0000000..c88382a
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-hyundai-a7hd.dts
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Hyundai A7HD";
+	compatible = "hyundai,a7hd", "allwinner,sun4i-a10";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic@34 {
+		compatible = "x-powers,axp209";
+		reg = <0x34>;
+		interrupts = <0>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	cd-inverted;
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	gpio = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb2_vbus_pin_a {
+	allwinner,pins = "PH6";
+};
+
+&usbphy {
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index 3e25ee4..4829143 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -48,8 +48,10 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "INet-97F Rev 02";
@@ -65,7 +67,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
diff --git a/arch/arm/boot/dts/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
new file mode 100644
index 0000000..9ee86a7
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 Aleksei Mamlin
+ * Aleksei Mamlin <mamlinav@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "HAOYU Electronics Marsboard A10";
+	compatible = "haoyu,a10-marsboard", "allwinner,sun4i-a10";
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_marsboard>;
+
+		red1 {
+			label = "marsboard:red1:usr";
+			gpios = <&pio 1 5 GPIO_ACTIVE_HIGH>;
+		};
+
+		red2 {
+			label = "marsboard:red2:usr";
+			gpios = <&pio 1 6 GPIO_ACTIVE_HIGH>;
+		};
+
+		red3 {
+			label = "marsboard:red3:usr";
+			gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		red4 {
+			label = "marsboard:red4:usr";
+			gpios = <&pio 1 8 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&ahci {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&emac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_pins_a>;
+	phy = <&phy1>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	status = "okay";
+};
+
+&mdio {
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	cd-inverted;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	led_pins_marsboard: led_pins@0 {
+		allwinner,pins = "PB5", "PB6", "PB7", "PB8";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&reg_usb1_vbus {
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	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 8b3f974..eb5fd69 100644
--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "PineRiver Mini X-Plus";
@@ -61,7 +64,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -91,7 +94,7 @@
 		pinctrl@01c20800 {
 			ir0_pins_a: ir0@0 {
 				/* The ir receiver is not always populated */
-				allwinner,pull = <1>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802.dts b/arch/arm/boot/dts/sun4i-a10-mk802.dts
new file mode 100644
index 0000000..e9a6886
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-mk802.dts
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "MK802";
+	compatible = "allwinner,mk802", "allwinner,sun4i-a10";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	cd-inverted;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&pio {
+	usb2_vbus_pin_mk802: usb2_vbus_pin@0 {
+		allwinner,pins = "PH12";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&reg_usb1_vbus {
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	pinctrl-0 = <&usb2_vbus_pin_mk802>;
+	gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>; /* PH12 */
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-mk802ii.dts b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
new file mode 100644
index 0000000..802eda4
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-mk802ii.dts
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "MK802ii";
+	compatible = "allwinner,mk802ii", "allwinner,sun4i-a10";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic@34 {
+		compatible = "x-powers,axp209";
+		reg = <0x34>;
+		interrupts = <0>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+	vmmc-supply = <&reg_vcc3v3>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	cd-inverted;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&reg_usb1_vbus {
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	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 88cf1a5..ab7891c 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -46,8 +46,11 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A10-OLinuXino-LIME";
@@ -74,7 +77,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -110,15 +113,15 @@
 			ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
 				allwinner,pins = "PC3";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_olinuxinolime: led_pins@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -151,14 +154,14 @@
 
 		green {
 			label = "a10-olinuxino-lime:green:usr";
-			gpios = <&pio 7 2 0>;
+			gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_ahci_5v: ahci-5v {
 		pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
-		gpio = <&pio 2 3 0>;
+		gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index ce59945..9d1e548 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -47,8 +47,12 @@
  */
 
 /dts-v1/;
-/include/ "sun4i-a10.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "LinkSprite pcDuino";
@@ -62,6 +66,22 @@
 			status = "okay";
 		};
 
+		pinctrl@01c20800 {
+			led_pins_pcduino: led_pins@0 {
+				allwinner,pins = "PH15", "PH16";
+				allwinner,function = "gpio_out";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			key_pins_pcduino: key_pins@0 {
+				allwinner,pins = "PH17", "PH18", "PH19";
+				allwinner,function = "gpio_in";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+		};
+
 		mdio@01c0b080 {
 			status = "okay";
 
@@ -75,7 +95,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -124,6 +144,48 @@
 		};
 	};
 
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_pcduino>;
+
+		tx {
+			label = "pcduino:green:tx";
+			gpios = <&pio 7 15 GPIO_ACTIVE_LOW>;
+		};
+
+		rx {
+			label = "pcduino:green:rx";
+			gpios = <&pio 7 16 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_pins_pcduino>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@0 {
+			label = "Key Back";
+			linux,code = <KEY_BACK>;
+			gpios = <&pio 7 17 GPIO_ACTIVE_LOW>;
+		};
+
+		button@1 {
+			label = "Key Home";
+			linux,code = <KEY_HOME>;
+			gpios = <&pio 7 18 GPIO_ACTIVE_LOW>;
+		};
+
+		button@2 {
+			label = "Key Menu";
+			linux,code = <KEY_MENU>;
+			gpios = <&pio 7 19 GPIO_ACTIVE_LOW>;
+		};
+	};
+
 	reg_usb1_vbus: usb1-vbus {
 		status = "okay";
 	};
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index d5c4669..8ca3c1a 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -10,7 +10,12 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/thermal/thermal.h>
+
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&intc>;
@@ -39,15 +44,78 @@
 				 <&ahb_gates 44>, <&ahb_gates 46>;
 			status = "disabled";
 		};
+
+		framebuffer@2 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_fe0-de_be0-lcd0";
+			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
+				 <&ahb_gates 46>;
+			status = "disabled";
+		};
+
+		framebuffer@3 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_fe0-de_be0-lcd0-tve0";
+			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+				 <&ahb_gates 44>, <&ahb_gates 46>;
+			status = "disabled";
+		};
 	};
 
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		cpu@0 {
+		cpu0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a8";
 			reg = <0x0>;
+			clocks = <&cpu>;
+			clock-latency = <244144>; /* 8 32k periods */
+			operating-points = <
+				/* kHz    uV */
+				1056000 1500000
+				1008000 1400000
+				912000  1350000
+				864000  1300000
+				624000  1250000
+				>;
+			#cooling-cells = <2>;
+			cooling-min-level = <0>;
+			cooling-max-level = <4>;
+		};
+	};
+
+	thermal-zones {
+		cpu_thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&rtp>;
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					/* milliCelsius */
+					temperature = <850000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					/* milliCelsius */
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
 		};
 	};
 
@@ -359,7 +427,8 @@
 			interrupts = <10>;
 			clocks = <&ahb_gates 20>, <&spi0_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 27>, <&dma 1 26>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+			       <&dma SUN4I_DMA_DEDICATED 26>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -372,7 +441,8 @@
 			interrupts = <11>;
 			clocks = <&ahb_gates 21>, <&spi1_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 9>, <&dma 1 8>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+			       <&dma SUN4I_DMA_DEDICATED 8>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -387,7 +457,7 @@
 			status = "disabled";
 		};
 
-		mdio@01c0b080 {
+		mdio: mdio@01c0b080 {
 			compatible = "allwinner,sun4i-a10-mdio";
 			reg = <0x01c0b080 0x14>;
 			status = "disabled";
@@ -469,7 +539,8 @@
 			interrupts = <12>;
 			clocks = <&ahb_gates 22>, <&spi2_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 29>, <&dma 1 28>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+			       <&dma SUN4I_DMA_DEDICATED 28>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -510,7 +581,8 @@
 			interrupts = <50>;
 			clocks = <&ahb_gates 23>, <&spi3_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 31>, <&dma 1 30>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 31>,
+			       <&dma SUN4I_DMA_DEDICATED 30>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -538,57 +610,57 @@
 			pwm0_pins_a: pwm0@0 {
 				allwinner,pins = "PB2";
 				allwinner,function = "pwm";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			pwm1_pins_a: pwm1@0 {
 				allwinner,pins = "PI3";
 				allwinner,function = "pwm";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PB22", "PB23";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart0_pins_b: uart0@1 {
 				allwinner,pins = "PF2", "PF4";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart1_pins_a: uart1@0 {
 				allwinner,pins = "PA10", "PA11";
 				allwinner,function = "uart1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PB0", "PB1";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PB18", "PB19";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PB20", "PB21";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			emac_pins_a: emac0@0 {
@@ -598,36 +670,78 @@
 						"PA11", "PA12", "PA13", "PA14",
 						"PA15", "PA16";
 				allwinner,function = "emac";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_cd_pin_reference_design: mmc0_cd_pin@0 {
 				allwinner,pins = "PH1";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			ir0_pins_a: ir0@0 {
 				allwinner,pins = "PB3","PB4";
 				allwinner,function = "ir0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			ir1_pins_a: ir1@0 {
 				allwinner,pins = "PB22","PB23";
 				allwinner,function = "ir1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi0_pins_a: spi0@0 {
+				allwinner,pins = "PI10", "PI11", "PI12", "PI13";
+				allwinner,function = "spi0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi1_pins_a: spi1@0 {
+				allwinner,pins = "PI16", "PI17", "PI18", "PI19";
+				allwinner,function = "spi1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi2_pins_a: spi2@0 {
+				allwinner,pins = "PB14", "PB15", "PB16", "PB17";
+				allwinner,function = "spi2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spi2_pins_b: spi2@1 {
+				allwinner,pins = "PC19", "PC20", "PC21", "PC22";
+				allwinner,function = "spi2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -675,6 +789,13 @@
 			status = "disabled";
 		};
 
+		lradc: lradc@01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <31>;
+			status = "disabled";
+		};
+
 		sid: eeprom@01c23800 {
 			compatible = "allwinner,sun4i-a10-sid";
 			reg = <0x01c23800 0x10>;
@@ -684,6 +805,7 @@
 			compatible = "allwinner,sun4i-a10-ts";
 			reg = <0x01c25000 0x100>;
 			interrupts = <29>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		uart0: serial@01c28000 {
@@ -795,5 +917,21 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <62>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <63>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun5i-a10s-mk802.dts b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
new file mode 100644
index 0000000..b21af87
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a10s-mk802.dts
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "MK802-A10s";
+	compatible = "allwinner,a10s-mk802", "allwinner,sun5i-a10s";
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_mk802>;
+
+		red {
+			label = "mk802:red:usr";
+			gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2 */
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	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;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&pio {
+	led_pins_mk802: led_pins@0 {
+		allwinner,pins = "PB2";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	mmc0_cd_pin_mk802: mmc0_cd_pin@0 {
+		allwinner,pins = "PG1";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+	};
+
+	usb1_vbus_pin_mk802: usb1_vbus_pin@0 {
+		allwinner,pins = "PB10";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&reg_usb1_vbus {
+	pinctrl-0 = <&usb1_vbus_pin_mk802>;
+	gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>; /* PB10 */
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	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 bfa7428..2bbc93b 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -48,8 +48,12 @@
  */
 
 /dts-v1/;
-/include/ "sun5i-a10s.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A10s-Olinuxino Micro";
@@ -82,7 +86,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino_micro>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 1 0>; /* PG1 */
+			cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -92,7 +96,7 @@
 			pinctrl-0 = <&mmc1_pins_a>, <&mmc1_cd_pin_olinuxino_micro>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 13 0>; /* PG13 */
+			cd-gpios = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -114,29 +118,69 @@
 			mmc0_cd_pin_olinuxino_micro: mmc0_cd_pin@0 {
 				allwinner,pins = "PG1";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			mmc1_cd_pin_olinuxino_micro: mmc1_cd_pin@0 {
 				allwinner,pins = "PG13";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PE3";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb1_vbus_pin_olinuxino_m: usb1_vbus_pin@0 {
 				allwinner,pins = "PB10";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+		};
+
+		lradc: lradc@01c22800 {
+			vref-supply = <&reg_vcc3v0>;
+			status = "okay";
+
+			button@191 {
+				label = "Volume Up";
+				linux,code = <KEY_VOLUMEUP>;
+				channel = <0>;
+				voltage = <191274>;
+			};
+
+			button@392 {
+				label = "Volume Down";
+				linux,code = <KEY_VOLUMEDOWN>;
+				channel = <0>;
+				voltage = <392644>;
+			};
+
+			button@601 {
+				label = "Menu";
+				linux,code = <KEY_MENU>;
+				channel = <0>;
+				voltage = <601151>;
+			};
+
+			button@795 {
+				label = "Enter";
+				linux,code = <KEY_ENTER>;
+				channel = <0>;
+				voltage = <795090>;
+			};
+
+			button@987 {
+				label = "Home";
+				linux,code = <KEY_HOMEPAGE>;
+				channel = <0>;
+				voltage = <987387>;
 			};
 		};
 
@@ -191,14 +235,14 @@
 
 		green {
 			label = "a10s-olinuxino-micro:green:usr";
-			gpios = <&pio 4 3 0>;
+			gpios = <&pio 4 3 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_olinuxino_m>;
-		gpio = <&pio 1 10 0>;
+		gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>;
 		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 1fa2916..7deddfc 100644
--- a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
@@ -46,8 +46,11 @@
  */
 
 /dts-v1/;
-/include/ "sun5i-a10s.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "R7 A10s hdmi tv-stick";
@@ -59,7 +62,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_r7>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 1 0>; /* PG1 */
+			cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -90,22 +93,22 @@
 			mmc0_cd_pin_r7: mmc0_cd_pin@0 {
 				allwinner,pins = "PG1";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			led_pins_r7: led_pins@0 {
 				allwinner,pins = "PB2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb1_vbus_pin_r7: usb1_vbus_pin@0 {
 				allwinner,pins = "PG13";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -123,14 +126,14 @@
 
 		green {
 			label = "r7-tv-dongle:green:usr";
-			gpios = <&pio 1 2 0>;
+			gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_r7>;
-		gpio = <&pio 6 13 0>;
+		gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 2e7d826..905f84d 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -11,7 +11,10 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&intc>;
@@ -32,6 +35,14 @@
 				 <&ahb_gates 44>;
 			status = "disabled";
 		};
+
+		framebuffer@1 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0";
+			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			status = "disabled";
+		};
 	};
 
 	cpus {
@@ -316,7 +327,8 @@
 			interrupts = <10>;
 			clocks = <&ahb_gates 20>, <&spi0_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 27>, <&dma 1 26>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+			       <&dma SUN4I_DMA_DEDICATED 26>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -329,7 +341,8 @@
 			interrupts = <11>;
 			clocks = <&ahb_gates 21>, <&spi1_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 9>, <&dma 1 8>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+			       <&dma SUN4I_DMA_DEDICATED 8>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -344,7 +357,7 @@
 			status = "disabled";
 		};
 
-		mdio@01c0b080 {
+		mdio: mdio@01c0b080 {
 			compatible = "allwinner,sun4i-a10-mdio";
 			reg = <0x01c0b080 0x14>;
 			status = "disabled";
@@ -417,7 +430,8 @@
 			interrupts = <12>;
 			clocks = <&ahb_gates 22>, <&spi2_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 29>, <&dma 1 28>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+			       <&dma SUN4I_DMA_DEDICATED 28>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -445,22 +459,22 @@
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PB19", "PB20";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart2_pins_a: uart2@0 {
 				allwinner,pins = "PC18", "PC19";
 				allwinner,function = "uart2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart3_pins_a: uart3@0 {
 				allwinner,pins = "PG9", "PG10";
 				allwinner,function = "uart3";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			emac_pins_a: emac0@0 {
@@ -470,43 +484,43 @@
 						"PA11", "PA12", "PA13", "PA14",
 						"PA15", "PA16";
 				allwinner,function = "emac";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PB0", "PB1";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PB15", "PB16";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PB17", "PB18";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc1_pins_a: mmc1@0 {
 				allwinner,pins = "PG3","PG4","PG5","PG6","PG7","PG8";
 				allwinner,function = "mmc1";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -522,6 +536,13 @@
 			reg = <0x01c20c90 0x10>;
 		};
 
+		lradc: lradc@01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <31>;
+			status = "disabled";
+		};
+
 		sid: eeprom@01c23800 {
 			compatible = "allwinner,sun4i-a10-sid";
 			reg = <0x01c23800 0x10>;
@@ -531,6 +552,7 @@
 			compatible = "allwinner,sun4i-a10-ts";
 			reg = <0x01c25000 0x100>;
 			interrupts = <29>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		uart0: serial@01c28000 {
diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
index c7be3ab..03aa045 100644
--- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
+++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
@@ -46,8 +46,11 @@
  */
 
 /dts-v1/;
-/include/ "sun5i-a13.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "HSG H702";
@@ -63,17 +66,13 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_h702>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
 			cd-inverted;
 			status = "okay";
 		};
 
 		usbphy: phy@01c13400 {
-			/*
-			 * There doesn't seem to be a GPIO for controlling
-			 * usb1 vbus, despite the fex file saying otherwise.
-			 */
-			usb1_vbus-supply = <&reg_vcc5v0>;
+			usb1_vbus-supply = <&reg_ldo3>;
 			status = "okay";
 		};
 
@@ -89,8 +88,8 @@
 			mmc0_cd_pin_h702: mmc0_cd_pin@0 {
 				allwinner,pins = "PG0";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 		};
 
@@ -106,11 +105,8 @@
 			status = "okay";
 
 			axp209: pmic@34 {
-				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupts = <0>;
-				interrupt-controller;
-				#interrupt-cells = <1>;
 			};
 		};
 
@@ -132,3 +128,40 @@
 		};
 	};
 };
+
+#include "axp209.dtsi"
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc2>;
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1500000>;
+	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-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_ldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index 3decefb..03deb84 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -47,8 +47,11 @@
  */
 
 /dts-v1/;
-/include/ "sun5i-a13.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A13-Olinuxino Micro";
@@ -64,7 +67,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxinom>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -86,22 +89,22 @@
 			mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
 				allwinner,pins = "PG0";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			led_pins_olinuxinom: led_pins@0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb1_vbus_pin_olinuxinom: usb1_vbus_pin@0 {
 				allwinner,pins = "PG11";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -137,14 +140,14 @@
 
 		power {
 			label = "a13-olinuxino-micro:green:power";
-			gpios = <&pio 6 9 0>;
+			gpios = <&pio 6 9 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_olinuxinom>;
-		gpio = <&pio 6 11 0>;
+		gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index b421f7f..6b24876 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -48,8 +48,12 @@
  */
 
 /dts-v1/;
-/include/ "sun5i-a13.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A13-Olinuxino";
@@ -65,7 +69,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_olinuxino>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 6 0 0>; /* PG0 */
+			cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -87,22 +91,62 @@
 			mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
 				allwinner,pins = "PG0";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PG9";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb1_vbus_pin_olinuxino: usb1_vbus_pin@0 {
 				allwinner,pins = "PG11";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+		};
+
+		lradc: lradc@01c22800 {
+			vref-supply = <&reg_vcc3v0>;
+			status = "okay";
+
+			button@191 {
+				label = "Volume Up";
+				linux,code = <KEY_VOLUMEUP>;
+				channel = <0>;
+				voltage = <191274>;
+			};
+
+			button@392 {
+				label = "Volume Down";
+				linux,code = <KEY_VOLUMEDOWN>;
+				channel = <0>;
+				voltage = <392644>;
+			};
+
+			button@601 {
+				label = "Menu";
+				linux,code = <KEY_MENU>;
+				channel = <0>;
+				voltage = <601151>;
+			};
+
+			button@795 {
+				label = "Enter";
+				linux,code = <KEY_ENTER>;
+				channel = <0>;
+				voltage = <795090>;
+			};
+
+			button@987 {
+				label = "Home";
+				linux,code = <KEY_HOMEPAGE>;
+				channel = <0>;
+				voltage = <987387>;
 			};
 		};
 
@@ -116,6 +160,15 @@
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c0_pins_a>;
 			status = "okay";
+
+			axp209: pmic@34 {
+				compatible = "x-powers,axp209";
+				reg = <0x34>;
+				interrupts = <0>;
+
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
 		};
 
 		i2c1: i2c@01c2b000 {
@@ -137,14 +190,14 @@
 		pinctrl-0 = <&led_pins_olinuxino>;
 
 		power {
-			gpios = <&pio 6 9 0>;
+			gpios = <&pio 6 9 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_olinuxino>;
-		gpio = <&pio 6 11 0>;
+		gpio = <&pio 6 11 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index c556688..4910393 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -11,18 +11,85 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/thermal/thermal.h>
+
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&intc>;
 
+	chosen {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		framebuffer@0 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0";
+			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			status = "disabled";
+		};
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		cpu@0 {
+
+		cpu0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a8";
 			reg = <0x0>;
+			clocks = <&cpu>;
+			clock-latency = <244144>; /* 8 32k periods */
+			operating-points = <
+				/* kHz    uV */
+				1104000	1500000
+				1008000 1400000
+				912000  1350000
+				864000  1300000
+				624000  1200000
+				576000  1200000
+				432000  1200000
+				>;
+			#cooling-cells = <2>;
+			cooling-min-level = <0>;
+			cooling-max-level = <6>;
+		};
+	};
+
+	thermal-zones {
+		cpu_thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&rtp>;
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					/* milliCelsius */
+					temperature = <850000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					/* milliCelsius */
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
 		};
 	};
 
@@ -299,7 +366,8 @@
 			interrupts = <10>;
 			clocks = <&ahb_gates 20>, <&spi0_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 27>, <&dma 1 26>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+			       <&dma SUN4I_DMA_DEDICATED 26>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -312,7 +380,8 @@
 			interrupts = <11>;
 			clocks = <&ahb_gates 21>, <&spi1_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 9>, <&dma 1 8>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+			       <&dma SUN4I_DMA_DEDICATED 8>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -375,7 +444,8 @@
 			interrupts = <12>;
 			clocks = <&ahb_gates 22>, <&spi2_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 29>, <&dma 1 28>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+			       <&dma SUN4I_DMA_DEDICATED 28>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -403,43 +473,43 @@
 			uart1_pins_a: uart1@0 {
 				allwinner,pins = "PE10", "PE11";
 				allwinner,function = "uart1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart1_pins_b: uart1@1 {
 				allwinner,pins = "PG3", "PG4";
 				allwinner,function = "uart1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PB0", "PB1";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PB15", "PB16";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PB17", "PB18";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -455,6 +525,13 @@
 			reg = <0x01c20c90 0x10>;
 		};
 
+		lradc: lradc@01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <31>;
+			status = "disabled";
+		};
+
 		sid: eeprom@01c23800 {
 			compatible = "allwinner,sun4i-a10-sid";
 			reg = <0x01c23800 0x10>;
@@ -464,6 +541,7 @@
 			compatible = "allwinner,sun4i-a10-ts";
 			reg = <0x01c25000 0x100>;
 			interrupts = <29>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		uart1: serial@01c28400 {
diff --git a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
index c74a63a..be9f5ee 100644
--- a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
+++ b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun6i-a31.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Allwinner A31 APP4 EVB1 Evaluation Board";
@@ -64,8 +67,8 @@
 			usb1_vbus_pin_a: usb1_vbus_pin@0 {
 				allwinner,pins = "PH27";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -87,7 +90,7 @@
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_a>;
-		gpio = <&pio 7 27 0>;
+		gpio = <&pio 7 27 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts
index c36b4dc..84630e5 100644
--- a/arch/arm/boot/dts/sun6i-a31-colombus.dts
+++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun6i-a31.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "WITS A31 Colombus Evaluation Board";
@@ -65,7 +68,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_colombus>;
 			vmmc-supply = <&reg_vcc3v0>;
 			bus-width = <4>;
-			cd-gpios = <&pio 0 8 0>; /* PA8 */
+			cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -81,21 +84,21 @@
 
 		pio: pinctrl@01c20800 {
 			mmc0_pins_a: mmc0@0 {
-				allwinner,pull = <1>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			mmc0_cd_pin_colombus: mmc0_cd_pin@0 {
 				allwinner,pins = "PA8";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			usb2_vbus_pin_colombus: usb2_vbus_pin@0 {
 				allwinner,pins = "PH24";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -127,7 +130,7 @@
 	reg_usb2_vbus: usb2-vbus {
 		pinctrl-names = "default";
 		pinctrl-0 = <&usb2_vbus_pin_colombus>;
-		gpio = <&pio 7 24 0>;
+		gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 6e924d9..8b61b1b 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -48,8 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun6i-a31.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Merrii A31 Hummingbird";
@@ -58,98 +61,96 @@
 	chosen {
 		bootargs = "earlyprintk console=ttyS0,115200";
 	};
+};
 
-	soc@01c00000 {
-		mmc0: mmc@01c0f000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
-			vmmc-supply = <&reg_vcc3v0>;
-			bus-width = <4>;
-			cd-gpios = <&pio 0 8 0>; /* PA8 */
-			cd-inverted;
-			status = "okay";
-		};
+&ehci0 {
+	status = "okay";
+};
 
-		usbphy: phy@01c19400 {
-			usb1_vbus-supply = <&reg_usb1_vbus>;
-			status = "okay";
-		};
+&gmac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac_pins_rgmii_a>;
+	phy = <&phy1>;
+	phy-mode = "rgmii";
+	snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 30000>;
+	status = "okay";
 
-		ehci0: usb@01c1a000 {
-			status = "okay";
-		};
-
-		ohci0: usb@01c1a400 {
-			status = "okay";
-		};
-
-		pio: pinctrl@01c20800 {
-			mmc0_pins_a: mmc0@0 {
-				/* external pull-ups missing for some pins */
-				allwinner,pull = <1>;
-			};
-
-			mmc0_cd_pin_hummingbird: mmc0_cd_pin@0 {
-				allwinner,pins = "PA8";
-				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
-			};
-
-			usb1_vbus_pin_a: usb1_vbus_pin@0 {
-				allwinner,pins = "PH24";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-		};
-
-		uart0: serial@01c28000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&uart0_pins_a>;
-			status = "okay";
-		};
-
-		i2c0: i2c@01c2ac00 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&i2c0_pins_a>;
-			/* pull-ups and devices require AXP221 DLDO3 */
-			status = "failed";
-		};
-
-		i2c1: i2c@01c2b000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&i2c1_pins_a>;
-			status = "okay";
-		};
-
-		i2c2: i2c@01c2b400 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&i2c2_pins_a>;
-			status = "okay";
-
-			pcf8563: rtc@51 {
-				compatible = "nxp,pcf8563";
-				reg = <0x51>;
-			};
-		};
-
-		gmac: ethernet@01c30000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&gmac_pins_rgmii_a>;
-			phy = <&phy1>;
-			phy-mode = "rgmii";
-			status = "okay";
-
-			phy1: ethernet-phy@1 {
-				reg = <1>;
-			};
-		};
+	phy1: ethernet-phy@1 {
+		reg = <1>;
 	};
+};
 
-	reg_usb1_vbus: usb1-vbus {
-		pinctrl-0 = <&usb1_vbus_pin_a>;
-		gpio = <&pio 7 24 0>; /* PH24 */
-		status = "okay";
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	/* pull-ups and devices require AXP221 DLDO3 */
+	status = "failed";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	status = "okay";
+
+	pcf8563: rtc@51 {
+		compatible = "nxp,pcf8563";
+		reg = <0x51>;
 	};
 };
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
+	vmmc-supply = <&reg_vcc3v0>;
+	bus-width = <4>;
+	cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc0_pins_a {
+	/* external pull-ups missing for some pins */
+	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&pio {
+	mmc0_cd_pin_hummingbird: mmc0_cd_pin@0 {
+		allwinner,pins = "PA8";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+	};
+};
+
+&reg_usb1_vbus {
+	gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&usb1_vbus_pin_a {
+	/* different pin from sunxi-common-regulators */
+	allwinner,pins = "PH24";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index 3ab544f..139a21e 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -46,8 +46,11 @@
  */
 
 /dts-v1/;
-/include/ "sun6i-a31.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun6i-a31.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Mele M9 / A1000G Quad top set box";
@@ -63,7 +66,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_m9>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 22 0>; /* PH22 */
+			cd-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -85,22 +88,22 @@
 			led_pins_m9: led_pins@0 {
 				allwinner,pins = "PH13";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_cd_pin_m9: mmc0_cd_pin@0 {
 				allwinner,pins = "PH22";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			usb1_vbus_pin_m9: usb1_vbus_pin@0 {
 				allwinner,pins = "PC27";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -121,6 +124,12 @@
 				reg = <1>;
 			};
 		};
+
+		ir@01f02000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&ir_pins_a>;
+			status = "okay";
+		};
 	};
 
 	leds {
@@ -130,14 +139,14 @@
 
 		blue {
 			label = "m9:blue:usr";
-			gpios = <&pio 7 13 0>;
+			gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-names = "default";
 		pinctrl-0 = <&usb1_vbus_pin_m9>;
-		gpio = <&pio 2 27 0>;
+		gpio = <&pio 2 27 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 1e7e7bc..47e5576 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -47,7 +47,11 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -67,6 +71,24 @@
 			clocks = <&pll6 0>;
 			status = "disabled";
 		};
+
+		framebuffer@1 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0";
+			clocks = <&pll6 0>;
+			status = "disabled";
+		};
+	};
+
+	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)>;
+		clock-frequency = <24000000>;
+		arm,cpu-registers-not-fw-configured;
 	};
 
 	cpus {
@@ -105,10 +127,10 @@
 
 	pmu {
 		compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
-		interrupts = <0 120 4>,
-			     <0 121 4>,
-			     <0 122 4>,
-			     <0 123 4>;
+		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>;
 	};
 
 	clocks {
@@ -355,7 +377,7 @@
 		dma: dma-controller@01c02000 {
 			compatible = "allwinner,sun6i-a31-dma";
 			reg = <0x01c02000 0x1000>;
-			interrupts = <0 50 4>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 6>;
 			resets = <&ahb1_rst 6>;
 			#dma-cells = <1>;
@@ -372,7 +394,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 8>;
 			reset-names = "ahb";
-			interrupts = <0 60 4>;
+			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -383,7 +405,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 9>;
 			reset-names = "ahb";
-			interrupts = <0 61 4>;
+			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -394,7 +416,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 10>;
 			reset-names = "ahb";
-			interrupts = <0 62 4>;
+			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -405,7 +427,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 11>;
 			reset-names = "ahb";
-			interrupts = <0 63 4>;
+			interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -436,7 +458,7 @@
 		ehci0: usb@01c1a000 {
 			compatible = "allwinner,sun6i-a31-ehci", "generic-ehci";
 			reg = <0x01c1a000 0x100>;
-			interrupts = <0 72 4>;
+			interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 26>;
 			resets = <&ahb1_rst 26>;
 			phys = <&usbphy 1>;
@@ -447,7 +469,7 @@
 		ohci0: usb@01c1a400 {
 			compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
 			reg = <0x01c1a400 0x100>;
-			interrupts = <0 73 4>;
+			interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 29>, <&usb_clk 16>;
 			resets = <&ahb1_rst 29>;
 			phys = <&usbphy 1>;
@@ -458,7 +480,7 @@
 		ehci1: usb@01c1b000 {
 			compatible = "allwinner,sun6i-a31-ehci", "generic-ehci";
 			reg = <0x01c1b000 0x100>;
-			interrupts = <0 74 4>;
+			interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 27>;
 			resets = <&ahb1_rst 27>;
 			phys = <&usbphy 2>;
@@ -469,7 +491,7 @@
 		ohci1: usb@01c1b400 {
 			compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
 			reg = <0x01c1b400 0x100>;
-			interrupts = <0 75 4>;
+			interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 30>, <&usb_clk 17>;
 			resets = <&ahb1_rst 30>;
 			phys = <&usbphy 2>;
@@ -480,7 +502,7 @@
 		ohci2: usb@01c1c400 {
 			compatible = "allwinner,sun6i-a31-ohci", "generic-ohci";
 			reg = <0x01c1c400 0x100>;
-			interrupts = <0 77 4>;
+			interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 31>, <&usb_clk 18>;
 			resets = <&ahb1_rst 31>;
 			status = "disabled";
@@ -489,10 +511,10 @@
 		pio: pinctrl@01c20800 {
 			compatible = "allwinner,sun6i-a31-pinctrl";
 			reg = <0x01c20800 0x400>;
-			interrupts = <0 11 4>,
-				     <0 15 4>,
-				     <0 16 4>,
-				     <0 17 4>;
+			interrupts = <GIC_SPI 11 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 = <&apb1_gates 5>;
 			gpio-controller;
 			interrupt-controller;
@@ -503,36 +525,36 @@
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PH14", "PH15";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PH16", "PH17";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PH18", "PH19";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_pins_mii_a: gmac_mii@0 {
@@ -542,8 +564,8 @@
 						"PA20", "PA21", "PA22", "PA23",
 						"PA24", "PA26", "PA27";
 				allwinner,function = "gmac";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_pins_gmii_a: gmac_gmii@0 {
@@ -559,8 +581,8 @@
 				 * data lines in GMII mode run at 125MHz and
 				 * might need a higher signal drive strength
 				 */
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_pins_rgmii_a: gmac_rgmii@0 {
@@ -573,8 +595,8 @@
 				 * data lines in RGMII mode use DDR mode
 				 * and need a higher signal drive strength
 				 */
-				allwinner,drive = <3>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -599,11 +621,11 @@
 		timer@01c20c00 {
 			compatible = "allwinner,sun4i-a10-timer";
 			reg = <0x01c20c00 0xa0>;
-			interrupts = <0 18 4>,
-				     <0 19 4>,
-				     <0 20 4>,
-				     <0 21 4>,
-				     <0 22 4>;
+			interrupts = <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>;
 			clocks = <&osc24M>;
 		};
 
@@ -612,10 +634,17 @@
 			reg = <0x01c20ca0 0x20>;
 		};
 
+		rtp: rtp@01c25000 {
+			compatible = "allwinner,sun6i-a31-ts";
+			reg = <0x01c25000 0x100>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+			#thermal-sensor-cells = <0>;
+		};
+
 		uart0: serial@01c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
-			interrupts = <0 0 4>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 16>;
@@ -628,7 +657,7 @@
 		uart1: serial@01c28400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28400 0x400>;
-			interrupts = <0 1 4>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 17>;
@@ -641,7 +670,7 @@
 		uart2: serial@01c28800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28800 0x400>;
-			interrupts = <0 2 4>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 18>;
@@ -654,7 +683,7 @@
 		uart3: serial@01c28c00 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28c00 0x400>;
-			interrupts = <0 3 4>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 19>;
@@ -667,7 +696,7 @@
 		uart4: serial@01c29000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29000 0x400>;
-			interrupts = <0 4 4>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 20>;
@@ -680,7 +709,7 @@
 		uart5: serial@01c29400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29400 0x400>;
-			interrupts = <0 5 4>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 21>;
@@ -693,7 +722,7 @@
 		i2c0: i2c@01c2ac00 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2ac00 0x400>;
-			interrupts = <0 6 4>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 0>;
 			resets = <&apb2_rst 0>;
 			status = "disabled";
@@ -704,7 +733,7 @@
 		i2c1: i2c@01c2b000 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2b000 0x400>;
-			interrupts = <0 7 4>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 1>;
 			resets = <&apb2_rst 1>;
 			status = "disabled";
@@ -715,7 +744,7 @@
 		i2c2: i2c@01c2b400 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2b400 0x400>;
-			interrupts = <0 8 4>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 2>;
 			resets = <&apb2_rst 2>;
 			status = "disabled";
@@ -726,7 +755,7 @@
 		i2c3: i2c@01c2b800 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2b800 0x400>;
-			interrupts = <0 9 4>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 3>;
 			resets = <&apb2_rst 3>;
 			status = "disabled";
@@ -737,7 +766,7 @@
 		gmac: ethernet@01c30000 {
 			compatible = "allwinner,sun7i-a20-gmac";
 			reg = <0x01c30000 0x1054>;
-			interrupts = <0 82 4>;
+			interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
 			clocks = <&ahb1_gates 17>, <&gmac_tx_clk>;
 			clock-names = "stmmaceth", "allwinner_gmac_tx";
@@ -754,10 +783,10 @@
 		timer@01c60000 {
 			compatible = "allwinner,sun6i-a31-hstimer", "allwinner,sun7i-a20-hstimer";
 			reg = <0x01c60000 0x1000>;
-			interrupts = <0 51 4>,
-				     <0 52 4>,
-				     <0 53 4>,
-				     <0 54 4>;
+			interrupts = <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>;
 			clocks = <&ahb1_gates 19>;
 			resets = <&ahb1_rst 19>;
 		};
@@ -765,7 +794,7 @@
 		spi0: spi@01c68000 {
 			compatible = "allwinner,sun6i-a31-spi";
 			reg = <0x01c68000 0x1000>;
-			interrupts = <0 65 4>;
+			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 20>, <&spi0_clk>;
 			clock-names = "ahb", "mod";
 			dmas = <&dma 23>, <&dma 23>;
@@ -777,7 +806,7 @@
 		spi1: spi@01c69000 {
 			compatible = "allwinner,sun6i-a31-spi";
 			reg = <0x01c69000 0x1000>;
-			interrupts = <0 66 4>;
+			interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 21>, <&spi1_clk>;
 			clock-names = "ahb", "mod";
 			dmas = <&dma 24>, <&dma 24>;
@@ -789,7 +818,7 @@
 		spi2: spi@01c6a000 {
 			compatible = "allwinner,sun6i-a31-spi";
 			reg = <0x01c6a000 0x1000>;
-			interrupts = <0 67 4>;
+			interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 22>, <&spi2_clk>;
 			clock-names = "ahb", "mod";
 			dmas = <&dma 25>, <&dma 25>;
@@ -801,7 +830,7 @@
 		spi3: spi@01c6b000 {
 			compatible = "allwinner,sun6i-a31-spi";
 			reg = <0x01c6b000 0x1000>;
-			interrupts = <0 68 4>;
+			interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 23>, <&spi3_clk>;
 			clock-names = "ahb", "mod";
 			dmas = <&dma 26>, <&dma 26>;
@@ -818,13 +847,14 @@
 			      <0x01c86000 0x2000>;
 			interrupt-controller;
 			#interrupt-cells = <3>;
-			interrupts = <1 9 0xf04>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
 		rtc: rtc@01f00000 {
 			compatible = "allwinner,sun6i-a31-rtc";
 			reg = <0x01f00000 0x54>;
-			interrupts = <0 40 4>, <0 41 4>;
+			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		nmi_intc: interrupt-controller@01f00c0c {
@@ -832,7 +862,7 @@
 			interrupt-controller;
 			#interrupt-cells = <2>;
 			reg = <0x01f00c0c 0x38>;
-			interrupts = <0 32 4>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		prcm@01f01400 {
@@ -872,6 +902,13 @@
 						"apb0_i2c";
 			};
 
+			ir_clk: ir_clk {
+				#clock-cells = <0>;
+				compatible = "allwinner,sun4i-a10-mod0-clk";
+				clocks = <&osc32k>, <&osc24M>;
+				clock-output-names = "ir";
+			};
+
 			apb0_rst: apb0_rst {
 				compatible = "allwinner,sun6i-a31-clock-reset";
 				#reset-cells = <1>;
@@ -883,11 +920,21 @@
 			reg = <0x01f01c00 0x300>;
 		};
 
+		ir: ir@01f02000 {
+			compatible = "allwinner,sun5i-a13-ir";
+			clocks = <&apb0_gates 1>, <&ir_clk>;
+			clock-names = "apb", "ir";
+			resets = <&apb0_rst 1>;
+			interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+			reg = <0x01f02000 0x40>;
+			status = "disabled";
+		};
+
 		r_pio: pinctrl@01f02c00 {
 			compatible = "allwinner,sun6i-a31-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
-			interrupts = <0 45 4>,
-				     <0 46 4>;
+			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>;
 			resets = <&apb0_rst 0>;
 			gpio-controller;
@@ -895,6 +942,13 @@
 			#interrupt-cells = <2>;
 			#size-cells = <0>;
 			#gpio-cells = <3>;
+
+			ir_pins_a: ir@0 {
+				allwinner,pins = "PL4";
+				allwinner,function = "s_ir";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31s-cs908.dts b/arch/arm/boot/dts/sun6i-a31s-cs908.dts
new file mode 100644
index 0000000..bc3734f
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-cs908.dts
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.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 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.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	model = "CSQ CS908 top set box";
+	compatible = "csq,cs908", "allwinner,sun6i-a31s";
+};
+
+&usbphy {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	usb1_vbus_pin_csq908: usb1_vbus_pin@0 {
+		allwinner,pins = "PC27";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&gmac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac_pins_mii_a>;
+	phy = <&phy1>;
+	phy-mode = "mii";
+	status = "okay";
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+};
+
+&ir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ir_pins_a>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31s.dtsi b/arch/arm/boot/dts/sun6i-a31s.dtsi
new file mode 100644
index 0000000..eaf5ec8
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s.dtsi
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.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 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.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+/*
+ * The A31s is the same die as the A31 in a different package, this is
+ * reflected by it having different pinctrl compatible everything else is
+ * identical.
+ */
+
+#include "sun6i-a31.dtsi"
+
+&pio {
+	compatible = "allwinner,sun6i-a31s-pinctrl";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index bd7b15a..5dd139e 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -48,8 +48,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "LeMaker Banana Pi";
@@ -73,7 +77,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 10 0>; /* PH10 */
+			cd-gpios = <&pio 7 10 GPIO_ACTIVE_HIGH>; /* PH10 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -108,22 +112,22 @@
 			mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
 				allwinner,pins = "PH10";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			gmac_power_pin_bananapi: gmac_power_pin@0 {
 				allwinner,pins = "PH23";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_bananapi: led_pins@0 {
 				allwinner,pins = "PH24";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -160,7 +164,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -194,7 +198,7 @@
 
 		green {
 			label = "bananapi:green:usr";
-			gpios = <&pio 7 24 0>;
+			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -215,6 +219,6 @@
 		regulator-max-microvolt = <3300000>;
 		startup-delay-us = <100000>;
 		enable-active-high;
-		gpio = <&pio 7 23 0>;
+		gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapro.dts b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
new file mode 100644
index 0000000..fb89fe7
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	model = "LeMaker Banana Pro";
+	compatible = "lemaker,bananapro", "allwinner,sun7i-a20";
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins_bananapro>;
+
+		blue {
+			label = "bananapro:blue:usr";
+			gpios = <&pio 6 2 GPIO_ACTIVE_HIGH>;
+		};
+
+		green {
+			label = "bananapro:green:usr";
+			gpios = <&pio 7 24 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	reg_gmac_3v3: gmac-3v3 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&gmac_power_pin_bananapro>;
+		regulator-name = "gmac-3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <100000>;
+		enable-active-high;
+		gpio = <&pio 7 23 GPIO_ACTIVE_HIGH>;
+	};
+
+	reg_vmmc3: vmmc3 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&vmmc3_pin_bananapro>;
+		regulator-name = "vmmc3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		enable-active-high;
+		gpio = <&pio 7 22 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&ahci {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&gmac {
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac_pins_rgmii_a>;
+	phy = <&phy1>;
+	phy-mode = "rgmii";
+	phy-supply = <&reg_gmac_3v3>;
+	status = "okay";
+
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic@34 {
+		compatible = "x-powers,axp209";
+		reg = <0x34>;
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	status = "okay";
+};
+
+&ir0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ir0_pins_a>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	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;
+	status = "okay";
+};
+
+&mmc3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc3_pins_a>;
+	vmmc-supply = <&reg_vmmc3>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	gmac_power_pin_bananapro: gmac_power_pin@0 {
+		allwinner,pins = "PH23";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	led_pins_bananapro: led_pins@0 {
+		allwinner,pins = "PH24", "PG2";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	mmc0_cd_pin_bananapro: mmc0_cd_pin@0 {
+		allwinner,pins = "PH10";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+	};
+
+	usb1_vbus_pin_bananapro: usb1_vbus_pin@0 {
+		allwinner,pins = "PH0";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	usb2_vbus_pin_bananapro: usb2_vbus_pin@0 {
+		allwinner,pins = "PH1";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	vmmc3_pin_bananapro: vmmc3_pin@0 {
+		allwinner,pins = "PH22";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&reg_usb1_vbus {
+	pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+	gpio = <&pio 7 0 GPIO_ACTIVE_HIGH>; /* PH0 */
+	status = "okay";
+};
+
+&reg_usb2_vbus {
+	pinctrl-0 = <&usb2_vbus_pin_bananapro>;
+	gpio = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins_a>;
+	status = "okay";
+};
+
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart7_pins_a>;
+	status = "okay";
+};
+
+&usbphy {
+	usb1_vbus-supply = <&reg_usb1_vbus>;
+	usb2_vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 5368098..c4ab6ed 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -3,17 +3,57 @@
  *
  * Maxime Ripard <maxime.ripard@free-electrons.com>
  *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * 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.
  *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ *  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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Cubietech Cubieboard2";
@@ -25,7 +65,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -61,8 +101,8 @@
 			led_pins_cubieboard2: led_pins@0 {
 				allwinner,pins = "PH20", "PH21";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -84,13 +124,9 @@
 			status = "okay";
 
 			axp209: pmic@34 {
-				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
-
-				interrupt-controller;
-				#interrupt-cells = <1>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 			};
 		};
 
@@ -120,12 +156,12 @@
 
 		blue {
 			label = "cubieboard2:blue:usr";
-			gpios = <&pio 7 21 0>;
+			gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>;
 		};
 
 		green {
 			label = "cubieboard2:green:usr";
-			gpios = <&pio 7 20 0>;
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -141,3 +177,34 @@
 		status = "okay";
 	};
 };
+
+#include "axp209.dtsi"
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc2>;
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1450000>;
+	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-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index a281d25..8f74a64 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -3,17 +3,57 @@
  *
  * Oliver Schinagl <oliver@schinagl.nl>
  *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * 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.
  *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ *  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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Cubietech Cubietruck";
@@ -25,7 +65,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -70,35 +110,35 @@
 		pinctrl@01c20800 {
 			mmc3_pins_a: mmc3@0 {
 				/* AP6210 requires pull-up */
-				allwinner,pull = <1>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			vmmc3_pin_cubietruck: vmmc3_pin@0 {
 				allwinner,pins = "PH9";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
 				allwinner,pins = "PH12";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_cubietruck: led_pins@0 {
 				allwinner,pins = "PH7", "PH11", "PH20", "PH21";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb0_vbus_pin_a: usb0_vbus_pin@0 {
 				allwinner,pins = "PH17";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -126,13 +166,9 @@
 			status = "okay";
 
 			axp209: pmic@34 {
-				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
-
-				interrupt-controller;
-				#interrupt-cells = <1>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 			};
 		};
 
@@ -168,34 +204,34 @@
 
 		blue {
 			label = "cubietruck:blue:usr";
-			gpios = <&pio 7 21 0>;
+			gpios = <&pio 7 21 GPIO_ACTIVE_HIGH>;
 		};
 
 		orange {
 			label = "cubietruck:orange:usr";
-			gpios = <&pio 7 20 0>;
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
 		};
 
 		white {
 			label = "cubietruck:white:usr";
-			gpios = <&pio 7 11 0>;
+			gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;
 		};
 
 		green {
 			label = "cubietruck:green:usr";
-			gpios = <&pio 7 7 0>;
+			gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
 	reg_ahci_5v: ahci-5v {
 		pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
-		gpio = <&pio 7 12 0>;
+		gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 
 	reg_usb0_vbus: usb0-vbus {
 		pinctrl-0 = <&usb0_vbus_pin_a>;
-		gpio = <&pio 7 17 0>;
+		gpio = <&pio 7 17 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 
@@ -215,6 +251,37 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		enable-active-high;
-		gpio = <&pio 7 9 0>;
+		gpio = <&pio 7 9 GPIO_ACTIVE_HIGH>;
 	};
 };
+
+#include "axp209.dtsi"
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc2>;
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1450000>;
+	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-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
index 0bcefcb..86a944c 100644
--- a/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
+++ b/arch/arm/boot/dts/sun7i-a20-hummingbird.dts
@@ -12,8 +12,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Merrii A20 Hummingbird";
@@ -33,7 +37,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v0>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -78,29 +82,29 @@
 			ahci_pwr_pin_a20_hummingbird: ahci_pwr_pin@0 {
 				allwinner,pins = "PH15";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			usb1_vbus_pin_a20_hummingbird: usb1_vbus_pin@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc3_vdd_pin_a20_hummingbird: mmc3_vdd_pin@0 {
 				allwinner,pins = "PH9";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_vdd_pin_a20_hummingbird: gmac_vdd_pin@0 {
 				allwinner,pins = "PH16";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -155,7 +159,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 				interrupt-controller;
 				#interrupt-cells = <1>;
 			};
@@ -192,7 +196,7 @@
 			phy-mode = "rgmii";
 			phy-supply = <&reg_gmac_vdd>;
 			/* phy reset config */
-			snps,reset-gpio = <&pio 0 17 0>; /* PA17 */
+			snps,reset-gpio = <&pio 0 17 GPIO_ACTIVE_HIGH>; /* PA17 */
 			snps,reset-active-low;
 			/* wait 1s after reset, otherwise fail to read phy id */
 			snps,reset-delays-us = <0 10000 1000000>;
@@ -206,13 +210,13 @@
 
 	reg_ahci_5v: ahci-5v {
 		pinctrl-0 = <&ahci_pwr_pin_a20_hummingbird>;
-		gpio = <&pio 7 15 0>; /* PH15 */
+		gpio = <&pio 7 15 GPIO_ACTIVE_HIGH>; /* PH15 */
 		status = "okay";
 	};
 
 	reg_usb1_vbus: usb1-vbus {
 		pinctrl-0 = <&usb1_vbus_pin_a20_hummingbird>;
-		gpio = <&pio 7 2 0>; /* PH2 */
+		gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
 		status = "okay";
 	};
 
@@ -228,7 +232,7 @@
 		regulator-min-microvolt = <3000000>;
 		regulator-max-microvolt = <3000000>;
 		enable-active-high;
-		gpio = <&pio 7 9 0>; /* PH9 */
+		gpio = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
 	};
 
 	reg_gmac_vdd: gmac_vdd {
@@ -239,6 +243,6 @@
 		regulator-min-microvolt = <3000000>;
 		regulator-max-microvolt = <3000000>;
 		enable-active-high;
-		gpio = <&pio 7 16 0>; /* PH16 */
+		gpio = <&pio 7 16 GPIO_ACTIVE_HIGH>; /* PH16 */
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
index f38bb1a..06148b4 100644
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -46,8 +46,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "I12 / Q5 / QT840A A20 tvbox";
@@ -59,7 +63,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -98,35 +102,35 @@
 		pinctrl@01c20800 {
 			mmc3_pins_a: mmc3@0 {
 				/* AP6210 / AP6330 requires pull-up */
-				allwinner,pull = <1>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			vmmc3_pin_i12_tvbox: vmmc3_pin@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			vmmc3_io_pin_i12_tvbox: vmmc3_io_pin@0 {
 				allwinner,pins = "PH12";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_power_pin_i12_tvbox: gmac_power_pin@0 {
 				allwinner,pins = "PH21";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_i12_tvbox: led_pins@0 {
 				allwinner,pins = "PH9", "PH20";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -151,7 +155,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -179,12 +183,12 @@
 
 		red {
 			label = "i12_tvbox:red:usr";
-			gpios = <&pio 7 9 1>;
+			gpios = <&pio 7 9 GPIO_ACTIVE_LOW>;
 		};
 
 		blue {
 			label = "i12_tvbox:blue:usr";
-			gpios = <&pio 7 20 0>;
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -204,7 +208,7 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		enable-active-high;
-		gpio = <&pio 7 2 0>;
+		gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 	};
 
 	reg_vmmc3_io: vmmc3-io {
@@ -217,7 +221,7 @@
 		/* This controls VCC-PI, must be always on! */
 		regulator-always-on;
 		enable-active-high;
-		gpio = <&pio 7 12 0>;
+		gpio = <&pio 7 12 GPIO_ACTIVE_HIGH>;
 	};
 
 	reg_gmac_3v3: gmac-3v3 {
@@ -229,6 +233,6 @@
 		regulator-max-microvolt = <3300000>;
 		startup-delay-us = <50000>;
 		enable-active-high;
-		gpio = <&pio 7 21 0>;
+		gpio = <&pio 7 21 GPIO_ACTIVE_HIGH>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts
index b8e568c..5add9f2 100644
--- a/arch/arm/boot/dts/sun7i-a20-m3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-m3.dts
@@ -48,8 +48,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Mele M3";
@@ -61,7 +65,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -101,8 +105,8 @@
 			led_pins_m3: led_pins@0 {
 				allwinner,pins = "PH20";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -127,7 +131,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -154,7 +158,7 @@
 
 		blue {
 			label = "m3:blue:usr";
-			gpios = <&pio 7 20 0>;
+			gpios = <&pio 7 20 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
index 3f3ff96..12ded69 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
@@ -49,8 +49,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A20-OLinuXino-LIME";
@@ -62,7 +66,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -98,15 +102,15 @@
 			ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
 				allwinner,pins = "PC3";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_olinuxinolime: led_pins@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -125,7 +129,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -152,14 +156,14 @@
 
 		green {
 			label = "a20-olinuxino-lime:green:usr";
-			gpios = <&pio 7 2 0>;
+			gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_ahci_5v: ahci-5v {
 		pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
-		gpio = <&pio 2 3 0>;
+		gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
 		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 ed364d5..260dbd3 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -46,8 +46,12 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#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/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A20-OLinuXino-LIME2";
@@ -59,7 +63,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -95,15 +99,15 @@
 			ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
 				allwinner,pins = "PC3";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			led_pins_olinuxinolime: led_pins@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -122,7 +126,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -199,14 +203,14 @@
 
 		green {
 			label = "a20-olinuxino-lime2:green:usr";
-			gpios = <&pio 7 2 0>;
+			gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
 
 	reg_ahci_5v: ahci-5v {
 		pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
-		gpio = <&pio 2 3 0>;
+		gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
 		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 66cc777..714e15a 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -12,8 +12,13 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Olimex A20-Olinuxino Micro";
@@ -39,7 +44,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -49,7 +54,7 @@
 			pinctrl-0 = <&mmc3_pins_a>, <&mmc3_cd_pin_olinuxinom>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 11 0>; /* PH11 */
+			cd-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -91,15 +96,69 @@
 			mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
 				allwinner,pins = "PH11";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			led_pins_olinuxino: led_pins@0 {
 				allwinner,pins = "PH2";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <1>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+		};
+
+		lradc: lradc@01c22800 {
+			vref-supply = <&reg_vcc3v0>;
+			status = "okay";
+
+			button@191 {
+				label = "Volume Up";
+				linux,code = <KEY_VOLUMEUP>;
+				channel = <0>;
+				voltage = <191274>;
+			};
+
+			button@392 {
+				label = "Volume Down";
+				linux,code = <KEY_VOLUMEDOWN>;
+				channel = <0>;
+				voltage = <392644>;
+			};
+
+			button@601 {
+				label = "Menu";
+				linux,code = <KEY_MENU>;
+				channel = <0>;
+				voltage = <601151>;
+			};
+
+			button@795 {
+				label = "Search";
+				linux,code = <KEY_SEARCH>;
+				channel = <0>;
+				voltage = <795090>;
+			};
+
+			button@987 {
+				label = "Home";
+				linux,code = <KEY_HOMEPAGE>;
+				channel = <0>;
+				voltage = <987387>;
+			};
+
+			button@1184 {
+				label = "Esc";
+				linux,code = <KEY_ESC>;
+				channel = <0>;
+				voltage = <1184678>;
+			};
+
+			button@1398 {
+				label = "Enter";
+				linux,code = <KEY_ENTER>;
+				channel = <0>;
+				voltage = <1398804>;
 			};
 		};
 
@@ -130,7 +189,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -169,7 +228,7 @@
 
 		green {
 			label = "a20-olinuxino-micro:green:usr";
-			gpios = <&pio 7 2 0>;
+			gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 			default-state = "on";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index 8dca49b..0a2c2ae 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -47,10 +47,13 @@
  */
 
 /dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "LinkSprite pcDuino3";
@@ -62,7 +65,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 			vmmc-supply = <&reg_vcc3v3>;
 			bus-width = <4>;
-			cd-gpios = <&pio 7 1 0>; /* PH1 */
+			cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -102,15 +105,15 @@
 			led_pins_pcduino3: led_pins@0 {
 				allwinner,pins = "PH15", "PH16";
 				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			key_pins_pcduino3: key_pins@0 {
 				allwinner,pins = "PH17", "PH18", "PH19";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -135,7 +138,7 @@
 				compatible = "x-powers,axp209";
 				reg = <0x34>;
 				interrupt-parent = <&nmi_intc>;
-				interrupts = <0 8>;
+				interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 
 				interrupt-controller;
 				#interrupt-cells = <1>;
@@ -203,7 +206,7 @@
 	};
 
 	reg_ahci_5v: ahci-5v {
-		gpio = <&pio 7 2 0>;
+		gpio = <&pio 7 2 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 89749ce..786d491 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -47,7 +47,13 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/thermal/thermal.h>
+
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -68,16 +74,49 @@
 				 <&ahb_gates 44>;
 			status = "disabled";
 		};
+
+		framebuffer@1 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0";
+			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			status = "disabled";
+		};
+
+		framebuffer@2 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0-tve0";
+			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+				 <&ahb_gates 44>;
+			status = "disabled";
+		};
 	};
 
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		cpu@0 {
+		cpu0: cpu@0 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&cpu>;
+			clock-latency = <244144>; /* 8 32k periods */
+			operating-points = <
+				/* kHz    uV */
+				1008000 1450000
+				960000  1400000
+				912000  1400000
+				864000  1300000
+				720000  1200000
+				528000  1100000
+				312000  1000000
+				144000  900000
+				>;
+			#cooling-cells = <2>;
+			cooling-min-level = <0>;
+			cooling-max-level = <7>;
 		};
 
 		cpu@1 {
@@ -87,22 +126,54 @@
 		};
 	};
 
+	thermal-zones {
+		cpu_thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&rtp>;
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					/* milliCelsius */
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_crit: cpu_crit {
+					/* milliCelsius */
+					temperature = <100000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+		};
+	};
+
 	memory {
 		reg = <0x40000000 0x80000000>;
 	};
 
 	timer {
 		compatible = "arm,armv7-timer";
-		interrupts = <1 13 0xf08>,
-			     <1 14 0xf08>,
-			     <1 11 0xf08>,
-			     <1 10 0xf08>;
+		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)>;
 	};
 
 	pmu {
 		compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
-		interrupts = <0 120 4>,
-			     <0 121 4>;
+		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
 	clocks {
@@ -454,13 +525,13 @@
 			interrupt-controller;
 			#interrupt-cells = <2>;
 			reg = <0x01c00030 0x0c>;
-			interrupts = <0 0 4>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		dma: dma-controller@01c02000 {
 			compatible = "allwinner,sun4i-a10-dma";
 			reg = <0x01c02000 0x1000>;
-			interrupts = <0 27 4>;
+			interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 6>;
 			#dma-cells = <2>;
 		};
@@ -468,10 +539,11 @@
 		spi0: spi@01c05000 {
 			compatible = "allwinner,sun4i-a10-spi";
 			reg = <0x01c05000 0x1000>;
-			interrupts = <0 10 4>;
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 20>, <&spi0_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 27>, <&dma 1 26>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+			       <&dma SUN4I_DMA_DEDICATED 26>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -481,10 +553,11 @@
 		spi1: spi@01c06000 {
 			compatible = "allwinner,sun4i-a10-spi";
 			reg = <0x01c06000 0x1000>;
-			interrupts = <0 11 4>;
+			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 21>, <&spi1_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 9>, <&dma 1 8>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+			       <&dma SUN4I_DMA_DEDICATED 8>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -494,12 +567,12 @@
 		emac: ethernet@01c0b000 {
 			compatible = "allwinner,sun4i-a10-emac";
 			reg = <0x01c0b000 0x1000>;
-			interrupts = <0 55 4>;
+			interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 17>;
 			status = "disabled";
 		};
 
-		mdio@01c0b080 {
+		mdio: mdio@01c0b080 {
 			compatible = "allwinner,sun4i-a10-mdio";
 			reg = <0x01c0b080 0x14>;
 			status = "disabled";
@@ -512,7 +585,7 @@
 			reg = <0x01c0f000 0x1000>;
 			clocks = <&ahb_gates 8>, <&mmc0_clk>;
 			clock-names = "ahb", "mmc";
-			interrupts = <0 32 4>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -521,7 +594,7 @@
 			reg = <0x01c10000 0x1000>;
 			clocks = <&ahb_gates 9>, <&mmc1_clk>;
 			clock-names = "ahb", "mmc";
-			interrupts = <0 33 4>;
+			interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -530,7 +603,7 @@
 			reg = <0x01c11000 0x1000>;
 			clocks = <&ahb_gates 10>, <&mmc2_clk>;
 			clock-names = "ahb", "mmc";
-			interrupts = <0 34 4>;
+			interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -539,7 +612,7 @@
 			reg = <0x01c12000 0x1000>;
 			clocks = <&ahb_gates 11>, <&mmc3_clk>;
 			clock-names = "ahb", "mmc";
-			interrupts = <0 35 4>;
+			interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -558,7 +631,7 @@
 		ehci0: usb@01c14000 {
 			compatible = "allwinner,sun7i-a20-ehci", "generic-ehci";
 			reg = <0x01c14000 0x100>;
-			interrupts = <0 39 4>;
+			interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 1>;
 			phys = <&usbphy 1>;
 			phy-names = "usb";
@@ -568,7 +641,7 @@
 		ohci0: usb@01c14400 {
 			compatible = "allwinner,sun7i-a20-ohci", "generic-ohci";
 			reg = <0x01c14400 0x100>;
-			interrupts = <0 64 4>;
+			interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&usb_clk 6>, <&ahb_gates 2>;
 			phys = <&usbphy 1>;
 			phy-names = "usb";
@@ -578,10 +651,11 @@
 		spi2: spi@01c17000 {
 			compatible = "allwinner,sun4i-a10-spi";
 			reg = <0x01c17000 0x1000>;
-			interrupts = <0 12 4>;
+			interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 22>, <&spi2_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 29>, <&dma 1 28>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+			       <&dma SUN4I_DMA_DEDICATED 28>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -591,7 +665,7 @@
 		ahci: sata@01c18000 {
 			compatible = "allwinner,sun4i-a10-ahci";
 			reg = <0x01c18000 0x1000>;
-			interrupts = <0 56 4>;
+			interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&pll6 0>, <&ahb_gates 25>;
 			status = "disabled";
 		};
@@ -599,7 +673,7 @@
 		ehci1: usb@01c1c000 {
 			compatible = "allwinner,sun7i-a20-ehci", "generic-ehci";
 			reg = <0x01c1c000 0x100>;
-			interrupts = <0 40 4>;
+			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 3>;
 			phys = <&usbphy 2>;
 			phy-names = "usb";
@@ -609,7 +683,7 @@
 		ohci1: usb@01c1c400 {
 			compatible = "allwinner,sun7i-a20-ohci", "generic-ohci";
 			reg = <0x01c1c400 0x100>;
-			interrupts = <0 65 4>;
+			interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&usb_clk 7>, <&ahb_gates 4>;
 			phys = <&usbphy 2>;
 			phy-names = "usb";
@@ -619,10 +693,11 @@
 		spi3: spi@01c1f000 {
 			compatible = "allwinner,sun4i-a10-spi";
 			reg = <0x01c1f000 0x1000>;
-			interrupts = <0 50 4>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 23>, <&spi3_clk>;
 			clock-names = "ahb", "mod";
-			dmas = <&dma 1 31>, <&dma 1 30>;
+			dmas = <&dma SUN4I_DMA_DEDICATED 31>,
+			       <&dma SUN4I_DMA_DEDICATED 30>;
 			dma-names = "rx", "tx";
 			status = "disabled";
 			#address-cells = <1>;
@@ -632,7 +707,7 @@
 		pio: pinctrl@01c20800 {
 			compatible = "allwinner,sun7i-a20-pinctrl";
 			reg = <0x01c20800 0x400>;
-			interrupts = <0 28 4>;
+			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 5>;
 			gpio-controller;
 			interrupt-controller;
@@ -643,99 +718,99 @@
 			pwm0_pins_a: pwm0@0 {
 				allwinner,pins = "PB2";
 				allwinner,function = "pwm";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			pwm1_pins_a: pwm1@0 {
 				allwinner,pins = "PI3";
 				allwinner,function = "pwm";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PB22", "PB23";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart2_pins_a: uart2@0 {
 				allwinner,pins = "PI16", "PI17", "PI18", "PI19";
 				allwinner,function = "uart2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart3_pins_a: uart3@0 {
 				allwinner,pins = "PG6", "PG7", "PG8", "PG9";
 				allwinner,function = "uart3";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart3_pins_b: uart3@1 {
 				allwinner,pins = "PH0", "PH1";
 				allwinner,function = "uart3";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart4_pins_a: uart4@0 {
 				allwinner,pins = "PG10", "PG11";
 				allwinner,function = "uart4";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart5_pins_a: uart5@0 {
 				allwinner,pins = "PI10", "PI11";
 				allwinner,function = "uart5";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart6_pins_a: uart6@0 {
 				allwinner,pins = "PI12", "PI13";
 				allwinner,function = "uart6";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart7_pins_a: uart7@0 {
 				allwinner,pins = "PI20", "PI21";
 				allwinner,function = "uart7";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PB0", "PB1";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PB18", "PB19";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PB20", "PB21";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c3_pins_a: i2c3@0 {
 				allwinner,pins = "PI0", "PI1";
 				allwinner,function = "i2c3";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			emac_pins_a: emac0@0 {
@@ -745,22 +820,22 @@
 						"PA11", "PA12", "PA13", "PA14",
 						"PA15", "PA16";
 				allwinner,function = "emac";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			clk_out_a_pins_a: clk_out_a@0 {
 				allwinner,pins = "PI12";
 				allwinner,function = "clk_out_a";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			clk_out_b_pins_a: clk_out_b@0 {
 				allwinner,pins = "PI13";
 				allwinner,function = "clk_out_b";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_pins_mii_a: gmac_mii@0 {
@@ -770,8 +845,8 @@
 						"PA11", "PA12", "PA13", "PA14",
 						"PA15", "PA16";
 				allwinner,function = "gmac";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			gmac_pins_rgmii_a: gmac_rgmii@0 {
@@ -785,90 +860,104 @@
 				 * data lines in RGMII mode use DDR mode
 				 * and need a higher signal drive strength
 				 */
-				allwinner,drive = <3>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_40_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			spi0_pins_a: spi0@0 {
 				allwinner,pins = "PI10", "PI11", "PI12", "PI13", "PI14";
 				allwinner,function = "spi0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			spi1_pins_a: spi1@0 {
 				allwinner,pins = "PI16", "PI17", "PI18", "PI19";
 				allwinner,function = "spi1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			spi2_pins_a: spi2@0 {
 				allwinner,pins = "PC19", "PC20", "PC21", "PC22";
 				allwinner,function = "spi2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			spi2_pins_b: spi2@1 {
 				allwinner,pins = "PB14", "PB15", "PB16", "PB17";
 				allwinner,function = "spi2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_cd_pin_reference_design: mmc0_cd_pin@0 {
 				allwinner,pins = "PH1";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			mmc2_pins_a: mmc2@0 {
 				allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11";
 				allwinner,function = "mmc2";
-				allwinner,drive = <2>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
 			};
 
 			mmc3_pins_a: mmc3@0 {
 				allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
 				allwinner,function = "mmc3";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			ir0_pins_a: ir0@0 {
 				    allwinner,pins = "PB3","PB4";
 				    allwinner,function = "ir0";
-				    allwinner,drive = <0>;
-				    allwinner,pull = <0>;
+				    allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				    allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			ir1_pins_a: ir1@0 {
 				    allwinner,pins = "PB22","PB23";
 				    allwinner,function = "ir1";
-				    allwinner,drive = <0>;
-				    allwinner,pull = <0>;
+				    allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				    allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			ps20_pins_a: ps20@0 {
+				allwinner,pins = "PI20", "PI21";
+				allwinner,function = "ps2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			ps21_pins_a: ps21@0 {
+				allwinner,pins = "PH12", "PH13";
+				allwinner,function = "ps2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
 		timer@01c20c00 {
 			compatible = "allwinner,sun4i-a10-timer";
 			reg = <0x01c20c00 0x90>;
-			interrupts = <0 22 4>,
-				     <0 23 4>,
-				     <0 24 4>,
-				     <0 25 4>,
-				     <0 67 4>,
-				     <0 68 4>;
+			interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&osc24M>;
 		};
 
@@ -880,7 +969,7 @@
 		rtc: rtc@01c20d00 {
 			compatible = "allwinner,sun7i-a20-rtc";
 			reg = <0x01c20d00 0x20>;
-			interrupts = <0 24 4>;
+			interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		pwm: pwm@01c20e00 {
@@ -895,7 +984,7 @@
 			compatible = "allwinner,sun4i-a10-ir";
 			clocks = <&apb0_gates 6>, <&ir0_clk>;
 			clock-names = "apb", "ir";
-			interrupts = <0 5 4>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 			reg = <0x01c21800 0x40>;
 			status = "disabled";
 		};
@@ -904,11 +993,18 @@
 			compatible = "allwinner,sun4i-a10-ir";
 			clocks = <&apb0_gates 7>, <&ir1_clk>;
 			clock-names = "apb", "ir";
-			interrupts = <0 6 4>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
 			reg = <0x01c21c00 0x40>;
 			status = "disabled";
 		};
 
+		lradc: lradc@01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
 		sid: eeprom@01c23800 {
 			compatible = "allwinner,sun7i-a20-sid";
 			reg = <0x01c23800 0x200>;
@@ -917,13 +1013,14 @@
 		rtp: rtp@01c25000 {
 			compatible = "allwinner,sun4i-a10-ts";
 			reg = <0x01c25000 0x100>;
-			interrupts = <0 29 4>;
+			interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		uart0: serial@01c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
-			interrupts = <0 1 4>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 16>;
@@ -933,7 +1030,7 @@
 		uart1: serial@01c28400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28400 0x400>;
-			interrupts = <0 2 4>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 17>;
@@ -943,7 +1040,7 @@
 		uart2: serial@01c28800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28800 0x400>;
-			interrupts = <0 3 4>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 18>;
@@ -953,7 +1050,7 @@
 		uart3: serial@01c28c00 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28c00 0x400>;
-			interrupts = <0 4 4>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 19>;
@@ -963,7 +1060,7 @@
 		uart4: serial@01c29000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29000 0x400>;
-			interrupts = <0 17 4>;
+			interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 20>;
@@ -973,7 +1070,7 @@
 		uart5: serial@01c29400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29400 0x400>;
-			interrupts = <0 18 4>;
+			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 21>;
@@ -983,7 +1080,7 @@
 		uart6: serial@01c29800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29800 0x400>;
-			interrupts = <0 19 4>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 22>;
@@ -993,7 +1090,7 @@
 		uart7: serial@01c29c00 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29c00 0x400>;
-			interrupts = <0 20 4>;
+			interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 23>;
@@ -1003,7 +1100,7 @@
 		i2c0: i2c@01c2ac00 {
 			compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2ac00 0x400>;
-			interrupts = <0 7 4>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 0>;
 			status = "disabled";
 			#address-cells = <1>;
@@ -1013,7 +1110,7 @@
 		i2c1: i2c@01c2b000 {
 			compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2b000 0x400>;
-			interrupts = <0 8 4>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 1>;
 			status = "disabled";
 			#address-cells = <1>;
@@ -1023,7 +1120,7 @@
 		i2c2: i2c@01c2b400 {
 			compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2b400 0x400>;
-			interrupts = <0 9 4>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 2>;
 			status = "disabled";
 			#address-cells = <1>;
@@ -1033,7 +1130,7 @@
 		i2c3: i2c@01c2b800 {
 			compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2b800 0x400>;
-			interrupts = <0 88 4>;
+			interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 3>;
 			status = "disabled";
 			#address-cells = <1>;
@@ -1043,7 +1140,7 @@
 		i2c4: i2c@01c2c000 {
 			compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c";
 			reg = <0x01c2c000 0x400>;
-			interrupts = <0 89 4>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 15>;
 			status = "disabled";
 			#address-cells = <1>;
@@ -1053,7 +1150,7 @@
 		gmac: ethernet@01c50000 {
 			compatible = "allwinner,sun7i-a20-gmac";
 			reg = <0x01c50000 0x10000>;
-			interrupts = <0 85 4>;
+			interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq";
 			clocks = <&ahb_gates 49>, <&gmac_tx_clk>;
 			clock-names = "stmmaceth", "allwinner_gmac_tx";
@@ -1068,10 +1165,10 @@
 		hstimer@01c60000 {
 			compatible = "allwinner,sun7i-a20-hstimer";
 			reg = <0x01c60000 0x1000>;
-			interrupts = <0 81 4>,
-				     <0 82 4>,
-				     <0 83 4>,
-				     <0 84 4>;
+			interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb_gates 28>;
 		};
 
@@ -1083,7 +1180,23 @@
 			      <0x01c86000 0x2000>;
 			interrupt-controller;
 			#interrupt-cells = <3>;
-			interrupts = <1 9 0xf04>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		};
+
+		ps20: ps2@01c2a000 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a000 0x400>;
+			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&apb1_gates 6>;
+			status = "disabled";
+		};
+
+		ps21: ps2@01c2a400 {
+			compatible = "allwinner,sun4i-a10-ps2";
+			reg = <0x01c2a400 0x400>;
+			interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&apb1_gates 7>;
+			status = "disabled";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
new file mode 100644
index 0000000..dd31c53
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+/*
+ * The Ippo Q8H v1.2 is almost identical to the v5, still it needs a separate
+ * dtb file since some gpio-s surrounding the wlan/bluetooth are different,
+ * and it uses different camera sensors.
+ */
+
+#include "sun8i-a23-ippo-q8h-v5.dts"
+
+/ {
+	model = "Ippo Q8H Dual Core Tablet (v1.2)";
+	compatible = "ippo,q8h-v1.2", "allwinner,sun8i-a23";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
index 32ad808..623573e 100644
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
@@ -48,8 +48,12 @@
  */
 
 /dts-v1/;
-/include/ "sun8i-a23.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun8i-a23.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Ippo Q8H Dual Core Tablet (v5)";
@@ -69,7 +73,7 @@
 			pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
 			vmmc-supply = <&reg_vcc3v0>;
 			bus-width = <4>;
-			cd-gpios = <&pio 1 4 0>; /* PB4 */
+			cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
 			cd-inverted;
 			status = "okay";
 		};
@@ -78,8 +82,27 @@
 			mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
 				allwinner,pins = "PB4";
 				allwinner,function = "gpio_in";
-				allwinner,drive = <0>;
-				allwinner,pull = <1>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+			};
+		};
+
+		lradc: lradc@01c22800 {
+			vref-supply = <&reg_vcc3v0>;
+			status = "okay";
+
+			button@200 {
+				label = "Volume Up";
+				linux,code = <KEY_VOLUMEUP>;
+				channel = <0>;
+				voltage = <200000>;
+			};
+
+			button@400 {
+				label = "Volume Down";
+				linux,code = <KEY_VOLUMEDOWN>;
+				channel = <0>;
+				voltage = <400000>;
 			};
 		};
 
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 86584fc..dd34527 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -47,11 +47,29 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&gic>;
 
+	chosen {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		framebuffer@0 {
+			compatible = "allwinner,simple-framebuffer",
+				     "simple-framebuffer";
+			allwinner,pipeline = "de_be0-lcd0";
+			clocks = <&pll6 0>;
+			status = "disabled";
+		};
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -233,7 +251,7 @@
 		dma: dma-controller@01c02000 {
 			compatible = "allwinner,sun8i-a23-dma";
 			reg = <0x01c02000 0x1000>;
-			interrupts = <0 50 4>;
+			interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ahb1_gates 6>;
 			resets = <&ahb1_rst 6>;
 			#dma-cells = <1>;
@@ -246,7 +264,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 8>;
 			reset-names = "ahb";
-			interrupts = <0 60 4>;
+			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -257,7 +275,7 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 9>;
 			reset-names = "ahb";
-			interrupts = <0 61 4>;
+			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
@@ -268,16 +286,16 @@
 			clock-names = "ahb", "mmc";
 			resets = <&ahb1_rst 10>;
 			reset-names = "ahb";
-			interrupts = <0 62 4>;
+			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
 		pio: pinctrl@01c20800 {
 			compatible = "allwinner,sun8i-a23-pinctrl";
 			reg = <0x01c20800 0x400>;
-			interrupts = <0 11 4>,
-				     <0 15 4>,
-				     <0 17 4>;
+			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 5>;
 			gpio-controller;
 			interrupt-controller;
@@ -288,43 +306,43 @@
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PF2", "PF4";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc0_pins_a: mmc0@0 {
 				allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
 				allwinner,function = "mmc0";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			mmc1_pins_a: mmc1@0 {
 				allwinner,pins = "PG0","PG1","PG2","PG3","PG4","PG5";
 				allwinner,function = "mmc1";
-				allwinner,drive = <2>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c0_pins_a: i2c0@0 {
 				allwinner,pins = "PH2", "PH3";
 				allwinner,function = "i2c0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c1_pins_a: i2c1@0 {
 				allwinner,pins = "PH4", "PH5";
 				allwinner,function = "i2c1";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			i2c2_pins_a: i2c2@0 {
 				allwinner,pins = "PE12", "PE13";
 				allwinner,function = "i2c2";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
@@ -349,21 +367,28 @@
 		timer@01c20c00 {
 			compatible = "allwinner,sun4i-a10-timer";
 			reg = <0x01c20c00 0xa0>;
-			interrupts = <0 18 4>,
-				     <0 19 4>;
+			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&osc24M>;
 		};
 
 		wdt0: watchdog@01c20ca0 {
 			compatible = "allwinner,sun6i-a31-wdt";
 			reg = <0x01c20ca0 0x20>;
-			interrupts = <0 25 4>;
+			interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		lradc: lradc@01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
 		};
 
 		uart0: serial@01c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
-			interrupts = <0 0 4>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 16>;
@@ -376,7 +401,7 @@
 		uart1: serial@01c28400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28400 0x400>;
-			interrupts = <0 1 4>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 17>;
@@ -389,7 +414,7 @@
 		uart2: serial@01c28800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28800 0x400>;
-			interrupts = <0 2 4>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 18>;
@@ -402,7 +427,7 @@
 		uart3: serial@01c28c00 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28c00 0x400>;
-			interrupts = <0 3 4>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 19>;
@@ -415,7 +440,7 @@
 		uart4: serial@01c29000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c29000 0x400>;
-			interrupts = <0 4 4>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb2_gates 20>;
@@ -428,7 +453,7 @@
 		i2c0: i2c@01c2ac00 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2ac00 0x400>;
-			interrupts = <0 6 4>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 0>;
 			resets = <&apb2_rst 0>;
 			status = "disabled";
@@ -439,7 +464,7 @@
 		i2c1: i2c@01c2b000 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2b000 0x400>;
-			interrupts = <0 7 4>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 1>;
 			resets = <&apb2_rst 1>;
 			status = "disabled";
@@ -450,7 +475,7 @@
 		i2c2: i2c@01c2b400 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x01c2b400 0x400>;
-			interrupts = <0 8 4>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb2_gates 2>;
 			resets = <&apb2_rst 2>;
 			status = "disabled";
@@ -466,13 +491,14 @@
 			      <0x01c86000 0x2000>;
 			interrupt-controller;
 			#interrupt-cells = <3>;
-			interrupts = <1 9 0xf04>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
 		rtc: rtc@01f00000 {
 			compatible = "allwinner,sun6i-a31-rtc";
 			reg = <0x01f00000 0x54>;
-			interrupts = <0 40 4>, <0 41 4>;
+			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		prcm@01f01400 {
@@ -522,7 +548,7 @@
 		r_uart: serial@01f02800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01f02800 0x400>;
-			interrupts = <0 38 4>;
+			interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb0_gates 4>;
@@ -533,7 +559,7 @@
 		r_pio: pinctrl@01f02c00 {
 			compatible = "allwinner,sun8i-a23-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
-			interrupts = <0 45 4>;
+			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>;
 			resets = <&apb0_rst 0>;
 			gpio-controller;
@@ -545,8 +571,8 @@
 			r_uart_pins_a: r_uart@0 {
 				allwinner,pins = "PL2", "PL3";
 				allwinner,function = "s_uart";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
index 11ec710..a3fed2b 100644
--- a/arch/arm/boot/dts/sun9i-a80-optimus.dts
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -48,7 +48,11 @@
  */
 
 /dts-v1/;
-/include/ "sun9i-a80.dtsi"
+#include "sun9i-a80.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	model = "Merrii A80 Optimus Board";
@@ -63,45 +67,6 @@
 		bootargs = "earlyprintk console=ttyS0,115200";
 	};
 
-	soc {
-		pio: pinctrl@06000800 {
-			i2c3_pins_a: i2c3@0 {
-				/* Enable internal pull-up */
-				allwinner,pull = <1>;
-			};
-
-			led_pins_optimus: led-pins@0 {
-				allwinner,pins = "PH0", "PH1";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-
-			uart4_pins_a: uart4@0 {
-				/* Enable internal pull-up */
-				allwinner,pull = <1>;
-			};
-		};
-
-		uart0: serial@07000000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&uart0_pins_a>;
-			status = "okay";
-		};
-
-		uart4: serial@07001000 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&uart4_pins_a>;
-			status = "okay";
-		};
-
-		i2c3: i2c@07003400 {
-			pinctrl-names = "default";
-			pinctrl-0 = <&i2c3_pins_a>;
-			status = "okay";
-		};
-	};
-
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -111,14 +76,77 @@
 
 		led2 {
 			label = "optimus:led2:usr";
-			gpios = <&pio 7 1 0>;
+			gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>;
 		};
 
 		/* led3 is on PM15, in R_PIO */
 
 		led4 {
 			label = "optimus:led4:usr";
-			gpios = <&pio 7 0 0>;
+			gpios = <&pio 7 0 GPIO_ACTIVE_HIGH>;
 		};
 	};
 };
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3_pins_a>;
+	status = "okay";
+};
+
+&i2c3_pins_a {
+	/* Enable internal pull-up */
+	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&pio {
+	led_pins_optimus: led-pins@0 {
+		allwinner,pins = "PH0", "PH1";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	mmc0_cd_pin_optimus: mmc0_cd_pin@0 {
+		allwinner,pins = "PH18";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin_optimus>;
+	vmmc-supply = <&reg_vcc3v0>;
+	bus-width = <4>;
+	cd-gpios = <&pio 7 18 GPIO_ACTIVE_HIGH>; /* PH8 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_vcc3v0>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_a>;
+	status = "okay";
+};
+
+&uart4_pins_a {
+	/* Enable internal pull-up */
+	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 9ef44382..f0f6fb9 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -47,7 +47,11 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/include/ "skeleton64.dtsi"
+#include "skeleton64.dtsi"
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
 / {
 	interrupt-parent = <&gic>;
@@ -205,11 +209,50 @@
 			clock-output-names = "cci400";
 		};
 
+		mmc0_clk: clk@06000410 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000410 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc0", "mmc0_output",
+					     "mmc0_sample";
+		};
+
+		mmc1_clk: clk@06000414 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000414 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc1", "mmc1_output",
+					     "mmc1_sample";
+		};
+
+		mmc2_clk: clk@06000418 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x06000418 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc2", "mmc2_output",
+					     "mmc2_sample";
+		};
+
+		mmc3_clk: clk@0600041c {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun9i-a80-mmc-clk";
+			reg = <0x0600041c 0x4>;
+			clocks = <&osc24M>, <&pll4>;
+			clock-output-names = "mmc3", "mmc3_output",
+					     "mmc3_sample";
+		};
+
 		ahb0_gates: clk@06000580 {
 			#clock-cells = <1>;
 			compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
 			reg = <0x06000580 0x4>;
 			clocks = <&ahb0>;
+			clock-indices = <0>, <1>, <3>, <5>, <8>, <12>, <13>,
+					<14>, <15>, <16>, <18>, <20>, <21>,
+					<22>, <23>;
 			clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
 					"ahb0_ss", "ahb0_sd", "ahb0_nand1",
 					"ahb0_nand0", "ahb0_sdram",
@@ -223,6 +266,7 @@
 			compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
 			reg = <0x06000584 0x4>;
 			clocks = <&ahb1>;
+			clock-indices = <0>, <1>, <17>, <21>, <22>, <23>, <24>;
 			clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
 					"ahb1_gmac", "ahb1_msgbox",
 					"ahb1_spinlock", "ahb1_hstimer",
@@ -234,6 +278,8 @@
 			compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
 			reg = <0x06000588 0x4>;
 			clocks = <&ahb2>;
+			clock-indices = <0>, <1>, <2>, <4>, <5>, <7>, <8>,
+					<11>;
 			clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
 					"ahb2_edp", "ahb2_csi", "ahb2_hdmi",
 					"ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
@@ -244,6 +290,8 @@
 			compatible = "allwinner,sun9i-a80-apb0-gates-clk";
 			reg = <0x06000590 0x4>;
 			clocks = <&apb0>;
+			clock-indices = <1>, <5>, <11>, <12>, <13>, <15>,
+					<17>, <18>, <19>;
 			clock-output-names = "apb0_spdif", "apb0_pio",
 					"apb0_ac97", "apb0_i2s0", "apb0_i2s1",
 					"apb0_lradc", "apb0_gpadc", "apb0_twd",
@@ -255,6 +303,8 @@
 			compatible = "allwinner,sun9i-a80-apb1-gates-clk";
 			reg = <0x06000594 0x4>;
 			clocks = <&apb1>;
+			clock-indices = <0>, <1>, <2>, <3>, <4>,
+					<16>, <17>, <18>, <19>, <20>, <21>;
 			clock-output-names = "apb1_i2c0", "apb1_i2c1",
 					"apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
 					"apb1_uart0", "apb1_uart1",
@@ -273,6 +323,67 @@
 		 */
 		ranges = <0 0 0 0x20000000>;
 
+		mmc0: mmc@01c0f000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&mmc_config_clk 0>, <&mmc0_clk 0>,
+				 <&mmc0_clk 1>, <&mmc0_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 0>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		mmc1: mmc@01c10000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&mmc_config_clk 1>, <&mmc1_clk 0>,
+				 <&mmc1_clk 1>, <&mmc1_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 1>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		mmc2: mmc@01c11000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c11000 0x1000>;
+			clocks = <&mmc_config_clk 2>, <&mmc2_clk 0>,
+				 <&mmc2_clk 1>, <&mmc2_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 2>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		mmc3: mmc@01c12000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c12000 0x1000>;
+			clocks = <&mmc_config_clk 3>, <&mmc3_clk 0>,
+				 <&mmc3_clk 1>, <&mmc3_clk 2>;
+			clock-names = "ahb", "mmc", "output", "sample";
+			resets = <&mmc_config_clk 3>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		mmc_config_clk: clk@01c13000 {
+			compatible = "allwinner,sun9i-a80-mmc-config-clk";
+			reg = <0x01c13000 0x10>;
+			clocks = <&ahb0_gates 8>;
+			clock-names = "ahb";
+			resets = <&ahb0_resets 8>;
+			reset-names = "ahb";
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			clock-output-names = "mmc0_config", "mmc1_config",
+					     "mmc2_config", "mmc3_config";
+		};
+
 		gic: interrupt-controller@01c41000 {
 			compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
 			reg = <0x01c41000 0x1000>,
@@ -281,7 +392,7 @@
 			      <0x01c46000 0x2000>;
 			interrupt-controller;
 			#interrupt-cells = <3>;
-			interrupts = <1 9 0xf04>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
 		ahb0_resets: reset@060005a0 {
@@ -317,12 +428,12 @@
 		timer@06000c00 {
 			compatible = "allwinner,sun4i-a10-timer";
 			reg = <0x06000c00 0xa0>;
-			interrupts = <0 18 4>,
-				     <0 19 4>,
-				     <0 20 4>,
-				     <0 21 4>,
-				     <0 22 4>,
-				     <0 23 4>;
+			interrupts = <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>;
 
 			clocks = <&osc24M>;
 		};
@@ -330,11 +441,11 @@
 		pio: pinctrl@06000800 {
 			compatible = "allwinner,sun9i-a80-pinctrl";
 			reg = <0x06000800 0x400>;
-			interrupts = <0 11 4>,
-				     <0 15 4>,
-				     <0 16 4>,
-				     <0 17 4>,
-				     <0 120 4>;
+			interrupts = <GIC_SPI 11 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>,
+				     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 5>;
 			gpio-controller;
 			interrupt-controller;
@@ -345,29 +456,46 @@
 			i2c3_pins_a: i2c3@0 {
 				allwinner,pins = "PG10", "PG11";
 				allwinner,function = "i2c3";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			mmc0_pins: mmc0 {
+				allwinner,pins = "PF0", "PF1" ,"PF2", "PF3",
+						 "PF4", "PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			mmc2_8bit_pins: mmc2_8bit {
+				allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+						 "PC10", "PC11", "PC12",
+						 "PC13", "PC14", "PC15";
+				allwinner,function = "mmc2";
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart0_pins_a: uart0@0 {
 				allwinner,pins = "PH12", "PH13";
 				allwinner,function = "uart0";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 
 			uart4_pins_a: uart4@0 {
 				allwinner,pins = "PG12", "PG13", "PG14", "PG15";
 				allwinner,function = "uart4";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 			};
 		};
 
 		uart0: serial@07000000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07000000 0x400>;
-			interrupts = <0 0 4>;
+			interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 16>;
@@ -378,7 +506,7 @@
 		uart1: serial@07000400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07000400 0x400>;
-			interrupts = <0 1 4>;
+			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 17>;
@@ -389,7 +517,7 @@
 		uart2: serial@07000800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07000800 0x400>;
-			interrupts = <0 2 4>;
+			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 18>;
@@ -400,7 +528,7 @@
 		uart3: serial@07000c00 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07000c00 0x400>;
-			interrupts = <0 3 4>;
+			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 19>;
@@ -411,7 +539,7 @@
 		uart4: serial@07001000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07001000 0x400>;
-			interrupts = <0 4 4>;
+			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 20>;
@@ -422,7 +550,7 @@
 		uart5: serial@07001400 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x07001400 0x400>;
-			interrupts = <0 5 4>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&apb1_gates 21>;
@@ -433,7 +561,7 @@
 		i2c0: i2c@07002800 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x07002800 0x400>;
-			interrupts = <0 6 4>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 0>;
 			resets = <&apb1_resets 0>;
 			status = "disabled";
@@ -444,7 +572,7 @@
 		i2c1: i2c@07002c00 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x07002c00 0x400>;
-			interrupts = <0 7 4>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 1>;
 			resets = <&apb1_resets 1>;
 			status = "disabled";
@@ -455,7 +583,7 @@
 		i2c2: i2c@07003000 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x07003000 0x400>;
-			interrupts = <0 8 4>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 2>;
 			resets = <&apb1_resets 2>;
 			status = "disabled";
@@ -466,7 +594,7 @@
 		i2c3: i2c@07003400 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x07003400 0x400>;
-			interrupts = <0 9 4>;
+			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 3>;
 			resets = <&apb1_resets 3>;
 			status = "disabled";
@@ -477,7 +605,7 @@
 		i2c4: i2c@07003800 {
 			compatible = "allwinner,sun6i-a31-i2c";
 			reg = <0x07003800 0x400>;
-			interrupts = <0 10 4>;
+			interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb1_gates 4>;
 			resets = <&apb1_resets 4>;
 			status = "disabled";
@@ -488,13 +616,13 @@
 		r_wdt: watchdog@08001000 {
 			compatible = "allwinner,sun6i-a31-wdt";
 			reg = <0x08001000 0x20>;
-			interrupts = <0 36 4>;
+			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
 		r_uart: serial@08002800 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x08002800 0x400>;
-			interrupts = <0 38 4>;
+			interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
 			clocks = <&osc24M>;
diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
index d887663..e02baa6 100644
--- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
@@ -47,39 +47,40 @@
  *     OTHER DEALINGS IN THE SOFTWARE.
  */
 
-/ {
-	soc@01c00000 {
-		pio: pinctrl@01c20800 {
-			ahci_pwr_pin_a: ahci_pwr_pin@0 {
-				allwinner,pins = "PB8";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
 
-			usb0_vbus_pin_a: usb0_vbus_pin@0 {
-				allwinner,pins = "PB9";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-
-			usb1_vbus_pin_a: usb1_vbus_pin@0 {
-				allwinner,pins = "PH6";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-
-			usb2_vbus_pin_a: usb2_vbus_pin@0 {
-				allwinner,pins = "PH3";
-				allwinner,function = "gpio_out";
-				allwinner,drive = <0>;
-				allwinner,pull = <0>;
-			};
-		};
+&pio {
+	ahci_pwr_pin_a: ahci_pwr_pin@0 {
+		allwinner,pins = "PB8";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
 	};
 
+	usb0_vbus_pin_a: usb0_vbus_pin@0 {
+		allwinner,pins = "PB9";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	usb1_vbus_pin_a: usb1_vbus_pin@0 {
+		allwinner,pins = "PH6";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	usb2_vbus_pin_a: usb2_vbus_pin@0 {
+		allwinner,pins = "PH3";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+/ {
 	reg_ahci_5v: ahci-5v {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
@@ -89,7 +90,7 @@
 		regulator-max-microvolt = <5000000>;
 		regulator-boot-on;
 		enable-active-high;
-		gpio = <&pio 1 8 0>;
+		gpio = <&pio 1 8 GPIO_ACTIVE_HIGH>;
 		status = "disabled";
 	};
 
@@ -101,7 +102,7 @@
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
 		enable-active-high;
-		gpio = <&pio 1 9 0>;
+		gpio = <&pio 1 9 GPIO_ACTIVE_HIGH>;
 		status = "disabled";
 	};
 
@@ -113,7 +114,7 @@
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
 		enable-active-high;
-		gpio = <&pio 7 6 0>;
+		gpio = <&pio 7 6 GPIO_ACTIVE_HIGH>;
 		status = "disabled";
 	};
 
@@ -125,7 +126,7 @@
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
 		enable-active-high;
-		gpio = <&pio 7 3 0>;
+		gpio = <&pio 7 3 GPIO_ACTIVE_HIGH>;
 		status = "disabled";
 	};
 
diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index 4eb540b..dbfaba0 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1673,6 +1673,13 @@
 		nvidia,core-pwr-off-time = <61036>;
 		nvidia,core-power-req-active-high;
 		nvidia,sys-clock-req-active-high;
+
+		i2c-thermtrip {
+			nvidia,i2c-controller-id = <4>;
+			nvidia,bus-addr = <0x40>;
+			nvidia,reg-addr = <0x36>;
+			nvidia,reg-data = <0x2>;
+		};
 	};
 
 	/* Serial ATA */
diff --git a/arch/arm/boot/dts/tegra124-nyan-big.dts b/arch/arm/boot/dts/tegra124-nyan-big.dts
index 53181d3..004e8e4 100644
--- a/arch/arm/boot/dts/tegra124-nyan-big.dts
+++ b/arch/arm/boot/dts/tegra124-nyan-big.dts
@@ -1131,6 +1131,8 @@
 		clock-names = "pll_a", "pll_a_out0", "mclk";
 
 		nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(I, 7) GPIO_ACTIVE_HIGH>;
+		nvidia,mic-det-gpios =
+				<&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 8acf5d8..e5527f7 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -68,9 +68,9 @@
 			reset-names = "2d";
 		};
 
-		gr3d@54140000 {
+		gr3d@54180000 {
 			compatible = "nvidia,tegra20-gr3d";
-			reg = <0x54140000 0x00040000>;
+			reg = <0x54180000 0x00040000>;
 			clocks = <&tegra_car TEGRA20_CLK_GR3D>;
 			resets = <&tegra_car 24>;
 			reset-names = "3d";
@@ -130,9 +130,9 @@
 			status = "disabled";
 		};
 
-		dsi@542c0000 {
+		dsi@54300000 {
 			compatible = "nvidia,tegra20-dsi";
-			reg = <0x542c0000 0x00040000>;
+			reg = <0x54300000 0x00040000>;
 			clocks = <&tegra_car TEGRA20_CLK_DSI>;
 			resets = <&tegra_car 48>;
 			reset-names = "dsi";
@@ -140,7 +140,7 @@
 		};
 	};
 
-	timer@50004600 {
+	timer@50040600 {
 		compatible = "arm,cortex-a9-twd-timer";
 		reg = <0x50040600 0x20>;
 		interrupts = <GIC_PPI 13
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index cbf5a1a..a1b682e 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -189,7 +189,7 @@
 
 		/* ALS and Proximity sensor */
 		isl29028@44 {
-			compatible = "isl,isl29028";
+			compatible = "isil,isl29028";
 			reg = <0x44>;
 			interrupt-parent = <&gpio>;
 			interrupts = <TEGRA_GPIO(L, 0) IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index 99475f6..db4810d 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -225,7 +225,7 @@
 		};
 	};
 
-	timer@50004600 {
+	timer@50040600 {
 		compatible = "arm,cortex-a9-twd-timer";
 		reg = <0x50040600 0x20>;
 		interrupts = <GIC_PPI 13
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
index 27d0d9c..01f4019 100644
--- a/arch/arm/boot/dts/versatile-ab.dts
+++ b/arch/arm/boot/dts/versatile-ab.dts
@@ -252,6 +252,11 @@
 			#size-cells = <1>;
 			ranges = <0 0x10000000 0x10000>;
 
+			sysreg@0 {
+				compatible = "arm,versatile-sysreg", "syscon";
+				reg = <0x00000 0x1000>;
+			};
+
 			aaci@4000 {
 				compatible = "arm,primecell";
 				reg = <0x4000 0x1000>;
diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
index 56a452b..36cafbf 100644
--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -35,7 +35,7 @@
 			regulator-name = "usbh_vbus";
 			regulator-min-microvolt = <5000000>;
 			regulator-max-microvolt = <5000000>;
-			gpio = <&gpio3 19 GPIO_ACTIVE_LOW>;
+			gpio = <&gpio2 19 GPIO_ACTIVE_LOW>;
 			vin-supply = <&sys_5v0_reg>;
 		};
 	};
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index 82f5728..5c2b732 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -31,7 +31,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_esdhc1>;
 	bus-width = <4>;
-	cd-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+	cd-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
 };
 
 &fec1 {
@@ -121,6 +121,7 @@
 
 		pinctrl_fec1: fec1grp {
 			fsl,pins = <
+				VF610_PAD_PTA6__RMII_CLKOUT		0x30d2
 				VF610_PAD_PTC9__ENET_RMII1_MDC		0x30d2
 				VF610_PAD_PTC10__ENET_RMII1_MDIO	0x30d3
 				VF610_PAD_PTC11__ENET_RMII1_CRS		0x30d1
diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi
index de67005..1dbf8d2 100644
--- a/arch/arm/boot/dts/vf500.dtsi
+++ b/arch/arm/boot/dts/vf500.dtsi
@@ -94,23 +94,23 @@
 	interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-&gpio1 {
+&gpio0 {
 	interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-&gpio2 {
+&gpio1 {
 	interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-&gpio3 {
+&gpio2 {
 	interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-&gpio4 {
+&gpio3 {
 	interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
 };
 
-&gpio5 {
+&gpio4 {
 	interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
 };
 
@@ -130,6 +130,14 @@
 	interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
 };
 
+&snvsrtc {
+	interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&src {
+	interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+};
+
 &uart0 {
 	interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
 };
@@ -169,3 +177,8 @@
 &usbphy1 {
 	interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
 };
+
+&wdoga5 {
+	interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index f2b64b1..f64fddc 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -123,7 +123,7 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_esdhc1>;
 	bus-width = <4>;
-	cd-gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
+	cd-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>;
 	status = "okay";
 };
 
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 505969a..a29c7ce 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -22,11 +22,11 @@
 		serial3 = &uart3;
 		serial4 = &uart4;
 		serial5 = &uart5;
-		gpio0 = &gpio1;
-		gpio1 = &gpio2;
-		gpio2 = &gpio3;
-		gpio3 = &gpio4;
-		gpio4 = &gpio5;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		gpio2 = &gpio2;
+		gpio3 = &gpio3;
+		gpio4 = &gpio4;
 		usbphy0 = &usbphy0;
 		usbphy1 = &usbphy1;
 	};
@@ -43,6 +43,13 @@
 		clock-frequency = <32768>;
 	};
 
+	reboot: syscon-reboot {
+		compatible = "syscon-reboot";
+		regmap = <&src>;
+		offset = <0x0>;
+		mask = <0x1000>;
+	};
+
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -184,7 +191,7 @@
 				status = "disabled";
 			};
 
-			wdog@4003e000 {
+			wdoga5: wdog@4003e000 {
 				compatible = "fsl,vf610-wdt", "fsl,imx21-wdt";
 				reg = <0x4003e000 0x1000>;
 				clocks = <&clks VF610_CLK_WDT>;
@@ -209,7 +216,7 @@
 				#gpio-range-cells = <3>;
 			};
 
-			gpio1: gpio@40049000 {
+			gpio0: gpio@40049000 {
 				compatible = "fsl,vf610-gpio";
 				reg = <0x40049000 0x1000 0x400ff000 0x40>;
 				gpio-controller;
@@ -219,7 +226,7 @@
 				gpio-ranges = <&iomuxc 0 0 32>;
 			};
 
-			gpio2: gpio@4004a000 {
+			gpio1: gpio@4004a000 {
 				compatible = "fsl,vf610-gpio";
 				reg = <0x4004a000 0x1000 0x400ff040 0x40>;
 				gpio-controller;
@@ -229,7 +236,7 @@
 				gpio-ranges = <&iomuxc 0 32 32>;
 			};
 
-			gpio3: gpio@4004b000 {
+			gpio2: gpio@4004b000 {
 				compatible = "fsl,vf610-gpio";
 				reg = <0x4004b000 0x1000 0x400ff080 0x40>;
 				gpio-controller;
@@ -239,7 +246,7 @@
 				gpio-ranges = <&iomuxc 0 64 32>;
 			};
 
-			gpio4: gpio@4004c000 {
+			gpio3: gpio@4004c000 {
 				compatible = "fsl,vf610-gpio";
 				reg = <0x4004c000 0x1000 0x400ff0c0 0x40>;
 				gpio-controller;
@@ -249,7 +256,7 @@
 				gpio-ranges = <&iomuxc 0 96 32>;
 			};
 
-			gpio5: gpio@4004d000 {
+			gpio4: gpio@4004d000 {
 				compatible = "fsl,vf610-gpio";
 				reg = <0x4004d000 0x1000 0x400ff100 0x40>;
 				gpio-controller;
@@ -318,6 +325,11 @@
 				clocks = <&clks VF610_CLK_USBC0>;
 				status = "disabled";
 			};
+
+			src: src@4006e000 {
+				compatible = "fsl,vf610-src", "syscon";
+				reg = <0x4006e000 0x1000>;
+			};
 		};
 
 		aips1: aips-bus@40080000 {
@@ -339,6 +351,20 @@
 				status = "disabled";
 			};
 
+			snvs0: snvs@400a7000 {
+			    compatible = "fsl,sec-v4.0-mon", "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x400a7000 0x2000>;
+
+				snvsrtc: snvs-rtc-lp@34 {
+					compatible = "fsl,sec-v4.0-mon-rtc-lp";
+					reg = <0x34 0x58>;
+					clocks = <&clks VF610_CLK_SNVS>;
+					clock-names = "snvs-rtc";
+				};
+			};
+
 			uart4: serial@400a9000 {
 				compatible = "fsl,vf610-lpuart";
 				reg = <0x400a9000 0x1000>;
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index ee3e5d6..a5cd2ed 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -237,7 +237,7 @@
 		slcr: slcr@f8000000 {
 			#address-cells = <1>;
 			#size-cells = <1>;
-			compatible = "xlnx,zynq-slcr", "syscon";
+			compatible = "xlnx,zynq-slcr", "syscon", "simple-bus";
 			reg = <0xF8000000 0x1000>;
 			ranges;
 			clkc: clkc@100 {
@@ -257,6 +257,12 @@
 						"dbg_trc", "dbg_apb";
 				reg = <0x100 0x100>;
 			};
+
+			pinctrl0: pinctrl@700 {
+				compatible = "xlnx,pinctrl-zynq";
+				reg = <0x700 0x200>;
+				syscon = <&slcr>;
+			};
 		};
 
 		dmac_s: dmac@f8003000 {
@@ -314,14 +320,32 @@
 			clocks = <&clkc 4>;
 		};
 
+		usb0: usb@e0002000 {
+			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
+			status = "disabled";
+			clocks = <&clkc 28>;
+			interrupt-parent = <&intc>;
+			interrupts = <0 21 4>;
+			reg = <0xe0002000 0x1000>;
+			phy_type = "ulpi";
+		};
+
+		usb1: usb@e0003000 {
+			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
+			status = "disabled";
+			clocks = <&clkc 29>;
+			interrupt-parent = <&intc>;
+			interrupts = <0 44 4>;
+			reg = <0xe0003000 0x1000>;
+			phy_type = "ulpi";
+		};
+
 		watchdog0: watchdog@f8005000 {
 			clocks = <&clkc 45>;
-			compatible = "xlnx,zynq-wdt-r1p2";
-			device_type = "watchdog";
+			compatible = "cdns,wdt-r1p2";
 			interrupt-parent = <&intc>;
 			interrupts = <0 9 1>;
 			reg = <0xf8005000 0x1000>;
-			reset = <0>;
 			timeout-sec = <10>;
 		};
 	};
diff --git a/arch/arm/boot/dts/zynq-parallella.dts b/arch/arm/boot/dts/zynq-parallella.dts
index ab1dc0a..1745712 100644
--- a/arch/arm/boot/dts/zynq-parallella.dts
+++ b/arch/arm/boot/dts/zynq-parallella.dts
@@ -58,7 +58,7 @@
 	status = "okay";
 
 	isl9305: isl9305@68 {
-		compatible = "isl,isl9305";
+		compatible = "isil,isl9305";
 		reg = <0x68>;
 
 		regulators {
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
index 280f02d..1fc1d39 100644
--- a/arch/arm/boot/dts/zynq-zc702.dts
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -18,6 +18,12 @@
 	model = "Zynq ZC702 Development Board";
 	compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";
 
+	aliases {
+		ethernet0 = &gem0;
+		i2c0 = &i2c0;
+		serial0 = &uart1;
+	};
+
 	memory {
 		device_type = "memory";
 		reg = <0x0 0x40000000>;
@@ -36,10 +42,17 @@
 			linux,default-trigger = "heartbeat";
 		};
 	};
+
+	usb_phy0: phy0 {
+		compatible = "usb-nop-xceiv";
+		#phy-cells = <0>;
+	};
 };
 
 &can0 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_can0_default>;
 };
 
 &clkc {
@@ -50,15 +63,24 @@
 	status = "okay";
 	phy-mode = "rgmii-id";
 	phy-handle = <&ethernet_phy>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gem0_default>;
 
 	ethernet_phy: ethernet-phy@7 {
 		reg = <7>;
 	};
 };
 
+&gpio0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio0_default>;
+};
+
 &i2c0 {
 	status = "okay";
 	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c0_default>;
 
 	i2cswitch@74 {
 		compatible = "nxp,pca9548";
@@ -132,10 +154,212 @@
 	};
 };
 
+&pinctrl0 {
+	pinctrl_can0_default: can0-default {
+		mux {
+			function = "can0";
+			groups = "can0_9_grp";
+		};
+
+		conf {
+			groups = "can0_9_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-rx {
+			pins = "MIO46";
+			bias-high-impedance;
+		};
+
+		conf-tx {
+			pins = "MIO47";
+			bias-disable;
+		};
+	};
+
+	pinctrl_gem0_default: gem0-default {
+		mux {
+			function = "ethernet0";
+			groups = "ethernet0_0_grp";
+		};
+
+		conf {
+			groups = "ethernet0_0_grp";
+			slew-rate = <0>;
+			io-standard = <4>;
+		};
+
+		conf-rx {
+			pins = "MIO22", "MIO23", "MIO24", "MIO25", "MIO26", "MIO27";
+			bias-high-impedance;
+			low-power-disable;
+		};
+
+		conf-tx {
+			pins = "MIO16", "MIO17", "MIO18", "MIO19", "MIO20", "MIO21";
+			bias-disable;
+			low-power-enable;
+		};
+
+		mux-mdio {
+			function = "mdio0";
+			groups = "mdio0_0_grp";
+		};
+
+		conf-mdio {
+			groups = "mdio0_0_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio0_default: gpio0-default {
+		mux {
+			function = "gpio0";
+			groups = "gpio0_7_grp", "gpio0_8_grp", "gpio0_9_grp",
+				 "gpio0_10_grp", "gpio0_11_grp", "gpio0_12_grp",
+				 "gpio0_13_grp", "gpio0_14_grp";
+		};
+
+		conf {
+			groups = "gpio0_7_grp", "gpio0_8_grp", "gpio0_9_grp",
+				 "gpio0_10_grp", "gpio0_11_grp", "gpio0_12_grp",
+				 "gpio0_13_grp", "gpio0_14_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-pull-up {
+			pins = "MIO9", "MIO10", "MIO11", "MIO12", "MIO13", "MIO14";
+			bias-pull-up;
+		};
+
+		conf-pull-none {
+			pins = "MIO7", "MIO8";
+			bias-disable;
+		};
+	};
+
+	pinctrl_i2c0_default: i2c0-default {
+		mux {
+			groups = "i2c0_10_grp";
+			function = "i2c0";
+		};
+
+		conf {
+			groups = "i2c0_10_grp";
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+	};
+
+	pinctrl_sdhci0_default: sdhci0-default {
+		mux {
+			groups = "sdio0_2_grp";
+			function = "sdio0";
+		};
+
+		conf {
+			groups = "sdio0_2_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+			bias-disable;
+		};
+
+		mux-cd {
+			groups = "gpio0_0_grp";
+			function = "sdio0_cd";
+		};
+
+		conf-cd {
+			groups = "gpio0_0_grp";
+			bias-high-impedance;
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		mux-wp {
+			groups = "gpio0_15_grp";
+			function = "sdio0_wp";
+		};
+
+		conf-wp {
+			groups = "gpio0_15_grp";
+			bias-high-impedance;
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+	};
+
+	pinctrl_uart1_default: uart1-default {
+		mux {
+			groups = "uart1_10_grp";
+			function = "uart1";
+		};
+
+		conf {
+			groups = "uart1_10_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-rx {
+			pins = "MIO49";
+			bias-high-impedance;
+		};
+
+		conf-tx {
+			pins = "MIO48";
+			bias-disable;
+		};
+	};
+
+	pinctrl_usb0_default: usb0-default {
+		mux {
+			groups = "usb0_0_grp";
+			function = "usb0";
+		};
+
+		conf {
+			groups = "usb0_0_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-rx {
+			pins = "MIO29", "MIO31", "MIO36";
+			bias-high-impedance;
+		};
+
+		conf-tx {
+			pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
+			       "MIO35", "MIO37", "MIO38", "MIO39";
+			bias-disable;
+		};
+	};
+};
+
 &sdhci0 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sdhci0_default>;
 };
 
 &uart1 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1_default>;
+};
+
+&usb0 {
+	status = "okay";
+	dr_mode = "host";
+	usb-phy = <&usb_phy0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb0_default>;
 };
diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts
index 34f7812..850518d 100644
--- a/arch/arm/boot/dts/zynq-zc706.dts
+++ b/arch/arm/boot/dts/zynq-zc706.dts
@@ -18,6 +18,12 @@
 	model = "Zynq ZC706 Development Board";
 	compatible = "xlnx,zynq-zc706", "xlnx,zynq-7000";
 
+	aliases {
+		ethernet0 = &gem0;
+		i2c0 = &i2c0;
+		serial0 = &uart1;
+	};
+
 	memory {
 		device_type = "memory";
 		reg = <0x0 0x40000000>;
@@ -27,6 +33,10 @@
 		bootargs = "console=ttyPS0,115200 earlyprintk";
 	};
 
+	usb_phy0: phy0 {
+		compatible = "usb-nop-xceiv";
+		#phy-cells = <0>;
+	};
 };
 
 &clkc {
@@ -37,15 +47,24 @@
 	status = "okay";
 	phy-mode = "rgmii-id";
 	phy-handle = <&ethernet_phy>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gem0_default>;
 
 	ethernet_phy: ethernet-phy@7 {
 		reg = <7>;
 	};
 };
 
+&gpio0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio0_default>;
+};
+
 &i2c0 {
 	status = "okay";
 	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c0_default>;
 
 	i2cswitch@74 {
 		compatible = "nxp,pca9548";
@@ -111,10 +130,185 @@
 	};
 };
 
+&pinctrl0 {
+	pinctrl_gem0_default: gem0-default {
+		mux {
+			function = "ethernet0";
+			groups = "ethernet0_0_grp";
+		};
+
+		conf {
+			groups = "ethernet0_0_grp";
+			slew-rate = <0>;
+			io-standard = <4>;
+		};
+
+		conf-rx {
+			pins = "MIO22", "MIO23", "MIO24", "MIO25", "MIO26", "MIO27";
+			bias-high-impedance;
+			low-power-disable;
+		};
+
+		conf-tx {
+			pins = "MIO16", "MIO17", "MIO18", "MIO19", "MIO20", "MIO21";
+			low-power-enable;
+			bias-disable;
+		};
+
+		mux-mdio {
+			function = "mdio0";
+			groups = "mdio0_0_grp";
+		};
+
+		conf-mdio {
+			groups = "mdio0_0_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio0_default: gpio0-default {
+		mux {
+			function = "gpio0";
+			groups = "gpio0_7_grp", "gpio0_46_grp", "gpio0_47_grp";
+		};
+
+		conf {
+			groups = "gpio0_7_grp", "gpio0_46_grp", "gpio0_47_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-pull-up {
+			pins = "MIO46", "MIO47";
+			bias-pull-up;
+		};
+
+		conf-pull-none {
+			pins = "MIO7";
+			bias-disable;
+		};
+	};
+
+	pinctrl_i2c0_default: i2c0-default {
+		mux {
+			groups = "i2c0_10_grp";
+			function = "i2c0";
+		};
+
+		conf {
+			groups = "i2c0_10_grp";
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+	};
+
+	pinctrl_sdhci0_default: sdhci0-default {
+		mux {
+			groups = "sdio0_2_grp";
+			function = "sdio0";
+		};
+
+		conf {
+			groups = "sdio0_2_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+			bias-disable;
+		};
+
+		mux-cd {
+			groups = "gpio0_14_grp";
+			function = "sdio0_cd";
+		};
+
+		conf-cd {
+			groups = "gpio0_14_grp";
+			bias-high-impedance;
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		mux-wp {
+			groups = "gpio0_15_grp";
+			function = "sdio0_wp";
+		};
+
+		conf-wp {
+			groups = "gpio0_15_grp";
+			bias-high-impedance;
+			bias-pull-up;
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+	};
+
+	pinctrl_uart1_default: uart1-default {
+		mux {
+			groups = "uart1_10_grp";
+			function = "uart1";
+		};
+
+		conf {
+			groups = "uart1_10_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-rx {
+			pins = "MIO49";
+			bias-high-impedance;
+		};
+
+		conf-tx {
+			pins = "MIO48";
+			bias-disable;
+		};
+	};
+
+	pinctrl_usb0_default: usb0-default {
+		mux {
+			groups = "usb0_0_grp";
+			function = "usb0";
+		};
+
+		conf {
+			groups = "usb0_0_grp";
+			slew-rate = <0>;
+			io-standard = <1>;
+		};
+
+		conf-rx {
+			pins = "MIO29", "MIO31", "MIO36";
+			bias-high-impedance;
+		};
+
+		conf-tx {
+			pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
+			       "MIO35", "MIO37", "MIO38", "MIO39";
+			bias-disable;
+		};
+	};
+};
+
 &sdhci0 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_sdhci0_default>;
 };
 
 &uart1 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1_default>;
+};
+
+&usb0 {
+	status = "okay";
+	dr_mode = "host";
+	usb-phy = <&usb_phy0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb0_default>;
 };
diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts
index 1c7cc99..5658bc8 100644
--- a/arch/arm/boot/dts/zynq-zed.dts
+++ b/arch/arm/boot/dts/zynq-zed.dts
@@ -18,6 +18,11 @@
 	model = "Zynq Zed Development Board";
 	compatible = "xlnx,zynq-zed", "xlnx,zynq-7000";
 
+	aliases {
+		ethernet0 = &gem0;
+		serial0 = &uart1;
+	};
+
 	memory {
 		device_type = "memory";
 		reg = <0x0 0x20000000>;
@@ -27,6 +32,10 @@
 		bootargs = "console=ttyPS0,115200 earlyprintk";
 	};
 
+	usb_phy0: phy0 {
+		compatible = "usb-nop-xceiv";
+		#phy-cells = <0>;
+	};
 };
 
 &clkc {
@@ -50,3 +59,9 @@
 &uart1 {
 	status = "okay";
 };
+
+&usb0 {
+	status = "okay";
+	dr_mode = "host";
+	usb-phy = <&usb_phy0>;
+};
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index a67375f..f2670f6 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -15,15 +15,7 @@
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_AT91=y
 CONFIG_SOC_AT91RM9200=y
-CONFIG_SOC_AT91SAM9260=y
-CONFIG_SOC_AT91SAM9261=y
-CONFIG_SOC_AT91SAM9263=y
-CONFIG_SOC_AT91SAM9RL=y
-CONFIG_SOC_AT91SAM9G45=y
-CONFIG_SOC_AT91SAM9X5=y
-CONFIG_SOC_AT91SAM9N12=y
-CONFIG_MACH_AT91RM9200_DT=y
-CONFIG_MACH_AT91SAM9_DT=y
+CONFIG_SOC_AT91SAM9=y
 CONFIG_AT91_TIMER_HZ=128
 CONFIG_AEABI=y
 CONFIG_UACCESS_WITH_MEMCPY=y
diff --git a/arch/arm/configs/efm32_defconfig b/arch/arm/configs/efm32_defconfig
index f59fffb..c4c17e3 100644
--- a/arch/arm/configs/efm32_defconfig
+++ b/arch/arm/configs/efm32_defconfig
@@ -17,7 +17,6 @@
 # CONFIG_IOSCHED_CFQ is not set
 # CONFIG_MMU is not set
 CONFIG_ARCH_EFM32=y
-# CONFIG_KUSER_HELPERS is not set
 CONFIG_SET_MEM_PARAM=y
 CONFIG_DRAM_BASE=0x88000000
 CONFIG_DRAM_SIZE=0x00400000
@@ -49,7 +48,6 @@
 CONFIG_MTD_BLOCK_RO=y
 CONFIG_MTD_ROM=y
 CONFIG_MTD_UCLINUX=y
-CONFIG_PROC_DEVICETREE=y
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_ARC is not set
@@ -78,6 +76,9 @@
 CONFIG_SERIAL_EFM32_UART=y
 CONFIG_SERIAL_EFM32_UART_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_EFM32=y
 CONFIG_SPI=y
 CONFIG_SPI_EFM32=y
 CONFIG_GPIO_SYSFS=y
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index 3d0c5d6..1d89353 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -1,4 +1,5 @@
 CONFIG_SYSVIPC=y
+CONFIG_FHANDLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_CGROUPS=y
@@ -83,6 +84,10 @@
 CONFIG_DEBUG_GPIO=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_BATTERY_SBS=y
+CONFIG_BATTERY_MAX17040=y
+CONFIG_BATTERY_MAX17042=y
+CONFIG_CHARGER_MAX14577=y
+CONFIG_CHARGER_MAX77693=y
 CONFIG_CHARGER_TPS65090=y
 CONFIG_HWMON=y
 CONFIG_SENSORS_LM90=y
@@ -94,6 +99,7 @@
 CONFIG_MFD_CROS_EC=y
 CONFIG_MFD_CROS_EC_I2C=y
 CONFIG_MFD_CROS_EC_SPI=y
+CONFIG_MFD_MAX14577=y
 CONFIG_MFD_MAX77686=y
 CONFIG_MFD_MAX77693=y
 CONFIG_MFD_MAX8997=y
@@ -102,6 +108,7 @@
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_MAX14577=y
 CONFIG_REGULATOR_MAX8997=y
 CONFIG_REGULATOR_MAX77686=y
 CONFIG_REGULATOR_MAX77802=y
@@ -168,6 +175,9 @@
 CONFIG_COMMON_CLK_MAX77802=y
 CONFIG_COMMON_CLK_S2MPS11=y
 CONFIG_EXYNOS_IOMMU=y
+CONFIG_EXTCON=y
+CONFIG_EXTCON_MAX14577=y
+CONFIG_EXTCON_MAX77693=y
 CONFIG_IIO=y
 CONFIG_EXYNOS_ADC=y
 CONFIG_PWM=y
@@ -198,6 +208,7 @@
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
+CONFIG_LOCKUP_DETECTOR=y
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_SHA256=y
diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig
index 1125436..c34da58 100644
--- a/arch/arm/configs/hisi_defconfig
+++ b/arch/arm/configs/hisi_defconfig
@@ -8,6 +8,7 @@
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_CMDLINE_PARTITION=y
 CONFIG_ARCH_HIX5HD2=y
+CONFIG_ARCH_HIP01=y
 CONFIG_ARCH_HIP04=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 7c2075a..cf1e71e 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -97,6 +97,7 @@
 CONFIG_MTD_NAND_GPMI_NAND=y
 CONFIG_MTD_NAND_MXC=y
 CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_FSL_QUADSPI=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
@@ -129,6 +130,11 @@
 CONFIG_SMSC911X=y
 # CONFIG_NET_VENDOR_STMICRO is not set
 CONFIG_AT803X_PHY=y
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_CDC_EEM=m
 CONFIG_BRCMFMAC=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=y
@@ -163,13 +169,14 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_MC9S08DZ60=y
 CONFIG_GPIO_STMPE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_IMX=y
+CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SENSORS_GPIO_FAN=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
 CONFIG_IMX_THERMAL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_IMX=y
 CONFIG_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_DA9052_I2C=y
@@ -189,6 +196,8 @@
 CONFIG_MEDIA_RC_SUPPORT=y
 CONFIG_RC_DEVICES=y
 CONFIG_IR_GPIO_CIR=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
 CONFIG_SOC_CAMERA=y
 CONFIG_VIDEO_MX3=y
@@ -198,16 +207,17 @@
 CONFIG_IMX_IPUV3_CORE=y
 CONFIG_DRM=y
 CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_L4F00242T03=y
 CONFIG_LCD_PLATFORM=y
+CONFIG_FB_MXS=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_BACKLIGHT_GPIO=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 CONFIG_SOUND=y
 CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_FSL_SAI=y
 CONFIG_SND_IMX_SOC=y
@@ -226,11 +236,32 @@
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_UDC=y
 CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_EHSET_TEST_FIXTURE=m
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_USB_MXS_PHY=y
 CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_ZERO=m
 CONFIG_USB_ETH=m
+CONFIG_USB_G_NCM=m
+CONFIG_USB_GADGETFS=m
 CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index a2067cb..f8a1c8f 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -201,3 +201,4 @@
 CONFIG_GPIO_SYSCON=y
 CONFIG_TI_DAVINCI_MDIO=y
 CONFIG_MARVELL_PHY=y
+CONFIG_DEVTMPFS=y
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
index 5d63fc5..23e8d14 100644
--- a/arch/arm/configs/kzm9g_defconfig
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -126,8 +126,8 @@
 CONFIG_SH_DMAE=y
 CONFIG_ASYNC_TX_DMA=y
 CONFIG_STAGING=y
-CONFIG_SENSORS_AK8975=y
 CONFIG_IIO=y
+CONFIG_AK8975=y
 # CONFIG_DNOTIFY is not set
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
diff --git a/arch/arm/configs/lager_defconfig b/arch/arm/configs/lager_defconfig
deleted file mode 100644
index a82afc9..0000000
--- a/arch/arm/configs/lager_defconfig
+++ /dev/null
@@ -1,150 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_NO_HZ=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_EMBEDDED=y
-CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_SHMOBILE_LEGACY=y
-CONFIG_ARCH_R8A7790=y
-CONFIG_MACH_LAGER=y
-# CONFIG_SH_TIMER_TMU is not set
-# CONFIG_EM_TIMER_STI is not set
-CONFIG_ARM_ERRATA_430973=y
-CONFIG_ARM_ERRATA_458693=y
-CONFIG_ARM_ERRATA_460075=y
-CONFIG_ARM_ERRATA_743622=y
-CONFIG_ARM_ERRATA_754322=y
-CONFIG_PCI=y
-CONFIG_PCI_RCAR_GEN2=y
-CONFIG_PCI_RCAR_GEN2_PCIE=y
-CONFIG_HAVE_ARM_ARCH_TIMER=y
-CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_FORCE_MAX_ZONEORDER=13
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_KEXEC=y
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_SATA_RCAR=y
-CONFIG_NETDEVICES=y
-# CONFIG_NET_CORE is not set
-# CONFIG_NET_VENDOR_ARC is not set
-# CONFIG_NET_CADENCE is not set
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_CIRRUS is not set
-# CONFIG_NET_VENDOR_FARADAY is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-CONFIG_SH_ETH=y
-# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SMSC is not set
-# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_NET_VENDOR_VIA is not set
-# CONFIG_NET_VENDOR_WIZNET is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=10
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C_GPIO=y
-CONFIG_I2C_SH_MOBILE=y
-CONFIG_I2C_RCAR=y
-CONFIG_SPI=y
-CONFIG_SPI_RSPI=y
-CONFIG_SPI_SH_MSIOF=y
-CONFIG_GPIO_SH_PFC=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_RCAR=y
-# CONFIG_HWMON is not set
-CONFIG_THERMAL=y
-CONFIG_RCAR_THERMAL=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
-CONFIG_REGULATOR_DA9210=y
-CONFIG_REGULATOR_GPIO=y
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_SOC_CAMERA=y
-CONFIG_SOC_CAMERA_PLATFORM=y
-CONFIG_VIDEO_RCAR_VIN=y
-# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-CONFIG_VIDEO_ADV7180=y
-CONFIG_DRM=y
-CONFIG_DRM_RCAR_DU=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_RCAR=y
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_SDHI=y
-CONFIG_MMC_SH_MMCIF=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_DMADEVICES=y
-CONFIG_SH_DMAE=y
-# CONFIG_IOMMU_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_ARM_UNWIND is not set
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 444685c..e8a4c95 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -32,6 +32,7 @@
 CONFIG_ARCH_HISI=y
 CONFIG_ARCH_HI3xxx=y
 CONFIG_ARCH_HIX5HD2=y
+CONFIG_ARCH_HIP01=y
 CONFIG_ARCH_HIP04=y
 CONFIG_ARCH_KEYSTONE=y
 CONFIG_ARCH_MESON=y
@@ -60,6 +61,7 @@
 CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_EXYNOS=y
+CONFIG_EXYNOS5420_MCPM=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_SIRF=y
 CONFIG_ARCH_TEGRA=y
@@ -78,6 +80,7 @@
 CONFIG_ARCH_ZYNQ=y
 CONFIG_TRUSTED_FOUNDATIONS=y
 CONFIG_PCI=y
+CONFIG_PCI_KEYSTONE=y
 CONFIG_PCI_MSI=y
 CONFIG_PCI_MVEBU=y
 CONFIG_PCI_TEGRA=y
@@ -132,6 +135,7 @@
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_DAVINCI=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTD_UBI=y
 CONFIG_BLK_DEV_LOOP=y
@@ -189,12 +193,15 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ATMEL_MXT=y
 CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_TOUCHSCREEN_SUN4I=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_MPU3050=y
+CONFIG_INPUT_AXP20X_PEK=y
 CONFIG_SERIO_AMBAKMI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_SERIAL_MESON=y
@@ -220,6 +227,7 @@
 CONFIG_SERIAL_ST_ASC=y
 CONFIG_SERIAL_ST_ASC_CONSOLE=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_DAVINCI=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_MUX_PCA954x=y
 CONFIG_I2C_MUX_PINCTRL=y
@@ -233,6 +241,7 @@
 CONFIG_I2C_ST=y
 CONFIG_SPI=y
 CONFIG_I2C_XILINX=y
+CONFIG_SPI_DAVINCI=y
 CONFIG_SPI_CADENCE=y
 CONFIG_SPI_OMAP24XX=y
 CONFIG_SPI_ORION=y
@@ -251,23 +260,28 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_GENERIC_PLATFORM=y
 CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_DAVINCI=y
 CONFIG_GPIO_XILINX=y
 CONFIG_GPIO_ZYNQ=y
 CONFIG_GPIO_PCA953X=y
 CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_GPIO_TWL4030=y
 CONFIG_GPIO_PALMAS=y
+CONFIG_GPIO_SYSCON=y
 CONFIG_GPIO_TPS6586X=y
 CONFIG_GPIO_TPS65910=y
 CONFIG_BATTERY_SBS=y
 CONFIG_CHARGER_TPS65090=y
 CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_KEYSTONE=y
 CONFIG_POWER_RESET_SUN6I=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM95245=y
 CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
 CONFIG_ARMADA_THERMAL=y
+CONFIG_DAVINCI_WATCHDOG
 CONFIG_ST_THERMAL_SYSCFG=y
 CONFIG_ST_THERMAL_MEMMAP=y
 CONFIG_WATCHDOG=y
@@ -278,6 +292,7 @@
 CONFIG_MESON_WATCHDOG=y
 CONFIG_MFD_AS3722=y
 CONFIG_MFD_BCM590XX=y
+CONFIG_MFD_AXP20X=y
 CONFIG_MFD_CROS_EC=y
 CONFIG_MFD_CROS_EC_SPI=y
 CONFIG_MFD_MAX77686=y
@@ -290,6 +305,7 @@
 CONFIG_MFD_TPS65910=y
 CONFIG_REGULATOR_AB8500=y
 CONFIG_REGULATOR_AS3722=y
+CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_BCM590XX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MFD_SYSCON=y
@@ -347,9 +363,11 @@
 CONFIG_USB_OHCI_HCD_STI=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
 CONFIG_USB_CHIPIDEA=y
 CONFIG_USB_CHIPIDEA_HOST=y
 CONFIG_AB8500_USB=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_OMAP_USB3=y
 CONFIG_SAMSUNG_USB2PHY=y
 CONFIG_SAMSUNG_USB3PHY=y
@@ -445,6 +463,7 @@
 CONFIG_TEGRA_IOMMU_GART=y
 CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_MEMORY=y
+CONFIG_TI_AEMIF=y
 CONFIG_IIO=y
 CONFIG_XILINX_XADC=y
 CONFIG_AK8975=y
@@ -454,6 +473,7 @@
 CONFIG_PHY_HIX5HD2_SATA=y
 CONFIG_OMAP_USB2=y
 CONFIG_TI_PIPE3=y
+CONFIG_PHY_MIPHY28LP=y
 CONFIG_PHY_MIPHY365X=y
 CONFIG_PHY_STIH41X_USB=y
 CONFIG_PHY_STIH407_USB=y
@@ -482,3 +502,4 @@
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_CRYPTO_DEV_TEGRA_AES=y
 CONFIG_CPUFREQ_DT=y
+CONFIG_KEYSTONE_IRQ=y
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index 627acce..73673e9 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -26,6 +26,7 @@
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_MVEBU_V7_CPUIDLE=y
 CONFIG_VFP=y
@@ -112,6 +113,7 @@
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_S35390A=y
 CONFIG_RTC_DRV_MV=y
+CONFIG_RTC_DRV_ARMADA38X=y
 CONFIG_DMADEVICES=y
 CONFIG_MV_XOR=y
 # CONFIG_IOMMU_SUPPORT is not set
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 667d9d5..b738652 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -13,7 +13,6 @@
 CONFIG_CGROUP_DEVICE=y
 CONFIG_CPUSETS=y
 CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
 CONFIG_MEMCG=y
 CONFIG_MEMCG_SWAP=y
 CONFIG_MEMCG_KMEM=y
@@ -103,13 +102,15 @@
 CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_DMA_CMA=y
 CONFIG_OMAP_OCP2SCP=y
-CONFIG_CONNECTOR=y
+CONFIG_CONNECTOR=m
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_OOPS=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_BCH=y
 CONFIG_MTD_NAND_OMAP2=y
@@ -122,14 +123,12 @@
 CONFIG_BLK_DEV_RAM_SIZE=16384
 CONFIG_SENSORS_TSL2550=m
 CONFIG_BMP085_I2C=m
-CONFIG_SENSORS_LIS3_I2C=m
 CONFIG_SRAM=y
-CONFIG_SCSI=y
+CONFIG_SENSORS_LIS3_I2C=m
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI_PLATFORM=y
-CONFIG_MD=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_CADENCE is not set
@@ -149,16 +148,19 @@
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
 # CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_TI_DAVINCI_EMAC=y
 CONFIG_TI_CPSW=y
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 CONFIG_AT803X_PHY=y
 CONFIG_SMSC_PHY=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_SMSC95XX=m
 CONFIG_USB_ALI_M5632=y
 CONFIG_USB_AN2720=y
 CONFIG_USB_EPSON2888=y
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_KC2190=y
 CONFIG_LIBERTAS=m
 CONFIG_LIBERTAS_USB=m
@@ -172,18 +174,24 @@
 CONFIG_MWIFIEX=m
 CONFIG_MWIFIEX_SDIO=m
 CONFIG_MWIFIEX_USB=m
-CONFIG_INPUT_JOYDEV=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_KEYBOARD_ATKBD=m
+CONFIG_KEYBOARD_GPIO=m
 CONFIG_KEYBOARD_MATRIX=m
-CONFIG_KEYBOARD_TWL4030=y
+CONFIG_KEYBOARD_OMAP4=m
+CONFIG_KEYBOARD_TWL4030=m
+# CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=m
 CONFIG_TOUCHSCREEN_EDT_FT5X06=m
 CONFIG_TOUCHSCREEN_TSC2005=m
 CONFIG_TOUCHSCREEN_TSC2007=m
 CONFIG_INPUT_MISC=y
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_TPS65218_PWRBUTTON=m
+CONFIG_INPUT_TWL4030_PWRBUTTON=m
+CONFIG_INPUT_PALMAS_PWRBUTTON=m
+CONFIG_SERIO=m
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -196,15 +204,18 @@
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_OMAP=y
 CONFIG_SERIAL_OMAP_CONSOLE=y
-CONFIG_HW_RANDOM=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_SPI=y
 CONFIG_SPI_OMAP24XX=y
+CONFIG_SPI_TI_QSPI=m
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_PCF857X=m
 CONFIG_GPIO_TWL4030=y
-CONFIG_W1=y
+CONFIG_GPIO_PALMAS=y
+CONFIG_W1=m
+CONFIG_HDQ_MASTER_OMAP=m
 CONFIG_BATTERY_BQ27x00=m
 CONFIG_CHARGER_ISP1704=m
 CONFIG_CHARGER_TWL4030=m
@@ -213,20 +224,22 @@
 CONFIG_CHARGER_BQ24735=m
 CONFIG_POWER_RESET=y
 CONFIG_POWER_AVS=y
+CONFIG_HWMON=m
+CONFIG_SENSORS_GPIO_FAN=m
 CONFIG_SENSORS_LM75=m
-CONFIG_THERMAL=y
+CONFIG_SENSORS_TMP102=m
+CONFIG_THERMAL=m
 CONFIG_THERMAL_GOV_FAIR_SHARE=y
 CONFIG_THERMAL_GOV_USER_SPACE=y
 CONFIG_CPU_THERMAL=y
-CONFIG_TI_SOC_THERMAL=y
+CONFIG_TI_SOC_THERMAL=m
 CONFIG_TI_THERMAL=y
 CONFIG_OMAP4_THERMAL=y
 CONFIG_OMAP5_THERMAL=y
 CONFIG_DRA752_THERMAL=y
 CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_WATCHDOG=y
-CONFIG_MFD_SYSCON=y
+CONFIG_OMAP_WATCHDOG=m
+CONFIG_TWL4030_WATCHDOG=m
 CONFIG_MFD_PALMAS=y
 CONFIG_MFD_TPS65217=y
 CONFIG_MFD_TPS65218=y
@@ -289,51 +302,79 @@
 CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
 CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
 CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
-CONFIG_USB=y
+CONFIG_HID_GENERIC=m
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB=m
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_MON=y
+CONFIG_USB_MON=m
 CONFIG_USB_XHCI_HCD=m
-CONFIG_USB_WDM=y
-CONFIG_USB_STORAGE=y
+CONFIG_USB_WDM=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_MUSB_HDRC=m
+CONFIG_USB_MUSB_OMAP2PLUS=m
+CONFIG_USB_MUSB_AM35X=m
+CONFIG_USB_MUSB_DSPS=m
 CONFIG_USB_DWC3=m
-CONFIG_USB_TEST=y
+CONFIG_USB_TEST=m
 CONFIG_AM335X_PHY_USB=y
-CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET=m
 CONFIG_USB_GADGET_DEBUG=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_ACM=y
+CONFIG_USB_CONFIGFS_OBEX=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_ECM=y
+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
+CONFIG_USB_CONFIGFS_RNDIS=y
+CONFIG_USB_CONFIGFS_EEM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_LB_SS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_UAC1=y
+CONFIG_USB_CONFIGFS_F_UAC2=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_ZERO=m
 CONFIG_MMC=y
 CONFIG_SDIO_UART=y
 CONFIG_MMC_OMAP=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_ONESHOT=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
 CONFIG_LEDS_TRIGGER_CPU=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_RTC_DRV_PALMAS=m
 CONFIG_RTC_DRV_TWL92330=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_RTC_DRV_OMAP=y
+CONFIG_RTC_DRV_TWL4030=m
+CONFIG_RTC_DRV_OMAP=m
 CONFIG_DMADEVICES=y
 CONFIG_TI_EDMA=y
 CONFIG_DMA_OMAP=y
-CONFIG_EXTCON=y
-CONFIG_EXTCON_PALMAS=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXTCON=m
+CONFIG_EXTCON_PALMAS=m
+CONFIG_TI_EMIF=m
 CONFIG_PWM=y
-CONFIG_PWM_TIECAP=y
-CONFIG_PWM_TIEHRPWM=y
-CONFIG_PWM_TWL=y
-CONFIG_PWM_TWL_LED=y
-CONFIG_OMAP_USB2=y
-CONFIG_TI_PIPE3=y
+CONFIG_PWM_TIECAP=m
+CONFIG_PWM_TIEHRPWM=m
+CONFIG_PWM_TWL=m
+CONFIG_PWM_TWL_LED=m
+CONFIG_OMAP_USB2=m
+CONFIG_TI_PIPE3=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index afa2479..41d856e 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -139,6 +139,12 @@
 CONFIG_SSB=m
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_ACT8865=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_VIDEO_ATMEL_ISI=y
 CONFIG_FB=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
@@ -202,8 +208,6 @@
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_FTRACE is not set
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index 3df6ca0..b170360 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -17,9 +17,8 @@
 CONFIG_ARCH_R8A7790=y
 CONFIG_ARCH_R8A7791=y
 CONFIG_ARCH_R8A7794=y
-CONFIG_MACH_LAGER=y
+CONFIG_ARCH_SH73A0=y
 CONFIG_MACH_MARZEN=y
-# CONFIG_SWP_EMULATE is not set
 CONFIG_CPU_BPREDICT_DISABLE=y
 CONFIG_PL310_ERRATA_588369=y
 CONFIG_ARM_ERRATA_754322=y
@@ -36,10 +35,16 @@
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_KEXEC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -49,7 +54,9 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_SIMPLE_PM_BUS=y
 CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_EEPROM_AT24=y
@@ -73,11 +80,15 @@
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 CONFIG_SMSC_PHY=y
+CONFIG_MICREL_PHY=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ST1232=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_ADXL34X=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
@@ -86,6 +97,7 @@
 CONFIG_SERIAL_SH_SCI=y
 CONFIG_SERIAL_SH_SCI_NR_UARTS=20
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_GPIO=y
 CONFIG_I2C_RIIC=y
 CONFIG_I2C_SH_MOBILE=y
@@ -96,11 +108,18 @@
 CONFIG_SPI_SH_HSPI=y
 CONFIG_GPIO_EM=y
 CONFIG_GPIO_RCAR=y
+CONFIG_GPIO_PCF857X=y
 # CONFIG_HWMON is not set
 CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
 CONFIG_RCAR_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_DA9063_WATCHDOG=y
+CONFIG_MFD_AS3711=y
+CONFIG_MFD_DA9063=y
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_AS3711=y
+CONFIG_REGULATOR_DA9210=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -116,10 +135,12 @@
 CONFIG_VIDEO_ADV7180=y
 CONFIG_DRM=y
 CONFIG_DRM_RCAR_DU=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_FB_SH_MOBILE_MERAM=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 # CONFIG_BACKLIGHT_GENERIC is not set
 CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_AS3711=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
@@ -130,6 +151,7 @@
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_R8A66597_HCD=y
 CONFIG_USB_RENESAS_USBHS=y
 CONFIG_USB_RCAR_PHY=y
 CONFIG_USB_RCAR_GEN2_PHY=y
@@ -143,18 +165,20 @@
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_RS5C372=y
 CONFIG_RTC_DRV_S35390A=y
 CONFIG_DMADEVICES=y
 CONFIG_SH_DMAE=y
 CONFIG_RCAR_DMAC=y
 # CONFIG_IOMMU_SUPPORT is not set
+CONFIG_IIO=y
+CONFIG_AK8975=y
 CONFIG_PWM=y
 CONFIG_PWM_RENESAS_TPU=y
 # CONFIG_DNOTIFY is not set
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3_ACL=y
@@ -166,16 +190,3 @@
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 # CONFIG_ARM_UNWIND is not set
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_GOV_COMMON=y
-CONFIG_CPU_FREQ_STAT=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_CPU_THERMAL=y
-CONFIG_CPUFREQ_DT=y
-CONFIG_REGULATOR_DA9210=y
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 7a342d2..38840a8 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -9,6 +9,8 @@
 CONFIG_HIGHPTE=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_VFP=y
 CONFIG_NEON=y
 CONFIG_PM=y
@@ -54,6 +56,10 @@
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SUN4I=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=8
@@ -71,12 +77,14 @@
 CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SUN6I=y
-# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_SUNXI_WATCHDOG=y
 CONFIG_MFD_AXP20X=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 3ea9c33..d199eb2 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -8,7 +8,6 @@
 CONFIG_CGROUP_DEBUG=y
 CONFIG_CGROUP_FREEZER=y
 CONFIG_CGROUP_CPUACCT=y
-CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_DEV_INITRD=y
@@ -46,7 +45,6 @@
 CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NEON=y
-CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
diff --git a/arch/arm/include/debug/at91.S b/arch/arm/include/debug/at91.S
new file mode 100644
index 0000000..80a6501
--- /dev/null
+++ b/arch/arm/include/debug/at91.S
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2003-2005 SAN People
+ *
+ * Debugging macro include header
+ *
+ * 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.
+ *
+*/
+
+#if defined(CONFIG_AT91_DEBUG_LL_DBGU0)
+#define AT91_DBGU 0xfffff200 /* AT91_BASE_DBGU0 */
+#elif defined(CONFIG_AT91_DEBUG_LL_DBGU1)
+#define AT91_DBGU 0xffffee00 /* AT91_BASE_DBGU1 */
+#else
+/* On sama5d4, use USART3 as low level serial console */
+#define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
+#endif
+
+/* Keep in sync with mach-at91/include/mach/hardware.h */
+#define AT91_IO_P2V(x) ((x) - 0x01000000)
+
+#define AT91_DBGU_SR		(0x14)	/* Status Register */
+#define AT91_DBGU_THR		(0x1c)	/* Transmitter Holding Register */
+#define AT91_DBGU_TXRDY		(1 << 1)	/* Transmitter Ready */
+#define AT91_DBGU_TXEMPTY	(1 << 9)	/* Transmitter Empty */
+
+	.macro	addruart, rp, rv, tmp
+	ldr	\rp, =AT91_DBGU				@ System peripherals (phys address)
+	ldr	\rv, =AT91_IO_P2V(AT91_DBGU)		@ System peripherals (virt address)
+	.endm
+
+	.macro	senduart,rd,rx
+	strb	\rd, [\rx, #(AT91_DBGU_THR)]		@ Write to Transmitter Holding Register
+	.endm
+
+	.macro	waituart,rd,rx
+1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR)]		@ Read Status Register
+	tst	\rd, #AT91_DBGU_TXRDY			@ DBGU_TXRDY = 1 when ready to transmit
+	beq	1001b
+	.endm
+
+	.macro	busyuart,rd,rx
+1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR)]		@ Read Status Register
+	tst	\rd, #AT91_DBGU_TXEMPTY			@ DBGU_TXEMPTY = 1 when transmission complete
+	beq	1001b
+	.endm
+
diff --git a/arch/arm/include/debug/digicolor.S b/arch/arm/include/debug/digicolor.S
new file mode 100644
index 0000000..c951715
--- /dev/null
+++ b/arch/arm/include/debug/digicolor.S
@@ -0,0 +1,35 @@
+/*
+ * Debugging macro include header for Conexant Digicolor USART
+ *
+ * Copyright (C) 2014 Paradox Innovation 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.
+ *
+*/
+
+#define UA0_STATUS	0x0742
+#define UA0_EMI_REC	0x0744
+
+#define UA0_STATUS_TX_READY	0x40
+
+#ifdef CONFIG_DEBUG_UART_PHYS
+		.macro	addruart, rp, rv, tmp
+		ldr	\rp, =CONFIG_DEBUG_UART_PHYS
+		ldr	\rv, =CONFIG_DEBUG_UART_VIRT
+		.endm
+#endif
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx, #UA0_EMI_REC]
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
+
+	.macro	busyuart,rd,rx
+1001:		ldrb	\rd, [\rx, #UA0_STATUS]
+		tst	\rd, #UA0_STATUS_TX_READY
+		beq	1001b
+		.endm
diff --git a/arch/arm/include/debug/msm.S b/arch/arm/include/debug/msm.S
index 9ef5761..e55a942 100644
--- a/arch/arm/include/debug/msm.S
+++ b/arch/arm/include/debug/msm.S
@@ -23,6 +23,7 @@
 	.endm
 
 	.macro	senduart, rd, rx
+ARM_BE8(rev	\rd, \rd )
 #ifdef CONFIG_DEBUG_QCOM_UARTDM
 	@ Write the 1 character to UARTDM_TF
 	str	\rd, [\rx, #0x70]
@@ -35,24 +36,29 @@
 #ifdef CONFIG_DEBUG_QCOM_UARTDM
 	@ check for TX_EMT in UARTDM_SR
 	ldr	\rd, [\rx, #0x08]
+ARM_BE8(rev     \rd, \rd )
 	tst	\rd, #0x08
 	bne	1002f
 	@ wait for TXREADY in UARTDM_ISR
 1001:	ldr	\rd, [\rx, #0x14]
+ARM_BE8(rev     \rd, \rd )
 	tst	\rd, #0x80
 	beq 	1001b
 1002:
 	@ Clear TX_READY by writing to the UARTDM_CR register
 	mov	\rd, #0x300
+ARM_BE8(rev     \rd, \rd )
 	str	\rd, [\rx, #0x10]
 	@ Write 0x1 to NCF register
 	mov 	\rd, #0x1
+ARM_BE8(rev     \rd, \rd )
 	str	\rd, [\rx, #0x40]
 	@ UARTDM reg. Read to induce delay
 	ldr	\rd, [\rx, #0x08]
 #else
 	@ wait for TX_READY
 1001:	ldr	\rd, [\rx, #0x08]
+ARM_BE8(rev     \rd, \rd )
 	tst	\rd, #0x04
 	beq	1001b
 #endif
diff --git a/arch/arm/include/debug/sirf.S b/arch/arm/include/debug/sirf.S
index dbf250c..630f231 100644
--- a/arch/arm/include/debug/sirf.S
+++ b/arch/arm/include/debug/sirf.S
@@ -6,37 +6,33 @@
  * Licensed under GPLv2 or later.
  */
 
-#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1)
-#define SIRFSOC_UART1_PA_BASE          0xb0060000
-#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1)
-#define SIRFSOC_UART1_PA_BASE          0xcc060000
+#define SIRF_LLUART_TXFIFO_STATUS	0x0114
+#define SIRF_LLUART_TXFIFO_DATA	0x0118
+
+#define SIRF_LLUART_TXFIFO_FULL                       (1 << 5)
+
+#ifdef CONFIG_DEBUG_SIRFATLAS7_UART0
+#define SIRF_LLUART_TXFIFO_EMPTY			(1 << 8)
 #else
-#define SIRFSOC_UART1_PA_BASE          0
+#define SIRF_LLUART_TXFIFO_EMPTY			(1 << 6)
 #endif
 
-#define SIRFSOC_UART1_VA_BASE		0xFEC60000
-
-#define SIRFSOC_UART_TXFIFO_STATUS	0x0114
-#define SIRFSOC_UART_TXFIFO_DATA	0x0118
-
-#define SIRFSOC_UART1_TXFIFO_FULL                       (1 << 5)
-#define SIRFSOC_UART1_TXFIFO_EMPTY			(1 << 6)
 
 	.macro	addruart, rp, rv, tmp
-	ldr	\rp, =SIRFSOC_UART1_PA_BASE		@ physical
-	ldr	\rv, =SIRFSOC_UART1_VA_BASE		@ virtual
+	ldr	\rp, =CONFIG_DEBUG_UART_PHYS		@ physical
+	ldr	\rv, =CONFIG_DEBUG_UART_VIRT		@ virtual
 	.endm
 
 	.macro	senduart,rd,rx
-	str	\rd, [\rx, #SIRFSOC_UART_TXFIFO_DATA]
+	str	\rd, [\rx, #SIRF_LLUART_TXFIFO_DATA]
 	.endm
 
 	.macro	busyuart,rd,rx
 	.endm
 
 	.macro	waituart,rd,rx
-1001:	ldr	\rd, [\rx, #SIRFSOC_UART_TXFIFO_STATUS]
-	tst	\rd, #SIRFSOC_UART1_TXFIFO_EMPTY
+1001:	ldr	\rd, [\rx, #SIRF_LLUART_TXFIFO_STATUS]
+	tst	\rd, #SIRF_LLUART_TXFIFO_EMPTY
 	beq	1001b
 	.endm
 
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index bea7db9..2e11961 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -41,7 +41,7 @@
 void *module_alloc(unsigned long size)
 {
 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-				GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+				GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
 				__builtin_return_address(0));
 }
 #endif
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 2395c68..c6740e3 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -6,15 +6,6 @@
 config HAVE_AT91_USB_CLK
 	bool
 
-config HAVE_AT91_DBGU0
-	bool
-
-config HAVE_AT91_DBGU1
-	bool
-
-config HAVE_AT91_DBGU2
-	bool
-
 config COMMON_CLK_AT91
 	bool
 	select COMMON_CLK
@@ -25,15 +16,6 @@
 config HAVE_AT91_H32MX
 	bool
 
-config SOC_AT91SAM9
-	bool
-	select ATMEL_AIC_IRQ
-	select COMMON_CLK_AT91
-	select CPU_ARM926T
-	select GENERIC_CLOCKEVENTS
-	select MEMORY
-	select ATMEL_SDRAMC
-
 config SOC_SAMA5
 	bool
 	select ATMEL_AIC5_IRQ
@@ -70,7 +52,6 @@
 	bool "SAMA5D3 family"
 	select SOC_SAMA5
 	select HAVE_FB_ATMEL
-	select HAVE_AT91_DBGU1
 	select HAVE_AT91_UTMI
 	select HAVE_AT91_SMD
 	select HAVE_AT91_USB_CLK
@@ -81,7 +62,6 @@
 config SOC_SAMA5D4
 	bool "SAMA5D4 family"
 	select SOC_SAMA5
-	select HAVE_AT91_DBGU2
 	select CLKSRC_MMIO
 	select CACHE_L2X0
 	select CACHE_PL310
@@ -101,91 +81,45 @@
 	select COMMON_CLK_AT91
 	select CPU_ARM920T
 	select GENERIC_CLOCKEVENTS
-	select HAVE_AT91_DBGU0
 	select HAVE_AT91_USB_CLK
 
-config SOC_AT91SAM9260
-	bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
-	select HAVE_AT91_DBGU0
-	select SOC_AT91SAM9
-	select HAVE_AT91_USB_CLK
-	help
-	  Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
-	  or AT91SAM9G20 SoC.
-
-config SOC_AT91SAM9261
-	bool "AT91SAM9261 or AT91SAM9G10"
-	select HAVE_AT91_DBGU0
-	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_USB_CLK
-	help
-	  Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
-
-config SOC_AT91SAM9263
-	bool "AT91SAM9263"
-	select HAVE_AT91_DBGU1
-	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_USB_CLK
-
-config SOC_AT91SAM9RL
-	bool "AT91SAM9RL"
-	select HAVE_AT91_DBGU0
-	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_UTMI
-
-config SOC_AT91SAM9G45
-	bool "AT91SAM9G45 or AT91SAM9M10 families"
-	select HAVE_AT91_DBGU1
-	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_UTMI
-	select HAVE_AT91_USB_CLK
-	help
-	  Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
-	  This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
-
-config SOC_AT91SAM9X5
-	bool "AT91SAM9x5 family"
-	select HAVE_AT91_DBGU0
-	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_UTMI
+config SOC_AT91SAM9
+	bool "AT91SAM9"
+	select ATMEL_AIC_IRQ
+	select ATMEL_SDRAMC
+	select COMMON_CLK_AT91
+	select CPU_ARM926T
+	select GENERIC_CLOCKEVENTS
 	select HAVE_AT91_SMD
 	select HAVE_AT91_USB_CLK
-	help
-	  Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
-	  This means that your SAM9 name finishes with a '5' (except if it is
-	  AT91SAM9G45!).
-	  This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
-	  and AT91SAM9X35.
-
-config SOC_AT91SAM9N12
-	bool "AT91SAM9N12 family"
-	select HAVE_AT91_DBGU0
+	select HAVE_AT91_UTMI
 	select HAVE_FB_ATMEL
-	select SOC_AT91SAM9
-	select HAVE_AT91_USB_CLK
+	select MEMORY
 	help
-	  Select this if you are using Atmel's AT91SAM9N12 SoC.
-
-# ----------------------------------------------------------
+	  Select this if you are using one of those Atmel SoC:
+	    AT91SAM9260
+	    AT91SAM9261
+	    AT91SAM9263
+	    AT91SAM9G15
+	    AT91SAM9G20
+	    AT91SAM9G25
+	    AT91SAM9G35
+	    AT91SAM9G45
+	    AT91SAM9G46
+	    AT91SAM9M10
+	    AT91SAM9M11
+	    AT91SAM9N12
+	    AT91SAM9RL
+	    AT91SAM9X25
+	    AT91SAM9X35
+	    AT91SAM9XE
 endif # SOC_SAM_V4_V5
 
-config MACH_AT91RM9200_DT
-	def_bool SOC_AT91RM9200
-
-config MACH_AT91SAM9_DT
-	def_bool SOC_AT91SAM9
-
-# ----------------------------------------------------------
-
 comment "AT91 Feature Selections"
 
 config AT91_SLOW_CLOCK
 	bool "Suspend-to-RAM disables main oscillator"
+	select SRAM
 	depends on SUSPEND
 	help
 	  Select this if you want Suspend-to-RAM to save the most power
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 7b6424d..827fdbc 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -2,28 +2,14 @@
 # Makefile for the linux kernel.
 #
 
-obj-y		:= setup.o sysirq_mask.o
+obj-y		:= setup.o
 
 obj-$(CONFIG_SOC_AT91SAM9)	+= sam9_smc.o
 
 # CPU-specific support
 obj-$(CONFIG_SOC_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o
-obj-$(CONFIG_SOC_AT91SAM9260)	+= at91sam9260.o
-obj-$(CONFIG_SOC_AT91SAM9261)	+= at91sam9261.o
-obj-$(CONFIG_SOC_AT91SAM9263)	+= at91sam9263.o
-obj-$(CONFIG_SOC_AT91SAM9G45)	+= at91sam9g45.o
-obj-$(CONFIG_SOC_AT91SAM9N12)	+= at91sam9n12.o
-obj-$(CONFIG_SOC_AT91SAM9X5)	+= at91sam9x5.o
-obj-$(CONFIG_SOC_AT91SAM9RL)	+= at91sam9rl.o
-obj-$(CONFIG_SOC_SAMA5D3)	+= sama5d3.o
-obj-$(CONFIG_SOC_SAMA5D4)	+= sama5d4.o
-
-# AT91SAM board with device-tree
-obj-$(CONFIG_MACH_AT91RM9200_DT) += board-dt-rm9200.o
-obj-$(CONFIG_MACH_AT91SAM9_DT) += board-dt-sam9.o
-
-# SAMA5 board with device-tree
-obj-$(CONFIG_SOC_SAMA5)		+= board-dt-sama5.o
+obj-$(CONFIG_SOC_AT91SAM9)	+= at91sam9.o
+obj-$(CONFIG_SOC_SAMA5)		+= sama5.o
 
 # Power Management
 obj-$(CONFIG_PM)		+= pm.o
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index b529169..8fcfb70 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -1,35 +1,33 @@
 /*
- * arch/arm/mach-at91/at91rm9200.c
+ *  Setup code for AT91RM9200
  *
- *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2011 Atmel,
+ *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *                2012 Joachim Eastwood <manabian@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.
- *
+ * Licensed under GPLv2 or later.
  */
 
+#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/clk/at91_pmc.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
 
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/irq.h>
 #include <asm/system_misc.h>
+
 #include <mach/at91_st.h>
-#include <mach/hardware.h>
 
-#include "soc.h"
 #include "generic.h"
 
-static void at91rm9200_idle(void)
-{
-	/*
-	 * Disable the processor clock.  The processor will be automatically
-	 * re-enabled by an interrupt or by a reset.
-	 */
-	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
-}
-
 static void at91rm9200_restart(enum reboot_mode reboot_mode, const char *cmd)
 {
 	/*
@@ -39,23 +37,31 @@
 	at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
-/* --------------------------------------------------------------------
- *  AT91RM9200 processor initialization
- * -------------------------------------------------------------------- */
-static void __init at91rm9200_map_io(void)
+static void __init at91rm9200_dt_timer_init(void)
 {
-	/* Map peripherals */
-	at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
+	of_clk_init(NULL);
+	at91rm9200_timer_init();
 }
 
-static void __init at91rm9200_initialize(void)
+static void __init at91rm9200_dt_device_init(void)
 {
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
 	arm_pm_idle = at91rm9200_idle;
 	arm_pm_restart = at91rm9200_restart;
+	at91rm9200_pm_init();
 }
 
 
-AT91_SOC_START(at91rm9200)
-	.map_io = at91rm9200_map_io,
-	.init = at91rm9200_initialize,
-AT91_SOC_END
+
+static const char *at91rm9200_dt_board_compat[] __initconst = {
+	"atmel,at91rm9200",
+	NULL
+};
+
+DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200")
+	.init_time      = at91rm9200_dt_timer_init,
+	.map_io		= at91_map_io,
+	.init_machine	= at91rm9200_dt_device_init,
+	.dt_compat	= at91rm9200_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c
new file mode 100644
index 0000000..56e3ba7
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9.c
@@ -0,0 +1,87 @@
+/*
+ *  Setup code for AT91SAM9
+ *
+ *  Copyright (C) 2011 Atmel,
+ *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk-provider.h>
+
+#include <asm/system_misc.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "generic.h"
+
+static void __init at91sam9_dt_device_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	arm_pm_idle = at91sam9_idle;
+	at91sam9260_pm_init();
+}
+
+static const char *at91_dt_board_compat[] __initconst = {
+	"atmel,at91sam9",
+	NULL
+};
+
+DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
+	/* Maintainer: Atmel */
+	.map_io		= at91_map_io,
+	.init_machine	= at91sam9_dt_device_init,
+	.dt_compat	= at91_dt_board_compat,
+MACHINE_END
+
+static void __init at91sam9g45_dt_device_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	arm_pm_idle = at91sam9_idle;
+	at91sam9g45_pm_init();
+}
+
+static const char *at91sam9g45_board_compat[] __initconst = {
+	"atmel,at91sam9g45",
+	NULL
+};
+
+DT_MACHINE_START(at91sam9g45_dt, "Atmel AT91SAM9G45")
+	/* Maintainer: Atmel */
+	.map_io		= at91_map_io,
+	.init_machine	= at91sam9g45_dt_device_init,
+	.dt_compat	= at91sam9g45_board_compat,
+MACHINE_END
+
+static void __init at91sam9x5_dt_device_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	arm_pm_idle = at91sam9_idle;
+	at91sam9x5_pm_init();
+}
+
+static const char *at91sam9x5_board_compat[] __initconst = {
+	"atmel,at91sam9x5",
+	"atmel,at91sam9n12",
+	NULL
+};
+
+DT_MACHINE_START(at91sam9x5_dt, "Atmel AT91SAM9")
+	/* Maintainer: Atmel */
+	.map_io		= at91_map_io,
+	.init_machine	= at91sam9x5_dt_device_init,
+	.dt_compat	= at91sam9x5_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
deleted file mode 100644
index 78137c2..0000000
--- a/arch/arm/mach-at91/at91sam9260.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9260.c
- *
- *  Copyright (C) 2006 SAN People
- *
- * 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 <asm/system_misc.h>
-#include <mach/cpu.h>
-#include <mach/at91_dbgu.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9260 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9xe_map_io(void)
-{
-	unsigned long sram_size;
-
-	switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
-		case AT91_CIDR_SRAMSIZ_32K:
-			sram_size = 2 * SZ_16K;
-			break;
-		case AT91_CIDR_SRAMSIZ_16K:
-		default:
-			sram_size = SZ_16K;
-	}
-
-	at91_init_sram(0, AT91SAM9XE_SRAM_BASE, sram_size);
-}
-
-static void __init at91sam9260_map_io(void)
-{
-	if (cpu_is_at91sam9xe())
-		at91sam9xe_map_io();
-	else if (cpu_is_at91sam9g20())
-		at91_init_sram(0, AT91SAM9G20_SRAM_BASE, AT91SAM9G20_SRAM_SIZE);
-	else
-		at91_init_sram(0, AT91SAM9260_SRAM_BASE, AT91SAM9260_SRAM_SIZE);
-}
-
-static void __init at91sam9260_initialize(void)
-{
-	arm_pm_idle = at91sam9_idle;
-
-	at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
-}
-
-AT91_SOC_START(at91sam9260)
-	.map_io = at91sam9260_map_io,
-	.init = at91sam9260_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
deleted file mode 100644
index d29953e..0000000
--- a/arch/arm/mach-at91/at91sam9261.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9261.c
- *
- *  Copyright (C) 2005 SAN People
- *
- * 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 <asm/system_misc.h>
-#include <mach/cpu.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9261 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9261_map_io(void)
-{
-	if (cpu_is_at91sam9g10())
-		at91_init_sram(0, AT91SAM9G10_SRAM_BASE, AT91SAM9G10_SRAM_SIZE);
-	else
-		at91_init_sram(0, AT91SAM9261_SRAM_BASE, AT91SAM9261_SRAM_SIZE);
-}
-
-static void __init at91sam9261_initialize(void)
-{
-	arm_pm_idle = at91sam9_idle;
-
-	at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
-}
-
-AT91_SOC_START(at91sam9261)
-	.map_io = at91sam9261_map_io,
-	.init = at91sam9261_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
deleted file mode 100644
index e7ad148..0000000
--- a/arch/arm/mach-at91/at91sam9263.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9263.c
- *
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <asm/system_misc.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9263 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9263_map_io(void)
-{
-	at91_init_sram(0, AT91SAM9263_SRAM0_BASE, AT91SAM9263_SRAM0_SIZE);
-	at91_init_sram(1, AT91SAM9263_SRAM1_BASE, AT91SAM9263_SRAM1_SIZE);
-}
-
-static void __init at91sam9263_initialize(void)
-{
-	arm_pm_idle = at91sam9_idle;
-
-	at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
-	at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
-}
-
-AT91_SOC_START(at91sam9263)
-	.map_io = at91sam9263_map_io,
-	.init = at91sam9263_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
deleted file mode 100644
index b6117be..0000000
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  Chip-specific setup code for the AT91SAM9G45 family
- *
- *  Copyright (C) 2009 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <asm/system_misc.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9G45 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9g45_map_io(void)
-{
-	at91_init_sram(0, AT91SAM9G45_SRAM_BASE, AT91SAM9G45_SRAM_SIZE);
-}
-
-static void __init at91sam9g45_initialize(void)
-{
-	arm_pm_idle = at91sam9_idle;
-
-	at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
-	at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
-}
-
-AT91_SOC_START(at91sam9g45)
-	.map_io = at91sam9g45_map_io,
-	.init = at91sam9g45_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
deleted file mode 100644
index dee569b..0000000
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SoC specific setup code for the AT91SAM9N12
- *
- * Copyright (C) 2012 Atmel Corporation.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <asm/system_misc.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9N12 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9n12_map_io(void)
-{
-	at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
-}
-
-static void __init at91sam9n12_initialize(void)
-{
-	at91_sysirq_mask_rtc(AT91SAM9N12_BASE_RTC);
-}
-
-AT91_SOC_START(at91sam9n12)
-	.map_io = at91sam9n12_map_io,
-	.init = at91sam9n12_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
deleted file mode 100644
index f25b9ae..0000000
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9rl.c
- *
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2007 Atmel Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#include <asm/system_misc.h>
-#include <asm/irq.h>
-#include <mach/cpu.h>
-#include <mach/at91_dbgu.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9RL processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9rl_map_io(void)
-{
-	unsigned long sram_size;
-
-	switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
-		case AT91_CIDR_SRAMSIZ_32K:
-			sram_size = 2 * SZ_16K;
-			break;
-		case AT91_CIDR_SRAMSIZ_16K:
-		default:
-			sram_size = SZ_16K;
-	}
-
-	/* Map SRAM */
-	at91_init_sram(0, AT91SAM9RL_SRAM_BASE, sram_size);
-}
-
-static void __init at91sam9rl_initialize(void)
-{
-	arm_pm_idle = at91sam9_idle;
-
-	at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
-	at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
-}
-
-AT91_SOC_START(at91sam9rl)
-	.map_io = at91sam9rl_map_io,
-	.init = at91sam9rl_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
deleted file mode 100644
index f0d5a69..0000000
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  Chip-specific setup code for the AT91SAM9x5 family
- *
- *  Copyright (C) 2010-2012 Atmel Corporation.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <asm/system_misc.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9x5 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91sam9x5_map_io(void)
-{
-	at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
-}
-
-static void __init at91sam9x5_initialize(void)
-{
-	at91_sysirq_mask_rtc(AT91SAM9X5_BASE_RTC);
-}
-
-/* --------------------------------------------------------------------
- *  Interrupt initialization
- * -------------------------------------------------------------------- */
-
-AT91_SOC_START(at91sam9x5)
-	.map_io = at91sam9x5_map_io,
-	.init = at91sam9x5_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/board-dt-rm9200.c b/arch/arm/mach-at91/board-dt-rm9200.c
deleted file mode 100644
index 76dfe8f..0000000
--- a/arch/arm/mach-at91/board-dt-rm9200.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Setup code for AT91RM9200 Evaluation Kits with Device Tree support
- *
- *  Copyright (C) 2011 Atmel,
- *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
- *                2012 Joachim Eastwood <manabian@gmail.com>
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/clk-provider.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include "generic.h"
-
-static void __init at91rm9200_dt_timer_init(void)
-{
-	of_clk_init(NULL);
-	at91rm9200_timer_init();
-}
-
-static const char *at91rm9200_dt_board_compat[] __initdata = {
-	"atmel,at91rm9200",
-	NULL
-};
-
-DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)")
-	.init_time      = at91rm9200_dt_timer_init,
-	.map_io		= at91_map_io,
-	.init_early	= at91rm9200_dt_initialize,
-	.dt_compat	= at91rm9200_dt_board_compat,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-dt-sam9.c b/arch/arm/mach-at91/board-dt-sam9.c
deleted file mode 100644
index f99246a..0000000
--- a/arch/arm/mach-at91/board-dt-sam9.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  Setup code for AT91SAM Evaluation Kits with Device Tree support
- *
- *  Copyright (C) 2011 Atmel,
- *                2011 Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/clk-provider.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include "generic.h"
-
-static const char *at91_dt_board_compat[] __initdata = {
-	"atmel,at91sam9",
-	NULL
-};
-
-DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
-	/* Maintainer: Atmel */
-	.map_io		= at91_map_io,
-	.init_early	= at91_dt_initialize,
-	.dt_compat	= at91_dt_board_compat,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-dt-sama5.c b/arch/arm/mach-at91/board-dt-sama5.c
deleted file mode 100644
index 97f7367..0000000
--- a/arch/arm/mach-at91/board-dt-sama5.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Setup code for SAMA5 Evaluation Kits with Device Tree support
- *
- *  Copyright (C) 2013 Atmel,
- *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/micrel_phy.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/phy.h>
-#include <linux/clk-provider.h>
-#include <linux/phy.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include "generic.h"
-
-static int ksz8081_phy_fixup(struct phy_device *phy)
-{
-	int value;
-
-	value = phy_read(phy, 0x16);
-	value &= ~0x20;
-	phy_write(phy, 0x16, value);
-
-	return 0;
-}
-
-static void __init sama5_dt_device_init(void)
-{
-	if (of_machine_is_compatible("atmel,sama5d4ek") &&
-	   IS_ENABLED(CONFIG_PHYLIB)) {
-		phy_register_fixup_for_id("fc028000.etherne:00",
-						ksz8081_phy_fixup);
-	}
-
-	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
-static const char *sama5_dt_board_compat[] __initconst = {
-	"atmel,sama5",
-	NULL
-};
-
-DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)")
-	/* Maintainer: Atmel */
-	.map_io		= at91_map_io,
-	.init_early	= at91_dt_initialize,
-	.init_machine	= sama5_dt_device_init,
-	.dt_compat	= sama5_dt_board_compat,
-MACHINE_END
-
-static const char *sama5_alt_dt_board_compat[] __initconst = {
-	"atmel,sama5d4",
-	NULL
-};
-
-DT_MACHINE_START(sama5_alt_dt, "Atmel SAMA5 (Device Tree)")
-	/* Maintainer: Atmel */
-	.map_io		= at91_alt_map_io,
-	.init_early	= at91_dt_initialize,
-	.init_machine	= sama5_dt_device_init,
-	.dt_compat	= sama5_alt_dt_board_compat,
-	.l2c_aux_mask	= ~0UL,
-MACHINE_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index d533242..a6e726a 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -17,24 +17,28 @@
  /* Map io */
 extern void __init at91_map_io(void);
 extern void __init at91_alt_map_io(void);
-extern void __init at91_init_sram(int bank, unsigned long base,
-				  unsigned int length);
-
- /* Processors */
-extern void __init at91rm9200_set_type(int type);
-extern void __init at91rm9200_dt_initialize(void);
-extern void __init at91_dt_initialize(void);
-
- /* Interrupts */
-extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
-extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
 
  /* Timer */
 extern void at91rm9200_timer_init(void);
 
 /* idle */
+extern void at91rm9200_idle(void);
 extern void at91sam9_idle(void);
 
 /* Matrix */
 extern void at91_ioremap_matrix(u32 base_addr);
+
+
+#ifdef CONFIG_PM
+extern void __init at91rm9200_pm_init(void);
+extern void __init at91sam9260_pm_init(void);
+extern void __init at91sam9g45_pm_init(void);
+extern void __init at91sam9x5_pm_init(void);
+#else
+void __init at91rm9200_pm_init(void) { }
+void __init at91sam9260_pm_init(void) { }
+void __init at91sam9g45_pm_init(void) { }
+void __init at91sam9x5_pm_init(void) { }
+#endif
+
 #endif /* _AT91_GENERIC_H */
diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h
deleted file mode 100644
index 7b73662..0000000
--- a/arch/arm/mach-at91/include/mach/at91_pio.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_pio.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Parallel I/O Controller (PIO) - System peripherals registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * 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 AT91_PIO_H
-#define AT91_PIO_H
-
-#define PIO_PER		0x00	/* Enable Register */
-#define PIO_PDR		0x04	/* Disable Register */
-#define PIO_PSR		0x08	/* Status Register */
-#define PIO_OER		0x10	/* Output Enable Register */
-#define PIO_ODR		0x14	/* Output Disable Register */
-#define PIO_OSR		0x18	/* Output Status Register */
-#define PIO_IFER	0x20	/* Glitch Input Filter Enable */
-#define PIO_IFDR	0x24	/* Glitch Input Filter Disable */
-#define PIO_IFSR	0x28	/* Glitch Input Filter Status */
-#define PIO_SODR	0x30	/* Set Output Data Register */
-#define PIO_CODR	0x34	/* Clear Output Data Register */
-#define PIO_ODSR	0x38	/* Output Data Status Register */
-#define PIO_PDSR	0x3c	/* Pin Data Status Register */
-#define PIO_IER		0x40	/* Interrupt Enable Register */
-#define PIO_IDR		0x44	/* Interrupt Disable Register */
-#define PIO_IMR		0x48	/* Interrupt Mask Register */
-#define PIO_ISR		0x4c	/* Interrupt Status Register */
-#define PIO_MDER	0x50	/* Multi-driver Enable Register */
-#define PIO_MDDR	0x54	/* Multi-driver Disable Register */
-#define PIO_MDSR	0x58	/* Multi-driver Status Register */
-#define PIO_PUDR	0x60	/* Pull-up Disable Register */
-#define PIO_PUER	0x64	/* Pull-up Enable Register */
-#define PIO_PUSR	0x68	/* Pull-up Status Register */
-#define PIO_ASR		0x70	/* Peripheral A Select Register */
-#define PIO_ABCDSR1	0x70	/* Peripheral ABCD Select Register 1 [some sam9 only] */
-#define PIO_BSR		0x74	/* Peripheral B Select Register */
-#define PIO_ABCDSR2	0x74	/* Peripheral ABCD Select Register 2 [some sam9 only] */
-#define PIO_ABSR	0x78	/* AB Status Register */
-#define PIO_IFSCDR	0x80	/* Input Filter Slow Clock Disable Register */
-#define PIO_IFSCER	0x84	/* Input Filter Slow Clock Enable Register */
-#define PIO_IFSCSR	0x88	/* Input Filter Slow Clock Status Register */
-#define PIO_SCDR	0x8c	/* Slow Clock Divider Debouncing Register */
-#define		PIO_SCDR_DIV	(0x3fff <<  0)		/* Slow Clock Divider Mask */
-#define PIO_PPDDR	0x90	/* Pad Pull-down Disable Register */
-#define PIO_PPDER	0x94	/* Pad Pull-down Enable Register */
-#define PIO_PPDSR	0x98	/* Pad Pull-down Status Register */
-#define PIO_OWER	0xa0	/* Output Write Enable Register */
-#define PIO_OWDR	0xa4	/* Output Write Disable Register */
-#define PIO_OWSR	0xa8	/* Output Write Status Register */
-#define PIO_AIMER	0xb0	/* Additional Interrupt Modes Enable Register */
-#define PIO_AIMDR	0xb4	/* Additional Interrupt Modes Disable Register */
-#define PIO_AIMMR	0xb8	/* Additional Interrupt Modes Mask Register */
-#define PIO_ESR		0xc0	/* Edge Select Register */
-#define PIO_LSR		0xc4	/* Level Select Register */
-#define PIO_ELSR	0xc8	/* Edge/Level Status Register */
-#define PIO_FELLSR	0xd0	/* Falling Edge/Low Level Select Register */
-#define PIO_REHLSR	0xd4	/* Rising Edge/ High Level Select Register */
-#define PIO_FRLHSR	0xd8	/* Fall/Rise - Low/High Status Register */
-#define PIO_SCHMITT	0x100	/* Schmitt Trigger Register */
-
-#define ABCDSR_PERIPH_A	0x0
-#define ABCDSR_PERIPH_B	0x1
-#define ABCDSR_PERIPH_C	0x2
-#define ABCDSR_PERIPH_D	0x3
-
-#define SAMA5D3_PIO_DRIVER1		0x118  /*PIO Driver 1 register offset*/
-#define SAMA5D3_PIO_DRIVER2		0x11C  /*PIO Driver 2 register offset*/
-
-#define AT91SAM9X5_PIO_DRIVER1	0x114  /*PIO Driver 1 register offset*/
-#define AT91SAM9X5_PIO_DRIVER2	0x118  /*PIO Driver 2 register offset*/
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91_rtt.h b/arch/arm/mach-at91/include/mach/at91_rtt.h
deleted file mode 100644
index 7ec75de..0000000
--- a/arch/arm/mach-at91/include/mach/at91_rtt.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_rtt.h
- *
- * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
- *
- * Real-time Timer (RTT) - System peripherals regsters.
- * Based on AT91SAM9261 datasheet revision D.
- *
- * 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 AT91_RTT_H
-#define AT91_RTT_H
-
-#define AT91_RTT_MR		0x00			/* Real-time Mode Register */
-#define		AT91_RTT_RTPRES		(0xffff << 0)		/* Real-time Timer Prescaler Value */
-#define		AT91_RTT_ALMIEN		(1 << 16)		/* Alarm Interrupt Enable */
-#define		AT91_RTT_RTTINCIEN	(1 << 17)		/* Real Time Timer Increment Interrupt Enable */
-#define		AT91_RTT_RTTRST		(1 << 18)		/* Real Time Timer Restart */
-
-#define AT91_RTT_AR		0x04			/* Real-time Alarm Register */
-#define		AT91_RTT_ALMV		(0xffffffff)		/* Alarm Value */
-
-#define AT91_RTT_VR		0x08			/* Real-time Value Register */
-#define		AT91_RTT_CRTV		(0xffffffff)		/* Current Real-time Value */
-
-#define AT91_RTT_SR		0x0c			/* Real-time Status Register */
-#define		AT91_RTT_ALMS		(1 << 0)		/* Real-time Alarm Status */
-#define		AT91_RTT_RTTINC		(1 << 1)		/* Real-time Timer Increment */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index 61914fb..ce7c80a 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -152,69 +152,45 @@
 #define cpu_is_at91rm9200_pqfp() (0)
 #endif
 
-#ifdef CONFIG_SOC_AT91SAM9260
+#ifdef CONFIG_SOC_AT91SAM9
 #define cpu_is_at91sam9xe()	(at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
 #define cpu_is_at91sam9260()	(at91_soc_initdata.type == AT91_SOC_SAM9260)
 #define cpu_is_at91sam9g20()	(at91_soc_initdata.type == AT91_SOC_SAM9G20)
-#else
-#define cpu_is_at91sam9xe()	(0)
-#define cpu_is_at91sam9260()	(0)
-#define cpu_is_at91sam9g20()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9261
 #define cpu_is_at91sam9261()	(at91_soc_initdata.type == AT91_SOC_SAM9261)
 #define cpu_is_at91sam9g10()	(at91_soc_initdata.type == AT91_SOC_SAM9G10)
-#else
-#define cpu_is_at91sam9261()	(0)
-#define cpu_is_at91sam9g10()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9263
 #define cpu_is_at91sam9263()	(at91_soc_initdata.type == AT91_SOC_SAM9263)
-#else
-#define cpu_is_at91sam9263()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9RL
 #define cpu_is_at91sam9rl()	(at91_soc_initdata.type == AT91_SOC_SAM9RL)
-#else
-#define cpu_is_at91sam9rl()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9G45
 #define cpu_is_at91sam9g45()	(at91_soc_initdata.type == AT91_SOC_SAM9G45)
 #define cpu_is_at91sam9g45es()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
 #define cpu_is_at91sam9m10()	(at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
 #define cpu_is_at91sam9g46()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G46)
 #define cpu_is_at91sam9m11()	(at91_soc_initdata.subtype == AT91_SOC_SAM9M11)
-#else
-#define cpu_is_at91sam9g45()	(0)
-#define cpu_is_at91sam9g45es()	(0)
-#define cpu_is_at91sam9m10()	(0)
-#define cpu_is_at91sam9g46()	(0)
-#define cpu_is_at91sam9m11()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9X5
 #define cpu_is_at91sam9x5()	(at91_soc_initdata.type == AT91_SOC_SAM9X5)
 #define cpu_is_at91sam9g15()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
 #define cpu_is_at91sam9g35()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
 #define cpu_is_at91sam9x35()	(at91_soc_initdata.subtype == AT91_SOC_SAM9X35)
 #define cpu_is_at91sam9g25()	(at91_soc_initdata.subtype == AT91_SOC_SAM9G25)
 #define cpu_is_at91sam9x25()	(at91_soc_initdata.subtype == AT91_SOC_SAM9X25)
+#define cpu_is_at91sam9n12()	(at91_soc_initdata.type == AT91_SOC_SAM9N12)
 #else
+#define cpu_is_at91sam9xe()	(0)
+#define cpu_is_at91sam9260()	(0)
+#define cpu_is_at91sam9g20()	(0)
+#define cpu_is_at91sam9261()	(0)
+#define cpu_is_at91sam9g10()	(0)
+#define cpu_is_at91sam9263()	(0)
+#define cpu_is_at91sam9rl()	(0)
+#define cpu_is_at91sam9g45()	(0)
+#define cpu_is_at91sam9g45es()	(0)
+#define cpu_is_at91sam9m10()	(0)
+#define cpu_is_at91sam9g46()	(0)
+#define cpu_is_at91sam9m11()	(0)
 #define cpu_is_at91sam9x5()	(0)
 #define cpu_is_at91sam9g15()	(0)
 #define cpu_is_at91sam9g35()	(0)
 #define cpu_is_at91sam9x35()	(0)
 #define cpu_is_at91sam9g25()	(0)
 #define cpu_is_at91sam9x25()	(0)
-#endif
-
-#ifdef CONFIG_SOC_AT91SAM9N12
-#define cpu_is_at91sam9n12()	(at91_soc_initdata.type == AT91_SOC_SAM9N12)
-#else
 #define cpu_is_at91sam9n12()	(0)
 #endif
 
diff --git a/arch/arm/mach-at91/include/mach/debug-macro.S b/arch/arm/mach-at91/include/mach/debug-macro.S
deleted file mode 100644
index 2103a90..0000000
--- a/arch/arm/mach-at91/include/mach/debug-macro.S
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/debug-macro.S
- *
- *  Copyright (C) 2003-2005 SAN People
- *
- * Debugging macro include header
- *
- * 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 <mach/hardware.h>
-#include <mach/at91_dbgu.h>
-
-#if defined(CONFIG_AT91_DEBUG_LL_DBGU0)
-#define AT91_DBGU AT91_BASE_DBGU0
-#elif defined(CONFIG_AT91_DEBUG_LL_DBGU1)
-#define AT91_DBGU AT91_BASE_DBGU1
-#else
-/* On sama5d4, use USART3 as low level serial console */
-#define AT91_DBGU SAMA5D4_BASE_USART3
-#endif
-
-	.macro	addruart, rp, rv, tmp
-	ldr	\rp, =AT91_DBGU				@ System peripherals (phys address)
-	ldr	\rv, =AT91_IO_P2V(AT91_DBGU)		@ System peripherals (virt address)
-	.endm
-
-	.macro	senduart,rd,rx
-	strb	\rd, [\rx, #(AT91_DBGU_THR)]		@ Write to Transmitter Holding Register
-	.endm
-
-	.macro	waituart,rd,rx
-1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR)]		@ Read Status Register
-	tst	\rd, #AT91_DBGU_TXRDY			@ DBGU_TXRDY = 1 when ready to transmit
-	beq	1001b
-	.endm
-
-	.macro	busyuart,rd,rx
-1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR)]		@ Read Status Register
-	tst	\rd, #AT91_DBGU_TXEMPTY			@ DBGU_TXEMPTY = 1 when transmission complete
-	beq	1001b
-	.endm
-
diff --git a/arch/arm/mach-at91/include/mach/memory.h b/arch/arm/mach-at91/include/mach/memory.h
deleted file mode 100644
index 401c207..0000000
--- a/arch/arm/mach-at91/include/mach/memory.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/memory.h
- *
- *  Copyright (C) 2004 SAN People
- *
- * 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_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#include <mach/hardware.h>
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h
deleted file mode 100644
index ef79a9a..0000000
--- a/arch/arm/mach-at91/include/mach/system_rev.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * Under GPLv2 only
- */
-
-#ifndef __ARCH_SYSTEM_REV_H__
-#define __ARCH_SYSTEM_REV_H__
-
-#include <asm/system_info.h>
-
-/*
- * board revision encoding
- * mach specific
- * the 16-31 bit are reserved for at91 generic information
- *
- * bit 31:
- *	0 => nand 8 bit
- *	1 => nand 16 bit
- */
-#define BOARD_HAVE_NAND_16BIT	(1 << 31)
-static inline int board_have_nand_16bit(void)
-{
-	return (system_rev & BOARD_HAVE_NAND_16BIT) ? 1 : 0;
-}
-
-#endif /* __ARCH_SYSTEM_REV_H__ */
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 9b15169..af8d8af 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -14,9 +14,13 @@
 #include <linux/suspend.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <linux/genalloc.h>
 #include <linux/interrupt.h>
 #include <linux/sysfs.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk/at91_pmc.h>
@@ -32,7 +36,13 @@
 #include "generic.h"
 #include "pm.h"
 
+static struct {
+	unsigned long uhp_udp_mask;
+	int memctrl;
+} at91_pm_data;
+
 static void (*at91_pm_standby)(void);
+void __iomem *at91_ramc_base[2];
 
 static int at91_pm_valid_state(suspend_state_t state)
 {
@@ -71,17 +81,9 @@
 	scsr = at91_pmc_read(AT91_PMC_SCSR);
 
 	/* USB must not be using PLLB */
-	if (cpu_is_at91rm9200()) {
-		if ((scsr & (AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP)) != 0) {
-			pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
-			return 0;
-		}
-	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()
-			|| cpu_is_at91sam9g20() || cpu_is_at91sam9g10()) {
-		if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) {
-			pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
-			return 0;
-		}
+	if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
+		pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
+		return 0;
 	}
 
 	/* PCK0..PCK3 must be disabled, or configured to use clk32k */
@@ -149,18 +151,13 @@
 			 * turning off the main oscillator; reverse on wakeup.
 			 */
 			if (slow_clock) {
-				int memctrl = AT91_MEMCTRL_SDRAMC;
-
-				if (cpu_is_at91rm9200())
-					memctrl = AT91_MEMCTRL_MC;
-				else if (cpu_is_at91sam9g45())
-					memctrl = AT91_MEMCTRL_DDRSDR;
 #ifdef CONFIG_AT91_SLOW_CLOCK
 				/* copy slow_clock handler to SRAM, and call it */
 				memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz);
 #endif
 				slow_clock(at91_pmc_base, at91_ramc_base[0],
-					   at91_ramc_base[1], memctrl);
+					   at91_ramc_base[1],
+					   at91_pm_data.memctrl);
 				break;
 			} else {
 				pr_info("AT91: PM - no slow clock mode enabled ...\n");
@@ -229,23 +226,134 @@
 	}
 }
 
-static int __init at91_pm_init(void)
+static struct of_device_id ramc_ids[] = {
+	{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
+	{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
+	{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
+	{ .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
+	{ /*sentinel*/ }
+};
+
+static void at91_dt_ramc(void)
+{
+	struct device_node *np;
+	const struct of_device_id *of_id;
+	int idx = 0;
+	const void *standby = NULL;
+
+	for_each_matching_node_and_match(np, ramc_ids, &of_id) {
+		at91_ramc_base[idx] = of_iomap(np, 0);
+		if (!at91_ramc_base[idx])
+			panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);
+
+		if (!standby)
+			standby = of_id->data;
+
+		idx++;
+	}
+
+	if (!idx)
+		panic(pr_fmt("unable to find compatible ram controller node in dtb\n"));
+
+	if (!standby) {
+		pr_warn("ramc no standby function available\n");
+		return;
+	}
+
+	at91_pm_set_standby(standby);
+}
+
+#ifdef CONFIG_AT91_SLOW_CLOCK
+static void __init at91_pm_sram_init(void)
+{
+	struct gen_pool *sram_pool;
+	phys_addr_t sram_pbase;
+	unsigned long sram_base;
+	struct device_node *node;
+	struct platform_device *pdev;
+
+	node = of_find_compatible_node(NULL, NULL, "mmio-sram");
+	if (!node) {
+		pr_warn("%s: failed to find sram node!\n", __func__);
+		return;
+	}
+
+	pdev = of_find_device_by_node(node);
+	if (!pdev) {
+		pr_warn("%s: failed to find sram device!\n", __func__);
+		goto put_node;
+	}
+
+	sram_pool = dev_get_gen_pool(&pdev->dev);
+	if (!sram_pool) {
+		pr_warn("%s: sram pool unavailable!\n", __func__);
+		goto put_node;
+	}
+
+	sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz);
+	if (!sram_base) {
+		pr_warn("%s: unable to alloc ocram!\n", __func__);
+		goto put_node;
+	}
+
+	sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
+	slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false);
+
+put_node:
+	of_node_put(node);
+}
+#endif
+
+
+static void __init at91_pm_init(void)
 {
 #ifdef CONFIG_AT91_SLOW_CLOCK
-	slow_clock = (void *) (AT91_IO_VIRT_BASE - at91_slow_clock_sz);
+	at91_pm_sram_init();
 #endif
 
 	pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : ""));
 
-	/* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
-	if (cpu_is_at91rm9200())
-		at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
-	
 	if (at91_cpuidle_device.dev.platform_data)
 		platform_device_register(&at91_cpuidle_device);
 
 	suspend_set_ops(&at91_pm_ops);
-
-	return 0;
 }
-arch_initcall(at91_pm_init);
+
+void __init at91rm9200_pm_init(void)
+{
+	at91_dt_ramc();
+
+	/*
+	 * AT91RM9200 SDRAM low-power mode cannot be used with self-refresh.
+	 */
+	at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
+
+	at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
+	at91_pm_data.memctrl = AT91_MEMCTRL_MC;
+
+	at91_pm_init();
+}
+
+void __init at91sam9260_pm_init(void)
+{
+	at91_dt_ramc();
+	at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
+	at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+	return at91_pm_init();
+}
+
+void __init at91sam9g45_pm_init(void)
+{
+	at91_dt_ramc();
+	at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
+	at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+	return at91_pm_init();
+}
+
+void __init at91sam9x5_pm_init(void)
+{
+	at91_dt_ramc();
+	at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+	at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+	return at91_pm_init();
+}
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index 2001877..556151e8 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -17,15 +17,6 @@
 #include <mach/hardware.h>
 #include <mach/at91_ramc.h>
 
-
-#ifdef CONFIG_SOC_AT91SAM9263
-/*
- * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
- * handle those cases both here and in the Suspend-To-RAM support.
- */
-#warning Assuming EB1 SDRAM controller is *NOT* used
-#endif
-
 /*
  * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master
  * clock during suspend by adjusting its prescalar and divisor.
diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c
new file mode 100644
index 0000000..03dcb44
--- /dev/null
+++ b/arch/arm/mach-at91/sama5.c
@@ -0,0 +1,111 @@
+/*
+ *  Setup code for SAMA5
+ *
+ *  Copyright (C) 2013 Atmel,
+ *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/micrel_phy.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/clk-provider.h>
+#include <linux/phy.h>
+
+#include <mach/hardware.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "generic.h"
+
+static int ksz8081_phy_fixup(struct phy_device *phy)
+{
+	int value;
+
+	value = phy_read(phy, 0x16);
+	value &= ~0x20;
+	phy_write(phy, 0x16, value);
+
+	return 0;
+}
+
+static void __init sama5_dt_device_init(void)
+{
+	if (of_machine_is_compatible("atmel,sama5d4ek") &&
+	   IS_ENABLED(CONFIG_PHYLIB)) {
+		phy_register_fixup_for_id("fc028000.etherne:00",
+						ksz8081_phy_fixup);
+	}
+
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	at91sam9x5_pm_init();
+}
+
+static const char *sama5_dt_board_compat[] __initconst = {
+	"atmel,sama5",
+	NULL
+};
+
+DT_MACHINE_START(sama5_dt, "Atmel SAMA5")
+	/* Maintainer: Atmel */
+	.map_io		= at91_map_io,
+	.init_machine	= sama5_dt_device_init,
+	.dt_compat	= sama5_dt_board_compat,
+MACHINE_END
+
+static struct map_desc at91_io_desc[] __initdata = {
+	{
+	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_MPDDRC),
+	.pfn            = __phys_to_pfn(SAMA5D4_BASE_MPDDRC),
+	.length         = SZ_512,
+	.type           = MT_DEVICE,
+	},
+	{
+	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_PMC),
+	.pfn            = __phys_to_pfn(SAMA5D4_BASE_PMC),
+	.length         = SZ_512,
+	.type           = MT_DEVICE,
+	},
+	{ /* On sama5d4, we use USART3 as serial console */
+	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_USART3),
+	.pfn            = __phys_to_pfn(SAMA5D4_BASE_USART3),
+	.length         = SZ_256,
+	.type           = MT_DEVICE,
+	},
+	{ /* A bunch of peripheral with fine grained IO space */
+	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_SYS2),
+	.pfn            = __phys_to_pfn(SAMA5D4_BASE_SYS2),
+	.length         = SZ_2K,
+	.type           = MT_DEVICE,
+	},
+};
+
+static void __init sama5_alt_map_io(void)
+{
+	at91_alt_map_io();
+	iotable_init(at91_io_desc, ARRAY_SIZE(at91_io_desc));
+}
+
+static const char *sama5_alt_dt_board_compat[] __initconst = {
+	"atmel,sama5d4",
+	NULL
+};
+
+DT_MACHINE_START(sama5_alt_dt, "Atmel SAMA5")
+	/* Maintainer: Atmel */
+	.map_io		= sama5_alt_map_io,
+	.init_machine	= sama5_dt_device_init,
+	.dt_compat	= sama5_alt_dt_board_compat,
+	.l2c_aux_mask	= ~0UL,
+MACHINE_END
diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c
deleted file mode 100644
index 3d775d0..0000000
--- a/arch/arm/mach-at91/sama5d3.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  Chip-specific setup code for the SAMA5D3 family
- *
- *  Copyright (C) 2013 Atmel,
- *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/sama5d3.h>
-#include <mach/cpu.h>
-
-#include "soc.h"
-#include "generic.h"
-#include "sam9_smc.h"
-
-/* --------------------------------------------------------------------
- *  AT91SAM9x5 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init sama5d3_map_io(void)
-{
-	at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE);
-}
-
-static void __init sama5d3_initialize(void)
-{
-	at91_sysirq_mask_rtc(SAMA5D3_BASE_RTC);
-}
-
-AT91_SOC_START(sama5d3)
-	.map_io = sama5d3_map_io,
-	.init = sama5d3_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/sama5d4.c b/arch/arm/mach-at91/sama5d4.c
deleted file mode 100644
index 7638509..0000000
--- a/arch/arm/mach-at91/sama5d4.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *  Chip-specific setup code for the SAMA5D4 family
- *
- *  Copyright (C) 2013 Atmel Corporation,
- *                     Nicolas Ferre <nicolas.ferre@atmel.com>
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/sama5d4.h>
-#include <mach/cpu.h>
-#include <mach/hardware.h>
-
-#include "soc.h"
-#include "generic.h"
-#include "sam9_smc.h"
-
-/* --------------------------------------------------------------------
- *  Processor initialization
- * -------------------------------------------------------------------- */
-static struct map_desc at91_io_desc[] __initdata = {
-	{
-	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_MPDDRC),
-	.pfn            = __phys_to_pfn(SAMA5D4_BASE_MPDDRC),
-	.length         = SZ_512,
-	.type           = MT_DEVICE,
-	},
-	{
-	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_PMC),
-	.pfn            = __phys_to_pfn(SAMA5D4_BASE_PMC),
-	.length         = SZ_512,
-	.type           = MT_DEVICE,
-	},
-	{ /* On sama5d4, we use USART3 as serial console */
-	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_USART3),
-	.pfn            = __phys_to_pfn(SAMA5D4_BASE_USART3),
-	.length         = SZ_256,
-	.type           = MT_DEVICE,
-	},
-	{ /* A bunch of peripheral with fine grained IO space */
-	.virtual        = (unsigned long)AT91_ALT_IO_P2V(SAMA5D4_BASE_SYS2),
-	.pfn            = __phys_to_pfn(SAMA5D4_BASE_SYS2),
-	.length         = SZ_2K,
-	.type           = MT_DEVICE,
-	},
-};
-
-
-static void __init sama5d4_map_io(void)
-{
-	iotable_init(at91_io_desc, ARRAY_SIZE(at91_io_desc));
-	at91_init_sram(0, SAMA5D4_NS_SRAM_BASE, SAMA5D4_NS_SRAM_SIZE);
-}
-
-AT91_SOC_START(sama5d4)
-	.map_io = sama5d4_map_io,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index ce25e85..4e58bc9 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -22,49 +22,12 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 
-#include "soc.h"
 #include "generic.h"
 #include "pm.h"
 
-struct at91_init_soc __initdata at91_boot_soc;
-
 struct at91_socinfo at91_soc_initdata;
 EXPORT_SYMBOL(at91_soc_initdata);
 
-void __init at91rm9200_set_type(int type)
-{
-	if (type == ARCH_REVISON_9200_PQFP)
-		at91_soc_initdata.subtype = AT91_SOC_RM9200_PQFP;
-	else
-		at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
-
-	pr_info("filled in soc subtype: %s\n",
-		at91_get_soc_subtype(&at91_soc_initdata));
-}
-
-void __iomem *at91_ramc_base[2];
-EXPORT_SYMBOL_GPL(at91_ramc_base);
-
-static struct map_desc sram_desc[2] __initdata;
-
-void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
-{
-	struct map_desc *desc = &sram_desc[bank];
-
-	desc->virtual = (unsigned long)AT91_IO_VIRT_BASE - length;
-	if (bank > 0)
-		desc->virtual -= sram_desc[bank - 1].length;
-
-	desc->pfn = __phys_to_pfn(base);
-	desc->length = length;
-	desc->type = MT_MEMORY_RWX_NONCACHED;
-
-	pr_info("sram at 0x%lx of 0x%x mapped at 0x%lx\n",
-		base, length, desc->virtual);
-
-	iotable_init(desc, 1);
-}
-
 static struct map_desc at91_io_desc __initdata __maybe_unused = {
 	.virtual	= (unsigned long)AT91_VA_BASE_SYS,
 	.pfn		= __phys_to_pfn(AT91_BASE_SYS),
@@ -91,61 +54,51 @@
 		at91_soc_initdata.type = AT91_SOC_RM9200;
 		if (at91_soc_initdata.subtype == AT91_SOC_SUBTYPE_UNKNOWN)
 			at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
-		at91_boot_soc = at91rm9200_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9260:
 		at91_soc_initdata.type = AT91_SOC_SAM9260;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9260_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9261:
 		at91_soc_initdata.type = AT91_SOC_SAM9261;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9261_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9263:
 		at91_soc_initdata.type = AT91_SOC_SAM9263;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9263_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9G20:
 		at91_soc_initdata.type = AT91_SOC_SAM9G20;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9260_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9G45:
 		at91_soc_initdata.type = AT91_SOC_SAM9G45;
 		if (cidr == ARCH_ID_AT91SAM9G45ES)
 			at91_soc_initdata.subtype = AT91_SOC_SAM9G45ES;
-		at91_boot_soc = at91sam9g45_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9RL64:
 		at91_soc_initdata.type = AT91_SOC_SAM9RL;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9rl_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9X5:
 		at91_soc_initdata.type = AT91_SOC_SAM9X5;
-		at91_boot_soc = at91sam9x5_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9N12:
 		at91_soc_initdata.type = AT91_SOC_SAM9N12;
-		at91_boot_soc = at91sam9n12_soc;
 		break;
 
 	case ARCH_ID_SAMA5:
 		at91_soc_initdata.exid = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_EXID);
 		if (at91_soc_initdata.exid & ARCH_EXID_SAMA5D3) {
 			at91_soc_initdata.type = AT91_SOC_SAMA5D3;
-			at91_boot_soc = sama5d3_soc;
 		}
 		break;
 	}
@@ -154,13 +107,11 @@
 	if ((socid & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
 		at91_soc_initdata.type = AT91_SOC_SAM9G10;
 		at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
-		at91_boot_soc = at91sam9261_soc;
 	}
 	/* at91sam9xe */
 	else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
 		at91_soc_initdata.type = AT91_SOC_SAM9260;
 		at91_soc_initdata.subtype = AT91_SOC_SAM9XE;
-		at91_boot_soc = at91sam9260_soc;
 	}
 
 	if (!at91_soc_is_detected())
@@ -240,10 +191,8 @@
 		at91_soc_initdata.exid = __raw_readl(AT91_ALT_IO_P2V(dbgu_base) + AT91_DBGU_EXID);
 		if (at91_soc_initdata.exid & ARCH_EXID_SAMA5D3) {
 			at91_soc_initdata.type = AT91_SOC_SAMA5D3;
-			at91_boot_soc = sama5d3_soc;
 		} else if (at91_soc_initdata.exid & ARCH_EXID_SAMA5D4) {
 			at91_soc_initdata.type = AT91_SOC_SAMA5D4;
-			at91_boot_soc = sama5d4_soc;
 		}
 		break;
 	}
@@ -349,12 +298,6 @@
 	if (at91_soc_initdata.subtype != AT91_SOC_SUBTYPE_NONE)
 		pr_info("Detected soc subtype: %s\n",
 			at91_get_soc_subtype(&at91_soc_initdata));
-
-	if (!at91_soc_is_enabled())
-		panic(pr_fmt("Soc not enabled"));
-
-	if (at91_boot_soc.map_io)
-		at91_boot_soc.map_io();
 }
 
 void __init at91_alt_map_io(void)
@@ -374,12 +317,6 @@
 	if (at91_soc_initdata.subtype != AT91_SOC_SUBTYPE_NONE)
 		pr_info("AT91: Detected soc subtype: %s\n",
 			at91_get_soc_subtype(&at91_soc_initdata));
-
-	if (!at91_soc_is_enabled())
-		panic("AT91: Soc not enabled");
-
-	if (at91_boot_soc.map_io)
-		at91_boot_soc.map_io();
 }
 
 void __iomem *at91_matrix_base;
@@ -391,55 +328,3 @@
 	if (!at91_matrix_base)
 		panic(pr_fmt("Impossible to ioremap at91_matrix_base\n"));
 }
-
-static struct of_device_id ramc_ids[] = {
-	{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
-	{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
-	{ .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
-	{ .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
-	{ /*sentinel*/ }
-};
-
-static void at91_dt_ramc(void)
-{
-	struct device_node *np;
-	const struct of_device_id *of_id;
-	int idx = 0;
-	const void *standby = NULL;
-
-	for_each_matching_node_and_match(np, ramc_ids, &of_id) {
-		at91_ramc_base[idx] = of_iomap(np, 0);
-		if (!at91_ramc_base[idx])
-			panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);
-
-		if (!standby)
-			standby = of_id->data;
-
-		idx++;
-	}
-
-	if (!idx)
-		panic(pr_fmt("unable to find compatible ram controller node in dtb\n"));
-
-	if (!standby) {
-		pr_warn("ramc no standby function available\n");
-		return;
-	}
-
-	at91_pm_set_standby(standby);
-}
-
-void __init at91rm9200_dt_initialize(void)
-{
-	at91_dt_ramc();
-
-	at91_boot_soc.init();
-}
-
-void __init at91_dt_initialize(void)
-{
-	at91_dt_ramc();
-
-	if (at91_boot_soc.init)
-		at91_boot_soc.init();
-}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
deleted file mode 100644
index ae6c0b2..0000000
--- a/arch/arm/mach-at91/soc.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * Under GPLv2
- */
-
-struct at91_init_soc {
-	int builtin;
-	void (*map_io)(void);
-	void (*init)(void);
-};
-
-extern struct at91_init_soc at91_boot_soc;
-extern struct at91_init_soc at91rm9200_soc;
-extern struct at91_init_soc at91sam9260_soc;
-extern struct at91_init_soc at91sam9261_soc;
-extern struct at91_init_soc at91sam9263_soc;
-extern struct at91_init_soc at91sam9g45_soc;
-extern struct at91_init_soc at91sam9rl_soc;
-extern struct at91_init_soc at91sam9x5_soc;
-extern struct at91_init_soc at91sam9n12_soc;
-extern struct at91_init_soc sama5d3_soc;
-extern struct at91_init_soc sama5d4_soc;
-
-#define AT91_SOC_START(_name)				\
-struct at91_init_soc __initdata _name##_soc		\
- __used							\
-						= {	\
-	.builtin	= 1,				\
-
-#define AT91_SOC_END					\
-};
-
-static inline int at91_soc_is_enabled(void)
-{
-	return at91_boot_soc.builtin;
-}
-
-#if !defined(CONFIG_SOC_AT91RM9200)
-#define at91rm9200_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9260)
-#define at91sam9260_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9261)
-#define at91sam9261_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9263)
-#define at91sam9263_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9G45)
-#define at91sam9g45_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9RL)
-#define at91sam9rl_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9X5)
-#define at91sam9x5_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_AT91SAM9N12)
-#define at91sam9n12_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_SAMA5D3)
-#define sama5d3_soc	at91_boot_soc
-#endif
-
-#if !defined(CONFIG_SOC_SAMA5D4)
-#define sama5d4_soc	at91_boot_soc
-#endif
diff --git a/arch/arm/mach-at91/sysirq_mask.c b/arch/arm/mach-at91/sysirq_mask.c
deleted file mode 100644
index f8bc351..0000000
--- a/arch/arm/mach-at91/sysirq_mask.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * sysirq_mask.c - System-interrupt masking
- *
- * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com>
- *
- * Functions to disable system interrupts from backup-powered peripherals.
- *
- * The RTC and RTT-peripherals are generally powered by backup power (VDDBU)
- * and are not reset on wake-up, user, watchdog or software reset. This means
- * that their interrupts may be enabled during early boot (e.g. after a user
- * reset).
- *
- * As the RTC and RTT share the system-interrupt line with the PIT, an
- * interrupt occurring before a handler has been installed would lead to the
- * system interrupt being disabled and prevent the system from booting.
- *
- * 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/io.h>
-#include <mach/at91_rtt.h>
-
-#include "generic.h"
-
-#define AT91_RTC_IDR		0x24	/* Interrupt Disable Register */
-#define AT91_RTC_IMR		0x28	/* Interrupt Mask Register */
-#define AT91_RTC_IRQ_MASK	0x1f	/* Available IRQs mask */
-
-void __init at91_sysirq_mask_rtc(u32 rtc_base)
-{
-	void __iomem *base;
-
-	base = ioremap(rtc_base, 64);
-	if (!base)
-		return;
-
-	/*
-	 * sam9x5 SoCs have the following errata:
-	 * "RTC: Interrupt Mask Register cannot be used
-	 *  Interrupt Mask Register read always returns 0."
-	 *
-	 * Hence we're not relying on IMR values to disable
-	 * interrupts.
-	 */
-	writel_relaxed(AT91_RTC_IRQ_MASK, base + AT91_RTC_IDR);
-	(void)readl_relaxed(base + AT91_RTC_IMR);	/* flush */
-
-	iounmap(base);
-}
-
-void __init at91_sysirq_mask_rtt(u32 rtt_base)
-{
-	void __iomem *base;
-	void __iomem *reg;
-	u32 mode;
-
-	base = ioremap(rtt_base, 16);
-	if (!base)
-		return;
-
-	reg = base + AT91_RTT_MR;
-
-	mode = readl_relaxed(reg);
-	if (mode & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)) {
-		pr_info("AT91: Disabling rtt irq\n");
-		mode &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
-		writel_relaxed(mode, reg);
-		(void)readl_relaxed(reg);			/* flush */
-	}
-
-	iounmap(base);
-}
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
index 31c87a2..e209e6f 100644
--- a/arch/arm/mach-bcm/platsmp-brcmstb.c
+++ b/arch/arm/mach-bcm/platsmp-brcmstb.c
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/jiffies.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/printk.h>
@@ -94,10 +95,35 @@
 	return readl_relaxed(base);
 }
 
-static void pwr_ctrl_wr(u32 cpu, u32 val)
+static void pwr_ctrl_set(unsigned int cpu, u32 val, u32 mask)
 {
 	void __iomem *base = pwr_ctrl_get_base(cpu);
-	writel(val, base);
+	writel((readl(base) & mask) | val, base);
+}
+
+static void pwr_ctrl_clr(unsigned int cpu, u32 val, u32 mask)
+{
+	void __iomem *base = pwr_ctrl_get_base(cpu);
+	writel((readl(base) & mask) & ~val, base);
+}
+
+#define POLL_TMOUT_MS 500
+static int pwr_ctrl_wait_tmout(unsigned int cpu, u32 set, u32 mask)
+{
+	const unsigned long timeo = jiffies + msecs_to_jiffies(POLL_TMOUT_MS);
+	u32 tmp;
+
+	do {
+		tmp = pwr_ctrl_rd(cpu) & mask;
+		if (!set == !tmp)
+			return 0;
+	} while (time_before(jiffies, timeo));
+
+	tmp = pwr_ctrl_rd(cpu) & mask;
+	if (!set == !tmp)
+		return 0;
+
+	return -ETIMEDOUT;
 }
 
 static void cpu_rst_cfg_set(u32 cpu, int set)
@@ -139,15 +165,22 @@
 	 * The secondary cores power was cut, so we must go through
 	 * power-on initialization.
 	 */
-	u32 tmp;
+	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, 0xffffff00);
+	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
+	pwr_ctrl_set(cpu, ZONE_RESERVED_1_MASK, -1);
 
-	/* Request zone power up */
-	pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK);
+	pwr_ctrl_set(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
 
-	/* Wait for the power up FSM to complete */
-	do {
-		tmp = pwr_ctrl_rd(cpu);
-	} while (!(tmp & ZONE_PWR_ON_STATE_MASK));
+	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_MEM_PWR_STATE_MASK))
+		panic("ZONE_MEM_PWR_STATE_MASK set timeout");
+
+	pwr_ctrl_set(cpu, ZONE_MAN_CLKEN_MASK, -1);
+
+	if (pwr_ctrl_wait_tmout(cpu, 1, ZONE_DPG_PWR_STATE_MASK))
+		panic("ZONE_DPG_PWR_STATE_MASK set timeout");
+
+	pwr_ctrl_clr(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
+	pwr_ctrl_set(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
 }
 
 static int brcmstb_cpu_get_power_state(u32 cpu)
@@ -174,25 +207,33 @@
 
 static int brcmstb_cpu_kill(u32 cpu)
 {
-	u32 tmp;
+	/*
+	 * Ordinarily, the hardware forbids power-down of CPU0 (which is good
+	 * because it is the boot CPU), but this is not true when using BPCM
+	 * manual mode.  Consequently, we must avoid turning off CPU0 here to
+	 * ensure that TI2C master reset will work.
+	 */
+	if (cpu == 0) {
+		pr_warn("SMP: refusing to power off CPU0\n");
+		return 1;
+	}
 
 	while (per_cpu_sw_state_rd(cpu))
 		;
 
-	/* Program zone reset */
-	pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK |
-			      ZONE_PWR_DN_REQ_MASK);
+	pwr_ctrl_set(cpu, ZONE_MANUAL_CONTROL_MASK, -1);
+	pwr_ctrl_clr(cpu, ZONE_MAN_RESET_CNTL_MASK, -1);
+	pwr_ctrl_clr(cpu, ZONE_MAN_CLKEN_MASK, -1);
+	pwr_ctrl_set(cpu, ZONE_MAN_ISO_CNTL_MASK, -1);
+	pwr_ctrl_clr(cpu, ZONE_MAN_MEM_PWR_MASK, -1);
 
-	/* Verify zone reset */
-	tmp = pwr_ctrl_rd(cpu);
-	if (!(tmp & ZONE_RESET_STATE_MASK))
-		pr_err("%s: Zone reset bit for CPU %d not asserted!\n",
-			__func__, cpu);
+	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_MEM_PWR_STATE_MASK))
+		panic("ZONE_MEM_PWR_STATE_MASK clear timeout");
 
-	/* Wait for power down */
-	do {
-		tmp = pwr_ctrl_rd(cpu);
-	} while (!(tmp & ZONE_PWR_OFF_STATE_MASK));
+	pwr_ctrl_clr(cpu, ZONE_RESERVED_1_MASK, -1);
+
+	if (pwr_ctrl_wait_tmout(cpu, 0, ZONE_DPG_PWR_STATE_MASK))
+		panic("ZONE_DPG_PWR_STATE_MASK clear timeout");
 
 	/* Flush pipeline before resetting CPU */
 	mb();
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 2204239..2e3464b 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -27,7 +27,7 @@
 obj-$(CONFIG_MACH_NEUROS_OSD2)		+= board-neuros-osd2.o
 obj-$(CONFIG_MACH_DAVINCI_DM355_EVM)	+= board-dm355-evm.o
 obj-$(CONFIG_MACH_DM355_LEOPARD)	+= board-dm355-leopard.o
-obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)	+= board-dm646x-evm.o cdce949.o
+obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)	+= board-dm646x-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DM365_EVM)	+= board-dm365-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA830_EVM)	+= board-da830-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA850_EVM)	+= board-da850-evm.o
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index ae129bc..846a84d 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -45,7 +45,6 @@
 #include <mach/irqs.h>
 #include <mach/serial.h>
 #include <mach/clock.h>
-#include <mach/cdce949.h>
 
 #include "davinci.h"
 #include "clock.h"
@@ -399,9 +398,6 @@
 	{
 		I2C_BOARD_INFO("cpld_video", 0x3b),
 	},
-	{
-		I2C_BOARD_INFO("cdce949", 0x6c),
-	},
 };
 
 static struct davinci_i2c_platform_data i2c_pdata = {
@@ -715,31 +711,6 @@
 	evm_init_video();
 }
 
-#define CDCE949_XIN_RATE	27000000
-
-/* CDCE949 support - "lpsc" field is overridden to work as clock number */
-static struct clk cdce_clk_in = {
-	.name	= "cdce_xin",
-	.rate	= CDCE949_XIN_RATE,
-};
-
-static struct clk_lookup cdce_clks[] = {
-	CLK(NULL, "xin", &cdce_clk_in),
-	CLK(NULL, NULL, NULL),
-};
-
-static void __init cdce_clk_init(void)
-{
-	struct clk_lookup *c;
-	struct clk *clk;
-
-	for (c = cdce_clks; c->clk; c++) {
-		clk = c->clk;
-		clkdev_add(c);
-		clk_register(clk);
-	}
-}
-
 #define DM6467T_EVM_REF_FREQ		33000000
 
 static void __init davinci_map_io(void)
@@ -748,8 +719,6 @@
 
 	if (machine_is_davinci_dm6467tevm())
 		davinci_set_refclk_rate(DM6467T_EVM_REF_FREQ);
-
-	cdce_clk_init();
 }
 
 #define DM646X_EVM_PHY_ID		"davinci_mdio-0:01"
diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c
deleted file mode 100644
index abafb92..0000000
--- a/arch/arm/mach-davinci/cdce949.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * TI CDCE949 clock synthesizer driver
- *
- * Note: This implementation assumes an input of 27MHz to the CDCE.
- * This is by no means constrained by CDCE hardware although the datasheet
- * does use this as an example for all illustrations and more importantly:
- * that is the crystal input on boards it is currently used on.
- *
- * Copyright (C) 2009 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 version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-
-#include <mach/clock.h>
-#include <mach/cdce949.h>
-
-#include "clock.h"
-
-static struct i2c_client *cdce_i2c_client;
-static DEFINE_MUTEX(cdce_mutex);
-
-/* CDCE register descriptor */
-struct cdce_reg {
-	u8	addr;
-	u8	val;
-};
-
-/* Per-Output (Y1, Y2 etc.) frequency descriptor */
-struct cdce_freq {
-	/* Frequency in KHz */
-	unsigned long frequency;
-	/*
-	 * List of registers to program to obtain a particular frequency.
-	 * 0x0 in register address and value is the end of list marker.
-	 */
-	struct cdce_reg *reglist;
-};
-
-#define CDCE_FREQ_TABLE_ENTRY(line, out)		\
-{							\
-	.reglist	= cdce_y ##line## _ ##out,		\
-	.frequency	= out,				\
-}
-
-/* List of CDCE outputs  */
-struct cdce_output {
-	/* List of frequencies on this output */
-	struct cdce_freq *freq_table;
-	/* Number of possible frequencies */
-	int size;
-};
-
-/*
- * Finding out the values to program into CDCE949 registers for a particular
- * frequency output is not a simple calculation. Have a look at the datasheet
- * for the details. There is desktop software available to help users with
- * the calculations. Here, we just depend on the output of that software
- * (or hand calculations) instead trying to runtime calculate the register
- * values and inflicting misery on ourselves.
- */
-static struct cdce_reg cdce_y1_148500[] = {
-	{ 0x13, 0x00 },
-	/* program PLL1_0 multiplier */
-	{ 0x18, 0xaf },
-	{ 0x19, 0x50 },
-	{ 0x1a, 0x02 },
-	{ 0x1b, 0xc9 },
-	/* program PLL1_11 multiplier */
-	{ 0x1c, 0x00 },
-	{ 0x1d, 0x40 },
-	{ 0x1e, 0x02 },
-	{ 0x1f, 0xc9 },
-	/* output state selection */
-	{ 0x15, 0x00 },
-	{ 0x14, 0xef },
-	/* switch MUX to PLL1 output */
-	{ 0x14, 0x6f },
-	{ 0x16, 0x06 },
-	/* set P2DIV divider, P3DIV and input crystal */
-	{ 0x17, 0x06 },
-	{ 0x01, 0x00 },
-	{ 0x05, 0x48 },
-	{ 0x02, 0x80 },
-	/* enable and disable PLL */
-	{ 0x02, 0xbc },
-	{ 0x03, 0x01 },
-	{ },
-};
-
-static struct cdce_reg cdce_y1_74250[] = {
-	{ 0x13, 0x00 },
-	{ 0x18, 0xaf },
-	{ 0x19, 0x50 },
-	{ 0x1a, 0x02 },
-	{ 0x1b, 0xc9 },
-	{ 0x1c, 0x00 },
-	{ 0x1d, 0x40 },
-	{ 0x1e, 0x02 },
-	{ 0x1f, 0xc9 },
-	/* output state selection */
-	{ 0x15, 0x00 },
-	{ 0x14, 0xef },
-	/* switch MUX to PLL1 output */
-	{ 0x14, 0x6f },
-	{ 0x16, 0x06 },
-	/* set P2DIV divider, P3DIV and input crystal */
-	{ 0x17, 0x06 },
-	{ 0x01, 0x00 },
-	{ 0x05, 0x48 },
-	{ 0x02, 0x80 },
-	/* enable and disable PLL */
-	{ 0x02, 0xbc },
-	{ 0x03, 0x02 },
-	{ },
-};
-
-static struct cdce_reg cdce_y1_27000[] = {
-	{ 0x13, 0x00 },
-	{ 0x18, 0x00 },
-	{ 0x19, 0x40 },
-	{ 0x1a, 0x02 },
-	{ 0x1b, 0x08 },
-	{ 0x1c, 0x00 },
-	{ 0x1d, 0x40 },
-	{ 0x1e, 0x02 },
-	{ 0x1f, 0x08 },
-	{ 0x15, 0x02 },
-	{ 0x14, 0xed },
-	{ 0x16, 0x01 },
-	{ 0x17, 0x01 },
-	{ 0x01, 0x00 },
-	{ 0x05, 0x50 },
-	{ 0x02, 0xb4 },
-	{ 0x03, 0x01 },
-	{ },
-};
-
-static struct cdce_freq cdce_y1_freqs[] = {
-	CDCE_FREQ_TABLE_ENTRY(1, 148500),
-	CDCE_FREQ_TABLE_ENTRY(1, 74250),
-	CDCE_FREQ_TABLE_ENTRY(1, 27000),
-};
-
-static struct cdce_reg cdce_y5_13500[] = {
-	{ 0x27, 0x08 },
-	{ 0x28, 0x00 },
-	{ 0x29, 0x40 },
-	{ 0x2a, 0x02 },
-	{ 0x2b, 0x08 },
-	{ 0x24, 0x6f },
-	{ },
-};
-
-static struct cdce_reg cdce_y5_16875[] = {
-	{ 0x27, 0x08 },
-	{ 0x28, 0x9f },
-	{ 0x29, 0xb0 },
-	{ 0x2a, 0x02 },
-	{ 0x2b, 0x89 },
-	{ 0x24, 0x6f },
-	{ },
-};
-
-static struct cdce_reg cdce_y5_27000[] = {
-	{ 0x27, 0x04 },
-	{ 0x28, 0x00 },
-	{ 0x29, 0x40 },
-	{ 0x2a, 0x02 },
-	{ 0x2b, 0x08 },
-	{ 0x24, 0x6f },
-	{ },
-};
-static struct cdce_reg cdce_y5_54000[] = {
-	{ 0x27, 0x04 },
-	{ 0x28, 0xff },
-	{ 0x29, 0x80 },
-	{ 0x2a, 0x02 },
-	{ 0x2b, 0x07 },
-	{ 0x24, 0x6f },
-	{ },
-};
-
-static struct cdce_reg cdce_y5_81000[] = {
-	{ 0x27, 0x02 },
-	{ 0x28, 0xbf },
-	{ 0x29, 0xa0 },
-	{ 0x2a, 0x03 },
-	{ 0x2b, 0x0a },
-	{ 0x24, 0x6f },
-	{ },
-};
-
-static struct cdce_freq cdce_y5_freqs[] = {
-	CDCE_FREQ_TABLE_ENTRY(5, 13500),
-	CDCE_FREQ_TABLE_ENTRY(5, 16875),
-	CDCE_FREQ_TABLE_ENTRY(5, 27000),
-	CDCE_FREQ_TABLE_ENTRY(5, 54000),
-	CDCE_FREQ_TABLE_ENTRY(5, 81000),
-};
-
-
-static struct cdce_output output_list[] = {
-	[1]	= { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) },
-	[5]	= { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) },
-};
-
-int cdce_set_rate(struct clk *clk, unsigned long rate)
-{
-	int i, ret = 0;
-	struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table;
-	struct cdce_reg  *regs = NULL;
-
-	if (!cdce_i2c_client)
-		return -ENODEV;
-
-	if (!freq_table)
-		return -EINVAL;
-
-	for (i = 0; i < output_list[clk->lpsc].size; i++) {
-		if (freq_table[i].frequency == rate / 1000) {
-			regs = freq_table[i].reglist;
-			break;
-		}
-	}
-
-	if (!regs)
-		return -EINVAL;
-
-	mutex_lock(&cdce_mutex);
-	for (i = 0; regs[i].addr; i++) {
-		ret = i2c_smbus_write_byte_data(cdce_i2c_client,
-					regs[i].addr | 0x80, regs[i].val);
-		if (ret)
-			break;
-	}
-	mutex_unlock(&cdce_mutex);
-
-	if (!ret)
-		clk->rate = rate;
-
-	return ret;
-}
-
-static int cdce_probe(struct i2c_client *client,
-					const struct i2c_device_id *id)
-{
-	cdce_i2c_client = client;
-	return 0;
-}
-
-static int cdce_remove(struct i2c_client *client)
-{
-	cdce_i2c_client = NULL;
-	return 0;
-}
-
-static const struct i2c_device_id cdce_id[] = {
-	{"cdce949", 0},
-	{},
-};
-MODULE_DEVICE_TABLE(i2c, cdce_id);
-
-static struct i2c_driver cdce_driver = {
-	.driver = {
-		.owner	= THIS_MODULE,
-		.name	= "cdce949",
-	},
-	.probe		= cdce_probe,
-	.remove		= cdce_remove,
-	.id_table	= cdce_id,
-};
-
-static int __init cdce_init(void)
-{
-	return i2c_add_driver(&cdce_driver);
-}
-subsys_initcall(cdce_init);
-
-static void __exit cdce_exit(void)
-{
-	i2c_del_driver(&cdce_driver);
-}
-module_exit(cdce_exit);
-
-MODULE_AUTHOR("Texas Instruments");
-MODULE_DESCRIPTION("CDCE949 clock synthesizer driver");
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach-davinci/include/mach/cdce949.h
deleted file mode 100644
index c73331fa..0000000
--- a/arch/arm/mach-davinci/include/mach/cdce949.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * TI CDCE949 off-chip clock synthesizer support
- *
- * 2009 (C) Texas Instruments, Inc. http://www.ti.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.
- */
-#ifndef _MACH_DAVINCI_CDCE949_H
-#define _MACH_DAVINCI_CDCE949_H
-
-#include <linux/clk.h>
-
-#include <mach/clock.h>
-
-int cdce_set_rate(struct clk *clk, unsigned long rate);
-
-#endif
diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index 5e93a73..951b620 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -31,16 +31,6 @@
 #include <mach/serial.h>
 #include <mach/cputype.h>
 
-static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
-					   int offset)
-{
-	offset <<= up->regshift;
-
-	WARN_ONCE(!up->membase, "unmapped read: uart[%d]\n", offset);
-
-	return (unsigned int)__raw_readl(up->membase + offset);
-}
-
 static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
 				    int value)
 {
diff --git a/arch/arm/mach-digicolor/Kconfig b/arch/arm/mach-digicolor/Kconfig
new file mode 100644
index 0000000..4f36d8d
--- /dev/null
+++ b/arch/arm/mach-digicolor/Kconfig
@@ -0,0 +1,7 @@
+config ARCH_DIGICOLOR
+	bool "Conexant Digicolor SoC Support"
+	depends on ARCH_MULTI_V7
+	select CLKSRC_MMIO
+	select DIGICOLOR_TIMER
+	select GENERIC_IRQ_CHIP
+	select MFD_SYSCON
diff --git a/arch/arm/mach-digicolor/Makefile b/arch/arm/mach-digicolor/Makefile
new file mode 100644
index 0000000..3d8a1d2
--- /dev/null
+++ b/arch/arm/mach-digicolor/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_DIGICOLOR)	+= digicolor.o
diff --git a/arch/arm/mach-digicolor/digicolor.c b/arch/arm/mach-digicolor/digicolor.c
new file mode 100644
index 0000000..cfc88d1
--- /dev/null
+++ b/arch/arm/mach-digicolor/digicolor.c
@@ -0,0 +1,18 @@
+/*
+ * Support for Conexant Digicolor SoCs
+ *
+ * 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 <asm/mach/arch.h>
+
+static const char *digicolor_dt_compat[] __initconst = {
+	"cnxt,cx92755",
+	NULL,
+};
+
+DT_MACHINE_START(DIGICOLOR, "Conexant Digicolor (Flattened Device Tree)")
+	.dt_compat	= digicolor_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 865f878..f70eca7 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -13,6 +13,7 @@
 #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
 #include <linux/of.h>
+#include <linux/platform_data/cpuidle-exynos.h>
 
 #define EXYNOS3250_SOC_ID	0xE3472000
 #define EXYNOS3_SOC_MASK	0xFFFFF000
@@ -150,8 +151,11 @@
 extern int exynos_pm_central_resume(void);
 extern void exynos_enter_aftr(void);
 
+extern struct cpuidle_exynos_data cpuidle_coupled_exynos_data;
+
 extern void s5p_init_cpu(void __iomem *cpuid_addr);
 extern unsigned int samsung_rev(void);
+extern void __iomem *cpu_boot_reg_base(void);
 
 static inline void pmu_raw_writel(u32 val, u32 offset)
 {
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index c13d083..2013f73 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -27,20 +27,16 @@
 #include <asm/mach/map.h>
 #include <asm/memory.h>
 
+#include <mach/map.h>
+
 #include "common.h"
 #include "mfc.h"
 #include "regs-pmu.h"
-#include "regs-sys.h"
 
 void __iomem *pmu_base_addr;
 
 static struct map_desc exynos4_iodesc[] __initdata = {
 	{
-		.virtual	= (unsigned long)S3C_VA_SYS,
-		.pfn		= __phys_to_pfn(EXYNOS4_PA_SYSCON),
-		.length		= SZ_64K,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= (unsigned long)S5P_VA_SROMC,
 		.pfn		= __phys_to_pfn(EXYNOS4_PA_SROMC),
 		.length		= SZ_4K,
@@ -70,11 +66,6 @@
 
 static struct map_desc exynos5_iodesc[] __initdata = {
 	{
-		.virtual	= (unsigned long)S3C_VA_SYS,
-		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSCON),
-		.length		= SZ_64K,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= (unsigned long)S5P_VA_SROMC,
 		.pfn		= __phys_to_pfn(EXYNOS5_PA_SROMC),
 		.length		= SZ_4K,
@@ -213,32 +204,6 @@
 
 static void __init exynos_dt_machine_init(void)
 {
-	struct device_node *i2c_np;
-	const char *i2c_compat = "samsung,s3c2440-i2c";
-	unsigned int tmp;
-	int id;
-
-	/*
-	 * Exynos5's legacy i2c controller and new high speed i2c
-	 * controller have muxed interrupt sources. By default the
-	 * interrupts for 4-channel HS-I2C controller are enabled.
-	 * If node for first four channels of legacy i2c controller
-	 * are available then re-configure the interrupts via the
-	 * system register.
-	 */
-	if (soc_is_exynos5()) {
-		for_each_compatible_node(i2c_np, NULL, i2c_compat) {
-			if (of_device_is_available(i2c_np)) {
-				id = of_alias_get_id(i2c_np, "i2c");
-				if (id < 4) {
-					tmp = readl(EXYNOS5_SYS_I2C_CFG);
-					writel(tmp & ~(0x1 << id),
-							EXYNOS5_SYS_I2C_CFG);
-				}
-			}
-		}
-	}
-
 	/*
 	 * This is called from smp_prepare_cpus if we've built for SMP, but
 	 * we still need to set it up for PM and firmware ops if not.
@@ -246,6 +211,10 @@
 	if (!IS_ENABLED(CONFIG_SMP))
 		exynos_sysram_init();
 
+#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
+	if (of_machine_is_compatible("samsung,exynos4210"))
+		exynos_cpuidle.dev.platform_data = &cpuidle_coupled_exynos_data;
+#endif
 	if (of_machine_is_compatible("samsung,exynos4210") ||
 	    of_machine_is_compatible("samsung,exynos4212") ||
 	    (of_machine_is_compatible("samsung,exynos4412") &&
@@ -282,6 +251,7 @@
 		"samsung,mfc-v5",
 		"samsung,mfc-v6",
 		"samsung,mfc-v7",
+		"samsung,mfc-v8",
 	};
 
 	for (i = 0; i < ARRAY_SIZE(mfc_mem); i++)
diff --git a/arch/arm/mach-exynos/include/mach/dma.h b/arch/arm/mach-exynos/include/mach/dma.h
deleted file mode 100644
index 201842a..0000000
--- a/arch/arm/mach-exynos/include/mach/dma.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.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.
- */
-
-#ifndef __MACH_DMA_H
-#define __MACH_DMA_H
-
-/* This platform uses the common DMA API driver for PL330 */
-#include <plat/dma-pl330.h>
-
-#endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 1ad3f49..de3ae59 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -24,9 +24,6 @@
 
 #define EXYNOS_PA_CHIPID		0x10000000
 
-#define EXYNOS4_PA_SYSCON		0x10010000
-#define EXYNOS5_PA_SYSCON		0x10050100
-
 #define EXYNOS4_PA_CMU			0x10030000
 #define EXYNOS5_PA_CMU			0x10010000
 
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 7a1ebfe..3f32c47 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -194,7 +194,7 @@
 		S5P_CORE_LOCAL_PWR_EN);
 }
 
-static inline void __iomem *cpu_boot_reg_base(void)
+void __iomem *cpu_boot_reg_base(void)
 {
 	if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1)
 		return pmu_base_addr + S5P_INFORM5;
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 86f3ecd..e6209da 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -23,12 +23,13 @@
 #include <asm/smp_scu.h>
 #include <asm/suspend.h>
 
+#include <mach/map.h>
+
 #include <plat/pm-common.h>
 
 #include "common.h"
 #include "exynos-pmu.h"
 #include "regs-pmu.h"
-#include "regs-sys.h"
 
 static inline void __iomem *exynos_boot_vector_addr(void)
 {
@@ -97,10 +98,6 @@
 	tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
 	tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
 	pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
-
-	/* Setting SEQ_OPTION register */
-	pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
-		       S5P_CENTRAL_SEQ_OPTION);
 }
 
 int exynos_pm_central_resume(void)
@@ -164,6 +161,13 @@
 
 	exynos_pm_central_suspend();
 
+	if (of_machine_is_compatible("samsung,exynos4212") ||
+	    of_machine_is_compatible("samsung,exynos4412")) {
+		/* Setting SEQ_OPTION register */
+		pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
+			       S5P_CENTRAL_SEQ_OPTION);
+	}
+
 	cpu_suspend(0, exynos_aftr_finisher);
 
 	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
@@ -176,3 +180,125 @@
 
 	cpu_pm_exit();
 }
+
+static atomic_t cpu1_wakeup = ATOMIC_INIT(0);
+
+static int exynos_cpu0_enter_aftr(void)
+{
+	int ret = -1;
+
+	/*
+	 * If the other cpu is powered on, we have to power it off, because
+	 * the AFTR state won't work otherwise
+	 */
+	if (cpu_online(1)) {
+		/*
+		 * We reach a sync point with the coupled idle state, we know
+		 * the other cpu will power down itself or will abort the
+		 * sequence, let's wait for one of these to happen
+		 */
+		while (exynos_cpu_power_state(1)) {
+			/*
+			 * The other cpu may skip idle and boot back
+			 * up again
+			 */
+			if (atomic_read(&cpu1_wakeup))
+				goto abort;
+
+			/*
+			 * The other cpu may bounce through idle and
+			 * boot back up again, getting stuck in the
+			 * boot rom code
+			 */
+			if (__raw_readl(cpu_boot_reg_base()) == 0)
+				goto abort;
+
+			cpu_relax();
+		}
+	}
+
+	exynos_enter_aftr();
+	ret = 0;
+
+abort:
+	if (cpu_online(1)) {
+		/*
+		 * Set the boot vector to something non-zero
+		 */
+		__raw_writel(virt_to_phys(exynos_cpu_resume),
+			     cpu_boot_reg_base());
+		dsb();
+
+		/*
+		 * Turn on cpu1 and wait for it to be on
+		 */
+		exynos_cpu_power_up(1);
+		while (exynos_cpu_power_state(1) != S5P_CORE_LOCAL_PWR_EN)
+			cpu_relax();
+
+		while (!atomic_read(&cpu1_wakeup)) {
+			/*
+			 * Poke cpu1 out of the boot rom
+			 */
+			__raw_writel(virt_to_phys(exynos_cpu_resume),
+				     cpu_boot_reg_base());
+
+			arch_send_wakeup_ipi_mask(cpumask_of(1));
+		}
+	}
+
+	return ret;
+}
+
+static int exynos_wfi_finisher(unsigned long flags)
+{
+	cpu_do_idle();
+
+	return -1;
+}
+
+static int exynos_cpu1_powerdown(void)
+{
+	int ret = -1;
+
+	/*
+	 * Idle sequence for cpu1
+	 */
+	if (cpu_pm_enter())
+		goto cpu1_aborted;
+
+	/*
+	 * Turn off cpu 1
+	 */
+	exynos_cpu_power_down(1);
+
+	ret = cpu_suspend(0, exynos_wfi_finisher);
+
+	cpu_pm_exit();
+
+cpu1_aborted:
+	dsb();
+	/*
+	 * Notify cpu 0 that cpu 1 is awake
+	 */
+	atomic_set(&cpu1_wakeup, 1);
+
+	return ret;
+}
+
+static void exynos_pre_enter_aftr(void)
+{
+	__raw_writel(virt_to_phys(exynos_cpu_resume), cpu_boot_reg_base());
+}
+
+static void exynos_post_enter_aftr(void)
+{
+	atomic_set(&cpu1_wakeup, 0);
+}
+
+struct cpuidle_exynos_data cpuidle_coupled_exynos_data = {
+	.cpu0_enter_aftr		= exynos_cpu0_enter_aftr,
+	.cpu1_powerdown		= exynos_cpu1_powerdown,
+	.pre_enter_aftr		= exynos_pre_enter_aftr,
+	.post_enter_aftr		= exynos_post_enter_aftr,
+};
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index b5f4406..eb461e1 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -160,12 +160,14 @@
 #define EXYNOS5_L2RSTDISABLE_VALUE		BIT(3)
 
 #define S5P_PAD_RET_MAUDIO_OPTION		0x3028
+#define S5P_PAD_RET_MMC2_OPTION			0x30c8
 #define S5P_PAD_RET_GPIO_OPTION			0x3108
 #define S5P_PAD_RET_UART_OPTION			0x3128
 #define S5P_PAD_RET_MMCA_OPTION			0x3148
 #define S5P_PAD_RET_MMCB_OPTION			0x3168
 #define S5P_PAD_RET_EBIA_OPTION			0x3188
 #define S5P_PAD_RET_EBIB_OPTION			0x31A8
+#define S5P_PAD_RET_SPI_OPTION			0x31c8
 
 #define S5P_PS_HOLD_CONTROL			0x330C
 #define S5P_PS_HOLD_EN				(1 << 31)
@@ -326,6 +328,7 @@
 			(EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80))
 
 #define EXYNOS3_ARM_COMMON_OPTION			0x2408
+#define EXYNOS3_ARM_L2_OPTION				0x2608
 #define EXYNOS3_TOP_PWR_OPTION				0x2C48
 #define EXYNOS3_CORE_TOP_PWR_OPTION			0x2CA8
 #define EXYNOS3_XUSBXTI_DURATION			0x341C
diff --git a/arch/arm/mach-exynos/regs-sys.h b/arch/arm/mach-exynos/regs-sys.h
deleted file mode 100644
index 84332b0..0000000
--- a/arch/arm/mach-exynos/regs-sys.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * EXYNOS - system register 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.
-*/
-
-#ifndef __ASM_ARCH_REGS_SYS_H
-#define __ASM_ARCH_REGS_SYS_H __FILE__
-
-#include <mach/map.h>
-
-#define S5P_SYSREG(x)                          (S3C_VA_SYS + (x))
-
-/* For EXYNOS5 */
-#define EXYNOS5_SYS_I2C_CFG                    S5P_SYSREG(0x0234)
-
-#endif /* __ASM_ARCH_REGS_SYS_H */
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index f8e7dcd..666ec3e 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -34,7 +34,6 @@
 
 #include "common.h"
 #include "regs-pmu.h"
-#include "regs-sys.h"
 #include "exynos-pmu.h"
 
 #define S5P_CHECK_SLEEP 0x00000BAD
@@ -53,10 +52,6 @@
 	u32 mask;
 };
 
-static struct sleep_save exynos5_sys_save[] = {
-	SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
-};
-
 static struct sleep_save exynos_core_save[] = {
 	/* SROM side */
 	SAVE_ITEM(S5P_SROM_BW),
@@ -91,6 +86,12 @@
 
 static u32 exynos_irqwake_intmask = 0xffffffff;
 
+static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
+	{ 73, BIT(1) }, /* RTC alarm */
+	{ 74, BIT(2) }, /* RTC tick */
+	{ /* sentinel */ },
+};
+
 static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
 	{ 76, BIT(1) }, /* RTC alarm */
 	{ 77, BIT(2) }, /* RTC tick */
@@ -114,6 +115,19 @@
 	REG_TABLE_END,
 };
 
+unsigned int exynos3250_release_ret_regs[] = {
+	S5P_PAD_RET_MAUDIO_OPTION,
+	S5P_PAD_RET_GPIO_OPTION,
+	S5P_PAD_RET_UART_OPTION,
+	S5P_PAD_RET_MMCA_OPTION,
+	S5P_PAD_RET_MMCB_OPTION,
+	S5P_PAD_RET_EBIA_OPTION,
+	S5P_PAD_RET_EBIB_OPTION,
+	S5P_PAD_RET_MMC2_OPTION,
+	S5P_PAD_RET_SPI_OPTION,
+	REG_TABLE_END,
+};
+
 unsigned int exynos5420_release_ret_regs[] = {
 	EXYNOS_PAD_RET_DRAM_OPTION,
 	EXYNOS_PAD_RET_MAUDIO_OPTION,
@@ -173,6 +187,12 @@
 	return exynos_cpu_do_idle();
 }
 
+static int exynos3250_cpu_suspend(unsigned long arg)
+{
+	flush_cache_all();
+	return exynos_cpu_do_idle();
+}
+
 static int exynos5420_cpu_suspend(unsigned long arg)
 {
 	/* MCPM works with HW CPU identifiers */
@@ -230,6 +250,23 @@
 	pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
 }
 
+static void exynos3250_pm_prepare(void)
+{
+	unsigned int tmp;
+
+	/* Set wake-up mask registers */
+	exynos_pm_set_wakeup_mask();
+
+	tmp = pmu_raw_readl(EXYNOS3_ARM_L2_OPTION);
+	tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
+	pmu_raw_writel(tmp, EXYNOS3_ARM_L2_OPTION);
+
+	exynos_pm_enter_sleep_mode();
+
+	/* ensure at least INFORM0 has the resume address */
+	pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
+}
+
 static void exynos5420_pm_prepare(void)
 {
 	unsigned int tmp;
@@ -282,6 +319,10 @@
 {
 	exynos_pm_central_suspend();
 
+	/* Setting SEQ_OPTION register */
+	pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
+		       S5P_CENTRAL_SEQ_OPTION);
+
 	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
 		exynos_cpu_save_register();
 
@@ -344,6 +385,28 @@
 	pmu_raw_writel(0x0, S5P_INFORM1);
 }
 
+static void exynos3250_pm_resume(void)
+{
+	u32 cpuid = read_cpuid_part();
+
+	if (exynos_pm_central_resume())
+		goto early_wakeup;
+
+	/* For release retention */
+	exynos_pm_release_retention();
+
+	pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
+
+	if (call_firmware_op(resume) == -ENOSYS
+	    && cpuid == ARM_CPU_PART_CORTEX_A9)
+		exynos_cpu_restore_register();
+
+early_wakeup:
+
+	/* Clear SLEEP mode set in INFORM1 */
+	pmu_raw_writel(0x0, S5P_INFORM1);
+}
+
 static void exynos5420_prepare_pm_resume(void)
 {
 	if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
@@ -483,6 +546,16 @@
 	.valid		= suspend_valid_only_mem,
 };
 
+static const struct exynos_pm_data exynos3250_pm_data = {
+	.wkup_irq	= exynos3250_wkup_irq,
+	.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
+	.release_ret_regs = exynos3250_release_ret_regs,
+	.pm_suspend	= exynos_pm_suspend,
+	.pm_resume	= exynos3250_pm_resume,
+	.pm_prepare	= exynos3250_pm_prepare,
+	.cpu_suspend	= exynos3250_cpu_suspend,
+};
+
 static const struct exynos_pm_data exynos4_pm_data = {
 	.wkup_irq	= exynos4_wkup_irq,
 	.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
@@ -497,8 +570,6 @@
 	.wkup_irq	= exynos5250_wkup_irq,
 	.wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
 	.release_ret_regs = exynos_release_ret_regs,
-	.extra_save	= exynos5_sys_save,
-	.num_extra_save	= ARRAY_SIZE(exynos5_sys_save),
 	.pm_suspend	= exynos_pm_suspend,
 	.pm_resume	= exynos_pm_resume,
 	.pm_prepare	= exynos_pm_prepare,
@@ -518,6 +589,9 @@
 
 static struct of_device_id exynos_pmu_of_device_ids[] = {
 	{
+		.compatible = "samsung,exynos3250-pmu",
+		.data = &exynos3250_pm_data,
+	}, {
 		.compatible = "samsung,exynos4210-pmu",
 		.data = &exynos4_pm_data,
 	}, {
diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig
index cd19433..83061ad 100644
--- a/arch/arm/mach-hisi/Kconfig
+++ b/arch/arm/mach-hisi/Kconfig
@@ -22,6 +22,14 @@
 	help
 	  Support for Hisilicon Hi36xx SoC family
 
+config ARCH_HIP01
+       bool "Hisilicon HIP01 family" if ARCH_MULTI_V7
+       select HAVE_ARM_SCU if SMP
+       select HAVE_ARM_TWD if SMP
+       select ARM_GLOBAL_TIMER
+       help
+         Support for Hisilicon HIP01 SoC family
+
 config ARCH_HIP04
 	bool "Hisilicon HiP04 Cortex A15 family" if ARCH_MULTI_V7
 	select ARM_ERRATA_798181 if SMP
diff --git a/arch/arm/mach-hisi/core.h b/arch/arm/mach-hisi/core.h
index 88b1f48..92a682d 100644
--- a/arch/arm/mach-hisi/core.h
+++ b/arch/arm/mach-hisi/core.h
@@ -12,9 +12,12 @@
 extern int hi3xxx_cpu_kill(unsigned int cpu);
 extern void hi3xxx_set_cpu(int cpu, bool enable);
 
-extern void hix5hd2_secondary_startup(void);
+extern void hisi_secondary_startup(void);
 extern struct smp_operations hix5hd2_smp_ops;
 extern void hix5hd2_set_cpu(int cpu, bool enable);
 extern void hix5hd2_cpu_die(unsigned int cpu);
 
+extern struct smp_operations hip01_smp_ops;
+extern void hip01_set_cpu(int cpu, bool enable);
+extern void hip01_cpu_die(unsigned int cpu);
 #endif
diff --git a/arch/arm/mach-hisi/headsmp.S b/arch/arm/mach-hisi/headsmp.S
index 278889c..81e35b1 100644
--- a/arch/arm/mach-hisi/headsmp.S
+++ b/arch/arm/mach-hisi/headsmp.S
@@ -11,6 +11,6 @@
 
 	__CPUINIT
 
-ENTRY(hix5hd2_secondary_startup)
+ENTRY(hisi_secondary_startup)
 	bl	v7_invalidate_l1
 	b	secondary_startup
diff --git a/arch/arm/mach-hisi/hisilicon.c b/arch/arm/mach-hisi/hisilicon.c
index 7744c35..76b9070 100644
--- a/arch/arm/mach-hisi/hisilicon.c
+++ b/arch/arm/mach-hisi/hisilicon.c
@@ -72,3 +72,13 @@
 DT_MACHINE_START(HIP04, "Hisilicon HiP04 (Flattened Device Tree)")
 	.dt_compat	= hip04_compat,
 MACHINE_END
+
+static const char *hip01_compat[] __initconst = {
+	"hisilicon,hip01",
+	"hisilicon,hip01-ca9x2",
+	NULL,
+};
+
+DT_MACHINE_START(HIP01, "Hisilicon HIP01 (Flattened Device Tree)")
+	.dt_compat      = hip01_compat,
+MACHINE_END
diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c
index 84e6919..a129aae 100644
--- a/arch/arm/mach-hisi/hotplug.c
+++ b/arch/arm/mach-hisi/hotplug.c
@@ -65,6 +65,9 @@
 #define PMC0_CPU1_PMC_ENABLE		(1 << 7)
 #define PMC0_CPU1_POWERDOWN		(1 << 3)
 
+#define HIP01_PERI9                    0x50
+#define PERI9_CPU1_RESET               (1 << 1)
+
 enum {
 	HI3620_CTRL,
 	ERROR_CTRL,
@@ -209,6 +212,34 @@
 	}
 }
 
+void hip01_set_cpu(int cpu, bool enable)
+{
+	unsigned int temp;
+	struct device_node *np;
+
+	if (!ctrl_base) {
+		np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
+		if (np)
+			ctrl_base = of_iomap(np, 0);
+		else
+			BUG();
+	}
+
+	if (enable) {
+		/* reset on CPU1  */
+		temp = readl_relaxed(ctrl_base + HIP01_PERI9);
+		temp |= PERI9_CPU1_RESET;
+		writel_relaxed(temp, ctrl_base + HIP01_PERI9);
+
+		udelay(50);
+
+		/* unreset on CPU1 */
+		temp = readl_relaxed(ctrl_base + HIP01_PERI9);
+		temp &= ~PERI9_CPU1_RESET;
+		writel_relaxed(temp, ctrl_base + HIP01_PERI9);
+	}
+}
+
 static inline void cpu_enter_lowpower(void)
 {
 	unsigned int v;
diff --git a/arch/arm/mach-hisi/platsmp.c b/arch/arm/mach-hisi/platsmp.c
index 575dd82..8880c8e 100644
--- a/arch/arm/mach-hisi/platsmp.c
+++ b/arch/arm/mach-hisi/platsmp.c
@@ -10,10 +10,12 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <linux/of_address.h>
+#include <linux/delay.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
+#include <asm/mach/map.h>
 
 #include "core.h"
 
@@ -96,7 +98,7 @@
 #endif
 };
 
-static void __init hix5hd2_smp_prepare_cpus(unsigned int max_cpus)
+static void __init hisi_common_smp_prepare_cpus(unsigned int max_cpus)
 {
 	hisi_enable_scu_a9();
 }
@@ -116,7 +118,7 @@
 {
 	phys_addr_t jumpaddr;
 
-	jumpaddr = virt_to_phys(hix5hd2_secondary_startup);
+	jumpaddr = virt_to_phys(hisi_secondary_startup);
 	hix5hd2_set_scu_boot_addr(HIX5HD2_BOOT_ADDRESS, jumpaddr);
 	hix5hd2_set_cpu(cpu, true);
 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
@@ -125,12 +127,60 @@
 
 
 struct smp_operations hix5hd2_smp_ops __initdata = {
-	.smp_prepare_cpus	= hix5hd2_smp_prepare_cpus,
+	.smp_prepare_cpus	= hisi_common_smp_prepare_cpus,
 	.smp_boot_secondary	= hix5hd2_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
 	.cpu_die		= hix5hd2_cpu_die,
 #endif
 };
 
+
+#define SC_SCTL_REMAP_CLR      0x00000100
+#define HIP01_BOOT_ADDRESS     0x80000000
+#define REG_SC_CTRL            0x000
+
+void hip01_set_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
+{
+	void __iomem *virt;
+
+	virt = phys_to_virt(start_addr);
+
+	writel_relaxed(0xe51ff004, virt);
+	writel_relaxed(jump_addr, virt + 4);
+}
+
+static int hip01_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	phys_addr_t jumpaddr;
+	unsigned int remap_reg_value = 0;
+	struct device_node *node;
+
+
+	jumpaddr = virt_to_phys(hisi_secondary_startup);
+	hip01_set_boot_addr(HIP01_BOOT_ADDRESS, jumpaddr);
+
+	node = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
+	if (WARN_ON(!node))
+		return -1;
+	ctrl_base = of_iomap(node, 0);
+
+	/* set the secondary core boot from DDR */
+	remap_reg_value = readl_relaxed(ctrl_base + REG_SC_CTRL);
+	barrier();
+	remap_reg_value |= SC_SCTL_REMAP_CLR;
+	barrier();
+	writel_relaxed(remap_reg_value, ctrl_base + REG_SC_CTRL);
+
+	hip01_set_cpu(cpu, true);
+
+	return 0;
+}
+
+struct smp_operations hip01_smp_ops __initdata = {
+	.smp_prepare_cpus       = hisi_common_smp_prepare_cpus,
+	.smp_boot_secondary     = hip01_boot_secondary,
+};
+
 CPU_METHOD_OF_DECLARE(hi3xxx_smp, "hisilicon,hi3620-smp", &hi3xxx_smp_ops);
 CPU_METHOD_OF_DECLARE(hix5hd2_smp, "hisilicon,hix5hd2-smp", &hix5hd2_smp_ops);
+CPU_METHOD_OF_DECLARE(hip01_smp, "hisilicon,hip01-smp", &hip01_smp_ops);
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index f5ac685..8d1b101 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -32,8 +32,7 @@
 obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
 obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
 obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
-# i.MX6SX reuses i.MX6Q cpuidle driver
-obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6q.o
+obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o
 endif
 
 ifdef CONFIG_SND_IMX_SOC
diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c
index 5a75cdc..8935bff 100644
--- a/arch/arm/mach-imx/clk-gate2.c
+++ b/arch/arm/mach-imx/clk-gate2.c
@@ -96,15 +96,30 @@
 {
 	struct clk_gate2 *gate = to_clk_gate2(hw);
 
-	if (gate->share_count)
-		return !!__clk_get_enable_count(hw->clk);
-	else
-		return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
+	return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx);
+}
+
+static void clk_gate2_disable_unused(struct clk_hw *hw)
+{
+	struct clk_gate2 *gate = to_clk_gate2(hw);
+	unsigned long flags = 0;
+	u32 reg;
+
+	spin_lock_irqsave(gate->lock, flags);
+
+	if (!gate->share_count || *gate->share_count == 0) {
+		reg = readl(gate->reg);
+		reg &= ~(3 << gate->bit_idx);
+		writel(reg, gate->reg);
+	}
+
+	spin_unlock_irqrestore(gate->lock, flags);
 }
 
 static struct clk_ops clk_gate2_ops = {
 	.enable = clk_gate2_enable,
 	.disable = clk_gate2_disable,
+	.disable_unused = clk_gate2_disable_unused,
 	.is_enabled = clk_gate2_is_enabled,
 };
 
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 2daef61..d04a430 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -386,7 +386,7 @@
 		clk[IMX6Q_CLK_ECSPI5] = imx_clk_gate2("ecspi5",        "ecspi_root",        base + 0x6c, 8);
 	clk[IMX6QDL_CLK_ENET]         = imx_clk_gate2("enet",          "ipg",               base + 0x6c, 10);
 	clk[IMX6QDL_CLK_ESAI_EXTAL]   = imx_clk_gate2_shared("esai_extal",   "esai_podf",   base + 0x6c, 16, &share_count_esai);
-	clk[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ipg",           base + 0x6c, 16, &share_count_esai);
+	clk[IMX6QDL_CLK_ESAI_IPG]     = imx_clk_gate2_shared("esai_ipg",   "ahb",           base + 0x6c, 16, &share_count_esai);
 	clk[IMX6QDL_CLK_ESAI_MEM]     = imx_clk_gate2_shared("esai_mem", "ahb",             base + 0x6c, 16, &share_count_esai);
 	clk[IMX6QDL_CLK_GPT_IPG]      = imx_clk_gate2("gpt_ipg",       "ipg",               base + 0x6c, 20);
 	clk[IMX6QDL_CLK_GPT_IPG_PER]  = imx_clk_gate2("gpt_ipg_per",   "ipg_per",           base + 0x6c, 22);
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index 0ad6e54..641ebc5 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -31,6 +31,7 @@
  * @base:	 base address of PLL registers
  * @powerup_set: set POWER bit to power up the PLL
  * @div_mask:	 mask of divider bits
+ * @div_shift:	 shift of divider bits
  *
  * IMX PLL clock version 3, found on i.MX6 series.  Divider for pllv3
  * is actually a multiplier, and always sits at bit 0.
@@ -40,6 +41,7 @@
 	void __iomem	*base;
 	bool		powerup_set;
 	u32		div_mask;
+	u32		div_shift;
 };
 
 #define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
@@ -97,7 +99,7 @@
 					   unsigned long parent_rate)
 {
 	struct clk_pllv3 *pll = to_clk_pllv3(hw);
-	u32 div = readl_relaxed(pll->base)  & pll->div_mask;
+	u32 div = (readl_relaxed(pll->base) >> pll->div_shift)  & pll->div_mask;
 
 	return (div == 1) ? parent_rate * 22 : parent_rate * 20;
 }
@@ -125,8 +127,8 @@
 		return -EINVAL;
 
 	val = readl_relaxed(pll->base);
-	val &= ~pll->div_mask;
-	val |= div;
+	val &= ~(pll->div_mask << pll->div_shift);
+	val |= (div << pll->div_shift);
 	writel_relaxed(val, pll->base);
 
 	return clk_pllv3_wait_lock(pll);
@@ -295,6 +297,8 @@
 	case IMX_PLLV3_SYS:
 		ops = &clk_pllv3_sys_ops;
 		break;
+	case IMX_PLLV3_USB_VF610:
+		pll->div_shift = 1;
 	case IMX_PLLV3_USB:
 		ops = &clk_pllv3_ops;
 		pll->powerup_set = true;
diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c
index 5937dde..61876ed 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/arch/arm/mach-imx/clk-vf610.c
@@ -172,11 +172,11 @@
 
 	clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1);
 	clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1);
-	clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "pll3_bypass_src", PLL3_CTRL, 0x1);
+	clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610,     "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2);
 	clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f);
 	clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3);
 	clk[VF610_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll6", "pll6_bypass_src", PLL6_CTRL, 0x7f);
-	clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "pll7_bypass_src", PLL7_CTRL, 0x1);
+	clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB_VF610,     "pll7", "pll7_bypass_src", PLL7_CTRL, 0x2);
 
 	clk[VF610_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", PLL1_CTRL, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
 	clk[VF610_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", PLL2_CTRL, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
@@ -267,6 +267,8 @@
 	clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8));
 	clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9));
 	clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10));
+	clk[VF610_CLK_UART4] = imx_clk_gate2("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9));
+	clk[VF610_CLK_UART5] = imx_clk_gate2("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10));
 
 	clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
 	clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
@@ -380,6 +382,8 @@
 	clk[VF610_CLK_DMAMUX2] = imx_clk_gate2("dmamux2", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(1));
 	clk[VF610_CLK_DMAMUX3] = imx_clk_gate2("dmamux3", "platform_bus", CCM_CCGR6, CCM_CCGRx_CGn(2));
 
+	clk[VF610_CLK_SNVS] = imx_clk_gate2("snvs-rtc", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(7));
+
 	imx_check_clocks(clk, ARRAY_SIZE(clk));
 
 	clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]);
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 5ef82e2..6a07903 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -20,6 +20,7 @@
 	IMX_PLLV3_GENERIC,
 	IMX_PLLV3_SYS,
 	IMX_PLLV3_USB,
+	IMX_PLLV3_USB_VF610,
 	IMX_PLLV3_AV,
 	IMX_PLLV3_ENET,
 };
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index cfcdb62..1028b6c 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -70,6 +70,10 @@
 unsigned int imx_get_soc_revision(void);
 void imx_init_revision_from_anatop(void);
 struct device *imx_soc_device_init(void);
+void imx6_enable_rbc(bool enable);
+void imx_gpc_set_arm_power_in_lpm(bool power_off);
+void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw);
+void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw);
 
 enum mxc_cpu_pwr_mode {
 	WAIT_CLOCKED,		/* wfi only */
diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c
new file mode 100644
index 0000000..5a36722
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6sx.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+
+#include "common.h"
+#include "cpuidle.h"
+
+static int imx6sx_idle_finish(unsigned long val)
+{
+	cpu_do_idle();
+
+	return 0;
+}
+
+static int imx6sx_enter_wait(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	imx6q_set_lpm(WAIT_UNCLOCKED);
+
+	switch (index) {
+	case 1:
+		cpu_do_idle();
+		break;
+	case 2:
+		imx6_enable_rbc(true);
+		imx_gpc_set_arm_power_in_lpm(true);
+		imx_set_cpu_jump(0, v7_cpu_resume);
+		/* Need to notify there is a cpu pm operation. */
+		cpu_pm_enter();
+		cpu_cluster_pm_enter();
+
+		cpu_suspend(0, imx6sx_idle_finish);
+
+		cpu_cluster_pm_exit();
+		cpu_pm_exit();
+		imx_gpc_set_arm_power_in_lpm(false);
+		imx6_enable_rbc(false);
+		break;
+	default:
+		break;
+	}
+
+	imx6q_set_lpm(WAIT_CLOCKED);
+
+	return index;
+}
+
+static struct cpuidle_driver imx6sx_cpuidle_driver = {
+	.name = "imx6sx_cpuidle",
+	.owner = THIS_MODULE,
+	.states = {
+		/* WFI */
+		ARM_CPUIDLE_WFI_STATE,
+		/* WAIT */
+		{
+			.exit_latency = 50,
+			.target_residency = 75,
+			.flags = CPUIDLE_FLAG_TIMER_STOP,
+			.enter = imx6sx_enter_wait,
+			.name = "WAIT",
+			.desc = "Clock off",
+		},
+		/* WAIT + ARM power off  */
+		{
+			/*
+			 * ARM gating 31us * 5 + RBC clear 65us
+			 * and some margin for SW execution, here set it
+			 * to 300us.
+			 */
+			.exit_latency = 300,
+			.target_residency = 500,
+			.enter = imx6sx_enter_wait,
+			.name = "LOW-POWER-IDLE",
+			.desc = "ARM power off",
+		},
+	},
+	.state_count = 3,
+	.safe_state_index = 0,
+};
+
+int __init imx6sx_cpuidle_init(void)
+{
+	imx6_enable_rbc(false);
+	/*
+	 * set ARM power up/down timing to the fastest,
+	 * sw2iso and sw can be set to one 32K cycle = 31us
+	 * except for power up sw2iso which need to be
+	 * larger than LDO ramp up time.
+	 */
+	imx_gpc_set_arm_power_up_timing(2, 1);
+	imx_gpc_set_arm_power_down_timing(1, 1);
+
+	return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index 24e3367..f914012 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -14,6 +14,7 @@
 extern int imx5_cpuidle_init(void);
 extern int imx6q_cpuidle_init(void);
 extern int imx6sl_cpuidle_init(void);
+extern int imx6sx_cpuidle_init(void);
 #else
 static inline int imx5_cpuidle_init(void)
 {
@@ -27,4 +28,8 @@
 {
 	return 0;
 }
+static inline int imx6sx_cpuidle_init(void)
+{
+	return 0;
+}
 #endif
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 5f3602e..745caa1 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -20,6 +20,10 @@
 
 #define GPC_IMR1		0x008
 #define GPC_PGC_CPU_PDN		0x2a0
+#define GPC_PGC_CPU_PUPSCR	0x2a4
+#define GPC_PGC_CPU_PDNSCR	0x2a8
+#define GPC_PGC_SW2ISO_SHIFT	0x8
+#define GPC_PGC_SW_SHIFT	0x0
 
 #define IMR_NUM			4
 
@@ -27,6 +31,23 @@
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
 
+void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
+{
+	writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
+		(sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PUPSCR);
+}
+
+void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw)
+{
+	writel_relaxed((sw2iso << GPC_PGC_SW2ISO_SHIFT) |
+		(sw << GPC_PGC_SW_SHIFT), gpc_base + GPC_PGC_CPU_PDNSCR);
+}
+
+void imx_gpc_set_arm_power_in_lpm(bool power_off)
+{
+	writel_relaxed(power_off, gpc_base + GPC_PGC_CPU_PDN);
+}
+
 void imx_gpc_pre_suspend(bool arm_power_off)
 {
 	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
@@ -34,7 +55,7 @@
 
 	/* Tell GPC to power off ARM core when suspend */
 	if (arm_power_off)
-		writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
+		imx_gpc_set_arm_power_in_lpm(arm_power_off);
 
 	for (i = 0; i < IMR_NUM; i++) {
 		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
@@ -48,7 +69,7 @@
 	int i;
 
 	/* Keep ARM core powered on for other low-power modes */
-	writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
+	imx_gpc_set_arm_power_in_lpm(false);
 
 	for (i = 0; i < IMR_NUM; i++)
 		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 5057d61..4ad6e47 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -329,7 +329,7 @@
 			if (dev_pm_opp_disable(cpu_dev, 852000000))
 				pr_warn("failed to disable 852 MHz OPP\n");
 	}
-
+	iounmap(base);
 put_node:
 	of_node_put(np);
 }
diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c
index 7a96c65..66988eb 100644
--- a/arch/arm/mach-imx/mach-imx6sx.c
+++ b/arch/arm/mach-imx/mach-imx6sx.c
@@ -90,7 +90,7 @@
 
 static void __init imx6sx_init_late(void)
 {
-	imx6q_cpuidle_init();
+	imx6sx_cpuidle_init();
 
 	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
 		platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c
index c11ab6a..2e7c75b 100644
--- a/arch/arm/mach-imx/mach-vf610.c
+++ b/arch/arm/mach-imx/mach-vf610.c
@@ -13,11 +13,14 @@
 #include <asm/hardware/cache-l2x0.h>
 
 static const char * const vf610_dt_compat[] __initconst = {
+	"fsl,vf500",
+	"fsl,vf510",
+	"fsl,vf600",
 	"fsl,vf610",
 	NULL,
 };
 
-DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF610 (Device Tree)")
+DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF5xx/VF6xx (Device Tree)")
 	.l2c_aux_val	= 0,
 	.l2c_aux_mask	= ~0,
 	.dt_compat	= vf610_dt_compat,
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 5d2c1bd..46fd695 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -205,7 +205,7 @@
 	writel_relaxed(val, ccm_base + CGPR);
 }
 
-static void imx6q_enable_rbc(bool enable)
+void imx6_enable_rbc(bool enable)
 {
 	u32 val;
 
@@ -359,17 +359,16 @@
 		 * RBC setting, so we do NOT need to do that here.
 		 */
 		if (!imx6_suspend_in_ocram_fn)
-			imx6q_enable_rbc(true);
+			imx6_enable_rbc(true);
 		imx_gpc_pre_suspend(true);
 		imx_anatop_pre_suspend();
-		imx_set_cpu_jump(0, v7_cpu_resume);
 		/* Zzz ... */
 		cpu_suspend(0, imx6q_suspend_finish);
 		if (cpu_is_imx6q() || cpu_is_imx6dl())
 			imx_smp_prepare();
 		imx_anatop_post_resume();
 		imx_gpc_post_resume();
-		imx6q_enable_rbc(false);
+		imx6_enable_rbc(false);
 		imx6q_enable_wb(false);
 		imx6q_set_int_mem_clk_lpm(true);
 		imx6q_set_lpm(WAIT_CLOCKED);
diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
index f73f588..f7e463c 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -1,6 +1,26 @@
-config ARCH_MEDIATEK
+menuconfig ARCH_MEDIATEK
 	bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7
 	select ARM_GIC
 	select MTK_TIMER
 	help
 	  Support for Mediatek MT65xx & MT81xx SoCs
+
+if ARCH_MEDIATEK
+
+config MACH_MT6589
+	bool "MediaTek MT6589 SoCs support"
+	default ARCH_MEDIATEK
+
+config MACH_MT6592
+	bool "MediaTek MT6592 SoCs support"
+	default ARCH_MEDIATEK
+
+config MACH_MT8127
+	bool "MediaTek MT8127 SoCs support"
+	default ARCH_MEDIATEK
+
+config MACH_MT8135
+	bool "MediaTek MT8135 SoCs support"
+	default ARCH_MEDIATEK
+
+endif
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index ccef880..b5895f0 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -33,6 +33,7 @@
 #include <asm/smp_plat.h>
 #include <asm/cacheflush.h>
 #include <asm/mach/map.h>
+#include <asm/dma-mapping.h>
 #include "coherency.h"
 #include "mvebu-soc-id.h"
 
@@ -76,54 +77,6 @@
 	return ll_enable_coherency();
 }
 
-static inline void mvebu_hwcc_sync_io_barrier(void)
-{
-	writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
-	while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
-}
-
-static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
-				  unsigned long offset, size_t size,
-				  enum dma_data_direction dir,
-				  struct dma_attrs *attrs)
-{
-	if (dir != DMA_TO_DEVICE)
-		mvebu_hwcc_sync_io_barrier();
-	return pfn_to_dma(dev, page_to_pfn(page)) + offset;
-}
-
-
-static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
-			      size_t size, enum dma_data_direction dir,
-			      struct dma_attrs *attrs)
-{
-	if (dir != DMA_TO_DEVICE)
-		mvebu_hwcc_sync_io_barrier();
-}
-
-static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
-			size_t size, enum dma_data_direction dir)
-{
-	if (dir != DMA_TO_DEVICE)
-		mvebu_hwcc_sync_io_barrier();
-}
-
-static struct dma_map_ops mvebu_hwcc_dma_ops = {
-	.alloc			= arm_dma_alloc,
-	.free			= arm_dma_free,
-	.mmap			= arm_dma_mmap,
-	.map_page		= mvebu_hwcc_dma_map_page,
-	.unmap_page		= mvebu_hwcc_dma_unmap_page,
-	.get_sgtable		= arm_dma_get_sgtable,
-	.map_sg			= arm_dma_map_sg,
-	.unmap_sg		= arm_dma_unmap_sg,
-	.sync_single_for_cpu	= mvebu_hwcc_dma_sync,
-	.sync_single_for_device	= mvebu_hwcc_dma_sync,
-	.sync_sg_for_cpu	= arm_dma_sync_sg_for_cpu,
-	.sync_sg_for_device	= arm_dma_sync_sg_for_device,
-	.set_dma_mask		= arm_dma_set_mask,
-};
-
 static int mvebu_hwcc_notifier(struct notifier_block *nb,
 			       unsigned long event, void *__dev)
 {
@@ -131,7 +84,7 @@
 
 	if (event != BUS_NOTIFY_ADD_DEVICE)
 		return NOTIFY_DONE;
-	set_dma_ops(dev, &mvebu_hwcc_dma_ops);
+	set_dma_ops(dev, &arm_coherent_dma_ops);
 
 	return NOTIFY_OK;
 }
@@ -253,14 +206,9 @@
 	return type;
 }
 
-/*
- * As a precaution, we currently completely disable hardware I/O
- * coherency, until enough testing is done with automatic I/O
- * synchronization barriers to validate that it is a proper solution.
- */
 int coherency_available(void)
 {
-	return false;
+	return coherency_type() != COHERENCY_FABRIC_TYPE_NONE;
 }
 
 int __init coherency_init(void)
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.h b/arch/arm/mach-mvebu/mvebu-soc-id.h
index c16bb68..e124a0b 100644
--- a/arch/arm/mach-mvebu/mvebu-soc-id.h
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.h
@@ -20,10 +20,28 @@
 #define MV78XX0_A0_REV	    0x1
 #define MV78XX0_B0_REV	    0x2
 
+/* Amada 370 ID */
+#define ARMADA_370_DEV_ID   0x6710
+
+/* Amada 370 Revision */
+#define ARMADA_370_A1_REV   0x1
+
+/* Armada 375 ID */
+#define ARMADA_375_DEV_ID   0x6720
+
 /* Armada 375 */
 #define ARMADA_375_Z1_REV   0x0
 #define ARMADA_375_A0_REV   0x3
 
+/* Armada 38x ID */
+#define ARMADA_380_DEV_ID   0x6810
+#define ARMADA_385_DEV_ID   0x6820
+#define ARMADA_388_DEV_ID   0x6828
+
+/* Armada 38x Revision */
+#define ARMADA_38x_Z1_REV   0x0
+#define ARMADA_38x_A0_REV   0x4
+
 #ifdef CONFIG_ARCH_MVEBU
 int mvebu_get_soc_id(u32 *dev, u32 *rev);
 #else
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 122ef67..a8a533d 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -64,11 +64,6 @@
 static unsigned int irq_bank_count;
 static struct omap_irq_bank *irq_banks;
 
-static inline unsigned int irq_bank_readl(int bank, int offset)
-{
-	return omap_readl(irq_banks[bank].base_reg + offset);
-}
-
 static inline void irq_bank_writel(unsigned long value, int bank, int offset)
 {
 	omap_writel(value, irq_banks[bank].base_reg + offset);
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index 107e7ab..36bf174 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -91,11 +91,6 @@
 	omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
 }
 
-static inline unsigned long omap_32k_timer_read(int reg)
-{
-	return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
-}
-
 static inline void omap_32k_timer_start(unsigned long load_val)
 {
 	if (!load_val)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 6ab656c..2b8e477 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -217,12 +217,6 @@
 	bool "OMAP3517/ AM3517 EVM board"
 	depends on ARCH_OMAP3
 	default y
-	select OMAP_PACKAGE_CBB
-
-config MACH_CRANEBOARD
-	bool "AM3517/05 CRANE board"
-	depends on ARCH_OMAP3
-	select OMAP_PACKAGE_CBB
 
 config MACH_OMAP3_PANDORA
 	bool "OMAP3 Pandora"
@@ -263,12 +257,6 @@
 	select MACH_CM_T3730
 	select OMAP_PACKAGE_CUS
 
-config MACH_CM_T3517
-	bool "CompuLab CM-T3517 module"
-	depends on ARCH_OMAP3
-	default y
-	select OMAP_PACKAGE_CBB
-
 config MACH_CM_T3730
        bool
 
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 5d27dfd..00d5d8f 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -58,6 +58,7 @@
 # Restart code (OMAP4/5 currently in omap4-common.c)
 obj-$(CONFIG_SOC_OMAP2420)		+= omap2-restart.o
 obj-$(CONFIG_SOC_OMAP2430)		+= omap2-restart.o
+obj-$(CONFIG_SOC_TI81XX)		+= ti81xx-restart.o
 obj-$(CONFIG_SOC_AM33XX)		+= am33xx-restart.o
 obj-$(CONFIG_SOC_AM43XX)		+= omap4-restart.o
 obj-$(CONFIG_ARCH_OMAP3)		+= omap3-restart.o
@@ -120,6 +121,7 @@
 obj-$(CONFIG_SOC_OMAP5)			+= $(omap-prcm-4-5-common)
 obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-prcm-4-5-common)
 am33xx-43xx-prcm-common			+= prm33xx.o cm33xx.o
+obj-$(CONFIG_SOC_TI81XX)		+= $(am33xx-43xx-prcm-common)
 obj-$(CONFIG_SOC_AM33XX)		+= $(am33xx-43xx-prcm-common)
 obj-$(CONFIG_SOC_AM43XX)		+= $(omap-prcm-4-5-common) \
 					   $(am33xx-43xx-prcm-common)
@@ -170,6 +172,8 @@
 obj-$(CONFIG_ARCH_OMAP4)		+= clockdomains44xx_data.o
 obj-$(CONFIG_SOC_AM33XX)		+= $(clockdomain-common)
 obj-$(CONFIG_SOC_AM33XX)		+= clockdomains33xx_data.o
+obj-$(CONFIG_SOC_TI81XX)		+= $(clockdomain-common)
+obj-$(CONFIG_SOC_TI81XX)		+= clockdomains81xx_data.o
 obj-$(CONFIG_SOC_AM43XX)		+= $(clockdomain-common)
 obj-$(CONFIG_SOC_AM43XX)		+= clockdomains43xx_data.o
 obj-$(CONFIG_SOC_OMAP5)			+= $(clockdomain-common)
@@ -181,7 +185,6 @@
 obj-$(CONFIG_ARCH_OMAP2)		+= $(clock-common) clock2xxx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpllcore.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_virt_prcm_set.o
-obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_apll.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpll.o clkt_iclk.o
 obj-$(CONFIG_SOC_OMAP2430)		+= clock2430.o
 obj-$(CONFIG_ARCH_OMAP3)		+= $(clock-common) clock3xxx.o
@@ -223,6 +226,7 @@
 obj-$(CONFIG_SOC_AM43XX)		+= omap_hwmod_43xx_data.o
 obj-$(CONFIG_SOC_AM43XX)		+= omap_hwmod_33xx_43xx_interconnect_data.o
 obj-$(CONFIG_SOC_AM43XX)		+= omap_hwmod_33xx_43xx_ipblock_data.o
+obj-$(CONFIG_SOC_TI81XX)		+= omap_hwmod_81xx_data.o
 obj-$(CONFIG_ARCH_OMAP4)		+= omap_hwmod_44xx_data.o
 obj-$(CONFIG_SOC_OMAP5)			+= omap_hwmod_54xx_data.o
 obj-$(CONFIG_SOC_DRA7XX)		+= omap_hwmod_7xx_data.o
@@ -250,13 +254,8 @@
 obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51-peripherals.o
 obj-$(CONFIG_MACH_NOKIA_RX51)		+= board-rx51-video.o
 obj-$(CONFIG_MACH_CM_T35)		+= board-cm-t35.o
-obj-$(CONFIG_MACH_CM_T3517)		+= board-cm-t3517.o
 obj-$(CONFIG_MACH_TOUCHBOOK)		+= board-omap3touchbook.o
 
-obj-$(CONFIG_MACH_OMAP3517EVM)		+= board-am3517evm.o
-
-obj-$(CONFIG_MACH_CRANEBOARD)		+= board-am3517crane.o
-
 obj-$(CONFIG_MACH_SBC3530)		+= board-omap3stalker.o
 
 # Platform specific device init code
@@ -286,7 +285,4 @@
 obj-y					+= hwspinlock.o
 endif
 
-emac-$(CONFIG_TI_DAVINCI_EMAC)		:= am35xx-emac.o
-obj-y					+= $(emac-m) $(emac-y)
-
 obj-y					+= common-board-devices.o twl-common.o dss-common.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
deleted file mode 100644
index 6a6935c..0000000
--- a/arch/arm/mach-omap2/am35xx-emac.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
- *
- * Based on mach-omap2/board-am3517evm.c
- * Copyright (C) 2009 Texas Instruments Incorporated
- * Author: Ranjith Lohithakshan <ranjithl@ti.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
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#include <linux/err.h>
-#include <linux/davinci_emac.h>
-#include "omap_device.h"
-#include "am35xx.h"
-#include "control.h"
-#include "am35xx-emac.h"
-
-static void am35xx_enable_emac_int(void)
-{
-	u32 v;
-
-	v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR |
-	      AM35XX_CPGMAC_C0_MISC_PULSE_CLR | AM35XX_CPGMAC_C0_RX_THRESH_CLR);
-	omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
-}
-
-static void am35xx_disable_emac_int(void)
-{
-	u32 v;
-
-	v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-	v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR);
-	omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
-	omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
-}
-
-static struct emac_platform_data am35xx_emac_pdata = {
-	.ctrl_reg_offset	= AM35XX_EMAC_CNTRL_OFFSET,
-	.ctrl_mod_reg_offset	= AM35XX_EMAC_CNTRL_MOD_OFFSET,
-	.ctrl_ram_offset	= AM35XX_EMAC_CNTRL_RAM_OFFSET,
-	.ctrl_ram_size		= AM35XX_EMAC_CNTRL_RAM_SIZE,
-	.hw_ram_addr		= AM35XX_EMAC_HW_RAM_ADDR,
-	.version		= EMAC_VERSION_2,
-	.interrupt_enable	= am35xx_enable_emac_int,
-	.interrupt_disable	= am35xx_disable_emac_int,
-};
-
-static struct mdio_platform_data am35xx_mdio_pdata;
-
-static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
-		void *pdata, int pdata_len)
-{
-	struct platform_device *pdev;
-
-	pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len);
-	if (IS_ERR(pdev)) {
-		WARN(1, "Can't build omap_device for %s:%s.\n",
-		     oh->class->name, oh->name);
-		return PTR_ERR(pdev);
-	}
-
-	return 0;
-}
-
-void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
-{
-	struct omap_hwmod *oh;
-	u32 v;
-	int ret;
-
-	oh = omap_hwmod_lookup("davinci_mdio");
-	if (!oh) {
-		pr_err("Could not find davinci_mdio hwmod\n");
-		return;
-	}
-
-	am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
-
-	ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
-					 sizeof(am35xx_mdio_pdata));
-	if (ret) {
-		pr_err("Could not build davinci_mdio hwmod device\n");
-		return;
-	}
-
-	oh = omap_hwmod_lookup("davinci_emac");
-	if (!oh) {
-		pr_err("Could not find davinci_emac hwmod\n");
-		return;
-	}
-
-	am35xx_emac_pdata.rmii_en = rmii_en;
-
-	ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
-					 sizeof(am35xx_emac_pdata));
-	if (ret) {
-		pr_err("Could not build davinci_emac hwmod device\n");
-		return;
-	}
-
-	v = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-	v &= ~AM35XX_CPGMACSS_SW_RST;
-	omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
-	omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
-}
diff --git a/arch/arm/mach-omap2/am35xx-emac.h b/arch/arm/mach-omap2/am35xx-emac.h
deleted file mode 100644
index 15c6f9c..0000000
--- a/arch/arm/mach-omap2/am35xx-emac.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define AM35XX_DEFAULT_MDIO_FREQUENCY	1000000
-
-#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE)
-void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en);
-#else
-static inline void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en) {}
-#endif
diff --git a/arch/arm/mach-omap2/am35xx.h b/arch/arm/mach-omap2/am35xx.h
deleted file mode 100644
index 9559449..0000000
--- a/arch/arm/mach-omap2/am35xx.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*:
- * Address mappings and base address for AM35XX specific interconnects
- * and peripherals.
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Author: Sriramakrishnan <srk@ti.com>
- *	   Vaibhav Hiremath <hvaibhav@ti.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 __ASM_ARCH_AM35XX_H
-#define __ASM_ARCH_AM35XX_H
-
-/*
- * Base addresses
- *	Note: OMAP3430 IVA2 memory space is being used for AM35xx IPSS modules
- */
-#define AM35XX_IPSS_EMAC_BASE		0x5C000000
-#define AM35XX_IPSS_USBOTGSS_BASE	0x5C040000
-#define AM35XX_IPSS_HECC_BASE		0x5C050000
-#define AM35XX_IPSS_VPFE_BASE		0x5C060000
-
-
-/* HECC module specifc offset definitions */
-#define AM35XX_HECC_SCC_HECC_OFFSET	(0x0)
-#define AM35XX_HECC_SCC_RAM_OFFSET	(0x3000)
-#define AM35XX_HECC_RAM_OFFSET		(0x3000)
-#define AM35XX_HECC_MBOX_OFFSET		(0x2000)
-#define AM35XX_HECC_INT_LINE		(0x0)
-#define AM35XX_HECC_VERSION		(0x1)
-
-#define AM35XX_EMAC_CNTRL_OFFSET	(0x10000)
-#define AM35XX_EMAC_CNTRL_MOD_OFFSET	(0x0)
-#define AM35XX_EMAC_CNTRL_RAM_OFFSET	(0x20000)
-#define AM35XX_EMAC_MDIO_OFFSET		(0x30000)
-#define AM35XX_IPSS_MDIO_BASE		(AM35XX_IPSS_EMAC_BASE + \
-						AM35XX_EMAC_MDIO_OFFSET)
-#define AM35XX_EMAC_CNTRL_RAM_SIZE	(0x2000)
-#define AM35XX_EMAC_RAM_ADDR		(AM3517_EMAC_BASE + \
-						AM3517_EMAC_CNTRL_RAM_OFFSET)
-#define AM35XX_EMAC_HW_RAM_ADDR		(0x01E20000)
-
-#endif  /*  __ASM_ARCH_AM35XX_H */
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
deleted file mode 100644
index 8168dda..0000000
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Support for AM3517/05 Craneboard
- * http://www.mistralsolutions.com/products/craneboard.php
- *
- * Copyright (C) 2010 Mistral Solutions Pvt Ltd. <www.mistralsolutions.com>
- * Author: R.Srinath <srinath@mistralsolutions.com>
- *
- * Based on mach-omap2/board-am3517evm.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as  published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/mfd/tps65910.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/omap-gpmc.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include "common-board-devices.h"
-#include "board-flash.h"
-
-#include "am35xx-emac.h"
-#include "mux.h"
-#include "control.h"
-
-#define GPIO_USB_POWER		35
-#define GPIO_USB_NRESET		38
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
-	OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
-	{ .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static struct usbhs_phy_data phy_data[] __initdata = {
-	{
-		.port = 1,
-		.reset_gpio = GPIO_USB_NRESET,
-		.vcc_gpio = GPIO_USB_POWER,
-		.vcc_polarity = 1,
-	},
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
-	.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-static struct mtd_partition crane_nand_partitions[] = {
-	{
-		.name		= "X-Loader",
-		.offset		= 0,
-		.size		= 4 * NAND_BLOCK_SIZE,
-		.mask_flags	= MTD_WRITEABLE,
-	},
-	{
-		.name		= "U-Boot",
-		.offset		= MTDPART_OFS_APPEND,
-		.size		= 14 * NAND_BLOCK_SIZE,
-		.mask_flags	= MTD_WRITEABLE,
-	},
-	{
-		.name		= "U-Boot Env",
-		.offset		= MTDPART_OFS_APPEND,
-		.size		= 2 * NAND_BLOCK_SIZE,
-	},
-	{
-		.name		= "Kernel",
-		.offset		= MTDPART_OFS_APPEND,
-		.size		= 40 * NAND_BLOCK_SIZE,
-	},
-	{
-		.name		= "File System",
-		.offset		= MTDPART_OFS_APPEND,
-		.size		= MTDPART_SIZ_FULL,
-	},
-};
-
-static struct tps65910_board tps65910_pdata = {
-	.irq = 7 + OMAP_INTC_START,
-	.en_ck32k_xtal = true,
-};
-
-static struct i2c_board_info __initdata tps65910_board_info[] = {
-	{
-		I2C_BOARD_INFO("tps65910", 0x2d),
-		.platform_data = &tps65910_pdata,
-	},
-};
-
-static void __init am3517_crane_i2c_init(void)
-{
-	omap_register_i2c_bus(1, 2600, tps65910_board_info,
-			ARRAY_SIZE(tps65910_board_info));
-}
-
-static void __init am3517_crane_init(void)
-{
-	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-	omap_serial_init();
-	omap_sdrc_init(NULL, NULL);
-	board_nand_init(crane_nand_partitions,
-			ARRAY_SIZE(crane_nand_partitions), 0,
-			NAND_BUSWIDTH_16, NULL);
-	am3517_crane_i2c_init();
-
-	/* Configure GPIO for EHCI port */
-	if (omap_mux_init_gpio(GPIO_USB_NRESET, OMAP_PIN_OUTPUT)) {
-		pr_err("Can not configure mux for GPIO_USB_NRESET %d\n",
-			GPIO_USB_NRESET);
-		return;
-	}
-
-	if (omap_mux_init_gpio(GPIO_USB_POWER, OMAP_PIN_OUTPUT)) {
-		pr_err("Can not configure mux for GPIO_USB_POWER %d\n",
-			GPIO_USB_POWER);
-		return;
-	}
-
-	usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
-	usbhs_init(&usbhs_bdata);
-	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
-}
-
-MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
-	.atag_offset	= 0x100,
-	.reserve	= omap_reserve,
-	.map_io		= omap3_map_io,
-	.init_early	= am35xx_init_early,
-	.init_irq	= omap3_init_irq,
-	.init_machine	= am3517_crane_init,
-	.init_late	= am35xx_init_late,
-	.init_time	= omap3_sync32k_timer_init,
-	.restart	= omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
deleted file mode 100644
index 1c091b3..0000000
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-am3517evm.c
- *
- * Copyright (C) 2009 Texas Instruments Incorporated
- * Author: Ranjith Lohithakshan <ranjithl@ti.com>
- *
- * Based on mach-omap2/board-omap3evm.c
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as  published by the
- * Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/pca953x.h>
-#include <linux/can/platform/ti_hecc.h>
-#include <linux/davinci_emac.h>
-#include <linux/mmc/host.h>
-#include <linux/usb/musb.h>
-#include <linux/platform_data/gpio-omap.h>
-
-#include "am35xx.h"
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include <video/omapdss.h>
-#include <video/omap-panel-data.h>
-
-#include "am35xx-emac.h"
-#include "mux.h"
-#include "control.h"
-#include "hsmmc.h"
-
-#define LCD_PANEL_PWR		176
-#define LCD_PANEL_BKLIGHT_PWR	182
-#define LCD_PANEL_PWM		181
-
-static struct i2c_board_info __initdata am3517evm_i2c1_boardinfo[] = {
-	{
-		I2C_BOARD_INFO("s35390a", 0x30),
-	},
-};
-
-/*
- * RTC - S35390A
- */
-#define GPIO_RTCS35390A_IRQ	55
-
-static void __init am3517_evm_rtc_init(void)
-{
-	int r;
-
-	omap_mux_init_gpio(GPIO_RTCS35390A_IRQ, OMAP_PIN_INPUT_PULLUP);
-
-	r = gpio_request_one(GPIO_RTCS35390A_IRQ, GPIOF_IN, "rtcs35390a-irq");
-	if (r < 0) {
-		printk(KERN_WARNING "failed to request GPIO#%d\n",
-				GPIO_RTCS35390A_IRQ);
-		return;
-	}
-
-	am3517evm_i2c1_boardinfo[0].irq = gpio_to_irq(GPIO_RTCS35390A_IRQ);
-}
-
-/*
- * I2C GPIO Expander - TCA6416
- */
-
-/* Mounted on Base-Board */
-static struct pca953x_platform_data am3517evm_gpio_expander_info_0 = {
-	.gpio_base	= OMAP_MAX_GPIO_LINES,
-};
-static struct i2c_board_info __initdata am3517evm_i2c2_boardinfo[] = {
-	{
-		I2C_BOARD_INFO("tlv320aic23", 0x1A),
-	},
-	{
-		I2C_BOARD_INFO("tca6416", 0x21),
-		.platform_data = &am3517evm_gpio_expander_info_0,
-	},
-};
-
-/* Mounted on UI Card */
-static struct pca953x_platform_data am3517evm_ui_gpio_expander_info_1 = {
-	.gpio_base	= OMAP_MAX_GPIO_LINES + 16,
-};
-static struct pca953x_platform_data am3517evm_ui_gpio_expander_info_2 = {
-	.gpio_base	= OMAP_MAX_GPIO_LINES + 32,
-};
-static struct i2c_board_info __initdata am3517evm_i2c3_boardinfo[] = {
-	{
-		I2C_BOARD_INFO("tca6416", 0x20),
-		.platform_data = &am3517evm_ui_gpio_expander_info_1,
-	},
-	{
-		I2C_BOARD_INFO("tca6416", 0x21),
-		.platform_data = &am3517evm_ui_gpio_expander_info_2,
-	},
-};
-
-static int __init am3517_evm_i2c_init(void)
-{
-	omap_register_i2c_bus(1, 400, NULL, 0);
-	omap_register_i2c_bus(2, 400, am3517evm_i2c2_boardinfo,
-			ARRAY_SIZE(am3517evm_i2c2_boardinfo));
-	omap_register_i2c_bus(3, 400, am3517evm_i2c3_boardinfo,
-			ARRAY_SIZE(am3517evm_i2c3_boardinfo));
-
-	return 0;
-}
-
-static const struct display_timing am3517_evm_lcd_videomode = {
-	.pixelclock	= { 0, 9000000, 0 },
-
-	.hactive = { 0, 480, 0 },
-	.hfront_porch = { 0, 3, 0 },
-	.hback_porch = { 0, 2, 0 },
-	.hsync_len = { 0, 42, 0 },
-
-	.vactive = { 0, 272, 0 },
-	.vfront_porch = { 0, 3, 0 },
-	.vback_porch = { 0, 2, 0 },
-	.vsync_len = { 0, 11, 0 },
-
-	.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
-		DISPLAY_FLAGS_DE_LOW | DISPLAY_FLAGS_PIXDATA_POSEDGE,
-};
-
-static struct panel_dpi_platform_data am3517_evm_lcd_pdata = {
-	.name                   = "lcd",
-	.source                 = "dpi.0",
-
-	.data_lines		= 16,
-
-	.display_timing		= &am3517_evm_lcd_videomode,
-
-	.enable_gpio		= LCD_PANEL_PWR,
-	.backlight_gpio		= LCD_PANEL_BKLIGHT_PWR,
-};
-
-static struct platform_device am3517_evm_lcd_device = {
-	.name                   = "panel-dpi",
-	.id                     = 0,
-	.dev.platform_data      = &am3517_evm_lcd_pdata,
-};
-
-static struct connector_dvi_platform_data am3517_evm_dvi_connector_pdata = {
-	.name                   = "dvi",
-	.source                 = "tfp410.0",
-	.i2c_bus_num            = -1,
-};
-
-static struct platform_device am3517_evm_dvi_connector_device = {
-	.name                   = "connector-dvi",
-	.id                     = 0,
-	.dev.platform_data      = &am3517_evm_dvi_connector_pdata,
-};
-
-static struct encoder_tfp410_platform_data am3517_evm_tfp410_pdata = {
-	.name                   = "tfp410.0",
-	.source                 = "dpi.0",
-	.data_lines             = 24,
-	.power_down_gpio        = -1,
-};
-
-static struct platform_device am3517_evm_tfp410_device = {
-	.name                   = "tfp410",
-	.id                     = 0,
-	.dev.platform_data      = &am3517_evm_tfp410_pdata,
-};
-
-static struct connector_atv_platform_data am3517_evm_tv_pdata = {
-	.name = "tv",
-	.source = "venc.0",
-	.connector_type = OMAP_DSS_VENC_TYPE_SVIDEO,
-	.invert_polarity = false,
-};
-
-static struct platform_device am3517_evm_tv_connector_device = {
-	.name                   = "connector-analog-tv",
-	.id                     = 0,
-	.dev.platform_data      = &am3517_evm_tv_pdata,
-};
-
-static struct omap_dss_board_info am3517_evm_dss_data = {
-	.default_display_name = "lcd",
-};
-
-static void __init am3517_evm_display_init(void)
-{
-	gpio_request_one(LCD_PANEL_PWM, GPIOF_OUT_INIT_HIGH, "lcd panel pwm");
-
-	omap_display_init(&am3517_evm_dss_data);
-
-	platform_device_register(&am3517_evm_tfp410_device);
-	platform_device_register(&am3517_evm_dvi_connector_device);
-	platform_device_register(&am3517_evm_lcd_device);
-	platform_device_register(&am3517_evm_tv_connector_device);
-}
-
-/*
- * Board initialization
- */
-
-static struct omap_musb_board_data musb_board_data = {
-	.interface_type         = MUSB_INTERFACE_ULPI,
-	.mode                   = MUSB_OTG,
-	.power                  = 500,
-	.set_phy_power		= am35x_musb_phy_power,
-	.clear_irq		= am35x_musb_clear_irq,
-	.set_mode		= am35x_set_mode,
-	.reset			= am35x_musb_reset,
-};
-
-static __init void am3517_evm_musb_init(void)
-{
-	u32 devconf2;
-
-	/*
-	 * Set up USB clock/mode in the DEVCONF2 register.
-	 */
-	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
-	/* USB2.0 PHY reference clock is 13 MHz */
-	devconf2 &= ~(CONF2_REFFREQ | CONF2_OTGMODE | CONF2_PHY_GPIOMODE);
-	devconf2 |=  CONF2_REFFREQ_13MHZ | CONF2_SESENDEN | CONF2_VBDTCTEN
-			| CONF2_DATPOL;
-
-	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
-
-	usb_musb_init(&musb_board_data);
-}
-
-static __init void am3517_evm_mcbsp1_init(void)
-{
-	u32 devconf0;
-
-	/* McBSP1 CLKR/FSR signal to be connected to CLKX/FSX pin */
-	devconf0 = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-	devconf0 |=  OMAP2_MCBSP1_CLKR_MASK | OMAP2_MCBSP1_FSR_MASK;
-	omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0);
-}
-
-static struct usbhs_phy_data phy_data[] __initdata = {
-	{
-		.port = 1,
-		.reset_gpio = 57,
-		.vcc_gpio = -EINVAL,
-	},
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
-	.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-	.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
-	/* USB OTG DRVVBUS offset = 0x212 */
-	OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
-	{ .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-
-static struct resource am3517_hecc_resources[] = {
-	{
-		.start	= AM35XX_IPSS_HECC_BASE,
-		.end	= AM35XX_IPSS_HECC_BASE + 0x3FFF,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= 24 + OMAP_INTC_START,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct platform_device am3517_hecc_device = {
-	.name		= "ti_hecc",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(am3517_hecc_resources),
-	.resource	= am3517_hecc_resources,
-};
-
-static struct ti_hecc_platform_data am3517_evm_hecc_pdata = {
-	.scc_hecc_offset	= AM35XX_HECC_SCC_HECC_OFFSET,
-	.scc_ram_offset		= AM35XX_HECC_SCC_RAM_OFFSET,
-	.hecc_ram_offset	= AM35XX_HECC_RAM_OFFSET,
-	.mbx_offset		= AM35XX_HECC_MBOX_OFFSET,
-	.int_line		= AM35XX_HECC_INT_LINE,
-	.version		= AM35XX_HECC_VERSION,
-};
-
-static void am3517_evm_hecc_init(struct ti_hecc_platform_data *pdata)
-{
-	am3517_hecc_device.dev.platform_data = pdata;
-	platform_device_register(&am3517_hecc_device);
-}
-
-static struct omap2_hsmmc_info mmc[] = {
-	{
-		.mmc		= 1,
-		.caps		= MMC_CAP_4_BIT_DATA,
-		.gpio_cd	= 127,
-		.gpio_wp	= 126,
-	},
-	{
-		.mmc		= 2,
-		.caps		= MMC_CAP_4_BIT_DATA,
-		.gpio_cd	= 128,
-		.gpio_wp	= 129,
-	},
-	{}      /* Terminator */
-};
-
-static void __init am3517_evm_init(void)
-{
-	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-
-	am3517_evm_i2c_init();
-
-	am3517_evm_display_init();
-
-	omap_serial_init();
-	omap_sdrc_init(NULL, NULL);
-
-	/* Configure GPIO for EHCI port */
-	omap_mux_init_gpio(57, OMAP_PIN_OUTPUT);
-
-	usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
-	usbhs_init(&usbhs_bdata);
-	am3517_evm_hecc_init(&am3517_evm_hecc_pdata);
-
-	/* RTC - S35390A */
-	am3517_evm_rtc_init();
-
-	i2c_register_board_info(1, am3517evm_i2c1_boardinfo,
-				ARRAY_SIZE(am3517evm_i2c1_boardinfo));
-	/*Ethernet*/
-	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
-
-	/* MUSB */
-	am3517_evm_musb_init();
-
-	/* McBSP1 */
-	am3517_evm_mcbsp1_init();
-
-	/* MMC init function */
-	omap_hsmmc_init(mmc);
-}
-
-MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
-	.atag_offset	= 0x100,
-	.reserve	= omap_reserve,
-	.map_io		= omap3_map_io,
-	.init_early	= am35xx_init_early,
-	.init_irq	= omap3_init_irq,
-	.init_machine	= am3517_evm_init,
-	.init_late	= am35xx_init_late,
-	.init_time	= omap3_sync32k_timer_init,
-	.restart	= omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
deleted file mode 100644
index 794756d..0000000
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-cm-t3517.c
- *
- * Support for the CompuLab CM-T3517 modules
- *
- * Copyright (C) 2010 CompuLab, Ltd.
- * Author: Igor Grinberg <grinberg@compulab.co.il>
- *
- * 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
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/leds.h>
-#include <linux/omap-gpmc.h>
-#include <linux/rtc-v3020.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mmc/host.h>
-#include <linux/can/platform/ti_hecc.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#include "am35xx.h"
-
-#include "mux.h"
-#include "control.h"
-#include "hsmmc.h"
-#include "common-board-devices.h"
-#include "am35xx-emac.h"
-
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-static struct gpio_led cm_t3517_leds[] = {
-	[0] = {
-		.gpio			= 186,
-		.name			= "cm-t3517:green",
-		.default_trigger	= "heartbeat",
-		.active_low		= 0,
-	},
-};
-
-static struct gpio_led_platform_data cm_t3517_led_pdata = {
-	.num_leds	= ARRAY_SIZE(cm_t3517_leds),
-	.leds		= cm_t3517_leds,
-};
-
-static struct platform_device cm_t3517_led_device = {
-	.name		= "leds-gpio",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &cm_t3517_led_pdata,
-	},
-};
-
-static void __init cm_t3517_init_leds(void)
-{
-	platform_device_register(&cm_t3517_led_device);
-}
-#else
-static inline void cm_t3517_init_leds(void) {}
-#endif
-
-#if defined(CONFIG_CAN_TI_HECC) || defined(CONFIG_CAN_TI_HECC_MODULE)
-static struct resource cm_t3517_hecc_resources[] = {
-	{
-		.start	= AM35XX_IPSS_HECC_BASE,
-		.end	= AM35XX_IPSS_HECC_BASE + SZ_16K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= 24 + OMAP_INTC_START,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct ti_hecc_platform_data cm_t3517_hecc_pdata = {
-	.scc_hecc_offset	= AM35XX_HECC_SCC_HECC_OFFSET,
-	.scc_ram_offset		= AM35XX_HECC_SCC_RAM_OFFSET,
-	.hecc_ram_offset	= AM35XX_HECC_RAM_OFFSET,
-	.mbx_offset		= AM35XX_HECC_MBOX_OFFSET,
-	.int_line		= AM35XX_HECC_INT_LINE,
-	.version		= AM35XX_HECC_VERSION,
-};
-
-static struct platform_device cm_t3517_hecc_device = {
-	.name		= "ti_hecc",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(cm_t3517_hecc_resources),
-	.resource	= cm_t3517_hecc_resources,
-	.dev		= {
-		.platform_data	= &cm_t3517_hecc_pdata,
-	},
-};
-
-static void cm_t3517_init_hecc(void)
-{
-	platform_device_register(&cm_t3517_hecc_device);
-}
-#else
-static inline void cm_t3517_init_hecc(void) {}
-#endif
-
-#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
-static struct omap2_hsmmc_info cm_t3517_mmc[] = {
-	{
-		.mmc		= 1,
-		.caps		= MMC_CAP_4_BIT_DATA,
-		.gpio_cd	= 144,
-		.gpio_wp	= 59,
-	},
-	{
-		.mmc		= 2,
-		.caps		= MMC_CAP_4_BIT_DATA,
-		.gpio_cd	= -EINVAL,
-		.gpio_wp	= -EINVAL,
-	},
-	{}	/* Terminator */
-};
-#else
-#define cm_t3517_mmc NULL
-#endif
-
-#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
-#define RTC_IO_GPIO		(153)
-#define RTC_WR_GPIO		(154)
-#define RTC_RD_GPIO		(53)
-#define RTC_CS_GPIO		(163)
-#define RTC_CS_EN_GPIO		(160)
-
-struct v3020_platform_data cm_t3517_v3020_pdata = {
-	.use_gpio	= 1,
-	.gpio_cs	= RTC_CS_GPIO,
-	.gpio_wr	= RTC_WR_GPIO,
-	.gpio_rd	= RTC_RD_GPIO,
-	.gpio_io	= RTC_IO_GPIO,
-};
-
-static struct platform_device cm_t3517_rtc_device = {
-	.name		= "v3020",
-	.id		= -1,
-	.dev		= {
-		.platform_data = &cm_t3517_v3020_pdata,
-	}
-};
-
-static void __init cm_t3517_init_rtc(void)
-{
-	int err;
-
-	err = gpio_request_one(RTC_CS_EN_GPIO, GPIOF_OUT_INIT_HIGH,
-			       "rtc cs en");
-	if (err) {
-		pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err);
-		return;
-	}
-
-	platform_device_register(&cm_t3517_rtc_device);
-}
-#else
-static inline void cm_t3517_init_rtc(void) {}
-#endif
-
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
-#define HSUSB1_RESET_GPIO	(146)
-#define HSUSB2_RESET_GPIO	(147)
-#define USB_HUB_RESET_GPIO	(152)
-
-static struct usbhs_phy_data phy_data[] __initdata = {
-	{
-		.port = 1,
-		.reset_gpio = HSUSB1_RESET_GPIO,
-		.vcc_gpio = -EINVAL,
-	},
-	{
-		.port = 2,
-		.reset_gpio = HSUSB2_RESET_GPIO,
-		.vcc_gpio = -EINVAL,
-	},
-};
-
-static struct usbhs_omap_platform_data cm_t3517_ehci_pdata __initdata = {
-	.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-	.port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-static int __init cm_t3517_init_usbh(void)
-{
-	int err;
-
-	err = gpio_request_one(USB_HUB_RESET_GPIO, GPIOF_OUT_INIT_LOW,
-			       "usb hub rst");
-	if (err) {
-		pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
-	} else {
-		udelay(10);
-		gpio_set_value(USB_HUB_RESET_GPIO, 1);
-		msleep(1);
-	}
-
-	usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
-	usbhs_init(&cm_t3517_ehci_pdata);
-
-	return 0;
-}
-#else
-static inline int cm_t3517_init_usbh(void)
-{
-	return 0;
-}
-#endif
-
-#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
-static struct mtd_partition cm_t3517_nand_partitions[] = {
-	{
-		.name           = "xloader",
-		.offset         = 0,			/* Offset = 0x00000 */
-		.size           = 4 * NAND_BLOCK_SIZE,
-		.mask_flags     = MTD_WRITEABLE
-	},
-	{
-		.name           = "uboot",
-		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x80000 */
-		.size           = 15 * NAND_BLOCK_SIZE,
-	},
-	{
-		.name           = "uboot environment",
-		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x260000 */
-		.size           = 2 * NAND_BLOCK_SIZE,
-	},
-	{
-		.name           = "linux",
-		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x2A0000 */
-		.size           = 32 * NAND_BLOCK_SIZE,
-	},
-	{
-		.name           = "rootfs",
-		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x6A0000 */
-		.size           = MTDPART_SIZ_FULL,
-	},
-};
-
-static struct omap_nand_platform_data cm_t3517_nand_data = {
-	.parts			= cm_t3517_nand_partitions,
-	.nr_parts		= ARRAY_SIZE(cm_t3517_nand_partitions),
-	.cs			= 0,
-};
-
-static void __init cm_t3517_init_nand(void)
-{
-	if (gpmc_nand_init(&cm_t3517_nand_data, NULL) < 0)
-		pr_err("CM-T3517: NAND initialization failed\n");
-}
-#else
-static inline void cm_t3517_init_nand(void) {}
-#endif
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
-	/* GPIO186 - Green LED */
-	OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-
-	/* RTC GPIOs: */
-	/* IO - GPIO153 */
-	OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-	/* WR# - GPIO154 */
-	OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-	/* RD# - GPIO53 */
-	OMAP3_MUX(GPMC_NCS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-	/* CS# - GPIO163 */
-	OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-	/* CS EN - GPIO160 */
-	OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
-
-	/* HSUSB1 RESET */
-	OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-	/* HSUSB2 RESET */
-	OMAP3_MUX(UART2_RX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-	/* CM-T3517 USB HUB nRESET */
-	OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
-
-	/* CD - GPIO144 and WP - GPIO59 for MMC1 - SB-T35 */
-	OMAP3_MUX(UART2_CTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
-	OMAP3_MUX(GPMC_CLK, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
-
-	{ .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static void __init cm_t3517_init(void)
-{
-	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-	omap_serial_init();
-	omap_sdrc_init(NULL, NULL);
-	cm_t3517_init_leds();
-	cm_t3517_init_nand();
-	cm_t3517_init_rtc();
-	cm_t3517_init_usbh();
-	cm_t3517_init_hecc();
-	am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
-	omap_hsmmc_init(cm_t3517_mmc);
-}
-
-MACHINE_START(CM_T3517, "Compulab CM-T3517")
-	.atag_offset	= 0x100,
-	.reserve        = omap_reserve,
-	.map_io		= omap3_map_io,
-	.init_early	= am35xx_init_early,
-	.init_irq	= omap3_init_irq,
-	.init_machine	= cm_t3517_init,
-	.init_late	= am35xx_init_late,
-	.init_time	= omap3_gptimer_timer_init,
-	.restart	= omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 42b7f4c..34ff14b 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -162,6 +162,42 @@
 MACHINE_END
 #endif
 
+#ifdef CONFIG_SOC_TI81XX
+static const char *const ti814x_boards_compat[] __initconst = {
+	"ti,dm8148",
+	"ti,dm814",
+	NULL,
+};
+
+DT_MACHINE_START(TI81XX_DT, "Generic ti814x (Flattened Device Tree)")
+	.reserve	= omap_reserve,
+	.map_io		= ti81xx_map_io,
+	.init_early	= ti814x_init_early,
+	.init_machine	= omap_generic_init,
+	.init_late	= ti81xx_init_late,
+	.init_time	= omap3_gptimer_timer_init,
+	.dt_compat	= ti814x_boards_compat,
+	.restart	= ti81xx_restart,
+MACHINE_END
+
+static const char *const ti816x_boards_compat[] __initconst = {
+	"ti,dm8168",
+	"ti,dm816",
+	NULL,
+};
+
+DT_MACHINE_START(TI816X_DT, "Generic ti816x (Flattened Device Tree)")
+	.reserve	= omap_reserve,
+	.map_io		= ti81xx_map_io,
+	.init_early	= ti816x_init_early,
+	.init_machine	= omap_generic_init,
+	.init_late	= ti81xx_init_late,
+	.init_time	= omap3_gptimer_timer_init,
+	.dt_compat	= ti816x_boards_compat,
+	.restart	= ti81xx_restart,
+MACHINE_END
+#endif
+
 #ifdef CONFIG_SOC_AM33XX
 static const char *const am33xx_boards_compat[] __initconst = {
 	"ti,am33xx",
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 644ff32..e79c80b 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -3634,10 +3634,6 @@
 		omap_clocks_register(omap36xx_am35xx_omap3430es2plus_clks,
 				     ARRAY_SIZE(omap36xx_am35xx_omap3430es2plus_clks));
 		omap_clocks_register(omap3xxx_clks, ARRAY_SIZE(omap3xxx_clks));
-	} else if (soc_is_am33xx()) {
-		cpu_mask = RATE_IN_AM33XX;
-	} else if (cpu_is_ti814x()) {
-		cpu_mask = RATE_IN_TI814X;
 	} else if (cpu_is_omap34xx()) {
 		if (omap_rev() == OMAP3430_REV_ES1_0) {
 			cpu_mask = RATE_IN_3430ES1;
@@ -3681,7 +3677,7 @@
 	 * Lock DPLL5 -- here only until other device init code can
 	 * handle this
 	 */
-	if (!cpu_is_ti81xx() && (omap_rev() >= OMAP3430_REV_ES2_0))
+	if (omap_rev() >= OMAP3430_REV_ES2_0)
 		omap3_clk_lock_dpll5();
 
 	/* Avoid sleeping during omap3_core_dpll_m2_set_rate() */
diff --git a/arch/arm/mach-omap2/clkt2xxx_apll.c b/arch/arm/mach-omap2/clkt2xxx_apll.c
deleted file mode 100644
index c78e893..0000000
--- a/arch/arm/mach-omap2/clkt2xxx_apll.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * OMAP2xxx APLL clock control functions
- *
- * Copyright (C) 2005-2008 Texas Instruments, Inc.
- * Copyright (C) 2004-2010 Nokia Corporation
- *
- * Contacts:
- * Richard Woodruff <r-woodruff2@ti.com>
- * Paul Walmsley
- *
- * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
- * Gordon McNutt and RidgeRun, 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.
- */
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-
-#include "clock.h"
-#include "clock2xxx.h"
-#include "cm2xxx.h"
-#include "cm-regbits-24xx.h"
-
-/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */
-#define EN_APLL_STOPPED			0
-#define EN_APLL_LOCKED			3
-
-/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */
-#define APLLS_CLKIN_19_2MHZ		0
-#define APLLS_CLKIN_13MHZ		2
-#define APLLS_CLKIN_12MHZ		3
-
-/* Private functions */
-
-/**
- * omap2xxx_clk_apll_locked - is the APLL locked?
- * @hw: struct clk_hw * of the APLL to check
- *
- * If the APLL IP block referred to by @hw indicates that it's locked,
- * return true; otherwise, return false.
- */
-static bool omap2xxx_clk_apll_locked(struct clk_hw *hw)
-{
-	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
-	u32 r, apll_mask;
-
-	apll_mask = EN_APLL_LOCKED << clk->enable_bit;
-
-	r = omap2xxx_cm_get_pll_status();
-
-	return ((r & apll_mask) == apll_mask) ? true : false;
-}
-
-int omap2_clk_apll96_enable(struct clk_hw *hw)
-{
-	return omap2xxx_cm_apll96_enable();
-}
-
-int omap2_clk_apll54_enable(struct clk_hw *hw)
-{
-	return omap2xxx_cm_apll54_enable();
-}
-
-static void _apll96_allow_idle(struct clk_hw_omap *clk)
-{
-	omap2xxx_cm_set_apll96_auto_low_power_stop();
-}
-
-static void _apll96_deny_idle(struct clk_hw_omap *clk)
-{
-	omap2xxx_cm_set_apll96_disable_autoidle();
-}
-
-static void _apll54_allow_idle(struct clk_hw_omap *clk)
-{
-	omap2xxx_cm_set_apll54_auto_low_power_stop();
-}
-
-static void _apll54_deny_idle(struct clk_hw_omap *clk)
-{
-	omap2xxx_cm_set_apll54_disable_autoidle();
-}
-
-void omap2_clk_apll96_disable(struct clk_hw *hw)
-{
-	omap2xxx_cm_apll96_disable();
-}
-
-void omap2_clk_apll54_disable(struct clk_hw *hw)
-{
-	omap2xxx_cm_apll54_disable();
-}
-
-unsigned long omap2_clk_apll54_recalc(struct clk_hw *hw,
-				      unsigned long parent_rate)
-{
-	return (omap2xxx_clk_apll_locked(hw)) ? 54000000 : 0;
-}
-
-unsigned long omap2_clk_apll96_recalc(struct clk_hw *hw,
-				      unsigned long parent_rate)
-{
-	return (omap2xxx_clk_apll_locked(hw)) ? 96000000 : 0;
-}
-
-/* Public data */
-const struct clk_hw_omap_ops clkhwops_apll54 = {
-	.allow_idle	= _apll54_allow_idle,
-	.deny_idle	= _apll54_deny_idle,
-};
-
-const struct clk_hw_omap_ops clkhwops_apll96 = {
-	.allow_idle	= _apll96_allow_idle,
-	.deny_idle	= _apll96_deny_idle,
-};
-
-/* Public functions */
-
-u32 omap2xxx_get_apll_clkin(void)
-{
-	u32 aplls, srate = 0;
-
-	aplls = omap2xxx_cm_get_pll_config();
-	aplls &= OMAP24XX_APLLS_CLKIN_MASK;
-	aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
-
-	if (aplls == APLLS_CLKIN_19_2MHZ)
-		srate = 19200000;
-	else if (aplls == APLLS_CLKIN_13MHZ)
-		srate = 13000000;
-	else if (aplls == APLLS_CLKIN_12MHZ)
-		srate = 12000000;
-
-	return srate;
-}
-
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 6ad5b4d..4ae4cce 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -620,6 +620,9 @@
 
 	for (i = 0; i < num_clocks; i++) {
 		init_clk = clk_get(NULL, clk_names[i]);
+		if (WARN(IS_ERR(init_clk), "could not find init clock %s\n",
+				clk_names[i]))
+			continue;
 		clk_prepare_enable(init_clk);
 	}
 }
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index a4282e7..1cf9dd8 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -177,7 +177,6 @@
 u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
 void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
 void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
-int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk);
 void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk);
 void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk);
 
diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h
index a090225..125c376 100644
--- a/arch/arm/mach-omap2/clock2xxx.h
+++ b/arch/arm/mach-omap2/clock2xxx.h
@@ -22,12 +22,7 @@
 unsigned long omap2_osc_clk_recalc(struct clk_hw *clk,
 				   unsigned long parent_rate);
 void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw);
-unsigned long omap2_clk_apll54_recalc(struct clk_hw *hw,
-				      unsigned long parent_rate);
-unsigned long omap2_clk_apll96_recalc(struct clk_hw *hw,
-				      unsigned long parent_rate);
 unsigned long omap2xxx_clk_get_core_rate(void);
-u32 omap2xxx_get_apll_clkin(void);
 u32 omap2xxx_get_sysclkdiv(void);
 void omap2xxx_clk_prepare_for_reboot(void);
 void omap2xxx_clkt_vps_check_bootloader_rates(void);
@@ -46,11 +41,5 @@
 #endif
 
 extern struct clk_hw *dclk_hw;
-int omap2_enable_osc_ck(struct clk_hw *hw);
-void omap2_disable_osc_ck(struct clk_hw *hw);
-int omap2_clk_apll96_enable(struct clk_hw *hw);
-int omap2_clk_apll54_enable(struct clk_hw *hw);
-void omap2_clk_apll96_disable(struct clk_hw *hw);
-void omap2_clk_apll54_disable(struct clk_hw *hw);
 
 #endif
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 82c37b1..77bab5f 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -216,6 +216,7 @@
 extern void __init omap243x_clockdomains_init(void);
 extern void __init omap3xxx_clockdomains_init(void);
 extern void __init am33xx_clockdomains_init(void);
+extern void __init ti81xx_clockdomains_init(void);
 extern void __init omap44xx_clockdomains_init(void);
 extern void __init omap54xx_clockdomains_init(void);
 extern void __init dra7xx_clockdomains_init(void);
diff --git a/arch/arm/mach-omap2/clockdomains81xx_data.c b/arch/arm/mach-omap2/clockdomains81xx_data.c
new file mode 100644
index 0000000..ce2a820
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomains81xx_data.c
@@ -0,0 +1,194 @@
+/*
+ * TI81XX Clock Domain data.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
+ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_81XX_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_81XX_H
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include "clockdomain.h"
+#include "cm81xx.h"
+
+/*
+ * Note that 814x seems to have HWSUP_SWSUP for many clockdomains
+ * while 816x does not. According to the TRM, 816x only has HWSUP
+ * for ALWON_L3_FAST. Also note that the TI tree clockdomains81xx.h
+ * seems to have the related ifdef the wrong way around claiming
+ * 816x supports HWSUP while 814x does not. For now, we only set
+ * HWSUP for ALWON_L3_FAST as that seems to be supported for both
+ * dm814x and dm816x.
+ */
+
+/* Common for 81xx */
+
+static struct clockdomain alwon_l3_slow_81xx_clkdm = {
+	.name		= "alwon_l3s_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_ALWON_L3_SLOW_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain alwon_l3_med_81xx_clkdm = {
+	.name		= "alwon_l3_med_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_ALWON_L3_MED_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain alwon_l3_fast_81xx_clkdm = {
+	.name		= "alwon_l3_fast_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_ALWON_L3_FAST_CLKDM,
+	.flags		= CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain alwon_ethernet_81xx_clkdm = {
+	.name		= "alwon_ethernet_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_ETHERNET_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain mmu_81xx_clkdm = {
+	.name		= "mmu_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_MMU_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain mmu_cfg_81xx_clkdm = {
+	.name		= "mmu_cfg_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_MMUCFG_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+/* 816x only */
+
+static struct clockdomain alwon_mpu_816x_clkdm = {
+	.name		= "alwon_mpu_clkdm",
+	.pwrdm		= { .name = "alwon_pwrdm" },
+	.cm_inst	= TI81XX_CM_ALWON_MOD,
+	.clkdm_offs	= TI81XX_CM_ALWON_MPU_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain active_gem_816x_clkdm = {
+	.name		= "active_gem_clkdm",
+	.pwrdm		= { .name = "active_pwrdm" },
+	.cm_inst	= TI816X_CM_ACTIVE_MOD,
+	.clkdm_offs	= TI816X_CM_ACTIVE_GEM_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain ivahd0_816x_clkdm = {
+	.name		= "ivahd0_clkdm",
+	.pwrdm		= { .name = "ivahd0_pwrdm" },
+	.cm_inst	= TI816X_CM_IVAHD0_MOD,
+	.clkdm_offs	= TI816X_CM_IVAHD0_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain ivahd1_816x_clkdm = {
+	.name		= "ivahd1_clkdm",
+	.pwrdm		= { .name = "ivahd1_pwrdm" },
+	.cm_inst	= TI816X_CM_IVAHD1_MOD,
+	.clkdm_offs	= TI816X_CM_IVAHD1_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain ivahd2_816x_clkdm = {
+	.name		= "ivahd2_clkdm",
+	.pwrdm		= { .name = "ivahd2_pwrdm" },
+	.cm_inst	= TI816X_CM_IVAHD2_MOD,
+	.clkdm_offs	= TI816X_CM_IVAHD2_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain sgx_816x_clkdm = {
+	.name		= "sgx_clkdm",
+	.pwrdm		= { .name = "sgx_pwrdm" },
+	.cm_inst	= TI816X_CM_SGX_MOD,
+	.clkdm_offs	= TI816X_CM_SGX_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain default_l3_med_816x_clkdm = {
+	.name		= "default_l3_med_clkdm",
+	.pwrdm		= { .name = "default_pwrdm" },
+	.cm_inst	= TI816X_CM_DEFAULT_MOD,
+	.clkdm_offs	= TI816X_CM_DEFAULT_L3_MED_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain default_ducati_816x_clkdm = {
+	.name		= "default_ducati_clkdm",
+	.pwrdm		= { .name = "default_pwrdm" },
+	.cm_inst	= TI816X_CM_DEFAULT_MOD,
+	.clkdm_offs	= TI816X_CM_DEFAULT_DUCATI_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain default_pci_816x_clkdm = {
+	.name		= "default_pci_clkdm",
+	.pwrdm		= { .name = "default_pwrdm" },
+	.cm_inst	= TI816X_CM_DEFAULT_MOD,
+	.clkdm_offs	= TI816X_CM_DEFAULT_PCI_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain default_l3_slow_816x_clkdm = {
+	.name		= "default_l3_slow_clkdm",
+	.pwrdm		= { .name = "default_pwrdm" },
+	.cm_inst	= TI816X_CM_DEFAULT_MOD,
+	.clkdm_offs	= TI816X_CM_DEFAULT_L3_SLOW_CLKDM,
+	.flags		= CLKDM_CAN_SWSUP,
+};
+
+static struct clockdomain *clockdomains_ti81xx[] __initdata = {
+	&alwon_mpu_816x_clkdm,
+	&alwon_l3_slow_81xx_clkdm,
+	&alwon_l3_med_81xx_clkdm,
+	&alwon_l3_fast_81xx_clkdm,
+	&alwon_ethernet_81xx_clkdm,
+	&mmu_81xx_clkdm,
+	&mmu_cfg_81xx_clkdm,
+	&active_gem_816x_clkdm,
+	&ivahd0_816x_clkdm,
+	&ivahd1_816x_clkdm,
+	&ivahd2_816x_clkdm,
+	&sgx_816x_clkdm,
+	&default_l3_med_816x_clkdm,
+	&default_ducati_816x_clkdm,
+	&default_pci_816x_clkdm,
+	&default_l3_slow_816x_clkdm,
+	NULL,
+};
+
+void __init ti81xx_clockdomains_init(void)
+{
+	clkdm_register_platform_funcs(&am33xx_clkdm_operations);
+	clkdm_register_clkdms(clockdomains_ti81xx);
+	clkdm_complete_init();
+}
+#endif
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
index a96d901..ef62ac9 100644
--- a/arch/arm/mach-omap2/cm2xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx.c
@@ -370,16 +370,6 @@
 	return omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
 }
 
-u32 omap2xxx_cm_get_pll_config(void)
-{
-	return omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
-}
-
-u32 omap2xxx_cm_get_pll_status(void)
-{
-	return omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN);
-}
-
 void omap2xxx_cm_set_mod_dividers(u32 mpu, u32 dsp, u32 gfx, u32 core, u32 mdm)
 {
 	u32 tmp;
diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h
index c89502b..83b6c59 100644
--- a/arch/arm/mach-omap2/cm2xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx.h
@@ -60,8 +60,6 @@
 extern int omap2xxx_cm_mpu_retention_allowed(void);
 extern u32 omap2xxx_cm_get_core_clk_src(void);
 extern u32 omap2xxx_cm_get_core_pll_config(void);
-extern u32 omap2xxx_cm_get_pll_config(void);
-extern u32 omap2xxx_cm_get_pll_status(void);
 extern void omap2xxx_cm_set_mod_dividers(u32 mpu, u32 dsp, u32 gfx, u32 core,
 					 u32 mdm);
 
diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c
index b9ad463..cc5aac7 100644
--- a/arch/arm/mach-omap2/cm33xx.c
+++ b/arch/arm/mach-omap2/cm33xx.c
@@ -72,27 +72,6 @@
 	return v;
 }
 
-static inline u32 am33xx_cm_set_reg_bits(u32 bits, s16 inst, s16 idx)
-{
-	return am33xx_cm_rmw_reg_bits(bits, bits, inst, idx);
-}
-
-static inline u32 am33xx_cm_clear_reg_bits(u32 bits, s16 inst, s16 idx)
-{
-	return am33xx_cm_rmw_reg_bits(bits, 0x0, inst, idx);
-}
-
-static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
-{
-	u32 v;
-
-	v = am33xx_cm_read_reg(inst, idx);
-	v &= mask;
-	v >>= __ffs(mask);
-
-	return v;
-}
-
 /**
  * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
  * @inst: CM instance register offset (*_INST macro)
diff --git a/arch/arm/mach-omap2/cm81xx.h b/arch/arm/mach-omap2/cm81xx.h
new file mode 100644
index 0000000..45cb407
--- /dev/null
+++ b/arch/arm/mach-omap2/cm81xx.h
@@ -0,0 +1,61 @@
+/*
+ * Clock domain register offsets for TI81XX.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
+ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CM_TI81XX_H
+#define __ARCH_ARM_MACH_OMAP2_CM_TI81XX_H
+
+/* TI81XX common CM module offsets */
+#define TI81XX_CM_ALWON_MOD			0x1400	/* 1KB */
+
+/* TI816X CM module offsets */
+#define TI816X_CM_ACTIVE_MOD			0x0400	/* 256B */
+#define TI816X_CM_DEFAULT_MOD			0x0500	/* 256B */
+#define TI816X_CM_IVAHD0_MOD			0x0600	/* 256B */
+#define TI816X_CM_IVAHD1_MOD			0x0700	/* 256B */
+#define TI816X_CM_IVAHD2_MOD			0x0800	/* 256B */
+#define TI816X_CM_SGX_MOD			0x0900	/* 256B */
+
+/* ALWON */
+#define TI81XX_CM_ALWON_L3_SLOW_CLKDM		0x0000
+#define TI81XX_CM_ALWON_L3_MED_CLKDM		0x0004
+#define TI81XX_CM_ETHERNET_CLKDM		0x0004
+#define TI81XX_CM_MMU_CLKDM			0x000C
+#define TI81XX_CM_MMUCFG_CLKDM			0x0010
+#define TI81XX_CM_ALWON_MPU_CLKDM		0x001C
+#define TI81XX_CM_ALWON_L3_FAST_CLKDM		0x0030
+
+/* ACTIVE */
+#define TI816X_CM_ACTIVE_GEM_CLKDM		0x0000
+
+/* IVAHD0 */
+#define TI816X_CM_IVAHD0_CLKDM			0x0000
+
+/* IVAHD1 */
+#define TI816X_CM_IVAHD1_CLKDM			0x0000
+
+/* IVAHD2 */
+#define TI816X_CM_IVAHD2_CLKDM			0x0000
+
+/* SGX */
+#define TI816X_CM_SGX_CLKDM			0x0000
+
+/* DEFAULT */
+#define TI816X_CM_DEFAULT_L3_MED_CLKDM		0x0004
+#define TI816X_CM_DEFAULT_PCI_CLKDM		0x0010
+#define TI816X_CM_DEFAULT_L3_SLOW_CLKDM		0x0014
+#define TI816X_CM_DEFAULT_DUCATI_CLKDM		0x0018
+
+#endif
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 3933b8a..46e2458 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -118,7 +118,8 @@
 void omap3_init_early(void);	/* Do not use this one */
 void am33xx_init_early(void);
 void am35xx_init_early(void);
-void ti81xx_init_early(void);
+void ti814x_init_early(void);
+void ti816x_init_early(void);
 void am33xx_init_early(void);
 void am43xx_init_early(void);
 void am43xx_init_late(void);
@@ -171,6 +172,14 @@
 }
 #endif
 
+#ifdef CONFIG_SOC_TI81XX
+void ti81xx_restart(enum reboot_mode mode, const char *cmd);
+#else
+static inline void ti81xx_restart(enum reboot_mode mode, const char *cmd)
+{
+}
+#endif
+
 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
 	defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX)
 void omap44xx_restart(enum reboot_mode mode, const char *cmd);
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index a80ac2d..b8a4871 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -53,6 +53,7 @@
 #define OMAP343X_CONTROL_GENERAL_WKUP	0xa60
 
 /* TI81XX spefic control submodules */
+#define TI81XX_CONTROL_DEVBOOT		0x040
 #define TI81XX_CONTROL_DEVCONF		0x600
 
 /* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
@@ -246,6 +247,9 @@
 #define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
 #define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
 
+/* TI81XX CONTROL_DEVBOOT register offsets */
+#define TI81XX_CONTROL_STATUS		(TI81XX_CONTROL_DEVBOOT + 0x000)
+
 /* TI81XX CONTROL_DEVCONF register offsets */
 #define TI81XX_CONTROL_DEVICE_ID	(TI81XX_CONTROL_DEVCONF + 0x000)
 
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 0e58e5a..fc71224 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -36,26 +36,6 @@
 /* Static rate multiplier for OMAP4 REGM4XEN clocks */
 #define OMAP4430_REGM4XEN_MULT				4
 
-/* Supported only on OMAP4 */
-int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk)
-{
-	u32 v;
-	u32 mask;
-
-	if (!clk || !clk->clksel_reg)
-		return -EINVAL;
-
-	mask = clk->flags & CLOCK_CLKOUTX2 ?
-			OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
-			OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
-
-	v = omap2_clk_readl(clk, clk->clksel_reg);
-	v &= mask;
-	v >>= __ffs(mask);
-
-	return v;
-}
-
 void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
 {
 	u32 v;
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index c25feba..2a2f4d5 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -56,6 +56,8 @@
 
 	if (cpu_is_omap24xx()) {
 		val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+	} else if (cpu_is_ti81xx()) {
+		val = omap_ctrl_readl(TI81XX_CONTROL_STATUS);
 	} else if (soc_is_am33xx() || soc_is_am43xx()) {
 		val = omap_ctrl_readl(AM33XX_CONTROL_STATUS);
 	} else if (cpu_is_omap34xx()) {
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index a1bd6af..e60780f 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -492,27 +492,6 @@
 		omap_clk_soc_init = am35xx_dt_clk_init;
 }
 
-void __init ti81xx_init_early(void)
-{
-	omap2_set_globals_tap(OMAP343X_CLASS,
-			      OMAP2_L4_IO_ADDRESS(TI81XX_TAP_BASE));
-	omap2_set_globals_control(OMAP2_L4_IO_ADDRESS(TI81XX_CTRL_BASE),
-				  NULL);
-	omap2_set_globals_prm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE));
-	omap2_set_globals_cm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE), NULL);
-	omap3xxx_check_revision();
-	ti81xx_check_features();
-	omap3xxx_voltagedomains_init();
-	omap3xxx_powerdomains_init();
-	omap3xxx_clockdomains_init();
-	omap3xxx_hwmod_init();
-	omap_hwmod_init_postsetup();
-	if (of_have_populated_dt())
-		omap_clk_soc_init = ti81xx_dt_clk_init;
-	else
-		omap_clk_soc_init = omap3xxx_clk_init;
-}
-
 void __init omap3_init_late(void)
 {
 	omap_common_late_init();
@@ -551,11 +530,54 @@
 void __init ti81xx_init_late(void)
 {
 	omap_common_late_init();
-	omap3_pm_init();
 	omap2_clk_enable_autoidle_all();
 }
 #endif
 
+#ifdef CONFIG_SOC_TI81XX
+void __init ti814x_init_early(void)
+{
+	omap2_set_globals_tap(TI814X_CLASS,
+			      OMAP2_L4_IO_ADDRESS(TI81XX_TAP_BASE));
+	omap2_set_globals_control(OMAP2_L4_IO_ADDRESS(TI81XX_CTRL_BASE),
+				  NULL);
+	omap2_set_globals_prm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE));
+	omap2_set_globals_cm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE), NULL);
+	omap3xxx_check_revision();
+	ti81xx_check_features();
+	am33xx_prm_init();
+	am33xx_cm_init();
+	omap3xxx_voltagedomains_init();
+	omap3xxx_powerdomains_init();
+	ti81xx_clockdomains_init();
+	ti81xx_hwmod_init();
+	omap_hwmod_init_postsetup();
+	if (of_have_populated_dt())
+		omap_clk_soc_init = ti81xx_dt_clk_init;
+}
+
+void __init ti816x_init_early(void)
+{
+	omap2_set_globals_tap(TI816X_CLASS,
+			      OMAP2_L4_IO_ADDRESS(TI81XX_TAP_BASE));
+	omap2_set_globals_control(OMAP2_L4_IO_ADDRESS(TI81XX_CTRL_BASE),
+				  NULL);
+	omap2_set_globals_prm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE));
+	omap2_set_globals_cm(OMAP2_L4_IO_ADDRESS(TI81XX_PRCM_BASE), NULL);
+	omap3xxx_check_revision();
+	ti81xx_check_features();
+	am33xx_prm_init();
+	am33xx_cm_init();
+	omap3xxx_voltagedomains_init();
+	omap3xxx_powerdomains_init();
+	ti81xx_clockdomains_init();
+	ti81xx_hwmod_init();
+	omap_hwmod_init_postsetup();
+	if (of_have_populated_dt())
+		omap_clk_soc_init = ti81xx_dt_clk_init;
+}
+#endif
+
 #ifdef CONFIG_SOC_AM33XX
 void __init am33xx_init_early(void)
 {
diff --git a/arch/arm/mach-omap2/omap-pm-noop.c b/arch/arm/mach-omap2/omap-pm-noop.c
index 6a3be2b..a1ee806 100644
--- a/arch/arm/mach-omap2/omap-pm-noop.c
+++ b/arch/arm/mach-omap2/omap-pm-noop.c
@@ -86,200 +86,10 @@
 	return 0;
 }
 
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
-				   long t)
-{
-	if (!req_dev || !dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
-		return -EINVAL;
-	}
-
-	if (t == -1)
-		pr_debug("OMAP PM: remove max device latency constraint: dev %s\n",
-			 dev_name(dev));
-	else
-		pr_debug("OMAP PM: add max device latency constraint: dev %s, t = %ld usec\n",
-			 dev_name(dev), t);
-
-	/*
-	 * For current Linux, this needs to map the device to a
-	 * powerdomain, then go through the list of current max lat
-	 * constraints on that powerdomain and find the smallest.  If
-	 * the latency constraint has changed, the code should
-	 * recompute the state to enter for the next powerdomain
-	 * state.  Conceivably, this code should also determine
-	 * whether to actually disable the device clocks or not,
-	 * depending on how long it takes to re-enable the clocks.
-	 *
-	 * TI CDP code can call constraint_set here.
-	 */
-
-	return 0;
-}
-
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
-{
-	if (!dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
-		return -EINVAL;
-	}
-
-	if (t == -1)
-		pr_debug("OMAP PM: remove max DMA latency constraint: dev %s\n",
-			 dev_name(dev));
-	else
-		pr_debug("OMAP PM: add max DMA latency constraint: dev %s, t = %ld usec\n",
-			 dev_name(dev), t);
-
-	/*
-	 * For current Linux PM QOS params, this code should scan the
-	 * list of maximum CPU and DMA latencies and select the
-	 * smallest, then set cpu_dma_latency pm_qos_param
-	 * accordingly.
-	 *
-	 * For future Linux PM QOS params, with separate CPU and DMA
-	 * latency params, this code should just set the dma_latency param.
-	 *
-	 * TI CDP code can call constraint_set here.
-	 */
-
-	return 0;
-}
-
-int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
-{
-	if (!dev || !c || r < 0) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
-		return -EINVAL;
-	}
-
-	if (r == 0)
-		pr_debug("OMAP PM: remove min clk rate constraint: dev %s\n",
-			 dev_name(dev));
-	else
-		pr_debug("OMAP PM: add min clk rate constraint: dev %s, rate = %ld Hz\n",
-			 dev_name(dev), r);
-
-	/*
-	 * Code in a real implementation should keep track of these
-	 * constraints on the clock, and determine the highest minimum
-	 * clock rate.  It should iterate over each OPP and determine
-	 * whether the OPP will result in a clock rate that would
-	 * satisfy this constraint (and any other PM constraint in effect
-	 * at that time).  Once it finds the lowest-voltage OPP that
-	 * meets those conditions, it should switch to it, or return
-	 * an error if the code is not capable of doing so.
-	 */
-
-	return 0;
-}
-
 /*
  * DSP Bridge-specific constraints
  */
 
-const struct omap_opp *omap_pm_dsp_get_opp_table(void)
-{
-	pr_debug("OMAP PM: DSP request for OPP table\n");
-
-	/*
-	 * Return DSP frequency table here:  The final item in the
-	 * array should have .rate = .opp_id = 0.
-	 */
-
-	return NULL;
-}
-
-void omap_pm_dsp_set_min_opp(u8 opp_id)
-{
-	if (opp_id == 0) {
-		WARN_ON(1);
-		return;
-	}
-
-	pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
-
-	/*
-	 *
-	 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
-	 * can just test to see which is higher, the CPU's desired OPP
-	 * ID or the DSP's desired OPP ID, and use whichever is
-	 * highest.
-	 *
-	 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
-	 * rate is keyed on MPU speed, not the OPP ID.  So we need to
-	 * map the OPP ID to the MPU speed for use with clk_set_rate()
-	 * if it is higher than the current OPP clock rate.
-	 *
-	 */
-}
-
-
-u8 omap_pm_dsp_get_opp(void)
-{
-	pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
-
-	/*
-	 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
-	 *
-	 * CDP12.14+:
-	 * Call clk_get_rate() on the OPP custom clock, map that to an
-	 * OPP ID using the tables defined in board-*.c/chip-*.c files.
-	 */
-
-	return 0;
-}
-
-/*
- * CPUFreq-originated constraint
- *
- * In the future, this should be handled by custom OPP clocktype
- * functions.
- */
-
-struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void)
-{
-	pr_debug("OMAP PM: CPUFreq request for frequency table\n");
-
-	/*
-	 * Return CPUFreq frequency table here: loop over
-	 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
-	 * table
-	 */
-
-	return NULL;
-}
-
-void omap_pm_cpu_set_freq(unsigned long f)
-{
-	if (f == 0) {
-		WARN_ON(1);
-		return;
-	}
-
-	pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
-		 f);
-
-	/*
-	 * For l-o dev tree, determine whether MPU freq or DSP OPP id
-	 * freq is higher.  Find the OPP ID corresponding to the
-	 * higher frequency.  Call clk_round_rate() and clk_set_rate()
-	 * on the OPP custom clock.
-	 *
-	 * CDP should just be able to set the VDD1 OPP clock rate here.
-	 */
-}
-
-unsigned long omap_pm_cpu_get_freq(void)
-{
-	pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
-
-	/*
-	 * Call clk_get_rate() on the mpu_ck.
-	 */
-
-	return 0;
-}
 
 /**
  * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
@@ -363,9 +173,3 @@
 {
 	return 0;
 }
-
-void omap_pm_if_exit(void)
-{
-	/* Deallocate CPUFreq frequency table here */
-}
-
diff --git a/arch/arm/mach-omap2/omap-pm.h b/arch/arm/mach-omap2/omap-pm.h
index 1d777e6..109bef5 100644
--- a/arch/arm/mach-omap2/omap-pm.h
+++ b/arch/arm/mach-omap2/omap-pm.h
@@ -50,14 +50,6 @@
  */
 int __init omap_pm_if_init(void);
 
-/**
- * omap_pm_if_exit - OMAP PM exit code
- *
- * Exit code; currently unused.  The "_if_" is to avoid name
- * collisions with the PM idle-loop code.
- */
-void omap_pm_if_exit(void);
-
 /*
  * Device-driver-originated constraints (via board-*.c files, platform_data)
  */
@@ -132,163 +124,6 @@
 int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r);
 
 
-/**
- * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency
- * @req_dev: struct device * requesting the constraint, or NULL if none
- * @dev: struct device * to set the constraint one
- * @t: maximum device wakeup latency in microseconds
- *
- * Request that the maximum amount of time necessary for a device @dev
- * to become accessible after its clocks are enabled should be no
- * greater than @t microseconds.  Specifically, this represents the
- * time from when a device driver enables device clocks with
- * clk_enable(), to when the register reads and writes on the device
- * will succeed.  This function should be called before clk_disable()
- * is called, since the power state transition decision may be made
- * during clk_disable().
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the powerdomain enclosing this
- * device into.
- *
- * Multiple calls to omap_pm_set_max_dev_wakeup_lat() will replace the
- * previous wakeup latency values for this device.  To remove the
- * wakeup latency restriction for this device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
-				   long t);
-
-
-/**
- * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency
- * @dev: struct device *
- * @t: maximum DMA transfer start latency in microseconds
- *
- * Request that the maximum system DMA transfer start latency for this
- * device 'dev' should be no greater than 't' microseconds.  "DMA
- * transfer start latency" here is defined as the elapsed time from
- * when a device (e.g., McBSP) requests that a system DMA transfer
- * start or continue, to the time at which data starts to flow into
- * that device from the system DMA controller.
- *
- * It is intended that underlying PM code will use this information to
- * determine what power state to put the CORE powerdomain into.
- *
- * Since system DMA transfers may not involve the MPU, this function
- * will not affect MPU wakeup latency.  Use set_max_cpu_lat() to do
- * so.  Similarly, this function will not affect device wakeup latency
- * -- use set_max_dev_wakeup_lat() to affect that.
- *
- * Multiple calls to set_max_sdma_lat() will replace the previous t
- * value for this device.  To remove the maximum DMA latency for this
- * device, call with t = -1.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_max_sdma_lat(struct device *dev, long t);
-
-
-/**
- * omap_pm_set_min_clk_rate - set minimum clock rate requested by @dev
- * @dev: struct device * requesting the constraint
- * @clk: struct clk * to set the minimum rate constraint on
- * @r: minimum rate in Hz
- *
- * Request that the minimum clock rate on the device @dev's clk @clk
- * be no less than @r Hz.
- *
- * It is expected that the OMAP PM code will use this information to
- * find an OPP or clock setting that will satisfy this clock rate
- * constraint, along with any other applicable system constraints on
- * the clock rate or corresponding voltage, etc.
- *
- * omap_pm_set_min_clk_rate() differs from the clock code's
- * clk_set_rate() in that it considers other constraints before taking
- * any hardware action, and may change a system OPP rather than just a
- * clock rate.  clk_set_rate() is intended to be a low-level
- * interface.
- *
- * omap_pm_set_min_clk_rate() is easily open to abuse.  A better API
- * would be something like "omap_pm_set_min_dev_performance()";
- * however, there is no easily-generalizable concept of performance
- * that applies to all devices.  Only a device (and possibly the
- * device subsystem) has both the subsystem-specific knowledge, and
- * the hardware IP block-specific knowledge, to translate a constraint
- * on "touchscreen sampling accuracy" or "number of pixels or polygons
- * rendered per second" to a clock rate.  This translation can be
- * dependent on the hardware IP block's revision, or firmware version,
- * and the driver is the only code on the system that has this
- * information and can know how to translate that into a clock rate.
- *
- * The intended use-case for this function is for userspace or other
- * kernel code to communicate a particular performance requirement to
- * a subsystem; then for the subsystem to communicate that requirement
- * to something that is meaningful to the device driver; then for the
- * device driver to convert that requirement to a clock rate, and to
- * then call omap_pm_set_min_clk_rate().
- *
- * Users of this function (such as device drivers) should not simply
- * call this function with some high clock rate to ensure "high
- * performance."  Rather, the device driver should take a performance
- * constraint from its subsystem, such as "render at least X polygons
- * per second," and use some formula or table to convert that into a
- * clock rate constraint given the hardware type and hardware
- * revision.  Device drivers or subsystems should not assume that they
- * know how to make a power/performance tradeoff - some device use
- * cases may tolerate a lower-fidelity device function for lower power
- * consumption; others may demand a higher-fidelity device function,
- * no matter what the power consumption.
- *
- * Multiple calls to omap_pm_set_min_clk_rate() will replace the
- * previous rate value for the device @dev.  To remove the minimum clock
- * rate constraint for the device, call with r = 0.
- *
- * Returns -EINVAL for an invalid argument, -ERANGE if the constraint
- * is not satisfiable, or 0 upon success.
- */
-int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r);
-
-/*
- * DSP Bridge-specific constraints
- */
-
-/**
- * omap_pm_dsp_get_opp_table - get OPP->DSP clock frequency table
- *
- * Intended for use by DSPBridge.  Returns an array of OPP->DSP clock
- * frequency entries.  The final item in the array should have .rate =
- * .opp_id = 0.
- */
-const struct omap_opp *omap_pm_dsp_get_opp_table(void);
-
-/**
- * omap_pm_dsp_set_min_opp - receive desired OPP target ID from DSP Bridge
- * @opp_id: target DSP OPP ID
- *
- * Set a minimum OPP ID for the DSP.  This is intended to be called
- * only from the DSP Bridge MPU-side driver.  Unfortunately, the only
- * information that code receives from the DSP/BIOS load estimator is the
- * target OPP ID; hence, this interface.  No return value.
- */
-void omap_pm_dsp_set_min_opp(u8 opp_id);
-
-/**
- * omap_pm_dsp_get_opp - report the current DSP OPP ID
- *
- * Report the current OPP for the DSP.  Since on OMAP3, the DSP and
- * MPU share a single voltage domain, the OPP ID returned back may
- * represent a higher DSP speed than the OPP requested via
- * omap_pm_dsp_set_min_opp().
- *
- * Returns the current VDD1 OPP ID, or 0 upon error.
- */
-u8 omap_pm_dsp_get_opp(void);
-
-
 /*
  * CPUFreq-originated constraint
  *
@@ -296,33 +131,6 @@
  * functions.
  */
 
-/**
- * omap_pm_cpu_get_freq_table - return a cpufreq_frequency_table array ptr
- *
- * Provide a frequency table usable by CPUFreq for the current chip/board.
- * Returns a pointer to a struct cpufreq_frequency_table array or NULL
- * upon error.
- */
-struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void);
-
-/**
- * omap_pm_cpu_set_freq - set the current minimum MPU frequency
- * @f: MPU frequency in Hz
- *
- * Set the current minimum CPU frequency.  The actual CPU frequency
- * used could end up higher if the DSP requested a higher OPP.
- * Intended to be called by plat-omap/cpu_omap.c:omap_target().  No
- * return value.
- */
-void omap_pm_cpu_set_freq(unsigned long f);
-
-/**
- * omap_pm_cpu_get_freq - report the current CPU frequency
- *
- * Returns the current MPU frequency, or 0 upon error.
- */
-unsigned long omap_pm_cpu_get_freq(void);
-
 
 /*
  * Device context loss tracking
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 9025fff..92afb72 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2155,8 +2155,8 @@
 		if (soc_ops.disable_module)
 			soc_ops.disable_module(oh);
 		_disable_clocks(oh);
-		pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
-			 oh->name, r);
+		pr_err("omap_hwmod: %s: _wait_target_ready failed: %d\n",
+		       oh->name, r);
 
 		if (oh->clkdm)
 			clkdm_hwmod_disable(oh->clkdm, oh);
@@ -3384,91 +3384,6 @@
 	return 0;
 }
 
-/**
- * omap_hwmod_enable_clocks - enable main_clk, all interface clocks
- * @oh: struct omap_hwmod *oh
- *
- * Intended to be called by the omap_device code.
- */
-int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&oh->_lock, flags);
-	_enable_clocks(oh);
-	spin_unlock_irqrestore(&oh->_lock, flags);
-
-	return 0;
-}
-
-/**
- * omap_hwmod_disable_clocks - disable main_clk, all interface clocks
- * @oh: struct omap_hwmod *oh
- *
- * Intended to be called by the omap_device code.
- */
-int omap_hwmod_disable_clocks(struct omap_hwmod *oh)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&oh->_lock, flags);
-	_disable_clocks(oh);
-	spin_unlock_irqrestore(&oh->_lock, flags);
-
-	return 0;
-}
-
-/**
- * omap_hwmod_ocp_barrier - wait for posted writes against the hwmod to complete
- * @oh: struct omap_hwmod *oh
- *
- * Intended to be called by drivers and core code when all posted
- * writes to a device must complete before continuing further
- * execution (for example, after clearing some device IRQSTATUS
- * register bits)
- *
- * XXX what about targets with multiple OCP threads?
- */
-void omap_hwmod_ocp_barrier(struct omap_hwmod *oh)
-{
-	BUG_ON(!oh);
-
-	if (!oh->class->sysc || !oh->class->sysc->sysc_flags) {
-		WARN(1, "omap_device: %s: OCP barrier impossible due to device configuration\n",
-			oh->name);
-		return;
-	}
-
-	/*
-	 * Forces posted writes to complete on the OCP thread handling
-	 * register writes
-	 */
-	omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
-}
-
-/**
- * omap_hwmod_reset - reset the hwmod
- * @oh: struct omap_hwmod *
- *
- * Under some conditions, a driver may wish to reset the entire device.
- * Called from omap_device code.  Returns -EINVAL on error or passes along
- * the return value from _reset().
- */
-int omap_hwmod_reset(struct omap_hwmod *oh)
-{
-	int r;
-	unsigned long flags;
-
-	if (!oh)
-		return -EINVAL;
-
-	spin_lock_irqsave(&oh->_lock, flags);
-	r = _reset(oh);
-	spin_unlock_irqrestore(&oh->_lock, flags);
-
-	return r;
-}
-
 /*
  * IP block data retrieval functions
  */
@@ -3729,52 +3644,12 @@
 	return oh->_mpu_rt_va;
 }
 
-/**
- * omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh
- * @oh: struct omap_hwmod *
- * @init_oh: struct omap_hwmod * (initiator)
- *
- * Add a sleep dependency between the initiator @init_oh and @oh.
- * Intended to be called by DSP/Bridge code via platform_data for the
- * DSP case; and by the DMA code in the sDMA case.  DMA code, *Bridge
- * code needs to add/del initiator dependencies dynamically
- * before/after accessing a device.  Returns the return value from
- * _add_initiator_dep().
- *
- * XXX Keep a usecount in the clockdomain code
- */
-int omap_hwmod_add_initiator_dep(struct omap_hwmod *oh,
-				 struct omap_hwmod *init_oh)
-{
-	return _add_initiator_dep(oh, init_oh);
-}
-
 /*
  * XXX what about functions for drivers to save/restore ocp_sysconfig
  * for context save/restore operations?
  */
 
 /**
- * omap_hwmod_del_initiator_dep - remove sleepdep from @init_oh to @oh
- * @oh: struct omap_hwmod *
- * @init_oh: struct omap_hwmod * (initiator)
- *
- * Remove a sleep dependency between the initiator @init_oh and @oh.
- * Intended to be called by DSP/Bridge code via platform_data for the
- * DSP case; and by the DMA code in the sDMA case.  DMA code, *Bridge
- * code needs to add/del initiator dependencies dynamically
- * before/after accessing a device.  Returns the return value from
- * _del_initiator_dep().
- *
- * XXX Keep a usecount in the clockdomain code
- */
-int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
-				 struct omap_hwmod *init_oh)
-{
-	return _del_initiator_dep(oh, init_oh);
-}
-
-/**
  * omap_hwmod_enable_wakeup - allow device to wake up the system
  * @oh: struct omap_hwmod *
  *
@@ -3895,33 +3770,6 @@
 }
 
 /**
- * omap_hwmod_read_hardreset - read the HW reset line state of submodules
- * contained in the hwmod module
- * @oh: struct omap_hwmod *
- * @name: name of the reset line to look up and read
- *
- * Return the current state of the hwmod @oh's reset line named @name:
- * returns -EINVAL upon parameter error or if this operation
- * is unsupported on the current OMAP; otherwise, passes along the return
- * value from _read_hardreset().
- */
-int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name)
-{
-	int ret;
-	unsigned long flags;
-
-	if (!oh)
-		return -EINVAL;
-
-	spin_lock_irqsave(&oh->_lock, flags);
-	ret = _read_hardreset(oh, name);
-	spin_unlock_irqrestore(&oh->_lock, flags);
-
-	return ret;
-}
-
-
-/**
  * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
  * @classname: struct omap_hwmod_class name to search for
  * @fn: callback function pointer to call for each hwmod in class @classname
@@ -4031,86 +3879,6 @@
 }
 
 /**
- * omap_hwmod_no_setup_reset - prevent a hwmod from being reset upon setup
- * @oh: struct omap_hwmod *
- *
- * Prevent the hwmod @oh from being reset during the setup process.
- * Intended for use by board-*.c files on boards with devices that
- * cannot tolerate being reset.  Must be called before the hwmod has
- * been set up.  Returns 0 upon success or negative error code upon
- * failure.
- */
-int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
-{
-	if (!oh)
-		return -EINVAL;
-
-	if (oh->_state != _HWMOD_STATE_REGISTERED) {
-		pr_err("omap_hwmod: %s: cannot prevent setup reset; in wrong state\n",
-			oh->name);
-		return -EINVAL;
-	}
-
-	oh->flags |= HWMOD_INIT_NO_RESET;
-
-	return 0;
-}
-
-/**
- * omap_hwmod_pad_route_irq - route an I/O pad wakeup to a particular MPU IRQ
- * @oh: struct omap_hwmod * containing hwmod mux entries
- * @pad_idx: array index in oh->mux of the hwmod mux entry to route wakeup
- * @irq_idx: the hwmod mpu_irqs array index of the IRQ to trigger on wakeup
- *
- * When an I/O pad wakeup arrives for the dynamic or wakeup hwmod mux
- * entry number @pad_idx for the hwmod @oh, trigger the interrupt
- * service routine for the hwmod's mpu_irqs array index @irq_idx.  If
- * this function is not called for a given pad_idx, then the ISR
- * associated with @oh's first MPU IRQ will be triggered when an I/O
- * pad wakeup occurs on that pad.  Note that @pad_idx is the index of
- * the _dynamic or wakeup_ entry: if there are other entries not
- * marked with OMAP_DEVICE_PAD_WAKEUP or OMAP_DEVICE_PAD_REMUX, these
- * entries are NOT COUNTED in the dynamic pad index.  This function
- * must be called separately for each pad that requires its interrupt
- * to be re-routed this way.  Returns -EINVAL if there is an argument
- * problem or if @oh does not have hwmod mux entries or MPU IRQs;
- * returns -ENOMEM if memory cannot be allocated; or 0 upon success.
- *
- * XXX This function interface is fragile.  Rather than using array
- * indexes, which are subject to unpredictable change, it should be
- * using hwmod IRQ names, and some other stable key for the hwmod mux
- * pad records.
- */
-int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
-{
-	int nr_irqs;
-
-	might_sleep();
-
-	if (!oh || !oh->mux || !oh->mpu_irqs || pad_idx < 0 ||
-	    pad_idx >= oh->mux->nr_pads_dynamic)
-		return -EINVAL;
-
-	/* Check the number of available mpu_irqs */
-	for (nr_irqs = 0; oh->mpu_irqs[nr_irqs].irq >= 0; nr_irqs++)
-		;
-
-	if (irq_idx >= nr_irqs)
-		return -EINVAL;
-
-	if (!oh->mux->irqs) {
-		/* XXX What frees this? */
-		oh->mux->irqs = kzalloc(sizeof(int) * oh->mux->nr_pads_dynamic,
-			GFP_KERNEL);
-		if (!oh->mux->irqs)
-			return -ENOMEM;
-	}
-	oh->mux->irqs[pad_idx] = irq_idx;
-
-	return 0;
-}
-
-/**
  * omap_hwmod_init - initialize the hwmod code
  *
  * Sets up some function pointers needed by the hwmod code to operate on the
@@ -4148,7 +3916,7 @@
 		soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
 		soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
 		soc_ops.init_clkdm = _init_clkdm;
-	} else if (soc_is_am33xx()) {
+	} else if (cpu_is_ti816x() || soc_is_am33xx()) {
 		soc_ops.enable_module = _omap4_enable_module;
 		soc_ops.disable_module = _omap4_disable_module;
 		soc_ops.wait_target_ready = _omap4_wait_target_ready;
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 5b42faf..9d4bec6e 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -703,13 +703,6 @@
 
 int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name);
 int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name);
-int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name);
-
-int omap_hwmod_enable_clocks(struct omap_hwmod *oh);
-int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
-
-int omap_hwmod_reset(struct omap_hwmod *oh);
-void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
 void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs);
 u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs);
@@ -724,11 +717,6 @@
 struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh);
 void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh);
 
-int omap_hwmod_add_initiator_dep(struct omap_hwmod *oh,
-				 struct omap_hwmod *init_oh);
-int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
-				 struct omap_hwmod *init_oh);
-
 int omap_hwmod_enable_wakeup(struct omap_hwmod *oh);
 int omap_hwmod_disable_wakeup(struct omap_hwmod *oh);
 
@@ -740,10 +728,6 @@
 int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
 int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
-int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
-
-int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx);
-
 extern void __init omap_hwmod_init(void);
 
 const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh);
@@ -764,6 +748,7 @@
 extern int omap44xx_hwmod_init(void);
 extern int omap54xx_hwmod_init(void);
 extern int am33xx_hwmod_init(void);
+extern int ti81xx_hwmod_init(void);
 extern int dra7xx_hwmod_init(void);
 int am43xx_hwmod_init(void);
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 11468ee..4e8e93c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -29,8 +29,6 @@
 #include <linux/platform_data/mailbox-omap.h>
 #include <plat/dmtimer.h>
 
-#include "am35xx.h"
-
 #include "soc.h"
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
@@ -50,6 +48,8 @@
  * elsewhere.
  */
 
+#define AM35XX_IPSS_USBOTGSS_BASE      0x5C040000
+
 /*
  * IP blocks
  */
@@ -3459,15 +3459,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_addr_space am35xx_mdio_addrs[] = {
-	{
-		.pa_start	= AM35XX_IPSS_MDIO_BASE,
-		.pa_end		= AM35XX_IPSS_MDIO_BASE + SZ_4K - 1,
-		.flags		= ADDR_TYPE_RT,
-	},
-	{ }
-};
-
 /* l4_core -> davinci mdio  */
 /*
  * XXX Should be connected to an IPSS hwmod, not the L4_CORE directly;
@@ -3478,25 +3469,15 @@
 	.master		= &omap3xxx_l4_core_hwmod,
 	.slave		= &am35xx_mdio_hwmod,
 	.clk		= "emac_fck",
-	.addr		= am35xx_mdio_addrs,
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_irq_info am35xx_emac_mpu_irqs[] = {
-	{ .name = "rxthresh",	.irq = 67 + OMAP_INTC_START, },
-	{ .name = "rx_pulse",	.irq = 68 + OMAP_INTC_START, },
-	{ .name = "tx_pulse",	.irq = 69 + OMAP_INTC_START },
-	{ .name = "misc_pulse",	.irq = 70 + OMAP_INTC_START },
-	{ .irq = -1 },
-};
-
 static struct omap_hwmod_class am35xx_emac_class = {
 	.name = "davinci_emac",
 };
 
 static struct omap_hwmod am35xx_emac_hwmod = {
 	.name		= "davinci_emac",
-	.mpu_irqs	= am35xx_emac_mpu_irqs,
 	.class		= &am35xx_emac_class,
 	/*
 	 * According to Mark Greer, the MPU will not return from WFI
@@ -3519,15 +3500,6 @@
 	.user		= OCP_USER_MPU,
 };
 
-static struct omap_hwmod_addr_space am35xx_emac_addrs[] = {
-	{
-		.pa_start	= AM35XX_IPSS_EMAC_BASE,
-		.pa_end		= AM35XX_IPSS_EMAC_BASE + 0x30000 - 1,
-		.flags		= ADDR_TYPE_RT,
-	},
-	{ }
-};
-
 /* l4_core -> davinci emac  */
 /*
  * XXX Should be connected to an IPSS hwmod, not the L4_CORE directly;
@@ -3538,7 +3510,6 @@
 	.master		= &omap3xxx_l4_core_hwmod,
 	.slave		= &am35xx_emac_hwmod,
 	.clk		= "emac_ick",
-	.addr		= am35xx_emac_addrs,
 	.user		= OCP_USER_MPU,
 };
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
index 5c6c841..8eb8592 100644
--- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
@@ -498,6 +498,7 @@
 		},
 	},
 	.dev_attr	= &am43xx_dss_dispc_dev_attr,
+	.parent_hwmod	= &am43xx_dss_core_hwmod,
 };
 
 /* rfbi */
@@ -512,6 +513,7 @@
 			.clkctrl_offs = AM43XX_CM_PER_DSS_CLKCTRL_OFFSET,
 		},
 	},
+	.parent_hwmod	= &am43xx_dss_core_hwmod,
 };
 
 /* Interfaces */
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index ffd6604..e8692e7 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -819,7 +819,8 @@
 	.name		= "gpmc",
 	.class		= &dra7xx_gpmc_hwmod_class,
 	.clkdm_name	= "l3main1_clkdm",
-	.flags		= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
+			   HWMOD_SWSUP_SIDLE),
 	.main_clk	= "l3_iclk_div",
 	.prcm = {
 		.omap4 = {
@@ -2017,7 +2018,7 @@
 	.class		= &dra7xx_uart_hwmod_class,
 	.clkdm_name	= "l4per_clkdm",
 	.main_clk	= "uart3_gfclk_mux",
-	.flags		= HWMOD_SWSUP_SIDLE_ACT,
+	.flags		= HWMOD_SWSUP_SIDLE_ACT | DEBUG_OMAP4UART3_FLAGS,
 	.prcm = {
 		.omap4 = {
 			.clkctrl_offs = DRA7XX_CM_L4PER_UART3_CLKCTRL_OFFSET,
diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
new file mode 100644
index 0000000..cab1eb6
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
@@ -0,0 +1,1136 @@
+/*
+ * DM81xx hwmod data.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
+ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_data/gpio-omap.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"
+#include "ti81xx.h"
+#include "wd_timer.h"
+
+/*
+ * DM816X hardware modules integration data
+ *
+ * Note: This is incomplete and at present, not generated from h/w database.
+ */
+
+/*
+ * The alwon .clkctrl_offs field is offset from the CM_ALWON, that's
+ * TRM 18.7.17 CM_ALWON device register values minus 0x1400.
+ */
+#define DM816X_DM_ALWON_BASE		0x1400
+#define DM816X_CM_ALWON_MCASP0_CLKCTRL	(0x1540 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MCASP1_CLKCTRL	(0x1544 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MCASP2_CLKCTRL	(0x1548 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MCBSP_CLKCTRL	(0x154c - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_UART_0_CLKCTRL	(0x1550 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_UART_1_CLKCTRL	(0x1554 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_UART_2_CLKCTRL	(0x1558 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_GPIO_0_CLKCTRL	(0x155c - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_GPIO_1_CLKCTRL	(0x1560 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_I2C_0_CLKCTRL	(0x1564 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_I2C_1_CLKCTRL	(0x1568 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_1_CLKCTRL	(0x1570 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_2_CLKCTRL	(0x1574 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_3_CLKCTRL	(0x1578 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_4_CLKCTRL	(0x157c - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_5_CLKCTRL	(0x1580 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_6_CLKCTRL	(0x1584 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TIMER_7_CLKCTRL	(0x1588 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_WDTIMER_CLKCTRL	(0x158c - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_SPI_CLKCTRL	(0x1590 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MAILBOX_CLKCTRL	(0x1594 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_SPINBOX_CLKCTRL	(0x1598 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MMUDATA_CLKCTRL	(0x159c - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MMUCFG_CLKCTRL	(0x15a8 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_SDIO_CLKCTRL	(0x15b0 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_OCMC_0_CLKCTRL	(0x15b4 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_OCMC_1_CLKCTRL	(0x15b8 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_CONTRL_CLKCTRL	(0x15c4 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_GPMC_CLKCTRL	(0x15d0 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_ETHERNET_0_CLKCTRL (0x15d4 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_ETHERNET_1_CLKCTRL (0x15d8 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_MPU_CLKCTRL	(0x15dc - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_L3_CLKCTRL	(0x15e4 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_L4HS_CLKCTRL	(0x15e8 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_L4LS_CLKCTRL	(0x15ec - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_RTC_CLKCTRL	(0x15f0 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TPCC_CLKCTRL	(0x15f4 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TPTC0_CLKCTRL	(0x15f8 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TPTC1_CLKCTRL	(0x15fc - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TPTC2_CLKCTRL	(0x1600 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_TPTC3_CLKCTRL	(0x1604 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_SR_0_CLKCTRL	(0x1608 - DM816X_DM_ALWON_BASE)
+#define DM816X_CM_ALWON_SR_1_CLKCTRL	(0x160c - DM816X_DM_ALWON_BASE)
+
+/*
+ * The default .clkctrl_offs field is offset from CM_DEFAULT, that's
+ * TRM 18.7.6 CM_DEFAULT device register values minus 0x500
+ */
+#define DM816X_CM_DEFAULT_OFFSET	0x500
+#define DM816X_CM_DEFAULT_USB_CLKCTRL	(0x558 - DM816X_CM_DEFAULT_OFFSET)
+
+/* L3 Interconnect entries clocked at 125, 250 and 500MHz */
+static struct omap_hwmod dm816x_alwon_l3_slow_hwmod = {
+	.name		= "alwon_l3_slow",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &l3_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod dm816x_default_l3_slow_hwmod = {
+	.name		= "default_l3_slow",
+	.clkdm_name	= "default_l3_slow_clkdm",
+	.class		= &l3_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod dm816x_alwon_l3_med_hwmod = {
+	.name		= "l3_med",
+	.clkdm_name	= "alwon_l3_med_clkdm",
+	.class		= &l3_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod dm816x_alwon_l3_fast_hwmod = {
+	.name		= "l3_fast",
+	.clkdm_name	= "alwon_l3_fast_clkdm",
+	.class		= &l3_hwmod_class,
+	.flags		= HWMOD_NO_IDLEST,
+};
+
+/*
+ * L4 standard peripherals, see TRM table 1-12 for devices using this.
+ * See TRM table 1-73 for devices using the 125MHz SYSCLK6 clock.
+ */
+static struct omap_hwmod dm816x_l4_ls_hwmod = {
+	.name		= "l4_ls",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &l4_hwmod_class,
+};
+
+/*
+ * L4 high-speed peripherals. For devices using this, please see the TRM
+ * table 1-13. On dm816x, only EMAC, MDIO and SATA use this. See also TRM
+ * table 1-73 for devices using 250MHz SYSCLK5 clock.
+ */
+static struct omap_hwmod dm816x_l4_hs_hwmod = {
+	.name		= "l4_hs",
+	.clkdm_name	= "alwon_l3_med_clkdm",
+	.class		= &l4_hwmod_class,
+};
+
+/* L3 slow -> L4 ls peripheral interface running at 125MHz */
+static struct omap_hwmod_ocp_if dm816x_alwon_l3_slow__l4_ls = {
+	.master	= &dm816x_alwon_l3_slow_hwmod,
+	.slave	= &dm816x_l4_ls_hwmod,
+	.user	= OCP_USER_MPU,
+};
+
+/* L3 med -> L4 fast peripheral interface running at 250MHz */
+static struct omap_hwmod_ocp_if dm816x_alwon_l3_slow__l4_hs = {
+	.master	= &dm816x_alwon_l3_med_hwmod,
+	.slave	= &dm816x_l4_hs_hwmod,
+	.user	= OCP_USER_MPU,
+};
+
+/* MPU */
+static struct omap_hwmod dm816x_mpu_hwmod = {
+	.name		= "mpu",
+	.clkdm_name	= "alwon_mpu_clkdm",
+	.class		= &mpu_hwmod_class,
+	.flags		= HWMOD_INIT_NO_IDLE,
+	.main_clk	= "mpu_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_MPU_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_ocp_if dm816x_mpu__alwon_l3_slow = {
+	.master		= &dm816x_mpu_hwmod,
+	.slave		= &dm816x_alwon_l3_slow_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+/* L3 med peripheral interface running at 250MHz */
+static struct omap_hwmod_ocp_if dm816x_mpu__alwon_l3_med = {
+	.master	= &dm816x_mpu_hwmod,
+	.slave	= &dm816x_alwon_l3_med_hwmod,
+	.user	= OCP_USER_MPU,
+};
+
+/* UART common */
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+				SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+				MSTANDBY_SMART_WKUP,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+static struct omap_hwmod dm816x_uart1_hwmod = {
+	.name		= "uart1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_UART_0_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &uart_class,
+	.flags		= DEBUG_TI81XXUART1_FLAGS,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__uart1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_uart1_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_uart2_hwmod = {
+	.name		= "uart2",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_UART_1_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &uart_class,
+	.flags		= DEBUG_TI81XXUART2_FLAGS,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__uart2 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_uart2_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_uart3_hwmod = {
+	.name		= "uart3",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_UART_2_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &uart_class,
+	.flags		= DEBUG_TI81XXUART3_FLAGS,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__uart3 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_uart3_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig wd_timer_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x14,
+	.sysc_flags	= SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+				SYSS_HAS_RESET_STATUS,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class wd_timer_class = {
+	.name		= "wd_timer",
+	.sysc		= &wd_timer_sysc,
+	.pre_shutdown	= &omap2_wd_timer_disable,
+	.reset		= &omap2_wd_timer_reset,
+};
+
+static struct omap_hwmod dm816x_wd_timer_hwmod = {
+	.name		= "wd_timer",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk18_ck",
+	.flags		= HWMOD_NO_IDLEST,
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_WDTIMER_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &wd_timer_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__wd_timer1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_wd_timer_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+/* I2C common */
+static struct omap_hwmod_class_sysconfig i2c_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x90,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_AUTOIDLE,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class i2c_class = {
+	.name = "i2c",
+	.sysc = &i2c_sysc,
+};
+
+static struct omap_hwmod dm81xx_i2c1_hwmod = {
+	.name		= "i2c1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_I2C_0_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &i2c_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__i2c1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm81xx_i2c1_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_i2c2_hwmod = {
+	.name		= "i2c2",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_I2C_1_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &i2c_class,
+};
+
+static struct omap_hwmod_class_sysconfig dm81xx_elm_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_SOFTRESET |
+				SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__i2c2 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_i2c2_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class dm81xx_elm_hwmod_class = {
+	.name = "elm",
+	.sysc = &dm81xx_elm_sysc,
+};
+
+static struct omap_hwmod dm81xx_elm_hwmod = {
+	.name		= "elm",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &dm81xx_elm_hwmod_class,
+	.main_clk	= "sysclk6_ck",
+};
+
+static struct omap_hwmod_ocp_if dm81xx_l4_ls__elm = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm81xx_elm_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm81xx_gpio_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0114,
+	.sysc_flags	= SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+				SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+				SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+				SIDLE_SMART_WKUP,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dm81xx_gpio_hwmod_class = {
+	.name	= "gpio",
+	.sysc	= &dm81xx_gpio_sysc,
+	.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" },
+};
+
+static struct omap_hwmod dm81xx_gpio1_hwmod = {
+	.name		= "gpio1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &dm81xx_gpio_hwmod_class,
+	.main_clk	= "sysclk6_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_GPIO_0_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.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 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm81xx_gpio1_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
+	{ .role = "dbclk", .clk = "sysclk18_ck" },
+};
+
+static struct omap_hwmod dm81xx_gpio2_hwmod = {
+	.name		= "gpio2",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &dm81xx_gpio_hwmod_class,
+	.main_clk	= "sysclk6_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_GPIO_1_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.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 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm81xx_gpio2_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm81xx_gpmc_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.syss_offs	= 0x14,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dm81xx_gpmc_hwmod_class = {
+	.name	= "gpmc",
+	.sysc	= &dm81xx_gpmc_sysc,
+};
+
+static struct omap_hwmod dm81xx_gpmc_hwmod = {
+	.name		= "gpmc",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &dm81xx_gpmc_hwmod_class,
+	.main_clk	= "sysclk6_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_GPMC_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm81xx_alwon_l3_slow__gpmc = {
+	.master		= &dm816x_alwon_l3_slow_hwmod,
+	.slave		= &dm81xx_gpmc_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm81xx_usbhsotg_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x10,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
+				SYSC_HAS_SOFTRESET,
+	.idlemodes	= SIDLE_SMART | MSTANDBY_FORCE | MSTANDBY_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dm81xx_usbotg_class = {
+	.name = "usbotg",
+	.sysc = &dm81xx_usbhsotg_sysc,
+};
+
+static struct omap_hwmod dm81xx_usbss_hwmod = {
+	.name		= "usb_otg_hs",
+	.clkdm_name	= "default_l3_slow_clkdm",
+	.main_clk	= "sysclk6_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_DEFAULT_USB_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &dm81xx_usbotg_class,
+};
+
+static struct omap_hwmod_ocp_if dm81xx_default_l3_slow__usbss = {
+	.master		= &dm816x_default_l3_slow_hwmod,
+	.slave		= &dm81xx_usbss_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm816x_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+				SIDLE_SMART_WKUP,
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dm816x_timer_hwmod_class = {
+	.name = "timer",
+	.sysc = &dm816x_timer_sysc,
+};
+
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+	.timer_capability	= OMAP_TIMER_ALWON,
+};
+
+static struct omap_hwmod dm816x_timer1_hwmod = {
+	.name		= "timer1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer1_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_1_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer1_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer2_hwmod = {
+	.name		= "timer2",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer2_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_2_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer2 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer2_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer3_hwmod = {
+	.name		= "timer3",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer3_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_3_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer3 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer3_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer4_hwmod = {
+	.name		= "timer4",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer4_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_4_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer4 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer4_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer5_hwmod = {
+	.name		= "timer5",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer5_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_5_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer5 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer5_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer6_hwmod = {
+	.name		= "timer6",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer6_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_6_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer6 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer6_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_timer7_hwmod = {
+	.name		= "timer7",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "timer7_fck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_TIMER_7_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &capability_alwon_dev_attr,
+	.class		= &dm816x_timer_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__timer7 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_timer7_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+/* EMAC Ethernet */
+static struct omap_hwmod_class_sysconfig dm816x_emac_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x4,
+	.sysc_flags	= SYSC_HAS_SOFTRESET,
+	.sysc_fields	= &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dm816x_emac_hwmod_class = {
+	.name		= "emac",
+	.sysc		= &dm816x_emac_sysc,
+};
+
+/*
+ * On dm816x the MDIO is within EMAC0. As the MDIO driver is a separate
+ * driver probed before EMAC0, we let MDIO do the clock idling.
+ */
+static struct omap_hwmod dm816x_emac0_hwmod = {
+	.name		= "emac0",
+	.clkdm_name	= "alwon_ethernet_clkdm",
+	.class		= &dm816x_emac_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_hs__emac0 = {
+	.master		= &dm816x_l4_hs_hwmod,
+	.slave		= &dm816x_emac0_hwmod,
+	.clk		= "sysclk5_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class dm816x_mdio_hwmod_class = {
+	.name		= "davinci_mdio",
+	.sysc		= &dm816x_emac_sysc,
+};
+
+struct omap_hwmod dm816x_emac0_mdio_hwmod = {
+	.name		= "davinci_mdio",
+	.class		= &dm816x_mdio_hwmod_class,
+	.clkdm_name	= "alwon_ethernet_clkdm",
+	.main_clk	= "sysclk24_ck",
+	.flags		= HWMOD_NO_IDLEST,
+	/*
+	 * REVISIT: This should be moved to the emac0_hwmod
+	 * once we have a better way to handle device slaves.
+	 */
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_ETHERNET_0_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_emac0__mdio = {
+	.master		= &dm816x_l4_hs_hwmod,
+	.slave		= &dm816x_emac0_mdio_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod dm816x_emac1_hwmod = {
+	.name		= "emac1",
+	.clkdm_name	= "alwon_ethernet_clkdm",
+	.main_clk	= "sysclk24_ck",
+	.flags		= HWMOD_NO_IDLEST,
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_ETHERNET_1_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &dm816x_emac_hwmod_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_hs__emac1 = {
+	.master		= &dm816x_l4_hs_hwmod,
+	.slave		= &dm816x_emac1_hwmod,
+	.clk		= "sysclk5_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm816x_mmc_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x110,
+	.syss_offs	= 0x114,
+	.sysc_flags	= SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dm816x_mmc_class = {
+	.name = "mmc",
+	.sysc = &dm816x_mmc_sysc,
+};
+
+static struct omap_hwmod_opt_clk dm816x_mmc1_opt_clks[] = {
+	{ .role = "dbck", .clk = "sysclk18_ck", },
+};
+
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
+	.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod dm816x_mmc1_hwmod = {
+	.name		= "mmc1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.opt_clks	= dm816x_mmc1_opt_clks,
+	.opt_clks_cnt	= ARRAY_SIZE(dm816x_mmc1_opt_clks),
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_SDIO_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.dev_attr	= &mmc1_dev_attr,
+	.class		= &dm816x_mmc_class,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__mmc1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_mmc1_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+	.flags		= OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod_class_sysconfig dm816x_mcspi_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x110,
+	.syss_offs	= 0x114,
+	.sysc_flags	= SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+				SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+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 dm816x_mcspi1_hwmod = {
+	.name		= "mcspi1",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk10_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_SPI_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+	.class		= &dm816x_mcspi_class,
+	.dev_attr	= &dm816x_mcspi1_dev_attr,
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__mcspi1 = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_mcspi1_hwmod,
+	.clk		= "sysclk6_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig dm816x_mailbox_sysc = {
+	.rev_offs	= 0x000,
+	.sysc_offs	= 0x010,
+	.syss_offs	= 0x014,
+	.sysc_flags	= SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+				SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE,
+	.idlemodes	= SIDLE_FORCE | SIDLE_NO | SIDLE_SMART,
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dm816x_mailbox_hwmod_class = {
+	.name = "mailbox",
+	.sysc = &dm816x_mailbox_sysc,
+};
+
+static struct omap_hwmod dm816x_mailbox_hwmod = {
+	.name		= "mailbox",
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.class		= &dm816x_mailbox_hwmod_class,
+	.main_clk	= "sysclk6_ck",
+	.prcm		= {
+		.omap4 = {
+			.clkctrl_offs = DM816X_CM_ALWON_MAILBOX_CLKCTRL,
+			.modulemode = MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+static struct omap_hwmod_ocp_if dm816x_l4_ls__mailbox = {
+	.master		= &dm816x_l4_ls_hwmod,
+	.slave		= &dm816x_mailbox_hwmod,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class dm816x_tpcc_hwmod_class = {
+	.name		= "tpcc",
+};
+
+struct omap_hwmod dm816x_tpcc_hwmod = {
+	.name		= "tpcc",
+	.class		= &dm816x_tpcc_hwmod_class,
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= DM816X_CM_ALWON_TPCC_CLKCTRL,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_alwon_l3_fast__tpcc = {
+	.master		= &dm816x_alwon_l3_fast_hwmod,
+	.slave		= &dm816x_tpcc_hwmod,
+	.clk		= "sysclk4_ck",
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space dm816x_tptc0_addr_space[] = {
+	{
+		.pa_start	= 0x49800000,
+		.pa_end		= 0x49800000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ },
+};
+
+static struct omap_hwmod_class dm816x_tptc0_hwmod_class = {
+	.name		= "tptc0",
+};
+
+struct omap_hwmod dm816x_tptc0_hwmod = {
+	.name		= "tptc0",
+	.class		= &dm816x_tptc0_hwmod_class,
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= DM816X_CM_ALWON_TPTC0_CLKCTRL,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_alwon_l3_fast__tptc0 = {
+	.master		= &dm816x_alwon_l3_fast_hwmod,
+	.slave		= &dm816x_tptc0_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+struct omap_hwmod_ocp_if dm816x_tptc0__alwon_l3_fast = {
+	.master		= &dm816x_tptc0_hwmod,
+	.slave		= &dm816x_alwon_l3_fast_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc0_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space dm816x_tptc1_addr_space[] = {
+	{
+		.pa_start	= 0x49900000,
+		.pa_end		= 0x49900000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ },
+};
+
+static struct omap_hwmod_class dm816x_tptc1_hwmod_class = {
+	.name		= "tptc1",
+};
+
+struct omap_hwmod dm816x_tptc1_hwmod = {
+	.name		= "tptc1",
+	.class		= &dm816x_tptc1_hwmod_class,
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= DM816X_CM_ALWON_TPTC1_CLKCTRL,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_alwon_l3_fast__tptc1 = {
+	.master		= &dm816x_alwon_l3_fast_hwmod,
+	.slave		= &dm816x_tptc1_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+struct omap_hwmod_ocp_if dm816x_tptc1__alwon_l3_fast = {
+	.master		= &dm816x_tptc1_hwmod,
+	.slave		= &dm816x_alwon_l3_fast_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc1_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space dm816x_tptc2_addr_space[] = {
+	{
+		.pa_start	= 0x49a00000,
+		.pa_end		= 0x49a00000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ },
+};
+
+static struct omap_hwmod_class dm816x_tptc2_hwmod_class = {
+	.name		= "tptc2",
+};
+
+struct omap_hwmod dm816x_tptc2_hwmod = {
+	.name		= "tptc2",
+	.class		= &dm816x_tptc2_hwmod_class,
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= DM816X_CM_ALWON_TPTC2_CLKCTRL,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_alwon_l3_fast__tptc2 = {
+	.master		= &dm816x_alwon_l3_fast_hwmod,
+	.slave		= &dm816x_tptc2_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+struct omap_hwmod_ocp_if dm816x_tptc2__alwon_l3_fast = {
+	.master		= &dm816x_tptc2_hwmod,
+	.slave		= &dm816x_alwon_l3_fast_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc2_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space dm816x_tptc3_addr_space[] = {
+	{
+		.pa_start	= 0x49b00000,
+		.pa_end		= 0x49b00000 + SZ_8K - 1,
+		.flags		= ADDR_TYPE_RT,
+	},
+	{ },
+};
+
+static struct omap_hwmod_class dm816x_tptc3_hwmod_class = {
+	.name		= "tptc3",
+};
+
+struct omap_hwmod dm816x_tptc3_hwmod = {
+	.name		= "tptc3",
+	.class		= &dm816x_tptc3_hwmod_class,
+	.clkdm_name	= "alwon_l3s_clkdm",
+	.main_clk	= "sysclk4_ck",
+	.prcm		= {
+		.omap4	= {
+			.clkctrl_offs	= DM816X_CM_ALWON_TPTC3_CLKCTRL,
+			.modulemode	= MODULEMODE_SWCTRL,
+		},
+	},
+};
+
+struct omap_hwmod_ocp_if dm816x_alwon_l3_fast__tptc3 = {
+	.master		= &dm816x_alwon_l3_fast_hwmod,
+	.slave		= &dm816x_tptc3_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc3_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+struct omap_hwmod_ocp_if dm816x_tptc3__alwon_l3_fast = {
+	.master		= &dm816x_tptc3_hwmod,
+	.slave		= &dm816x_alwon_l3_fast_hwmod,
+	.clk		= "sysclk4_ck",
+	.addr		= dm816x_tptc3_addr_space,
+	.user		= OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if *dm816x_hwmod_ocp_ifs[] __initdata = {
+	&dm816x_mpu__alwon_l3_slow,
+	&dm816x_mpu__alwon_l3_med,
+	&dm816x_alwon_l3_slow__l4_ls,
+	&dm816x_alwon_l3_slow__l4_hs,
+	&dm816x_l4_ls__uart1,
+	&dm816x_l4_ls__uart2,
+	&dm816x_l4_ls__uart3,
+	&dm816x_l4_ls__wd_timer1,
+	&dm816x_l4_ls__i2c1,
+	&dm816x_l4_ls__i2c2,
+	&dm81xx_l4_ls__gpio1,
+	&dm81xx_l4_ls__gpio2,
+	&dm81xx_l4_ls__elm,
+	&dm816x_l4_ls__mmc1,
+	&dm816x_l4_ls__timer1,
+	&dm816x_l4_ls__timer2,
+	&dm816x_l4_ls__timer3,
+	&dm816x_l4_ls__timer4,
+	&dm816x_l4_ls__timer5,
+	&dm816x_l4_ls__timer6,
+	&dm816x_l4_ls__timer7,
+	&dm816x_l4_ls__mcspi1,
+	&dm816x_l4_ls__mailbox,
+	&dm816x_l4_hs__emac0,
+	&dm816x_emac0__mdio,
+	&dm816x_l4_hs__emac1,
+	&dm816x_alwon_l3_fast__tpcc,
+	&dm816x_alwon_l3_fast__tptc0,
+	&dm816x_alwon_l3_fast__tptc1,
+	&dm816x_alwon_l3_fast__tptc2,
+	&dm816x_alwon_l3_fast__tptc3,
+	&dm816x_tptc0__alwon_l3_fast,
+	&dm816x_tptc1__alwon_l3_fast,
+	&dm816x_tptc2__alwon_l3_fast,
+	&dm816x_tptc3__alwon_l3_fast,
+	&dm81xx_alwon_l3_slow__gpmc,
+	&dm81xx_default_l3_slow__usbss,
+	NULL,
+};
+
+int __init ti81xx_hwmod_init(void)
+{
+	omap_hwmod_init();
+	return omap_hwmod_register_links(dm816x_hwmod_ocp_ifs);
+}
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index 1a19fa0..8e90356 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -152,38 +152,3 @@
 
 	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
 }
-
-void ti81xx_musb_phy_power(u8 on)
-{
-	void __iomem *scm_base = NULL;
-	u32 usbphycfg;
-
-	scm_base = ioremap(TI81XX_SCM_BASE, SZ_2K);
-	if (!scm_base) {
-		pr_err("system control module ioremap failed\n");
-		return;
-	}
-
-	usbphycfg = readl_relaxed(scm_base + USBCTRL0);
-
-	if (on) {
-		if (cpu_is_ti816x()) {
-			usbphycfg |= TI816X_USBPHY0_NORMAL_MODE;
-			usbphycfg &= ~TI816X_USBPHY_REFCLK_OSC;
-		} else if (cpu_is_ti814x()) {
-			usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN
-				| USBPHY_DPINPUT | USBPHY_DMINPUT);
-			usbphycfg |= (USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN
-				| USBPHY_DPOPBUFCTL | USBPHY_DMOPBUFCTL);
-		}
-	} else {
-		if (cpu_is_ti816x())
-			usbphycfg &= ~TI816X_USBPHY0_NORMAL_MODE;
-		else if (cpu_is_ti814x())
-			usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
-
-	}
-	writel_relaxed(usbphycfg, scm_base + USBCTRL0);
-
-	iounmap(scm_base);
-}
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 3d7eee1..190fa43 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -19,7 +19,6 @@
 #include <linux/platform_data/pinctrl-single.h>
 #include <linux/platform_data/iommu-omap.h>
 
-#include "am35xx.h"
 #include "common.h"
 #include "common-board-devices.h"
 #include "dss-common.h"
diff --git a/arch/arm/mach-omap2/pmu.c b/arch/arm/mach-omap2/pmu.c
index 33c8846..a69e9a3 100644
--- a/arch/arm/mach-omap2/pmu.c
+++ b/arch/arm/mach-omap2/pmu.c
@@ -13,7 +13,7 @@
  */
 #include <linux/of.h>
 
-#include <asm/pmu.h>
+#include <asm/system_info.h>
 
 #include "soc.h"
 #include "omap_hwmod.h"
@@ -37,7 +37,8 @@
 {
 	int i;
 	struct omap_hwmod *oh[3];
-	char *dev_name = "arm-pmu";
+	char *dev_name = cpu_architecture() == CPU_ARCH_ARMv6 ?
+			 "armv6-pmu" : "armv7-pmu";
 
 	if ((!oh_num) || (oh_num > 3))
 		return -EINVAL;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 7fb033e..78af6d8 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -115,7 +115,6 @@
 	}
 	pwrdm->voltdm.ptr = voltdm;
 	INIT_LIST_HEAD(&pwrdm->voltdm_node);
-	voltdm_add_pwrdm(voltdm, pwrdm);
 skip_voltdm:
 	spin_lock_init(&pwrdm->_lock);
 
@@ -484,87 +483,6 @@
 }
 
 /**
- * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
- * @pwrdm: struct powerdomain * to add the clockdomain to
- * @clkdm: struct clockdomain * to associate with a powerdomain
- *
- * Dissociate the clockdomain @clkdm from the powerdomain
- * @pwrdm. Returns -EINVAL if presented with invalid pointers; -ENOENT
- * if @clkdm was not associated with the powerdomain, or 0 upon
- * success.
- */
-int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
-{
-	int ret = -EINVAL;
-	int i;
-
-	if (!pwrdm || !clkdm)
-		return -EINVAL;
-
-	pr_debug("powerdomain: %s: dissociating clockdomain %s\n",
-		 pwrdm->name, clkdm->name);
-
-	for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
-		if (pwrdm->pwrdm_clkdms[i] == clkdm)
-			break;
-
-	if (i == PWRDM_MAX_CLKDMS) {
-		pr_debug("powerdomain: %s: clkdm %s not associated?!\n",
-			 pwrdm->name, clkdm->name);
-		ret = -ENOENT;
-		goto pdc_exit;
-	}
-
-	pwrdm->pwrdm_clkdms[i] = NULL;
-
-	ret = 0;
-
-pdc_exit:
-	return ret;
-}
-
-/**
- * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
- * @pwrdm: struct powerdomain * to iterate over
- * @fn: callback function *
- *
- * Call the supplied function @fn for each clockdomain in the powerdomain
- * @pwrdm.  The callback function can return anything but 0 to bail
- * out early from the iterator.  Returns -EINVAL if presented with
- * invalid pointers; or passes along the last return value of the
- * callback function, which should be 0 for success or anything else
- * to indicate failure.
- */
-int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
-			 int (*fn)(struct powerdomain *pwrdm,
-				   struct clockdomain *clkdm))
-{
-	int ret = 0;
-	int i;
-
-	if (!fn)
-		return -EINVAL;
-
-	for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
-		if (pwrdm->pwrdm_clkdms[i])
-			ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
-
-	return ret;
-}
-
-/**
- * pwrdm_get_voltdm - return a ptr to the voltdm that this pwrdm resides in
- * @pwrdm: struct powerdomain *
- *
- * Return a pointer to the struct voltageomain that the specified powerdomain
- * @pwrdm exists in.
- */
-struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm)
-{
-	return pwrdm->voltdm.ptr;
-}
-
-/**
  * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
  * @pwrdm: struct powerdomain *
  *
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 11bd4dd..28a796c 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -212,11 +212,6 @@
 			void *user);
 
 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
-int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
-int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
-			 int (*fn)(struct powerdomain *pwrdm,
-				   struct clockdomain *clkdm));
-struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
 
 int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 328c103..70bc706 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -464,7 +464,7 @@
 {
 	unsigned int rev;
 
-	if (!cpu_is_omap34xx())
+	if (!cpu_is_omap34xx() && !cpu_is_ti81xx())
 		return;
 
 	pwrdm_register_platform_funcs(&omap3_pwrdm_operations);
diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h
index cfde3f4..ed8a3d8 100644
--- a/arch/arm/mach-omap2/prm3xxx.h
+++ b/arch/arm/mach-omap2/prm3xxx.h
@@ -145,7 +145,6 @@
 extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 
 extern int __init omap3xxx_prm_init(void);
-extern u32 omap3xxx_prm_get_reset_sources(void);
 int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits);
 void omap3xxx_prm_iva_idle(void);
 void omap3_prm_reset_modem(void);
diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h
index f751251..7143295 100644
--- a/arch/arm/mach-omap2/prm44xx_54xx.h
+++ b/arch/arm/mach-omap2/prm44xx_54xx.h
@@ -39,7 +39,6 @@
 extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
 
 extern int __init omap44xx_prm_init(void);
-extern u32 omap44xx_prm_get_reset_sources(void);
 
 #endif
 
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index dea2833..264b5e2 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -581,6 +581,10 @@
 	{ .compatible = "ti,am3-scrm" },
 	{ .compatible = "ti,am4-prcm" },
 	{ .compatible = "ti,am4-scrm" },
+	{ .compatible = "ti,dm814-prcm" },
+	{ .compatible = "ti,dm814-scrm" },
+	{ .compatible = "ti,dm816-prcm" },
+	{ .compatible = "ti,dm816-scrm" },
 	{ .compatible = "ti,omap2-prcm" },
 	{ .compatible = "ti,omap2-scrm" },
 	{ .compatible = "ti,omap3-prm" },
diff --git a/arch/arm/mach-omap2/soc.h b/arch/arm/mach-omap2/soc.h
index c1a3b44..f97654d 100644
--- a/arch/arm/mach-omap2/soc.h
+++ b/arch/arm/mach-omap2/soc.h
@@ -423,13 +423,13 @@
 #define OMAP3630_REV_ES1_1	(OMAP363X_CLASS | (0x1 << 8))
 #define OMAP3630_REV_ES1_2	(OMAP363X_CLASS | (0x2 << 8))
 
-#define TI816X_CLASS		0x81600034
+#define TI816X_CLASS		0x81600081
 #define TI8168_REV_ES1_0	TI816X_CLASS
 #define TI8168_REV_ES1_1	(TI816X_CLASS | (0x1 << 8))
 #define TI8168_REV_ES2_0	(TI816X_CLASS | (0x2 << 8))
 #define TI8168_REV_ES2_1	(TI816X_CLASS | (0x3 << 8))
 
-#define TI814X_CLASS		0x81400034
+#define TI814X_CLASS		0x81400081
 #define TI8148_REV_ES1_0	TI814X_CLASS
 #define TI8148_REV_ES2_0	(TI814X_CLASS | (0x1 << 8))
 #define TI8148_REV_ES2_1	(TI814X_CLASS | (0x2 << 8))
diff --git a/arch/arm/mach-omap2/ti81xx-restart.c b/arch/arm/mach-omap2/ti81xx-restart.c
new file mode 100644
index 0000000..6c3ce7c
--- /dev/null
+++ b/arch/arm/mach-omap2/ti81xx-restart.c
@@ -0,0 +1,34 @@
+/*
+ * 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/init.h>
+#include <linux/reboot.h>
+
+#include "iomap.h"
+#include "common.h"
+#include "control.h"
+#include "prm3xxx.h"
+
+#define TI81XX_PRM_DEVICE_RSTCTRL	0x00a0
+#define TI81XX_GLOBAL_RST_COLD		BIT(1)
+
+/**
+ * ti81xx_restart - trigger a software restart of the SoC
+ * @mode: the "reboot mode", see arch/arm/kernel/{setup,process}.c
+ * @cmd: passed from the userspace program rebooting the system (if provided)
+ *
+ * Resets the SoC.  For @cmd, see the 'reboot' syscall in
+ * kernel/sys.c.  No return value.
+ *
+ * NOTE: Warm reset does not seem to work, may require resetting
+ * clocks to bypass mode.
+ */
+void ti81xx_restart(enum reboot_mode mode, const char *cmd)
+{
+	omap2_prm_set_mod_reg_bits(TI81XX_GLOBAL_RST_COLD, 0,
+				   TI81XX_PRM_DEVICE_RSTCTRL);
+	while (1);
+}
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 7d45c84..cef67af 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -147,6 +147,8 @@
 	{ .compatible = "ti,omap3430-timer", },
 	{ .compatible = "ti,omap4430-timer", },
 	{ .compatible = "ti,omap5430-timer", },
+	{ .compatible = "ti,dm814-timer", },
+	{ .compatible = "ti,dm816-timer", },
 	{ .compatible = "ti,am335x-timer", },
 	{ .compatible = "ti,am335x-timer-1ms", },
 	{ }
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index bc89723..e4562b2 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -82,16 +82,8 @@
 	musb_plat.mode = board_data->mode;
 	musb_plat.extvbus = board_data->extvbus;
 
-	if (soc_is_am35xx()) {
-		oh_name = "am35x_otg_hs";
-		name = "musb-am35x";
-	} else if (cpu_is_ti81xx()) {
-		oh_name = "usb_otg_hs";
-		name = "musb-ti81xx";
-	} else {
-		oh_name = "usb_otg_hs";
-		name = "musb-omap2430";
-	}
+	oh_name = "usb_otg_hs";
+	name = "musb-omap2430";
 
         oh = omap_hwmod_lookup(oh_name);
         if (WARN(!oh, "%s: could not find omap_hwmod for %s\n",
diff --git a/arch/arm/mach-omap2/usb.h b/arch/arm/mach-omap2/usb.h
index 4ba2ae7..3395365 100644
--- a/arch/arm/mach-omap2/usb.h
+++ b/arch/arm/mach-omap2/usb.h
@@ -68,5 +68,3 @@
 extern void am35x_musb_phy_power(u8 on);
 extern void am35x_musb_clear_irq(void);
 extern void am35x_set_mode(u8 musb_mode);
-extern void ti81xx_musb_phy_power(u8 on);
-
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 3783b86..cba8cad 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -224,37 +224,6 @@
 }
 
 /**
- * omap_change_voltscale_method() - API to change the voltage scaling method.
- * @voltdm:	pointer to the VDD whose voltage scaling method
- *		has to be changed.
- * @voltscale_method:	the method to be used for voltage scaling.
- *
- * This API can be used by the board files to change the method of voltage
- * scaling between vpforceupdate and vcbypass. The parameter values are
- * defined in voltage.h
- */
-void omap_change_voltscale_method(struct voltagedomain *voltdm,
-				  int voltscale_method)
-{
-	if (!voltdm || IS_ERR(voltdm)) {
-		pr_warn("%s: VDD specified does not exist!\n", __func__);
-		return;
-	}
-
-	switch (voltscale_method) {
-	case VOLTSCALE_VPFORCEUPDATE:
-		voltdm->scale = omap_vp_forceupdate_scale;
-		return;
-	case VOLTSCALE_VCBYPASS:
-		voltdm->scale = omap_vc_bypass_scale;
-		return;
-	default:
-		pr_warn("%s: Trying to change the method of voltage scaling to an unsupported one!\n",
-			__func__);
-	}
-}
-
-/**
  * omap_voltage_late_init() - Init the various voltage parameters
  *
  * This API is to be called in the later stages of the
@@ -316,90 +285,11 @@
 	return voltdm;
 }
 
-/**
- * voltdm_add_pwrdm - add a powerdomain to a voltagedomain
- * @voltdm: struct voltagedomain * to add the powerdomain to
- * @pwrdm: struct powerdomain * to associate with a voltagedomain
- *
- * Associate the powerdomain @pwrdm with a voltagedomain @voltdm.  This
- * enables the use of voltdm_for_each_pwrdm().  Returns -EINVAL if
- * presented with invalid pointers; -ENOMEM if memory could not be allocated;
- * or 0 upon success.
- */
-int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm)
-{
-	if (!voltdm || !pwrdm)
-		return -EINVAL;
-
-	pr_debug("voltagedomain: %s: associating powerdomain %s\n",
-		 voltdm->name, pwrdm->name);
-
-	list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list);
-
-	return 0;
-}
-
-/**
- * voltdm_for_each_pwrdm - call function for each pwrdm in a voltdm
- * @voltdm: struct voltagedomain * to iterate over
- * @fn: callback function *
- *
- * Call the supplied function @fn for each powerdomain in the
- * voltagedomain @voltdm.  Returns -EINVAL if presented with invalid
- * pointers; or passes along the last return value of the callback
- * function, which should be 0 for success or anything else to
- * indicate failure.
- */
-int voltdm_for_each_pwrdm(struct voltagedomain *voltdm,
-			  int (*fn)(struct voltagedomain *voltdm,
-				    struct powerdomain *pwrdm))
-{
-	struct powerdomain *pwrdm;
-	int ret = 0;
-
-	if (!fn)
-		return -EINVAL;
-
-	list_for_each_entry(pwrdm, &voltdm->pwrdm_list, voltdm_node)
-		ret = (*fn)(voltdm, pwrdm);
-
-	return ret;
-}
-
-/**
- * voltdm_for_each - call function on each registered voltagedomain
- * @fn: callback function *
- *
- * Call the supplied function @fn for each registered voltagedomain.
- * The callback function @fn can return anything but 0 to bail out
- * early from the iterator.  Returns the last return value of the
- * callback function, which should be 0 for success or anything else
- * to indicate failure; or -EINVAL if the function pointer is null.
- */
-int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user),
-		    void *user)
-{
-	struct voltagedomain *temp_voltdm;
-	int ret = 0;
-
-	if (!fn)
-		return -EINVAL;
-
-	list_for_each_entry(temp_voltdm, &voltdm_list, node) {
-		ret = (*fn)(temp_voltdm, user);
-		if (ret)
-			break;
-	}
-
-	return ret;
-}
-
 static int _voltdm_register(struct voltagedomain *voltdm)
 {
 	if (!voltdm || !voltdm->name)
 		return -EINVAL;
 
-	INIT_LIST_HEAD(&voltdm->pwrdm_list);
 	list_add(&voltdm->node, &voltdm_list);
 
 	pr_debug("voltagedomain: registered %s\n", voltdm->name);
diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h
index f7f2879..e645503 100644
--- a/arch/arm/mach-omap2/voltage.h
+++ b/arch/arm/mach-omap2/voltage.h
@@ -23,10 +23,6 @@
 
 struct powerdomain;
 
-/* XXX document */
-#define VOLTSCALE_VPFORCEUPDATE		1
-#define VOLTSCALE_VCBYPASS		2
-
 /*
  * OMAP3 GENERIC setup times. Revisit to see if these needs to be
  * passed from board or PMIC file
@@ -55,7 +51,6 @@
  * @name: Name of the voltage domain which can be used as a unique identifier.
  * @scalable: Whether or not this voltage domain is scalable
  * @node: list_head linking all voltage domains
- * @pwrdm_list: list_head linking all powerdomains in this voltagedomain
  * @vc: pointer to VC channel associated with this voltagedomain
  * @vp: pointer to VP associated with this voltagedomain
  * @read: read a VC/VP register
@@ -71,7 +66,6 @@
 	char *name;
 	bool scalable;
 	struct list_head node;
-	struct list_head pwrdm_list;
 	struct omap_vc_channel *vc;
 	const struct omap_vfsm_instance *vfsm;
 	struct omap_vp_instance *vp;
@@ -163,8 +157,6 @@
 		unsigned long volt);
 int omap_voltage_register_pmic(struct voltagedomain *voltdm,
 			       struct omap_voltdm_pmic *pmic);
-void omap_change_voltscale_method(struct voltagedomain *voltdm,
-		int voltscale_method);
 int omap_voltage_late_init(void);
 
 extern void omap2xxx_voltagedomains_init(void);
@@ -175,11 +167,6 @@
 struct voltagedomain *voltdm_lookup(const char *name);
 void voltdm_init(struct voltagedomain **voltdm_list);
 int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm);
-int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user),
-		    void *user);
-int voltdm_for_each_pwrdm(struct voltagedomain *voltdm,
-			  int (*fn)(struct voltagedomain *voltdm,
-				    struct powerdomain *pwrdm));
 int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt);
 void voltdm_reset(struct voltagedomain *voltdm);
 unsigned long voltdm_get_voltage(struct voltagedomain *voltdm);
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig
index 042f693..a219dc3 100644
--- a/arch/arm/mach-prima2/Kconfig
+++ b/arch/arm/mach-prima2/Kconfig
@@ -11,7 +11,7 @@
 
 if ARCH_SIRF
 
-comment "CSR SiRF atlas6/primaII/Marco/Polo Specific Features"
+comment "CSR SiRF atlas6/primaII/Atlas7 Specific Features"
 
 config ARCH_ATLAS6
 	bool "CSR SiRFSoC ATLAS6 ARM Cortex A9 Platform"
@@ -20,6 +20,17 @@
 	help
           Support for CSR SiRFSoC ARM Cortex A9 Platform
 
+config ARCH_ATLAS7
+	bool "CSR SiRFSoC ATLAS7 ARM Cortex A7 Platform"
+	default y
+	select ARM_GIC
+	select CPU_V7
+	select HAVE_ARM_SCU if SMP
+	select HAVE_SMP
+	select SMP_ON_UP if SMP
+	help
+          Support for CSR SiRFSoC ARM Cortex A7 Platform
+
 config ARCH_PRIMA2
 	bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
 	default y
@@ -28,15 +39,6 @@
 	help
           Support for CSR SiRFSoC ARM Cortex A9 Platform
 
-config ARCH_MARCO
-	bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform"
-	default y
-	select ARM_GIC
-	select HAVE_ARM_SCU if SMP
-	select SMP_ON_UP if SMP
-	help
-          Support for CSR SiRFSoC ARM Cortex A9 Platform
-
 config SIRF_IRQ
 	bool
 
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index 8846e7d..d7d02b0 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -1,7 +1,6 @@
 obj-y += rstc.o
 obj-y += common.o
 obj-y += rtciobrg.o
-obj-$(CONFIG_DEBUG_LL) += lluart.o
 obj-$(CONFIG_SUSPEND) += pm.o sleep.o
 obj-$(CONFIG_SMP) += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)  += hotplug.o
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index a860ea2..0c819bb 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -20,12 +20,6 @@
 	sirfsoc_pm_init();
 }
 
-static __init void sirfsoc_map_io(void)
-{
-	sirfsoc_map_lluart();
-	sirfsoc_map_scu();
-}
-
 #ifdef CONFIG_ARCH_ATLAS6
 static const char *atlas6_dt_match[] __initconst = {
 	"sirf,atlas6",
@@ -36,7 +30,6 @@
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
 	.l2c_aux_val	= 0,
 	.l2c_aux_mask	= ~0,
-	.map_io         = sirfsoc_map_io,
 	.init_late	= sirfsoc_init_late,
 	.dt_compat      = atlas6_dt_match,
 MACHINE_END
@@ -52,26 +45,21 @@
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
 	.l2c_aux_val	= 0,
 	.l2c_aux_mask	= ~0,
-	.map_io         = sirfsoc_map_io,
 	.dma_zone_size	= SZ_256M,
 	.init_late	= sirfsoc_init_late,
 	.dt_compat      = prima2_dt_match,
 MACHINE_END
 #endif
 
-#ifdef CONFIG_ARCH_MARCO
-static const char *marco_dt_match[] __initconst = {
-	"sirf,marco",
+#ifdef CONFIG_ARCH_ATLAS7
+static const char *atlas7_dt_match[] __initdata = {
+	"sirf,atlas7",
 	NULL
 };
 
-DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
+DT_MACHINE_START(ATLAS7_DT, "Generic ATLAS7 (Flattened Device Tree)")
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
-	.l2c_aux_val	= 0,
-	.l2c_aux_mask	= ~0,
 	.smp            = smp_ops(sirfsoc_smp_ops),
-	.map_io         = sirfsoc_map_io,
-	.init_late	= sirfsoc_init_late,
-	.dt_compat      = marco_dt_match,
+	.dt_compat      = atlas7_dt_match,
 MACHINE_END
 #endif
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 07d3e5e..3916a66 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -15,9 +15,6 @@
 #include <asm/mach/time.h>
 #include <asm/exception.h>
 
-#define SIRFSOC_VA_BASE		_AC(0xFEC00000, UL)
-#define SIRFSOC_VA(x)		(SIRFSOC_VA_BASE + ((x) & 0x00FFF000))
-
 extern struct smp_operations   sirfsoc_smp_ops;
 extern void sirfsoc_secondary_startup(void);
 extern void sirfsoc_cpu_die(unsigned int cpu);
@@ -25,18 +22,6 @@
 extern void __init sirfsoc_of_irq_init(void);
 extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs);
 
-#ifndef CONFIG_DEBUG_LL
-static inline void sirfsoc_map_lluart(void)  {}
-#else
-extern void __init sirfsoc_map_lluart(void);
-#endif
-
-#ifndef CONFIG_SMP
-static inline void sirfsoc_map_scu(void) {}
-#else
-extern void sirfsoc_map_scu(void);
-#endif
-
 #ifdef CONFIG_SUSPEND
 extern int sirfsoc_pm_init(void);
 #else
diff --git a/arch/arm/mach-prima2/lluart.c b/arch/arm/mach-prima2/lluart.c
deleted file mode 100644
index 99c0c92..0000000
--- a/arch/arm/mach-prima2/lluart.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Static memory mapping for DEBUG_LL
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/kernel.h>
-#include <asm/page.h>
-#include <asm/mach/map.h>
-#include "common.h"
-
-#if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1)
-#define SIRFSOC_UART1_PA_BASE          0xb0060000
-#elif defined(CONFIG_DEBUG_SIRFMARCO_UART1)
-#define SIRFSOC_UART1_PA_BASE          0xcc060000
-#else
-#define SIRFSOC_UART1_PA_BASE          0
-#endif
-
-#define SIRFSOC_UART1_VA_BASE          SIRFSOC_VA(0x060000)
-#define SIRFSOC_UART1_SIZE		SZ_4K
-
-void __init sirfsoc_map_lluart(void)
-{
-	struct map_desc sirfsoc_lluart_map = {
-		.virtual        = SIRFSOC_UART1_VA_BASE,
-		.pfn            = __phys_to_pfn(SIRFSOC_UART1_PA_BASE),
-		.length         = SIRFSOC_UART1_SIZE,
-		.type           = MT_DEVICE,
-	};
-
-	iotable_init(&sirfsoc_lluart_map, 1);
-}
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
index 335c12e..fc2b03c 100644
--- a/arch/arm/mach-prima2/platsmp.c
+++ b/arch/arm/mach-prima2/platsmp.c
@@ -20,30 +20,10 @@
 
 #include "common.h"
 
-static void __iomem *scu_base;
-static void __iomem *rsc_base;
+static void __iomem *clk_base;
 
 static DEFINE_SPINLOCK(boot_lock);
 
-static struct map_desc scu_io_desc __initdata = {
-	.length		= SZ_4K,
-	.type		= MT_DEVICE,
-};
-
-void __init sirfsoc_map_scu(void)
-{
-	unsigned long base;
-
-	/* Get SCU base */
-	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
-
-	scu_io_desc.virtual = SIRFSOC_VA(base);
-	scu_io_desc.pfn = __phys_to_pfn(base);
-	iotable_init(&scu_io_desc, 1);
-
-	scu_base = (void __iomem *)SIRFSOC_VA(base);
-}
-
 static void sirfsoc_secondary_init(unsigned int cpu)
 {
 	/*
@@ -60,8 +40,8 @@
 	spin_unlock(&boot_lock);
 }
 
-static struct of_device_id rsc_ids[]  = {
-	{ .compatible = "sirf,marco-rsc" },
+static struct of_device_id clk_ids[]  = {
+	{ .compatible = "sirf,atlas7-clkc" },
 	{},
 };
 
@@ -70,27 +50,27 @@
 	unsigned long timeout;
 	struct device_node *np;
 
-	np = of_find_matching_node(NULL, rsc_ids);
+	np = of_find_matching_node(NULL, clk_ids);
 	if (!np)
 		return -ENODEV;
 
-	rsc_base = of_iomap(np, 0);
-	if (!rsc_base)
+	clk_base = of_iomap(np, 0);
+	if (!clk_base)
 		return -ENOMEM;
 
 	/*
-	 * write the address of secondary startup into the sram register
-	 * at offset 0x2C, then write the magic number 0x3CAF5D62 to the
-	 * RSC register at offset 0x28, which is what boot rom code is
+	 * write the address of secondary startup into the clkc register
+	 * at offset 0x2bC, then write the magic number 0x3CAF5D62 to the
+	 * clkc register at offset 0x2b8, which is what boot rom code is
 	 * waiting for. This would wake up the secondary core from WFE
 	 */
-#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C
+#define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2bc
 	__raw_writel(virt_to_phys(sirfsoc_secondary_startup),
-		rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
+		clk_base + SIRFSOC_CPU1_JUMPADDR_OFFSET);
 
-#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28
+#define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x2b8
 	__raw_writel(0x3CAF5D62,
-		rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
+		clk_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET);
 
 	/* make sure write buffer is drained */
 	mb();
@@ -132,13 +112,7 @@
 	return pen_release != -1 ? -ENOSYS : 0;
 }
 
-static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
-{
-	scu_enable(scu_base);
-}
-
 struct smp_operations sirfsoc_smp_ops __initdata = {
-	.smp_prepare_cpus       = sirfsoc_smp_prepare_cpus,
 	.smp_secondary_init     = sirfsoc_secondary_init,
 	.smp_boot_secondary     = sirfsoc_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
index e1f1f86..7c251eb 100644
--- a/arch/arm/mach-prima2/rstc.c
+++ b/arch/arm/mach-prima2/rstc.c
@@ -34,36 +34,20 @@
 
 	mutex_lock(&rstc_lock);
 
-	if (of_device_is_compatible(rcdev->of_node, "sirf,prima2-rstc")) {
-		/*
-		 * Writing 1 to this bit resets corresponding block.
-		 * Writing 0 to this bit de-asserts reset signal of the
-		 * corresponding block. datasheet doesn't require explicit
-		 * delay between the set and clear of reset bit. it could
-		 * be shorter if tests pass.
-		 */
-		writel(readl(sirfsoc_rstc_base +
+	/*
+	 * Writing 1 to this bit resets corresponding block.
+	 * Writing 0 to this bit de-asserts reset signal of the
+	 * corresponding block. datasheet doesn't require explicit
+	 * delay between the set and clear of reset bit. it could
+	 * be shorter if tests pass.
+	 */
+	writel(readl(sirfsoc_rstc_base +
 			(reset_bit / 32) * 4) | (1 << reset_bit),
-			sirfsoc_rstc_base + (reset_bit / 32) * 4);
-		msleep(20);
-		writel(readl(sirfsoc_rstc_base +
+		sirfsoc_rstc_base + (reset_bit / 32) * 4);
+	msleep(20);
+	writel(readl(sirfsoc_rstc_base +
 			(reset_bit / 32) * 4) & ~(1 << reset_bit),
-			sirfsoc_rstc_base + (reset_bit / 32) * 4);
-	} else {
-		/*
-		 * For MARCO and POLO
-		 * Writing 1 to SET register resets corresponding block.
-		 * Writing 1 to CLEAR register de-asserts reset signal of the
-		 * corresponding block.
-		 * datasheet doesn't require explicit delay between the set and
-		 * clear of reset bit. it could be shorter if tests pass.
-		 */
-		writel(1 << reset_bit,
-			sirfsoc_rstc_base + (reset_bit / 32) * 8);
-		msleep(20);
-		writel(1 << reset_bit,
-			sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4);
-	}
+		sirfsoc_rstc_base + (reset_bit / 32) * 4);
 
 	mutex_unlock(&rstc_lock);
 
@@ -106,7 +90,6 @@
 
 static const struct of_device_id rstc_ids[]  = {
 	{ .compatible = "sirf,prima2-rstc" },
-	{ .compatible = "sirf,marco-rstc" },
 	{},
 };
 
diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c
index 70a0b47..8f66d8f 100644
--- a/arch/arm/mach-prima2/rtciobrg.c
+++ b/arch/arm/mach-prima2/rtciobrg.c
@@ -104,7 +104,6 @@
 
 static const struct of_device_id rtciobrg_ids[] = {
 	{ .compatible = "sirf,prima2-rtciobg" },
-	{ .compatible = "sirf,marco-rtciobg" },
 	{}
 };
 
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 83efe91..8896e71 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -6,7 +6,6 @@
 
 config MACH_PXA27X_DT
 	bool "Support PXA27x platforms from device tree"
-	select CPU_PXA27x
 	select POWER_SUPPLY
 	select PXA27x
 	select USE_OF
@@ -84,14 +83,12 @@
 	select I2C_GPIO if I2C=y
 	select ISA
 	select PXA25x
-	select PXA_HAVE_ISA_IRQS
 
 config MACH_ARCOM_ZEUS
 	bool "Arcom/Eurotech ZEUS SBC"
 	select ARCOM_PCMCIA
 	select ISA
 	select PXA27x
-	select PXA_HAVE_ISA_IRQS
 
 config MACH_BALLOON3
 	bool "Balloon 3 board"
@@ -691,9 +688,6 @@
 	select SPI
 	select SPI_MASTER
 
-config PXA_HAVE_ISA_IRQS
-	bool
-
 config PXA310_ULPI
 	bool
 
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index 06022b2..89f790d 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -26,6 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/io.h>
+#include <linux/regulator/machine.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/corgi_lcd.h>
@@ -752,6 +753,8 @@
 		sharpsl_nand_partitions[1].size = 53 * 1024 * 1024;
 
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+	regulator_has_full_constraints();
 }
 
 static void __init fixup_corgi(struct tag *tags, char **cmdline)
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index ac7b3ea..3543466 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -40,7 +40,7 @@
 };
 
 struct platform_device pxa_device_pmu = {
-	.name		= "arm-pmu",
+	.name		= "xscale-pmu",
 	.id		= -1,
 	.resource	= &pxa_resource_pmu,
 	.num_resources	= 1,
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index c66ad4e..5fb41ad 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -893,6 +893,8 @@
 	mdelay(10);
 	gpio_set_value(GPIO71_HX4700_ASIC3_nRESET, 1);
 	mdelay(10);
+
+	regulator_has_full_constraints();
 }
 
 MACHINE_START(H4700, "HP iPAQ HX4700")
diff --git a/arch/arm/mach-pxa/include/mach/irqs.h b/arch/arm/mach-pxa/include/mach/irqs.h
index 48c2fd8..7e3ea35 100644
--- a/arch/arm/mach-pxa/include/mach/irqs.h
+++ b/arch/arm/mach-pxa/include/mach/irqs.h
@@ -12,14 +12,10 @@
 #ifndef __ASM_MACH_IRQS_H
 #define __ASM_MACH_IRQS_H
 
-#ifdef CONFIG_PXA_HAVE_ISA_IRQS
-#define PXA_ISA_IRQ(x)	(x)
-#define PXA_ISA_IRQ_NUM	(16)
-#else
-#define PXA_ISA_IRQ_NUM	(0)
-#endif
+#include <asm/irq.h>
 
-#define PXA_IRQ(x)	(PXA_ISA_IRQ_NUM + (x))
+#define PXA_ISA_IRQ(x)	(x)
+#define PXA_IRQ(x)	(NR_IRQS_LEGACY + (x))
 
 #define IRQ_SSP3	PXA_IRQ(0)	/* SSP3 service request */
 #define IRQ_MSL		PXA_IRQ(1)	/* MSL Interface interrupt */
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 29019be..195b112 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -25,6 +25,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pxa-i2c.h>
+#include <linux/regulator/machine.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/pxa2xx_spi.h>
@@ -455,6 +456,7 @@
 	pxa_set_i2c_info(NULL);
 	i2c_register_board_info(0, ARRAY_AND_SIZE(poodle_i2c_devices));
 	poodle_init_spi();
+	regulator_has_full_constraints();
 }
 
 static void __init fixup_poodle(struct tag *tags, char **cmdline)
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 962a7f3..f4e2e27 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -979,6 +979,8 @@
 	spitz_nand_init();
 	spitz_i2c_init();
 	spitz_audio_init();
+
+	regulator_has_full_constraints();
 }
 
 static void __init spitz_fixup(struct tag *tags, char **cmdline)
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index ee5697b..48003ea 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -1,9 +1,8 @@
 menuconfig ARCH_QCOM
 	bool "Qualcomm Support" if ARCH_MULTI_V7
-	select ARCH_REQUIRE_GPIOLIB
+	select ARCH_SUPPORTS_BIG_ENDIAN
 	select ARM_GIC
 	select ARM_AMBA
-	select CLKSRC_OF
 	select PINCTRL
 	select QCOM_SCM if SMP
 	help
diff --git a/arch/arm/mach-qcom/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c
index 45cee3e..e8ff7be 100644
--- a/arch/arm/mach-qcom/scm-boot.c
+++ b/arch/arm/mach-qcom/scm-boot.c
@@ -24,15 +24,15 @@
 /*
  * Set the cold/warm boot address for one of the CPU cores.
  */
-int scm_set_boot_addr(phys_addr_t addr, int flags)
+int scm_set_boot_addr(u32 addr, int flags)
 {
 	struct {
-		unsigned int flags;
-		phys_addr_t  addr;
+		__le32 flags;
+		__le32 addr;
 	} cmd;
 
-	cmd.addr = addr;
-	cmd.flags = flags;
+	cmd.addr = cpu_to_le32(addr);
+	cmd.flags = cpu_to_le32(flags);
 	return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR,
 			&cmd, sizeof(cmd), NULL, 0);
 }
diff --git a/arch/arm/mach-qcom/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h
index 6aabb24..3e210fb 100644
--- a/arch/arm/mach-qcom/scm-boot.h
+++ b/arch/arm/mach-qcom/scm-boot.h
@@ -18,7 +18,9 @@
 #define SCM_FLAG_COLDBOOT_CPU3		0x20
 #define SCM_FLAG_WARMBOOT_CPU0		0x04
 #define SCM_FLAG_WARMBOOT_CPU1		0x02
+#define SCM_FLAG_WARMBOOT_CPU2		0x10
+#define SCM_FLAG_WARMBOOT_CPU3		0x40
 
-int scm_set_boot_addr(phys_addr_t addr, int flags);
+int scm_set_boot_addr(u32 addr, int flags);
 
 #endif
diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c
index c536fd6..1d9cf18 100644
--- a/arch/arm/mach-qcom/scm.c
+++ b/arch/arm/mach-qcom/scm.c
@@ -22,13 +22,11 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 
+#include <asm/outercache.h>
 #include <asm/cacheflush.h>
 
 #include "scm.h"
 
-/* Cache line size for msm8x60 */
-#define CACHELINESIZE 32
-
 #define SCM_ENOMEM		-5
 #define SCM_EOPNOTSUPP		-4
 #define SCM_EINVAL_ADDR		-3
@@ -63,11 +61,11 @@
  * to access the buffers in a safe manner.
  */
 struct scm_command {
-	u32	len;
-	u32	buf_offset;
-	u32	resp_hdr_offset;
-	u32	id;
-	u32	buf[0];
+	__le32 len;
+	__le32 buf_offset;
+	__le32 resp_hdr_offset;
+	__le32 id;
+	__le32 buf[0];
 };
 
 /**
@@ -77,9 +75,9 @@
  * @is_complete: indicates if the command has finished processing
  */
 struct scm_response {
-	u32	len;
-	u32	buf_offset;
-	u32	is_complete;
+	__le32 len;
+	__le32 buf_offset;
+	__le32 is_complete;
 };
 
 /**
@@ -97,12 +95,14 @@
 	struct scm_command *cmd;
 	size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size +
 		resp_size;
+	u32 offset;
 
 	cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
 	if (cmd) {
-		cmd->len = len;
-		cmd->buf_offset = offsetof(struct scm_command, buf);
-		cmd->resp_hdr_offset = cmd->buf_offset + cmd_size;
+		cmd->len = cpu_to_le32(len);
+		offset = offsetof(struct scm_command, buf);
+		cmd->buf_offset = cpu_to_le32(offset);
+		cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
 	}
 	return cmd;
 }
@@ -127,7 +127,7 @@
 static inline struct scm_response *scm_command_to_response(
 		const struct scm_command *cmd)
 {
-	return (void *)cmd + cmd->resp_hdr_offset;
+	return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
 }
 
 /**
@@ -149,11 +149,12 @@
  */
 static inline void *scm_get_response_buffer(const struct scm_response *rsp)
 {
-	return (void *)rsp + rsp->buf_offset;
+	return (void *)rsp + le32_to_cpu(rsp->buf_offset);
 }
 
 static int scm_remap_error(int err)
 {
+	pr_err("scm_call failed with error code %d\n", err);
 	switch (err) {
 	case SCM_ERROR:
 		return -EIO;
@@ -198,11 +199,12 @@
 	u32 cmd_addr = virt_to_phys(cmd);
 
 	/*
-	 * Flush the entire cache here so callers don't have to remember
-	 * to flush the cache when passing physical addresses to the secure
-	 * side in the buffer.
+	 * Flush the command buffer so that the secure world sees
+	 * the correct data.
 	 */
-	flush_cache_all();
+	__cpuc_flush_dcache_area((void *)cmd, cmd->len);
+	outer_flush_range(cmd_addr, cmd_addr + cmd->len);
+
 	ret = smc(cmd_addr);
 	if (ret < 0)
 		ret = scm_remap_error(ret);
@@ -210,6 +212,25 @@
 	return ret;
 }
 
+static void scm_inv_range(unsigned long start, unsigned long end)
+{
+	u32 cacheline_size, ctr;
+
+	asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+	cacheline_size = 4 << ((ctr >> 16) & 0xf);
+
+	start = round_down(start, cacheline_size);
+	end = round_up(end, cacheline_size);
+	outer_inv_range(start, end);
+	while (start < end) {
+		asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
+		     : "memory");
+		start += cacheline_size;
+	}
+	dsb();
+	isb();
+}
+
 /**
  * scm_call() - Send an SCM command
  * @svc_id: service identifier
@@ -220,6 +241,13 @@
  * @resp_len: length of the response buffer
  *
  * Sends a command to the SCM and waits for the command to finish processing.
+ *
+ * A note on cache maintenance:
+ * Note that any buffers that are expected to be accessed by the secure world
+ * must be flushed before invoking scm_call and invalidated in the cache
+ * immediately after scm_call returns. Cache maintenance on the command and
+ * response buffers is taken care of by scm_call; however, callers are
+ * responsible for any other cached buffers passed over to the secure world.
  */
 int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
 		void *resp_buf, size_t resp_len)
@@ -227,12 +255,13 @@
 	int ret;
 	struct scm_command *cmd;
 	struct scm_response *rsp;
+	unsigned long start, end;
 
 	cmd = alloc_scm_command(cmd_len, resp_len);
 	if (!cmd)
 		return -ENOMEM;
 
-	cmd->id = (svc_id << 10) | cmd_id;
+	cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
 	if (cmd_buf)
 		memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len);
 
@@ -243,17 +272,15 @@
 		goto out;
 
 	rsp = scm_command_to_response(cmd);
+	start = (unsigned long)rsp;
+
 	do {
-		u32 start = (u32)rsp;
-		u32 end = (u32)scm_get_response_buffer(rsp) + resp_len;
-		start &= ~(CACHELINESIZE - 1);
-		while (start < end) {
-			asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
-			     : "memory");
-			start += CACHELINESIZE;
-		}
+		scm_inv_range(start, start + sizeof(*rsp));
 	} while (!rsp->is_complete);
 
+	end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
+	scm_inv_range(start, end);
+
 	if (resp_buf)
 		memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
 out:
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 739d4f1..64c88d6 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -37,6 +37,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/smp_twd.h>
+#include <asm/system_info.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -296,7 +297,6 @@
 };
 
 static struct platform_device pmu_device = {
-	.name			= "arm-pmu",
 	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
@@ -451,6 +451,7 @@
 		 */
 		l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
 #endif
+		pmu_device.name = core_tile_a9mp() ? "armv7-pmu" : "armv6-pmu";
 		platform_device_register(&pmu_device);
 	}
 
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index b0e0dca..ce92c18 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -280,7 +280,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name			= "arm-pmu",
+	.name			= "armv6-pmu",
 	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 47bf55f..15c45e2 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -262,7 +262,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name			= "arm-pmu",
+	.name			= "armv6-pmu",
 	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 4e57a85..4c64662 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -240,7 +240,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name			= "arm-pmu",
+	.name			= "armv7-pmu",
 	.id			= -1,
 	.num_resources		= 1,
 	.resource		= &pmu_resource,
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index d89eb40..9a22b86 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -280,7 +280,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name			= "arm-pmu",
+	.name			= "armv7-pmu",
 	.id			= -1,
 	.num_resources		= ARRAY_SIZE(pmu_resources),
 	.resource		= pmu_resources,
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index ac5803c..5078932 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -11,6 +11,7 @@
 	select HAVE_ARM_SCU if SMP
 	select HAVE_ARM_TWD if SMP
 	select DW_APB_TIMER_OF
+	select ROCKCHIP_TIMER
 	select ARM_GLOBAL_TIMER
 	select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
 	help
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index b29d8ea..5c3a9b2 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -1,4 +1,5 @@
 CFLAGS_platsmp.o := -march=armv7-a
 
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip.o
+obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c
new file mode 100644
index 0000000..50cb781
--- /dev/null
+++ b/arch/arm/mach-rockchip/pm.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Tony Xie <tony.xie@rock-chips.com>
+ *
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/suspend.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regulator/machine.h>
+
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/suspend.h>
+
+#include "pm.h"
+
+/* These enum are option of low power mode */
+enum {
+	ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0,
+	ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
+};
+
+struct rockchip_pm_data {
+	const struct platform_suspend_ops *ops;
+	int (*init)(struct device_node *np);
+};
+
+static void __iomem *rk3288_bootram_base;
+static phys_addr_t rk3288_bootram_phy;
+
+static struct regmap *pmu_regmap;
+static struct regmap *sgrf_regmap;
+
+static u32 rk3288_pmu_pwr_mode_con;
+static u32 rk3288_sgrf_soc_con0;
+
+static inline u32 rk3288_l2_config(void)
+{
+	u32 l2ctlr;
+
+	asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (l2ctlr));
+	return l2ctlr;
+}
+
+static void rk3288_config_bootdata(void)
+{
+	rkpm_bootdata_cpusp = rk3288_bootram_phy + (SZ_4K - 8);
+	rkpm_bootdata_cpu_code = virt_to_phys(cpu_resume);
+
+	rkpm_bootdata_l2ctlr_f  = 1;
+	rkpm_bootdata_l2ctlr = rk3288_l2_config();
+}
+
+static void rk3288_slp_mode_set(int level)
+{
+	u32 mode_set, mode_set1;
+
+	regmap_read(sgrf_regmap, RK3288_SGRF_SOC_CON0, &rk3288_sgrf_soc_con0);
+
+	regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON,
+		    &rk3288_pmu_pwr_mode_con);
+
+	/* set bit 8 so that system will resume to FAST_BOOT_ADDR */
+	regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
+		     SGRF_FAST_BOOT_EN | SGRF_FAST_BOOT_EN_WRITE);
+
+	/* booting address of resuming system is from this register value */
+	regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
+		     rk3288_bootram_phy);
+
+	regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
+		     PMU_ARMINT_WAKEUP_EN);
+
+	mode_set = BIT(PMU_GLOBAL_INT_DISABLE) | BIT(PMU_L2FLUSH_EN) |
+		   BIT(PMU_SREF0_ENTER_EN) | BIT(PMU_SREF1_ENTER_EN) |
+		   BIT(PMU_DDR0_GATING_EN) | BIT(PMU_DDR1_GATING_EN) |
+		   BIT(PMU_PWR_MODE_EN) | BIT(PMU_CHIP_PD_EN) |
+		   BIT(PMU_SCU_EN);
+
+	mode_set1 = BIT(PMU_CLR_CORE) | BIT(PMU_CLR_CPUP);
+
+	if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
+		/* arm off, logic deep sleep */
+		mode_set |= BIT(PMU_BUS_PD_EN) |
+			    BIT(PMU_DDR1IO_RET_EN) | BIT(PMU_DDR0IO_RET_EN) |
+			    BIT(PMU_OSC_24M_DIS) | BIT(PMU_PMU_USE_LF) |
+			    BIT(PMU_ALIVE_USE_LF) | BIT(PMU_PLL_PD_EN);
+
+		mode_set1 |= BIT(PMU_CLR_ALIVE) | BIT(PMU_CLR_BUS) |
+			     BIT(PMU_CLR_PERI) | BIT(PMU_CLR_DMA);
+	} else {
+		/*
+		 * arm off, logic normal
+		 * if pmu_clk_core_src_gate_en is not set,
+		 * wakeup will be error
+		 */
+		mode_set |= BIT(PMU_CLK_CORE_SRC_GATE_EN);
+	}
+
+	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON, mode_set);
+	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON1, mode_set1);
+}
+
+static void rk3288_slp_mode_set_resume(void)
+{
+	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON,
+		     rk3288_pmu_pwr_mode_con);
+
+	regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
+		     rk3288_sgrf_soc_con0 | SGRF_FAST_BOOT_EN_WRITE);
+}
+
+static int rockchip_lpmode_enter(unsigned long arg)
+{
+	flush_cache_all();
+
+	cpu_do_idle();
+
+	pr_err("%s: Failed to suspend\n", __func__);
+
+	return 1;
+}
+
+static int rk3288_suspend_enter(suspend_state_t state)
+{
+	local_fiq_disable();
+
+	rk3288_slp_mode_set(ROCKCHIP_ARM_OFF_LOGIC_NORMAL);
+
+	cpu_suspend(0, rockchip_lpmode_enter);
+
+	rk3288_slp_mode_set_resume();
+
+	local_fiq_enable();
+
+	return 0;
+}
+
+static int rk3288_suspend_prepare(void)
+{
+	return regulator_suspend_prepare(PM_SUSPEND_MEM);
+}
+
+static void rk3288_suspend_finish(void)
+{
+	if (regulator_suspend_finish())
+		pr_err("%s: Suspend finish failed\n", __func__);
+}
+
+static int rk3288_suspend_init(struct device_node *np)
+{
+	struct device_node *sram_np;
+	struct resource res;
+	int ret;
+
+	pmu_regmap = syscon_node_to_regmap(np);
+	if (IS_ERR(pmu_regmap)) {
+		pr_err("%s: could not find pmu regmap\n", __func__);
+		return PTR_ERR(pmu_regmap);
+	}
+
+	sgrf_regmap = syscon_regmap_lookup_by_compatible(
+				"rockchip,rk3288-sgrf");
+	if (IS_ERR(sgrf_regmap)) {
+		pr_err("%s: could not find sgrf regmap\n", __func__);
+		return PTR_ERR(pmu_regmap);
+	}
+
+	sram_np = of_find_compatible_node(NULL, NULL,
+					  "rockchip,rk3288-pmu-sram");
+	if (!sram_np) {
+		pr_err("%s: could not find bootram dt node\n", __func__);
+		return -ENODEV;
+	}
+
+	rk3288_bootram_base = of_iomap(sram_np, 0);
+	if (!rk3288_bootram_base) {
+		pr_err("%s: could not map bootram base\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = of_address_to_resource(sram_np, 0, &res);
+	if (ret) {
+		pr_err("%s: could not get bootram phy addr\n", __func__);
+		return ret;
+	}
+	rk3288_bootram_phy = res.start;
+
+	of_node_put(sram_np);
+
+	rk3288_config_bootdata();
+
+	/* copy resume code and data to bootsram */
+	memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
+	       rk3288_bootram_sz);
+
+	return 0;
+}
+
+static const struct platform_suspend_ops rk3288_suspend_ops = {
+	.enter   = rk3288_suspend_enter,
+	.valid   = suspend_valid_only_mem,
+	.prepare = rk3288_suspend_prepare,
+	.finish  = rk3288_suspend_finish,
+};
+
+static const struct rockchip_pm_data rk3288_pm_data __initconst = {
+	.ops = &rk3288_suspend_ops,
+	.init = rk3288_suspend_init,
+};
+
+static const struct of_device_id rockchip_pmu_of_device_ids[] __initconst = {
+	{
+		.compatible = "rockchip,rk3288-pmu",
+		.data = &rk3288_pm_data,
+	},
+	{ /* sentinel */ },
+};
+
+void __init rockchip_suspend_init(void)
+{
+	const struct rockchip_pm_data *pm_data;
+	const struct of_device_id *match;
+	struct device_node *np;
+	int ret;
+
+	np = of_find_matching_node_and_match(NULL, rockchip_pmu_of_device_ids,
+					     &match);
+	if (!match) {
+		pr_err("Failed to find PMU node\n");
+		return;
+	}
+	pm_data = (struct rockchip_pm_data *) match->data;
+
+	if (pm_data->init) {
+		ret = pm_data->init(np);
+
+		if (ret) {
+			pr_err("%s: matches init error %d\n", __func__, ret);
+			return;
+		}
+	}
+
+	suspend_set_ops(pm_data->ops);
+}
diff --git a/arch/arm/mach-rockchip/pm.h b/arch/arm/mach-rockchip/pm.h
new file mode 100644
index 0000000..7d752ff
--- /dev/null
+++ b/arch/arm/mach-rockchip/pm.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Tony Xie <tony.xie@rock-chips.com>
+ *
+ * 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 __MACH_ROCKCHIP_PM_H
+#define __MACH_ROCKCHIP_PM_H
+
+extern unsigned long rkpm_bootdata_cpusp;
+extern unsigned long rkpm_bootdata_cpu_code;
+extern unsigned long rkpm_bootdata_l2ctlr_f;
+extern unsigned long rkpm_bootdata_l2ctlr;
+extern unsigned long rkpm_bootdata_ddr_code;
+extern unsigned long rkpm_bootdata_ddr_data;
+extern unsigned long rk3288_bootram_sz;
+
+void rockchip_slp_cpu_resume(void);
+void __init rockchip_suspend_init(void);
+
+/****** following is rk3288 defined **********/
+#define RK3288_PMU_WAKEUP_CFG0		0x00
+#define RK3288_PMU_WAKEUP_CFG1		0x04
+#define RK3288_PMU_PWRMODE_CON		0x18
+#define RK3288_PMU_OSC_CNT		0x20
+#define RK3288_PMU_PLL_CNT		0x24
+#define RK3288_PMU_STABL_CNT		0x28
+#define RK3288_PMU_DDR0IO_PWRON_CNT	0x2c
+#define RK3288_PMU_DDR1IO_PWRON_CNT	0x30
+#define RK3288_PMU_CORE_PWRDWN_CNT	0x34
+#define RK3288_PMU_CORE_PWRUP_CNT	0x38
+#define RK3288_PMU_GPU_PWRDWN_CNT	0x3c
+#define RK3288_PMU_GPU_PWRUP_CNT	0x40
+#define RK3288_PMU_WAKEUP_RST_CLR_CNT	0x44
+#define RK3288_PMU_PWRMODE_CON1		0x90
+
+#define RK3288_SGRF_SOC_CON0		(0x0000)
+#define RK3288_SGRF_FAST_BOOT_ADDR	(0x0120)
+#define SGRF_FAST_BOOT_EN		BIT(8)
+#define SGRF_FAST_BOOT_EN_WRITE		BIT(24)
+
+#define RK3288_CRU_MODE_CON		0x50
+#define RK3288_CRU_SEL0_CON		0x60
+#define RK3288_CRU_SEL1_CON		0x64
+#define RK3288_CRU_SEL10_CON		0x88
+#define RK3288_CRU_SEL33_CON		0xe4
+#define RK3288_CRU_SEL37_CON		0xf4
+
+/* PMU_WAKEUP_CFG1 bits */
+#define PMU_ARMINT_WAKEUP_EN		BIT(0)
+
+enum rk3288_pwr_mode_con {
+	PMU_PWR_MODE_EN = 0,
+	PMU_CLK_CORE_SRC_GATE_EN,
+	PMU_GLOBAL_INT_DISABLE,
+	PMU_L2FLUSH_EN,
+	PMU_BUS_PD_EN,
+	PMU_A12_0_PD_EN,
+	PMU_SCU_EN,
+	PMU_PLL_PD_EN,
+	PMU_CHIP_PD_EN, /* POWER OFF PIN ENABLE */
+	PMU_PWROFF_COMB,
+	PMU_ALIVE_USE_LF,
+	PMU_PMU_USE_LF,
+	PMU_OSC_24M_DIS,
+	PMU_INPUT_CLAMP_EN,
+	PMU_WAKEUP_RESET_EN,
+	PMU_SREF0_ENTER_EN,
+	PMU_SREF1_ENTER_EN,
+	PMU_DDR0IO_RET_EN,
+	PMU_DDR1IO_RET_EN,
+	PMU_DDR0_GATING_EN,
+	PMU_DDR1_GATING_EN,
+	PMU_DDR0IO_RET_DE_REQ,
+	PMU_DDR1IO_RET_DE_REQ
+};
+
+enum rk3288_pwr_mode_con1 {
+	PMU_CLR_BUS = 0,
+	PMU_CLR_CORE,
+	PMU_CLR_CPUP,
+	PMU_CLR_ALIVE,
+	PMU_CLR_DMA,
+	PMU_CLR_PERI,
+	PMU_CLR_GPU,
+	PMU_CLR_VIDEO,
+	PMU_CLR_HEVC,
+	PMU_CLR_VIO,
+};
+
+#endif /* __MACH_ROCKCHIP_PM_H */
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index a611f48..d360ec0 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -27,6 +27,7 @@
 #include <asm/mach/map.h>
 #include <asm/hardware/cache-l2x0.h>
 #include "core.h"
+#include "pm.h"
 
 #define RK3288_GRF_SOC_CON0 0x244
 
@@ -52,6 +53,7 @@
 
 static void __init rockchip_dt_init(void)
 {
+	rockchip_suspend_init();
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 	platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
 }
@@ -65,7 +67,7 @@
 	NULL,
 };
 
-DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
+DT_MACHINE_START(ROCKCHIP_DT, "Rockchip (Device Tree)")
 	.l2c_aux_val	= 0,
 	.l2c_aux_mask	= ~0,
 	.init_time	= rockchip_timer_init,
diff --git a/arch/arm/mach-rockchip/sleep.S b/arch/arm/mach-rockchip/sleep.S
new file mode 100644
index 0000000..2eec9a3
--- /dev/null
+++ b/arch/arm/mach-rockchip/sleep.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Tony Xie <tony.xie@rock-chips.com>
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+.data
+/*
+ * this code will be copied from
+ * ddr to sram for system resumeing.
+ * so it is ".data section".
+ */
+.align
+
+ENTRY(rockchip_slp_cpu_resume)
+	setmode	PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1  @ set svc, irqs off
+	mrc	p15, 0, r1, c0, c0, 5
+	and	r1, r1, #0xf
+	cmp	r1, #0
+	/* olny cpu0 can continue to run, the others is halt here */
+	beq	cpu0run
+secondary_loop:
+	wfe
+	b	secondary_loop
+cpu0run:
+	ldr	r3, rkpm_bootdata_l2ctlr_f
+	cmp	r3, #0
+	beq	sp_set
+	ldr	r3, rkpm_bootdata_l2ctlr
+	mcr	p15, 1, r3, c9, c0, 2
+sp_set:
+	ldr	sp, rkpm_bootdata_cpusp
+	ldr	r1, rkpm_bootdata_cpu_code
+	bx	r1
+ENDPROC(rockchip_slp_cpu_resume)
+
+/* Parameters filled in by the kernel */
+
+/* Flag for whether to restore L2CTLR on resume */
+	.global rkpm_bootdata_l2ctlr_f
+rkpm_bootdata_l2ctlr_f:
+	.long 0
+
+/* Saved L2CTLR to restore on resume */
+	.global rkpm_bootdata_l2ctlr
+rkpm_bootdata_l2ctlr:
+	.long 0
+
+/* CPU resume SP addr */
+	.globl rkpm_bootdata_cpusp
+rkpm_bootdata_cpusp:
+	.long 0
+
+/* CPU resume function (physical address) */
+	.globl rkpm_bootdata_cpu_code
+rkpm_bootdata_cpu_code:
+	.long 0
+
+ENTRY(rk3288_bootram_sz)
+        .word   . - rockchip_slp_cpu_resume
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
index 9eb2229..79c49ff 100644
--- a/arch/arm/mach-s3c24xx/Kconfig
+++ b/arch/arm/mach-s3c24xx/Kconfig
@@ -29,7 +29,6 @@
 	default y
 	select CPU_ARM920T
 	select S3C2410_COMMON_CLK
-	select S3C2410_DMA if S3C24XX_DMA
 	select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ
 	select S3C2410_PM if PM
 	help
@@ -40,7 +39,6 @@
 	bool "SAMSUNG S3C2412"
 	select CPU_ARM926T
 	select S3C2412_COMMON_CLK
-	select S3C2412_DMA if S3C24XX_DMA
 	select S3C2412_PM if PM
 	help
 	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
@@ -50,7 +48,6 @@
 	select CPU_ARM926T
 	select S3C2416_PM if PM
 	select S3C2443_COMMON_CLK
-	select S3C2443_DMA if S3C24XX_DMA
 	help
 	  Support for the S3C2416 SoC from the S3C24XX line
 
@@ -59,7 +56,6 @@
 	select CPU_ARM920T
 	select S3C2410_COMMON_CLK
 	select S3C2410_PM if PM
-	select S3C2440_DMA if S3C24XX_DMA
 	help
 	  Support for S3C2440 Samsung Mobile CPU based systems.
 
@@ -67,7 +63,6 @@
 	bool "SAMSUNG S3C2442"
 	select CPU_ARM920T
 	select S3C2410_COMMON_CLK
-	select S3C2410_DMA if S3C24XX_DMA
 	select S3C2410_PM if PM
 	help
 	  Support for S3C2442 Samsung Mobile CPU based systems.
@@ -80,7 +75,6 @@
 	bool "SAMSUNG S3C2443"
 	select CPU_ARM920T
 	select S3C2443_COMMON_CLK
-	select S3C2443_DMA if S3C24XX_DMA
 	help
 	  Support for the S3C2443 SoC from the S3C24XX line
 
@@ -114,27 +108,6 @@
 	help
 	  Compile in platform device definition for Samsung TouchScreen.
 
-config S3C24XX_DMA
-	bool "S3C2410 DMA support (deprecated)"
-	select S3C_DMA
-	help
-	  S3C2410 DMA support. This is needed for drivers like sound which
-	  use the S3C2410's DMA system to move data to and from the
-	  peripheral blocks.
-
-config S3C2410_DMA_DEBUG
-	bool "S3C2410 DMA support debug"
-	depends on S3C2410_DMA
-	help
-	  Enable debugging output for the DMA code. This option sends info
-	  to the kernel log, at priority KERN_DEBUG.
-
-config S3C2410_DMA
-	bool
-	depends on S3C24XX_DMA && (CPU_S3C2410 || CPU_S3C2442)
-	help
-	  DMA device selection for S3C2410 and compatible CPUs
-
 config S3C2410_PM
 	bool
 	help
@@ -325,11 +298,6 @@
 		   !CPU_S3C2442 && !CPU_S3C2443
 	default y
 
-config S3C2412_DMA
-	bool
-	help
-	  Internal config node for S3C2412 DMA support
-
 config S3C2412_PM
 	bool
 	select S3C2412_PM_SLEEP
@@ -438,11 +406,6 @@
 
 if CPU_S3C2440
 
-config S3C2440_DMA
-	bool
-	help
-	  Support for S3C2440 specific DMA code5A
-
 config S3C2440_XTAL_12000000
 	bool
 	help
@@ -601,11 +564,6 @@
 
 if CPU_S3C2443 || CPU_S3C2416
 
-config S3C2443_DMA
-	bool
-	help
-	  Internal config node for S3C2443 DMA support
-
 config S3C2443_SETUP_SPI
 	bool
 	help
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index b920716..b40a22f 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -12,12 +12,10 @@
 obj-y				+= common.o
 
 obj-$(CONFIG_CPU_S3C2410)	+= s3c2410.o
-obj-$(CONFIG_S3C2410_DMA)	+= dma-s3c2410.o
 obj-$(CONFIG_S3C2410_PLL)	+= pll-s3c2410.o
 obj-$(CONFIG_S3C2410_PM)	+= pm-s3c2410.o sleep-s3c2410.o
 
 obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
-obj-$(CONFIG_S3C2412_DMA)	+= dma-s3c2412.o
 obj-$(CONFIG_S3C2412_PM)	+= pm-s3c2412.o
 obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep-s3c2412.o
 
@@ -27,7 +25,6 @@
 obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o
 obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o
 obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o
-obj-$(CONFIG_S3C2440_DMA)	+= dma-s3c2440.o
 obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o
 obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o
 
@@ -39,15 +36,11 @@
 
 # common code
 
-obj-$(CONFIG_S3C24XX_DMA)	+= dma.o
-
 obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += cpufreq-utils.o
 
 obj-$(CONFIG_S3C2410_IOTIMING)	+= iotiming-s3c2410.o
 obj-$(CONFIG_S3C2412_IOTIMING)	+= iotiming-s3c2412.o
 
-obj-$(CONFIG_S3C2443_DMA)	+= dma-s3c2443.o
-
 #
 # machine support
 # following is ordered alphabetically by option text.
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c
deleted file mode 100644
index 09aa12d..0000000
--- a/arch/arm/mach-s3c24xx/dma-s3c2410.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 DMA selection
- *
- * http://armlinux.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/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include <plat/cpu.h>
-#include <plat/dma-s3c24xx.h>
-
-#include <mach/regs-gpio.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-lcd.h>
-#include <plat/regs-spi.h>
-
-static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
-	[DMACH_XD0] = {
-		.name		= "xdreq0",
-		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
-	},
-	[DMACH_XD1] = {
-		.name		= "xdreq1",
-		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
-	},
-	[DMACH_SDI] = {
-		.name		= "sdi",
-		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
-		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
-	},
-	[DMACH_SPI0] = {
-		.name		= "spi0",
-		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
-	},
-	[DMACH_SPI1] = {
-		.name		= "spi1",
-		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
-	},
-	[DMACH_UART0] = {
-		.name		= "uart0",
-		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
-	},
-	[DMACH_UART1] = {
-		.name		= "uart1",
-		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
-	},
-      	[DMACH_UART2] = {
-		.name		= "uart2",
-		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
-	},
-	[DMACH_TIMER] = {
-		.name		= "timer",
-		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
-		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
-	},
-	[DMACH_I2S_IN] = {
-		.name		= "i2s-sdi",
-		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
-	},
-	[DMACH_I2S_OUT] = {
-		.name		= "i2s-sdo",
-		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP1] = {
-		.name		= "usb-ep1",
-		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP2] = {
-		.name		= "usb-ep2",
-		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP3] = {
-		.name		= "usb-ep3",
-		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP4] = {
-		.name		= "usb-ep4",
-		.channels[3]	=S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
-	},
-};
-
-static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
-			       struct s3c24xx_dma_map *map)
-{
-	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
-	.select		= s3c2410_dma_select,
-	.dcon_mask	= 7 << 24,
-	.map		= s3c2410_dma_mappings,
-	.map_size	= ARRAY_SIZE(s3c2410_dma_mappings),
-};
-
-static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
-	.channels	= {
-		[DMACH_SDI]	= {
-			.list	= {
-				[0]	= 3 | DMA_CH_VALID,
-				[1]	= 2 | DMA_CH_VALID,
-				[2]	= 0 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_I2S_IN]	= {
-			.list	= {
-				[0]	= 1 | DMA_CH_VALID,
-				[1]	= 2 | DMA_CH_VALID,
-			},
-		},
-	},
-};
-
-static int __init s3c2410_dma_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	s3c2410_dma_init();
-	s3c24xx_dma_order_set(&s3c2410_dma_order);
-	return s3c24xx_dma_init_map(&s3c2410_dma_sel);
-}
-
-#if defined(CONFIG_CPU_S3C2410)
-static struct subsys_interface s3c2410_dma_interface = {
-	.name		= "s3c2410_dma",
-	.subsys		= &s3c2410_subsys,
-	.add_dev	= s3c2410_dma_add,
-};
-
-static int __init s3c2410_dma_drvinit(void)
-{
-	return subsys_interface_register(&s3c2410_dma_interface);
-}
-
-arch_initcall(s3c2410_dma_drvinit);
-
-static struct subsys_interface s3c2410a_dma_interface = {
-	.name		= "s3c2410a_dma",
-	.subsys		= &s3c2410a_subsys,
-	.add_dev	= s3c2410_dma_add,
-};
-
-static int __init s3c2410a_dma_drvinit(void)
-{
-	return subsys_interface_register(&s3c2410a_dma_interface);
-}
-
-arch_initcall(s3c2410a_dma_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2442)
-/* S3C2442 DMA contains the same selection table as the S3C2410 */
-static struct subsys_interface s3c2442_dma_interface = {
-	.name		= "s3c2442_dma",
-	.subsys		= &s3c2442_subsys,
-	.add_dev	= s3c2410_dma_add,
-};
-
-static int __init s3c2442_dma_drvinit(void)
-{
-	return subsys_interface_register(&s3c2442_dma_interface);
-}
-
-arch_initcall(s3c2442_dma_drvinit);
-#endif
-
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c
deleted file mode 100644
index 0c0106d..0000000
--- a/arch/arm/mach-s3c24xx/dma-s3c2412.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2412 DMA selection
- *
- * http://armlinux.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/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <mach/regs-gpio.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-lcd.h>
-#include <plat/regs-spi.h>
-
-#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
-
-static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
-	[DMACH_XD0] = {
-		.name		= "xdreq0",
-		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ0),
-	},
-	[DMACH_XD1] = {
-		.name		= "xdreq1",
-		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ1),
-	},
-	[DMACH_SDI] = {
-		.name		= "sdi",
-		.channels	= MAP(S3C2412_DMAREQSEL_SDI),
-	},
-	[DMACH_SPI0_RX] = {
-		.name		= "spi0-rx",
-		.channels	= MAP(S3C2412_DMAREQSEL_SPI0RX),
-	},
-	[DMACH_SPI0_TX] = {
-		.name		= "spi0-tx",
-		.channels	= MAP(S3C2412_DMAREQSEL_SPI0TX),
-	},
-	[DMACH_SPI1_RX] = {
-		.name		= "spi1-rx",
-		.channels	= MAP(S3C2412_DMAREQSEL_SPI1RX),
-	},
-	[DMACH_SPI1_TX] = {
-		.name		= "spi1-tx",
-		.channels	= MAP(S3C2412_DMAREQSEL_SPI1TX),
-	},
-	[DMACH_UART0] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART0_0),
-	},
-	[DMACH_UART1] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART1_0),
-	},
-      	[DMACH_UART2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART2_0),
-	},
-	[DMACH_UART0_SRC2] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART0_1),
-	},
-	[DMACH_UART1_SRC2] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART1_1),
-	},
-      	[DMACH_UART2_SRC2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2412_DMAREQSEL_UART2_1),
-	},
-	[DMACH_TIMER] = {
-		.name		= "timer",
-		.channels	= MAP(S3C2412_DMAREQSEL_TIMER),
-	},
-	[DMACH_I2S_IN] = {
-		.name		= "i2s-sdi",
-		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX),
-	},
-	[DMACH_I2S_OUT] = {
-		.name		= "i2s-sdo",
-		.channels	= MAP(S3C2412_DMAREQSEL_I2STX),
-	},
-	[DMACH_USB_EP1] = {
-		.name		= "usb-ep1",
-		.channels	= MAP(S3C2412_DMAREQSEL_USBEP1),
-	},
-	[DMACH_USB_EP2] = {
-		.name		= "usb-ep2",
-		.channels	= MAP(S3C2412_DMAREQSEL_USBEP2),
-	},
-	[DMACH_USB_EP3] = {
-		.name		= "usb-ep3",
-		.channels	= MAP(S3C2412_DMAREQSEL_USBEP3),
-	},
-	[DMACH_USB_EP4] = {
-		.name		= "usb-ep4",
-		.channels	= MAP(S3C2412_DMAREQSEL_USBEP4),
-	},
-};
-
-static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
-			       struct s3c24xx_dma_map *map)
-{
-	unsigned long chsel = map->channels[0] & (~DMA_CH_VALID);
-	writel(chsel | S3C2412_DMAREQSEL_HW,
-	       chan->regs + S3C2412_DMA_DMAREQSEL);
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
-	.select		= s3c2412_dma_select,
-	.dcon_mask	= 0,
-	.map		= s3c2412_dma_mappings,
-	.map_size	= ARRAY_SIZE(s3c2412_dma_mappings),
-};
-
-static int __init s3c2412_dma_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	s3c2410_dma_init();
-	return s3c24xx_dma_init_map(&s3c2412_dma_sel);
-}
-
-static struct subsys_interface s3c2412_dma_interface = {
-	.name		= "s3c2412_dma",
-	.subsys		= &s3c2412_subsys,
-	.add_dev	= s3c2412_dma_add,
-};
-
-static int __init s3c2412_dma_init(void)
-{
-	return subsys_interface_register(&s3c2412_dma_interface);
-}
-
-arch_initcall(s3c2412_dma_init);
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c
deleted file mode 100644
index 2f8e8a3..0000000
--- a/arch/arm/mach-s3c24xx/dma-s3c2440.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2440 DMA selection
- *
- * http://armlinux.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/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <mach/regs-gpio.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-lcd.h>
-#include <plat/regs-spi.h>
-
-static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
-	[DMACH_XD0] = {
-		.name		= "xdreq0",
-		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
-	},
-	[DMACH_XD1] = {
-		.name		= "xdreq1",
-		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
-	},
-	[DMACH_SDI] = {
-		.name		= "sdi",
-		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
-		.channels[1]	= S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
-		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
-	},
-	[DMACH_SPI0] = {
-		.name		= "spi0",
-		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
-	},
-	[DMACH_SPI1] = {
-		.name		= "spi1",
-		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
-	},
-	[DMACH_UART0] = {
-		.name		= "uart0",
-		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
-	},
-	[DMACH_UART1] = {
-		.name		= "uart1",
-		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
-	},
-      	[DMACH_UART2] = {
-		.name		= "uart2",
-		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
-	},
-	[DMACH_TIMER] = {
-		.name		= "timer",
-		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
-		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
-	},
-	[DMACH_I2S_IN] = {
-		.name		= "i2s-sdi",
-		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
-	},
-	[DMACH_I2S_OUT] = {
-		.name		= "i2s-sdo",
-		.channels[0]	= S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
-		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
-	},
-	[DMACH_PCM_IN] = {
-		.name		= "pcm-in",
-		.channels[0]	= S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
-		.channels[2]	= S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
-	},
-	[DMACH_PCM_OUT] = {
-		.name		= "pcm-out",
-		.channels[1]	= S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
-		.channels[3]	= S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
-	},
-	[DMACH_MIC_IN] = {
-		.name		= "mic-in",
-		.channels[2]	= S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
-		.channels[3]	= S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP1] = {
-		.name		= "usb-ep1",
-		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP2] = {
-		.name		= "usb-ep2",
-		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP3] = {
-		.name		= "usb-ep3",
-		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
-	},
-	[DMACH_USB_EP4] = {
-		.name		= "usb-ep4",
-		.channels[3]	= S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
-	},
-};
-
-static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
-			       struct s3c24xx_dma_map *map)
-{
-	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
-	.select		= s3c2440_dma_select,
-	.dcon_mask	= 7 << 24,
-	.map		= s3c2440_dma_mappings,
-	.map_size	= ARRAY_SIZE(s3c2440_dma_mappings),
-};
-
-static struct s3c24xx_dma_order __initdata s3c2440_dma_order = {
-	.channels	= {
-		[DMACH_SDI]	= {
-			.list	= {
-				[0]	= 3 | DMA_CH_VALID,
-				[1]	= 2 | DMA_CH_VALID,
-				[2]	= 1 | DMA_CH_VALID,
-				[3]	= 0 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_I2S_IN]	= {
-			.list	= {
-				[0]	= 1 | DMA_CH_VALID,
-				[1]	= 2 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_I2S_OUT]	= {
-			.list	= {
-				[0]	= 2 | DMA_CH_VALID,
-				[1]	= 1 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_PCM_IN] = {
-			.list	= {
-				[0]	= 2 | DMA_CH_VALID,
-				[1]	= 1 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_PCM_OUT] = {
-			.list	= {
-				[0]	= 1 | DMA_CH_VALID,
-				[1]	= 3 | DMA_CH_VALID,
-			},
-		},
-		[DMACH_MIC_IN] = {
-			.list	= {
-				[0]	= 3 | DMA_CH_VALID,
-				[1]	= 2 | DMA_CH_VALID,
-			},
-		},
-	},
-};
-
-static int __init s3c2440_dma_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	s3c2410_dma_init();
-	s3c24xx_dma_order_set(&s3c2440_dma_order);
-	return s3c24xx_dma_init_map(&s3c2440_dma_sel);
-}
-
-static struct subsys_interface s3c2440_dma_interface = {
-	.name		= "s3c2440_dma",
-	.subsys		= &s3c2440_subsys,
-	.add_dev	= s3c2440_dma_add,
-};
-
-static int __init s3c2440_dma_init(void)
-{
-	return subsys_interface_register(&s3c2440_dma_interface);
-}
-
-arch_initcall(s3c2440_dma_init);
-
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c
deleted file mode 100644
index f4096ec..0000000
--- a/arch/arm/mach-s3c24xx/dma-s3c2443.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/dma.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 DMA selection
- *
- * http://armlinux.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/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial_s3c.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <mach/regs-gpio.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-lcd.h>
-#include <plat/regs-spi.h>
-
-#define MAP(x) { \
-		[0]	= (x) | DMA_CH_VALID,	\
-		[1]	= (x) | DMA_CH_VALID,	\
-		[2]	= (x) | DMA_CH_VALID,	\
-		[3]	= (x) | DMA_CH_VALID,	\
-		[4]	= (x) | DMA_CH_VALID,	\
-		[5]     = (x) | DMA_CH_VALID,	\
-	}
-
-static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
-	[DMACH_XD0] = {
-		.name		= "xdreq0",
-		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ0),
-	},
-	[DMACH_XD1] = {
-		.name		= "xdreq1",
-		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ1),
-	},
-	[DMACH_SDI] = { /* only on S3C2443 */
-		.name		= "sdi",
-		.channels	= MAP(S3C2443_DMAREQSEL_SDI),
-	},
-	[DMACH_SPI0_RX] = {
-		.name		= "spi0-rx",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI0RX),
-	},
-	[DMACH_SPI0_TX] = {
-		.name		= "spi0-tx",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI0TX),
-	},
-	[DMACH_SPI1_RX] = { /* only on S3C2443/S3C2450 */
-		.name		= "spi1-rx",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI1RX),
-	},
-	[DMACH_SPI1_TX] = { /* only on S3C2443/S3C2450 */
-		.name		= "spi1-tx",
-		.channels	= MAP(S3C2443_DMAREQSEL_SPI1TX),
-	},
-	[DMACH_UART0] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART0_0),
-	},
-	[DMACH_UART1] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART1_0),
-	},
-	[DMACH_UART2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART2_0),
-	},
-	[DMACH_UART3] = {
-		.name		= "uart3",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART3_0),
-	},
-	[DMACH_UART0_SRC2] = {
-		.name		= "uart0",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART0_1),
-	},
-	[DMACH_UART1_SRC2] = {
-		.name		= "uart1",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART1_1),
-	},
-	[DMACH_UART2_SRC2] = {
-		.name		= "uart2",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART2_1),
-	},
-	[DMACH_UART3_SRC2] = {
-		.name		= "uart3",
-		.channels	= MAP(S3C2443_DMAREQSEL_UART3_1),
-	},
-	[DMACH_TIMER] = {
-		.name		= "timer",
-		.channels	= MAP(S3C2443_DMAREQSEL_TIMER),
-	},
-	[DMACH_I2S_IN] = {
-		.name		= "i2s-sdi",
-		.channels	= MAP(S3C2443_DMAREQSEL_I2SRX),
-	},
-	[DMACH_I2S_OUT] = {
-		.name		= "i2s-sdo",
-		.channels	= MAP(S3C2443_DMAREQSEL_I2STX),
-	},
-	[DMACH_PCM_IN] = {
-		.name		= "pcm-in",
-		.channels	= MAP(S3C2443_DMAREQSEL_PCMIN),
-	},
-	[DMACH_PCM_OUT] = {
-		.name		= "pcm-out",
-		.channels	= MAP(S3C2443_DMAREQSEL_PCMOUT),
-	},
-	[DMACH_MIC_IN] = {
-		.name		= "mic-in",
-		.channels	= MAP(S3C2443_DMAREQSEL_MICIN),
-	},
-};
-
-static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
-			       struct s3c24xx_dma_map *map)
-{
-	unsigned long chsel = map->channels[0] & (~DMA_CH_VALID);
-	writel(chsel | S3C2443_DMAREQSEL_HW,
-	       chan->regs + S3C2443_DMA_DMAREQSEL);
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
-	.select		= s3c2443_dma_select,
-	.dcon_mask	= 0,
-	.map		= s3c2443_dma_mappings,
-	.map_size	= ARRAY_SIZE(s3c2443_dma_mappings),
-};
-
-static int __init s3c2443_dma_add(struct device *dev,
-				  struct subsys_interface *sif)
-{
-	s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
-	return s3c24xx_dma_init_map(&s3c2443_dma_sel);
-}
-
-#ifdef CONFIG_CPU_S3C2416
-/* S3C2416 DMA contains the same selection table as the S3C2443 */
-static struct subsys_interface s3c2416_dma_interface = {
-	.name		= "s3c2416_dma",
-	.subsys		= &s3c2416_subsys,
-	.add_dev	= s3c2443_dma_add,
-};
-
-static int __init s3c2416_dma_init(void)
-{
-	return subsys_interface_register(&s3c2416_dma_interface);
-}
-
-arch_initcall(s3c2416_dma_init);
-#endif
-
-#ifdef CONFIG_CPU_S3C2443
-static struct subsys_interface s3c2443_dma_interface = {
-	.name		= "s3c2443_dma",
-	.subsys		= &s3c2443_subsys,
-	.add_dev	= s3c2443_dma_add,
-};
-
-static int __init s3c2443_dma_init(void)
-{
-	return subsys_interface_register(&s3c2443_dma_interface);
-}
-
-arch_initcall(s3c2443_dma_init);
-#endif
diff --git a/arch/arm/mach-s3c24xx/dma.c b/arch/arm/mach-s3c24xx/dma.c
deleted file mode 100644
index a8dafc1..0000000
--- a/arch/arm/mach-s3c24xx/dma.c
+++ /dev/null
@@ -1,1465 +0,0 @@
-/*
- * Copyright 2003-2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 DMA core
- *
- * http://armlinux.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.
-*/
-
-
-#ifdef CONFIG_S3C2410_DMA_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/syscore_ops.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/map.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/regs-dma.h>
-
-/* io map for dma */
-static void __iomem *dma_base;
-static struct kmem_cache *dma_kmem;
-
-static int dma_channels;
-
-static struct s3c24xx_dma_selection dma_sel;
-
-
-/* debugging functions */
-
-#define BUF_MAGIC (0xcafebabe)
-
-#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
-
-#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
-
-#if 1
-#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
-#else
-static inline void
-dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
-{
-	pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
-	writel(val, dma_regaddr(chan, reg));
-}
-#endif
-
-#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
-
-/* captured register state for debug */
-
-struct s3c2410_dma_regstate {
-	unsigned long         dcsrc;
-	unsigned long         disrc;
-	unsigned long         dstat;
-	unsigned long         dcon;
-	unsigned long         dmsktrig;
-};
-
-#ifdef CONFIG_S3C2410_DMA_DEBUG
-
-/* dmadbg_showregs
- *
- * simple debug routine to print the current state of the dma registers
-*/
-
-static void
-dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
-{
-	regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC);
-	regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC);
-	regs->dstat    = dma_rdreg(chan, S3C2410_DMA_DSTAT);
-	regs->dcon     = dma_rdreg(chan, S3C2410_DMA_DCON);
-	regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-}
-
-static void
-dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
-		 struct s3c2410_dma_regstate *regs)
-{
-	printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
-	       chan->number, fname, line,
-	       regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
-	       regs->dcon);
-}
-
-static void
-dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
-{
-	struct s3c2410_dma_regstate state;
-
-	dmadbg_capture(chan, &state);
-
-	printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
-	       chan->number, fname, line, chan->load_state,
-	       chan->curr, chan->next, chan->end);
-
-	dmadbg_dumpregs(fname, line, chan, &state);
-}
-
-static void
-dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
-{
-	struct s3c2410_dma_regstate state;
-
-	dmadbg_capture(chan, &state);
-	dmadbg_dumpregs(fname, line, chan, &state);
-}
-
-#define dbg_showregs(chan) dmadbg_showregs(__func__, __LINE__, (chan))
-#define dbg_showchan(chan) dmadbg_showchan(__func__, __LINE__, (chan))
-#else
-#define dbg_showregs(chan) do { } while(0)
-#define dbg_showchan(chan) do { } while(0)
-#endif /* CONFIG_S3C2410_DMA_DEBUG */
-
-/* s3c2410_dma_stats_timeout
- *
- * Update DMA stats from timeout info
-*/
-
-static void
-s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
-{
-	if (stats == NULL)
-		return;
-
-	if (val > stats->timeout_longest)
-		stats->timeout_longest = val;
-	if (val < stats->timeout_shortest)
-		stats->timeout_shortest = val;
-
-	stats->timeout_avg += val;
-}
-
-/* s3c2410_dma_waitforload
- *
- * wait for the DMA engine to load a buffer, and update the state accordingly
-*/
-
-static int
-s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
-{
-	int timeout = chan->load_timeout;
-	int took;
-
-	if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
-		printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
-		return 0;
-	}
-
-	if (chan->stats != NULL)
-		chan->stats->loads++;
-
-	while (--timeout > 0) {
-		if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
-			took = chan->load_timeout - timeout;
-
-			s3c2410_dma_stats_timeout(chan->stats, took);
-
-			switch (chan->load_state) {
-			case S3C2410_DMALOAD_1LOADED:
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				break;
-
-			default:
-				printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
-			}
-
-			return 1;
-		}
-	}
-
-	if (chan->stats != NULL) {
-		chan->stats->timeout_failed++;
-	}
-
-	return 0;
-}
-
-/* s3c2410_dma_loadbuffer
- *
- * load a buffer, and update the channel state
-*/
-
-static inline int
-s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
-		       struct s3c2410_dma_buf *buf)
-{
-	unsigned long reload;
-
-	if (buf == NULL) {
-		dmawarn("buffer is NULL\n");
-		return -EINVAL;
-	}
-
-	pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
-		 buf, (unsigned long)buf->data, buf->size);
-
-	/* check the state of the channel before we do anything */
-
-	if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
-	}
-
-	if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
-		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
-	}
-
-	/* it would seem sensible if we are the last buffer to not bother
-	 * with the auto-reload bit, so that the DMA engine will not try
-	 * and load another transfer after this one has finished...
-	 */
-	if (chan->load_state == S3C2410_DMALOAD_NONE) {
-		pr_debug("load_state is none, checking for noreload (next=%p)\n",
-			 buf->next);
-		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
-	} else {
-		//pr_debug("load_state is %d => autoreload\n", chan->load_state);
-		reload = S3C2410_DCON_AUTORELOAD;
-	}
-
-	if ((buf->data & 0xf0000000) != 0x30000000) {
-		dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
-	}
-
-	writel(buf->data, chan->addr_reg);
-
-	dma_wrreg(chan, S3C2410_DMA_DCON,
-		  chan->dcon | reload | (buf->size/chan->xfer_unit));
-
-	chan->next = buf->next;
-
-	/* update the state of the channel */
-
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_NONE:
-		chan->load_state = S3C2410_DMALOAD_1LOADED;
-		break;
-
-	case S3C2410_DMALOAD_1RUNNING:
-		chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
-		break;
-
-	default:
-		dmawarn("dmaload: unknown state %d in loadbuffer\n",
-			chan->load_state);
-		break;
-	}
-
-	return 0;
-}
-
-/* s3c2410_dma_call_op
- *
- * small routine to call the op routine with the given op if it has been
- * registered
-*/
-
-static void
-s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
-{
-	if (chan->op_fn != NULL) {
-		(chan->op_fn)(chan, op);
-	}
-}
-
-/* s3c2410_dma_buffdone
- *
- * small wrapper to check if callback routine needs to be called, and
- * if so, call it
-*/
-
-static inline void
-s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
-		     enum s3c2410_dma_buffresult result)
-{
-#if 0
-	pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
-		 chan->callback_fn, buf, buf->id, buf->size, result);
-#endif
-
-	if (chan->callback_fn != NULL) {
-		(chan->callback_fn)(chan, buf->id, buf->size, result);
-	}
-}
-
-/* s3c2410_dma_start
- *
- * start a dma channel going
-*/
-
-static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
-{
-	unsigned long tmp;
-	unsigned long flags;
-
-	pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
-
-	local_irq_save(flags);
-
-	if (chan->state == S3C2410_DMA_RUNNING) {
-		pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
-		local_irq_restore(flags);
-		return 0;
-	}
-
-	chan->state = S3C2410_DMA_RUNNING;
-
-	/* check whether there is anything to load, and if not, see
-	 * if we can find anything to load
-	 */
-
-	if (chan->load_state == S3C2410_DMALOAD_NONE) {
-		if (chan->next == NULL) {
-			printk(KERN_ERR "dma%d: channel has nothing loaded\n",
-			       chan->number);
-			chan->state = S3C2410_DMA_IDLE;
-			local_irq_restore(flags);
-			return -EINVAL;
-		}
-
-		s3c2410_dma_loadbuffer(chan, chan->next);
-	}
-
-	dbg_showchan(chan);
-
-	/* enable the channel */
-
-	if (!chan->irq_enabled) {
-		enable_irq(chan->irq);
-		chan->irq_enabled = 1;
-	}
-
-	/* start the channel going */
-
-	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-	tmp &= ~S3C2410_DMASKTRIG_STOP;
-	tmp |= S3C2410_DMASKTRIG_ON;
-	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
-
-	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
-
-#if 0
-	/* the dma buffer loads should take care of clearing the AUTO
-	 * reloading feature */
-	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
-	tmp &= ~S3C2410_DCON_NORELOAD;
-	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-#endif
-
-	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
-
-	dbg_showchan(chan);
-
-	/* if we've only loaded one buffer onto the channel, then chec
-	 * to see if we have another, and if so, try and load it so when
-	 * the first buffer is finished, the new one will be loaded onto
-	 * the channel */
-
-	if (chan->next != NULL) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				pr_debug("%s: buff not yet loaded, no more todo\n",
-					 __func__);
-			} else {
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				s3c2410_dma_loadbuffer(chan, chan->next);
-			}
-
-		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	}
-
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-/* s3c2410_dma_canload
- *
- * work out if we can queue another buffer into the DMA engine
-*/
-
-static int
-s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
-{
-	if (chan->load_state == S3C2410_DMALOAD_NONE ||
-	    chan->load_state == S3C2410_DMALOAD_1RUNNING)
-		return 1;
-
-	return 0;
-}
-
-/* s3c2410_dma_enqueue
- *
- * queue an given buffer for dma transfer.
- *
- * id         the device driver's id information for this buffer
- * data       the physical address of the buffer data
- * size       the size of the buffer in bytes
- *
- * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
- * is checked, and if set, the channel is started. If this flag isn't set,
- * then an error will be returned.
- *
- * It is possible to queue more than one DMA buffer onto a channel at
- * once, and the code will deal with the re-loading of the next buffer
- * when necessary.
-*/
-
-int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
-			dma_addr_t data, int size)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	struct s3c2410_dma_buf *buf;
-	unsigned long flags;
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: id=%p, data=%08x, size=%d\n",
-		 __func__, id, (unsigned int)data, size);
-
-	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
-	if (buf == NULL) {
-		pr_debug("%s: out of memory (%ld alloc)\n",
-			 __func__, (long)sizeof(*buf));
-		return -ENOMEM;
-	}
-
-	//pr_debug("%s: new buffer %p\n", __func__, buf);
-	//dbg_showchan(chan);
-
-	buf->next  = NULL;
-	buf->data  = buf->ptr = data;
-	buf->size  = size;
-	buf->id    = id;
-	buf->magic = BUF_MAGIC;
-
-	local_irq_save(flags);
-
-	if (chan->curr == NULL) {
-		/* we've got nothing loaded... */
-		pr_debug("%s: buffer %p queued onto empty channel\n",
-			 __func__, buf);
-
-		chan->curr = buf;
-		chan->end  = buf;
-		chan->next = NULL;
-	} else {
-		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
-			 chan->number, __func__, buf);
-
-		if (chan->end == NULL) {
-			pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
-				 chan->number, __func__, chan);
-		} else {
-			chan->end->next = buf;
-			chan->end = buf;
-		}
-	}
-
-	/* if necessary, update the next buffer field */
-	if (chan->next == NULL)
-		chan->next = buf;
-
-	/* check to see if we can load a buffer */
-	if (chan->state == S3C2410_DMA_RUNNING) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				printk(KERN_ERR "dma%d: loadbuffer:"
-				       "timeout loading buffer\n",
-				       chan->number);
-				dbg_showchan(chan);
-				local_irq_restore(flags);
-				return -EINVAL;
-			}
-		}
-
-		while (s3c2410_dma_canload(chan) && chan->next != NULL) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	} else if (chan->state == S3C2410_DMA_IDLE) {
-		if (chan->flags & S3C2410_DMAF_AUTOSTART) {
-			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
-					 S3C2410_DMAOP_START);
-		}
-	}
-
-	local_irq_restore(flags);
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_enqueue);
-
-static inline void
-s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
-{
-	int magicok = (buf->magic == BUF_MAGIC);
-
-	buf->magic = -1;
-
-	if (magicok) {
-		kmem_cache_free(dma_kmem, buf);
-	} else {
-		printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
-	}
-}
-
-/* s3c2410_dma_lastxfer
- *
- * called when the system is out of buffers, to ensure that the channel
- * is prepared for shutdown.
-*/
-
-static inline void
-s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
-{
-#if 0
-	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
-		 chan->number, chan->load_state);
-#endif
-
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_NONE:
-		break;
-
-	case S3C2410_DMALOAD_1LOADED:
-		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				/* flag error? */
-			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
-			       chan->number, __func__);
-			return;
-		}
-		break;
-
-	case S3C2410_DMALOAD_1LOADED_1RUNNING:
-		/* I believe in this case we do not have anything to do
-		 * until the next buffer comes along, and we turn off the
-		 * reload */
-		return;
-
-	default:
-		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
-			 chan->number, chan->load_state);
-		return;
-
-	}
-
-	/* hopefully this'll shut the damned thing up after the transfer... */
-	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
-}
-
-
-#define dmadbg2(x...)
-
-static irqreturn_t
-s3c2410_dma_irq(int irq, void *devpw)
-{
-	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
-	struct s3c2410_dma_buf  *buf;
-
-	buf = chan->curr;
-
-	dbg_showchan(chan);
-
-	/* modify the channel state */
-
-	switch (chan->load_state) {
-	case S3C2410_DMALOAD_1RUNNING:
-		/* TODO - if we are running only one buffer, we probably
-		 * want to reload here, and then worry about the buffer
-		 * callback */
-
-		chan->load_state = S3C2410_DMALOAD_NONE;
-		break;
-
-	case S3C2410_DMALOAD_1LOADED:
-		/* iirc, we should go back to NONE loaded here, we
-		 * had a buffer, and it was never verified as being
-		 * loaded.
-		 */
-
-		chan->load_state = S3C2410_DMALOAD_NONE;
-		break;
-
-	case S3C2410_DMALOAD_1LOADED_1RUNNING:
-		/* we'll worry about checking to see if another buffer is
-		 * ready after we've called back the owner. This should
-		 * ensure we do not wait around too long for the DMA
-		 * engine to start the next transfer
-		 */
-
-		chan->load_state = S3C2410_DMALOAD_1LOADED;
-		break;
-
-	case S3C2410_DMALOAD_NONE:
-		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
-		       chan->number);
-		break;
-
-	default:
-		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
-		       chan->number, chan->load_state);
-		break;
-	}
-
-	if (buf != NULL) {
-		/* update the chain to make sure that if we load any more
-		 * buffers when we call the callback function, things should
-		 * work properly */
-
-		chan->curr = buf->next;
-		buf->next  = NULL;
-
-		if (buf->magic != BUF_MAGIC) {
-			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
-			       chan->number, __func__, buf);
-			return IRQ_HANDLED;
-		}
-
-		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
-
-		/* free resouces */
-		s3c2410_dma_freebuf(buf);
-	} else {
-	}
-
-	/* only reload if the channel is still running... our buffer done
-	 * routine may have altered the state by requesting the dma channel
-	 * to stop or shutdown... */
-
-	/* todo: check that when the channel is shut-down from inside this
-	 * function, we cope with unsetting reload, etc */
-
-	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
-		unsigned long flags;
-
-		switch (chan->load_state) {
-		case S3C2410_DMALOAD_1RUNNING:
-			/* don't need to do anything for this state */
-			break;
-
-		case S3C2410_DMALOAD_NONE:
-			/* can load buffer immediately */
-			break;
-
-		case S3C2410_DMALOAD_1LOADED:
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				/* flag error? */
-				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
-				       chan->number, __func__);
-				return IRQ_HANDLED;
-			}
-
-			break;
-
-		case S3C2410_DMALOAD_1LOADED_1RUNNING:
-			goto no_load;
-
-		default:
-			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
-			       chan->number, chan->load_state);
-			return IRQ_HANDLED;
-		}
-
-		local_irq_save(flags);
-		s3c2410_dma_loadbuffer(chan, chan->next);
-		local_irq_restore(flags);
-	} else {
-		s3c2410_dma_lastxfer(chan);
-
-		/* see if we can stop this channel.. */
-		if (chan->load_state == S3C2410_DMALOAD_NONE) {
-			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
-				 chan->number, jiffies);
-			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
-					 S3C2410_DMAOP_STOP);
-		}
-	}
-
- no_load:
-	return IRQ_HANDLED;
-}
-
-static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
-
-/* s3c2410_request_dma
- *
- * get control of an dma channel
-*/
-
-int s3c2410_dma_request(enum dma_ch channel,
-			struct s3c2410_dma_client *client,
-			void *dev)
-{
-	struct s3c2410_dma_chan *chan;
-	unsigned long flags;
-	int err;
-
-	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
-		 channel, client->name, dev);
-
-	local_irq_save(flags);
-
-	chan = s3c2410_dma_map_channel(channel);
-	if (chan == NULL) {
-		local_irq_restore(flags);
-		return -EBUSY;
-	}
-
-	dbg_showchan(chan);
-
-	chan->client = client;
-	chan->in_use = 1;
-
-	if (!chan->irq_claimed) {
-		pr_debug("dma%d: %s : requesting irq %d\n",
-			 channel, __func__, chan->irq);
-
-		chan->irq_claimed = 1;
-		local_irq_restore(flags);
-
-		err = request_irq(chan->irq, s3c2410_dma_irq, 0,
-				  client->name, (void *)chan);
-
-		local_irq_save(flags);
-
-		if (err) {
-			chan->in_use = 0;
-			chan->irq_claimed = 0;
-			local_irq_restore(flags);
-
-			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
-			       client->name, chan->irq, chan->number);
-			return err;
-		}
-
-		chan->irq_enabled = 1;
-	}
-
-	local_irq_restore(flags);
-
-	/* need to setup */
-
-	pr_debug("%s: channel initialised, %p\n", __func__, chan);
-
-	return chan->number | DMACH_LOW_LEVEL;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_request);
-
-/* s3c2410_dma_free
- *
- * release the given channel back to the system, will stop and flush
- * any outstanding transfers, and ensure the channel is ready for the
- * next claimant.
- *
- * Note, although a warning is currently printed if the freeing client
- * info is not the same as the registrant's client info, the free is still
- * allowed to go through.
-*/
-
-int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	unsigned long flags;
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	local_irq_save(flags);
-
-	if (chan->client != client) {
-		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
-		       channel, chan->client, client);
-	}
-
-	/* sort out stopping and freeing the channel */
-
-	if (chan->state != S3C2410_DMA_IDLE) {
-		pr_debug("%s: need to stop dma channel %p\n",
-		       __func__, chan);
-
-		/* possibly flush the channel */
-		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
-	}
-
-	chan->client = NULL;
-	chan->in_use = 0;
-
-	if (chan->irq_claimed)
-		free_irq(chan->irq, (void *)chan);
-
-	chan->irq_claimed = 0;
-
-	if (!(channel & DMACH_LOW_LEVEL))
-		s3c_dma_chan_map[channel] = NULL;
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_free);
-
-static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
-{
-	unsigned long flags;
-	unsigned long tmp;
-
-	pr_debug("%s:\n", __func__);
-
-	dbg_showchan(chan);
-
-	local_irq_save(flags);
-
-	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);
-
-	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-	tmp |= S3C2410_DMASKTRIG_STOP;
-	//tmp &= ~S3C2410_DMASKTRIG_ON;
-	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
-
-#if 0
-	/* should also clear interrupts, according to WinCE BSP */
-	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
-	tmp |= S3C2410_DCON_NORELOAD;
-	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-#endif
-
-	/* should stop do this, or should we wait for flush? */
-	chan->state      = S3C2410_DMA_IDLE;
-	chan->load_state = S3C2410_DMALOAD_NONE;
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
-{
-	unsigned long tmp;
-	unsigned int timeout = 0x10000;
-
-	while (timeout-- > 0) {
-		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-
-		if (!(tmp & S3C2410_DMASKTRIG_ON))
-			return;
-	}
-
-	pr_debug("dma%d: failed to stop?\n", chan->number);
-}
-
-
-/* s3c2410_dma_flush
- *
- * stop the channel, and remove all current and pending transfers
-*/
-
-static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
-{
-	struct s3c2410_dma_buf *buf, *next;
-	unsigned long flags;
-
-	pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);
-
-	dbg_showchan(chan);
-
-	local_irq_save(flags);
-
-	if (chan->state != S3C2410_DMA_IDLE) {
-		pr_debug("%s: stopping channel...\n", __func__ );
-		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
-	}
-
-	buf = chan->curr;
-	if (buf == NULL)
-		buf = chan->next;
-
-	chan->curr = chan->next = chan->end = NULL;
-
-	if (buf != NULL) {
-		for ( ; buf != NULL; buf = next) {
-			next = buf->next;
-
-			pr_debug("%s: free buffer %p, next %p\n",
-			       __func__, buf, buf->next);
-
-			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
-			s3c2410_dma_freebuf(buf);
-		}
-	}
-
-	dbg_showregs(chan);
-
-	s3c2410_dma_waitforstop(chan);
-
-#if 0
-	/* should also clear interrupts, according to WinCE BSP */
-	{
-		unsigned long tmp;
-
-		tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
-		tmp |= S3C2410_DCON_NORELOAD;
-		dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-	}
-#endif
-
-	dbg_showregs(chan);
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	dbg_showchan(chan);
-
-	/* if we've only loaded one buffer onto the channel, then chec
-	 * to see if we have another, and if so, try and load it so when
-	 * the first buffer is finished, the new one will be loaded onto
-	 * the channel */
-
-	if (chan->next != NULL) {
-		if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
-			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
-				pr_debug("%s: buff not yet loaded, no more todo\n",
-					 __func__);
-			} else {
-				chan->load_state = S3C2410_DMALOAD_1RUNNING;
-				s3c2410_dma_loadbuffer(chan, chan->next);
-			}
-
-		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
-			s3c2410_dma_loadbuffer(chan, chan->next);
-		}
-	}
-
-
-	local_irq_restore(flags);
-
-	return 0;
-
-}
-
-int
-s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	switch (op) {
-	case S3C2410_DMAOP_START:
-		return s3c2410_dma_start(chan);
-
-	case S3C2410_DMAOP_STOP:
-		return s3c2410_dma_dostop(chan);
-
-	case S3C2410_DMAOP_PAUSE:
-	case S3C2410_DMAOP_RESUME:
-		return -ENOENT;
-
-	case S3C2410_DMAOP_FLUSH:
-		return s3c2410_dma_flush(chan);
-
-	case S3C2410_DMAOP_STARTED:
-		return s3c2410_dma_started(chan);
-
-	case S3C2410_DMAOP_TIMEOUT:
-		return 0;
-
-	}
-
-	return -ENOENT;      /* unknown, don't bother */
-}
-
-EXPORT_SYMBOL(s3c2410_dma_ctrl);
-
-/* DMA configuration for each channel
- *
- * DISRCC -> source of the DMA (AHB,APB)
- * DISRC  -> source address of the DMA
- * DIDSTC -> destination of the DMA (AHB,APD)
- * DIDST  -> destination address of the DMA
-*/
-
-/* s3c2410_dma_config
- *
- * xfersize:     size of unit in bytes (1,2,4)
-*/
-
-int s3c2410_dma_config(enum dma_ch channel,
-		       int xferunit)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	unsigned int dcon;
-
-	pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	dcon = chan->dcon & dma_sel.dcon_mask;
-	pr_debug("%s: dcon is %08x\n", __func__, dcon);
-
-	switch (chan->req_ch) {
-	case DMACH_I2S_IN:
-	case DMACH_I2S_OUT:
-	case DMACH_PCM_IN:
-	case DMACH_PCM_OUT:
-	case DMACH_MIC_IN:
-	default:
-		dcon |= S3C2410_DCON_HANDSHAKE;
-		dcon |= S3C2410_DCON_SYNC_PCLK;
-		break;
-
-	case DMACH_SDI:
-		/* note, ensure if need HANDSHAKE or not */
-		dcon |= S3C2410_DCON_SYNC_PCLK;
-		break;
-
-	case DMACH_XD0:
-	case DMACH_XD1:
-		dcon |= S3C2410_DCON_HANDSHAKE;
-		dcon |= S3C2410_DCON_SYNC_HCLK;
-		break;
-	}
-
-	switch (xferunit) {
-	case 1:
-		dcon |= S3C2410_DCON_BYTE;
-		break;
-
-	case 2:
-		dcon |= S3C2410_DCON_HALFWORD;
-		break;
-
-	case 4:
-		dcon |= S3C2410_DCON_WORD;
-		break;
-
-	default:
-		pr_debug("%s: bad transfer size %d\n", __func__, xferunit);
-		return -EINVAL;
-	}
-
-	dcon |= S3C2410_DCON_HWTRIG;
-	dcon |= S3C2410_DCON_INTREQ;
-
-	pr_debug("%s: dcon now %08x\n", __func__, dcon);
-
-	chan->dcon = dcon;
-	chan->xfer_unit = xferunit;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_config);
-
-
-/* s3c2410_dma_devconfig
- *
- * configure the dma source/destination hardware type and address
- *
- * source:    DMA_FROM_DEVICE: source is hardware
- *            DMA_TO_DEVICE: source is memory
- *
- * devaddr:   physical address of the source
-*/
-
-int s3c2410_dma_devconfig(enum dma_ch channel,
-			  enum dma_data_direction source,
-			  unsigned long devaddr)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-	unsigned int hwcfg;
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: source=%d, devaddr=%08lx\n",
-		 __func__, (int)source, devaddr);
-
-	chan->source = source;
-	chan->dev_addr = devaddr;
-
-	switch (chan->req_ch) {
-	case DMACH_XD0:
-	case DMACH_XD1:
-		hwcfg = 0; /* AHB */
-		break;
-
-	default:
-		hwcfg = S3C2410_DISRCC_APB;
-	}
-
-	/* always assume our peripheral desintation is a fixed
-	 * address in memory. */
-	 hwcfg |= S3C2410_DISRCC_INC;
-
-	switch (source) {
-	case DMA_FROM_DEVICE:
-		/* source is hardware */
-		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
-			 __func__, devaddr, hwcfg);
-		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
-		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
-		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
-
-		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
-		break;
-
-	case DMA_TO_DEVICE:
-		/* source is memory */
-		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
-			 __func__, devaddr, hwcfg);
-		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
-		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
-		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
-
-		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
-		break;
-
-	default:
-		printk(KERN_ERR "dma%d: invalid source type (%d)\n",
-		       channel, source);
-
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_devconfig);
-
-/* s3c2410_dma_getposition
- *
- * returns the current transfer points for the dma source and destination
-*/
-
-int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	if (src != NULL)
- 		*src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
-
- 	if (dst != NULL)
- 		*dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
-
- 	return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_getposition);
-
-/* system core operations */
-
-#ifdef CONFIG_PM
-
-static void s3c2410_dma_suspend_chan(struct s3c2410_dma_chan *cp)
-{
-	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
-
-	if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
-		/* the dma channel is still working, which is probably
-		 * a bad thing to do over suspend/resume. We stop the
-		 * channel and assume that the client is either going to
-		 * retry after resume, or that it is broken.
-		 */
-
-		printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
-		       cp->number);
-
-		s3c2410_dma_dostop(cp);
-	}
-}
-
-static int s3c2410_dma_suspend(void)
-{
-	struct s3c2410_dma_chan *cp = s3c2410_chans;
-	int channel;
-
-	for (channel = 0; channel < dma_channels; cp++, channel++)
-		s3c2410_dma_suspend_chan(cp);
-
-	return 0;
-}
-
-static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
-{
-	unsigned int no = cp->number | DMACH_LOW_LEVEL;
-
-	/* restore channel's hardware configuration */
-
-	if (!cp->in_use)
-		return;
-
-	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
-
-	s3c2410_dma_config(no, cp->xfer_unit);
-	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
-
-	/* re-select the dma source for this channel */
-
-	if (cp->map != NULL)
-		dma_sel.select(cp, cp->map);
-}
-
-static void s3c2410_dma_resume(void)
-{
-	struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
-	int channel;
-
-	for (channel = dma_channels - 1; channel >= 0; cp--, channel--)
-		s3c2410_dma_resume_chan(cp);
-}
-
-#else
-#define s3c2410_dma_suspend NULL
-#define s3c2410_dma_resume  NULL
-#endif /* CONFIG_PM */
-
-struct syscore_ops dma_syscore_ops = {
-	.suspend	= s3c2410_dma_suspend,
-	.resume		= s3c2410_dma_resume,
-};
-
-/* kmem cache implementation */
-
-static void s3c2410_dma_cache_ctor(void *p)
-{
-	memset(p, 0, sizeof(struct s3c2410_dma_buf));
-}
-
-/* initialisation code */
-
-static int __init s3c24xx_dma_syscore_init(void)
-{
-	register_syscore_ops(&dma_syscore_ops);
-
-	return 0;
-}
-
-late_initcall(s3c24xx_dma_syscore_init);
-
-int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
-			    unsigned int stride)
-{
-	struct s3c2410_dma_chan *cp;
-	int channel;
-	int ret;
-
-	printk("S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics\n");
-
-	dma_channels = channels;
-
-	dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);
-	if (dma_base == NULL) {
-		printk(KERN_ERR "dma failed to remap register block\n");
-		return -ENOMEM;
-	}
-
-	dma_kmem = kmem_cache_create("dma_desc",
-				     sizeof(struct s3c2410_dma_buf), 0,
-				     SLAB_HWCACHE_ALIGN,
-				     s3c2410_dma_cache_ctor);
-
-	if (dma_kmem == NULL) {
-		printk(KERN_ERR "dma failed to make kmem cache\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	for (channel = 0; channel < channels;  channel++) {
-		cp = &s3c2410_chans[channel];
-
-		memset(cp, 0, sizeof(struct s3c2410_dma_chan));
-
-		/* dma channel irqs are in order.. */
-		cp->number = channel;
-		cp->irq    = channel + irq;
-		cp->regs   = dma_base + (channel * stride);
-
-		/* point current stats somewhere */
-		cp->stats  = &cp->stats_store;
-		cp->stats_store.timeout_shortest = LONG_MAX;
-
-		/* basic channel configuration */
-
-		cp->load_timeout = 1<<18;
-
-		printk("DMA channel %d at %p, irq %d\n",
-		       cp->number, cp->regs, cp->irq);
-	}
-
-	return 0;
-
- err:
-	kmem_cache_destroy(dma_kmem);
-	iounmap(dma_base);
-	dma_base = NULL;
-	return ret;
-}
-
-int __init s3c2410_dma_init(void)
-{
-	return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
-}
-
-static inline int is_channel_valid(unsigned int channel)
-{
-	return (channel & DMA_CH_VALID);
-}
-
-static struct s3c24xx_dma_order *dma_order;
-
-
-/* s3c2410_dma_map_channel()
- *
- * turn the virtual channel number into a real, and un-used hardware
- * channel.
- *
- * first, try the dma ordering given to us by either the relevant
- * dma code, or the board. Then just find the first usable free
- * channel
-*/
-
-static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
-{
-	struct s3c24xx_dma_order_ch *ord = NULL;
-	struct s3c24xx_dma_map *ch_map;
-	struct s3c2410_dma_chan *dmach;
-	int ch;
-
-	if (dma_sel.map == NULL || channel > dma_sel.map_size)
-		return NULL;
-
-	ch_map = dma_sel.map + channel;
-
-	/* first, try the board mapping */
-
-	if (dma_order) {
-		ord = &dma_order->channels[channel];
-
-		for (ch = 0; ch < dma_channels; ch++) {
-			int tmp;
-			if (!is_channel_valid(ord->list[ch]))
-				continue;
-
-			tmp = ord->list[ch] & ~DMA_CH_VALID;
-			if (s3c2410_chans[tmp].in_use == 0) {
-				ch = tmp;
-				goto found;
-			}
-		}
-
-		if (ord->flags & DMA_CH_NEVER)
-			return NULL;
-	}
-
-	/* second, search the channel map for first free */
-
-	for (ch = 0; ch < dma_channels; ch++) {
-		if (!is_channel_valid(ch_map->channels[ch]))
-			continue;
-
-		if (s3c2410_chans[ch].in_use == 0) {
-			printk("mapped channel %d to %d\n", channel, ch);
-			break;
-		}
-	}
-
-	if (ch >= dma_channels)
-		return NULL;
-
-	/* update our channel mapping */
-
- found:
-	dmach = &s3c2410_chans[ch];
-	dmach->map = ch_map;
-	dmach->req_ch = channel;
-	s3c_dma_chan_map[channel] = dmach;
-
-	/* select the channel */
-
-	(dma_sel.select)(dmach, ch_map);
-
-	return dmach;
-}
-
-static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
-{
-	return 0;
-}
-
-int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
-{
-	struct s3c24xx_dma_map *nmap;
-	size_t map_sz = sizeof(*nmap) * sel->map_size;
-	int ptr;
-
-	nmap = kmemdup(sel->map, map_sz, GFP_KERNEL);
-	if (nmap == NULL)
-		return -ENOMEM;
-
-	memcpy(&dma_sel, sel, sizeof(*sel));
-
-	dma_sel.map = nmap;
-
-	for (ptr = 0; ptr < sel->map_size; ptr++)
-		s3c24xx_dma_check_entry(nmap+ptr, ptr);
-
-	return 0;
-}
-
-int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
-{
-	struct s3c24xx_dma_order *nord = dma_order;
-
-	if (nord == NULL)
-		nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
-
-	if (nord == NULL) {
-		printk(KERN_ERR "no memory to store dma channel order\n");
-		return -ENOMEM;
-	}
-
-	dma_order = nord;
-	memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
-	return 0;
-}
diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h
index b55da1d..9e81171 100644
--- a/arch/arm/mach-s3c24xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c24xx/include/mach/dma.h
@@ -15,8 +15,6 @@
 
 #include <linux/device.h>
 
-#define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
-
 /* We use `virtual` dma channels to hide the fact we have only a limited
  * number of DMA channels, and not of all of them (dependent on the device)
  * can be attached to any DMA source. We therefore let the DMA core handle
@@ -54,161 +52,4 @@
 	DMACH_MAX,		/* the end entry */
 };
 
-static inline bool samsung_dma_has_circular(void)
-{
-	return false;
-}
-
-static inline bool samsung_dma_is_dmadev(void)
-{
-	return false;
-}
-
-#include <plat/dma.h>
-
-#define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
-
-/* we have 4 dma channels */
-#if !defined(CONFIG_CPU_S3C2443) && !defined(CONFIG_CPU_S3C2416)
-#define S3C_DMA_CHANNELS		(4)
-#else
-#define S3C_DMA_CHANNELS		(6)
-#endif
-
-/* types */
-
-enum s3c2410_dma_state {
-	S3C2410_DMA_IDLE,
-	S3C2410_DMA_RUNNING,
-	S3C2410_DMA_PAUSED
-};
-
-/* enum s3c2410_dma_loadst
- *
- * This represents the state of the DMA engine, wrt to the loaded / running
- * transfers. Since we don't have any way of knowing exactly the state of
- * the DMA transfers, we need to know the state to make decisions on whether
- * we can
- *
- * S3C2410_DMA_NONE
- *
- * There are no buffers loaded (the channel should be inactive)
- *
- * S3C2410_DMA_1LOADED
- *
- * There is one buffer loaded, however it has not been confirmed to be
- * loaded by the DMA engine. This may be because the channel is not
- * yet running, or the DMA driver decided that it was too costly to
- * sit and wait for it to happen.
- *
- * S3C2410_DMA_1RUNNING
- *
- * The buffer has been confirmed running, and not finisged
- *
- * S3C2410_DMA_1LOADED_1RUNNING
- *
- * There is a buffer waiting to be loaded by the DMA engine, and one
- * currently running.
-*/
-
-enum s3c2410_dma_loadst {
-	S3C2410_DMALOAD_NONE,
-	S3C2410_DMALOAD_1LOADED,
-	S3C2410_DMALOAD_1RUNNING,
-	S3C2410_DMALOAD_1LOADED_1RUNNING,
-};
-
-
-/* flags */
-
-#define S3C2410_DMAF_SLOW         (1<<0)   /* slow, so don't worry about
-					    * waiting for reloads */
-#define S3C2410_DMAF_AUTOSTART    (1<<1)   /* auto-start if buffer queued */
-
-#define S3C2410_DMAF_CIRCULAR	(1 << 2)	/* no circular dma support */
-
-/* dma buffer */
-
-struct s3c2410_dma_buf;
-
-/* s3c2410_dma_buf
- *
- * internally used buffer structure to describe a queued or running
- * buffer.
-*/
-
-struct s3c2410_dma_buf {
-	struct s3c2410_dma_buf	*next;
-	int			 magic;		/* magic */
-	int			 size;		/* buffer size in bytes */
-	dma_addr_t		 data;		/* start of DMA data */
-	dma_addr_t		 ptr;		/* where the DMA got to [1] */
-	void			*id;		/* client's id */
-};
-
-/* [1] is this updated for both recv/send modes? */
-
-struct s3c2410_dma_stats {
-	unsigned long		loads;
-	unsigned long		timeout_longest;
-	unsigned long		timeout_shortest;
-	unsigned long		timeout_avg;
-	unsigned long		timeout_failed;
-};
-
-struct s3c2410_dma_map;
-
-/* struct s3c2410_dma_chan
- *
- * full state information for each DMA channel
-*/
-
-struct s3c2410_dma_chan {
-	/* channel state flags and information */
-	unsigned char		 number;      /* number of this dma channel */
-	unsigned char		 in_use;      /* channel allocated */
-	unsigned char		 irq_claimed; /* irq claimed for channel */
-	unsigned char		 irq_enabled; /* irq enabled for channel */
-	unsigned char		 xfer_unit;   /* size of an transfer */
-
-	/* channel state */
-
-	enum s3c2410_dma_state	 state;
-	enum s3c2410_dma_loadst	 load_state;
-	struct s3c2410_dma_client *client;
-
-	/* channel configuration */
-	enum dma_data_direction	 source;
-	enum dma_ch		 req_ch;
-	unsigned long		 dev_addr;
-	unsigned long		 load_timeout;
-	unsigned int		 flags;		/* channel flags */
-
-	struct s3c24xx_dma_map	*map;		/* channel hw maps */
-
-	/* channel's hardware position and configuration */
-	void __iomem		*regs;		/* channels registers */
-	void __iomem		*addr_reg;	/* data address register */
-	unsigned int		 irq;		/* channel irq */
-	unsigned long		 dcon;		/* default value of DCON */
-
-	/* driver handles */
-	s3c2410_dma_cbfn_t	 callback_fn;	/* buffer done callback */
-	s3c2410_dma_opfn_t	 op_fn;		/* channel op callback */
-
-	/* stats gathering */
-	struct s3c2410_dma_stats *stats;
-	struct s3c2410_dma_stats  stats_store;
-
-	/* buffer list and information */
-	struct s3c2410_dma_buf	*curr;		/* current dma buffer */
-	struct s3c2410_dma_buf	*next;		/* next buffer to load */
-	struct s3c2410_dma_buf	*end;		/* end of queue */
-
-	/* system device */
-	struct device	dev;
-};
-
-typedef unsigned long dma_device_t;
-
 #endif /* __ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index 059b1fc..096e140 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -51,21 +51,6 @@
 	DMACH_MAX = 32
 };
 
-struct s3c2410_dma_client {
-	char	*name;
-};
-
-static inline bool samsung_dma_has_circular(void)
-{
-	return true;
-}
-
-static inline bool samsung_dma_is_dmadev(void)
-{
-	return true;
-}
-
 #include <linux/amba/pl08x.h>
-#include <plat/dma-ops.h>
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 1b4fafe..2f36c85 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -7,6 +7,7 @@
 
 config PM_RMOBILE
 	bool
+	select PM_GENERIC_DOMAINS
 
 config ARCH_RCAR_GEN1
 	bool
@@ -23,7 +24,7 @@
 
 config ARCH_RMOBILE
 	bool
-	select PM_RMOBILE if PM && !ARCH_SHMOBILE_MULTI
+	select PM_RMOBILE if PM
 	select SYS_SUPPORTS_SH_CMT
 	select SYS_SUPPORTS_SH_TMU
 
@@ -51,6 +52,11 @@
 	bool "RZ/A1H (R7S72100)"
 	select SYS_SUPPORTS_SH_MTU2
 
+config ARCH_R8A73A4
+	bool "R-Mobile APE6 (R8A73A40)"
+	select ARCH_RMOBILE
+	select RENESAS_IRQC
+
 config ARCH_R8A7740
 	bool "R-Mobile A1 (R8A77400)"
 	select ARCH_RMOBILE
@@ -74,11 +80,6 @@
 
 comment "Renesas ARM SoCs Board Type"
 
-config MACH_LAGER
-	bool "Lager board"
-	depends on ARCH_R8A7790
-	select MICREL_PHY if SH_ETH
-
 config MACH_MARZEN
 	bool "MARZEN board"
 	depends on ARCH_R8A7779
@@ -133,14 +134,6 @@
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_GIC
 
-config ARCH_R8A7790
-	bool "R-Car H2 (R8A77900)"
-	select ARCH_RCAR_GEN2
-	select ARCH_WANT_OPTIONAL_GPIOLIB
-	select ARM_GIC
-	select MIGHT_HAVE_PCI
-	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-
 comment "Renesas ARM SoCs Board Type"
 
 config MACH_APE6EVM
@@ -208,13 +201,6 @@
 	select REGULATOR_FIXED_VOLTAGE if REGULATOR
 	select USE_OF
 
-config MACH_LAGER
-	bool "Lager board"
-	depends on ARCH_R8A7790
-	select USE_OF
-	select MICREL_PHY if SH_ETH
-	select SND_SOC_AK4642 if SND_SIMPLE_CARD
-
 config MACH_KZM9G
 	bool "KZM-A9-GT board"
 	depends on ARCH_SH73A0
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index b55cac0..d53996e 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -27,7 +27,6 @@
 obj-$(CONFIG_ARCH_R8A7740)	+= clock-r8a7740.o
 obj-$(CONFIG_ARCH_R8A7778)	+= clock-r8a7778.o
 obj-$(CONFIG_ARCH_R8A7779)	+= clock-r8a7779.o
-obj-$(CONFIG_ARCH_R8A7790)	+= clock-r8a7790.o
 endif
 
 # CPU reset vector handling objects
@@ -57,7 +56,6 @@
 
 # Board objects
 ifdef CONFIG_ARCH_SHMOBILE_MULTI
-obj-$(CONFIG_MACH_LAGER)	+= board-lager-reference.o
 obj-$(CONFIG_MACH_MARZEN)	+= board-marzen-reference.o
 else
 obj-$(CONFIG_MACH_APE6EVM)	+= board-ape6evm.o
@@ -66,7 +64,6 @@
 obj-$(CONFIG_MACH_BOCKW)	+= board-bockw.o
 obj-$(CONFIG_MACH_BOCKW_REFERENCE)	+= board-bockw-reference.o
 obj-$(CONFIG_MACH_MARZEN)	+= board-marzen.o
-obj-$(CONFIG_MACH_LAGER)	+= board-lager.o
 obj-$(CONFIG_MACH_ARMADILLO800EVA)	+= board-armadillo800eva.o
 obj-$(CONFIG_MACH_KZM9G)	+= board-kzm9g.o
 obj-$(CONFIG_MACH_KZM9G_REFERENCE)	+= board-kzm9g-reference.o
diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot
index 57d00ed..02532be 100644
--- a/arch/arm/mach-shmobile/Makefile.boot
+++ b/arch/arm/mach-shmobile/Makefile.boot
@@ -7,7 +7,6 @@
 loadaddr-$(CONFIG_MACH_BOCKW_REFERENCE) += 0x60008000
 loadaddr-$(CONFIG_MACH_KZM9G) += 0x41008000
 loadaddr-$(CONFIG_MACH_KZM9G_REFERENCE) += 0x41008000
-loadaddr-$(CONFIG_MACH_LAGER) += 0x40008000
 loadaddr-$(CONFIG_MACH_MACKEREL) += 0x40008000
 loadaddr-$(CONFIG_MACH_MARZEN) += 0x60008000
 
diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c
deleted file mode 100644
index fa06bdb..0000000
--- a/arch/arm/mach-shmobile/board-lager-reference.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Lager board support - Reference DT implementation
- *
- * Copyright (C) 2013  Renesas Solutions Corp.
- * Copyright (C) 2013  Simon Horman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/of_platform.h>
-
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "r8a7790.h"
-#include "rcar-gen2.h"
-
-static const char *lager_boards_compat_dt[] __initdata = {
-	"renesas,lager",
-	"renesas,lager-reference",
-	NULL,
-};
-
-DT_MACHINE_START(LAGER_DT, "lager")
-	.smp		= smp_ops(r8a7790_smp_ops),
-	.init_early	= shmobile_init_delay,
-	.init_time	= rcar_gen2_timer_init,
-	.init_late	= shmobile_init_late,
-	.reserve	= rcar_gen2_reserve,
-	.dt_compat	= lager_boards_compat_dt,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c
deleted file mode 100644
index 65b128d..0000000
--- a/arch/arm/mach-shmobile/board-lager.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * Lager board support
- *
- * Copyright (C) 2013-2014  Renesas Solutions Corp.
- * Copyright (C) 2013  Magnus Damm
- * Copyright (C) 2014  Cogent Embedded, 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.
- */
-
-#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/irqchip.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/kernel.h>
-#include <linux/leds.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/mtd.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/platform_data/camera-rcar.h>
-#include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/usb-rcar-gen2-phy.h>
-#include <linux/platform_device.h>
-#include <linux/phy.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/gpio-regulator.h>
-#include <linux/regulator/machine.h>
-#include <linux/sh_eth.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/rspi.h>
-#include <linux/spi/spi.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/renesas_usbhs.h>
-
-#include <media/soc_camera.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <sound/rcar_snd.h>
-#include <sound/simple_card.h>
-
-#include "common.h"
-#include "irqs.h"
-#include "r8a7790.h"
-#include "rcar-gen2.h"
-
-/*
- * SSI-AK4643
- *
- * SW1: 1: AK4643
- *      2: CN22
- *      3: ADV7511
- *
- * this command is required when playback.
- *
- * # amixer set "LINEOUT Mixer DACL" on
- */
-
-/*
- * SDHI0 (CN8)
- *
- * JP3:  pin1
- * SW20: pin1
-
- * GP5_24:	1:  VDD  3.3V (defult)
- *		0:  VDD  0.0V
- * GP5_29:	1:  VccQ 3.3V (defult)
- *		0:  VccQ 1.8V
- *
- */
-
-/* LEDS */
-static struct gpio_led lager_leds[] = {
-	{
-		.name		= "led8",
-		.gpio		= RCAR_GP_PIN(5, 17),
-		.default_state	= LEDS_GPIO_DEFSTATE_ON,
-	}, {
-		.name		= "led7",
-		.gpio		= RCAR_GP_PIN(4, 23),
-		.default_state	= LEDS_GPIO_DEFSTATE_ON,
-	}, {
-		.name		= "led6",
-		.gpio		= RCAR_GP_PIN(4, 22),
-		.default_state	= LEDS_GPIO_DEFSTATE_ON,
-	},
-};
-
-static const struct gpio_led_platform_data lager_leds_pdata __initconst = {
-	.leds		= lager_leds,
-	.num_leds	= ARRAY_SIZE(lager_leds),
-};
-
-/* GPIO KEY */
-#define GPIO_KEY(c, g, d, ...) \
-	{ .code = c, .gpio = g, .desc = d, .active_low = 1, \
-	  .wakeup = 1, .debounce_interval = 20 }
-
-static struct gpio_keys_button gpio_buttons[] = {
-	GPIO_KEY(KEY_4,		RCAR_GP_PIN(1, 28),	"SW2-pin4"),
-	GPIO_KEY(KEY_3,		RCAR_GP_PIN(1, 26),	"SW2-pin3"),
-	GPIO_KEY(KEY_2,		RCAR_GP_PIN(1, 24),	"SW2-pin2"),
-	GPIO_KEY(KEY_1,		RCAR_GP_PIN(1, 14),	"SW2-pin1"),
-};
-
-static const struct gpio_keys_platform_data lager_keys_pdata __initconst = {
-	.buttons	= gpio_buttons,
-	.nbuttons	= ARRAY_SIZE(gpio_buttons),
-};
-
-/* Fixed 3.3V regulator to be used by MMCIF */
-static struct regulator_consumer_supply fixed3v3_power_consumers[] =
-{
-	REGULATOR_SUPPLY("vmmc", "sh_mmcif.1"),
-};
-
-/*
- * SDHI regulator macro
- *
- ** FIXME**
- * Lager board vqmmc is provided via DA9063 PMIC chip,
- * and we should use ${LINK}/drivers/mfd/da9063-* driver for it.
- * but, it doesn't have regulator support at this point.
- * It uses gpio-regulator for vqmmc as quick-hack.
- */
-#define SDHI_REGULATOR(idx, vdd_pin, vccq_pin)				\
-static struct regulator_consumer_supply vcc_sdhi##idx##_consumer =	\
-	REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi." #idx);		\
-									\
-static struct regulator_init_data vcc_sdhi##idx##_init_data = {		\
-	.constraints = {						\
-		.valid_ops_mask = REGULATOR_CHANGE_STATUS,		\
-	},								\
-	.consumer_supplies	= &vcc_sdhi##idx##_consumer,		\
-	.num_consumer_supplies	= 1,					\
-};									\
-									\
-static const struct fixed_voltage_config vcc_sdhi##idx##_info __initconst = {\
-	.supply_name	= "SDHI" #idx "Vcc",				\
-	.microvolts	= 3300000,					\
-	.gpio		= vdd_pin,					\
-	.enable_high	= 1,						\
-	.init_data	= &vcc_sdhi##idx##_init_data,			\
-};									\
-									\
-static struct regulator_consumer_supply vccq_sdhi##idx##_consumer =	\
-	REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi." #idx);		\
-									\
-static struct regulator_init_data vccq_sdhi##idx##_init_data = {	\
-	.constraints = {						\
-		.input_uV	= 3300000,				\
-		.min_uV		= 1800000,				\
-		.max_uV		= 3300000,				\
-		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |		\
-				  REGULATOR_CHANGE_STATUS,		\
-	},								\
-	.consumer_supplies	= &vccq_sdhi##idx##_consumer,		\
-	.num_consumer_supplies	= 1,					\
-};									\
-									\
-static struct gpio vccq_sdhi##idx##_gpio =				\
-	{ vccq_pin, GPIOF_OUT_INIT_HIGH, "vccq-sdhi" #idx };		\
-									\
-static struct gpio_regulator_state vccq_sdhi##idx##_states[] = {	\
-	{ .value = 1800000, .gpios = 0 },				\
-	{ .value = 3300000, .gpios = 1 },				\
-};									\
-									\
-static const struct gpio_regulator_config vccq_sdhi##idx##_info __initconst = {\
-	.supply_name	= "vqmmc",					\
-	.gpios		= &vccq_sdhi##idx##_gpio,			\
-	.nr_gpios	= 1,						\
-	.states		= vccq_sdhi##idx##_states,			\
-	.nr_states	= ARRAY_SIZE(vccq_sdhi##idx##_states),		\
-	.type		= REGULATOR_VOLTAGE,				\
-	.init_data	= &vccq_sdhi##idx##_init_data,			\
-};
-
-SDHI_REGULATOR(0, RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 29));
-SDHI_REGULATOR(2, RCAR_GP_PIN(5, 25), RCAR_GP_PIN(5, 30));
-
-/* MMCIF */
-static const struct sh_mmcif_plat_data mmcif1_pdata __initconst = {
-	.caps		= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
-	.clk_ctrl2_present = true,
-	.ccs_unsupported = true,
-};
-
-static const struct resource mmcif1_resources[] __initconst = {
-	DEFINE_RES_MEM(0xee220000, 0x80),
-	DEFINE_RES_IRQ(gic_spi(170)),
-};
-
-/* Ether */
-static const struct sh_eth_plat_data ether_pdata __initconst = {
-	.phy			= 0x1,
-	.phy_irq		= irq_pin(0),
-	.edmac_endian		= EDMAC_LITTLE_ENDIAN,
-	.phy_interface		= PHY_INTERFACE_MODE_RMII,
-	.ether_link_active_low	= 1,
-};
-
-static const struct resource ether_resources[] __initconst = {
-	DEFINE_RES_MEM(0xee700000, 0x400),
-	DEFINE_RES_IRQ(gic_spi(162)),
-};
-
-static const struct platform_device_info ether_info __initconst = {
-	.name		= "r8a7790-ether",
-	.id		= -1,
-	.res		= ether_resources,
-	.num_res	= ARRAY_SIZE(ether_resources),
-	.data		= &ether_pdata,
-	.size_data	= sizeof(ether_pdata),
-	.dma_mask	= DMA_BIT_MASK(32),
-};
-
-/* SPI Flash memory (Spansion S25FL512SAGMFIG11 64Mb) */
-static struct mtd_partition spi_flash_part[] = {
-	/* Reserved for user loader program, read-only */
-	{
-		.name = "loader",
-		.offset = 0,
-		.size = SZ_256K,
-		.mask_flags = MTD_WRITEABLE,
-	},
-	/* Reserved for user program, read-only */
-	{
-		.name = "user",
-		.offset = MTDPART_OFS_APPEND,
-		.size = SZ_4M,
-		.mask_flags = MTD_WRITEABLE,
-	},
-	/* All else is writable (e.g. JFFS2) */
-	{
-		.name = "flash",
-		.offset = MTDPART_OFS_APPEND,
-		.size = MTDPART_SIZ_FULL,
-		.mask_flags = 0,
-	},
-};
-
-static const struct flash_platform_data spi_flash_data = {
-	.name           = "m25p80",
-	.parts          = spi_flash_part,
-	.nr_parts       = ARRAY_SIZE(spi_flash_part),
-	.type           = "s25fl512s",
-};
-
-static const struct rspi_plat_data qspi_pdata __initconst = {
-	.num_chipselect	= 1,
-};
-
-static const struct spi_board_info spi_info[] __initconst = {
-	{
-		.modalias	= "m25p80",
-		.platform_data	= &spi_flash_data,
-		.mode		= SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD,
-		.max_speed_hz	= 30000000,
-		.bus_num	= 0,
-		.chip_select	= 0,
-	},
-};
-
-/* QSPI resource */
-static const struct resource qspi_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe6b10000, 0x1000),
-	DEFINE_RES_IRQ_NAMED(gic_spi(184), "mux"),
-};
-
-/* VIN */
-static const struct resource vin_resources[] __initconst = {
-	/* VIN0 */
-	DEFINE_RES_MEM(0xe6ef0000, 0x1000),
-	DEFINE_RES_IRQ(gic_spi(188)),
-	/* VIN1 */
-	DEFINE_RES_MEM(0xe6ef1000, 0x1000),
-	DEFINE_RES_IRQ(gic_spi(189)),
-};
-
-static void __init lager_add_vin_device(unsigned idx,
-					struct rcar_vin_platform_data *pdata)
-{
-	struct platform_device_info vin_info = {
-		.name		= "r8a7790-vin",
-		.id		= idx,
-		.res		= &vin_resources[idx * 2],
-		.num_res	= 2,
-		.dma_mask	= DMA_BIT_MASK(32),
-		.data		= pdata,
-		.size_data	= sizeof(*pdata),
-	};
-
-	BUG_ON(idx > 1);
-
-	platform_device_register_full(&vin_info);
-}
-
-#define LAGER_CAMERA(idx, name, addr, pdata, flag)			\
-static struct i2c_board_info i2c_cam##idx##_device = {			\
-	I2C_BOARD_INFO(name, addr),					\
-};									\
-									\
-static struct rcar_vin_platform_data vin##idx##_pdata = {		\
-	.flags = flag,							\
-};									\
-									\
-static struct soc_camera_link cam##idx##_link = {			\
-	.bus_id = idx,							\
-	.board_info = &i2c_cam##idx##_device,				\
-	.i2c_adapter_id = 2,						\
-	.module_name = name,						\
-	.priv = pdata,							\
-}
-
-/* Camera 0 is not currently supported due to adv7612 support missing */
-LAGER_CAMERA(1, "adv7180", 0x20, NULL, RCAR_VIN_BT656);
-
-static void __init lager_add_camera1_device(void)
-{
-	platform_device_register_data(NULL, "soc-camera-pdrv", 1,
-				      &cam1_link, sizeof(cam1_link));
-	lager_add_vin_device(1, &vin1_pdata);
-}
-
-/* SATA1 */
-static const struct resource sata1_resources[] __initconst = {
-	DEFINE_RES_MEM(0xee500000, 0x2000),
-	DEFINE_RES_IRQ(gic_spi(106)),
-};
-
-static const struct platform_device_info sata1_info __initconst = {
-	.name		= "sata-r8a7790",
-	.id		= 1,
-	.res		= sata1_resources,
-	.num_res	= ARRAY_SIZE(sata1_resources),
-	.dma_mask	= DMA_BIT_MASK(32),
-};
-
-/* USBHS */
-static const struct resource usbhs_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe6590000, 0x100),
-	DEFINE_RES_IRQ(gic_spi(107)),
-};
-
-struct usbhs_private {
-	struct renesas_usbhs_platform_info info;
-	struct usb_phy *phy;
-};
-
-#define usbhs_get_priv(pdev) \
-	container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info)
-
-static int usbhs_power_ctrl(struct platform_device *pdev,
-				void __iomem *base, int enable)
-{
-	struct usbhs_private *priv = usbhs_get_priv(pdev);
-
-	if (!priv->phy)
-		return -ENODEV;
-
-	if (enable) {
-		int retval = usb_phy_init(priv->phy);
-
-		if (!retval)
-			retval = usb_phy_set_suspend(priv->phy, 0);
-		return retval;
-	}
-
-	usb_phy_set_suspend(priv->phy, 1);
-	usb_phy_shutdown(priv->phy);
-	return 0;
-}
-
-static int usbhs_hardware_init(struct platform_device *pdev)
-{
-	struct usbhs_private *priv = usbhs_get_priv(pdev);
-	struct usb_phy *phy;
-	int ret;
-
-	/* USB0 Function - use PWEN as GPIO input to detect DIP Switch SW5
-	 * setting to avoid VBUS short circuit due to wrong cable.
-	 * PWEN should be pulled up high if USB Function is selected by SW5
-	 */
-	gpio_request_one(RCAR_GP_PIN(5, 18), GPIOF_IN, NULL); /* USB0_PWEN */
-	if (!gpio_get_value(RCAR_GP_PIN(5, 18))) {
-		pr_warn("Error: USB Function not selected - check SW5 + SW6\n");
-		ret = -ENOTSUPP;
-		goto error;
-	}
-
-	phy = usb_get_phy_dev(&pdev->dev, 0);
-	if (IS_ERR(phy)) {
-		ret = PTR_ERR(phy);
-		goto error;
-	}
-
-	priv->phy = phy;
-	return 0;
- error:
-	gpio_free(RCAR_GP_PIN(5, 18));
-	return ret;
-}
-
-static int usbhs_hardware_exit(struct platform_device *pdev)
-{
-	struct usbhs_private *priv = usbhs_get_priv(pdev);
-
-	if (!priv->phy)
-		return 0;
-
-	usb_put_phy(priv->phy);
-	priv->phy = NULL;
-
-	gpio_free(RCAR_GP_PIN(5, 18));
-	return 0;
-}
-
-static int usbhs_get_id(struct platform_device *pdev)
-{
-	return USBHS_GADGET;
-}
-
-static u32 lager_usbhs_pipe_type[] = {
-	USB_ENDPOINT_XFER_CONTROL,
-	USB_ENDPOINT_XFER_ISOC,
-	USB_ENDPOINT_XFER_ISOC,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_INT,
-	USB_ENDPOINT_XFER_INT,
-	USB_ENDPOINT_XFER_INT,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-	USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usbhs_private usbhs_priv __initdata = {
-	.info = {
-		.platform_callback = {
-			.power_ctrl	= usbhs_power_ctrl,
-			.hardware_init	= usbhs_hardware_init,
-			.hardware_exit	= usbhs_hardware_exit,
-			.get_id		= usbhs_get_id,
-		},
-		.driver_param = {
-			.buswait_bwait	= 4,
-			.pipe_type = lager_usbhs_pipe_type,
-			.pipe_size = ARRAY_SIZE(lager_usbhs_pipe_type),
-		},
-	}
-};
-
-static void __init lager_register_usbhs(void)
-{
-	usb_bind_phy("renesas_usbhs", 0, "usb_phy_rcar_gen2");
-	platform_device_register_resndata(NULL,
-					  "renesas_usbhs", -1,
-					  usbhs_resources,
-					  ARRAY_SIZE(usbhs_resources),
-					  &usbhs_priv.info,
-					  sizeof(usbhs_priv.info));
-}
-
-/* USBHS PHY */
-static const struct rcar_gen2_phy_platform_data usbhs_phy_pdata __initconst = {
-	.chan0_pci = 0,	/* Channel 0 is USBHS */
-	.chan2_pci = 1,	/* Channel 2 is PCI USB */
-};
-
-static const struct resource usbhs_phy_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe6590100, 0x100),
-};
-
-/* I2C */
-static struct i2c_board_info i2c2_devices[] = {
-	{
-		I2C_BOARD_INFO("ak4643", 0x12),
-	}
-};
-
-/* Sound */
-static struct resource rsnd_resources[] __initdata = {
-	[RSND_GEN2_SCU]  = DEFINE_RES_MEM(0xec500000, 0x1000),
-	[RSND_GEN2_ADG]  = DEFINE_RES_MEM(0xec5a0000, 0x100),
-	[RSND_GEN2_SSIU] = DEFINE_RES_MEM(0xec540000, 0x1000),
-	[RSND_GEN2_SSI]  = DEFINE_RES_MEM(0xec541000, 0x1280),
-};
-
-static struct rsnd_ssi_platform_info rsnd_ssi[] = {
-	RSND_SSI(0, gic_spi(370), 0),
-	RSND_SSI(0, gic_spi(371), RSND_SSI_CLK_PIN_SHARE),
-};
-
-static struct rsnd_src_platform_info rsnd_src[2] = {
-	/* no member at this point */
-};
-
-static struct rsnd_dai_platform_info rsnd_dai = {
-	.playback = { .ssi = &rsnd_ssi[0], },
-	.capture  = { .ssi = &rsnd_ssi[1], },
-};
-
-static struct rcar_snd_info rsnd_info = {
-	.flags		= RSND_GEN2,
-	.ssi_info	= rsnd_ssi,
-	.ssi_info_nr	= ARRAY_SIZE(rsnd_ssi),
-	.src_info	= rsnd_src,
-	.src_info_nr	= ARRAY_SIZE(rsnd_src),
-	.dai_info	= &rsnd_dai,
-	.dai_info_nr	= 1,
-};
-
-static struct asoc_simple_card_info rsnd_card_info = {
-	.name		= "AK4643",
-	.card		= "SSI01-AK4643",
-	.codec		= "ak4642-codec.2-0012",
-	.platform	= "rcar_sound",
-	.daifmt		= SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
-	.cpu_dai = {
-		.name	= "rcar_sound",
-	},
-	.codec_dai = {
-		.name	= "ak4642-hifi",
-		.sysclk	= 11289600,
-	},
-};
-
-static void __init lager_add_rsnd_device(void)
-{
-	struct platform_device_info cardinfo = {
-		.name           = "asoc-simple-card",
-		.id             = -1,
-		.data           = &rsnd_card_info,
-		.size_data      = sizeof(struct asoc_simple_card_info),
-		.dma_mask       = DMA_BIT_MASK(32),
-	};
-
-	i2c_register_board_info(2, i2c2_devices,
-				ARRAY_SIZE(i2c2_devices));
-
-	platform_device_register_resndata(
-		NULL, "rcar_sound", -1,
-		rsnd_resources, ARRAY_SIZE(rsnd_resources),
-		&rsnd_info, sizeof(rsnd_info));
-
-	platform_device_register_full(&cardinfo);
-}
-
-/* SDHI0 */
-static struct sh_mobile_sdhi_info sdhi0_info __initdata = {
-	.tmio_caps	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
-			  MMC_CAP_POWER_OFF_CARD,
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT |
-			  TMIO_MMC_WRPROTECT_DISABLE,
-};
-
-static struct resource sdhi0_resources[] __initdata = {
-	DEFINE_RES_MEM(0xee100000, 0x200),
-	DEFINE_RES_IRQ(gic_spi(165)),
-};
-
-/* SDHI2 */
-static struct sh_mobile_sdhi_info sdhi2_info __initdata = {
-	.tmio_caps	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
-			  MMC_CAP_POWER_OFF_CARD,
-	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT |
-			  TMIO_MMC_WRPROTECT_DISABLE,
-};
-
-static struct resource sdhi2_resources[] __initdata = {
-	DEFINE_RES_MEM(0xee140000, 0x100),
-	DEFINE_RES_IRQ(gic_spi(167)),
-};
-
-/* Internal PCI1 */
-static const struct resource pci1_resources[] __initconst = {
-	DEFINE_RES_MEM(0xee0b0000, 0x10000),	/* CFG */
-	DEFINE_RES_MEM(0xee0a0000, 0x10000),	/* MEM */
-	DEFINE_RES_IRQ(gic_spi(112)),
-};
-
-static const struct platform_device_info pci1_info __initconst = {
-	.name		= "pci-rcar-gen2",
-	.id		= 1,
-	.res		= pci1_resources,
-	.num_res	= ARRAY_SIZE(pci1_resources),
-	.dma_mask	= DMA_BIT_MASK(32),
-};
-
-static void __init lager_add_usb1_device(void)
-{
-	platform_device_register_full(&pci1_info);
-}
-
-/* Internal PCI2 */
-static const struct resource pci2_resources[] __initconst = {
-	DEFINE_RES_MEM(0xee0d0000, 0x10000),	/* CFG */
-	DEFINE_RES_MEM(0xee0c0000, 0x10000),	/* MEM */
-	DEFINE_RES_IRQ(gic_spi(113)),
-};
-
-static const struct platform_device_info pci2_info __initconst = {
-	.name		= "pci-rcar-gen2",
-	.id		= 2,
-	.res		= pci2_resources,
-	.num_res	= ARRAY_SIZE(pci2_resources),
-	.dma_mask	= DMA_BIT_MASK(32),
-};
-
-static void __init lager_add_usb2_device(void)
-{
-	platform_device_register_full(&pci2_info);
-}
-
-static const struct pinctrl_map lager_pinctrl_map[] = {
-	/* DU (CN10: ARGB0, CN13: LVDS) */
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790",
-				  "du_rgb666", "du"),
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790",
-				  "du_sync_1", "du"),
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7790", "pfc-r8a7790",
-				  "du_clk_out_0", "du"),
-	/* I2C2 */
-	PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar.2", "pfc-r8a7790",
-				  "i2c2", "i2c2"),
-	/* QSPI */
-	PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7790",
-				  "qspi_ctrl", "qspi"),
-	PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7790",
-				  "qspi_data4", "qspi"),
-	/* SCIF0 (CN19: DEBUG SERIAL0) */
-	PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.6", "pfc-r8a7790",
-				  "scif0_data", "scif0"),
-	/* SCIF1 (CN20: DEBUG SERIAL1) */
-	PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.7", "pfc-r8a7790",
-				  "scif1_data", "scif1"),
-	/* SDHI0 */
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7790",
-				  "sdhi0_data4", "sdhi0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7790",
-				  "sdhi0_ctrl", "sdhi0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7790",
-				  "sdhi0_cd", "sdhi0"),
-	/* SDHI2 */
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7790",
-				  "sdhi2_data4", "sdhi2"),
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7790",
-				  "sdhi2_ctrl", "sdhi2"),
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7790",
-				  "sdhi2_cd", "sdhi2"),
-	/* SSI (CN17: sound) */
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790",
-				  "ssi0129_ctrl", "ssi"),
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790",
-				  "ssi0_data", "ssi"),
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790",
-				  "ssi1_data", "ssi"),
-	PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7790",
-				  "audio_clk_a", "audio_clk"),
-	/* MMCIF1 */
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.1", "pfc-r8a7790",
-				  "mmc1_data8", "mmc1"),
-	PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.1", "pfc-r8a7790",
-				  "mmc1_ctrl", "mmc1"),
-	/* Ether */
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-ether", "pfc-r8a7790",
-				  "eth_link", "eth"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-ether", "pfc-r8a7790",
-				  "eth_mdio", "eth"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-ether", "pfc-r8a7790",
-				  "eth_rmii", "eth"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-ether", "pfc-r8a7790",
-				  "intc_irq0", "intc"),
-	/* VIN0 */
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790",
-				  "vin0_data24", "vin0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790",
-				  "vin0_sync", "vin0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790",
-				  "vin0_field", "vin0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790",
-				  "vin0_clkenb", "vin0"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.0", "pfc-r8a7790",
-				  "vin0_clk", "vin0"),
-	/* VIN1 */
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.1", "pfc-r8a7790",
-				  "vin1_data8", "vin1"),
-	PIN_MAP_MUX_GROUP_DEFAULT("r8a7790-vin.1", "pfc-r8a7790",
-				  "vin1_clk", "vin1"),
-	/* USB0 */
-	PIN_MAP_MUX_GROUP_DEFAULT("renesas_usbhs", "pfc-r8a7790",
-				  "usb0_ovc_vbus", "usb0"),
-	/* USB1 */
-	PIN_MAP_MUX_GROUP_DEFAULT("pci-rcar-gen2.1", "pfc-r8a7790",
-				  "usb1", "usb1"),
-	/* USB2 */
-	PIN_MAP_MUX_GROUP_DEFAULT("pci-rcar-gen2.2", "pfc-r8a7790",
-				  "usb2", "usb2"),
-};
-
-static void __init lager_add_standard_devices(void)
-{
-	int fixed_regulator_idx = 0;
-	int gpio_regulator_idx = 0;
-
-	r8a7790_clock_init();
-
-	pinctrl_register_mappings(lager_pinctrl_map,
-				  ARRAY_SIZE(lager_pinctrl_map));
-	r8a7790_pinmux_init();
-
-	r8a7790_add_standard_devices();
-	platform_device_register_data(NULL, "leds-gpio", -1,
-				      &lager_leds_pdata,
-				      sizeof(lager_leds_pdata));
-	platform_device_register_data(NULL, "gpio-keys", -1,
-				      &lager_keys_pdata,
-				      sizeof(lager_keys_pdata));
-	regulator_register_always_on(fixed_regulator_idx++,
-				     "fixed-3.3V", fixed3v3_power_consumers,
-				     ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
-	platform_device_register_resndata(NULL, "sh_mmcif", 1,
-					  mmcif1_resources, ARRAY_SIZE(mmcif1_resources),
-					  &mmcif1_pdata, sizeof(mmcif1_pdata));
-
-	platform_device_register_full(&ether_info);
-
-	platform_device_register_resndata(NULL, "qspi", 0,
-					  qspi_resources,
-					  ARRAY_SIZE(qspi_resources),
-					  &qspi_pdata, sizeof(qspi_pdata));
-	spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
-
-	platform_device_register_data(NULL, "reg-fixed-voltage", fixed_regulator_idx++,
-				      &vcc_sdhi0_info, sizeof(struct fixed_voltage_config));
-	platform_device_register_data(NULL, "reg-fixed-voltage", fixed_regulator_idx++,
-				      &vcc_sdhi2_info, sizeof(struct fixed_voltage_config));
-
-	platform_device_register_data(NULL, "gpio-regulator", gpio_regulator_idx++,
-				      &vccq_sdhi0_info, sizeof(struct gpio_regulator_config));
-	platform_device_register_data(NULL, "gpio-regulator", gpio_regulator_idx++,
-				      &vccq_sdhi2_info, sizeof(struct gpio_regulator_config));
-
-	lager_add_camera1_device();
-
-	platform_device_register_full(&sata1_info);
-
-	platform_device_register_resndata(NULL, "usb_phy_rcar_gen2",
-					  -1, usbhs_phy_resources,
-					  ARRAY_SIZE(usbhs_phy_resources),
-					  &usbhs_phy_pdata,
-					  sizeof(usbhs_phy_pdata));
-	lager_register_usbhs();
-	lager_add_usb1_device();
-	lager_add_usb2_device();
-
-	lager_add_rsnd_device();
-
-	platform_device_register_resndata(NULL, "sh_mobile_sdhi", 0,
-					  sdhi0_resources, ARRAY_SIZE(sdhi0_resources),
-					  &sdhi0_info, sizeof(struct sh_mobile_sdhi_info));
-	platform_device_register_resndata(NULL, "sh_mobile_sdhi", 2,
-					  sdhi2_resources, ARRAY_SIZE(sdhi2_resources),
-					  &sdhi2_info, sizeof(struct sh_mobile_sdhi_info));
-}
-
-/*
- * Ether LEDs on the Lager board are named LINK and ACTIVE which corresponds
- * to non-default 01 setting of the Micrel KSZ8041 PHY control register 1 bits
- * 14-15. We have to set them back to 01 from the default 00 value each time
- * the PHY is reset. It's also important because the PHY's LED0 signal is
- * connected to SoC's ETH_LINK signal and in the PHY's default mode it will
- * bounce on and off after each packet, which we apparently want to avoid.
- */
-static int lager_ksz8041_fixup(struct phy_device *phydev)
-{
-	u16 phyctrl1 = phy_read(phydev, 0x1e);
-
-	phyctrl1 &= ~0xc000;
-	phyctrl1 |= 0x4000;
-	return phy_write(phydev, 0x1e, phyctrl1);
-}
-
-static void __init lager_init(void)
-{
-	lager_add_standard_devices();
-
-	irq_set_irq_type(irq_pin(0), IRQ_TYPE_LEVEL_LOW);
-
-	if (IS_ENABLED(CONFIG_PHYLIB))
-		phy_register_fixup_for_id("r8a7790-ether-ff:01",
-					  lager_ksz8041_fixup);
-}
-
-static void __init lager_legacy_init_irq(void)
-{
-	void __iomem *gic_dist_base = ioremap_nocache(0xf1001000, 0x1000);
-	void __iomem *gic_cpu_base = ioremap_nocache(0xf1002000, 0x1000);
-
-	gic_init(0, 29, gic_dist_base, gic_cpu_base);
-
-	/* Do not invoke DT-based interrupt code via irqchip_init() */
-}
-
-static const char * const lager_boards_compat_dt[] __initconst = {
-	"renesas,lager",
-	NULL,
-};
-
-DT_MACHINE_START(LAGER_DT, "lager")
-	.smp		= smp_ops(r8a7790_smp_ops),
-	.init_early	= shmobile_init_delay,
-	.init_irq	= lager_legacy_init_irq,
-	.init_time	= rcar_gen2_timer_init,
-	.init_machine	= lager_init,
-	.init_late	= shmobile_init_late,
-	.reserve	= rcar_gen2_reserve,
-	.dt_compat	= lager_boards_compat_dt,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c
deleted file mode 100644
index f9bbc5f..0000000
--- a/arch/arm/mach-shmobile/clock-r8a7790.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * r8a7790 clock framework support
- *
- * Copyright (C) 2013  Renesas Solutions Corp.
- * Copyright (C) 2013  Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/sh_clk.h>
-#include <linux/clkdev.h>
-
-#include "clock.h"
-#include "common.h"
-#include "r8a7790.h"
-#include "rcar-gen2.h"
-
-/*
- *   MD		EXTAL		PLL0	PLL1	PLL3
- * 14 13 19	(MHz)		*1	*1
- *---------------------------------------------------
- * 0  0  0	15 x 1		x172/2	x208/2	x106
- * 0  0  1	15 x 1		x172/2	x208/2	x88
- * 0  1  0	20 x 1		x130/2	x156/2	x80
- * 0  1  1	20 x 1		x130/2	x156/2	x66
- * 1  0  0	26 / 2		x200/2	x240/2	x122
- * 1  0  1	26 / 2		x200/2	x240/2	x102
- * 1  1  0	30 / 2		x172/2	x208/2	x106
- * 1  1  1	30 / 2		x172/2	x208/2	x88
- *
- * *1 :	Table 7.6 indicates VCO ouput (PLLx = VCO/2)
- *	see "p1 / 2" on R8A7790_CLOCK_ROOT() below
- */
-
-#define CPG_BASE	0xe6150000
-#define CPG_LEN		0x1000
-
-#define SMSTPCR1	0xe6150134
-#define SMSTPCR2	0xe6150138
-#define SMSTPCR3	0xe615013c
-#define SMSTPCR5	0xe6150144
-#define SMSTPCR7	0xe615014c
-#define SMSTPCR8	0xe6150990
-#define SMSTPCR9	0xe6150994
-#define SMSTPCR10	0xe6150998
-
-#define MSTPSR1		IOMEM(0xe6150038)
-#define MSTPSR2		IOMEM(0xe6150040)
-#define MSTPSR3		IOMEM(0xe6150048)
-#define MSTPSR5		IOMEM(0xe615003c)
-#define MSTPSR7		IOMEM(0xe61501c4)
-#define MSTPSR8		IOMEM(0xe61509a0)
-#define MSTPSR9		IOMEM(0xe61509a4)
-#define MSTPSR10	IOMEM(0xe61509a8)
-
-#define SDCKCR		0xE6150074
-#define SD2CKCR		0xE6150078
-#define SD3CKCR		0xE615026C
-#define MMC0CKCR	0xE6150240
-#define MMC1CKCR	0xE6150244
-#define SSPCKCR		0xE6150248
-#define SSPRSCKCR	0xE615024C
-
-static struct clk_mapping cpg_mapping = {
-	.phys   = CPG_BASE,
-	.len    = CPG_LEN,
-};
-
-static struct clk extal_clk = {
-	/* .rate will be updated on r8a7790_clock_init() */
-	.mapping	= &cpg_mapping,
-};
-
-static struct sh_clk_ops followparent_clk_ops = {
-	.recalc	= followparent_recalc,
-};
-
-static struct clk main_clk = {
-	/* .parent will be set r8a7790_clock_init */
-	.ops	= &followparent_clk_ops,
-};
-
-static struct clk audio_clk_a = {
-};
-
-static struct clk audio_clk_b = {
-};
-
-static struct clk audio_clk_c = {
-};
-
-/*
- * clock ratio of these clock will be updated
- * on r8a7790_clock_init()
- */
-SH_FIXED_RATIO_CLK_SET(pll1_clk,		main_clk,	1, 1);
-SH_FIXED_RATIO_CLK_SET(pll3_clk,		main_clk,	1, 1);
-SH_FIXED_RATIO_CLK_SET(lb_clk,			pll1_clk,	1, 1);
-SH_FIXED_RATIO_CLK_SET(qspi_clk,		pll1_clk,	1, 1);
-
-/* fixed ratio clock */
-SH_FIXED_RATIO_CLK_SET(extal_div2_clk,		extal_clk,	1, 2);
-SH_FIXED_RATIO_CLK_SET(cp_clk,			extal_clk,	1, 2);
-
-SH_FIXED_RATIO_CLK_SET(pll1_div2_clk,		pll1_clk,	1, 2);
-SH_FIXED_RATIO_CLK_SET(zg_clk,			pll1_clk,	1, 3);
-SH_FIXED_RATIO_CLK_SET(zx_clk,			pll1_clk,	1, 3);
-SH_FIXED_RATIO_CLK_SET(zs_clk,			pll1_clk,	1, 6);
-SH_FIXED_RATIO_CLK_SET(hp_clk,			pll1_clk,	1, 12);
-SH_FIXED_RATIO_CLK_SET(i_clk,			pll1_clk,	1, 2);
-SH_FIXED_RATIO_CLK_SET(b_clk,			pll1_clk,	1, 12);
-SH_FIXED_RATIO_CLK_SET(p_clk,			pll1_clk,	1, 24);
-SH_FIXED_RATIO_CLK_SET(cl_clk,			pll1_clk,	1, 48);
-SH_FIXED_RATIO_CLK_SET(m2_clk,			pll1_clk,	1, 8);
-SH_FIXED_RATIO_CLK_SET(imp_clk,			pll1_clk,	1, 4);
-SH_FIXED_RATIO_CLK_SET(rclk_clk,		pll1_clk,	1, (48 * 1024));
-SH_FIXED_RATIO_CLK_SET(oscclk_clk,		pll1_clk,	1, (12 * 1024));
-
-SH_FIXED_RATIO_CLK_SET(zb3_clk,			pll3_clk,	1, 4);
-SH_FIXED_RATIO_CLK_SET(zb3d2_clk,		pll3_clk,	1, 8);
-SH_FIXED_RATIO_CLK_SET(ddr_clk,			pll3_clk,	1, 8);
-SH_FIXED_RATIO_CLK_SET(mp_clk,			pll1_div2_clk,	1, 15);
-
-static struct clk *main_clks[] = {
-	&audio_clk_a,
-	&audio_clk_b,
-	&audio_clk_c,
-	&extal_clk,
-	&extal_div2_clk,
-	&main_clk,
-	&pll1_clk,
-	&pll1_div2_clk,
-	&pll3_clk,
-	&lb_clk,
-	&qspi_clk,
-	&zg_clk,
-	&zx_clk,
-	&zs_clk,
-	&hp_clk,
-	&i_clk,
-	&b_clk,
-	&p_clk,
-	&cl_clk,
-	&m2_clk,
-	&imp_clk,
-	&rclk_clk,
-	&oscclk_clk,
-	&zb3_clk,
-	&zb3d2_clk,
-	&ddr_clk,
-	&mp_clk,
-	&cp_clk,
-};
-
-/* SDHI (DIV4) clock */
-static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, 24, 0, 36, 48, 10 };
-
-static struct clk_div_mult_table div4_div_mult_table = {
-	.divisors = divisors,
-	.nr_divisors = ARRAY_SIZE(divisors),
-};
-
-static struct clk_div4_table div4_table = {
-	.div_mult_table = &div4_div_mult_table,
-};
-
-enum {
-	DIV4_SDH, DIV4_SD0, DIV4_SD1, DIV4_NR
-};
-
-static struct clk div4_clks[DIV4_NR] = {
-	[DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT),
-	[DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1df0, CLK_ENABLE_ON_INIT),
-	[DIV4_SD1] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 0, 0x1df0, CLK_ENABLE_ON_INIT),
-};
-
-/* DIV6 clocks */
-enum {
-	DIV6_SD2, DIV6_SD3,
-	DIV6_MMC0, DIV6_MMC1,
-	DIV6_SSP, DIV6_SSPRS,
-	DIV6_NR
-};
-
-static struct clk div6_clks[DIV6_NR] = {
-	[DIV6_SD2]	= SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0),
-	[DIV6_SD3]	= SH_CLK_DIV6(&pll1_div2_clk, SD3CKCR, 0),
-	[DIV6_MMC0]	= SH_CLK_DIV6(&pll1_div2_clk, MMC0CKCR, 0),
-	[DIV6_MMC1]	= SH_CLK_DIV6(&pll1_div2_clk, MMC1CKCR, 0),
-	[DIV6_SSP]	= SH_CLK_DIV6(&pll1_div2_clk, SSPCKCR, 0),
-	[DIV6_SSPRS]	= SH_CLK_DIV6(&pll1_div2_clk, SSPRSCKCR, 0),
-};
-
-/* MSTP */
-enum {
-	MSTP1017, /* parent of SCU */
-
-	MSTP1031, MSTP1030,
-	MSTP1029, MSTP1028, MSTP1027, MSTP1026, MSTP1025, MSTP1024, MSTP1023, MSTP1022,
-	MSTP1015, MSTP1014, MSTP1013, MSTP1012, MSTP1011, MSTP1010,
-	MSTP1009, MSTP1008, MSTP1007, MSTP1006, MSTP1005,
-	MSTP931, MSTP930, MSTP929, MSTP928,
-	MSTP917,
-	MSTP815, MSTP814,
-	MSTP813,
-	MSTP811, MSTP810, MSTP809, MSTP808,
-	MSTP726, MSTP725, MSTP724, MSTP723, MSTP722, MSTP721, MSTP720,
-	MSTP717, MSTP716,
-	MSTP704, MSTP703,
-	MSTP522,
-	MSTP502, MSTP501,
-	MSTP315, MSTP314, MSTP313, MSTP312, MSTP311, MSTP305, MSTP304,
-	MSTP216, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202,
-	MSTP124,
-	MSTP_NR
-};
-
-static struct clk mstp_clks[MSTP_NR] = {
-	[MSTP1031] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 31, MSTPSR10, 0), /* SCU0 */
-	[MSTP1030] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 30, MSTPSR10, 0), /* SCU1 */
-	[MSTP1029] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 29, MSTPSR10, 0), /* SCU2 */
-	[MSTP1028] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 28, MSTPSR10, 0), /* SCU3 */
-	[MSTP1027] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 27, MSTPSR10, 0), /* SCU4 */
-	[MSTP1026] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 26, MSTPSR10, 0), /* SCU5 */
-	[MSTP1025] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 25, MSTPSR10, 0), /* SCU6 */
-	[MSTP1024] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 24, MSTPSR10, 0), /* SCU7 */
-	[MSTP1023] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 23, MSTPSR10, 0), /* SCU8 */
-	[MSTP1022] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 22, MSTPSR10, 0), /* SCU9 */
-	[MSTP1017] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 17, MSTPSR10, 0), /* SCU */
-	[MSTP1015] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 15, MSTPSR10, 0), /* SSI0 */
-	[MSTP1014] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 14, MSTPSR10, 0), /* SSI1 */
-	[MSTP1013] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 13, MSTPSR10, 0), /* SSI2 */
-	[MSTP1012] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 12, MSTPSR10, 0), /* SSI3 */
-	[MSTP1011] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 11, MSTPSR10, 0), /* SSI4 */
-	[MSTP1010] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 10, MSTPSR10, 0), /* SSI5 */
-	[MSTP1009] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 9, MSTPSR10, 0), /* SSI6 */
-	[MSTP1008] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 8, MSTPSR10, 0), /* SSI7 */
-	[MSTP1007] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 7, MSTPSR10, 0), /* SSI8 */
-	[MSTP1006] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 6, MSTPSR10, 0), /* SSI9 */
-	[MSTP1005] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 5, MSTPSR10, 0), /* SSI ALL */
-	[MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
-	[MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
-	[MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
-	[MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
-	[MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */
-	[MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */
-	[MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */
-	[MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */
-	[MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */
-	[MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */
-	[MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8,  9, MSTPSR8, 0), /* VIN2 */
-	[MSTP808] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8,  8, MSTPSR8, 0), /* VIN3 */
-	[MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */
-	[MSTP725] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 25, MSTPSR7, 0), /* LVDS1 */
-	[MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */
-	[MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */
-	[MSTP722] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 22, MSTPSR7, 0), /* DU2 */
-	[MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */
-	[MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */
-	[MSTP717] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 17, MSTPSR7, 0), /* HSCIF0 */
-	[MSTP716] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 16, MSTPSR7, 0), /* HSCIF1 */
-	[MSTP704] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 4, MSTPSR7, 0), /* HSUSB */
-	[MSTP703] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 3, MSTPSR7, 0), /* EHCI */
-	[MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */
-	[MSTP502] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 2, MSTPSR5, 0), /* Audio-DMAC low */
-	[MSTP501] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 1, MSTPSR5, 0), /* Audio-DMAC hi */
-	[MSTP315] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, MSTPSR3, 0), /* MMC0 */
-	[MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */
-	[MSTP313] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD1], SMSTPCR3, 13, MSTPSR3, 0), /* SDHI1 */
-	[MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI2 */
-	[MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD3], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI3 */
-	[MSTP305] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC1], SMSTPCR3, 5, MSTPSR3, 0), /* MMC1 */
-	[MSTP304] = SH_CLK_MSTP32_STS(&cp_clk, SMSTPCR3, 4, MSTPSR3, 0), /* TPU0 */
-	[MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */
-	[MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */
-	[MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */
-	[MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */
-	[MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */
-	[MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */
-	[MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */
-};
-
-static struct clk_lookup lookups[] = {
-
-	/* main clocks */
-	CLKDEV_CON_ID("extal",		&extal_clk),
-	CLKDEV_CON_ID("extal_div2",	&extal_div2_clk),
-	CLKDEV_CON_ID("main",		&main_clk),
-	CLKDEV_CON_ID("pll1",		&pll1_clk),
-	CLKDEV_CON_ID("pll1_div2",	&pll1_div2_clk),
-	CLKDEV_CON_ID("pll3",		&pll3_clk),
-	CLKDEV_CON_ID("zg",		&zg_clk),
-	CLKDEV_CON_ID("zx",		&zx_clk),
-	CLKDEV_CON_ID("zs",		&zs_clk),
-	CLKDEV_CON_ID("hp",		&hp_clk),
-	CLKDEV_CON_ID("i",		&i_clk),
-	CLKDEV_CON_ID("b",		&b_clk),
-	CLKDEV_CON_ID("lb",		&lb_clk),
-	CLKDEV_CON_ID("p",		&p_clk),
-	CLKDEV_CON_ID("cl",		&cl_clk),
-	CLKDEV_CON_ID("m2",		&m2_clk),
-	CLKDEV_CON_ID("imp",		&imp_clk),
-	CLKDEV_CON_ID("rclk",		&rclk_clk),
-	CLKDEV_CON_ID("oscclk",		&oscclk_clk),
-	CLKDEV_CON_ID("zb3",		&zb3_clk),
-	CLKDEV_CON_ID("zb3d2",		&zb3d2_clk),
-	CLKDEV_CON_ID("ddr",		&ddr_clk),
-	CLKDEV_CON_ID("mp",		&mp_clk),
-	CLKDEV_CON_ID("qspi",		&qspi_clk),
-	CLKDEV_CON_ID("cp",		&cp_clk),
-
-	/* DIV4 */
-	CLKDEV_CON_ID("sdh",		&div4_clks[DIV4_SDH]),
-
-	/* DIV6 */
-	CLKDEV_CON_ID("ssp",		&div6_clks[DIV6_SSP]),
-	CLKDEV_CON_ID("ssprs",		&div6_clks[DIV6_SSPRS]),
-
-	/* MSTP */
-	CLKDEV_DEV_ID("rcar_sound", &mstp_clks[MSTP1005]),
-	CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]),
-	CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]),
-	CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP206]),
-	CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP207]),
-	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP216]),
-	CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP202]),
-	CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP721]),
-	CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP720]),
-	CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP717]),
-	CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP716]),
-	CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]),
-	CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]),
-	CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]),
-	CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]),
-	CLKDEV_DEV_ID("r8a7790-ether", &mstp_clks[MSTP813]),
-	CLKDEV_DEV_ID("r8a7790-vin.0", &mstp_clks[MSTP811]),
-	CLKDEV_DEV_ID("r8a7790-vin.1", &mstp_clks[MSTP810]),
-	CLKDEV_DEV_ID("r8a7790-vin.2", &mstp_clks[MSTP809]),
-	CLKDEV_DEV_ID("r8a7790-vin.3", &mstp_clks[MSTP808]),
-	CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]),
-	CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP502]),
-	CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP501]),
-	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP315]),
-	CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]),
-	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]),
-	CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP312]),
-	CLKDEV_DEV_ID("sh_mobile_sdhi.3", &mstp_clks[MSTP311]),
-	CLKDEV_DEV_ID("sh_mmcif.1", &mstp_clks[MSTP305]),
-	CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]),
-	CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP704]),
-	CLKDEV_DEV_ID("pci-rcar-gen2.0", &mstp_clks[MSTP703]),
-	CLKDEV_DEV_ID("pci-rcar-gen2.1", &mstp_clks[MSTP703]),
-	CLKDEV_DEV_ID("pci-rcar-gen2.2", &mstp_clks[MSTP703]),
-	CLKDEV_DEV_ID("sata-r8a7790.0", &mstp_clks[MSTP815]),
-	CLKDEV_DEV_ID("sata-r8a7790.1", &mstp_clks[MSTP814]),
-
-	/* ICK */
-	CLKDEV_ICK_ID("fck", "sh-cmt-48-gen2.0", &mstp_clks[MSTP124]),
-	CLKDEV_ICK_ID("usbhs", "usb_phy_rcar_gen2", &mstp_clks[MSTP704]),
-	CLKDEV_ICK_ID("lvds.0", "rcar-du-r8a7790", &mstp_clks[MSTP726]),
-	CLKDEV_ICK_ID("lvds.1", "rcar-du-r8a7790", &mstp_clks[MSTP725]),
-	CLKDEV_ICK_ID("du.0", "rcar-du-r8a7790", &mstp_clks[MSTP724]),
-	CLKDEV_ICK_ID("du.1", "rcar-du-r8a7790", &mstp_clks[MSTP723]),
-	CLKDEV_ICK_ID("du.2", "rcar-du-r8a7790", &mstp_clks[MSTP722]),
-	CLKDEV_ICK_ID("clk_a", "rcar_sound", &audio_clk_a),
-	CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b),
-	CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c),
-	CLKDEV_ICK_ID("clk_i", "rcar_sound", &m2_clk),
-	CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP1031]),
-	CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP1030]),
-	CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP1029]),
-	CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP1028]),
-	CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP1027]),
-	CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP1026]),
-	CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP1025]),
-	CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP1024]),
-	CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP1023]),
-	CLKDEV_ICK_ID("src.9", "rcar_sound", &mstp_clks[MSTP1022]),
-	CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP1015]),
-	CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP1014]),
-	CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP1013]),
-	CLKDEV_ICK_ID("ssi.3", "rcar_sound", &mstp_clks[MSTP1012]),
-	CLKDEV_ICK_ID("ssi.4", "rcar_sound", &mstp_clks[MSTP1011]),
-	CLKDEV_ICK_ID("ssi.5", "rcar_sound", &mstp_clks[MSTP1010]),
-	CLKDEV_ICK_ID("ssi.6", "rcar_sound", &mstp_clks[MSTP1009]),
-	CLKDEV_ICK_ID("ssi.7", "rcar_sound", &mstp_clks[MSTP1008]),
-	CLKDEV_ICK_ID("ssi.8", "rcar_sound", &mstp_clks[MSTP1007]),
-	CLKDEV_ICK_ID("ssi.9", "rcar_sound", &mstp_clks[MSTP1006]),
-
-};
-
-#define R8A7790_CLOCK_ROOT(e, m, p0, p1, p30, p31)		\
-	extal_clk.rate	= e * 1000 * 1000;			\
-	main_clk.parent	= m;					\
-	SH_CLK_SET_RATIO(&pll1_clk_ratio, p1 / 2, 1);		\
-	if (mode & MD(19))					\
-		SH_CLK_SET_RATIO(&pll3_clk_ratio, p31, 1);	\
-	else							\
-		SH_CLK_SET_RATIO(&pll3_clk_ratio, p30, 1)
-
-
-void __init r8a7790_clock_init(void)
-{
-	u32 mode = rcar_gen2_read_mode_pins();
-	int k, ret = 0;
-
-	switch (mode & (MD(14) | MD(13))) {
-	case 0:
-		R8A7790_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88);
-		break;
-	case MD(13):
-		R8A7790_CLOCK_ROOT(20, &extal_clk, 130, 156, 80, 66);
-		break;
-	case MD(14):
-		R8A7790_CLOCK_ROOT(26 / 2, &extal_div2_clk, 200, 240, 122, 102);
-		break;
-	case MD(13) | MD(14):
-		R8A7790_CLOCK_ROOT(30 / 2, &extal_div2_clk, 172, 208, 106, 88);
-		break;
-	}
-
-	if (mode & (MD(18)))
-		SH_CLK_SET_RATIO(&lb_clk_ratio, 1, 36);
-	else
-		SH_CLK_SET_RATIO(&lb_clk_ratio, 1, 24);
-
-	if ((mode & (MD(3) | MD(2) | MD(1))) == MD(2))
-		SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 16);
-	else
-		SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 20);
-
-	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
-		ret = clk_register(main_clks[k]);
-
-	if (!ret)
-		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
-
-	if (!ret)
-		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
-
-	if (!ret)
-		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
-
-	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
-	if (!ret)
-		shmobile_clk_init();
-	else
-		panic("failed to setup r8a7790 clocks\n");
-}
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 6b4c1f3..3855fb0 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -553,6 +553,7 @@
 	MSTP314, MSTP313, MSTP312, MSTP311,
 	MSTP304, MSTP303, MSTP302, MSTP301, MSTP300,
 	MSTP411, MSTP410, MSTP403,
+	MSTP508,
 	MSTP_NR };
 
 #define MSTP(_parent, _reg, _bit, _flags) \
@@ -597,6 +598,7 @@
 	[MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
 	[MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */
 	[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
+	[MSTP508] = MSTP(&div4_clks[DIV4_HP], SMSTPCR5, 8, 0), /* INTCA0 */
 };
 
 /* The lookups structure below includes duplicate entries for some clocks
@@ -677,6 +679,14 @@
 	CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
 	CLKDEV_DEV_ID("e6828000.i2c", &mstp_clks[MSTP410]), /* I2C4 */
 	CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
+	CLKDEV_DEV_ID("renesas_intc_irqpin.0",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("e6900000.irqpin",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("renesas_intc_irqpin.1",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("e6900004.irqpin",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("renesas_intc_irqpin.2",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("e6900008.irqpin",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("renesas_intc_irqpin.3",	&mstp_clks[MSTP508]), /* INTCA0 */
+	CLKDEV_DEV_ID("e690000c.irqpin",	&mstp_clks[MSTP508]), /* INTCA0 */
 
 	/* ICK */
 	CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c
index ac2eecd..34608fc 100644
--- a/arch/arm/mach-shmobile/pm-r8a7740.c
+++ b/arch/arm/mach-shmobile/pm-r8a7740.c
@@ -9,10 +9,14 @@
  * for more details.
  */
 #include <linux/console.h>
+#include <linux/io.h>
 #include <linux/suspend.h>
+
 #include "common.h"
 #include "pm-rmobile.h"
 
+#define SYSC_BASE	IOMEM(0xe6180000)
+
 #if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM)
 static int r8a7740_pd_a3sm_suspend(void)
 {
@@ -45,41 +49,51 @@
 static struct rmobile_pm_domain r8a7740_pm_domains[] = {
 	{
 		.genpd.name	= "A4LC",
+		.base		= SYSC_BASE,
 		.bit_shift	= 1,
 	}, {
 		.genpd.name	= "A4MP",
+		.base		= SYSC_BASE,
 		.bit_shift	= 2,
 	}, {
 		.genpd.name	= "D4",
+		.base		= SYSC_BASE,
 		.bit_shift	= 3,
 		.gov		= &pm_domain_always_on_gov,
 		.suspend	= r8a7740_pd_d4_suspend,
 	}, {
 		.genpd.name	= "A4R",
+		.base		= SYSC_BASE,
 		.bit_shift	= 5,
 	}, {
 		.genpd.name	= "A3RV",
+		.base		= SYSC_BASE,
 		.bit_shift	= 6,
 	}, {
 		.genpd.name	= "A4S",
+		.base		= SYSC_BASE,
 		.bit_shift	= 10,
 		.no_debug	= true,
 	}, {
 		.genpd.name	= "A3SP",
+		.base		= SYSC_BASE,
 		.bit_shift	= 11,
 		.gov		= &pm_domain_always_on_gov,
 		.no_debug	= true,
 		.suspend	= r8a7740_pd_a3sp_suspend,
 	}, {
 		.genpd.name	= "A3SM",
+		.base		= SYSC_BASE,
 		.bit_shift	= 12,
 		.gov		= &pm_domain_always_on_gov,
 		.suspend	= r8a7740_pd_a3sm_suspend,
 	}, {
 		.genpd.name	= "A3SG",
+		.base		= SYSC_BASE,
 		.bit_shift	= 13,
 	}, {
 		.genpd.name	= "A4SU",
+		.base		= SYSC_BASE,
 		.bit_shift	= 20,
 	},
 };
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index 6f7d56e..9501820 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2012  Renesas Solutions Corp.
  * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ * Copyright (C) 2014  Glider bvba
  *
  * based on pm-sh7372.c
  *  Copyright (C) 2011 Magnus Damm
@@ -13,16 +14,22 @@
  */
 #include <linux/console.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_clock.h>
+#include <linux/slab.h>
+
 #include <asm/io.h>
+
 #include "pm-rmobile.h"
 
 /* SYSC */
-#define SPDCR		IOMEM(0xe6180008)
-#define SWUCR		IOMEM(0xe6180014)
-#define PSTR		IOMEM(0xe6180080)
+#define SPDCR		0x08	/* SYS Power Down Control Register */
+#define SWUCR		0x14	/* SYS Wakeup Control Register */
+#define PSTR		0x80	/* Power Status Register */
 
 #define PSTR_RETRIES	100
 #define PSTR_DELAY_US	10
@@ -30,8 +37,12 @@
 static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
 {
 	struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
-	unsigned int mask = 1 << rmobile_pd->bit_shift;
+	unsigned int mask;
 
+	if (rmobile_pd->bit_shift == ~0)
+		return -EBUSY;
+
+	mask = 1 << rmobile_pd->bit_shift;
 	if (rmobile_pd->suspend) {
 		int ret = rmobile_pd->suspend();
 
@@ -39,12 +50,12 @@
 			return ret;
 	}
 
-	if (__raw_readl(PSTR) & mask) {
+	if (__raw_readl(rmobile_pd->base + PSTR) & mask) {
 		unsigned int retry_count;
-		__raw_writel(mask, SPDCR);
+		__raw_writel(mask, rmobile_pd->base + SPDCR);
 
 		for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
-			if (!(__raw_readl(SPDCR) & mask))
+			if (!(__raw_readl(rmobile_pd->base + SPDCR) & mask))
 				break;
 			cpu_relax();
 		}
@@ -52,7 +63,8 @@
 
 	if (!rmobile_pd->no_debug)
 		pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n",
-			 genpd->name, mask, __raw_readl(PSTR));
+			 genpd->name, mask,
+			 __raw_readl(rmobile_pd->base + PSTR));
 
 	return 0;
 }
@@ -60,17 +72,21 @@
 static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd,
 				 bool do_resume)
 {
-	unsigned int mask = 1 << rmobile_pd->bit_shift;
+	unsigned int mask;
 	unsigned int retry_count;
 	int ret = 0;
 
-	if (__raw_readl(PSTR) & mask)
+	if (rmobile_pd->bit_shift == ~0)
+		return 0;
+
+	mask = 1 << rmobile_pd->bit_shift;
+	if (__raw_readl(rmobile_pd->base + PSTR) & mask)
 		goto out;
 
-	__raw_writel(mask, SWUCR);
+	__raw_writel(mask, rmobile_pd->base + SWUCR);
 
 	for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
-		if (!(__raw_readl(SWUCR) & mask))
+		if (!(__raw_readl(rmobile_pd->base + SWUCR) & mask))
 			break;
 		if (retry_count > PSTR_RETRIES)
 			udelay(PSTR_DELAY_US);
@@ -82,7 +98,8 @@
 
 	if (!rmobile_pd->no_debug)
 		pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
-			 rmobile_pd->genpd.name, mask, __raw_readl(PSTR));
+			 rmobile_pd->genpd.name, mask,
+			 __raw_readl(rmobile_pd->base + PSTR));
 
 out:
 	if (ret == 0 && rmobile_pd->resume && do_resume)
@@ -101,6 +118,36 @@
 	return true;
 }
 
+static int rmobile_pd_attach_dev(struct generic_pm_domain *domain,
+				 struct device *dev)
+{
+	int error;
+
+	error = pm_clk_create(dev);
+	if (error) {
+		dev_err(dev, "pm_clk_create failed %d\n", error);
+		return error;
+	}
+
+	error = pm_clk_add(dev, NULL);
+	if (error) {
+		dev_err(dev, "pm_clk_add failed %d\n", error);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	pm_clk_destroy(dev);
+	return error;
+}
+
+static void rmobile_pd_detach_dev(struct generic_pm_domain *domain,
+				  struct device *dev)
+{
+	pm_clk_destroy(dev);
+}
+
 static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 {
 	struct generic_pm_domain *genpd = &rmobile_pd->genpd;
@@ -111,9 +158,13 @@
 	genpd->dev_ops.active_wakeup	= rmobile_pd_active_wakeup;
 	genpd->power_off		= rmobile_pd_power_down;
 	genpd->power_on			= rmobile_pd_power_up;
+	genpd->attach_dev		= rmobile_pd_attach_dev;
+	genpd->detach_dev		= rmobile_pd_detach_dev;
 	__rmobile_pd_power_up(rmobile_pd, false);
 }
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+
 void rmobile_init_domains(struct rmobile_pm_domain domains[], int num)
 {
 	int j;
@@ -129,8 +180,6 @@
 	struct device *dev = &pdev->dev;
 
 	__pm_genpd_name_add_device(domain_name, dev, td);
-	if (pm_clk_no_clocks(dev))
-		pm_clk_add(dev, NULL);
 }
 
 void rmobile_add_devices_to_domains(struct pm_domain_device data[],
@@ -148,3 +197,238 @@
 		rmobile_add_device_to_domain_td(data[j].domain_name,
 						data[j].pdev, &latencies);
 }
+
+#else /* !CONFIG_ARCH_SHMOBILE_LEGACY */
+
+static int rmobile_pd_suspend_busy(void)
+{
+	/*
+	 * This domain should not be turned off.
+	 */
+	return -EBUSY;
+}
+
+static int rmobile_pd_suspend_console(void)
+{
+	/*
+	 * Serial consoles make use of SCIF hardware located in this domain,
+	 * hence keep the power domain on if "no_console_suspend" is set.
+	 */
+	return console_suspend_enabled ? 0 : -EBUSY;
+}
+
+enum pd_types {
+	PD_NORMAL,
+	PD_CPU,
+	PD_CONSOLE,
+	PD_DEBUG,
+	PD_MEMCTL,
+};
+
+#define MAX_NUM_SPECIAL_PDS	16
+
+static struct special_pd {
+	struct device_node *pd;
+	enum pd_types type;
+} special_pds[MAX_NUM_SPECIAL_PDS] __initdata;
+
+static unsigned int num_special_pds __initdata;
+
+static const struct of_device_id special_ids[] __initconst = {
+	{ .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG },
+	{ .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, },
+	{ .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, },
+	{ .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, },
+	{ /* sentinel */ },
+};
+
+static void __init add_special_pd(struct device_node *np, enum pd_types type)
+{
+	unsigned int i;
+	struct device_node *pd;
+
+	pd = of_parse_phandle(np, "power-domains", 0);
+	if (!pd)
+		return;
+
+	for (i = 0; i < num_special_pds; i++)
+		if (pd == special_pds[i].pd && type == special_pds[i].type) {
+			of_node_put(pd);
+			return;
+		}
+
+	if (num_special_pds == ARRAY_SIZE(special_pds)) {
+		pr_warn("Too many special PM domains\n");
+		of_node_put(pd);
+		return;
+	}
+
+	pr_debug("Special PM domain %s type %d for %s\n", pd->name, type,
+		 np->full_name);
+
+	special_pds[num_special_pds].pd = pd;
+	special_pds[num_special_pds].type = type;
+	num_special_pds++;
+}
+
+static void __init get_special_pds(void)
+{
+	struct device_node *np;
+	const struct of_device_id *id;
+
+	/* PM domains containing CPUs */
+	for_each_node_by_type(np, "cpu")
+		add_special_pd(np, PD_CPU);
+
+	/* PM domain containing console */
+	if (of_stdout)
+		add_special_pd(of_stdout, PD_CONSOLE);
+
+	/* PM domains containing other special devices */
+	for_each_matching_node_and_match(np, special_ids, &id)
+		add_special_pd(np, (enum pd_types)id->data);
+}
+
+static void __init put_special_pds(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_special_pds; i++)
+		of_node_put(special_pds[i].pd);
+}
+
+static enum pd_types __init pd_type(const struct device_node *pd)
+{
+	unsigned int i;
+
+	for (i = 0; i < num_special_pds; i++)
+		if (pd == special_pds[i].pd)
+			return special_pds[i].type;
+
+	return PD_NORMAL;
+}
+
+static void __init rmobile_setup_pm_domain(struct device_node *np,
+					   struct rmobile_pm_domain *pd)
+{
+	const char *name = pd->genpd.name;
+
+	switch (pd_type(np)) {
+	case PD_CPU:
+		/*
+		 * This domain contains the CPU core and therefore it should
+		 * only be turned off if the CPU is not in use.
+		 */
+		pr_debug("PM domain %s contains CPU\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = rmobile_pd_suspend_busy;
+		break;
+
+	case PD_CONSOLE:
+		pr_debug("PM domain %s contains serial console\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = rmobile_pd_suspend_console;
+		break;
+
+	case PD_DEBUG:
+		/*
+		 * This domain contains the Coresight-ETM hardware block and
+		 * therefore it should only be turned off if the debug module
+		 * is not in use.
+		 */
+		pr_debug("PM domain %s contains Coresight-ETM\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = rmobile_pd_suspend_busy;
+		break;
+
+	case PD_MEMCTL:
+		/*
+		 * This domain contains a memory-controller and therefore it
+		 * should only be turned off if memory is not in use.
+		 */
+		pr_debug("PM domain %s contains MEMCTL\n", name);
+		pd->gov = &pm_domain_always_on_gov;
+		pd->suspend = rmobile_pd_suspend_busy;
+		break;
+
+	case PD_NORMAL:
+		break;
+	}
+
+	rmobile_init_pm_domain(pd);
+}
+
+static int __init rmobile_add_pm_domains(void __iomem *base,
+					 struct device_node *parent,
+					 struct generic_pm_domain *genpd_parent)
+{
+	struct device_node *np;
+
+	for_each_child_of_node(parent, np) {
+		struct rmobile_pm_domain *pd;
+		u32 idx = ~0;
+
+		if (of_property_read_u32(np, "reg", &idx)) {
+			/* always-on domain */
+		}
+
+		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+		if (!pd)
+			return -ENOMEM;
+
+		pd->genpd.name = np->name;
+		pd->base = base;
+		pd->bit_shift = idx;
+
+		rmobile_setup_pm_domain(np, pd);
+		if (genpd_parent)
+			pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
+		of_genpd_add_provider_simple(np, &pd->genpd);
+
+		rmobile_add_pm_domains(base, np, &pd->genpd);
+	}
+	return 0;
+}
+
+static int __init rmobile_init_pm_domains(void)
+{
+	struct device_node *np, *pmd;
+	bool scanned = false;
+	void __iomem *base;
+	int ret = 0;
+
+	for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
+		base = of_iomap(np, 0);
+		if (!base) {
+			pr_warn("%s cannot map reg 0\n", np->full_name);
+			continue;
+		}
+
+		pmd = of_get_child_by_name(np, "pm-domains");
+		if (!pmd) {
+			pr_warn("%s lacks pm-domains node\n", np->full_name);
+			continue;
+		}
+
+		if (!scanned) {
+			/* Find PM domains containing special blocks */
+			get_special_pds();
+			scanned = true;
+		}
+
+		ret = rmobile_add_pm_domains(base, pmd, NULL);
+		of_node_put(pmd);
+		if (ret) {
+			of_node_put(np);
+			break;
+		}
+	}
+
+	put_special_pds();
+
+	return ret;
+}
+
+core_initcall(rmobile_init_pm_domains);
+
+#endif /* !CONFIG_ARCH_SHMOBILE_LEGACY */
diff --git a/arch/arm/mach-shmobile/pm-rmobile.h b/arch/arm/mach-shmobile/pm-rmobile.h
index 8f66b34..5321978 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.h
+++ b/arch/arm/mach-shmobile/pm-rmobile.h
@@ -21,6 +21,7 @@
 	struct dev_power_governor *gov;
 	int (*suspend)(void);
 	void (*resume)(void);
+	void __iomem *base;
 	unsigned int bit_shift;
 	bool no_debug;
 };
@@ -36,7 +37,7 @@
 	struct platform_device *pdev;
 };
 
-#ifdef CONFIG_PM_RMOBILE
+#if defined(CONFIG_PM_RMOBILE) && defined(CONFIG_ARCH_SHMOBILE_LEGACY)
 extern void rmobile_init_domains(struct rmobile_pm_domain domains[], int num);
 extern void rmobile_add_device_to_domain_td(const char *domain_name,
 					    struct platform_device *pdev,
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 0e37da6..c0293ae 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -45,6 +45,8 @@
 #define PLLC01STPCR IOMEM(0xe61500c8)
 
 /* SYSC */
+#define SYSC_BASE IOMEM(0xe6180000)
+
 #define SBAR IOMEM(0xe6180020)
 #define WUPRMSK IOMEM(0xe6180028)
 #define WUPSMSK IOMEM(0xe618002c)
@@ -118,24 +120,28 @@
 		.genpd.name = "A4LC",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 1,
 	},
 	{
 		.genpd.name = "A4MP",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 2,
 	},
 	{
 		.genpd.name = "D4",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 3,
 	},
 	{
 		.genpd.name = "A4R",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 5,
 		.suspend = sh7372_a4r_pd_suspend,
 		.resume = sh7372_intcs_resume,
@@ -144,18 +150,21 @@
 		.genpd.name = "A3RV",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 6,
 	},
 	{
 		.genpd.name = "A3RI",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 8,
 	},
 	{
 		.genpd.name = "A4S",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 10,
 		.gov = &pm_domain_always_on_gov,
 		.no_debug = true,
@@ -166,6 +175,7 @@
 		.genpd.name = "A3SP",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 11,
 		.gov = &pm_domain_always_on_gov,
 		.no_debug = true,
@@ -175,6 +185,7 @@
 		.genpd.name = "A3SG",
 		.genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
 		.genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+		.base = SYSC_BASE,
 		.bit_shift = 13,
 	},
 };
diff --git a/arch/arm/mach-shmobile/r8a7790.h b/arch/arm/mach-shmobile/r8a7790.h
index 388f051..bf73a85 100644
--- a/arch/arm/mach-shmobile/r8a7790.h
+++ b/arch/arm/mach-shmobile/r8a7790.h
@@ -1,34 +1,6 @@
 #ifndef __ASM_R8A7790_H__
 #define __ASM_R8A7790_H__
 
-/* DMA slave IDs */
-enum {
-	RCAR_DMA_SLAVE_INVALID,
-	AUDIO_DMAC_SLAVE_SSI0_TX,
-	AUDIO_DMAC_SLAVE_SSI0_RX,
-	AUDIO_DMAC_SLAVE_SSI1_TX,
-	AUDIO_DMAC_SLAVE_SSI1_RX,
-	AUDIO_DMAC_SLAVE_SSI2_TX,
-	AUDIO_DMAC_SLAVE_SSI2_RX,
-	AUDIO_DMAC_SLAVE_SSI3_TX,
-	AUDIO_DMAC_SLAVE_SSI3_RX,
-	AUDIO_DMAC_SLAVE_SSI4_TX,
-	AUDIO_DMAC_SLAVE_SSI4_RX,
-	AUDIO_DMAC_SLAVE_SSI5_TX,
-	AUDIO_DMAC_SLAVE_SSI5_RX,
-	AUDIO_DMAC_SLAVE_SSI6_TX,
-	AUDIO_DMAC_SLAVE_SSI6_RX,
-	AUDIO_DMAC_SLAVE_SSI7_TX,
-	AUDIO_DMAC_SLAVE_SSI7_RX,
-	AUDIO_DMAC_SLAVE_SSI8_TX,
-	AUDIO_DMAC_SLAVE_SSI8_RX,
-	AUDIO_DMAC_SLAVE_SSI9_TX,
-	AUDIO_DMAC_SLAVE_SSI9_RX,
-};
-
-void r8a7790_add_standard_devices(void);
-void r8a7790_clock_init(void);
-void r8a7790_pinmux_init(void);
 void r8a7790_pm_init(void);
 extern struct smp_operations r8a7790_smp_ops;
 
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index d191cf4..dd64caf 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -656,7 +656,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name	= "arm-pmu",
+	.name	= "armv7-pmu",
 	.id	= -1,
 	.num_resources = ARRAY_SIZE(pmu_resources),
 	.resource = pmu_resources,
diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c
index ec7d97d..3a18af4 100644
--- a/arch/arm/mach-shmobile/setup-r8a7790.c
+++ b/arch/arm/mach-shmobile/setup-r8a7790.c
@@ -14,295 +14,14 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/of_platform.h>
-#include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/irq-renesas-irqc.h>
-#include <linux/serial_sci.h>
-#include <linux/sh_dma.h>
-#include <linux/sh_timer.h>
+#include <linux/init.h>
 
 #include <asm/mach/arch.h>
 
 #include "common.h"
-#include "dma-register.h"
-#include "irqs.h"
 #include "r8a7790.h"
 #include "rcar-gen2.h"
 
-/* Audio-DMAC */
-#define AUDIO_DMAC_SLAVE(_id, _addr, t, r)			\
-{								\
-	.slave_id	= AUDIO_DMAC_SLAVE_## _id ##_TX,	\
-	.addr		= _addr + 0x8,				\
-	.chcr		= CHCR_TX(XMIT_SZ_32BIT),		\
-	.mid_rid	= t,					\
-}, {								\
-	.slave_id	= AUDIO_DMAC_SLAVE_## _id ##_RX,	\
-	.addr		= _addr + 0xc,				\
-	.chcr		= CHCR_RX(XMIT_SZ_32BIT),		\
-	.mid_rid	= r,					\
-}
-
-static const struct sh_dmae_slave_config r8a7790_audio_dmac_slaves[] = {
-	AUDIO_DMAC_SLAVE(SSI0, 0xec241000, 0x01, 0x02),
-	AUDIO_DMAC_SLAVE(SSI1, 0xec241040, 0x03, 0x04),
-	AUDIO_DMAC_SLAVE(SSI2, 0xec241080, 0x05, 0x06),
-	AUDIO_DMAC_SLAVE(SSI3, 0xec2410c0, 0x07, 0x08),
-	AUDIO_DMAC_SLAVE(SSI4, 0xec241100, 0x09, 0x0a),
-	AUDIO_DMAC_SLAVE(SSI5, 0xec241140, 0x0b, 0x0c),
-	AUDIO_DMAC_SLAVE(SSI6, 0xec241180, 0x0d, 0x0e),
-	AUDIO_DMAC_SLAVE(SSI7, 0xec2411c0, 0x0f, 0x10),
-	AUDIO_DMAC_SLAVE(SSI8, 0xec241200, 0x11, 0x12),
-	AUDIO_DMAC_SLAVE(SSI9, 0xec241240, 0x13, 0x14),
-};
-
-#define DMAE_CHANNEL(a, b)			\
-{						\
-	.offset		= (a) - 0x20,		\
-	.dmars		= (a) - 0x20 + 0x40,	\
-	.chclr_bit	= (b),			\
-	.chclr_offset	= 0x80 - 0x20,		\
-}
-
-static const struct sh_dmae_channel r8a7790_audio_dmac_channels[] = {
-	DMAE_CHANNEL(0x8000, 0),
-	DMAE_CHANNEL(0x8080, 1),
-	DMAE_CHANNEL(0x8100, 2),
-	DMAE_CHANNEL(0x8180, 3),
-	DMAE_CHANNEL(0x8200, 4),
-	DMAE_CHANNEL(0x8280, 5),
-	DMAE_CHANNEL(0x8300, 6),
-	DMAE_CHANNEL(0x8380, 7),
-	DMAE_CHANNEL(0x8400, 8),
-	DMAE_CHANNEL(0x8480, 9),
-	DMAE_CHANNEL(0x8500, 10),
-	DMAE_CHANNEL(0x8580, 11),
-	DMAE_CHANNEL(0x8600, 12),
-};
-
-static struct sh_dmae_pdata r8a7790_audio_dmac_platform_data = {
-	.slave		= r8a7790_audio_dmac_slaves,
-	.slave_num	= ARRAY_SIZE(r8a7790_audio_dmac_slaves),
-	.channel	= r8a7790_audio_dmac_channels,
-	.channel_num	= ARRAY_SIZE(r8a7790_audio_dmac_channels),
-	.ts_low_shift	= TS_LOW_SHIFT,
-	.ts_low_mask	= TS_LOW_BIT << TS_LOW_SHIFT,
-	.ts_high_shift	= TS_HI_SHIFT,
-	.ts_high_mask	= TS_HI_BIT << TS_HI_SHIFT,
-	.ts_shift	= dma_ts_shift,
-	.ts_shift_num	= ARRAY_SIZE(dma_ts_shift),
-	.dmaor_init	= DMAOR_DME,
-	.chclr_present	= 1,
-	.chclr_bitwise	= 1,
-};
-
-static struct resource r8a7790_audio_dmac_resources[] = {
-	/* Channel registers and DMAOR for low */
-	DEFINE_RES_MEM(0xec700020, 0x8663 - 0x20),
-	DEFINE_RES_IRQ(gic_spi(346)),
-	DEFINE_RES_NAMED(gic_spi(320), 13, NULL, IORESOURCE_IRQ),
-
-	/* Channel registers and DMAOR for hi */
-	DEFINE_RES_MEM(0xec720020, 0x8663 - 0x20), /* hi */
-	DEFINE_RES_IRQ(gic_spi(347)),
-	DEFINE_RES_NAMED(gic_spi(333), 13, NULL, IORESOURCE_IRQ),
-};
-
-#define r8a7790_register_audio_dmac(id)				\
-	platform_device_register_resndata(			\
-		NULL, "sh-dma-engine", id,			\
-		&r8a7790_audio_dmac_resources[id * 3],	3,	\
-		&r8a7790_audio_dmac_platform_data,		\
-		sizeof(r8a7790_audio_dmac_platform_data))
-
-static const struct resource pfc_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe6060000, 0x250),
-};
-
-#define r8a7790_register_pfc()						\
-	platform_device_register_simple("pfc-r8a7790", -1, pfc_resources, \
-					ARRAY_SIZE(pfc_resources))
-
-#define R8A7790_GPIO(idx)						\
-static const struct resource r8a7790_gpio##idx##_resources[] __initconst = { \
-	DEFINE_RES_MEM(0xe6050000 + 0x1000 * (idx), 0x50),		\
-	DEFINE_RES_IRQ(gic_spi(4 + (idx))),				\
-};									\
-									\
-static const struct gpio_rcar_config					\
-r8a7790_gpio##idx##_platform_data __initconst = {			\
-	.gpio_base	= 32 * (idx),					\
-	.irq_base	= 0,						\
-	.number_of_pins	= 32,						\
-	.pctl_name	= "pfc-r8a7790",				\
-	.has_both_edge_trigger = 1,					\
-};									\
-
-R8A7790_GPIO(0);
-R8A7790_GPIO(1);
-R8A7790_GPIO(2);
-R8A7790_GPIO(3);
-R8A7790_GPIO(4);
-R8A7790_GPIO(5);
-
-#define r8a7790_register_gpio(idx)					\
-	platform_device_register_resndata(NULL, "gpio_rcar", idx,	\
-		r8a7790_gpio##idx##_resources,				\
-		ARRAY_SIZE(r8a7790_gpio##idx##_resources),		\
-		&r8a7790_gpio##idx##_platform_data,			\
-		sizeof(r8a7790_gpio##idx##_platform_data))
-
-static struct resource i2c_resources[] __initdata = {
-	/* I2C0 */
-	DEFINE_RES_MEM(0xE6508000, 0x40),
-	DEFINE_RES_IRQ(gic_spi(287)),
-	/* I2C1 */
-	DEFINE_RES_MEM(0xE6518000, 0x40),
-	DEFINE_RES_IRQ(gic_spi(288)),
-	/* I2C2 */
-	DEFINE_RES_MEM(0xE6530000, 0x40),
-	DEFINE_RES_IRQ(gic_spi(286)),
-	/* I2C3 */
-	DEFINE_RES_MEM(0xE6540000, 0x40),
-	DEFINE_RES_IRQ(gic_spi(290)),
-
-};
-
-#define r8a7790_register_i2c(idx)		\
-	platform_device_register_simple(	\
-		"i2c-rcar_gen2", idx,		\
-		i2c_resources + (2 * idx), 2);	\
-
-void __init r8a7790_pinmux_init(void)
-{
-	r8a7790_register_pfc();
-	r8a7790_register_gpio(0);
-	r8a7790_register_gpio(1);
-	r8a7790_register_gpio(2);
-	r8a7790_register_gpio(3);
-	r8a7790_register_gpio(4);
-	r8a7790_register_gpio(5);
-}
-
-#define __R8A7790_SCIF(scif_type, _scscr, index, baseaddr, irq)		\
-static struct plat_sci_port scif##index##_platform_data = {		\
-	.type		= scif_type,					\
-	.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,		\
-	.scscr		= _scscr,					\
-};									\
-									\
-static struct resource scif##index##_resources[] = {			\
-	DEFINE_RES_MEM(baseaddr, 0x100),				\
-	DEFINE_RES_IRQ(irq),						\
-}
-
-#define R8A7790_SCIF(index, baseaddr, irq)				\
-	__R8A7790_SCIF(PORT_SCIF, SCSCR_RE | SCSCR_TE,			\
-		       index, baseaddr, irq)
-
-#define R8A7790_SCIFA(index, baseaddr, irq)				\
-	__R8A7790_SCIF(PORT_SCIFA, SCSCR_RE | SCSCR_TE | SCSCR_CKE0,	\
-		       index, baseaddr, irq)
-
-#define R8A7790_SCIFB(index, baseaddr, irq)				\
-	__R8A7790_SCIF(PORT_SCIFB, SCSCR_RE | SCSCR_TE,			\
-		       index, baseaddr, irq)
-
-#define R8A7790_HSCIF(index, baseaddr, irq)				\
-	__R8A7790_SCIF(PORT_HSCIF, SCSCR_RE | SCSCR_TE,			\
-		       index, baseaddr, irq)
-
-R8A7790_SCIFA(0, 0xe6c40000, gic_spi(144)); /* SCIFA0 */
-R8A7790_SCIFA(1, 0xe6c50000, gic_spi(145)); /* SCIFA1 */
-R8A7790_SCIFB(2, 0xe6c20000, gic_spi(148)); /* SCIFB0 */
-R8A7790_SCIFB(3, 0xe6c30000, gic_spi(149)); /* SCIFB1 */
-R8A7790_SCIFB(4, 0xe6ce0000, gic_spi(150)); /* SCIFB2 */
-R8A7790_SCIFA(5, 0xe6c60000, gic_spi(151)); /* SCIFA2 */
-R8A7790_SCIF(6,  0xe6e60000, gic_spi(152)); /* SCIF0 */
-R8A7790_SCIF(7,  0xe6e68000, gic_spi(153)); /* SCIF1 */
-R8A7790_HSCIF(8, 0xe62c0000, gic_spi(154)); /* HSCIF0 */
-R8A7790_HSCIF(9, 0xe62c8000, gic_spi(155)); /* HSCIF1 */
-
-#define r8a7790_register_scif(index)					       \
-	platform_device_register_resndata(NULL, "sh-sci", index,  	       \
-					  scif##index##_resources,	       \
-					  ARRAY_SIZE(scif##index##_resources), \
-					  &scif##index##_platform_data,	       \
-					  sizeof(scif##index##_platform_data))
-
-static const struct renesas_irqc_config irqc0_data __initconst = {
-	.irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
-};
-
-static const struct resource irqc0_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe61c0000, 0x200), /* IRQC Event Detector Block_0 */
-	DEFINE_RES_IRQ(gic_spi(0)), /* IRQ0 */
-	DEFINE_RES_IRQ(gic_spi(1)), /* IRQ1 */
-	DEFINE_RES_IRQ(gic_spi(2)), /* IRQ2 */
-	DEFINE_RES_IRQ(gic_spi(3)), /* IRQ3 */
-};
-
-#define r8a7790_register_irqc(idx)					\
-	platform_device_register_resndata(NULL, "renesas_irqc",		\
-					  idx, irqc##idx##_resources,	\
-					  ARRAY_SIZE(irqc##idx##_resources), \
-					  &irqc##idx##_data,		\
-					  sizeof(struct renesas_irqc_config))
-
-static const struct resource thermal_resources[] __initconst = {
-	DEFINE_RES_MEM(0xe61f0000, 0x14),
-	DEFINE_RES_MEM(0xe61f0100, 0x38),
-	DEFINE_RES_IRQ(gic_spi(69)),
-};
-
-#define r8a7790_register_thermal()					\
-	platform_device_register_simple("rcar_thermal", -1,		\
-					thermal_resources,		\
-					ARRAY_SIZE(thermal_resources))
-
-static struct sh_timer_config cmt0_platform_data = {
-	.channels_mask = 0x60,
-};
-
-static struct resource cmt0_resources[] = {
-	DEFINE_RES_MEM(0xffca0000, 0x1004),
-	DEFINE_RES_IRQ(gic_spi(142)),
-};
-
-#define r8a7790_register_cmt(idx)					\
-	platform_device_register_resndata(NULL, "sh-cmt-48-gen2",	\
-					  idx, cmt##idx##_resources,	\
-					  ARRAY_SIZE(cmt##idx##_resources), \
-					  &cmt##idx##_platform_data,	\
-					  sizeof(struct sh_timer_config))
-
-void __init r8a7790_add_standard_devices(void)
-{
-	r8a7790_register_scif(0);
-	r8a7790_register_scif(1);
-	r8a7790_register_scif(2);
-	r8a7790_register_scif(3);
-	r8a7790_register_scif(4);
-	r8a7790_register_scif(5);
-	r8a7790_register_scif(6);
-	r8a7790_register_scif(7);
-	r8a7790_register_scif(8);
-	r8a7790_register_scif(9);
-	r8a7790_register_cmt(0);
-	r8a7790_register_irqc(0);
-	r8a7790_register_thermal();
-	r8a7790_register_i2c(0);
-	r8a7790_register_i2c(1);
-	r8a7790_register_i2c(2);
-	r8a7790_register_i2c(3);
-	r8a7790_register_audio_dmac(0);
-	r8a7790_register_audio_dmac(1);
-}
-
-#ifdef CONFIG_USE_OF
-
 static const char * const r8a7790_boards_compat_dt[] __initconst = {
 	"renesas,r8a7790",
 	NULL,
@@ -316,4 +35,3 @@
 	.reserve	= rcar_gen2_reserve,
 	.dt_compat	= r8a7790_boards_compat_dt,
 MACHINE_END
-#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c
index cc9470d..d1fa625 100644
--- a/arch/arm/mach-shmobile/setup-rcar-gen2.c
+++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c
@@ -52,15 +52,13 @@
 {
 #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK)
 	u32 mode = rcar_gen2_read_mode_pins();
-	bool is_e2 = (bool)of_find_compatible_node(NULL, NULL,
-		"renesas,r8a7794");
 #endif
 #ifdef CONFIG_ARM_ARCH_TIMER
 	void __iomem *base;
 	int extal_mhz = 0;
 	u32 freq;
 
-	if (is_e2) {
+	if (of_machine_is_compatible("renesas,r8a7794")) {
 		freq = 260000000 / 8;	/* ZS / 8 */
 		/* CNTVOFF has to be initialized either from non-secure
 		 * Hypervisor mode or secure Monitor mode with SCR.NS==1.
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index fb5e1bb..faea74a 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -563,7 +563,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name		= "arm-pmu",
+	.name		= "armv7-pmu",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(pmu_resources),
 	.resource	= pmu_resources,
@@ -766,7 +766,9 @@
 void __init sh73a0_earlytimer_init(void)
 {
 	shmobile_init_delay();
+#ifndef CONFIG_COMMON_CLK
 	sh73a0_clock_init();
+#endif
 	shmobile_earlytimer_init();
 	sh73a0_register_twd();
 }
@@ -785,8 +787,9 @@
 void __init sh73a0_add_standard_devices_dt(void)
 {
 	/* clocks are setup late during boot in the case of DT */
+#ifndef CONFIG_COMMON_CLK
 	sh73a0_clock_init();
-
+#endif
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
index 3f761f8..9fc280e 100644
--- a/arch/arm/mach-shmobile/smp-r8a7779.c
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -56,7 +56,7 @@
 	[3] = &r8a7779_ch_cpu3,
 };
 
-#ifdef CONFIG_HAVE_ARM_TWD
+#if defined(CONFIG_HAVE_ARM_TWD) && !defined(CONFIG_ARCH_MULTIPLATFORM)
 static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, R8A7779_SCU_BASE + 0x600, 29);
 void __init r8a7779_register_twd(void)
 {
diff --git a/arch/arm/mach-sti/board-dt.c b/arch/arm/mach-sti/board-dt.c
index 3cf6ef8..b067390 100644
--- a/arch/arm/mach-sti/board-dt.c
+++ b/arch/arm/mach-sti/board-dt.c
@@ -18,6 +18,7 @@
 	"st,stih415",
 	"st,stih416",
 	"st,stih407",
+	"st,stih418",
 	NULL
 };
 
diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c
index e44d028..587b046 100644
--- a/arch/arm/mach-sunxi/platsmp.c
+++ b/arch/arm/mach-sunxi/platsmp.c
@@ -120,4 +120,4 @@
 	.smp_prepare_cpus	= sun6i_smp_prepare_cpus,
 	.smp_boot_secondary	= sun6i_smp_boot_secondary,
 };
-CPU_METHOD_OF_DECLARE(sun6i_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
+CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 1f98675..1bc811a 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -13,9 +13,15 @@
 #include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach/arch.h>
 
+static void __init sunxi_dt_cpufreq_init(void)
+{
+	platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+}
+
 static const char * const sunxi_board_dt_compat[] = {
 	"allwinner,sun4i-a10",
 	"allwinner,sun5i-a10s",
@@ -25,10 +31,12 @@
 
 DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
 	.dt_compat	= sunxi_board_dt_compat,
+	.init_late	= sunxi_dt_cpufreq_init,
 MACHINE_END
 
 static const char * const sun6i_board_dt_compat[] = {
 	"allwinner,sun6i-a31",
+	"allwinner,sun6i-a31s",
 	NULL,
 };
 
@@ -44,6 +52,7 @@
 DT_MACHINE_START(SUN6I_DT, "Allwinner sun6i (A31) Family")
 	.init_time	= sun6i_timer_init,
 	.dt_compat	= sun6i_board_dt_compat,
+	.init_late	= sunxi_dt_cpufreq_init,
 MACHINE_END
 
 static const char * const sun7i_board_dt_compat[] = {
@@ -53,6 +62,7 @@
 
 DT_MACHINE_START(SUN7I_DT, "Allwinner sun7i (A20) Family")
 	.dt_compat	= sun7i_board_dt_compat,
+	.init_late	= sunxi_dt_cpufreq_init,
 MACHINE_END
 
 static const char * const sun8i_board_dt_compat[] = {
@@ -62,6 +72,7 @@
 
 DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
 	.dt_compat	= sun8i_board_dt_compat,
+	.init_late	= sunxi_dt_cpufreq_init,
 MACHINE_END
 
 static const char * const sun9i_board_dt_compat[] = {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index d0be9a1..5d1a318 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -27,6 +27,7 @@
 	select PINCTRL_TEGRA20
 	select PL310_ERRATA_727915 if CACHE_L2X0
 	select PL310_ERRATA_769419 if CACHE_L2X0
+	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
 	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -37,6 +38,7 @@
 	select ARM_ERRATA_764369 if SMP
 	select PINCTRL_TEGRA30
 	select PL310_ERRATA_769419 if CACHE_L2X0
+	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra T30 processor family, based on the
 	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -47,6 +49,7 @@
 	select ARM_L1_CACHE_SHIFT_6
 	select HAVE_ARM_ARCH_TIMER
 	select PINCTRL_TEGRA114
+	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra T114 processor family, based on the
 	  ARM CortexA15MP CPU
@@ -56,6 +59,7 @@
 	select ARM_L1_CACHE_SHIFT_6
 	select HAVE_ARM_ARCH_TIMER
 	select PINCTRL_TEGRA124
+	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra T124 processor family, based on the
 	  ARM CortexA15MP CPU
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 08fb8c8..6ea09fe 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -728,43 +728,6 @@
 };
 #endif
 
-#ifdef CONFIG_LEDS
-#define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
-
-static void versatile_leds_event(led_event_t ledevt)
-{
-	unsigned long flags;
-	u32 val;
-
-	local_irq_save(flags);
-	val = readl(VA_LEDS_BASE);
-
-	switch (ledevt) {
-	case led_idle_start:
-		val = val & ~VERSATILE_SYS_LED0;
-		break;
-
-	case led_idle_end:
-		val = val | VERSATILE_SYS_LED0;
-		break;
-
-	case led_timer:
-		val = val ^ VERSATILE_SYS_LED1;
-		break;
-
-	case led_halted:
-		val = 0;
-		break;
-
-	default:
-		break;
-	}
-
-	writel(val, VA_LEDS_BASE);
-	local_irq_restore(flags);
-}
-#endif	/* CONFIG_LEDS */
-
 void versatile_restart(enum reboot_mode mode, const char *cmd)
 {
 	void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index aaa5162..78e5e00 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -9,6 +9,8 @@
 	select HAVE_ARM_TWD if SMP
 	select ICST
 	select MFD_SYSCON
+	select PINCTRL
+	select PINCTRL_ZYNQ
 	select SOC_BUS
 	help
 	  Support for Xilinx Zynq ARM Cortex A9 Platform
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 26f92c2..c887196 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -146,8 +146,6 @@
 
 	platform_device_register(&zynq_cpuidle_device);
 	platform_device_register_full(&devinfo);
-
-	zynq_slcr_init();
 }
 
 static void __init zynq_timer_init(void)
diff --git a/arch/arm/mach-zynq/pm.c b/arch/arm/mach-zynq/pm.c
index 911fcf8..fa44fc1 100644
--- a/arch/arm/mach-zynq/pm.c
+++ b/arch/arm/mach-zynq/pm.c
@@ -61,7 +61,7 @@
 /**
  * zynq_pm_late_init() - Power management init
  *
- * Initialization of power management related featurs and infrastructure.
+ * Initialization of power management related features and infrastructure.
  */
 void __init zynq_pm_late_init(void)
 {
diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c
index d4cb50c..c3c24fd8 100644
--- a/arch/arm/mach-zynq/slcr.c
+++ b/arch/arm/mach-zynq/slcr.c
@@ -47,11 +47,6 @@
  */
 static int zynq_slcr_write(u32 val, u32 offset)
 {
-	if (!zynq_slcr_regmap) {
-		writel(val, zynq_slcr_base + offset);
-		return 0;
-	}
-
 	return regmap_write(zynq_slcr_regmap, offset, val);
 }
 
@@ -65,12 +60,7 @@
  */
 static int zynq_slcr_read(u32 *val, u32 offset)
 {
-	if (zynq_slcr_regmap)
-		return regmap_read(zynq_slcr_regmap, offset, val);
-
-	*val = readl(zynq_slcr_base + offset);
-
-	return 0;
+	return regmap_read(zynq_slcr_regmap, offset, val);
 }
 
 /**
@@ -196,23 +186,6 @@
 }
 
 /**
- * zynq_slcr_init - Regular slcr driver init
- * Return:	0 on success, negative errno otherwise.
- *
- * Called early during boot from platform code to remap SLCR area.
- */
-int __init zynq_slcr_init(void)
-{
-	zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
-	if (IS_ERR(zynq_slcr_regmap)) {
-		pr_err("%s: failed to find zynq-slcr\n", __func__);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-/**
  * zynq_early_slcr_init - Early slcr init function
  *
  * Return:	0 on success, negative errno otherwise.
@@ -237,6 +210,12 @@
 
 	np->data = (__force void *)zynq_slcr_base;
 
+	zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
+	if (IS_ERR(zynq_slcr_regmap)) {
+		pr_err("%s: failed to find zynq-slcr\n", __func__);
+		return -ENODEV;
+	}
+
 	/* unlock the SLCR so that registers can be changed */
 	zynq_slcr_unlock();
 
diff --git a/arch/arm/plat-iop/pmu.c b/arch/arm/plat-iop/pmu.c
index ad9f974..c6d979a 100644
--- a/arch/arm/plat-iop/pmu.c
+++ b/arch/arm/plat-iop/pmu.c
@@ -24,7 +24,7 @@
 };
 
 static struct platform_device pmu_device = {
-	.name		= "arm-pmu",
+	.name		= "xscale-pmu",
 	.id		= -1,
 	.resource	= &pmu_resource,
 	.num_resources	= 1,
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 24770e5..6416e03 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -151,14 +151,6 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP1
-static inline int get_gdma_dev(int req)
-{
-	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
-	int shift = ((req - 1) % 5) * 6;
-
-	return ((omap_readl(reg) >> shift) & 0x3f) + 1;
-}
-
 static inline void set_gdma_dev(int req, int dev)
 {
 	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 9bd2776..cb8e3d6 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -236,13 +236,6 @@
 	help
 	  Compile in common setup code for S3C CAMIF devices
 
-# DMA
-
-config S3C_DMA
-	bool
-	help
-	  Internal configuration for S3C DMA core
-
 config SAMSUNG_PM_GPIO
 	bool
 	default y if GPIO_SAMSUNG && PM
@@ -250,14 +243,6 @@
 	  Include legacy GPIO power management code for platforms not using
 	  pinctrl-samsung driver.
 
-config SAMSUNG_DMADEV
-	bool "Use legacy Samsung DMA abstraction"
-	depends on CPU_S5PV210 || ARCH_S3C64XX
-	select DMADEVICES
-	default y
-	help
-	  Use DMA device engine for PL330 DMAC.
-
 endif
 
 config S5P_DEV_MFC
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 87746c3..1a29ab1 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -26,12 +26,6 @@
 
 obj-$(CONFIG_S3C_SETUP_CAMIF)	+= setup-camif.o
 
-# DMA support
-
-obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
-
-obj-$(CONFIG_SAMSUNG_DMADEV)	+= dma-ops.o
-
 # PM support
 
 obj-$(CONFIG_PM_SLEEP)		+= pm-common.o
diff --git a/arch/arm/plat-samsung/cpu.c b/arch/arm/plat-samsung/cpu.c
index 360618e..71333bb 100644
--- a/arch/arm/plat-samsung/cpu.c
+++ b/arch/arm/plat-samsung/cpu.c
@@ -40,10 +40,14 @@
 	}
 
 	samsung_cpu_rev = 0;
+
+	pr_info("Samsung CPU ID: 0x%08lx\n", samsung_cpu_id);
 }
 
 void __init s5p_init_cpu(void __iomem *cpuid_addr)
 {
 	samsung_cpu_id = __raw_readl(cpuid_addr);
 	samsung_cpu_rev = samsung_cpu_id & 0xFF;
+
+	pr_info("Samsung CPU ID: 0x%08lx\n", samsung_cpu_id);
 }
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
deleted file mode 100644
index 886326e..0000000
--- a/arch/arm/plat-samsung/dma-ops.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* linux/arch/arm/plat-samsung/dma-ops.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Samsung DMA Operations
- *
- * 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/errno.h>
-#include <linux/amba/pl330.h>
-#include <linux/scatterlist.h>
-#include <linux/export.h>
-
-#include <mach/dma.h>
-
-#if defined(CONFIG_PL330_DMA)
-#define dma_filter pl330_filter
-#elif defined(CONFIG_S3C64XX_PL080)
-#define dma_filter pl08x_filter_id
-#endif
-
-static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
-				struct samsung_dma_req *param,
-				struct device *dev, char *ch_name)
-{
-	dma_cap_mask_t mask;
-
-	dma_cap_zero(mask);
-	dma_cap_set(param->cap, mask);
-
-	if (dev->of_node)
-		return (unsigned)dma_request_slave_channel(dev, ch_name);
-	else
-		return (unsigned)dma_request_channel(mask, dma_filter,
-							(void *)dma_ch);
-}
-
-static int samsung_dmadev_release(unsigned ch, void *param)
-{
-	dma_release_channel((struct dma_chan *)ch);
-
-	return 0;
-}
-
-static int samsung_dmadev_config(unsigned ch,
-				struct samsung_dma_config *param)
-{
-	struct dma_chan *chan = (struct dma_chan *)ch;
-	struct dma_slave_config slave_config;
-
-	if (param->direction == DMA_DEV_TO_MEM) {
-		memset(&slave_config, 0, sizeof(struct dma_slave_config));
-		slave_config.direction = param->direction;
-		slave_config.src_addr = param->fifo;
-		slave_config.src_addr_width = param->width;
-		slave_config.src_maxburst = 1;
-		dmaengine_slave_config(chan, &slave_config);
-	} else if (param->direction == DMA_MEM_TO_DEV) {
-		memset(&slave_config, 0, sizeof(struct dma_slave_config));
-		slave_config.direction = param->direction;
-		slave_config.dst_addr = param->fifo;
-		slave_config.dst_addr_width = param->width;
-		slave_config.dst_maxburst = 1;
-		dmaengine_slave_config(chan, &slave_config);
-	} else {
-		pr_warn("unsupported direction\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int samsung_dmadev_prepare(unsigned ch,
-			struct samsung_dma_prep *param)
-{
-	struct scatterlist sg;
-	struct dma_chan *chan = (struct dma_chan *)ch;
-	struct dma_async_tx_descriptor *desc;
-
-	switch (param->cap) {
-	case DMA_SLAVE:
-		sg_init_table(&sg, 1);
-		sg_dma_len(&sg) = param->len;
-		sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)),
-			    param->len, offset_in_page(param->buf));
-		sg_dma_address(&sg) = param->buf;
-
-		desc = dmaengine_prep_slave_sg(chan,
-			&sg, 1, param->direction, DMA_PREP_INTERRUPT);
-		break;
-	case DMA_CYCLIC:
-		desc = dmaengine_prep_dma_cyclic(chan, param->buf,
-			param->len, param->period, param->direction,
-			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-		break;
-	default:
-		dev_err(&chan->dev->device, "unsupported format\n");
-		return -EFAULT;
-	}
-
-	if (!desc) {
-		dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
-		return -EFAULT;
-	}
-
-	desc->callback = param->fp;
-	desc->callback_param = param->fp_param;
-
-	dmaengine_submit((struct dma_async_tx_descriptor *)desc);
-
-	return 0;
-}
-
-static inline int samsung_dmadev_trigger(unsigned ch)
-{
-	dma_async_issue_pending((struct dma_chan *)ch);
-
-	return 0;
-}
-
-static inline int samsung_dmadev_flush(unsigned ch)
-{
-	return dmaengine_terminate_all((struct dma_chan *)ch);
-}
-
-static struct samsung_dma_ops dmadev_ops = {
-	.request	= samsung_dmadev_request,
-	.release	= samsung_dmadev_release,
-	.config		= samsung_dmadev_config,
-	.prepare	= samsung_dmadev_prepare,
-	.trigger	= samsung_dmadev_trigger,
-	.started	= NULL,
-	.flush		= samsung_dmadev_flush,
-	.stop		= samsung_dmadev_flush,
-};
-
-void *samsung_dmadev_get_ops(void)
-{
-	return &dmadev_ops;
-}
-EXPORT_SYMBOL(samsung_dmadev_get_ops);
diff --git a/arch/arm/plat-samsung/dma.c b/arch/arm/plat-samsung/dma.c
deleted file mode 100644
index 6143aa1..0000000
--- a/arch/arm/plat-samsung/dma.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* linux/arch/arm/plat-samsung/dma.c
- *
- * Copyright (c) 2003-2009 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *	http://armlinux.simtec.co.uk/
- *
- * S3C DMA core
- *
- * 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.
-*/
-
-struct s3c2410_dma_buf;
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-
-#include <mach/dma.h>
-#include <mach/irqs.h>
-
-/* dma channel state information */
-struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
-struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX];
-
-/* s3c_dma_lookup_channel
- *
- * change the dma channel number given into a real dma channel id
-*/
-
-struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
-{
-	if (channel & DMACH_LOW_LEVEL)
-		return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
-	else
-		return s3c_dma_chan_map[channel];
-}
-
-/* do we need to protect the settings of the fields from
- * irq?
-*/
-
-int s3c2410_dma_set_opfn(enum dma_ch channel, s3c2410_dma_opfn_t rtn)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
-
-	chan->op_fn = rtn;
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_set_opfn);
-
-int s3c2410_dma_set_buffdone_fn(enum dma_ch channel, s3c2410_dma_cbfn_t rtn)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
-
-	chan->callback_fn = rtn;
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
-
-int s3c2410_dma_setflags(enum dma_ch channel, unsigned int flags)
-{
-	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
-
-	if (chan == NULL)
-		return -EINVAL;
-
-	chan->flags = flags;
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_setflags);
diff --git a/arch/arm/plat-samsung/include/plat/dma-core.h b/arch/arm/plat-samsung/include/plat/dma-core.h
deleted file mode 100644
index 32ff2a9..0000000
--- a/arch/arm/plat-samsung/include/plat/dma-core.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* arch/arm/plat-s3c/include/plat/dma.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *	http://armlinux.simtec.co.uk/
- *
- * Samsung S3C DMA core 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.
-*/
-
-extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel);
-
-extern struct s3c2410_dma_chan *s3c_dma_chan_map[];
-
-/* the currently allocated channel information */
-extern struct s3c2410_dma_chan s3c2410_chans[];
-
-
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
deleted file mode 100644
index ce6d763..0000000
--- a/arch/arm/plat-samsung/include/plat/dma-ops.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/dma-ops.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Samsung DMA 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 __SAMSUNG_DMA_OPS_H_
-#define __SAMSUNG_DMA_OPS_H_ __FILE__
-
-#include <linux/dmaengine.h>
-#include <mach/dma.h>
-
-struct samsung_dma_req {
-	enum dma_transaction_type cap;
-	struct s3c2410_dma_client *client;
-};
-
-struct samsung_dma_prep {
-	enum dma_transaction_type cap;
-	enum dma_transfer_direction direction;
-	dma_addr_t buf;
-	unsigned long period;
-	unsigned long len;
-	void (*fp)(void *data);
-	void *fp_param;
-};
-
-struct samsung_dma_config {
-	enum dma_transfer_direction direction;
-	enum dma_slave_buswidth width;
-	dma_addr_t fifo;
-};
-
-struct samsung_dma_ops {
-	unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param,
-				struct device *dev, char *ch_name);
-	int (*release)(unsigned ch, void *param);
-	int (*config)(unsigned ch, struct samsung_dma_config *param);
-	int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
-	int (*trigger)(unsigned ch);
-	int (*started)(unsigned ch);
-	int (*flush)(unsigned ch);
-	int (*stop)(unsigned ch);
-};
-
-extern void *samsung_dmadev_get_ops(void);
-extern void *s3c_dma_get_ops(void);
-
-static inline void *__samsung_dma_get_ops(void)
-{
-	if (samsung_dma_is_dmadev())
-		return samsung_dmadev_get_ops();
-	else
-		return s3c_dma_get_ops();
-}
-
-/*
- * samsung_dma_get_ops
- * get the set of samsung dma operations
- */
-#define samsung_dma_get_ops() __samsung_dma_get_ops()
-
-#endif /* __SAMSUNG_DMA_OPS_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
deleted file mode 100644
index abe07fa..0000000
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.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 __DMA_PL330_H_
-#define __DMA_PL330_H_ __FILE__
-
-/*
- * PL330 can assign any channel to communicate with
- * any of the peripherals attched to the DMAC.
- * For the sake of consistency across client drivers,
- * We keep the channel names unchanged and only add
- * missing peripherals are added.
- * Order is not important since DMA PL330 API driver
- * use these just as IDs.
- */
-enum dma_ch {
-	DMACH_UART0_RX = 0,
-	DMACH_UART0_TX,
-	DMACH_UART1_RX,
-	DMACH_UART1_TX,
-	DMACH_UART2_RX,
-	DMACH_UART2_TX,
-	DMACH_UART3_RX,
-	DMACH_UART3_TX,
-	DMACH_UART4_RX,
-	DMACH_UART4_TX,
-	DMACH_UART5_RX,
-	DMACH_UART5_TX,
-	DMACH_USI_RX,
-	DMACH_USI_TX,
-	DMACH_IRDA,
-	DMACH_I2S0_RX,
-	DMACH_I2S0_TX,
-	DMACH_I2S0S_TX,
-	DMACH_I2S1_RX,
-	DMACH_I2S1_TX,
-	DMACH_I2S2_RX,
-	DMACH_I2S2_TX,
-	DMACH_SPI0_RX,
-	DMACH_SPI0_TX,
-	DMACH_SPI1_RX,
-	DMACH_SPI1_TX,
-	DMACH_SPI2_RX,
-	DMACH_SPI2_TX,
-	DMACH_AC97_MICIN,
-	DMACH_AC97_PCMIN,
-	DMACH_AC97_PCMOUT,
-	DMACH_EXTERNAL,
-	DMACH_PWM,
-	DMACH_SPDIF,
-	DMACH_HSI_RX,
-	DMACH_HSI_TX,
-	DMACH_PCM0_TX,
-	DMACH_PCM0_RX,
-	DMACH_PCM1_TX,
-	DMACH_PCM1_RX,
-	DMACH_PCM2_TX,
-	DMACH_PCM2_RX,
-	DMACH_MSM_REQ3,
-	DMACH_MSM_REQ2,
-	DMACH_MSM_REQ1,
-	DMACH_MSM_REQ0,
-	DMACH_SLIMBUS0_RX,
-	DMACH_SLIMBUS0_TX,
-	DMACH_SLIMBUS0AUX_RX,
-	DMACH_SLIMBUS0AUX_TX,
-	DMACH_SLIMBUS1_RX,
-	DMACH_SLIMBUS1_TX,
-	DMACH_SLIMBUS2_RX,
-	DMACH_SLIMBUS2_TX,
-	DMACH_SLIMBUS3_RX,
-	DMACH_SLIMBUS3_TX,
-	DMACH_SLIMBUS4_RX,
-	DMACH_SLIMBUS4_TX,
-	DMACH_SLIMBUS5_RX,
-	DMACH_SLIMBUS5_TX,
-	DMACH_MIPI_HSI0,
-	DMACH_MIPI_HSI1,
-	DMACH_MIPI_HSI2,
-	DMACH_MIPI_HSI3,
-	DMACH_MIPI_HSI4,
-	DMACH_MIPI_HSI5,
-	DMACH_MIPI_HSI6,
-	DMACH_MIPI_HSI7,
-	DMACH_DISP1,
-	DMACH_MTOM_0,
-	DMACH_MTOM_1,
-	DMACH_MTOM_2,
-	DMACH_MTOM_3,
-	DMACH_MTOM_4,
-	DMACH_MTOM_5,
-	DMACH_MTOM_6,
-	DMACH_MTOM_7,
-	/* END Marker, also used to denote a reserved channel */
-	DMACH_MAX,
-};
-
-struct s3c2410_dma_client {
-	char	*name;
-};
-
-static inline bool samsung_dma_has_circular(void)
-{
-	return true;
-}
-
-static inline bool samsung_dma_is_dmadev(void)
-{
-	return true;
-}
-
-#include <plat/dma-ops.h>
-
-#endif	/* __DMA_PL330_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h b/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
deleted file mode 100644
index bd3a6db..0000000
--- a/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/dma-s3c24xx.h
- *
- * Copyright (C) 2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C24XX DMA support - per SoC functions
- *
- * 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 <plat/dma-core.h>
-
-extern struct bus_type dma_subsys;
-extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
-
-#define DMA_CH_VALID		(1<<31)
-#define DMA_CH_NEVER		(1<<30)
-
-/* struct s3c24xx_dma_map
- *
- * this holds the mapping information for the channel selected
- * to be connected to the specified device
-*/
-
-struct s3c24xx_dma_map {
-	const char		*name;
-
-	unsigned long		 channels[S3C_DMA_CHANNELS];
-};
-
-struct s3c24xx_dma_selection {
-	struct s3c24xx_dma_map	*map;
-	unsigned long		 map_size;
-	unsigned long		 dcon_mask;
-
-	void	(*select)(struct s3c2410_dma_chan *chan,
-			  struct s3c24xx_dma_map *map);
-};
-
-extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
-
-/* struct s3c24xx_dma_order_ch
- *
- * channel map for one of the `enum dma_ch` dma channels. the list
- * entry contains a set of low-level channel numbers, orred with
- * DMA_CH_VALID, which are checked in the order in the array.
-*/
-
-struct s3c24xx_dma_order_ch {
-	unsigned int	list[S3C_DMA_CHANNELS];	/* list of channels */
-	unsigned int	flags;				/* flags */
-};
-
-/* struct s3c24xx_dma_order
- *
- * information provided by either the core or the board to give the
- * dma system a hint on how to allocate channels
-*/
-
-struct s3c24xx_dma_order {
-	struct s3c24xx_dma_order_ch	channels[DMACH_MAX];
-};
-
-extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
-
-/* DMA init code, called from the cpu support code */
-
-extern int s3c2410_dma_init(void);
-
-extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
-			    unsigned int stride);
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
deleted file mode 100644
index 7b02143..0000000
--- a/arch/arm/plat-samsung/include/plat/dma.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/dma.h
- *
- * Copyright (C) 2003-2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C DMA 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 __PLAT_DMA_H
-#define __PLAT_DMA_H
-
-#include <linux/dma-mapping.h>
-
-enum s3c2410_dma_buffresult {
-	S3C2410_RES_OK,
-	S3C2410_RES_ERR,
-	S3C2410_RES_ABORT
-};
-
-/* enum s3c2410_chan_op
- *
- * operation codes passed to the DMA code by the user, and also used
- * to inform the current channel owner of any changes to the system state
-*/
-
-enum s3c2410_chan_op {
-	S3C2410_DMAOP_START,
-	S3C2410_DMAOP_STOP,
-	S3C2410_DMAOP_PAUSE,
-	S3C2410_DMAOP_RESUME,
-	S3C2410_DMAOP_FLUSH,
-	S3C2410_DMAOP_TIMEOUT,		/* internal signal to handler */
-	S3C2410_DMAOP_STARTED,		/* indicate channel started */
-};
-
-struct s3c2410_dma_client {
-	char                *name;
-};
-
-struct s3c2410_dma_chan;
-enum dma_ch;
-
-/* s3c2410_dma_cbfn_t
- *
- * buffer callback routine type
-*/
-
-typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
-				   void *buf, int size,
-				   enum s3c2410_dma_buffresult result);
-
-typedef int  (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
-				   enum s3c2410_chan_op );
-
-
-
-/* s3c2410_dma_request
- *
- * request a dma channel exclusivley
-*/
-
-extern int s3c2410_dma_request(enum dma_ch channel,
-			       struct s3c2410_dma_client *, void *dev);
-
-
-/* s3c2410_dma_ctrl
- *
- * change the state of the dma channel
-*/
-
-extern int s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op);
-
-/* s3c2410_dma_setflags
- *
- * set the channel's flags to a given state
-*/
-
-extern int s3c2410_dma_setflags(enum dma_ch channel,
-				unsigned int flags);
-
-/* s3c2410_dma_free
- *
- * free the dma channel (will also abort any outstanding operations)
-*/
-
-extern int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *);
-
-/* s3c2410_dma_enqueue
- *
- * place the given buffer onto the queue of operations for the channel.
- * The buffer must be allocated from dma coherent memory, or the Dcache/WB
- * drained before the buffer is given to the DMA system.
-*/
-
-extern int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
-			       dma_addr_t data, int size);
-
-/* s3c2410_dma_config
- *
- * configure the dma channel
-*/
-
-extern int s3c2410_dma_config(enum dma_ch channel, int xferunit);
-
-/* s3c2410_dma_devconfig
- *
- * configure the device we're talking to
-*/
-
-extern int s3c2410_dma_devconfig(enum dma_ch channel,
-		enum dma_data_direction source, unsigned long devaddr);
-
-/* s3c2410_dma_getposition
- *
- * get the position that the dma transfer is currently at
-*/
-
-extern int s3c2410_dma_getposition(enum dma_ch channel,
-				   dma_addr_t *src, dma_addr_t *dest);
-
-extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn);
-extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn);
-
-#include <plat/dma-ops.h>
-
-#endif
diff --git a/arch/arm/plat-samsung/include/plat/regs-dma.h b/arch/arm/plat-samsung/include/plat/regs-dma.h
deleted file mode 100644
index a7d622e..0000000
--- a/arch/arm/plat-samsung/include/plat/regs-dma.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/* arch/arm/plat-samsung/include/plat/regs-dma.h
- *
- * Copyright (C) 2003-2006 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C24XX DMA 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 __ASM_PLAT_REGS_DMA_H
-#define __ASM_PLAT_REGS_DMA_H __FILE__
-
-#define S3C2410_DMA_DISRC		(0x00)
-#define S3C2410_DMA_DISRCC		(0x04)
-#define S3C2410_DMA_DIDST		(0x08)
-#define S3C2410_DMA_DIDSTC		(0x0C)
-#define S3C2410_DMA_DCON		(0x10)
-#define S3C2410_DMA_DSTAT		(0x14)
-#define S3C2410_DMA_DCSRC		(0x18)
-#define S3C2410_DMA_DCDST		(0x1C)
-#define S3C2410_DMA_DMASKTRIG		(0x20)
-#define S3C2412_DMA_DMAREQSEL		(0x24)
-#define S3C2443_DMA_DMAREQSEL		(0x24)
-
-#define S3C2410_DISRCC_INC		(1 << 0)
-#define S3C2410_DISRCC_APB		(1 << 1)
-
-#define S3C2410_DMASKTRIG_STOP		(1 << 2)
-#define S3C2410_DMASKTRIG_ON		(1 << 1)
-#define S3C2410_DMASKTRIG_SWTRIG	(1 << 0)
-
-#define S3C2410_DCON_DEMAND		(0 << 31)
-#define S3C2410_DCON_HANDSHAKE		(1 << 31)
-#define S3C2410_DCON_SYNC_PCLK		(0 << 30)
-#define S3C2410_DCON_SYNC_HCLK		(1 << 30)
-
-#define S3C2410_DCON_INTREQ		(1 << 29)
-
-#define S3C2410_DCON_CH0_XDREQ0		(0 << 24)
-#define S3C2410_DCON_CH0_UART0		(1 << 24)
-#define S3C2410_DCON_CH0_SDI		(2 << 24)
-#define S3C2410_DCON_CH0_TIMER		(3 << 24)
-#define S3C2410_DCON_CH0_USBEP1		(4 << 24)
-
-#define S3C2410_DCON_CH1_XDREQ1		(0 << 24)
-#define S3C2410_DCON_CH1_UART1		(1 << 24)
-#define S3C2410_DCON_CH1_I2SSDI		(2 << 24)
-#define S3C2410_DCON_CH1_SPI		(3 << 24)
-#define S3C2410_DCON_CH1_USBEP2		(4 << 24)
-
-#define S3C2410_DCON_CH2_I2SSDO		(0 << 24)
-#define S3C2410_DCON_CH2_I2SSDI		(1 << 24)
-#define S3C2410_DCON_CH2_SDI		(2 << 24)
-#define S3C2410_DCON_CH2_TIMER		(3 << 24)
-#define S3C2410_DCON_CH2_USBEP3		(4 << 24)
-
-#define S3C2410_DCON_CH3_UART2		(0 << 24)
-#define S3C2410_DCON_CH3_SDI		(1 << 24)
-#define S3C2410_DCON_CH3_SPI		(2 << 24)
-#define S3C2410_DCON_CH3_TIMER		(3 << 24)
-#define S3C2410_DCON_CH3_USBEP4		(4 << 24)
-
-#define S3C2410_DCON_SRCSHIFT		(24)
-#define S3C2410_DCON_SRCMASK		(7 << 24)
-
-#define S3C2410_DCON_BYTE		(0 << 20)
-#define S3C2410_DCON_HALFWORD		(1 << 20)
-#define S3C2410_DCON_WORD		(2 << 20)
-
-#define S3C2410_DCON_AUTORELOAD		(0 << 22)
-#define S3C2410_DCON_NORELOAD		(1 << 22)
-#define S3C2410_DCON_HWTRIG		(1 << 23)
-
-#ifdef CONFIG_CPU_S3C2440
-
-#define S3C2440_DIDSTC_CHKINT		(1 << 2)
-
-#define S3C2440_DCON_CH0_I2SSDO		(5 << 24)
-#define S3C2440_DCON_CH0_PCMIN		(6 << 24)
-
-#define S3C2440_DCON_CH1_PCMOUT		(5 << 24)
-#define S3C2440_DCON_CH1_SDI		(6 << 24)
-
-#define S3C2440_DCON_CH2_PCMIN		(5 << 24)
-#define S3C2440_DCON_CH2_MICIN		(6 << 24)
-
-#define S3C2440_DCON_CH3_MICIN		(5 << 24)
-#define S3C2440_DCON_CH3_PCMOUT		(6 << 24)
-#endif /* CONFIG_CPU_S3C2440 */
-
-#ifdef CONFIG_CPU_S3C2412
-
-#define S3C2412_DMAREQSEL_SRC(x)	((x) << 1)
-
-#define S3C2412_DMAREQSEL_HW		(1)
-
-#define S3C2412_DMAREQSEL_SPI0TX	S3C2412_DMAREQSEL_SRC(0)
-#define S3C2412_DMAREQSEL_SPI0RX	S3C2412_DMAREQSEL_SRC(1)
-#define S3C2412_DMAREQSEL_SPI1TX	S3C2412_DMAREQSEL_SRC(2)
-#define S3C2412_DMAREQSEL_SPI1RX	S3C2412_DMAREQSEL_SRC(3)
-#define S3C2412_DMAREQSEL_I2STX		S3C2412_DMAREQSEL_SRC(4)
-#define S3C2412_DMAREQSEL_I2SRX		S3C2412_DMAREQSEL_SRC(5)
-#define S3C2412_DMAREQSEL_TIMER		S3C2412_DMAREQSEL_SRC(9)
-#define S3C2412_DMAREQSEL_SDI		S3C2412_DMAREQSEL_SRC(10)
-#define S3C2412_DMAREQSEL_USBEP1	S3C2412_DMAREQSEL_SRC(13)
-#define S3C2412_DMAREQSEL_USBEP2	S3C2412_DMAREQSEL_SRC(14)
-#define S3C2412_DMAREQSEL_USBEP3	S3C2412_DMAREQSEL_SRC(15)
-#define S3C2412_DMAREQSEL_USBEP4	S3C2412_DMAREQSEL_SRC(16)
-#define S3C2412_DMAREQSEL_XDREQ0	S3C2412_DMAREQSEL_SRC(17)
-#define S3C2412_DMAREQSEL_XDREQ1	S3C2412_DMAREQSEL_SRC(18)
-#define S3C2412_DMAREQSEL_UART0_0	S3C2412_DMAREQSEL_SRC(19)
-#define S3C2412_DMAREQSEL_UART0_1	S3C2412_DMAREQSEL_SRC(20)
-#define S3C2412_DMAREQSEL_UART1_0	S3C2412_DMAREQSEL_SRC(21)
-#define S3C2412_DMAREQSEL_UART1_1	S3C2412_DMAREQSEL_SRC(22)
-#define S3C2412_DMAREQSEL_UART2_0	S3C2412_DMAREQSEL_SRC(23)
-#define S3C2412_DMAREQSEL_UART2_1	S3C2412_DMAREQSEL_SRC(24)
-#endif /* CONFIG_CPU_S3C2412 */
-
-#if defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2443)
-
-#define S3C2443_DMAREQSEL_SRC(x)	((x) << 1)
-
-#define S3C2443_DMAREQSEL_HW		(1)
-
-#define S3C2443_DMAREQSEL_SPI0TX	S3C2443_DMAREQSEL_SRC(0)
-#define S3C2443_DMAREQSEL_SPI0RX	S3C2443_DMAREQSEL_SRC(1)
-#define S3C2443_DMAREQSEL_SPI1TX	S3C2443_DMAREQSEL_SRC(2)
-#define S3C2443_DMAREQSEL_SPI1RX	S3C2443_DMAREQSEL_SRC(3)
-#define S3C2443_DMAREQSEL_I2STX		S3C2443_DMAREQSEL_SRC(4)
-#define S3C2443_DMAREQSEL_I2SRX		S3C2443_DMAREQSEL_SRC(5)
-#define S3C2443_DMAREQSEL_TIMER		S3C2443_DMAREQSEL_SRC(9)
-#define S3C2443_DMAREQSEL_SDI		S3C2443_DMAREQSEL_SRC(10)
-#define S3C2443_DMAREQSEL_XDREQ0	S3C2443_DMAREQSEL_SRC(17)
-#define S3C2443_DMAREQSEL_XDREQ1	S3C2443_DMAREQSEL_SRC(18)
-#define S3C2443_DMAREQSEL_UART0_0	S3C2443_DMAREQSEL_SRC(19)
-#define S3C2443_DMAREQSEL_UART0_1	S3C2443_DMAREQSEL_SRC(20)
-#define S3C2443_DMAREQSEL_UART1_0	S3C2443_DMAREQSEL_SRC(21)
-#define S3C2443_DMAREQSEL_UART1_1	S3C2443_DMAREQSEL_SRC(22)
-#define S3C2443_DMAREQSEL_UART2_0	S3C2443_DMAREQSEL_SRC(23)
-#define S3C2443_DMAREQSEL_UART2_1	S3C2443_DMAREQSEL_SRC(24)
-#define S3C2443_DMAREQSEL_UART3_0	S3C2443_DMAREQSEL_SRC(25)
-#define S3C2443_DMAREQSEL_UART3_1	S3C2443_DMAREQSEL_SRC(26)
-#define S3C2443_DMAREQSEL_PCMOUT	S3C2443_DMAREQSEL_SRC(27)
-#define S3C2443_DMAREQSEL_PCMIN		S3C2443_DMAREQSEL_SRC(28)
-#define S3C2443_DMAREQSEL_MICIN		S3C2443_DMAREQSEL_SRC(29)
-#endif /* CONFIG_CPU_S3C2443 */
-
-#endif /* __ASM_PLAT_REGS_DMA_H */
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
deleted file mode 100644
index 98b10ba..0000000
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com
- *
- * Samsung S3C-DMA Operations
- *
- * 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/errno.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/export.h>
-
-#include <mach/dma.h>
-
-struct cb_data {
-	void (*fp) (void *);
-	void *fp_param;
-	unsigned ch;
-	struct list_head node;
-};
-
-static LIST_HEAD(dma_list);
-
-static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
-		       int size, enum s3c2410_dma_buffresult res)
-{
-	struct cb_data *data = param;
-
-	data->fp(data->fp_param);
-}
-
-static unsigned s3c_dma_request(enum dma_ch dma_ch,
-				struct samsung_dma_req *param,
-				struct device *dev, char *ch_name)
-{
-	struct cb_data *data;
-
-	if (s3c2410_dma_request(dma_ch, param->client, NULL) < 0) {
-		s3c2410_dma_free(dma_ch, param->client);
-		return 0;
-	}
-
-	if (param->cap == DMA_CYCLIC)
-		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
-
-	data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
-	data->ch = dma_ch;
-	list_add_tail(&data->node, &dma_list);
-
-	return (unsigned)dma_ch;
-}
-
-static int s3c_dma_release(unsigned ch, void *param)
-{
-	struct cb_data *data;
-
-	list_for_each_entry(data, &dma_list, node)
-		if (data->ch == ch)
-			break;
-	list_del(&data->node);
-
-	s3c2410_dma_free(ch, param);
-	kfree(data);
-
-	return 0;
-}
-
-static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
-{
-	s3c2410_dma_devconfig(ch, param->direction, param->fifo);
-	s3c2410_dma_config(ch, param->width);
-
-	return 0;
-}
-
-static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
-{
-	struct cb_data *data;
-	dma_addr_t pos = param->buf;
-	dma_addr_t end = param->buf + param->len;
-
-	list_for_each_entry(data, &dma_list, node)
-		if (data->ch == ch)
-			break;
-
-	if (!data->fp) {
-		s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
-		data->fp = param->fp;
-		data->fp_param = param->fp_param;
-	}
-
-	if (param->cap != DMA_CYCLIC) {
-		s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
-		return 0;
-	}
-
-	while (pos < end) {
-		s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
-		pos += param->period;
-	}
-
-	return 0;
-}
-
-static inline int s3c_dma_trigger(unsigned ch)
-{
-	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
-}
-
-static inline int s3c_dma_started(unsigned ch)
-{
-	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
-}
-
-static inline int s3c_dma_flush(unsigned ch)
-{
-	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
-}
-
-static inline int s3c_dma_stop(unsigned ch)
-{
-	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
-}
-
-static struct samsung_dma_ops s3c_dma_ops = {
-	.request	= s3c_dma_request,
-	.release	= s3c_dma_release,
-	.config		= s3c_dma_config,
-	.prepare	= s3c_dma_prepare,
-	.trigger	= s3c_dma_trigger,
-	.started	= s3c_dma_started,
-	.flush		= s3c_dma_flush,
-	.stop		= s3c_dma_stop,
-};
-
-void *s3c_dma_get_ops(void)
-{
-	return &s3c_dma_ops;
-}
-EXPORT_SYMBOL(s3c_dma_get_ops);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 676454a..1b8e973 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -149,11 +149,65 @@
 
 menu "Platform selection"
 
+config ARCH_EXYNOS
+	bool
+	help
+	  This enables support for Samsung Exynos SoC family
+
+config ARCH_EXYNOS7
+	bool "ARMv8 based Samsung Exynos7"
+	select ARCH_EXYNOS
+	select COMMON_CLK_SAMSUNG
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
+	select HAVE_S3C_RTC if RTC_CLASS
+	select PINCTRL
+	select PINCTRL_EXYNOS
+
+	help
+	  This enables support for Samsung Exynos7 SoC family
+
+config ARCH_FSL_LS2085A
+	bool "Freescale LS2085A SOC"
+	help
+	  This enables support for Freescale LS2085A SOC.
+
+config ARCH_MEDIATEK
+	bool "Mediatek MT65xx & MT81xx ARMv8 SoC"
+	select ARM_GIC
+	help
+	  Support for Mediatek MT65xx & MT81xx ARMv8 SoCs
+
 config ARCH_SEATTLE
 	bool "AMD Seattle SoC Family"
 	help
 	  This enables support for AMD Seattle SOC Family
 
+config ARCH_TEGRA
+	bool "NVIDIA Tegra SoC Family"
+	select ARCH_HAS_RESET_CONTROLLER
+	select ARCH_REQUIRE_GPIOLIB
+	select CLKDEV_LOOKUP
+	select CLKSRC_MMIO
+	select CLKSRC_OF
+	select GENERIC_CLOCKEVENTS
+	select HAVE_CLK
+	select PINCTRL
+	select RESET_CONTROLLER
+	help
+	  This enables support for the NVIDIA Tegra SoC family.
+
+config ARCH_TEGRA_132_SOC
+	bool "NVIDIA Tegra132 SoC"
+	depends on ARCH_TEGRA
+	select PINCTRL_TEGRA124
+	select USB_ULPI if USB_PHY
+	select USB_ULPI_VIEWPORT if USB_PHY
+	help
+	  Enable support for NVIDIA Tegra132 SoC, based on the Denver
+	  ARMv8 CPU.  The Tegra132 SoC is similar to the Tegra124 SoC,
+	  but contains an NVIDIA Denver CPU complex in place of
+	  Tegra124's "4+1" Cortex-A15 CPU complex.
+
 config ARCH_THUNDER
 	bool "Cavium Inc. Thunder SoC Family"
 	help
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index c62b0f4..e0350ca 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -2,5 +2,8 @@
 dts-dirs += apm
 dts-dirs += arm
 dts-dirs += cavium
+dts-dirs += exynos
+dts-dirs += freescale
+dts-dirs += mediatek
 
 subdir-y	:= $(dts-dirs)
diff --git a/arch/arm64/boot/dts/exynos/Makefile b/arch/arm64/boot/dts/exynos/Makefile
new file mode 100644
index 0000000..20310e5
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_EXYNOS7) += exynos7-espresso.dtb
+
+always		:= $(dtb-y)
+subdir-y	:= $(dts-dirs)
+clean-files	:= *.dtb
diff --git a/arch/arm64/boot/dts/exynos/exynos7-espresso.dts b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
new file mode 100644
index 0000000..5424cc4
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
@@ -0,0 +1,84 @@
+/*
+ * SAMSUNG Exynos7 Espresso board device tree source
+ *
+ * Copyright (c) 2014 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.
+*/
+
+/dts-v1/;
+#include "exynos7.dtsi"
+
+/ {
+	model = "Samsung Exynos7 Espresso board based on EXYNOS7";
+	compatible = "samsung,exynos7-espresso", "samsung,exynos7";
+
+	aliases {
+		serial0 = &serial_2;
+		mshc0 = &mmc_0;
+		mshc2 = &mmc_2;
+	};
+
+	chosen {
+		linux,stdout-path = &serial_2;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0x0 0xC0000000>;
+	};
+};
+
+&fin_pll {
+	clock-frequency = <24000000>;
+};
+
+&serial_2 {
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&adc {
+	status = "okay";
+};
+
+&mmc_0 {
+	status = "okay";
+	num-slots = <1>;
+	broken-cd;
+	cap-mmc-highspeed;
+	non-removable;
+	card-detect-delay = <200>;
+	clock-frequency = <800000000>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <0 4>;
+	samsung,dw-mshc-ddr-timing = <0 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_qrdy &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+	bus-width = <8>;
+};
+
+&mmc_2 {
+	status = "okay";
+	num-slots = <1>;
+	cap-sd-highspeed;
+	card-detect-delay = <200>;
+	clock-frequency = <400000000>;
+	samsung,dw-mshc-ciu-div = <3>;
+	samsung,dw-mshc-sdr-timing = <2 3>;
+	samsung,dw-mshc-ddr-timing = <1 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
+	bus-width = <4>;
+	disable-wp;
+};
diff --git a/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
new file mode 100644
index 0000000..2eef4a2
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
@@ -0,0 +1,588 @@
+/*
+ * Samsung's Exynos7 SoC pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung's Exynos7 SoC pin-mux and pin-config options are listed as
+ * device tree nodes in this file.
+ *
+ * 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.
+*/
+
+&pinctrl_alive {
+	gpa0: gpa0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+		interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+			     <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>;
+	};
+
+	gpa1: gpa1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+		interrupts = <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+			     <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+	};
+
+	gpa2: gpa2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpa3: gpa3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
+
+&pinctrl_bus0 {
+	gpb0: gpb0 {
+		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>;
+	};
+
+	gpc2: gpc2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpc3: gpc3 {
+		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>;
+	};
+
+	gpd2: gpd2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd4: gpd4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd5: gpd5 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd6: gpd6 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd7: gpd7 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd8: gpd8 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg0: gpg0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg3: gpg3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	hs_i2c10_bus: hs-i2c10-bus {
+		samsung,pins = "gpb0-1", "gpb0-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c11_bus: hs-i2c11-bus {
+		samsung,pins = "gpb0-3", "gpb0-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c2_bus: hs-i2c2-bus {
+		samsung,pins = "gpd0-3", "gpd0-2";
+		samsung,pin-function = <3>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart0_data: uart0-data {
+		samsung,pins = "gpd0-0", "gpd0-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart0_fctl: uart0-fctl {
+		samsung,pins = "gpd0-2", "gpd0-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart2_data: uart2-data {
+		samsung,pins = "gpd1-4", "gpd1-5";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c3_bus: hs-i2c3-bus {
+		samsung,pins = "gpd1-3", "gpd1-2";
+		samsung,pin-function = <3>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart1_data: uart1-data {
+		samsung,pins = "gpd1-0", "gpd1-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart1_fctl: uart1-fctl {
+		samsung,pins = "gpd1-2", "gpd1-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c0_bus: hs-i2c0-bus {
+		samsung,pins = "gpd2-1", "gpd2-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c1_bus: hs-i2c1-bus {
+		samsung,pins = "gpd2-3", "gpd2-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c9_bus: hs-i2c9-bus {
+		samsung,pins = "gpd2-7", "gpd2-6";
+		samsung,pin-function = <3>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	pwm0_out: pwm0-out {
+		samsung,pins = "gpd2-4";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pwm1_out: pwm1-out {
+		samsung,pins = "gpd2-5";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pwm2_out: pwm2-out {
+		samsung,pins = "gpd2-6";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	pwm3_out: pwm3-out {
+		samsung,pins = "gpd2-7";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c8_bus: hs-i2c8-bus {
+		samsung,pins = "gpd5-3", "gpd5-2";
+		samsung,pin-function = <3>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	uart3_data: uart3-data {
+		samsung,pins = "gpd5-0", "gpd5-1";
+		samsung,pin-function = <3>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
+	spi2_bus: spi2-bus {
+		samsung,pins = "gpd5-0", "gpd5-1", "gpd5-2", "gpd5-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	spi1_bus: spi1-bus {
+		samsung,pins = "gpd6-2", "gpd6-3", "gpd6-4", "gpd6-5";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	spi0_bus: spi0-bus {
+		samsung,pins = "gpd8-0", "gpd8-1", "gpd6-0", "gpd6-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c4_bus: hs-i2c4-bus {
+		samsung,pins = "gpg3-1", "gpg3-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+
+	hs_i2c5_bus: hs-i2c5-bus {
+		samsung,pins = "gpg3-3", "gpg3-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_nfc {
+	gpj0: gpj0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	hs_i2c6_bus: hs-i2c6-bus {
+		samsung,pins = "gpj0-1", "gpj0-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_touch {
+	gpj1: gpj1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	hs_i2c7_bus: hs-i2c7-bus {
+		samsung,pins = "gpj1-1", "gpj1-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_ff {
+	gpg4: gpg4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	spi3_bus: spi3-bus {
+		samsung,pins = "gpg4-0", "gpg4-1", "gpg4-2", "gpg4-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_ese {
+	gpv7: gpv7 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	spi4_bus: spi4-bus {
+		samsung,pins = "gpv7-0", "gpv7-1", "gpv7-2", "gpv7-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <0>;
+	};
+};
+
+&pinctrl_fsys0 {
+	gpr4: gpr4 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	sd2_clk: sd2-clk {
+		samsung,pins = "gpr4-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_cmd: sd2-cmd {
+		samsung,pins = "gpr4-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_cd: sd2-cd {
+		samsung,pins = "gpr4-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_bus1: sd2-bus-width1 {
+		samsung,pins = "gpr4-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_bus4: sd2-bus-width4 {
+		samsung,pins = "gpr4-4", "gpr4-5", "gpr4-6";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+};
+
+&pinctrl_fsys1 {
+	gpr0: gpr0 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpr1: gpr1 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpr2: gpr2 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpr3: gpr3 {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	sd0_clk: sd0-clk {
+		samsung,pins = "gpr0-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_cmd: sd0-cmd {
+		samsung,pins = "gpr0-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_ds: sd0-ds {
+		samsung,pins = "gpr0-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_qrdy: sd0-qrdy {
+		samsung,pins = "gpr0-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_bus1: sd0-bus-width1 {
+		samsung,pins = "gpr1-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_bus4: sd0-bus-width4 {
+		samsung,pins = "gpr1-1", "gpr1-2", "gpr1-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd0_bus8: sd0-bus-width8 {
+		samsung,pins = "gpr1-4", "gpr1-5", "gpr1-6", "gpr1-7";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd1_clk: sd1-clk {
+		samsung,pins = "gpr2-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <2>;
+	};
+
+	sd1_cmd: sd1-cmd {
+		samsung,pins = "gpr2-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <2>;
+	};
+
+	sd1_ds: sd1-ds {
+		samsung,pins = "gpr2-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <6>;
+	};
+
+	sd1_qrdy: sd1-qrdy {
+		samsung,pins = "gpr2-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <6>;
+	};
+
+	sd1_int: sd1-int {
+		samsung,pins = "gpr2-4";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <1>;
+		samsung,pin-drv = <6>;
+	};
+
+	sd1_bus1: sd1-bus-width1 {
+		samsung,pins = "gpr3-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <2>;
+	};
+
+	sd1_bus4: sd1-bus-width4 {
+		samsung,pins = "gpr3-1", "gpr3-2", "gpr3-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <2>;
+	};
+
+	sd1_bus8: sd1-bus-width8 {
+		samsung,pins = "gpr3-4", "gpr3-5", "gpr3-6", "gpr3-7";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi
new file mode 100644
index 0000000..d7a37c3
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi
@@ -0,0 +1,530 @@
+/*
+ * SAMSUNG EXYNOS7 SoC device tree source
+ *
+ * Copyright (c) 2014 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.
+ */
+
+#include <dt-bindings/clock/exynos7-clk.h>
+
+/ {
+	compatible = "samsung,exynos7";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		pinctrl0 = &pinctrl_alive;
+		pinctrl1 = &pinctrl_bus0;
+		pinctrl2 = &pinctrl_nfc;
+		pinctrl3 = &pinctrl_touch;
+		pinctrl4 = &pinctrl_ff;
+		pinctrl5 = &pinctrl_ese;
+		pinctrl6 = &pinctrl_fsys0;
+		pinctrl7 = &pinctrl_fsys1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x0>;
+			enable-method = "psci";
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x1>;
+			enable-method = "psci";
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x2>;
+			enable-method = "psci";
+		};
+
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x3>;
+			enable-method = "psci";
+		};
+	};
+
+	psci {
+		compatible = "arm,psci-0.2";
+		method = "smc";
+	};
+
+	soc: soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x18000000>;
+
+		chipid@10000000 {
+			compatible = "samsung,exynos4210-chipid";
+			reg = <0x10000000 0x100>;
+		};
+
+		fin_pll: xxti {
+			compatible = "fixed-clock";
+			clock-output-names = "fin_pll";
+			#clock-cells = <0>;
+		};
+
+		gic: interrupt-controller@11001000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg =	<0x11001000 0x1000>,
+				<0x11002000 0x1000>,
+				<0x11004000 0x2000>,
+				<0x11006000 0x2000>;
+		};
+
+		clock_topc: clock-controller@10570000 {
+			compatible = "samsung,exynos7-clock-topc";
+			reg = <0x10570000 0x10000>;
+			#clock-cells = <1>;
+		};
+
+		clock_top0: clock-controller@105d0000 {
+			compatible = "samsung,exynos7-clock-top0";
+			reg = <0x105d0000 0xb000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_topc DOUT_SCLK_BUS0_PLL>,
+				 <&clock_topc DOUT_SCLK_BUS1_PLL>,
+				 <&clock_topc DOUT_SCLK_CC_PLL>,
+				 <&clock_topc DOUT_SCLK_MFC_PLL>;
+			clock-names = "fin_pll", "dout_sclk_bus0_pll",
+				      "dout_sclk_bus1_pll", "dout_sclk_cc_pll",
+				      "dout_sclk_mfc_pll";
+		};
+
+		clock_top1: clock-controller@105e0000 {
+			compatible = "samsung,exynos7-clock-top1";
+			reg = <0x105e0000 0xb000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_topc DOUT_SCLK_BUS0_PLL>,
+				 <&clock_topc DOUT_SCLK_BUS1_PLL>,
+				 <&clock_topc DOUT_SCLK_CC_PLL>,
+				 <&clock_topc DOUT_SCLK_MFC_PLL>;
+			clock-names = "fin_pll", "dout_sclk_bus0_pll",
+				      "dout_sclk_bus1_pll", "dout_sclk_cc_pll",
+				      "dout_sclk_mfc_pll";
+		};
+
+		clock_ccore: clock-controller@105b0000 {
+			compatible = "samsung,exynos7-clock-ccore";
+			reg = <0x105b0000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_topc DOUT_ACLK_CCORE_133>;
+			clock-names = "fin_pll", "dout_aclk_ccore_133";
+		};
+
+		clock_peric0: clock-controller@13610000 {
+			compatible = "samsung,exynos7-clock-peric0";
+			reg = <0x13610000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_top0 DOUT_ACLK_PERIC0>,
+				 <&clock_top0 CLK_SCLK_UART0>;
+			clock-names = "fin_pll", "dout_aclk_peric0_66",
+				      "sclk_uart0";
+		};
+
+		clock_peric1: clock-controller@14c80000 {
+			compatible = "samsung,exynos7-clock-peric1";
+			reg = <0x14c80000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_top0 DOUT_ACLK_PERIC1>,
+				 <&clock_top0 CLK_SCLK_UART1>,
+				 <&clock_top0 CLK_SCLK_UART2>,
+				 <&clock_top0 CLK_SCLK_UART3>;
+			clock-names = "fin_pll", "dout_aclk_peric1_66",
+				      "sclk_uart1", "sclk_uart2", "sclk_uart3";
+		};
+
+		clock_peris: clock-controller@10040000 {
+			compatible = "samsung,exynos7-clock-peris";
+			reg = <0x10040000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_topc DOUT_ACLK_PERIS>;
+			clock-names = "fin_pll", "dout_aclk_peris_66";
+		};
+
+		clock_fsys0: clock-controller@10e90000 {
+			compatible = "samsung,exynos7-clock-fsys0";
+			reg = <0x10e90000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_top1 DOUT_ACLK_FSYS0_200>,
+				 <&clock_top1 DOUT_SCLK_MMC2>;
+			clock-names = "fin_pll", "dout_aclk_fsys0_200",
+				      "dout_sclk_mmc2";
+		};
+
+		clock_fsys1: clock-controller@156e0000 {
+			compatible = "samsung,exynos7-clock-fsys1";
+			reg = <0x156e0000 0xd00>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>, <&clock_top1 DOUT_ACLK_FSYS1_200>,
+				 <&clock_top1 DOUT_SCLK_MMC0>,
+				 <&clock_top1 DOUT_SCLK_MMC1>;
+			clock-names = "fin_pll", "dout_aclk_fsys1_200",
+				      "dout_sclk_mmc0", "dout_sclk_mmc1";
+		};
+
+		serial_0: serial@13630000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13630000 0x100>;
+			interrupts = <0 440 0>;
+			clocks = <&clock_peric0 PCLK_UART0>,
+				 <&clock_peric0 SCLK_UART0>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		serial_1: serial@14c20000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x14c20000 0x100>;
+			interrupts = <0 456 0>;
+			clocks = <&clock_peric1 PCLK_UART1>,
+				 <&clock_peric1 SCLK_UART1>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		serial_2: serial@14c30000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x14c30000 0x100>;
+			interrupts = <0 457 0>;
+			clocks = <&clock_peric1 PCLK_UART2>,
+				 <&clock_peric1 SCLK_UART2>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		serial_3: serial@14c40000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x14c40000 0x100>;
+			interrupts = <0 458 0>;
+			clocks = <&clock_peric1 PCLK_UART3>,
+				 <&clock_peric1 SCLK_UART3>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		pinctrl_alive: pinctrl@10580000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x10580000 0x1000>;
+
+			wakeup-interrupt-controller {
+				compatible = "samsung,exynos7-wakeup-eint";
+				interrupt-parent = <&gic>;
+				interrupts = <0 16 0>;
+			};
+		};
+
+		pinctrl_bus0: pinctrl@13470000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x13470000 0x1000>;
+			interrupts = <0 383 0>;
+		};
+
+		pinctrl_nfc: pinctrl@14cd0000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x14cd0000 0x1000>;
+			interrupts = <0 473 0>;
+		};
+
+		pinctrl_touch: pinctrl@14ce0000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x14ce0000 0x1000>;
+			interrupts = <0 474 0>;
+		};
+
+		pinctrl_ff: pinctrl@14c90000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x14c90000 0x1000>;
+			interrupts = <0 475 0>;
+		};
+
+		pinctrl_ese: pinctrl@14ca0000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x14ca0000 0x1000>;
+			interrupts = <0 476 0>;
+		};
+
+		pinctrl_fsys0: pinctrl@10e60000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x10e60000 0x1000>;
+			interrupts = <0 221 0>;
+		};
+
+		pinctrl_fsys1: pinctrl@15690000 {
+			compatible = "samsung,exynos7-pinctrl";
+			reg = <0x15690000 0x1000>;
+			interrupts = <0 203 0>;
+		};
+
+		hsi2c_0: hsi2c@13640000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13640000 0x1000>;
+			interrupts = <0 441 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c0_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C0>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_1: hsi2c@13650000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13650000 0x1000>;
+			interrupts = <0 442 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c1_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C1>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_2: hsi2c@14e60000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x14e60000 0x1000>;
+			interrupts = <0 459 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c2_bus>;
+			clocks = <&clock_peric1 PCLK_HSI2C2>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_3: hsi2c@14e70000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x14e70000 0x1000>;
+			interrupts = <0 460 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c3_bus>;
+			clocks = <&clock_peric1 PCLK_HSI2C3>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_4: hsi2c@13660000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13660000 0x1000>;
+			interrupts = <0 443 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c4_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C4>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_5: hsi2c@13670000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13670000 0x1000>;
+			interrupts = <0 444 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c5_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C5>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_6: hsi2c@14e00000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x14e00000 0x1000>;
+			interrupts = <0 461 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c6_bus>;
+			clocks = <&clock_peric1 PCLK_HSI2C6>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_7: hsi2c@13e10000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13e10000 0x1000>;
+			interrupts = <0 462 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c7_bus>;
+			clocks = <&clock_peric1 PCLK_HSI2C7>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_8: hsi2c@14e20000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x14e20000 0x1000>;
+			interrupts = <0 463 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c8_bus>;
+			clocks = <&clock_peric1 PCLK_HSI2C8>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_9: hsi2c@13680000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13680000 0x1000>;
+			interrupts = <0 445 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c9_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C9>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_10: hsi2c@13690000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x13690000 0x1000>;
+			interrupts = <0 446 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c10_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C10>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_11: hsi2c@136a0000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x136a0000 0x1000>;
+			interrupts = <0 447 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c11_bus>;
+			clocks = <&clock_peric0 PCLK_HSI2C11>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		timer {
+			compatible = "arm,armv8-timer";
+			interrupts = <1 13 0xff01>,
+				     <1 14 0xff01>,
+				     <1 11 0xff01>,
+				     <1 10 0xff01>;
+		};
+
+		pmu_system_controller: system-controller@105c0000 {
+			compatible = "samsung,exynos7-pmu", "syscon";
+			reg = <0x105c0000 0x5000>;
+		};
+
+		rtc: rtc@10590000 {
+			compatible = "samsung,s3c6410-rtc";
+			reg = <0x10590000 0x100>;
+			interrupts = <0 355 0>, <0 356 0>;
+			clocks = <&clock_ccore PCLK_RTC>;
+			clock-names = "rtc";
+			status = "disabled";
+		};
+
+		watchdog: watchdog@101d0000 {
+			compatible = "samsung,exynos7-wdt";
+			reg = <0x101d0000 0x100>;
+			interrupts = <0 110 0>;
+			clocks = <&clock_peris PCLK_WDT>;
+			clock-names = "watchdog";
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			status = "disabled";
+		};
+
+		mmc_0: mmc@15740000 {
+			compatible = "samsung,exynos7-dw-mshc-smu";
+			interrupts = <0 201 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x15740000 0x2000>;
+			clocks = <&clock_fsys1 ACLK_MMC0>,
+				 <&clock_top1 CLK_SCLK_MMC0>;
+			clock-names = "biu", "ciu";
+			fifo-depth = <0x40>;
+			status = "disabled";
+		};
+
+		mmc_1: mmc@15750000 {
+			compatible = "samsung,exynos7-dw-mshc";
+			interrupts = <0 202 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x15750000 0x2000>;
+			clocks = <&clock_fsys1 ACLK_MMC1>,
+				 <&clock_top1 CLK_SCLK_MMC1>;
+			clock-names = "biu", "ciu";
+			fifo-depth = <0x40>;
+			status = "disabled";
+		};
+
+		mmc_2: mmc@15560000 {
+			compatible = "samsung,exynos7-dw-mshc-smu";
+			interrupts = <0 216 0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x15560000 0x2000>;
+			clocks = <&clock_fsys0 ACLK_MMC2>,
+				 <&clock_top1 CLK_SCLK_MMC2>;
+			clock-names = "biu", "ciu";
+			fifo-depth = <0x40>;
+			status = "disabled";
+		};
+
+		adc: adc@13620000 {
+			compatible = "samsung,exynos7-adc";
+			reg = <0x13620000 0x100>;
+			interrupts = <0 448 0>;
+			clocks = <&clock_peric0 PCLK_ADCIF>;
+			clock-names = "adc";
+			#io-channel-cells = <1>;
+			io-channel-ranges;
+			status = "disabled";
+		};
+
+		pwm: pwm@136c0000 {
+			compatible = "samsung,exynos4210-pwm";
+			reg = <0x136c0000 0x100>;
+			samsung,pwm-outputs = <0>, <1>, <2>, <3>;
+			#pwm-cells = <3>;
+			clocks = <&clock_peric0 PCLK_PWM>;
+			clock-names = "timers";
+		};
+	};
+};
+
+#include "exynos7-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
new file mode 100644
index 0000000..4f2de3e7
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_FSL_LS2085A) += fsl-ls2085a-simu.dtb
+ 
+always		:= $(dtb-y)
+subdir-y	:= $(dts-dirs)
+clean-files	:= *.dtb
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts b/arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts
new file mode 100644
index 0000000..82e2a6f
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts
@@ -0,0 +1,65 @@
+/*
+ * Device Tree file for Freescale LS2085a software Simulator model
+ *
+ * Copyright (C) 2014, Freescale Semiconductor
+ *
+ * Bhupesh Sharma <bhupesh.sharma@freescale.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 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.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+/include/ "fsl-ls2085a.dtsi"
+
+/ {
+	model = "Freescale Layerscape 2085a software Simulator model";
+	compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
+
+	ethernet@2210000 {
+		compatible = "smsc,lan91c111";
+		reg = <0x0 0x2210000 0x0 0x100>;
+		interrupts = <0 58 0x1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi
new file mode 100644
index 0000000..e281ceb
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi
@@ -0,0 +1,163 @@
+/*
+ * Device Tree Include file for Freescale Layerscape-2085A family SoC.
+ *
+ * Copyright (C) 2014, Freescale Semiconductor
+ *
+ * Bhupesh Sharma <bhupesh.sharma@freescale.com>
+ *
+ * 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.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+/ {
+	compatible = "fsl,ls2085a";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		/*
+		 * We expect the enable-method for cpu's to be "psci", but this
+		 * is dependent on the SoC FW, which will fill this in.
+		 *
+		 * Currently supported enable-method is psci v0.2
+		 */
+
+		/* We have 4 clusters having 2 Cortex-A57 cores each */
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x1>;
+		};
+
+		cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x100>;
+		};
+
+		cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x101>;
+		};
+
+		cpu@200 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x200>;
+		};
+
+		cpu@201 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x201>;
+		};
+
+		cpu@300 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x300>;
+		};
+
+		cpu@301 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x0 0x301>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x80000000>;
+		      /* DRAM space - 1, size : 2 GB DRAM */
+	};
+
+	gic: interrupt-controller@6000000 {
+		compatible = "arm,gic-v3";
+		reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */
+		      <0x0 0x06100000 0 0x100000>; /* GICR (RD_base + SGI_base) */
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		interrupts = <1 9 0x4>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0x8>, /* Physical Secure PPI, active-low */
+			     <1 14 0x8>, /* Physical Non-Secure PPI, active-low */
+			     <1 11 0x8>, /* Virtual PPI, active-low */
+			     <1 10 0x8>; /* Hypervisor PPI, active-low */
+	};
+
+	serial0: serial@21c0500 {
+		device_type = "serial";
+		compatible = "fsl,ns16550", "ns16550a";
+		reg = <0x0 0x21c0500 0x0 0x100>;
+		clock-frequency = <0>;	/* Updated by bootloader */
+		interrupts = <0 32 0x1>; /* edge triggered */
+	};
+
+	serial1: serial@21c0600 {
+		device_type = "serial";
+		compatible = "fsl,ns16550", "ns16550a";
+		reg = <0x0 0x21c0600 0x0 0x100>;
+		clock-frequency = <0>; 	/* Updated by bootloader */
+		interrupts = <0 32 0x1>; /* edge triggered */
+	};
+
+	fsl_mc: fsl-mc@80c000000 {
+		compatible = "fsl,qoriq-mc";
+		reg = <0x00000008 0x0c000000 0 0x40>,	 /* MC portal base */
+		      <0x00000000 0x08340000 0 0x40000>; /* MC control reg */
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile
new file mode 100644
index 0000000..3ce2462
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-evb.dtb
+
+always		:= $(dtb-y)
+subdir-y	:= $(dts-dirs)
+clean-files	:= *.dtb
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
new file mode 100644
index 0000000..43d5401
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Eddie Huang <eddie.huang@mediatek.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.
+ */
+
+/dts-v1/;
+#include "mt8173.dtsi"
+
+/ {
+	model = "mediatek,mt8173-evb";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0 0x40000000 0 0x80000000>;
+	};
+
+	chosen { };
+};
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
new file mode 100644
index 0000000..8554ec3
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Eddie Huang <eddie.huang@mediatek.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,
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	compatible = "mediatek,mt8173";
+	interrupt-parent = <&sysirq>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&cpu0>;
+				};
+				core1 {
+					cpu = <&cpu1>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&cpu2>;
+				};
+				core1 {
+					cpu = <&cpu3>;
+				};
+			};
+		};
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x000>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x001>;
+			enable-method = "psci";
+		};
+
+		cpu2: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x100>;
+			enable-method = "psci";
+		};
+
+		cpu3: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57";
+			reg = <0x101>;
+			enable-method = "psci";
+		};
+	};
+
+	psci {
+		compatible = "arm,psci";
+		method = "smc";
+		cpu_suspend   = <0x84000001>;
+		cpu_off	      = <0x84000002>;
+		cpu_on	      = <0x84000003>;
+	};
+
+	uart_clk: dummy26m {
+		compatible = "fixed-clock";
+		clock-frequency = <26000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		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)>;
+	};
+
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		ranges;
+
+		sysirq: intpol-controller@10200620 {
+			compatible = "mediatek,mt8173-sysirq",
+					"mediatek,mt6577-sysirq";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+			reg = <0 0x10200620 0 0x20>;
+		};
+
+		gic: interrupt-controller@10220000 {
+			compatible = "arm,gic-400";
+			#interrupt-cells = <3>;
+			interrupt-parent = <&gic>;
+			interrupt-controller;
+			reg = <0 0x10221000 0 0x1000>,
+			      <0 0x10222000 0 0x2000>,
+			      <0 0x10224000 0 0x2000>,
+			      <0 0x10226000 0 0x2000>;
+			interrupts = <GIC_PPI 9
+				(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		};
+
+		uart0: serial@11002000 {
+			compatible = "mediatek,mt8173-uart",
+					"mediatek,mt6577-uart";
+			reg = <0 0x11002000 0 0x400>;
+			interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart1: serial@11003000 {
+			compatible = "mediatek,mt8173-uart",
+					"mediatek,mt6577-uart";
+			reg = <0 0x11003000 0 0x400>;
+			interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart2: serial@11004000 {
+			compatible = "mediatek,mt8173-uart",
+					"mediatek,mt6577-uart";
+			reg = <0 0x11004000 0 0x400>;
+			interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+
+		uart3: serial@11005000 {
+			compatible = "mediatek,mt8173-uart",
+					"mediatek,mt6577-uart";
+			reg = <0 0x11005000 0 0x400>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&uart_clk>;
+			status = "disabled";
+		};
+	};
+
+};
+
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 66b6cac..be1f12a 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -31,6 +31,8 @@
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_FSL_LS2085A=y
+CONFIG_ARCH_MEDIATEK=y
 CONFIG_ARCH_THUNDER=y
 CONFIG_ARCH_VEXPRESS=y
 CONFIG_ARCH_XGENE=y
@@ -88,6 +90,7 @@
 CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_MT6577=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 9b6f71d..67bf410 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -35,8 +35,8 @@
 void *module_alloc(unsigned long size)
 {
 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-				    GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE,
-				    __builtin_return_address(0));
+				    GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
+				    NUMA_NO_NODE, __builtin_return_address(0));
 }
 
 enum aarch64_reloc_op {
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 52731e2..4a03911 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -57,6 +57,10 @@
 	int
 	default 100
 
+config NR_CPUS
+	int
+	default "1"
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c
index f772068..4dda9bd 100644
--- a/arch/cris/arch-v32/drivers/sync_serial.c
+++ b/arch/cris/arch-v32/drivers/sync_serial.c
@@ -1286,7 +1286,7 @@
 
 		tr_cfg.tr_en = regk_sser_yes;
 		REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
-		DEBUGTRDMA(pr_info(KERN_INFO "dma s\n"););
+		DEBUGTRDMA(pr_info("dma s\n"););
 	} else {
 		DMA_CONTINUE_DATA(port->regi_dmaout);
 		DEBUGTRDMA(pr_info("dma c\n"););
@@ -1443,7 +1443,7 @@
 	reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes };
 	unsigned long flags;
 
-	DEBUGRXINT(pr_info(KERN_INFO "!"));
+	DEBUGRXINT(pr_info("!"));
 	spin_lock_irqsave(&port->lock, flags);
 
 	/* If we overrun the user experience is crap regardless if we
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index eb74dab..c17b01a 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -107,8 +107,10 @@
  * is used though, so set this really low. */
 #define WATCHDOG_MIN_FREE_PAGES 8
 
+#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY)
 /* for reliable NICE_DOGGY behaviour */
 static int bite_in_progress;
+#endif
 
 void reset_watchdog(void)
 {
@@ -155,7 +157,9 @@
 
 	nmi_enter();
 	oops_in_progress = 1;
+#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY)
 	bite_in_progress = 1;
+#endif
 	printk(KERN_WARNING "Watchdog bite\n");
 
 	/* Check if forced restart or unexpected watchdog */
diff --git a/arch/cris/include/asm/uaccess.h b/arch/cris/include/asm/uaccess.h
index 9145408..e3530d0 100644
--- a/arch/cris/include/asm/uaccess.h
+++ b/arch/cris/include/asm/uaccess.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Authors:    Bjorn Wesen (bjornw@axis.com)
  *	       Hans-Peter Nilsson (hp@axis.com)
  */
@@ -35,7 +35,7 @@
 #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 
 /* addr_limit is the maximum accessible address for the task. we misuse
- * the KERNEL_DS and USER_DS values to both assign and compare the 
+ * the KERNEL_DS and USER_DS values to both assign and compare the
  * addr_limit values through the equally misnamed get/set_fs macros.
  * (see above)
  */
@@ -47,12 +47,13 @@
 #define get_fs()	(current_thread_info()->addr_limit)
 #define set_fs(x)	(current_thread_info()->addr_limit = (x))
 
-#define segment_eq(a,b)	((a).seg == (b).seg)
+#define segment_eq(a, b)	((a).seg == (b).seg)
 
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
-#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
-#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
-#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+#define __user_ok(addr, size) \
+	(((size) <= TASK_SIZE) && ((addr) <= TASK_SIZE-(size)))
+#define __access_ok(addr, size) (__kernel_ok || __user_ok((addr), (size)))
+#define access_ok(type, addr, size) __access_ok((unsigned long)(addr), (size))
 
 #include <arch/uaccess.h>
 
@@ -69,8 +70,7 @@
  * on our cache or tlb entries.
  */
 
-struct exception_table_entry
-{
+struct exception_table_entry {
 	unsigned long insn, fixup;
 };
 
@@ -92,56 +92,74 @@
  * CRIS, we can just do these as direct assignments.  (Of course, the
  * exception handling means that it's no longer "just"...)
  */
-#define get_user(x,ptr) \
-  __get_user_check((x),(ptr),sizeof(*(ptr)))
-#define put_user(x,ptr) \
-  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+#define get_user(x, ptr) \
+	__get_user_check((x), (ptr), sizeof(*(ptr)))
+#define put_user(x, ptr) \
+	__put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
-#define __get_user(x,ptr) \
-  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __put_user(x,ptr) \
-  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+#define __get_user(x, ptr) \
+	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+#define __put_user(x, ptr) \
+	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 
 extern long __put_user_bad(void);
 
-#define __put_user_size(x,ptr,size,retval)			\
-do {								\
-	retval = 0;						\
-	switch (size) {						\
-	  case 1: __put_user_asm(x,ptr,retval,"move.b"); break;	\
-	  case 2: __put_user_asm(x,ptr,retval,"move.w"); break;	\
-	  case 4: __put_user_asm(x,ptr,retval,"move.d"); break;	\
-	  case 8: __put_user_asm_64(x,ptr,retval); break;	\
-	  default: __put_user_bad();				\
-	}							\
+#define __put_user_size(x, ptr, size, retval)				\
+do {									\
+	retval = 0;							\
+	switch (size) {							\
+	case 1:								\
+		__put_user_asm(x, ptr, retval, "move.b");		\
+		break;							\
+	case 2:								\
+		__put_user_asm(x, ptr, retval, "move.w");		\
+		break;							\
+	case 4:								\
+		__put_user_asm(x, ptr, retval, "move.d");		\
+		break;							\
+	case 8:								\
+		__put_user_asm_64(x, ptr, retval);			\
+		break;							\
+	default:							\
+		__put_user_bad();					\
+	}								\
 } while (0)
 
-#define __get_user_size(x,ptr,size,retval)			\
-do {								\
-	retval = 0;						\
-	switch (size) {						\
-	  case 1: __get_user_asm(x,ptr,retval,"move.b"); break;	\
-	  case 2: __get_user_asm(x,ptr,retval,"move.w"); break;	\
-	  case 4: __get_user_asm(x,ptr,retval,"move.d"); break;	\
-	  case 8: __get_user_asm_64(x,ptr,retval); break;	\
-	  default: (x) = __get_user_bad();			\
-	}							\
+#define __get_user_size(x, ptr, size, retval)				\
+do {									\
+	retval = 0;							\
+	switch (size) {							\
+	case 1:								\
+		__get_user_asm(x, ptr, retval, "move.b");		\
+		break;							\
+	case 2:								\
+		__get_user_asm(x, ptr, retval, "move.w");		\
+		break;							\
+	case 4:								\
+		__get_user_asm(x, ptr, retval, "move.d");		\
+		break;							\
+	case 8:								\
+		__get_user_asm_64(x, ptr, retval);			\
+		break;							\
+	default:							\
+		(x) = __get_user_bad();					\
+	}								\
 } while (0)
 
-#define __put_user_nocheck(x,ptr,size)			\
+#define __put_user_nocheck(x, ptr, size)		\
 ({							\
 	long __pu_err;					\
-	__put_user_size((x),(ptr),(size),__pu_err);	\
+	__put_user_size((x), (ptr), (size), __pu_err);	\
 	__pu_err;					\
 })
 
-#define __put_user_check(x,ptr,size)				\
-({								\
-	long __pu_err = -EFAULT;				\
-	__typeof__(*(ptr)) *__pu_addr = (ptr);			\
-	if (access_ok(VERIFY_WRITE,__pu_addr,size))		\
-		__put_user_size((x),__pu_addr,(size),__pu_err);	\
-	__pu_err;						\
+#define __put_user_check(x, ptr, size)					\
+({									\
+	long __pu_err = -EFAULT;					\
+	__typeof__(*(ptr)) *__pu_addr = (ptr);				\
+	if (access_ok(VERIFY_WRITE, __pu_addr, size))			\
+		__put_user_size((x), __pu_addr, (size), __pu_err);	\
+	__pu_err;							\
 })
 
 struct __large_struct { unsigned long buf[100]; };
@@ -149,21 +167,21 @@
 
 
 
-#define __get_user_nocheck(x,ptr,size)				\
+#define __get_user_nocheck(x, ptr, size)			\
 ({								\
 	long __gu_err, __gu_val;				\
-	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
-	(x) = (__typeof__(*(ptr)))__gu_val;			\
+	__get_user_size(__gu_val, (ptr), (size), __gu_err);	\
+	(x) = (__force __typeof__(*(ptr)))__gu_val;		\
 	__gu_err;						\
 })
 
-#define __get_user_check(x,ptr,size)					\
+#define __get_user_check(x, ptr, size)					\
 ({									\
 	long __gu_err = -EFAULT, __gu_val = 0;				\
 	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
-	if (access_ok(VERIFY_READ,__gu_addr,size))			\
-		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
-	(x) = (__typeof__(*(ptr)))__gu_val;				\
+	if (access_ok(VERIFY_READ, __gu_addr, size))			\
+		__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
+	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
 	__gu_err;							\
 })
 
@@ -180,7 +198,7 @@
 __generic_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
-		return __copy_user(to,from,n);
+		return __copy_user(to, from, n);
 	return n;
 }
 
@@ -188,7 +206,7 @@
 __generic_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	if (access_ok(VERIFY_READ, from, n))
-		return __copy_user_zeroing(to,from,n);
+		return __copy_user_zeroing(to, from, n);
 	return n;
 }
 
@@ -196,7 +214,7 @@
 __generic_clear_user(void __user *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
-		return __do_clear_user(to,n);
+		return __do_clear_user(to, n);
 	return n;
 }
 
@@ -210,6 +228,7 @@
 strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res = -EFAULT;
+
 	if (access_ok(VERIFY_READ, src, 1))
 		res = __do_strncpy_from_user(dst, src, count);
 	return res;
@@ -223,6 +242,7 @@
 __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
 	unsigned long ret = 0;
+
 	if (n == 0)
 		;
 	else if (n == 1)
@@ -273,6 +293,7 @@
 __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
+
 	if (n == 0)
 		;
 	else if (n == 1)
@@ -323,6 +344,7 @@
 __constant_clear_user(void __user *to, unsigned long n)
 {
 	unsigned long ret = 0;
+
 	if (n == 0)
 		;
 	else if (n == 1)
@@ -350,20 +372,20 @@
 }
 
 
-#define clear_user(to, n)			\
-(__builtin_constant_p(n) ?			\
- __constant_clear_user(to, n) :			\
- __generic_clear_user(to, n))
+#define clear_user(to, n)				\
+	(__builtin_constant_p(n) ?			\
+	 __constant_clear_user(to, n) :			\
+	 __generic_clear_user(to, n))
 
-#define copy_from_user(to, from, n)		\
-(__builtin_constant_p(n) ?			\
- __constant_copy_from_user(to, from, n) :	\
- __generic_copy_from_user(to, from, n))
+#define copy_from_user(to, from, n)			\
+	(__builtin_constant_p(n) ?			\
+	 __constant_copy_from_user(to, from, n) :	\
+	 __generic_copy_from_user(to, from, n))
 
-#define copy_to_user(to, from, n)		\
-(__builtin_constant_p(n) ?			\
- __constant_copy_to_user(to, from, n) :		\
- __generic_copy_to_user(to, from, n))
+#define copy_to_user(to, from, n)			\
+	(__builtin_constant_p(n) ?			\
+	 __constant_copy_to_user(to, from, n) :		\
+	 __generic_copy_to_user(to, from, n))
 
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
@@ -373,29 +395,31 @@
 __generic_copy_from_user_nocheck(void *to, const void __user *from,
 				 unsigned long n)
 {
-	return __copy_user_zeroing(to,from,n);
+	return __copy_user_zeroing(to, from, n);
 }
 
 static inline unsigned long
 __generic_copy_to_user_nocheck(void __user *to, const void *from,
 			       unsigned long n)
 {
-	return __copy_user(to,from,n);
+	return __copy_user(to, from, n);
 }
 
 static inline unsigned long
 __generic_clear_user_nocheck(void __user *to, unsigned long n)
 {
-	return __do_clear_user(to,n);
+	return __do_clear_user(to, n);
 }
 
 /* without checking */
 
-#define __copy_to_user(to,from,n)   __generic_copy_to_user_nocheck((to),(from),(n))
-#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
+#define __copy_to_user(to, from, n) \
+	__generic_copy_to_user_nocheck((to), (from), (n))
+#define __copy_from_user(to, from, n) \
+	__generic_copy_from_user_nocheck((to), (from), (n))
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
-#define __clear_user(to,n) __generic_clear_user_nocheck((to),(n))
+#define __clear_user(to, n) __generic_clear_user_nocheck((to), (n))
 
 #define strlen_user(str)	strnlen_user((str), 0x7ffffffe)
 
diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c
index 3908b94..e704f81 100644
--- a/arch/cris/kernel/crisksyms.c
+++ b/arch/cris/kernel/crisksyms.c
@@ -67,3 +67,4 @@
 #endif
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_from_user);
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index 2686a7a..83f12f2 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -219,6 +219,9 @@
 	/* User mode accesses just cause a SIGSEGV */
 
 	if (user_mode(regs)) {
+#ifdef CONFIG_NO_SEGFAULT_TERMINATION
+		DECLARE_WAIT_QUEUE_HEAD(wq);
+#endif
 		printk(KERN_NOTICE "%s (pid %d) segfaults for page "
 			"address %08lx at pc %08lx\n",
 			tsk->comm, tsk->pid,
@@ -229,7 +232,6 @@
 			show_registers(regs);
 
 #ifdef CONFIG_NO_SEGFAULT_TERMINATION
-		DECLARE_WAIT_QUEUE_HEAD(wq);
 		wait_event_interruptible(wq, 0 == 1);
 #else
 		info.si_signo = SIGSEGV;
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index f295f9a..965ab42 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -217,14 +217,12 @@
 
 static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf)
 {
-	ssize_t	len;
 	cpumask_t shared_cpu_map;
 
 	cpumask_and(&shared_cpu_map,
 				&this_leaf->shared_cpu_map, cpu_online_mask);
-	len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map);
-	len += sprintf(buf+len, "\n");
-	return len;
+	return scnprintf(buf, PAGE_SIZE, "%*pb\n",
+			 cpumask_pr_args(&shared_cpu_map));
 }
 
 static ssize_t show_type(struct cache_info *this_leaf, char *buf)
diff --git a/arch/m68k/68360/commproc.c b/arch/m68k/68360/commproc.c
index 315727b..14d7f35 100644
--- a/arch/m68k/68360/commproc.c
+++ b/arch/m68k/68360/commproc.c
@@ -64,15 +64,15 @@
 
 /* CPM interrupt vector functions. */
 struct	cpm_action {
-	void	(*handler)(void *);
-	void	*dev_id;
+	irq_handler_t	handler;
+	void		*dev_id;
 };
 static	struct	cpm_action cpm_vecs[CPMVEC_NR];
 static	void	cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
 static	void	cpm_error_interrupt(void *);
 
 /* prototypes: */
-void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
+void cpm_install_handler(int vec, irq_handler_t handler, void *dev_id);
 void m360_cpm_reset(void);
 
 
@@ -208,7 +208,7 @@
 /* Install a CPM interrupt handler.
 */
 void
-cpm_install_handler(int vec, void (*handler)(), void *dev_id)
+cpm_install_handler(int vec, irq_handler_t handler, void *dev_id)
 {
 
 	request_irq(vec, handler, 0, "timer", dev_id);
diff --git a/arch/m68k/68360/config.c b/arch/m68k/68360/config.c
index 17ec416..fd1f948 100644
--- a/arch/m68k/68360/config.c
+++ b/arch/m68k/68360/config.c
@@ -106,19 +106,6 @@
   pquicc->timer_tgcr  = tgcr_save;
 }
 
-int BSP_set_clock_mmss(unsigned long nowtime)
-{
-#if 0
-  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-
-  tod->second1 = real_seconds / 10;
-  tod->second2 = real_seconds % 10;
-  tod->minute1 = real_minutes / 10;
-  tod->minute2 = real_minutes % 10;
-#endif
-  return 0;
-}
-
 void BSP_reset (void)
 {
   local_irq_disable();
diff --git a/arch/m68k/include/asm/commproc.h b/arch/m68k/include/asm/commproc.h
index 66a36bd..f41c968 100644
--- a/arch/m68k/include/asm/commproc.h
+++ b/arch/m68k/include/asm/commproc.h
@@ -480,28 +480,6 @@
 #define SICR_ENET_CLKRT	((uint)0x0000003d)
 #endif
 
-#ifdef CONFIG_BSEIP
-/* This ENET stuff is for the MPC823 with ethernet on SCC2.
- * This is unique to the BSE ip-Engine board.
- */
-#define PA_ENET_RXD	((ushort)0x0004)
-#define PA_ENET_TXD	((ushort)0x0008)
-#define PA_ENET_TCLK	((ushort)0x0100)
-#define PA_ENET_RCLK	((ushort)0x0200)
-#define PB_ENET_TENA	((uint)0x00002000)
-#define PC_ENET_CLSN	((ushort)0x0040)
-#define PC_ENET_RENA	((ushort)0x0080)
-
-/* BSE uses port B and C bits for PHY control also.
-*/
-#define PB_BSE_POWERUP	((uint)0x00000004)
-#define PB_BSE_FDXDIS	((uint)0x00008000)
-#define PC_BSE_LOOPBACK	((ushort)0x0800)
-
-#define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002c00)
-#endif
-
 /* SCC Event register as used by Ethernet.
 */
 #define SCCE_ENET_GRA	((ushort)0x0080)	/* Graceful stop complete */
@@ -671,7 +649,7 @@
 /* #define	CPMVEC_PIO_PC4		((ushort)0x01) */
 /* #define	CPMVEC_ERROR		((ushort)0x00) */
 
-extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+extern void cpm_install_handler(int vec, irq_handler_t handler, void *dev_id);
 
 /* CPM interrupt configuration vector.
 */
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 42f5f1a..69a8a8d 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -16,6 +16,7 @@
 obj-y += dma-octeon.o
 obj-y += octeon-memcpy.o
 obj-y += executive/
+obj-y += crypto/
 
 obj-$(CONFIG_MTD)		      += flash_setup.o
 obj-$(CONFIG_SMP)		      += smp.o
diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile
new file mode 100644
index 0000000..a74f76d
--- /dev/null
+++ b/arch/mips/cavium-octeon/crypto/Makefile
@@ -0,0 +1,7 @@
+#
+# OCTEON-specific crypto modules.
+#
+
+obj-y += octeon-crypto.o
+
+obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o
diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.c b/arch/mips/cavium-octeon/crypto/octeon-crypto.c
new file mode 100644
index 0000000..7c82ff4
--- /dev/null
+++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.c
@@ -0,0 +1,66 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004-2012 Cavium Networks
+ */
+
+#include <asm/cop2.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include "octeon-crypto.h"
+
+/**
+ * Enable access to Octeon's COP2 crypto hardware for kernel use. Wrap any
+ * crypto operations in calls to octeon_crypto_enable/disable in order to make
+ * sure the state of COP2 isn't corrupted if userspace is also performing
+ * hardware crypto operations. Allocate the state parameter on the stack.
+ * Preemption must be disabled to prevent context switches.
+ *
+ * @state: Pointer to state structure to store current COP2 state in.
+ *
+ * Returns: Flags to be passed to octeon_crypto_disable()
+ */
+unsigned long octeon_crypto_enable(struct octeon_cop2_state *state)
+{
+	int status;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	status = read_c0_status();
+	write_c0_status(status | ST0_CU2);
+	if (KSTK_STATUS(current) & ST0_CU2) {
+		octeon_cop2_save(&(current->thread.cp2));
+		KSTK_STATUS(current) &= ~ST0_CU2;
+		status &= ~ST0_CU2;
+	} else if (status & ST0_CU2) {
+		octeon_cop2_save(state);
+	}
+	local_irq_restore(flags);
+	return status & ST0_CU2;
+}
+EXPORT_SYMBOL_GPL(octeon_crypto_enable);
+
+/**
+ * Disable access to Octeon's COP2 crypto hardware in the kernel. This must be
+ * called after an octeon_crypto_enable() before any context switch or return to
+ * userspace.
+ *
+ * @state:	Pointer to COP2 state to restore
+ * @flags:	Return value from octeon_crypto_enable()
+ */
+void octeon_crypto_disable(struct octeon_cop2_state *state,
+			   unsigned long crypto_flags)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (crypto_flags & ST0_CU2)
+		octeon_cop2_restore(state);
+	else
+		write_c0_status(read_c0_status() & ~ST0_CU2);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(octeon_crypto_disable);
diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.h b/arch/mips/cavium-octeon/crypto/octeon-crypto.h
new file mode 100644
index 0000000..e2a4aec
--- /dev/null
+++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.h
@@ -0,0 +1,75 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2013 Cavium Inc., All Rights Reserved.
+ *
+ * MD5 instruction definitions added by Aaro Koskinen <aaro.koskinen@iki.fi>.
+ *
+ */
+#ifndef __LINUX_OCTEON_CRYPTO_H
+#define __LINUX_OCTEON_CRYPTO_H
+
+#include <linux/sched.h>
+#include <asm/mipsregs.h>
+
+#define OCTEON_CR_OPCODE_PRIORITY 300
+
+extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state);
+extern void octeon_crypto_disable(struct octeon_cop2_state *state,
+				  unsigned long flags);
+
+/*
+ * Macros needed to implement MD5:
+ */
+
+/*
+ * The index can be 0-1.
+ */
+#define write_octeon_64bit_hash_dword(value, index)	\
+do {							\
+	__asm__ __volatile__ (				\
+	"dmtc2 %[rt],0x0048+" STR(index)		\
+	:						\
+	: [rt] "d" (value));				\
+} while (0)
+
+/*
+ * The index can be 0-1.
+ */
+#define read_octeon_64bit_hash_dword(index)		\
+({							\
+	u64 __value;					\
+							\
+	__asm__ __volatile__ (				\
+	"dmfc2 %[rt],0x0048+" STR(index)		\
+	: [rt] "=d" (__value)				\
+	: );						\
+							\
+	__value;					\
+})
+
+/*
+ * The index can be 0-6.
+ */
+#define write_octeon_64bit_block_dword(value, index)	\
+do {							\
+	__asm__ __volatile__ (				\
+	"dmtc2 %[rt],0x0040+" STR(index)		\
+	:						\
+	: [rt] "d" (value));				\
+} while (0)
+
+/*
+ * The value is the final block dword (64-bit).
+ */
+#define octeon_md5_start(value)				\
+do {							\
+	__asm__ __volatile__ (				\
+	"dmtc2 %[rt],0x4047"				\
+	:						\
+	: [rt] "d" (value));				\
+} while (0)
+
+#endif /* __LINUX_OCTEON_CRYPTO_H */
diff --git a/arch/mips/cavium-octeon/crypto/octeon-md5.c b/arch/mips/cavium-octeon/crypto/octeon-md5.c
new file mode 100644
index 0000000..b909881
--- /dev/null
+++ b/arch/mips/cavium-octeon/crypto/octeon-md5.c
@@ -0,0 +1,216 @@
+/*
+ * Cryptographic API.
+ *
+ * MD5 Message Digest Algorithm (RFC1321).
+ *
+ * Adapted for OCTEON by Aaro Koskinen <aaro.koskinen@iki.fi>.
+ *
+ * Based on crypto/md5.c, which is:
+ *
+ * Derived from cryptoapi implementation, originally based on the
+ * public domain implementation written by Colin Plumb in 1993.
+ *
+ * Copyright (c) Cryptoapi developers.
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * 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 <crypto/md5.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <linux/cryptohash.h>
+#include <asm/octeon/octeon.h>
+#include <crypto/internal/hash.h>
+
+#include "octeon-crypto.h"
+
+/*
+ * We pass everything as 64-bit. OCTEON can handle misaligned data.
+ */
+
+static void octeon_md5_store_hash(struct md5_state *ctx)
+{
+	u64 *hash = (u64 *)ctx->hash;
+
+	write_octeon_64bit_hash_dword(hash[0], 0);
+	write_octeon_64bit_hash_dword(hash[1], 1);
+}
+
+static void octeon_md5_read_hash(struct md5_state *ctx)
+{
+	u64 *hash = (u64 *)ctx->hash;
+
+	hash[0] = read_octeon_64bit_hash_dword(0);
+	hash[1] = read_octeon_64bit_hash_dword(1);
+}
+
+static void octeon_md5_transform(const void *_block)
+{
+	const u64 *block = _block;
+
+	write_octeon_64bit_block_dword(block[0], 0);
+	write_octeon_64bit_block_dword(block[1], 1);
+	write_octeon_64bit_block_dword(block[2], 2);
+	write_octeon_64bit_block_dword(block[3], 3);
+	write_octeon_64bit_block_dword(block[4], 4);
+	write_octeon_64bit_block_dword(block[5], 5);
+	write_octeon_64bit_block_dword(block[6], 6);
+	octeon_md5_start(block[7]);
+}
+
+static int octeon_md5_init(struct shash_desc *desc)
+{
+	struct md5_state *mctx = shash_desc_ctx(desc);
+
+	mctx->hash[0] = cpu_to_le32(0x67452301);
+	mctx->hash[1] = cpu_to_le32(0xefcdab89);
+	mctx->hash[2] = cpu_to_le32(0x98badcfe);
+	mctx->hash[3] = cpu_to_le32(0x10325476);
+	mctx->byte_count = 0;
+
+	return 0;
+}
+
+static int octeon_md5_update(struct shash_desc *desc, const u8 *data,
+			     unsigned int len)
+{
+	struct md5_state *mctx = shash_desc_ctx(desc);
+	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
+	struct octeon_cop2_state state;
+	unsigned long flags;
+
+	mctx->byte_count += len;
+
+	if (avail > len) {
+		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
+		       data, len);
+		return 0;
+	}
+
+	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data,
+	       avail);
+
+	local_bh_disable();
+	preempt_disable();
+	flags = octeon_crypto_enable(&state);
+	octeon_md5_store_hash(mctx);
+
+	octeon_md5_transform(mctx->block);
+	data += avail;
+	len -= avail;
+
+	while (len >= sizeof(mctx->block)) {
+		octeon_md5_transform(data);
+		data += sizeof(mctx->block);
+		len -= sizeof(mctx->block);
+	}
+
+	octeon_md5_read_hash(mctx);
+	octeon_crypto_disable(&state, flags);
+	preempt_enable();
+	local_bh_enable();
+
+	memcpy(mctx->block, data, len);
+
+	return 0;
+}
+
+static int octeon_md5_final(struct shash_desc *desc, u8 *out)
+{
+	struct md5_state *mctx = shash_desc_ctx(desc);
+	const unsigned int offset = mctx->byte_count & 0x3f;
+	char *p = (char *)mctx->block + offset;
+	int padding = 56 - (offset + 1);
+	struct octeon_cop2_state state;
+	unsigned long flags;
+
+	*p++ = 0x80;
+
+	local_bh_disable();
+	preempt_disable();
+	flags = octeon_crypto_enable(&state);
+	octeon_md5_store_hash(mctx);
+
+	if (padding < 0) {
+		memset(p, 0x00, padding + sizeof(u64));
+		octeon_md5_transform(mctx->block);
+		p = (char *)mctx->block;
+		padding = 56;
+	}
+
+	memset(p, 0, padding);
+	mctx->block[14] = cpu_to_le32(mctx->byte_count << 3);
+	mctx->block[15] = cpu_to_le32(mctx->byte_count >> 29);
+	octeon_md5_transform(mctx->block);
+
+	octeon_md5_read_hash(mctx);
+	octeon_crypto_disable(&state, flags);
+	preempt_enable();
+	local_bh_enable();
+
+	memcpy(out, mctx->hash, sizeof(mctx->hash));
+	memset(mctx, 0, sizeof(*mctx));
+
+	return 0;
+}
+
+static int octeon_md5_export(struct shash_desc *desc, void *out)
+{
+	struct md5_state *ctx = shash_desc_ctx(desc);
+
+	memcpy(out, ctx, sizeof(*ctx));
+	return 0;
+}
+
+static int octeon_md5_import(struct shash_desc *desc, const void *in)
+{
+	struct md5_state *ctx = shash_desc_ctx(desc);
+
+	memcpy(ctx, in, sizeof(*ctx));
+	return 0;
+}
+
+static struct shash_alg alg = {
+	.digestsize	=	MD5_DIGEST_SIZE,
+	.init		=	octeon_md5_init,
+	.update		=	octeon_md5_update,
+	.final		=	octeon_md5_final,
+	.export		=	octeon_md5_export,
+	.import		=	octeon_md5_import,
+	.descsize	=	sizeof(struct md5_state),
+	.statesize	=	sizeof(struct md5_state),
+	.base		=	{
+		.cra_name	=	"md5",
+		.cra_driver_name=	"octeon-md5",
+		.cra_priority	=	OCTEON_CR_OPCODE_PRIORITY,
+		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
+		.cra_blocksize	=	MD5_HMAC_BLOCK_SIZE,
+		.cra_module	=	THIS_MODULE,
+	}
+};
+
+static int __init md5_mod_init(void)
+{
+	if (!octeon_has_crypto())
+		return -ENOTSUPP;
+	return crypto_register_shash(&alg);
+}
+
+static void __exit md5_mod_fini(void)
+{
+	crypto_unregister_shash(&alg);
+}
+
+module_init(md5_mod_init);
+module_exit(md5_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MD5 Message Digest Algorithm (OCTEON)");
+MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c
index e15b049..b2104bd 100644
--- a/arch/mips/cavium-octeon/executive/octeon-model.c
+++ b/arch/mips/cavium-octeon/executive/octeon-model.c
@@ -27,6 +27,9 @@
 
 #include <asm/octeon/octeon.h>
 
+enum octeon_feature_bits __octeon_feature_bits __read_mostly;
+EXPORT_SYMBOL_GPL(__octeon_feature_bits);
+
 /**
  * Read a byte of fuse data
  * @byte_addr:	 address to read
@@ -103,6 +106,9 @@
 	else
 		suffix = "NSP";
 
+	if (!fus_dat2.s.nocrypto)
+		__octeon_feature_bits |= OCTEON_HAS_CRYPTO;
+
 	/*
 	 * Assume pass number is encoded using <5:3><2:0>. Exceptions
 	 * will be fixed later.
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index b67ddf0..12410a2 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -77,7 +77,7 @@
 
 static int octeon2_usb_clock_start_cnt;
 
-static void octeon2_usb_clocks_start(void)
+static void octeon2_usb_clocks_start(struct device *dev)
 {
 	u64 div;
 	union cvmx_uctlx_if_ena if_ena;
@@ -86,6 +86,8 @@
 	union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
 	int i;
 	unsigned long io_clk_64_to_ns;
+	u32 clock_rate = 12000000;
+	bool is_crystal_clock = false;
 
 
 	mutex_lock(&octeon2_usb_clocks_mutex);
@@ -96,6 +98,28 @@
 
 	io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
 
+	if (dev->of_node) {
+		struct device_node *uctl_node;
+		const char *clock_type;
+
+		uctl_node = of_get_parent(dev->of_node);
+		if (!uctl_node) {
+			dev_err(dev, "No UCTL device node\n");
+			goto exit;
+		}
+		i = of_property_read_u32(uctl_node,
+					 "refclk-frequency", &clock_rate);
+		if (i) {
+			dev_err(dev, "No UCTL \"refclk-frequency\"\n");
+			goto exit;
+		}
+		i = of_property_read_string(uctl_node,
+					    "refclk-type", &clock_type);
+
+		if (!i && strcmp("crystal", clock_type) == 0)
+			is_crystal_clock = true;
+	}
+
 	/*
 	 * Step 1: Wait for voltages stable.  That surely happened
 	 * before starting the kernel.
@@ -126,9 +150,22 @@
 	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 
 	/* 3b */
-	/* 12MHz crystal. */
-	clk_rst_ctl.s.p_refclk_sel = 0;
-	clk_rst_ctl.s.p_refclk_div = 0;
+	clk_rst_ctl.s.p_refclk_sel = is_crystal_clock ? 0 : 1;
+	switch (clock_rate) {
+	default:
+		pr_err("Invalid UCTL clock rate of %u, using 12000000 instead\n",
+			clock_rate);
+		/* Fall through */
+	case 12000000:
+		clk_rst_ctl.s.p_refclk_div = 0;
+		break;
+	case 24000000:
+		clk_rst_ctl.s.p_refclk_div = 1;
+		break;
+	case 48000000:
+		clk_rst_ctl.s.p_refclk_div = 2;
+		break;
+	}
 	cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
 
 	/* 3c */
@@ -259,7 +296,7 @@
 
 static int octeon_ehci_power_on(struct platform_device *pdev)
 {
-	octeon2_usb_clocks_start();
+	octeon2_usb_clocks_start(&pdev->dev);
 	return 0;
 }
 
@@ -273,15 +310,16 @@
 #ifdef __BIG_ENDIAN
 	.big_endian_mmio	= 1,
 #endif
+	.dma_mask_64	= 1,
 	.power_on	= octeon_ehci_power_on,
 	.power_off	= octeon_ehci_power_off,
 };
 
-static void __init octeon_ehci_hw_start(void)
+static void __init octeon_ehci_hw_start(struct device *dev)
 {
 	union cvmx_uctlx_ehci_ctl ehci_ctl;
 
-	octeon2_usb_clocks_start();
+	octeon2_usb_clocks_start(dev);
 
 	ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
 	/* Use 64-bit addressing. */
@@ -294,64 +332,30 @@
 	octeon2_usb_clocks_stop();
 }
 
-static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64);
-
 static int __init octeon_ehci_device_init(void)
 {
 	struct platform_device *pd;
+	struct device_node *ehci_node;
 	int ret = 0;
 
-	struct resource usb_resources[] = {
-		{
-			.flags	= IORESOURCE_MEM,
-		}, {
-			.flags	= IORESOURCE_IRQ,
-		}
-	};
-
-	/* Only Octeon2 has ehci/ohci */
-	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
+	ehci_node = of_find_node_by_name(NULL, "ehci");
+	if (!ehci_node)
 		return 0;
 
-	if (octeon_is_simulation() || usb_disabled())
-		return 0; /* No USB in the simulator. */
+	pd = of_find_device_by_node(ehci_node);
+	if (!pd)
+		return 0;
 
-	pd = platform_device_alloc("ehci-platform", 0);
-	if (!pd) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	usb_resources[0].start = 0x00016F0000000000ULL;
-	usb_resources[0].end = usb_resources[0].start + 0x100;
-
-	usb_resources[1].start = OCTEON_IRQ_USB0;
-	usb_resources[1].end = OCTEON_IRQ_USB0;
-
-	ret = platform_device_add_resources(pd, usb_resources,
-					    ARRAY_SIZE(usb_resources));
-	if (ret)
-		goto fail;
-
-	pd->dev.dma_mask = &octeon_ehci_dma_mask;
 	pd->dev.platform_data = &octeon_ehci_pdata;
-	octeon_ehci_hw_start();
+	octeon_ehci_hw_start(&pd->dev);
 
-	ret = platform_device_add(pd);
-	if (ret)
-		goto fail;
-
-	return ret;
-fail:
-	platform_device_put(pd);
-out:
 	return ret;
 }
 device_initcall(octeon_ehci_device_init);
 
 static int octeon_ohci_power_on(struct platform_device *pdev)
 {
-	octeon2_usb_clocks_start();
+	octeon2_usb_clocks_start(&pdev->dev);
 	return 0;
 }
 
@@ -369,11 +373,11 @@
 	.power_off	= octeon_ohci_power_off,
 };
 
-static void __init octeon_ohci_hw_start(void)
+static void __init octeon_ohci_hw_start(struct device *dev)
 {
 	union cvmx_uctlx_ohci_ctl ohci_ctl;
 
-	octeon2_usb_clocks_start();
+	octeon2_usb_clocks_start(dev);
 
 	ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
 	ohci_ctl.s.l2c_addr_msb = 0;
@@ -387,57 +391,27 @@
 static int __init octeon_ohci_device_init(void)
 {
 	struct platform_device *pd;
+	struct device_node *ohci_node;
 	int ret = 0;
 
-	struct resource usb_resources[] = {
-		{
-			.flags	= IORESOURCE_MEM,
-		}, {
-			.flags	= IORESOURCE_IRQ,
-		}
-	};
-
-	/* Only Octeon2 has ehci/ohci */
-	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
+	ohci_node = of_find_node_by_name(NULL, "ohci");
+	if (!ohci_node)
 		return 0;
 
-	if (octeon_is_simulation() || usb_disabled())
-		return 0; /* No USB in the simulator. */
-
-	pd = platform_device_alloc("ohci-platform", 0);
-	if (!pd) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	usb_resources[0].start = 0x00016F0000000400ULL;
-	usb_resources[0].end = usb_resources[0].start + 0x100;
-
-	usb_resources[1].start = OCTEON_IRQ_USB0;
-	usb_resources[1].end = OCTEON_IRQ_USB0;
-
-	ret = platform_device_add_resources(pd, usb_resources,
-					    ARRAY_SIZE(usb_resources));
-	if (ret)
-		goto fail;
+	pd = of_find_device_by_node(ohci_node);
+	if (!pd)
+		return 0;
 
 	pd->dev.platform_data = &octeon_ohci_pdata;
-	octeon_ohci_hw_start();
+	octeon_ohci_hw_start(&pd->dev);
 
-	ret = platform_device_add(pd);
-	if (ret)
-		goto fail;
-
-	return ret;
-fail:
-	platform_device_put(pd);
-out:
 	return ret;
 }
 device_initcall(octeon_ohci_device_init);
 
 #endif /* CONFIG_USB */
 
+
 static struct of_device_id __initdata octeon_ids[] = {
 	{ .compatible = "simple-bus", },
 	{ .compatible = "cavium,octeon-6335-uctl", },
diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h
index c4fe81f..8ebd3f57 100644
--- a/arch/mips/include/asm/octeon/octeon-feature.h
+++ b/arch/mips/include/asm/octeon/octeon-feature.h
@@ -46,8 +46,6 @@
 	OCTEON_FEATURE_SAAD,
 	/* Does this Octeon support the ZIP offload engine? */
 	OCTEON_FEATURE_ZIP,
-	/* Does this Octeon support crypto acceleration using COP2? */
-	OCTEON_FEATURE_CRYPTO,
 	OCTEON_FEATURE_DORM_CRYPTO,
 	/* Does this Octeon support PCI express? */
 	OCTEON_FEATURE_PCIE,
@@ -86,6 +84,21 @@
 	OCTEON_MAX_FEATURE
 };
 
+enum octeon_feature_bits {
+	OCTEON_HAS_CRYPTO = 0x0001,	/* Crypto acceleration using COP2 */
+};
+extern enum octeon_feature_bits __octeon_feature_bits;
+
+/**
+ * octeon_has_crypto() - Check if this OCTEON has crypto acceleration support.
+ *
+ * Returns: Non-zero if the feature exists. Zero if the feature does not exist.
+ */
+static inline int octeon_has_crypto(void)
+{
+	return __octeon_feature_bits & OCTEON_HAS_CRYPTO;
+}
+
 /**
  * Determine if the current Octeon supports a specific feature. These
  * checks have been optimized to be fairly quick, but they should still
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
index d781f9e..6dfefd2 100644
--- a/arch/mips/include/asm/octeon/octeon.h
+++ b/arch/mips/include/asm/octeon/octeon.h
@@ -44,11 +44,6 @@
 extern const char *octeon_get_boot_argument(int arg);
 extern void octeon_hal_setup_reserved32(void);
 extern void octeon_user_io_init(void);
-struct octeon_cop2_state;
-extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state);
-extern void octeon_crypto_disable(struct octeon_cop2_state *state,
-				  unsigned long flags);
-extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
 
 extern void octeon_init_cvmcount(void);
 extern void octeon_setup_delays(void);
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index 2a52568..1833f51 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -47,7 +47,7 @@
 void *module_alloc(unsigned long size)
 {
 	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
-				GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE,
+				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
 				__builtin_return_address(0));
 }
 #endif
diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c
index 4fde7ac..e743bdd 100644
--- a/arch/mips/netlogic/common/smp.c
+++ b/arch/mips/netlogic/common/smp.c
@@ -162,7 +162,6 @@
 	unsigned int boot_cpu;
 	int num_cpus, i, ncore, node;
 	volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
-	char buf[64];
 
 	boot_cpu = hard_smp_processor_id();
 	cpumask_clear(&phys_cpu_present_mask);
@@ -189,10 +188,10 @@
 		}
 	}
 
-	cpumask_scnprintf(buf, ARRAY_SIZE(buf), &phys_cpu_present_mask);
-	pr_info("Physical CPU mask: %s\n", buf);
-	cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask);
-	pr_info("Possible CPU mask: %s\n", buf);
+	pr_info("Physical CPU mask: %*pb\n",
+		cpumask_pr_args(&phys_cpu_present_mask));
+	pr_info("Possible CPU mask: %*pb\n",
+		cpumask_pr_args(cpu_possible_mask));
 
 	/* check with the cores we have woken up */
 	for (ncore = 0, i = 0; i < NLM_NR_NODES; i++)
@@ -209,7 +208,6 @@
 {
 	uint32_t core0_thr_mask, core_thr_mask;
 	int threadmode, i, j;
-	char buf[64];
 
 	core0_thr_mask = 0;
 	for (i = 0; i < NLM_THREADS_PER_CORE; i++)
@@ -244,8 +242,7 @@
 	return threadmode;
 
 unsupp:
-	cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask);
-	panic("Unsupported CPU mask %s", buf);
+	panic("Unsupported CPU mask %*pb", cpumask_pr_args(wakeup_mask));
 	return 0;
 }
 
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 5822e8e..3c63a82 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -219,7 +219,7 @@
 	 * init_data correctly */
 	return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
 				    GFP_KERNEL | __GFP_HIGHMEM,
-				    PAGE_KERNEL_RWX, NUMA_NO_NODE,
+				    PAGE_KERNEL_RWX, 0, NUMA_NO_NODE,
 				    __builtin_return_address(0));
 }
 
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 067fb0d..c7240a0 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -95,6 +95,9 @@
 #define OR_FCM_TRLX_SHIFT                2
 #define OR_FCM_EHTR             0x00000002
 #define OR_FCM_EHTR_SHIFT                1
+
+#define OR_GPCM_AM		0xFFFF8000
+#define OR_GPCM_AM_SHIFT		15
 };
 
 struct fsl_lbc_regs {
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index 14bdcbd..64b52b1 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -333,8 +333,8 @@
 /*
  * Encode and decode a swap entry.
  * Note that the bits we use in a PTE for representing a swap entry
- * must not include the _PAGE_PRESENT bit, the _PAGE_FILE bit, or the
- *_PAGE_HASHPTE bit (if used).  -- paulus
+ * must not include the _PAGE_PRESENT bit or the _PAGE_HASHPTE bit (if used).
+ *   -- paulus
  */
 #define __swp_type(entry)		((entry).val & 0x1f)
 #define __swp_offset(entry)		((entry).val >> 5)
@@ -342,11 +342,6 @@
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> 3 })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val << 3 })
 
-/* Encode and decode a nonlinear file mapping entry */
-#define PTE_FILE_MAX_BITS	29
-#define pte_to_pgoff(pte)	(pte_val(pte) >> 3)
-#define pgoff_to_pte(off)	((pte_t) { ((off) << 3) | _PAGE_FILE })
-
 #ifndef CONFIG_PPC_4K_PAGES
 void pgtable_cache_init(void);
 #else
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index d46532c..43e6ad4 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -352,9 +352,6 @@
 #define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
 #define __pte_to_swp_entry(pte)	((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
 #define __swp_entry_to_pte(x)	((pte_t) { (x).val << PTE_RPN_SHIFT })
-#define pte_to_pgoff(pte)	(pte_val(pte) >> PTE_RPN_SHIFT)
-#define pgoff_to_pte(off)	((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
-#define PTE_FILE_MAX_BITS	(BITS_PER_LONG - PTE_RPN_SHIFT)
 
 void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
 void pgtable_cache_init(void);
@@ -389,7 +386,7 @@
  * The last three bits are intentionally left to zero. This memory location
  * are also used as normal page PTE pointers. So if we have any pointers
  * left around while we collapse a hugepage, we need to make sure
- * _PAGE_PRESENT and _PAGE_FILE bits of that are zero when we look at them
+ * _PAGE_PRESENT bit of that is zero when we look at them
  */
 static inline unsigned int hpte_valid(unsigned char *hpte_slot_array, int index)
 {
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 79fee2e..9835ac4 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -34,7 +34,6 @@
 {	return (pte_val(pte) & (_PAGE_RW | _PAGE_RO)) != _PAGE_RO; }
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 static inline int pte_none(pte_t pte)		{ return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
 static inline pgprot_t pte_pgprot(pte_t pte)	{ return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
diff --git a/arch/powerpc/include/asm/pte-40x.h b/arch/powerpc/include/asm/pte-40x.h
index ec0b0b0..486b1ef 100644
--- a/arch/powerpc/include/asm/pte-40x.h
+++ b/arch/powerpc/include/asm/pte-40x.h
@@ -38,7 +38,6 @@
  */
 
 #define	_PAGE_GUARDED	0x001	/* G: page is guarded from prefetch */
-#define _PAGE_FILE	0x001	/* when !present: nonlinear file mapping */
 #define _PAGE_PRESENT	0x002	/* software: PTE contains a translation */
 #define	_PAGE_NO_CACHE	0x004	/* I: caching is inhibited */
 #define	_PAGE_WRITETHRU	0x008	/* W: caching is write-through */
diff --git a/arch/powerpc/include/asm/pte-44x.h b/arch/powerpc/include/asm/pte-44x.h
index 4192b9b..36f75fa 100644
--- a/arch/powerpc/include/asm/pte-44x.h
+++ b/arch/powerpc/include/asm/pte-44x.h
@@ -44,9 +44,6 @@
  *   - PRESENT *must* be in the bottom three bits because swap cache
  *     entries use the top 29 bits for TLB2.
  *
- *   - FILE *must* be in the bottom three bits because swap cache
- *     entries use the top 29 bits for TLB2.
- *
  *   - CACHE COHERENT bit (M) has no effect on original PPC440 cores,
  *     because it doesn't support SMP. However, some later 460 variants
  *     have -some- form of SMP support and so I keep the bit there for
@@ -68,7 +65,6 @@
  *
  * There are three protection bits available for SWAP entry:
  *	_PAGE_PRESENT
- *	_PAGE_FILE
  *	_PAGE_HASHPTE (if HW has)
  *
  * So those three bits have to be inside of 0-2nd LSB of PTE.
@@ -77,7 +73,6 @@
 
 #define _PAGE_PRESENT	0x00000001		/* S: PTE valid */
 #define _PAGE_RW	0x00000002		/* S: Write permission */
-#define _PAGE_FILE	0x00000004		/* S: nonlinear file mapping */
 #define _PAGE_EXEC	0x00000004		/* H: Execute permission */
 #define _PAGE_ACCESSED	0x00000008		/* S: Page referenced */
 #define _PAGE_DIRTY	0x00000010		/* S: Page dirty */
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h
index eb6edb4..97bae64 100644
--- a/arch/powerpc/include/asm/pte-8xx.h
+++ b/arch/powerpc/include/asm/pte-8xx.h
@@ -29,7 +29,6 @@
 
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT	0x0001	/* Page is valid */
-#define _PAGE_FILE	0x0002	/* when !present: nonlinear file mapping */
 #define _PAGE_NO_CACHE	0x0002	/* I: cache inhibit */
 #define _PAGE_SHARED	0x0004	/* No ASID (context) compare */
 #define _PAGE_SPECIAL	0x0008	/* SW entry, forced to 0 by the TLB miss */
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
index 576ad88..91a7049 100644
--- a/arch/powerpc/include/asm/pte-book3e.h
+++ b/arch/powerpc/include/asm/pte-book3e.h
@@ -10,7 +10,6 @@
 
 /* Architected bits */
 #define _PAGE_PRESENT	0x000001 /* software: pte contains a translation */
-#define _PAGE_FILE	0x000002 /* (!present only) software: pte holds file offset */
 #define _PAGE_SW1	0x000002
 #define _PAGE_BAP_SR	0x000004
 #define _PAGE_BAP_UR	0x000008
diff --git a/arch/powerpc/include/asm/pte-fsl-booke.h b/arch/powerpc/include/asm/pte-fsl-booke.h
index e84dd7e..9f5c3d0 100644
--- a/arch/powerpc/include/asm/pte-fsl-booke.h
+++ b/arch/powerpc/include/asm/pte-fsl-booke.h
@@ -13,14 +13,11 @@
    - PRESENT *must* be in the bottom three bits because swap cache
      entries use the top 29 bits.
 
-   - FILE *must* be in the bottom three bits because swap cache
-     entries use the top 29 bits.
 */
 
 /* Definitions for FSL Book-E Cores */
 #define _PAGE_PRESENT	0x00001	/* S: PTE contains a translation */
 #define _PAGE_USER	0x00002	/* S: User page (maps to UR) */
-#define _PAGE_FILE	0x00002	/* S: when !present: nonlinear file mapping */
 #define _PAGE_RW	0x00004	/* S: Write permission (SW) */
 #define _PAGE_DIRTY	0x00008	/* S: Page dirty */
 #define _PAGE_EXEC	0x00010	/* H: SX permission */
diff --git a/arch/powerpc/include/asm/pte-hash32.h b/arch/powerpc/include/asm/pte-hash32.h
index 4aad413..62cfb0c 100644
--- a/arch/powerpc/include/asm/pte-hash32.h
+++ b/arch/powerpc/include/asm/pte-hash32.h
@@ -18,7 +18,6 @@
 
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
 #define _PAGE_HASHPTE	0x002	/* hash_page has made an HPTE for this pte */
-#define _PAGE_FILE	0x004	/* when !present: nonlinear file mapping */
 #define _PAGE_USER	0x004	/* usermode access allowed */
 #define _PAGE_GUARDED	0x008	/* G: prohibit speculative access */
 #define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
diff --git a/arch/powerpc/include/asm/pte-hash64.h b/arch/powerpc/include/asm/pte-hash64.h
index 55aea0c..fc852f7 100644
--- a/arch/powerpc/include/asm/pte-hash64.h
+++ b/arch/powerpc/include/asm/pte-hash64.h
@@ -16,7 +16,6 @@
  */
 #define _PAGE_PRESENT		0x0001 /* software: pte contains a translation */
 #define _PAGE_USER		0x0002 /* matches one of the PP bits */
-#define _PAGE_FILE		0x0002 /* (!present only) software: pte holds file offset */
 #define _PAGE_EXEC		0x0004 /* No execute on POWER4 and newer (we invert) */
 #define _PAGE_GUARDED		0x0008
 /* We can derive Memory coherence from _PAGE_NO_CACHE */
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 40198d5..ae77b7e 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -607,19 +607,16 @@
 {
 	struct cache_index_dir *index;
 	struct cache *cache;
-	int len;
-	int n = 0;
+	int ret;
 
 	index = kobj_to_cache_index_dir(k);
 	cache = index->cache;
-	len = PAGE_SIZE - 2;
 
-	if (len > 1) {
-		n = cpumask_scnprintf(buf, len, &cache->shared_cpu_map);
-		buf[n++] = '\n';
-		buf[n] = '\0';
-	}
-	return n;
+	ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb\n",
+			cpumask_pr_args(&cache->shared_cpu_map));
+	buf[ret++] = '\n';
+	buf[ret] = '\0';
+	return ret;
 }
 
 static struct kobj_attribute cache_shared_cpu_map_attr =
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index 7b066f6..7c22997 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -152,7 +152,7 @@
 	 * in virtual mode.
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		/* Down_CPPR */
 		new_state.cppr = new_cppr;
@@ -211,7 +211,7 @@
 	 * pending priority
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		xirr = old_state.xisr | (((u32)old_state.cppr) << 24);
 		if (!old_state.xisr)
@@ -277,7 +277,7 @@
 	 * whenever the MFRR is made less favored.
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		/* Set_MFRR */
 		new_state.mfrr = mfrr;
@@ -352,7 +352,7 @@
 	icp_rm_clr_vcpu_irq(icp->vcpu);
 
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		reject = 0;
 		new_state.cppr = cppr;
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 807351f..a4a8d9f 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -327,7 +327,7 @@
 		 icp->server_num);
 
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		*reject = 0;
 
@@ -512,7 +512,7 @@
 	 * in virtual mode.
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		/* Down_CPPR */
 		new_state.cppr = new_cppr;
@@ -567,7 +567,7 @@
 	 * pending priority
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		xirr = old_state.xisr | (((u32)old_state.cppr) << 24);
 		if (!old_state.xisr)
@@ -634,7 +634,7 @@
 	 * whenever the MFRR is made less favored.
 	 */
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		/* Set_MFRR */
 		new_state.mfrr = mfrr;
@@ -679,7 +679,7 @@
 		if (!icp)
 			return H_PARAMETER;
 	}
-	state = ACCESS_ONCE(icp->state);
+	state = READ_ONCE(icp->state);
 	kvmppc_set_gpr(vcpu, 4, ((u32)state.cppr << 24) | state.xisr);
 	kvmppc_set_gpr(vcpu, 5, state.mfrr);
 	return H_SUCCESS;
@@ -721,7 +721,7 @@
 				      BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
 
 	do {
-		old_state = new_state = ACCESS_ONCE(icp->state);
+		old_state = new_state = READ_ONCE(icp->state);
 
 		reject = 0;
 		new_state.cppr = cppr;
@@ -885,7 +885,7 @@
 		if (!icp)
 			continue;
 
-		state.raw = ACCESS_ONCE(icp->state.raw);
+		state.raw = READ_ONCE(icp->state.raw);
 		seq_printf(m, "cpu server %#lx XIRR:%#x PPRI:%#x CPPR:%#x MFRR:%#x OUT:%d NR:%d\n",
 			   icp->server_num, state.xisr,
 			   state.pending_pri, state.cppr, state.mfrr,
@@ -1082,7 +1082,7 @@
 	 * the ICS states before the ICP states.
 	 */
 	do {
-		old_state = ACCESS_ONCE(icp->state);
+		old_state = READ_ONCE(icp->state);
 
 		if (new_state.mfrr <= old_state.mfrr) {
 			resend = false;
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index cf0464f..7e408bf 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -986,7 +986,7 @@
 		 */
 		pdshift = PUD_SHIFT;
 		pudp = pud_offset(&pgd, ea);
-		pud  = ACCESS_ONCE(*pudp);
+		pud  = READ_ONCE(*pudp);
 
 		if (pud_none(pud))
 			return NULL;
@@ -998,7 +998,7 @@
 		else {
 			pdshift = PMD_SHIFT;
 			pmdp = pmd_offset(&pud, ea);
-			pmd  = ACCESS_ONCE(*pmdp);
+			pmd  = READ_ONCE(*pmdp);
 			/*
 			 * A hugepage collapse is captured by pmd_none, because
 			 * it mark the pmd none and do a hpte invalidate.
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 91bb883..6957cc1 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -782,7 +782,7 @@
 {
 	pmd_t pmd;
 	/*
-	 * For a valid pte, we would have _PAGE_PRESENT or _PAGE_FILE always
+	 * For a valid pte, we would have _PAGE_PRESENT always
 	 * set. We use this to check THP page at pmd level.
 	 * leaf pte for huge page, bottom two bits != 00
 	 */
diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c
index 4ba554e..68c7e5c 100644
--- a/arch/powerpc/sysdev/xics/ics-opal.c
+++ b/arch/powerpc/sysdev/xics/ics-opal.c
@@ -131,10 +131,8 @@
 
 	wanted_server = xics_get_irq_server(d->irq, cpumask, 1);
 	if (wanted_server < 0) {
-		char cpulist[128];
-		cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
-		pr_warning("%s: No online cpus in the mask %s for irq %d\n",
-			   __func__, cpulist, d->irq);
+		pr_warning("%s: No online cpus in the mask %*pb for irq %d\n",
+			   __func__, cpumask_pr_args(cpumask), d->irq);
 		return -1;
 	}
 	server = ics_opal_mangle_server(wanted_server);
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
index bc81335b..0af97de 100644
--- a/arch/powerpc/sysdev/xics/ics-rtas.c
+++ b/arch/powerpc/sysdev/xics/ics-rtas.c
@@ -140,11 +140,8 @@
 
 	irq_server = xics_get_irq_server(d->irq, cpumask, 1);
 	if (irq_server == -1) {
-		char cpulist[128];
-		cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
-		printk(KERN_WARNING
-			"%s: No online cpus in the mask %s for irq %d\n",
-			__func__, cpulist, d->irq);
+		pr_warning("%s: No online cpus in the mask %*pb for irq %d\n",
+			   __func__, cpumask_pr_args(cpumask), d->irq);
 		return -1;
 	}
 
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 409d152..36154a2 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -50,7 +50,7 @@
 	if (PAGE_ALIGN(size) > MODULES_LEN)
 		return NULL;
 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-				    GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE,
+				    GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
 				    __builtin_return_address(0));
 }
 #endif
diff --git a/arch/sh/mm/gup.c b/arch/sh/mm/gup.c
index e15f52a..e7af6a6 100644
--- a/arch/sh/mm/gup.c
+++ b/arch/sh/mm/gup.c
@@ -17,7 +17,7 @@
 static inline pte_t gup_get_pte(pte_t *ptep)
 {
 #ifndef CONFIG_X2TLB
-	return ACCESS_ONCE(*ptep);
+	return READ_ONCE(*ptep);
 #else
 	/*
 	 * With get_user_pages_fast, we walk down the pagetables without
diff --git a/arch/sparc/crypto/aes_glue.c b/arch/sparc/crypto/aes_glue.c
index 7054087..2e48eb8 100644
--- a/arch/sparc/crypto/aes_glue.c
+++ b/arch/sparc/crypto/aes_glue.c
@@ -497,7 +497,7 @@
 module_exit(aes_sparc64_mod_fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("AES Secure Hash Algorithm, sparc64 aes opcode accelerated");
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, sparc64 aes opcode accelerated");
 
 MODULE_ALIAS_CRYPTO("aes");
 
diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c
index 641f55c..6bf2479 100644
--- a/arch/sparc/crypto/camellia_glue.c
+++ b/arch/sparc/crypto/camellia_glue.c
@@ -322,6 +322,6 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated");
 
-MODULE_ALIAS_CRYPTO("aes");
+MODULE_ALIAS_CRYPTO("camellia");
 
 #include "crop_devid.c"
diff --git a/arch/sparc/crypto/des_glue.c b/arch/sparc/crypto/des_glue.c
index d115009..dd6a34f 100644
--- a/arch/sparc/crypto/des_glue.c
+++ b/arch/sparc/crypto/des_glue.c
@@ -533,5 +533,6 @@
 MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms, sparc64 des opcode accelerated");
 
 MODULE_ALIAS_CRYPTO("des");
+MODULE_ALIAS_CRYPTO("des3_ede");
 
 #include "crop_devid.c"
diff --git a/arch/sparc/crypto/md5_glue.c b/arch/sparc/crypto/md5_glue.c
index 64c7ff5..b688731 100644
--- a/arch/sparc/crypto/md5_glue.c
+++ b/arch/sparc/crypto/md5_glue.c
@@ -183,7 +183,7 @@
 module_exit(md5_sparc64_mod_fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, sparc64 md5 opcode accelerated");
+MODULE_DESCRIPTION("MD5 Message Digest Algorithm, sparc64 md5 opcode accelerated");
 
 MODULE_ALIAS_CRYPTO("md5");
 
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
index 97655e0..192a617 100644
--- a/arch/sparc/kernel/module.c
+++ b/arch/sparc/kernel/module.c
@@ -29,7 +29,7 @@
 	if (PAGE_ALIGN(size) > MODULES_LEN)
 		return NULL;
 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-				GFP_KERNEL, PAGE_KERNEL, NUMA_NO_NODE,
+				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
 				__builtin_return_address(0));
 }
 #else
diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c
index c4646bb..2fd1694 100644
--- a/arch/tile/kernel/hardwall.c
+++ b/arch/tile/kernel/hardwall.c
@@ -909,11 +909,8 @@
 static int hardwall_proc_show(struct seq_file *sf, void *v)
 {
 	struct hardwall_info *info = sf->private;
-	char buf[256];
 
-	int rc = cpulist_scnprintf(buf, sizeof(buf), &info->cpumask);
-	buf[rc++] = '\n';
-	seq_write(sf, buf, rc);
+	seq_printf(sf, "%*pbl\n", cpumask_pr_args(&info->cpumask));
 	return 0;
 }
 
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c
index 6829a95..7983e98 100644
--- a/arch/tile/kernel/proc.c
+++ b/arch/tile/kernel/proc.c
@@ -45,10 +45,9 @@
 	int n = ptr_to_cpu(v);
 
 	if (n == 0) {
-		char buf[NR_CPUS*5];
-		cpulist_scnprintf(buf, sizeof(buf), cpu_online_mask);
 		seq_printf(m, "cpu count\t: %d\n", num_online_cpus());
-		seq_printf(m, "cpu list\t: %s\n", buf);
+		seq_printf(m, "cpu list\t: %*pbl\n",
+			   cpumask_pr_args(cpu_online_mask));
 		seq_printf(m, "model name\t: %s\n", chip_model);
 		seq_printf(m, "flags\t\t:\n");  /* nothing for now */
 		seq_printf(m, "cpu MHz\t\t: %llu.%06llu\n",
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 864eea6..f1f5799 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -215,12 +215,11 @@
 
 static int __init setup_isolnodes(char *str)
 {
-	char buf[MAX_NUMNODES * 5];
 	if (str == NULL || nodelist_parse(str, isolnodes) != 0)
 		return -EINVAL;
 
-	nodelist_scnprintf(buf, sizeof(buf), isolnodes);
-	pr_info("Set isolnodes value to '%s'\n", buf);
+	pr_info("Set isolnodes value to '%*pbl'\n",
+		nodemask_pr_args(&isolnodes));
 	return 0;
 }
 early_param("isolnodes", setup_isolnodes);
@@ -1315,11 +1314,9 @@
 
 void __init print_disabled_cpus(void)
 {
-	if (!cpumask_empty(&disabled_map)) {
-		char buf[100];
-		cpulist_scnprintf(buf, sizeof(buf), &disabled_map);
-		pr_info("CPUs not available for Linux: %s\n", buf);
-	}
+	if (!cpumask_empty(&disabled_map))
+		pr_info("CPUs not available for Linux: %*pbl\n",
+			cpumask_pr_args(&disabled_map));
 }
 
 static void __init setup_cpu_maps(void)
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index 0029b3f..40ca30a 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
@@ -115,7 +115,6 @@
 	struct cpumask cache_cpumask_copy, tlb_cpumask_copy;
 	struct cpumask *cache_cpumask, *tlb_cpumask;
 	HV_PhysAddr cache_pa;
-	char cache_buf[NR_CPUS*5], tlb_buf[NR_CPUS*5];
 
 	mb();   /* provided just to simplify "magic hypervisor" mode */
 
@@ -149,13 +148,12 @@
 			     asids, asidcount);
 	if (rc == 0)
 		return;
-	cpumask_scnprintf(cache_buf, sizeof(cache_buf), &cache_cpumask_copy);
-	cpumask_scnprintf(tlb_buf, sizeof(tlb_buf), &tlb_cpumask_copy);
 
-	pr_err("hv_flush_remote(%#llx, %#lx, %p [%s], %#lx, %#lx, %#lx, %p [%s], %p, %d) = %d\n",
-	       cache_pa, cache_control, cache_cpumask, cache_buf,
-	       (unsigned long)tlb_va, tlb_length, tlb_pgsize,
-	       tlb_cpumask, tlb_buf, asids, asidcount, rc);
+	pr_err("hv_flush_remote(%#llx, %#lx, %p [%*pb], %#lx, %#lx, %#lx, %p [%*pb], %p, %d) = %d\n",
+	       cache_pa, cache_control, cache_cpumask,
+	       cpumask_pr_args(&cache_cpumask_copy),
+	       (unsigned long)tlb_va, tlb_length, tlb_pgsize, tlb_cpumask,
+	       cpumask_pr_args(&tlb_cpumask_copy), asids, asidcount, rc);
 	panic("Unsafe to continue.");
 }
 
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index be240cc..ace32d7 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -353,15 +353,13 @@
 
 	/* Neighborhood ktext pages on specified mask */
 	else if (cpulist_parse(str, &ktext_mask) == 0) {
-		char buf[NR_CPUS * 5];
-		cpulist_scnprintf(buf, sizeof(buf), &ktext_mask);
 		if (cpumask_weight(&ktext_mask) > 1) {
 			ktext_small = 1;
-			pr_info("ktext: using caching neighborhood %s with small pages\n",
-				buf);
+			pr_info("ktext: using caching neighborhood %*pbl with small pages\n",
+				cpumask_pr_args(&ktext_mask));
 		} else {
-			pr_info("ktext: caching on cpu %s with one huge page\n",
-				buf);
+			pr_info("ktext: caching on cpu %*pbl with one huge page\n",
+				cpumask_pr_args(&ktext_mask));
 		}
 	}
 
@@ -492,11 +490,9 @@
 		struct cpumask bad;
 		cpumask_andnot(&bad, &ktext_mask, cpu_possible_mask);
 		cpumask_and(&ktext_mask, &ktext_mask, cpu_possible_mask);
-		if (!cpumask_empty(&bad)) {
-			char buf[NR_CPUS * 5];
-			cpulist_scnprintf(buf, sizeof(buf), &bad);
-			pr_info("ktext: not using unavailable cpus %s\n", buf);
-		}
+		if (!cpumask_empty(&bad))
+			pr_info("ktext: not using unavailable cpus %*pbl\n",
+				cpumask_pr_args(&bad));
 		if (cpumask_empty(&ktext_mask)) {
 			pr_warn("ktext: no valid cpus; caching on %d\n",
 				smp_processor_id());
diff --git a/arch/unicore32/kernel/module.c b/arch/unicore32/kernel/module.c
index dc41f6d..e191b34 100644
--- a/arch/unicore32/kernel/module.c
+++ b/arch/unicore32/kernel/module.c
@@ -25,7 +25,7 @@
 void *module_alloc(unsigned long size)
 {
 	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
-				GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+				GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
 				__builtin_return_address(0));
 }
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 33ce9a3..eb1cf89 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -85,6 +85,7 @@
 	select HAVE_CMPXCHG_LOCAL
 	select HAVE_CMPXCHG_DOUBLE
 	select HAVE_ARCH_KMEMCHECK
+	select HAVE_ARCH_KASAN if X86_64 && SPARSEMEM_VMEMMAP
 	select HAVE_USER_RETURN_NOTIFIER
 	select ARCH_BINFMT_ELF_RANDOMIZE_PIE
 	select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 3db07f3..57bbf2f 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -14,6 +14,8 @@
 # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
 # The number is the same as you would ordinarily press at bootup.
 
+KASAN_SANITIZE := n
+
 SVGA_MODE	:= -DSVGA_MODE=NORMAL_VGA
 
 targets		:= vmlinux.bin setup.bin setup.elf bzImage
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index ad754b4..843feb3 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -16,6 +16,8 @@
 #	(see scripts/Makefile.lib size_append)
 #	compressed vmlinux.bin.all + u32 size of vmlinux.bin.all
 
+KASAN_SANITIZE := n
+
 targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
 	vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
 
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 92b9a5f..ef17683 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -13,8 +13,7 @@
 #include <asm/setup.h>
 #include <asm/desc.h>
 
-#undef memcpy			/* Use memcpy from misc.c */
-
+#include "../string.h"
 #include "eboot.h"
 
 static efi_system_table_t *sys_table;
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 24e3e56..04477d6 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -7,6 +7,7 @@
  * we just keep it from happening
  */
 #undef CONFIG_PARAVIRT
+#undef CONFIG_KASAN
 #ifdef CONFIG_X86_32
 #define _ASM_X86_DESC_H 1
 #endif
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
index 477e9d7..6bd2c6c 100644
--- a/arch/x86/crypto/aesni-intel_asm.S
+++ b/arch/x86/crypto/aesni-intel_asm.S
@@ -32,12 +32,23 @@
 #include <linux/linkage.h>
 #include <asm/inst.h>
 
+/*
+ * The following macros are used to move an (un)aligned 16 byte value to/from
+ * an XMM register.  This can done for either FP or integer values, for FP use
+ * movaps (move aligned packed single) or integer use movdqa (move double quad
+ * aligned).  It doesn't make a performance difference which instruction is used
+ * since Nehalem (original Core i7) was released.  However, the movaps is a byte
+ * shorter, so that is the one we'll use for now. (same for unaligned).
+ */
+#define MOVADQ	movaps
+#define MOVUDQ	movups
+
 #ifdef __x86_64__
+
 .data
 .align 16
 .Lgf128mul_x_ble_mask:
 	.octa 0x00000000000000010000000000000087
-
 POLY:   .octa 0xC2000000000000000000000000000001
 TWOONE: .octa 0x00000001000000000000000000000001
 
@@ -89,6 +100,7 @@
 #define arg8 STACK_OFFSET+16(%r14)
 #define arg9 STACK_OFFSET+24(%r14)
 #define arg10 STACK_OFFSET+32(%r14)
+#define keysize 2*15*16(%arg1)
 #endif
 
 
@@ -213,10 +225,12 @@
 
 .macro INITIAL_BLOCKS_DEC num_initial_blocks TMP1 TMP2 TMP3 TMP4 TMP5 XMM0 XMM1 \
 XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation
+        MOVADQ     SHUF_MASK(%rip), %xmm14
 	mov	   arg7, %r10           # %r10 = AAD
 	mov	   arg8, %r12           # %r12 = aadLen
 	mov	   %r12, %r11
 	pxor	   %xmm\i, %xmm\i
+
 _get_AAD_loop\num_initial_blocks\operation:
 	movd	   (%r10), \TMP1
 	pslldq	   $12, \TMP1
@@ -225,16 +239,18 @@
 	add	   $4, %r10
 	sub	   $4, %r12
 	jne	   _get_AAD_loop\num_initial_blocks\operation
+
 	cmp	   $16, %r11
 	je	   _get_AAD_loop2_done\num_initial_blocks\operation
+
 	mov	   $16, %r12
 _get_AAD_loop2\num_initial_blocks\operation:
 	psrldq	   $4, %xmm\i
 	sub	   $4, %r12
 	cmp	   %r11, %r12
 	jne	   _get_AAD_loop2\num_initial_blocks\operation
+
 _get_AAD_loop2_done\num_initial_blocks\operation:
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM   %xmm14, %xmm\i # byte-reflect the AAD data
 
 	xor	   %r11, %r11 # initialise the data pointer offset as zero
@@ -243,59 +259,34 @@
 
 	mov	   %arg5, %rax                      # %rax = *Y0
 	movdqu	   (%rax), \XMM0                    # XMM0 = Y0
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM   %xmm14, \XMM0
 
 .if (\i == 5) || (\i == 6) || (\i == 7)
+	MOVADQ		ONE(%RIP),\TMP1
+	MOVADQ		(%arg1),\TMP2
 .irpc index, \i_seq
-	paddd	   ONE(%rip), \XMM0                 # INCR Y0
+	paddd	   \TMP1, \XMM0                 # INCR Y0
 	movdqa	   \XMM0, %xmm\index
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM   %xmm14, %xmm\index      # perform a 16 byte swap
+	pxor	   \TMP2, %xmm\index
+.endr
+	lea	0x10(%arg1),%r10
+	mov	keysize,%eax
+	shr	$2,%eax				# 128->4, 192->6, 256->8
+	add	$5,%eax			      # 128->9, 192->11, 256->13
 
+aes_loop_initial_dec\num_initial_blocks:
+	MOVADQ	(%r10),\TMP1
+.irpc	index, \i_seq
+	AESENC	\TMP1, %xmm\index
 .endr
+	add	$16,%r10
+	sub	$1,%eax
+	jnz	aes_loop_initial_dec\num_initial_blocks
+
+	MOVADQ	(%r10), \TMP1
 .irpc index, \i_seq
-	pxor	   16*0(%arg1), %xmm\index
-.endr
-.irpc index, \i_seq
-	movaps 0x10(%rdi), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 1
-.endr
-.irpc index, \i_seq
-	movaps 0x20(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x30(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x40(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x50(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x60(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x70(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x80(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x90(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0xa0(%arg1), \TMP1
-	AESENCLAST \TMP1, %xmm\index         # Round 10
+	AESENCLAST \TMP1, %xmm\index         # Last Round
 .endr
 .irpc index, \i_seq
 	movdqu	   (%arg3 , %r11, 1), \TMP1
@@ -305,10 +296,8 @@
 	add	   $16, %r11
 
 	movdqa     \TMP1, %xmm\index
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM	   %xmm14, %xmm\index
-
-		# prepare plaintext/ciphertext for GHASH computation
+                # prepare plaintext/ciphertext for GHASH computation
 .endr
 .endif
 	GHASH_MUL  %xmm\i, \TMP3, \TMP1, \TMP2, \TMP4, \TMP5, \XMM1
@@ -338,30 +327,28 @@
 * Precomputations for HashKey parallel with encryption of first 4 blocks.
 * Haskey_i_k holds XORed values of the low and high parts of the Haskey_i
 */
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM1
-        movdqa     SHUF_MASK(%rip), %xmm14
+	MOVADQ	   ONE(%rip), \TMP1
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM1
 	PSHUFB_XMM  %xmm14, \XMM1        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM2
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM2
 	PSHUFB_XMM  %xmm14, \XMM2        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM3
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM3
 	PSHUFB_XMM %xmm14, \XMM3        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM4
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM4
 	PSHUFB_XMM %xmm14, \XMM4        # perform a 16 byte swap
 
-	pxor	   16*0(%arg1), \XMM1
-	pxor	   16*0(%arg1), \XMM2
-	pxor	   16*0(%arg1), \XMM3
-	pxor	   16*0(%arg1), \XMM4
+	MOVADQ	   0(%arg1),\TMP1
+	pxor	   \TMP1, \XMM1
+	pxor	   \TMP1, \XMM2
+	pxor	   \TMP1, \XMM3
+	pxor	   \TMP1, \XMM4
 	movdqa	   \TMP3, \TMP5
 	pshufd	   $78, \TMP3, \TMP1
 	pxor	   \TMP3, \TMP1
@@ -399,7 +386,23 @@
 	pshufd	   $78, \TMP5, \TMP1
 	pxor	   \TMP5, \TMP1
 	movdqa	   \TMP1, HashKey_4_k(%rsp)
-	movaps 0xa0(%arg1), \TMP2
+	lea	   0xa0(%arg1),%r10
+	mov	   keysize,%eax
+	shr	   $2,%eax			# 128->4, 192->6, 256->8
+	sub	   $4,%eax			# 128->0, 192->2, 256->4
+	jz	   aes_loop_pre_dec_done\num_initial_blocks
+
+aes_loop_pre_dec\num_initial_blocks:
+	MOVADQ	   (%r10),\TMP2
+.irpc	index, 1234
+	AESENC	   \TMP2, %xmm\index
+.endr
+	add	   $16,%r10
+	sub	   $1,%eax
+	jnz	   aes_loop_pre_dec\num_initial_blocks
+
+aes_loop_pre_dec_done\num_initial_blocks:
+	MOVADQ	   (%r10), \TMP2
 	AESENCLAST \TMP2, \XMM1
 	AESENCLAST \TMP2, \XMM2
 	AESENCLAST \TMP2, \XMM3
@@ -421,15 +424,11 @@
 	movdqu	   \XMM4, 16*3(%arg2 , %r11 , 1)
 	movdqa     \TMP1, \XMM4
 	add	   $64, %r11
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM1 # perform a 16 byte swap
 	pxor	   \XMMDst, \XMM1
 # combine GHASHed value with the corresponding ciphertext
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM2 # perform a 16 byte swap
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM3 # perform a 16 byte swap
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM4 # perform a 16 byte swap
 
 _initial_blocks_done\num_initial_blocks\operation:
@@ -451,6 +450,7 @@
 
 .macro INITIAL_BLOCKS_ENC num_initial_blocks TMP1 TMP2 TMP3 TMP4 TMP5 XMM0 XMM1 \
 XMM2 XMM3 XMM4 XMMDst TMP6 TMP7 i i_seq operation
+        MOVADQ     SHUF_MASK(%rip), %xmm14
 	mov	   arg7, %r10           # %r10 = AAD
 	mov	   arg8, %r12           # %r12 = aadLen
 	mov	   %r12, %r11
@@ -472,7 +472,6 @@
 	cmp	   %r11, %r12
 	jne	   _get_AAD_loop2\num_initial_blocks\operation
 _get_AAD_loop2_done\num_initial_blocks\operation:
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM   %xmm14, %xmm\i # byte-reflect the AAD data
 
 	xor	   %r11, %r11 # initialise the data pointer offset as zero
@@ -481,59 +480,35 @@
 
 	mov	   %arg5, %rax                      # %rax = *Y0
 	movdqu	   (%rax), \XMM0                    # XMM0 = Y0
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM   %xmm14, \XMM0
 
 .if (\i == 5) || (\i == 6) || (\i == 7)
-.irpc index, \i_seq
-	paddd	   ONE(%rip), \XMM0                 # INCR Y0
-	movdqa	   \XMM0, %xmm\index
-        movdqa     SHUF_MASK(%rip), %xmm14
-	PSHUFB_XMM   %xmm14, %xmm\index      # perform a 16 byte swap
 
-.endr
+	MOVADQ		ONE(%RIP),\TMP1
+	MOVADQ		0(%arg1),\TMP2
 .irpc index, \i_seq
-	pxor	   16*0(%arg1), %xmm\index
+	paddd		\TMP1, \XMM0                 # INCR Y0
+	MOVADQ		\XMM0, %xmm\index
+	PSHUFB_XMM	%xmm14, %xmm\index      # perform a 16 byte swap
+	pxor		\TMP2, %xmm\index
 .endr
-.irpc index, \i_seq
-	movaps 0x10(%rdi), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 1
+	lea	0x10(%arg1),%r10
+	mov	keysize,%eax
+	shr	$2,%eax				# 128->4, 192->6, 256->8
+	add	$5,%eax			      # 128->9, 192->11, 256->13
+
+aes_loop_initial_enc\num_initial_blocks:
+	MOVADQ	(%r10),\TMP1
+.irpc	index, \i_seq
+	AESENC	\TMP1, %xmm\index
 .endr
+	add	$16,%r10
+	sub	$1,%eax
+	jnz	aes_loop_initial_enc\num_initial_blocks
+
+	MOVADQ	(%r10), \TMP1
 .irpc index, \i_seq
-	movaps 0x20(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x30(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x40(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x50(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x60(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x70(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x80(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0x90(%arg1), \TMP1
-	AESENC     \TMP1, %xmm\index          # Round 2
-.endr
-.irpc index, \i_seq
-	movaps 0xa0(%arg1), \TMP1
-	AESENCLAST \TMP1, %xmm\index         # Round 10
+	AESENCLAST \TMP1, %xmm\index         # Last Round
 .endr
 .irpc index, \i_seq
 	movdqu	   (%arg3 , %r11, 1), \TMP1
@@ -541,8 +516,6 @@
 	movdqu	   %xmm\index, (%arg2 , %r11, 1)
 	# write back plaintext/ciphertext for num_initial_blocks
 	add	   $16, %r11
-
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM	   %xmm14, %xmm\index
 
 		# prepare plaintext/ciphertext for GHASH computation
@@ -575,30 +548,28 @@
 * Precomputations for HashKey parallel with encryption of first 4 blocks.
 * Haskey_i_k holds XORed values of the low and high parts of the Haskey_i
 */
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM1
-        movdqa     SHUF_MASK(%rip), %xmm14
+	MOVADQ	   ONE(%RIP),\TMP1
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM1
 	PSHUFB_XMM  %xmm14, \XMM1        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM2
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM2
 	PSHUFB_XMM  %xmm14, \XMM2        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM3
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM3
 	PSHUFB_XMM %xmm14, \XMM3        # perform a 16 byte swap
 
-	paddd	   ONE(%rip), \XMM0              # INCR Y0
-	movdqa	   \XMM0, \XMM4
-        movdqa     SHUF_MASK(%rip), %xmm14
+	paddd	   \TMP1, \XMM0              # INCR Y0
+	MOVADQ	   \XMM0, \XMM4
 	PSHUFB_XMM %xmm14, \XMM4        # perform a 16 byte swap
 
-	pxor	   16*0(%arg1), \XMM1
-	pxor	   16*0(%arg1), \XMM2
-	pxor	   16*0(%arg1), \XMM3
-	pxor	   16*0(%arg1), \XMM4
+	MOVADQ	   0(%arg1),\TMP1
+	pxor	   \TMP1, \XMM1
+	pxor	   \TMP1, \XMM2
+	pxor	   \TMP1, \XMM3
+	pxor	   \TMP1, \XMM4
 	movdqa	   \TMP3, \TMP5
 	pshufd	   $78, \TMP3, \TMP1
 	pxor	   \TMP3, \TMP1
@@ -636,7 +607,23 @@
 	pshufd	   $78, \TMP5, \TMP1
 	pxor	   \TMP5, \TMP1
 	movdqa	   \TMP1, HashKey_4_k(%rsp)
-	movaps 0xa0(%arg1), \TMP2
+	lea	   0xa0(%arg1),%r10
+	mov	   keysize,%eax
+	shr	   $2,%eax			# 128->4, 192->6, 256->8
+	sub	   $4,%eax			# 128->0, 192->2, 256->4
+	jz	   aes_loop_pre_enc_done\num_initial_blocks
+
+aes_loop_pre_enc\num_initial_blocks:
+	MOVADQ	   (%r10),\TMP2
+.irpc	index, 1234
+	AESENC	   \TMP2, %xmm\index
+.endr
+	add	   $16,%r10
+	sub	   $1,%eax
+	jnz	   aes_loop_pre_enc\num_initial_blocks
+
+aes_loop_pre_enc_done\num_initial_blocks:
+	MOVADQ	   (%r10), \TMP2
 	AESENCLAST \TMP2, \XMM1
 	AESENCLAST \TMP2, \XMM2
 	AESENCLAST \TMP2, \XMM3
@@ -655,15 +642,11 @@
 	movdqu     \XMM4, 16*3(%arg2 , %r11 , 1)
 
 	add	   $64, %r11
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM1 # perform a 16 byte swap
 	pxor	   \XMMDst, \XMM1
 # combine GHASHed value with the corresponding ciphertext
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM2 # perform a 16 byte swap
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM3 # perform a 16 byte swap
-        movdqa     SHUF_MASK(%rip), %xmm14
 	PSHUFB_XMM %xmm14, \XMM4 # perform a 16 byte swap
 
 _initial_blocks_done\num_initial_blocks\operation:
@@ -794,7 +777,23 @@
 	AESENC	  \TMP3, \XMM3
 	AESENC	  \TMP3, \XMM4
 	PCLMULQDQ 0x00, \TMP5, \XMM8          # XMM8 = a0*b0
-	movaps 0xa0(%arg1), \TMP3
+	lea	  0xa0(%arg1),%r10
+	mov	  keysize,%eax
+	shr	  $2,%eax			# 128->4, 192->6, 256->8
+	sub	  $4,%eax			# 128->0, 192->2, 256->4
+	jz	  aes_loop_par_enc_done
+
+aes_loop_par_enc:
+	MOVADQ	  (%r10),\TMP3
+.irpc	index, 1234
+	AESENC	  \TMP3, %xmm\index
+.endr
+	add	  $16,%r10
+	sub	  $1,%eax
+	jnz	  aes_loop_par_enc
+
+aes_loop_par_enc_done:
+	MOVADQ	  (%r10), \TMP3
 	AESENCLAST \TMP3, \XMM1           # Round 10
 	AESENCLAST \TMP3, \XMM2
 	AESENCLAST \TMP3, \XMM3
@@ -986,8 +985,24 @@
 	AESENC	  \TMP3, \XMM3
 	AESENC	  \TMP3, \XMM4
 	PCLMULQDQ 0x00, \TMP5, \XMM8          # XMM8 = a0*b0
-	movaps 0xa0(%arg1), \TMP3
-	AESENCLAST \TMP3, \XMM1           # Round 10
+	lea	  0xa0(%arg1),%r10
+	mov	  keysize,%eax
+	shr	  $2,%eax		        # 128->4, 192->6, 256->8
+	sub	  $4,%eax			# 128->0, 192->2, 256->4
+	jz	  aes_loop_par_dec_done
+
+aes_loop_par_dec:
+	MOVADQ	  (%r10),\TMP3
+.irpc	index, 1234
+	AESENC	  \TMP3, %xmm\index
+.endr
+	add	  $16,%r10
+	sub	  $1,%eax
+	jnz	  aes_loop_par_dec
+
+aes_loop_par_dec_done:
+	MOVADQ	  (%r10), \TMP3
+	AESENCLAST \TMP3, \XMM1           # last round
 	AESENCLAST \TMP3, \XMM2
 	AESENCLAST \TMP3, \XMM3
 	AESENCLAST \TMP3, \XMM4
@@ -1155,33 +1170,29 @@
 	pxor      \TMP6, \XMMDst            # reduced result is in XMMDst
 .endm
 
-/* Encryption of a single block done*/
+
+/* Encryption of a single block
+* uses eax & r10
+*/
+
 .macro ENCRYPT_SINGLE_BLOCK XMM0 TMP1
 
-	pxor	(%arg1), \XMM0
-        movaps 16(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 32(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 48(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 64(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 80(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 96(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 112(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 128(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 144(%arg1), \TMP1
-	AESENC	\TMP1, \XMM0
-        movaps 160(%arg1), \TMP1
-	AESENCLAST	\TMP1, \XMM0
+	pxor		(%arg1), \XMM0
+	mov		keysize,%eax
+	shr		$2,%eax			# 128->4, 192->6, 256->8
+	add		$5,%eax			# 128->9, 192->11, 256->13
+	lea		16(%arg1), %r10	  # get first expanded key address
+
+_esb_loop_\@:
+	MOVADQ		(%r10),\TMP1
+	AESENC		\TMP1,\XMM0
+	add		$16,%r10
+	sub		$1,%eax
+	jnz		_esb_loop_\@
+
+	MOVADQ		(%r10),\TMP1
+	AESENCLAST	\TMP1,\XMM0
 .endm
-
-
 /*****************************************************************************
 * void aesni_gcm_dec(void *aes_ctx,    // AES Key schedule. Starts on a 16 byte boundary.
 *                   u8 *out,           // Plaintext output. Encrypt in-place is allowed.
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index ae855f4..947c6bf 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -43,6 +43,7 @@
 #include <asm/crypto/glue_helper.h>
 #endif
 
+
 /* This data is stored at the end of the crypto_tfm struct.
  * It's a type of per "session" data storage location.
  * This needs to be 16 byte aligned.
@@ -182,7 +183,8 @@
 			u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
 			u8 *auth_tag, unsigned long auth_tag_len)
 {
-	if (plaintext_len < AVX_GEN2_OPTSIZE) {
+        struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
+	if ((plaintext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)){
 		aesni_gcm_enc(ctx, out, in, plaintext_len, iv, hash_subkey, aad,
 				aad_len, auth_tag, auth_tag_len);
 	} else {
@@ -197,7 +199,8 @@
 			u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
 			u8 *auth_tag, unsigned long auth_tag_len)
 {
-	if (ciphertext_len < AVX_GEN2_OPTSIZE) {
+        struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
+	if ((ciphertext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
 		aesni_gcm_dec(ctx, out, in, ciphertext_len, iv, hash_subkey, aad,
 				aad_len, auth_tag, auth_tag_len);
 	} else {
@@ -231,7 +234,8 @@
 			u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
 			u8 *auth_tag, unsigned long auth_tag_len)
 {
-	if (plaintext_len < AVX_GEN2_OPTSIZE) {
+       struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
+	if ((plaintext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
 		aesni_gcm_enc(ctx, out, in, plaintext_len, iv, hash_subkey, aad,
 				aad_len, auth_tag, auth_tag_len);
 	} else if (plaintext_len < AVX_GEN4_OPTSIZE) {
@@ -250,7 +254,8 @@
 			u8 *hash_subkey, const u8 *aad, unsigned long aad_len,
 			u8 *auth_tag, unsigned long auth_tag_len)
 {
-	if (ciphertext_len < AVX_GEN2_OPTSIZE) {
+       struct crypto_aes_ctx *aes_ctx = (struct crypto_aes_ctx*)ctx;
+	if ((ciphertext_len < AVX_GEN2_OPTSIZE) || (aes_ctx-> key_length != AES_KEYSIZE_128)) {
 		aesni_gcm_dec(ctx, out, in, ciphertext_len, iv, hash_subkey,
 				aad, aad_len, auth_tag, auth_tag_len);
 	} else if (ciphertext_len < AVX_GEN4_OPTSIZE) {
@@ -511,7 +516,7 @@
 	kernel_fpu_begin();
 	while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
 		aesni_ctr_enc_tfm(ctx, walk.dst.virt.addr, walk.src.virt.addr,
-				  nbytes & AES_BLOCK_MASK, walk.iv);
+			              nbytes & AES_BLOCK_MASK, walk.iv);
 		nbytes &= AES_BLOCK_SIZE - 1;
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
@@ -902,7 +907,8 @@
 	}
 	/*Account for 4 byte nonce at the end.*/
 	key_len -= 4;
-	if (key_len != AES_KEYSIZE_128) {
+	if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
+	    key_len != AES_KEYSIZE_256) {
 		crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 		return -EINVAL;
 	}
@@ -1013,6 +1019,7 @@
 	__be32 counter = cpu_to_be32(1);
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
+	u32 key_len = ctx->aes_key_expanded.key_length;
 	void *aes_ctx = &(ctx->aes_key_expanded);
 	unsigned long auth_tag_len = crypto_aead_authsize(tfm);
 	u8 iv_tab[16+AESNI_ALIGN];
@@ -1027,6 +1034,13 @@
 	/* to 8 or 12 bytes */
 	if (unlikely(req->assoclen != 8 && req->assoclen != 12))
 		return -EINVAL;
+	if (unlikely(auth_tag_len != 8 && auth_tag_len != 12 && auth_tag_len != 16))
+	        return -EINVAL;
+	if (unlikely(key_len != AES_KEYSIZE_128 &&
+	             key_len != AES_KEYSIZE_192 &&
+	             key_len != AES_KEYSIZE_256))
+	        return -EINVAL;
+
 	/* IV below built */
 	for (i = 0; i < 4; i++)
 		*(iv+i) = ctx->nonce[i];
@@ -1091,6 +1105,7 @@
 	int retval = 0;
 	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
 	struct aesni_rfc4106_gcm_ctx *ctx = aesni_rfc4106_gcm_ctx_get(tfm);
+	u32 key_len = ctx->aes_key_expanded.key_length;
 	void *aes_ctx = &(ctx->aes_key_expanded);
 	unsigned long auth_tag_len = crypto_aead_authsize(tfm);
 	u8 iv_and_authTag[32+AESNI_ALIGN];
@@ -1104,6 +1119,13 @@
 	if (unlikely((req->cryptlen < auth_tag_len) ||
 		(req->assoclen != 8 && req->assoclen != 12)))
 		return -EINVAL;
+	if (unlikely(auth_tag_len != 8 && auth_tag_len != 12 && auth_tag_len != 16))
+	        return -EINVAL;
+	if (unlikely(key_len != AES_KEYSIZE_128 &&
+	             key_len != AES_KEYSIZE_192 &&
+	             key_len != AES_KEYSIZE_256))
+	        return -EINVAL;
+
 	/* Assuming we are supporting rfc4106 64-bit extended */
 	/* sequence numbers We need to have the AAD length */
 	/* equal to 8 or 12 bytes */
diff --git a/arch/x86/crypto/des3_ede_glue.c b/arch/x86/crypto/des3_ede_glue.c
index 38a14f8..d6fc59a 100644
--- a/arch/x86/crypto/des3_ede_glue.c
+++ b/arch/x86/crypto/des3_ede_glue.c
@@ -504,6 +504,4 @@
 MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized");
 MODULE_ALIAS_CRYPTO("des3_ede");
 MODULE_ALIAS_CRYPTO("des3_ede-asm");
-MODULE_ALIAS_CRYPTO("des");
-MODULE_ALIAS_CRYPTO("des-asm");
 MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>");
diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h
index e34e097..705d357 100644
--- a/arch/x86/include/asm/intel-mid.h
+++ b/arch/x86/include/asm/intel-mid.h
@@ -136,9 +136,6 @@
 #define SFI_MTMR_MAX_NUM 8
 #define SFI_MRTC_MAX	8
 
-extern struct console early_mrst_console;
-extern void mrst_early_console_init(void);
-
 extern struct console early_hsu_console;
 extern void hsu_early_console_init(const char *);
 
diff --git a/arch/x86/include/asm/kasan.h b/arch/x86/include/asm/kasan.h
new file mode 100644
index 0000000..8b22422
--- /dev/null
+++ b/arch/x86/include/asm/kasan.h
@@ -0,0 +1,31 @@
+#ifndef _ASM_X86_KASAN_H
+#define _ASM_X86_KASAN_H
+
+/*
+ * Compiler uses shadow offset assuming that addresses start
+ * from 0. Kernel addresses don't start from 0, so shadow
+ * for kernel really starts from compiler's shadow offset +
+ * 'kernel address space start' >> KASAN_SHADOW_SCALE_SHIFT
+ */
+#define KASAN_SHADOW_START      (KASAN_SHADOW_OFFSET + \
+					(0xffff800000000000ULL >> 3))
+/* 47 bits for kernel address -> (47 - 3) bits for shadow */
+#define KASAN_SHADOW_END        (KASAN_SHADOW_START + (1ULL << (47 - 3)))
+
+#ifndef __ASSEMBLY__
+
+extern pte_t kasan_zero_pte[];
+extern pte_t kasan_zero_pmd[];
+extern pte_t kasan_zero_pud[];
+
+#ifdef CONFIG_KASAN
+void __init kasan_map_early_shadow(pgd_t *pgd);
+void __init kasan_init(void);
+#else
+static inline void kasan_map_early_shadow(pgd_t *pgd) { }
+static inline void kasan_init(void) { }
+#endif
+
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h
index 876e74e..09b9620 100644
--- a/arch/x86/include/asm/mmu.h
+++ b/arch/x86/include/asm/mmu.h
@@ -19,6 +19,8 @@
 
 	struct mutex lock;
 	void __user *vdso;
+
+	atomic_t perf_rdpmc_allowed;	/* nonzero if rdpmc is allowed */
 } mm_context_t;
 
 #ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 4b75d59..883f6b9 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -18,6 +18,21 @@
 }
 #endif	/* !CONFIG_PARAVIRT */
 
+#ifdef CONFIG_PERF_EVENTS
+extern struct static_key rdpmc_always_available;
+
+static inline void load_mm_cr4(struct mm_struct *mm)
+{
+	if (static_key_true(&rdpmc_always_available) ||
+	    atomic_read(&mm->context.perf_rdpmc_allowed))
+		cr4_set_bits(X86_CR4_PCE);
+	else
+		cr4_clear_bits(X86_CR4_PCE);
+}
+#else
+static inline void load_mm_cr4(struct mm_struct *mm) {}
+#endif
+
 /*
  * Used for LDT copy/destruction.
  */
@@ -52,15 +67,20 @@
 		/* Stop flush ipis for the previous mm */
 		cpumask_clear_cpu(cpu, mm_cpumask(prev));
 
+		/* Load per-mm CR4 state */
+		load_mm_cr4(next);
+
 		/*
 		 * Load the LDT, if the LDT is different.
 		 *
-		 * It's possible leave_mm(prev) has been called.  If so,
-		 * then prev->context.ldt could be out of sync with the
-		 * LDT descriptor or the LDT register.  This can only happen
-		 * if prev->context.ldt is non-null, since we never free
-		 * an LDT.  But LDTs can't be shared across mms, so
-		 * prev->context.ldt won't be equal to next->context.ldt.
+		 * It's possible that prev->context.ldt doesn't match
+		 * the LDT register.  This can happen if leave_mm(prev)
+		 * was called and then modify_ldt changed
+		 * prev->context.ldt but suppressed an IPI to this CPU.
+		 * In this case, prev->context.ldt != NULL, because we
+		 * never free an LDT while the mm still exists.  That
+		 * means that next->context.ldt != prev->context.ldt,
+		 * because mms never share an LDT.
 		 */
 		if (unlikely(prev->context.ldt != next->context.ldt))
 			load_LDT_nolock(&next->context);
@@ -85,6 +105,7 @@
 			 */
 			load_cr3(next->pgd);
 			trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
+			load_mm_cr4(next);
 			load_LDT_nolock(&next->context);
 		}
 	}
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 75450b2..4edd53b 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -1,17 +1,23 @@
 #ifndef _ASM_X86_PAGE_64_DEFS_H
 #define _ASM_X86_PAGE_64_DEFS_H
 
-#define THREAD_SIZE_ORDER	2
+#ifdef CONFIG_KASAN
+#define KASAN_STACK_ORDER 1
+#else
+#define KASAN_STACK_ORDER 0
+#endif
+
+#define THREAD_SIZE_ORDER	(2 + KASAN_STACK_ORDER)
 #define THREAD_SIZE  (PAGE_SIZE << THREAD_SIZE_ORDER)
 #define CURRENT_MASK (~(THREAD_SIZE - 1))
 
-#define EXCEPTION_STACK_ORDER 0
+#define EXCEPTION_STACK_ORDER (0 + KASAN_STACK_ORDER)
 #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER)
 
 #define DEBUG_STACK_ORDER (EXCEPTION_STACK_ORDER + 1)
 #define DEBUG_STKSZ (PAGE_SIZE << DEBUG_STACK_ORDER)
 
-#define IRQ_STACK_ORDER 2
+#define IRQ_STACK_ORDER (2 + KASAN_STACK_ORDER)
 #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
 
 #define DOUBLEFAULT_STACK 1
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 32444ae..965c47d 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -80,16 +80,16 @@
 	PVOP_VCALL1(pv_mmu_ops.write_cr3, x);
 }
 
-static inline unsigned long read_cr4(void)
+static inline unsigned long __read_cr4(void)
 {
 	return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4);
 }
-static inline unsigned long read_cr4_safe(void)
+static inline unsigned long __read_cr4_safe(void)
 {
 	return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr4_safe);
 }
 
-static inline void write_cr4(unsigned long x)
+static inline void __write_cr4(unsigned long x)
 {
 	PVOP_VCALL1(pv_cpu_ops.write_cr4, x);
 }
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index a092a0c..ec1c935 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -579,39 +579,6 @@
 #define set_iopl_mask native_set_iopl_mask
 #endif /* CONFIG_PARAVIRT */
 
-/*
- * Save the cr4 feature set we're using (ie
- * Pentium 4MB enable and PPro Global page
- * enable), so that any CPU's that boot up
- * after us can get the correct flags.
- */
-extern unsigned long mmu_cr4_features;
-extern u32 *trampoline_cr4_features;
-
-static inline void set_in_cr4(unsigned long mask)
-{
-	unsigned long cr4;
-
-	mmu_cr4_features |= mask;
-	if (trampoline_cr4_features)
-		*trampoline_cr4_features = mmu_cr4_features;
-	cr4 = read_cr4();
-	cr4 |= mask;
-	write_cr4(cr4);
-}
-
-static inline void clear_in_cr4(unsigned long mask)
-{
-	unsigned long cr4;
-
-	mmu_cr4_features &= ~mask;
-	if (trampoline_cr4_features)
-		*trampoline_cr4_features = mmu_cr4_features;
-	cr4 = read_cr4();
-	cr4 &= ~mask;
-	write_cr4(cr4);
-}
-
 typedef struct {
 	unsigned long		seg;
 } mm_segment_t;
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index e820c08..6a4b00f 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -137,17 +137,17 @@
 	native_write_cr3(x);
 }
 
-static inline unsigned long read_cr4(void)
+static inline unsigned long __read_cr4(void)
 {
 	return native_read_cr4();
 }
 
-static inline unsigned long read_cr4_safe(void)
+static inline unsigned long __read_cr4_safe(void)
 {
 	return native_read_cr4_safe();
 }
 
-static inline void write_cr4(unsigned long x)
+static inline void __write_cr4(unsigned long x)
 {
 	native_write_cr4(x);
 }
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 625660f..7050d86 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -183,10 +183,10 @@
 
 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
 {
-	__ticket_t head = ACCESS_ONCE(lock->tickets.head);
+	__ticket_t head = READ_ONCE(lock->tickets.head);
 
 	for (;;) {
-		struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
+		struct __raw_tickets tmp = READ_ONCE(lock->tickets);
 		/*
 		 * We need to check "unlocked" in a loop, tmp.head == head
 		 * can be false positive because of overflow.
diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h
index 19e2c46..e466119 100644
--- a/arch/x86/include/asm/string_64.h
+++ b/arch/x86/include/asm/string_64.h
@@ -27,11 +27,12 @@
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
+extern void *__memcpy(void *to, const void *from, size_t len);
+
 #ifndef CONFIG_KMEMCHECK
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
 extern void *memcpy(void *to, const void *from, size_t len);
 #else
-extern void *__memcpy(void *to, const void *from, size_t len);
 #define memcpy(dst, src, len)					\
 ({								\
 	size_t __len = (len);					\
@@ -53,9 +54,11 @@
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
+void *__memset(void *s, int c, size_t n);
 
 #define __HAVE_ARCH_MEMMOVE
 void *memmove(void *dest, const void *src, size_t count);
+void *__memmove(void *dest, const void *src, size_t count);
 
 int memcmp(const void *cs, const void *ct, size_t count);
 size_t strlen(const char *s);
@@ -63,6 +66,19 @@
 char *strcat(char *dest, const char *src);
 int strcmp(const char *cs, const char *ct);
 
+#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
+
+/*
+ * For files that not instrumented (e.g. mm/slub.c) we
+ * should use not instrumented version of mem* functions.
+ */
+
+#undef memcpy
+#define memcpy(dst, src, len) __memcpy(dst, src, len)
+#define memmove(dst, src, len) __memmove(dst, src, len)
+#define memset(s, c, n) __memset(s, c, n)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_STRING_64_H */
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index 04905bf..cd79194 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -15,6 +15,75 @@
 #define __flush_tlb_single(addr) __native_flush_tlb_single(addr)
 #endif
 
+struct tlb_state {
+#ifdef CONFIG_SMP
+	struct mm_struct *active_mm;
+	int state;
+#endif
+
+	/*
+	 * Access to this CR4 shadow and to H/W CR4 is protected by
+	 * disabling interrupts when modifying either one.
+	 */
+	unsigned long cr4;
+};
+DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
+
+/* Initialize cr4 shadow for this CPU. */
+static inline void cr4_init_shadow(void)
+{
+	this_cpu_write(cpu_tlbstate.cr4, __read_cr4());
+}
+
+/* Set in this cpu's CR4. */
+static inline void cr4_set_bits(unsigned long mask)
+{
+	unsigned long cr4;
+
+	cr4 = this_cpu_read(cpu_tlbstate.cr4);
+	if ((cr4 | mask) != cr4) {
+		cr4 |= mask;
+		this_cpu_write(cpu_tlbstate.cr4, cr4);
+		__write_cr4(cr4);
+	}
+}
+
+/* Clear in this cpu's CR4. */
+static inline void cr4_clear_bits(unsigned long mask)
+{
+	unsigned long cr4;
+
+	cr4 = this_cpu_read(cpu_tlbstate.cr4);
+	if ((cr4 & ~mask) != cr4) {
+		cr4 &= ~mask;
+		this_cpu_write(cpu_tlbstate.cr4, cr4);
+		__write_cr4(cr4);
+	}
+}
+
+/* Read the CR4 shadow. */
+static inline unsigned long cr4_read_shadow(void)
+{
+	return this_cpu_read(cpu_tlbstate.cr4);
+}
+
+/*
+ * Save some of cr4 feature set we're using (e.g.  Pentium 4MB
+ * enable and PPro Global page enable), so that any CPU's that boot
+ * up after us can get the correct flags.  This should only be used
+ * during boot on the boot cpu.
+ */
+extern unsigned long mmu_cr4_features;
+extern u32 *trampoline_cr4_features;
+
+static inline void cr4_set_bits_and_update_boot(unsigned long mask)
+{
+	mmu_cr4_features |= mask;
+	if (trampoline_cr4_features)
+		*trampoline_cr4_features = mmu_cr4_features;
+	cr4_set_bits(mask);
+}
+
 static inline void __native_flush_tlb(void)
 {
 	native_write_cr3(native_read_cr3());
@@ -24,7 +93,7 @@
 {
 	unsigned long cr4;
 
-	cr4 = native_read_cr4();
+	cr4 = this_cpu_read(cpu_tlbstate.cr4);
 	/* clear PGE */
 	native_write_cr4(cr4 & ~X86_CR4_PGE);
 	/* write old PGE again and flush TLBs */
@@ -184,12 +253,6 @@
 #define TLBSTATE_OK	1
 #define TLBSTATE_LAZY	2
 
-struct tlb_state {
-	struct mm_struct *active_mm;
-	int state;
-};
-DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
-
 static inline void reset_lazy_tlbstate(void)
 {
 	this_cpu_write(cpu_tlbstate.state, 0);
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 5da71c2..cce9ee6 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -19,6 +19,7 @@
 
 #include <asm/vmx.h>
 #include <asm/svm.h>
+#include <asm/tlbflush.h>
 
 /*
  * VMX functions:
@@ -40,12 +41,12 @@
 static inline void cpu_vmxoff(void)
 {
 	asm volatile (ASM_VMX_VMXOFF : : : "cc");
-	write_cr4(read_cr4() & ~X86_CR4_VMXE);
+	cr4_clear_bits(X86_CR4_VMXE);
 }
 
 static inline int cpu_vmx_enabled(void)
 {
-	return read_cr4() & X86_CR4_VMXE;
+	return __read_cr4() & X86_CR4_VMXE;
 }
 
 /** Disable VMX if it is enabled on the current CPU
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 462efe7..90c458e 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -187,6 +187,17 @@
 #define HV_X64_MSR_SINT14			0x4000009E
 #define HV_X64_MSR_SINT15			0x4000009F
 
+/*
+ * Synthetic Timer MSRs. Four timers per vcpu.
+ */
+#define HV_X64_MSR_STIMER0_CONFIG		0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT		0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG		0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT		0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG		0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT		0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG		0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT		0x400000B7
 
 #define HV_X64_MSR_HYPERCALL_ENABLE		0x00000001
 #define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT	12
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7322234..cdb1b70 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -16,6 +16,10 @@
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
+KASAN_SANITIZE_head$(BITS).o := n
+KASAN_SANITIZE_dumpstack.o := n
+KASAN_SANITIZE_dumpstack_$(BITS).o := n
+
 CFLAGS_irq.o := -I$(src)/../include/asm/trace
 
 obj-y			:= process_$(BITS).o signal.o entry_$(BITS).o
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 3136820..d1daead 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -78,7 +78,7 @@
 
 	header->pmode_cr0 = read_cr0();
 	if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
-		header->pmode_cr4 = read_cr4();
+		header->pmode_cr4 = __read_cr4();
 		header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
 	}
 	if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index b15bffc..b5c8ff5 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -19,6 +19,7 @@
 #include <asm/archrandom.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
+#include <asm/tlbflush.h>
 #include <asm/debugreg.h>
 #include <asm/sections.h>
 #include <asm/vsyscall.h>
@@ -278,7 +279,7 @@
 static __always_inline void setup_smep(struct cpuinfo_x86 *c)
 {
 	if (cpu_has(c, X86_FEATURE_SMEP))
-		set_in_cr4(X86_CR4_SMEP);
+		cr4_set_bits(X86_CR4_SMEP);
 }
 
 static __init int setup_disable_smap(char *arg)
@@ -298,9 +299,9 @@
 
 	if (cpu_has(c, X86_FEATURE_SMAP)) {
 #ifdef CONFIG_X86_SMAP
-		set_in_cr4(X86_CR4_SMAP);
+		cr4_set_bits(X86_CR4_SMAP);
 #else
-		clear_in_cr4(X86_CR4_SMAP);
+		cr4_clear_bits(X86_CR4_SMAP);
 #endif
 	}
 }
@@ -1295,6 +1296,12 @@
 	wait_for_master_cpu(cpu);
 
 	/*
+	 * Initialize the CR4 shadow before doing anything that could
+	 * try to read it.
+	 */
+	cr4_init_shadow();
+
+	/*
 	 * Load microcode on this cpu if a valid microcode is available.
 	 * This is early microcode loading procedure.
 	 */
@@ -1313,7 +1320,7 @@
 
 	pr_debug("Initializing CPU#%d\n", cpu);
 
-	clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+	cr4_clear_bits(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
 	/*
 	 * Initialize the per-CPU GDT with the boot GDT,
@@ -1394,7 +1401,7 @@
 	printk(KERN_INFO "Initializing CPU#%d\n", cpu);
 
 	if (cpu_feature_enabled(X86_FEATURE_VME) || cpu_has_tsc || cpu_has_de)
-		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+		cr4_clear_bits(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
 	load_current_idt();
 	switch_to_new_gdt(cpu);
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index c703507..6596433 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -952,20 +952,18 @@
 static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
 					int type, char *buf)
 {
-	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
-	int n = 0;
+	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map);
+	int ret;
 
-	if (len > 1) {
-		const struct cpumask *mask;
-
-		mask = to_cpumask(this_leaf->shared_cpu_map);
-		n = type ?
-			cpulist_scnprintf(buf, len-2, mask) :
-			cpumask_scnprintf(buf, len-2, mask);
-		buf[n++] = '\n';
-		buf[n] = '\0';
-	}
-	return n;
+	if (type)
+		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+				cpumask_pr_args(mask));
+	else
+		ret = scnprintf(buf, PAGE_SIZE - 1, "%*pb",
+				cpumask_pr_args(mask));
+	buf[ret++] = '\n';
+	buf[ret] = '\0';
+	return ret;
 }
 
 static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index cdfed79..3be9fa6 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -44,6 +44,7 @@
 
 #include <asm/processor.h>
 #include <asm/traps.h>
+#include <asm/tlbflush.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
 
@@ -1452,7 +1453,7 @@
 	bitmap_fill(all_banks, MAX_NR_BANKS);
 	machine_check_poll(MCP_UC | m_fl, &all_banks);
 
-	set_in_cr4(X86_CR4_MCE);
+	cr4_set_bits(X86_CR4_MCE);
 
 	rdmsrl(MSR_IA32_MCG_CAP, cap);
 	if (cap & MCG_CTL_P)
diff --git a/arch/x86/kernel/cpu/mcheck/p5.c b/arch/x86/kernel/cpu/mcheck/p5.c
index ec2663a..737b0ad 100644
--- a/arch/x86/kernel/cpu/mcheck/p5.c
+++ b/arch/x86/kernel/cpu/mcheck/p5.c
@@ -9,6 +9,7 @@
 
 #include <asm/processor.h>
 #include <asm/traps.h>
+#include <asm/tlbflush.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
 
@@ -65,7 +66,7 @@
 	       "Intel old style machine check architecture supported.\n");
 
 	/* Enable MCE: */
-	set_in_cr4(X86_CR4_MCE);
+	cr4_set_bits(X86_CR4_MCE);
 	printk(KERN_INFO
 	       "Intel old style machine check reporting enabled on CPU#%d.\n",
 	       smp_processor_id());
diff --git a/arch/x86/kernel/cpu/mcheck/winchip.c b/arch/x86/kernel/cpu/mcheck/winchip.c
index bd5d46a..44f1382 100644
--- a/arch/x86/kernel/cpu/mcheck/winchip.c
+++ b/arch/x86/kernel/cpu/mcheck/winchip.c
@@ -8,6 +8,7 @@
 
 #include <asm/processor.h>
 #include <asm/traps.h>
+#include <asm/tlbflush.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
 
@@ -36,7 +37,7 @@
 	lo &= ~(1<<4);	/* Enable MCE */
 	wrmsr(MSR_IDT_FCR1, lo, hi);
 
-	set_in_cr4(X86_CR4_MCE);
+	cr4_set_bits(X86_CR4_MCE);
 
 	printk(KERN_INFO
 	       "Winchip machine check reporting enabled on CPU#0.\n");
diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c
index 9e451b0..f8c81ba 100644
--- a/arch/x86/kernel/cpu/mtrr/cyrix.c
+++ b/arch/x86/kernel/cpu/mtrr/cyrix.c
@@ -138,8 +138,8 @@
 
 	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
 	if (cpu_has_pge) {
-		cr4 = read_cr4();
-		write_cr4(cr4 & ~X86_CR4_PGE);
+		cr4 = __read_cr4();
+		__write_cr4(cr4 & ~X86_CR4_PGE);
 	}
 
 	/*
@@ -171,7 +171,7 @@
 
 	/* Restore value of CR4 */
 	if (cpu_has_pge)
-		write_cr4(cr4);
+		__write_cr4(cr4);
 }
 
 static void cyrix_set_arr(unsigned int reg, unsigned long base,
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 0e25a1b..7d74f7b 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -678,8 +678,8 @@
 
 	/* Save value of CR4 and clear Page Global Enable (bit 7) */
 	if (cpu_has_pge) {
-		cr4 = read_cr4();
-		write_cr4(cr4 & ~X86_CR4_PGE);
+		cr4 = __read_cr4();
+		__write_cr4(cr4 & ~X86_CR4_PGE);
 	}
 
 	/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
@@ -708,7 +708,7 @@
 
 	/* Restore value of CR4 */
 	if (cpu_has_pge)
-		write_cr4(cr4);
+		__write_cr4(cr4);
 	raw_spin_unlock(&set_atomicity_lock);
 }
 
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 143e5f5..b71a7f8 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -31,6 +31,8 @@
 #include <asm/nmi.h>
 #include <asm/smp.h>
 #include <asm/alternative.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
 #include <asm/timer.h>
 #include <asm/desc.h>
 #include <asm/ldt.h>
@@ -43,6 +45,8 @@
 	.enabled = 1,
 };
 
+struct static_key rdpmc_always_available = STATIC_KEY_INIT_FALSE;
+
 u64 __read_mostly hw_cache_event_ids
 				[PERF_COUNT_HW_CACHE_MAX]
 				[PERF_COUNT_HW_CACHE_OP_MAX]
@@ -1327,8 +1331,6 @@
 		break;
 
 	case CPU_STARTING:
-		if (x86_pmu.attr_rdpmc)
-			set_in_cr4(X86_CR4_PCE);
 		if (x86_pmu.cpu_starting)
 			x86_pmu.cpu_starting(cpu);
 		break;
@@ -1804,14 +1806,44 @@
 			event->destroy(event);
 	}
 
+	if (ACCESS_ONCE(x86_pmu.attr_rdpmc))
+		event->hw.flags |= PERF_X86_EVENT_RDPMC_ALLOWED;
+
 	return err;
 }
 
+static void refresh_pce(void *ignored)
+{
+	if (current->mm)
+		load_mm_cr4(current->mm);
+}
+
+static void x86_pmu_event_mapped(struct perf_event *event)
+{
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+		return;
+
+	if (atomic_inc_return(&current->mm->context.perf_rdpmc_allowed) == 1)
+		on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
+}
+
+static void x86_pmu_event_unmapped(struct perf_event *event)
+{
+	if (!current->mm)
+		return;
+
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
+		return;
+
+	if (atomic_dec_and_test(&current->mm->context.perf_rdpmc_allowed))
+		on_each_cpu_mask(mm_cpumask(current->mm), refresh_pce, NULL, 1);
+}
+
 static int x86_pmu_event_idx(struct perf_event *event)
 {
 	int idx = event->hw.idx;
 
-	if (!x86_pmu.attr_rdpmc)
+	if (!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED))
 		return 0;
 
 	if (x86_pmu.num_counters_fixed && idx >= INTEL_PMC_IDX_FIXED) {
@@ -1829,16 +1861,6 @@
 	return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
 }
 
-static void change_rdpmc(void *info)
-{
-	bool enable = !!(unsigned long)info;
-
-	if (enable)
-		set_in_cr4(X86_CR4_PCE);
-	else
-		clear_in_cr4(X86_CR4_PCE);
-}
-
 static ssize_t set_attr_rdpmc(struct device *cdev,
 			      struct device_attribute *attr,
 			      const char *buf, size_t count)
@@ -1850,14 +1872,27 @@
 	if (ret)
 		return ret;
 
+	if (val > 2)
+		return -EINVAL;
+
 	if (x86_pmu.attr_rdpmc_broken)
 		return -ENOTSUPP;
 
-	if (!!val != !!x86_pmu.attr_rdpmc) {
-		x86_pmu.attr_rdpmc = !!val;
-		on_each_cpu(change_rdpmc, (void *)val, 1);
+	if ((val == 2) != (x86_pmu.attr_rdpmc == 2)) {
+		/*
+		 * Changing into or out of always available, aka
+		 * perf-event-bypassing mode.  This path is extremely slow,
+		 * but only root can trigger it, so it's okay.
+		 */
+		if (val == 2)
+			static_key_slow_inc(&rdpmc_always_available);
+		else
+			static_key_slow_dec(&rdpmc_always_available);
+		on_each_cpu(refresh_pce, NULL, 1);
 	}
 
+	x86_pmu.attr_rdpmc = val;
+
 	return count;
 }
 
@@ -1900,6 +1935,9 @@
 
 	.event_init		= x86_pmu_event_init,
 
+	.event_mapped		= x86_pmu_event_mapped,
+	.event_unmapped		= x86_pmu_event_unmapped,
+
 	.add			= x86_pmu_add,
 	.del			= x86_pmu_del,
 	.start			= x86_pmu_start,
@@ -1914,13 +1952,15 @@
 	.flush_branch_stack	= x86_pmu_flush_branch_stack,
 };
 
-void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
+void arch_perf_update_userpage(struct perf_event *event,
+			       struct perf_event_mmap_page *userpg, u64 now)
 {
 	struct cyc2ns_data *data;
 
 	userpg->cap_user_time = 0;
 	userpg->cap_user_time_zero = 0;
-	userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc;
+	userpg->cap_user_rdpmc =
+		!!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED);
 	userpg->pmc_width = x86_pmu.cntval_bits;
 
 	if (!sched_clock_stable())
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 4e6cdb0..df525d2 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -71,6 +71,8 @@
 #define PERF_X86_EVENT_COMMITTED	0x8 /* event passed commit_txn */
 #define PERF_X86_EVENT_PEBS_LD_HSW	0x10 /* haswell style datala, load */
 #define PERF_X86_EVENT_PEBS_NA_HSW	0x20 /* haswell style datala, unknown */
+#define PERF_X86_EVENT_RDPMC_ALLOWED	0x40 /* grant rdpmc permission */
+
 
 struct amd_nb {
 	int nb_id;  /* NorthBridge id */
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index b74ebc7..cf3df1d 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -265,7 +265,10 @@
 	printk("SMP ");
 #endif
 #ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC");
+	printk("DEBUG_PAGEALLOC ");
+#endif
+#ifdef CONFIG_KASAN
+	printk("KASAN");
 #endif
 	printk("\n");
 	if (notify_die(DIE_OOPS, str, regs, err,
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 01d1c18..a62536a 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -19,6 +19,7 @@
 #include <linux/usb/ehci_def.h>
 #include <linux/efi.h>
 #include <asm/efi.h>
+#include <asm/pci_x86.h>
 
 /* Simple VGA output */
 #define VGABASE		(__ISA_IO_base + 0xb8000)
@@ -76,7 +77,7 @@
 
 /* Serial functions loosely based on a similar package from Klaus P. Gerlicher */
 
-static int early_serial_base = 0x3f8;  /* ttyS0 */
+static unsigned long early_serial_base = 0x3f8;  /* ttyS0 */
 
 #define XMTRDY          0x20
 
@@ -94,13 +95,40 @@
 #define DLL             0       /*  Divisor Latch Low         */
 #define DLH             1       /*  Divisor latch High        */
 
+static void mem32_serial_out(unsigned long addr, int offset, int value)
+{
+	uint32_t *vaddr = (uint32_t *)addr;
+	/* shift implied by pointer type */
+	writel(value, vaddr + offset);
+}
+
+static unsigned int mem32_serial_in(unsigned long addr, int offset)
+{
+	uint32_t *vaddr = (uint32_t *)addr;
+	/* shift implied by pointer type */
+	return readl(vaddr + offset);
+}
+
+static unsigned int io_serial_in(unsigned long addr, int offset)
+{
+	return inb(addr + offset);
+}
+
+static void io_serial_out(unsigned long addr, int offset, int value)
+{
+	outb(value, addr + offset);
+}
+
+static unsigned int (*serial_in)(unsigned long addr, int offset) = io_serial_in;
+static void (*serial_out)(unsigned long addr, int offset, int value) = io_serial_out;
+
 static int early_serial_putc(unsigned char ch)
 {
 	unsigned timeout = 0xffff;
 
-	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
+	while ((serial_in(early_serial_base, LSR) & XMTRDY) == 0 && --timeout)
 		cpu_relax();
-	outb(ch, early_serial_base + TXR);
+	serial_out(early_serial_base, TXR, ch);
 	return timeout ? 0 : -1;
 }
 
@@ -114,13 +142,28 @@
 	}
 }
 
+static __init void early_serial_hw_init(unsigned divisor)
+{
+	unsigned char c;
+
+	serial_out(early_serial_base, LCR, 0x3);	/* 8n1 */
+	serial_out(early_serial_base, IER, 0);	/* no interrupt */
+	serial_out(early_serial_base, FCR, 0);	/* no fifo */
+	serial_out(early_serial_base, MCR, 0x3);	/* DTR + RTS */
+
+	c = serial_in(early_serial_base, LCR);
+	serial_out(early_serial_base, LCR, c | DLAB);
+	serial_out(early_serial_base, DLL, divisor & 0xff);
+	serial_out(early_serial_base, DLH, (divisor >> 8) & 0xff);
+	serial_out(early_serial_base, LCR, c & ~DLAB);
+}
+
 #define DEFAULT_BAUD 9600
 
 static __init void early_serial_init(char *s)
 {
-	unsigned char c;
 	unsigned divisor;
-	unsigned baud = DEFAULT_BAUD;
+	unsigned long baud = DEFAULT_BAUD;
 	char *e;
 
 	if (*s == ',')
@@ -145,25 +188,125 @@
 			s++;
 	}
 
-	outb(0x3, early_serial_base + LCR);	/* 8n1 */
-	outb(0, early_serial_base + IER);	/* no interrupt */
-	outb(0, early_serial_base + FCR);	/* no fifo */
-	outb(0x3, early_serial_base + MCR);	/* DTR + RTS */
-
 	if (*s) {
-		baud = simple_strtoul(s, &e, 0);
-		if (baud == 0 || s == e)
+		if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
 			baud = DEFAULT_BAUD;
 	}
 
+	/* Convert from baud to divisor value */
 	divisor = 115200 / baud;
-	c = inb(early_serial_base + LCR);
-	outb(c | DLAB, early_serial_base + LCR);
-	outb(divisor & 0xff, early_serial_base + DLL);
-	outb((divisor >> 8) & 0xff, early_serial_base + DLH);
-	outb(c & ~DLAB, early_serial_base + LCR);
+
+	/* These will always be IO based ports */
+	serial_in = io_serial_in;
+	serial_out = io_serial_out;
+
+	/* Set up the HW */
+	early_serial_hw_init(divisor);
 }
 
+#ifdef CONFIG_PCI
+/*
+ * early_pci_serial_init()
+ *
+ * This function is invoked when the early_printk param starts with "pciserial"
+ * The rest of the param should be ",B:D.F,baud" where B, D & F describe the
+ * location of a PCI device that must be a UART device.
+ */
+static __init void early_pci_serial_init(char *s)
+{
+	unsigned divisor;
+	unsigned long baud = DEFAULT_BAUD;
+	u8 bus, slot, func;
+	uint32_t classcode, bar0;
+	uint16_t cmdreg;
+	char *e;
+
+
+	/*
+	 * First, part the param to get the BDF values
+	 */
+	if (*s == ',')
+		++s;
+
+	if (*s == 0)
+		return;
+
+	bus = (u8)simple_strtoul(s, &e, 16);
+	s = e;
+	if (*s != ':')
+		return;
+	++s;
+	slot = (u8)simple_strtoul(s, &e, 16);
+	s = e;
+	if (*s != '.')
+		return;
+	++s;
+	func = (u8)simple_strtoul(s, &e, 16);
+	s = e;
+
+	/* A baud might be following */
+	if (*s == ',')
+		s++;
+
+	/*
+	 * Second, find the device from the BDF
+	 */
+	cmdreg = read_pci_config(bus, slot, func, PCI_COMMAND);
+	classcode = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+	bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+
+	/*
+	 * Verify it is a UART type device
+	 */
+	if (((classcode >> 16 != PCI_CLASS_COMMUNICATION_MODEM) &&
+	     (classcode >> 16 != PCI_CLASS_COMMUNICATION_SERIAL)) ||
+	   (((classcode >> 8) & 0xff) != 0x02)) /* 16550 I/F at BAR0 */
+		return;
+
+	/*
+	 * Determine if it is IO or memory mapped
+	 */
+	if (bar0 & 0x01) {
+		/* it is IO mapped */
+		serial_in = io_serial_in;
+		serial_out = io_serial_out;
+		early_serial_base = bar0&0xfffffffc;
+		write_pci_config(bus, slot, func, PCI_COMMAND,
+						cmdreg|PCI_COMMAND_IO);
+	} else {
+		/* It is memory mapped - assume 32-bit alignment */
+		serial_in = mem32_serial_in;
+		serial_out = mem32_serial_out;
+		/* WARNING! assuming the address is always in the first 4G */
+		early_serial_base =
+			(unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10);
+		write_pci_config(bus, slot, func, PCI_COMMAND,
+						cmdreg|PCI_COMMAND_MEMORY);
+	}
+
+	/*
+	 * Lastly, initalize the hardware
+	 */
+	if (*s) {
+		if (strcmp(s, "nocfg") == 0)
+			/* Sometimes, we want to leave the UART alone
+			 * and assume the BIOS has set it up correctly.
+			 * "nocfg" tells us this is the case, and we
+			 * should do no more setup.
+			 */
+			return;
+		if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
+			baud = DEFAULT_BAUD;
+	}
+
+	/* Convert from baud to divisor value */
+	divisor = 115200 / baud;
+
+	/* Set up the HW */
+	early_serial_hw_init(divisor);
+}
+#endif
+
 static struct console early_serial_console = {
 	.name =		"earlyser",
 	.write =	early_serial_write,
@@ -210,6 +353,13 @@
 			early_serial_init(buf + 4);
 			early_console_register(&early_serial_console, keep);
 		}
+#ifdef CONFIG_PCI
+		if (!strncmp(buf, "pciserial", 9)) {
+			early_pci_serial_init(buf + 9);
+			early_console_register(&early_serial_console, keep);
+			buf += 9; /* Keep from match the above "serial" */
+		}
+#endif
 		if (!strncmp(buf, "vga", 3) &&
 		    boot_params.screen_info.orig_video_isVGA == 1) {
 			max_xpos = boot_params.screen_info.orig_video_cols;
@@ -226,11 +376,6 @@
 			early_console_register(&xenboot_console, keep);
 #endif
 #ifdef CONFIG_EARLY_PRINTK_INTEL_MID
-		if (!strncmp(buf, "mrst", 4)) {
-			mrst_early_console_init();
-			early_console_register(&early_mrst_console, keep);
-		}
-
 		if (!strncmp(buf, "hsu", 3)) {
 			hsu_early_console_init(buf + 3);
 			early_console_register(&early_hsu_console, keep);
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index d6c1b983..2911ef3 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -31,6 +31,7 @@
 
 asmlinkage __visible void __init i386_start_kernel(void)
 {
+	cr4_init_shadow();
 	sanitize_boot_params(&boot_params);
 
 	/* Call the subarch specific early setup function */
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index eda1a86..c4f8d46 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -27,6 +27,7 @@
 #include <asm/bios_ebda.h>
 #include <asm/bootparam_utils.h>
 #include <asm/microcode.h>
+#include <asm/kasan.h>
 
 /*
  * Manage page tables very early on.
@@ -46,7 +47,7 @@
 
 	next_early_pgt = 0;
 
-	write_cr3(__pa(early_level4_pgt));
+	write_cr3(__pa_nodebug(early_level4_pgt));
 }
 
 /* Create a new PMD entry */
@@ -59,7 +60,7 @@
 	pmdval_t pmd, *pmd_p;
 
 	/* Invalid address or early pgt is done ?  */
-	if (physaddr >= MAXMEM || read_cr3() != __pa(early_level4_pgt))
+	if (physaddr >= MAXMEM || read_cr3() != __pa_nodebug(early_level4_pgt))
 		return -1;
 
 again:
@@ -155,9 +156,13 @@
 				(__START_KERNEL & PGDIR_MASK)));
 	BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
 
+	cr4_init_shadow();
+
 	/* Kill off the identity-map trampoline */
 	reset_early_page_tables();
 
+	kasan_map_early_shadow(early_level4_pgt);
+
 	/* clear bss before set_intr_gate with early_idt_handler */
 	clear_bss();
 
@@ -179,6 +184,8 @@
 	/* set init_level4_pgt kernel high mapping*/
 	init_level4_pgt[511] = early_level4_pgt[511];
 
+	kasan_map_early_shadow(init_level4_pgt);
+
 	x86_64_start_reservations(real_mode_data);
 }
 
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index a468c0a..6fd514d9 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -514,8 +514,38 @@
 	/* This must match the first entry in level2_kernel_pgt */
 	.quad   0x0000000000000000
 
+#ifdef CONFIG_KASAN
+#define FILL(VAL, COUNT)				\
+	.rept (COUNT) ;					\
+	.quad	(VAL) ;					\
+	.endr
+
+NEXT_PAGE(kasan_zero_pte)
+	FILL(kasan_zero_page - __START_KERNEL_map + _KERNPG_TABLE, 512)
+NEXT_PAGE(kasan_zero_pmd)
+	FILL(kasan_zero_pte - __START_KERNEL_map + _KERNPG_TABLE, 512)
+NEXT_PAGE(kasan_zero_pud)
+	FILL(kasan_zero_pmd - __START_KERNEL_map + _KERNPG_TABLE, 512)
+
+#undef FILL
+#endif
+
+
 #include "../../x86/xen/xen-head.S"
 	
 	__PAGE_ALIGNED_BSS
 NEXT_PAGE(empty_zero_page)
 	.skip PAGE_SIZE
+
+#ifdef CONFIG_KASAN
+/*
+ * This page used as early shadow. We don't use empty_zero_page
+ * at early stages, stack instrumentation could write some garbage
+ * to this page.
+ * Latter we reuse it as zero shadow for large ranges of memory
+ * that allowed to access, but not instrumented by kasan
+ * (vmalloc/vmemmap ...).
+ */
+NEXT_PAGE(kasan_zero_page)
+	.skip PAGE_SIZE
+#endif
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 81049ff..d5651fc 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -13,6 +13,7 @@
 #include <asm/sigcontext.h>
 #include <asm/processor.h>
 #include <asm/math_emu.h>
+#include <asm/tlbflush.h>
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/i387.h>
@@ -193,7 +194,7 @@
 	if (cpu_has_xmm)
 		cr4_mask |= X86_CR4_OSXMMEXCPT;
 	if (cr4_mask)
-		set_in_cr4(cr4_mask);
+		cr4_set_bits(cr4_mask);
 
 	cr0 = read_cr0();
 	cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index e69f988..d1ac80b 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/kasan.h>
 #include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/gfp.h>
@@ -83,13 +84,22 @@
 
 void *module_alloc(unsigned long size)
 {
+	void *p;
+
 	if (PAGE_ALIGN(size) > MODULES_LEN)
 		return NULL;
-	return __vmalloc_node_range(size, 1,
+
+	p = __vmalloc_node_range(size, MODULE_ALIGN,
 				    MODULES_VADDR + get_module_load_offset(),
 				    MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
-				    PAGE_KERNEL_EXEC, NUMA_NO_NODE,
+				    PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
 				    __builtin_return_address(0));
+	if (p && (kasan_module_alloc(p, size) < 0)) {
+		vfree(p);
+		return NULL;
+	}
+
+	return p;
 }
 
 #ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e127dda..046e2d6 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -28,6 +28,7 @@
 #include <asm/fpu-internal.h>
 #include <asm/debugreg.h>
 #include <asm/nmi.h>
+#include <asm/tlbflush.h>
 
 /*
  * per-CPU TSS segments. Threads are completely 'soft' on Linux,
@@ -141,7 +142,7 @@
 
 static void hard_disable_TSC(void)
 {
-	write_cr4(read_cr4() | X86_CR4_TSD);
+	cr4_set_bits(X86_CR4_TSD);
 }
 
 void disable_TSC(void)
@@ -158,7 +159,7 @@
 
 static void hard_enable_TSC(void)
 {
-	write_cr4(read_cr4() & ~X86_CR4_TSD);
+	cr4_clear_bits(X86_CR4_TSD);
 }
 
 static void enable_TSC(void)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 8f3ebfe..603c4f9 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -101,7 +101,7 @@
 	cr0 = read_cr0();
 	cr2 = read_cr2();
 	cr3 = read_cr3();
-	cr4 = read_cr4_safe();
+	cr4 = __read_cr4_safe();
 	printk(KERN_DEFAULT "CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
 			cr0, cr2, cr3, cr4);
 
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 5a2c029..67fcc43 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -93,7 +93,7 @@
 	cr0 = read_cr0();
 	cr2 = read_cr2();
 	cr3 = read_cr3();
-	cr4 = read_cr4();
+	cr4 = __read_cr4();
 
 	printk(KERN_DEFAULT "FS:  %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
 	       fs, fsindex, gs, gsindex, shadowgs);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index c4648ada..0a2421c 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -89,6 +89,7 @@
 #include <asm/cacheflush.h>
 #include <asm/processor.h>
 #include <asm/bugs.h>
+#include <asm/kasan.h>
 
 #include <asm/vsyscall.h>
 #include <asm/cpu.h>
@@ -1174,9 +1175,11 @@
 
 	x86_init.paging.pagetable_init();
 
+	kasan_init();
+
 	if (boot_cpu_data.cpuid_level >= 0) {
 		/* A CPU has %cr4 if and only if it has CPUID */
-		mmu_cr4_features = read_cr4();
+		mmu_cr4_features = __read_cr4();
 		if (trampoline_cr4_features)
 			*trampoline_cr4_features = mmu_cr4_features;
 	}
diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c
index 0406819..37d8fa4 100644
--- a/arch/x86/kernel/x8664_ksyms_64.c
+++ b/arch/x86/kernel/x8664_ksyms_64.c
@@ -50,13 +50,19 @@
 #undef memset
 #undef memmove
 
+extern void *__memset(void *, int, __kernel_size_t);
+extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *__memmove(void *, const void *, __kernel_size_t);
 extern void *memset(void *, int, __kernel_size_t);
 extern void *memcpy(void *, const void *, __kernel_size_t);
-extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+EXPORT_SYMBOL(__memset);
+EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(__memmove);
 
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(memmove);
 
 #ifndef CONFIG_DEBUG_VIRTUAL
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 0de1fae..34f66e5 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -12,6 +12,7 @@
 #include <asm/i387.h>
 #include <asm/fpu-internal.h>
 #include <asm/sigframe.h>
+#include <asm/tlbflush.h>
 #include <asm/xcr.h>
 
 /*
@@ -453,7 +454,7 @@
  */
 static inline void xstate_enable(void)
 {
-	set_in_cr4(X86_CR4_OSXSAVE);
+	cr4_set_bits(X86_CR4_OSXSAVE);
 	xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
 }
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index a17d848..d319e0c 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1583,7 +1583,7 @@
 
 static int svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
-	unsigned long host_cr4_mce = read_cr4() & X86_CR4_MCE;
+	unsigned long host_cr4_mce = cr4_read_shadow() & X86_CR4_MCE;
 	unsigned long old_cr4 = to_svm(vcpu)->vmcb->save.cr4;
 
 	if (cr4 & X86_CR4_VMXE)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3f73bfa..14c1a18 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2871,7 +2871,7 @@
 	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
 	u64 old, test_bits;
 
-	if (read_cr4() & X86_CR4_VMXE)
+	if (cr4_read_shadow() & X86_CR4_VMXE)
 		return -EBUSY;
 
 	INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
@@ -2898,7 +2898,7 @@
 		/* enable and lock */
 		wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits);
 	}
-	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
+	cr4_set_bits(X86_CR4_VMXE);
 
 	if (vmm_exclusive) {
 		kvm_cpu_vmxon(phys_addr);
@@ -2935,7 +2935,7 @@
 		vmclear_local_loaded_vmcss();
 		kvm_cpu_vmxoff();
 	}
-	write_cr4(read_cr4() & ~X86_CR4_VMXE);
+	cr4_clear_bits(X86_CR4_VMXE);
 }
 
 static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
@@ -4450,7 +4450,7 @@
 	vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
 
 	/* Save the most likely value for this task's CR4 in the VMCS. */
-	cr4 = read_cr4();
+	cr4 = cr4_read_shadow();
 	vmcs_writel(HOST_CR4, cr4);			/* 22.2.3, 22.2.5 */
 	vmx->host_state.vmcs_host_cr4 = cr4;
 
@@ -8146,7 +8146,7 @@
 	if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty))
 		vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);
 
-	cr4 = read_cr4();
+	cr4 = cr4_read_shadow();
 	if (unlikely(cr4 != vmx->host_state.vmcs_host_cr4)) {
 		vmcs_writel(HOST_CR4, cr4);
 		vmx->host_state.vmcs_host_cr4 = cr4;
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index 56313a3..89b53c9 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -53,6 +53,8 @@
 .Lmemcpy_e_e:
 	.previous
 
+.weak memcpy
+
 ENTRY(__memcpy)
 ENTRY(memcpy)
 	CFI_STARTPROC
@@ -199,8 +201,8 @@
 	 * only outcome...
 	 */
 	.section .altinstructions, "a"
-	altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
+	altinstruction_entry __memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
 			     .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c
-	altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
+	altinstruction_entry __memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
 			     .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e
 	.previous
diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S
index 65268a6..9c4b530 100644
--- a/arch/x86/lib/memmove_64.S
+++ b/arch/x86/lib/memmove_64.S
@@ -24,7 +24,10 @@
  * Output:
  * rax: dest
  */
+.weak memmove
+
 ENTRY(memmove)
+ENTRY(__memmove)
 	CFI_STARTPROC
 
 	/* Handle more 32 bytes in loop */
@@ -220,4 +223,5 @@
 		.Lmemmove_end_forward-.Lmemmove_begin_forward,	\
 		.Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs
 	.previous
+ENDPROC(__memmove)
 ENDPROC(memmove)
diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S
index 2dcb380..6f44935 100644
--- a/arch/x86/lib/memset_64.S
+++ b/arch/x86/lib/memset_64.S
@@ -56,6 +56,8 @@
 .Lmemset_e_e:
 	.previous
 
+.weak memset
+
 ENTRY(memset)
 ENTRY(__memset)
 	CFI_STARTPROC
@@ -147,8 +149,8 @@
          * feature to implement the right patch order.
 	 */
 	.section .altinstructions,"a"
-	altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
-			     .Lfinal-memset,.Lmemset_e-.Lmemset_c
-	altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
-			     .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e
+	altinstruction_entry __memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
+			     .Lfinal-__memset,.Lmemset_e-.Lmemset_c
+	altinstruction_entry __memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
+			     .Lfinal-__memset,.Lmemset_e_e-.Lmemset_c_e
 	.previous
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index ecfdc46..c4cc740 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -20,6 +20,9 @@
 
 obj-$(CONFIG_KMEMCHECK)		+= kmemcheck/
 
+KASAN_SANITIZE_kasan_init_$(BITS).o := n
+obj-$(CONFIG_KASAN)		+= kasan_init_$(BITS).o
+
 obj-$(CONFIG_MMIOTRACE)		+= mmiotrace.o
 mmiotrace-y			:= kmmio.o pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)	+= testmmiotrace.o
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index e3ff27a..ede025f 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -600,7 +600,7 @@
 			printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
 		if (pte && pte_present(*pte) && pte_exec(*pte) &&
 				(pgd_flags(*pgd) & _PAGE_USER) &&
-				(read_cr4() & X86_CR4_SMEP))
+				(__read_cr4() & X86_CR4_SMEP))
 			printk(smep_warning, from_kuid(&init_user_ns, current_uid()));
 	}
 
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 649da47..553c094 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -173,11 +173,11 @@
 
 	/* Enable PSE if available */
 	if (cpu_has_pse)
-		set_in_cr4(X86_CR4_PSE);
+		cr4_set_bits_and_update_boot(X86_CR4_PSE);
 
 	/* Enable PGE if available */
 	if (cpu_has_pge) {
-		set_in_cr4(X86_CR4_PGE);
+		cr4_set_bits_and_update_boot(X86_CR4_PGE);
 		__supported_pte_mask |= _PAGE_GLOBAL;
 	}
 }
@@ -713,6 +713,15 @@
 	free_area_init_nodes(max_zone_pfns);
 }
 
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = {
+#ifdef CONFIG_SMP
+	.active_mm = &init_mm,
+	.state = 0,
+#endif
+	.cr4 = ~0UL,	/* fail hard if we screw up cr4 shadow initialization */
+};
+EXPORT_SYMBOL_GPL(cpu_tlbstate);
+
 void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache)
 {
 	/* entry 0 MUST be WB (hardwired to speed up translations) */
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
new file mode 100644
index 0000000..4860906
--- /dev/null
+++ b/arch/x86/mm/kasan_init_64.c
@@ -0,0 +1,206 @@
+#include <linux/bootmem.h>
+#include <linux/kasan.h>
+#include <linux/kdebug.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#include <asm/tlbflush.h>
+#include <asm/sections.h>
+
+extern pgd_t early_level4_pgt[PTRS_PER_PGD];
+extern struct range pfn_mapped[E820_X_MAX];
+
+extern unsigned char kasan_zero_page[PAGE_SIZE];
+
+static int __init map_range(struct range *range)
+{
+	unsigned long start;
+	unsigned long end;
+
+	start = (unsigned long)kasan_mem_to_shadow(pfn_to_kaddr(range->start));
+	end = (unsigned long)kasan_mem_to_shadow(pfn_to_kaddr(range->end));
+
+	/*
+	 * end + 1 here is intentional. We check several shadow bytes in advance
+	 * to slightly speed up fastpath. In some rare cases we could cross
+	 * boundary of mapped shadow, so we just map some more here.
+	 */
+	return vmemmap_populate(start, end + 1, NUMA_NO_NODE);
+}
+
+static void __init clear_pgds(unsigned long start,
+			unsigned long end)
+{
+	for (; start < end; start += PGDIR_SIZE)
+		pgd_clear(pgd_offset_k(start));
+}
+
+void __init kasan_map_early_shadow(pgd_t *pgd)
+{
+	int i;
+	unsigned long start = KASAN_SHADOW_START;
+	unsigned long end = KASAN_SHADOW_END;
+
+	for (i = pgd_index(start); start < end; i++) {
+		pgd[i] = __pgd(__pa_nodebug(kasan_zero_pud)
+				| _KERNPG_TABLE);
+		start += PGDIR_SIZE;
+	}
+}
+
+static int __init zero_pte_populate(pmd_t *pmd, unsigned long addr,
+				unsigned long end)
+{
+	pte_t *pte = pte_offset_kernel(pmd, addr);
+
+	while (addr + PAGE_SIZE <= end) {
+		WARN_ON(!pte_none(*pte));
+		set_pte(pte, __pte(__pa_nodebug(kasan_zero_page)
+					| __PAGE_KERNEL_RO));
+		addr += PAGE_SIZE;
+		pte = pte_offset_kernel(pmd, addr);
+	}
+	return 0;
+}
+
+static int __init zero_pmd_populate(pud_t *pud, unsigned long addr,
+				unsigned long end)
+{
+	int ret = 0;
+	pmd_t *pmd = pmd_offset(pud, addr);
+
+	while (IS_ALIGNED(addr, PMD_SIZE) && addr + PMD_SIZE <= end) {
+		WARN_ON(!pmd_none(*pmd));
+		set_pmd(pmd, __pmd(__pa_nodebug(kasan_zero_pte)
+					| __PAGE_KERNEL_RO));
+		addr += PMD_SIZE;
+		pmd = pmd_offset(pud, addr);
+	}
+	if (addr < end) {
+		if (pmd_none(*pmd)) {
+			void *p = vmemmap_alloc_block(PAGE_SIZE, NUMA_NO_NODE);
+			if (!p)
+				return -ENOMEM;
+			set_pmd(pmd, __pmd(__pa_nodebug(p) | _KERNPG_TABLE));
+		}
+		ret = zero_pte_populate(pmd, addr, end);
+	}
+	return ret;
+}
+
+
+static int __init zero_pud_populate(pgd_t *pgd, unsigned long addr,
+				unsigned long end)
+{
+	int ret = 0;
+	pud_t *pud = pud_offset(pgd, addr);
+
+	while (IS_ALIGNED(addr, PUD_SIZE) && addr + PUD_SIZE <= end) {
+		WARN_ON(!pud_none(*pud));
+		set_pud(pud, __pud(__pa_nodebug(kasan_zero_pmd)
+					| __PAGE_KERNEL_RO));
+		addr += PUD_SIZE;
+		pud = pud_offset(pgd, addr);
+	}
+
+	if (addr < end) {
+		if (pud_none(*pud)) {
+			void *p = vmemmap_alloc_block(PAGE_SIZE, NUMA_NO_NODE);
+			if (!p)
+				return -ENOMEM;
+			set_pud(pud, __pud(__pa_nodebug(p) | _KERNPG_TABLE));
+		}
+		ret = zero_pmd_populate(pud, addr, end);
+	}
+	return ret;
+}
+
+static int __init zero_pgd_populate(unsigned long addr, unsigned long end)
+{
+	int ret = 0;
+	pgd_t *pgd = pgd_offset_k(addr);
+
+	while (IS_ALIGNED(addr, PGDIR_SIZE) && addr + PGDIR_SIZE <= end) {
+		WARN_ON(!pgd_none(*pgd));
+		set_pgd(pgd, __pgd(__pa_nodebug(kasan_zero_pud)
+					| __PAGE_KERNEL_RO));
+		addr += PGDIR_SIZE;
+		pgd = pgd_offset_k(addr);
+	}
+
+	if (addr < end) {
+		if (pgd_none(*pgd)) {
+			void *p = vmemmap_alloc_block(PAGE_SIZE, NUMA_NO_NODE);
+			if (!p)
+				return -ENOMEM;
+			set_pgd(pgd, __pgd(__pa_nodebug(p) | _KERNPG_TABLE));
+		}
+		ret = zero_pud_populate(pgd, addr, end);
+	}
+	return ret;
+}
+
+
+static void __init populate_zero_shadow(const void *start, const void *end)
+{
+	if (zero_pgd_populate((unsigned long)start, (unsigned long)end))
+		panic("kasan: unable to map zero shadow!");
+}
+
+
+#ifdef CONFIG_KASAN_INLINE
+static int kasan_die_handler(struct notifier_block *self,
+			     unsigned long val,
+			     void *data)
+{
+	if (val == DIE_GPF) {
+		pr_emerg("CONFIG_KASAN_INLINE enabled");
+		pr_emerg("GPF could be caused by NULL-ptr deref or user memory access");
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kasan_die_notifier = {
+	.notifier_call = kasan_die_handler,
+};
+#endif
+
+void __init kasan_init(void)
+{
+	int i;
+
+#ifdef CONFIG_KASAN_INLINE
+	register_die_notifier(&kasan_die_notifier);
+#endif
+
+	memcpy(early_level4_pgt, init_level4_pgt, sizeof(early_level4_pgt));
+	load_cr3(early_level4_pgt);
+
+	clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
+
+	populate_zero_shadow((void *)KASAN_SHADOW_START,
+			kasan_mem_to_shadow((void *)PAGE_OFFSET));
+
+	for (i = 0; i < E820_X_MAX; i++) {
+		if (pfn_mapped[i].end == 0)
+			break;
+
+		if (map_range(&pfn_mapped[i]))
+			panic("kasan: unable to allocate shadow!");
+	}
+	populate_zero_shadow(kasan_mem_to_shadow((void *)PAGE_OFFSET + MAXMEM),
+			kasan_mem_to_shadow((void *)__START_KERNEL_map));
+
+	vmemmap_populate((unsigned long)kasan_mem_to_shadow(_stext),
+			(unsigned long)kasan_mem_to_shadow(_end),
+			NUMA_NO_NODE);
+
+	populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_END),
+			(void *)KASAN_SHADOW_END);
+
+	memset(kasan_zero_page, 0, PAGE_SIZE);
+
+	load_cr3(init_level4_pgt);
+	init_task.kasan_depth = 0;
+}
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 1a88370..cd4785b 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -794,7 +794,6 @@
 void debug_cpumask_set_cpu(int cpu, int node, bool enable)
 {
 	struct cpumask *mask;
-	char buf[64];
 
 	if (node == NUMA_NO_NODE) {
 		/* early_cpu_to_node() already emits a warning and trace */
@@ -812,10 +811,9 @@
 	else
 		cpumask_clear_cpu(cpu, mask);
 
-	cpulist_scnprintf(buf, sizeof(buf), mask);
-	printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n",
+	printk(KERN_DEBUG "%s cpu %d node %d: mask now %*pbl\n",
 		enable ? "numa_add_cpu" : "numa_remove_cpu",
-		cpu, node, buf);
+		cpu, node, cpumask_pr_args(mask));
 	return;
 }
 
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index ee61c36..3250f23 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -14,9 +14,6 @@
 #include <asm/uv/uv.h>
 #include <linux/debugfs.h>
 
-DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate)
-			= { &init_mm, 0, };
-
 /*
  *	Smarter SMP flushing macros.
  *		c/o Linus Torvalds.
diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile
index af9307f..91ec9f8 100644
--- a/arch/x86/platform/intel-mid/device_libs/Makefile
+++ b/arch/x86/platform/intel-mid/device_libs/Makefile
@@ -16,8 +16,6 @@
 obj-$(subst m,y,$(CONFIG_INPUT_BMA150)) += platform_bma023.o
 obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o
 obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o
-# SPI Devices
-obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
 # MISC Devices
 obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
 obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max3111.c b/arch/x86/platform/intel-mid/device_libs/platform_max3111.c
deleted file mode 100644
index afd1df9..0000000
--- a/arch/x86/platform/intel-mid/device_libs/platform_max3111.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * platform_max3111.c: max3111 platform data initilization file
- *
- * (C) Copyright 2013 Intel Corporation
- * Author: Sathyanarayanan Kuppuswamy <sathyanarayanan.kuppuswamy@intel.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/gpio.h>
-#include <linux/spi/spi.h>
-#include <asm/intel-mid.h>
-
-static void __init *max3111_platform_data(void *info)
-{
-	struct spi_board_info *spi_info = info;
-	int intr = get_gpio_by_name("max3111_int");
-
-	spi_info->mode = SPI_MODE_0;
-	if (intr == -1)
-		return NULL;
-	spi_info->irq = intr + INTEL_MID_IRQ_OFFSET;
-	return NULL;
-}
-
-static const struct devs_id max3111_dev_id __initconst = {
-	.name = "spi_max3111",
-	.type = SFI_DEV_TYPE_SPI,
-	.get_platform_data = &max3111_platform_data,
-};
-
-sfi_device(max3111_dev_id);
diff --git a/arch/x86/platform/intel-mid/early_printk_intel_mid.c b/arch/x86/platform/intel-mid/early_printk_intel_mid.c
index e0bd082..4e72082 100644
--- a/arch/x86/platform/intel-mid/early_printk_intel_mid.c
+++ b/arch/x86/platform/intel-mid/early_printk_intel_mid.c
@@ -10,15 +10,13 @@
  */
 
 /*
- * This file implements two early consoles named mrst and hsu.
- * mrst is based on Maxim3110 spi-uart device, it exists in both
- * Moorestown and Medfield platforms, while hsu is based on a High
- * Speed UART device which only exists in the Medfield platform
+ * This file implements early console named hsu.
+ * hsu is based on a High Speed UART device which only exists in the Medfield
+ * platform
  */
 
 #include <linux/serial_reg.h>
 #include <linux/serial_mfd.h>
-#include <linux/kmsg_dump.h>
 #include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -28,216 +26,6 @@
 #include <asm/pgtable.h>
 #include <asm/intel-mid.h>
 
-#define MRST_SPI_TIMEOUT		0x200000
-#define MRST_REGBASE_SPI0		0xff128000
-#define MRST_REGBASE_SPI1		0xff128400
-#define MRST_CLK_SPI0_REG		0xff11d86c
-
-/* Bit fields in CTRLR0 */
-#define SPI_DFS_OFFSET			0
-
-#define SPI_FRF_OFFSET			4
-#define SPI_FRF_SPI			0x0
-#define SPI_FRF_SSP			0x1
-#define SPI_FRF_MICROWIRE		0x2
-#define SPI_FRF_RESV			0x3
-
-#define SPI_MODE_OFFSET			6
-#define SPI_SCPH_OFFSET			6
-#define SPI_SCOL_OFFSET			7
-#define SPI_TMOD_OFFSET			8
-#define	SPI_TMOD_TR			0x0		/* xmit & recv */
-#define SPI_TMOD_TO			0x1		/* xmit only */
-#define SPI_TMOD_RO			0x2		/* recv only */
-#define SPI_TMOD_EPROMREAD		0x3		/* eeprom read mode */
-
-#define SPI_SLVOE_OFFSET		10
-#define SPI_SRL_OFFSET			11
-#define SPI_CFS_OFFSET			12
-
-/* Bit fields in SR, 7 bits */
-#define SR_MASK				0x7f		/* cover 7 bits */
-#define SR_BUSY				(1 << 0)
-#define SR_TF_NOT_FULL			(1 << 1)
-#define SR_TF_EMPT			(1 << 2)
-#define SR_RF_NOT_EMPT			(1 << 3)
-#define SR_RF_FULL			(1 << 4)
-#define SR_TX_ERR			(1 << 5)
-#define SR_DCOL				(1 << 6)
-
-struct dw_spi_reg {
-	u32	ctrl0;
-	u32	ctrl1;
-	u32	ssienr;
-	u32	mwcr;
-	u32	ser;
-	u32	baudr;
-	u32	txfltr;
-	u32	rxfltr;
-	u32	txflr;
-	u32	rxflr;
-	u32	sr;
-	u32	imr;
-	u32	isr;
-	u32	risr;
-	u32	txoicr;
-	u32	rxoicr;
-	u32	rxuicr;
-	u32	msticr;
-	u32	icr;
-	u32	dmacr;
-	u32	dmatdlr;
-	u32	dmardlr;
-	u32	idr;
-	u32	version;
-
-	/* Currently operates as 32 bits, though only the low 16 bits matter */
-	u32	dr;
-} __packed;
-
-#define dw_readl(dw, name)		__raw_readl(&(dw)->name)
-#define dw_writel(dw, name, val)	__raw_writel((val), &(dw)->name)
-
-/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
-static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
-
-static u32 *pclk_spi0;
-/* Always contains an accessible address, start with 0 */
-static struct dw_spi_reg *pspi;
-
-static struct kmsg_dumper dw_dumper;
-static int dumper_registered;
-
-static void dw_kmsg_dump(struct kmsg_dumper *dumper,
-			 enum kmsg_dump_reason reason)
-{
-	static char line[1024];
-	size_t len;
-
-	/* When run to this, we'd better re-init the HW */
-	mrst_early_console_init();
-
-	while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
-		early_mrst_console.write(&early_mrst_console, line, len);
-}
-
-/* Set the ratio rate to 115200, 8n1, IRQ disabled */
-static void max3110_write_config(void)
-{
-	u16 config;
-
-	config = 0xc001;
-	dw_writel(pspi, dr, config);
-}
-
-/* Translate char to a eligible word and send to max3110 */
-static void max3110_write_data(char c)
-{
-	u16 data;
-
-	data = 0x8000 | c;
-	dw_writel(pspi, dr, data);
-}
-
-void mrst_early_console_init(void)
-{
-	u32 ctrlr0 = 0;
-	u32 spi0_cdiv;
-	u32 freq; /* Freqency info only need be searched once */
-
-	/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
-	pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
-							MRST_CLK_SPI0_REG);
-	spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
-	freq = 100000000 / (spi0_cdiv + 1);
-
-	if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL)
-		mrst_spi_paddr = MRST_REGBASE_SPI1;
-
-	pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
-						mrst_spi_paddr);
-
-	/* Disable SPI controller */
-	dw_writel(pspi, ssienr, 0);
-
-	/* Set control param, 8 bits, transmit only mode */
-	ctrlr0 = dw_readl(pspi, ctrl0);
-
-	ctrlr0 &= 0xfcc0;
-	ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
-		      | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
-	dw_writel(pspi, ctrl0, ctrlr0);
-
-	/*
-	 * Change the spi0 clk to comply with 115200 bps, use 100000 to
-	 * calculate the clk dividor to make the clock a little slower
-	 * than real baud rate.
-	 */
-	dw_writel(pspi, baudr, freq/100000);
-
-	/* Disable all INT for early phase */
-	dw_writel(pspi, imr, 0x0);
-
-	/* Set the cs to spi-uart */
-	dw_writel(pspi, ser, 0x2);
-
-	/* Enable the HW, the last step for HW init */
-	dw_writel(pspi, ssienr, 0x1);
-
-	/* Set the default configuration */
-	max3110_write_config();
-
-	/* Register the kmsg dumper */
-	if (!dumper_registered) {
-		dw_dumper.dump = dw_kmsg_dump;
-		kmsg_dump_register(&dw_dumper);
-		dumper_registered = 1;
-	}
-}
-
-/* Slave select should be called in the read/write function */
-static void early_mrst_spi_putc(char c)
-{
-	unsigned int timeout;
-	u32 sr;
-
-	timeout = MRST_SPI_TIMEOUT;
-	/* Early putc needs to make sure the TX FIFO is not full */
-	while (--timeout) {
-		sr = dw_readl(pspi, sr);
-		if (!(sr & SR_TF_NOT_FULL))
-			cpu_relax();
-		else
-			break;
-	}
-
-	if (!timeout)
-		pr_warn("MRST earlycon: timed out\n");
-	else
-		max3110_write_data(c);
-}
-
-/* Early SPI only uses polling mode */
-static void early_mrst_spi_write(struct console *con, const char *str,
-					unsigned n)
-{
-	int i;
-
-	for (i = 0; i < n && *str; i++) {
-		if (*str == '\n')
-			early_mrst_spi_putc('\r');
-		early_mrst_spi_putc(*str);
-		str++;
-	}
-}
-
-struct console early_mrst_console = {
-	.name =		"earlymrst",
-	.write =	early_mrst_spi_write,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
-};
-
 /*
  * Following is the early console based on Medfield HSU (High
  * Speed UART) device.
@@ -259,7 +47,7 @@
 		port = clamp_val(port, 0, 2);
 
 	paddr = HSU_PORT_BASE + port * 0x80;
-	phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
+	phsu = (void __iomem *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
 
 	/* Disable FIFO */
 	writeb(0x0, phsu + UART_FCR);
diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c
index c6b146e..7488caf 100644
--- a/arch/x86/platform/uv/uv_nmi.c
+++ b/arch/x86/platform/uv/uv_nmi.c
@@ -273,20 +273,6 @@
 	}
 }
 
-/* Print non-responding cpus */
-static void uv_nmi_nr_cpus_pr(char *fmt)
-{
-	static char cpu_list[1024];
-	int len = sizeof(cpu_list);
-	int c = cpumask_weight(uv_nmi_cpu_mask);
-	int n = cpulist_scnprintf(cpu_list, len, uv_nmi_cpu_mask);
-
-	if (n >= len-1)
-		strcpy(&cpu_list[len - 6], "...\n");
-
-	printk(fmt, c, cpu_list);
-}
-
 /* Ping non-responding cpus attemping to force them into the NMI handler */
 static void uv_nmi_nr_cpus_ping(void)
 {
@@ -371,16 +357,19 @@
 			break;
 
 		/* if not all made it in, send IPI NMI to them */
-		uv_nmi_nr_cpus_pr(KERN_ALERT
-			"UV: Sending NMI IPI to %d non-responding CPUs: %s\n");
+		pr_alert("UV: Sending NMI IPI to %d non-responding CPUs: %*pbl\n",
+			 cpumask_weight(uv_nmi_cpu_mask),
+			 cpumask_pr_args(uv_nmi_cpu_mask));
+
 		uv_nmi_nr_cpus_ping();
 
 		/* if all cpus are in, then done */
 		if (!uv_nmi_wait_cpus(0))
 			break;
 
-		uv_nmi_nr_cpus_pr(KERN_ALERT
-			"UV: %d CPUs not in NMI loop: %s\n");
+		pr_alert("UV: %d CPUs not in NMI loop: %*pbl\n",
+			 cpumask_weight(uv_nmi_cpu_mask),
+			 cpumask_pr_args(uv_nmi_cpu_mask));
 	} while (0);
 
 	pr_alert("UV: %d of %d CPUs in NMI\n",
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 6ec7910..3e32ed5 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -105,11 +105,8 @@
 	ctxt->cr0 = read_cr0();
 	ctxt->cr2 = read_cr2();
 	ctxt->cr3 = read_cr3();
-#ifdef CONFIG_X86_32
-	ctxt->cr4 = read_cr4_safe();
-#else
-/* CONFIG_X86_64 */
-	ctxt->cr4 = read_cr4();
+	ctxt->cr4 = __read_cr4_safe();
+#ifdef CONFIG_X86_64
 	ctxt->cr8 = read_cr8();
 #endif
 	ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE,
@@ -175,12 +172,12 @@
 	/* cr4 was introduced in the Pentium CPU */
 #ifdef CONFIG_X86_32
 	if (ctxt->cr4)
-		write_cr4(ctxt->cr4);
+		__write_cr4(ctxt->cr4);
 #else
 /* CONFIG X86_64 */
 	wrmsrl(MSR_EFER, ctxt->efer);
 	write_cr8(ctxt->cr8);
-	write_cr4(ctxt->cr4);
+	__write_cr4(ctxt->cr4);
 #endif
 	write_cr3(ctxt->cr3);
 	write_cr2(ctxt->cr2);
diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile
index 94f7fbe..e02c2c6 100644
--- a/arch/x86/realmode/Makefile
+++ b/arch/x86/realmode/Makefile
@@ -6,7 +6,7 @@
 # for more details.
 #
 #
-
+KASAN_SANITIZE := n
 subdir- := rm
 
 obj-y += init.o
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
index bad628a..0b7a63d 100644
--- a/arch/x86/realmode/init.c
+++ b/arch/x86/realmode/init.c
@@ -81,7 +81,7 @@
 
 	trampoline_header->start = (u64) secondary_startup_64;
 	trampoline_cr4_features = &trampoline_header->cr4;
-	*trampoline_cr4_features = read_cr4();
+	*trampoline_cr4_features = __read_cr4();
 
 	trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
 	trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 7c0d7be..2730d77 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -6,6 +6,7 @@
 # for more details.
 #
 #
+KASAN_SANITIZE := n
 
 always := realmode.bin realmode.relocs
 
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index 09297c8..7b9be98 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -3,6 +3,7 @@
 #
 
 KBUILD_CFLAGS += $(DISABLE_LTO)
+KASAN_SANITIZE := n
 
 VDSO64-$(CONFIG_X86_64)		:= y
 VDSOX32-$(CONFIG_X86_X32_ABI)	:= y
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 78a881b..bd8b845 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1494,10 +1494,10 @@
 	 * set them here. For all, OSFXSR OSXMMEXCPT are set in fpu_init.
 	*/
 	if (cpu_has_pse)
-		set_in_cr4(X86_CR4_PSE);
+		cr4_set_bits_and_update_boot(X86_CR4_PSE);
 
 	if (cpu_has_pge)
-		set_in_cr4(X86_CR4_PGE);
+		cr4_set_bits_and_update_boot(X86_CR4_PGE);
 }
 
 /*
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index f18fd1d..740ae30 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -550,7 +550,7 @@
 		mid_mfn = NULL;
 	}
 
-	p2m_pfn = pte_pfn(ACCESS_ONCE(*ptep));
+	p2m_pfn = pte_pfn(READ_ONCE(*ptep));
 	if (p2m_pfn == PFN_DOWN(__pa(p2m_identity)) ||
 	    p2m_pfn == PFN_DOWN(__pa(p2m_missing))) {
 		/* p2m leaf page is missing */
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 06370cc..28fc57e 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -574,12 +574,9 @@
 static int
 c_show(struct seq_file *f, void *slot)
 {
-	char buf[NR_CPUS * 5];
-
-	cpulist_scnprintf(buf, sizeof(buf), cpu_online_mask);
 	/* high-level stuff */
 	seq_printf(f, "CPU count\t: %u\n"
-		      "CPU list\t: %s\n"
+		      "CPU list\t: %*pbl\n"
 		      "vendor_id\t: Tensilica\n"
 		      "model\t\t: Xtensa " XCHAL_HW_VERSION_NAME "\n"
 		      "core ID\t\t: " XCHAL_CORE_ID "\n"
@@ -588,7 +585,7 @@
 		      "cpu MHz\t\t: %lu.%02lu\n"
 		      "bogomips\t: %lu.%02lu\n",
 		      num_online_cpus(),
-		      buf,
+		      cpumask_pr_args(cpu_online_mask),
 		      XCHAL_BUILD_UNIQUE_ID,
 		      XCHAL_HAVE_BE ?  "big" : "little",
 		      ccount_freq/1000000,
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 87bbc9c..50f4da4 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -427,6 +427,15 @@
 	help
 	  MD5 message digest algorithm (RFC1321).
 
+config CRYPTO_MD5_OCTEON
+	tristate "MD5 digest algorithm (OCTEON)"
+	depends on CPU_CAVIUM_OCTEON
+	select CRYPTO_MD5
+	select CRYPTO_HASH
+	help
+	  MD5 message digest algorithm (RFC1321) implemented
+	  using OCTEON crypto instructions, when available.
+
 config CRYPTO_MD5_SPARC64
 	tristate "MD5 digest algorithm (SPARC64)"
 	depends on SPARC64
@@ -1505,6 +1514,15 @@
 	  This option enables the user-spaces interface for symmetric
 	  key cipher algorithms.
 
+config CRYPTO_USER_API_RNG
+	tristate "User-space interface for random number generator algorithms"
+	depends on NET
+	select CRYPTO_RNG
+	select CRYPTO_USER_API
+	help
+	  This option enables the user-spaces interface for random
+	  number generator algorithms.
+
 config CRYPTO_HASH_INFO
 	bool
 
diff --git a/crypto/Makefile b/crypto/Makefile
index 1445b91..ba19465 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -99,6 +99,7 @@
 obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
 obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
+obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
 
 #
 # generic algorithms and the async_tx api
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index 40886c4..db201bca 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -69,6 +69,7 @@
 static inline u8 *ablkcipher_get_spot(u8 *start, unsigned int len)
 {
 	u8 *end_page = (u8 *)(((unsigned long)(start + len - 1)) & PAGE_MASK);
+
 	return max(start, end_page);
 }
 
@@ -86,7 +87,7 @@
 		if (n == len_this_page)
 			break;
 		n -= len_this_page;
-		scatterwalk_start(&walk->out, scatterwalk_sg_next(walk->out.sg));
+		scatterwalk_start(&walk->out, sg_next(walk->out.sg));
 	}
 
 	return bsize;
@@ -284,6 +285,7 @@
 	walk->iv = req->info;
 	if (unlikely(((unsigned long)walk->iv & alignmask))) {
 		int err = ablkcipher_copy_iv(walk, tfm, alignmask);
+
 		if (err)
 			return err;
 	}
@@ -589,7 +591,8 @@
 	if (IS_ERR(inst))
 		goto put_tmpl;
 
-	if ((err = crypto_register_instance(tmpl, inst))) {
+	err = crypto_register_instance(tmpl, inst);
+	if (err) {
 		tmpl->free(inst);
 		goto put_tmpl;
 	}
diff --git a/crypto/aead.c b/crypto/aead.c
index 547491e..2222710 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -448,7 +448,8 @@
 	if (IS_ERR(inst))
 		goto put_tmpl;
 
-	if ((err = crypto_register_instance(tmpl, inst))) {
+	err = crypto_register_instance(tmpl, inst);
+	if (err) {
 		tmpl->free(inst);
 		goto put_tmpl;
 	}
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 3e80d8b..7f8b7edc 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -188,7 +188,7 @@
 	err = type->setkey(ask->private, key, keylen);
 
 out:
-	sock_kfree_s(sk, key, keylen);
+	sock_kzfree_s(sk, key, keylen);
 
 	return err;
 }
@@ -215,6 +215,13 @@
 			goto unlock;
 
 		err = alg_setkey(sk, optval, optlen);
+		break;
+	case ALG_SET_AEAD_AUTHSIZE:
+		if (sock->state == SS_CONNECTED)
+			goto unlock;
+		if (!type->setauthsize)
+			goto unlock;
+		err = type->setauthsize(ask->private, optlen);
 	}
 
 unlock:
@@ -387,7 +394,7 @@
 		if (cmsg->cmsg_level != SOL_ALG)
 			continue;
 
-		switch(cmsg->cmsg_type) {
+		switch (cmsg->cmsg_type) {
 		case ALG_SET_IV:
 			if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv)))
 				return -EINVAL;
diff --git a/crypto/ahash.c b/crypto/ahash.c
index f6a36a5..8acb88603 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -55,6 +55,7 @@
 
 	if (offset & alignmask) {
 		unsigned int unaligned = alignmask + 1 - (offset & alignmask);
+
 		if (nbytes > unaligned)
 			nbytes = unaligned;
 	}
@@ -120,7 +121,7 @@
 	if (!walk->total)
 		return 0;
 
-	walk->sg = scatterwalk_sg_next(walk->sg);
+	walk->sg = sg_next(walk->sg);
 
 	return hash_walk_new_entry(walk);
 }
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 71a8143..83b04e0 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -473,6 +473,7 @@
 	list = &tmpl->instances;
 	hlist_for_each_entry(inst, list, list) {
 		int err = crypto_remove_alg(&inst->alg, &users);
+
 		BUG_ON(err);
 	}
 
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
new file mode 100644
index 0000000..67f612c
--- /dev/null
+++ b/crypto/algif_rng.c
@@ -0,0 +1,192 @@
+/*
+ * algif_rng: User-space interface for random number generators
+ *
+ * This file provides the user-space API for random number generators.
+ *
+ * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
+ *
+ * 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, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 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 name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL2
+ * are required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <crypto/rng.h>
+#include <linux/random.h>
+#include <crypto/if_alg.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("User-space interface for random number generators");
+
+struct rng_ctx {
+#define MAXSIZE 128
+	unsigned int len;
+	struct crypto_rng *drng;
+};
+
+static int rng_recvmsg(struct kiocb *unused, struct socket *sock,
+		       struct msghdr *msg, size_t len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+	struct rng_ctx *ctx = ask->private;
+	int err = -EFAULT;
+	int genlen = 0;
+	u8 result[MAXSIZE];
+
+	if (len == 0)
+		return 0;
+	if (len > MAXSIZE)
+		len = MAXSIZE;
+
+	/*
+	 * although not strictly needed, this is a precaution against coding
+	 * errors
+	 */
+	memset(result, 0, len);
+
+	/*
+	 * The enforcement of a proper seeding of an RNG is done within an
+	 * RNG implementation. Some RNGs (DRBG, krng) do not need specific
+	 * seeding as they automatically seed. The X9.31 DRNG will return
+	 * an error if it was not seeded properly.
+	 */
+	genlen = crypto_rng_get_bytes(ctx->drng, result, len);
+	if (genlen < 0)
+		return genlen;
+
+	err = memcpy_to_msg(msg, result, len);
+	memzero_explicit(result, genlen);
+
+	return err ? err : len;
+}
+
+static struct proto_ops algif_rng_ops = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.accept		=	sock_no_accept,
+	.setsockopt	=	sock_no_setsockopt,
+	.poll		=	sock_no_poll,
+	.sendmsg	=	sock_no_sendmsg,
+	.sendpage	=	sock_no_sendpage,
+
+	.release	=	af_alg_release,
+	.recvmsg	=	rng_recvmsg,
+};
+
+static void *rng_bind(const char *name, u32 type, u32 mask)
+{
+	return crypto_alloc_rng(name, type, mask);
+}
+
+static void rng_release(void *private)
+{
+	crypto_free_rng(private);
+}
+
+static void rng_sock_destruct(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct rng_ctx *ctx = ask->private;
+
+	sock_kfree_s(sk, ctx, ctx->len);
+	af_alg_release_parent(sk);
+}
+
+static int rng_accept_parent(void *private, struct sock *sk)
+{
+	struct rng_ctx *ctx;
+	struct alg_sock *ask = alg_sk(sk);
+	unsigned int len = sizeof(*ctx);
+
+	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->len = len;
+
+	/*
+	 * No seeding done at that point -- if multiple accepts are
+	 * done on one RNG instance, each resulting FD points to the same
+	 * state of the RNG.
+	 */
+
+	ctx->drng = private;
+	ask->private = ctx;
+	sk->sk_destruct = rng_sock_destruct;
+
+	return 0;
+}
+
+static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
+{
+	/*
+	 * Check whether seedlen is of sufficient size is done in RNG
+	 * implementations.
+	 */
+	return crypto_rng_reset(private, (u8 *)seed, seedlen);
+}
+
+static const struct af_alg_type algif_type_rng = {
+	.bind		=	rng_bind,
+	.release	=	rng_release,
+	.accept		=	rng_accept_parent,
+	.setkey		=	rng_setkey,
+	.ops		=	&algif_rng_ops,
+	.name		=	"rng",
+	.owner		=	THIS_MODULE
+};
+
+static int __init rng_init(void)
+{
+	return af_alg_register_type(&algif_type_rng);
+}
+
+static void __exit rng_exit(void)
+{
+	int err = af_alg_unregister_type(&algif_type_rng);
+	BUG_ON(err);
+}
+
+module_init(rng_init);
+module_exit(rng_exit);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 6fc12c3..0c8a1e5 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -330,6 +330,7 @@
 
 		sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
 		sg = sgl->sg;
+		sg_unmark_end(sg + sgl->cur);
 		do {
 			i = sgl->cur;
 			plen = min_t(int, len, PAGE_SIZE);
@@ -355,6 +356,9 @@
 			sgl->cur++;
 		} while (len && sgl->cur < MAX_SGL_ENTS);
 
+		if (!size)
+			sg_mark_end(sg + sgl->cur - 1);
+
 		ctx->merge = plen & (PAGE_SIZE - 1);
 	}
 
@@ -401,6 +405,10 @@
 	ctx->merge = 0;
 	sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
 
+	if (sgl->cur)
+		sg_unmark_end(sgl->sg + sgl->cur - 1);
+
+	sg_mark_end(sgl->sg + sgl->cur);
 	get_page(page);
 	sg_set_page(sgl->sg + sgl->cur, page, size, offset);
 	sgl->cur++;
diff --git a/crypto/cts.c b/crypto/cts.c
index bd94058..e467ec0 100644
--- a/crypto/cts.c
+++ b/crypto/cts.c
@@ -290,6 +290,9 @@
 	if (!is_power_of_2(alg->cra_blocksize))
 		goto out_put_alg;
 
+	if (strncmp(alg->cra_name, "cbc(", 4))
+		goto out_put_alg;
+
 	inst = crypto_alloc_instance("cts", alg);
 	if (IS_ERR(inst))
 		goto out_put_alg;
@@ -307,8 +310,6 @@
 	inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
 	inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 
-	inst->alg.cra_blkcipher.geniv = "seqiv";
-
 	inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx);
 
 	inst->alg.cra_init = crypto_cts_init_tfm;
diff --git a/crypto/drbg.c b/crypto/drbg.c
index d748a1d..d8ff16e 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -98,7 +98,6 @@
  */
 
 #include <crypto/drbg.h>
-#include <linux/string.h>
 
 /***************************************************************
  * Backend cipher definitions available to DRBG
@@ -223,15 +222,6 @@
  * function. Thus, the function implicitly knows the size of the
  * buffer.
  *
- * The FIPS test can be called in an endless loop until it returns
- * true. Although the code looks like a potential for a deadlock, it
- * is not the case, because returning a false cannot mathematically
- * occur (except once when a reseed took place and the updated state
- * would is now set up such that the generation of new value returns
- * an identical one -- this is most unlikely and would happen only once).
- * Thus, if this function repeatedly returns false and thus would cause
- * a deadlock, the integrity of the entire kernel is lost.
- *
  * @drbg DRBG handle
  * @buf output buffer of random data to be checked
  *
@@ -258,6 +248,8 @@
 		return false;
 	}
 	ret = memcmp(drbg->prev, buf, drbg_blocklen(drbg));
+	if (!ret)
+		panic("DRBG continuous self test failed\n");
 	memcpy(drbg->prev, buf, drbg_blocklen(drbg));
 	/* the test shall pass when the two compared values are not equal */
 	return ret != 0;
@@ -498,9 +490,9 @@
 	ret = 0;
 
 out:
-	memzero_explicit(iv, drbg_blocklen(drbg));
-	memzero_explicit(temp, drbg_statelen(drbg));
-	memzero_explicit(pad, drbg_blocklen(drbg));
+	memset(iv, 0, drbg_blocklen(drbg));
+	memset(temp, 0, drbg_statelen(drbg));
+	memset(pad, 0, drbg_blocklen(drbg));
 	return ret;
 }
 
@@ -574,9 +566,9 @@
 	ret = 0;
 
 out:
-	memzero_explicit(temp, drbg_statelen(drbg) + drbg_blocklen(drbg));
+	memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg));
 	if (2 != reseed)
-		memzero_explicit(df_data, drbg_statelen(drbg));
+		memset(df_data, 0, drbg_statelen(drbg));
 	return ret;
 }
 
@@ -634,7 +626,7 @@
 		len = ret;
 
 out:
-	memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
+	memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
 	return len;
 }
 
@@ -872,7 +864,7 @@
 	}
 
 out:
-	memzero_explicit(tmp, drbg_blocklen(drbg));
+	memset(tmp, 0, drbg_blocklen(drbg));
 	return ret;
 }
 
@@ -916,7 +908,7 @@
 	ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2);
 
 out:
-	memzero_explicit(drbg->scratchpad, drbg_statelen(drbg));
+	memset(drbg->scratchpad, 0, drbg_statelen(drbg));
 	return ret;
 }
 
@@ -951,7 +943,7 @@
 		     drbg->scratchpad, drbg_blocklen(drbg));
 
 out:
-	memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
+	memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
 	return ret;
 }
 
@@ -998,7 +990,7 @@
 	}
 
 out:
-	memzero_explicit(drbg->scratchpad,
+	memset(drbg->scratchpad, 0,
 	       (drbg_statelen(drbg) + drbg_blocklen(drbg)));
 	return len;
 }
@@ -1047,7 +1039,7 @@
 	drbg_add_buf(drbg->V, drbg_statelen(drbg), u.req, 8);
 
 out:
-	memzero_explicit(drbg->scratchpad, drbg_blocklen(drbg));
+	memset(drbg->scratchpad, 0, drbg_blocklen(drbg));
 	return len;
 }
 
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index 79ca227..3bd749c 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -62,7 +62,7 @@
 		walk->offset += PAGE_SIZE - 1;
 		walk->offset &= PAGE_MASK;
 		if (walk->offset >= walk->sg->offset + walk->sg->length)
-			scatterwalk_start(walk, scatterwalk_sg_next(walk->sg));
+			scatterwalk_start(walk, sg_next(walk->sg));
 	}
 }
 
@@ -116,7 +116,7 @@
 			break;
 
 		offset += sg->length;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	scatterwalk_advance(&walk, start - offset);
@@ -136,7 +136,7 @@
 	do {
 		offset += sg->length;
 		n++;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 
 		/* num_bytes is too large */
 		if (unlikely(!sg && (num_bytes < offset)))
diff --git a/crypto/seqiv.c b/crypto/seqiv.c
index 9daa854c..b7bb9a2 100644
--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -267,6 +267,12 @@
 	if (IS_ERR(inst))
 		goto out;
 
+	if (inst->alg.cra_ablkcipher.ivsize < sizeof(u64)) {
+		skcipher_geniv_free(inst);
+		inst = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
 	inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first;
 
 	inst->alg.cra_init = seqiv_init;
@@ -287,6 +293,12 @@
 	if (IS_ERR(inst))
 		goto out;
 
+	if (inst->alg.cra_aead.ivsize < sizeof(u64)) {
+		aead_geniv_free(inst);
+		inst = ERR_PTR(-EINVAL);
+		goto out;
+	}
+
 	inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first;
 
 	inst->alg.cra_init = seqiv_aead_init;
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 1d864e9..4b9e23f 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -250,19 +250,19 @@
 	int np = (buflen + PAGE_SIZE - 1)/PAGE_SIZE;
 	int k, rem;
 
-	np = (np > XBUFSIZE) ? XBUFSIZE : np;
-	rem = buflen % PAGE_SIZE;
 	if (np > XBUFSIZE) {
 		rem = PAGE_SIZE;
 		np = XBUFSIZE;
+	} else {
+		rem = buflen % PAGE_SIZE;
 	}
+
 	sg_init_table(sg, np);
-	for (k = 0; k < np; ++k) {
-		if (k == (np-1))
-			sg_set_buf(&sg[k], xbuf[k], rem);
-		else
-			sg_set_buf(&sg[k], xbuf[k], PAGE_SIZE);
-	}
+	np--;
+	for (k = 0; k < np; k++)
+		sg_set_buf(&sg[k], xbuf[k], PAGE_SIZE);
+
+	sg_set_buf(&sg[k], xbuf[k], rem);
 }
 
 static void test_aead_speed(const char *algo, int enc, unsigned int secs,
@@ -280,16 +280,20 @@
 	struct scatterlist *sgout;
 	const char *e;
 	void *assoc;
-	char iv[MAX_IVLEN];
+	char *iv;
 	char *xbuf[XBUFSIZE];
 	char *xoutbuf[XBUFSIZE];
 	char *axbuf[XBUFSIZE];
 	unsigned int *b_size;
 	unsigned int iv_len;
 
+	iv = kzalloc(MAX_IVLEN, GFP_KERNEL);
+	if (!iv)
+		return;
+
 	if (aad_size >= PAGE_SIZE) {
 		pr_err("associate data length (%u) too big\n", aad_size);
-		return;
+		goto out_noxbuf;
 	}
 
 	if (enc == ENCRYPT)
@@ -355,7 +359,7 @@
 
 			iv_len = crypto_aead_ivsize(tfm);
 			if (iv_len)
-				memset(&iv, 0xff, iv_len);
+				memset(iv, 0xff, iv_len);
 
 			crypto_aead_clear_flags(tfm, ~0);
 			printk(KERN_INFO "test %u (%d bit key, %d byte blocks): ",
@@ -408,6 +412,7 @@
 out_noaxbuf:
 	testmgr_free_buf(xbuf);
 out_noxbuf:
+	kfree(iv);
 	return;
 }
 
@@ -764,10 +769,9 @@
 	if (ret == -EINPROGRESS || ret == -EBUSY) {
 		struct tcrypt_result *tr = req->base.data;
 
-		ret = wait_for_completion_interruptible(&tr->completion);
-		if (!ret)
-			ret = tr->err;
+		wait_for_completion(&tr->completion);
 		reinit_completion(&tr->completion);
+		ret = tr->err;
 	}
 	return ret;
 }
@@ -993,10 +997,9 @@
 	if (ret == -EINPROGRESS || ret == -EBUSY) {
 		struct tcrypt_result *tr = req->base.data;
 
-		ret = wait_for_completion_interruptible(&tr->completion);
-		if (!ret)
-			ret = tr->err;
+		wait_for_completion(&tr->completion);
 		reinit_completion(&tr->completion);
+		ret = tr->err;
 	}
 
 	return ret;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 037368d..f4ed6d4 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -181,10 +181,9 @@
 static int wait_async_op(struct tcrypt_result *tr, int ret)
 {
 	if (ret == -EINPROGRESS || ret == -EBUSY) {
-		ret = wait_for_completion_interruptible(&tr->completion);
-		if (!ret)
-			ret = tr->err;
+		wait_for_completion(&tr->completion);
 		reinit_completion(&tr->completion);
+		ret = tr->err;
 	}
 	return ret;
 }
@@ -353,12 +352,11 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&tresult.completion);
-			if (!ret && !(ret = tresult.err)) {
-				reinit_completion(&tresult.completion);
+			wait_for_completion(&tresult.completion);
+			reinit_completion(&tresult.completion);
+			ret = tresult.err;
+			if (!ret)
 				break;
-			}
 			/* fall through */
 		default:
 			printk(KERN_ERR "alg: hash: digest failed "
@@ -431,7 +429,7 @@
 	struct scatterlist *sgout;
 	const char *e, *d;
 	struct tcrypt_result result;
-	unsigned int authsize;
+	unsigned int authsize, iv_len;
 	void *input;
 	void *output;
 	void *assoc;
@@ -502,10 +500,11 @@
 
 		memcpy(input, template[i].input, template[i].ilen);
 		memcpy(assoc, template[i].assoc, template[i].alen);
+		iv_len = crypto_aead_ivsize(tfm);
 		if (template[i].iv)
-			memcpy(iv, template[i].iv, MAX_IVLEN);
+			memcpy(iv, template[i].iv, iv_len);
 		else
-			memset(iv, 0, MAX_IVLEN);
+			memset(iv, 0, iv_len);
 
 		crypto_aead_clear_flags(tfm, ~0);
 		if (template[i].wk)
@@ -569,12 +568,11 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&result.completion);
-			if (!ret && !(ret = result.err)) {
-				reinit_completion(&result.completion);
+			wait_for_completion(&result.completion);
+			reinit_completion(&result.completion);
+			ret = result.err;
+			if (!ret)
 				break;
-			}
 		case -EBADMSG:
 			if (template[i].novrfy)
 				/* verification failure was expected */
@@ -720,12 +718,11 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&result.completion);
-			if (!ret && !(ret = result.err)) {
-				reinit_completion(&result.completion);
+			wait_for_completion(&result.completion);
+			reinit_completion(&result.completion);
+			ret = result.err;
+			if (!ret)
 				break;
-			}
 		case -EBADMSG:
 			if (template[i].novrfy)
 				/* verification failure was expected */
@@ -1002,12 +999,11 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-				&result.completion);
-			if (!ret && !((ret = result.err))) {
-				reinit_completion(&result.completion);
+			wait_for_completion(&result.completion);
+			reinit_completion(&result.completion);
+			ret = result.err;
+			if (!ret)
 				break;
-			}
 			/* fall through */
 		default:
 			pr_err("alg: skcipher%s: %s failed on test %d for %s: ret=%d\n",
@@ -1097,12 +1093,11 @@
 			break;
 		case -EINPROGRESS:
 		case -EBUSY:
-			ret = wait_for_completion_interruptible(
-					&result.completion);
-			if (!ret && !((ret = result.err))) {
-				reinit_completion(&result.completion);
+			wait_for_completion(&result.completion);
+			reinit_completion(&result.completion);
+			ret = result.err;
+			if (!ret)
 				break;
-			}
 			/* fall through */
 		default:
 			pr_err("alg: skcipher%s: %s failed on chunk test %d for %s: ret=%d\n",
@@ -3299,6 +3294,7 @@
 	}, {
 		.alg = "rfc4106(gcm(aes))",
 		.test = alg_test_aead,
+		.fips_allowed = 1,
 		.suite = {
 			.aead = {
 				.enc = {
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c70d6e4..c0cc96b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -36,8 +36,6 @@
 
 source "drivers/firewire/Kconfig"
 
-source "drivers/message/i2o/Kconfig"
-
 source "drivers/macintosh/Kconfig"
 
 source "drivers/net/Kconfig"
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 8c43521..33b09b6 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -37,6 +37,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/pid_namespace.h>
+#include <linux/security.h>
 
 #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
 #define BINDER_IPC_32BIT 1
@@ -1400,6 +1401,11 @@
 			return_error = BR_DEAD_REPLY;
 			goto err_dead_binder;
 		}
+		if (security_binder_transaction(proc->tsk,
+						target_proc->tsk) < 0) {
+			return_error = BR_FAILED_REPLY;
+			goto err_invalid_target_handle;
+		}
 		if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
 			struct binder_transaction *tmp;
 
@@ -1551,6 +1557,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_for_node_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk,
+							    target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_for_node_failed;
+			}
 			ref = binder_get_ref_for_node(target_proc, node);
 			if (ref == NULL) {
 				return_error = BR_FAILED_REPLY;
@@ -1581,6 +1592,11 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_binder_get_ref_failed;
 			}
+			if (security_binder_transfer_binder(proc->tsk,
+							    target_proc->tsk)) {
+				return_error = BR_FAILED_REPLY;
+				goto err_binder_get_ref_failed;
+			}
 			if (ref->node->proc == target_proc) {
 				if (fp->type == BINDER_TYPE_HANDLE)
 					fp->type = BINDER_TYPE_BINDER;
@@ -1638,6 +1654,13 @@
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
 			}
+			if (security_binder_transfer_file(proc->tsk,
+							  target_proc->tsk,
+							  file) < 0) {
+				fput(file);
+				return_error = BR_FAILED_REPLY;
+				goto err_get_unused_fd_failed;
+			}
 			target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
 			if (target_fd < 0) {
 				fput(file);
@@ -2675,6 +2698,9 @@
 		ret = -EBUSY;
 		goto out;
 	}
+	ret = security_binder_set_context_mgr(proc->tsk);
+	if (ret < 0)
+		goto out;
 	if (uid_valid(binder_context_mgr_uid)) {
 		if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
 			pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 97e2baf..07304a3 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2080,54 +2080,47 @@
 }
 EXPORT_SYMBOL(dev_printk_emit);
 
-static int __dev_printk(const char *level, const struct device *dev,
+static void __dev_printk(const char *level, const struct device *dev,
 			struct va_format *vaf)
 {
-	if (!dev)
-		return printk("%s(NULL device *): %pV", level, vaf);
-
-	return dev_printk_emit(level[1] - '0', dev,
-			       "%s %s: %pV",
-			       dev_driver_string(dev), dev_name(dev), vaf);
+	if (dev)
+		dev_printk_emit(level[1] - '0', dev, "%s %s: %pV",
+				dev_driver_string(dev), dev_name(dev), vaf);
+	else
+		printk("%s(NULL device *): %pV", level, vaf);
 }
 
-int dev_printk(const char *level, const struct device *dev,
-	       const char *fmt, ...)
+void dev_printk(const char *level, const struct device *dev,
+		const char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list args;
-	int r;
 
 	va_start(args, fmt);
 
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	r = __dev_printk(level, dev, &vaf);
+	__dev_printk(level, dev, &vaf);
 
 	va_end(args);
-
-	return r;
 }
 EXPORT_SYMBOL(dev_printk);
 
 #define define_dev_printk_level(func, kern_level)		\
-int func(const struct device *dev, const char *fmt, ...)	\
+void func(const struct device *dev, const char *fmt, ...)	\
 {								\
 	struct va_format vaf;					\
 	va_list args;						\
-	int r;							\
 								\
 	va_start(args, fmt);					\
 								\
 	vaf.fmt = fmt;						\
 	vaf.va = &args;						\
 								\
-	r = __dev_printk(kern_level, dev, &vaf);		\
+	__dev_printk(kern_level, dev, &vaf);			\
 								\
 	va_end(args);						\
-								\
-	return r;						\
 }								\
 EXPORT_SYMBOL(func);
 
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f829a4c..f160ea4 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -245,7 +245,7 @@
 	if (!alloc_cpumask_var(&offline, GFP_KERNEL))
 		return -ENOMEM;
 	cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask);
-	n = cpulist_scnprintf(buf, len, offline);
+	n = scnprintf(buf, len, "%*pbl", cpumask_pr_args(offline));
 	free_cpumask_var(offline);
 
 	/* display offline cpus >= nr_cpu_ids */
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index c3293f0..6c5c9ed 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -94,7 +94,7 @@
 
 static inline long firmware_loading_timeout(void)
 {
-	return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+	return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET;
 }
 
 /* firmware behavior options */
@@ -446,7 +446,6 @@
  */
 #ifdef CONFIG_FW_LOADER_USER_HELPER
 struct firmware_priv {
-	struct delayed_work timeout_work;
 	bool nowait;
 	struct device dev;
 	struct firmware_buf *buf;
@@ -836,16 +835,6 @@
 	.write = firmware_data_write,
 };
 
-static void firmware_class_timeout_work(struct work_struct *work)
-{
-	struct firmware_priv *fw_priv = container_of(work,
-			struct firmware_priv, timeout_work.work);
-
-	mutex_lock(&fw_lock);
-	fw_load_abort(fw_priv);
-	mutex_unlock(&fw_lock);
-}
-
 static struct firmware_priv *
 fw_create_instance(struct firmware *firmware, const char *fw_name,
 		   struct device *device, unsigned int opt_flags)
@@ -861,9 +850,6 @@
 
 	fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT);
 	fw_priv->fw = firmware;
-	INIT_DELAYED_WORK(&fw_priv->timeout_work,
-		firmware_class_timeout_work);
-
 	f_dev = &fw_priv->dev;
 
 	device_initialize(f_dev);
@@ -916,16 +902,19 @@
 		buf->need_uevent = true;
 		dev_set_uevent_suppress(f_dev, false);
 		dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
-		if (timeout != MAX_SCHEDULE_TIMEOUT)
-			queue_delayed_work(system_power_efficient_wq,
-					   &fw_priv->timeout_work, timeout);
-
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+	} else {
+		timeout = MAX_JIFFY_OFFSET;
 	}
 
-	retval = wait_for_completion_interruptible(&buf->completion);
+	retval = wait_for_completion_interruptible_timeout(&buf->completion,
+			timeout);
+	if (retval == -ERESTARTSYS || !retval) {
+		mutex_lock(&fw_lock);
+		fw_load_abort(fw_priv);
+		mutex_unlock(&fw_lock);
+	}
 
-	cancel_delayed_work_sync(&fw_priv->timeout_work);
 	if (is_fw_load_aborted(buf))
 		retval = -EAGAIN;
 	else if (!buf->data)
@@ -1193,7 +1182,7 @@
 EXPORT_SYMBOL(request_firmware);
 
 /**
- * request_firmware: - load firmware directly without usermode helper
+ * request_firmware_direct: - load firmware directly without usermode helper
  * @firmware_p: pointer to firmware image
  * @name: name of firmware file
  * @device: device for which firmware is being loaded
diff --git a/drivers/base/node.c b/drivers/base/node.c
index a3b82e9..36fabe43 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -605,7 +605,8 @@
 {
 	int n;
 
-	n = nodelist_scnprintf(buf, PAGE_SIZE-2, node_states[state]);
+	n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+		      nodemask_pr_args(&node_states[state]));
 	buf[n++] = '\n';
 	buf[n] = '\0';
 	return n;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 014a1cf..1b8094d 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -393,14 +393,15 @@
 	  The default value is 4096 kilobytes. Only change this if you know
 	  what you are doing.
 
-config BLK_DEV_XIP
-	bool "Support XIP filesystems on RAM block device"
-	depends on BLK_DEV_RAM
+config BLK_DEV_RAM_DAX
+	bool "Support Direct Access (DAX) to RAM block devices"
+	depends on BLK_DEV_RAM && FS_DAX
 	default n
 	help
-	  Support XIP filesystems (such as ext2 with XIP support on) on
-	  top of block ram device. This will slightly enlarge the kernel, and
-	  will prevent RAM block device backing store memory from being
+	  Support filesystems using DAX to access RAM block devices.  This
+	  avoids double-buffering data in the page cache before copying it
+	  to the block device.  Answering Y will slightly enlarge the kernel,
+	  and will prevent RAM block device backing store memory from being
 	  allocated from highmem (only a problem for highmem systems).
 
 config CDROM_PKTCDVD
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index c01b921..64ab495 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -97,13 +97,13 @@
 	 * Must use NOIO because we don't want to recurse back into the
 	 * block or filesystem layers from page reclaim.
 	 *
-	 * Cannot support XIP and highmem, because our ->direct_access
-	 * routine for XIP must return memory that is always addressable.
-	 * If XIP was reworked to use pfns and kmap throughout, this
+	 * Cannot support DAX and highmem, because our ->direct_access
+	 * routine for DAX must return memory that is always addressable.
+	 * If DAX was reworked to use pfns and kmap throughout, this
 	 * restriction might be able to be lifted.
 	 */
 	gfp_flags = GFP_NOIO | __GFP_ZERO;
-#ifndef CONFIG_BLK_DEV_XIP
+#ifndef CONFIG_BLK_DEV_RAM_DAX
 	gfp_flags |= __GFP_HIGHMEM;
 #endif
 	page = alloc_page(gfp_flags);
@@ -369,7 +369,7 @@
 	return err;
 }
 
-#ifdef CONFIG_BLK_DEV_XIP
+#ifdef CONFIG_BLK_DEV_RAM_DAX
 static long brd_direct_access(struct block_device *bdev, sector_t sector,
 			void **kaddr, unsigned long *pfn, long size)
 {
@@ -390,6 +390,8 @@
 	 */
 	return PAGE_SIZE;
 }
+#else
+#define brd_direct_access NULL
 #endif
 
 static int brd_ioctl(struct block_device *bdev, fmode_t mode,
@@ -430,9 +432,7 @@
 	.owner =		THIS_MODULE,
 	.rw_page =		brd_rw_page,
 	.ioctl =		brd_ioctl,
-#ifdef CONFIG_BLK_DEV_XIP
 	.direct_access =	brd_direct_access,
-#endif
 };
 
 /*
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 2ff6dfd..9c4dcf4 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -51,33 +51,22 @@
 
 static int ath_wakeup_ar3k(struct tty_struct *tty)
 {
-	struct ktermios ktermios;
 	int status = tty->driver->ops->tiocmget(tty);
 
 	if (status & TIOCM_CTS)
 		return status;
 
-	/* Disable Automatic RTSCTS */
-	ktermios = tty->termios;
-	ktermios.c_cflag &= ~CRTSCTS;
-	tty_set_termios(tty, &ktermios);
-
 	/* Clear RTS first */
-	status = tty->driver->ops->tiocmget(tty);
+	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
 	mdelay(20);
 
 	/* Set RTS, wake up board */
-	status = tty->driver->ops->tiocmget(tty);
+	tty->driver->ops->tiocmget(tty);
 	tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
 	mdelay(20);
 
 	status = tty->driver->ops->tiocmget(tty);
-
-	/* Enable Automatic RTSCTS */
-	ktermios.c_cflag |= CRTSCTS;
-	status = tty_set_termios(tty, &ktermios);
-
 	return status;
 }
 
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 0ce5e2d..84fd660 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -806,8 +806,8 @@
 static ssize_t pmu_attr_cpumask_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
-	int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &pmu->cpus);
-
+	int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+			  cpumask_pr_args(&pmu->cpus));
 	buf[n++] = '\n';
 	buf[n] = '\0';
 	return n;
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 81bf297..fb9ec62 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -58,6 +58,7 @@
 #include <linux/debugfs.h>
 #include <linux/log2.h>
 #include <linux/syscore_ops.h>
+#include <linux/memblock.h>
 
 /*
  * DDR target is the same on all platforms.
@@ -69,6 +70,7 @@
  */
 #define WIN_CTRL_OFF		0x0000
 #define   WIN_CTRL_ENABLE       BIT(0)
+#define   WIN_CTRL_SYNCBARRIER  BIT(1)
 #define   WIN_CTRL_TGT_MASK     0xf0
 #define   WIN_CTRL_TGT_SHIFT    4
 #define   WIN_CTRL_ATTR_MASK    0xff00
@@ -82,6 +84,9 @@
 #define   WIN_REMAP_LOW         0xffff0000
 #define WIN_REMAP_HI_OFF	0x000c
 
+#define UNIT_SYNC_BARRIER_OFF   0x84
+#define   UNIT_SYNC_BARRIER_ALL 0xFFFF
+
 #define ATTR_HW_COHERENCY	(0x1 << 4)
 
 #define DDR_BASE_CS_OFF(n)	(0x0000 + ((n) << 3))
@@ -97,7 +102,9 @@
 
 /* Relative to mbusbridge_base */
 #define MBUS_BRIDGE_CTRL_OFF	0x0
+#define  MBUS_BRIDGE_SIZE_MASK  0xffff0000
 #define MBUS_BRIDGE_BASE_OFF	0x4
+#define  MBUS_BRIDGE_BASE_MASK  0xffff0000
 
 /* Maximum number of windows, for all known platforms */
 #define MBUS_WINS_MAX           20
@@ -106,9 +113,9 @@
 
 struct mvebu_mbus_soc_data {
 	unsigned int num_wins;
-	unsigned int num_remappable_wins;
 	bool has_mbus_bridge;
 	unsigned int (*win_cfg_offset)(const int win);
+	unsigned int (*win_remap_offset)(const int win);
 	void (*setup_cpu_target)(struct mvebu_mbus_state *s);
 	int (*save_cpu_target)(struct mvebu_mbus_state *s,
 			       u32 *store_addr);
@@ -154,6 +161,13 @@
 }
 EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
 
+/* Checks whether the given window has remap capability */
+static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus,
+					    const int win)
+{
+	return mbus->soc->win_remap_offset(win) != MVEBU_MBUS_NO_REMAP;
+}
+
 /*
  * Functions to manipulate the address decoding windows
  */
@@ -185,9 +199,12 @@
 		*attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
 
 	if (remap) {
-		if (win < mbus->soc->num_remappable_wins) {
-			u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
-			u32 remap_hi  = readl(addr + WIN_REMAP_HI_OFF);
+		if (mvebu_mbus_window_is_remappable(mbus, win)) {
+			u32 remap_low, remap_hi;
+			void __iomem *addr_rmp = mbus->mbuswins_base +
+				mbus->soc->win_remap_offset(win);
+			remap_low = readl(addr_rmp + WIN_REMAP_LO_OFF);
+			remap_hi  = readl(addr_rmp + WIN_REMAP_HI_OFF);
 			*remap = ((u64)remap_hi << 32) | remap_low;
 		} else
 			*remap = 0;
@@ -200,10 +217,11 @@
 	void __iomem *addr;
 
 	addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
-
 	writel(0, addr + WIN_BASE_OFF);
 	writel(0, addr + WIN_CTRL_OFF);
-	if (win < mbus->soc->num_remappable_wins) {
+
+	if (mvebu_mbus_window_is_remappable(mbus, win)) {
+		addr = mbus->mbuswins_base + mbus->soc->win_remap_offset(win);
 		writel(0, addr + WIN_REMAP_LO_OFF);
 		writel(0, addr + WIN_REMAP_HI_OFF);
 	}
@@ -211,14 +229,6 @@
 
 /* Checks whether the given window number is available */
 
-/* On Armada XP, 375 and 38x the MBus window 13 has the remap
- * capability, like windows 0 to 7. However, the mvebu-mbus driver
- * isn't currently taking into account this special case, which means
- * that when window 13 is actually used, the remap registers are left
- * to 0, making the device using this MBus window unavailable. The
- * quick fix for stable is to not use window 13. A follow up patch
- * will correctly handle this window.
-*/
 static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
 				     const int win)
 {
@@ -226,9 +236,6 @@
 		mbus->soc->win_cfg_offset(win);
 	u32 ctrl = readl(addr + WIN_CTRL_OFF);
 
-	if (win == 13)
-		return false;
-
 	return !(ctrl & WIN_CTRL_ENABLE);
 }
 
@@ -316,17 +323,22 @@
 	ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
 		(attr << WIN_CTRL_ATTR_SHIFT)    |
 		(target << WIN_CTRL_TGT_SHIFT)   |
+		WIN_CTRL_SYNCBARRIER             |
 		WIN_CTRL_ENABLE;
 
 	writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
 	writel(ctrl, addr + WIN_CTRL_OFF);
-	if (win < mbus->soc->num_remappable_wins) {
+
+	if (mvebu_mbus_window_is_remappable(mbus, win)) {
+		void __iomem *addr_rmp = mbus->mbuswins_base +
+			mbus->soc->win_remap_offset(win);
+
 		if (remap == MVEBU_MBUS_NO_REMAP)
 			remap_addr = base;
 		else
 			remap_addr = remap;
-		writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
-		writel(0, addr + WIN_REMAP_HI_OFF);
+		writel(remap_addr & WIN_REMAP_LOW, addr_rmp + WIN_REMAP_LO_OFF);
+		writel(0, addr_rmp + WIN_REMAP_HI_OFF);
 	}
 
 	return 0;
@@ -340,19 +352,27 @@
 	int win;
 
 	if (remap == MVEBU_MBUS_NO_REMAP) {
-		for (win = mbus->soc->num_remappable_wins;
-		     win < mbus->soc->num_wins; win++)
+		for (win = 0; win < mbus->soc->num_wins; win++) {
+			if (mvebu_mbus_window_is_remappable(mbus, win))
+				continue;
+
 			if (mvebu_mbus_window_is_free(mbus, win))
 				return mvebu_mbus_setup_window(mbus, win, base,
 							       size, remap,
 							       target, attr);
+		}
 	}
 
+	for (win = 0; win < mbus->soc->num_wins; win++) {
+		/* Skip window if need remap but is not supported */
+		if ((remap != MVEBU_MBUS_NO_REMAP) &&
+		    !mvebu_mbus_window_is_remappable(mbus, win))
+			continue;
 
-	for (win = 0; win < mbus->soc->num_wins; win++)
 		if (mvebu_mbus_window_is_free(mbus, win))
 			return mvebu_mbus_setup_window(mbus, win, base, size,
 						       remap, target, attr);
+	}
 
 	return -ENOMEM;
 }
@@ -464,7 +484,7 @@
 		    ((wbase & (u64)(wsize - 1)) != 0))
 			seq_puts(seq, " (Invalid base/size!!)");
 
-		if (win < mbus->soc->num_remappable_wins) {
+		if (mvebu_mbus_window_is_remappable(mbus, win)) {
 			seq_printf(seq, " (remap %016llx)\n",
 				   (unsigned long long)wremap);
 		} else
@@ -490,12 +510,12 @@
  * SoC-specific functions and definitions
  */
 
-static unsigned int orion_mbus_win_offset(int win)
+static unsigned int generic_mbus_win_cfg_offset(int win)
 {
 	return win << 4;
 }
 
-static unsigned int armada_370_xp_mbus_win_offset(int win)
+static unsigned int armada_370_xp_mbus_win_cfg_offset(int win)
 {
 	/* The register layout is a bit annoying and the below code
 	 * tries to cope with it.
@@ -515,7 +535,7 @@
 		return 0x90 + ((win - 8) << 3);
 }
 
-static unsigned int mv78xx0_mbus_win_offset(int win)
+static unsigned int mv78xx0_mbus_win_cfg_offset(int win)
 {
 	if (win < 8)
 		return win << 4;
@@ -523,36 +543,140 @@
 		return 0x900 + ((win - 8) << 4);
 }
 
+static unsigned int generic_mbus_win_remap_2_offset(int win)
+{
+	if (win < 2)
+		return generic_mbus_win_cfg_offset(win);
+	else
+		return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int generic_mbus_win_remap_4_offset(int win)
+{
+	if (win < 4)
+		return generic_mbus_win_cfg_offset(win);
+	else
+		return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int generic_mbus_win_remap_8_offset(int win)
+{
+	if (win < 8)
+		return generic_mbus_win_cfg_offset(win);
+	else
+		return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int armada_xp_mbus_win_remap_offset(int win)
+{
+	if (win < 8)
+		return generic_mbus_win_cfg_offset(win);
+	else if (win == 13)
+		return 0xF0 - WIN_REMAP_LO_OFF;
+	else
+		return MVEBU_MBUS_NO_REMAP;
+}
+
+/*
+ * Use the memblock information to find the MBus bridge hole in the
+ * physical address space.
+ */
+static void __init
+mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
+{
+	struct memblock_region *r;
+	uint64_t s = 0;
+
+	for_each_memblock(memory, r) {
+		/*
+		 * This part of the memory is above 4 GB, so we don't
+		 * care for the MBus bridge hole.
+		 */
+		if (r->base >= 0x100000000)
+			continue;
+
+		/*
+		 * The MBus bridge hole is at the end of the RAM under
+		 * the 4 GB limit.
+		 */
+		if (r->base + r->size > s)
+			s = r->base + r->size;
+	}
+
+	*start = s;
+	*end = 0x100000000;
+}
+
 static void __init
 mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
 {
 	int i;
 	int cs;
+	uint64_t mbus_bridge_base, mbus_bridge_end;
 
 	mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
 
+	mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end);
+
 	for (i = 0, cs = 0; i < 4; i++) {
-		u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
-		u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+		u64 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
+		u64 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+		u64 end;
+		struct mbus_dram_window *w;
+
+		/* Ignore entries that are not enabled */
+		if (!(size & DDR_SIZE_ENABLED))
+			continue;
 
 		/*
-		 * We only take care of entries for which the chip
-		 * select is enabled, and that don't have high base
-		 * address bits set (devices can only access the first
-		 * 32 bits of the memory).
+		 * Ignore entries whose base address is above 2^32,
+		 * since devices cannot DMA to such high addresses
 		 */
-		if ((size & DDR_SIZE_ENABLED) &&
-		    !(base & DDR_BASE_CS_HIGH_MASK)) {
-			struct mbus_dram_window *w;
+		if (base & DDR_BASE_CS_HIGH_MASK)
+			continue;
 
-			w = &mvebu_mbus_dram_info.cs[cs++];
-			w->cs_index = i;
-			w->mbus_attr = 0xf & ~(1 << i);
-			if (mbus->hw_io_coherency)
-				w->mbus_attr |= ATTR_HW_COHERENCY;
-			w->base = base & DDR_BASE_CS_LOW_MASK;
-			w->size = (size | ~DDR_SIZE_MASK) + 1;
+		base = base & DDR_BASE_CS_LOW_MASK;
+		size = (size | ~DDR_SIZE_MASK) + 1;
+		end = base + size;
+
+		/*
+		 * Adjust base/size of the current CS to make sure it
+		 * doesn't overlap with the MBus bridge hole. This is
+		 * particularly important for devices that do DMA from
+		 * DRAM to a SRAM mapped in a MBus window, such as the
+		 * CESA cryptographic engine.
+		 */
+
+		/*
+		 * The CS is fully enclosed inside the MBus bridge
+		 * area, so ignore it.
+		 */
+		if (base >= mbus_bridge_base && end <= mbus_bridge_end)
+			continue;
+
+		/*
+		 * Beginning of CS overlaps with end of MBus, raise CS
+		 * base address, and shrink its size.
+		 */
+		if (base >= mbus_bridge_base && end > mbus_bridge_end) {
+			size -= mbus_bridge_end - base;
+			base = mbus_bridge_end;
 		}
+
+		/*
+		 * End of CS overlaps with beginning of MBus, shrink
+		 * CS size.
+		 */
+		if (base < mbus_bridge_base && end > mbus_bridge_base)
+			size -= end - mbus_bridge_base;
+
+		w = &mvebu_mbus_dram_info.cs[cs++];
+		w->cs_index = i;
+		w->mbus_attr = 0xf & ~(1 << i);
+		if (mbus->hw_io_coherency)
+			w->mbus_attr |= ATTR_HW_COHERENCY;
+		w->base = base;
+		w->size = size;
 	}
 	mvebu_mbus_dram_info.num_cs = cs;
 }
@@ -632,30 +756,40 @@
 	return mbus_state.soc->save_cpu_target(&mbus_state, store_addr);
 }
 
-static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = {
+static const struct mvebu_mbus_soc_data armada_370_mbus_data = {
 	.num_wins            = 20,
-	.num_remappable_wins = 8,
 	.has_mbus_bridge     = true,
-	.win_cfg_offset      = armada_370_xp_mbus_win_offset,
-	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+	.win_cfg_offset      = armada_370_xp_mbus_win_cfg_offset,
+	.win_remap_offset    = generic_mbus_win_remap_8_offset,
 	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_orion,
+	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+};
+
+static const struct mvebu_mbus_soc_data armada_xp_mbus_data = {
+	.num_wins            = 20,
+	.has_mbus_bridge     = true,
+	.win_cfg_offset      = armada_370_xp_mbus_win_cfg_offset,
+	.win_remap_offset    = armada_xp_mbus_win_remap_offset,
+	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
+	.show_cpu_target     = mvebu_sdram_debug_show_orion,
+	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
 };
 
 static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
 	.num_wins            = 8,
-	.num_remappable_wins = 4,
-	.win_cfg_offset      = orion_mbus_win_offset,
+	.win_cfg_offset      = generic_mbus_win_cfg_offset,
 	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+	.win_remap_offset    = generic_mbus_win_remap_4_offset,
 	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_orion,
 };
 
 static const struct mvebu_mbus_soc_data dove_mbus_data = {
 	.num_wins            = 8,
-	.num_remappable_wins = 4,
-	.win_cfg_offset      = orion_mbus_win_offset,
+	.win_cfg_offset      = generic_mbus_win_cfg_offset,
 	.save_cpu_target     = mvebu_mbus_dove_save_cpu_target,
+	.win_remap_offset    = generic_mbus_win_remap_4_offset,
 	.setup_cpu_target    = mvebu_mbus_dove_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_dove,
 };
@@ -666,36 +800,40 @@
  */
 static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
 	.num_wins            = 8,
-	.num_remappable_wins = 4,
-	.win_cfg_offset      = orion_mbus_win_offset,
+	.win_cfg_offset      = generic_mbus_win_cfg_offset,
 	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+	.win_remap_offset    = generic_mbus_win_remap_4_offset,
 	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_orion,
 };
 
 static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
 	.num_wins            = 8,
-	.num_remappable_wins = 2,
-	.win_cfg_offset      = orion_mbus_win_offset,
+	.win_cfg_offset      = generic_mbus_win_cfg_offset,
 	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+	.win_remap_offset    = generic_mbus_win_remap_2_offset,
 	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_orion,
 };
 
 static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
 	.num_wins            = 14,
-	.num_remappable_wins = 8,
-	.win_cfg_offset      = mv78xx0_mbus_win_offset,
+	.win_cfg_offset      = mv78xx0_mbus_win_cfg_offset,
 	.save_cpu_target     = mvebu_mbus_default_save_cpu_target,
+	.win_remap_offset    = generic_mbus_win_remap_8_offset,
 	.setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 	.show_cpu_target     = mvebu_sdram_debug_show_orion,
 };
 
 static const struct of_device_id of_mvebu_mbus_ids[] = {
 	{ .compatible = "marvell,armada370-mbus",
-	  .data = &armada_370_xp_mbus_data, },
+	  .data = &armada_370_mbus_data, },
+	{ .compatible = "marvell,armada375-mbus",
+	  .data = &armada_xp_mbus_data, },
+	{ .compatible = "marvell,armada380-mbus",
+	  .data = &armada_xp_mbus_data, },
 	{ .compatible = "marvell,armadaxp-mbus",
-	  .data = &armada_370_xp_mbus_data, },
+	  .data = &armada_xp_mbus_data, },
 	{ .compatible = "marvell,kirkwood-mbus",
 	  .data = &kirkwood_mbus_data, },
 	{ .compatible = "marvell,dove-mbus",
@@ -802,15 +940,19 @@
 	for (win = 0; win < s->soc->num_wins; win++) {
 		void __iomem *addr = s->mbuswins_base +
 			s->soc->win_cfg_offset(win);
+		void __iomem *addr_rmp;
 
 		s->wins[win].base = readl(addr + WIN_BASE_OFF);
 		s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF);
 
-		if (win >= s->soc->num_remappable_wins)
+		if (!mvebu_mbus_window_is_remappable(s, win))
 			continue;
 
-		s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
-		s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
+		addr_rmp = s->mbuswins_base +
+			s->soc->win_remap_offset(win);
+
+		s->wins[win].remap_lo = readl(addr_rmp + WIN_REMAP_LO_OFF);
+		s->wins[win].remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF);
 	}
 
 	s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
@@ -834,15 +976,19 @@
 	for (win = 0; win < s->soc->num_wins; win++) {
 		void __iomem *addr = s->mbuswins_base +
 			s->soc->win_cfg_offset(win);
+		void __iomem *addr_rmp;
 
 		writel(s->wins[win].base, addr + WIN_BASE_OFF);
 		writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF);
 
-		if (win >= s->soc->num_remappable_wins)
+		if (!mvebu_mbus_window_is_remappable(s, win))
 			continue;
 
-		writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
-		writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
+		addr_rmp = s->mbuswins_base +
+			s->soc->win_remap_offset(win);
+
+		writel(s->wins[win].remap_lo, addr_rmp + WIN_REMAP_LO_OFF);
+		writel(s->wins[win].remap_hi, addr_rmp + WIN_REMAP_HI_OFF);
 	}
 }
 
@@ -857,7 +1003,8 @@
 					 phys_addr_t sdramwins_phys_base,
 					 size_t sdramwins_size,
 					 phys_addr_t mbusbridge_phys_base,
-					 size_t mbusbridge_size)
+					 size_t mbusbridge_size,
+					 bool is_coherent)
 {
 	int win;
 
@@ -889,6 +1036,10 @@
 
 	mbus->soc->setup_cpu_target(mbus);
 
+	if (is_coherent)
+		writel(UNIT_SYNC_BARRIER_ALL,
+		       mbus->mbuswins_base + UNIT_SYNC_BARRIER_OFF);
+
 	register_syscore_ops(&mvebu_mbus_syscore_ops);
 
 	return 0;
@@ -916,7 +1067,7 @@
 			mbuswins_phys_base,
 			mbuswins_size,
 			sdramwins_phys_base,
-			sdramwins_size, 0, 0);
+			sdramwins_size, 0, 0, false);
 }
 
 #ifdef CONFIG_OF
@@ -1118,7 +1269,8 @@
 				     sdramwins_res.start,
 				     resource_size(&sdramwins_res),
 				     mbusbridge_res.start,
-				     resource_size(&mbusbridge_res));
+				     resource_size(&mbusbridge_res),
+				     is_coherent);
 	if (ret)
 		return ret;
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index efefd12..a4af822 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -6,6 +6,15 @@
 
 source "drivers/tty/Kconfig"
 
+config DEVMEM
+	bool "/dev/mem virtual device support"
+	default y
+	help
+	  Say Y here if you want to support the /dev/mem device.
+	  The /dev/mem device is used to access areas of physical
+	  memory.
+	  When in doubt, say "Y".
+
 config DEVKMEM
 	bool "/dev/kmem virtual device support"
 	default y
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index b709749..4eb1c77 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -219,7 +219,10 @@
 /* generic functions for user-populated AGP memory types */
 struct agp_memory *agp_generic_alloc_user(size_t page_count, int type);
 void agp_alloc_page_array(size_t size, struct agp_memory *mem);
-void agp_free_page_array(struct agp_memory *mem);
+static inline void agp_free_page_array(struct agp_memory *mem)
+{
+	kvfree(mem->pages);
+}
 
 
 /* generic routines for agp>=3 */
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 0fbccce..f002fa5 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -98,17 +98,6 @@
 }
 EXPORT_SYMBOL(agp_alloc_page_array);
 
-void agp_free_page_array(struct agp_memory *mem)
-{
-	if (is_vmalloc_addr(mem->pages)) {
-		vfree(mem->pages);
-	} else {
-		kfree(mem->pages);
-	}
-}
-EXPORT_SYMBOL(agp_free_page_array);
-
-
 static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
 {
 	struct agp_memory *new;
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 92aa43f..0b4188b 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -225,7 +225,7 @@
 		intel_private.driver->write_entry(addr,
 						  i, type);
 	}
-	readl(intel_private.gtt+i-1);
+	wmb();
 
 	return 0;
 }
@@ -329,7 +329,7 @@
 		break;
 	}
 
-	writel(addr | pte_flags, intel_private.gtt + entry);
+	writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
 }
 
 static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
@@ -735,7 +735,7 @@
 	if (flags ==  AGP_USER_CACHED_MEMORY)
 		pte_flags |= I830_PTE_SYSTEM_CACHED;
 
-	writel(addr | pte_flags, intel_private.gtt + entry);
+	writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
 }
 
 bool intel_enable_gtt(void)
@@ -858,7 +858,7 @@
 			j++;
 		}
 	}
-	readl(intel_private.gtt+j-1);
+	wmb();
 }
 EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
 
@@ -875,7 +875,7 @@
 		intel_private.driver->write_entry(addr,
 						  j, flags);
 	}
-	readl(intel_private.gtt+j-1);
+	wmb();
 }
 
 static int intel_fake_agp_insert_entries(struct agp_memory *mem,
@@ -938,7 +938,7 @@
 		intel_private.driver->write_entry(intel_private.scratch_page_dma,
 						  i, 0);
 	}
-	readl(intel_private.gtt+i-1);
+	wmb();
 }
 EXPORT_SYMBOL(intel_gtt_clear_range);
 
@@ -1106,7 +1106,7 @@
 
 	/* Shift high bits down */
 	addr |= (addr >> 28) & 0xf0;
-	writel(addr | pte_flags, intel_private.gtt + entry);
+	writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
 }
 
 static int i9xx_setup(void)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1500cfd..32a8a86 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/err.h>
 #include <asm/uaccess.h>
 
 
@@ -53,7 +54,10 @@
 static struct hwrng *current_rng;
 static struct task_struct *hwrng_fill;
 static LIST_HEAD(rng_list);
+/* Protects rng_list and current_rng */
 static DEFINE_MUTEX(rng_mutex);
+/* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */
+static DEFINE_MUTEX(reading_mutex);
 static int data_avail;
 static u8 *rng_buffer, *rng_fillbuf;
 static unsigned short current_quality;
@@ -66,6 +70,8 @@
 MODULE_PARM_DESC(default_quality,
 		 "default entropy content of hwrng per mill");
 
+static void drop_current_rng(void);
+static int hwrng_init(struct hwrng *rng);
 static void start_khwrngd(void);
 
 static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
@@ -81,13 +87,83 @@
 	unsigned char bytes[16];
 	int bytes_read;
 
+	mutex_lock(&reading_mutex);
 	bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+	mutex_unlock(&reading_mutex);
 	if (bytes_read > 0)
 		add_device_randomness(bytes, bytes_read);
 }
 
-static inline int hwrng_init(struct hwrng *rng)
+static inline void cleanup_rng(struct kref *kref)
 {
+	struct hwrng *rng = container_of(kref, struct hwrng, ref);
+
+	if (rng->cleanup)
+		rng->cleanup(rng);
+
+	complete(&rng->cleanup_done);
+}
+
+static int set_current_rng(struct hwrng *rng)
+{
+	int err;
+
+	BUG_ON(!mutex_is_locked(&rng_mutex));
+
+	err = hwrng_init(rng);
+	if (err)
+		return err;
+
+	drop_current_rng();
+	current_rng = rng;
+
+	return 0;
+}
+
+static void drop_current_rng(void)
+{
+	BUG_ON(!mutex_is_locked(&rng_mutex));
+	if (!current_rng)
+		return;
+
+	/* decrease last reference for triggering the cleanup */
+	kref_put(&current_rng->ref, cleanup_rng);
+	current_rng = NULL;
+}
+
+/* Returns ERR_PTR(), NULL or refcounted hwrng */
+static struct hwrng *get_current_rng(void)
+{
+	struct hwrng *rng;
+
+	if (mutex_lock_interruptible(&rng_mutex))
+		return ERR_PTR(-ERESTARTSYS);
+
+	rng = current_rng;
+	if (rng)
+		kref_get(&rng->ref);
+
+	mutex_unlock(&rng_mutex);
+	return rng;
+}
+
+static void put_rng(struct hwrng *rng)
+{
+	/*
+	 * Hold rng_mutex here so we serialize in case they set_current_rng
+	 * on rng again immediately.
+	 */
+	mutex_lock(&rng_mutex);
+	if (rng)
+		kref_put(&rng->ref, cleanup_rng);
+	mutex_unlock(&rng_mutex);
+}
+
+static int hwrng_init(struct hwrng *rng)
+{
+	if (kref_get_unless_zero(&rng->ref))
+		goto skip_init;
+
 	if (rng->init) {
 		int ret;
 
@@ -95,6 +171,11 @@
 		if (ret)
 			return ret;
 	}
+
+	kref_init(&rng->ref);
+	reinit_completion(&rng->cleanup_done);
+
+skip_init:
 	add_early_randomness(rng);
 
 	current_quality = rng->quality ? : default_quality;
@@ -108,12 +189,6 @@
 	return 0;
 }
 
-static inline void hwrng_cleanup(struct hwrng *rng)
-{
-	if (rng && rng->cleanup)
-		rng->cleanup(rng);
-}
-
 static int rng_dev_open(struct inode *inode, struct file *filp)
 {
 	/* enforce read-only access to this chrdev */
@@ -128,6 +203,7 @@
 			int wait) {
 	int present;
 
+	BUG_ON(!mutex_is_locked(&reading_mutex));
 	if (rng->read)
 		return rng->read(rng, (void *)buffer, size, wait);
 
@@ -148,25 +224,27 @@
 	ssize_t ret = 0;
 	int err = 0;
 	int bytes_read, len;
+	struct hwrng *rng;
 
 	while (size) {
-		if (mutex_lock_interruptible(&rng_mutex)) {
-			err = -ERESTARTSYS;
+		rng = get_current_rng();
+		if (IS_ERR(rng)) {
+			err = PTR_ERR(rng);
+			goto out;
+		}
+		if (!rng) {
+			err = -ENODEV;
 			goto out;
 		}
 
-		if (!current_rng) {
-			err = -ENODEV;
-			goto out_unlock;
-		}
-
+		mutex_lock(&reading_mutex);
 		if (!data_avail) {
-			bytes_read = rng_get_data(current_rng, rng_buffer,
+			bytes_read = rng_get_data(rng, rng_buffer,
 				rng_buffer_size(),
 				!(filp->f_flags & O_NONBLOCK));
 			if (bytes_read < 0) {
 				err = bytes_read;
-				goto out_unlock;
+				goto out_unlock_reading;
 			}
 			data_avail = bytes_read;
 		}
@@ -174,7 +252,7 @@
 		if (!data_avail) {
 			if (filp->f_flags & O_NONBLOCK) {
 				err = -EAGAIN;
-				goto out_unlock;
+				goto out_unlock_reading;
 			}
 		} else {
 			len = data_avail;
@@ -186,14 +264,15 @@
 			if (copy_to_user(buf + ret, rng_buffer + data_avail,
 								len)) {
 				err = -EFAULT;
-				goto out_unlock;
+				goto out_unlock_reading;
 			}
 
 			size -= len;
 			ret += len;
 		}
 
-		mutex_unlock(&rng_mutex);
+		mutex_unlock(&reading_mutex);
+		put_rng(rng);
 
 		if (need_resched())
 			schedule_timeout_interruptible(1);
@@ -205,8 +284,10 @@
 	}
 out:
 	return ret ? : err;
-out_unlock:
-	mutex_unlock(&rng_mutex);
+
+out_unlock_reading:
+	mutex_unlock(&reading_mutex);
+	put_rng(rng);
 	goto out;
 }
 
@@ -239,16 +320,9 @@
 	err = -ENODEV;
 	list_for_each_entry(rng, &rng_list, list) {
 		if (strcmp(rng->name, buf) == 0) {
-			if (rng == current_rng) {
-				err = 0;
-				break;
-			}
-			err = hwrng_init(rng);
-			if (err)
-				break;
-			hwrng_cleanup(current_rng);
-			current_rng = rng;
 			err = 0;
+			if (rng != current_rng)
+				err = set_current_rng(rng);
 			break;
 		}
 	}
@@ -261,17 +335,15 @@
 				       struct device_attribute *attr,
 				       char *buf)
 {
-	int err;
 	ssize_t ret;
-	const char *name = "none";
+	struct hwrng *rng;
 
-	err = mutex_lock_interruptible(&rng_mutex);
-	if (err)
-		return -ERESTARTSYS;
-	if (current_rng)
-		name = current_rng->name;
-	ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
-	mutex_unlock(&rng_mutex);
+	rng = get_current_rng();
+	if (IS_ERR(rng))
+		return PTR_ERR(rng);
+
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none");
+	put_rng(rng);
 
 	return ret;
 }
@@ -305,14 +377,14 @@
 		   NULL);
 
 
-static void unregister_miscdev(void)
+static void __exit unregister_miscdev(void)
 {
 	device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
 	device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
 	misc_deregister(&rng_miscdev);
 }
 
-static int register_miscdev(void)
+static int __init register_miscdev(void)
 {
 	int err;
 
@@ -342,15 +414,22 @@
 	long rc;
 
 	while (!kthread_should_stop()) {
-		if (!current_rng)
+		struct hwrng *rng;
+
+		rng = get_current_rng();
+		if (IS_ERR(rng) || !rng)
 			break;
-		rc = rng_get_data(current_rng, rng_fillbuf,
+		mutex_lock(&reading_mutex);
+		rc = rng_get_data(rng, rng_fillbuf,
 				  rng_buffer_size(), 1);
+		mutex_unlock(&reading_mutex);
+		put_rng(rng);
 		if (rc <= 0) {
 			pr_warn("hwrng: no data available\n");
 			msleep_interruptible(10000);
 			continue;
 		}
+		/* Outside lock, sure, but y'know: randomness. */
 		add_hwgenerator_randomness((void *)rng_fillbuf, rc,
 					   rc * current_quality * 8 >> 10);
 	}
@@ -400,23 +479,16 @@
 			goto out_unlock;
 	}
 
+	init_completion(&rng->cleanup_done);
+	complete(&rng->cleanup_done);
+
 	old_rng = current_rng;
-	if (!old_rng) {
-		err = hwrng_init(rng);
-		if (err)
-			goto out_unlock;
-		current_rng = rng;
-	}
 	err = 0;
 	if (!old_rng) {
-		err = register_miscdev();
-		if (err) {
-			hwrng_cleanup(rng);
-			current_rng = NULL;
+		err = set_current_rng(rng);
+		if (err)
 			goto out_unlock;
-		}
 	}
-	INIT_LIST_HEAD(&rng->list);
 	list_add_tail(&rng->list, &rng_list);
 
 	if (old_rng && !rng->init) {
@@ -439,42 +511,49 @@
 
 void hwrng_unregister(struct hwrng *rng)
 {
-	int err;
-
 	mutex_lock(&rng_mutex);
 
 	list_del(&rng->list);
 	if (current_rng == rng) {
-		hwrng_cleanup(rng);
-		if (list_empty(&rng_list)) {
-			current_rng = NULL;
-		} else {
-			current_rng = list_entry(rng_list.prev, struct hwrng, list);
-			err = hwrng_init(current_rng);
-			if (err)
-				current_rng = NULL;
+		drop_current_rng();
+		if (!list_empty(&rng_list)) {
+			struct hwrng *tail;
+
+			tail = list_entry(rng_list.prev, struct hwrng, list);
+
+			set_current_rng(tail);
 		}
 	}
+
 	if (list_empty(&rng_list)) {
-		unregister_miscdev();
+		mutex_unlock(&rng_mutex);
 		if (hwrng_fill)
 			kthread_stop(hwrng_fill);
-	}
+	} else
+		mutex_unlock(&rng_mutex);
 
-	mutex_unlock(&rng_mutex);
+	wait_for_completion(&rng->cleanup_done);
 }
 EXPORT_SYMBOL_GPL(hwrng_unregister);
 
-static void __exit hwrng_exit(void)
+static int __init hwrng_modinit(void)
+{
+	return register_miscdev();
+}
+
+static void __exit hwrng_modexit(void)
 {
 	mutex_lock(&rng_mutex);
 	BUG_ON(current_rng);
 	kfree(rng_buffer);
 	kfree(rng_fillbuf);
 	mutex_unlock(&rng_mutex);
+
+	unregister_miscdev();
 }
 
-module_exit(hwrng_exit);
+module_init(hwrng_modinit);
+module_exit(hwrng_modexit);
 
 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 72295ea..3fa2f8a 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -39,7 +39,6 @@
 	bool hwrng_removed;
 };
 
-
 static void random_recv_done(struct virtqueue *vq)
 {
 	struct virtrng_info *vi = vq->vdev->priv;
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index e34a019..24cc4ed 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -5,7 +5,8 @@
  *
  * Hwmon integration:
  * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
- * Copyright (C) 2013  Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2013, 2014  Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2014  Pali Rohár <pali.rohar@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
@@ -20,6 +21,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -41,11 +43,15 @@
 #define I8K_SMM_SET_FAN		0x01a3
 #define I8K_SMM_GET_FAN		0x00a3
 #define I8K_SMM_GET_SPEED	0x02a3
+#define I8K_SMM_GET_FAN_TYPE	0x03a3
+#define I8K_SMM_GET_NOM_SPEED	0x04a3
 #define I8K_SMM_GET_TEMP	0x10a3
+#define I8K_SMM_GET_TEMP_TYPE	0x11a3
 #define I8K_SMM_GET_DELL_SIG1	0xfea3
 #define I8K_SMM_GET_DELL_SIG2	0xffa3
 
 #define I8K_FAN_MULT		30
+#define I8K_FAN_MAX_RPM		30000
 #define I8K_MAX_TEMP		127
 
 #define I8K_FN_NONE		0x00
@@ -58,15 +64,13 @@
 #define I8K_POWER_AC		0x05
 #define I8K_POWER_BATTERY	0x01
 
-#define I8K_TEMPERATURE_BUG	1
-
 static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
 static struct device *i8k_hwmon_dev;
 static u32 i8k_hwmon_flags;
-static int i8k_fan_mult;
-static int i8k_pwm_mult;
-static int i8k_fan_max = I8K_FAN_HIGH;
+static uint i8k_fan_mult = I8K_FAN_MULT;
+static uint i8k_pwm_mult;
+static uint i8k_fan_max = I8K_FAN_HIGH;
 
 #define I8K_HWMON_HAVE_TEMP1	(1 << 0)
 #define I8K_HWMON_HAVE_TEMP2	(1 << 1)
@@ -95,13 +99,13 @@
 module_param(power_status, bool, 0600);
 MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
 
-static int fan_mult = I8K_FAN_MULT;
-module_param(fan_mult, int, 0);
-MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+static uint fan_mult;
+module_param(fan_mult, uint, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)");
 
-static int fan_max = I8K_FAN_HIGH;
-module_param(fan_max, int, 0);
-MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
+static uint fan_max;
+module_param(fan_max, uint, 0);
+MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)");
 
 static int i8k_open_fs(struct inode *inode, struct file *file);
 static long i8k_ioctl(struct file *, unsigned int, unsigned long);
@@ -276,6 +280,28 @@
 }
 
 /*
+ * Read the fan type.
+ */
+static int i8k_get_fan_type(int fan)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
+
+	regs.ebx = fan & 0xff;
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+/*
+ * Read the fan nominal rpm for specific fan speed.
+ */
+static int i8k_get_fan_nominal_speed(int fan, int speed)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
+
+	regs.ebx = (fan & 0xff) | (speed << 8);
+	return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
+/*
  * Set the fan speed (off, low, high). Returns the new fan status.
  */
 static int i8k_set_fan(int fan, int speed)
@@ -288,42 +314,52 @@
 	return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
 }
 
+static int i8k_get_temp_type(int sensor)
+{
+	struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };
+
+	regs.ebx = sensor & 0xff;
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
 /*
  * Read the cpu temperature.
  */
+static int _i8k_get_temp(int sensor)
+{
+	struct smm_regs regs = {
+		.eax = I8K_SMM_GET_TEMP,
+		.ebx = sensor & 0xff,
+	};
+
+	return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
 static int i8k_get_temp(int sensor)
 {
-	struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
-	int rc;
-	int temp;
+	int temp = _i8k_get_temp(sensor);
 
-#ifdef I8K_TEMPERATURE_BUG
-	static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 };
-#endif
-	regs.ebx = sensor & 0xff;
-	rc = i8k_smm(&regs);
-	if (rc < 0)
-		return rc;
-
-	temp = regs.eax & 0xff;
-
-#ifdef I8K_TEMPERATURE_BUG
 	/*
 	 * Sometimes the temperature sensor returns 0x99, which is out of range.
-	 * In this case we return (once) the previous cached value. For example:
+	 * In this case we retry (once) before returning an error.
 	 # 1003655137 00000058 00005a4b
 	 # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
 	 # 1003655139 00000054 00005c52
 	 */
-	if (temp > I8K_MAX_TEMP) {
-		temp = prev[sensor];
-		prev[sensor] = I8K_MAX_TEMP+1;
-	} else {
-		prev[sensor] = temp;
+	if (temp == 0x99) {
+		msleep(100);
+		temp = _i8k_get_temp(sensor);
 	}
+	/*
+	 * Return -ENODATA for all invalid temperatures.
+	 *
+	 * Known instances are the 0x99 value as seen above as well as
+	 * 0xc1 (193), which may be returned when trying to read the GPU
+	 * temperature if the system supports a GPU and it is currently
+	 * turned off.
+	 */
 	if (temp > I8K_MAX_TEMP)
-		return -ERANGE;
-#endif
+		return -ENODATA;
 
 	return temp;
 }
@@ -493,6 +529,29 @@
  * Hwmon interface
  */
 
+static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
+					 struct device_attribute *devattr,
+					 char *buf)
+{
+	static const char * const labels[] = {
+		"CPU",
+		"GPU",
+		"SODIMM",
+		"Other",
+		"Ambient",
+		"Other",
+	};
+	int index = to_sensor_dev_attr(devattr)->index;
+	int type;
+
+	type = i8k_get_temp_type(index);
+	if (type < 0)
+		return type;
+	if (type >= ARRAY_SIZE(labels))
+		type = ARRAY_SIZE(labels) - 1;
+	return sprintf(buf, "%s\n", labels[type]);
+}
+
 static ssize_t i8k_hwmon_show_temp(struct device *dev,
 				   struct device_attribute *devattr,
 				   char *buf)
@@ -501,13 +560,42 @@
 	int temp;
 
 	temp = i8k_get_temp(index);
-	if (temp == -ERANGE)
-		return -EINVAL;
 	if (temp < 0)
 		return temp;
 	return sprintf(buf, "%d\n", temp * 1000);
 }
 
+static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
+					struct device_attribute *devattr,
+					char *buf)
+{
+	static const char * const labels[] = {
+		"Processor Fan",
+		"Motherboard Fan",
+		"Video Fan",
+		"Power Supply Fan",
+		"Chipset Fan",
+		"Other Fan",
+	};
+	int index = to_sensor_dev_attr(devattr)->index;
+	bool dock = false;
+	int type;
+
+	type = i8k_get_fan_type(index);
+	if (type < 0)
+		return type;
+
+	if (type & 0x10) {
+		dock = true;
+		type &= 0x0F;
+	}
+
+	if (type >= ARRAY_SIZE(labels))
+		type = (ARRAY_SIZE(labels) - 1);
+
+	return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
+}
+
 static ssize_t i8k_hwmon_show_fan(struct device *dev,
 				  struct device_attribute *devattr,
 				  char *buf)
@@ -555,45 +643,66 @@
 }
 
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  0);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  1);
 static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  2);
 static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
-			  I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+			  3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+			  0);
 static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
-			  i8k_hwmon_set_pwm, I8K_FAN_LEFT);
+			  i8k_hwmon_set_pwm, 0);
 static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
-			  I8K_FAN_RIGHT);
+			  1);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+			  1);
 static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
-			  i8k_hwmon_set_pwm, I8K_FAN_RIGHT);
+			  i8k_hwmon_set_pwm, 1);
 
 static struct attribute *i8k_attrs[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,	/* 0 */
-	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 1 */
-	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 2 */
-	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 3 */
-	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 4 */
-	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 5 */
-	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 6 */
-	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 7 */
+	&sensor_dev_attr_temp1_label.dev_attr.attr,	/* 1 */
+	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 2 */
+	&sensor_dev_attr_temp2_label.dev_attr.attr,	/* 3 */
+	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 4 */
+	&sensor_dev_attr_temp3_label.dev_attr.attr,	/* 5 */
+	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 6 */
+	&sensor_dev_attr_temp4_label.dev_attr.attr,	/* 7 */
+	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 8 */
+	&sensor_dev_attr_fan1_label.dev_attr.attr,	/* 9 */
+	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 10 */
+	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 11 */
+	&sensor_dev_attr_fan2_label.dev_attr.attr,	/* 12 */
+	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 13 */
 	NULL
 };
 
 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
 			      int index)
 {
-	if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
+	if (index >= 0 && index <= 1 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
 		return 0;
-	if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
-		return 0;
-	if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
-		return 0;
-	if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+	if (index >= 2 && index <= 3 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
 		return 0;
 	if (index >= 4 && index <= 5 &&
-	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
 		return 0;
 	if (index >= 6 && index <= 7 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+		return 0;
+	if (index >= 8 && index <= 10 &&
+	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
+		return 0;
+	if (index >= 11 && index <= 13 &&
 	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
 		return 0;
 
@@ -612,28 +721,28 @@
 
 	i8k_hwmon_flags = 0;
 
-	/* CPU temperature attributes, if temperature reading is OK */
-	err = i8k_get_temp(0);
-	if (err >= 0 || err == -ERANGE)
+	/* CPU temperature attributes, if temperature type is OK */
+	err = i8k_get_temp_type(0);
+	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;
 	/* check for additional temperature sensors */
-	err = i8k_get_temp(1);
-	if (err >= 0 || err == -ERANGE)
+	err = i8k_get_temp_type(1);
+	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;
-	err = i8k_get_temp(2);
-	if (err >= 0 || err == -ERANGE)
+	err = i8k_get_temp_type(2);
+	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;
-	err = i8k_get_temp(3);
-	if (err >= 0 || err == -ERANGE)
+	err = i8k_get_temp_type(3);
+	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
 
-	/* Left fan attributes, if left fan is present */
-	err = i8k_get_fan_status(I8K_FAN_LEFT);
+	/* First fan attributes, if fan type is OK */
+	err = i8k_get_fan_type(0);
 	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
 
-	/* Right fan attributes, if right fan is present */
-	err = i8k_get_fan_status(I8K_FAN_RIGHT);
+	/* Second fan attributes, if fan type is OK */
+	err = i8k_get_fan_type(1);
 	if (err >= 0)
 		i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
 
@@ -649,16 +758,15 @@
 }
 
 struct i8k_config_data {
-	int fan_mult;
-	int fan_max;
+	uint fan_mult;
+	uint fan_max;
 };
 
 enum i8k_configs {
 	DELL_LATITUDE_D520,
-	DELL_LATITUDE_E6540,
 	DELL_PRECISION_490,
 	DELL_STUDIO,
-	DELL_XPS_M140,
+	DELL_XPS,
 };
 
 static const struct i8k_config_data i8k_config_data[] = {
@@ -666,10 +774,6 @@
 		.fan_mult = 1,
 		.fan_max = I8K_FAN_TURBO,
 	},
-	[DELL_LATITUDE_E6540] = {
-		.fan_mult = 1,
-		.fan_max = I8K_FAN_HIGH,
-	},
 	[DELL_PRECISION_490] = {
 		.fan_mult = 1,
 		.fan_max = I8K_FAN_TURBO,
@@ -678,7 +782,7 @@
 		.fan_mult = 1,
 		.fan_max = I8K_FAN_HIGH,
 	},
-	[DELL_XPS_M140] = {
+	[DELL_XPS] = {
 		.fan_mult = 1,
 		.fan_max = I8K_FAN_HIGH,
 	},
@@ -715,22 +819,6 @@
 		.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
 	},
 	{
-		.ident = "Dell Latitude E6440",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"),
-		},
-		.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
-	},
-	{
-		.ident = "Dell Latitude E6540",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"),
-		},
-		.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
-	},
-	{
 		.ident = "Dell Latitude 2",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -790,12 +878,20 @@
 		.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
 	},
 	{
+		.ident = "Dell XPS 13",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_XPS],
+	},
+	{
 		.ident = "Dell XPS M140",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
 		},
-		.driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
+		.driver_data = (void *)&i8k_config_data[DELL_XPS],
 	},
 	{ }
 };
@@ -808,6 +904,7 @@
 static int __init i8k_probe(void)
 {
 	const struct dmi_system_id *id;
+	int fan, ret;
 
 	/*
 	 * Get DMI information
@@ -836,19 +933,40 @@
 			return -ENODEV;
 	}
 
-	i8k_fan_mult = fan_mult;
-	i8k_fan_max = fan_max ? : I8K_FAN_HIGH;	/* Must not be 0 */
+	/*
+	 * Set fan multiplier and maximal fan speed from dmi config
+	 * Values specified in module parameters override values from dmi
+	 */
 	id = dmi_first_match(i8k_dmi_table);
 	if (id && id->driver_data) {
 		const struct i8k_config_data *conf = id->driver_data;
-
-		if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
-			i8k_fan_mult = conf->fan_mult;
-		if (fan_max == I8K_FAN_HIGH && conf->fan_max)
-			i8k_fan_max = conf->fan_max;
+		if (!fan_mult && conf->fan_mult)
+			fan_mult = conf->fan_mult;
+		if (!fan_max && conf->fan_max)
+			fan_max = conf->fan_max;
 	}
+
+	i8k_fan_max = fan_max ? : I8K_FAN_HIGH;	/* Must not be 0 */
 	i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
 
+	if (!fan_mult) {
+		/*
+		 * Autodetect fan multiplier based on nominal rpm
+		 * If fan reports rpm value too high then set multiplier to 1
+		 */
+		for (fan = 0; fan < 2; ++fan) {
+			ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);
+			if (ret < 0)
+				continue;
+			if (ret > I8K_FAN_MAX_RPM)
+				i8k_fan_mult = 1;
+			break;
+		}
+	} else {
+		/* Fan multiplier was specified in module param or in dmi */
+		i8k_fan_mult = fan_mult;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 9a6b637..297110c 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 #include <linux/aio.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
@@ -352,7 +352,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_DEVKMEM
 static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long pfn;
@@ -373,9 +372,7 @@
 	vma->vm_pgoff = pfn;
 	return mmap_mem(file, vma);
 }
-#endif
 
-#ifdef CONFIG_DEVKMEM
 /*
  * This function reads the *virtual* memory as seen by the kernel.
  */
@@ -555,9 +552,7 @@
 	*ppos = p;
 	return virtr + wrote ? : err;
 }
-#endif
 
-#ifdef CONFIG_DEVPORT
 static ssize_t read_port(struct file *file, char __user *buf,
 			 size_t count, loff_t *ppos)
 {
@@ -586,6 +581,7 @@
 		return -EFAULT;
 	while (count-- > 0 && i < 65536) {
 		char c;
+
 		if (__get_user(c, tmp)) {
 			if (tmp > buf)
 				break;
@@ -598,7 +594,6 @@
 	*ppos = i;
 	return tmp-buf;
 }
-#endif
 
 static ssize_t read_null(struct file *file, char __user *buf,
 			 size_t count, loff_t *ppos)
@@ -642,6 +637,7 @@
 
 	while (iov_iter_count(iter)) {
 		size_t chunk = iov_iter_count(iter), n;
+
 		if (chunk > PAGE_SIZE)
 			chunk = PAGE_SIZE;	/* Just for latency reasons */
 		n = iov_iter_zero(chunk, iter);
@@ -726,7 +722,7 @@
 #define open_mem	open_port
 #define open_kmem	open_mem
 
-static const struct file_operations mem_fops = {
+static const struct file_operations __maybe_unused mem_fops = {
 	.llseek		= memory_lseek,
 	.read		= read_mem,
 	.write		= write_mem,
@@ -738,8 +734,7 @@
 #endif
 };
 
-#ifdef CONFIG_DEVKMEM
-static const struct file_operations kmem_fops = {
+static const struct file_operations __maybe_unused kmem_fops = {
 	.llseek		= memory_lseek,
 	.read		= read_kmem,
 	.write		= write_kmem,
@@ -750,7 +745,6 @@
 	.mmap_capabilities = memory_mmap_capabilities,
 #endif
 };
-#endif
 
 static const struct file_operations null_fops = {
 	.llseek		= null_lseek,
@@ -761,14 +755,12 @@
 	.splice_write	= splice_write_null,
 };
 
-#ifdef CONFIG_DEVPORT
-static const struct file_operations port_fops = {
+static const struct file_operations __maybe_unused port_fops = {
 	.llseek		= memory_lseek,
 	.read		= read_port,
 	.write		= write_port,
 	.open		= open_port,
 };
-#endif
 
 static const struct file_operations zero_fops = {
 	.llseek		= zero_lseek,
@@ -795,7 +787,9 @@
 	const struct file_operations *fops;
 	fmode_t fmode;
 } devlist[] = {
+#ifdef CONFIG_DEVMEM
 	 [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+#endif
 #ifdef CONFIG_DEVKMEM
 	 [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
 #endif
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index bf53a37..e85d341 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -901,8 +901,10 @@
 	if (chip == NULL)
 		return -ENODEV;
 
-	if (chip->flags & TPM_CHIP_FLAG_TPM2)
-		return tpm2_shutdown(chip, TPM2_SU_CLEAR);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		tpm2_shutdown(chip, TPM2_SU_STATE);
+		return 0;
+	}
 
 	/* for buggy tpm, flush pcrs with extend to selected dummy */
 	if (tpm_suspend_pcr) {
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 7b0727c..f8319a0 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -432,7 +432,8 @@
 			u32 *value, const char *desc);
 
 extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
-extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
+extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
 extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
 extern int tpm2_do_selftest(struct tpm_chip *chip);
-extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet);
+extern int tpm2_gen_interrupt(struct tpm_chip *chip);
+extern int tpm2_probe(struct tpm_chip *chip);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 1abe650..011909a 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -456,20 +456,23 @@
  * @chip:		TPM chip to use.
  * @shutdown_type	shutdown type. The value is either
  *			TPM_SU_CLEAR or TPM_SU_STATE.
- *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
  */
-int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
+void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
 {
 	struct tpm2_cmd cmd;
+	int rc;
 
 	cmd.header.in = tpm2_shutdown_header;
-
 	cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
-	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
-				"stopping the TPM");
+
+	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
+
+	/* In places where shutdown command is sent there's no much we can do
+	 * except print the error code on a system failure.
+	 */
+	if (rc < 0)
+		dev_warn(chip->pdev, "transmit returned %d while stopping the TPM",
+			 rc);
 }
 EXPORT_SYMBOL_GPL(tpm2_shutdown);
 
@@ -598,20 +601,46 @@
 /**
  * tpm2_gen_interrupt() - generate an interrupt
  * @chip: TPM chip to use
- * @quiet: surpress the error message
  *
  * 0 is returned when the operation is successful. If a negative number is
  * returned it remarks a POSIX error code. If a positive number is returned
  * it remarks a TPM error.
  */
-int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet)
+int tpm2_gen_interrupt(struct tpm_chip *chip)
 {
-	const char *desc = NULL;
 	u32 dummy;
 
-	if (!quiet)
-		desc = "attempting to generate an interrupt";
-
-	return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc);
+	return tpm2_get_tpm_pt(chip, 0x100, &dummy,
+			       "attempting to generate an interrupt");
 }
 EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
+
+/**
+ * tpm2_probe() - probe TPM 2.0
+ * @chip: TPM chip to use
+ *
+ * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
+ * the reply tag.
+ */
+int tpm2_probe(struct tpm_chip *chip)
+{
+	struct tpm2_cmd cmd;
+	int rc;
+
+	cmd.header.in = tpm2_get_tpm_pt_header;
+	cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
+	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
+	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
+
+	rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd));
+	if (rc <  0)
+		return rc;
+	else if (rc < TPM_HEADER_SIZE)
+		return -EFAULT;
+
+	if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS)
+		chip->flags |= TPM_CHIP_FLAG_TPM2;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tpm2_probe);
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 3dd23cf..b26ceee 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -95,21 +95,7 @@
 	u8 __iomem *rsp;
 };
 
-#ifdef CONFIG_PM_SLEEP
-static int crb_resume(struct device *dev)
-{
-	int rc;
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	rc = tpm2_shutdown(chip, TPM2_SU_STATE);
-	if (!rc)
-		rc = tpm2_do_selftest(chip);
-
-	return rc;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
+static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume);
 
 static u8 crb_status(struct tpm_chip *chip)
 {
@@ -326,6 +312,10 @@
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 	tpm_chip_unregister(chip);
+
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		tpm2_shutdown(chip, TPM2_SU_CLEAR);
+
 	return 0;
 }
 
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index 0840347..b1e53e3 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -148,7 +148,8 @@
 	crq.len = (u16)count;
 	crq.data = ibmvtpm->rtce_dma_handle;
 
-	rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]);
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
+			      cpu_to_be64(word[1]));
 	if (rc != H_SUCCESS) {
 		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
 		rc = 0;
@@ -186,7 +187,8 @@
 	crq.valid = (u8)IBMVTPM_VALID_CMD;
 	crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
 
-	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+			      cpu_to_be64(buf[1]));
 	if (rc != H_SUCCESS)
 		dev_err(ibmvtpm->dev,
 			"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
@@ -212,7 +214,8 @@
 	crq.valid = (u8)IBMVTPM_VALID_CMD;
 	crq.msg = (u8)VTPM_GET_VERSION;
 
-	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+			      cpu_to_be64(buf[1]));
 	if (rc != H_SUCCESS)
 		dev_err(ibmvtpm->dev,
 			"ibmvtpm_crq_get_version failed rc=%d\n", rc);
@@ -336,7 +339,8 @@
 	crq.valid = (u8)IBMVTPM_VALID_CMD;
 	crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
 
-	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+			      cpu_to_be64(buf[1]));
 	if (rc != H_SUCCESS)
 		dev_err(ibmvtpm->dev,
 			"tpm_ibmvtpm_suspend failed rc=%d\n", rc);
@@ -481,11 +485,11 @@
 	case IBMVTPM_VALID_CMD:
 		switch (crq->msg) {
 		case VTPM_GET_RTCE_BUFFER_SIZE_RES:
-			if (crq->len <= 0) {
+			if (be16_to_cpu(crq->len) <= 0) {
 				dev_err(ibmvtpm->dev, "Invalid rtce size\n");
 				return;
 			}
-			ibmvtpm->rtce_size = crq->len;
+			ibmvtpm->rtce_size = be16_to_cpu(crq->len);
 			ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
 						    GFP_KERNEL);
 			if (!ibmvtpm->rtce_buf) {
@@ -506,11 +510,11 @@
 
 			return;
 		case VTPM_GET_VERSION_RES:
-			ibmvtpm->vtpm_version = crq->data;
+			ibmvtpm->vtpm_version = be32_to_cpu(crq->data);
 			return;
 		case VTPM_TPM_COMMAND_RES:
 			/* len of the data in rtce buffer */
-			ibmvtpm->res_len = crq->len;
+			ibmvtpm->res_len = be16_to_cpu(crq->len);
 			wake_up_interruptible(&ibmvtpm->wq);
 			return;
 		default:
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 6725bef..f2dffa7 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -588,6 +588,9 @@
 
 static void tpm_tis_remove(struct tpm_chip *chip)
 {
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		tpm2_shutdown(chip, TPM2_SU_CLEAR);
+
 	iowrite32(~TPM_GLOBAL_INT_ENABLE &
 		  ioread32(chip->vendor.iobase +
 			   TPM_INT_ENABLE(chip->vendor.
@@ -639,12 +642,9 @@
 		goto out_err;
 	}
 
-	/* Every TPM 2.x command has a higher ordinal than TPM 1.x commands.
-	 * Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x.
-	 */
-	rc = tpm2_gen_interrupt(chip, true);
-	if (rc == 0 || rc == TPM2_RC_INITIALIZE)
-		chip->flags |= TPM_CHIP_FLAG_TPM2;
+	rc = tpm2_probe(chip);
+	if (rc)
+		goto out_err;
 
 	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
 	chip->vendor.manufacturer_id = vendor;
@@ -747,7 +747,7 @@
 
 			/* Generate Interrupts */
 			if (chip->flags & TPM_CHIP_FLAG_TPM2)
-				tpm2_gen_interrupt(chip, false);
+				tpm2_gen_interrupt(chip);
 			else
 				tpm_gen_interrupt(chip);
 
@@ -865,25 +865,22 @@
 static int tpm_tis_resume(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	int ret = 0;
+	int ret;
 
 	if (chip->vendor.irq)
 		tpm_tis_reenable_interrupts(chip);
 
-	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
-		/* NOP if firmware properly does this. */
-		tpm2_startup(chip, TPM2_SU_STATE);
+	ret = tpm_pm_resume(dev);
+	if (ret)
+		return ret;
 
-		ret = tpm2_shutdown(chip, TPM2_SU_STATE);
-		if (!ret)
-			ret = tpm2_do_selftest(chip);
-	} else {
-		ret = tpm_pm_resume(dev);
-		if (!ret)
-			tpm_do_selftest(chip);
-	}
+	/* TPM 1.2 requires self-test on resume. This function actually returns
+	 * an error code but for unknown reason it isn't handled.
+	 */
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+		tpm_do_selftest(chip);
 
-	return ret;
+	return 0;
 }
 #endif
 
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index de03df9..26afb56 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1986,6 +1986,12 @@
 	bool multiport;
 	bool early = early_put_chars != NULL;
 
+	if (!vdev->config->get) {
+		dev_err(&vdev->dev, "%s failure: config access disabled\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	/* Ensure to read early_put_chars now */
 	barrier();
 
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 386999b..f07c815 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -27,6 +27,15 @@
 void __iomem *at91_pmc_base;
 EXPORT_SYMBOL_GPL(at91_pmc_base);
 
+void at91rm9200_idle(void)
+{
+	/*
+	 * Disable the processor clock.  The processor will be automatically
+	 * re-enabled by an interrupt or by a reset.
+	 */
+	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+}
+
 void at91sam9_idle(void)
 {
 	at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d48ac71..642cf37 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2048,7 +2048,7 @@
 		goto fail_out;
 	}
 
-	clk->name = kstrdup(hw->init->name, GFP_KERNEL);
+	clk->name = kstrdup_const(hw->init->name, GFP_KERNEL);
 	if (!clk->name) {
 		pr_err("%s: could not allocate clk->name\n", __func__);
 		ret = -ENOMEM;
@@ -2075,7 +2075,7 @@
 
 	/* copy each string name in case parent_names is __initdata */
 	for (i = 0; i < clk->num_parents; i++) {
-		clk->parent_names[i] = kstrdup(hw->init->parent_names[i],
+		clk->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
 						GFP_KERNEL);
 		if (!clk->parent_names[i]) {
 			pr_err("%s: could not copy parent_names\n", __func__);
@@ -2090,10 +2090,10 @@
 
 fail_parent_names_copy:
 	while (--i >= 0)
-		kfree(clk->parent_names[i]);
+		kfree_const(clk->parent_names[i]);
 	kfree(clk->parent_names);
 fail_parent_names:
-	kfree(clk->name);
+	kfree_const(clk->name);
 fail_name:
 	kfree(clk);
 fail_out:
@@ -2112,10 +2112,10 @@
 
 	kfree(clk->parents);
 	while (--i >= 0)
-		kfree(clk->parent_names[i]);
+		kfree_const(clk->parent_names[i]);
 
 	kfree(clk->parent_names);
-	kfree(clk->name);
+	kfree_const(clk->name);
 	kfree(clk);
 }
 
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 848d602..07d666c 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -635,8 +635,8 @@
 			SRC_TOP3, 0, 1),
 	MUX(0, "mout_user_aclk400_mscl", mout_user_aclk400_mscl_p,
 			SRC_TOP3, 4, 1),
-	MUX(0, "mout_user_aclk200_disp1", mout_user_aclk200_disp1_p,
-			SRC_TOP3, 8, 1),
+	MUX(CLK_MOUT_USER_ACLK200_DISP1, "mout_user_aclk200_disp1",
+			mout_user_aclk200_disp1_p, SRC_TOP3, 8, 1),
 	MUX(0, "mout_user_aclk200_fsys2", mout_user_aclk200_fsys2_p,
 			SRC_TOP3, 12, 1),
 	MUX(0, "mout_user_aclk400_wcore", mout_user_aclk400_wcore_p,
@@ -663,8 +663,8 @@
 	MUX(CLK_MOUT_USER_ACLK333, "mout_user_aclk333", mout_user_aclk333_p,
 			SRC_TOP4, 28, 1),
 
-	MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p,
-			SRC_TOP5, 0, 1),
+	MUX(CLK_MOUT_USER_ACLK400_DISP1, "mout_user_aclk400_disp1",
+			mout_user_aclk400_disp1_p, SRC_TOP5, 0, 1),
 	MUX(0, "mout_user_aclk66_psgen", mout_user_aclk66_peric_p,
 			SRC_TOP5, 4, 1),
 	MUX(0, "mout_user_aclk333_g2d", mout_user_aclk333_g2d_p,
@@ -675,8 +675,8 @@
 			SRC_TOP5, 16, 1),
 	MUX(0, "mout_user_aclk300_jpeg", mout_user_aclk300_jpeg_p,
 			SRC_TOP5, 20, 1),
-	MUX(0, "mout_user_aclk300_disp1", mout_user_aclk300_disp1_p,
-			SRC_TOP5, 24, 1),
+	MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
+			mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
 	MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
 			SRC_TOP5, 28, 1),
 
@@ -693,7 +693,8 @@
 			SRC_TOP10, 0, 1),
 	MUX(0, "mout_sw_aclk400_mscl", mout_sw_aclk400_mscl_p,
 			SRC_TOP10, 4, 1),
-	MUX(0, "mout_sw_aclk200", mout_sw_aclk200_p, SRC_TOP10, 8, 1),
+	MUX(CLK_MOUT_SW_ACLK200, "mout_sw_aclk200", mout_sw_aclk200_p,
+			SRC_TOP10, 8, 1),
 	MUX(0, "mout_sw_aclk200_fsys2", mout_sw_aclk200_fsys2_p,
 			SRC_TOP10, 12, 1),
 	MUX(0, "mout_sw_aclk400_wcore", mout_sw_aclk400_wcore_p,
@@ -717,8 +718,8 @@
 	MUX(CLK_MOUT_SW_ACLK333, "mout_sw_aclk333", mout_sw_aclk333_p,
 			SRC_TOP11, 28, 1),
 
-	MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p,
-			SRC_TOP12, 4, 1),
+	MUX(CLK_MOUT_SW_ACLK400, "mout_sw_aclk400_disp1",
+			mout_sw_aclk400_disp1_p, SRC_TOP12, 4, 1),
 	MUX(0, "mout_sw_aclk333_g2d", mout_sw_aclk333_g2d_p,
 			SRC_TOP12, 8, 1),
 	MUX(0, "mout_sw_aclk266_g2d", mout_sw_aclk266_g2d_p,
@@ -726,8 +727,8 @@
 	MUX(0, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, SRC_TOP12, 16, 1),
 	MUX(0, "mout_sw_aclk300_jpeg", mout_sw_aclk300_jpeg_p,
 			SRC_TOP12, 20, 1),
-	MUX(0, "mout_sw_aclk300_disp1", mout_sw_aclk300_disp1_p,
-			SRC_TOP12, 24, 1),
+	MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
+			mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
 	MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
 			SRC_TOP12, 28, 1),
 
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 960bf22..f83980f 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -5,5 +5,6 @@
 obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7794)		+= clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_SH73A0)		+= clk-sh73a0.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-div6.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-mstp.o
diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c
new file mode 100644
index 0000000..cd529cf
--- /dev/null
+++ b/drivers/clk/shmobile/clk-sh73a0.c
@@ -0,0 +1,218 @@
+/*
+ * sh73a0 Core CPG Clocks
+ *
+ * Copyright (C) 2014  Ulrich Hecht
+ *
+ * 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/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct sh73a0_cpg {
+	struct clk_onecell_data data;
+	spinlock_t lock;
+	void __iomem *reg;
+};
+
+#define CPG_FRQCRA	0x00
+#define CPG_FRQCRB	0x04
+#define CPG_SD0CKCR	0x74
+#define CPG_SD1CKCR	0x78
+#define CPG_SD2CKCR	0x7c
+#define CPG_PLLECR	0xd0
+#define CPG_PLL0CR	0xd8
+#define CPG_PLL1CR	0x28
+#define CPG_PLL2CR	0x2c
+#define CPG_PLL3CR	0xdc
+#define CPG_CKSCR	0xc0
+#define CPG_DSI0PHYCR	0x6c
+#define CPG_DSI1PHYCR	0x70
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+	const char *name;
+	const char *parent;
+	unsigned int reg;
+	unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+	{ "zg", "pll0", CPG_FRQCRA, 16 },
+	{ "m3", "pll1", CPG_FRQCRA, 12 },
+	{ "b",  "pll1", CPG_FRQCRA,  8 },
+	{ "m1", "pll1", CPG_FRQCRA,  4 },
+	{ "m2", "pll1", CPG_FRQCRA,  0 },
+	{ "zx", "pll1", CPG_FRQCRB, 12 },
+	{ "hp", "pll1", CPG_FRQCRB,  4 },
+	{ NULL, NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+	{ 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+	{ 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+	{ 12, 7 }, { 0, 0 }
+};
+
+static const struct clk_div_table z_div_table[] = {
+	/* ZSEL == 0 */
+	{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 },
+	{ 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 },
+	{ 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 },
+	/* ZSEL == 1 */
+	{ 16, 2 }, { 17, 3 }, { 18, 4 }, { 19, 6 }, { 20, 8 }, { 21, 12 },
+	{ 22, 16 }, { 24, 24 }, { 27, 48 }, { 0, 0 }
+};
+
+static struct clk * __init
+sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg,
+			     const char *name)
+{
+	const struct clk_div_table *table = NULL;
+	unsigned int shift, reg, width;
+	const char *parent_name;
+	unsigned int mult = 1;
+	unsigned int div = 1;
+
+	if (!strcmp(name, "main")) {
+		/* extal1, extal1_div2, extal2, extal2_div2 */
+		u32 parent_idx = (clk_readl(cpg->reg + CPG_CKSCR) >> 28) & 3;
+
+		parent_name = of_clk_get_parent_name(np, parent_idx >> 1);
+		div = (parent_idx & 1) + 1;
+	} else if (!strncmp(name, "pll", 3)) {
+		void __iomem *enable_reg = cpg->reg;
+		u32 enable_bit = name[3] - '0';
+
+		parent_name = "main";
+		switch (enable_bit) {
+		case 0:
+			enable_reg += CPG_PLL0CR;
+			break;
+		case 1:
+			enable_reg += CPG_PLL1CR;
+			break;
+		case 2:
+			enable_reg += CPG_PLL2CR;
+			break;
+		case 3:
+			enable_reg += CPG_PLL3CR;
+			break;
+		default:
+			return ERR_PTR(-EINVAL);
+		}
+		if (clk_readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) {
+			mult = ((clk_readl(enable_reg) >> 24) & 0x3f) + 1;
+			/* handle CFG bit for PLL1 and PLL2 */
+			if (enable_bit == 1 || enable_bit == 2)
+				if (clk_readl(enable_reg) & BIT(20))
+					mult *= 2;
+		}
+	} else if (!strcmp(name, "dsi0phy") || !strcmp(name, "dsi1phy")) {
+		u32 phy_no = name[3] - '0';
+		void __iomem *dsi_reg = cpg->reg +
+			(phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR);
+
+		parent_name = phy_no ? "dsi1pck" : "dsi0pck";
+		mult = __raw_readl(dsi_reg);
+		if (!(mult & 0x8000))
+			mult = 1;
+		else
+			mult = (mult & 0x3f) + 1;
+	} else if (!strcmp(name, "z")) {
+		parent_name = "pll0";
+		table = z_div_table;
+		reg = CPG_FRQCRB;
+		shift = 24;
+		width = 5;
+	} else {
+		struct div4_clk *c;
+
+		for (c = div4_clks; c->name; c++) {
+			if (!strcmp(name, c->name)) {
+				parent_name = c->parent;
+				table = div4_div_table;
+				reg = c->reg;
+				shift = c->shift;
+				width = 4;
+				break;
+			}
+		}
+		if (!c->name)
+			return ERR_PTR(-EINVAL);
+	}
+
+	if (!table) {
+		return clk_register_fixed_factor(NULL, name, parent_name, 0,
+						 mult, div);
+	} else {
+		return clk_register_divider_table(NULL, name, parent_name, 0,
+						  cpg->reg + reg, shift, width, 0,
+						  table, &cpg->lock);
+	}
+}
+
+static void __init sh73a0_cpg_clocks_init(struct device_node *np)
+{
+	struct sh73a0_cpg *cpg;
+	struct clk **clks;
+	unsigned int i;
+	int num_clks;
+
+	num_clks = of_property_count_strings(np, "clock-output-names");
+	if (num_clks < 0) {
+		pr_err("%s: failed to count clocks\n", __func__);
+		return;
+	}
+
+	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+	clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+	if (cpg == NULL || clks == NULL) {
+		/* We're leaking memory on purpose, there's no point in cleaning
+		 * up as the system won't boot anyway.
+		 */
+		return;
+	}
+
+	spin_lock_init(&cpg->lock);
+
+	cpg->data.clks = clks;
+	cpg->data.clk_num = num_clks;
+
+	cpg->reg = of_iomap(np, 0);
+	if (WARN_ON(cpg->reg == NULL))
+		return;
+
+	/* Set SDHI clocks to a known state */
+	clk_writel(0x108, cpg->reg + CPG_SD0CKCR);
+	clk_writel(0x108, cpg->reg + CPG_SD1CKCR);
+	clk_writel(0x108, cpg->reg + CPG_SD2CKCR);
+
+	for (i = 0; i < num_clks; ++i) {
+		const char *name;
+		struct clk *clk;
+
+		of_property_read_string_index(np, "clock-output-names", i,
+					      &name);
+
+		clk = sh73a0_cpg_register_clock(np, cpg, name);
+		if (IS_ERR(clk))
+			pr_err("%s: failed to register %s %s clock (%ld)\n",
+			       __func__, np->name, name, PTR_ERR(clk));
+		else
+			cpg->data.clks[i] = clk;
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(sh73a0_cpg_clks, "renesas,sh73a0-cpg-clocks",
+	       sh73a0_cpg_clocks_init);
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 5702025..1818f40 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1226,6 +1226,7 @@
 			  ARRAY_SIZE(sun6i_critical_clocks));
 }
 CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
+CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
 CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
 
 static void __init sun9i_init_clocks(struct device_node *node)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 8a1479f..1c2506f 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,6 +18,9 @@
 config CLKSRC_MMIO
 	bool
 
+config DIGICOLOR_TIMER
+	bool
+
 config DW_APB_TIMER
 	bool
 
@@ -26,6 +29,10 @@
 	select DW_APB_TIMER
 	select CLKSRC_OF
 
+config ROCKCHIP_TIMER
+	bool
+	select CLKSRC_OF
+
 config ARMADA_370_XP_TIMER
 	bool
 	select CLKSRC_OF
@@ -47,6 +54,9 @@
 	select CLKSRC_MMIO
 	bool
 
+config TEGRA_TIMER
+	bool
+
 config VT8500_TIMER
 	bool
 
@@ -236,4 +246,14 @@
 	  This enables OST0 support available on PXA and SA-11x0
 	  platforms.
 
+config ASM9260_TIMER
+	bool "Alphascale ASM9260 timer driver"
+	depends on GENERIC_CLOCKEVENTS
+	select CLKSRC_MMIO
+	select CLKSRC_OF
+	default y if MACH_ASM9260
+	help
+	  This enables build of a clocksource and clockevent driver for
+	  the 32-bit System Timer hardware available on a Alphascale ASM9260.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index aa526f4..752d5c7 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -10,15 +10,17 @@
 obj-$(CONFIG_EM_TIMER_STI)	+= em_sti.o
 obj-$(CONFIG_CLKBLD_I8253)	+= i8253.o
 obj-$(CONFIG_CLKSRC_MMIO)	+= mmio.o
+obj-$(CONFIG_DIGICOLOR_TIMER)	+= timer-digicolor.o
 obj-$(CONFIG_DW_APB_TIMER)	+= dw_apb_timer.o
 obj-$(CONFIG_DW_APB_TIMER_OF)	+= dw_apb_timer_of.o
+obj-$(CONFIG_ROCKCHIP_TIMER)      += rockchip_timer.o
 obj-$(CONFIG_CLKSRC_NOMADIK_MTU)	+= nomadik-mtu.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)	+= clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)	+= time-armada-370-xp.o
 obj-$(CONFIG_ORION_TIMER)	+= time-orion.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_ARCH_CLPS711X)	+= clps711x-timer.o
-obj-$(CONFIG_ARCH_MARCO)	+= timer-marco.o
+obj-$(CONFIG_ARCH_ATLAS7)	+= timer-atlas7.o
 obj-$(CONFIG_ARCH_MOXART)	+= moxart_timer.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o
 obj-$(CONFIG_CLKSRC_PXA)	+= pxa_timer.o
@@ -27,7 +29,7 @@
 obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o
 obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
 obj-$(CONFIG_MESON6_TIMER)	+= meson6_timer.o
-obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
+obj-$(CONFIG_TEGRA_TIMER)	+= tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
 obj-$(CONFIG_ARCH_NSPIRE)	+= zevio-timer.o
 obj-$(CONFIG_ARCH_BCM_MOBILE)	+= bcm_kona_timer.o
@@ -48,3 +50,4 @@
 obj-$(CONFIG_ARCH_INTEGRATOR_AP)	+= timer-integrator-ap.o
 obj-$(CONFIG_CLKSRC_VERSATILE)		+= versatile.o
 obj-$(CONFIG_CLKSRC_MIPS_GIC)		+= mips-gic-timer.o
+obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
new file mode 100644
index 0000000..2c9c993
--- /dev/null
+++ b/drivers/clocksource/asm9260_timer.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/bitops.h>
+
+#define DRIVER_NAME	"asm9260-timer"
+
+/*
+ * this device provide 4 offsets for each register:
+ * 0x0 - plain read write mode
+ * 0x4 - set mode, OR logic.
+ * 0x8 - clr mode, XOR logic.
+ * 0xc - togle mode.
+ */
+#define SET_REG 4
+#define CLR_REG 8
+
+#define HW_IR           0x0000 /* RW. Interrupt */
+#define BM_IR_CR0	BIT(4)
+#define BM_IR_MR3	BIT(3)
+#define BM_IR_MR2	BIT(2)
+#define BM_IR_MR1	BIT(1)
+#define BM_IR_MR0	BIT(0)
+
+#define HW_TCR		0x0010 /* RW. Timer controller */
+/* BM_C*_RST
+ * Timer Counter and the Prescale Counter are synchronously reset on the
+ * next positive edge of PCLK. The counters remain reset until TCR[1] is
+ * returned to zero. */
+#define BM_C3_RST	BIT(7)
+#define BM_C2_RST	BIT(6)
+#define BM_C1_RST	BIT(5)
+#define BM_C0_RST	BIT(4)
+/* BM_C*_EN
+ * 1 - Timer Counter and Prescale Counter are enabled for counting
+ * 0 - counters are disabled */
+#define BM_C3_EN	BIT(3)
+#define BM_C2_EN	BIT(2)
+#define BM_C1_EN	BIT(1)
+#define BM_C0_EN	BIT(0)
+
+#define HW_DIR		0x0020 /* RW. Direction? */
+/* 00 - count up
+ * 01 - count down
+ * 10 - ?? 2^n/2 */
+#define BM_DIR_COUNT_UP		0
+#define BM_DIR_COUNT_DOWN	1
+#define BM_DIR0_SHIFT	0
+#define BM_DIR1_SHIFT	4
+#define BM_DIR2_SHIFT	8
+#define BM_DIR3_SHIFT	12
+#define BM_DIR_DEFAULT		(BM_DIR_COUNT_UP << BM_DIR0_SHIFT | \
+				 BM_DIR_COUNT_UP << BM_DIR1_SHIFT | \
+				 BM_DIR_COUNT_UP << BM_DIR2_SHIFT | \
+				 BM_DIR_COUNT_UP << BM_DIR3_SHIFT)
+
+#define HW_TC0		0x0030 /* RO. Timer counter 0 */
+/* HW_TC*. Timer counter owerflow (0xffff.ffff to 0x0000.0000) do not generate
+ * interrupt. This registers can be used to detect overflow */
+#define HW_TC1          0x0040
+#define HW_TC2		0x0050
+#define HW_TC3		0x0060
+
+#define HW_PR		0x0070 /* RW. prescaler */
+#define BM_PR_DISABLE	0
+#define HW_PC		0x0080 /* RO. Prescaler counter */
+#define HW_MCR		0x0090 /* RW. Match control */
+/* enable interrupt on match */
+#define BM_MCR_INT_EN(n)	(1 << (n * 3 + 0))
+/* enable TC reset on match */
+#define BM_MCR_RES_EN(n)	(1 << (n * 3 + 1))
+/* enable stop TC on match */
+#define BM_MCR_STOP_EN(n)	(1 << (n * 3 + 2))
+
+#define HW_MR0		0x00a0 /* RW. Match reg */
+#define HW_MR1		0x00b0
+#define HW_MR2		0x00C0
+#define HW_MR3		0x00D0
+
+#define HW_CTCR		0x0180 /* Counter control */
+#define BM_CTCR0_SHIFT	0
+#define BM_CTCR1_SHIFT	2
+#define BM_CTCR2_SHIFT	4
+#define BM_CTCR3_SHIFT	6
+#define BM_CTCR_TM	0	/* Timer mode. Every rising PCLK edge. */
+#define BM_CTCR_DEFAULT	(BM_CTCR_TM << BM_CTCR0_SHIFT | \
+			 BM_CTCR_TM << BM_CTCR1_SHIFT | \
+			 BM_CTCR_TM << BM_CTCR2_SHIFT | \
+			 BM_CTCR_TM << BM_CTCR3_SHIFT)
+
+static struct asm9260_timer_priv {
+	void __iomem *base;
+	unsigned long ticks_per_jiffy;
+} priv;
+
+static int asm9260_timer_set_next_event(unsigned long delta,
+					 struct clock_event_device *evt)
+{
+	/* configure match count for TC0 */
+	writel_relaxed(delta, priv.base + HW_MR0);
+	/* enable TC0 */
+	writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
+	return 0;
+}
+
+static void asm9260_timer_set_mode(enum clock_event_mode mode,
+				    struct clock_event_device *evt)
+{
+	/* stop timer0 */
+	writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* disable reset and stop on match */
+		writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
+				priv.base + HW_MCR + CLR_REG);
+		/* configure match count for TC0 */
+		writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0);
+		/* enable TC0 */
+		writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* enable reset and stop on match */
+		writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
+				priv.base + HW_MCR + SET_REG);
+		break;
+	default:
+		break;
+	}
+}
+
+static struct clock_event_device event_dev = {
+	.name		= DRIVER_NAME,
+	.rating		= 200,
+	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event	= asm9260_timer_set_next_event,
+	.set_mode	= asm9260_timer_set_mode,
+};
+
+static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	evt->event_handler(evt);
+
+	writel_relaxed(BM_IR_MR0, priv.base + HW_IR);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init asm9260_timer_init(struct device_node *np)
+{
+	int irq;
+	struct clk *clk;
+	int ret;
+	unsigned long rate;
+
+	priv.base = of_io_request_and_map(np, 0, np->name);
+	if (!priv.base)
+		panic("%s: unable to map resource", np->name);
+
+	clk = of_clk_get(np, 0);
+
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		panic("Failed to enable clk!\n");
+
+	irq = irq_of_parse_and_map(np, 0);
+	ret = request_irq(irq, asm9260_timer_interrupt, IRQF_TIMER,
+			DRIVER_NAME, &event_dev);
+	if (ret)
+		panic("Failed to setup irq!\n");
+
+	/* set all timers for count-up */
+	writel_relaxed(BM_DIR_DEFAULT, priv.base + HW_DIR);
+	/* disable divider */
+	writel_relaxed(BM_PR_DISABLE, priv.base + HW_PR);
+	/* make sure all timers use every rising PCLK edge. */
+	writel_relaxed(BM_CTCR_DEFAULT, priv.base + HW_CTCR);
+	/* enable interrupt for TC0 and clean setting for all other lines */
+	writel_relaxed(BM_MCR_INT_EN(0) , priv.base + HW_MCR);
+
+	rate = clk_get_rate(clk);
+	clocksource_mmio_init(priv.base + HW_TC1, DRIVER_NAME, rate,
+			200, 32, clocksource_mmio_readl_up);
+
+	/* Seems like we can't use counter without match register even if
+	 * actions for MR are disabled. So, set MR to max value. */
+	writel_relaxed(0xffffffff, priv.base + HW_MR1);
+	/* enable TC1 */
+	writel_relaxed(BM_C1_EN, priv.base + HW_TCR + SET_REG);
+
+	priv.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
+	event_dev.cpumask = cpumask_of(0);
+	clockevents_config_and_register(&event_dev, rate, 0x2c00, 0xfffffffe);
+}
+CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer",
+		asm9260_timer_init);
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
new file mode 100644
index 0000000..a35993b
--- /dev/null
+++ b/drivers/clocksource/rockchip_timer.c
@@ -0,0 +1,180 @@
+/*
+ * Rockchip timer support
+ *
+ * Copyright (C) Daniel Lezcano <daniel.lezcano@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.
+ */
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_NAME "rk_timer"
+
+#define TIMER_LOAD_COUNT0 0x00
+#define TIMER_LOAD_COUNT1 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_INT_STATUS 0x18
+
+#define TIMER_DISABLE 0x0
+#define TIMER_ENABLE 0x1
+#define TIMER_MODE_FREE_RUNNING (0 << 1)
+#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
+#define TIMER_INT_UNMASK (1 << 2)
+
+struct bc_timer {
+	struct clock_event_device ce;
+	void __iomem *base;
+	u32 freq;
+};
+
+static struct bc_timer bc_timer;
+
+static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
+{
+	return container_of(ce, struct bc_timer, ce);
+}
+
+static inline void __iomem *rk_base(struct clock_event_device *ce)
+{
+	return rk_timer(ce)->base;
+}
+
+static inline void rk_timer_disable(struct clock_event_device *ce)
+{
+	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
+	dsb();
+}
+
+static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
+{
+	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
+		       rk_base(ce) + TIMER_CONTROL_REG);
+	dsb();
+}
+
+static void rk_timer_update_counter(unsigned long cycles,
+				    struct clock_event_device *ce)
+{
+	writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
+	writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
+	dsb();
+}
+
+static void rk_timer_interrupt_clear(struct clock_event_device *ce)
+{
+	writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
+	dsb();
+}
+
+static inline int rk_timer_set_next_event(unsigned long cycles,
+					  struct clock_event_device *ce)
+{
+	rk_timer_disable(ce);
+	rk_timer_update_counter(cycles, ce);
+	rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
+	return 0;
+}
+
+static inline void rk_timer_set_mode(enum clock_event_mode mode,
+				     struct clock_event_device *ce)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		rk_timer_disable(ce);
+		rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
+		rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		rk_timer_disable(ce);
+		break;
+	}
+}
+
+static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+
+	rk_timer_interrupt_clear(ce);
+
+	if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+		rk_timer_disable(ce);
+
+	ce->event_handler(ce);
+
+	return IRQ_HANDLED;
+}
+
+static void __init rk_timer_init(struct device_node *np)
+{
+	struct clock_event_device *ce = &bc_timer.ce;
+	struct clk *timer_clk;
+	struct clk *pclk;
+	int ret, irq;
+
+	bc_timer.base = of_iomap(np, 0);
+	if (!bc_timer.base) {
+		pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
+		return;
+	}
+
+	pclk = of_clk_get_by_name(np, "pclk");
+	if (IS_ERR(pclk)) {
+		pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
+		return;
+	}
+
+	if (clk_prepare_enable(pclk)) {
+		pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
+		return;
+	}
+
+	timer_clk = of_clk_get_by_name(np, "timer");
+	if (IS_ERR(timer_clk)) {
+		pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
+		return;
+	}
+
+	if (clk_prepare_enable(timer_clk)) {
+		pr_err("Failed to enable timer clock\n");
+		return;
+	}
+
+	bc_timer.freq = clk_get_rate(timer_clk);
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (irq == NO_IRQ) {
+		pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
+		return;
+	}
+
+	ce->name = TIMER_NAME;
+	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	ce->set_next_event = rk_timer_set_next_event;
+	ce->set_mode = rk_timer_set_mode;
+	ce->irq = irq;
+	ce->cpumask = cpumask_of(0);
+	ce->rating = 250;
+
+	rk_timer_interrupt_clear(ce);
+	rk_timer_disable(ce);
+
+	ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
+	if (ret) {
+		pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
+		return;
+	}
+
+	clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c
new file mode 100644
index 0000000..60f9de3
--- /dev/null
+++ b/drivers/clocksource/timer-atlas7.c
@@ -0,0 +1,306 @@
+/*
+ * System timer for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/cpu.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+
+#define SIRFSOC_TIMER_32COUNTER_0_CTRL			0x0000
+#define SIRFSOC_TIMER_32COUNTER_1_CTRL			0x0004
+#define SIRFSOC_TIMER_MATCH_0				0x0018
+#define SIRFSOC_TIMER_MATCH_1				0x001c
+#define SIRFSOC_TIMER_COUNTER_0				0x0048
+#define SIRFSOC_TIMER_COUNTER_1				0x004c
+#define SIRFSOC_TIMER_INTR_STATUS			0x0060
+#define SIRFSOC_TIMER_WATCHDOG_EN			0x0064
+#define SIRFSOC_TIMER_64COUNTER_CTRL			0x0068
+#define SIRFSOC_TIMER_64COUNTER_LO			0x006c
+#define SIRFSOC_TIMER_64COUNTER_HI			0x0070
+#define SIRFSOC_TIMER_64COUNTER_LOAD_LO			0x0074
+#define SIRFSOC_TIMER_64COUNTER_LOAD_HI			0x0078
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO		0x007c
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI		0x0080
+
+#define SIRFSOC_TIMER_REG_CNT 6
+
+static unsigned long atlas7_timer_rate;
+
+static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
+	SIRFSOC_TIMER_WATCHDOG_EN,
+	SIRFSOC_TIMER_32COUNTER_0_CTRL,
+	SIRFSOC_TIMER_32COUNTER_1_CTRL,
+	SIRFSOC_TIMER_64COUNTER_CTRL,
+	SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
+	SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
+};
+
+static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
+
+static void __iomem *sirfsoc_timer_base;
+
+/* disable count and interrupt */
+static inline void sirfsoc_timer_count_disable(int idx)
+{
+	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
+		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* enable count and interrupt */
+static inline void sirfsoc_timer_count_enable(int idx)
+{
+	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
+		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* timer interrupt handler */
+static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+	int cpu = smp_processor_id();
+
+	/* clear timer interrupt */
+	writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+	if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+		sirfsoc_timer_count_disable(cpu);
+
+	ce->event_handler(ce);
+
+	return IRQ_HANDLED;
+}
+
+/* read 64-bit timer counter */
+static cycle_t sirfsoc_timer_read(struct clocksource *cs)
+{
+	u64 cycles;
+
+	writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+			BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+
+	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
+	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
+
+	return cycles;
+}
+
+static int sirfsoc_timer_set_next_event(unsigned long delta,
+	struct clock_event_device *ce)
+{
+	int cpu = smp_processor_id();
+
+	/* disable timer first, then modify the related registers */
+	sirfsoc_timer_count_disable(cpu);
+
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
+		4 * cpu);
+	writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
+		4 * cpu);
+
+	/* enable the tick */
+	sirfsoc_timer_count_enable(cpu);
+
+	return 0;
+}
+
+static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
+	struct clock_event_device *ce)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* enable in set_next_event */
+		break;
+	default:
+		break;
+	}
+
+	sirfsoc_timer_count_disable(smp_processor_id());
+}
+
+static void sirfsoc_clocksource_suspend(struct clocksource *cs)
+{
+	int i;
+
+	for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
+		sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+}
+
+static void sirfsoc_clocksource_resume(struct clocksource *cs)
+{
+	int i;
+
+	for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
+		writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+
+	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
+		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
+	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
+		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+
+	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+}
+
+static struct clock_event_device __percpu *sirfsoc_clockevent;
+
+static struct clocksource sirfsoc_clocksource = {
+	.name = "sirfsoc_clocksource",
+	.rating = 200,
+	.mask = CLOCKSOURCE_MASK(64),
+	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+	.read = sirfsoc_timer_read,
+	.suspend = sirfsoc_clocksource_suspend,
+	.resume = sirfsoc_clocksource_resume,
+};
+
+static struct irqaction sirfsoc_timer_irq = {
+	.name = "sirfsoc_timer0",
+	.flags = IRQF_TIMER | IRQF_NOBALANCING,
+	.handler = sirfsoc_timer_interrupt,
+};
+
+static struct irqaction sirfsoc_timer1_irq = {
+	.name = "sirfsoc_timer1",
+	.flags = IRQF_TIMER | IRQF_NOBALANCING,
+	.handler = sirfsoc_timer_interrupt,
+};
+
+static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
+{
+	int cpu = smp_processor_id();
+	struct irqaction *action;
+
+	if (cpu == 0)
+		action = &sirfsoc_timer_irq;
+	else
+		action = &sirfsoc_timer1_irq;
+
+	ce->irq = action->irq;
+	ce->name = "local_timer";
+	ce->features = CLOCK_EVT_FEAT_ONESHOT;
+	ce->rating = 200;
+	ce->set_mode = sirfsoc_timer_set_mode;
+	ce->set_next_event = sirfsoc_timer_set_next_event;
+	clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
+	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
+	ce->min_delta_ns = clockevent_delta2ns(2, ce);
+	ce->cpumask = cpumask_of(cpu);
+
+	action->dev_id = ce;
+	BUG_ON(setup_irq(ce->irq, action));
+	irq_force_affinity(action->irq, cpumask_of(cpu));
+
+	clockevents_register_device(ce);
+	return 0;
+}
+
+static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
+{
+	int cpu = smp_processor_id();
+
+	sirfsoc_timer_count_disable(1);
+
+	if (cpu == 0)
+		remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+	else
+		remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+}
+
+static int sirfsoc_cpu_notify(struct notifier_block *self,
+			      unsigned long action, void *hcpu)
+{
+	/*
+	 * Grab cpu pointer in each case to avoid spurious
+	 * preemptible warnings
+	 */
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_STARTING:
+		sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+		break;
+	case CPU_DYING:
+		sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block sirfsoc_cpu_nb = {
+	.notifier_call = sirfsoc_cpu_notify,
+};
+
+static void __init sirfsoc_clockevent_init(void)
+{
+	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
+	BUG_ON(!sirfsoc_clockevent);
+
+	BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
+
+	/* Immediately configure the timer on the boot CPU */
+	sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+}
+
+/* initialize the kernel jiffy timer source */
+static void __init sirfsoc_atlas7_timer_init(struct device_node *np)
+{
+	struct clk *clk;
+
+	clk = of_clk_get(np, 0);
+	BUG_ON(IS_ERR(clk));
+
+	BUG_ON(clk_prepare_enable(clk));
+
+	atlas7_timer_rate = clk_get_rate(clk);
+
+	/* timer dividers: 0, not divided */
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
+
+	/* Initialize timer counters to 0 */
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
+	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
+
+	/* Clear all interrupts */
+	writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate));
+
+	sirfsoc_clockevent_init();
+}
+
+static void __init sirfsoc_of_timer_init(struct device_node *np)
+{
+	sirfsoc_timer_base = of_iomap(np, 0);
+	if (!sirfsoc_timer_base)
+		panic("unable to map timer cpu registers\n");
+
+	sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
+	if (!sirfsoc_timer_irq.irq)
+		panic("No irq passed for timer0 via DT\n");
+
+	sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
+	if (!sirfsoc_timer1_irq.irq)
+		panic("No irq passed for timer1 via DT\n");
+
+	sirfsoc_atlas7_timer_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c
new file mode 100644
index 0000000..7f8388c
--- /dev/null
+++ b/drivers/clocksource/timer-digicolor.c
@@ -0,0 +1,199 @@
+/*
+ * Conexant Digicolor timer driver
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * Based on:
+ *	Allwinner SoCs hstimer driver
+ *
+ * Copyright (C) 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.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.
+ */
+
+/*
+ * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to
+ * "Timer H". Timer A is the only one with watchdog support, so it is dedicated
+ * to the watchdog driver. This driver uses Timer B for sched_clock(), and
+ * Timer C for clockevents.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/sched_clock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+enum {
+	TIMER_A,
+	TIMER_B,
+	TIMER_C,
+	TIMER_D,
+	TIMER_E,
+	TIMER_F,
+	TIMER_G,
+	TIMER_H,
+};
+
+#define CONTROL(t)	((t)*8)
+#define COUNT(t)	((t)*8 + 4)
+
+#define CONTROL_DISABLE		0
+#define CONTROL_ENABLE		BIT(0)
+#define CONTROL_MODE(m)		((m) << 4)
+#define CONTROL_MODE_ONESHOT	CONTROL_MODE(1)
+#define CONTROL_MODE_PERIODIC	CONTROL_MODE(2)
+
+struct digicolor_timer {
+	struct clock_event_device ce;
+	void __iomem *base;
+	u32 ticks_per_jiffy;
+	int timer_id; /* one of TIMER_* */
+};
+
+struct digicolor_timer *dc_timer(struct clock_event_device *ce)
+{
+	return container_of(ce, struct digicolor_timer, ce);
+}
+
+static inline void dc_timer_disable(struct clock_event_device *ce)
+{
+	struct digicolor_timer *dt = dc_timer(ce);
+	writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id));
+}
+
+static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode)
+{
+	struct digicolor_timer *dt = dc_timer(ce);
+	writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id));
+}
+
+static inline void dc_timer_set_count(struct clock_event_device *ce,
+				      unsigned long count)
+{
+	struct digicolor_timer *dt = dc_timer(ce);
+	writel(count, dt->base + COUNT(dt->timer_id));
+}
+
+static void digicolor_clkevt_mode(enum clock_event_mode mode,
+				  struct clock_event_device *ce)
+{
+	struct digicolor_timer *dt = dc_timer(ce);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		dc_timer_disable(ce);
+		dc_timer_set_count(ce, dt->ticks_per_jiffy);
+		dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		dc_timer_disable(ce);
+		dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		dc_timer_disable(ce);
+		break;
+	}
+}
+
+static int digicolor_clkevt_next_event(unsigned long evt,
+				       struct clock_event_device *ce)
+{
+	dc_timer_disable(ce);
+	dc_timer_set_count(ce, evt);
+	dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
+
+	return 0;
+}
+
+static struct digicolor_timer dc_timer_dev = {
+	.ce = {
+		.name = "digicolor_tick",
+		.rating = 340,
+		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+		.set_mode = digicolor_clkevt_mode,
+		.set_next_event = digicolor_clkevt_next_event,
+	},
+	.timer_id = TIMER_C,
+};
+
+static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static u64 digicolor_timer_sched_read(void)
+{
+	return ~readl(dc_timer_dev.base + COUNT(TIMER_B));
+}
+
+static void __init digicolor_timer_init(struct device_node *node)
+{
+	unsigned long rate;
+	struct clk *clk;
+	int ret, irq;
+
+	/*
+	 * timer registers are shared with the watchdog timer;
+	 * don't map exclusively
+	 */
+	dc_timer_dev.base = of_iomap(node, 0);
+	if (!dc_timer_dev.base) {
+		pr_err("Can't map registers");
+		return;
+	}
+
+	irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
+	if (irq <= 0) {
+		pr_err("Can't parse IRQ");
+		return;
+	}
+
+	clk = of_clk_get(node, 0);
+	if (IS_ERR(clk)) {
+		pr_err("Can't get timer clock");
+		return;
+	}
+	clk_prepare_enable(clk);
+	rate = clk_get_rate(clk);
+	dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
+
+	writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B));
+	writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B));
+	writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B));
+
+	sched_clock_register(digicolor_timer_sched_read, 32, rate);
+	clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name,
+			      rate, 340, 32, clocksource_mmio_readl_down);
+
+	ret = request_irq(irq, digicolor_timer_interrupt,
+			  IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC",
+			  &dc_timer_dev.ce);
+	if (ret)
+		pr_warn("request of timer irq %d failed (%d)\n", irq, ret);
+
+	dc_timer_dev.ce.cpumask = cpu_possible_mask;
+	dc_timer_dev.ce.irq = irq;
+
+	clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff);
+}
+CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
+		       digicolor_timer_init);
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c
deleted file mode 100644
index 361a789..0000000
--- a/drivers/clocksource/timer-marco.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * System timer for CSR SiRFprimaII
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/clocksource.h>
-#include <linux/cpu.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/sched_clock.h>
-
-#define SIRFSOC_TIMER_32COUNTER_0_CTRL			0x0000
-#define SIRFSOC_TIMER_32COUNTER_1_CTRL			0x0004
-#define SIRFSOC_TIMER_MATCH_0				0x0018
-#define SIRFSOC_TIMER_MATCH_1				0x001c
-#define SIRFSOC_TIMER_COUNTER_0				0x0048
-#define SIRFSOC_TIMER_COUNTER_1				0x004c
-#define SIRFSOC_TIMER_INTR_STATUS			0x0060
-#define SIRFSOC_TIMER_WATCHDOG_EN			0x0064
-#define SIRFSOC_TIMER_64COUNTER_CTRL			0x0068
-#define SIRFSOC_TIMER_64COUNTER_LO			0x006c
-#define SIRFSOC_TIMER_64COUNTER_HI			0x0070
-#define SIRFSOC_TIMER_64COUNTER_LOAD_LO			0x0074
-#define SIRFSOC_TIMER_64COUNTER_LOAD_HI			0x0078
-#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO		0x007c
-#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI		0x0080
-
-#define SIRFSOC_TIMER_REG_CNT 6
-
-static unsigned long marco_timer_rate;
-
-static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
-	SIRFSOC_TIMER_WATCHDOG_EN,
-	SIRFSOC_TIMER_32COUNTER_0_CTRL,
-	SIRFSOC_TIMER_32COUNTER_1_CTRL,
-	SIRFSOC_TIMER_64COUNTER_CTRL,
-	SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
-	SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
-};
-
-static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
-
-static void __iomem *sirfsoc_timer_base;
-
-/* disable count and interrupt */
-static inline void sirfsoc_timer_count_disable(int idx)
-{
-	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
-		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
-}
-
-/* enable count and interrupt */
-static inline void sirfsoc_timer_count_enable(int idx)
-{
-	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
-		sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
-}
-
-/* timer interrupt handler */
-static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *ce = dev_id;
-	int cpu = smp_processor_id();
-
-	/* clear timer interrupt */
-	writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
-
-	if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
-		sirfsoc_timer_count_disable(cpu);
-
-	ce->event_handler(ce);
-
-	return IRQ_HANDLED;
-}
-
-/* read 64-bit timer counter */
-static cycle_t sirfsoc_timer_read(struct clocksource *cs)
-{
-	u64 cycles;
-
-	writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
-			BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-
-	cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
-	cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
-
-	return cycles;
-}
-
-static int sirfsoc_timer_set_next_event(unsigned long delta,
-	struct clock_event_device *ce)
-{
-	int cpu = smp_processor_id();
-
-	/* disable timer first, then modify the related registers */
-	sirfsoc_timer_count_disable(cpu);
-
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
-		4 * cpu);
-	writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
-		4 * cpu);
-
-	/* enable the tick */
-	sirfsoc_timer_count_enable(cpu);
-
-	return 0;
-}
-
-static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
-	struct clock_event_device *ce)
-{
-	switch (mode) {
-	case CLOCK_EVT_MODE_ONESHOT:
-		/* enable in set_next_event */
-		break;
-	default:
-		break;
-	}
-
-	sirfsoc_timer_count_disable(smp_processor_id());
-}
-
-static void sirfsoc_clocksource_suspend(struct clocksource *cs)
-{
-	int i;
-
-	for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
-		sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
-}
-
-static void sirfsoc_clocksource_resume(struct clocksource *cs)
-{
-	int i;
-
-	for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
-		writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
-
-	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
-		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
-	writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
-		sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
-
-	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
-		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-}
-
-static struct clock_event_device __percpu *sirfsoc_clockevent;
-
-static struct clocksource sirfsoc_clocksource = {
-	.name = "sirfsoc_clocksource",
-	.rating = 200,
-	.mask = CLOCKSOURCE_MASK(64),
-	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
-	.read = sirfsoc_timer_read,
-	.suspend = sirfsoc_clocksource_suspend,
-	.resume = sirfsoc_clocksource_resume,
-};
-
-static struct irqaction sirfsoc_timer_irq = {
-	.name = "sirfsoc_timer0",
-	.flags = IRQF_TIMER | IRQF_NOBALANCING,
-	.handler = sirfsoc_timer_interrupt,
-};
-
-static struct irqaction sirfsoc_timer1_irq = {
-	.name = "sirfsoc_timer1",
-	.flags = IRQF_TIMER | IRQF_NOBALANCING,
-	.handler = sirfsoc_timer_interrupt,
-};
-
-static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
-{
-	int cpu = smp_processor_id();
-	struct irqaction *action;
-
-	if (cpu == 0)
-		action = &sirfsoc_timer_irq;
-	else
-		action = &sirfsoc_timer1_irq;
-
-	ce->irq = action->irq;
-	ce->name = "local_timer";
-	ce->features = CLOCK_EVT_FEAT_ONESHOT;
-	ce->rating = 200;
-	ce->set_mode = sirfsoc_timer_set_mode;
-	ce->set_next_event = sirfsoc_timer_set_next_event;
-	clockevents_calc_mult_shift(ce, marco_timer_rate, 60);
-	ce->max_delta_ns = clockevent_delta2ns(-2, ce);
-	ce->min_delta_ns = clockevent_delta2ns(2, ce);
-	ce->cpumask = cpumask_of(cpu);
-
-	action->dev_id = ce;
-	BUG_ON(setup_irq(ce->irq, action));
-	irq_force_affinity(action->irq, cpumask_of(cpu));
-
-	clockevents_register_device(ce);
-	return 0;
-}
-
-static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
-{
-	int cpu = smp_processor_id();
-
-	sirfsoc_timer_count_disable(1);
-
-	if (cpu == 0)
-		remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
-	else
-		remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
-}
-
-static int sirfsoc_cpu_notify(struct notifier_block *self,
-			      unsigned long action, void *hcpu)
-{
-	/*
-	 * Grab cpu pointer in each case to avoid spurious
-	 * preemptible warnings
-	 */
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_STARTING:
-		sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
-		break;
-	case CPU_DYING:
-		sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block sirfsoc_cpu_nb = {
-	.notifier_call = sirfsoc_cpu_notify,
-};
-
-static void __init sirfsoc_clockevent_init(void)
-{
-	sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
-	BUG_ON(!sirfsoc_clockevent);
-
-	BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
-
-	/* Immediately configure the timer on the boot CPU */
-	sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
-}
-
-/* initialize the kernel jiffy timer source */
-static void __init sirfsoc_marco_timer_init(struct device_node *np)
-{
-	u32 timer_div;
-	struct clk *clk;
-
-	clk = of_clk_get(np, 0);
-	BUG_ON(IS_ERR(clk));
-
-	BUG_ON(clk_prepare_enable(clk));
-
-	marco_timer_rate = clk_get_rate(clk);
-
-	/* timer dividers: 0, not divided */
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
-
-	/* Initialize timer counters to 0 */
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
-	writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
-		BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
-	writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
-
-	/* Clear all interrupts */
-	writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
-
-	BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate));
-
-	sirfsoc_clockevent_init();
-}
-
-static void __init sirfsoc_of_timer_init(struct device_node *np)
-{
-	sirfsoc_timer_base = of_iomap(np, 0);
-	if (!sirfsoc_timer_base)
-		panic("unable to map timer cpu registers\n");
-
-	sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
-	if (!sirfsoc_timer_irq.irq)
-		panic("No irq passed for timer0 via DT\n");
-
-	sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
-	if (!sirfsoc_timer1_irq.irq)
-		panic("No irq passed for timer1 via DT\n");
-
-	sirfsoc_marco_timer_init(np);
-}
-CLOCKSOURCE_OF_DECLARE(sirfsoc_marco_timer, "sirf,marco-tick", sirfsoc_of_timer_init );
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c
index 2798e74..0a26d3d 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/versatile.c
@@ -36,5 +36,7 @@
 
 	sched_clock_register(versatile_sys_24mhz_read, 32, 24000000);
 }
-CLOCKSOURCE_OF_DECLARE(versatile, "arm,vexpress-sysreg",
+CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg",
+		       versatile_sched_clock_init);
+CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg",
 		       versatile_sched_clock_init);
diff --git a/drivers/coresight/coresight-etb10.c b/drivers/coresight/coresight-etb10.c
index c922d4a..c9acd40 100644
--- a/drivers/coresight/coresight-etb10.c
+++ b/drivers/coresight/coresight-etb10.c
@@ -454,7 +454,7 @@
 	if (ret)
 		return ret;
 
-	drvdata->buffer_depth =  etb_get_buffer_depth(drvdata);
+	drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
 	clk_disable_unprepare(drvdata->clk);
 
 	if (drvdata->buffer_depth < 0)
@@ -521,17 +521,7 @@
 	.id_table	= etb_ids,
 };
 
-static int __init etb_init(void)
-{
-	return amba_driver_register(&etb_driver);
-}
-module_init(etb_init);
-
-static void __exit etb_exit(void)
-{
-	amba_driver_unregister(&etb_driver);
-}
-module_exit(etb_exit);
+module_amba_driver(etb_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
diff --git a/drivers/coresight/coresight-etm3x.c b/drivers/coresight/coresight-etm3x.c
index d9e3ed6..c965f57 100644
--- a/drivers/coresight/coresight-etm3x.c
+++ b/drivers/coresight/coresight-etm3x.c
@@ -34,14 +34,8 @@
 
 #include "coresight-etm.h"
 
-#ifdef CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE
-static int boot_enable = 1;
-#else
 static int boot_enable;
-#endif
-module_param_named(
-	boot_enable, boot_enable, int, S_IRUGO
-);
+module_param_named(boot_enable, boot_enable, int, S_IRUGO);
 
 /* The number of ETM/PTM currently registered */
 static int etm_count;
@@ -573,7 +567,8 @@
 	if (drvdata->mode & ETM_MODE_STALL) {
 		if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
 			dev_warn(drvdata->dev, "stall mode not supported\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_unlock;
 		}
 		drvdata->ctrl |= ETMCR_STALL_MODE;
 	 } else
@@ -582,7 +577,8 @@
 	if (drvdata->mode & ETM_MODE_TIMESTAMP) {
 		if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
 			dev_warn(drvdata->dev, "timestamp not supported\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_unlock;
 		}
 		drvdata->ctrl |= ETMCR_TIMESTAMP_EN;
 	} else
@@ -595,6 +591,10 @@
 	spin_unlock(&drvdata->spinlock);
 
 	return size;
+
+err_unlock:
+	spin_unlock(&drvdata->spinlock);
+	return ret;
 }
 static DEVICE_ATTR_RW(mode);
 
@@ -1743,7 +1743,11 @@
 
 static void etm_init_default_data(struct etm_drvdata *drvdata)
 {
-	static int etm3x_traceid;
+	/*
+	 * A trace ID of value 0 is invalid, so let's start at some
+	 * random value that fits in 7 bits and will be just as good.
+	 */
+	static int etm3x_traceid = 0x10;
 
 	u32 flags = (1 << 0 | /* instruction execute*/
 		     3 << 3 | /* ARM instruction */
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 2108edf..3db36f7 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -252,17 +252,7 @@
 	.id_table	= funnel_ids,
 };
 
-static int __init funnel_init(void)
-{
-	return amba_driver_register(&funnel_driver);
-}
-module_init(funnel_init);
-
-static void __exit funnel_exit(void)
-{
-	amba_driver_unregister(&funnel_driver);
-}
-module_exit(funnel_exit);
+module_amba_driver(funnel_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Funnel driver");
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 7b3372f..62fcd98 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -57,7 +57,7 @@
 extern int etm_writel_cp14(u32 off, u32 val);
 #else
 static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
-static inline int etm_writel_cp14(u32 val, u32 off) { return 0; }
+static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
 #endif
 
 #endif
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index a2dfcf9..cdf0553 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -87,7 +87,7 @@
 		return -ENOMEM;
 
 	desc->type = CORESIGHT_DEV_TYPE_LINK;
-	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
 	desc->ops = &replicator_cs_ops;
 	desc->pdata = pdev->dev.platform_data;
 	desc->dev = &pdev->dev;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index ce2c293..3ff232f 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -760,17 +760,7 @@
 	.id_table	= tmc_ids,
 };
 
-static int __init tmc_init(void)
-{
-	return amba_driver_register(&tmc_driver);
-}
-module_init(tmc_init);
-
-static void __exit tmc_exit(void)
-{
-	amba_driver_unregister(&tmc_driver);
-}
-module_exit(tmc_exit);
+module_amba_driver(tmc_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index ae10108..3b33af2 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -201,17 +201,7 @@
 	.id_table	= tpiu_ids,
 };
 
-static int __init tpiu_init(void)
-{
-	return amba_driver_register(&tpiu_driver);
-}
-module_init(tpiu_init);
-
-static void __exit tpiu_exit(void)
-{
-	amba_driver_unregister(&tpiu_driver);
-}
-module_exit(tpiu_exit);
+module_amba_driver(tpiu_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index 6e0181f..c5def93 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -498,17 +498,18 @@
 	 * Circle throuch all the connection of that component.  If we find
 	 * an orphan connection whose name matches @csdev, link it.
 	 */
-	for (i = 0; i < i_csdev->nr_outport; i++)	{
+	for (i = 0; i < i_csdev->nr_outport; i++) {
 		conn = &i_csdev->conns[i];
 
 		/* We have found at least one orphan connection */
 		if (conn->child_dev == NULL) {
 			/* Does it match this newly added device? */
-			if (!strcmp(dev_name(&csdev->dev), conn->child_name))
+			if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
 				conn->child_dev = csdev;
-		} else {
-			/* Too bad, this component still has an orphan */
-			still_orphan = true;
+			} else {
+				/* This component still has an orphan */
+				still_orphan = true;
+			}
 		}
 	}
 
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
index 5030c07..c3efa41 100644
--- a/drivers/coresight/of_coresight.c
+++ b/drivers/coresight/of_coresight.c
@@ -93,7 +93,7 @@
 	if (!pdata->outports)
 		return -ENOMEM;
 
-	/* Children connected to this component via @outport */
+	/* Children connected to this component via @outports */
 	 pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
 					  sizeof(*pdata->child_names),
 					  GFP_KERNEL);
@@ -117,7 +117,7 @@
 	struct coresight_platform_data *pdata;
 	struct of_endpoint endpoint, rendpoint;
 	struct device *rdev;
-	struct device_node *cpu;
+	struct device_node *dn;
 	struct device_node *ep = NULL;
 	struct device_node *rparent = NULL;
 	struct device_node *rport = NULL;
@@ -126,7 +126,7 @@
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
 
-	/* Use device name as debugfs handle */
+	/* Use device name as sysfs handle */
 	pdata->name = dev_name(dev);
 
 	/* Get the number of input and output port for this component */
@@ -174,7 +174,7 @@
 				continue;
 
 			rdev = of_coresight_get_endpoint_device(rparent);
-			if (!dev)
+			if (!rdev)
 				continue;
 
 			pdata->child_names[i] = dev_name(rdev);
@@ -186,14 +186,16 @@
 
 	/* Affinity defaults to CPU0 */
 	pdata->cpu = 0;
-	cpu = of_parse_phandle(node, "cpu", 0);
-	if (cpu) {
-		const u32 *mpidr;
+	dn = of_parse_phandle(node, "cpu", 0);
+	if (dn) {
+		const u32 *cell;
 		int len, index;
+		u64 hwid;
 
-		mpidr = of_get_property(cpu, "reg", &len);
-		if (mpidr && len == 4) {
-			index = get_logical_index(be32_to_cpup(mpidr));
+		cell = of_get_property(dn, "reg", &len);
+		if (cell) {
+			hwid = of_read_number(cell, of_n_addr_cells(dn));
+			index = get_logical_index(hwid);
 			if (index != -EINVAL)
 				pdata->cpu = index;
 		}
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index 8c16ab2..8e07c94 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -55,6 +55,7 @@
 config ARM_EXYNOS_CPUIDLE
 	bool "Cpu Idle Driver for the Exynos processors"
 	depends on ARCH_EXYNOS
+	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
 	help
 	  Select this to enable cpuidle for Exynos processors
 
diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c
index 4003a31..26f5f29 100644
--- a/drivers/cpuidle/cpuidle-exynos.c
+++ b/drivers/cpuidle/cpuidle-exynos.c
@@ -1,8 +1,11 @@
-/* linux/arch/arm/mach-exynos/cpuidle.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
+ * Coupled cpuidle support based on the work of:
+ *	Colin Cross <ccross@android.com>
+ *	Daniel Lezcano <daniel.lezcano@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.
@@ -13,13 +16,49 @@
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/platform_data/cpuidle-exynos.h>
 
 #include <asm/proc-fns.h>
 #include <asm/suspend.h>
 #include <asm/cpuidle.h>
 
+static atomic_t exynos_idle_barrier;
+
+static struct cpuidle_exynos_data *exynos_cpuidle_pdata;
 static void (*exynos_enter_aftr)(void);
 
+static int exynos_enter_coupled_lowpower(struct cpuidle_device *dev,
+					 struct cpuidle_driver *drv,
+					 int index)
+{
+	int ret;
+
+	exynos_cpuidle_pdata->pre_enter_aftr();
+
+	/*
+	 * Waiting all cpus to reach this point at the same moment
+	 */
+	cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
+
+	/*
+	 * Both cpus will reach this point at the same time
+	 */
+	ret = dev->cpu ? exynos_cpuidle_pdata->cpu1_powerdown()
+		       : exynos_cpuidle_pdata->cpu0_enter_aftr();
+	if (ret)
+		index = ret;
+
+	/*
+	 * Waiting all cpus to finish the power sequence before going further
+	 */
+	cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
+
+	exynos_cpuidle_pdata->post_enter_aftr();
+
+	return index;
+}
+
 static int exynos_enter_lowpower(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 				int index)
@@ -55,13 +94,40 @@
 	.safe_state_index = 0,
 };
 
+static struct cpuidle_driver exynos_coupled_idle_driver = {
+	.name			= "exynos_coupled_idle",
+	.owner			= THIS_MODULE,
+	.states = {
+		[0] = ARM_CPUIDLE_WFI_STATE,
+		[1] = {
+			.enter			= exynos_enter_coupled_lowpower,
+			.exit_latency		= 5000,
+			.target_residency	= 10000,
+			.flags			= CPUIDLE_FLAG_COUPLED |
+						  CPUIDLE_FLAG_TIMER_STOP,
+			.name			= "C1",
+			.desc			= "ARM power down",
+		},
+	},
+	.state_count = 2,
+	.safe_state_index = 0,
+};
+
 static int exynos_cpuidle_probe(struct platform_device *pdev)
 {
 	int ret;
 
-	exynos_enter_aftr = (void *)(pdev->dev.platform_data);
+	if (of_machine_is_compatible("samsung,exynos4210")) {
+		exynos_cpuidle_pdata = pdev->dev.platform_data;
 
-	ret = cpuidle_register(&exynos_idle_driver, NULL);
+		ret = cpuidle_register(&exynos_coupled_idle_driver,
+				       cpu_possible_mask);
+	} else {
+		exynos_enter_aftr = (void *)(pdev->dev.platform_data);
+
+		ret = cpuidle_register(&exynos_idle_driver, NULL);
+	}
+
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register cpuidle driver\n");
 		return ret;
diff --git a/drivers/crypto/amcc/crypto4xx_sa.c b/drivers/crypto/amcc/crypto4xx_sa.c
index de8a7a4..69182e2 100644
--- a/drivers/crypto/amcc/crypto4xx_sa.c
+++ b/drivers/crypto/amcc/crypto4xx_sa.c
@@ -34,29 +34,6 @@
 #include "crypto4xx_sa.h"
 #include "crypto4xx_core.h"
 
-u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx *ctx)
-{
-	u32 offset;
-	union dynamic_sa_contents cts;
-
-	if (ctx->direction == DIR_INBOUND)
-		cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
-	else
-		cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
-	offset = cts.bf.key_size
-		+ cts.bf.inner_size
-		+ cts.bf.outer_size
-		+ cts.bf.spi
-		+ cts.bf.seq_num0
-		+ cts.bf.seq_num1
-		+ cts.bf.seq_num_mask0
-		+ cts.bf.seq_num_mask1
-		+ cts.bf.seq_num_mask2
-		+ cts.bf.seq_num_mask3;
-
-	return sizeof(struct dynamic_sa_ctl) + offset * 4;
-}
-
 u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx)
 {
 	u32 offset;
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 53d1c33..6597aac 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -673,9 +673,9 @@
 	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
 		DMA_TO_DEVICE);
 err_map_in:
+err_alloc:
 	free_page((unsigned long)dd->buf_out);
 	free_page((unsigned long)dd->buf_in);
-err_alloc:
 	if (err)
 		pr_err("error: %d\n", err);
 	return err;
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index d94f07c..34db04a 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -102,10 +102,6 @@
 	struct atmel_sha_dev	*dd;
 
 	unsigned long		flags;
-
-	/* fallback stuff */
-	struct crypto_shash	*fallback;
-
 };
 
 #define ATMEL_SHA_QUEUE_LENGTH	50
@@ -974,19 +970,8 @@
 	return atmel_sha_init(req) ?: atmel_sha_finup(req);
 }
 
-static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
+static int atmel_sha_cra_init(struct crypto_tfm *tfm)
 {
-	struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
-	const char *alg_name = crypto_tfm_alg_name(tfm);
-
-	/* Allocate a fallback and abort if it failed. */
-	tctx->fallback = crypto_alloc_shash(alg_name, 0,
-					    CRYPTO_ALG_NEED_FALLBACK);
-	if (IS_ERR(tctx->fallback)) {
-		pr_err("atmel-sha: fallback driver '%s' could not be loaded.\n",
-				alg_name);
-		return PTR_ERR(tctx->fallback);
-	}
 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
 				 sizeof(struct atmel_sha_reqctx) +
 				 SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
@@ -994,19 +979,6 @@
 	return 0;
 }
 
-static int atmel_sha_cra_init(struct crypto_tfm *tfm)
-{
-	return atmel_sha_cra_init_alg(tfm, NULL);
-}
-
-static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
-{
-	struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
-
-	crypto_free_shash(tctx->fallback);
-	tctx->fallback = NULL;
-}
-
 static struct ahash_alg sha_1_256_algs[] = {
 {
 	.init		= atmel_sha_init,
@@ -1020,14 +992,12 @@
 			.cra_name		= "sha1",
 			.cra_driver_name	= "atmel-sha1",
 			.cra_priority		= 100,
-			.cra_flags		= CRYPTO_ALG_ASYNC |
-						CRYPTO_ALG_NEED_FALLBACK,
+			.cra_flags		= CRYPTO_ALG_ASYNC,
 			.cra_blocksize		= SHA1_BLOCK_SIZE,
 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
 			.cra_alignmask		= 0,
 			.cra_module		= THIS_MODULE,
 			.cra_init		= atmel_sha_cra_init,
-			.cra_exit		= atmel_sha_cra_exit,
 		}
 	}
 },
@@ -1043,14 +1013,12 @@
 			.cra_name		= "sha256",
 			.cra_driver_name	= "atmel-sha256",
 			.cra_priority		= 100,
-			.cra_flags		= CRYPTO_ALG_ASYNC |
-						CRYPTO_ALG_NEED_FALLBACK,
+			.cra_flags		= CRYPTO_ALG_ASYNC,
 			.cra_blocksize		= SHA256_BLOCK_SIZE,
 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
 			.cra_alignmask		= 0,
 			.cra_module		= THIS_MODULE,
 			.cra_init		= atmel_sha_cra_init,
-			.cra_exit		= atmel_sha_cra_exit,
 		}
 	}
 },
@@ -1068,14 +1036,12 @@
 			.cra_name		= "sha224",
 			.cra_driver_name	= "atmel-sha224",
 			.cra_priority		= 100,
-			.cra_flags		= CRYPTO_ALG_ASYNC |
-						CRYPTO_ALG_NEED_FALLBACK,
+			.cra_flags		= CRYPTO_ALG_ASYNC,
 			.cra_blocksize		= SHA224_BLOCK_SIZE,
 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
 			.cra_alignmask		= 0,
 			.cra_module		= THIS_MODULE,
 			.cra_init		= atmel_sha_cra_init,
-			.cra_exit		= atmel_sha_cra_exit,
 		}
 	}
 };
@@ -1093,14 +1059,12 @@
 			.cra_name		= "sha384",
 			.cra_driver_name	= "atmel-sha384",
 			.cra_priority		= 100,
-			.cra_flags		= CRYPTO_ALG_ASYNC |
-						CRYPTO_ALG_NEED_FALLBACK,
+			.cra_flags		= CRYPTO_ALG_ASYNC,
 			.cra_blocksize		= SHA384_BLOCK_SIZE,
 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
 			.cra_alignmask		= 0x3,
 			.cra_module		= THIS_MODULE,
 			.cra_init		= atmel_sha_cra_init,
-			.cra_exit		= atmel_sha_cra_exit,
 		}
 	}
 },
@@ -1116,14 +1080,12 @@
 			.cra_name		= "sha512",
 			.cra_driver_name	= "atmel-sha512",
 			.cra_priority		= 100,
-			.cra_flags		= CRYPTO_ALG_ASYNC |
-						CRYPTO_ALG_NEED_FALLBACK,
+			.cra_flags		= CRYPTO_ALG_ASYNC,
 			.cra_blocksize		= SHA512_BLOCK_SIZE,
 			.cra_ctxsize		= sizeof(struct atmel_sha_ctx),
 			.cra_alignmask		= 0x3,
 			.cra_module		= THIS_MODULE,
 			.cra_init		= atmel_sha_cra_init,
-			.cra_exit		= atmel_sha_cra_exit,
 		}
 	}
 },
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 5e7c896..258772d 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -376,9 +376,9 @@
 	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
 		DMA_TO_DEVICE);
 err_map_in:
+err_alloc:
 	free_page((unsigned long)dd->buf_out);
 	free_page((unsigned long)dd->buf_in);
-err_alloc:
 	if (err)
 		pr_err("error: %d\n", err);
 	return err;
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index 9ae149b..d9af940 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -110,7 +110,7 @@
 
 	while (!sg_is_last(sg)) {
 		sg_nents++;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	return sg_nents;
@@ -744,7 +744,7 @@
 
 	ret = platform_driver_register(&bfin_crypto_crc_driver);
 	if (ret) {
-		pr_info(KERN_ERR "unable to register driver\n");
+		pr_err("unable to register driver\n");
 		return ret;
 	}
 
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 3187400..29071a1 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2532,7 +2532,7 @@
 		in_options = 0;
 	} else {
 		src_dma = edesc->sec4_sg_dma;
-		sec4_sg_index += (iv_contig ? 0 : 1) + edesc->src_nents;
+		sec4_sg_index += edesc->src_nents + 1;
 		in_options = LDST_SGF;
 	}
 	append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options);
@@ -2714,10 +2714,10 @@
 	if (!all_contig) {
 		if (!is_gcm) {
 			sg_to_sec4_sg(req->assoc,
-				      (assoc_nents ? : 1),
+				      assoc_nents,
 				      edesc->sec4_sg +
 				      sec4_sg_index, 0);
-			sec4_sg_index += assoc_nents ? : 1;
+			sec4_sg_index += assoc_nents;
 		}
 
 		dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index,
@@ -2726,17 +2726,17 @@
 
 		if (is_gcm) {
 			sg_to_sec4_sg(req->assoc,
-				      (assoc_nents ? : 1),
+				      assoc_nents,
 				      edesc->sec4_sg +
 				      sec4_sg_index, 0);
-			sec4_sg_index += assoc_nents ? : 1;
+			sec4_sg_index += assoc_nents;
 		}
 
 		sg_to_sec4_sg_last(req->src,
-				   (src_nents ? : 1),
+				   src_nents,
 				   edesc->sec4_sg +
 				   sec4_sg_index, 0);
-		sec4_sg_index += src_nents ? : 1;
+		sec4_sg_index += src_nents;
 	}
 	if (dst_nents) {
 		sg_to_sec4_sg_last(req->dst, dst_nents,
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 70f1e6f..efba4cc 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -175,13 +175,10 @@
 {
 	struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
 	struct caam_ctrl __iomem *ctrl;
-	struct rng4tst __iomem *r4tst;
 	u32 *desc, status, rdsta_val;
 	int ret = 0, sh_idx;
 
 	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
-	r4tst = &ctrl->r4tst[0];
-
 	desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
 	if (!desc)
 		return -ENOMEM;
@@ -209,8 +206,7 @@
 		 * without any error (HW optimizations for later
 		 * CAAM eras), then try again.
 		 */
-		rdsta_val =
-			rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+		rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
 		if (status || !(rdsta_val & (1 << sh_idx)))
 			ret = -EAGAIN;
 		if (ret)
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
index 66d73bf..33e41ea 100644
--- a/drivers/crypto/caam/error.c
+++ b/drivers/crypto/caam/error.c
@@ -151,10 +151,15 @@
 	else
 		snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
 
-	dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
-		status, error, idx_str, idx,
-		cha_str, cha_err_code,
-		err_str, err_err_code);
+	/*
+	 * CCB ICV check failures are part of normal operation life;
+	 * we leave the upper layers to do what they want with them.
+	 */
+	if (err_id != JRSTA_CCBERR_ERRID_ICVCHK)
+		dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
+			status, error, idx_str, idx,
+			cha_str, cha_err_code,
+			err_str, err_err_code);
 }
 
 static void report_jump_status(struct device *jrdev, const u32 status,
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 9b3ef1bc..b8b5d47 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -384,30 +384,28 @@
 	if (error) {
 		dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
 			jrp->ridx, jrp->irq);
-		irq_dispose_mapping(jrp->irq);
-		jrp->irq = 0;
-		return -EINVAL;
+		goto out_kill_deq;
 	}
 
 	error = caam_reset_hw_jr(dev);
 	if (error)
-		return error;
+		goto out_free_irq;
 
+	error = -ENOMEM;
 	jrp->inpring = dma_alloc_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
 					  &inpbusaddr, GFP_KERNEL);
+	if (!jrp->inpring)
+		goto out_free_irq;
 
 	jrp->outring = dma_alloc_coherent(dev, sizeof(struct jr_outentry) *
 					  JOBR_DEPTH, &outbusaddr, GFP_KERNEL);
+	if (!jrp->outring)
+		goto out_free_inpring;
 
 	jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH,
 			       GFP_KERNEL);
-
-	if ((jrp->inpring == NULL) || (jrp->outring == NULL) ||
-	    (jrp->entinfo == NULL)) {
-		dev_err(dev, "can't allocate job rings for %d\n",
-			jrp->ridx);
-		return -ENOMEM;
-	}
+	if (!jrp->entinfo)
+		goto out_free_outring;
 
 	for (i = 0; i < JOBR_DEPTH; i++)
 		jrp->entinfo[i].desc_addr_dma = !0;
@@ -434,6 +432,19 @@
 		  (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
 
 	return 0;
+
+out_free_outring:
+	dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH,
+			  jrp->outring, outbusaddr);
+out_free_inpring:
+	dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
+			  jrp->inpring, inpbusaddr);
+	dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx);
+out_free_irq:
+	free_irq(jrp->irq, dev);
+out_kill_deq:
+	tasklet_kill(&jrp->irqtask);
+	return error;
 }
 
 
@@ -484,8 +495,10 @@
 
 	/* Now do the platform independent part */
 	error = caam_jr_init(jrdev); /* now turn on hardware */
-	if (error)
+	if (error) {
+		irq_dispose_mapping(jrpriv->irq);
 		return error;
+	}
 
 	jrpriv->dev = jrdev;
 	spin_lock(&driver_data.jr_alloc_lock);
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index ce28a56..3b91821 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -37,7 +37,7 @@
 		dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg),
 				   sg_dma_len(sg), offset);
 		sec4_sg_ptr++;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 		sg_count--;
 	}
 	return sec4_sg_ptr - 1;
@@ -67,7 +67,7 @@
 		nbytes -= sg->length;
 		if (!sg_is_last(sg) && (sg + 1)->length == 0)
 			*chained = true;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	return sg_nents;
@@ -93,7 +93,7 @@
 		int i;
 		for (i = 0; i < nents; i++) {
 			dma_map_sg(dev, sg, 1, dir);
-			sg = scatterwalk_sg_next(sg);
+			sg = sg_next(sg);
 		}
 	} else {
 		dma_map_sg(dev, sg, nents, dir);
@@ -109,7 +109,7 @@
 		int i;
 		for (i = 0; i < nents; i++) {
 			dma_unmap_sg(dev, sg, 1, dir);
-			sg = scatterwalk_sg_next(sg);
+			sg = sg_next(sg);
 		}
 	} else {
 		dma_unmap_sg(dev, sg, nents, dir);
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index c6e6171..ca29c12 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -583,6 +583,7 @@
 #ifdef CONFIG_X86
 static const struct x86_cpu_id ccp_support[] = {
 	{ X86_VENDOR_AMD, 22, },
+	{ },
 };
 #endif
 
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index f757a0f..48f4535 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -784,7 +784,7 @@
 		struct buffer_desc *buf, gfp_t flags,
 		enum dma_data_direction dir)
 {
-	for (;nbytes > 0; sg = scatterwalk_sg_next(sg)) {
+	for (; nbytes > 0; sg = sg_next(sg)) {
 		unsigned len = min(nbytes, sg->length);
 		struct buffer_desc *next_buf;
 		u32 next_buf_phys;
@@ -982,7 +982,7 @@
 			break;
 
 		offset += sg->length;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 	return (start + nbytes > offset + sg->length);
 }
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index a392465..1da6dc5 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -177,7 +177,7 @@
 			break;
 
 		offset += sg_src->length;
-		sg_src = scatterwalk_sg_next(sg_src);
+		sg_src = sg_next(sg_src);
 	}
 
 	/* start - offset is the number of bytes to advance in the scatterlist
@@ -187,9 +187,9 @@
 	while (len && (nx_sg - nx_dst) < sglen) {
 		n = scatterwalk_clamp(&walk, len);
 		if (!n) {
-			/* In cases where we have scatterlist chain scatterwalk_sg_next
+			/* In cases where we have scatterlist chain sg_next
 			 * handles with it properly */
-			scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
+			scatterwalk_start(&walk, sg_next(walk.sg));
 			n = scatterwalk_clamp(&walk, len);
 		}
 		dst = scatterwalk_map(&walk);
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index f79dd41..42f95a4 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -994,7 +994,7 @@
 
 			scatterwalk_advance(&dd->in_walk, 4);
 			if (dd->in_sg->length == _calc_walked(in)) {
-				dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+				dd->in_sg = sg_next(dd->in_sg);
 				if (dd->in_sg) {
 					scatterwalk_start(&dd->in_walk,
 							  dd->in_sg);
@@ -1026,7 +1026,7 @@
 			*dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i));
 			scatterwalk_advance(&dd->out_walk, 4);
 			if (dd->out_sg->length == _calc_walked(out)) {
-				dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+				dd->out_sg = sg_next(dd->out_sg);
 				if (dd->out_sg) {
 					scatterwalk_start(&dd->out_walk,
 							  dd->out_sg);
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index e350f5b..4630709 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -921,7 +921,7 @@
 
 			scatterwalk_advance(&dd->in_walk, 4);
 			if (dd->in_sg->length == _calc_walked(in)) {
-				dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+				dd->in_sg = sg_next(dd->in_sg);
 				if (dd->in_sg) {
 					scatterwalk_start(&dd->in_walk,
 							  dd->in_sg);
@@ -953,7 +953,7 @@
 			*dst = omap_des_read(dd, DES_REG_DATA_N(dd, i));
 			scatterwalk_advance(&dd->out_walk, 4);
 			if (dd->out_sg->length == _calc_walked(out)) {
-				dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+				dd->out_sg = sg_next(dd->out_sg);
 				if (dd->out_sg) {
 					scatterwalk_start(&dd->out_walk,
 							  dd->out_sg);
@@ -965,9 +965,9 @@
 			}
 		}
 
-		dd->total -= DES_BLOCK_SIZE;
+		BUG_ON(dd->total < DES_BLOCK_SIZE);
 
-		BUG_ON(dd->total < 0);
+		dd->total -= DES_BLOCK_SIZE;
 
 		/* Clear IRQ status */
 		status &= ~DES_REG_IRQ_DATA_OUT;
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
index 2ed4256..19c0efa 100644
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
@@ -47,7 +47,6 @@
 #ifndef ADF_ACCEL_DEVICES_H_
 #define ADF_ACCEL_DEVICES_H_
 #include <linux/module.h>
-#include <linux/atomic.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/io.h>
@@ -148,6 +147,11 @@
 	int (*alloc_irq)(struct adf_accel_dev *accel_dev);
 	void (*free_irq)(struct adf_accel_dev *accel_dev);
 	void (*enable_error_correction)(struct adf_accel_dev *accel_dev);
+	int (*init_admin_comms)(struct adf_accel_dev *accel_dev);
+	void (*exit_admin_comms)(struct adf_accel_dev *accel_dev);
+	int (*init_arb)(struct adf_accel_dev *accel_dev);
+	void (*exit_arb)(struct adf_accel_dev *accel_dev);
+	void (*enable_ints)(struct adf_accel_dev *accel_dev);
 	const char *fw_name;
 	uint32_t pci_dev_id;
 	uint32_t fuses;
diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c
index 10ce4a2..fa1fef8 100644
--- a/drivers/crypto/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/qat/qat_common/adf_aer.c
@@ -82,28 +82,15 @@
 	struct work_struct reset_work;
 };
 
-#define PPDSTAT_OFFSET 0x7E
 static void adf_dev_restore(struct adf_accel_dev *accel_dev)
 {
 	struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
 	struct pci_dev *parent = pdev->bus->self;
-	uint16_t ppdstat = 0, bridge_ctl = 0;
-	int pending = 0;
+	uint16_t bridge_ctl = 0;
 
 	pr_info("QAT: Resetting device qat_dev%d\n", accel_dev->accel_id);
-	pci_read_config_word(pdev, PPDSTAT_OFFSET, &ppdstat);
-	pending = ppdstat & PCI_EXP_DEVSTA_TRPND;
-	if (pending) {
-		int ctr = 0;
 
-		do {
-			msleep(100);
-			pci_read_config_word(pdev, PPDSTAT_OFFSET, &ppdstat);
-			pending = ppdstat & PCI_EXP_DEVSTA_TRPND;
-		} while (pending && ctr++ < 10);
-	}
-
-	if (pending)
+	if (!pci_wait_for_pending_transaction(pdev))
 		pr_info("QAT: Transaction still in progress. Proceeding\n");
 
 	pci_read_config_word(parent, PCI_BRIDGE_CONTROL, &bridge_ctl);
@@ -125,8 +112,9 @@
 
 	adf_dev_restarting_notify(accel_dev);
 	adf_dev_stop(accel_dev);
+	adf_dev_shutdown(accel_dev);
 	adf_dev_restore(accel_dev);
-	if (adf_dev_start(accel_dev)) {
+	if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
 		/* The device hanged and we can't restart it so stop here */
 		dev_err(&GET_DEV(accel_dev), "Restart device failed\n");
 		kfree(reset_data);
@@ -148,8 +136,8 @@
 {
 	struct adf_reset_dev_data *reset_data;
 
-	if (adf_dev_started(accel_dev) &&
-	    !test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+	if (!adf_dev_started(accel_dev) ||
+	    test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
 		return 0;
 
 	set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
diff --git a/drivers/crypto/qat/qat_common/adf_cfg.c b/drivers/crypto/qat/qat_common/adf_cfg.c
index aba7f1d..de16da9 100644
--- a/drivers/crypto/qat/qat_common/adf_cfg.c
+++ b/drivers/crypto/qat/qat_common/adf_cfg.c
@@ -50,6 +50,7 @@
 #include <linux/seq_file.h>
 #include "adf_accel_devices.h"
 #include "adf_cfg.h"
+#include "adf_common_drv.h"
 
 static DEFINE_MUTEX(qat_cfg_read_lock);
 
@@ -159,6 +160,7 @@
 	down_write(&dev_cfg_data->lock);
 	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
 	up_write(&dev_cfg_data->lock);
+	clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
 }
 
 /**
diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h
index 5e8f9d4..a62e485 100644
--- a/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -93,7 +93,7 @@
 int adf_dev_init(struct adf_accel_dev *accel_dev);
 int adf_dev_start(struct adf_accel_dev *accel_dev);
 int adf_dev_stop(struct adf_accel_dev *accel_dev);
-int adf_dev_shutdown(struct adf_accel_dev *accel_dev);
+void adf_dev_shutdown(struct adf_accel_dev *accel_dev);
 
 int adf_ctl_dev_register(void);
 void adf_ctl_dev_unregister(void);
diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
index 7ee93f8..74207a6 100644
--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -282,6 +282,8 @@
 			if (adf_dev_stop(accel_dev)) {
 				pr_err("QAT: Failed to stop qat_dev%d\n", id);
 				ret = -EFAULT;
+			} else {
+				adf_dev_shutdown(accel_dev);
 			}
 		}
 	}
@@ -343,7 +345,9 @@
 	if (!adf_dev_started(accel_dev)) {
 		pr_info("QAT: Starting acceleration device qat_dev%d.\n",
 			ctl_data->device_id);
-		ret = adf_dev_start(accel_dev);
+		ret = adf_dev_init(accel_dev);
+		if (!ret)
+			ret = adf_dev_start(accel_dev);
 	} else {
 		pr_info("QAT: Acceleration device qat_dev%d already started.\n",
 			ctl_data->device_id);
@@ -351,6 +355,7 @@
 	if (ret) {
 		pr_err("QAT: Failed to start qat_dev%d\n", ctl_data->device_id);
 		adf_dev_stop(accel_dev);
+		adf_dev_shutdown(accel_dev);
 	}
 out:
 	kfree(ctl_data);
diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c
index 5c0e47a..8f0ca49 100644
--- a/drivers/crypto/qat/qat_common/adf_init.c
+++ b/drivers/crypto/qat/qat_common/adf_init.c
@@ -108,26 +108,47 @@
 EXPORT_SYMBOL_GPL(adf_service_unregister);
 
 /**
- * adf_dev_start() - Start acceleration service for the given accel device
- * @accel_dev:    Pointer to acceleration device.
+ * adf_dev_init() - Init data structures and services for the given accel device
+ * @accel_dev: Pointer to acceleration device.
  *
- * Function notifies all the registered services that the acceleration device
- * is ready to be used.
- * To be used by QAT device specific drivers.
+ * Initialize the ring data structures and the admin comms and arbitration
+ * services.
  *
  * Return: 0 on success, error code othewise.
  */
-int adf_dev_start(struct adf_accel_dev *accel_dev)
+int adf_dev_init(struct adf_accel_dev *accel_dev)
 {
 	struct service_hndl *service;
 	struct list_head *list_itr;
 	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
 
+	if (!hw_data) {
+		dev_err(&GET_DEV(accel_dev),
+			"QAT: Failed to init device - hw_data not set\n");
+		return -EFAULT;
+	}
+
 	if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status)) {
 		pr_info("QAT: Device not configured\n");
 		return -EFAULT;
 	}
-	set_bit(ADF_STATUS_STARTING, &accel_dev->status);
+
+	if (adf_init_etr_data(accel_dev)) {
+		dev_err(&GET_DEV(accel_dev), "Failed initialize etr\n");
+		return -EFAULT;
+	}
+
+	if (hw_data->init_admin_comms && hw_data->init_admin_comms(accel_dev)) {
+		dev_err(&GET_DEV(accel_dev), "Failed initialize admin comms\n");
+		return -EFAULT;
+	}
+
+	if (hw_data->init_arb && hw_data->init_arb(accel_dev)) {
+		dev_err(&GET_DEV(accel_dev), "Failed initialize hw arbiter\n");
+		return -EFAULT;
+	}
+
+	hw_data->enable_ints(accel_dev);
 
 	if (adf_ae_init(accel_dev)) {
 		pr_err("QAT: Failed to initialise Acceleration Engine\n");
@@ -178,6 +199,27 @@
 
 	hw_data->enable_error_correction(accel_dev);
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adf_dev_init);
+
+/**
+ * adf_dev_start() - Start acceleration service for the given accel device
+ * @accel_dev:    Pointer to acceleration device.
+ *
+ * Function notifies all the registered services that the acceleration device
+ * is ready to be used.
+ * To be used by QAT device specific drivers.
+ *
+ * Return: 0 on success, error code othewise.
+ */
+int adf_dev_start(struct adf_accel_dev *accel_dev)
+{
+	struct service_hndl *service;
+	struct list_head *list_itr;
+
+	set_bit(ADF_STATUS_STARTING, &accel_dev->status);
+
 	if (adf_ae_start(accel_dev)) {
 		pr_err("QAT: AE Start Failed\n");
 		return -EFAULT;
@@ -232,16 +274,15 @@
  */
 int adf_dev_stop(struct adf_accel_dev *accel_dev)
 {
-	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
 	struct service_hndl *service;
 	struct list_head *list_itr;
-	int ret, wait = 0;
+	bool wait = false;
+	int ret;
 
 	if (!adf_dev_started(accel_dev) &&
 	    !test_bit(ADF_STATUS_STARTING, &accel_dev->status)) {
 		return 0;
 	}
-	clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
 	clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
 	clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
 
@@ -258,7 +299,7 @@
 		if (!ret) {
 			clear_bit(accel_dev->accel_id, &service->start_status);
 		} else if (ret == -EAGAIN) {
-			wait = 1;
+			wait = true;
 			clear_bit(accel_dev->accel_id, &service->start_status);
 		}
 	}
@@ -278,13 +319,36 @@
 	if (wait)
 		msleep(100);
 
-	if (adf_dev_started(accel_dev)) {
+	if (test_bit(ADF_STATUS_AE_STARTED, &accel_dev->status)) {
 		if (adf_ae_stop(accel_dev))
 			pr_err("QAT: failed to stop AE\n");
 		else
 			clear_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
 	}
 
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adf_dev_stop);
+
+/**
+ * adf_dev_shutdown() - shutdown acceleration services and data strucutures
+ * @accel_dev: Pointer to acceleration device
+ *
+ * Cleanup the ring data structures and the admin comms and arbitration
+ * services.
+ */
+void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
+{
+	struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+	struct service_hndl *service;
+	struct list_head *list_itr;
+
+	if (!hw_data) {
+		dev_err(&GET_DEV(accel_dev),
+			"QAT: Failed to shutdown device - hw_data not set\n");
+		return;
+	}
+
 	if (test_bit(ADF_STATUS_AE_UCODE_LOADED, &accel_dev->status)) {
 		if (adf_ae_fw_release(accel_dev))
 			pr_err("QAT: Failed to release the ucode\n");
@@ -335,9 +399,15 @@
 	if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
 		adf_cfg_del_all(accel_dev);
 
-	return 0;
+	if (hw_data->exit_arb)
+		hw_data->exit_arb(accel_dev);
+
+	if (hw_data->exit_admin_comms)
+		hw_data->exit_admin_comms(accel_dev);
+
+	adf_cleanup_etr_data(accel_dev);
 }
-EXPORT_SYMBOL_GPL(adf_dev_stop);
+EXPORT_SYMBOL_GPL(adf_dev_shutdown);
 
 int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)
 {
diff --git a/drivers/crypto/qat/qat_common/adf_transport_internal.h b/drivers/crypto/qat/qat_common/adf_transport_internal.h
index c405460..a486962 100644
--- a/drivers/crypto/qat/qat_common/adf_transport_internal.h
+++ b/drivers/crypto/qat/qat_common/adf_transport_internal.h
@@ -48,7 +48,6 @@
 #define ADF_TRANSPORT_INTRN_H
 
 #include <linux/interrupt.h>
-#include <linux/atomic.h>
 #include <linux/spinlock_types.h>
 #include "adf_transport.h"
 
diff --git a/drivers/crypto/qat/qat_common/icp_qat_hw.h b/drivers/crypto/qat/qat_common/icp_qat_hw.h
index 5031f8c..68f191b 100644
--- a/drivers/crypto/qat/qat_common/icp_qat_hw.h
+++ b/drivers/crypto/qat/qat_common/icp_qat_hw.h
@@ -301,5 +301,5 @@
 
 struct icp_qat_hw_cipher_algo_blk {
 	struct icp_qat_hw_cipher_aes256_f8 aes;
-};
+} __aligned(64);
 #endif
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 19eea1c..1dc5b0a 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -63,15 +63,15 @@
 #include "icp_qat_fw.h"
 #include "icp_qat_fw_la.h"
 
-#define QAT_AES_HW_CONFIG_ENC(alg) \
+#define QAT_AES_HW_CONFIG_CBC_ENC(alg) \
 	ICP_QAT_HW_CIPHER_CONFIG_BUILD(ICP_QAT_HW_CIPHER_CBC_MODE, alg, \
-			ICP_QAT_HW_CIPHER_NO_CONVERT, \
-			ICP_QAT_HW_CIPHER_ENCRYPT)
+				       ICP_QAT_HW_CIPHER_NO_CONVERT, \
+				       ICP_QAT_HW_CIPHER_ENCRYPT)
 
-#define QAT_AES_HW_CONFIG_DEC(alg) \
+#define QAT_AES_HW_CONFIG_CBC_DEC(alg) \
 	ICP_QAT_HW_CIPHER_CONFIG_BUILD(ICP_QAT_HW_CIPHER_CBC_MODE, alg, \
-			ICP_QAT_HW_CIPHER_KEY_CONVERT, \
-			ICP_QAT_HW_CIPHER_DECRYPT)
+				       ICP_QAT_HW_CIPHER_KEY_CONVERT, \
+				       ICP_QAT_HW_CIPHER_DECRYPT)
 
 static atomic_t active_dev;
 
@@ -102,25 +102,31 @@
 	};
 } __aligned(64);
 
-#define MAX_AUTH_STATE_SIZE sizeof(struct icp_qat_hw_auth_algo_blk)
-
-struct qat_auth_state {
-	uint8_t data[MAX_AUTH_STATE_SIZE + 64];
-} __aligned(64);
-
-struct qat_alg_session_ctx {
+struct qat_alg_aead_ctx {
 	struct qat_alg_cd *enc_cd;
-	dma_addr_t enc_cd_paddr;
 	struct qat_alg_cd *dec_cd;
+	dma_addr_t enc_cd_paddr;
 	dma_addr_t dec_cd_paddr;
-	struct icp_qat_fw_la_bulk_req enc_fw_req_tmpl;
-	struct icp_qat_fw_la_bulk_req dec_fw_req_tmpl;
-	struct qat_crypto_instance *inst;
-	struct crypto_tfm *tfm;
+	struct icp_qat_fw_la_bulk_req enc_fw_req;
+	struct icp_qat_fw_la_bulk_req dec_fw_req;
 	struct crypto_shash *hash_tfm;
 	enum icp_qat_hw_auth_algo qat_hash_alg;
+	struct qat_crypto_instance *inst;
+	struct crypto_tfm *tfm;
 	uint8_t salt[AES_BLOCK_SIZE];
-	spinlock_t lock;	/* protects qat_alg_session_ctx struct */
+	spinlock_t lock;	/* protects qat_alg_aead_ctx struct */
+};
+
+struct qat_alg_ablkcipher_ctx {
+	struct icp_qat_hw_cipher_algo_blk *enc_cd;
+	struct icp_qat_hw_cipher_algo_blk *dec_cd;
+	dma_addr_t enc_cd_paddr;
+	dma_addr_t dec_cd_paddr;
+	struct icp_qat_fw_la_bulk_req enc_fw_req;
+	struct icp_qat_fw_la_bulk_req dec_fw_req;
+	struct qat_crypto_instance *inst;
+	struct crypto_tfm *tfm;
+	spinlock_t lock;	/* protects qat_alg_ablkcipher_ctx struct */
 };
 
 static int get_current_node(void)
@@ -144,43 +150,37 @@
 }
 
 static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
-				  struct qat_alg_session_ctx *ctx,
+				  struct qat_alg_aead_ctx *ctx,
 				  const uint8_t *auth_key,
 				  unsigned int auth_keylen)
 {
-	struct qat_auth_state auth_state;
 	SHASH_DESC_ON_STACK(shash, ctx->hash_tfm);
 	struct sha1_state sha1;
 	struct sha256_state sha256;
 	struct sha512_state sha512;
 	int block_size = crypto_shash_blocksize(ctx->hash_tfm);
 	int digest_size = crypto_shash_digestsize(ctx->hash_tfm);
-	uint8_t *ipad = auth_state.data;
-	uint8_t *opad = ipad + block_size;
+	char ipad[block_size];
+	char opad[block_size];
 	__be32 *hash_state_out;
 	__be64 *hash512_state_out;
 	int i, offset;
 
-	memzero_explicit(auth_state.data, MAX_AUTH_STATE_SIZE + 64);
+	memset(ipad, 0, block_size);
+	memset(opad, 0, block_size);
 	shash->tfm = ctx->hash_tfm;
 	shash->flags = 0x0;
 
 	if (auth_keylen > block_size) {
-		char buff[SHA512_BLOCK_SIZE];
 		int ret = crypto_shash_digest(shash, auth_key,
-					      auth_keylen, buff);
+					      auth_keylen, ipad);
 		if (ret)
 			return ret;
 
-		memcpy(ipad, buff, digest_size);
-		memcpy(opad, buff, digest_size);
-		memzero_explicit(ipad + digest_size, block_size - digest_size);
-		memzero_explicit(opad + digest_size, block_size - digest_size);
+		memcpy(opad, ipad, digest_size);
 	} else {
 		memcpy(ipad, auth_key, auth_keylen);
 		memcpy(opad, auth_key, auth_keylen);
-		memzero_explicit(ipad + auth_keylen, block_size - auth_keylen);
-		memzero_explicit(opad + auth_keylen, block_size - auth_keylen);
 	}
 
 	for (i = 0; i < block_size; i++) {
@@ -267,8 +267,6 @@
 	header->comn_req_flags =
 		ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR,
 					    QAT_COMN_PTR_TYPE_SGL);
-	ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
-					   ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
 	ICP_QAT_FW_LA_PARTIAL_SET(header->serv_specif_flags,
 				  ICP_QAT_FW_LA_PARTIAL_NONE);
 	ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags,
@@ -279,8 +277,9 @@
 				       ICP_QAT_FW_LA_NO_UPDATE_STATE);
 }
 
-static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
-				    int alg, struct crypto_authenc_keys *keys)
+static int qat_alg_aead_init_enc_session(struct qat_alg_aead_ctx *ctx,
+					 int alg,
+					 struct crypto_authenc_keys *keys)
 {
 	struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm);
 	unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize;
@@ -289,7 +288,7 @@
 	struct icp_qat_hw_auth_algo_blk *hash =
 		(struct icp_qat_hw_auth_algo_blk *)((char *)enc_ctx +
 		sizeof(struct icp_qat_hw_auth_setup) + keys->enckeylen);
-	struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->enc_fw_req_tmpl;
+	struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->enc_fw_req;
 	struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req_tmpl->cd_pars;
 	struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr;
 	void *ptr = &req_tmpl->cd_ctrl;
@@ -297,7 +296,7 @@
 	struct icp_qat_fw_auth_cd_ctrl_hdr *hash_cd_ctrl = ptr;
 
 	/* CD setup */
-	cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_ENC(alg);
+	cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_ENC(alg);
 	memcpy(cipher->aes.key, keys->enckey, keys->enckeylen);
 	hash->sha.inner_setup.auth_config.config =
 		ICP_QAT_HW_AUTH_CONFIG_BUILD(ICP_QAT_HW_AUTH_MODE1,
@@ -311,6 +310,8 @@
 	/* Request setup */
 	qat_alg_init_common_hdr(header);
 	header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER_HASH;
+	ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
+					   ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
 	ICP_QAT_FW_LA_RET_AUTH_SET(header->serv_specif_flags,
 				   ICP_QAT_FW_LA_RET_AUTH_RES);
 	ICP_QAT_FW_LA_CMP_AUTH_SET(header->serv_specif_flags,
@@ -356,8 +357,9 @@
 	return 0;
 }
 
-static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
-				    int alg, struct crypto_authenc_keys *keys)
+static int qat_alg_aead_init_dec_session(struct qat_alg_aead_ctx *ctx,
+					 int alg,
+					 struct crypto_authenc_keys *keys)
 {
 	struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm);
 	unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize;
@@ -367,7 +369,7 @@
 		(struct icp_qat_hw_cipher_algo_blk *)((char *)dec_ctx +
 		sizeof(struct icp_qat_hw_auth_setup) +
 		roundup(crypto_shash_digestsize(ctx->hash_tfm), 8) * 2);
-	struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->dec_fw_req_tmpl;
+	struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->dec_fw_req;
 	struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req_tmpl->cd_pars;
 	struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr;
 	void *ptr = &req_tmpl->cd_ctrl;
@@ -379,7 +381,7 @@
 		sizeof(struct icp_qat_fw_la_cipher_req_params));
 
 	/* CD setup */
-	cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_DEC(alg);
+	cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_DEC(alg);
 	memcpy(cipher->aes.key, keys->enckey, keys->enckeylen);
 	hash->sha.inner_setup.auth_config.config =
 		ICP_QAT_HW_AUTH_CONFIG_BUILD(ICP_QAT_HW_AUTH_MODE1,
@@ -394,6 +396,8 @@
 	/* Request setup */
 	qat_alg_init_common_hdr(header);
 	header->service_cmd_id = ICP_QAT_FW_LA_CMD_HASH_CIPHER;
+	ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
+					   ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
 	ICP_QAT_FW_LA_RET_AUTH_SET(header->serv_specif_flags,
 				   ICP_QAT_FW_LA_NO_RET_AUTH_RES);
 	ICP_QAT_FW_LA_CMP_AUTH_SET(header->serv_specif_flags,
@@ -444,8 +448,74 @@
 	return 0;
 }
 
-static int qat_alg_init_sessions(struct qat_alg_session_ctx *ctx,
-				 const uint8_t *key, unsigned int keylen)
+static void qat_alg_ablkcipher_init_com(struct qat_alg_ablkcipher_ctx *ctx,
+					struct icp_qat_fw_la_bulk_req *req,
+					struct icp_qat_hw_cipher_algo_blk *cd,
+					const uint8_t *key, unsigned int keylen)
+{
+	struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+	struct icp_qat_fw_comn_req_hdr *header = &req->comn_hdr;
+	struct icp_qat_fw_cipher_cd_ctrl_hdr *cd_ctrl = (void *)&req->cd_ctrl;
+
+	memcpy(cd->aes.key, key, keylen);
+	qat_alg_init_common_hdr(header);
+	header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER;
+	cd_pars->u.s.content_desc_params_sz =
+				sizeof(struct icp_qat_hw_cipher_algo_blk) >> 3;
+	/* Cipher CD config setup */
+	cd_ctrl->cipher_key_sz = keylen >> 3;
+	cd_ctrl->cipher_state_sz = AES_BLOCK_SIZE >> 3;
+	cd_ctrl->cipher_cfg_offset = 0;
+	ICP_QAT_FW_COMN_CURR_ID_SET(cd_ctrl, ICP_QAT_FW_SLICE_CIPHER);
+	ICP_QAT_FW_COMN_NEXT_ID_SET(cd_ctrl, ICP_QAT_FW_SLICE_DRAM_WR);
+}
+
+static void qat_alg_ablkcipher_init_enc(struct qat_alg_ablkcipher_ctx *ctx,
+					int alg, const uint8_t *key,
+					unsigned int keylen)
+{
+	struct icp_qat_hw_cipher_algo_blk *enc_cd = ctx->enc_cd;
+	struct icp_qat_fw_la_bulk_req *req = &ctx->enc_fw_req;
+	struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+
+	qat_alg_ablkcipher_init_com(ctx, req, enc_cd, key, keylen);
+	cd_pars->u.s.content_desc_addr = ctx->enc_cd_paddr;
+	enc_cd->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_ENC(alg);
+}
+
+static void qat_alg_ablkcipher_init_dec(struct qat_alg_ablkcipher_ctx *ctx,
+					int alg, const uint8_t *key,
+					unsigned int keylen)
+{
+	struct icp_qat_hw_cipher_algo_blk *dec_cd = ctx->dec_cd;
+	struct icp_qat_fw_la_bulk_req *req = &ctx->dec_fw_req;
+	struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+
+	qat_alg_ablkcipher_init_com(ctx, req, dec_cd, key, keylen);
+	cd_pars->u.s.content_desc_addr = ctx->dec_cd_paddr;
+	dec_cd->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_DEC(alg);
+}
+
+static int qat_alg_validate_key(int key_len, int *alg)
+{
+	switch (key_len) {
+	case AES_KEYSIZE_128:
+		*alg = ICP_QAT_HW_CIPHER_ALGO_AES128;
+		break;
+	case AES_KEYSIZE_192:
+		*alg = ICP_QAT_HW_CIPHER_ALGO_AES192;
+		break;
+	case AES_KEYSIZE_256:
+		*alg = ICP_QAT_HW_CIPHER_ALGO_AES256;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int qat_alg_aead_init_sessions(struct qat_alg_aead_ctx *ctx,
+				      const uint8_t *key, unsigned int keylen)
 {
 	struct crypto_authenc_keys keys;
 	int alg;
@@ -456,24 +526,13 @@
 	if (crypto_authenc_extractkeys(&keys, key, keylen))
 		goto bad_key;
 
-	switch (keys.enckeylen) {
-	case AES_KEYSIZE_128:
-		alg = ICP_QAT_HW_CIPHER_ALGO_AES128;
-		break;
-	case AES_KEYSIZE_192:
-		alg = ICP_QAT_HW_CIPHER_ALGO_AES192;
-		break;
-	case AES_KEYSIZE_256:
-		alg = ICP_QAT_HW_CIPHER_ALGO_AES256;
-		break;
-	default:
+	if (qat_alg_validate_key(keys.enckeylen, &alg))
 		goto bad_key;
-	}
 
-	if (qat_alg_init_enc_session(ctx, alg, &keys))
+	if (qat_alg_aead_init_enc_session(ctx, alg, &keys))
 		goto error;
 
-	if (qat_alg_init_dec_session(ctx, alg, &keys))
+	if (qat_alg_aead_init_dec_session(ctx, alg, &keys))
 		goto error;
 
 	return 0;
@@ -484,22 +543,37 @@
 	return -EFAULT;
 }
 
-static int qat_alg_setkey(struct crypto_aead *tfm, const uint8_t *key,
-			  unsigned int keylen)
+static int qat_alg_ablkcipher_init_sessions(struct qat_alg_ablkcipher_ctx *ctx,
+					    const uint8_t *key,
+					    unsigned int keylen)
 {
-	struct qat_alg_session_ctx *ctx = crypto_aead_ctx(tfm);
+	int alg;
+
+	if (qat_alg_validate_key(keylen, &alg))
+		goto bad_key;
+
+	qat_alg_ablkcipher_init_enc(ctx, alg, key, keylen);
+	qat_alg_ablkcipher_init_dec(ctx, alg, key, keylen);
+	return 0;
+bad_key:
+	crypto_tfm_set_flags(ctx->tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+	return -EINVAL;
+}
+
+static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key,
+			       unsigned int keylen)
+{
+	struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
 	struct device *dev;
 
 	spin_lock(&ctx->lock);
 	if (ctx->enc_cd) {
 		/* rekeying */
 		dev = &GET_DEV(ctx->inst->accel_dev);
-		memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
-		memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
-		memzero_explicit(&ctx->enc_fw_req_tmpl,
-				 sizeof(struct icp_qat_fw_la_bulk_req));
-		memzero_explicit(&ctx->dec_fw_req_tmpl,
-				 sizeof(struct icp_qat_fw_la_bulk_req));
+		memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+		memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+		memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+		memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
 	} else {
 		/* new key */
 		int node = get_current_node();
@@ -512,16 +586,14 @@
 
 		dev = &GET_DEV(inst->accel_dev);
 		ctx->inst = inst;
-		ctx->enc_cd = dma_zalloc_coherent(dev,
-						  sizeof(struct qat_alg_cd),
+		ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd),
 						  &ctx->enc_cd_paddr,
 						  GFP_ATOMIC);
 		if (!ctx->enc_cd) {
 			spin_unlock(&ctx->lock);
 			return -ENOMEM;
 		}
-		ctx->dec_cd = dma_zalloc_coherent(dev,
-						  sizeof(struct qat_alg_cd),
+		ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd),
 						  &ctx->dec_cd_paddr,
 						  GFP_ATOMIC);
 		if (!ctx->dec_cd) {
@@ -530,18 +602,18 @@
 		}
 	}
 	spin_unlock(&ctx->lock);
-	if (qat_alg_init_sessions(ctx, key, keylen))
+	if (qat_alg_aead_init_sessions(ctx, key, keylen))
 		goto out_free_all;
 
 	return 0;
 
 out_free_all:
-	memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
+	memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
 	dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 			  ctx->dec_cd, ctx->dec_cd_paddr);
 	ctx->dec_cd = NULL;
 out_free_enc:
-	memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
+	memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
 	dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 			  ctx->enc_cd, ctx->enc_cd_paddr);
 	ctx->enc_cd = NULL;
@@ -557,7 +629,8 @@
 	dma_addr_t blp = qat_req->buf.blp;
 	dma_addr_t blpout = qat_req->buf.bloutp;
 	size_t sz = qat_req->buf.sz;
-	int i, bufs = bl->num_bufs;
+	size_t sz_out = qat_req->buf.sz_out;
+	int i;
 
 	for (i = 0; i < bl->num_bufs; i++)
 		dma_unmap_single(dev, bl->bufers[i].addr,
@@ -567,14 +640,14 @@
 	kfree(bl);
 	if (blp != blpout) {
 		/* If out of place operation dma unmap only data */
-		int bufless = bufs - blout->num_mapped_bufs;
+		int bufless = blout->num_bufs - blout->num_mapped_bufs;
 
-		for (i = bufless; i < bufs; i++) {
+		for (i = bufless; i < blout->num_bufs; i++) {
 			dma_unmap_single(dev, blout->bufers[i].addr,
 					 blout->bufers[i].len,
 					 DMA_BIDIRECTIONAL);
 		}
-		dma_unmap_single(dev, blpout, sz, DMA_TO_DEVICE);
+		dma_unmap_single(dev, blpout, sz_out, DMA_TO_DEVICE);
 		kfree(blout);
 	}
 }
@@ -587,19 +660,20 @@
 			       struct qat_crypto_request *qat_req)
 {
 	struct device *dev = &GET_DEV(inst->accel_dev);
-	int i, bufs = 0, n = sg_nents(sgl), assoc_n = sg_nents(assoc);
+	int i, bufs = 0, sg_nctr = 0;
+	int n = sg_nents(sgl), assoc_n = sg_nents(assoc);
 	struct qat_alg_buf_list *bufl;
 	struct qat_alg_buf_list *buflout = NULL;
 	dma_addr_t blp;
 	dma_addr_t bloutp = 0;
 	struct scatterlist *sg;
-	size_t sz = sizeof(struct qat_alg_buf_list) +
+	size_t sz_out, sz = sizeof(struct qat_alg_buf_list) +
 			((1 + n + assoc_n) * sizeof(struct qat_alg_buf));
 
 	if (unlikely(!n))
 		return -EINVAL;
 
-	bufl = kmalloc_node(sz, GFP_ATOMIC,
+	bufl = kzalloc_node(sz, GFP_ATOMIC,
 			    dev_to_node(&GET_DEV(inst->accel_dev)));
 	if (unlikely(!bufl))
 		return -ENOMEM;
@@ -620,15 +694,20 @@
 			goto err;
 		bufs++;
 	}
-	bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen,
-						 DMA_BIDIRECTIONAL);
-	bufl->bufers[bufs].len = ivlen;
-	if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr)))
-		goto err;
-	bufs++;
+	if (ivlen) {
+		bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen,
+							 DMA_BIDIRECTIONAL);
+		bufl->bufers[bufs].len = ivlen;
+		if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr)))
+			goto err;
+		bufs++;
+	}
 
 	for_each_sg(sgl, sg, n, i) {
-		int y = i + bufs;
+		int y = sg_nctr + bufs;
+
+		if (!sg->length)
+			continue;
 
 		bufl->bufers[y].addr = dma_map_single(dev, sg_virt(sg),
 						      sg->length,
@@ -636,8 +715,9 @@
 		bufl->bufers[y].len = sg->length;
 		if (unlikely(dma_mapping_error(dev, bufl->bufers[y].addr)))
 			goto err;
+		sg_nctr++;
 	}
-	bufl->num_bufs = n + bufs;
+	bufl->num_bufs = sg_nctr + bufs;
 	qat_req->buf.bl = bufl;
 	qat_req->buf.blp = blp;
 	qat_req->buf.sz = sz;
@@ -645,11 +725,15 @@
 	if (sgl != sglout) {
 		struct qat_alg_buf *bufers;
 
-		buflout = kmalloc_node(sz, GFP_ATOMIC,
+		n = sg_nents(sglout);
+		sz_out = sizeof(struct qat_alg_buf_list) +
+			((1 + n + assoc_n) * sizeof(struct qat_alg_buf));
+		sg_nctr = 0;
+		buflout = kzalloc_node(sz_out, GFP_ATOMIC,
 				       dev_to_node(&GET_DEV(inst->accel_dev)));
 		if (unlikely(!buflout))
 			goto err;
-		bloutp = dma_map_single(dev, buflout, sz, DMA_TO_DEVICE);
+		bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE);
 		if (unlikely(dma_mapping_error(dev, bloutp)))
 			goto err;
 		bufers = buflout->bufers;
@@ -660,60 +744,62 @@
 			bufers[i].addr = bufl->bufers[i].addr;
 		}
 		for_each_sg(sglout, sg, n, i) {
-			int y = i + bufs;
+			int y = sg_nctr + bufs;
+
+			if (!sg->length)
+				continue;
 
 			bufers[y].addr = dma_map_single(dev, sg_virt(sg),
 							sg->length,
 							DMA_BIDIRECTIONAL);
-			buflout->bufers[y].len = sg->length;
 			if (unlikely(dma_mapping_error(dev, bufers[y].addr)))
 				goto err;
+			bufers[y].len = sg->length;
+			sg_nctr++;
 		}
-		buflout->num_bufs = n + bufs;
-		buflout->num_mapped_bufs = n;
+		buflout->num_bufs = sg_nctr + bufs;
+		buflout->num_mapped_bufs = sg_nctr;
 		qat_req->buf.blout = buflout;
 		qat_req->buf.bloutp = bloutp;
+		qat_req->buf.sz_out = sz_out;
 	} else {
 		/* Otherwise set the src and dst to the same address */
 		qat_req->buf.bloutp = qat_req->buf.blp;
+		qat_req->buf.sz_out = 0;
 	}
 	return 0;
 err:
 	dev_err(dev, "Failed to map buf for dma\n");
-	for_each_sg(sgl, sg, n + bufs, i) {
-		if (!dma_mapping_error(dev, bufl->bufers[i].addr)) {
+	sg_nctr = 0;
+	for (i = 0; i < n + bufs; i++)
+		if (!dma_mapping_error(dev, bufl->bufers[i].addr))
 			dma_unmap_single(dev, bufl->bufers[i].addr,
 					 bufl->bufers[i].len,
 					 DMA_BIDIRECTIONAL);
-		}
-	}
+
 	if (!dma_mapping_error(dev, blp))
 		dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE);
 	kfree(bufl);
 	if (sgl != sglout && buflout) {
-		for_each_sg(sglout, sg, n, i) {
-			int y = i + bufs;
-
-			if (!dma_mapping_error(dev, buflout->bufers[y].addr))
-				dma_unmap_single(dev, buflout->bufers[y].addr,
-						 buflout->bufers[y].len,
+		n = sg_nents(sglout);
+		for (i = bufs; i < n + bufs; i++)
+			if (!dma_mapping_error(dev, buflout->bufers[i].addr))
+				dma_unmap_single(dev, buflout->bufers[i].addr,
+						 buflout->bufers[i].len,
 						 DMA_BIDIRECTIONAL);
-		}
 		if (!dma_mapping_error(dev, bloutp))
-			dma_unmap_single(dev, bloutp, sz, DMA_TO_DEVICE);
+			dma_unmap_single(dev, bloutp, sz_out, DMA_TO_DEVICE);
 		kfree(buflout);
 	}
 	return -ENOMEM;
 }
 
-void qat_alg_callback(void *resp)
+static void qat_aead_alg_callback(struct icp_qat_fw_la_resp *qat_resp,
+				  struct qat_crypto_request *qat_req)
 {
-	struct icp_qat_fw_la_resp *qat_resp = resp;
-	struct qat_crypto_request *qat_req =
-				(void *)(__force long)qat_resp->opaque_data;
-	struct qat_alg_session_ctx *ctx = qat_req->ctx;
+	struct qat_alg_aead_ctx *ctx = qat_req->aead_ctx;
 	struct qat_crypto_instance *inst = ctx->inst;
-	struct aead_request *areq = qat_req->areq;
+	struct aead_request *areq = qat_req->aead_req;
 	uint8_t stat_filed = qat_resp->comn_resp.comn_status;
 	int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed);
 
@@ -723,11 +809,35 @@
 	areq->base.complete(&areq->base, res);
 }
 
-static int qat_alg_dec(struct aead_request *areq)
+static void qat_ablkcipher_alg_callback(struct icp_qat_fw_la_resp *qat_resp,
+					struct qat_crypto_request *qat_req)
+{
+	struct qat_alg_ablkcipher_ctx *ctx = qat_req->ablkcipher_ctx;
+	struct qat_crypto_instance *inst = ctx->inst;
+	struct ablkcipher_request *areq = qat_req->ablkcipher_req;
+	uint8_t stat_filed = qat_resp->comn_resp.comn_status;
+	int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed);
+
+	qat_alg_free_bufl(inst, qat_req);
+	if (unlikely(qat_res != ICP_QAT_FW_COMN_STATUS_FLAG_OK))
+		res = -EINVAL;
+	areq->base.complete(&areq->base, res);
+}
+
+void qat_alg_callback(void *resp)
+{
+	struct icp_qat_fw_la_resp *qat_resp = resp;
+	struct qat_crypto_request *qat_req =
+				(void *)(__force long)qat_resp->opaque_data;
+
+	qat_req->cb(qat_resp, qat_req);
+}
+
+static int qat_alg_aead_dec(struct aead_request *areq)
 {
 	struct crypto_aead *aead_tfm = crypto_aead_reqtfm(areq);
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
-	struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct qat_crypto_request *qat_req = aead_request_ctx(areq);
 	struct icp_qat_fw_la_cipher_req_params *cipher_param;
 	struct icp_qat_fw_la_auth_req_params *auth_param;
@@ -741,9 +851,10 @@
 		return ret;
 
 	msg = &qat_req->req;
-	*msg = ctx->dec_fw_req_tmpl;
-	qat_req->ctx = ctx;
-	qat_req->areq = areq;
+	*msg = ctx->dec_fw_req;
+	qat_req->aead_ctx = ctx;
+	qat_req->aead_req = areq;
+	qat_req->cb = qat_aead_alg_callback;
 	qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
 	qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
 	qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
@@ -766,12 +877,12 @@
 	return -EINPROGRESS;
 }
 
-static int qat_alg_enc_internal(struct aead_request *areq, uint8_t *iv,
-				int enc_iv)
+static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv,
+				     int enc_iv)
 {
 	struct crypto_aead *aead_tfm = crypto_aead_reqtfm(areq);
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
-	struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct qat_crypto_request *qat_req = aead_request_ctx(areq);
 	struct icp_qat_fw_la_cipher_req_params *cipher_param;
 	struct icp_qat_fw_la_auth_req_params *auth_param;
@@ -784,9 +895,10 @@
 		return ret;
 
 	msg = &qat_req->req;
-	*msg = ctx->enc_fw_req_tmpl;
-	qat_req->ctx = ctx;
-	qat_req->areq = areq;
+	*msg = ctx->enc_fw_req;
+	qat_req->aead_ctx = ctx;
+	qat_req->aead_req = areq;
+	qat_req->cb = qat_aead_alg_callback;
 	qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
 	qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
 	qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
@@ -815,31 +927,168 @@
 	return -EINPROGRESS;
 }
 
-static int qat_alg_enc(struct aead_request *areq)
+static int qat_alg_aead_enc(struct aead_request *areq)
 {
-	return qat_alg_enc_internal(areq, areq->iv, 0);
+	return qat_alg_aead_enc_internal(areq, areq->iv, 0);
 }
 
-static int qat_alg_genivenc(struct aead_givcrypt_request *req)
+static int qat_alg_aead_genivenc(struct aead_givcrypt_request *req)
 {
 	struct crypto_aead *aead_tfm = crypto_aead_reqtfm(&req->areq);
 	struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
-	struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
 	__be64 seq;
 
 	memcpy(req->giv, ctx->salt, AES_BLOCK_SIZE);
 	seq = cpu_to_be64(req->seq);
 	memcpy(req->giv + AES_BLOCK_SIZE - sizeof(uint64_t),
 	       &seq, sizeof(uint64_t));
-	return qat_alg_enc_internal(&req->areq, req->giv, 1);
+	return qat_alg_aead_enc_internal(&req->areq, req->giv, 1);
 }
 
-static int qat_alg_init(struct crypto_tfm *tfm,
-			enum icp_qat_hw_auth_algo hash, const char *hash_name)
+static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+				     const uint8_t *key,
+				     unsigned int keylen)
 {
-	struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+	struct device *dev;
 
-	memzero_explicit(ctx, sizeof(*ctx));
+	spin_lock(&ctx->lock);
+	if (ctx->enc_cd) {
+		/* rekeying */
+		dev = &GET_DEV(ctx->inst->accel_dev);
+		memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+		memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+		memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+		memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
+	} else {
+		/* new key */
+		int node = get_current_node();
+		struct qat_crypto_instance *inst =
+				qat_crypto_get_instance_node(node);
+		if (!inst) {
+			spin_unlock(&ctx->lock);
+			return -EINVAL;
+		}
+
+		dev = &GET_DEV(inst->accel_dev);
+		ctx->inst = inst;
+		ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd),
+						  &ctx->enc_cd_paddr,
+						  GFP_ATOMIC);
+		if (!ctx->enc_cd) {
+			spin_unlock(&ctx->lock);
+			return -ENOMEM;
+		}
+		ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd),
+						  &ctx->dec_cd_paddr,
+						  GFP_ATOMIC);
+		if (!ctx->dec_cd) {
+			spin_unlock(&ctx->lock);
+			goto out_free_enc;
+		}
+	}
+	spin_unlock(&ctx->lock);
+	if (qat_alg_ablkcipher_init_sessions(ctx, key, keylen))
+		goto out_free_all;
+
+	return 0;
+
+out_free_all:
+	memset(ctx->dec_cd, 0, sizeof(*ctx->enc_cd));
+	dma_free_coherent(dev, sizeof(*ctx->enc_cd),
+			  ctx->dec_cd, ctx->dec_cd_paddr);
+	ctx->dec_cd = NULL;
+out_free_enc:
+	memset(ctx->enc_cd, 0, sizeof(*ctx->dec_cd));
+	dma_free_coherent(dev, sizeof(*ctx->dec_cd),
+			  ctx->enc_cd, ctx->enc_cd_paddr);
+	ctx->enc_cd = NULL;
+	return -ENOMEM;
+}
+
+static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm);
+	struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
+	struct icp_qat_fw_la_cipher_req_params *cipher_param;
+	struct icp_qat_fw_la_bulk_req *msg;
+	int ret, ctr = 0;
+
+	ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+				  NULL, 0, qat_req);
+	if (unlikely(ret))
+		return ret;
+
+	msg = &qat_req->req;
+	*msg = ctx->enc_fw_req;
+	qat_req->ablkcipher_ctx = ctx;
+	qat_req->ablkcipher_req = req;
+	qat_req->cb = qat_ablkcipher_alg_callback;
+	qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
+	qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
+	qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
+	cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
+	cipher_param->cipher_length = req->nbytes;
+	cipher_param->cipher_offset = 0;
+	memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+	do {
+		ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
+	} while (ret == -EAGAIN && ctr++ < 10);
+
+	if (ret == -EAGAIN) {
+		qat_alg_free_bufl(ctx->inst, qat_req);
+		return -EBUSY;
+	}
+	return -EINPROGRESS;
+}
+
+static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+	struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm);
+	struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
+	struct icp_qat_fw_la_cipher_req_params *cipher_param;
+	struct icp_qat_fw_la_bulk_req *msg;
+	int ret, ctr = 0;
+
+	ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+				  NULL, 0, qat_req);
+	if (unlikely(ret))
+		return ret;
+
+	msg = &qat_req->req;
+	*msg = ctx->dec_fw_req;
+	qat_req->ablkcipher_ctx = ctx;
+	qat_req->ablkcipher_req = req;
+	qat_req->cb = qat_ablkcipher_alg_callback;
+	qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
+	qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
+	qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
+	cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
+	cipher_param->cipher_length = req->nbytes;
+	cipher_param->cipher_offset = 0;
+	memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+	do {
+		ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
+	} while (ret == -EAGAIN && ctr++ < 10);
+
+	if (ret == -EAGAIN) {
+		qat_alg_free_bufl(ctx->inst, qat_req);
+		return -EBUSY;
+	}
+	return -EINPROGRESS;
+}
+
+static int qat_alg_aead_init(struct crypto_tfm *tfm,
+			     enum icp_qat_hw_auth_algo hash,
+			     const char *hash_name)
+{
+	struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+
 	ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0);
 	if (IS_ERR(ctx->hash_tfm))
 		return -EFAULT;
@@ -851,24 +1100,24 @@
 	return 0;
 }
 
-static int qat_alg_sha1_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha1_init(struct crypto_tfm *tfm)
 {
-	return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1");
+	return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1");
 }
 
-static int qat_alg_sha256_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha256_init(struct crypto_tfm *tfm)
 {
-	return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256");
+	return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256");
 }
 
-static int qat_alg_sha512_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha512_init(struct crypto_tfm *tfm)
 {
-	return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512");
+	return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512");
 }
 
-static void qat_alg_exit(struct crypto_tfm *tfm)
+static void qat_alg_aead_exit(struct crypto_tfm *tfm)
 {
-	struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
 	struct qat_crypto_instance *inst = ctx->inst;
 	struct device *dev;
 
@@ -880,36 +1129,74 @@
 
 	dev = &GET_DEV(inst->accel_dev);
 	if (ctx->enc_cd) {
-		memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
+		memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
 		dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 				  ctx->enc_cd, ctx->enc_cd_paddr);
 	}
 	if (ctx->dec_cd) {
-		memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
+		memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
 		dma_free_coherent(dev, sizeof(struct qat_alg_cd),
 				  ctx->dec_cd, ctx->dec_cd_paddr);
 	}
 	qat_crypto_put_instance(inst);
 }
 
+static int qat_alg_ablkcipher_init(struct crypto_tfm *tfm)
+{
+	struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	spin_lock_init(&ctx->lock);
+	tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+					sizeof(struct qat_crypto_request);
+	ctx->tfm = tfm;
+	return 0;
+}
+
+static void qat_alg_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+	struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct qat_crypto_instance *inst = ctx->inst;
+	struct device *dev;
+
+	if (!inst)
+		return;
+
+	dev = &GET_DEV(inst->accel_dev);
+	if (ctx->enc_cd) {
+		memset(ctx->enc_cd, 0,
+		       sizeof(struct icp_qat_hw_cipher_algo_blk));
+		dma_free_coherent(dev,
+				  sizeof(struct icp_qat_hw_cipher_algo_blk),
+				  ctx->enc_cd, ctx->enc_cd_paddr);
+	}
+	if (ctx->dec_cd) {
+		memset(ctx->dec_cd, 0,
+		       sizeof(struct icp_qat_hw_cipher_algo_blk));
+		dma_free_coherent(dev,
+				  sizeof(struct icp_qat_hw_cipher_algo_blk),
+				  ctx->dec_cd, ctx->dec_cd_paddr);
+	}
+	qat_crypto_put_instance(inst);
+}
+
 static struct crypto_alg qat_algs[] = { {
 	.cra_name = "authenc(hmac(sha1),cbc(aes))",
 	.cra_driver_name = "qat_aes_cbc_hmac_sha1",
 	.cra_priority = 4001,
 	.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
 	.cra_blocksize = AES_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+	.cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
 	.cra_alignmask = 0,
 	.cra_type = &crypto_aead_type,
 	.cra_module = THIS_MODULE,
-	.cra_init = qat_alg_sha1_init,
-	.cra_exit = qat_alg_exit,
+	.cra_init = qat_alg_aead_sha1_init,
+	.cra_exit = qat_alg_aead_exit,
 	.cra_u = {
 		.aead = {
-			.setkey = qat_alg_setkey,
-			.decrypt = qat_alg_dec,
-			.encrypt = qat_alg_enc,
-			.givencrypt = qat_alg_genivenc,
+			.setkey = qat_alg_aead_setkey,
+			.decrypt = qat_alg_aead_dec,
+			.encrypt = qat_alg_aead_enc,
+			.givencrypt = qat_alg_aead_genivenc,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA1_DIGEST_SIZE,
 		},
@@ -920,18 +1207,18 @@
 	.cra_priority = 4001,
 	.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
 	.cra_blocksize = AES_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+	.cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
 	.cra_alignmask = 0,
 	.cra_type = &crypto_aead_type,
 	.cra_module = THIS_MODULE,
-	.cra_init = qat_alg_sha256_init,
-	.cra_exit = qat_alg_exit,
+	.cra_init = qat_alg_aead_sha256_init,
+	.cra_exit = qat_alg_aead_exit,
 	.cra_u = {
 		.aead = {
-			.setkey = qat_alg_setkey,
-			.decrypt = qat_alg_dec,
-			.encrypt = qat_alg_enc,
-			.givencrypt = qat_alg_genivenc,
+			.setkey = qat_alg_aead_setkey,
+			.decrypt = qat_alg_aead_dec,
+			.encrypt = qat_alg_aead_enc,
+			.givencrypt = qat_alg_aead_genivenc,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA256_DIGEST_SIZE,
 		},
@@ -942,22 +1229,44 @@
 	.cra_priority = 4001,
 	.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
 	.cra_blocksize = AES_BLOCK_SIZE,
-	.cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+	.cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
 	.cra_alignmask = 0,
 	.cra_type = &crypto_aead_type,
 	.cra_module = THIS_MODULE,
-	.cra_init = qat_alg_sha512_init,
-	.cra_exit = qat_alg_exit,
+	.cra_init = qat_alg_aead_sha512_init,
+	.cra_exit = qat_alg_aead_exit,
 	.cra_u = {
 		.aead = {
-			.setkey = qat_alg_setkey,
-			.decrypt = qat_alg_dec,
-			.encrypt = qat_alg_enc,
-			.givencrypt = qat_alg_genivenc,
+			.setkey = qat_alg_aead_setkey,
+			.decrypt = qat_alg_aead_dec,
+			.encrypt = qat_alg_aead_enc,
+			.givencrypt = qat_alg_aead_genivenc,
 			.ivsize = AES_BLOCK_SIZE,
 			.maxauthsize = SHA512_DIGEST_SIZE,
 		},
 	},
+}, {
+	.cra_name = "cbc(aes)",
+	.cra_driver_name = "qat_aes_cbc",
+	.cra_priority = 4001,
+	.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize = AES_BLOCK_SIZE,
+	.cra_ctxsize = sizeof(struct qat_alg_ablkcipher_ctx),
+	.cra_alignmask = 0,
+	.cra_type = &crypto_ablkcipher_type,
+	.cra_module = THIS_MODULE,
+	.cra_init = qat_alg_ablkcipher_init,
+	.cra_exit = qat_alg_ablkcipher_exit,
+	.cra_u = {
+		.ablkcipher = {
+			.setkey = qat_alg_ablkcipher_setkey,
+			.decrypt = qat_alg_ablkcipher_decrypt,
+			.encrypt = qat_alg_ablkcipher_encrypt,
+			.min_keysize = AES_MIN_KEY_SIZE,
+			.max_keysize = AES_MAX_KEY_SIZE,
+			.ivsize = AES_BLOCK_SIZE,
+		},
+	},
 } };
 
 int qat_algs_register(void)
@@ -966,8 +1275,11 @@
 		int i;
 
 		for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
-			qat_algs[i].cra_flags =	CRYPTO_ALG_TYPE_AEAD |
-						CRYPTO_ALG_ASYNC;
+			qat_algs[i].cra_flags =
+				(qat_algs[i].cra_type == &crypto_aead_type) ?
+				CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
+				CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+
 		return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
 	}
 	return 0;
diff --git a/drivers/crypto/qat/qat_common/qat_crypto.h b/drivers/crypto/qat/qat_common/qat_crypto.h
index ab8468d..d503007 100644
--- a/drivers/crypto/qat/qat_common/qat_crypto.h
+++ b/drivers/crypto/qat/qat_common/qat_crypto.h
@@ -72,12 +72,24 @@
 	struct qat_alg_buf_list *blout;
 	dma_addr_t bloutp;
 	size_t sz;
+	size_t sz_out;
 };
 
+struct qat_crypto_request;
+
 struct qat_crypto_request {
 	struct icp_qat_fw_la_bulk_req req;
-	struct qat_alg_session_ctx *ctx;
-	struct aead_request *areq;
+	union {
+		struct qat_alg_aead_ctx *aead_ctx;
+		struct qat_alg_ablkcipher_ctx *ablkcipher_ctx;
+	};
+	union {
+		struct aead_request *aead_req;
+		struct ablkcipher_request *ablkcipher_req;
+	};
 	struct qat_crypto_request_buffs buf;
+	void (*cb)(struct icp_qat_fw_la_resp *resp,
+		   struct qat_crypto_request *req);
 };
+
 #endif
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
index ef05825..6a735d5 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
@@ -46,6 +46,7 @@
 */
 #include <adf_accel_devices.h>
 #include "adf_dh895xcc_hw_data.h"
+#include "adf_common_drv.h"
 #include "adf_drv.h"
 
 /* Worker thread to service arbiter mappings based on dev SKUs */
@@ -182,6 +183,19 @@
 	}
 }
 
+static void adf_enable_ints(struct adf_accel_dev *accel_dev)
+{
+	void __iomem *addr;
+
+	addr = (&GET_BARS(accel_dev)[ADF_DH895XCC_PMISC_BAR])->virt_addr;
+
+	/* Enable bundle and misc interrupts */
+	ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF0_MASK_OFFSET,
+		   ADF_DH895XCC_SMIA0_MASK);
+	ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF1_MASK_OFFSET,
+		   ADF_DH895XCC_SMIA1_MASK);
+}
+
 void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
 {
 	hw_data->dev_class = &dh895xcc_class;
@@ -206,6 +220,11 @@
 	hw_data->get_misc_bar_id = get_misc_bar_id;
 	hw_data->get_sku = get_sku;
 	hw_data->fw_name = ADF_DH895XCC_FW;
+	hw_data->init_admin_comms = adf_init_admin_comms;
+	hw_data->exit_admin_comms = adf_exit_admin_comms;
+	hw_data->init_arb = adf_init_arb;
+	hw_data->exit_arb = adf_exit_arb;
+	hw_data->enable_ints = adf_enable_ints;
 }
 
 void adf_clean_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
index 948f66b..8ffdb95 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
@@ -90,9 +90,7 @@
 	struct adf_accel_pci *accel_pci_dev = &accel_dev->accel_pci_dev;
 	int i;
 
-	adf_exit_admin_comms(accel_dev);
-	adf_exit_arb(accel_dev);
-	adf_cleanup_etr_data(accel_dev);
+	adf_dev_shutdown(accel_dev);
 
 	for (i = 0; i < ADF_PCI_MAX_BARS; i++) {
 		struct adf_bar *bar = &accel_pci_dev->pci_bars[i];
@@ -119,7 +117,7 @@
 	kfree(accel_dev);
 }
 
-static int qat_dev_start(struct adf_accel_dev *accel_dev)
+static int adf_dev_configure(struct adf_accel_dev *accel_dev)
 {
 	int cpus = num_online_cpus();
 	int banks = GET_MAX_BANKS(accel_dev);
@@ -206,7 +204,7 @@
 		goto err;
 
 	set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
-	return adf_dev_start(accel_dev);
+	return 0;
 err:
 	dev_err(&GET_DEV(accel_dev), "Failed to start QAT accel dev\n");
 	return -EINVAL;
@@ -217,7 +215,6 @@
 	struct adf_accel_dev *accel_dev;
 	struct adf_accel_pci *accel_pci_dev;
 	struct adf_hw_device_data *hw_data;
-	void __iomem *pmisc_bar_addr = NULL;
 	char name[ADF_DEVICE_NAME_LENGTH];
 	unsigned int i, bar_nr;
 	int ret;
@@ -347,8 +344,6 @@
 			ret = -EFAULT;
 			goto out_err;
 		}
-		if (i == ADF_DH895XCC_PMISC_BAR)
-			pmisc_bar_addr = bar->virt_addr;
 	}
 	pci_set_master(pdev);
 
@@ -358,36 +353,21 @@
 		goto out_err;
 	}
 
-	if (adf_init_etr_data(accel_dev)) {
-		dev_err(&pdev->dev, "Failed initialize etr\n");
-		ret = -EFAULT;
-		goto out_err;
-	}
-
-	if (adf_init_admin_comms(accel_dev)) {
-		dev_err(&pdev->dev, "Failed initialize admin comms\n");
-		ret = -EFAULT;
-		goto out_err;
-	}
-
-	if (adf_init_arb(accel_dev)) {
-		dev_err(&pdev->dev, "Failed initialize hw arbiter\n");
-		ret = -EFAULT;
-		goto out_err;
-	}
 	if (pci_save_state(pdev)) {
 		dev_err(&pdev->dev, "Failed to save pci state\n");
 		ret = -ENOMEM;
 		goto out_err;
 	}
 
-	/* Enable bundle and misc interrupts */
-	ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCC_SMIAPF0_MASK_OFFSET,
-		   ADF_DH895XCC_SMIA0_MASK);
-	ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCC_SMIAPF1_MASK_OFFSET,
-		   ADF_DH895XCC_SMIA1_MASK);
+	ret = adf_dev_configure(accel_dev);
+	if (ret)
+		goto out_err;
 
-	ret = qat_dev_start(accel_dev);
+	ret = adf_dev_init(accel_dev);
+	if (ret)
+		goto out_err;
+
+	ret = adf_dev_start(accel_dev);
 	if (ret) {
 		adf_dev_stop(accel_dev);
 		goto out_err;
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 0fb21e1..378cb76 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -64,7 +64,7 @@
 			err = dma_map_sg(dev, sg, 1, dir);
 			if (!err)
 				return -EFAULT;
-			sg = scatterwalk_sg_next(sg);
+			sg = sg_next(sg);
 		}
 	} else {
 		err = dma_map_sg(dev, sg, nents, dir);
@@ -81,7 +81,7 @@
 	if (chained)
 		while (sg) {
 			dma_unmap_sg(dev, sg, 1, dir);
-			sg = scatterwalk_sg_next(sg);
+			sg = sg_next(sg);
 		}
 	else
 		dma_unmap_sg(dev, sg, nents, dir);
@@ -100,7 +100,7 @@
 		nbytes -= sg->length;
 		if (!sg_is_last(sg) && (sg + 1)->length == 0 && chained)
 			*chained = true;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	return nents;
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index f338593..5c5df1d 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -285,7 +285,7 @@
 			break;
 		len += sg_dma_len(sg);
 		sg_last = sg;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	if (!sg_last)
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 220b92f..290a7f0 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -940,7 +940,7 @@
 			break;
 		}
 		nbytes -= sg->length;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	return nbytes;
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 067ec21..ebbae8d 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -743,7 +743,7 @@
 	if (unlikely(chained))
 		while (sg) {
 			dma_map_sg(dev, sg, 1, dir);
-			sg = scatterwalk_sg_next(sg);
+			sg = sg_next(sg);
 		}
 	else
 		dma_map_sg(dev, sg, nents, dir);
@@ -755,7 +755,7 @@
 {
 	while (sg) {
 		dma_unmap_sg(dev, sg, 1, dir);
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 }
 
@@ -915,7 +915,7 @@
 		link_tbl_ptr->j_extent = 0;
 		link_tbl_ptr++;
 		cryptlen -= sg_dma_len(sg);
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	/* adjust (decrease) last one (or two) entry's len to cryptlen */
@@ -1102,7 +1102,7 @@
 		nbytes -= sg->length;
 		if (!sg_is_last(sg) && (sg + 1)->length == 0)
 			*chained = true;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	return sg_nents;
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index f831bb9..d594ae96 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -479,13 +479,13 @@
 		.dst_addr = device_data->phybase + CRYP_DMA_TX_FIFO,
 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
 		.dst_maxburst = 4,
-        };
+	};
 	struct dma_slave_config cryp2mem = {
 		.direction = DMA_DEV_TO_MEM,
 		.src_addr = device_data->phybase + CRYP_DMA_RX_FIFO,
 		.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
 		.src_maxburst = 4,
-        };
+	};
 
 	dma_cap_zero(device_data->dma.mask);
 	dma_cap_set(DMA_SLAVE, device_data->dma.mask);
@@ -814,7 +814,7 @@
 
 	while (nbytes > 0) {
 		nbytes -= sg->length;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 		nents++;
 	}
 
@@ -1774,8 +1774,8 @@
 static SIMPLE_DEV_PM_OPS(ux500_cryp_pm, ux500_cryp_suspend, ux500_cryp_resume);
 
 static const struct of_device_id ux500_cryp_match[] = {
-        { .compatible = "stericsson,ux500-cryp" },
-        { },
+	{ .compatible = "stericsson,ux500-cryp" },
+	{ },
 };
 
 static struct platform_driver cryp_driver = {
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index f2b2c4e..faf30a4 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -184,7 +184,7 @@
 
 config S3C24XX_DMAC
 	tristate "Samsung S3C24XX DMA support"
-	depends on ARCH_S3C24XX && !S3C24XX_DMA
+	depends on ARCH_S3C24XX
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 	help
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 5d7ab57..2bb82e5 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -173,6 +173,7 @@
 
 	free_irq(data->irq, data);
 	cancel_work_sync(&data->handler.work);
+	iio_channel_release(data->chan);
 
 	return 0;
 }
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 043dcd9..8319f25 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -32,7 +32,6 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
-#include <linux/of.h>
 
 /*
  * extcon_cable_name suggests the standard cable names for commonly used
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 740a14d..af165fd 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1033,7 +1033,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct regmap_config max77693_muic_regmap_config = {
+static const struct regmap_config max77693_muic_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 };
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 8902f52..280bc0a 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -19,6 +19,7 @@
 				   $(call cc-option,-fno-stack-protector)
 
 GCOV_PROFILE			:= n
+KASAN_SANITIZE			:= n
 
 lib-y				:= efi-stub-helper.o
 lib-$(CONFIG_EFI_ARMSTUB)	+= arm-stub.o fdt.o
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 2be1098..47437b1 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -5,6 +5,10 @@
 /* error code which can't be mistaken for valid address */
 #define EFI_ERROR	(~0UL)
 
+#undef memcpy
+#undef memset
+#undef memmove
+
 void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
 
 efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 70da9eb..e9ed439 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1,3 +1,6 @@
-obj-y			+= drm/ vga/
+# drm/tegra depends on host1x, so if both drivers are built-in care must be
+# taken to initialize them in the correct order. Link order is the only way
+# to ensure this currently.
 obj-$(CONFIG_TEGRA_HOST1X)	+= host1x/
+obj-y			+= drm/ vga/
 obj-$(CONFIG_IMX_IPUV3_CORE)	+= ipu-v3/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c3413b6..151a050 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -62,12 +62,13 @@
 
 config DRM_GEM_CMA_HELPER
 	bool
-	depends on DRM
+	depends on DRM && HAVE_DMA_ATTRS
 	help
 	  Choose this if you need the GEM CMA helper functions
 
 config DRM_KMS_CMA_HELPER
 	bool
+	depends on DRM && HAVE_DMA_ATTRS
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_FB_HELPER
 	select FB_SYS_FILLRECT
@@ -110,7 +111,6 @@
 	select HWMON
 	select BACKLIGHT_CLASS_DEVICE
 	select INTERVAL_TREE
-	select MMU_NOTIFIER
 	help
 	  Choose this option if you have an ATI Radeon graphics card.  There
 	  are both PCI and AGP versions.  You don't need to choose this to
@@ -183,6 +183,8 @@
 
 source "drivers/gpu/drm/armada/Kconfig"
 
+source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
+
 source "drivers/gpu/drm/rcar-du/Kconfig"
 
 source "drivers/gpu/drm/shmobile/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e620807..2c239b9 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@
 		drm_info.o drm_debugfs.o drm_encoder_slave.o \
 		drm_trace_points.o drm_global.o drm_prime.o \
 		drm_rect.o drm_vma_manager.o drm_flip_work.o \
-		drm_modeset_lock.o drm_atomic.o
+		drm_modeset_lock.o drm_atomic.o drm_bridge.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -55,6 +55,7 @@
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 obj-$(CONFIG_DRM_ARMADA) += armada/
+obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile
index 307a309..0f49601 100644
--- a/drivers/gpu/drm/amd/amdkfd/Makefile
+++ b/drivers/gpu/drm/amd/amdkfd/Makefile
@@ -7,7 +7,10 @@
 amdkfd-y	:= kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
 		kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
 		kfd_process.o kfd_queue.o kfd_mqd_manager.o \
-		kfd_kernel_queue.o kfd_packet_manager.o \
-		kfd_process_queue_manager.o kfd_device_queue_manager.o
+		kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \
+		kfd_kernel_queue.o kfd_kernel_queue_cik.o \
+		kfd_kernel_queue_vi.o kfd_packet_manager.o \
+		kfd_process_queue_manager.o kfd_device_queue_manager.o \
+		kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \
 
 obj-$(CONFIG_HSA_AMD)	+= amdkfd.o
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
index 607fc5c..01ff332 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h
+++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
@@ -168,6 +168,8 @@
 #define	IB_ATC_EN					(1U << 23)
 #define	DEFAULT_MIN_IB_AVAIL_SIZE			(3U << 20)
 
+#define	AQL_ENABLE					1
+
 #define CP_HQD_DEQUEUE_REQUEST				0xC974
 #define	DEQUEUE_REQUEST_DRAIN				1
 #define DEQUEUE_REQUEST_RESET				2
@@ -188,6 +190,17 @@
 #define	MQD_VMID_MASK					(0xf << 0)
 #define	MQD_CONTROL_PRIV_STATE_EN			(1U << 8)
 
+#define	SDMA_RB_VMID(x)					(x << 24)
+#define	SDMA_RB_ENABLE					(1 << 0)
+#define	SDMA_RB_SIZE(x)					((x) << 1) /* log2 */
+#define	SDMA_RPTR_WRITEBACK_ENABLE			(1 << 12)
+#define	SDMA_RPTR_WRITEBACK_TIMER(x)			((x) << 16) /* log2 */
+#define	SDMA_OFFSET(x)					(x << 0)
+#define	SDMA_DB_ENABLE					(1 << 28)
+#define	SDMA_ATC					(1 << 0)
+#define	SDMA_VA_PTR32					(1 << 4)
+#define	SDMA_VA_SHARED_BASE(x)				(x << 8)
+
 #define GRBM_GFX_INDEX					0x30800
 #define	INSTANCE_INDEX(x)				((x) << 0)
 #define	SH_INDEX(x)					((x) << 8)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index fcfdf23..5c50aa8 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -178,6 +178,22 @@
 		return -EFAULT;
 	}
 
+	if (args->eop_buffer_address &&
+		!access_ok(VERIFY_WRITE,
+			(const void __user *) args->eop_buffer_address,
+			sizeof(uint32_t))) {
+		pr_debug("kfd: can't access eop buffer");
+		return -EFAULT;
+	}
+
+	if (args->ctx_save_restore_address &&
+		!access_ok(VERIFY_WRITE,
+			(const void __user *) args->ctx_save_restore_address,
+			sizeof(uint32_t))) {
+		pr_debug("kfd: can't access ctx save restore buffer");
+		return -EFAULT;
+	}
+
 	q_properties->is_interop = false;
 	q_properties->queue_percent = args->queue_percentage;
 	q_properties->priority = args->queue_priority;
@@ -185,9 +201,16 @@
 	q_properties->queue_size = args->ring_size;
 	q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
 	q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
+	q_properties->eop_ring_buffer_address = args->eop_buffer_address;
+	q_properties->eop_ring_buffer_size = args->eop_buffer_size;
+	q_properties->ctx_save_restore_area_address =
+			args->ctx_save_restore_address;
+	q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size;
 	if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
 		args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
 		q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
+	else if (args->queue_type == KFD_IOC_QUEUE_TYPE_SDMA)
+		q_properties->type = KFD_QUEUE_TYPE_SDMA;
 	else
 		return -ENOTSUPP;
 
@@ -214,6 +237,11 @@
 
 	pr_debug("Queue Format (%d)\n", q_properties->format);
 
+	pr_debug("Queue EOP (0x%llX)\n", q_properties->eop_ring_buffer_address);
+
+	pr_debug("Queue CTX save arex (0x%llX)\n",
+			q_properties->ctx_save_restore_area_address);
+
 	return 0;
 }
 
@@ -235,9 +263,12 @@
 	if (err)
 		return err;
 
+	pr_debug("kfd: looking for gpu id 0x%x\n", args->gpu_id);
 	dev = kfd_device_by_id(args->gpu_id);
-	if (dev == NULL)
+	if (dev == NULL) {
+		pr_debug("kfd: gpu id 0x%x was not found\n", args->gpu_id);
 		return -EINVAL;
+	}
 
 	mutex_lock(&p->mutex);
 
@@ -251,8 +282,8 @@
 			p->pasid,
 			dev->id);
 
-	err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0,
-				KFD_QUEUE_TYPE_COMPUTE, &queue_id);
+	err = pqm_create_queue(&p->pqm, dev, filep, &q_properties,
+				0, q_properties.type, &queue_id);
 	if (err != 0)
 		goto err_create_queue;
 
@@ -385,7 +416,7 @@
 		(args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
 		   ? cache_policy_coherent : cache_policy_noncoherent;
 
-	if (!dev->dqm->set_cache_memory_policy(dev->dqm,
+	if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm,
 				&pdd->qpd,
 				default_policy,
 				alternate_policy,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 25bc47f..5bc32c2 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -31,11 +31,20 @@
 #define MQD_SIZE_ALIGNED 768
 
 static const struct kfd_device_info kaveri_device_info = {
+	.asic_family = CHIP_KAVERI,
 	.max_pasid_bits = 16,
 	.ih_ring_entry_size = 4 * sizeof(uint32_t),
 	.mqd_size_aligned = MQD_SIZE_ALIGNED
 };
 
+static const struct kfd_device_info carrizo_device_info = {
+	.asic_family = CHIP_CARRIZO,
+	.max_pasid_bits = 16,
+	.ih_ring_entry_size = 4 * sizeof(uint32_t),
+	.num_of_watch_points = 4,
+	.mqd_size_aligned = MQD_SIZE_ALIGNED
+};
+
 struct kfd_deviceid {
 	unsigned short did;
 	const struct kfd_device_info *device_info;
@@ -64,9 +73,13 @@
 	{ 0x1318, &kaveri_device_info },	/* Kaveri */
 	{ 0x131B, &kaveri_device_info },	/* Kaveri */
 	{ 0x131C, &kaveri_device_info },	/* Kaveri */
-	{ 0x131D, &kaveri_device_info },	/* Kaveri */
+	{ 0x131D, &kaveri_device_info }		/* Kaveri */
 };
 
+static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
+				unsigned int chunk_size);
+static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
+
 static const struct kfd_device_info *lookup_device_info(unsigned short did)
 {
 	size_t i;
@@ -173,16 +186,39 @@
 	size = max_num_of_queues_per_device *
 			kfd->device_info->mqd_size_aligned;
 
-	/* add another 512KB for all other allocations on gart */
+	/*
+	 * calculate max size of runlist packet.
+	 * There can be only 2 packets at once
+	 */
+	size += (KFD_MAX_NUM_OF_PROCESSES * sizeof(struct pm4_map_process) +
+		max_num_of_queues_per_device *
+		sizeof(struct pm4_map_queues) + sizeof(struct pm4_runlist)) * 2;
+
+	/* Add size of HIQ & DIQ */
+	size += KFD_KERNEL_QUEUE_SIZE * 2;
+
+	/* add another 512KB for all other allocations on gart (HPD, fences) */
 	size += 512 * 1024;
 
-	if (kfd2kgd->init_sa_manager(kfd->kgd, size)) {
+	if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
+			&kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
 		dev_err(kfd_device,
-			"Error initializing sa manager for device (%x:%x)\n",
-			kfd->pdev->vendor, kfd->pdev->device);
+			"Could not allocate %d bytes for device (%x:%x)\n",
+			size, kfd->pdev->vendor, kfd->pdev->device);
 		goto out;
 	}
 
+	dev_info(kfd_device,
+		"Allocated %d bytes on gart for device(%x:%x)\n",
+		size, kfd->pdev->vendor, kfd->pdev->device);
+
+	/* Initialize GTT sa with 512 byte chunk size */
+	if (kfd_gtt_sa_init(kfd, size, 512) != 0) {
+		dev_err(kfd_device,
+			"Error initializing gtt sub-allocator\n");
+		goto kfd_gtt_sa_init_error;
+	}
+
 	kfd_doorbell_init(kfd);
 
 	if (kfd_topology_add_device(kfd) != 0) {
@@ -209,7 +245,7 @@
 		goto device_queue_manager_error;
 	}
 
-	if (kfd->dqm->start(kfd->dqm) != 0) {
+	if (kfd->dqm->ops.start(kfd->dqm) != 0) {
 		dev_err(kfd_device,
 			"Error starting queuen manager for device (%x:%x)\n",
 			kfd->pdev->vendor, kfd->pdev->device);
@@ -232,7 +268,9 @@
 device_iommu_pasid_error:
 	kfd_topology_remove_device(kfd);
 kfd_topology_add_device_error:
-	kfd2kgd->fini_sa_manager(kfd->kgd);
+	kfd_gtt_sa_fini(kfd);
+kfd_gtt_sa_init_error:
+	kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
 	dev_err(kfd_device,
 		"device (%x:%x) NOT added due to errors\n",
 		kfd->pdev->vendor, kfd->pdev->device);
@@ -246,6 +284,8 @@
 		device_queue_manager_uninit(kfd->dqm);
 		amd_iommu_free_device(kfd->pdev);
 		kfd_topology_remove_device(kfd);
+		kfd_gtt_sa_fini(kfd);
+		kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
 	}
 
 	kfree(kfd);
@@ -256,7 +296,7 @@
 	BUG_ON(kfd == NULL);
 
 	if (kfd->init_complete) {
-		kfd->dqm->stop(kfd->dqm);
+		kfd->dqm->ops.stop(kfd->dqm);
 		amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
 		amd_iommu_free_device(kfd->pdev);
 	}
@@ -277,7 +317,7 @@
 			return -ENXIO;
 		amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
 						iommu_pasid_shutdown_callback);
-		kfd->dqm->start(kfd->dqm);
+		kfd->dqm->ops.start(kfd->dqm);
 	}
 
 	return 0;
@@ -288,3 +328,188 @@
 {
 	/* Process interrupts / schedule work as necessary */
 }
+
+static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
+				unsigned int chunk_size)
+{
+	unsigned int num_of_bits;
+
+	BUG_ON(!kfd);
+	BUG_ON(!kfd->gtt_mem);
+	BUG_ON(buf_size < chunk_size);
+	BUG_ON(buf_size == 0);
+	BUG_ON(chunk_size == 0);
+
+	kfd->gtt_sa_chunk_size = chunk_size;
+	kfd->gtt_sa_num_of_chunks = buf_size / chunk_size;
+
+	num_of_bits = kfd->gtt_sa_num_of_chunks / BITS_PER_BYTE;
+	BUG_ON(num_of_bits == 0);
+
+	kfd->gtt_sa_bitmap = kzalloc(num_of_bits, GFP_KERNEL);
+
+	if (!kfd->gtt_sa_bitmap)
+		return -ENOMEM;
+
+	pr_debug("kfd: gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p\n",
+			kfd->gtt_sa_num_of_chunks, kfd->gtt_sa_bitmap);
+
+	mutex_init(&kfd->gtt_sa_lock);
+
+	return 0;
+
+}
+
+static void kfd_gtt_sa_fini(struct kfd_dev *kfd)
+{
+	mutex_destroy(&kfd->gtt_sa_lock);
+	kfree(kfd->gtt_sa_bitmap);
+}
+
+static inline uint64_t kfd_gtt_sa_calc_gpu_addr(uint64_t start_addr,
+						unsigned int bit_num,
+						unsigned int chunk_size)
+{
+	return start_addr + bit_num * chunk_size;
+}
+
+static inline uint32_t *kfd_gtt_sa_calc_cpu_addr(void *start_addr,
+						unsigned int bit_num,
+						unsigned int chunk_size)
+{
+	return (uint32_t *) ((uint64_t) start_addr + bit_num * chunk_size);
+}
+
+int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
+			struct kfd_mem_obj **mem_obj)
+{
+	unsigned int found, start_search, cur_size;
+
+	BUG_ON(!kfd);
+
+	if (size == 0)
+		return -EINVAL;
+
+	if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size)
+		return -ENOMEM;
+
+	*mem_obj = kmalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
+	if ((*mem_obj) == NULL)
+		return -ENOMEM;
+
+	pr_debug("kfd: allocated mem_obj = %p for size = %d\n", *mem_obj, size);
+
+	start_search = 0;
+
+	mutex_lock(&kfd->gtt_sa_lock);
+
+kfd_gtt_restart_search:
+	/* Find the first chunk that is free */
+	found = find_next_zero_bit(kfd->gtt_sa_bitmap,
+					kfd->gtt_sa_num_of_chunks,
+					start_search);
+
+	pr_debug("kfd: found = %d\n", found);
+
+	/* If there wasn't any free chunk, bail out */
+	if (found == kfd->gtt_sa_num_of_chunks)
+		goto kfd_gtt_no_free_chunk;
+
+	/* Update fields of mem_obj */
+	(*mem_obj)->range_start = found;
+	(*mem_obj)->range_end = found;
+	(*mem_obj)->gpu_addr = kfd_gtt_sa_calc_gpu_addr(
+					kfd->gtt_start_gpu_addr,
+					found,
+					kfd->gtt_sa_chunk_size);
+	(*mem_obj)->cpu_ptr = kfd_gtt_sa_calc_cpu_addr(
+					kfd->gtt_start_cpu_ptr,
+					found,
+					kfd->gtt_sa_chunk_size);
+
+	pr_debug("kfd: gpu_addr = %p, cpu_addr = %p\n",
+			(uint64_t *) (*mem_obj)->gpu_addr, (*mem_obj)->cpu_ptr);
+
+	/* If we need only one chunk, mark it as allocated and get out */
+	if (size <= kfd->gtt_sa_chunk_size) {
+		pr_debug("kfd: single bit\n");
+		set_bit(found, kfd->gtt_sa_bitmap);
+		goto kfd_gtt_out;
+	}
+
+	/* Otherwise, try to see if we have enough contiguous chunks */
+	cur_size = size - kfd->gtt_sa_chunk_size;
+	do {
+		(*mem_obj)->range_end =
+			find_next_zero_bit(kfd->gtt_sa_bitmap,
+					kfd->gtt_sa_num_of_chunks, ++found);
+		/*
+		 * If next free chunk is not contiguous than we need to
+		 * restart our search from the last free chunk we found (which
+		 * wasn't contiguous to the previous ones
+		 */
+		if ((*mem_obj)->range_end != found) {
+			start_search = found;
+			goto kfd_gtt_restart_search;
+		}
+
+		/*
+		 * If we reached end of buffer, bail out with error
+		 */
+		if (found == kfd->gtt_sa_num_of_chunks)
+			goto kfd_gtt_no_free_chunk;
+
+		/* Check if we don't need another chunk */
+		if (cur_size <= kfd->gtt_sa_chunk_size)
+			cur_size = 0;
+		else
+			cur_size -= kfd->gtt_sa_chunk_size;
+
+	} while (cur_size > 0);
+
+	pr_debug("kfd: range_start = %d, range_end = %d\n",
+		(*mem_obj)->range_start, (*mem_obj)->range_end);
+
+	/* Mark the chunks as allocated */
+	for (found = (*mem_obj)->range_start;
+		found <= (*mem_obj)->range_end;
+		found++)
+		set_bit(found, kfd->gtt_sa_bitmap);
+
+kfd_gtt_out:
+	mutex_unlock(&kfd->gtt_sa_lock);
+	return 0;
+
+kfd_gtt_no_free_chunk:
+	pr_debug("kfd: allocation failed with mem_obj = %p\n", mem_obj);
+	mutex_unlock(&kfd->gtt_sa_lock);
+	kfree(mem_obj);
+	return -ENOMEM;
+}
+
+int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj)
+{
+	unsigned int bit;
+
+	BUG_ON(!kfd);
+
+	/* Act like kfree when trying to free a NULL object */
+	if (!mem_obj)
+		return 0;
+
+	pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n",
+			mem_obj, mem_obj->range_start, mem_obj->range_end);
+
+	mutex_lock(&kfd->gtt_sa_lock);
+
+	/* Mark the chunks as free */
+	for (bit = mem_obj->range_start;
+		bit <= mem_obj->range_end;
+		bit++)
+		clear_bit(bit, kfd->gtt_sa_bitmap);
+
+	mutex_unlock(&kfd->gtt_sa_lock);
+
+	kfree(mem_obj);
+	return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 0fd59279..b3589d0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -26,34 +26,40 @@
 #include <linux/types.h>
 #include <linux/printk.h>
 #include <linux/bitops.h>
+#include <linux/sched.h>
 #include "kfd_priv.h"
 #include "kfd_device_queue_manager.h"
 #include "kfd_mqd_manager.h"
 #include "cik_regs.h"
 #include "kfd_kernel_queue.h"
-#include "../../radeon/cik_reg.h"
 
 /* Size of the per-pipe EOP queue */
 #define CIK_HPD_EOP_BYTES_LOG2 11
 #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
 
-static bool is_mem_initialized;
-
-static int init_memory(struct device_queue_manager *dqm);
 static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
 					unsigned int pasid, unsigned int vmid);
 
 static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
 					struct queue *q,
 					struct qcm_process_device *qpd);
+
 static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock);
 static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock);
 
+static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
+					struct queue *q,
+					struct qcm_process_device *qpd);
 
-static inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
+static void deallocate_sdma_queue(struct device_queue_manager *dqm,
+				unsigned int sdma_queue_id);
+
+static inline
+enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
 {
-	BUG_ON(!dqm || !dqm->dev);
-	return dqm->dev->shared_resources.compute_pipe_count;
+	if (type == KFD_QUEUE_TYPE_SDMA)
+		return KFD_MQD_TYPE_SDMA;
+	return KFD_MQD_TYPE_CP;
 }
 
 static inline unsigned int get_first_pipe(struct device_queue_manager *dqm)
@@ -67,61 +73,7 @@
 	return PIPE_PER_ME_CP_SCHEDULING;
 }
 
-static inline unsigned int
-get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
-{
-	uint32_t nybble;
-
-	nybble = (pdd->lds_base >> 60) & 0x0E;
-
-	return nybble;
-
-}
-
-static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
-{
-	unsigned int shared_base;
-
-	shared_base = (pdd->lds_base >> 16) & 0xFF;
-
-	return shared_base;
-}
-
-static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble);
-static void init_process_memory(struct device_queue_manager *dqm,
-				struct qcm_process_device *qpd)
-{
-	struct kfd_process_device *pdd;
-	unsigned int temp;
-
-	BUG_ON(!dqm || !qpd);
-
-	pdd = qpd_to_pdd(qpd);
-
-	/* check if sh_mem_config register already configured */
-	if (qpd->sh_mem_config == 0) {
-		qpd->sh_mem_config =
-			ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
-			DEFAULT_MTYPE(MTYPE_NONCACHED) |
-			APE1_MTYPE(MTYPE_NONCACHED);
-		qpd->sh_mem_ape1_limit = 0;
-		qpd->sh_mem_ape1_base = 0;
-	}
-
-	if (qpd->pqm->process->is_32bit_user_mode) {
-		temp = get_sh_mem_bases_32(pdd);
-		qpd->sh_mem_bases = SHARED_BASE(temp);
-		qpd->sh_mem_config |= PTR32;
-	} else {
-		temp = get_sh_mem_bases_nybble_64(pdd);
-		qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
-	}
-
-	pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
-		qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
-}
-
-static void program_sh_mem_settings(struct device_queue_manager *dqm,
+void program_sh_mem_settings(struct device_queue_manager *dqm,
 					struct qcm_process_device *qpd)
 {
 	return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
@@ -200,7 +152,10 @@
 	*allocated_vmid = qpd->vmid;
 	q->properties.vmid = qpd->vmid;
 
-	retval = create_compute_queue_nocpsch(dqm, q, qpd);
+	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
+		retval = create_compute_queue_nocpsch(dqm, q, qpd);
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+		retval = create_sdma_queue_nocpsch(dqm, q, qpd);
 
 	if (retval != 0) {
 		if (list_empty(&qpd->queues_list)) {
@@ -212,7 +167,11 @@
 	}
 
 	list_add(&q->list, &qpd->queues_list);
-	dqm->queue_count++;
+	if (q->properties.is_active)
+		dqm->queue_count++;
+
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+		dqm->sdma_queue_count++;
 
 	/*
 	 * Unconditionally increment this counter, regardless of the queue's
@@ -229,12 +188,12 @@
 static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
 {
 	bool set;
-	int pipe, bit;
+	int pipe, bit, i;
 
 	set = false;
 
-	for (pipe = dqm->next_pipe_to_allocate; pipe < get_pipes_num(dqm);
-			pipe = (pipe + 1) % get_pipes_num(dqm)) {
+	for (pipe = dqm->next_pipe_to_allocate, i = 0; i < get_pipes_num(dqm);
+			pipe = ((pipe + 1) % get_pipes_num(dqm)), ++i) {
 		if (dqm->allocated_queues[pipe] != 0) {
 			bit = find_first_bit(
 				(unsigned long *)&dqm->allocated_queues[pipe],
@@ -275,7 +234,7 @@
 
 	BUG_ON(!dqm || !q || !qpd);
 
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+	mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
 	if (mqd == NULL)
 		return -ENOMEM;
 
@@ -319,28 +278,44 @@
 	pr_debug("kfd: In Func %s\n", __func__);
 
 	mutex_lock(&dqm->lock);
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
-	if (mqd == NULL) {
-		retval = -ENOMEM;
+
+	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
+		mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
+		if (mqd == NULL) {
+			retval = -ENOMEM;
+			goto out;
+		}
+		deallocate_hqd(dqm, q);
+	} else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
+		mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
+		if (mqd == NULL) {
+			retval = -ENOMEM;
+			goto out;
+		}
+		dqm->sdma_queue_count--;
+		deallocate_sdma_queue(dqm, q->sdma_id);
+	} else {
+		pr_debug("q->properties.type is invalid (%d)\n",
+				q->properties.type);
+		retval = -EINVAL;
 		goto out;
 	}
 
 	retval = mqd->destroy_mqd(mqd, q->mqd,
-				KFD_PREEMPT_TYPE_WAVEFRONT,
+				KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
 				QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
 				q->pipe, q->queue);
 
 	if (retval != 0)
 		goto out;
 
-	deallocate_hqd(dqm, q);
-
 	mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
 
 	list_del(&q->list);
 	if (list_empty(&qpd->queues_list))
 		deallocate_vmid(dqm, qpd, q);
-	dqm->queue_count--;
+	if (q->properties.is_active)
+		dqm->queue_count--;
 
 	/*
 	 * Unconditionally decrement this counter, regardless of the queue's
@@ -364,7 +339,8 @@
 	BUG_ON(!dqm || !q || !q->mqd);
 
 	mutex_lock(&dqm->lock);
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+	mqd = dqm->ops.get_mqd_manager(dqm,
+			get_mqd_type_from_queue_type(q->properties.type));
 	if (mqd == NULL) {
 		mutex_unlock(&dqm->lock);
 		return -ENOMEM;
@@ -415,6 +391,7 @@
 					struct qcm_process_device *qpd)
 {
 	struct device_process_node *n;
+	int retval;
 
 	BUG_ON(!dqm || !qpd);
 
@@ -429,12 +406,13 @@
 	mutex_lock(&dqm->lock);
 	list_add(&n->list, &dqm->queues);
 
-	init_process_memory(dqm, qpd);
+	retval = dqm->ops_asic_specific.register_process(dqm, qpd);
+
 	dqm->processes_count++;
 
 	mutex_unlock(&dqm->lock);
 
-	return 0;
+	return retval;
 }
 
 static int unregister_process_nocpsch(struct device_queue_manager *dqm,
@@ -479,48 +457,7 @@
 						vmid);
 }
 
-static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
-{
-	/* In 64-bit mode, we can only control the top 3 bits of the LDS,
-	 * scratch and GPUVM apertures.
-	 * The hardware fills in the remaining 59 bits according to the
-	 * following pattern:
-	 * LDS:		X0000000'00000000 - X0000001'00000000 (4GB)
-	 * Scratch:	X0000001'00000000 - X0000002'00000000 (4GB)
-	 * GPUVM:	Y0010000'00000000 - Y0020000'00000000 (1TB)
-	 *
-	 * (where X/Y is the configurable nybble with the low-bit 0)
-	 *
-	 * LDS and scratch will have the same top nybble programmed in the
-	 * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
-	 * GPUVM can have a different top nybble programmed in the
-	 * top 3 bits of SH_MEM_BASES.SHARED_BASE.
-	 * We don't bother to support different top nybbles
-	 * for LDS/Scratch and GPUVM.
-	 */
-
-	BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
-		top_address_nybble == 0);
-
-	return PRIVATE_BASE(top_address_nybble << 12) |
-			SHARED_BASE(top_address_nybble << 12);
-}
-
-static int init_memory(struct device_queue_manager *dqm)
-{
-	int i, retval;
-
-	for (i = 8; i < 16; i++)
-		set_pasid_vmid_mapping(dqm, 0, i);
-
-	retval = kfd2kgd->init_memory(dqm->dev->kgd);
-	if (retval == 0)
-		is_mem_initialized = true;
-	return retval;
-}
-
-
-static int init_pipelines(struct device_queue_manager *dqm,
+int init_pipelines(struct device_queue_manager *dqm,
 			unsigned int pipes_num, unsigned int first_pipe)
 {
 	void *hpdptr;
@@ -539,11 +476,8 @@
 	 * because it contains no data when there are no active queues.
 	 */
 
-	err = kfd2kgd->allocate_mem(dqm->dev->kgd,
-				CIK_HPD_EOP_BYTES * pipes_num,
-				PAGE_SIZE,
-				KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-				(struct kgd_mem **) &dqm->pipeline_mem);
+	err = kfd_gtt_sa_allocate(dqm->dev, CIK_HPD_EOP_BYTES * pipes_num,
+					&dqm->pipeline_mem);
 
 	if (err) {
 		pr_err("kfd: error allocate vidmem num pipes: %d\n",
@@ -556,10 +490,9 @@
 
 	memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num);
 
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+	mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
 	if (mqd == NULL) {
-		kfd2kgd->free_mem(dqm->dev->kgd,
-				(struct kgd_mem *) dqm->pipeline_mem);
+		kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
 		return -ENOMEM;
 	}
 
@@ -579,7 +512,6 @@
 	return 0;
 }
 
-
 static int init_scheduler(struct device_queue_manager *dqm)
 {
 	int retval;
@@ -589,11 +521,6 @@
 	pr_debug("kfd: In %s\n", __func__);
 
 	retval = init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
-	if (retval != 0)
-		return retval;
-
-	retval = init_memory(dqm);
-
 	return retval;
 }
 
@@ -609,6 +536,7 @@
 	mutex_init(&dqm->lock);
 	INIT_LIST_HEAD(&dqm->queues);
 	dqm->queue_count = dqm->next_pipe_to_allocate = 0;
+	dqm->sdma_queue_count = 0;
 	dqm->allocated_queues = kcalloc(get_pipes_num(dqm),
 					sizeof(unsigned int), GFP_KERNEL);
 	if (!dqm->allocated_queues) {
@@ -620,6 +548,7 @@
 		dqm->allocated_queues[i] = (1 << QUEUES_PER_PIPE) - 1;
 
 	dqm->vmid_bitmap = (1 << VMID_PER_DEVICE) - 1;
+	dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1;
 
 	init_scheduler(dqm);
 	return 0;
@@ -637,8 +566,7 @@
 	for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
 		kfree(dqm->mqds[i]);
 	mutex_destroy(&dqm->lock);
-	kfd2kgd->free_mem(dqm->dev->kgd,
-			(struct kgd_mem *) dqm->pipeline_mem);
+	kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
 }
 
 static int start_nocpsch(struct device_queue_manager *dqm)
@@ -651,6 +579,77 @@
 	return 0;
 }
 
+static int allocate_sdma_queue(struct device_queue_manager *dqm,
+				unsigned int *sdma_queue_id)
+{
+	int bit;
+
+	if (dqm->sdma_bitmap == 0)
+		return -ENOMEM;
+
+	bit = find_first_bit((unsigned long *)&dqm->sdma_bitmap,
+				CIK_SDMA_QUEUES);
+
+	clear_bit(bit, (unsigned long *)&dqm->sdma_bitmap);
+	*sdma_queue_id = bit;
+
+	return 0;
+}
+
+static void deallocate_sdma_queue(struct device_queue_manager *dqm,
+				unsigned int sdma_queue_id)
+{
+	if (sdma_queue_id >= CIK_SDMA_QUEUES)
+		return;
+	set_bit(sdma_queue_id, (unsigned long *)&dqm->sdma_bitmap);
+}
+
+static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q,
+				struct qcm_process_device *qpd)
+{
+	uint32_t value = SDMA_ATC;
+
+	if (q->process->is_32bit_user_mode)
+		value |= SDMA_VA_PTR32 | get_sh_mem_bases_32(qpd_to_pdd(qpd));
+	else
+		value |= SDMA_VA_SHARED_BASE(get_sh_mem_bases_nybble_64(
+							qpd_to_pdd(qpd)));
+	q->properties.sdma_vm_addr = value;
+}
+
+static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
+					struct queue *q,
+					struct qcm_process_device *qpd)
+{
+	struct mqd_manager *mqd;
+	int retval;
+
+	mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
+	if (!mqd)
+		return -ENOMEM;
+
+	retval = allocate_sdma_queue(dqm, &q->sdma_id);
+	if (retval != 0)
+		return retval;
+
+	q->properties.sdma_queue_id = q->sdma_id % CIK_SDMA_QUEUES_PER_ENGINE;
+	q->properties.sdma_engine_id = q->sdma_id / CIK_SDMA_ENGINE_NUM;
+
+	pr_debug("kfd: sdma id is:    %d\n", q->sdma_id);
+	pr_debug("     sdma queue id: %d\n", q->properties.sdma_queue_id);
+	pr_debug("     sdma engine id: %d\n", q->properties.sdma_engine_id);
+
+	retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
+				&q->gart_mqd_addr, &q->properties);
+	if (retval != 0) {
+		deallocate_sdma_queue(dqm, q->sdma_id);
+		return retval;
+	}
+
+	init_sdma_vm(dqm, q, qpd);
+	return 0;
+}
+
 /*
  * Device Queue Manager implementation for cp scheduler
  */
@@ -692,8 +691,9 @@
 	mutex_init(&dqm->lock);
 	INIT_LIST_HEAD(&dqm->queues);
 	dqm->queue_count = dqm->processes_count = 0;
+	dqm->sdma_queue_count = 0;
 	dqm->active_runlist = false;
-	retval = init_pipelines(dqm, get_pipes_num(dqm), 0);
+	retval = dqm->ops_asic_specific.initialize(dqm);
 	if (retval != 0)
 		goto fail_init_pipelines;
 
@@ -724,18 +724,14 @@
 	pr_debug("kfd: allocating fence memory\n");
 
 	/* allocate fence memory on the gart */
-	retval = kfd2kgd->allocate_mem(dqm->dev->kgd,
-					sizeof(*dqm->fence_addr),
-					32,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &dqm->fence_mem);
+	retval = kfd_gtt_sa_allocate(dqm->dev, sizeof(*dqm->fence_addr),
+					&dqm->fence_mem);
 
 	if (retval != 0)
 		goto fail_allocate_vidmem;
 
 	dqm->fence_addr = dqm->fence_mem->cpu_ptr;
 	dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
-
 	list_for_each_entry(node, &dqm->queues, list)
 		if (node->qpd->pqm->process && dqm->dev)
 			kfd_bind_process_to_device(dqm->dev,
@@ -764,8 +760,7 @@
 		pdd = qpd_to_pdd(node->qpd);
 		pdd->bound = false;
 	}
-	kfd2kgd->free_mem(dqm->dev->kgd,
-			(struct kgd_mem *) dqm->fence_mem);
+	kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
 	pm_uninit(&dqm->packets);
 
 	return 0;
@@ -828,6 +823,14 @@
 	mutex_unlock(&dqm->lock);
 }
 
+static void select_sdma_engine_id(struct queue *q)
+{
+	static int sdma_id;
+
+	q->sdma_id = sdma_id;
+	sdma_id = (sdma_id + 1) % 2;
+}
+
 static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
 			struct qcm_process_device *qpd, int *allocate_vmid)
 {
@@ -850,7 +853,12 @@
 		goto out;
 	}
 
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+		select_sdma_engine_id(q);
+
+	mqd = dqm->ops.get_mqd_manager(dqm,
+			get_mqd_type_from_queue_type(q->properties.type));
+
 	if (mqd == NULL) {
 		mutex_unlock(&dqm->lock);
 		return -ENOMEM;
@@ -867,6 +875,8 @@
 		retval = execute_queues_cpsch(dqm, false);
 	}
 
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+			dqm->sdma_queue_count++;
 	/*
 	 * Unconditionally increment this counter, regardless of the queue's
 	 * type or whether the queue is active.
@@ -893,12 +903,20 @@
 			pr_err("kfd: qcm fence wait loop timeout expired\n");
 			return -ETIME;
 		}
-		cpu_relax();
+		schedule();
 	}
 
 	return 0;
 }
 
+static int destroy_sdma_queues(struct device_queue_manager *dqm,
+				unsigned int sdma_engine)
+{
+	return pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_SDMA,
+			KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false,
+			sdma_engine);
+}
+
 static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
 {
 	int retval;
@@ -911,6 +929,15 @@
 		mutex_lock(&dqm->lock);
 	if (dqm->active_runlist == false)
 		goto out;
+
+	pr_debug("kfd: Before destroying queues, sdma queue count is : %u\n",
+		dqm->sdma_queue_count);
+
+	if (dqm->sdma_queue_count > 0) {
+		destroy_sdma_queues(dqm, 0);
+		destroy_sdma_queues(dqm, 1);
+	}
+
 	retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_COMPUTE,
 			KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false, 0);
 	if (retval != 0)
@@ -982,15 +1009,19 @@
 
 	/* remove queue from list to prevent rescheduling after preemption */
 	mutex_lock(&dqm->lock);
-
-	mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+	mqd = dqm->ops.get_mqd_manager(dqm,
+			get_mqd_type_from_queue_type(q->properties.type));
 	if (!mqd) {
 		retval = -ENOMEM;
 		goto failed;
 	}
 
+	if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+		dqm->sdma_queue_count--;
+
 	list_del(&q->list);
-	dqm->queue_count--;
+	if (q->properties.is_active)
+		dqm->queue_count--;
 
 	execute_queues_cpsch(dqm, false);
 
@@ -1028,8 +1059,7 @@
 				   void __user *alternate_aperture_base,
 				   uint64_t alternate_aperture_size)
 {
-	uint32_t default_mtype;
-	uint32_t ape1_mtype;
+	bool retval;
 
 	pr_debug("kfd: In func %s\n", __func__);
 
@@ -1066,18 +1096,13 @@
 		qpd->sh_mem_ape1_limit = limit >> 16;
 	}
 
-	default_mtype = (default_policy == cache_policy_coherent) ?
-			MTYPE_NONCACHED :
-			MTYPE_CACHED;
-
-	ape1_mtype = (alternate_policy == cache_policy_coherent) ?
-			MTYPE_NONCACHED :
-			MTYPE_CACHED;
-
-	qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
-			| ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
-			| DEFAULT_MTYPE(default_mtype)
-			| APE1_MTYPE(ape1_mtype);
+	retval = dqm->ops_asic_specific.set_cache_memory_policy(
+			dqm,
+			qpd,
+			default_policy,
+			alternate_policy,
+			alternate_aperture_base,
+			alternate_aperture_size);
 
 	if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
 		program_sh_mem_settings(dqm, qpd);
@@ -1087,7 +1112,7 @@
 		qpd->sh_mem_ape1_limit);
 
 	mutex_unlock(&dqm->lock);
-	return true;
+	return retval;
 
 out:
 	mutex_unlock(&dqm->lock);
@@ -1100,6 +1125,8 @@
 
 	BUG_ON(!dev);
 
+	pr_debug("kfd: loading device queue manager\n");
+
 	dqm = kzalloc(sizeof(struct device_queue_manager), GFP_KERNEL);
 	if (!dqm)
 		return NULL;
@@ -1109,40 +1136,50 @@
 	case KFD_SCHED_POLICY_HWS:
 	case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
 		/* initialize dqm for cp scheduling */
-		dqm->create_queue = create_queue_cpsch;
-		dqm->initialize = initialize_cpsch;
-		dqm->start = start_cpsch;
-		dqm->stop = stop_cpsch;
-		dqm->destroy_queue = destroy_queue_cpsch;
-		dqm->update_queue = update_queue;
-		dqm->get_mqd_manager = get_mqd_manager_nocpsch;
-		dqm->register_process = register_process_nocpsch;
-		dqm->unregister_process = unregister_process_nocpsch;
-		dqm->uninitialize = uninitialize_nocpsch;
-		dqm->create_kernel_queue = create_kernel_queue_cpsch;
-		dqm->destroy_kernel_queue = destroy_kernel_queue_cpsch;
-		dqm->set_cache_memory_policy = set_cache_memory_policy;
+		dqm->ops.create_queue = create_queue_cpsch;
+		dqm->ops.initialize = initialize_cpsch;
+		dqm->ops.start = start_cpsch;
+		dqm->ops.stop = stop_cpsch;
+		dqm->ops.destroy_queue = destroy_queue_cpsch;
+		dqm->ops.update_queue = update_queue;
+		dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
+		dqm->ops.register_process = register_process_nocpsch;
+		dqm->ops.unregister_process = unregister_process_nocpsch;
+		dqm->ops.uninitialize = uninitialize_nocpsch;
+		dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
+		dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
+		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
 		break;
 	case KFD_SCHED_POLICY_NO_HWS:
 		/* initialize dqm for no cp scheduling */
-		dqm->start = start_nocpsch;
-		dqm->stop = stop_nocpsch;
-		dqm->create_queue = create_queue_nocpsch;
-		dqm->destroy_queue = destroy_queue_nocpsch;
-		dqm->update_queue = update_queue;
-		dqm->get_mqd_manager = get_mqd_manager_nocpsch;
-		dqm->register_process = register_process_nocpsch;
-		dqm->unregister_process = unregister_process_nocpsch;
-		dqm->initialize = initialize_nocpsch;
-		dqm->uninitialize = uninitialize_nocpsch;
-		dqm->set_cache_memory_policy = set_cache_memory_policy;
+		dqm->ops.start = start_nocpsch;
+		dqm->ops.stop = stop_nocpsch;
+		dqm->ops.create_queue = create_queue_nocpsch;
+		dqm->ops.destroy_queue = destroy_queue_nocpsch;
+		dqm->ops.update_queue = update_queue;
+		dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
+		dqm->ops.register_process = register_process_nocpsch;
+		dqm->ops.unregister_process = unregister_process_nocpsch;
+		dqm->ops.initialize = initialize_nocpsch;
+		dqm->ops.uninitialize = uninitialize_nocpsch;
+		dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
 		break;
 	default:
 		BUG();
 		break;
 	}
 
-	if (dqm->initialize(dqm) != 0) {
+	switch (dev->device_info->asic_family) {
+	case CHIP_CARRIZO:
+		device_queue_manager_init_vi(&dqm->ops_asic_specific);
+		break;
+
+	case CHIP_KAVERI:
+		device_queue_manager_init_cik(&dqm->ops_asic_specific);
+		break;
+	}
+
+	if (dqm->ops.initialize(dqm) != 0) {
 		kfree(dqm);
 		return NULL;
 	}
@@ -1154,7 +1191,6 @@
 {
 	BUG_ON(!dqm);
 
-	dqm->uninitialize(dqm);
+	dqm->ops.uninitialize(dqm);
 	kfree(dqm);
 }
-
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index 52035bf..d64f86c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -36,6 +36,9 @@
 #define KFD_VMID_START_OFFSET			(8)
 #define VMID_PER_DEVICE				CIK_VMID_NUM
 #define KFD_DQM_FIRST_PIPE			(0)
+#define CIK_SDMA_QUEUES				(4)
+#define CIK_SDMA_QUEUES_PER_ENGINE		(2)
+#define CIK_SDMA_ENGINE_NUM			(2)
 
 struct device_process_node {
 	struct qcm_process_device *qpd;
@@ -43,7 +46,7 @@
 };
 
 /**
- * struct device_queue_manager
+ * struct device_queue_manager_ops
  *
  * @create_queue: Queue creation routine.
  *
@@ -78,15 +81,9 @@
  * @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the
  * memory apertures.
  *
- * This struct is a base class for the kfd queues scheduler in the
- * device level. The device base class should expose the basic operations
- * for queue creation and queue destruction. This base class hides the
- * scheduling mode of the driver and the specific implementation of the
- * concrete device. This class is the only class in the queues scheduler
- * that configures the H/W.
  */
 
-struct device_queue_manager {
+struct device_queue_manager_ops {
 	int	(*create_queue)(struct device_queue_manager *dqm,
 				struct queue *q,
 				struct qcm_process_device *qpd,
@@ -121,7 +118,23 @@
 					   enum cache_policy alternate_policy,
 					   void __user *alternate_aperture_base,
 					   uint64_t alternate_aperture_size);
+};
 
+/**
+ * struct device_queue_manager
+ *
+ * This struct is a base class for the kfd queues scheduler in the
+ * device level. The device base class should expose the basic operations
+ * for queue creation and queue destruction. This base class hides the
+ * scheduling mode of the driver and the specific implementation of the
+ * concrete device. This class is the only class in the queues scheduler
+ * that configures the H/W.
+ *
+ */
+
+struct device_queue_manager {
+	struct device_queue_manager_ops ops;
+	struct device_queue_manager_ops ops_asic_specific;
 
 	struct mqd_manager	*mqds[KFD_MQD_TYPE_MAX];
 	struct packet_manager	packets;
@@ -130,9 +143,11 @@
 	struct list_head	queues;
 	unsigned int		processes_count;
 	unsigned int		queue_count;
+	unsigned int		sdma_queue_count;
 	unsigned int		total_queue_count;
 	unsigned int		next_pipe_to_allocate;
 	unsigned int		*allocated_queues;
+	unsigned int		sdma_bitmap;
 	unsigned int		vmid_bitmap;
 	uint64_t		pipelines_addr;
 	struct kfd_mem_obj	*pipeline_mem;
@@ -142,6 +157,28 @@
 	bool			active_runlist;
 };
 
+void device_queue_manager_init_cik(struct device_queue_manager_ops *ops);
+void device_queue_manager_init_vi(struct device_queue_manager_ops *ops);
+void program_sh_mem_settings(struct device_queue_manager *dqm,
+					struct qcm_process_device *qpd);
+int init_pipelines(struct device_queue_manager *dqm,
+		unsigned int pipes_num, unsigned int first_pipe);
 
+extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
+{
+	return (pdd->lds_base >> 16) & 0xFF;
+}
+
+extern inline unsigned int
+get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
+{
+	return (pdd->lds_base >> 60) & 0x0E;
+}
+
+extern inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
+{
+	BUG_ON(!dqm || !dqm->dev);
+	return dqm->dev->shared_resources.compute_pipe_count;
+}
 
 #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
new file mode 100644
index 0000000..6b07246
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2014 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 "kfd_device_queue_manager.h"
+#include "cik_regs.h"
+
+static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+				   struct qcm_process_device *qpd,
+				   enum cache_policy default_policy,
+				   enum cache_policy alternate_policy,
+				   void __user *alternate_aperture_base,
+				   uint64_t alternate_aperture_size);
+static int register_process_cik(struct device_queue_manager *dqm,
+					struct qcm_process_device *qpd);
+static int initialize_cpsch_cik(struct device_queue_manager *dqm);
+
+void device_queue_manager_init_cik(struct device_queue_manager_ops *ops)
+{
+	ops->set_cache_memory_policy = set_cache_memory_policy_cik;
+	ops->register_process = register_process_cik;
+	ops->initialize = initialize_cpsch_cik;
+}
+
+static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
+{
+	/* In 64-bit mode, we can only control the top 3 bits of the LDS,
+	 * scratch and GPUVM apertures.
+	 * The hardware fills in the remaining 59 bits according to the
+	 * following pattern:
+	 * LDS:		X0000000'00000000 - X0000001'00000000 (4GB)
+	 * Scratch:	X0000001'00000000 - X0000002'00000000 (4GB)
+	 * GPUVM:	Y0010000'00000000 - Y0020000'00000000 (1TB)
+	 *
+	 * (where X/Y is the configurable nybble with the low-bit 0)
+	 *
+	 * LDS and scratch will have the same top nybble programmed in the
+	 * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
+	 * GPUVM can have a different top nybble programmed in the
+	 * top 3 bits of SH_MEM_BASES.SHARED_BASE.
+	 * We don't bother to support different top nybbles
+	 * for LDS/Scratch and GPUVM.
+	 */
+
+	BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
+		top_address_nybble == 0);
+
+	return PRIVATE_BASE(top_address_nybble << 12) |
+			SHARED_BASE(top_address_nybble << 12);
+}
+
+static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+				   struct qcm_process_device *qpd,
+				   enum cache_policy default_policy,
+				   enum cache_policy alternate_policy,
+				   void __user *alternate_aperture_base,
+				   uint64_t alternate_aperture_size)
+{
+	uint32_t default_mtype;
+	uint32_t ape1_mtype;
+
+	default_mtype = (default_policy == cache_policy_coherent) ?
+			MTYPE_NONCACHED :
+			MTYPE_CACHED;
+
+	ape1_mtype = (alternate_policy == cache_policy_coherent) ?
+			MTYPE_NONCACHED :
+			MTYPE_CACHED;
+
+	qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
+			| ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
+			| DEFAULT_MTYPE(default_mtype)
+			| APE1_MTYPE(ape1_mtype);
+
+	return true;
+}
+
+static int register_process_cik(struct device_queue_manager *dqm,
+		struct qcm_process_device *qpd)
+{
+	struct kfd_process_device *pdd;
+	unsigned int temp;
+
+	BUG_ON(!dqm || !qpd);
+
+	pdd = qpd_to_pdd(qpd);
+
+	/* check if sh_mem_config register already configured */
+	if (qpd->sh_mem_config == 0) {
+		qpd->sh_mem_config =
+			ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
+			DEFAULT_MTYPE(MTYPE_NONCACHED) |
+			APE1_MTYPE(MTYPE_NONCACHED);
+		qpd->sh_mem_ape1_limit = 0;
+		qpd->sh_mem_ape1_base = 0;
+	}
+
+	if (qpd->pqm->process->is_32bit_user_mode) {
+		temp = get_sh_mem_bases_32(pdd);
+		qpd->sh_mem_bases = SHARED_BASE(temp);
+		qpd->sh_mem_config |= PTR32;
+	} else {
+		temp = get_sh_mem_bases_nybble_64(pdd);
+		qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
+	}
+
+	pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
+		qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
+
+	return 0;
+}
+
+static int initialize_cpsch_cik(struct device_queue_manager *dqm)
+{
+	return init_pipelines(dqm, get_pipes_num(dqm), 0);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
new file mode 100644
index 0000000..20553dc
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 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 "kfd_device_queue_manager.h"
+
+static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+				   struct qcm_process_device *qpd,
+				   enum cache_policy default_policy,
+				   enum cache_policy alternate_policy,
+				   void __user *alternate_aperture_base,
+				   uint64_t alternate_aperture_size);
+static int register_process_vi(struct device_queue_manager *dqm,
+					struct qcm_process_device *qpd);
+static int initialize_cpsch_vi(struct device_queue_manager *dqm);
+
+void device_queue_manager_init_vi(struct device_queue_manager_ops *ops)
+{
+	pr_warn("amdkfd: VI DQM is not currently supported\n");
+
+	ops->set_cache_memory_policy = set_cache_memory_policy_vi;
+	ops->register_process = register_process_vi;
+	ops->initialize = initialize_cpsch_vi;
+}
+
+static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+				   struct qcm_process_device *qpd,
+				   enum cache_policy default_policy,
+				   enum cache_policy alternate_policy,
+				   void __user *alternate_aperture_base,
+				   uint64_t alternate_aperture_size)
+{
+	return false;
+}
+
+static int register_process_vi(struct device_queue_manager *dqm,
+					struct qcm_process_device *qpd)
+{
+	return -1;
+}
+
+static int initialize_cpsch_vi(struct device_queue_manager *dqm)
+{
+	return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index b5791a5..1a9b355 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -137,10 +137,6 @@
 	if (dev == NULL)
 		return -EINVAL;
 
-	/* Find if pdd exists for combination of process and gpu id */
-	if (!kfd_get_process_device_data(dev, process, 0))
-		return -EINVAL;
-
 	/* Calculate physical address of doorbell */
 	address = kfd_get_process_doorbells(dev, process);
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
index e64aa99..35b9875 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
@@ -303,10 +303,11 @@
 	while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
 		id < NUM_OF_SUPPORTED_GPUS) {
 
-		pdd = kfd_get_process_device_data(dev, process, 1);
-		if (!pdd)
+		pdd = kfd_create_process_device_data(dev, process);
+		if (pdd == NULL) {
+			pr_err("Failed to create process device data\n");
 			return -1;
-
+		}
 		/*
 		 * For 64 bit process aperture will be statically reserved in
 		 * the x86_64 non canonical process address space
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
index 9350714..e415a2a 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
@@ -56,8 +56,8 @@
 	switch (type) {
 	case KFD_QUEUE_TYPE_DIQ:
 	case KFD_QUEUE_TYPE_HIQ:
-		kq->mqd = dev->dqm->get_mqd_manager(dev->dqm,
-						KFD_MQD_TYPE_CIK_HIQ);
+		kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm,
+						KFD_MQD_TYPE_HIQ);
 		break;
 	default:
 		BUG();
@@ -72,23 +72,19 @@
 	if (prop.doorbell_ptr == NULL)
 		goto err_get_kernel_doorbell;
 
-	retval = kfd2kgd->allocate_mem(dev->kgd,
-					queue_size,
-					PAGE_SIZE,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &kq->pq);
-
+	retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
 	if (retval != 0)
 		goto err_pq_allocate_vidmem;
 
 	kq->pq_kernel_addr = kq->pq->cpu_ptr;
 	kq->pq_gpu_addr = kq->pq->gpu_addr;
 
-	retval = kfd2kgd->allocate_mem(dev->kgd,
-					sizeof(*kq->rptr_kernel),
-					32,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &kq->rptr_mem);
+	retval = kq->ops_asic_specific.initialize(kq, dev, type, queue_size);
+	if (retval == false)
+		goto err_eop_allocate_vidmem;
+
+	retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->rptr_kernel),
+					&kq->rptr_mem);
 
 	if (retval != 0)
 		goto err_rptr_allocate_vidmem;
@@ -96,11 +92,8 @@
 	kq->rptr_kernel = kq->rptr_mem->cpu_ptr;
 	kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr;
 
-	retval = kfd2kgd->allocate_mem(dev->kgd,
-					sizeof(*kq->wptr_kernel),
-					32,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &kq->wptr_mem);
+	retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->wptr_kernel),
+					&kq->wptr_mem);
 
 	if (retval != 0)
 		goto err_wptr_allocate_vidmem;
@@ -121,6 +114,8 @@
 	prop.queue_address = kq->pq_gpu_addr;
 	prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr;
 	prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr;
+	prop.eop_ring_buffer_address = kq->eop_gpu_addr;
+	prop.eop_ring_buffer_size = PAGE_SIZE;
 
 	if (init_queue(&kq->queue, prop) != 0)
 		goto err_init_queue;
@@ -145,11 +140,8 @@
 	} else {
 		/* allocate fence for DIQ */
 
-		retval = kfd2kgd->allocate_mem(dev->kgd,
-					sizeof(uint32_t),
-					32,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &kq->fence_mem_obj);
+		retval = kfd_gtt_sa_allocate(dev, sizeof(uint32_t),
+						&kq->fence_mem_obj);
 
 		if (retval != 0)
 			goto err_alloc_fence;
@@ -165,11 +157,13 @@
 err_init_mqd:
 	uninit_queue(kq->queue);
 err_init_queue:
-	kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->wptr_mem);
+	kfd_gtt_sa_free(dev, kq->wptr_mem);
 err_wptr_allocate_vidmem:
-	kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->rptr_mem);
+	kfd_gtt_sa_free(dev, kq->rptr_mem);
 err_rptr_allocate_vidmem:
-	kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->pq);
+	kfd_gtt_sa_free(dev, kq->eop_mem);
+err_eop_allocate_vidmem:
+	kfd_gtt_sa_free(dev, kq->pq);
 err_pq_allocate_vidmem:
 	pr_err("kfd: error init pq\n");
 	kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
@@ -190,10 +184,13 @@
 					QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
 					kq->queue->pipe,
 					kq->queue->queue);
+	else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
+		kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
 
-	kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->rptr_mem);
-	kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->wptr_mem);
-	kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->pq);
+	kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
+	kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
+	kq->ops_asic_specific.uninitialize(kq);
+	kfd_gtt_sa_free(kq->dev, kq->pq);
 	kfd_release_kernel_doorbell(kq->dev,
 					kq->queue->properties.doorbell_ptr);
 	uninit_queue(kq->queue);
@@ -265,28 +262,6 @@
 				kq->pending_wptr);
 }
 
-static int sync_with_hw(struct kernel_queue *kq, unsigned long timeout_ms)
-{
-	unsigned long org_timeout_ms;
-
-	BUG_ON(!kq);
-
-	org_timeout_ms = timeout_ms;
-	timeout_ms += jiffies * 1000 / HZ;
-	while (*kq->wptr_kernel != *kq->rptr_kernel) {
-		if (time_after(jiffies * 1000 / HZ, timeout_ms)) {
-			pr_err("kfd: kernel_queue %s timeout expired %lu\n",
-				__func__, org_timeout_ms);
-			pr_err("kfd: wptr: %d rptr: %d\n",
-				*kq->wptr_kernel, *kq->rptr_kernel);
-			return -ETIME;
-		}
-		schedule();
-	}
-
-	return 0;
-}
-
 static void rollback_packet(struct kernel_queue *kq)
 {
 	BUG_ON(!kq);
@@ -304,14 +279,23 @@
 	if (!kq)
 		return NULL;
 
-	kq->initialize = initialize;
-	kq->uninitialize = uninitialize;
-	kq->acquire_packet_buffer = acquire_packet_buffer;
-	kq->submit_packet = submit_packet;
-	kq->sync_with_hw = sync_with_hw;
-	kq->rollback_packet = rollback_packet;
+	kq->ops.initialize = initialize;
+	kq->ops.uninitialize = uninitialize;
+	kq->ops.acquire_packet_buffer = acquire_packet_buffer;
+	kq->ops.submit_packet = submit_packet;
+	kq->ops.rollback_packet = rollback_packet;
 
-	if (kq->initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
+	switch (dev->device_info->asic_family) {
+	case CHIP_CARRIZO:
+		kernel_queue_init_vi(&kq->ops_asic_specific);
+		break;
+
+	case CHIP_KAVERI:
+		kernel_queue_init_cik(&kq->ops_asic_specific);
+		break;
+	}
+
+	if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
 		pr_err("kfd: failed to init kernel queue\n");
 		kfree(kq);
 		return NULL;
@@ -323,7 +307,7 @@
 {
 	BUG_ON(!kq);
 
-	kq->uninitialize(kq);
+	kq->ops.uninitialize(kq);
 	kfree(kq);
 }
 
@@ -335,19 +319,18 @@
 
 	BUG_ON(!dev);
 
-	pr_debug("kfd: starting kernel queue test\n");
+	pr_err("kfd: starting kernel queue test\n");
 
 	kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
 	BUG_ON(!kq);
 
-	retval = kq->acquire_packet_buffer(kq, 5, &buffer);
+	retval = kq->ops.acquire_packet_buffer(kq, 5, &buffer);
 	BUG_ON(retval != 0);
 	for (i = 0; i < 5; i++)
 		buffer[i] = kq->nop_packet;
-	kq->submit_packet(kq);
-	kq->sync_with_hw(kq, 1000);
+	kq->ops.submit_packet(kq);
 
-	pr_debug("kfd: ending kernel queue test\n");
+	pr_err("kfd: ending kernel queue test\n");
 }
 
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
index dcd2bdb..5940531 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
@@ -28,8 +28,31 @@
 #include <linux/types.h>
 #include "kfd_priv.h"
 
-struct kernel_queue {
-	/* interface */
+/**
+ * struct kernel_queue_ops
+ *
+ * @initialize: Initialize a kernel queue, including allocations of GART memory
+ * needed for the queue.
+ *
+ * @uninitialize: Uninitialize a kernel queue and free all its memory usages.
+ *
+ * @acquire_packet_buffer: Returns a pointer to the location in the kernel
+ * queue ring buffer where the calling function can write its packet. It is
+ * Guaranteed that there is enough space for that packet. It also updates the
+ * pending write pointer to that location so subsequent calls to
+ * acquire_packet_buffer will get a correct write pointer
+ *
+ * @submit_packet: Update the write pointer and doorbell of a kernel queue.
+ *
+ * @sync_with_hw: Wait until the write pointer and the read pointer of a kernel
+ * queue are equal, which means the CP has read all the submitted packets.
+ *
+ * @rollback_packet: This routine is called if we failed to build an acquired
+ * packet for some reason. It just overwrites the pending wptr with the current
+ * one
+ *
+ */
+struct kernel_queue_ops {
 	bool	(*initialize)(struct kernel_queue *kq, struct kfd_dev *dev,
 			enum kfd_queue_type type, unsigned int queue_size);
 	void	(*uninitialize)(struct kernel_queue *kq);
@@ -38,9 +61,12 @@
 					unsigned int **buffer_ptr);
 
 	void	(*submit_packet)(struct kernel_queue *kq);
-	int	(*sync_with_hw)(struct kernel_queue *kq,
-				unsigned long timeout_ms);
 	void	(*rollback_packet)(struct kernel_queue *kq);
+};
+
+struct kernel_queue {
+	struct kernel_queue_ops ops;
+	struct kernel_queue_ops ops_asic_specific;
 
 	/* data */
 	struct kfd_dev		*dev;
@@ -58,6 +84,9 @@
 	struct kfd_mem_obj	*pq;
 	uint64_t		pq_gpu_addr;
 	uint32_t		*pq_kernel_addr;
+	struct kfd_mem_obj	*eop_mem;
+	uint64_t		eop_gpu_addr;
+	uint32_t		*eop_kernel_addr;
 
 	struct kfd_mem_obj	*fence_mem_obj;
 	uint64_t		fence_gpu_addr;
@@ -66,4 +95,7 @@
 	struct list_head	list;
 };
 
+void kernel_queue_init_cik(struct kernel_queue_ops *ops);
+void kernel_queue_init_vi(struct kernel_queue_ops *ops);
+
 #endif /* KFD_KERNEL_QUEUE_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c
new file mode 100644
index 0000000..a90eb44
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 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 "kfd_kernel_queue.h"
+
+static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
+			enum kfd_queue_type type, unsigned int queue_size);
+static void uninitialize_cik(struct kernel_queue *kq);
+
+void kernel_queue_init_cik(struct kernel_queue_ops *ops)
+{
+	ops->initialize = initialize_cik;
+	ops->uninitialize = uninitialize_cik;
+}
+
+static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
+			enum kfd_queue_type type, unsigned int queue_size)
+{
+	return true;
+}
+
+static void uninitialize_cik(struct kernel_queue *kq)
+{
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c
new file mode 100644
index 0000000..f1d4828
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 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 "kfd_kernel_queue.h"
+
+static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
+			enum kfd_queue_type type, unsigned int queue_size);
+static void uninitialize_vi(struct kernel_queue *kq);
+
+void kernel_queue_init_vi(struct kernel_queue_ops *ops)
+{
+	ops->initialize = initialize_vi;
+	ops->uninitialize = uninitialize_vi;
+}
+
+static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
+			enum kfd_queue_type type, unsigned int queue_size)
+{
+	int retval;
+
+	retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem);
+	if (retval != 0)
+		return false;
+
+	kq->eop_gpu_addr = kq->eop_mem->gpu_addr;
+	kq->eop_kernel_addr = kq->eop_mem->cpu_ptr;
+
+	memset(kq->eop_kernel_addr, 0, PAGE_SIZE);
+
+	return true;
+}
+
+static void uninitialize_vi(struct kernel_queue *kq)
+{
+	kfd_gtt_sa_free(kq->dev, kq->eop_mem);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
index 1c385c2..3f34ae1 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
@@ -29,10 +29,10 @@
 #define KFD_DRIVER_AUTHOR	"AMD Inc. and others"
 
 #define KFD_DRIVER_DESC		"Standalone HSA driver for AMD's GPUs"
-#define KFD_DRIVER_DATE		"20141113"
+#define KFD_DRIVER_DATE		"20150122"
 #define KFD_DRIVER_MAJOR	0
 #define KFD_DRIVER_MINOR	7
-#define KFD_DRIVER_PATCHLEVEL	0
+#define KFD_DRIVER_PATCHLEVEL	1
 
 const struct kfd2kgd_calls *kfd2kgd;
 static const struct kgd2kfd_calls kgd2kfd = {
@@ -48,7 +48,7 @@
 int sched_policy = KFD_SCHED_POLICY_HWS;
 module_param(sched_policy, int, 0444);
 MODULE_PARM_DESC(sched_policy,
-	"Kernel cmdline parameter that defines the amdkfd scheduling policy");
+	"Scheduling policy (0 = HWS (Default), 1 = HWS without over-subscription, 2 = Non-HWS (Used for debugging only)");
 
 int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT;
 module_param(max_num_of_queues_per_device, int, 0444);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
index 4c3828c..b1ef136 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
@@ -21,326 +21,17 @@
  *
  */
 
-#include <linux/printk.h>
-#include <linux/slab.h>
 #include "kfd_priv.h"
-#include "kfd_mqd_manager.h"
-#include "cik_regs.h"
-#include "../../radeon/cik_reg.h"
-
-inline void busy_wait(unsigned long ms)
-{
-	while (time_before(jiffies, ms))
-		cpu_relax();
-}
-
-static inline struct cik_mqd *get_mqd(void *mqd)
-{
-	return (struct cik_mqd *)mqd;
-}
-
-static int init_mqd(struct mqd_manager *mm, void **mqd,
-		struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
-		struct queue_properties *q)
-{
-	uint64_t addr;
-	struct cik_mqd *m;
-	int retval;
-
-	BUG_ON(!mm || !q || !mqd);
-
-	pr_debug("kfd: In func %s\n", __func__);
-
-	retval = kfd2kgd->allocate_mem(mm->dev->kgd,
-					sizeof(struct cik_mqd),
-					256,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) mqd_mem_obj);
-
-	if (retval != 0)
-		return -ENOMEM;
-
-	m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
-	addr = (*mqd_mem_obj)->gpu_addr;
-
-	memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
-
-	m->header = 0xC0310800;
-	m->compute_pipelinestat_enable = 1;
-	m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
-
-	/*
-	 * Make sure to use the last queue state saved on mqd when the cp
-	 * reassigns the queue, so when queue is switched on/off (e.g over
-	 * subscription or quantum timeout) the context will be consistent
-	 */
-	m->cp_hqd_persistent_state =
-				DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
-
-	m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
-	m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
-	m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
-
-	m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
-	/* Although WinKFD writes this, I suspect it should not be necessary */
-	m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
-
-	m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
-				QUANTUM_DURATION(10);
-
-	/*
-	 * Pipe Priority
-	 * Identifies the pipe relative priority when this queue is connected
-	 * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
-	 * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
-	 * 0 = CS_LOW (typically below GFX)
-	 * 1 = CS_MEDIUM (typically between HP3D and GFX
-	 * 2 = CS_HIGH (typically above HP3D)
-	 */
-	m->cp_hqd_pipe_priority = 1;
-	m->cp_hqd_queue_priority = 15;
-
-	*mqd = m;
-	if (gart_addr != NULL)
-		*gart_addr = addr;
-	retval = mm->update_mqd(mm, m, q);
-
-	return retval;
-}
-
-static void uninit_mqd(struct mqd_manager *mm, void *mqd,
-			struct kfd_mem_obj *mqd_mem_obj)
-{
-	BUG_ON(!mm || !mqd);
-	kfd2kgd->free_mem(mm->dev->kgd, (struct kgd_mem *) mqd_mem_obj);
-}
-
-static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
-			uint32_t queue_id, uint32_t __user *wptr)
-{
-	return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
-
-}
-
-static int update_mqd(struct mqd_manager *mm, void *mqd,
-			struct queue_properties *q)
-{
-	struct cik_mqd *m;
-
-	BUG_ON(!mm || !q || !mqd);
-
-	pr_debug("kfd: In func %s\n", __func__);
-
-	m = get_mqd(mqd);
-	m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
-				DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
-
-	/*
-	 * Calculating queue size which is log base 2 of actual queue size -1
-	 * dwords and another -1 for ffs
-	 */
-	m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
-								- 1 - 1;
-	m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
-	m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
-	m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
-	m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
-	m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
-					DOORBELL_OFFSET(q->doorbell_off);
-
-	m->cp_hqd_vmid = q->vmid;
-
-	if (q->format == KFD_QUEUE_FORMAT_AQL) {
-		m->cp_hqd_iq_rptr = AQL_ENABLE;
-		m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
-	}
-
-	m->cp_hqd_active = 0;
-	q->is_active = false;
-	if (q->queue_size > 0 &&
-			q->queue_address != 0 &&
-			q->queue_percent > 0) {
-		m->cp_hqd_active = 1;
-		q->is_active = true;
-	}
-
-	return 0;
-}
-
-static int destroy_mqd(struct mqd_manager *mm, void *mqd,
-			enum kfd_preempt_type type,
-			unsigned int timeout, uint32_t pipe_id,
-			uint32_t queue_id)
-{
-	return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
-					pipe_id, queue_id);
-}
-
-static bool is_occupied(struct mqd_manager *mm, void *mqd,
-			uint64_t queue_address,	uint32_t pipe_id,
-			uint32_t queue_id)
-{
-
-	return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
-					pipe_id, queue_id);
-
-}
-
-/*
- * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
- * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
- * queues but with different initial values.
- */
-
-static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
-		struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
-		struct queue_properties *q)
-{
-	uint64_t addr;
-	struct cik_mqd *m;
-	int retval;
-
-	BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
-
-	pr_debug("kfd: In func %s\n", __func__);
-
-	retval = kfd2kgd->allocate_mem(mm->dev->kgd,
-					sizeof(struct cik_mqd),
-					256,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) mqd_mem_obj);
-
-	if (retval != 0)
-		return -ENOMEM;
-
-	m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
-	addr = (*mqd_mem_obj)->gpu_addr;
-
-	memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
-
-	m->header = 0xC0310800;
-	m->compute_pipelinestat_enable = 1;
-	m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
-	m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
-
-	m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
-					PRELOAD_REQ;
-	m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
-				QUANTUM_DURATION(10);
-
-	m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
-	m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
-	m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
-
-	m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
-
-	/*
-	 * Pipe Priority
-	 * Identifies the pipe relative priority when this queue is connected
-	 * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
-	 * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
-	 * 0 = CS_LOW (typically below GFX)
-	 * 1 = CS_MEDIUM (typically between HP3D and GFX
-	 * 2 = CS_HIGH (typically above HP3D)
-	 */
-	m->cp_hqd_pipe_priority = 1;
-	m->cp_hqd_queue_priority = 15;
-
-	*mqd = m;
-	if (gart_addr)
-		*gart_addr = addr;
-	retval = mm->update_mqd(mm, m, q);
-
-	return retval;
-}
-
-static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
-				struct queue_properties *q)
-{
-	struct cik_mqd *m;
-
-	BUG_ON(!mm || !q || !mqd);
-
-	pr_debug("kfd: In func %s\n", __func__);
-
-	m = get_mqd(mqd);
-	m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
-				DEFAULT_MIN_AVAIL_SIZE |
-				PRIV_STATE |
-				KMD_QUEUE;
-
-	/*
-	 * Calculating queue size which is log base 2 of actual queue
-	 * size -1 dwords
-	 */
-	m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
-								- 1 - 1;
-	m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
-	m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
-	m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
-	m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
-	m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
-					DOORBELL_OFFSET(q->doorbell_off);
-
-	m->cp_hqd_vmid = q->vmid;
-
-	m->cp_hqd_active = 0;
-	q->is_active = false;
-	if (q->queue_size > 0 &&
-			q->queue_address != 0 &&
-			q->queue_percent > 0) {
-		m->cp_hqd_active = 1;
-		q->is_active = true;
-	}
-
-	return 0;
-}
 
 struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
 					struct kfd_dev *dev)
 {
-	struct mqd_manager *mqd;
-
-	BUG_ON(!dev);
-	BUG_ON(type >= KFD_MQD_TYPE_MAX);
-
-	pr_debug("kfd: In func %s\n", __func__);
-
-	mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
-	if (!mqd)
-		return NULL;
-
-	mqd->dev = dev;
-
-	switch (type) {
-	case KFD_MQD_TYPE_CIK_CP:
-	case KFD_MQD_TYPE_CIK_COMPUTE:
-		mqd->init_mqd = init_mqd;
-		mqd->uninit_mqd = uninit_mqd;
-		mqd->load_mqd = load_mqd;
-		mqd->update_mqd = update_mqd;
-		mqd->destroy_mqd = destroy_mqd;
-		mqd->is_occupied = is_occupied;
-		break;
-	case KFD_MQD_TYPE_CIK_HIQ:
-		mqd->init_mqd = init_mqd_hiq;
-		mqd->uninit_mqd = uninit_mqd;
-		mqd->load_mqd = load_mqd;
-		mqd->update_mqd = update_mqd_hiq;
-		mqd->destroy_mqd = destroy_mqd;
-		mqd->is_occupied = is_occupied;
-		break;
-	default:
-		kfree(mqd);
-		return NULL;
+	switch (dev->device_info->asic_family) {
+	case CHIP_KAVERI:
+		return mqd_manager_init_cik(type, dev);
+	case CHIP_CARRIZO:
+		return mqd_manager_init_vi(type, dev);
 	}
 
-	return mqd;
+	return NULL;
 }
-
-/* SDMA queues should be implemented here when the cp will supports them */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
new file mode 100644
index 0000000..a09e18a
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2014 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 <linux/printk.h>
+#include <linux/slab.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+#include "cik_regs.h"
+#include "cik_structs.h"
+
+static inline struct cik_mqd *get_mqd(void *mqd)
+{
+	return (struct cik_mqd *)mqd;
+}
+
+static int init_mqd(struct mqd_manager *mm, void **mqd,
+		struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+		struct queue_properties *q)
+{
+	uint64_t addr;
+	struct cik_mqd *m;
+	int retval;
+
+	BUG_ON(!mm || !q || !mqd);
+
+	pr_debug("kfd: In func %s\n", __func__);
+
+	retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
+					mqd_mem_obj);
+
+	if (retval != 0)
+		return -ENOMEM;
+
+	m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+	addr = (*mqd_mem_obj)->gpu_addr;
+
+	memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+	m->header = 0xC0310800;
+	m->compute_pipelinestat_enable = 1;
+	m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+	/*
+	 * Make sure to use the last queue state saved on mqd when the cp
+	 * reassigns the queue, so when queue is switched on/off (e.g over
+	 * subscription or quantum timeout) the context will be consistent
+	 */
+	m->cp_hqd_persistent_state =
+				DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
+
+	m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
+	m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
+	m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
+
+	m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
+	/* Although WinKFD writes this, I suspect it should not be necessary */
+	m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
+
+	m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+				QUANTUM_DURATION(10);
+
+	/*
+	 * Pipe Priority
+	 * Identifies the pipe relative priority when this queue is connected
+	 * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+	 * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+	 * 0 = CS_LOW (typically below GFX)
+	 * 1 = CS_MEDIUM (typically between HP3D and GFX
+	 * 2 = CS_HIGH (typically above HP3D)
+	 */
+	m->cp_hqd_pipe_priority = 1;
+	m->cp_hqd_queue_priority = 15;
+
+	if (q->format == KFD_QUEUE_FORMAT_AQL)
+		m->cp_hqd_iq_rptr = AQL_ENABLE;
+
+	*mqd = m;
+	if (gart_addr != NULL)
+		*gart_addr = addr;
+	retval = mm->update_mqd(mm, m, q);
+
+	return retval;
+}
+
+static int init_mqd_sdma(struct mqd_manager *mm, void **mqd,
+			struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+			struct queue_properties *q)
+{
+	int retval;
+	struct cik_sdma_rlc_registers *m;
+
+	BUG_ON(!mm || !mqd || !mqd_mem_obj);
+
+	retval = kfd_gtt_sa_allocate(mm->dev,
+					sizeof(struct cik_sdma_rlc_registers),
+					mqd_mem_obj);
+
+	if (retval != 0)
+		return -ENOMEM;
+
+	m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr;
+
+	memset(m, 0, sizeof(struct cik_sdma_rlc_registers));
+
+	*mqd = m;
+	if (gart_addr != NULL)
+		*gart_addr = (*mqd_mem_obj)->gpu_addr;
+
+	retval = mm->update_mqd(mm, m, q);
+
+	return retval;
+}
+
+static void uninit_mqd(struct mqd_manager *mm, void *mqd,
+			struct kfd_mem_obj *mqd_mem_obj)
+{
+	BUG_ON(!mm || !mqd);
+	kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+}
+
+static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
+				struct kfd_mem_obj *mqd_mem_obj)
+{
+	BUG_ON(!mm || !mqd);
+	kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+}
+
+static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
+			uint32_t queue_id, uint32_t __user *wptr)
+{
+	return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
+}
+
+static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
+			uint32_t pipe_id, uint32_t queue_id,
+			uint32_t __user *wptr)
+{
+	return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
+}
+
+static int update_mqd(struct mqd_manager *mm, void *mqd,
+			struct queue_properties *q)
+{
+	struct cik_mqd *m;
+
+	BUG_ON(!mm || !q || !mqd);
+
+	pr_debug("kfd: In func %s\n", __func__);
+
+	m = get_mqd(mqd);
+	m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+				DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
+
+	/*
+	 * Calculating queue size which is log base 2 of actual queue size -1
+	 * dwords and another -1 for ffs
+	 */
+	m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+								- 1 - 1;
+	m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+	m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+	m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+	m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+	m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+					DOORBELL_OFFSET(q->doorbell_off);
+
+	m->cp_hqd_vmid = q->vmid;
+
+	if (q->format == KFD_QUEUE_FORMAT_AQL) {
+		m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
+	}
+
+	m->cp_hqd_active = 0;
+	q->is_active = false;
+	if (q->queue_size > 0 &&
+			q->queue_address != 0 &&
+			q->queue_percent > 0) {
+		m->cp_hqd_active = 1;
+		q->is_active = true;
+	}
+
+	return 0;
+}
+
+static int update_mqd_sdma(struct mqd_manager *mm, void *mqd,
+				struct queue_properties *q)
+{
+	struct cik_sdma_rlc_registers *m;
+
+	BUG_ON(!mm || !mqd || !q);
+
+	m = get_sdma_mqd(mqd);
+	m->sdma_rlc_rb_cntl =
+		SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) |
+		SDMA_RB_VMID(q->vmid) |
+		SDMA_RPTR_WRITEBACK_ENABLE |
+		SDMA_RPTR_WRITEBACK_TIMER(6);
+
+	m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8);
+	m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8);
+	m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+	m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+	m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE;
+	m->sdma_rlc_virtual_addr = q->sdma_vm_addr;
+
+	m->sdma_engine_id = q->sdma_engine_id;
+	m->sdma_queue_id = q->sdma_queue_id;
+
+	q->is_active = false;
+	if (q->queue_size > 0 &&
+			q->queue_address != 0 &&
+			q->queue_percent > 0) {
+		m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE;
+		q->is_active = true;
+	}
+
+	return 0;
+}
+
+static int destroy_mqd(struct mqd_manager *mm, void *mqd,
+			enum kfd_preempt_type type,
+			unsigned int timeout, uint32_t pipe_id,
+			uint32_t queue_id)
+{
+	return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+					pipe_id, queue_id);
+}
+
+/*
+ * preempt type here is ignored because there is only one way
+ * to preempt sdma queue
+ */
+static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
+				enum kfd_preempt_type type,
+				unsigned int timeout, uint32_t pipe_id,
+				uint32_t queue_id)
+{
+	return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
+}
+
+static bool is_occupied(struct mqd_manager *mm, void *mqd,
+			uint64_t queue_address,	uint32_t pipe_id,
+			uint32_t queue_id)
+{
+
+	return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
+					pipe_id, queue_id);
+
+}
+
+static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
+			uint64_t queue_address,	uint32_t pipe_id,
+			uint32_t queue_id)
+{
+	return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
+}
+
+/*
+ * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
+ * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
+ * queues but with different initial values.
+ */
+
+static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
+		struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+		struct queue_properties *q)
+{
+	uint64_t addr;
+	struct cik_mqd *m;
+	int retval;
+
+	BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
+
+	pr_debug("kfd: In func %s\n", __func__);
+
+	retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
+					mqd_mem_obj);
+
+	if (retval != 0)
+		return -ENOMEM;
+
+	m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+	addr = (*mqd_mem_obj)->gpu_addr;
+
+	memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+	m->header = 0xC0310800;
+	m->compute_pipelinestat_enable = 1;
+	m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+	m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+	m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
+					PRELOAD_REQ;
+	m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+				QUANTUM_DURATION(10);
+
+	m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
+	m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
+	m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
+
+	m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
+
+	/*
+	 * Pipe Priority
+	 * Identifies the pipe relative priority when this queue is connected
+	 * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+	 * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+	 * 0 = CS_LOW (typically below GFX)
+	 * 1 = CS_MEDIUM (typically between HP3D and GFX
+	 * 2 = CS_HIGH (typically above HP3D)
+	 */
+	m->cp_hqd_pipe_priority = 1;
+	m->cp_hqd_queue_priority = 15;
+
+	*mqd = m;
+	if (gart_addr)
+		*gart_addr = addr;
+	retval = mm->update_mqd(mm, m, q);
+
+	return retval;
+}
+
+static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
+				struct queue_properties *q)
+{
+	struct cik_mqd *m;
+
+	BUG_ON(!mm || !q || !mqd);
+
+	pr_debug("kfd: In func %s\n", __func__);
+
+	m = get_mqd(mqd);
+	m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+				DEFAULT_MIN_AVAIL_SIZE |
+				PRIV_STATE |
+				KMD_QUEUE;
+
+	/*
+	 * Calculating queue size which is log base 2 of actual queue
+	 * size -1 dwords
+	 */
+	m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+								- 1 - 1;
+	m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+	m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+	m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+	m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+	m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+					DOORBELL_OFFSET(q->doorbell_off);
+
+	m->cp_hqd_vmid = q->vmid;
+
+	m->cp_hqd_active = 0;
+	q->is_active = false;
+	if (q->queue_size > 0 &&
+			q->queue_address != 0 &&
+			q->queue_percent > 0) {
+		m->cp_hqd_active = 1;
+		q->is_active = true;
+	}
+
+	return 0;
+}
+
+struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
+{
+	struct cik_sdma_rlc_registers *m;
+
+	BUG_ON(!mqd);
+
+	m = (struct cik_sdma_rlc_registers *)mqd;
+
+	return m;
+}
+
+struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
+		struct kfd_dev *dev)
+{
+	struct mqd_manager *mqd;
+
+	BUG_ON(!dev);
+	BUG_ON(type >= KFD_MQD_TYPE_MAX);
+
+	pr_debug("kfd: In func %s\n", __func__);
+
+	mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
+	if (!mqd)
+		return NULL;
+
+	mqd->dev = dev;
+
+	switch (type) {
+	case KFD_MQD_TYPE_CP:
+	case KFD_MQD_TYPE_COMPUTE:
+		mqd->init_mqd = init_mqd;
+		mqd->uninit_mqd = uninit_mqd;
+		mqd->load_mqd = load_mqd;
+		mqd->update_mqd = update_mqd;
+		mqd->destroy_mqd = destroy_mqd;
+		mqd->is_occupied = is_occupied;
+		break;
+	case KFD_MQD_TYPE_HIQ:
+		mqd->init_mqd = init_mqd_hiq;
+		mqd->uninit_mqd = uninit_mqd;
+		mqd->load_mqd = load_mqd;
+		mqd->update_mqd = update_mqd_hiq;
+		mqd->destroy_mqd = destroy_mqd;
+		mqd->is_occupied = is_occupied;
+		break;
+	case KFD_MQD_TYPE_SDMA:
+		mqd->init_mqd = init_mqd_sdma;
+		mqd->uninit_mqd = uninit_mqd_sdma;
+		mqd->load_mqd = load_mqd_sdma;
+		mqd->update_mqd = update_mqd_sdma;
+		mqd->destroy_mqd = destroy_mqd_sdma;
+		mqd->is_occupied = is_occupied_sdma;
+		break;
+	default:
+		kfree(mqd);
+		return NULL;
+	}
+
+	return mqd;
+}
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
new file mode 100644
index 0000000..b3a7e3b
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 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 <linux/printk.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+
+struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
+					struct kfd_dev *dev)
+{
+	pr_warn("amdkfd: VI MQD is not currently supported\n");
+	return NULL;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
index 5ce9233..e2533d8 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
@@ -97,11 +97,8 @@
 
 	pm_calc_rlib_size(pm, rl_buffer_size, is_over_subscription);
 
-	retval = kfd2kgd->allocate_mem(pm->dqm->dev->kgd,
-					*rl_buffer_size,
-					PAGE_SIZE,
-					KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
-					(struct kgd_mem **) &pm->ib_buffer_obj);
+	retval = kfd_gtt_sa_allocate(pm->dqm->dev, *rl_buffer_size,
+					&pm->ib_buffer_obj);
 
 	if (retval != 0) {
 		pr_err("kfd: failed to allocate runlist IB\n");
@@ -351,7 +348,7 @@
 	pr_debug("kfd: In func %s\n", __func__);
 
 	mutex_lock(&pm->lock);
-	pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+	pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
 					sizeof(*packet) / sizeof(uint32_t),
 			(unsigned int **)&packet);
 	if (packet == NULL) {
@@ -378,8 +375,7 @@
 	packet->queue_mask_lo = lower_32_bits(res->queue_mask);
 	packet->queue_mask_hi = upper_32_bits(res->queue_mask);
 
-	pm->priv_queue->submit_packet(pm->priv_queue);
-	pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+	pm->priv_queue->ops.submit_packet(pm->priv_queue);
 
 	mutex_unlock(&pm->lock);
 
@@ -405,7 +401,7 @@
 	packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t);
 	mutex_lock(&pm->lock);
 
-	retval = pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+	retval = pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
 					packet_size_dwords, &rl_buffer);
 	if (retval != 0)
 		goto fail_acquire_packet_buffer;
@@ -415,15 +411,14 @@
 	if (retval != 0)
 		goto fail_create_runlist;
 
-	pm->priv_queue->submit_packet(pm->priv_queue);
-	pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+	pm->priv_queue->ops.submit_packet(pm->priv_queue);
 
 	mutex_unlock(&pm->lock);
 
 	return retval;
 
 fail_create_runlist:
-	pm->priv_queue->rollback_packet(pm->priv_queue);
+	pm->priv_queue->ops.rollback_packet(pm->priv_queue);
 fail_acquire_packet_buffer:
 	mutex_unlock(&pm->lock);
 fail_create_runlist_ib:
@@ -441,7 +436,7 @@
 	BUG_ON(!pm || !fence_address);
 
 	mutex_lock(&pm->lock);
-	retval = pm->priv_queue->acquire_packet_buffer(
+	retval = pm->priv_queue->ops.acquire_packet_buffer(
 			pm->priv_queue,
 			sizeof(struct pm4_query_status) / sizeof(uint32_t),
 			(unsigned int **)&packet);
@@ -462,8 +457,7 @@
 	packet->data_hi = upper_32_bits((uint64_t)fence_value);
 	packet->data_lo = lower_32_bits((uint64_t)fence_value);
 
-	pm->priv_queue->submit_packet(pm->priv_queue);
-	pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+	pm->priv_queue->ops.submit_packet(pm->priv_queue);
 	mutex_unlock(&pm->lock);
 
 	return 0;
@@ -485,7 +479,7 @@
 	BUG_ON(!pm);
 
 	mutex_lock(&pm->lock);
-	retval = pm->priv_queue->acquire_packet_buffer(
+	retval = pm->priv_queue->ops.acquire_packet_buffer(
 			pm->priv_queue,
 			sizeof(struct pm4_unmap_queues) / sizeof(uint32_t),
 			&buffer);
@@ -540,8 +534,7 @@
 		break;
 	};
 
-	pm->priv_queue->submit_packet(pm->priv_queue);
-	pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+	pm->priv_queue->ops.submit_packet(pm->priv_queue);
 
 	mutex_unlock(&pm->lock);
 	return 0;
@@ -557,8 +550,7 @@
 
 	mutex_lock(&pm->lock);
 	if (pm->allocated) {
-		kfd2kgd->free_mem(pm->dqm->dev->kgd,
-				(struct kgd_mem *) pm->ib_buffer_obj);
+		kfd_gtt_sa_free(pm->dqm->dev, pm->ib_buffer_obj);
 		pm->allocated = false;
 	}
 	mutex_unlock(&pm->lock);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 96dc10e..5a44f2f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -103,12 +103,26 @@
 	cache_policy_noncoherent
 };
 
+enum asic_family_type {
+	CHIP_KAVERI = 0,
+	CHIP_CARRIZO
+};
+
 struct kfd_device_info {
+	unsigned int asic_family;
 	unsigned int max_pasid_bits;
 	size_t ih_ring_entry_size;
+	uint8_t num_of_watch_points;
 	uint16_t mqd_size_aligned;
 };
 
+struct kfd_mem_obj {
+	uint32_t range_start;
+	uint32_t range_end;
+	uint64_t gpu_addr;
+	uint32_t *cpu_ptr;
+};
+
 struct kfd_dev {
 	struct kgd_dev *kgd;
 
@@ -134,6 +148,14 @@
 
 	struct kgd2kfd_shared_resources shared_resources;
 
+	void *gtt_mem;
+	uint64_t gtt_start_gpu_addr;
+	void *gtt_start_cpu_ptr;
+	void *gtt_sa_bitmap;
+	struct mutex gtt_sa_lock;
+	unsigned int gtt_sa_chunk_size;
+	unsigned int gtt_sa_num_of_chunks;
+
 	/* QCM Device instance */
 	struct device_queue_manager *dqm;
 
@@ -149,12 +171,6 @@
 
 extern const struct kfd2kgd_calls *kfd2kgd;
 
-struct kfd_mem_obj {
-	void *bo;
-	uint64_t gpu_addr;
-	uint32_t *cpu_ptr;
-};
-
 enum kfd_mempool {
 	KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
 	KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -272,6 +288,15 @@
 	bool is_active;
 	/* Not relevant for user mode queues in cp scheduling */
 	unsigned int vmid;
+	/* Relevant only for sdma queues*/
+	uint32_t sdma_engine_id;
+	uint32_t sdma_queue_id;
+	uint32_t sdma_vm_addr;
+	/* Relevant only for VI */
+	uint64_t eop_ring_buffer_address;
+	uint32_t eop_ring_buffer_size;
+	uint64_t ctx_save_restore_area_address;
+	uint32_t ctx_save_restore_area_size;
 };
 
 /**
@@ -314,6 +339,8 @@
 	uint32_t pipe;
 	uint32_t queue;
 
+	unsigned int sdma_id;
+
 	struct kfd_process	*process;
 	struct kfd_dev		*device;
 };
@@ -322,10 +349,10 @@
  * Please read the kfd_mqd_manager.h description.
  */
 enum KFD_MQD_TYPE {
-	KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */
-	KFD_MQD_TYPE_CIK_HIQ, /* for hiq */
-	KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */
-	KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */
+	KFD_MQD_TYPE_COMPUTE = 0,	/* for no cp scheduling */
+	KFD_MQD_TYPE_HIQ,		/* for hiq */
+	KFD_MQD_TYPE_CP,		/* for cp queues and diq */
+	KFD_MQD_TYPE_SDMA,		/* for sdma queues */
 	KFD_MQD_TYPE_MAX
 };
 
@@ -477,8 +504,9 @@
 							struct kfd_process *p);
 void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid);
 struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
-							struct kfd_process *p,
-							int create_pdd);
+							struct kfd_process *p);
+struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
+							struct kfd_process *p);
 
 /* Process device data iterator */
 struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p);
@@ -506,6 +534,13 @@
 					struct kfd_process *process,
 					unsigned int queue_id);
 
+/* GTT Sub-Allocator */
+
+int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
+			struct kfd_mem_obj **mem_obj);
+
+int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj);
+
 extern struct device *kfd_device;
 
 /* Topology */
@@ -530,6 +565,8 @@
 /* Queue Context Management */
 inline uint32_t lower_32(uint64_t x);
 inline uint32_t upper_32(uint64_t x);
+struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
+inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m);
 
 int init_queue(struct queue **q, struct queue_properties properties);
 void uninit_queue(struct queue *q);
@@ -538,6 +575,10 @@
 
 struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
 					struct kfd_dev *dev);
+struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
+		struct kfd_dev *dev);
+struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
+		struct kfd_dev *dev);
 struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev);
 void device_queue_manager_uninit(struct device_queue_manager *dqm);
 struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 3c76ef0..a369c14 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -311,24 +311,29 @@
 }
 
 struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
-							struct kfd_process *p,
-							int create_pdd)
+							struct kfd_process *p)
 {
 	struct kfd_process_device *pdd = NULL;
 
 	list_for_each_entry(pdd, &p->per_device_data, per_device_list)
 		if (pdd->dev == dev)
-			return pdd;
+			break;
 
-	if (create_pdd) {
-		pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
-		if (pdd != NULL) {
-			pdd->dev = dev;
-			INIT_LIST_HEAD(&pdd->qpd.queues_list);
-			INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
-			pdd->qpd.dqm = dev->dqm;
-			list_add(&pdd->per_device_list, &p->per_device_data);
-		}
+	return pdd;
+}
+
+struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
+							struct kfd_process *p)
+{
+	struct kfd_process_device *pdd = NULL;
+
+	pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
+	if (pdd != NULL) {
+		pdd->dev = dev;
+		INIT_LIST_HEAD(&pdd->qpd.queues_list);
+		INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
+		pdd->qpd.dqm = dev->dqm;
+		list_add(&pdd->per_device_list, &p->per_device_data);
 	}
 
 	return pdd;
@@ -344,11 +349,14 @@
 struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
 							struct kfd_process *p)
 {
-	struct kfd_process_device *pdd = kfd_get_process_device_data(dev, p, 1);
+	struct kfd_process_device *pdd;
 	int err;
 
-	if (pdd == NULL)
+	pdd = kfd_get_process_device_data(dev, p);
+	if (!pdd) {
+		pr_err("Process device data doesn't exist\n");
 		return ERR_PTR(-ENOMEM);
+	}
 
 	if (pdd->bound)
 		return pdd;
@@ -384,7 +392,7 @@
 
 	pqm_uninit(&p->pqm);
 
-	pdd = kfd_get_process_device_data(dev, p, 0);
+	pdd = kfd_get_process_device_data(dev, p);
 
 	/*
 	 * Just mark pdd as unbound, because we still need it to call
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index 2fda1927..530b82c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -128,7 +128,6 @@
 	/* let DQM handle it*/
 	q_properties->vmid = 0;
 	q_properties->queue_id = qid;
-	q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
 
 	retval = init_queue(q, *q_properties);
 	if (retval != 0)
@@ -167,8 +166,11 @@
 	q = NULL;
 	kq = NULL;
 
-	pdd = kfd_get_process_device_data(dev, pqm->process, 1);
-	BUG_ON(!pdd);
+	pdd = kfd_get_process_device_data(dev, pqm->process);
+	if (!pdd) {
+		pr_err("Process device data doesn't exist\n");
+		return -1;
+	}
 
 	retval = find_available_queue_slot(pqm, qid);
 	if (retval != 0)
@@ -176,7 +178,7 @@
 
 	if (list_empty(&pqm->queues)) {
 		pdd->qpd.pqm = pqm;
-		dev->dqm->register_process(dev->dqm, &pdd->qpd);
+		dev->dqm->ops.register_process(dev->dqm, &pdd->qpd);
 	}
 
 	pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL);
@@ -186,6 +188,7 @@
 	}
 
 	switch (type) {
+	case KFD_QUEUE_TYPE_SDMA:
 	case KFD_QUEUE_TYPE_COMPUTE:
 		/* check if there is over subscription */
 		if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
@@ -201,7 +204,7 @@
 			goto err_create_queue;
 		pqn->q = q;
 		pqn->kq = NULL;
-		retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd,
+		retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
 						&q->properties.vmid);
 		pr_debug("DQM returned %d for create_queue\n", retval);
 		print_queue(q);
@@ -215,7 +218,8 @@
 		kq->queue->properties.queue_id = *qid;
 		pqn->kq = kq;
 		pqn->q = NULL;
-		retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd);
+		retval = dev->dqm->ops.create_kernel_queue(dev->dqm,
+							kq, &pdd->qpd);
 		break;
 	default:
 		BUG();
@@ -245,7 +249,7 @@
 	/* check if queues list is empty unregister process from device */
 	clear_bit(*qid, pqm->queue_slot_bitmap);
 	if (list_empty(&pqm->queues))
-		dev->dqm->unregister_process(dev->dqm, &pdd->qpd);
+		dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd);
 	return retval;
 }
 
@@ -277,19 +281,22 @@
 		dev = pqn->q->device;
 	BUG_ON(!dev);
 
-	pdd = kfd_get_process_device_data(dev, pqm->process, 1);
-	BUG_ON(!pdd);
+	pdd = kfd_get_process_device_data(dev, pqm->process);
+	if (!pdd) {
+		pr_err("Process device data doesn't exist\n");
+		return -1;
+	}
 
 	if (pqn->kq) {
 		/* destroy kernel queue (DIQ) */
 		dqm = pqn->kq->dev->dqm;
-		dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
+		dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
 		kernel_queue_uninit(pqn->kq);
 	}
 
 	if (pqn->q) {
 		dqm = pqn->q->device->dqm;
-		retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q);
+		retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
 		if (retval != 0)
 			return retval;
 
@@ -301,7 +308,7 @@
 	clear_bit(qid, pqm->queue_slot_bitmap);
 
 	if (list_empty(&pqm->queues))
-		dqm->unregister_process(dqm, &pdd->qpd);
+		dqm->ops.unregister_process(dqm, &pdd->qpd);
 
 	return retval;
 }
@@ -326,7 +333,8 @@
 	pqn->q->properties.queue_percent = p->queue_percent;
 	pqn->q->properties.priority = p->priority;
 
-	retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q);
+	retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
+							pqn->q);
 	if (retval != 0)
 		return retval;
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index cca1708..4983993 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -27,6 +27,7 @@
 #include <linux/acpi.h>
 #include <linux/hash.h>
 #include <linux/cpufreq.h>
+#include <linux/log2.h>
 
 #include "kfd_priv.h"
 #include "kfd_crat.h"
@@ -630,10 +631,10 @@
 static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
 		char *buffer)
 {
-	ssize_t ret;
 	struct kfd_topology_device *dev;
 	char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
 	uint32_t i;
+	uint32_t log_max_watch_addr;
 
 	/* Making sure that the buffer is an empty string */
 	buffer[0] = 0;
@@ -641,8 +642,10 @@
 	if (strcmp(attr->name, "gpu_id") == 0) {
 		dev = container_of(attr, struct kfd_topology_device,
 				attr_gpuid);
-		ret = sysfs_show_32bit_val(buffer, dev->gpu_id);
-	} else if (strcmp(attr->name, "name") == 0) {
+		return sysfs_show_32bit_val(buffer, dev->gpu_id);
+	}
+
+	if (strcmp(attr->name, "name") == 0) {
 		dev = container_of(attr, struct kfd_topology_device,
 				attr_name);
 		for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) {
@@ -652,80 +655,90 @@
 				break;
 		}
 		public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0;
-		ret = sysfs_show_str_val(buffer, public_name);
-	} else {
-		dev = container_of(attr, struct kfd_topology_device,
-				attr_props);
-		sysfs_show_32bit_prop(buffer, "cpu_cores_count",
-				dev->node_props.cpu_cores_count);
-		sysfs_show_32bit_prop(buffer, "simd_count",
-				dev->node_props.simd_count);
-
-		if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
-			pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
-					dev->node_props.mem_banks_count,
-					dev->mem_bank_count);
-			sysfs_show_32bit_prop(buffer, "mem_banks_count",
-					dev->mem_bank_count);
-		} else {
-			sysfs_show_32bit_prop(buffer, "mem_banks_count",
-					dev->node_props.mem_banks_count);
-		}
-
-		sysfs_show_32bit_prop(buffer, "caches_count",
-				dev->node_props.caches_count);
-		sysfs_show_32bit_prop(buffer, "io_links_count",
-				dev->node_props.io_links_count);
-		sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
-				dev->node_props.cpu_core_id_base);
-		sysfs_show_32bit_prop(buffer, "simd_id_base",
-				dev->node_props.simd_id_base);
-		sysfs_show_32bit_prop(buffer, "capability",
-				dev->node_props.capability);
-		sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
-				dev->node_props.max_waves_per_simd);
-		sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
-				dev->node_props.lds_size_in_kb);
-		sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
-				dev->node_props.gds_size_in_kb);
-		sysfs_show_32bit_prop(buffer, "wave_front_size",
-				dev->node_props.wave_front_size);
-		sysfs_show_32bit_prop(buffer, "array_count",
-				dev->node_props.array_count);
-		sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
-				dev->node_props.simd_arrays_per_engine);
-		sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
-				dev->node_props.cu_per_simd_array);
-		sysfs_show_32bit_prop(buffer, "simd_per_cu",
-				dev->node_props.simd_per_cu);
-		sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
-				dev->node_props.max_slots_scratch_cu);
-		sysfs_show_32bit_prop(buffer, "vendor_id",
-				dev->node_props.vendor_id);
-		sysfs_show_32bit_prop(buffer, "device_id",
-				dev->node_props.device_id);
-		sysfs_show_32bit_prop(buffer, "location_id",
-				dev->node_props.location_id);
-
-		if (dev->gpu) {
-			sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
-					kfd2kgd->get_max_engine_clock_in_mhz(
-						dev->gpu->kgd));
-			sysfs_show_64bit_prop(buffer, "local_mem_size",
-					kfd2kgd->get_vmem_size(dev->gpu->kgd));
-
-			sysfs_show_32bit_prop(buffer, "fw_version",
-					kfd2kgd->get_fw_version(
-							dev->gpu->kgd,
-							KGD_ENGINE_MEC1));
-
-		}
-
-		ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
-				cpufreq_quick_get_max(0)/1000);
+		return sysfs_show_str_val(buffer, public_name);
 	}
 
-	return ret;
+	dev = container_of(attr, struct kfd_topology_device,
+			attr_props);
+	sysfs_show_32bit_prop(buffer, "cpu_cores_count",
+			dev->node_props.cpu_cores_count);
+	sysfs_show_32bit_prop(buffer, "simd_count",
+			dev->node_props.simd_count);
+
+	if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
+		pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
+				dev->node_props.mem_banks_count,
+				dev->mem_bank_count);
+		sysfs_show_32bit_prop(buffer, "mem_banks_count",
+				dev->mem_bank_count);
+	} else {
+		sysfs_show_32bit_prop(buffer, "mem_banks_count",
+				dev->node_props.mem_banks_count);
+	}
+
+	sysfs_show_32bit_prop(buffer, "caches_count",
+			dev->node_props.caches_count);
+	sysfs_show_32bit_prop(buffer, "io_links_count",
+			dev->node_props.io_links_count);
+	sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
+			dev->node_props.cpu_core_id_base);
+	sysfs_show_32bit_prop(buffer, "simd_id_base",
+			dev->node_props.simd_id_base);
+	sysfs_show_32bit_prop(buffer, "capability",
+			dev->node_props.capability);
+	sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
+			dev->node_props.max_waves_per_simd);
+	sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
+			dev->node_props.lds_size_in_kb);
+	sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
+			dev->node_props.gds_size_in_kb);
+	sysfs_show_32bit_prop(buffer, "wave_front_size",
+			dev->node_props.wave_front_size);
+	sysfs_show_32bit_prop(buffer, "array_count",
+			dev->node_props.array_count);
+	sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
+			dev->node_props.simd_arrays_per_engine);
+	sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
+			dev->node_props.cu_per_simd_array);
+	sysfs_show_32bit_prop(buffer, "simd_per_cu",
+			dev->node_props.simd_per_cu);
+	sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
+			dev->node_props.max_slots_scratch_cu);
+	sysfs_show_32bit_prop(buffer, "vendor_id",
+			dev->node_props.vendor_id);
+	sysfs_show_32bit_prop(buffer, "device_id",
+			dev->node_props.device_id);
+	sysfs_show_32bit_prop(buffer, "location_id",
+			dev->node_props.location_id);
+
+	if (dev->gpu) {
+		log_max_watch_addr =
+			__ilog2_u32(dev->gpu->device_info->num_of_watch_points);
+
+		if (log_max_watch_addr) {
+			dev->node_props.capability |=
+					HSA_CAP_WATCH_POINTS_SUPPORTED;
+
+			dev->node_props.capability |=
+				((log_max_watch_addr <<
+					HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) &
+				HSA_CAP_WATCH_POINTS_TOTALBITS_MASK);
+		}
+
+		sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
+				kfd2kgd->get_max_engine_clock_in_mhz(
+					dev->gpu->kgd));
+		sysfs_show_64bit_prop(buffer, "local_mem_size",
+				kfd2kgd->get_vmem_size(dev->gpu->kgd));
+
+		sysfs_show_32bit_prop(buffer, "fw_version",
+				kfd2kgd->get_fw_version(
+						dev->gpu->kgd,
+						KGD_ENGINE_MEC1));
+	}
+
+	return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
+					cpufreq_quick_get_max(0)/1000);
 }
 
 static const struct sysfs_ops node_ops = {
diff --git a/drivers/gpu/drm/amd/include/cik_structs.h b/drivers/gpu/drm/amd/include/cik_structs.h
new file mode 100644
index 0000000..749eab9
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/cik_structs.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2012 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.
+ *
+ */
+
+#ifndef CIK_STRUCTS_H_
+#define CIK_STRUCTS_H_
+
+struct cik_mqd {
+	uint32_t header;
+	uint32_t compute_dispatch_initiator;
+	uint32_t compute_dim_x;
+	uint32_t compute_dim_y;
+	uint32_t compute_dim_z;
+	uint32_t compute_start_x;
+	uint32_t compute_start_y;
+	uint32_t compute_start_z;
+	uint32_t compute_num_thread_x;
+	uint32_t compute_num_thread_y;
+	uint32_t compute_num_thread_z;
+	uint32_t compute_pipelinestat_enable;
+	uint32_t compute_perfcount_enable;
+	uint32_t compute_pgm_lo;
+	uint32_t compute_pgm_hi;
+	uint32_t compute_tba_lo;
+	uint32_t compute_tba_hi;
+	uint32_t compute_tma_lo;
+	uint32_t compute_tma_hi;
+	uint32_t compute_pgm_rsrc1;
+	uint32_t compute_pgm_rsrc2;
+	uint32_t compute_vmid;
+	uint32_t compute_resource_limits;
+	uint32_t compute_static_thread_mgmt_se0;
+	uint32_t compute_static_thread_mgmt_se1;
+	uint32_t compute_tmpring_size;
+	uint32_t compute_static_thread_mgmt_se2;
+	uint32_t compute_static_thread_mgmt_se3;
+	uint32_t compute_restart_x;
+	uint32_t compute_restart_y;
+	uint32_t compute_restart_z;
+	uint32_t compute_thread_trace_enable;
+	uint32_t compute_misc_reserved;
+	uint32_t compute_user_data_0;
+	uint32_t compute_user_data_1;
+	uint32_t compute_user_data_2;
+	uint32_t compute_user_data_3;
+	uint32_t compute_user_data_4;
+	uint32_t compute_user_data_5;
+	uint32_t compute_user_data_6;
+	uint32_t compute_user_data_7;
+	uint32_t compute_user_data_8;
+	uint32_t compute_user_data_9;
+	uint32_t compute_user_data_10;
+	uint32_t compute_user_data_11;
+	uint32_t compute_user_data_12;
+	uint32_t compute_user_data_13;
+	uint32_t compute_user_data_14;
+	uint32_t compute_user_data_15;
+	uint32_t cp_compute_csinvoc_count_lo;
+	uint32_t cp_compute_csinvoc_count_hi;
+	uint32_t cp_mqd_base_addr_lo;
+	uint32_t cp_mqd_base_addr_hi;
+	uint32_t cp_hqd_active;
+	uint32_t cp_hqd_vmid;
+	uint32_t cp_hqd_persistent_state;
+	uint32_t cp_hqd_pipe_priority;
+	uint32_t cp_hqd_queue_priority;
+	uint32_t cp_hqd_quantum;
+	uint32_t cp_hqd_pq_base_lo;
+	uint32_t cp_hqd_pq_base_hi;
+	uint32_t cp_hqd_pq_rptr;
+	uint32_t cp_hqd_pq_rptr_report_addr_lo;
+	uint32_t cp_hqd_pq_rptr_report_addr_hi;
+	uint32_t cp_hqd_pq_wptr_poll_addr_lo;
+	uint32_t cp_hqd_pq_wptr_poll_addr_hi;
+	uint32_t cp_hqd_pq_doorbell_control;
+	uint32_t cp_hqd_pq_wptr;
+	uint32_t cp_hqd_pq_control;
+	uint32_t cp_hqd_ib_base_addr_lo;
+	uint32_t cp_hqd_ib_base_addr_hi;
+	uint32_t cp_hqd_ib_rptr;
+	uint32_t cp_hqd_ib_control;
+	uint32_t cp_hqd_iq_timer;
+	uint32_t cp_hqd_iq_rptr;
+	uint32_t cp_hqd_dequeue_request;
+	uint32_t cp_hqd_dma_offload;
+	uint32_t cp_hqd_sema_cmd;
+	uint32_t cp_hqd_msg_type;
+	uint32_t cp_hqd_atomic0_preop_lo;
+	uint32_t cp_hqd_atomic0_preop_hi;
+	uint32_t cp_hqd_atomic1_preop_lo;
+	uint32_t cp_hqd_atomic1_preop_hi;
+	uint32_t cp_hqd_hq_status0;
+	uint32_t cp_hqd_hq_control0;
+	uint32_t cp_mqd_control;
+	uint32_t cp_mqd_query_time_lo;
+	uint32_t cp_mqd_query_time_hi;
+	uint32_t cp_mqd_connect_start_time_lo;
+	uint32_t cp_mqd_connect_start_time_hi;
+	uint32_t cp_mqd_connect_end_time_lo;
+	uint32_t cp_mqd_connect_end_time_hi;
+	uint32_t cp_mqd_connect_end_wf_count;
+	uint32_t cp_mqd_connect_end_pq_rptr;
+	uint32_t cp_mqd_connect_end_pq_wptr;
+	uint32_t cp_mqd_connect_end_ib_rptr;
+	uint32_t reserved_96;
+	uint32_t reserved_97;
+	uint32_t reserved_98;
+	uint32_t reserved_99;
+	uint32_t iqtimer_pkt_header;
+	uint32_t iqtimer_pkt_dw0;
+	uint32_t iqtimer_pkt_dw1;
+	uint32_t iqtimer_pkt_dw2;
+	uint32_t iqtimer_pkt_dw3;
+	uint32_t iqtimer_pkt_dw4;
+	uint32_t iqtimer_pkt_dw5;
+	uint32_t iqtimer_pkt_dw6;
+	uint32_t reserved_108;
+	uint32_t reserved_109;
+	uint32_t reserved_110;
+	uint32_t reserved_111;
+	uint32_t queue_doorbell_id0;
+	uint32_t queue_doorbell_id1;
+	uint32_t queue_doorbell_id2;
+	uint32_t queue_doorbell_id3;
+	uint32_t queue_doorbell_id4;
+	uint32_t queue_doorbell_id5;
+	uint32_t queue_doorbell_id6;
+	uint32_t queue_doorbell_id7;
+	uint32_t queue_doorbell_id8;
+	uint32_t queue_doorbell_id9;
+	uint32_t queue_doorbell_id10;
+	uint32_t queue_doorbell_id11;
+	uint32_t queue_doorbell_id12;
+	uint32_t queue_doorbell_id13;
+	uint32_t queue_doorbell_id14;
+	uint32_t queue_doorbell_id15;
+};
+
+struct cik_sdma_rlc_registers {
+	uint32_t sdma_rlc_rb_cntl;
+	uint32_t sdma_rlc_rb_base;
+	uint32_t sdma_rlc_rb_base_hi;
+	uint32_t sdma_rlc_rb_rptr;
+	uint32_t sdma_rlc_rb_wptr;
+	uint32_t sdma_rlc_rb_wptr_poll_cntl;
+	uint32_t sdma_rlc_rb_wptr_poll_addr_hi;
+	uint32_t sdma_rlc_rb_wptr_poll_addr_lo;
+	uint32_t sdma_rlc_rb_rptr_addr_hi;
+	uint32_t sdma_rlc_rb_rptr_addr_lo;
+	uint32_t sdma_rlc_ib_cntl;
+	uint32_t sdma_rlc_ib_rptr;
+	uint32_t sdma_rlc_ib_offset;
+	uint32_t sdma_rlc_ib_base_lo;
+	uint32_t sdma_rlc_ib_base_hi;
+	uint32_t sdma_rlc_ib_size;
+	uint32_t sdma_rlc_skip_cntl;
+	uint32_t sdma_rlc_context_status;
+	uint32_t sdma_rlc_doorbell;
+	uint32_t sdma_rlc_virtual_addr;
+	uint32_t sdma_rlc_ape1_cntl;
+	uint32_t sdma_rlc_doorbell_log;
+	uint32_t reserved_22;
+	uint32_t reserved_23;
+	uint32_t reserved_24;
+	uint32_t reserved_25;
+	uint32_t reserved_26;
+	uint32_t reserved_27;
+	uint32_t reserved_28;
+	uint32_t reserved_29;
+	uint32_t reserved_30;
+	uint32_t reserved_31;
+	uint32_t reserved_32;
+	uint32_t reserved_33;
+	uint32_t reserved_34;
+	uint32_t reserved_35;
+	uint32_t reserved_36;
+	uint32_t reserved_37;
+	uint32_t reserved_38;
+	uint32_t reserved_39;
+	uint32_t reserved_40;
+	uint32_t reserved_41;
+	uint32_t reserved_42;
+	uint32_t reserved_43;
+	uint32_t reserved_44;
+	uint32_t reserved_45;
+	uint32_t reserved_46;
+	uint32_t reserved_47;
+	uint32_t reserved_48;
+	uint32_t reserved_49;
+	uint32_t reserved_50;
+	uint32_t reserved_51;
+	uint32_t reserved_52;
+	uint32_t reserved_53;
+	uint32_t reserved_54;
+	uint32_t reserved_55;
+	uint32_t reserved_56;
+	uint32_t reserved_57;
+	uint32_t reserved_58;
+	uint32_t reserved_59;
+	uint32_t reserved_60;
+	uint32_t reserved_61;
+	uint32_t reserved_62;
+	uint32_t reserved_63;
+	uint32_t reserved_64;
+	uint32_t reserved_65;
+	uint32_t reserved_66;
+	uint32_t reserved_67;
+	uint32_t reserved_68;
+	uint32_t reserved_69;
+	uint32_t reserved_70;
+	uint32_t reserved_71;
+	uint32_t reserved_72;
+	uint32_t reserved_73;
+	uint32_t reserved_74;
+	uint32_t reserved_75;
+	uint32_t reserved_76;
+	uint32_t reserved_77;
+	uint32_t reserved_78;
+	uint32_t reserved_79;
+	uint32_t reserved_80;
+	uint32_t reserved_81;
+	uint32_t reserved_82;
+	uint32_t reserved_83;
+	uint32_t reserved_84;
+	uint32_t reserved_85;
+	uint32_t reserved_86;
+	uint32_t reserved_87;
+	uint32_t reserved_88;
+	uint32_t reserved_89;
+	uint32_t reserved_90;
+	uint32_t reserved_91;
+	uint32_t reserved_92;
+	uint32_t reserved_93;
+	uint32_t reserved_94;
+	uint32_t reserved_95;
+	uint32_t reserved_96;
+	uint32_t reserved_97;
+	uint32_t reserved_98;
+	uint32_t reserved_99;
+	uint32_t reserved_100;
+	uint32_t reserved_101;
+	uint32_t reserved_102;
+	uint32_t reserved_103;
+	uint32_t reserved_104;
+	uint32_t reserved_105;
+	uint32_t reserved_106;
+	uint32_t reserved_107;
+	uint32_t reserved_108;
+	uint32_t reserved_109;
+	uint32_t reserved_110;
+	uint32_t reserved_111;
+	uint32_t reserved_112;
+	uint32_t reserved_113;
+	uint32_t reserved_114;
+	uint32_t reserved_115;
+	uint32_t reserved_116;
+	uint32_t reserved_117;
+	uint32_t reserved_118;
+	uint32_t reserved_119;
+	uint32_t reserved_120;
+	uint32_t reserved_121;
+	uint32_t reserved_122;
+	uint32_t reserved_123;
+	uint32_t reserved_124;
+	uint32_t reserved_125;
+	uint32_t reserved_126;
+	uint32_t reserved_127;
+	uint32_t sdma_engine_id;
+	uint32_t sdma_queue_id;
+};
+
+
+
+#endif /* CIK_STRUCTS_H_ */
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 96a5122..239bc16 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -110,17 +110,10 @@
 /**
  * struct kfd2kgd_calls
  *
- * @init_sa_manager: Initialize an instance of the sa manager, used by
- * amdkfd for all system memory allocations that are mapped to the GART
- * address space
+ * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
+ * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
  *
- * @fini_sa_manager: Releases all memory allocations for amdkfd that are
- * handled by kgd sa manager
- *
- * @allocate_mem: Allocate a buffer from amdkfd's sa manager. The buffer can
- * be used for mqds, hpds, kernel queue, fence and runlists
- *
- * @free_mem: Frees a buffer that was allocated by amdkfd's sa manager
+ * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
  *
  * @get_vmem_size: Retrieves (physical) size of VRAM
  *
@@ -136,18 +129,23 @@
  * @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp
  * scheduling mode. Only used for no cp scheduling mode.
  *
- * @init_memory: Initializes memory apertures to fixed base/limit address
- * and non cached memory types.
- *
  * @init_pipeline: Initialized the compute pipelines.
  *
  * @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp
  * sceduling mode.
  *
+ * @hqd_sdma_load: Loads the SDMA mqd structure to a H/W SDMA hqd slot.
+ * used only for no HWS mode.
+ *
  * @hqd_is_occupies: Checks if a hqd slot is occupied.
  *
  * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
  *
+ * @hqd_sdma_is_occupied: Checks if an SDMA hqd slot is occupied.
+ *
+ * @hqd_sdma_destroy: Destructs and preempts the SDMA queue assigned to that
+ * SDMA hqd slot.
+ *
  * @get_fw_version: Returns FW versions from the header
  *
  * This structure contains function pointers to services that the kgd driver
@@ -155,13 +153,11 @@
  *
  */
 struct kfd2kgd_calls {
-	/* Memory management. */
-	int (*init_sa_manager)(struct kgd_dev *kgd, unsigned int size);
-	void (*fini_sa_manager)(struct kgd_dev *kgd);
-	int (*allocate_mem)(struct kgd_dev *kgd, size_t size, size_t alignment,
-			enum kgd_memory_pool pool, struct kgd_mem **mem);
+	int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
+					void **mem_obj, uint64_t *gpu_addr,
+					void **cpu_ptr);
 
-	void (*free_mem)(struct kgd_dev *kgd, struct kgd_mem *mem);
+	void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
 
 	uint64_t (*get_vmem_size)(struct kgd_dev *kgd);
 	uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
@@ -176,25 +172,32 @@
 	int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
 					unsigned int vmid);
 
-	int (*init_memory)(struct kgd_dev *kgd);
 	int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
 				uint32_t hpd_size, uint64_t hpd_gpu_addr);
 
 	int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
 			uint32_t queue_id, uint32_t __user *wptr);
 
+	int (*hqd_sdma_load)(struct kgd_dev *kgd, void *mqd);
+
 	bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address,
 				uint32_t pipe_id, uint32_t queue_id);
 
 	int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
 				unsigned int timeout, uint32_t pipe_id,
 				uint32_t queue_id);
+
+	bool (*hqd_sdma_is_occupied)(struct kgd_dev *kgd, void *mqd);
+
+	int (*hqd_sdma_destroy)(struct kgd_dev *kgd, void *mqd,
+				unsigned int timeout);
+
 	uint16_t (*get_fw_version)(struct kgd_dev *kgd,
 				enum kgd_engine_type type);
 };
 
 bool kgd2kfd_init(unsigned interface_version,
-		  const struct kfd2kgd_calls *f2g,
-		  const struct kgd2kfd_calls **g2f);
+		const struct kfd2kgd_calls *f2g,
+		const struct kgd2kfd_calls **g2f);
 
-#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
+#endif	/* KGD_KFD_INTERFACE_H_INCLUDED */
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index e3a7a50..42d2ffa 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -653,10 +653,6 @@
 	return 0;
 }
 
-static void armada_drm_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
 /* The mode_config.mutex will be held for this call */
 static void armada_drm_crtc_disable(struct drm_crtc *crtc)
 {
@@ -678,7 +674,6 @@
 	.mode_fixup	= armada_drm_crtc_mode_fixup,
 	.mode_set	= armada_drm_crtc_mode_set,
 	.mode_set_base	= armada_drm_crtc_mode_set_base,
-	.load_lut	= armada_drm_crtc_load_lut,
 	.disable	= armada_drm_crtc_disable,
 };
 
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 5c60ae5..ff68eef 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -335,18 +335,27 @@
 
 	ret = drm_fb_helper_init(dev, &afbdev->helper,
 				 1, 1);
-	if (ret) {
-		kfree(afbdev);
-		return ret;
-	}
+	if (ret)
+		goto free;
 
-	drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+	ret = drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(dev);
 
-	drm_fb_helper_initial_config(&afbdev->helper, 32);
+	ret = drm_fb_helper_initial_config(&afbdev->helper, 32);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&afbdev->helper);
+free:
+	kfree(afbdev);
+	return ret;
 }
 
 void ast_fbdev_fini(struct drm_device *dev)
diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig
new file mode 100644
index 0000000..99b4f06
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig
@@ -0,0 +1,11 @@
+config DRM_ATMEL_HLCDC
+	tristate "DRM Support for ATMEL HLCDC Display Controller"
+	depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC && ARM
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this option if you have an ATMEL SoC with an HLCDC display
+	  controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile
new file mode 100644
index 0000000..10ae426
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
@@ -0,0 +1,7 @@
+atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
+		atmel_hlcdc_dc.o \
+		atmel_hlcdc_layer.o \
+		atmel_hlcdc_output.o \
+		atmel_hlcdc_plane.o
+
+obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc-dc.o
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
new file mode 100644
index 0000000..0409b90
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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.
+ *
+ * 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/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC CRTC structure
+ *
+ * @base: base DRM CRTC structure
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @event: pointer to the current page flip event
+ * @id: CRTC id (returned by drm_crtc_index)
+ * @dpms: DPMS mode
+ */
+struct atmel_hlcdc_crtc {
+	struct drm_crtc base;
+	struct atmel_hlcdc_dc *dc;
+	struct drm_pending_vblank_event *event;
+	int id;
+	int dpms;
+};
+
+static inline struct atmel_hlcdc_crtc *
+drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct atmel_hlcdc_crtc, base);
+}
+
+static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
+{
+	struct drm_device *dev = c->dev;
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct regmap *regmap = crtc->dc->hlcdc->regmap;
+	unsigned int status;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	if (crtc->dpms == mode)
+		return;
+
+	pm_runtime_get_sync(dev->dev);
+
+	if (mode != DRM_MODE_DPMS_ON) {
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       (status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+		clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
+
+		pm_runtime_allow(dev->dev);
+	} else {
+		pm_runtime_forbid(dev->dev);
+
+		clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_PIXEL_CLK))
+			cpu_relax();
+
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_SYNC))
+			cpu_relax();
+
+		regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
+		while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+		       !(status & ATMEL_HLCDC_DISP))
+			cpu_relax();
+	}
+
+	pm_runtime_put_sync(dev->dev);
+
+	crtc->dpms = mode;
+}
+
+static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
+				     struct drm_display_mode *mode,
+				     struct drm_display_mode *adj,
+				     int x, int y,
+				     struct drm_framebuffer *old_fb)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct regmap *regmap = crtc->dc->hlcdc->regmap;
+	struct drm_plane *plane = c->primary;
+	struct drm_framebuffer *fb;
+	unsigned long mode_rate;
+	struct videomode vm;
+	unsigned long prate;
+	unsigned int cfg;
+	int div;
+
+	if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
+		return -EINVAL;
+
+	vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
+	vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
+	vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
+	vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
+	vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
+	vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(1),
+		     (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(2),
+		     (vm.vfront_porch - 1) | (vm.vback_porch << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(3),
+		     (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
+
+	regmap_write(regmap, ATMEL_HLCDC_CFG(4),
+		     (adj->crtc_hdisplay - 1) |
+		     ((adj->crtc_vdisplay - 1) << 16));
+
+	cfg = ATMEL_HLCDC_CLKPOL;
+
+	prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
+	mode_rate = mode->crtc_clock * 1000;
+	if ((prate / 2) < mode_rate) {
+		prate *= 2;
+		cfg |= ATMEL_HLCDC_CLKSEL;
+	}
+
+	div = DIV_ROUND_UP(prate, mode_rate);
+	if (div < 2)
+		div = 2;
+
+	cfg |= ATMEL_HLCDC_CLKDIV(div);
+
+	regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
+			   ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
+			   ATMEL_HLCDC_CLKPOL, cfg);
+
+	cfg = 0;
+
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		cfg |= ATMEL_HLCDC_VSPOL;
+
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		cfg |= ATMEL_HLCDC_HSPOL;
+
+	regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
+			   ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
+			   ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
+			   ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
+			   ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
+			   ATMEL_HLCDC_GUARDTIME_MASK,
+			   cfg);
+
+	fb = plane->fb;
+	plane->fb = old_fb;
+
+	return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0,
+						  adj->hdisplay, adj->vdisplay,
+						  x << 16, y << 16,
+						  adj->hdisplay << 16,
+						  adj->vdisplay << 16,
+						  adj);
+}
+
+int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y,
+				   struct drm_framebuffer *old_fb)
+{
+	struct drm_plane *plane = c->primary;
+	struct drm_framebuffer *fb = plane->fb;
+	struct drm_display_mode *mode = &c->hwmode;
+
+	plane->fb = old_fb;
+
+	return plane->funcs->update_plane(plane, c, fb,
+					  0, 0,
+					  mode->hdisplay,
+					  mode->vdisplay,
+					  x << 16, y << 16,
+					  mode->hdisplay << 16,
+					  mode->vdisplay << 16);
+}
+
+static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
+{
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
+					const struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc)
+{
+	struct drm_plane *plane;
+
+	atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+	crtc->primary->funcs->disable_plane(crtc->primary);
+
+	drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
+		if (plane->crtc != crtc)
+			continue;
+
+		plane->funcs->disable_plane(crtc->primary);
+		plane->crtc = NULL;
+	}
+}
+
+static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
+	.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
+	.dpms = atmel_hlcdc_crtc_dpms,
+	.mode_set = atmel_hlcdc_crtc_mode_set,
+	.mode_set_base = atmel_hlcdc_crtc_mode_set_base,
+	.prepare = atmel_hlcdc_crtc_prepare,
+	.commit = atmel_hlcdc_crtc_commit,
+	.disable = atmel_hlcdc_crtc_disable,
+};
+
+static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+	drm_crtc_cleanup(c);
+	kfree(crtc);
+}
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
+				       struct drm_file *file)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct drm_pending_vblank_event *event;
+	struct drm_device *dev = c->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event = crtc->event;
+	if (event && event->base.file_priv == file) {
+		event->base.destroy(&event->base);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (crtc->event) {
+		drm_send_vblank_event(dev, crtc->id, crtc->event);
+		drm_vblank_put(dev, crtc->id);
+		crtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
+{
+	drm_handle_vblank(c->dev, 0);
+	atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
+}
+
+static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
+				      struct drm_framebuffer *fb,
+				      struct drm_pending_vblank_event *event,
+				      uint32_t page_flip_flags)
+{
+	struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+	struct atmel_hlcdc_plane_update_req req;
+	struct drm_plane *plane = c->primary;
+	struct drm_device *dev = c->dev;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (crtc->event)
+		ret = -EBUSY;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (ret)
+		return ret;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = 0;
+	req.crtc_y = 0;
+	req.crtc_h = c->mode.crtc_vdisplay;
+	req.crtc_w = c->mode.crtc_hdisplay;
+	req.src_x = c->x << 16;
+	req.src_y = c->y << 16;
+	req.src_w = req.crtc_w << 16;
+	req.src_h = req.crtc_h << 16;
+	req.fb = fb;
+
+	ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
+	if (ret)
+		return ret;
+
+	if (event) {
+		drm_vblank_get(c->dev, crtc->id);
+		spin_lock_irqsave(&dev->event_lock, flags);
+		crtc->event = event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
+
+	ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
+	if (ret)
+		crtc->event = NULL;
+	else
+		plane->fb = fb;
+
+	return ret;
+}
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
+	.page_flip = atmel_hlcdc_crtc_page_flip,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = atmel_hlcdc_crtc_destroy,
+};
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes = dc->planes;
+	struct atmel_hlcdc_crtc *crtc;
+	int ret;
+	int i;
+
+	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+	if (!crtc)
+		return -ENOMEM;
+
+	crtc->dpms = DRM_MODE_DPMS_OFF;
+	crtc->dc = dc;
+
+	ret = drm_crtc_init_with_planes(dev, &crtc->base,
+				&planes->primary->base,
+				planes->cursor ? &planes->cursor->base : NULL,
+				&atmel_hlcdc_crtc_funcs);
+	if (ret < 0)
+		goto fail;
+
+	crtc->id = drm_crtc_index(&crtc->base);
+
+	if (planes->cursor)
+		planes->cursor->base.possible_crtcs = 1 << crtc->id;
+
+	for (i = 0; i < planes->noverlays; i++)
+		planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
+
+	drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+
+	dc->crtc = &crtc->base;
+
+	return 0;
+
+fail:
+	atmel_hlcdc_crtc_destroy(&crtc->base);
+	return ret;
+}
+
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
new file mode 100644
index 0000000..7320a6c
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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.
+ *
+ * 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/irq.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "atmel_hlcdc_dc.h"
+
+#define ATMEL_HLCDC_LAYER_IRQS_OFFSET		8
+
+static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
+	{
+		.name = "base",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x40,
+		.id = 0,
+		.type = ATMEL_HLCDC_BASE_LAYER,
+		.nconfigs = 7,
+		.layout = {
+			.xstride = { 2 },
+			.default_color = 3,
+			.general_config = 4,
+			.disc_pos = 5,
+			.disc_size = 6,
+		},
+	},
+	{
+		.name = "overlay1",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x140,
+		.id = 1,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "overlay2",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x240,
+		.id = 2,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 10,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+	{
+		.name = "high-end-overlay",
+		.formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+		.regs_offset = 0x340,
+		.id = 3,
+		.type = ATMEL_HLCDC_OVERLAY_LAYER,
+		.nconfigs = 42,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.memsize = 4,
+			.xstride = { 5, 7 },
+			.pstride = { 6, 8 },
+			.default_color = 9,
+			.chroma_key = 10,
+			.chroma_key_mask = 11,
+			.general_config = 12,
+			.csc = 14,
+		},
+	},
+	{
+		.name = "cursor",
+		.formats = &atmel_hlcdc_plane_rgb_formats,
+		.regs_offset = 0x440,
+		.id = 4,
+		.type = ATMEL_HLCDC_CURSOR_LAYER,
+		.nconfigs = 10,
+		.max_width = 128,
+		.max_height = 128,
+		.layout = {
+			.pos = 2,
+			.size = 3,
+			.xstride = { 4 },
+			.pstride = { 5 },
+			.default_color = 6,
+			.chroma_key = 7,
+			.chroma_key_mask = 8,
+			.general_config = 9,
+		},
+	},
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
+	.min_width = 0,
+	.min_height = 0,
+	.max_width = 2048,
+	.max_height = 2048,
+	.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
+	.layers = atmel_hlcdc_sama5d3_layers,
+};
+
+static const struct of_device_id atmel_hlcdc_of_match[] = {
+	{
+		.compatible = "atmel,sama5d3-hlcdc",
+		.data = &atmel_hlcdc_dc_sama5d3,
+	},
+	{ /* sentinel */ },
+};
+
+int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
+			      struct drm_display_mode *mode)
+{
+	int vfront_porch = mode->vsync_start - mode->vdisplay;
+	int vback_porch = mode->vtotal - mode->vsync_end;
+	int vsync_len = mode->vsync_end - mode->vsync_start;
+	int hfront_porch = mode->hsync_start - mode->hdisplay;
+	int hback_porch = mode->htotal - mode->hsync_end;
+	int hsync_len = mode->hsync_end - mode->hsync_start;
+
+	if (hsync_len > 0x40 || hsync_len < 1)
+		return MODE_HSYNC;
+
+	if (vsync_len > 0x40 || vsync_len < 1)
+		return MODE_VSYNC;
+
+	if (hfront_porch > 0x200 || hfront_porch < 1 ||
+	    hback_porch > 0x200 || hback_porch < 1 ||
+	    mode->hdisplay < 1)
+		return MODE_H_ILLEGAL;
+
+	if (vfront_porch > 0x40 || vfront_porch < 1 ||
+	    vback_porch > 0x40 || vback_porch < 0 ||
+	    mode->vdisplay < 1)
+		return MODE_V_ILLEGAL;
+
+	return MODE_OK;
+}
+
+static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
+{
+	struct drm_device *dev = data;
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned long status;
+	unsigned int imr, isr;
+	int i;
+
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return IRQ_NONE;
+
+	if (status & ATMEL_HLCDC_SOF)
+		atmel_hlcdc_crtc_irq(dc->crtc);
+
+	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+		struct atmel_hlcdc_layer *layer = dc->layers[i];
+
+		if (!(ATMEL_HLCDC_LAYER_STATUS(i) & status) || !layer)
+			continue;
+
+		atmel_hlcdc_layer_irq(layer);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	if (dc->fbdev) {
+		drm_fbdev_cma_hotplug_event(dc->fbdev);
+	} else {
+		dc->fbdev = drm_fbdev_cma_init(dev, 24,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(dc->fbdev))
+			dc->fbdev = NULL;
+	}
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = atmel_hlcdc_fb_create,
+	.output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+};
+
+static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_planes *planes;
+	int ret;
+	int i;
+
+	drm_mode_config_init(dev);
+
+	ret = atmel_hlcdc_create_outputs(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create panel: %d\n", ret);
+		return ret;
+	}
+
+	planes = atmel_hlcdc_create_planes(dev);
+	if (IS_ERR(planes)) {
+		dev_err(dev->dev, "failed to create planes\n");
+		return PTR_ERR(planes);
+	}
+
+	dc->planes = planes;
+
+	dc->layers[planes->primary->layer.desc->id] =
+						&planes->primary->layer;
+
+	if (planes->cursor)
+		dc->layers[planes->cursor->layer.desc->id] =
+							&planes->cursor->layer;
+
+	for (i = 0; i < planes->noverlays; i++)
+		dc->layers[planes->overlays[i]->layer.desc->id] =
+						&planes->overlays[i]->layer;
+
+	ret = atmel_hlcdc_crtc_create(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to create crtc\n");
+		return ret;
+	}
+
+	dev->mode_config.min_width = dc->desc->min_width;
+	dev->mode_config.min_height = dc->desc->min_height;
+	dev->mode_config.max_width = dc->desc->max_width;
+	dev->mode_config.max_height = dc->desc->max_height;
+	dev->mode_config.funcs = &mode_config_funcs;
+
+	return 0;
+}
+
+static int atmel_hlcdc_dc_load(struct drm_device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev->dev);
+	const struct of_device_id *match;
+	struct atmel_hlcdc_dc *dc;
+	int ret;
+
+	match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "invalid compatible string\n");
+		return -ENODEV;
+	}
+
+	if (!match->data) {
+		dev_err(&pdev->dev, "invalid hlcdc description\n");
+		return -EINVAL;
+	}
+
+	dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
+	if (!dc)
+		return -ENOMEM;
+
+	dc->wq = alloc_ordered_workqueue("atmel-hlcdc-dc", 0);
+	if (!dc->wq)
+		return -ENOMEM;
+
+	dc->desc = match->data;
+	dc->hlcdc = dev_get_drvdata(dev->dev->parent);
+	dev->dev_private = dc;
+
+	ret = clk_prepare_enable(dc->hlcdc->periph_clk);
+	if (ret) {
+		dev_err(dev->dev, "failed to enable periph_clk\n");
+		goto err_destroy_wq;
+	}
+
+	pm_runtime_enable(dev->dev);
+
+	pm_runtime_put_sync(dev->dev);
+
+	ret = atmel_hlcdc_dc_modeset_init(dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize mode setting\n");
+		goto err_periph_clk_disable;
+	}
+
+	ret = drm_vblank_init(dev, 1);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to initialize vblank\n");
+		goto err_periph_clk_disable;
+	}
+
+	pm_runtime_get_sync(dev->dev);
+	ret = drm_irq_install(dev, dc->hlcdc->irq);
+	pm_runtime_put_sync(dev->dev);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to install IRQ handler\n");
+		goto err_periph_clk_disable;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	drm_kms_helper_poll_init(dev);
+
+	/* force connectors detection */
+	drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_periph_clk_disable:
+	pm_runtime_disable(dev->dev);
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+err_destroy_wq:
+	destroy_workqueue(dc->wq);
+
+	return ret;
+}
+
+static void atmel_hlcdc_dc_unload(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	if (dc->fbdev)
+		drm_fbdev_cma_fini(dc->fbdev);
+	flush_workqueue(dc->wq);
+	drm_kms_helper_poll_fini(dev);
+	drm_mode_config_cleanup(dev);
+	drm_vblank_cleanup(dev);
+
+	pm_runtime_get_sync(dev->dev);
+	drm_irq_uninstall(dev);
+	pm_runtime_put_sync(dev->dev);
+
+	dev->dev_private = NULL;
+
+	pm_runtime_disable(dev->dev);
+	clk_disable_unprepare(dc->hlcdc->periph_clk);
+	destroy_workqueue(dc->wq);
+}
+
+static int atmel_hlcdc_dc_connector_plug_all(struct drm_device *dev)
+{
+	struct drm_connector *connector, *failed;
+	int ret;
+
+	mutex_lock(&dev->mode_config.mutex);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		ret = drm_connector_register(connector);
+		if (ret) {
+			failed = connector;
+			goto err;
+		}
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+	return 0;
+
+err:
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (failed == connector)
+			break;
+
+		drm_connector_unregister(connector);
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
+}
+
+static void atmel_hlcdc_dc_connector_unplug_all(struct drm_device *dev)
+{
+	mutex_lock(&dev->mode_config.mutex);
+	drm_connector_unplug_all(dev);
+	mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void atmel_hlcdc_dc_preclose(struct drm_device *dev,
+				    struct drm_file *file)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+		atmel_hlcdc_crtc_cancel_page_flip(crtc, file);
+}
+
+static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	drm_fbdev_cma_restore_mode(dc->fbdev);
+}
+
+static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned int cfg = 0;
+	int i;
+
+	/* Enable interrupts on activated layers */
+	for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+		if (dc->layers[i])
+			cfg |= ATMEL_HLCDC_LAYER_STATUS(i);
+	}
+
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, cfg);
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	unsigned int isr;
+
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
+	regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+}
+
+static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	/* Enable SOF (Start Of Frame) interrupt for vblank counting */
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
+
+	return 0;
+}
+
+static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+	regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
+}
+
+static const struct file_operations fops = {
+	.owner              = THIS_MODULE,
+	.open               = drm_open,
+	.release            = drm_release,
+	.unlocked_ioctl     = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl       = drm_compat_ioctl,
+#endif
+	.poll               = drm_poll,
+	.read               = drm_read,
+	.llseek             = no_llseek,
+	.mmap               = drm_gem_cma_mmap,
+};
+
+static struct drm_driver atmel_hlcdc_dc_driver = {
+	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+	.preclose = atmel_hlcdc_dc_preclose,
+	.lastclose = atmel_hlcdc_dc_lastclose,
+	.irq_handler = atmel_hlcdc_dc_irq_handler,
+	.irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
+	.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
+	.irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
+	.get_vblank_counter = drm_vblank_count,
+	.enable_vblank = atmel_hlcdc_dc_enable_vblank,
+	.disable_vblank = atmel_hlcdc_dc_disable_vblank,
+	.gem_free_object = drm_gem_cma_free_object,
+	.gem_vm_ops = &drm_gem_cma_vm_ops,
+	.dumb_create = drm_gem_cma_dumb_create,
+	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
+	.dumb_destroy = drm_gem_dumb_destroy,
+	.fops = &fops,
+	.name = "atmel-hlcdc",
+	.desc = "Atmel HLCD Controller DRM",
+	.date = "20141504",
+	.major = 1,
+	.minor = 0,
+};
+
+static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
+{
+	struct drm_device *ddev;
+	int ret;
+
+	ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
+	if (!ddev)
+		return -ENOMEM;
+
+	ret = drm_dev_set_unique(ddev, dev_name(ddev->dev));
+	if (ret)
+		goto err_unref;
+
+	ret = atmel_hlcdc_dc_load(ddev);
+	if (ret)
+		goto err_unref;
+
+	ret = drm_dev_register(ddev, 0);
+	if (ret)
+		goto err_unload;
+
+	ret = atmel_hlcdc_dc_connector_plug_all(ddev);
+	if (ret)
+		goto err_unregister;
+
+	return 0;
+
+err_unregister:
+	drm_dev_unregister(ddev);
+
+err_unload:
+	atmel_hlcdc_dc_unload(ddev);
+
+err_unref:
+	drm_dev_unref(ddev);
+
+	return ret;
+}
+
+static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
+{
+	struct drm_device *ddev = platform_get_drvdata(pdev);
+
+	atmel_hlcdc_dc_connector_unplug_all(ddev);
+	drm_dev_unregister(ddev);
+	atmel_hlcdc_dc_unload(ddev);
+	drm_dev_unref(ddev);
+
+	return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
+	{ .compatible = "atmel,hlcdc-display-controller" },
+	{ },
+};
+
+static struct platform_driver atmel_hlcdc_dc_platform_driver = {
+	.probe	= atmel_hlcdc_dc_drm_probe,
+	.remove	= atmel_hlcdc_dc_drm_remove,
+	.driver	= {
+		.name	= "atmel-hlcdc-display-controller",
+		.of_match_table = atmel_hlcdc_dc_of_match,
+	},
+};
+module_platform_driver(atmel_hlcdc_dc_platform_driver);
+
+MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel-hlcdc-dc");
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
new file mode 100644
index 0000000..7bc96af
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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.
+ *
+ * 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 DRM_ATMEL_HLCDC_H
+#define DRM_ATMEL_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/irqdomain.h>
+#include <linux/pwm.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drmP.h>
+
+#include "atmel_hlcdc_layer.h"
+
+#define ATMEL_HLCDC_MAX_LAYERS		5
+
+/**
+ * Atmel HLCDC Display Controller description structure.
+ *
+ * This structure describe the HLCDC IP capabilities and depends on the
+ * HLCDC IP version (or Atmel SoC family).
+ *
+ * @min_width: minimum width supported by the Display Controller
+ * @min_height: minimum height supported by the Display Controller
+ * @max_width: maximum width supported by the Display Controller
+ * @max_height: maximum height supported by the Display Controller
+ * @layers: a layer description table describing available layers
+ * @nlayers: layer description table size
+ */
+struct atmel_hlcdc_dc_desc {
+	int min_width;
+	int min_height;
+	int max_width;
+	int max_height;
+	const struct atmel_hlcdc_layer_desc *layers;
+	int nlayers;
+};
+
+/**
+ * Atmel HLCDC Plane properties.
+ *
+ * This structure stores plane property definitions.
+ *
+ * @alpha: alpha blending (or transparency) property
+ * @rotation: rotation property
+ */
+struct atmel_hlcdc_plane_properties {
+	struct drm_property *alpha;
+	struct drm_property *rotation;
+};
+
+/**
+ * Atmel HLCDC Plane.
+ *
+ * @base: base DRM plane structure
+ * @layer: HLCDC layer structure
+ * @properties: pointer to the property definitions structure
+ * @rotation: current rotation status
+ */
+struct atmel_hlcdc_plane {
+	struct drm_plane base;
+	struct atmel_hlcdc_layer layer;
+	struct atmel_hlcdc_plane_properties *properties;
+	unsigned int rotation;
+};
+
+static inline struct atmel_hlcdc_plane *
+drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
+{
+	return container_of(p, struct atmel_hlcdc_plane, base);
+}
+
+static inline struct atmel_hlcdc_plane *
+atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
+{
+	return container_of(l, struct atmel_hlcdc_plane, layer);
+}
+
+/**
+ * Atmel HLCDC Plane update request structure.
+ *
+ * @crtc_x: x position of the plane relative to the CRTC
+ * @crtc_y: y position of the plane relative to the CRTC
+ * @crtc_w: visible width of the plane
+ * @crtc_h: visible height of the plane
+ * @src_x: x buffer position
+ * @src_y: y buffer position
+ * @src_w: buffer width
+ * @src_h: buffer height
+ * @fb: framebuffer object object
+ * @bpp: bytes per pixel deduced from pixel_format
+ * @offsets: offsets to apply to the GEM buffers
+ * @xstride: value to add to the pixel pointer between each line
+ * @pstride: value to add to the pixel pointer between each pixel
+ * @nplanes: number of planes (deduced from pixel_format)
+ */
+struct atmel_hlcdc_plane_update_req {
+	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_framebuffer *fb;
+
+	/* These fields are private and should not be touched */
+	int bpp[ATMEL_HLCDC_MAX_PLANES];
+	unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int nplanes;
+};
+
+/**
+ * Atmel HLCDC Planes.
+ *
+ * This structure stores the instantiated HLCDC Planes and can be accessed by
+ * the HLCDC Display Controller or the HLCDC CRTC.
+ *
+ * @primary: primary plane
+ * @cursor: hardware cursor plane
+ * @overlays: overlay plane table
+ * @noverlays: number of overlay planes
+ */
+struct atmel_hlcdc_planes {
+	struct atmel_hlcdc_plane *primary;
+	struct atmel_hlcdc_plane *cursor;
+	struct atmel_hlcdc_plane **overlays;
+	int noverlays;
+};
+
+/**
+ * Atmel HLCDC Display Controller.
+ *
+ * @desc: HLCDC Display Controller description
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @fbdev: framebuffer device attached to the Display Controller
+ * @crtc: CRTC provided by the display controller
+ * @planes: instantiated planes
+ * @layers: active HLCDC layer
+ * @wq: display controller workqueue
+ */
+struct atmel_hlcdc_dc {
+	const struct atmel_hlcdc_dc_desc *desc;
+	struct atmel_hlcdc *hlcdc;
+	struct drm_fbdev_cma *fbdev;
+	struct drm_crtc *crtc;
+	struct atmel_hlcdc_planes *planes;
+	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
+	struct workqueue_struct *wq;
+};
+
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
+
+int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
+			      struct drm_display_mode *mode);
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev);
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req,
+				const struct drm_display_mode *mode);
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req);
+
+int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
+				       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,
+				       const struct drm_display_mode *mode);
+
+void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
+				       struct drm_file *file);
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev);
+
+int atmel_hlcdc_create_outputs(struct drm_device *dev);
+
+#endif /* DRM_ATMEL_HLCDC_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
new file mode 100644
index 0000000..063d2a7
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * 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.
+ *
+ * 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/interrupt.h>
+
+#include "atmel_hlcdc_dc.h"
+
+static void
+atmel_hlcdc_layer_fb_flip_release(struct drm_flip_work *work, void *val)
+{
+	struct atmel_hlcdc_layer_fb_flip *flip = val;
+
+	if (flip->fb)
+		drm_framebuffer_unreference(flip->fb);
+	kfree(flip);
+}
+
+static void
+atmel_hlcdc_layer_fb_flip_destroy(struct atmel_hlcdc_layer_fb_flip *flip)
+{
+	if (flip->fb)
+		drm_framebuffer_unreference(flip->fb);
+	kfree(flip->task);
+	kfree(flip);
+}
+
+static void
+atmel_hlcdc_layer_fb_flip_release_queue(struct atmel_hlcdc_layer *layer,
+					struct atmel_hlcdc_layer_fb_flip *flip)
+{
+	int i;
+
+	if (!flip)
+		return;
+
+	for (i = 0; i < layer->max_planes; i++) {
+		if (!flip->dscrs[i])
+			break;
+
+		flip->dscrs[i]->status = 0;
+		flip->dscrs[i] = NULL;
+	}
+
+	drm_flip_work_queue_task(&layer->gc, flip->task);
+	drm_flip_work_commit(&layer->gc, layer->wq);
+}
+
+static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer,
+					   int id)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (id < 0 || id > 1)
+		return;
+
+	slot = &upd->slots[id];
+	bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+	memset(slot->configs, 0,
+	       sizeof(*slot->configs) * layer->desc->nconfigs);
+
+	if (slot->fb_flip) {
+		atmel_hlcdc_layer_fb_flip_release_queue(layer, slot->fb_flip);
+		slot->fb_flip = NULL;
+	}
+}
+
+static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	struct atmel_hlcdc_layer_fb_flip *fb_flip;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	unsigned int cfg;
+	u32 action = 0;
+	int i = 0;
+
+	if (upd->pending < 0 || upd->pending > 1)
+		return;
+
+	slot = &upd->slots[upd->pending];
+
+	for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CFG(layer, cfg),
+			     slot->configs[cfg]);
+		action |= ATMEL_HLCDC_LAYER_UPDATE;
+	}
+
+	fb_flip = slot->fb_flip;
+
+	if (!fb_flip->fb)
+		goto apply;
+
+	if (dma->status == ATMEL_HLCDC_LAYER_DISABLED) {
+		for (i = 0; i < fb_flip->ngems; i++) {
+			dscr = fb_flip->dscrs[i];
+			dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
+				     ATMEL_HLCDC_LAYER_DMA_IRQ |
+				     ATMEL_HLCDC_LAYER_ADD_IRQ |
+				     ATMEL_HLCDC_LAYER_DONE_IRQ;
+
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+				     dscr->addr);
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+				     dscr->ctrl);
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+				     dscr->next);
+		}
+
+		action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
+		dma->status = ATMEL_HLCDC_LAYER_ENABLED;
+	} else {
+		for (i = 0; i < fb_flip->ngems; i++) {
+			dscr =  fb_flip->dscrs[i];
+			dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
+				     ATMEL_HLCDC_LAYER_DMA_IRQ |
+				     ATMEL_HLCDC_LAYER_DSCR_IRQ |
+				     ATMEL_HLCDC_LAYER_DONE_IRQ;
+
+			regmap_write(regmap,
+				     desc->regs_offset +
+				     ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
+				     dscr->next);
+		}
+
+		action |= ATMEL_HLCDC_LAYER_A2Q;
+	}
+
+	/* Release unneeded descriptors */
+	for (i = fb_flip->ngems; i < layer->max_planes; i++) {
+		fb_flip->dscrs[i]->status = 0;
+		fb_flip->dscrs[i] = NULL;
+	}
+
+	dma->queue = fb_flip;
+	slot->fb_flip = NULL;
+
+apply:
+	if (action)
+		regmap_write(regmap,
+			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
+			     action);
+
+	atmel_hlcdc_layer_update_reset(layer, upd->pending);
+
+	upd->pending = -1;
+}
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_fb_flip *flip;
+	unsigned long flags;
+	unsigned int isr, imr;
+	unsigned int status;
+	unsigned int plane_status;
+	u32 flip_status;
+
+	int i;
+
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+	status = imr & isr;
+	if (!status)
+		return;
+
+	spin_lock_irqsave(&layer->lock, flags);
+
+	flip = dma->queue ? dma->queue : dma->cur;
+
+	if (!flip) {
+		spin_unlock_irqrestore(&layer->lock, flags);
+		return;
+	}
+
+	/*
+	 * Set LOADED and DONE flags: they'll be cleared if at least one
+	 * memory plane is not LOADED or DONE.
+	 */
+	flip_status = ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED |
+		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+	for (i = 0; i < flip->ngems; i++) {
+		plane_status = (status >> (8 * i));
+
+		if (plane_status &
+		    (ATMEL_HLCDC_LAYER_ADD_IRQ |
+		     ATMEL_HLCDC_LAYER_DSCR_IRQ) &
+		    ~flip->dscrs[i]->ctrl) {
+			flip->dscrs[i]->status |=
+					ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
+			flip->dscrs[i]->ctrl |=
+					ATMEL_HLCDC_LAYER_ADD_IRQ |
+					ATMEL_HLCDC_LAYER_DSCR_IRQ;
+		}
+
+		if (plane_status &
+		    ATMEL_HLCDC_LAYER_DONE_IRQ &
+		    ~flip->dscrs[i]->ctrl) {
+			flip->dscrs[i]->status |=
+					ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+			flip->dscrs[i]->ctrl |=
+					ATMEL_HLCDC_LAYER_DONE_IRQ;
+		}
+
+		if (plane_status & ATMEL_HLCDC_LAYER_OVR_IRQ)
+			flip->dscrs[i]->status |=
+					ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
+
+		/*
+		 * Clear LOADED and DONE flags if the memory plane is either
+		 * not LOADED or not DONE.
+		 */
+		if (!(flip->dscrs[i]->status &
+		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED))
+			flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
+
+		if (!(flip->dscrs[i]->status &
+		      ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE))
+			flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+
+		/*
+		 * An overrun on one memory plane impact the whole framebuffer
+		 * transfer, hence we set the OVERRUN flag as soon as there's
+		 * one memory plane reporting such an overrun.
+		 */
+		flip_status |= flip->dscrs[i]->status &
+			       ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
+	}
+
+	/* Get changed bits */
+	flip_status ^= flip->status;
+	flip->status |= flip_status;
+
+	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED) {
+		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+		dma->cur = dma->queue;
+		dma->queue = NULL;
+	}
+
+	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE) {
+		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+		dma->cur = NULL;
+	}
+
+	if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN) {
+		regmap_write(regmap,
+			     desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+			     ATMEL_HLCDC_LAYER_RST);
+		if (dma->queue)
+			atmel_hlcdc_layer_fb_flip_release_queue(layer,
+								dma->queue);
+
+		if (dma->cur)
+			atmel_hlcdc_layer_fb_flip_release_queue(layer,
+								dma->cur);
+
+		dma->cur = NULL;
+		dma->queue = NULL;
+	}
+
+	if (!dma->queue) {
+		atmel_hlcdc_layer_update_apply(layer);
+
+		if (!dma->cur)
+			dma->status = ATMEL_HLCDC_LAYER_DISABLED;
+	}
+
+	spin_unlock_irqrestore(&layer->lock, flags);
+}
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	unsigned long flags;
+	unsigned int isr;
+
+	spin_lock_irqsave(&layer->lock, flags);
+
+	/* Disable the layer */
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+
+	/* Clear all pending interrupts */
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+
+	/* Discard current and queued framebuffer transfers. */
+	if (dma->cur) {
+		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+		dma->cur = NULL;
+	}
+
+	if (dma->queue) {
+		atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->queue);
+		dma->queue = NULL;
+	}
+
+	/*
+	 * Then discard the pending update request (if any) to prevent
+	 * DMA irq handler from restarting the DMA channel after it has
+	 * been disabled.
+	 */
+	if (upd->pending >= 0) {
+		atmel_hlcdc_layer_update_reset(layer, upd->pending);
+		upd->pending = -1;
+	}
+
+	dma->status = ATMEL_HLCDC_LAYER_DISABLED;
+
+	spin_unlock_irqrestore(&layer->lock, flags);
+
+	return 0;
+}
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct regmap *regmap = layer->hlcdc->regmap;
+	struct atmel_hlcdc_layer_fb_flip *fb_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+	int i, j = 0;
+
+	fb_flip = kzalloc(sizeof(*fb_flip), GFP_KERNEL);
+	if (!fb_flip)
+		return -ENOMEM;
+
+	fb_flip->task = drm_flip_work_allocate_task(fb_flip, GFP_KERNEL);
+	if (!fb_flip->task) {
+		kfree(fb_flip);
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&layer->lock, flags);
+
+	upd->next = upd->pending ? 0 : 1;
+
+	slot = &upd->slots[upd->next];
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		if (!dma->dscrs[i].status) {
+			fb_flip->dscrs[j++] = &dma->dscrs[i];
+			dma->dscrs[i].status =
+				ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED;
+			if (j == layer->max_planes)
+				break;
+		}
+	}
+
+	if (j < layer->max_planes) {
+		for (i = 0; i < j; i++)
+			fb_flip->dscrs[i]->status = 0;
+	}
+
+	if (j < layer->max_planes) {
+		spin_unlock_irqrestore(&layer->lock, flags);
+		atmel_hlcdc_layer_fb_flip_destroy(fb_flip);
+		return -EBUSY;
+	}
+
+	slot->fb_flip = fb_flip;
+
+	if (upd->pending >= 0) {
+		memcpy(slot->configs,
+		       upd->slots[upd->pending].configs,
+		       layer->desc->nconfigs * sizeof(u32));
+		memcpy(slot->updated_configs,
+		       upd->slots[upd->pending].updated_configs,
+		       DIV_ROUND_UP(layer->desc->nconfigs,
+				    BITS_PER_BYTE * sizeof(unsigned long)) *
+		       sizeof(unsigned long));
+		slot->fb_flip->fb = upd->slots[upd->pending].fb_flip->fb;
+		if (upd->slots[upd->pending].fb_flip->fb) {
+			slot->fb_flip->fb =
+				upd->slots[upd->pending].fb_flip->fb;
+			slot->fb_flip->ngems =
+				upd->slots[upd->pending].fb_flip->ngems;
+			drm_framebuffer_reference(slot->fb_flip->fb);
+		}
+	} else {
+		regmap_bulk_read(regmap,
+				 layer->desc->regs_offset +
+				 ATMEL_HLCDC_LAYER_CFG(layer, 0),
+				 upd->slots[upd->next].configs,
+				 layer->desc->nconfigs);
+	}
+
+	spin_unlock_irqrestore(&layer->lock, flags);
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+	atmel_hlcdc_layer_update_reset(layer, upd->next);
+	upd->next = -1;
+}
+
+void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
+				     struct drm_framebuffer *fb,
+				     unsigned int *offsets)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_fb_flip *fb_flip;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	struct atmel_hlcdc_dma_channel_dscr *dscr;
+	struct drm_framebuffer *old_fb;
+	int nplanes = 0;
+	int i;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (fb)
+		nplanes = drm_format_num_planes(fb->pixel_format);
+
+	if (nplanes > layer->max_planes)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	fb_flip = slot->fb_flip;
+	old_fb = slot->fb_flip->fb;
+
+	for (i = 0; i < nplanes; i++) {
+		struct drm_gem_cma_object *gem;
+
+		dscr = slot->fb_flip->dscrs[i];
+		gem = drm_fb_cma_get_gem_obj(fb, i);
+		dscr->addr = gem->paddr + offsets[i];
+	}
+
+	fb_flip->ngems = nplanes;
+	fb_flip->fb = fb;
+
+	if (fb)
+		drm_framebuffer_reference(fb);
+
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
+}
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+
+	if (upd->next < 0 || upd->next > 1)
+		return;
+
+	if (cfg >= layer->desc->nconfigs)
+		return;
+
+	slot = &upd->slots[upd->next];
+	slot->configs[cfg] &= ~mask;
+	slot->configs[cfg] |= (val & mask);
+	set_bit(cfg, slot->updated_configs);
+}
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	struct atmel_hlcdc_layer_update_slot *slot;
+	unsigned long flags;
+
+	if (upd->next < 0  || upd->next > 1)
+		return;
+
+	slot = &upd->slots[upd->next];
+
+	spin_lock_irqsave(&layer->lock, flags);
+
+	/*
+	 * Release pending update request and replace it by the new one.
+	 */
+	if (upd->pending >= 0)
+		atmel_hlcdc_layer_update_reset(layer, upd->pending);
+
+	upd->pending = upd->next;
+	upd->next = -1;
+
+	if (!dma->queue)
+		atmel_hlcdc_layer_update_apply(layer);
+
+	spin_unlock_irqrestore(&layer->lock, flags);
+
+
+	upd->next = -1;
+}
+
+static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
+				      struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	dma_addr_t dma_addr;
+	int i;
+
+	dma->dscrs = dma_alloc_coherent(dev->dev,
+					layer->max_planes * 4 *
+					sizeof(*dma->dscrs),
+					&dma_addr, GFP_KERNEL);
+	if (!dma->dscrs)
+		return -ENOMEM;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		dscr->next = dma_addr + (i * sizeof(*dscr));
+	}
+
+	return 0;
+}
+
+static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
+					  struct atmel_hlcdc_layer *layer)
+{
+	struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+	int i;
+
+	for (i = 0; i < layer->max_planes * 4; i++) {
+		struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+		dscr->status = 0;
+	}
+
+	dma_free_coherent(dev->dev, layer->max_planes * 4 *
+			  sizeof(*dma->dscrs), dma->dscrs,
+			  dma->dscrs[0].next);
+}
+
+static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
+				struct atmel_hlcdc_layer *layer,
+				const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_layer_update *upd = &layer->update;
+	int updated_size;
+	void *buffer;
+	int i;
+
+	updated_size = DIV_ROUND_UP(desc->nconfigs,
+				    BITS_PER_BYTE *
+				    sizeof(unsigned long));
+
+	buffer = devm_kzalloc(dev->dev,
+			      ((desc->nconfigs * sizeof(u32)) +
+				(updated_size * sizeof(unsigned long))) * 2,
+			      GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i = 0; i < 2; i++) {
+		upd->slots[i].updated_configs = buffer;
+		buffer += updated_size * sizeof(unsigned long);
+		upd->slots[i].configs = buffer;
+		buffer += desc->nconfigs * sizeof(u32);
+	}
+
+	upd->pending = -1;
+	upd->next = -1;
+
+	return 0;
+}
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct regmap *regmap = dc->hlcdc->regmap;
+	unsigned int tmp;
+	int ret;
+	int i;
+
+	layer->hlcdc = dc->hlcdc;
+	layer->wq = dc->wq;
+	layer->desc = desc;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+	for (i = 0; i < desc->formats->nformats; i++) {
+		int nplanes = drm_format_num_planes(desc->formats->formats[i]);
+
+		if (nplanes > layer->max_planes)
+			layer->max_planes = nplanes;
+	}
+
+	spin_lock_init(&layer->lock);
+	drm_flip_work_init(&layer->gc, desc->name,
+			   atmel_hlcdc_layer_fb_flip_release);
+	ret = atmel_hlcdc_layer_dma_init(dev, layer);
+	if (ret)
+		return ret;
+
+	ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
+	if (ret)
+		return ret;
+
+	/* Flush Status Register */
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
+		    &tmp);
+
+	tmp = 0;
+	for (i = 0; i < layer->max_planes; i++)
+		tmp |= (ATMEL_HLCDC_LAYER_DMA_IRQ |
+			ATMEL_HLCDC_LAYER_DSCR_IRQ |
+			ATMEL_HLCDC_LAYER_ADD_IRQ |
+			ATMEL_HLCDC_LAYER_DONE_IRQ |
+			ATMEL_HLCDC_LAYER_OVR_IRQ) << (8 * i);
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER, tmp);
+
+	return 0;
+}
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer)
+{
+	const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+	struct regmap *regmap = layer->hlcdc->regmap;
+
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+		     0xffffffff);
+	regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+		     ATMEL_HLCDC_LAYER_RST);
+
+	atmel_hlcdc_layer_dma_cleanup(dev, layer);
+	drm_flip_work_cleanup(&layer->gc);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
new file mode 100644
index 0000000..27e56c0
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * 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.
+ *
+ * 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 DRM_ATMEL_HLCDC_LAYER_H
+#define DRM_ATMEL_HLCDC_LAYER_H
+
+#include <linux/mfd/atmel-hlcdc.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drmP.h>
+
+#define ATMEL_HLCDC_LAYER_CHER			0x0
+#define ATMEL_HLCDC_LAYER_CHDR			0x4
+#define ATMEL_HLCDC_LAYER_CHSR			0x8
+#define ATMEL_HLCDC_LAYER_DMA_CHAN		BIT(0)
+#define ATMEL_HLCDC_LAYER_UPDATE		BIT(1)
+#define ATMEL_HLCDC_LAYER_A2Q			BIT(2)
+#define ATMEL_HLCDC_LAYER_RST			BIT(8)
+
+#define ATMEL_HLCDC_LAYER_IER			0xc
+#define ATMEL_HLCDC_LAYER_IDR			0x10
+#define ATMEL_HLCDC_LAYER_IMR			0x14
+#define ATMEL_HLCDC_LAYER_ISR			0x18
+#define ATMEL_HLCDC_LAYER_DFETCH		BIT(0)
+#define ATMEL_HLCDC_LAYER_LFETCH		BIT(1)
+#define ATMEL_HLCDC_LAYER_DMA_IRQ		BIT(2)
+#define ATMEL_HLCDC_LAYER_DSCR_IRQ		BIT(3)
+#define ATMEL_HLCDC_LAYER_ADD_IRQ		BIT(4)
+#define ATMEL_HLCDC_LAYER_DONE_IRQ		BIT(5)
+#define ATMEL_HLCDC_LAYER_OVR_IRQ		BIT(6)
+
+#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n)		(((n) * 0x10) + 0x1c)
+#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n)		(((n) * 0x10) + 0x20)
+#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n)		(((n) * 0x10) + 0x24)
+#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n)		(((n) * 0x10) + 0x28)
+#define ATMEL_HLCDC_LAYER_CFG(p, c)		(((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
+
+#define ATMEL_HLCDC_LAYER_DMA_CFG_ID		0
+#define ATMEL_HLCDC_LAYER_DMA_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
+#define ATMEL_HLCDC_LAYER_DMA_SIF		BIT(0)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_MASK		GENMASK(5, 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_SINGLE	(0 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR4	(1 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR8	(2 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16	(3 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_DLBO		BIT(8)
+#define ATMEL_HLCDC_LAYER_DMA_ROTDIS		BIT(12)
+#define ATMEL_HLCDC_LAYER_DMA_LOCKDIS		BIT(13)
+
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID		1
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
+#define ATMEL_HLCDC_LAYER_RGB			(0 << 0)
+#define ATMEL_HLCDC_LAYER_CLUT			(1 << 0)
+#define ATMEL_HLCDC_LAYER_YUV			(2 << 0)
+#define ATMEL_HLCDC_RGB_MODE(m)			(((m) & 0xf) << 4)
+#define ATMEL_HLCDC_CLUT_MODE(m)		(((m) & 0x3) << 8)
+#define ATMEL_HLCDC_YUV_MODE(m)			(((m) & 0xf) << 12)
+#define ATMEL_HLCDC_YUV422ROT			BIT(16)
+#define ATMEL_HLCDC_YUV422SWP			BIT(17)
+#define ATMEL_HLCDC_DSCALEOPT			BIT(20)
+
+#define ATMEL_HLCDC_XRGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
+#define ATMEL_HLCDC_ARGB4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
+#define ATMEL_HLCDC_RGBA4444_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
+#define ATMEL_HLCDC_RGB565_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
+#define ATMEL_HLCDC_ARGB1555_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
+#define ATMEL_HLCDC_XRGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
+#define ATMEL_HLCDC_RGB888_MODE			(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
+#define ATMEL_HLCDC_ARGB8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
+#define ATMEL_HLCDC_RGBA8888_MODE		(ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
+
+#define ATMEL_HLCDC_AYUV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
+#define ATMEL_HLCDC_YUYV_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
+#define ATMEL_HLCDC_UYVY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
+#define ATMEL_HLCDC_YVYU_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
+#define ATMEL_HLCDC_VYUY_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
+#define ATMEL_HLCDC_NV61_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
+#define ATMEL_HLCDC_YUV422_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
+#define ATMEL_HLCDC_NV21_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
+#define ATMEL_HLCDC_YUV420_MODE			(ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
+
+#define ATMEL_HLCDC_LAYER_POS_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
+#define ATMEL_HLCDC_LAYER_SIZE_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
+#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
+#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
+#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
+#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
+#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
+#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
+
+#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
+#define ATMEL_HLCDC_LAYER_CRKEY			BIT(0)
+#define ATMEL_HLCDC_LAYER_INV			BIT(1)
+#define ATMEL_HLCDC_LAYER_ITER2BL		BIT(2)
+#define ATMEL_HLCDC_LAYER_ITER			BIT(3)
+#define ATMEL_HLCDC_LAYER_REVALPHA		BIT(4)
+#define ATMEL_HLCDC_LAYER_GAEN			BIT(5)
+#define ATMEL_HLCDC_LAYER_LAEN			BIT(6)
+#define ATMEL_HLCDC_LAYER_OVR			BIT(7)
+#define ATMEL_HLCDC_LAYER_DMA			BIT(8)
+#define ATMEL_HLCDC_LAYER_REP			BIT(9)
+#define ATMEL_HLCDC_LAYER_DSTKEY		BIT(10)
+#define ATMEL_HLCDC_LAYER_DISCEN		BIT(11)
+#define ATMEL_HLCDC_LAYER_GA_SHIFT		16
+#define ATMEL_HLCDC_LAYER_GA_MASK		GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
+
+#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)		ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
+
+#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
+
+#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p)	ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
+
+#define ATMEL_HLCDC_MAX_PLANES			3
+
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED	BIT(0)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED	BIT(1)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE	BIT(2)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN	BIT(3)
+
+/**
+ * Atmel HLCDC Layer registers layout structure
+ *
+ * Each HLCDC layer has its own register organization and a given register
+ * can be placed differently on 2 different layers depending on its
+ * capabilities.
+ * This structure stores common registers layout for a given layer and is
+ * used by HLCDC layer code to choose the appropriate register to write to
+ * or to read from.
+ *
+ * For all fields, a value of zero means "unsupported".
+ *
+ * See Atmel's datasheet for a detailled description of these registers.
+ *
+ * @xstride: xstride registers
+ * @pstride: pstride registers
+ * @pos: position register
+ * @size: displayed size register
+ * @memsize: memory size register
+ * @default_color: default color register
+ * @chroma_key: chroma key register
+ * @chroma_key_mask: chroma key mask register
+ * @general_config: general layer config register
+ * @disc_pos: discard area position register
+ * @disc_size: discard area size register
+ * @csc: color space conversion register
+ */
+struct atmel_hlcdc_layer_cfg_layout {
+	int xstride[ATMEL_HLCDC_MAX_PLANES];
+	int pstride[ATMEL_HLCDC_MAX_PLANES];
+	int pos;
+	int size;
+	int memsize;
+	int default_color;
+	int chroma_key;
+	int chroma_key_mask;
+	int general_config;
+	int disc_pos;
+	int disc_size;
+	int csc;
+};
+
+/**
+ * Atmel HLCDC framebuffer flip structure
+ *
+ * This structure is allocated when someone asked for a layer update (most
+ * likely a DRM plane update, either primary, overlay or cursor plane) and
+ * released when the layer do not need to reference the framebuffer object
+ * anymore (i.e. the layer was disabled or updated).
+ *
+ * @dscrs: DMA descriptors
+ * @fb: the referenced framebuffer object
+ * @ngems: number of GEM objects referenced by the fb element
+ * @status: fb flip operation status
+ */
+struct atmel_hlcdc_layer_fb_flip {
+	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+	struct drm_flip_task *task;
+	struct drm_framebuffer *fb;
+	int ngems;
+	u32 status;
+};
+
+/**
+ * Atmel HLCDC DMA descriptor structure
+ *
+ * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
+ *
+ * The structure fields must remain in this specific order, because they're
+ * used by the HLCDC DMA engine, which expect them in this order.
+ * HLCDC DMA descriptors must be aligned on 64 bits.
+ *
+ * @addr: buffer DMA address
+ * @ctrl: DMA transfer options
+ * @next: next DMA descriptor to fetch
+ * @gem_flip: the attached gem_flip operation
+ */
+struct atmel_hlcdc_dma_channel_dscr {
+	dma_addr_t addr;
+	u32 ctrl;
+	dma_addr_t next;
+	u32 status;
+} __aligned(sizeof(u64));
+
+/**
+ * Atmel HLCDC layer types
+ */
+enum atmel_hlcdc_layer_type {
+	ATMEL_HLCDC_BASE_LAYER,
+	ATMEL_HLCDC_OVERLAY_LAYER,
+	ATMEL_HLCDC_CURSOR_LAYER,
+	ATMEL_HLCDC_PP_LAYER,
+};
+
+/**
+ * Atmel HLCDC Supported formats structure
+ *
+ * This structure list all the formats supported by a given layer.
+ *
+ * @nformats: number of supported formats
+ * @formats: supported formats
+ */
+struct atmel_hlcdc_formats {
+	int nformats;
+	uint32_t *formats;
+};
+
+/**
+ * Atmel HLCDC Layer description structure
+ *
+ * This structure describe the capabilities provided by a given layer.
+ *
+ * @name: layer name
+ * @type: layer type
+ * @id: layer id
+ * @regs_offset: offset of the layer registers from the HLCDC registers base
+ * @nconfigs: number of config registers provided by this layer
+ * @formats: supported formats
+ * @layout: config registers layout
+ * @max_width: maximum width supported by this layer (0 means unlimited)
+ * @max_height: maximum height supported by this layer (0 means unlimited)
+ */
+struct atmel_hlcdc_layer_desc {
+	const char *name;
+	enum atmel_hlcdc_layer_type type;
+	int id;
+	int regs_offset;
+	int nconfigs;
+	struct atmel_hlcdc_formats *formats;
+	struct atmel_hlcdc_layer_cfg_layout layout;
+	int max_width;
+	int max_height;
+};
+
+/**
+ * Atmel HLCDC Layer Update Slot structure
+ *
+ * This structure stores layer update requests to be applied on next frame.
+ * This is the base structure behind the atomic layer update infrastructure.
+ *
+ * Atomic layer update provides a way to update all layer's parameters
+ * simultaneously. This is needed to avoid incompatible sequential updates
+ * like this one:
+ * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
+ *    (2 planes/buffers)
+ * 2) the format update is applied but the DMA channel for the second
+ *    plane/buffer is not enabled
+ * 3) enable the DMA channel for the second plane
+ *
+ * @fb_flip: fb_flip object
+ * @updated_configs: bitmask used to record modified configs
+ * @configs: new config values
+ */
+struct atmel_hlcdc_layer_update_slot {
+	struct atmel_hlcdc_layer_fb_flip *fb_flip;
+	unsigned long *updated_configs;
+	u32 *configs;
+};
+
+/**
+ * Atmel HLCDC Layer Update structure
+ *
+ * This structure provides a way to queue layer update requests.
+ *
+ * At a given time there is at most:
+ *  - one pending update request, which means the update request has been
+ *    committed (or validated) and is waiting for the DMA channel(s) to be
+ *    available
+ *  - one request being prepared, which means someone started a layer update
+ *    but has not committed it yet. There cannot be more than one started
+ *    request, because the update lock is taken when starting a layer update
+ *    and release when committing or rolling back the request.
+ *
+ * @slots: update slots. One is used for pending request and the other one
+ *	   for started update request
+ * @pending: the pending slot index or -1 if no request is pending
+ * @next: the started update slot index or -1 no update has been started
+ */
+struct atmel_hlcdc_layer_update {
+	struct atmel_hlcdc_layer_update_slot slots[2];
+	int pending;
+	int next;
+};
+
+enum atmel_hlcdc_layer_dma_channel_status {
+	ATMEL_HLCDC_LAYER_DISABLED,
+	ATMEL_HLCDC_LAYER_ENABLED,
+	ATMEL_HLCDC_LAYER_DISABLING,
+};
+
+/**
+ * Atmel HLCDC Layer DMA channel structure
+ *
+ * This structure stores information on the DMA channel associated to a
+ * given layer.
+ *
+ * @status: DMA channel status
+ * @cur: current framebuffer
+ * @queue: next framebuffer
+ * @dscrs: allocated DMA descriptors
+ */
+struct atmel_hlcdc_layer_dma_channel {
+	enum atmel_hlcdc_layer_dma_channel_status status;
+	struct atmel_hlcdc_layer_fb_flip *cur;
+	struct atmel_hlcdc_layer_fb_flip *queue;
+	struct atmel_hlcdc_dma_channel_dscr *dscrs;
+};
+
+/**
+ * Atmel HLCDC Layer structure
+ *
+ * This structure stores information on the layer instance.
+ *
+ * @desc: layer description
+ * @max_planes: maximum planes/buffers that can be associated with this layer.
+ *	       This depends on the supported formats.
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @dma: dma channel
+ * @gc: fb flip garbage collector
+ * @update: update handler
+ * @lock: layer lock
+ */
+struct atmel_hlcdc_layer {
+	const struct atmel_hlcdc_layer_desc *desc;
+	int max_planes;
+	struct atmel_hlcdc *hlcdc;
+	struct workqueue_struct *wq;
+	struct drm_flip_work gc;
+	struct atmel_hlcdc_layer_dma_channel dma;
+	struct atmel_hlcdc_layer_update update;
+	spinlock_t lock;
+};
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+			   struct atmel_hlcdc_layer *layer,
+			   const struct atmel_hlcdc_layer_desc *desc);
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+			       struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+				  u32 mask, u32 val);
+
+void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
+				     struct drm_framebuffer *fb,
+				     unsigned int *offsets);
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+					   void (*finished)(void *data),
+					   void *finished_data);
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
+
+#endif /* DRM_ATMEL_HLCDC_LAYER_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
new file mode 100644
index 0000000..c402192
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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.
+ *
+ * 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_graph.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC RGB output mode
+ */
+enum atmel_hlcdc_connector_rgb_mode {
+	ATMEL_HLCDC_CONNECTOR_RGB444,
+	ATMEL_HLCDC_CONNECTOR_RGB565,
+	ATMEL_HLCDC_CONNECTOR_RGB666,
+	ATMEL_HLCDC_CONNECTOR_RGB888,
+};
+
+/**
+ * Atmel HLCDC RGB connector structure
+ *
+ * This structure stores RGB slave device information.
+ *
+ * @connector: DRM connector
+ * @encoder: DRM encoder
+ * @dc: pointer to the atmel_hlcdc_dc structure
+ * @dpms: current DPMS mode
+ */
+struct atmel_hlcdc_rgb_output {
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct atmel_hlcdc_dc *dc;
+	int dpms;
+};
+
+static inline struct atmel_hlcdc_rgb_output *
+drm_connector_to_atmel_hlcdc_rgb_output(struct drm_connector *connector)
+{
+	return container_of(connector, struct atmel_hlcdc_rgb_output,
+			    connector);
+}
+
+static inline struct atmel_hlcdc_rgb_output *
+drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
+}
+
+/**
+ * Atmel HLCDC Panel device structure
+ *
+ * This structure is specialization of the slave device structure to
+ * interface with drm panels.
+ *
+ * @base: base slave device fields
+ * @panel: drm panel attached to this slave device
+ */
+struct atmel_hlcdc_panel {
+	struct atmel_hlcdc_rgb_output base;
+	struct drm_panel *panel;
+};
+
+static inline struct atmel_hlcdc_panel *
+atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output)
+{
+	return container_of(output, struct atmel_hlcdc_panel, base);
+}
+
+static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
+					   int mode)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
+	struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	if (mode == rgb->dpms)
+		return;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		drm_panel_disable(panel->panel);
+	else
+		drm_panel_enable(panel->panel);
+
+	rgb->dpms = mode;
+}
+
+static bool
+atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
+				     const struct drm_display_mode *mode,
+				     struct drm_display_mode *adjusted)
+{
+	return true;
+}
+
+static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
+{
+	atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void
+atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
+				 struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
+	struct drm_display_info *info = &rgb->connector.display_info;
+	unsigned int cfg;
+
+	cfg = 0;
+
+	if (info->num_bus_formats) {
+		switch (info->bus_formats[0]) {
+		case MEDIA_BUS_FMT_RGB666_1X18:
+			cfg |= ATMEL_HLCDC_CONNECTOR_RGB666 << 8;
+			break;
+		case MEDIA_BUS_FMT_RGB888_1X24:
+			cfg |= ATMEL_HLCDC_CONNECTOR_RGB888 << 8;
+			break;
+		default:
+			break;
+		}
+	}
+
+	regmap_update_bits(rgb->dc->hlcdc->regmap, ATMEL_HLCDC_CFG(5),
+			   ATMEL_HLCDC_MODE_MASK,
+			   cfg);
+}
+
+static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
+	.dpms = atmel_hlcdc_panel_encoder_dpms,
+	.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
+	.prepare = atmel_hlcdc_panel_encoder_prepare,
+	.commit = atmel_hlcdc_panel_encoder_commit,
+	.mode_set = atmel_hlcdc_rgb_encoder_mode_set,
+};
+
+static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+	memset(encoder, 0, sizeof(*encoder));
+}
+
+static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
+	.destroy = atmel_hlcdc_rgb_encoder_destroy,
+};
+
+static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_connector_to_atmel_hlcdc_rgb_output(connector);
+	struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+	return panel->panel->funcs->get_modes(panel->panel);
+}
+
+static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_connector_to_atmel_hlcdc_rgb_output(connector);
+
+	return atmel_hlcdc_dc_mode_valid(rgb->dc, mode);
+}
+
+
+
+static struct drm_encoder *
+atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_connector_to_atmel_hlcdc_rgb_output(connector);
+
+	return &rgb->encoder;
+}
+
+static struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
+	.get_modes = atmel_hlcdc_panel_get_modes,
+	.mode_valid = atmel_hlcdc_rgb_mode_valid,
+	.best_encoder = atmel_hlcdc_rgb_best_encoder,
+};
+
+static enum drm_connector_status
+atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void
+atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
+{
+	struct atmel_hlcdc_rgb_output *rgb =
+			drm_connector_to_atmel_hlcdc_rgb_output(connector);
+	struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+	drm_panel_detach(panel->panel);
+	drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = atmel_hlcdc_panel_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = atmel_hlcdc_panel_connector_destroy,
+};
+
+static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
+					   struct of_endpoint *ep)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct device_node *np;
+	struct drm_panel *p = NULL;
+	struct atmel_hlcdc_panel *panel;
+	int ret;
+
+	np = of_graph_get_remote_port_parent(ep->local_node);
+	if (!np)
+		return -EINVAL;
+
+	p = of_drm_find_panel(np);
+	of_node_put(np);
+
+	if (!p)
+		return -EPROBE_DEFER;
+
+	panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
+	if (!panel)
+		return -EINVAL;
+
+	panel->base.dpms = DRM_MODE_DPMS_OFF;
+
+	panel->base.dc = dc;
+
+	drm_encoder_helper_add(&panel->base.encoder,
+			       &atmel_hlcdc_panel_encoder_helper_funcs);
+	ret = drm_encoder_init(dev, &panel->base.encoder,
+			       &atmel_hlcdc_panel_encoder_funcs,
+			       DRM_MODE_ENCODER_LVDS);
+	if (ret)
+		return ret;
+
+	panel->base.connector.dpms = DRM_MODE_DPMS_OFF;
+	panel->base.connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+	drm_connector_helper_add(&panel->base.connector,
+				 &atmel_hlcdc_panel_connector_helper_funcs);
+	ret = drm_connector_init(dev, &panel->base.connector,
+				 &atmel_hlcdc_panel_connector_funcs,
+				 DRM_MODE_CONNECTOR_LVDS);
+	if (ret)
+		goto err_encoder_cleanup;
+
+	drm_mode_connector_attach_encoder(&panel->base.connector,
+					  &panel->base.encoder);
+	panel->base.encoder.possible_crtcs = 0x1;
+
+	drm_panel_attach(p, &panel->base.connector);
+	panel->panel = p;
+
+	return 0;
+
+err_encoder_cleanup:
+	drm_encoder_cleanup(&panel->base.encoder);
+
+	return ret;
+}
+
+int atmel_hlcdc_create_outputs(struct drm_device *dev)
+{
+	struct device_node *port_np, *np;
+	struct of_endpoint ep;
+	int ret;
+
+	port_np = of_get_child_by_name(dev->dev->of_node, "port");
+	if (!port_np)
+		return -EINVAL;
+
+	np = of_get_child_by_name(port_np, "endpoint");
+	of_node_put(port_np);
+
+	if (!np)
+		return -EINVAL;
+
+	ret = of_graph_parse_endpoint(np, &ep);
+	of_node_put(port_np);
+
+	if (ret)
+		return ret;
+
+	/* We currently only support panel output */
+	return atmel_hlcdc_create_panel_output(dev, &ep);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
new file mode 100644
index 0000000..c5892dc
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -0,0 +1,856 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * 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.
+ *
+ * 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 "atmel_hlcdc_dc.h"
+
+#define SUBPIXEL_MASK			0xffff
+
+static uint32_t rgb_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
+	.formats = rgb_formats,
+	.nformats = ARRAY_SIZE(rgb_formats),
+};
+
+static uint32_t rgb_and_yuv_formats[] = {
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_AYUV,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_VYUY,
+	DRM_FORMAT_NV21,
+	DRM_FORMAT_NV61,
+	DRM_FORMAT_YUV422,
+	DRM_FORMAT_YUV420,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
+	.formats = rgb_and_yuv_formats,
+	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
+};
+
+static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB4444:
+		*mode = ATMEL_HLCDC_XRGB4444_MODE;
+		break;
+	case DRM_FORMAT_ARGB4444:
+		*mode = ATMEL_HLCDC_ARGB4444_MODE;
+		break;
+	case DRM_FORMAT_RGBA4444:
+		*mode = ATMEL_HLCDC_RGBA4444_MODE;
+		break;
+	case DRM_FORMAT_RGB565:
+		*mode = ATMEL_HLCDC_RGB565_MODE;
+		break;
+	case DRM_FORMAT_RGB888:
+		*mode = ATMEL_HLCDC_RGB888_MODE;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		*mode = ATMEL_HLCDC_ARGB1555_MODE;
+		break;
+	case DRM_FORMAT_XRGB8888:
+		*mode = ATMEL_HLCDC_XRGB8888_MODE;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		*mode = ATMEL_HLCDC_ARGB8888_MODE;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		*mode = ATMEL_HLCDC_RGBA8888_MODE;
+		break;
+	case DRM_FORMAT_AYUV:
+		*mode = ATMEL_HLCDC_AYUV_MODE;
+		break;
+	case DRM_FORMAT_YUYV:
+		*mode = ATMEL_HLCDC_YUYV_MODE;
+		break;
+	case DRM_FORMAT_UYVY:
+		*mode = ATMEL_HLCDC_UYVY_MODE;
+		break;
+	case DRM_FORMAT_YVYU:
+		*mode = ATMEL_HLCDC_YVYU_MODE;
+		break;
+	case DRM_FORMAT_VYUY:
+		*mode = ATMEL_HLCDC_VYUY_MODE;
+		break;
+	case DRM_FORMAT_NV21:
+		*mode = ATMEL_HLCDC_NV21_MODE;
+		break;
+	case DRM_FORMAT_NV61:
+		*mode = ATMEL_HLCDC_NV61_MODE;
+		break;
+	case DRM_FORMAT_YUV420:
+		*mode = ATMEL_HLCDC_YUV420_MODE;
+		break;
+	case DRM_FORMAT_YUV422:
+		*mode = ATMEL_HLCDC_YUV422_MODE;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static bool atmel_hlcdc_format_embedds_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,
+	0x1635300c,
+	0x000000f9,
+	0x1b362c08,
+	0x000000fb,
+	0x1f372804,
+	0x000000fe,
+	0x24382400,
+	0x00000000,
+	0x28371ffe,
+	0x00000004,
+	0x2c361bfb,
+	0x00000008,
+	0x303516f9,
+	0x0000000c,
+};
+
+static u32 heo_downscaling_ycoef[] = {
+	0x00123737,
+	0x00173732,
+	0x001b382d,
+	0x001f3928,
+	0x00243824,
+	0x0028391f,
+	0x002d381b,
+	0x00323717,
+};
+
+static u32 heo_upscaling_xcoef[] = {
+	0xf74949f7,
+	0x00000000,
+	0xf55f33fb,
+	0x000000fe,
+	0xf5701efe,
+	0x000000ff,
+	0xf87c0dff,
+	0x00000000,
+	0x00800000,
+	0x00000000,
+	0x0d7cf800,
+	0x000000ff,
+	0x1e70f5ff,
+	0x000000fe,
+	0x335ff5fe,
+	0x000000fb,
+};
+
+static u32 heo_upscaling_ycoef[] = {
+	0x00004040,
+	0x00075920,
+	0x00056f0c,
+	0x00027b03,
+	0x00008000,
+	0x00037b02,
+	0x000c6f05,
+	0x00205907,
+};
+
+static void
+atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (layout->size)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->size,
+					     0xffffffff,
+					     (req->crtc_w - 1) |
+					     ((req->crtc_h - 1) << 16));
+
+	if (layout->memsize)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->memsize,
+					     0xffffffff,
+					     (req->src_w - 1) |
+					     ((req->src_h - 1) << 16));
+
+	if (layout->pos)
+		atmel_hlcdc_layer_update_cfg(&plane->layer,
+					     layout->pos,
+					     0xffffffff,
+					     req->crtc_x |
+					     (req->crtc_y  << 16));
+
+	/* TODO: rework the rescaling part */
+	if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
+		u32 factor_reg = 0;
+
+		if (req->crtc_w != req->src_w) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_xcoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_xcoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     17 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= factor | 0x80000000;
+		}
+
+		if (req->crtc_h != req->src_h) {
+			int i;
+			u32 factor;
+			u32 *coeff_tab = heo_upscaling_ycoef;
+			u32 max_memsize;
+
+			if (req->crtc_w < req->src_w)
+				coeff_tab = heo_downscaling_ycoef;
+			for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
+				atmel_hlcdc_layer_update_cfg(&plane->layer,
+							     33 + i,
+							     0xffffffff,
+							     coeff_tab[i]);
+			factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+				 req->crtc_w;
+			factor++;
+			max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+				      2048;
+			if (max_memsize > req->src_w)
+				factor--;
+			factor_reg |= (factor << 16) | 0x80000000;
+		}
+
+		atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
+					     factor_reg);
+	}
+}
+
+static void
+atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
+
+	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
+		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
+		       ATMEL_HLCDC_LAYER_ITER;
+
+		if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))
+			cfg |= ATMEL_HLCDC_LAYER_LAEN;
+		else
+			cfg |= ATMEL_HLCDC_LAYER_GAEN;
+	}
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
+				     ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
+				     ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
+				     ATMEL_HLCDC_LAYER_ITER2BL |
+				     ATMEL_HLCDC_LAYER_ITER |
+				     ATMEL_HLCDC_LAYER_GAEN |
+				     ATMEL_HLCDC_LAYER_LAEN |
+				     ATMEL_HLCDC_LAYER_OVR |
+				     ATMEL_HLCDC_LAYER_DMA, cfg);
+}
+
+static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	u32 cfg;
+	int ret;
+
+	ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg);
+	if (ret)
+		return;
+
+	if ((req->fb->pixel_format == DRM_FORMAT_YUV422 ||
+	     req->fb->pixel_format == DRM_FORMAT_NV61) &&
+	    (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
+		cfg |= ATMEL_HLCDC_YUV422ROT;
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
+				     0xffffffff,
+				     cfg);
+
+	/*
+	 * Rotation optimization is not working on RGB888 (rotation is still
+	 * working but without any optimization).
+	 */
+	if (req->fb->pixel_format == DRM_FORMAT_RGB888)
+		cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
+	else
+		cfg = 0;
+
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     ATMEL_HLCDC_LAYER_DMA_CFG_ID,
+				     ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
+}
+
+static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_layer *layer = &plane->layer;
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+							&layer->desc->layout;
+	int i;
+
+	atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets);
+
+	for (i = 0; i < req->nplanes; i++) {
+		if (layout->xstride[i]) {
+			atmel_hlcdc_layer_update_cfg(&plane->layer,
+						layout->xstride[i],
+						0xffffffff,
+						req->xstride[i]);
+		}
+
+		if (layout->pstride[i]) {
+			atmel_hlcdc_layer_update_cfg(&plane->layer,
+						layout->pstride[i],
+						0xffffffff,
+						req->pstride[i]);
+		}
+	}
+}
+
+static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req,
+				const struct drm_display_mode *mode)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	const struct atmel_hlcdc_layer_cfg_layout *layout =
+						&plane->layer.desc->layout;
+
+	if (!layout->size &&
+	    (mode->hdisplay != req->crtc_w ||
+	     mode->vdisplay != req->crtc_h))
+		return -EINVAL;
+
+	if (plane->layer.desc->max_height &&
+	    req->crtc_h > plane->layer.desc->max_height)
+		return -EINVAL;
+
+	if (plane->layer.desc->max_width &&
+	    req->crtc_w > plane->layer.desc->max_width)
+		return -EINVAL;
+
+	if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
+	    (!layout->memsize ||
+	     atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)))
+		return -EINVAL;
+
+	if (req->crtc_x < 0 || req->crtc_y < 0)
+		return -EINVAL;
+
+	if (req->crtc_w + req->crtc_x > mode->hdisplay ||
+	    req->crtc_h + req->crtc_y > mode->vdisplay)
+		return -EINVAL;
+
+	return 0;
+}
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req,
+				const struct drm_display_mode *mode)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	unsigned int patched_crtc_w;
+	unsigned int patched_crtc_h;
+	unsigned int patched_src_w;
+	unsigned int patched_src_h;
+	unsigned int tmp;
+	int x_offset = 0;
+	int y_offset = 0;
+	int hsub = 1;
+	int vsub = 1;
+	int i;
+
+	if ((req->src_x | req->src_y | req->src_w | req->src_h) &
+	    SUBPIXEL_MASK)
+		return -EINVAL;
+
+	req->src_x >>= 16;
+	req->src_y >>= 16;
+	req->src_w >>= 16;
+	req->src_h >>= 16;
+
+	req->nplanes = drm_format_num_planes(req->fb->pixel_format);
+	if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
+		return -EINVAL;
+
+	/*
+	 * Swap width and size in case of 90 or 270 degrees rotation
+	 */
+	if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
+		tmp = req->crtc_w;
+		req->crtc_w = req->crtc_h;
+		req->crtc_h = tmp;
+		tmp = req->src_w;
+		req->src_w = req->src_h;
+		req->src_h = tmp;
+	}
+
+	if (req->crtc_x + req->crtc_w > mode->hdisplay)
+		patched_crtc_w = mode->hdisplay - req->crtc_x;
+	else
+		patched_crtc_w = req->crtc_w;
+
+	if (req->crtc_x < 0) {
+		patched_crtc_w += req->crtc_x;
+		x_offset = -req->crtc_x;
+		req->crtc_x = 0;
+	}
+
+	if (req->crtc_y + req->crtc_h > mode->vdisplay)
+		patched_crtc_h = mode->vdisplay - req->crtc_y;
+	else
+		patched_crtc_h = req->crtc_h;
+
+	if (req->crtc_y < 0) {
+		patched_crtc_h += req->crtc_y;
+		y_offset = -req->crtc_y;
+		req->crtc_y = 0;
+	}
+
+	patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
+					  req->crtc_w);
+	patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
+					  req->crtc_h);
+
+	hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format);
+	vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format);
+
+	for (i = 0; i < req->nplanes; i++) {
+		unsigned int offset = 0;
+		int xdiv = i ? hsub : 1;
+		int ydiv = i ? vsub : 1;
+
+		req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i);
+		if (!req->bpp[i])
+			return -EINVAL;
+
+		switch (plane->rotation & 0xf) {
+		case BIT(DRM_ROTATE_90):
+			offset = ((y_offset + req->src_y + patched_src_w - 1) /
+				  ydiv) * req->fb->pitches[i];
+			offset += ((x_offset + req->src_x) / xdiv) *
+				  req->bpp[i];
+			req->xstride[i] = ((patched_src_w - 1) / ydiv) *
+					  req->fb->pitches[i];
+			req->pstride[i] = -req->fb->pitches[i] - req->bpp[i];
+			break;
+		case BIT(DRM_ROTATE_180):
+			offset = ((y_offset + req->src_y + patched_src_h - 1) /
+				  ydiv) * req->fb->pitches[i];
+			offset += ((x_offset + req->src_x + patched_src_w - 1) /
+				   xdiv) * req->bpp[i];
+			req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
+					   req->bpp[i]) - req->fb->pitches[i];
+			req->pstride[i] = -2 * req->bpp[i];
+			break;
+		case BIT(DRM_ROTATE_270):
+			offset = ((y_offset + req->src_y) / ydiv) *
+				 req->fb->pitches[i];
+			offset += ((x_offset + req->src_x + patched_src_h - 1) /
+				   xdiv) * req->bpp[i];
+			req->xstride[i] = -(((patched_src_w - 1) / ydiv) *
+					    req->fb->pitches[i]) -
+					  (2 * req->bpp[i]);
+			req->pstride[i] = req->fb->pitches[i] - req->bpp[i];
+			break;
+		case BIT(DRM_ROTATE_0):
+		default:
+			offset = ((y_offset + req->src_y) / ydiv) *
+				 req->fb->pitches[i];
+			offset += ((x_offset + req->src_x) / xdiv) *
+				  req->bpp[i];
+			req->xstride[i] = req->fb->pitches[i] -
+					  ((patched_src_w / xdiv) *
+					   req->bpp[i]);
+			req->pstride[i] = 0;
+			break;
+		}
+
+		req->offsets[i] = offset + req->fb->offsets[i];
+	}
+
+	req->src_w = patched_src_w;
+	req->src_h = patched_src_h;
+	req->crtc_w = patched_crtc_w;
+	req->crtc_h = patched_crtc_h;
+
+	return atmel_hlcdc_plane_check_update_req(p, req, mode);
+}
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+				struct atmel_hlcdc_plane_update_req *req)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	int ret;
+
+	ret = atmel_hlcdc_layer_update_start(&plane->layer);
+	if (ret)
+		return ret;
+
+	atmel_hlcdc_plane_update_pos_and_size(plane, req);
+	atmel_hlcdc_plane_update_general_settings(plane, req);
+	atmel_hlcdc_plane_update_format(plane, req);
+	atmel_hlcdc_plane_update_buffers(plane, req);
+
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
+				       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,
+				       const struct drm_display_mode *mode)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_update_req req;
+	int ret = 0;
+
+	memset(&req, 0, sizeof(req));
+	req.crtc_x = crtc_x;
+	req.crtc_y = crtc_y;
+	req.crtc_w = crtc_w;
+	req.crtc_h = crtc_h;
+	req.src_x = src_x;
+	req.src_y = src_y;
+	req.src_w = src_w;
+	req.src_h = src_h;
+	req.fb = fb;
+
+	ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode);
+	if (ret)
+		return ret;
+
+	if (!req.crtc_h || !req.crtc_w)
+		return atmel_hlcdc_layer_disable(&plane->layer);
+
+	return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+}
+
+static int atmel_hlcdc_plane_update(struct drm_plane *p,
+				    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)
+{
+	return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y,
+						  crtc_w, crtc_h, src_x, src_y,
+						  src_w, src_h, &crtc->hwmode);
+}
+
+static int atmel_hlcdc_plane_disable(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	return atmel_hlcdc_layer_disable(&plane->layer);
+}
+
+static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+	if (plane->base.fb)
+		drm_framebuffer_unreference(plane->base.fb);
+
+	atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
+
+	drm_plane_cleanup(p);
+	devm_kfree(p->dev->dev, plane);
+}
+
+static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
+				       u8 alpha)
+{
+	atmel_hlcdc_layer_update_start(&plane->layer);
+	atmel_hlcdc_layer_update_cfg(&plane->layer,
+				     plane->layer.desc->layout.general_config,
+				     ATMEL_HLCDC_LAYER_GA_MASK,
+				     alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
+	atmel_hlcdc_layer_update_commit(&plane->layer);
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane,
+					  unsigned int rotation)
+{
+	plane->rotation = rotation;
+
+	return 0;
+}
+
+static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
+					  struct drm_property *property,
+					  uint64_t value)
+{
+	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+	struct atmel_hlcdc_plane_properties *props = plane->properties;
+
+	if (property == props->alpha)
+		atmel_hlcdc_plane_set_alpha(plane, value);
+	else if (property == props->rotation)
+		atmel_hlcdc_plane_set_rotation(plane, value);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
+				const struct atmel_hlcdc_layer_desc *desc,
+				struct atmel_hlcdc_plane_properties *props)
+{
+	struct regmap *regmap = plane->layer.hlcdc->regmap;
+
+	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
+	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
+		drm_object_attach_property(&plane->base.base,
+					   props->alpha, 255);
+
+		/* Set default alpha value */
+		regmap_update_bits(regmap,
+				desc->regs_offset +
+				ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
+				ATMEL_HLCDC_LAYER_GA_MASK,
+				ATMEL_HLCDC_LAYER_GA_MASK);
+	}
+
+	if (desc->layout.xstride && desc->layout.pstride)
+		drm_object_attach_property(&plane->base.base,
+					   props->rotation,
+					   BIT(DRM_ROTATE_0));
+
+	if (desc->layout.csc) {
+		/*
+		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
+		 * userspace modify these factors (using a BLOB property ?).
+		 */
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
+			     0x4c900091);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
+			     0x7a5f5090);
+		regmap_write(regmap,
+			     desc->regs_offset +
+			     ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
+			     0x40040890);
+	}
+}
+
+static struct drm_plane_funcs layer_plane_funcs = {
+	.update_plane = atmel_hlcdc_plane_update,
+	.disable_plane = atmel_hlcdc_plane_disable,
+	.set_property = atmel_hlcdc_plane_set_property,
+	.destroy = atmel_hlcdc_plane_destroy,
+};
+
+static struct atmel_hlcdc_plane *
+atmel_hlcdc_plane_create(struct drm_device *dev,
+			 const struct atmel_hlcdc_layer_desc *desc,
+			 struct atmel_hlcdc_plane_properties *props)
+{
+	struct atmel_hlcdc_plane *plane;
+	enum drm_plane_type type;
+	int ret;
+
+	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+	if (!plane)
+		return ERR_PTR(-ENOMEM);
+
+	ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
+		type = DRM_PLANE_TYPE_PRIMARY;
+	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
+		type = DRM_PLANE_TYPE_CURSOR;
+	else
+		type = DRM_PLANE_TYPE_OVERLAY;
+
+	ret = drm_universal_plane_init(dev, &plane->base, 0,
+				       &layer_plane_funcs,
+				       desc->formats->formats,
+				       desc->formats->nformats, type);
+	if (ret)
+		return ERR_PTR(ret);
+
+	/* Set default property values*/
+	atmel_hlcdc_plane_init_properties(plane, desc, props);
+
+	return plane;
+}
+
+static struct atmel_hlcdc_plane_properties *
+atmel_hlcdc_plane_create_properties(struct drm_device *dev)
+{
+	struct atmel_hlcdc_plane_properties *props;
+
+	props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
+	if (!props)
+		return ERR_PTR(-ENOMEM);
+
+	props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
+	if (!props->alpha)
+		return ERR_PTR(-ENOMEM);
+
+	props->rotation = drm_mode_create_rotation_property(dev,
+						BIT(DRM_ROTATE_0) |
+						BIT(DRM_ROTATE_90) |
+						BIT(DRM_ROTATE_180) |
+						BIT(DRM_ROTATE_270));
+	if (!props->rotation)
+		return ERR_PTR(-ENOMEM);
+
+	return props;
+}
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev)
+{
+	struct atmel_hlcdc_dc *dc = dev->dev_private;
+	struct atmel_hlcdc_plane_properties *props;
+	struct atmel_hlcdc_planes *planes;
+	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
+	int nlayers = dc->desc->nlayers;
+	int i;
+
+	planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
+	if (!planes)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < nlayers; i++) {
+		if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
+			planes->noverlays++;
+	}
+
+	if (planes->noverlays) {
+		planes->overlays = devm_kzalloc(dev->dev,
+						planes->noverlays *
+						sizeof(*planes->overlays),
+						GFP_KERNEL);
+		if (!planes->overlays)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	props = atmel_hlcdc_plane_create_properties(dev);
+	if (IS_ERR(props))
+		return ERR_CAST(props);
+
+	planes->noverlays = 0;
+	for (i = 0; i < nlayers; i++) {
+		struct atmel_hlcdc_plane *plane;
+
+		if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
+			continue;
+
+		plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
+		if (IS_ERR(plane))
+			return ERR_CAST(plane);
+
+		plane->properties = props;
+
+		switch (descs[i].type) {
+		case ATMEL_HLCDC_BASE_LAYER:
+			if (planes->primary)
+				return ERR_PTR(-EINVAL);
+			planes->primary = plane;
+			break;
+
+		case ATMEL_HLCDC_OVERLAY_LAYER:
+			planes->overlays[planes->noverlays++] = plane;
+			break;
+
+		case ATMEL_HLCDC_CURSOR_LAYER:
+			if (planes->cursor)
+				return ERR_PTR(-EINVAL);
+			planes->cursor = plane;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return planes;
+}
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
index 61dbf09..976d979 100644
--- a/drivers/gpu/drm/bochs/bochs_fbdev.c
+++ b/drivers/gpu/drm/bochs/bochs_fbdev.c
@@ -207,12 +207,22 @@
 	if (ret)
 		return ret;
 
-	drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
+	ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
+	if (ret)
+		goto fini;
+
 	drm_helper_disable_unused_functions(bochs->dev);
-	drm_fb_helper_initial_config(&bochs->fb.helper, 32);
+
+	ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32);
+	if (ret)
+		goto fini;
 
 	bochs->fb.initialized = true;
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&bochs->fb.helper);
+	return ret;
 }
 
 void bochs_fbdev_fini(struct bochs_device *bochs)
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 85f0f8cf..26bcd03 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -18,10 +18,6 @@
 
 /* ---------------------------------------------------------------------- */
 
-static void bochs_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
 static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	switch (mode) {
@@ -144,7 +140,6 @@
 	.mode_set_base = bochs_crtc_mode_set_base,
 	.prepare = bochs_crtc_prepare,
 	.commit = bochs_crtc_commit,
-	.load_lut = bochs_crtc_load_lut,
 };
 
 static void bochs_crtc_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..f38bbcd 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,5 +1,13 @@
+config DRM_DW_HDMI
+	tristate
+	depends on DRM
+	select DRM_KMS_HELPER
+
 config DRM_PTN3460
 	tristate "PTN3460 DP/LVDS bridge"
 	depends on DRM
+	depends on OF
 	select DRM_KMS_HELPER
+	select DRM_PANEL
 	---help---
+	  ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
 ccflags-y := -Iinclude/drm
 
 obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
new file mode 100644
index 0000000..cd6a706
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -0,0 +1,1707 @@
+/*
+ * Copyright (C) 2011-2013 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Designware High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ */
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/hdmi.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include "dw_hdmi.h"
+
+#define HDMI_EDID_LEN		512
+
+#define RGB			0
+#define YCBCR444		1
+#define YCBCR422_16BITS		2
+#define YCBCR422_8BITS		3
+#define XVYCC444		4
+
+enum hdmi_datamap {
+	RGB444_8B = 0x01,
+	RGB444_10B = 0x03,
+	RGB444_12B = 0x05,
+	RGB444_16B = 0x07,
+	YCbCr444_8B = 0x09,
+	YCbCr444_10B = 0x0B,
+	YCbCr444_12B = 0x0D,
+	YCbCr444_16B = 0x0F,
+	YCbCr422_8B = 0x16,
+	YCbCr422_10B = 0x14,
+	YCbCr422_12B = 0x12,
+};
+
+static const u16 csc_coeff_default[3][4] = {
+	{ 0x2000, 0x0000, 0x0000, 0x0000 },
+	{ 0x0000, 0x2000, 0x0000, 0x0000 },
+	{ 0x0000, 0x0000, 0x2000, 0x0000 }
+};
+
+static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
+	{ 0x2000, 0x6926, 0x74fd, 0x010e },
+	{ 0x2000, 0x2cdd, 0x0000, 0x7e9a },
+	{ 0x2000, 0x0000, 0x38b4, 0x7e3b }
+};
+
+static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
+	{ 0x2000, 0x7106, 0x7a02, 0x00a7 },
+	{ 0x2000, 0x3264, 0x0000, 0x7e6d },
+	{ 0x2000, 0x0000, 0x3b61, 0x7e25 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
+	{ 0x2591, 0x1322, 0x074b, 0x0000 },
+	{ 0x6535, 0x2000, 0x7acc, 0x0200 },
+	{ 0x6acd, 0x7534, 0x2000, 0x0200 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
+	{ 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
+	{ 0x62f0, 0x2000, 0x7d11, 0x0200 },
+	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
+};
+
+struct hdmi_vmode {
+	bool mdvi;
+	bool mhsyncpolarity;
+	bool mvsyncpolarity;
+	bool minterlaced;
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct dw_hdmi {
+	struct drm_connector connector;
+	struct drm_encoder *encoder;
+	struct drm_bridge *bridge;
+
+	enum dw_hdmi_devtype dev_type;
+	struct device *dev;
+	struct clk *isfr_clk;
+	struct clk *iahb_clk;
+
+	struct hdmi_data_info hdmi_data;
+	const struct dw_hdmi_plat_data *plat_data;
+
+	int vic;
+
+	u8 edid[HDMI_EDID_LEN];
+	bool cable_plugin;
+
+	bool phy_enabled;
+	struct drm_display_mode previous_mode;
+
+	struct regmap *regmap;
+	struct i2c_adapter *ddc;
+	void __iomem *regs;
+
+	unsigned int sample_rate;
+	int ratio;
+
+	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+	writel(val, hdmi->regs + (offset << 2));
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+	return readl(hdmi->regs + (offset << 2));
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+	writeb(val, hdmi->regs + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+	return readb(hdmi->regs + offset);
+}
+
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+	hdmi->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+	return hdmi->read(hdmi, offset);
+}
+
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+	u8 val = hdmi_readb(hdmi, reg) & ~mask;
+
+	val |= data & mask;
+	hdmi_writeb(hdmi, val, reg);
+}
+
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
+			     u8 shift, u8 mask)
+{
+	hdmi_modb(hdmi, data << shift, mask, reg);
+}
+
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
+					 unsigned int value)
+{
+	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
+	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+
+	/* nshift factor = 0 */
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
+}
+
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
+{
+	/* Must be set/cleared first */
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+
+	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+	hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+		    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+				   unsigned int ratio)
+{
+	unsigned int n = (128 * freq) / 1000;
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 4576;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 4096;
+		else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+			n = 11648;
+		else
+			n = 4096;
+		break;
+
+	case 44100:
+		if (pixel_clk == 25170000)
+			n = 7007;
+		else if (pixel_clk == 74170000)
+			n = 17836;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 17836 : 8918;
+		else
+			n = 6272;
+		break;
+
+	case 48000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 6864;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 6144;
+		else if (pixel_clk == 74170000)
+			n = 11648;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 11648 : 5824;
+		else
+			n = 6144;
+		break;
+
+	case 88200:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+		break;
+
+	case 96000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+		break;
+
+	case 176400:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+		break;
+
+	case 192000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+		break;
+
+	default:
+		break;
+	}
+
+	return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+				     unsigned int ratio)
+{
+	unsigned int cts = 0;
+
+	pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
+		 pixel_clk, ratio);
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 297000000) {
+			cts = 222750;
+			break;
+		}
+	case 48000:
+	case 96000:
+	case 192000:
+		switch (pixel_clk) {
+		case 25200000:
+		case 27000000:
+		case 54000000:
+		case 74250000:
+		case 148500000:
+			cts = pixel_clk / 1000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		/*
+		 * All other TMDS clocks are not supported by
+		 * DWC_hdmi_tx. The TMDS clocks divided or
+		 * multiplied by 1,001 coefficients are not
+		 * supported.
+		 */
+		default:
+			break;
+		}
+		break;
+	case 44100:
+	case 88200:
+	case 176400:
+		switch (pixel_clk) {
+		case 25200000:
+			cts = 28000;
+			break;
+		case 27000000:
+			cts = 30000;
+			break;
+		case 54000000:
+			cts = 60000;
+			break;
+		case 74250000:
+			cts = 82500;
+			break;
+		case 148500000:
+			cts = 165000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	if (ratio == 100)
+		return cts;
+	return (cts * ratio) / 100;
+}
+
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
+				     unsigned long pixel_clk)
+{
+	unsigned int clk_n, clk_cts;
+
+	clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
+			       hdmi->ratio);
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
+				   hdmi->ratio);
+
+	if (!clk_cts) {
+		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+			__func__, pixel_clk);
+		return;
+	}
+
+	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+		__func__, hdmi->sample_rate, hdmi->ratio,
+		pixel_clk, clk_n, clk_cts);
+
+	hdmi_set_clock_regenerator_n(hdmi, clk_n);
+	hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
+{
+	hdmi_set_clk_regenerator(hdmi, 74250000);
+}
+
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
+{
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+
+/*
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ *			pin{47~40} <==> R[7:0]
+ *			pin{31~24} <==> G[7:0]
+ *			pin{15~8}  <==> B[7:0]
+ */
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
+{
+	int color_format = 0;
+	u8 val;
+
+	if (hdmi->hdmi_data.enc_in_format == RGB) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x01;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x03;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x05;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x07;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x09;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x0B;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x0D;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x0F;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x16;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x14;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x12;
+		else
+			return;
+	}
+
+	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+		((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+		HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+	hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+
+	/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+	hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+}
+
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
+{
+	return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
+}
+
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
+{
+	if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+		return 0;
+	if (hdmi->hdmi_data.enc_in_format == RGB ||
+	    hdmi->hdmi_data.enc_in_format == YCBCR444)
+		return 1;
+	return 0;
+}
+
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
+{
+	if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+		return 0;
+	if (hdmi->hdmi_data.enc_out_format == RGB ||
+	    hdmi->hdmi_data.enc_out_format == YCBCR444)
+		return 1;
+	return 0;
+}
+
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
+{
+	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+	unsigned i;
+	u32 csc_scale = 1;
+
+	if (is_color_space_conversion(hdmi)) {
+		if (hdmi->hdmi_data.enc_out_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry ==
+					HDMI_COLORIMETRY_ITU_601)
+				csc_coeff = &csc_coeff_rgb_out_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_out_eitu709;
+		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry ==
+					HDMI_COLORIMETRY_ITU_601)
+				csc_coeff = &csc_coeff_rgb_in_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_in_eitu709;
+			csc_scale = 0;
+		}
+	}
+
+	/* The CSC registers are sequential, alternating MSB then LSB */
+	for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+		u16 coeff_a = (*csc_coeff)[0][i];
+		u16 coeff_b = (*csc_coeff)[1][i];
+		u16 coeff_c = (*csc_coeff)[2][i];
+
+		hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+	}
+
+	hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+		  HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
+{
+	int color_depth = 0;
+	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+	int decimation = 0;
+
+	/* YCC422 interpolation to 444 mode */
+	if (is_color_space_interpolation(hdmi))
+		interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+	else if (is_color_space_decimation(hdmi))
+		decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+	if (hdmi->hdmi_data.enc_color_depth == 8)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 10)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 12)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 16)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+	else
+		return;
+
+	/* Configure the CSC registers */
+	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+	hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+		  HDMI_CSC_SCALE);
+
+	dw_hdmi_update_csc_coeffs(hdmi);
+}
+
+/*
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
+{
+	unsigned int color_depth = 0;
+	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+	u8 val, vp_conf;
+
+	if (hdmi_data->enc_out_format == RGB ||
+	    hdmi_data->enc_out_format == YCBCR444) {
+		if (!hdmi_data->enc_color_depth) {
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		} else if (hdmi_data->enc_color_depth == 8) {
+			color_depth = 4;
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		} else if (hdmi_data->enc_color_depth == 10) {
+			color_depth = 5;
+		} else if (hdmi_data->enc_color_depth == 12) {
+			color_depth = 6;
+		} else if (hdmi_data->enc_color_depth == 16) {
+			color_depth = 7;
+		} else {
+			return;
+		}
+	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+		if (!hdmi_data->enc_color_depth ||
+		    hdmi_data->enc_color_depth == 8)
+			remap_size = HDMI_VP_REMAP_YCC422_16bit;
+		else if (hdmi_data->enc_color_depth == 10)
+			remap_size = HDMI_VP_REMAP_YCC422_20bit;
+		else if (hdmi_data->enc_color_depth == 12)
+			remap_size = HDMI_VP_REMAP_YCC422_24bit;
+		else
+			return;
+		output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+	} else {
+		return;
+	}
+
+	/* set the packetizer registers */
+	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+		((hdmi_data->pix_repet_factor <<
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
+
+	/* Data from pixel repeater block */
+	if (hdmi_data->pix_repet_factor > 1) {
+		vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+	} else { /* data from packetizer block */
+		vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+	}
+
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_PR_EN_MASK |
+		  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
+	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
+
+	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+
+	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_ENABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_ENABLE;
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
+	} else {
+		return;
+	}
+
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+		  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PP_STUFFING_MASK |
+		  HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
+
+	hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+		  HDMI_VP_CONF);
+}
+
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
+				       unsigned char bit)
+{
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+		  HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
+					unsigned char bit)
+{
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+		  HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
+				       unsigned char bit)
+{
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+		  HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
+				     unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
+				      unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
+{
+	u32 val;
+
+	while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+		if (msec-- == 0)
+			return false;
+		udelay(1000);
+	}
+	hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
+	return true;
+}
+
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+				 unsigned char addr)
+{
+	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 8),
+		    HDMI_PHY_I2CM_DATAO_1_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+		    HDMI_PHY_I2CM_DATAO_0_ADDR);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+		    HDMI_PHY_I2CM_OPERATION_ADDR);
+	hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+			      unsigned char addr)
+{
+	__hdmi_phy_i2c_write(hdmi, data, addr);
+	return 0;
+}
+
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_PDZ_OFFSET,
+			 HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_ENTMDS_OFFSET,
+			 HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+			 HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+			 HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+			 HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
+			      unsigned char res, int cscon)
+{
+	unsigned res_idx, i;
+	u8 val, msec;
+	const struct dw_hdmi_mpll_config *mpll_config =
+						hdmi->plat_data->mpll_cfg;
+	const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr;
+	const struct dw_hdmi_sym_term *sym_term =  hdmi->plat_data->sym_term;
+
+	if (prep)
+		return -EINVAL;
+
+	switch (res) {
+	case 0:	/* color resolution 0 is 8 bit colour depth */
+	case 8:
+		res_idx = DW_HDMI_RES_8;
+		break;
+	case 10:
+		res_idx = DW_HDMI_RES_10;
+		break;
+	case 12:
+		res_idx = DW_HDMI_RES_12;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Enable csc path */
+	if (cscon)
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+	else
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+	hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+
+	/* gen2 tx power off */
+	dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+	/* gen2 pddq */
+	dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+	/* PHY reset */
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+	hdmi_phy_test_clear(hdmi, 1);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+		    HDMI_PHY_I2CM_SLAVE_ADDR);
+	hdmi_phy_test_clear(hdmi, 0);
+
+	/* PLL/MPLL Cfg - always match on final entry */
+	for (i = 0; mpll_config[i].mpixelclock != (~0UL); i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    mpll_config[i].mpixelclock)
+			break;
+
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+	for (i = 0; curr_ctrl[i].mpixelclock != (~0UL); i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    curr_ctrl[i].mpixelclock)
+			break;
+
+	if (curr_ctrl[i].mpixelclock == (~0UL)) {
+		dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+			hdmi->hdmi_data.video_mode.mpixelclock);
+		return -EINVAL;
+	}
+
+	/* CURRCTRL */
+	hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
+	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
+	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+	for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    sym_term[i].mpixelclock)
+			break;
+
+	/* RESISTANCE TERM 133Ohm Cfg */
+	hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19);  /* TXTERM */
+	/* PREEMP Cgf 0.00 */
+	hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09);  /* CKSYMTXCTRL */
+
+	/* TX/CK LVL 10 */
+	hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
+	/* REMOVE CLK TERM */
+	hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+
+	dw_hdmi_phy_enable_power(hdmi, 1);
+
+	/* toggle TMDS enable */
+	dw_hdmi_phy_enable_tmds(hdmi, 0);
+	dw_hdmi_phy_enable_tmds(hdmi, 1);
+
+	/* gen2 tx power on */
+	dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+	dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+	if (hdmi->dev_type == RK3288_HDMI)
+		dw_hdmi_phy_enable_spare(hdmi, 1);
+
+	/*Wait for PHY PLL lock */
+	msec = 5;
+	do {
+		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+		if (!val)
+			break;
+
+		if (msec == 0) {
+			dev_err(hdmi->dev, "PHY PLL not locked\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1000);
+		msec--;
+	} while (1);
+
+	return 0;
+}
+
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+{
+	int i, ret;
+	bool cscon = false;
+
+	/*check csc whether needed activated in HDMI mode */
+	cscon = (is_color_space_conversion(hdmi) &&
+			!hdmi->hdmi_data.video_mode.mdvi);
+
+	/* HDMI Phy spec says to do the phy initialization sequence twice */
+	for (i = 0; i < 2; i++) {
+		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+		dw_hdmi_phy_sel_interface_control(hdmi, 0);
+		dw_hdmi_phy_enable_tmds(hdmi, 0);
+		dw_hdmi_phy_enable_power(hdmi, 0);
+
+		/* Enable CSC */
+		ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+		if (ret)
+			return ret;
+	}
+
+	hdmi->phy_enabled = true;
+	return 0;
+}
+
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
+{
+	u8 de;
+
+	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+	else
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+	/* disable rx detect */
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+		  HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
+
+	hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
+
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+		  HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
+}
+
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
+{
+	u8 val, pix_fmt, under_scan;
+	u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+	bool aspect_16_9;
+
+	aspect_16_9 = false; /* FIXME */
+
+	/* AVI Data Byte 1 */
+	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+	else
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+		under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+	/*
+	 * Active format identification data is present in the AVI InfoFrame.
+	 * Under scan info, no bar data
+	 */
+	val = pix_fmt | under_scan |
+		HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+		HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+
+	/* AVI Data Byte 2 -Set the Aspect Ratio */
+	if (aspect_16_9) {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+	} else {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+	}
+
+	/* Set up colorimetry */
+	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	} else { /* Carries no data */
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	}
+
+	val = colorimetry | coded_ratio | act_ratio;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+
+	/* AVI Data Byte 3 */
+	val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+		HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+		HDMI_FC_AVICONF2_SCALING_NONE;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+
+	/* AVI Data Byte 4 */
+	hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+
+	/* AVI Data Byte 5- set up input and output pixel repetition */
+	val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+		((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+
+	/* IT Content and quantization range = don't care */
+	val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+		HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+
+	/* AVI Data Bytes 6-13 */
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+}
+
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
+			     const struct drm_display_mode *mode)
+{
+	u8 inv_val;
+	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+
+	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+	vmode->mpixelclock = mode->clock * 1000;
+
+	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+	/* Set up HDMI_FC_INVIDCONF */
+	inv_val = (hdmi->hdmi_data.hdcp_enable ?
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+	inv_val |= (vmode->mvsyncpolarity ?
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mhsyncpolarity ?
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mdataenablepolarity ?
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+	if (hdmi->vic == 39)
+		inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+	else
+		inv_val |= (vmode->minterlaced ?
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+	inv_val |= (vmode->minterlaced ?
+		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+	inv_val |= (vmode->mdvi ?
+		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
+	/* Set up horizontal active pixel width */
+	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+
+	/* Set up vertical active lines */
+	hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+	hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+
+	/* Set up horizontal blanking pixel region width */
+	hblank = mode->htotal - mode->hdisplay;
+	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+	/* Set up vertical blanking pixel region width */
+	vblank = mode->vtotal - mode->vdisplay;
+	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+	/* Set up HSYNC active edge delay width (in pixel clks) */
+	h_de_hs = mode->hsync_start - mode->hdisplay;
+	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+	/* Set up VSYNC active edge delay (in lines) */
+	v_de_vs = mode->vsync_start - mode->vdisplay;
+	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+	/* Set up HSYNC active pulse width (in pixel clks) */
+	hsync_len = mode->hsync_end - mode->hsync_start;
+	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+	/* Set up VSYNC active edge delay (in lines) */
+	vsync_len = mode->vsync_end - mode->vsync_start;
+	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+}
+
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
+{
+	if (!hdmi->phy_enabled)
+		return;
+
+	dw_hdmi_phy_enable_tmds(hdmi, 0);
+	dw_hdmi_phy_enable_power(hdmi, 0);
+
+	hdmi->phy_enabled = false;
+}
+
+/* HDMI Initialization Step B.4 */
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
+{
+	u8 clkdis;
+
+	/* control period minimum duration */
+	hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
+	hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
+	hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+
+	/* Set to fill TMDS data channels */
+	hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+	hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
+	hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+
+	/* Enable pixel clock and tmds data path */
+	clkdis = 0x7F;
+	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	/* Enable csc path */
+	if (is_color_space_conversion(hdmi)) {
+		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	}
+}
+
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
+{
+	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
+{
+	int count;
+	u8 val;
+
+	/* TMDS software reset */
+	hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+	val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+	if (hdmi->dev_type == IMX6DL_HDMI) {
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+		return;
+	}
+
+	for (count = 0; count < 4; count++)
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+		    HDMI_IH_MUTE_FC_STAT2);
+}
+
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+{
+	int ret;
+
+	hdmi_disable_overflow_interrupts(hdmi);
+
+	hdmi->vic = drm_match_cea_mode(mode);
+
+	if (!hdmi->vic) {
+		dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
+		hdmi->hdmi_data.video_mode.mdvi = true;
+	} else {
+		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+		hdmi->hdmi_data.video_mode.mdvi = false;
+	}
+
+	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+	    (hdmi->vic == 21) || (hdmi->vic == 22) ||
+	    (hdmi->vic == 2) || (hdmi->vic == 3) ||
+	    (hdmi->vic == 17) || (hdmi->vic == 18))
+		hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
+	else
+		hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
+
+	if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+	    (hdmi->vic == 12) || (hdmi->vic == 13) ||
+	    (hdmi->vic == 14) || (hdmi->vic == 15) ||
+	    (hdmi->vic == 25) || (hdmi->vic == 26) ||
+	    (hdmi->vic == 27) || (hdmi->vic == 28) ||
+	    (hdmi->vic == 29) || (hdmi->vic == 30) ||
+	    (hdmi->vic == 35) || (hdmi->vic == 36) ||
+	    (hdmi->vic == 37) || (hdmi->vic == 38))
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
+	else
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
+
+	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+	/* TODO: Get input format from IPU (via FB driver interface) */
+	hdmi->hdmi_data.enc_in_format = RGB;
+
+	hdmi->hdmi_data.enc_out_format = RGB;
+
+	hdmi->hdmi_data.enc_color_depth = 8;
+	hdmi->hdmi_data.pix_repet_factor = 0;
+	hdmi->hdmi_data.hdcp_enable = 0;
+	hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
+
+	/* HDMI Initialization Step B.1 */
+	hdmi_av_composer(hdmi, mode);
+
+	/* HDMI Initializateion Step B.2 */
+	ret = dw_hdmi_phy_init(hdmi);
+	if (ret)
+		return ret;
+
+	/* HDMI Initialization Step B.3 */
+	dw_hdmi_enable_video_path(hdmi);
+
+	/* not for DVI mode */
+	if (hdmi->hdmi_data.video_mode.mdvi) {
+		dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
+	} else {
+		dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+
+		/* HDMI Initialization Step E - Configure audio */
+		hdmi_clk_regenerator_update_pixel_clock(hdmi);
+		hdmi_enable_audio_clk(hdmi);
+
+		/* HDMI Initialization Step F - Configure AVI InfoFrame */
+		hdmi_config_AVI(hdmi);
+	}
+
+	hdmi_video_packetize(hdmi);
+	hdmi_video_csc(hdmi);
+	hdmi_video_sample(hdmi);
+	hdmi_tx_hdcp_config(hdmi);
+
+	dw_hdmi_clear_overflow(hdmi);
+	if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+		hdmi_enable_overflow_interrupts(hdmi);
+
+	return 0;
+}
+
+/* Wait until we are registered to enable interrupts */
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+		    HDMI_PHY_I2CM_INT_ADDR);
+
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+		    HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+		    HDMI_PHY_I2CM_CTLINT_ADDR);
+
+	/* enable cable hot plug irq */
+	hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	return 0;
+}
+
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
+{
+	u8 ih_mute;
+
+	/*
+	 * Boot up defaults are:
+	 * HDMI_IH_MUTE   = 0x03 (disabled)
+	 * HDMI_IH_MUTE_* = 0x00 (enabled)
+	 *
+	 * Disable top level interrupt bits in HDMI block
+	 */
+	ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+	/* by default mask all interrupts */
+	hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+	hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+
+	/* Disable interrupts in the IH_MUTE_* registers */
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	/* Enable top level interrupt bits in HDMI block */
+	ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		    HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
+
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
+{
+	dw_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
+{
+	dw_hdmi_phy_disable(hdmi);
+}
+
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *orig_mode,
+				    struct drm_display_mode *mode)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	dw_hdmi_setup(hdmi, mode);
+
+	/* Store the display mode for plugin/DKMS poweron events */
+	memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+				      const struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi *hdmi = bridge->driver_private;
+
+	dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_nop(struct drm_bridge *bridge)
+{
+	/* do nothing */
+}
+
+static enum drm_connector_status
+dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+					     connector);
+
+	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+		connector_status_connected : connector_status_disconnected;
+}
+
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+					     connector);
+	struct edid *edid;
+	int ret;
+
+	if (!hdmi->ddc)
+		return 0;
+
+	edid = drm_get_edid(connector, hdmi->ddc);
+	if (edid) {
+		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		drm_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(hdmi->dev, "failed to get edid\n");
+	}
+
+	return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
+{
+	struct dw_hdmi *hdmi = container_of(connector,
+					   struct dw_hdmi, connector);
+	enum drm_mode_status mode_status = MODE_OK;
+
+	if (hdmi->plat_data->mode_valid)
+		mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+	return mode_status;
+}
+
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
+							   *connector)
+{
+	struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+					     connector);
+
+	return hdmi->encoder;
+}
+
+static void dw_hdmi_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = dw_hdmi_connector_detect,
+	.destroy = dw_hdmi_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+	.get_modes = dw_hdmi_connector_get_modes,
+	.mode_valid = dw_hdmi_connector_mode_valid,
+	.best_encoder = dw_hdmi_connector_best_encoder,
+};
+
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+	.enable = dw_hdmi_bridge_enable,
+	.disable = dw_hdmi_bridge_disable,
+	.pre_enable = dw_hdmi_bridge_nop,
+	.post_disable = dw_hdmi_bridge_nop,
+	.mode_set = dw_hdmi_bridge_mode_set,
+	.mode_fixup = dw_hdmi_bridge_mode_fixup,
+};
+
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
+{
+	struct dw_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+	if (intr_stat)
+		hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
+{
+	struct dw_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+	u8 phy_int_pol;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+
+	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+
+	if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+		if (phy_int_pol & HDMI_PHY_HPD) {
+			dev_dbg(hdmi->dev, "EVENT=plugin\n");
+
+			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+			dw_hdmi_poweron(hdmi);
+		} else {
+			dev_dbg(hdmi->dev, "EVENT=plugout\n");
+
+			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+				  HDMI_PHY_POL0);
+
+			dw_hdmi_poweroff(hdmi);
+		}
+		drm_helper_hpd_irq_event(hdmi->connector.dev);
+	}
+
+	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+	return IRQ_HANDLED;
+}
+
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
+{
+	struct drm_encoder *encoder = hdmi->encoder;
+	struct drm_bridge *bridge;
+	int ret;
+
+	bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+	if (!bridge) {
+		DRM_ERROR("Failed to allocate drm bridge\n");
+		return -ENOMEM;
+	}
+
+	hdmi->bridge = bridge;
+	bridge->driver_private = hdmi;
+	bridge->funcs = &dw_hdmi_bridge_funcs;
+	ret = drm_bridge_attach(drm, bridge);
+	if (ret) {
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return -EINVAL;
+	}
+
+	encoder->bridge = bridge;
+	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(&hdmi->connector,
+				 &dw_hdmi_connector_helper_funcs);
+	drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+
+	hdmi->connector.encoder = encoder;
+
+	drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+
+	return 0;
+}
+
+int dw_hdmi_bind(struct device *dev, struct device *master,
+		 void *data, struct drm_encoder *encoder,
+		 struct resource *iores, int irq,
+		 const struct dw_hdmi_plat_data *plat_data)
+{
+	struct drm_device *drm = data;
+	struct device_node *np = dev->of_node;
+	struct device_node *ddc_node;
+	struct dw_hdmi *hdmi;
+	int ret;
+	u32 val = 1;
+
+	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->plat_data = plat_data;
+	hdmi->dev = dev;
+	hdmi->dev_type = plat_data->dev_type;
+	hdmi->sample_rate = 48000;
+	hdmi->ratio = 100;
+	hdmi->encoder = encoder;
+
+	of_property_read_u32(np, "reg-io-width", &val);
+
+	switch (val) {
+	case 4:
+		hdmi->write = dw_hdmi_writel;
+		hdmi->read = dw_hdmi_readl;
+		break;
+	case 1:
+		hdmi->write = dw_hdmi_writeb;
+		hdmi->read = dw_hdmi_readb;
+		break;
+	default:
+		dev_err(dev, "reg-io-width must be 1 or 4\n");
+		return -EINVAL;
+	}
+
+	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
+	if (ddc_node) {
+		hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+		of_node_put(ddc_node);
+		if (!hdmi->ddc) {
+			dev_dbg(hdmi->dev, "failed to read ddc node\n");
+			return -EPROBE_DEFER;
+		}
+
+	} else {
+		dev_dbg(hdmi->dev, "no ddc property found\n");
+	}
+
+	hdmi->regs = devm_ioremap_resource(dev, iores);
+	if (IS_ERR(hdmi->regs))
+		return PTR_ERR(hdmi->regs);
+
+	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+	if (IS_ERR(hdmi->isfr_clk)) {
+		ret = PTR_ERR(hdmi->isfr_clk);
+		dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdmi->isfr_clk);
+	if (ret) {
+		dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+	if (IS_ERR(hdmi->iahb_clk)) {
+		ret = PTR_ERR(hdmi->iahb_clk);
+		dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret);
+		goto err_isfr;
+	}
+
+	ret = clk_prepare_enable(hdmi->iahb_clk);
+	if (ret) {
+		dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+		goto err_isfr;
+	}
+
+	/* Product and revision IDs */
+	dev_info(dev,
+		 "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+		 hdmi_readb(hdmi, HDMI_DESIGN_ID),
+		 hdmi_readb(hdmi, HDMI_REVISION_ID),
+		 hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+		 hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+
+	initialize_hdmi_ih_mutes(hdmi);
+
+	ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+					dw_hdmi_irq, IRQF_SHARED,
+					dev_name(dev), hdmi);
+	if (ret)
+		goto err_iahb;
+
+	/*
+	 * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+	 * N and cts values before enabling phy
+	 */
+	hdmi_init_clk_regenerator(hdmi);
+
+	/*
+	 * Configure registers related to HDMI interrupt
+	 * generation before registering IRQ.
+	 */
+	hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	ret = dw_hdmi_fb_registered(hdmi);
+	if (ret)
+		goto err_iahb;
+
+	ret = dw_hdmi_register(drm, hdmi);
+	if (ret)
+		goto err_iahb;
+
+	/* Unmute interrupts */
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+	dev_set_drvdata(dev, hdmi);
+
+	return 0;
+
+err_iahb:
+	clk_disable_unprepare(hdmi->iahb_clk);
+err_isfr:
+	clk_disable_unprepare(hdmi->isfr_clk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
+
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+	/* Disable all interrupts */
+	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder->funcs->destroy(hdmi->encoder);
+
+	clk_disable_unprepare(hdmi->iahb_clk);
+	clk_disable_unprepare(hdmi->isfr_clk);
+	i2c_put_adapter(hdmi->ddc);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..175dbc8
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2011 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __IMX_HDMI_H__
+#define __IMX_HDMI_H__
+
+/* Identification Registers */
+#define HDMI_DESIGN_ID                          0x0000
+#define HDMI_REVISION_ID                        0x0001
+#define HDMI_PRODUCT_ID0                        0x0002
+#define HDMI_PRODUCT_ID1                        0x0003
+#define HDMI_CONFIG0_ID                         0x0004
+#define HDMI_CONFIG1_ID                         0x0005
+#define HDMI_CONFIG2_ID                         0x0006
+#define HDMI_CONFIG3_ID                         0x0007
+
+/* Interrupt Registers */
+#define HDMI_IH_FC_STAT0                        0x0100
+#define HDMI_IH_FC_STAT1                        0x0101
+#define HDMI_IH_FC_STAT2                        0x0102
+#define HDMI_IH_AS_STAT0                        0x0103
+#define HDMI_IH_PHY_STAT0                       0x0104
+#define HDMI_IH_I2CM_STAT0                      0x0105
+#define HDMI_IH_CEC_STAT0                       0x0106
+#define HDMI_IH_VP_STAT0                        0x0107
+#define HDMI_IH_I2CMPHY_STAT0                   0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
+
+#define HDMI_IH_MUTE_FC_STAT0                   0x0180
+#define HDMI_IH_MUTE_FC_STAT1                   0x0181
+#define HDMI_IH_MUTE_FC_STAT2                   0x0182
+#define HDMI_IH_MUTE_AS_STAT0                   0x0183
+#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
+#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
+#define HDMI_IH_MUTE_VP_STAT0                   0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
+#define HDMI_IH_MUTE                            0x01FF
+
+/* Video Sample Registers */
+#define HDMI_TX_INVID0                          0x0200
+#define HDMI_TX_INSTUFFING                      0x0201
+#define HDMI_TX_GYDATA0                         0x0202
+#define HDMI_TX_GYDATA1                         0x0203
+#define HDMI_TX_RCRDATA0                        0x0204
+#define HDMI_TX_RCRDATA1                        0x0205
+#define HDMI_TX_BCBDATA0                        0x0206
+#define HDMI_TX_BCBDATA1                        0x0207
+
+/* Video Packetizer Registers */
+#define HDMI_VP_STATUS                          0x0800
+#define HDMI_VP_PR_CD                           0x0801
+#define HDMI_VP_STUFF                           0x0802
+#define HDMI_VP_REMAP                           0x0803
+#define HDMI_VP_CONF                            0x0804
+#define HDMI_VP_STAT                            0x0805
+#define HDMI_VP_INT                             0x0806
+#define HDMI_VP_MASK                            0x0807
+#define HDMI_VP_POL                             0x0808
+
+/* Frame Composer Registers */
+#define HDMI_FC_INVIDCONF                       0x1000
+#define HDMI_FC_INHACTV0                        0x1001
+#define HDMI_FC_INHACTV1                        0x1002
+#define HDMI_FC_INHBLANK0                       0x1003
+#define HDMI_FC_INHBLANK1                       0x1004
+#define HDMI_FC_INVACTV0                        0x1005
+#define HDMI_FC_INVACTV1                        0x1006
+#define HDMI_FC_INVBLANK                        0x1007
+#define HDMI_FC_HSYNCINDELAY0                   0x1008
+#define HDMI_FC_HSYNCINDELAY1                   0x1009
+#define HDMI_FC_HSYNCINWIDTH0                   0x100A
+#define HDMI_FC_HSYNCINWIDTH1                   0x100B
+#define HDMI_FC_VSYNCINDELAY                    0x100C
+#define HDMI_FC_VSYNCINWIDTH                    0x100D
+#define HDMI_FC_INFREQ0                         0x100E
+#define HDMI_FC_INFREQ1                         0x100F
+#define HDMI_FC_INFREQ2                         0x1010
+#define HDMI_FC_CTRLDUR                         0x1011
+#define HDMI_FC_EXCTRLDUR                       0x1012
+#define HDMI_FC_EXCTRLSPAC                      0x1013
+#define HDMI_FC_CH0PREAM                        0x1014
+#define HDMI_FC_CH1PREAM                        0x1015
+#define HDMI_FC_CH2PREAM                        0x1016
+#define HDMI_FC_AVICONF3                        0x1017
+#define HDMI_FC_GCP                             0x1018
+#define HDMI_FC_AVICONF0                        0x1019
+#define HDMI_FC_AVICONF1                        0x101A
+#define HDMI_FC_AVICONF2                        0x101B
+#define HDMI_FC_AVIVID                          0x101C
+#define HDMI_FC_AVIETB0                         0x101D
+#define HDMI_FC_AVIETB1                         0x101E
+#define HDMI_FC_AVISBB0                         0x101F
+#define HDMI_FC_AVISBB1                         0x1020
+#define HDMI_FC_AVIELB0                         0x1021
+#define HDMI_FC_AVIELB1                         0x1022
+#define HDMI_FC_AVISRB0                         0x1023
+#define HDMI_FC_AVISRB1                         0x1024
+#define HDMI_FC_AUDICONF0                       0x1025
+#define HDMI_FC_AUDICONF1                       0x1026
+#define HDMI_FC_AUDICONF2                       0x1027
+#define HDMI_FC_AUDICONF3                       0x1028
+#define HDMI_FC_VSDIEEEID0                      0x1029
+#define HDMI_FC_VSDSIZE                         0x102A
+#define HDMI_FC_VSDIEEEID1                      0x1030
+#define HDMI_FC_VSDIEEEID2                      0x1031
+#define HDMI_FC_VSDPAYLOAD0                     0x1032
+#define HDMI_FC_VSDPAYLOAD1                     0x1033
+#define HDMI_FC_VSDPAYLOAD2                     0x1034
+#define HDMI_FC_VSDPAYLOAD3                     0x1035
+#define HDMI_FC_VSDPAYLOAD4                     0x1036
+#define HDMI_FC_VSDPAYLOAD5                     0x1037
+#define HDMI_FC_VSDPAYLOAD6                     0x1038
+#define HDMI_FC_VSDPAYLOAD7                     0x1039
+#define HDMI_FC_VSDPAYLOAD8                     0x103A
+#define HDMI_FC_VSDPAYLOAD9                     0x103B
+#define HDMI_FC_VSDPAYLOAD10                    0x103C
+#define HDMI_FC_VSDPAYLOAD11                    0x103D
+#define HDMI_FC_VSDPAYLOAD12                    0x103E
+#define HDMI_FC_VSDPAYLOAD13                    0x103F
+#define HDMI_FC_VSDPAYLOAD14                    0x1040
+#define HDMI_FC_VSDPAYLOAD15                    0x1041
+#define HDMI_FC_VSDPAYLOAD16                    0x1042
+#define HDMI_FC_VSDPAYLOAD17                    0x1043
+#define HDMI_FC_VSDPAYLOAD18                    0x1044
+#define HDMI_FC_VSDPAYLOAD19                    0x1045
+#define HDMI_FC_VSDPAYLOAD20                    0x1046
+#define HDMI_FC_VSDPAYLOAD21                    0x1047
+#define HDMI_FC_VSDPAYLOAD22                    0x1048
+#define HDMI_FC_VSDPAYLOAD23                    0x1049
+#define HDMI_FC_SPDVENDORNAME0                  0x104A
+#define HDMI_FC_SPDVENDORNAME1                  0x104B
+#define HDMI_FC_SPDVENDORNAME2                  0x104C
+#define HDMI_FC_SPDVENDORNAME3                  0x104D
+#define HDMI_FC_SPDVENDORNAME4                  0x104E
+#define HDMI_FC_SPDVENDORNAME5                  0x104F
+#define HDMI_FC_SPDVENDORNAME6                  0x1050
+#define HDMI_FC_SPDVENDORNAME7                  0x1051
+#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
+#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
+#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
+#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
+#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
+#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
+#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
+#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
+#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
+#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
+#define HDMI_FC_SDPPRODUCTNAME10                0x105C
+#define HDMI_FC_SDPPRODUCTNAME11                0x105D
+#define HDMI_FC_SDPPRODUCTNAME12                0x105E
+#define HDMI_FC_SDPPRODUCTNAME13                0x105F
+#define HDMI_FC_SDPPRODUCTNAME14                0x1060
+#define HDMI_FC_SPDPRODUCTNAME15                0x1061
+#define HDMI_FC_SPDDEVICEINF                    0x1062
+#define HDMI_FC_AUDSCONF                        0x1063
+#define HDMI_FC_AUDSSTAT                        0x1064
+#define HDMI_FC_DATACH0FILL                     0x1070
+#define HDMI_FC_DATACH1FILL                     0x1071
+#define HDMI_FC_DATACH2FILL                     0x1072
+#define HDMI_FC_CTRLQHIGH                       0x1073
+#define HDMI_FC_CTRLQLOW                        0x1074
+#define HDMI_FC_ACP0                            0x1075
+#define HDMI_FC_ACP28                           0x1076
+#define HDMI_FC_ACP27                           0x1077
+#define HDMI_FC_ACP26                           0x1078
+#define HDMI_FC_ACP25                           0x1079
+#define HDMI_FC_ACP24                           0x107A
+#define HDMI_FC_ACP23                           0x107B
+#define HDMI_FC_ACP22                           0x107C
+#define HDMI_FC_ACP21                           0x107D
+#define HDMI_FC_ACP20                           0x107E
+#define HDMI_FC_ACP19                           0x107F
+#define HDMI_FC_ACP18                           0x1080
+#define HDMI_FC_ACP17                           0x1081
+#define HDMI_FC_ACP16                           0x1082
+#define HDMI_FC_ACP15                           0x1083
+#define HDMI_FC_ACP14                           0x1084
+#define HDMI_FC_ACP13                           0x1085
+#define HDMI_FC_ACP12                           0x1086
+#define HDMI_FC_ACP11                           0x1087
+#define HDMI_FC_ACP10                           0x1088
+#define HDMI_FC_ACP9                            0x1089
+#define HDMI_FC_ACP8                            0x108A
+#define HDMI_FC_ACP7                            0x108B
+#define HDMI_FC_ACP6                            0x108C
+#define HDMI_FC_ACP5                            0x108D
+#define HDMI_FC_ACP4                            0x108E
+#define HDMI_FC_ACP3                            0x108F
+#define HDMI_FC_ACP2                            0x1090
+#define HDMI_FC_ACP1                            0x1091
+#define HDMI_FC_ISCR1_0                         0x1092
+#define HDMI_FC_ISCR1_16                        0x1093
+#define HDMI_FC_ISCR1_15                        0x1094
+#define HDMI_FC_ISCR1_14                        0x1095
+#define HDMI_FC_ISCR1_13                        0x1096
+#define HDMI_FC_ISCR1_12                        0x1097
+#define HDMI_FC_ISCR1_11                        0x1098
+#define HDMI_FC_ISCR1_10                        0x1099
+#define HDMI_FC_ISCR1_9                         0x109A
+#define HDMI_FC_ISCR1_8                         0x109B
+#define HDMI_FC_ISCR1_7                         0x109C
+#define HDMI_FC_ISCR1_6                         0x109D
+#define HDMI_FC_ISCR1_5                         0x109E
+#define HDMI_FC_ISCR1_4                         0x109F
+#define HDMI_FC_ISCR1_3                         0x10A0
+#define HDMI_FC_ISCR1_2                         0x10A1
+#define HDMI_FC_ISCR1_1                         0x10A2
+#define HDMI_FC_ISCR2_15                        0x10A3
+#define HDMI_FC_ISCR2_14                        0x10A4
+#define HDMI_FC_ISCR2_13                        0x10A5
+#define HDMI_FC_ISCR2_12                        0x10A6
+#define HDMI_FC_ISCR2_11                        0x10A7
+#define HDMI_FC_ISCR2_10                        0x10A8
+#define HDMI_FC_ISCR2_9                         0x10A9
+#define HDMI_FC_ISCR2_8                         0x10AA
+#define HDMI_FC_ISCR2_7                         0x10AB
+#define HDMI_FC_ISCR2_6                         0x10AC
+#define HDMI_FC_ISCR2_5                         0x10AD
+#define HDMI_FC_ISCR2_4                         0x10AE
+#define HDMI_FC_ISCR2_3                         0x10AF
+#define HDMI_FC_ISCR2_2                         0x10B0
+#define HDMI_FC_ISCR2_1                         0x10B1
+#define HDMI_FC_ISCR2_0                         0x10B2
+#define HDMI_FC_DATAUTO0                        0x10B3
+#define HDMI_FC_DATAUTO1                        0x10B4
+#define HDMI_FC_DATAUTO2                        0x10B5
+#define HDMI_FC_DATMAN                          0x10B6
+#define HDMI_FC_DATAUTO3                        0x10B7
+#define HDMI_FC_RDRB0                           0x10B8
+#define HDMI_FC_RDRB1                           0x10B9
+#define HDMI_FC_RDRB2                           0x10BA
+#define HDMI_FC_RDRB3                           0x10BB
+#define HDMI_FC_RDRB4                           0x10BC
+#define HDMI_FC_RDRB5                           0x10BD
+#define HDMI_FC_RDRB6                           0x10BE
+#define HDMI_FC_RDRB7                           0x10BF
+#define HDMI_FC_STAT0                           0x10D0
+#define HDMI_FC_INT0                            0x10D1
+#define HDMI_FC_MASK0                           0x10D2
+#define HDMI_FC_POL0                            0x10D3
+#define HDMI_FC_STAT1                           0x10D4
+#define HDMI_FC_INT1                            0x10D5
+#define HDMI_FC_MASK1                           0x10D6
+#define HDMI_FC_POL1                            0x10D7
+#define HDMI_FC_STAT2                           0x10D8
+#define HDMI_FC_INT2                            0x10D9
+#define HDMI_FC_MASK2                           0x10DA
+#define HDMI_FC_POL2                            0x10DB
+#define HDMI_FC_PRCONF                          0x10E0
+
+#define HDMI_FC_GMD_STAT                        0x1100
+#define HDMI_FC_GMD_EN                          0x1101
+#define HDMI_FC_GMD_UP                          0x1102
+#define HDMI_FC_GMD_CONF                        0x1103
+#define HDMI_FC_GMD_HB                          0x1104
+#define HDMI_FC_GMD_PB0                         0x1105
+#define HDMI_FC_GMD_PB1                         0x1106
+#define HDMI_FC_GMD_PB2                         0x1107
+#define HDMI_FC_GMD_PB3                         0x1108
+#define HDMI_FC_GMD_PB4                         0x1109
+#define HDMI_FC_GMD_PB5                         0x110A
+#define HDMI_FC_GMD_PB6                         0x110B
+#define HDMI_FC_GMD_PB7                         0x110C
+#define HDMI_FC_GMD_PB8                         0x110D
+#define HDMI_FC_GMD_PB9                         0x110E
+#define HDMI_FC_GMD_PB10                        0x110F
+#define HDMI_FC_GMD_PB11                        0x1110
+#define HDMI_FC_GMD_PB12                        0x1111
+#define HDMI_FC_GMD_PB13                        0x1112
+#define HDMI_FC_GMD_PB14                        0x1113
+#define HDMI_FC_GMD_PB15                        0x1114
+#define HDMI_FC_GMD_PB16                        0x1115
+#define HDMI_FC_GMD_PB17                        0x1116
+#define HDMI_FC_GMD_PB18                        0x1117
+#define HDMI_FC_GMD_PB19                        0x1118
+#define HDMI_FC_GMD_PB20                        0x1119
+#define HDMI_FC_GMD_PB21                        0x111A
+#define HDMI_FC_GMD_PB22                        0x111B
+#define HDMI_FC_GMD_PB23                        0x111C
+#define HDMI_FC_GMD_PB24                        0x111D
+#define HDMI_FC_GMD_PB25                        0x111E
+#define HDMI_FC_GMD_PB26                        0x111F
+#define HDMI_FC_GMD_PB27                        0x1120
+
+#define HDMI_FC_DBGFORCE                        0x1200
+#define HDMI_FC_DBGAUD0CH0                      0x1201
+#define HDMI_FC_DBGAUD1CH0                      0x1202
+#define HDMI_FC_DBGAUD2CH0                      0x1203
+#define HDMI_FC_DBGAUD0CH1                      0x1204
+#define HDMI_FC_DBGAUD1CH1                      0x1205
+#define HDMI_FC_DBGAUD2CH1                      0x1206
+#define HDMI_FC_DBGAUD0CH2                      0x1207
+#define HDMI_FC_DBGAUD1CH2                      0x1208
+#define HDMI_FC_DBGAUD2CH2                      0x1209
+#define HDMI_FC_DBGAUD0CH3                      0x120A
+#define HDMI_FC_DBGAUD1CH3                      0x120B
+#define HDMI_FC_DBGAUD2CH3                      0x120C
+#define HDMI_FC_DBGAUD0CH4                      0x120D
+#define HDMI_FC_DBGAUD1CH4                      0x120E
+#define HDMI_FC_DBGAUD2CH4                      0x120F
+#define HDMI_FC_DBGAUD0CH5                      0x1210
+#define HDMI_FC_DBGAUD1CH5                      0x1211
+#define HDMI_FC_DBGAUD2CH5                      0x1212
+#define HDMI_FC_DBGAUD0CH6                      0x1213
+#define HDMI_FC_DBGAUD1CH6                      0x1214
+#define HDMI_FC_DBGAUD2CH6                      0x1215
+#define HDMI_FC_DBGAUD0CH7                      0x1216
+#define HDMI_FC_DBGAUD1CH7                      0x1217
+#define HDMI_FC_DBGAUD2CH7                      0x1218
+#define HDMI_FC_DBGTMDS0                        0x1219
+#define HDMI_FC_DBGTMDS1                        0x121A
+#define HDMI_FC_DBGTMDS2                        0x121B
+
+/* HDMI Source PHY Registers */
+#define HDMI_PHY_CONF0                          0x3000
+#define HDMI_PHY_TST0                           0x3001
+#define HDMI_PHY_TST1                           0x3002
+#define HDMI_PHY_TST2                           0x3003
+#define HDMI_PHY_STAT0                          0x3004
+#define HDMI_PHY_INT0                           0x3005
+#define HDMI_PHY_MASK0                          0x3006
+#define HDMI_PHY_POL0                           0x3007
+
+/* HDMI Master PHY Registers */
+#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
+#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
+
+/* Audio Sampler Registers */
+#define HDMI_AUD_CONF0                          0x3100
+#define HDMI_AUD_CONF1                          0x3101
+#define HDMI_AUD_INT                            0x3102
+#define HDMI_AUD_CONF2                          0x3103
+#define HDMI_AUD_N1                             0x3200
+#define HDMI_AUD_N2                             0x3201
+#define HDMI_AUD_N3                             0x3202
+#define HDMI_AUD_CTS1                           0x3203
+#define HDMI_AUD_CTS2                           0x3204
+#define HDMI_AUD_CTS3                           0x3205
+#define HDMI_AUD_INPUTCLKFS                     0x3206
+#define HDMI_AUD_SPDIFINT			0x3302
+#define HDMI_AUD_CONF0_HBR                      0x3400
+#define HDMI_AUD_HBR_STATUS                     0x3401
+#define HDMI_AUD_HBR_INT                        0x3402
+#define HDMI_AUD_HBR_POL                        0x3403
+#define HDMI_AUD_HBR_MASK                       0x3404
+
+/*
+ * Generic Parallel Audio Interface Registers
+ * Not used as GPAUD interface is not enabled in hw
+ */
+#define HDMI_GP_CONF0                           0x3500
+#define HDMI_GP_CONF1                           0x3501
+#define HDMI_GP_CONF2                           0x3502
+#define HDMI_GP_STAT                            0x3503
+#define HDMI_GP_INT                             0x3504
+#define HDMI_GP_MASK                            0x3505
+#define HDMI_GP_POL                             0x3506
+
+/* Audio DMA Registers */
+#define HDMI_AHB_DMA_CONF0                      0x3600
+#define HDMI_AHB_DMA_START                      0x3601
+#define HDMI_AHB_DMA_STOP                       0x3602
+#define HDMI_AHB_DMA_THRSLD                     0x3603
+#define HDMI_AHB_DMA_STRADDR0                   0x3604
+#define HDMI_AHB_DMA_STRADDR1                   0x3605
+#define HDMI_AHB_DMA_STRADDR2                   0x3606
+#define HDMI_AHB_DMA_STRADDR3                   0x3607
+#define HDMI_AHB_DMA_STPADDR0                   0x3608
+#define HDMI_AHB_DMA_STPADDR1                   0x3609
+#define HDMI_AHB_DMA_STPADDR2                   0x360a
+#define HDMI_AHB_DMA_STPADDR3                   0x360b
+#define HDMI_AHB_DMA_BSTADDR0                   0x360c
+#define HDMI_AHB_DMA_BSTADDR1                   0x360d
+#define HDMI_AHB_DMA_BSTADDR2                   0x360e
+#define HDMI_AHB_DMA_BSTADDR3                   0x360f
+#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
+#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
+#define HDMI_AHB_DMA_STAT                       0x3612
+#define HDMI_AHB_DMA_INT                        0x3613
+#define HDMI_AHB_DMA_MASK                       0x3614
+#define HDMI_AHB_DMA_POL                        0x3615
+#define HDMI_AHB_DMA_CONF1                      0x3616
+#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
+#define HDMI_AHB_DMA_BUFFINT                    0x3618
+#define HDMI_AHB_DMA_BUFFMASK                   0x3619
+#define HDMI_AHB_DMA_BUFFPOL                    0x361a
+
+/* Main Controller Registers */
+#define HDMI_MC_SFRDIV                          0x4000
+#define HDMI_MC_CLKDIS                          0x4001
+#define HDMI_MC_SWRSTZ                          0x4002
+#define HDMI_MC_OPCTRL                          0x4003
+#define HDMI_MC_FLOWCTRL                        0x4004
+#define HDMI_MC_PHYRSTZ                         0x4005
+#define HDMI_MC_LOCKONCLOCK                     0x4006
+#define HDMI_MC_HEACPHY_RST                     0x4007
+
+/* Color Space  Converter Registers */
+#define HDMI_CSC_CFG                            0x4100
+#define HDMI_CSC_SCALE                          0x4101
+#define HDMI_CSC_COEF_A1_MSB                    0x4102
+#define HDMI_CSC_COEF_A1_LSB                    0x4103
+#define HDMI_CSC_COEF_A2_MSB                    0x4104
+#define HDMI_CSC_COEF_A2_LSB                    0x4105
+#define HDMI_CSC_COEF_A3_MSB                    0x4106
+#define HDMI_CSC_COEF_A3_LSB                    0x4107
+#define HDMI_CSC_COEF_A4_MSB                    0x4108
+#define HDMI_CSC_COEF_A4_LSB                    0x4109
+#define HDMI_CSC_COEF_B1_MSB                    0x410A
+#define HDMI_CSC_COEF_B1_LSB                    0x410B
+#define HDMI_CSC_COEF_B2_MSB                    0x410C
+#define HDMI_CSC_COEF_B2_LSB                    0x410D
+#define HDMI_CSC_COEF_B3_MSB                    0x410E
+#define HDMI_CSC_COEF_B3_LSB                    0x410F
+#define HDMI_CSC_COEF_B4_MSB                    0x4110
+#define HDMI_CSC_COEF_B4_LSB                    0x4111
+#define HDMI_CSC_COEF_C1_MSB                    0x4112
+#define HDMI_CSC_COEF_C1_LSB                    0x4113
+#define HDMI_CSC_COEF_C2_MSB                    0x4114
+#define HDMI_CSC_COEF_C2_LSB                    0x4115
+#define HDMI_CSC_COEF_C3_MSB                    0x4116
+#define HDMI_CSC_COEF_C3_LSB                    0x4117
+#define HDMI_CSC_COEF_C4_MSB                    0x4118
+#define HDMI_CSC_COEF_C4_LSB                    0x4119
+
+/* HDCP Encryption Engine Registers */
+#define HDMI_A_HDCPCFG0                         0x5000
+#define HDMI_A_HDCPCFG1                         0x5001
+#define HDMI_A_HDCPOBS0                         0x5002
+#define HDMI_A_HDCPOBS1                         0x5003
+#define HDMI_A_HDCPOBS2                         0x5004
+#define HDMI_A_HDCPOBS3                         0x5005
+#define HDMI_A_APIINTCLR                        0x5006
+#define HDMI_A_APIINTSTAT                       0x5007
+#define HDMI_A_APIINTMSK                        0x5008
+#define HDMI_A_VIDPOLCFG                        0x5009
+#define HDMI_A_OESSWCFG                         0x500A
+#define HDMI_A_TIMER1SETUP0                     0x500B
+#define HDMI_A_TIMER1SETUP1                     0x500C
+#define HDMI_A_TIMER2SETUP0                     0x500D
+#define HDMI_A_TIMER2SETUP1                     0x500E
+#define HDMI_A_100MSCFG                         0x500F
+#define HDMI_A_2SCFG0                           0x5010
+#define HDMI_A_2SCFG1                           0x5011
+#define HDMI_A_5SCFG0                           0x5012
+#define HDMI_A_5SCFG1                           0x5013
+#define HDMI_A_SRMVERLSB                        0x5014
+#define HDMI_A_SRMVERMSB                        0x5015
+#define HDMI_A_SRMCTRL                          0x5016
+#define HDMI_A_SFRSETUP                         0x5017
+#define HDMI_A_I2CHSETUP                        0x5018
+#define HDMI_A_INTSETUP                         0x5019
+#define HDMI_A_PRESETUP                         0x501A
+#define HDMI_A_SRM_BASE                         0x5020
+
+/* CEC Engine Registers */
+#define HDMI_CEC_CTRL                           0x7D00
+#define HDMI_CEC_STAT                           0x7D01
+#define HDMI_CEC_MASK                           0x7D02
+#define HDMI_CEC_POLARITY                       0x7D03
+#define HDMI_CEC_INT                            0x7D04
+#define HDMI_CEC_ADDR_L                         0x7D05
+#define HDMI_CEC_ADDR_H                         0x7D06
+#define HDMI_CEC_TX_CNT                         0x7D07
+#define HDMI_CEC_RX_CNT                         0x7D08
+#define HDMI_CEC_TX_DATA0                       0x7D10
+#define HDMI_CEC_TX_DATA1                       0x7D11
+#define HDMI_CEC_TX_DATA2                       0x7D12
+#define HDMI_CEC_TX_DATA3                       0x7D13
+#define HDMI_CEC_TX_DATA4                       0x7D14
+#define HDMI_CEC_TX_DATA5                       0x7D15
+#define HDMI_CEC_TX_DATA6                       0x7D16
+#define HDMI_CEC_TX_DATA7                       0x7D17
+#define HDMI_CEC_TX_DATA8                       0x7D18
+#define HDMI_CEC_TX_DATA9                       0x7D19
+#define HDMI_CEC_TX_DATA10                      0x7D1a
+#define HDMI_CEC_TX_DATA11                      0x7D1b
+#define HDMI_CEC_TX_DATA12                      0x7D1c
+#define HDMI_CEC_TX_DATA13                      0x7D1d
+#define HDMI_CEC_TX_DATA14                      0x7D1e
+#define HDMI_CEC_TX_DATA15                      0x7D1f
+#define HDMI_CEC_RX_DATA0                       0x7D20
+#define HDMI_CEC_RX_DATA1                       0x7D21
+#define HDMI_CEC_RX_DATA2                       0x7D22
+#define HDMI_CEC_RX_DATA3                       0x7D23
+#define HDMI_CEC_RX_DATA4                       0x7D24
+#define HDMI_CEC_RX_DATA5                       0x7D25
+#define HDMI_CEC_RX_DATA6                       0x7D26
+#define HDMI_CEC_RX_DATA7                       0x7D27
+#define HDMI_CEC_RX_DATA8                       0x7D28
+#define HDMI_CEC_RX_DATA9                       0x7D29
+#define HDMI_CEC_RX_DATA10                      0x7D2a
+#define HDMI_CEC_RX_DATA11                      0x7D2b
+#define HDMI_CEC_RX_DATA12                      0x7D2c
+#define HDMI_CEC_RX_DATA13                      0x7D2d
+#define HDMI_CEC_RX_DATA14                      0x7D2e
+#define HDMI_CEC_RX_DATA15                      0x7D2f
+#define HDMI_CEC_LOCK                           0x7D30
+#define HDMI_CEC_WKUPCTRL                       0x7D31
+
+/* I2C Master Registers (E-DDC) */
+#define HDMI_I2CM_SLAVE                         0x7E00
+#define HDMI_I2CMESS                            0x7E01
+#define HDMI_I2CM_DATAO                         0x7E02
+#define HDMI_I2CM_DATAI                         0x7E03
+#define HDMI_I2CM_OPERATION                     0x7E04
+#define HDMI_I2CM_INT                           0x7E05
+#define HDMI_I2CM_CTLINT                        0x7E06
+#define HDMI_I2CM_DIV                           0x7E07
+#define HDMI_I2CM_SEGADDR                       0x7E08
+#define HDMI_I2CM_SOFTRSTZ                      0x7E09
+#define HDMI_I2CM_SEGPTR                        0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
+
+enum {
+/* IH_FC_INT2 field values */
+	HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_FC_STAT2 field values */
+	HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_PHY_STAT0 field values */
+	HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
+	HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
+	HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
+	HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
+	HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
+	HDMI_IH_PHY_STAT0_HPD = 0x1,
+
+/* IH_MUTE_I2CMPHY_STAT0 field values */
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
+/* IH_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE_FC_STAT2 field values */
+	HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_MUTE_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE field values */
+	HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
+	HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
+
+/* TX_INVID0 field values */
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
+	HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
+	HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
+
+/* TX_INSTUFFING field values */
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
+
+/* VP_PR_CD field values */
+	HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
+	HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
+
+/* VP_STUFF field values */
+	HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
+	HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
+	HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
+
+/* VP_CONF field values */
+	HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
+	HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
+	HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PR_EN_MASK = 0x10,
+	HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
+	HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
+	HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
+	HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
+	HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
+
+/* VP_REMAP field values */
+	HDMI_VP_REMAP_MASK = 0x3,
+	HDMI_VP_REMAP_YCC422_24bit = 0x2,
+	HDMI_VP_REMAP_YCC422_20bit = 0x1,
+	HDMI_VP_REMAP_YCC422_16bit = 0x0,
+
+/* FC_INVIDCONF field values */
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
+	HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
+
+/* FC_AUDICONF0 field values */
+	HDMI_FC_AUDICONF0_CC_OFFSET = 4,
+	HDMI_FC_AUDICONF0_CC_MASK = 0x70,
+	HDMI_FC_AUDICONF0_CT_OFFSET = 0,
+	HDMI_FC_AUDICONF0_CT_MASK = 0xF,
+
+/* FC_AUDICONF1 field values */
+	HDMI_FC_AUDICONF1_SS_OFFSET = 3,
+	HDMI_FC_AUDICONF1_SS_MASK = 0x18,
+	HDMI_FC_AUDICONF1_SF_OFFSET = 0,
+	HDMI_FC_AUDICONF1_SF_MASK = 0x7,
+
+/* FC_AUDICONF3 field values */
+	HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
+	HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
+	HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
+	HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
+	HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
+	HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
+
+/* FC_AUDSCHNLS0 field values */
+	HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
+
+/* FC_AUDSCHNLS3-6 field values */
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
+
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
+
+/* HDMI_FC_AUDSCHNLS7 field values */
+	HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+
+/* HDMI_FC_AUDSCHNLS8 field values */
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+
+/* FC_AUDSCONF field values */
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
+
+/* FC_STAT2 field values */
+	HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_INT2 field values */
+	HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_MASK2 field values */
+	HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_PRCONF field values */
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
+
+/* FC_AVICONF0-FC_AVICONF3 field values */
+	HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
+	HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
+	HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+	HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+	HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+	HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+	HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
+	HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
+
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
+	HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
+	HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
+	HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
+	HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
+
+	HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
+	HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
+	HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
+	HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
+	HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
+	HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
+	HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
+	HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
+	HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
+	HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
+	HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
+	HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
+
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
+	HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
+	HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
+	HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+
+/* FC_DBGFORCE field values */
+	HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
+	HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+
+/* PHY_CONF0 field values */
+	HDMI_PHY_CONF0_PDZ_MASK = 0x80,
+	HDMI_PHY_CONF0_PDZ_OFFSET = 7,
+	HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
+	HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
+	HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
+	HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
+	HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
+	HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
+	HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
+	HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
+	HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
+	HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
+
+/* PHY_TST0 field values */
+	HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
+	HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
+	HDMI_PHY_TST0_TSTEN_MASK = 0x10,
+	HDMI_PHY_TST0_TSTEN_OFFSET = 4,
+	HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
+	HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
+
+/* PHY_STAT0 field values */
+	HDMI_PHY_RX_SENSE3 = 0x80,
+	HDMI_PHY_RX_SENSE2 = 0x40,
+	HDMI_PHY_RX_SENSE1 = 0x20,
+	HDMI_PHY_RX_SENSE0 = 0x10,
+	HDMI_PHY_HPD = 0x02,
+	HDMI_PHY_TX_PHY_LOCK = 0x01,
+
+/* PHY_I2CM_SLAVE_ADDR field values */
+	HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
+	HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
+
+/* PHY_I2CM_OPERATION_ADDR field values */
+	HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
+	HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
+
+/* HDMI_PHY_I2CM_INT_ADDR */
+	HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
+	HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
+
+/* HDMI_PHY_I2CM_CTLINT_ADDR */
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
+
+/* AUD_CTS3 field values */
+	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
+	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
+	HDMI_AUD_CTS3_N_SHIFT_1 = 0,
+	HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
+	HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
+	HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
+	HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
+	HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
+	/* note that the CTS3 MANUAL bit has been removed
+	   from our part. Can't set it, will read as 0. */
+	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
+	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
+
+/* AHB_DMA_CONF0 field values */
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
+	HDMI_AHB_DMA_CONF0_HBR = 0x10,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
+	HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
+	HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
+	HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
+	HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
+
+/* HDMI_AHB_DMA_START field values */
+	HDMI_AHB_DMA_START_START_OFFSET = 0,
+	HDMI_AHB_DMA_START_START_MASK = 0x01,
+
+/* HDMI_AHB_DMA_STOP field values */
+	HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
+	HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
+
+/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
+	HDMI_AHB_DMA_DONE = 0x80,
+	HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
+	HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
+	HDMI_AHB_DMA_ERROR = 0x10,
+	HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
+	HDMI_AHB_DMA_FIFO_FULL = 0x02,
+	HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
+
+/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
+	HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
+	HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
+
+/* MC_CLKDIS field values */
+	HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
+	HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
+	HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
+	HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
+	HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
+	HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
+	HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
+
+/* MC_SWRSTZ field values */
+	HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+
+/* MC_FLOWCTRL field values */
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
+
+/* MC_PHYRSTZ field values */
+	HDMI_MC_PHYRSTZ_ASSERT = 0x0,
+	HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+
+/* MC_HEACPHY_RST field values */
+	HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
+	HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
+
+/* CSC_CFG field values */
+	HDMI_CSC_CFG_INTMODE_MASK = 0x30,
+	HDMI_CSC_CFG_INTMODE_OFFSET = 4,
+	HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
+	HDMI_CSC_CFG_DECMODE_MASK = 0x3,
+	HDMI_CSC_CFG_DECMODE_OFFSET = 0,
+	HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
+
+/* CSC_SCALE field values */
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
+	HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
+
+/* A_HDCPCFG0 field values */
+	HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
+
+/* A_HDCPCFG1 field values */
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
+	HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+
+/* A_VIDPOLCFG field values */
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
+	HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
+};
+
+#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index d466696..826833e 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -13,20 +13,23 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
+#include <linux/of_graph.h>
 
-#include "drmP.h"
-#include "drm_edid.h"
-#include "drm_crtc.h"
-#include "drm_crtc_helper.h"
+#include <drm/drm_panel.h>
 
 #include "bridge/ptn3460.h"
 
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+#include "drmP.h"
+
 #define PTN3460_EDID_ADDR			0x0
 #define PTN3460_EDID_EMULATION_ADDR		0x84
 #define PTN3460_EDID_ENABLE_EMULATION		0
@@ -36,15 +39,27 @@
 struct ptn3460_bridge {
 	struct drm_connector connector;
 	struct i2c_client *client;
-	struct drm_encoder *encoder;
-	struct drm_bridge *bridge;
+	struct drm_bridge bridge;
 	struct edid *edid;
-	int gpio_pd_n;
-	int gpio_rst_n;
+	struct drm_panel *panel;
+	struct gpio_desc *gpio_pd_n;
+	struct gpio_desc *gpio_rst_n;
 	u32 edid_emulation;
 	bool enabled;
 };
 
+static inline struct ptn3460_bridge *
+		bridge_to_ptn3460(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct ptn3460_bridge, bridge);
+}
+
+static inline struct ptn3460_bridge *
+		connector_to_ptn3460(struct drm_connector *connector)
+{
+	return container_of(connector, struct ptn3460_bridge, connector);
+}
+
 static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
 		u8 *buf, int len)
 {
@@ -92,7 +107,7 @@
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
 			ptn_bridge->edid_emulation);
 	if (ret) {
-		DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
+		DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -102,7 +117,7 @@
 
 	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
 	if (ret) {
-		DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
+		DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
 		return ret;
 	}
 
@@ -111,19 +126,21 @@
 
 static void ptn3460_pre_enable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
 
 	if (ptn_bridge->enabled)
 		return;
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
-		udelay(10);
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
+	usleep_range(10, 20);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
+
+	if (drm_panel_prepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to prepare panel\n");
+		return;
 	}
 
 	/*
@@ -135,73 +152,67 @@
 
 	ret = ptn3460_select_edid(ptn_bridge);
 	if (ret)
-		DRM_ERROR("Select edid failed ret=%d\n", ret);
+		DRM_ERROR("Select EDID failed ret=%d\n", ret);
 
 	ptn_bridge->enabled = true;
 }
 
 static void ptn3460_enable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_enable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to enable panel\n");
+		return;
+	}
 }
 
 static void ptn3460_disable(struct drm_bridge *bridge)
 {
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 
 	if (!ptn_bridge->enabled)
 		return;
 
 	ptn_bridge->enabled = false;
 
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+	if (drm_panel_disable(ptn_bridge->panel)) {
+		DRM_ERROR("failed to disable panel\n");
+		return;
+	}
 
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_set_value(ptn_bridge->gpio_pd_n, 0);
+	gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
+	gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
 }
 
 static void ptn3460_post_disable(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+	if (drm_panel_unprepare(ptn_bridge->panel)) {
+		DRM_ERROR("failed to unprepare panel\n");
+		return;
+	}
 }
 
-void ptn3460_bridge_destroy(struct drm_bridge *bridge)
-{
-	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
-
-	drm_bridge_cleanup(bridge);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
-	/* Nothing else to free, we've got devm allocated memory */
-}
-
-struct drm_bridge_funcs ptn3460_bridge_funcs = {
-	.pre_enable = ptn3460_pre_enable,
-	.enable = ptn3460_enable,
-	.disable = ptn3460_disable,
-	.post_disable = ptn3460_post_disable,
-	.destroy = ptn3460_bridge_destroy,
-};
-
-int ptn3460_get_modes(struct drm_connector *connector)
+static int ptn3460_get_modes(struct drm_connector *connector)
 {
 	struct ptn3460_bridge *ptn_bridge;
 	u8 *edid;
-	int ret, num_modes;
+	int ret, num_modes = 0;
 	bool power_off;
 
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+	ptn_bridge = connector_to_ptn3460(connector);
 
 	if (ptn_bridge->edid)
 		return drm_add_edid_modes(connector, ptn_bridge->edid);
 
 	power_off = !ptn_bridge->enabled;
-	ptn3460_pre_enable(ptn_bridge->bridge);
+	ptn3460_pre_enable(&ptn_bridge->bridge);
 
 	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
 	if (!edid) {
-		DRM_ERROR("Failed to allocate edid\n");
+		DRM_ERROR("Failed to allocate EDID\n");
 		return 0;
 	}
 
@@ -209,7 +220,6 @@
 			EDID_LENGTH);
 	if (ret) {
 		kfree(edid);
-		num_modes = 0;
 		goto out;
 	}
 
@@ -220,124 +230,188 @@
 
 out:
 	if (power_off)
-		ptn3460_disable(ptn_bridge->bridge);
+		ptn3460_disable(&ptn_bridge->bridge);
 
 	return num_modes;
 }
 
-struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
 {
-	struct ptn3460_bridge *ptn_bridge;
+	struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
 
-	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
-
-	return ptn_bridge->encoder;
+	return ptn_bridge->bridge.encoder;
 }
 
-struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
 	.get_modes = ptn3460_get_modes,
 	.best_encoder = ptn3460_best_encoder,
 };
 
-enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
+static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
 		bool force)
 {
 	return connector_status_connected;
 }
 
-void ptn3460_connector_destroy(struct drm_connector *connector)
+static void ptn3460_connector_destroy(struct drm_connector *connector)
 {
 	drm_connector_cleanup(connector);
 }
 
-struct drm_connector_funcs ptn3460_connector_funcs = {
+static struct drm_connector_funcs ptn3460_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = ptn3460_detect,
 	.destroy = ptn3460_connector_destroy,
 };
 
-int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
-		struct i2c_client *client, struct device_node *node)
+int ptn3460_bridge_attach(struct drm_bridge *bridge)
 {
+	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
 	int ret;
-	struct drm_bridge *bridge;
-	struct ptn3460_bridge *ptn_bridge;
 
-	bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
-	if (!bridge) {
-		DRM_ERROR("Failed to allocate drm bridge\n");
-		return -ENOMEM;
+	if (!bridge->encoder) {
+		DRM_ERROR("Parent encoder object not found");
+		return -ENODEV;
 	}
 
-	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
-	if (!ptn_bridge) {
-		DRM_ERROR("Failed to allocate ptn bridge\n");
-		return -ENOMEM;
-	}
-
-	ptn_bridge->client = client;
-	ptn_bridge->encoder = encoder;
-	ptn_bridge->bridge = bridge;
-	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
-		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
-				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
-		if (ret) {
-			DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
-			return ret;
-		}
-	}
-
-	ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
-		/*
-		 * Request the reset pin low to avoid the bridge being
-		 * initialized prematurely
-		 */
-		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
-				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
-		if (ret) {
-			DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
-			gpio_free(ptn_bridge->gpio_pd_n);
-			return ret;
-		}
-	}
-
-	ret = of_property_read_u32(node, "edid-emulation",
-			&ptn_bridge->edid_emulation);
-	if (ret) {
-		DRM_ERROR("Can't read edid emulation value\n");
-		goto err;
-	}
-
-	ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
-	if (ret) {
-		DRM_ERROR("Failed to initialize bridge with drm\n");
-		goto err;
-	}
-
-	bridge->driver_private = ptn_bridge;
-	encoder->bridge = bridge;
-
-	ret = drm_connector_init(dev, &ptn_bridge->connector,
+	ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
+	ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
 			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 	if (ret) {
 		DRM_ERROR("Failed to initialize connector with drm\n");
-		goto err;
+		return ret;
 	}
 	drm_connector_helper_add(&ptn_bridge->connector,
-			&ptn3460_connector_helper_funcs);
+					&ptn3460_connector_helper_funcs);
 	drm_connector_register(&ptn_bridge->connector);
-	drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
+	drm_mode_connector_attach_encoder(&ptn_bridge->connector,
+							bridge->encoder);
 
-	return 0;
+	if (ptn_bridge->panel)
+		drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
 
-err:
-	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
-		gpio_free(ptn_bridge->gpio_pd_n);
-	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
-		gpio_free(ptn_bridge->gpio_rst_n);
+	drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
+
 	return ret;
 }
-EXPORT_SYMBOL(ptn3460_init);
+
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
+	.pre_enable = ptn3460_pre_enable,
+	.enable = ptn3460_enable,
+	.disable = ptn3460_disable,
+	.post_disable = ptn3460_post_disable,
+	.attach = ptn3460_bridge_attach,
+};
+
+static int ptn3460_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct ptn3460_bridge *ptn_bridge;
+	struct device_node *endpoint, *panel_node;
+	int ret;
+
+	ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
+	if (!ptn_bridge) {
+		return -ENOMEM;
+	}
+
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		if (panel_node) {
+			ptn_bridge->panel = of_drm_find_panel(panel_node);
+			of_node_put(panel_node);
+			if (!ptn_bridge->panel)
+				return -EPROBE_DEFER;
+		}
+	}
+
+	ptn_bridge->client = client;
+
+	ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown");
+	if (IS_ERR(ptn_bridge->gpio_pd_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_pd_n);
+		dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
+		return ret;
+	}
+
+	ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_pd_n\n");
+		return ret;
+	}
+
+	ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
+	if (IS_ERR(ptn_bridge->gpio_rst_n)) {
+		ret = PTR_ERR(ptn_bridge->gpio_rst_n);
+		DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Request the reset pin low to avoid the bridge being
+	 * initialized prematurely
+	 */
+	ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0);
+	if (ret) {
+		DRM_ERROR("cannot configure gpio_rst_n\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "edid-emulation",
+			&ptn_bridge->edid_emulation);
+	if (ret) {
+		dev_err(dev, "Can't read EDID emulation value\n");
+		return ret;
+	}
+
+	ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+	ptn_bridge->bridge.of_node = dev->of_node;
+	ret = drm_bridge_add(&ptn_bridge->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to add bridge\n");
+		return ret;
+	}
+
+	i2c_set_clientdata(client, ptn_bridge);
+
+	return 0;
+}
+
+static int ptn3460_remove(struct i2c_client *client)
+{
+	struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&ptn_bridge->bridge);
+
+	return 0;
+}
+
+static const struct i2c_device_id ptn3460_i2c_table[] = {
+	{"nxp,ptn3460", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
+
+static const struct of_device_id ptn3460_match[] = {
+	{ .compatible = "nxp,ptn3460" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ptn3460_match);
+
+static struct i2c_driver ptn3460_driver = {
+	.id_table	= ptn3460_i2c_table,
+	.probe		= ptn3460_probe,
+	.remove		= ptn3460_remove,
+	.driver		= {
+		.name	= "nxp,ptn3460",
+		.owner	= THIS_MODULE,
+		.of_match_table = ptn3460_match,
+	},
+};
+module_i2c_driver(ptn3460_driver);
+
+MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
+MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 502a89e..13ddf1c 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -317,17 +317,17 @@
 
 	ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
 				 cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
-	if (ret) {
-		kfree(gfbdev);
+	if (ret)
 		return ret;
-	}
-	drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
+
+	ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
+	if (ret)
+		return ret;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(cdev->dev);
-	drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
 
-	return 0;
+	return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
 }
 
 void cirrus_fbdev_fini(struct cirrus_device *cdev)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index ff5f034..c2e9c52 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -56,6 +56,11 @@
 	if (!state)
 		return NULL;
 
+	/* TODO legacy paths should maybe do a better job about
+	 * setting this appropriately?
+	 */
+	state->allow_modeset = true;
+
 	state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
 
 	state->crtcs = kcalloc(dev->mode_config.num_crtc,
@@ -129,6 +134,7 @@
 
 		connector->funcs->atomic_destroy_state(connector,
 						       state->connector_states[i]);
+		state->connector_states[i] = NULL;
 	}
 
 	for (i = 0; i < config->num_crtc; i++) {
@@ -139,6 +145,7 @@
 
 		crtc->funcs->atomic_destroy_state(crtc,
 						  state->crtc_states[i]);
+		state->crtc_states[i] = NULL;
 	}
 
 	for (i = 0; i < config->num_total_plane; i++) {
@@ -149,6 +156,7 @@
 
 		plane->funcs->atomic_destroy_state(plane,
 						   state->plane_states[i]);
+		state->plane_states[i] = NULL;
 	}
 }
 EXPORT_SYMBOL(drm_atomic_state_clear);
@@ -217,6 +225,83 @@
 EXPORT_SYMBOL(drm_atomic_get_crtc_state);
 
 /**
+ * drm_atomic_crtc_set_property - set property on CRTC
+ * @crtc: the drm CRTC to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling crtc->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state, struct drm_property *property,
+		uint64_t val)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	/* FIXME: Mode prop is missing, which also controls ->enable. */
+	if (property == config->prop_active) {
+		state->active = val;
+	} else if (crtc->funcs->atomic_set_property)
+		return crtc->funcs->atomic_set_property(crtc, state, property, val);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_atomic_crtc_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
+		const struct drm_crtc_state *state,
+		struct drm_property *property, uint64_t *val)
+{
+	if (crtc->funcs->atomic_get_property)
+		return crtc->funcs->atomic_get_property(crtc, state, property, val);
+	return -EINVAL;
+}
+
+/**
+ * drm_atomic_crtc_check - check crtc state
+ * @crtc: crtc to check
+ * @state: crtc state to check
+ *
+ * Provides core sanity checks for crtc state.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static int drm_atomic_crtc_check(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	/* NOTE: we explicitly don't enforce constraints such as primary
+	 * layer covering entire screen, since that is something we want
+	 * to allow (on hw that supports it).  For hw that does not, it
+	 * should be checked in driver's crtc->atomic_check() vfunc.
+	 *
+	 * TODO: Add generic modeset state checks once we support those.
+	 */
+
+	if (state->active && !state->enable) {
+		DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n",
+			      crtc->base.id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
  * drm_atomic_get_plane_state - get plane state
  * @state: global atomic state object
  * @plane: plane to get state object for
@@ -272,6 +357,185 @@
 EXPORT_SYMBOL(drm_atomic_get_plane_state);
 
 /**
+ * drm_atomic_plane_set_property - set property on plane
+ * @plane: the drm plane to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling plane->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_plane_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 drm_mode_config *config = &dev->mode_config;
+
+	if (property == config->prop_fb_id) {
+		struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val);
+		drm_atomic_set_fb_for_plane(state, fb);
+		if (fb)
+			drm_framebuffer_unreference(fb);
+	} else if (property == config->prop_crtc_id) {
+		struct drm_crtc *crtc = drm_crtc_find(dev, val);
+		return drm_atomic_set_crtc_for_plane(state, crtc);
+	} else if (property == config->prop_crtc_x) {
+		state->crtc_x = U642I64(val);
+	} else if (property == config->prop_crtc_y) {
+		state->crtc_y = U642I64(val);
+	} else if (property == config->prop_crtc_w) {
+		state->crtc_w = val;
+	} else if (property == config->prop_crtc_h) {
+		state->crtc_h = val;
+	} else if (property == config->prop_src_x) {
+		state->src_x = val;
+	} else if (property == config->prop_src_y) {
+		state->src_y = val;
+	} else if (property == config->prop_src_w) {
+		state->src_w = val;
+	} else if (property == config->prop_src_h) {
+		state->src_h = val;
+	} else if (property == config->rotation_property) {
+		state->rotation = val;
+	} else if (plane->funcs->atomic_set_property) {
+		return plane->funcs->atomic_set_property(plane, state,
+				property, val);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_plane_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+static int
+drm_atomic_plane_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 drm_mode_config *config = &dev->mode_config;
+
+	if (property == config->prop_fb_id) {
+		*val = (state->fb) ? state->fb->base.id : 0;
+	} else if (property == config->prop_crtc_id) {
+		*val = (state->crtc) ? state->crtc->base.id : 0;
+	} else if (property == config->prop_crtc_x) {
+		*val = I642U64(state->crtc_x);
+	} else if (property == config->prop_crtc_y) {
+		*val = I642U64(state->crtc_y);
+	} else if (property == config->prop_crtc_w) {
+		*val = state->crtc_w;
+	} else if (property == config->prop_crtc_h) {
+		*val = state->crtc_h;
+	} else if (property == config->prop_src_x) {
+		*val = state->src_x;
+	} else if (property == config->prop_src_y) {
+		*val = state->src_y;
+	} else if (property == config->prop_src_w) {
+		*val = state->src_w;
+	} else if (property == config->prop_src_h) {
+		*val = state->src_h;
+	} else if (plane->funcs->atomic_get_property) {
+		return plane->funcs->atomic_get_property(plane, state, property, val);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * drm_atomic_plane_check - check plane state
+ * @plane: plane to check
+ * @state: plane state to check
+ *
+ * Provides core sanity checks for plane state.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static int drm_atomic_plane_check(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	unsigned int fb_width, fb_height;
+	unsigned int i;
+
+	/* either *both* CRTC and FB must be set, or neither */
+	if (WARN_ON(state->crtc && !state->fb)) {
+		DRM_DEBUG_KMS("CRTC set but no FB\n");
+		return -EINVAL;
+	} else if (WARN_ON(state->fb && !state->crtc)) {
+		DRM_DEBUG_KMS("FB set but no CRTC\n");
+		return -EINVAL;
+	}
+
+	/* if disabled, we don't care about the rest of the state: */
+	if (!state->crtc)
+		return 0;
+
+	/* Check whether this plane is usable on this CRTC */
+	if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
+		DRM_DEBUG_KMS("Invalid crtc for plane\n");
+		return -EINVAL;
+	}
+
+	/* Check whether this plane supports the fb pixel format. */
+	for (i = 0; i < plane->format_count; i++)
+		if (state->fb->pixel_format == plane->format_types[i])
+			break;
+	if (i == plane->format_count) {
+		DRM_DEBUG_KMS("Invalid pixel format %s\n",
+			      drm_get_format_name(state->fb->pixel_format));
+		return -EINVAL;
+	}
+
+	/* Give drivers some help against integer overflows */
+	if (state->crtc_w > INT_MAX ||
+	    state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+	    state->crtc_h > INT_MAX ||
+	    state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+			      state->crtc_w, state->crtc_h,
+			      state->crtc_x, state->crtc_y);
+		return -ERANGE;
+	}
+
+	fb_width = state->fb->width << 16;
+	fb_height = state->fb->height << 16;
+
+	/* Make sure source coordinates are inside the fb. */
+	if (state->src_w > fb_width ||
+	    state->src_x > fb_width - state->src_w ||
+	    state->src_h > fb_height ||
+	    state->src_y > fb_height - state->src_h) {
+		DRM_DEBUG_KMS("Invalid source coordinates "
+			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+			      state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
+			      state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
+			      state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
+			      state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
@@ -343,9 +607,113 @@
 EXPORT_SYMBOL(drm_atomic_get_connector_state);
 
 /**
+ * drm_atomic_connector_set_property - set property on connector.
+ * @connector: the drm connector to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling connector->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_connector_set_property(struct drm_connector *connector,
+		struct drm_connector_state *state, struct drm_property *property,
+		uint64_t val)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	if (property == config->prop_crtc_id) {
+		struct drm_crtc *crtc = drm_crtc_find(dev, val);
+		return drm_atomic_set_crtc_for_connector(state, crtc);
+	} else if (property == config->dpms_property) {
+		/* setting DPMS property requires special handling, which
+		 * is done in legacy setprop path for us.  Disallow (for
+		 * now?) atomic writes to DPMS property:
+		 */
+		return -EINVAL;
+	} else if (connector->funcs->atomic_set_property) {
+		return connector->funcs->atomic_set_property(connector,
+				state, property, val);
+	} else {
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(drm_atomic_connector_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties.  To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+static int
+drm_atomic_connector_get_property(struct drm_connector *connector,
+		const struct drm_connector_state *state,
+		struct drm_property *property, uint64_t *val)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	if (property == config->prop_crtc_id) {
+		*val = (state->crtc) ? state->crtc->base.id : 0;
+	} else if (property == config->dpms_property) {
+		*val = connector->dpms;
+	} else if (connector->funcs->atomic_get_property) {
+		return connector->funcs->atomic_get_property(connector,
+				state, property, val);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int drm_atomic_get_property(struct drm_mode_object *obj,
+		struct drm_property *property, uint64_t *val)
+{
+	struct drm_device *dev = property->dev;
+	int ret;
+
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_CONNECTOR: {
+		struct drm_connector *connector = obj_to_connector(obj);
+		WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+		ret = drm_atomic_connector_get_property(connector,
+				connector->state, property, val);
+		break;
+	}
+	case DRM_MODE_OBJECT_CRTC: {
+		struct drm_crtc *crtc = obj_to_crtc(obj);
+		WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+		ret = drm_atomic_crtc_get_property(crtc,
+				crtc->state, property, val);
+		break;
+	}
+	case DRM_MODE_OBJECT_PLANE: {
+		struct drm_plane *plane = obj_to_plane(obj);
+		WARN_ON(!drm_modeset_is_locked(&plane->mutex));
+		ret = drm_atomic_plane_get_property(plane,
+				plane->state, property, val);
+		break;
+	}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/**
  * drm_atomic_set_crtc_for_plane - set crtc for plane
- * @state: the incoming atomic state
- * @plane: the plane whose incoming state to update
+ * @plane_state: the plane whose incoming state to update
  * @crtc: crtc to use for the plane
  *
  * Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -358,16 +726,12 @@
  * sequence must be restarted. All other errors are fatal.
  */
 int
-drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
-			      struct drm_plane *plane, struct drm_crtc *crtc)
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc)
 {
-	struct drm_plane_state *plane_state =
-			drm_atomic_get_plane_state(state, plane);
+	struct drm_plane *plane = plane_state->plane;
 	struct drm_crtc_state *crtc_state;
 
-	if (WARN_ON(IS_ERR(plane_state)))
-		return PTR_ERR(plane_state);
-
 	if (plane_state->crtc) {
 		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
 						       plane_state->crtc);
@@ -583,14 +947,63 @@
  */
 int drm_atomic_check_only(struct drm_atomic_state *state)
 {
-	struct drm_mode_config *config = &state->dev->mode_config;
+	struct drm_device *dev = state->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+	int nplanes = config->num_total_plane;
+	int ncrtcs = config->num_crtc;
+	int i, ret = 0;
 
 	DRM_DEBUG_KMS("checking %p\n", state);
 
+	for (i = 0; i < nplanes; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		ret = drm_atomic_plane_check(plane, state->plane_states[i]);
+		if (ret) {
+			DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n",
+				      plane->base.id);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+
+		if (!crtc)
+			continue;
+
+		ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
+		if (ret) {
+			DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n",
+				      crtc->base.id);
+			return ret;
+		}
+	}
+
 	if (config->funcs->atomic_check)
-		return config->funcs->atomic_check(state->dev, state);
-	else
-		return 0;
+		ret = config->funcs->atomic_check(state->dev, state);
+
+	if (!state->allow_modeset) {
+		for (i = 0; i < ncrtcs; i++) {
+			struct drm_crtc *crtc = state->crtcs[i];
+			struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+			if (!crtc)
+				continue;
+
+			if (crtc_state->mode_changed ||
+			    crtc_state->active_changed) {
+				DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
+					      crtc->base.id);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_check_only);
 
@@ -655,3 +1068,315 @@
 	return config->funcs->atomic_commit(state->dev, state, true);
 }
 EXPORT_SYMBOL(drm_atomic_async_commit);
+
+/*
+ * The big monstor ioctl
+ */
+
+static struct drm_pending_vblank_event *create_vblank_event(
+		struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
+{
+	struct drm_pending_vblank_event *e = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (file_priv->event_space < sizeof e->event) {
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+	file_priv->event_space -= sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	e = kzalloc(sizeof *e, GFP_KERNEL);
+	if (e == NULL) {
+		spin_lock_irqsave(&dev->event_lock, flags);
+		file_priv->event_space += sizeof e->event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+
+	e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+	e->event.base.length = sizeof e->event;
+	e->event.user_data = user_data;
+	e->base.event = &e->event.base;
+	e->base.file_priv = file_priv;
+	e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+out:
+	return e;
+}
+
+static void destroy_vblank_event(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_pending_vblank_event *e)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	file_priv->event_space += sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+	kfree(e);
+}
+
+static int atomic_set_prop(struct drm_atomic_state *state,
+		struct drm_mode_object *obj, struct drm_property *prop,
+		uint64_t prop_value)
+{
+	struct drm_mode_object *ref;
+	int ret;
+
+	if (!drm_property_change_valid_get(prop, prop_value, &ref))
+		return -EINVAL;
+
+	switch (obj->type) {
+	case DRM_MODE_OBJECT_CONNECTOR: {
+		struct drm_connector *connector = obj_to_connector(obj);
+		struct drm_connector_state *connector_state;
+
+		connector_state = drm_atomic_get_connector_state(state, connector);
+		if (IS_ERR(connector_state)) {
+			ret = PTR_ERR(connector_state);
+			break;
+		}
+
+		ret = drm_atomic_connector_set_property(connector,
+				connector_state, prop, prop_value);
+		break;
+	}
+	case DRM_MODE_OBJECT_CRTC: {
+		struct drm_crtc *crtc = obj_to_crtc(obj);
+		struct drm_crtc_state *crtc_state;
+
+		crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(crtc_state)) {
+			ret = PTR_ERR(crtc_state);
+			break;
+		}
+
+		ret = drm_atomic_crtc_set_property(crtc,
+				crtc_state, prop, prop_value);
+		break;
+	}
+	case DRM_MODE_OBJECT_PLANE: {
+		struct drm_plane *plane = obj_to_plane(obj);
+		struct drm_plane_state *plane_state;
+
+		plane_state = drm_atomic_get_plane_state(state, plane);
+		if (IS_ERR(plane_state)) {
+			ret = PTR_ERR(plane_state);
+			break;
+		}
+
+		ret = drm_atomic_plane_set_property(plane,
+				plane_state, prop, prop_value);
+		break;
+	}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	drm_property_change_valid_put(prop, ref);
+	return ret;
+}
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_atomic *arg = data;
+	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+	unsigned int copied_objs, copied_props;
+	struct drm_atomic_state *state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_plane *plane;
+	unsigned plane_mask = 0;
+	int ret = 0;
+	unsigned int i, j;
+
+	/* disallow for drivers not supporting atomic: */
+	if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+		return -EINVAL;
+
+	/* disallow for userspace that has not enabled atomic cap (even
+	 * though this may be a bit overkill, since legacy userspace
+	 * wouldn't know how to call this ioctl)
+	 */
+	if (!file_priv->atomic)
+		return -EINVAL;
+
+	if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
+		return -EINVAL;
+
+	if (arg->reserved)
+		return -EINVAL;
+
+	if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) &&
+			!dev->mode_config.async_page_flip)
+		return -EINVAL;
+
+	/* can't test and expect an event at the same time. */
+	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
+			(arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
+		return -EINVAL;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = &ctx;
+	state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
+
+retry:
+	copied_objs = 0;
+	copied_props = 0;
+
+	for (i = 0; i < arg->count_objs; i++) {
+		uint32_t obj_id, count_props;
+		struct drm_mode_object *obj;
+
+		if (get_user(obj_id, objs_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+
+		obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+		if (!obj || !obj->properties) {
+			ret = -ENOENT;
+			goto fail;
+		}
+
+		if (obj->type == DRM_MODE_OBJECT_PLANE) {
+			plane = obj_to_plane(obj);
+			plane_mask |= (1 << drm_plane_index(plane));
+			plane->old_fb = plane->fb;
+		}
+
+		if (get_user(count_props, count_props_ptr + copied_objs)) {
+			ret = -EFAULT;
+			goto fail;
+		}
+
+		copied_objs++;
+
+		for (j = 0; j < count_props; j++) {
+			uint32_t prop_id;
+			uint64_t prop_value;
+			struct drm_property *prop;
+
+			if (get_user(prop_id, props_ptr + copied_props)) {
+				ret = -EFAULT;
+				goto fail;
+			}
+
+			prop = drm_property_find(dev, prop_id);
+			if (!prop) {
+				ret = -ENOENT;
+				goto fail;
+			}
+
+			if (copy_from_user(&prop_value,
+					   prop_values_ptr + copied_props,
+					   sizeof(prop_value))) {
+				ret = -EFAULT;
+				goto fail;
+			}
+
+			ret = atomic_set_prop(state, obj, prop, prop_value);
+			if (ret)
+				goto fail;
+
+			copied_props++;
+		}
+	}
+
+	if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+		int ncrtcs = dev->mode_config.num_crtc;
+
+		for (i = 0; i < ncrtcs; i++) {
+			struct drm_crtc_state *crtc_state = state->crtc_states[i];
+			struct drm_pending_vblank_event *e;
+
+			if (!crtc_state)
+				continue;
+
+			e = create_vblank_event(dev, file_priv, arg->user_data);
+			if (!e) {
+				ret = -ENOMEM;
+				goto fail;
+			}
+
+			crtc_state->event = e;
+		}
+	}
+
+	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
+		ret = drm_atomic_check_only(state);
+		/* _check_only() does not free state, unlike _commit() */
+		drm_atomic_state_free(state);
+	} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
+		ret = drm_atomic_async_commit(state);
+	} else {
+		ret = drm_atomic_commit(state);
+	}
+
+	/* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
+	 * locks (ie. while it is still safe to deref plane->state).  We
+	 * need to do this here because the driver entry points cannot
+	 * distinguish between legacy and atomic ioctls.
+	 */
+	drm_for_each_plane_mask(plane, dev, plane_mask) {
+		if (ret == 0) {
+			struct drm_framebuffer *new_fb = plane->state->fb;
+			if (new_fb)
+				drm_framebuffer_reference(new_fb);
+			plane->fb = new_fb;
+			plane->crtc = plane->state->crtc;
+		} else {
+			plane->old_fb = NULL;
+		}
+		if (plane->old_fb) {
+			drm_framebuffer_unreference(plane->old_fb);
+			plane->old_fb = NULL;
+		}
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return ret;
+
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+		int ncrtcs = dev->mode_config.num_crtc;
+
+		for (i = 0; i < ncrtcs; i++) {
+			struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+			if (!crtc_state)
+				continue;
+
+			destroy_vblank_event(dev, file_priv, crtc_state->event);
+			crtc_state->event = NULL;
+		}
+	}
+
+	drm_atomic_state_free(state);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return ret;
+
+backoff:
+	drm_atomic_state_clear(state);
+	drm_modeset_backoff(&ctx);
+
+	goto retry;
+}
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bbdbe47..7e3a52b 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -297,13 +297,22 @@
 			}
 		}
 
-
-		ret = funcs->mode_fixup(encoder, &crtc_state->mode,
-					&crtc_state->adjusted_mode);
-		if (!ret) {
-			DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
-				      encoder->base.id, encoder->name);
-			return -EINVAL;
+		if (funcs->atomic_check) {
+			ret = funcs->atomic_check(encoder, crtc_state,
+						  conn_state);
+			if (ret) {
+				DRM_DEBUG_KMS("[ENCODER:%d:%s] check failed\n",
+					      encoder->base.id, encoder->name);
+				return ret;
+			}
+		} else {
+			ret = funcs->mode_fixup(encoder, &crtc_state->mode,
+						&crtc_state->adjusted_mode);
+			if (!ret) {
+				DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
+					      encoder->base.id, encoder->name);
+				return -EINVAL;
+			}
 		}
 	}
 
@@ -330,7 +339,35 @@
 	return 0;
 }
 
-static int
+static bool
+needs_modeset(struct drm_crtc_state *state)
+{
+	return state->mode_changed || state->active_changed;
+}
+
+/**
+ * drm_atomic_helper_check - validate state object for modeset changes
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is physically possible.
+ * This does all the crtc and connector related computations for an atomic
+ * update. It computes and updates crtc_state->mode_changed, adds any additional
+ * connectors needed for full modesets and calls down into ->mode_fixup
+ * functions of the driver backend.
+ *
+ * IMPORTANT:
+ *
+ * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a
+ * plane update can't be done without a full modeset) _must_ call this function
+ * afterwards after that change. It is permitted to call this function multiple
+ * times for the same update, e.g. when the ->atomic_check functions depend upon
+ * the adjusted dotclock for fifo space allocation and watermark computation.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int
 drm_atomic_helper_check_modeset(struct drm_device *dev,
 				struct drm_atomic_state *state)
 {
@@ -382,12 +419,27 @@
 		crtc = state->crtcs[i];
 		crtc_state = state->crtc_states[i];
 
-		if (!crtc || !crtc_state->mode_changed)
+		if (!crtc)
 			continue;
 
-		DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
+		/*
+		 * We must set ->active_changed after walking connectors for
+		 * otherwise an update that only changes active would result in
+		 * a full modeset because update_connector_routing force that.
+		 */
+		if (crtc->state->active != crtc_state->active) {
+			DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
+				      crtc->base.id);
+			crtc_state->active_changed = true;
+		}
+
+		if (!needs_modeset(crtc_state))
+			continue;
+
+		DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
 			      crtc->base.id,
-			      crtc_state->enable ? 'y' : 'n');
+			      crtc_state->enable ? 'y' : 'n',
+			      crtc_state->active ? 'y' : 'n');
 
 		ret = drm_atomic_add_affected_connectors(state, crtc);
 		if (ret != 0)
@@ -406,23 +458,23 @@
 
 	return mode_fixup(state);
 }
+EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
 
 /**
- * drm_atomic_helper_check - validate state object
+ * drm_atomic_helper_check - validate state object for modeset changes
  * @dev: DRM device
  * @state: the driver state object
  *
  * Check the state object to see if the requested state is physically possible.
- * Only crtcs and planes have check callbacks, so for any additional (global)
- * checking that a driver needs it can simply wrap that around this function.
- * Drivers without such needs can directly use this as their ->atomic_check()
- * callback.
+ * This does all the plane update related checks using by calling into the
+ * ->atomic_check hooks provided by the driver.
  *
  * RETURNS
  * Zero for success or -errno
  */
-int drm_atomic_helper_check(struct drm_device *dev,
-			    struct drm_atomic_state *state)
+int
+drm_atomic_helper_check_planes(struct drm_device *dev,
+			       struct drm_atomic_state *state)
 {
 	int nplanes = dev->mode_config.num_total_plane;
 	int ncrtcs = dev->mode_config.num_crtc;
@@ -445,7 +497,7 @@
 
 		ret = funcs->atomic_check(plane, plane_state);
 		if (ret) {
-			DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n",
+			DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n",
 				      plane->base.id);
 			return ret;
 		}
@@ -465,16 +517,49 @@
 
 		ret = funcs->atomic_check(crtc, state->crtc_states[i]);
 		if (ret) {
-			DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n",
+			DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n",
 				      crtc->base.id);
 			return ret;
 		}
 	}
 
+	return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_check_planes);
+
+/**
+ * drm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is physically possible.
+ * Only crtcs and planes have check callbacks, so for any additional (global)
+ * checking that a driver needs it can simply wrap that around this function.
+ * Drivers without such needs can directly use this as their ->atomic_check()
+ * callback.
+ *
+ * This just wraps the two parts of the state checking for planes and modeset
+ * state in the default order: First it calls drm_atomic_helper_check_modeset()
+ * and then drm_atomic_helper_check_planes(). The assumption is that the
+ * ->atomic_check functions depend upon an updated adjusted_mode.clock to
+ * e.g. properly compute watermarks.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_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_helper_check_planes(dev, state);
+	if (ret)
+		return ret;
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
@@ -490,6 +575,7 @@
 		struct drm_connector *connector;
 		struct drm_encoder_helper_funcs *funcs;
 		struct drm_encoder *encoder;
+		struct drm_crtc_state *old_crtc_state;
 
 		old_conn_state = old_state->connector_states[i];
 		connector = old_state->connectors[i];
@@ -499,6 +585,11 @@
 		if (!old_conn_state || !old_conn_state->crtc)
 			continue;
 
+		old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
+
+		if (!old_crtc_state->active)
+			continue;
+
 		encoder = old_conn_state->best_encoder;
 
 		/* We shouldn't get this far if we didn't previously have
@@ -509,6 +600,9 @@
 
 		funcs = encoder->helper_private;
 
+		DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n",
+			      encoder->base.id, encoder->name);
+
 		/*
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call call disable hooks twice.
@@ -517,7 +611,7 @@
 			encoder->bridge->funcs->disable(encoder->bridge);
 
 		/* Right function depends upon target state. */
-		if (connector->state->crtc)
+		if (connector->state->crtc && funcs->prepare)
 			funcs->prepare(encoder);
 		else if (funcs->disable)
 			funcs->disable(encoder);
@@ -531,17 +625,26 @@
 	for (i = 0; i < ncrtcs; i++) {
 		struct drm_crtc_helper_funcs *funcs;
 		struct drm_crtc *crtc;
+		struct drm_crtc_state *old_crtc_state;
 
 		crtc = old_state->crtcs[i];
+		old_crtc_state = old_state->crtc_states[i];
 
 		/* Shut down everything that needs a full modeset. */
-		if (!crtc || !crtc->state->mode_changed)
+		if (!crtc || !needs_modeset(crtc->state))
+			continue;
+
+		if (!old_crtc_state->active)
 			continue;
 
 		funcs = crtc->helper_private;
 
+		DRM_DEBUG_KMS("disabling [CRTC:%d]\n",
+			      crtc->base.id);
+
+
 		/* Right function depends upon target state. */
-		if (crtc->state->enable)
+		if (crtc->state->enable && funcs->prepare)
 			funcs->prepare(crtc);
 		else if (funcs->disable)
 			funcs->disable(crtc);
@@ -620,8 +723,12 @@
 
 		funcs = crtc->helper_private;
 
-		if (crtc->state->enable)
+		if (crtc->state->enable) {
+			DRM_DEBUG_KMS("modeset on [CRTC:%d]\n",
+				      crtc->base.id);
+
 			funcs->mode_set_nofb(crtc);
+		}
 	}
 
 	for (i = 0; i < old_state->num_connector; i++) {
@@ -642,6 +749,12 @@
 		mode = &new_crtc_state->mode;
 		adjusted_mode = &new_crtc_state->adjusted_mode;
 
+		if (!new_crtc_state->mode_changed)
+			continue;
+
+		DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n",
+			      encoder->base.id, encoder->name);
+
 		/*
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call call mode_set hooks twice.
@@ -694,13 +807,23 @@
 		crtc = old_state->crtcs[i];
 
 		/* Need to filter out CRTCs where only planes change. */
-		if (!crtc || !crtc->state->mode_changed)
+		if (!crtc || !needs_modeset(crtc->state))
+			continue;
+
+		if (!crtc->state->active)
 			continue;
 
 		funcs = crtc->helper_private;
 
-		if (crtc->state->enable)
-			funcs->commit(crtc);
+		if (crtc->state->enable) {
+			DRM_DEBUG_KMS("enabling [CRTC:%d]\n",
+				      crtc->base.id);
+
+			if (funcs->enable)
+				funcs->enable(crtc);
+			else
+				funcs->commit(crtc);
+		}
 	}
 
 	for (i = 0; i < old_state->num_connector; i++) {
@@ -713,9 +836,15 @@
 		if (!connector || !connector->state->best_encoder)
 			continue;
 
+		if (!connector->state->crtc->state->active)
+			continue;
+
 		encoder = connector->state->best_encoder;
 		funcs = encoder->helper_private;
 
+		DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n",
+			      encoder->base.id, encoder->name);
+
 		/*
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call call enable hooks twice.
@@ -723,7 +852,10 @@
 		if (encoder->bridge)
 			encoder->bridge->funcs->pre_enable(encoder->bridge);
 
-		funcs->commit(encoder);
+		if (funcs->enable)
+			funcs->enable(encoder);
+		else
+			funcs->commit(encoder);
 
 		if (encoder->bridge)
 			encoder->bridge->funcs->enable(encoder->bridge);
@@ -813,6 +945,11 @@
 		if (!crtc->state->enable)
 			continue;
 
+		/* Legacy cursor ioctls are completely unsynced, and userspace
+		 * relies on that (by doing tons of cursor updates). */
+		if (old_state->legacy_cursor_update)
+			continue;
+
 		if (!framebuffer_changed(dev, old_state, crtc))
 			continue;
 
@@ -1053,12 +1190,19 @@
 
 		funcs = plane->helper_private;
 
-		if (!funcs || !funcs->atomic_update)
+		if (!funcs)
 			continue;
 
 		old_plane_state = old_state->plane_states[i];
 
-		funcs->atomic_update(plane, old_plane_state);
+		/*
+		 * Special-case disabling the plane if drivers support it.
+		 */
+		if (drm_atomic_plane_disabling(plane, old_plane_state) &&
+		    funcs->atomic_disable)
+			funcs->atomic_disable(plane, old_plane_state);
+		else
+			funcs->atomic_update(plane, old_plane_state);
 	}
 
 	for (i = 0; i < ncrtcs; i++) {
@@ -1222,7 +1366,7 @@
 		goto fail;
 	}
 
-	ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
 	if (ret != 0)
 		goto fail;
 	drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1239,6 +1383,9 @@
 	if (ret != 0)
 		goto fail;
 
+	if (plane == crtc->cursor)
+		state->legacy_cursor_update = true;
+
 	/* Driver takes ownership of state on successful commit. */
 	return 0;
 fail:
@@ -1301,7 +1448,7 @@
 		goto fail;
 	}
 
-	ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
+	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
 	if (ret != 0)
 		goto fail;
 	drm_atomic_set_fb_for_plane(plane_state, NULL);
@@ -1314,6 +1461,9 @@
 	plane_state->src_h = 0;
 	plane_state->src_w = 0;
 
+	if (plane == plane->crtc->cursor)
+		state->legacy_cursor_update = true;
+
 	ret = drm_atomic_commit(state);
 	if (ret != 0)
 		goto fail;
@@ -1463,8 +1613,9 @@
 		WARN_ON(set->num_connectors);
 
 		crtc_state->enable = false;
+		crtc_state->active = false;
 
-		ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL);
+		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
 		if (ret != 0)
 			goto fail;
 
@@ -1477,9 +1628,10 @@
 	WARN_ON(!set->num_connectors);
 
 	crtc_state->enable = true;
+	crtc_state->active = true;
 	drm_mode_copy(&crtc_state->mode, set->mode);
 
-	ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
+	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
 	if (ret != 0)
 		goto fail;
 	drm_atomic_set_fb_for_plane(primary_state, set->fb);
@@ -1558,8 +1710,8 @@
 		goto fail;
 	}
 
-	ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
-					       property, val);
+	ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+			property, val);
 	if (ret)
 		goto fail;
 
@@ -1617,8 +1769,8 @@
 		goto fail;
 	}
 
-	ret = plane->funcs->atomic_set_property(plane, plane_state,
-					       property, val);
+	ret = drm_atomic_plane_set_property(plane, plane_state,
+			property, val);
 	if (ret)
 		goto fail;
 
@@ -1676,8 +1828,8 @@
 		goto fail;
 	}
 
-	ret = connector->funcs->atomic_set_property(connector, connector_state,
-					       property, val);
+	ret = drm_atomic_connector_set_property(connector, connector_state,
+			property, val);
 	if (ret)
 		goto fail;
 
@@ -1751,7 +1903,7 @@
 		goto fail;
 	}
 
-	ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
+	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
 	if (ret != 0)
 		goto fail;
 	drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1789,6 +1941,83 @@
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
 
 /**
+ * drm_atomic_helper_connector_dpms() - connector dpms helper implementation
+ * @connector: affected connector
+ * @mode: DPMS mode
+ *
+ * This is the main helper function provided by the atomic helper framework for
+ * implementing the legacy DPMS connector interface. It computes the new desired
+ * ->active state for the corresponding CRTC (if the connector is enabled) and
+ *  updates it.
+ */
+void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+				      int mode)
+{
+	struct drm_mode_config *config = &connector->dev->mode_config;
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
+	struct drm_connector *tmp_connector;
+	int ret;
+	bool active = false;
+
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
+	connector->dpms = mode;
+	crtc = connector->state->crtc;
+
+	if (!crtc)
+		return;
+
+	/* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
+	state = drm_atomic_state_alloc(connector->dev);
+	if (!state)
+		return;
+
+	state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state))
+		return;
+
+	WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
+	list_for_each_entry(tmp_connector, &config->connector_list, head) {
+		if (connector->state->crtc != crtc)
+			continue;
+
+		if (connector->dpms == DRM_MODE_DPMS_ON) {
+			active = true;
+			break;
+		}
+	}
+	crtc_state->active = active;
+
+	ret = drm_atomic_commit(state);
+	if (ret != 0)
+		goto fail;
+
+	/* Driver takes ownership of state on successful async commit. */
+	return;
+fail:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_free(state);
+
+	WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
+
+	return;
+backoff:
+	drm_atomic_state_clear(state);
+	drm_atomic_legacy_backoff(state);
+
+	goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
+
+/**
  * DOC: atomic state reset and initialization
  *
  * Both the drm core and the atomic helpers assume that there is always the full
@@ -1814,6 +2043,9 @@
 {
 	kfree(crtc->state);
 	crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+
+	if (crtc->state)
+		crtc->state->crtc = crtc;
 }
 EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
 
@@ -1836,6 +2068,7 @@
 
 	if (state) {
 		state->mode_changed = false;
+		state->active_changed = false;
 		state->planes_changed = false;
 		state->event = NULL;
 	}
@@ -1873,6 +2106,9 @@
 
 	kfree(plane->state);
 	plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+
+	if (plane->state)
+		plane->state->plane = plane;
 }
 EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
 
@@ -1930,6 +2166,9 @@
 {
 	kfree(connector->state);
 	connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+
+	if (connector->state)
+		connector->state->connector = connector;
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
new file mode 100644
index 0000000..d1187e5
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * 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, sub license,
+ * 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 NON-INFRINGEMENT. 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/err.h>
+#include <linux/module.h>
+
+#include <drm/drm_crtc.h>
+
+#include "drm/drmP.h"
+
+static DEFINE_MUTEX(bridge_lock);
+static LIST_HEAD(bridge_list);
+
+int drm_bridge_add(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_add_tail(&bridge->list, &bridge_list);
+	mutex_unlock(&bridge_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_add);
+
+void drm_bridge_remove(struct drm_bridge *bridge)
+{
+	mutex_lock(&bridge_lock);
+	list_del_init(&bridge->list);
+	mutex_unlock(&bridge_lock);
+}
+EXPORT_SYMBOL(drm_bridge_remove);
+
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+{
+	if (!dev || !bridge)
+		return -EINVAL;
+
+	if (bridge->dev)
+		return -EBUSY;
+
+	bridge->dev = dev;
+
+	if (bridge->funcs->attach)
+		return bridge->funcs->attach(bridge);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_bridge_attach);
+
+#ifdef CONFIG_OF
+struct drm_bridge *of_drm_find_bridge(struct device_node *np)
+{
+	struct drm_bridge *bridge;
+
+	mutex_lock(&bridge_lock);
+
+	list_for_each_entry(bridge, &bridge_list, list) {
+		if (bridge->of_node == np) {
+			mutex_unlock(&bridge_lock);
+			return bridge;
+		}
+	}
+
+	mutex_unlock(&bridge_lock);
+	return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_bridge);
+#endif
+
+MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
+MODULE_DESCRIPTION("DRM bridge infrastructure");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index a6b6906..9a62d7a 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -32,6 +32,7 @@
 #include <drm/drmP.h>
 
 #if defined(CONFIG_X86)
+#include <asm/smp.h>
 
 /*
  * clflushopt is an unordered instruction which needs fencing with mfence or
@@ -64,12 +65,6 @@
 		drm_clflush_page(*pages++);
 	mb();
 }
-
-static void
-drm_clflush_ipi_handler(void *null)
-{
-	wbinvd();
-}
 #endif
 
 void
@@ -82,7 +77,7 @@
 		return;
 	}
 
-	if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+	if (wbinvd_on_all_cpus())
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
 
 #elif defined(__powerpc__)
@@ -121,7 +116,7 @@
 		return;
 	}
 
-	if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+	if (wbinvd_on_all_cpus())
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
 #else
 	printk(KERN_ERR "Architecture has no drm_cache.c support\n");
@@ -144,7 +139,7 @@
 		return;
 	}
 
-	if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+	if (wbinvd_on_all_cpus())
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
 #else
 	printk(KERN_ERR "Architecture has no drm_cache.c support\n");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5213da4..6b00173 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -38,6 +38,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
+#include <drm/drm_atomic.h>
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
@@ -61,8 +62,8 @@
 /*
  * Global properties
  */
-static const struct drm_prop_enum_list drm_dpms_enum_list[] =
-{	{ DRM_MODE_DPMS_ON, "On" },
+static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
+	{ DRM_MODE_DPMS_ON, "On" },
 	{ DRM_MODE_DPMS_STANDBY, "Standby" },
 	{ DRM_MODE_DPMS_SUSPEND, "Suspend" },
 	{ DRM_MODE_DPMS_OFF, "Off" }
@@ -70,8 +71,7 @@
 
 DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
 
-static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
 	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
 	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
 	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
@@ -80,8 +80,7 @@
 /*
  * Optional properties
  */
-static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
 	{ DRM_MODE_SCALE_NONE, "None" },
 	{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
 	{ DRM_MODE_SCALE_CENTER, "Center" },
@@ -97,8 +96,7 @@
 /*
  * Non-global properties, but "required" for certain connectors.
  */
-static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
@@ -106,8 +104,7 @@
 
 DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
 
-static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
 	{ DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
@@ -116,8 +113,7 @@
 DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
 		 drm_dvi_i_subconnector_enum_list)
 
-static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
@@ -127,8 +123,7 @@
 
 DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
 
-static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
 	{ DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
@@ -154,8 +149,8 @@
 /*
  * Connector and encoder types.
  */
-static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
-{	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
+	{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
 	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
 	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
 	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
@@ -174,8 +169,8 @@
 	{ DRM_MODE_CONNECTOR_DSI, "DSI" },
 };
 
-static const struct drm_prop_enum_list drm_encoder_enum_list[] =
-{	{ DRM_MODE_ENCODER_NONE, "None" },
+static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
+	{ DRM_MODE_ENCODER_NONE, "None" },
 	{ DRM_MODE_ENCODER_DAC, "DAC" },
 	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
 	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
@@ -185,8 +180,7 @@
 	{ DRM_MODE_ENCODER_DPMST, "DP MST" },
 };
 
-static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
 	{ SubPixelUnknown, "Unknown" },
 	{ SubPixelHorizontalRGB, "Horizontal RGB" },
 	{ SubPixelHorizontalBGR, "Horizontal BGR" },
@@ -697,6 +691,10 @@
 	if (cursor)
 		cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
+	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+		drm_object_attach_property(&crtc->base, config->prop_active, 0);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_crtc_init_with_planes);
@@ -768,6 +766,40 @@
 }
 
 /**
+ * drm_display_info_set_bus_formats - set the supported bus formats
+ * @info: display info to store bus formats in
+ * @formats: array containing the supported bus formats
+ * @num_formats: the number of entries in the fmts array
+ *
+ * Store the supported bus formats in display info structure.
+ * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
+ * a full list of available formats.
+ */
+int drm_display_info_set_bus_formats(struct drm_display_info *info,
+				     const u32 *formats,
+				     unsigned int num_formats)
+{
+	u32 *fmts = NULL;
+
+	if (!formats && num_formats)
+		return -EINVAL;
+
+	if (formats && num_formats) {
+		fmts = kmemdup(formats, sizeof(*formats) * num_formats,
+			       GFP_KERNEL);
+		if (!fmts)
+			return -ENOMEM;
+	}
+
+	kfree(info->bus_formats);
+	info->bus_formats = fmts;
+	info->num_bus_formats = num_formats;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_display_info_set_bus_formats);
+
+/**
  * drm_connector_get_cmdline_mode - reads the user's cmdline mode
  * @connector: connector to quwery
  *
@@ -837,6 +869,7 @@
 		       const struct drm_connector_funcs *funcs,
 		       int connector_type)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 	struct ida *connector_ida =
 		&drm_connector_enum_list[connector_type].ida;
@@ -875,16 +908,20 @@
 
 	/* We should add connectors at the end to avoid upsetting the connector
 	 * index too much. */
-	list_add_tail(&connector->head, &dev->mode_config.connector_list);
-	dev->mode_config.num_connector++;
+	list_add_tail(&connector->head, &config->connector_list);
+	config->num_connector++;
 
 	if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
 		drm_object_attach_property(&connector->base,
-					      dev->mode_config.edid_property,
+					      config->edid_property,
 					      0);
 
 	drm_object_attach_property(&connector->base,
-				      dev->mode_config.dpms_property, 0);
+				      config->dpms_property, 0);
+
+	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+		drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
+	}
 
 	connector->debugfs_entry = NULL;
 
@@ -924,6 +961,7 @@
 	ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
 		   connector->connector_type_id);
 
+	kfree(connector->display_info.bus_formats);
 	drm_mode_object_put(dev, &connector->base);
 	kfree(connector->name);
 	connector->name = NULL;
@@ -1028,61 +1066,6 @@
 EXPORT_SYMBOL(drm_connector_unplug_all);
 
 /**
- * drm_bridge_init - initialize a drm transcoder/bridge
- * @dev: drm device
- * @bridge: transcoder/bridge to set up
- * @funcs: bridge function table
- *
- * Initialises a preallocated bridge. Bridges should be
- * subclassed as part of driver connector objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-		const struct drm_bridge_funcs *funcs)
-{
-	int ret;
-
-	drm_modeset_lock_all(dev);
-
-	ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
-	if (ret)
-		goto out;
-
-	bridge->dev = dev;
-	bridge->funcs = funcs;
-
-	list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
-	dev->mode_config.num_bridge++;
-
- out:
-	drm_modeset_unlock_all(dev);
-	return ret;
-}
-EXPORT_SYMBOL(drm_bridge_init);
-
-/**
- * drm_bridge_cleanup - cleans up an initialised bridge
- * @bridge: bridge to cleanup
- *
- * Cleans up the bridge but doesn't free the object.
- */
-void drm_bridge_cleanup(struct drm_bridge *bridge)
-{
-	struct drm_device *dev = bridge->dev;
-
-	drm_modeset_lock_all(dev);
-	drm_mode_object_put(dev, &bridge->base);
-	list_del(&bridge->head);
-	dev->mode_config.num_bridge--;
-	drm_modeset_unlock_all(dev);
-
-	memset(bridge, 0, sizeof(*bridge));
-}
-EXPORT_SYMBOL(drm_bridge_cleanup);
-
-/**
  * drm_encoder_init - Init a preallocated encoder
  * @dev: drm device
  * @encoder: the encoder to init
@@ -1142,6 +1125,7 @@
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
+
 	drm_modeset_lock_all(dev);
 	drm_mode_object_put(dev, &encoder->base);
 	kfree(encoder->name);
@@ -1174,6 +1158,7 @@
 			     const uint32_t *formats, uint32_t format_count,
 			     enum drm_plane_type type)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -1185,8 +1170,8 @@
 	plane->base.properties = &plane->properties;
 	plane->dev = dev;
 	plane->funcs = funcs;
-	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
-				      GFP_KERNEL);
+	plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
+					    GFP_KERNEL);
 	if (!plane->format_types) {
 		DRM_DEBUG_KMS("out of memory when allocating plane\n");
 		drm_mode_object_put(dev, &plane->base);
@@ -1198,15 +1183,28 @@
 	plane->possible_crtcs = possible_crtcs;
 	plane->type = type;
 
-	list_add_tail(&plane->head, &dev->mode_config.plane_list);
-	dev->mode_config.num_total_plane++;
+	list_add_tail(&plane->head, &config->plane_list);
+	config->num_total_plane++;
 	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-		dev->mode_config.num_overlay_plane++;
+		config->num_overlay_plane++;
 
 	drm_object_attach_property(&plane->base,
-				   dev->mode_config.plane_type_property,
+				   config->plane_type_property,
 				   plane->type);
 
+	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+		drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+		drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+		drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+		drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+		drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+		drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+		drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+		drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+		drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+		drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_universal_plane_init);
@@ -1328,50 +1326,115 @@
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
-static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+static int drm_mode_create_standard_properties(struct drm_device *dev)
 {
-	struct drm_property *edid;
-	struct drm_property *dpms;
-	struct drm_property *dev_path;
+	struct drm_property *prop;
 
 	/*
 	 * Standard properties (apply to all connectors)
 	 */
-	edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
 				   DRM_MODE_PROP_IMMUTABLE,
 				   "EDID", 0);
-	dev->mode_config.edid_property = edid;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.edid_property = prop;
 
-	dpms = drm_property_create_enum(dev, 0,
+	prop = drm_property_create_enum(dev, 0,
 				   "DPMS", drm_dpms_enum_list,
 				   ARRAY_SIZE(drm_dpms_enum_list));
-	dev->mode_config.dpms_property = dpms;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.dpms_property = prop;
 
-	dev_path = drm_property_create(dev,
-				       DRM_MODE_PROP_BLOB |
-				       DRM_MODE_PROP_IMMUTABLE,
-				       "PATH", 0);
-	dev->mode_config.path_property = dev_path;
+	prop = drm_property_create(dev,
+				   DRM_MODE_PROP_BLOB |
+				   DRM_MODE_PROP_IMMUTABLE,
+				   "PATH", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.path_property = prop;
 
-	dev->mode_config.tile_property = drm_property_create(dev,
-							     DRM_MODE_PROP_BLOB |
-							     DRM_MODE_PROP_IMMUTABLE,
-							     "TILE", 0);
+	prop = drm_property_create(dev,
+				   DRM_MODE_PROP_BLOB |
+				   DRM_MODE_PROP_IMMUTABLE,
+				   "TILE", 0);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.tile_property = prop;
 
-	return 0;
-}
-
-static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
-{
-	struct drm_property *type;
-
-	/*
-	 * Standard properties (apply to all planes)
-	 */
-	type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+	prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
 					"type", drm_plane_type_enum_list,
 					ARRAY_SIZE(drm_plane_type_enum_list));
-	dev->mode_config.plane_type_property = type;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.plane_type_property = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"SRC_X", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_x = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"SRC_Y", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_y = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"SRC_W", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_w = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"SRC_H", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_h = prop;
+
+	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+			"CRTC_X", INT_MIN, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_x = prop;
+
+	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+			"CRTC_Y", INT_MIN, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_y = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"CRTC_W", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_w = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+			"CRTC_H", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_h = prop;
+
+	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+			"FB_ID", DRM_MODE_OBJECT_FB);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_fb_id = prop;
+
+	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_id = prop;
+
+	prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+			"ACTIVE");
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_active = prop;
 
 	return 0;
 }
@@ -1597,16 +1660,14 @@
 	total_objects += dev->mode_config.num_crtc;
 	total_objects += dev->mode_config.num_connector;
 	total_objects += dev->mode_config.num_encoder;
-	total_objects += dev->mode_config.num_bridge;
 
-	group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
+	group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
 	if (!group->id_list)
 		return -ENOMEM;
 
 	group->num_crtcs = 0;
 	group->num_connectors = 0;
 	group->num_encoders = 0;
-	group->num_bridges = 0;
 	return 0;
 }
 
@@ -1626,10 +1687,10 @@
 	struct drm_crtc *crtc;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	struct drm_bridge *bridge;
 	int ret;
 
-	if ((ret = drm_mode_group_init(dev, group)))
+	ret = drm_mode_group_init(dev, group);
+	if (ret)
 		return ret;
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
@@ -1643,11 +1704,6 @@
 		group->id_list[group->num_crtcs + group->num_encoders +
 			       group->num_connectors++] = connector->base.id;
 
-	list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
-		group->id_list[group->num_crtcs + group->num_encoders +
-			       group->num_connectors + group->num_bridges++] =
-					bridge->base.id;
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
@@ -1996,6 +2052,44 @@
 	return connector->encoder;
 }
 
+/* helper for getconnector and getproperties ioctls */
+static int get_properties(struct drm_mode_object *obj, bool atomic,
+		uint32_t __user *prop_ptr, uint64_t __user *prop_values,
+		uint32_t *arg_count_props)
+{
+	int props_count;
+	int i, ret, copied;
+
+	props_count = obj->properties->count;
+	if (!atomic)
+		props_count -= obj->properties->atomic_count;
+
+	if ((*arg_count_props >= props_count) && props_count) {
+		for (i = 0, copied = 0; copied < props_count; i++) {
+			struct drm_property *prop = obj->properties->properties[i];
+			uint64_t val;
+
+			if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
+				continue;
+
+			ret = drm_object_property_get_value(obj, prop, &val);
+			if (ret)
+				return ret;
+
+			if (put_user(prop->base.id, prop_ptr + copied))
+				return -EFAULT;
+
+			if (put_user(val, prop_values + copied))
+				return -EFAULT;
+
+			copied++;
+		}
+	}
+	*arg_count_props = props_count;
+
+	return 0;
+}
+
 /**
  * drm_mode_getconnector - get connector configuration
  * @dev: drm device for the ioctl
@@ -2017,15 +2111,12 @@
 	struct drm_encoder *encoder;
 	struct drm_display_mode *mode;
 	int mode_count = 0;
-	int props_count = 0;
 	int encoders_count = 0;
 	int ret = 0;
 	int copied = 0;
 	int i;
 	struct drm_mode_modeinfo u_mode;
 	struct drm_mode_modeinfo __user *mode_ptr;
-	uint32_t __user *prop_ptr;
-	uint64_t __user *prop_values;
 	uint32_t __user *encoder_ptr;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -2036,6 +2127,7 @@
 	DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
 
 	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 
 	connector = drm_connector_find(dev, out_resp->connector_id);
 	if (!connector) {
@@ -2043,13 +2135,9 @@
 		goto out;
 	}
 
-	props_count = connector->properties.count;
-
-	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-		if (connector->encoder_ids[i] != 0) {
+	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
+		if (connector->encoder_ids[i] != 0)
 			encoders_count++;
-		}
-	}
 
 	if (out_resp->count_modes == 0) {
 		connector->funcs->fill_modes(connector,
@@ -2069,14 +2157,11 @@
 	out_resp->mm_height = connector->display_info.height_mm;
 	out_resp->subpixel = connector->display_info.subpixel_order;
 	out_resp->connection = connector->status;
-	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-
 	encoder = drm_connector_get_encoder(connector);
 	if (encoder)
 		out_resp->encoder_id = encoder->base.id;
 	else
 		out_resp->encoder_id = 0;
-	drm_modeset_unlock(&dev->mode_config.connection_mutex);
 
 	/*
 	 * This ioctl is called twice, once to determine how much space is
@@ -2100,26 +2185,12 @@
 	}
 	out_resp->count_modes = mode_count;
 
-	if ((out_resp->count_props >= props_count) && props_count) {
-		copied = 0;
-		prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
-		prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
-		for (i = 0; i < connector->properties.count; i++) {
-			if (put_user(connector->properties.ids[i],
-				     prop_ptr + copied)) {
-				ret = -EFAULT;
-				goto out;
-			}
-
-			if (put_user(connector->properties.values[i],
-				     prop_values + copied)) {
-				ret = -EFAULT;
-				goto out;
-			}
-			copied++;
-		}
-	}
-	out_resp->count_props = props_count;
+	ret = get_properties(&connector->base, file_priv->atomic,
+			(uint32_t __user *)(unsigned long)(out_resp->props_ptr),
+			(uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
+			&out_resp->count_props);
+	if (ret)
+		goto out;
 
 	if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
 		copied = 0;
@@ -2138,6 +2209,7 @@
 	out_resp->count_encoders = encoders_count;
 
 out:
+	drm_modeset_unlock(&dev->mode_config.connection_mutex);
 	mutex_unlock(&dev->mode_config.mutex);
 
 	return ret;
@@ -2529,7 +2601,7 @@
  *
  * This is a little helper to wrap internal calls to the ->set_config driver
  * interface. The only thing it adds is correct refcounting dance.
- * 
+ *
  * Returns:
  * Zero on success, negative errno on failure.
  */
@@ -2569,6 +2641,27 @@
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
 /**
+ * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
+ * @mode: mode to query
+ * @hdisplay: hdisplay value to fill in
+ * @vdisplay: vdisplay value to fill in
+ *
+ * The vdisplay value will be doubled if the specified mode is a stereo mode of
+ * the appropriate layout.
+ */
+void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
+			    int *hdisplay, int *vdisplay)
+{
+	struct drm_display_mode adjusted;
+
+	drm_mode_copy(&adjusted, mode);
+	drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
+	*hdisplay = adjusted.crtc_hdisplay;
+	*vdisplay = adjusted.crtc_vdisplay;
+}
+EXPORT_SYMBOL(drm_crtc_get_hv_timing);
+
+/**
  * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
  *     CRTC viewport
  * @crtc: CRTC that framebuffer will be displayed on
@@ -2585,16 +2678,7 @@
 {
 	int hdisplay, vdisplay;
 
-	hdisplay = mode->hdisplay;
-	vdisplay = mode->vdisplay;
-
-	if (drm_mode_is_stereo(mode)) {
-		struct drm_display_mode adjusted = *mode;
-
-		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
-		hdisplay = adjusted.crtc_hdisplay;
-		vdisplay = adjusted.crtc_vdisplay;
-	}
+	drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
 
 	if (crtc->invert_dimensions)
 		swap(hdisplay, vdisplay);
@@ -2690,6 +2774,12 @@
 			goto out;
 		}
 
+		mode->status = drm_mode_validate_basic(mode);
+		if (mode->status != MODE_OK) {
+			ret = -EINVAL;
+			goto out;
+		}
+
 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 
 		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
@@ -2721,9 +2811,9 @@
 			goto out;
 		}
 
-		connector_set = kmalloc(crtc_req->count_connectors *
-					sizeof(struct drm_connector *),
-					GFP_KERNEL);
+		connector_set = kmalloc_array(crtc_req->count_connectors,
+					      sizeof(struct drm_connector *),
+					      GFP_KERNEL);
 		if (!connector_set) {
 			ret = -ENOMEM;
 			goto out;
@@ -2968,6 +3058,7 @@
 			   void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_cursor2 *req = data;
+
 	return drm_mode_cursor_common(dev, req, file_priv);
 }
 
@@ -3415,7 +3506,7 @@
 			ret = -EINVAL;
 			goto out_err1;
 		}
-		clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
+		clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
 		if (!clips) {
 			ret = -ENOMEM;
 			goto out_err1;
@@ -3516,7 +3607,8 @@
 	property->dev = dev;
 
 	if (num_values) {
-		property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+		property->values = kcalloc(num_values, sizeof(uint64_t),
+					   GFP_KERNEL);
 		if (!property->values)
 			goto fail;
 	}
@@ -3665,7 +3757,7 @@
 }
 
 /**
- * drm_property_create_range - create a new ranged property type
+ * drm_property_create_range - create a new unsigned ranged property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3676,8 +3768,8 @@
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
- * Userspace is allowed to set any integer value in the (min, max) range
- * inclusive.
+ * Userspace is allowed to set any unsigned integer value in the (min, max)
+ * range inclusive.
  *
  * Returns:
  * A pointer to the newly created property on success, NULL on failure.
@@ -3691,6 +3783,24 @@
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+/**
+ * drm_property_create_signed_range - create a new signed ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is allowed to set any signed integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
 					 int flags, const char *name,
 					 int64_t min, int64_t max)
@@ -3700,6 +3810,23 @@
 }
 EXPORT_SYMBOL(drm_property_create_signed_range);
 
+/**
+ * drm_property_create_object - create a new object property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @type: object type from DRM_MODE_OBJECT_* defines
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is only allowed to set this to any property value of the given
+ * @type. Only useful for atomic properties, which is enforced.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_object(struct drm_device *dev,
 					 int flags, const char *name, uint32_t type)
 {
@@ -3707,6 +3834,9 @@
 
 	flags |= DRM_MODE_PROP_OBJECT;
 
+	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
+		return NULL;
+
 	property = drm_property_create(dev, flags, name, 1);
 	if (!property)
 		return NULL;
@@ -3718,6 +3848,28 @@
 EXPORT_SYMBOL(drm_property_create_object);
 
 /**
+ * drm_property_create_bool - create a new boolean property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * This is implemented as a ranged property with only {0, 1} as valid values.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+					 const char *name)
+{
+	return drm_property_create_range(dev, flags, name, 0, 1);
+}
+EXPORT_SYMBOL(drm_property_create_bool);
+
+/**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
  * @index: index of the new enumeration
@@ -3822,9 +3974,11 @@
 		return;
 	}
 
-	obj->properties->ids[count] = property->base.id;
+	obj->properties->properties[count] = property;
 	obj->properties->values[count] = init_val;
 	obj->properties->count++;
+	if (property->flags & DRM_MODE_PROP_ATOMIC)
+		obj->properties->atomic_count++;
 }
 EXPORT_SYMBOL(drm_object_attach_property);
 
@@ -3847,7 +4001,7 @@
 	int i;
 
 	for (i = 0; i < obj->properties->count; i++) {
-		if (obj->properties->ids[i] == property->base.id) {
+		if (obj->properties->properties[i] == property) {
 			obj->properties->values[i] = val;
 			return 0;
 		}
@@ -3876,8 +4030,16 @@
 {
 	int i;
 
+	/* read-only properties bypass atomic mechanism and still store
+	 * their value in obj->properties->values[].. mostly to avoid
+	 * having to deal w/ EDID and similar props in atomic paths:
+	 */
+	if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
+			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
+		return drm_atomic_get_property(obj, property, val);
+
 	for (i = 0; i < obj->properties->count; i++) {
-		if (obj->properties->ids[i] == property->base.id) {
+		if (obj->properties->properties[i] == property) {
 			*val = obj->properties->values[i];
 			return 0;
 		}
@@ -4057,7 +4219,7 @@
 
 	if (out_resp->length == blob->length) {
 		blob_ptr = (void __user *)(unsigned long)out_resp->data;
-		if (copy_to_user(blob_ptr, blob->data, blob->length)){
+		if (copy_to_user(blob_ptr, blob->data, blob->length)) {
 			ret = -EFAULT;
 			goto done;
 		}
@@ -4193,25 +4355,38 @@
 }
 EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 
-static bool drm_property_change_is_valid(struct drm_property *property,
-					 uint64_t value)
+/* Some properties could refer to dynamic refcnt'd objects, or things that
+ * need special locking to handle lifetime issues (ie. to ensure the prop
+ * value doesn't become invalid part way through the property update due to
+ * race).  The value returned by reference via 'obj' should be passed back
+ * to drm_property_change_valid_put() after the property is set (and the
+ * object to which the property is attached has a chance to take it's own
+ * reference).
+ */
+bool drm_property_change_valid_get(struct drm_property *property,
+					 uint64_t value, struct drm_mode_object **ref)
 {
+	int i;
+
 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
 		return false;
 
+	*ref = NULL;
+
 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
 		int64_t svalue = U642I64(value);
+
 		if (svalue < U642I64(property->values[0]) ||
 				svalue > U642I64(property->values[1]))
 			return false;
 		return true;
 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-		int i;
 		uint64_t valid_mask = 0;
+
 		for (i = 0; i < property->num_values; i++)
 			valid_mask |= (1ULL << property->values[i]);
 		return !(value & ~valid_mask);
@@ -4219,25 +4394,40 @@
 		/* Only the driver knows */
 		return true;
 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
-		struct drm_mode_object *obj;
 		/* a zero value for an object property translates to null: */
 		if (value == 0)
 			return true;
-		/*
-		 * NOTE: use _object_find() directly to bypass restriction on
-		 * looking up refcnt'd objects (ie. fb's).  For a refcnt'd
-		 * object this could race against object finalization, so it
-		 * simply tells us that the object *was* valid.  Which is good
-		 * enough.
-		 */
-		obj = _object_find(property->dev, value, property->values[0]);
-		return obj != NULL;
-	} else {
-		int i;
-		for (i = 0; i < property->num_values; i++)
-			if (property->values[i] == value)
+
+		/* handle refcnt'd objects specially: */
+		if (property->values[0] == DRM_MODE_OBJECT_FB) {
+			struct drm_framebuffer *fb;
+			fb = drm_framebuffer_lookup(property->dev, value);
+			if (fb) {
+				*ref = &fb->base;
 				return true;
-		return false;
+			} else {
+				return false;
+			}
+		} else {
+			return _object_find(property->dev, value, property->values[0]) != NULL;
+		}
+	}
+
+	for (i = 0; i < property->num_values; i++)
+		if (property->values[i] == value)
+			return true;
+	return false;
+}
+
+void drm_property_change_valid_put(struct drm_property *property,
+		struct drm_mode_object *ref)
+{
+	if (!ref)
+		return;
+
+	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+		if (property->values[0] == DRM_MODE_OBJECT_FB)
+			drm_framebuffer_unreference(obj_to_fb(ref));
 	}
 }
 
@@ -4356,11 +4546,6 @@
 	struct drm_mode_obj_get_properties *arg = data;
 	struct drm_mode_object *obj;
 	int ret = 0;
-	int i;
-	int copied = 0;
-	int props_count = 0;
-	uint32_t __user *props_ptr;
-	uint64_t __user *prop_values_ptr;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -4377,30 +4562,11 @@
 		goto out;
 	}
 
-	props_count = obj->properties->count;
+	ret = get_properties(obj, file_priv->atomic,
+			(uint32_t __user *)(unsigned long)(arg->props_ptr),
+			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
+			&arg->count_props);
 
-	/* This ioctl is called twice, once to determine how much space is
-	 * needed, and the 2nd time to fill it. */
-	if ((arg->count_props >= props_count) && props_count) {
-		copied = 0;
-		props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
-		prop_values_ptr = (uint64_t __user *)(unsigned long)
-				  (arg->prop_values_ptr);
-		for (i = 0; i < props_count; i++) {
-			if (put_user(obj->properties->ids[i],
-				     props_ptr + copied)) {
-				ret = -EFAULT;
-				goto out;
-			}
-			if (put_user(obj->properties->values[i],
-				     prop_values_ptr + copied)) {
-				ret = -EFAULT;
-				goto out;
-			}
-			copied++;
-		}
-	}
-	arg->count_props = props_count;
 out:
 	drm_modeset_unlock_all(dev);
 	return ret;
@@ -4429,8 +4595,8 @@
 	struct drm_mode_object *arg_obj;
 	struct drm_mode_object *prop_obj;
 	struct drm_property *property;
-	int ret = -EINVAL;
-	int i;
+	int i, ret = -EINVAL;
+	struct drm_mode_object *ref;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
@@ -4446,7 +4612,7 @@
 		goto out;
 
 	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == arg->prop_id)
+		if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
 			break;
 
 	if (i == arg_obj->properties->count)
@@ -4460,7 +4626,7 @@
 	}
 	property = obj_to_property(prop_obj);
 
-	if (!drm_property_change_is_valid(property, arg->value))
+	if (!drm_property_change_valid_get(property, arg->value, &ref))
 		goto out;
 
 	switch (arg_obj->type) {
@@ -4477,6 +4643,8 @@
 		break;
 	}
 
+	drm_property_change_valid_put(property, ref);
+
 out:
 	drm_modeset_unlock_all(dev);
 	return ret;
@@ -4526,7 +4694,8 @@
 {
 	crtc->gamma_size = gamma_size;
 
-	crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
+	crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
+				    GFP_KERNEL);
 	if (!crtc->gamma_store) {
 		crtc->gamma_size = 0;
 		return -ENOMEM;
@@ -4741,23 +4910,23 @@
 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 		ret = -ENOMEM;
 		spin_lock_irqsave(&dev->event_lock, flags);
-		if (file_priv->event_space < sizeof e->event) {
+		if (file_priv->event_space < sizeof(e->event)) {
 			spin_unlock_irqrestore(&dev->event_lock, flags);
 			goto out;
 		}
-		file_priv->event_space -= sizeof e->event;
+		file_priv->event_space -= sizeof(e->event);
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 
-		e = kzalloc(sizeof *e, GFP_KERNEL);
+		e = kzalloc(sizeof(*e), GFP_KERNEL);
 		if (e == NULL) {
 			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
+			file_priv->event_space += sizeof(e->event);
 			spin_unlock_irqrestore(&dev->event_lock, flags);
 			goto out;
 		}
 
 		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
-		e->event.base.length = sizeof e->event;
+		e->event.base.length = sizeof(e->event);
 		e->event.user_data = page_flip->user_data;
 		e->base.event = &e->event.base;
 		e->base.file_priv = file_priv;
@@ -4770,7 +4939,7 @@
 	if (ret) {
 		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
+			file_priv->event_space += sizeof(e->event);
 			spin_unlock_irqrestore(&dev->event_lock, flags);
 			kfree(e);
 		}
@@ -5211,7 +5380,6 @@
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
-	INIT_LIST_HEAD(&dev->mode_config.bridge_list);
 	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_list);
 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
@@ -5220,8 +5388,7 @@
 	idr_init(&dev->mode_config.tile_idr);
 
 	drm_modeset_lock_all(dev);
-	drm_mode_create_standard_connector_properties(dev);
-	drm_mode_create_standard_plane_properties(dev);
+	drm_mode_create_standard_properties(dev);
 	drm_modeset_unlock_all(dev);
 
 	/* Just to be sure */
@@ -5252,7 +5419,6 @@
 	struct drm_connector *connector, *ot;
 	struct drm_crtc *crtc, *ct;
 	struct drm_encoder *encoder, *enct;
-	struct drm_bridge *bridge, *brt;
 	struct drm_framebuffer *fb, *fbt;
 	struct drm_property *property, *pt;
 	struct drm_property_blob *blob, *bt;
@@ -5263,11 +5429,6 @@
 		encoder->funcs->destroy(encoder);
 	}
 
-	list_for_each_entry_safe(bridge, brt,
-				 &dev->mode_config.bridge_list, head) {
-		bridge->funcs->destroy(bridge);
-	}
-
 	list_for_each_entry_safe(connector, ot,
 				 &dev->mode_config.connector_list, head) {
 		connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d552708..b1979e7 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -946,6 +946,7 @@
 		crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
 	if (!crtc_state)
 		return -ENOMEM;
+	crtc_state->crtc = crtc;
 
 	crtc_state->enable = true;
 	crtc_state->planes_changed = true;
@@ -1005,6 +1006,7 @@
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
+	plane_state->plane = plane;
 
 	plane_state->crtc = crtc;
 	drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index a2945ee..247dc8b 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -36,3 +36,9 @@
 void drm_mode_object_put(struct drm_device *dev,
 			 struct drm_mode_object *object);
 
+/* drm_atomic.c */
+int drm_atomic_get_property(struct drm_mode_object *obj,
+			   struct drm_property *property, uint64_t *val);
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv);
+
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 79968e3..f128387 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -354,6 +354,37 @@
 EXPORT_SYMBOL(drm_dp_link_power_up);
 
 /**
+ * drm_dp_link_power_down() - power down a DisplayPort link
+ * @aux: DisplayPort AUX channel
+ * @link: pointer to a structure containing the link configuration
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link)
+{
+	u8 value;
+	int err;
+
+	/* DP_SET_POWER register is only available on DPCD v1.1 and later */
+	if (link->revision < 0x11)
+		return 0;
+
+	err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
+	if (err < 0)
+		return err;
+
+	value &= ~DP_SET_POWER_MASK;
+	value |= DP_SET_POWER_D3;
+
+	err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_link_power_down);
+
+/**
  * drm_dp_link_configure() - configure a DisplayPort link
  * @aux: DisplayPort AUX channel
  * @link: pointer to a structure containing the link configuration
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 4f41377..d512134 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -40,15 +40,19 @@
 unsigned int drm_debug = 0;	/* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
+bool drm_atomic = 0;
+
 MODULE_AUTHOR(CORE_AUTHOR);
 MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
 MODULE_PARM_DESC(debug, "Enable debug output");
+MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API");
 MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
 MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
 MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
 
 module_param_named(debug, drm_debug, int, 0600);
+module_param_named_unsafe(atomic, drm_atomic, bool, 0600);
 
 static DEFINE_SPINLOCK(drm_minor_lock);
 static struct idr drm_minors_idr;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index dc386eb..1e6a0c7 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1722,7 +1722,7 @@
  * RETURNS:
  * Zero if everything went ok, nonzero otherwise.
  */
-bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
+int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 {
 	struct drm_device *dev = fb_helper->dev;
 	int count = 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 0b9514b..076dd60 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -478,64 +478,59 @@
 }
 EXPORT_SYMBOL(drm_release);
 
-static bool
-drm_dequeue_event(struct drm_file *file_priv,
-		  size_t total, size_t max, struct drm_pending_event **out)
-{
-	struct drm_device *dev = file_priv->minor->dev;
-	struct drm_pending_event *e;
-	unsigned long flags;
-	bool ret = false;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-
-	*out = NULL;
-	if (list_empty(&file_priv->event_list))
-		goto out;
-	e = list_first_entry(&file_priv->event_list,
-			     struct drm_pending_event, link);
-	if (e->event->length + total > max)
-		goto out;
-
-	file_priv->event_space += e->event->length;
-	list_del(&e->link);
-	*out = e;
-	ret = true;
-
-out:
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-	return ret;
-}
-
 ssize_t drm_read(struct file *filp, char __user *buffer,
 		 size_t count, loff_t *offset)
 {
 	struct drm_file *file_priv = filp->private_data;
-	struct drm_pending_event *e;
-	size_t total;
-	ssize_t ret;
+	struct drm_device *dev = file_priv->minor->dev;
+	ssize_t ret = 0;
 
-	if ((filp->f_flags & O_NONBLOCK) == 0) {
-		ret = wait_event_interruptible(file_priv->event_wait,
-					       !list_empty(&file_priv->event_list));
-		if (ret < 0)
-			return ret;
-	}
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
 
-	total = 0;
-	while (drm_dequeue_event(file_priv, total, count, &e)) {
-		if (copy_to_user(buffer + total,
-				 e->event, e->event->length)) {
-			total = -EFAULT;
+	spin_lock_irq(&dev->event_lock);
+	for (;;) {
+		if (list_empty(&file_priv->event_list)) {
+			if (ret)
+				break;
+
+			if (filp->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				break;
+			}
+
+			spin_unlock_irq(&dev->event_lock);
+			ret = wait_event_interruptible(file_priv->event_wait,
+						       !list_empty(&file_priv->event_list));
+			spin_lock_irq(&dev->event_lock);
+			if (ret < 0)
+				break;
+
+			ret = 0;
+		} else {
+			struct drm_pending_event *e;
+
+			e = list_first_entry(&file_priv->event_list,
+					     struct drm_pending_event, link);
+			if (e->event->length + ret > count)
+				break;
+
+			if (__copy_to_user_inatomic(buffer + ret,
+						    e->event, e->event->length)) {
+				if (ret == 0)
+					ret = -EFAULT;
+				break;
+			}
+
+			file_priv->event_space += e->event->length;
+			ret += e->event->length;
+			list_del(&e->link);
 			e->destroy(e);
-			break;
 		}
-
-		total += e->event->length;
-		e->destroy(e);
 	}
+	spin_unlock_irq(&dev->event_lock);
 
-	return total ?: -EAGAIN;
+	return ret;
 }
 EXPORT_SYMBOL(drm_read);
 
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 51efebd..f1b32f9 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -153,30 +153,6 @@
 }
 
 /**
- * Called when "/proc/dri/.../vblank" is read.
- */
-int drm_vblank_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-	int crtc;
-
-	mutex_lock(&dev->struct_mutex);
-	for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
-		seq_printf(m, "CRTC %d enable:     %d\n",
-			   crtc, atomic_read(&dev->vblank[crtc].refcount));
-		seq_printf(m, "CRTC %d counter:    %d\n",
-			   crtc, drm_vblank_count(dev, crtc));
-		seq_printf(m, "CRTC %d last wait:  %d\n",
-			   crtc, dev->vblank[crtc].last_wait);
-		seq_printf(m, "CRTC %d in modeset: %d\n",
-			   crtc, dev->vblank[crtc].inmodeset);
-	}
-	mutex_unlock(&dev->struct_mutex);
-	return 0;
-}
-
-/**
  * Called when "/proc/dri/.../clients" is read.
  *
  */
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 7cc0a35..12a61d70 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -55,7 +55,6 @@
 int drm_name_info(struct seq_file *m, void *data);
 int drm_vm_info(struct seq_file *m, void *data);
 int drm_bufs_info(struct seq_file *m, void *data);
-int drm_vblank_info(struct seq_file *m, void *data);
 int drm_clients_info(struct seq_file *m, void* data);
 int drm_gem_name_info(struct seq_file *m, void *data);
 
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 00587a1..3785d66 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -32,6 +32,7 @@
 #include <drm/drm_core.h>
 #include "drm_legacy.h"
 #include "drm_internal.h"
+#include "drm_crtc_internal.h"
 
 #include <linux/pci.h>
 #include <linux/export.h>
@@ -345,6 +346,17 @@
 			return -EINVAL;
 		file_priv->universal_planes = req->value;
 		break;
+	case DRM_CLIENT_CAP_ATOMIC:
+		/* for now, hide behind experimental drm.atomic moduleparam */
+		if (!drm_atomic)
+			return -EINVAL;
+		if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+			return -EINVAL;
+		if (req->value > 1)
+			return -EINVAL;
+		file_priv->atomic = req->value;
+		file_priv->universal_planes = req->value;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -620,6 +632,7 @@
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 4d79dad..10574a0 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -185,8 +185,15 @@
 		return;
 	}
 
-	dev->driver->disable_vblank(dev, crtc);
-	vblank->enabled = false;
+	/*
+	 * Only disable vblank interrupts if they're enabled. This avoids
+	 * calling the ->disable_vblank() operation in atomic context with the
+	 * hardware potentially runtime suspended.
+	 */
+	if (vblank->enabled) {
+		dev->driver->disable_vblank(dev, crtc);
+		vblank->enabled = false;
+	}
 
 	/* No further vblank irq's will be processed after
 	 * this point. Get current hardware vblank count and
@@ -778,7 +785,7 @@
 
 /**
  * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
- * 			       vblank interval
+ *                             vblank interval
  * @dev: DRM device
  * @crtc: which CRTC's vblank timestamp to retrieve
  * @tvblank: Pointer to target struct timeval which should receive the timestamp
@@ -933,6 +940,7 @@
 {
 	struct timeval now;
 	unsigned int seq;
+
 	if (crtc >= 0) {
 		seq = drm_vblank_count_and_time(dev, crtc, &now);
 	} else {
@@ -1422,7 +1430,7 @@
 	unsigned int seq;
 	int ret;
 
-	e = kzalloc(sizeof *e, GFP_KERNEL);
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
 	if (e == NULL) {
 		ret = -ENOMEM;
 		goto err_put;
@@ -1431,7 +1439,7 @@
 	e->pipe = pipe;
 	e->base.pid = current->pid;
 	e->event.base.type = DRM_EVENT_VBLANK;
-	e->event.base.length = sizeof e->event;
+	e->event.base.length = sizeof(e->event);
 	e->event.user_data = vblwait->request.signal;
 	e->base.event = &e->event.base;
 	e->base.file_priv = file_priv;
@@ -1451,12 +1459,12 @@
 		goto err_unlock;
 	}
 
-	if (file_priv->event_space < sizeof e->event) {
+	if (file_priv->event_space < sizeof(e->event)) {
 		ret = -EBUSY;
 		goto err_unlock;
 	}
 
-	file_priv->event_space -= sizeof e->event;
+	file_priv->event_space -= sizeof(e->event);
 	seq = drm_vblank_count_and_time(dev, pipe, &now);
 
 	if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index c0644bb..2d5ca8ee 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -323,8 +323,6 @@
 int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
 			   const struct mipi_dsi_msg *msg)
 {
-	const u8 *tx = msg->tx_buf;
-
 	if (!packet || !msg)
 		return -EINVAL;
 
@@ -353,8 +351,10 @@
 		packet->header[2] = (msg->tx_len >> 8) & 0xff;
 
 		packet->payload_length = msg->tx_len;
-		packet->payload = tx;
+		packet->payload = msg->tx_buf;
 	} else {
+		const u8 *tx = msg->tx_buf;
+
 		packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
 		packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
 	}
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 6d8b941..487d0e3 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -615,6 +615,46 @@
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
 
+/**
+ * drm_display_mode_to_videomode - fill in @vm using @dmode,
+ * @dmode: drm_display_mode structure to use as source
+ * @vm: videomode structure to use as destination
+ *
+ * Fills out @vm using the display mode specified in @dmode.
+ */
+void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
+				   struct videomode *vm)
+{
+	vm->hactive = dmode->hdisplay;
+	vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
+	vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
+	vm->hback_porch = dmode->htotal - dmode->hsync_end;
+
+	vm->vactive = dmode->vdisplay;
+	vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
+	vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
+	vm->vback_porch = dmode->vtotal - dmode->vsync_end;
+
+	vm->pixelclock = dmode->clock * 1000;
+
+	vm->flags = 0;
+	if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
+		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+	else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
+		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+	if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
+		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+	else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
+		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+	if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
+		vm->flags |= DISPLAY_FLAGS_INTERLACED;
+	if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
+		vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+	if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
+		vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
+}
+EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
+
 #ifdef CONFIG_OF
 /**
  * of_get_drm_display_mode - get a drm_display_mode from devicetree
@@ -739,6 +779,8 @@
  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
  *   buffers containing two eyes (only adjust the timings when needed, eg. for
  *   "frame packing" or "side by side full").
+ * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
+ *   be performed for doublescan and vscan > 1 modes respectively.
  */
 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
 {
@@ -765,18 +807,22 @@
 		}
 	}
 
-	if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
-		p->crtc_vdisplay *= 2;
-		p->crtc_vsync_start *= 2;
-		p->crtc_vsync_end *= 2;
-		p->crtc_vtotal *= 2;
+	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
+		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
+			p->crtc_vdisplay *= 2;
+			p->crtc_vsync_start *= 2;
+			p->crtc_vsync_end *= 2;
+			p->crtc_vtotal *= 2;
+		}
 	}
 
-	if (p->vscan > 1) {
-		p->crtc_vdisplay *= p->vscan;
-		p->crtc_vsync_start *= p->vscan;
-		p->crtc_vsync_end *= p->vscan;
-		p->crtc_vtotal *= p->vscan;
+	if (!(adjust_flags & CRTC_NO_VSCAN)) {
+		if (p->vscan > 1) {
+			p->crtc_vdisplay *= p->vscan;
+			p->crtc_vsync_start *= p->vscan;
+			p->crtc_vsync_end *= p->vscan;
+			p->crtc_vtotal *= p->vscan;
+		}
 	}
 
 	if (adjust_flags & CRTC_STEREO_DOUBLE) {
@@ -906,9 +952,40 @@
 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
+drm_mode_validate_basic(const struct drm_display_mode *mode)
+{
+	if (mode->clock == 0)
+		return MODE_CLOCK_LOW;
+
+	if (mode->hdisplay == 0 ||
+	    mode->hsync_start < mode->hdisplay ||
+	    mode->hsync_end < mode->hsync_start ||
+	    mode->htotal < mode->hsync_end)
+		return MODE_H_ILLEGAL;
+
+	if (mode->vdisplay == 0 ||
+	    mode->vsync_start < mode->vdisplay ||
+	    mode->vsync_end < mode->vsync_start ||
+	    mode->vtotal < mode->vsync_end)
+		return MODE_V_ILLEGAL;
+
+	return MODE_OK;
+}
+EXPORT_SYMBOL(drm_mode_validate_basic);
+
+/**
  * drm_mode_validate_size - make sure modes adhere to size constraints
- * @dev: DRM device
- * @mode_list: list of modes to check
+ * @mode: mode to check
  * @maxX: maximum width
  * @maxY: maximum height
  *
@@ -916,23 +993,80 @@
  * limitations of the DRM device/connector. If a mode is too big its status
  * member is updated with the appropriate validation failure code. The list
  * itself is not changed.
+ *
+ * Returns:
+ * The mode status
  */
-void drm_mode_validate_size(struct drm_device *dev,
-			    struct list_head *mode_list,
-			    int maxX, int maxY)
+enum drm_mode_status
+drm_mode_validate_size(const struct drm_display_mode *mode,
+		       int maxX, int maxY)
 {
-	struct drm_display_mode *mode;
+	if (maxX > 0 && mode->hdisplay > maxX)
+		return MODE_VIRTUAL_X;
 
-	list_for_each_entry(mode, mode_list, head) {
-		if (maxX > 0 && mode->hdisplay > maxX)
-			mode->status = MODE_VIRTUAL_X;
+	if (maxY > 0 && mode->vdisplay > maxY)
+		return MODE_VIRTUAL_Y;
 
-		if (maxY > 0 && mode->vdisplay > maxY)
-			mode->status = MODE_VIRTUAL_Y;
-	}
+	return MODE_OK;
 }
 EXPORT_SYMBOL(drm_mode_validate_size);
 
+#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
+
+static const char * const drm_mode_status_names[] = {
+	MODE_STATUS(OK),
+	MODE_STATUS(HSYNC),
+	MODE_STATUS(VSYNC),
+	MODE_STATUS(H_ILLEGAL),
+	MODE_STATUS(V_ILLEGAL),
+	MODE_STATUS(BAD_WIDTH),
+	MODE_STATUS(NOMODE),
+	MODE_STATUS(NO_INTERLACE),
+	MODE_STATUS(NO_DBLESCAN),
+	MODE_STATUS(NO_VSCAN),
+	MODE_STATUS(MEM),
+	MODE_STATUS(VIRTUAL_X),
+	MODE_STATUS(VIRTUAL_Y),
+	MODE_STATUS(MEM_VIRT),
+	MODE_STATUS(NOCLOCK),
+	MODE_STATUS(CLOCK_HIGH),
+	MODE_STATUS(CLOCK_LOW),
+	MODE_STATUS(CLOCK_RANGE),
+	MODE_STATUS(BAD_HVALUE),
+	MODE_STATUS(BAD_VVALUE),
+	MODE_STATUS(BAD_VSCAN),
+	MODE_STATUS(HSYNC_NARROW),
+	MODE_STATUS(HSYNC_WIDE),
+	MODE_STATUS(HBLANK_NARROW),
+	MODE_STATUS(HBLANK_WIDE),
+	MODE_STATUS(VSYNC_NARROW),
+	MODE_STATUS(VSYNC_WIDE),
+	MODE_STATUS(VBLANK_NARROW),
+	MODE_STATUS(VBLANK_WIDE),
+	MODE_STATUS(PANEL),
+	MODE_STATUS(INTERLACE_WIDTH),
+	MODE_STATUS(ONE_WIDTH),
+	MODE_STATUS(ONE_HEIGHT),
+	MODE_STATUS(ONE_SIZE),
+	MODE_STATUS(NO_REDUCED),
+	MODE_STATUS(NO_STEREO),
+	MODE_STATUS(UNVERIFIED),
+	MODE_STATUS(BAD),
+	MODE_STATUS(ERROR),
+};
+
+#undef MODE_STATUS
+
+static const char *drm_get_mode_status_name(enum drm_mode_status status)
+{
+	int index = status + 3;
+
+	if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
+		return "";
+
+	return drm_mode_status_names[index];
+}
+
 /**
  * drm_mode_prune_invalid - remove invalid modes from mode list
  * @dev: DRM device
@@ -954,8 +1088,9 @@
 			list_del(&mode->head);
 			if (verbose) {
 				drm_mode_debug_printmodeline(mode);
-				DRM_DEBUG_KMS("Not using %s mode %d\n",
-					mode->name, mode->status);
+				DRM_DEBUG_KMS("Not using %s mode: %s\n",
+					      mode->name,
+					      drm_get_mode_status_name(mode->status));
 			}
 			drm_mode_destroy(dev, mode);
 		}
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 18a1ac6..5ba5792 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -142,6 +142,17 @@
 {
 	int hscale, vscale;
 
+	if (!fb) {
+		*visible = false;
+		return 0;
+	}
+
+	/* crtc should only be NULL when disabling (i.e., !fb) */
+	if (WARN_ON(!crtc)) {
+		*visible = false;
+		return 0;
+	}
+
 	if (!crtc->enabled && !can_update_disabled) {
 		DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
 		return -EINVAL;
@@ -155,11 +166,6 @@
 		return -ERANGE;
 	}
 
-	if (!fb) {
-		*visible = false;
-		return 0;
-	}
-
 	*visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
 	if (!*visible)
 		/*
@@ -429,7 +435,8 @@
 			goto out;
 	}
 
-	if (plane_funcs->prepare_fb && plane_state->fb) {
+	if (plane_funcs->prepare_fb && plane_state->fb &&
+	    plane_state->fb != old_fb) {
 		ret = plane_funcs->prepare_fb(plane, plane_state->fb);
 		if (ret)
 			goto out;
@@ -443,13 +450,28 @@
 			crtc_funcs[i]->atomic_begin(crtc[i]);
 	}
 
-	plane_funcs->atomic_update(plane, plane_state);
+	/*
+	 * Drivers may optionally implement the ->atomic_disable callback, so
+	 * special-case that here.
+	 */
+	if (drm_atomic_plane_disabling(plane, plane_state) &&
+	    plane_funcs->atomic_disable)
+		plane_funcs->atomic_disable(plane, plane_state);
+	else
+		plane_funcs->atomic_update(plane, plane_state);
 
 	for (i = 0; i < 2; i++) {
 		if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
 			crtc_funcs[i]->atomic_flush(crtc[i]);
 	}
 
+	/*
+	 * If we only moved the plane and didn't change fb's, there's no need to
+	 * wait for vblank.
+	 */
+	if (plane->state->fb == old_fb)
+		goto out;
+
 	for (i = 0; i < 2; i++) {
 		if (!crtc[i])
 			continue;
@@ -478,7 +500,7 @@
 }
 
 /**
- * drm_plane_helper_update() - Helper for primary plane update
+ * drm_plane_helper_update() - Transitional helper for plane update
  * @plane: plane object to update
  * @crtc: owning CRTC of owning plane
  * @fb: framebuffer to flip onto plane
@@ -517,6 +539,7 @@
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
+	plane_state->plane = plane;
 
 	plane_state->crtc = crtc;
 	drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -534,7 +557,7 @@
 EXPORT_SYMBOL(drm_plane_helper_update);
 
 /**
- * drm_plane_helper_disable() - Helper for primary plane disable
+ * drm_plane_helper_disable() - Transitional helper for plane disable
  * @plane: plane to disable
  *
  * Provides a default plane disable handler using the atomic plane update
@@ -563,6 +586,7 @@
 		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
 	if (!plane_state)
 		return -ENOMEM;
+	plane_state->plane = plane;
 
 	plane_state->crtc = NULL;
 	drm_atomic_set_fb_for_plane(plane_state, NULL);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 7483a47..6591d48 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -58,28 +58,23 @@
 static bool drm_kms_helper_poll = true;
 module_param_named(poll, drm_kms_helper_poll, bool, 0600);
 
-static void drm_mode_validate_flag(struct drm_connector *connector,
-				   int flags)
+static enum drm_mode_status
+drm_mode_validate_flag(const struct drm_display_mode *mode,
+		       int flags)
 {
-	struct drm_display_mode *mode;
+	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
+	    !(flags & DRM_MODE_FLAG_INTERLACE))
+		return MODE_NO_INTERLACE;
 
-	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
-		      DRM_MODE_FLAG_3D_MASK))
-		return;
+	if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
+	    !(flags & DRM_MODE_FLAG_DBLSCAN))
+		return MODE_NO_DBLESCAN;
 
-	list_for_each_entry(mode, &connector->modes, head) {
-		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
-				!(flags & DRM_MODE_FLAG_INTERLACE))
-			mode->status = MODE_NO_INTERLACE;
-		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
-				!(flags & DRM_MODE_FLAG_DBLSCAN))
-			mode->status = MODE_NO_DBLESCAN;
-		if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
-				!(flags & DRM_MODE_FLAG_3D_MASK))
-			mode->status = MODE_NO_STEREO;
-	}
+	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
+	    !(flags & DRM_MODE_FLAG_3D_MASK))
+		return MODE_NO_STEREO;
 
-	return;
+	return MODE_OK;
 }
 
 static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
@@ -108,6 +103,7 @@
 	int count = 0;
 	int mode_flags = 0;
 	bool verbose_prune = true;
+	enum drm_connector_status old_status;
 
 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
@@ -126,7 +122,33 @@
 		if (connector->funcs->force)
 			connector->funcs->force(connector);
 	} else {
+		old_status = connector->status;
+
 		connector->status = connector->funcs->detect(connector, true);
+
+		/*
+		 * Normally either the driver's hpd code or the poll loop should
+		 * pick up any changes and fire the hotplug event. But if
+		 * userspace sneaks in a probe, we might miss a change. Hence
+		 * check here, and if anything changed start the hotplug code.
+		 */
+		if (old_status != connector->status) {
+			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+				      connector->base.id,
+				      connector->name,
+				      old_status, connector->status);
+
+			/*
+			 * The hotplug event code might call into the fb
+			 * helpers, and so expects that we do not hold any
+			 * locks. Fire up the poll struct instead, it will
+			 * disable itself again.
+			 */
+			dev->mode_config.delayed_event = true;
+			if (dev->mode_config.poll_enabled)
+				schedule_delayed_work(&dev->mode_config.output_poll_work,
+						      0);
+		}
 	}
 
 	/* Re-enable polling in case the global poll config changed. */
@@ -164,18 +186,22 @@
 
 	drm_mode_connector_list_update(connector, merge_type_bits);
 
-	if (maxX && maxY)
-		drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
-
 	if (connector->interlace_allowed)
 		mode_flags |= DRM_MODE_FLAG_INTERLACE;
 	if (connector->doublescan_allowed)
 		mode_flags |= DRM_MODE_FLAG_DBLSCAN;
 	if (connector->stereo_allowed)
 		mode_flags |= DRM_MODE_FLAG_3D_MASK;
-	drm_mode_validate_flag(connector, mode_flags);
 
 	list_for_each_entry(mode, &connector->modes, head) {
+		mode->status = drm_mode_validate_basic(mode);
+
+		if (mode->status == MODE_OK)
+			mode->status = drm_mode_validate_size(mode, maxX, maxY);
+
+		if (mode->status == MODE_OK)
+			mode->status = drm_mode_validate_flag(mode, mode_flags);
+
 		if (mode->status == MODE_OK && connector_funcs->mode_valid)
 			mode->status = connector_funcs->mode_valid(connector,
 								   mode);
@@ -275,10 +301,14 @@
 	struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
 	struct drm_connector *connector;
 	enum drm_connector_status old_status;
-	bool repoll = false, changed = false;
+	bool repoll = false, changed;
+
+	/* Pick up any changes detected by the probe functions. */
+	changed = dev->mode_config.delayed_event;
+	dev->mode_config.delayed_event = false;
 
 	if (!drm_kms_helper_poll)
-		return;
+		goto out;
 
 	mutex_lock(&dev->mode_config.mutex);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -305,6 +335,24 @@
 		if (old_status != connector->status) {
 			const char *old, *new;
 
+			/*
+			 * The poll work sets force=false when calling detect so
+			 * that drivers can avoid to do disruptive tests (e.g.
+			 * when load detect cycles could cause flickering on
+			 * other, running displays). This bears the risk that we
+			 * flip-flop between unknown here in the poll work and
+			 * the real state when userspace forces a full detect
+			 * call after receiving a hotplug event due to this
+			 * change.
+			 *
+			 * Hence clamp an unknown detect status to the old
+			 * value.
+			 */
+			if (connector->status == connector_status_unknown) {
+				connector->status = old_status;
+				continue;
+			}
+
 			old = drm_get_connector_status_name(old_status);
 			new = drm_get_connector_status_name(connector->status);
 
@@ -320,6 +368,7 @@
 
 	mutex_unlock(&dev->mode_config.mutex);
 
+out:
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
 
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index cc3d6d6..5c99d37 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -339,19 +339,51 @@
 			drm_get_dvi_i_select_name((int)subconnector));
 }
 
-static struct device_attribute connector_attrs[] = {
-	__ATTR_RO(status),
-	__ATTR_RO(enabled),
-	__ATTR_RO(dpms),
-	__ATTR_RO(modes),
+static DEVICE_ATTR_RO(status);
+static DEVICE_ATTR_RO(enabled);
+static DEVICE_ATTR_RO(dpms);
+static DEVICE_ATTR_RO(modes);
+
+static struct attribute *connector_dev_attrs[] = {
+	&dev_attr_status.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_dpms.attr,
+	&dev_attr_modes.attr,
+	NULL
 };
 
 /* These attributes are for both DVI-I connectors and all types of tv-out. */
-static struct device_attribute connector_attrs_opt1[] = {
-	__ATTR_RO(subconnector),
-	__ATTR_RO(select_subconnector),
+static DEVICE_ATTR_RO(subconnector);
+static DEVICE_ATTR_RO(select_subconnector);
+
+static struct attribute *connector_opt_dev_attrs[] = {
+	&dev_attr_subconnector.attr,
+	&dev_attr_select_subconnector.attr,
+	NULL
 };
 
+static umode_t connector_opt_dev_is_visible(struct kobject *kobj,
+					    struct attribute *attr, int idx)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct drm_connector *connector = to_drm_connector(dev);
+
+	/*
+	 * In the long run it maybe a good idea to make one set of
+	 * optionals per connector type.
+	 */
+	switch (connector->connector_type) {
+	case DRM_MODE_CONNECTOR_DVII:
+	case DRM_MODE_CONNECTOR_Composite:
+	case DRM_MODE_CONNECTOR_SVIDEO:
+	case DRM_MODE_CONNECTOR_Component:
+	case DRM_MODE_CONNECTOR_TV:
+		return attr->mode;
+	}
+
+	return 0;
+}
+
 static struct bin_attribute edid_attr = {
 	.attr.name = "edid",
 	.attr.mode = 0444,
@@ -359,6 +391,27 @@
 	.read = edid_show,
 };
 
+static struct bin_attribute *connector_bin_attrs[] = {
+	&edid_attr,
+	NULL
+};
+
+static const struct attribute_group connector_dev_group = {
+	.attrs = connector_dev_attrs,
+	.bin_attrs = connector_bin_attrs,
+};
+
+static const struct attribute_group connector_opt_dev_group = {
+	.attrs = connector_opt_dev_attrs,
+	.is_visible = connector_opt_dev_is_visible,
+};
+
+static const struct attribute_group *connector_dev_groups[] = {
+	&connector_dev_group,
+	&connector_opt_dev_group,
+	NULL
+};
+
 /**
  * drm_sysfs_connector_add - add a connector to sysfs
  * @connector: connector to add
@@ -371,73 +424,27 @@
 int drm_sysfs_connector_add(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
-	int attr_cnt = 0;
-	int opt_cnt = 0;
-	int i;
-	int ret;
 
 	if (connector->kdev)
 		return 0;
 
-	connector->kdev = device_create(drm_class, dev->primary->kdev,
-					0, connector, "card%d-%s",
-					dev->primary->index, connector->name);
+	connector->kdev =
+		device_create_with_groups(drm_class, dev->primary->kdev, 0,
+					  connector, connector_dev_groups,
+					  "card%d-%s", dev->primary->index,
+					  connector->name);
 	DRM_DEBUG("adding \"%s\" to sysfs\n",
 		  connector->name);
 
 	if (IS_ERR(connector->kdev)) {
 		DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
-		ret = PTR_ERR(connector->kdev);
-		goto out;
+		return PTR_ERR(connector->kdev);
 	}
 
-	/* Standard attributes */
-
-	for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) {
-		ret = device_create_file(connector->kdev, &connector_attrs[attr_cnt]);
-		if (ret)
-			goto err_out_files;
-	}
-
-	/* Optional attributes */
-	/*
-	 * In the long run it maybe a good idea to make one set of
-	 * optionals per connector type.
-	 */
-	switch (connector->connector_type) {
-		case DRM_MODE_CONNECTOR_DVII:
-		case DRM_MODE_CONNECTOR_Composite:
-		case DRM_MODE_CONNECTOR_SVIDEO:
-		case DRM_MODE_CONNECTOR_Component:
-		case DRM_MODE_CONNECTOR_TV:
-			for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) {
-				ret = device_create_file(connector->kdev, &connector_attrs_opt1[opt_cnt]);
-				if (ret)
-					goto err_out_files;
-			}
-			break;
-		default:
-			break;
-	}
-
-	ret = sysfs_create_bin_file(&connector->kdev->kobj, &edid_attr);
-	if (ret)
-		goto err_out_files;
-
 	/* Let userspace know we have a new connector */
 	drm_sysfs_hotplug_event(dev);
 
 	return 0;
-
-err_out_files:
-	for (i = 0; i < opt_cnt; i++)
-		device_remove_file(connector->kdev, &connector_attrs_opt1[i]);
-	for (i = 0; i < attr_cnt; i++)
-		device_remove_file(connector->kdev, &connector_attrs[i]);
-	device_unregister(connector->kdev);
-
-out:
-	return ret;
 }
 
 /**
@@ -455,16 +462,11 @@
  */
 void drm_sysfs_connector_remove(struct drm_connector *connector)
 {
-	int i;
-
 	if (!connector->kdev)
 		return;
 	DRM_DEBUG("removing \"%s\" from sysfs\n",
 		  connector->name);
 
-	for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
-		device_remove_file(connector->kdev, &connector_attrs[i]);
-	sysfs_remove_bin_file(&connector->kdev->kobj, &edid_attr);
 	device_unregister(connector->kdev);
 	connector->kdev = NULL;
 }
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 7f9f6f9..a5e7461 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -6,23 +6,15 @@
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
-	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	select VIDEOMODE_HELPERS
 	help
 	  Choose this option if you have a Samsung SoC EXYNOS chipset.
 	  If M is selected the module will be called exynosdrm.
 
 config DRM_EXYNOS_IOMMU
-	bool "EXYNOS DRM IOMMU Support"
+	bool
 	depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
-	help
-	  Choose this option if you want to use IOMMU feature for DRM.
-
-config DRM_EXYNOS_DMABUF
-	bool "EXYNOS DRM DMABUF"
-	depends on DRM_EXYNOS
-	help
-	  Choose this option if you want to use DMABUF feature for DRM.
+	default y
 
 config DRM_EXYNOS_FIMD
 	bool "Exynos DRM FIMD"
@@ -32,9 +24,16 @@
 	help
 	  Choose this option if you want to use Exynos FIMD for DRM.
 
+config DRM_EXYNOS7_DECON
+	bool "Exynos DRM DECON"
+	depends on DRM_EXYNOS
+	select FB_MODE_HELPERS
+	help
+	  Choose this option if you want to use Exynos DECON for DRM.
+
 config DRM_EXYNOS_DPI
 	bool "EXYNOS DRM parallel output support"
-	depends on DRM_EXYNOS_FIMD
+	depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
 	select DRM_PANEL
 	default n
 	help
@@ -42,7 +41,7 @@
 
 config DRM_EXYNOS_DSI
 	bool "EXYNOS DRM MIPI-DSI driver support"
-	depends on DRM_EXYNOS_FIMD
+	depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
 	select DRM_MIPI_DSI
 	select DRM_PANEL
 	default n
@@ -51,7 +50,7 @@
 
 config DRM_EXYNOS_DP
 	bool "EXYNOS DRM DP driver support"
-	depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+	depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
 	default DRM_EXYNOS
 	select DRM_PANEL
 	help
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 33ae365..cc90679 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -6,11 +6,11 @@
 exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
 		exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
 		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
-		exynos_drm_plane.o
+		exynos_drm_plane.o exynos_drm_dmabuf.o
 
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)	+= exynos7_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DPI)	+= exynos_drm_dpi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DSI)	+= exynos_drm_dsi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DP)	+= exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
new file mode 100644
index 0000000..63f02e2
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -0,0 +1,990 @@
+/* drivers/gpu/drm/exynos/exynos7_drm_decon.c
+ *
+ * Copyright (C) 2014 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Akshu Agarwal <akshua@gmail.com>
+ *	Ajay Kumar <ajaykumar.rs@samsung.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 <drm/drmP.h>
+#include <drm/exynos_drm.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/exynos7_decon.h>
+
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_fbdev.h"
+#include "exynos_drm_iommu.h"
+
+/*
+ * DECON stands for Display and Enhancement controller.
+ */
+
+#define DECON_DEFAULT_FRAMERATE 60
+#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
+
+#define WINDOWS_NR	2
+
+struct decon_win_data {
+	unsigned int		ovl_x;
+	unsigned int		ovl_y;
+	unsigned int		offset_x;
+	unsigned int		offset_y;
+	unsigned int		ovl_width;
+	unsigned int		ovl_height;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
+	unsigned int		bpp;
+	unsigned int		pixel_format;
+	dma_addr_t		dma_addr;
+	bool			enabled;
+	bool			resume;
+};
+
+struct decon_context {
+	struct device			*dev;
+	struct drm_device		*drm_dev;
+	struct exynos_drm_crtc		*crtc;
+	struct clk			*pclk;
+	struct clk			*aclk;
+	struct clk			*eclk;
+	struct clk			*vclk;
+	void __iomem			*regs;
+	struct decon_win_data		win_data[WINDOWS_NR];
+	unsigned int			default_win;
+	unsigned long			irq_flags;
+	bool				i80_if;
+	bool				suspended;
+	int				pipe;
+	wait_queue_head_t		wait_vsync_queue;
+	atomic_t			wait_vsync_event;
+
+	struct exynos_drm_panel_info panel;
+	struct exynos_drm_display *display;
+};
+
+static const struct of_device_id decon_driver_dt_match[] = {
+	{.compatible = "samsung,exynos7-decon"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, decon_driver_dt_match);
+
+static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
+{
+	struct decon_context *ctx = crtc->ctx;
+
+	if (ctx->suspended)
+		return;
+
+	atomic_set(&ctx->wait_vsync_event, 1);
+
+	/*
+	 * wait for DECON to signal VSYNC interrupt or return after
+	 * timeout which is set to 50ms (refresh rate of 20).
+	 */
+	if (!wait_event_timeout(ctx->wait_vsync_queue,
+				!atomic_read(&ctx->wait_vsync_event),
+				HZ/20))
+		DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static void decon_clear_channel(struct decon_context *ctx)
+{
+	int win, ch_enabled = 0;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* Check if any channel is enabled. */
+	for (win = 0; win < WINDOWS_NR; win++) {
+		u32 val = readl(ctx->regs + WINCON(win));
+
+		if (val & WINCONx_ENWIN) {
+			val &= ~WINCONx_ENWIN;
+			writel(val, ctx->regs + WINCON(win));
+			ch_enabled = 1;
+		}
+	}
+
+	/* Wait for vsync, as disable channel takes effect at next vsync */
+	if (ch_enabled) {
+		unsigned int state = ctx->suspended;
+
+		ctx->suspended = 0;
+		decon_wait_for_vblank(ctx->crtc);
+		ctx->suspended = state;
+	}
+}
+
+static int decon_ctx_initialize(struct decon_context *ctx,
+			struct drm_device *drm_dev)
+{
+	struct exynos_drm_private *priv = drm_dev->dev_private;
+
+	ctx->drm_dev = drm_dev;
+	ctx->pipe = priv->pipe++;
+
+	/* attach this sub driver to iommu mapping if supported. */
+	if (is_drm_iommu_supported(ctx->drm_dev)) {
+		int ret;
+
+		/*
+		 * If any channel is already active, iommu will throw
+		 * a PAGE FAULT when enabled. So clear any channel if enabled.
+		 */
+		decon_clear_channel(ctx);
+		ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+		if (ret) {
+			DRM_ERROR("drm_iommu_attach failed.\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void decon_ctx_remove(struct decon_context *ctx)
+{
+	/* detach this sub driver from iommu mapping if supported. */
+	if (is_drm_iommu_supported(ctx->drm_dev))
+		drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+}
+
+static u32 decon_calc_clkdiv(struct decon_context *ctx,
+		const struct drm_display_mode *mode)
+{
+	unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+	u32 clkdiv;
+
+	/* Find the clock divider value that gets us closest to ideal_clk */
+	clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->vclk), ideal_clk);
+
+	return (clkdiv < 0x100) ? clkdiv : 0xff;
+}
+
+static bool decon_mode_fixup(struct exynos_drm_crtc *crtc,
+		const struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	if (adjusted_mode->vrefresh == 0)
+		adjusted_mode->vrefresh = DECON_DEFAULT_FRAMERATE;
+
+	return true;
+}
+
+static void decon_commit(struct exynos_drm_crtc *crtc)
+{
+	struct decon_context *ctx = crtc->ctx;
+	struct drm_display_mode *mode = &crtc->base.mode;
+	u32 val, clkdiv;
+
+	if (ctx->suspended)
+		return;
+
+	/* nothing to do if we haven't set the mode yet */
+	if (mode->htotal == 0 || mode->vtotal == 0)
+		return;
+
+	if (!ctx->i80_if) {
+		int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
+	      /* setup vertical timing values. */
+		vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+		vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
+		vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
+
+		val = VIDTCON0_VBPD(vbpd - 1) | VIDTCON0_VFPD(vfpd - 1);
+		writel(val, ctx->regs + VIDTCON0);
+
+		val = VIDTCON1_VSPW(vsync_len - 1);
+		writel(val, ctx->regs + VIDTCON1);
+
+		/* setup horizontal timing values.  */
+		hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+		hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
+		hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
+
+		/* setup horizontal timing values.  */
+		val = VIDTCON2_HBPD(hbpd - 1) | VIDTCON2_HFPD(hfpd - 1);
+		writel(val, ctx->regs + VIDTCON2);
+
+		val = VIDTCON3_HSPW(hsync_len - 1);
+		writel(val, ctx->regs + VIDTCON3);
+	}
+
+	/* setup horizontal and vertical display size. */
+	val = VIDTCON4_LINEVAL(mode->vdisplay - 1) |
+	       VIDTCON4_HOZVAL(mode->hdisplay - 1);
+	writel(val, ctx->regs + VIDTCON4);
+
+	writel(mode->vdisplay - 1, ctx->regs + LINECNT_OP_THRESHOLD);
+
+	/*
+	 * fields of register with prefix '_F' would be updated
+	 * at vsync(same as dma start)
+	 */
+	val = VIDCON0_ENVID | VIDCON0_ENVID_F;
+	writel(val, ctx->regs + VIDCON0);
+
+	clkdiv = decon_calc_clkdiv(ctx, mode);
+	if (clkdiv > 1) {
+		val = VCLKCON1_CLKVAL_NUM_VCLK(clkdiv - 1);
+		writel(val, ctx->regs + VCLKCON1);
+		writel(val, ctx->regs + VCLKCON2);
+	}
+
+	val = readl(ctx->regs + DECON_UPDATE);
+	val |= DECON_UPDATE_STANDALONE_F;
+	writel(val, ctx->regs + DECON_UPDATE);
+}
+
+static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
+{
+	struct decon_context *ctx = crtc->ctx;
+	u32 val;
+
+	if (ctx->suspended)
+		return -EPERM;
+
+	if (!test_and_set_bit(0, &ctx->irq_flags)) {
+		val = readl(ctx->regs + VIDINTCON0);
+
+		val |= VIDINTCON0_INT_ENABLE;
+
+		if (!ctx->i80_if) {
+			val |= VIDINTCON0_INT_FRAME;
+			val &= ~VIDINTCON0_FRAMESEL0_MASK;
+			val |= VIDINTCON0_FRAMESEL0_VSYNC;
+		}
+
+		writel(val, ctx->regs + VIDINTCON0);
+	}
+
+	return 0;
+}
+
+static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
+{
+	struct decon_context *ctx = crtc->ctx;
+	u32 val;
+
+	if (ctx->suspended)
+		return;
+
+	if (test_and_clear_bit(0, &ctx->irq_flags)) {
+		val = readl(ctx->regs + VIDINTCON0);
+
+		val &= ~VIDINTCON0_INT_ENABLE;
+		if (!ctx->i80_if)
+			val &= ~VIDINTCON0_INT_FRAME;
+
+		writel(val, ctx->regs + VIDINTCON0);
+	}
+}
+
+static void decon_win_mode_set(struct exynos_drm_crtc *crtc,
+			struct exynos_drm_plane *plane)
+{
+	struct decon_context *ctx = crtc->ctx;
+	struct decon_win_data *win_data;
+	int win, padding;
+
+	if (!plane) {
+		DRM_ERROR("plane is NULL\n");
+		return;
+	}
+
+	win = plane->zpos;
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win >= WINDOWS_NR)
+		return;
+
+
+	win_data = &ctx->win_data[win];
+
+	padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+	win_data->offset_x = plane->fb_x;
+	win_data->offset_y = plane->fb_y;
+	win_data->fb_width = plane->fb_width + padding;
+	win_data->fb_height = plane->fb_height;
+	win_data->ovl_x = plane->crtc_x;
+	win_data->ovl_y = plane->crtc_y;
+	win_data->ovl_width = plane->crtc_width;
+	win_data->ovl_height = plane->crtc_height;
+	win_data->dma_addr = plane->dma_addr[0];
+	win_data->bpp = plane->bpp;
+	win_data->pixel_format = plane->pixel_format;
+
+	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+			win_data->offset_x, win_data->offset_y);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
+	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
+	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+			plane->fb_width, plane->crtc_width);
+}
+
+static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
+{
+	struct decon_win_data *win_data = &ctx->win_data[win];
+	unsigned long val;
+
+	val = readl(ctx->regs + WINCON(win));
+	val &= ~WINCONx_BPPMODE_MASK;
+
+	switch (win_data->pixel_format) {
+	case DRM_FORMAT_RGB565:
+		val |= WINCONx_BPPMODE_16BPP_565;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_XRGB8888:
+		val |= WINCONx_BPPMODE_24BPP_xRGB;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_XBGR8888:
+		val |= WINCONx_BPPMODE_24BPP_xBGR;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_RGBX8888:
+		val |= WINCONx_BPPMODE_24BPP_RGBx;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_BGRX8888:
+		val |= WINCONx_BPPMODE_24BPP_BGRx;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		val |= WINCONx_BPPMODE_32BPP_ARGB | WINCONx_BLD_PIX |
+			WINCONx_ALPHA_SEL;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_ABGR8888:
+		val |= WINCONx_BPPMODE_32BPP_ABGR | WINCONx_BLD_PIX |
+			WINCONx_ALPHA_SEL;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		val |= WINCONx_BPPMODE_32BPP_RGBA | WINCONx_BLD_PIX |
+			WINCONx_ALPHA_SEL;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	case DRM_FORMAT_BGRA8888:
+		val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX |
+			WINCONx_ALPHA_SEL;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	default:
+		DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
+
+		val |= WINCONx_BPPMODE_24BPP_xRGB;
+		val |= WINCONx_BURSTLEN_16WORD;
+		break;
+	}
+
+	DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+
+	/*
+	 * In case of exynos, setting dma-burst to 16Word causes permanent
+	 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
+	 * switching which is based on plane size is not recommended as
+	 * plane size varies a lot towards the end of the screen and rapid
+	 * movement causes unstable DMA which results into iommu crash/tear.
+	 */
+
+	if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+		val &= ~WINCONx_BURSTLEN_MASK;
+		val |= WINCONx_BURSTLEN_8WORD;
+	}
+
+	writel(val, ctx->regs + WINCON(win));
+}
+
+static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
+{
+	unsigned int keycon0 = 0, keycon1 = 0;
+
+	keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
+			WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
+
+	keycon1 = WxKEYCON1_COLVAL(0xffffffff);
+
+	writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
+	writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
+}
+
+/**
+ * shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void decon_shadow_protect_win(struct decon_context *ctx,
+							int win, bool protect)
+{
+	u32 bits, val;
+
+	bits = SHADOWCON_WINx_PROTECT(win);
+
+	val = readl(ctx->regs + SHADOWCON);
+	if (protect)
+		val |= bits;
+	else
+		val &= ~bits;
+	writel(val, ctx->regs + SHADOWCON);
+}
+
+static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+{
+	struct decon_context *ctx = crtc->ctx;
+	struct drm_display_mode *mode = &crtc->base.mode;
+	struct decon_win_data *win_data;
+	int win = zpos;
+	unsigned long val, alpha;
+	unsigned int last_x;
+	unsigned int last_y;
+
+	if (ctx->suspended)
+		return;
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win >= WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+
+	/* If suspended, enable this on resume */
+	if (ctx->suspended) {
+		win_data->resume = true;
+		return;
+	}
+
+	/*
+	 * SHADOWCON/PRTCON register is used for enabling timing.
+	 *
+	 * for example, once only width value of a register is set,
+	 * if the dma is started then decon hardware could malfunction so
+	 * with protect window setting, the register fields with prefix '_F'
+	 * wouldn't be updated at vsync also but updated once unprotect window
+	 * is set.
+	 */
+
+	/* protect windows */
+	decon_shadow_protect_win(ctx, win, true);
+
+	/* buffer start address */
+	val = (unsigned long)win_data->dma_addr;
+	writel(val, ctx->regs + VIDW_BUF_START(win));
+
+	/* buffer size */
+	writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win));
+	writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+
+	/* offset from the start of the buffer to read */
+	writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win));
+	writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win));
+
+	DRM_DEBUG_KMS("start addr = 0x%lx\n",
+			(unsigned long)win_data->dma_addr);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
+
+	/*
+	 * OSD position.
+	 * In case the window layout goes of LCD layout, DECON fails.
+	 */
+	if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay)
+		win_data->ovl_x = mode->hdisplay - win_data->ovl_width;
+	if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay)
+		win_data->ovl_y = mode->vdisplay - win_data->ovl_height;
+
+	val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) |
+		VIDOSDxA_TOPLEFT_Y(win_data->ovl_y);
+	writel(val, ctx->regs + VIDOSD_A(win));
+
+	last_x = win_data->ovl_x + win_data->ovl_width;
+	if (last_x)
+		last_x--;
+	last_y = win_data->ovl_y + win_data->ovl_height;
+	if (last_y)
+		last_y--;
+
+	val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y);
+
+	writel(val, ctx->regs + VIDOSD_B(win));
+
+	DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
+			win_data->ovl_x, win_data->ovl_y, last_x, last_y);
+
+	/* OSD alpha */
+	alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
+			VIDOSDxC_ALPHA0_G_F(0x0) |
+			VIDOSDxC_ALPHA0_B_F(0x0);
+
+	writel(alpha, ctx->regs + VIDOSD_C(win));
+
+	alpha = VIDOSDxD_ALPHA1_R_F(0xff) |
+			VIDOSDxD_ALPHA1_G_F(0xff) |
+			VIDOSDxD_ALPHA1_B_F(0xff);
+
+	writel(alpha, ctx->regs + VIDOSD_D(win));
+
+	decon_win_set_pixfmt(ctx, win);
+
+	/* hardware window 0 doesn't support color key. */
+	if (win != 0)
+		decon_win_set_colkey(ctx, win);
+
+	/* wincon */
+	val = readl(ctx->regs + WINCON(win));
+	val |= WINCONx_TRIPLE_BUF_MODE;
+	val |= WINCONx_ENWIN;
+	writel(val, ctx->regs + WINCON(win));
+
+	/* Enable DMA channel and unprotect windows */
+	decon_shadow_protect_win(ctx, win, false);
+
+	val = readl(ctx->regs + DECON_UPDATE);
+	val |= DECON_UPDATE_STANDALONE_F;
+	writel(val, ctx->regs + DECON_UPDATE);
+
+	win_data->enabled = true;
+}
+
+static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+{
+	struct decon_context *ctx = crtc->ctx;
+	struct decon_win_data *win_data;
+	int win = zpos;
+	u32 val;
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win >= WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+
+	if (ctx->suspended) {
+		/* do not resume this window*/
+		win_data->resume = false;
+		return;
+	}
+
+	/* protect windows */
+	decon_shadow_protect_win(ctx, win, true);
+
+	/* wincon */
+	val = readl(ctx->regs + WINCON(win));
+	val &= ~WINCONx_ENWIN;
+	writel(val, ctx->regs + WINCON(win));
+
+	/* unprotect windows */
+	decon_shadow_protect_win(ctx, win, false);
+
+	val = readl(ctx->regs + DECON_UPDATE);
+	val |= DECON_UPDATE_STANDALONE_F;
+	writel(val, ctx->regs + DECON_UPDATE);
+
+	win_data->enabled = false;
+}
+
+static void decon_window_suspend(struct decon_context *ctx)
+{
+	struct decon_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		win_data->resume = win_data->enabled;
+		if (win_data->enabled)
+			decon_win_disable(ctx->crtc, i);
+	}
+}
+
+static void decon_window_resume(struct decon_context *ctx)
+{
+	struct decon_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		win_data->enabled = win_data->resume;
+		win_data->resume = false;
+	}
+}
+
+static void decon_apply(struct decon_context *ctx)
+{
+	struct decon_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		if (win_data->enabled)
+			decon_win_commit(ctx->crtc, i);
+		else
+			decon_win_disable(ctx->crtc, i);
+	}
+
+	decon_commit(ctx->crtc);
+}
+
+static void decon_init(struct decon_context *ctx)
+{
+	u32 val;
+
+	writel(VIDCON0_SWRESET, ctx->regs + VIDCON0);
+
+	val = VIDOUTCON0_DISP_IF_0_ON;
+	if (!ctx->i80_if)
+		val |= VIDOUTCON0_RGBIF;
+	writel(val, ctx->regs + VIDOUTCON0);
+
+	writel(VCLKCON0_CLKVALUP | VCLKCON0_VCLKFREE, ctx->regs + VCLKCON0);
+
+	if (!ctx->i80_if)
+		writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0));
+}
+
+static int decon_poweron(struct decon_context *ctx)
+{
+	int ret;
+
+	if (!ctx->suspended)
+		return 0;
+
+	ctx->suspended = false;
+
+	pm_runtime_get_sync(ctx->dev);
+
+	ret = clk_prepare_enable(ctx->pclk);
+	if (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
+		goto pclk_err;
+	}
+
+	ret = clk_prepare_enable(ctx->aclk);
+	if (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
+		goto aclk_err;
+	}
+
+	ret = clk_prepare_enable(ctx->eclk);
+	if  (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
+		goto eclk_err;
+	}
+
+	ret = clk_prepare_enable(ctx->vclk);
+	if  (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
+		goto vclk_err;
+	}
+
+	decon_init(ctx);
+
+	/* if vblank was enabled status, enable it again. */
+	if (test_and_clear_bit(0, &ctx->irq_flags)) {
+		ret = decon_enable_vblank(ctx->crtc);
+		if (ret) {
+			DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
+			goto err;
+		}
+	}
+
+	decon_window_resume(ctx);
+
+	decon_apply(ctx);
+
+	return 0;
+
+err:
+	clk_disable_unprepare(ctx->vclk);
+vclk_err:
+	clk_disable_unprepare(ctx->eclk);
+eclk_err:
+	clk_disable_unprepare(ctx->aclk);
+aclk_err:
+	clk_disable_unprepare(ctx->pclk);
+pclk_err:
+	ctx->suspended = true;
+	return ret;
+}
+
+static int decon_poweroff(struct decon_context *ctx)
+{
+	if (ctx->suspended)
+		return 0;
+
+	/*
+	 * We need to make sure that all windows are disabled before we
+	 * suspend that connector. Otherwise we might try to scan from
+	 * a destroyed buffer later.
+	 */
+	decon_window_suspend(ctx);
+
+	clk_disable_unprepare(ctx->vclk);
+	clk_disable_unprepare(ctx->eclk);
+	clk_disable_unprepare(ctx->aclk);
+	clk_disable_unprepare(ctx->pclk);
+
+	pm_runtime_put_sync(ctx->dev);
+
+	ctx->suspended = true;
+	return 0;
+}
+
+static void decon_dpms(struct exynos_drm_crtc *crtc, int mode)
+{
+	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		decon_poweron(crtc->ctx);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		decon_poweroff(crtc->ctx);
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+}
+
+static struct exynos_drm_crtc_ops decon_crtc_ops = {
+	.dpms = decon_dpms,
+	.mode_fixup = decon_mode_fixup,
+	.commit = decon_commit,
+	.enable_vblank = decon_enable_vblank,
+	.disable_vblank = decon_disable_vblank,
+	.wait_for_vblank = decon_wait_for_vblank,
+	.win_mode_set = decon_win_mode_set,
+	.win_commit = decon_win_commit,
+	.win_disable = decon_win_disable,
+};
+
+
+static irqreturn_t decon_irq_handler(int irq, void *dev_id)
+{
+	struct decon_context *ctx = (struct decon_context *)dev_id;
+	u32 val, clear_bit;
+
+	val = readl(ctx->regs + VIDINTCON1);
+
+	clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME;
+	if (val & clear_bit)
+		writel(clear_bit, ctx->regs + VIDINTCON1);
+
+	/* check the crtc is detached already from encoder */
+	if (ctx->pipe < 0 || !ctx->drm_dev)
+		goto out;
+
+	if (!ctx->i80_if) {
+		drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+		exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+
+		/* set wait vsync event to zero and wake up queue. */
+		if (atomic_read(&ctx->wait_vsync_event)) {
+			atomic_set(&ctx->wait_vsync_event, 0);
+			wake_up(&ctx->wait_vsync_queue);
+		}
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+static int decon_bind(struct device *dev, struct device *master, void *data)
+{
+	struct decon_context *ctx = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ret = decon_ctx_initialize(ctx, drm_dev);
+	if (ret) {
+		DRM_ERROR("decon_ctx_initialize failed.\n");
+		return ret;
+	}
+
+	ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+					   EXYNOS_DISPLAY_TYPE_LCD,
+					   &decon_crtc_ops, ctx);
+	if (IS_ERR(ctx->crtc)) {
+		decon_ctx_remove(ctx);
+		return PTR_ERR(ctx->crtc);
+	}
+
+	if (ctx->display)
+		exynos_drm_create_enc_conn(drm_dev, ctx->display);
+
+	return 0;
+
+}
+
+static void decon_unbind(struct device *dev, struct device *master,
+			void *data)
+{
+	struct decon_context *ctx = dev_get_drvdata(dev);
+
+	decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
+
+	if (ctx->display)
+		exynos_dpi_remove(ctx->display);
+
+	decon_ctx_remove(ctx);
+}
+
+static const struct component_ops decon_component_ops = {
+	.bind	= decon_bind,
+	.unbind = decon_unbind,
+};
+
+static int decon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct decon_context *ctx;
+	struct device_node *i80_if_timings;
+	struct resource *res;
+	int ret;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
+					EXYNOS_DISPLAY_TYPE_LCD);
+	if (ret)
+		return ret;
+
+	ctx->dev = dev;
+	ctx->suspended = true;
+
+	i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings");
+	if (i80_if_timings)
+		ctx->i80_if = true;
+	of_node_put(i80_if_timings);
+
+	ctx->regs = of_iomap(dev->of_node, 0);
+	if (IS_ERR(ctx->regs)) {
+		ret = PTR_ERR(ctx->regs);
+		goto err_del_component;
+	}
+
+	ctx->pclk = devm_clk_get(dev, "pclk_decon0");
+	if (IS_ERR(ctx->pclk)) {
+		dev_err(dev, "failed to get bus clock pclk\n");
+		ret = PTR_ERR(ctx->pclk);
+		goto err_iounmap;
+	}
+
+	ctx->aclk = devm_clk_get(dev, "aclk_decon0");
+	if (IS_ERR(ctx->aclk)) {
+		dev_err(dev, "failed to get bus clock aclk\n");
+		ret = PTR_ERR(ctx->aclk);
+		goto err_iounmap;
+	}
+
+	ctx->eclk = devm_clk_get(dev, "decon0_eclk");
+	if (IS_ERR(ctx->eclk)) {
+		dev_err(dev, "failed to get eclock\n");
+		ret = PTR_ERR(ctx->eclk);
+		goto err_iounmap;
+	}
+
+	ctx->vclk = devm_clk_get(dev, "decon0_vclk");
+	if (IS_ERR(ctx->vclk)) {
+		dev_err(dev, "failed to get vclock\n");
+		ret = PTR_ERR(ctx->vclk);
+		goto err_iounmap;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+					   ctx->i80_if ? "lcd_sys" : "vsync");
+	if (!res) {
+		dev_err(dev, "irq request failed.\n");
+		ret = -ENXIO;
+		goto err_iounmap;
+	}
+
+	ret = devm_request_irq(dev, res->start, decon_irq_handler,
+							0, "drm_decon", ctx);
+	if (ret) {
+		dev_err(dev, "irq request failed.\n");
+		goto err_iounmap;
+	}
+
+	init_waitqueue_head(&ctx->wait_vsync_queue);
+	atomic_set(&ctx->wait_vsync_event, 0);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ctx->display = exynos_dpi_probe(dev);
+	if (IS_ERR(ctx->display)) {
+		ret = PTR_ERR(ctx->display);
+		goto err_iounmap;
+	}
+
+	pm_runtime_enable(dev);
+
+	ret = component_add(dev, &decon_component_ops);
+	if (ret)
+		goto err_disable_pm_runtime;
+
+	return ret;
+
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
+
+err_iounmap:
+	iounmap(ctx->regs);
+
+err_del_component:
+	exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
+	return ret;
+}
+
+static int decon_remove(struct platform_device *pdev)
+{
+	struct decon_context *ctx = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+
+	iounmap(ctx->regs);
+
+	component_del(&pdev->dev, &decon_component_ops);
+	exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+
+	return 0;
+}
+
+struct platform_driver decon_driver = {
+	.probe		= decon_probe,
+	.remove		= decon_remove,
+	.driver		= {
+		.name	= "exynos-decon",
+		.of_match_table = decon_driver_dt_match,
+	},
+};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 34d46aa..bf17a60 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/of_graph.h>
 #include <linux/gpio.h>
 #include <linux/component.h>
 #include <linux/phy/phy.h>
@@ -993,32 +994,20 @@
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static bool find_bridge(const char *compat, struct bridge_init *bridge)
-{
-	bridge->client = NULL;
-	bridge->node = of_find_compatible_node(NULL, NULL, compat);
-	if (!bridge->node)
-		return false;
-
-	bridge->client = of_find_i2c_device_by_node(bridge->node);
-	if (!bridge->client)
-		return false;
-
-	return true;
-}
-
 /* returns the number of bridges attached */
-static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
+static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
 		struct drm_encoder *encoder)
 {
-	struct bridge_init bridge;
 	int ret;
 
-	if (find_bridge("nxp,ptn3460", &bridge)) {
-		ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
-		if (!ret)
-			return 1;
+	encoder->bridge = dp->bridge;
+	dp->bridge->encoder = encoder;
+	ret = drm_bridge_attach(encoder->dev, dp->bridge);
+	if (ret) {
+		DRM_ERROR("Failed to attach bridge to drm\n");
+		return ret;
 	}
+
 	return 0;
 }
 
@@ -1032,9 +1021,11 @@
 	dp->encoder = encoder;
 
 	/* Pre-empt DP connector creation if there's a bridge */
-	ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
-	if (ret)
-		return 0;
+	if (dp->bridge) {
+		ret = exynos_drm_attach_lcd_bridge(dp, encoder);
+		if (!ret)
+			return 0;
+	}
 
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1067,10 +1058,8 @@
 		phy_power_off(dp->phy);
 }
 
-static void exynos_dp_poweron(struct exynos_drm_display *display)
+static void exynos_dp_poweron(struct exynos_dp_device *dp)
 {
-	struct exynos_dp_device *dp = display_to_dp(display);
-
 	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
 		return;
 
@@ -1085,13 +1074,11 @@
 	exynos_dp_phy_init(dp);
 	exynos_dp_init_dp(dp);
 	enable_irq(dp->irq);
-	exynos_dp_commit(display);
+	exynos_dp_commit(&dp->display);
 }
 
-static void exynos_dp_poweroff(struct exynos_drm_display *display)
+static void exynos_dp_poweroff(struct exynos_dp_device *dp)
 {
-	struct exynos_dp_device *dp = display_to_dp(display);
-
 	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
 		return;
 
@@ -1119,12 +1106,12 @@
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		exynos_dp_poweron(display);
+		exynos_dp_poweron(dp);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		exynos_dp_poweroff(display);
+		exynos_dp_poweroff(dp);
 		break;
 	default:
 		break;
@@ -1241,7 +1228,7 @@
 		}
 	}
 
-	if (!dp->panel) {
+	if (!dp->panel && !dp->bridge) {
 		ret = exynos_dp_dt_parse_panel(dp);
 		if (ret)
 			return ret;
@@ -1325,7 +1312,7 @@
 static int exynos_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *panel_node;
+	struct device_node *panel_node, *bridge_node, *endpoint;
 	struct exynos_dp_device *dp;
 	int ret;
 
@@ -1351,6 +1338,18 @@
 			return -EPROBE_DEFER;
 	}
 
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (endpoint) {
+		bridge_node = of_graph_get_remote_port_parent(endpoint);
+		if (bridge_node) {
+			dp->bridge = of_drm_find_bridge(bridge_node);
+			of_node_put(bridge_node);
+			if (!dp->bridge)
+				return -EPROBE_DEFER;
+		} else
+			return -EPROBE_DEFER;
+	}
+
 	ret = component_add(&pdev->dev, &exynos_dp_ops);
 	if (ret)
 		exynos_drm_component_del(&pdev->dev,
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 164f171..a4e7996 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -153,6 +153,7 @@
 	struct drm_connector	connector;
 	struct drm_encoder	*encoder;
 	struct drm_panel	*panel;
+	struct drm_bridge	*bridge;
 	struct clk		*clock;
 	unsigned int		irq;
 	void __iomem		*reg_base;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 9c80884..24994ba 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -63,11 +63,11 @@
 			return -ENOMEM;
 		}
 
-		buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+		buf->cookie = dma_alloc_attrs(dev->dev,
 					buf->size,
 					&buf->dma_addr, GFP_KERNEL,
 					&buf->dma_attrs);
-		if (!buf->kvaddr) {
+		if (!buf->cookie) {
 			DRM_ERROR("failed to allocate buffer.\n");
 			ret = -ENOMEM;
 			goto err_free;
@@ -132,7 +132,7 @@
 	buf->sgt = NULL;
 
 	if (!is_drm_iommu_supported(dev)) {
-		dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+		dma_free_attrs(dev->dev, buf->size, buf->cookie,
 				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
 		drm_free_large(buf->pages);
 	} else
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 45026e6..48ccab7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -20,43 +20,9 @@
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_plane.h"
 
-#define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc,\
-				drm_crtc)
-
-enum exynos_crtc_mode {
-	CRTC_MODE_NORMAL,	/* normal mode */
-	CRTC_MODE_BLANK,	/* The private plane of crtc is blank */
-};
-
-/*
- * Exynos specific crtc structure.
- *
- * @drm_crtc: crtc object.
- * @manager: the manager associated with this crtc
- * @pipe: a crtc index created at load() with a new crtc object creation
- *	and the crtc object would be set to private->crtc array
- *	to get a crtc object corresponding to this pipe from private->crtc
- *	array when irq interrupt occurred. the reason of using this pipe is that
- *	drm framework doesn't support multiple irq yet.
- *	we can refer to the crtc to current hardware interrupt occurred through
- *	this pipe value.
- * @dpms: store the crtc dpms value
- * @mode: store the crtc mode value
- */
-struct exynos_drm_crtc {
-	struct drm_crtc			drm_crtc;
-	struct exynos_drm_manager	*manager;
-	unsigned int			pipe;
-	unsigned int			dpms;
-	enum exynos_crtc_mode		mode;
-	wait_queue_head_t		pending_flip_queue;
-	atomic_t			pending_flip;
-};
-
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
@@ -74,8 +40,8 @@
 		drm_crtc_vblank_off(crtc);
 	}
 
-	if (manager->ops->dpms)
-		manager->ops->dpms(manager, mode);
+	if (exynos_crtc->ops->dpms)
+		exynos_crtc->ops->dpms(exynos_crtc, mode);
 
 	exynos_crtc->dpms = mode;
 
@@ -91,16 +57,15 @@
 static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary);
 
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 
-	exynos_plane_commit(crtc->primary);
+	if (exynos_crtc->ops->win_commit)
+		exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
 
-	if (manager->ops->commit)
-		manager->ops->commit(manager);
-
-	exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON);
+	if (exynos_crtc->ops->commit)
+		exynos_crtc->ops->commit(exynos_crtc);
 }
 
 static bool
@@ -109,10 +74,10 @@
 			    struct drm_display_mode *adjusted_mode)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
-	if (manager->ops->mode_fixup)
-		return manager->ops->mode_fixup(manager, mode, adjusted_mode);
+	if (exynos_crtc->ops->mode_fixup)
+		return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
+						    adjusted_mode);
 
 	return true;
 }
@@ -122,11 +87,10 @@
 			  struct drm_display_mode *adjusted_mode, int x, int y,
 			  struct drm_framebuffer *old_fb)
 {
-	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
 	struct drm_framebuffer *fb = crtc->primary->fb;
 	unsigned int crtc_w;
 	unsigned int crtc_h;
+	int ret;
 
 	/*
 	 * copy the mode data adjusted by mode_fixup() into crtc->mode
@@ -134,24 +98,25 @@
 	 */
 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
+	ret = exynos_check_plane(crtc->primary, fb);
+	if (ret < 0)
+		return ret;
+
 	crtc_w = fb->width - x;
 	crtc_h = fb->height - y;
+	exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
+			      crtc_w, crtc_h, x, y, crtc_w, crtc_h);
 
-	if (manager->ops->mode_set)
-		manager->ops->mode_set(manager, &crtc->mode);
-
-	return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
-				     crtc_w, crtc_h, x, y, crtc_w, crtc_h);
+	return 0;
 }
 
-static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
+static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 					  struct drm_framebuffer *old_fb)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 	struct drm_framebuffer *fb = crtc->primary->fb;
 	unsigned int crtc_w;
 	unsigned int crtc_h;
-	int ret;
 
 	/* when framebuffer changing is requested, crtc's dpms should be on */
 	if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
@@ -162,20 +127,8 @@
 	crtc_w = fb->width - x;
 	crtc_h = fb->height - y;
 
-	ret = exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
-				    crtc_w, crtc_h, x, y, crtc_w, crtc_h);
-	if (ret)
-		return ret;
-
-	exynos_drm_crtc_commit(crtc);
-
-	return 0;
-}
-
-static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-					  struct drm_framebuffer *old_fb)
-{
-	return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+	return exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+				   crtc_w, crtc_h, x, y, crtc_w, crtc_h);
 }
 
 static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
@@ -214,6 +167,7 @@
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 	struct drm_framebuffer *old_fb = crtc->primary->fb;
+	unsigned int crtc_w, crtc_h;
 	int ret = -EINVAL;
 
 	/* when the page flip is requested, crtc's dpms should be on */
@@ -245,8 +199,11 @@
 		spin_unlock_irq(&dev->event_lock);
 
 		crtc->primary->fb = fb;
-		ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
-						    NULL);
+		crtc_w = fb->width - crtc->x;
+		crtc_h = fb->height - crtc->y;
+		ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+					  crtc_w, crtc_h, crtc->x, crtc->y,
+					  crtc_w, crtc_h);
 		if (ret) {
 			crtc->primary->fb = old_fb;
 
@@ -275,116 +232,61 @@
 	kfree(exynos_crtc);
 }
 
-static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
-					struct drm_property *property,
-					uint64_t val)
-{
-	struct drm_device *dev = crtc->dev;
-	struct exynos_drm_private *dev_priv = dev->dev_private;
-	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
-	if (property == dev_priv->crtc_mode_property) {
-		enum exynos_crtc_mode mode = val;
-
-		if (mode == exynos_crtc->mode)
-			return 0;
-
-		exynos_crtc->mode = mode;
-
-		switch (mode) {
-		case CRTC_MODE_NORMAL:
-			exynos_drm_crtc_commit(crtc);
-			break;
-		case CRTC_MODE_BLANK:
-			exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_OFF);
-			break;
-		default:
-			break;
-		}
-
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
 static struct drm_crtc_funcs exynos_crtc_funcs = {
 	.set_config	= drm_crtc_helper_set_config,
 	.page_flip	= exynos_drm_crtc_page_flip,
 	.destroy	= exynos_drm_crtc_destroy,
-	.set_property	= exynos_drm_crtc_set_property,
 };
 
-static const struct drm_prop_enum_list mode_names[] = {
-	{ CRTC_MODE_NORMAL, "normal" },
-	{ CRTC_MODE_BLANK, "blank" },
-};
-
-static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct exynos_drm_private *dev_priv = dev->dev_private;
-	struct drm_property *prop;
-
-	prop = dev_priv->crtc_mode_property;
-	if (!prop) {
-		prop = drm_property_create_enum(dev, 0, "mode", mode_names,
-						ARRAY_SIZE(mode_names));
-		if (!prop)
-			return;
-
-		dev_priv->crtc_mode_property = prop;
-	}
-
-	drm_object_attach_property(&crtc->base, prop, 0);
-}
-
-int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
+struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+					       int pipe,
+					       enum exynos_drm_output_type type,
+					       struct exynos_drm_crtc_ops *ops,
+					       void *ctx)
 {
 	struct exynos_drm_crtc *exynos_crtc;
 	struct drm_plane *plane;
-	struct exynos_drm_private *private = manager->drm_dev->dev_private;
+	struct exynos_drm_private *private = drm_dev->dev_private;
 	struct drm_crtc *crtc;
 	int ret;
 
 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 	if (!exynos_crtc)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	init_waitqueue_head(&exynos_crtc->pending_flip_queue);
 	atomic_set(&exynos_crtc->pending_flip, 0);
 
 	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
-	exynos_crtc->manager = manager;
-	exynos_crtc->pipe = manager->pipe;
-	plane = exynos_plane_init(manager->drm_dev, 1 << manager->pipe,
+	exynos_crtc->pipe = pipe;
+	exynos_crtc->type = type;
+	exynos_crtc->ops = ops;
+	exynos_crtc->ctx = ctx;
+	plane = exynos_plane_init(drm_dev, 1 << pipe,
 				  DRM_PLANE_TYPE_PRIMARY);
 	if (IS_ERR(plane)) {
 		ret = PTR_ERR(plane);
 		goto err_plane;
 	}
 
-	manager->crtc = &exynos_crtc->drm_crtc;
-	crtc = &exynos_crtc->drm_crtc;
+	crtc = &exynos_crtc->base;
 
-	private->crtc[manager->pipe] = crtc;
+	private->crtc[pipe] = crtc;
 
-	ret = drm_crtc_init_with_planes(manager->drm_dev, crtc, plane, NULL,
+	ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
 					&exynos_crtc_funcs);
 	if (ret < 0)
 		goto err_crtc;
 
 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
-	exynos_drm_crtc_attach_mode_property(crtc);
-
-	return 0;
+	return exynos_crtc;
 
 err_crtc:
 	plane->funcs->destroy(plane);
 err_plane:
 	kfree(exynos_crtc);
-	return ret;
+	return ERR_PTR(ret);
 }
 
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
@@ -392,13 +294,12 @@
 	struct exynos_drm_private *private = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc =
 		to_exynos_crtc(private->crtc[pipe]);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return -EPERM;
 
-	if (manager->ops->enable_vblank)
-		manager->ops->enable_vblank(manager);
+	if (exynos_crtc->ops->enable_vblank)
+		exynos_crtc->ops->enable_vblank(exynos_crtc);
 
 	return 0;
 }
@@ -408,13 +309,12 @@
 	struct exynos_drm_private *private = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc =
 		to_exynos_crtc(private->crtc[pipe]);
-	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return;
 
-	if (manager->ops->disable_vblank)
-		manager->ops->disable_vblank(manager);
+	if (exynos_crtc->ops->disable_vblank)
+		exynos_crtc->ops->disable_vblank(exynos_crtc);
 }
 
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
@@ -443,42 +343,9 @@
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
-			struct exynos_drm_overlay *overlay)
-{
-	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
-	if (manager->ops->win_mode_set)
-		manager->ops->win_mode_set(manager, overlay);
-}
-
-void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
-{
-	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
-	if (manager->ops->win_commit)
-		manager->ops->win_commit(manager, zpos);
-}
-
-void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
-{
-	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
-	if (manager->ops->win_enable)
-		manager->ops->win_enable(manager, zpos);
-}
-
-void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
-{
-	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
-	if (manager->ops->win_disable)
-		manager->ops->win_disable(manager, zpos);
-}
-
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
 {
-	struct exynos_drm_manager *manager;
+	struct exynos_drm_crtc *exynos_crtc;
 	struct drm_device *dev = fb->dev;
 	struct drm_crtc *crtc;
 
@@ -487,15 +354,15 @@
 	 * for all encoders.
 	 */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		manager = to_exynos_crtc(crtc)->manager;
+		exynos_crtc = to_exynos_crtc(crtc);
 
 		/*
 		 * wait for vblank interrupt
 		 * - this makes sure that overlay data are updated to
 		 *	real hardware.
 		 */
-		if (manager->ops->wait_for_vblank)
-			manager->ops->wait_for_vblank(manager);
+		if (exynos_crtc->ops->wait_for_vblank)
+			exynos_crtc->ops->wait_for_vblank(exynos_crtc);
 	}
 }
 
@@ -508,8 +375,8 @@
 		struct exynos_drm_crtc *exynos_crtc;
 
 		exynos_crtc = to_exynos_crtc(crtc);
-		if (exynos_crtc->manager->type == out_type)
-			return exynos_crtc->manager->pipe;
+		if (exynos_crtc->type == out_type)
+			return exynos_crtc->pipe;
 	}
 
 	return -EPERM;
@@ -517,8 +384,8 @@
 
 void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
 {
-	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-	if (manager->ops->te_handler)
-		manager->ops->te_handler(manager);
+	if (exynos_crtc->ops->te_handler)
+		exynos_crtc->ops->te_handler(exynos_crtc);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index e353d35..6258b80 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -17,14 +17,18 @@
 
 #include "exynos_drm_drv.h"
 
-int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+					       int pipe,
+					       enum exynos_drm_output_type type,
+					       struct exynos_drm_crtc_ops *ops,
+					       void *context);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
 
 void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
-			struct exynos_drm_overlay *overlay);
+			struct exynos_drm_plane *plane);
 void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 60192ed..3833bf8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -279,7 +279,3 @@
 
 	return ERR_PTR(ret);
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM DMABUF Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
index 49acfaf..886de9f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
@@ -12,14 +12,9 @@
 #ifndef _EXYNOS_DRM_DMABUF_H_
 #define _EXYNOS_DRM_DMABUF_H_
 
-#ifdef CONFIG_DRM_EXYNOS_DMABUF
 struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
 				struct drm_gem_object *obj, int flags);
 
 struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
 						struct dma_buf *dma_buf);
-#else
-#define exynos_dmabuf_prime_export		NULL
-#define exynos_dmabuf_prime_import		NULL
-#endif
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 1bcbe07..90168d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -556,6 +556,9 @@
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	&fimd_driver,
 #endif
+#ifdef CONFIG_DRM_EXYNOS7_DECON
+	&decon_driver,
+#endif
 #ifdef CONFIG_DRM_EXYNOS_DP
 	&dp_driver,
 #endif
@@ -612,6 +615,7 @@
 	"samsung,exynos3",
 	"samsung,exynos4",
 	"samsung,exynos5",
+	"samsung,exynos7",
 };
 
 static struct platform_driver exynos_drm_platform_driver = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 2e50634..9afd390 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -23,6 +23,9 @@
 #define MAX_FB_BUFFER	4
 #define DEFAULT_ZPOS	-1
 
+#define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc, base)
+#define to_exynos_plane(x)	container_of(x, struct exynos_drm_plane, base)
+
 /* This enumerates device type. */
 enum exynos_drm_device_type {
 	EXYNOS_DEVICE_TYPE_NONE,
@@ -44,6 +47,7 @@
 /*
  * Exynos drm common overlay structure.
  *
+ * @base: plane object
  * @fb_x: offset x on a framebuffer to be displayed.
  *	- the unit is screen coordinates.
  * @fb_y: offset y on a framebuffer to be displayed.
@@ -73,11 +77,14 @@
  * @local_path: in case of lcd type, local path mode on or off.
  * @transparency: transparency on or off.
  * @activated: activated or not.
+ * @enabled: enabled or not.
  *
  * this structure is common to exynos SoC and its contents would be copied
  * to hardware specific overlay info.
  */
-struct exynos_drm_overlay {
+
+struct exynos_drm_plane {
+	struct drm_plane base;
 	unsigned int fb_x;
 	unsigned int fb_y;
 	unsigned int fb_width;
@@ -104,6 +111,7 @@
 	bool local_path:1;
 	bool transparency:1;
 	bool activated:1;
+	bool enabled:1;
 };
 
 /*
@@ -155,11 +163,10 @@
 };
 
 /*
- * Exynos drm manager ops
+ * Exynos drm crtc ops
  *
  * @dpms: control device power.
  * @mode_fixup: fix mode data before applying it
- * @mode_set: set the given mode to the manager
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -172,44 +179,49 @@
  * @te_handler: trigger to transfer video image at the tearing effect
  *	synchronization signal if there is a page flip request.
  */
-struct exynos_drm_manager;
-struct exynos_drm_manager_ops {
-	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
-	bool (*mode_fixup)(struct exynos_drm_manager *mgr,
+struct exynos_drm_crtc;
+struct exynos_drm_crtc_ops {
+	void (*dpms)(struct exynos_drm_crtc *crtc, int mode);
+	bool (*mode_fixup)(struct exynos_drm_crtc *crtc,
 				const struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode);
-	void (*mode_set)(struct exynos_drm_manager *mgr,
-				const struct drm_display_mode *mode);
-	void (*commit)(struct exynos_drm_manager *mgr);
-	int (*enable_vblank)(struct exynos_drm_manager *mgr);
-	void (*disable_vblank)(struct exynos_drm_manager *mgr);
-	void (*wait_for_vblank)(struct exynos_drm_manager *mgr);
-	void (*win_mode_set)(struct exynos_drm_manager *mgr,
-				struct exynos_drm_overlay *overlay);
-	void (*win_commit)(struct exynos_drm_manager *mgr, int zpos);
-	void (*win_enable)(struct exynos_drm_manager *mgr, int zpos);
-	void (*win_disable)(struct exynos_drm_manager *mgr, int zpos);
-	void (*te_handler)(struct exynos_drm_manager *mgr);
+	void (*commit)(struct exynos_drm_crtc *crtc);
+	int (*enable_vblank)(struct exynos_drm_crtc *crtc);
+	void (*disable_vblank)(struct exynos_drm_crtc *crtc);
+	void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
+	void (*win_mode_set)(struct exynos_drm_crtc *crtc,
+				struct exynos_drm_plane *plane);
+	void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos);
+	void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos);
+	void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos);
+	void (*te_handler)(struct exynos_drm_crtc *crtc);
 };
 
 /*
- * Exynos drm common manager structure, maps 1:1 with a crtc
+ * Exynos specific crtc structure.
  *
- * @list: the list entry for this manager
+ * @base: crtc object.
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
- * @drm_dev: pointer to the drm device
- * @crtc: crtc object.
- * @pipe: the pipe number for this crtc/manager
+ * @pipe: a crtc index created at load() with a new crtc object creation
+ *	and the crtc object would be set to private->crtc array
+ *	to get a crtc object corresponding to this pipe from private->crtc
+ *	array when irq interrupt occurred. the reason of using this pipe is that
+ *	drm framework doesn't support multiple irq yet.
+ *	we can refer to the crtc to current hardware interrupt occurred through
+ *	this pipe value.
+ * @dpms: store the crtc dpms value
  * @ops: pointer to callbacks for exynos drm specific functionality
- * @ctx: A pointer to the manager's implementation specific context
+ * @ctx: A pointer to the crtc's implementation specific context
  */
-struct exynos_drm_manager {
-	struct list_head list;
-	enum exynos_drm_output_type type;
-	struct drm_device *drm_dev;
-	struct drm_crtc *crtc;
-	int pipe;
-	struct exynos_drm_manager_ops *ops;
+struct exynos_drm_crtc {
+	struct drm_crtc			base;
+	enum exynos_drm_output_type	type;
+	unsigned int			pipe;
+	unsigned int			dpms;
+	wait_queue_head_t		pending_flip_queue;
+	atomic_t			pending_flip;
+	struct exynos_drm_crtc_ops	*ops;
+	void				*ctx;
 };
 
 struct exynos_drm_g2d_private {
@@ -246,7 +258,6 @@
 	 */
 	struct drm_crtc *crtc[MAX_CRTC];
 	struct drm_property *plane_zpos_property;
-	struct drm_property *crtc_mode_property;
 
 	unsigned long da_start;
 	unsigned long da_space_size;
@@ -333,6 +344,7 @@
 				enum exynos_drm_device_type dev_type);
 
 extern struct platform_driver fimd_driver;
+extern struct platform_driver decon_driver;
 extern struct platform_driver dp_driver;
 extern struct platform_driver dsi_driver;
 extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 7e282e3..57de0bd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -102,7 +102,7 @@
 
 	/* all planes connected to this encoder should be also disabled. */
 	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
-		if (plane->crtc == encoder->crtc)
+		if (plane->crtc && (plane->crtc == encoder->crtc))
 			plane->funcs->disable_plane(plane);
 	}
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index e12ea90..84f8dfe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -79,9 +79,9 @@
 				     struct drm_framebuffer *fb)
 {
 	struct fb_info *fbi = helper->fbdev;
-	struct drm_device *dev = helper->dev;
 	struct exynos_drm_gem_buf *buffer;
 	unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+	unsigned int nr_pages;
 	unsigned long offset;
 
 	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
@@ -94,25 +94,14 @@
 		return -EFAULT;
 	}
 
-	/* map pages with kernel virtual space. */
-	if (!buffer->kvaddr) {
-		if (is_drm_iommu_supported(dev)) {
-			unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
+	nr_pages = buffer->size >> PAGE_SHIFT;
 
-			buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
-					nr_pages, VM_MAP,
-					pgprot_writecombine(PAGE_KERNEL));
-		} else {
-			phys_addr_t dma_addr = buffer->dma_addr;
-			if (dma_addr)
-				buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
-			else
-				buffer->kvaddr = (void __iomem *)NULL;
-		}
-		if (!buffer->kvaddr) {
-			DRM_ERROR("failed to map pages to kernel space.\n");
-			return -EIO;
-		}
+	buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+			nr_pages, VM_MAP,
+			pgprot_writecombine(PAGE_KERNEL));
+	if (!buffer->kvaddr) {
+		DRM_ERROR("failed to map pages to kernel space.\n");
+		return -EIO;
 	}
 
 	/* buffer count to framebuffer always is 1 at booting time. */
@@ -313,7 +302,7 @@
 	struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
 	struct drm_framebuffer *fb;
 
-	if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr)
+	if (exynos_gem_obj->buffer->kvaddr)
 		vunmap(exynos_gem_obj->buffer->kvaddr);
 
 	/* release drm framebuffer and real buffer */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 835b6af..842d6b8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -461,7 +461,6 @@
 		cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE;
 		break;
 	case DRM_FORMAT_NV12:
-	case DRM_FORMAT_NV12MT:
 	case DRM_FORMAT_NV16:
 		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |
 			EXYNOS_MSCTRL_C_INT_IN_2PLANE);
@@ -511,7 +510,6 @@
 	case DRM_FORMAT_YVU420:
 	case DRM_FORMAT_NV12:
 	case DRM_FORMAT_NV21:
-	case DRM_FORMAT_NV12MT:
 		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
 		break;
 	default:
@@ -524,10 +522,7 @@
 	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
 	cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;
 
-	if (fmt == DRM_FORMAT_NV12MT)
-		cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;
-	else
-		cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
+	cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
 
 	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
 
@@ -812,7 +807,6 @@
 		cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE;
 		break;
 	case DRM_FORMAT_NV12:
-	case DRM_FORMAT_NV12MT:
 	case DRM_FORMAT_NV16:
 		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;
 		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
@@ -867,7 +861,6 @@
 		case DRM_FORMAT_YUV420:
 		case DRM_FORMAT_YVU420:
 		case DRM_FORMAT_NV12:
-		case DRM_FORMAT_NV12MT:
 		case DRM_FORMAT_NV21:
 			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
 			break;
@@ -883,10 +876,7 @@
 	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
 	cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;
 
-	if (fmt == DRM_FORMAT_NV12MT)
-		cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;
-	else
-		cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
+	cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
 
 	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index e5810d1..925fc69 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -157,14 +157,13 @@
 };
 
 struct fimd_context {
-	struct exynos_drm_manager	manager;
 	struct device			*dev;
 	struct drm_device		*drm_dev;
+	struct exynos_drm_crtc		*crtc;
 	struct clk			*bus_clk;
 	struct clk			*lcd_clk;
 	void __iomem			*regs;
 	struct regmap			*sysreg;
-	struct drm_display_mode		mode;
 	struct fimd_win_data		win_data[WINDOWS_NR];
 	unsigned int			default_win;
 	unsigned long			irq_flags;
@@ -185,11 +184,6 @@
 	struct exynos_drm_display *display;
 };
 
-static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr)
-{
-	return container_of(mgr, struct fimd_context, manager);
-}
-
 static const struct of_device_id fimd_driver_dt_match[] = {
 	{ .compatible = "samsung,s3c6400-fimd",
 	  .data = &s3c64xx_fimd_driver_data },
@@ -214,9 +208,9 @@
 	return (struct fimd_driver_data *)of_id->data;
 }
 
-static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
+static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 
 	if (ctx->suspended)
 		return;
@@ -259,9 +253,8 @@
 	writel(val, ctx->regs + SHADOWCON);
 }
 
-static void fimd_clear_channel(struct exynos_drm_manager *mgr)
+static void fimd_clear_channel(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	int win, ch_enabled = 0;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -286,38 +279,42 @@
 		unsigned int state = ctx->suspended;
 
 		ctx->suspended = 0;
-		fimd_wait_for_vblank(mgr);
+		fimd_wait_for_vblank(ctx->crtc);
 		ctx->suspended = state;
 	}
 }
 
-static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
+static int fimd_ctx_initialize(struct fimd_context *ctx,
 			struct drm_device *drm_dev)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	struct exynos_drm_private *priv;
 	priv = drm_dev->dev_private;
 
-	mgr->drm_dev = ctx->drm_dev = drm_dev;
-	mgr->pipe = ctx->pipe = priv->pipe++;
+	ctx->drm_dev = drm_dev;
+	ctx->pipe = priv->pipe++;
 
 	/* attach this sub driver to iommu mapping if supported. */
 	if (is_drm_iommu_supported(ctx->drm_dev)) {
+		int ret;
+
 		/*
 		 * If any channel is already active, iommu will throw
 		 * a PAGE FAULT when enabled. So clear any channel if enabled.
 		 */
-		fimd_clear_channel(mgr);
-		drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+		fimd_clear_channel(ctx);
+		ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+		if (ret) {
+			DRM_ERROR("drm_iommu_attach failed.\n");
+			return ret;
+		}
+
 	}
 
 	return 0;
 }
 
-static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
+static void fimd_ctx_remove(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
-
 	/* detach this sub driver from iommu mapping if supported. */
 	if (is_drm_iommu_supported(ctx->drm_dev))
 		drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
@@ -343,7 +340,7 @@
 	return (clkdiv < 0x100) ? clkdiv : 0xff;
 }
 
-static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
+static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
 {
@@ -353,18 +350,10 @@
 	return true;
 }
 
-static void fimd_mode_set(struct exynos_drm_manager *mgr,
-		const struct drm_display_mode *in_mode)
+static void fimd_commit(struct exynos_drm_crtc *crtc)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
-
-	drm_mode_copy(&ctx->mode, in_mode);
-}
-
-static void fimd_commit(struct exynos_drm_manager *mgr)
-{
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
-	struct drm_display_mode *mode = &ctx->mode;
+	struct fimd_context *ctx = crtc->ctx;
+	struct drm_display_mode *mode = &crtc->base.mode;
 	struct fimd_driver_data *driver_data = ctx->driver_data;
 	void *timing_base = ctx->regs + driver_data->timing_base;
 	u32 val, clkdiv;
@@ -461,9 +450,9 @@
 	writel(val, ctx->regs + VIDCON0);
 }
 
-static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
+static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 	u32 val;
 
 	if (ctx->suspended)
@@ -493,9 +482,9 @@
 	return 0;
 }
 
-static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
+static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 	u32 val;
 
 	if (ctx->suspended)
@@ -517,45 +506,45 @@
 	}
 }
 
-static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
-			struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
+			struct exynos_drm_plane *plane)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 	struct fimd_win_data *win_data;
 	int win;
 	unsigned long offset;
 
-	if (!overlay) {
-		DRM_ERROR("overlay is NULL\n");
+	if (!plane) {
+		DRM_ERROR("plane is NULL\n");
 		return;
 	}
 
-	win = overlay->zpos;
+	win = plane->zpos;
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
 	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
-	offset = overlay->fb_x * (overlay->bpp >> 3);
-	offset += overlay->fb_y * overlay->pitch;
+	offset = plane->fb_x * (plane->bpp >> 3);
+	offset += plane->fb_y * plane->pitch;
 
-	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
 
 	win_data = &ctx->win_data[win];
 
-	win_data->offset_x = overlay->crtc_x;
-	win_data->offset_y = overlay->crtc_y;
-	win_data->ovl_width = overlay->crtc_width;
-	win_data->ovl_height = overlay->crtc_height;
-	win_data->fb_width = overlay->fb_width;
-	win_data->fb_height = overlay->fb_height;
-	win_data->dma_addr = overlay->dma_addr[0] + offset;
-	win_data->bpp = overlay->bpp;
-	win_data->pixel_format = overlay->pixel_format;
-	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
-				(overlay->bpp >> 3);
-	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+	win_data->offset_x = plane->crtc_x;
+	win_data->offset_y = plane->crtc_y;
+	win_data->ovl_width = plane->crtc_width;
+	win_data->ovl_height = plane->crtc_height;
+	win_data->fb_width = plane->fb_width;
+	win_data->fb_height = plane->fb_height;
+	win_data->dma_addr = plane->dma_addr[0] + offset;
+	win_data->bpp = plane->bpp;
+	win_data->pixel_format = plane->pixel_format;
+	win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
+				(plane->bpp >> 3);
+	win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
 
 	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
 			win_data->offset_x, win_data->offset_y);
@@ -563,7 +552,7 @@
 			win_data->ovl_width, win_data->ovl_height);
 	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
 	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-			overlay->fb_width, overlay->crtc_width);
+			plane->fb_width, plane->crtc_width);
 }
 
 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
@@ -623,8 +612,8 @@
 	/*
 	 * In case of exynos, setting dma-burst to 16Word causes permanent
 	 * tearing for very small buffers, e.g. cursor buffer. Burst Mode
-	 * switching which is based on overlay size is not recommended as
-	 * overlay size varies alot towards the end of the screen and rapid
+	 * switching which is based on plane size is not recommended as
+	 * plane size varies alot towards the end of the screen and rapid
 	 * movement causes unstable DMA which results into iommu crash/tear.
 	 */
 
@@ -676,9 +665,9 @@
 	writel(val, ctx->regs + reg);
 }
 
-static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 	struct fimd_win_data *win_data;
 	int win = zpos;
 	unsigned long val, alpha, size;
@@ -799,9 +788,9 @@
 		atomic_set(&ctx->win_updated, 1);
 }
 
-static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 	struct fimd_win_data *win_data;
 	int win = zpos;
 
@@ -833,9 +822,8 @@
 	win_data->enabled = false;
 }
 
-static void fimd_window_suspend(struct exynos_drm_manager *mgr)
+static void fimd_window_suspend(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	struct fimd_win_data *win_data;
 	int i;
 
@@ -843,13 +831,12 @@
 		win_data = &ctx->win_data[i];
 		win_data->resume = win_data->enabled;
 		if (win_data->enabled)
-			fimd_win_disable(mgr, i);
+			fimd_win_disable(ctx->crtc, i);
 	}
 }
 
-static void fimd_window_resume(struct exynos_drm_manager *mgr)
+static void fimd_window_resume(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	struct fimd_win_data *win_data;
 	int i;
 
@@ -860,26 +847,24 @@
 	}
 }
 
-static void fimd_apply(struct exynos_drm_manager *mgr)
+static void fimd_apply(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	struct fimd_win_data *win_data;
 	int i;
 
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled)
-			fimd_win_commit(mgr, i);
+			fimd_win_commit(ctx->crtc, i);
 		else
-			fimd_win_disable(mgr, i);
+			fimd_win_disable(ctx->crtc, i);
 	}
 
-	fimd_commit(mgr);
+	fimd_commit(ctx->crtc);
 }
 
-static int fimd_poweron(struct exynos_drm_manager *mgr)
+static int fimd_poweron(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
 	int ret;
 
 	if (!ctx->suspended)
@@ -903,16 +888,16 @@
 
 	/* if vblank was enabled status, enable it again. */
 	if (test_and_clear_bit(0, &ctx->irq_flags)) {
-		ret = fimd_enable_vblank(mgr);
+		ret = fimd_enable_vblank(ctx->crtc);
 		if (ret) {
 			DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
 			goto enable_vblank_err;
 		}
 	}
 
-	fimd_window_resume(mgr);
+	fimd_window_resume(ctx);
 
-	fimd_apply(mgr);
+	fimd_apply(ctx);
 
 	return 0;
 
@@ -925,10 +910,8 @@
 	return ret;
 }
 
-static int fimd_poweroff(struct exynos_drm_manager *mgr)
+static int fimd_poweroff(struct fimd_context *ctx)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
-
 	if (ctx->suspended)
 		return 0;
 
@@ -937,7 +920,7 @@
 	 * suspend that connector. Otherwise we might try to scan from
 	 * a destroyed buffer later.
 	 */
-	fimd_window_suspend(mgr);
+	fimd_window_suspend(ctx);
 
 	clk_disable_unprepare(ctx->lcd_clk);
 	clk_disable_unprepare(ctx->bus_clk);
@@ -948,18 +931,18 @@
 	return 0;
 }
 
-static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
+static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode)
 {
 	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		fimd_poweron(mgr);
+		fimd_poweron(crtc->ctx);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		fimd_poweroff(mgr);
+		fimd_poweroff(crtc->ctx);
 		break;
 	default:
 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -996,9 +979,9 @@
 		atomic_set(&ctx->triggering, 0);
 }
 
-static void fimd_te_handler(struct exynos_drm_manager *mgr)
+static void fimd_te_handler(struct exynos_drm_crtc *crtc)
 {
-	struct fimd_context *ctx = mgr_to_fimd(mgr);
+	struct fimd_context *ctx = crtc->ctx;
 
 	/* Checks the crtc is detached already from encoder */
 	if (ctx->pipe < 0 || !ctx->drm_dev)
@@ -1021,10 +1004,9 @@
 		drm_handle_vblank(ctx->drm_dev, ctx->pipe);
 }
 
-static struct exynos_drm_manager_ops fimd_manager_ops = {
+static struct exynos_drm_crtc_ops fimd_crtc_ops = {
 	.dpms = fimd_dpms,
 	.mode_fixup = fimd_mode_fixup,
-	.mode_set = fimd_mode_set,
 	.commit = fimd_commit,
 	.enable_vblank = fimd_enable_vblank,
 	.disable_vblank = fimd_disable_vblank,
@@ -1074,9 +1056,22 @@
 {
 	struct fimd_context *ctx = dev_get_drvdata(dev);
 	struct drm_device *drm_dev = data;
+	int ret;
 
-	fimd_mgr_initialize(&ctx->manager, drm_dev);
-	exynos_drm_crtc_create(&ctx->manager);
+	ret = fimd_ctx_initialize(ctx, drm_dev);
+	if (ret) {
+		DRM_ERROR("fimd_ctx_initialize failed.\n");
+		return ret;
+	}
+
+	ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+					   EXYNOS_DISPLAY_TYPE_LCD,
+					   &fimd_crtc_ops, ctx);
+	if (IS_ERR(ctx->crtc)) {
+		fimd_ctx_remove(ctx);
+		return PTR_ERR(ctx->crtc);
+	}
+
 	if (ctx->display)
 		exynos_drm_create_enc_conn(drm_dev, ctx->display);
 
@@ -1089,12 +1084,12 @@
 {
 	struct fimd_context *ctx = dev_get_drvdata(dev);
 
-	fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF);
+	fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
 
 	if (ctx->display)
 		exynos_dpi_remove(ctx->display);
 
-	fimd_mgr_remove(&ctx->manager);
+	fimd_ctx_remove(ctx);
 }
 
 static const struct component_ops fimd_component_ops = {
@@ -1108,7 +1103,7 @@
 	struct fimd_context *ctx;
 	struct device_node *i80_if_timings;
 	struct resource *res;
-	int ret = -EINVAL;
+	int ret;
 
 	if (!dev->of_node)
 		return -ENODEV;
@@ -1117,11 +1112,8 @@
 	if (!ctx)
 		return -ENOMEM;
 
-	ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD;
-	ctx->manager.ops = &fimd_manager_ops;
-
 	ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
-				       ctx->manager.type);
+				       EXYNOS_DISPLAY_TYPE_LCD);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index ec58fe9..308173c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -22,6 +22,7 @@
 /*
  * exynos drm gem buffer structure.
  *
+ * @cookie: cookie returned by dma_alloc_attrs
  * @kvaddr: kernel virtual address to allocated memory region.
  * *userptr: user space address.
  * @dma_addr: bus address(accessed by dma) to allocated memory region.
@@ -35,6 +36,7 @@
  *	VM_PFNMAP or not.
  */
 struct exynos_drm_gem_buf {
+	void 			*cookie;
 	void __iomem		*kvaddr;
 	unsigned long		userptr;
 	dma_addr_t		dma_addr;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 0261468..8040ed2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -542,9 +542,6 @@
 		cfg |= (GSC_IN_CHROMA_ORDER_CBCR |
 			GSC_IN_YUV420_2P);
 		break;
-	case DRM_FORMAT_NV12MT:
-		cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE);
-		break;
 	default:
 		dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
 		return -EINVAL;
@@ -809,9 +806,6 @@
 		cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |
 			GSC_OUT_YUV420_2P);
 		break;
-	case DRM_FORMAT_NV12MT:
-		cfg |= (GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE);
-		break;
 	default:
 		dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
 		return -EINVAL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index c7045a66..a561687 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -12,25 +12,17 @@
 #include <drm/drmP.h>
 
 #include <drm/exynos_drm.h>
+#include <drm/drm_plane_helper.h>
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
 
-#define to_exynos_plane(x)	container_of(x, struct exynos_plane, base)
-
-struct exynos_plane {
-	struct drm_plane		base;
-	struct exynos_drm_overlay	overlay;
-	bool				enabled;
-};
-
 static const uint32_t formats[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
 	DRM_FORMAT_NV12,
-	DRM_FORMAT_NV12MT,
 };
 
 /*
@@ -69,16 +61,9 @@
 	return size;
 }
 
-int exynos_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)
+int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb)
 {
-	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
-	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-	unsigned int actual_w;
-	unsigned int actual_h;
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 	int nr;
 	int i;
 
@@ -91,12 +76,26 @@
 			return -EFAULT;
 		}
 
-		overlay->dma_addr[i] = buffer->dma_addr;
+		exynos_plane->dma_addr[i] = buffer->dma_addr;
 
 		DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
-				i, (unsigned long)overlay->dma_addr[i]);
+				i, (unsigned long)exynos_plane->dma_addr[i]);
 	}
 
+	return 0;
+}
+
+void exynos_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 exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	unsigned int actual_w;
+	unsigned int actual_h;
+
 	actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
 	actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
 
@@ -113,98 +112,79 @@
 	}
 
 	/* set drm framebuffer data. */
-	overlay->fb_x = src_x;
-	overlay->fb_y = src_y;
-	overlay->fb_width = fb->width;
-	overlay->fb_height = fb->height;
-	overlay->src_width = src_w;
-	overlay->src_height = src_h;
-	overlay->bpp = fb->bits_per_pixel;
-	overlay->pitch = fb->pitches[0];
-	overlay->pixel_format = fb->pixel_format;
+	exynos_plane->fb_x = src_x;
+	exynos_plane->fb_y = src_y;
+	exynos_plane->fb_width = fb->width;
+	exynos_plane->fb_height = fb->height;
+	exynos_plane->src_width = src_w;
+	exynos_plane->src_height = src_h;
+	exynos_plane->bpp = fb->bits_per_pixel;
+	exynos_plane->pitch = fb->pitches[0];
+	exynos_plane->pixel_format = fb->pixel_format;
 
-	/* set overlay range to be displayed. */
-	overlay->crtc_x = crtc_x;
-	overlay->crtc_y = crtc_y;
-	overlay->crtc_width = actual_w;
-	overlay->crtc_height = actual_h;
+	/* set plane range to be displayed. */
+	exynos_plane->crtc_x = crtc_x;
+	exynos_plane->crtc_y = crtc_y;
+	exynos_plane->crtc_width = actual_w;
+	exynos_plane->crtc_height = actual_h;
 
 	/* set drm mode data. */
-	overlay->mode_width = crtc->mode.hdisplay;
-	overlay->mode_height = crtc->mode.vdisplay;
-	overlay->refresh = crtc->mode.vrefresh;
-	overlay->scan_flag = crtc->mode.flags;
+	exynos_plane->mode_width = crtc->mode.hdisplay;
+	exynos_plane->mode_height = crtc->mode.vdisplay;
+	exynos_plane->refresh = crtc->mode.vrefresh;
+	exynos_plane->scan_flag = crtc->mode.flags;
 
-	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
-			overlay->crtc_x, overlay->crtc_y,
-			overlay->crtc_width, overlay->crtc_height);
+	DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
+			exynos_plane->crtc_x, exynos_plane->crtc_y,
+			exynos_plane->crtc_width, exynos_plane->crtc_height);
 
 	plane->crtc = crtc;
 
-	exynos_drm_crtc_plane_mode_set(crtc, overlay);
-
-	return 0;
+	if (exynos_crtc->ops->win_mode_set)
+		exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
 }
 
-void exynos_plane_commit(struct drm_plane *plane)
-{
-	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
-	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
-	exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
-}
-
-void exynos_plane_dpms(struct drm_plane *plane, int mode)
-{
-	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
-	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
-	if (mode == DRM_MODE_DPMS_ON) {
-		if (exynos_plane->enabled)
-			return;
-
-		exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
-		exynos_plane->enabled = true;
-	} else {
-		if (!exynos_plane->enabled)
-			return;
-
-		exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
-		exynos_plane->enabled = false;
-	}
-}
-
-static int
+int
 exynos_update_plane(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 exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 	int ret;
 
-	ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
-			crtc_w, crtc_h, src_x >> 16, src_y >> 16,
-			src_w >> 16, src_h >> 16);
+	ret = exynos_check_plane(plane, fb);
 	if (ret < 0)
 		return ret;
 
-	exynos_plane_commit(plane);
-	exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
+	exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
+			      crtc_w, crtc_h, src_x >> 16, src_y >> 16,
+			      src_w >> 16, src_h >> 16);
+
+	if (exynos_crtc->ops->win_commit)
+		exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
 
 	return 0;
 }
 
 static int exynos_disable_plane(struct drm_plane *plane)
 {
-	exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
+
+	if (exynos_crtc->ops->win_disable)
+		exynos_crtc->ops->win_disable(exynos_crtc,
+					      exynos_plane->zpos);
 
 	return 0;
 }
 
 static void exynos_plane_destroy(struct drm_plane *plane)
 {
-	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 
 	exynos_disable_plane(plane);
 	drm_plane_cleanup(plane);
@@ -216,11 +196,11 @@
 				     uint64_t val)
 {
 	struct drm_device *dev = plane->dev;
-	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 
 	if (property == dev_priv->plane_zpos_property) {
-		exynos_plane->overlay.zpos = val;
+		exynos_plane->zpos = val;
 		return 0;
 	}
 
@@ -257,10 +237,10 @@
 				    unsigned long possible_crtcs,
 				    enum drm_plane_type type)
 {
-	struct exynos_plane *exynos_plane;
+	struct exynos_drm_plane *exynos_plane;
 	int err;
 
-	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
+	exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL);
 	if (!exynos_plane)
 		return ERR_PTR(-ENOMEM);
 
@@ -274,7 +254,7 @@
 	}
 
 	if (type == DRM_PLANE_TYPE_PRIMARY)
-		exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+		exynos_plane->zpos = DEFAULT_ZPOS;
 	else
 		exynos_plane_attach_zpos_property(&exynos_plane->base);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 0d1986b..9d3c374 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -9,13 +9,17 @@
  *
  */
 
-int exynos_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);
-void exynos_plane_commit(struct drm_plane *plane);
-void exynos_plane_dpms(struct drm_plane *plane, int mode);
+int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb);
+void exynos_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);
+int exynos_update_plane(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_plane *exynos_plane_init(struct drm_device *dev,
 				    unsigned long possible_crtcs,
 				    enum drm_plane_type type);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 45899fb..b886972 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -47,11 +47,10 @@
 };
 
 struct vidi_context {
-	struct exynos_drm_manager	manager;
 	struct exynos_drm_display	display;
 	struct platform_device		*pdev;
 	struct drm_device		*drm_dev;
-	struct drm_crtc			*crtc;
+	struct exynos_drm_crtc		*crtc;
 	struct drm_encoder		*encoder;
 	struct drm_connector		connector;
 	struct vidi_win_data		win_data[WINDOWS_NR];
@@ -68,11 +67,6 @@
 	int				pipe;
 };
 
-static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
-{
-	return container_of(m, struct vidi_context, manager);
-}
-
 static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
 {
 	return container_of(d, struct vidi_context, display);
@@ -103,34 +97,22 @@
 	0x00, 0x00, 0x00, 0x06
 };
 
-static void vidi_apply(struct exynos_drm_manager *mgr)
+static void vidi_apply(struct vidi_context *ctx)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
-	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+	struct exynos_drm_crtc_ops *crtc_ops = ctx->crtc->ops;
 	struct vidi_win_data *win_data;
 	int i;
 
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
-		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
-			mgr_ops->win_commit(mgr, i);
+		if (win_data->enabled && (crtc_ops && crtc_ops->win_commit))
+			crtc_ops->win_commit(ctx->crtc, i);
 	}
-
-	if (mgr_ops && mgr_ops->commit)
-		mgr_ops->commit(mgr);
 }
 
-static void vidi_commit(struct exynos_drm_manager *mgr)
+static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
-
-	if (ctx->suspended)
-		return;
-}
-
-static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
-{
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 
 	if (ctx->suspended)
 		return -EPERM;
@@ -143,16 +125,16 @@
 	/*
 	 * in case of page flip request, vidi_finish_pageflip function
 	 * will not be called because direct_vblank is true and then
-	 * that function will be called by manager_ops->win_commit callback
+	 * that function will be called by crtc_ops->win_commit callback
 	 */
 	schedule_work(&ctx->work);
 
 	return 0;
 }
 
-static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
+static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 
 	if (ctx->suspended)
 		return;
@@ -161,44 +143,44 @@
 		ctx->vblank_on = false;
 }
 
-static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
-			struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(struct exynos_drm_crtc *crtc,
+			struct exynos_drm_plane *plane)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 	struct vidi_win_data *win_data;
 	int win;
 	unsigned long offset;
 
-	if (!overlay) {
-		DRM_ERROR("overlay is NULL\n");
+	if (!plane) {
+		DRM_ERROR("plane is NULL\n");
 		return;
 	}
 
-	win = overlay->zpos;
+	win = plane->zpos;
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
 	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
-	offset = overlay->fb_x * (overlay->bpp >> 3);
-	offset += overlay->fb_y * overlay->pitch;
+	offset = plane->fb_x * (plane->bpp >> 3);
+	offset += plane->fb_y * plane->pitch;
 
-	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
 
 	win_data = &ctx->win_data[win];
 
-	win_data->offset_x = overlay->crtc_x;
-	win_data->offset_y = overlay->crtc_y;
-	win_data->ovl_width = overlay->crtc_width;
-	win_data->ovl_height = overlay->crtc_height;
-	win_data->fb_width = overlay->fb_width;
-	win_data->fb_height = overlay->fb_height;
-	win_data->dma_addr = overlay->dma_addr[0] + offset;
-	win_data->bpp = overlay->bpp;
-	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
-				(overlay->bpp >> 3);
-	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+	win_data->offset_x = plane->crtc_x;
+	win_data->offset_y = plane->crtc_y;
+	win_data->ovl_width = plane->crtc_width;
+	win_data->ovl_height = plane->crtc_height;
+	win_data->fb_width = plane->fb_width;
+	win_data->fb_height = plane->fb_height;
+	win_data->dma_addr = plane->dma_addr[0] + offset;
+	win_data->bpp = plane->bpp;
+	win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
+				(plane->bpp >> 3);
+	win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
 
 	/*
 	 * some parts of win_data should be transferred to user side
@@ -211,12 +193,12 @@
 			win_data->ovl_width, win_data->ovl_height);
 	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
 	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
-			overlay->fb_width, overlay->crtc_width);
+			plane->fb_width, plane->crtc_width);
 }
 
-static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
@@ -239,9 +221,9 @@
 		schedule_work(&ctx->work);
 }
 
-static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
@@ -257,10 +239,8 @@
 	/* TODO. */
 }
 
-static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
+static int vidi_power_on(struct vidi_context *ctx, bool enable)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
-
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
 	if (enable != false && enable != true)
@@ -271,9 +251,9 @@
 
 		/* if vblank was enabled status, enable it again. */
 		if (test_and_clear_bit(0, &ctx->irq_flags))
-			vidi_enable_vblank(mgr);
+			vidi_enable_vblank(ctx->crtc);
 
-		vidi_apply(mgr);
+		vidi_apply(ctx);
 	} else {
 		ctx->suspended = true;
 	}
@@ -281,9 +261,9 @@
 	return 0;
 }
 
-static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
+static void vidi_dpms(struct exynos_drm_crtc *crtc, int mode)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
+	struct vidi_context *ctx = crtc->ctx;
 
 	DRM_DEBUG_KMS("%d\n", mode);
 
@@ -291,12 +271,12 @@
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		vidi_power_on(mgr, true);
+		vidi_power_on(ctx, true);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		vidi_power_on(mgr, false);
+		vidi_power_on(ctx, false);
 		break;
 	default:
 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -306,21 +286,19 @@
 	mutex_unlock(&ctx->lock);
 }
 
-static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
+static int vidi_ctx_initialize(struct vidi_context *ctx,
 			struct drm_device *drm_dev)
 {
-	struct vidi_context *ctx = manager_to_vidi(mgr);
 	struct exynos_drm_private *priv = drm_dev->dev_private;
 
-	mgr->drm_dev = ctx->drm_dev = drm_dev;
-	mgr->pipe = ctx->pipe = priv->pipe++;
+	ctx->drm_dev = drm_dev;
+	ctx->pipe = priv->pipe++;
 
 	return 0;
 }
 
-static struct exynos_drm_manager_ops vidi_manager_ops = {
+static struct exynos_drm_crtc_ops vidi_crtc_ops = {
 	.dpms = vidi_dpms,
-	.commit = vidi_commit,
 	.enable_vblank = vidi_enable_vblank,
 	.disable_vblank = vidi_disable_vblank,
 	.win_mode_set = vidi_win_mode_set,
@@ -565,21 +543,21 @@
 {
 	struct vidi_context *ctx = dev_get_drvdata(dev);
 	struct drm_device *drm_dev = data;
-	struct drm_crtc *crtc = ctx->crtc;
 	int ret;
 
-	vidi_mgr_initialize(&ctx->manager, drm_dev);
+	vidi_ctx_initialize(ctx, drm_dev);
 
-	ret = exynos_drm_crtc_create(&ctx->manager);
-	if (ret) {
+	ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+					   EXYNOS_DISPLAY_TYPE_VIDI,
+					   &vidi_crtc_ops, ctx);
+	if (IS_ERR(ctx->crtc)) {
 		DRM_ERROR("failed to create crtc.\n");
-		return ret;
+		return PTR_ERR(ctx->crtc);
 	}
 
 	ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
 	if (ret) {
-		crtc->funcs->destroy(crtc);
-		DRM_ERROR("failed to create encoder and connector.\n");
+		ctx->crtc->base.funcs->destroy(&ctx->crtc->base);
 		return ret;
 	}
 
@@ -605,15 +583,13 @@
 	if (!ctx)
 		return -ENOMEM;
 
-	ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
-	ctx->manager.ops = &vidi_manager_ops;
 	ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
 	ctx->display.ops = &vidi_display_ops;
 	ctx->default_win = 0;
 	ctx->pdev = pdev;
 
 	ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
-					ctx->manager.type);
+					EXYNOS_DISPLAY_TYPE_VIDI);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 98051e8..229b361 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2032,9 +2032,8 @@
 	hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweron(struct exynos_drm_display *display)
+static void hdmi_poweron(struct hdmi_context *hdata)
 {
-	struct hdmi_context *hdata = display_to_hdmi(display);
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -2060,12 +2059,11 @@
 	clk_prepare_enable(res->sclk_hdmi);
 
 	hdmiphy_poweron(hdata);
-	hdmi_commit(display);
+	hdmi_commit(&hdata->display);
 }
 
-static void hdmi_poweroff(struct exynos_drm_display *display)
+static void hdmi_poweroff(struct hdmi_context *hdata)
 {
-	struct hdmi_context *hdata = display_to_hdmi(display);
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -2109,7 +2107,7 @@
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		hdmi_poweron(display);
+		hdmi_poweron(hdata);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
@@ -2128,7 +2126,7 @@
 		if (funcs && funcs->dpms)
 			(*funcs->dpms)(crtc, mode);
 
-		hdmi_poweroff(display);
+		hdmi_poweroff(hdata);
 		break;
 	default:
 		DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 064ed65..3518bc4 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -72,6 +72,7 @@
 	spinlock_t		reg_slock;
 	struct clk		*mixer;
 	struct clk		*vp;
+	struct clk		*hdmi;
 	struct clk		*sclk_mixer;
 	struct clk		*sclk_hdmi;
 	struct clk		*mout_mixer;
@@ -84,10 +85,10 @@
 };
 
 struct mixer_context {
-	struct exynos_drm_manager manager;
 	struct platform_device *pdev;
 	struct device		*dev;
 	struct drm_device	*drm_dev;
+	struct exynos_drm_crtc	*crtc;
 	int			pipe;
 	bool			interlace;
 	bool			powered;
@@ -103,11 +104,6 @@
 	atomic_t		wait_vsync_event;
 };
 
-static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
-{
-	return container_of(mgr, struct mixer_context, manager);
-}
-
 struct mixer_drv_data {
 	enum mixer_version_id	version;
 	bool					is_vp_enabled;
@@ -417,8 +413,6 @@
 	win_data = &ctx->win_data[win];
 
 	switch (win_data->pixel_format) {
-	case DRM_FORMAT_NV12MT:
-		tiled_mode = true;
 	case DRM_FORMAT_NV12:
 		crcb_mode = false;
 		buf_num = 2;
@@ -587,8 +581,8 @@
 	/* setup display size */
 	if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
 		win == MIXER_DEFAULT_WIN) {
-		val  = MXR_MXR_RES_HEIGHT(win_data->fb_height);
-		val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
+		val  = MXR_MXR_RES_HEIGHT(win_data->mode_height);
+		val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
 		mixer_reg_write(res, MXR_RESOLUTION, val);
 	}
 
@@ -774,6 +768,12 @@
 		return -ENODEV;
 	}
 
+	mixer_res->hdmi = devm_clk_get(dev, "hdmi");
+	if (IS_ERR(mixer_res->hdmi)) {
+		dev_err(dev, "failed to get clock 'hdmi'\n");
+		return PTR_ERR(mixer_res->hdmi);
+	}
+
 	mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
 	if (IS_ERR(mixer_res->sclk_hdmi)) {
 		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
@@ -854,16 +854,15 @@
 	return 0;
 }
 
-static int mixer_initialize(struct exynos_drm_manager *mgr,
+static int mixer_initialize(struct mixer_context *mixer_ctx,
 			struct drm_device *drm_dev)
 {
 	int ret;
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 	struct exynos_drm_private *priv;
 	priv = drm_dev->dev_private;
 
-	mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
-	mgr->pipe = mixer_ctx->pipe = priv->pipe++;
+	mixer_ctx->drm_dev = drm_dev;
+	mixer_ctx->pipe = priv->pipe++;
 
 	/* acquire resources: regs, irqs, clocks */
 	ret = mixer_resources_init(mixer_ctx);
@@ -887,17 +886,15 @@
 	return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
+static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
-
 	if (is_drm_iommu_supported(mixer_ctx->drm_dev))
 		drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
+static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
 	if (!mixer_ctx->powered) {
@@ -912,34 +909,34 @@
 	return 0;
 }
 
-static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
+static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
 	/* disable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
-			struct exynos_drm_overlay *overlay)
+static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
+			struct exynos_drm_plane *plane)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	struct hdmi_win_data *win_data;
 	int win;
 
-	if (!overlay) {
-		DRM_ERROR("overlay is NULL\n");
+	if (!plane) {
+		DRM_ERROR("plane is NULL\n");
 		return;
 	}
 
 	DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
-				 overlay->fb_width, overlay->fb_height,
-				 overlay->fb_x, overlay->fb_y,
-				 overlay->crtc_width, overlay->crtc_height,
-				 overlay->crtc_x, overlay->crtc_y);
+				 plane->fb_width, plane->fb_height,
+				 plane->fb_x, plane->fb_y,
+				 plane->crtc_width, plane->crtc_height,
+				 plane->crtc_x, plane->crtc_y);
 
-	win = overlay->zpos;
+	win = plane->zpos;
 	if (win == DEFAULT_ZPOS)
 		win = MIXER_DEFAULT_WIN;
 
@@ -950,32 +947,32 @@
 
 	win_data = &mixer_ctx->win_data[win];
 
-	win_data->dma_addr = overlay->dma_addr[0];
-	win_data->chroma_dma_addr = overlay->dma_addr[1];
-	win_data->pixel_format = overlay->pixel_format;
-	win_data->bpp = overlay->bpp;
+	win_data->dma_addr = plane->dma_addr[0];
+	win_data->chroma_dma_addr = plane->dma_addr[1];
+	win_data->pixel_format = plane->pixel_format;
+	win_data->bpp = plane->bpp;
 
-	win_data->crtc_x = overlay->crtc_x;
-	win_data->crtc_y = overlay->crtc_y;
-	win_data->crtc_width = overlay->crtc_width;
-	win_data->crtc_height = overlay->crtc_height;
+	win_data->crtc_x = plane->crtc_x;
+	win_data->crtc_y = plane->crtc_y;
+	win_data->crtc_width = plane->crtc_width;
+	win_data->crtc_height = plane->crtc_height;
 
-	win_data->fb_x = overlay->fb_x;
-	win_data->fb_y = overlay->fb_y;
-	win_data->fb_width = overlay->fb_width;
-	win_data->fb_height = overlay->fb_height;
-	win_data->src_width = overlay->src_width;
-	win_data->src_height = overlay->src_height;
+	win_data->fb_x = plane->fb_x;
+	win_data->fb_y = plane->fb_y;
+	win_data->fb_width = plane->fb_width;
+	win_data->fb_height = plane->fb_height;
+	win_data->src_width = plane->src_width;
+	win_data->src_height = plane->src_height;
 
-	win_data->mode_width = overlay->mode_width;
-	win_data->mode_height = overlay->mode_height;
+	win_data->mode_width = plane->mode_width;
+	win_data->mode_height = plane->mode_height;
 
-	win_data->scan_flags = overlay->scan_flag;
+	win_data->scan_flags = plane->scan_flag;
 }
 
-static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
 	DRM_DEBUG_KMS("win: %d\n", win);
@@ -995,9 +992,9 @@
 	mixer_ctx->win_data[win].enabled = true;
 }
 
-static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 	unsigned long flags;
@@ -1023,9 +1020,9 @@
 	mixer_ctx->win_data[win].enabled = false;
 }
 
-static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
+static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
 {
-	struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+	struct mixer_context *mixer_ctx = crtc->ctx;
 	int err;
 
 	mutex_lock(&mixer_ctx->mixer_mutex);
@@ -1035,7 +1032,7 @@
 	}
 	mutex_unlock(&mixer_ctx->mixer_mutex);
 
-	err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
+	err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
 	if (err < 0) {
 		DRM_DEBUG_KMS("failed to acquire vblank counter\n");
 		return;
@@ -1052,26 +1049,24 @@
 				HZ/20))
 		DRM_DEBUG_KMS("vblank wait timed out.\n");
 
-	drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
+	drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
 }
 
-static void mixer_window_suspend(struct exynos_drm_manager *mgr)
+static void mixer_window_suspend(struct mixer_context *ctx)
 {
-	struct mixer_context *ctx = mgr_to_mixer(mgr);
 	struct hdmi_win_data *win_data;
 	int i;
 
 	for (i = 0; i < MIXER_WIN_NR; i++) {
 		win_data = &ctx->win_data[i];
 		win_data->resume = win_data->enabled;
-		mixer_win_disable(mgr, i);
+		mixer_win_disable(ctx->crtc, i);
 	}
-	mixer_wait_for_vblank(mgr);
+	mixer_wait_for_vblank(ctx->crtc);
 }
 
-static void mixer_window_resume(struct exynos_drm_manager *mgr)
+static void mixer_window_resume(struct mixer_context *ctx)
 {
-	struct mixer_context *ctx = mgr_to_mixer(mgr);
 	struct hdmi_win_data *win_data;
 	int i;
 
@@ -1080,13 +1075,12 @@
 		win_data->enabled = win_data->resume;
 		win_data->resume = false;
 		if (win_data->enabled)
-			mixer_win_commit(mgr, i);
+			mixer_win_commit(ctx->crtc, i);
 	}
 }
 
-static void mixer_poweron(struct exynos_drm_manager *mgr)
+static void mixer_poweron(struct mixer_context *ctx)
 {
-	struct mixer_context *ctx = mgr_to_mixer(mgr);
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -1100,6 +1094,7 @@
 	pm_runtime_get_sync(ctx->dev);
 
 	clk_prepare_enable(res->mixer);
+	clk_prepare_enable(res->hdmi);
 	if (ctx->vp_enabled) {
 		clk_prepare_enable(res->vp);
 		if (ctx->has_sclk)
@@ -1115,12 +1110,11 @@
 	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
 	mixer_win_reset(ctx);
 
-	mixer_window_resume(mgr);
+	mixer_window_resume(ctx);
 }
 
-static void mixer_poweroff(struct exynos_drm_manager *mgr)
+static void mixer_poweroff(struct mixer_context *ctx)
 {
-	struct mixer_context *ctx = mgr_to_mixer(mgr);
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -1131,7 +1125,7 @@
 	mutex_unlock(&ctx->mixer_mutex);
 
 	mixer_stop(ctx);
-	mixer_window_suspend(mgr);
+	mixer_window_suspend(ctx);
 
 	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
@@ -1139,6 +1133,7 @@
 	ctx->powered = false;
 	mutex_unlock(&ctx->mixer_mutex);
 
+	clk_disable_unprepare(res->hdmi);
 	clk_disable_unprepare(res->mixer);
 	if (ctx->vp_enabled) {
 		clk_disable_unprepare(res->vp);
@@ -1149,16 +1144,16 @@
 	pm_runtime_put_sync(ctx->dev);
 }
 
-static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
+static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
 {
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		mixer_poweron(mgr);
+		mixer_poweron(crtc->ctx);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		mixer_poweroff(mgr);
+		mixer_poweroff(crtc->ctx);
 		break;
 	default:
 		DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -1186,7 +1181,7 @@
 	return -EINVAL;
 }
 
-static struct exynos_drm_manager_ops mixer_manager_ops = {
+static struct exynos_drm_crtc_ops mixer_crtc_ops = {
 	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
@@ -1257,24 +1252,31 @@
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	ret = mixer_initialize(&ctx->manager, drm_dev);
+	ret = mixer_initialize(ctx, drm_dev);
 	if (ret)
 		return ret;
 
-	ret = exynos_drm_crtc_create(&ctx->manager);
-	if (ret) {
-		mixer_mgr_remove(&ctx->manager);
-		return ret;
+	ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+				     EXYNOS_DISPLAY_TYPE_HDMI,
+				     &mixer_crtc_ops, ctx);
+	if (IS_ERR(ctx->crtc)) {
+		mixer_ctx_remove(ctx);
+		ret = PTR_ERR(ctx->crtc);
+		goto free_ctx;
 	}
 
 	return 0;
+
+free_ctx:
+	devm_kfree(dev, ctx);
+	return ret;
 }
 
 static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
 	struct mixer_context *ctx = dev_get_drvdata(dev);
 
-	mixer_mgr_remove(&ctx->manager);
+	mixer_ctx_remove(ctx);
 }
 
 static const struct component_ops mixer_component_ops = {
@@ -1297,9 +1299,6 @@
 
 	mutex_init(&ctx->mixer_mutex);
 
-	ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
-	ctx->manager.ops = &mixer_manager_ops;
-
 	if (dev->of_node) {
 		const struct of_device_id *match;
 
@@ -1321,7 +1320,7 @@
 	platform_set_drvdata(pdev, ctx);
 
 	ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
-					ctx->manager.type);
+					EXYNOS_DISPLAY_TYPE_HDMI);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index ddd90dd..2d42ce6 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -593,6 +593,7 @@
 {
 	struct psb_fbdev *fbdev;
 	struct drm_psb_private *dev_priv = dev->dev_private;
+	int ret;
 
 	fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL);
 	if (!fbdev) {
@@ -604,16 +605,29 @@
 
 	drm_fb_helper_prepare(dev, &fbdev->psb_fb_helper, &psb_fb_helper_funcs);
 
-	drm_fb_helper_init(dev, &fbdev->psb_fb_helper, dev_priv->ops->crtcs,
-							INTELFB_CONN_LIMIT);
+	ret = drm_fb_helper_init(dev, &fbdev->psb_fb_helper,
+				 dev_priv->ops->crtcs, INTELFB_CONN_LIMIT);
+	if (ret)
+		goto free;
 
-	drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
+	ret = drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(dev);
 
-	drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
+	ret = drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&fbdev->psb_fb_helper);
+free:
+	kfree(fbdev);
+	return ret;
 }
 
 static void psb_fbdev_fini(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index faf1c0c..fa140e0 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -644,9 +644,6 @@
 	if (mode->clock > 165000)
 		return MODE_CLOCK_HIGH;
 
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-		return MODE_NO_INTERLACE;
-
 	return MODE_OK;
 }
 
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 4e39ab3..74acca9 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -11,6 +11,8 @@
 	select SHMEM
 	select TMPFS
 	select DRM_KMS_HELPER
+	select DRM_PANEL
+	select DRM_MIPI_DSI
 	# i915 depends on ACPI_VIDEO when ACPI is enabled
 	# but for select to work, need to select ACPI_VIDEO's dependencies, ick
 	select BACKLIGHT_LCD_SUPPORT if ACPI
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e4083e4..f019225 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -19,6 +19,7 @@
 
 # GEM code
 i915-y += i915_cmd_parser.o \
+	  i915_gem_batch_pool.o \
 	  i915_gem_context.o \
 	  i915_gem_render_state.o \
 	  i915_gem_debug.o \
@@ -47,6 +48,7 @@
 i915-y += intel_audio.o \
 	  intel_bios.o \
 	  intel_display.o \
+	  intel_fbc.o \
 	  intel_fifo_underrun.o \
 	  intel_frontbuffer.o \
 	  intel_modes.o \
@@ -64,11 +66,12 @@
 	  dvo_ns2501.o \
 	  dvo_sil164.o \
 	  dvo_tfp410.o \
+	  intel_atomic.o \
+	  intel_atomic_plane.o \
 	  intel_crt.o \
 	  intel_ddi.o \
 	  intel_dp.o \
 	  intel_dp_mst.o \
-	  intel_dsi_cmd.o \
 	  intel_dsi.o \
 	  intel_dsi_pll.o \
 	  intel_dsi_panel_vbt.o \
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index 22c992a..806e812 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -152,6 +152,7 @@
 	CMD(  MI_PREDICATE,                     SMI,    F,  1,      S  ),
 	CMD(  MI_TOPOLOGY_FILTER,               SMI,    F,  1,      S  ),
 	CMD(  MI_DISPLAY_FLIP,                  SMI,   !F,  0xFF,   R  ),
+	CMD(  MI_SET_APPID,                     SMI,    F,  1,      S  ),
 	CMD(  MI_SET_CONTEXT,                   SMI,   !F,  0xFF,   R  ),
 	CMD(  MI_URB_CLEAR,                     SMI,   !F,  0xFF,   S  ),
 	CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0x3F,   B,
@@ -210,6 +211,7 @@
 	CMD(  MI_SET_PREDICATE,                 SMI,    F,  1,      S  ),
 	CMD(  MI_RS_CONTROL,                    SMI,    F,  1,      S  ),
 	CMD(  MI_URB_ATOMIC_ALLOC,              SMI,    F,  1,      S  ),
+	CMD(  MI_SET_APPID,                     SMI,    F,  1,      S  ),
 	CMD(  MI_RS_CONTEXT,                    SMI,    F,  1,      S  ),
 	CMD(  MI_LOAD_SCAN_LINES_INCL,          SMI,   !F,  0x3F,   M  ),
 	CMD(  MI_LOAD_SCAN_LINES_EXCL,          SMI,   !F,  0x3F,   R  ),
@@ -229,6 +231,7 @@
 
 static const struct drm_i915_cmd_descriptor video_cmds[] = {
 	CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
+	CMD(  MI_SET_APPID,                     SMI,    F,  1,      S  ),
 	CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0xFF,   B,
 	      .bits = {{
 			.offset = 0,
@@ -272,6 +275,7 @@
 
 static const struct drm_i915_cmd_descriptor vecs_cmds[] = {
 	CMD(  MI_ARB_ON_OFF,                    SMI,    F,  1,      R  ),
+	CMD(  MI_SET_APPID,                     SMI,    F,  1,      S  ),
 	CMD(  MI_STORE_DWORD_IMM,               SMI,   !F,  0xFF,   B,
 	      .bits = {{
 			.offset = 0,
@@ -401,6 +405,7 @@
 #define REG64(addr) (addr), (addr + sizeof(u32))
 
 static const u32 gen7_render_regs[] = {
+	REG64(GPGPU_THREADS_DISPATCHED),
 	REG64(HS_INVOCATION_COUNT),
 	REG64(DS_INVOCATION_COUNT),
 	REG64(IA_VERTICES_COUNT),
@@ -481,13 +486,17 @@
 	u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
 	u32 subclient =
 		(cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;
+	u32 op = (cmd_header & INSTR_26_TO_24_MASK) >> INSTR_26_TO_24_SHIFT;
 
 	if (client == INSTR_MI_CLIENT)
 		return 0x3F;
 	else if (client == INSTR_RC_CLIENT) {
-		if (subclient == INSTR_MEDIA_SUBCLIENT)
-			return 0xFFF;
-		else
+		if (subclient == INSTR_MEDIA_SUBCLIENT) {
+			if (op == 6)
+				return 0xFFFF;
+			else
+				return 0xFFF;
+		} else
 			return 0xFF;
 	}
 
@@ -716,13 +725,13 @@
 	BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count));
 	BUG_ON(!validate_regs_sorted(ring));
 
-	if (hash_empty(ring->cmd_hash)) {
-		ret = init_hash_table(ring, cmd_tables, cmd_table_count);
-		if (ret) {
-			DRM_ERROR("CMD: cmd_parser_init failed!\n");
-			fini_hash_table(ring);
-			return ret;
-		}
+	WARN_ON(!hash_empty(ring->cmd_hash));
+
+	ret = init_hash_table(ring, cmd_tables, cmd_table_count);
+	if (ret) {
+		DRM_ERROR("CMD: cmd_parser_init failed!\n");
+		fini_hash_table(ring);
+		return ret;
 	}
 
 	ring->needs_cmd_parser = true;
@@ -840,6 +849,69 @@
 	return (u32*)addr;
 }
 
+/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
+static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
+		       struct drm_i915_gem_object *src_obj,
+		       u32 batch_start_offset,
+		       u32 batch_len)
+{
+	int ret = 0;
+	int needs_clflush = 0;
+	u32 *src_base, *dest_base = NULL;
+	u32 *src_addr, *dest_addr;
+	u32 offset = batch_start_offset / sizeof(*dest_addr);
+	u32 end = batch_start_offset + batch_len;
+
+	if (end > dest_obj->base.size || end > src_obj->base.size)
+		return ERR_PTR(-E2BIG);
+
+	ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
+	if (ret) {
+		DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
+		return ERR_PTR(ret);
+	}
+
+	src_base = vmap_batch(src_obj);
+	if (!src_base) {
+		DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
+		ret = -ENOMEM;
+		goto unpin_src;
+	}
+
+	src_addr = src_base + offset;
+
+	if (needs_clflush)
+		drm_clflush_virt_range((char *)src_addr, batch_len);
+
+	ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
+	if (ret) {
+		DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n");
+		goto unmap_src;
+	}
+
+	dest_base = vmap_batch(dest_obj);
+	if (!dest_base) {
+		DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
+		ret = -ENOMEM;
+		goto unmap_src;
+	}
+
+	dest_addr = dest_base + offset;
+
+	if (batch_start_offset != 0)
+		memset((u8 *)dest_base, 0, batch_start_offset);
+
+	memcpy(dest_addr, src_addr, batch_len);
+	memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end);
+
+unmap_src:
+	vunmap(src_base);
+unpin_src:
+	i915_gem_object_unpin_pages(src_obj);
+
+	return ret ? ERR_PTR(ret) : dest_base;
+}
+
 /**
  * i915_needs_cmd_parser() - should a given ring use software command parsing?
  * @ring: the ring in question
@@ -956,7 +1028,9 @@
  * i915_parse_cmds() - parse a submitted batch buffer for privilege violations
  * @ring: the ring on which the batch is to execute
  * @batch_obj: the batch buffer in question
+ * @shadow_batch_obj: copy of the batch buffer in question
  * @batch_start_offset: byte offset in the batch at which execution starts
+ * @batch_len: length of the commands in batch_obj
  * @is_master: is the submitting process the drm master?
  *
  * Parses the specified batch buffer looking for privilege violations as
@@ -967,33 +1041,38 @@
  */
 int i915_parse_cmds(struct intel_engine_cs *ring,
 		    struct drm_i915_gem_object *batch_obj,
+		    struct drm_i915_gem_object *shadow_batch_obj,
 		    u32 batch_start_offset,
+		    u32 batch_len,
 		    bool is_master)
 {
 	int ret = 0;
 	u32 *cmd, *batch_base, *batch_end;
 	struct drm_i915_cmd_descriptor default_desc = { 0 };
-	int needs_clflush = 0;
 	bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
 
-	ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush);
+	ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0);
 	if (ret) {
-		DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
-		return ret;
+		DRM_DEBUG_DRIVER("CMD: Failed to pin shadow batch\n");
+		return -1;
 	}
 
-	batch_base = vmap_batch(batch_obj);
-	if (!batch_base) {
-		DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
-		i915_gem_object_unpin_pages(batch_obj);
-		return -ENOMEM;
+	batch_base = copy_batch(shadow_batch_obj, batch_obj,
+				batch_start_offset, batch_len);
+	if (IS_ERR(batch_base)) {
+		DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
+		i915_gem_object_ggtt_unpin(shadow_batch_obj);
+		return PTR_ERR(batch_base);
 	}
 
-	if (needs_clflush)
-		drm_clflush_virt_range((char *)batch_base, batch_obj->base.size);
-
 	cmd = batch_base + (batch_start_offset / sizeof(*cmd));
-	batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));
+
+	/*
+	 * We use the batch length as size because the shadow object is as
+	 * large or larger and copy_batch() will write MI_NOPs to the extra
+	 * space. Parsing should be faster in some cases this way.
+	 */
+	batch_end = cmd + (batch_len / sizeof(*batch_end));
 
 	while (cmd < batch_end) {
 		const struct drm_i915_cmd_descriptor *desc;
@@ -1053,8 +1132,7 @@
 	}
 
 	vunmap(batch_base);
-
-	i915_gem_object_unpin_pages(batch_obj);
+	i915_gem_object_ggtt_unpin(shadow_batch_obj);
 
 	return ret;
 }
@@ -1076,6 +1154,7 @@
 	 *    hardware parsing enabled (so does not allow new use cases).
 	 * 2. Allow access to the MI_PREDICATE_SRC0 and
 	 *    MI_PREDICATE_SRC1 registers.
+	 * 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
 	 */
-	return 2;
+	return 3;
 }
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 779a275..96e811f 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -96,9 +96,7 @@
 
 static const char *get_pin_flag(struct drm_i915_gem_object *obj)
 {
-	if (obj->user_pin_count > 0)
-		return "P";
-	else if (i915_gem_obj_is_pinned(obj))
+	if (i915_gem_obj_is_pinned(obj))
 		return "p";
 	else
 		return " ";
@@ -125,7 +123,7 @@
 	struct i915_vma *vma;
 	int pin_count = 0;
 
-	seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s",
+	seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %x %x %x%s%s%s",
 		   &obj->base,
 		   get_pin_flag(obj),
 		   get_tiling_flag(obj),
@@ -133,9 +131,9 @@
 		   obj->base.size / 1024,
 		   obj->base.read_domains,
 		   obj->base.write_domain,
-		   obj->last_read_seqno,
-		   obj->last_write_seqno,
-		   obj->last_fenced_seqno,
+		   i915_gem_request_get_seqno(obj->last_read_req),
+		   i915_gem_request_get_seqno(obj->last_write_req),
+		   i915_gem_request_get_seqno(obj->last_fenced_req),
 		   i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
 		   obj->dirty ? " dirty" : "",
 		   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
@@ -154,8 +152,9 @@
 			seq_puts(m, " (pp");
 		else
 			seq_puts(m, " (g");
-		seq_printf(m, "gtt offset: %08lx, size: %08lx)",
-			   vma->node.start, vma->node.size);
+		seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
+			   vma->node.start, vma->node.size,
+			   vma->ggtt_view.type);
 	}
 	if (obj->stolen)
 		seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
@@ -168,8 +167,9 @@
 		*t = '\0';
 		seq_printf(m, " (%s mappable)", s);
 	}
-	if (obj->ring != NULL)
-		seq_printf(m, " (%s)", obj->ring->name);
+	if (obj->last_read_req != NULL)
+		seq_printf(m, " (%s)",
+			   i915_gem_request_get_ring(obj->last_read_req)->name);
 	if (obj->frontbuffer_bits)
 		seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits);
 }
@@ -336,7 +336,7 @@
 			if (ppgtt->file_priv != stats->file_priv)
 				continue;
 
-			if (obj->ring) /* XXX per-vma statistic */
+			if (obj->active) /* XXX per-vma statistic */
 				stats->active += obj->base.size;
 			else
 				stats->inactive += obj->base.size;
@@ -346,7 +346,7 @@
 	} else {
 		if (i915_gem_obj_ggtt_bound(obj)) {
 			stats->global += obj->base.size;
-			if (obj->ring)
+			if (obj->active)
 				stats->active += obj->base.size;
 			else
 				stats->inactive += obj->base.size;
@@ -360,6 +360,33 @@
 	return 0;
 }
 
+#define print_file_stats(m, name, stats) \
+	seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \
+		   name, \
+		   stats.count, \
+		   stats.total, \
+		   stats.active, \
+		   stats.inactive, \
+		   stats.global, \
+		   stats.shared, \
+		   stats.unbound)
+
+static void print_batch_pool_stats(struct seq_file *m,
+				   struct drm_i915_private *dev_priv)
+{
+	struct drm_i915_gem_object *obj;
+	struct file_stats stats;
+
+	memset(&stats, 0, sizeof(stats));
+
+	list_for_each_entry(obj,
+			    &dev_priv->mm.batch_pool.cache_list,
+			    batch_pool_list)
+		per_file_stats(0, obj, &stats);
+
+	print_file_stats(m, "batch pool", stats);
+}
+
 #define count_vmas(list, member) do { \
 	list_for_each_entry(vma, list, member) { \
 		size += i915_gem_obj_ggtt_size(vma->obj); \
@@ -442,6 +469,9 @@
 		   dev_priv->gtt.mappable_end - dev_priv->gtt.base.start);
 
 	seq_putc(m, '\n');
+	print_batch_pool_stats(m, dev_priv);
+
+	seq_putc(m, '\n');
 	list_for_each_entry_reverse(file, &dev->filelist, lhead) {
 		struct file_stats stats;
 		struct task_struct *task;
@@ -459,15 +489,7 @@
 		 */
 		rcu_read_lock();
 		task = pid_task(file->pid, PIDTYPE_PID);
-		seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n",
-			   task ? task->comm : "<unknown>",
-			   stats.count,
-			   stats.total,
-			   stats.active,
-			   stats.inactive,
-			   stats.global,
-			   stats.shared,
-			   stats.unbound);
+		print_file_stats(m, task ? task->comm : "<unknown>", stats);
 		rcu_read_unlock();
 	}
 
@@ -543,14 +565,16 @@
 				seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
 					   pipe, plane);
 			}
-			if (work->flip_queued_ring) {
-				seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
-					   work->flip_queued_ring->name,
-					   work->flip_queued_seqno,
+			if (work->flip_queued_req) {
+				struct intel_engine_cs *ring =
+					i915_gem_request_get_ring(work->flip_queued_req);
+
+				seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
+					   ring->name,
+					   i915_gem_request_get_seqno(work->flip_queued_req),
 					   dev_priv->next_seqno,
-					   work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
-					   i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
-							     work->flip_queued_seqno));
+					   ring->get_seqno(ring, true),
+					   i915_gem_request_completed(work->flip_queued_req, true));
 			} else
 				seq_printf(m, "Flip not associated with any ring\n");
 			seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
@@ -582,6 +606,36 @@
 	return 0;
 }
 
+static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj;
+	int count = 0;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	seq_puts(m, "cache:\n");
+	list_for_each_entry(obj,
+			    &dev_priv->mm.batch_pool.cache_list,
+			    batch_pool_list) {
+		seq_puts(m, "   ");
+		describe_obj(m, obj);
+		seq_putc(m, '\n');
+		count++;
+	}
+
+	seq_printf(m, "total: %d\n", count);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
 static int i915_gem_request_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = m->private;
@@ -604,7 +658,7 @@
 		list_for_each_entry(gem_request,
 				    &ring->request_list,
 				    list) {
-			seq_printf(m, "    %d @ %d\n",
+			seq_printf(m, "    %x @ %d\n",
 				   gem_request->seqno,
 				   (int) (jiffies - gem_request->emitted_jiffies));
 		}
@@ -622,7 +676,7 @@
 				 struct intel_engine_cs *ring)
 {
 	if (ring->get_seqno) {
-		seq_printf(m, "Current sequence (%s): %u\n",
+		seq_printf(m, "Current sequence (%s): %x\n",
 			   ring->name, ring->get_seqno(ring, false));
 	}
 }
@@ -1051,7 +1105,7 @@
 		if (ret)
 			goto out;
 
-		gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+		intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 		reqf = I915_READ(GEN6_RPNSWREQ);
 		reqf &= ~GEN6_TURBO_DISABLE;
@@ -1059,7 +1113,7 @@
 			reqf >>= 24;
 		else
 			reqf >>= 25;
-		reqf *= GT_FREQUENCY_MULTIPLIER;
+		reqf = intel_gpu_freq(dev_priv, reqf);
 
 		rpmodectl = I915_READ(GEN6_RP_CONTROL);
 		rpinclimit = I915_READ(GEN6_RP_UP_THRESHOLD);
@@ -1076,9 +1130,9 @@
 			cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
 		else
 			cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
-		cagf *= GT_FREQUENCY_MULTIPLIER;
+		cagf = intel_gpu_freq(dev_priv, cagf);
 
-		gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+		intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 		mutex_unlock(&dev->struct_mutex);
 
 		if (IS_GEN6(dev) || IS_GEN7(dev)) {
@@ -1124,18 +1178,18 @@
 
 		max_freq = (rp_state_cap & 0xff0000) >> 16;
 		seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
-			   max_freq * GT_FREQUENCY_MULTIPLIER);
+			   intel_gpu_freq(dev_priv, max_freq));
 
 		max_freq = (rp_state_cap & 0xff00) >> 8;
 		seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
-			   max_freq * GT_FREQUENCY_MULTIPLIER);
+			   intel_gpu_freq(dev_priv, max_freq));
 
 		max_freq = rp_state_cap & 0xff;
 		seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
-			   max_freq * GT_FREQUENCY_MULTIPLIER);
+			   intel_gpu_freq(dev_priv, max_freq));
 
 		seq_printf(m, "Max overclocked frequency: %dMHz\n",
-			   dev_priv->rps.max_freq * GT_FREQUENCY_MULTIPLIER);
+			   intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
 	} else if (IS_VALLEYVIEW(dev)) {
 		u32 freq_sts;
 
@@ -1145,16 +1199,17 @@
 		seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
 
 		seq_printf(m, "max GPU freq: %d MHz\n",
-			   vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+			   intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
 
 		seq_printf(m, "min GPU freq: %d MHz\n",
-			   vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq));
+			   intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
 
-		seq_printf(m, "efficient (RPe) frequency: %d MHz\n",
-			   vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+		seq_printf(m,
+			   "efficient (RPe) frequency: %d MHz\n",
+			   intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
 
 		seq_printf(m, "current GPU freq: %d MHz\n",
-			   vlv_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
+			   intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
 		mutex_unlock(&dev_priv->rps.hw_lock);
 	} else {
 		seq_puts(m, "no P-state info available\n");
@@ -1165,6 +1220,53 @@
 	return ret;
 }
 
+static int i915_hangcheck_info(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_engine_cs *ring;
+	u64 acthd[I915_NUM_RINGS];
+	u32 seqno[I915_NUM_RINGS];
+	int i;
+
+	if (!i915.enable_hangcheck) {
+		seq_printf(m, "Hangcheck disabled\n");
+		return 0;
+	}
+
+	intel_runtime_pm_get(dev_priv);
+
+	for_each_ring(ring, dev_priv, i) {
+		seqno[i] = ring->get_seqno(ring, false);
+		acthd[i] = intel_ring_get_active_head(ring);
+	}
+
+	intel_runtime_pm_put(dev_priv);
+
+	if (delayed_work_pending(&dev_priv->gpu_error.hangcheck_work)) {
+		seq_printf(m, "Hangcheck active, fires in %dms\n",
+			   jiffies_to_msecs(dev_priv->gpu_error.hangcheck_work.timer.expires -
+					    jiffies));
+	} else
+		seq_printf(m, "Hangcheck inactive\n");
+
+	for_each_ring(ring, dev_priv, i) {
+		seq_printf(m, "%s:\n", ring->name);
+		seq_printf(m, "\tseqno = %x [current %x]\n",
+			   ring->hangcheck.seqno, seqno[i]);
+		seq_printf(m, "\tACTHD = 0x%08llx [current 0x%08llx]\n",
+			   (long long)ring->hangcheck.acthd,
+			   (long long)acthd[i]);
+		seq_printf(m, "\tmax ACTHD = 0x%08llx\n",
+			   (long long)ring->hangcheck.max_acthd);
+		seq_printf(m, "\tscore = %d\n", ring->hangcheck.score);
+		seq_printf(m, "\taction = %d\n", ring->hangcheck.action);
+	}
+
+	return 0;
+}
+
 static int ironlake_drpc_info(struct seq_file *m)
 {
 	struct drm_info_node *node = m->private;
@@ -1234,14 +1336,31 @@
 	return 0;
 }
 
+static int i915_forcewake_domains(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_uncore_forcewake_domain *fw_domain;
+	int i;
+
+	spin_lock_irq(&dev_priv->uncore.lock);
+	for_each_fw_domain(fw_domain, dev_priv, i) {
+		seq_printf(m, "%s.wake_count = %u\n",
+			   intel_uncore_forcewake_domain_to_str(i),
+			   fw_domain->wake_count);
+	}
+	spin_unlock_irq(&dev_priv->uncore.lock);
+
+	return 0;
+}
+
 static int vlv_drpc_info(struct seq_file *m)
 {
-
 	struct drm_info_node *node = m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 rpmodectl1, rcctl1, pw_status;
-	unsigned fw_rendercount = 0, fw_mediacount = 0;
 
 	intel_runtime_pm_get(dev_priv);
 
@@ -1273,22 +1392,11 @@
 	seq_printf(m, "Media RC6 residency since boot: %u\n",
 		   I915_READ(VLV_GT_MEDIA_RC6));
 
-	spin_lock_irq(&dev_priv->uncore.lock);
-	fw_rendercount = dev_priv->uncore.fw_rendercount;
-	fw_mediacount = dev_priv->uncore.fw_mediacount;
-	spin_unlock_irq(&dev_priv->uncore.lock);
-
-	seq_printf(m, "Forcewake Render Count = %u\n", fw_rendercount);
-	seq_printf(m, "Forcewake Media Count = %u\n", fw_mediacount);
-
-
-	return 0;
+	return i915_forcewake_domains(m, NULL);
 }
 
-
 static int gen6_drpc_info(struct seq_file *m)
 {
-
 	struct drm_info_node *node = m->private;
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1302,7 +1410,7 @@
 	intel_runtime_pm_get(dev_priv);
 
 	spin_lock_irq(&dev_priv->uncore.lock);
-	forcewake_count = dev_priv->uncore.forcewake_count;
+	forcewake_count = dev_priv->uncore.fw_domain[FW_DOMAIN_ID_RENDER].wake_count;
 	spin_unlock_irq(&dev_priv->uncore.lock);
 
 	if (forcewake_count) {
@@ -1617,7 +1725,7 @@
 				       GEN6_PCODE_READ_MIN_FREQ_TABLE,
 				       &ia_freq);
 		seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
-			   gpu_freq * GT_FREQUENCY_MULTIPLIER,
+			   intel_gpu_freq(dev_priv, gpu_freq),
 			   ((ia_freq >> 0) & 0xff) * 100,
 			   ((ia_freq >> 8) & 0xff) * 100);
 	}
@@ -1874,7 +1982,7 @@
 	intel_runtime_pm_get(dev_priv);
 
 	for_each_ring(ring, dev_priv, ring_id) {
-		struct intel_ctx_submit_request *head_req = NULL;
+		struct drm_i915_gem_request *head_req = NULL;
 		int count = 0;
 		unsigned long flags;
 
@@ -1907,7 +2015,7 @@
 		list_for_each(cursor, &ring->execlist_queue)
 			count++;
 		head_req = list_first_entry_or_null(&ring->execlist_queue,
-				struct intel_ctx_submit_request, execlist_link);
+				struct drm_i915_gem_request, execlist_link);
 		spin_unlock_irqrestore(&ring->execlist_lock, flags);
 
 		seq_printf(m, "\t%d requests in queue\n", count);
@@ -1930,30 +2038,6 @@
 	return 0;
 }
 
-static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
-{
-	struct drm_info_node *node = m->private;
-	struct drm_device *dev = node->minor->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	unsigned forcewake_count = 0, fw_rendercount = 0, fw_mediacount = 0;
-
-	spin_lock_irq(&dev_priv->uncore.lock);
-	if (IS_VALLEYVIEW(dev)) {
-		fw_rendercount = dev_priv->uncore.fw_rendercount;
-		fw_mediacount = dev_priv->uncore.fw_mediacount;
-	} else
-		forcewake_count = dev_priv->uncore.forcewake_count;
-	spin_unlock_irq(&dev_priv->uncore.lock);
-
-	if (IS_VALLEYVIEW(dev)) {
-		seq_printf(m, "fw_rendercount = %u\n", fw_rendercount);
-		seq_printf(m, "fw_mediacount = %u\n", fw_mediacount);
-	} else
-		seq_printf(m, "forcewake count = %u\n", forcewake_count);
-
-	return 0;
-}
-
 static const char *swizzle_string(unsigned swizzle)
 {
 	switch (swizzle) {
@@ -2155,6 +2239,8 @@
 	struct drm_device *dev = node->minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 psrperf = 0;
+	u32 stat[3];
+	enum pipe pipe;
 	bool enabled = false;
 
 	intel_runtime_pm_get(dev_priv);
@@ -2169,14 +2255,39 @@
 	seq_printf(m, "Re-enable work scheduled: %s\n",
 		   yesno(work_busy(&dev_priv->psr.work.work)));
 
-	enabled = HAS_PSR(dev) &&
-		I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
-	seq_printf(m, "HW Enabled & Active bit: %s\n", yesno(enabled));
+	if (HAS_PSR(dev)) {
+		if (HAS_DDI(dev))
+			enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+		else {
+			for_each_pipe(dev_priv, pipe) {
+				stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
+					VLV_EDP_PSR_CURR_STATE_MASK;
+				if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+				    (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+					enabled = true;
+			}
+		}
+	}
+	seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled));
 
-	if (HAS_PSR(dev))
+	if (!HAS_DDI(dev))
+		for_each_pipe(dev_priv, pipe) {
+			if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+			    (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+				seq_printf(m, " pipe %c", pipe_name(pipe));
+		}
+	seq_puts(m, "\n");
+
+	seq_printf(m, "Link standby: %s\n",
+		   yesno((bool)dev_priv->psr.link_standby));
+
+	/* CHV PSR has no kind of performance counter */
+	if (HAS_PSR(dev) && HAS_DDI(dev)) {
 		psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
 			EDP_PSR_PERF_CNT_MASK;
-	seq_printf(m, "Performance_Counter: %u\n", psrperf);
+
+		seq_printf(m, "Performance_Counter: %u\n", psrperf);
+	}
 	mutex_unlock(&dev_priv->psr.lock);
 
 	intel_runtime_pm_put(dev_priv);
@@ -2319,10 +2430,18 @@
 		return "AUDIO";
 	case POWER_DOMAIN_PLLS:
 		return "PLLS";
+	case POWER_DOMAIN_AUX_A:
+		return "AUX_A";
+	case POWER_DOMAIN_AUX_B:
+		return "AUX_B";
+	case POWER_DOMAIN_AUX_C:
+		return "AUX_C";
+	case POWER_DOMAIN_AUX_D:
+		return "AUX_D";
 	case POWER_DOMAIN_INIT:
 		return "INIT";
 	default:
-		WARN_ON(1);
+		MISSING_CASE(domain);
 		return "?";
 	}
 }
@@ -2547,7 +2666,8 @@
 
 		seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n",
 			   crtc->base.base.id, pipe_name(crtc->pipe),
-			   yesno(crtc->active), crtc->config.pipe_src_w, crtc->config.pipe_src_h);
+			   yesno(crtc->active), crtc->config->pipe_src_w,
+			   crtc->config->pipe_src_h);
 		if (crtc->active) {
 			intel_crtc_info(m, crtc);
 
@@ -2718,6 +2838,9 @@
 	enum pipe pipe;
 	int plane;
 
+	if (INTEL_INFO(dev)->gen < 9)
+		return 0;
+
 	drm_modeset_lock_all(dev);
 
 	ddb = &dev_priv->wm.skl_hw.ddb;
@@ -2830,7 +2953,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 	char buf[PIPE_CRC_BUFFER_LEN];
-	int head, tail, n_entries, n;
+	int n_entries;
 	ssize_t bytes_read;
 
 	/*
@@ -2862,36 +2985,39 @@
 	}
 
 	/* We now have one or more entries to read */
-	head = pipe_crc->head;
-	tail = pipe_crc->tail;
-	n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR),
-			count / PIPE_CRC_LINE_LEN);
-	spin_unlock_irq(&pipe_crc->lock);
+	n_entries = count / PIPE_CRC_LINE_LEN;
 
 	bytes_read = 0;
-	n = 0;
-	do {
-		struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail];
+	while (n_entries > 0) {
+		struct intel_pipe_crc_entry *entry =
+			&pipe_crc->entries[pipe_crc->tail];
 		int ret;
 
+		if (CIRC_CNT(pipe_crc->head, pipe_crc->tail,
+			     INTEL_PIPE_CRC_ENTRIES_NR) < 1)
+			break;
+
+		BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
+		pipe_crc->tail = (pipe_crc->tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
+
 		bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN,
 				       "%8u %8x %8x %8x %8x %8x\n",
 				       entry->frame, entry->crc[0],
 				       entry->crc[1], entry->crc[2],
 				       entry->crc[3], entry->crc[4]);
 
-		ret = copy_to_user(user_buf + n * PIPE_CRC_LINE_LEN,
-				   buf, PIPE_CRC_LINE_LEN);
+		spin_unlock_irq(&pipe_crc->lock);
+
+		ret = copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN);
 		if (ret == PIPE_CRC_LINE_LEN)
 			return -EFAULT;
 
-		BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
-		tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
-		n++;
-	} while (--n_entries);
+		user_buf += PIPE_CRC_LINE_LEN;
+		n_entries--;
 
-	spin_lock_irq(&pipe_crc->lock);
-	pipe_crc->tail = tail;
+		spin_lock_irq(&pipe_crc->lock);
+	}
+
 	spin_unlock_irq(&pipe_crc->lock);
 
 	return bytes_read;
@@ -3072,6 +3198,12 @@
 		*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV;
 		need_stable_symbols = true;
 		break;
+	case INTEL_PIPE_CRC_SOURCE_DP_D:
+		if (!IS_CHERRYVIEW(dev))
+			return -EINVAL;
+		*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_VLV;
+		need_stable_symbols = true;
+		break;
 	case INTEL_PIPE_CRC_SOURCE_NONE:
 		*val = 0;
 		break;
@@ -3092,11 +3224,19 @@
 		uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
 		tmp |= DC_BALANCE_RESET_VLV;
-		if (pipe == PIPE_A)
+		switch (pipe) {
+		case PIPE_A:
 			tmp |= PIPE_A_SCRAMBLE_RESET;
-		else
+			break;
+		case PIPE_B:
 			tmp |= PIPE_B_SCRAMBLE_RESET;
-
+			break;
+		case PIPE_C:
+			tmp |= PIPE_C_SCRAMBLE_RESET;
+			break;
+		default:
+			return -EINVAL;
+		}
 		I915_WRITE(PORT_DFT2_G4X, tmp);
 	}
 
@@ -3185,10 +3325,19 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
-	if (pipe == PIPE_A)
+	switch (pipe) {
+	case PIPE_A:
 		tmp &= ~PIPE_A_SCRAMBLE_RESET;
-	else
+		break;
+	case PIPE_B:
 		tmp &= ~PIPE_B_SCRAMBLE_RESET;
+		break;
+	case PIPE_C:
+		tmp &= ~PIPE_C_SCRAMBLE_RESET;
+		break;
+	default:
+		return;
+	}
 	if (!(tmp & PIPE_SCRAMBLE_RESET_MASK))
 		tmp &= ~DC_BALANCE_RESET_VLV;
 	I915_WRITE(PORT_DFT2_G4X, tmp);
@@ -3252,9 +3401,9 @@
 	 * relevant on hsw with pipe A when using the always-on power well
 	 * routing.
 	 */
-	if (crtc->config.cpu_transcoder == TRANSCODER_EDP &&
-	    !crtc->config.pch_pfit.enabled) {
-		crtc->config.pch_pfit.force_thru = true;
+	if (crtc->config->cpu_transcoder == TRANSCODER_EDP &&
+	    !crtc->config->pch_pfit.enabled) {
+		crtc->config->pch_pfit.force_thru = true;
 
 		intel_display_power_get(dev_priv,
 					POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
@@ -3278,8 +3427,8 @@
 	 * relevant on hsw with pipe A when using the always-on power well
 	 * routing.
 	 */
-	if (crtc->config.pch_pfit.force_thru) {
-		crtc->config.pch_pfit.force_thru = false;
+	if (crtc->config->pch_pfit.force_thru) {
+		crtc->config->pch_pfit.force_thru = false;
 
 		dev_priv->display.crtc_disable(&crtc->base);
 		dev_priv->display.crtc_enable(&crtc->base);
@@ -3359,13 +3508,15 @@
 
 	/* none -> real source transition */
 	if (source) {
+		struct intel_pipe_crc_entry *entries;
+
 		DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n",
 				 pipe_name(pipe), pipe_crc_source_name(source));
 
-		pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) *
-					    INTEL_PIPE_CRC_ENTRIES_NR,
-					    GFP_KERNEL);
-		if (!pipe_crc->entries)
+		entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
+				  sizeof(pipe_crc->entries[0]),
+				  GFP_KERNEL);
+		if (!entries)
 			return -ENOMEM;
 
 		/*
@@ -3377,6 +3528,8 @@
 		hsw_disable_ips(crtc);
 
 		spin_lock_irq(&pipe_crc->lock);
+		kfree(pipe_crc->entries);
+		pipe_crc->entries = entries;
 		pipe_crc->head = 0;
 		pipe_crc->tail = 0;
 		spin_unlock_irq(&pipe_crc->lock);
@@ -3404,6 +3557,8 @@
 		spin_lock_irq(&pipe_crc->lock);
 		entries = pipe_crc->entries;
 		pipe_crc->entries = NULL;
+		pipe_crc->head = 0;
+		pipe_crc->tail = 0;
 		spin_unlock_irq(&pipe_crc->lock);
 
 		kfree(entries);
@@ -3826,6 +3981,17 @@
 	struct drm_device *dev = data;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	/*
+	 * There is no safeguard against this debugfs entry colliding
+	 * with the hangcheck calling same i915_handle_error() in
+	 * parallel, causing an explosion. For now we assume that the
+	 * test harness is responsible enough not to inject gpu hangs
+	 * while it is writing to 'i915_wedged'
+	 */
+
+	if (i915_reset_in_progress(&dev_priv->gpu_error))
+		return -EAGAIN;
+
 	intel_runtime_pm_get(dev_priv);
 
 	i915_handle_error(dev, val,
@@ -4012,10 +4178,7 @@
 	if (ret)
 		return ret;
 
-	if (IS_VALLEYVIEW(dev))
-		*val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
-	else
-		*val = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+	*val = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
 	return 0;
@@ -4044,12 +4207,12 @@
 	 * Turbo will still be enabled, but won't go above the set value.
 	 */
 	if (IS_VALLEYVIEW(dev)) {
-		val = vlv_freq_opcode(dev_priv, val);
+		val = intel_freq_opcode(dev_priv, val);
 
 		hw_max = dev_priv->rps.max_freq;
 		hw_min = dev_priv->rps.min_freq;
 	} else {
-		do_div(val, GT_FREQUENCY_MULTIPLIER);
+		val = intel_freq_opcode(dev_priv, val);
 
 		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 		hw_max = dev_priv->rps.max_freq;
@@ -4093,10 +4256,7 @@
 	if (ret)
 		return ret;
 
-	if (IS_VALLEYVIEW(dev))
-		*val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
-	else
-		*val = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+	*val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
 	return 0;
@@ -4125,12 +4285,12 @@
 	 * Turbo will still be enabled, but won't go below the set value.
 	 */
 	if (IS_VALLEYVIEW(dev)) {
-		val = vlv_freq_opcode(dev_priv, val);
+		val = intel_freq_opcode(dev_priv, val);
 
 		hw_max = dev_priv->rps.max_freq;
 		hw_min = dev_priv->rps.min_freq;
 	} else {
-		do_div(val, GT_FREQUENCY_MULTIPLIER);
+		val = intel_freq_opcode(dev_priv, val);
 
 		rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 		hw_max = dev_priv->rps.max_freq;
@@ -4222,7 +4382,8 @@
 	if (INTEL_INFO(dev)->gen < 6)
 		return 0;
 
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_runtime_pm_get(dev_priv);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	return 0;
 }
@@ -4235,7 +4396,8 @@
 	if (INTEL_INFO(dev)->gen < 6)
 		return 0;
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+	intel_runtime_pm_put(dev_priv);
 
 	return 0;
 }
@@ -4296,7 +4458,9 @@
 	{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
 	{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
 	{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
+	{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
 	{"i915_frequency_info", i915_frequency_info, 0},
+	{"i915_hangcheck_info", i915_hangcheck_info, 0},
 	{"i915_drpc_info", i915_drpc_info, 0},
 	{"i915_emon_status", i915_emon_status, 0},
 	{"i915_ring_freq_table", i915_ring_freq_table, 0},
@@ -4308,7 +4472,7 @@
 	{"i915_context_status", i915_context_status, 0},
 	{"i915_dump_lrc", i915_dump_lrc, 0},
 	{"i915_execlists", i915_execlists, 0},
-	{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
+	{"i915_forcewake_domains", i915_forcewake_domains, 0},
 	{"i915_swizzle_info", i915_swizzle_info, 0},
 	{"i915_ppgtt_info", i915_ppgtt_info, 0},
 	{"i915_llc", i915_llc, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 26b3199..1a46787 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -92,6 +92,9 @@
 	case I915_PARAM_HAS_VEBOX:
 		value = intel_ring_initialized(&dev_priv->ring[VECS]);
 		break;
+	case I915_PARAM_HAS_BSD2:
+		value = intel_ring_initialized(&dev_priv->ring[VCS2]);
+		break;
 	case I915_PARAM_HAS_RELAXED_FENCING:
 		value = 1;
 		break;
@@ -143,6 +146,9 @@
 	case I915_PARAM_HAS_COHERENT_PHYS_GTT:
 		value = 1;
 		break;
+	case I915_PARAM_MMAP_VERSION:
+		value = 1;
+		break;
 	default:
 		DRM_DEBUG("Unknown parameter %d\n", param->param);
 		return -EINVAL;
@@ -598,6 +604,17 @@
 			info->num_pipes = 0;
 		}
 	}
+
+	if (IS_CHERRYVIEW(dev)) {
+		u32 fuse, mask_eu;
+
+		fuse = I915_READ(CHV_FUSE_GT);
+		mask_eu = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
+				  CHV_FGT_EU_DIS_SS0_R1_MASK |
+				  CHV_FGT_EU_DIS_SS1_R0_MASK |
+				  CHV_FGT_EU_DIS_SS1_R1_MASK);
+		info->eu_total = 16 - hweight32(mask_eu);
+	}
 }
 
 /**
@@ -773,6 +790,14 @@
 		goto out_freewq;
 	}
 
+	dev_priv->gpu_error.hangcheck_wq =
+		alloc_ordered_workqueue("i915-hangcheck", 0);
+	if (dev_priv->gpu_error.hangcheck_wq == NULL) {
+		DRM_ERROR("Failed to create our hangcheck workqueue.\n");
+		ret = -ENOMEM;
+		goto out_freedpwq;
+	}
+
 	intel_irq_init(dev_priv);
 	intel_uncore_sanitize(dev);
 
@@ -847,6 +872,8 @@
 	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 	pm_qos_remove_request(&dev_priv->pm_qos);
+	destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
+out_freedpwq:
 	destroy_workqueue(dev_priv->dp_wq);
 out_freewq:
 	destroy_workqueue(dev_priv->wq);
@@ -917,8 +944,7 @@
 	}
 
 	/* Free error state after interrupts are fully disabled. */
-	del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
-	cancel_work_sync(&dev_priv->gpu_error.work);
+	cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
 	i915_destroy_error_state(dev);
 
 	if (dev->pdev->msi_enabled)
@@ -932,6 +958,7 @@
 
 		mutex_lock(&dev->struct_mutex);
 		i915_gem_cleanup_ringbuffer(dev);
+		i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
 		i915_gem_context_fini(dev);
 		mutex_unlock(&dev->struct_mutex);
 		i915_gem_cleanup_stolen(dev);
@@ -942,6 +969,7 @@
 
 	destroy_workqueue(dev_priv->dp_wq);
 	destroy_workqueue(dev_priv->wq);
+	destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
 	pm_qos_remove_request(&dev_priv->pm_qos);
 
 	i915_global_gtt_cleanup(dev);
@@ -1008,6 +1036,13 @@
 	kfree(file_priv);
 }
 
+static int
+i915_gem_reject_pin_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file)
+{
+	return -ENODEV;
+}
+
 const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH),
@@ -1029,8 +1064,8 @@
 	DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
 	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED),
 	DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
-	DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
-	DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
 	DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
@@ -1059,6 +1094,8 @@
 	DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 
 int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 489b220..8039cec 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -835,6 +835,8 @@
 		return ret;
 	}
 
+	intel_overlay_reset(dev_priv);
+
 	/* Ok, now get things going again... */
 
 	/*
@@ -1290,7 +1292,9 @@
 	err = vlv_allow_gt_wake(dev_priv, false);
 	if (err)
 		goto err2;
-	vlv_save_gunit_s0ix_state(dev_priv);
+
+	if (!IS_CHERRYVIEW(dev_priv->dev))
+		vlv_save_gunit_s0ix_state(dev_priv);
 
 	err = vlv_force_gfx_clock(dev_priv, false);
 	if (err)
@@ -1321,7 +1325,8 @@
 	 */
 	ret = vlv_force_gfx_clock(dev_priv, true);
 
-	vlv_restore_gunit_s0ix_state(dev_priv);
+	if (!IS_CHERRYVIEW(dev_priv->dev))
+		vlv_restore_gunit_s0ix_state(dev_priv);
 
 	err = vlv_allow_gt_wake(dev_priv, true);
 	if (!ret)
@@ -1354,8 +1359,6 @@
 	if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
 		return -ENODEV;
 
-	assert_force_wake_inactive(dev_priv);
-
 	DRM_DEBUG_KMS("Suspending device\n");
 
 	/*
@@ -1393,7 +1396,8 @@
 		return ret;
 	}
 
-	del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+	cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
+	intel_uncore_forcewake_reset(dev, false);
 	dev_priv->pm.suspended = true;
 
 	/*
@@ -1421,6 +1425,8 @@
 		intel_opregion_notify_adapter(dev, PCI_D3hot);
 	}
 
+	assert_forcewakes_inactive(dev_priv);
+
 	DRM_DEBUG_KMS("Device suspended\n");
 	return 0;
 }
@@ -1631,6 +1637,14 @@
 #endif
 	}
 
+	/*
+	 * FIXME: Note that we're lying to the DRM core here so that we can get access
+	 * to the atomic ioctl and the atomic properties.  Only plane operations on
+	 * a single CRTC will actually work.
+	 */
+	if (i915.nuclear_pageflip)
+		driver.driver_features |= DRIVER_ATOMIC;
+
 	return drm_pci_init(&driver, &i915_pci_driver);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 24cc36a..f2a825e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -55,10 +55,51 @@
 
 #define DRIVER_NAME		"i915"
 #define DRIVER_DESC		"Intel Graphics"
-#define DRIVER_DATE		"20141121"
+#define DRIVER_DATE		"20150130"
 
 #undef WARN_ON
-#define WARN_ON(x)		WARN(x, "WARN_ON(" #x ")")
+/* Many gcc seem to no see through this and fall over :( */
+#if 0
+#define WARN_ON(x) ({ \
+	bool __i915_warn_cond = (x); \
+	if (__builtin_constant_p(__i915_warn_cond)) \
+		BUILD_BUG_ON(__i915_warn_cond); \
+	WARN(__i915_warn_cond, "WARN_ON(" #x ")"); })
+#else
+#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
+#endif
+
+#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
+			     (long) (x), __func__);
+
+/* 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
+ * which may not necessarily be a user visible problem.  This will either
+ * WARN() or DRM_ERROR() depending on the verbose_checks moduleparam, to
+ * enable distros and users to tailor their preferred amount of i915 abrt
+ * spam.
+ */
+#define I915_STATE_WARN(condition, format...) ({			\
+	int __ret_warn_on = !!(condition);				\
+	if (unlikely(__ret_warn_on)) {					\
+		if (i915.verbose_state_checks)				\
+			WARN(1, format);				\
+		else 							\
+			DRM_ERROR(format);				\
+	}								\
+	unlikely(__ret_warn_on);					\
+})
+
+#define I915_STATE_WARN_ON(condition) ({				\
+	int __ret_warn_on = !!(condition);				\
+	if (unlikely(__ret_warn_on)) {					\
+		if (i915.verbose_state_checks)				\
+			WARN(1, "WARN_ON(" #condition ")\n");		\
+		else 							\
+			DRM_ERROR("WARN_ON(" #condition ")\n");		\
+	}								\
+	unlikely(__ret_warn_on);					\
+})
 
 enum pipe {
 	INVALID_PIPE = -1,
@@ -143,6 +184,10 @@
 	POWER_DOMAIN_VGA,
 	POWER_DOMAIN_AUDIO,
 	POWER_DOMAIN_PLLS,
+	POWER_DOMAIN_AUX_A,
+	POWER_DOMAIN_AUX_B,
+	POWER_DOMAIN_AUX_C,
+	POWER_DOMAIN_AUX_D,
 	POWER_DOMAIN_INIT,
 
 	POWER_DOMAIN_NUM,
@@ -458,8 +503,8 @@
 
 struct intel_connector;
 struct intel_encoder;
-struct intel_crtc_config;
-struct intel_plane_config;
+struct intel_crtc_state;
+struct intel_initial_plane_config;
 struct intel_crtc;
 struct intel_limit;
 struct dpll;
@@ -497,10 +542,11 @@
 	/* Returns the active state of the crtc, and if the crtc is active,
 	 * fills out the pipe-config with the hw state. */
 	bool (*get_pipe_config)(struct intel_crtc *,
-				struct intel_crtc_config *);
-	void (*get_plane_config)(struct intel_crtc *,
-				 struct intel_plane_config *);
-	int (*crtc_compute_clock)(struct intel_crtc *crtc);
+				struct intel_crtc_state *);
+	void (*get_initial_plane_config)(struct intel_crtc *,
+					 struct intel_initial_plane_config *);
+	int (*crtc_compute_clock)(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state);
 	void (*crtc_enable)(struct drm_crtc *crtc);
 	void (*crtc_disable)(struct drm_crtc *crtc);
 	void (*off)(struct drm_crtc *crtc);
@@ -533,11 +579,28 @@
 	void (*enable_backlight)(struct intel_connector *connector);
 };
 
+enum forcewake_domain_id {
+	FW_DOMAIN_ID_RENDER = 0,
+	FW_DOMAIN_ID_BLITTER,
+	FW_DOMAIN_ID_MEDIA,
+
+	FW_DOMAIN_ID_COUNT
+};
+
+enum forcewake_domains {
+	FORCEWAKE_RENDER = (1 << FW_DOMAIN_ID_RENDER),
+	FORCEWAKE_BLITTER = (1 << FW_DOMAIN_ID_BLITTER),
+	FORCEWAKE_MEDIA	= (1 << FW_DOMAIN_ID_MEDIA),
+	FORCEWAKE_ALL = (FORCEWAKE_RENDER |
+			 FORCEWAKE_BLITTER |
+			 FORCEWAKE_MEDIA)
+};
+
 struct intel_uncore_funcs {
 	void (*force_wake_get)(struct drm_i915_private *dev_priv,
-							int fw_engine);
+							enum forcewake_domains domains);
 	void (*force_wake_put)(struct drm_i915_private *dev_priv,
-							int fw_engine);
+							enum forcewake_domains domains);
 
 	uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
 	uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
@@ -560,15 +623,32 @@
 	struct intel_uncore_funcs funcs;
 
 	unsigned fifo_count;
-	unsigned forcewake_count;
+	enum forcewake_domains fw_domains;
 
-	unsigned fw_rendercount;
-	unsigned fw_mediacount;
-	unsigned fw_blittercount;
-
-	struct timer_list force_wake_timer;
+	struct intel_uncore_forcewake_domain {
+		struct drm_i915_private *i915;
+		enum forcewake_domain_id id;
+		unsigned wake_count;
+		struct timer_list timer;
+		u32 reg_set;
+		u32 val_set;
+		u32 val_clear;
+		u32 reg_ack;
+		u32 reg_post;
+		u32 val_reset;
+	} fw_domain[FW_DOMAIN_ID_COUNT];
 };
 
+/* Iterate over initialised fw domains */
+#define for_each_fw_domain_mask(domain__, mask__, dev_priv__, i__) \
+	for ((i__) = 0, (domain__) = &(dev_priv__)->uncore.fw_domain[0]; \
+	     (i__) < FW_DOMAIN_ID_COUNT; \
+	     (i__)++, (domain__) = &(dev_priv__)->uncore.fw_domain[i__]) \
+		if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
+
+#define for_each_fw_domain(domain__, dev_priv__, i__) \
+	for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
+
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
 	func(is_mobile) sep \
 	func(is_i85x) sep \
@@ -612,6 +692,7 @@
 	int trans_offsets[I915_MAX_TRANSCODERS];
 	int palette_offsets[I915_MAX_PIPES];
 	int cursor_offsets[I915_MAX_PIPES];
+	unsigned int eu_total;
 };
 
 #undef DEFINE_FLAG
@@ -637,6 +718,11 @@
 	/* Time when this context was last blamed for a GPU reset */
 	unsigned long guilty_ts;
 
+	/* If the contexts causes a second GPU hang within this time,
+	 * it is permanently banned from submitting any more work.
+	 */
+	unsigned long ban_period_seconds;
+
 	/* This context is banned to submit more work */
 	bool banned;
 };
@@ -679,7 +765,7 @@
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
-		int unpin_count;
+		int pin_count;
 	} engine[I915_NUM_RINGS];
 
 	struct list_head link;
@@ -730,11 +816,33 @@
 	} no_fbc_reason;
 };
 
-struct i915_drrs {
-	struct intel_connector *connector;
+/**
+ * HIGH_RR is the highest eDP panel refresh rate read from EDID
+ * LOW_RR is the lowest eDP panel refresh rate found from EDID
+ * parsing for same resolution.
+ */
+enum drrs_refresh_rate_type {
+	DRRS_HIGH_RR,
+	DRRS_LOW_RR,
+	DRRS_MAX_RR, /* RR count */
+};
+
+enum drrs_support_type {
+	DRRS_NOT_SUPPORTED = 0,
+	STATIC_DRRS_SUPPORT = 1,
+	SEAMLESS_DRRS_SUPPORT = 2
 };
 
 struct intel_dp;
+struct i915_drrs {
+	struct mutex mutex;
+	struct delayed_work work;
+	struct intel_dp *dp;
+	unsigned busy_frontbuffer_bits;
+	enum drrs_refresh_rate_type refresh_rate_type;
+	enum drrs_support_type type;
+};
+
 struct i915_psr {
 	struct mutex lock;
 	bool sink_support;
@@ -743,6 +851,7 @@
 	bool active;
 	struct delayed_work work;
 	unsigned busy_frontbuffer_bits;
+	bool link_standby;
 };
 
 enum intel_pch {
@@ -1130,6 +1239,11 @@
 	int which_slice;
 };
 
+struct i915_gem_batch_pool {
+	struct drm_device *dev;
+	struct list_head cache_list;
+};
+
 struct i915_gem_mm {
 	/** Memory allocator for GTT stolen memory */
 	struct drm_mm stolen;
@@ -1143,6 +1257,13 @@
 	 */
 	struct list_head unbound_list;
 
+	/*
+	 * A pool of objects to use as shadow copies of client batch buffers
+	 * when the command parser is enabled. Prevents the client from
+	 * modifying the batch contents after software parsing.
+	 */
+	struct i915_gem_batch_pool batch_pool;
+
 	/** Usable portion of the GTT for GEM */
 	unsigned long stolen_base; /* limited to low memory (32-bit) */
 
@@ -1224,14 +1345,13 @@
 	/* Hang gpu twice in this window and your context gets banned */
 #define DRM_I915_CTX_BAN_PERIOD DIV_ROUND_UP(8*DRM_I915_HANGCHECK_PERIOD, 1000)
 
-	struct timer_list hangcheck_timer;
+	struct workqueue_struct *hangcheck_wq;
+	struct delayed_work hangcheck_work;
 
 	/* For reset and error_state handling. */
 	spinlock_t lock;
 	/* Protected by the above dev->gpu_error.lock. */
 	struct drm_i915_error_state *first_error;
-	struct work_struct work;
-
 
 	unsigned long missed_irq_rings;
 
@@ -1301,10 +1421,11 @@
 	uint8_t supports_dp:1;
 };
 
-enum drrs_support_type {
-	DRRS_NOT_SUPPORTED = 0,
-	STATIC_DRRS_SUPPORT = 1,
-	SEAMLESS_DRRS_SUPPORT = 2
+enum psr_lines_to_wait {
+	PSR_0_LINES_TO_WAIT = 0,
+	PSR_1_LINE_TO_WAIT,
+	PSR_4_LINES_TO_WAIT,
+	PSR_8_LINES_TO_WAIT
 };
 
 struct intel_vbt_data {
@@ -1336,6 +1457,15 @@
 	struct edp_power_seq edp_pps;
 
 	struct {
+		bool full_link;
+		bool require_aux_wakeup;
+		int idle_frames;
+		enum psr_lines_to_wait lines_to_wait;
+		int tp1_wakeup_time;
+		int tp2_tp3_wakeup_time;
+	} psr;
+
+	struct {
 		u16 pwm_freq_hz;
 		bool present;
 		bool active_low_pwm;
@@ -1773,6 +1903,8 @@
 		void (*stop_ring)(struct intel_engine_cs *ring);
 	} gt;
 
+	uint32_t request_uniq;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -1861,6 +1993,8 @@
 	/** Used in execbuf to temporarily hold a ref */
 	struct list_head obj_exec_link;
 
+	struct list_head batch_pool_list;
+
 	/**
 	 * This is set if the object is on the active lists (has pending
 	 * rendering and so a non-zero seqno), and is not set if it i s on
@@ -1920,6 +2054,7 @@
 	 */
 	unsigned long gt_ro:1;
 	unsigned int cache_level:3;
+	unsigned int cache_dirty:1;
 
 	unsigned int has_dma_mapping:1;
 
@@ -1932,13 +2067,11 @@
 	void *dma_buf_vmapping;
 	int vmapping_count;
 
-	struct intel_engine_cs *ring;
-
 	/** Breadcrumb of last rendering to the buffer. */
-	uint32_t last_read_seqno;
-	uint32_t last_write_seqno;
+	struct drm_i915_gem_request *last_read_req;
+	struct drm_i915_gem_request *last_write_req;
 	/** Breadcrumb of last fenced GPU access to the buffer. */
-	uint32_t last_fenced_seqno;
+	struct drm_i915_gem_request *last_fenced_req;
 
 	/** Current tiling stride for the object, if it's tiled. */
 	uint32_t stride;
@@ -1949,10 +2082,6 @@
 	/** Record of address bit 17 of each page at last unbind. */
 	unsigned long *bit_17;
 
-	/** User space pin count and filp owning the pin */
-	unsigned long user_pin_count;
-	struct drm_file *pin_filp;
-
 	union {
 		/** for phy allocated objects */
 		struct drm_dma_handle *phys_handle;
@@ -1981,11 +2110,14 @@
  * The request queue allows us to note sequence numbers that have been emitted
  * and may be associated with active buffers to be retired.
  *
- * By keeping this list, we can avoid having to do questionable
- * sequence-number comparisons on buffer last_rendering_seqnos, and associate
- * an emission time with seqnos for tracking how far ahead of the GPU we are.
+ * By keeping this list, we can avoid having to do questionable sequence
+ * number comparisons on buffer last_read|write_seqno. It also allows an
+ * emission time to be associated with the request for tracking how far ahead
+ * of the GPU the submission is.
  */
 struct drm_i915_gem_request {
+	struct kref ref;
+
 	/** On Which ring this request was generated */
 	struct intel_engine_cs *ring;
 
@@ -1995,7 +2127,14 @@
 	/** Position in the ringbuffer of the start of the request */
 	u32 head;
 
-	/** Position in the ringbuffer of the end of the request */
+	/**
+	 * Position in the ringbuffer of the start of the postfix.
+	 * This is required to calculate the maximum available ringbuffer
+	 * space without overwriting the postfix.
+	 */
+	 u32 postfix;
+
+	/** Position in the ringbuffer of the end of the whole request */
 	u32 tail;
 
 	/** Context related to this request */
@@ -2013,8 +2152,75 @@
 	struct drm_i915_file_private *file_priv;
 	/** file_priv list entry for this request */
 	struct list_head client_list;
+
+	uint32_t uniq;
+
+	/**
+	 * The ELSP only accepts two elements at a time, so we queue
+	 * context/tail pairs on a given queue (ring->execlist_queue) until the
+	 * hardware is available. The queue serves a double purpose: we also use
+	 * it to keep track of the up to 2 contexts currently in the hardware
+	 * (usually one in execution and the other queued up by the GPU): We
+	 * only remove elements from the head of the queue when the hardware
+	 * informs us that an element has been completed.
+	 *
+	 * All accesses to the queue are mediated by a spinlock
+	 * (ring->execlist_lock).
+	 */
+
+	/** Execlist link in the submission queue.*/
+	struct list_head execlist_link;
+
+	/** Execlists no. of times this request has been sent to the ELSP */
+	int elsp_submitted;
+
 };
 
+void i915_gem_request_free(struct kref *req_ref);
+
+static inline uint32_t
+i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
+{
+	return req ? req->seqno : 0;
+}
+
+static inline struct intel_engine_cs *
+i915_gem_request_get_ring(struct drm_i915_gem_request *req)
+{
+	return req ? req->ring : NULL;
+}
+
+static inline void
+i915_gem_request_reference(struct drm_i915_gem_request *req)
+{
+	kref_get(&req->ref);
+}
+
+static inline void
+i915_gem_request_unreference(struct drm_i915_gem_request *req)
+{
+	WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
+	kref_put(&req->ref, i915_gem_request_free);
+}
+
+static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
+					   struct drm_i915_gem_request *src)
+{
+	if (src)
+		i915_gem_request_reference(src);
+
+	if (*pdst)
+		i915_gem_request_unreference(*pdst);
+
+	*pdst = src;
+}
+
+/*
+ * XXX: i915_gem_request_completed should be here but currently needs the
+ * definition of i915_seqno_passed() which is below. It will be moved in
+ * a later patch when the call to i915_seqno_passed() is obsoleted...
+ */
+
 struct drm_i915_file_private {
 	struct drm_i915_private *dev_priv;
 	struct drm_file *file;
@@ -2247,7 +2453,9 @@
 
 #define HAS_DDI(dev)		(INTEL_INFO(dev)->has_ddi)
 #define HAS_FPGA_DBG_UNCLAIMED(dev)	(INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev)		(IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+				 IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
+				 IS_SKYLAKE(dev))
 #define HAS_RUNTIME_PM(dev)	(IS_GEN6(dev) || IS_HASWELL(dev) || \
 				 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
@@ -2317,6 +2525,8 @@
 	bool disable_vtd_wa;
 	int use_mmio_flip;
 	bool mmio_debug;
+	bool verbose_state_checks;
+	bool nuclear_pageflip;
 };
 extern struct i915_params i915 __read_mostly;
 
@@ -2361,6 +2571,12 @@
 extern void intel_uncore_check_errors(struct drm_device *dev);
 extern void intel_uncore_fini(struct drm_device *dev);
 extern void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore);
+const char *intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id);
+void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
+				enum forcewake_domains domains);
+void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+				enum forcewake_domains domains);
+void assert_forcewakes_inactive(struct drm_i915_private *dev_priv);
 
 void
 i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
@@ -2417,10 +2633,6 @@
 			struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
-int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
-		       struct drm_file *file_priv);
-int i915_gem_unpin_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,
@@ -2465,10 +2677,23 @@
 #define PIN_GLOBAL 0x4
 #define PIN_OFFSET_BIAS 0x8
 #define PIN_OFFSET_MASK (~4095)
+int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
+					  struct i915_address_space *vm,
+					  uint32_t alignment,
+					  uint64_t flags,
+					  const struct i915_ggtt_view *view);
+static inline
 int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
 				     struct i915_address_space *vm,
 				     uint32_t alignment,
-				     uint64_t flags);
+				     uint64_t flags)
+{
+	return i915_gem_object_pin_view(obj, vm, alignment, flags,
+						&i915_ggtt_view_normal);
+}
+
+int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
+		  u32 flags);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
 void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
@@ -2517,6 +2742,18 @@
 	return (int32_t)(seq1 - seq2) >= 0;
 }
 
+static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
+					      bool lazy_coherency)
+{
+	u32 seqno;
+
+	BUG_ON(req == NULL);
+
+	seqno = req->ring->get_seqno(req->ring, lazy_coherency);
+
+	return i915_seqno_passed(seqno, req->seqno);
+}
+
 int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
 int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
 int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
@@ -2532,7 +2769,7 @@
 void i915_gem_retire_requests_ring(struct intel_engine_cs *ring);
 int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
 				      bool interruptible);
-int __must_check i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno);
+int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req);
 
 static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
 {
@@ -2575,17 +2812,15 @@
 int __must_check i915_gem_suspend(struct drm_device *dev);
 int __i915_add_request(struct intel_engine_cs *ring,
 		       struct drm_file *file,
-		       struct drm_i915_gem_object *batch_obj,
-		       u32 *seqno);
-#define i915_add_request(ring, seqno) \
-	__i915_add_request(ring, NULL, NULL, seqno)
-int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
+		       struct drm_i915_gem_object *batch_obj);
+#define i915_add_request(ring) \
+	__i915_add_request(ring, NULL, NULL)
+int __i915_wait_request(struct drm_i915_gem_request *req,
 			unsigned reset_counter,
 			bool interruptible,
 			s64 *timeout,
 			struct drm_i915_file_private *file_priv);
-int __must_check i915_wait_seqno(struct intel_engine_cs *ring,
-				 uint32_t seqno);
+int __must_check i915_wait_request(struct drm_i915_gem_request *req);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int __must_check
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@ -2619,18 +2854,51 @@
 
 void i915_gem_restore_fences(struct drm_device *dev);
 
+unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
+				       struct i915_address_space *vm,
+				       enum i915_ggtt_view_type view);
+static inline
 unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
-				  struct i915_address_space *vm);
+				  struct i915_address_space *vm)
+{
+	return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
+}
 bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
+bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
+			     struct i915_address_space *vm,
+			     enum i915_ggtt_view_type view);
+static inline
 bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-			struct i915_address_space *vm);
+			struct i915_address_space *vm)
+{
+	return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
+}
+
 unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
 				struct i915_address_space *vm);
+struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
+					  struct i915_address_space *vm,
+					  const struct i915_ggtt_view *view);
+static inline
 struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-				     struct i915_address_space *vm);
+				     struct i915_address_space *vm)
+{
+	return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
+}
+
+struct i915_vma *
+i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
+				       struct i915_address_space *vm,
+				       const struct i915_ggtt_view *view);
+
+static inline
 struct i915_vma *
 i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-				  struct i915_address_space *vm);
+				  struct i915_address_space *vm)
+{
+	return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
+						&i915_ggtt_view_normal);
+}
 
 struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
 static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
@@ -2727,6 +2995,10 @@
 				  struct drm_file *file);
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file);
+int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv);
+int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv);
 
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
@@ -2812,6 +3084,13 @@
 void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
 const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
 
+/* i915_gem_batch_pool.c */
+void i915_gem_batch_pool_init(struct drm_device *dev,
+			      struct i915_gem_batch_pool *pool);
+void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
+struct drm_i915_gem_object*
+i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
+
 /* i915_cmd_parser.c */
 int i915_cmd_parser_get_version(void);
 int i915_cmd_parser_init_ring(struct intel_engine_cs *ring);
@@ -2819,7 +3098,9 @@
 bool i915_needs_cmd_parser(struct intel_engine_cs *ring);
 int i915_parse_cmds(struct intel_engine_cs *ring,
 		    struct drm_i915_gem_object *batch_obj,
+		    struct drm_i915_gem_object *shadow_batch_obj,
 		    u32 batch_start_offset,
+		    u32 batch_len,
 		    bool is_master);
 
 /* i915_suspend.c */
@@ -2899,9 +3180,6 @@
 					 bool force_restore);
 extern void i915_redisable_vga(struct drm_device *dev);
 extern void i915_redisable_vga_power_on(struct drm_device *dev);
-extern bool intel_fbc_enabled(struct drm_device *dev);
-extern void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
-extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
 extern void intel_init_pch_refclk(struct drm_device *dev);
 extern void gen6_set_rps(struct drm_device *dev, u8 val);
@@ -2930,20 +3208,12 @@
 					    struct drm_device *dev,
 					    struct intel_display_error_state *error);
 
-/* On SNB platform, before reading ring registers forcewake bit
- * must be set to prevent GT core from power down and stale values being
- * returned.
- */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine);
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
-void assert_force_wake_inactive(struct drm_i915_private *dev_priv);
-
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val);
 
 /* intel_sideband.c */
-u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr);
-void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr);
+void vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val);
 u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr);
 u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
@@ -2964,15 +3234,8 @@
 u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 
-int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val);
-int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val);
-
-#define FORCEWAKE_RENDER	(1 << 0)
-#define FORCEWAKE_MEDIA		(1 << 1)
-#define FORCEWAKE_BLITTER	(1 << 2)
-#define FORCEWAKE_ALL		(FORCEWAKE_RENDER | FORCEWAKE_MEDIA | \
-					FORCEWAKE_BLITTER)
-
+int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
+int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
 
 #define I915_READ8(reg)		dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true)
 #define I915_WRITE8(reg, val)	dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true)
@@ -3077,4 +3340,11 @@
 	}
 }
 
+static inline void i915_trace_irq_get(struct intel_engine_cs *ring,
+				      struct drm_i915_gem_request *req)
+{
+	if (ring->trace_irq_req == NULL && ring->irq_get(ring))
+		i915_gem_request_assign(&ring->trace_irq_req, req);
+}
+
 #endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5f61482..c26d36c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -39,8 +39,7 @@
 #include <linux/dma-buf.h>
 
 static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
-static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
-						   bool force);
+static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
 static __must_check int
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
 			       bool readonly);
@@ -153,12 +152,6 @@
 	return 0;
 }
 
-static inline bool
-i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
-{
-	return i915_gem_obj_bound_any(obj) && !obj->active;
-}
-
 int
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file)
@@ -1157,19 +1150,18 @@
 }
 
 /*
- * Compare seqno against outstanding lazy request. Emit a request if they are
- * equal.
+ * Compare arbitrary request against outstanding lazy request. Emit on match.
  */
 int
-i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno)
+i915_gem_check_olr(struct drm_i915_gem_request *req)
 {
 	int ret;
 
-	BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+	WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
 
 	ret = 0;
-	if (seqno == ring->outstanding_lazy_seqno)
-		ret = i915_add_request(ring, NULL);
+	if (req == req->ring->outstanding_lazy_request)
+		ret = i915_add_request(req->ring);
 
 	return ret;
 }
@@ -1194,10 +1186,9 @@
 }
 
 /**
- * __i915_wait_seqno - wait until execution of seqno has finished
- * @ring: the ring expected to report seqno
- * @seqno: duh!
- * @reset_counter: reset sequence associated with the given seqno
+ * __i915_wait_request - wait until execution of request has finished
+ * @req: duh!
+ * @reset_counter: reset sequence associated with the given request
  * @interruptible: do an interruptible wait (normally yes)
  * @timeout: in - how long to wait (NULL forever); out - how much time remaining
  *
@@ -1208,15 +1199,16 @@
  * reset_counter _must_ be read before, and an appropriate smp_rmb must be
  * inserted.
  *
- * Returns 0 if the seqno was found within the alloted time. Else returns the
+ * Returns 0 if the request was found within the alloted time. Else returns the
  * errno with remaining time filled in timeout argument.
  */
-int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
+int __i915_wait_request(struct drm_i915_gem_request *req,
 			unsigned reset_counter,
 			bool interruptible,
 			s64 *timeout,
 			struct drm_i915_file_private *file_priv)
 {
+	struct intel_engine_cs *ring = i915_gem_request_get_ring(req);
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	const bool irq_test_in_progress =
@@ -1228,7 +1220,7 @@
 
 	WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled");
 
-	if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
+	if (i915_gem_request_completed(req, true))
 		return 0;
 
 	timeout_expire = timeout ?
@@ -1246,7 +1238,7 @@
 		return -ENODEV;
 
 	/* Record current time in case interrupted by signal, or wedged */
-	trace_i915_gem_request_wait_begin(ring, seqno);
+	trace_i915_gem_request_wait_begin(req);
 	before = ktime_get_raw_ns();
 	for (;;) {
 		struct timer_list timer;
@@ -1265,7 +1257,7 @@
 			break;
 		}
 
-		if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) {
+		if (i915_gem_request_completed(req, false)) {
 			ret = 0;
 			break;
 		}
@@ -1297,7 +1289,7 @@
 		}
 	}
 	now = ktime_get_raw_ns();
-	trace_i915_gem_request_wait_end(ring, seqno);
+	trace_i915_gem_request_wait_end(req);
 
 	if (!irq_test_in_progress)
 		ring->irq_put(ring);
@@ -1324,32 +1316,40 @@
 }
 
 /**
- * Waits for a sequence number to be signaled, and cleans up the
+ * Waits for a request to be signaled, and cleans up the
  * request and object lists appropriately for that event.
  */
 int
-i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno)
+i915_wait_request(struct drm_i915_gem_request *req)
 {
-	struct drm_device *dev = ring->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	bool interruptible = dev_priv->mm.interruptible;
+	struct drm_device *dev;
+	struct drm_i915_private *dev_priv;
+	bool interruptible;
 	unsigned reset_counter;
 	int ret;
 
+	BUG_ON(req == NULL);
+
+	dev = req->ring->dev;
+	dev_priv = dev->dev_private;
+	interruptible = dev_priv->mm.interruptible;
+
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
-	BUG_ON(seqno == 0);
 
 	ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible);
 	if (ret)
 		return ret;
 
-	ret = i915_gem_check_olr(ring, seqno);
+	ret = i915_gem_check_olr(req);
 	if (ret)
 		return ret;
 
 	reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
-	return __i915_wait_seqno(ring, seqno, reset_counter, interruptible,
-				 NULL, NULL);
+	i915_gem_request_reference(req);
+	ret = __i915_wait_request(req, reset_counter,
+				  interruptible, NULL, NULL);
+	i915_gem_request_unreference(req);
+	return ret;
 }
 
 static int
@@ -1361,11 +1361,11 @@
 	/* Manually manage the write flush as we may have not yet
 	 * retired the buffer.
 	 *
-	 * Note that the last_write_seqno is always the earlier of
-	 * the two (read/write) seqno, so if we haved successfully waited,
+	 * Note that the last_write_req is always the earlier of
+	 * the two (read/write) requests, so if we haved successfully waited,
 	 * we know we have passed the last write.
 	 */
-	obj->last_write_seqno = 0;
+	i915_gem_request_assign(&obj->last_write_req, NULL);
 
 	return 0;
 }
@@ -1378,15 +1378,14 @@
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
 			       bool readonly)
 {
-	struct intel_engine_cs *ring = obj->ring;
-	u32 seqno;
+	struct drm_i915_gem_request *req;
 	int ret;
 
-	seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
-	if (seqno == 0)
+	req = readonly ? obj->last_write_req : obj->last_read_req;
+	if (!req)
 		return 0;
 
-	ret = i915_wait_seqno(ring, seqno);
+	ret = i915_wait_request(req);
 	if (ret)
 		return ret;
 
@@ -1401,33 +1400,33 @@
 					    struct drm_i915_file_private *file_priv,
 					    bool readonly)
 {
+	struct drm_i915_gem_request *req;
 	struct drm_device *dev = obj->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_engine_cs *ring = obj->ring;
 	unsigned reset_counter;
-	u32 seqno;
 	int ret;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 	BUG_ON(!dev_priv->mm.interruptible);
 
-	seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
-	if (seqno == 0)
+	req = readonly ? obj->last_write_req : obj->last_read_req;
+	if (!req)
 		return 0;
 
 	ret = i915_gem_check_wedge(&dev_priv->gpu_error, true);
 	if (ret)
 		return ret;
 
-	ret = i915_gem_check_olr(ring, seqno);
+	ret = i915_gem_check_olr(req);
 	if (ret)
 		return ret;
 
 	reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+	i915_gem_request_reference(req);
 	mutex_unlock(&dev->struct_mutex);
-	ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL,
-				file_priv);
+	ret = __i915_wait_request(req, reset_counter, true, NULL, file_priv);
 	mutex_lock(&dev->struct_mutex);
+	i915_gem_request_unreference(req);
 	if (ret)
 		return ret;
 
@@ -1481,18 +1480,10 @@
 	if (ret)
 		goto unref;
 
-	if (read_domains & I915_GEM_DOMAIN_GTT) {
+	if (read_domains & I915_GEM_DOMAIN_GTT)
 		ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
-
-		/* Silently promote "you're not bound, there was nothing to do"
-		 * to success, since the client was just asking us to
-		 * make sure everything was done.
-		 */
-		if (ret == -EINVAL)
-			ret = 0;
-	} else {
+	else
 		ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
-	}
 
 unref:
 	drm_gem_object_unreference(&obj->base);
@@ -1524,7 +1515,7 @@
 
 	/* Pinned buffers may be scanout, so flush the cache */
 	if (obj->pin_display)
-		i915_gem_object_flush_cpu_write_domain(obj, true);
+		i915_gem_object_flush_cpu_write_domain(obj);
 
 	drm_gem_object_unreference(&obj->base);
 unlock:
@@ -1557,6 +1548,12 @@
 	struct drm_gem_object *obj;
 	unsigned long addr;
 
+	if (args->flags & ~(I915_MMAP_WC))
+		return -EINVAL;
+
+	if (args->flags & I915_MMAP_WC && !cpu_has_pat)
+		return -ENODEV;
+
 	obj = drm_gem_object_lookup(dev, file, args->handle);
 	if (obj == NULL)
 		return -ENOENT;
@@ -1572,6 +1569,19 @@
 	addr = vm_mmap(obj->filp, 0, args->size,
 		       PROT_READ | PROT_WRITE, MAP_SHARED,
 		       args->offset);
+	if (args->flags & I915_MMAP_WC) {
+		struct mm_struct *mm = current->mm;
+		struct vm_area_struct *vma;
+
+		down_write(&mm->mmap_sem);
+		vma = find_vma(mm, addr);
+		if (vma)
+			vma->vm_page_prot =
+				pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+		else
+			addr = -ENOMEM;
+		up_write(&mm->mmap_sem);
+	}
 	drm_gem_object_unreference_unlocked(obj);
 	if (IS_ERR((void *)addr))
 		return addr;
@@ -2256,14 +2266,18 @@
 i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
 			       struct intel_engine_cs *ring)
 {
-	u32 seqno = intel_ring_get_seqno(ring);
+	struct drm_i915_gem_request *req;
+	struct intel_engine_cs *old_ring;
 
 	BUG_ON(ring == NULL);
-	if (obj->ring != ring && obj->last_write_seqno) {
-		/* Keep the seqno relative to the current ring */
-		obj->last_write_seqno = seqno;
+
+	req = intel_ring_get_request(ring);
+	old_ring = i915_gem_request_get_ring(obj->last_read_req);
+
+	if (old_ring != ring && obj->last_write_req) {
+		/* Keep the request relative to the current ring */
+		i915_gem_request_assign(&obj->last_write_req, req);
 	}
-	obj->ring = ring;
 
 	/* Add a reference if we're newly entering the active list. */
 	if (!obj->active) {
@@ -2273,7 +2287,7 @@
 
 	list_move_tail(&obj->ring_list, &ring->active_list);
 
-	obj->last_read_seqno = seqno;
+	i915_gem_request_assign(&obj->last_read_req, req);
 }
 
 void i915_vma_move_to_active(struct i915_vma *vma,
@@ -2286,29 +2300,25 @@
 static void
 i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
 {
-	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-	struct i915_address_space *vm;
 	struct i915_vma *vma;
 
 	BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
 	BUG_ON(!obj->active);
 
-	list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
-		vma = i915_gem_obj_to_vma(obj, vm);
-		if (vma && !list_empty(&vma->mm_list))
-			list_move_tail(&vma->mm_list, &vm->inactive_list);
+	list_for_each_entry(vma, &obj->vma_list, vma_link) {
+		if (!list_empty(&vma->mm_list))
+			list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
 	}
 
 	intel_fb_obj_flush(obj, true);
 
 	list_del_init(&obj->ring_list);
-	obj->ring = NULL;
 
-	obj->last_read_seqno = 0;
-	obj->last_write_seqno = 0;
+	i915_gem_request_assign(&obj->last_read_req, NULL);
+	i915_gem_request_assign(&obj->last_write_req, NULL);
 	obj->base.write_domain = 0;
 
-	obj->last_fenced_seqno = 0;
+	i915_gem_request_assign(&obj->last_fenced_req, NULL);
 
 	obj->active = 0;
 	drm_gem_object_unreference(&obj->base);
@@ -2319,13 +2329,10 @@
 static void
 i915_gem_object_retire(struct drm_i915_gem_object *obj)
 {
-	struct intel_engine_cs *ring = obj->ring;
-
-	if (ring == NULL)
+	if (obj->last_read_req == NULL)
 		return;
 
-	if (i915_seqno_passed(ring->get_seqno(ring, true),
-			      obj->last_read_seqno))
+	if (i915_gem_request_completed(obj->last_read_req, true))
 		i915_gem_object_move_to_inactive(obj);
 }
 
@@ -2401,22 +2408,20 @@
 
 int __i915_add_request(struct intel_engine_cs *ring,
 		       struct drm_file *file,
-		       struct drm_i915_gem_object *obj,
-		       u32 *out_seqno)
+		       struct drm_i915_gem_object *obj)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
 	struct intel_ringbuffer *ringbuf;
-	u32 request_ring_position, request_start;
+	u32 request_start;
 	int ret;
 
-	request = ring->preallocated_lazy_request;
+	request = ring->outstanding_lazy_request;
 	if (WARN_ON(request == NULL))
 		return -ENOMEM;
 
 	if (i915.enable_execlists) {
-		struct intel_context *ctx = request->ctx;
-		ringbuf = ctx->engine[ring->id].ringbuf;
+		ringbuf = request->ctx->engine[ring->id].ringbuf;
 	} else
 		ringbuf = ring->buffer;
 
@@ -2429,7 +2434,7 @@
 	 * what.
 	 */
 	if (i915.enable_execlists) {
-		ret = logical_ring_flush_all_caches(ringbuf);
+		ret = logical_ring_flush_all_caches(ringbuf, request->ctx);
 		if (ret)
 			return ret;
 	} else {
@@ -2443,10 +2448,10 @@
 	 * GPU processing the request, we never over-estimate the
 	 * position of the head.
 	 */
-	request_ring_position = intel_ring_get_tail(ringbuf);
+	request->postfix = intel_ring_get_tail(ringbuf);
 
 	if (i915.enable_execlists) {
-		ret = ring->emit_request(ringbuf);
+		ret = ring->emit_request(ringbuf, request);
 		if (ret)
 			return ret;
 	} else {
@@ -2455,10 +2460,8 @@
 			return ret;
 	}
 
-	request->seqno = intel_ring_get_seqno(ring);
-	request->ring = ring;
 	request->head = request_start;
-	request->tail = request_ring_position;
+	request->tail = intel_ring_get_tail(ringbuf);
 
 	/* Whilst this request exists, batch_obj will be on the
 	 * active_list, and so will hold the active reference. Only when this
@@ -2491,9 +2494,8 @@
 		spin_unlock(&file_priv->mm.lock);
 	}
 
-	trace_i915_gem_request_add(ring, request->seqno);
-	ring->outstanding_lazy_seqno = 0;
-	ring->preallocated_lazy_request = NULL;
+	trace_i915_gem_request_add(request);
+	ring->outstanding_lazy_request = NULL;
 
 	i915_queue_hangcheck(ring->dev);
 
@@ -2503,8 +2505,6 @@
 			   round_jiffies_up_relative(HZ));
 	intel_mark_busy(dev_priv->dev);
 
-	if (out_seqno)
-		*out_seqno = request->seqno;
 	return 0;
 }
 
@@ -2532,7 +2532,8 @@
 	if (ctx->hang_stats.banned)
 		return true;
 
-	if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
+	if (ctx->hang_stats.ban_period_seconds &&
+	    elapsed <= ctx->hang_stats.ban_period_seconds) {
 		if (!i915_gem_context_is_default(ctx)) {
 			DRM_DEBUG("context hanging too fast, banning!\n");
 			return true;
@@ -2568,33 +2569,39 @@
 
 static void i915_gem_free_request(struct drm_i915_gem_request *request)
 {
-	struct intel_context *ctx = request->ctx;
-
 	list_del(&request->list);
 	i915_gem_request_remove_from_client(request);
 
+	i915_gem_request_unreference(request);
+}
+
+void i915_gem_request_free(struct kref *req_ref)
+{
+	struct drm_i915_gem_request *req = container_of(req_ref,
+						 typeof(*req), ref);
+	struct intel_context *ctx = req->ctx;
+
 	if (ctx) {
 		if (i915.enable_execlists) {
-			struct intel_engine_cs *ring = request->ring;
+			struct intel_engine_cs *ring = req->ring;
 
 			if (ctx != ring->default_context)
 				intel_lr_context_unpin(ring, ctx);
 		}
+
 		i915_gem_context_unreference(ctx);
 	}
-	kfree(request);
+
+	kfree(req);
 }
 
 struct drm_i915_gem_request *
 i915_gem_find_active_request(struct intel_engine_cs *ring)
 {
 	struct drm_i915_gem_request *request;
-	u32 completed_seqno;
-
-	completed_seqno = ring->get_seqno(ring, false);
 
 	list_for_each_entry(request, &ring->request_list, list) {
-		if (i915_seqno_passed(completed_seqno, request->seqno))
+		if (i915_gem_request_completed(request, false))
 			continue;
 
 		return request;
@@ -2641,13 +2648,17 @@
 	 * pinned in place.
 	 */
 	while (!list_empty(&ring->execlist_queue)) {
-		struct intel_ctx_submit_request *submit_req;
+		struct drm_i915_gem_request *submit_req;
 
 		submit_req = list_first_entry(&ring->execlist_queue,
-				struct intel_ctx_submit_request,
+				struct drm_i915_gem_request,
 				execlist_link);
 		list_del(&submit_req->execlist_link);
 		intel_runtime_pm_put(dev_priv);
+
+		if (submit_req->ctx != ring->default_context)
+			intel_lr_context_unpin(ring, submit_req->ctx);
+
 		i915_gem_context_unreference(submit_req->ctx);
 		kfree(submit_req);
 	}
@@ -2669,10 +2680,8 @@
 		i915_gem_free_request(request);
 	}
 
-	/* These may not have been flush before the reset, do so now */
-	kfree(ring->preallocated_lazy_request);
-	ring->preallocated_lazy_request = NULL;
-	ring->outstanding_lazy_seqno = 0;
+	/* This may not have been flushed before the reset, so clean it now */
+	i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
 }
 
 void i915_gem_restore_fences(struct drm_device *dev)
@@ -2724,15 +2733,11 @@
 void
 i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 {
-	uint32_t seqno;
-
 	if (list_empty(&ring->request_list))
 		return;
 
 	WARN_ON(i915_verify_lists(ring->dev));
 
-	seqno = ring->get_seqno(ring, true);
-
 	/* Move any buffers on the active list that are no longer referenced
 	 * by the ringbuffer to the flushing/inactive lists as appropriate,
 	 * before we free the context associated with the requests.
@@ -2744,7 +2749,7 @@
 				      struct drm_i915_gem_object,
 				      ring_list);
 
-		if (!i915_seqno_passed(seqno, obj->last_read_seqno))
+		if (!i915_gem_request_completed(obj->last_read_req, true))
 			break;
 
 		i915_gem_object_move_to_inactive(obj);
@@ -2759,10 +2764,10 @@
 					   struct drm_i915_gem_request,
 					   list);
 
-		if (!i915_seqno_passed(seqno, request->seqno))
+		if (!i915_gem_request_completed(request, true))
 			break;
 
-		trace_i915_gem_request_retire(ring, request->seqno);
+		trace_i915_gem_request_retire(request);
 
 		/* This is one of the few common intersection points
 		 * between legacy ringbuffer submission and execlists:
@@ -2780,15 +2785,15 @@
 		 * of tail of the request to update the last known position
 		 * of the GPU head.
 		 */
-		ringbuf->last_retired_head = request->tail;
+		ringbuf->last_retired_head = request->postfix;
 
 		i915_gem_free_request(request);
 	}
 
-	if (unlikely(ring->trace_irq_seqno &&
-		     i915_seqno_passed(seqno, ring->trace_irq_seqno))) {
+	if (unlikely(ring->trace_irq_req &&
+		     i915_gem_request_completed(ring->trace_irq_req, true))) {
 		ring->irq_put(ring);
-		ring->trace_irq_seqno = 0;
+		i915_gem_request_assign(&ring->trace_irq_req, NULL);
 	}
 
 	WARN_ON(i915_verify_lists(ring->dev));
@@ -2860,14 +2865,17 @@
 static int
 i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
 {
+	struct intel_engine_cs *ring;
 	int ret;
 
 	if (obj->active) {
-		ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno);
+		ring = i915_gem_request_get_ring(obj->last_read_req);
+
+		ret = i915_gem_check_olr(obj->last_read_req);
 		if (ret)
 			return ret;
 
-		i915_gem_retire_requests_ring(obj->ring);
+		i915_gem_retire_requests_ring(ring);
 	}
 
 	return 0;
@@ -2901,9 +2909,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_wait *args = data;
 	struct drm_i915_gem_object *obj;
-	struct intel_engine_cs *ring = NULL;
+	struct drm_i915_gem_request *req;
 	unsigned reset_counter;
-	u32 seqno = 0;
 	int ret = 0;
 
 	if (args->flags != 0)
@@ -2924,13 +2931,10 @@
 	if (ret)
 		goto out;
 
-	if (obj->active) {
-		seqno = obj->last_read_seqno;
-		ring = obj->ring;
-	}
+	if (!obj->active || !obj->last_read_req)
+		goto out;
 
-	if (seqno == 0)
-		 goto out;
+	req = obj->last_read_req;
 
 	/* Do this after OLR check to make sure we make forward progress polling
 	 * on this IOCTL with a timeout <=0 (like busy ioctl)
@@ -2942,10 +2946,15 @@
 
 	drm_gem_object_unreference(&obj->base);
 	reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+	i915_gem_request_reference(req);
 	mutex_unlock(&dev->struct_mutex);
 
-	return __i915_wait_seqno(ring, seqno, reset_counter, true,
-				 &args->timeout_ns, file->driver_priv);
+	ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns,
+				  file->driver_priv);
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_request_unreference(req);
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
 
 out:
 	drm_gem_object_unreference(&obj->base);
@@ -2969,10 +2978,12 @@
 i915_gem_object_sync(struct drm_i915_gem_object *obj,
 		     struct intel_engine_cs *to)
 {
-	struct intel_engine_cs *from = obj->ring;
+	struct intel_engine_cs *from;
 	u32 seqno;
 	int ret, idx;
 
+	from = i915_gem_request_get_ring(obj->last_read_req);
+
 	if (from == NULL || to == from)
 		return 0;
 
@@ -2981,24 +2992,25 @@
 
 	idx = intel_ring_sync_index(from, to);
 
-	seqno = obj->last_read_seqno;
+	seqno = i915_gem_request_get_seqno(obj->last_read_req);
 	/* Optimization: Avoid semaphore sync when we are sure we already
 	 * waited for an object with higher seqno */
 	if (seqno <= from->semaphore.sync_seqno[idx])
 		return 0;
 
-	ret = i915_gem_check_olr(obj->ring, seqno);
+	ret = i915_gem_check_olr(obj->last_read_req);
 	if (ret)
 		return ret;
 
-	trace_i915_gem_ring_sync_to(from, to, seqno);
+	trace_i915_gem_ring_sync_to(from, to, obj->last_read_req);
 	ret = to->semaphore.sync_to(to, from, seqno);
 	if (!ret)
-		/* We use last_read_seqno because sync_to()
+		/* We use last_read_req because sync_to()
 		 * might have just caused seqno wrap under
 		 * the radar.
 		 */
-		from->semaphore.sync_seqno[idx] = obj->last_read_seqno;
+		from->semaphore.sync_seqno[idx] =
+				i915_gem_request_get_seqno(obj->last_read_req);
 
 	return ret;
 }
@@ -3054,10 +3066,8 @@
 	 * cause memory corruption through use-after-free.
 	 */
 
-	/* Throw away the active reference before moving to the unbound list */
-	i915_gem_object_retire(obj);
-
-	if (i915_is_ggtt(vma->vm)) {
+	if (i915_is_ggtt(vma->vm) &&
+	    vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
 		i915_gem_object_finish_gtt(obj);
 
 		/* release the fence reg _after_ flushing */
@@ -3071,8 +3081,15 @@
 	vma->unbind_vma(vma);
 
 	list_del_init(&vma->mm_list);
-	if (i915_is_ggtt(vma->vm))
-		obj->map_and_fenceable = false;
+	if (i915_is_ggtt(vma->vm)) {
+		if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
+			obj->map_and_fenceable = false;
+		} else if (vma->ggtt_view.pages) {
+			sg_free_table(vma->ggtt_view.pages);
+			kfree(vma->ggtt_view.pages);
+			vma->ggtt_view.pages = NULL;
+		}
+	}
 
 	drm_mm_remove_node(&vma->node);
 	i915_gem_vma_destroy(vma);
@@ -3080,6 +3097,10 @@
 	/* Since the unbound list is global, only move to that list if
 	 * no more VMAs exist. */
 	if (list_empty(&obj->vma_list)) {
+		/* Throw away the active reference before
+		 * moving to the unbound list. */
+		i915_gem_object_retire(obj);
+
 		i915_gem_gtt_finish_object(obj);
 		list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
 	}
@@ -3270,17 +3291,12 @@
 	     "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
 	     obj->stride, obj->tiling_mode);
 
-	switch (INTEL_INFO(dev)->gen) {
-	case 9:
-	case 8:
-	case 7:
-	case 6:
-	case 5:
-	case 4: i965_write_fence_reg(dev, reg, obj); break;
-	case 3: i915_write_fence_reg(dev, reg, obj); break;
-	case 2: i830_write_fence_reg(dev, reg, obj); break;
-	default: BUG();
-	}
+	if (IS_GEN2(dev))
+		i830_write_fence_reg(dev, reg, obj);
+	else if (IS_GEN3(dev))
+		i915_write_fence_reg(dev, reg, obj);
+	else if (INTEL_INFO(dev)->gen >= 4)
+		i965_write_fence_reg(dev, reg, obj);
 
 	/* And similarly be paranoid that no direct access to this region
 	 * is reordered to before the fence is installed.
@@ -3319,12 +3335,12 @@
 static int
 i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
 {
-	if (obj->last_fenced_seqno) {
-		int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
+	if (obj->last_fenced_req) {
+		int ret = i915_wait_request(obj->last_fenced_req);
 		if (ret)
 			return ret;
 
-		obj->last_fenced_seqno = 0;
+		i915_gem_request_assign(&obj->last_fenced_req, NULL);
 	}
 
 	return 0;
@@ -3497,7 +3513,8 @@
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
 			   struct i915_address_space *vm,
 			   unsigned alignment,
-			   uint64_t flags)
+			   uint64_t flags,
+			   const struct i915_ggtt_view *view)
 {
 	struct drm_device *dev = obj->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3547,7 +3564,7 @@
 
 	i915_gem_object_pin_pages(obj);
 
-	vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
+	vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
 	if (IS_ERR(vma))
 		goto err_unpin;
 
@@ -3577,15 +3594,19 @@
 	if (ret)
 		goto err_remove_node;
 
+	trace_i915_vma_bind(vma, flags);
+	ret = i915_vma_bind(vma, obj->cache_level,
+			    flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
+	if (ret)
+		goto err_finish_gtt;
+
 	list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
 	list_add_tail(&vma->mm_list, &vm->inactive_list);
 
-	trace_i915_vma_bind(vma, flags);
-	vma->bind_vma(vma, obj->cache_level,
-		      flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
-
 	return vma;
 
+err_finish_gtt:
+	i915_gem_gtt_finish_object(obj);
 err_remove_node:
 	drm_mm_remove_node(&vma->node);
 err_free_vma:
@@ -3622,11 +3643,14 @@
 	 * snooping behaviour occurs naturally as the result of our domain
 	 * tracking.
 	 */
-	if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level))
+	if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) {
+		obj->cache_dirty = true;
 		return false;
+	}
 
 	trace_i915_gem_object_clflush(obj);
 	drm_clflush_sg(obj->pages);
+	obj->cache_dirty = false;
 
 	return true;
 }
@@ -3662,15 +3686,14 @@
 
 /** Flushes the CPU write domain for the object if it's dirty. */
 static void
-i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
-				       bool force)
+i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
 {
 	uint32_t old_write_domain;
 
 	if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
 		return;
 
-	if (i915_gem_clflush_object(obj, force))
+	if (i915_gem_clflush_object(obj, obj->pin_display))
 		i915_gem_chipset_flush(obj->base.dev);
 
 	old_write_domain = obj->base.write_domain;
@@ -3692,15 +3715,10 @@
 int
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 {
-	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-	struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
 	uint32_t old_write_domain, old_read_domains;
+	struct i915_vma *vma;
 	int ret;
 
-	/* Not valid to be called on unbound objects. */
-	if (vma == NULL)
-		return -EINVAL;
-
 	if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
 		return 0;
 
@@ -3709,7 +3727,20 @@
 		return ret;
 
 	i915_gem_object_retire(obj);
-	i915_gem_object_flush_cpu_write_domain(obj, false);
+
+	/* Flush and acquire obj->pages so that we are coherent through
+	 * direct access in memory with previous cached writes through
+	 * shmemfs and that our cache domain tracking remains valid.
+	 * For example, if the obj->filp was moved to swap without us
+	 * being notified and releasing the pages, we would mistakenly
+	 * continue to assume that the obj remained out of the CPU cached
+	 * domain.
+	 */
+	ret = i915_gem_object_get_pages(obj);
+	if (ret)
+		return ret;
+
+	i915_gem_object_flush_cpu_write_domain(obj);
 
 	/* Serialise direct access to this object with the barriers for
 	 * coherent writes from the GPU, by effectively invalidating the
@@ -3740,9 +3771,10 @@
 					    old_write_domain);
 
 	/* And bump the LRU for this access */
-	if (i915_gem_object_is_inactive(obj))
+	vma = i915_gem_obj_to_ggtt(obj);
+	if (vma && drm_mm_node_allocated(&vma->node) && !obj->active)
 		list_move_tail(&vma->mm_list,
-			       &dev_priv->gtt.base.inactive_list);
+			       &to_i915(obj->base.dev)->gtt.base.inactive_list);
 
 	return 0;
 }
@@ -3788,36 +3820,23 @@
 		}
 
 		list_for_each_entry(vma, &obj->vma_list, vma_link)
-			if (drm_mm_node_allocated(&vma->node))
-				vma->bind_vma(vma, cache_level,
-						vma->bound & GLOBAL_BIND);
+			if (drm_mm_node_allocated(&vma->node)) {
+				ret = i915_vma_bind(vma, cache_level,
+						    vma->bound & GLOBAL_BIND);
+				if (ret)
+					return ret;
+			}
 	}
 
 	list_for_each_entry(vma, &obj->vma_list, vma_link)
 		vma->node.color = cache_level;
 	obj->cache_level = cache_level;
 
-	if (cpu_write_needs_clflush(obj)) {
-		u32 old_read_domains, old_write_domain;
-
-		/* If we're coming from LLC cached, then we haven't
-		 * actually been tracking whether the data is in the
-		 * CPU cache or not, since we only allow one bit set
-		 * in obj->write_domain and have been skipping the clflushes.
-		 * Just set it to the CPU cache for now.
-		 */
-		i915_gem_object_retire(obj);
-		WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU);
-
-		old_read_domains = obj->base.read_domains;
-		old_write_domain = obj->base.write_domain;
-
-		obj->base.read_domains = I915_GEM_DOMAIN_CPU;
-		obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-
-		trace_i915_gem_object_change_domain(obj,
-						    old_read_domains,
-						    old_write_domain);
+	if (obj->cache_dirty &&
+	    obj->base.write_domain != I915_GEM_DOMAIN_CPU &&
+	    cpu_write_needs_clflush(obj)) {
+		if (i915_gem_clflush_object(obj, true))
+			i915_gem_chipset_flush(obj->base.dev);
 	}
 
 	return 0;
@@ -3909,18 +3928,14 @@
 	if (!vma)
 		return false;
 
-	/* There are 3 sources that pin objects:
+	/* There are 2 sources that pin objects:
 	 *   1. The display engine (scanouts, sprites, cursors);
 	 *   2. Reservations for execbuffer;
-	 *   3. The user.
 	 *
 	 * We can ignore reservations as we hold the struct_mutex and
-	 * are only called outside of the reservation path.  The user
-	 * can only increment pin_count once, and so if after
-	 * subtracting the potential reference by the user, any pin_count
-	 * remains, it must be due to another use by the display engine.
+	 * are only called outside of the reservation path.
 	 */
-	return vma->pin_count - !!obj->user_pin_count;
+	return vma->pin_count;
 }
 
 /*
@@ -3937,7 +3952,7 @@
 	bool was_pin_display;
 	int ret;
 
-	if (pipelined != obj->ring) {
+	if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
 		ret = i915_gem_object_sync(obj, pipelined);
 		if (ret)
 			return ret;
@@ -3971,7 +3986,7 @@
 	if (ret)
 		goto err_unpin_display;
 
-	i915_gem_object_flush_cpu_write_domain(obj, true);
+	i915_gem_object_flush_cpu_write_domain(obj);
 
 	old_write_domain = obj->base.write_domain;
 	old_read_domains = obj->base.read_domains;
@@ -4089,10 +4104,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
-	struct drm_i915_gem_request *request;
-	struct intel_engine_cs *ring = NULL;
+	struct drm_i915_gem_request *request, *target = NULL;
 	unsigned reset_counter;
-	u32 seqno = 0;
 	int ret;
 
 	ret = i915_gem_wait_for_error(&dev_priv->gpu_error);
@@ -4108,19 +4121,24 @@
 		if (time_after_eq(request->emitted_jiffies, recent_enough))
 			break;
 
-		ring = request->ring;
-		seqno = request->seqno;
+		target = request;
 	}
 	reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+	if (target)
+		i915_gem_request_reference(target);
 	spin_unlock(&file_priv->mm.lock);
 
-	if (seqno == 0)
+	if (target == NULL)
 		return 0;
 
-	ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, NULL);
+	ret = __i915_wait_request(target, reset_counter, true, NULL, NULL);
 	if (ret == 0)
 		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_request_unreference(target);
+	mutex_unlock(&dev->struct_mutex);
+
 	return ret;
 }
 
@@ -4144,10 +4162,11 @@
 }
 
 int
-i915_gem_object_pin(struct drm_i915_gem_object *obj,
-		    struct i915_address_space *vm,
-		    uint32_t alignment,
-		    uint64_t flags)
+i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
+			 struct i915_address_space *vm,
+			 uint32_t alignment,
+			 uint64_t flags,
+			 const struct i915_ggtt_view *view)
 {
 	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 	struct i915_vma *vma;
@@ -4163,7 +4182,7 @@
 	if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
 		return -EINVAL;
 
-	vma = i915_gem_obj_to_vma(obj, vm);
+	vma = i915_gem_obj_to_vma_view(obj, vm, view);
 	if (vma) {
 		if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
 			return -EBUSY;
@@ -4173,7 +4192,8 @@
 			     "bo is already pinned with incorrect alignment:"
 			     " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
 			     " obj->map_and_fenceable=%d\n",
-			     i915_gem_obj_offset(obj, vm), alignment,
+			     i915_gem_obj_offset_view(obj, vm, view->type),
+			     alignment,
 			     !!(flags & PIN_MAPPABLE),
 			     obj->map_and_fenceable);
 			ret = i915_vma_unbind(vma);
@@ -4186,13 +4206,17 @@
 
 	bound = vma ? vma->bound : 0;
 	if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
-		vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags);
+		vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
+						 flags, view);
 		if (IS_ERR(vma))
 			return PTR_ERR(vma);
 	}
 
-	if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND))
-		vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
+	if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
+		ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
+		if (ret)
+			return ret;
+	}
 
 	if ((bound ^ vma->bound) & GLOBAL_BIND) {
 		bool mappable, fenceable;
@@ -4264,102 +4288,6 @@
 }
 
 int
-i915_gem_pin_ioctl(struct drm_device *dev, void *data,
-		   struct drm_file *file)
-{
-	struct drm_i915_gem_pin *args = data;
-	struct drm_i915_gem_object *obj;
-	int ret;
-
-	if (drm_core_check_feature(dev, DRIVER_MODESET))
-		return -ENODEV;
-
-	ret = i915_mutex_lock_interruptible(dev);
-	if (ret)
-		return ret;
-
-	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
-	if (&obj->base == NULL) {
-		ret = -ENOENT;
-		goto unlock;
-	}
-
-	if (obj->madv != I915_MADV_WILLNEED) {
-		DRM_DEBUG("Attempting to pin a purgeable buffer\n");
-		ret = -EFAULT;
-		goto out;
-	}
-
-	if (obj->pin_filp != NULL && obj->pin_filp != file) {
-		DRM_DEBUG("Already pinned in i915_gem_pin_ioctl(): %d\n",
-			  args->handle);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	if (obj->user_pin_count == ULONG_MAX) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	if (obj->user_pin_count == 0) {
-		ret = i915_gem_obj_ggtt_pin(obj, args->alignment, PIN_MAPPABLE);
-		if (ret)
-			goto out;
-	}
-
-	obj->user_pin_count++;
-	obj->pin_filp = file;
-
-	args->offset = i915_gem_obj_ggtt_offset(obj);
-out:
-	drm_gem_object_unreference(&obj->base);
-unlock:
-	mutex_unlock(&dev->struct_mutex);
-	return ret;
-}
-
-int
-i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
-		     struct drm_file *file)
-{
-	struct drm_i915_gem_pin *args = data;
-	struct drm_i915_gem_object *obj;
-	int ret;
-
-	if (drm_core_check_feature(dev, DRIVER_MODESET))
-		return -ENODEV;
-
-	ret = i915_mutex_lock_interruptible(dev);
-	if (ret)
-		return ret;
-
-	obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
-	if (&obj->base == NULL) {
-		ret = -ENOENT;
-		goto unlock;
-	}
-
-	if (obj->pin_filp != file) {
-		DRM_DEBUG("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
-			  args->handle);
-		ret = -EINVAL;
-		goto out;
-	}
-	obj->user_pin_count--;
-	if (obj->user_pin_count == 0) {
-		obj->pin_filp = NULL;
-		i915_gem_object_ggtt_unpin(obj);
-	}
-
-out:
-	drm_gem_object_unreference(&obj->base);
-unlock:
-	mutex_unlock(&dev->struct_mutex);
-	return ret;
-}
-
-int
 i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 		    struct drm_file *file)
 {
@@ -4385,9 +4313,11 @@
 	ret = i915_gem_object_flush_active(obj);
 
 	args->busy = obj->active;
-	if (obj->ring) {
+	if (obj->last_read_req) {
+		struct intel_engine_cs *ring;
 		BUILD_BUG_ON(I915_NUM_RINGS > 16);
-		args->busy |= intel_ring_flag(obj->ring) << 16;
+		ring = i915_gem_request_get_ring(obj->last_read_req);
+		args->busy |= intel_ring_flag(ring) << 16;
 	}
 
 	drm_gem_object_unreference(&obj->base);
@@ -4467,6 +4397,7 @@
 	INIT_LIST_HEAD(&obj->ring_list);
 	INIT_LIST_HEAD(&obj->obj_exec_link);
 	INIT_LIST_HEAD(&obj->vma_list);
+	INIT_LIST_HEAD(&obj->batch_pool_list);
 
 	obj->ops = ops;
 
@@ -4622,12 +4553,13 @@
 	intel_runtime_pm_put(dev_priv);
 }
 
-struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
-				     struct i915_address_space *vm)
+struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
+					  struct i915_address_space *vm,
+					  const struct i915_ggtt_view *view)
 {
 	struct i915_vma *vma;
 	list_for_each_entry(vma, &obj->vma_list, vma_link)
-		if (vma->vm == vm)
+		if (vma->vm == vm && vma->ggtt_view.type == view->type)
 			return vma;
 
 	return NULL;
@@ -4683,10 +4615,15 @@
 	i915_gem_stop_ringbuffers(dev);
 	mutex_unlock(&dev->struct_mutex);
 
-	del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+	cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
 	cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 	flush_delayed_work(&dev_priv->mm.idle_work);
 
+	/* Assert that we sucessfully flushed all the work and
+	 * reset the GPU back to its idle, low power state.
+	 */
+	WARN_ON(dev_priv->mm.busy);
+
 	return 0;
 
 err:
@@ -4798,14 +4735,6 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
-	/*
-	 * At least 830 can leave some of the unused rings
-	 * "active" (ie. head != tail) after resume which
-	 * will prevent c3 entry. Makes sure all unused rings
-	 * are totally idle.
-	 */
-	init_unused_rings(dev);
-
 	ret = intel_init_render_ring_buffer(dev);
 	if (ret)
 		return ret;
@@ -4858,6 +4787,7 @@
 i915_gem_init_hw(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_engine_cs *ring;
 	int ret, i;
 
 	if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
@@ -4884,9 +4814,19 @@
 
 	i915_gem_init_swizzling(dev);
 
-	ret = dev_priv->gt.init_rings(dev);
-	if (ret)
-		return ret;
+	/*
+	 * At least 830 can leave some of the unused rings
+	 * "active" (ie. head != tail) after resume which
+	 * will prevent c3 entry. Makes sure all unused rings
+	 * are totally idle.
+	 */
+	init_unused_rings(dev);
+
+	for_each_ring(ring, dev_priv, i) {
+		ret = ring->init_hw(ring);
+		if (ret)
+			return ret;
+	}
 
 	for (i = 0; i < NUM_L3_SLICES(dev); i++)
 		i915_gem_l3_remap(&dev_priv->ring[RCS], i);
@@ -4939,18 +4879,18 @@
 	}
 
 	ret = i915_gem_init_userptr(dev);
-	if (ret) {
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
-	}
+	if (ret)
+		goto out_unlock;
 
 	i915_gem_init_global_gtt(dev);
 
 	ret = i915_gem_context_init(dev);
-	if (ret) {
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
-	}
+	if (ret)
+		goto out_unlock;
+
+	ret = dev_priv->gt.init_rings(dev);
+	if (ret)
+		goto out_unlock;
 
 	ret = i915_gem_init_hw(dev);
 	if (ret == -EIO) {
@@ -4962,6 +4902,8 @@
 		atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
 		ret = 0;
 	}
+
+out_unlock:
 	mutex_unlock(&dev->struct_mutex);
 
 	return ret;
@@ -5062,6 +5004,8 @@
 	dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
 	register_oom_notifier(&dev_priv->mm.oom_notifier);
 
+	i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
+
 	mutex_init(&dev_priv->fb_tracking.lock);
 }
 
@@ -5155,7 +5099,7 @@
 	if (!mutex_is_locked(mutex))
 		return false;
 
-#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
 	return mutex->owner == task;
 #else
 	/* Since UP may be pre-empted, we cannot assume that we own the lock */
@@ -5222,8 +5166,9 @@
 }
 
 /* All the new VM stuff */
-unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
-				  struct i915_address_space *vm)
+unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
+				       struct i915_address_space *vm,
+				       enum i915_ggtt_view_type view)
 {
 	struct drm_i915_private *dev_priv = o->base.dev->dev_private;
 	struct i915_vma *vma;
@@ -5231,7 +5176,7 @@
 	WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
 	list_for_each_entry(vma, &o->vma_list, vma_link) {
-		if (vma->vm == vm)
+		if (vma->vm == vm && vma->ggtt_view.type == view)
 			return vma->node.start;
 
 	}
@@ -5240,13 +5185,16 @@
 	return -1;
 }
 
-bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
-			struct i915_address_space *vm)
+bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
+			     struct i915_address_space *vm,
+			     enum i915_ggtt_view_type view)
 {
 	struct i915_vma *vma;
 
 	list_for_each_entry(vma, &o->vma_list, vma_link)
-		if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
+		if (vma->vm == vm &&
+		    vma->ggtt_view.type == view &&
+		    drm_mm_node_allocated(&vma->node))
 			return true;
 
 	return false;
@@ -5378,11 +5326,13 @@
 
 struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
 {
+	struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
 	struct i915_vma *vma;
 
-	vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
-	if (vma->vm != i915_obj_to_ggtt(obj))
-		return NULL;
+	list_for_each_entry(vma, &obj->vma_list, vma_link)
+		if (vma->vm == ggtt &&
+		    vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
+			return vma;
 
-	return vma;
+	return NULL;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
new file mode 100644
index 0000000..c690170
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2014 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 "i915_drv.h"
+
+/**
+ * DOC: batch pool
+ *
+ * In order to submit batch buffers as 'secure', the software command parser
+ * must ensure that a batch buffer cannot be modified after parsing. It does
+ * this by copying the user provided batch buffer contents to a kernel owned
+ * buffer from which the hardware will actually execute, and by carefully
+ * managing the address space bindings for such buffers.
+ *
+ * The batch pool framework provides a mechanism for the driver to manage a
+ * set of scratch buffers to use for this purpose. The framework can be
+ * extended to support other uses cases should they arise.
+ */
+
+/**
+ * i915_gem_batch_pool_init() - initialize a batch buffer pool
+ * @dev: the drm device
+ * @pool: the batch buffer pool
+ */
+void i915_gem_batch_pool_init(struct drm_device *dev,
+			      struct i915_gem_batch_pool *pool)
+{
+	pool->dev = dev;
+	INIT_LIST_HEAD(&pool->cache_list);
+}
+
+/**
+ * i915_gem_batch_pool_fini() - clean up a batch buffer pool
+ * @pool: the pool to clean up
+ *
+ * Note: Callers must hold the struct_mutex.
+ */
+void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool)
+{
+	WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+
+	while (!list_empty(&pool->cache_list)) {
+		struct drm_i915_gem_object *obj =
+			list_first_entry(&pool->cache_list,
+					 struct drm_i915_gem_object,
+					 batch_pool_list);
+
+		WARN_ON(obj->active);
+
+		list_del_init(&obj->batch_pool_list);
+		drm_gem_object_unreference(&obj->base);
+	}
+}
+
+/**
+ * i915_gem_batch_pool_get() - select a buffer from the pool
+ * @pool: the batch buffer pool
+ * @size: the minimum desired size of the returned buffer
+ *
+ * Finds or allocates a batch buffer in the pool with at least the requested
+ * size. The caller is responsible for any domain, active/inactive, or
+ * purgeability management for the returned buffer.
+ *
+ * Note: Callers must hold the struct_mutex
+ *
+ * Return: the selected batch buffer object
+ */
+struct drm_i915_gem_object *
+i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
+			size_t size)
+{
+	struct drm_i915_gem_object *obj = NULL;
+	struct drm_i915_gem_object *tmp, *next;
+
+	WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+
+	list_for_each_entry_safe(tmp, next,
+			&pool->cache_list, batch_pool_list) {
+
+		if (tmp->active)
+			continue;
+
+		/* While we're looping, do some clean up */
+		if (tmp->madv == __I915_MADV_PURGED) {
+			list_del(&tmp->batch_pool_list);
+			drm_gem_object_unreference(&tmp->base);
+			continue;
+		}
+
+		/*
+		 * Select a buffer that is at least as big as needed
+		 * but not 'too much' bigger. A better way to do this
+		 * might be to bucket the pool objects based on size.
+		 */
+		if (tmp->base.size >= size &&
+		    tmp->base.size <= (2 * size)) {
+			obj = tmp;
+			break;
+		}
+	}
+
+	if (!obj) {
+		obj = i915_gem_alloc_object(pool->dev, size);
+		if (!obj)
+			return ERR_PTR(-ENOMEM);
+
+		list_add_tail(&obj->batch_pool_list, &pool->cache_list);
+	}
+	else
+		/* Keep list in LRU order */
+		list_move_tail(&obj->batch_pool_list, &pool->cache_list);
+
+	obj->madv = I915_MADV_WILLNEED;
+
+	return obj;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index d011ec8..8603bf4 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -222,6 +222,8 @@
 	 * is no remap info, it will be a NOP. */
 	ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
 
+	ctx->hang_stats.ban_period_seconds = DRM_I915_CTX_BAN_PERIOD;
+
 	return ctx;
 
 err_out:
@@ -408,14 +410,25 @@
 
 	BUG_ON(!dev_priv->ring[RCS].default_context);
 
-	if (i915.enable_execlists)
-		return 0;
+	if (i915.enable_execlists) {
+		for_each_ring(ring, dev_priv, i) {
+			if (ring->init_context) {
+				ret = ring->init_context(ring,
+						ring->default_context);
+				if (ret) {
+					DRM_ERROR("ring init context: %d\n",
+							ret);
+					return ret;
+				}
+			}
+		}
 
-	for_each_ring(ring, dev_priv, i) {
-		ret = i915_switch_context(ring, ring->default_context);
-		if (ret)
-			return ret;
-	}
+	} else
+		for_each_ring(ring, dev_priv, i) {
+			ret = i915_switch_context(ring, ring->default_context);
+			if (ret)
+				return ret;
+		}
 
 	return 0;
 }
@@ -611,9 +624,14 @@
 		goto unpin_out;
 
 	vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
-	if (!(vma->bound & GLOBAL_BIND))
-		vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level,
-				GLOBAL_BIND);
+	if (!(vma->bound & GLOBAL_BIND)) {
+		ret = i915_vma_bind(vma,
+				    to->legacy_hw_ctx.rcs_state->cache_level,
+				    GLOBAL_BIND);
+		/* This shouldn't ever fail. */
+		if (WARN_ONCE(ret, "GGTT context bind failed!"))
+			goto unpin_out;
+	}
 
 	if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
 		hw_flags |= MI_RESTORE_INHIBIT;
@@ -651,7 +669,8 @@
 		 * swapped, but there is no way to do that yet.
 		 */
 		from->legacy_hw_ctx.rcs_state->dirty = 1;
-		BUG_ON(from->legacy_hw_ctx.rcs_state->ring != ring);
+		BUG_ON(i915_gem_request_get_ring(
+			from->legacy_hw_ctx.rcs_state->last_read_req) != ring);
 
 		/* obj is kept alive until the next request by its active ref */
 		i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
@@ -671,10 +690,6 @@
 			if (ret)
 				DRM_ERROR("ring init context: %d\n", ret);
 		}
-
-		ret = i915_gem_render_state_init(ring);
-		if (ret)
-			DRM_ERROR("init render state: %d\n", ret);
 	}
 
 	return 0;
@@ -779,3 +794,72 @@
 	DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id);
 	return 0;
 }
+
+int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file)
+{
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct drm_i915_gem_context_param *args = data;
+	struct intel_context *ctx;
+	int ret;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
+	ctx = i915_gem_context_get(file_priv, args->ctx_id);
+	if (IS_ERR(ctx)) {
+		mutex_unlock(&dev->struct_mutex);
+		return PTR_ERR(ctx);
+	}
+
+	args->size = 0;
+	switch (args->param) {
+	case I915_CONTEXT_PARAM_BAN_PERIOD:
+		args->value = ctx->hang_stats.ban_period_seconds;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file)
+{
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct drm_i915_gem_context_param *args = data;
+	struct intel_context *ctx;
+	int ret;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
+	ctx = i915_gem_context_get(file_priv, args->ctx_id);
+	if (IS_ERR(ctx)) {
+		mutex_unlock(&dev->struct_mutex);
+		return PTR_ERR(ctx);
+	}
+
+	switch (args->param) {
+	case I915_CONTEXT_PARAM_BAN_PERIOD:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value < ctx->hang_stats.ban_period_seconds &&
+			 !capable(CAP_SYS_ADMIN))
+			ret = -EPERM;
+		else
+			ctx->hang_stats.ban_period_seconds = args->value;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 886ff2e..e3a49d9 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -50,11 +50,12 @@
  * i915_gem_evict_something - Evict vmas to make room for binding a new one
  * @dev: drm_device
  * @vm: address space to evict from
- * @size: size of the desired free space
+ * @min_size: size of the desired free space
  * @alignment: alignment constraint of the desired free space
  * @cache_level: cache_level for the desired space
- * @mappable: whether the free space must be mappable
- * @nonblocking: whether evicting active objects is allowed or not
+ * @start: start (inclusive) of the range from which to evict objects
+ * @end: end (exclusive) of the range from which to evict objects
+ * @flags: additional flags to control the eviction algorithm
  *
  * This function will try to evict vmas until a free space satisfying the
  * requirements is found. Callers must check first whether any such hole exists
@@ -196,7 +197,6 @@
 
 /**
  * i915_gem_evict_vm - Evict all idle vmas from a vm
- *
  * @vm: Address space to cleanse
  * @do_idle: Boolean directing whether to idle first.
  *
@@ -214,6 +214,7 @@
 	struct i915_vma *vma, *next;
 	int ret;
 
+	WARN_ON(!mutex_is_locked(&vm->dev->struct_mutex));
 	trace_i915_gem_evict_vm(vm);
 
 	if (do_idle) {
@@ -222,6 +223,8 @@
 			return ret;
 
 		i915_gem_retire_requests(vm->dev);
+
+		WARN_ON(!list_empty(&vm->active_list));
 	}
 
 	list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 1173831..b773368 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -37,6 +37,7 @@
 #define  __EXEC_OBJECT_HAS_FENCE (1<<30)
 #define  __EXEC_OBJECT_NEEDS_MAP (1<<29)
 #define  __EXEC_OBJECT_NEEDS_BIAS (1<<28)
+#define  __EXEC_OBJECT_PURGEABLE (1<<27)
 
 #define BATCH_OFFSET_BIAS (256*1024)
 
@@ -223,7 +224,12 @@
 	if (entry->flags & __EXEC_OBJECT_HAS_PIN)
 		vma->pin_count--;
 
-	entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
+	if (entry->flags & __EXEC_OBJECT_PURGEABLE)
+		obj->madv = I915_MADV_DONTNEED;
+
+	entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE |
+			  __EXEC_OBJECT_HAS_PIN |
+			  __EXEC_OBJECT_PURGEABLE);
 }
 
 static void eb_destroy(struct eb_vmas *eb)
@@ -357,9 +363,12 @@
 	 * through the ppgtt for non_secure batchbuffers. */
 	if (unlikely(IS_GEN6(dev) &&
 	    reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
-	    !(target_vma->bound & GLOBAL_BIND)))
-		target_vma->bind_vma(target_vma, target_i915_obj->cache_level,
-				GLOBAL_BIND);
+	    !(target_vma->bound & GLOBAL_BIND))) {
+		ret = i915_vma_bind(target_vma, target_i915_obj->cache_level,
+				    GLOBAL_BIND);
+		if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!"))
+			return ret;
+	}
 
 	/* Validate that the target is in a valid r/w GPU domain */
 	if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
@@ -943,7 +952,7 @@
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 				   struct intel_engine_cs *ring)
 {
-	u32 seqno = intel_ring_get_seqno(ring);
+	struct drm_i915_gem_request *req = intel_ring_get_request(ring);
 	struct i915_vma *vma;
 
 	list_for_each_entry(vma, vmas, exec_list) {
@@ -960,7 +969,7 @@
 		i915_vma_move_to_active(vma, ring);
 		if (obj->base.write_domain) {
 			obj->dirty = 1;
-			obj->last_write_seqno = seqno;
+			i915_gem_request_assign(&obj->last_write_req, req);
 
 			intel_fb_obj_invalidate(obj, ring);
 
@@ -968,7 +977,7 @@
 			obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
 		}
 		if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
-			obj->last_fenced_seqno = seqno;
+			i915_gem_request_assign(&obj->last_fenced_req, req);
 			if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
 				struct drm_i915_private *dev_priv = to_i915(ring->dev);
 				list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
@@ -990,7 +999,7 @@
 	ring->gpu_caches_dirty = true;
 
 	/* Add a breadcrumb for the completion of the batch buffer */
-	(void)__i915_add_request(ring, file, obj, NULL);
+	(void)__i915_add_request(ring, file, obj);
 }
 
 static int
@@ -1060,6 +1069,67 @@
 	return 0;
 }
 
+static struct drm_i915_gem_object*
+i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
+			  struct drm_i915_gem_exec_object2 *shadow_exec_entry,
+			  struct eb_vmas *eb,
+			  struct drm_i915_gem_object *batch_obj,
+			  u32 batch_start_offset,
+			  u32 batch_len,
+			  bool is_master,
+			  u32 *flags)
+{
+	struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
+	struct drm_i915_gem_object *shadow_batch_obj;
+	bool need_reloc = false;
+	int ret;
+
+	shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool,
+						   batch_obj->base.size);
+	if (IS_ERR(shadow_batch_obj))
+		return shadow_batch_obj;
+
+	ret = i915_parse_cmds(ring,
+			      batch_obj,
+			      shadow_batch_obj,
+			      batch_start_offset,
+			      batch_len,
+			      is_master);
+	if (ret) {
+		if (ret == -EACCES)
+			return batch_obj;
+	} else {
+		struct i915_vma *vma;
+
+		memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
+
+		vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
+		vma->exec_entry = shadow_exec_entry;
+		vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE;
+		drm_gem_object_reference(&shadow_batch_obj->base);
+		i915_gem_execbuffer_reserve_vma(vma, ring, &need_reloc);
+		list_add_tail(&vma->exec_list, &eb->vmas);
+
+		shadow_batch_obj->base.pending_read_domains =
+			batch_obj->base.pending_read_domains;
+
+		/*
+		 * Set the DISPATCH_SECURE bit to remove the NON_SECURE
+		 * bit from MI_BATCH_BUFFER_START commands issued in the
+		 * dispatch_execbuffer implementations. We specifically
+		 * don't want that set when the command parser is
+		 * enabled.
+		 *
+		 * FIXME: with aliasing ppgtt, buffers that should only
+		 * be in ggtt still end up in the aliasing ppgtt. remove
+		 * this check when that is fixed.
+		 */
+		if (USES_FULL_PPGTT(dev))
+			*flags |= I915_DISPATCH_SECURE;
+	}
+
+	return ret ? ERR_PTR(ret) : shadow_batch_obj;
+}
 
 int
 i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
@@ -1208,7 +1278,7 @@
 			return ret;
 	}
 
-	trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
+	trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), flags);
 
 	i915_gem_execbuffer_move_to_active(vmas, ring);
 	i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
@@ -1277,6 +1347,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct eb_vmas *eb;
 	struct drm_i915_gem_object *batch_obj;
+	struct drm_i915_gem_exec_object2 shadow_exec_entry;
 	struct intel_engine_cs *ring;
 	struct intel_context *ctx;
 	struct i915_address_space *vm;
@@ -1309,13 +1380,35 @@
 		return -EINVAL;
 	}
 
+	if (((args->flags & I915_EXEC_RING_MASK) != I915_EXEC_BSD) &&
+	    ((args->flags & I915_EXEC_BSD_MASK) != 0)) {
+		DRM_DEBUG("execbuf with non bsd ring but with invalid "
+			"bsd dispatch flags: %d\n", (int)(args->flags));
+		return -EINVAL;
+	} 
+
 	if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
 		ring = &dev_priv->ring[RCS];
 	else if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) {
 		if (HAS_BSD2(dev)) {
 			int ring_id;
-			ring_id = gen8_dispatch_bsd_ring(dev, file);
-			ring = &dev_priv->ring[ring_id];
+
+			switch (args->flags & I915_EXEC_BSD_MASK) {
+			case I915_EXEC_BSD_DEFAULT:
+				ring_id = gen8_dispatch_bsd_ring(dev, file);
+				ring = &dev_priv->ring[ring_id];
+				break;
+			case I915_EXEC_BSD_RING1:
+				ring = &dev_priv->ring[VCS];
+				break;
+			case I915_EXEC_BSD_RING2:
+				ring = &dev_priv->ring[VCS2];
+				break;
+			default:
+				DRM_DEBUG("execbuf with unknown bsd ring: %d\n",
+					  (int)(args->flags & I915_EXEC_BSD_MASK));
+				return -EINVAL;
+			}
 		} else
 			ring = &dev_priv->ring[VCS];
 	} else
@@ -1393,28 +1486,24 @@
 		ret = -EINVAL;
 		goto err;
 	}
-	batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
 
 	if (i915_needs_cmd_parser(ring)) {
-		ret = i915_parse_cmds(ring,
-				      batch_obj,
-				      args->batch_start_offset,
-				      file->is_master);
-		if (ret) {
-			if (ret != -EACCES)
-				goto err;
-		} else {
-			/*
-			 * XXX: Actually do this when enabling batch copy...
-			 *
-			 * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit
-			 * from MI_BATCH_BUFFER_START commands issued in the
-			 * dispatch_execbuffer implementations. We specifically don't
-			 * want that set when the command parser is enabled.
-			 */
+		batch_obj = i915_gem_execbuffer_parse(ring,
+						      &shadow_exec_entry,
+						      eb,
+						      batch_obj,
+						      args->batch_start_offset,
+						      args->batch_len,
+						      file->is_master,
+						      &flags);
+		if (IS_ERR(batch_obj)) {
+			ret = PTR_ERR(batch_obj);
+			goto err;
 		}
 	}
 
+	batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
 	/* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
 	 * batch" bit. Hence we need to pin secure batches into the global gtt.
 	 * hsw should have this fixed, but bdw mucks it up again. */
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 171f6ea..746f77f 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -30,6 +30,68 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/**
+ * DOC: Global GTT views
+ *
+ * Background and previous state
+ *
+ * Historically objects could exists (be bound) in global GTT space only as
+ * singular instances with a view representing all of the object's backing pages
+ * in a linear fashion. This view will be called a normal view.
+ *
+ * To support multiple views of the same object, where the number of mapped
+ * pages is not equal to the backing store, or where the layout of the pages
+ * is not linear, concept of a GGTT view was added.
+ *
+ * One example of an alternative view is a stereo display driven by a single
+ * image. In this case we would have a framebuffer looking like this
+ * (2x2 pages):
+ *
+ *    12
+ *    34
+ *
+ * Above would represent a normal GGTT view as normally mapped for GPU or CPU
+ * rendering. In contrast, fed to the display engine would be an alternative
+ * view which could look something like this:
+ *
+ *   1212
+ *   3434
+ *
+ * In this example both the size and layout of pages in the alternative view is
+ * different from the normal view.
+ *
+ * Implementation and usage
+ *
+ * GGTT views are implemented using VMAs and are distinguished via enum
+ * i915_ggtt_view_type and struct i915_ggtt_view.
+ *
+ * A new flavour of core GEM functions which work with GGTT bound objects were
+ * added with the _view suffix. They take the struct i915_ggtt_view parameter
+ * encapsulating all metadata required to implement a view.
+ *
+ * As a helper for callers which are only interested in the normal view,
+ * globally const i915_ggtt_view_normal singleton instance exists. All old core
+ * GEM API functions, the ones not taking the view parameter, are operating on,
+ * or with the normal GGTT view.
+ *
+ * Code wanting to add or use a new GGTT view needs to:
+ *
+ * 1. Add a new enum with a suitable name.
+ * 2. Extend the metadata in the i915_ggtt_view structure if required.
+ * 3. Add support to i915_get_vma_pages().
+ *
+ * New views are required to build a scatter-gather table from within the
+ * i915_get_vma_pages function. This table is stored in the vma.ggtt_view and
+ * exists for the lifetime of an VMA.
+ *
+ * Core API is designed to have copy semantics which means that passed in
+ * struct i915_ggtt_view does not need to be persistent (left around after
+ * calling the core API functions).
+ *
+ */
+
+const struct i915_ggtt_view i915_ggtt_view_normal;
+
 static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
 static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
 
@@ -40,8 +102,6 @@
 
 	has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
 	has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
-	if (IS_GEN8(dev))
-		has_full_ppgtt = false; /* XXX why? */
 
 	/*
 	 * We don't allow disabling PPGTT for gen9+ as it's a requirement for
@@ -72,7 +132,10 @@
 		return 0;
 	}
 
-	return has_aliasing_ppgtt ? 1 : 0;
+	if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists)
+		return 2;
+	else
+		return has_aliasing_ppgtt ? 1 : 0;
 }
 
 
@@ -132,7 +195,7 @@
 		pte |= GEN6_PTE_UNCACHED;
 		break;
 	default:
-		WARN_ON(1);
+		MISSING_CASE(level);
 	}
 
 	return pte;
@@ -156,7 +219,7 @@
 		pte |= GEN6_PTE_UNCACHED;
 		break;
 	default:
-		WARN_ON(1);
+		MISSING_CASE(level);
 	}
 
 	return pte;
@@ -1102,10 +1165,8 @@
 
 	if (INTEL_INFO(dev)->gen < 8)
 		return gen6_ppgtt_init(ppgtt);
-	else if (IS_GEN8(dev) || IS_GEN9(dev))
-		return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
 	else
-		BUG();
+		return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
 }
 int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 {
@@ -1146,7 +1207,7 @@
 	else if (INTEL_INFO(dev)->gen >= 8)
 		gen8_ppgtt_enable(dev);
 	else
-		WARN_ON(1);
+		MISSING_CASE(INTEL_INFO(dev)->gen);
 
 	if (ppgtt) {
 		for_each_ring(ring, dev_priv, i) {
@@ -1341,9 +1402,12 @@
 		/* The bind_vma code tries to be smart about tracking mappings.
 		 * Unfortunately above, we've just wiped out the mappings
 		 * without telling our object about it. So we need to fake it.
+		 *
+		 * Bind is not expected to fail since this is only called on
+		 * resume and assumption is all requirements exist already.
 		 */
 		vma->bound &= ~GLOBAL_BIND;
-		vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
+		WARN_ON(i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND));
 	}
 
 
@@ -1538,7 +1602,7 @@
 		AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
 
 	BUG_ON(!i915_is_ggtt(vma->vm));
-	intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags);
+	intel_gtt_insert_sg_entries(vma->ggtt_view.pages, entry, flags);
 	vma->bound = GLOBAL_BIND;
 }
 
@@ -1588,7 +1652,7 @@
 	if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
 		if (!(vma->bound & GLOBAL_BIND) ||
 		    (cache_level != obj->cache_level)) {
-			vma->vm->insert_entries(vma->vm, obj->pages,
+			vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
 						vma->node.start,
 						cache_level, flags);
 			vma->bound |= GLOBAL_BIND;
@@ -1600,7 +1664,7 @@
 	     (cache_level != obj->cache_level))) {
 		struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
 		appgtt->base.insert_entries(&appgtt->base,
-					    vma->obj->pages,
+					    vma->ggtt_view.pages,
 					    vma->node.start,
 					    cache_level, flags);
 		vma->bound |= LOCAL_BIND;
@@ -2165,7 +2229,8 @@
 }
 
 static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
-					      struct i915_address_space *vm)
+					      struct i915_address_space *vm,
+					      const struct i915_ggtt_view *view)
 {
 	struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
 	if (vma == NULL)
@@ -2176,12 +2241,9 @@
 	INIT_LIST_HEAD(&vma->exec_list);
 	vma->vm = vm;
 	vma->obj = obj;
+	vma->ggtt_view = *view;
 
-	switch (INTEL_INFO(vm->dev)->gen) {
-	case 9:
-	case 8:
-	case 7:
-	case 6:
+	if (INTEL_INFO(vm->dev)->gen >= 6) {
 		if (i915_is_ggtt(vm)) {
 			vma->unbind_vma = ggtt_unbind_vma;
 			vma->bind_vma = ggtt_bind_vma;
@@ -2189,39 +2251,73 @@
 			vma->unbind_vma = ppgtt_unbind_vma;
 			vma->bind_vma = ppgtt_bind_vma;
 		}
-		break;
-	case 5:
-	case 4:
-	case 3:
-	case 2:
+	} else {
 		BUG_ON(!i915_is_ggtt(vm));
 		vma->unbind_vma = i915_ggtt_unbind_vma;
 		vma->bind_vma = i915_ggtt_bind_vma;
-		break;
-	default:
-		BUG();
 	}
 
-	/* Keep GGTT vmas first to make debug easier */
-	if (i915_is_ggtt(vm))
-		list_add(&vma->vma_link, &obj->vma_list);
-	else {
-		list_add_tail(&vma->vma_link, &obj->vma_list);
+	list_add_tail(&vma->vma_link, &obj->vma_list);
+	if (!i915_is_ggtt(vm))
 		i915_ppgtt_get(i915_vm_to_ppgtt(vm));
-	}
 
 	return vma;
 }
 
 struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-				  struct i915_address_space *vm)
+i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
+				       struct i915_address_space *vm,
+				       const struct i915_ggtt_view *view)
 {
 	struct i915_vma *vma;
 
-	vma = i915_gem_obj_to_vma(obj, vm);
+	vma = i915_gem_obj_to_vma_view(obj, vm, view);
 	if (!vma)
-		vma = __i915_gem_vma_create(obj, vm);
+		vma = __i915_gem_vma_create(obj, vm, view);
 
 	return vma;
 }
+
+static inline
+int i915_get_vma_pages(struct i915_vma *vma)
+{
+	if (vma->ggtt_view.pages)
+		return 0;
+
+	if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
+		vma->ggtt_view.pages = vma->obj->pages;
+	else
+		WARN_ONCE(1, "GGTT view %u not implemented!\n",
+			  vma->ggtt_view.type);
+
+	if (!vma->ggtt_view.pages) {
+		DRM_ERROR("Failed to get pages for VMA view type %u!\n",
+			  vma->ggtt_view.type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
+ * @vma: VMA to map
+ * @cache_level: mapping cache level
+ * @flags: flags like global or local mapping
+ *
+ * DMA addresses are taken from the scatter-gather table of this object (or of
+ * this VMA in case of non-default GGTT views) and PTE entries set up.
+ * Note that DMA addresses are also the only part of the SG table we care about.
+ */
+int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
+		  u32 flags)
+{
+	int ret = i915_get_vma_pages(vma);
+
+	if (ret)
+		return ret;
+
+	vma->bind_vma(vma, cache_level, flags);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index beaf4bc..e377c7d 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -109,7 +109,20 @@
 #define GEN8_PPAT_ELLC_OVERRIDE		(0<<2)
 #define GEN8_PPAT(i, x)			((uint64_t) (x) << ((i) * 8))
 
+enum i915_ggtt_view_type {
+	I915_GGTT_VIEW_NORMAL = 0,
+};
+
+struct i915_ggtt_view {
+	enum i915_ggtt_view_type type;
+
+	struct sg_table *pages;
+};
+
+extern const struct i915_ggtt_view i915_ggtt_view_normal;
+
 enum i915_cache_level;
+
 /**
  * A VMA represents a GEM BO that is bound into an address space. Therefore, a
  * VMA's presence cannot be guaranteed before binding, or after unbinding the
@@ -129,6 +142,15 @@
 #define PTE_READ_ONLY	(1<<2)
 	unsigned int bound : 4;
 
+	/**
+	 * Support different GGTT views into the same object.
+	 * This means there can be multiple VMA mappings per object and per VM.
+	 * i915_ggtt_view_type is used to distinguish between those entries.
+	 * The default one of zero (I915_GGTT_VIEW_NORMAL) is default and also
+	 * assumed in GEM functions which take no ggtt view parameter.
+	 */
+	struct i915_ggtt_view ggtt_view;
+
 	/** This object's place on the active/inactive lists */
 	struct list_head mm_list;
 
@@ -146,11 +168,10 @@
 
 	/**
 	 * How many users have pinned this object in GTT space. The following
-	 * users can each hold at most one reference: pwrite/pread, pin_ioctl
-	 * (via user_pin_count), execbuffer (objects are not allowed multiple
-	 * times for the same batchbuffer), and the framebuffer code. When
-	 * switching/pageflipping, the framebuffer code has at most two buffers
-	 * pinned per crtc.
+	 * users can each hold at most one reference: pwrite/pread, execbuffer
+	 * (objects are not allowed multiple times for the same batchbuffer),
+	 * and the framebuffer code. When switching/pageflipping, the
+	 * framebuffer code has at most two buffers pinned per crtc.
 	 *
 	 * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
 	 * bits with absolutely no headroom. So use 4 bits. */
@@ -182,7 +203,7 @@
 	 * List of objects currently involved in rendering.
 	 *
 	 * Includes buffers having the contents of their GPU caches
-	 * flushed, not necessarily primitives.  last_rendering_seqno
+	 * flushed, not necessarily primitives. last_read_req
 	 * represents when the rendering involved will be completed.
 	 *
 	 * A reference is held on the buffer while on this list.
@@ -193,7 +214,7 @@
 	 * LRU list of objects which are not in the ringbuffer and
 	 * are ready to unbind, but are still in the GTT.
 	 *
-	 * last_rendering_seqno is 0 while an object is in this list.
+	 * last_read_req is NULL while an object is in this list.
 	 *
 	 * A reference is not held on the buffer while on this list,
 	 * as merely being GTT-bound shouldn't prevent its being
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c
index 98dcd94..521548a 100644
--- a/drivers/gpu/drm/i915/i915_gem_render_state.c
+++ b/drivers/gpu/drm/i915/i915_gem_render_state.c
@@ -173,7 +173,7 @@
 
 	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
 
-	ret = __i915_add_request(ring, NULL, so.obj, NULL);
+	ret = __i915_add_request(ring, NULL, so.obj);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
 	i915_gem_render_state_fini(&so);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 4727a4e..7a24bd1 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -399,7 +399,7 @@
 			}
 
 			obj->fence_dirty =
-				obj->last_fenced_seqno ||
+				obj->last_fenced_req ||
 				obj->fence_reg != I915_FENCE_REG_NONE;
 
 			obj->tiling_mode = args->tiling_mode;
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index d182058..1719078 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -113,7 +113,10 @@
 			continue;
 
 		obj = mo->obj;
-		drm_gem_object_reference(&obj->base);
+
+		if (!kref_get_unless_zero(&obj->base.refcount))
+			continue;
+
 		spin_unlock(&mn->lock);
 
 		cancel_userptr(obj);
@@ -149,7 +152,20 @@
 			it = interval_tree_iter_first(&mn->objects, start, end);
 		if (it != NULL) {
 			obj = container_of(it, struct i915_mmu_object, it)->obj;
-			drm_gem_object_reference(&obj->base);
+
+			/* The mmu_object is released late when destroying the
+			 * GEM object so it is entirely possible to gain a
+			 * reference on an object in the process of being freed
+			 * since our serialisation is via the spinlock and not
+			 * the struct_mutex - and consequently use it after it
+			 * is freed and then double free it.
+			 */
+			if (!kref_get_unless_zero(&obj->base.refcount)) {
+				spin_unlock(&mn->lock);
+				serial = 0;
+				continue;
+			}
+
 			serial = mn->serial;
 		}
 		spin_unlock(&mn->lock);
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index cdaee6c..48ddbf4 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -670,8 +670,8 @@
 
 	err->size = obj->base.size;
 	err->name = obj->base.name;
-	err->rseqno = obj->last_read_seqno;
-	err->wseqno = obj->last_write_seqno;
+	err->rseqno = i915_gem_request_get_seqno(obj->last_read_req);
+	err->wseqno = i915_gem_request_get_seqno(obj->last_write_req);
 	err->gtt_offset = vma->node.start;
 	err->read_domains = obj->base.read_domains;
 	err->write_domain = obj->base.write_domain;
@@ -679,13 +679,12 @@
 	err->pinned = 0;
 	if (i915_gem_obj_is_pinned(obj))
 		err->pinned = 1;
-	if (obj->user_pin_count > 0)
-		err->pinned = -1;
 	err->tiling = obj->tiling_mode;
 	err->dirty = obj->dirty;
 	err->purgeable = obj->madv != I915_MADV_WILLNEED;
 	err->userptr = obj->userptr.mm != NULL;
-	err->ring = obj->ring ? obj->ring->id : -1;
+	err->ring = obj->last_read_req ?
+			i915_gem_request_get_ring(obj->last_read_req)->id : -1;
 	err->cache_level = obj->cache_level;
 }
 
@@ -719,10 +718,8 @@
 			break;
 
 		list_for_each_entry(vma, &obj->vma_list, vma_link)
-			if (vma->vm == vm && vma->pin_count > 0) {
+			if (vma->vm == vm && vma->pin_count > 0)
 				capture_bo(err++, vma);
-				break;
-			}
 	}
 
 	return err - first;
@@ -767,32 +764,21 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
-	/* Fences */
-	switch (INTEL_INFO(dev)->gen) {
-	case 9:
-	case 8:
-	case 7:
-	case 6:
-		for (i = 0; i < dev_priv->num_fence_regs; i++)
-			error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
-		break;
-	case 5:
-	case 4:
-		for (i = 0; i < 16; i++)
-			error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
-		break;
-	case 3:
-		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-			for (i = 0; i < 8; i++)
-				error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
-	case 2:
+	if (IS_GEN3(dev) || IS_GEN2(dev)) {
 		for (i = 0; i < 8; i++)
 			error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
-		break;
-
-	default:
-		BUG();
-	}
+		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+			for (i = 0; i < 8; i++)
+				error->fence[i+8] = I915_READ(FENCE_REG_945_8 +
+							      (i * 4));
+	} else if (IS_GEN5(dev) || IS_GEN4(dev))
+		for (i = 0; i < 16; i++)
+			error->fence[i] = I915_READ64(FENCE_REG_965_0 +
+						      (i * 8));
+	else if (INTEL_INFO(dev)->gen >= 6)
+		for (i = 0; i < dev_priv->num_fence_regs; i++)
+			error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 +
+						      (i * 8));
 }
 
 
@@ -926,9 +912,13 @@
 
 		ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring));
 
-		switch (INTEL_INFO(dev)->gen) {
-		case 9:
-		case 8:
+		if (IS_GEN6(dev))
+			ering->vm_info.pp_dir_base =
+				I915_READ(RING_PP_DIR_BASE_READ(ring));
+		else if (IS_GEN7(dev))
+			ering->vm_info.pp_dir_base =
+				I915_READ(RING_PP_DIR_BASE(ring));
+		else if (INTEL_INFO(dev)->gen >= 8)
 			for (i = 0; i < 4; i++) {
 				ering->vm_info.pdp[i] =
 					I915_READ(GEN8_RING_PDP_UDW(ring, i));
@@ -936,16 +926,6 @@
 				ering->vm_info.pdp[i] |=
 					I915_READ(GEN8_RING_PDP_LDW(ring, i));
 			}
-			break;
-		case 7:
-			ering->vm_info.pp_dir_base =
-				I915_READ(RING_PP_DIR_BASE(ring));
-			break;
-		case 6:
-			ering->vm_info.pp_dir_base =
-				I915_READ(RING_PP_DIR_BASE_READ(ring));
-			break;
-		}
 	}
 }
 
@@ -1072,7 +1052,7 @@
 			erq = &error->ring[i].requests[count++];
 			erq->seqno = request->seqno;
 			erq->jiffies = request->emitted_jiffies;
-			erq->tail = request->tail;
+			erq->tail = request->postfix;
 		}
 	}
 }
@@ -1097,10 +1077,8 @@
 
 	list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
 		list_for_each_entry(vma, &obj->vma_list, vma_link)
-			if (vma->vm == vm && vma->pin_count > 0) {
+			if (vma->vm == vm && vma->pin_count > 0)
 				i++;
-				break;
-			}
 	}
 	error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
 
@@ -1378,26 +1356,15 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
 
-	switch (INTEL_INFO(dev)->gen) {
-	case 2:
-	case 3:
+	if (IS_GEN2(dev) || IS_GEN3(dev))
 		instdone[0] = I915_READ(INSTDONE);
-		break;
-	case 4:
-	case 5:
-	case 6:
+	else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
 		instdone[0] = I915_READ(INSTDONE_I965);
 		instdone[1] = I915_READ(INSTDONE1);
-		break;
-	default:
-		WARN_ONCE(1, "Unsupported platform\n");
-	case 7:
-	case 8:
-	case 9:
+	} else if (INTEL_INFO(dev)->gen >= 7) {
 		instdone[0] = I915_READ(GEN7_INSTDONE_1);
 		instdone[1] = I915_READ(GEN7_SC_INSTDONE);
 		instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
 		instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
-		break;
 	}
 }
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b051a23..4145d95 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -45,7 +45,7 @@
  * and related files, but that will be described in separate chapters.
  */
 
-static const u32 hpd_ibx[] = {
+static const u32 hpd_ibx[HPD_NUM_PINS] = {
 	[HPD_CRT] = SDE_CRT_HOTPLUG,
 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG,
@@ -53,7 +53,7 @@
 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG
 };
 
-static const u32 hpd_cpt[] = {
+static const u32 hpd_cpt[HPD_NUM_PINS] = {
 	[HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
 	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
 	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
@@ -61,7 +61,7 @@
 	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
 };
 
-static const u32 hpd_mask_i915[] = {
+static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
 	[HPD_CRT] = CRT_HOTPLUG_INT_EN,
 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
@@ -70,7 +70,7 @@
 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
 };
 
-static const u32 hpd_status_g4x[] = {
+static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@ -79,7 +79,7 @@
 	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
-static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+static const u32 hpd_status_i915[HPD_NUM_PINS] = { /* i915 and valleyview are the same */
 	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
 	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
 	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
@@ -183,6 +183,8 @@
 {
 	assert_spin_locked(&dev_priv->irq_lock);
 
+	WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
 		return;
 
@@ -229,6 +231,8 @@
 {
 	uint32_t new_val;
 
+	WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
 	assert_spin_locked(&dev_priv->irq_lock);
 
 	new_val = dev_priv->pm_irq_mask;
@@ -348,6 +352,8 @@
 	sdeimr &= ~interrupt_mask;
 	sdeimr |= (~enabled_irq_mask & interrupt_mask);
 
+	WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
 	assert_spin_locked(&dev_priv->irq_lock);
 
 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
@@ -587,7 +593,7 @@
 		struct intel_crtc *intel_crtc =
 			to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 		const struct drm_display_mode *mode =
-			&intel_crtc->config.adjusted_mode;
+			&intel_crtc->config->base.adjusted_mode;
 
 		htotal = mode->crtc_htotal;
 		hsync_start = mode->crtc_hsync_start;
@@ -658,7 +664,7 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+	const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
 	enum pipe pipe = crtc->pipe;
 	int position, vtotal;
 
@@ -685,7 +691,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+	const struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
 	int position;
 	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
 	bool in_vbl = true;
@@ -843,7 +849,7 @@
 	return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
 						     vblank_time, flags,
 						     crtc,
-						     &to_intel_crtc(crtc)->config.adjusted_mode);
+						     &to_intel_crtc(crtc)->config->base.adjusted_mode);
 }
 
 static bool intel_hpd_irq_event(struct drm_device *dev,
@@ -873,7 +879,7 @@
 		container_of(work, struct drm_i915_private, dig_port_work);
 	u32 long_port_mask, short_port_mask;
 	struct intel_digital_port *intel_dig_port;
-	int i, ret;
+	int i;
 	u32 old_bits = 0;
 
 	spin_lock_irq(&dev_priv->irq_lock);
@@ -897,9 +903,11 @@
 			valid = true;
 
 		if (valid) {
+			enum irqreturn ret;
+
 			ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd);
-			if (ret == true) {
-				/* if we get true fallback to old school hpd */
+			if (ret == IRQ_NONE) {
+				/* fall back to old school hpd */
 				old_bits |= (1 << intel_dig_port->base.hpd_pin);
 			}
 		}
@@ -1033,7 +1041,7 @@
 	if (!intel_ring_initialized(ring))
 		return;
 
-	trace_i915_gem_request_complete(ring);
+	trace_i915_gem_request_notify(ring);
 
 	wake_up_all(&ring->irq_queue);
 }
@@ -1399,14 +1407,14 @@
 			if (rcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, ring);
 			if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
-				intel_execlists_handle_ctx_events(ring);
+				intel_lrc_irq_handler(ring);
 
 			bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
 			ring = &dev_priv->ring[BCS];
 			if (bcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, ring);
 			if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
-				intel_execlists_handle_ctx_events(ring);
+				intel_lrc_irq_handler(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1422,14 +1430,14 @@
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, ring);
 			if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-				intel_execlists_handle_ctx_events(ring);
+				intel_lrc_irq_handler(ring);
 
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
 			ring = &dev_priv->ring[VCS2];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, ring);
 			if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-				intel_execlists_handle_ctx_events(ring);
+				intel_lrc_irq_handler(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1456,7 +1464,7 @@
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, ring);
 			if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
-				intel_execlists_handle_ctx_events(ring);
+				intel_lrc_irq_handler(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
@@ -1516,7 +1524,7 @@
 static inline void intel_hpd_irq_handler(struct drm_device *dev,
 					 u32 hotplug_trigger,
 					 u32 dig_hotplug_reg,
-					 const u32 *hpd)
+					 const u32 hpd[HPD_NUM_PINS])
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
@@ -2413,19 +2421,15 @@
 }
 
 /**
- * i915_error_work_func - do process context error handling work
- * @work: work struct
+ * i915_reset_and_wakeup - do process context error handling work
  *
  * Fire an error uevent so userspace can see that a hang or error
  * was detected.
  */
-static void i915_error_work_func(struct work_struct *work)
+static void i915_reset_and_wakeup(struct drm_device *dev)
 {
-	struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
-						    work);
-	struct drm_i915_private *dev_priv =
-		container_of(error, struct drm_i915_private, gpu_error);
-	struct drm_device *dev = dev_priv->dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct i915_gpu_error *error = &dev_priv->gpu_error;
 	char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
 	char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
 	char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
@@ -2592,10 +2596,10 @@
 }
 
 /**
- * i915_handle_error - handle an error interrupt
+ * i915_handle_error - handle a gpu error
  * @dev: drm device
  *
- * Do some basic checking of regsiter state at error interrupt time and
+ * Do some basic checking of regsiter state at error time and
  * dump it to the syslog.  Also call i915_capture_error_state() to make
  * sure we get a record and make it available in debugfs.  Fire a uevent
  * so userspace knows something bad happened (should trigger collection
@@ -2620,9 +2624,9 @@
 				&dev_priv->gpu_error.reset_counter);
 
 		/*
-		 * Wakeup waiting processes so that the reset work function
-		 * i915_error_work_func doesn't deadlock trying to grab various
-		 * locks. By bumping the reset counter first, the woken
+		 * Wakeup waiting processes so that the reset function
+		 * i915_reset_and_wakeup doesn't deadlock trying to grab
+		 * various locks. By bumping the reset counter first, the woken
 		 * processes will see a reset in progress and back off,
 		 * releasing their locks and then wait for the reset completion.
 		 * We must do this for _all_ gpu waiters that might hold locks
@@ -2635,13 +2639,7 @@
 		i915_error_wake_up(dev_priv, false);
 	}
 
-	/*
-	 * Our reset work can grab modeset locks (since it needs to reset the
-	 * state of outstanding pagelips). Hence it must not be run on our own
-	 * dev-priv->wq work queue for otherwise the flush_work in the pageflip
-	 * code will deadlock.
-	 */
-	schedule_work(&dev_priv->gpu_error.work);
+	i915_reset_and_wakeup(dev);
 }
 
 /* Called from drm generic code, passed 'crtc' which
@@ -2769,18 +2767,18 @@
 	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-static u32
-ring_last_seqno(struct intel_engine_cs *ring)
+static struct drm_i915_gem_request *
+ring_last_request(struct intel_engine_cs *ring)
 {
 	return list_entry(ring->request_list.prev,
-			  struct drm_i915_gem_request, list)->seqno;
+			  struct drm_i915_gem_request, list);
 }
 
 static bool
-ring_idle(struct intel_engine_cs *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *ring)
 {
 	return (list_empty(&ring->request_list) ||
-		i915_seqno_passed(seqno, ring_last_seqno(ring)));
+		i915_gem_request_completed(ring_last_request(ring), false));
 }
 
 static bool
@@ -2966,7 +2964,7 @@
 	return HANGCHECK_HUNG;
 }
 
-/**
+/*
  * This is called when the chip hasn't reported back with completed
  * batchbuffers in a long time. We keep track per ring seqno progress and
  * if there are no progress, hangcheck score for that ring is increased.
@@ -2974,10 +2972,12 @@
  * we kick the ring. If we see no progress on three subsequent calls
  * we assume chip is wedged and try to fix it by resetting the chip.
  */
-static void i915_hangcheck_elapsed(unsigned long data)
+static void i915_hangcheck_elapsed(struct work_struct *work)
 {
-	struct drm_device *dev = (struct drm_device *)data;
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv =
+		container_of(work, typeof(*dev_priv),
+			     gpu_error.hangcheck_work.work);
+	struct drm_device *dev = dev_priv->dev;
 	struct intel_engine_cs *ring;
 	int i;
 	int busy_count = 0, rings_hung = 0;
@@ -3000,7 +3000,7 @@
 		acthd = intel_ring_get_active_head(ring);
 
 		if (ring->hangcheck.seqno == seqno) {
-			if (ring_idle(ring, seqno)) {
+			if (ring_idle(ring)) {
 				ring->hangcheck.action = HANGCHECK_IDLE;
 
 				if (waitqueue_active(&ring->irq_queue)) {
@@ -3091,17 +3091,18 @@
 
 void i915_queue_hangcheck(struct drm_device *dev)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct timer_list *timer = &dev_priv->gpu_error.hangcheck_timer;
+	struct i915_gpu_error *e = &to_i915(dev)->gpu_error;
 
 	if (!i915.enable_hangcheck)
 		return;
 
-	/* Don't continually defer the hangcheck, but make sure it is active */
-	if (timer_pending(timer))
-		return;
-	mod_timer(timer,
-		  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+	/* Don't continually defer the hangcheck so that it is always run at
+	 * least once after work has been scheduled on any ring. Otherwise,
+	 * we will ignore a hung ring if a second ring is kept busy.
+	 */
+
+	queue_delayed_work(e->hangcheck_wq, &e->hangcheck_work,
+			   round_jiffies_up_relative(DRM_I915_HANGCHECK_JIFFIES));
 }
 
 static void ibx_irq_reset(struct drm_device *dev)
@@ -4139,26 +4140,24 @@
 
 	assert_spin_locked(&dev_priv->irq_lock);
 
-	if (I915_HAS_HOTPLUG(dev)) {
-		hotplug_en = I915_READ(PORT_HOTPLUG_EN);
-		hotplug_en &= ~HOTPLUG_INT_EN_MASK;
-		/* Note HDMI and DP share hotplug bits */
-		/* enable bits are the same for all generations */
-		for_each_intel_encoder(dev, intel_encoder)
-			if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
-				hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
-		/* Programming the CRT detection parameters tends
-		   to generate a spurious hotplug event about three
-		   seconds later.  So just do it once.
-		*/
-		if (IS_G4X(dev))
-			hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
-		hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
-		hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+	hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+	hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+	/* Note HDMI and DP share hotplug bits */
+	/* enable bits are the same for all generations */
+	for_each_intel_encoder(dev, intel_encoder)
+		if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+			hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
+	/* Programming the CRT detection parameters tends
+	   to generate a spurious hotplug event about three
+	   seconds later.  So just do it once.
+	*/
+	if (IS_G4X(dev))
+		hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+	hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
+	hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
 
-		/* Ignore TV since it's buggy */
-		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
-	}
+	/* Ignore TV since it's buggy */
+	I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 }
 
 static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -4336,7 +4335,6 @@
 
 	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 	INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
-	INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func);
 	INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
 	INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
@@ -4347,9 +4345,8 @@
 	else
 		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
-	setup_timer(&dev_priv->gpu_error.hangcheck_timer,
-		    i915_hangcheck_elapsed,
-		    (unsigned long) dev);
+	INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
+			  i915_hangcheck_elapsed);
 	INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
 			  intel_hpd_irq_reenable_work);
 
@@ -4422,14 +4419,14 @@
 			dev->driver->irq_postinstall = i915_irq_postinstall;
 			dev->driver->irq_uninstall = i915_irq_uninstall;
 			dev->driver->irq_handler = i915_irq_handler;
-			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
 		} else {
 			dev->driver->irq_preinstall = i965_irq_preinstall;
 			dev->driver->irq_postinstall = i965_irq_postinstall;
 			dev->driver->irq_uninstall = i965_irq_uninstall;
 			dev->driver->irq_handler = i965_irq_handler;
-			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
 		}
+		if (I915_HAS_HOTPLUG(dev_priv))
+			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
 		dev->driver->enable_vblank = i915_enable_vblank;
 		dev->driver->disable_vblank = i915_disable_vblank;
 	}
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index c91cb20..44f2262 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -35,7 +35,7 @@
 	.vbt_sdvo_panel_type = -1,
 	.enable_rc6 = -1,
 	.enable_fbc = -1,
-	.enable_execlists = 0,
+	.enable_execlists = -1,
 	.enable_hangcheck = true,
 	.enable_ppgtt = -1,
 	.enable_psr = 0,
@@ -51,6 +51,8 @@
 	.disable_vtd_wa = 0,
 	.use_mmio_flip = 0,
 	.mmio_debug = 0,
+	.verbose_state_checks = 1,
+	.nuclear_pageflip = 0,
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -122,7 +124,7 @@
 module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
 MODULE_PARM_DESC(enable_execlists,
 	"Override execlists usage. "
-	"(-1=auto, 0=disabled [default], 1=enabled)");
+	"(-1=auto [default], 0=disabled, 1=enabled)");
 
 module_param_named(enable_psr, i915.enable_psr, int, 0600);
 MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
@@ -173,3 +175,11 @@
 MODULE_PARM_DESC(mmio_debug,
 	"Enable the MMIO debug code (default: false). This may negatively "
 	"affect performance.");
+
+module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
+MODULE_PARM_DESC(verbose_state_checks,
+	"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");
+
+module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
+MODULE_PARM_DESC(nuclear_pageflip,
+		 "Force atomic modeset functionality; only planes work for now (default: false).");
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 172de3b..33b3d0a2 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -31,6 +31,8 @@
 #define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
 #define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \
 			       (pipe) == PIPE_B ? (b) : (c))
+#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
+			       (port) == PORT_B ? (b) : (c))
 
 #define _MASKED_FIELD(mask, value) ({					   \
 	if (__builtin_constant_p(mask))					   \
@@ -217,6 +219,8 @@
 #define INSTR_SUBCLIENT_SHIFT   27
 #define INSTR_SUBCLIENT_MASK    0x18000000
 #define   INSTR_MEDIA_SUBCLIENT 0x2
+#define INSTR_26_TO_24_MASK	0x7000000
+#define   INSTR_26_TO_24_SHIFT	24
 
 /*
  * Memory interface instructions used by the kernel
@@ -246,6 +250,7 @@
 #define MI_BATCH_BUFFER_END	MI_INSTR(0x0a, 0)
 #define MI_SUSPEND_FLUSH	MI_INSTR(0x0b, 0)
 #define   MI_SUSPEND_FLUSH_EN	(1<<0)
+#define MI_SET_APPID		MI_INSTR(0x0e, 0)
 #define MI_OVERLAY_FLIP		MI_INSTR(0x11, 0)
 #define   MI_OVERLAY_CONTINUE	(0x0<<21)
 #define   MI_OVERLAY_ON		(0x1<<21)
@@ -303,8 +308,9 @@
 #define   MI_SEMAPHORE_POLL		(1<<15)
 #define   MI_SEMAPHORE_SAD_GTE_SDD	(1<<12)
 #define MI_STORE_DWORD_IMM	MI_INSTR(0x20, 1)
-#define MI_STORE_DWORD_IMM_GEN8	MI_INSTR(0x20, 2)
-#define   MI_MEM_VIRTUAL	(1 << 22) /* 965+ only */
+#define MI_STORE_DWORD_IMM_GEN4	MI_INSTR(0x20, 2)
+#define   MI_MEM_VIRTUAL	(1 << 22) /* 945,g33,965 */
+#define   MI_USE_GGTT		(1 << 22) /* g4x+ */
 #define MI_STORE_DWORD_INDEX	MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
 /* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM:
@@ -470,17 +476,18 @@
  */
 #define BCS_SWCTRL 0x22200
 
-#define HS_INVOCATION_COUNT 0x2300
-#define DS_INVOCATION_COUNT 0x2308
-#define IA_VERTICES_COUNT   0x2310
-#define IA_PRIMITIVES_COUNT 0x2318
-#define VS_INVOCATION_COUNT 0x2320
-#define GS_INVOCATION_COUNT 0x2328
-#define GS_PRIMITIVES_COUNT 0x2330
-#define CL_INVOCATION_COUNT 0x2338
-#define CL_PRIMITIVES_COUNT 0x2340
-#define PS_INVOCATION_COUNT 0x2348
-#define PS_DEPTH_COUNT      0x2350
+#define GPGPU_THREADS_DISPATCHED        0x2290
+#define HS_INVOCATION_COUNT             0x2300
+#define DS_INVOCATION_COUNT             0x2308
+#define IA_VERTICES_COUNT               0x2310
+#define IA_PRIMITIVES_COUNT             0x2318
+#define VS_INVOCATION_COUNT             0x2320
+#define GS_INVOCATION_COUNT             0x2328
+#define GS_PRIMITIVES_COUNT             0x2330
+#define CL_INVOCATION_COUNT             0x2338
+#define CL_PRIMITIVES_COUNT             0x2340
+#define PS_INVOCATION_COUNT             0x2348
+#define PS_DEPTH_COUNT                  0x2350
 
 /* There are the 4 64-bit counter registers, one for each stream output */
 #define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
@@ -598,6 +605,15 @@
 #define PUNIT_FUSE_BUS2				0xf6 /* bits 47:40 */
 #define PUNIT_FUSE_BUS1				0xf5 /* bits 55:48 */
 
+#define FB_GFX_FMAX_AT_VMAX_FUSE		0x136
+#define FB_GFX_FREQ_FUSE_MASK			0xff
+#define FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT	24
+#define FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT	16
+#define FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT	8
+
+#define FB_GFX_FMIN_AT_VMIN_FUSE		0x137
+#define FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT		8
+
 #define PUNIT_GPU_STATUS_REG			0xdb
 #define PUNIT_GPU_STATUS_MAX_FREQ_SHIFT	16
 #define PUNIT_GPU_STATUS_MAX_FREQ_MASK		0xff
@@ -1464,6 +1480,17 @@
 #define   GEN8_RC_SEMA_IDLE_MSG_DISABLE	(1 << 12)
 #define   GEN8_FF_DOP_CLOCK_GATE_DISABLE	(1<<10)
 
+/* Fuse readout registers for GT */
+#define CHV_FUSE_GT			(VLV_DISPLAY_BASE + 0x2168)
+#define   CHV_FGT_EU_DIS_SS0_R0_SHIFT	16
+#define   CHV_FGT_EU_DIS_SS0_R0_MASK	(0xf << CHV_FGT_EU_DIS_SS0_R0_SHIFT)
+#define   CHV_FGT_EU_DIS_SS0_R1_SHIFT	20
+#define   CHV_FGT_EU_DIS_SS0_R1_MASK	(0xf << CHV_FGT_EU_DIS_SS0_R1_SHIFT)
+#define   CHV_FGT_EU_DIS_SS1_R0_SHIFT	24
+#define   CHV_FGT_EU_DIS_SS1_R0_MASK	(0xf << CHV_FGT_EU_DIS_SS1_R0_SHIFT)
+#define   CHV_FGT_EU_DIS_SS1_R1_SHIFT	28
+#define   CHV_FGT_EU_DIS_SS1_R1_MASK	(0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
+
 #define GEN6_BSD_SLEEP_PSMI_CONTROL	0x12050
 #define   GEN6_BSD_SLEEP_MSG_DISABLE	(1 << 0)
 #define   GEN6_BSD_SLEEP_FLUSH_DISABLE	(1 << 2)
@@ -1509,7 +1536,7 @@
 #define I915_ISP_INTERRUPT				(1<<22)
 #define I915_LPE_PIPE_B_INTERRUPT			(1<<21)
 #define I915_LPE_PIPE_A_INTERRUPT			(1<<20)
-#define I915_MIPIB_INTERRUPT				(1<<19)
+#define I915_MIPIC_INTERRUPT				(1<<19)
 #define I915_MIPIA_INTERRUPT				(1<<18)
 #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT		(1<<18)
 #define I915_DISPLAY_PORT_INTERRUPT			(1<<17)
@@ -2539,6 +2566,42 @@
 #define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
 #define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
 
+/* VLV eDP PSR registers */
+#define _PSRCTLA				(VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB				(VLV_DISPLAY_BASE + 0x61090)
+#define  VLV_EDP_PSR_ENABLE			(1<<0)
+#define  VLV_EDP_PSR_RESET			(1<<1)
+#define  VLV_EDP_PSR_MODE_MASK			(7<<2)
+#define  VLV_EDP_PSR_MODE_HW_TIMER		(1<<3)
+#define  VLV_EDP_PSR_MODE_SW_TIMER		(1<<2)
+#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE	(1<<7)
+#define  VLV_EDP_PSR_ACTIVE_ENTRY		(1<<8)
+#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE	(1<<9)
+#define  VLV_EDP_PSR_DBL_FRAME			(1<<10)
+#define  VLV_EDP_PSR_FRAME_COUNT_MASK		(0xff<<16)
+#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT		16
+#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA			(VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB			(VLV_DISPLAY_BASE + 0x610a0)
+#define  VLV_EDP_PSR_SDP_FREQ_MASK	(3<<30)
+#define  VLV_EDP_PSR_SDP_FREQ_ONCE	(1<<31)
+#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME	(1<<30)
+#define VLV_VSCSDP(pipe)	_PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA			(VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB			(VLV_DISPLAY_BASE + 0x61094)
+#define  VLV_EDP_PSR_LAST_STATE_MASK	(7<<3)
+#define  VLV_EDP_PSR_CURR_STATE_MASK	7
+#define  VLV_EDP_PSR_DISABLED		(0<<0)
+#define  VLV_EDP_PSR_INACTIVE		(1<<0)
+#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE	(2<<0)
+#define  VLV_EDP_PSR_ACTIVE_NORFB_UP	(3<<0)
+#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE	(4<<0)
+#define  VLV_EDP_PSR_EXIT		(5<<0)
+#define  VLV_EDP_PSR_IN_TRANS		(1<<7)
+#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
@@ -2762,7 +2825,8 @@
 #define   DC_BALANCE_RESET			(1 << 25)
 #define PORT_DFT2_G4X		(dev_priv->info.display_mmio_offset + 0x61154)
 #define   DC_BALANCE_RESET_VLV			(1 << 31)
-#define   PIPE_SCRAMBLE_RESET_MASK		(0x3 << 0)
+#define   PIPE_SCRAMBLE_RESET_MASK		((1 << 14) | (0x3 << 0))
+#define   PIPE_C_SCRAMBLE_RESET			(1 << 14) /* chv */
 #define   PIPE_B_SCRAMBLE_RESET			(1 << 1)
 #define   PIPE_A_SCRAMBLE_RESET			(1 << 0)
 
@@ -3704,6 +3768,11 @@
 #define   DP_AUX_CH_CTL_PRECHARGE_TEST	    (1 << 11)
 #define   DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK    (0x7ff)
 #define   DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT   0
+#define   DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL	(1 << 14)
+#define   DP_AUX_CH_CTL_FS_DATA_AUX_REG_SKL	(1 << 13)
+#define   DP_AUX_CH_CTL_GTC_DATA_AUX_REG_SKL	(1 << 12)
+#define   DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL_MASK (1f << 5)
+#define   DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(c) (((c) - 1) << 5)
 #define   DP_AUX_CH_CTL_SYNC_PULSE_SKL(c)   ((c) - 1)
 
 /*
@@ -5158,6 +5227,9 @@
 #define COMMON_SLICE_CHICKEN2			0x7014
 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE	(1<<0)
 
+#define HIZ_CHICKEN				0x7018
+# define CHV_HZ_8X8_MODE_IN_1X			(1<<15)
+
 #define GEN7_L3SQCREG1				0xB010
 #define  VLV_B0_WA_L3SQCREG1_VALUE		0x00D30000
 
@@ -6005,6 +6077,13 @@
 #define GEN6_PMINTRMSK				0xA168
 #define GEN8_PMINTR_REDIRECT_TO_NON_DISP	(1<<31)
 #define VLV_PWRDWNUPCTL				0xA294
+#define GEN9_MEDIA_PG_IDLE_HYSTERESIS		0xA0C4
+#define GEN9_RENDER_PG_IDLE_HYSTERESIS		0xA0C8
+#define GEN9_PG_ENABLE				0xA210
+
+#define VLV_CHICKEN_3				(VLV_DISPLAY_BASE + 0x7040C)
+#define  PIXEL_OVERLAP_CNT_MASK			(3 << 30)
+#define  PIXEL_OVERLAP_CNT_SHIFT		30
 
 #define GEN6_PMISR				0x44020
 #define GEN6_PMIMR				0x44024 /* rps_lock */
@@ -6119,6 +6198,7 @@
 #define  HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE    (1 << 6)
 
 #define HALF_SLICE_CHICKEN3		0xe184
+#define   HSW_SAMPLE_C_PERFORMANCE	(1<<9)
 #define   GEN8_CENTROID_PIXEL_OPT_DIS	(1<<8)
 #define   GEN8_SAMPLER_POWER_BYPASS_DIS	(1<<1)
 
@@ -6631,29 +6711,31 @@
 #define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
 #define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
 
-/* VLV MIPI registers */
+/* MIPI DSI registers */
+
+#define _MIPI_PORT(port, a, c)	_PORT3(port, a, 0, c)	/* ports A and C only */
 
 #define _MIPIA_PORT_CTRL			(VLV_DISPLAY_BASE + 0x61190)
-#define _MIPIB_PORT_CTRL			(VLV_DISPLAY_BASE + 0x61700)
-#define MIPI_PORT_CTRL(tc)		_TRANSCODER(tc, _MIPIA_PORT_CTRL, \
-						_MIPIB_PORT_CTRL)
-#define  DPI_ENABLE					(1 << 31) /* A + B */
+#define _MIPIC_PORT_CTRL			(VLV_DISPLAY_BASE + 0x61700)
+#define MIPI_PORT_CTRL(port)	_MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
+#define  DPI_ENABLE					(1 << 31) /* A + C */
 #define  MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT		27
 #define  MIPIA_MIPI4DPHY_DELAY_COUNT_MASK		(0xf << 27)
+#define  DUAL_LINK_MODE_SHIFT				26
 #define  DUAL_LINK_MODE_MASK				(1 << 26)
 #define  DUAL_LINK_MODE_FRONT_BACK			(0 << 26)
 #define  DUAL_LINK_MODE_PIXEL_ALTERNATIVE		(1 << 26)
-#define  DITHERING_ENABLE				(1 << 25) /* A + B */
+#define  DITHERING_ENABLE				(1 << 25) /* A + C */
 #define  FLOPPED_HSTX					(1 << 23)
 #define  DE_INVERT					(1 << 19) /* XXX */
 #define  MIPIA_FLISDSI_DELAY_COUNT_SHIFT		18
 #define  MIPIA_FLISDSI_DELAY_COUNT_MASK			(0xf << 18)
 #define  AFE_LATCHOUT					(1 << 17)
 #define  LP_OUTPUT_HOLD					(1 << 16)
-#define  MIPIB_FLISDSI_DELAY_COUNT_HIGH_SHIFT		15
-#define  MIPIB_FLISDSI_DELAY_COUNT_HIGH_MASK		(1 << 15)
-#define  MIPIB_MIPI4DPHY_DELAY_COUNT_SHIFT		11
-#define  MIPIB_MIPI4DPHY_DELAY_COUNT_MASK		(0xf << 11)
+#define  MIPIC_FLISDSI_DELAY_COUNT_HIGH_SHIFT		15
+#define  MIPIC_FLISDSI_DELAY_COUNT_HIGH_MASK		(1 << 15)
+#define  MIPIC_MIPI4DPHY_DELAY_COUNT_SHIFT		11
+#define  MIPIC_MIPI4DPHY_DELAY_COUNT_MASK		(0xf << 11)
 #define  CSB_SHIFT					9
 #define  CSB_MASK					(3 << 9)
 #define  CSB_20MHZ					(0 << 9)
@@ -6662,10 +6744,10 @@
 #define  BANDGAP_MASK					(1 << 8)
 #define  BANDGAP_PNW_CIRCUIT				(0 << 8)
 #define  BANDGAP_LNC_CIRCUIT				(1 << 8)
-#define  MIPIB_FLISDSI_DELAY_COUNT_LOW_SHIFT		5
-#define  MIPIB_FLISDSI_DELAY_COUNT_LOW_MASK		(7 << 5)
-#define  TEARING_EFFECT_DELAY				(1 << 4) /* A + B */
-#define  TEARING_EFFECT_SHIFT				2 /* A + B */
+#define  MIPIC_FLISDSI_DELAY_COUNT_LOW_SHIFT		5
+#define  MIPIC_FLISDSI_DELAY_COUNT_LOW_MASK		(7 << 5)
+#define  TEARING_EFFECT_DELAY				(1 << 4) /* A + C */
+#define  TEARING_EFFECT_SHIFT				2 /* A + C */
 #define  TEARING_EFFECT_MASK				(3 << 2)
 #define  TEARING_EFFECT_OFF				(0 << 2)
 #define  TEARING_EFFECT_DSI				(1 << 2)
@@ -6677,9 +6759,9 @@
 #define  LANE_CONFIGURATION_DUAL_LINK_B			(2 << 0)
 
 #define _MIPIA_TEARING_CTRL			(VLV_DISPLAY_BASE + 0x61194)
-#define _MIPIB_TEARING_CTRL			(VLV_DISPLAY_BASE + 0x61704)
-#define MIPI_TEARING_CTRL(tc)			_TRANSCODER(tc, \
-				_MIPIA_TEARING_CTRL, _MIPIB_TEARING_CTRL)
+#define _MIPIC_TEARING_CTRL			(VLV_DISPLAY_BASE + 0x61704)
+#define MIPI_TEARING_CTRL(port)			_MIPI_PORT(port, \
+				_MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
 #define  TEARING_EFFECT_DELAY_SHIFT			0
 #define  TEARING_EFFECT_DELAY_MASK			(0xffff << 0)
 
@@ -6689,9 +6771,9 @@
 /* MIPI DSI Controller and D-PHY registers */
 
 #define _MIPIA_DEVICE_READY		(dev_priv->mipi_mmio_base + 0xb000)
-#define _MIPIB_DEVICE_READY		(dev_priv->mipi_mmio_base + 0xb800)
-#define MIPI_DEVICE_READY(tc)		_TRANSCODER(tc, _MIPIA_DEVICE_READY, \
-						_MIPIB_DEVICE_READY)
+#define _MIPIC_DEVICE_READY		(dev_priv->mipi_mmio_base + 0xb800)
+#define MIPI_DEVICE_READY(port)		_MIPI_PORT(port, _MIPIA_DEVICE_READY, \
+						_MIPIC_DEVICE_READY)
 #define  BUS_POSSESSION					(1 << 3) /* set to give bus to receiver */
 #define  ULPS_STATE_MASK				(3 << 1)
 #define  ULPS_STATE_ENTER				(2 << 1)
@@ -6700,13 +6782,13 @@
 #define  DEVICE_READY					(1 << 0)
 
 #define _MIPIA_INTR_STAT		(dev_priv->mipi_mmio_base + 0xb004)
-#define _MIPIB_INTR_STAT		(dev_priv->mipi_mmio_base + 0xb804)
-#define MIPI_INTR_STAT(tc)		_TRANSCODER(tc, _MIPIA_INTR_STAT, \
-					_MIPIB_INTR_STAT)
+#define _MIPIC_INTR_STAT		(dev_priv->mipi_mmio_base + 0xb804)
+#define MIPI_INTR_STAT(port)		_MIPI_PORT(port, _MIPIA_INTR_STAT, \
+					_MIPIC_INTR_STAT)
 #define _MIPIA_INTR_EN			(dev_priv->mipi_mmio_base + 0xb008)
-#define _MIPIB_INTR_EN			(dev_priv->mipi_mmio_base + 0xb808)
-#define MIPI_INTR_EN(tc)		_TRANSCODER(tc, _MIPIA_INTR_EN, \
-					_MIPIB_INTR_EN)
+#define _MIPIC_INTR_EN			(dev_priv->mipi_mmio_base + 0xb808)
+#define MIPI_INTR_EN(port)		_MIPI_PORT(port, _MIPIA_INTR_EN, \
+					_MIPIC_INTR_EN)
 #define  TEARING_EFFECT					(1 << 31)
 #define  SPL_PKT_SENT_INTERRUPT				(1 << 30)
 #define  GEN_READ_DATA_AVAIL				(1 << 29)
@@ -6741,9 +6823,9 @@
 #define  RXSOT_ERROR					(1 << 0)
 
 #define _MIPIA_DSI_FUNC_PRG		(dev_priv->mipi_mmio_base + 0xb00c)
-#define _MIPIB_DSI_FUNC_PRG		(dev_priv->mipi_mmio_base + 0xb80c)
-#define MIPI_DSI_FUNC_PRG(tc)		_TRANSCODER(tc, _MIPIA_DSI_FUNC_PRG, \
-						_MIPIB_DSI_FUNC_PRG)
+#define _MIPIC_DSI_FUNC_PRG		(dev_priv->mipi_mmio_base + 0xb80c)
+#define MIPI_DSI_FUNC_PRG(port)		_MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \
+						_MIPIC_DSI_FUNC_PRG)
 #define  CMD_MODE_DATA_WIDTH_MASK			(7 << 13)
 #define  CMD_MODE_NOT_SUPPORTED				(0 << 13)
 #define  CMD_MODE_DATA_WIDTH_16_BIT			(1 << 13)
@@ -6765,93 +6847,93 @@
 #define  DATA_LANES_PRG_REG_MASK			(7 << 0)
 
 #define _MIPIA_HS_TX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb010)
-#define _MIPIB_HS_TX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb810)
-#define MIPI_HS_TX_TIMEOUT(tc)	_TRANSCODER(tc, _MIPIA_HS_TX_TIMEOUT, \
-					_MIPIB_HS_TX_TIMEOUT)
+#define _MIPIC_HS_TX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb810)
+#define MIPI_HS_TX_TIMEOUT(port)	_MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \
+					_MIPIC_HS_TX_TIMEOUT)
 #define  HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK		0xffffff
 
 #define _MIPIA_LP_RX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb014)
-#define _MIPIB_LP_RX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb814)
-#define MIPI_LP_RX_TIMEOUT(tc)	_TRANSCODER(tc, _MIPIA_LP_RX_TIMEOUT, \
-					_MIPIB_LP_RX_TIMEOUT)
+#define _MIPIC_LP_RX_TIMEOUT		(dev_priv->mipi_mmio_base + 0xb814)
+#define MIPI_LP_RX_TIMEOUT(port)	_MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \
+					_MIPIC_LP_RX_TIMEOUT)
 #define  LOW_POWER_RX_TIMEOUT_COUNTER_MASK		0xffffff
 
 #define _MIPIA_TURN_AROUND_TIMEOUT	(dev_priv->mipi_mmio_base + 0xb018)
-#define _MIPIB_TURN_AROUND_TIMEOUT	(dev_priv->mipi_mmio_base + 0xb818)
-#define MIPI_TURN_AROUND_TIMEOUT(tc)	_TRANSCODER(tc, \
-			_MIPIA_TURN_AROUND_TIMEOUT, _MIPIB_TURN_AROUND_TIMEOUT)
+#define _MIPIC_TURN_AROUND_TIMEOUT	(dev_priv->mipi_mmio_base + 0xb818)
+#define MIPI_TURN_AROUND_TIMEOUT(port)	_MIPI_PORT(port, \
+			_MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
 #define  TURN_AROUND_TIMEOUT_MASK			0x3f
 
 #define _MIPIA_DEVICE_RESET_TIMER	(dev_priv->mipi_mmio_base + 0xb01c)
-#define _MIPIB_DEVICE_RESET_TIMER	(dev_priv->mipi_mmio_base + 0xb81c)
-#define MIPI_DEVICE_RESET_TIMER(tc)	_TRANSCODER(tc, \
-			_MIPIA_DEVICE_RESET_TIMER, _MIPIB_DEVICE_RESET_TIMER)
+#define _MIPIC_DEVICE_RESET_TIMER	(dev_priv->mipi_mmio_base + 0xb81c)
+#define MIPI_DEVICE_RESET_TIMER(port)	_MIPI_PORT(port, \
+			_MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
 #define  DEVICE_RESET_TIMER_MASK			0xffff
 
 #define _MIPIA_DPI_RESOLUTION		(dev_priv->mipi_mmio_base + 0xb020)
-#define _MIPIB_DPI_RESOLUTION		(dev_priv->mipi_mmio_base + 0xb820)
-#define MIPI_DPI_RESOLUTION(tc)	_TRANSCODER(tc, _MIPIA_DPI_RESOLUTION, \
-					_MIPIB_DPI_RESOLUTION)
+#define _MIPIC_DPI_RESOLUTION		(dev_priv->mipi_mmio_base + 0xb820)
+#define MIPI_DPI_RESOLUTION(port)	_MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \
+					_MIPIC_DPI_RESOLUTION)
 #define  VERTICAL_ADDRESS_SHIFT				16
 #define  VERTICAL_ADDRESS_MASK				(0xffff << 16)
 #define  HORIZONTAL_ADDRESS_SHIFT			0
 #define  HORIZONTAL_ADDRESS_MASK			0xffff
 
 #define _MIPIA_DBI_FIFO_THROTTLE	(dev_priv->mipi_mmio_base + 0xb024)
-#define _MIPIB_DBI_FIFO_THROTTLE	(dev_priv->mipi_mmio_base + 0xb824)
-#define MIPI_DBI_FIFO_THROTTLE(tc)	_TRANSCODER(tc, \
-			_MIPIA_DBI_FIFO_THROTTLE, _MIPIB_DBI_FIFO_THROTTLE)
+#define _MIPIC_DBI_FIFO_THROTTLE	(dev_priv->mipi_mmio_base + 0xb824)
+#define MIPI_DBI_FIFO_THROTTLE(port)	_MIPI_PORT(port, \
+			_MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
 #define  DBI_FIFO_EMPTY_HALF				(0 << 0)
 #define  DBI_FIFO_EMPTY_QUARTER				(1 << 0)
 #define  DBI_FIFO_EMPTY_7_LOCATIONS			(2 << 0)
 
 /* regs below are bits 15:0 */
 #define _MIPIA_HSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb028)
-#define _MIPIB_HSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb828)
-#define MIPI_HSYNC_PADDING_COUNT(tc)	_TRANSCODER(tc, \
-			_MIPIA_HSYNC_PADDING_COUNT, _MIPIB_HSYNC_PADDING_COUNT)
+#define _MIPIC_HSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb828)
+#define MIPI_HSYNC_PADDING_COUNT(port)	_MIPI_PORT(port, \
+			_MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
 
 #define _MIPIA_HBP_COUNT		(dev_priv->mipi_mmio_base + 0xb02c)
-#define _MIPIB_HBP_COUNT		(dev_priv->mipi_mmio_base + 0xb82c)
-#define MIPI_HBP_COUNT(tc)		_TRANSCODER(tc, _MIPIA_HBP_COUNT, \
-					_MIPIB_HBP_COUNT)
+#define _MIPIC_HBP_COUNT		(dev_priv->mipi_mmio_base + 0xb82c)
+#define MIPI_HBP_COUNT(port)		_MIPI_PORT(port, _MIPIA_HBP_COUNT, \
+					_MIPIC_HBP_COUNT)
 
 #define _MIPIA_HFP_COUNT		(dev_priv->mipi_mmio_base + 0xb030)
-#define _MIPIB_HFP_COUNT		(dev_priv->mipi_mmio_base + 0xb830)
-#define MIPI_HFP_COUNT(tc)		_TRANSCODER(tc, _MIPIA_HFP_COUNT, \
-					_MIPIB_HFP_COUNT)
+#define _MIPIC_HFP_COUNT		(dev_priv->mipi_mmio_base + 0xb830)
+#define MIPI_HFP_COUNT(port)		_MIPI_PORT(port, _MIPIA_HFP_COUNT, \
+					_MIPIC_HFP_COUNT)
 
 #define _MIPIA_HACTIVE_AREA_COUNT	(dev_priv->mipi_mmio_base + 0xb034)
-#define _MIPIB_HACTIVE_AREA_COUNT	(dev_priv->mipi_mmio_base + 0xb834)
-#define MIPI_HACTIVE_AREA_COUNT(tc)	_TRANSCODER(tc, \
-			_MIPIA_HACTIVE_AREA_COUNT, _MIPIB_HACTIVE_AREA_COUNT)
+#define _MIPIC_HACTIVE_AREA_COUNT	(dev_priv->mipi_mmio_base + 0xb834)
+#define MIPI_HACTIVE_AREA_COUNT(port)	_MIPI_PORT(port, \
+			_MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
 
 #define _MIPIA_VSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb038)
-#define _MIPIB_VSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb838)
-#define MIPI_VSYNC_PADDING_COUNT(tc)	_TRANSCODER(tc, \
-			_MIPIA_VSYNC_PADDING_COUNT, _MIPIB_VSYNC_PADDING_COUNT)
+#define _MIPIC_VSYNC_PADDING_COUNT	(dev_priv->mipi_mmio_base + 0xb838)
+#define MIPI_VSYNC_PADDING_COUNT(port)	_MIPI_PORT(port, \
+			_MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
 
 #define _MIPIA_VBP_COUNT		(dev_priv->mipi_mmio_base + 0xb03c)
-#define _MIPIB_VBP_COUNT		(dev_priv->mipi_mmio_base + 0xb83c)
-#define MIPI_VBP_COUNT(tc)		_TRANSCODER(tc, _MIPIA_VBP_COUNT, \
-					_MIPIB_VBP_COUNT)
+#define _MIPIC_VBP_COUNT		(dev_priv->mipi_mmio_base + 0xb83c)
+#define MIPI_VBP_COUNT(port)		_MIPI_PORT(port, _MIPIA_VBP_COUNT, \
+					_MIPIC_VBP_COUNT)
 
 #define _MIPIA_VFP_COUNT		(dev_priv->mipi_mmio_base + 0xb040)
-#define _MIPIB_VFP_COUNT		(dev_priv->mipi_mmio_base + 0xb840)
-#define MIPI_VFP_COUNT(tc)		_TRANSCODER(tc, _MIPIA_VFP_COUNT, \
-					_MIPIB_VFP_COUNT)
+#define _MIPIC_VFP_COUNT		(dev_priv->mipi_mmio_base + 0xb840)
+#define MIPI_VFP_COUNT(port)		_MIPI_PORT(port, _MIPIA_VFP_COUNT, \
+					_MIPIC_VFP_COUNT)
 
 #define _MIPIA_HIGH_LOW_SWITCH_COUNT	(dev_priv->mipi_mmio_base + 0xb044)
-#define _MIPIB_HIGH_LOW_SWITCH_COUNT	(dev_priv->mipi_mmio_base + 0xb844)
-#define MIPI_HIGH_LOW_SWITCH_COUNT(tc)	_TRANSCODER(tc,	\
-		_MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIB_HIGH_LOW_SWITCH_COUNT)
+#define _MIPIC_HIGH_LOW_SWITCH_COUNT	(dev_priv->mipi_mmio_base + 0xb844)
+#define MIPI_HIGH_LOW_SWITCH_COUNT(port)	_MIPI_PORT(port,	\
+		_MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
 
 /* regs above are bits 15:0 */
 
 #define _MIPIA_DPI_CONTROL		(dev_priv->mipi_mmio_base + 0xb048)
-#define _MIPIB_DPI_CONTROL		(dev_priv->mipi_mmio_base + 0xb848)
-#define MIPI_DPI_CONTROL(tc)		_TRANSCODER(tc, _MIPIA_DPI_CONTROL, \
-					_MIPIB_DPI_CONTROL)
+#define _MIPIC_DPI_CONTROL		(dev_priv->mipi_mmio_base + 0xb848)
+#define MIPI_DPI_CONTROL(port)		_MIPI_PORT(port, _MIPIA_DPI_CONTROL, \
+					_MIPIC_DPI_CONTROL)
 #define  DPI_LP_MODE					(1 << 6)
 #define  BACKLIGHT_OFF					(1 << 5)
 #define  BACKLIGHT_ON					(1 << 4)
@@ -6861,30 +6943,30 @@
 #define  SHUTDOWN					(1 << 0)
 
 #define _MIPIA_DPI_DATA			(dev_priv->mipi_mmio_base + 0xb04c)
-#define _MIPIB_DPI_DATA			(dev_priv->mipi_mmio_base + 0xb84c)
-#define MIPI_DPI_DATA(tc)		_TRANSCODER(tc, _MIPIA_DPI_DATA, \
-					_MIPIB_DPI_DATA)
+#define _MIPIC_DPI_DATA			(dev_priv->mipi_mmio_base + 0xb84c)
+#define MIPI_DPI_DATA(port)		_MIPI_PORT(port, _MIPIA_DPI_DATA, \
+					_MIPIC_DPI_DATA)
 #define  COMMAND_BYTE_SHIFT				0
 #define  COMMAND_BYTE_MASK				(0x3f << 0)
 
 #define _MIPIA_INIT_COUNT		(dev_priv->mipi_mmio_base + 0xb050)
-#define _MIPIB_INIT_COUNT		(dev_priv->mipi_mmio_base + 0xb850)
-#define MIPI_INIT_COUNT(tc)		_TRANSCODER(tc, _MIPIA_INIT_COUNT, \
-					_MIPIB_INIT_COUNT)
+#define _MIPIC_INIT_COUNT		(dev_priv->mipi_mmio_base + 0xb850)
+#define MIPI_INIT_COUNT(port)		_MIPI_PORT(port, _MIPIA_INIT_COUNT, \
+					_MIPIC_INIT_COUNT)
 #define  MASTER_INIT_TIMER_SHIFT			0
 #define  MASTER_INIT_TIMER_MASK				(0xffff << 0)
 
 #define _MIPIA_MAX_RETURN_PKT_SIZE	(dev_priv->mipi_mmio_base + 0xb054)
-#define _MIPIB_MAX_RETURN_PKT_SIZE	(dev_priv->mipi_mmio_base + 0xb854)
-#define MIPI_MAX_RETURN_PKT_SIZE(tc)	_TRANSCODER(tc, \
-			_MIPIA_MAX_RETURN_PKT_SIZE, _MIPIB_MAX_RETURN_PKT_SIZE)
+#define _MIPIC_MAX_RETURN_PKT_SIZE	(dev_priv->mipi_mmio_base + 0xb854)
+#define MIPI_MAX_RETURN_PKT_SIZE(port)	_MIPI_PORT(port, \
+			_MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE)
 #define  MAX_RETURN_PKT_SIZE_SHIFT			0
 #define  MAX_RETURN_PKT_SIZE_MASK			(0x3ff << 0)
 
 #define _MIPIA_VIDEO_MODE_FORMAT	(dev_priv->mipi_mmio_base + 0xb058)
-#define _MIPIB_VIDEO_MODE_FORMAT	(dev_priv->mipi_mmio_base + 0xb858)
-#define MIPI_VIDEO_MODE_FORMAT(tc)	_TRANSCODER(tc, \
-			_MIPIA_VIDEO_MODE_FORMAT, _MIPIB_VIDEO_MODE_FORMAT)
+#define _MIPIC_VIDEO_MODE_FORMAT	(dev_priv->mipi_mmio_base + 0xb858)
+#define MIPI_VIDEO_MODE_FORMAT(port)	_MIPI_PORT(port, \
+			_MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
 #define  RANDOM_DPI_DISPLAY_RESOLUTION			(1 << 4)
 #define  DISABLE_VIDEO_BTA				(1 << 3)
 #define  IP_TG_CONFIG					(1 << 2)
@@ -6893,9 +6975,9 @@
 #define  VIDEO_MODE_BURST				(3 << 0)
 
 #define _MIPIA_EOT_DISABLE		(dev_priv->mipi_mmio_base + 0xb05c)
-#define _MIPIB_EOT_DISABLE		(dev_priv->mipi_mmio_base + 0xb85c)
-#define MIPI_EOT_DISABLE(tc)		_TRANSCODER(tc, _MIPIA_EOT_DISABLE, \
-					_MIPIB_EOT_DISABLE)
+#define _MIPIC_EOT_DISABLE		(dev_priv->mipi_mmio_base + 0xb85c)
+#define MIPI_EOT_DISABLE(port)		_MIPI_PORT(port, _MIPIA_EOT_DISABLE, \
+					_MIPIC_EOT_DISABLE)
 #define  LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE		(1 << 7)
 #define  HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE		(1 << 6)
 #define  LOW_CONTENTION_RECOVERY_DISABLE		(1 << 5)
@@ -6906,32 +6988,32 @@
 #define  EOT_DISABLE					(1 << 0)
 
 #define _MIPIA_LP_BYTECLK		(dev_priv->mipi_mmio_base + 0xb060)
-#define _MIPIB_LP_BYTECLK		(dev_priv->mipi_mmio_base + 0xb860)
-#define MIPI_LP_BYTECLK(tc)		_TRANSCODER(tc, _MIPIA_LP_BYTECLK, \
-					_MIPIB_LP_BYTECLK)
+#define _MIPIC_LP_BYTECLK		(dev_priv->mipi_mmio_base + 0xb860)
+#define MIPI_LP_BYTECLK(port)		_MIPI_PORT(port, _MIPIA_LP_BYTECLK, \
+					_MIPIC_LP_BYTECLK)
 #define  LP_BYTECLK_SHIFT				0
 #define  LP_BYTECLK_MASK				(0xffff << 0)
 
 /* bits 31:0 */
 #define _MIPIA_LP_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb064)
-#define _MIPIB_LP_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb864)
-#define MIPI_LP_GEN_DATA(tc)		_TRANSCODER(tc, _MIPIA_LP_GEN_DATA, \
-					_MIPIB_LP_GEN_DATA)
+#define _MIPIC_LP_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb864)
+#define MIPI_LP_GEN_DATA(port)		_MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \
+					_MIPIC_LP_GEN_DATA)
 
 /* bits 31:0 */
 #define _MIPIA_HS_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb068)
-#define _MIPIB_HS_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb868)
-#define MIPI_HS_GEN_DATA(tc)		_TRANSCODER(tc, _MIPIA_HS_GEN_DATA, \
-					_MIPIB_HS_GEN_DATA)
+#define _MIPIC_HS_GEN_DATA		(dev_priv->mipi_mmio_base + 0xb868)
+#define MIPI_HS_GEN_DATA(port)		_MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \
+					_MIPIC_HS_GEN_DATA)
 
 #define _MIPIA_LP_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb06c)
-#define _MIPIB_LP_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb86c)
-#define MIPI_LP_GEN_CTRL(tc)		_TRANSCODER(tc, _MIPIA_LP_GEN_CTRL, \
-					_MIPIB_LP_GEN_CTRL)
+#define _MIPIC_LP_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb86c)
+#define MIPI_LP_GEN_CTRL(port)		_MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \
+					_MIPIC_LP_GEN_CTRL)
 #define _MIPIA_HS_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb070)
-#define _MIPIB_HS_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb870)
-#define MIPI_HS_GEN_CTRL(tc)		_TRANSCODER(tc, _MIPIA_HS_GEN_CTRL, \
-					_MIPIB_HS_GEN_CTRL)
+#define _MIPIC_HS_GEN_CTRL		(dev_priv->mipi_mmio_base + 0xb870)
+#define MIPI_HS_GEN_CTRL(port)		_MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \
+					_MIPIC_HS_GEN_CTRL)
 #define  LONG_PACKET_WORD_COUNT_SHIFT			8
 #define  LONG_PACKET_WORD_COUNT_MASK			(0xffff << 8)
 #define  SHORT_PACKET_PARAM_SHIFT			8
@@ -6943,9 +7025,9 @@
 /* data type values, see include/video/mipi_display.h */
 
 #define _MIPIA_GEN_FIFO_STAT		(dev_priv->mipi_mmio_base + 0xb074)
-#define _MIPIB_GEN_FIFO_STAT		(dev_priv->mipi_mmio_base + 0xb874)
-#define MIPI_GEN_FIFO_STAT(tc)	_TRANSCODER(tc, _MIPIA_GEN_FIFO_STAT, \
-					_MIPIB_GEN_FIFO_STAT)
+#define _MIPIC_GEN_FIFO_STAT		(dev_priv->mipi_mmio_base + 0xb874)
+#define MIPI_GEN_FIFO_STAT(port)	_MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \
+					_MIPIC_GEN_FIFO_STAT)
 #define  DPI_FIFO_EMPTY					(1 << 28)
 #define  DBI_FIFO_EMPTY					(1 << 27)
 #define  LP_CTRL_FIFO_EMPTY				(1 << 26)
@@ -6962,17 +7044,17 @@
 #define  HS_DATA_FIFO_FULL				(1 << 0)
 
 #define _MIPIA_HS_LS_DBI_ENABLE		(dev_priv->mipi_mmio_base + 0xb078)
-#define _MIPIB_HS_LS_DBI_ENABLE		(dev_priv->mipi_mmio_base + 0xb878)
-#define MIPI_HS_LP_DBI_ENABLE(tc)	_TRANSCODER(tc, \
-			_MIPIA_HS_LS_DBI_ENABLE, _MIPIB_HS_LS_DBI_ENABLE)
+#define _MIPIC_HS_LS_DBI_ENABLE		(dev_priv->mipi_mmio_base + 0xb878)
+#define MIPI_HS_LP_DBI_ENABLE(port)	_MIPI_PORT(port, \
+			_MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
 #define  DBI_HS_LP_MODE_MASK				(1 << 0)
 #define  DBI_LP_MODE					(1 << 0)
 #define  DBI_HS_MODE					(0 << 0)
 
 #define _MIPIA_DPHY_PARAM		(dev_priv->mipi_mmio_base + 0xb080)
-#define _MIPIB_DPHY_PARAM		(dev_priv->mipi_mmio_base + 0xb880)
-#define MIPI_DPHY_PARAM(tc)		_TRANSCODER(tc, _MIPIA_DPHY_PARAM, \
-					_MIPIB_DPHY_PARAM)
+#define _MIPIC_DPHY_PARAM		(dev_priv->mipi_mmio_base + 0xb880)
+#define MIPI_DPHY_PARAM(port)		_MIPI_PORT(port, _MIPIA_DPHY_PARAM, \
+					_MIPIC_DPHY_PARAM)
 #define  EXIT_ZERO_COUNT_SHIFT				24
 #define  EXIT_ZERO_COUNT_MASK				(0x3f << 24)
 #define  TRAIL_COUNT_SHIFT				16
@@ -6984,36 +7066,36 @@
 
 /* bits 31:0 */
 #define _MIPIA_DBI_BW_CTRL		(dev_priv->mipi_mmio_base + 0xb084)
-#define _MIPIB_DBI_BW_CTRL		(dev_priv->mipi_mmio_base + 0xb884)
-#define MIPI_DBI_BW_CTRL(tc)		_TRANSCODER(tc, _MIPIA_DBI_BW_CTRL, \
-					_MIPIB_DBI_BW_CTRL)
+#define _MIPIC_DBI_BW_CTRL		(dev_priv->mipi_mmio_base + 0xb884)
+#define MIPI_DBI_BW_CTRL(port)		_MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \
+					_MIPIC_DBI_BW_CTRL)
 
 #define _MIPIA_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base \
 							+ 0xb088)
-#define _MIPIB_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base \
+#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT		(dev_priv->mipi_mmio_base \
 							+ 0xb888)
-#define MIPI_CLK_LANE_SWITCH_TIME_CNT(tc)	_TRANSCODER(tc, \
-	_MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIB_CLK_LANE_SWITCH_TIME_CNT)
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port)	_MIPI_PORT(port, \
+	_MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
 #define  LP_HS_SSW_CNT_SHIFT				16
 #define  LP_HS_SSW_CNT_MASK				(0xffff << 16)
 #define  HS_LP_PWR_SW_CNT_SHIFT				0
 #define  HS_LP_PWR_SW_CNT_MASK				(0xffff << 0)
 
 #define _MIPIA_STOP_STATE_STALL		(dev_priv->mipi_mmio_base + 0xb08c)
-#define _MIPIB_STOP_STATE_STALL		(dev_priv->mipi_mmio_base + 0xb88c)
-#define MIPI_STOP_STATE_STALL(tc)	_TRANSCODER(tc, \
-			_MIPIA_STOP_STATE_STALL, _MIPIB_STOP_STATE_STALL)
+#define _MIPIC_STOP_STATE_STALL		(dev_priv->mipi_mmio_base + 0xb88c)
+#define MIPI_STOP_STATE_STALL(port)	_MIPI_PORT(port, \
+			_MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
 #define  STOP_STATE_STALL_COUNTER_SHIFT			0
 #define  STOP_STATE_STALL_COUNTER_MASK			(0xff << 0)
 
 #define _MIPIA_INTR_STAT_REG_1		(dev_priv->mipi_mmio_base + 0xb090)
-#define _MIPIB_INTR_STAT_REG_1		(dev_priv->mipi_mmio_base + 0xb890)
-#define MIPI_INTR_STAT_REG_1(tc)	_TRANSCODER(tc, \
-				_MIPIA_INTR_STAT_REG_1, _MIPIB_INTR_STAT_REG_1)
+#define _MIPIC_INTR_STAT_REG_1		(dev_priv->mipi_mmio_base + 0xb890)
+#define MIPI_INTR_STAT_REG_1(port)	_MIPI_PORT(port, \
+				_MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
 #define _MIPIA_INTR_EN_REG_1		(dev_priv->mipi_mmio_base + 0xb094)
-#define _MIPIB_INTR_EN_REG_1		(dev_priv->mipi_mmio_base + 0xb894)
-#define MIPI_INTR_EN_REG_1(tc)	_TRANSCODER(tc, _MIPIA_INTR_EN_REG_1, \
-					_MIPIB_INTR_EN_REG_1)
+#define _MIPIC_INTR_EN_REG_1		(dev_priv->mipi_mmio_base + 0xb894)
+#define MIPI_INTR_EN_REG_1(port)	_MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \
+					_MIPIC_INTR_EN_REG_1)
 #define  RX_CONTENTION_DETECTED				(1 << 0)
 
 /* XXX: only pipe A ?!? */
@@ -7032,9 +7114,9 @@
 /* MIPI adapter registers */
 
 #define _MIPIA_CTRL			(dev_priv->mipi_mmio_base + 0xb104)
-#define _MIPIB_CTRL			(dev_priv->mipi_mmio_base + 0xb904)
-#define MIPI_CTRL(tc)			_TRANSCODER(tc, _MIPIA_CTRL, \
-					_MIPIB_CTRL)
+#define _MIPIC_CTRL			(dev_priv->mipi_mmio_base + 0xb904)
+#define MIPI_CTRL(port)			_MIPI_PORT(port, _MIPIA_CTRL, \
+					_MIPIC_CTRL)
 #define  ESCAPE_CLOCK_DIVIDER_SHIFT			5 /* A only */
 #define  ESCAPE_CLOCK_DIVIDER_MASK			(3 << 5)
 #define  ESCAPE_CLOCK_DIVIDER_1				(0 << 5)
@@ -7047,24 +7129,24 @@
 #define  RGB_FLIP_TO_BGR				(1 << 2)
 
 #define _MIPIA_DATA_ADDRESS		(dev_priv->mipi_mmio_base + 0xb108)
-#define _MIPIB_DATA_ADDRESS		(dev_priv->mipi_mmio_base + 0xb908)
-#define MIPI_DATA_ADDRESS(tc)		_TRANSCODER(tc, _MIPIA_DATA_ADDRESS, \
-					_MIPIB_DATA_ADDRESS)
+#define _MIPIC_DATA_ADDRESS		(dev_priv->mipi_mmio_base + 0xb908)
+#define MIPI_DATA_ADDRESS(port)		_MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
+					_MIPIC_DATA_ADDRESS)
 #define  DATA_MEM_ADDRESS_SHIFT				5
 #define  DATA_MEM_ADDRESS_MASK				(0x7ffffff << 5)
 #define  DATA_VALID					(1 << 0)
 
 #define _MIPIA_DATA_LENGTH		(dev_priv->mipi_mmio_base + 0xb10c)
-#define _MIPIB_DATA_LENGTH		(dev_priv->mipi_mmio_base + 0xb90c)
-#define MIPI_DATA_LENGTH(tc)		_TRANSCODER(tc, _MIPIA_DATA_LENGTH, \
-					_MIPIB_DATA_LENGTH)
+#define _MIPIC_DATA_LENGTH		(dev_priv->mipi_mmio_base + 0xb90c)
+#define MIPI_DATA_LENGTH(port)		_MIPI_PORT(port, _MIPIA_DATA_LENGTH, \
+					_MIPIC_DATA_LENGTH)
 #define  DATA_LENGTH_SHIFT				0
 #define  DATA_LENGTH_MASK				(0xfffff << 0)
 
 #define _MIPIA_COMMAND_ADDRESS		(dev_priv->mipi_mmio_base + 0xb110)
-#define _MIPIB_COMMAND_ADDRESS		(dev_priv->mipi_mmio_base + 0xb910)
-#define MIPI_COMMAND_ADDRESS(tc)	_TRANSCODER(tc, \
-				_MIPIA_COMMAND_ADDRESS, _MIPIB_COMMAND_ADDRESS)
+#define _MIPIC_COMMAND_ADDRESS		(dev_priv->mipi_mmio_base + 0xb910)
+#define MIPI_COMMAND_ADDRESS(port)	_MIPI_PORT(port, \
+				_MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
 #define  COMMAND_MEM_ADDRESS_SHIFT			5
 #define  COMMAND_MEM_ADDRESS_MASK			(0x7ffffff << 5)
 #define  AUTO_PWG_ENABLE				(1 << 2)
@@ -7072,22 +7154,22 @@
 #define  COMMAND_VALID					(1 << 0)
 
 #define _MIPIA_COMMAND_LENGTH		(dev_priv->mipi_mmio_base + 0xb114)
-#define _MIPIB_COMMAND_LENGTH		(dev_priv->mipi_mmio_base + 0xb914)
-#define MIPI_COMMAND_LENGTH(tc)	_TRANSCODER(tc, _MIPIA_COMMAND_LENGTH, \
-					_MIPIB_COMMAND_LENGTH)
+#define _MIPIC_COMMAND_LENGTH		(dev_priv->mipi_mmio_base + 0xb914)
+#define MIPI_COMMAND_LENGTH(port)	_MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \
+					_MIPIC_COMMAND_LENGTH)
 #define  COMMAND_LENGTH_SHIFT(n)			(8 * (n)) /* n: 0...3 */
 #define  COMMAND_LENGTH_MASK(n)				(0xff << (8 * (n)))
 
 #define _MIPIA_READ_DATA_RETURN0	(dev_priv->mipi_mmio_base + 0xb118)
-#define _MIPIB_READ_DATA_RETURN0	(dev_priv->mipi_mmio_base + 0xb918)
-#define MIPI_READ_DATA_RETURN(tc, n) \
-	(_TRANSCODER(tc, _MIPIA_READ_DATA_RETURN0, _MIPIB_READ_DATA_RETURN0) \
+#define _MIPIC_READ_DATA_RETURN0	(dev_priv->mipi_mmio_base + 0xb918)
+#define MIPI_READ_DATA_RETURN(port, n) \
+	(_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \
 					+ 4 * (n)) /* n: 0...7 */
 
 #define _MIPIA_READ_DATA_VALID		(dev_priv->mipi_mmio_base + 0xb138)
-#define _MIPIB_READ_DATA_VALID		(dev_priv->mipi_mmio_base + 0xb938)
-#define MIPI_READ_DATA_VALID(tc)	_TRANSCODER(tc, \
-				_MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID)
+#define _MIPIC_READ_DATA_VALID		(dev_priv->mipi_mmio_base + 0xb938)
+#define MIPI_READ_DATA_VALID(port)	_MIPI_PORT(port, \
+				_MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
 #define  READ_DATA_VALID(n)				(1 << (n))
 
 /* For UMS only (deprecated): */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 2636882..9f19ed3 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -264,7 +264,7 @@
 	}
 
 	/* only restore FBC info on the platform that supports FBC*/
-	intel_disable_fbc(dev);
+	intel_fbc_disable(dev);
 
 	/* restore FBC interval */
 	if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 4a5af69..49f5ade 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -49,14 +49,14 @@
 
 	/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
 	if (IS_VALLEYVIEW(dev)) {
-		u32 reg, czcount_30ns;
+		u32 clk_reg, czcount_30ns;
 
 		if (IS_CHERRYVIEW(dev))
-			reg = CHV_CLK_CTL1;
+			clk_reg = CHV_CLK_CTL1;
 		else
-			reg = VLV_CLK_CTL2;
+			clk_reg = VLV_CLK_CTL2;
 
-		czcount_30ns = I915_READ(reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT;
+		czcount_30ns = I915_READ(clk_reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT;
 
 		if (!czcount_30ns) {
 			WARN(!czcount_30ns, "bogus CZ count value");
@@ -116,8 +116,6 @@
 {
 	struct drm_minor *dminor = dev_to_drm_minor(kdev);
 	u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
-	if (IS_VALLEYVIEW(dminor->dev))
-		rc6p_residency = 0;
 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
 }
 
@@ -126,8 +124,6 @@
 {
 	struct drm_minor *dminor = dev_to_drm_minor(kdev);
 	u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
-	if (IS_VALLEYVIEW(dminor->dev))
-		rc6pp_residency = 0;
 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
 }
 
@@ -285,7 +281,7 @@
 	.private = (void *)1
 };
 
-static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
+static ssize_t gt_act_freq_mhz_show(struct device *kdev,
 				    struct device_attribute *attr, char *buf)
 {
 	struct drm_minor *minor = dev_to_drm_minor(kdev);
@@ -301,9 +297,14 @@
 	if (IS_VALLEYVIEW(dev_priv->dev)) {
 		u32 freq;
 		freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
-		ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff);
+		ret = intel_gpu_freq(dev_priv, (freq >> 8) & 0xff);
 	} else {
-		ret = dev_priv->rps.cur_freq * GT_FREQUENCY_MULTIPLIER;
+		u32 rpstat = I915_READ(GEN6_RPSTAT1);
+		if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+			ret = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
+		else
+			ret = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
+		ret = intel_gpu_freq(dev_priv, ret);
 	}
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -312,6 +313,27 @@
 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
 }
 
+static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct drm_minor *minor = dev_to_drm_minor(kdev);
+	struct drm_device *dev = minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+	intel_runtime_pm_get(dev_priv);
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+	ret = intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	intel_runtime_pm_put(dev_priv);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
 static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
 				     struct device_attribute *attr, char *buf)
 {
@@ -319,8 +341,9 @@
 	struct drm_device *dev = minor->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+	return snprintf(buf, PAGE_SIZE,
+			"%d\n",
+			intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
 }
 
 static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
@@ -333,10 +356,7 @@
 	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
 	mutex_lock(&dev_priv->rps.hw_lock);
-	if (IS_VALLEYVIEW(dev_priv->dev))
-		ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
-	else
-		ret = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+	ret = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -360,10 +380,7 @@
 
 	mutex_lock(&dev_priv->rps.hw_lock);
 
-	if (IS_VALLEYVIEW(dev_priv->dev))
-		val = vlv_freq_opcode(dev_priv, val);
-	else
-		val /= GT_FREQUENCY_MULTIPLIER;
+	val = intel_freq_opcode(dev_priv, val);
 
 	if (val < dev_priv->rps.min_freq ||
 	    val > dev_priv->rps.max_freq ||
@@ -374,21 +391,21 @@
 
 	if (val > dev_priv->rps.rp0_freq)
 		DRM_DEBUG("User requested overclocking to %d\n",
-			  val * GT_FREQUENCY_MULTIPLIER);
+			  intel_gpu_freq(dev_priv, val));
 
 	dev_priv->rps.max_freq_softlimit = val;
 
-	if (dev_priv->rps.cur_freq > val) {
-		if (IS_VALLEYVIEW(dev))
-			valleyview_set_rps(dev, val);
-		else
-			gen6_set_rps(dev, val);
-	} else if (!IS_VALLEYVIEW(dev)) {
-		/* We still need gen6_set_rps to process the new max_delay and
-		 * update the interrupt limits even though frequency request is
-		 * unchanged. */
-		gen6_set_rps(dev, dev_priv->rps.cur_freq);
-	}
+	val = clamp_t(int, dev_priv->rps.cur_freq,
+		      dev_priv->rps.min_freq_softlimit,
+		      dev_priv->rps.max_freq_softlimit);
+
+	/* We still need *_set_rps to process the new max_delay and
+	 * update the interrupt limits and PMINTRMSK even though
+	 * frequency request may be unchanged. */
+	if (IS_VALLEYVIEW(dev))
+		valleyview_set_rps(dev, val);
+	else
+		gen6_set_rps(dev, val);
 
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -405,10 +422,7 @@
 	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
 	mutex_lock(&dev_priv->rps.hw_lock);
-	if (IS_VALLEYVIEW(dev_priv->dev))
-		ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
-	else
-		ret = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+	ret = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -432,10 +446,7 @@
 
 	mutex_lock(&dev_priv->rps.hw_lock);
 
-	if (IS_VALLEYVIEW(dev))
-		val = vlv_freq_opcode(dev_priv, val);
-	else
-		val /= GT_FREQUENCY_MULTIPLIER;
+	val = intel_freq_opcode(dev_priv, val);
 
 	if (val < dev_priv->rps.min_freq ||
 	    val > dev_priv->rps.max_freq ||
@@ -446,17 +457,17 @@
 
 	dev_priv->rps.min_freq_softlimit = val;
 
-	if (dev_priv->rps.cur_freq < val) {
-		if (IS_VALLEYVIEW(dev))
-			valleyview_set_rps(dev, val);
-		else
-			gen6_set_rps(dev, val);
-	} else if (!IS_VALLEYVIEW(dev)) {
-		/* We still need gen6_set_rps to process the new min_delay and
-		 * update the interrupt limits even though frequency request is
-		 * unchanged. */
-		gen6_set_rps(dev, dev_priv->rps.cur_freq);
-	}
+	val = clamp_t(int, dev_priv->rps.cur_freq,
+		      dev_priv->rps.min_freq_softlimit,
+		      dev_priv->rps.max_freq_softlimit);
+
+	/* We still need *_set_rps to process the new min_delay and
+	 * update the interrupt limits and PMINTRMSK even though
+	 * frequency request may be unchanged. */
+	if (IS_VALLEYVIEW(dev))
+		valleyview_set_rps(dev, val);
+	else
+		gen6_set_rps(dev, val);
 
 	mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -464,6 +475,7 @@
 
 }
 
+static DEVICE_ATTR(gt_act_freq_mhz, S_IRUGO, gt_act_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
 static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
@@ -494,19 +506,22 @@
 
 	if (attr == &dev_attr_gt_RP0_freq_mhz) {
 		if (IS_VALLEYVIEW(dev))
-			val = vlv_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
+			val = intel_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
 		else
-			val = ((rp_state_cap & 0x0000ff) >> 0) * GT_FREQUENCY_MULTIPLIER;
+			val = intel_gpu_freq(dev_priv,
+					     ((rp_state_cap & 0x0000ff) >> 0));
 	} else if (attr == &dev_attr_gt_RP1_freq_mhz) {
 		if (IS_VALLEYVIEW(dev))
-			val = vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
+			val = intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
 		else
-			val = ((rp_state_cap & 0x00ff00) >> 8) * GT_FREQUENCY_MULTIPLIER;
+			val = intel_gpu_freq(dev_priv,
+					     ((rp_state_cap & 0x00ff00) >> 8));
 	} else if (attr == &dev_attr_gt_RPn_freq_mhz) {
 		if (IS_VALLEYVIEW(dev))
-			val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq);
+			val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq);
 		else
-			val = ((rp_state_cap & 0xff0000) >> 16) * GT_FREQUENCY_MULTIPLIER;
+			val = intel_gpu_freq(dev_priv,
+					     ((rp_state_cap & 0xff0000) >> 16));
 	} else {
 		BUG();
 	}
@@ -514,6 +529,7 @@
 }
 
 static const struct attribute *gen6_attrs[] = {
+	&dev_attr_gt_act_freq_mhz.attr,
 	&dev_attr_gt_cur_freq_mhz.attr,
 	&dev_attr_gt_max_freq_mhz.attr,
 	&dev_attr_gt_min_freq_mhz.attr,
@@ -524,6 +540,7 @@
 };
 
 static const struct attribute *vlv_attrs[] = {
+	&dev_attr_gt_act_freq_mhz.attr,
 	&dev_attr_gt_cur_freq_mhz.attr,
 	&dev_attr_gt_max_freq_mhz.attr,
 	&dev_attr_gt_min_freq_mhz.attr,
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 751d4ad..6058a01 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -328,8 +328,8 @@
 TRACE_EVENT(i915_gem_ring_sync_to,
 	    TP_PROTO(struct intel_engine_cs *from,
 		     struct intel_engine_cs *to,
-		     u32 seqno),
-	    TP_ARGS(from, to, seqno),
+		     struct drm_i915_gem_request *req),
+	    TP_ARGS(from, to, req),
 
 	    TP_STRUCT__entry(
 			     __field(u32, dev)
@@ -342,7 +342,7 @@
 			   __entry->dev = from->dev->primary->index;
 			   __entry->sync_from = from->id;
 			   __entry->sync_to = to->id;
-			   __entry->seqno = seqno;
+			   __entry->seqno = i915_gem_request_get_seqno(req);
 			   ),
 
 	    TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u",
@@ -352,8 +352,8 @@
 );
 
 TRACE_EVENT(i915_gem_ring_dispatch,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno, u32 flags),
-	    TP_ARGS(ring, seqno, flags),
+	    TP_PROTO(struct drm_i915_gem_request *req, u32 flags),
+	    TP_ARGS(req, flags),
 
 	    TP_STRUCT__entry(
 			     __field(u32, dev)
@@ -363,11 +363,13 @@
 			     ),
 
 	    TP_fast_assign(
+			   struct intel_engine_cs *ring =
+						i915_gem_request_get_ring(req);
 			   __entry->dev = ring->dev->primary->index;
 			   __entry->ring = ring->id;
-			   __entry->seqno = seqno;
+			   __entry->seqno = i915_gem_request_get_seqno(req);
 			   __entry->flags = flags;
-			   i915_trace_irq_get(ring, seqno);
+			   i915_trace_irq_get(ring, req);
 			   ),
 
 	    TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x",
@@ -398,31 +400,36 @@
 );
 
 DECLARE_EVENT_CLASS(i915_gem_request,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
-	    TP_ARGS(ring, seqno),
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req),
 
 	    TP_STRUCT__entry(
 			     __field(u32, dev)
 			     __field(u32, ring)
+			     __field(u32, uniq)
 			     __field(u32, seqno)
 			     ),
 
 	    TP_fast_assign(
+			   struct intel_engine_cs *ring =
+						i915_gem_request_get_ring(req);
 			   __entry->dev = ring->dev->primary->index;
 			   __entry->ring = ring->id;
-			   __entry->seqno = seqno;
+			   __entry->uniq = req ? req->uniq : 0;
+			   __entry->seqno = i915_gem_request_get_seqno(req);
 			   ),
 
-	    TP_printk("dev=%u, ring=%u, seqno=%u",
-		      __entry->dev, __entry->ring, __entry->seqno)
+	    TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u",
+		      __entry->dev, __entry->ring, __entry->uniq,
+		      __entry->seqno)
 );
 
 DEFINE_EVENT(i915_gem_request, i915_gem_request_add,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
-	    TP_ARGS(ring, seqno)
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req)
 );
 
-TRACE_EVENT(i915_gem_request_complete,
+TRACE_EVENT(i915_gem_request_notify,
 	    TP_PROTO(struct intel_engine_cs *ring),
 	    TP_ARGS(ring),
 
@@ -443,17 +450,23 @@
 );
 
 DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
-	    TP_ARGS(ring, seqno)
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req)
+);
+
+DEFINE_EVENT(i915_gem_request, i915_gem_request_complete,
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req)
 );
 
 TRACE_EVENT(i915_gem_request_wait_begin,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
-	    TP_ARGS(ring, seqno),
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req),
 
 	    TP_STRUCT__entry(
 			     __field(u32, dev)
 			     __field(u32, ring)
+			     __field(u32, uniq)
 			     __field(u32, seqno)
 			     __field(bool, blocking)
 			     ),
@@ -465,20 +478,24 @@
 	     * less desirable.
 	     */
 	    TP_fast_assign(
+			   struct intel_engine_cs *ring =
+						i915_gem_request_get_ring(req);
 			   __entry->dev = ring->dev->primary->index;
 			   __entry->ring = ring->id;
-			   __entry->seqno = seqno;
-			   __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex);
+			   __entry->uniq = req ? req->uniq : 0;
+			   __entry->seqno = i915_gem_request_get_seqno(req);
+			   __entry->blocking =
+				     mutex_is_locked(&ring->dev->struct_mutex);
 			   ),
 
-	    TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s",
-		      __entry->dev, __entry->ring, __entry->seqno,
-		      __entry->blocking ?  "yes (NB)" : "no")
+	    TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u, blocking=%s",
+		      __entry->dev, __entry->ring, __entry->uniq,
+		      __entry->seqno, __entry->blocking ?  "yes (NB)" : "no")
 );
 
 DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
-	    TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
-	    TP_ARGS(ring, seqno)
+	    TP_PROTO(struct drm_i915_gem_request *req),
+	    TP_ARGS(req)
 );
 
 DECLARE_EVENT_CLASS(i915_ring,
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
new file mode 100644
index 0000000..19a9dd5
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2015 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.
+ */
+
+/**
+ * DOC: atomic modeset support
+ *
+ * The functions here implement the state management and hardware programming
+ * dispatch required by the atomic modeset infrastructure.
+ * See intel_atomic_plane.c for the plane-specific atomic functionality.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "intel_drv.h"
+
+
+/**
+ * intel_atomic_check - validate state object
+ * @dev: drm device
+ * @state: state to validate
+ */
+int intel_atomic_check(struct drm_device *dev,
+		       struct drm_atomic_state *state)
+{
+	int nplanes = dev->mode_config.num_total_plane;
+	int ncrtcs = dev->mode_config.num_crtc;
+	int nconnectors = dev->mode_config.num_connector;
+	enum pipe nuclear_pipe = INVALID_PIPE;
+	int ret;
+	int i;
+	bool not_nuclear = false;
+
+	/*
+	 * FIXME:  At the moment, we only support "nuclear pageflip" on a
+	 * single CRTC.  Cross-crtc updates will be added later.
+	 */
+	for (i = 0; i < nplanes; i++) {
+		struct intel_plane *plane = to_intel_plane(state->planes[i]);
+		if (!plane)
+			continue;
+
+		if (nuclear_pipe == INVALID_PIPE) {
+			nuclear_pipe = plane->pipe;
+		} else if (nuclear_pipe != plane->pipe) {
+			DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n");
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * FIXME:  We only handle planes for now; make sure there are no CRTC's
+	 * or connectors involved.
+	 */
+	state->allow_modeset = false;
+	for (i = 0; i < ncrtcs; i++) {
+		struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]);
+		if (crtc && crtc->pipe != nuclear_pipe)
+			not_nuclear = true;
+	}
+	for (i = 0; i < nconnectors; i++)
+		if (state->connectors[i] != NULL)
+			not_nuclear = true;
+
+	if (not_nuclear) {
+		DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n");
+		return -EINVAL;
+	}
+
+	ret = drm_atomic_helper_check_planes(dev, state);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+
+/**
+ * intel_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the top-level driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a top-level state object that has been validated
+ * with drm_atomic_helper_check().
+ *
+ * FIXME:  Atomic modeset support for i915 is not yet complete.  At the moment
+ * we can only handle plane-related operations and do not yet support
+ * asynchronous commit.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+int intel_atomic_commit(struct drm_device *dev,
+			struct drm_atomic_state *state,
+			bool async)
+{
+	int ret;
+	int i;
+
+	if (async) {
+		DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+		return -EINVAL;
+	}
+
+	ret = drm_atomic_helper_prepare_planes(dev, state);
+	if (ret)
+		return ret;
+
+	/* Point of no return */
+
+	/*
+	 * FIXME:  The proper sequence here will eventually be:
+	 *
+	 * drm_atomic_helper_swap_state(dev, state)
+	 * drm_atomic_helper_commit_pre_planes(dev, state);
+	 * drm_atomic_helper_commit_planes(dev, state);
+	 * drm_atomic_helper_commit_post_planes(dev, state);
+	 * drm_atomic_helper_wait_for_vblanks(dev, state);
+	 * drm_atomic_helper_cleanup_planes(dev, state);
+	 * drm_atomic_state_free(state);
+	 *
+	 * once we have full atomic modeset.  For now, just manually update
+	 * plane states to avoid clobbering good states with dummy states
+	 * while nuclear pageflipping.
+	 */
+	for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+		struct drm_plane *plane = state->planes[i];
+
+		if (!plane)
+			continue;
+
+		plane->state->state = state;
+		swap(state->plane_states[i], plane->state);
+		plane->state->state = NULL;
+	}
+	drm_atomic_helper_commit_planes(dev, state);
+	drm_atomic_helper_wait_for_vblanks(dev, state);
+	drm_atomic_helper_cleanup_planes(dev, state);
+	drm_atomic_state_free(state);
+
+	return 0;
+}
+
+/**
+ * intel_connector_atomic_get_property - fetch connector property value
+ * @connector: connector to fetch property for
+ * @state: state containing the property value
+ * @property: property to look up
+ * @val: pointer to write property value into
+ *
+ * The DRM core does not store shadow copies of properties for
+ * atomic-capable drivers.  This entrypoint is used to fetch
+ * the current value of a driver-specific connector property.
+ */
+int
+intel_connector_atomic_get_property(struct drm_connector *connector,
+				    const struct drm_connector_state *state,
+				    struct drm_property *property,
+				    uint64_t *val)
+{
+	int i;
+
+	/*
+	 * TODO: We only have atomic modeset for planes at the moment, so the
+	 * crtc/connector code isn't quite ready yet.  Until it's ready,
+	 * continue to look up all property values in the DRM's shadow copy
+	 * in obj->properties->values[].
+	 *
+	 * When the crtc/connector state work matures, this function should
+	 * be updated to read the values out of the state structure instead.
+	 */
+	for (i = 0; i < connector->base.properties->count; i++) {
+		if (connector->base.properties->properties[i] == property) {
+			*val = connector->base.properties->values[i];
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * intel_crtc_duplicate_state - duplicate crtc state
+ * @crtc: drm crtc
+ *
+ * Allocates and returns a copy of the crtc state (both common and
+ * Intel-specific) for the specified crtc.
+ *
+ * Returns: The newly allocated crtc state, or NULL on failure.
+ */
+struct drm_crtc_state *
+intel_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (WARN_ON(!intel_crtc->config))
+		return kzalloc(sizeof(*intel_crtc->config), GFP_KERNEL);
+
+	return kmemdup(intel_crtc->config, sizeof(*intel_crtc->config),
+		       GFP_KERNEL);
+}
+
+/**
+ * intel_crtc_destroy_state - destroy crtc state
+ * @crtc: drm crtc
+ *
+ * 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)
+{
+	drm_atomic_helper_crtc_destroy_state(crtc, state);
+}
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
new file mode 100644
index 0000000..9e6f727
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2014 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.
+ */
+
+/**
+ * DOC: atomic plane helpers
+ *
+ * The functions here are used by the atomic plane helper functions to
+ * implement legacy plane updates (i.e., drm_plane->update_plane() and
+ * drm_plane->disable_plane()).  This allows plane updates to use the
+ * atomic state infrastructure and perform plane updates as separate
+ * prepare/check/commit/cleanup steps.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "intel_drv.h"
+
+/**
+ * intel_create_plane_state - create plane state object
+ * @plane: drm plane
+ *
+ * Allocates a fresh plane state for the given plane and sets some of
+ * the state values to sensible initial values.
+ *
+ * Returns: A newly allocated plane state, or NULL on failure
+ */
+struct intel_plane_state *
+intel_create_plane_state(struct drm_plane *plane)
+{
+	struct intel_plane_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	state->base.plane = plane;
+	state->base.rotation = BIT(DRM_ROTATE_0);
+
+	return state;
+}
+
+/**
+ * intel_plane_duplicate_state - duplicate plane state
+ * @plane: drm plane
+ *
+ * Allocates and returns a copy of the plane state (both common and
+ * Intel-specific) for the specified plane.
+ *
+ * Returns: The newly allocated plane state, or NULL on failure.
+ */
+struct drm_plane_state *
+intel_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct drm_plane_state *state;
+	struct intel_plane_state *intel_state;
+
+	if (WARN_ON(!plane->state))
+		intel_state = intel_create_plane_state(plane);
+	else
+		intel_state = kmemdup(plane->state, sizeof(*intel_state),
+				      GFP_KERNEL);
+
+	if (!intel_state)
+		return NULL;
+
+	state = &intel_state->base;
+	if (state->fb)
+		drm_framebuffer_reference(state->fb);
+
+	return state;
+}
+
+/**
+ * intel_plane_destroy_state - destroy plane state
+ * @plane: drm plane
+ * @state: state object to destroy
+ *
+ * Destroys the plane state (both common and Intel-specific) for the
+ * specified plane.
+ */
+void
+intel_plane_destroy_state(struct drm_plane *plane,
+			  struct drm_plane_state *state)
+{
+	drm_atomic_helper_plane_destroy_state(plane, state);
+}
+
+static int intel_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct drm_crtc *crtc = state->crtc;
+	struct intel_crtc *intel_crtc;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_state *intel_state = to_intel_plane_state(state);
+
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
+
+	/*
+	 * Both crtc and plane->crtc could be NULL if we're updating a
+	 * property while the plane is disabled.  We don't actually have
+	 * anything driver-specific we need to test in that case, so
+	 * just return success.
+	 */
+	if (!crtc)
+		return 0;
+
+	/*
+	 * The original src/dest coordinates are stored in state->base, but
+	 * we want to keep another copy internal to our driver that we can
+	 * clip/modify ourselves.
+	 */
+	intel_state->src.x1 = state->src_x;
+	intel_state->src.y1 = state->src_y;
+	intel_state->src.x2 = state->src_x + state->src_w;
+	intel_state->src.y2 = state->src_y + state->src_h;
+	intel_state->dst.x1 = state->crtc_x;
+	intel_state->dst.y1 = state->crtc_y;
+	intel_state->dst.x2 = state->crtc_x + state->crtc_w;
+	intel_state->dst.y2 = state->crtc_y + state->crtc_h;
+
+	/* 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 =
+		intel_crtc->active ? intel_crtc->config->pipe_src_w : 0;
+	intel_state->clip.y2 =
+		intel_crtc->active ? intel_crtc->config->pipe_src_h : 0;
+
+	/*
+	 * Disabling a plane is always okay; we just need to update
+	 * fb tracking in a special way since cleanup_fb() won't
+	 * get called by the plane helpers.
+	 */
+	if (state->fb == NULL && plane->state->fb != NULL) {
+		/*
+		 * 'prepare' is never called when plane is being disabled, so
+		 * we need to handle frontbuffer tracking as a special case
+		 */
+		intel_crtc->atomic.disabled_planes |=
+			(1 << drm_plane_index(plane));
+	}
+
+	return intel_plane->check_plane(plane, intel_state);
+}
+
+static void intel_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_state *intel_state =
+		to_intel_plane_state(plane->state);
+
+	/* Don't disable an already disabled plane */
+	if (!plane->state->fb && !old_state->fb)
+		return;
+
+	intel_plane->commit_plane(plane, intel_state);
+}
+
+const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
+	.prepare_fb = intel_prepare_plane_fb,
+	.cleanup_fb = intel_cleanup_plane_fb,
+	.atomic_check = intel_plane_atomic_check,
+	.atomic_update = intel_plane_atomic_update,
+};
+
+/**
+ * intel_plane_atomic_get_property - fetch plane property value
+ * @plane: plane to fetch property for
+ * @state: state containing the property value
+ * @property: property to look up
+ * @val: pointer to write property value into
+ *
+ * The DRM core does not store shadow copies of properties for
+ * atomic-capable drivers.  This entrypoint is used to fetch
+ * the current value of a driver-specific plane property.
+ */
+int
+intel_plane_atomic_get_property(struct drm_plane *plane,
+				const struct drm_plane_state *state,
+				struct drm_property *property,
+				uint64_t *val)
+{
+	struct drm_mode_config *config = &plane->dev->mode_config;
+
+	if (property == config->rotation_property) {
+		*val = state->rotation;
+	} else {
+		DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * intel_plane_atomic_set_property - set plane property value
+ * @plane: plane to set property for
+ * @state: state to update property value in
+ * @property: property to set
+ * @val: value to set property to
+ *
+ * Writes the specified property value for a plane into the provided atomic
+ * state object.
+ *
+ * Returns 0 on success, -EINVAL on unrecognized properties
+ */
+int
+intel_plane_atomic_set_property(struct drm_plane *plane,
+				struct drm_plane_state *state,
+				struct drm_property *property,
+				uint64_t val)
+{
+	struct drm_mode_config *config = &plane->dev->mode_config;
+
+	if (property == config->rotation_property) {
+		state->rotation = val;
+	} else {
+		DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index ee41b88..2396cc7 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -400,7 +400,7 @@
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
-	struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+	struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
 	struct drm_connector *connector;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index a4bd90f..3f17825 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -664,6 +664,50 @@
 	}
 }
 
+static void
+parse_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+	struct bdb_psr *psr;
+	struct psr_table *psr_table;
+
+	psr = find_section(bdb, BDB_PSR);
+	if (!psr) {
+		DRM_DEBUG_KMS("No PSR BDB found.\n");
+		return;
+	}
+
+	psr_table = &psr->psr_table[panel_type];
+
+	dev_priv->vbt.psr.full_link = psr_table->full_link;
+	dev_priv->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup;
+
+	/* Allowed VBT values goes from 0 to 15 */
+	dev_priv->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 :
+		psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames;
+
+	switch (psr_table->lines_to_wait) {
+	case 0:
+		dev_priv->vbt.psr.lines_to_wait = PSR_0_LINES_TO_WAIT;
+		break;
+	case 1:
+		dev_priv->vbt.psr.lines_to_wait = PSR_1_LINE_TO_WAIT;
+		break;
+	case 2:
+		dev_priv->vbt.psr.lines_to_wait = PSR_4_LINES_TO_WAIT;
+		break;
+	case 3:
+		dev_priv->vbt.psr.lines_to_wait = PSR_8_LINES_TO_WAIT;
+		break;
+	default:
+		DRM_DEBUG_KMS("VBT has unknown PSR lines to wait %u\n",
+			      psr_table->lines_to_wait);
+		break;
+	}
+
+	dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time;
+	dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time;
+}
+
 static u8 *goto_next_sequence(u8 *data, int *size)
 {
 	u16 len;
@@ -1241,6 +1285,7 @@
 	parse_device_mapping(dev_priv, bdb);
 	parse_driver_features(dev_priv, bdb);
 	parse_edp(dev_priv, bdb);
+	parse_psr(dev_priv, bdb);
 	parse_mipi(dev_priv, bdb);
 	parse_ddi_ports(dev_priv, bdb);
 
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 7603765..a6a8710 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -80,7 +80,7 @@
 #define BDB_EXT_MMIO_REGS	  6
 #define BDB_SWF_IO		  7
 #define BDB_SWF_MMIO		  8
-#define BDB_DOT_CLOCK_TABLE	  9
+#define BDB_PSR			  9
 #define BDB_MODE_REMOVAL_TABLE	 10
 #define BDB_CHILD_DEVICE_TABLE	 11
 #define BDB_DRIVER_FEATURES	 12
@@ -556,6 +556,26 @@
 	u16 edp_t3_optimization;
 } __packed;
 
+struct psr_table {
+	/* Feature bits */
+	u8 full_link:1;
+	u8 require_aux_to_wakeup:1;
+	u8 feature_bits_rsvd:6;
+
+	/* Wait times */
+	u8 idle_frames:4;
+	u8 lines_to_wait:3;
+	u8 wait_times_rsvd:1;
+
+	/* TP wake up time in multiple of 100 */
+	u16 tp1_wakeup_time;
+	u16 tp2_tp3_wakeup_time;
+} __packed;
+
+struct bdb_psr {
+	struct psr_table psr_table[16];
+} __packed;
+
 void intel_setup_bios(struct drm_device *dev);
 int intel_parse_bios(struct drm_device *dev);
 
@@ -798,7 +818,8 @@
 #define DUAL_LINK_PIXEL_ALT	2
 	u16 dual_link:2;
 	u16 lane_cnt:2;
-	u16 rsvd3:12;
+	u16 pixel_overlap:3;
+	u16 rsvd3:9;
 
 	u16 rsvd4;
 
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index a9af9a4..e66e17a 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
@@ -110,31 +111,31 @@
 }
 
 static void intel_crt_get_config(struct intel_encoder *encoder,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = encoder->base.dev;
 	int dotclock;
 
-	pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder);
+	pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
 
 	dotclock = pipe_config->port_clock;
 
 	if (HAS_PCH_SPLIT(dev))
 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-	pipe_config->adjusted_mode.crtc_clock = dotclock;
+	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 }
 
 static void hsw_crt_get_config(struct intel_encoder *encoder,
-			       struct intel_crtc_config *pipe_config)
+			       struct intel_crtc_state *pipe_config)
 {
 	intel_ddi_get_config(encoder, pipe_config);
 
-	pipe_config->adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
+	pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
 					      DRM_MODE_FLAG_NHSYNC |
 					      DRM_MODE_FLAG_PVSYNC |
 					      DRM_MODE_FLAG_NVSYNC);
-	pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder);
+	pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
 }
 
 static void hsw_crt_pre_enable(struct intel_encoder *encoder)
@@ -157,7 +158,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crt *crt = intel_encoder_to_crt(encoder);
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-	struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
 	u32 adpa;
 
 	if (INTEL_INFO(dev)->gen >= 5)
@@ -303,7 +304,7 @@
 }
 
 static bool intel_crt_compute_config(struct intel_encoder *encoder,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = encoder->base.dev;
 
@@ -792,6 +793,8 @@
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = intel_crt_destroy,
 	.set_property = intel_crt_set_property,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_get_property = intel_connector_atomic_get_property,
 };
 
 static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e6b45cd..f14e8a2 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -128,15 +128,15 @@
 };
 
 static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
-	{ 0x00000018, 0x000000a0 },
-	{ 0x00004014, 0x00000098 },
+	{ 0x00000018, 0x000000a2 },
+	{ 0x00004014, 0x0000009B },
 	{ 0x00006012, 0x00000088 },
-	{ 0x00008010, 0x00000080 },
-	{ 0x00000018, 0x00000098 },
+	{ 0x00008010, 0x00000087 },
+	{ 0x00000018, 0x0000009B },
 	{ 0x00004014, 0x00000088 },
-	{ 0x00006012, 0x00000080 },
+	{ 0x00006012, 0x00000087 },
 	{ 0x00000018, 0x00000088 },
-	{ 0x00004014, 0x00000080 },
+	{ 0x00004014, 0x00000087 },
 };
 
 static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
@@ -328,7 +328,7 @@
 	/* Enable the PCH Receiver FDI PLL */
 	rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
 		     FDI_RX_PLL_ENABLE |
-		     FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+		     FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
 	I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
 	POSTING_READ(_FDI_RXA_CTL);
 	udelay(220);
@@ -338,8 +338,8 @@
 	I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
 
 	/* Configure Port Clock Select */
-	I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config.ddi_pll_sel);
-	WARN_ON(intel_crtc->config.ddi_pll_sel != PORT_CLK_SEL_SPLL);
+	I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
+	WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL);
 
 	/* Start the training iterating through available voltages and emphasis,
 	 * testing each value twice. */
@@ -357,7 +357,7 @@
 		 * port reversal bit */
 		I915_WRITE(DDI_BUF_CTL(PORT_E),
 			   DDI_BUF_CTL_ENABLE |
-			   ((intel_crtc->config.fdi_lanes - 1) << 1) |
+			   ((intel_crtc->config->fdi_lanes - 1) << 1) |
 			   DDI_BUF_TRANS_SELECT(i / 2));
 		POSTING_READ(DDI_BUF_CTL(PORT_E));
 
@@ -732,7 +732,7 @@
 
 
 static void skl_ddi_clock_get(struct intel_encoder *encoder,
-				struct intel_crtc_config *pipe_config)
+				struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	int link_clock = 0;
@@ -768,15 +768,15 @@
 	pipe_config->port_clock = link_clock;
 
 	if (pipe_config->has_dp_encoder)
-		pipe_config->adjusted_mode.crtc_clock =
+		pipe_config->base.adjusted_mode.crtc_clock =
 			intel_dotclock_calculate(pipe_config->port_clock,
 						 &pipe_config->dp_m_n);
 	else
-		pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+		pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
 static void hsw_ddi_clock_get(struct intel_encoder *encoder,
-			      struct intel_crtc_config *pipe_config)
+			      struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	int link_clock = 0;
@@ -820,21 +820,26 @@
 	pipe_config->port_clock = link_clock * 2;
 
 	if (pipe_config->has_pch_encoder)
-		pipe_config->adjusted_mode.crtc_clock =
+		pipe_config->base.adjusted_mode.crtc_clock =
 			intel_dotclock_calculate(pipe_config->port_clock,
 						 &pipe_config->fdi_m_n);
 	else if (pipe_config->has_dp_encoder)
-		pipe_config->adjusted_mode.crtc_clock =
+		pipe_config->base.adjusted_mode.crtc_clock =
 			intel_dotclock_calculate(pipe_config->port_clock,
 						 &pipe_config->dp_m_n);
 	else
-		pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+		pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
 void intel_ddi_clock_get(struct intel_encoder *encoder,
-			 struct intel_crtc_config *pipe_config)
+			 struct intel_crtc_state *pipe_config)
 {
-	hsw_ddi_clock_get(encoder, pipe_config);
+	struct drm_device *dev = encoder->base.dev;
+
+	if (INTEL_INFO(dev)->gen <= 8)
+		hsw_ddi_clock_get(encoder, pipe_config);
+	else
+		skl_ddi_clock_get(encoder, pipe_config);
 }
 
 static void
@@ -904,6 +909,7 @@
 
 static bool
 hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
+		   struct intel_crtc_state *crtc_state,
 		   struct intel_encoder *intel_encoder,
 		   int clock)
 {
@@ -918,16 +924,16 @@
 		      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
 		      WRPLL_DIVIDER_POST(p);
 
-		intel_crtc->new_config->dpll_hw_state.wrpll = val;
+		crtc_state->dpll_hw_state.wrpll = val;
 
-		pll = intel_get_shared_dpll(intel_crtc);
+		pll = intel_get_shared_dpll(intel_crtc, crtc_state);
 		if (pll == NULL) {
 			DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
 					 pipe_name(intel_crtc->pipe));
 			return false;
 		}
 
-		intel_crtc->new_config->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+		crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
 	}
 
 	return true;
@@ -1090,6 +1096,7 @@
 
 static bool
 skl_ddi_pll_select(struct intel_crtc *intel_crtc,
+		   struct intel_crtc_state *crtc_state,
 		   struct intel_encoder *intel_encoder,
 		   int clock)
 {
@@ -1139,11 +1146,11 @@
 	} else /* eDP */
 		return true;
 
-	intel_crtc->new_config->dpll_hw_state.ctrl1 = ctrl1;
-	intel_crtc->new_config->dpll_hw_state.cfgcr1 = cfgcr1;
-	intel_crtc->new_config->dpll_hw_state.cfgcr2 = cfgcr2;
+	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
 
-	pll = intel_get_shared_dpll(intel_crtc);
+	pll = intel_get_shared_dpll(intel_crtc, crtc_state);
 	if (pll == NULL) {
 		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
 				 pipe_name(intel_crtc->pipe));
@@ -1151,7 +1158,7 @@
 	}
 
 	/* shared DPLL id 0 is DPLL 1 */
-	intel_crtc->new_config->ddi_pll_sel = pll->id + 1;
+	crtc_state->ddi_pll_sel = pll->id + 1;
 
 	return true;
 }
@@ -1163,17 +1170,20 @@
  * For private DPLLs, compute_config() should do the selection for us. This
  * function should be folded into compute_config() eventually.
  */
-bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
+bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
+			  struct intel_crtc_state *crtc_state)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct intel_encoder *intel_encoder =
 		intel_ddi_get_crtc_new_encoder(intel_crtc);
-	int clock = intel_crtc->new_config->port_clock;
+	int clock = crtc_state->port_clock;
 
 	if (IS_SKYLAKE(dev))
-		return skl_ddi_pll_select(intel_crtc, intel_encoder, clock);
+		return skl_ddi_pll_select(intel_crtc, crtc_state,
+					  intel_encoder, clock);
 	else
-		return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock);
+		return hsw_ddi_pll_select(intel_crtc, crtc_state,
+					  intel_encoder, clock);
 }
 
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
@@ -1181,13 +1191,13 @@
 	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	int type = intel_encoder->type;
 	uint32_t temp;
 
 	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
 		temp = TRANS_MSA_SYNC_CLK;
-		switch (intel_crtc->config.pipe_bpp) {
+		switch (intel_crtc->config->pipe_bpp) {
 		case 18:
 			temp |= TRANS_MSA_6_BPC;
 			break;
@@ -1212,7 +1222,7 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	uint32_t temp;
 	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
 	if (state == true)
@@ -1230,7 +1240,7 @@
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum pipe pipe = intel_crtc->pipe;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
 	int type = intel_encoder->type;
 	uint32_t temp;
@@ -1239,7 +1249,7 @@
 	temp = TRANS_DDI_FUNC_ENABLE;
 	temp |= TRANS_DDI_SELECT_PORT(port);
 
-	switch (intel_crtc->config.pipe_bpp) {
+	switch (intel_crtc->config->pipe_bpp) {
 	case 18:
 		temp |= TRANS_DDI_BPC_6;
 		break;
@@ -1256,9 +1266,9 @@
 		BUG();
 	}
 
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
 		temp |= TRANS_DDI_PVSYNC;
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
 		temp |= TRANS_DDI_PHSYNC;
 
 	if (cpu_transcoder == TRANSCODER_EDP) {
@@ -1269,8 +1279,8 @@
 			 * using motion blur mitigation (which we don't
 			 * support). */
 			if (IS_HASWELL(dev) &&
-			    (intel_crtc->config.pch_pfit.enabled ||
-			     intel_crtc->config.pch_pfit.force_thru))
+			    (intel_crtc->config->pch_pfit.enabled ||
+			     intel_crtc->config->pch_pfit.force_thru))
 				temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
 			else
 				temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@ -1288,14 +1298,14 @@
 	}
 
 	if (type == INTEL_OUTPUT_HDMI) {
-		if (intel_crtc->config.has_hdmi_sink)
+		if (intel_crtc->config->has_hdmi_sink)
 			temp |= TRANS_DDI_MODE_SELECT_HDMI;
 		else
 			temp |= TRANS_DDI_MODE_SELECT_DVI;
 
 	} else if (type == INTEL_OUTPUT_ANALOG) {
 		temp |= TRANS_DDI_MODE_SELECT_FDI;
-		temp |= (intel_crtc->config.fdi_lanes - 1) << 1;
+		temp |= (intel_crtc->config->fdi_lanes - 1) << 1;
 
 	} else if (type == INTEL_OUTPUT_DISPLAYPORT ||
 		   type == INTEL_OUTPUT_EDP) {
@@ -1445,7 +1455,7 @@
 	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
 	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 
 	if (cpu_transcoder != TRANSCODER_EDP)
 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1455,7 +1465,7 @@
 void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
 {
 	struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 
 	if (cpu_transcoder != TRANSCODER_EDP)
 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1477,7 +1487,7 @@
 	}
 
 	if (IS_SKYLAKE(dev)) {
-		uint32_t dpll = crtc->config.ddi_pll_sel;
+		uint32_t dpll = crtc->config->ddi_pll_sel;
 		uint32_t val;
 
 		/*
@@ -1492,7 +1502,7 @@
 			val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
 				 DPLL_CTRL1_SSC(dpll) |
 				 DPLL_CRTL1_LINK_RATE_MASK(dpll));
-			val |= crtc->config.dpll_hw_state.ctrl1 << (dpll * 6);
+			val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
 
 			I915_WRITE(DPLL_CTRL1, val);
 			POSTING_READ(DPLL_CTRL1);
@@ -1509,8 +1519,8 @@
 		I915_WRITE(DPLL_CTRL2, val);
 
 	} else {
-		WARN_ON(crtc->config.ddi_pll_sel == PORT_CLK_SEL_NONE);
-		I915_WRITE(PORT_CLK_SEL(port), crtc->config.ddi_pll_sel);
+		WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
+		I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
 	}
 
 	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
@@ -1527,8 +1537,8 @@
 		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
 
 		intel_hdmi->set_infoframes(encoder,
-					   crtc->config.has_hdmi_sink,
-					   &crtc->config.adjusted_mode);
+					   crtc->config->has_hdmi_sink,
+					   &crtc->config->base.adjusted_mode);
 	}
 }
 
@@ -1600,9 +1610,10 @@
 
 		intel_edp_backlight_on(intel_dp);
 		intel_psr_enable(intel_dp);
+		intel_edp_drrs_enable(intel_dp);
 	}
 
-	if (intel_crtc->config.has_audio) {
+	if (intel_crtc->config->has_audio) {
 		intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
 		intel_audio_codec_enable(intel_encoder);
 	}
@@ -1617,7 +1628,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (intel_crtc->config.has_audio) {
+	if (intel_crtc->config->has_audio) {
 		intel_audio_codec_disable(intel_encoder);
 		intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
 	}
@@ -1625,6 +1636,7 @@
 	if (type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
+		intel_edp_drrs_disable(intel_dp);
 		intel_psr_disable(intel_dp);
 		intel_edp_backlight_off(intel_dp);
 	}
@@ -2022,14 +2034,13 @@
 }
 
 void intel_ddi_get_config(struct intel_encoder *encoder,
-			  struct intel_crtc_config *pipe_config)
+			  struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
 	struct intel_hdmi *intel_hdmi;
 	u32 temp, flags = 0;
-	struct drm_device *dev = dev_priv->dev;
 
 	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
 	if (temp & TRANS_DDI_PHSYNC)
@@ -2041,7 +2052,7 @@
 	else
 		flags |= DRM_MODE_FLAG_NVSYNC;
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
 	switch (temp & TRANS_DDI_BPC_MASK) {
 	case TRANS_DDI_BPC_6:
@@ -2106,10 +2117,7 @@
 		dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
 	}
 
-	if (INTEL_INFO(dev)->gen <= 8)
-		hsw_ddi_clock_get(encoder, pipe_config);
-	else
-		skl_ddi_clock_get(encoder, pipe_config);
+	intel_ddi_clock_get(encoder, pipe_config);
 }
 
 static void intel_ddi_destroy(struct drm_encoder *encoder)
@@ -2119,7 +2127,7 @@
 }
 
 static bool intel_ddi_compute_config(struct intel_encoder *encoder,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	int type = encoder->type;
 	int port = intel_ddi_get_encoder_port(encoder);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e7a16f1..3d220a6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -37,6 +37,7 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_plane_helper.h>
@@ -76,9 +77,9 @@
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
-				struct intel_crtc_config *pipe_config);
+				struct intel_crtc_state *pipe_config);
 static void ironlake_pch_clock_get(struct intel_crtc *crtc,
-				   struct intel_crtc_config *pipe_config);
+				   struct intel_crtc_state *pipe_config);
 
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
 			  int x, int y, struct drm_framebuffer *old_fb);
@@ -95,9 +96,11 @@
 static void haswell_set_pipeconf(struct drm_crtc *crtc);
 static void intel_set_pipe_csc(struct drm_crtc *crtc);
 static void vlv_prepare_pll(struct intel_crtc *crtc,
-			    const struct intel_crtc_config *pipe_config);
+			    const struct intel_crtc_state *pipe_config);
 static void chv_prepare_pll(struct intel_crtc *crtc,
-			    const struct intel_crtc_config *pipe_config);
+			    const struct intel_crtc_state *pipe_config);
+static void intel_begin_crtc_commit(struct drm_crtc *crtc);
+static void intel_finish_crtc_commit(struct drm_crtc *crtc);
 
 static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
 {
@@ -895,7 +898,7 @@
 	 * properly reconstruct framebuffers.
 	 */
 	return intel_crtc->active && crtc->primary->fb &&
-		intel_crtc->config.adjusted_mode.crtc_clock;
+		intel_crtc->config->base.adjusted_mode.crtc_clock;
 }
 
 enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
@@ -904,7 +907,7 @@
 	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	return intel_crtc->config.cpu_transcoder;
+	return intel_crtc->config->cpu_transcoder;
 }
 
 static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
@@ -946,7 +949,7 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 	enum pipe pipe = crtc->pipe;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
@@ -1024,7 +1027,7 @@
 	reg = DPLL(pipe);
 	val = I915_READ(reg);
 	cur_state = !!(val & DPLL_VCO_ENABLE);
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "PLL state assertion failure (expected %s, current %s)\n",
 	     state_string(state), state_string(cur_state));
 }
@@ -1040,7 +1043,7 @@
 	mutex_unlock(&dev_priv->dpio_lock);
 
 	cur_state = val & DSI_PLL_VCO_EN;
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "DSI PLL state assertion failure (expected %s, current %s)\n",
 	     state_string(state), state_string(cur_state));
 }
@@ -1052,10 +1055,10 @@
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 
-	if (crtc->config.shared_dpll < 0)
+	if (crtc->config->shared_dpll < 0)
 		return NULL;
 
-	return &dev_priv->shared_dplls[crtc->config.shared_dpll];
+	return &dev_priv->shared_dplls[crtc->config->shared_dpll];
 }
 
 /* For ILK+ */
@@ -1071,7 +1074,7 @@
 		return;
 
 	cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "%s assertion failure (expected %s, current %s)\n",
 	     pll->name, state_string(state), state_string(cur_state));
 }
@@ -1095,7 +1098,7 @@
 		val = I915_READ(reg);
 		cur_state = !!(val & FDI_TX_ENABLE);
 	}
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "FDI TX state assertion failure (expected %s, current %s)\n",
 	     state_string(state), state_string(cur_state));
 }
@@ -1112,7 +1115,7 @@
 	reg = FDI_RX_CTL(pipe);
 	val = I915_READ(reg);
 	cur_state = !!(val & FDI_RX_ENABLE);
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "FDI RX state assertion failure (expected %s, current %s)\n",
 	     state_string(state), state_string(cur_state));
 }
@@ -1135,7 +1138,7 @@
 
 	reg = FDI_TX_CTL(pipe);
 	val = I915_READ(reg);
-	WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
+	I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
 }
 
 void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
@@ -1148,7 +1151,7 @@
 	reg = FDI_RX_CTL(pipe);
 	val = I915_READ(reg);
 	cur_state = !!(val & FDI_RX_PLL_ENABLE);
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "FDI RX PLL assertion failure (expected %s, current %s)\n",
 	     state_string(state), state_string(cur_state));
 }
@@ -1190,7 +1193,7 @@
 	    ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
 		locked = false;
 
-	WARN(panel_pipe == pipe && locked,
+	I915_STATE_WARN(panel_pipe == pipe && locked,
 	     "panel assertion failure, pipe %c regs locked\n",
 	     pipe_name(pipe));
 }
@@ -1206,7 +1209,7 @@
 	else
 		cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
 
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "cursor on pipe %c assertion failure (expected %s, current %s)\n",
 	     pipe_name(pipe), state_string(state), state_string(cur_state));
 }
@@ -1236,7 +1239,7 @@
 		cur_state = !!(val & PIPECONF_ENABLE);
 	}
 
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "pipe %c assertion failure (expected %s, current %s)\n",
 	     pipe_name(pipe), state_string(state), state_string(cur_state));
 }
@@ -1251,7 +1254,7 @@
 	reg = DSPCNTR(plane);
 	val = I915_READ(reg);
 	cur_state = !!(val & DISPLAY_PLANE_ENABLE);
-	WARN(cur_state != state,
+	I915_STATE_WARN(cur_state != state,
 	     "plane %c assertion failure (expected %s, current %s)\n",
 	     plane_name(plane), state_string(state), state_string(cur_state));
 }
@@ -1271,7 +1274,7 @@
 	if (INTEL_INFO(dev)->gen >= 4) {
 		reg = DSPCNTR(pipe);
 		val = I915_READ(reg);
-		WARN(val & DISPLAY_PLANE_ENABLE,
+		I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE,
 		     "plane %c assertion failure, should be disabled but not\n",
 		     plane_name(pipe));
 		return;
@@ -1283,7 +1286,7 @@
 		val = I915_READ(reg);
 		cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
 			DISPPLANE_SEL_PIPE_SHIFT;
-		WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
+		I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
 		     "plane %c assertion failure, should be off on pipe %c but is still active\n",
 		     plane_name(i), pipe_name(pipe));
 	}
@@ -1299,7 +1302,7 @@
 	if (INTEL_INFO(dev)->gen >= 9) {
 		for_each_sprite(pipe, sprite) {
 			val = I915_READ(PLANE_CTL(pipe, sprite));
-			WARN(val & PLANE_CTL_ENABLE,
+			I915_STATE_WARN(val & PLANE_CTL_ENABLE,
 			     "plane %d assertion failure, should be off on pipe %c but is still active\n",
 			     sprite, pipe_name(pipe));
 		}
@@ -1307,20 +1310,20 @@
 		for_each_sprite(pipe, sprite) {
 			reg = SPCNTR(pipe, sprite);
 			val = I915_READ(reg);
-			WARN(val & SP_ENABLE,
+			I915_STATE_WARN(val & SP_ENABLE,
 			     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
 			     sprite_name(pipe, sprite), pipe_name(pipe));
 		}
 	} else if (INTEL_INFO(dev)->gen >= 7) {
 		reg = SPRCTL(pipe);
 		val = I915_READ(reg);
-		WARN(val & SPRITE_ENABLE,
+		I915_STATE_WARN(val & SPRITE_ENABLE,
 		     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
 		     plane_name(pipe), pipe_name(pipe));
 	} else if (INTEL_INFO(dev)->gen >= 5) {
 		reg = DVSCNTR(pipe);
 		val = I915_READ(reg);
-		WARN(val & DVS_ENABLE,
+		I915_STATE_WARN(val & DVS_ENABLE,
 		     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
 		     plane_name(pipe), pipe_name(pipe));
 	}
@@ -1328,7 +1331,7 @@
 
 static void assert_vblank_disabled(struct drm_crtc *crtc)
 {
-	if (WARN_ON(drm_crtc_vblank_get(crtc) == 0))
+	if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
 		drm_crtc_vblank_put(crtc);
 }
 
@@ -1337,12 +1340,12 @@
 	u32 val;
 	bool enabled;
 
-	WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
+	I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
 
 	val = I915_READ(PCH_DREF_CONTROL);
 	enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
 			    DREF_SUPERSPREAD_SOURCE_MASK));
-	WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
+	I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
 }
 
 static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
@@ -1355,7 +1358,7 @@
 	reg = PCH_TRANSCONF(pipe);
 	val = I915_READ(reg);
 	enabled = !!(val & TRANS_ENABLE);
-	WARN(enabled,
+	I915_STATE_WARN(enabled,
 	     "transcoder assertion failed, should be off on pipe %c but is still active\n",
 	     pipe_name(pipe));
 }
@@ -1435,11 +1438,11 @@
 				   enum pipe pipe, int reg, u32 port_sel)
 {
 	u32 val = I915_READ(reg);
-	WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
+	I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
 	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
 	     reg, pipe_name(pipe));
 
-	WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
+	I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
 	     && (val & DP_PIPEB_SELECT),
 	     "IBX PCH dp port still using transcoder B\n");
 }
@@ -1448,11 +1451,11 @@
 				     enum pipe pipe, int reg)
 {
 	u32 val = I915_READ(reg);
-	WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
+	I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
 	     "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
 	     reg, pipe_name(pipe));
 
-	WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
+	I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
 	     && (val & SDVO_PIPE_B_SELECT),
 	     "IBX PCH hdmi port still using transcoder B\n");
 }
@@ -1469,13 +1472,13 @@
 
 	reg = PCH_ADPA;
 	val = I915_READ(reg);
-	WARN(adpa_pipe_enabled(dev_priv, pipe, val),
+	I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val),
 	     "PCH VGA enabled on transcoder %c, should be disabled\n",
 	     pipe_name(pipe));
 
 	reg = PCH_LVDS;
 	val = I915_READ(reg);
-	WARN(lvds_pipe_enabled(dev_priv, pipe, val),
+	I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val),
 	     "PCH LVDS enabled on transcoder %c, should be disabled\n",
 	     pipe_name(pipe));
 
@@ -1505,7 +1508,7 @@
 }
 
 static void vlv_enable_pll(struct intel_crtc *crtc,
-			   const struct intel_crtc_config *pipe_config)
+			   const struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1544,7 +1547,7 @@
 }
 
 static void chv_enable_pll(struct intel_crtc *crtc,
-			   const struct intel_crtc_config *pipe_config)
+			   const struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1599,7 +1602,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int reg = DPLL(crtc->pipe);
-	u32 dpll = crtc->config.dpll_hw_state.dpll;
+	u32 dpll = crtc->config->dpll_hw_state.dpll;
 
 	assert_pipe_disabled(dev_priv, crtc->pipe);
 
@@ -1629,7 +1632,7 @@
 
 	if (INTEL_INFO(dev)->gen >= 4) {
 		I915_WRITE(DPLL_MD(crtc->pipe),
-			   crtc->config.dpll_hw_state.dpll_md);
+			   crtc->config->dpll_hw_state.dpll_md);
 	} else {
 		/* The pixel multiplier can only be updated once the
 		 * DPLL is enabled and the clocks are stable.
@@ -2034,7 +2037,7 @@
 		else
 			assert_pll_enabled(dev_priv, pipe);
 	else {
-		if (crtc->config.has_pch_encoder) {
+		if (crtc->config->has_pch_encoder) {
 			/* if driving the PCH, we need FDI enabled */
 			assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
 			assert_fdi_tx_pll_enabled(dev_priv,
@@ -2068,7 +2071,7 @@
 static void intel_disable_pipe(struct intel_crtc *crtc)
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-	enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 	enum pipe pipe = crtc->pipe;
 	int reg;
 	u32 val;
@@ -2090,7 +2093,7 @@
 	 * Double wide has implications for planes
 	 * so best keep it disabled when not needed.
 	 */
-	if (crtc->config.double_wide)
+	if (crtc->config->double_wide)
 		val &= ~PIPECONF_DOUBLE_WIDE;
 
 	/* Don't disable pipe or pipe PLLs if needed */
@@ -2165,7 +2168,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	assert_pipe_enabled(dev_priv, intel_crtc->pipe);
+	if (WARN_ON(!intel_crtc->active))
+		return;
 
 	if (!intel_crtc->primary_enabled)
 		return;
@@ -2185,11 +2189,12 @@
 	return false;
 }
 
-static int intel_align_height(struct drm_device *dev, int height, bool tiled)
+int
+intel_fb_align_height(struct drm_device *dev, int height, unsigned int tiling)
 {
 	int tile_height;
 
-	tile_height = tiled ? (IS_GEN2(dev) ? 16 : 8) : 1;
+	tile_height = tiling ? (IS_GEN2(dev) ? 16 : 8) : 1;
 	return ALIGN(height, tile_height);
 }
 
@@ -2312,7 +2317,7 @@
 	}
 }
 
-int intel_format_to_fourcc(int format)
+static int i9xx_format_to_fourcc(int format)
 {
 	switch (format) {
 	case DISPPLANE_8BPP:
@@ -2333,8 +2338,35 @@
 	}
 }
 
-static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
-				  struct intel_plane_config *plane_config)
+static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
+{
+	switch (format) {
+	case PLANE_CTL_FORMAT_RGB_565:
+		return DRM_FORMAT_RGB565;
+	default:
+	case PLANE_CTL_FORMAT_XRGB_8888:
+		if (rgb_order) {
+			if (alpha)
+				return DRM_FORMAT_ABGR8888;
+			else
+				return DRM_FORMAT_XBGR8888;
+		} else {
+			if (alpha)
+				return DRM_FORMAT_ARGB8888;
+			else
+				return DRM_FORMAT_XRGB8888;
+		}
+	case PLANE_CTL_FORMAT_XRGB_2101010:
+		if (rgb_order)
+			return DRM_FORMAT_XBGR2101010;
+		else
+			return DRM_FORMAT_XRGB2101010;
+	}
+}
+
+static bool
+intel_alloc_plane_obj(struct intel_crtc *crtc,
+		      struct intel_initial_plane_config *plane_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_gem_object *obj = NULL;
@@ -2349,10 +2381,9 @@
 	if (!obj)
 		return false;
 
-	if (plane_config->tiled) {
-		obj->tiling_mode = I915_TILING_X;
+	obj->tiling_mode = plane_config->tiling;
+	if (obj->tiling_mode == I915_TILING_X)
 		obj->stride = crtc->base.primary->fb->pitches[0];
-	}
 
 	mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
 	mode_cmd.width = crtc->base.primary->fb->width;
@@ -2379,8 +2410,9 @@
 	return false;
 }
 
-static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
-				 struct intel_plane_config *plane_config)
+static void
+intel_find_plane_obj(struct intel_crtc *intel_crtc,
+		     struct intel_initial_plane_config *plane_config)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2468,13 +2500,13 @@
 		 * which should always be the user's requested size.
 		 */
 		I915_WRITE(DSPSIZE(plane),
-			   ((intel_crtc->config.pipe_src_h - 1) << 16) |
-			   (intel_crtc->config.pipe_src_w - 1));
+			   ((intel_crtc->config->pipe_src_h - 1) << 16) |
+			   (intel_crtc->config->pipe_src_w - 1));
 		I915_WRITE(DSPPOS(plane), 0);
 	} else if (IS_CHERRYVIEW(dev) && plane == PLANE_B) {
 		I915_WRITE(PRIMSIZE(plane),
-			   ((intel_crtc->config.pipe_src_h - 1) << 16) |
-			   (intel_crtc->config.pipe_src_w - 1));
+			   ((intel_crtc->config->pipe_src_h - 1) << 16) |
+			   (intel_crtc->config->pipe_src_w - 1));
 		I915_WRITE(PRIMPOS(plane), 0);
 		I915_WRITE(PRIMCNSTALPHA(plane), 0);
 	}
@@ -2529,17 +2561,17 @@
 		intel_crtc->dspaddr_offset = linear_offset;
 	}
 
-	if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+	if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
 		dspcntr |= DISPPLANE_ROTATE_180;
 
-		x += (intel_crtc->config.pipe_src_w - 1);
-		y += (intel_crtc->config.pipe_src_h - 1);
+		x += (intel_crtc->config->pipe_src_w - 1);
+		y += (intel_crtc->config->pipe_src_h - 1);
 
 		/* Finding the last pixel of the last line of the display
 		data and adding to linear_offset*/
 		linear_offset +=
-			(intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
-			(intel_crtc->config.pipe_src_w - 1) * pixel_size;
+			(intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
+			(intel_crtc->config->pipe_src_w - 1) * pixel_size;
 	}
 
 	I915_WRITE(reg, dspcntr);
@@ -2631,18 +2663,18 @@
 					       pixel_size,
 					       fb->pitches[0]);
 	linear_offset -= intel_crtc->dspaddr_offset;
-	if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+	if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
 		dspcntr |= DISPPLANE_ROTATE_180;
 
 		if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
-			x += (intel_crtc->config.pipe_src_w - 1);
-			y += (intel_crtc->config.pipe_src_h - 1);
+			x += (intel_crtc->config->pipe_src_w - 1);
+			y += (intel_crtc->config->pipe_src_h - 1);
 
 			/* Finding the last pixel of the last line of the display
 			data and adding to linear_offset*/
 			linear_offset +=
-				(intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
-				(intel_crtc->config.pipe_src_w - 1) * pixel_size;
+				(intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
+				(intel_crtc->config->pipe_src_w - 1) * pixel_size;
 		}
 	}
 
@@ -2728,7 +2760,7 @@
 	}
 
 	plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
-	if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180))
+	if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180))
 		plane_ctl |= PLANE_CTL_ROTATE_180;
 
 	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
@@ -2741,8 +2773,8 @@
 	I915_WRITE(PLANE_POS(pipe, 0), 0);
 	I915_WRITE(PLANE_OFFSET(pipe, 0), (y << 16) | x);
 	I915_WRITE(PLANE_SIZE(pipe, 0),
-		   (intel_crtc->config.pipe_src_h - 1) << 16 |
-		   (intel_crtc->config.pipe_src_w - 1));
+		   (intel_crtc->config->pipe_src_h - 1) << 16 |
+		   (intel_crtc->config->pipe_src_w - 1));
 	I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
 	I915_WRITE(PLANE_SURF(pipe, 0), i915_gem_obj_ggtt_offset(obj));
 
@@ -2938,85 +2970,20 @@
 	 * then update the pipesrc and pfit state, even on the flip path.
 	 */
 
-	adjusted_mode = &crtc->config.adjusted_mode;
+	adjusted_mode = &crtc->config->base.adjusted_mode;
 
 	I915_WRITE(PIPESRC(crtc->pipe),
 		   ((adjusted_mode->crtc_hdisplay - 1) << 16) |
 		   (adjusted_mode->crtc_vdisplay - 1));
-	if (!crtc->config.pch_pfit.enabled &&
+	if (!crtc->config->pch_pfit.enabled &&
 	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
 	     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
 		I915_WRITE(PF_CTL(crtc->pipe), 0);
 		I915_WRITE(PF_WIN_POS(crtc->pipe), 0);
 		I915_WRITE(PF_WIN_SZ(crtc->pipe), 0);
 	}
-	crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay;
-	crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
-}
-
-static int
-intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
-		    struct drm_framebuffer *fb)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_framebuffer *old_fb = crtc->primary->fb;
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
-	int ret;
-
-	if (intel_crtc_has_pending_flip(crtc)) {
-		DRM_ERROR("pipe is still busy with an old pageflip\n");
-		return -EBUSY;
-	}
-
-	/* no fb bound */
-	if (!fb) {
-		DRM_ERROR("No FB bound\n");
-		return 0;
-	}
-
-	if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
-		DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n",
-			  plane_name(intel_crtc->plane),
-			  INTEL_INFO(dev)->num_pipes);
-		return -EINVAL;
-	}
-
-	mutex_lock(&dev->struct_mutex);
-	ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
-	if (ret == 0)
-		i915_gem_track_fb(old_obj, intel_fb_obj(fb),
-				  INTEL_FRONTBUFFER_PRIMARY(pipe));
-	mutex_unlock(&dev->struct_mutex);
-	if (ret != 0) {
-		DRM_ERROR("pin & fence failed\n");
-		return ret;
-	}
-
-	dev_priv->display.update_primary_plane(crtc, fb, x, y);
-
-	if (intel_crtc->active)
-		intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
-
-	crtc->primary->fb = fb;
-	crtc->x = x;
-	crtc->y = y;
-
-	if (old_fb) {
-		if (intel_crtc->active && old_fb != fb)
-			intel_wait_for_vblank(dev, intel_crtc->pipe);
-		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(old_obj);
-		mutex_unlock(&dev->struct_mutex);
-	}
-
-	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
-	mutex_unlock(&dev->struct_mutex);
-
-	return 0;
+	crtc->config->pipe_src_w = adjusted_mode->crtc_hdisplay;
+	crtc->config->pipe_src_h = adjusted_mode->crtc_vdisplay;
 }
 
 static void intel_fdi_normal_train(struct drm_crtc *crtc)
@@ -3063,7 +3030,7 @@
 static bool pipe_has_enabled_pch(struct intel_crtc *crtc)
 {
 	return crtc->base.enabled && crtc->active &&
-		crtc->config.has_pch_encoder;
+		crtc->config->has_pch_encoder;
 }
 
 static void ivb_modeset_global_resources(struct drm_device *dev)
@@ -3118,7 +3085,7 @@
 	reg = FDI_TX_CTL(pipe);
 	temp = I915_READ(reg);
 	temp &= ~FDI_DP_PORT_WIDTH_MASK;
-	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
 	I915_WRITE(reg, temp | FDI_TX_ENABLE);
@@ -3216,7 +3183,7 @@
 	reg = FDI_TX_CTL(pipe);
 	temp = I915_READ(reg);
 	temp &= ~FDI_DP_PORT_WIDTH_MASK;
-	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
 	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -3367,7 +3334,7 @@
 		reg = FDI_TX_CTL(pipe);
 		temp = I915_READ(reg);
 		temp &= ~FDI_DP_PORT_WIDTH_MASK;
-		temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+		temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
 		temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
 		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 		temp |= snb_b_fdi_train_param[j/2];
@@ -3455,7 +3422,7 @@
 	reg = FDI_RX_CTL(pipe);
 	temp = I915_READ(reg);
 	temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
-	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+	temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
 	temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
 	I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
@@ -3639,7 +3606,7 @@
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
+	int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
 	u32 divsel, phaseinc, auxdiv, phasedir = 0;
 	u32 temp;
 
@@ -3728,7 +3695,7 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
 
 	I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
 		   I915_READ(HTOTAL(cpu_transcoder)));
@@ -3774,7 +3741,7 @@
 	case PIPE_A:
 		break;
 	case PIPE_B:
-		if (intel_crtc->config.fdi_lanes > 2)
+		if (intel_crtc->config->fdi_lanes > 2)
 			WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT);
 		else
 			cpt_enable_fdi_bc_bifurcation(dev);
@@ -3826,7 +3793,7 @@
 		temp = I915_READ(PCH_DPLL_SEL);
 		temp |= TRANS_DPLL_ENABLE(pipe);
 		sel = TRANS_DPLLB_SEL(pipe);
-		if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B)
+		if (intel_crtc->config->shared_dpll == DPLL_ID_PCH_PLL_B)
 			temp |= sel;
 		else
 			temp &= ~sel;
@@ -3849,7 +3816,7 @@
 	intel_fdi_normal_train(crtc);
 
 	/* For PCH DP, enable TRANS_DP_CTL */
-	if (HAS_PCH_CPT(dev) && intel_crtc->config.has_dp_encoder) {
+	if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) {
 		u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
 		reg = TRANS_DP_CTL(pipe);
 		temp = I915_READ(reg);
@@ -3890,7 +3857,7 @@
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 
 	assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A);
 
@@ -3920,10 +3887,11 @@
 		WARN_ON(pll->active);
 	}
 
-	crtc->config.shared_dpll = DPLL_ID_PRIVATE;
+	crtc->config->shared_dpll = DPLL_ID_PRIVATE;
 }
 
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+						struct intel_crtc_state *crtc_state)
 {
 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 	struct intel_shared_dpll *pll;
@@ -3949,7 +3917,7 @@
 		if (pll->new_config->crtc_mask == 0)
 			continue;
 
-		if (memcmp(&crtc->new_config->dpll_hw_state,
+		if (memcmp(&crtc_state->dpll_hw_state,
 			   &pll->new_config->hw_state,
 			   sizeof(pll->new_config->hw_state)) == 0) {
 			DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
@@ -3974,9 +3942,9 @@
 
 found:
 	if (pll->new_config->crtc_mask == 0)
-		pll->new_config->hw_state = crtc->new_config->dpll_hw_state;
+		pll->new_config->hw_state = crtc_state->dpll_hw_state;
 
-	crtc->new_config->shared_dpll = i;
+	crtc_state->shared_dpll = i;
 	DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
 			 pipe_name(crtc->pipe));
 
@@ -4073,10 +4041,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = crtc->pipe;
 
-	if (crtc->config.pch_pfit.enabled) {
+	if (crtc->config->pch_pfit.enabled) {
 		I915_WRITE(PS_CTL(pipe), PS_ENABLE);
-		I915_WRITE(PS_WIN_POS(pipe), crtc->config.pch_pfit.pos);
-		I915_WRITE(PS_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+		I915_WRITE(PS_WIN_POS(pipe), crtc->config->pch_pfit.pos);
+		I915_WRITE(PS_WIN_SZ(pipe), crtc->config->pch_pfit.size);
 	}
 }
 
@@ -4086,7 +4054,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = crtc->pipe;
 
-	if (crtc->config.pch_pfit.enabled) {
+	if (crtc->config->pch_pfit.enabled) {
 		/* Force use of hard-coded filter coefficients
 		 * as some pre-programmed values are broken,
 		 * e.g. x201.
@@ -4096,12 +4064,12 @@
 						 PF_PIPE_SEL_IVB(pipe));
 		else
 			I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
-		I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos);
-		I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+		I915_WRITE(PF_WIN_POS(pipe), crtc->config->pch_pfit.pos);
+		I915_WRITE(PF_WIN_SZ(pipe), crtc->config->pch_pfit.size);
 	}
 }
 
-static void intel_enable_planes(struct drm_crtc *crtc)
+static void intel_enable_sprite_planes(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@ -4115,7 +4083,7 @@
 	}
 }
 
-static void intel_disable_planes(struct drm_crtc *crtc)
+static void intel_disable_sprite_planes(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@ -4125,7 +4093,7 @@
 	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
 		intel_plane = to_intel_plane(plane);
 		if (intel_plane->pipe == pipe)
-			intel_plane_disable(&intel_plane->base);
+			plane->funcs->disable_plane(plane);
 	}
 }
 
@@ -4134,7 +4102,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!crtc->config.ips_enabled)
+	if (!crtc->config->ips_enabled)
 		return;
 
 	/* We can only enable IPS after we enable a plane and wait for a vblank */
@@ -4167,7 +4135,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!crtc->config.ips_enabled)
+	if (!crtc->config->ips_enabled)
 		return;
 
 	assert_plane_enabled(dev_priv, crtc->plane);
@@ -4216,7 +4184,7 @@
 	/* Workaround : Do not read or write the pipe palette/gamma data while
 	 * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
 	 */
-	if (IS_HASWELL(dev) && intel_crtc->config.ips_enabled &&
+	if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
 	    ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
 	     GAMMA_MODE_MODE_SPLIT)) {
 		hsw_disable_ips(intel_crtc);
@@ -4259,14 +4227,14 @@
 	int pipe = intel_crtc->pipe;
 
 	intel_enable_primary_hw_plane(crtc->primary, crtc);
-	intel_enable_planes(crtc);
+	intel_enable_sprite_planes(crtc);
 	intel_crtc_update_cursor(crtc, true);
 	intel_crtc_dpms_overlay(intel_crtc, true);
 
 	hsw_enable_ips(intel_crtc);
 
 	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 
 	/*
@@ -4288,13 +4256,13 @@
 	intel_crtc_wait_for_pending_flips(crtc);
 
 	if (dev_priv->fbc.plane == plane)
-		intel_disable_fbc(dev);
+		intel_fbc_disable(dev);
 
 	hsw_disable_ips(intel_crtc);
 
 	intel_crtc_dpms_overlay(intel_crtc, false);
 	intel_crtc_update_cursor(crtc, false);
-	intel_disable_planes(crtc);
+	intel_disable_sprite_planes(crtc);
 	intel_disable_primary_hw_plane(crtc->primary, crtc);
 
 	/*
@@ -4318,17 +4286,17 @@
 	if (intel_crtc->active)
 		return;
 
-	if (intel_crtc->config.has_pch_encoder)
+	if (intel_crtc->config->has_pch_encoder)
 		intel_prepare_shared_dpll(intel_crtc);
 
-	if (intel_crtc->config.has_dp_encoder)
+	if (intel_crtc->config->has_dp_encoder)
 		intel_dp_set_m_n(intel_crtc);
 
 	intel_set_pipe_timings(intel_crtc);
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		intel_cpu_transcoder_set_m_n(intel_crtc,
-				     &intel_crtc->config.fdi_m_n, NULL);
+				     &intel_crtc->config->fdi_m_n, NULL);
 	}
 
 	ironlake_set_pipeconf(crtc);
@@ -4342,7 +4310,7 @@
 		if (encoder->pre_enable)
 			encoder->pre_enable(encoder);
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		/* Note: FDI PLL enabling _must_ be done before we enable the
 		 * cpu pipes, hence this is separate from all the other fdi/pch
 		 * enabling. */
@@ -4363,18 +4331,18 @@
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
-	if (intel_crtc->config.has_pch_encoder)
+	if (intel_crtc->config->has_pch_encoder)
 		ironlake_pch_enable(crtc);
 
+	assert_vblank_disabled(crtc);
+	drm_crtc_vblank_on(crtc);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->enable(encoder);
 
 	if (HAS_PCH_CPT(dev))
 		cpt_verify_modeset(dev, intel_crtc->pipe);
 
-	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
-
 	intel_crtc_enable_planes(crtc);
 }
 
@@ -4429,19 +4397,19 @@
 	if (intel_crtc_to_shared_dpll(intel_crtc))
 		intel_enable_shared_dpll(intel_crtc);
 
-	if (intel_crtc->config.has_dp_encoder)
+	if (intel_crtc->config->has_dp_encoder)
 		intel_dp_set_m_n(intel_crtc);
 
 	intel_set_pipe_timings(intel_crtc);
 
-	if (intel_crtc->config.cpu_transcoder != TRANSCODER_EDP) {
-		I915_WRITE(PIPE_MULT(intel_crtc->config.cpu_transcoder),
-			   intel_crtc->config.pixel_multiplier - 1);
+	if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) {
+		I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder),
+			   intel_crtc->config->pixel_multiplier - 1);
 	}
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		intel_cpu_transcoder_set_m_n(intel_crtc,
-				     &intel_crtc->config.fdi_m_n, NULL);
+				     &intel_crtc->config->fdi_m_n, NULL);
 	}
 
 	haswell_set_pipeconf(crtc);
@@ -4455,7 +4423,7 @@
 		if (encoder->pre_enable)
 			encoder->pre_enable(encoder);
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 						      true);
 		dev_priv->display.fdi_link_train(crtc);
@@ -4480,20 +4448,20 @@
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
-	if (intel_crtc->config.has_pch_encoder)
+	if (intel_crtc->config->has_pch_encoder)
 		lpt_pch_enable(crtc);
 
-	if (intel_crtc->config.dp_encoder_is_mst)
+	if (intel_crtc->config->dp_encoder_is_mst)
 		intel_ddi_set_vc_payload_alloc(crtc, true);
 
+	assert_vblank_disabled(crtc);
+	drm_crtc_vblank_on(crtc);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		encoder->enable(encoder);
 		intel_opregion_notify_encoder(encoder, true);
 	}
 
-	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
-
 	/* If we change the relative order between pipe/planes enabling, we need
 	 * to change the workaround. */
 	haswell_mode_set_planes_workaround(intel_crtc);
@@ -4508,7 +4476,7 @@
 
 	/* To avoid upsetting the power well on haswell only disable the pfit if
 	 * it's in use. The hw state code will make sure we get this right. */
-	if (crtc->config.pch_pfit.enabled) {
+	if (crtc->config->pch_pfit.enabled) {
 		I915_WRITE(PS_CTL(pipe), 0);
 		I915_WRITE(PS_WIN_POS(pipe), 0);
 		I915_WRITE(PS_WIN_SZ(pipe), 0);
@@ -4523,7 +4491,7 @@
 
 	/* To avoid upsetting the power well on haswell only disable the pfit if
 	 * it's in use. The hw state code will make sure we get this right. */
-	if (crtc->config.pch_pfit.enabled) {
+	if (crtc->config->pch_pfit.enabled) {
 		I915_WRITE(PF_CTL(pipe), 0);
 		I915_WRITE(PF_WIN_POS(pipe), 0);
 		I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -4544,13 +4512,13 @@
 
 	intel_crtc_disable_planes(crtc);
 
-	drm_crtc_vblank_off(crtc);
-	assert_vblank_disabled(crtc);
-
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->disable(encoder);
 
-	if (intel_crtc->config.has_pch_encoder)
+	drm_crtc_vblank_off(crtc);
+	assert_vblank_disabled(crtc);
+
+	if (intel_crtc->config->has_pch_encoder)
 		intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
 
 	intel_disable_pipe(intel_crtc);
@@ -4561,7 +4529,7 @@
 		if (encoder->post_disable)
 			encoder->post_disable(encoder);
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		ironlake_fdi_disable(crtc);
 
 		ironlake_disable_pch_transcoder(dev_priv, pipe);
@@ -4591,7 +4559,7 @@
 	intel_update_watermarks(crtc);
 
 	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 }
 
@@ -4601,27 +4569,27 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_encoder *encoder;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 
 	if (!intel_crtc->active)
 		return;
 
 	intel_crtc_disable_planes(crtc);
 
-	drm_crtc_vblank_off(crtc);
-	assert_vblank_disabled(crtc);
-
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		intel_opregion_notify_encoder(encoder, false);
 		encoder->disable(encoder);
 	}
 
-	if (intel_crtc->config.has_pch_encoder)
+	drm_crtc_vblank_off(crtc);
+	assert_vblank_disabled(crtc);
+
+	if (intel_crtc->config->has_pch_encoder)
 		intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
 						      false);
 	intel_disable_pipe(intel_crtc);
 
-	if (intel_crtc->config.dp_encoder_is_mst)
+	if (intel_crtc->config->dp_encoder_is_mst)
 		intel_ddi_set_vc_payload_alloc(crtc, false);
 
 	intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
@@ -4633,7 +4601,7 @@
 
 	intel_ddi_disable_pipe_clock(intel_crtc);
 
-	if (intel_crtc->config.has_pch_encoder) {
+	if (intel_crtc->config->has_pch_encoder) {
 		lpt_disable_pch_transcoder(dev_priv);
 		intel_ddi_fdi_disable(crtc);
 	}
@@ -4646,7 +4614,7 @@
 	intel_update_watermarks(crtc);
 
 	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 
 	if (intel_crtc_to_shared_dpll(intel_crtc))
@@ -4664,9 +4632,9 @@
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc_config *pipe_config = &crtc->config;
+	struct intel_crtc_state *pipe_config = crtc->config;
 
-	if (!crtc->config.gmch_pfit.control)
+	if (!pipe_config->gmch_pfit.control)
 		return;
 
 	/*
@@ -4745,8 +4713,8 @@
 
 	mask = BIT(POWER_DOMAIN_PIPE(pipe));
 	mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
-	if (intel_crtc->config.pch_pfit.enabled ||
-	    intel_crtc->config.pch_pfit.force_thru)
+	if (intel_crtc->config->pch_pfit.enabled ||
+	    intel_crtc->config->pch_pfit.force_thru)
 		mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
 
 	for_each_encoder_on_crtc(dev, crtc, intel_encoder)
@@ -4909,7 +4877,7 @@
 		cmd = 0;
 		break;
 	default:
-		WARN_ON(1);
+		MISSING_CASE(cdclk);
 		return;
 	}
 
@@ -4970,7 +4938,7 @@
 	for_each_intel_crtc(dev, intel_crtc) {
 		if (intel_crtc->new_enabled)
 			max_pixclk = max(max_pixclk,
-					 intel_crtc->new_config->adjusted_mode.crtc_clock);
+					 intel_crtc->new_config->base.adjusted_mode.crtc_clock);
 	}
 
 	return max_pixclk;
@@ -5038,12 +5006,12 @@
 
 	if (!is_dsi) {
 		if (IS_CHERRYVIEW(dev))
-			chv_prepare_pll(intel_crtc, &intel_crtc->config);
+			chv_prepare_pll(intel_crtc, intel_crtc->config);
 		else
-			vlv_prepare_pll(intel_crtc, &intel_crtc->config);
+			vlv_prepare_pll(intel_crtc, intel_crtc->config);
 	}
 
-	if (intel_crtc->config.has_dp_encoder)
+	if (intel_crtc->config->has_dp_encoder)
 		intel_dp_set_m_n(intel_crtc);
 
 	intel_set_pipe_timings(intel_crtc);
@@ -5067,9 +5035,9 @@
 
 	if (!is_dsi) {
 		if (IS_CHERRYVIEW(dev))
-			chv_enable_pll(intel_crtc, &intel_crtc->config);
+			chv_enable_pll(intel_crtc, intel_crtc->config);
 		else
-			vlv_enable_pll(intel_crtc, &intel_crtc->config);
+			vlv_enable_pll(intel_crtc, intel_crtc->config);
 	}
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -5083,12 +5051,12 @@
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
-	for_each_encoder_on_crtc(dev, crtc, encoder)
-		encoder->enable(encoder);
-
 	assert_vblank_disabled(crtc);
 	drm_crtc_vblank_on(crtc);
 
+	for_each_encoder_on_crtc(dev, crtc, encoder)
+		encoder->enable(encoder);
+
 	intel_crtc_enable_planes(crtc);
 
 	/* Underruns don't raise interrupts, so check manually. */
@@ -5100,8 +5068,8 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	I915_WRITE(FP0(crtc->pipe), crtc->config.dpll_hw_state.fp0);
-	I915_WRITE(FP1(crtc->pipe), crtc->config.dpll_hw_state.fp1);
+	I915_WRITE(FP0(crtc->pipe), crtc->config->dpll_hw_state.fp0);
+	I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
 }
 
 static void i9xx_crtc_enable(struct drm_crtc *crtc)
@@ -5119,7 +5087,7 @@
 
 	i9xx_set_pll_dividers(intel_crtc);
 
-	if (intel_crtc->config.has_dp_encoder)
+	if (intel_crtc->config->has_dp_encoder)
 		intel_dp_set_m_n(intel_crtc);
 
 	intel_set_pipe_timings(intel_crtc);
@@ -5144,12 +5112,12 @@
 	intel_update_watermarks(crtc);
 	intel_enable_pipe(intel_crtc);
 
-	for_each_encoder_on_crtc(dev, crtc, encoder)
-		encoder->enable(encoder);
-
 	assert_vblank_disabled(crtc);
 	drm_crtc_vblank_on(crtc);
 
+	for_each_encoder_on_crtc(dev, crtc, encoder)
+		encoder->enable(encoder);
+
 	intel_crtc_enable_planes(crtc);
 
 	/*
@@ -5171,7 +5139,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (!crtc->config.gmch_pfit.control)
+	if (!crtc->config->gmch_pfit.control)
 		return;
 
 	assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -5221,12 +5189,12 @@
 	 */
 	intel_wait_for_vblank(dev, pipe);
 
-	drm_crtc_vblank_off(crtc);
-	assert_vblank_disabled(crtc);
-
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->disable(encoder);
 
+	drm_crtc_vblank_off(crtc);
+	assert_vblank_disabled(crtc);
+
 	intel_disable_pipe(intel_crtc);
 
 	i9xx_pfit_disable(intel_crtc);
@@ -5251,7 +5219,7 @@
 	intel_update_watermarks(crtc);
 
 	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 }
 
@@ -5309,8 +5277,6 @@
 	struct drm_device *dev = crtc->dev;
 	struct drm_connector *connector;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(crtc->primary->fb);
-	enum pipe pipe = to_intel_crtc(crtc)->pipe;
 
 	/* crtc should still be enabled when we disable it. */
 	WARN_ON(!crtc->enabled);
@@ -5318,14 +5284,7 @@
 	dev_priv->display.crtc_disable(crtc);
 	dev_priv->display.off(crtc);
 
-	if (crtc->primary->fb) {
-		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(old_obj);
-		i915_gem_track_fb(old_obj, NULL,
-				  INTEL_FRONTBUFFER_PRIMARY(pipe));
-		mutex_unlock(&dev->struct_mutex);
-		crtc->primary->fb = NULL;
-	}
+	crtc->primary->funcs->disable_plane(crtc->primary);
 
 	/* Update computed state. */
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -5382,25 +5341,25 @@
 		if (connector->mst_port)
 			return;
 
-		WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
+		I915_STATE_WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
 		     "wrong connector dpms state\n");
-		WARN(connector->base.encoder != &encoder->base,
+		I915_STATE_WARN(connector->base.encoder != &encoder->base,
 		     "active connector not linked to encoder\n");
 
 		if (encoder) {
-			WARN(!encoder->connectors_active,
+			I915_STATE_WARN(!encoder->connectors_active,
 			     "encoder->connectors_active not set\n");
 
 			encoder_enabled = encoder->get_hw_state(encoder, &pipe);
-			WARN(!encoder_enabled, "encoder not enabled\n");
-			if (WARN_ON(!encoder->base.crtc))
+			I915_STATE_WARN(!encoder_enabled, "encoder not enabled\n");
+			if (I915_STATE_WARN_ON(!encoder->base.crtc))
 				return;
 
 			crtc = encoder->base.crtc;
 
-			WARN(!crtc->enabled, "crtc not enabled\n");
-			WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
-			WARN(pipe != to_intel_crtc(crtc)->pipe,
+			I915_STATE_WARN(!crtc->enabled, "crtc not enabled\n");
+			I915_STATE_WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
+			I915_STATE_WARN(pipe != to_intel_crtc(crtc)->pipe,
 			     "encoder active on the wrong pipe\n");
 		}
 	}
@@ -5438,7 +5397,7 @@
 }
 
 static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *pipe_B_crtc =
@@ -5479,7 +5438,7 @@
 		return true;
 	case PIPE_C:
 		if (!pipe_has_enabled_pch(pipe_B_crtc) ||
-		    pipe_B_crtc->config.fdi_lanes <= 2) {
+		    pipe_B_crtc->config->fdi_lanes <= 2) {
 			if (pipe_config->fdi_lanes > 2) {
 				DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
 					      pipe_name(pipe), pipe_config->fdi_lanes);
@@ -5497,10 +5456,10 @@
 
 #define RETRY 1
 static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
-				       struct intel_crtc_config *pipe_config)
+				       struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	int lane, link_bw, fdi_dotclock;
 	bool setup_ok, needs_recompute = false;
 
@@ -5543,7 +5502,7 @@
 }
 
 static void hsw_compute_ips_config(struct intel_crtc *crtc,
-				   struct intel_crtc_config *pipe_config)
+				   struct intel_crtc_state *pipe_config)
 {
 	pipe_config->ips_enabled = i915.enable_ips &&
 				   hsw_crtc_supports_ips(crtc) &&
@@ -5551,11 +5510,11 @@
 }
 
 static int intel_crtc_compute_config(struct intel_crtc *crtc,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 
 	/* FIXME should check pixel clock limits on all platforms */
 	if (INTEL_INFO(dev)->gen < 4) {
@@ -5800,30 +5759,31 @@
 }
 
 static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
+				     struct intel_crtc_state *crtc_state,
 				     intel_clock_t *reduced_clock)
 {
 	struct drm_device *dev = crtc->base.dev;
 	u32 fp, fp2 = 0;
 
 	if (IS_PINEVIEW(dev)) {
-		fp = pnv_dpll_compute_fp(&crtc->new_config->dpll);
+		fp = pnv_dpll_compute_fp(&crtc_state->dpll);
 		if (reduced_clock)
 			fp2 = pnv_dpll_compute_fp(reduced_clock);
 	} else {
-		fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll);
+		fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
 		if (reduced_clock)
 			fp2 = i9xx_dpll_compute_fp(reduced_clock);
 	}
 
-	crtc->new_config->dpll_hw_state.fp0 = fp;
+	crtc_state->dpll_hw_state.fp0 = fp;
 
 	crtc->lowfreq_avail = false;
 	if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
 	    reduced_clock && i915.powersave) {
-		crtc->new_config->dpll_hw_state.fp1 = fp2;
+		crtc_state->dpll_hw_state.fp1 = fp2;
 		crtc->lowfreq_avail = true;
 	} else {
-		crtc->new_config->dpll_hw_state.fp1 = fp;
+		crtc_state->dpll_hw_state.fp1 = fp;
 	}
 }
 
@@ -5876,7 +5836,7 @@
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int pipe = crtc->pipe;
-	enum transcoder transcoder = crtc->config.cpu_transcoder;
+	enum transcoder transcoder = crtc->config->cpu_transcoder;
 
 	if (INTEL_INFO(dev)->gen >= 5) {
 		I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
@@ -5888,7 +5848,7 @@
 		 * registers are not unnecessarily accessed).
 		 */
 		if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
-			crtc->config.has_drrs) {
+			crtc->config->has_drrs) {
 			I915_WRITE(PIPE_DATA_M2(transcoder),
 					TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
 			I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
@@ -5905,15 +5865,15 @@
 
 void intel_dp_set_m_n(struct intel_crtc *crtc)
 {
-	if (crtc->config.has_pch_encoder)
-		intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+	if (crtc->config->has_pch_encoder)
+		intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
 	else
-		intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n,
-						   &crtc->config.dp_m2_n2);
+		intel_cpu_transcoder_set_m_n(crtc, &crtc->config->dp_m_n,
+						   &crtc->config->dp_m2_n2);
 }
 
 static void vlv_update_pll(struct intel_crtc *crtc,
-			   struct intel_crtc_config *pipe_config)
+			   struct intel_crtc_state *pipe_config)
 {
 	u32 dpll, dpll_md;
 
@@ -5936,7 +5896,7 @@
 }
 
 static void vlv_prepare_pll(struct intel_crtc *crtc,
-			    const struct intel_crtc_config *pipe_config)
+			    const struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5997,7 +5957,7 @@
 		vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
 				 0x00d0000f);
 
-	if (crtc->config.has_dp_encoder) {
+	if (pipe_config->has_dp_encoder) {
 		/* Use SSC source */
 		if (pipe == PIPE_A)
 			vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
@@ -6027,7 +5987,7 @@
 }
 
 static void chv_update_pll(struct intel_crtc *crtc,
-			   struct intel_crtc_config *pipe_config)
+			   struct intel_crtc_state *pipe_config)
 {
 	pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
 		DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS |
@@ -6040,7 +6000,7 @@
 }
 
 static void chv_prepare_pll(struct intel_crtc *crtc,
-			    const struct intel_crtc_config *pipe_config)
+			    const struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6125,7 +6085,7 @@
 {
 	struct intel_crtc *crtc =
 		to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
-	struct intel_crtc_config pipe_config = {
+	struct intel_crtc_state pipe_config = {
 		.pixel_multiplier = 1,
 		.dpll = *dpll,
 	};
@@ -6158,6 +6118,7 @@
 }
 
 static void i9xx_update_pll(struct intel_crtc *crtc,
+			    struct intel_crtc_state *crtc_state,
 			    intel_clock_t *reduced_clock,
 			    int num_connectors)
 {
@@ -6165,9 +6126,9 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpll;
 	bool is_sdvo;
-	struct dpll *clock = &crtc->new_config->dpll;
+	struct dpll *clock = &crtc_state->dpll;
 
-	i9xx_update_pll_dividers(crtc, reduced_clock);
+	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
 
 	is_sdvo = intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO) ||
 		intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI);
@@ -6180,14 +6141,14 @@
 		dpll |= DPLLB_MODE_DAC_SERIAL;
 
 	if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
-		dpll |= (crtc->new_config->pixel_multiplier - 1)
+		dpll |= (crtc_state->pixel_multiplier - 1)
 			<< SDVO_MULTIPLIER_SHIFT_HIRES;
 	}
 
 	if (is_sdvo)
 		dpll |= DPLL_SDVO_HIGH_SPEED;
 
-	if (crtc->new_config->has_dp_encoder)
+	if (crtc_state->has_dp_encoder)
 		dpll |= DPLL_SDVO_HIGH_SPEED;
 
 	/* compute bitmask from p1 value */
@@ -6215,7 +6176,7 @@
 	if (INTEL_INFO(dev)->gen >= 4)
 		dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 
-	if (crtc->new_config->sdvo_tv_clock)
+	if (crtc_state->sdvo_tv_clock)
 		dpll |= PLL_REF_INPUT_TVCLKINBC;
 	else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
 		 intel_panel_use_ssc(dev_priv) && num_connectors < 2)
@@ -6224,25 +6185,26 @@
 		dpll |= PLL_REF_INPUT_DREFCLK;
 
 	dpll |= DPLL_VCO_ENABLE;
-	crtc->new_config->dpll_hw_state.dpll = dpll;
+	crtc_state->dpll_hw_state.dpll = dpll;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
-		u32 dpll_md = (crtc->new_config->pixel_multiplier - 1)
+		u32 dpll_md = (crtc_state->pixel_multiplier - 1)
 			<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
-		crtc->new_config->dpll_hw_state.dpll_md = dpll_md;
+		crtc_state->dpll_hw_state.dpll_md = dpll_md;
 	}
 }
 
 static void i8xx_update_pll(struct intel_crtc *crtc,
+			    struct intel_crtc_state *crtc_state,
 			    intel_clock_t *reduced_clock,
 			    int num_connectors)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpll;
-	struct dpll *clock = &crtc->new_config->dpll;
+	struct dpll *clock = &crtc_state->dpll;
 
-	i9xx_update_pll_dividers(crtc, reduced_clock);
+	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
 
 	dpll = DPLL_VGA_MODE_DIS;
 
@@ -6267,7 +6229,7 @@
 		dpll |= PLL_REF_INPUT_DREFCLK;
 
 	dpll |= DPLL_VCO_ENABLE;
-	crtc->new_config->dpll_hw_state.dpll = dpll;
+	crtc_state->dpll_hw_state.dpll = dpll;
 }
 
 static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
@@ -6275,9 +6237,9 @@
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum pipe pipe = intel_crtc->pipe;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	struct drm_display_mode *adjusted_mode =
-		&intel_crtc->config.adjusted_mode;
+		&intel_crtc->config->base.adjusted_mode;
 	uint32_t crtc_vtotal, crtc_vblank_end;
 	int vsyncshift = 0;
 
@@ -6335,12 +6297,12 @@
 	 * always be the user's requested size.
 	 */
 	I915_WRITE(PIPESRC(pipe),
-		   ((intel_crtc->config.pipe_src_w - 1) << 16) |
-		   (intel_crtc->config.pipe_src_h - 1));
+		   ((intel_crtc->config->pipe_src_w - 1) << 16) |
+		   (intel_crtc->config->pipe_src_h - 1));
 }
 
 static void intel_get_pipe_timings(struct intel_crtc *crtc,
-				   struct intel_crtc_config *pipe_config)
+				   struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6348,56 +6310,56 @@
 	uint32_t tmp;
 
 	tmp = I915_READ(HTOTAL(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
 	tmp = I915_READ(HBLANK(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
 	tmp = I915_READ(HSYNC(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
 
 	tmp = I915_READ(VTOTAL(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
 	tmp = I915_READ(VBLANK(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
 	tmp = I915_READ(VSYNC(cpu_transcoder));
-	pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
-	pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
+	pipe_config->base.adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
 
 	if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) {
-		pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
-		pipe_config->adjusted_mode.crtc_vtotal += 1;
-		pipe_config->adjusted_mode.crtc_vblank_end += 1;
+		pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+		pipe_config->base.adjusted_mode.crtc_vtotal += 1;
+		pipe_config->base.adjusted_mode.crtc_vblank_end += 1;
 	}
 
 	tmp = I915_READ(PIPESRC(crtc->pipe));
 	pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
 	pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
 
-	pipe_config->requested_mode.vdisplay = pipe_config->pipe_src_h;
-	pipe_config->requested_mode.hdisplay = pipe_config->pipe_src_w;
+	pipe_config->base.mode.vdisplay = pipe_config->pipe_src_h;
+	pipe_config->base.mode.hdisplay = pipe_config->pipe_src_w;
 }
 
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
-	mode->hdisplay = pipe_config->adjusted_mode.crtc_hdisplay;
-	mode->htotal = pipe_config->adjusted_mode.crtc_htotal;
-	mode->hsync_start = pipe_config->adjusted_mode.crtc_hsync_start;
-	mode->hsync_end = pipe_config->adjusted_mode.crtc_hsync_end;
+	mode->hdisplay = pipe_config->base.adjusted_mode.crtc_hdisplay;
+	mode->htotal = pipe_config->base.adjusted_mode.crtc_htotal;
+	mode->hsync_start = pipe_config->base.adjusted_mode.crtc_hsync_start;
+	mode->hsync_end = pipe_config->base.adjusted_mode.crtc_hsync_end;
 
-	mode->vdisplay = pipe_config->adjusted_mode.crtc_vdisplay;
-	mode->vtotal = pipe_config->adjusted_mode.crtc_vtotal;
-	mode->vsync_start = pipe_config->adjusted_mode.crtc_vsync_start;
-	mode->vsync_end = pipe_config->adjusted_mode.crtc_vsync_end;
+	mode->vdisplay = pipe_config->base.adjusted_mode.crtc_vdisplay;
+	mode->vtotal = pipe_config->base.adjusted_mode.crtc_vtotal;
+	mode->vsync_start = pipe_config->base.adjusted_mode.crtc_vsync_start;
+	mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end;
 
-	mode->flags = pipe_config->adjusted_mode.flags;
+	mode->flags = pipe_config->base.adjusted_mode.flags;
 
-	mode->clock = pipe_config->adjusted_mode.crtc_clock;
-	mode->flags |= pipe_config->adjusted_mode.flags;
+	mode->clock = pipe_config->base.adjusted_mode.crtc_clock;
+	mode->flags |= pipe_config->base.adjusted_mode.flags;
 }
 
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
@@ -6412,17 +6374,17 @@
 	    (intel_crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
 		pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
 
-	if (intel_crtc->config.double_wide)
+	if (intel_crtc->config->double_wide)
 		pipeconf |= PIPECONF_DOUBLE_WIDE;
 
 	/* only g4x and later have fancy bpc/dither controls */
 	if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
 		/* Bspec claims that we can't use dithering for 30bpp pipes. */
-		if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30)
+		if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
 			pipeconf |= PIPECONF_DITHER_EN |
 				    PIPECONF_DITHER_TYPE_SP;
 
-		switch (intel_crtc->config.pipe_bpp) {
+		switch (intel_crtc->config->pipe_bpp) {
 		case 18:
 			pipeconf |= PIPECONF_6BPC;
 			break;
@@ -6447,7 +6409,7 @@
 		}
 	}
 
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
 		if (INTEL_INFO(dev)->gen < 4 ||
 		    intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_SDVO))
 			pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
@@ -6456,14 +6418,15 @@
 	} else
 		pipeconf |= PIPECONF_PROGRESSIVE;
 
-	if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range)
+	if (IS_VALLEYVIEW(dev) && intel_crtc->config->limited_color_range)
 		pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
 
 	I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
 	POSTING_READ(PIPECONF(intel_crtc->pipe));
 }
 
-static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
+static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
+				   struct intel_crtc_state *crtc_state)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6495,7 +6458,7 @@
 	if (is_dsi)
 		return 0;
 
-	if (!crtc->new_config->clock_set) {
+	if (!crtc_state->clock_set) {
 		refclk = i9xx_get_refclk(crtc, num_connectors);
 
 		/*
@@ -6506,7 +6469,7 @@
 		 */
 		limit = intel_limit(crtc, refclk);
 		ok = dev_priv->display.find_dpll(limit, crtc,
-						 crtc->new_config->port_clock,
+						 crtc_state->port_clock,
 						 refclk, NULL, &clock);
 		if (!ok) {
 			DRM_ERROR("Couldn't find PLL settings for mode!\n");
@@ -6527,23 +6490,23 @@
 							    &reduced_clock);
 		}
 		/* Compat-code for transition, will disappear. */
-		crtc->new_config->dpll.n = clock.n;
-		crtc->new_config->dpll.m1 = clock.m1;
-		crtc->new_config->dpll.m2 = clock.m2;
-		crtc->new_config->dpll.p1 = clock.p1;
-		crtc->new_config->dpll.p2 = clock.p2;
+		crtc_state->dpll.n = clock.n;
+		crtc_state->dpll.m1 = clock.m1;
+		crtc_state->dpll.m2 = clock.m2;
+		crtc_state->dpll.p1 = clock.p1;
+		crtc_state->dpll.p2 = clock.p2;
 	}
 
 	if (IS_GEN2(dev)) {
-		i8xx_update_pll(crtc,
+		i8xx_update_pll(crtc, crtc_state,
 				has_reduced_clock ? &reduced_clock : NULL,
 				num_connectors);
 	} else if (IS_CHERRYVIEW(dev)) {
-		chv_update_pll(crtc, crtc->new_config);
+		chv_update_pll(crtc, crtc_state);
 	} else if (IS_VALLEYVIEW(dev)) {
-		vlv_update_pll(crtc, crtc->new_config);
+		vlv_update_pll(crtc, crtc_state);
 	} else {
-		i9xx_update_pll(crtc,
+		i9xx_update_pll(crtc, crtc_state,
 				has_reduced_clock ? &reduced_clock : NULL,
 				num_connectors);
 	}
@@ -6552,7 +6515,7 @@
 }
 
 static void i9xx_get_pfit_config(struct intel_crtc *crtc,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6582,7 +6545,7 @@
 }
 
 static void vlv_crtc_clock_get(struct intel_crtc *crtc,
-			       struct intel_crtc_config *pipe_config)
+			       struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6611,8 +6574,9 @@
 	pipe_config->port_clock = clock.dot / 5;
 }
 
-static void i9xx_get_plane_config(struct intel_crtc *crtc,
-				  struct intel_plane_config *plane_config)
+static void
+i9xx_get_initial_plane_config(struct intel_crtc *crtc,
+			      struct intel_initial_plane_config *plane_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6620,27 +6584,30 @@
 	int pipe = crtc->pipe, plane = crtc->plane;
 	int fourcc, pixel_format;
 	int aligned_height;
+	struct drm_framebuffer *fb;
+	struct intel_framebuffer *intel_fb;
 
-	crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
-	if (!crtc->base.primary->fb) {
+	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+	if (!intel_fb) {
 		DRM_DEBUG_KMS("failed to alloc fb\n");
 		return;
 	}
 
+	fb = &intel_fb->base;
+
 	val = I915_READ(DSPCNTR(plane));
 
 	if (INTEL_INFO(dev)->gen >= 4)
 		if (val & DISPPLANE_TILED)
-			plane_config->tiled = true;
+			plane_config->tiling = I915_TILING_X;
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
-	fourcc = intel_format_to_fourcc(pixel_format);
-	crtc->base.primary->fb->pixel_format = fourcc;
-	crtc->base.primary->fb->bits_per_pixel =
-		drm_format_plane_cpp(fourcc, 0) * 8;
+	fourcc = i9xx_format_to_fourcc(pixel_format);
+	fb->pixel_format = fourcc;
+	fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
-		if (plane_config->tiled)
+		if (plane_config->tiling)
 			offset = I915_READ(DSPTILEOFF(plane));
 		else
 			offset = I915_READ(DSPLINOFF(plane));
@@ -6651,29 +6618,27 @@
 	plane_config->base = base;
 
 	val = I915_READ(PIPESRC(pipe));
-	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
-	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+	fb->width = ((val >> 16) & 0xfff) + 1;
+	fb->height = ((val >> 0) & 0xfff) + 1;
 
 	val = I915_READ(DSPSTRIDE(pipe));
-	crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
+	fb->pitches[0] = val & 0xffffffc0;
 
-	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
-					    plane_config->tiled);
+	aligned_height = intel_fb_align_height(dev, fb->height,
+					       plane_config->tiling);
 
-	plane_config->size = PAGE_ALIGN(crtc->base.primary->fb->pitches[0] *
-					aligned_height);
+	plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
 
-	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
-		      pipe, plane, crtc->base.primary->fb->width,
-		      crtc->base.primary->fb->height,
-		      crtc->base.primary->fb->bits_per_pixel, base,
-		      crtc->base.primary->fb->pitches[0],
+	DRM_DEBUG_KMS("pipe/plane %c/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+		      pipe_name(pipe), plane, fb->width, fb->height,
+		      fb->bits_per_pixel, base, fb->pitches[0],
 		      plane_config->size);
 
+	crtc->base.primary->fb = fb;
 }
 
 static void chv_crtc_clock_get(struct intel_crtc *crtc,
-			       struct intel_crtc_config *pipe_config)
+			       struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6703,7 +6668,7 @@
 }
 
 static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7183,7 +7148,7 @@
 
 	val = 0;
 
-	switch (intel_crtc->config.pipe_bpp) {
+	switch (intel_crtc->config->pipe_bpp) {
 	case 18:
 		val |= PIPECONF_6BPC;
 		break;
@@ -7201,15 +7166,15 @@
 		BUG();
 	}
 
-	if (intel_crtc->config.dither)
+	if (intel_crtc->config->dither)
 		val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
 		val |= PIPECONF_INTERLACED_ILK;
 	else
 		val |= PIPECONF_PROGRESSIVE;
 
-	if (intel_crtc->config.limited_color_range)
+	if (intel_crtc->config->limited_color_range)
 		val |= PIPECONF_COLOR_RANGE_SELECT;
 
 	I915_WRITE(PIPECONF(pipe), val);
@@ -7238,7 +7203,7 @@
 	 * consideration.
 	 */
 
-	if (intel_crtc->config.limited_color_range)
+	if (intel_crtc->config->limited_color_range)
 		coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
 
 	/*
@@ -7262,7 +7227,7 @@
 	if (INTEL_INFO(dev)->gen > 6) {
 		uint16_t postoff = 0;
 
-		if (intel_crtc->config.limited_color_range)
+		if (intel_crtc->config->limited_color_range)
 			postoff = (16 * (1 << 12) / 255) & 0x1fff;
 
 		I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
@@ -7273,7 +7238,7 @@
 	} else {
 		uint32_t mode = CSC_MODE_YUV_TO_RGB;
 
-		if (intel_crtc->config.limited_color_range)
+		if (intel_crtc->config->limited_color_range)
 			mode |= CSC_BLACK_SCREEN_OFFSET;
 
 		I915_WRITE(PIPE_CSC_MODE(pipe), mode);
@@ -7286,15 +7251,15 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	enum pipe pipe = intel_crtc->pipe;
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	uint32_t val;
 
 	val = 0;
 
-	if (IS_HASWELL(dev) && intel_crtc->config.dither)
+	if (IS_HASWELL(dev) && intel_crtc->config->dither)
 		val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
 		val |= PIPECONF_INTERLACED_ILK;
 	else
 		val |= PIPECONF_PROGRESSIVE;
@@ -7308,7 +7273,7 @@
 	if (IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
 		val = 0;
 
-		switch (intel_crtc->config.pipe_bpp) {
+		switch (intel_crtc->config->pipe_bpp) {
 		case 18:
 			val |= PIPEMISC_DITHER_6_BPC;
 			break;
@@ -7326,7 +7291,7 @@
 			BUG();
 		}
 
-		if (intel_crtc->config.dither)
+		if (intel_crtc->config->dither)
 			val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
 
 		I915_WRITE(PIPEMISC(pipe), val);
@@ -7334,6 +7299,7 @@
 }
 
 static bool ironlake_compute_clocks(struct drm_crtc *crtc,
+				    struct intel_crtc_state *crtc_state,
 				    intel_clock_t *clock,
 				    bool *has_reduced_clock,
 				    intel_clock_t *reduced_clock)
@@ -7356,7 +7322,7 @@
 	 */
 	limit = intel_limit(intel_crtc, refclk);
 	ret = dev_priv->display.find_dpll(limit, intel_crtc,
-					  intel_crtc->new_config->port_clock,
+					  crtc_state->port_clock,
 					  refclk, NULL, clock);
 	if (!ret)
 		return false;
@@ -7395,6 +7361,7 @@
 }
 
 static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
+				      struct intel_crtc_state *crtc_state,
 				      u32 *fp,
 				      intel_clock_t *reduced_clock, u32 *fp2)
 {
@@ -7432,10 +7399,10 @@
 		     dev_priv->vbt.lvds_ssc_freq == 100000) ||
 		    (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
 			factor = 25;
-	} else if (intel_crtc->new_config->sdvo_tv_clock)
+	} else if (crtc_state->sdvo_tv_clock)
 		factor = 20;
 
-	if (ironlake_needs_fb_cb_tune(&intel_crtc->new_config->dpll, factor))
+	if (ironlake_needs_fb_cb_tune(&crtc_state->dpll, factor))
 		*fp |= FP_CB_TUNE;
 
 	if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
@@ -7448,20 +7415,20 @@
 	else
 		dpll |= DPLLB_MODE_DAC_SERIAL;
 
-	dpll |= (intel_crtc->new_config->pixel_multiplier - 1)
+	dpll |= (crtc_state->pixel_multiplier - 1)
 		<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 
 	if (is_sdvo)
 		dpll |= DPLL_SDVO_HIGH_SPEED;
-	if (intel_crtc->new_config->has_dp_encoder)
+	if (crtc_state->has_dp_encoder)
 		dpll |= DPLL_SDVO_HIGH_SPEED;
 
 	/* compute bitmask from p1 value */
-	dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
 	/* also FPA1 */
-	dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
 
-	switch (intel_crtc->new_config->dpll.p2) {
+	switch (crtc_state->dpll.p2) {
 	case 5:
 		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
 		break;
@@ -7484,7 +7451,8 @@
 	return dpll | DPLL_VCO_ENABLE;
 }
 
-static int ironlake_crtc_compute_clock(struct intel_crtc *crtc)
+static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
+				       struct intel_crtc_state *crtc_state)
 {
 	struct drm_device *dev = crtc->base.dev;
 	intel_clock_t clock, reduced_clock;
@@ -7498,39 +7466,39 @@
 	WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
 	     "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
 
-	ok = ironlake_compute_clocks(&crtc->base, &clock,
+	ok = ironlake_compute_clocks(&crtc->base, crtc_state, &clock,
 				     &has_reduced_clock, &reduced_clock);
-	if (!ok && !crtc->new_config->clock_set) {
+	if (!ok && !crtc_state->clock_set) {
 		DRM_ERROR("Couldn't find PLL settings for mode!\n");
 		return -EINVAL;
 	}
 	/* Compat-code for transition, will disappear. */
-	if (!crtc->new_config->clock_set) {
-		crtc->new_config->dpll.n = clock.n;
-		crtc->new_config->dpll.m1 = clock.m1;
-		crtc->new_config->dpll.m2 = clock.m2;
-		crtc->new_config->dpll.p1 = clock.p1;
-		crtc->new_config->dpll.p2 = clock.p2;
+	if (!crtc_state->clock_set) {
+		crtc_state->dpll.n = clock.n;
+		crtc_state->dpll.m1 = clock.m1;
+		crtc_state->dpll.m2 = clock.m2;
+		crtc_state->dpll.p1 = clock.p1;
+		crtc_state->dpll.p2 = clock.p2;
 	}
 
 	/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
-	if (crtc->new_config->has_pch_encoder) {
-		fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll);
+	if (crtc_state->has_pch_encoder) {
+		fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
 		if (has_reduced_clock)
 			fp2 = i9xx_dpll_compute_fp(&reduced_clock);
 
-		dpll = ironlake_compute_dpll(crtc,
+		dpll = ironlake_compute_dpll(crtc, crtc_state,
 					     &fp, &reduced_clock,
 					     has_reduced_clock ? &fp2 : NULL);
 
-		crtc->new_config->dpll_hw_state.dpll = dpll;
-		crtc->new_config->dpll_hw_state.fp0 = fp;
+		crtc_state->dpll_hw_state.dpll = dpll;
+		crtc_state->dpll_hw_state.fp0 = fp;
 		if (has_reduced_clock)
-			crtc->new_config->dpll_hw_state.fp1 = fp2;
+			crtc_state->dpll_hw_state.fp1 = fp2;
 		else
-			crtc->new_config->dpll_hw_state.fp1 = fp;
+			crtc_state->dpll_hw_state.fp1 = fp;
 
-		pll = intel_get_shared_dpll(crtc);
+		pll = intel_get_shared_dpll(crtc, crtc_state);
 		if (pll == NULL) {
 			DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
 					 pipe_name(crtc->pipe));
@@ -7584,7 +7552,7 @@
 		 * registers are not unnecessarily read).
 		 */
 		if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
-			crtc->config.has_drrs) {
+			crtc->config->has_drrs) {
 			m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
 			m2_n2->link_n =	I915_READ(PIPE_LINK_N2(transcoder));
 			m2_n2->gmch_m =	I915_READ(PIPE_DATA_M2(transcoder))
@@ -7605,9 +7573,9 @@
 }
 
 void intel_dp_get_m_n(struct intel_crtc *crtc,
-		      struct intel_crtc_config *pipe_config)
+		      struct intel_crtc_state *pipe_config)
 {
-	if (crtc->config.has_pch_encoder)
+	if (pipe_config->has_pch_encoder)
 		intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n);
 	else
 		intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
@@ -7616,14 +7584,14 @@
 }
 
 static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
-					struct intel_crtc_config *pipe_config)
+					struct intel_crtc_state *pipe_config)
 {
 	intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
 				     &pipe_config->fdi_m_n, NULL);
 }
 
 static void skylake_get_pfit_config(struct intel_crtc *crtc,
-				    struct intel_crtc_config *pipe_config)
+				    struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7638,8 +7606,80 @@
 	}
 }
 
+static void
+skylake_get_initial_plane_config(struct intel_crtc *crtc,
+				 struct intel_initial_plane_config *plane_config)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val, base, offset, stride_mult;
+	int pipe = crtc->pipe;
+	int fourcc, pixel_format;
+	int aligned_height;
+	struct drm_framebuffer *fb;
+	struct intel_framebuffer *intel_fb;
+
+	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+	if (!intel_fb) {
+		DRM_DEBUG_KMS("failed to alloc fb\n");
+		return;
+	}
+
+	fb = &intel_fb->base;
+
+	val = I915_READ(PLANE_CTL(pipe, 0));
+	if (val & PLANE_CTL_TILED_MASK)
+		plane_config->tiling = I915_TILING_X;
+
+	pixel_format = val & PLANE_CTL_FORMAT_MASK;
+	fourcc = skl_format_to_fourcc(pixel_format,
+				      val & PLANE_CTL_ORDER_RGBX,
+				      val & PLANE_CTL_ALPHA_MASK);
+	fb->pixel_format = fourcc;
+	fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
+
+	base = I915_READ(PLANE_SURF(pipe, 0)) & 0xfffff000;
+	plane_config->base = base;
+
+	offset = I915_READ(PLANE_OFFSET(pipe, 0));
+
+	val = I915_READ(PLANE_SIZE(pipe, 0));
+	fb->height = ((val >> 16) & 0xfff) + 1;
+	fb->width = ((val >> 0) & 0x1fff) + 1;
+
+	val = I915_READ(PLANE_STRIDE(pipe, 0));
+	switch (plane_config->tiling) {
+	case I915_TILING_NONE:
+		stride_mult = 64;
+		break;
+	case I915_TILING_X:
+		stride_mult = 512;
+		break;
+	default:
+		MISSING_CASE(plane_config->tiling);
+		goto error;
+	}
+	fb->pitches[0] = (val & 0x3ff) * stride_mult;
+
+	aligned_height = intel_fb_align_height(dev, fb->height,
+					       plane_config->tiling);
+
+	plane_config->size = ALIGN(fb->pitches[0] * aligned_height, PAGE_SIZE);
+
+	DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+		      pipe_name(pipe), fb->width, fb->height,
+		      fb->bits_per_pixel, base, fb->pitches[0],
+		      plane_config->size);
+
+	crtc->base.primary->fb = fb;
+	return;
+
+error:
+	kfree(fb);
+}
+
 static void ironlake_get_pfit_config(struct intel_crtc *crtc,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7662,68 +7702,71 @@
 	}
 }
 
-static void ironlake_get_plane_config(struct intel_crtc *crtc,
-				      struct intel_plane_config *plane_config)
+static void
+ironlake_get_initial_plane_config(struct intel_crtc *crtc,
+				  struct intel_initial_plane_config *plane_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 val, base, offset;
-	int pipe = crtc->pipe, plane = crtc->plane;
+	int pipe = crtc->pipe;
 	int fourcc, pixel_format;
 	int aligned_height;
+	struct drm_framebuffer *fb;
+	struct intel_framebuffer *intel_fb;
 
-	crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
-	if (!crtc->base.primary->fb) {
+	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+	if (!intel_fb) {
 		DRM_DEBUG_KMS("failed to alloc fb\n");
 		return;
 	}
 
-	val = I915_READ(DSPCNTR(plane));
+	fb = &intel_fb->base;
+
+	val = I915_READ(DSPCNTR(pipe));
 
 	if (INTEL_INFO(dev)->gen >= 4)
 		if (val & DISPPLANE_TILED)
-			plane_config->tiled = true;
+			plane_config->tiling = I915_TILING_X;
 
 	pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
-	fourcc = intel_format_to_fourcc(pixel_format);
-	crtc->base.primary->fb->pixel_format = fourcc;
-	crtc->base.primary->fb->bits_per_pixel =
-		drm_format_plane_cpp(fourcc, 0) * 8;
+	fourcc = i9xx_format_to_fourcc(pixel_format);
+	fb->pixel_format = fourcc;
+	fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
 
-	base = I915_READ(DSPSURF(plane)) & 0xfffff000;
+	base = I915_READ(DSPSURF(pipe)) & 0xfffff000;
 	if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-		offset = I915_READ(DSPOFFSET(plane));
+		offset = I915_READ(DSPOFFSET(pipe));
 	} else {
-		if (plane_config->tiled)
-			offset = I915_READ(DSPTILEOFF(plane));
+		if (plane_config->tiling)
+			offset = I915_READ(DSPTILEOFF(pipe));
 		else
-			offset = I915_READ(DSPLINOFF(plane));
+			offset = I915_READ(DSPLINOFF(pipe));
 	}
 	plane_config->base = base;
 
 	val = I915_READ(PIPESRC(pipe));
-	crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
-	crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+	fb->width = ((val >> 16) & 0xfff) + 1;
+	fb->height = ((val >> 0) & 0xfff) + 1;
 
 	val = I915_READ(DSPSTRIDE(pipe));
-	crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
+	fb->pitches[0] = val & 0xffffffc0;
 
-	aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
-					    plane_config->tiled);
+	aligned_height = intel_fb_align_height(dev, fb->height,
+					       plane_config->tiling);
 
-	plane_config->size = PAGE_ALIGN(crtc->base.primary->fb->pitches[0] *
-					aligned_height);
+	plane_config->size = PAGE_ALIGN(fb->pitches[0] * aligned_height);
 
-	DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
-		      pipe, plane, crtc->base.primary->fb->width,
-		      crtc->base.primary->fb->height,
-		      crtc->base.primary->fb->bits_per_pixel, base,
-		      crtc->base.primary->fb->pitches[0],
+	DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+		      pipe_name(pipe), fb->width, fb->height,
+		      fb->bits_per_pixel, base, fb->pitches[0],
 		      plane_config->size);
+
+	crtc->base.primary->fb = fb;
 }
 
 static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7810,24 +7853,24 @@
 	struct intel_crtc *crtc;
 
 	for_each_intel_crtc(dev, crtc)
-		WARN(crtc->active, "CRTC for pipe %c enabled\n",
+		I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
 		     pipe_name(crtc->pipe));
 
-	WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
-	WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
-	WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
-	WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
-	WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
-	WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+	I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
+	I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
+	I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
+	I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
+	I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
+	I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
 	     "CPU PWM1 enabled\n");
 	if (IS_HASWELL(dev))
-		WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+		I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
 		     "CPU PWM2 enabled\n");
-	WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+	I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
 	     "PCH PWM1 enabled\n");
-	WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+	I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
 	     "Utility pin enabled\n");
-	WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
+	I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
 
 	/*
 	 * In theory we can still leave IRQs enabled, as long as only the HPD
@@ -7835,7 +7878,7 @@
 	 * gen-specific and since we only disable LCPLL after we fully disable
 	 * the interrupts, the check below should be enough.
 	 */
-	WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
+	I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
 }
 
 static uint32_t hsw_read_dcomp(struct drm_i915_private *dev_priv)
@@ -7933,19 +7976,8 @@
 	/*
 	 * Make sure we're not on PC8 state before disabling PC8, otherwise
 	 * we'll hang the machine. To prevent PC8 state, just enable force_wake.
-	 *
-	 * The other problem is that hsw_restore_lcpll() is called as part of
-	 * the runtime PM resume sequence, so we can't just call
-	 * gen6_gt_force_wake_get() because that function calls
-	 * intel_runtime_pm_get(), and we can't change the runtime PM refcount
-	 * while we are on the resume sequence. So to solve this problem we have
-	 * to call special forcewake code that doesn't touch runtime PM and
-	 * doesn't enable the forcewake delayed work.
 	 */
-	spin_lock_irq(&dev_priv->uncore.lock);
-	if (dev_priv->uncore.forcewake_count++ == 0)
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
-	spin_unlock_irq(&dev_priv->uncore.lock);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	if (val & LCPLL_POWER_DOWN_ALLOW) {
 		val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -7975,11 +8007,7 @@
 			DRM_ERROR("Switching back to LCPLL failed\n");
 	}
 
-	/* See the big comment above. */
-	spin_lock_irq(&dev_priv->uncore.lock);
-	if (--dev_priv->uncore.forcewake_count == 0)
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
-	spin_unlock_irq(&dev_priv->uncore.lock);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 /*
@@ -8041,9 +8069,10 @@
 	intel_prepare_ddi(dev);
 }
 
-static int haswell_crtc_compute_clock(struct intel_crtc *crtc)
+static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
+				      struct intel_crtc_state *crtc_state)
 {
-	if (!intel_ddi_pll_select(crtc))
+	if (!intel_ddi_pll_select(crtc, crtc_state))
 		return -EINVAL;
 
 	crtc->lowfreq_avail = false;
@@ -8053,14 +8082,23 @@
 
 static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
 				enum port port,
-				struct intel_crtc_config *pipe_config)
+				struct intel_crtc_state *pipe_config)
 {
-	u32 temp;
+	u32 temp, dpll_ctl1;
 
 	temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
 	pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
 
 	switch (pipe_config->ddi_pll_sel) {
+	case SKL_DPLL0:
+		/*
+		 * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
+		 * of the shared DPLL framework and thus needs to be read out
+		 * separately
+		 */
+		dpll_ctl1 = I915_READ(DPLL_CTRL1);
+		pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
+		break;
 	case SKL_DPLL1:
 		pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
 		break;
@@ -8075,7 +8113,7 @@
 
 static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
 				enum port port,
-				struct intel_crtc_config *pipe_config)
+				struct intel_crtc_state *pipe_config)
 {
 	pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
 
@@ -8090,7 +8128,7 @@
 }
 
 static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
-				       struct intel_crtc_config *pipe_config)
+				       struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8132,7 +8170,7 @@
 }
 
 static bool haswell_get_pipe_config(struct intel_crtc *crtc,
-				    struct intel_crtc_config *pipe_config)
+				    struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8286,7 +8324,7 @@
 				cntl |= CURSOR_MODE_256_ARGB_AX;
 				break;
 			default:
-				WARN_ON(1);
+				MISSING_CASE(intel_crtc->cursor_width);
 				return;
 		}
 		cntl |= pipe << 28; /* Connect to correct pipe */
@@ -8295,7 +8333,7 @@
 			cntl |= CURSOR_PIPE_CSC_ENABLE;
 	}
 
-	if (to_intel_plane(crtc->cursor)->rotation == BIT(DRM_ROTATE_180))
+	if (crtc->cursor->state->rotation == BIT(DRM_ROTATE_180))
 		cntl |= CURSOR_ROTATE_180;
 
 	if (intel_crtc->cursor_cntl != cntl) {
@@ -8326,10 +8364,10 @@
 	if (on)
 		base = intel_crtc->cursor_addr;
 
-	if (x >= intel_crtc->config.pipe_src_w)
+	if (x >= intel_crtc->config->pipe_src_w)
 		base = 0;
 
-	if (y >= intel_crtc->config.pipe_src_h)
+	if (y >= intel_crtc->config->pipe_src_h)
 		base = 0;
 
 	if (x < 0) {
@@ -8357,7 +8395,7 @@
 
 	/* ILK+ do this automagically */
 	if (HAS_GMCH_DISPLAY(dev) &&
-		to_intel_plane(crtc->cursor)->rotation == BIT(DRM_ROTATE_180)) {
+	    crtc->cursor->state->rotation == BIT(DRM_ROTATE_180)) {
 		base += (intel_crtc->cursor_height *
 			intel_crtc->cursor_width - 1) * 4;
 	}
@@ -8405,109 +8443,6 @@
 	return true;
 }
 
-static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
-				     struct drm_i915_gem_object *obj,
-				     uint32_t width, uint32_t height)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	unsigned old_width;
-	uint32_t addr;
-	int ret;
-
-	/* if we want to turn off the cursor ignore width and height */
-	if (!obj) {
-		DRM_DEBUG_KMS("cursor off\n");
-		addr = 0;
-		mutex_lock(&dev->struct_mutex);
-		goto finish;
-	}
-
-	/* we only need to pin inside GTT if cursor is non-phy */
-	mutex_lock(&dev->struct_mutex);
-	if (!INTEL_INFO(dev)->cursor_needs_physical) {
-		unsigned alignment;
-
-		/*
-		 * Global gtt pte registers are special registers which actually
-		 * forward writes to a chunk of system memory. Which means that
-		 * there is no risk that the register values disappear as soon
-		 * as we call intel_runtime_pm_put(), so it is correct to wrap
-		 * only the pin/unpin/fence and not more.
-		 */
-		intel_runtime_pm_get(dev_priv);
-
-		/* Note that the w/a also requires 2 PTE of padding following
-		 * the bo. We currently fill all unused PTE with the shadow
-		 * page and so we should always have valid PTE following the
-		 * cursor preventing the VT-d warning.
-		 */
-		alignment = 0;
-		if (need_vtd_wa(dev))
-			alignment = 64*1024;
-
-		ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
-		if (ret) {
-			DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n");
-			intel_runtime_pm_put(dev_priv);
-			goto fail_locked;
-		}
-
-		ret = i915_gem_object_put_fence(obj);
-		if (ret) {
-			DRM_DEBUG_KMS("failed to release fence for cursor");
-			intel_runtime_pm_put(dev_priv);
-			goto fail_unpin;
-		}
-
-		addr = i915_gem_obj_ggtt_offset(obj);
-
-		intel_runtime_pm_put(dev_priv);
-	} else {
-		int align = IS_I830(dev) ? 16 * 1024 : 256;
-		ret = i915_gem_object_attach_phys(obj, align);
-		if (ret) {
-			DRM_DEBUG_KMS("failed to attach phys object\n");
-			goto fail_locked;
-		}
-		addr = obj->phys_handle->busaddr;
-	}
-
- finish:
-	if (intel_crtc->cursor_bo) {
-		if (!INTEL_INFO(dev)->cursor_needs_physical)
-			i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo);
-	}
-
-	i915_gem_track_fb(intel_crtc->cursor_bo, obj,
-			  INTEL_FRONTBUFFER_CURSOR(pipe));
-	mutex_unlock(&dev->struct_mutex);
-
-	old_width = intel_crtc->cursor_width;
-
-	intel_crtc->cursor_addr = addr;
-	intel_crtc->cursor_bo = obj;
-	intel_crtc->cursor_width = width;
-	intel_crtc->cursor_height = height;
-
-	if (intel_crtc->active) {
-		if (old_width != width)
-			intel_update_watermarks(crtc);
-		intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
-
-		intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
-	}
-
-	return 0;
-fail_unpin:
-	i915_gem_object_unpin_from_display_plane(obj);
-fail_locked:
-	mutex_unlock(&dev->struct_mutex);
-	return ret;
-}
-
 static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
 				 u16 *blue, uint32_t start, uint32_t size)
 {
@@ -8730,7 +8665,7 @@
 
 	intel_crtc = to_intel_crtc(crtc);
 	intel_crtc->new_enabled = true;
-	intel_crtc->new_config = &intel_crtc->config;
+	intel_crtc->new_config = intel_crtc->config;
 	old->dpms_mode = connector->dpms;
 	old->load_detect_temp = true;
 	old->release_fb = NULL;
@@ -8771,7 +8706,7 @@
  fail:
 	intel_crtc->new_enabled = crtc->enabled;
 	if (intel_crtc->new_enabled)
-		intel_crtc->new_config = &intel_crtc->config;
+		intel_crtc->new_config = intel_crtc->config;
 	else
 		intel_crtc->new_config = NULL;
 fail_unlock:
@@ -8817,7 +8752,7 @@
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
-			   const struct intel_crtc_config *pipe_config)
+			   const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpll = pipe_config->dpll_hw_state.dpll;
@@ -8834,7 +8769,7 @@
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
-				struct intel_crtc_config *pipe_config)
+				struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8941,7 +8876,7 @@
 }
 
 static void ironlake_pch_clock_get(struct intel_crtc *crtc,
-				   struct intel_crtc_config *pipe_config)
+				   struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 
@@ -8954,7 +8889,7 @@
 	 * agree once we know their relationship in the encoder's
 	 * get_config() function.
 	 */
-	pipe_config->adjusted_mode.crtc_clock =
+	pipe_config->base.adjusted_mode.crtc_clock =
 		intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
 					 &pipe_config->fdi_m_n);
 }
@@ -8965,9 +8900,9 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	struct drm_display_mode *mode;
-	struct intel_crtc_config pipe_config;
+	struct intel_crtc_state pipe_config;
 	int htot = I915_READ(HTOTAL(cpu_transcoder));
 	int hsync = I915_READ(HSYNC(cpu_transcoder));
 	int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -9082,6 +9017,14 @@
 	intel_runtime_pm_put(dev_priv);
 }
 
+static void intel_crtc_set_state(struct intel_crtc *crtc,
+				 struct intel_crtc_state *crtc_state)
+{
+	kfree(crtc->config);
+	crtc->config = crtc_state;
+	crtc->base.state = &crtc_state->base;
+}
+
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -9098,6 +9041,7 @@
 		kfree(work);
 	}
 
+	intel_crtc_set_state(intel_crtc, NULL);
 	drm_crtc_cleanup(crtc);
 
 	kfree(intel_crtc);
@@ -9115,7 +9059,10 @@
 	drm_gem_object_unreference(&work->pending_flip_obj->base);
 	drm_gem_object_unreference(&work->old_fb_obj->base);
 
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
+
+	if (work->flip_queued_req)
+		i915_gem_request_assign(&work->flip_queued_req, NULL);
 	mutex_unlock(&dev->struct_mutex);
 
 	intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
@@ -9511,25 +9458,53 @@
 	else if (i915.enable_execlists)
 		return true;
 	else
-		return ring != obj->ring;
+		return ring != i915_gem_request_get_ring(obj->last_read_req);
 }
 
-static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
+static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
+{
+	struct drm_device *dev = intel_crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
+	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+	struct drm_i915_gem_object *obj = intel_fb->obj;
+	const enum pipe pipe = intel_crtc->pipe;
+	u32 ctl, stride;
+
+	ctl = I915_READ(PLANE_CTL(pipe, 0));
+	ctl &= ~PLANE_CTL_TILED_MASK;
+	if (obj->tiling_mode == I915_TILING_X)
+		ctl |= PLANE_CTL_TILED_X;
+
+	/*
+	 * The stride is either expressed as a multiple of 64 bytes chunks for
+	 * linear buffers or in number of tiles for tiled buffers.
+	 */
+	stride = fb->pitches[0] >> 6;
+	if (obj->tiling_mode == I915_TILING_X)
+		stride = fb->pitches[0] >> 9; /* X tiles are 512 bytes wide */
+
+	/*
+	 * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
+	 * PLANE_SURF updates, the update is then guaranteed to be atomic.
+	 */
+	I915_WRITE(PLANE_CTL(pipe, 0), ctl);
+	I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
+
+	I915_WRITE(PLANE_SURF(pipe, 0), intel_crtc->unpin_work->gtt_offset);
+	POSTING_READ(PLANE_SURF(pipe, 0));
+}
+
+static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_framebuffer *intel_fb =
 		to_intel_framebuffer(intel_crtc->base.primary->fb);
 	struct drm_i915_gem_object *obj = intel_fb->obj;
-	bool atomic_update;
-	u32 start_vbl_count;
 	u32 dspcntr;
 	u32 reg;
 
-	intel_mark_page_flip_active(intel_crtc);
-
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
 	reg = DSPCNTR(intel_crtc->plane);
 	dspcntr = I915_READ(reg);
 
@@ -9544,26 +9519,50 @@
 		   intel_crtc->unpin_work->gtt_offset);
 	POSTING_READ(DSPSURF(intel_crtc->plane));
 
+}
+
+/*
+ * XXX: This is the temporary way to update the plane registers until we get
+ * around to using the usual plane update functions for MMIO flips
+ */
+static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
+{
+	struct drm_device *dev = intel_crtc->base.dev;
+	bool atomic_update;
+	u32 start_vbl_count;
+
+	intel_mark_page_flip_active(intel_crtc);
+
+	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+
+	if (INTEL_INFO(dev)->gen >= 9)
+		skl_do_mmio_flip(intel_crtc);
+	else
+		/* use_mmio_flip() retricts MMIO flips to ilk+ */
+		ilk_do_mmio_flip(intel_crtc);
+
 	if (atomic_update)
 		intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
 static void intel_mmio_flip_work_func(struct work_struct *work)
 {
-	struct intel_crtc *intel_crtc =
+	struct intel_crtc *crtc =
 		container_of(work, struct intel_crtc, mmio_flip.work);
-	struct intel_engine_cs *ring;
-	uint32_t seqno;
+	struct intel_mmio_flip *mmio_flip;
 
-	seqno = intel_crtc->mmio_flip.seqno;
-	ring = intel_crtc->mmio_flip.ring;
+	mmio_flip = &crtc->mmio_flip;
+	if (mmio_flip->req)
+		WARN_ON(__i915_wait_request(mmio_flip->req,
+					    crtc->reset_counter,
+					    false, NULL, NULL) != 0);
 
-	if (seqno)
-		WARN_ON(__i915_wait_seqno(ring, seqno,
-					  intel_crtc->reset_counter,
-					  false, NULL, NULL) != 0);
-
-	intel_do_mmio_flip(intel_crtc);
+	intel_do_mmio_flip(crtc);
+	if (mmio_flip->req) {
+		mutex_lock(&crtc->base.dev->struct_mutex);
+		i915_gem_request_assign(&mmio_flip->req, NULL);
+		mutex_unlock(&crtc->base.dev->struct_mutex);
+	}
 }
 
 static int intel_queue_mmio_flip(struct drm_device *dev,
@@ -9575,8 +9574,8 @@
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-	intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
-	intel_crtc->mmio_flip.ring = obj->ring;
+	i915_gem_request_assign(&intel_crtc->mmio_flip.req,
+				obj->last_write_req);
 
 	schedule_work(&intel_crtc->mmio_flip.work);
 
@@ -9671,9 +9670,8 @@
 		return false;
 
 	if (work->flip_ready_vblank == 0) {
-		if (work->flip_queued_ring &&
-		    !i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
-				       work->flip_queued_seqno))
+		if (work->flip_queued_req &&
+		    !i915_gem_request_completed(work->flip_queued_req, true))
 			return false;
 
 		work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
@@ -9726,6 +9724,7 @@
 	struct drm_framebuffer *old_fb = crtc->primary->fb;
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_plane *primary = crtc->primary;
 	enum pipe pipe = intel_crtc->pipe;
 	struct intel_unpin_work *work;
 	struct intel_engine_cs *ring;
@@ -9818,7 +9817,7 @@
 	} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
 		ring = &dev_priv->ring[BCS];
 	} else if (INTEL_INFO(dev)->gen >= 7) {
-		ring = obj->ring;
+		ring = i915_gem_request_get_ring(obj->last_read_req);
 		if (ring == NULL || ring->id != RCS)
 			ring = &dev_priv->ring[BCS];
 	} else {
@@ -9838,16 +9837,16 @@
 		if (ret)
 			goto cleanup_unpin;
 
-		work->flip_queued_seqno = obj->last_write_seqno;
-		work->flip_queued_ring = obj->ring;
+		i915_gem_request_assign(&work->flip_queued_req,
+					obj->last_write_req);
 	} else {
 		ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
 						   page_flip_flags);
 		if (ret)
 			goto cleanup_unpin;
 
-		work->flip_queued_seqno = intel_ring_get_seqno(ring);
-		work->flip_queued_ring = ring;
+		i915_gem_request_assign(&work->flip_queued_req,
+					intel_ring_get_request(ring));
 	}
 
 	work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
@@ -9856,7 +9855,7 @@
 	i915_gem_track_fb(work->old_fb_obj, obj,
 			  INTEL_FRONTBUFFER_PRIMARY(pipe));
 
-	intel_disable_fbc(dev);
+	intel_fbc_disable(dev);
 	intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
 	mutex_unlock(&dev->struct_mutex);
 
@@ -9884,8 +9883,7 @@
 
 	if (ret == -EIO) {
 out_hang:
-		intel_crtc_wait_for_pending_flips(crtc);
-		ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb);
+		ret = intel_plane_restore(primary);
 		if (ret == 0 && event) {
 			spin_lock_irq(&dev->event_lock);
 			drm_send_vblank_event(dev, pipe, event);
@@ -9898,6 +9896,8 @@
 static struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
 	.load_lut = intel_crtc_load_lut,
+	.atomic_begin = intel_begin_crtc_commit,
+	.atomic_flush = intel_finish_crtc_commit,
 };
 
 /**
@@ -9927,7 +9927,7 @@
 		crtc->new_enabled = crtc->base.enabled;
 
 		if (crtc->new_enabled)
-			crtc->new_config = &crtc->config;
+			crtc->new_config = crtc->config;
 		else
 			crtc->new_config = NULL;
 	}
@@ -9960,7 +9960,7 @@
 
 static void
 connected_sink_compute_bpp(struct intel_connector *connector,
-			   struct intel_crtc_config *pipe_config)
+			   struct intel_crtc_state *pipe_config)
 {
 	int bpp = pipe_config->pipe_bpp;
 
@@ -9987,7 +9987,7 @@
 static int
 compute_baseline_pipe_bpp(struct intel_crtc *crtc,
 			  struct drm_framebuffer *fb,
-			  struct intel_crtc_config *pipe_config)
+			  struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = crtc->base.dev;
 	struct intel_connector *connector;
@@ -10056,7 +10056,7 @@
 }
 
 static void intel_dump_pipe_config(struct intel_crtc *crtc,
-				   struct intel_crtc_config *pipe_config,
+				   struct intel_crtc_state *pipe_config,
 				   const char *context)
 {
 	DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id,
@@ -10090,10 +10090,10 @@
 		      pipe_config->has_infoframe);
 
 	DRM_DEBUG_KMS("requested mode:\n");
-	drm_mode_debug_printmodeline(&pipe_config->requested_mode);
+	drm_mode_debug_printmodeline(&pipe_config->base.mode);
 	DRM_DEBUG_KMS("adjusted mode:\n");
-	drm_mode_debug_printmodeline(&pipe_config->adjusted_mode);
-	intel_dump_crtc_timings(&pipe_config->adjusted_mode);
+	drm_mode_debug_printmodeline(&pipe_config->base.adjusted_mode);
+	intel_dump_crtc_timings(&pipe_config->base.adjusted_mode);
 	DRM_DEBUG_KMS("port clock: %d\n", pipe_config->port_clock);
 	DRM_DEBUG_KMS("pipe src size: %dx%d\n",
 		      pipe_config->pipe_src_w, pipe_config->pipe_src_h);
@@ -10192,14 +10192,14 @@
 	return true;
 }
 
-static struct intel_crtc_config *
+static struct intel_crtc_state *
 intel_modeset_pipe_config(struct drm_crtc *crtc,
 			  struct drm_framebuffer *fb,
 			  struct drm_display_mode *mode)
 {
 	struct drm_device *dev = crtc->dev;
 	struct intel_encoder *encoder;
-	struct intel_crtc_config *pipe_config;
+	struct intel_crtc_state *pipe_config;
 	int plane_bpp, ret = -EINVAL;
 	bool retry = true;
 
@@ -10217,8 +10217,8 @@
 	if (!pipe_config)
 		return ERR_PTR(-ENOMEM);
 
-	drm_mode_copy(&pipe_config->adjusted_mode, mode);
-	drm_mode_copy(&pipe_config->requested_mode, mode);
+	drm_mode_copy(&pipe_config->base.adjusted_mode, mode);
+	drm_mode_copy(&pipe_config->base.mode, mode);
 
 	pipe_config->cpu_transcoder =
 		(enum transcoder) to_intel_crtc(crtc)->pipe;
@@ -10229,13 +10229,13 @@
 	 * positive or negative polarity is requested, treat this as meaning
 	 * negative polarity.
 	 */
-	if (!(pipe_config->adjusted_mode.flags &
+	if (!(pipe_config->base.adjusted_mode.flags &
 	      (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
-		pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
+		pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
 
-	if (!(pipe_config->adjusted_mode.flags &
+	if (!(pipe_config->base.adjusted_mode.flags &
 	      (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
-		pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+		pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
 
 	/* Compute a starting value for pipe_config->pipe_bpp taking the source
 	 * plane pixel format and any sink constraints into account. Returns the
@@ -10254,9 +10254,9 @@
 	 * computation to clearly distinguish it from the adjusted mode, which
 	 * can be changed by the connectors in the below retry loop.
 	 */
-	drm_mode_set_crtcinfo(&pipe_config->requested_mode, CRTC_STEREO_DOUBLE);
-	pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay;
-	pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay;
+	drm_crtc_get_hv_timing(&pipe_config->base.mode,
+			       &pipe_config->pipe_src_w,
+			       &pipe_config->pipe_src_h);
 
 encoder_retry:
 	/* Ensure the port clock defaults are reset when retrying. */
@@ -10264,7 +10264,8 @@
 	pipe_config->pixel_multiplier = 1;
 
 	/* Fill in default crtc timings, allow encoders to overwrite them. */
-	drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, CRTC_STEREO_DOUBLE);
+	drm_mode_set_crtcinfo(&pipe_config->base.adjusted_mode,
+			      CRTC_STEREO_DOUBLE);
 
 	/* Pass our mode to the connectors and the CRTC to give them a chance to
 	 * adjust it according to limitations or connector properties, and also
@@ -10284,7 +10285,7 @@
 	/* Set default port clock if not overwritten by the encoder. Needs to be
 	 * done afterwards in case the encoder adjusts the mode. */
 	if (!pipe_config->port_clock)
-		pipe_config->port_clock = pipe_config->adjusted_mode.crtc_clock
+		pipe_config->port_clock = pipe_config->base.adjusted_mode.crtc_clock
 			* pipe_config->pixel_multiplier;
 
 	ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
@@ -10441,7 +10442,7 @@
 	for_each_intel_crtc(dev, intel_crtc) {
 		WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base));
 		WARN_ON(intel_crtc->new_config &&
-			intel_crtc->new_config != &intel_crtc->config);
+			intel_crtc->new_config != intel_crtc->config);
 		WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config);
 	}
 
@@ -10493,8 +10494,8 @@
 
 static bool
 intel_pipe_config_compare(struct drm_device *dev,
-			  struct intel_crtc_config *current_config,
-			  struct intel_crtc_config *pipe_config)
+			  struct intel_crtc_state *current_config,
+			  struct intel_crtc_state *pipe_config)
 {
 #define PIPE_CONF_CHECK_X(name)	\
 	if (current_config->name != pipe_config->name) { \
@@ -10585,19 +10586,19 @@
 		PIPE_CONF_CHECK_I_ALT(dp_m_n.tu, dp_m2_n2.tu);
 	}
 
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_end);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_start);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_end);
 
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
-	PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vdisplay);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vtotal);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_start);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_end);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_start);
+	PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end);
 
 	PIPE_CONF_CHECK_I(pixel_multiplier);
 	PIPE_CONF_CHECK_I(has_hdmi_sink);
@@ -10608,17 +10609,17 @@
 
 	PIPE_CONF_CHECK_I(has_audio);
 
-	PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+	PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
 			      DRM_MODE_FLAG_INTERLACE);
 
 	if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
-		PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+		PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
 				      DRM_MODE_FLAG_PHSYNC);
-		PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+		PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
 				      DRM_MODE_FLAG_NHSYNC);
-		PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+		PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
 				      DRM_MODE_FLAG_PVSYNC);
-		PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+		PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
 				      DRM_MODE_FLAG_NVSYNC);
 	}
 
@@ -10668,7 +10669,7 @@
 	if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
 		PIPE_CONF_CHECK_I(pipe_bpp);
 
-	PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock);
+	PIPE_CONF_CHECK_CLOCK_FUZZY(base.adjusted_mode.crtc_clock);
 	PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
 
 #undef PIPE_CONF_CHECK_X
@@ -10742,7 +10743,7 @@
 		 * ->get_hw_state callbacks. */
 		intel_connector_check_state(connector);
 
-		WARN(&connector->new_encoder->base != connector->base.encoder,
+		I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder,
 		     "connector's staged encoder doesn't match current encoder\n");
 	}
 }
@@ -10762,9 +10763,9 @@
 			      encoder->base.base.id,
 			      encoder->base.name);
 
-		WARN(&encoder->new_crtc->base != encoder->base.crtc,
+		I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc,
 		     "encoder's stage crtc doesn't match current crtc\n");
-		WARN(encoder->connectors_active && !encoder->base.crtc,
+		I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
 		     "encoder's active_connectors set, but no crtc\n");
 
 		list_for_each_entry(connector, &dev->mode_config.connector_list,
@@ -10783,19 +10784,19 @@
 		if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
 			continue;
 
-		WARN(!!encoder->base.crtc != enabled,
+		I915_STATE_WARN(!!encoder->base.crtc != enabled,
 		     "encoder's enabled state mismatch "
 		     "(expected %i, found %i)\n",
 		     !!encoder->base.crtc, enabled);
-		WARN(active && !encoder->base.crtc,
+		I915_STATE_WARN(active && !encoder->base.crtc,
 		     "active encoder with no crtc\n");
 
-		WARN(encoder->connectors_active != active,
+		I915_STATE_WARN(encoder->connectors_active != active,
 		     "encoder's computed active state doesn't match tracked active state "
 		     "(expected %i, found %i)\n", active, encoder->connectors_active);
 
 		active = encoder->get_hw_state(encoder, &pipe);
-		WARN(active != encoder->connectors_active,
+		I915_STATE_WARN(active != encoder->connectors_active,
 		     "encoder's hw state doesn't match sw tracking "
 		     "(expected %i, found %i)\n",
 		     encoder->connectors_active, active);
@@ -10804,7 +10805,7 @@
 			continue;
 
 		tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
-		WARN(active && pipe != tracked_pipe,
+		I915_STATE_WARN(active && pipe != tracked_pipe,
 		     "active encoder's pipe doesn't match"
 		     "(expected %i, found %i)\n",
 		     tracked_pipe, pipe);
@@ -10818,7 +10819,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc;
 	struct intel_encoder *encoder;
-	struct intel_crtc_config pipe_config;
+	struct intel_crtc_state pipe_config;
 
 	for_each_intel_crtc(dev, crtc) {
 		bool enabled = false;
@@ -10829,7 +10830,7 @@
 		DRM_DEBUG_KMS("[CRTC:%d]\n",
 			      crtc->base.base.id);
 
-		WARN(crtc->active && !crtc->base.enabled,
+		I915_STATE_WARN(crtc->active && !crtc->base.enabled,
 		     "active crtc, but not enabled in sw tracking\n");
 
 		for_each_intel_encoder(dev, encoder) {
@@ -10840,10 +10841,10 @@
 				active = true;
 		}
 
-		WARN(active != crtc->active,
+		I915_STATE_WARN(active != crtc->active,
 		     "crtc's computed active state doesn't match tracked active state "
 		     "(expected %i, found %i)\n", active, crtc->active);
-		WARN(enabled != crtc->base.enabled,
+		I915_STATE_WARN(enabled != crtc->base.enabled,
 		     "crtc's computed enabled state doesn't match tracked enabled state "
 		     "(expected %i, found %i)\n", enabled, crtc->base.enabled);
 
@@ -10863,16 +10864,16 @@
 				encoder->get_config(encoder, &pipe_config);
 		}
 
-		WARN(crtc->active != active,
+		I915_STATE_WARN(crtc->active != active,
 		     "crtc active state doesn't match with hw state "
 		     "(expected %i, found %i)\n", crtc->active, active);
 
 		if (active &&
-		    !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) {
-			WARN(1, "pipe state doesn't match!\n");
+		    !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) {
+			I915_STATE_WARN(1, "pipe state doesn't match!\n");
 			intel_dump_pipe_config(crtc, &pipe_config,
 					       "[hw state]");
-			intel_dump_pipe_config(crtc, &crtc->config,
+			intel_dump_pipe_config(crtc, crtc->config,
 					       "[sw state]");
 		}
 	}
@@ -10897,14 +10898,14 @@
 
 		active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
 
-		WARN(pll->active > hweight32(pll->config.crtc_mask),
+		I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask),
 		     "more active pll users than references: %i vs %i\n",
 		     pll->active, hweight32(pll->config.crtc_mask));
-		WARN(pll->active && !pll->on,
+		I915_STATE_WARN(pll->active && !pll->on,
 		     "pll in active use but not on in sw tracking\n");
-		WARN(pll->on && !pll->active,
+		I915_STATE_WARN(pll->on && !pll->active,
 		     "pll in on but not on in use in sw tracking\n");
-		WARN(pll->on != active,
+		I915_STATE_WARN(pll->on != active,
 		     "pll on state mismatch (expected %i, found %i)\n",
 		     pll->on, active);
 
@@ -10914,14 +10915,14 @@
 			if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
 				active_crtcs++;
 		}
-		WARN(pll->active != active_crtcs,
+		I915_STATE_WARN(pll->active != active_crtcs,
 		     "pll active crtcs mismatch (expected %i, found %i)\n",
 		     pll->active, active_crtcs);
-		WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
+		I915_STATE_WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
 		     "pll enabled crtcs mismatch (expected %i, found %i)\n",
 		     hweight32(pll->config.crtc_mask), enabled_crtcs);
 
-		WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
+		I915_STATE_WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
 				       sizeof(dpll_hw_state)),
 		     "pll hw state mismatch\n");
 	}
@@ -10937,16 +10938,16 @@
 	check_shared_dpll_state(dev);
 }
 
-void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
+void ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
 				     int dotclock)
 {
 	/*
 	 * FDI already provided one idea for the dotclock.
 	 * Yell if the encoder disagrees.
 	 */
-	WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.crtc_clock, dotclock),
+	WARN(!intel_fuzzy_clock_check(pipe_config->base.adjusted_mode.crtc_clock, dotclock),
 	     "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
-	     pipe_config->adjusted_mode.crtc_clock, dotclock);
+	     pipe_config->base.adjusted_mode.crtc_clock, dotclock);
 }
 
 static void update_scanline_offset(struct intel_crtc *crtc)
@@ -10972,7 +10973,7 @@
 	 * one to the value.
 	 */
 	if (IS_GEN2(dev)) {
-		const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+		const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
 		int vtotal;
 
 		vtotal = mode->crtc_vtotal;
@@ -10987,7 +10988,7 @@
 		crtc->scanline_offset = 1;
 }
 
-static struct intel_crtc_config *
+static struct intel_crtc_state *
 intel_modeset_compute_config(struct drm_crtc *crtc,
 			     struct drm_display_mode *mode,
 			     struct drm_framebuffer *fb,
@@ -10995,7 +10996,7 @@
 			     unsigned *prepare_pipes,
 			     unsigned *disable_pipes)
 {
-	struct intel_crtc_config *pipe_config = NULL;
+	struct intel_crtc_state *pipe_config = NULL;
 
 	intel_modeset_affected_pipes(crtc, modeset_pipes,
 				     prepare_pipes, disable_pipes);
@@ -11020,10 +11021,40 @@
 	return pipe_config;
 }
 
+static int __intel_set_mode_setup_plls(struct drm_device *dev,
+				       unsigned modeset_pipes,
+				       unsigned disable_pipes)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	unsigned clear_pipes = modeset_pipes | disable_pipes;
+	struct intel_crtc *intel_crtc;
+	int ret = 0;
+
+	if (!dev_priv->display.crtc_compute_clock)
+		return 0;
+
+	ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
+	if (ret)
+		goto done;
+
+	for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
+		struct intel_crtc_state *state = intel_crtc->new_config;
+		ret = dev_priv->display.crtc_compute_clock(intel_crtc,
+							   state);
+		if (ret) {
+			intel_shared_dpll_abort_config(dev_priv);
+			goto done;
+		}
+	}
+
+done:
+	return ret;
+}
+
 static int __intel_set_mode(struct drm_crtc *crtc,
 			    struct drm_display_mode *mode,
 			    int x, int y, struct drm_framebuffer *fb,
-			    struct intel_crtc_config *pipe_config,
+			    struct intel_crtc_state *pipe_config,
 			    unsigned modeset_pipes,
 			    unsigned prepare_pipes,
 			    unsigned disable_pipes)
@@ -11057,21 +11088,9 @@
 		prepare_pipes &= ~disable_pipes;
 	}
 
-	if (dev_priv->display.crtc_compute_clock) {
-		unsigned clear_pipes = modeset_pipes | disable_pipes;
-
-		ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
-		if (ret)
-			goto done;
-
-		for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
-			ret = dev_priv->display.crtc_compute_clock(intel_crtc);
-			if (ret) {
-				intel_shared_dpll_abort_config(dev_priv);
-				goto done;
-			}
-		}
-	}
+	ret = __intel_set_mode_setup_plls(dev, modeset_pipes, disable_pipes);
+	if (ret)
+		goto done;
 
 	for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
 		intel_crtc_disable(&intel_crtc->base);
@@ -11092,8 +11111,7 @@
 		crtc->mode = *mode;
 		/* mode_set/enable/disable functions rely on a correct pipe
 		 * config. */
-		to_intel_crtc(crtc)->config = *pipe_config;
-		to_intel_crtc(crtc)->new_config = &to_intel_crtc(crtc)->config;
+		intel_crtc_set_state(to_intel_crtc(crtc), pipe_config);
 
 		/*
 		 * Calculate and store various constants which
@@ -11101,7 +11119,7 @@
 		 * timestamping. They are derived from true hwmode.
 		 */
 		drm_calc_timestamping_constants(crtc,
-						&pipe_config->adjusted_mode);
+						&pipe_config->base.adjusted_mode);
 	}
 
 	/* Only after disabling all output pipelines that will be changed can we
@@ -11114,26 +11132,15 @@
 	 * on the DPLL.
 	 */
 	for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
-		struct drm_framebuffer *old_fb = crtc->primary->fb;
-		struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
-		struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+		struct drm_plane *primary = intel_crtc->base.primary;
+		int vdisplay, hdisplay;
 
-		mutex_lock(&dev->struct_mutex);
-		ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
-		if (ret != 0) {
-			DRM_ERROR("pin & fence failed\n");
-			mutex_unlock(&dev->struct_mutex);
-			goto done;
-		}
-		if (old_fb)
-			intel_unpin_fb_obj(old_obj);
-		i915_gem_track_fb(old_obj, obj,
-				  INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
-		mutex_unlock(&dev->struct_mutex);
-
-		crtc->primary->fb = fb;
-		crtc->x = x;
-		crtc->y = y;
+		drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
+		ret = primary->funcs->update_plane(primary, &intel_crtc->base,
+						   fb, 0, 0,
+						   hdisplay, vdisplay,
+						   x << 16, y << 16,
+						   hdisplay << 16, vdisplay << 16);
 	}
 
 	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@ -11148,7 +11155,6 @@
 	if (ret && crtc->enabled)
 		crtc->mode = *saved_mode;
 
-	kfree(pipe_config);
 	kfree(saved_mode);
 	return ret;
 }
@@ -11156,7 +11162,7 @@
 static int intel_set_mode_pipes(struct drm_crtc *crtc,
 				struct drm_display_mode *mode,
 				int x, int y, struct drm_framebuffer *fb,
-				struct intel_crtc_config *pipe_config,
+				struct intel_crtc_state *pipe_config,
 				unsigned modeset_pipes,
 				unsigned prepare_pipes,
 				unsigned disable_pipes)
@@ -11176,7 +11182,7 @@
 			  struct drm_display_mode *mode,
 			  int x, int y, struct drm_framebuffer *fb)
 {
-	struct intel_crtc_config *pipe_config;
+	struct intel_crtc_state *pipe_config;
 	unsigned modeset_pipes, prepare_pipes, disable_pipes;
 
 	pipe_config = intel_modeset_compute_config(crtc, mode, fb,
@@ -11271,7 +11277,7 @@
 		crtc->new_enabled = config->save_crtc_enabled[count++];
 
 		if (crtc->new_enabled)
-			crtc->new_config = &crtc->config;
+			crtc->new_config = crtc->config;
 		else
 			crtc->new_config = NULL;
 	}
@@ -11483,7 +11489,7 @@
 		}
 
 		if (crtc->new_enabled)
-			crtc->new_config = &crtc->config;
+			crtc->new_config = crtc->config;
 		else
 			crtc->new_config = NULL;
 	}
@@ -11520,7 +11526,7 @@
 	struct drm_device *dev;
 	struct drm_mode_set save_set;
 	struct intel_set_config *config;
-	struct intel_crtc_config *pipe_config;
+	struct intel_crtc_state *pipe_config;
 	unsigned modeset_pipes, prepare_pipes, disable_pipes;
 	int ret;
 
@@ -11577,7 +11583,7 @@
 		goto fail;
 	} else if (pipe_config) {
 		if (pipe_config->has_audio !=
-		    to_intel_crtc(set->crtc)->config.has_audio)
+		    to_intel_crtc(set->crtc)->config->has_audio)
 			config->mode_changed = true;
 
 		/*
@@ -11601,11 +11607,14 @@
 					   disable_pipes);
 	} else if (config->fb_changed) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
+		struct drm_plane *primary = set->crtc->primary;
+		int vdisplay, hdisplay;
 
-		intel_crtc_wait_for_pending_flips(set->crtc);
-
-		ret = intel_pipe_set_base(set->crtc,
-					  set->x, set->y, set->fb);
+		drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+		ret = primary->funcs->update_plane(primary, set->crtc, set->fb,
+						   0, 0, hdisplay, vdisplay,
+						   set->x << 16, set->y << 16,
+						   hdisplay << 16, vdisplay << 16);
 
 		/*
 		 * We need to make sure the primary plane is re-enabled if it
@@ -11660,6 +11669,8 @@
 	.set_config = intel_crtc_set_config,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
+	.atomic_duplicate_state = intel_crtc_duplicate_state,
+	.atomic_destroy_state = intel_crtc_destroy_state,
 };
 
 static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -11762,129 +11773,118 @@
 	BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
 }
 
-static int
-intel_primary_plane_disable(struct drm_plane *plane)
+/**
+ * intel_prepare_plane_fb - Prepare fb for usage on plane
+ * @plane: drm plane to prepare for
+ * @fb: framebuffer to prepare for presentation
+ *
+ * Prepares a framebuffer for usage on a display plane.  Generally this
+ * involves pinning the underlying object and updating the frontbuffer tracking
+ * bits.  Some older platforms need special physical address handling for
+ * cursor planes.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int
+intel_prepare_plane_fb(struct drm_plane *plane,
+		       struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = plane->dev;
-	struct intel_crtc *intel_crtc;
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	enum pipe pipe = intel_plane->pipe;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
+	unsigned frontbuffer_bits = 0;
+	int ret = 0;
 
-	if (!plane->fb)
+	if (!obj)
 		return 0;
 
-	BUG_ON(!plane->crtc);
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe);
+		break;
+	case DRM_PLANE_TYPE_CURSOR:
+		frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe);
+		break;
+	case DRM_PLANE_TYPE_OVERLAY:
+		frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe);
+		break;
+	}
 
-	intel_crtc = to_intel_crtc(plane->crtc);
-
-	/*
-	 * Even though we checked plane->fb above, it's still possible that
-	 * the primary plane has been implicitly disabled because the crtc
-	 * coordinates given weren't visible, or because we detected
-	 * that it was 100% covered by a sprite plane.  Or, the CRTC may be
-	 * off and we've set a fb, but haven't actually turned on the CRTC yet.
-	 * In either case, we need to unpin the FB and let the fb pointer get
-	 * updated, but otherwise we don't need to touch the hardware.
-	 */
-	if (!intel_crtc->primary_enabled)
-		goto disable_unpin;
-
-	intel_crtc_wait_for_pending_flips(plane->crtc);
-	intel_disable_primary_hw_plane(plane, plane->crtc);
-
-disable_unpin:
 	mutex_lock(&dev->struct_mutex);
-	i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
-			  INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
-	intel_unpin_fb_obj(intel_fb_obj(plane->fb));
-	mutex_unlock(&dev->struct_mutex);
-	plane->fb = NULL;
 
-	return 0;
+	if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+	    INTEL_INFO(dev)->cursor_needs_physical) {
+		int align = IS_I830(dev) ? 16 * 1024 : 256;
+		ret = i915_gem_object_attach_phys(obj, align);
+		if (ret)
+			DRM_DEBUG_KMS("failed to attach phys object\n");
+	} else {
+		ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
+	}
+
+	if (ret == 0)
+		i915_gem_track_fb(old_obj, obj, frontbuffer_bits);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
+
+/**
+ * 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
+ *
+ * Cleans up a framebuffer that has just been removed from a plane.
+ */
+void
+intel_cleanup_plane_fb(struct drm_plane *plane,
+		       struct drm_framebuffer *fb)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+
+	if (WARN_ON(!obj))
+		return;
+
+	if (plane->type != DRM_PLANE_TYPE_CURSOR ||
+	    !INTEL_INFO(dev)->cursor_needs_physical) {
+		mutex_lock(&dev->struct_mutex);
+		intel_unpin_fb_obj(obj);
+		mutex_unlock(&dev->struct_mutex);
+	}
 }
 
 static int
 intel_check_primary_plane(struct drm_plane *plane,
 			  struct intel_plane_state *state)
 {
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_framebuffer *fb = state->fb;
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = state->base.crtc;
+	struct intel_crtc *intel_crtc;
+	struct drm_framebuffer *fb = state->base.fb;
 	struct drm_rect *dest = &state->dst;
 	struct drm_rect *src = &state->src;
 	const struct drm_rect *clip = &state->clip;
-
-	return drm_plane_helper_check_update(plane, crtc, fb,
-					     src, dest, clip,
-					     DRM_PLANE_HELPER_NO_SCALING,
-					     DRM_PLANE_HELPER_NO_SCALING,
-					     false, true, &state->visible);
-}
-
-static int
-intel_prepare_primary_plane(struct drm_plane *plane,
-			    struct intel_plane_state *state)
-{
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_framebuffer *fb = state->fb;
-	struct drm_device *dev = crtc->dev;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
 	int ret;
 
-	intel_crtc_wait_for_pending_flips(crtc);
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
 
-	if (intel_crtc_has_pending_flip(crtc)) {
-		DRM_ERROR("pipe is still busy with an old pageflip\n");
-		return -EBUSY;
-	}
-
-	if (old_obj != obj) {
-		mutex_lock(&dev->struct_mutex);
-		ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
-		if (ret == 0)
-			i915_gem_track_fb(old_obj, obj,
-					  INTEL_FRONTBUFFER_PRIMARY(pipe));
-		mutex_unlock(&dev->struct_mutex);
-		if (ret != 0) {
-			DRM_DEBUG_KMS("pin & fence failed\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static void
-intel_commit_primary_plane(struct drm_plane *plane,
-			   struct intel_plane_state *state)
-{
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_framebuffer *fb = state->fb;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_framebuffer *old_fb = plane->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct drm_rect *src = &state->src;
-
-	crtc->primary->fb = fb;
-	crtc->x = src->x1 >> 16;
-	crtc->y = src->y1 >> 16;
-
-	intel_plane->crtc_x = state->orig_dst.x1;
-	intel_plane->crtc_y = state->orig_dst.y1;
-	intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
-	intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
-	intel_plane->src_x = state->orig_src.x1;
-	intel_plane->src_y = state->orig_src.y1;
-	intel_plane->src_w = drm_rect_width(&state->orig_src);
-	intel_plane->src_h = drm_rect_height(&state->orig_src);
-	intel_plane->obj = obj;
+	ret = drm_plane_helper_check_update(plane, crtc, fb,
+					    src, dest, clip,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    DRM_PLANE_HELPER_NO_SCALING,
+					    false, true, &state->visible);
+	if (ret)
+		return ret;
 
 	if (intel_crtc->active) {
+		intel_crtc->atomic.wait_for_flips = true;
+
 		/*
 		 * FBC does not work on some platforms for rotated
 		 * planes, so disable it when rotation is not 0 and
@@ -11898,13 +11898,53 @@
 		if (intel_crtc->primary_enabled &&
 		    INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
 		    dev_priv->fbc.plane == intel_crtc->plane &&
-		    intel_plane->rotation != BIT(DRM_ROTATE_0)) {
-			intel_disable_fbc(dev);
+		    state->base.rotation != BIT(DRM_ROTATE_0)) {
+			intel_crtc->atomic.disable_fbc = true;
 		}
 
 		if (state->visible) {
-			bool was_enabled = intel_crtc->primary_enabled;
+			/*
+			 * BDW signals flip done immediately if the plane
+			 * is disabled, even if the plane enable is already
+			 * armed to occur at the next vblank :(
+			 */
+			if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled)
+				intel_crtc->atomic.wait_vblank = true;
+		}
 
+		intel_crtc->atomic.fb_bits |=
+			INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
+
+		intel_crtc->atomic.update_fbc = true;
+	}
+
+	return 0;
+}
+
+static void
+intel_commit_primary_plane(struct drm_plane *plane,
+			   struct intel_plane_state *state)
+{
+	struct drm_crtc *crtc = state->base.crtc;
+	struct drm_framebuffer *fb = state->base.fb;
+	struct drm_device *dev = plane->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct drm_rect *src = &state->src;
+
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
+
+	plane->fb = fb;
+	crtc->x = src->x1 >> 16;
+	crtc->y = src->y1 >> 16;
+
+	intel_plane->obj = obj;
+
+	if (intel_crtc->active) {
+		if (state->visible) {
 			/* FIXME: kill this fastboot hack */
 			intel_update_pipe_size(intel_crtc);
 
@@ -11912,14 +11952,6 @@
 
 			dev_priv->display.update_primary_plane(crtc, plane->fb,
 					crtc->x, crtc->y);
-
-			/*
-			 * BDW signals flip done immediately if the plane
-			 * is disabled, even if the plane enable is already
-			 * armed to occur at the next vblank :(
-			 */
-			if (IS_BROADWELL(dev) && !was_enabled)
-				intel_wait_for_vblank(dev, intel_crtc->pipe);
 		} else {
 			/*
 			 * If clipping results in a non-visible primary plane,
@@ -11930,90 +11962,129 @@
 			 */
 			intel_disable_primary_hw_plane(plane, crtc);
 		}
-
-		intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
-
-		mutex_lock(&dev->struct_mutex);
-		intel_update_fbc(dev);
-		mutex_unlock(&dev->struct_mutex);
-	}
-
-	if (old_fb && old_fb != fb) {
-		if (intel_crtc->active)
-			intel_wait_for_vblank(dev, intel_crtc->pipe);
-
-		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(old_obj);
-		mutex_unlock(&dev->struct_mutex);
 	}
 }
 
-static int
-intel_primary_plane_setplane(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 void intel_begin_crtc_commit(struct drm_crtc *crtc)
 {
-	struct intel_plane_state state;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int ret;
+	struct intel_plane *intel_plane;
+	struct drm_plane *p;
+	unsigned fb_bits = 0;
 
-	state.crtc = crtc;
-	state.fb = fb;
+	/* Track fb's for any planes being disabled */
+	list_for_each_entry(p, &dev->mode_config.plane_list, head) {
+		intel_plane = to_intel_plane(p);
 
-	/* sample coordinates in 16.16 fixed point */
-	state.src.x1 = src_x;
-	state.src.x2 = src_x + src_w;
-	state.src.y1 = src_y;
-	state.src.y2 = src_y + src_h;
+		if (intel_crtc->atomic.disabled_planes &
+		    (1 << drm_plane_index(p))) {
+			switch (p->type) {
+			case DRM_PLANE_TYPE_PRIMARY:
+				fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe);
+				break;
+			case DRM_PLANE_TYPE_CURSOR:
+				fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe);
+				break;
+			case DRM_PLANE_TYPE_OVERLAY:
+				fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe);
+				break;
+			}
 
-	/* integer pixels */
-	state.dst.x1 = crtc_x;
-	state.dst.x2 = crtc_x + crtc_w;
-	state.dst.y1 = crtc_y;
-	state.dst.y2 = crtc_y + crtc_h;
+			mutex_lock(&dev->struct_mutex);
+			i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits);
+			mutex_unlock(&dev->struct_mutex);
+		}
+	}
 
-	state.clip.x1 = 0;
-	state.clip.y1 = 0;
-	state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
-	state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
+	if (intel_crtc->atomic.wait_for_flips)
+		intel_crtc_wait_for_pending_flips(crtc);
 
-	state.orig_src = state.src;
-	state.orig_dst = state.dst;
+	if (intel_crtc->atomic.disable_fbc)
+		intel_fbc_disable(dev);
 
-	ret = intel_check_primary_plane(plane, &state);
-	if (ret)
-		return ret;
+	if (intel_crtc->atomic.pre_disable_primary)
+		intel_pre_disable_primary(crtc);
 
-	ret = intel_prepare_primary_plane(plane, &state);
-	if (ret)
-		return ret;
+	if (intel_crtc->atomic.update_wm)
+		intel_update_watermarks(crtc);
 
-	intel_commit_primary_plane(plane, &state);
+	intel_runtime_pm_get(dev_priv);
 
-	return 0;
+	/* Perform vblank evasion around commit operation */
+	if (intel_crtc->active)
+		intel_crtc->atomic.evade =
+			intel_pipe_update_start(intel_crtc,
+						&intel_crtc->atomic.start_vbl_count);
 }
 
-/* Common destruction function for both primary and cursor planes */
-static void intel_plane_destroy(struct drm_plane *plane)
+static void intel_finish_crtc_commit(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_plane *p;
+
+	if (intel_crtc->atomic.evade)
+		intel_pipe_update_end(intel_crtc,
+				      intel_crtc->atomic.start_vbl_count);
+
+	intel_runtime_pm_put(dev_priv);
+
+	if (intel_crtc->atomic.wait_vblank)
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+	intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits);
+
+	if (intel_crtc->atomic.update_fbc) {
+		mutex_lock(&dev->struct_mutex);
+		intel_fbc_update(dev);
+		mutex_unlock(&dev->struct_mutex);
+	}
+
+	if (intel_crtc->atomic.post_enable_primary)
+		intel_post_enable_primary(crtc);
+
+	drm_for_each_legacy_plane(p, &dev->mode_config.plane_list)
+		if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p))
+			intel_update_sprite_watermarks(p, crtc, 0, 0, 0,
+						       false, false);
+
+	memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic));
+}
+
+/**
+ * intel_plane_destroy - destroy a plane
+ * @plane: plane to destroy
+ *
+ * Common destruction function for all types of planes (primary, cursor,
+ * sprite).
+ */
+void intel_plane_destroy(struct drm_plane *plane)
 {
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	drm_plane_cleanup(plane);
 	kfree(intel_plane);
 }
 
-static const struct drm_plane_funcs intel_primary_plane_funcs = {
-	.update_plane = intel_primary_plane_setplane,
-	.disable_plane = intel_primary_plane_disable,
+const struct drm_plane_funcs intel_plane_funcs = {
+	.update_plane = drm_plane_helper_update,
+	.disable_plane = drm_plane_helper_disable,
 	.destroy = intel_plane_destroy,
-	.set_property = intel_plane_set_property
+	.set_property = drm_atomic_helper_plane_set_property,
+	.atomic_get_property = intel_plane_atomic_get_property,
+	.atomic_set_property = intel_plane_atomic_set_property,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
+
 };
 
 static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 						    int pipe)
 {
 	struct intel_plane *primary;
+	struct intel_plane_state *state;
 	const uint32_t *intel_primary_formats;
 	int num_formats;
 
@@ -12021,11 +12092,19 @@
 	if (primary == NULL)
 		return NULL;
 
+	state = intel_create_plane_state(&primary->base);
+	if (!state) {
+		kfree(primary);
+		return NULL;
+	}
+	primary->base.state = &state->base;
+
 	primary->can_scale = false;
 	primary->max_downscale = 1;
 	primary->pipe = pipe;
 	primary->plane = pipe;
-	primary->rotation = BIT(DRM_ROTATE_0);
+	primary->check_plane = intel_check_primary_plane;
+	primary->commit_plane = intel_commit_primary_plane;
 	if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
 		primary->plane = !pipe;
 
@@ -12038,7 +12117,7 @@
 	}
 
 	drm_universal_plane_init(dev, &primary->base, 0,
-				 &intel_primary_plane_funcs,
+				 &intel_plane_funcs,
 				 intel_primary_formats, num_formats,
 				 DRM_PLANE_TYPE_PRIMARY);
 
@@ -12051,38 +12130,32 @@
 		if (dev->mode_config.rotation_property)
 			drm_object_attach_property(&primary->base.base,
 				dev->mode_config.rotation_property,
-				primary->rotation);
+				state->base.rotation);
 	}
 
+	drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
+
 	return &primary->base;
 }
 
 static int
-intel_cursor_plane_disable(struct drm_plane *plane)
-{
-	if (!plane->fb)
-		return 0;
-
-	BUG_ON(!plane->crtc);
-
-	return intel_crtc_cursor_set_obj(plane->crtc, NULL, 0, 0);
-}
-
-static int
 intel_check_cursor_plane(struct drm_plane *plane,
 			 struct intel_plane_state *state)
 {
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_device *dev = crtc->dev;
-	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->base.crtc;
+	struct drm_device *dev = plane->dev;
+	struct drm_framebuffer *fb = state->base.fb;
 	struct drm_rect *dest = &state->dst;
 	struct drm_rect *src = &state->src;
 	const struct drm_rect *clip = &state->clip;
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	int crtc_w, crtc_h;
+	struct intel_crtc *intel_crtc;
 	unsigned stride;
 	int ret;
 
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
+
 	ret = drm_plane_helper_check_update(plane, crtc, fb,
 					    src, dest, clip,
 					    DRM_PLANE_HELPER_NO_SCALING,
@@ -12094,18 +12167,17 @@
 
 	/* if we want to turn off the cursor ignore width and height */
 	if (!obj)
-		return 0;
+		goto finish;
 
 	/* Check for which cursor types we support */
-	crtc_w = drm_rect_width(&state->orig_dst);
-	crtc_h = drm_rect_height(&state->orig_dst);
-	if (!cursor_size_ok(dev, crtc_w, crtc_h)) {
-		DRM_DEBUG("Cursor dimension not supported\n");
+	if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) {
+		DRM_DEBUG("Cursor dimension %dx%d not supported\n",
+			  state->base.crtc_w, state->base.crtc_h);
 		return -EINVAL;
 	}
 
-	stride = roundup_pow_of_two(crtc_w) * 4;
-	if (obj->base.size < stride * crtc_h) {
+	stride = roundup_pow_of_two(state->base.crtc_w) * 4;
+	if (obj->base.size < stride * state->base.crtc_h) {
 		DRM_DEBUG_KMS("buffer is too small\n");
 		return -ENOMEM;
 	}
@@ -12121,113 +12193,84 @@
 	}
 	mutex_unlock(&dev->struct_mutex);
 
+finish:
+	if (intel_crtc->active) {
+		if (intel_crtc->cursor_width != state->base.crtc_w)
+			intel_crtc->atomic.update_wm = true;
+
+		intel_crtc->atomic.fb_bits |=
+			INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
+	}
+
 	return ret;
 }
 
-static int
+static void
 intel_commit_cursor_plane(struct drm_plane *plane,
 			  struct intel_plane_state *state)
 {
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_framebuffer *fb = state->fb;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_crtc *crtc = state->base.crtc;
+	struct drm_device *dev = plane->dev;
+	struct intel_crtc *intel_crtc;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
-	struct drm_i915_gem_object *obj = intel_fb->obj;
-	int crtc_w, crtc_h;
+	struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
+	uint32_t addr;
 
-	crtc->cursor_x = state->orig_dst.x1;
-	crtc->cursor_y = state->orig_dst.y1;
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
 
-	intel_plane->crtc_x = state->orig_dst.x1;
-	intel_plane->crtc_y = state->orig_dst.y1;
-	intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
-	intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
-	intel_plane->src_x = state->orig_src.x1;
-	intel_plane->src_y = state->orig_src.y1;
-	intel_plane->src_w = drm_rect_width(&state->orig_src);
-	intel_plane->src_h = drm_rect_height(&state->orig_src);
+	plane->fb = state->base.fb;
+	crtc->cursor_x = state->base.crtc_x;
+	crtc->cursor_y = state->base.crtc_y;
+
 	intel_plane->obj = obj;
 
-	if (fb != crtc->cursor->fb) {
-		crtc_w = drm_rect_width(&state->orig_dst);
-		crtc_h = drm_rect_height(&state->orig_dst);
-		return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h);
-	} else {
+	if (intel_crtc->cursor_bo == obj)
+		goto update;
+
+	if (!obj)
+		addr = 0;
+	else if (!INTEL_INFO(dev)->cursor_needs_physical)
+		addr = i915_gem_obj_ggtt_offset(obj);
+	else
+		addr = obj->phys_handle->busaddr;
+
+	intel_crtc->cursor_addr = addr;
+	intel_crtc->cursor_bo = obj;
+update:
+	intel_crtc->cursor_width = state->base.crtc_w;
+	intel_crtc->cursor_height = state->base.crtc_h;
+
+	if (intel_crtc->active)
 		intel_crtc_update_cursor(crtc, state->visible);
-
-		intel_frontbuffer_flip(crtc->dev,
-				       INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe));
-
-		return 0;
-	}
 }
 
-static int
-intel_cursor_plane_update(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 intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_plane_state state;
-	int ret;
-
-	state.crtc = crtc;
-	state.fb = fb;
-
-	/* sample coordinates in 16.16 fixed point */
-	state.src.x1 = src_x;
-	state.src.x2 = src_x + src_w;
-	state.src.y1 = src_y;
-	state.src.y2 = src_y + src_h;
-
-	/* integer pixels */
-	state.dst.x1 = crtc_x;
-	state.dst.x2 = crtc_x + crtc_w;
-	state.dst.y1 = crtc_y;
-	state.dst.y2 = crtc_y + crtc_h;
-
-	state.clip.x1 = 0;
-	state.clip.y1 = 0;
-	state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
-	state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
-
-	state.orig_src = state.src;
-	state.orig_dst = state.dst;
-
-	ret = intel_check_cursor_plane(plane, &state);
-	if (ret)
-		return ret;
-
-	return intel_commit_cursor_plane(plane, &state);
-}
-
-static const struct drm_plane_funcs intel_cursor_plane_funcs = {
-	.update_plane = intel_cursor_plane_update,
-	.disable_plane = intel_cursor_plane_disable,
-	.destroy = intel_plane_destroy,
-	.set_property = intel_plane_set_property,
-};
-
 static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
 						   int pipe)
 {
 	struct intel_plane *cursor;
+	struct intel_plane_state *state;
 
 	cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
 	if (cursor == NULL)
 		return NULL;
 
+	state = intel_create_plane_state(&cursor->base);
+	if (!state) {
+		kfree(cursor);
+		return NULL;
+	}
+	cursor->base.state = &state->base;
+
 	cursor->can_scale = false;
 	cursor->max_downscale = 1;
 	cursor->pipe = pipe;
 	cursor->plane = pipe;
-	cursor->rotation = BIT(DRM_ROTATE_0);
+	cursor->check_plane = intel_check_cursor_plane;
+	cursor->commit_plane = intel_commit_cursor_plane;
 
 	drm_universal_plane_init(dev, &cursor->base, 0,
-				 &intel_cursor_plane_funcs,
+				 &intel_plane_funcs,
 				 intel_cursor_formats,
 				 ARRAY_SIZE(intel_cursor_formats),
 				 DRM_PLANE_TYPE_CURSOR);
@@ -12241,9 +12284,11 @@
 		if (dev->mode_config.rotation_property)
 			drm_object_attach_property(&cursor->base.base,
 				dev->mode_config.rotation_property,
-				cursor->rotation);
+				state->base.rotation);
 	}
 
+	drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+
 	return &cursor->base;
 }
 
@@ -12251,6 +12296,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
+	struct intel_crtc_state *crtc_state = NULL;
 	struct drm_plane *primary = NULL;
 	struct drm_plane *cursor = NULL;
 	int i, ret;
@@ -12259,6 +12305,11 @@
 	if (intel_crtc == NULL)
 		return;
 
+	crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+	if (!crtc_state)
+		goto fail;
+	intel_crtc_set_state(intel_crtc, crtc_state);
+
 	primary = intel_primary_plane_create(dev, pipe);
 	if (!primary)
 		goto fail;
@@ -12311,6 +12362,7 @@
 		drm_plane_cleanup(primary);
 	if (cursor)
 		drm_plane_cleanup(cursor);
+	kfree(crtc_state);
 	kfree(intel_crtc);
 }
 
@@ -12383,28 +12435,6 @@
 	return true;
 }
 
-const char *intel_output_name(int output)
-{
-	static const char *names[] = {
-		[INTEL_OUTPUT_UNUSED] = "Unused",
-		[INTEL_OUTPUT_ANALOG] = "Analog",
-		[INTEL_OUTPUT_DVO] = "DVO",
-		[INTEL_OUTPUT_SDVO] = "SDVO",
-		[INTEL_OUTPUT_LVDS] = "LVDS",
-		[INTEL_OUTPUT_TVOUT] = "TV",
-		[INTEL_OUTPUT_HDMI] = "HDMI",
-		[INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort",
-		[INTEL_OUTPUT_EDP] = "eDP",
-		[INTEL_OUTPUT_DSI] = "DSI",
-		[INTEL_OUTPUT_UNKNOWN] = "Unknown",
-	};
-
-	if (output < 0 || output >= ARRAY_SIZE(names) || !names[output])
-		return "Invalid";
-
-	return names[output];
-}
-
 static bool intel_crt_present(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12428,6 +12458,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
+	struct drm_connector *connector;
 	bool dpd_is_edp = false;
 
 	intel_lvds_init(dev);
@@ -12491,14 +12522,16 @@
 		 * eDP ports. Consult the VBT as well as DP_DETECTED to
 		 * detect eDP ports.
 		 */
-		if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED)
+		if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED &&
+		    !intel_dp_is_edp(dev, PORT_B))
 			intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
 					PORT_B);
 		if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED ||
 		    intel_dp_is_edp(dev, PORT_B))
 			intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
 
-		if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED)
+		if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED &&
+		    !intel_dp_is_edp(dev, PORT_C))
 			intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
 					PORT_C);
 		if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED ||
@@ -12556,6 +12589,37 @@
 	if (SUPPORTS_TV(dev))
 		intel_tv_init(dev);
 
+	/*
+	 * FIXME:  We don't have full atomic support yet, but we want to be
+	 * able to enable/test plane updates via the atomic interface in the
+	 * meantime.  However as soon as we flip DRIVER_ATOMIC on, the DRM core
+	 * will take some atomic codepaths to lookup properties during
+	 * drmModeGetConnector() that unconditionally dereference
+	 * connector->state.
+	 *
+	 * We create a dummy connector state here for each connector to ensure
+	 * the DRM core doesn't try to dereference a NULL connector->state.
+	 * The actual connector properties will never be updated or contain
+	 * useful information, but since we're doing this specifically for
+	 * testing/debug of the plane operations (and only when a specific
+	 * kernel module option is given), that shouldn't really matter.
+	 *
+	 * Once atomic support for crtc's + connectors lands, this loop should
+	 * be removed since we'll be setting up real connector state, which
+	 * will contain Intel-specific properties.
+	 */
+	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+		list_for_each_entry(connector,
+				    &dev->mode_config.connector_list,
+				    head) {
+			if (!WARN_ON(connector->state)) {
+				connector->state =
+					kzalloc(sizeof(*connector->state),
+						GFP_KERNEL);
+			}
+		}
+	}
+
 	intel_psr_init(dev);
 
 	for_each_intel_encoder(dev, encoder) {
@@ -12696,8 +12760,8 @@
 	if (mode_cmd->offsets[0] != 0)
 		return -EINVAL;
 
-	aligned_height = intel_align_height(dev, mode_cmd->height,
-					    obj->tiling_mode);
+	aligned_height = intel_fb_align_height(dev, mode_cmd->height,
+					       obj->tiling_mode);
 	/* FIXME drm helper for size checks (especially planar formats)? */
 	if (obj->base.size < aligned_height * mode_cmd->pitches[0])
 		return -EINVAL;
@@ -12739,6 +12803,8 @@
 static const struct drm_mode_config_funcs intel_mode_funcs = {
 	.fb_create = intel_user_framebuffer_create,
 	.output_poll_changed = intel_fbdev_output_poll_changed,
+	.atomic_check = intel_atomic_check,
+	.atomic_commit = intel_atomic_commit,
 };
 
 /* Set up chip specific display functions */
@@ -12757,23 +12823,32 @@
 	else
 		dev_priv->display.find_dpll = i9xx_find_best_dpll;
 
-	if (HAS_DDI(dev)) {
+	if (INTEL_INFO(dev)->gen >= 9) {
 		dev_priv->display.get_pipe_config = haswell_get_pipe_config;
-		dev_priv->display.get_plane_config = ironlake_get_plane_config;
+		dev_priv->display.get_initial_plane_config =
+			skylake_get_initial_plane_config;
 		dev_priv->display.crtc_compute_clock =
 			haswell_crtc_compute_clock;
 		dev_priv->display.crtc_enable = haswell_crtc_enable;
 		dev_priv->display.crtc_disable = haswell_crtc_disable;
 		dev_priv->display.off = ironlake_crtc_off;
-		if (INTEL_INFO(dev)->gen >= 9)
-			dev_priv->display.update_primary_plane =
-				skylake_update_primary_plane;
-		else
-			dev_priv->display.update_primary_plane =
-				ironlake_update_primary_plane;
+		dev_priv->display.update_primary_plane =
+			skylake_update_primary_plane;
+	} else if (HAS_DDI(dev)) {
+		dev_priv->display.get_pipe_config = haswell_get_pipe_config;
+		dev_priv->display.get_initial_plane_config =
+			ironlake_get_initial_plane_config;
+		dev_priv->display.crtc_compute_clock =
+			haswell_crtc_compute_clock;
+		dev_priv->display.crtc_enable = haswell_crtc_enable;
+		dev_priv->display.crtc_disable = haswell_crtc_disable;
+		dev_priv->display.off = ironlake_crtc_off;
+		dev_priv->display.update_primary_plane =
+			ironlake_update_primary_plane;
 	} else if (HAS_PCH_SPLIT(dev)) {
 		dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
-		dev_priv->display.get_plane_config = ironlake_get_plane_config;
+		dev_priv->display.get_initial_plane_config =
+			ironlake_get_initial_plane_config;
 		dev_priv->display.crtc_compute_clock =
 			ironlake_crtc_compute_clock;
 		dev_priv->display.crtc_enable = ironlake_crtc_enable;
@@ -12783,7 +12858,8 @@
 			ironlake_update_primary_plane;
 	} else if (IS_VALLEYVIEW(dev)) {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_plane_config = i9xx_get_plane_config;
+		dev_priv->display.get_initial_plane_config =
+			i9xx_get_initial_plane_config;
 		dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
 		dev_priv->display.crtc_enable = valleyview_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -12792,7 +12868,8 @@
 			i9xx_update_primary_plane;
 	} else {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_plane_config = i9xx_get_plane_config;
+		dev_priv->display.get_initial_plane_config =
+			i9xx_get_initial_plane_config;
 		dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
 		dev_priv->display.crtc_enable = i9xx_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -13147,7 +13224,7 @@
 	intel_setup_outputs(dev);
 
 	/* Just in case the BIOS is doing something questionable. */
-	intel_disable_fbc(dev);
+	intel_fbc_disable(dev);
 
 	drm_modeset_lock_all(dev);
 	intel_modeset_setup_hw_state(dev, false);
@@ -13164,8 +13241,8 @@
 		 * can even allow for smooth boot transitions if the BIOS
 		 * fb is large enough for the active pipe configuration.
 		 */
-		if (dev_priv->display.get_plane_config) {
-			dev_priv->display.get_plane_config(crtc,
+		if (dev_priv->display.get_initial_plane_config) {
+			dev_priv->display.get_initial_plane_config(crtc,
 							   &crtc->plane_config);
 			/*
 			 * If the fb is shared between multiple heads, we'll
@@ -13229,7 +13306,7 @@
 	u32 reg;
 
 	/* Clear any frame start delays used for debugging left by the BIOS */
-	reg = PIPECONF(crtc->config.cpu_transcoder);
+	reg = PIPECONF(crtc->config->cpu_transcoder);
 	I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
 
 	/* restore vblank interrupts to correct state */
@@ -13433,12 +13510,12 @@
 	int i;
 
 	for_each_intel_crtc(dev, crtc) {
-		memset(&crtc->config, 0, sizeof(crtc->config));
+		memset(crtc->config, 0, sizeof(*crtc->config));
 
-		crtc->config.quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
+		crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
 
 		crtc->active = dev_priv->display.get_pipe_config(crtc,
-								 &crtc->config);
+								 crtc->config);
 
 		crtc->base.enabled = crtc->active;
 		crtc->primary_enabled = primary_get_hw_state(crtc);
@@ -13475,7 +13552,7 @@
 		if (encoder->get_hw_state(encoder, &pipe)) {
 			crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 			encoder->base.crtc = &crtc->base;
-			encoder->get_config(encoder, &crtc->config);
+			encoder->get_config(encoder, crtc->config);
 		} else {
 			encoder->base.crtc = NULL;
 		}
@@ -13525,7 +13602,8 @@
 	 */
 	for_each_intel_crtc(dev, crtc) {
 		if (crtc->active && i915.fastboot) {
-			intel_mode_from_pipe_config(&crtc->base.mode, &crtc->config);
+			intel_mode_from_pipe_config(&crtc->base.mode,
+						    crtc->config);
 			DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
 				      crtc->base.base.id);
 			drm_mode_debug_printmodeline(&crtc->base.mode);
@@ -13540,7 +13618,8 @@
 	for_each_pipe(dev_priv, pipe) {
 		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 		intel_sanitize_crtc(crtc);
-		intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
+		intel_dump_pipe_config(crtc, crtc->config,
+				       "[setup_hw_state]");
 	}
 
 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
@@ -13664,7 +13743,7 @@
 
 	intel_unregister_dsm_handler();
 
-	intel_disable_fbc(dev);
+	intel_fbc_disable(dev);
 
 	ironlake_teardown_rc6(dev);
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5cecc20..a74aaf9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -31,6 +31,7 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
@@ -1074,7 +1075,7 @@
 }
 
 static void
-skl_edp_set_pll_config(struct intel_crtc_config *pipe_config, int link_bw)
+skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw)
 {
 	u32 ctrl1;
 
@@ -1101,7 +1102,7 @@
 }
 
 static void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_config *pipe_config, int link_bw)
+hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw)
 {
 	switch (link_bw) {
 	case DP_LINK_BW_1_62:
@@ -1118,7 +1119,7 @@
 
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
-		   struct intel_crtc_config *pipe_config, int link_bw)
+		   struct intel_crtc_state *pipe_config, int link_bw)
 {
 	struct drm_device *dev = encoder->base.dev;
 	const struct dp_link_dpll *divisor = NULL;
@@ -1151,11 +1152,11 @@
 
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
-			struct intel_crtc_config *pipe_config)
+			struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = encoder->new_crtc;
@@ -1269,7 +1270,7 @@
 			       &pipe_config->dp_m_n);
 
 	if (intel_connector->panel.downclock_mode != NULL &&
-		intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+		dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
 			pipe_config->has_drrs = true;
 			intel_link_compute_m_n(bpp, lane_count,
 				intel_connector->panel.downclock_mode->clock,
@@ -1295,11 +1296,12 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 dpa_ctl;
 
-	DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", crtc->config.port_clock);
+	DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
+		      crtc->config->port_clock);
 	dpa_ctl = I915_READ(DP_A);
 	dpa_ctl &= ~DP_PLL_FREQ_MASK;
 
-	if (crtc->config.port_clock == 162000) {
+	if (crtc->config->port_clock == 162000) {
 		/* For a long time we've carried around a ILK-DevA w/a for the
 		 * 160MHz clock. If we're really unlucky, it's still required.
 		 */
@@ -1324,7 +1326,7 @@
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-	struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
 
 	/*
 	 * There are four kinds of DP registers:
@@ -1352,7 +1354,7 @@
 	intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
 	intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
 
-	if (crtc->config.has_audio)
+	if (crtc->config->has_audio)
 		intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
 
 	/* Split out the IBX/CPU vs CPT settings */
@@ -1558,7 +1560,7 @@
 	vdd = edp_panel_vdd_on(intel_dp);
 	pps_unlock(intel_dp);
 
-	WARN(!vdd, "eDP port %c VDD already requested on\n",
+	I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
 	     port_name(dp_to_dig_port(intel_dp)->port));
 }
 
@@ -1642,7 +1644,7 @@
 	if (!is_edp(intel_dp))
 		return;
 
-	WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
+	I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
 	     port_name(dp_to_dig_port(intel_dp)->port));
 
 	intel_dp->want_panel_vdd = false;
@@ -2013,7 +2015,7 @@
 }
 
 static void intel_dp_get_config(struct intel_encoder *encoder,
-				struct intel_crtc_config *pipe_config)
+				struct intel_crtc_state *pipe_config)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	u32 tmp, flags = 0;
@@ -2050,7 +2052,7 @@
 			flags |= DRM_MODE_FLAG_NVSYNC;
 	}
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
 	if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
 	    tmp & DP_COLOR_RANGE_16_235)
@@ -2073,7 +2075,7 @@
 	if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A)
 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-	pipe_config->adjusted_mode.crtc_clock = dotclock;
+	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 
 	if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
 	    pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
@@ -2102,9 +2104,12 @@
 	struct drm_device *dev = encoder->base.dev;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 
-	if (crtc->config.has_audio)
+	if (crtc->config->has_audio)
 		intel_audio_codec_disable(encoder);
 
+	if (HAS_PSR(dev) && !HAS_DDI(dev))
+		intel_psr_disable(intel_dp);
+
 	/* Make sure the panel is off before trying to change the mode. But also
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_panel_vdd_on(intel_dp);
@@ -2309,7 +2314,7 @@
 	intel_dp_complete_link_train(intel_dp);
 	intel_dp_stop_link_train(intel_dp);
 
-	if (crtc->config.has_audio) {
+	if (crtc->config->has_audio) {
 		DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
 				 pipe_name(crtc->pipe));
 		intel_audio_codec_enable(encoder);
@@ -2329,6 +2334,7 @@
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
 	intel_edp_backlight_on(intel_dp);
+	intel_psr_enable(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -3515,8 +3521,6 @@
 	enum port port = intel_dig_port->port;
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc =
-		to_intel_crtc(intel_dig_port->base.base.crtc);
 	uint32_t DP = intel_dp->DP;
 
 	if (WARN_ON(HAS_DDI(dev)))
@@ -3541,8 +3545,6 @@
 
 	if (HAS_PCH_IBX(dev) &&
 	    I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
-		struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
-
 		/* Hardware workaround: leaving our transcoder select
 		 * set to transcoder B while it's off will prevent the
 		 * corresponding HDMI output on transcoder A.
@@ -3553,18 +3555,7 @@
 		 */
 		DP &= ~DP_PIPEB_SELECT;
 		I915_WRITE(intel_dp->output_reg, DP);
-
-		/* Changes to enable or select take place the vblank
-		 * after being written.
-		 */
-		if (WARN_ON(crtc == NULL)) {
-			/* We should never try to disable a port without a crtc
-			 * attached. For paranoia keep the code around for a
-			 * bit. */
-			POSTING_READ(intel_dp->output_reg);
-			msleep(50);
-		} else
-			intel_wait_for_vblank(dev, intel_crtc->pipe);
+		POSTING_READ(intel_dp->output_reg);
 	}
 
 	DP &= ~DP_AUDIO_OUTPUT_ENABLE;
@@ -3769,7 +3760,7 @@
 				intel_dp_stop_link_train(intel_dp);
 			}
 
-			DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+			DRM_DEBUG_KMS("got esi %3ph\n", esi);
 			ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
 
 			if (handled) {
@@ -3785,7 +3776,7 @@
 
 				bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
 				if (bret == true) {
-					DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+					DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
 					goto go_again;
 				}
 			} else
@@ -4306,7 +4297,6 @@
 
 	drm_dp_aux_unregister(&intel_dp->aux);
 	intel_dp_mst_encoder_cleanup(intel_dig_port);
-	drm_encoder_cleanup(encoder);
 	if (is_edp(intel_dp)) {
 		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
 		/*
@@ -4322,6 +4312,7 @@
 			intel_dp->edp_notifier.notifier_call = NULL;
 		}
 	}
+	drm_encoder_cleanup(encoder);
 	kfree(intel_dig_port);
 }
 
@@ -4396,7 +4387,9 @@
 	.force = intel_dp_force,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.set_property = intel_dp_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.destroy = intel_dp_connector_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4416,7 +4409,7 @@
 	return;
 }
 
-bool
+enum irqreturn
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -4424,7 +4417,7 @@
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum intel_display_power_domain power_domain;
-	bool ret = true;
+	enum irqreturn ret = IRQ_NONE;
 
 	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
 		intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
@@ -4438,7 +4431,7 @@
 		 */
 		DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
 			      port_name(intel_dig_port->port));
-		return false;
+		return IRQ_HANDLED;
 	}
 
 	DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
@@ -4483,7 +4476,9 @@
 			drm_modeset_unlock(&dev->mode_config.connection_mutex);
 		}
 	}
-	ret = false;
+
+	ret = IRQ_HANDLED;
+
 	goto put_power;
 mst_fail:
 	/* if we were in MST mode, and device is not there get out of MST mode */
@@ -4741,39 +4736,34 @@
 		      I915_READ(pp_div_reg));
 }
 
-void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
-	struct intel_dp *intel_dp = NULL;
-	struct intel_crtc_config *config = NULL;
+	struct intel_digital_port *dig_port = NULL;
+	struct intel_dp *intel_dp = dev_priv->drrs.dp;
+	struct intel_crtc_state *config = NULL;
 	struct intel_crtc *intel_crtc = NULL;
-	struct intel_connector *intel_connector = dev_priv->drrs.connector;
 	u32 reg, val;
-	enum edp_drrs_refresh_rate_type index = DRRS_HIGH_RR;
+	enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
 
 	if (refresh_rate <= 0) {
 		DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
 		return;
 	}
 
-	if (intel_connector == NULL) {
-		DRM_DEBUG_KMS("DRRS supported for eDP only.\n");
+	if (intel_dp == NULL) {
+		DRM_DEBUG_KMS("DRRS not supported.\n");
 		return;
 	}
 
 	/*
-	 * FIXME: This needs proper synchronization with psr state. But really
-	 * hard to tell without seeing the user of this function of this code.
-	 * Check locking and ordering once that lands.
+	 * FIXME: This needs proper synchronization with psr state for some
+	 * platforms that cannot have PSR and DRRS enabled at the same time.
 	 */
-	if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {
-		DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
-		return;
-	}
 
-	encoder = intel_attached_encoder(&intel_connector->base);
-	intel_dp = enc_to_intel_dp(&encoder->base);
+	dig_port = dp_to_dig_port(intel_dp);
+	encoder = &dig_port->base;
 	intel_crtc = encoder->new_crtc;
 
 	if (!intel_crtc) {
@@ -4781,17 +4771,18 @@
 		return;
 	}
 
-	config = &intel_crtc->config;
+	config = intel_crtc->config;
 
-	if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) {
+	if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
 		DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
 		return;
 	}
 
-	if (intel_connector->panel.downclock_mode->vrefresh == refresh_rate)
+	if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
+			refresh_rate)
 		index = DRRS_LOW_RR;
 
-	if (index == intel_dp->drrs_state.refresh_rate_type) {
+	if (index == dev_priv->drrs.refresh_rate_type) {
 		DRM_DEBUG_KMS(
 			"DRRS requested for previously set RR...ignoring\n");
 		return;
@@ -4803,7 +4794,7 @@
 	}
 
 	if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) {
-		reg = PIPECONF(intel_crtc->config.cpu_transcoder);
+		reg = PIPECONF(intel_crtc->config->cpu_transcoder);
 		val = I915_READ(reg);
 		if (index > DRRS_HIGH_RR) {
 			val |= PIPECONF_EDP_RR_MODE_SWITCH;
@@ -4814,30 +4805,154 @@
 		I915_WRITE(reg, val);
 	}
 
-	/*
-	 * mutex taken to ensure that there is no race between differnt
-	 * drrs calls trying to update refresh rate. This scenario may occur
-	 * in future when idleness detection based DRRS in kernel and
-	 * possible calls from user space to set differnt RR are made.
-	 */
-
-	mutex_lock(&intel_dp->drrs_state.mutex);
-
-	intel_dp->drrs_state.refresh_rate_type = index;
-
-	mutex_unlock(&intel_dp->drrs_state.mutex);
+	dev_priv->drrs.refresh_rate_type = index;
 
 	DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
 }
 
+void intel_edp_drrs_enable(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_crtc *crtc = dig_port->base.base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (!intel_crtc->config->has_drrs) {
+		DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
+		return;
+	}
+
+	mutex_lock(&dev_priv->drrs.mutex);
+	if (WARN_ON(dev_priv->drrs.dp)) {
+		DRM_ERROR("DRRS already enabled\n");
+		goto unlock;
+	}
+
+	dev_priv->drrs.busy_frontbuffer_bits = 0;
+
+	dev_priv->drrs.dp = intel_dp;
+
+unlock:
+	mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_disable(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp_to_dev(intel_dp);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_crtc *crtc = dig_port->base.base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	if (!intel_crtc->config->has_drrs)
+		return;
+
+	mutex_lock(&dev_priv->drrs.mutex);
+	if (!dev_priv->drrs.dp) {
+		mutex_unlock(&dev_priv->drrs.mutex);
+		return;
+	}
+
+	if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+		intel_dp_set_drrs_state(dev_priv->dev,
+			intel_dp->attached_connector->panel.
+			fixed_mode->vrefresh);
+
+	dev_priv->drrs.dp = NULL;
+	mutex_unlock(&dev_priv->drrs.mutex);
+
+	cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+static void intel_edp_drrs_downclock_work(struct work_struct *work)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(work, typeof(*dev_priv), drrs.work.work);
+	struct intel_dp *intel_dp;
+
+	mutex_lock(&dev_priv->drrs.mutex);
+
+	intel_dp = dev_priv->drrs.dp;
+
+	if (!intel_dp)
+		goto unlock;
+
+	/*
+	 * The delayed work can race with an invalidate hence we need to
+	 * recheck.
+	 */
+
+	if (dev_priv->drrs.busy_frontbuffer_bits)
+		goto unlock;
+
+	if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
+		intel_dp_set_drrs_state(dev_priv->dev,
+			intel_dp->attached_connector->panel.
+			downclock_mode->vrefresh);
+
+unlock:
+
+	mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_invalidate(struct drm_device *dev,
+		unsigned frontbuffer_bits)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	enum pipe pipe;
+
+	if (!dev_priv->drrs.dp)
+		return;
+
+	mutex_lock(&dev_priv->drrs.mutex);
+	crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+	pipe = to_intel_crtc(crtc)->pipe;
+
+	if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) {
+		cancel_delayed_work_sync(&dev_priv->drrs.work);
+		intel_dp_set_drrs_state(dev_priv->dev,
+				dev_priv->drrs.dp->attached_connector->panel.
+				fixed_mode->vrefresh);
+	}
+
+	frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+
+	dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+	mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_flush(struct drm_device *dev,
+		unsigned frontbuffer_bits)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc;
+	enum pipe pipe;
+
+	if (!dev_priv->drrs.dp)
+		return;
+
+	mutex_lock(&dev_priv->drrs.mutex);
+	crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+	pipe = to_intel_crtc(crtc)->pipe;
+	dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+	cancel_delayed_work_sync(&dev_priv->drrs.work);
+
+	if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR &&
+			!dev_priv->drrs.busy_frontbuffer_bits)
+		schedule_delayed_work(&dev_priv->drrs.work,
+				msecs_to_jiffies(1000));
+	mutex_unlock(&dev_priv->drrs.mutex);
+}
+
 static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
-			struct intel_connector *intel_connector,
-			struct drm_display_mode *fixed_mode)
+intel_dp_drrs_init(struct intel_connector *intel_connector,
+		struct drm_display_mode *fixed_mode)
 {
 	struct drm_connector *connector = &intel_connector->base;
-	struct intel_dp *intel_dp = &intel_dig_port->dp;
-	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_display_mode *downclock_mode = NULL;
 
@@ -4859,13 +4974,13 @@
 		return NULL;
 	}
 
-	dev_priv->drrs.connector = intel_connector;
+	INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
 
-	mutex_init(&intel_dp->drrs_state.mutex);
+	mutex_init(&dev_priv->drrs.mutex);
 
-	intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
+	dev_priv->drrs.type = dev_priv->vbt.drrs_type;
 
-	intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
+	dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
 	DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
 	return downclock_mode;
 }
@@ -4885,7 +5000,7 @@
 	struct edid *edid;
 	enum pipe pipe = INVALID_PIPE;
 
-	intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED;
+	dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
 
 	if (!is_edp(intel_dp))
 		return true;
@@ -4934,7 +5049,6 @@
 		if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
 			fixed_mode = drm_mode_duplicate(dev, scan);
 			downclock_mode = intel_dp_drrs_init(
-						intel_dig_port,
 						intel_connector, fixed_mode);
 			break;
 		}
@@ -5086,7 +5200,7 @@
 	intel_dp_aux_init(intel_dp, intel_connector);
 
 	/* init MST on ports that can support it */
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+	if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
 		if (port == PORT_B || port == PORT_C || port == PORT_D) {
 			intel_dp_mst_encoder_init(intel_dig_port,
 						  intel_connector->base.base.id);
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 7f8c6a6..9f67a37 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -26,11 +26,12 @@
 #include <drm/drmP.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
 static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
-					struct intel_crtc_config *pipe_config)
+					struct intel_crtc_state *pipe_config)
 {
 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
@@ -38,7 +39,7 @@
 	struct drm_device *dev = encoder->base.dev;
 	int bpp;
 	int lane_count, slots;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	struct intel_connector *found = NULL, *intel_connector;
 	int mst_pbn;
 
@@ -157,7 +158,8 @@
 	if (intel_dp->active_mst_links == 0) {
 		enum port port = intel_ddi_get_encoder_port(encoder);
 
-		I915_WRITE(PORT_CLK_SEL(port), intel_crtc->config.ddi_pll_sel);
+		I915_WRITE(PORT_CLK_SEL(port),
+			   intel_crtc->config->ddi_pll_sel);
 
 		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
@@ -170,7 +172,8 @@
 	}
 
 	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
-				       intel_mst->port, intel_crtc->config.pbn, &slots);
+				       intel_mst->port,
+				       intel_crtc->config->pbn, &slots);
 	if (ret == false) {
 		DRM_ERROR("failed to allocate vcpi\n");
 		return;
@@ -216,14 +219,14 @@
 }
 
 static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
-					struct intel_crtc_config *pipe_config)
+					struct intel_crtc_state *pipe_config)
 {
 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+	enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
 	u32 temp, flags = 0;
 
 	pipe_config->has_dp_encoder = true;
@@ -254,7 +257,7 @@
 	default:
 		break;
 	}
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 	intel_dp_get_m_n(crtc, pipe_config);
 
 	intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
@@ -311,7 +314,9 @@
 	.detect = intel_dp_mst_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.set_property = intel_dp_mst_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.destroy = intel_dp_mst_connector_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static int intel_dp_mst_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 29ba962..eef79cc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -143,7 +143,7 @@
 	bool connectors_active;
 	void (*hot_plug)(struct intel_encoder *);
 	bool (*compute_config)(struct intel_encoder *,
-			       struct intel_crtc_config *);
+			       struct intel_crtc_state *);
 	void (*pre_pll_enable)(struct intel_encoder *);
 	void (*pre_enable)(struct intel_encoder *);
 	void (*enable)(struct intel_encoder *);
@@ -159,7 +159,7 @@
 	 * pre-filled the pipe config. Note that intel_encoder->base.crtc must
 	 * be set correctly before calling this function. */
 	void (*get_config)(struct intel_encoder *,
-			   struct intel_crtc_config *pipe_config);
+			   struct intel_crtc_state *pipe_config);
 	/*
 	 * Called during system suspend after all pending requests for the
 	 * encoder are flushed (for example for DP AUX transactions) and
@@ -244,23 +244,28 @@
 } intel_clock_t;
 
 struct intel_plane_state {
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	struct drm_plane_state base;
 	struct drm_rect src;
 	struct drm_rect dst;
 	struct drm_rect clip;
-	struct drm_rect orig_src;
-	struct drm_rect orig_dst;
 	bool visible;
+
+	/*
+	 * used only for sprite planes to determine when to implicitly
+	 * enable/disable the primary plane
+	 */
+	bool hides_primary;
 };
 
-struct intel_plane_config {
-	bool tiled;
+struct intel_initial_plane_config {
+	unsigned int tiling;
 	int size;
 	u32 base;
 };
 
-struct intel_crtc_config {
+struct intel_crtc_state {
+	struct drm_crtc_state base;
+
 	/**
 	 * quirks - bitfield with hw state readout quirks
 	 *
@@ -273,16 +278,6 @@
 #define PIPE_CONFIG_QUIRK_INHERITED_MODE	(1<<1) /* mode inherited from firmware */
 	unsigned long quirks;
 
-	/* User requested mode, only valid as a starting point to
-	 * compute adjusted_mode, except in the case of (S)DVO where
-	 * it's also for the output timings of the (S)DVO chip.
-	 * adjusted_mode will then correspond to the S(DVO) chip's
-	 * preferred input timings. */
-	struct drm_display_mode requested_mode;
-	/* Actual pipe timings ie. what we program into the pipe timing
-	 * registers. adjusted_mode.crtc_clock is the pipe pixel clock. */
-	struct drm_display_mode adjusted_mode;
-
 	/* Pipe source size (ie. panel fitter input size)
 	 * All planes will be positioned inside this space,
 	 * and get clipped at the edges. */
@@ -406,8 +401,7 @@
 };
 
 struct intel_mmio_flip {
-	u32 seqno;
-	struct intel_engine_cs *ring;
+	struct drm_i915_gem_request *req;
 	struct work_struct work;
 };
 
@@ -417,6 +411,32 @@
 	uint32_t linetime;
 };
 
+/*
+ * Tracking of operations that need to be performed at the beginning/end of an
+ * atomic commit, outside the atomic section where interrupts are disabled.
+ * These are generally operations that grab mutexes or might otherwise sleep
+ * and thus can't be run with interrupts disabled.
+ */
+struct intel_crtc_atomic_commit {
+	/* vblank evasion */
+	bool evade;
+	unsigned start_vbl_count;
+
+	/* Sleepable operations to perform before commit */
+	bool wait_for_flips;
+	bool disable_fbc;
+	bool pre_disable_primary;
+	bool update_wm;
+	unsigned disabled_planes;
+
+	/* Sleepable operations to perform after commit */
+	unsigned fb_bits;
+	bool wait_vblank;
+	bool update_fbc;
+	bool post_enable_primary;
+	unsigned update_sprite_watermarks;
+};
+
 struct intel_crtc {
 	struct drm_crtc base;
 	enum pipe pipe;
@@ -448,9 +468,9 @@
 	uint32_t cursor_size;
 	uint32_t cursor_base;
 
-	struct intel_plane_config plane_config;
-	struct intel_crtc_config config;
-	struct intel_crtc_config *new_config;
+	struct intel_initial_plane_config plane_config;
+	struct intel_crtc_state *config;
+	struct intel_crtc_state *new_config;
 	bool new_enabled;
 
 	/* reset counter value when the last flip was submitted */
@@ -470,6 +490,8 @@
 
 	int scanline_offset;
 	struct intel_mmio_flip mmio_flip;
+
+	struct intel_crtc_atomic_commit atomic;
 };
 
 struct intel_plane_wm_parameters {
@@ -487,11 +509,6 @@
 	struct drm_i915_gem_object *obj;
 	bool can_scale;
 	int max_downscale;
-	int crtc_x, crtc_y;
-	unsigned int crtc_w, crtc_h;
-	uint32_t src_x, src_y;
-	uint32_t src_w, src_h;
-	unsigned int rotation;
 
 	/* Since we need to change the watermarks before/after
 	 * enabling/disabling the planes, we need to store the parameters here
@@ -500,6 +517,12 @@
 	 */
 	struct intel_plane_wm_parameters wm;
 
+	/*
+	 * NOTE: Do not place new plane state fields here (e.g., when adding
+	 * new plane properties).  New runtime state should now be placed in
+	 * the intel_plane_state structure and accessed via drm_plane->state.
+	 */
+
 	void (*update_plane)(struct drm_plane *plane,
 			     struct drm_crtc *crtc,
 			     struct drm_framebuffer *fb,
@@ -510,6 +533,10 @@
 			     uint32_t src_w, uint32_t src_h);
 	void (*disable_plane)(struct drm_plane *plane,
 			      struct drm_crtc *crtc);
+	int (*check_plane)(struct drm_plane *plane,
+			   struct intel_plane_state *state);
+	void (*commit_plane)(struct drm_plane *plane,
+			     struct intel_plane_state *state);
 	int (*update_colorkey)(struct drm_plane *plane,
 			       struct drm_intel_sprite_colorkey *key);
 	void (*get_colorkey)(struct drm_plane *plane,
@@ -540,6 +567,7 @@
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 #define to_intel_plane(x) container_of(x, struct intel_plane, base)
+#define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
 #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
 
 struct intel_hdmi {
@@ -564,17 +592,6 @@
 struct intel_dp_mst_encoder;
 #define DP_MAX_DOWNSTREAM_PORTS		0x10
 
-/**
- * HIGH_RR is the highest eDP panel refresh rate read from EDID
- * LOW_RR is the lowest eDP panel refresh rate found from EDID
- * parsing for same resolution.
- */
-enum edp_drrs_refresh_rate_type {
-	DRRS_HIGH_RR,
-	DRRS_LOW_RR,
-	DRRS_MAX_RR, /* RR count */
-};
-
 struct intel_dp {
 	uint32_t output_reg;
 	uint32_t aux_ch_ctl_reg;
@@ -630,12 +647,6 @@
 				     bool has_aux_irq,
 				     int send_bytes,
 				     uint32_t aux_clock_divider);
-	struct {
-		enum drrs_support_type type;
-		enum edp_drrs_refresh_rate_type refresh_rate_type;
-		struct mutex mutex;
-	} drrs_state;
-
 };
 
 struct intel_digital_port {
@@ -644,7 +655,7 @@
 	u32 saved_port_bits;
 	struct intel_dp dp;
 	struct intel_hdmi hdmi;
-	bool (*hpd_pulse)(struct intel_digital_port *, bool);
+	enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
 };
 
 struct intel_dp_mst_encoder {
@@ -708,8 +719,7 @@
 #define INTEL_FLIP_COMPLETE	2
 	u32 flip_count;
 	u32 gtt_offset;
-	struct intel_engine_cs *flip_queued_ring;
-	u32 flip_queued_seqno;
+	struct drm_i915_gem_request *flip_queued_req;
 	int flip_queued_vblank;
 	int flip_ready_vblank;
 	bool enable_stall_check;
@@ -826,17 +836,18 @@
 				       enum transcoder cpu_transcoder);
 void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
 void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
-bool intel_ddi_pll_select(struct intel_crtc *crtc);
+bool intel_ddi_pll_select(struct intel_crtc *crtc,
+			  struct intel_crtc_state *crtc_state);
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
 void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
 bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
 void intel_ddi_fdi_disable(struct drm_crtc *crtc);
 void intel_ddi_get_config(struct intel_encoder *encoder,
-			  struct intel_crtc_config *pipe_config);
+			  struct intel_crtc_state *pipe_config);
 
 void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
 void intel_ddi_clock_get(struct intel_encoder *encoder,
-			 struct intel_crtc_config *pipe_config);
+			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 
 /* intel_frontbuffer.c */
@@ -866,6 +877,8 @@
 	intel_frontbuffer_flush(dev, frontbuffer_bits);
 }
 
+int intel_fb_align_height(struct drm_device *dev, int height,
+			  unsigned int tiling);
 void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
 
 
@@ -877,7 +890,7 @@
 void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
 
 /* intel_display.c */
-const char *intel_output_name(int output);
+extern const struct drm_plane_funcs intel_plane_funcs;
 bool intel_has_pending_fb_unpin(struct drm_device *dev);
 int intel_pch_rawclk(struct drm_device *dev);
 void intel_mark_busy(struct drm_device *dev);
@@ -928,6 +941,18 @@
 void intel_finish_page_flip(struct drm_device *dev, int pipe);
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
 void intel_check_page_flip(struct drm_device *dev, int pipe);
+int intel_prepare_plane_fb(struct drm_plane *plane,
+			   struct drm_framebuffer *fb);
+void intel_cleanup_plane_fb(struct drm_plane *plane,
+			    struct drm_framebuffer *fb);
+int intel_plane_atomic_get_property(struct drm_plane *plane,
+				    const struct drm_plane_state *state,
+				    struct drm_property *property,
+				    uint64_t *val);
+int intel_plane_atomic_set_property(struct drm_plane *plane,
+				    struct drm_plane_state *state,
+				    struct drm_property *property,
+				    uint64_t val);
 
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
@@ -936,7 +961,8 @@
 			bool state);
 #define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
 #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc);
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+						struct intel_crtc_state *state);
 void intel_put_shared_dpll(struct intel_crtc *crtc);
 
 void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
@@ -966,11 +992,11 @@
 void hsw_enable_pc8(struct drm_i915_private *dev_priv);
 void hsw_disable_pc8(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
-		      struct intel_crtc_config *pipe_config);
+		      struct intel_crtc_state *pipe_config);
 void intel_dp_set_m_n(struct intel_crtc *crtc);
 int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
 void
-ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
+ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
 				int dotclock);
 bool intel_crtc_active(struct drm_crtc *crtc);
 void hsw_enable_ips(struct intel_crtc *crtc);
@@ -978,8 +1004,7 @@
 enum intel_display_power_domain
 intel_display_port_power_domain(struct intel_encoder *intel_encoder);
 void intel_mode_from_pipe_config(struct drm_display_mode *mode,
-				 struct intel_crtc_config *pipe_config);
-int intel_format_to_fourcc(int format);
+				 struct intel_crtc_state *pipe_config);
 void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
 void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 
@@ -995,16 +1020,15 @@
 void intel_dp_check_link_status(struct intel_dp *intel_dp);
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
-			     struct intel_crtc_config *pipe_config);
+			     struct intel_crtc_state *pipe_config);
 bool intel_dp_is_edp(struct drm_device *dev, enum port port);
-bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
-			bool long_hpd);
+enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
+				  bool long_hpd);
 void intel_edp_backlight_on(struct intel_dp *intel_dp);
 void intel_edp_backlight_off(struct intel_dp *intel_dp);
 void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
 void intel_edp_panel_on(struct intel_dp *intel_dp);
 void intel_edp_panel_off(struct intel_dp *intel_dp);
-void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
 void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
@@ -1013,6 +1037,18 @@
 void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
 uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
 void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
+int intel_update_plane(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);
+int intel_disable_plane(struct drm_plane *plane);
+void intel_plane_destroy(struct drm_plane *plane);
+void intel_edp_drrs_enable(struct intel_dp *intel_dp);
+void intel_edp_drrs_disable(struct intel_dp *intel_dp);
+void intel_edp_drrs_invalidate(struct drm_device *dev,
+		unsigned frontbuffer_bits);
+void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
 
 /* intel_dp_mst.c */
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@@ -1056,13 +1092,20 @@
 }
 #endif
 
+/* intel_fbc.c */
+bool intel_fbc_enabled(struct drm_device *dev);
+void intel_fbc_update(struct drm_device *dev);
+void intel_fbc_init(struct drm_i915_private *dev_priv);
+void intel_fbc_disable(struct drm_device *dev);
+void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
+
 /* intel_hdmi.c */
 void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
 void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 			       struct intel_connector *intel_connector);
 struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
-			       struct intel_crtc_config *pipe_config);
+			       struct intel_crtc_state *pipe_config);
 
 
 /* intel_lvds.c */
@@ -1086,6 +1129,7 @@
 			    struct drm_file *file_priv);
 int intel_overlay_attrs(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
+void intel_overlay_reset(struct drm_i915_private *dev_priv);
 
 
 /* intel_panel.c */
@@ -1096,10 +1140,10 @@
 void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
 			    struct drm_display_mode *adjusted_mode);
 void intel_pch_panel_fitting(struct intel_crtc *crtc,
-			     struct intel_crtc_config *pipe_config,
+			     struct intel_crtc_state *pipe_config,
 			     int fitting_mode);
 void intel_gmch_panel_fitting(struct intel_crtc *crtc,
-			      struct intel_crtc_config *pipe_config,
+			      struct intel_crtc_state *pipe_config,
 			      int fitting_mode);
 void intel_panel_set_backlight_acpi(struct intel_connector *connector,
 				    u32 level, u32 max);
@@ -1118,7 +1162,6 @@
 
 
 /* intel_psr.c */
-bool intel_psr_is_enabled(struct drm_device *dev);
 void intel_psr_enable(struct intel_dp *intel_dp);
 void intel_psr_disable(struct intel_dp *intel_dp);
 void intel_psr_invalidate(struct drm_device *dev,
@@ -1162,8 +1205,6 @@
 				    bool enabled, bool scaled);
 void intel_init_pm(struct drm_device *dev);
 void intel_pm_setup(struct drm_device *dev);
-bool intel_fbc_enabled(struct drm_device *dev);
-void intel_update_fbc(struct drm_device *dev);
 void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
 void intel_gpu_ips_teardown(void);
 void intel_init_gt_powersave(struct drm_device *dev);
@@ -1194,7 +1235,6 @@
 			     struct drm_property *prop,
 			     uint64_t val);
 int intel_plane_restore(struct drm_plane *plane);
-void intel_plane_disable(struct drm_plane *plane);
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
@@ -1202,8 +1242,31 @@
 bool intel_pipe_update_start(struct intel_crtc *crtc,
 			     uint32_t *start_vbl_count);
 void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
+void intel_post_enable_primary(struct drm_crtc *crtc);
+void intel_pre_disable_primary(struct drm_crtc *crtc);
 
 /* intel_tv.c */
 void intel_tv_init(struct drm_device *dev);
 
+/* intel_atomic.c */
+int intel_atomic_check(struct drm_device *dev,
+		       struct drm_atomic_state *state);
+int intel_atomic_commit(struct drm_device *dev,
+			struct drm_atomic_state *state,
+			bool async);
+int intel_connector_atomic_get_property(struct drm_connector *connector,
+					const struct drm_connector_state *state,
+					struct drm_property *property,
+					uint64_t *val);
+struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
+void intel_crtc_destroy_state(struct drm_crtc *crtc,
+			       struct drm_crtc_state *state);
+
+/* intel_atomic_plane.c */
+struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
+struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
+void intel_plane_destroy_state(struct drm_plane *plane,
+			       struct drm_plane_state *state);
+extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
+
 #endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 0b18407..10ab684 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -24,24 +24,219 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/i915_drm.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_mipi_dsi.h>
 #include <linux/slab.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
 
-/* the sub-encoders aka panel drivers */
-static const struct intel_dsi_device intel_dsi_devices[] = {
+static const struct {
+	u16 panel_id;
+	struct drm_panel * (*init)(struct intel_dsi *intel_dsi, u16 panel_id);
+} intel_dsi_drivers[] = {
 	{
 		.panel_id = MIPI_DSI_GENERIC_PANEL_ID,
-		.name = "vbt-generic-dsi-vid-mode-display",
-		.dev_ops = &vbt_generic_dsi_display_ops,
+		.init = vbt_panel_init,
 	},
 };
 
+static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
+{
+	struct drm_encoder *encoder = &intel_dsi->base.base;
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 mask;
+
+	mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
+		LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
+
+	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 100))
+		DRM_ERROR("DPI FIFOs are not empty\n");
+}
+
+static void write_data(struct drm_i915_private *dev_priv, u32 reg,
+		       const u8 *data, u32 len)
+{
+	u32 i, j;
+
+	for (i = 0; i < len; i += 4) {
+		u32 val = 0;
+
+		for (j = 0; j < min_t(u32, len - i, 4); j++)
+			val |= *data++ << 8 * j;
+
+		I915_WRITE(reg, val);
+	}
+}
+
+static void read_data(struct drm_i915_private *dev_priv, u32 reg,
+		      u8 *data, u32 len)
+{
+	u32 i, j;
+
+	for (i = 0; i < len; i += 4) {
+		u32 val = I915_READ(reg);
+
+		for (j = 0; j < min_t(u32, len - i, 4); j++)
+			*data++ = val >> 8 * j;
+	}
+}
+
+static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
+				       const struct mipi_dsi_msg *msg)
+{
+	struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
+	struct drm_device *dev = intel_dsi_host->intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum port port = intel_dsi_host->port;
+	struct mipi_dsi_packet packet;
+	ssize_t ret;
+	const u8 *header, *data;
+	u32 data_reg, data_mask, ctrl_reg, ctrl_mask;
+
+	ret = mipi_dsi_create_packet(&packet, msg);
+	if (ret < 0)
+		return ret;
+
+	header = packet.header;
+	data = packet.payload;
+
+	if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
+		data_reg = MIPI_LP_GEN_DATA(port);
+		data_mask = LP_DATA_FIFO_FULL;
+		ctrl_reg = MIPI_LP_GEN_CTRL(port);
+		ctrl_mask = LP_CTRL_FIFO_FULL;
+	} else {
+		data_reg = MIPI_HS_GEN_DATA(port);
+		data_mask = HS_DATA_FIFO_FULL;
+		ctrl_reg = MIPI_HS_GEN_CTRL(port);
+		ctrl_mask = HS_CTRL_FIFO_FULL;
+	}
+
+	/* note: this is never true for reads */
+	if (packet.payload_length) {
+
+		if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & data_mask) == 0, 50))
+			DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
+
+		write_data(dev_priv, data_reg, packet.payload,
+			   packet.payload_length);
+	}
+
+	if (msg->rx_len) {
+		I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
+	}
+
+	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & ctrl_mask) == 0, 50)) {
+		DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
+	}
+
+	I915_WRITE(ctrl_reg, header[2] << 16 | header[1] << 8 | header[0]);
+
+	/* ->rx_len is set only for reads */
+	if (msg->rx_len) {
+		data_mask = GEN_READ_DATA_AVAIL;
+		if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & data_mask) == data_mask, 50))
+			DRM_ERROR("Timeout waiting for read data.\n");
+
+		read_data(dev_priv, data_reg, msg->rx_buf, msg->rx_len);
+	}
+
+	/* XXX: fix for reads and writes */
+	return 4 + packet.payload_length;
+}
+
+static int intel_dsi_host_attach(struct mipi_dsi_host *host,
+				 struct mipi_dsi_device *dsi)
+{
+	return 0;
+}
+
+static int intel_dsi_host_detach(struct mipi_dsi_host *host,
+				 struct mipi_dsi_device *dsi)
+{
+	return 0;
+}
+
+static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
+	.attach = intel_dsi_host_attach,
+	.detach = intel_dsi_host_detach,
+	.transfer = intel_dsi_host_transfer,
+};
+
+static struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+						  enum port port)
+{
+	struct intel_dsi_host *host;
+	struct mipi_dsi_device *device;
+
+	host = kzalloc(sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return NULL;
+
+	host->base.ops = &intel_dsi_host_ops;
+	host->intel_dsi = intel_dsi;
+	host->port = port;
+
+	/*
+	 * We should call mipi_dsi_host_register(&host->base) here, but we don't
+	 * have a host->dev, and we don't have OF stuff either. So just use the
+	 * dsi framework as a library and hope for the best. Create the dsi
+	 * devices by ourselves here too. Need to be careful though, because we
+	 * don't initialize any of the driver model devices here.
+	 */
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device) {
+		kfree(host);
+		return NULL;
+	}
+
+	device->host = &host->base;
+	host->device = device;
+
+	return host;
+}
+
+/*
+ * send a video mode command
+ *
+ * XXX: commands with data in MIPI_DPI_DATA?
+ */
+static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs,
+			enum port port)
+{
+	struct drm_encoder *encoder = &intel_dsi->base.base;
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 mask;
+
+	/* XXX: pipe, hs */
+	if (hs)
+		cmd &= ~DPI_LP_MODE;
+	else
+		cmd |= DPI_LP_MODE;
+
+	/* clear bit */
+	I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
+
+	/* XXX: old code skips write if control unchanged */
+	if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
+		DRM_ERROR("Same special packet %02x twice in a row.\n", cmd);
+
+	I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
+
+	mask = SPL_PKT_SENT_INTERRUPT;
+	if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 100))
+		DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
+
+	return 0;
+}
+
 static void band_gap_reset(struct drm_i915_private *dev_priv)
 {
 	mutex_lock(&dev_priv->dpio_lock);
@@ -56,12 +251,6 @@
 	mutex_unlock(&dev_priv->dpio_lock);
 }
 
-static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector)
-{
-	return container_of(intel_attached_encoder(connector),
-			    struct intel_dsi, base);
-}
-
 static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
 {
 	return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
@@ -78,14 +267,13 @@
 }
 
 static bool intel_dsi_compute_config(struct intel_encoder *encoder,
-				     struct intel_crtc_config *config)
+				     struct intel_crtc_state *config)
 {
 	struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
 						   base);
 	struct intel_connector *intel_connector = intel_dsi->attached_connector;
 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-	struct drm_display_mode *adjusted_mode = &config->adjusted_mode;
-	struct drm_display_mode *mode = &config->requested_mode;
+	struct drm_display_mode *adjusted_mode = &config->base.adjusted_mode;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -95,18 +283,65 @@
 	/* DSI uses short packets for sync events, so clear mode flags for DSI */
 	adjusted_mode->flags = 0;
 
-	if (intel_dsi->dev.dev_ops->mode_fixup)
-		return intel_dsi->dev.dev_ops->mode_fixup(&intel_dsi->dev,
-							  mode, adjusted_mode);
-
 	return true;
 }
 
+static void intel_dsi_port_enable(struct intel_encoder *encoder)
+{
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	enum port port;
+	u32 temp;
+
+	if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+		temp = I915_READ(VLV_CHICKEN_3);
+		temp &= ~PIXEL_OVERLAP_CNT_MASK |
+					intel_dsi->pixel_overlap <<
+					PIXEL_OVERLAP_CNT_SHIFT;
+		I915_WRITE(VLV_CHICKEN_3, temp);
+	}
+
+	for_each_dsi_port(port, intel_dsi->ports) {
+		temp = I915_READ(MIPI_PORT_CTRL(port));
+		temp &= ~LANE_CONFIGURATION_MASK;
+		temp &= ~DUAL_LINK_MODE_MASK;
+
+		if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) {
+			temp |= (intel_dsi->dual_link - 1)
+						<< DUAL_LINK_MODE_SHIFT;
+			temp |= intel_crtc->pipe ?
+					LANE_CONFIGURATION_DUAL_LINK_B :
+					LANE_CONFIGURATION_DUAL_LINK_A;
+		}
+		/* assert ip_tg_enable signal */
+		I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE);
+		POSTING_READ(MIPI_PORT_CTRL(port));
+	}
+}
+
+static void intel_dsi_port_disable(struct intel_encoder *encoder)
+{
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	enum port port;
+	u32 temp;
+
+	for_each_dsi_port(port, intel_dsi->ports) {
+		/* de-assert ip_tg_enable signal */
+		temp = I915_READ(MIPI_PORT_CTRL(port));
+		I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE);
+		POSTING_READ(MIPI_PORT_CTRL(port));
+	}
+}
+
 static void intel_dsi_device_ready(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-	int pipe = intel_crtc->pipe;
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	enum port port;
 	u32 val;
 
 	DRM_DEBUG_KMS("\n");
@@ -120,48 +355,51 @@
 	/* bandgap reset is needed after everytime we do power gate */
 	band_gap_reset(dev_priv);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER);
-	usleep_range(2500, 3000);
+	for_each_dsi_port(port, intel_dsi->ports) {
 
-	val = I915_READ(MIPI_PORT_CTRL(pipe));
-	I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD);
-	usleep_range(1000, 1500);
+		I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
+		usleep_range(2500, 3000);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT);
-	usleep_range(2500, 3000);
+		/* Enable MIPI PHY transparent latch
+		 * Common bit for both MIPI Port A & MIPI Port C
+		 * No similar bit in MIPI Port C reg
+		 */
+		val = I915_READ(MIPI_PORT_CTRL(PORT_A));
+		I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
+		usleep_range(1000, 1500);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY);
-	usleep_range(2500, 3000);
+		I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
+		usleep_range(2500, 3000);
+
+		I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
+		usleep_range(2500, 3000);
+	}
 }
 
 static void intel_dsi_enable(struct intel_encoder *encoder)
 {
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-	int pipe = intel_crtc->pipe;
-	u32 temp;
+	enum port port;
 
 	DRM_DEBUG_KMS("\n");
 
-	if (is_cmd_mode(intel_dsi))
-		I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4);
-	else {
+	if (is_cmd_mode(intel_dsi)) {
+		for_each_dsi_port(port, intel_dsi->ports)
+			I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
+	} else {
 		msleep(20); /* XXX */
-		dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN);
+		for_each_dsi_port(port, intel_dsi->ports)
+			dpi_send_cmd(intel_dsi, TURN_ON, false, port);
 		msleep(100);
 
-		if (intel_dsi->dev.dev_ops->enable)
-			intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
+		drm_panel_enable(intel_dsi->panel);
 
-		wait_for_dsi_fifo_empty(intel_dsi);
+		for_each_dsi_port(port, intel_dsi->ports)
+			wait_for_dsi_fifo_empty(intel_dsi, port);
 
-		/* assert ip_tg_enable signal */
-		temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK;
-		temp = temp | intel_dsi->port_bits;
-		I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE);
-		POSTING_READ(MIPI_PORT_CTRL(pipe));
+		intel_dsi_port_enable(encoder);
 	}
 }
 
@@ -172,6 +410,7 @@
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	enum pipe pipe = intel_crtc->pipe;
+	enum port port;
 	u32 tmp;
 
 	DRM_DEBUG_KMS("\n");
@@ -183,7 +422,7 @@
 	I915_WRITE(DPLL(pipe), tmp);
 
 	/* update the hw state for DPLL */
-	intel_crtc->config.dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV |
+	intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV |
 		DPLL_REFA_CLK_ENABLE_VLV;
 
 	tmp = I915_READ(DSPCLK_GATE_D);
@@ -195,13 +434,10 @@
 
 	msleep(intel_dsi->panel_on_delay);
 
-	if (intel_dsi->dev.dev_ops->panel_reset)
-		intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev);
+	drm_panel_prepare(intel_dsi->panel);
 
-	if (intel_dsi->dev.dev_ops->send_otp_cmds)
-		intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);
-
-	wait_for_dsi_fifo_empty(intel_dsi);
+	for_each_dsi_port(port, intel_dsi->ports)
+		wait_for_dsi_fifo_empty(intel_dsi, port);
 
 	/* Enable port in pre-enable phase itself because as per hw team
 	 * recommendation, port should be enabled befor plane & pipe */
@@ -221,12 +457,14 @@
 static void intel_dsi_pre_disable(struct intel_encoder *encoder)
 {
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	enum port port;
 
 	DRM_DEBUG_KMS("\n");
 
 	if (is_vid_mode(intel_dsi)) {
 		/* Send Shutdown command to the panel in LP mode */
-		dpi_send_cmd(intel_dsi, SHUTDOWN, DPI_LP_MODE_EN);
+		for_each_dsi_port(port, intel_dsi->ports)
+			dpi_send_cmd(intel_dsi, SHUTDOWN, false, port);
 		msleep(10);
 	}
 }
@@ -235,77 +473,85 @@
 {
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-	int pipe = intel_crtc->pipe;
+	enum port port;
 	u32 temp;
 
 	DRM_DEBUG_KMS("\n");
 
 	if (is_vid_mode(intel_dsi)) {
-		wait_for_dsi_fifo_empty(intel_dsi);
+		for_each_dsi_port(port, intel_dsi->ports)
+			wait_for_dsi_fifo_empty(intel_dsi, port);
 
-		/* de-assert ip_tg_enable signal */
-		temp = I915_READ(MIPI_PORT_CTRL(pipe));
-		I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE);
-		POSTING_READ(MIPI_PORT_CTRL(pipe));
-
+		intel_dsi_port_disable(encoder);
 		msleep(2);
 	}
 
-	/* Panel commands can be sent when clock is in LP11 */
-	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0);
+	for_each_dsi_port(port, intel_dsi->ports) {
+		/* Panel commands can be sent when clock is in LP11 */
+		I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
 
-	temp = I915_READ(MIPI_CTRL(pipe));
-	temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-	I915_WRITE(MIPI_CTRL(pipe), temp |
-		   intel_dsi->escape_clk_div <<
-		   ESCAPE_CLOCK_DIVIDER_SHIFT);
+		temp = I915_READ(MIPI_CTRL(port));
+		temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+		I915_WRITE(MIPI_CTRL(port), temp |
+			   intel_dsi->escape_clk_div <<
+			   ESCAPE_CLOCK_DIVIDER_SHIFT);
 
-	I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP);
+		I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
 
-	temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe));
-	temp &= ~VID_MODE_FORMAT_MASK;
-	I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp);
+		temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
+		temp &= ~VID_MODE_FORMAT_MASK;
+		I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);
-
+		I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
+	}
 	/* if disable packets are sent before sending shutdown packet then in
 	 * some next enable sequence send turn on packet error is observed */
-	if (intel_dsi->dev.dev_ops->disable)
-		intel_dsi->dev.dev_ops->disable(&intel_dsi->dev);
+	drm_panel_disable(intel_dsi->panel);
 
-	wait_for_dsi_fifo_empty(intel_dsi);
+	for_each_dsi_port(port, intel_dsi->ports)
+		wait_for_dsi_fifo_empty(intel_dsi, port);
 }
 
 static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-	int pipe = intel_crtc->pipe;
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	enum port port;
 	u32 val;
 
 	DRM_DEBUG_KMS("\n");
+	for_each_dsi_port(port, intel_dsi->ports) {
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER);
-	usleep_range(2000, 2500);
+		I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+							ULPS_STATE_ENTER);
+		usleep_range(2000, 2500);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT);
-	usleep_range(2000, 2500);
+		I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+							ULPS_STATE_EXIT);
+		usleep_range(2000, 2500);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER);
-	usleep_range(2000, 2500);
+		I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+							ULPS_STATE_ENTER);
+		usleep_range(2000, 2500);
 
-	if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT)
-		      == 0x00000), 30))
-		DRM_ERROR("DSI LP not going Low\n");
+		/* Wait till Clock lanes are in LP-00 state for MIPI Port A
+		 * only. MIPI Port C has no similar bit for checking
+		 */
+		if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT)
+							== 0x00000), 30))
+			DRM_ERROR("DSI LP not going Low\n");
 
-	val = I915_READ(MIPI_PORT_CTRL(pipe));
-	I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD);
-	usleep_range(1000, 1500);
+		/* Disable MIPI PHY transparent latch
+		 * Common bit for both MIPI Port A & MIPI Port C
+		 */
+		val = I915_READ(MIPI_PORT_CTRL(PORT_A));
+		I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD);
+		usleep_range(1000, 1500);
 
-	I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00);
-	usleep_range(2000, 2500);
+		I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
+		usleep_range(2000, 2500);
+	}
 
 	vlv_disable_dsi_pll(encoder);
 }
@@ -326,8 +572,7 @@
 	val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
 	I915_WRITE(DSPCLK_GATE_D, val);
 
-	if (intel_dsi->dev.dev_ops->disable_panel_power)
-		intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev);
+	drm_panel_unprepare(intel_dsi->panel);
 
 	msleep(intel_dsi->panel_off_delay);
 	msleep(intel_dsi->panel_pwr_cycle_delay);
@@ -337,9 +582,11 @@
 				   enum pipe *pipe)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	struct drm_device *dev = encoder->base.dev;
 	enum intel_display_power_domain power_domain;
-	u32 port, func;
-	enum pipe p;
+	u32 dpi_enabled, func;
+	enum port port;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -348,13 +595,23 @@
 		return false;
 
 	/* XXX: this only works for one DSI output */
-	for (p = PIPE_A; p <= PIPE_B; p++) {
-		port = I915_READ(MIPI_PORT_CTRL(p));
-		func = I915_READ(MIPI_DSI_FUNC_PRG(p));
+	for_each_dsi_port(port, intel_dsi->ports) {
+		func = I915_READ(MIPI_DSI_FUNC_PRG(port));
+		dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) &
+							DPI_ENABLE;
 
-		if ((port & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) {
-			if (I915_READ(MIPI_DEVICE_READY(p)) & DEVICE_READY) {
-				*pipe = p;
+		/* Due to some hardware limitations on BYT, MIPI Port C DPI
+		 * Enable bit does not get set. To check whether DSI Port C
+		 * was enabled in BIOS, check the Pipe B enable bit
+		 */
+		if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
+		    (port == PORT_C))
+			dpi_enabled = I915_READ(PIPECONF(PIPE_B)) &
+							PIPECONF_ENABLE;
+
+		if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) {
+			if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) {
+				*pipe = port == PORT_A ? PIPE_A : PIPE_B;
 				return true;
 			}
 		}
@@ -364,7 +621,7 @@
 }
 
 static void intel_dsi_get_config(struct intel_encoder *encoder,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
 	u32 pclk;
 	DRM_DEBUG_KMS("\n");
@@ -379,7 +636,7 @@
 	if (!pclk)
 		return;
 
-	pipe_config->adjusted_mode.crtc_clock = pclk;
+	pipe_config->base.adjusted_mode.crtc_clock = pclk;
 	pipe_config->port_clock = pclk;
 }
 
@@ -389,7 +646,6 @@
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-	struct intel_dsi *intel_dsi = intel_attached_dsi(connector);
 
 	DRM_DEBUG_KMS("\n");
 
@@ -405,7 +661,7 @@
 			return MODE_PANEL;
 	}
 
-	return intel_dsi->dev.dev_ops->mode_valid(&intel_dsi->dev, mode);
+	return MODE_OK;
 }
 
 /* return txclkesc cycles in terms of divider and duration in us */
@@ -437,8 +693,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-	int pipe = intel_crtc->pipe;
-	unsigned int bpp = intel_crtc->config.pipe_bpp;
+	enum port port;
+	unsigned int bpp = intel_crtc->config->pipe_bpp;
 	unsigned int lane_count = intel_dsi->lane_count;
 
 	u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
@@ -448,6 +704,15 @@
 	hsync = mode->hsync_end - mode->hsync_start;
 	hbp = mode->htotal - mode->hsync_end;
 
+	if (intel_dsi->dual_link) {
+		hactive /= 2;
+		if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+			hactive += intel_dsi->pixel_overlap;
+		hfp /= 2;
+		hsync /= 2;
+		hbp /= 2;
+	}
+
 	vfp = mode->vsync_start - mode->vdisplay;
 	vsync = mode->vsync_end - mode->vsync_start;
 	vbp = mode->vtotal - mode->vsync_end;
@@ -460,18 +725,20 @@
 			    intel_dsi->burst_mode_ratio);
 	hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
 
-	I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive);
-	I915_WRITE(MIPI_HFP_COUNT(pipe), hfp);
+	for_each_dsi_port(port, intel_dsi->ports) {
+		I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
+		I915_WRITE(MIPI_HFP_COUNT(port), hfp);
 
-	/* meaningful for video mode non-burst sync pulse mode only, can be zero
-	 * for non-burst sync events and burst modes */
-	I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync);
-	I915_WRITE(MIPI_HBP_COUNT(pipe), hbp);
+		/* meaningful for video mode non-burst sync pulse mode only,
+		 * can be zero for non-burst sync events and burst modes */
+		I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
+		I915_WRITE(MIPI_HBP_COUNT(port), hbp);
 
-	/* vertical values are in terms of lines */
-	I915_WRITE(MIPI_VFP_COUNT(pipe), vfp);
-	I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync);
-	I915_WRITE(MIPI_VBP_COUNT(pipe), vbp);
+		/* vertical values are in terms of lines */
+		I915_WRITE(MIPI_VFP_COUNT(port), vfp);
+		I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
+		I915_WRITE(MIPI_VBP_COUNT(port), vbp);
+	}
 }
 
 static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
@@ -482,33 +749,44 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
 	struct drm_display_mode *adjusted_mode =
-		&intel_crtc->config.adjusted_mode;
-	int pipe = intel_crtc->pipe;
-	unsigned int bpp = intel_crtc->config.pipe_bpp;
+		&intel_crtc->config->base.adjusted_mode;
+	enum port port;
+	unsigned int bpp = intel_crtc->config->pipe_bpp;
 	u32 val, tmp;
+	u16 mode_hdisplay;
 
-	DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
+	DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
 
-	/* escape clock divider, 20MHz, shared for A and C. device ready must be
-	 * off when doing this! txclkesc? */
-	tmp = I915_READ(MIPI_CTRL(0));
-	tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-	I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1);
+	mode_hdisplay = adjusted_mode->hdisplay;
 
-	/* read request priority is per pipe */
-	tmp = I915_READ(MIPI_CTRL(pipe));
-	tmp &= ~READ_REQUEST_PRIORITY_MASK;
-	I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH);
+	if (intel_dsi->dual_link) {
+		mode_hdisplay /= 2;
+		if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+			mode_hdisplay += intel_dsi->pixel_overlap;
+	}
 
-	/* XXX: why here, why like this? handling in irq handler?! */
-	I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff);
-	I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff);
+	for_each_dsi_port(port, intel_dsi->ports) {
+		/* escape clock divider, 20MHz, shared for A and C.
+		 * device ready must be off when doing this! txclkesc? */
+		tmp = I915_READ(MIPI_CTRL(PORT_A));
+		tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+		I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1);
 
-	I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg);
+		/* read request priority is per pipe */
+		tmp = I915_READ(MIPI_CTRL(port));
+		tmp &= ~READ_REQUEST_PRIORITY_MASK;
+		I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH);
 
-	I915_WRITE(MIPI_DPI_RESOLUTION(pipe),
-		   adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
-		   adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT);
+		/* XXX: why here, why like this? handling in irq handler?! */
+		I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
+		I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
+
+		I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
+
+		I915_WRITE(MIPI_DPI_RESOLUTION(port),
+			adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
+			mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
+	}
 
 	set_dsi_timings(encoder, adjusted_mode);
 
@@ -522,95 +800,102 @@
 		/* XXX: cross-check bpp vs. pixel format? */
 		val |= intel_dsi->pixel_format;
 	}
-	I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);
 
-	/* timeouts for recovery. one frame IIUC. if counter expires, EOT and
-	 * stop state. */
-
-	/*
-	 * In burst mode, value greater than one DPI line Time in byte clock
-	 * (txbyteclkhs) To timeout this timer 1+ of the above said value is
-	 * recommended.
-	 *
-	 * In non-burst mode, Value greater than one DPI frame time in byte
-	 * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
-	 * is recommended.
-	 *
-	 * In DBI only mode, value greater than one DBI frame time in byte
-	 * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
-	 * is recommended.
-	 */
-
-	if (is_vid_mode(intel_dsi) &&
-	    intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
-		I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
-			   txbyteclkhs(adjusted_mode->htotal, bpp,
-				       intel_dsi->lane_count,
-				       intel_dsi->burst_mode_ratio) + 1);
-	} else {
-		I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
-			   txbyteclkhs(adjusted_mode->vtotal *
-				       adjusted_mode->htotal,
-				       bpp, intel_dsi->lane_count,
-				       intel_dsi->burst_mode_ratio) + 1);
-	}
-	I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
-	I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
-	I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val);
-
-	/* dphy stuff */
-
-	/* in terms of low power clock */
-	I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100));
-
-	val = 0;
+	tmp = 0;
 	if (intel_dsi->eotp_pkt == 0)
-		val |= EOT_DISABLE;
-
+		tmp |= EOT_DISABLE;
 	if (intel_dsi->clock_stop)
-		val |= CLOCKSTOP;
+		tmp |= CLOCKSTOP;
 
-	/* recovery disables */
-	I915_WRITE(MIPI_EOT_DISABLE(pipe), val);
+	for_each_dsi_port(port, intel_dsi->ports) {
+		I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
 
-	/* in terms of low power clock */
-	I915_WRITE(MIPI_INIT_COUNT(pipe), intel_dsi->init_count);
+		/* timeouts for recovery. one frame IIUC. if counter expires,
+		 * EOT and stop state. */
 
-	/* in terms of txbyteclkhs. actual high to low switch +
-	 * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
-	 *
-	 * XXX: write MIPI_STOP_STATE_STALL?
-	 */
-	I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe),
-		   intel_dsi->hs_to_lp_count);
+		/*
+		 * In burst mode, value greater than one DPI line Time in byte
+		 * clock (txbyteclkhs) To timeout this timer 1+ of the above
+		 * said value is recommended.
+		 *
+		 * In non-burst mode, Value greater than one DPI frame time in
+		 * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+		 * said value is recommended.
+		 *
+		 * In DBI only mode, value greater than one DBI frame time in
+		 * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+		 * said value is recommended.
+		 */
 
-	/* XXX: low power clock equivalence in terms of byte clock. the number
-	 * of byte clocks occupied in one low power clock. based on txbyteclkhs
-	 * and txclkesc. txclkesc time / txbyteclk time * (105 +
-	 * MIPI_STOP_STATE_STALL) / 105.???
-	 */
-	I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk);
+		if (is_vid_mode(intel_dsi) &&
+			intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+			I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+				txbyteclkhs(adjusted_mode->htotal, bpp,
+					intel_dsi->lane_count,
+					intel_dsi->burst_mode_ratio) + 1);
+		} else {
+			I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+				txbyteclkhs(adjusted_mode->vtotal *
+					adjusted_mode->htotal,
+					bpp, intel_dsi->lane_count,
+					intel_dsi->burst_mode_ratio) + 1);
+		}
+		I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
+		I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
+						intel_dsi->turn_arnd_val);
+		I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
+						intel_dsi->rst_timer_val);
 
-	/* the bw essential for transmitting 16 long packets containing 252
-	 * bytes meant for dcs write memory command is programmed in this
-	 * register in terms of byte clocks. based on dsi transfer rate and the
-	 * number of lanes configured the time taken to transmit 16 long packets
-	 * in a dsi stream varies. */
-	I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);
+		/* dphy stuff */
 
-	I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe),
-		   intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
-		   intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
+		/* in terms of low power clock */
+		I915_WRITE(MIPI_INIT_COUNT(port),
+				txclkesc(intel_dsi->escape_clk_div, 100));
 
-	if (is_vid_mode(intel_dsi))
-		/* Some panels might have resolution which is not a multiple of
-		 * 64 like 1366 x 768. Enable RANDOM resolution support for such
-		 * panels by default */
-		I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
-			   intel_dsi->video_frmt_cfg_bits |
-			   intel_dsi->video_mode_format |
-			   IP_TG_CONFIG |
-			   RANDOM_DPI_DISPLAY_RESOLUTION);
+
+		/* recovery disables */
+		I915_WRITE(MIPI_EOT_DISABLE(port), val);
+
+		/* in terms of low power clock */
+		I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
+
+		/* in terms of txbyteclkhs. actual high to low switch +
+		 * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
+		 *
+		 * XXX: write MIPI_STOP_STATE_STALL?
+		 */
+		I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
+						intel_dsi->hs_to_lp_count);
+
+		/* XXX: low power clock equivalence in terms of byte clock.
+		 * the number of byte clocks occupied in one low power clock.
+		 * based on txbyteclkhs and txclkesc.
+		 * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
+		 * ) / 105.???
+		 */
+		I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
+
+		/* the bw essential for transmitting 16 long packets containing
+		 * 252 bytes meant for dcs write memory command is programmed in
+		 * this register in terms of byte clocks. based on dsi transfer
+		 * rate and the number of lanes configured the time taken to
+		 * transmit 16 long packets in a dsi stream varies. */
+		I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
+
+		I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
+		intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
+		intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
+
+		if (is_vid_mode(intel_dsi))
+			/* Some panels might have resolution which is not a
+			 * multiple of 64 like 1366 x 768. Enable RANDOM
+			 * resolution support for such panels by default */
+			I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
+				intel_dsi->video_frmt_cfg_bits |
+				intel_dsi->video_mode_format |
+				IP_TG_CONFIG |
+				RANDOM_DPI_DISPLAY_RESOLUTION);
+	}
 }
 
 static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
@@ -625,20 +910,7 @@
 static enum drm_connector_status
 intel_dsi_detect(struct drm_connector *connector, bool force)
 {
-	struct intel_dsi *intel_dsi = intel_attached_dsi(connector);
-	struct intel_encoder *intel_encoder = &intel_dsi->base;
-	enum intel_display_power_domain power_domain;
-	enum drm_connector_status connector_status;
-	struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
-
-	DRM_DEBUG_KMS("\n");
-	power_domain = intel_display_port_power_domain(intel_encoder);
-
-	intel_display_power_get(dev_priv, power_domain);
-	connector_status = intel_dsi->dev.dev_ops->detect(&intel_dsi->dev);
-	intel_display_power_put(dev_priv, power_domain);
-
-	return connector_status;
+	return connector_status_connected;
 }
 
 static int intel_dsi_get_modes(struct drm_connector *connector)
@@ -664,7 +936,7 @@
 	return 1;
 }
 
-static void intel_dsi_destroy(struct drm_connector *connector)
+static void intel_dsi_connector_destroy(struct drm_connector *connector)
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 
@@ -674,8 +946,20 @@
 	kfree(connector);
 }
 
+static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+
+	if (intel_dsi->panel) {
+		drm_panel_detach(intel_dsi->panel);
+		/* XXX: Logically this call belongs in the panel driver. */
+		drm_panel_remove(intel_dsi->panel);
+	}
+	intel_encoder_destroy(encoder);
+}
+
 static const struct drm_encoder_funcs intel_dsi_funcs = {
-	.destroy = intel_encoder_destroy,
+	.destroy = intel_dsi_encoder_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
@@ -687,8 +971,10 @@
 static const struct drm_connector_funcs intel_dsi_connector_funcs = {
 	.dpms = intel_connector_dpms,
 	.detect = intel_dsi_detect,
-	.destroy = intel_dsi_destroy,
+	.destroy = intel_dsi_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.atomic_get_property = intel_connector_atomic_get_property,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 void intel_dsi_init(struct drm_device *dev)
@@ -698,9 +984,9 @@
 	struct drm_encoder *encoder;
 	struct intel_connector *intel_connector;
 	struct drm_connector *connector;
-	struct drm_display_mode *fixed_mode = NULL;
+	struct drm_display_mode *scan, *fixed_mode = NULL;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	const struct intel_dsi_device *dsi;
+	enum port port;
 	unsigned int i;
 
 	DRM_DEBUG_KMS("\n");
@@ -748,22 +1034,43 @@
 	intel_connector->get_hw_state = intel_connector_get_hw_state;
 	intel_connector->unregister = intel_connector_unregister;
 
-	for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) {
-		dsi = &intel_dsi_devices[i];
-		intel_dsi->dev = *dsi;
+	/* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */
+	if (dev_priv->vbt.dsi.config->dual_link) {
+		/* XXX: does dual link work on either pipe? */
+		intel_encoder->crtc_mask = (1 << PIPE_A);
+		intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C));
+	} else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) {
+		intel_encoder->crtc_mask = (1 << PIPE_A);
+		intel_dsi->ports = (1 << PORT_A);
+	} else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) {
+		intel_encoder->crtc_mask = (1 << PIPE_B);
+		intel_dsi->ports = (1 << PORT_C);
+	}
 
-		if (dsi->dev_ops->init(&intel_dsi->dev))
+	/* Create a DSI host (and a device) for each port. */
+	for_each_dsi_port(port, intel_dsi->ports) {
+		struct intel_dsi_host *host;
+
+		host = intel_dsi_host_init(intel_dsi, port);
+		if (!host)
+			goto err;
+
+		intel_dsi->dsi_hosts[port] = host;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(intel_dsi_drivers); i++) {
+		intel_dsi->panel = intel_dsi_drivers[i].init(intel_dsi,
+							     intel_dsi_drivers[i].panel_id);
+		if (intel_dsi->panel)
 			break;
 	}
 
-	if (i == ARRAY_SIZE(intel_dsi_devices)) {
+	if (!intel_dsi->panel) {
 		DRM_DEBUG_KMS("no device found\n");
 		goto err;
 	}
 
 	intel_encoder->type = INTEL_OUTPUT_DSI;
-	intel_encoder->crtc_mask = (1 << 0); /* XXX */
-
 	intel_encoder->cloneable = 0;
 	drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
 			   DRM_MODE_CONNECTOR_DSI);
@@ -778,13 +1085,23 @@
 
 	drm_connector_register(connector);
 
-	fixed_mode = dsi->dev_ops->get_modes(&intel_dsi->dev);
+	drm_panel_attach(intel_dsi->panel, connector);
+
+	mutex_lock(&dev->mode_config.mutex);
+	drm_panel_get_modes(intel_dsi->panel);
+	list_for_each_entry(scan, &connector->probed_modes, head) {
+		if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
+			fixed_mode = drm_mode_duplicate(dev, scan);
+			break;
+		}
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
 	if (!fixed_mode) {
 		DRM_DEBUG_KMS("no fixed mode\n");
 		goto err;
 	}
 
-	fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
 	intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
 
 	return;
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index 657eb5c..2784ac4 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -26,58 +26,27 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
 #include "intel_drv.h"
 
-struct intel_dsi_device {
-	unsigned int panel_id;
-	const char *name;
-	const struct intel_dsi_dev_ops *dev_ops;
-	void *dev_priv;
-};
+/* Dual Link support */
+#define DSI_DUAL_LINK_NONE		0
+#define DSI_DUAL_LINK_FRONT_BACK	1
+#define DSI_DUAL_LINK_PIXEL_ALT		2
 
-struct intel_dsi_dev_ops {
-	bool (*init)(struct intel_dsi_device *dsi);
-
-	void (*panel_reset)(struct intel_dsi_device *dsi);
-
-	void (*disable_panel_power)(struct intel_dsi_device *dsi);
-
-	/* one time programmable commands if needed */
-	void (*send_otp_cmds)(struct intel_dsi_device *dsi);
-
-	/* This callback must be able to assume DSI commands can be sent */
-	void (*enable)(struct intel_dsi_device *dsi);
-
-	/* This callback must be able to assume DSI commands can be sent */
-	void (*disable)(struct intel_dsi_device *dsi);
-
-	int (*mode_valid)(struct intel_dsi_device *dsi,
-			  struct drm_display_mode *mode);
-
-	bool (*mode_fixup)(struct intel_dsi_device *dsi,
-			   const struct drm_display_mode *mode,
-			   struct drm_display_mode *adjusted_mode);
-
-	void (*mode_set)(struct intel_dsi_device *dsi,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode);
-
-	enum drm_connector_status (*detect)(struct intel_dsi_device *dsi);
-
-	bool (*get_hw_state)(struct intel_dsi_device *dev);
-
-	struct drm_display_mode *(*get_modes)(struct intel_dsi_device *dsi);
-
-	void (*destroy) (struct intel_dsi_device *dsi);
-};
+struct intel_dsi_host;
 
 struct intel_dsi {
 	struct intel_encoder base;
 
-	struct intel_dsi_device dev;
+	struct drm_panel *panel;
+	struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
 
 	struct intel_connector *attached_connector;
 
+	/* bit mask of ports being driven */
+	u16 ports;
+
 	/* if true, use HS mode, otherwise LP */
 	bool hs;
 
@@ -101,6 +70,8 @@
 	u8 clock_stop;
 
 	u8 escape_clk_div;
+	u8 dual_link;
+	u8 pixel_overlap;
 	u32 port_bits;
 	u32 bw_timer;
 	u32 dphy_reg;
@@ -127,6 +98,24 @@
 	u16 panel_pwr_cycle_delay;
 };
 
+struct intel_dsi_host {
+	struct mipi_dsi_host base;
+	struct intel_dsi *intel_dsi;
+	enum port port;
+
+	/* our little hack */
+	struct mipi_dsi_device *device;
+};
+
+static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h)
+{
+	return container_of(h, struct intel_dsi_host, base);
+}
+
+#define for_each_dsi_port(__port, __ports_mask) \
+	for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++)	\
+		if ((__ports_mask) & (1 << (__port)))
+
 static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
 {
 	return container_of(encoder, struct intel_dsi, base.base);
@@ -136,6 +125,6 @@
 extern void vlv_disable_dsi_pll(struct intel_encoder *encoder);
 extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp);
 
-extern struct intel_dsi_dev_ops vbt_generic_dsi_display_ops;
+struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id);
 
 #endif /* _INTEL_DSI_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c
deleted file mode 100644
index f4767fd..0000000
--- a/drivers/gpu/drm/i915/intel_dsi_cmd.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright © 2013 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.
- *
- * Author: Jani Nikula <jani.nikula@intel.com>
- */
-
-#include <linux/export.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <video/mipi_display.h>
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
-
-/*
- * XXX: MIPI_DATA_ADDRESS, MIPI_DATA_LENGTH, MIPI_COMMAND_LENGTH, and
- * MIPI_COMMAND_ADDRESS registers.
- *
- * Apparently these registers provide a MIPI adapter level way to send (lots of)
- * commands and data to the receiver, without having to write the commands and
- * data to MIPI_{HS,LP}_GEN_{CTRL,DATA} registers word by word.
- *
- * Presumably for anything other than MIPI_DCS_WRITE_MEMORY_START and
- * MIPI_DCS_WRITE_MEMORY_CONTINUE (which are used to update the external
- * framebuffer in command mode displays) these are just an optimization that can
- * come later.
- *
- * For memory writes, these should probably be used for performance.
- */
-
-static void print_stat(struct intel_dsi *intel_dsi)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 val;
-
-	val = I915_READ(MIPI_INTR_STAT(pipe));
-
-#define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : ""
-	DRM_DEBUG_KMS("MIPI_INTR_STAT(%d) = %08x"
-		      "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
-		      "\n", pipe, val,
-		      STAT_BIT(val, TEARING_EFFECT),
-		      STAT_BIT(val, SPL_PKT_SENT_INTERRUPT),
-		      STAT_BIT(val, GEN_READ_DATA_AVAIL),
-		      STAT_BIT(val, LP_GENERIC_WR_FIFO_FULL),
-		      STAT_BIT(val, HS_GENERIC_WR_FIFO_FULL),
-		      STAT_BIT(val, RX_PROT_VIOLATION),
-		      STAT_BIT(val, RX_INVALID_TX_LENGTH),
-		      STAT_BIT(val, ACK_WITH_NO_ERROR),
-		      STAT_BIT(val, TURN_AROUND_ACK_TIMEOUT),
-		      STAT_BIT(val, LP_RX_TIMEOUT),
-		      STAT_BIT(val, HS_TX_TIMEOUT),
-		      STAT_BIT(val, DPI_FIFO_UNDERRUN),
-		      STAT_BIT(val, LOW_CONTENTION),
-		      STAT_BIT(val, HIGH_CONTENTION),
-		      STAT_BIT(val, TXDSI_VC_ID_INVALID),
-		      STAT_BIT(val, TXDSI_DATA_TYPE_NOT_RECOGNISED),
-		      STAT_BIT(val, TXCHECKSUM_ERROR),
-		      STAT_BIT(val, TXECC_MULTIBIT_ERROR),
-		      STAT_BIT(val, TXECC_SINGLE_BIT_ERROR),
-		      STAT_BIT(val, TXFALSE_CONTROL_ERROR),
-		      STAT_BIT(val, RXDSI_VC_ID_INVALID),
-		      STAT_BIT(val, RXDSI_DATA_TYPE_NOT_REGOGNISED),
-		      STAT_BIT(val, RXCHECKSUM_ERROR),
-		      STAT_BIT(val, RXECC_MULTIBIT_ERROR),
-		      STAT_BIT(val, RXECC_SINGLE_BIT_ERROR),
-		      STAT_BIT(val, RXFALSE_CONTROL_ERROR),
-		      STAT_BIT(val, RXHS_RECEIVE_TIMEOUT_ERROR),
-		      STAT_BIT(val, RX_LP_TX_SYNC_ERROR),
-		      STAT_BIT(val, RXEXCAPE_MODE_ENTRY_ERROR),
-		      STAT_BIT(val, RXEOT_SYNC_ERROR),
-		      STAT_BIT(val, RXSOT_SYNC_ERROR),
-		      STAT_BIT(val, RXSOT_ERROR));
-#undef STAT_BIT
-}
-
-enum dsi_type {
-	DSI_DCS,
-	DSI_GENERIC,
-};
-
-/* enable or disable command mode hs transmissions */
-void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 temp;
-	u32 mask = DBI_FIFO_EMPTY;
-
-	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 50))
-		DRM_ERROR("Timeout waiting for DBI FIFO empty\n");
-
-	temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(pipe));
-	temp &= DBI_HS_LP_MODE_MASK;
-	I915_WRITE(MIPI_HS_LP_DBI_ENABLE(pipe), enable ? DBI_HS_MODE : DBI_LP_MODE);
-
-	intel_dsi->hs = enable;
-}
-
-static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel,
-			     u8 data_type, u16 data)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 ctrl_reg;
-	u32 ctrl;
-	u32 mask;
-
-	DRM_DEBUG_KMS("channel %d, data_type %d, data %04x\n",
-		      channel, data_type, data);
-
-	if (intel_dsi->hs) {
-		ctrl_reg = MIPI_HS_GEN_CTRL(pipe);
-		mask = HS_CTRL_FIFO_FULL;
-	} else {
-		ctrl_reg = MIPI_LP_GEN_CTRL(pipe);
-		mask = LP_CTRL_FIFO_FULL;
-	}
-
-	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) {
-		DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
-		print_stat(intel_dsi);
-	}
-
-	/*
-	 * Note: This function is also used for long packets, with length passed
-	 * as data, since SHORT_PACKET_PARAM_SHIFT ==
-	 * LONG_PACKET_WORD_COUNT_SHIFT.
-	 */
-	ctrl = data << SHORT_PACKET_PARAM_SHIFT |
-		channel << VIRTUAL_CHANNEL_SHIFT |
-		data_type << DATA_TYPE_SHIFT;
-
-	I915_WRITE(ctrl_reg, ctrl);
-
-	return 0;
-}
-
-static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel,
-			    u8 data_type, const u8 *data, int len)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 data_reg;
-	int i, j, n;
-	u32 mask;
-
-	DRM_DEBUG_KMS("channel %d, data_type %d, len %04x\n",
-		      channel, data_type, len);
-
-	if (intel_dsi->hs) {
-		data_reg = MIPI_HS_GEN_DATA(pipe);
-		mask = HS_DATA_FIFO_FULL;
-	} else {
-		data_reg = MIPI_LP_GEN_DATA(pipe);
-		mask = LP_DATA_FIFO_FULL;
-	}
-
-	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50))
-		DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
-
-	for (i = 0; i < len; i += n) {
-		u32 val = 0;
-		n = min_t(int, len - i, 4);
-
-		for (j = 0; j < n; j++)
-			val |= *data++ << 8 * j;
-
-		I915_WRITE(data_reg, val);
-		/* XXX: check for data fifo full, once that is set, write 4
-		 * dwords, then wait for not set, then continue. */
-	}
-
-	return dsi_vc_send_short(intel_dsi, channel, data_type, len);
-}
-
-static int dsi_vc_write_common(struct intel_dsi *intel_dsi,
-			       int channel, const u8 *data, int len,
-			       enum dsi_type type)
-{
-	int ret;
-
-	if (len == 0) {
-		BUG_ON(type == DSI_GENERIC);
-		ret = dsi_vc_send_short(intel_dsi, channel,
-					MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM,
-					0);
-	} else if (len == 1) {
-		ret = dsi_vc_send_short(intel_dsi, channel,
-					type == DSI_GENERIC ?
-					MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
-					MIPI_DSI_DCS_SHORT_WRITE, data[0]);
-	} else if (len == 2) {
-		ret = dsi_vc_send_short(intel_dsi, channel,
-					type == DSI_GENERIC ?
-					MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
-					MIPI_DSI_DCS_SHORT_WRITE_PARAM,
-					(data[1] << 8) | data[0]);
-	} else {
-		ret = dsi_vc_send_long(intel_dsi, channel,
-				       type == DSI_GENERIC ?
-				       MIPI_DSI_GENERIC_LONG_WRITE :
-				       MIPI_DSI_DCS_LONG_WRITE, data, len);
-	}
-
-	return ret;
-}
-
-int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
-		     const u8 *data, int len)
-{
-	return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS);
-}
-
-int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
-			 const u8 *data, int len)
-{
-	return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC);
-}
-
-static int dsi_vc_dcs_send_read_request(struct intel_dsi *intel_dsi,
-					int channel, u8 dcs_cmd)
-{
-	return dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_DCS_READ,
-				 dcs_cmd);
-}
-
-static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi,
-					    int channel, u8 *reqdata,
-					    int reqlen)
-{
-	u16 data;
-	u8 data_type;
-
-	switch (reqlen) {
-	case 0:
-		data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
-		data = 0;
-		break;
-	case 1:
-		data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
-		data = reqdata[0];
-		break;
-	case 2:
-		data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
-		data = (reqdata[1] << 8) | reqdata[0];
-		break;
-	default:
-		BUG();
-	}
-
-	return dsi_vc_send_short(intel_dsi, channel, data_type, data);
-}
-
-static int dsi_read_data_return(struct intel_dsi *intel_dsi,
-				u8 *buf, int buflen)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	int i, len = 0;
-	u32 data_reg, val;
-
-	if (intel_dsi->hs) {
-		data_reg = MIPI_HS_GEN_DATA(pipe);
-	} else {
-		data_reg = MIPI_LP_GEN_DATA(pipe);
-	}
-
-	while (len < buflen) {
-		val = I915_READ(data_reg);
-		for (i = 0; i < 4 && len < buflen; i++, len++)
-			buf[len] = val >> 8 * i;
-	}
-
-	return len;
-}
-
-int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
-		    u8 *buf, int buflen)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 mask;
-	int ret;
-
-	/*
-	 * XXX: should issue multiple read requests and reads if request is
-	 * longer than MIPI_MAX_RETURN_PKT_SIZE
-	 */
-
-	I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL);
-
-	ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd);
-	if (ret)
-		return ret;
-
-	mask = GEN_READ_DATA_AVAIL;
-	if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50))
-		DRM_ERROR("Timeout waiting for read data.\n");
-
-	ret = dsi_read_data_return(intel_dsi, buf, buflen);
-	if (ret < 0)
-		return ret;
-
-	if (ret != buflen)
-		return -EIO;
-
-	return 0;
-}
-
-int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
-			u8 *reqdata, int reqlen, u8 *buf, int buflen)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 mask;
-	int ret;
-
-	/*
-	 * XXX: should issue multiple read requests and reads if request is
-	 * longer than MIPI_MAX_RETURN_PKT_SIZE
-	 */
-
-	I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL);
-
-	ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata,
-					       reqlen);
-	if (ret)
-		return ret;
-
-	mask = GEN_READ_DATA_AVAIL;
-	if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50))
-		DRM_ERROR("Timeout waiting for read data.\n");
-
-	ret = dsi_read_data_return(intel_dsi, buf, buflen);
-	if (ret < 0)
-		return ret;
-
-	if (ret != buflen)
-		return -EIO;
-
-	return 0;
-}
-
-/*
- * send a video mode command
- *
- * XXX: commands with data in MIPI_DPI_DATA?
- */
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 mask;
-
-	/* XXX: pipe, hs */
-	if (hs)
-		cmd &= ~DPI_LP_MODE;
-	else
-		cmd |= DPI_LP_MODE;
-
-	/* clear bit */
-	I915_WRITE(MIPI_INTR_STAT(pipe), SPL_PKT_SENT_INTERRUPT);
-
-	/* XXX: old code skips write if control unchanged */
-	if (cmd == I915_READ(MIPI_DPI_CONTROL(pipe)))
-		DRM_ERROR("Same special packet %02x twice in a row.\n", cmd);
-
-	I915_WRITE(MIPI_DPI_CONTROL(pipe), cmd);
-
-	mask = SPL_PKT_SENT_INTERRUPT;
-	if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 100))
-		DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
-
-	return 0;
-}
-
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi)
-{
-	struct drm_encoder *encoder = &intel_dsi->base.base;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	enum pipe pipe = intel_crtc->pipe;
-	u32 mask;
-
-	mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
-		LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
-
-	if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100))
-		DRM_ERROR("DPI FIFOs are not empty\n");
-}
diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.h b/drivers/gpu/drm/i915/intel_dsi_cmd.h
index 46aa1ac..8867790 100644
--- a/drivers/gpu/drm/i915/intel_dsi_cmd.h
+++ b/drivers/gpu/drm/i915/intel_dsi_cmd.h
@@ -33,81 +33,7 @@
 #include "intel_drv.h"
 #include "intel_dsi.h"
 
-#define DPI_LP_MODE_EN	false
-#define DPI_HS_MODE_EN	true
-
-void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable);
-
-int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
-		     const u8 *data, int len);
-
-int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
-			 const u8 *data, int len);
-
-int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
-		    u8 *buf, int buflen);
-
-int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
-			u8 *reqdata, int reqlen, u8 *buf, int buflen);
-
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs);
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi);
-
-/* XXX: questionable write helpers */
-static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi,
-				     int channel, u8 dcs_cmd)
-{
-	return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1);
-}
-
-static inline int dsi_vc_dcs_write_1(struct intel_dsi *intel_dsi,
-				     int channel, u8 dcs_cmd, u8 param)
-{
-	u8 buf[2] = { dcs_cmd, param };
-	return dsi_vc_dcs_write(intel_dsi, channel, buf, 2);
-}
-
-static inline int dsi_vc_generic_write_0(struct intel_dsi *intel_dsi,
-					 int channel)
-{
-	return dsi_vc_generic_write(intel_dsi, channel, NULL, 0);
-}
-
-static inline int dsi_vc_generic_write_1(struct intel_dsi *intel_dsi,
-					 int channel, u8 param)
-{
-	return dsi_vc_generic_write(intel_dsi, channel, &param, 1);
-}
-
-static inline int dsi_vc_generic_write_2(struct intel_dsi *intel_dsi,
-					 int channel, u8 param1, u8 param2)
-{
-	u8 buf[2] = { param1, param2 };
-	return dsi_vc_generic_write(intel_dsi, channel, buf, 2);
-}
-
-/* XXX: questionable read helpers */
-static inline int dsi_vc_generic_read_0(struct intel_dsi *intel_dsi,
-					int channel, u8 *buf, int buflen)
-{
-	return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen);
-}
-
-static inline int dsi_vc_generic_read_1(struct intel_dsi *intel_dsi,
-					int channel, u8 param, u8 *buf,
-					int buflen)
-{
-	return dsi_vc_generic_read(intel_dsi, channel, &param, 1, buf, buflen);
-}
-
-static inline int dsi_vc_generic_read_2(struct intel_dsi *intel_dsi,
-					int channel, u8 param1, u8 param2,
-					u8 *buf, int buflen)
-{
-	u8 req[2] = { param1, param2 };
-
-	return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen);
-}
-
+void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable,
+						enum port port);
 
 #endif /* _INTEL_DSI_DSI_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
index f6bdd44..d2cd8d5 100644
--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -28,6 +28,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include <drm/i915_drm.h>
+#include <drm/drm_panel.h>
 #include <linux/slab.h>
 #include <video/mipi_display.h>
 #include <asm/intel-mid.h>
@@ -35,7 +36,16 @@
 #include "i915_drv.h"
 #include "intel_drv.h"
 #include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
+
+struct vbt_panel {
+	struct drm_panel panel;
+	struct intel_dsi *intel_dsi;
+};
+
+static inline struct vbt_panel *to_vbt_panel(struct drm_panel *panel)
+{
+	return container_of(panel, struct vbt_panel, panel);
+}
 
 #define MIPI_TRANSFER_MODE_SHIFT	0
 #define MIPI_VIRTUAL_CHANNEL_SHIFT	1
@@ -94,34 +104,59 @@
 	{ GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0}
 };
 
-static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
+static inline enum port intel_dsi_seq_port_to_port(u8 port)
 {
-	u8 type, byte, mode, vc, port;
+	return port ? PORT_C : PORT_A;
+}
+
+static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
+				       const u8 *data)
+{
+	struct mipi_dsi_device *dsi_device;
+	u8 type, flags, seq_port;
 	u16 len;
+	enum port port;
 
-	byte = *data++;
-	mode = (byte >> MIPI_TRANSFER_MODE_SHIFT) & 0x1;
-	vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3;
-	port = (byte >> MIPI_PORT_SHIFT) & 0x3;
-
-	/* LP or HS mode */
-	intel_dsi->hs = mode;
-
-	/* get packet type and increment the pointer */
+	flags = *data++;
 	type = *data++;
 
 	len = *((u16 *) data);
 	data += 2;
 
+	seq_port = (flags >> MIPI_PORT_SHIFT) & 3;
+
+	/* For DSI single link on Port A & C, the seq_port value which is
+	 * parsed from Sequence Block#53 of VBT has been set to 0
+	 * Now, read/write of packets for the DSI single link on Port A and
+	 * Port C will based on the DVO port from VBT block 2.
+	 */
+	if (intel_dsi->ports == (1 << PORT_C))
+		port = PORT_C;
+	else
+		port = intel_dsi_seq_port_to_port(seq_port);
+
+	dsi_device = intel_dsi->dsi_hosts[port]->device;
+	if (!dsi_device) {
+		DRM_DEBUG_KMS("no dsi device for port %c\n", port_name(port));
+		goto out;
+	}
+
+	if ((flags >> MIPI_TRANSFER_MODE_SHIFT) & 1)
+		dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;
+	else
+		dsi_device->mode_flags |= MIPI_DSI_MODE_LPM;
+
+	dsi_device->channel = (flags >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 3;
+
 	switch (type) {
 	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
-		dsi_vc_generic_write_0(intel_dsi, vc);
+		mipi_dsi_generic_write(dsi_device, NULL, 0);
 		break;
 	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
-		dsi_vc_generic_write_1(intel_dsi, vc, *data);
+		mipi_dsi_generic_write(dsi_device, data, 1);
 		break;
 	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
-		dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1));
+		mipi_dsi_generic_write(dsi_device, data, 2);
 		break;
 	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
 	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
@@ -129,30 +164,31 @@
 		DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n");
 		break;
 	case MIPI_DSI_GENERIC_LONG_WRITE:
-		dsi_vc_generic_write(intel_dsi, vc, data, len);
+		mipi_dsi_generic_write(dsi_device, data, len);
 		break;
 	case MIPI_DSI_DCS_SHORT_WRITE:
-		dsi_vc_dcs_write_0(intel_dsi, vc, *data);
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 1);
 		break;
 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
-		dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1));
+		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
 		break;
 	case MIPI_DSI_DCS_READ:
 		DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n");
 		break;
 	case MIPI_DSI_DCS_LONG_WRITE:
-		dsi_vc_dcs_write(intel_dsi, vc, data, len);
+		mipi_dsi_dcs_write_buffer(dsi_device, data, len);
 		break;
 	}
 
+out:
 	data += len;
 
 	return data;
 }
 
-static u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, u8 *data)
+static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
 {
-	u32 delay = *((u32 *) data);
+	u32 delay = *((const u32 *) data);
 
 	usleep_range(delay, delay + 10);
 	data += 4;
@@ -160,7 +196,7 @@
 	return data;
 }
 
-static u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, u8 *data)
+static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
 {
 	u8 gpio, action;
 	u16 function, pad;
@@ -193,7 +229,8 @@
 	return data;
 }
 
-typedef u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi, u8 *data);
+typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
+					const u8 *data);
 static const fn_mipi_elem_exec exec_elem[] = {
 	NULL, /* reserved */
 	mipi_exec_send_packet,
@@ -217,13 +254,12 @@
 	"MIPI_SEQ_DEASSERT_RESET"
 };
 
-static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
+static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
 {
-	u8 *data = sequence;
 	fn_mipi_elem_exec mipi_elem_exec;
 	int index;
 
-	if (!sequence)
+	if (!data)
 		return;
 
 	DRM_DEBUG_DRIVER("Starting MIPI sequence - %s\n", seq_name[*data]);
@@ -256,14 +292,103 @@
 	}
 }
 
-static bool generic_init(struct intel_dsi_device *dsi)
+static int vbt_panel_prepare(struct drm_panel *panel)
 {
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
+	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const u8 *sequence;
+
+	sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET];
+	generic_exec_sequence(intel_dsi, sequence);
+
+	sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
+	generic_exec_sequence(intel_dsi, sequence);
+
+	return 0;
+}
+
+static int vbt_panel_unprepare(struct drm_panel *panel)
+{
+	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const u8 *sequence;
+
+	sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET];
+	generic_exec_sequence(intel_dsi, sequence);
+
+	return 0;
+}
+
+static int vbt_panel_enable(struct drm_panel *panel)
+{
+	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const u8 *sequence;
+
+	sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON];
+	generic_exec_sequence(intel_dsi, sequence);
+
+	return 0;
+}
+
+static int vbt_panel_disable(struct drm_panel *panel)
+{
+	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	const u8 *sequence;
+
+	sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_OFF];
+	generic_exec_sequence(intel_dsi, sequence);
+
+	return 0;
+}
+
+static int vbt_panel_get_modes(struct drm_panel *panel)
+{
+	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_display_mode *mode;
+
+	if (!panel->connector)
+		return 0;
+
+	mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode);
+	if (!mode)
+		return 0;
+
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+	drm_mode_probed_add(panel->connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs vbt_panel_funcs = {
+	.disable = vbt_panel_disable,
+	.unprepare = vbt_panel_unprepare,
+	.prepare = vbt_panel_prepare,
+	.enable = vbt_panel_enable,
+	.get_modes = vbt_panel_get_modes,
+};
+
+struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
+{
 	struct drm_device *dev = intel_dsi->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
 	struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
 	struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
+	struct vbt_panel *vbt_panel;
 	u32 bits_per_pixel = 24;
 	u32 tlpx_ns, extra_byte_count, bitrate, tlpx_ui;
 	u32 ui_num, ui_den;
@@ -273,6 +398,7 @@
 	u32 lp_to_hs_switch, hs_to_lp_switch;
 	u32 pclk, computed_ddr;
 	u16 burst_mode_ratio;
+	enum port port;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -280,6 +406,8 @@
 	intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
 	intel_dsi->lane_count = mipi_config->lane_cnt + 1;
 	intel_dsi->pixel_format = mipi_config->videomode_color_format << 7;
+	intel_dsi->dual_link = mipi_config->dual_link;
+	intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
 
 	if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666)
 		bits_per_pixel = 18;
@@ -299,6 +427,20 @@
 
 	pclk = mode->clock;
 
+	/* In dual link mode each port needs half of pixel clock */
+	if (intel_dsi->dual_link) {
+		pclk = pclk / 2;
+
+		/* we can enable pixel_overlap if needed by panel. In this
+		 * case we need to increase the pixelclock for extra pixels
+		 */
+		if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+			pclk += DIV_ROUND_UP(mode->vtotal *
+						intel_dsi->pixel_overlap *
+						60, 1000);
+		}
+	}
+
 	/* Burst Mode Ratio
 	 * Target ddr frequency from VBT / non burst ddr freq
 	 * multiply by 100 to preserve remainder
@@ -311,7 +453,7 @@
 			if (mipi_config->target_burst_mode_freq <
 								computed_ddr) {
 				DRM_ERROR("Burst mode freq is less than computed\n");
-				return false;
+				return NULL;
 			}
 
 			burst_mode_ratio = DIV_ROUND_UP(
@@ -321,7 +463,7 @@
 			pclk = DIV_ROUND_UP(pclk * burst_mode_ratio, 100);
 		} else {
 			DRM_ERROR("Burst mode target is not set\n");
-			return false;
+			return NULL;
 		}
 	} else
 		burst_mode_ratio = 100;
@@ -493,6 +635,12 @@
 	DRM_DEBUG_KMS("Clockstop %s\n", intel_dsi->clock_stop ?
 						"disabled" : "enabled");
 	DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video");
+	if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+		DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
+	else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
+		DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
+	else
+		DRM_DEBUG_KMS("Dual link: NONE\n");
 	DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format);
 	DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div);
 	DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout);
@@ -516,110 +664,18 @@
 	intel_dsi->panel_off_delay = pps->panel_off_delay / 10;
 	intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10;
 
-	return true;
+	/* This is cheating a bit with the cleanup. */
+	vbt_panel = devm_kzalloc(dev->dev, sizeof(*vbt_panel), GFP_KERNEL);
+
+	vbt_panel->intel_dsi = intel_dsi;
+	drm_panel_init(&vbt_panel->panel);
+	vbt_panel->panel.funcs = &vbt_panel_funcs;
+	drm_panel_add(&vbt_panel->panel);
+
+	/* a regular driver would get the device in probe */
+	for_each_dsi_port(port, intel_dsi->ports) {
+		mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device);
+	}
+
+	return &vbt_panel->panel;
 }
-
-static int generic_mode_valid(struct intel_dsi_device *dsi,
-		   struct drm_display_mode *mode)
-{
-	return MODE_OK;
-}
-
-static bool generic_mode_fixup(struct intel_dsi_device *dsi,
-		    const struct drm_display_mode *mode,
-		    struct drm_display_mode *adjusted_mode) {
-	return true;
-}
-
-static void generic_panel_reset(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET];
-
-	generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_disable_panel_power(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET];
-
-	generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_send_otp_cmds(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
-
-	generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_enable(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON];
-
-	generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_disable(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_OFF];
-
-	generic_exec_sequence(intel_dsi, sequence);
-}
-
-static enum drm_connector_status generic_detect(struct intel_dsi_device *dsi)
-{
-	return connector_status_connected;
-}
-
-static bool generic_get_hw_state(struct intel_dsi_device *dev)
-{
-	return true;
-}
-
-static struct drm_display_mode *generic_get_modes(struct intel_dsi_device *dsi)
-{
-	struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
-	struct drm_device *dev = intel_dsi->base.base.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	dev_priv->vbt.lfp_lvds_vbt_mode->type |= DRM_MODE_TYPE_PREFERRED;
-	return dev_priv->vbt.lfp_lvds_vbt_mode;
-}
-
-static void generic_destroy(struct intel_dsi_device *dsi) { }
-
-/* Callbacks. We might not need them all. */
-struct intel_dsi_dev_ops vbt_generic_dsi_display_ops = {
-	.init = generic_init,
-	.mode_valid = generic_mode_valid,
-	.mode_fixup = generic_mode_fixup,
-	.panel_reset = generic_panel_reset,
-	.disable_panel_power = generic_disable_panel_power,
-	.send_otp_cmds = generic_send_otp_cmds,
-	.enable = generic_enable,
-	.disable = generic_disable,
-	.detect = generic_detect,
-	.get_hw_state = generic_get_hw_state,
-	.get_modes = generic_get_modes,
-	.destroy = generic_destroy,
-};
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index fa7a6ca..3622d0b 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -241,7 +241,11 @@
 		return;
 	}
 
-	dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+	if (intel_dsi->ports & (1 << PORT_A))
+		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+
+	if (intel_dsi->ports & (1 << PORT_C))
+		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
 
 	DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
 		      dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl);
@@ -269,12 +273,14 @@
 	tmp |= DSI_PLL_VCO_EN;
 	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
 
-	mutex_unlock(&dev_priv->dpio_lock);
+	if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
+						DSI_PLL_LOCK, 20)) {
 
-	if (wait_for(I915_READ(PIPECONF(PIPE_A)) & PIPECONF_DSI_PLL_LOCKED, 20)) {
+		mutex_unlock(&dev_priv->dpio_lock);
 		DRM_ERROR("DSI PLL lock failed\n");
 		return;
 	}
+	mutex_unlock(&dev_priv->dpio_lock);
 
 	DRM_DEBUG_KMS("DSI PLL locked\n");
 }
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index e40e3df..d857951 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -27,6 +27,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
@@ -144,7 +145,7 @@
 }
 
 static void intel_dvo_get_config(struct intel_encoder *encoder,
-				 struct intel_crtc_config *pipe_config)
+				 struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
@@ -160,9 +161,9 @@
 	else
 		flags |= DRM_MODE_FLAG_NVSYNC;
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
-	pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
 static void intel_disable_dvo(struct intel_encoder *encoder)
@@ -186,8 +187,8 @@
 	u32 temp = I915_READ(dvo_reg);
 
 	intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
-					 &crtc->config.requested_mode,
-					 &crtc->config.adjusted_mode);
+					 &crtc->config->base.mode,
+					 &crtc->config->base.adjusted_mode);
 
 	I915_WRITE(dvo_reg, temp | DVO_ENABLE);
 	I915_READ(dvo_reg);
@@ -200,7 +201,7 @@
 {
 	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 	struct drm_crtc *crtc;
-	struct intel_crtc_config *config;
+	struct intel_crtc_state *config;
 
 	/* dvo supports only 2 dpms states. */
 	if (mode != DRM_MODE_DPMS_ON)
@@ -221,7 +222,7 @@
 	/* We call connector dpms manually below in case pipe dpms doesn't
 	 * change due to cloning. */
 	if (mode == DRM_MODE_DPMS_ON) {
-		config = &to_intel_crtc(crtc)->config;
+		config = to_intel_crtc(crtc)->config;
 
 		intel_dvo->base.connectors_active = true;
 
@@ -261,10 +262,10 @@
 }
 
 static bool intel_dvo_compute_config(struct intel_encoder *encoder,
-				     struct intel_crtc_config *pipe_config)
+				     struct intel_crtc_state *pipe_config)
 {
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_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
 	 * to the adjusted mode.  The CRTC will be set up for this mode,
@@ -295,7 +296,7 @@
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-	struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
 	struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
 	int pipe = crtc->pipe;
 	u32 dvo_val;
@@ -390,6 +391,8 @@
 	.detect = intel_dvo_detect,
 	.destroy = intel_dvo_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.atomic_get_property = intel_connector_atomic_get_property,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
new file mode 100644
index 0000000..624d1d9
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright © 2014 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.
+ */
+
+/**
+ * DOC: Frame Buffer Compression (FBC)
+ *
+ * FBC tries to save memory bandwidth (and so power consumption) by
+ * compressing the amount of memory used by the display. It is total
+ * transparent to user space and completely handled in the kernel.
+ *
+ * The benefits of FBC are mostly visible with solid backgrounds and
+ * variation-less patterns. It comes from keeping the memory footprint small
+ * and having fewer memory pages opened and accessed for refreshing the display.
+ *
+ * i915 is responsible to reserve stolen memory for FBC and configure its
+ * offset on proper registers. The hardware takes care of all
+ * compress/decompress. However there are many known cases where we have to
+ * forcibly disable it to allow proper screen updates.
+ */
+
+#include "intel_drv.h"
+#include "i915_drv.h"
+
+static void i8xx_fbc_disable(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 fbc_ctl;
+
+	dev_priv->fbc.enabled = false;
+
+	/* Disable compression */
+	fbc_ctl = I915_READ(FBC_CONTROL);
+	if ((fbc_ctl & FBC_CTL_EN) == 0)
+		return;
+
+	fbc_ctl &= ~FBC_CTL_EN;
+	I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+	/* Wait for compressing bit to clear */
+	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
+		DRM_DEBUG_KMS("FBC idle timed out\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("disabled FBC\n");
+}
+
+static void i8xx_fbc_enable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_framebuffer *fb = crtc->primary->fb;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int cfb_pitch;
+	int i;
+	u32 fbc_ctl;
+
+	dev_priv->fbc.enabled = true;
+
+	cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
+	if (fb->pitches[0] < cfb_pitch)
+		cfb_pitch = fb->pitches[0];
+
+	/* FBC_CTL wants 32B or 64B units */
+	if (IS_GEN2(dev))
+		cfb_pitch = (cfb_pitch / 32) - 1;
+	else
+		cfb_pitch = (cfb_pitch / 64) - 1;
+
+	/* Clear old tags */
+	for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
+		I915_WRITE(FBC_TAG + (i * 4), 0);
+
+	if (IS_GEN4(dev)) {
+		u32 fbc_ctl2;
+
+		/* Set it up... */
+		fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
+		fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
+		I915_WRITE(FBC_CONTROL2, fbc_ctl2);
+		I915_WRITE(FBC_FENCE_OFF, crtc->y);
+	}
+
+	/* enable it... */
+	fbc_ctl = I915_READ(FBC_CONTROL);
+	fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
+	fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
+	if (IS_I945GM(dev))
+		fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
+	fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
+	fbc_ctl |= obj->fence_reg;
+	I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
+		      cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
+}
+
+static bool i8xx_fbc_enabled(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
+}
+
+static void g4x_fbc_enable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_framebuffer *fb = crtc->primary->fb;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	u32 dpfc_ctl;
+
+	dev_priv->fbc.enabled = true;
+
+	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
+	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+	else
+		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+	dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
+
+	I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
+
+	/* enable it... */
+	I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+static void g4x_fbc_disable(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 dpfc_ctl;
+
+	dev_priv->fbc.enabled = false;
+
+	/* Disable compression */
+	dpfc_ctl = I915_READ(DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
+}
+
+static bool g4x_fbc_enabled(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+static void snb_fbc_blit_update(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 blt_ecoskpd;
+
+	/* Make sure blitter notifies FBC of writes */
+
+	/* Blitter is part of Media powerwell on VLV. No impact of
+	 * his param in other platforms for now */
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_MEDIA);
+
+	blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
+	blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
+		GEN6_BLITTER_LOCK_SHIFT;
+	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+	blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
+	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+	blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
+			 GEN6_BLITTER_LOCK_SHIFT);
+	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+	POSTING_READ(GEN6_BLITTER_ECOSKPD);
+
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_MEDIA);
+}
+
+static void ilk_fbc_enable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_framebuffer *fb = crtc->primary->fb;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	u32 dpfc_ctl;
+
+	dev_priv->fbc.enabled = true;
+
+	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
+	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+		dev_priv->fbc.threshold++;
+
+	switch (dev_priv->fbc.threshold) {
+	case 4:
+	case 3:
+		dpfc_ctl |= DPFC_CTL_LIMIT_4X;
+		break;
+	case 2:
+		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+		break;
+	case 1:
+		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+		break;
+	}
+	dpfc_ctl |= DPFC_CTL_FENCE_EN;
+	if (IS_GEN5(dev))
+		dpfc_ctl |= obj->fence_reg;
+
+	I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
+	I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
+	/* enable it... */
+	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+	if (IS_GEN6(dev)) {
+		I915_WRITE(SNB_DPFC_CTL_SA,
+			   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+		I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+		snb_fbc_blit_update(dev);
+	}
+
+	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+static void ilk_fbc_disable(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 dpfc_ctl;
+
+	dev_priv->fbc.enabled = false;
+
+	/* Disable compression */
+	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
+}
+
+static bool ilk_fbc_enabled(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+static void gen7_fbc_enable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_framebuffer *fb = crtc->primary->fb;
+	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	u32 dpfc_ctl;
+
+	dev_priv->fbc.enabled = true;
+
+	dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
+	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+		dev_priv->fbc.threshold++;
+
+	switch (dev_priv->fbc.threshold) {
+	case 4:
+	case 3:
+		dpfc_ctl |= DPFC_CTL_LIMIT_4X;
+		break;
+	case 2:
+		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+		break;
+	case 1:
+		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+		break;
+	}
+
+	dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
+
+	if (dev_priv->fbc.false_color)
+		dpfc_ctl |= FBC_CTL_FALSE_COLOR;
+
+	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+	if (IS_IVYBRIDGE(dev)) {
+		/* WaFbcAsynchFlipDisableFbcQueue:ivb */
+		I915_WRITE(ILK_DISPLAY_CHICKEN1,
+			   I915_READ(ILK_DISPLAY_CHICKEN1) |
+			   ILK_FBCQ_DIS);
+	} else {
+		/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
+		I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
+			   I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
+			   HSW_FBCQ_DIS);
+	}
+
+	I915_WRITE(SNB_DPFC_CTL_SA,
+		   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+	I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+
+	snb_fbc_blit_update(dev);
+
+	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+/**
+ * intel_fbc_enabled - Is FBC enabled?
+ * @dev: the drm_device
+ *
+ * This function is used to verify the current state of FBC.
+ * FIXME: This should be tracked in the plane config eventually
+ *        instead of queried at runtime for most callers.
+ */
+bool intel_fbc_enabled(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	return dev_priv->fbc.enabled;
+}
+
+void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!IS_GEN8(dev))
+		return;
+
+	if (!intel_fbc_enabled(dev))
+		return;
+
+	I915_WRITE(MSG_FBC_REND_STATE, value);
+}
+
+static void intel_fbc_work_fn(struct work_struct *__work)
+{
+	struct intel_fbc_work *work =
+		container_of(to_delayed_work(__work),
+			     struct intel_fbc_work, work);
+	struct drm_device *dev = work->crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	mutex_lock(&dev->struct_mutex);
+	if (work == dev_priv->fbc.fbc_work) {
+		/* Double check that we haven't switched fb without cancelling
+		 * the prior work.
+		 */
+		if (work->crtc->primary->fb == work->fb) {
+			dev_priv->display.enable_fbc(work->crtc);
+
+			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
+			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
+			dev_priv->fbc.y = work->crtc->y;
+		}
+
+		dev_priv->fbc.fbc_work = NULL;
+	}
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(work);
+}
+
+static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv)
+{
+	if (dev_priv->fbc.fbc_work == NULL)
+		return;
+
+	DRM_DEBUG_KMS("cancelling pending FBC enable\n");
+
+	/* Synchronisation is provided by struct_mutex and checking of
+	 * dev_priv->fbc.fbc_work, so we can perform the cancellation
+	 * entirely asynchronously.
+	 */
+	if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
+		/* tasklet was killed before being run, clean up */
+		kfree(dev_priv->fbc.fbc_work);
+
+	/* Mark the work as no longer wanted so that if it does
+	 * wake-up (because the work was already running and waiting
+	 * for our mutex), it will discover that is no longer
+	 * necessary to run.
+	 */
+	dev_priv->fbc.fbc_work = NULL;
+}
+
+static void intel_fbc_enable(struct drm_crtc *crtc)
+{
+	struct intel_fbc_work *work;
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!dev_priv->display.enable_fbc)
+		return;
+
+	intel_fbc_cancel_work(dev_priv);
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (work == NULL) {
+		DRM_ERROR("Failed to allocate FBC work structure\n");
+		dev_priv->display.enable_fbc(crtc);
+		return;
+	}
+
+	work->crtc = crtc;
+	work->fb = crtc->primary->fb;
+	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
+
+	dev_priv->fbc.fbc_work = work;
+
+	/* Delay the actual enabling to let pageflipping cease and the
+	 * display to settle before starting the compression. Note that
+	 * this delay also serves a second purpose: it allows for a
+	 * vblank to pass after disabling the FBC before we attempt
+	 * to modify the control registers.
+	 *
+	 * A more complicated solution would involve tracking vblanks
+	 * following the termination of the page-flipping sequence
+	 * and indeed performing the enable as a co-routine and not
+	 * waiting synchronously upon the vblank.
+	 *
+	 * WaFbcWaitForVBlankBeforeEnable:ilk,snb
+	 */
+	schedule_delayed_work(&work->work, msecs_to_jiffies(50));
+}
+
+/**
+ * intel_fbc_disable - disable FBC
+ * @dev: the drm_device
+ *
+ * This function disables FBC.
+ */
+void intel_fbc_disable(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_fbc_cancel_work(dev_priv);
+
+	if (!dev_priv->display.disable_fbc)
+		return;
+
+	dev_priv->display.disable_fbc(dev);
+	dev_priv->fbc.plane = -1;
+}
+
+static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
+			      enum no_fbc_reason reason)
+{
+	if (dev_priv->fbc.no_fbc_reason == reason)
+		return false;
+
+	dev_priv->fbc.no_fbc_reason = reason;
+	return true;
+}
+
+/**
+ * intel_fbc_update - enable/disable FBC as needed
+ * @dev: the drm_device
+ *
+ * Set up the framebuffer compression hardware at mode set time.  We
+ * enable it if possible:
+ *   - plane A only (on pre-965)
+ *   - no pixel mulitply/line duplication
+ *   - no alpha buffer discard
+ *   - no dual wide
+ *   - framebuffer <= max_hdisplay in width, max_vdisplay in height
+ *
+ * We can't assume that any compression will take place (worst case),
+ * so the compressed buffer has to be the same size as the uncompressed
+ * one.  It also must reside (along with the line length buffer) in
+ * stolen memory.
+ *
+ * We need to enable/disable FBC on a global basis.
+ */
+void intel_fbc_update(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = NULL, *tmp_crtc;
+	struct intel_crtc *intel_crtc;
+	struct drm_framebuffer *fb;
+	struct drm_i915_gem_object *obj;
+	const struct drm_display_mode *adjusted_mode;
+	unsigned int max_width, max_height;
+
+	if (!HAS_FBC(dev)) {
+		set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
+		return;
+	}
+
+	if (!i915.powersave) {
+		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
+			DRM_DEBUG_KMS("fbc disabled per module param\n");
+		return;
+	}
+
+	/*
+	 * If FBC is already on, we just have to verify that we can
+	 * keep it that way...
+	 * Need to disable if:
+	 *   - more than one pipe is active
+	 *   - changing FBC params (stride, fence, mode)
+	 *   - new fb is too large to fit in compressed buffer
+	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
+	 */
+	for_each_crtc(dev, tmp_crtc) {
+		if (intel_crtc_active(tmp_crtc) &&
+		    to_intel_crtc(tmp_crtc)->primary_enabled) {
+			if (crtc) {
+				if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
+					DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+				goto out_disable;
+			}
+			crtc = tmp_crtc;
+		}
+	}
+
+	if (!crtc || crtc->primary->fb == NULL) {
+		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
+			DRM_DEBUG_KMS("no output, disabling\n");
+		goto out_disable;
+	}
+
+	intel_crtc = to_intel_crtc(crtc);
+	fb = crtc->primary->fb;
+	obj = intel_fb_obj(fb);
+	adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+
+	if (i915.enable_fbc < 0) {
+		if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
+			DRM_DEBUG_KMS("disabled per chip default\n");
+		goto out_disable;
+	}
+	if (!i915.enable_fbc) {
+		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
+			DRM_DEBUG_KMS("fbc disabled per module param\n");
+		goto out_disable;
+	}
+	if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
+	    (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+		if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
+			DRM_DEBUG_KMS("mode incompatible with compression, "
+				      "disabling\n");
+		goto out_disable;
+	}
+
+	if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
+		max_width = 4096;
+		max_height = 4096;
+	} else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+		max_width = 4096;
+		max_height = 2048;
+	} else {
+		max_width = 2048;
+		max_height = 1536;
+	}
+	if (intel_crtc->config->pipe_src_w > max_width ||
+	    intel_crtc->config->pipe_src_h > max_height) {
+		if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
+			DRM_DEBUG_KMS("mode too large for compression, disabling\n");
+		goto out_disable;
+	}
+	if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
+	    intel_crtc->plane != PLANE_A) {
+		if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
+			DRM_DEBUG_KMS("plane not A, disabling compression\n");
+		goto out_disable;
+	}
+
+	/* The use of a CPU fence is mandatory in order to detect writes
+	 * by the CPU to the scanout and trigger updates to the FBC.
+	 */
+	if (obj->tiling_mode != I915_TILING_X ||
+	    obj->fence_reg == I915_FENCE_REG_NONE) {
+		if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
+			DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
+		goto out_disable;
+	}
+	if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+	    crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) {
+		if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
+			DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
+		goto out_disable;
+	}
+
+	/* If the kernel debugger is active, always disable compression */
+	if (in_dbg_master())
+		goto out_disable;
+
+	if (i915_gem_stolen_setup_compression(dev, obj->base.size,
+					      drm_format_plane_cpp(fb->pixel_format, 0))) {
+		if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
+			DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
+		goto out_disable;
+	}
+
+	/* If the scanout has not changed, don't modify the FBC settings.
+	 * Note that we make the fundamental assumption that the fb->obj
+	 * cannot be unpinned (and have its GTT offset and fence revoked)
+	 * without first being decoupled from the scanout and FBC disabled.
+	 */
+	if (dev_priv->fbc.plane == intel_crtc->plane &&
+	    dev_priv->fbc.fb_id == fb->base.id &&
+	    dev_priv->fbc.y == crtc->y)
+		return;
+
+	if (intel_fbc_enabled(dev)) {
+		/* We update FBC along two paths, after changing fb/crtc
+		 * configuration (modeswitching) and after page-flipping
+		 * finishes. For the latter, we know that not only did
+		 * we disable the FBC at the start of the page-flip
+		 * sequence, but also more than one vblank has passed.
+		 *
+		 * For the former case of modeswitching, it is possible
+		 * to switch between two FBC valid configurations
+		 * instantaneously so we do need to disable the FBC
+		 * before we can modify its control registers. We also
+		 * have to wait for the next vblank for that to take
+		 * effect. However, since we delay enabling FBC we can
+		 * assume that a vblank has passed since disabling and
+		 * that we can safely alter the registers in the deferred
+		 * callback.
+		 *
+		 * In the scenario that we go from a valid to invalid
+		 * and then back to valid FBC configuration we have
+		 * no strict enforcement that a vblank occurred since
+		 * disabling the FBC. However, along all current pipe
+		 * disabling paths we do need to wait for a vblank at
+		 * some point. And we wait before enabling FBC anyway.
+		 */
+		DRM_DEBUG_KMS("disabling active FBC for update\n");
+		intel_fbc_disable(dev);
+	}
+
+	intel_fbc_enable(crtc);
+	dev_priv->fbc.no_fbc_reason = FBC_OK;
+	return;
+
+out_disable:
+	/* Multiple disables should be harmless */
+	if (intel_fbc_enabled(dev)) {
+		DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
+		intel_fbc_disable(dev);
+	}
+	i915_gem_stolen_cleanup_compression(dev);
+}
+
+/**
+ * intel_fbc_init - Initialize FBC
+ * @dev_priv: the i915 device
+ *
+ * This function might be called during PM init process.
+ */
+void intel_fbc_init(struct drm_i915_private *dev_priv)
+{
+	if (!HAS_FBC(dev_priv)) {
+		dev_priv->fbc.enabled = false;
+		return;
+	}
+
+	if (INTEL_INFO(dev_priv)->gen >= 7) {
+		dev_priv->display.fbc_enabled = ilk_fbc_enabled;
+		dev_priv->display.enable_fbc = gen7_fbc_enable;
+		dev_priv->display.disable_fbc = ilk_fbc_disable;
+	} else if (INTEL_INFO(dev_priv)->gen >= 5) {
+		dev_priv->display.fbc_enabled = ilk_fbc_enabled;
+		dev_priv->display.enable_fbc = ilk_fbc_enable;
+		dev_priv->display.disable_fbc = ilk_fbc_disable;
+	} else if (IS_GM45(dev_priv)) {
+		dev_priv->display.fbc_enabled = g4x_fbc_enabled;
+		dev_priv->display.enable_fbc = g4x_fbc_enable;
+		dev_priv->display.disable_fbc = g4x_fbc_disable;
+	} else {
+		dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
+		dev_priv->display.enable_fbc = i8xx_fbc_enable;
+		dev_priv->display.disable_fbc = i8xx_fbc_disable;
+
+		/* This value was pulled out of someone's hat */
+		I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
+	}
+
+	dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
+}
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 850cf7d..3001a867 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -443,7 +443,7 @@
 			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
 				      connector->name);
 			intel_mode_from_pipe_config(&encoder->crtc->hwmode,
-						    &to_intel_crtc(encoder->crtc)->config);
+						    to_intel_crtc(encoder->crtc)->config);
 			modes[i] = &encoder->crtc->hwmode;
 		}
 		crtcs[i] = new_crtc;
@@ -531,7 +531,7 @@
 	struct intel_framebuffer *fb = NULL;
 	struct drm_crtc *crtc;
 	struct intel_crtc *intel_crtc;
-	struct intel_plane_config *plane_config = NULL;
+	struct intel_initial_plane_config *plane_config = NULL;
 	unsigned int max_size = 0;
 
 	if (!i915.fastboot)
@@ -581,7 +581,7 @@
 		 * pipe.  Note we need to use the selected fb's pitch and bpp
 		 * rather than the current pipe's, since they differ.
 		 */
-		cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay;
+		cur_size = intel_crtc->config->base.adjusted_mode.crtc_hdisplay;
 		cur_size = cur_size * fb->base.bits_per_pixel / 8;
 		if (fb->base.pitches[0] < cur_size) {
 			DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
@@ -592,13 +592,14 @@
 			break;
 		}
 
-		cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay;
-		cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1);
+		cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
+		cur_size = intel_fb_align_height(dev, cur_size,
+						 plane_config->tiling);
 		cur_size *= fb->base.pitches[0];
 		DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
 			      pipe_name(intel_crtc->pipe),
-			      intel_crtc->config.adjusted_mode.crtc_hdisplay,
-			      intel_crtc->config.adjusted_mode.crtc_vdisplay,
+			      intel_crtc->config->base.adjusted_mode.crtc_hdisplay,
+			      intel_crtc->config->base.adjusted_mode.crtc_vdisplay,
 			      fb->base.bits_per_pixel,
 			      cur_size);
 
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 77af512..04e248d 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -341,7 +341,7 @@
 }
 
 /**
- * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrupt
+ * intel_cpu_fifo_underrun_irq_handler - handle CPU fifo underrun interrupt
  * @dev_priv: i915 device instance
  * @pipe: (CPU) pipe to set state for
  *
diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c
index 79f6d72..73cb6e0 100644
--- a/drivers/gpu/drm/i915/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
@@ -157,6 +157,7 @@
 	intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
 
 	intel_psr_invalidate(dev, obj->frontbuffer_bits);
+	intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
 }
 
 /**
@@ -182,6 +183,7 @@
 
 	intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
 
+	intel_edp_drrs_flush(dev, frontbuffer_bits);
 	intel_psr_flush(dev, frontbuffer_bits);
 
 	/*
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 3abc200..995c5b2 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/hdmi.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
@@ -337,13 +338,13 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
 	u32 data_reg;
 	int i;
 	u32 val = I915_READ(ctl_reg);
 
 	data_reg = hsw_infoframe_data_reg(type,
-					  intel_crtc->config.cpu_transcoder,
+					  intel_crtc->config->cpu_transcoder,
 					  dev_priv);
 	if (data_reg == 0)
 		return;
@@ -371,7 +372,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
 	u32 val = I915_READ(ctl_reg);
 
 	return val & (VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_SPD_HSW |
@@ -436,7 +437,7 @@
 	}
 
 	if (intel_hdmi->rgb_quant_range_selectable) {
-		if (intel_crtc->config.limited_color_range)
+		if (intel_crtc->config->limited_color_range)
 			frame.avi.quantization_range =
 				HDMI_QUANTIZATION_RANGE_LIMITED;
 		else
@@ -672,7 +673,7 @@
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
 	u32 val = I915_READ(reg);
 
 	assert_hdmi_port_disabled(intel_hdmi);
@@ -700,7 +701,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-	struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
 	u32 hdmi_val;
 
 	hdmi_val = SDVO_ENCODING_HDMI;
@@ -711,12 +712,12 @@
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 		hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
 
-	if (crtc->config.pipe_bpp > 24)
+	if (crtc->config->pipe_bpp > 24)
 		hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
 	else
 		hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
 
-	if (crtc->config.has_hdmi_sink)
+	if (crtc->config->has_hdmi_sink)
 		hdmi_val |= HDMI_MODE_SELECT_HDMI;
 
 	if (HAS_PCH_CPT(dev))
@@ -759,7 +760,7 @@
 }
 
 static void intel_hdmi_get_config(struct intel_encoder *encoder,
-				  struct intel_crtc_config *pipe_config)
+				  struct intel_crtc_state *pipe_config)
 {
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	struct drm_device *dev = encoder->base.dev;
@@ -792,7 +793,7 @@
 	    tmp & HDMI_COLOR_RANGE_16_235)
 		pipe_config->limited_color_range = true;
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
 	if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
 		dotclock = pipe_config->port_clock * 2 / 3;
@@ -802,7 +803,7 @@
 	if (HAS_PCH_SPLIT(dev_priv->dev))
 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-	pipe_config->adjusted_mode.crtc_clock = dotclock;
+	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 }
 
 static void intel_enable_hdmi(struct intel_encoder *encoder)
@@ -814,7 +815,7 @@
 	u32 temp;
 	u32 enable_bits = SDVO_ENABLE;
 
-	if (intel_crtc->config.has_audio)
+	if (intel_crtc->config->has_audio)
 		enable_bits |= SDVO_AUDIO_ENABLE;
 
 	temp = I915_READ(intel_hdmi->hdmi_reg);
@@ -845,8 +846,8 @@
 		POSTING_READ(intel_hdmi->hdmi_reg);
 	}
 
-	if (intel_crtc->config.has_audio) {
-		WARN_ON(!intel_crtc->config.has_hdmi_sink);
+	if (intel_crtc->config->has_audio) {
+		WARN_ON(!intel_crtc->config->has_hdmi_sink);
 		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
 				 pipe_name(intel_crtc->pipe));
 		intel_audio_codec_enable(encoder);
@@ -866,7 +867,7 @@
 	u32 temp;
 	u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
 
-	if (crtc->config.has_audio)
+	if (crtc->config->has_audio)
 		intel_audio_codec_disable(encoder);
 
 	temp = I915_READ(intel_hdmi->hdmi_reg);
@@ -975,12 +976,12 @@
 }
 
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
-			       struct intel_crtc_config *pipe_config)
+			       struct intel_crtc_state *pipe_config)
 {
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	struct drm_device *dev = encoder->base.dev;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
-	int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+	int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2;
 	int portclock_limit = hdmi_portclock_limit(intel_hdmi, false);
 	int desired_bpp;
 
@@ -1252,12 +1253,12 @@
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	struct drm_display_mode *adjusted_mode =
-		&intel_crtc->config.adjusted_mode;
+		&intel_crtc->config->base.adjusted_mode;
 
 	intel_hdmi_prepare(encoder);
 
 	intel_hdmi->set_infoframes(&encoder->base,
-				   intel_crtc->config.has_hdmi_sink,
+				   intel_crtc->config->has_hdmi_sink,
 				   adjusted_mode);
 }
 
@@ -1270,7 +1271,7 @@
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(encoder->base.crtc);
 	struct drm_display_mode *adjusted_mode =
-		&intel_crtc->config.adjusted_mode;
+		&intel_crtc->config->base.adjusted_mode;
 	enum dpio_channel port = vlv_dport_to_channel(dport);
 	int pipe = intel_crtc->pipe;
 	u32 val;
@@ -1302,7 +1303,7 @@
 	mutex_unlock(&dev_priv->dpio_lock);
 
 	intel_hdmi->set_infoframes(&encoder->base,
-				   intel_crtc->config.has_hdmi_sink,
+				   intel_crtc->config->has_hdmi_sink,
 				   adjusted_mode);
 
 	intel_enable_hdmi(encoder);
@@ -1467,7 +1468,7 @@
 	struct intel_crtc *intel_crtc =
 		to_intel_crtc(encoder->base.crtc);
 	struct drm_display_mode *adjusted_mode =
-		&intel_crtc->config.adjusted_mode;
+		&intel_crtc->config->base.adjusted_mode;
 	enum dpio_channel ch = vlv_dport_to_channel(dport);
 	int pipe = intel_crtc->pipe;
 	int data, i;
@@ -1593,7 +1594,7 @@
 	mutex_unlock(&dev_priv->dpio_lock);
 
 	intel_hdmi->set_infoframes(&encoder->base,
-				   intel_crtc->config.has_hdmi_sink,
+				   intel_crtc->config->has_hdmi_sink,
 				   adjusted_mode);
 
 	intel_enable_hdmi(encoder);
@@ -1614,7 +1615,9 @@
 	.force = intel_hdmi_force,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.set_property = intel_hdmi_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.destroy = intel_hdmi_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index e588376..0f358c5 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -212,8 +212,7 @@
  * @enable_execlists: value of i915.enable_execlists module parameter.
  *
  * Only certain platforms support Execlists (the prerequisites being
- * support for Logical Ring Contexts and Aliasing PPGTT or better),
- * and only when enabled via module parameter.
+ * support for Logical Ring Contexts and Aliasing PPGTT or better).
  *
  * Return: 1 if Execlists is supported and has to be enabled.
  */
@@ -284,7 +283,6 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint64_t temp = 0;
 	uint32_t desc[4];
-	unsigned long flags;
 
 	/* XXX: You must always write both descriptors in the order below. */
 	if (ctx_obj1)
@@ -298,63 +296,17 @@
 	desc[3] = (u32)(temp >> 32);
 	desc[2] = (u32)temp;
 
-	/* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
-	 * are in progress.
-	 *
-	 * The other problem is that we can't just call gen6_gt_force_wake_get()
-	 * because that function calls intel_runtime_pm_get(), which might sleep.
-	 * Instead, we do the runtime_pm_get/put when creating/destroying requests.
-	 */
-	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
-	if (IS_CHERRYVIEW(dev) || INTEL_INFO(dev)->gen >= 9) {
-		if (dev_priv->uncore.fw_rendercount++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							      FORCEWAKE_RENDER);
-		if (dev_priv->uncore.fw_mediacount++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							      FORCEWAKE_MEDIA);
-		if (INTEL_INFO(dev)->gen >= 9) {
-			if (dev_priv->uncore.fw_blittercount++ == 0)
-				dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							FORCEWAKE_BLITTER);
-		}
-	} else {
-		if (dev_priv->uncore.forcewake_count++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							      FORCEWAKE_ALL);
-	}
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
-
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 	I915_WRITE(RING_ELSP(ring), desc[1]);
 	I915_WRITE(RING_ELSP(ring), desc[0]);
 	I915_WRITE(RING_ELSP(ring), desc[3]);
+
 	/* The context is automatically loaded after the following */
 	I915_WRITE(RING_ELSP(ring), desc[2]);
 
 	/* ELSP is a wo register, so use another nearby reg for posting instead */
 	POSTING_READ(RING_EXECLIST_STATUS(ring));
-
-	/* Release Force Wakeup (see the big comment above). */
-	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
-	if (IS_CHERRYVIEW(dev) || INTEL_INFO(dev)->gen >= 9) {
-		if (--dev_priv->uncore.fw_rendercount == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							      FORCEWAKE_RENDER);
-		if (--dev_priv->uncore.fw_mediacount == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							      FORCEWAKE_MEDIA);
-		if (INTEL_INFO(dev)->gen >= 9) {
-			if (--dev_priv->uncore.fw_blittercount == 0)
-				dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							FORCEWAKE_BLITTER);
-		}
-	} else {
-		if (--dev_priv->uncore.forcewake_count == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							      FORCEWAKE_ALL);
-	}
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static int execlists_update_context(struct drm_i915_gem_object *ctx_obj,
@@ -405,8 +357,8 @@
 
 static void execlists_context_unqueue(struct intel_engine_cs *ring)
 {
-	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
-	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+	struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
+	struct drm_i915_gem_request *cursor = NULL, *tmp = NULL;
 
 	assert_spin_locked(&ring->execlist_lock);
 
@@ -446,12 +398,12 @@
 static bool execlists_check_remove_request(struct intel_engine_cs *ring,
 					   u32 request_id)
 {
-	struct intel_ctx_submit_request *head_req;
+	struct drm_i915_gem_request *head_req;
 
 	assert_spin_locked(&ring->execlist_lock);
 
 	head_req = list_first_entry_or_null(&ring->execlist_queue,
-					    struct intel_ctx_submit_request,
+					    struct drm_i915_gem_request,
 					    execlist_link);
 
 	if (head_req != NULL) {
@@ -474,13 +426,13 @@
 }
 
 /**
- * intel_execlists_handle_ctx_events() - handle Context Switch interrupts
+ * intel_lrc_irq_handler() - handle Context Switch interrupts
  * @ring: Engine Command Streamer to handle.
  *
  * Check the unread Context Status Buffers and manage the submission of new
  * contexts to the ELSP accordingly.
  */
-void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
+void intel_lrc_irq_handler(struct intel_engine_cs *ring)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	u32 status_pointer;
@@ -535,24 +487,34 @@
 
 static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
-				   u32 tail)
+				   u32 tail,
+				   struct drm_i915_gem_request *request)
 {
-	struct intel_ctx_submit_request *req = NULL, *cursor;
+	struct drm_i915_gem_request *cursor;
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	unsigned long flags;
 	int num_elements = 0;
 
-	req = kzalloc(sizeof(*req), GFP_KERNEL);
-	if (req == NULL)
-		return -ENOMEM;
-	req->ctx = to;
-	i915_gem_context_reference(req->ctx);
-
 	if (to != ring->default_context)
 		intel_lr_context_pin(ring, to);
 
-	req->ring = ring;
-	req->tail = tail;
+	if (!request) {
+		/*
+		 * If there isn't a request associated with this submission,
+		 * create one as a temporary holder.
+		 */
+		WARN(1, "execlist context submission without request");
+		request = kzalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return -ENOMEM;
+		request->ring = ring;
+		request->ctx = to;
+	} else {
+		WARN_ON(to != request->ctx);
+	}
+	request->tail = tail;
+	i915_gem_request_reference(request);
+	i915_gem_context_reference(request->ctx);
 
 	intel_runtime_pm_get(dev_priv);
 
@@ -563,10 +525,10 @@
 			break;
 
 	if (num_elements > 2) {
-		struct intel_ctx_submit_request *tail_req;
+		struct drm_i915_gem_request *tail_req;
 
 		tail_req = list_last_entry(&ring->execlist_queue,
-					   struct intel_ctx_submit_request,
+					   struct drm_i915_gem_request,
 					   execlist_link);
 
 		if (to == tail_req->ctx) {
@@ -578,7 +540,7 @@
 		}
 	}
 
-	list_add_tail(&req->execlist_link, &ring->execlist_queue);
+	list_add_tail(&request->execlist_link, &ring->execlist_queue);
 	if (num_elements == 0)
 		execlists_context_unqueue(ring);
 
@@ -587,7 +549,8 @@
 	return 0;
 }
 
-static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
+static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf,
+					      struct intel_context *ctx)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
 	uint32_t flush_domains;
@@ -597,7 +560,8 @@
 	if (ring->gpu_caches_dirty)
 		flush_domains = I915_GEM_GPU_DOMAINS;
 
-	ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains);
+	ret = ring->emit_flush(ringbuf, ctx,
+			       I915_GEM_GPU_DOMAINS, flush_domains);
 	if (ret)
 		return ret;
 
@@ -606,6 +570,7 @@
 }
 
 static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
+				 struct intel_context *ctx,
 				 struct list_head *vmas)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -633,7 +598,7 @@
 	/* Unconditionally invalidate gpu caches and ensure that we do flush
 	 * any residual writes from the previous batch.
 	 */
-	return logical_ring_invalidate_all_caches(ringbuf);
+	return logical_ring_invalidate_all_caches(ringbuf, ctx);
 }
 
 /**
@@ -713,13 +678,13 @@
 		return -EINVAL;
 	}
 
-	ret = execlists_move_to_gpu(ringbuf, vmas);
+	ret = execlists_move_to_gpu(ringbuf, ctx, vmas);
 	if (ret)
 		return ret;
 
 	if (ring == &dev_priv->ring[RCS] &&
 	    instp_mode != dev_priv->relative_constants_mode) {
-		ret = intel_logical_ring_begin(ringbuf, 4);
+		ret = intel_logical_ring_begin(ringbuf, ctx, 4);
 		if (ret)
 			return ret;
 
@@ -732,7 +697,7 @@
 		dev_priv->relative_constants_mode = instp_mode;
 	}
 
-	ret = ring->emit_bb_start(ringbuf, exec_start, flags);
+	ret = ring->emit_bb_start(ringbuf, ctx, exec_start, flags);
 	if (ret)
 		return ret;
 
@@ -744,7 +709,7 @@
 
 void intel_execlists_retire_requests(struct intel_engine_cs *ring)
 {
-	struct intel_ctx_submit_request *req, *tmp;
+	struct drm_i915_gem_request *req, *tmp;
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	unsigned long flags;
 	struct list_head retired_list;
@@ -766,9 +731,9 @@
 		if (ctx_obj && (ctx != ring->default_context))
 			intel_lr_context_unpin(ring, ctx);
 		intel_runtime_pm_put(dev_priv);
-		i915_gem_context_unreference(req->ctx);
+		i915_gem_context_unreference(ctx);
 		list_del(&req->execlist_link);
-		kfree(req);
+		i915_gem_request_unreference(req);
 	}
 }
 
@@ -794,7 +759,8 @@
 	I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
 }
 
-int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
+				  struct intel_context *ctx)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
 	int ret;
@@ -802,7 +768,7 @@
 	if (!ring->gpu_caches_dirty)
 		return 0;
 
-	ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+	ret = ring->emit_flush(ringbuf, ctx, 0, I915_GEM_GPU_DOMAINS);
 	if (ret)
 		return ret;
 
@@ -819,17 +785,18 @@
  * on a queue waiting for the ELSP to be ready to accept a new context submission. At that
  * point, the tail *inside* the context is updated and the ELSP written to.
  */
-void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf,
+					   struct intel_context *ctx,
+					   struct drm_i915_gem_request *request)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
-	struct intel_context *ctx = ringbuf->FIXME_lrc_ctx;
 
 	intel_logical_ring_advance(ringbuf);
 
 	if (intel_ring_stopped(ring))
 		return;
 
-	execlists_context_queue(ring, ctx, ringbuf->tail);
+	execlists_context_queue(ring, ctx, ringbuf->tail, request);
 }
 
 static int intel_lr_context_pin(struct intel_engine_cs *ring,
@@ -840,11 +807,11 @@
 	int ret = 0;
 
 	WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
-	if (ctx->engine[ring->id].unpin_count++ == 0) {
+	if (ctx->engine[ring->id].pin_count++ == 0) {
 		ret = i915_gem_obj_ggtt_pin(ctx_obj,
 				GEN8_LR_CONTEXT_ALIGN, 0);
 		if (ret)
-			goto reset_unpin_count;
+			goto reset_pin_count;
 
 		ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
 		if (ret)
@@ -855,8 +822,8 @@
 
 unpin_ctx_obj:
 	i915_gem_object_ggtt_unpin(ctx_obj);
-reset_unpin_count:
-	ctx->engine[ring->id].unpin_count = 0;
+reset_pin_count:
+	ctx->engine[ring->id].pin_count = 0;
 
 	return ret;
 }
@@ -869,47 +836,55 @@
 
 	if (ctx_obj) {
 		WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
-		if (--ctx->engine[ring->id].unpin_count == 0) {
+		if (--ctx->engine[ring->id].pin_count == 0) {
 			intel_unpin_ringbuffer_obj(ringbuf);
 			i915_gem_object_ggtt_unpin(ctx_obj);
 		}
 	}
 }
 
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
-				    struct intel_context *ctx)
+static int logical_ring_alloc_request(struct intel_engine_cs *ring,
+				      struct intel_context *ctx)
 {
+	struct drm_i915_gem_request *request;
+	struct drm_i915_private *dev_private = ring->dev->dev_private;
 	int ret;
 
-	if (ring->outstanding_lazy_seqno)
+	if (ring->outstanding_lazy_request)
 		return 0;
 
-	if (ring->preallocated_lazy_request == NULL) {
-		struct drm_i915_gem_request *request;
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
 
-		request = kmalloc(sizeof(*request), GFP_KERNEL);
-		if (request == NULL)
-			return -ENOMEM;
-
-		if (ctx != ring->default_context) {
-			ret = intel_lr_context_pin(ring, ctx);
-			if (ret) {
-				kfree(request);
-				return ret;
-			}
+	if (ctx != ring->default_context) {
+		ret = intel_lr_context_pin(ring, ctx);
+		if (ret) {
+			kfree(request);
+			return ret;
 		}
-
-		/* Hold a reference to the context this request belongs to
-		 * (we will need it when the time comes to emit/retire the
-		 * request).
-		 */
-		request->ctx = ctx;
-		i915_gem_context_reference(request->ctx);
-
-		ring->preallocated_lazy_request = request;
 	}
 
-	return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+	kref_init(&request->ref);
+	request->ring = ring;
+	request->uniq = dev_private->request_uniq++;
+
+	ret = i915_gem_get_seqno(ring->dev, &request->seqno);
+	if (ret) {
+		intel_lr_context_unpin(ring, ctx);
+		kfree(request);
+		return ret;
+	}
+
+	/* Hold a reference to the context this request belongs to
+	 * (we will need it when the time comes to emit/retire the
+	 * request).
+	 */
+	request->ctx = ctx;
+	i915_gem_context_reference(request->ctx);
+
+	ring->outstanding_lazy_request = request;
+	return 0;
 }
 
 static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
@@ -917,42 +892,42 @@
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
 	struct drm_i915_gem_request *request;
-	u32 seqno = 0;
 	int ret;
 
-	if (ringbuf->last_retired_head != -1) {
-		ringbuf->head = ringbuf->last_retired_head;
-		ringbuf->last_retired_head = -1;
-
-		ringbuf->space = intel_ring_space(ringbuf);
-		if (ringbuf->space >= bytes)
-			return 0;
-	}
+	if (intel_ring_space(ringbuf) >= bytes)
+		return 0;
 
 	list_for_each_entry(request, &ring->request_list, list) {
+		/*
+		 * The request queue is per-engine, so can contain requests
+		 * from multiple ringbuffers. Here, we must ignore any that
+		 * aren't from the ringbuffer we're considering.
+		 */
+		struct intel_context *ctx = request->ctx;
+		if (ctx->engine[ring->id].ringbuf != ringbuf)
+			continue;
+
+		/* Would completion of this request free enough space? */
 		if (__intel_ring_space(request->tail, ringbuf->tail,
 				       ringbuf->size) >= bytes) {
-			seqno = request->seqno;
 			break;
 		}
 	}
 
-	if (seqno == 0)
+	if (&request->list == &ring->request_list)
 		return -ENOSPC;
 
-	ret = i915_wait_seqno(ring, seqno);
+	ret = i915_wait_request(request);
 	if (ret)
 		return ret;
 
 	i915_gem_retire_requests_ring(ring);
-	ringbuf->head = ringbuf->last_retired_head;
-	ringbuf->last_retired_head = -1;
 
-	ringbuf->space = intel_ring_space(ringbuf);
-	return 0;
+	return intel_ring_space(ringbuf) >= bytes ? 0 : -ENOSPC;
 }
 
 static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
+				       struct intel_context *ctx,
 				       int bytes)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -966,7 +941,7 @@
 		return ret;
 
 	/* Force the context submission in case we have been skipping it */
-	intel_logical_ring_advance_and_submit(ringbuf);
+	intel_logical_ring_advance_and_submit(ringbuf, ctx, NULL);
 
 	/* With GEM the hangcheck timer should kick us out of the loop,
 	 * leaving it early runs the risk of corrupting GEM state (due
@@ -975,13 +950,10 @@
 	 * case by choosing an insanely large timeout. */
 	end = jiffies + 60 * HZ;
 
+	ret = 0;
 	do {
-		ringbuf->head = I915_READ_HEAD(ring);
-		ringbuf->space = intel_ring_space(ringbuf);
-		if (ringbuf->space >= bytes) {
-			ret = 0;
+		if (intel_ring_space(ringbuf) >= bytes)
 			break;
-		}
 
 		msleep(1);
 
@@ -1004,13 +976,14 @@
 	return ret;
 }
 
-static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf,
+				    struct intel_context *ctx)
 {
 	uint32_t __iomem *virt;
 	int rem = ringbuf->size - ringbuf->tail;
 
 	if (ringbuf->space < rem) {
-		int ret = logical_ring_wait_for_space(ringbuf, rem);
+		int ret = logical_ring_wait_for_space(ringbuf, ctx, rem);
 
 		if (ret)
 			return ret;
@@ -1022,23 +995,24 @@
 		iowrite32(MI_NOOP, virt++);
 
 	ringbuf->tail = 0;
-	ringbuf->space = intel_ring_space(ringbuf);
+	intel_ring_update_space(ringbuf);
 
 	return 0;
 }
 
-static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
+				struct intel_context *ctx, int bytes)
 {
 	int ret;
 
 	if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
-		ret = logical_ring_wrap_buffer(ringbuf);
+		ret = logical_ring_wrap_buffer(ringbuf, ctx);
 		if (unlikely(ret))
 			return ret;
 	}
 
 	if (unlikely(ringbuf->space < bytes)) {
-		ret = logical_ring_wait_for_space(ringbuf, bytes);
+		ret = logical_ring_wait_for_space(ringbuf, ctx, bytes);
 		if (unlikely(ret))
 			return ret;
 	}
@@ -1059,7 +1033,8 @@
  *
  * Return: non-zero if the ringbuffer is not ready to be written to.
  */
-int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+			     struct intel_context *ctx, int num_dwords)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
 	struct drm_device *dev = ring->dev;
@@ -1071,12 +1046,12 @@
 	if (ret)
 		return ret;
 
-	ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+	ret = logical_ring_prepare(ringbuf, ctx, num_dwords * sizeof(uint32_t));
 	if (ret)
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx);
+	ret = logical_ring_alloc_request(ring, ctx);
 	if (ret)
 		return ret;
 
@@ -1093,15 +1068,15 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct i915_workarounds *w = &dev_priv->workarounds;
 
-	if (WARN_ON(w->count == 0))
+	if (WARN_ON_ONCE(w->count == 0))
 		return 0;
 
 	ring->gpu_caches_dirty = true;
-	ret = logical_ring_flush_all_caches(ringbuf);
+	ret = logical_ring_flush_all_caches(ringbuf, ctx);
 	if (ret)
 		return ret;
 
-	ret = intel_logical_ring_begin(ringbuf, w->count * 2 + 2);
+	ret = intel_logical_ring_begin(ringbuf, ctx, w->count * 2 + 2);
 	if (ret)
 		return ret;
 
@@ -1115,7 +1090,7 @@
 	intel_logical_ring_advance(ringbuf);
 
 	ring->gpu_caches_dirty = true;
-	ret = logical_ring_flush_all_caches(ringbuf);
+	ret = logical_ring_flush_all_caches(ringbuf, ctx);
 	if (ret)
 		return ret;
 
@@ -1134,6 +1109,7 @@
 		   _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
 		   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
 	POSTING_READ(RING_MODE_GEN7(ring));
+	ring->next_context_status_buffer = 0;
 	DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
 
 	memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
@@ -1159,22 +1135,19 @@
 	 */
 	I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
 
-	ret = intel_init_pipe_control(ring);
-	if (ret)
-		return ret;
-
 	I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
 
 	return init_workarounds_ring(ring);
 }
 
 static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+			      struct intel_context *ctx,
 			      u64 offset, unsigned flags)
 {
 	bool ppgtt = !(flags & I915_DISPATCH_SECURE);
 	int ret;
 
-	ret = intel_logical_ring_begin(ringbuf, 4);
+	ret = intel_logical_ring_begin(ringbuf, ctx, 4);
 	if (ret)
 		return ret;
 
@@ -1222,6 +1195,7 @@
 }
 
 static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
+			   struct intel_context *ctx,
 			   u32 invalidate_domains,
 			   u32 unused)
 {
@@ -1231,21 +1205,23 @@
 	uint32_t cmd;
 	int ret;
 
-	ret = intel_logical_ring_begin(ringbuf, 4);
+	ret = intel_logical_ring_begin(ringbuf, ctx, 4);
 	if (ret)
 		return ret;
 
 	cmd = MI_FLUSH_DW + 1;
 
-	if (ring == &dev_priv->ring[VCS]) {
-		if (invalidate_domains & I915_GEM_GPU_DOMAINS)
-			cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
-				MI_FLUSH_DW_STORE_INDEX |
-				MI_FLUSH_DW_OP_STOREDW;
-	} else {
-		if (invalidate_domains & I915_GEM_DOMAIN_RENDER)
-			cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
-				MI_FLUSH_DW_OP_STOREDW;
+	/* We always require a command barrier so that subsequent
+	 * commands, such as breadcrumb interrupts, are strictly ordered
+	 * wrt the contents of the write cache being flushed to memory
+	 * (and thus being coherent from the CPU).
+	 */
+	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
+	if (invalidate_domains & I915_GEM_GPU_DOMAINS) {
+		cmd |= MI_INVALIDATE_TLB;
+		if (ring == &dev_priv->ring[VCS])
+			cmd |= MI_INVALIDATE_BSD;
 	}
 
 	intel_logical_ring_emit(ringbuf, cmd);
@@ -1260,6 +1236,7 @@
 }
 
 static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
+				  struct intel_context *ctx,
 				  u32 invalidate_domains,
 				  u32 flush_domains)
 {
@@ -1286,7 +1263,7 @@
 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
 	}
 
-	ret = intel_logical_ring_begin(ringbuf, 6);
+	ret = intel_logical_ring_begin(ringbuf, ctx, 6);
 	if (ret)
 		return ret;
 
@@ -1311,17 +1288,18 @@
 	intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
 }
 
-static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
+static int gen8_emit_request(struct intel_ringbuffer *ringbuf,
+			     struct drm_i915_gem_request *request)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
 	u32 cmd;
 	int ret;
 
-	ret = intel_logical_ring_begin(ringbuf, 6);
+	ret = intel_logical_ring_begin(ringbuf, request->ctx, 6);
 	if (ret)
 		return ret;
 
-	cmd = MI_STORE_DWORD_IMM_GEN8;
+	cmd = MI_STORE_DWORD_IMM_GEN4;
 	cmd |= MI_GLOBAL_GTT;
 
 	intel_logical_ring_emit(ringbuf, cmd);
@@ -1329,14 +1307,27 @@
 				(ring->status_page.gfx_addr +
 				(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
 	intel_logical_ring_emit(ringbuf, 0);
-	intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno);
+	intel_logical_ring_emit(ringbuf,
+		i915_gem_request_get_seqno(ring->outstanding_lazy_request));
 	intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
 	intel_logical_ring_emit(ringbuf, MI_NOOP);
-	intel_logical_ring_advance_and_submit(ringbuf);
+	intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request);
 
 	return 0;
 }
 
+static int gen8_init_rcs_context(struct intel_engine_cs *ring,
+		       struct intel_context *ctx)
+{
+	int ret;
+
+	ret = intel_logical_ring_workarounds_emit(ring, ctx);
+	if (ret)
+		return ret;
+
+	return intel_lr_context_render_state_init(ring, ctx);
+}
+
 /**
  * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
  *
@@ -1354,8 +1345,7 @@
 
 	intel_logical_ring_stop(ring);
 	WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
-	ring->preallocated_lazy_request = NULL;
-	ring->outstanding_lazy_seqno = 0;
+	i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
 
 	if (ring->cleanup)
 		ring->cleanup(ring);
@@ -1383,18 +1373,11 @@
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	INIT_LIST_HEAD(&ring->execlist_retired_req_list);
 	spin_lock_init(&ring->execlist_lock);
-	ring->next_context_status_buffer = 0;
 
 	ret = i915_cmd_parser_init_ring(ring);
 	if (ret)
 		return ret;
 
-	if (ring->init) {
-		ret = ring->init(ring);
-		if (ret)
-			return ret;
-	}
-
 	ret = intel_lr_context_deferred_create(ring->default_context, ring);
 
 	return ret;
@@ -1404,6 +1387,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
+	int ret;
 
 	ring->name = "render ring";
 	ring->id = RCS;
@@ -1415,8 +1399,8 @@
 	if (HAS_L3_DPF(dev))
 		ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
-	ring->init = gen8_init_render_ring;
-	ring->init_context = intel_logical_ring_workarounds_emit;
+	ring->init_hw = gen8_init_render_ring;
+	ring->init_context = gen8_init_rcs_context;
 	ring->cleanup = intel_fini_pipe_control;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
@@ -1426,7 +1410,12 @@
 	ring->irq_put = gen8_logical_ring_put_irq;
 	ring->emit_bb_start = gen8_emit_bb_start;
 
-	return logical_ring_init(dev, ring);
+	ring->dev = dev;
+	ret = logical_ring_init(dev, ring);
+	if (ret)
+		return ret;
+
+	return intel_init_pipe_control(ring);
 }
 
 static int logical_bsd_ring_init(struct drm_device *dev)
@@ -1442,7 +1431,7 @@
 	ring->irq_keep_mask =
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
-	ring->init = gen8_init_common_ring;
+	ring->init_hw = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
@@ -1467,7 +1456,7 @@
 	ring->irq_keep_mask =
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
-	ring->init = gen8_init_common_ring;
+	ring->init_hw = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
@@ -1492,7 +1481,7 @@
 	ring->irq_keep_mask =
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
-	ring->init = gen8_init_common_ring;
+	ring->init_hw = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
@@ -1517,7 +1506,7 @@
 	ring->irq_keep_mask =
 		GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
-	ring->init = gen8_init_common_ring;
+	ring->init_hw = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
@@ -1609,6 +1598,7 @@
 		return 0;
 
 	ret = ring->emit_bb_start(ringbuf,
+			ctx,
 			so.ggtt_offset,
 			I915_DISPATCH_SECURE);
 	if (ret)
@@ -1616,7 +1606,7 @@
 
 	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
 
-	ret = __i915_add_request(ring, file, so.obj, NULL);
+	ret = __i915_add_request(ring, file, so.obj);
 	/* intel_logical_ring_add_request moves object to inactive if it
 	 * fails */
 out:
@@ -1763,6 +1753,7 @@
 				intel_unpin_ringbuffer_obj(ringbuf);
 				i915_gem_object_ggtt_unpin(ctx_obj);
 			}
+			WARN_ON(ctx->engine[ring->id].pin_count);
 			intel_destroy_ringbuffer_obj(ringbuf);
 			kfree(ringbuf);
 			drm_gem_object_unreference(&ctx_obj->base);
@@ -1835,8 +1826,7 @@
 	int ret;
 
 	WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
-	if (ctx->engine[ring->id].state)
-		return 0;
+	WARN_ON(ctx->engine[ring->id].state);
 
 	context_size = round_up(get_lr_context_size(ring), 4096);
 
@@ -1866,14 +1856,13 @@
 	}
 
 	ringbuf->ring = ring;
-	ringbuf->FIXME_lrc_ctx = ctx;
 
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
 	ringbuf->tail = 0;
-	ringbuf->space = ringbuf->size;
 	ringbuf->last_retired_head = -1;
+	intel_ring_update_space(ringbuf);
 
 	if (ringbuf->obj == NULL) {
 		ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
@@ -1907,21 +1896,17 @@
 
 	if (ctx == ring->default_context)
 		lrc_setup_hardware_status_page(ring, ctx_obj);
-
-	if (ring->id == RCS && !ctx->rcs_initialized) {
+	else if (ring->id == RCS && !ctx->rcs_initialized) {
 		if (ring->init_context) {
 			ret = ring->init_context(ring, ctx);
-			if (ret)
+			if (ret) {
 				DRM_ERROR("ring init context: %d\n", ret);
+				ctx->engine[ring->id].ringbuf = NULL;
+				ctx->engine[ring->id].state = NULL;
+				goto error;
+			}
 		}
 
-		ret = intel_lr_context_render_state_init(ring, ctx);
-		if (ret) {
-			DRM_ERROR("Init render state failed: %d\n", ret);
-			ctx->engine[ring->id].ringbuf = NULL;
-			ctx->engine[ring->id].state = NULL;
-			goto error;
-		}
 		ctx->rcs_initialized = true;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 14b216b..6f2d7da 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -38,8 +38,12 @@
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
 int intel_logical_rings_init(struct drm_device *dev);
 
-int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
-void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
+				  struct intel_context *ctx);
+void intel_logical_ring_advance_and_submit(
+				struct intel_ringbuffer *ringbuf,
+				struct intel_context *ctx,
+				struct drm_i915_gem_request *request);
 /**
  * intel_logical_ring_advance() - advance the ringbuffer tail
  * @ringbuf: Ringbuffer to advance.
@@ -61,7 +65,9 @@
 	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
 	ringbuf->tail += 4;
 }
-int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+			     struct intel_context *ctx,
+			     int num_dwords);
 
 /* Logical Ring Contexts */
 int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
@@ -83,36 +89,7 @@
 			       u64 exec_start, u32 flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
-/**
- * struct intel_ctx_submit_request - queued context submission request
- * @ctx: Context to submit to the ELSP.
- * @ring: Engine to submit it to.
- * @tail: how far in the context's ringbuffer this request goes to.
- * @execlist_link: link in the submission queue.
- * @work: workqueue for processing this request in a bottom half.
- * @elsp_submitted: no. of times this request has been sent to the ELSP.
- *
- * The ELSP only accepts two elements at a time, so we queue context/tail
- * pairs on a given queue (ring->execlist_queue) until the hardware is
- * available. The queue serves a double purpose: we also use it to keep track
- * of the up to 2 contexts currently in the hardware (usually one in execution
- * and the other queued up by the GPU): We only remove elements from the head
- * of the queue when the hardware informs us that an element has been
- * completed.
- *
- * All accesses to the queue are mediated by a spinlock (ring->execlist_lock).
- */
-struct intel_ctx_submit_request {
-	struct intel_context *ctx;
-	struct intel_engine_cs *ring;
-	u32 tail;
-
-	struct list_head execlist_link;
-
-	int elsp_submitted;
-};
-
-void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+void intel_lrc_irq_handler(struct intel_engine_cs *ring);
 void intel_execlists_retire_requests(struct intel_engine_cs *ring);
 
 #endif /* _INTEL_LRC_H_ */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 14654d6..071b96d 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
@@ -93,7 +94,7 @@
 }
 
 static void intel_lvds_get_config(struct intel_encoder *encoder,
-				  struct intel_crtc_config *pipe_config)
+				  struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -115,7 +116,7 @@
 	else
 		flags |= DRM_MODE_FLAG_PVSYNC;
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
 	/* gen2/3 store dither state in pfit control, needs to match */
 	if (INTEL_INFO(dev)->gen < 4) {
@@ -129,7 +130,7 @@
 	if (HAS_PCH_SPLIT(dev_priv->dev))
 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-	pipe_config->adjusted_mode.crtc_clock = dotclock;
+	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 }
 
 static void intel_pre_enable_lvds(struct intel_encoder *encoder)
@@ -139,7 +140,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	const struct drm_display_mode *adjusted_mode =
-		&crtc->config.adjusted_mode;
+		&crtc->config->base.adjusted_mode;
 	int pipe = crtc->pipe;
 	u32 temp;
 
@@ -167,7 +168,7 @@
 
 	/* set the corresponsding LVDS_BORDER bit */
 	temp &= ~LVDS_BORDER_ENABLE;
-	temp |= crtc->config.gmch_pfit.lvds_border_bits;
+	temp |= crtc->config->gmch_pfit.lvds_border_bits;
 	/* Set the B0-B3 data pairs corresponding to whether we're going to
 	 * set the DPLLs for dual-channel mode or not.
 	 */
@@ -190,7 +191,7 @@
 	if (INTEL_INFO(dev)->gen == 4) {
 		/* Bspec wording suggests that LVDS port dithering only exists
 		 * for 18bpp panels. */
-		if (crtc->config.dither && crtc->config.pipe_bpp == 18)
+		if (crtc->config->dither && crtc->config->pipe_bpp == 18)
 			temp |= LVDS_ENABLE_DITHER;
 		else
 			temp &= ~LVDS_ENABLE_DITHER;
@@ -277,14 +278,14 @@
 }
 
 static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
-				      struct intel_crtc_config *pipe_config)
+				      struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = intel_encoder->base.dev;
 	struct intel_lvds_encoder *lvds_encoder =
 		to_lvds_encoder(&intel_encoder->base);
 	struct intel_connector *intel_connector =
 		&lvds_encoder->attached_connector->base;
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
 	unsigned int lvds_bpp;
 
@@ -531,7 +532,9 @@
 	.detect = intel_lvds_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.set_property = intel_lvds_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.destroy = intel_lvds_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index dc2f4f26..f93dfc1 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -182,7 +182,7 @@
 	u32 flip_addr;
 	struct drm_i915_gem_object *reg_bo;
 	/* flip handling */
-	uint32_t last_flip_req;
+	struct drm_i915_gem_request *last_flip_req;
 	void (*flip_tail)(struct intel_overlay *);
 };
 
@@ -217,17 +217,19 @@
 	int ret;
 
 	BUG_ON(overlay->last_flip_req);
-	ret = i915_add_request(ring, &overlay->last_flip_req);
+	i915_gem_request_assign(&overlay->last_flip_req,
+					     ring->outstanding_lazy_request);
+	ret = i915_add_request(ring);
 	if (ret)
 		return ret;
 
 	overlay->flip_tail = tail;
-	ret = i915_wait_seqno(ring, overlay->last_flip_req);
+	ret = i915_wait_request(overlay->last_flip_req);
 	if (ret)
 		return ret;
 	i915_gem_retire_requests(dev);
 
-	overlay->last_flip_req = 0;
+	i915_gem_request_assign(&overlay->last_flip_req, NULL);
 	return 0;
 }
 
@@ -286,7 +288,10 @@
 	intel_ring_emit(ring, flip_addr);
 	intel_ring_advance(ring);
 
-	return i915_add_request(ring, &overlay->last_flip_req);
+	WARN_ON(overlay->last_flip_req);
+	i915_gem_request_assign(&overlay->last_flip_req,
+					     ring->outstanding_lazy_request);
+	return i915_add_request(ring);
 }
 
 static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
@@ -361,23 +366,20 @@
  * We have to be careful not to repeat work forever an make forward progess. */
 static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 {
-	struct drm_device *dev = overlay->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
 	int ret;
 
-	if (overlay->last_flip_req == 0)
+	if (overlay->last_flip_req == NULL)
 		return 0;
 
-	ret = i915_wait_seqno(ring, overlay->last_flip_req);
+	ret = i915_wait_request(overlay->last_flip_req);
 	if (ret)
 		return ret;
-	i915_gem_retire_requests(dev);
+	i915_gem_retire_requests(overlay->dev);
 
 	if (overlay->flip_tail)
 		overlay->flip_tail(overlay);
 
-	overlay->last_flip_req = 0;
+	i915_gem_request_assign(&overlay->last_flip_req, NULL);
 	return 0;
 }
 
@@ -392,6 +394,8 @@
 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
 	int ret;
 
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
 	/* Only wait if there is actually an old frame to release to
 	 * guarantee forward progress.
 	 */
@@ -422,6 +426,22 @@
 	return 0;
 }
 
+void intel_overlay_reset(struct drm_i915_private *dev_priv)
+{
+	struct intel_overlay *overlay = dev_priv->overlay;
+
+	if (!overlay)
+		return;
+
+	intel_overlay_release_old_vid(overlay);
+
+	overlay->last_flip_req = NULL;
+	overlay->old_xscale = 0;
+	overlay->old_yscale = 0;
+	overlay->crtc = NULL;
+	overlay->active = false;
+}
+
 struct put_image_params {
 	int format;
 	short dst_x;
@@ -836,7 +856,7 @@
 		return -EINVAL;
 
 	/* can't use the overlay with double wide pipe */
-	if (crtc->config.double_wide)
+	if (crtc->config->double_wide)
 		return -EINVAL;
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index dfb783a..d8686ce 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -98,13 +98,13 @@
 /* adjusted_mode has been preset to be the panel's fixed mode */
 void
 intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
-			struct intel_crtc_config *pipe_config,
+			struct intel_crtc_state *pipe_config,
 			int fitting_mode)
 {
 	struct drm_display_mode *adjusted_mode;
 	int x, y, width, height;
 
-	adjusted_mode = &pipe_config->adjusted_mode;
+	adjusted_mode = &pipe_config->base.adjusted_mode;
 
 	x = y = width = height = 0;
 
@@ -223,10 +223,10 @@
 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
 }
 
-static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
+static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
 			      u32 *pfit_control)
 {
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	u32 scaled_width = adjusted_mode->hdisplay *
 		pipe_config->pipe_src_h;
 	u32 scaled_height = pipe_config->pipe_src_w *
@@ -243,11 +243,11 @@
 		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
 }
 
-static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
+static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
 			      u32 *pfit_control, u32 *pfit_pgm_ratios,
 			      u32 *border)
 {
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	u32 scaled_width = adjusted_mode->hdisplay *
 		pipe_config->pipe_src_h;
 	u32 scaled_height = pipe_config->pipe_src_w *
@@ -301,14 +301,14 @@
 }
 
 void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
-			      struct intel_crtc_config *pipe_config,
+			      struct intel_crtc_state *pipe_config,
 			      int fitting_mode)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 	struct drm_display_mode *adjusted_mode;
 
-	adjusted_mode = &pipe_config->adjusted_mode;
+	adjusted_mode = &pipe_config->base.adjusted_mode;
 
 	/* Native modes don't need fitting */
 	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index bf814a6..24d77dd 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -52,17 +52,6 @@
 #define INTEL_RC6p_ENABLE			(1<<1)
 #define INTEL_RC6pp_ENABLE			(1<<2)
 
-/* FBC, or Frame Buffer Compression, is a technique employed to compress the
- * framebuffer contents in-memory, aiming at reducing the required bandwidth
- * during in-memory transfers and, therefore, reduce the power packet.
- *
- * The benefits of FBC are mostly visible with solid backgrounds and
- * variation-less patterns.
- *
- * FBC-related functionality can be enabled by the means of the
- * i915.i915_enable_fbc parameter
- */
-
 static void gen9_init_clock_gating(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -87,614 +76,6 @@
 		   _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
 }
 
-static void i8xx_disable_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 fbc_ctl;
-
-	dev_priv->fbc.enabled = false;
-
-	/* Disable compression */
-	fbc_ctl = I915_READ(FBC_CONTROL);
-	if ((fbc_ctl & FBC_CTL_EN) == 0)
-		return;
-
-	fbc_ctl &= ~FBC_CTL_EN;
-	I915_WRITE(FBC_CONTROL, fbc_ctl);
-
-	/* Wait for compressing bit to clear */
-	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
-		DRM_DEBUG_KMS("FBC idle timed out\n");
-		return;
-	}
-
-	DRM_DEBUG_KMS("disabled FBC\n");
-}
-
-static void i8xx_enable_fbc(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->primary->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int cfb_pitch;
-	int i;
-	u32 fbc_ctl;
-
-	dev_priv->fbc.enabled = true;
-
-	cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
-	if (fb->pitches[0] < cfb_pitch)
-		cfb_pitch = fb->pitches[0];
-
-	/* FBC_CTL wants 32B or 64B units */
-	if (IS_GEN2(dev))
-		cfb_pitch = (cfb_pitch / 32) - 1;
-	else
-		cfb_pitch = (cfb_pitch / 64) - 1;
-
-	/* Clear old tags */
-	for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
-		I915_WRITE(FBC_TAG + (i * 4), 0);
-
-	if (IS_GEN4(dev)) {
-		u32 fbc_ctl2;
-
-		/* Set it up... */
-		fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
-		fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
-		I915_WRITE(FBC_CONTROL2, fbc_ctl2);
-		I915_WRITE(FBC_FENCE_OFF, crtc->y);
-	}
-
-	/* enable it... */
-	fbc_ctl = I915_READ(FBC_CONTROL);
-	fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
-	fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
-	if (IS_I945GM(dev))
-		fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
-	fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
-	fbc_ctl |= obj->fence_reg;
-	I915_WRITE(FBC_CONTROL, fbc_ctl);
-
-	DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
-		      cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
-}
-
-static bool i8xx_fbc_enabled(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
-}
-
-static void g4x_enable_fbc(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->primary->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 dpfc_ctl;
-
-	dev_priv->fbc.enabled = true;
-
-	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
-	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
-		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
-	else
-		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
-	dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
-
-	I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
-
-	/* enable it... */
-	I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-static void g4x_disable_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 dpfc_ctl;
-
-	dev_priv->fbc.enabled = false;
-
-	/* Disable compression */
-	dpfc_ctl = I915_READ(DPFC_CONTROL);
-	if (dpfc_ctl & DPFC_CTL_EN) {
-		dpfc_ctl &= ~DPFC_CTL_EN;
-		I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-
-		DRM_DEBUG_KMS("disabled FBC\n");
-	}
-}
-
-static bool g4x_fbc_enabled(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void sandybridge_blit_fbc_update(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blt_ecoskpd;
-
-	/* Make sure blitter notifies FBC of writes */
-
-	/* Blitter is part of Media powerwell on VLV. No impact of
-	 * his param in other platforms for now */
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
-
-	blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
-	blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
-		GEN6_BLITTER_LOCK_SHIFT;
-	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-	blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
-	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-	blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
-			 GEN6_BLITTER_LOCK_SHIFT);
-	I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-	POSTING_READ(GEN6_BLITTER_ECOSKPD);
-
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
-}
-
-static void ironlake_enable_fbc(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->primary->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 dpfc_ctl;
-
-	dev_priv->fbc.enabled = true;
-
-	dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
-	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
-		dev_priv->fbc.threshold++;
-
-	switch (dev_priv->fbc.threshold) {
-	case 4:
-	case 3:
-		dpfc_ctl |= DPFC_CTL_LIMIT_4X;
-		break;
-	case 2:
-		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
-		break;
-	case 1:
-		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
-		break;
-	}
-	dpfc_ctl |= DPFC_CTL_FENCE_EN;
-	if (IS_GEN5(dev))
-		dpfc_ctl |= obj->fence_reg;
-
-	I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
-	I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
-	/* enable it... */
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-	if (IS_GEN6(dev)) {
-		I915_WRITE(SNB_DPFC_CTL_SA,
-			   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
-		I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-		sandybridge_blit_fbc_update(dev);
-	}
-
-	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-static void ironlake_disable_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 dpfc_ctl;
-
-	dev_priv->fbc.enabled = false;
-
-	/* Disable compression */
-	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-	if (dpfc_ctl & DPFC_CTL_EN) {
-		dpfc_ctl &= ~DPFC_CTL_EN;
-		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
-
-		DRM_DEBUG_KMS("disabled FBC\n");
-	}
-}
-
-static bool ironlake_fbc_enabled(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void gen7_enable_fbc(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->primary->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	u32 dpfc_ctl;
-
-	dev_priv->fbc.enabled = true;
-
-	dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
-	if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
-		dev_priv->fbc.threshold++;
-
-	switch (dev_priv->fbc.threshold) {
-	case 4:
-	case 3:
-		dpfc_ctl |= DPFC_CTL_LIMIT_4X;
-		break;
-	case 2:
-		dpfc_ctl |= DPFC_CTL_LIMIT_2X;
-		break;
-	case 1:
-		dpfc_ctl |= DPFC_CTL_LIMIT_1X;
-		break;
-	}
-
-	dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
-
-	if (dev_priv->fbc.false_color)
-		dpfc_ctl |= FBC_CTL_FALSE_COLOR;
-
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
-	if (IS_IVYBRIDGE(dev)) {
-		/* WaFbcAsynchFlipDisableFbcQueue:ivb */
-		I915_WRITE(ILK_DISPLAY_CHICKEN1,
-			   I915_READ(ILK_DISPLAY_CHICKEN1) |
-			   ILK_FBCQ_DIS);
-	} else {
-		/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
-		I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
-			   I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
-			   HSW_FBCQ_DIS);
-	}
-
-	I915_WRITE(SNB_DPFC_CTL_SA,
-		   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
-	I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-
-	sandybridge_blit_fbc_update(dev);
-
-	DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-bool intel_fbc_enabled(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	return dev_priv->fbc.enabled;
-}
-
-void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	if (!IS_GEN8(dev))
-		return;
-
-	if (!intel_fbc_enabled(dev))
-		return;
-
-	I915_WRITE(MSG_FBC_REND_STATE, value);
-}
-
-static void intel_fbc_work_fn(struct work_struct *__work)
-{
-	struct intel_fbc_work *work =
-		container_of(to_delayed_work(__work),
-			     struct intel_fbc_work, work);
-	struct drm_device *dev = work->crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	mutex_lock(&dev->struct_mutex);
-	if (work == dev_priv->fbc.fbc_work) {
-		/* Double check that we haven't switched fb without cancelling
-		 * the prior work.
-		 */
-		if (work->crtc->primary->fb == work->fb) {
-			dev_priv->display.enable_fbc(work->crtc);
-
-			dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
-			dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
-			dev_priv->fbc.y = work->crtc->y;
-		}
-
-		dev_priv->fbc.fbc_work = NULL;
-	}
-	mutex_unlock(&dev->struct_mutex);
-
-	kfree(work);
-}
-
-static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
-{
-	if (dev_priv->fbc.fbc_work == NULL)
-		return;
-
-	DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
-	/* Synchronisation is provided by struct_mutex and checking of
-	 * dev_priv->fbc.fbc_work, so we can perform the cancellation
-	 * entirely asynchronously.
-	 */
-	if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
-		/* tasklet was killed before being run, clean up */
-		kfree(dev_priv->fbc.fbc_work);
-
-	/* Mark the work as no longer wanted so that if it does
-	 * wake-up (because the work was already running and waiting
-	 * for our mutex), it will discover that is no longer
-	 * necessary to run.
-	 */
-	dev_priv->fbc.fbc_work = NULL;
-}
-
-static void intel_enable_fbc(struct drm_crtc *crtc)
-{
-	struct intel_fbc_work *work;
-	struct drm_device *dev = crtc->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	if (!dev_priv->display.enable_fbc)
-		return;
-
-	intel_cancel_fbc_work(dev_priv);
-
-	work = kzalloc(sizeof(*work), GFP_KERNEL);
-	if (work == NULL) {
-		DRM_ERROR("Failed to allocate FBC work structure\n");
-		dev_priv->display.enable_fbc(crtc);
-		return;
-	}
-
-	work->crtc = crtc;
-	work->fb = crtc->primary->fb;
-	INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
-
-	dev_priv->fbc.fbc_work = work;
-
-	/* Delay the actual enabling to let pageflipping cease and the
-	 * display to settle before starting the compression. Note that
-	 * this delay also serves a second purpose: it allows for a
-	 * vblank to pass after disabling the FBC before we attempt
-	 * to modify the control registers.
-	 *
-	 * A more complicated solution would involve tracking vblanks
-	 * following the termination of the page-flipping sequence
-	 * and indeed performing the enable as a co-routine and not
-	 * waiting synchronously upon the vblank.
-	 *
-	 * WaFbcWaitForVBlankBeforeEnable:ilk,snb
-	 */
-	schedule_delayed_work(&work->work, msecs_to_jiffies(50));
-}
-
-void intel_disable_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	intel_cancel_fbc_work(dev_priv);
-
-	if (!dev_priv->display.disable_fbc)
-		return;
-
-	dev_priv->display.disable_fbc(dev);
-	dev_priv->fbc.plane = -1;
-}
-
-static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
-			      enum no_fbc_reason reason)
-{
-	if (dev_priv->fbc.no_fbc_reason == reason)
-		return false;
-
-	dev_priv->fbc.no_fbc_reason = reason;
-	return true;
-}
-
-/**
- * intel_update_fbc - enable/disable FBC as needed
- * @dev: the drm_device
- *
- * Set up the framebuffer compression hardware at mode set time.  We
- * enable it if possible:
- *   - plane A only (on pre-965)
- *   - no pixel mulitply/line duplication
- *   - no alpha buffer discard
- *   - no dual wide
- *   - framebuffer <= max_hdisplay in width, max_vdisplay in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one.  It also must reside (along with the line length buffer) in
- * stolen memory.
- *
- * We need to enable/disable FBC on a global basis.
- */
-void intel_update_fbc(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc = NULL, *tmp_crtc;
-	struct intel_crtc *intel_crtc;
-	struct drm_framebuffer *fb;
-	struct drm_i915_gem_object *obj;
-	const struct drm_display_mode *adjusted_mode;
-	unsigned int max_width, max_height;
-
-	if (!HAS_FBC(dev)) {
-		set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
-		return;
-	}
-
-	if (!i915.powersave) {
-		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
-			DRM_DEBUG_KMS("fbc disabled per module param\n");
-		return;
-	}
-
-	/*
-	 * If FBC is already on, we just have to verify that we can
-	 * keep it that way...
-	 * Need to disable if:
-	 *   - more than one pipe is active
-	 *   - changing FBC params (stride, fence, mode)
-	 *   - new fb is too large to fit in compressed buffer
-	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
-	 */
-	for_each_crtc(dev, tmp_crtc) {
-		if (intel_crtc_active(tmp_crtc) &&
-		    to_intel_crtc(tmp_crtc)->primary_enabled) {
-			if (crtc) {
-				if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
-					DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-				goto out_disable;
-			}
-			crtc = tmp_crtc;
-		}
-	}
-
-	if (!crtc || crtc->primary->fb == NULL) {
-		if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
-			DRM_DEBUG_KMS("no output, disabling\n");
-		goto out_disable;
-	}
-
-	intel_crtc = to_intel_crtc(crtc);
-	fb = crtc->primary->fb;
-	obj = intel_fb_obj(fb);
-	adjusted_mode = &intel_crtc->config.adjusted_mode;
-
-	if (i915.enable_fbc < 0) {
-		if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
-			DRM_DEBUG_KMS("disabled per chip default\n");
-		goto out_disable;
-	}
-	if (!i915.enable_fbc) {
-		if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
-			DRM_DEBUG_KMS("fbc disabled per module param\n");
-		goto out_disable;
-	}
-	if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
-	    (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
-		if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
-			DRM_DEBUG_KMS("mode incompatible with compression, "
-				      "disabling\n");
-		goto out_disable;
-	}
-
-	if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
-		max_width = 4096;
-		max_height = 4096;
-	} else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
-		max_width = 4096;
-		max_height = 2048;
-	} else {
-		max_width = 2048;
-		max_height = 1536;
-	}
-	if (intel_crtc->config.pipe_src_w > max_width ||
-	    intel_crtc->config.pipe_src_h > max_height) {
-		if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
-			DRM_DEBUG_KMS("mode too large for compression, disabling\n");
-		goto out_disable;
-	}
-	if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
-	    intel_crtc->plane != PLANE_A) {
-		if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
-			DRM_DEBUG_KMS("plane not A, disabling compression\n");
-		goto out_disable;
-	}
-
-	/* The use of a CPU fence is mandatory in order to detect writes
-	 * by the CPU to the scanout and trigger updates to the FBC.
-	 */
-	if (obj->tiling_mode != I915_TILING_X ||
-	    obj->fence_reg == I915_FENCE_REG_NONE) {
-		if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
-			DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
-		goto out_disable;
-	}
-	if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
-	    to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
-		if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
-			DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
-		goto out_disable;
-	}
-
-	/* If the kernel debugger is active, always disable compression */
-	if (in_dbg_master())
-		goto out_disable;
-
-	if (i915_gem_stolen_setup_compression(dev, obj->base.size,
-					      drm_format_plane_cpp(fb->pixel_format, 0))) {
-		if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
-			DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
-		goto out_disable;
-	}
-
-	/* If the scanout has not changed, don't modify the FBC settings.
-	 * Note that we make the fundamental assumption that the fb->obj
-	 * cannot be unpinned (and have its GTT offset and fence revoked)
-	 * without first being decoupled from the scanout and FBC disabled.
-	 */
-	if (dev_priv->fbc.plane == intel_crtc->plane &&
-	    dev_priv->fbc.fb_id == fb->base.id &&
-	    dev_priv->fbc.y == crtc->y)
-		return;
-
-	if (intel_fbc_enabled(dev)) {
-		/* We update FBC along two paths, after changing fb/crtc
-		 * configuration (modeswitching) and after page-flipping
-		 * finishes. For the latter, we know that not only did
-		 * we disable the FBC at the start of the page-flip
-		 * sequence, but also more than one vblank has passed.
-		 *
-		 * For the former case of modeswitching, it is possible
-		 * to switch between two FBC valid configurations
-		 * instantaneously so we do need to disable the FBC
-		 * before we can modify its control registers. We also
-		 * have to wait for the next vblank for that to take
-		 * effect. However, since we delay enabling FBC we can
-		 * assume that a vblank has passed since disabling and
-		 * that we can safely alter the registers in the deferred
-		 * callback.
-		 *
-		 * In the scenario that we go from a valid to invalid
-		 * and then back to valid FBC configuration we have
-		 * no strict enforcement that a vblank occurred since
-		 * disabling the FBC. However, along all current pipe
-		 * disabling paths we do need to wait for a vblank at
-		 * some point. And we wait before enabling FBC anyway.
-		 */
-		DRM_DEBUG_KMS("disabling active FBC for update\n");
-		intel_disable_fbc(dev);
-	}
-
-	intel_enable_fbc(crtc);
-	dev_priv->fbc.no_fbc_reason = FBC_OK;
-	return;
-
-out_disable:
-	/* Multiple disables should be harmless */
-	if (intel_fbc_enabled(dev)) {
-		DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
-		intel_disable_fbc(dev);
-	}
-	i915_gem_stolen_cleanup_compression(dev);
-}
-
 static void i915_pineview_get_mem_freq(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1157,7 +538,7 @@
 		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 		int clock;
 
-		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+		adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 		clock = adjusted_mode->crtc_clock;
 
 		/* Display SR */
@@ -1226,10 +607,10 @@
 		return false;
 	}
 
-	adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+	adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 	clock = adjusted_mode->crtc_clock;
 	htotal = adjusted_mode->crtc_htotal;
-	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+	hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
 	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
 	/* Use the small buffer method to calculate plane watermark */
@@ -1313,10 +694,10 @@
 	}
 
 	crtc = intel_get_crtc_for_plane(dev, plane);
-	adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+	adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 	clock = adjusted_mode->crtc_clock;
 	htotal = adjusted_mode->crtc_htotal;
-	hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+	hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
 	pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
 	line_time_us = max(htotal * 1000 / clock, 1);
@@ -1347,7 +728,7 @@
 {
 	struct drm_device *dev = crtc->dev;
 	int entries;
-	int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
+	int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
 
 	if (WARN(clock == 0, "Pixel clock is zero!\n"))
 		return false;
@@ -1677,10 +1058,10 @@
 		/* self-refresh has much higher latency */
 		static const int sr_latency_ns = 12000;
 		const struct drm_display_mode *adjusted_mode =
-			&to_intel_crtc(crtc)->config.adjusted_mode;
+			&to_intel_crtc(crtc)->config->base.adjusted_mode;
 		int clock = adjusted_mode->crtc_clock;
 		int htotal = adjusted_mode->crtc_htotal;
-		int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+		int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
 		int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 		unsigned long line_time_us;
 		int entries;
@@ -1762,7 +1143,7 @@
 		if (IS_GEN2(dev))
 			cpp = 4;
 
-		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+		adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 		planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
 					       wm_info, fifo_size, cpp,
 					       pessimal_latency_ns);
@@ -1784,7 +1165,7 @@
 		if (IS_GEN2(dev))
 			cpp = 4;
 
-		adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+		adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 		planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
 					       wm_info, fifo_size, cpp,
 					       pessimal_latency_ns);
@@ -1823,10 +1204,10 @@
 		/* self-refresh has much higher latency */
 		static const int sr_latency_ns = 6000;
 		const struct drm_display_mode *adjusted_mode =
-			&to_intel_crtc(enabled)->config.adjusted_mode;
+			&to_intel_crtc(enabled)->config->base.adjusted_mode;
 		int clock = adjusted_mode->crtc_clock;
 		int htotal = adjusted_mode->crtc_htotal;
-		int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
+		int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w;
 		int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
 		unsigned long line_time_us;
 		int entries;
@@ -1879,7 +1260,7 @@
 	if (crtc == NULL)
 		return;
 
-	adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+	adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
 	planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
 				       &i845_wm_info,
 				       dev_priv->display.get_fifo_size(dev, 0),
@@ -1898,17 +1279,17 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	uint32_t pixel_rate;
 
-	pixel_rate = intel_crtc->config.adjusted_mode.crtc_clock;
+	pixel_rate = intel_crtc->config->base.adjusted_mode.crtc_clock;
 
 	/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
 	 * adjust the pixel_rate here. */
 
-	if (intel_crtc->config.pch_pfit.enabled) {
+	if (intel_crtc->config->pch_pfit.enabled) {
 		uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
-		uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
+		uint32_t pfit_size = intel_crtc->config->pch_pfit.size;
 
-		pipe_w = intel_crtc->config.pipe_src_w;
-		pipe_h = intel_crtc->config.pipe_src_h;
+		pipe_w = intel_crtc->config->pipe_src_w;
+		pipe_h = intel_crtc->config->pipe_src_h;
 		pfit_w = (pfit_size >> 16) & 0xFFFF;
 		pfit_h = pfit_size & 0xFFFF;
 		if (pipe_w < pfit_w)
@@ -2261,7 +1642,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+	struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
 	u32 linetime, ips_linetime;
 
 	if (!intel_crtc_active(crtc))
@@ -2521,11 +1902,11 @@
 		return;
 
 	p->active = true;
-	p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
+	p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
 	p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
 	p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
 	p->cur.bytes_per_pixel = 4;
-	p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
+	p->pri.horiz_pixels = intel_crtc->config->pipe_src_w;
 	p->cur.horiz_pixels = intel_crtc->cursor_width;
 	/* TODO: for now, assume primary and cursor planes are always enabled. */
 	p->pri.enabled = true;
@@ -3174,10 +2555,10 @@
 
 }
 
-static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config)
+static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_state *config)
 {
 	/* TODO: Take into account the scalers once we support them */
-	return config->adjusted_mode.crtc_clock;
+	return config->base.adjusted_mode.crtc_clock;
 }
 
 /*
@@ -3265,8 +2646,8 @@
 
 	p->active = intel_crtc_active(crtc);
 	if (p->active) {
-		p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
-		p->pixel_rate = skl_pipe_pixel_rate(&intel_crtc->config);
+		p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
+		p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
 
 		/*
 		 * For now, assume primary and cursor planes are always enabled.
@@ -3274,8 +2655,8 @@
 		p->plane[0].enabled = true;
 		p->plane[0].bytes_per_pixel =
 			crtc->primary->fb->bits_per_pixel / 8;
-		p->plane[0].horiz_pixels = intel_crtc->config.pipe_src_w;
-		p->plane[0].vert_pixels = intel_crtc->config.pipe_src_h;
+		p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
+		p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
 
 		p->cursor.enabled = true;
 		p->cursor.bytes_per_pixel = 4;
@@ -3286,7 +2667,8 @@
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
 		struct intel_plane *intel_plane = to_intel_plane(plane);
 
-		if (intel_plane->pipe == pipe)
+		if (intel_plane->pipe == pipe &&
+			plane->type == DRM_PLANE_TYPE_OVERLAY)
 			p->plane[i++] = intel_plane->wm;
 	}
 }
@@ -3621,9 +3003,8 @@
 		    skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
 			skl_wm_flush_pipe(dev_priv, pipe, 2);
 			intel_wait_for_vblank(dev, pipe);
+			reallocated[pipe] = true;
 		}
-
-		reallocated[pipe] = true;
 	}
 
 	/*
@@ -4418,8 +3799,8 @@
 {
 	struct drm_device *dev = dev_priv->dev;
 
-	/* Latest VLV doesn't need to force the gfx clock */
-	if (dev->pdev->revision >= 0xd) {
+	/* CHV and latest VLV don't need to force the gfx clock */
+	if (IS_CHERRYVIEW(dev) || dev->pdev->revision >= 0xd) {
 		valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
 		return;
 	}
@@ -4458,9 +3839,7 @@
 
 	mutex_lock(&dev_priv->rps.hw_lock);
 	if (dev_priv->rps.enabled) {
-		if (IS_CHERRYVIEW(dev))
-			valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
-		else if (IS_VALLEYVIEW(dev))
+		if (IS_VALLEYVIEW(dev))
 			vlv_set_rps_idle(dev_priv);
 		else
 			gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
@@ -4502,7 +3881,7 @@
 	I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 
 	dev_priv->rps.cur_freq = val;
-	trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
+	trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
 }
 
 static void gen9_disable_rps(struct drm_device *dev)
@@ -4510,6 +3889,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
+	I915_WRITE(GEN9_PG_ENABLE, 0);
 }
 
 static void gen6_disable_rps(struct drm_device *dev)
@@ -4533,11 +3913,11 @@
 
 	/* we're doing forcewake before Disabling RC6,
 	 * This what the BIOS expects when going into suspend */
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	I915_WRITE(GEN6_RC_CONTROL, 0);
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
@@ -4625,7 +4005,10 @@
 					&ddcc_status);
 		if (0 == ret)
 			dev_priv->rps.efficient_freq =
-				(ddcc_status >> 8) & 0xff;
+				clamp_t(u8,
+					((ddcc_status >> 8) & 0xff),
+					dev_priv->rps.min_freq,
+					dev_priv->rps.max_freq);
 	}
 
 	/* Preserve min/max settings in case of re-init */
@@ -4643,9 +4026,39 @@
 	}
 }
 
+/* See the Gen9_GT_PM_Programming_Guide doc for the below */
 static void gen9_enable_rps(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+	gen6_init_rps_frequencies(dev);
+
+	I915_WRITE(GEN6_RPNSWREQ, 0xc800000);
+	I915_WRITE(GEN6_RC_VIDEO_FREQ, 0xc800000);
+
+	I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 0xf4240);
+	I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, 0x12060000);
+	I915_WRITE(GEN6_RP_UP_THRESHOLD, 0xe808);
+	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 0x3bd08);
+	I915_WRITE(GEN6_RP_UP_EI, 0x101d0);
+	I915_WRITE(GEN6_RP_DOWN_EI, 0x55730);
+	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 0xa);
+	I915_WRITE(GEN6_PMINTRMSK, 0x6);
+	I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO |
+		   GEN6_RP_MEDIA_HW_MODE | GEN6_RP_MEDIA_IS_GFX |
+		   GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG |
+		   GEN6_RP_DOWN_IDLE_AVG);
+
+	gen6_enable_rps_interrupts(dev);
+
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+}
+
+static void gen9_enable_rc6(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_engine_cs *ring;
 	uint32_t rc6_mask = 0;
 	int unused;
@@ -4655,7 +4068,7 @@
 
 	/* 1b: Get forcewake during program sequence. Although the driver
 	 * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	/* 2a: Disable RC states. */
 	I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -4669,6 +4082,10 @@
 	I915_WRITE(GEN6_RC_SLEEP, 0);
 	I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
 
+	/* 2c: Program Coarse Power Gating Policies. */
+	I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25);
+	I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25);
+
 	/* 3a: Enable RC6 */
 	if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
 		rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
@@ -4678,7 +4095,10 @@
 				   GEN6_RC_CTL_EI_MODE(1) |
 				   rc6_mask);
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	/* 3b: Enable Coarse Power Gating only when RC6 is enabled */
+	I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? 3 : 0);
+
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
 }
 
@@ -4694,7 +4114,7 @@
 
 	/* 1c & 1d: Get forcewake during program sequence. Although the driver
 	 * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	/* 2a: Disable RC states. */
 	I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -4761,7 +4181,7 @@
 	dev_priv->rps.power = HIGH_POWER; /* force a reset */
 	gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static void gen6_enable_rps(struct drm_device *dev)
@@ -4789,7 +4209,7 @@
 		I915_WRITE(GTFIFODBG, gtfifodbg);
 	}
 
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	/* Initialize rps frequencies */
 	gen6_init_rps_frequencies(dev);
@@ -4869,7 +4289,7 @@
 			DRM_ERROR("Couldn't fix incorrect rc6 voltage\n");
 	}
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static void __gen6_update_ring_freq(struct drm_device *dev)
@@ -4956,11 +4376,35 @@
 
 static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv)
 {
+	struct drm_device *dev = dev_priv->dev;
 	u32 val, rp0;
 
-	val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
-	rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & PUNIT_GPU_STATUS_MAX_FREQ_MASK;
+	if (dev->pdev->revision >= 0x20) {
+		val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
 
+		switch (INTEL_INFO(dev)->eu_total) {
+		case 8:
+				/* (2 * 4) config */
+				rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
+				break;
+		case 12:
+				/* (2 * 6) config */
+				rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT);
+				break;
+		case 16:
+				/* (2 * 8) config */
+		default:
+				/* Setting (2 * 8) Min RP0 for any other combination */
+				rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT);
+				break;
+		}
+		rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK);
+	} else {
+		/* For pre-production hardware */
+		val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
+		rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
+		       PUNIT_GPU_STATUS_MAX_FREQ_MASK;
+	}
 	return rp0;
 }
 
@@ -4976,20 +4420,36 @@
 
 static int cherryview_rps_guar_freq(struct drm_i915_private *dev_priv)
 {
+	struct drm_device *dev = dev_priv->dev;
 	u32 val, rp1;
 
-	val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
-	rp1 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & PUNIT_GPU_STATUS_MAX_FREQ_MASK;
-
+	if (dev->pdev->revision >= 0x20) {
+		val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
+		rp1 = (val & FB_GFX_FREQ_FUSE_MASK);
+	} else {
+		/* For pre-production hardware */
+		val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+		rp1 = ((val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
+		       PUNIT_GPU_STATUS_MAX_FREQ_MASK);
+	}
 	return rp1;
 }
 
 static int cherryview_rps_min_freq(struct drm_i915_private *dev_priv)
 {
+	struct drm_device *dev = dev_priv->dev;
 	u32 val, rpn;
 
-	val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
-	rpn = (val >> PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT) & PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK;
+	if (dev->pdev->revision >= 0x20) {
+		val = vlv_punit_read(dev_priv, FB_GFX_FMIN_AT_VMIN_FUSE);
+		rpn = ((val >> FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT) &
+		       FB_GFX_FREQ_FUSE_MASK);
+	} else { /* For pre-production hardware */
+		val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
+		rpn = ((val >> PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT) &
+		       PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK);
+	}
+
 	return rpn;
 }
 
@@ -5160,22 +4620,22 @@
 	dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
 	dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
 	DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
 			 dev_priv->rps.max_freq);
 
 	dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
 	DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 			 dev_priv->rps.efficient_freq);
 
 	dev_priv->rps.rp1_freq = valleyview_rps_guar_freq(dev_priv);
 	DRM_DEBUG_DRIVER("RP1(Guar Freq) GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
 			 dev_priv->rps.rp1_freq);
 
 	dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
 	DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
 			 dev_priv->rps.min_freq);
 
 	/* Preserve min/max settings in case of re-init */
@@ -5229,22 +4689,22 @@
 	dev_priv->rps.max_freq = cherryview_rps_max_freq(dev_priv);
 	dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
 	DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
 			 dev_priv->rps.max_freq);
 
 	dev_priv->rps.efficient_freq = cherryview_rps_rpe_freq(dev_priv);
 	DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 			 dev_priv->rps.efficient_freq);
 
 	dev_priv->rps.rp1_freq = cherryview_rps_guar_freq(dev_priv);
 	DRM_DEBUG_DRIVER("RP1(Guar) GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
 			 dev_priv->rps.rp1_freq);
 
 	dev_priv->rps.min_freq = cherryview_rps_min_freq(dev_priv);
 	DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
 			 dev_priv->rps.min_freq);
 
 	WARN_ONCE((dev_priv->rps.max_freq |
@@ -5288,7 +4748,10 @@
 
 	/* 1a & 1b: Get forcewake during program sequence. Although the driver
 	 * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+	/*  Disable RC states. */
+	I915_WRITE(GEN6_RC_CONTROL, 0);
 
 	/* 2a: Program RC6 thresholds.*/
 	I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
@@ -5299,7 +4762,8 @@
 		I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
 	I915_WRITE(GEN6_RC_SLEEP, 0);
 
-	I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
+	/* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
+	I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
 
 	/* allows RC6 residency counter to work */
 	I915_WRITE(VLV_COUNTER_CONTROL,
@@ -5313,11 +4777,12 @@
 	/* 3: Enable RC6 */
 	if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) &&
 						(pcbr >> VLV_PCBR_ADDR_SHIFT))
-		rc6_mode = GEN6_RC_CTL_EI_MODE(1);
+		rc6_mode = GEN7_RC_CTL_TO_MODE;
 
 	I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
 
 	/* 4 Program defaults and thresholds for RPS*/
+	I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
 	I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
 	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
 	I915_WRITE(GEN6_RP_UP_EI, 66000);
@@ -5325,14 +4790,10 @@
 
 	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 
-	/* WaDisablePwrmtrEvent:chv (pre-production hw) */
-	I915_WRITE(0xA80C, I915_READ(0xA80C) & 0x00ffffff);
-	I915_WRITE(0xA810, I915_READ(0xA810) & 0xffffff00);
-
 	/* 5: Enable RPS */
 	I915_WRITE(GEN6_RP_CONTROL,
 		   GEN6_RP_MEDIA_HW_NORMAL_MODE |
-		   GEN6_RP_MEDIA_IS_GFX | /* WaSetMaskForGfxBusyness:chv (pre-production hw ?) */
+		   GEN6_RP_MEDIA_IS_GFX |
 		   GEN6_RP_ENABLE |
 		   GEN6_RP_UP_BUSY_AVG |
 		   GEN6_RP_DOWN_IDLE_AVG);
@@ -5347,16 +4808,16 @@
 
 	dev_priv->rps.cur_freq = (val >> 8) & 0xff;
 	DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
 			 dev_priv->rps.cur_freq);
 
 	DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 			 dev_priv->rps.efficient_freq);
 
 	valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static void valleyview_enable_rps(struct drm_device *dev)
@@ -5377,15 +4838,18 @@
 	}
 
 	/* If VLV, Forcewake all wells, else re-direct to regular path */
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
+	/*  Disable RC states. */
+	I915_WRITE(GEN6_RC_CONTROL, 0);
+
+	I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
 	I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
 	I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
 	I915_WRITE(GEN6_RP_UP_EI, 66000);
 	I915_WRITE(GEN6_RP_DOWN_EI, 350000);
 
 	I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
-	I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 0xf4240);
 
 	I915_WRITE(GEN6_RP_CONTROL,
 		   GEN6_RP_MEDIA_TURBO |
@@ -5428,16 +4892,16 @@
 
 	dev_priv->rps.cur_freq = (val >> 8) & 0xff;
 	DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
 			 dev_priv->rps.cur_freq);
 
 	DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-			 vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+			 intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 			 dev_priv->rps.efficient_freq);
 
 	valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 void ironlake_teardown_rc6(struct drm_device *dev)
@@ -5673,146 +5137,27 @@
 	return ((m * x) / 127) - b;
 }
 
-static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
+static int _pxvid_to_vd(u8 pxvid)
+{
+	if (pxvid == 0)
+		return 0;
+
+	if (pxvid >= 8 && pxvid < 31)
+		pxvid = 31;
+
+	return (pxvid + 2) * 125;
+}
+
+static u32 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
 {
 	struct drm_device *dev = dev_priv->dev;
-	static const struct v_table {
-		u16 vd; /* in .1 mil */
-		u16 vm; /* in .1 mil */
-	} v_table[] = {
-		{ 0, 0, },
-		{ 375, 0, },
-		{ 500, 0, },
-		{ 625, 0, },
-		{ 750, 0, },
-		{ 875, 0, },
-		{ 1000, 0, },
-		{ 1125, 0, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4125, 3000, },
-		{ 4250, 3125, },
-		{ 4375, 3250, },
-		{ 4500, 3375, },
-		{ 4625, 3500, },
-		{ 4750, 3625, },
-		{ 4875, 3750, },
-		{ 5000, 3875, },
-		{ 5125, 4000, },
-		{ 5250, 4125, },
-		{ 5375, 4250, },
-		{ 5500, 4375, },
-		{ 5625, 4500, },
-		{ 5750, 4625, },
-		{ 5875, 4750, },
-		{ 6000, 4875, },
-		{ 6125, 5000, },
-		{ 6250, 5125, },
-		{ 6375, 5250, },
-		{ 6500, 5375, },
-		{ 6625, 5500, },
-		{ 6750, 5625, },
-		{ 6875, 5750, },
-		{ 7000, 5875, },
-		{ 7125, 6000, },
-		{ 7250, 6125, },
-		{ 7375, 6250, },
-		{ 7500, 6375, },
-		{ 7625, 6500, },
-		{ 7750, 6625, },
-		{ 7875, 6750, },
-		{ 8000, 6875, },
-		{ 8125, 7000, },
-		{ 8250, 7125, },
-		{ 8375, 7250, },
-		{ 8500, 7375, },
-		{ 8625, 7500, },
-		{ 8750, 7625, },
-		{ 8875, 7750, },
-		{ 9000, 7875, },
-		{ 9125, 8000, },
-		{ 9250, 8125, },
-		{ 9375, 8250, },
-		{ 9500, 8375, },
-		{ 9625, 8500, },
-		{ 9750, 8625, },
-		{ 9875, 8750, },
-		{ 10000, 8875, },
-		{ 10125, 9000, },
-		{ 10250, 9125, },
-		{ 10375, 9250, },
-		{ 10500, 9375, },
-		{ 10625, 9500, },
-		{ 10750, 9625, },
-		{ 10875, 9750, },
-		{ 11000, 9875, },
-		{ 11125, 10000, },
-		{ 11250, 10125, },
-		{ 11375, 10250, },
-		{ 11500, 10375, },
-		{ 11625, 10500, },
-		{ 11750, 10625, },
-		{ 11875, 10750, },
-		{ 12000, 10875, },
-		{ 12125, 11000, },
-		{ 12250, 11125, },
-		{ 12375, 11250, },
-		{ 12500, 11375, },
-		{ 12625, 11500, },
-		{ 12750, 11625, },
-		{ 12875, 11750, },
-		{ 13000, 11875, },
-		{ 13125, 12000, },
-		{ 13250, 12125, },
-		{ 13375, 12250, },
-		{ 13500, 12375, },
-		{ 13625, 12500, },
-		{ 13750, 12625, },
-		{ 13875, 12750, },
-		{ 14000, 12875, },
-		{ 14125, 13000, },
-		{ 14250, 13125, },
-		{ 14375, 13250, },
-		{ 14500, 13375, },
-		{ 14625, 13500, },
-		{ 14750, 13625, },
-		{ 14875, 13750, },
-		{ 15000, 13875, },
-		{ 15125, 14000, },
-		{ 15250, 14125, },
-		{ 15375, 14250, },
-		{ 15500, 14375, },
-		{ 15625, 14500, },
-		{ 15750, 14625, },
-		{ 15875, 14750, },
-		{ 16000, 14875, },
-		{ 16125, 15000, },
-	};
+	const int vd = _pxvid_to_vd(pxvid);
+	const int vm = vd - 1125;
+
 	if (INTEL_INFO(dev)->is_mobile)
-		return v_table[pxvid].vm;
-	else
-		return v_table[pxvid].vd;
+		return vm > 0 ? vm : 0;
+
+	return vd;
 }
 
 static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
@@ -6264,7 +5609,9 @@
 	} else if (IS_VALLEYVIEW(dev)) {
 		valleyview_enable_rps(dev);
 	} else if (INTEL_INFO(dev)->gen >= 9) {
+		gen9_enable_rc6(dev);
 		gen9_enable_rps(dev);
+		__gen6_update_ring_freq(dev);
 	} else if (IS_BROADWELL(dev)) {
 		gen8_enable_rps(dev);
 		__gen6_update_ring_freq(dev);
@@ -6710,6 +6057,10 @@
 	I915_WRITE(GEN7_GT_MODE,
 		   _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
 
+	/* WaSampleCChickenBitEnable:hsw */
+	I915_WRITE(HALF_SLICE_CHICKEN3,
+		   _MASKED_BIT_ENABLE(HSW_SAMPLE_C_PERFORMANCE));
+
 	/* WaSwitchSolVfFArbitrationPriority:hsw */
 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
@@ -6880,6 +6231,17 @@
 		   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 
 	/*
+	 * BSpec recommends 8x4 when MSAA is used,
+	 * however in practice 16x4 seems fastest.
+	 *
+	 * Note that PS/WM thread counts depend on the WIZ hashing
+	 * disable bit, which we don't touch here, but it's good
+	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+	 */
+	I915_WRITE(GEN7_GT_MODE,
+		   _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
+
+	/*
 	 * WaIncreaseL3CreditsForVLVB0:vlv
 	 * This is the hardware default actually.
 	 */
@@ -7043,43 +6405,12 @@
 		lpt_suspend_hw(dev);
 }
 
-static void intel_init_fbc(struct drm_i915_private *dev_priv)
-{
-	if (!HAS_FBC(dev_priv)) {
-		dev_priv->fbc.enabled = false;
-		return;
-	}
-
-	if (INTEL_INFO(dev_priv)->gen >= 7) {
-		dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
-		dev_priv->display.enable_fbc = gen7_enable_fbc;
-		dev_priv->display.disable_fbc = ironlake_disable_fbc;
-	} else if (INTEL_INFO(dev_priv)->gen >= 5) {
-		dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
-		dev_priv->display.enable_fbc = ironlake_enable_fbc;
-		dev_priv->display.disable_fbc = ironlake_disable_fbc;
-	} else if (IS_GM45(dev_priv)) {
-		dev_priv->display.fbc_enabled = g4x_fbc_enabled;
-		dev_priv->display.enable_fbc = g4x_enable_fbc;
-		dev_priv->display.disable_fbc = g4x_disable_fbc;
-	} else {
-		dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
-		dev_priv->display.enable_fbc = i8xx_enable_fbc;
-		dev_priv->display.disable_fbc = i8xx_disable_fbc;
-
-		/* This value was pulled out of someone's hat */
-		I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
-	}
-
-	dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
-}
-
 /* Set up chip specific power management-related functions */
 void intel_init_pm(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	intel_init_fbc(dev_priv);
+	intel_fbc_init(dev_priv);
 
 	/* For cxsr */
 	if (IS_PINEVIEW(dev))
@@ -7285,28 +6616,24 @@
 	return DIV_ROUND_CLOSEST(val * 2 * mul, czclk_freq) * 2;
 }
 
-int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val)
+int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
 {
-	int ret = -1;
-
 	if (IS_CHERRYVIEW(dev_priv->dev))
-		ret = chv_gpu_freq(dev_priv, val);
+		return chv_gpu_freq(dev_priv, val);
 	else if (IS_VALLEYVIEW(dev_priv->dev))
-		ret = byt_gpu_freq(dev_priv, val);
-
-	return ret;
+		return byt_gpu_freq(dev_priv, val);
+	else
+		return val * GT_FREQUENCY_MULTIPLIER;
 }
 
-int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val)
+int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
 {
-	int ret = -1;
-
 	if (IS_CHERRYVIEW(dev_priv->dev))
-		ret = chv_freq_opcode(dev_priv, val);
+		return chv_freq_opcode(dev_priv, val);
 	else if (IS_VALLEYVIEW(dev_priv->dev))
-		ret = byt_freq_opcode(dev_priv, val);
-
-	return ret;
+		return byt_freq_opcode(dev_priv, val);
+	else
+		return val / GT_FREQUENCY_MULTIPLIER;
 }
 
 void intel_pm_setup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 716b8a9..b9f40c2 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -61,14 +61,15 @@
 	return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
 }
 
-bool intel_psr_is_enabled(struct drm_device *dev)
+static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t val;
 
-	if (!HAS_PSR(dev))
-		return false;
-
-	return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+	val = I915_READ(VLV_PSRSTAT(pipe)) &
+	      VLV_EDP_PSR_CURR_STATE_MASK;
+	return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+	       (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
 }
 
 static void intel_psr_write_vsc(struct intel_dp *intel_dp,
@@ -78,8 +79,8 @@
 	struct drm_device *dev = dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
-	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
-	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
+	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder);
+	u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config->cpu_transcoder);
 	uint32_t *data = (uint32_t *) vsc_psr;
 	unsigned int i;
 
@@ -100,7 +101,23 @@
 	POSTING_READ(ctl_reg);
 }
 
-static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
+static void vlv_psr_setup_vsc(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	uint32_t val;
+
+	/* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */
+	val  = I915_READ(VLV_VSCSDP(pipe));
+	val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+	val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+	I915_WRITE(VLV_VSCSDP(pipe), val);
+}
+
+static void hsw_psr_setup_vsc(struct intel_dp *intel_dp)
 {
 	struct edp_vsc_psr psr_vsc;
 
@@ -113,14 +130,20 @@
 	intel_psr_write_vsc(intel_dp, &psr_vsc);
 }
 
-static void intel_psr_enable_sink(struct intel_dp *intel_dp)
+static void vlv_psr_enable_sink(struct intel_dp *intel_dp)
+{
+	drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
+			   DP_PSR_ENABLE);
+}
+
+static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t aux_clock_divider;
+	uint32_t aux_data_reg, aux_ctl_reg;
 	int precharge = 0x3;
-	bool only_standby = false;
 	static const uint8_t aux_msg[] = {
 		[0] = DP_AUX_NATIVE_WRITE << 4,
 		[1] = DP_SET_POWER >> 8,
@@ -134,49 +157,96 @@
 
 	aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
 
-	if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
-		only_standby = true;
-
 	/* Enable PSR in sink */
-	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby)
-		drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
-				   DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
-	else
+	if (dev_priv->psr.link_standby)
 		drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
 				   DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
+	else
+		drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
+				   DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
+
+	aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ?
+				DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev);
+	aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ?
+				DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev);
 
 	/* Setup AUX registers */
 	for (i = 0; i < sizeof(aux_msg); i += 4)
-		I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
+		I915_WRITE(aux_data_reg + i,
 			   intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
 
-	I915_WRITE(EDP_PSR_AUX_CTL(dev),
+	if (INTEL_INFO(dev)->gen >= 9) {
+		uint32_t val;
+
+		val = I915_READ(aux_ctl_reg);
+		val &= ~DP_AUX_CH_CTL_TIME_OUT_MASK;
+		val |= DP_AUX_CH_CTL_TIME_OUT_1600us;
+		val &= ~DP_AUX_CH_CTL_MESSAGE_SIZE_MASK;
+		val |= (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+		/* Use hardcoded data values for PSR */
+		val &= ~DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL;
+		I915_WRITE(aux_ctl_reg, val);
+	} else {
+		I915_WRITE(aux_ctl_reg,
 		   DP_AUX_CH_CTL_TIME_OUT_400us |
 		   (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
 		   (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
 		   (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+	}
 }
 
-static void intel_psr_enable_source(struct intel_dp *intel_dp)
+static void vlv_psr_enable_source(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dig_port->base.base.crtc;
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+
+	/* Transition from PSR_state 0 to PSR_state 1, i.e. PSR Inactive */
+	I915_WRITE(VLV_PSRCTL(pipe),
+		   VLV_EDP_PSR_MODE_SW_TIMER |
+		   VLV_EDP_PSR_SRC_TRANSMITTER_STATE |
+		   VLV_EDP_PSR_ENABLE);
+}
+
+static void vlv_psr_activate(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dig_port->base.base.crtc;
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+
+	/* Let's do the transition from PSR_state 1 to PSR_state 2
+	 * that is PSR transition to active - static frame transmission.
+	 * Then Hardware is responsible for the transition to PSR_state 3
+	 * that is PSR active - no Remote Frame Buffer (RFB) update.
+	 */
+	I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) |
+		   VLV_EDP_PSR_ACTIVE_ENTRY);
+}
+
+static void hsw_psr_enable_source(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t max_sleep_time = 0x1f;
-	uint32_t idle_frames = 1;
+	/* Lately it was identified that depending on panel idle frame count
+	 * calculated at HW can be off by 1. So let's use what came
+	 * from VBT + 1 and at minimum 2 to be on the safe side.
+	 */
+	uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ?
+			       dev_priv->vbt.psr.idle_frames + 1 : 2;
 	uint32_t val = 0x0;
 	const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
-	bool only_standby = false;
 
-	if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
-		only_standby = true;
-
-	if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) {
+	if (dev_priv->psr.link_standby) {
 		val |= EDP_PSR_LINK_STANDBY;
 		val |= EDP_PSR_TP2_TP3_TIME_0us;
 		val |= EDP_PSR_TP1_TIME_0us;
 		val |= EDP_PSR_SKIP_AUX_EXIT;
-		val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0;
 	} else
 		val |= EDP_PSR_LINK_DISABLE;
 
@@ -211,27 +281,24 @@
 		return false;
 	}
 
-	/* Below limitations aren't valid for Broadwell */
-	if (IS_BROADWELL(dev))
-		goto out;
-
-	if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
-	    S3D_ENABLE) {
+	if (IS_HASWELL(dev) &&
+	    I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config->cpu_transcoder)) &
+		      S3D_ENABLE) {
 		DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
 		return false;
 	}
 
-	if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+	if (IS_HASWELL(dev) &&
+	    intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
 		DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
 		return false;
 	}
 
- out:
 	dev_priv->psr.source_ok = true;
 	return true;
 }
 
-static void intel_psr_do_enable(struct intel_dp *intel_dp)
+static void intel_psr_activate(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -242,7 +309,14 @@
 	lockdep_assert_held(&dev_priv->psr.lock);
 
 	/* Enable/Re-enable PSR on the host */
-	intel_psr_enable_source(intel_dp);
+	if (HAS_DDI(dev))
+		/* On HSW+ after we enable PSR on source it will activate it
+		 * as soon as it match configure idle_frame count. So
+		 * we just actually enable it here on activation time.
+		 */
+		hsw_psr_enable_source(intel_dp);
+	else
+		vlv_psr_activate(intel_dp);
 
 	dev_priv->psr.active = true;
 }
@@ -278,22 +352,95 @@
 	if (!intel_psr_match_conditions(intel_dp))
 		goto unlock;
 
+	/* First we check VBT, but we must respect sink and source
+	 * known restrictions */
+	dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link;
+	if ((intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) ||
+	    (IS_BROADWELL(dev) && intel_dig_port->port != PORT_A))
+		dev_priv->psr.link_standby = true;
+
 	dev_priv->psr.busy_frontbuffer_bits = 0;
 
-	intel_psr_setup_vsc(intel_dp);
+	if (HAS_DDI(dev)) {
+		hsw_psr_setup_vsc(intel_dp);
 
-	/* Avoid continuous PSR exit by masking memup and hpd */
-	I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
-		   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+		/* Avoid continuous PSR exit by masking memup and hpd */
+		I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+			   EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
 
-	/* Enable PSR on the panel */
-	intel_psr_enable_sink(intel_dp);
+		/* Enable PSR on the panel */
+		hsw_psr_enable_sink(intel_dp);
+
+		if (INTEL_INFO(dev)->gen >= 9)
+			intel_psr_activate(intel_dp);
+	} else {
+		vlv_psr_setup_vsc(intel_dp);
+
+		/* Enable PSR on the panel */
+		vlv_psr_enable_sink(intel_dp);
+
+		/* On HSW+ enable_source also means go to PSR entry/active
+		 * state as soon as idle_frame achieved and here would be
+		 * to soon. However on VLV enable_source just enable PSR
+		 * but let it on inactive state. So we might do this prior
+		 * to active transition, i.e. here.
+		 */
+		vlv_psr_enable_source(intel_dp);
+	}
 
 	dev_priv->psr.enabled = intel_dp;
 unlock:
 	mutex_unlock(&dev_priv->psr.lock);
 }
 
+static void vlv_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc =
+		to_intel_crtc(intel_dig_port->base.base.crtc);
+	uint32_t val;
+
+	if (dev_priv->psr.active) {
+		/* Put VLV PSR back to PSR_state 0 that is PSR Disabled. */
+		if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
+			      VLV_EDP_PSR_IN_TRANS) == 0, 1))
+			WARN(1, "PSR transition took longer than expected\n");
+
+		val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
+		val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+		val &= ~VLV_EDP_PSR_ENABLE;
+		val &= ~VLV_EDP_PSR_MODE_MASK;
+		I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+
+		dev_priv->psr.active = false;
+	} else {
+		WARN_ON(vlv_is_psr_active_on_pipe(dev, intel_crtc->pipe));
+	}
+}
+
+static void hsw_psr_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->psr.active) {
+		I915_WRITE(EDP_PSR_CTL(dev),
+			   I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
+
+		/* Wait till PSR is idle */
+		if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
+			       EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
+			DRM_ERROR("Timed out waiting for PSR Idle State\n");
+
+		dev_priv->psr.active = false;
+	} else {
+		WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
+	}
+}
+
 /**
  * intel_psr_disable - Disable PSR
  * @intel_dp: Intel DP
@@ -312,19 +459,10 @@
 		return;
 	}
 
-	if (dev_priv->psr.active) {
-		I915_WRITE(EDP_PSR_CTL(dev),
-			   I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
-
-		/* Wait till PSR is idle */
-		if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
-			       EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
-			DRM_ERROR("Timed out waiting for PSR Idle State\n");
-
-		dev_priv->psr.active = false;
-	} else {
-		WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
-	}
+	if (HAS_DDI(dev))
+		hsw_psr_disable(intel_dp);
+	else
+		vlv_psr_disable(intel_dp);
 
 	dev_priv->psr.enabled = NULL;
 	mutex_unlock(&dev_priv->psr.lock);
@@ -337,18 +475,27 @@
 	struct drm_i915_private *dev_priv =
 		container_of(work, typeof(*dev_priv), psr.work.work);
 	struct intel_dp *intel_dp = dev_priv->psr.enabled;
+	struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
 
 	/* We have to make sure PSR is ready for re-enable
 	 * otherwise it keeps disabled until next full enable/disable cycle.
 	 * PSR might take some time to get fully disabled
 	 * and be ready for re-enable.
 	 */
-	if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
-		      EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
-		DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
-		return;
+	if (HAS_DDI(dev_priv->dev)) {
+		if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
+			      EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
+			DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+			return;
+		}
+	} else {
+		if (wait_for((I915_READ(VLV_PSRSTAT(pipe)) &
+			      VLV_EDP_PSR_IN_TRANS) == 0, 1)) {
+			DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+			return;
+		}
 	}
-
 	mutex_lock(&dev_priv->psr.lock);
 	intel_dp = dev_priv->psr.enabled;
 
@@ -363,7 +510,7 @@
 	if (dev_priv->psr.busy_frontbuffer_bits)
 		goto unlock;
 
-	intel_psr_do_enable(intel_dp);
+	intel_psr_activate(intel_dp);
 unlock:
 	mutex_unlock(&dev_priv->psr.lock);
 }
@@ -371,17 +518,47 @@
 static void intel_psr_exit(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_dp *intel_dp = dev_priv->psr.enabled;
+	struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+	enum pipe pipe = to_intel_crtc(crtc)->pipe;
+	u32 val;
 
-	if (dev_priv->psr.active) {
-		u32 val = I915_READ(EDP_PSR_CTL(dev));
+	if (!dev_priv->psr.active)
+		return;
+
+	if (HAS_DDI(dev)) {
+		val = I915_READ(EDP_PSR_CTL(dev));
 
 		WARN_ON(!(val & EDP_PSR_ENABLE));
 
 		I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
 
 		dev_priv->psr.active = false;
+	} else {
+		val = I915_READ(VLV_PSRCTL(pipe));
+
+		/* Here we do the transition from PSR_state 3 to PSR_state 5
+		 * directly once PSR State 4 that is active with single frame
+		 * update can be skipped. PSR_state 5 that is PSR exit then
+		 * Hardware is responsible to transition back to PSR_state 1
+		 * that is PSR inactive. Same state after
+		 * vlv_edp_psr_enable_source.
+		 */
+		val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+		I915_WRITE(VLV_PSRCTL(pipe), val);
+
+		/* Send AUX wake up - Spec says after transitioning to PSR
+		 * active we have to send AUX wake up by writing 01h in DPCD
+		 * 600h of sink device.
+		 * XXX: This might slow down the transition, but without this
+		 * HW doesn't complete the transition to PSR_state 1 and we
+		 * never get the screen updated.
+		 */
+		drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+				   DP_SET_POWER_D0);
 	}
 
+	dev_priv->psr.active = false;
 }
 
 /**
@@ -459,6 +636,15 @@
 	    (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
 		intel_psr_exit(dev);
 
+	/*
+	 * On Valleyview and Cherryview we don't use hardware tracking so
+	 * any plane updates or cursor moves don't result in a PSR
+	 * invalidating. Which means we need to manually fake this in
+	 * software for all flushes, not just when we've seen a preceding
+	 * invalidation through frontbuffer rendering. */
+	if (!HAS_DDI(dev))
+		intel_psr_exit(dev);
+
 	if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
 		schedule_delayed_work(&dev_priv->psr.work,
 				      msecs_to_jiffies(100));
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen6.c b/drivers/gpu/drm/i915/intel_renderstate_gen6.c
index 56c1429..11c8e7b 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen6.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen6.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 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.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
 #include "intel_renderstate.h"
 
 static const u32 gen6_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen7.c b/drivers/gpu/drm/i915/intel_renderstate_gen7.c
index 419e35a..6551806 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen7.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen7.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 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.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
 #include "intel_renderstate.h"
 
 static const u32 gen7_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen8.c b/drivers/gpu/drm/i915/intel_renderstate_gen8.c
index 78011d7..95288a3 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen8.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen8.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 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.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
 #include "intel_renderstate.h"
 
 static const u32 gen8_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen9.c b/drivers/gpu/drm/i915/intel_renderstate_gen9.c
index 8750753..16a7ec2 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen9.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen9.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 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.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
 #include "intel_renderstate.h"
 
 static const u32 gen9_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index c7bc93d..e5b3c6d 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -52,16 +52,27 @@
 
 int __intel_ring_space(int head, int tail, int size)
 {
-	int space = head - (tail + I915_RING_FREE_SPACE);
-	if (space < 0)
+	int space = head - tail;
+	if (space <= 0)
 		space += size;
-	return space;
+	return space - I915_RING_FREE_SPACE;
+}
+
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
+{
+	if (ringbuf->last_retired_head != -1) {
+		ringbuf->head = ringbuf->last_retired_head;
+		ringbuf->last_retired_head = -1;
+	}
+
+	ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
+					    ringbuf->tail, ringbuf->size);
 }
 
 int intel_ring_space(struct intel_ringbuffer *ringbuf)
 {
-	return __intel_ring_space(ringbuf->head & HEAD_ADDR,
-				  ringbuf->tail, ringbuf->size);
+	intel_ring_update_space(ringbuf);
+	return ringbuf->space;
 }
 
 bool intel_ring_stopped(struct intel_engine_cs *ring)
@@ -528,7 +539,7 @@
 	struct drm_i915_gem_object *obj = ringbuf->obj;
 	int ret = 0;
 
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
 	if (!stop_ring(ring)) {
 		/* G45 ring initialization often fails to reset head to zero */
@@ -592,15 +603,15 @@
 		goto out;
 	}
 
+	ringbuf->last_retired_head = -1;
 	ringbuf->head = I915_READ_HEAD(ring);
 	ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-	ringbuf->space = intel_ring_space(ringbuf);
-	ringbuf->last_retired_head = -1;
+	intel_ring_update_space(ringbuf);
 
 	memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
 
 out:
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
 	return ret;
 }
@@ -627,8 +638,7 @@
 {
 	int ret;
 
-	if (ring->scratch.obj)
-		return 0;
+	WARN_ON(ring->scratch.obj);
 
 	ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096);
 	if (ring->scratch.obj == NULL) {
@@ -672,7 +682,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct i915_workarounds *w = &dev_priv->workarounds;
 
-	if (WARN_ON(w->count == 0))
+	if (WARN_ON_ONCE(w->count == 0))
 		return 0;
 
 	ring->gpu_caches_dirty = true;
@@ -703,6 +713,22 @@
 	return 0;
 }
 
+static int intel_rcs_ctx_init(struct intel_engine_cs *ring,
+			      struct intel_context *ctx)
+{
+	int ret;
+
+	ret = intel_ring_workarounds_emit(ring, ctx);
+	if (ret != 0)
+		return ret;
+
+	ret = i915_gem_render_state_init(ring);
+	if (ret)
+		DRM_ERROR("init render state: %d\n", ret);
+
+	return ret;
+}
+
 static int wa_add(struct drm_i915_private *dev_priv,
 		  const u32 addr, const u32 mask, const u32 val)
 {
@@ -762,11 +788,24 @@
 	 * workaround for for a possible hang in the unlikely event a TLB
 	 * invalidation occurs during a PSD flush.
 	 */
+	/* WaForceEnableNonCoherent:bdw */
+	/* WaHdcDisableFetchWhenMasked:bdw */
 	/* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */
 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
 			  HDC_FORCE_NON_COHERENT |
+			  HDC_DONOT_FETCH_MEM_WHEN_MASKED |
 			  (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
 
+	/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
+	 * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
+	 *  polygons in the same 8x4 pixel/sample area to be processed without
+	 *  stalling waiting for the earlier ones to write to Hierarchical Z
+	 *  buffer."
+	 *
+	 * This optimization is off by default for Broadwell; turn it on.
+	 */
+	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
+
 	/* Wa4x4STCOptimizationDisable:bdw */
 	WA_SET_BIT_MASKED(CACHE_MODE_1,
 			  GEN8_4x4_STC_OPTIMIZATION_DISABLE);
@@ -807,6 +846,30 @@
 			  HDC_FORCE_NON_COHERENT |
 			  HDC_DONOT_FETCH_MEM_WHEN_MASKED);
 
+	/* According to the CACHE_MODE_0 default value documentation, some
+	 * CHV platforms disable this optimization by default.  Turn it on.
+	 */
+	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
+
+	/* Wa4x4STCOptimizationDisable:chv */
+	WA_SET_BIT_MASKED(CACHE_MODE_1,
+			  GEN8_4x4_STC_OPTIMIZATION_DISABLE);
+
+	/* Improve HiZ throughput on CHV. */
+	WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
+
+	/*
+	 * BSpec recommends 8x4 when MSAA is used,
+	 * however in practice 16x4 seems fastest.
+	 *
+	 * Note that PS/WM thread counts depend on the WIZ hashing
+	 * disable bit, which we don't touch here, but it's good
+	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+	 */
+	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
+			    GEN6_WIZ_HASHING_MASK,
+			    GEN6_WIZ_HASHING_16x4);
+
 	return 0;
 }
 
@@ -861,12 +924,6 @@
 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
-	if (INTEL_INFO(dev)->gen >= 5) {
-		ret = intel_init_pipe_control(ring);
-		if (ret)
-			return ret;
-	}
-
 	if (IS_GEN6(dev)) {
 		/* From the Sandybridge PRM, volume 1 part 3, page 24:
 		 * "If this bit is set, STCunit will have LRA as replacement
@@ -918,17 +975,20 @@
 		return ret;
 
 	for_each_ring(waiter, dev_priv, i) {
+		u32 seqno;
 		u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
 			continue;
 
+		seqno = i915_gem_request_get_seqno(
+					   signaller->outstanding_lazy_request);
 		intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
 		intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
 					   PIPE_CONTROL_QW_WRITE |
 					   PIPE_CONTROL_FLUSH_ENABLE);
 		intel_ring_emit(signaller, lower_32_bits(gtt_offset));
 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
-		intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+		intel_ring_emit(signaller, seqno);
 		intel_ring_emit(signaller, 0);
 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
 					   MI_SEMAPHORE_TARGET(waiter->id));
@@ -956,16 +1016,19 @@
 		return ret;
 
 	for_each_ring(waiter, dev_priv, i) {
+		u32 seqno;
 		u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
 			continue;
 
+		seqno = i915_gem_request_get_seqno(
+					   signaller->outstanding_lazy_request);
 		intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
 					   MI_FLUSH_DW_OP_STOREDW);
 		intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
 					   MI_FLUSH_DW_USE_GTT);
 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
-		intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+		intel_ring_emit(signaller, seqno);
 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
 					   MI_SEMAPHORE_TARGET(waiter->id));
 		intel_ring_emit(signaller, 0);
@@ -994,9 +1057,11 @@
 	for_each_ring(useless, dev_priv, i) {
 		u32 mbox_reg = signaller->semaphore.mbox.signal[i];
 		if (mbox_reg != GEN6_NOSYNC) {
+			u32 seqno = i915_gem_request_get_seqno(
+					   signaller->outstanding_lazy_request);
 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
 			intel_ring_emit(signaller, mbox_reg);
-			intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+			intel_ring_emit(signaller, seqno);
 		}
 	}
 
@@ -1031,7 +1096,8 @@
 
 	intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
 	intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-	intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+	intel_ring_emit(ring,
+		    i915_gem_request_get_seqno(ring->outstanding_lazy_request));
 	intel_ring_emit(ring, MI_USER_INTERRUPT);
 	__intel_ring_advance(ring);
 
@@ -1149,7 +1215,8 @@
 			PIPE_CONTROL_WRITE_FLUSH |
 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
 	intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
-	intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+	intel_ring_emit(ring,
+		    i915_gem_request_get_seqno(ring->outstanding_lazy_request));
 	intel_ring_emit(ring, 0);
 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
 	scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
@@ -1168,7 +1235,8 @@
 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
 			PIPE_CONTROL_NOTIFY);
 	intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
-	intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+	intel_ring_emit(ring,
+		    i915_gem_request_get_seqno(ring->outstanding_lazy_request));
 	intel_ring_emit(ring, 0);
 	__intel_ring_advance(ring);
 
@@ -1408,7 +1476,8 @@
 
 	intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
 	intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
-	intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+	intel_ring_emit(ring,
+		    i915_gem_request_get_seqno(ring->outstanding_lazy_request));
 	intel_ring_emit(ring, MI_USER_INTERRUPT);
 	__intel_ring_advance(ring);
 
@@ -1789,15 +1858,15 @@
 static int intel_init_ring_buffer(struct drm_device *dev,
 				  struct intel_engine_cs *ring)
 {
-	struct intel_ringbuffer *ringbuf = ring->buffer;
+	struct intel_ringbuffer *ringbuf;
 	int ret;
 
-	if (ringbuf == NULL) {
-		ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
-		if (!ringbuf)
-			return -ENOMEM;
-		ring->buffer = ringbuf;
-	}
+	WARN_ON(ring->buffer);
+
+	ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
+	if (!ringbuf)
+		return -ENOMEM;
+	ring->buffer = ringbuf;
 
 	ring->dev = dev;
 	INIT_LIST_HEAD(&ring->active_list);
@@ -1820,21 +1889,21 @@
 			goto error;
 	}
 
-	if (ringbuf->obj == NULL) {
-		ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
-		if (ret) {
-			DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
-					ring->name, ret);
-			goto error;
-		}
+	WARN_ON(ringbuf->obj);
 
-		ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
-		if (ret) {
-			DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
-					ring->name, ret);
-			intel_destroy_ringbuffer_obj(ringbuf);
-			goto error;
-		}
+	ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
+	if (ret) {
+		DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
+				ring->name, ret);
+		goto error;
+	}
+
+	ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
+	if (ret) {
+		DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
+				ring->name, ret);
+		intel_destroy_ringbuffer_obj(ringbuf);
+		goto error;
 	}
 
 	/* Workaround an erratum on the i830 which causes a hang if
@@ -1849,10 +1918,6 @@
 	if (ret)
 		goto error;
 
-	ret = ring->init(ring);
-	if (ret)
-		goto error;
-
 	return 0;
 
 error:
@@ -1877,8 +1942,7 @@
 
 	intel_unpin_ringbuffer_obj(ringbuf);
 	intel_destroy_ringbuffer_obj(ringbuf);
-	ring->preallocated_lazy_request = NULL;
-	ring->outstanding_lazy_seqno = 0;
+	i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
 
 	if (ring->cleanup)
 		ring->cleanup(ring);
@@ -1895,38 +1959,27 @@
 {
 	struct intel_ringbuffer *ringbuf = ring->buffer;
 	struct drm_i915_gem_request *request;
-	u32 seqno = 0;
 	int ret;
 
-	if (ringbuf->last_retired_head != -1) {
-		ringbuf->head = ringbuf->last_retired_head;
-		ringbuf->last_retired_head = -1;
-
-		ringbuf->space = intel_ring_space(ringbuf);
-		if (ringbuf->space >= n)
-			return 0;
-	}
+	if (intel_ring_space(ringbuf) >= n)
+		return 0;
 
 	list_for_each_entry(request, &ring->request_list, list) {
-		if (__intel_ring_space(request->tail, ringbuf->tail,
+		if (__intel_ring_space(request->postfix, ringbuf->tail,
 				       ringbuf->size) >= n) {
-			seqno = request->seqno;
 			break;
 		}
 	}
 
-	if (seqno == 0)
+	if (&request->list == &ring->request_list)
 		return -ENOSPC;
 
-	ret = i915_wait_seqno(ring, seqno);
+	ret = i915_wait_request(request);
 	if (ret)
 		return ret;
 
 	i915_gem_retire_requests_ring(ring);
-	ringbuf->head = ringbuf->last_retired_head;
-	ringbuf->last_retired_head = -1;
 
-	ringbuf->space = intel_ring_space(ringbuf);
 	return 0;
 }
 
@@ -1952,14 +2005,14 @@
 	 * case by choosing an insanely large timeout. */
 	end = jiffies + 60 * HZ;
 
+	ret = 0;
 	trace_i915_ring_wait_begin(ring);
 	do {
-		ringbuf->head = I915_READ_HEAD(ring);
-		ringbuf->space = intel_ring_space(ringbuf);
-		if (ringbuf->space >= n) {
-			ret = 0;
+		if (intel_ring_space(ringbuf) >= n)
 			break;
-		}
+		ringbuf->head = I915_READ_HEAD(ring);
+		if (intel_ring_space(ringbuf) >= n)
+			break;
 
 		msleep(1);
 
@@ -2000,19 +2053,19 @@
 		iowrite32(MI_NOOP, virt++);
 
 	ringbuf->tail = 0;
-	ringbuf->space = intel_ring_space(ringbuf);
+	intel_ring_update_space(ringbuf);
 
 	return 0;
 }
 
 int intel_ring_idle(struct intel_engine_cs *ring)
 {
-	u32 seqno;
+	struct drm_i915_gem_request *req;
 	int ret;
 
 	/* We need to add any requests required to flush the objects and ring */
-	if (ring->outstanding_lazy_seqno) {
-		ret = i915_add_request(ring, NULL);
+	if (ring->outstanding_lazy_request) {
+		ret = i915_add_request(ring);
 		if (ret)
 			return ret;
 	}
@@ -2021,30 +2074,39 @@
 	if (list_empty(&ring->request_list))
 		return 0;
 
-	seqno = list_entry(ring->request_list.prev,
+	req = list_entry(ring->request_list.prev,
 			   struct drm_i915_gem_request,
-			   list)->seqno;
+			   list);
 
-	return i915_wait_seqno(ring, seqno);
+	return i915_wait_request(req);
 }
 
 static int
-intel_ring_alloc_seqno(struct intel_engine_cs *ring)
+intel_ring_alloc_request(struct intel_engine_cs *ring)
 {
-	if (ring->outstanding_lazy_seqno)
+	int ret;
+	struct drm_i915_gem_request *request;
+	struct drm_i915_private *dev_private = ring->dev->dev_private;
+
+	if (ring->outstanding_lazy_request)
 		return 0;
 
-	if (ring->preallocated_lazy_request == NULL) {
-		struct drm_i915_gem_request *request;
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
 
-		request = kmalloc(sizeof(*request), GFP_KERNEL);
-		if (request == NULL)
-			return -ENOMEM;
+	kref_init(&request->ref);
+	request->ring = ring;
+	request->uniq = dev_private->request_uniq++;
 
-		ring->preallocated_lazy_request = request;
+	ret = i915_gem_get_seqno(ring->dev, &request->seqno);
+	if (ret) {
+		kfree(request);
+		return ret;
 	}
 
-	return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+	ring->outstanding_lazy_request = request;
+	return 0;
 }
 
 static int __intel_ring_prepare(struct intel_engine_cs *ring,
@@ -2084,7 +2146,7 @@
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = intel_ring_alloc_seqno(ring);
+	ret = intel_ring_alloc_request(ring);
 	if (ret)
 		return ret;
 
@@ -2119,7 +2181,7 @@
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	BUG_ON(ring->outstanding_lazy_seqno);
+	BUG_ON(ring->outstanding_lazy_request);
 
 	if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) {
 		I915_WRITE(RING_SYNC_0(ring->mmio_base), 0);
@@ -2178,6 +2240,14 @@
 	cmd = MI_FLUSH_DW;
 	if (INTEL_INFO(ring->dev)->gen >= 8)
 		cmd += 1;
+
+	/* We always require a command barrier so that subsequent
+	 * commands, such as breadcrumb interrupts, are strictly ordered
+	 * wrt the contents of the write cache being flushed to memory
+	 * (and thus being coherent from the CPU).
+	 */
+	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
 	/*
 	 * Bspec vol 1c.5 - video engine command streamer:
 	 * "If ENABLED, all TLBs will be invalidated once the flush
@@ -2185,8 +2255,8 @@
 	 * Post-Sync Operation field is a value of 1h or 3h."
 	 */
 	if (invalidate & I915_GEM_GPU_DOMAINS)
-		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
-			MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
+
 	intel_ring_emit(ring, cmd);
 	intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
 	if (INTEL_INFO(ring->dev)->gen >= 8) {
@@ -2282,6 +2352,14 @@
 	cmd = MI_FLUSH_DW;
 	if (INTEL_INFO(ring->dev)->gen >= 8)
 		cmd += 1;
+
+	/* We always require a command barrier so that subsequent
+	 * commands, such as breadcrumb interrupts, are strictly ordered
+	 * wrt the contents of the write cache being flushed to memory
+	 * (and thus being coherent from the CPU).
+	 */
+	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
 	/*
 	 * Bspec vol 1c.3 - blitter engine command streamer:
 	 * "If ENABLED, all TLBs will be invalidated once the flush
@@ -2289,8 +2367,7 @@
 	 * Post-Sync Operation field is a value of 1h or 3h."
 	 */
 	if (invalidate & I915_GEM_DOMAIN_RENDER)
-		cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
-			MI_FLUSH_DW_OP_STOREDW;
+		cmd |= MI_INVALIDATE_TLB;
 	intel_ring_emit(ring, cmd);
 	intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
 	if (INTEL_INFO(ring->dev)->gen >= 8) {
@@ -2341,7 +2418,7 @@
 			}
 		}
 
-		ring->init_context = intel_ring_workarounds_emit;
+		ring->init_context = intel_rcs_ctx_init;
 		ring->add_request = gen6_add_request;
 		ring->flush = gen8_render_ring_flush;
 		ring->irq_get = gen8_ring_get_irq;
@@ -2426,7 +2503,7 @@
 		ring->dispatch_execbuffer = i830_dispatch_execbuffer;
 	else
 		ring->dispatch_execbuffer = i915_dispatch_execbuffer;
-	ring->init = init_render_ring;
+	ring->init_hw = init_render_ring;
 	ring->cleanup = render_ring_cleanup;
 
 	/* Workaround batchbuffer to combat CS tlb bug. */
@@ -2448,7 +2525,17 @@
 		ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
 	}
 
-	return intel_init_ring_buffer(dev, ring);
+	ret = intel_init_ring_buffer(dev, ring);
+	if (ret)
+		return ret;
+
+	if (INTEL_INFO(dev)->gen >= 5) {
+		ret = intel_init_pipe_control(ring);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
 }
 
 int intel_init_bsd_ring_buffer(struct drm_device *dev)
@@ -2519,7 +2606,7 @@
 		}
 		ring->dispatch_execbuffer = i965_dispatch_execbuffer;
 	}
-	ring->init = init_ring_common;
+	ring->init_hw = init_ring_common;
 
 	return intel_init_ring_buffer(dev, ring);
 }
@@ -2558,7 +2645,7 @@
 		ring->semaphore.signal = gen8_xcs_signal;
 		GEN8_RING_SEMAPHORE_INIT;
 	}
-	ring->init = init_ring_common;
+	ring->init_hw = init_ring_common;
 
 	return intel_init_ring_buffer(dev, ring);
 }
@@ -2615,7 +2702,7 @@
 			ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
 		}
 	}
-	ring->init = init_ring_common;
+	ring->init_hw = init_ring_common;
 
 	return intel_init_ring_buffer(dev, ring);
 }
@@ -2666,7 +2753,7 @@
 			ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
 		}
 	}
-	ring->init = init_ring_common;
+	ring->init_hw = init_ring_common;
 
 	return intel_init_ring_buffer(dev, ring);
 }
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index fe426cf..714f3fd 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -99,13 +99,6 @@
 
 	struct intel_engine_cs *ring;
 
-	/*
-	 * FIXME: This backpointer is an artifact of the history of how the
-	 * execlist patches came into being. It will get removed once the basic
-	 * code has landed.
-	 */
-	struct intel_context *FIXME_lrc_ctx;
-
 	u32 head;
 	u32 tail;
 	int space;
@@ -123,6 +116,8 @@
 	u32 last_retired_head;
 };
 
+struct	intel_context;
+
 struct  intel_engine_cs {
 	const char	*name;
 	enum intel_ring_id {
@@ -142,11 +137,11 @@
 
 	unsigned irq_refcount; /* protected by dev_priv->irq_lock */
 	u32		irq_enable_mask;	/* bitmask to enable ring interrupt */
-	u32		trace_irq_seqno;
+	struct drm_i915_gem_request *trace_irq_req;
 	bool __must_check (*irq_get)(struct intel_engine_cs *ring);
 	void		(*irq_put)(struct intel_engine_cs *ring);
 
-	int		(*init)(struct intel_engine_cs *ring);
+	int		(*init_hw)(struct intel_engine_cs *ring);
 
 	int		(*init_context)(struct intel_engine_cs *ring,
 					struct intel_context *ctx);
@@ -239,11 +234,14 @@
 	struct list_head execlist_retired_req_list;
 	u8 next_context_status_buffer;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
-	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
+	int		(*emit_request)(struct intel_ringbuffer *ringbuf,
+					struct drm_i915_gem_request *request);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
+				      struct intel_context *ctx,
 				      u32 invalidate_domains,
 				      u32 flush_domains);
 	int		(*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+					 struct intel_context *ctx,
 					 u64 offset, unsigned flags);
 
 	/**
@@ -251,7 +249,7 @@
 	 * ringbuffer.
 	 *
 	 * Includes buffers having the contents of their GPU caches
-	 * flushed, not necessarily primitives.  last_rendering_seqno
+	 * flushed, not necessarily primitives.  last_read_req
 	 * represents when the rendering involved will be completed.
 	 *
 	 * A reference is held on the buffer while on this list.
@@ -267,8 +265,7 @@
 	/**
 	 * Do we have some not yet emitted requests outstanding?
 	 */
-	struct drm_i915_gem_request *preallocated_lazy_request;
-	u32 outstanding_lazy_seqno;
+	struct drm_i915_gem_request *outstanding_lazy_request;
 	bool gpu_caches_dirty;
 	bool fbc_dirty;
 
@@ -408,6 +405,7 @@
 	ringbuf->tail &= ringbuf->size - 1;
 }
 int __intel_ring_space(int head, int tail, int size);
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf);
 int intel_ring_space(struct intel_ringbuffer *ringbuf);
 bool intel_ring_stopped(struct intel_engine_cs *ring);
 void __intel_ring_advance(struct intel_engine_cs *ring);
@@ -436,16 +434,11 @@
 	return ringbuf->tail;
 }
 
-static inline u32 intel_ring_get_seqno(struct intel_engine_cs *ring)
+static inline struct drm_i915_gem_request *
+intel_ring_get_request(struct intel_engine_cs *ring)
 {
-	BUG_ON(ring->outstanding_lazy_seqno == 0);
-	return ring->outstanding_lazy_seqno;
-}
-
-static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno)
-{
-	if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
-		ring->trace_irq_seqno = seqno;
+	BUG_ON(ring->outstanding_lazy_request == NULL);
+	return ring->outstanding_lazy_request;
 }
 
 #endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 39ddf40..49695d7 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -115,7 +115,7 @@
 }
 
 /**
- * intel_display_power_is_enabled - unlocked check for a power domain
+ * intel_display_power_is_enabled - check for a power domain
  * @dev_priv: i915 device instance
  * @domain: power domain to check
  *
@@ -703,6 +703,10 @@
 	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |		\
 	BIT(POWER_DOMAIN_PORT_CRT) |			\
 	BIT(POWER_DOMAIN_PLLS) |			\
+	BIT(POWER_DOMAIN_AUX_A) |			\
+	BIT(POWER_DOMAIN_AUX_B) |			\
+	BIT(POWER_DOMAIN_AUX_C) |			\
+	BIT(POWER_DOMAIN_AUX_D) |			\
 	BIT(POWER_DOMAIN_INIT))
 #define HSW_DISPLAY_POWER_DOMAINS (				\
 	(POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) |	\
@@ -724,24 +728,30 @@
 	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_CRT) |		\
+	BIT(POWER_DOMAIN_AUX_B) |		\
+	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_B) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_PIPE_A_POWER_DOMAINS (	\
@@ -761,20 +771,25 @@
 	BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_B) |		\
+	BIT(POWER_DOMAIN_AUX_C) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_DPIO_CMN_D_POWER_DOMAINS (		\
 	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_D) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |	\
 	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_D) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 #define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS (	\
 	BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |	\
+	BIT(POWER_DOMAIN_AUX_D) |		\
 	BIT(POWER_DOMAIN_INIT))
 
 static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 6d7a277..64ad2b4 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
@@ -1007,7 +1008,7 @@
 	}
 
 	if (intel_sdvo->rgb_quant_range_selectable) {
-		if (intel_crtc->config.limited_color_range)
+		if (intel_crtc->config->limited_color_range)
 			frame.avi.quantization_range =
 				HDMI_QUANTIZATION_RANGE_LIMITED;
 		else
@@ -1085,7 +1086,7 @@
 	return true;
 }
 
-static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
+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;
@@ -1112,11 +1113,11 @@
 }
 
 static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
-				      struct intel_crtc_config *pipe_config)
+				      struct intel_crtc_state *pipe_config)
 {
 	struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
-	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
-	struct drm_display_mode *mode = &pipe_config->requested_mode;
+	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+	struct drm_display_mode *mode = &pipe_config->base.mode;
 
 	DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
 	pipe_config->pipe_bpp = 8*3;
@@ -1181,8 +1182,8 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
 	struct drm_display_mode *adjusted_mode =
-		&crtc->config.adjusted_mode;
-	struct drm_display_mode *mode = &crtc->config.requested_mode;
+		&crtc->config->base.adjusted_mode;
+	struct drm_display_mode *mode = &crtc->config->base.mode;
 	struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
 	u32 sdvox;
 	struct intel_sdvo_in_out_map in_out;
@@ -1224,7 +1225,7 @@
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return;
 
-	if (crtc->config.has_hdmi_sink) {
+	if (crtc->config->has_hdmi_sink) {
 		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
 		intel_sdvo_set_colorimetry(intel_sdvo,
 					   SDVO_COLORIMETRY_RGB256);
@@ -1244,7 +1245,7 @@
 		DRM_INFO("Setting input timings on %s failed\n",
 			 SDVO_NAME(intel_sdvo));
 
-	switch (crtc->config.pixel_multiplier) {
+	switch (crtc->config->pixel_multiplier) {
 	default:
 		WARN(1, "unknown pixel mutlipler specified\n");
 	case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
@@ -1259,7 +1260,7 @@
 		/* The real mode polarity is set by the SDVO commands, using
 		 * struct intel_sdvo_dtd. */
 		sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
-		if (!HAS_PCH_SPLIT(dev) && crtc->config.limited_color_range)
+		if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
 			sdvox |= HDMI_COLOR_RANGE_16_235;
 		if (INTEL_INFO(dev)->gen < 5)
 			sdvox |= SDVO_BORDER_ENABLE;
@@ -1289,7 +1290,7 @@
 	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
 		/* done in crtc_mode_set as it lives inside the dpll register */
 	} else {
-		sdvox |= (crtc->config.pixel_multiplier - 1)
+		sdvox |= (crtc->config->pixel_multiplier - 1)
 			<< SDVO_PORT_MULTIPLY_SHIFT;
 	}
 
@@ -1338,7 +1339,7 @@
 }
 
 static void intel_sdvo_get_config(struct intel_encoder *encoder,
-				  struct intel_crtc_config *pipe_config)
+				  struct intel_crtc_state *pipe_config)
 {
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1370,7 +1371,7 @@
 			flags |= DRM_MODE_FLAG_NVSYNC;
 	}
 
-	pipe_config->adjusted_mode.flags |= flags;
+	pipe_config->base.adjusted_mode.flags |= flags;
 
 	/*
 	 * pixel multiplier readout is tricky: Only on i915g/gm it is stored in
@@ -1392,7 +1393,7 @@
 	if (HAS_PCH_SPLIT(dev))
 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
 
-	pipe_config->adjusted_mode.crtc_clock = dotclock;
+	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 
 	/* Cross check the port pixel multiplier with the sdvo encoder state. */
 	if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
@@ -1617,6 +1618,9 @@
 	struct drm_device *dev = intel_sdvo->base.base.dev;
 	uint16_t hotplug;
 
+	if (!I915_HAS_HOTPLUG(dev))
+		return 0;
+
 	/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
 	 * on the line. */
 	if (IS_I945G(dev) || IS_I945GM(dev))
@@ -2187,7 +2191,9 @@
 	.detect = intel_sdvo_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.set_property = intel_sdvo_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.destroy = intel_sdvo_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c
index 01d841e..693ce82 100644
--- a/drivers/gpu/drm/i915/intel_sideband.c
+++ b/drivers/gpu/drm/i915/intel_sideband.c
@@ -75,26 +75,26 @@
 	return 0;
 }
 
-u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr)
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr)
 {
 	u32 val = 0;
 
 	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
 	mutex_lock(&dev_priv->dpio_lock);
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
 			SB_CRRDDA_NP, addr, &val);
 	mutex_unlock(&dev_priv->dpio_lock);
 
 	return val;
 }
 
-void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
+void vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val)
 {
 	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
 	mutex_lock(&dev_priv->dpio_lock);
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
 			SB_CRWRDA_NP, addr, &val);
 	mutex_unlock(&dev_priv->dpio_lock);
 }
@@ -103,7 +103,7 @@
 {
 	u32 val = 0;
 
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
 			SB_CRRDDA_NP, reg, &val);
 
 	return val;
@@ -111,7 +111,7 @@
 
 void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
 {
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
 			SB_CRWRDA_NP, reg, &val);
 }
 
@@ -122,7 +122,7 @@
 	WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
 	mutex_lock(&dev_priv->dpio_lock);
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_NC,
 			SB_CRRDDA_NP, addr, &val);
 	mutex_unlock(&dev_priv->dpio_lock);
 
@@ -132,56 +132,56 @@
 u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg)
 {
 	u32 val = 0;
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC,
 			SB_CRRDDA_NP, reg, &val);
 	return val;
 }
 
 void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
 {
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC,
 			SB_CRWRDA_NP, reg, &val);
 }
 
 u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg)
 {
 	u32 val = 0;
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
 			SB_CRRDDA_NP, reg, &val);
 	return val;
 }
 
 void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
 {
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
 			SB_CRWRDA_NP, reg, &val);
 }
 
 u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg)
 {
 	u32 val = 0;
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
 			SB_CRRDDA_NP, reg, &val);
 	return val;
 }
 
 void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
 {
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
 			SB_CRWRDA_NP, reg, &val);
 }
 
 u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg)
 {
 	u32 val = 0;
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE,
 			SB_CRRDDA_NP, reg, &val);
 	return val;
 }
 
 void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
 {
-	vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE,
+	vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE,
 			SB_CRWRDA_NP, reg, &val);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 7d9c340..0a52c44 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_plane_helper.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -79,7 +80,7 @@
 bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
 {
 	struct drm_device *dev = crtc->base.dev;
-	const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+	const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
 	enum pipe pipe = crtc->pipe;
 	long timeout = msecs_to_jiffies_timeout(1);
 	int scanline, min, max, vblank_start;
@@ -255,7 +256,7 @@
 	default:
 		BUG();
 	}
-	if (intel_plane->rotation == BIT(DRM_ROTATE_180))
+	if (drm_plane->state->rotation == BIT(DRM_ROTATE_180))
 		plane_ctl |= PLANE_CTL_ROTATE_180;
 
 	plane_ctl |= PLANE_CTL_ENABLE;
@@ -412,8 +413,6 @@
 	u32 sprctl;
 	unsigned long sprsurf_offset, linear_offset;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
-	u32 start_vbl_count;
-	bool atomic_update;
 
 	sprctl = I915_READ(SPCNTR(pipe, plane));
 
@@ -494,7 +493,7 @@
 							fb->pitches[0]);
 	linear_offset -= sprsurf_offset;
 
-	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+	if (dplane->state->rotation == BIT(DRM_ROTATE_180)) {
 		sprctl |= SP_ROTATE_180;
 
 		x += src_w;
@@ -502,8 +501,6 @@
 		linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
 	}
 
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
 	intel_update_primary_plane(intel_crtc);
 
 	if (IS_CHERRYVIEW(dev) && pipe == PIPE_B)
@@ -525,9 +522,6 @@
 		   sprsurf_offset);
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
 static void
@@ -539,10 +533,6 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_plane->pipe;
 	int plane = intel_plane->plane;
-	u32 start_vbl_count;
-	bool atomic_update;
-
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
 
@@ -553,9 +543,6 @@
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
 
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
-
 	intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
 }
 
@@ -626,8 +613,6 @@
 	u32 sprctl, sprscale = 0;
 	unsigned long sprsurf_offset, linear_offset;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
-	u32 start_vbl_count;
-	bool atomic_update;
 
 	sprctl = I915_READ(SPRCTL(pipe));
 
@@ -699,7 +684,7 @@
 					       pixel_size, fb->pitches[0]);
 	linear_offset -= sprsurf_offset;
 
-	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+	if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
 		sprctl |= SPRITE_ROTATE_180;
 
 		/* HSW and BDW does this automagically in hardware */
@@ -711,8 +696,6 @@
 		}
 	}
 
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
 	intel_update_primary_plane(intel_crtc);
 
 	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
@@ -735,9 +718,6 @@
 		   i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
 static void
@@ -748,10 +728,6 @@
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_plane->pipe;
-	u32 start_vbl_count;
-	bool atomic_update;
-
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
 
@@ -764,16 +740,12 @@
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
 
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
-
 	/*
 	 * Avoid underruns when disabling the sprite.
 	 * FIXME remove once watermark updates are done properly.
 	 */
-	intel_wait_for_vblank(dev, pipe);
-
-	intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+	intel_crtc->atomic.wait_vblank = true;
+	intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
 }
 
 static int
@@ -846,8 +818,6 @@
 	unsigned long dvssurf_offset, linear_offset;
 	u32 dvscntr, dvsscale;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
-	u32 start_vbl_count;
-	bool atomic_update;
 
 	dvscntr = I915_READ(DVSCNTR(pipe));
 
@@ -914,7 +884,7 @@
 					       pixel_size, fb->pitches[0]);
 	linear_offset -= dvssurf_offset;
 
-	if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+	if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
 		dvscntr |= DVS_ROTATE_180;
 
 		x += src_w;
@@ -922,8 +892,6 @@
 		linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
 	}
 
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
 	intel_update_primary_plane(intel_crtc);
 
 	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
@@ -941,9 +909,6 @@
 		   i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
 }
 
 static void
@@ -954,10 +919,6 @@
 	struct intel_plane *intel_plane = to_intel_plane(plane);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_plane->pipe;
-	u32 start_vbl_count;
-	bool atomic_update;
-
-	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 
 	intel_update_primary_plane(intel_crtc);
 
@@ -969,19 +930,25 @@
 
 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
 
-	if (atomic_update)
-		intel_pipe_update_end(intel_crtc, start_vbl_count);
-
 	/*
 	 * Avoid underruns when disabling the sprite.
 	 * FIXME remove once watermark updates are done properly.
 	 */
-	intel_wait_for_vblank(dev, pipe);
-
-	intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+	intel_crtc->atomic.wait_vblank = true;
+	intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
 }
 
-static void
+/**
+ * intel_post_enable_primary - Perform operations after enabling primary plane
+ * @crtc: the CRTC whose primary plane was just enabled
+ *
+ * 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
+ * called due to an explicit primary plane update, or due to an implicit
+ * re-enable that is caused when a sprite plane is updated to no longer
+ * completely hide the primary plane.
+ */
+void
 intel_post_enable_primary(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1004,11 +971,21 @@
 	hsw_enable_ips(intel_crtc);
 
 	mutex_lock(&dev->struct_mutex);
-	intel_update_fbc(dev);
+	intel_fbc_update(dev);
 	mutex_unlock(&dev->struct_mutex);
 }
 
-static void
+/**
+ * intel_pre_disable_primary - Perform operations before disabling primary plane
+ * @crtc: the CRTC whose primary plane is to be disabled
+ *
+ * Performs potentially sleeping operations that must be done before the
+ * primary plane is enabled, such as updating FBC and IPS.  Note that this may
+ * be called due to an explicit primary plane update, or due to an implicit
+ * disable that is caused when a sprite plane completely hides the primary
+ * plane.
+ */
+void
 intel_pre_disable_primary(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1017,7 +994,7 @@
 
 	mutex_lock(&dev->struct_mutex);
 	if (dev_priv->fbc.plane == intel_crtc->plane)
-		intel_disable_fbc(dev);
+		intel_fbc_disable(dev);
 	mutex_unlock(&dev->struct_mutex);
 
 	/*
@@ -1096,20 +1073,26 @@
 intel_check_sprite_plane(struct drm_plane *plane,
 			 struct intel_plane_state *state)
 {
-	struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc);
+	struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct drm_framebuffer *fb = state->fb;
+	struct drm_framebuffer *fb = state->base.fb;
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 	int crtc_x, crtc_y;
 	unsigned int crtc_w, crtc_h;
 	uint32_t src_x, src_y, src_w, src_h;
 	struct drm_rect *src = &state->src;
 	struct drm_rect *dst = &state->dst;
-	struct drm_rect *orig_src = &state->orig_src;
 	const struct drm_rect *clip = &state->clip;
 	int hscale, vscale;
 	int max_scale, min_scale;
-	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+	int pixel_size;
+
+	intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc);
+
+	if (!fb) {
+		state->visible = false;
+		goto finish;
+	}
 
 	/* Don't modify another pipe's plane */
 	if (intel_plane->pipe != intel_crtc->pipe) {
@@ -1142,7 +1125,7 @@
 	min_scale = intel_plane->can_scale ? 1 : (1 << 16);
 
 	drm_rect_rotate(src, fb->width << 16, fb->height << 16,
-			intel_plane->rotation);
+			state->base.rotation);
 
 	hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
 	BUG_ON(hscale < 0);
@@ -1183,13 +1166,13 @@
 				     drm_rect_height(dst) * vscale - drm_rect_height(src));
 
 		drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
-				    intel_plane->rotation);
+				    state->base.rotation);
 
 		/* sanity check to make sure the src viewport wasn't enlarged */
-		WARN_ON(src->x1 < (int) orig_src->x1 ||
-			src->y1 < (int) orig_src->y1 ||
-			src->x2 > (int) orig_src->x2 ||
-			src->y2 > (int) orig_src->y2);
+		WARN_ON(src->x1 < (int) state->base.src_x ||
+			src->y1 < (int) state->base.src_y ||
+			src->x2 > (int) state->base.src_x + state->base.src_w ||
+			src->y2 > (int) state->base.src_y + state->base.src_h);
 
 		/*
 		 * Hardware doesn't handle subpixel coordinates.
@@ -1232,6 +1215,7 @@
 		if (src_w < 3 || src_h < 3)
 			state->visible = false;
 
+		pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 		width_bytes = ((src_x * pixel_size) & 63) +
 					src_w * pixel_size;
 
@@ -1254,39 +1238,27 @@
 	dst->y1 = crtc_y;
 	dst->y2 = crtc_y + crtc_h;
 
-	return 0;
-}
+finish:
+	/*
+	 * If the sprite is completely covering the primary plane,
+	 * we can disable the primary and save power.
+	 */
+	state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) &&
+		!colorkey_enabled(intel_plane);
+	WARN_ON(state->hides_primary && !state->visible && intel_crtc->active);
 
-static int
-intel_prepare_sprite_plane(struct drm_plane *plane,
-			   struct intel_plane_state *state)
-{
-	struct drm_device *dev = plane->dev;
-	struct drm_crtc *crtc = state->crtc;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_framebuffer *fb = state->fb;
-	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_plane->obj;
-	int ret;
+	if (intel_crtc->active) {
+		if (intel_crtc->primary_enabled == state->hides_primary)
+			intel_crtc->atomic.wait_for_flips = true;
 
-	if (old_obj != obj) {
-		mutex_lock(&dev->struct_mutex);
+		if (intel_crtc->primary_enabled && state->hides_primary)
+			intel_crtc->atomic.pre_disable_primary = true;
 
-		/* Note that this will apply the VT-d workaround for scanouts,
-		 * which is more restrictive than required for sprites. (The
-		 * primary plane requires 256KiB alignment with 64 PTE padding,
-		 * the sprite planes only require 128KiB alignment and 32 PTE
-		 * padding.
-		 */
-		ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
-		if (ret == 0)
-			i915_gem_track_fb(old_obj, obj,
-					  INTEL_FRONTBUFFER_SPRITE(pipe));
-		mutex_unlock(&dev->struct_mutex);
-		if (ret)
-			return ret;
+		intel_crtc->atomic.fb_bits |=
+			INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
+
+		if (!intel_crtc->primary_enabled && !state->hides_primary)
+			intel_crtc->atomic.post_enable_primary = true;
 	}
 
 	return 0;
@@ -1296,48 +1268,23 @@
 intel_commit_sprite_plane(struct drm_plane *plane,
 			  struct intel_plane_state *state)
 {
-	struct drm_device *dev = plane->dev;
-	struct drm_crtc *crtc = state->crtc;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_crtc *crtc = state->base.crtc;
+	struct intel_crtc *intel_crtc;
 	struct intel_plane *intel_plane = to_intel_plane(plane);
-	enum pipe pipe = intel_crtc->pipe;
-	struct drm_framebuffer *fb = state->fb;
+	struct drm_framebuffer *fb = state->base.fb;
 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	struct drm_i915_gem_object *old_obj = intel_plane->obj;
 	int crtc_x, crtc_y;
 	unsigned int crtc_w, crtc_h;
 	uint32_t src_x, src_y, src_w, src_h;
-	struct drm_rect *dst = &state->dst;
-	const struct drm_rect *clip = &state->clip;
-	bool primary_enabled;
 
-	/*
-	 * If the sprite is completely covering the primary plane,
-	 * we can disable the primary and save power.
-	 */
-	primary_enabled = !drm_rect_equals(dst, clip) || colorkey_enabled(intel_plane);
-	WARN_ON(!primary_enabled && !state->visible && intel_crtc->active);
+	crtc = crtc ? crtc : plane->crtc;
+	intel_crtc = to_intel_crtc(crtc);
 
-	intel_plane->crtc_x = state->orig_dst.x1;
-	intel_plane->crtc_y = state->orig_dst.y1;
-	intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
-	intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
-	intel_plane->src_x = state->orig_src.x1;
-	intel_plane->src_y = state->orig_src.y1;
-	intel_plane->src_w = drm_rect_width(&state->orig_src);
-	intel_plane->src_h = drm_rect_height(&state->orig_src);
+	plane->fb = state->base.fb;
 	intel_plane->obj = obj;
 
 	if (intel_crtc->active) {
-		bool primary_was_enabled = intel_crtc->primary_enabled;
-
-		intel_crtc->primary_enabled = primary_enabled;
-
-		if (primary_was_enabled != primary_enabled)
-			intel_crtc_wait_for_pending_flips(crtc);
-
-		if (primary_was_enabled && !primary_enabled)
-			intel_pre_disable_primary(crtc);
+		intel_crtc->primary_enabled = !state->hides_primary;
 
 		if (state->visible) {
 			crtc_x = state->dst.x1;
@@ -1354,127 +1301,7 @@
 		} else {
 			intel_plane->disable_plane(plane, crtc);
 		}
-
-
-		intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe));
-
-		if (!primary_was_enabled && primary_enabled)
-			intel_post_enable_primary(crtc);
 	}
-
-	/* Unpin old obj after new one is active to avoid ugliness */
-	if (old_obj && old_obj != obj) {
-
-		/*
-		 * It's fairly common to simply update the position of
-		 * an existing object.  In that case, we don't need to
-		 * wait for vblank to avoid ugliness, we only need to
-		 * do the pin & ref bookkeeping.
-		 */
-		if (intel_crtc->active)
-			intel_wait_for_vblank(dev, intel_crtc->pipe);
-
-		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(old_obj);
-		mutex_unlock(&dev->struct_mutex);
-	}
-}
-
-static int
-intel_update_plane(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 intel_plane_state state;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int ret;
-
-	state.crtc = crtc;
-	state.fb = fb;
-
-	/* sample coordinates in 16.16 fixed point */
-	state.src.x1 = src_x;
-	state.src.x2 = src_x + src_w;
-	state.src.y1 = src_y;
-	state.src.y2 = src_y + src_h;
-
-	/* integer pixels */
-	state.dst.x1 = crtc_x;
-	state.dst.x2 = crtc_x + crtc_w;
-	state.dst.y1 = crtc_y;
-	state.dst.y2 = crtc_y + crtc_h;
-
-	state.clip.x1 = 0;
-	state.clip.y1 = 0;
-	state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
-	state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
-	state.orig_src = state.src;
-	state.orig_dst = state.dst;
-
-	ret = intel_check_sprite_plane(plane, &state);
-	if (ret)
-		return ret;
-
-	ret = intel_prepare_sprite_plane(plane, &state);
-	if (ret)
-		return ret;
-
-	intel_commit_sprite_plane(plane, &state);
-	return 0;
-}
-
-static int
-intel_disable_plane(struct drm_plane *plane)
-{
-	struct drm_device *dev = plane->dev;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	struct intel_crtc *intel_crtc;
-	enum pipe pipe;
-
-	if (!plane->fb)
-		return 0;
-
-	if (WARN_ON(!plane->crtc))
-		return -EINVAL;
-
-	intel_crtc = to_intel_crtc(plane->crtc);
-	pipe = intel_crtc->pipe;
-
-	if (intel_crtc->active) {
-		bool primary_was_enabled = intel_crtc->primary_enabled;
-
-		intel_crtc->primary_enabled = true;
-
-		intel_plane->disable_plane(plane, plane->crtc);
-
-		if (!primary_was_enabled && intel_crtc->primary_enabled)
-			intel_post_enable_primary(plane->crtc);
-	}
-
-	if (intel_plane->obj) {
-		if (intel_crtc->active)
-			intel_wait_for_vblank(dev, intel_plane->pipe);
-
-		mutex_lock(&dev->struct_mutex);
-		intel_unpin_fb_obj(intel_plane->obj);
-		i915_gem_track_fb(intel_plane->obj, NULL,
-				  INTEL_FRONTBUFFER_SPRITE(pipe));
-		mutex_unlock(&dev->struct_mutex);
-
-		intel_plane->obj = NULL;
-	}
-
-	return 0;
-}
-
-static void intel_destroy_plane(struct drm_plane *plane)
-{
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	intel_disable_plane(plane);
-	drm_plane_cleanup(plane);
-	kfree(intel_plane);
 }
 
 int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
@@ -1535,62 +1362,18 @@
 	return ret;
 }
 
-int intel_plane_set_property(struct drm_plane *plane,
-			     struct drm_property *prop,
-			     uint64_t val)
-{
-	struct drm_device *dev = plane->dev;
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-	uint64_t old_val;
-	int ret = -ENOENT;
-
-	if (prop == dev->mode_config.rotation_property) {
-		/* exactly one rotation angle please */
-		if (hweight32(val & 0xf) != 1)
-			return -EINVAL;
-
-		if (intel_plane->rotation == val)
-			return 0;
-
-		old_val = intel_plane->rotation;
-		intel_plane->rotation = val;
-		ret = intel_plane_restore(plane);
-		if (ret)
-			intel_plane->rotation = old_val;
-	}
-
-	return ret;
-}
-
 int intel_plane_restore(struct drm_plane *plane)
 {
-	struct intel_plane *intel_plane = to_intel_plane(plane);
-
 	if (!plane->crtc || !plane->fb)
 		return 0;
 
 	return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
-				  intel_plane->crtc_x, intel_plane->crtc_y,
-				  intel_plane->crtc_w, intel_plane->crtc_h,
-				  intel_plane->src_x, intel_plane->src_y,
-				  intel_plane->src_w, intel_plane->src_h);
+				  plane->state->crtc_x, plane->state->crtc_y,
+				  plane->state->crtc_w, plane->state->crtc_h,
+				  plane->state->src_x, plane->state->src_y,
+				  plane->state->src_w, plane->state->src_h);
 }
 
-void intel_plane_disable(struct drm_plane *plane)
-{
-	if (!plane->crtc || !plane->fb)
-		return;
-
-	intel_disable_plane(plane);
-}
-
-static const struct drm_plane_funcs intel_plane_funcs = {
-	.update_plane = intel_update_plane,
-	.disable_plane = intel_disable_plane,
-	.destroy = intel_destroy_plane,
-	.set_property = intel_plane_set_property,
-};
-
 static uint32_t ilk_plane_formats[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_YUYV,
@@ -1638,6 +1421,7 @@
 intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 {
 	struct intel_plane *intel_plane;
+	struct intel_plane_state *state;
 	unsigned long possible_crtcs;
 	const uint32_t *plane_formats;
 	int num_plane_formats;
@@ -1650,6 +1434,13 @@
 	if (!intel_plane)
 		return -ENOMEM;
 
+	state = intel_create_plane_state(&intel_plane->base);
+	if (!state) {
+		kfree(intel_plane);
+		return -ENOMEM;
+	}
+	intel_plane->base.state = &state->base;
+
 	switch (INTEL_INFO(dev)->gen) {
 	case 5:
 	case 6:
@@ -1719,7 +1510,8 @@
 
 	intel_plane->pipe = pipe;
 	intel_plane->plane = plane;
-	intel_plane->rotation = BIT(DRM_ROTATE_0);
+	intel_plane->check_plane = intel_check_sprite_plane;
+	intel_plane->commit_plane = intel_commit_sprite_plane;
 	possible_crtcs = (1 << pipe);
 	ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
 				       &intel_plane_funcs,
@@ -1739,7 +1531,9 @@
 	if (dev->mode_config.rotation_property)
 		drm_object_attach_property(&intel_plane->base.base,
 					   dev->mode_config.rotation_property,
-					   intel_plane->rotation);
+					   state->base.rotation);
+
+	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
 
  out:
 	return ret;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6f5f59b..892d23c 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -31,6 +31,7 @@
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
@@ -908,14 +909,14 @@
 
 static void
 intel_tv_get_config(struct intel_encoder *encoder,
-		    struct intel_crtc_config *pipe_config)
+		    struct intel_crtc_state *pipe_config)
 {
-	pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
 }
 
 static bool
 intel_tv_compute_config(struct intel_encoder *encoder,
-			struct intel_crtc_config *pipe_config)
+			struct intel_crtc_state *pipe_config)
 {
 	struct intel_tv *intel_tv = enc_to_tv(encoder);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
@@ -923,12 +924,12 @@
 	if (!tv_mode)
 		return false;
 
-	pipe_config->adjusted_mode.crtc_clock = tv_mode->clock;
+	pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
 	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
 	pipe_config->pipe_bpp = 8*3;
 
 	/* TV has it's own notion of sync and other mode flags, so clear them. */
-	pipe_config->adjusted_mode.flags = 0;
+	pipe_config->base.adjusted_mode.flags = 0;
 
 	/*
 	 * FIXME: We don't check whether the input mode is actually what we want
@@ -1512,7 +1513,9 @@
 	.detect = intel_tv_detect,
 	.destroy = intel_tv_destroy,
 	.set_property = intel_tv_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 46de8d7..c47a3ba 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -24,6 +24,8 @@
 #include "i915_drv.h"
 #include "intel_drv.h"
 
+#include <linux/pm_runtime.h>
+
 #define FORCEWAKE_ACK_TIMEOUT_MS 2
 
 #define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
@@ -40,6 +42,26 @@
 
 #define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
 
+static const char * const forcewake_domain_names[] = {
+	"render",
+	"blitter",
+	"media",
+};
+
+const char *
+intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
+{
+	BUILD_BUG_ON((sizeof(forcewake_domain_names)/sizeof(const char *)) !=
+		     FW_DOMAIN_ID_COUNT);
+
+	if (id >= 0 && id < FW_DOMAIN_ID_COUNT)
+		return forcewake_domain_names[id];
+
+	WARN_ON(id);
+
+	return "unknown";
+}
+
 static void
 assert_device_not_suspended(struct drm_i915_private *dev_priv)
 {
@@ -47,6 +69,112 @@
 		  "Device suspended\n");
 }
 
+static inline void
+fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
+{
+	WARN_ON(d->reg_set == 0);
+	__raw_i915_write32(d->i915, d->reg_set, d->val_reset);
+}
+
+static inline void
+fw_domain_arm_timer(struct intel_uncore_forcewake_domain *d)
+{
+	mod_timer_pinned(&d->timer, jiffies + 1);
+}
+
+static inline void
+fw_domain_wait_ack_clear(const struct intel_uncore_forcewake_domain *d)
+{
+	if (wait_for_atomic((__raw_i915_read32(d->i915, d->reg_ack) &
+			     FORCEWAKE_KERNEL) == 0,
+			    FORCEWAKE_ACK_TIMEOUT_MS))
+		DRM_ERROR("%s: timed out waiting for forcewake ack to clear.\n",
+			  intel_uncore_forcewake_domain_to_str(d->id));
+}
+
+static inline void
+fw_domain_get(const struct intel_uncore_forcewake_domain *d)
+{
+	__raw_i915_write32(d->i915, d->reg_set, d->val_set);
+}
+
+static inline void
+fw_domain_wait_ack(const struct intel_uncore_forcewake_domain *d)
+{
+	if (wait_for_atomic((__raw_i915_read32(d->i915, d->reg_ack) &
+			     FORCEWAKE_KERNEL),
+			    FORCEWAKE_ACK_TIMEOUT_MS))
+		DRM_ERROR("%s: timed out waiting for forcewake ack request.\n",
+			  intel_uncore_forcewake_domain_to_str(d->id));
+}
+
+static inline void
+fw_domain_put(const struct intel_uncore_forcewake_domain *d)
+{
+	__raw_i915_write32(d->i915, d->reg_set, d->val_clear);
+}
+
+static inline void
+fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d)
+{
+	/* something from same cacheline, but not from the set register */
+	if (d->reg_post)
+		__raw_posting_read(d->i915, d->reg_post);
+}
+
+static void
+fw_domains_get(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
+{
+	struct intel_uncore_forcewake_domain *d;
+	enum forcewake_domain_id id;
+
+	for_each_fw_domain_mask(d, fw_domains, dev_priv, id) {
+		fw_domain_wait_ack_clear(d);
+		fw_domain_get(d);
+		fw_domain_wait_ack(d);
+	}
+}
+
+static void
+fw_domains_put(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
+{
+	struct intel_uncore_forcewake_domain *d;
+	enum forcewake_domain_id id;
+
+	for_each_fw_domain_mask(d, fw_domains, dev_priv, id) {
+		fw_domain_put(d);
+		fw_domain_posting_read(d);
+	}
+}
+
+static void
+fw_domains_posting_read(struct drm_i915_private *dev_priv)
+{
+	struct intel_uncore_forcewake_domain *d;
+	enum forcewake_domain_id id;
+
+	/* No need to do for all, just do for first found */
+	for_each_fw_domain(d, dev_priv, id) {
+		fw_domain_posting_read(d);
+		break;
+	}
+}
+
+static void
+fw_domains_reset(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
+{
+	struct intel_uncore_forcewake_domain *d;
+	enum forcewake_domain_id id;
+
+	if (dev_priv->uncore.fw_domains == 0)
+		return;
+
+	for_each_fw_domain_mask(d, fw_domains, dev_priv, id)
+		fw_domain_reset(d);
+
+	fw_domains_posting_read(dev_priv);
+}
+
 static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
 {
 	/* w/a for a sporadic read returning 0 by waiting for the GT
@@ -57,63 +185,12 @@
 		DRM_ERROR("GT thread status wait timed out\n");
 }
 
-static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv)
+static void fw_domains_get_with_thread_status(struct drm_i915_private *dev_priv,
+					      enum forcewake_domains fw_domains)
 {
-	__raw_i915_write32(dev_priv, FORCEWAKE, 0);
-	/* something from same cacheline, but !FORCEWAKE */
-	__raw_posting_read(dev_priv, ECOBUS);
-}
+	fw_domains_get(dev_priv, fw_domains);
 
-static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv,
-							int fw_engine)
-{
-	if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0,
-			    FORCEWAKE_ACK_TIMEOUT_MS))
-		DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
-
-	__raw_i915_write32(dev_priv, FORCEWAKE, 1);
-	/* something from same cacheline, but !FORCEWAKE */
-	__raw_posting_read(dev_priv, ECOBUS);
-
-	if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1),
-			    FORCEWAKE_ACK_TIMEOUT_MS))
-		DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
-
-	/* WaRsForcewakeWaitTC0:snb */
-	__gen6_gt_wait_for_thread_c0(dev_priv);
-}
-
-static void __gen7_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
-{
-	__raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff));
-	/* something from same cacheline, but !FORCEWAKE_MT */
-	__raw_posting_read(dev_priv, ECOBUS);
-}
-
-static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
-							int fw_engine)
-{
-	u32 forcewake_ack;
-
-	if (IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))
-		forcewake_ack = FORCEWAKE_ACK_HSW;
-	else
-		forcewake_ack = FORCEWAKE_MT_ACK;
-
-	if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL) == 0,
-			    FORCEWAKE_ACK_TIMEOUT_MS))
-		DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
-
-	__raw_i915_write32(dev_priv, FORCEWAKE_MT,
-			   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-	/* something from same cacheline, but !FORCEWAKE_MT */
-	__raw_posting_read(dev_priv, ECOBUS);
-
-	if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL),
-			    FORCEWAKE_ACK_TIMEOUT_MS))
-		DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
-
-	/* WaRsForcewakeWaitTC0:ivb,hsw */
+	/* WaRsForcewakeWaitTC0:snb,ivb,hsw,bdw,vlv */
 	__gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
@@ -126,27 +203,13 @@
 		__raw_i915_write32(dev_priv, GTFIFODBG, gtfifodbg);
 }
 
-static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv,
-							int fw_engine)
+static void fw_domains_put_with_fifo(struct drm_i915_private *dev_priv,
+				     enum forcewake_domains fw_domains)
 {
-	__raw_i915_write32(dev_priv, FORCEWAKE, 0);
-	/* something from same cacheline, but !FORCEWAKE */
-	__raw_posting_read(dev_priv, ECOBUS);
+	fw_domains_put(dev_priv, fw_domains);
 	gen6_gt_check_fifodbg(dev_priv);
 }
 
-static void __gen7_gt_force_wake_mt_put(struct drm_i915_private *dev_priv,
-							int fw_engine)
-{
-	__raw_i915_write32(dev_priv, FORCEWAKE_MT,
-			   _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-	/* something from same cacheline, but !FORCEWAKE_MT */
-	__raw_posting_read(dev_priv, ECOBUS);
-
-	if (IS_GEN7(dev_priv->dev))
-		gen6_gt_check_fifodbg(dev_priv);
-}
-
 static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
 	int ret = 0;
@@ -174,332 +237,78 @@
 	return ret;
 }
 
-static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
+static void intel_uncore_fw_release_timer(unsigned long arg)
 {
-	__raw_i915_write32(dev_priv, FORCEWAKE_VLV,
-			   _MASKED_BIT_DISABLE(0xffff));
-	__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
-			   _MASKED_BIT_DISABLE(0xffff));
-	/* something from same cacheline, but !FORCEWAKE_VLV */
-	__raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
-}
-
-static void __vlv_force_wake_get(struct drm_i915_private *dev_priv,
-						int fw_engine)
-{
-	/* Check for Render Engine */
-	if (FORCEWAKE_RENDER & fw_engine) {
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_VLV) &
-						FORCEWAKE_KERNEL) == 0,
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: Render forcewake old ack to clear.\n");
-
-		__raw_i915_write32(dev_priv, FORCEWAKE_VLV,
-				   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_VLV) &
-						FORCEWAKE_KERNEL),
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: waiting for Render to ack.\n");
-	}
-
-	/* Check for Media Engine */
-	if (FORCEWAKE_MEDIA & fw_engine) {
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_MEDIA_VLV) &
-						FORCEWAKE_KERNEL) == 0,
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: Media forcewake old ack to clear.\n");
-
-		__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
-				   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_MEDIA_VLV) &
-						FORCEWAKE_KERNEL),
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: waiting for media to ack.\n");
-	}
-}
-
-static void __vlv_force_wake_put(struct drm_i915_private *dev_priv,
-					int fw_engine)
-{
-
-	/* Check for Render Engine */
-	if (FORCEWAKE_RENDER & fw_engine)
-		__raw_i915_write32(dev_priv, FORCEWAKE_VLV,
-					_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
-
-	/* Check for Media Engine */
-	if (FORCEWAKE_MEDIA & fw_engine)
-		__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
-				_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
-	/* something from same cacheline, but !FORCEWAKE_VLV */
-	__raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
-	if (!IS_CHERRYVIEW(dev_priv->dev))
-		gen6_gt_check_fifodbg(dev_priv);
-}
-
-static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
-{
+	struct intel_uncore_forcewake_domain *domain = (void *)arg;
 	unsigned long irqflags;
 
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+	assert_device_not_suspended(domain->i915);
 
-	if (fw_engine & FORCEWAKE_RENDER &&
-	    dev_priv->uncore.fw_rendercount++ != 0)
-		fw_engine &= ~FORCEWAKE_RENDER;
-	if (fw_engine & FORCEWAKE_MEDIA &&
-	    dev_priv->uncore.fw_mediacount++ != 0)
-		fw_engine &= ~FORCEWAKE_MEDIA;
+	spin_lock_irqsave(&domain->i915->uncore.lock, irqflags);
+	if (WARN_ON(domain->wake_count == 0))
+		domain->wake_count++;
 
-	if (fw_engine)
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine);
+	if (--domain->wake_count == 0)
+		domain->i915->uncore.funcs.force_wake_put(domain->i915,
+							  1 << domain->id);
 
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	if (fw_engine & FORCEWAKE_RENDER) {
-		WARN_ON(!dev_priv->uncore.fw_rendercount);
-		if (--dev_priv->uncore.fw_rendercount != 0)
-			fw_engine &= ~FORCEWAKE_RENDER;
-	}
-
-	if (fw_engine & FORCEWAKE_MEDIA) {
-		WARN_ON(!dev_priv->uncore.fw_mediacount);
-		if (--dev_priv->uncore.fw_mediacount != 0)
-			fw_engine &= ~FORCEWAKE_MEDIA;
-	}
-
-	if (fw_engine)
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine);
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void __gen9_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
-{
-	__raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
-			_MASKED_BIT_DISABLE(0xffff));
-
-	__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
-			_MASKED_BIT_DISABLE(0xffff));
-
-	__raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
-			_MASKED_BIT_DISABLE(0xffff));
-}
-
-static void
-__gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
-{
-	/* Check for Render Engine */
-	if (FORCEWAKE_RENDER & fw_engine) {
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_RENDER_GEN9) &
-						FORCEWAKE_KERNEL) == 0,
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: Render forcewake old ack to clear.\n");
-
-		__raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
-				   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_RENDER_GEN9) &
-						FORCEWAKE_KERNEL),
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: waiting for Render to ack.\n");
-	}
-
-	/* Check for Media Engine */
-	if (FORCEWAKE_MEDIA & fw_engine) {
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_MEDIA_GEN9) &
-						FORCEWAKE_KERNEL) == 0,
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: Media forcewake old ack to clear.\n");
-
-		__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
-				   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_MEDIA_GEN9) &
-						FORCEWAKE_KERNEL),
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: waiting for Media to ack.\n");
-	}
-
-	/* Check for Blitter Engine */
-	if (FORCEWAKE_BLITTER & fw_engine) {
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_BLITTER_GEN9) &
-						FORCEWAKE_KERNEL) == 0,
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: Blitter forcewake old ack to clear.\n");
-
-		__raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
-				   _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
-		if (wait_for_atomic((__raw_i915_read32(dev_priv,
-						FORCEWAKE_ACK_BLITTER_GEN9) &
-						FORCEWAKE_KERNEL),
-					FORCEWAKE_ACK_TIMEOUT_MS))
-			DRM_ERROR("Timed out: waiting for Blitter to ack.\n");
-	}
-}
-
-static void
-__gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
-	/* Check for Render Engine */
-	if (FORCEWAKE_RENDER & fw_engine)
-		__raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
-				_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
-	/* Check for Media Engine */
-	if (FORCEWAKE_MEDIA & fw_engine)
-		__raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
-				_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
-	/* Check for Blitter Engine */
-	if (FORCEWAKE_BLITTER & fw_engine)
-		__raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
-				_MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-}
-
-static void
-gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
-{
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	if (FORCEWAKE_RENDER & fw_engine) {
-		if (dev_priv->uncore.fw_rendercount++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							FORCEWAKE_RENDER);
-	}
-
-	if (FORCEWAKE_MEDIA & fw_engine) {
-		if (dev_priv->uncore.fw_mediacount++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							FORCEWAKE_MEDIA);
-	}
-
-	if (FORCEWAKE_BLITTER & fw_engine) {
-		if (dev_priv->uncore.fw_blittercount++ == 0)
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,
-							FORCEWAKE_BLITTER);
-	}
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void
-gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	if (FORCEWAKE_RENDER & fw_engine) {
-		WARN_ON(dev_priv->uncore.fw_rendercount == 0);
-		if (--dev_priv->uncore.fw_rendercount == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							FORCEWAKE_RENDER);
-	}
-
-	if (FORCEWAKE_MEDIA & fw_engine) {
-		WARN_ON(dev_priv->uncore.fw_mediacount == 0);
-		if (--dev_priv->uncore.fw_mediacount == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							FORCEWAKE_MEDIA);
-	}
-
-	if (FORCEWAKE_BLITTER & fw_engine) {
-		WARN_ON(dev_priv->uncore.fw_blittercount == 0);
-		if (--dev_priv->uncore.fw_blittercount == 0)
-			dev_priv->uncore.funcs.force_wake_put(dev_priv,
-							FORCEWAKE_BLITTER);
-	}
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void gen6_force_wake_timer(unsigned long arg)
-{
-	struct drm_i915_private *dev_priv = (void *)arg;
-	unsigned long irqflags;
-
-	assert_device_not_suspended(dev_priv);
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-	WARN_ON(!dev_priv->uncore.forcewake_count);
-
-	if (--dev_priv->uncore.forcewake_count == 0)
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-
-	intel_runtime_pm_put(dev_priv);
+	spin_unlock_irqrestore(&domain->i915->uncore.lock, irqflags);
 }
 
 void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
-
-	if (del_timer_sync(&dev_priv->uncore.force_wake_timer))
-		gen6_force_wake_timer((unsigned long)dev_priv);
+	struct intel_uncore_forcewake_domain *domain;
+	int retry_count = 100;
+	enum forcewake_domain_id id;
+	enum forcewake_domains fw = 0, active_domains;
 
 	/* Hold uncore.lock across reset to prevent any register access
-	 * with forcewake not set correctly
+	 * with forcewake not set correctly. Wait until all pending
+	 * timers are run before holding.
 	 */
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+	while (1) {
+		active_domains = 0;
 
-	if (IS_VALLEYVIEW(dev))
-		vlv_force_wake_reset(dev_priv);
-	else if (IS_GEN6(dev) || IS_GEN7(dev))
-		__gen6_gt_force_wake_reset(dev_priv);
+		for_each_fw_domain(domain, dev_priv, id) {
+			if (del_timer_sync(&domain->timer) == 0)
+				continue;
 
-	if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
-		__gen7_gt_force_wake_mt_reset(dev_priv);
-
-	if (IS_GEN9(dev))
-		__gen9_gt_force_wake_mt_reset(dev_priv);
-
-	if (restore) { /* If reset with a user forcewake, try to restore */
-		unsigned fw = 0;
-
-		if (IS_VALLEYVIEW(dev)) {
-			if (dev_priv->uncore.fw_rendercount)
-				fw |= FORCEWAKE_RENDER;
-
-			if (dev_priv->uncore.fw_mediacount)
-				fw |= FORCEWAKE_MEDIA;
-		} else if (IS_GEN9(dev)) {
-			if (dev_priv->uncore.fw_rendercount)
-				fw |= FORCEWAKE_RENDER;
-
-			if (dev_priv->uncore.fw_mediacount)
-				fw |= FORCEWAKE_MEDIA;
-
-			if (dev_priv->uncore.fw_blittercount)
-				fw |= FORCEWAKE_BLITTER;
-		} else {
-			if (dev_priv->uncore.forcewake_count)
-				fw = FORCEWAKE_ALL;
+			intel_uncore_fw_release_timer((unsigned long)domain);
 		}
 
+		spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+		for_each_fw_domain(domain, dev_priv, id) {
+			if (timer_pending(&domain->timer))
+				active_domains |= (1 << id);
+		}
+
+		if (active_domains == 0)
+			break;
+
+		if (--retry_count == 0) {
+			DRM_ERROR("Timed out waiting for forcewake timers to finish\n");
+			break;
+		}
+
+		spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+		cond_resched();
+	}
+
+	WARN_ON(active_domains);
+
+	for_each_fw_domain(domain, dev_priv, id)
+		if (domain->wake_count)
+			fw |= 1 << id;
+
+	if (fw)
+		dev_priv->uncore.funcs.force_wake_put(dev_priv, fw);
+
+	fw_domains_reset(dev_priv, FORCEWAKE_ALL);
+
+	if (restore) { /* If reset with a user forcewake, try to restore */
 		if (fw)
 			dev_priv->uncore.funcs.force_wake_get(dev_priv, fw);
 
@@ -509,17 +318,16 @@
 				GT_FIFO_FREE_ENTRIES_MASK;
 	}
 
+	if (!restore)
+		assert_forcewakes_inactive(dev_priv);
+
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-static void __intel_uncore_early_sanitize(struct drm_device *dev,
-					  bool restore_forcewake)
+static void intel_uncore_ellc_detect(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (HAS_FPGA_DBG_UNCLAIMED(dev))
-		__raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-
 	if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
 	    (__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) {
 		/* The docs do not explain exactly how the calculation can be
@@ -530,6 +338,15 @@
 		dev_priv->ellc_size = 128;
 		DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size);
 	}
+}
+
+static void __intel_uncore_early_sanitize(struct drm_device *dev,
+					  bool restore_forcewake)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (HAS_FPGA_DBG_UNCLAIMED(dev))
+		__raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
 
 	/* clear out old GT FIFO errors */
 	if (IS_GEN6(dev) || IS_GEN7(dev))
@@ -551,81 +368,92 @@
 	intel_disable_gt_powersave(dev);
 }
 
-/*
- * Generally this is called implicitly by the register read function. However,
- * if some sequence requires the GT to not power down then this function should
- * be called at the beginning of the sequence followed by a call to
- * gen6_gt_force_wake_put() at the end of the sequence.
+/**
+ * intel_uncore_forcewake_get - grab forcewake domain references
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to get reference on
+ *
+ * This function can be used get GT's forcewake domain references.
+ * Normal register access will handle the forcewake domains automatically.
+ * However if some sequence requires the GT to not power down a particular
+ * forcewake domains this function should be called at the beginning of the
+ * sequence. And subsequently the reference should be dropped by symmetric
+ * call to intel_unforce_forcewake_put(). Usually caller wants all the domains
+ * to be kept awake so the @fw_domains would be then FORCEWAKE_ALL.
  */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
+void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
+				enum forcewake_domains fw_domains)
 {
 	unsigned long irqflags;
+	struct intel_uncore_forcewake_domain *domain;
+	enum forcewake_domain_id id;
 
 	if (!dev_priv->uncore.funcs.force_wake_get)
 		return;
 
-	intel_runtime_pm_get(dev_priv);
+	WARN_ON(dev_priv->pm.suspended);
 
-	/* Redirect to Gen9 specific routine */
-	if (IS_GEN9(dev_priv->dev))
-		return gen9_force_wake_get(dev_priv, fw_engine);
-
-	/* Redirect to VLV specific routine */
-	if (IS_VALLEYVIEW(dev_priv->dev))
-		return vlv_force_wake_get(dev_priv, fw_engine);
+	fw_domains &= dev_priv->uncore.fw_domains;
 
 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-	if (dev_priv->uncore.forcewake_count++ == 0)
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+
+	for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+		if (domain->wake_count++)
+			fw_domains &= ~(1 << id);
+	}
+
+	if (fw_domains)
+		dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
+
 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-/*
- * see gen6_gt_force_wake_get()
+/**
+ * intel_uncore_forcewake_put - release a forcewake domain reference
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to put references
+ *
+ * This function drops the device-level forcewakes for specified
+ * domains obtained by intel_uncore_forcewake_get().
  */
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
+void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+				enum forcewake_domains fw_domains)
 {
 	unsigned long irqflags;
-	bool delayed = false;
+	struct intel_uncore_forcewake_domain *domain;
+	enum forcewake_domain_id id;
 
 	if (!dev_priv->uncore.funcs.force_wake_put)
 		return;
 
-	/* Redirect to Gen9 specific routine */
-	if (IS_GEN9(dev_priv->dev)) {
-		gen9_force_wake_put(dev_priv, fw_engine);
-		goto out;
-	}
-
-	/* Redirect to VLV specific routine */
-	if (IS_VALLEYVIEW(dev_priv->dev)) {
-		vlv_force_wake_put(dev_priv, fw_engine);
-		goto out;
-	}
-
+	fw_domains &= dev_priv->uncore.fw_domains;
 
 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-	WARN_ON(!dev_priv->uncore.forcewake_count);
 
-	if (--dev_priv->uncore.forcewake_count == 0) {
-		dev_priv->uncore.forcewake_count++;
-		delayed = true;
-		mod_timer_pinned(&dev_priv->uncore.force_wake_timer,
-				 jiffies + 1);
+	for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+		if (WARN_ON(domain->wake_count == 0))
+			continue;
+
+		if (--domain->wake_count)
+			continue;
+
+		domain->wake_count++;
+		fw_domain_arm_timer(domain);
 	}
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 
-out:
-	if (!delayed)
-		intel_runtime_pm_put(dev_priv);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
+void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
 {
+	struct intel_uncore_forcewake_domain *domain;
+	enum forcewake_domain_id id;
+
 	if (!dev_priv->uncore.funcs.force_wake_get)
 		return;
 
-	WARN_ON(dev_priv->uncore.forcewake_count > 0);
+	for_each_fw_domain(domain, dev_priv, id)
+		WARN_ON(domain->wake_count);
 }
 
 /* We give fast paths for the really cool registers */
@@ -647,9 +475,9 @@
 
 #define FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg) \
 	(REG_RANGE((reg), 0x2000, 0x4000) || \
-	 REG_RANGE((reg), 0x5000, 0x8000) || \
+	 REG_RANGE((reg), 0x5200, 0x8000) || \
 	 REG_RANGE((reg), 0x8300, 0x8500) || \
-	 REG_RANGE((reg), 0xB000, 0xC000) || \
+	 REG_RANGE((reg), 0xB000, 0xB480) || \
 	 REG_RANGE((reg), 0xE000, 0xE800))
 
 #define FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg) \
@@ -658,17 +486,14 @@
 	 REG_RANGE((reg), 0x12000, 0x14000) || \
 	 REG_RANGE((reg), 0x1A000, 0x1C000) || \
 	 REG_RANGE((reg), 0x1E800, 0x1EA00) || \
-	 REG_RANGE((reg), 0x30000, 0x40000))
+	 REG_RANGE((reg), 0x30000, 0x38000))
 
 #define FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg) \
 	(REG_RANGE((reg), 0x4000, 0x5000) || \
 	 REG_RANGE((reg), 0x8000, 0x8300) || \
 	 REG_RANGE((reg), 0x8500, 0x8600) || \
 	 REG_RANGE((reg), 0x9000, 0xB000) || \
-	 REG_RANGE((reg), 0xC000, 0xC800) || \
-	 REG_RANGE((reg), 0xF000, 0x10000) || \
-	 REG_RANGE((reg), 0x14000, 0x14400) || \
-	 REG_RANGE((reg), 0x22000, 0x24000))
+	 REG_RANGE((reg), 0xF000, 0x10000))
 
 #define FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) \
 	REG_RANGE((reg), 0xB00,  0x2000)
@@ -740,96 +565,118 @@
 	}
 }
 
-#define REG_READ_HEADER(x) \
-	unsigned long irqflags; \
+#define GEN2_READ_HEADER(x) \
 	u##x val = 0; \
-	assert_device_not_suspended(dev_priv); \
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+	assert_device_not_suspended(dev_priv);
 
-#define REG_READ_FOOTER \
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+#define GEN2_READ_FOOTER \
 	trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
 	return val
 
-#define __gen4_read(x) \
+#define __gen2_read(x) \
 static u##x \
-gen4_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	REG_READ_HEADER(x); \
+gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+	GEN2_READ_HEADER(x); \
 	val = __raw_i915_read##x(dev_priv, reg); \
-	REG_READ_FOOTER; \
+	GEN2_READ_FOOTER; \
 }
 
 #define __gen5_read(x) \
 static u##x \
 gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	REG_READ_HEADER(x); \
+	GEN2_READ_HEADER(x); \
 	ilk_dummy_write(dev_priv); \
 	val = __raw_i915_read##x(dev_priv, reg); \
-	REG_READ_FOOTER; \
+	GEN2_READ_FOOTER; \
+}
+
+__gen5_read(8)
+__gen5_read(16)
+__gen5_read(32)
+__gen5_read(64)
+__gen2_read(8)
+__gen2_read(16)
+__gen2_read(32)
+__gen2_read(64)
+
+#undef __gen5_read
+#undef __gen2_read
+
+#undef GEN2_READ_FOOTER
+#undef GEN2_READ_HEADER
+
+#define GEN6_READ_HEADER(x) \
+	unsigned long irqflags; \
+	u##x val = 0; \
+	assert_device_not_suspended(dev_priv); \
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define GEN6_READ_FOOTER \
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+	trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+	return val
+
+static inline void __force_wake_get(struct drm_i915_private *dev_priv,
+				    enum forcewake_domains fw_domains)
+{
+	struct intel_uncore_forcewake_domain *domain;
+	enum forcewake_domain_id id;
+
+	if (WARN_ON(!fw_domains))
+		return;
+
+	/* Ideally GCC would be constant-fold and eliminate this loop */
+	for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+		if (domain->wake_count) {
+			fw_domains &= ~(1 << id);
+			continue;
+		}
+
+		domain->wake_count++;
+		fw_domain_arm_timer(domain);
+	}
+
+	if (fw_domains)
+		dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
 }
 
 #define __gen6_read(x) \
 static u##x \
 gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	REG_READ_HEADER(x); \
+	GEN6_READ_HEADER(x); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
-	if (dev_priv->uncore.forcewake_count == 0 && \
-	    NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, \
-						      FORCEWAKE_ALL); \
-		val = __raw_i915_read##x(dev_priv, reg); \
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, \
-						      FORCEWAKE_ALL); \
-	} else { \
-		val = __raw_i915_read##x(dev_priv, reg); \
-	} \
+	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+	val = __raw_i915_read##x(dev_priv, reg); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
-	REG_READ_FOOTER; \
+	GEN6_READ_FOOTER; \
 }
 
 #define __vlv_read(x) \
 static u##x \
 vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	unsigned fwengine = 0; \
-	REG_READ_HEADER(x); \
-	if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \
-		if (dev_priv->uncore.fw_rendercount == 0) \
-			fwengine = FORCEWAKE_RENDER; \
-	} else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \
-		if (dev_priv->uncore.fw_mediacount == 0) \
-			fwengine = FORCEWAKE_MEDIA; \
-	}  \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
+	GEN6_READ_HEADER(x); \
+	if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \
+		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+	else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \
+		__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
 	val = __raw_i915_read##x(dev_priv, reg); \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
-	REG_READ_FOOTER; \
+	GEN6_READ_FOOTER; \
 }
 
 #define __chv_read(x) \
 static u##x \
 chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	unsigned fwengine = 0; \
-	REG_READ_HEADER(x); \
-	if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) { \
-		if (dev_priv->uncore.fw_rendercount == 0) \
-			fwengine = FORCEWAKE_RENDER; \
-	} else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) { \
-		if (dev_priv->uncore.fw_mediacount == 0) \
-			fwengine = FORCEWAKE_MEDIA; \
-	} else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) { \
-		if (dev_priv->uncore.fw_rendercount == 0) \
-			fwengine |= FORCEWAKE_RENDER; \
-		if (dev_priv->uncore.fw_mediacount == 0) \
-			fwengine |= FORCEWAKE_MEDIA; \
-	} \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
+	GEN6_READ_HEADER(x); \
+	if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
+		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+	else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
+		__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+	else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
+		__force_wake_get(dev_priv, \
+				 FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
 	val = __raw_i915_read##x(dev_priv, reg); \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
-	REG_READ_FOOTER; \
+	GEN6_READ_FOOTER; \
 }
 
 #define SKL_NEEDS_FORCE_WAKE(dev_priv, reg)	\
@@ -838,33 +685,22 @@
 #define __gen9_read(x) \
 static u##x \
 gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
-	REG_READ_HEADER(x); \
-	if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-		val = __raw_i915_read##x(dev_priv, reg); \
-	} else { \
-		unsigned fwengine = 0; \
-		if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine = FORCEWAKE_RENDER; \
-		} else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine = FORCEWAKE_MEDIA; \
-		} else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine |= FORCEWAKE_RENDER; \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine |= FORCEWAKE_MEDIA; \
-		} else { \
-			if (dev_priv->uncore.fw_blittercount == 0) \
-				fwengine = FORCEWAKE_BLITTER; \
-		} \
-		if (fwengine) \
-			dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
-		val = __raw_i915_read##x(dev_priv, reg); \
-		if (fwengine) \
-			dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
-	} \
-	REG_READ_FOOTER; \
+	enum forcewake_domains fw_engine; \
+	GEN6_READ_HEADER(x); \
+	if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)))	\
+		fw_engine = 0; \
+	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg))	\
+		fw_engine = FORCEWAKE_RENDER; \
+	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+		fw_engine = FORCEWAKE_MEDIA; \
+	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+	else \
+		fw_engine = FORCEWAKE_BLITTER; \
+	if (fw_engine) \
+		__force_wake_get(dev_priv, fw_engine); \
+	val = __raw_i915_read##x(dev_priv, reg); \
+	GEN6_READ_FOOTER; \
 }
 
 __gen9_read(8)
@@ -883,55 +719,66 @@
 __gen6_read(16)
 __gen6_read(32)
 __gen6_read(64)
-__gen5_read(8)
-__gen5_read(16)
-__gen5_read(32)
-__gen5_read(64)
-__gen4_read(8)
-__gen4_read(16)
-__gen4_read(32)
-__gen4_read(64)
 
 #undef __gen9_read
 #undef __chv_read
 #undef __vlv_read
 #undef __gen6_read
-#undef __gen5_read
-#undef __gen4_read
-#undef REG_READ_FOOTER
-#undef REG_READ_HEADER
+#undef GEN6_READ_FOOTER
+#undef GEN6_READ_HEADER
 
-#define REG_WRITE_HEADER \
-	unsigned long irqflags; \
+#define GEN2_WRITE_HEADER \
 	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
 	assert_device_not_suspended(dev_priv); \
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 
-#define REG_WRITE_FOOTER \
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+#define GEN2_WRITE_FOOTER
 
-#define __gen4_write(x) \
+#define __gen2_write(x) \
 static void \
-gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-	REG_WRITE_HEADER; \
+gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+	GEN2_WRITE_HEADER; \
 	__raw_i915_write##x(dev_priv, reg, val); \
-	REG_WRITE_FOOTER; \
+	GEN2_WRITE_FOOTER; \
 }
 
 #define __gen5_write(x) \
 static void \
 gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-	REG_WRITE_HEADER; \
+	GEN2_WRITE_HEADER; \
 	ilk_dummy_write(dev_priv); \
 	__raw_i915_write##x(dev_priv, reg, val); \
-	REG_WRITE_FOOTER; \
+	GEN2_WRITE_FOOTER; \
 }
 
+__gen5_write(8)
+__gen5_write(16)
+__gen5_write(32)
+__gen5_write(64)
+__gen2_write(8)
+__gen2_write(16)
+__gen2_write(32)
+__gen2_write(64)
+
+#undef __gen5_write
+#undef __gen2_write
+
+#undef GEN2_WRITE_FOOTER
+#undef GEN2_WRITE_HEADER
+
+#define GEN6_WRITE_HEADER \
+	unsigned long irqflags; \
+	trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+	assert_device_not_suspended(dev_priv); \
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define GEN6_WRITE_FOOTER \
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+
 #define __gen6_write(x) \
 static void \
 gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 	u32 __fifo_ret = 0; \
-	REG_WRITE_HEADER; \
+	GEN6_WRITE_HEADER; \
 	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
 		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
@@ -939,14 +786,14 @@
 	if (unlikely(__fifo_ret)) { \
 		gen6_gt_check_fifodbg(dev_priv); \
 	} \
-	REG_WRITE_FOOTER; \
+	GEN6_WRITE_FOOTER; \
 }
 
 #define __hsw_write(x) \
 static void \
 hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
 	u32 __fifo_ret = 0; \
-	REG_WRITE_HEADER; \
+	GEN6_WRITE_HEADER; \
 	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
 		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
@@ -957,7 +804,7 @@
 	} \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
 	hsw_unclaimed_reg_detect(dev_priv); \
-	REG_WRITE_FOOTER; \
+	GEN6_WRITE_FOOTER; \
 }
 
 static const u32 gen8_shadowed_regs[] = {
@@ -984,50 +831,31 @@
 #define __gen8_write(x) \
 static void \
 gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-	REG_WRITE_HEADER; \
+	GEN6_WRITE_HEADER; \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
-	if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) { \
-		if (dev_priv->uncore.forcewake_count == 0) \
-			dev_priv->uncore.funcs.force_wake_get(dev_priv,	\
-							      FORCEWAKE_ALL); \
-		__raw_i915_write##x(dev_priv, reg, val); \
-		if (dev_priv->uncore.forcewake_count == 0) \
-			dev_priv->uncore.funcs.force_wake_put(dev_priv, \
-							      FORCEWAKE_ALL); \
-	} else { \
-		__raw_i915_write##x(dev_priv, reg, val); \
-	} \
+	if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \
+		__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+	__raw_i915_write##x(dev_priv, reg, val); \
 	hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
 	hsw_unclaimed_reg_detect(dev_priv); \
-	REG_WRITE_FOOTER; \
+	GEN6_WRITE_FOOTER; \
 }
 
 #define __chv_write(x) \
 static void \
 chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-	unsigned fwengine = 0; \
 	bool shadowed = is_gen8_shadowed(dev_priv, reg); \
-	REG_WRITE_HEADER; \
+	GEN6_WRITE_HEADER; \
 	if (!shadowed) { \
-		if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine = FORCEWAKE_RENDER; \
-		} else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine = FORCEWAKE_MEDIA; \
-		} else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine |= FORCEWAKE_RENDER; \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine |= FORCEWAKE_MEDIA; \
-		} \
+		if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
+			__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+		else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
+			__force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+		else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
+			__force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
 	} \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
 	__raw_i915_write##x(dev_priv, reg, val); \
-	if (fwengine) \
-		dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
-	REG_WRITE_FOOTER; \
+	GEN6_WRITE_FOOTER; \
 }
 
 static const u32 gen9_shadowed_regs[] = {
@@ -1057,36 +885,23 @@
 static void \
 gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
 		bool trace) { \
-	REG_WRITE_HEADER; \
-	if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) || \
-			is_gen9_shadowed(dev_priv, reg)) { \
-		__raw_i915_write##x(dev_priv, reg, val); \
-	} else { \
-		unsigned fwengine = 0; \
-		if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine = FORCEWAKE_RENDER; \
-		} else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine = FORCEWAKE_MEDIA; \
-		} else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) { \
-			if (dev_priv->uncore.fw_rendercount == 0) \
-				fwengine |= FORCEWAKE_RENDER; \
-			if (dev_priv->uncore.fw_mediacount == 0) \
-				fwengine |= FORCEWAKE_MEDIA; \
-		} else { \
-			if (dev_priv->uncore.fw_blittercount == 0) \
-				fwengine = FORCEWAKE_BLITTER; \
-		} \
-		if (fwengine) \
-			dev_priv->uncore.funcs.force_wake_get(dev_priv, \
-					fwengine); \
-		__raw_i915_write##x(dev_priv, reg, val); \
-		if (fwengine) \
-			dev_priv->uncore.funcs.force_wake_put(dev_priv, \
-					fwengine); \
-	} \
-	REG_WRITE_FOOTER; \
+	enum forcewake_domains fw_engine; \
+	GEN6_WRITE_HEADER; \
+	if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) ||	\
+	    is_gen9_shadowed(dev_priv, reg)) \
+		fw_engine = 0; \
+	else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+		fw_engine = FORCEWAKE_RENDER; \
+	else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+		fw_engine = FORCEWAKE_MEDIA; \
+	else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+		fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+	else \
+		fw_engine = FORCEWAKE_BLITTER; \
+	if (fw_engine) \
+		__force_wake_get(dev_priv, fw_engine); \
+	__raw_i915_write##x(dev_priv, reg, val); \
+	GEN6_WRITE_FOOTER; \
 }
 
 __gen9_write(8)
@@ -1109,24 +924,14 @@
 __gen6_write(16)
 __gen6_write(32)
 __gen6_write(64)
-__gen5_write(8)
-__gen5_write(16)
-__gen5_write(32)
-__gen5_write(64)
-__gen4_write(8)
-__gen4_write(16)
-__gen4_write(32)
-__gen4_write(64)
 
 #undef __gen9_write
 #undef __chv_write
 #undef __gen8_write
 #undef __hsw_write
 #undef __gen6_write
-#undef __gen5_write
-#undef __gen4_write
-#undef REG_WRITE_FOOTER
-#undef REG_WRITE_HEADER
+#undef GEN6_WRITE_FOOTER
+#undef GEN6_WRITE_HEADER
 
 #define ASSIGN_WRITE_MMIO_VFUNCS(x) \
 do { \
@@ -1144,24 +949,86 @@
 	dev_priv->uncore.funcs.mmio_readq = x##_read64; \
 } while (0)
 
-void intel_uncore_init(struct drm_device *dev)
+
+static void fw_domain_init(struct drm_i915_private *dev_priv,
+			   enum forcewake_domain_id domain_id,
+			   u32 reg_set, u32 reg_ack)
+{
+	struct intel_uncore_forcewake_domain *d;
+
+	if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
+		return;
+
+	d = &dev_priv->uncore.fw_domain[domain_id];
+
+	WARN_ON(d->wake_count);
+
+	d->wake_count = 0;
+	d->reg_set = reg_set;
+	d->reg_ack = reg_ack;
+
+	if (IS_GEN6(dev_priv)) {
+		d->val_reset = 0;
+		d->val_set = FORCEWAKE_KERNEL;
+		d->val_clear = 0;
+	} else {
+		d->val_reset = _MASKED_BIT_DISABLE(0xffff);
+		d->val_set = _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL);
+		d->val_clear = _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL);
+	}
+
+	if (IS_VALLEYVIEW(dev_priv))
+		d->reg_post = FORCEWAKE_ACK_VLV;
+	else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv))
+		d->reg_post = ECOBUS;
+	else
+		d->reg_post = 0;
+
+	d->i915 = dev_priv;
+	d->id = domain_id;
+
+	setup_timer(&d->timer, intel_uncore_fw_release_timer, (unsigned long)d);
+
+	dev_priv->uncore.fw_domains |= (1 << domain_id);
+
+	fw_domain_reset(d);
+}
+
+static void intel_uncore_fw_domains_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	setup_timer(&dev_priv->uncore.force_wake_timer,
-		    gen6_force_wake_timer, (unsigned long)dev_priv);
-
-	__intel_uncore_early_sanitize(dev, false);
+	if (INTEL_INFO(dev_priv->dev)->gen <= 5)
+		return;
 
 	if (IS_GEN9(dev)) {
-		dev_priv->uncore.funcs.force_wake_get = __gen9_force_wake_get;
-		dev_priv->uncore.funcs.force_wake_put = __gen9_force_wake_put;
+		dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
+		dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+			       FORCEWAKE_RENDER_GEN9,
+			       FORCEWAKE_ACK_RENDER_GEN9);
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_BLITTER,
+			       FORCEWAKE_BLITTER_GEN9,
+			       FORCEWAKE_ACK_BLITTER_GEN9);
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA,
+			       FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
 	} else if (IS_VALLEYVIEW(dev)) {
-		dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get;
-		dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put;
+		dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
+		if (!IS_CHERRYVIEW(dev))
+			dev_priv->uncore.funcs.force_wake_put =
+				fw_domains_put_with_fifo;
+		else
+			dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+			       FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA,
+			       FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
 	} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-		dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get;
-		dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put;
+		dev_priv->uncore.funcs.force_wake_get =
+			fw_domains_get_with_thread_status;
+		dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+			       FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
 	} else if (IS_IVYBRIDGE(dev)) {
 		u32 ecobus;
 
@@ -1174,35 +1041,54 @@
 		 * (correctly) interpreted by the test below as MT
 		 * forcewake being disabled.
 		 */
+		dev_priv->uncore.funcs.force_wake_get =
+			fw_domains_get_with_thread_status;
+		dev_priv->uncore.funcs.force_wake_put =
+			fw_domains_put_with_fifo;
+
+		/* We need to init first for ECOBUS access and then
+		 * determine later if we want to reinit, in case of MT access is
+		 * not working
+		 */
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+			       FORCEWAKE_MT, FORCEWAKE_MT_ACK);
+
 		mutex_lock(&dev->struct_mutex);
-		__gen7_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL);
+		fw_domains_get_with_thread_status(dev_priv, FORCEWAKE_ALL);
 		ecobus = __raw_i915_read32(dev_priv, ECOBUS);
-		__gen7_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL);
+		fw_domains_put_with_fifo(dev_priv, FORCEWAKE_ALL);
 		mutex_unlock(&dev->struct_mutex);
 
-		if (ecobus & FORCEWAKE_MT_ENABLE) {
-			dev_priv->uncore.funcs.force_wake_get =
-				__gen7_gt_force_wake_mt_get;
-			dev_priv->uncore.funcs.force_wake_put =
-				__gen7_gt_force_wake_mt_put;
-		} else {
+		if (!(ecobus & FORCEWAKE_MT_ENABLE)) {
 			DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
 			DRM_INFO("when using vblank-synced partial screen updates.\n");
-			dev_priv->uncore.funcs.force_wake_get =
-				__gen6_gt_force_wake_get;
-			dev_priv->uncore.funcs.force_wake_put =
-				__gen6_gt_force_wake_put;
+			fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+				       FORCEWAKE, FORCEWAKE_ACK);
 		}
 	} else if (IS_GEN6(dev)) {
 		dev_priv->uncore.funcs.force_wake_get =
-			__gen6_gt_force_wake_get;
+			fw_domains_get_with_thread_status;
 		dev_priv->uncore.funcs.force_wake_put =
-			__gen6_gt_force_wake_put;
+			fw_domains_put_with_fifo;
+		fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+			       FORCEWAKE, FORCEWAKE_ACK);
 	}
 
+	/* All future platforms are expected to require complex power gating */
+	WARN_ON(dev_priv->uncore.fw_domains == 0);
+}
+
+void intel_uncore_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_uncore_ellc_detect(dev);
+	intel_uncore_fw_domains_init(dev);
+	__intel_uncore_early_sanitize(dev, false);
+
 	switch (INTEL_INFO(dev)->gen) {
 	default:
-		WARN_ON(1);
+		MISSING_CASE(INTEL_INFO(dev)->gen);
 		return;
 	case 9:
 		ASSIGN_WRITE_MMIO_VFUNCS(gen9);
@@ -1239,8 +1125,8 @@
 	case 4:
 	case 3:
 	case 2:
-		ASSIGN_WRITE_MMIO_VFUNCS(gen4);
-		ASSIGN_READ_MMIO_VFUNCS(gen4);
+		ASSIGN_WRITE_MMIO_VFUNCS(gen2);
+		ASSIGN_READ_MMIO_VFUNCS(gen2);
 		break;
 	}
 
@@ -1300,7 +1186,7 @@
 		reg->val = I915_READ8(reg->offset);
 		break;
 	default:
-		WARN_ON(1);
+		MISSING_CASE(entry->size);
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index ab31848..33cdddf 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -5,7 +5,7 @@
 	select VIDEOMODE_HELPERS
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_CMA_HELPER
-	depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
+	depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM) && HAVE_DMA_ATTRS
 	depends on IMX_IPUV3_CORE
 	help
 	  enable i.MX graphics support
@@ -49,6 +49,7 @@
 
 config DRM_IMX_HDMI
 	tristate "Freescale i.MX DRM HDMI"
+	select DRM_DW_HDMI
 	depends on DRM_IMX
 	help
 	  Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index 582c438..f3ecd89 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -9,4 +9,4 @@
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
new file mode 100644
index 0000000..121d30c
--- /dev/null
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <drm/bridge/dw_hdmi.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "imx-drm.h"
+
+struct imx_hdmi {
+	struct device *dev;
+	struct drm_encoder encoder;
+	struct regmap *regmap;
+};
+
+static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
+	{
+		45250000, {
+			{ 0x01e0, 0x0000 },
+			{ 0x21e1, 0x0000 },
+			{ 0x41e2, 0x0000 }
+		},
+	}, {
+		92500000, {
+			{ 0x0140, 0x0005 },
+			{ 0x2141, 0x0005 },
+			{ 0x4142, 0x0005 },
+	},
+	}, {
+		148500000, {
+			{ 0x00a0, 0x000a },
+			{ 0x20a1, 0x000a },
+			{ 0x40a2, 0x000a },
+		},
+	}, {
+		~0UL, {
+			{ 0x00a0, 0x000a },
+			{ 0x2001, 0x000f },
+			{ 0x4002, 0x000f },
+		},
+	}
+};
+
+static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
+	/*      pixelclk     bpp8    bpp10   bpp12 */
+	{
+		54000000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		58400000, { 0x091c, 0x06dc, 0x06dc },
+	}, {
+		72000000, { 0x06dc, 0x06dc, 0x091c },
+	}, {
+		74250000, { 0x06dc, 0x0b5c, 0x091c },
+	}, {
+		118800000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		216000000, { 0x06dc, 0x0b5c, 0x091c },
+	}
+};
+
+static const struct dw_hdmi_sym_term imx_sym_term[] = {
+	/*pixelclk   symbol   term*/
+	{ 148500000, 0x800d, 0x0005 },
+	{ ~0UL,      0x0000, 0x0000 }
+};
+
+static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
+{
+	struct device_node *np = hdmi->dev->of_node;
+
+	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+	if (IS_ERR(hdmi->regmap)) {
+		dev_err(hdmi->dev, "Unable to get gpr\n");
+		return PTR_ERR(hdmi->regmap);
+	}
+
+	return 0;
+}
+
+static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_imx_encoder_mode_fixup(struct drm_encoder *encoder,
+					   const struct drm_display_mode *mode,
+					   struct drm_display_mode *adj_mode)
+{
+	return true;
+}
+
+static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder,
+					 struct drm_display_mode *mode,
+					 struct drm_display_mode *adj_mode)
+{
+}
+
+static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+	int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
+
+	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
+			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+			   mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+}
+
+static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
+{
+	imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
+	.mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
+	.mode_set   = dw_hdmi_imx_encoder_mode_set,
+	.prepare    = dw_hdmi_imx_encoder_prepare,
+	.commit     = dw_hdmi_imx_encoder_commit,
+	.disable    = dw_hdmi_imx_encoder_disable,
+};
+
+static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+	.mpll_cfg = imx_mpll_cfg,
+	.cur_ctr  = imx_cur_ctr,
+	.sym_term = imx_sym_term,
+	.dev_type = IMX6Q_HDMI,
+};
+
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+	.mpll_cfg = imx_mpll_cfg,
+	.cur_ctr  = imx_cur_ctr,
+	.sym_term = imx_sym_term,
+	.dev_type = IMX6DL_HDMI,
+};
+
+static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-hdmi",
+	  .data = &imx6q_hdmi_drv_data
+	}, {
+	  .compatible = "fsl,imx6dl-hdmi",
+	  .data = &imx6dl_hdmi_drv_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
+
+static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct dw_hdmi_plat_data *plat_data;
+	const struct of_device_id *match;
+	struct drm_device *drm = data;
+	struct drm_encoder *encoder;
+	struct imx_hdmi *hdmi;
+	struct resource *iores;
+	int irq;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
+	plat_data = match->data;
+	hdmi->dev = &pdev->dev;
+	encoder = &hdmi->encoder;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores)
+		return -ENXIO;
+
+	platform_set_drvdata(pdev, hdmi);
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	ret = dw_hdmi_imx_parse_dt(hdmi);
+	if (ret < 0)
+		return ret;
+
+	drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+
+	return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	return dw_hdmi_unbind(dev, master, data);
+}
+
+static const struct component_ops dw_hdmi_imx_ops = {
+	.bind	= dw_hdmi_imx_bind,
+	.unbind	= dw_hdmi_imx_unbind,
+};
+
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &dw_hdmi_imx_ops);
+}
+
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+	return 0;
+}
+
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+	.probe  = dw_hdmi_imx_probe,
+	.remove = dw_hdmi_imx_remove,
+	.driver = {
+		.name = "dwhdmi-imx",
+		.of_match_table = dw_hdmi_imx_dt_ids,
+	},
+};
+
+module_platform_driver(dw_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index b250130..a002f53 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -25,6 +25,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_of.h>
 
 #include "imx-drm.h"
 
@@ -46,7 +47,6 @@
 	struct drm_crtc				*crtc;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
-	struct device_node			*port;
 };
 
 static int legacyfb_depth = 16;
@@ -116,8 +116,7 @@
 	helper = &imx_crtc->imx_drm_helper_funcs;
 	if (helper->set_interface_pix_fmt)
 		return helper->set_interface_pix_fmt(encoder->crtc,
-				encoder->encoder_type, interface_pix_fmt,
-				hsync_pin, vsync_pin);
+				interface_pix_fmt, hsync_pin, vsync_pin);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
@@ -365,9 +364,10 @@
 
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
 	imx_drm_crtc->pipe = imxdrm->pipes++;
-	imx_drm_crtc->port = port;
 	imx_drm_crtc->crtc = crtc;
 
+	crtc->port = port;
+
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
@@ -408,75 +408,19 @@
 }
 EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
 
-/*
- * Find the DRM CRTC possible mask for the connected endpoint.
- *
- * The encoder possible masks are defined by their position in the
- * mode_config crtc_list.  This means that CRTCs must not be added
- * or removed once the DRM device has been fully initialised.
- */
-static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
-	struct device_node *endpoint)
-{
-	struct device_node *port;
-	unsigned i;
-
-	port = of_graph_get_remote_port(endpoint);
-	if (!port)
-		return 0;
-	of_node_put(port);
-
-	for (i = 0; i < MAX_CRTC; i++) {
-		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-
-		if (imx_drm_crtc && imx_drm_crtc->port == port)
-			return drm_crtc_mask(imx_drm_crtc->crtc);
-	}
-
-	return 0;
-}
-
-static struct device_node *imx_drm_of_get_next_endpoint(
-		const struct device_node *parent, struct device_node *prev)
-{
-	struct device_node *node = of_graph_get_next_endpoint(parent, prev);
-
-	of_node_put(prev);
-	return node;
-}
-
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np)
 {
-	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct device_node *ep = NULL;
-	uint32_t crtc_mask = 0;
-	int i;
+	uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
 
-	for (i = 0; ; i++) {
-		u32 mask;
-
-		ep = imx_drm_of_get_next_endpoint(np, ep);
-		if (!ep)
-			break;
-
-		mask = imx_drm_find_crtc_mask(imxdrm, ep);
-
-		/*
-		 * If we failed to find the CRTC(s) which this encoder is
-		 * supposed to be connected to, it's because the CRTC has
-		 * not been registered yet.  Defer probing, and hope that
-		 * the required CRTC is added later.
-		 */
-		if (mask == 0)
-			return -EPROBE_DEFER;
-
-		crtc_mask |= mask;
-	}
-
-	of_node_put(ep);
-	if (i == 0)
-		return -ENOENT;
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (crtc_mask == 0)
+		return -EPROBE_DEFER;
 
 	encoder->possible_crtcs = crtc_mask;
 
@@ -487,6 +431,15 @@
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
 
+static struct device_node *imx_drm_of_get_next_endpoint(
+		const struct device_node *parent, struct device_node *prev)
+{
+	struct device_node *node = of_graph_get_next_endpoint(parent, prev);
+
+	of_node_put(prev);
+	return node;
+}
+
 /*
  * @node: device tree node containing encoder input ports
  * @encoder: drm_encoder
@@ -510,7 +463,7 @@
 
 		port = of_graph_get_remote_port(ep);
 		of_node_put(port);
-		if (port == imx_crtc->port) {
+		if (port == imx_crtc->crtc->port) {
 			ret = of_graph_parse_endpoint(ep, &endpoint);
 			return ret ? ret : endpoint.port;
 		}
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 7453ae0..3c559cc 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -17,7 +17,7 @@
 struct imx_drm_crtc_helper_funcs {
 	int (*enable_vblank)(struct drm_crtc *crtc);
 	void (*disable_vblank)(struct drm_crtc *crtc);
-	int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
+	int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
 			u32 pix_fmt, int hsync_pin, int vsync_pin);
 	const struct drm_crtc_helper_funcs *crtc_helper_funcs;
 	const struct drm_crtc_funcs *crtc_funcs;
diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c
deleted file mode 100644
index ddc53e0..0000000
--- a/drivers/gpu/drm/imx/imx-hdmi.c
+++ /dev/null
@@ -1,1766 +0,0 @@
-/*
- * Copyright (C) 2011-2013 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- */
-
-#include <linux/component.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-#include <linux/of_device.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
-#include <video/imx-ipu-v3.h>
-
-#include "imx-hdmi.h"
-#include "imx-drm.h"
-
-#define HDMI_EDID_LEN		512
-
-#define RGB			0
-#define YCBCR444		1
-#define YCBCR422_16BITS		2
-#define YCBCR422_8BITS		3
-#define XVYCC444		4
-
-enum hdmi_datamap {
-	RGB444_8B = 0x01,
-	RGB444_10B = 0x03,
-	RGB444_12B = 0x05,
-	RGB444_16B = 0x07,
-	YCbCr444_8B = 0x09,
-	YCbCr444_10B = 0x0B,
-	YCbCr444_12B = 0x0D,
-	YCbCr444_16B = 0x0F,
-	YCbCr422_8B = 0x16,
-	YCbCr422_10B = 0x14,
-	YCbCr422_12B = 0x12,
-};
-
-enum imx_hdmi_devtype {
-	IMX6Q_HDMI,
-	IMX6DL_HDMI,
-};
-
-static const u16 csc_coeff_default[3][4] = {
-	{ 0x2000, 0x0000, 0x0000, 0x0000 },
-	{ 0x0000, 0x2000, 0x0000, 0x0000 },
-	{ 0x0000, 0x0000, 0x2000, 0x0000 }
-};
-
-static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
-	{ 0x2000, 0x6926, 0x74fd, 0x010e },
-	{ 0x2000, 0x2cdd, 0x0000, 0x7e9a },
-	{ 0x2000, 0x0000, 0x38b4, 0x7e3b }
-};
-
-static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
-	{ 0x2000, 0x7106, 0x7a02, 0x00a7 },
-	{ 0x2000, 0x3264, 0x0000, 0x7e6d },
-	{ 0x2000, 0x0000, 0x3b61, 0x7e25 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
-	{ 0x2591, 0x1322, 0x074b, 0x0000 },
-	{ 0x6535, 0x2000, 0x7acc, 0x0200 },
-	{ 0x6acd, 0x7534, 0x2000, 0x0200 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
-	{ 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
-	{ 0x62f0, 0x2000, 0x7d11, 0x0200 },
-	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
-};
-
-struct hdmi_vmode {
-	bool mdvi;
-	bool mhsyncpolarity;
-	bool mvsyncpolarity;
-	bool minterlaced;
-	bool mdataenablepolarity;
-
-	unsigned int mpixelclock;
-	unsigned int mpixelrepetitioninput;
-	unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
-	unsigned int enc_in_format;
-	unsigned int enc_out_format;
-	unsigned int enc_color_depth;
-	unsigned int colorimetry;
-	unsigned int pix_repet_factor;
-	unsigned int hdcp_enable;
-	struct hdmi_vmode video_mode;
-};
-
-struct imx_hdmi {
-	struct drm_connector connector;
-	struct drm_encoder encoder;
-
-	enum imx_hdmi_devtype dev_type;
-	struct device *dev;
-	struct clk *isfr_clk;
-	struct clk *iahb_clk;
-
-	struct hdmi_data_info hdmi_data;
-	int vic;
-
-	u8 edid[HDMI_EDID_LEN];
-	bool cable_plugin;
-
-	bool phy_enabled;
-	struct drm_display_mode previous_mode;
-
-	struct regmap *regmap;
-	struct i2c_adapter *ddc;
-	void __iomem *regs;
-
-	unsigned int sample_rate;
-	int ratio;
-};
-
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
-	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
-			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
-			   ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
-{
-	writeb(val, hdmi->regs + offset);
-}
-
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
-{
-	return readb(hdmi->regs + offset);
-}
-
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
-{
-	u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
-	val |= data & mask;
-	hdmi_writeb(hdmi, val, reg);
-}
-
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
-		      u8 shift, u8 mask)
-{
-	hdmi_modb(hdmi, data << shift, mask, reg);
-}
-
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
-					 unsigned int value)
-{
-	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
-	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
-	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
-
-	/* nshift factor = 0 */
-	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
-}
-
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
-{
-	/* Must be set/cleared first */
-	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-
-	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
-	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
-	hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
-		    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-}
-
-static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
-				   unsigned int ratio)
-{
-	unsigned int n = (128 * freq) / 1000;
-
-	switch (freq) {
-	case 32000:
-		if (pixel_clk == 25170000)
-			n = (ratio == 150) ? 9152 : 4576;
-		else if (pixel_clk == 27020000)
-			n = (ratio == 150) ? 8192 : 4096;
-		else if (pixel_clk == 74170000 || pixel_clk == 148350000)
-			n = 11648;
-		else
-			n = 4096;
-		break;
-
-	case 44100:
-		if (pixel_clk == 25170000)
-			n = 7007;
-		else if (pixel_clk == 74170000)
-			n = 17836;
-		else if (pixel_clk == 148350000)
-			n = (ratio == 150) ? 17836 : 8918;
-		else
-			n = 6272;
-		break;
-
-	case 48000:
-		if (pixel_clk == 25170000)
-			n = (ratio == 150) ? 9152 : 6864;
-		else if (pixel_clk == 27020000)
-			n = (ratio == 150) ? 8192 : 6144;
-		else if (pixel_clk == 74170000)
-			n = 11648;
-		else if (pixel_clk == 148350000)
-			n = (ratio == 150) ? 11648 : 5824;
-		else
-			n = 6144;
-		break;
-
-	case 88200:
-		n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
-		break;
-
-	case 96000:
-		n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
-		break;
-
-	case 176400:
-		n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
-		break;
-
-	case 192000:
-		n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
-		break;
-
-	default:
-		break;
-	}
-
-	return n;
-}
-
-static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
-				     unsigned int ratio)
-{
-	unsigned int cts = 0;
-
-	pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
-		 pixel_clk, ratio);
-
-	switch (freq) {
-	case 32000:
-		if (pixel_clk == 297000000) {
-			cts = 222750;
-			break;
-		}
-	case 48000:
-	case 96000:
-	case 192000:
-		switch (pixel_clk) {
-		case 25200000:
-		case 27000000:
-		case 54000000:
-		case 74250000:
-		case 148500000:
-			cts = pixel_clk / 1000;
-			break;
-		case 297000000:
-			cts = 247500;
-			break;
-		/*
-		 * All other TMDS clocks are not supported by
-		 * DWC_hdmi_tx. The TMDS clocks divided or
-		 * multiplied by 1,001 coefficients are not
-		 * supported.
-		 */
-		default:
-			break;
-		}
-		break;
-	case 44100:
-	case 88200:
-	case 176400:
-		switch (pixel_clk) {
-		case 25200000:
-			cts = 28000;
-			break;
-		case 27000000:
-			cts = 30000;
-			break;
-		case 54000000:
-			cts = 60000;
-			break;
-		case 74250000:
-			cts = 82500;
-			break;
-		case 148500000:
-			cts = 165000;
-			break;
-		case 297000000:
-			cts = 247500;
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-	if (ratio == 100)
-		return cts;
-	return (cts * ratio) / 100;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
-	unsigned long pixel_clk)
-{
-	unsigned int clk_n, clk_cts;
-
-	clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
-			       hdmi->ratio);
-	clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
-				   hdmi->ratio);
-
-	if (!clk_cts) {
-		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-			 __func__, pixel_clk);
-		return;
-	}
-
-	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
-		__func__, hdmi->sample_rate, hdmi->ratio,
-		pixel_clk, clk_n, clk_cts);
-
-	hdmi_set_clock_regenerator_n(hdmi, clk_n);
-	hdmi_regenerate_cts(hdmi, clk_cts);
-}
-
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
-{
-	hdmi_set_clk_regenerator(hdmi, 74250000);
-}
-
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
-{
-	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
-}
-
-/*
- * this submodule is responsible for the video data synchronization.
- * for example, for RGB 4:4:4 input, the data map is defined as
- *			pin{47~40} <==> R[7:0]
- *			pin{31~24} <==> G[7:0]
- *			pin{15~8}  <==> B[7:0]
- */
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
-{
-	int color_format = 0;
-	u8 val;
-
-	if (hdmi->hdmi_data.enc_in_format == RGB) {
-		if (hdmi->hdmi_data.enc_color_depth == 8)
-			color_format = 0x01;
-		else if (hdmi->hdmi_data.enc_color_depth == 10)
-			color_format = 0x03;
-		else if (hdmi->hdmi_data.enc_color_depth == 12)
-			color_format = 0x05;
-		else if (hdmi->hdmi_data.enc_color_depth == 16)
-			color_format = 0x07;
-		else
-			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
-		if (hdmi->hdmi_data.enc_color_depth == 8)
-			color_format = 0x09;
-		else if (hdmi->hdmi_data.enc_color_depth == 10)
-			color_format = 0x0B;
-		else if (hdmi->hdmi_data.enc_color_depth == 12)
-			color_format = 0x0D;
-		else if (hdmi->hdmi_data.enc_color_depth == 16)
-			color_format = 0x0F;
-		else
-			return;
-	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
-		if (hdmi->hdmi_data.enc_color_depth == 8)
-			color_format = 0x16;
-		else if (hdmi->hdmi_data.enc_color_depth == 10)
-			color_format = 0x14;
-		else if (hdmi->hdmi_data.enc_color_depth == 12)
-			color_format = 0x12;
-		else
-			return;
-	}
-
-	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
-		((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
-		HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
-	hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
-
-	/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
-	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
-		HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
-		HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
-	hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
-	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
-}
-
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
-{
-	return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
-}
-
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
-{
-	if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
-		return 0;
-	if (hdmi->hdmi_data.enc_in_format == RGB ||
-	    hdmi->hdmi_data.enc_in_format == YCBCR444)
-		return 1;
-	return 0;
-}
-
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
-{
-	if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
-		return 0;
-	if (hdmi->hdmi_data.enc_out_format == RGB ||
-	    hdmi->hdmi_data.enc_out_format == YCBCR444)
-		return 1;
-	return 0;
-}
-
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
-{
-	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
-	unsigned i;
-	u32 csc_scale = 1;
-
-	if (is_color_space_conversion(hdmi)) {
-		if (hdmi->hdmi_data.enc_out_format == RGB) {
-			if (hdmi->hdmi_data.colorimetry ==
-					HDMI_COLORIMETRY_ITU_601)
-				csc_coeff = &csc_coeff_rgb_out_eitu601;
-			else
-				csc_coeff = &csc_coeff_rgb_out_eitu709;
-		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
-			if (hdmi->hdmi_data.colorimetry ==
-					HDMI_COLORIMETRY_ITU_601)
-				csc_coeff = &csc_coeff_rgb_in_eitu601;
-			else
-				csc_coeff = &csc_coeff_rgb_in_eitu709;
-			csc_scale = 0;
-		}
-	}
-
-	/* The CSC registers are sequential, alternating MSB then LSB */
-	for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
-		u16 coeff_a = (*csc_coeff)[0][i];
-		u16 coeff_b = (*csc_coeff)[1][i];
-		u16 coeff_c = (*csc_coeff)[2][i];
-
-		hdmi_writeb(hdmi, coeff_a & 0xff,
-			HDMI_CSC_COEF_A1_LSB + i * 2);
-		hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
-		hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
-		hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
-		hdmi_writeb(hdmi, coeff_c & 0xff,
-			HDMI_CSC_COEF_C1_LSB + i * 2);
-		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
-	}
-
-	hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
-		  HDMI_CSC_SCALE);
-}
-
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
-{
-	int color_depth = 0;
-	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
-	int decimation = 0;
-
-	/* YCC422 interpolation to 444 mode */
-	if (is_color_space_interpolation(hdmi))
-		interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
-	else if (is_color_space_decimation(hdmi))
-		decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
-
-	if (hdmi->hdmi_data.enc_color_depth == 8)
-		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
-	else if (hdmi->hdmi_data.enc_color_depth == 10)
-		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
-	else if (hdmi->hdmi_data.enc_color_depth == 12)
-		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
-	else if (hdmi->hdmi_data.enc_color_depth == 16)
-		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
-	else
-		return;
-
-	/* Configure the CSC registers */
-	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
-	hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
-		  HDMI_CSC_SCALE);
-
-	imx_hdmi_update_csc_coeffs(hdmi);
-}
-
-/*
- * HDMI video packetizer is used to packetize the data.
- * for example, if input is YCC422 mode or repeater is used,
- * data should be repacked this module can be bypassed.
- */
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
-{
-	unsigned int color_depth = 0;
-	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
-	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
-	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
-	u8 val, vp_conf;
-
-	if (hdmi_data->enc_out_format == RGB
-		|| hdmi_data->enc_out_format == YCBCR444) {
-		if (!hdmi_data->enc_color_depth)
-			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
-		else if (hdmi_data->enc_color_depth == 8) {
-			color_depth = 4;
-			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
-		} else if (hdmi_data->enc_color_depth == 10)
-			color_depth = 5;
-		else if (hdmi_data->enc_color_depth == 12)
-			color_depth = 6;
-		else if (hdmi_data->enc_color_depth == 16)
-			color_depth = 7;
-		else
-			return;
-	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
-		if (!hdmi_data->enc_color_depth ||
-		    hdmi_data->enc_color_depth == 8)
-			remap_size = HDMI_VP_REMAP_YCC422_16bit;
-		else if (hdmi_data->enc_color_depth == 10)
-			remap_size = HDMI_VP_REMAP_YCC422_20bit;
-		else if (hdmi_data->enc_color_depth == 12)
-			remap_size = HDMI_VP_REMAP_YCC422_24bit;
-		else
-			return;
-		output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
-	} else
-		return;
-
-	/* set the packetizer registers */
-	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
-		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
-		((hdmi_data->pix_repet_factor <<
-		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
-		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
-	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
-
-	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
-		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
-
-	/* Data from pixel repeater block */
-	if (hdmi_data->pix_repet_factor > 1) {
-		vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
-			  HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
-	} else { /* data from packetizer block */
-		vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
-			  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
-	}
-
-	hdmi_modb(hdmi, vp_conf,
-		  HDMI_VP_CONF_PR_EN_MASK |
-		  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
-
-	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
-		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
-
-	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
-
-	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			  HDMI_VP_CONF_PP_EN_ENABLE |
-			  HDMI_VP_CONF_YCC422_EN_DISABLE;
-	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			  HDMI_VP_CONF_PP_EN_DISABLE |
-			  HDMI_VP_CONF_YCC422_EN_ENABLE;
-	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-		vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
-			  HDMI_VP_CONF_PP_EN_DISABLE |
-			  HDMI_VP_CONF_YCC422_EN_DISABLE;
-	} else {
-		return;
-	}
-
-	hdmi_modb(hdmi, vp_conf,
-		  HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
-		  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
-
-	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
-			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
-		  HDMI_VP_STUFF_PP_STUFFING_MASK |
-		  HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
-
-	hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
-		  HDMI_VP_CONF);
-}
-
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
-						unsigned char bit)
-{
-	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
-		  HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
-						unsigned char bit)
-{
-	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
-		  HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
-						unsigned char bit)
-{
-	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
-		  HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
-						unsigned char bit)
-{
-	hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
-}
-
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
-						unsigned char bit)
-{
-	hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
-}
-
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
-{
-	while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
-		if (msec-- == 0)
-			return false;
-		udelay(1000);
-	}
-	return true;
-}
-
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
-			      unsigned char addr)
-{
-	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
-	hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
-	hdmi_writeb(hdmi, (unsigned char)(data >> 8),
-		HDMI_PHY_I2CM_DATAO_1_ADDR);
-	hdmi_writeb(hdmi, (unsigned char)(data >> 0),
-		HDMI_PHY_I2CM_DATAO_0_ADDR);
-	hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
-		HDMI_PHY_I2CM_OPERATION_ADDR);
-	hdmi_phy_wait_i2c_done(hdmi, 1000);
-}
-
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
-				     unsigned char addr)
-{
-	__hdmi_phy_i2c_write(hdmi, data, addr);
-	return 0;
-}
-
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_PDZ_OFFSET,
-			 HDMI_PHY_CONF0_PDZ_MASK);
-}
-
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_ENTMDS_OFFSET,
-			 HDMI_PHY_CONF0_ENTMDS_MASK);
-}
-
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
-			 HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
-}
-
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
-			 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
-}
-
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
-			 HDMI_PHY_CONF0_SELDATAENPOL_MASK);
-}
-
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
-{
-	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
-			 HDMI_PHY_CONF0_SELDIPIF_OFFSET,
-			 HDMI_PHY_CONF0_SELDIPIF_MASK);
-}
-
-enum {
-	RES_8,
-	RES_10,
-	RES_12,
-	RES_MAX,
-};
-
-struct mpll_config {
-	unsigned long mpixelclock;
-	struct {
-		u16 cpce;
-		u16 gmp;
-	} res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
-	{
-		45250000, {
-			{ 0x01e0, 0x0000 },
-			{ 0x21e1, 0x0000 },
-			{ 0x41e2, 0x0000 }
-		},
-	}, {
-		92500000, {
-			{ 0x0140, 0x0005 },
-			{ 0x2141, 0x0005 },
-			{ 0x4142, 0x0005 },
-		},
-	}, {
-		148500000, {
-			{ 0x00a0, 0x000a },
-			{ 0x20a1, 0x000a },
-			{ 0x40a2, 0x000a },
-		},
-	}, {
-		~0UL, {
-			{ 0x00a0, 0x000a },
-			{ 0x2001, 0x000f },
-			{ 0x4002, 0x000f },
-		},
-	}
-};
-
-struct curr_ctrl {
-	unsigned long mpixelclock;
-	u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
-	/*	pixelclk     bpp8    bpp10   bpp12 */
-	{
-		 54000000, { 0x091c, 0x091c, 0x06dc },
-	}, {
-		 58400000, { 0x091c, 0x06dc, 0x06dc },
-	}, {
-		 72000000, { 0x06dc, 0x06dc, 0x091c },
-	}, {
-		 74250000, { 0x06dc, 0x0b5c, 0x091c },
-	}, {
-		118800000, { 0x091c, 0x091c, 0x06dc },
-	}, {
-		216000000, { 0x06dc, 0x0b5c, 0x091c },
-	}
-};
-
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
-			      unsigned char res, int cscon)
-{
-	unsigned res_idx, i;
-	u8 val, msec;
-
-	if (prep)
-		return -EINVAL;
-
-	switch (res) {
-	case 0:	/* color resolution 0 is 8 bit colour depth */
-	case 8:
-		res_idx = RES_8;
-		break;
-	case 10:
-		res_idx = RES_10;
-		break;
-	case 12:
-		res_idx = RES_12;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* Enable csc path */
-	if (cscon)
-		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
-	else
-		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
-
-	hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
-
-	/* gen2 tx power off */
-	imx_hdmi_phy_gen2_txpwron(hdmi, 0);
-
-	/* gen2 pddq */
-	imx_hdmi_phy_gen2_pddq(hdmi, 1);
-
-	/* PHY reset */
-	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
-	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
-
-	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
-
-	hdmi_phy_test_clear(hdmi, 1);
-	hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
-			HDMI_PHY_I2CM_SLAVE_ADDR);
-	hdmi_phy_test_clear(hdmi, 0);
-
-	/* PLL/MPLL Cfg - always match on final entry */
-	for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
-		if (hdmi->hdmi_data.video_mode.mpixelclock <=
-		    mpll_config[i].mpixelclock)
-			break;
-
-	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
-	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
-
-	for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
-		if (hdmi->hdmi_data.video_mode.mpixelclock <=
-		    curr_ctrl[i].mpixelclock)
-			break;
-
-	if (i >= ARRAY_SIZE(curr_ctrl)) {
-		dev_err(hdmi->dev,
-				"Pixel clock %d - unsupported by HDMI\n",
-				hdmi->hdmi_data.video_mode.mpixelclock);
-		return -EINVAL;
-	}
-
-	/* CURRCTRL */
-	hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
-
-	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
-	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
-	/* RESISTANCE TERM 133Ohm Cfg */
-	hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);  /* TXTERM */
-	/* PREEMP Cgf 0.00 */
-	hdmi_phy_i2c_write(hdmi, 0x800d, 0x09);  /* CKSYMTXCTRL */
-	/* TX/CK LVL 10 */
-	hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
-	/* REMOVE CLK TERM */
-	hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
-
-	imx_hdmi_phy_enable_power(hdmi, 1);
-
-	/* toggle TMDS enable */
-	imx_hdmi_phy_enable_tmds(hdmi, 0);
-	imx_hdmi_phy_enable_tmds(hdmi, 1);
-
-	/* gen2 tx power on */
-	imx_hdmi_phy_gen2_txpwron(hdmi, 1);
-	imx_hdmi_phy_gen2_pddq(hdmi, 0);
-
-	/*Wait for PHY PLL lock */
-	msec = 5;
-	do {
-		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-		if (!val)
-			break;
-
-		if (msec == 0) {
-			dev_err(hdmi->dev, "PHY PLL not locked\n");
-			return -ETIMEDOUT;
-		}
-
-		udelay(1000);
-		msec--;
-	} while (1);
-
-	return 0;
-}
-
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
-{
-	int i, ret;
-	bool cscon = false;
-
-	/*check csc whether needed activated in HDMI mode */
-	cscon = (is_color_space_conversion(hdmi) &&
-			!hdmi->hdmi_data.video_mode.mdvi);
-
-	/* HDMI Phy spec says to do the phy initialization sequence twice */
-	for (i = 0; i < 2; i++) {
-		imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
-		imx_hdmi_phy_sel_interface_control(hdmi, 0);
-		imx_hdmi_phy_enable_tmds(hdmi, 0);
-		imx_hdmi_phy_enable_power(hdmi, 0);
-
-		/* Enable CSC */
-		ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
-		if (ret)
-			return ret;
-	}
-
-	hdmi->phy_enabled = true;
-	return 0;
-}
-
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
-{
-	u8 de;
-
-	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
-		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
-	else
-		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
-
-	/* disable rx detect */
-	hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
-		  HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
-
-	hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
-
-	hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
-		  HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
-}
-
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
-{
-	u8 val, pix_fmt, under_scan;
-	u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
-	bool aspect_16_9;
-
-	aspect_16_9 = false; /* FIXME */
-
-	/* AVI Data Byte 1 */
-	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
-		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
-	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
-		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
-	else
-		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
-
-		under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
-
-	/*
-	 * Active format identification data is present in the AVI InfoFrame.
-	 * Under scan info, no bar data
-	 */
-	val = pix_fmt | under_scan |
-		HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
-		HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
-
-	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
-
-	/* AVI Data Byte 2 -Set the Aspect Ratio */
-	if (aspect_16_9) {
-		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
-		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
-	} else {
-		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
-		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
-	}
-
-	/* Set up colorimetry */
-	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
-		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
-		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
-			ext_colorimetry =
-				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
-			ext_colorimetry =
-				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
-	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
-		if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
-			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
-		else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
-			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
-		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-	} else { /* Carries no data */
-		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
-		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-	}
-
-	val = colorimetry | coded_ratio | act_ratio;
-	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
-
-	/* AVI Data Byte 3 */
-	val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
-		HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
-		HDMI_FC_AVICONF2_SCALING_NONE;
-	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
-
-	/* AVI Data Byte 4 */
-	hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
-
-	/* AVI Data Byte 5- set up input and output pixel repetition */
-	val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
-		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
-		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
-		((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
-		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
-		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
-	hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
-
-	/* IT Content and quantization range = don't care */
-	val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
-		HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
-	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
-
-	/* AVI Data Bytes 6-13 */
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
-	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
-}
-
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
-			     const struct drm_display_mode *mode)
-{
-	u8 inv_val;
-	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
-	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
-
-	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
-	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
-	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
-	vmode->mpixelclock = mode->clock * 1000;
-
-	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
-
-	/* Set up HDMI_FC_INVIDCONF */
-	inv_val = (hdmi->hdmi_data.hdcp_enable ?
-		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
-		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
-
-	inv_val |= (vmode->mvsyncpolarity ?
-		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
-		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
-
-	inv_val |= (vmode->mhsyncpolarity ?
-		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
-		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
-
-	inv_val |= (vmode->mdataenablepolarity ?
-		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
-		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
-
-	if (hdmi->vic == 39)
-		inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
-	else
-		inv_val |= (vmode->minterlaced ?
-			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
-			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
-
-	inv_val |= (vmode->minterlaced ?
-		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
-		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
-
-	inv_val |= (vmode->mdvi ?
-		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
-		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
-
-	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
-
-	/* Set up horizontal active pixel width */
-	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
-	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
-
-	/* Set up vertical active lines */
-	hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
-	hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
-
-	/* Set up horizontal blanking pixel region width */
-	hblank = mode->htotal - mode->hdisplay;
-	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
-	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
-
-	/* Set up vertical blanking pixel region width */
-	vblank = mode->vtotal - mode->vdisplay;
-	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
-
-	/* Set up HSYNC active edge delay width (in pixel clks) */
-	h_de_hs = mode->hsync_start - mode->hdisplay;
-	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
-	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
-
-	/* Set up VSYNC active edge delay (in lines) */
-	v_de_vs = mode->vsync_start - mode->vdisplay;
-	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
-
-	/* Set up HSYNC active pulse width (in pixel clks) */
-	hsync_len = mode->hsync_end - mode->hsync_start;
-	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
-	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
-
-	/* Set up VSYNC active edge delay (in lines) */
-	vsync_len = mode->vsync_end - mode->vsync_start;
-	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
-}
-
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
-{
-	if (!hdmi->phy_enabled)
-		return;
-
-	imx_hdmi_phy_enable_tmds(hdmi, 0);
-	imx_hdmi_phy_enable_power(hdmi, 0);
-
-	hdmi->phy_enabled = false;
-}
-
-/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
-{
-	u8 clkdis;
-
-	/* control period minimum duration */
-	hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
-	hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
-	hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
-
-	/* Set to fill TMDS data channels */
-	hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
-	hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
-	hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
-
-	/* Enable pixel clock and tmds data path */
-	clkdis = 0x7F;
-	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
-	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
-	/* Enable csc path */
-	if (is_color_space_conversion(hdmi)) {
-		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
-		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-	}
-}
-
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
-{
-	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
-}
-
-/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
-{
-	int count;
-	u8 val;
-
-	/* TMDS software reset */
-	hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
-
-	val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
-	if (hdmi->dev_type == IMX6DL_HDMI) {
-		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
-		return;
-	}
-
-	for (count = 0; count < 4; count++)
-		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
-}
-
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
-	hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
-	hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
-}
-
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
-	hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
-		    HDMI_IH_MUTE_FC_STAT2);
-}
-
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
-{
-	int ret;
-
-	hdmi_disable_overflow_interrupts(hdmi);
-
-	hdmi->vic = drm_match_cea_mode(mode);
-
-	if (!hdmi->vic) {
-		dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
-		hdmi->hdmi_data.video_mode.mdvi = true;
-	} else {
-		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
-		hdmi->hdmi_data.video_mode.mdvi = false;
-	}
-
-	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
-		(hdmi->vic == 21) || (hdmi->vic == 22) ||
-		(hdmi->vic == 2) || (hdmi->vic == 3) ||
-		(hdmi->vic == 17) || (hdmi->vic == 18))
-		hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
-	else
-		hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
-
-	if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
-		(hdmi->vic == 12) || (hdmi->vic == 13) ||
-		(hdmi->vic == 14) || (hdmi->vic == 15) ||
-		(hdmi->vic == 25) || (hdmi->vic == 26) ||
-		(hdmi->vic == 27) || (hdmi->vic == 28) ||
-		(hdmi->vic == 29) || (hdmi->vic == 30) ||
-		(hdmi->vic == 35) || (hdmi->vic == 36) ||
-		(hdmi->vic == 37) || (hdmi->vic == 38))
-		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
-	else
-		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
-
-	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
-
-	/* TODO: Get input format from IPU (via FB driver interface) */
-	hdmi->hdmi_data.enc_in_format = RGB;
-
-	hdmi->hdmi_data.enc_out_format = RGB;
-
-	hdmi->hdmi_data.enc_color_depth = 8;
-	hdmi->hdmi_data.pix_repet_factor = 0;
-	hdmi->hdmi_data.hdcp_enable = 0;
-	hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
-
-	/* HDMI Initialization Step B.1 */
-	hdmi_av_composer(hdmi, mode);
-
-	/* HDMI Initializateion Step B.2 */
-	ret = imx_hdmi_phy_init(hdmi);
-	if (ret)
-		return ret;
-
-	/* HDMI Initialization Step B.3 */
-	imx_hdmi_enable_video_path(hdmi);
-
-	/* not for DVI mode */
-	if (hdmi->hdmi_data.video_mode.mdvi)
-		dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
-	else {
-		dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
-
-		/* HDMI Initialization Step E - Configure audio */
-		hdmi_clk_regenerator_update_pixel_clock(hdmi);
-		hdmi_enable_audio_clk(hdmi);
-
-		/* HDMI Initialization Step F - Configure AVI InfoFrame */
-		hdmi_config_AVI(hdmi);
-	}
-
-	hdmi_video_packetize(hdmi);
-	hdmi_video_csc(hdmi);
-	hdmi_video_sample(hdmi);
-	hdmi_tx_hdcp_config(hdmi);
-
-	imx_hdmi_clear_overflow(hdmi);
-	if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
-		hdmi_enable_overflow_interrupts(hdmi);
-
-	return 0;
-}
-
-/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
-{
-	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
-		    HDMI_PHY_I2CM_INT_ADDR);
-
-	hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
-		    HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
-		    HDMI_PHY_I2CM_CTLINT_ADDR);
-
-	/* enable cable hot plug irq */
-	hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
-
-	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
-	return 0;
-}
-
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
-{
-	u8 ih_mute;
-
-	/*
-	 * Boot up defaults are:
-	 * HDMI_IH_MUTE   = 0x03 (disabled)
-	 * HDMI_IH_MUTE_* = 0x00 (enabled)
-	 *
-	 * Disable top level interrupt bits in HDMI block
-	 */
-	ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
-		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
-		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
-
-	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-
-	/* by default mask all interrupts */
-	hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
-	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
-	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
-	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
-	hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
-	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
-	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
-	hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
-	hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
-	hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
-	hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
-	hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
-	hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
-	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
-	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
-
-	/* Disable interrupts in the IH_MUTE_* registers */
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
-	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
-
-	/* Enable top level interrupt bits in HDMI block */
-	ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
-		    HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
-	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-}
-
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
-{
-	imx_hdmi_setup(hdmi, &hdmi->previous_mode);
-}
-
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
-{
-	imx_hdmi_phy_disable(hdmi);
-}
-
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
-							*connector, bool force)
-{
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
-
-	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
-		connector_status_connected : connector_status_disconnected;
-}
-
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
-{
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
-	struct edid *edid;
-	int ret;
-
-	if (!hdmi->ddc)
-		return 0;
-
-	edid = drm_get_edid(connector, hdmi->ddc);
-	if (edid) {
-		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
-			edid->width_cm, edid->height_cm);
-
-		drm_mode_connector_update_edid_property(connector, edid);
-		ret = drm_add_edid_modes(connector, edid);
-		kfree(edid);
-	} else {
-		dev_dbg(hdmi->dev, "failed to get edid\n");
-	}
-
-	return 0;
-}
-
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
-							   *connector)
-{
-	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
-					     connector);
-
-	return &hdmi->encoder;
-}
-
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
-			struct drm_display_mode *mode,
-			struct drm_display_mode *adjusted_mode)
-{
-	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-	imx_hdmi_setup(hdmi, mode);
-
-	/* Store the display mode for plugin/DKMS poweron events */
-	memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
-			const struct drm_display_mode *mode,
-			struct drm_display_mode *adjusted_mode)
-{
-	return true;
-}
-
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-	if (mode)
-		imx_hdmi_poweroff(hdmi);
-	else
-		imx_hdmi_poweron(hdmi);
-}
-
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
-	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
-	imx_hdmi_poweroff(hdmi);
-	imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
-}
-
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
-	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-	int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
-
-	imx_hdmi_set_ipu_di_mux(hdmi, mux);
-
-	imx_hdmi_poweron(hdmi);
-}
-
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
-	.destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
-	.dpms = imx_hdmi_encoder_dpms,
-	.prepare = imx_hdmi_encoder_prepare,
-	.commit = imx_hdmi_encoder_commit,
-	.mode_set = imx_hdmi_encoder_mode_set,
-	.mode_fixup = imx_hdmi_encoder_mode_fixup,
-	.disable = imx_hdmi_encoder_disable,
-};
-
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.detect = imx_hdmi_connector_detect,
-	.destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
-	.get_modes = imx_hdmi_connector_get_modes,
-	.best_encoder = imx_hdmi_connector_best_encoder,
-};
-
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
-{
-	struct imx_hdmi *hdmi = dev_id;
-	u8 intr_stat;
-
-	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-	if (intr_stat)
-		hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
-	return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
-}
-
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
-{
-	struct imx_hdmi *hdmi = dev_id;
-	u8 intr_stat;
-	u8 phy_int_pol;
-
-	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-
-	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
-
-	if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
-		if (phy_int_pol & HDMI_PHY_HPD) {
-			dev_dbg(hdmi->dev, "EVENT=plugin\n");
-
-			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
-			imx_hdmi_poweron(hdmi);
-		} else {
-			dev_dbg(hdmi->dev, "EVENT=plugout\n");
-
-			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
-				HDMI_PHY_POL0);
-
-			imx_hdmi_poweroff(hdmi);
-		}
-		drm_helper_hpd_irq_event(hdmi->connector.dev);
-	}
-
-	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
-	return IRQ_HANDLED;
-}
-
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
-{
-	int ret;
-
-	ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
-				       hdmi->dev->of_node);
-	if (ret)
-		return ret;
-
-	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
-	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
-	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
-			 DRM_MODE_ENCODER_TMDS);
-
-	drm_connector_helper_add(&hdmi->connector,
-			&imx_hdmi_connector_helper_funcs);
-	drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
-			   DRM_MODE_CONNECTOR_HDMIA);
-
-	hdmi->connector.encoder = &hdmi->encoder;
-
-	drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
-
-	return 0;
-}
-
-static struct platform_device_id imx_hdmi_devtype[] = {
-	{
-		.name = "imx6q-hdmi",
-		.driver_data = IMX6Q_HDMI,
-	}, {
-		.name = "imx6dl-hdmi",
-		.driver_data = IMX6DL_HDMI,
-	}, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	const struct of_device_id *of_id =
-				of_match_device(imx_hdmi_dt_ids, dev);
-	struct drm_device *drm = data;
-	struct device_node *np = dev->of_node;
-	struct device_node *ddc_node;
-	struct imx_hdmi *hdmi;
-	struct resource *iores;
-	int ret, irq;
-
-	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
-	if (!hdmi)
-		return -ENOMEM;
-
-	hdmi->dev = dev;
-	hdmi->sample_rate = 48000;
-	hdmi->ratio = 100;
-
-	if (of_id) {
-		const struct platform_device_id *device_id = of_id->data;
-
-		hdmi->dev_type = device_id->driver_data;
-	}
-
-	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
-	if (ddc_node) {
-		hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
-		if (!hdmi->ddc)
-			dev_dbg(hdmi->dev, "failed to read ddc node\n");
-
-		of_node_put(ddc_node);
-	} else {
-		dev_dbg(hdmi->dev, "no ddc property found\n");
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
-					imx_hdmi_irq, IRQF_SHARED,
-					dev_name(dev), hdmi);
-	if (ret)
-		return ret;
-
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(hdmi->regs))
-		return PTR_ERR(hdmi->regs);
-
-	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
-	if (IS_ERR(hdmi->regmap))
-		return PTR_ERR(hdmi->regmap);
-
-	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
-	if (IS_ERR(hdmi->isfr_clk)) {
-		ret = PTR_ERR(hdmi->isfr_clk);
-		dev_err(hdmi->dev,
-			"Unable to get HDMI isfr clk: %d\n", ret);
-		return ret;
-	}
-
-	ret = clk_prepare_enable(hdmi->isfr_clk);
-	if (ret) {
-		dev_err(hdmi->dev,
-			"Cannot enable HDMI isfr clock: %d\n", ret);
-		return ret;
-	}
-
-	hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
-	if (IS_ERR(hdmi->iahb_clk)) {
-		ret = PTR_ERR(hdmi->iahb_clk);
-		dev_err(hdmi->dev,
-			"Unable to get HDMI iahb clk: %d\n", ret);
-		goto err_isfr;
-	}
-
-	ret = clk_prepare_enable(hdmi->iahb_clk);
-	if (ret) {
-		dev_err(hdmi->dev,
-			"Cannot enable HDMI iahb clock: %d\n", ret);
-		goto err_isfr;
-	}
-
-	/* Product and revision IDs */
-	dev_info(dev,
-		"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
-		hdmi_readb(hdmi, HDMI_DESIGN_ID),
-		hdmi_readb(hdmi, HDMI_REVISION_ID),
-		hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
-		hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
-
-	initialize_hdmi_ih_mutes(hdmi);
-
-	/*
-	 * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
-	 * N and cts values before enabling phy
-	 */
-	hdmi_init_clk_regenerator(hdmi);
-
-	/*
-	 * Configure registers related to HDMI interrupt
-	 * generation before registering IRQ.
-	 */
-	hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
-	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
-	ret = imx_hdmi_fb_registered(hdmi);
-	if (ret)
-		goto err_iahb;
-
-	ret = imx_hdmi_register(drm, hdmi);
-	if (ret)
-		goto err_iahb;
-
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
-	dev_set_drvdata(dev, hdmi);
-
-	return 0;
-
-err_iahb:
-	clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
-	clk_disable_unprepare(hdmi->isfr_clk);
-
-	return ret;
-}
-
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
-	void *data)
-{
-	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
-	/* Disable all interrupts */
-	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
-	hdmi->connector.funcs->destroy(&hdmi->connector);
-	hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
-	clk_disable_unprepare(hdmi->iahb_clk);
-	clk_disable_unprepare(hdmi->isfr_clk);
-	i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
-	.bind	= imx_hdmi_bind,
-	.unbind	= imx_hdmi_unbind,
-};
-
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
-{
-	return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
-{
-	component_del(&pdev->dev, &hdmi_ops);
-	return 0;
-}
-
-static struct platform_driver imx_hdmi_driver = {
-	.probe  = imx_hdmi_platform_probe,
-	.remove = imx_hdmi_platform_remove,
-	.driver = {
-		.name = "imx-hdmi",
-		.of_match_table = imx_hdmi_dt_ids,
-	},
-};
-
-module_platform_driver(imx_hdmi_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/gpu/drm/imx/imx-hdmi.h b/drivers/gpu/drm/imx/imx-hdmi.h
deleted file mode 100644
index 39b6776..0000000
--- a/drivers/gpu/drm/imx/imx-hdmi.h
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright (C) 2011 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
-
-/* Identification Registers */
-#define HDMI_DESIGN_ID                          0x0000
-#define HDMI_REVISION_ID                        0x0001
-#define HDMI_PRODUCT_ID0                        0x0002
-#define HDMI_PRODUCT_ID1                        0x0003
-#define HDMI_CONFIG0_ID                         0x0004
-#define HDMI_CONFIG1_ID                         0x0005
-#define HDMI_CONFIG2_ID                         0x0006
-#define HDMI_CONFIG3_ID                         0x0007
-
-/* Interrupt Registers */
-#define HDMI_IH_FC_STAT0                        0x0100
-#define HDMI_IH_FC_STAT1                        0x0101
-#define HDMI_IH_FC_STAT2                        0x0102
-#define HDMI_IH_AS_STAT0                        0x0103
-#define HDMI_IH_PHY_STAT0                       0x0104
-#define HDMI_IH_I2CM_STAT0                      0x0105
-#define HDMI_IH_CEC_STAT0                       0x0106
-#define HDMI_IH_VP_STAT0                        0x0107
-#define HDMI_IH_I2CMPHY_STAT0                   0x0108
-#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
-
-#define HDMI_IH_MUTE_FC_STAT0                   0x0180
-#define HDMI_IH_MUTE_FC_STAT1                   0x0181
-#define HDMI_IH_MUTE_FC_STAT2                   0x0182
-#define HDMI_IH_MUTE_AS_STAT0                   0x0183
-#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
-#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
-#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
-#define HDMI_IH_MUTE_VP_STAT0                   0x0187
-#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
-#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
-#define HDMI_IH_MUTE                            0x01FF
-
-/* Video Sample Registers */
-#define HDMI_TX_INVID0                          0x0200
-#define HDMI_TX_INSTUFFING                      0x0201
-#define HDMI_TX_GYDATA0                         0x0202
-#define HDMI_TX_GYDATA1                         0x0203
-#define HDMI_TX_RCRDATA0                        0x0204
-#define HDMI_TX_RCRDATA1                        0x0205
-#define HDMI_TX_BCBDATA0                        0x0206
-#define HDMI_TX_BCBDATA1                        0x0207
-
-/* Video Packetizer Registers */
-#define HDMI_VP_STATUS                          0x0800
-#define HDMI_VP_PR_CD                           0x0801
-#define HDMI_VP_STUFF                           0x0802
-#define HDMI_VP_REMAP                           0x0803
-#define HDMI_VP_CONF                            0x0804
-#define HDMI_VP_STAT                            0x0805
-#define HDMI_VP_INT                             0x0806
-#define HDMI_VP_MASK                            0x0807
-#define HDMI_VP_POL                             0x0808
-
-/* Frame Composer Registers */
-#define HDMI_FC_INVIDCONF                       0x1000
-#define HDMI_FC_INHACTV0                        0x1001
-#define HDMI_FC_INHACTV1                        0x1002
-#define HDMI_FC_INHBLANK0                       0x1003
-#define HDMI_FC_INHBLANK1                       0x1004
-#define HDMI_FC_INVACTV0                        0x1005
-#define HDMI_FC_INVACTV1                        0x1006
-#define HDMI_FC_INVBLANK                        0x1007
-#define HDMI_FC_HSYNCINDELAY0                   0x1008
-#define HDMI_FC_HSYNCINDELAY1                   0x1009
-#define HDMI_FC_HSYNCINWIDTH0                   0x100A
-#define HDMI_FC_HSYNCINWIDTH1                   0x100B
-#define HDMI_FC_VSYNCINDELAY                    0x100C
-#define HDMI_FC_VSYNCINWIDTH                    0x100D
-#define HDMI_FC_INFREQ0                         0x100E
-#define HDMI_FC_INFREQ1                         0x100F
-#define HDMI_FC_INFREQ2                         0x1010
-#define HDMI_FC_CTRLDUR                         0x1011
-#define HDMI_FC_EXCTRLDUR                       0x1012
-#define HDMI_FC_EXCTRLSPAC                      0x1013
-#define HDMI_FC_CH0PREAM                        0x1014
-#define HDMI_FC_CH1PREAM                        0x1015
-#define HDMI_FC_CH2PREAM                        0x1016
-#define HDMI_FC_AVICONF3                        0x1017
-#define HDMI_FC_GCP                             0x1018
-#define HDMI_FC_AVICONF0                        0x1019
-#define HDMI_FC_AVICONF1                        0x101A
-#define HDMI_FC_AVICONF2                        0x101B
-#define HDMI_FC_AVIVID                          0x101C
-#define HDMI_FC_AVIETB0                         0x101D
-#define HDMI_FC_AVIETB1                         0x101E
-#define HDMI_FC_AVISBB0                         0x101F
-#define HDMI_FC_AVISBB1                         0x1020
-#define HDMI_FC_AVIELB0                         0x1021
-#define HDMI_FC_AVIELB1                         0x1022
-#define HDMI_FC_AVISRB0                         0x1023
-#define HDMI_FC_AVISRB1                         0x1024
-#define HDMI_FC_AUDICONF0                       0x1025
-#define HDMI_FC_AUDICONF1                       0x1026
-#define HDMI_FC_AUDICONF2                       0x1027
-#define HDMI_FC_AUDICONF3                       0x1028
-#define HDMI_FC_VSDIEEEID0                      0x1029
-#define HDMI_FC_VSDSIZE                         0x102A
-#define HDMI_FC_VSDIEEEID1                      0x1030
-#define HDMI_FC_VSDIEEEID2                      0x1031
-#define HDMI_FC_VSDPAYLOAD0                     0x1032
-#define HDMI_FC_VSDPAYLOAD1                     0x1033
-#define HDMI_FC_VSDPAYLOAD2                     0x1034
-#define HDMI_FC_VSDPAYLOAD3                     0x1035
-#define HDMI_FC_VSDPAYLOAD4                     0x1036
-#define HDMI_FC_VSDPAYLOAD5                     0x1037
-#define HDMI_FC_VSDPAYLOAD6                     0x1038
-#define HDMI_FC_VSDPAYLOAD7                     0x1039
-#define HDMI_FC_VSDPAYLOAD8                     0x103A
-#define HDMI_FC_VSDPAYLOAD9                     0x103B
-#define HDMI_FC_VSDPAYLOAD10                    0x103C
-#define HDMI_FC_VSDPAYLOAD11                    0x103D
-#define HDMI_FC_VSDPAYLOAD12                    0x103E
-#define HDMI_FC_VSDPAYLOAD13                    0x103F
-#define HDMI_FC_VSDPAYLOAD14                    0x1040
-#define HDMI_FC_VSDPAYLOAD15                    0x1041
-#define HDMI_FC_VSDPAYLOAD16                    0x1042
-#define HDMI_FC_VSDPAYLOAD17                    0x1043
-#define HDMI_FC_VSDPAYLOAD18                    0x1044
-#define HDMI_FC_VSDPAYLOAD19                    0x1045
-#define HDMI_FC_VSDPAYLOAD20                    0x1046
-#define HDMI_FC_VSDPAYLOAD21                    0x1047
-#define HDMI_FC_VSDPAYLOAD22                    0x1048
-#define HDMI_FC_VSDPAYLOAD23                    0x1049
-#define HDMI_FC_SPDVENDORNAME0                  0x104A
-#define HDMI_FC_SPDVENDORNAME1                  0x104B
-#define HDMI_FC_SPDVENDORNAME2                  0x104C
-#define HDMI_FC_SPDVENDORNAME3                  0x104D
-#define HDMI_FC_SPDVENDORNAME4                  0x104E
-#define HDMI_FC_SPDVENDORNAME5                  0x104F
-#define HDMI_FC_SPDVENDORNAME6                  0x1050
-#define HDMI_FC_SPDVENDORNAME7                  0x1051
-#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
-#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
-#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
-#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
-#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
-#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
-#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
-#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
-#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
-#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
-#define HDMI_FC_SDPPRODUCTNAME10                0x105C
-#define HDMI_FC_SDPPRODUCTNAME11                0x105D
-#define HDMI_FC_SDPPRODUCTNAME12                0x105E
-#define HDMI_FC_SDPPRODUCTNAME13                0x105F
-#define HDMI_FC_SDPPRODUCTNAME14                0x1060
-#define HDMI_FC_SPDPRODUCTNAME15                0x1061
-#define HDMI_FC_SPDDEVICEINF                    0x1062
-#define HDMI_FC_AUDSCONF                        0x1063
-#define HDMI_FC_AUDSSTAT                        0x1064
-#define HDMI_FC_DATACH0FILL                     0x1070
-#define HDMI_FC_DATACH1FILL                     0x1071
-#define HDMI_FC_DATACH2FILL                     0x1072
-#define HDMI_FC_CTRLQHIGH                       0x1073
-#define HDMI_FC_CTRLQLOW                        0x1074
-#define HDMI_FC_ACP0                            0x1075
-#define HDMI_FC_ACP28                           0x1076
-#define HDMI_FC_ACP27                           0x1077
-#define HDMI_FC_ACP26                           0x1078
-#define HDMI_FC_ACP25                           0x1079
-#define HDMI_FC_ACP24                           0x107A
-#define HDMI_FC_ACP23                           0x107B
-#define HDMI_FC_ACP22                           0x107C
-#define HDMI_FC_ACP21                           0x107D
-#define HDMI_FC_ACP20                           0x107E
-#define HDMI_FC_ACP19                           0x107F
-#define HDMI_FC_ACP18                           0x1080
-#define HDMI_FC_ACP17                           0x1081
-#define HDMI_FC_ACP16                           0x1082
-#define HDMI_FC_ACP15                           0x1083
-#define HDMI_FC_ACP14                           0x1084
-#define HDMI_FC_ACP13                           0x1085
-#define HDMI_FC_ACP12                           0x1086
-#define HDMI_FC_ACP11                           0x1087
-#define HDMI_FC_ACP10                           0x1088
-#define HDMI_FC_ACP9                            0x1089
-#define HDMI_FC_ACP8                            0x108A
-#define HDMI_FC_ACP7                            0x108B
-#define HDMI_FC_ACP6                            0x108C
-#define HDMI_FC_ACP5                            0x108D
-#define HDMI_FC_ACP4                            0x108E
-#define HDMI_FC_ACP3                            0x108F
-#define HDMI_FC_ACP2                            0x1090
-#define HDMI_FC_ACP1                            0x1091
-#define HDMI_FC_ISCR1_0                         0x1092
-#define HDMI_FC_ISCR1_16                        0x1093
-#define HDMI_FC_ISCR1_15                        0x1094
-#define HDMI_FC_ISCR1_14                        0x1095
-#define HDMI_FC_ISCR1_13                        0x1096
-#define HDMI_FC_ISCR1_12                        0x1097
-#define HDMI_FC_ISCR1_11                        0x1098
-#define HDMI_FC_ISCR1_10                        0x1099
-#define HDMI_FC_ISCR1_9                         0x109A
-#define HDMI_FC_ISCR1_8                         0x109B
-#define HDMI_FC_ISCR1_7                         0x109C
-#define HDMI_FC_ISCR1_6                         0x109D
-#define HDMI_FC_ISCR1_5                         0x109E
-#define HDMI_FC_ISCR1_4                         0x109F
-#define HDMI_FC_ISCR1_3                         0x10A0
-#define HDMI_FC_ISCR1_2                         0x10A1
-#define HDMI_FC_ISCR1_1                         0x10A2
-#define HDMI_FC_ISCR2_15                        0x10A3
-#define HDMI_FC_ISCR2_14                        0x10A4
-#define HDMI_FC_ISCR2_13                        0x10A5
-#define HDMI_FC_ISCR2_12                        0x10A6
-#define HDMI_FC_ISCR2_11                        0x10A7
-#define HDMI_FC_ISCR2_10                        0x10A8
-#define HDMI_FC_ISCR2_9                         0x10A9
-#define HDMI_FC_ISCR2_8                         0x10AA
-#define HDMI_FC_ISCR2_7                         0x10AB
-#define HDMI_FC_ISCR2_6                         0x10AC
-#define HDMI_FC_ISCR2_5                         0x10AD
-#define HDMI_FC_ISCR2_4                         0x10AE
-#define HDMI_FC_ISCR2_3                         0x10AF
-#define HDMI_FC_ISCR2_2                         0x10B0
-#define HDMI_FC_ISCR2_1                         0x10B1
-#define HDMI_FC_ISCR2_0                         0x10B2
-#define HDMI_FC_DATAUTO0                        0x10B3
-#define HDMI_FC_DATAUTO1                        0x10B4
-#define HDMI_FC_DATAUTO2                        0x10B5
-#define HDMI_FC_DATMAN                          0x10B6
-#define HDMI_FC_DATAUTO3                        0x10B7
-#define HDMI_FC_RDRB0                           0x10B8
-#define HDMI_FC_RDRB1                           0x10B9
-#define HDMI_FC_RDRB2                           0x10BA
-#define HDMI_FC_RDRB3                           0x10BB
-#define HDMI_FC_RDRB4                           0x10BC
-#define HDMI_FC_RDRB5                           0x10BD
-#define HDMI_FC_RDRB6                           0x10BE
-#define HDMI_FC_RDRB7                           0x10BF
-#define HDMI_FC_STAT0                           0x10D0
-#define HDMI_FC_INT0                            0x10D1
-#define HDMI_FC_MASK0                           0x10D2
-#define HDMI_FC_POL0                            0x10D3
-#define HDMI_FC_STAT1                           0x10D4
-#define HDMI_FC_INT1                            0x10D5
-#define HDMI_FC_MASK1                           0x10D6
-#define HDMI_FC_POL1                            0x10D7
-#define HDMI_FC_STAT2                           0x10D8
-#define HDMI_FC_INT2                            0x10D9
-#define HDMI_FC_MASK2                           0x10DA
-#define HDMI_FC_POL2                            0x10DB
-#define HDMI_FC_PRCONF                          0x10E0
-
-#define HDMI_FC_GMD_STAT                        0x1100
-#define HDMI_FC_GMD_EN                          0x1101
-#define HDMI_FC_GMD_UP                          0x1102
-#define HDMI_FC_GMD_CONF                        0x1103
-#define HDMI_FC_GMD_HB                          0x1104
-#define HDMI_FC_GMD_PB0                         0x1105
-#define HDMI_FC_GMD_PB1                         0x1106
-#define HDMI_FC_GMD_PB2                         0x1107
-#define HDMI_FC_GMD_PB3                         0x1108
-#define HDMI_FC_GMD_PB4                         0x1109
-#define HDMI_FC_GMD_PB5                         0x110A
-#define HDMI_FC_GMD_PB6                         0x110B
-#define HDMI_FC_GMD_PB7                         0x110C
-#define HDMI_FC_GMD_PB8                         0x110D
-#define HDMI_FC_GMD_PB9                         0x110E
-#define HDMI_FC_GMD_PB10                        0x110F
-#define HDMI_FC_GMD_PB11                        0x1110
-#define HDMI_FC_GMD_PB12                        0x1111
-#define HDMI_FC_GMD_PB13                        0x1112
-#define HDMI_FC_GMD_PB14                        0x1113
-#define HDMI_FC_GMD_PB15                        0x1114
-#define HDMI_FC_GMD_PB16                        0x1115
-#define HDMI_FC_GMD_PB17                        0x1116
-#define HDMI_FC_GMD_PB18                        0x1117
-#define HDMI_FC_GMD_PB19                        0x1118
-#define HDMI_FC_GMD_PB20                        0x1119
-#define HDMI_FC_GMD_PB21                        0x111A
-#define HDMI_FC_GMD_PB22                        0x111B
-#define HDMI_FC_GMD_PB23                        0x111C
-#define HDMI_FC_GMD_PB24                        0x111D
-#define HDMI_FC_GMD_PB25                        0x111E
-#define HDMI_FC_GMD_PB26                        0x111F
-#define HDMI_FC_GMD_PB27                        0x1120
-
-#define HDMI_FC_DBGFORCE                        0x1200
-#define HDMI_FC_DBGAUD0CH0                      0x1201
-#define HDMI_FC_DBGAUD1CH0                      0x1202
-#define HDMI_FC_DBGAUD2CH0                      0x1203
-#define HDMI_FC_DBGAUD0CH1                      0x1204
-#define HDMI_FC_DBGAUD1CH1                      0x1205
-#define HDMI_FC_DBGAUD2CH1                      0x1206
-#define HDMI_FC_DBGAUD0CH2                      0x1207
-#define HDMI_FC_DBGAUD1CH2                      0x1208
-#define HDMI_FC_DBGAUD2CH2                      0x1209
-#define HDMI_FC_DBGAUD0CH3                      0x120A
-#define HDMI_FC_DBGAUD1CH3                      0x120B
-#define HDMI_FC_DBGAUD2CH3                      0x120C
-#define HDMI_FC_DBGAUD0CH4                      0x120D
-#define HDMI_FC_DBGAUD1CH4                      0x120E
-#define HDMI_FC_DBGAUD2CH4                      0x120F
-#define HDMI_FC_DBGAUD0CH5                      0x1210
-#define HDMI_FC_DBGAUD1CH5                      0x1211
-#define HDMI_FC_DBGAUD2CH5                      0x1212
-#define HDMI_FC_DBGAUD0CH6                      0x1213
-#define HDMI_FC_DBGAUD1CH6                      0x1214
-#define HDMI_FC_DBGAUD2CH6                      0x1215
-#define HDMI_FC_DBGAUD0CH7                      0x1216
-#define HDMI_FC_DBGAUD1CH7                      0x1217
-#define HDMI_FC_DBGAUD2CH7                      0x1218
-#define HDMI_FC_DBGTMDS0                        0x1219
-#define HDMI_FC_DBGTMDS1                        0x121A
-#define HDMI_FC_DBGTMDS2                        0x121B
-
-/* HDMI Source PHY Registers */
-#define HDMI_PHY_CONF0                          0x3000
-#define HDMI_PHY_TST0                           0x3001
-#define HDMI_PHY_TST1                           0x3002
-#define HDMI_PHY_TST2                           0x3003
-#define HDMI_PHY_STAT0                          0x3004
-#define HDMI_PHY_INT0                           0x3005
-#define HDMI_PHY_MASK0                          0x3006
-#define HDMI_PHY_POL0                           0x3007
-
-/* HDMI Master PHY Registers */
-#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
-#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
-#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
-#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
-#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
-#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
-#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
-#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
-#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
-#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
-#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
-
-/* Audio Sampler Registers */
-#define HDMI_AUD_CONF0                          0x3100
-#define HDMI_AUD_CONF1                          0x3101
-#define HDMI_AUD_INT                            0x3102
-#define HDMI_AUD_CONF2                          0x3103
-#define HDMI_AUD_N1                             0x3200
-#define HDMI_AUD_N2                             0x3201
-#define HDMI_AUD_N3                             0x3202
-#define HDMI_AUD_CTS1                           0x3203
-#define HDMI_AUD_CTS2                           0x3204
-#define HDMI_AUD_CTS3                           0x3205
-#define HDMI_AUD_INPUTCLKFS                     0x3206
-#define HDMI_AUD_SPDIFINT			0x3302
-#define HDMI_AUD_CONF0_HBR                      0x3400
-#define HDMI_AUD_HBR_STATUS                     0x3401
-#define HDMI_AUD_HBR_INT                        0x3402
-#define HDMI_AUD_HBR_POL                        0x3403
-#define HDMI_AUD_HBR_MASK                       0x3404
-
-/*
- * Generic Parallel Audio Interface Registers
- * Not used as GPAUD interface is not enabled in hw
- */
-#define HDMI_GP_CONF0                           0x3500
-#define HDMI_GP_CONF1                           0x3501
-#define HDMI_GP_CONF2                           0x3502
-#define HDMI_GP_STAT                            0x3503
-#define HDMI_GP_INT                             0x3504
-#define HDMI_GP_MASK                            0x3505
-#define HDMI_GP_POL                             0x3506
-
-/* Audio DMA Registers */
-#define HDMI_AHB_DMA_CONF0                      0x3600
-#define HDMI_AHB_DMA_START                      0x3601
-#define HDMI_AHB_DMA_STOP                       0x3602
-#define HDMI_AHB_DMA_THRSLD                     0x3603
-#define HDMI_AHB_DMA_STRADDR0                   0x3604
-#define HDMI_AHB_DMA_STRADDR1                   0x3605
-#define HDMI_AHB_DMA_STRADDR2                   0x3606
-#define HDMI_AHB_DMA_STRADDR3                   0x3607
-#define HDMI_AHB_DMA_STPADDR0                   0x3608
-#define HDMI_AHB_DMA_STPADDR1                   0x3609
-#define HDMI_AHB_DMA_STPADDR2                   0x360a
-#define HDMI_AHB_DMA_STPADDR3                   0x360b
-#define HDMI_AHB_DMA_BSTADDR0                   0x360c
-#define HDMI_AHB_DMA_BSTADDR1                   0x360d
-#define HDMI_AHB_DMA_BSTADDR2                   0x360e
-#define HDMI_AHB_DMA_BSTADDR3                   0x360f
-#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
-#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
-#define HDMI_AHB_DMA_STAT                       0x3612
-#define HDMI_AHB_DMA_INT                        0x3613
-#define HDMI_AHB_DMA_MASK                       0x3614
-#define HDMI_AHB_DMA_POL                        0x3615
-#define HDMI_AHB_DMA_CONF1                      0x3616
-#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
-#define HDMI_AHB_DMA_BUFFINT                    0x3618
-#define HDMI_AHB_DMA_BUFFMASK                   0x3619
-#define HDMI_AHB_DMA_BUFFPOL                    0x361a
-
-/* Main Controller Registers */
-#define HDMI_MC_SFRDIV                          0x4000
-#define HDMI_MC_CLKDIS                          0x4001
-#define HDMI_MC_SWRSTZ                          0x4002
-#define HDMI_MC_OPCTRL                          0x4003
-#define HDMI_MC_FLOWCTRL                        0x4004
-#define HDMI_MC_PHYRSTZ                         0x4005
-#define HDMI_MC_LOCKONCLOCK                     0x4006
-#define HDMI_MC_HEACPHY_RST                     0x4007
-
-/* Color Space  Converter Registers */
-#define HDMI_CSC_CFG                            0x4100
-#define HDMI_CSC_SCALE                          0x4101
-#define HDMI_CSC_COEF_A1_MSB                    0x4102
-#define HDMI_CSC_COEF_A1_LSB                    0x4103
-#define HDMI_CSC_COEF_A2_MSB                    0x4104
-#define HDMI_CSC_COEF_A2_LSB                    0x4105
-#define HDMI_CSC_COEF_A3_MSB                    0x4106
-#define HDMI_CSC_COEF_A3_LSB                    0x4107
-#define HDMI_CSC_COEF_A4_MSB                    0x4108
-#define HDMI_CSC_COEF_A4_LSB                    0x4109
-#define HDMI_CSC_COEF_B1_MSB                    0x410A
-#define HDMI_CSC_COEF_B1_LSB                    0x410B
-#define HDMI_CSC_COEF_B2_MSB                    0x410C
-#define HDMI_CSC_COEF_B2_LSB                    0x410D
-#define HDMI_CSC_COEF_B3_MSB                    0x410E
-#define HDMI_CSC_COEF_B3_LSB                    0x410F
-#define HDMI_CSC_COEF_B4_MSB                    0x4110
-#define HDMI_CSC_COEF_B4_LSB                    0x4111
-#define HDMI_CSC_COEF_C1_MSB                    0x4112
-#define HDMI_CSC_COEF_C1_LSB                    0x4113
-#define HDMI_CSC_COEF_C2_MSB                    0x4114
-#define HDMI_CSC_COEF_C2_LSB                    0x4115
-#define HDMI_CSC_COEF_C3_MSB                    0x4116
-#define HDMI_CSC_COEF_C3_LSB                    0x4117
-#define HDMI_CSC_COEF_C4_MSB                    0x4118
-#define HDMI_CSC_COEF_C4_LSB                    0x4119
-
-/* HDCP Encryption Engine Registers */
-#define HDMI_A_HDCPCFG0                         0x5000
-#define HDMI_A_HDCPCFG1                         0x5001
-#define HDMI_A_HDCPOBS0                         0x5002
-#define HDMI_A_HDCPOBS1                         0x5003
-#define HDMI_A_HDCPOBS2                         0x5004
-#define HDMI_A_HDCPOBS3                         0x5005
-#define HDMI_A_APIINTCLR                        0x5006
-#define HDMI_A_APIINTSTAT                       0x5007
-#define HDMI_A_APIINTMSK                        0x5008
-#define HDMI_A_VIDPOLCFG                        0x5009
-#define HDMI_A_OESSWCFG                         0x500A
-#define HDMI_A_TIMER1SETUP0                     0x500B
-#define HDMI_A_TIMER1SETUP1                     0x500C
-#define HDMI_A_TIMER2SETUP0                     0x500D
-#define HDMI_A_TIMER2SETUP1                     0x500E
-#define HDMI_A_100MSCFG                         0x500F
-#define HDMI_A_2SCFG0                           0x5010
-#define HDMI_A_2SCFG1                           0x5011
-#define HDMI_A_5SCFG0                           0x5012
-#define HDMI_A_5SCFG1                           0x5013
-#define HDMI_A_SRMVERLSB                        0x5014
-#define HDMI_A_SRMVERMSB                        0x5015
-#define HDMI_A_SRMCTRL                          0x5016
-#define HDMI_A_SFRSETUP                         0x5017
-#define HDMI_A_I2CHSETUP                        0x5018
-#define HDMI_A_INTSETUP                         0x5019
-#define HDMI_A_PRESETUP                         0x501A
-#define HDMI_A_SRM_BASE                         0x5020
-
-/* CEC Engine Registers */
-#define HDMI_CEC_CTRL                           0x7D00
-#define HDMI_CEC_STAT                           0x7D01
-#define HDMI_CEC_MASK                           0x7D02
-#define HDMI_CEC_POLARITY                       0x7D03
-#define HDMI_CEC_INT                            0x7D04
-#define HDMI_CEC_ADDR_L                         0x7D05
-#define HDMI_CEC_ADDR_H                         0x7D06
-#define HDMI_CEC_TX_CNT                         0x7D07
-#define HDMI_CEC_RX_CNT                         0x7D08
-#define HDMI_CEC_TX_DATA0                       0x7D10
-#define HDMI_CEC_TX_DATA1                       0x7D11
-#define HDMI_CEC_TX_DATA2                       0x7D12
-#define HDMI_CEC_TX_DATA3                       0x7D13
-#define HDMI_CEC_TX_DATA4                       0x7D14
-#define HDMI_CEC_TX_DATA5                       0x7D15
-#define HDMI_CEC_TX_DATA6                       0x7D16
-#define HDMI_CEC_TX_DATA7                       0x7D17
-#define HDMI_CEC_TX_DATA8                       0x7D18
-#define HDMI_CEC_TX_DATA9                       0x7D19
-#define HDMI_CEC_TX_DATA10                      0x7D1a
-#define HDMI_CEC_TX_DATA11                      0x7D1b
-#define HDMI_CEC_TX_DATA12                      0x7D1c
-#define HDMI_CEC_TX_DATA13                      0x7D1d
-#define HDMI_CEC_TX_DATA14                      0x7D1e
-#define HDMI_CEC_TX_DATA15                      0x7D1f
-#define HDMI_CEC_RX_DATA0                       0x7D20
-#define HDMI_CEC_RX_DATA1                       0x7D21
-#define HDMI_CEC_RX_DATA2                       0x7D22
-#define HDMI_CEC_RX_DATA3                       0x7D23
-#define HDMI_CEC_RX_DATA4                       0x7D24
-#define HDMI_CEC_RX_DATA5                       0x7D25
-#define HDMI_CEC_RX_DATA6                       0x7D26
-#define HDMI_CEC_RX_DATA7                       0x7D27
-#define HDMI_CEC_RX_DATA8                       0x7D28
-#define HDMI_CEC_RX_DATA9                       0x7D29
-#define HDMI_CEC_RX_DATA10                      0x7D2a
-#define HDMI_CEC_RX_DATA11                      0x7D2b
-#define HDMI_CEC_RX_DATA12                      0x7D2c
-#define HDMI_CEC_RX_DATA13                      0x7D2d
-#define HDMI_CEC_RX_DATA14                      0x7D2e
-#define HDMI_CEC_RX_DATA15                      0x7D2f
-#define HDMI_CEC_LOCK                           0x7D30
-#define HDMI_CEC_WKUPCTRL                       0x7D31
-
-/* I2C Master Registers (E-DDC) */
-#define HDMI_I2CM_SLAVE                         0x7E00
-#define HDMI_I2CMESS                            0x7E01
-#define HDMI_I2CM_DATAO                         0x7E02
-#define HDMI_I2CM_DATAI                         0x7E03
-#define HDMI_I2CM_OPERATION                     0x7E04
-#define HDMI_I2CM_INT                           0x7E05
-#define HDMI_I2CM_CTLINT                        0x7E06
-#define HDMI_I2CM_DIV                           0x7E07
-#define HDMI_I2CM_SEGADDR                       0x7E08
-#define HDMI_I2CM_SOFTRSTZ                      0x7E09
-#define HDMI_I2CM_SEGPTR                        0x7E0A
-#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
-#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
-#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
-#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
-#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
-#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
-#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
-#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
-
-enum {
-/* IH_FC_INT2 field values */
-	HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
-	HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_FC_STAT2 field values */
-	HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
-	HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_PHY_STAT0 field values */
-	HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
-	HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
-	HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
-	HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
-	HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
-	HDMI_IH_PHY_STAT0_HPD = 0x1,
-
-/* IH_MUTE_I2CMPHY_STAT0 field values */
-	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
-	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
-
-/* IH_AHBDMAAUD_STAT0 field values */
-	HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
-	HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
-	HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
-	HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
-	HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
-	HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE_FC_STAT2 field values */
-	HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
-	HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_MUTE_AHBDMAAUD_STAT0 field values */
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
-	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE field values */
-	HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
-	HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
-
-/* TX_INVID0 field values */
-	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
-	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
-	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
-	HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
-	HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
-
-/* TX_INSTUFFING field values */
-	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
-	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
-	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
-	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
-	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
-	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
-	HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
-	HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
-	HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
-
-/* VP_PR_CD field values */
-	HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
-	HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
-	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
-	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
-
-/* VP_STUFF field values */
-	HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
-	HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
-	HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
-	HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
-	HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
-	HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
-	HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
-	HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
-	HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
-	HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
-	HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
-	HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
-	HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
-	HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
-	HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
-
-/* VP_CONF field values */
-	HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
-	HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
-	HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
-	HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
-	HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
-	HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
-	HDMI_VP_CONF_PR_EN_MASK = 0x10,
-	HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
-	HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
-	HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
-	HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
-	HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
-	HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
-	HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
-	HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
-	HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
-	HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
-	HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
-	HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
-
-/* VP_REMAP field values */
-	HDMI_VP_REMAP_MASK = 0x3,
-	HDMI_VP_REMAP_YCC422_24bit = 0x2,
-	HDMI_VP_REMAP_YCC422_20bit = 0x1,
-	HDMI_VP_REMAP_YCC422_16bit = 0x0,
-
-/* FC_INVIDCONF field values */
-	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
-	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
-	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
-	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
-	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
-	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
-	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
-	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
-	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
-	HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
-	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
-	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
-	HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
-	HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
-	HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
-	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
-	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
-	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
-	HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
-	HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
-	HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
-
-/* FC_AUDICONF0 field values */
-	HDMI_FC_AUDICONF0_CC_OFFSET = 4,
-	HDMI_FC_AUDICONF0_CC_MASK = 0x70,
-	HDMI_FC_AUDICONF0_CT_OFFSET = 0,
-	HDMI_FC_AUDICONF0_CT_MASK = 0xF,
-
-/* FC_AUDICONF1 field values */
-	HDMI_FC_AUDICONF1_SS_OFFSET = 3,
-	HDMI_FC_AUDICONF1_SS_MASK = 0x18,
-	HDMI_FC_AUDICONF1_SF_OFFSET = 0,
-	HDMI_FC_AUDICONF1_SF_MASK = 0x7,
-
-/* FC_AUDICONF3 field values */
-	HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
-	HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
-	HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
-	HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
-	HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
-	HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
-
-/* FC_AUDSCHNLS0 field values */
-	HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
-	HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
-	HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
-
-/* FC_AUDSCHNLS3-6 field values */
-	HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
-	HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
-	HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
-	HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
-	HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
-	HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
-
-	HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
-	HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
-	HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
-	HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
-	HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
-	HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
-
-/* HDMI_FC_AUDSCHNLS7 field values */
-	HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
-
-/* HDMI_FC_AUDSCHNLS8 field values */
-	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
-	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
-	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
-	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
-
-/* FC_AUDSCONF field values */
-	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
-	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
-	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
-	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
-	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
-	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
-
-/* FC_STAT2 field values */
-	HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
-	HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_INT2 field values */
-	HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
-	HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_MASK2 field values */
-	HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
-	HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
-	HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_PRCONF field values */
-	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
-	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
-	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
-	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
-
-/* FC_AVICONF0-FC_AVICONF3 field values */
-	HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
-	HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
-	HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
-	HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
-	HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
-	HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
-	HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
-	HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
-	HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
-	HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
-	HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
-	HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
-	HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
-	HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
-	HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
-	HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
-
-	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
-	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
-	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
-	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
-	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
-	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
-	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
-	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
-	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
-	HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
-	HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
-	HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
-	HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
-	HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
-
-	HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
-	HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
-	HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
-	HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
-	HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
-	HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
-	HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
-	HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
-	HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
-	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
-	HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
-	HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
-	HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
-
-	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
-	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
-	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
-	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
-	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
-	HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
-	HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
-	HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
-
-/* FC_DBGFORCE field values */
-	HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
-	HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
-
-/* PHY_CONF0 field values */
-	HDMI_PHY_CONF0_PDZ_MASK = 0x80,
-	HDMI_PHY_CONF0_PDZ_OFFSET = 7,
-	HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
-	HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
-	HDMI_PHY_CONF0_SPARECTRL = 0x20,
-	HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
-	HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
-	HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
-	HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
-	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
-	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
-	HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
-	HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
-	HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
-	HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
-
-/* PHY_TST0 field values */
-	HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
-	HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
-	HDMI_PHY_TST0_TSTEN_MASK = 0x10,
-	HDMI_PHY_TST0_TSTEN_OFFSET = 4,
-	HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
-	HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
-
-/* PHY_STAT0 field values */
-	HDMI_PHY_RX_SENSE3 = 0x80,
-	HDMI_PHY_RX_SENSE2 = 0x40,
-	HDMI_PHY_RX_SENSE1 = 0x20,
-	HDMI_PHY_RX_SENSE0 = 0x10,
-	HDMI_PHY_HPD = 0x02,
-	HDMI_PHY_TX_PHY_LOCK = 0x01,
-
-/* PHY_I2CM_SLAVE_ADDR field values */
-	HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
-	HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
-
-/* PHY_I2CM_OPERATION_ADDR field values */
-	HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
-	HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
-
-/* HDMI_PHY_I2CM_INT_ADDR */
-	HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
-	HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
-
-/* HDMI_PHY_I2CM_CTLINT_ADDR */
-	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
-	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
-	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
-	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
-
-/* AUD_CTS3 field values */
-	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
-	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
-	HDMI_AUD_CTS3_N_SHIFT_1 = 0,
-	HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
-	HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
-	HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
-	HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
-	HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
-	/* note that the CTS3 MANUAL bit has been removed
-	   from our part. Can't set it, will read as 0. */
-	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
-	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
-
-/* AHB_DMA_CONF0 field values */
-	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
-	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-	HDMI_AHB_DMA_CONF0_HBR = 0x10,
-	HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
-	HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
-	HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
-	HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
-	HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
-	HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
-	HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
-	HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
-
-/* HDMI_AHB_DMA_START field values */
-	HDMI_AHB_DMA_START_START_OFFSET = 0,
-	HDMI_AHB_DMA_START_START_MASK = 0x01,
-
-/* HDMI_AHB_DMA_STOP field values */
-	HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
-	HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
-
-/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
-	HDMI_AHB_DMA_DONE = 0x80,
-	HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
-	HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
-	HDMI_AHB_DMA_ERROR = 0x10,
-	HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
-	HDMI_AHB_DMA_FIFO_FULL = 0x02,
-	HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
-
-/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
-	HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
-	HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
-
-/* MC_CLKDIS field values */
-	HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
-	HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
-	HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
-	HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
-	HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
-	HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
-	HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
-
-/* MC_SWRSTZ field values */
-	HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
-
-/* MC_FLOWCTRL field values */
-	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
-	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
-	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
-
-/* MC_PHYRSTZ field values */
-	HDMI_MC_PHYRSTZ_ASSERT = 0x0,
-	HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
-
-/* MC_HEACPHY_RST field values */
-	HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
-	HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
-
-/* CSC_CFG field values */
-	HDMI_CSC_CFG_INTMODE_MASK = 0x30,
-	HDMI_CSC_CFG_INTMODE_OFFSET = 4,
-	HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
-	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
-	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
-	HDMI_CSC_CFG_DECMODE_MASK = 0x3,
-	HDMI_CSC_CFG_DECMODE_OFFSET = 0,
-	HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
-	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
-	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
-	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
-
-/* CSC_SCALE field values */
-	HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
-	HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
-	HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
-	HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
-	HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
-	HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
-
-/* A_HDCPCFG0 field values */
-	HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
-	HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
-	HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
-	HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
-	HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
-	HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
-	HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
-	HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
-	HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
-	HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
-	HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
-	HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
-	HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
-	HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
-	HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
-	HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
-	HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
-	HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
-	HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
-	HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
-	HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
-	HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
-	HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
-	HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
-
-/* A_HDCPCFG1 field values */
-	HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
-	HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
-	HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
-	HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
-	HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
-	HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
-	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
-	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
-	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
-	HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
-	HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
-
-/* A_VIDPOLCFG field values */
-	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
-	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
-	HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
-	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
-	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
-	HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
-	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
-	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
-	HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
-	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
-	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
-};
-#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index c604600..1b86aac 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -163,7 +163,7 @@
 {
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
-	struct drm_display_mode *mode = &encoder->crtc->mode;
+	struct drm_display_mode *mode = &encoder->crtc->hwmode;
 	u32 pixel_fmt;
 	unsigned long serial_clk;
 	unsigned long di_clk = mode->clock * 1000;
@@ -241,8 +241,8 @@
 }
 
 static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+			 struct drm_display_mode *orig_mode,
+			 struct drm_display_mode *mode)
 {
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
@@ -574,6 +574,8 @@
 
 		channel->connector.funcs->destroy(&channel->connector);
 		channel->encoder.funcs->destroy(&channel->encoder);
+
+		kfree(channel->edid);
 	}
 }
 
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index a729f4f7..4216e47 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -191,10 +191,18 @@
 	/* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
 	ret = regmap_update_bits(tve->regmap, TVE_TVDAC0_CONT_REG,
 				 TVE_TVDAC_GAIN_MASK, 0x0a);
+	if (ret)
+		return ret;
+
 	ret = regmap_update_bits(tve->regmap, TVE_TVDAC1_CONT_REG,
 				 TVE_TVDAC_GAIN_MASK, 0x0a);
+	if (ret)
+		return ret;
+
 	ret = regmap_update_bits(tve->regmap, TVE_TVDAC2_CONT_REG,
 				 TVE_TVDAC_GAIN_MASK, 0x0a);
+	if (ret)
+		return ret;
 
 	/* set configuration register */
 	mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM;
@@ -204,16 +212,12 @@
 	mask |= TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN;
 	val  |= TVE_TV_OUT_RGB       | TVE_SYNC_CH_0_EN;
 	ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, mask, val);
-	if (ret < 0) {
-		dev_err(tve->dev, "failed to set configuration: %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	/* set test mode (as documented) */
-	ret = regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
+	return regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
 				 TVE_TVDAC_TEST_MODE_MASK, 1);
-
-	return 0;
 }
 
 static enum drm_connector_status imx_tve_connector_detect(
@@ -307,8 +311,8 @@
 }
 
 static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
-				     struct drm_display_mode *mode,
-				     struct drm_display_mode *adjusted_mode)
+				     struct drm_display_mode *orig_mode,
+				     struct drm_display_mode *mode)
 {
 	struct imx_tve *tve = enc_to_tve(encoder);
 	unsigned long rounded_rate;
@@ -335,9 +339,11 @@
 	}
 
 	if (tve->mode == TVE_MODE_VGA)
-		tve_setup_vga(tve);
+		ret = tve_setup_vga(tve);
 	else
-		tve_setup_tvout(tve);
+		ret = tve_setup_tvout(tve);
+	if (ret)
+		dev_err(tve->dev, "failed to set configuration: %d\n", ret);
 }
 
 static void imx_tve_encoder_commit(struct drm_encoder *encoder)
@@ -671,6 +677,8 @@
 
 	/* disable cable detection for VGA mode */
 	ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
+	if (ret)
+		return ret;
 
 	ret = imx_tve_register(drm, tve);
 	if (ret)
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index ebee59c..98551e3 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -46,7 +46,6 @@
 	struct drm_framebuffer	*newfb;
 	int			irq;
 	u32			interface_pix_fmt;
-	unsigned long		di_clkflags;
 	int			di_hsync_pin;
 	int			di_vsync_pin;
 };
@@ -141,47 +140,51 @@
 			       int x, int y,
 			       struct drm_framebuffer *old_fb)
 {
+	struct drm_device *dev = crtc->dev;
+	struct drm_encoder *encoder;
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-	int ret;
 	struct ipu_di_signal_cfg sig_cfg = {};
+	unsigned long encoder_types = 0;
 	u32 out_pixel_fmt;
+	int ret;
 
 	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
 			mode->hdisplay);
 	dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
 			mode->vdisplay);
 
-	out_pixel_fmt = ipu_crtc->interface_pix_fmt;
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		if (encoder->crtc == crtc)
+			encoder_types |= BIT(encoder->encoder_type);
 
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-		sig_cfg.interlaced = 1;
-	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-		sig_cfg.Hsync_pol = 1;
-	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-		sig_cfg.Vsync_pol = 1;
+	dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
+		__func__, encoder_types);
+
+	/*
+	 * If we have DAC, TVDAC or LDB, then we need the IPU DI clock
+	 * to be the same as the LDB DI clock.
+	 */
+	if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
+			     BIT(DRM_MODE_ENCODER_TVDAC) |
+			     BIT(DRM_MODE_ENCODER_LVDS)))
+		sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
+	else
+		sig_cfg.clkflags = 0;
+
+	out_pixel_fmt = ipu_crtc->interface_pix_fmt;
 
 	sig_cfg.enable_pol = 1;
 	sig_cfg.clk_pol = 0;
-	sig_cfg.width = mode->hdisplay;
-	sig_cfg.height = mode->vdisplay;
 	sig_cfg.pixel_fmt = out_pixel_fmt;
-	sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
-	sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
-	sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
-
-	sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
-	sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
-	sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
-	sig_cfg.pixelclock = mode->clock * 1000;
-	sig_cfg.clkflags = ipu_crtc->di_clkflags;
-
 	sig_cfg.v_to_h_sync = 0;
-
 	sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
 	sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
 
-	ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
-			out_pixel_fmt, mode->hdisplay);
+	drm_display_mode_to_videomode(mode, &sig_cfg.mode);
+
+	ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
+			       mode->flags & DRM_MODE_FLAG_INTERLACE,
+			       out_pixel_fmt, mode->hdisplay);
 	if (ret) {
 		dev_err(ipu_crtc->dev,
 				"initializing display controller failed with %d\n",
@@ -237,6 +240,18 @@
 				  const struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct videomode vm;
+	int ret;
+
+	drm_display_mode_to_videomode(adjusted_mode, &vm);
+
+	ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
+	if (ret)
+		return false;
+
+	drm_display_mode_from_videomode(&vm, adjusted_mode);
+
 	return true;
 }
 
@@ -275,7 +290,7 @@
 	ipu_crtc->newfb = NULL;
 }
 
-static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
+static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
 		u32 pixfmt, int hsync_pin, int vsync_pin)
 {
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
@@ -284,19 +299,6 @@
 	ipu_crtc->di_hsync_pin = hsync_pin;
 	ipu_crtc->di_vsync_pin = vsync_pin;
 
-	switch (encoder_type) {
-	case DRM_MODE_ENCODER_DAC:
-	case DRM_MODE_ENCODER_TVDAC:
-	case DRM_MODE_ENCODER_LVDS:
-		ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
-			IPU_DI_CLKMODE_EXT;
-		break;
-	case DRM_MODE_ENCODER_TMDS:
-	case DRM_MODE_ENCODER_NONE:
-		ipu_crtc->di_clkflags = 0;
-		break;
-	}
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 796c3c1..5e83e00 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -130,8 +130,8 @@
 }
 
 static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
-			 struct drm_display_mode *mode,
-			 struct drm_display_mode *adjusted_mode)
+			 struct drm_display_mode *orig_mode,
+			 struct drm_display_mode *mode)
 {
 }
 
@@ -257,6 +257,8 @@
 
 	imxpd->encoder.funcs->destroy(&imxpd->encoder);
 	imxpd->connector.funcs->destroy(&imxpd->connector);
+
+	kfree(imxpd->edid);
 }
 
 static const struct component_ops imx_pd_ops = {
@@ -272,6 +274,7 @@
 static int imx_pd_remove(struct platform_device *pdev)
 {
 	component_del(&pdev->dev, &imx_pd_ops);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 4415af3..c36b830 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -303,14 +303,22 @@
 	if (ret)
 		return ret;
 
-	drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
+	ret = drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(mdev->dev);
 
-	drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
+	ret = drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
+	if (ret)
+		goto fini;
 
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&mfbdev->helper);
+	return ret;
 }
 
 void mgag200_fbdev_fini(struct mga_device *mdev)
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 5b2a1ff..bacbbb7 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -3,6 +3,7 @@
 	tristate "MSM DRM"
 	depends on DRM
 	depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+	depends on OF && COMMON_CLK
 	select REGULATOR
 	select DRM_KMS_HELPER
 	select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 143d988..674a132 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -1,7 +1,4 @@
 ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
-ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
-	ccflags-y += -Werror
-endif
 
 msm-y := \
 	adreno/adreno_device.o \
@@ -16,6 +13,12 @@
 	hdmi/hdmi_phy_8960.o \
 	hdmi/hdmi_phy_8x60.o \
 	hdmi/hdmi_phy_8x74.o \
+	edp/edp.o \
+	edp/edp_aux.o \
+	edp/edp_bridge.o \
+	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 \
diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h
index 22882cc..edc845f 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h
@@ -12,9 +12,9 @@
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  51069 bytes, from 2014-12-21 15:51:54)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h
index 109e9a2..e91a739 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h
@@ -12,9 +12,9 @@
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  51069 bytes, from 2014-12-21 15:51:54)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -58,111 +58,130 @@
 };
 
 enum a3xx_vtx_fmt {
-	VFMT_FLOAT_32 = 0,
-	VFMT_FLOAT_32_32 = 1,
-	VFMT_FLOAT_32_32_32 = 2,
-	VFMT_FLOAT_32_32_32_32 = 3,
-	VFMT_FLOAT_16 = 4,
-	VFMT_FLOAT_16_16 = 5,
-	VFMT_FLOAT_16_16_16 = 6,
-	VFMT_FLOAT_16_16_16_16 = 7,
-	VFMT_FIXED_32 = 8,
-	VFMT_FIXED_32_32 = 9,
-	VFMT_FIXED_32_32_32 = 10,
-	VFMT_FIXED_32_32_32_32 = 11,
-	VFMT_SHORT_16 = 16,
-	VFMT_SHORT_16_16 = 17,
-	VFMT_SHORT_16_16_16 = 18,
-	VFMT_SHORT_16_16_16_16 = 19,
-	VFMT_USHORT_16 = 20,
-	VFMT_USHORT_16_16 = 21,
-	VFMT_USHORT_16_16_16 = 22,
-	VFMT_USHORT_16_16_16_16 = 23,
-	VFMT_NORM_SHORT_16 = 24,
-	VFMT_NORM_SHORT_16_16 = 25,
-	VFMT_NORM_SHORT_16_16_16 = 26,
-	VFMT_NORM_SHORT_16_16_16_16 = 27,
-	VFMT_NORM_USHORT_16 = 28,
-	VFMT_NORM_USHORT_16_16 = 29,
-	VFMT_NORM_USHORT_16_16_16 = 30,
-	VFMT_NORM_USHORT_16_16_16_16 = 31,
-	VFMT_UINT_32 = 32,
-	VFMT_UINT_32_32 = 33,
-	VFMT_UINT_32_32_32 = 34,
-	VFMT_UINT_32_32_32_32 = 35,
-	VFMT_INT_32 = 36,
-	VFMT_INT_32_32 = 37,
-	VFMT_INT_32_32_32 = 38,
-	VFMT_INT_32_32_32_32 = 39,
-	VFMT_UBYTE_8 = 40,
-	VFMT_UBYTE_8_8 = 41,
-	VFMT_UBYTE_8_8_8 = 42,
-	VFMT_UBYTE_8_8_8_8 = 43,
-	VFMT_NORM_UBYTE_8 = 44,
-	VFMT_NORM_UBYTE_8_8 = 45,
-	VFMT_NORM_UBYTE_8_8_8 = 46,
-	VFMT_NORM_UBYTE_8_8_8_8 = 47,
-	VFMT_BYTE_8 = 48,
-	VFMT_BYTE_8_8 = 49,
-	VFMT_BYTE_8_8_8 = 50,
-	VFMT_BYTE_8_8_8_8 = 51,
-	VFMT_NORM_BYTE_8 = 52,
-	VFMT_NORM_BYTE_8_8 = 53,
-	VFMT_NORM_BYTE_8_8_8 = 54,
-	VFMT_NORM_BYTE_8_8_8_8 = 55,
-	VFMT_UINT_10_10_10_2 = 60,
-	VFMT_NORM_UINT_10_10_10_2 = 61,
-	VFMT_INT_10_10_10_2 = 62,
-	VFMT_NORM_INT_10_10_10_2 = 63,
+	VFMT_32_FLOAT = 0,
+	VFMT_32_32_FLOAT = 1,
+	VFMT_32_32_32_FLOAT = 2,
+	VFMT_32_32_32_32_FLOAT = 3,
+	VFMT_16_FLOAT = 4,
+	VFMT_16_16_FLOAT = 5,
+	VFMT_16_16_16_FLOAT = 6,
+	VFMT_16_16_16_16_FLOAT = 7,
+	VFMT_32_FIXED = 8,
+	VFMT_32_32_FIXED = 9,
+	VFMT_32_32_32_FIXED = 10,
+	VFMT_32_32_32_32_FIXED = 11,
+	VFMT_16_SINT = 16,
+	VFMT_16_16_SINT = 17,
+	VFMT_16_16_16_SINT = 18,
+	VFMT_16_16_16_16_SINT = 19,
+	VFMT_16_UINT = 20,
+	VFMT_16_16_UINT = 21,
+	VFMT_16_16_16_UINT = 22,
+	VFMT_16_16_16_16_UINT = 23,
+	VFMT_16_SNORM = 24,
+	VFMT_16_16_SNORM = 25,
+	VFMT_16_16_16_SNORM = 26,
+	VFMT_16_16_16_16_SNORM = 27,
+	VFMT_16_UNORM = 28,
+	VFMT_16_16_UNORM = 29,
+	VFMT_16_16_16_UNORM = 30,
+	VFMT_16_16_16_16_UNORM = 31,
+	VFMT_32_UINT = 32,
+	VFMT_32_32_UINT = 33,
+	VFMT_32_32_32_UINT = 34,
+	VFMT_32_32_32_32_UINT = 35,
+	VFMT_32_SINT = 36,
+	VFMT_32_32_SINT = 37,
+	VFMT_32_32_32_SINT = 38,
+	VFMT_32_32_32_32_SINT = 39,
+	VFMT_8_UINT = 40,
+	VFMT_8_8_UINT = 41,
+	VFMT_8_8_8_UINT = 42,
+	VFMT_8_8_8_8_UINT = 43,
+	VFMT_8_UNORM = 44,
+	VFMT_8_8_UNORM = 45,
+	VFMT_8_8_8_UNORM = 46,
+	VFMT_8_8_8_8_UNORM = 47,
+	VFMT_8_SINT = 48,
+	VFMT_8_8_SINT = 49,
+	VFMT_8_8_8_SINT = 50,
+	VFMT_8_8_8_8_SINT = 51,
+	VFMT_8_SNORM = 52,
+	VFMT_8_8_SNORM = 53,
+	VFMT_8_8_8_SNORM = 54,
+	VFMT_8_8_8_8_SNORM = 55,
+	VFMT_10_10_10_2_UINT = 60,
+	VFMT_10_10_10_2_UNORM = 61,
+	VFMT_10_10_10_2_SINT = 62,
+	VFMT_10_10_10_2_SNORM = 63,
 };
 
 enum a3xx_tex_fmt {
-	TFMT_NORM_USHORT_565 = 4,
-	TFMT_NORM_USHORT_5551 = 6,
-	TFMT_NORM_USHORT_4444 = 7,
-	TFMT_NORM_USHORT_Z16 = 9,
-	TFMT_NORM_UINT_X8Z24 = 10,
-	TFMT_FLOAT_Z32 = 11,
-	TFMT_NORM_UINT_NV12_UV_TILED = 17,
-	TFMT_NORM_UINT_NV12_Y_TILED = 19,
-	TFMT_NORM_UINT_NV12_UV = 21,
-	TFMT_NORM_UINT_NV12_Y = 23,
-	TFMT_NORM_UINT_I420_Y = 24,
-	TFMT_NORM_UINT_I420_U = 26,
-	TFMT_NORM_UINT_I420_V = 27,
-	TFMT_NORM_UINT_2_10_10_10 = 41,
-	TFMT_FLOAT_9_9_9_E5 = 42,
-	TFMT_FLOAT_10_11_11 = 43,
-	TFMT_NORM_UINT_A8 = 44,
-	TFMT_NORM_UINT_L8_A8 = 47,
-	TFMT_NORM_UINT_8 = 48,
-	TFMT_NORM_UINT_8_8 = 49,
-	TFMT_NORM_UINT_8_8_8 = 50,
-	TFMT_NORM_UINT_8_8_8_8 = 51,
-	TFMT_NORM_SINT_8_8 = 53,
-	TFMT_NORM_SINT_8_8_8_8 = 55,
-	TFMT_UINT_8_8 = 57,
-	TFMT_UINT_8_8_8_8 = 59,
-	TFMT_SINT_8_8 = 61,
-	TFMT_SINT_8_8_8_8 = 63,
-	TFMT_FLOAT_16 = 64,
-	TFMT_FLOAT_16_16 = 65,
-	TFMT_FLOAT_16_16_16_16 = 67,
-	TFMT_UINT_16 = 68,
-	TFMT_UINT_16_16 = 69,
-	TFMT_UINT_16_16_16_16 = 71,
-	TFMT_SINT_16 = 72,
-	TFMT_SINT_16_16 = 73,
-	TFMT_SINT_16_16_16_16 = 75,
-	TFMT_FLOAT_32 = 84,
-	TFMT_FLOAT_32_32 = 85,
-	TFMT_FLOAT_32_32_32_32 = 87,
-	TFMT_UINT_32 = 88,
-	TFMT_UINT_32_32 = 89,
-	TFMT_UINT_32_32_32_32 = 91,
-	TFMT_SINT_32 = 92,
-	TFMT_SINT_32_32 = 93,
-	TFMT_SINT_32_32_32_32 = 95,
+	TFMT_5_6_5_UNORM = 4,
+	TFMT_5_5_5_1_UNORM = 5,
+	TFMT_4_4_4_4_UNORM = 7,
+	TFMT_Z16_UNORM = 9,
+	TFMT_X8Z24_UNORM = 10,
+	TFMT_Z32_FLOAT = 11,
+	TFMT_NV12_UV_TILED = 17,
+	TFMT_NV12_Y_TILED = 19,
+	TFMT_NV12_UV = 21,
+	TFMT_NV12_Y = 23,
+	TFMT_I420_Y = 24,
+	TFMT_I420_U = 26,
+	TFMT_I420_V = 27,
+	TFMT_DXT1 = 36,
+	TFMT_DXT3 = 37,
+	TFMT_DXT5 = 38,
+	TFMT_10_10_10_2_UNORM = 41,
+	TFMT_9_9_9_E5_FLOAT = 42,
+	TFMT_11_11_10_FLOAT = 43,
+	TFMT_A8_UNORM = 44,
+	TFMT_L8_A8_UNORM = 47,
+	TFMT_8_UNORM = 48,
+	TFMT_8_8_UNORM = 49,
+	TFMT_8_8_8_UNORM = 50,
+	TFMT_8_8_8_8_UNORM = 51,
+	TFMT_8_SNORM = 52,
+	TFMT_8_8_SNORM = 53,
+	TFMT_8_8_8_SNORM = 54,
+	TFMT_8_8_8_8_SNORM = 55,
+	TFMT_8_UINT = 56,
+	TFMT_8_8_UINT = 57,
+	TFMT_8_8_8_UINT = 58,
+	TFMT_8_8_8_8_UINT = 59,
+	TFMT_8_SINT = 60,
+	TFMT_8_8_SINT = 61,
+	TFMT_8_8_8_SINT = 62,
+	TFMT_8_8_8_8_SINT = 63,
+	TFMT_16_FLOAT = 64,
+	TFMT_16_16_FLOAT = 65,
+	TFMT_16_16_16_16_FLOAT = 67,
+	TFMT_16_UINT = 68,
+	TFMT_16_16_UINT = 69,
+	TFMT_16_16_16_16_UINT = 71,
+	TFMT_16_SINT = 72,
+	TFMT_16_16_SINT = 73,
+	TFMT_16_16_16_16_SINT = 75,
+	TFMT_16_UNORM = 76,
+	TFMT_16_16_UNORM = 77,
+	TFMT_16_16_16_16_UNORM = 79,
+	TFMT_16_SNORM = 80,
+	TFMT_16_16_SNORM = 81,
+	TFMT_16_16_16_16_SNORM = 83,
+	TFMT_32_FLOAT = 84,
+	TFMT_32_32_FLOAT = 85,
+	TFMT_32_32_32_32_FLOAT = 87,
+	TFMT_32_UINT = 88,
+	TFMT_32_32_UINT = 89,
+	TFMT_32_32_32_32_UINT = 91,
+	TFMT_32_SINT = 92,
+	TFMT_32_32_SINT = 93,
+	TFMT_32_32_32_32_SINT = 95,
+	TFMT_RGTC2_SNORM = 112,
+	TFMT_RGTC2_UNORM = 113,
+	TFMT_RGTC1_SNORM = 114,
+	TFMT_RGTC1_UNORM = 115,
 };
 
 enum a3xx_tex_fetchsize {
@@ -180,9 +199,11 @@
 	RB_R4G4B4A4_UNORM = 3,
 	RB_R8G8B8_UNORM = 4,
 	RB_R8G8B8A8_UNORM = 8,
+	RB_R8G8B8A8_SNORM = 9,
 	RB_R8G8B8A8_UINT = 10,
 	RB_R8G8B8A8_SINT = 11,
 	RB_R8G8_UNORM = 12,
+	RB_R8G8_SNORM = 13,
 	RB_R8_UINT = 14,
 	RB_R8_SINT = 15,
 	RB_R10G10B10A2_UNORM = 16,
@@ -258,6 +279,14 @@
 	A3XX_TEX_MIRROR_CLAMP = 4,
 };
 
+enum a3xx_tex_aniso {
+	A3XX_TEX_ANISO_1 = 0,
+	A3XX_TEX_ANISO_2 = 1,
+	A3XX_TEX_ANISO_4 = 2,
+	A3XX_TEX_ANISO_8 = 3,
+	A3XX_TEX_ANISO_16 = 4,
+};
+
 enum a3xx_tex_swiz {
 	A3XX_TEX_X = 0,
 	A3XX_TEX_Y = 1,
@@ -1563,12 +1592,13 @@
 {
 	return ((val) << A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK;
 }
-#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK			0x0001ff80
+#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK			0x0000ff80
 #define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT			7
 static inline uint32_t A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE(uint32_t val)
 {
 	return ((val) << A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK;
 }
+#define A3XX_VFD_FETCH_INSTR_0_INSTANCED			0x00010000
 #define A3XX_VFD_FETCH_INSTR_0_SWITCHNEXT			0x00020000
 #define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__MASK			0x00fc0000
 #define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__SHIFT			18
@@ -2509,6 +2539,12 @@
 {
 	return ((val) << A3XX_TEX_SAMP_0_WRAP_R__SHIFT) & A3XX_TEX_SAMP_0_WRAP_R__MASK;
 }
+#define A3XX_TEX_SAMP_0_ANISO__MASK				0x00038000
+#define A3XX_TEX_SAMP_0_ANISO__SHIFT				15
+static inline uint32_t A3XX_TEX_SAMP_0_ANISO(enum a3xx_tex_aniso val)
+{
+	return ((val) << A3XX_TEX_SAMP_0_ANISO__SHIFT) & A3XX_TEX_SAMP_0_ANISO__MASK;
+}
 #define A3XX_TEX_SAMP_0_COMPARE_FUNC__MASK			0x00700000
 #define A3XX_TEX_SAMP_0_COMPARE_FUNC__SHIFT			20
 static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val)
diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h
index 5a24c41..755723f 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a4xx.xml.h
@@ -12,9 +12,9 @@
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  51069 bytes, from 2014-12-21 15:51:54)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -63,72 +63,82 @@
 };
 
 enum a4xx_vtx_fmt {
-	VFMT4_FLOAT_32 = 1,
-	VFMT4_FLOAT_32_32 = 2,
-	VFMT4_FLOAT_32_32_32 = 3,
-	VFMT4_FLOAT_32_32_32_32 = 4,
-	VFMT4_FLOAT_16 = 5,
-	VFMT4_FLOAT_16_16 = 6,
-	VFMT4_FLOAT_16_16_16 = 7,
-	VFMT4_FLOAT_16_16_16_16 = 8,
-	VFMT4_FIXED_32 = 9,
-	VFMT4_FIXED_32_32 = 10,
-	VFMT4_FIXED_32_32_32 = 11,
-	VFMT4_FIXED_32_32_32_32 = 12,
-	VFMT4_SHORT_16 = 16,
-	VFMT4_SHORT_16_16 = 17,
-	VFMT4_SHORT_16_16_16 = 18,
-	VFMT4_SHORT_16_16_16_16 = 19,
-	VFMT4_USHORT_16 = 20,
-	VFMT4_USHORT_16_16 = 21,
-	VFMT4_USHORT_16_16_16 = 22,
-	VFMT4_USHORT_16_16_16_16 = 23,
-	VFMT4_NORM_SHORT_16 = 24,
-	VFMT4_NORM_SHORT_16_16 = 25,
-	VFMT4_NORM_SHORT_16_16_16 = 26,
-	VFMT4_NORM_SHORT_16_16_16_16 = 27,
-	VFMT4_NORM_USHORT_16 = 28,
-	VFMT4_NORM_USHORT_16_16 = 29,
-	VFMT4_NORM_USHORT_16_16_16 = 30,
-	VFMT4_NORM_USHORT_16_16_16_16 = 31,
-	VFMT4_UBYTE_8 = 40,
-	VFMT4_UBYTE_8_8 = 41,
-	VFMT4_UBYTE_8_8_8 = 42,
-	VFMT4_UBYTE_8_8_8_8 = 43,
-	VFMT4_NORM_UBYTE_8 = 44,
-	VFMT4_NORM_UBYTE_8_8 = 45,
-	VFMT4_NORM_UBYTE_8_8_8 = 46,
-	VFMT4_NORM_UBYTE_8_8_8_8 = 47,
-	VFMT4_BYTE_8 = 48,
-	VFMT4_BYTE_8_8 = 49,
-	VFMT4_BYTE_8_8_8 = 50,
-	VFMT4_BYTE_8_8_8_8 = 51,
-	VFMT4_NORM_BYTE_8 = 52,
-	VFMT4_NORM_BYTE_8_8 = 53,
-	VFMT4_NORM_BYTE_8_8_8 = 54,
-	VFMT4_NORM_BYTE_8_8_8_8 = 55,
-	VFMT4_UINT_10_10_10_2 = 60,
-	VFMT4_NORM_UINT_10_10_10_2 = 61,
-	VFMT4_INT_10_10_10_2 = 62,
-	VFMT4_NORM_INT_10_10_10_2 = 63,
+	VFMT4_32_FLOAT = 1,
+	VFMT4_32_32_FLOAT = 2,
+	VFMT4_32_32_32_FLOAT = 3,
+	VFMT4_32_32_32_32_FLOAT = 4,
+	VFMT4_16_FLOAT = 5,
+	VFMT4_16_16_FLOAT = 6,
+	VFMT4_16_16_16_FLOAT = 7,
+	VFMT4_16_16_16_16_FLOAT = 8,
+	VFMT4_32_FIXED = 9,
+	VFMT4_32_32_FIXED = 10,
+	VFMT4_32_32_32_FIXED = 11,
+	VFMT4_32_32_32_32_FIXED = 12,
+	VFMT4_16_SINT = 16,
+	VFMT4_16_16_SINT = 17,
+	VFMT4_16_16_16_SINT = 18,
+	VFMT4_16_16_16_16_SINT = 19,
+	VFMT4_16_UINT = 20,
+	VFMT4_16_16_UINT = 21,
+	VFMT4_16_16_16_UINT = 22,
+	VFMT4_16_16_16_16_UINT = 23,
+	VFMT4_16_SNORM = 24,
+	VFMT4_16_16_SNORM = 25,
+	VFMT4_16_16_16_SNORM = 26,
+	VFMT4_16_16_16_16_SNORM = 27,
+	VFMT4_16_UNORM = 28,
+	VFMT4_16_16_UNORM = 29,
+	VFMT4_16_16_16_UNORM = 30,
+	VFMT4_16_16_16_16_UNORM = 31,
+	VFMT4_32_32_SINT = 37,
+	VFMT4_8_UINT = 40,
+	VFMT4_8_8_UINT = 41,
+	VFMT4_8_8_8_UINT = 42,
+	VFMT4_8_8_8_8_UINT = 43,
+	VFMT4_8_UNORM = 44,
+	VFMT4_8_8_UNORM = 45,
+	VFMT4_8_8_8_UNORM = 46,
+	VFMT4_8_8_8_8_UNORM = 47,
+	VFMT4_8_SINT = 48,
+	VFMT4_8_8_SINT = 49,
+	VFMT4_8_8_8_SINT = 50,
+	VFMT4_8_8_8_8_SINT = 51,
+	VFMT4_8_SNORM = 52,
+	VFMT4_8_8_SNORM = 53,
+	VFMT4_8_8_8_SNORM = 54,
+	VFMT4_8_8_8_8_SNORM = 55,
+	VFMT4_10_10_10_2_UINT = 60,
+	VFMT4_10_10_10_2_UNORM = 61,
+	VFMT4_10_10_10_2_SINT = 62,
+	VFMT4_10_10_10_2_SNORM = 63,
 };
 
 enum a4xx_tex_fmt {
-	TFMT4_NORM_USHORT_565 = 11,
-	TFMT4_NORM_USHORT_5551 = 10,
-	TFMT4_NORM_USHORT_4444 = 8,
-	TFMT4_NORM_UINT_X8Z24 = 71,
-	TFMT4_NORM_UINT_2_10_10_10 = 33,
-	TFMT4_NORM_UINT_A8 = 3,
-	TFMT4_NORM_UINT_L8_A8 = 13,
-	TFMT4_NORM_UINT_8 = 4,
-	TFMT4_NORM_UINT_8_8_8_8 = 28,
-	TFMT4_FLOAT_16 = 20,
-	TFMT4_FLOAT_16_16 = 40,
-	TFMT4_FLOAT_16_16_16_16 = 53,
-	TFMT4_FLOAT_32 = 43,
-	TFMT4_FLOAT_32_32 = 56,
-	TFMT4_FLOAT_32_32_32_32 = 63,
+	TFMT4_5_6_5_UNORM = 11,
+	TFMT4_5_5_5_1_UNORM = 10,
+	TFMT4_4_4_4_4_UNORM = 8,
+	TFMT4_X8Z24_UNORM = 71,
+	TFMT4_10_10_10_2_UNORM = 33,
+	TFMT4_A8_UNORM = 3,
+	TFMT4_L8_A8_UNORM = 13,
+	TFMT4_8_UNORM = 4,
+	TFMT4_8_8_UNORM = 14,
+	TFMT4_8_8_8_8_UNORM = 28,
+	TFMT4_16_FLOAT = 20,
+	TFMT4_16_16_FLOAT = 40,
+	TFMT4_16_16_16_16_FLOAT = 53,
+	TFMT4_32_FLOAT = 43,
+	TFMT4_32_32_FLOAT = 56,
+	TFMT4_32_32_32_32_FLOAT = 63,
+};
+
+enum a4xx_tex_fetchsize {
+	TFETCH4_1_BYTE = 0,
+	TFETCH4_2_BYTE = 1,
+	TFETCH4_4_BYTE = 2,
+	TFETCH4_8_BYTE = 3,
+	TFETCH4_16_BYTE = 4,
 };
 
 enum a4xx_depth_format {
@@ -264,14 +274,19 @@
 	return ((val) << A4XX_RB_MSAA_CONTROL_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL_SAMPLES__MASK;
 }
 
-#define REG_A4XX_RB_MSAA_CONTROL2				0x000020a3
-#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK		0x00000380
-#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT		7
-static inline uint32_t A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES(uint32_t val)
+#define REG_A4XX_RB_RENDER_CONTROL2				0x000020a3
+#define A4XX_RB_RENDER_CONTROL2_XCOORD				0x00000001
+#define A4XX_RB_RENDER_CONTROL2_YCOORD				0x00000002
+#define A4XX_RB_RENDER_CONTROL2_ZCOORD				0x00000004
+#define A4XX_RB_RENDER_CONTROL2_WCOORD				0x00000008
+#define A4XX_RB_RENDER_CONTROL2_FACENESS			0x00000020
+#define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK		0x00000380
+#define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT		7
+static inline uint32_t A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES(uint32_t val)
 {
-	return ((val) << A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK;
+	return ((val) << A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK;
 }
-#define A4XX_RB_MSAA_CONTROL2_VARYING				0x00001000
+#define A4XX_RB_RENDER_CONTROL2_VARYING				0x00001000
 
 static inline uint32_t REG_A4XX_RB_MRT(uint32_t i0) { return 0x000020a4 + 0x5*i0; }
 
@@ -362,7 +377,69 @@
 	return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK;
 }
 
+#define REG_A4XX_RB_BLEND_RED					0x000020f3
+#define A4XX_RB_BLEND_RED_UINT__MASK				0x00007fff
+#define A4XX_RB_BLEND_RED_UINT__SHIFT				0
+static inline uint32_t A4XX_RB_BLEND_RED_UINT(uint32_t val)
+{
+	return ((val) << A4XX_RB_BLEND_RED_UINT__SHIFT) & A4XX_RB_BLEND_RED_UINT__MASK;
+}
+#define A4XX_RB_BLEND_RED_FLOAT__MASK				0xffff0000
+#define A4XX_RB_BLEND_RED_FLOAT__SHIFT				16
+static inline uint32_t A4XX_RB_BLEND_RED_FLOAT(float val)
+{
+	return ((util_float_to_half(val)) << A4XX_RB_BLEND_RED_FLOAT__SHIFT) & A4XX_RB_BLEND_RED_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_GREEN					0x000020f4
+#define A4XX_RB_BLEND_GREEN_UINT__MASK				0x00007fff
+#define A4XX_RB_BLEND_GREEN_UINT__SHIFT				0
+static inline uint32_t A4XX_RB_BLEND_GREEN_UINT(uint32_t val)
+{
+	return ((val) << A4XX_RB_BLEND_GREEN_UINT__SHIFT) & A4XX_RB_BLEND_GREEN_UINT__MASK;
+}
+#define A4XX_RB_BLEND_GREEN_FLOAT__MASK				0xffff0000
+#define A4XX_RB_BLEND_GREEN_FLOAT__SHIFT			16
+static inline uint32_t A4XX_RB_BLEND_GREEN_FLOAT(float val)
+{
+	return ((util_float_to_half(val)) << A4XX_RB_BLEND_GREEN_FLOAT__SHIFT) & A4XX_RB_BLEND_GREEN_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_BLUE					0x000020f5
+#define A4XX_RB_BLEND_BLUE_UINT__MASK				0x00007fff
+#define A4XX_RB_BLEND_BLUE_UINT__SHIFT				0
+static inline uint32_t A4XX_RB_BLEND_BLUE_UINT(uint32_t val)
+{
+	return ((val) << A4XX_RB_BLEND_BLUE_UINT__SHIFT) & A4XX_RB_BLEND_BLUE_UINT__MASK;
+}
+#define A4XX_RB_BLEND_BLUE_FLOAT__MASK				0xffff0000
+#define A4XX_RB_BLEND_BLUE_FLOAT__SHIFT				16
+static inline uint32_t A4XX_RB_BLEND_BLUE_FLOAT(float val)
+{
+	return ((util_float_to_half(val)) << A4XX_RB_BLEND_BLUE_FLOAT__SHIFT) & A4XX_RB_BLEND_BLUE_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_ALPHA					0x000020f6
+#define A4XX_RB_BLEND_ALPHA_UINT__MASK				0x00007fff
+#define A4XX_RB_BLEND_ALPHA_UINT__SHIFT				0
+static inline uint32_t A4XX_RB_BLEND_ALPHA_UINT(uint32_t val)
+{
+	return ((val) << A4XX_RB_BLEND_ALPHA_UINT__SHIFT) & A4XX_RB_BLEND_ALPHA_UINT__MASK;
+}
+#define A4XX_RB_BLEND_ALPHA_FLOAT__MASK				0xffff0000
+#define A4XX_RB_BLEND_ALPHA_FLOAT__SHIFT			16
+static inline uint32_t A4XX_RB_BLEND_ALPHA_FLOAT(float val)
+{
+	return ((util_float_to_half(val)) << A4XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A4XX_RB_BLEND_ALPHA_FLOAT__MASK;
+}
+
 #define REG_A4XX_RB_ALPHA_CONTROL				0x000020f8
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK			0x000000ff
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT			0
+static inline uint32_t A4XX_RB_ALPHA_CONTROL_ALPHA_REF(uint32_t val)
+{
+	return ((val) << A4XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT) & A4XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK;
+}
 #define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST			0x00000100
 #define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK		0x00000e00
 #define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT		9
@@ -372,7 +449,7 @@
 }
 
 #define REG_A4XX_RB_FS_OUTPUT					0x000020f9
-#define A4XX_RB_FS_OUTPUT_ENABLE_COLOR_PIPE			0x00000001
+#define A4XX_RB_FS_OUTPUT_ENABLE_BLEND				0x00000001
 #define A4XX_RB_FS_OUTPUT_FAST_CLEAR				0x00000100
 #define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK			0xffff0000
 #define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT			16
@@ -416,11 +493,11 @@
 }
 
 #define REG_A4XX_RB_COPY_DEST_BASE				0x000020fd
-#define A4XX_RB_COPY_DEST_BASE_BASE__MASK			0xfffffff0
-#define A4XX_RB_COPY_DEST_BASE_BASE__SHIFT			4
+#define A4XX_RB_COPY_DEST_BASE_BASE__MASK			0xffffffe0
+#define A4XX_RB_COPY_DEST_BASE_BASE__SHIFT			5
 static inline uint32_t A4XX_RB_COPY_DEST_BASE_BASE(uint32_t val)
 {
-	return ((val >> 4) << A4XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A4XX_RB_COPY_DEST_BASE_BASE__MASK;
+	return ((val >> 5) << A4XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A4XX_RB_COPY_DEST_BASE_BASE__MASK;
 }
 
 #define REG_A4XX_RB_COPY_DEST_PITCH				0x000020fe
@@ -508,7 +585,7 @@
 #define A4XX_RB_DEPTH_PITCH__SHIFT				0
 static inline uint32_t A4XX_RB_DEPTH_PITCH(uint32_t val)
 {
-	return ((val >> 4) << A4XX_RB_DEPTH_PITCH__SHIFT) & A4XX_RB_DEPTH_PITCH__MASK;
+	return ((val >> 5) << A4XX_RB_DEPTH_PITCH__SHIFT) & A4XX_RB_DEPTH_PITCH__MASK;
 }
 
 #define REG_A4XX_RB_DEPTH_PITCH2				0x00002105
@@ -516,7 +593,7 @@
 #define A4XX_RB_DEPTH_PITCH2__SHIFT				0
 static inline uint32_t A4XX_RB_DEPTH_PITCH2(uint32_t val)
 {
-	return ((val >> 4) << A4XX_RB_DEPTH_PITCH2__SHIFT) & A4XX_RB_DEPTH_PITCH2__MASK;
+	return ((val >> 5) << A4XX_RB_DEPTH_PITCH2__SHIFT) & A4XX_RB_DEPTH_PITCH2__MASK;
 }
 
 #define REG_A4XX_RB_STENCIL_CONTROL				0x00002106
@@ -630,7 +707,11 @@
 	return ((val) << A4XX_RB_BIN_OFFSET_Y__SHIFT) & A4XX_RB_BIN_OFFSET_Y__MASK;
 }
 
-#define REG_A4XX_RB_VPORT_Z_CLAMP_MAX_15			0x0000213f
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP(uint32_t i0) { return 0x00002120 + 0x2*i0; }
+
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP_MIN(uint32_t i0) { return 0x00002120 + 0x2*i0; }
+
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP_MAX(uint32_t i0) { return 0x00002121 + 0x2*i0; }
 
 #define REG_A4XX_RBBM_HW_VERSION				0x00000000
 
@@ -1121,7 +1202,9 @@
 {
 	return ((val) << A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT) & A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK;
 }
+#define A4XX_SP_FS_CTRL_REG1_FACENESS				0x00080000
 #define A4XX_SP_FS_CTRL_REG1_VARYING				0x00100000
+#define A4XX_SP_FS_CTRL_REG1_FRAGCOORD				0x00200000
 
 #define REG_A4XX_SP_FS_OBJ_OFFSET_REG				0x000022ea
 #define A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK	0x01ff0000
@@ -1384,6 +1467,12 @@
 #define REG_A4XX_VFD_CONTROL_2					0x00002202
 
 #define REG_A4XX_VFD_CONTROL_3					0x00002203
+#define A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK			0x0000ff00
+#define A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT			8
+static inline uint32_t A4XX_VFD_CONTROL_3_REGID_VTXCNT(uint32_t val)
+{
+	return ((val) << A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT) & A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK;
+}
 
 #define REG_A4XX_VFD_CONTROL_4					0x00002204
 
@@ -1405,12 +1494,7 @@
 	return ((val) << A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK;
 }
 #define A4XX_VFD_FETCH_INSTR_0_SWITCHNEXT			0x00080000
-#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK			0xff000000
-#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT			24
-static inline uint32_t A4XX_VFD_FETCH_INSTR_0_STEPRATE(uint32_t val)
-{
-	return ((val) << A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK;
-}
+#define A4XX_VFD_FETCH_INSTR_0_INSTANCED			0x00100000
 
 static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_1(uint32_t i0) { return 0x0000220b + 0x4*i0; }
 
@@ -1423,6 +1507,12 @@
 }
 
 static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_3(uint32_t i0) { return 0x0000220d + 0x4*i0; }
+#define A4XX_VFD_FETCH_INSTR_3_STEPRATE__MASK			0x000001ff
+#define A4XX_VFD_FETCH_INSTR_3_STEPRATE__SHIFT			0
+static inline uint32_t A4XX_VFD_FETCH_INSTR_3_STEPRATE(uint32_t val)
+{
+	return ((val) << A4XX_VFD_FETCH_INSTR_3_STEPRATE__SHIFT) & A4XX_VFD_FETCH_INSTR_3_STEPRATE__MASK;
+}
 
 static inline uint32_t REG_A4XX_VFD_DECODE(uint32_t i0) { return 0x0000228a + 0x1*i0; }
 
@@ -1446,6 +1536,7 @@
 {
 	return ((val) << A4XX_VFD_DECODE_INSTR_REGID__SHIFT) & A4XX_VFD_DECODE_INSTR_REGID__MASK;
 }
+#define A4XX_VFD_DECODE_INSTR_INT				0x00100000
 #define A4XX_VFD_DECODE_INSTR_SWAP__MASK			0x00c00000
 #define A4XX_VFD_DECODE_INSTR_SWAP__SHIFT			22
 static inline uint32_t A4XX_VFD_DECODE_INSTR_SWAP(enum a3xx_color_swap val)
@@ -1585,7 +1676,47 @@
 	return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
 }
 
-#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_TL			0x0000209f
+#define REG_A4XX_GRAS_DEPTH_CONTROL				0x00002077
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK			0x00000003
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT			0
+static inline uint32_t A4XX_GRAS_DEPTH_CONTROL_FORMAT(enum a4xx_depth_format val)
+{
+	return ((val) << A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT) & A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_MODE_CONTROL				0x00002078
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_FRONT			0x00000001
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_BACK			0x00000002
+#define A4XX_GRAS_SU_MODE_CONTROL_FRONT_CW			0x00000004
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK		0x000007f8
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT		3
+static inline uint32_t A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
+{
+	return ((((int32_t)(val * 4.0))) << A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+}
+#define A4XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET			0x00000800
+#define A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS		0x00100000
+
+#define REG_A4XX_GRAS_SC_CONTROL				0x0000207b
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK			0x0000000c
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT			2
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val)
+{
+	return ((val) << A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK			0x00000380
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT		7
+static inline uint32_t A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(uint32_t val)
+{
+	return ((val) << A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_DISABLE			0x00000800
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK			0x0000f000
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT			12
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val)
+{
+	return ((val) << A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK;
+}
 
 #define REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL			0x0000207c
 #define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_WINDOW_OFFSET_DISABLE	0x80000000
@@ -1647,46 +1778,34 @@
 	return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK;
 }
 
-#define REG_A4XX_GRAS_DEPTH_CONTROL				0x00002077
-#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK			0x00000003
-#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT			0
-static inline uint32_t A4XX_GRAS_DEPTH_CONTROL_FORMAT(enum a4xx_depth_format val)
+#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_BR			0x0000209e
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_WINDOW_OFFSET_DISABLE	0x80000000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__MASK			0x00007fff
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__SHIFT			0
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_BR_X(uint32_t val)
 {
-	return ((val) << A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT) & A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK;
+	return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__MASK;
+}
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__MASK			0x7fff0000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__SHIFT			16
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y(uint32_t val)
+{
+	return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__MASK;
 }
 
-#define REG_A4XX_GRAS_SU_MODE_CONTROL				0x00002078
-#define A4XX_GRAS_SU_MODE_CONTROL_CULL_FRONT			0x00000001
-#define A4XX_GRAS_SU_MODE_CONTROL_CULL_BACK			0x00000002
-#define A4XX_GRAS_SU_MODE_CONTROL_FRONT_CW			0x00000004
-#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK		0x000007f8
-#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT		3
-static inline uint32_t A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
+#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_TL			0x0000209f
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_WINDOW_OFFSET_DISABLE	0x80000000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__MASK			0x00007fff
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__SHIFT			0
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_TL_X(uint32_t val)
 {
-	return ((((int32_t)(val * 4.0))) << A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+	return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__MASK;
 }
-#define A4XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET			0x00000800
-#define A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS		0x00100000
-
-#define REG_A4XX_GRAS_SC_CONTROL				0x0000207b
-#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK			0x0000000c
-#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT			2
-static inline uint32_t A4XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val)
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__MASK			0x7fff0000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__SHIFT			16
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y(uint32_t val)
 {
-	return ((val) << A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK;
-}
-#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK			0x00000380
-#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT		7
-static inline uint32_t A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(uint32_t val)
-{
-	return ((val) << A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK;
-}
-#define A4XX_GRAS_SC_CONTROL_MSAA_DISABLE			0x00000800
-#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK			0x0000f000
-#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT			12
-static inline uint32_t A4XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val)
-{
-	return ((val) << A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK;
+	return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__MASK;
 }
 
 #define REG_A4XX_UCHE_CACHE_MODE_CONTROL			0x00000e80
@@ -1742,6 +1861,12 @@
 }
 #define A4XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE		0x00000100
 #define A4XX_HLSQ_CONTROL_1_REG_RESERVED1			0x00000200
+#define A4XX_HLSQ_CONTROL_1_REG_COORDREGID__MASK		0x00ff0000
+#define A4XX_HLSQ_CONTROL_1_REG_COORDREGID__SHIFT		16
+static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_COORDREGID(uint32_t val)
+{
+	return ((val) << A4XX_HLSQ_CONTROL_1_REG_COORDREGID__SHIFT) & A4XX_HLSQ_CONTROL_1_REG_COORDREGID__MASK;
+}
 #define A4XX_HLSQ_CONTROL_1_REG_ZWCOORD				0x02000000
 
 #define REG_A4XX_HLSQ_CONTROL_2_REG				0x000023c2
@@ -1751,6 +1876,12 @@
 {
 	return ((val) << A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK;
 }
+#define A4XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK			0x000003fc
+#define A4XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT		2
+static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_FACEREGID(uint32_t val)
+{
+	return ((val) << A4XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK;
+}
 
 #define REG_A4XX_HLSQ_CONTROL_3_REG				0x000023c3
 #define A4XX_HLSQ_CONTROL_3_REG_REGID__MASK			0x000000ff
@@ -1965,15 +2096,13 @@
 
 #define REG_A4XX_UNKNOWN_20F2					0x000020f2
 
-#define REG_A4XX_UNKNOWN_20F3					0x000020f3
-
-#define REG_A4XX_UNKNOWN_20F4					0x000020f4
-
-#define REG_A4XX_UNKNOWN_20F5					0x000020f5
-
-#define REG_A4XX_UNKNOWN_20F6					0x000020f6
-
 #define REG_A4XX_UNKNOWN_20F7					0x000020f7
+#define A4XX_UNKNOWN_20F7__MASK					0xffffffff
+#define A4XX_UNKNOWN_20F7__SHIFT				0
+static inline uint32_t A4XX_UNKNOWN_20F7(float val)
+{
+	return ((fui(val)) << A4XX_UNKNOWN_20F7__SHIFT) & A4XX_UNKNOWN_20F7__MASK;
+}
 
 #define REG_A4XX_UNKNOWN_2152					0x00002152
 
@@ -2000,6 +2129,7 @@
 #define REG_A4XX_UNKNOWN_23A0					0x000023a0
 
 #define REG_A4XX_TEX_SAMP_0					0x00000000
+#define A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR			0x00000001
 #define A4XX_TEX_SAMP_0_XY_MAG__MASK				0x00000006
 #define A4XX_TEX_SAMP_0_XY_MAG__SHIFT				1
 static inline uint32_t A4XX_TEX_SAMP_0_XY_MAG(enum a4xx_tex_filter val)
@@ -2038,17 +2168,19 @@
 {
 	return ((val) << A4XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT) & A4XX_TEX_SAMP_1_COMPARE_FUNC__MASK;
 }
+#define A4XX_TEX_SAMP_1_UNNORM_COORDS				0x00000020
+#define A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR			0x00000040
 #define A4XX_TEX_SAMP_1_MAX_LOD__MASK				0x000fff00
 #define A4XX_TEX_SAMP_1_MAX_LOD__SHIFT				8
 static inline uint32_t A4XX_TEX_SAMP_1_MAX_LOD(float val)
 {
-	return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A4XX_TEX_SAMP_1_MAX_LOD__MASK;
+	return ((((uint32_t)(val * 256.0))) << A4XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A4XX_TEX_SAMP_1_MAX_LOD__MASK;
 }
 #define A4XX_TEX_SAMP_1_MIN_LOD__MASK				0xfff00000
 #define A4XX_TEX_SAMP_1_MIN_LOD__SHIFT				20
 static inline uint32_t A4XX_TEX_SAMP_1_MIN_LOD(float val)
 {
-	return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A4XX_TEX_SAMP_1_MIN_LOD__MASK;
+	return ((((uint32_t)(val * 256.0))) << A4XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A4XX_TEX_SAMP_1_MIN_LOD__MASK;
 }
 
 #define REG_A4XX_TEX_CONST_0					0x00000000
@@ -2077,6 +2209,12 @@
 {
 	return ((val) << A4XX_TEX_CONST_0_SWIZ_W__SHIFT) & A4XX_TEX_CONST_0_SWIZ_W__MASK;
 }
+#define A4XX_TEX_CONST_0_MIPLVLS__MASK				0x000f0000
+#define A4XX_TEX_CONST_0_MIPLVLS__SHIFT				16
+static inline uint32_t A4XX_TEX_CONST_0_MIPLVLS(uint32_t val)
+{
+	return ((val) << A4XX_TEX_CONST_0_MIPLVLS__SHIFT) & A4XX_TEX_CONST_0_MIPLVLS__MASK;
+}
 #define A4XX_TEX_CONST_0_FMT__MASK				0x1fc00000
 #define A4XX_TEX_CONST_0_FMT__SHIFT				22
 static inline uint32_t A4XX_TEX_CONST_0_FMT(enum a4xx_tex_fmt val)
@@ -2105,6 +2243,12 @@
 }
 
 #define REG_A4XX_TEX_CONST_2					0x00000002
+#define A4XX_TEX_CONST_2_FETCHSIZE__MASK			0x0000000f
+#define A4XX_TEX_CONST_2_FETCHSIZE__SHIFT			0
+static inline uint32_t A4XX_TEX_CONST_2_FETCHSIZE(enum a4xx_tex_fetchsize val)
+{
+	return ((val) << A4XX_TEX_CONST_2_FETCHSIZE__SHIFT) & A4XX_TEX_CONST_2_FETCHSIZE__MASK;
+}
 #define A4XX_TEX_CONST_2_PITCH__MASK				0x3ffffe00
 #define A4XX_TEX_CONST_2_PITCH__SHIFT				9
 static inline uint32_t A4XX_TEX_CONST_2_PITCH(uint32_t val)
@@ -2119,19 +2263,31 @@
 }
 
 #define REG_A4XX_TEX_CONST_3					0x00000003
-#define A4XX_TEX_CONST_3_LAYERSZ__MASK				0x0000000f
+#define A4XX_TEX_CONST_3_LAYERSZ__MASK				0x00003fff
 #define A4XX_TEX_CONST_3_LAYERSZ__SHIFT				0
 static inline uint32_t A4XX_TEX_CONST_3_LAYERSZ(uint32_t val)
 {
 	return ((val >> 12) << A4XX_TEX_CONST_3_LAYERSZ__SHIFT) & A4XX_TEX_CONST_3_LAYERSZ__MASK;
 }
+#define A4XX_TEX_CONST_3_DEPTH__MASK				0x7ffc0000
+#define A4XX_TEX_CONST_3_DEPTH__SHIFT				18
+static inline uint32_t A4XX_TEX_CONST_3_DEPTH(uint32_t val)
+{
+	return ((val) << A4XX_TEX_CONST_3_DEPTH__SHIFT) & A4XX_TEX_CONST_3_DEPTH__MASK;
+}
 
 #define REG_A4XX_TEX_CONST_4					0x00000004
-#define A4XX_TEX_CONST_4_BASE__MASK				0xffffffff
-#define A4XX_TEX_CONST_4_BASE__SHIFT				0
+#define A4XX_TEX_CONST_4_LAYERSZ__MASK				0x0000000f
+#define A4XX_TEX_CONST_4_LAYERSZ__SHIFT				0
+static inline uint32_t A4XX_TEX_CONST_4_LAYERSZ(uint32_t val)
+{
+	return ((val >> 12) << A4XX_TEX_CONST_4_LAYERSZ__SHIFT) & A4XX_TEX_CONST_4_LAYERSZ__MASK;
+}
+#define A4XX_TEX_CONST_4_BASE__MASK				0xffffffe0
+#define A4XX_TEX_CONST_4_BASE__SHIFT				5
 static inline uint32_t A4XX_TEX_CONST_4_BASE(uint32_t val)
 {
-	return ((val) << A4XX_TEX_CONST_4_BASE__SHIFT) & A4XX_TEX_CONST_4_BASE__MASK;
+	return ((val >> 5) << A4XX_TEX_CONST_4_BASE__SHIFT) & A4XX_TEX_CONST_4_BASE__MASK;
 }
 
 #define REG_A4XX_TEX_CONST_5					0x00000005
diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
index a4b33af..8531beb 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
@@ -12,9 +12,9 @@
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  51069 bytes, from 2014-12-21 15:51:54)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
index 6a75cee..6ffc4f6 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
@@ -12,9 +12,9 @@
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml  (   1453 bytes, from 2013-03-31 16:51:27)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml          (  32901 bytes, from 2014-06-02 15:21:30)
 - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (  10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (  51069 bytes, from 2014-12-21 15:51:54)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -172,7 +172,9 @@
 	CP_DRAW_INDIRECT = 40,
 	CP_DRAW_INDX_INDIRECT = 41,
 	CP_DRAW_AUTO = 36,
+	CP_UNKNOWN_19 = 25,
 	CP_UNKNOWN_1A = 26,
+	CP_UNKNOWN_4E = 78,
 	CP_WIDE_REG_WRITE = 116,
 	IN_IB_PREFETCH_END = 23,
 	IN_SUBBLK_PREFETCH = 31,
@@ -203,6 +205,12 @@
 	SS_INDIRECT = 4,
 };
 
+enum a4xx_index_size {
+	INDEX4_SIZE_8_BIT = 0,
+	INDEX4_SIZE_16_BIT = 1,
+	INDEX4_SIZE_32_BIT = 2,
+};
+
 #define REG_CP_LOAD_STATE_0					0x00000000
 #define CP_LOAD_STATE_0_DST_OFF__MASK				0x0000ffff
 #define CP_LOAD_STATE_0_DST_OFF__SHIFT				0
@@ -374,29 +382,20 @@
 {
 	return ((val) << CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK;
 }
-#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK			0x00000700
-#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT			8
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_VIS_CULL(enum pc_di_vis_cull_mode val)
-{
-	return ((val) << CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT) & CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK;
-}
-#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK			0x00000800
-#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT			11
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum pc_di_index_size val)
+#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK			0x00000c00
+#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT			10
+static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum a4xx_index_size val)
 {
 	return ((val) << CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK;
 }
-#define CP_DRAW_INDX_OFFSET_0_NOT_EOP				0x00001000
-#define CP_DRAW_INDX_OFFSET_0_SMALL_INDEX			0x00002000
-#define CP_DRAW_INDX_OFFSET_0_PRE_DRAW_INITIATOR_ENABLE		0x00004000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK		0xffff0000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT		16
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES(uint32_t val)
-{
-	return ((val) << CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK;
-}
 
 #define REG_CP_DRAW_INDX_OFFSET_1				0x00000001
+#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK		0xffffffff
+#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT		0
+static inline uint32_t CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES(uint32_t val)
+{
+	return ((val) << CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK;
+}
 
 #define REG_CP_DRAW_INDX_OFFSET_2				0x00000002
 #define CP_DRAW_INDX_OFFSET_2_NUM_INDICES__MASK			0xffffffff
diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h
index 448438b7..abf1bba 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.xml.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h
@@ -8,16 +8,17 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
index c102a7f..695f99d 100644
--- a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
+++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
@@ -8,16 +8,17 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h
index a900134..50ff985 100644
--- a/drivers/gpu/drm/msm/dsi/sfpb.xml.h
+++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h
@@ -8,16 +8,17 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
new file mode 100644
index 0000000..0940e84
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.c
@@ -0,0 +1,208 @@
+/*
+ * 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 <linux/of_irq.h>
+#include "edp.h"
+
+static irqreturn_t edp_irq(int irq, void *dev_id)
+{
+	struct msm_edp *edp = dev_id;
+
+	/* Process eDP irq */
+	return msm_edp_ctrl_irq(edp->ctrl);
+}
+
+static void edp_destroy(struct platform_device *pdev)
+{
+	struct msm_edp *edp = platform_get_drvdata(pdev);
+
+	if (!edp)
+		return;
+
+	if (edp->ctrl) {
+		msm_edp_ctrl_destroy(edp->ctrl);
+		edp->ctrl = NULL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+}
+
+/* construct eDP at bind/probe time, grab all the resources. */
+static struct msm_edp *edp_init(struct platform_device *pdev)
+{
+	struct msm_edp *edp = NULL;
+	int ret;
+
+	if (!pdev) {
+		pr_err("no eDP device\n");
+		ret = -ENXIO;
+		goto fail;
+	}
+
+	edp = devm_kzalloc(&pdev->dev, sizeof(*edp), GFP_KERNEL);
+	if (!edp) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+	DBG("eDP probed=%p", edp);
+
+	edp->pdev = pdev;
+	platform_set_drvdata(pdev, edp);
+
+	ret = msm_edp_ctrl_init(edp);
+	if (ret)
+		goto fail;
+
+	return edp;
+
+fail:
+	if (edp)
+		edp_destroy(pdev);
+
+	return ERR_PTR(ret);
+}
+
+static int edp_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct msm_drm_private *priv = drm->dev_private;
+	struct msm_edp *edp;
+
+	DBG("");
+	edp = edp_init(to_platform_device(dev));
+	if (IS_ERR(edp))
+		return PTR_ERR(edp);
+	priv->edp = edp;
+
+	return 0;
+}
+
+static void edp_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm = dev_get_drvdata(master);
+	struct msm_drm_private *priv = drm->dev_private;
+
+	DBG("");
+	if (priv->edp) {
+		edp_destroy(to_platform_device(dev));
+		priv->edp = NULL;
+	}
+}
+
+static const struct component_ops edp_ops = {
+		.bind   = edp_bind,
+		.unbind = edp_unbind,
+};
+
+static int edp_dev_probe(struct platform_device *pdev)
+{
+	DBG("");
+	return component_add(&pdev->dev, &edp_ops);
+}
+
+static int edp_dev_remove(struct platform_device *pdev)
+{
+	DBG("");
+	component_del(&pdev->dev, &edp_ops);
+	return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+	{ .compatible = "qcom,mdss-edp" },
+	{}
+};
+
+static struct platform_driver edp_driver = {
+	.probe = edp_dev_probe,
+	.remove = edp_dev_remove,
+	.driver = {
+		.name = "msm_edp",
+		.of_match_table = dt_match,
+	},
+};
+
+void __init msm_edp_register(void)
+{
+	DBG("");
+	platform_driver_register(&edp_driver);
+}
+
+void __exit msm_edp_unregister(void)
+{
+	DBG("");
+	platform_driver_unregister(&edp_driver);
+}
+
+/* Second part of initialization, the drm/kms level modeset_init */
+int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
+				struct drm_encoder *encoder)
+{
+	struct platform_device *pdev = edp->pdev;
+	struct msm_drm_private *priv = dev->dev_private;
+	int ret;
+
+	edp->encoder = encoder;
+	edp->dev = dev;
+
+	edp->bridge = msm_edp_bridge_init(edp);
+	if (IS_ERR(edp->bridge)) {
+		ret = PTR_ERR(edp->bridge);
+		dev_err(dev->dev, "failed to create eDP bridge: %d\n", ret);
+		edp->bridge = NULL;
+		goto fail;
+	}
+
+	edp->connector = msm_edp_connector_init(edp);
+	if (IS_ERR(edp->connector)) {
+		ret = PTR_ERR(edp->connector);
+		dev_err(dev->dev, "failed to create eDP connector: %d\n", ret);
+		edp->connector = NULL;
+		goto fail;
+	}
+
+	edp->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (edp->irq < 0) {
+		ret = edp->irq;
+		dev_err(dev->dev, "failed to get IRQ: %d\n", ret);
+		goto fail;
+	}
+
+	ret = devm_request_irq(&pdev->dev, edp->irq,
+			edp_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+			"edp_isr", edp);
+	if (ret < 0) {
+		dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+				edp->irq, ret);
+		goto fail;
+	}
+
+	encoder->bridge = edp->bridge;
+
+	priv->bridges[priv->num_bridges++]       = edp->bridge;
+	priv->connectors[priv->num_connectors++] = edp->connector;
+
+	return 0;
+
+fail:
+	/* bridge/connector are normally destroyed by drm */
+	if (edp->bridge) {
+		edp_bridge_destroy(edp->bridge);
+		edp->bridge = NULL;
+	}
+	if (edp->connector) {
+		edp->connector->funcs->destroy(edp->connector);
+		edp->connector = NULL;
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h
new file mode 100644
index 0000000..ba5bedd
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef __EDP_CONNECTOR_H__
+#define __EDP_CONNECTOR_H__
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include "drm_crtc.h"
+#include "drm_dp_helper.h"
+#include "msm_drv.h"
+
+#define edp_read(offset) msm_readl((offset))
+#define edp_write(offset, data) msm_writel((data), (offset))
+
+struct edp_ctrl;
+struct edp_aux;
+struct edp_phy;
+
+struct msm_edp {
+	struct drm_device *dev;
+	struct platform_device *pdev;
+
+	struct drm_connector *connector;
+	struct drm_bridge *bridge;
+
+	/* the encoder we are hooked to (outside of eDP block) */
+	struct drm_encoder *encoder;
+
+	struct edp_ctrl *ctrl;
+
+	int irq;
+};
+
+/* eDP bridge */
+struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp);
+void edp_bridge_destroy(struct drm_bridge *bridge);
+
+/* eDP connector */
+struct drm_connector *msm_edp_connector_init(struct msm_edp *edp);
+
+/* AUX */
+void *msm_edp_aux_init(struct device *dev, void __iomem *regbase,
+			struct drm_dp_aux **drm_aux);
+void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux);
+irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr);
+void msm_edp_aux_ctrl(struct edp_aux *aux, int enable);
+
+/* Phy */
+bool msm_edp_phy_ready(struct edp_phy *phy);
+void msm_edp_phy_ctrl(struct edp_phy *phy, int enable);
+void msm_edp_phy_vm_pe_init(struct edp_phy *phy);
+void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1);
+void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane);
+void *msm_edp_phy_init(struct device *dev, void __iomem *regbase);
+
+/* Ctrl */
+irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl);
+void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on);
+int msm_edp_ctrl_init(struct msm_edp *edp);
+void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl);
+bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl);
+int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl,
+	struct drm_connector *connector, struct edid **edid);
+int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl,
+				const struct drm_display_mode *mode,
+				const struct drm_display_info *info);
+/* @pixel_rate is in kHz */
+bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl,
+	u32 pixel_rate, u32 *pm, u32 *pn);
+
+#endif /* __EDP_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/edp/edp.xml.h b/drivers/gpu/drm/msm/edp/edp.xml.h
new file mode 100644
index 0000000..a29f1df
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.xml.h
@@ -0,0 +1,292 @@
+#ifndef EDP_XML
+#define EDP_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 2014-12-05 15:34:49)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
+
+Copyright (C) 2013-2014 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+
+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 edp_color_depth {
+	EDP_6BIT = 0,
+	EDP_8BIT = 1,
+	EDP_10BIT = 2,
+	EDP_12BIT = 3,
+	EDP_16BIT = 4,
+};
+
+enum edp_component_format {
+	EDP_RGB = 0,
+	EDP_YUV422 = 1,
+	EDP_YUV444 = 2,
+};
+
+#define REG_EDP_MAINLINK_CTRL					0x00000004
+#define EDP_MAINLINK_CTRL_ENABLE				0x00000001
+#define EDP_MAINLINK_CTRL_RESET					0x00000002
+
+#define REG_EDP_STATE_CTRL					0x00000008
+#define EDP_STATE_CTRL_TRAIN_PATTERN_1				0x00000001
+#define EDP_STATE_CTRL_TRAIN_PATTERN_2				0x00000002
+#define EDP_STATE_CTRL_TRAIN_PATTERN_3				0x00000004
+#define EDP_STATE_CTRL_SYMBOL_ERR_RATE_MEAS			0x00000008
+#define EDP_STATE_CTRL_PRBS7					0x00000010
+#define EDP_STATE_CTRL_CUSTOM_80_BIT_PATTERN			0x00000020
+#define EDP_STATE_CTRL_SEND_VIDEO				0x00000040
+#define EDP_STATE_CTRL_PUSH_IDLE				0x00000080
+
+#define REG_EDP_CONFIGURATION_CTRL				0x0000000c
+#define EDP_CONFIGURATION_CTRL_SYNC_CLK				0x00000001
+#define EDP_CONFIGURATION_CTRL_STATIC_MVID			0x00000002
+#define EDP_CONFIGURATION_CTRL_PROGRESSIVE			0x00000004
+#define EDP_CONFIGURATION_CTRL_LANES__MASK			0x00000030
+#define EDP_CONFIGURATION_CTRL_LANES__SHIFT			4
+static inline uint32_t EDP_CONFIGURATION_CTRL_LANES(uint32_t val)
+{
+	return ((val) << EDP_CONFIGURATION_CTRL_LANES__SHIFT) & EDP_CONFIGURATION_CTRL_LANES__MASK;
+}
+#define EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING			0x00000040
+#define EDP_CONFIGURATION_CTRL_COLOR__MASK			0x00000100
+#define EDP_CONFIGURATION_CTRL_COLOR__SHIFT			8
+static inline uint32_t EDP_CONFIGURATION_CTRL_COLOR(enum edp_color_depth val)
+{
+	return ((val) << EDP_CONFIGURATION_CTRL_COLOR__SHIFT) & EDP_CONFIGURATION_CTRL_COLOR__MASK;
+}
+
+#define REG_EDP_SOFTWARE_MVID					0x00000014
+
+#define REG_EDP_SOFTWARE_NVID					0x00000018
+
+#define REG_EDP_TOTAL_HOR_VER					0x0000001c
+#define EDP_TOTAL_HOR_VER_HORIZ__MASK				0x0000ffff
+#define EDP_TOTAL_HOR_VER_HORIZ__SHIFT				0
+static inline uint32_t EDP_TOTAL_HOR_VER_HORIZ(uint32_t val)
+{
+	return ((val) << EDP_TOTAL_HOR_VER_HORIZ__SHIFT) & EDP_TOTAL_HOR_VER_HORIZ__MASK;
+}
+#define EDP_TOTAL_HOR_VER_VERT__MASK				0xffff0000
+#define EDP_TOTAL_HOR_VER_VERT__SHIFT				16
+static inline uint32_t EDP_TOTAL_HOR_VER_VERT(uint32_t val)
+{
+	return ((val) << EDP_TOTAL_HOR_VER_VERT__SHIFT) & EDP_TOTAL_HOR_VER_VERT__MASK;
+}
+
+#define REG_EDP_START_HOR_VER_FROM_SYNC				0x00000020
+#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK			0x0000ffff
+#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT		0
+static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_HORIZ(uint32_t val)
+{
+	return ((val) << EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK;
+}
+#define EDP_START_HOR_VER_FROM_SYNC_VERT__MASK			0xffff0000
+#define EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT			16
+static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_VERT(uint32_t val)
+{
+	return ((val) << EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_VERT__MASK;
+}
+
+#define REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY			0x00000024
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK		0x00007fff
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT		0
+static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ(uint32_t val)
+{
+	return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK;
+}
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC			0x00008000
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK		0x7fff0000
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT		16
+static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT(uint32_t val)
+{
+	return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK;
+}
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC			0x80000000
+
+#define REG_EDP_ACTIVE_HOR_VER					0x00000028
+#define EDP_ACTIVE_HOR_VER_HORIZ__MASK				0x0000ffff
+#define EDP_ACTIVE_HOR_VER_HORIZ__SHIFT				0
+static inline uint32_t EDP_ACTIVE_HOR_VER_HORIZ(uint32_t val)
+{
+	return ((val) << EDP_ACTIVE_HOR_VER_HORIZ__SHIFT) & EDP_ACTIVE_HOR_VER_HORIZ__MASK;
+}
+#define EDP_ACTIVE_HOR_VER_VERT__MASK				0xffff0000
+#define EDP_ACTIVE_HOR_VER_VERT__SHIFT				16
+static inline uint32_t EDP_ACTIVE_HOR_VER_VERT(uint32_t val)
+{
+	return ((val) << EDP_ACTIVE_HOR_VER_VERT__SHIFT) & EDP_ACTIVE_HOR_VER_VERT__MASK;
+}
+
+#define REG_EDP_MISC1_MISC0					0x0000002c
+#define EDP_MISC1_MISC0_MISC0__MASK				0x000000ff
+#define EDP_MISC1_MISC0_MISC0__SHIFT				0
+static inline uint32_t EDP_MISC1_MISC0_MISC0(uint32_t val)
+{
+	return ((val) << EDP_MISC1_MISC0_MISC0__SHIFT) & EDP_MISC1_MISC0_MISC0__MASK;
+}
+#define EDP_MISC1_MISC0_SYNC					0x00000001
+#define EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK			0x00000006
+#define EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT			1
+static inline uint32_t EDP_MISC1_MISC0_COMPONENT_FORMAT(enum edp_component_format val)
+{
+	return ((val) << EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT) & EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK;
+}
+#define EDP_MISC1_MISC0_CEA					0x00000008
+#define EDP_MISC1_MISC0_BT709_5					0x00000010
+#define EDP_MISC1_MISC0_COLOR__MASK				0x000000e0
+#define EDP_MISC1_MISC0_COLOR__SHIFT				5
+static inline uint32_t EDP_MISC1_MISC0_COLOR(enum edp_color_depth val)
+{
+	return ((val) << EDP_MISC1_MISC0_COLOR__SHIFT) & EDP_MISC1_MISC0_COLOR__MASK;
+}
+#define EDP_MISC1_MISC0_MISC1__MASK				0x0000ff00
+#define EDP_MISC1_MISC0_MISC1__SHIFT				8
+static inline uint32_t EDP_MISC1_MISC0_MISC1(uint32_t val)
+{
+	return ((val) << EDP_MISC1_MISC0_MISC1__SHIFT) & EDP_MISC1_MISC0_MISC1__MASK;
+}
+#define EDP_MISC1_MISC0_INTERLACED_ODD				0x00000100
+#define EDP_MISC1_MISC0_STEREO__MASK				0x00000600
+#define EDP_MISC1_MISC0_STEREO__SHIFT				9
+static inline uint32_t EDP_MISC1_MISC0_STEREO(uint32_t val)
+{
+	return ((val) << EDP_MISC1_MISC0_STEREO__SHIFT) & EDP_MISC1_MISC0_STEREO__MASK;
+}
+
+#define REG_EDP_PHY_CTRL					0x00000074
+#define EDP_PHY_CTRL_SW_RESET_PLL				0x00000001
+#define EDP_PHY_CTRL_SW_RESET					0x00000004
+
+#define REG_EDP_MAINLINK_READY					0x00000084
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY		0x00000008
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_2_READY		0x00000010
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_3_READY		0x00000020
+
+#define REG_EDP_AUX_CTRL					0x00000300
+#define EDP_AUX_CTRL_ENABLE					0x00000001
+#define EDP_AUX_CTRL_RESET					0x00000002
+
+#define REG_EDP_INTERRUPT_REG_1					0x00000308
+#define EDP_INTERRUPT_REG_1_HPD					0x00000001
+#define EDP_INTERRUPT_REG_1_HPD_ACK				0x00000002
+#define EDP_INTERRUPT_REG_1_HPD_EN				0x00000004
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE			0x00000008
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_ACK			0x00000010
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_EN			0x00000020
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR				0x00000040
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR_ACK			0x00000080
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR_EN			0x00000100
+#define EDP_INTERRUPT_REG_1_TIMEOUT				0x00000200
+#define EDP_INTERRUPT_REG_1_TIMEOUT_ACK				0x00000400
+#define EDP_INTERRUPT_REG_1_TIMEOUT_EN				0x00000800
+#define EDP_INTERRUPT_REG_1_NACK_DEFER				0x00001000
+#define EDP_INTERRUPT_REG_1_NACK_DEFER_ACK			0x00002000
+#define EDP_INTERRUPT_REG_1_NACK_DEFER_EN			0x00004000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT			0x00008000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_ACK			0x00010000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_EN			0x00020000
+#define EDP_INTERRUPT_REG_1_I2C_NACK				0x00040000
+#define EDP_INTERRUPT_REG_1_I2C_NACK_ACK			0x00080000
+#define EDP_INTERRUPT_REG_1_I2C_NACK_EN				0x00100000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER				0x00200000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER_ACK			0x00400000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER_EN			0x00800000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK				0x01000000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_ACK			0x02000000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_EN			0x04000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR				0x08000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR_ACK			0x10000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR_EN			0x20000000
+
+#define REG_EDP_INTERRUPT_REG_2					0x0000030c
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO			0x00000001
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_ACK			0x00000002
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_EN			0x00000004
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT			0x00000008
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_ACK		0x00000010
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_EN		0x00000020
+#define EDP_INTERRUPT_REG_2_FRAME_END				0x00000200
+#define EDP_INTERRUPT_REG_2_FRAME_END_ACK			0x00000080
+#define EDP_INTERRUPT_REG_2_FRAME_END_EN			0x00000100
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED				0x00000200
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED_ACK			0x00000400
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED_EN			0x00000800
+
+#define REG_EDP_INTERRUPT_TRANS_NUM				0x00000310
+
+#define REG_EDP_AUX_DATA					0x00000314
+#define EDP_AUX_DATA_READ					0x00000001
+#define EDP_AUX_DATA_DATA__MASK					0x0000ff00
+#define EDP_AUX_DATA_DATA__SHIFT				8
+static inline uint32_t EDP_AUX_DATA_DATA(uint32_t val)
+{
+	return ((val) << EDP_AUX_DATA_DATA__SHIFT) & EDP_AUX_DATA_DATA__MASK;
+}
+#define EDP_AUX_DATA_INDEX__MASK				0x00ff0000
+#define EDP_AUX_DATA_INDEX__SHIFT				16
+static inline uint32_t EDP_AUX_DATA_INDEX(uint32_t val)
+{
+	return ((val) << EDP_AUX_DATA_INDEX__SHIFT) & EDP_AUX_DATA_INDEX__MASK;
+}
+#define EDP_AUX_DATA_INDEX_WRITE				0x80000000
+
+#define REG_EDP_AUX_TRANS_CTRL					0x00000318
+#define EDP_AUX_TRANS_CTRL_I2C					0x00000100
+#define EDP_AUX_TRANS_CTRL_GO					0x00000200
+
+#define REG_EDP_AUX_STATUS					0x00000324
+
+static inline uint32_t REG_EDP_PHY_LN(uint32_t i0) { return 0x00000400 + 0x40*i0; }
+
+static inline uint32_t REG_EDP_PHY_LN_PD_CTL(uint32_t i0) { return 0x00000404 + 0x40*i0; }
+
+#define REG_EDP_PHY_GLB_VM_CFG0					0x00000510
+
+#define REG_EDP_PHY_GLB_VM_CFG1					0x00000514
+
+#define REG_EDP_PHY_GLB_MISC9					0x00000518
+
+#define REG_EDP_PHY_GLB_CFG					0x00000528
+
+#define REG_EDP_PHY_GLB_PD_CTL					0x0000052c
+
+#define REG_EDP_PHY_GLB_PHY_STATUS				0x00000598
+
+
+#endif /* EDP_XML */
diff --git a/drivers/gpu/drm/msm/edp/edp_aux.c b/drivers/gpu/drm/msm/edp/edp_aux.c
new file mode 100644
index 0000000..5f5a84f
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_aux.c
@@ -0,0 +1,268 @@
+/*
+ * 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 "edp.h"
+#include "edp.xml.h"
+
+#define AUX_CMD_FIFO_LEN	144
+#define AUX_CMD_NATIVE_MAX	16
+#define AUX_CMD_I2C_MAX		128
+
+#define EDP_INTR_AUX_I2C_ERR	\
+	(EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
+	EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
+	EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER)
+#define EDP_INTR_TRANS_STATUS	\
+	(EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR)
+
+struct edp_aux {
+	void __iomem *base;
+	bool msg_err;
+
+	struct completion msg_comp;
+
+	/* To prevent the message transaction routine from reentry. */
+	struct mutex msg_mutex;
+
+	struct drm_dp_aux drm_aux;
+};
+#define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux)
+
+static int edp_msg_fifo_tx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+	u32 data[4];
+	u32 reg, len;
+	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+	u8 *msgdata = msg->buffer;
+	int i;
+
+	if (read)
+		len = 4;
+	else
+		len = msg->size + 4;
+
+	/*
+	 * cmd fifo only has depth of 144 bytes
+	 */
+	if (len > AUX_CMD_FIFO_LEN)
+		return -EINVAL;
+
+	/* Pack cmd and write to HW */
+	data[0] = (msg->address >> 16) & 0xf;	/* addr[19:16] */
+	if (read)
+		data[0] |=  BIT(4);		/* R/W */
+
+	data[1] = (msg->address >> 8) & 0xff;	/* addr[15:8] */
+	data[2] = msg->address & 0xff;		/* addr[7:0] */
+	data[3] = (msg->size - 1) & 0xff;	/* len[7:0] */
+
+	for (i = 0; i < len; i++) {
+		reg = (i < 4) ? data[i] : msgdata[i - 4];
+		reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
+		if (i == 0)
+			reg |= EDP_AUX_DATA_INDEX_WRITE;
+		edp_write(aux->base + REG_EDP_AUX_DATA, reg);
+	}
+
+	reg = 0; /* Transaction number is always 1 */
+	if (!native) /* i2c */
+		reg |= EDP_AUX_TRANS_CTRL_I2C;
+
+	reg |= EDP_AUX_TRANS_CTRL_GO;
+	edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, reg);
+
+	return 0;
+}
+
+static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+	u32 data;
+	u8 *dp;
+	int i;
+	u32 len = msg->size;
+
+	edp_write(aux->base + REG_EDP_AUX_DATA,
+		EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
+
+	dp = msg->buffer;
+
+	/* discard first byte */
+	data = edp_read(aux->base + REG_EDP_AUX_DATA);
+	for (i = 0; i < len; i++) {
+		data = edp_read(aux->base + REG_EDP_AUX_DATA);
+		dp[i] = (u8)((data >> 8) & 0xff);
+	}
+
+	return 0;
+}
+
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call msm_edp_aux_ctrl() function to reset the AUX channel,
+ * if the waiting is timeout.
+ * The caller who triggers the transaction should avoid the
+ * msm_edp_aux_ctrl() running concurrently in other threads, i.e.
+ * start transaction only when AUX channel is fully enabled.
+ */
+ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg)
+{
+	struct edp_aux *aux = to_edp_aux(drm_aux);
+	ssize_t ret;
+	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		return msg->size;
+	}
+
+	/* msg sanity check */
+	if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
+		(msg->size > AUX_CMD_I2C_MAX)) {
+		pr_err("%s: invalid msg: size(%d), request(%x)\n",
+			__func__, msg->size, msg->request);
+		return -EINVAL;
+	}
+
+	mutex_lock(&aux->msg_mutex);
+
+	aux->msg_err = false;
+	reinit_completion(&aux->msg_comp);
+
+	ret = edp_msg_fifo_tx(aux, msg);
+	if (ret < 0)
+		goto unlock_exit;
+
+	DBG("wait_for_completion");
+	ret = wait_for_completion_timeout(&aux->msg_comp, 300);
+	if (ret <= 0) {
+		/*
+		 * Clear GO and reset AUX channel
+		 * to cancel the current transaction.
+		 */
+		edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
+		msm_edp_aux_ctrl(aux, 1);
+		pr_err("%s: aux timeout, %d\n", __func__, ret);
+		goto unlock_exit;
+	}
+	DBG("completion");
+
+	if (!aux->msg_err) {
+		if (read) {
+			ret = edp_msg_fifo_rx(aux, msg);
+			if (ret < 0)
+				goto unlock_exit;
+		}
+
+		msg->reply = native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+		/*
+		 * The sleep time in caller is not long enough to make sure
+		 * our H/W completes transactions. Add more defer time here.
+		 */
+		msleep(100);
+	}
+
+	/* Return requested size for success or retry */
+	ret = msg->size;
+
+unlock_exit:
+	mutex_unlock(&aux->msg_mutex);
+	return ret;
+}
+
+void *msm_edp_aux_init(struct device *dev, void __iomem *regbase,
+	struct drm_dp_aux **drm_aux)
+{
+	struct edp_aux *aux = NULL;
+	int ret;
+
+	DBG("");
+	aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
+	if (!aux)
+		return NULL;
+
+	aux->base = regbase;
+	mutex_init(&aux->msg_mutex);
+	init_completion(&aux->msg_comp);
+
+	aux->drm_aux.name = "msm_edp_aux";
+	aux->drm_aux.dev = dev;
+	aux->drm_aux.transfer = edp_aux_transfer;
+	ret = drm_dp_aux_register(&aux->drm_aux);
+	if (ret) {
+		pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
+		mutex_destroy(&aux->msg_mutex);
+	}
+
+	if (drm_aux && aux)
+		*drm_aux = &aux->drm_aux;
+
+	return aux;
+}
+
+void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux)
+{
+	if (aux) {
+		drm_dp_aux_unregister(&aux->drm_aux);
+		mutex_destroy(&aux->msg_mutex);
+	}
+}
+
+irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr)
+{
+	if (isr & EDP_INTR_TRANS_STATUS) {
+		DBG("isr=%x", isr);
+		edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
+
+		if (isr & EDP_INTR_AUX_I2C_ERR)
+			aux->msg_err = true;
+		else
+			aux->msg_err = false;
+
+		complete(&aux->msg_comp);
+	}
+
+	return IRQ_HANDLED;
+}
+
+void msm_edp_aux_ctrl(struct edp_aux *aux, int enable)
+{
+	u32 data;
+
+	DBG("enable=%d", enable);
+	data = edp_read(aux->base + REG_EDP_AUX_CTRL);
+
+	if (enable) {
+		data |= EDP_AUX_CTRL_RESET;
+		edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+		/* Make sure full reset */
+		wmb();
+		usleep_range(500, 1000);
+
+		data &= ~EDP_AUX_CTRL_RESET;
+		data |= EDP_AUX_CTRL_ENABLE;
+		edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+	} else {
+		data &= ~EDP_AUX_CTRL_ENABLE;
+		edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+	}
+}
+
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
new file mode 100644
index 0000000..2bc73f82
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
@@ -0,0 +1,120 @@
+/*
+ * 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 "edp.h"
+
+struct edp_bridge {
+	struct drm_bridge base;
+	struct msm_edp *edp;
+};
+#define to_edp_bridge(x) container_of(x, struct edp_bridge, base)
+
+void edp_bridge_destroy(struct drm_bridge *bridge)
+{
+}
+
+static void edp_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+	struct msm_edp *edp = edp_bridge->edp;
+
+	DBG("");
+	msm_edp_ctrl_power(edp->ctrl, true);
+}
+
+static void edp_bridge_enable(struct drm_bridge *bridge)
+{
+	DBG("");
+}
+
+static void edp_bridge_disable(struct drm_bridge *bridge)
+{
+	DBG("");
+}
+
+static void edp_bridge_post_disable(struct drm_bridge *bridge)
+{
+	struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+	struct msm_edp *edp = edp_bridge->edp;
+
+	DBG("");
+	msm_edp_ctrl_power(edp->ctrl, false);
+}
+
+static void edp_bridge_mode_set(struct drm_bridge *bridge,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	struct drm_device *dev = bridge->dev;
+	struct drm_connector *connector;
+	struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+	struct msm_edp *edp = edp_bridge->edp;
+
+	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);
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if ((connector->encoder != NULL) &&
+			(connector->encoder->bridge == bridge)) {
+			msm_edp_ctrl_timing_cfg(edp->ctrl,
+				adjusted_mode, &connector->display_info);
+			break;
+		}
+	}
+}
+
+static const struct drm_bridge_funcs edp_bridge_funcs = {
+	.pre_enable = edp_bridge_pre_enable,
+	.enable = edp_bridge_enable,
+	.disable = edp_bridge_disable,
+	.post_disable = edp_bridge_post_disable,
+	.mode_set = edp_bridge_mode_set,
+};
+
+/* initialize bridge */
+struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
+{
+	struct drm_bridge *bridge = NULL;
+	struct edp_bridge *edp_bridge;
+	int ret;
+
+	edp_bridge = devm_kzalloc(edp->dev->dev,
+			sizeof(*edp_bridge), GFP_KERNEL);
+	if (!edp_bridge) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	edp_bridge->edp = edp;
+
+	bridge = &edp_bridge->base;
+	bridge->funcs = &edp_bridge_funcs;
+
+	ret = drm_bridge_attach(edp->dev, bridge);
+	if (ret)
+		goto fail;
+
+	return bridge;
+
+fail:
+	if (bridge)
+		edp_bridge_destroy(bridge);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c
new file mode 100644
index 0000000..d8812e8
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_connector.c
@@ -0,0 +1,161 @@
+/*
+ * 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 "drm/drm_edid.h"
+#include "msm_kms.h"
+#include "edp.h"
+
+struct edp_connector {
+	struct drm_connector base;
+	struct msm_edp *edp;
+};
+#define to_edp_connector(x) container_of(x, struct edp_connector, base)
+
+static enum drm_connector_status edp_connector_detect(
+		struct drm_connector *connector, bool force)
+{
+	struct edp_connector *edp_connector = to_edp_connector(connector);
+	struct msm_edp *edp = edp_connector->edp;
+
+	DBG("");
+	return msm_edp_ctrl_panel_connected(edp->ctrl) ?
+		connector_status_connected : connector_status_disconnected;
+}
+
+static void edp_connector_destroy(struct drm_connector *connector)
+{
+	struct edp_connector *edp_connector = to_edp_connector(connector);
+
+	DBG("");
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+
+	kfree(edp_connector);
+}
+
+static int edp_connector_get_modes(struct drm_connector *connector)
+{
+	struct edp_connector *edp_connector = to_edp_connector(connector);
+	struct msm_edp *edp = edp_connector->edp;
+
+	struct edid *drm_edid = NULL;
+	int ret = 0;
+
+	DBG("");
+	ret = msm_edp_ctrl_get_panel_info(edp->ctrl, connector, &drm_edid);
+	if (ret)
+		return ret;
+
+	drm_mode_connector_update_edid_property(connector, drm_edid);
+	if (drm_edid)
+		ret = drm_add_edid_modes(connector, drm_edid);
+
+	return ret;
+}
+
+static int edp_connector_mode_valid(struct drm_connector *connector,
+				 struct drm_display_mode *mode)
+{
+	struct edp_connector *edp_connector = to_edp_connector(connector);
+	struct msm_edp *edp = edp_connector->edp;
+	struct msm_drm_private *priv = connector->dev->dev_private;
+	struct msm_kms *kms = priv->kms;
+	long actual, requested;
+
+	requested = 1000 * mode->clock;
+	actual = kms->funcs->round_pixclk(kms,
+			requested, edp_connector->edp->encoder);
+
+	DBG("requested=%ld, actual=%ld", requested, actual);
+	if (actual != requested)
+		return MODE_CLOCK_RANGE;
+
+	if (!msm_edp_ctrl_pixel_clock_valid(
+		edp->ctrl, mode->clock, NULL, NULL))
+		return MODE_CLOCK_RANGE;
+
+	/* Invalidate all modes if color format is not supported */
+	if (connector->display_info.bpc > 8)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+edp_connector_best_encoder(struct drm_connector *connector)
+{
+	struct edp_connector *edp_connector = to_edp_connector(connector);
+
+	DBG("");
+	return edp_connector->edp->encoder;
+}
+
+static const struct drm_connector_funcs edp_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = edp_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = edp_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 edp_connector_helper_funcs = {
+	.get_modes = edp_connector_get_modes,
+	.mode_valid = edp_connector_mode_valid,
+	.best_encoder = edp_connector_best_encoder,
+};
+
+/* initialize connector */
+struct drm_connector *msm_edp_connector_init(struct msm_edp *edp)
+{
+	struct drm_connector *connector = NULL;
+	struct edp_connector *edp_connector;
+	int ret;
+
+	edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL);
+	if (!edp_connector) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	edp_connector->edp = edp;
+
+	connector = &edp_connector->base;
+
+	ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs,
+			DRM_MODE_CONNECTOR_eDP);
+	if (ret)
+		goto fail;
+
+	drm_connector_helper_add(connector, &edp_connector_helper_funcs);
+
+	/* We don't support HPD, so only poll status until connected. */
+	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+	/* Display driver doesn't support interlace now. */
+	connector->interlace_allowed = false;
+	connector->doublescan_allowed = false;
+
+	ret = drm_connector_register(connector);
+	if (ret)
+		goto fail;
+
+	return connector;
+
+fail:
+	if (connector)
+		edp_connector_destroy(connector);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c
new file mode 100644
index 0000000..3e24621
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c
@@ -0,0 +1,1373 @@
+/*
+ * 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 <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include "drm_crtc.h"
+#include "drm_dp_helper.h"
+#include "drm_edid.h"
+#include "edp.h"
+#include "edp.xml.h"
+
+#define VDDA_MIN_UV		1800000	/* uV units */
+#define VDDA_MAX_UV		1800000	/* uV units */
+#define VDDA_UA_ON_LOAD		100000	/* uA units */
+#define VDDA_UA_OFF_LOAD	100	/* uA units */
+
+#define DPCD_LINK_VOLTAGE_MAX		4
+#define DPCD_LINK_PRE_EMPHASIS_MAX	4
+
+#define EDP_LINK_BW_MAX		DP_LINK_BW_2_7
+
+/* Link training return value */
+#define EDP_TRAIN_FAIL		-1
+#define EDP_TRAIN_SUCCESS	0
+#define EDP_TRAIN_RECONFIG	1
+
+#define EDP_CLK_MASK_AHB		BIT(0)
+#define EDP_CLK_MASK_AUX		BIT(1)
+#define EDP_CLK_MASK_LINK		BIT(2)
+#define EDP_CLK_MASK_PIXEL		BIT(3)
+#define EDP_CLK_MASK_MDP_CORE		BIT(4)
+#define EDP_CLK_MASK_LINK_CHAN	(EDP_CLK_MASK_LINK | EDP_CLK_MASK_PIXEL)
+#define EDP_CLK_MASK_AUX_CHAN	\
+	(EDP_CLK_MASK_AHB | EDP_CLK_MASK_AUX | EDP_CLK_MASK_MDP_CORE)
+#define EDP_CLK_MASK_ALL	(EDP_CLK_MASK_AUX_CHAN | EDP_CLK_MASK_LINK_CHAN)
+
+#define EDP_BACKLIGHT_MAX	255
+
+#define EDP_INTR_STATUS1	\
+	(EDP_INTERRUPT_REG_1_HPD | EDP_INTERRUPT_REG_1_AUX_I2C_DONE | \
+	EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
+	EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
+	EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER | \
+	EDP_INTERRUPT_REG_1_PLL_UNLOCK | EDP_INTERRUPT_REG_1_AUX_ERROR)
+#define EDP_INTR_MASK1	(EDP_INTR_STATUS1 << 2)
+#define EDP_INTR_STATUS2	\
+	(EDP_INTERRUPT_REG_2_READY_FOR_VIDEO | \
+	EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT | \
+	EDP_INTERRUPT_REG_2_FRAME_END | EDP_INTERRUPT_REG_2_CRC_UPDATED)
+#define EDP_INTR_MASK2	(EDP_INTR_STATUS2 << 2)
+
+struct edp_ctrl {
+	struct platform_device *pdev;
+
+	void __iomem *base;
+
+	/* regulators */
+	struct regulator *vdda_vreg;
+	struct regulator *lvl_vreg;
+
+	/* clocks */
+	struct clk *aux_clk;
+	struct clk *pixel_clk;
+	struct clk *ahb_clk;
+	struct clk *link_clk;
+	struct clk *mdp_core_clk;
+
+	/* gpios */
+	struct gpio_desc *panel_en_gpio;
+	struct gpio_desc *panel_hpd_gpio;
+
+	/* completion and mutex */
+	struct completion idle_comp;
+	struct mutex dev_mutex; /* To protect device power status */
+
+	/* work queue */
+	struct work_struct on_work;
+	struct work_struct off_work;
+	struct workqueue_struct *workqueue;
+
+	/* Interrupt register lock */
+	spinlock_t irq_lock;
+
+	bool edp_connected;
+	bool power_on;
+
+	/* edid raw data */
+	struct edid *edid;
+
+	struct drm_dp_link dp_link;
+	struct drm_dp_aux *drm_aux;
+
+	/* dpcd raw data */
+	u8 dpcd[DP_RECEIVER_CAP_SIZE];
+
+	/* Link status */
+	u8 link_rate;
+	u8 lane_cnt;
+	u8 v_level;
+	u8 p_level;
+
+	/* Timing status */
+	u8 interlaced;
+	u32 pixel_rate; /* in kHz */
+	u32 color_depth;
+
+	struct edp_aux *aux;
+	struct edp_phy *phy;
+};
+
+struct edp_pixel_clk_div {
+	u32 rate; /* in kHz */
+	u32 m;
+	u32 n;
+};
+
+#define EDP_PIXEL_CLK_NUM 8
+static const struct edp_pixel_clk_div clk_divs[2][EDP_PIXEL_CLK_NUM] = {
+	{ /* Link clock = 162MHz, source clock = 810MHz */
+		{119000, 31,  211}, /* WSXGA+ 1680x1050@60Hz CVT */
+		{130250, 32,  199}, /* UXGA 1600x1200@60Hz CVT */
+		{148500, 11,  60},  /* FHD 1920x1080@60Hz */
+		{154000, 50,  263}, /* WUXGA 1920x1200@60Hz CVT */
+		{209250, 31,  120}, /* QXGA 2048x1536@60Hz CVT */
+		{268500, 119, 359}, /* WQXGA 2560x1600@60Hz CVT */
+		{138530, 33,  193}, /* AUO B116HAN03.0 Panel */
+		{141400, 48,  275}, /* AUO B133HTN01.2 Panel */
+	},
+	{ /* Link clock = 270MHz, source clock = 675MHz */
+		{119000, 52,  295}, /* WSXGA+ 1680x1050@60Hz CVT */
+		{130250, 11,  57},  /* UXGA 1600x1200@60Hz CVT */
+		{148500, 11,  50},  /* FHD 1920x1080@60Hz */
+		{154000, 47,  206}, /* WUXGA 1920x1200@60Hz CVT */
+		{209250, 31,  100}, /* QXGA 2048x1536@60Hz CVT */
+		{268500, 107, 269}, /* WQXGA 2560x1600@60Hz CVT */
+		{138530, 63,  307}, /* AUO B116HAN03.0 Panel */
+		{141400, 53,  253}, /* AUO B133HTN01.2 Panel */
+	},
+};
+
+static int edp_clk_init(struct edp_ctrl *ctrl)
+{
+	struct device *dev = &ctrl->pdev->dev;
+	int ret;
+
+	ctrl->aux_clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(ctrl->aux_clk)) {
+		ret = PTR_ERR(ctrl->aux_clk);
+		pr_err("%s: Can't find aux_clk, %d\n", __func__, ret);
+		ctrl->aux_clk = NULL;
+		return ret;
+	}
+
+	ctrl->pixel_clk = devm_clk_get(dev, "pixel_clk");
+	if (IS_ERR(ctrl->pixel_clk)) {
+		ret = PTR_ERR(ctrl->pixel_clk);
+		pr_err("%s: Can't find pixel_clk, %d\n", __func__, ret);
+		ctrl->pixel_clk = NULL;
+		return ret;
+	}
+
+	ctrl->ahb_clk = devm_clk_get(dev, "iface_clk");
+	if (IS_ERR(ctrl->ahb_clk)) {
+		ret = PTR_ERR(ctrl->ahb_clk);
+		pr_err("%s: Can't find ahb_clk, %d\n", __func__, ret);
+		ctrl->ahb_clk = NULL;
+		return ret;
+	}
+
+	ctrl->link_clk = devm_clk_get(dev, "link_clk");
+	if (IS_ERR(ctrl->link_clk)) {
+		ret = PTR_ERR(ctrl->link_clk);
+		pr_err("%s: Can't find link_clk, %d\n", __func__, ret);
+		ctrl->link_clk = NULL;
+		return ret;
+	}
+
+	/* need mdp core clock to receive irq */
+	ctrl->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
+	if (IS_ERR(ctrl->mdp_core_clk)) {
+		ret = PTR_ERR(ctrl->mdp_core_clk);
+		pr_err("%s: Can't find mdp_core_clk, %d\n", __func__, ret);
+		ctrl->mdp_core_clk = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static int edp_clk_enable(struct edp_ctrl *ctrl, u32 clk_mask)
+{
+	int ret;
+
+	DBG("mask=%x", clk_mask);
+	/* ahb_clk should be enabled first */
+	if (clk_mask & EDP_CLK_MASK_AHB) {
+		ret = clk_prepare_enable(ctrl->ahb_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable ahb clk\n", __func__);
+			goto f0;
+		}
+	}
+	if (clk_mask & EDP_CLK_MASK_AUX) {
+		ret = clk_set_rate(ctrl->aux_clk, 19200000);
+		if (ret) {
+			pr_err("%s: Failed to set rate aux clk\n", __func__);
+			goto f1;
+		}
+		ret = clk_prepare_enable(ctrl->aux_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable aux clk\n", __func__);
+			goto f1;
+		}
+	}
+	/* Need to set rate and enable link_clk prior to pixel_clk */
+	if (clk_mask & EDP_CLK_MASK_LINK) {
+		DBG("edp->link_clk, set_rate %ld",
+				(unsigned long)ctrl->link_rate * 27000000);
+		ret = clk_set_rate(ctrl->link_clk,
+				(unsigned long)ctrl->link_rate * 27000000);
+		if (ret) {
+			pr_err("%s: Failed to set rate to link clk\n",
+				__func__);
+			goto f2;
+		}
+
+		ret = clk_prepare_enable(ctrl->link_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable link clk\n", __func__);
+			goto f2;
+		}
+	}
+	if (clk_mask & EDP_CLK_MASK_PIXEL) {
+		DBG("edp->pixel_clk, set_rate %ld",
+				(unsigned long)ctrl->pixel_rate * 1000);
+		ret = clk_set_rate(ctrl->pixel_clk,
+				(unsigned long)ctrl->pixel_rate * 1000);
+		if (ret) {
+			pr_err("%s: Failed to set rate to pixel clk\n",
+				__func__);
+			goto f3;
+		}
+
+		ret = clk_prepare_enable(ctrl->pixel_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable pixel clk\n", __func__);
+			goto f3;
+		}
+	}
+	if (clk_mask & EDP_CLK_MASK_MDP_CORE) {
+		ret = clk_prepare_enable(ctrl->mdp_core_clk);
+		if (ret) {
+			pr_err("%s: Failed to enable mdp core clk\n", __func__);
+			goto f4;
+		}
+	}
+
+	return 0;
+
+f4:
+	if (clk_mask & EDP_CLK_MASK_PIXEL)
+		clk_disable_unprepare(ctrl->pixel_clk);
+f3:
+	if (clk_mask & EDP_CLK_MASK_LINK)
+		clk_disable_unprepare(ctrl->link_clk);
+f2:
+	if (clk_mask & EDP_CLK_MASK_AUX)
+		clk_disable_unprepare(ctrl->aux_clk);
+f1:
+	if (clk_mask & EDP_CLK_MASK_AHB)
+		clk_disable_unprepare(ctrl->ahb_clk);
+f0:
+	return ret;
+}
+
+static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask)
+{
+	if (clk_mask & EDP_CLK_MASK_MDP_CORE)
+		clk_disable_unprepare(ctrl->mdp_core_clk);
+	if (clk_mask & EDP_CLK_MASK_PIXEL)
+		clk_disable_unprepare(ctrl->pixel_clk);
+	if (clk_mask & EDP_CLK_MASK_LINK)
+		clk_disable_unprepare(ctrl->link_clk);
+	if (clk_mask & EDP_CLK_MASK_AUX)
+		clk_disable_unprepare(ctrl->aux_clk);
+	if (clk_mask & EDP_CLK_MASK_AHB)
+		clk_disable_unprepare(ctrl->ahb_clk);
+}
+
+static int edp_regulator_init(struct edp_ctrl *ctrl)
+{
+	struct device *dev = &ctrl->pdev->dev;
+
+	DBG("");
+	ctrl->vdda_vreg = devm_regulator_get(dev, "vdda");
+	if (IS_ERR(ctrl->vdda_vreg)) {
+		pr_err("%s: Could not get vdda reg, ret = %ld\n", __func__,
+				PTR_ERR(ctrl->vdda_vreg));
+		ctrl->vdda_vreg = NULL;
+		return PTR_ERR(ctrl->vdda_vreg);
+	}
+	ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd");
+	if (IS_ERR(ctrl->lvl_vreg)) {
+		pr_err("Could not get lvl-vdd reg, %ld",
+				PTR_ERR(ctrl->lvl_vreg));
+		ctrl->lvl_vreg = NULL;
+		return PTR_ERR(ctrl->lvl_vreg);
+	}
+
+	return 0;
+}
+
+static int edp_regulator_enable(struct edp_ctrl *ctrl)
+{
+	int ret;
+
+	ret = regulator_set_voltage(ctrl->vdda_vreg, VDDA_MIN_UV, VDDA_MAX_UV);
+	if (ret) {
+		pr_err("%s:vdda_vreg set_voltage failed, %d\n", __func__, ret);
+		goto vdda_set_fail;
+	}
+
+	ret = regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_ON_LOAD);
+	if (ret < 0) {
+		pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__);
+		goto vdda_set_fail;
+	}
+
+	ret = regulator_enable(ctrl->vdda_vreg);
+	if (ret) {
+		pr_err("%s: Failed to enable vdda_vreg regulator.\n", __func__);
+		goto vdda_enable_fail;
+	}
+
+	ret = regulator_enable(ctrl->lvl_vreg);
+	if (ret) {
+		pr_err("Failed to enable lvl-vdd reg regulator, %d", ret);
+		goto lvl_enable_fail;
+	}
+
+	DBG("exit");
+	return 0;
+
+lvl_enable_fail:
+	regulator_disable(ctrl->vdda_vreg);
+vdda_enable_fail:
+	regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD);
+vdda_set_fail:
+	return ret;
+}
+
+static void edp_regulator_disable(struct edp_ctrl *ctrl)
+{
+	regulator_disable(ctrl->lvl_vreg);
+	regulator_disable(ctrl->vdda_vreg);
+	regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD);
+}
+
+static int edp_gpio_config(struct edp_ctrl *ctrl)
+{
+	struct device *dev = &ctrl->pdev->dev;
+	int ret;
+
+	ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd");
+	if (IS_ERR(ctrl->panel_hpd_gpio)) {
+		ret = PTR_ERR(ctrl->panel_hpd_gpio);
+		ctrl->panel_hpd_gpio = NULL;
+		pr_err("%s: cannot get panel-hpd-gpios, %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = gpiod_direction_input(ctrl->panel_hpd_gpio);
+	if (ret) {
+		pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret);
+		return ret;
+	}
+
+	ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en");
+	if (IS_ERR(ctrl->panel_en_gpio)) {
+		ret = PTR_ERR(ctrl->panel_en_gpio);
+		ctrl->panel_en_gpio = NULL;
+		pr_err("%s: cannot get panel-en-gpios, %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = gpiod_direction_output(ctrl->panel_en_gpio, 0);
+	if (ret) {
+		pr_err("%s: Set direction for panel_en failed, %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	DBG("gpio on");
+
+	return 0;
+}
+
+static void edp_ctrl_irq_enable(struct edp_ctrl *ctrl, int enable)
+{
+	unsigned long flags;
+
+	DBG("%d", enable);
+	spin_lock_irqsave(&ctrl->irq_lock, flags);
+	if (enable) {
+		edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, EDP_INTR_MASK1);
+		edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, EDP_INTR_MASK2);
+	} else {
+		edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, 0x0);
+		edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, 0x0);
+	}
+	spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+	DBG("exit");
+}
+
+static void edp_fill_link_cfg(struct edp_ctrl *ctrl)
+{
+	u32 prate;
+	u32 lrate;
+	u32 bpp;
+	u8 max_lane = ctrl->dp_link.num_lanes;
+	u8 lane;
+
+	prate = ctrl->pixel_rate;
+	bpp = ctrl->color_depth * 3;
+
+	/*
+	 * By default, use the maximum link rate and minimum lane count,
+	 * so that we can do rate down shift during link training.
+	 */
+	ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate);
+
+	prate *= bpp;
+	prate /= 8; /* in kByte */
+
+	lrate = 270000; /* in kHz */
+	lrate *= ctrl->link_rate;
+	lrate /= 10; /* in kByte, 10 bits --> 8 bits */
+
+	for (lane = 1; lane <= max_lane; lane <<= 1) {
+		if (lrate >= prate)
+			break;
+		lrate <<= 1;
+	}
+
+	ctrl->lane_cnt = lane;
+	DBG("rate=%d lane=%d", ctrl->link_rate, ctrl->lane_cnt);
+}
+
+static void edp_config_ctrl(struct edp_ctrl *ctrl)
+{
+	u32 data;
+	enum edp_color_depth depth;
+
+	data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1);
+
+	if (ctrl->dp_link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+		data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
+
+	depth = EDP_6BIT;
+	if (ctrl->color_depth == 8)
+		depth = EDP_8BIT;
+
+	data |= EDP_CONFIGURATION_CTRL_COLOR(depth);
+
+	if (!ctrl->interlaced)	/* progressive */
+		data |= EDP_CONFIGURATION_CTRL_PROGRESSIVE;
+
+	data |= (EDP_CONFIGURATION_CTRL_SYNC_CLK |
+		EDP_CONFIGURATION_CTRL_STATIC_MVID);
+
+	edp_write(ctrl->base + REG_EDP_CONFIGURATION_CTRL, data);
+}
+
+static void edp_state_ctrl(struct edp_ctrl *ctrl, u32 state)
+{
+	edp_write(ctrl->base + REG_EDP_STATE_CTRL, state);
+	/* Make sure H/W status is set */
+	wmb();
+}
+
+static int edp_lane_set_write(struct edp_ctrl *ctrl,
+	u8 voltage_level, u8 pre_emphasis_level)
+{
+	int i;
+	u8 buf[4];
+
+	if (voltage_level >= DPCD_LINK_VOLTAGE_MAX)
+		voltage_level |= 0x04;
+
+	if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX)
+		pre_emphasis_level |= 0x04;
+
+	pre_emphasis_level <<= 3;
+
+	for (i = 0; i < 4; i++)
+		buf[i] = voltage_level | pre_emphasis_level;
+
+	DBG("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level);
+	if (drm_dp_dpcd_write(ctrl->drm_aux, 0x103, buf, 4) < 4) {
+		pr_err("%s: Set sw/pe to panel failed\n", __func__);
+		return -ENOLINK;
+	}
+
+	return 0;
+}
+
+static int edp_train_pattern_set_write(struct edp_ctrl *ctrl, u8 pattern)
+{
+	u8 p = pattern;
+
+	DBG("pattern=%x", p);
+	if (drm_dp_dpcd_write(ctrl->drm_aux,
+				DP_TRAINING_PATTERN_SET, &p, 1) < 1) {
+		pr_err("%s: Set training pattern to panel failed\n", __func__);
+		return -ENOLINK;
+	}
+
+	return 0;
+}
+
+static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl,
+	const u8 *link_status)
+{
+	int i;
+	u8 max = 0;
+	u8 data;
+
+	/* use the max level across lanes */
+	for (i = 0; i < ctrl->lane_cnt; i++) {
+		data = drm_dp_get_adjust_request_voltage(link_status, i);
+		DBG("lane=%d req_voltage_swing=0x%x", i, data);
+		if (max < data)
+			max = data;
+	}
+
+	ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+
+	/* use the max level across lanes */
+	max = 0;
+	for (i = 0; i < ctrl->lane_cnt; i++) {
+		data = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+		DBG("lane=%d req_pre_emphasis=0x%x", i, data);
+		if (max < data)
+			max = data;
+	}
+
+	ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+	DBG("v_level=%d, p_level=%d", ctrl->v_level, ctrl->p_level);
+}
+
+static void edp_host_train_set(struct edp_ctrl *ctrl, u32 train)
+{
+	int cnt = 10;
+	u32 data;
+	u32 shift = train - 1;
+
+	DBG("train=%d", train);
+
+	edp_state_ctrl(ctrl, EDP_STATE_CTRL_TRAIN_PATTERN_1 << shift);
+	while (--cnt) {
+		data = edp_read(ctrl->base + REG_EDP_MAINLINK_READY);
+		if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift))
+			break;
+	}
+
+	if (cnt == 0)
+		pr_err("%s: set link_train=%d failed\n", __func__, train);
+}
+
+static const u8 vm_pre_emphasis[4][4] = {
+	{0x03, 0x06, 0x09, 0x0C},	/* pe0, 0 db */
+	{0x03, 0x06, 0x09, 0xFF},	/* pe1, 3.5 db */
+	{0x03, 0x06, 0xFF, 0xFF},	/* pe2, 6.0 db */
+	{0x03, 0xFF, 0xFF, 0xFF}	/* pe3, 9.5 db */
+};
+
+/* voltage swing, 0.2v and 1.0v are not support */
+static const u8 vm_voltage_swing[4][4] = {
+	{0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v  */
+	{0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */
+	{0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */
+	{0x1E, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
+};
+
+static int edp_voltage_pre_emphasise_set(struct edp_ctrl *ctrl)
+{
+	u32 value0;
+	u32 value1;
+
+	DBG("v=%d p=%d", ctrl->v_level, ctrl->p_level);
+
+	value0 = vm_pre_emphasis[(int)(ctrl->v_level)][(int)(ctrl->p_level)];
+	value1 = vm_voltage_swing[(int)(ctrl->v_level)][(int)(ctrl->p_level)];
+
+	/* Configure host and panel only if both values are allowed */
+	if (value0 != 0xFF && value1 != 0xFF) {
+		msm_edp_phy_vm_pe_cfg(ctrl->phy, value0, value1);
+		return edp_lane_set_write(ctrl, ctrl->v_level, ctrl->p_level);
+	}
+
+	return -EINVAL;
+}
+
+static int edp_start_link_train_1(struct edp_ctrl *ctrl)
+{
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	u8 old_v_level;
+	int tries;
+	int ret;
+	int rlen;
+
+	DBG("");
+
+	edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1);
+	ret = edp_voltage_pre_emphasise_set(ctrl);
+	if (ret)
+		return ret;
+	ret = edp_train_pattern_set_write(ctrl,
+			DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN);
+	if (ret)
+		return ret;
+
+	tries = 0;
+	old_v_level = ctrl->v_level;
+	while (1) {
+		drm_dp_link_train_clock_recovery_delay(ctrl->dpcd);
+
+		rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			pr_err("%s: read link status failed\n", __func__);
+			return -ENOLINK;
+		}
+		if (drm_dp_clock_recovery_ok(link_status, ctrl->lane_cnt)) {
+			ret = 0;
+			break;
+		}
+
+		if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) {
+			ret = -1;
+			break;
+		}
+
+		if (old_v_level == ctrl->v_level) {
+			tries++;
+			if (tries >= 5) {
+				ret = -1;
+				break;
+			}
+		} else {
+			tries = 0;
+			old_v_level = ctrl->v_level;
+		}
+
+		edp_sink_train_set_adjust(ctrl, link_status);
+		ret = edp_voltage_pre_emphasise_set(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int edp_start_link_train_2(struct edp_ctrl *ctrl)
+{
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	int tries = 0;
+	int ret;
+	int rlen;
+
+	DBG("");
+
+	edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2);
+	ret = edp_voltage_pre_emphasise_set(ctrl);
+	if (ret)
+		return ret;
+
+	ret = edp_train_pattern_set_write(ctrl,
+			DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN);
+	if (ret)
+		return ret;
+
+	while (1) {
+		drm_dp_link_train_channel_eq_delay(ctrl->dpcd);
+
+		rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			pr_err("%s: read link status failed\n", __func__);
+			return -ENOLINK;
+		}
+		if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) {
+			ret = 0;
+			break;
+		}
+
+		tries++;
+		if (tries > 10) {
+			ret = -1;
+			break;
+		}
+
+		edp_sink_train_set_adjust(ctrl, link_status);
+		ret = edp_voltage_pre_emphasise_set(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int edp_link_rate_down_shift(struct edp_ctrl *ctrl)
+{
+	u32 prate, lrate, bpp;
+	u8 rate, lane, max_lane;
+	int changed = 0;
+
+	rate = ctrl->link_rate;
+	lane = ctrl->lane_cnt;
+	max_lane = ctrl->dp_link.num_lanes;
+
+	bpp = ctrl->color_depth * 3;
+	prate = ctrl->pixel_rate;
+	prate *= bpp;
+	prate /= 8; /* in kByte */
+
+	if (rate > DP_LINK_BW_1_62 && rate <= EDP_LINK_BW_MAX) {
+		rate -= 4;	/* reduce rate */
+		changed++;
+	}
+
+	if (changed) {
+		if (lane >= 1 && lane < max_lane)
+			lane <<= 1;	/* increase lane */
+
+		lrate = 270000; /* in kHz */
+		lrate *= rate;
+		lrate /= 10; /* kByte, 10 bits --> 8 bits */
+		lrate *= lane;
+
+		DBG("new lrate=%u prate=%u(kHz) rate=%d lane=%d p=%u b=%d",
+			lrate, prate, rate, lane,
+			ctrl->pixel_rate,
+			bpp);
+
+		if (lrate > prate) {
+			ctrl->link_rate = rate;
+			ctrl->lane_cnt = lane;
+			DBG("new rate=%d %d", rate, lane);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int edp_clear_training_pattern(struct edp_ctrl *ctrl)
+{
+	int ret;
+
+	ret = edp_train_pattern_set_write(ctrl, 0);
+
+	drm_dp_link_train_channel_eq_delay(ctrl->dpcd);
+
+	return ret;
+}
+
+static int edp_do_link_train(struct edp_ctrl *ctrl)
+{
+	int ret;
+	struct drm_dp_link dp_link;
+
+	DBG("");
+	/*
+	 * Set the current link rate and lane cnt to panel. They may have been
+	 * adjusted and the values are different from them in DPCD CAP
+	 */
+	dp_link.num_lanes = ctrl->lane_cnt;
+	dp_link.rate = drm_dp_bw_code_to_link_rate(ctrl->link_rate);
+	dp_link.capabilities = ctrl->dp_link.capabilities;
+	if (drm_dp_link_configure(ctrl->drm_aux, &dp_link) < 0)
+		return EDP_TRAIN_FAIL;
+
+	ctrl->v_level = 0; /* start from default level */
+	ctrl->p_level = 0;
+
+	edp_state_ctrl(ctrl, 0);
+	if (edp_clear_training_pattern(ctrl))
+		return EDP_TRAIN_FAIL;
+
+	ret = edp_start_link_train_1(ctrl);
+	if (ret < 0) {
+		if (edp_link_rate_down_shift(ctrl) == 0) {
+			DBG("link reconfig");
+			ret = EDP_TRAIN_RECONFIG;
+			goto clear;
+		} else {
+			pr_err("%s: Training 1 failed", __func__);
+			ret = EDP_TRAIN_FAIL;
+			goto clear;
+		}
+	}
+	DBG("Training 1 completed successfully");
+
+	edp_state_ctrl(ctrl, 0);
+	if (edp_clear_training_pattern(ctrl))
+		return EDP_TRAIN_FAIL;
+
+	ret = edp_start_link_train_2(ctrl);
+	if (ret < 0) {
+		if (edp_link_rate_down_shift(ctrl) == 0) {
+			DBG("link reconfig");
+			ret = EDP_TRAIN_RECONFIG;
+			goto clear;
+		} else {
+			pr_err("%s: Training 2 failed", __func__);
+			ret = EDP_TRAIN_FAIL;
+			goto clear;
+		}
+	}
+	DBG("Training 2 completed successfully");
+
+	edp_state_ctrl(ctrl, EDP_STATE_CTRL_SEND_VIDEO);
+clear:
+	edp_clear_training_pattern(ctrl);
+
+	return ret;
+}
+
+static void edp_clock_synchrous(struct edp_ctrl *ctrl, int sync)
+{
+	u32 data;
+	enum edp_color_depth depth;
+
+	data = edp_read(ctrl->base + REG_EDP_MISC1_MISC0);
+
+	if (sync)
+		data |= EDP_MISC1_MISC0_SYNC;
+	else
+		data &= ~EDP_MISC1_MISC0_SYNC;
+
+	/* only legacy rgb mode supported */
+	depth = EDP_6BIT; /* Default */
+	if (ctrl->color_depth == 8)
+		depth = EDP_8BIT;
+	else if (ctrl->color_depth == 10)
+		depth = EDP_10BIT;
+	else if (ctrl->color_depth == 12)
+		depth = EDP_12BIT;
+	else if (ctrl->color_depth == 16)
+		depth = EDP_16BIT;
+
+	data |= EDP_MISC1_MISC0_COLOR(depth);
+
+	edp_write(ctrl->base + REG_EDP_MISC1_MISC0, data);
+}
+
+static int edp_sw_mvid_nvid(struct edp_ctrl *ctrl, u32 m, u32 n)
+{
+	u32 n_multi, m_multi = 5;
+
+	if (ctrl->link_rate == DP_LINK_BW_1_62) {
+		n_multi = 1;
+	} else if (ctrl->link_rate == DP_LINK_BW_2_7) {
+		n_multi = 2;
+	} else {
+		pr_err("%s: Invalid link rate, %d\n", __func__,
+			ctrl->link_rate);
+		return -EINVAL;
+	}
+
+	edp_write(ctrl->base + REG_EDP_SOFTWARE_MVID, m * m_multi);
+	edp_write(ctrl->base + REG_EDP_SOFTWARE_NVID, n * n_multi);
+
+	return 0;
+}
+
+static void edp_mainlink_ctrl(struct edp_ctrl *ctrl, int enable)
+{
+	u32 data = 0;
+
+	edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, EDP_MAINLINK_CTRL_RESET);
+	/* Make sure fully reset */
+	wmb();
+	usleep_range(500, 1000);
+
+	if (enable)
+		data |= EDP_MAINLINK_CTRL_ENABLE;
+
+	edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, data);
+}
+
+static void edp_ctrl_phy_aux_enable(struct edp_ctrl *ctrl, int enable)
+{
+	if (enable) {
+		edp_regulator_enable(ctrl);
+		edp_clk_enable(ctrl, EDP_CLK_MASK_AUX_CHAN);
+		msm_edp_phy_ctrl(ctrl->phy, 1);
+		msm_edp_aux_ctrl(ctrl->aux, 1);
+		gpiod_set_value(ctrl->panel_en_gpio, 1);
+	} else {
+		gpiod_set_value(ctrl->panel_en_gpio, 0);
+		msm_edp_aux_ctrl(ctrl->aux, 0);
+		msm_edp_phy_ctrl(ctrl->phy, 0);
+		edp_clk_disable(ctrl, EDP_CLK_MASK_AUX_CHAN);
+		edp_regulator_disable(ctrl);
+	}
+}
+
+static void edp_ctrl_link_enable(struct edp_ctrl *ctrl, int enable)
+{
+	u32 m, n;
+
+	if (enable) {
+		/* Enable link channel clocks */
+		edp_clk_enable(ctrl, EDP_CLK_MASK_LINK_CHAN);
+
+		msm_edp_phy_lane_power_ctrl(ctrl->phy, true, ctrl->lane_cnt);
+
+		msm_edp_phy_vm_pe_init(ctrl->phy);
+
+		/* Make sure phy is programed */
+		wmb();
+		msm_edp_phy_ready(ctrl->phy);
+
+		edp_config_ctrl(ctrl);
+		msm_edp_ctrl_pixel_clock_valid(ctrl, ctrl->pixel_rate, &m, &n);
+		edp_sw_mvid_nvid(ctrl, m, n);
+		edp_mainlink_ctrl(ctrl, 1);
+	} else {
+		edp_mainlink_ctrl(ctrl, 0);
+
+		msm_edp_phy_lane_power_ctrl(ctrl->phy, false, 0);
+		edp_clk_disable(ctrl, EDP_CLK_MASK_LINK_CHAN);
+	}
+}
+
+static int edp_ctrl_training(struct edp_ctrl *ctrl)
+{
+	int ret;
+
+	/* Do link training only when power is on */
+	if (!ctrl->power_on)
+		return -EINVAL;
+
+train_start:
+	ret = edp_do_link_train(ctrl);
+	if (ret == EDP_TRAIN_RECONFIG) {
+		/* Re-configure main link */
+		edp_ctrl_irq_enable(ctrl, 0);
+		edp_ctrl_link_enable(ctrl, 0);
+		msm_edp_phy_ctrl(ctrl->phy, 0);
+
+		/* Make sure link is fully disabled */
+		wmb();
+		usleep_range(500, 1000);
+
+		msm_edp_phy_ctrl(ctrl->phy, 1);
+		edp_ctrl_link_enable(ctrl, 1);
+		edp_ctrl_irq_enable(ctrl, 1);
+		goto train_start;
+	}
+
+	return ret;
+}
+
+static void edp_ctrl_on_worker(struct work_struct *work)
+{
+	struct edp_ctrl *ctrl = container_of(
+				work, struct edp_ctrl, on_work);
+	int ret;
+
+	mutex_lock(&ctrl->dev_mutex);
+
+	if (ctrl->power_on) {
+		DBG("already on");
+		goto unlock_ret;
+	}
+
+	edp_ctrl_phy_aux_enable(ctrl, 1);
+	edp_ctrl_link_enable(ctrl, 1);
+
+	edp_ctrl_irq_enable(ctrl, 1);
+	ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link);
+	if (ret)
+		goto fail;
+
+	ctrl->power_on = true;
+
+	/* Start link training */
+	ret = edp_ctrl_training(ctrl);
+	if (ret != EDP_TRAIN_SUCCESS)
+		goto fail;
+
+	DBG("DONE");
+	goto unlock_ret;
+
+fail:
+	edp_ctrl_irq_enable(ctrl, 0);
+	edp_ctrl_link_enable(ctrl, 0);
+	edp_ctrl_phy_aux_enable(ctrl, 0);
+	ctrl->power_on = false;
+unlock_ret:
+	mutex_unlock(&ctrl->dev_mutex);
+}
+
+static void edp_ctrl_off_worker(struct work_struct *work)
+{
+	struct edp_ctrl *ctrl = container_of(
+				work, struct edp_ctrl, off_work);
+	int ret;
+
+	mutex_lock(&ctrl->dev_mutex);
+
+	if (!ctrl->power_on) {
+		DBG("already off");
+		goto unlock_ret;
+	}
+
+	reinit_completion(&ctrl->idle_comp);
+	edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE);
+
+	ret = wait_for_completion_timeout(&ctrl->idle_comp,
+						msecs_to_jiffies(500));
+	if (ret <= 0)
+		DBG("%s: idle pattern timedout, %d\n",
+				__func__, ret);
+
+	edp_state_ctrl(ctrl, 0);
+
+	drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link);
+
+	edp_ctrl_irq_enable(ctrl, 0);
+
+	edp_ctrl_link_enable(ctrl, 0);
+
+	edp_ctrl_phy_aux_enable(ctrl, 0);
+
+	ctrl->power_on = false;
+
+unlock_ret:
+	mutex_unlock(&ctrl->dev_mutex);
+}
+
+irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl)
+{
+	u32 isr1, isr2, mask1, mask2;
+	u32 ack;
+
+	DBG("");
+	spin_lock(&ctrl->irq_lock);
+	isr1 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_1);
+	isr2 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_2);
+
+	mask1 = isr1 & EDP_INTR_MASK1;
+	mask2 = isr2 & EDP_INTR_MASK2;
+
+	isr1 &= ~mask1;	/* remove masks bit */
+	isr2 &= ~mask2;
+
+	DBG("isr=%x mask=%x isr2=%x mask2=%x",
+			isr1, mask1, isr2, mask2);
+
+	ack = isr1 & EDP_INTR_STATUS1;
+	ack <<= 1;	/* ack bits */
+	ack |= mask1;
+	edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, ack);
+
+	ack = isr2 & EDP_INTR_STATUS2;
+	ack <<= 1;	/* ack bits */
+	ack |= mask2;
+	edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, ack);
+	spin_unlock(&ctrl->irq_lock);
+
+	if (isr1 & EDP_INTERRUPT_REG_1_HPD)
+		DBG("edp_hpd");
+
+	if (isr2 & EDP_INTERRUPT_REG_2_READY_FOR_VIDEO)
+		DBG("edp_video_ready");
+
+	if (isr2 & EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT) {
+		DBG("idle_patterns_sent");
+		complete(&ctrl->idle_comp);
+	}
+
+	msm_edp_aux_irq(ctrl->aux, isr1);
+
+	return IRQ_HANDLED;
+}
+
+void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on)
+{
+	if (on)
+		queue_work(ctrl->workqueue, &ctrl->on_work);
+	else
+		queue_work(ctrl->workqueue, &ctrl->off_work);
+}
+
+int msm_edp_ctrl_init(struct msm_edp *edp)
+{
+	struct edp_ctrl *ctrl = NULL;
+	struct device *dev = &edp->pdev->dev;
+	int ret;
+
+	if (!edp) {
+		pr_err("%s: edp is NULL!\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	edp->ctrl = ctrl;
+	ctrl->pdev = edp->pdev;
+
+	ctrl->base = msm_ioremap(ctrl->pdev, "edp", "eDP");
+	if (IS_ERR(ctrl->base))
+		return PTR_ERR(ctrl->base);
+
+	/* Get regulator, clock, gpio, pwm */
+	ret = edp_regulator_init(ctrl);
+	if (ret) {
+		pr_err("%s:regulator init fail\n", __func__);
+		return ret;
+	}
+	ret = edp_clk_init(ctrl);
+	if (ret) {
+		pr_err("%s:clk init fail\n", __func__);
+		return ret;
+	}
+	ret = edp_gpio_config(ctrl);
+	if (ret) {
+		pr_err("%s:failed to configure GPIOs: %d", __func__, ret);
+		return ret;
+	}
+
+	/* Init aux and phy */
+	ctrl->aux = msm_edp_aux_init(dev, ctrl->base, &ctrl->drm_aux);
+	if (!ctrl->aux || !ctrl->drm_aux) {
+		pr_err("%s:failed to init aux\n", __func__);
+		return ret;
+	}
+
+	ctrl->phy = msm_edp_phy_init(dev, ctrl->base);
+	if (!ctrl->phy) {
+		pr_err("%s:failed to init phy\n", __func__);
+		goto err_destory_aux;
+	}
+
+	spin_lock_init(&ctrl->irq_lock);
+	mutex_init(&ctrl->dev_mutex);
+	init_completion(&ctrl->idle_comp);
+
+	/* setup workqueue */
+	ctrl->workqueue = alloc_ordered_workqueue("edp_drm_work", 0);
+	INIT_WORK(&ctrl->on_work, edp_ctrl_on_worker);
+	INIT_WORK(&ctrl->off_work, edp_ctrl_off_worker);
+
+	return 0;
+
+err_destory_aux:
+	msm_edp_aux_destroy(dev, ctrl->aux);
+	ctrl->aux = NULL;
+	return ret;
+}
+
+void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl)
+{
+	if (!ctrl)
+		return;
+
+	if (ctrl->workqueue) {
+		flush_workqueue(ctrl->workqueue);
+		destroy_workqueue(ctrl->workqueue);
+		ctrl->workqueue = NULL;
+	}
+
+	if (ctrl->aux) {
+		msm_edp_aux_destroy(&ctrl->pdev->dev, ctrl->aux);
+		ctrl->aux = NULL;
+	}
+
+	kfree(ctrl->edid);
+	ctrl->edid = NULL;
+
+	mutex_destroy(&ctrl->dev_mutex);
+}
+
+bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl)
+{
+	mutex_lock(&ctrl->dev_mutex);
+	DBG("connect status = %d", ctrl->edp_connected);
+	if (ctrl->edp_connected) {
+		mutex_unlock(&ctrl->dev_mutex);
+		return true;
+	}
+
+	if (!ctrl->power_on) {
+		edp_ctrl_phy_aux_enable(ctrl, 1);
+		edp_ctrl_irq_enable(ctrl, 1);
+	}
+
+	if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd,
+				DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) {
+		pr_err("%s: AUX channel is NOT ready\n", __func__);
+		memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE);
+	} else {
+		ctrl->edp_connected = true;
+	}
+
+	if (!ctrl->power_on) {
+		edp_ctrl_irq_enable(ctrl, 0);
+		edp_ctrl_phy_aux_enable(ctrl, 0);
+	}
+
+	DBG("exit: connect status=%d", ctrl->edp_connected);
+
+	mutex_unlock(&ctrl->dev_mutex);
+
+	return ctrl->edp_connected;
+}
+
+int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl,
+		struct drm_connector *connector, struct edid **edid)
+{
+	int ret = 0;
+
+	mutex_lock(&ctrl->dev_mutex);
+
+	if (ctrl->edid) {
+		if (edid) {
+			DBG("Just return edid buffer");
+			*edid = ctrl->edid;
+		}
+		goto unlock_ret;
+	}
+
+	if (!ctrl->power_on) {
+		edp_ctrl_phy_aux_enable(ctrl, 1);
+		edp_ctrl_irq_enable(ctrl, 1);
+	}
+
+	ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link);
+	if (ret) {
+		pr_err("%s: read dpcd cap failed, %d\n", __func__, ret);
+		goto disable_ret;
+	}
+
+	/* Initialize link rate as panel max link rate */
+	ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate);
+
+	ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc);
+	if (!ctrl->edid) {
+		pr_err("%s: edid read fail\n", __func__);
+		goto disable_ret;
+	}
+
+	if (edid)
+		*edid = ctrl->edid;
+
+disable_ret:
+	if (!ctrl->power_on) {
+		edp_ctrl_irq_enable(ctrl, 0);
+		edp_ctrl_phy_aux_enable(ctrl, 0);
+	}
+unlock_ret:
+	mutex_unlock(&ctrl->dev_mutex);
+	return ret;
+}
+
+int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl,
+				const struct drm_display_mode *mode,
+				const struct drm_display_info *info)
+{
+	u32 hstart_from_sync, vstart_from_sync;
+	u32 data;
+	int ret = 0;
+
+	mutex_lock(&ctrl->dev_mutex);
+	/*
+	 * Need to keep color depth, pixel rate and
+	 * interlaced information in ctrl context
+	 */
+	ctrl->color_depth = info->bpc;
+	ctrl->pixel_rate = mode->clock;
+	ctrl->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+
+	/* Fill initial link config based on passed in timing */
+	edp_fill_link_cfg(ctrl);
+
+	if (edp_clk_enable(ctrl, EDP_CLK_MASK_AHB)) {
+		pr_err("%s, fail to prepare enable ahb clk\n", __func__);
+		ret = -EINVAL;
+		goto unlock_ret;
+	}
+	edp_clock_synchrous(ctrl, 1);
+
+	/* Configure eDP timing to HW */
+	edp_write(ctrl->base + REG_EDP_TOTAL_HOR_VER,
+		EDP_TOTAL_HOR_VER_HORIZ(mode->htotal) |
+		EDP_TOTAL_HOR_VER_VERT(mode->vtotal));
+
+	vstart_from_sync = mode->vtotal - mode->vsync_start;
+	hstart_from_sync = mode->htotal - mode->hsync_start;
+	edp_write(ctrl->base + REG_EDP_START_HOR_VER_FROM_SYNC,
+		EDP_START_HOR_VER_FROM_SYNC_HORIZ(hstart_from_sync) |
+		EDP_START_HOR_VER_FROM_SYNC_VERT(vstart_from_sync));
+
+	data = EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT(
+			mode->vsync_end - mode->vsync_start);
+	data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ(
+			mode->hsync_end - mode->hsync_start);
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC;
+	edp_write(ctrl->base + REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY, data);
+
+	edp_write(ctrl->base + REG_EDP_ACTIVE_HOR_VER,
+		EDP_ACTIVE_HOR_VER_HORIZ(mode->hdisplay) |
+		EDP_ACTIVE_HOR_VER_VERT(mode->vdisplay));
+
+	edp_clk_disable(ctrl, EDP_CLK_MASK_AHB);
+
+unlock_ret:
+	mutex_unlock(&ctrl->dev_mutex);
+	return ret;
+}
+
+bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl,
+	u32 pixel_rate, u32 *pm, u32 *pn)
+{
+	const struct edp_pixel_clk_div *divs;
+	u32 err = 1; /* 1% error tolerance */
+	u32 clk_err;
+	int i;
+
+	if (ctrl->link_rate == DP_LINK_BW_1_62) {
+		divs = clk_divs[0];
+	} else if (ctrl->link_rate == DP_LINK_BW_2_7) {
+		divs = clk_divs[1];
+	} else {
+		pr_err("%s: Invalid link rate,%d\n", __func__, ctrl->link_rate);
+		return false;
+	}
+
+	for (i = 0; i < EDP_PIXEL_CLK_NUM; i++) {
+		clk_err = abs(divs[i].rate - pixel_rate);
+		if ((divs[i].rate * err / 100) >= clk_err) {
+			if (pm)
+				*pm = divs[i].m;
+			if (pn)
+				*pn = divs[i].n;
+			return true;
+		}
+	}
+
+	DBG("pixel clock %d(kHz) not supported", pixel_rate);
+
+	return false;
+}
+
diff --git a/drivers/gpu/drm/msm/edp/edp_phy.c b/drivers/gpu/drm/msm/edp/edp_phy.c
new file mode 100644
index 0000000..36bb893
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_phy.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "edp.h"
+#include "edp.xml.h"
+
+#define EDP_MAX_LANE	4
+
+struct edp_phy {
+	void __iomem *base;
+};
+
+bool msm_edp_phy_ready(struct edp_phy *phy)
+{
+	u32 status;
+	int cnt = 100;
+
+	while (--cnt) {
+		status = edp_read(phy->base +
+				REG_EDP_PHY_GLB_PHY_STATUS);
+		if (status & 0x01)
+			break;
+		usleep_range(500, 1000);
+	}
+
+	if (cnt == 0) {
+		pr_err("%s: PHY NOT ready\n", __func__);
+		return false;
+	} else {
+		return true;
+	}
+}
+
+void msm_edp_phy_ctrl(struct edp_phy *phy, int enable)
+{
+	DBG("enable=%d", enable);
+	if (enable) {
+		/* Reset */
+		edp_write(phy->base + REG_EDP_PHY_CTRL,
+			EDP_PHY_CTRL_SW_RESET | EDP_PHY_CTRL_SW_RESET_PLL);
+		/* Make sure fully reset */
+		wmb();
+		usleep_range(500, 1000);
+		edp_write(phy->base + REG_EDP_PHY_CTRL, 0x000);
+		edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0x3f);
+		edp_write(phy->base + REG_EDP_PHY_GLB_CFG, 0x1);
+	} else {
+		edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0xc0);
+	}
+}
+
+/* voltage mode and pre emphasis cfg */
+void msm_edp_phy_vm_pe_init(struct edp_phy *phy)
+{
+	edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, 0x3);
+	edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, 0x64);
+	edp_write(phy->base + REG_EDP_PHY_GLB_MISC9, 0x6c);
+}
+
+void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1)
+{
+	edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, v0);
+	edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, v1);
+}
+
+void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane)
+{
+	u32 i;
+	u32 data;
+
+	if (up)
+		data = 0;	/* power up */
+	else
+		data = 0x7;	/* power down */
+
+	for (i = 0; i < max_lane; i++)
+		edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
+
+	/* power down unused lane */
+	data = 0x7;	/* power down */
+	for (i = max_lane; i < EDP_MAX_LANE; i++)
+		edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
+}
+
+void *msm_edp_phy_init(struct device *dev, void __iomem *regbase)
+{
+	struct edp_phy *phy = NULL;
+
+	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy)
+		return NULL;
+
+	phy->base = regbase;
+	return phy;
+}
+
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 062c687..8145362 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -106,7 +107,12 @@
 		goto fail;
 	}
 
-	BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs));
+	hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
+			config->hpd_reg_cnt, GFP_KERNEL);
+	if (!hdmi->hpd_regs) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 	for (i = 0; i < config->hpd_reg_cnt; i++) {
 		struct regulator *reg;
 
@@ -122,7 +128,12 @@
 		hdmi->hpd_regs[i] = reg;
 	}
 
-	BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs));
+	hdmi->pwr_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_regs[0]) *
+			config->pwr_reg_cnt, GFP_KERNEL);
+	if (!hdmi->pwr_regs) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 	for (i = 0; i < config->pwr_reg_cnt; i++) {
 		struct regulator *reg;
 
@@ -138,7 +149,12 @@
 		hdmi->pwr_regs[i] = reg;
 	}
 
-	BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks));
+	hdmi->hpd_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_clks[0]) *
+			config->hpd_clk_cnt, GFP_KERNEL);
+	if (!hdmi->hpd_clks) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 	for (i = 0; i < config->hpd_clk_cnt; i++) {
 		struct clk *clk;
 
@@ -153,7 +169,12 @@
 		hdmi->hpd_clks[i] = clk;
 	}
 
-	BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks));
+	hdmi->pwr_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_clks[0]) *
+			config->pwr_clk_cnt, GFP_KERNEL);
+	if (!hdmi->pwr_clks) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 	for (i = 0; i < config->pwr_clk_cnt; i++) {
 		struct clk *clk;
 
@@ -247,9 +268,9 @@
 	return 0;
 
 fail:
-	/* bridge/connector are normally destroyed by drm: */
+	/* bridge is normally destroyed by drm: */
 	if (hdmi->bridge) {
-		hdmi->bridge->funcs->destroy(hdmi->bridge);
+		hdmi_bridge_destroy(hdmi->bridge);
 		hdmi->bridge = NULL;
 	}
 	if (hdmi->connector) {
@@ -266,6 +287,57 @@
 
 #include <linux/of_gpio.h>
 
+#define HDMI_CFG(item, entry) \
+	.item ## _names = item ##_names_ ## entry, \
+	.item ## _cnt   = ARRAY_SIZE(item ## _names_ ## entry)
+
+static struct hdmi_platform_config hdmi_tx_8660_config = {
+		.phy_init = hdmi_phy_8x60_init,
+};
+
+static const char *hpd_reg_names_8960[] = {"core-vdda", "hdmi-mux"};
+static const char *hpd_clk_names_8960[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
+
+static struct hdmi_platform_config hdmi_tx_8960_config = {
+		.phy_init = hdmi_phy_8960_init,
+		HDMI_CFG(hpd_reg, 8960),
+		HDMI_CFG(hpd_clk, 8960),
+};
+
+static const char *pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"};
+static const char *hpd_reg_names_8x74[] = {"hpd-gdsc", "hpd-5v"};
+static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"};
+static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"};
+static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
+
+static struct hdmi_platform_config hdmi_tx_8074_config = {
+		.phy_init = hdmi_phy_8x74_init,
+		HDMI_CFG(pwr_reg, 8x74),
+		HDMI_CFG(hpd_reg, 8x74),
+		HDMI_CFG(pwr_clk, 8x74),
+		HDMI_CFG(hpd_clk, 8x74),
+		.hpd_freq      = hpd_clk_freq_8x74,
+};
+
+static const char *hpd_reg_names_8084[] = {"hpd-gdsc", "hpd-5v", "hpd-5v-en"};
+
+static struct hdmi_platform_config hdmi_tx_8084_config = {
+		.phy_init = hdmi_phy_8x74_init,
+		HDMI_CFG(pwr_reg, 8x74),
+		HDMI_CFG(hpd_reg, 8084),
+		HDMI_CFG(pwr_clk, 8x74),
+		HDMI_CFG(hpd_clk, 8x74),
+		.hpd_freq      = hpd_clk_freq_8x74,
+};
+
+static const struct of_device_id dt_match[] = {
+	{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
+	{ .compatible = "qcom,hdmi-tx-8074", .data = &hdmi_tx_8074_config },
+	{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
+	{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
+	{}
+};
+
 #ifdef CONFIG_OF
 static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
 {
@@ -288,50 +360,31 @@
 {
 	struct drm_device *drm = dev_get_drvdata(master);
 	struct msm_drm_private *priv = drm->dev_private;
-	static struct hdmi_platform_config config = {};
+	static struct hdmi_platform_config *hdmi_cfg;
 	struct hdmi *hdmi;
 #ifdef CONFIG_OF
 	struct device_node *of_node = dev->of_node;
+	const struct of_device_id *match;
 
-	if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) {
-		static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
-		static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
-		static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
-		static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
-		static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
-		config.phy_init      = hdmi_phy_8x74_init;
-		config.hpd_reg_names = hpd_reg_names;
-		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
-		config.pwr_reg_names = pwr_reg_names;
-		config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names);
-		config.hpd_clk_names = hpd_clk_names;
-		config.hpd_freq      = hpd_clk_freq;
-		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
-		config.pwr_clk_names = pwr_clk_names;
-		config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
-	} else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) {
-		static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
-		static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"};
-		config.phy_init      = hdmi_phy_8960_init;
-		config.hpd_reg_names = hpd_reg_names;
-		config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
-		config.hpd_clk_names = hpd_clk_names;
-		config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
-	} else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) {
-		config.phy_init      = hdmi_phy_8x60_init;
+	match = of_match_node(dt_match, of_node);
+	if (match && match->data) {
+		hdmi_cfg = (struct hdmi_platform_config *)match->data;
+		DBG("hdmi phy: %s", match->compatible);
 	} else {
 		dev_err(dev, "unknown phy: %s\n", of_node->name);
+		return -ENXIO;
 	}
 
-	config.mmio_name     = "core_physical";
-	config.ddc_clk_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
-	config.ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
-	config.hpd_gpio      = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
-	config.mux_en_gpio   = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en");
-	config.mux_sel_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
-	config.mux_lpm_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
+	hdmi_cfg->mmio_name     = "core_physical";
+	hdmi_cfg->ddc_clk_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
+	hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
+	hdmi_cfg->hpd_gpio      = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
+	hdmi_cfg->mux_en_gpio   = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en");
+	hdmi_cfg->mux_sel_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
+	hdmi_cfg->mux_lpm_gpio  = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
 
 #else
+	static struct hdmi_platform_config config = {};
 	static const char *hpd_clk_names[] = {
 			"core_clk", "master_iface_clk", "slave_iface_clk",
 	};
@@ -377,12 +430,15 @@
 		config.mux_en_gpio   = -1;
 		config.mux_sel_gpio  = -1;
 	}
+	hdmi_cfg = &config;
 #endif
-	dev->platform_data = &config;
+	dev->platform_data = hdmi_cfg;
+
 	hdmi = hdmi_init(to_platform_device(dev));
 	if (IS_ERR(hdmi))
 		return PTR_ERR(hdmi);
 	priv->hdmi = hdmi;
+
 	return 0;
 }
 
@@ -413,13 +469,6 @@
 	return 0;
 }
 
-static const struct of_device_id dt_match[] = {
-	{ .compatible = "qcom,hdmi-tx-8074" },
-	{ .compatible = "qcom,hdmi-tx-8960" },
-	{ .compatible = "qcom,hdmi-tx-8660" },
-	{}
-};
-
 static struct platform_driver hdmi_driver = {
 	.probe = hdmi_dev_probe,
 	.remove = hdmi_dev_remove,
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 43e654f..68fdfb3 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -52,10 +52,10 @@
 
 	void __iomem *mmio;
 
-	struct regulator *hpd_regs[2];
-	struct regulator *pwr_regs[2];
-	struct clk *hpd_clks[3];
-	struct clk *pwr_clks[2];
+	struct regulator **hpd_regs;
+	struct regulator **pwr_regs;
+	struct clk **hpd_clks;
+	struct clk **pwr_clks;
 
 	struct hdmi_phy *phy;
 	struct i2c_adapter *i2c;
@@ -146,6 +146,7 @@
  */
 
 struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
+void hdmi_bridge_destroy(struct drm_bridge *bridge);
 
 /*
  * hdmi connector:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
index 5b0844b..3509887 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
@@ -8,18 +8,19 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
-Copyright (C) 2013-2014 by the following authors:
+Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -45,12 +46,14 @@
 
 
 enum hdmi_hdcp_key_state {
-	NO_KEYS = 0,
-	NOT_CHECKED = 1,
-	CHECKING = 2,
-	KEYS_VALID = 3,
-	AKSV_INVALID = 4,
-	CHECKSUM_MISMATCH = 5,
+	HDCP_KEYS_STATE_NO_KEYS = 0,
+	HDCP_KEYS_STATE_NOT_CHECKED = 1,
+	HDCP_KEYS_STATE_CHECKING = 2,
+	HDCP_KEYS_STATE_VALID = 3,
+	HDCP_KEYS_STATE_AKSV_NOT_VALID = 4,
+	HDCP_KEYS_STATE_CHKSUM_MISMATCH = 5,
+	HDCP_KEYS_STATE_PROD_AKSV = 6,
+	HDCP_KEYS_STATE_RESERVED = 7,
 };
 
 enum hdmi_ddc_read_write {
@@ -199,11 +202,29 @@
 #define HDMI_HDCP_CTRL_ENABLE					0x00000001
 #define HDMI_HDCP_CTRL_ENCRYPTION_ENABLE			0x00000100
 
+#define REG_HDMI_HDCP_DEBUG_CTRL				0x00000114
+#define HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER				0x00000004
+
 #define REG_HDMI_HDCP_INT_CTRL					0x00000118
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT			0x00000001
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_ACK			0x00000002
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_MASK			0x00000004
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT			0x00000010
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_ACK			0x00000020
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_MASK			0x00000040
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK			0x00000080
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_INT			0x00000100
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_ACK			0x00000200
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_MASK			0x00000400
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_INT			0x00001000
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_ACK			0x00002000
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_MASK			0x00004000
 
 #define REG_HDMI_HDCP_LINK0_STATUS				0x0000011c
 #define HDMI_HDCP_LINK0_STATUS_AN_0_READY			0x00000100
 #define HDMI_HDCP_LINK0_STATUS_AN_1_READY			0x00000200
+#define HDMI_HDCP_LINK0_STATUS_RI_MATCHES			0x00001000
+#define HDMI_HDCP_LINK0_STATUS_V_MATCHES			0x00100000
 #define HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK			0x70000000
 #define HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT			28
 static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state val)
@@ -211,9 +232,56 @@
 	return ((val) << HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT) & HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK;
 }
 
+#define REG_HDMI_HDCP_DDC_CTRL_0				0x00000120
+#define HDMI_HDCP_DDC_CTRL_0_DISABLE				0x00000001
+
+#define REG_HDMI_HDCP_DDC_CTRL_1				0x00000124
+#define HDMI_HDCP_DDC_CTRL_1_FAILED_ACK				0x00000001
+
+#define REG_HDMI_HDCP_DDC_STATUS				0x00000128
+#define HDMI_HDCP_DDC_STATUS_XFER_REQ				0x00000010
+#define HDMI_HDCP_DDC_STATUS_XFER_DONE				0x00000400
+#define HDMI_HDCP_DDC_STATUS_ABORTED				0x00001000
+#define HDMI_HDCP_DDC_STATUS_TIMEOUT				0x00002000
+#define HDMI_HDCP_DDC_STATUS_NACK0				0x00004000
+#define HDMI_HDCP_DDC_STATUS_NACK1				0x00008000
+#define HDMI_HDCP_DDC_STATUS_FAILED				0x00010000
+
+#define REG_HDMI_HDCP_ENTROPY_CTRL0				0x0000012c
+
+#define REG_HDMI_HDCP_ENTROPY_CTRL1				0x0000025c
+
 #define REG_HDMI_HDCP_RESET					0x00000130
 #define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE			0x00000001
 
+#define REG_HDMI_HDCP_RCVPORT_DATA0				0x00000134
+
+#define REG_HDMI_HDCP_RCVPORT_DATA1				0x00000138
+
+#define REG_HDMI_HDCP_RCVPORT_DATA2_0				0x0000013c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA2_1				0x00000140
+
+#define REG_HDMI_HDCP_RCVPORT_DATA3				0x00000144
+
+#define REG_HDMI_HDCP_RCVPORT_DATA4				0x00000148
+
+#define REG_HDMI_HDCP_RCVPORT_DATA5				0x0000014c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA6				0x00000150
+
+#define REG_HDMI_HDCP_RCVPORT_DATA7				0x00000154
+
+#define REG_HDMI_HDCP_RCVPORT_DATA8				0x00000158
+
+#define REG_HDMI_HDCP_RCVPORT_DATA9				0x0000015c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA10				0x00000160
+
+#define REG_HDMI_HDCP_RCVPORT_DATA11				0x00000164
+
+#define REG_HDMI_HDCP_RCVPORT_DATA12				0x00000168
+
 #define REG_HDMI_VENSPEC_INFO0					0x0000016c
 
 #define REG_HDMI_VENSPEC_INFO1					0x00000170
@@ -266,6 +334,7 @@
 #define HDMI_DDC_SW_STATUS_NACK3				0x00008000
 
 #define REG_HDMI_DDC_HW_STATUS					0x0000021c
+#define HDMI_DDC_HW_STATUS_DONE					0x00000008
 
 #define REG_HDMI_DDC_SPEED					0x00000220
 #define HDMI_DDC_SPEED_THRESHOLD__MASK				0x00000003
@@ -329,6 +398,15 @@
 }
 #define HDMI_DDC_DATA_INDEX_WRITE				0x80000000
 
+#define REG_HDMI_HDCP_SHA_CTRL					0x0000023c
+
+#define REG_HDMI_HDCP_SHA_STATUS				0x00000240
+#define HDMI_HDCP_SHA_STATUS_BLOCK_DONE				0x00000001
+#define HDMI_HDCP_SHA_STATUS_COMP_DONE				0x00000010
+
+#define REG_HDMI_HDCP_SHA_DATA					0x00000244
+#define HDMI_HDCP_SHA_DATA_DONE					0x00000001
+
 #define REG_HDMI_HPD_INT_STATUS					0x00000250
 #define HDMI_HPD_INT_STATUS_INT					0x00000001
 #define HDMI_HPD_INT_STATUS_CABLE_DETECTED			0x00000002
@@ -359,6 +437,10 @@
 	return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK;
 }
 
+#define REG_HDMI_HDCP_SW_UPPER_AKSV				0x00000284
+
+#define REG_HDMI_HDCP_SW_LOWER_AKSV				0x00000288
+
 #define REG_HDMI_CEC_STATUS					0x00000298
 
 #define REG_HDMI_CEC_INT					0x0000029c
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 6902ad6..a7a1d82 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -23,11 +23,8 @@
 };
 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
 
-static void hdmi_bridge_destroy(struct drm_bridge *bridge)
+void hdmi_bridge_destroy(struct drm_bridge *bridge)
 {
-	struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
-	drm_bridge_cleanup(bridge);
-	kfree(hdmi_bridge);
 }
 
 static void power_on(struct drm_bridge *bridge)
@@ -200,7 +197,6 @@
 		.disable = hdmi_bridge_disable,
 		.post_disable = hdmi_bridge_post_disable,
 		.mode_set = hdmi_bridge_mode_set,
-		.destroy = hdmi_bridge_destroy,
 };
 
 
@@ -211,7 +207,8 @@
 	struct hdmi_bridge *hdmi_bridge;
 	int ret;
 
-	hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
+	hdmi_bridge = devm_kzalloc(hdmi->dev->dev,
+			sizeof(*hdmi_bridge), GFP_KERNEL);
 	if (!hdmi_bridge) {
 		ret = -ENOMEM;
 		goto fail;
@@ -220,8 +217,11 @@
 	hdmi_bridge->hdmi = hdmi;
 
 	bridge = &hdmi_bridge->base;
+	bridge->funcs = &hdmi_bridge_funcs;
 
-	drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
+	ret = drm_bridge_attach(hdmi->dev, bridge);
+	if (ret)
+		goto fail;
 
 	return bridge;
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index b4e70e0..b62cdb9 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -386,7 +386,7 @@
 }
 
 static const struct drm_connector_funcs hdmi_connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
+	.dpms = drm_atomic_helper_connector_dpms,
 	.detect = hdmi_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = hdmi_connector_destroy,
@@ -426,7 +426,7 @@
 	connector->polled = DRM_CONNECTOR_POLL_CONNECT |
 			DRM_CONNECTOR_POLL_DISCONNECT;
 
-	connector->interlace_allowed = 1;
+	connector->interlace_allowed = 0;
 	connector->doublescan_allowed = 0;
 
 	drm_connector_register(connector);
diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
index 29bd796..43bb54a 100644
--- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
@@ -8,16 +8,17 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
index a4a7f8c..1d39174 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
@@ -8,16 +8,17 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
 Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -72,6 +73,18 @@
 	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,
@@ -637,6 +650,8 @@
 
 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
@@ -720,7 +735,25 @@
 }
 #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
@@ -751,6 +784,18 @@
 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
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 3449213..73afa21 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -140,26 +140,6 @@
 	kfree(mdp4_crtc);
 }
 
-static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-	struct mdp4_kms *mdp4_kms = get_kms(crtc);
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-
-	DBG("%s: mode=%d", mdp4_crtc->name, mode);
-
-	if (enabled != mdp4_crtc->enabled) {
-		if (enabled) {
-			mdp4_enable(mdp4_kms);
-			mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
-		} else {
-			mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
-			mdp4_disable(mdp4_kms);
-		}
-		mdp4_crtc->enabled = enabled;
-	}
-}
-
 static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
@@ -304,27 +284,38 @@
 	}
 }
 
-static void mdp4_crtc_prepare(struct drm_crtc *crtc)
+static void mdp4_crtc_disable(struct drm_crtc *crtc)
 {
 	struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+	struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
 	DBG("%s", mdp4_crtc->name);
-	/* make sure we hold a ref to mdp clks while setting up mode: */
-	drm_crtc_vblank_get(crtc);
-	mdp4_enable(get_kms(crtc));
-	mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	if (WARN_ON(!mdp4_crtc->enabled))
+		return;
+
+	mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
+	mdp4_disable(mdp4_kms);
+
+	mdp4_crtc->enabled = false;
 }
 
-static void mdp4_crtc_commit(struct drm_crtc *crtc)
+static void mdp4_crtc_enable(struct drm_crtc *crtc)
 {
-	mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+	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);
+	mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
+
 	crtc_flush(crtc);
-	/* drop the ref to mdp clk's that we got in prepare: */
-	mdp4_disable(get_kms(crtc));
-	drm_crtc_vblank_put(crtc);
-}
 
-static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
-{
+	mdp4_crtc->enabled = true;
 }
 
 static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -508,14 +499,10 @@
 };
 
 static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
-	.dpms = mdp4_crtc_dpms,
 	.mode_fixup = mdp4_crtc_mode_fixup,
 	.mode_set_nofb = mdp4_crtc_mode_set_nofb,
-	.mode_set = drm_helper_crtc_mode_set,
-	.mode_set_base = drm_helper_crtc_mode_set_base,
-	.prepare = mdp4_crtc_prepare,
-	.commit = mdp4_crtc_commit,
-	.load_lut = mdp4_crtc_load_lut,
+	.disable = mdp4_crtc_disable,
+	.enable = mdp4_crtc_enable,
 	.atomic_check = mdp4_crtc_atomic_check,
 	.atomic_begin = mdp4_crtc_atomic_begin,
 	.atomic_flush = mdp4_crtc_atomic_flush,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
index c387842..7896323 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
@@ -94,61 +94,6 @@
 	.destroy = mdp4_dtv_encoder_destroy,
 };
 
-static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	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);
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-
-	DBG("mode=%d", mode);
-
-	if (enabled == mdp4_dtv_encoder->enabled)
-		return;
-
-	if (enabled) {
-		unsigned long pc = mdp4_dtv_encoder->pixclock;
-		int ret;
-
-		bs_set(mdp4_dtv_encoder, 1);
-
-		DBG("setting src_clk=%lu", pc);
-
-		ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
-		if (ret)
-			dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret);
-		clk_prepare_enable(mdp4_dtv_encoder->src_clk);
-		ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
-		if (ret)
-			dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
-		ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
-		if (ret)
-			dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
-
-		mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
-	} else {
-		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->src_clk);
-		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 = enabled;
-}
-
 static bool mdp4_dtv_encoder_mode_fixup(struct drm_encoder *encoder,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
@@ -221,28 +166,78 @@
 	mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
 }
 
-static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
+static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder)
 {
-	mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+	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->src_clk);
+	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_commit(struct drm_encoder *encoder)
+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);
-	mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+	bs_set(mdp4_dtv_encoder, 1);
+
+	DBG("setting src_clk=%lu", pc);
+
+	ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
+	if (ret)
+		dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret);
+	clk_prepare_enable(mdp4_dtv_encoder->src_clk);
+	ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
+	if (ret)
+		dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
+	ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
+	if (ret)
+		dev_err(dev->dev, "failed to enabled mdp_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 = {
-	.dpms = mdp4_dtv_encoder_dpms,
 	.mode_fixup = mdp4_dtv_encoder_mode_fixup,
 	.mode_set = mdp4_dtv_encoder_mode_set,
-	.prepare = mdp4_dtv_encoder_prepare,
-	.commit = mdp4_dtv_encoder_commit,
+	.enable = mdp4_dtv_encoder_enable,
+	.disable = mdp4_dtv_encoder_disable,
 };
 
 long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index a62109e4..d847b94 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -125,6 +125,38 @@
 	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, ncrtcs = state->dev->mode_config.num_crtc;
+
+	mdp4_enable(mdp4_kms);
+
+	/* see 119ecb7fd */
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+		if (!crtc)
+			continue;
+		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, ncrtcs = state->dev->mode_config.num_crtc;
+
+	/* see 119ecb7fd */
+	for (i = 0; i < ncrtcs; i++) {
+		struct drm_crtc *crtc = state->crtcs[i];
+		if (!crtc)
+			continue;
+		drm_crtc_vblank_put(crtc);
+	}
+
+	mdp4_disable(mdp4_kms);
+}
+
 static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
 		struct drm_encoder *encoder)
 {
@@ -161,6 +193,8 @@
 		.irq             = mdp4_irq,
 		.enable_vblank   = mdp4_enable_vblank,
 		.disable_vblank  = mdp4_disable_vblank,
+		.prepare_commit  = mdp4_prepare_commit,
+		.complete_commit = mdp4_complete_commit,
 		.get_format      = mdp_get_format,
 		.round_pixclk    = mdp4_round_pixclk,
 		.preclose        = mdp4_preclose,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
index cbd77bc..0a5c58b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
@@ -175,14 +175,25 @@
 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 bool pipe_supports_yuv(enum mdp4_pipe pipe)
+{
+	switch (pipe) {
+	case VG1:
+	case VG2:
+	case VG3:
+	case VG4:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static inline
 uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
 		uint32_t max_formats)
 {
-	/* TODO when we have YUV, we need to filter supported formats
-	 * based on pipe_id..
-	 */
-	return mdp_get_formats(pixel_formats, max_formats);
+	return mdp_get_formats(pixel_formats, max_formats,
+				!pipe_supports_yuv(pipe_id));
 }
 
 void mdp4_plane_install_properties(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
index 41f6436..60ec822 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
@@ -259,77 +259,6 @@
 	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
 }
 
-static void mdp4_lcdc_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	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 = mdp4_lcdc_encoder->panel;
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-	int i, ret;
-
-	DBG("mode=%d", mode);
-
-	if (enabled == mdp4_lcdc_encoder->enabled)
-		return;
-
-	if (enabled) {
-		unsigned long pc = mdp4_lcdc_encoder->pixclock;
-		int ret;
-
-		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);
-
-		if (panel)
-			drm_panel_enable(panel);
-
-		setup_phy(encoder);
-
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
-	} else {
-		mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
-
-		if (panel)
-			drm_panel_disable(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 = enabled;
-}
-
 static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
@@ -403,13 +332,59 @@
 	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
 }
 
-static void mdp4_lcdc_encoder_prepare(struct drm_encoder *encoder)
+static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
 {
-	mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+	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 = mdp4_lcdc_encoder->panel;
+	int i, ret;
+
+	if (WARN_ON(!mdp4_lcdc_encoder->enabled))
+		return;
+
+	mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+
+	if (panel)
+		drm_panel_disable(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_commit(struct drm_encoder *encoder)
+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 = mdp4_lcdc_encoder->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) |
@@ -420,15 +395,38 @@
 			MDP4_DMA_CONFIG_DEFLKR_EN |
 			MDP4_DMA_CONFIG_DITHER_EN);
 	mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
-	mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+	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);
+
+	if (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 = {
-	.dpms = mdp4_lcdc_encoder_dpms,
 	.mode_fixup = mdp4_lcdc_encoder_mode_fixup,
 	.mode_set = mdp4_lcdc_encoder_mode_set,
-	.prepare = mdp4_lcdc_encoder_prepare,
-	.commit = mdp4_lcdc_encoder_commit,
+	.disable = mdp4_lcdc_encoder_disable,
+	.enable = mdp4_lcdc_encoder_enable,
 };
 
 long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
index 4ddc28e1..9211851 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
@@ -94,7 +94,7 @@
 }
 
 static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
+	.dpms = drm_atomic_helper_connector_dpms,
 	.detect = mdp4_lvds_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = mdp4_lvds_connector_destroy,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 1e5ebe8..cde2500 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -17,6 +17,8 @@
 
 #include "mdp4_kms.h"
 
+#define DOWN_SCALE_MAX	8
+#define UP_SCALE_MAX	8
 
 struct mdp4_plane {
 	struct drm_plane base;
@@ -136,10 +138,6 @@
 	struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
 	struct mdp4_kms *mdp4_kms = get_kms(plane);
 	enum mdp4_pipe pipe = mdp4_plane->pipe;
-	uint32_t iova = msm_framebuffer_iova(fb, mdp4_kms->id, 0);
-
-	DBG("%s: set_scanout: %08x (%u)", mdp4_plane->name,
-			iova, fb->pitches[0]);
 
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
 			MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
@@ -149,11 +147,45 @@
 			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), iova);
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe),
+			msm_framebuffer_iova(fb, mdp4_kms->id, 0));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe),
+			msm_framebuffer_iova(fb, mdp4_kms->id, 1));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe),
+			msm_framebuffer_iova(fb, mdp4_kms->id, 2));
+	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe),
+			msm_framebuffer_iova(fb, mdp4_kms->id, 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,
@@ -163,6 +195,7 @@
 		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;
@@ -186,14 +219,59 @@
 			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;
-		/* TODO calc phasex_step */
+
+		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;
-		/* TODO calc phasey_step */
+
+		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),
@@ -214,8 +292,6 @@
 
 	mdp4_plane_set_scanout(plane, fb);
 
-	format = to_mdp_format(msm_framebuffer_format(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) |
@@ -224,6 +300,8 @@
 			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) |
 			COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT));
 
 	mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe),
@@ -232,6 +310,14 @@
 			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);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
index e87ef55..09b4a25 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
@@ -8,18 +8,19 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
-Copyright (C) 2013-2014 by the following authors:
+Copyright (C) 2013-2015 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -88,13 +89,6 @@
 	PACK_3D_COL_INT = 3,
 };
 
-enum mdp5_chroma_samp_type {
-	CHROMA_RGB = 0,
-	CHROMA_H2V1 = 1,
-	CHROMA_H1V2 = 2,
-	CHROMA_420 = 3,
-};
-
 enum mdp5_scale_filter {
 	SCALE_FILTER_NEAREST = 0,
 	SCALE_FILTER_BIL = 1,
@@ -135,6 +129,17 @@
 	CID_MAX = 23,
 };
 
+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,
@@ -142,6 +147,11 @@
 	IGC_DSPP = 3,
 };
 
+enum mdp5_data_format {
+	DATA_FORMAT_RGB = 0,
+	DATA_FORMAT_YUV = 1,
+};
+
 #define MDP5_IRQ_INTF0_WB_ROT_COMP				0x00000001
 #define MDP5_IRQ_INTF1_WB_ROT_COMP				0x00000002
 #define MDP5_IRQ_INTF2_WB_ROT_COMP				0x00000004
@@ -463,12 +473,143 @@
 }
 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
@@ -618,15 +759,15 @@
 }
 #define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT			0x00020000
 #define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB			0x00040000
-#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK			0x00780000
+#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK			0x00180000
 #define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT			19
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(uint32_t val)
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_sspp_fetch_type val)
 {
 	return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__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 mdp5_chroma_samp_type val)
+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;
 }
@@ -753,6 +894,10 @@
 
 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); }
@@ -839,20 +984,88 @@
 static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000048 + __offset_LM(i0) + 0x30*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); }
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index f021f96..46fac54 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -24,6 +24,9 @@
 #include "drm_crtc_helper.h"
 #include "drm_flip_work.h"
 
+#define CURSOR_WIDTH	64
+#define CURSOR_HEIGHT	64
+
 #define SSPP_MAX	(SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */
 
 struct mdp5_crtc {
@@ -47,8 +50,21 @@
 #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 {
+		/* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
+		spinlock_t lock;
+
+		/* current cursor being scanned out: */
+		struct drm_gem_object *scanout_bo;
+		uint32_t width;
+		uint32_t height;
+	} cursor;
 };
 #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
 
@@ -129,37 +145,26 @@
 	}
 }
 
+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);
+
+	msm_gem_put_iova(val, mdp5_kms->id);
+	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 void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
-	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
-	struct mdp5_kms *mdp5_kms = get_kms(crtc);
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-
-	DBG("%s: mode=%d", mdp5_crtc->name, mode);
-
-	if (enabled != mdp5_crtc->enabled) {
-		if (enabled) {
-			mdp5_enable(mdp5_kms);
-			mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
-		} else {
-			/* set STAGE_UNUSED for all layers */
-			mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
-			mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
-			mdp5_disable(mdp5_kms);
-		}
-		mdp5_crtc->enabled = enabled;
-	}
-}
-
 static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
@@ -256,27 +261,41 @@
 	spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
 }
 
-static void mdp5_crtc_prepare(struct drm_crtc *crtc)
+static void mdp5_crtc_disable(struct drm_crtc *crtc)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+
 	DBG("%s", mdp5_crtc->name);
-	/* make sure we hold a ref to mdp clks while setting up mode: */
-	mdp5_enable(get_kms(crtc));
-	mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	if (WARN_ON(!mdp5_crtc->enabled))
+		return;
+
+	/* set STAGE_UNUSED for all layers */
+	mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
+
+	mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
+	mdp5_disable(mdp5_kms);
+
+	mdp5_crtc->enabled = false;
 }
 
-static void mdp5_crtc_commit(struct drm_crtc *crtc)
+static void mdp5_crtc_enable(struct drm_crtc *crtc)
 {
 	struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+
 	DBG("%s", mdp5_crtc->name);
-	mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
+	if (WARN_ON(mdp5_crtc->enabled))
+		return;
+
+	mdp5_enable(mdp5_kms);
+	mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
+
 	crtc_flush_all(crtc);
-	/* drop the ref to mdp clk's that we got in prepare: */
-	mdp5_disable(get_kms(crtc));
-}
 
-static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
-{
+	mdp5_crtc->enabled = true;
 }
 
 struct plane_state {
@@ -384,6 +403,132 @@
 	return -EINVAL;
 }
 
+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 drm_device *dev = crtc->dev;
+	struct mdp5_kms *mdp5_kms = get_kms(crtc);
+	struct drm_gem_object *cursor_bo, *old_bo;
+	uint32_t blendcfg, cursor_addr, stride;
+	int ret, bpp, lm;
+	unsigned int depth;
+	enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
+	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+	unsigned long flags;
+
+	if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+		dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+		return -EINVAL;
+	}
+
+	if (NULL == mdp5_crtc->ctl)
+		return -EINVAL;
+
+	if (!handle) {
+		DBG("Cursor off");
+		return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
+	}
+
+	cursor_bo = drm_gem_object_lookup(dev, file, handle);
+	if (!cursor_bo)
+		return -ENOENT;
+
+	ret = msm_gem_get_iova(cursor_bo, mdp5_kms->id, &cursor_addr);
+	if (ret)
+		return -EINVAL;
+
+	lm = mdp5_crtc->lm;
+	drm_fb_get_bpp_depth(DRM_FORMAT_ARGB8888, &depth, &bpp);
+	stride = width * (bpp >> 3);
+
+	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+	old_bo = mdp5_crtc->cursor.scanout_bo;
+
+	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(height) |
+			MDP5_LM_CURSOR_SIZE_ROI_W(width));
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
+
+
+	blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
+	blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
+	blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
+
+	mdp5_crtc->cursor.scanout_bo = cursor_bo;
+	mdp5_crtc->cursor.width = width;
+	mdp5_crtc->cursor.height = height;
+	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+	ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
+	if (ret)
+		goto end;
+
+	flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
+	crtc_flush(crtc, flush_mask);
+
+end:
+	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);
+	uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+	uint32_t xres = crtc->mode.hdisplay;
+	uint32_t yres = crtc->mode.vdisplay;
+	uint32_t roi_w;
+	uint32_t roi_h;
+	unsigned long flags;
+
+	x = (x > 0) ? x : 0;
+	y = (y > 0) ? y : 0;
+
+	/*
+	 * Cursor Region Of Interest (ROI) is a plane read from cursor
+	 * buffer to render. The ROI region is determined by the visiblity 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 - x);
+	roi_h = min(mdp5_crtc->cursor.height, yres - y);
+
+	spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->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(mdp5_crtc->lm),
+			MDP5_LM_CURSOR_START_XY_Y_START(y) |
+			MDP5_LM_CURSOR_START_XY_X_START(x));
+	spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+	crtc_flush(crtc, flush_mask);
+
+	return 0;
+}
+
 static const struct drm_crtc_funcs mdp5_crtc_funcs = {
 	.set_config = drm_atomic_helper_set_config,
 	.destroy = mdp5_crtc_destroy,
@@ -392,17 +537,15 @@
 	.reset = drm_atomic_helper_crtc_reset,
 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+	.cursor_set = mdp5_crtc_cursor_set,
+	.cursor_move = mdp5_crtc_cursor_move,
 };
 
 static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
-	.dpms = mdp5_crtc_dpms,
 	.mode_fixup = mdp5_crtc_mode_fixup,
 	.mode_set_nofb = mdp5_crtc_mode_set_nofb,
-	.mode_set = drm_helper_crtc_mode_set,
-	.mode_set_base = drm_helper_crtc_mode_set_base,
-	.prepare = mdp5_crtc_prepare,
-	.commit = mdp5_crtc_commit,
-	.load_lut = mdp5_crtc_load_lut,
+	.prepare = mdp5_crtc_disable,
+	.commit = mdp5_crtc_enable,
 	.atomic_check = mdp5_crtc_atomic_check,
 	.atomic_begin = mdp5_crtc_atomic_begin,
 	.atomic_flush = mdp5_crtc_atomic_flush,
@@ -412,6 +555,7 @@
 {
 	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);
@@ -421,6 +565,9 @@
 	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)
@@ -520,6 +667,7 @@
 	mdp5_crtc->lm = GET_LM_ID(id);
 
 	spin_lock_init(&mdp5_crtc->lm_lock);
+	spin_lock_init(&mdp5_crtc->cursor.lock);
 
 	mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
 	mdp5_crtc->err.irq = mdp5_crtc_err_irq;
@@ -528,6 +676,10 @@
 			pipe2name(mdp5_plane_pipe(plane)), id);
 
 	drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
+
+	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;
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
index dea4505..1511290 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
@@ -95,7 +95,7 @@
 }
 
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf)
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
 {
 	unsigned long flags;
 	static const enum mdp5_intfnum intfnum[] = {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
index 1018519..ad48788 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
@@ -34,7 +34,7 @@
  */
 struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf);
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
 
 int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index 0254bfd..d6a14bb 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -110,45 +111,6 @@
 	.destroy = mdp5_encoder_destroy,
 };
 
-static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
-	struct mdp5_kms *mdp5_kms = get_kms(encoder);
-	int intf = mdp5_encoder->intf;
-	bool enabled = (mode == DRM_MODE_DPMS_ON);
-	unsigned long flags;
-
-	DBG("mode=%d", mode);
-
-	if (enabled == mdp5_encoder->enabled)
-		return;
-
-	if (enabled) {
-		bs_set(mdp5_encoder, 1);
-		spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
-		spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-	} else {
-		spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-		mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
-		spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-
-		/*
-		 * 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(intf));
-
-		bs_set(mdp5_encoder, 0);
-	}
-
-	mdp5_encoder->enabled = enabled;
-}
-
 static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder,
 		const struct drm_display_mode *mode,
 		struct drm_display_mode *adjusted_mode)
@@ -162,11 +124,13 @@
 {
 	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;
 	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;
+	uint32_t format = 0x2100;
 	unsigned long flags;
 
 	mode = adjusted_mode;
@@ -188,7 +152,28 @@
 	/* probably need to get DATA_EN polarity from panel.. */
 
 	dtv_hsync_skew = 0;  /* get this from panel? */
-	format = 0x213f;     /* 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;
@@ -198,6 +183,16 @@
 	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_id == 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),
@@ -225,25 +220,61 @@
 	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 }
 
-static void mdp5_encoder_prepare(struct drm_encoder *encoder)
-{
-	mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void mdp5_encoder_commit(struct drm_encoder *encoder)
+static void mdp5_encoder_disable(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;
+	unsigned long flags;
+
+	if (WARN_ON(!mdp5_encoder->enabled))
+		return;
+
+	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+	/*
+	 * 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(intf));
+
+	bs_set(mdp5_encoder, 0);
+
+	mdp5_encoder->enabled = false;
+}
+
+static void mdp5_encoder_enable(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;
+	unsigned long flags;
+
+	if (WARN_ON(mdp5_encoder->enabled))
+		return;
+
 	mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
 			mdp5_encoder->intf_id);
-	mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+	bs_set(mdp5_encoder, 1);
+	spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+	mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+	spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+	mdp5_encoder->enabled = false;
 }
 
 static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
-	.dpms = mdp5_encoder_dpms,
 	.mode_fixup = mdp5_encoder_mode_fixup,
 	.mode_set = mdp5_encoder_mode_set,
-	.prepare = mdp5_encoder_prepare,
-	.commit = mdp5_encoder_commit,
+	.prepare = mdp5_encoder_disable,
+	.commit = mdp5_encoder_enable,
 };
 
 /* initialize encoder */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 9f01a4f..92b61db 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -68,6 +68,18 @@
 	return 0;
 }
 
+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));
+	mdp5_enable(mdp5_kms);
+}
+
+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));
+	mdp5_disable(mdp5_kms);
+}
+
 static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
 		struct drm_encoder *encoder)
 {
@@ -115,6 +127,8 @@
 		.irq             = mdp5_irq,
 		.enable_vblank   = mdp5_enable_vblank,
 		.disable_vblank  = mdp5_disable_vblank,
+		.prepare_commit  = mdp5_prepare_commit,
+		.complete_commit = mdp5_complete_commit,
 		.get_format      = mdp_get_format,
 		.round_pixclk    = mdp5_round_pixclk,
 		.preclose        = mdp5_preclose,
@@ -208,19 +222,18 @@
 		}
 	}
 
-	/* Construct encoder for HDMI: */
-	encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
-	if (IS_ERR(encoder)) {
-		dev_err(dev->dev, "failed to construct encoder\n");
-		ret = PTR_ERR(encoder);
-		goto fail;
-	}
-
-	encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
-	priv->encoders[priv->num_encoders++] = encoder;
-
-	/* Construct bridge/connector for HDMI: */
 	if (priv->hdmi) {
+		/* Construct encoder for HDMI: */
+		encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
+		if (IS_ERR(encoder)) {
+			dev_err(dev->dev, "failed to construct encoder\n");
+			ret = PTR_ERR(encoder);
+			goto fail;
+		}
+
+		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
+		priv->encoders[priv->num_encoders++] = encoder;
+
 		ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
 		if (ret) {
 			dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
@@ -228,6 +241,27 @@
 		}
 	}
 
+	if (priv->edp) {
+		/* Construct encoder for eDP: */
+		encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
+		if (IS_ERR(encoder)) {
+			dev_err(dev->dev, "failed to construct eDP encoder\n");
+			ret = PTR_ERR(encoder);
+			goto fail;
+		}
+
+		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+		priv->encoders[priv->num_encoders++] = encoder;
+
+		/* Construct bridge/connector for eDP: */
+		ret = msm_edp_modeset_init(priv->edp, dev, encoder);
+		if (ret) {
+			dev_err(dev->dev, "failed to initialize eDP: %d\n",
+									ret);
+			goto fail;
+		}
+	}
+
 	return 0;
 
 fail:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index dd69c77..49d011e 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -165,14 +165,25 @@
 int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
 void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
 
+static inline bool pipe_supports_yuv(enum mdp5_pipe pipe)
+{
+	switch (pipe) {
+	case SSPP_VIG0:
+	case SSPP_VIG1:
+	case SSPP_VIG2:
+	case SSPP_VIG3:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static inline
 uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
 		uint32_t max_formats)
 {
-	/* TODO when we have YUV, we need to filter supported formats
-	 * based on pipe id..
-	 */
-	return mdp_get_formats(pixel_formats, max_formats);
+	return mdp_get_formats(pixel_formats, max_formats,
+				!pipe_supports_yuv(pipe));
 }
 
 void mdp5_plane_install_properties(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 26e5fde..05cf9ab 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -18,8 +18,6 @@
 
 #include "mdp5_kms.h"
 
-#define MAX_PLANE	4
-
 struct mdp5_plane {
 	struct drm_plane base;
 	const char *name;
@@ -113,6 +111,7 @@
 	} else {
 		mdp5_state->zpos = 1 + drm_plane_index(plane);
 	}
+	mdp5_state->base.plane = plane;
 
 	plane->state = &mdp5_state->base;
 }
@@ -277,6 +276,155 @@
 	plane->fb = fb;
 }
 
+/* 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(uint32_t pixel_format, uint32_t src, uint32_t dest,
+		uint32_t phasex_steps[2])
+{
+	uint32_t phasex_step;
+	unsigned int hsub;
+	int ret;
+
+	ret = calc_phase_step(src, dest, &phasex_step);
+	if (ret)
+		return ret;
+
+	hsub = drm_format_horz_chroma_subsampling(pixel_format);
+
+	phasex_steps[0] = phasex_step;
+	phasex_steps[1] = phasex_step / hsub;
+
+	return 0;
+}
+
+static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
+		uint32_t phasey_steps[2])
+{
+	uint32_t phasey_step;
+	unsigned int vsub;
+	int ret;
+
+	ret = calc_phase_step(src, dest, &phasey_step);
+	if (ret)
+		return ret;
+
+	vsub = drm_format_vert_chroma_subsampling(pixel_format);
+
+	phasey_steps[0] = phasey_step;
+	phasey_steps[1] = phasey_step / vsub;
+
+	return 0;
+}
+
+static uint32_t get_scalex_config(uint32_t src, uint32_t dest)
+{
+	uint32_t filter;
+
+	filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+
+	return  MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
+		MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) |
+		MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter)  |
+		MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter);
+}
+
+static uint32_t get_scaley_config(uint32_t src, uint32_t dest)
+{
+	uint32_t filter;
+
+	filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+
+	return  MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
+		MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) |
+		MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter)  |
+		MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter);
+}
+
 static int mdp5_plane_mode_set(struct drm_plane *plane,
 		struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		int crtc_x, int crtc_y,
@@ -286,11 +434,14 @@
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 	struct mdp5_kms *mdp5_kms = get_kms(plane);
+	struct device *dev = mdp5_kms->dev->dev;
 	enum mdp5_pipe pipe = mdp5_plane->pipe;
 	const struct mdp_format *format;
 	uint32_t nplanes, config = 0;
-	uint32_t phasex_step = 0, phasey_step = 0;
+	/* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
+	uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,};
 	uint32_t hdecm = 0, vdecm = 0;
+	uint32_t pix_format;
 	unsigned long flags;
 	int ret;
 
@@ -300,6 +451,9 @@
 	if (WARN_ON(nplanes > pipe2nclients(pipe)))
 		return -EINVAL;
 
+	format = to_mdp_format(msm_framebuffer_format(fb));
+	pix_format = format->base.pixel_format;
+
 	/* src values are in Q16 fixed point, convert to integer: */
 	src_x = src_x >> 16;
 	src_y = src_y >> 16;
@@ -324,14 +478,28 @@
 	 */
 	mdp5_smp_configure(mdp5_kms->smp, pipe);
 
-	if (src_w != crtc_w) {
-		config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN;
-		/* TODO calc phasex_step, hdecm */
+	/* SCALE is used to both scale and up-sample chroma components */
+
+	if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) {
+		/* TODO calc hdecm */
+		ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step);
+		if (ret) {
+			dev_err(dev, "X scaling (%d -> %d) failed: %d\n",
+					src_w, crtc_w, ret);
+			return ret;
+		}
+		config |= get_scalex_config(src_w, crtc_w);
 	}
 
-	if (src_h != crtc_h) {
-		config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN;
-		/* TODO calc phasey_step, vdecm */
+	if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) {
+		/* TODO calc vdecm */
+		ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step);
+		if (ret) {
+			dev_err(dev, "Y scaling (%d -> %d) failed: %d\n",
+					src_h, crtc_h, ret);
+			return ret;
+		}
+		config |= get_scaley_config(src_h, crtc_h);
 	}
 
 	spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
@@ -356,8 +524,6 @@
 			MDP5_PIPE_OUT_XY_X(crtc_x) |
 			MDP5_PIPE_OUT_XY_Y(crtc_y));
 
-	format = to_mdp_format(msm_framebuffer_format(fb));
-
 	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) |
@@ -367,8 +533,8 @@
 			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_NUM_PLANES(nplanes - 1) |
-			MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB));
+			MDP5_PIPE_SRC_FORMAT_NUM_PLANES(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]) |
@@ -382,18 +548,24 @@
 	/* not using secure mode: */
 	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
 
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step);
-	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step);
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
+			phasex_step[0]);
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
+			phasey_step[0]);
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
+			phasex_step[1]);
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
+			phasey_step[1]);
 	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),
-			MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) |
-			MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST));
+	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
+
+	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(plane, fb);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
index bf55188..1f795af 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
@@ -119,9 +119,10 @@
 
 	spin_lock_irqsave(&smp->state_lock, flags);
 
-	nblks -= reserved;
-	if (reserved)
+	if (reserved) {
+		nblks = max(0, nblks - reserved);
 		DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
+	}
 
 	avail = cnt - bitmap_weight(smp->state, cnt);
 	if (nblks > avail) {
diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
index 64c1afd..a1d35f1 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
@@ -8,18 +8,19 @@
 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                 (    647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml                 (    676 bytes, from 2014-12-05 15:34:49)
 - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml            (  20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml      (   2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml            (  27208 bytes, from 2015-01-13 23:56:11)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml             (  11712 bytes, from 2013-08-17 17:13:43)
 - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml            (    344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml         (   1686 bytes, from 2014-10-31 16:48:57)
 - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml             (   8253 bytes, from 2014-12-08 16:13:00)
 
-Copyright (C) 2013 by the following authors:
+Copyright (C) 2013-2014 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
 
 Permission is hereby granted, free of charge, to any person obtaining
@@ -44,6 +45,19 @@
 */
 
 
+enum mdp_chroma_samp_type {
+	CHROMA_RGB = 0,
+	CHROMA_H2V1 = 1,
+	CHROMA_H1V2 = 2,
+	CHROMA_420 = 3,
+};
+
+enum mdp_sspp_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,
diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c
index e0a6ffb..f683433 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_format.c
+++ b/drivers/gpu/drm/msm/mdp/mdp_format.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -19,7 +20,58 @@
 #include "msm_drv.h"
 #include "mdp_kms.h"
 
-#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \
+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) { \
 		.base = { .pixel_format = DRM_FORMAT_ ## name }, \
 		.bpc_a = BPC ## a ## A,                          \
 		.bpc_r = BPC ## r,                               \
@@ -30,21 +82,46 @@
 		.unpack_tight = tight,                           \
 		.cpp = c,                                        \
 		.unpack_count = cnt,                             \
-	}
+		.fetch_type = fp,                                \
+		.chroma_sample = cs                              \
+}
 
 #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),
-	FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4),
-	FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3),
-	FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3),
-	FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3),
-	FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3),
+	/*  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_RGB),
+	FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4,
+			MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+	FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+	FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+	FMT(RGB565,   0, 5, 6, 5,  1, 0, 2, 0,  false,  true,  2,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+	FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3,
+			MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+
+	/* --- RGB formats above / YUV formats below this line --- */
+
+	FMT(NV12,     0, 8, 8, 8,  1, 2, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
+	FMT(NV21,     0, 8, 8, 8,  2, 1, 0, 0,  false,  true,  2, 2,
+			MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
 };
 
-uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats)
+/*
+ * 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++) {
@@ -53,6 +130,9 @@
 		if (i == max_formats)
 			break;
 
+		if (rgb_only && MDP_FORMAT_IS_YUV(f))
+			break;
+
 		pixel_formats[i] = f->base.pixel_format;
 	}
 
@@ -69,3 +149,11 @@
 	}
 	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
index 2a73172..1988c24 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c
@@ -34,7 +34,7 @@
 	struct mdp_irq *irq;
 	uint32_t irqmask = mdp_kms->vblank_mask;
 
-	BUG_ON(!spin_is_locked(&list_lock));
+	assert_spin_locked(&list_lock);
 
 	list_for_each_entry(irq, &mdp_kms->irq_list, node)
 		irqmask |= irq->irqmask;
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h
index b268ce9..5ae4039 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h
@@ -88,10 +88,32 @@
 	uint8_t unpack[4];
 	bool alpha_enable, unpack_tight;
 	uint8_t cpp, unpack_count;
+	enum mdp_sspp_fetch_type fetch_type;
+	enum mdp_chroma_samp_type chroma_sample;
 };
 #define to_mdp_format(x) container_of(x, struct mdp_format, base)
+#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->chroma_sample > CHROMA_RGB)
 
-uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats);
+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);
 
+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_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 1919682..871aa21 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -20,6 +20,7 @@
 #include "msm_gem.h"
 
 struct msm_commit {
+	struct drm_device *dev;
 	struct drm_atomic_state *state;
 	uint32_t fence;
 	struct msm_fence_cb fence_cb;
@@ -58,14 +59,16 @@
 	spin_unlock(&priv->pending_crtcs_event.lock);
 }
 
-static struct msm_commit *new_commit(struct drm_atomic_state *state)
+static struct msm_commit *commit_init(struct drm_atomic_state *state)
 {
 	struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
 
 	if (!c)
 		return NULL;
 
+	c->dev = state->dev;
 	c->state = state;
+
 	/* TODO we might need a way to indicate to run the cb on a
 	 * different wq so wait_for_vblanks() doesn't block retiring
 	 * bo's..
@@ -75,6 +78,12 @@
 	return c;
 }
 
+static void commit_destroy(struct msm_commit *c)
+{
+	end_atomic(c->dev->dev_private, c->crtc_mask);
+	kfree(c);
+}
+
 /* The (potentially) asynchronous part of the commit.  At this point
  * nothing can fail short of armageddon.
  */
@@ -82,6 +91,10 @@
 {
 	struct drm_atomic_state *state = c->state;
 	struct drm_device *dev = state->dev;
+	struct msm_drm_private *priv = dev->dev_private;
+	struct msm_kms *kms = priv->kms;
+
+	kms->funcs->prepare_commit(kms, state);
 
 	drm_atomic_helper_commit_pre_planes(dev, state);
 
@@ -106,11 +119,11 @@
 
 	drm_atomic_helper_cleanup_planes(dev, state);
 
+	kms->funcs->complete_commit(kms, state);
+
 	drm_atomic_state_free(state);
 
-	end_atomic(dev->dev_private, c->crtc_mask);
-
-	kfree(c);
+	commit_destroy(c);
 }
 
 static void fence_cb(struct msm_fence_cb *cb)
@@ -127,6 +140,26 @@
 }
 
 
+int msm_atomic_check(struct drm_device *dev,
+		     struct drm_atomic_state *state)
+{
+	int ret;
+
+	/*
+	 * msm ->atomic_check can update ->mode_changed for pixel format
+	 * changes, hence must be run before we check the modeset changes.
+	 */
+	ret = drm_atomic_helper_check_planes(dev, state);
+	if (ret)
+		return ret;
+
+	ret = drm_atomic_helper_check_modeset(dev, state);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
 /**
  * drm_atomic_helper_commit - commit validated state object
  * @dev: DRM device
@@ -145,6 +178,7 @@
 {
 	int nplanes = dev->mode_config.num_total_plane;
 	int ncrtcs = dev->mode_config.num_crtc;
+	struct timespec timeout;
 	struct msm_commit *c;
 	int i, ret;
 
@@ -152,7 +186,7 @@
 	if (ret)
 		return ret;
 
-	c = new_commit(state);
+	c = commit_init(state);
 	if (!c)
 		return -ENOMEM;
 
@@ -217,10 +251,12 @@
 		return 0;
 	}
 
-	ret = msm_wait_fence_interruptable(dev, c->fence, NULL);
+	jiffies_to_timespec(jiffies + msecs_to_jiffies(1000), &timeout);
+
+	ret = msm_wait_fence_interruptable(dev, c->fence, &timeout);
 	if (ret) {
 		WARN_ON(ret);  // TODO unswap state back?  or??
-		kfree(c);
+		commit_destroy(c);
 		return ret;
 	}
 
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 9a61546..a426911 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -29,7 +29,7 @@
 static const struct drm_mode_config_funcs mode_config_funcs = {
 	.fb_create = msm_framebuffer_create,
 	.output_poll_changed = msm_fb_output_poll_changed,
-	.atomic_check = drm_atomic_helper_check,
+	.atomic_check = msm_atomic_check,
 	.atomic_commit = msm_atomic_commit,
 };
 
@@ -54,6 +54,12 @@
 #define reglog 0
 #endif
 
+#ifdef CONFIG_DRM_MSM_FBDEV
+static bool fbdev = true;
+MODULE_PARM_DESC(fbdev, "Enable fbdev compat layer");
+module_param(fbdev, bool, 0600);
+#endif
+
 static char *vram = "16m";
 MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU");
 module_param(vram, charp, 0);
@@ -300,7 +306,8 @@
 	drm_mode_config_reset(dev);
 
 #ifdef CONFIG_DRM_MSM_FBDEV
-	priv->fbdev = msm_fbdev_init(dev);
+	if (fbdev)
+		priv->fbdev = msm_fbdev_init(dev);
 #endif
 
 	ret = msm_debugfs_late_init(dev);
@@ -1023,6 +1030,7 @@
 static int __init msm_drm_register(void)
 {
 	DBG("init");
+	msm_edp_register();
 	hdmi_register();
 	adreno_register();
 	return platform_driver_register(&msm_platform_driver);
@@ -1034,6 +1042,7 @@
 	platform_driver_unregister(&msm_platform_driver);
 	hdmi_unregister();
 	adreno_unregister();
+	msm_edp_unregister();
 }
 
 module_init(msm_drm_register);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b69ef2d..9e8d441 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -76,6 +76,12 @@
 	 */
 	struct hdmi *hdmi;
 
+	/* eDP is for mdp5 only, but kms has not been created
+	 * when edp_bind() and edp_init() are called. Here is the only
+	 * place to keep the edp instance.
+	 */
+	struct msm_edp *edp;
+
 	/* when we have more than one 'msm_gpu' these need to be an array: */
 	struct msm_gpu *gpu;
 	struct msm_file_private *lastctx;
@@ -148,6 +154,8 @@
 		(_cb)->func = _func;                         \
 	} while (0)
 
+int msm_atomic_check(struct drm_device *dev,
+		     struct drm_atomic_state *state);
 int msm_atomic_commit(struct drm_device *dev,
 		struct drm_atomic_state *state, bool async);
 
@@ -222,6 +230,12 @@
 void __init hdmi_register(void);
 void __exit hdmi_unregister(void);
 
+struct msm_edp;
+void __init msm_edp_register(void);
+void __exit msm_edp_unregister(void);
+int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
+		struct drm_encoder *encoder);
+
 #ifdef CONFIG_DEBUG_FS
 void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
 void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 84dec16..6b573e6 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -24,7 +24,7 @@
 struct msm_framebuffer {
 	struct drm_framebuffer base;
 	const struct msm_format *format;
-	struct drm_gem_object *planes[3];
+	struct drm_gem_object *planes[MAX_PLANE];
 };
 #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
 
@@ -122,7 +122,7 @@
 	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
 	if (!msm_fb->planes[plane])
 		return 0;
-	return msm_gem_iova(msm_fb->planes[plane], id);
+	return msm_gem_iova(msm_fb->planes[plane], id) + fb->offsets[plane];
 }
 
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 1f3af13..df60f65 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -241,17 +241,20 @@
 		goto fail;
 	}
 
-	drm_fb_helper_single_add_all_connectors(helper);
+	ret = drm_fb_helper_single_add_all_connectors(helper);
+	if (ret)
+		goto fini;
 
-	/* disable all the possible outputs/crtcs before entering KMS mode */
-	drm_helper_disable_unused_functions(dev);
-
-	drm_fb_helper_initial_config(helper, 32);
+	ret = drm_fb_helper_initial_config(helper, 32);
+	if (ret)
+		goto fini;
 
 	priv->fbdev = helper;
 
 	return helper;
 
+fini:
+	drm_fb_helper_fini(helper);
 fail:
 	kfree(fbdev);
 	return NULL;
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 0643774..3a78cb4 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -23,6 +23,8 @@
 
 #include "msm_drv.h"
 
+#define MAX_PLANE	4
+
 /* As there are different display controller blocks depending on the
  * snapdragon version, the kms support is split out and the appropriate
  * implementation is loaded at runtime.  The kms module is responsible
@@ -38,6 +40,9 @@
 	irqreturn_t (*irq)(struct msm_kms *kms);
 	int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
 	void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
+	/* modeset, bracketing atomic_commit(): */
+	void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
+	void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
 	/* misc: */
 	const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
 	long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
new file mode 100644
index 0000000..2b76566
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -0,0 +1,66 @@
+ccflags-y := -Iinclude/drm
+ccflags-y += -I$(src)/include
+ccflags-y += -I$(src)/include/nvkm
+ccflags-y += -I$(src)/nvkm
+ccflags-y += -I$(src)
+
+# NVKM - HW resource manager
+#- code also used by various userspace tools/tests
+include $(src)/nvif/Kbuild
+nouveau-y := $(nvif-y)
+
+# NVIF - NVKM interface library (NVKM user interface also defined here)
+#- code also used by various userspace tools/tests
+include $(src)/nvkm/Kbuild
+nouveau-y += $(nvkm-y)
+
+# DRM - general
+ifdef CONFIG_X86
+nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
+endif
+nouveau-y += nouveau_agp.o
+nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
+nouveau-y += nouveau_drm.o
+nouveau-y += nouveau_hwmon.o
+nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
+nouveau-y += nouveau_nvif.o
+nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
+nouveau-y += nouveau_sysfs.o
+nouveau-y += nouveau_usif.o # userspace <-> nvif
+nouveau-y += nouveau_vga.o
+
+# DRM - memory management
+nouveau-y += nouveau_bo.o
+nouveau-y += nouveau_gem.o
+nouveau-y += nouveau_prime.o
+nouveau-y += nouveau_sgdma.o
+nouveau-y += nouveau_ttm.o
+
+# DRM - modesetting
+nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
+nouveau-y += nouveau_connector.o
+nouveau-y += nouveau_display.o
+nouveau-y += nv50_display.o
+nouveau-y += nouveau_dp.o
+nouveau-y += nouveau_fbcon.o
+nouveau-y += nv04_fbcon.o
+nouveau-y += nv50_fbcon.o
+nouveau-y += nvc0_fbcon.o
+
+# DRM - command submission
+nouveau-y += nouveau_abi16.o
+nouveau-y += nouveau_chan.o
+nouveau-y += nouveau_dma.o
+nouveau-y += nouveau_fence.o
+nouveau-y += nv04_fence.o
+nouveau-y += nv10_fence.o
+nouveau-y += nv17_fence.o
+nouveau-y += nv50_fence.o
+nouveau-y += nv84_fence.o
+nouveau-y += nvc0_fence.o
+
+# DRM - prehistoric modesetting (NV04-G7x)
+nouveau-y += nouveau_bios.o
+include $(src)/dispnv04/Kbuild
+
+obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 40afc69..5ab13e7 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -26,7 +26,7 @@
 	  Choose this option for open-source NVIDIA support.
 
 config NOUVEAU_PLATFORM_DRIVER
-	tristate "Nouveau (NVIDIA) SoC GPUs"
+	bool "Nouveau (NVIDIA) SoC GPUs"
 	depends on DRM_NOUVEAU && ARCH_TEGRA
 	default y
 	help
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
deleted file mode 100644
index 6461e35..0000000
--- a/drivers/gpu/drm/nouveau/Makefile
+++ /dev/null
@@ -1,400 +0,0 @@
-#
-# Makefile for the drm device driver.  This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-ccflags-y := -Iinclude/drm
-ccflags-y += -I$(src)/core/include
-ccflags-y += -I$(src)/core
-ccflags-y += -I$(src)
-
-nouveau-y := core/core/client.o
-nouveau-y += core/core/engctx.o
-nouveau-y += core/core/engine.o
-nouveau-y += core/core/enum.o
-nouveau-y += core/core/event.o
-nouveau-y += core/core/gpuobj.o
-nouveau-y += core/core/handle.o
-nouveau-y += core/core/ioctl.o
-nouveau-y += core/core/mm.o
-nouveau-y += core/core/namedb.o
-nouveau-y += core/core/notify.o
-nouveau-y += core/core/object.o
-nouveau-y += core/core/option.o
-nouveau-y += core/core/parent.o
-nouveau-y += core/core/printk.o
-nouveau-y += core/core/ramht.o
-nouveau-y += core/core/subdev.o
-
-nouveau-y += core/subdev/bar/base.o
-nouveau-y += core/subdev/bar/nv50.o
-nouveau-y += core/subdev/bar/nvc0.o
-nouveau-y += core/subdev/bar/gk20a.o
-nouveau-y += core/subdev/bios/base.o
-nouveau-y += core/subdev/bios/bit.o
-nouveau-y += core/subdev/bios/boost.o
-nouveau-y += core/subdev/bios/conn.o
-nouveau-y += core/subdev/bios/cstep.o
-nouveau-y += core/subdev/bios/dcb.o
-nouveau-y += core/subdev/bios/disp.o
-nouveau-y += core/subdev/bios/dp.o
-nouveau-y += core/subdev/bios/extdev.o
-nouveau-y += core/subdev/bios/fan.o
-nouveau-y += core/subdev/bios/gpio.o
-nouveau-y += core/subdev/bios/i2c.o
-nouveau-y += core/subdev/bios/image.o
-nouveau-y += core/subdev/bios/init.o
-nouveau-y += core/subdev/bios/mxm.o
-nouveau-y += core/subdev/bios/npde.o
-nouveau-y += core/subdev/bios/pcir.o
-nouveau-y += core/subdev/bios/perf.o
-nouveau-y += core/subdev/bios/pll.o
-nouveau-y += core/subdev/bios/pmu.o
-nouveau-y += core/subdev/bios/ramcfg.o
-nouveau-y += core/subdev/bios/rammap.o
-nouveau-y += core/subdev/bios/shadow.o
-nouveau-y += core/subdev/bios/shadowacpi.o
-nouveau-y += core/subdev/bios/shadowof.o
-nouveau-y += core/subdev/bios/shadowpci.o
-nouveau-y += core/subdev/bios/shadowramin.o
-nouveau-y += core/subdev/bios/shadowrom.o
-nouveau-y += core/subdev/bios/timing.o
-nouveau-y += core/subdev/bios/therm.o
-nouveau-y += core/subdev/bios/vmap.o
-nouveau-y += core/subdev/bios/volt.o
-nouveau-y += core/subdev/bios/xpio.o
-nouveau-y += core/subdev/bios/M0203.o
-nouveau-y += core/subdev/bios/M0205.o
-nouveau-y += core/subdev/bios/M0209.o
-nouveau-y += core/subdev/bios/P0260.o
-nouveau-y += core/subdev/bus/hwsq.o
-nouveau-y += core/subdev/bus/nv04.o
-nouveau-y += core/subdev/bus/nv31.o
-nouveau-y += core/subdev/bus/nv50.o
-nouveau-y += core/subdev/bus/nv94.o
-nouveau-y += core/subdev/bus/nvc0.o
-nouveau-y += core/subdev/clock/base.o
-nouveau-y += core/subdev/clock/nv04.o
-nouveau-y += core/subdev/clock/nv40.o
-nouveau-y += core/subdev/clock/nv50.o
-nouveau-y += core/subdev/clock/nv84.o
-nouveau-y += core/subdev/clock/nva3.o
-nouveau-y += core/subdev/clock/nvaa.o
-nouveau-y += core/subdev/clock/nvc0.o
-nouveau-y += core/subdev/clock/nve0.o
-nouveau-y += core/subdev/clock/gk20a.o
-nouveau-y += core/subdev/clock/pllnv04.o
-nouveau-y += core/subdev/clock/pllnva3.o
-nouveau-y += core/subdev/devinit/base.o
-nouveau-y += core/subdev/devinit/nv04.o
-nouveau-y += core/subdev/devinit/nv05.o
-nouveau-y += core/subdev/devinit/nv10.o
-nouveau-y += core/subdev/devinit/nv1a.o
-nouveau-y += core/subdev/devinit/nv20.o
-nouveau-y += core/subdev/devinit/nv50.o
-nouveau-y += core/subdev/devinit/nv84.o
-nouveau-y += core/subdev/devinit/nv98.o
-nouveau-y += core/subdev/devinit/nva3.o
-nouveau-y += core/subdev/devinit/nvaf.o
-nouveau-y += core/subdev/devinit/nvc0.o
-nouveau-y += core/subdev/devinit/gm107.o
-nouveau-y += core/subdev/devinit/gm204.o
-nouveau-y += core/subdev/fb/base.o
-nouveau-y += core/subdev/fb/nv04.o
-nouveau-y += core/subdev/fb/nv10.o
-nouveau-y += core/subdev/fb/nv1a.o
-nouveau-y += core/subdev/fb/nv20.o
-nouveau-y += core/subdev/fb/nv25.o
-nouveau-y += core/subdev/fb/nv30.o
-nouveau-y += core/subdev/fb/nv35.o
-nouveau-y += core/subdev/fb/nv36.o
-nouveau-y += core/subdev/fb/nv40.o
-nouveau-y += core/subdev/fb/nv41.o
-nouveau-y += core/subdev/fb/nv44.o
-nouveau-y += core/subdev/fb/nv46.o
-nouveau-y += core/subdev/fb/nv47.o
-nouveau-y += core/subdev/fb/nv49.o
-nouveau-y += core/subdev/fb/nv4e.o
-nouveau-y += core/subdev/fb/nv50.o
-nouveau-y += core/subdev/fb/nv84.o
-nouveau-y += core/subdev/fb/nva3.o
-nouveau-y += core/subdev/fb/nvaa.o
-nouveau-y += core/subdev/fb/nvaf.o
-nouveau-y += core/subdev/fb/nvc0.o
-nouveau-y += core/subdev/fb/nve0.o
-nouveau-y += core/subdev/fb/gk20a.o
-nouveau-y += core/subdev/fb/gm107.o
-nouveau-y += core/subdev/fb/ramnv04.o
-nouveau-y += core/subdev/fb/ramnv10.o
-nouveau-y += core/subdev/fb/ramnv1a.o
-nouveau-y += core/subdev/fb/ramnv20.o
-nouveau-y += core/subdev/fb/ramnv40.o
-nouveau-y += core/subdev/fb/ramnv41.o
-nouveau-y += core/subdev/fb/ramnv44.o
-nouveau-y += core/subdev/fb/ramnv49.o
-nouveau-y += core/subdev/fb/ramnv4e.o
-nouveau-y += core/subdev/fb/ramnv50.o
-nouveau-y += core/subdev/fb/ramnva3.o
-nouveau-y += core/subdev/fb/ramnvaa.o
-nouveau-y += core/subdev/fb/ramnvc0.o
-nouveau-y += core/subdev/fb/ramnve0.o
-nouveau-y += core/subdev/fb/ramgk20a.o
-nouveau-y += core/subdev/fb/ramgm107.o
-nouveau-y += core/subdev/fb/sddr2.o
-nouveau-y += core/subdev/fb/sddr3.o
-nouveau-y += core/subdev/fb/gddr3.o
-nouveau-y += core/subdev/fb/gddr5.o
-nouveau-y += core/subdev/fuse/base.o
-nouveau-y += core/subdev/fuse/g80.o
-nouveau-y += core/subdev/fuse/gf100.o
-nouveau-y += core/subdev/fuse/gm107.o
-nouveau-y += core/subdev/gpio/base.o
-nouveau-y += core/subdev/gpio/nv10.o
-nouveau-y += core/subdev/gpio/nv50.o
-nouveau-y += core/subdev/gpio/nv94.o
-nouveau-y += core/subdev/gpio/nvd0.o
-nouveau-y += core/subdev/gpio/nve0.o
-nouveau-y += core/subdev/i2c/base.o
-nouveau-y += core/subdev/i2c/anx9805.o
-nouveau-y += core/subdev/i2c/aux.o
-nouveau-y += core/subdev/i2c/bit.o
-nouveau-y += core/subdev/i2c/pad.o
-nouveau-y += core/subdev/i2c/padnv04.o
-nouveau-y += core/subdev/i2c/padnv94.o
-nouveau-y += core/subdev/i2c/padgm204.o
-nouveau-y += core/subdev/i2c/nv04.o
-nouveau-y += core/subdev/i2c/nv4e.o
-nouveau-y += core/subdev/i2c/nv50.o
-nouveau-y += core/subdev/i2c/nv94.o
-nouveau-y += core/subdev/i2c/nvd0.o
-nouveau-y += core/subdev/i2c/gf117.o
-nouveau-y += core/subdev/i2c/nve0.o
-nouveau-y += core/subdev/i2c/gm204.o
-nouveau-y += core/subdev/ibus/nvc0.o
-nouveau-y += core/subdev/ibus/nve0.o
-nouveau-y += core/subdev/ibus/gk20a.o
-nouveau-y += core/subdev/instmem/base.o
-nouveau-y += core/subdev/instmem/nv04.o
-nouveau-y += core/subdev/instmem/nv40.o
-nouveau-y += core/subdev/instmem/nv50.o
-nouveau-y += core/subdev/ltc/base.o
-nouveau-y += core/subdev/ltc/gf100.o
-nouveau-y += core/subdev/ltc/gk104.o
-nouveau-y += core/subdev/ltc/gm107.o
-nouveau-y += core/subdev/mc/base.o
-nouveau-y += core/subdev/mc/nv04.o
-nouveau-y += core/subdev/mc/nv40.o
-nouveau-y += core/subdev/mc/nv44.o
-nouveau-y += core/subdev/mc/nv4c.o
-nouveau-y += core/subdev/mc/nv50.o
-nouveau-y += core/subdev/mc/nv94.o
-nouveau-y += core/subdev/mc/nv98.o
-nouveau-y += core/subdev/mc/nvc0.o
-nouveau-y += core/subdev/mc/nvc3.o
-nouveau-y += core/subdev/mc/gk20a.o
-nouveau-y += core/subdev/mxm/base.o
-nouveau-y += core/subdev/mxm/mxms.o
-nouveau-y += core/subdev/mxm/nv50.o
-nouveau-y += core/subdev/pwr/base.o
-nouveau-y += core/subdev/pwr/memx.o
-nouveau-y += core/subdev/pwr/nva3.o
-nouveau-y += core/subdev/pwr/nvc0.o
-nouveau-y += core/subdev/pwr/nvd0.o
-nouveau-y += core/subdev/pwr/gk104.o
-nouveau-y += core/subdev/pwr/nv108.o
-nouveau-y += core/subdev/therm/base.o
-nouveau-y += core/subdev/therm/fan.o
-nouveau-y += core/subdev/therm/fannil.o
-nouveau-y += core/subdev/therm/fanpwm.o
-nouveau-y += core/subdev/therm/fantog.o
-nouveau-y += core/subdev/therm/ic.o
-nouveau-y += core/subdev/therm/temp.o
-nouveau-y += core/subdev/therm/nv40.o
-nouveau-y += core/subdev/therm/nv50.o
-nouveau-y += core/subdev/therm/nv84.o
-nouveau-y += core/subdev/therm/nva3.o
-nouveau-y += core/subdev/therm/nvd0.o
-nouveau-y += core/subdev/therm/gm107.o
-nouveau-y += core/subdev/timer/base.o
-nouveau-y += core/subdev/timer/nv04.o
-nouveau-y += core/subdev/timer/gk20a.o
-nouveau-y += core/subdev/vm/base.o
-nouveau-y += core/subdev/vm/nv04.o
-nouveau-y += core/subdev/vm/nv41.o
-nouveau-y += core/subdev/vm/nv44.o
-nouveau-y += core/subdev/vm/nv50.o
-nouveau-y += core/subdev/vm/nvc0.o
-nouveau-y += core/subdev/volt/base.o
-nouveau-y += core/subdev/volt/gpio.o
-nouveau-y += core/subdev/volt/nv40.o
-nouveau-y += core/subdev/volt/gk20a.o
-
-nouveau-y += core/engine/falcon.o
-nouveau-y += core/engine/xtensa.o
-nouveau-y += core/engine/dmaobj/base.o
-nouveau-y += core/engine/dmaobj/nv04.o
-nouveau-y += core/engine/dmaobj/nv50.o
-nouveau-y += core/engine/dmaobj/nvc0.o
-nouveau-y += core/engine/dmaobj/nvd0.o
-nouveau-y += core/engine/bsp/nv84.o
-nouveau-y += core/engine/bsp/nv98.o
-nouveau-y += core/engine/bsp/nvc0.o
-nouveau-y += core/engine/bsp/nve0.o
-nouveau-y += core/engine/copy/nva3.o
-nouveau-y += core/engine/copy/nvc0.o
-nouveau-y += core/engine/copy/nve0.o
-nouveau-y += core/engine/crypt/nv84.o
-nouveau-y += core/engine/crypt/nv98.o
-nouveau-y += core/engine/device/acpi.o
-nouveau-y += core/engine/device/base.o
-nouveau-y += core/engine/device/ctrl.o
-nouveau-y += core/engine/device/nv04.o
-nouveau-y += core/engine/device/nv10.o
-nouveau-y += core/engine/device/nv20.o
-nouveau-y += core/engine/device/nv30.o
-nouveau-y += core/engine/device/nv40.o
-nouveau-y += core/engine/device/nv50.o
-nouveau-y += core/engine/device/nvc0.o
-nouveau-y += core/engine/device/nve0.o
-nouveau-y += core/engine/device/gm100.o
-nouveau-y += core/engine/disp/base.o
-nouveau-y += core/engine/disp/conn.o
-nouveau-y += core/engine/disp/outp.o
-nouveau-y += core/engine/disp/outpdp.o
-nouveau-y += core/engine/disp/nv04.o
-nouveau-y += core/engine/disp/nv50.o
-nouveau-y += core/engine/disp/nv84.o
-nouveau-y += core/engine/disp/nv94.o
-nouveau-y += core/engine/disp/nva0.o
-nouveau-y += core/engine/disp/nva3.o
-nouveau-y += core/engine/disp/nvd0.o
-nouveau-y += core/engine/disp/nve0.o
-nouveau-y += core/engine/disp/nvf0.o
-nouveau-y += core/engine/disp/gm107.o
-nouveau-y += core/engine/disp/gm204.o
-nouveau-y += core/engine/disp/dacnv50.o
-nouveau-y += core/engine/disp/dport.o
-nouveau-y += core/engine/disp/hdanva3.o
-nouveau-y += core/engine/disp/hdanvd0.o
-nouveau-y += core/engine/disp/hdminv84.o
-nouveau-y += core/engine/disp/hdminva3.o
-nouveau-y += core/engine/disp/hdminvd0.o
-nouveau-y += core/engine/disp/hdminve0.o
-nouveau-y += core/engine/disp/piornv50.o
-nouveau-y += core/engine/disp/sornv50.o
-nouveau-y += core/engine/disp/sornv94.o
-nouveau-y += core/engine/disp/sornvd0.o
-nouveau-y += core/engine/disp/sorgm204.o
-nouveau-y += core/engine/disp/vga.o
-nouveau-y += core/engine/fifo/base.o
-nouveau-y += core/engine/fifo/nv04.o
-nouveau-y += core/engine/fifo/nv10.o
-nouveau-y += core/engine/fifo/nv17.o
-nouveau-y += core/engine/fifo/nv40.o
-nouveau-y += core/engine/fifo/nv50.o
-nouveau-y += core/engine/fifo/nv84.o
-nouveau-y += core/engine/fifo/nvc0.o
-nouveau-y += core/engine/fifo/nve0.o
-nouveau-y += core/engine/fifo/gk20a.o
-nouveau-y += core/engine/fifo/nv108.o
-nouveau-y += core/engine/graph/ctxnv40.o
-nouveau-y += core/engine/graph/ctxnv50.o
-nouveau-y += core/engine/graph/ctxnvc0.o
-nouveau-y += core/engine/graph/ctxnvc1.o
-nouveau-y += core/engine/graph/ctxnvc4.o
-nouveau-y += core/engine/graph/ctxnvc8.o
-nouveau-y += core/engine/graph/ctxnvd7.o
-nouveau-y += core/engine/graph/ctxnvd9.o
-nouveau-y += core/engine/graph/ctxnve4.o
-nouveau-y += core/engine/graph/ctxgk20a.o
-nouveau-y += core/engine/graph/ctxnvf0.o
-nouveau-y += core/engine/graph/ctxgk110b.o
-nouveau-y += core/engine/graph/ctxnv108.o
-nouveau-y += core/engine/graph/ctxgm107.o
-nouveau-y += core/engine/graph/nv04.o
-nouveau-y += core/engine/graph/nv10.o
-nouveau-y += core/engine/graph/nv20.o
-nouveau-y += core/engine/graph/nv25.o
-nouveau-y += core/engine/graph/nv2a.o
-nouveau-y += core/engine/graph/nv30.o
-nouveau-y += core/engine/graph/nv34.o
-nouveau-y += core/engine/graph/nv35.o
-nouveau-y += core/engine/graph/nv40.o
-nouveau-y += core/engine/graph/nv50.o
-nouveau-y += core/engine/graph/nvc0.o
-nouveau-y += core/engine/graph/nvc1.o
-nouveau-y += core/engine/graph/nvc4.o
-nouveau-y += core/engine/graph/nvc8.o
-nouveau-y += core/engine/graph/nvd7.o
-nouveau-y += core/engine/graph/nvd9.o
-nouveau-y += core/engine/graph/nve4.o
-nouveau-y += core/engine/graph/gk20a.o
-nouveau-y += core/engine/graph/nvf0.o
-nouveau-y += core/engine/graph/gk110b.o
-nouveau-y += core/engine/graph/nv108.o
-nouveau-y += core/engine/graph/gm107.o
-nouveau-y += core/engine/mpeg/nv31.o
-nouveau-y += core/engine/mpeg/nv40.o
-nouveau-y += core/engine/mpeg/nv44.o
-nouveau-y += core/engine/mpeg/nv50.o
-nouveau-y += core/engine/mpeg/nv84.o
-nouveau-y += core/engine/perfmon/base.o
-nouveau-y += core/engine/perfmon/daemon.o
-nouveau-y += core/engine/perfmon/nv40.o
-nouveau-y += core/engine/perfmon/nv50.o
-nouveau-y += core/engine/perfmon/nv84.o
-nouveau-y += core/engine/perfmon/nva3.o
-nouveau-y += core/engine/perfmon/nvc0.o
-nouveau-y += core/engine/perfmon/nve0.o
-nouveau-y += core/engine/perfmon/nvf0.o
-nouveau-y += core/engine/ppp/nv98.o
-nouveau-y += core/engine/ppp/nvc0.o
-nouveau-y += core/engine/software/nv04.o
-nouveau-y += core/engine/software/nv10.o
-nouveau-y += core/engine/software/nv50.o
-nouveau-y += core/engine/software/nvc0.o
-nouveau-y += core/engine/vp/nv84.o
-nouveau-y += core/engine/vp/nv98.o
-nouveau-y += core/engine/vp/nvc0.o
-nouveau-y += core/engine/vp/nve0.o
-
-# nvif
-nouveau-y += nvif/object.o
-nouveau-y += nvif/client.o
-nouveau-y += nvif/device.o
-nouveau-y += nvif/notify.o
-
-# drm/core
-nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
-nouveau-y += nouveau_vga.o nouveau_agp.o
-nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
-nouveau-y += nouveau_prime.o nouveau_abi16.o
-nouveau-y += nouveau_nvif.o nouveau_usif.o
-nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
-nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
-
-# drm/kms
-nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
-nouveau-y += nouveau_connector.o nouveau_dp.o
-nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
-
-# drm/kms/nv04:nv50
-include $(src)/dispnv04/Makefile
-
-# drm/kms/nv50-
-nouveau-y += nv50_display.o
-
-# drm/pm
-nouveau-y += nouveau_hwmon.o nouveau_sysfs.o
-
-# other random bits
-nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
-ifdef CONFIG_X86
-nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
-endif
-nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
-nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
-
-obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
-
-# platform driver
-obj-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c
deleted file mode 100644
index e962433..0000000
--- a/drivers/gpu/drm/nouveau/core/core/client.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <nvif/unpack.h>
-#include <nvif/event.h>
-
-#include <engine/device.h>
-
-struct nvkm_client_notify {
-	struct nouveau_client *client;
-	struct nvkm_notify n;
-	u8 version;
-	u8 size;
-	union {
-		struct nvif_notify_rep_v0 v0;
-	} rep;
-};
-
-static int
-nvkm_client_notify(struct nvkm_notify *n)
-{
-	struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
-	struct nouveau_client *client = notify->client;
-	return client->ntfy(&notify->rep, notify->size, n->data, n->size);
-}
-
-int
-nvkm_client_notify_put(struct nouveau_client *client, int index)
-{
-	if (index < ARRAY_SIZE(client->notify)) {
-		if (client->notify[index]) {
-			nvkm_notify_put(&client->notify[index]->n);
-			return 0;
-		}
-	}
-	return -ENOENT;
-}
-
-int
-nvkm_client_notify_get(struct nouveau_client *client, int index)
-{
-	if (index < ARRAY_SIZE(client->notify)) {
-		if (client->notify[index]) {
-			nvkm_notify_get(&client->notify[index]->n);
-			return 0;
-		}
-	}
-	return -ENOENT;
-}
-
-int
-nvkm_client_notify_del(struct nouveau_client *client, int index)
-{
-	if (index < ARRAY_SIZE(client->notify)) {
-		if (client->notify[index]) {
-			nvkm_notify_fini(&client->notify[index]->n);
-			kfree(client->notify[index]);
-			client->notify[index] = NULL;
-			return 0;
-		}
-	}
-	return -ENOENT;
-}
-
-int
-nvkm_client_notify_new(struct nouveau_object *object,
-		       struct nvkm_event *event, void *data, u32 size)
-{
-	struct nouveau_client *client = nouveau_client(object);
-	struct nvkm_client_notify *notify;
-	union {
-		struct nvif_notify_req_v0 v0;
-	} *req = data;
-	u8  index, reply;
-	int ret;
-
-	for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
-		if (!client->notify[index])
-			break;
-	}
-
-	if (index == ARRAY_SIZE(client->notify))
-		return -ENOSPC;
-
-	notify = kzalloc(sizeof(*notify), GFP_KERNEL);
-	if (!notify)
-		return -ENOMEM;
-
-	nv_ioctl(client, "notify new size %d\n", size);
-	if (nvif_unpack(req->v0, 0, 0, true)) {
-		nv_ioctl(client, "notify new vers %d reply %d route %02x "
-				 "token %llx\n", req->v0.version,
-			 req->v0.reply, req->v0.route, req->v0.token);
-		notify->version = req->v0.version;
-		notify->size = sizeof(notify->rep.v0);
-		notify->rep.v0.version = req->v0.version;
-		notify->rep.v0.route = req->v0.route;
-		notify->rep.v0.token = req->v0.token;
-		reply = req->v0.reply;
-	}
-
-	if (ret == 0) {
-		ret = nvkm_notify_init(object, event, nvkm_client_notify,
-				       false, data, size, reply, &notify->n);
-		if (ret == 0) {
-			client->notify[index] = notify;
-			notify->client = client;
-			return index;
-		}
-	}
-
-	kfree(notify);
-	return ret;
-}
-
-static int
-nouveau_client_devlist(struct nouveau_object *object, void *data, u32 size)
-{
-	union {
-		struct nv_client_devlist_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "client devlist size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "client devlist vers %d count %d\n",
-			 args->v0.version, args->v0.count);
-		if (size == sizeof(args->v0.device[0]) * args->v0.count) {
-			ret = nouveau_device_list(args->v0.device,
-						  args->v0.count);
-			if (ret >= 0) {
-				args->v0.count = ret;
-				ret = 0;
-			}
-		} else {
-			ret = -EINVAL;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nouveau_client_mthd(struct nouveau_object *object, u32 mthd,
-		    void *data, u32 size)
-{
-	switch (mthd) {
-	case NV_CLIENT_DEVLIST:
-		return nouveau_client_devlist(object, data, size);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static void
-nouveau_client_dtor(struct nouveau_object *object)
-{
-	struct nouveau_client *client = (void *)object;
-	int i;
-	for (i = 0; i < ARRAY_SIZE(client->notify); i++)
-		nvkm_client_notify_del(client, i);
-	nouveau_object_ref(NULL, &client->device);
-	nouveau_handle_destroy(client->root);
-	nouveau_namedb_destroy(&client->base);
-}
-
-static struct nouveau_oclass
-nouveau_client_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.dtor = nouveau_client_dtor,
-		.mthd = nouveau_client_mthd,
-	},
-};
-
-int
-nouveau_client_create_(const char *name, u64 devname, const char *cfg,
-		       const char *dbg, int length, void **pobject)
-{
-	struct nouveau_object *device;
-	struct nouveau_client *client;
-	int ret;
-
-	device = (void *)nouveau_device_find(devname);
-	if (!device)
-		return -ENODEV;
-
-	ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,
-				     NV_CLIENT_CLASS, NULL,
-				     (1ULL << NVDEV_ENGINE_DEVICE),
-				     length, pobject);
-	client = *pobject;
-	if (ret)
-		return ret;
-
-	ret = nouveau_handle_create(nv_object(client), ~0, ~0,
-				    nv_object(client), &client->root);
-	if (ret)
-		return ret;
-
-	/* prevent init/fini being called, os in in charge of this */
-	atomic_set(&nv_object(client)->usecount, 2);
-
-	nouveau_object_ref(device, &client->device);
-	snprintf(client->name, sizeof(client->name), "%s", name);
-	client->debug = nouveau_dbgopt(dbg, "CLIENT");
-	return 0;
-}
-
-int
-nouveau_client_init(struct nouveau_client *client)
-{
-	int ret;
-	nv_debug(client, "init running\n");
-	ret = nouveau_handle_init(client->root);
-	nv_debug(client, "init completed with %d\n", ret);
-	return ret;
-}
-
-int
-nouveau_client_fini(struct nouveau_client *client, bool suspend)
-{
-	const char *name[2] = { "fini", "suspend" };
-	int ret, i;
-	nv_debug(client, "%s running\n", name[suspend]);
-	nv_debug(client, "%s notify\n", name[suspend]);
-	for (i = 0; i < ARRAY_SIZE(client->notify); i++)
-		nvkm_client_notify_put(client, i);
-	nv_debug(client, "%s object\n", name[suspend]);
-	ret = nouveau_handle_fini(client->root, suspend);
-	nv_debug(client, "%s completed with %d\n", name[suspend], ret);
-	return ret;
-}
-
-const char *
-nouveau_client_name(void *obj)
-{
-	const char *client_name = "unknown";
-	struct nouveau_client *client = nouveau_client(obj);
-	if (client)
-		client_name = client->name;
-	return client_name;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/engctx.c b/drivers/gpu/drm/nouveau/core/core/engctx.c
deleted file mode 100644
index 84c71fa..0000000
--- a/drivers/gpu/drm/nouveau/core/core/engctx.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/client.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-
-static inline int
-nouveau_engctx_exists(struct nouveau_object *parent,
-		      struct nouveau_engine *engine, void **pobject)
-{
-	struct nouveau_engctx *engctx;
-	struct nouveau_object *parctx;
-
-	list_for_each_entry(engctx, &engine->contexts, head) {
-		parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
-		if (parctx == parent) {
-			atomic_inc(&nv_object(engctx)->refcount);
-			*pobject = engctx;
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-int
-nouveau_engctx_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engobj,
-		       struct nouveau_oclass *oclass,
-		       struct nouveau_object *pargpu,
-		       u32 size, u32 align, u32 flags,
-		       int length, void **pobject)
-{
-	struct nouveau_client *client = nouveau_client(parent);
-	struct nouveau_engine *engine = nv_engine(engobj);
-	struct nouveau_object *engctx;
-	unsigned long save;
-	int ret;
-
-	/* check if this engine already has a context for the parent object,
-	 * and reference it instead of creating a new one
-	 */
-	spin_lock_irqsave(&engine->lock, save);
-	ret = nouveau_engctx_exists(parent, engine, pobject);
-	spin_unlock_irqrestore(&engine->lock, save);
-	if (ret)
-		return ret;
-
-	/* create the new context, supports creating both raw objects and
-	 * objects backed by instance memory
-	 */
-	if (size) {
-		ret = nouveau_gpuobj_create_(parent, engobj, oclass,
-					     NV_ENGCTX_CLASS,
-					     pargpu, size, align, flags,
-					     length, pobject);
-	} else {
-		ret = nouveau_object_create_(parent, engobj, oclass,
-					     NV_ENGCTX_CLASS, length, pobject);
-	}
-
-	engctx = *pobject;
-	if (ret)
-		return ret;
-
-	/* must take the lock again and re-check a context doesn't already
-	 * exist (in case of a race) - the lock had to be dropped before as
-	 * it's not possible to allocate the object with it held.
-	 */
-	spin_lock_irqsave(&engine->lock, save);
-	ret = nouveau_engctx_exists(parent, engine, pobject);
-	if (ret) {
-		spin_unlock_irqrestore(&engine->lock, save);
-		nouveau_object_ref(NULL, &engctx);
-		return ret;
-	}
-
-	if (client->vm)
-		atomic_inc(&client->vm->engref[nv_engidx(engobj)]);
-	list_add(&nv_engctx(engctx)->head, &engine->contexts);
-	nv_engctx(engctx)->addr = ~0ULL;
-	spin_unlock_irqrestore(&engine->lock, save);
-	return 0;
-}
-
-void
-nouveau_engctx_destroy(struct nouveau_engctx *engctx)
-{
-	struct nouveau_object *engobj = nv_object(engctx)->engine;
-	struct nouveau_engine *engine = nv_engine(engobj);
-	struct nouveau_client *client = nouveau_client(engctx);
-	unsigned long save;
-
-	nouveau_gpuobj_unmap(&engctx->vma);
-	spin_lock_irqsave(&engine->lock, save);
-	list_del(&engctx->head);
-	spin_unlock_irqrestore(&engine->lock, save);
-
-	if (client->vm)
-		atomic_dec(&client->vm->engref[nv_engidx(engobj)]);
-
-	if (engctx->base.size)
-		nouveau_gpuobj_destroy(&engctx->base);
-	else
-		nouveau_object_destroy(&engctx->base.base);
-}
-
-int
-nouveau_engctx_init(struct nouveau_engctx *engctx)
-{
-	struct nouveau_object *object = nv_object(engctx);
-	struct nouveau_subdev *subdev = nv_subdev(object->engine);
-	struct nouveau_object *parent;
-	struct nouveau_subdev *pardev;
-	int ret;
-
-	ret = nouveau_gpuobj_init(&engctx->base);
-	if (ret)
-		return ret;
-
-	parent = nv_pclass(object->parent, NV_PARENT_CLASS);
-	pardev = nv_subdev(parent->engine);
-	if (nv_parent(parent)->context_attach) {
-		mutex_lock(&pardev->mutex);
-		ret = nv_parent(parent)->context_attach(parent, object);
-		mutex_unlock(&pardev->mutex);
-	}
-
-	if (ret) {
-		nv_error(parent, "failed to attach %s context, %d\n",
-			 subdev->name, ret);
-		return ret;
-	}
-
-	nv_debug(parent, "attached %s context\n", subdev->name);
-	return 0;
-}
-
-int
-nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
-{
-	struct nouveau_object *object = nv_object(engctx);
-	struct nouveau_subdev *subdev = nv_subdev(object->engine);
-	struct nouveau_object *parent;
-	struct nouveau_subdev *pardev;
-	int ret = 0;
-
-	parent = nv_pclass(object->parent, NV_PARENT_CLASS);
-	pardev = nv_subdev(parent->engine);
-	if (nv_parent(parent)->context_detach) {
-		mutex_lock(&pardev->mutex);
-		ret = nv_parent(parent)->context_detach(parent, suspend, object);
-		mutex_unlock(&pardev->mutex);
-	}
-
-	if (ret) {
-		nv_error(parent, "failed to detach %s context, %d\n",
-			 subdev->name, ret);
-		return ret;
-	}
-
-	nv_debug(parent, "detached %s context\n", subdev->name);
-	return nouveau_gpuobj_fini(&engctx->base, suspend);
-}
-
-int
-_nouveau_engctx_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	struct nouveau_engctx *engctx;
-	int ret;
-
-	ret = nouveau_engctx_create(parent, engine, oclass, NULL, 256, 256,
-				    NVOBJ_FLAG_ZERO_ALLOC, &engctx);
-	*pobject = nv_object(engctx);
-	return ret;
-}
-
-void
-_nouveau_engctx_dtor(struct nouveau_object *object)
-{
-	nouveau_engctx_destroy(nv_engctx(object));
-}
-
-int
-_nouveau_engctx_init(struct nouveau_object *object)
-{
-	return nouveau_engctx_init(nv_engctx(object));
-}
-
-
-int
-_nouveau_engctx_fini(struct nouveau_object *object, bool suspend)
-{
-	return nouveau_engctx_fini(nv_engctx(object), suspend);
-}
-
-struct nouveau_object *
-nouveau_engctx_get(struct nouveau_engine *engine, u64 addr)
-{
-	struct nouveau_engctx *engctx;
-	unsigned long flags;
-
-	spin_lock_irqsave(&engine->lock, flags);
-	list_for_each_entry(engctx, &engine->contexts, head) {
-		if (engctx->addr == addr) {
-			engctx->save = flags;
-			return nv_object(engctx);
-		}
-	}
-	spin_unlock_irqrestore(&engine->lock, flags);
-	return NULL;
-}
-
-void
-nouveau_engctx_put(struct nouveau_object *object)
-{
-	if (object) {
-		struct nouveau_engine *engine = nv_engine(object->engine);
-		struct nouveau_engctx *engctx = nv_engctx(object);
-		spin_unlock_irqrestore(&engine->lock, engctx->save);
-	}
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c
deleted file mode 100644
index 1f6954a..0000000
--- a/drivers/gpu/drm/nouveau/core/core/engine.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/engine.h>
-#include <core/option.h>
-
-int
-nouveau_engine_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engobj,
-		       struct nouveau_oclass *oclass, bool enable,
-		       const char *iname, const char *fname,
-		       int length, void **pobject)
-{
-	struct nouveau_engine *engine;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
-				     iname, fname, length, pobject);
-	engine = *pobject;
-	if (ret)
-		return ret;
-
-	if (parent) {
-		struct nouveau_device *device = nv_device(parent);
-		int engidx = nv_engidx(nv_object(engine));
-
-		if (device->disable_mask & (1ULL << engidx)) {
-			if (!nouveau_boolopt(device->cfgopt, iname, false)) {
-				nv_debug(engine, "engine disabled by hw/fw\n");
-				return -ENODEV;
-			}
-
-			nv_warn(engine, "ignoring hw/fw engine disable\n");
-		}
-
-		if (!nouveau_boolopt(device->cfgopt, iname, enable)) {
-			if (!enable)
-				nv_warn(engine, "disabled, %s=1 to enable\n", iname);
-			return -ENODEV;
-		}
-	}
-
-	INIT_LIST_HEAD(&engine->contexts);
-	spin_lock_init(&engine->lock);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/enum.c b/drivers/gpu/drm/nouveau/core/core/enum.c
deleted file mode 100644
index dd43479..0000000
--- a/drivers/gpu/drm/nouveau/core/core/enum.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2010 Nouveau Project
- *
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include <core/os.h>
-#include <core/enum.h>
-
-const struct nouveau_enum *
-nouveau_enum_find(const struct nouveau_enum *en, u32 value)
-{
-	while (en->name) {
-		if (en->value == value)
-			return en;
-		en++;
-	}
-
-	return NULL;
-}
-
-const struct nouveau_enum *
-nouveau_enum_print(const struct nouveau_enum *en, u32 value)
-{
-	en = nouveau_enum_find(en, value);
-	if (en)
-		pr_cont("%s", en->name);
-	else
-		pr_cont("(unknown enum 0x%08x)", value);
-	return en;
-}
-
-void
-nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
-{
-	while (bf->name) {
-		if (value & bf->mask) {
-			pr_cont(" %s", bf->name);
-			value &= ~bf->mask;
-		}
-
-		bf++;
-	}
-
-	if (value)
-		pr_cont(" (unknown bits 0x%08x)", value);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c
deleted file mode 100644
index 760947e..0000000
--- a/drivers/gpu/drm/nouveau/core/core/event.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2013-2014 Red Hat 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 <core/object.h>
-#include <core/event.h>
-
-void
-nvkm_event_put(struct nvkm_event *event, u32 types, int index)
-{
-	assert_spin_locked(&event->refs_lock);
-	while (types) {
-		int type = __ffs(types); types &= ~(1 << type);
-		if (--event->refs[index * event->types_nr + type] == 0) {
-			if (event->func->fini)
-				event->func->fini(event, 1 << type, index);
-		}
-	}
-}
-
-void
-nvkm_event_get(struct nvkm_event *event, u32 types, int index)
-{
-	assert_spin_locked(&event->refs_lock);
-	while (types) {
-		int type = __ffs(types); types &= ~(1 << type);
-		if (++event->refs[index * event->types_nr + type] == 1) {
-			if (event->func->init)
-				event->func->init(event, 1 << type, index);
-		}
-	}
-}
-
-void
-nvkm_event_send(struct nvkm_event *event, u32 types, int index,
-		void *data, u32 size)
-{
-	struct nvkm_notify *notify;
-	unsigned long flags;
-
-	if (!event->refs || WARN_ON(index >= event->index_nr))
-		return;
-
-	spin_lock_irqsave(&event->list_lock, flags);
-	list_for_each_entry(notify, &event->list, head) {
-		if (notify->index == index && (notify->types & types)) {
-			if (event->func->send) {
-				event->func->send(data, size, notify);
-				continue;
-			}
-			nvkm_notify_send(notify, data, size);
-		}
-	}
-	spin_unlock_irqrestore(&event->list_lock, flags);
-}
-
-void
-nvkm_event_fini(struct nvkm_event *event)
-{
-	if (event->refs) {
-		kfree(event->refs);
-		event->refs = NULL;
-	}
-}
-
-int
-nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
-		struct nvkm_event *event)
-{
-	event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
-			      GFP_KERNEL);
-	if (!event->refs)
-		return -ENOMEM;
-
-	event->func = func;
-	event->types_nr = types_nr;
-	event->index_nr = index_nr;
-	spin_lock_init(&event->refs_lock);
-	spin_lock_init(&event->list_lock);
-	INIT_LIST_HEAD(&event->list);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/drivers/gpu/drm/nouveau/core/core/gpuobj.c
deleted file mode 100644
index daee877..0000000
--- a/drivers/gpu/drm/nouveau/core/core/gpuobj.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/gpuobj.h>
-
-#include <subdev/instmem.h>
-#include <subdev/bar.h>
-#include <subdev/vm.h>
-
-void
-nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
-{
-	int i;
-
-	if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
-		for (i = 0; i < gpuobj->size; i += 4)
-			nv_wo32(gpuobj, i, 0x00000000);
-	}
-
-	if (gpuobj->node) {
-		nouveau_mm_free(&nv_gpuobj(gpuobj->parent)->heap,
-				&gpuobj->node);
-	}
-
-	if (gpuobj->heap.block_size)
-		nouveau_mm_fini(&gpuobj->heap);
-
-	nouveau_object_destroy(&gpuobj->base);
-}
-
-int
-nouveau_gpuobj_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pclass,
-		       struct nouveau_object *pargpu,
-		       u32 size, u32 align, u32 flags,
-		       int length, void **pobject)
-{
-	struct nouveau_instmem *imem = nouveau_instmem(parent);
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nouveau_gpuobj *gpuobj;
-	struct nouveau_mm *heap = NULL;
-	int ret, i;
-	u64 addr;
-
-	*pobject = NULL;
-
-	if (pargpu) {
-		while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
-			if (nv_gpuobj(pargpu)->heap.block_size)
-				break;
-			pargpu = pargpu->parent;
-		}
-
-		if (unlikely(pargpu == NULL)) {
-			nv_error(parent, "no gpuobj heap\n");
-			return -EINVAL;
-		}
-
-		addr =  nv_gpuobj(pargpu)->addr;
-		heap = &nv_gpuobj(pargpu)->heap;
-		atomic_inc(&parent->refcount);
-	} else {
-		ret = imem->alloc(imem, parent, size, align, &parent);
-		pargpu = parent;
-		if (ret)
-			return ret;
-
-		addr = nv_memobj(pargpu)->addr;
-		size = nv_memobj(pargpu)->size;
-
-		if (bar && bar->alloc) {
-			struct nouveau_instobj *iobj = (void *)parent;
-			struct nouveau_mem **mem = (void *)(iobj + 1);
-			struct nouveau_mem *node = *mem;
-			if (!bar->alloc(bar, parent, node, &pargpu)) {
-				nouveau_object_ref(NULL, &parent);
-				parent = pargpu;
-			}
-		}
-	}
-
-	ret = nouveau_object_create_(parent, engine, oclass, pclass |
-				     NV_GPUOBJ_CLASS, length, pobject);
-	nouveau_object_ref(NULL, &parent);
-	gpuobj = *pobject;
-	if (ret)
-		return ret;
-
-	gpuobj->parent = pargpu;
-	gpuobj->flags = flags;
-	gpuobj->addr = addr;
-	gpuobj->size = size;
-
-	if (heap) {
-		ret = nouveau_mm_head(heap, 0, 1, size, size,
-				      max(align, (u32)1), &gpuobj->node);
-		if (ret)
-			return ret;
-
-		gpuobj->addr += gpuobj->node->offset;
-	}
-
-	if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
-		ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
-		if (ret)
-			return ret;
-	}
-
-	if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
-		for (i = 0; i < gpuobj->size; i += 4)
-			nv_wo32(gpuobj, i, 0x00000000);
-	}
-
-	return ret;
-}
-
-struct nouveau_gpuobj_class {
-	struct nouveau_object *pargpu;
-	u64 size;
-	u32 align;
-	u32 flags;
-};
-
-static int
-_nouveau_gpuobj_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj_class *args = data;
-	struct nouveau_gpuobj *object;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
-				    args->size, args->align, args->flags,
-				    &object);
-	*pobject = nv_object(object);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-void
-_nouveau_gpuobj_dtor(struct nouveau_object *object)
-{
-	nouveau_gpuobj_destroy(nv_gpuobj(object));
-}
-
-int
-_nouveau_gpuobj_init(struct nouveau_object *object)
-{
-	return nouveau_gpuobj_init(nv_gpuobj(object));
-}
-
-int
-_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
-{
-	return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
-}
-
-u32
-_nouveau_gpuobj_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
-	struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
-	if (gpuobj->node)
-		addr += gpuobj->node->offset;
-	return pfuncs->rd32(gpuobj->parent, addr);
-}
-
-void
-_nouveau_gpuobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
-	struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
-	if (gpuobj->node)
-		addr += gpuobj->node->offset;
-	pfuncs->wr32(gpuobj->parent, addr, data);
-}
-
-static struct nouveau_oclass
-_nouveau_gpuobj_oclass = {
-	.handle = 0x00000000,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpuobj_ctor,
-		.dtor = _nouveau_gpuobj_dtor,
-		.init = _nouveau_gpuobj_init,
-		.fini = _nouveau_gpuobj_fini,
-		.rd32 = _nouveau_gpuobj_rd32,
-		.wr32 = _nouveau_gpuobj_wr32,
-	},
-};
-
-int
-nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
-		   u32 size, u32 align, u32 flags,
-		   struct nouveau_gpuobj **pgpuobj)
-{
-	struct nouveau_object *engine = parent;
-	struct nouveau_gpuobj_class args = {
-		.pargpu = pargpu,
-		.size = size,
-		.align = align,
-		.flags = flags,
-	};
-
-	if (!nv_iclass(engine, NV_SUBDEV_CLASS))
-		engine = engine->engine;
-	BUG_ON(engine == NULL);
-
-	return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
-				   &args, sizeof(args),
-				   (struct nouveau_object **)pgpuobj);
-}
-
-int
-nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
-		   struct nouveau_vma *vma)
-{
-	struct nouveau_bar *bar = nouveau_bar(gpuobj);
-	int ret = -EINVAL;
-
-	if (bar && bar->umap) {
-		struct nouveau_instobj *iobj = (void *)
-			nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
-		struct nouveau_mem **mem = (void *)(iobj + 1);
-		ret = bar->umap(bar, *mem, access, vma);
-	}
-
-	return ret;
-}
-
-int
-nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
-		      u32 access, struct nouveau_vma *vma)
-{
-	struct nouveau_instobj *iobj = (void *)
-		nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
-	struct nouveau_mem **mem = (void *)(iobj + 1);
-	int ret;
-
-	ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
-	if (ret)
-		return ret;
-
-	nouveau_vm_map(vma, *mem);
-	return 0;
-}
-
-void
-nouveau_gpuobj_unmap(struct nouveau_vma *vma)
-{
-	if (vma->node) {
-		nouveau_vm_unmap(vma);
-		nouveau_vm_put(vma);
-	}
-}
-
-/* the below is basically only here to support sharing the paged dma object
- * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
- * anywhere else.
- */
-
-static void
-nouveau_gpudup_dtor(struct nouveau_object *object)
-{
-	struct nouveau_gpuobj *gpuobj = (void *)object;
-	nouveau_object_ref(NULL, &gpuobj->parent);
-	nouveau_object_destroy(&gpuobj->base);
-}
-
-static struct nouveau_oclass
-nouveau_gpudup_oclass = {
-	.handle = NV_GPUOBJ_CLASS,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.dtor = nouveau_gpudup_dtor,
-		.init = nouveau_object_init,
-		.fini = nouveau_object_fini,
-	},
-};
-
-int
-nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
-		   struct nouveau_gpuobj **pgpuobj)
-{
-	struct nouveau_gpuobj *gpuobj;
-	int ret;
-
-	ret = nouveau_object_create(parent, parent->engine,
-				   &nouveau_gpudup_oclass, 0, &gpuobj);
-	*pgpuobj = gpuobj;
-	if (ret)
-		return ret;
-
-	nouveau_object_ref(nv_object(base), &gpuobj->parent);
-	gpuobj->addr = base->addr;
-	gpuobj->size = base->size;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c
deleted file mode 100644
index 13f816c..0000000
--- a/drivers/gpu/drm/nouveau/core/core/handle.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/handle.h>
-#include <core/client.h>
-
-#define hprintk(h,l,f,a...) do {                                               \
-	struct nouveau_client *c = nouveau_client((h)->object);                \
-	struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0;      \
-	nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a);               \
-} while(0)
-
-int
-nouveau_handle_init(struct nouveau_handle *handle)
-{
-	struct nouveau_handle *item;
-	int ret;
-
-	hprintk(handle, TRACE, "init running\n");
-	ret = nouveau_object_inc(handle->object);
-	if (ret)
-		return ret;
-
-	hprintk(handle, TRACE, "init children\n");
-	list_for_each_entry(item, &handle->tree, head) {
-		ret = nouveau_handle_init(item);
-		if (ret)
-			goto fail;
-	}
-
-	hprintk(handle, TRACE, "init completed\n");
-	return 0;
-fail:
-	hprintk(handle, ERROR, "init failed with %d\n", ret);
-	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
-		nouveau_handle_fini(item, false);
-	}
-
-	nouveau_object_dec(handle->object, false);
-	return ret;
-}
-
-int
-nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
-{
-	static char *name[2] = { "fini", "suspend" };
-	struct nouveau_handle *item;
-	int ret;
-
-	hprintk(handle, TRACE, "%s children\n", name[suspend]);
-	list_for_each_entry(item, &handle->tree, head) {
-		ret = nouveau_handle_fini(item, suspend);
-		if (ret && suspend)
-			goto fail;
-	}
-
-	hprintk(handle, TRACE, "%s running\n", name[suspend]);
-	if (handle->object) {
-		ret = nouveau_object_dec(handle->object, suspend);
-		if (ret && suspend)
-			goto fail;
-	}
-
-	hprintk(handle, TRACE, "%s completed\n", name[suspend]);
-	return 0;
-fail:
-	hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
-	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
-		int rret = nouveau_handle_init(item);
-		if (rret)
-			hprintk(handle, FATAL, "failed to restart, %d\n", rret);
-	}
-
-	return ret;
-}
-
-int
-nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
-		      struct nouveau_object *object,
-		      struct nouveau_handle **phandle)
-{
-	struct nouveau_object *namedb;
-	struct nouveau_handle *handle;
-	int ret;
-
-	namedb = parent;
-	while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
-		namedb = namedb->parent;
-
-	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-	if (!handle)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&handle->head);
-	INIT_LIST_HEAD(&handle->tree);
-	handle->name = _handle;
-	handle->priv = ~0;
-
-	ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
-	if (ret) {
-		kfree(handle);
-		return ret;
-	}
-
-	if (nv_parent(parent)->object_attach) {
-		ret = nv_parent(parent)->object_attach(parent, object, _handle);
-		if (ret < 0) {
-			nouveau_handle_destroy(handle);
-			return ret;
-		}
-
-		handle->priv = ret;
-	}
-
-	if (object != namedb) {
-		while (!nv_iclass(namedb, NV_CLIENT_CLASS))
-			namedb = namedb->parent;
-
-		handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
-		if (handle->parent) {
-			list_add(&handle->head, &handle->parent->tree);
-			nouveau_namedb_put(handle->parent);
-		}
-	}
-
-	hprintk(handle, TRACE, "created\n");
-	*phandle = handle;
-	return 0;
-}
-
-void
-nouveau_handle_destroy(struct nouveau_handle *handle)
-{
-	struct nouveau_handle *item, *temp;
-
-	hprintk(handle, TRACE, "destroy running\n");
-	list_for_each_entry_safe(item, temp, &handle->tree, head) {
-		nouveau_handle_destroy(item);
-	}
-	list_del(&handle->head);
-
-	if (handle->priv != ~0) {
-		struct nouveau_object *parent = handle->parent->object;
-		nv_parent(parent)->object_detach(parent, handle->priv);
-	}
-
-	hprintk(handle, TRACE, "destroy completed\n");
-	nouveau_namedb_remove(handle);
-	kfree(handle);
-}
-
-struct nouveau_object *
-nouveau_handle_ref(struct nouveau_object *parent, u32 name)
-{
-	struct nouveau_object *object = NULL;
-	struct nouveau_handle *handle;
-
-	while (!nv_iclass(parent, NV_NAMEDB_CLASS))
-		parent = parent->parent;
-
-	handle = nouveau_namedb_get(nv_namedb(parent), name);
-	if (handle) {
-		nouveau_object_ref(handle->object, &object);
-		nouveau_namedb_put(handle);
-	}
-
-	return object;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
-{
-	struct nouveau_namedb *namedb;
-	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
-		return nouveau_namedb_get_class(namedb, oclass);
-	return NULL;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
-{
-	struct nouveau_namedb *namedb;
-	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
-		return nouveau_namedb_get_vinst(namedb, vinst);
-	return NULL;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
-{
-	struct nouveau_namedb *namedb;
-	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
-		return nouveau_namedb_get_cinst(namedb, cinst);
-	return NULL;
-}
-
-void
-nouveau_handle_put(struct nouveau_handle *handle)
-{
-	if (handle)
-		nouveau_namedb_put(handle);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/ioctl.c b/drivers/gpu/drm/nouveau/core/core/ioctl.c
deleted file mode 100644
index 692aa92..0000000
--- a/drivers/gpu/drm/nouveau/core/core/ioctl.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/object.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/client.h>
-#include <core/device.h>
-#include <core/ioctl.h>
-#include <core/event.h>
-
-#include <nvif/unpack.h>
-#include <nvif/ioctl.h>
-
-static int
-nvkm_ioctl_nop(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_nop none;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "nop size %d\n", size);
-	if (nvif_unvers(args->none)) {
-		nv_ioctl(object, "nop\n");
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_sclass(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_sclass_v0 v0;
-	} *args = data;
-	int ret;
-
-	if (!nv_iclass(object, NV_PARENT_CLASS)) {
-		nv_debug(object, "cannot have children (sclass)\n");
-		return -ENODEV;
-	}
-
-	nv_ioctl(object, "sclass size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "sclass vers %d count %d\n",
-			 args->v0.version, args->v0.count);
-		if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
-			ret = nouveau_parent_lclass(object, args->v0.oclass,
-							    args->v0.count);
-			if (ret >= 0) {
-				args->v0.count = ret;
-				ret = 0;
-			}
-		} else {
-			ret = -EINVAL;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size)
-{
-	union {
-		struct nvif_ioctl_new_v0 v0;
-	} *args = data;
-	struct nouveau_client *client = nouveau_client(parent->object);
-	struct nouveau_object *engctx = NULL;
-	struct nouveau_object *object = NULL;
-	struct nouveau_object *engine;
-	struct nouveau_oclass *oclass;
-	struct nouveau_handle *handle;
-	u32 _handle, _oclass;
-	int ret;
-
-	nv_ioctl(client, "new size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		_handle = args->v0.handle;
-		_oclass = args->v0.oclass;
-	} else
-		return ret;
-
-	nv_ioctl(client, "new vers %d handle %08x class %08x "
-			 "route %02x token %llx\n",
-		args->v0.version, _handle, _oclass,
-		args->v0.route, args->v0.token);
-
-	if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {
-		nv_debug(parent->object, "cannot have children (ctor)\n");
-		ret = -ENODEV;
-		goto fail_class;
-	}
-
-	/* check that parent supports the requested subclass */
-	ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);
-	if (ret) {
-		nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);
-		goto fail_class;
-	}
-
-	/* make sure engine init has been completed *before* any objects
-	 * it controls are created - the constructors may depend on
-	 * state calculated at init (ie. default context construction)
-	 */
-	if (engine) {
-		ret = nouveau_object_inc(engine);
-		if (ret)
-			goto fail_class;
-	}
-
-	/* if engine requires it, create a context object to insert
-	 * between the parent and its children (eg. PGRAPH context)
-	 */
-	if (engine && nv_engine(engine)->cclass) {
-		ret = nouveau_object_ctor(parent->object, engine,
-					  nv_engine(engine)->cclass,
-					  data, size, &engctx);
-		if (ret)
-			goto fail_engctx;
-	} else {
-		nouveau_object_ref(parent->object, &engctx);
-	}
-
-	/* finally, create new object and bind it to its handle */
-	ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
-	client->data = object;
-	if (ret)
-		goto fail_ctor;
-
-	ret = nouveau_object_inc(object);
-	if (ret)
-		goto fail_init;
-
-	ret = nouveau_handle_create(parent->object, parent->name,
-				    _handle, object, &handle);
-	if (ret)
-		goto fail_handle;
-
-	ret = nouveau_handle_init(handle);
-	handle->route = args->v0.route;
-	handle->token = args->v0.token;
-	if (ret)
-		nouveau_handle_destroy(handle);
-
-fail_handle:
-	nouveau_object_dec(object, false);
-fail_init:
-	nouveau_object_ref(NULL, &object);
-fail_ctor:
-	nouveau_object_ref(NULL, &engctx);
-fail_engctx:
-	if (engine)
-		nouveau_object_dec(engine, false);
-fail_class:
-	return ret;
-}
-
-static int
-nvkm_ioctl_del(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_del none;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "delete size %d\n", size);
-	if (nvif_unvers(args->none)) {
-		nv_ioctl(object, "delete\n");
-		nouveau_handle_fini(handle, false);
-		nouveau_handle_destroy(handle);
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
-	union {
-		struct nvif_ioctl_mthd_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "mthd size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "mthd vers %d mthd %02x\n",
-			 args->v0.version, args->v0.method);
-		if (ret = -ENODEV, ofuncs->mthd)
-			ret = ofuncs->mthd(object, args->v0.method, data, size);
-	}
-
-	return ret;
-}
-
-
-static int
-nvkm_ioctl_rd(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
-	union {
-		struct nvif_ioctl_rd_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "rd size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
-			args->v0.version, args->v0.size, args->v0.addr);
-		switch (args->v0.size) {
-		case 1:
-			if (ret = -ENODEV, ofuncs->rd08) {
-				args->v0.data = nv_ro08(object, args->v0.addr);
-				ret = 0;
-			}
-			break;
-		case 2:
-			if (ret = -ENODEV, ofuncs->rd16) {
-				args->v0.data = nv_ro16(object, args->v0.addr);
-				ret = 0;
-			}
-			break;
-		case 4:
-			if (ret = -ENODEV, ofuncs->rd32) {
-				args->v0.data = nv_ro32(object, args->v0.addr);
-				ret = 0;
-			}
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_wr(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
-	union {
-		struct nvif_ioctl_wr_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "wr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
-			 args->v0.version, args->v0.size, args->v0.addr,
-			 args->v0.data);
-		switch (args->v0.size) {
-		case 1:
-			if (ret = -ENODEV, ofuncs->wr08) {
-				nv_wo08(object, args->v0.addr, args->v0.data);
-				ret = 0;
-			}
-			break;
-		case 2:
-			if (ret = -ENODEV, ofuncs->wr16) {
-				nv_wo16(object, args->v0.addr, args->v0.data);
-				ret = 0;
-			}
-			break;
-		case 4:
-			if (ret = -ENODEV, ofuncs->wr32) {
-				nv_wo32(object, args->v0.addr, args->v0.data);
-				ret = 0;
-			}
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_map(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
-	union {
-		struct nvif_ioctl_map_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "map size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "map vers %d\n", args->v0.version);
-		if (ret = -ENODEV, ofuncs->map) {
-			ret = ofuncs->map(object, &args->v0.handle,
-						  &args->v0.length);
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_unmap none;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "unmap size %d\n", size);
-	if (nvif_unvers(args->none)) {
-		nv_ioctl(object, "unmap\n");
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_object *object = handle->object;
-	struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
-	union {
-		struct nvif_ioctl_ntfy_new_v0 v0;
-	} *args = data;
-	struct nvkm_event *event;
-	int ret;
-
-	nv_ioctl(object, "ntfy new size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "ntfy new vers %d event %02x\n",
-			 args->v0.version, args->v0.event);
-		if (ret = -ENODEV, ofuncs->ntfy)
-			ret = ofuncs->ntfy(object, args->v0.event, &event);
-		if (ret == 0) {
-			ret = nvkm_client_notify_new(object, event, data, size);
-			if (ret >= 0) {
-				args->v0.index = ret;
-				ret = 0;
-			}
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_del(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_client *client = nouveau_client(handle->object);
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_ntfy_del_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "ntfy del size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "ntfy del vers %d index %d\n",
-			 args->v0.version, args->v0.index);
-		ret = nvkm_client_notify_del(client, args->v0.index);
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_get(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_client *client = nouveau_client(handle->object);
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_ntfy_get_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "ntfy get size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "ntfy get vers %d index %d\n",
-			 args->v0.version, args->v0.index);
-		ret = nvkm_client_notify_get(client, args->v0.index);
-	}
-
-	return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_put(struct nouveau_handle *handle, void *data, u32 size)
-{
-	struct nouveau_client *client = nouveau_client(handle->object);
-	struct nouveau_object *object = handle->object;
-	union {
-		struct nvif_ioctl_ntfy_put_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "ntfy put size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "ntfy put vers %d index %d\n",
-			 args->v0.version, args->v0.index);
-		ret = nvkm_client_notify_put(client, args->v0.index);
-	}
-
-	return ret;
-}
-
-static struct {
-	int version;
-	int (*func)(struct nouveau_handle *, void *, u32);
-}
-nvkm_ioctl_v0[] = {
-	{ 0x00, nvkm_ioctl_nop },
-	{ 0x00, nvkm_ioctl_sclass },
-	{ 0x00, nvkm_ioctl_new },
-	{ 0x00, nvkm_ioctl_del },
-	{ 0x00, nvkm_ioctl_mthd },
-	{ 0x00, nvkm_ioctl_rd },
-	{ 0x00, nvkm_ioctl_wr },
-	{ 0x00, nvkm_ioctl_map },
-	{ 0x00, nvkm_ioctl_unmap },
-	{ 0x00, nvkm_ioctl_ntfy_new },
-	{ 0x00, nvkm_ioctl_ntfy_del },
-	{ 0x00, nvkm_ioctl_ntfy_get },
-	{ 0x00, nvkm_ioctl_ntfy_put },
-};
-
-static int
-nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,
-		  u32 *path, void *data, u32 size,
-		  u8 owner, u8 *route, u64 *token)
-{
-	struct nouveau_handle *handle = parent;
-	struct nouveau_namedb *namedb;
-	struct nouveau_object *object;
-	int ret;
-
-	while ((object = parent->object), nr--) {
-		nv_ioctl(object, "path 0x%08x\n", path[nr]);
-		if (!nv_iclass(object, NV_PARENT_CLASS)) {
-			nv_debug(object, "cannot have children (path)\n");
-			return -EINVAL;
-		}
-
-		if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
-		    !(handle = nouveau_namedb_get(namedb, path[nr]))) {
-			nv_debug(object, "handle 0x%08x not found\n", path[nr]);
-			return -ENOENT;
-		}
-		nouveau_namedb_put(handle);
-		parent = handle;
-	}
-
-	if (owner != NVIF_IOCTL_V0_OWNER_ANY &&
-	    owner != handle->route) {
-		nv_ioctl(object, "object route != owner\n");
-		return -EACCES;
-	}
-	*route = handle->route;
-	*token = handle->token;
-
-	if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
-		if (nvkm_ioctl_v0[type].version == 0) {
-			ret = nvkm_ioctl_v0[type].func(handle, data, size);
-		}
-	}
-
-	return ret;
-}
-
-int
-nvkm_ioctl(struct nouveau_client *client, bool supervisor,
-	   void *data, u32 size, void **hack)
-{
-	union {
-		struct nvif_ioctl_v0 v0;
-	} *args = data;
-	int ret;
-
-	client->super = supervisor;
-	nv_ioctl(client, "size %d\n", size);
-
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
-			 args->v0.version, args->v0.type, args->v0.path_nr,
-			 args->v0.owner);
-		ret = nvkm_ioctl_path(client->root, args->v0.type,
-				      args->v0.path_nr, args->v0.path,
-				      data, size, args->v0.owner,
-				     &args->v0.route, &args->v0.token);
-	}
-
-	nv_ioctl(client, "return %d\n", ret);
-	if (hack) {
-		*hack = client->data;
-		client->data = NULL;
-	}
-	client->super = false;
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
deleted file mode 100644
index b4f5db6..0000000
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/os.h"
-#include "core/mm.h"
-
-#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
-	list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
-
-static void
-nouveau_mm_dump(struct nouveau_mm *mm, const char *header)
-{
-	struct nouveau_mm_node *node;
-
-	printk(KERN_ERR "nouveau: %s\n", header);
-	printk(KERN_ERR "nouveau: node list:\n");
-	list_for_each_entry(node, &mm->nodes, nl_entry) {
-		printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
-		       node->offset, node->length, node->type);
-	}
-	printk(KERN_ERR "nouveau: free list:\n");
-	list_for_each_entry(node, &mm->free, fl_entry) {
-		printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
-		       node->offset, node->length, node->type);
-	}
-}
-
-void
-nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
-{
-	struct nouveau_mm_node *this = *pthis;
-
-	if (this) {
-		struct nouveau_mm_node *prev = node(this, prev);
-		struct nouveau_mm_node *next = node(this, next);
-
-		if (prev && prev->type == NVKM_MM_TYPE_NONE) {
-			prev->length += this->length;
-			list_del(&this->nl_entry);
-			kfree(this); this = prev;
-		}
-
-		if (next && next->type == NVKM_MM_TYPE_NONE) {
-			next->offset  = this->offset;
-			next->length += this->length;
-			if (this->type == NVKM_MM_TYPE_NONE)
-				list_del(&this->fl_entry);
-			list_del(&this->nl_entry);
-			kfree(this); this = NULL;
-		}
-
-		if (this && this->type != NVKM_MM_TYPE_NONE) {
-			list_for_each_entry(prev, &mm->free, fl_entry) {
-				if (this->offset < prev->offset)
-					break;
-			}
-
-			list_add_tail(&this->fl_entry, &prev->fl_entry);
-			this->type = NVKM_MM_TYPE_NONE;
-		}
-	}
-
-	*pthis = NULL;
-}
-
-static struct nouveau_mm_node *
-region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
-{
-	struct nouveau_mm_node *b;
-
-	if (a->length == size)
-		return a;
-
-	b = kmalloc(sizeof(*b), GFP_KERNEL);
-	if (unlikely(b == NULL))
-		return NULL;
-
-	b->offset = a->offset;
-	b->length = size;
-	b->heap   = a->heap;
-	b->type   = a->type;
-	a->offset += size;
-	a->length -= size;
-	list_add_tail(&b->nl_entry, &a->nl_entry);
-	if (b->type == NVKM_MM_TYPE_NONE)
-		list_add_tail(&b->fl_entry, &a->fl_entry);
-	return b;
-}
-
-int
-nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
-		u32 size_min, u32 align, struct nouveau_mm_node **pnode)
-{
-	struct nouveau_mm_node *prev, *this, *next;
-	u32 mask = align - 1;
-	u32 splitoff;
-	u32 s, e;
-
-	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
-
-	list_for_each_entry(this, &mm->free, fl_entry) {
-		if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
-			if (this->heap != heap)
-				continue;
-		}
-		e = this->offset + this->length;
-		s = this->offset;
-
-		prev = node(this, prev);
-		if (prev && prev->type != type)
-			s = roundup(s, mm->block_size);
-
-		next = node(this, next);
-		if (next && next->type != type)
-			e = rounddown(e, mm->block_size);
-
-		s  = (s + mask) & ~mask;
-		e &= ~mask;
-		if (s > e || e - s < size_min)
-			continue;
-
-		splitoff = s - this->offset;
-		if (splitoff && !region_head(mm, this, splitoff))
-			return -ENOMEM;
-
-		this = region_head(mm, this, min(size_max, e - s));
-		if (!this)
-			return -ENOMEM;
-
-		this->type = type;
-		list_del(&this->fl_entry);
-		*pnode = this;
-		return 0;
-	}
-
-	return -ENOSPC;
-}
-
-static struct nouveau_mm_node *
-region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
-{
-	struct nouveau_mm_node *b;
-
-	if (a->length == size)
-		return a;
-
-	b = kmalloc(sizeof(*b), GFP_KERNEL);
-	if (unlikely(b == NULL))
-		return NULL;
-
-	a->length -= size;
-	b->offset  = a->offset + a->length;
-	b->length  = size;
-	b->heap    = a->heap;
-	b->type    = a->type;
-
-	list_add(&b->nl_entry, &a->nl_entry);
-	if (b->type == NVKM_MM_TYPE_NONE)
-		list_add(&b->fl_entry, &a->fl_entry);
-	return b;
-}
-
-int
-nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
-		u32 size_min, u32 align, struct nouveau_mm_node **pnode)
-{
-	struct nouveau_mm_node *prev, *this, *next;
-	u32 mask = align - 1;
-
-	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
-
-	list_for_each_entry_reverse(this, &mm->free, fl_entry) {
-		u32 e = this->offset + this->length;
-		u32 s = this->offset;
-		u32 c = 0, a;
-		if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
-			if (this->heap != heap)
-				continue;
-		}
-
-		prev = node(this, prev);
-		if (prev && prev->type != type)
-			s = roundup(s, mm->block_size);
-
-		next = node(this, next);
-		if (next && next->type != type) {
-			e = rounddown(e, mm->block_size);
-			c = next->offset - e;
-		}
-
-		s = (s + mask) & ~mask;
-		a = e - s;
-		if (s > e || a < size_min)
-			continue;
-
-		a  = min(a, size_max);
-		s  = (e - a) & ~mask;
-		c += (e - s) - a;
-
-		if (c && !region_tail(mm, this, c))
-			return -ENOMEM;
-
-		this = region_tail(mm, this, a);
-		if (!this)
-			return -ENOMEM;
-
-		this->type = type;
-		list_del(&this->fl_entry);
-		*pnode = this;
-		return 0;
-	}
-
-	return -ENOSPC;
-}
-
-int
-nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
-{
-	struct nouveau_mm_node *node, *prev;
-	u32 next;
-
-	if (nouveau_mm_initialised(mm)) {
-		prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
-		next = prev->offset + prev->length;
-		if (next != offset) {
-			BUG_ON(next > offset);
-			if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
-				return -ENOMEM;
-			node->type   = NVKM_MM_TYPE_HOLE;
-			node->offset = next;
-			node->length = offset - next;
-			list_add_tail(&node->nl_entry, &mm->nodes);
-		}
-		BUG_ON(block != mm->block_size);
-	} else {
-		INIT_LIST_HEAD(&mm->nodes);
-		INIT_LIST_HEAD(&mm->free);
-		mm->block_size = block;
-		mm->heap_nodes = 0;
-	}
-
-	node = kzalloc(sizeof(*node), GFP_KERNEL);
-	if (!node)
-		return -ENOMEM;
-
-	if (length) {
-		node->offset  = roundup(offset, mm->block_size);
-		node->length  = rounddown(offset + length, mm->block_size);
-		node->length -= node->offset;
-	}
-
-	list_add_tail(&node->nl_entry, &mm->nodes);
-	list_add_tail(&node->fl_entry, &mm->free);
-	node->heap = ++mm->heap_nodes;
-	return 0;
-}
-
-int
-nouveau_mm_fini(struct nouveau_mm *mm)
-{
-	struct nouveau_mm_node *node, *temp;
-	int nodes = 0;
-
-	if (!nouveau_mm_initialised(mm))
-		return 0;
-
-	list_for_each_entry(node, &mm->nodes, nl_entry) {
-		if (node->type != NVKM_MM_TYPE_HOLE) {
-			if (++nodes > mm->heap_nodes) {
-				nouveau_mm_dump(mm, "mm not clean!");
-				return -EBUSY;
-			}
-		}
-	}
-
-	list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
-		list_del(&node->nl_entry);
-		kfree(node);
-	}
-	mm->heap_nodes = 0;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/namedb.c b/drivers/gpu/drm/nouveau/core/core/namedb.c
deleted file mode 100644
index 0594a59..0000000
--- a/drivers/gpu/drm/nouveau/core/core/namedb.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-
-static struct nouveau_handle *
-nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)
-{
-	struct nouveau_handle *handle;
-
-	list_for_each_entry(handle, &namedb->list, node) {
-		if (handle->name == name)
-			return handle;
-	}
-
-	return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass)
-{
-	struct nouveau_handle *handle;
-
-	list_for_each_entry(handle, &namedb->list, node) {
-		if (nv_mclass(handle->object) == oclass)
-			return handle;
-	}
-
-	return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst)
-{
-	struct nouveau_handle *handle;
-
-	list_for_each_entry(handle, &namedb->list, node) {
-		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
-			if (nv_gpuobj(handle->object)->addr == vinst)
-				return handle;
-		}
-	}
-
-	return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst)
-{
-	struct nouveau_handle *handle;
-
-	list_for_each_entry(handle, &namedb->list, node) {
-		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
-			if (nv_gpuobj(handle->object)->node &&
-			    nv_gpuobj(handle->object)->node->offset == cinst)
-				return handle;
-		}
-	}
-
-	return NULL;
-}
-
-int
-nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,
-		      struct nouveau_object *object,
-		      struct nouveau_handle *handle)
-{
-	int ret = -EEXIST;
-	write_lock_irq(&namedb->lock);
-	if (!nouveau_namedb_lookup(namedb, name)) {
-		nouveau_object_ref(object, &handle->object);
-		handle->namedb = namedb;
-		list_add(&handle->node, &namedb->list);
-		ret = 0;
-	}
-	write_unlock_irq(&namedb->lock);
-	return ret;
-}
-
-void
-nouveau_namedb_remove(struct nouveau_handle *handle)
-{
-	struct nouveau_namedb *namedb = handle->namedb;
-	struct nouveau_object *object = handle->object;
-	write_lock_irq(&namedb->lock);
-	list_del(&handle->node);
-	write_unlock_irq(&namedb->lock);
-	nouveau_object_ref(NULL, &object);
-}
-
-struct nouveau_handle *
-nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)
-{
-	struct nouveau_handle *handle;
-	read_lock(&namedb->lock);
-	handle = nouveau_namedb_lookup(namedb, name);
-	if (handle == NULL)
-		read_unlock(&namedb->lock);
-	return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass)
-{
-	struct nouveau_handle *handle;
-	read_lock(&namedb->lock);
-	handle = nouveau_namedb_lookup_class(namedb, oclass);
-	if (handle == NULL)
-		read_unlock(&namedb->lock);
-	return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst)
-{
-	struct nouveau_handle *handle;
-	read_lock(&namedb->lock);
-	handle = nouveau_namedb_lookup_vinst(namedb, vinst);
-	if (handle == NULL)
-		read_unlock(&namedb->lock);
-	return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst)
-{
-	struct nouveau_handle *handle;
-	read_lock(&namedb->lock);
-	handle = nouveau_namedb_lookup_cinst(namedb, cinst);
-	if (handle == NULL)
-		read_unlock(&namedb->lock);
-	return handle;
-}
-
-void
-nouveau_namedb_put(struct nouveau_handle *handle)
-{
-	if (handle)
-		read_unlock(&handle->namedb->lock);
-}
-
-int
-nouveau_namedb_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pclass,
-		       struct nouveau_oclass *sclass, u64 engcls,
-		       int length, void **pobject)
-{
-	struct nouveau_namedb *namedb;
-	int ret;
-
-	ret = nouveau_parent_create_(parent, engine, oclass, pclass |
-				     NV_NAMEDB_CLASS, sclass, engcls,
-				     length, pobject);
-	namedb = *pobject;
-	if (ret)
-		return ret;
-
-	rwlock_init(&namedb->lock);
-	INIT_LIST_HEAD(&namedb->list);
-	return 0;
-}
-
-int
-_nouveau_namedb_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	struct nouveau_namedb *object;
-	int ret;
-
-	ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
-	*pobject = nv_object(object);
-	if (ret)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/notify.c b/drivers/gpu/drm/nouveau/core/core/notify.c
deleted file mode 100644
index 839a325..0000000
--- a/drivers/gpu/drm/nouveau/core/core/notify.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/client.h>
-#include <core/event.h>
-#include <core/notify.h>
-
-#include <nvif/unpack.h>
-#include <nvif/event.h>
-
-static inline void
-nvkm_notify_put_locked(struct nvkm_notify *notify)
-{
-	if (notify->block++ == 0)
-		nvkm_event_put(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_put(struct nvkm_notify *notify)
-{
-	struct nvkm_event *event = notify->event;
-	unsigned long flags;
-	if (likely(event) &&
-	    test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
-		spin_lock_irqsave(&event->refs_lock, flags);
-		nvkm_notify_put_locked(notify);
-		spin_unlock_irqrestore(&event->refs_lock, flags);
-		if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
-			flush_work(&notify->work);
-	}
-}
-
-static inline void
-nvkm_notify_get_locked(struct nvkm_notify *notify)
-{
-	if (--notify->block == 0)
-		nvkm_event_get(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_get(struct nvkm_notify *notify)
-{
-	struct nvkm_event *event = notify->event;
-	unsigned long flags;
-	if (likely(event) &&
-	    !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
-		spin_lock_irqsave(&event->refs_lock, flags);
-		nvkm_notify_get_locked(notify);
-		spin_unlock_irqrestore(&event->refs_lock, flags);
-	}
-}
-
-static inline void
-nvkm_notify_func(struct nvkm_notify *notify)
-{
-	struct nvkm_event *event = notify->event;
-	int ret = notify->func(notify);
-	unsigned long flags;
-	if ((ret == NVKM_NOTIFY_KEEP) ||
-	    !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
-		spin_lock_irqsave(&event->refs_lock, flags);
-		nvkm_notify_get_locked(notify);
-		spin_unlock_irqrestore(&event->refs_lock, flags);
-	}
-}
-
-static void
-nvkm_notify_work(struct work_struct *work)
-{
-	struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
-	nvkm_notify_func(notify);
-}
-
-void
-nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
-{
-	struct nvkm_event *event = notify->event;
-	unsigned long flags;
-
-	assert_spin_locked(&event->list_lock);
-	BUG_ON(size != notify->size);
-
-	spin_lock_irqsave(&event->refs_lock, flags);
-	if (notify->block) {
-		spin_unlock_irqrestore(&event->refs_lock, flags);
-		return;
-	}
-	nvkm_notify_put_locked(notify);
-	spin_unlock_irqrestore(&event->refs_lock, flags);
-
-	if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
-		memcpy((void *)notify->data, data, size);
-		schedule_work(&notify->work);
-	} else {
-		notify->data = data;
-		nvkm_notify_func(notify);
-		notify->data = NULL;
-	}
-}
-
-void
-nvkm_notify_fini(struct nvkm_notify *notify)
-{
-	unsigned long flags;
-	if (notify->event) {
-		nvkm_notify_put(notify);
-		spin_lock_irqsave(&notify->event->list_lock, flags);
-		list_del(&notify->head);
-		spin_unlock_irqrestore(&notify->event->list_lock, flags);
-		kfree((void *)notify->data);
-		notify->event = NULL;
-	}
-}
-
-int
-nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event,
-		 int (*func)(struct nvkm_notify *), bool work,
-		 void *data, u32 size, u32 reply,
-		 struct nvkm_notify *notify)
-{
-	unsigned long flags;
-	int ret = -ENODEV;
-	if ((notify->event = event), event->refs) {
-		ret = event->func->ctor(object, data, size, notify);
-		if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
-			notify->flags = 0;
-			notify->block = 1;
-			notify->func = func;
-			notify->data = NULL;
-			if (ret = 0, work) {
-				INIT_WORK(&notify->work, nvkm_notify_work);
-				set_bit(NVKM_NOTIFY_WORK, &notify->flags);
-				notify->data = kmalloc(reply, GFP_KERNEL);
-				if (!notify->data)
-					ret = -ENOMEM;
-			}
-		}
-		if (ret == 0) {
-			spin_lock_irqsave(&event->list_lock, flags);
-			list_add_tail(&notify->head, &event->list);
-			spin_unlock_irqrestore(&event->list_lock, flags);
-		}
-	}
-	if (ret)
-		notify->event = NULL;
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c
deleted file mode 100644
index b086305..0000000
--- a/drivers/gpu/drm/nouveau/core/core/object.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/engine.h>
-
-#ifdef NOUVEAU_OBJECT_MAGIC
-static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
-static DEFINE_SPINLOCK(_objlist_lock);
-#endif
-
-int
-nouveau_object_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pclass,
-		       int size, void **pobject)
-{
-	struct nouveau_object *object;
-
-	object = *pobject = kzalloc(size, GFP_KERNEL);
-	if (!object)
-		return -ENOMEM;
-
-	nouveau_object_ref(parent, &object->parent);
-	nouveau_object_ref(engine, &object->engine);
-	object->oclass = oclass;
-	object->oclass->handle |= pclass;
-	atomic_set(&object->refcount, 1);
-	atomic_set(&object->usecount, 0);
-
-#ifdef NOUVEAU_OBJECT_MAGIC
-	object->_magic = NOUVEAU_OBJECT_MAGIC;
-	spin_lock(&_objlist_lock);
-	list_add(&object->list, &_objlist);
-	spin_unlock(&_objlist_lock);
-#endif
-	return 0;
-}
-
-int
-_nouveau_object_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	if (size != 0)
-		return -ENOSYS;
-	return nouveau_object_create(parent, engine, oclass, 0, pobject);
-}
-
-void
-nouveau_object_destroy(struct nouveau_object *object)
-{
-#ifdef NOUVEAU_OBJECT_MAGIC
-	spin_lock(&_objlist_lock);
-	list_del(&object->list);
-	spin_unlock(&_objlist_lock);
-#endif
-	nouveau_object_ref(NULL, &object->engine);
-	nouveau_object_ref(NULL, &object->parent);
-	kfree(object);
-}
-
-int
-nouveau_object_init(struct nouveau_object *object)
-{
-	return 0;
-}
-
-int
-nouveau_object_fini(struct nouveau_object *object, bool suspend)
-{
-	return 0;
-}
-
-struct nouveau_ofuncs
-nouveau_object_ofuncs = {
-	.ctor = _nouveau_object_ctor,
-	.dtor = nouveau_object_destroy,
-	.init = nouveau_object_init,
-	.fini = nouveau_object_fini,
-};
-
-int
-nouveau_object_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
-	struct nouveau_object *object = NULL;
-	int ret;
-
-	ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
-	*pobject = object;
-	if (ret < 0) {
-		if (ret != -ENODEV) {
-			nv_error(parent, "failed to create 0x%08x, %d\n",
-				 oclass->handle, ret);
-		}
-
-		if (object) {
-			ofuncs->dtor(object);
-			*pobject = NULL;
-		}
-
-		return ret;
-	}
-
-	if (ret == 0) {
-		nv_trace(object, "created\n");
-		atomic_set(&object->refcount, 1);
-	}
-
-	return 0;
-}
-
-static void
-nouveau_object_dtor(struct nouveau_object *object)
-{
-	nv_trace(object, "destroying\n");
-	nv_ofuncs(object)->dtor(object);
-}
-
-void
-nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
-{
-	if (obj) {
-		atomic_inc(&obj->refcount);
-		nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
-	}
-
-	if (*ref) {
-		int dead = atomic_dec_and_test(&(*ref)->refcount);
-		nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
-		if (dead)
-			nouveau_object_dtor(*ref);
-	}
-
-	*ref = obj;
-}
-
-int
-nouveau_object_inc(struct nouveau_object *object)
-{
-	int ref = atomic_add_return(1, &object->usecount);
-	int ret;
-
-	nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
-	if (ref != 1)
-		return 0;
-
-	nv_trace(object, "initialising...\n");
-	if (object->parent) {
-		ret = nouveau_object_inc(object->parent);
-		if (ret) {
-			nv_error(object, "parent failed, %d\n", ret);
-			goto fail_parent;
-		}
-	}
-
-	if (object->engine) {
-		mutex_lock(&nv_subdev(object->engine)->mutex);
-		ret = nouveau_object_inc(object->engine);
-		mutex_unlock(&nv_subdev(object->engine)->mutex);
-		if (ret) {
-			nv_error(object, "engine failed, %d\n", ret);
-			goto fail_engine;
-		}
-	}
-
-	ret = nv_ofuncs(object)->init(object);
-	atomic_set(&object->usecount, 1);
-	if (ret) {
-		nv_error(object, "init failed, %d\n", ret);
-		goto fail_self;
-	}
-
-	nv_trace(object, "initialised\n");
-	return 0;
-
-fail_self:
-	if (object->engine) {
-		mutex_lock(&nv_subdev(object->engine)->mutex);
-		nouveau_object_dec(object->engine, false);
-		mutex_unlock(&nv_subdev(object->engine)->mutex);
-	}
-fail_engine:
-	if (object->parent)
-		 nouveau_object_dec(object->parent, false);
-fail_parent:
-	atomic_dec(&object->usecount);
-	return ret;
-}
-
-static int
-nouveau_object_decf(struct nouveau_object *object)
-{
-	int ret;
-
-	nv_trace(object, "stopping...\n");
-
-	ret = nv_ofuncs(object)->fini(object, false);
-	atomic_set(&object->usecount, 0);
-	if (ret)
-		nv_warn(object, "failed fini, %d\n", ret);
-
-	if (object->engine) {
-		mutex_lock(&nv_subdev(object->engine)->mutex);
-		nouveau_object_dec(object->engine, false);
-		mutex_unlock(&nv_subdev(object->engine)->mutex);
-	}
-
-	if (object->parent)
-		nouveau_object_dec(object->parent, false);
-
-	nv_trace(object, "stopped\n");
-	return 0;
-}
-
-static int
-nouveau_object_decs(struct nouveau_object *object)
-{
-	int ret, rret;
-
-	nv_trace(object, "suspending...\n");
-
-	ret = nv_ofuncs(object)->fini(object, true);
-	atomic_set(&object->usecount, 0);
-	if (ret) {
-		nv_error(object, "failed suspend, %d\n", ret);
-		return ret;
-	}
-
-	if (object->engine) {
-		mutex_lock(&nv_subdev(object->engine)->mutex);
-		ret = nouveau_object_dec(object->engine, true);
-		mutex_unlock(&nv_subdev(object->engine)->mutex);
-		if (ret) {
-			nv_warn(object, "engine failed suspend, %d\n", ret);
-			goto fail_engine;
-		}
-	}
-
-	if (object->parent) {
-		ret = nouveau_object_dec(object->parent, true);
-		if (ret) {
-			nv_warn(object, "parent failed suspend, %d\n", ret);
-			goto fail_parent;
-		}
-	}
-
-	nv_trace(object, "suspended\n");
-	return 0;
-
-fail_parent:
-	if (object->engine) {
-		mutex_lock(&nv_subdev(object->engine)->mutex);
-		rret = nouveau_object_inc(object->engine);
-		mutex_unlock(&nv_subdev(object->engine)->mutex);
-		if (rret)
-			nv_fatal(object, "engine failed to reinit, %d\n", rret);
-	}
-
-fail_engine:
-	rret = nv_ofuncs(object)->init(object);
-	if (rret)
-		nv_fatal(object, "failed to reinit, %d\n", rret);
-
-	return ret;
-}
-
-int
-nouveau_object_dec(struct nouveau_object *object, bool suspend)
-{
-	int ref = atomic_add_return(-1, &object->usecount);
-	int ret;
-
-	nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
-
-	if (ref == 0) {
-		if (suspend)
-			ret = nouveau_object_decs(object);
-		else
-			ret = nouveau_object_decf(object);
-
-		if (ret) {
-			atomic_inc(&object->usecount);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-void
-nouveau_object_debug(void)
-{
-#ifdef NOUVEAU_OBJECT_MAGIC
-	struct nouveau_object *object;
-	if (!list_empty(&_objlist)) {
-		nv_fatal(NULL, "*******************************************\n");
-		nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
-		nv_fatal(NULL, "*******************************************\n");
-		list_for_each_entry(object, &_objlist, list) {
-			nv_fatal(object, "%p/%p/%d/%d\n",
-				 object->parent, object->engine,
-				 atomic_read(&object->refcount),
-				 atomic_read(&object->usecount));
-		}
-	}
-#endif
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/option.c b/drivers/gpu/drm/nouveau/core/core/option.c
deleted file mode 100644
index 9f6fcc5..0000000
--- a/drivers/gpu/drm/nouveau/core/core/option.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-#include <core/debug.h>
-
-const char *
-nouveau_stropt(const char *optstr, const char *opt, int *arglen)
-{
-	while (optstr && *optstr != '\0') {
-		int len = strcspn(optstr, ",=");
-		switch (optstr[len]) {
-		case '=':
-			if (!strncasecmpz(optstr, opt, len)) {
-				optstr += len + 1;
-				*arglen = strcspn(optstr, ",=");
-				return *arglen ? optstr : NULL;
-			}
-			optstr++;
-			break;
-		case ',':
-			optstr++;
-			break;
-		default:
-			break;
-		}
-		optstr += len;
-	}
-
-	return NULL;
-}
-
-bool
-nouveau_boolopt(const char *optstr, const char *opt, bool value)
-{
-	int arglen;
-
-	optstr = nouveau_stropt(optstr, opt, &arglen);
-	if (optstr) {
-		if (!strncasecmpz(optstr, "0", arglen) ||
-		    !strncasecmpz(optstr, "no", arglen) ||
-		    !strncasecmpz(optstr, "off", arglen) ||
-		    !strncasecmpz(optstr, "false", arglen))
-			value = false;
-		else
-		if (!strncasecmpz(optstr, "1", arglen) ||
-		    !strncasecmpz(optstr, "yes", arglen) ||
-		    !strncasecmpz(optstr, "on", arglen) ||
-		    !strncasecmpz(optstr, "true", arglen))
-			value = true;
-	}
-
-	return value;
-}
-
-int
-nouveau_dbgopt(const char *optstr, const char *sub)
-{
-	int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
-
-	while (optstr) {
-		int len = strcspn(optstr, ",=");
-		switch (optstr[len]) {
-		case '=':
-			if (strncasecmpz(optstr, sub, len))
-				mode = 0;
-			optstr++;
-			break;
-		default:
-			if (mode) {
-				if (!strncasecmpz(optstr, "fatal", len))
-					level = NV_DBG_FATAL;
-				else if (!strncasecmpz(optstr, "error", len))
-					level = NV_DBG_ERROR;
-				else if (!strncasecmpz(optstr, "warn", len))
-					level = NV_DBG_WARN;
-				else if (!strncasecmpz(optstr, "info", len))
-					level = NV_DBG_INFO_NORMAL;
-				else if (!strncasecmpz(optstr, "debug", len))
-					level = NV_DBG_DEBUG;
-				else if (!strncasecmpz(optstr, "trace", len))
-					level = NV_DBG_TRACE;
-				else if (!strncasecmpz(optstr, "paranoia", len))
-					level = NV_DBG_PARANOIA;
-				else if (!strncasecmpz(optstr, "spam", len))
-					level = NV_DBG_SPAM;
-			}
-
-			if (optstr[len] != '\0') {
-				optstr++;
-				mode = 1;
-				break;
-			}
-
-			return level;
-		}
-		optstr += len;
-	}
-
-	return level;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c
deleted file mode 100644
index 30a2911..0000000
--- a/drivers/gpu/drm/nouveau/core/core/parent.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/parent.h>
-#include <core/client.h>
-
-int
-nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
-		      struct nouveau_object **pengine,
-		      struct nouveau_oclass **poclass)
-{
-	struct nouveau_sclass *sclass;
-	struct nouveau_engine *engine;
-	struct nouveau_oclass *oclass;
-	u64 mask;
-
-	sclass = nv_parent(parent)->sclass;
-	while (sclass) {
-		if ((sclass->oclass->handle & 0xffff) == handle) {
-			*pengine = parent->engine;
-			*poclass = sclass->oclass;
-			return 0;
-		}
-
-		sclass = sclass->sclass;
-	}
-
-	mask = nv_parent(parent)->engine;
-	while (mask) {
-		int i = __ffs64(mask);
-
-		if (nv_iclass(parent, NV_CLIENT_CLASS))
-			engine = nv_engine(nv_client(parent)->device);
-		else
-			engine = nouveau_engine(parent, i);
-
-		if (engine) {
-			oclass = engine->sclass;
-			while (oclass->ofuncs) {
-				if ((oclass->handle & 0xffff) == handle) {
-					*pengine = nv_object(engine);
-					*poclass = oclass;
-					return 0;
-				}
-				oclass++;
-			}
-		}
-
-		mask &= ~(1ULL << i);
-	}
-
-	return -EINVAL;
-}
-
-int
-nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size)
-{
-	struct nouveau_sclass *sclass;
-	struct nouveau_engine *engine;
-	struct nouveau_oclass *oclass;
-	int nr = -1, i;
-	u64 mask;
-
-	sclass = nv_parent(parent)->sclass;
-	while (sclass) {
-		if (++nr < size)
-			lclass[nr] = sclass->oclass->handle & 0xffff;
-		sclass = sclass->sclass;
-	}
-
-	mask = nv_parent(parent)->engine;
-	while (i = __ffs64(mask), mask) {
-		engine = nouveau_engine(parent, i);
-		if (engine && (oclass = engine->sclass)) {
-			while (oclass->ofuncs) {
-				if (++nr < size)
-					lclass[nr] = oclass->handle & 0xffff;
-				oclass++;
-			}
-		}
-
-		mask &= ~(1ULL << i);
-	}
-
-	return nr + 1;
-}
-
-int
-nouveau_parent_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pclass,
-		       struct nouveau_oclass *sclass, u64 engcls,
-		       int size, void **pobject)
-{
-	struct nouveau_parent *object;
-	struct nouveau_sclass *nclass;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, pclass |
-				     NV_PARENT_CLASS, size, pobject);
-	object = *pobject;
-	if (ret)
-		return ret;
-
-	while (sclass && sclass->ofuncs) {
-		nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
-		if (!nclass)
-			return -ENOMEM;
-
-		nclass->sclass = object->sclass;
-		object->sclass = nclass;
-		nclass->engine = engine ? nv_engine(engine) : NULL;
-		nclass->oclass = sclass;
-		sclass++;
-	}
-
-	object->engine = engcls;
-	return 0;
-}
-
-void
-nouveau_parent_destroy(struct nouveau_parent *parent)
-{
-	struct nouveau_sclass *sclass;
-
-	while ((sclass = parent->sclass)) {
-		parent->sclass = sclass->sclass;
-		kfree(sclass);
-	}
-
-	nouveau_object_destroy(&parent->base);
-}
-
-
-void
-_nouveau_parent_dtor(struct nouveau_object *object)
-{
-	nouveau_parent_destroy(nv_parent(object));
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/printk.c b/drivers/gpu/drm/nouveau/core/core/printk.c
deleted file mode 100644
index 03e0060..0000000
--- a/drivers/gpu/drm/nouveau/core/core/printk.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/subdev.h>
-#include <core/printk.h>
-
-int nv_info_debug_level = NV_DBG_INFO_NORMAL;
-
-void
-nv_printk_(struct nouveau_object *object, int level, const char *fmt, ...)
-{
-	static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
-	const char *pfx;
-	char mfmt[256];
-	va_list args;
-
-	switch (level) {
-	case NV_DBG_FATAL:
-		pfx = KERN_CRIT;
-		break;
-	case NV_DBG_ERROR:
-		pfx = KERN_ERR;
-		break;
-	case NV_DBG_WARN:
-		pfx = KERN_WARNING;
-		break;
-	case NV_DBG_INFO_NORMAL:
-		pfx = KERN_INFO;
-		break;
-	case NV_DBG_DEBUG:
-	case NV_DBG_PARANOIA:
-	case NV_DBG_TRACE:
-	case NV_DBG_SPAM:
-	default:
-		pfx = KERN_DEBUG;
-		break;
-	}
-
-	if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
-		struct nouveau_object *device = object;
-		struct nouveau_object *subdev = object;
-		char obuf[64], *ofmt = "";
-
-		if (object->engine) {
-			snprintf(obuf, sizeof(obuf), "[0x%08x][%p]",
-				 nv_hclass(object), object);
-			ofmt = obuf;
-			subdev = object->engine;
-			device = object->engine;
-		}
-
-		if (subdev->parent)
-			device = subdev->parent;
-
-		if (level > nv_subdev(subdev)->debug)
-			return;
-
-		snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
-			 name[level], nv_subdev(subdev)->name,
-			 nv_device(device)->name, ofmt, fmt);
-	} else
-	if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
-		if (level > nv_client(object)->debug)
-			return;
-
-		snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
-			 name[level], nv_client(object)->name, fmt);
-	} else {
-		snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
-	}
-
-	va_start(args, fmt);
-	vprintk(mfmt, args);
-	va_end(args);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/ramht.c b/drivers/gpu/drm/nouveau/core/core/ramht.c
deleted file mode 100644
index f3b9bdd..0000000
--- a/drivers/gpu/drm/nouveau/core/core/ramht.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 <core/object.h>
-#include <core/ramht.h>
-
-#include <subdev/bar.h>
-
-static u32
-nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
-{
-	u32 hash = 0;
-
-	while (handle) {
-		hash ^= (handle & ((1 << ramht->bits) - 1));
-		handle >>= ramht->bits;
-	}
-
-	hash ^= chid << (ramht->bits - 4);
-	hash  = hash << 3;
-	return hash;
-}
-
-int
-nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
-		     u32 handle, u32 context)
-{
-	struct nouveau_bar *bar = nouveau_bar(ramht);
-	u32 co, ho;
-
-	co = ho = nouveau_ramht_hash(ramht, chid, handle);
-	do {
-		if (!nv_ro32(ramht, co + 4)) {
-			nv_wo32(ramht, co + 0, handle);
-			nv_wo32(ramht, co + 4, context);
-			if (bar)
-				bar->flush(bar);
-			return co;
-		}
-
-		co += 8;
-		if (co >= nv_gpuobj(ramht)->size)
-			co = 0;
-	} while (co != ho);
-
-	return -ENOMEM;
-}
-
-void
-nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
-{
-	struct nouveau_bar *bar = nouveau_bar(ramht);
-	nv_wo32(ramht, cookie + 0, 0x00000000);
-	nv_wo32(ramht, cookie + 4, 0x00000000);
-	if (bar)
-		bar->flush(bar);
-}
-
-static struct nouveau_oclass
-nouveau_ramht_oclass = {
-	.handle = 0x0000abcd,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = NULL,
-		.dtor = _nouveau_gpuobj_dtor,
-		.init = _nouveau_gpuobj_init,
-		.fini = _nouveau_gpuobj_fini,
-		.rd32 = _nouveau_gpuobj_rd32,
-		.wr32 = _nouveau_gpuobj_wr32,
-	},
-};
-
-int
-nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
-		  u32 size, u32 align, struct nouveau_ramht **pramht)
-{
-	struct nouveau_ramht *ramht;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, parent->engine ?
-				    parent->engine : parent, /* <nv50 ramht */
-				    &nouveau_ramht_oclass, 0, pargpu, size,
-				    align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
-	*pramht = ramht;
-	if (ret)
-		return ret;
-
-	ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c
deleted file mode 100644
index 2ea5568..0000000
--- a/drivers/gpu/drm/nouveau/core/core/subdev.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/option.h>
-
-void
-nouveau_subdev_reset(struct nouveau_object *subdev)
-{
-	nv_trace(subdev, "resetting...\n");
-	nv_ofuncs(subdev)->fini(subdev, false);
-	nv_debug(subdev, "reset\n");
-}
-
-int
-nouveau_subdev_init(struct nouveau_subdev *subdev)
-{
-	int ret = nouveau_object_init(&subdev->base);
-	if (ret)
-		return ret;
-
-	nouveau_subdev_reset(&subdev->base);
-	return 0;
-}
-
-int
-_nouveau_subdev_init(struct nouveau_object *object)
-{
-	return nouveau_subdev_init(nv_subdev(object));
-}
-
-int
-nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend)
-{
-	if (subdev->unit) {
-		nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
-		nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
-	}
-
-	return nouveau_object_fini(&subdev->base, suspend);
-}
-
-int
-_nouveau_subdev_fini(struct nouveau_object *object, bool suspend)
-{
-	return nouveau_subdev_fini(nv_subdev(object), suspend);
-}
-
-void
-nouveau_subdev_destroy(struct nouveau_subdev *subdev)
-{
-	int subidx = nv_hclass(subdev) & 0xff;
-	nv_device(subdev)->subdev[subidx] = NULL;
-	nouveau_object_destroy(&subdev->base);
-}
-
-void
-_nouveau_subdev_dtor(struct nouveau_object *object)
-{
-	nouveau_subdev_destroy(nv_subdev(object));
-}
-
-int
-nouveau_subdev_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pclass,
-		       const char *subname, const char *sysname,
-		       int size, void **pobject)
-{
-	struct nouveau_subdev *subdev;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, pclass |
-				     NV_SUBDEV_CLASS, size, pobject);
-	subdev = *pobject;
-	if (ret)
-		return ret;
-
-	__mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
-	subdev->name = subname;
-
-	if (parent) {
-		struct nouveau_device *device = nv_device(parent);
-		subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
-		subdev->mmio  = nv_subdev(device)->mmio;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
deleted file mode 100644
index 1e8e75c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs, Ilia Mirkin
- */
-
-#include <engine/xtensa.h>
-#include <engine/bsp.h>
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_bsp_sclass[] = {
-	{ 0x74b0, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * BSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_bsp_cclass = {
-	.handle = NV_ENGCTX(BSP, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_xtensa_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
-	},
-};
-
-/*******************************************************************************
- * BSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_xtensa *priv;
-	int ret;
-
-	ret = nouveau_xtensa_create(parent, engine, oclass, 0x103000, true,
-				    "PBSP", "bsp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x04008000;
-	nv_engine(priv)->cclass = &nv84_bsp_cclass;
-	nv_engine(priv)->sclass = nv84_bsp_sclass;
-	priv->fifo_val = 0x1111;
-	priv->unkd28 = 0x90044;
-	return 0;
-}
-
-struct nouveau_oclass
-nv84_bsp_oclass = {
-	.handle = NV_ENGINE(BSP, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_bsp_ctor,
-		.dtor = _nouveau_xtensa_dtor,
-		.init = _nouveau_xtensa_init,
-		.fini = _nouveau_xtensa_fini,
-		.rd32 = _nouveau_xtensa_rd32,
-		.wr32 = _nouveau_xtensa_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
deleted file mode 100644
index 6b089e0..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nv98_bsp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_bsp_sclass[] = {
-	{ 0x88b1, &nouveau_object_ofuncs },
-	{ 0x85b1, &nouveau_object_ofuncs },
-	{ 0x86b1, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_bsp_cclass = {
-	.handle = NV_ENGCTX(BSP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_bsp_init(struct nouveau_object *object)
-{
-	struct nv98_bsp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x084010, 0x0000ffd2);
-	nv_wr32(priv, 0x08401c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv98_bsp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
-				    "PBSP", "bsp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x04008000;
-	nv_engine(priv)->cclass = &nv98_bsp_cclass;
-	nv_engine(priv)->sclass = nv98_bsp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nv98_bsp_oclass = {
-	.handle = NV_ENGINE(BSP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv98_bsp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nv98_bsp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
deleted file mode 100644
index ce860de..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nvc0_bsp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_sclass[] = {
-	{ 0x90b1, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_cclass = {
-	.handle = NV_ENGCTX(BSP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_bsp_init(struct nouveau_object *object)
-{
-	struct nvc0_bsp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x084010, 0x0000fff2);
-	nv_wr32(priv, 0x08401c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nvc0_bsp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
-				    "PBSP", "bsp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00008000;
-	nv_subdev(priv)->intr = nouveau_falcon_intr;
-	nv_engine(priv)->cclass = &nvc0_bsp_cclass;
-	nv_engine(priv)->sclass = nvc0_bsp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_bsp_oclass = {
-	.handle = NV_ENGINE(BSP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_bsp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nvc0_bsp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
deleted file mode 100644
index ba6aeca..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nve0_bsp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_sclass[] = {
-	{ 0x95b1, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_cclass = {
-	.handle = NV_ENGCTX(BSP, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_bsp_init(struct nouveau_object *object)
-{
-	struct nve0_bsp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x084010, 0x0000fff2);
-	nv_wr32(priv, 0x08401c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nve0_bsp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
-				    "PBSP", "bsp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00008000;
-	nv_subdev(priv)->intr = nouveau_falcon_intr;
-	nv_engine(priv)->cclass = &nve0_bsp_cclass;
-	nv_engine(priv)->sclass = nve0_bsp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_bsp_oclass = {
-	.handle = NV_ENGINE(BSP, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_bsp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nve0_bsp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc
deleted file mode 100644
index 219850d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc
+++ /dev/null
@@ -1,872 +0,0 @@
-/* fuc microcode for copy engine on nva3- chipsets
- *
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-/* To build for nva3:nvc0
- *    m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
- *
- * To build for nvc0-
- *    m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
- */
-
-ifdef(`NVA3',
-.section #nva3_pcopy_data
-,
-.section #nvc0_pcopy_data
-)
-
-ctx_object:                   .b32 0
-ifdef(`NVA3',
-ctx_dma:
-ctx_dma_query:                .b32 0
-ctx_dma_src:                  .b32 0
-ctx_dma_dst:                  .b32 0
-,)
-.equ #ctx_dma_count 3
-ctx_query_address_high:       .b32 0
-ctx_query_address_low:        .b32 0
-ctx_query_counter:            .b32 0
-ctx_src_address_high:         .b32 0
-ctx_src_address_low:          .b32 0
-ctx_src_pitch:                .b32 0
-ctx_src_tile_mode:            .b32 0
-ctx_src_xsize:                .b32 0
-ctx_src_ysize:                .b32 0
-ctx_src_zsize:                .b32 0
-ctx_src_zoff:                 .b32 0
-ctx_src_xoff:                 .b32 0
-ctx_src_yoff:                 .b32 0
-ctx_src_cpp:                  .b32 0
-ctx_dst_address_high:         .b32 0
-ctx_dst_address_low:          .b32 0
-ctx_dst_pitch:                .b32 0
-ctx_dst_tile_mode:            .b32 0
-ctx_dst_xsize:                .b32 0
-ctx_dst_ysize:                .b32 0
-ctx_dst_zsize:                .b32 0
-ctx_dst_zoff:                 .b32 0
-ctx_dst_xoff:                 .b32 0
-ctx_dst_yoff:                 .b32 0
-ctx_dst_cpp:                  .b32 0
-ctx_format:                   .b32 0
-ctx_swz_const0:               .b32 0
-ctx_swz_const1:               .b32 0
-ctx_xcnt:                     .b32 0
-ctx_ycnt:                     .b32 0
-.align 256
-
-dispatch_table:
-// mthd 0x0000, NAME
-.b16 0x000 1
-.b32 #ctx_object                     ~0xffffffff
-// mthd 0x0100, NOP
-.b16 0x040 1
-.b32 0x00010000 + #cmd_nop           ~0xffffffff
-// mthd 0x0140, PM_TRIGGER
-.b16 0x050 1
-.b32 0x00010000 + #cmd_pm_trigger    ~0xffffffff
-ifdef(`NVA3', `
-// mthd 0x0180-0x018c, DMA_
-.b16 0x060 #ctx_dma_count
-dispatch_dma:
-.b32 0x00010000 + #cmd_dma           ~0xffffffff
-.b32 0x00010000 + #cmd_dma           ~0xffffffff
-.b32 0x00010000 + #cmd_dma           ~0xffffffff
-',)
-// mthd 0x0200-0x0218, SRC_TILE
-.b16 0x80 7
-.b32 #ctx_src_tile_mode              ~0x00000fff
-.b32 #ctx_src_xsize                  ~0x0007ffff
-.b32 #ctx_src_ysize                  ~0x00001fff
-.b32 #ctx_src_zsize                  ~0x000007ff
-.b32 #ctx_src_zoff                   ~0x00000fff
-.b32 #ctx_src_xoff                   ~0x0007ffff
-.b32 #ctx_src_yoff                   ~0x00001fff
-// mthd 0x0220-0x0238, DST_TILE
-.b16 0x88 7
-.b32 #ctx_dst_tile_mode              ~0x00000fff
-.b32 #ctx_dst_xsize                  ~0x0007ffff
-.b32 #ctx_dst_ysize                  ~0x00001fff
-.b32 #ctx_dst_zsize                  ~0x000007ff
-.b32 #ctx_dst_zoff                   ~0x00000fff
-.b32 #ctx_dst_xoff                   ~0x0007ffff
-.b32 #ctx_dst_yoff                   ~0x00001fff
-// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
-.b16 0xc0 2
-.b32 0x00010000 + #cmd_exec          ~0xffffffff
-.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff
-// mthd 0x030c-0x0340, various stuff
-.b16 0xc3 14
-.b32 #ctx_src_address_high           ~0x000000ff
-.b32 #ctx_src_address_low            ~0xffffffff
-.b32 #ctx_dst_address_high           ~0x000000ff
-.b32 #ctx_dst_address_low            ~0xffffffff
-.b32 #ctx_src_pitch                  ~0x0007ffff
-.b32 #ctx_dst_pitch                  ~0x0007ffff
-.b32 #ctx_xcnt                       ~0x0000ffff
-.b32 #ctx_ycnt                       ~0x00001fff
-.b32 #ctx_format                     ~0x0333ffff
-.b32 #ctx_swz_const0                 ~0xffffffff
-.b32 #ctx_swz_const1                 ~0xffffffff
-.b32 #ctx_query_address_high         ~0x000000ff
-.b32 #ctx_query_address_low          ~0xffffffff
-.b32 #ctx_query_counter              ~0xffffffff
-.b16 0x800 0
-
-ifdef(`NVA3',
-.section #nva3_pcopy_code
-,
-.section #nvc0_pcopy_code
-)
-
-main:
-   clear b32 $r0
-   mov $sp $r0
-
-   // setup i0 handler and route fifo and ctxswitch to it
-   mov $r1 #ih
-   mov $iv0 $r1
-   mov $r1 0x400
-   movw $r2 0xfff3
-   sethi $r2 0
-   iowr I[$r1 + 0x300] $r2
-
-   // enable interrupts
-   or $r2 0xc
-   iowr I[$r1] $r2
-   bset $flags ie0
-
-   // enable fifo access and context switching
-   mov $r1 0x1200
-   mov $r2 3
-   iowr I[$r1] $r2
-
-   // sleep forever, waking for interrupts
-   bset $flags $p0
-   spin:
-      sleep $p0
-      bra #spin
-
-// i0 handler
-ih:
-   iord $r1 I[$r0 + 0x200]
-
-   and $r2 $r1 0x00000008
-   bra e #ih_no_chsw
-      call #chsw
-   ih_no_chsw:
-   and $r2 $r1 0x00000004
-   bra e #ih_no_cmd
-      call #dispatch
-
-   ih_no_cmd:
-   and $r1 $r1 0x0000000c
-   iowr I[$r0 + 0x100] $r1
-   iret
-
-// $p1 direction (0 = unload, 1 = load)
-// $r3 channel
-swctx:
-   mov $r4 0x7700
-   mov $xtargets $r4
-ifdef(`NVA3', `
-   // target 7 hardcoded to ctx dma object
-   mov $xdbase $r0
-', ` // NVC0
-   // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
-   mov $r4 0x2100
-   iord $r4 I[$r4 + 0]
-   and $r4 1
-   shl b32 $r4 4
-   add b32 $r4 0x30
-
-   // channel is in vram
-   mov $r15 0x61c
-   shl b32 $r15 6
-   mov $r5 0x114
-   iowrs I[$r15] $r5
-
-   // read 16-byte PCOPYn info, containing context pointer, from channel
-   shl b32 $r5 $r3 4
-   add b32 $r5 2
-   mov $xdbase $r5
-   mov $r5 $sp
-   // get a chunk of stack space, aligned to 256 byte boundary
-   sub b32 $r5 0x100
-   mov $r6 0xff
-   not b32 $r6
-   and $r5 $r6
-   sethi $r5 0x00020000
-   xdld $r4 $r5
-   xdwait
-   sethi $r5 0
-
-   // set context pointer, from within channel VM
-   mov $r14 0
-   iowrs I[$r15] $r14
-   ld b32 $r4 D[$r5 + 0]
-   shr b32 $r4 8
-   ld b32 $r6 D[$r5 + 4]
-   shl b32 $r6 24
-   or $r4 $r6
-   mov $xdbase $r4
-')
-   // 256-byte context, at start of data segment
-   mov b32 $r4 $r0
-   sethi $r4 0x60000
-
-   // swap!
-   bra $p1 #swctx_load
-      xdst $r0 $r4
-      bra #swctx_done
-   swctx_load:
-      xdld $r0 $r4
-   swctx_done:
-   xdwait
-   ret
-
-chsw:
-   // read current channel
-   mov $r2 0x1400
-   iord $r3 I[$r2]
-
-   // if it's active, unload it and return
-   xbit $r15 $r3 0x1e
-   bra e #chsw_no_unload
-      bclr $flags $p1
-      call #swctx
-      bclr $r3 0x1e
-      iowr I[$r2] $r3
-      mov $r4 1
-      iowr I[$r2 + 0x200] $r4
-      ret
-
-   // read next channel
-   chsw_no_unload:
-   iord $r3 I[$r2 + 0x100]
-
-   // is there a channel waiting to be loaded?
-   xbit $r13 $r3 0x1e
-   bra e #chsw_finish_load
-      bset $flags $p1
-      call #swctx
-ifdef(`NVA3',
-      // load dma objects back into TARGET regs
-      mov $r5 #ctx_dma
-      mov $r6 #ctx_dma_count
-      chsw_load_ctx_dma:
-         ld b32 $r7 D[$r5 + $r6 * 4]
-         add b32 $r8 $r6 0x180
-         shl b32 $r8 8
-         iowr I[$r8] $r7
-         sub b32 $r6 1
-         bra nc #chsw_load_ctx_dma
-,)
-
-   chsw_finish_load:
-   mov $r3 2
-   iowr I[$r2 + 0x200] $r3
-   ret
-
-dispatch:
-   // read incoming fifo command
-   mov $r3 0x1900
-   iord $r2 I[$r3 + 0x100]
-   iord $r3 I[$r3 + 0x000]
-   and $r4 $r2 0x7ff
-   // $r2 will be used to store exception data
-   shl b32 $r2 0x10
-
-   // lookup method in the dispatch table, ILLEGAL_MTHD if not found
-   mov $r5 #dispatch_table
-   clear b32 $r6
-   clear b32 $r7
-   dispatch_loop:
-      ld b16 $r6 D[$r5 + 0]
-      ld b16 $r7 D[$r5 + 2]
-      add b32 $r5 4
-      cmpu b32 $r4 $r6
-      bra c #dispatch_illegal_mthd
-      add b32 $r7 $r6
-      cmpu b32 $r4 $r7
-      bra c #dispatch_valid_mthd
-      sub b32 $r7 $r6
-      shl b32 $r7 3
-      add b32 $r5 $r7
-      bra #dispatch_loop
-
-   // ensure no bits set in reserved fields, INVALID_BITFIELD
-   dispatch_valid_mthd:
-   sub b32 $r4 $r6
-   shl b32 $r4 3
-   add b32 $r4 $r5
-   ld b32 $r5 D[$r4 + 4]
-   and $r5 $r3
-   cmpu b32 $r5 0
-   bra ne #dispatch_invalid_bitfield
-
-   // depending on dispatch flags: execute method, or save data as state
-   ld b16 $r5 D[$r4 + 0]
-   ld b16 $r6 D[$r4 + 2]
-   cmpu b32 $r6 0
-   bra ne #dispatch_cmd
-      st b32 D[$r5] $r3
-      bra #dispatch_done
-   dispatch_cmd:
-      bclr $flags $p1
-      call $r5
-      bra $p1 #dispatch_error
-      bra #dispatch_done
-
-   dispatch_invalid_bitfield:
-   or $r2 2
-   dispatch_illegal_mthd:
-   or $r2 1
-
-   // store exception data in SCRATCH0/SCRATCH1, signal hostirq
-   dispatch_error:
-   mov $r4 0x1000
-   iowr I[$r4 + 0x000] $r2
-   iowr I[$r4 + 0x100] $r3
-   mov $r2 0x40
-   iowr I[$r0] $r2
-   hostirq_wait:
-      iord $r2 I[$r0 + 0x200]
-      and $r2 0x40
-      cmpu b32 $r2 0
-      bra ne #hostirq_wait
-
-   dispatch_done:
-   mov $r2 0x1d00
-   mov $r3 1
-   iowr I[$r2] $r3
-   ret
-
-// No-operation
-//
-// Inputs:
-//    $r1: irqh state
-//    $r2: hostirq state
-//    $r3: data
-//    $r4: dispatch table entry
-// Outputs:
-//    $r1: irqh state
-//    $p1: set on error
-//       $r2: hostirq state
-//       $r3: data
-cmd_nop:
-   ret
-
-// PM_TRIGGER
-//
-// Inputs:
-//    $r1: irqh state
-//    $r2: hostirq state
-//    $r3: data
-//    $r4: dispatch table entry
-// Outputs:
-//    $r1: irqh state
-//    $p1: set on error
-//       $r2: hostirq state
-//       $r3: data
-cmd_pm_trigger:
-   mov $r2 0x2200
-   clear b32 $r3
-   sethi $r3 0x20000
-   iowr I[$r2] $r3
-   ret
-
-ifdef(`NVA3',
-// SET_DMA_* method handler
-//
-// Inputs:
-//    $r1: irqh state
-//    $r2: hostirq state
-//    $r3: data
-//    $r4: dispatch table entry
-// Outputs:
-//    $r1: irqh state
-//    $p1: set on error
-//       $r2: hostirq state
-//       $r3: data
-cmd_dma:
-   sub b32 $r4 #dispatch_dma
-   shr b32 $r4 1
-   bset $r3 0x1e
-   st b32 D[$r4 + #ctx_dma] $r3
-   add b32 $r4 0x600
-   shl b32 $r4 6
-   iowr I[$r4] $r3
-   ret
-,)
-
-// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
-//
-cmd_exec_set_format:
-   // zero out a chunk of the stack to store the swizzle into
-   add $sp -0x10
-   st b32 D[$sp + 0x00] $r0
-   st b32 D[$sp + 0x04] $r0
-   st b32 D[$sp + 0x08] $r0
-   st b32 D[$sp + 0x0c] $r0
-
-   // extract cpp, src_ncomp and dst_ncomp from FORMAT
-   ld b32 $r4 D[$r0 + #ctx_format]
-   extr $r5 $r4 16:17
-   add b32 $r5 1
-   extr $r6 $r4 20:21
-   add b32 $r6 1
-   extr $r7 $r4 24:25
-   add b32 $r7 1
-
-   // convert FORMAT swizzle mask to hw swizzle mask
-   bclr $flags $p2
-   clear b32 $r8
-   clear b32 $r9
-   ncomp_loop:
-      and $r10 $r4 0xf
-      shr b32 $r4 4
-      clear b32 $r11
-      bpc_loop:
-         cmpu b8 $r10 4
-         bra nc #cmp_c0
-            mulu $r12 $r10 $r5
-            add b32 $r12 $r11
-            bset $flags $p2
-            bra #bpc_next
-         cmp_c0:
-         bra ne #cmp_c1
-            mov $r12 0x10
-            add b32 $r12 $r11
-            bra #bpc_next
-         cmp_c1:
-         cmpu b8 $r10 6
-         bra nc #cmp_zero
-            mov $r12 0x14
-            add b32 $r12 $r11
-            bra #bpc_next
-         cmp_zero:
-            mov $r12 0x80
-         bpc_next:
-         st b8 D[$sp + $r8] $r12
-         add b32 $r8 1
-         add b32 $r11 1
-         cmpu b32 $r11 $r5
-         bra c #bpc_loop
-      add b32 $r9 1
-      cmpu b32 $r9 $r7
-      bra c #ncomp_loop
-
-   // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
-   mulu $r6 $r5
-   st b32 D[$r0 + #ctx_src_cpp] $r6
-   ld b32 $r8 D[$r0 + #ctx_xcnt]
-   mulu $r6 $r8
-   bra $p2 #dst_xcnt
-   clear b32 $r6
-
-   dst_xcnt:
-   mulu $r7 $r5
-   st b32 D[$r0 + #ctx_dst_cpp] $r7
-   mulu $r7 $r8
-
-   mov $r5 0x810
-   shl b32 $r5 6
-   iowr I[$r5 + 0x000] $r6
-   iowr I[$r5 + 0x100] $r7
-   add b32 $r5 0x800
-   ld b32 $r6 D[$r0 + #ctx_dst_cpp]
-   sub b32 $r6 1
-   shl b32 $r6 8
-   ld b32 $r7 D[$r0 + #ctx_src_cpp]
-   sub b32 $r7 1
-   or $r6 $r7
-   iowr I[$r5 + 0x000] $r6
-   add b32 $r5 0x100
-   ld b32 $r6 D[$sp + 0x00]
-   iowr I[$r5 + 0x000] $r6
-   ld b32 $r6 D[$sp + 0x04]
-   iowr I[$r5 + 0x100] $r6
-   ld b32 $r6 D[$sp + 0x08]
-   iowr I[$r5 + 0x200] $r6
-   ld b32 $r6 D[$sp + 0x0c]
-   iowr I[$r5 + 0x300] $r6
-   add b32 $r5 0x400
-   ld b32 $r6 D[$r0 + #ctx_swz_const0]
-   iowr I[$r5 + 0x000] $r6
-   ld b32 $r6 D[$r0 + #ctx_swz_const1]
-   iowr I[$r5 + 0x100] $r6
-   add $sp 0x10
-   ret
-
-// Setup to handle a tiled surface
-//
-// Calculates a number of parameters the hardware requires in order
-// to correctly handle tiling.
-//
-// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
-//    nTx = round_up(w * cpp, 1 << Tp) >> Tp
-//    nTy = round_up(h, 1 << Th) >> Th
-//    Txo = (x * cpp) & ((1 << Tp) - 1)
-//     Tx = (x * cpp) >> Tp
-//    Tyo = y & ((1 << Th) - 1)
-//     Ty = y >> Th
-//    Tzo = z & ((1 << Td) - 1)
-//     Tz = z >> Td
-//
-//    off  = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
-//    off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
-//
-// Inputs:
-//    $r4: hw command (0x104800)
-//    $r5: ctx offset adjustment for src/dst selection
-//    $p2: set if dst surface
-//
-cmd_exec_set_surface_tiled:
-   // translate TILE_MODE into Tp, Th, Td shift values
-   ld b32 $r7 D[$r5 + #ctx_src_tile_mode]
-   extr $r9 $r7 8:11
-   extr $r8 $r7 4:7
-ifdef(`NVA3',
-   add b32 $r8 2
-,
-   add b32 $r8 3
-)
-   extr $r7 $r7 0:3
-   cmp b32 $r7 0xe
-   bra ne #xtile64
-   mov $r7 4
-   bra #xtileok
-   xtile64:
-   xbit $r7 $flags $p2
-   add b32 $r7 17
-   bset $r4 $r7
-   mov $r7 6
-   xtileok:
-
-   // Op = (x * cpp) & ((1 << Tp) - 1)
-   // Tx = (x * cpp) >> Tp
-   ld b32 $r10 D[$r5 + #ctx_src_xoff]
-   ld b32 $r11 D[$r5 + #ctx_src_cpp]
-   mulu $r10 $r11
-   mov $r11 1
-   shl b32 $r11 $r7
-   sub b32 $r11 1
-   and $r12 $r10 $r11
-   shr b32 $r10 $r7
-
-   // Tyo = y & ((1 << Th) - 1)
-   // Ty  = y >> Th
-   ld b32 $r13 D[$r5 + #ctx_src_yoff]
-   mov $r14 1
-   shl b32 $r14 $r8
-   sub b32 $r14 1
-   and $r11 $r13 $r14
-   shr b32 $r13 $r8
-
-   // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
-   add b32 $r14 1
-   shl b32 $r15 $r14 12
-   sub b32 $r14 $r11
-   or $r15 $r14
-   xbit $r6 $flags $p2
-   add b32 $r6 0x208
-   shl b32 $r6 8
-   iowr I[$r6 + 0x000] $r15
-
-   // Op += Tyo << Tp
-   shl b32 $r11 $r7
-   add b32 $r12 $r11
-
-   // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
-   ld b32 $r15 D[$r5 + #ctx_src_xsize]
-   ld b32 $r11 D[$r5 + #ctx_src_cpp]
-   mulu $r15 $r11
-   mov $r11 1
-   shl b32 $r11 $r7
-   sub b32 $r11 1
-   add b32 $r15 $r11
-   shr b32 $r15 $r7
-   push $r15
-
-   // nTy = (h + ((1 << Th) - 1)) >> Th
-   ld b32 $r15 D[$r5 + #ctx_src_ysize]
-   mov $r11 1
-   shl b32 $r11 $r8
-   sub b32 $r11 1
-   add b32 $r15 $r11
-   shr b32 $r15 $r8
-   push $r15
-
-   // Tys = Tp + Th
-   // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
-   add b32 $r7 $r8
-   sub b32 $r8 2
-   mov $r11 1
-   shl b32 $r11 $r8
-   shl b32 $r11 $r9
-
-   // Tzo = z & ((1 << Td) - 1)
-   // Tz  = z >> Td
-   // Op += Tzo << Tys
-   // Ts  = Tys + Td
-   ld b32 $r8 D[$r5 + #ctx_src_zoff]
-   mov $r14 1
-   shl b32 $r14 $r9
-   sub b32 $r14 1
-   and $r15 $r8 $r14
-   shl b32 $r15 $r7
-   add b32 $r12 $r15
-   add b32 $r7 $r9
-   shr b32 $r8 $r9
-
-   // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
-   pop $r15
-   pop $r9
-   mulu $r13 $r9
-   add b32 $r10 $r13
-   mulu $r8 $r9
-   mulu $r8 $r15
-   add b32 $r10 $r8
-   shl b32 $r10 $r7
-
-   // PITCH = (nTx - 1) << Ts
-   sub b32 $r9 1
-   shl b32 $r9 $r7
-   iowr I[$r6 + 0x200] $r9
-
-   // SRC_ADDRESS_LOW   = (Ot + Op) & 0xffffffff
-   // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
-   ld b32 $r7 D[$r5 + #ctx_src_address_low]
-   ld b32 $r8 D[$r5 + #ctx_src_address_high]
-   add b32 $r10 $r12
-   add b32 $r7 $r10
-   adc b32 $r8 0
-   shl b32 $r8 16
-   or $r8 $r11
-   sub b32 $r6 0x600
-   iowr I[$r6 + 0x000] $r7
-   add b32 $r6 0x400
-   iowr I[$r6 + 0x000] $r8
-   ret
-
-// Setup to handle a linear surface
-//
-// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
-//
-cmd_exec_set_surface_linear:
-   xbit $r6 $flags $p2
-   add b32 $r6 0x202
-   shl b32 $r6 8
-   ld b32 $r7 D[$r5 + #ctx_src_address_low]
-   iowr I[$r6 + 0x000] $r7
-   add b32 $r6 0x400
-   ld b32 $r7 D[$r5 + #ctx_src_address_high]
-   shl b32 $r7 16
-   iowr I[$r6 + 0x000] $r7
-   add b32 $r6 0x400
-   ld b32 $r7 D[$r5 + #ctx_src_pitch]
-   iowr I[$r6 + 0x000] $r7
-   ret
-
-// wait for regs to be available for use
-cmd_exec_wait:
-   push $r0
-   push $r1
-   mov $r0 0x800
-   shl b32 $r0 6
-   loop:
-      iord $r1 I[$r0]
-      and $r1 1
-      bra ne #loop
-   pop $r1
-   pop $r0
-   ret
-
-cmd_exec_query:
-   // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
-   xbit $r4 $r3 13
-   bra ne #query_counter
-      call #cmd_exec_wait
-      mov $r4 0x80c
-      shl b32 $r4 6
-      ld b32 $r5 D[$r0 + #ctx_query_address_low]
-      add b32 $r5 4
-      iowr I[$r4 + 0x000] $r5
-      iowr I[$r4 + 0x100] $r0
-      mov $r5 0xc
-      iowr I[$r4 + 0x200] $r5
-      add b32 $r4 0x400
-      ld b32 $r5 D[$r0 + #ctx_query_address_high]
-      shl b32 $r5 16
-      iowr I[$r4 + 0x000] $r5
-      add b32 $r4 0x500
-      mov $r5 0x00000b00
-      sethi $r5 0x00010000
-      iowr I[$r4 + 0x000] $r5
-      mov $r5 0x00004040
-      shl b32 $r5 1
-      sethi $r5 0x80800000
-      iowr I[$r4 + 0x100] $r5
-      mov $r5 0x00001110
-      sethi $r5 0x13120000
-      iowr I[$r4 + 0x200] $r5
-      mov $r5 0x00001514
-      sethi $r5 0x17160000
-      iowr I[$r4 + 0x300] $r5
-      mov $r5 0x00002601
-      sethi $r5 0x00010000
-      mov $r4 0x800
-      shl b32 $r4 6
-      iowr I[$r4 + 0x000] $r5
-
-   // write COUNTER
-   query_counter:
-   call #cmd_exec_wait
-   mov $r4 0x80c
-   shl b32 $r4 6
-   ld b32 $r5 D[$r0 + #ctx_query_address_low]
-   iowr I[$r4 + 0x000] $r5
-   iowr I[$r4 + 0x100] $r0
-   mov $r5 0x4
-   iowr I[$r4 + 0x200] $r5
-   add b32 $r4 0x400
-   ld b32 $r5 D[$r0 + #ctx_query_address_high]
-   shl b32 $r5 16
-   iowr I[$r4 + 0x000] $r5
-   add b32 $r4 0x500
-   mov $r5 0x00000300
-   iowr I[$r4 + 0x000] $r5
-   mov $r5 0x00001110
-   sethi $r5 0x13120000
-   iowr I[$r4 + 0x100] $r5
-   ld b32 $r5 D[$r0 + #ctx_query_counter]
-   add b32 $r4 0x500
-   iowr I[$r4 + 0x000] $r5
-   mov $r5 0x00002601
-   sethi $r5 0x00010000
-   mov $r4 0x800
-   shl b32 $r4 6
-   iowr I[$r4 + 0x000] $r5
-   ret
-
-// Execute a copy operation
-//
-// Inputs:
-//    $r1: irqh state
-//    $r2: hostirq state
-//    $r3: data
-//       000002000 QUERY_SHORT
-//       000001000 QUERY
-//       000000100 DST_LINEAR
-//       000000010 SRC_LINEAR
-//       000000001 FORMAT
-//    $r4: dispatch table entry
-// Outputs:
-//    $r1: irqh state
-//    $p1: set on error
-//       $r2: hostirq state
-//       $r3: data
-cmd_exec:
-   call #cmd_exec_wait
-
-   // if format requested, call function to calculate it, otherwise
-   // fill in cpp/xcnt for both surfaces as if (cpp == 1)
-   xbit $r15 $r3 0
-   bra e #cmd_exec_no_format
-      call #cmd_exec_set_format
-      mov $r4 0x200
-      bra #cmd_exec_init_src_surface
-   cmd_exec_no_format:
-      mov $r6 0x810
-      shl b32 $r6 6
-      mov $r7 1
-      st b32 D[$r0 + #ctx_src_cpp] $r7
-      st b32 D[$r0 + #ctx_dst_cpp] $r7
-      ld b32 $r7 D[$r0 + #ctx_xcnt]
-      iowr I[$r6 + 0x000] $r7
-      iowr I[$r6 + 0x100] $r7
-      clear b32 $r4
-
-   cmd_exec_init_src_surface:
-   bclr $flags $p2
-   clear b32 $r5
-   xbit $r15 $r3 4
-   bra e #src_tiled
-      call #cmd_exec_set_surface_linear
-      bra #cmd_exec_init_dst_surface
-   src_tiled:
-      call #cmd_exec_set_surface_tiled
-      bset $r4 7
-
-   cmd_exec_init_dst_surface:
-   bset $flags $p2
-   mov $r5 #ctx_dst_address_high - #ctx_src_address_high
-   xbit $r15 $r3 8
-   bra e #dst_tiled
-      call #cmd_exec_set_surface_linear
-      bra #cmd_exec_kick
-   dst_tiled:
-      call #cmd_exec_set_surface_tiled
-      bset $r4 8
-
-   cmd_exec_kick:
-   mov $r5 0x800
-   shl b32 $r5 6
-   ld b32 $r6 D[$r0 + #ctx_ycnt]
-   iowr I[$r5 + 0x100] $r6
-   mov $r6 0x0041
-   // SRC_TARGET = 1, DST_TARGET = 2
-   sethi $r6 0x44000000
-   or $r4 $r6
-   iowr I[$r5] $r4
-
-   // if requested, queue up a QUERY write after the copy has completed
-   xbit $r15 $r3 12
-   bra e #cmd_exec_done
-      call #cmd_exec_query
-
-   cmd_exec_done:
-   ret
-
-// Flush write cache
-//
-// Inputs:
-//    $r1: irqh state
-//    $r2: hostirq state
-//    $r3: data
-//    $r4: dispatch table entry
-// Outputs:
-//    $r1: irqh state
-//    $p1: set on error
-//       $r2: hostirq state
-//       $r3: data
-cmd_wrcache_flush:
-   mov $r2 0x2200
-   clear b32 $r3
-   sethi $r3 0x10000
-   iowr I[$r2] $r3
-   ret
-
-.align 0x100
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
deleted file mode 100644
index 241b272..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
+++ /dev/null
@@ -1,620 +0,0 @@
-uint32_t nva3_pcopy_data[] = {
-/* 0x0000: ctx_object */
-	0x00000000,
-/* 0x0004: ctx_dma */
-/* 0x0004: ctx_dma_query */
-	0x00000000,
-/* 0x0008: ctx_dma_src */
-	0x00000000,
-/* 0x000c: ctx_dma_dst */
-	0x00000000,
-/* 0x0010: ctx_query_address_high */
-	0x00000000,
-/* 0x0014: ctx_query_address_low */
-	0x00000000,
-/* 0x0018: ctx_query_counter */
-	0x00000000,
-/* 0x001c: ctx_src_address_high */
-	0x00000000,
-/* 0x0020: ctx_src_address_low */
-	0x00000000,
-/* 0x0024: ctx_src_pitch */
-	0x00000000,
-/* 0x0028: ctx_src_tile_mode */
-	0x00000000,
-/* 0x002c: ctx_src_xsize */
-	0x00000000,
-/* 0x0030: ctx_src_ysize */
-	0x00000000,
-/* 0x0034: ctx_src_zsize */
-	0x00000000,
-/* 0x0038: ctx_src_zoff */
-	0x00000000,
-/* 0x003c: ctx_src_xoff */
-	0x00000000,
-/* 0x0040: ctx_src_yoff */
-	0x00000000,
-/* 0x0044: ctx_src_cpp */
-	0x00000000,
-/* 0x0048: ctx_dst_address_high */
-	0x00000000,
-/* 0x004c: ctx_dst_address_low */
-	0x00000000,
-/* 0x0050: ctx_dst_pitch */
-	0x00000000,
-/* 0x0054: ctx_dst_tile_mode */
-	0x00000000,
-/* 0x0058: ctx_dst_xsize */
-	0x00000000,
-/* 0x005c: ctx_dst_ysize */
-	0x00000000,
-/* 0x0060: ctx_dst_zsize */
-	0x00000000,
-/* 0x0064: ctx_dst_zoff */
-	0x00000000,
-/* 0x0068: ctx_dst_xoff */
-	0x00000000,
-/* 0x006c: ctx_dst_yoff */
-	0x00000000,
-/* 0x0070: ctx_dst_cpp */
-	0x00000000,
-/* 0x0074: ctx_format */
-	0x00000000,
-/* 0x0078: ctx_swz_const0 */
-	0x00000000,
-/* 0x007c: ctx_swz_const1 */
-	0x00000000,
-/* 0x0080: ctx_xcnt */
-	0x00000000,
-/* 0x0084: ctx_ycnt */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: dispatch_table */
-	0x00010000,
-	0x00000000,
-	0x00000000,
-	0x00010040,
-	0x00010160,
-	0x00000000,
-	0x00010050,
-	0x00010162,
-	0x00000000,
-	0x00030060,
-/* 0x0128: dispatch_dma */
-	0x00010170,
-	0x00000000,
-	0x00010170,
-	0x00000000,
-	0x00010170,
-	0x00000000,
-	0x00070080,
-	0x00000028,
-	0xfffff000,
-	0x0000002c,
-	0xfff80000,
-	0x00000030,
-	0xffffe000,
-	0x00000034,
-	0xfffff800,
-	0x00000038,
-	0xfffff000,
-	0x0000003c,
-	0xfff80000,
-	0x00000040,
-	0xffffe000,
-	0x00070088,
-	0x00000054,
-	0xfffff000,
-	0x00000058,
-	0xfff80000,
-	0x0000005c,
-	0xffffe000,
-	0x00000060,
-	0xfffff800,
-	0x00000064,
-	0xfffff000,
-	0x00000068,
-	0xfff80000,
-	0x0000006c,
-	0xffffe000,
-	0x000200c0,
-	0x00010492,
-	0x00000000,
-	0x0001051b,
-	0x00000000,
-	0x000e00c3,
-	0x0000001c,
-	0xffffff00,
-	0x00000020,
-	0x00000000,
-	0x00000048,
-	0xffffff00,
-	0x0000004c,
-	0x00000000,
-	0x00000024,
-	0xfff80000,
-	0x00000050,
-	0xfff80000,
-	0x00000080,
-	0xffff0000,
-	0x00000084,
-	0xffffe000,
-	0x00000074,
-	0xfccc0000,
-	0x00000078,
-	0x00000000,
-	0x0000007c,
-	0x00000000,
-	0x00000010,
-	0xffffff00,
-	0x00000014,
-	0x00000000,
-	0x00000018,
-	0x00000000,
-	0x00000800,
-};
-
-uint32_t nva3_pcopy_code[] = {
-/* 0x0000: main */
-	0x04fe04bd,
-	0x3517f000,
-	0xf10010fe,
-	0xf1040017,
-	0xf0fff327,
-	0x12d00023,
-	0x0c25f0c0,
-	0xf40012d0,
-	0x17f11031,
-	0x27f01200,
-	0x0012d003,
-/* 0x002f: spin */
-	0xf40031f4,
-	0x0ef40028,
-/* 0x0035: ih */
-	0x8001cffd,
-	0xf40812c4,
-	0x21f4060b,
-/* 0x0041: ih_no_chsw */
-	0x0412c472,
-	0xf4060bf4,
-/* 0x004a: ih_no_cmd */
-	0x11c4c321,
-	0x4001d00c,
-/* 0x0052: swctx */
-	0x47f101f8,
-	0x4bfe7700,
-	0x0007fe00,
-	0xf00204b9,
-	0x01f40643,
-	0x0604fa09,
-/* 0x006b: swctx_load */
-	0xfa060ef4,
-/* 0x006e: swctx_done */
-	0x03f80504,
-/* 0x0072: chsw */
-	0x27f100f8,
-	0x23cf1400,
-	0x1e3fc800,
-	0xf4170bf4,
-	0x21f40132,
-	0x1e3af052,
-	0xf00023d0,
-	0x24d00147,
-/* 0x0093: chsw_no_unload */
-	0xcf00f880,
-	0x3dc84023,
-	0x220bf41e,
-	0xf40131f4,
-	0x57f05221,
-	0x0367f004,
-/* 0x00a8: chsw_load_ctx_dma */
-	0xa07856bc,
-	0xb6018068,
-	0x87d00884,
-	0x0162b600,
-/* 0x00bb: chsw_finish_load */
-	0xf0f018f4,
-	0x23d00237,
-/* 0x00c3: dispatch */
-	0xf100f880,
-	0xcf190037,
-	0x33cf4032,
-	0xff24e400,
-	0x1024b607,
-	0x010057f1,
-	0x74bd64bd,
-/* 0x00dc: dispatch_loop */
-	0x58005658,
-	0x50b60157,
-	0x0446b804,
-	0xbb4d08f4,
-	0x47b80076,
-	0x0f08f404,
-	0xb60276bb,
-	0x57bb0374,
-	0xdf0ef400,
-/* 0x0100: dispatch_valid_mthd */
-	0xb60246bb,
-	0x45bb0344,
-	0x01459800,
-	0xb00453fd,
-	0x1bf40054,
-	0x00455820,
-	0xb0014658,
-	0x1bf40064,
-	0x00538009,
-/* 0x0127: dispatch_cmd */
-	0xf4300ef4,
-	0x55f90132,
-	0xf40c01f4,
-/* 0x0132: dispatch_invalid_bitfield */
-	0x25f0250e,
-/* 0x0135: dispatch_illegal_mthd */
-	0x0125f002,
-/* 0x0138: dispatch_error */
-	0x100047f1,
-	0xd00042d0,
-	0x27f04043,
-	0x0002d040,
-/* 0x0148: hostirq_wait */
-	0xf08002cf,
-	0x24b04024,
-	0xf71bf400,
-/* 0x0154: dispatch_done */
-	0x1d0027f1,
-	0xd00137f0,
-	0x00f80023,
-/* 0x0160: cmd_nop */
-/* 0x0162: cmd_pm_trigger */
-	0x27f100f8,
-	0x34bd2200,
-	0xd00233f0,
-	0x00f80023,
-/* 0x0170: cmd_dma */
-	0x012842b7,
-	0xf00145b6,
-	0x43801e39,
-	0x0040b701,
-	0x0644b606,
-	0xf80043d0,
-/* 0x0189: cmd_exec_set_format */
-	0xf030f400,
-	0xb00001b0,
-	0x01b00101,
-	0x0301b002,
-	0xc71d0498,
-	0x50b63045,
-	0x3446c701,
-	0xc70160b6,
-	0x70b63847,
-	0x0232f401,
-	0x94bd84bd,
-/* 0x01b4: ncomp_loop */
-	0xb60f4ac4,
-	0xb4bd0445,
-/* 0x01bc: bpc_loop */
-	0xf404a430,
-	0xa5ff0f18,
-	0x00cbbbc0,
-	0xf40231f4,
-/* 0x01ce: cmp_c0 */
-	0x1bf4220e,
-	0x10c7f00c,
-	0xf400cbbb,
-/* 0x01da: cmp_c1 */
-	0xa430160e,
-	0x0c18f406,
-	0xbb14c7f0,
-	0x0ef400cb,
-/* 0x01e9: cmp_zero */
-	0x80c7f107,
-/* 0x01ed: bpc_next */
-	0x01c83800,
-	0xb60180b6,
-	0xb5b801b0,
-	0xc308f404,
-	0xb80190b6,
-	0x08f40497,
-	0x0065fdb2,
-	0x98110680,
-	0x68fd2008,
-	0x0502f400,
-/* 0x0216: dst_xcnt */
-	0x75fd64bd,
-	0x1c078000,
-	0xf10078fd,
-	0xb6081057,
-	0x56d00654,
-	0x4057d000,
-	0x080050b7,
-	0xb61c0698,
-	0x64b60162,
-	0x11079808,
-	0xfd0172b6,
-	0x56d00567,
-	0x0050b700,
-	0x0060b401,
-	0xb40056d0,
-	0x56d00160,
-	0x0260b440,
-	0xb48056d0,
-	0x56d00360,
-	0x0050b7c0,
-	0x1e069804,
-	0x980056d0,
-	0x56d01f06,
-	0x1030f440,
-/* 0x0276: cmd_exec_set_surface_tiled */
-	0x579800f8,
-	0x6879c70a,
-	0xb66478c7,
-	0x77c70280,
-	0x0e76b060,
-	0xf0091bf4,
-	0x0ef40477,
-/* 0x0291: xtile64 */
-	0x027cf00f,
-	0xfd1170b6,
-	0x77f00947,
-/* 0x029d: xtileok */
-	0x0f5a9806,
-	0xfd115b98,
-	0xb7f000ab,
-	0x04b7bb01,
-	0xff01b2b6,
-	0xa7bbc4ab,
-	0x105d9805,
-	0xbb01e7f0,
-	0xe2b604e8,
-	0xb4deff01,
-	0xb605d8bb,
-	0xef9401e0,
-	0x02ebbb0c,
-	0xf005fefd,
-	0x60b7026c,
-	0x64b60208,
-	0x006fd008,
-	0xbb04b7bb,
-	0x5f9800cb,
-	0x115b980b,
-	0xf000fbfd,
-	0xb7bb01b7,
-	0x01b2b604,
-	0xbb00fbbb,
-	0xf0f905f7,
-	0xf00c5f98,
-	0xb8bb01b7,
-	0x01b2b604,
-	0xbb00fbbb,
-	0xf0f905f8,
-	0xb60078bb,
-	0xb7f00282,
-	0x04b8bb01,
-	0x9804b9bb,
-	0xe7f00e58,
-	0x04e9bb01,
-	0xff01e2b6,
-	0xf7bbf48e,
-	0x00cfbb04,
-	0xbb0079bb,
-	0xf0fc0589,
-	0xd9fd90fc,
-	0x00adbb00,
-	0xfd0089fd,
-	0xa8bb008f,
-	0x04a7bb00,
-	0xbb0192b6,
-	0x69d00497,
-	0x08579880,
-	0xbb075898,
-	0x7abb00ac,
-	0x0081b600,
-	0xfd1084b6,
-	0x62b7058b,
-	0x67d00600,
-	0x0060b700,
-	0x0068d004,
-/* 0x0382: cmd_exec_set_surface_linear */
-	0x6cf000f8,
-	0x0260b702,
-	0x0864b602,
-	0xd0085798,
-	0x60b70067,
-	0x57980400,
-	0x1074b607,
-	0xb70067d0,
-	0x98040060,
-	0x67d00957,
-/* 0x03ab: cmd_exec_wait */
-	0xf900f800,
-	0xf110f900,
-	0xb6080007,
-/* 0x03b6: loop */
-	0x01cf0604,
-	0x0114f000,
-	0xfcfa1bf4,
-	0xf800fc10,
-/* 0x03c5: cmd_exec_query */
-	0x0d34c800,
-	0xf5701bf4,
-	0xf103ab21,
-	0xb6080c47,
-	0x05980644,
-	0x0450b605,
-	0xd00045d0,
-	0x57f04040,
-	0x8045d00c,
-	0x040040b7,
-	0xb6040598,
-	0x45d01054,
-	0x0040b700,
-	0x0057f105,
-	0x0153f00b,
-	0xf10045d0,
-	0xb6404057,
-	0x53f10154,
-	0x45d08080,
-	0x1057f140,
-	0x1253f111,
-	0x8045d013,
-	0x151457f1,
-	0x171653f1,
-	0xf1c045d0,
-	0xf0260157,
-	0x47f10153,
-	0x44b60800,
-	0x0045d006,
-/* 0x0438: query_counter */
-	0x03ab21f5,
-	0x080c47f1,
-	0x980644b6,
-	0x45d00505,
-	0x4040d000,
-	0xd00457f0,
-	0x40b78045,
-	0x05980400,
-	0x1054b604,
-	0xb70045d0,
-	0xf1050040,
-	0xd0030057,
-	0x57f10045,
-	0x53f11110,
-	0x45d01312,
-	0x06059840,
-	0x050040b7,
-	0xf10045d0,
-	0xf0260157,
-	0x47f10153,
-	0x44b60800,
-	0x0045d006,
-/* 0x0492: cmd_exec */
-	0x21f500f8,
-	0x3fc803ab,
-	0x0e0bf400,
-	0x018921f5,
-	0x020047f1,
-/* 0x04a7: cmd_exec_no_format */
-	0xf11e0ef4,
-	0xb6081067,
-	0x77f00664,
-	0x11078001,
-	0x981c0780,
-	0x67d02007,
-	0x4067d000,
-/* 0x04c2: cmd_exec_init_src_surface */
-	0x32f444bd,
-	0xc854bd02,
-	0x0bf4043f,
-	0x8221f50a,
-	0x0a0ef403,
-/* 0x04d4: src_tiled */
-	0x027621f5,
-/* 0x04db: cmd_exec_init_dst_surface */
-	0xf40749f0,
-	0x57f00231,
-	0x083fc82c,
-	0xf50a0bf4,
-	0xf4038221,
-/* 0x04ee: dst_tiled */
-	0x21f50a0e,
-	0x49f00276,
-/* 0x04f5: cmd_exec_kick */
-	0x0057f108,
-	0x0654b608,
-	0xd0210698,
-	0x67f04056,
-	0x0063f141,
-	0x0546fd44,
-	0xc80054d0,
-	0x0bf40c3f,
-	0xc521f507,
-/* 0x0519: cmd_exec_done */
-/* 0x051b: cmd_wrcache_flush */
-	0xf100f803,
-	0xbd220027,
-	0x0133f034,
-	0xf80023d0,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
deleted file mode 100644
index 98cc421..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
+++ /dev/null
@@ -1,606 +0,0 @@
-uint32_t nvc0_pcopy_data[] = {
-/* 0x0000: ctx_object */
-	0x00000000,
-/* 0x0004: ctx_query_address_high */
-	0x00000000,
-/* 0x0008: ctx_query_address_low */
-	0x00000000,
-/* 0x000c: ctx_query_counter */
-	0x00000000,
-/* 0x0010: ctx_src_address_high */
-	0x00000000,
-/* 0x0014: ctx_src_address_low */
-	0x00000000,
-/* 0x0018: ctx_src_pitch */
-	0x00000000,
-/* 0x001c: ctx_src_tile_mode */
-	0x00000000,
-/* 0x0020: ctx_src_xsize */
-	0x00000000,
-/* 0x0024: ctx_src_ysize */
-	0x00000000,
-/* 0x0028: ctx_src_zsize */
-	0x00000000,
-/* 0x002c: ctx_src_zoff */
-	0x00000000,
-/* 0x0030: ctx_src_xoff */
-	0x00000000,
-/* 0x0034: ctx_src_yoff */
-	0x00000000,
-/* 0x0038: ctx_src_cpp */
-	0x00000000,
-/* 0x003c: ctx_dst_address_high */
-	0x00000000,
-/* 0x0040: ctx_dst_address_low */
-	0x00000000,
-/* 0x0044: ctx_dst_pitch */
-	0x00000000,
-/* 0x0048: ctx_dst_tile_mode */
-	0x00000000,
-/* 0x004c: ctx_dst_xsize */
-	0x00000000,
-/* 0x0050: ctx_dst_ysize */
-	0x00000000,
-/* 0x0054: ctx_dst_zsize */
-	0x00000000,
-/* 0x0058: ctx_dst_zoff */
-	0x00000000,
-/* 0x005c: ctx_dst_xoff */
-	0x00000000,
-/* 0x0060: ctx_dst_yoff */
-	0x00000000,
-/* 0x0064: ctx_dst_cpp */
-	0x00000000,
-/* 0x0068: ctx_format */
-	0x00000000,
-/* 0x006c: ctx_swz_const0 */
-	0x00000000,
-/* 0x0070: ctx_swz_const1 */
-	0x00000000,
-/* 0x0074: ctx_xcnt */
-	0x00000000,
-/* 0x0078: ctx_ycnt */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: dispatch_table */
-	0x00010000,
-	0x00000000,
-	0x00000000,
-	0x00010040,
-	0x0001019f,
-	0x00000000,
-	0x00010050,
-	0x000101a1,
-	0x00000000,
-	0x00070080,
-	0x0000001c,
-	0xfffff000,
-	0x00000020,
-	0xfff80000,
-	0x00000024,
-	0xffffe000,
-	0x00000028,
-	0xfffff800,
-	0x0000002c,
-	0xfffff000,
-	0x00000030,
-	0xfff80000,
-	0x00000034,
-	0xffffe000,
-	0x00070088,
-	0x00000048,
-	0xfffff000,
-	0x0000004c,
-	0xfff80000,
-	0x00000050,
-	0xffffe000,
-	0x00000054,
-	0xfffff800,
-	0x00000058,
-	0xfffff000,
-	0x0000005c,
-	0xfff80000,
-	0x00000060,
-	0xffffe000,
-	0x000200c0,
-	0x000104b8,
-	0x00000000,
-	0x00010541,
-	0x00000000,
-	0x000e00c3,
-	0x00000010,
-	0xffffff00,
-	0x00000014,
-	0x00000000,
-	0x0000003c,
-	0xffffff00,
-	0x00000040,
-	0x00000000,
-	0x00000018,
-	0xfff80000,
-	0x00000044,
-	0xfff80000,
-	0x00000074,
-	0xffff0000,
-	0x00000078,
-	0xffffe000,
-	0x00000068,
-	0xfccc0000,
-	0x0000006c,
-	0x00000000,
-	0x00000070,
-	0x00000000,
-	0x00000004,
-	0xffffff00,
-	0x00000008,
-	0x00000000,
-	0x0000000c,
-	0x00000000,
-	0x00000800,
-};
-
-uint32_t nvc0_pcopy_code[] = {
-/* 0x0000: main */
-	0x04fe04bd,
-	0x3517f000,
-	0xf10010fe,
-	0xf1040017,
-	0xf0fff327,
-	0x12d00023,
-	0x0c25f0c0,
-	0xf40012d0,
-	0x17f11031,
-	0x27f01200,
-	0x0012d003,
-/* 0x002f: spin */
-	0xf40031f4,
-	0x0ef40028,
-/* 0x0035: ih */
-	0x8001cffd,
-	0xf40812c4,
-	0x21f4060b,
-/* 0x0041: ih_no_chsw */
-	0x0412c4ca,
-	0xf5070bf4,
-/* 0x004b: ih_no_cmd */
-	0xc4010221,
-	0x01d00c11,
-/* 0x0053: swctx */
-	0xf101f840,
-	0xfe770047,
-	0x47f1004b,
-	0x44cf2100,
-	0x0144f000,
-	0xb60444b6,
-	0xf7f13040,
-	0xf4b6061c,
-	0x1457f106,
-	0x00f5d101,
-	0xb6043594,
-	0x57fe0250,
-	0x0145fe00,
-	0x010052b7,
-	0x00ff67f1,
-	0x56fd60bd,
-	0x0253f004,
-	0xf80545fa,
-	0x0053f003,
-	0xd100e7f0,
-	0x549800fe,
-	0x0845b600,
-	0xb6015698,
-	0x46fd1864,
-	0x0047fe05,
-	0xf00204b9,
-	0x01f40643,
-	0x0604fa09,
-/* 0x00c3: swctx_load */
-	0xfa060ef4,
-/* 0x00c6: swctx_done */
-	0x03f80504,
-/* 0x00ca: chsw */
-	0x27f100f8,
-	0x23cf1400,
-	0x1e3fc800,
-	0xf4170bf4,
-	0x21f40132,
-	0x1e3af053,
-	0xf00023d0,
-	0x24d00147,
-/* 0x00eb: chsw_no_unload */
-	0xcf00f880,
-	0x3dc84023,
-	0x090bf41e,
-	0xf40131f4,
-/* 0x00fa: chsw_finish_load */
-	0x37f05321,
-	0x8023d002,
-/* 0x0102: dispatch */
-	0x37f100f8,
-	0x32cf1900,
-	0x0033cf40,
-	0x07ff24e4,
-	0xf11024b6,
-	0xbd010057,
-/* 0x011b: dispatch_loop */
-	0x5874bd64,
-	0x57580056,
-	0x0450b601,
-	0xf40446b8,
-	0x76bb4d08,
-	0x0447b800,
-	0xbb0f08f4,
-	0x74b60276,
-	0x0057bb03,
-/* 0x013f: dispatch_valid_mthd */
-	0xbbdf0ef4,
-	0x44b60246,
-	0x0045bb03,
-	0xfd014598,
-	0x54b00453,
-	0x201bf400,
-	0x58004558,
-	0x64b00146,
-	0x091bf400,
-	0xf4005380,
-/* 0x0166: dispatch_cmd */
-	0x32f4300e,
-	0xf455f901,
-	0x0ef40c01,
-/* 0x0171: dispatch_invalid_bitfield */
-	0x0225f025,
-/* 0x0174: dispatch_illegal_mthd */
-/* 0x0177: dispatch_error */
-	0xf10125f0,
-	0xd0100047,
-	0x43d00042,
-	0x4027f040,
-/* 0x0187: hostirq_wait */
-	0xcf0002d0,
-	0x24f08002,
-	0x0024b040,
-/* 0x0193: dispatch_done */
-	0xf1f71bf4,
-	0xf01d0027,
-	0x23d00137,
-/* 0x019f: cmd_nop */
-	0xf800f800,
-/* 0x01a1: cmd_pm_trigger */
-	0x0027f100,
-	0xf034bd22,
-	0x23d00233,
-/* 0x01af: cmd_exec_set_format */
-	0xf400f800,
-	0x01b0f030,
-	0x0101b000,
-	0xb00201b0,
-	0x04980301,
-	0x3045c71a,
-	0xc70150b6,
-	0x60b63446,
-	0x3847c701,
-	0xf40170b6,
-	0x84bd0232,
-/* 0x01da: ncomp_loop */
-	0x4ac494bd,
-	0x0445b60f,
-/* 0x01e2: bpc_loop */
-	0xa430b4bd,
-	0x0f18f404,
-	0xbbc0a5ff,
-	0x31f400cb,
-	0x220ef402,
-/* 0x01f4: cmp_c0 */
-	0xf00c1bf4,
-	0xcbbb10c7,
-	0x160ef400,
-/* 0x0200: cmp_c1 */
-	0xf406a430,
-	0xc7f00c18,
-	0x00cbbb14,
-/* 0x020f: cmp_zero */
-	0xf1070ef4,
-/* 0x0213: bpc_next */
-	0x380080c7,
-	0x80b601c8,
-	0x01b0b601,
-	0xf404b5b8,
-	0x90b6c308,
-	0x0497b801,
-	0xfdb208f4,
-	0x06800065,
-	0x1d08980e,
-	0xf40068fd,
-	0x64bd0502,
-/* 0x023c: dst_xcnt */
-	0x800075fd,
-	0x78fd1907,
-	0x1057f100,
-	0x0654b608,
-	0xd00056d0,
-	0x50b74057,
-	0x06980800,
-	0x0162b619,
-	0x980864b6,
-	0x72b60e07,
-	0x0567fd01,
-	0xb70056d0,
-	0xb4010050,
-	0x56d00060,
-	0x0160b400,
-	0xb44056d0,
-	0x56d00260,
-	0x0360b480,
-	0xb7c056d0,
-	0x98040050,
-	0x56d01b06,
-	0x1c069800,
-	0xf44056d0,
-	0x00f81030,
-/* 0x029c: cmd_exec_set_surface_tiled */
-	0xc7075798,
-	0x78c76879,
-	0x0380b664,
-	0xb06077c7,
-	0x1bf40e76,
-	0x0477f009,
-/* 0x02b7: xtile64 */
-	0xf00f0ef4,
-	0x70b6027c,
-	0x0947fd11,
-/* 0x02c3: xtileok */
-	0x980677f0,
-	0x5b980c5a,
-	0x00abfd0e,
-	0xbb01b7f0,
-	0xb2b604b7,
-	0xc4abff01,
-	0x9805a7bb,
-	0xe7f00d5d,
-	0x04e8bb01,
-	0xff01e2b6,
-	0xd8bbb4de,
-	0x01e0b605,
-	0xbb0cef94,
-	0xfefd02eb,
-	0x026cf005,
-	0x020860b7,
-	0xd00864b6,
-	0xb7bb006f,
-	0x00cbbb04,
-	0x98085f98,
-	0xfbfd0e5b,
-	0x01b7f000,
-	0xb604b7bb,
-	0xfbbb01b2,
-	0x05f7bb00,
-	0x5f98f0f9,
-	0x01b7f009,
-	0xb604b8bb,
-	0xfbbb01b2,
-	0x05f8bb00,
-	0x78bbf0f9,
-	0x0282b600,
-	0xbb01b7f0,
-	0xb9bb04b8,
-	0x0b589804,
-	0xbb01e7f0,
-	0xe2b604e9,
-	0xf48eff01,
-	0xbb04f7bb,
-	0x79bb00cf,
-	0x0589bb00,
-	0x90fcf0fc,
-	0xbb00d9fd,
-	0x89fd00ad,
-	0x008ffd00,
-	0xbb00a8bb,
-	0x92b604a7,
-	0x0497bb01,
-	0x988069d0,
-	0x58980557,
-	0x00acbb04,
-	0xb6007abb,
-	0x84b60081,
-	0x058bfd10,
-	0x060062b7,
-	0xb70067d0,
-	0xd0040060,
-	0x00f80068,
-/* 0x03a8: cmd_exec_set_surface_linear */
-	0xb7026cf0,
-	0xb6020260,
-	0x57980864,
-	0x0067d005,
-	0x040060b7,
-	0xb6045798,
-	0x67d01074,
-	0x0060b700,
-	0x06579804,
-	0xf80067d0,
-/* 0x03d1: cmd_exec_wait */
-	0xf900f900,
-	0x0007f110,
-	0x0604b608,
-/* 0x03dc: loop */
-	0xf00001cf,
-	0x1bf40114,
-	0xfc10fcfa,
-/* 0x03eb: cmd_exec_query */
-	0xc800f800,
-	0x1bf40d34,
-	0xd121f570,
-	0x0c47f103,
-	0x0644b608,
-	0xb6020598,
-	0x45d00450,
-	0x4040d000,
-	0xd00c57f0,
-	0x40b78045,
-	0x05980400,
-	0x1054b601,
-	0xb70045d0,
-	0xf1050040,
-	0xf00b0057,
-	0x45d00153,
-	0x4057f100,
-	0x0154b640,
-	0x808053f1,
-	0xf14045d0,
-	0xf1111057,
-	0xd0131253,
-	0x57f18045,
-	0x53f11514,
-	0x45d01716,
-	0x0157f1c0,
-	0x0153f026,
-	0x080047f1,
-	0xd00644b6,
-/* 0x045e: query_counter */
-	0x21f50045,
-	0x47f103d1,
-	0x44b6080c,
-	0x02059806,
-	0xd00045d0,
-	0x57f04040,
-	0x8045d004,
-	0x040040b7,
-	0xb6010598,
-	0x45d01054,
-	0x0040b700,
-	0x0057f105,
-	0x0045d003,
-	0x111057f1,
-	0x131253f1,
-	0x984045d0,
-	0x40b70305,
-	0x45d00500,
-	0x0157f100,
-	0x0153f026,
-	0x080047f1,
-	0xd00644b6,
-	0x00f80045,
-/* 0x04b8: cmd_exec */
-	0x03d121f5,
-	0xf4003fc8,
-	0x21f50e0b,
-	0x47f101af,
-	0x0ef40200,
-/* 0x04cd: cmd_exec_no_format */
-	0x1067f11e,
-	0x0664b608,
-	0x800177f0,
-	0x07800e07,
-	0x1d079819,
-	0xd00067d0,
-	0x44bd4067,
-/* 0x04e8: cmd_exec_init_src_surface */
-	0xbd0232f4,
-	0x043fc854,
-	0xf50a0bf4,
-	0xf403a821,
-/* 0x04fa: src_tiled */
-	0x21f50a0e,
-	0x49f0029c,
-/* 0x0501: cmd_exec_init_dst_surface */
-	0x0231f407,
-	0xc82c57f0,
-	0x0bf4083f,
-	0xa821f50a,
-	0x0a0ef403,
-/* 0x0514: dst_tiled */
-	0x029c21f5,
-/* 0x051b: cmd_exec_kick */
-	0xf10849f0,
-	0xb6080057,
-	0x06980654,
-	0x4056d01e,
-	0xf14167f0,
-	0xfd440063,
-	0x54d00546,
-	0x0c3fc800,
-	0xf5070bf4,
-/* 0x053f: cmd_exec_done */
-	0xf803eb21,
-/* 0x0541: cmd_wrcache_flush */
-	0x0027f100,
-	0xf034bd22,
-	0x23d00133,
-	0x0000f800,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
deleted file mode 100644
index abb410e..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/copy.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <core/client.h>
-#include <core/enum.h>
-
-
-#include "fuc/nva3.fuc.h"
-
-struct nva3_copy_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_copy_sclass[] = {
-	{ 0x85b5, &nouveau_object_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_copy_cclass = {
-	.handle = NV_ENGCTX(COPY0, 0xa3),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-
-	},
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_enum nva3_copy_isr_error_name[] = {
-	{ 0x0001, "ILLEGAL_MTHD" },
-	{ 0x0002, "INVALID_ENUM" },
-	{ 0x0003, "INVALID_BITFIELD" },
-	{}
-};
-
-void
-nva3_copy_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_falcon *falcon = (void *)subdev;
-	struct nouveau_object *engctx;
-	u32 dispatch = nv_ro32(falcon, 0x01c);
-	u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
-	u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
-	u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
-	u32 addr = nv_ro32(falcon, 0x040) >> 16;
-	u32 mthd = (addr & 0x07ff) << 2;
-	u32 subc = (addr & 0x3800) >> 11;
-	u32 data = nv_ro32(falcon, 0x044);
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x00000040) {
-		nv_error(falcon, "DISPATCH_ERROR [");
-		nouveau_enum_print(nva3_copy_isr_error_name, ssta);
-		pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
-		       chid, inst << 12, nouveau_client_name(engctx), subc,
-		       mthd, data);
-		nv_wo32(falcon, 0x004, 0x00000040);
-		stat &= ~0x00000040;
-	}
-
-	if (stat) {
-		nv_error(falcon, "unhandled intr 0x%08x\n", stat);
-		nv_wo32(falcon, 0x004, stat);
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	bool enable = (nv_device(parent)->chipset != 0xaf);
-	struct nva3_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, enable,
-				    "PCE0", "copy0", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00802000;
-	nv_subdev(priv)->intr = nva3_copy_intr;
-	nv_engine(priv)->cclass = &nva3_copy_cclass;
-	nv_engine(priv)->sclass = nva3_copy_sclass;
-	nv_falcon(priv)->code.data = nva3_pcopy_code;
-	nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
-	nv_falcon(priv)->data.data = nva3_pcopy_data;
-	nv_falcon(priv)->data.size = sizeof(nva3_pcopy_data);
-	return 0;
-}
-
-struct nouveau_oclass
-nva3_copy_oclass = {
-	.handle = NV_ENGINE(COPY0, 0xa3),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_copy_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = _nouveau_falcon_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
deleted file mode 100644
index 9261694..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/copy.h>
-
-#include <core/enum.h>
-#include <core/enum.h>
-
-#include "fuc/nvc0.fuc.h"
-
-struct nvc0_copy_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_copy0_sclass[] = {
-	{ 0x90b5, &nouveau_object_ofuncs },
-	{},
-};
-
-static struct nouveau_oclass
-nvc0_copy1_sclass[] = {
-	{ 0x90b8, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_ofuncs
-nvc0_copy_context_ofuncs = {
-	.ctor = _nouveau_falcon_context_ctor,
-	.dtor = _nouveau_falcon_context_dtor,
-	.init = _nouveau_falcon_context_init,
-	.fini = _nouveau_falcon_context_fini,
-	.rd32 = _nouveau_falcon_context_rd32,
-	.wr32 = _nouveau_falcon_context_wr32,
-};
-
-static struct nouveau_oclass
-nvc0_copy0_cclass = {
-	.handle = NV_ENGCTX(COPY0, 0xc0),
-	.ofuncs = &nvc0_copy_context_ofuncs,
-};
-
-static struct nouveau_oclass
-nvc0_copy1_cclass = {
-	.handle = NV_ENGCTX(COPY1, 0xc0),
-	.ofuncs = &nvc0_copy_context_ofuncs,
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_copy_init(struct nouveau_object *object)
-{
-	struct nvc0_copy_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wo32(priv, 0x084, nv_engidx(object) - NVDEV_ENGINE_COPY0);
-	return 0;
-}
-
-static int
-nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvc0_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true,
-				    "PCE0", "copy0", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000040;
-	nv_subdev(priv)->intr = nva3_copy_intr;
-	nv_engine(priv)->cclass = &nvc0_copy0_cclass;
-	nv_engine(priv)->sclass = nvc0_copy0_sclass;
-	nv_falcon(priv)->code.data = nvc0_pcopy_code;
-	nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
-	nv_falcon(priv)->data.data = nvc0_pcopy_data;
-	nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
-	return 0;
-}
-
-static int
-nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvc0_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true,
-				    "PCE1", "copy1", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000080;
-	nv_subdev(priv)->intr = nva3_copy_intr;
-	nv_engine(priv)->cclass = &nvc0_copy1_cclass;
-	nv_engine(priv)->sclass = nvc0_copy1_sclass;
-	nv_falcon(priv)->code.data = nvc0_pcopy_code;
-	nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
-	nv_falcon(priv)->data.data = nvc0_pcopy_data;
-	nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_copy0_oclass = {
-	.handle = NV_ENGINE(COPY0, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_copy0_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nvc0_copy_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
-
-struct nouveau_oclass
-nvc0_copy1_oclass = {
-	.handle = NV_ENGINE(COPY1, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_copy1_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nvc0_copy_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
deleted file mode 100644
index c7194b3..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-
-#include <engine/copy.h>
-
-struct nve0_copy_priv {
-	struct nouveau_engine base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_copy_sclass[] = {
-	{ 0xa0b5, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_ofuncs
-nve0_copy_context_ofuncs = {
-	.ctor = _nouveau_engctx_ctor,
-	.dtor = _nouveau_engctx_dtor,
-	.init = _nouveau_engctx_init,
-	.fini = _nouveau_engctx_fini,
-	.rd32 = _nouveau_engctx_rd32,
-	.wr32 = _nouveau_engctx_wr32,
-};
-
-static struct nouveau_oclass
-nve0_copy_cclass = {
-	.handle = NV_ENGCTX(COPY0, 0xc0),
-	.ofuncs = &nve0_copy_context_ofuncs,
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static void
-nve0_copy_intr(struct nouveau_subdev *subdev)
-{
-	const int ce = nv_subidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
-	struct nve0_copy_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
-
-	if (stat) {
-		nv_warn(priv, "unhandled intr 0x%08x\n", stat);
-		nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
-	}
-}
-
-static int
-nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nve0_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_engine_create(parent, engine, oclass, true,
-				    "PCE0", "copy0", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000040;
-	nv_subdev(priv)->intr = nve0_copy_intr;
-	nv_engine(priv)->cclass = &nve0_copy_cclass;
-	nv_engine(priv)->sclass = nve0_copy_sclass;
-	return 0;
-}
-
-static int
-nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nve0_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_engine_create(parent, engine, oclass, true,
-				    "PCE1", "copy1", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000080;
-	nv_subdev(priv)->intr = nve0_copy_intr;
-	nv_engine(priv)->cclass = &nve0_copy_cclass;
-	nv_engine(priv)->sclass = nve0_copy_sclass;
-	return 0;
-}
-
-static int
-nve0_copy2_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nve0_copy_priv *priv;
-	int ret;
-
-	ret = nouveau_engine_create(parent, engine, oclass, true,
-				    "PCE2", "copy2", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00200000;
-	nv_subdev(priv)->intr = nve0_copy_intr;
-	nv_engine(priv)->cclass = &nve0_copy_cclass;
-	nv_engine(priv)->sclass = nve0_copy_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_copy0_oclass = {
-	.handle = NV_ENGINE(COPY0, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_copy0_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
-	},
-};
-
-struct nouveau_oclass
-nve0_copy1_oclass = {
-	.handle = NV_ENGINE(COPY1, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_copy1_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
-	},
-};
-
-struct nouveau_oclass
-nve0_copy2_oclass = {
-	.handle = NV_ENGINE(COPY2, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_copy2_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc
deleted file mode 100644
index 629da02..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- *  fuc microcode for nv98 pcrypt engine
- *  Copyright (C) 2010  Marcin Kościelnicki
- *
- *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-.section #nv98_pcrypt_data
-
-ctx_dma:
-ctx_dma_query:		.b32 0
-ctx_dma_src:		.b32 0
-ctx_dma_dst:		.b32 0
-.equ #dma_count 3
-ctx_query_address_high:	.b32 0
-ctx_query_address_low:	.b32 0
-ctx_query_counter:	.b32 0
-ctx_cond_address_high:	.b32 0
-ctx_cond_address_low:	.b32 0
-ctx_cond_off:		.b32 0
-ctx_src_address_high:	.b32 0
-ctx_src_address_low:	.b32 0
-ctx_dst_address_high:	.b32 0
-ctx_dst_address_low:	.b32 0
-ctx_mode:		.b32 0
-.align 16
-ctx_key:		.skip 16
-ctx_iv:			.skip 16
-
-.align 0x80
-swap:
-.skip 32
-
-.align 8
-common_cmd_dtable:
-.b32 #ctx_query_address_high + 0x20000 ~0xff
-.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
-.b32 #ctx_query_counter + 0x20000 ~0xffffffff
-.b32 #cmd_query_get + 0x00000 ~1
-.b32 #ctx_cond_address_high + 0x20000 ~0xff
-.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
-.b32 #cmd_cond_mode + 0x00000 ~7
-.b32 #cmd_wrcache_flush + 0x00000 ~0
-.equ #common_cmd_max 0x88
-
-
-.align 8
-engine_cmd_dtable:
-.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
-.b32 #ctx_src_address_high + 0x20000 ~0xff
-.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
-.b32 #ctx_dst_address_high + 0x20000 ~0xff
-.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
-.b32 #crypt_cmd_mode + 0x00000 ~0xf
-.b32 #crypt_cmd_length + 0x10000 ~0x0ffffff0
-.equ #engine_cmd_max 0xce
-
-.align 4
-crypt_dtable:
-.b16 #crypt_copy_prep #crypt_do_inout
-.b16 #crypt_store_prep #crypt_do_out
-.b16 #crypt_ecb_e_prep #crypt_do_inout
-.b16 #crypt_ecb_d_prep #crypt_do_inout
-.b16 #crypt_cbc_e_prep #crypt_do_inout
-.b16 #crypt_cbc_d_prep #crypt_do_inout
-.b16 #crypt_pcbc_e_prep #crypt_do_inout
-.b16 #crypt_pcbc_d_prep #crypt_do_inout
-.b16 #crypt_cfb_e_prep #crypt_do_inout
-.b16 #crypt_cfb_d_prep #crypt_do_inout
-.b16 #crypt_ofb_prep #crypt_do_inout
-.b16 #crypt_ctr_prep #crypt_do_inout
-.b16 #crypt_cbc_mac_prep #crypt_do_in
-.b16 #crypt_cmac_finish_complete_prep #crypt_do_in
-.b16 #crypt_cmac_finish_partial_prep #crypt_do_in
-
-.align 0x100
-
-.section #nv98_pcrypt_code
-
-	// $r0 is always set to 0 in our code - this allows some space savings.
-	clear b32 $r0
-
-	// set up the interrupt handler
-	mov $r1 #ih
-	mov $iv0 $r1
-
-	// init stack pointer
-	mov $sp $r0
-
-	// set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
-	movw $r1 0xfff0
-	sethi $r1 0
-	mov $r2 0x400
-	iowr I[$r2 + 0x300] $r1
-
-	// enable the interrupts
-	or $r1 0xc
-	iowr I[$r2] $r1
-
-	// enable fifo access and context switching
-	mov $r1 3
-	mov $r2 0x1200
-	iowr I[$r2] $r1
-
-	// enable i0 delivery
-	bset $flags ie0
-
-	// sleep forver, waking only for interrupts.
-	bset $flags $p0
-	spin:
-	sleep $p0
-	bra #spin
-
-// i0 handler
-ih:
-	// see which interrupts we got
-	iord $r1 I[$r0 + 0x200]
-
-	and $r2 $r1 0x8
-	cmpu b32 $r2 0
-	bra e #noctx
-
-		// context switch... prepare the regs for xfer
-		mov $r2 0x7700
-		mov $xtargets $r2
-		mov $xdbase $r0
-		// 128-byte context.
-		mov $r2 0
-		sethi $r2 0x50000
-
-		// read current channel
-		mov $r3 0x1400
-		iord $r4 I[$r3]
-		// if bit 30 set, it's active, so we have to unload it first.
-		shl b32 $r5 $r4 1
-		cmps b32 $r5 0
-		bra nc #ctxload
-
-			// unload the current channel - save the context
-			xdst $r0 $r2
-			xdwait
-			// and clear bit 30, then write back
-			bclr $r4 0x1e
-			iowr I[$r3] $r4
-			// tell PFIFO we unloaded
-			mov $r4 1
-			iowr I[$r3 + 0x200] $r4
-
-		bra #noctx
-
-		ctxload:
-			// no channel loaded - perhaps we're requested to load one
-			iord $r4 I[$r3 + 0x100]
-			shl b32 $r15 $r4 1
-			cmps b32 $r15 0
-			// if bit 30 of next channel not set, probably PFIFO is just
-			// killing a context. do a faux load, without the active bit.
-			bra nc #dummyload
-
-				// ok, do a real context load.
-				xdld $r0 $r2
-				xdwait
-				mov $r5 #ctx_dma
-				mov $r6 #dma_count - 1
-				ctxload_dma_loop:
-					ld b32 $r7 D[$r5 + $r6 * 4]
-					add b32 $r8 $r6 0x180
-					shl b32 $r8 8
-					iowr I[$r8] $r7
-					sub b32 $r6 1
-				bra nc #ctxload_dma_loop
-
-			dummyload:
-			// tell PFIFO we're done
-			mov $r5 2
-			iowr I[$r3 + 0x200] $r5
-
-	noctx:
-	and $r2 $r1 0x4
-	cmpu b32 $r2 0
-	bra e #nocmd
-
-		// incoming fifo command.
-		mov $r3 0x1900
-		iord $r2 I[$r3 + 0x100]
-		iord $r3 I[$r3]
-		// extract the method
-		and $r4 $r2 0x7ff
-		// shift the addr to proper position if we need to interrupt later
-		shl b32 $r2 0x10
-
-		// mthd 0 and 0x100 [NAME, NOP]: ignore
-		and $r5 $r4 0x7bf
-		cmpu b32 $r5 0
-		bra e #cmddone
-
-		mov $r5 #engine_cmd_dtable - 0xc0 * 8
-		mov $r6 #engine_cmd_max
-		cmpu b32 $r4 0xc0
-		bra nc #dtable_cmd
-		mov $r5 #common_cmd_dtable - 0x80 * 8
-		mov $r6 #common_cmd_max
-		cmpu b32 $r4 0x80
-		bra nc #dtable_cmd
-		cmpu b32 $r4 0x60
-		bra nc #dma_cmd
-		cmpu b32 $r4 0x50
-		bra ne #illegal_mthd
-
-			// mthd 0x140: PM_TRIGGER
-			mov $r2 0x2200
-			clear b32 $r3
-			sethi $r3 0x20000
-			iowr I[$r2] $r3
-			bra #cmddone
-
-		dma_cmd:
-			// mthd 0x180...: DMA_*
-			cmpu b32 $r4 0x60+#dma_count
-			bra nc #illegal_mthd
-			shl b32 $r5 $r4 2
-			add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
-			bset $r3 0x1e
-			st b32 D[$r5] $r3
-			add b32 $r4 0x180 - 0x60
-			shl b32 $r4 8
-			iowr I[$r4] $r3
-			bra #cmddone
-
-		dtable_cmd:
-			cmpu b32 $r4 $r6
-			bra nc #illegal_mthd
-			shl b32 $r4 3
-			add b32 $r4 $r5
-			ld b32 $r5 D[$r4 + 4]
-			and $r5 $r3
-			cmpu b32 $r5 0
-			bra ne #invalid_bitfield
-			ld b16 $r5 D[$r4]
-			ld b16 $r6 D[$r4 + 2]
-			cmpu b32 $r6 2
-			bra e #cmd_setctx
-			ld b32 $r7 D[$r0 + #ctx_cond_off]
-			and $r6 $r7
-			cmpu b32 $r6 1
-			bra e #cmddone
-			call $r5
-			bra $p1 #dispatch_error
-			bra #cmddone
-
-		cmd_setctx:
-			st b32 D[$r5] $r3
-			bra #cmddone
-
-
-		invalid_bitfield:
-			or $r2 1
-		dispatch_error:
-		illegal_mthd:
-			mov $r4 0x1000
-			iowr I[$r4] $r2
-			iowr I[$r4 + 0x100] $r3
-			mov $r4 0x40
-			iowr I[$r0] $r4
-
-			im_loop:
-				iord $r4 I[$r0 + 0x200]
-				and $r4 0x40
-				cmpu b32 $r4 0
-			bra ne #im_loop
-
-		cmddone:
-		// remove the command from FIFO
-		mov $r3 0x1d00
-		mov $r4 1
-		iowr I[$r3] $r4
-
-	nocmd:
-	// ack the processed interrupts
-	and $r1 $r1 0xc
-	iowr I[$r0 + 0x100] $r1
-iret
-
-cmd_query_get:
-	// if bit 0 of param set, trigger interrupt afterwards.
-	setp $p1 $r3
-	or $r2 3
-
-	// read PTIMER, beware of races...
-	mov $r4 0xb00
-	ptimer_retry:
-		iord $r6 I[$r4 + 0x100]
-		iord $r5 I[$r4]
-		iord $r7 I[$r4 + 0x100]
-		cmpu b32 $r6 $r7
-	bra ne #ptimer_retry
-
-	// prepare the query structure
-	ld b32 $r4 D[$r0 + #ctx_query_counter]
-	st b32 D[$r0 + #swap + 0x0] $r4
-	st b32 D[$r0 + #swap + 0x4] $r0
-	st b32 D[$r0 + #swap + 0x8] $r5
-	st b32 D[$r0 + #swap + 0xc] $r6
-
-	// will use target 0, DMA_QUERY.
-	mov $xtargets $r0
-
-	ld b32 $r4 D[$r0 + #ctx_query_address_high]
-	shl b32 $r4 0x18
-	mov $xdbase $r4
-
-	ld b32 $r4 D[$r0 + #ctx_query_address_low]
-	mov $r5 #swap
-	sethi $r5 0x20000
-	xdst $r4 $r5
-	xdwait
-
-	ret
-
-cmd_cond_mode:
-	// if >= 5, INVALID_ENUM
-	bset $flags $p1
-	or $r2 2
-	cmpu b32 $r3 5
-	bra nc #return
-
-	// otherwise, no error.
-	bclr $flags $p1
-
-	// if < 2, no QUERY object is involved
-	cmpu b32 $r3 2
-	bra nc #cmd_cond_mode_queryful
-
-		xor $r3 1
-		st b32 D[$r0 + #ctx_cond_off] $r3
-	return:
-		ret
-
-	cmd_cond_mode_queryful:
-	// ok, will need to pull a QUERY object, prepare offsets
-	ld b32 $r4 D[$r0 + #ctx_cond_address_high]
-	ld b32 $r5 D[$r0 + #ctx_cond_address_low]
-	and $r6 $r5 0xff
-	shr b32 $r5 8
-	shl b32 $r4 0x18
-	or $r4 $r5
-	mov $xdbase $r4
-	mov $xtargets $r0
-
-	// pull the first one
-	mov $r5 #swap
-	sethi $r5 0x20000
-	xdld $r6 $r5
-
-	// if == 2, only a single QUERY is involved...
-	cmpu b32 $r3 2
-	bra ne #cmd_cond_mode_double
-
-		xdwait
-		ld b32 $r4 D[$r0 + #swap + 4]
-		cmpu b32 $r4 0
-		xbit $r4 $flags z
-		st b32 D[$r0 + #ctx_cond_off] $r4
-		ret
-
-	// ok, we'll need to pull second one too
-	cmd_cond_mode_double:
-	add b32 $r6 0x10
-	add b32 $r5 0x10
-	xdld $r6 $r5
-	xdwait
-
-	// compare COUNTERs
-	ld b32 $r5 D[$r0 + #swap + 0x00]
-	ld b32 $r6 D[$r0 + #swap + 0x10]
-	cmpu b32 $r5 $r6
-	xbit $r4 $flags z
-
-	// compare RESen
-	ld b32 $r5 D[$r0 + #swap + 0x04]
-	ld b32 $r6 D[$r0 + #swap + 0x14]
-	cmpu b32 $r5 $r6
-	xbit $r5 $flags z
-	and $r4 $r5
-
-	// and negate or not, depending on mode
-	cmpu b32 $r3 3
-	xbit $r5 $flags z
-	xor $r4 $r5
-	st b32 D[$r0 + #ctx_cond_off] $r4
-	ret
-
-cmd_wrcache_flush:
-	bclr $flags $p1
-	mov $r2 0x2200
-	clear b32 $r3
-	sethi $r3 0x10000
-	iowr I[$r2] $r3
-	ret
-
-crypt_cmd_mode:
-	// if >= 0xf, INVALID_ENUM
-	bset $flags $p1
-	or $r2 2
-	cmpu b32 $r3 0xf
-	bra nc #crypt_cmd_mode_return
-
-		bclr $flags $p1
-		st b32 D[$r0 + #ctx_mode] $r3
-
-	crypt_cmd_mode_return:
-	ret
-
-crypt_cmd_length:
-	// nop if length == 0
-	cmpu b32 $r3 0
-	bra e #crypt_cmd_mode_return
-
-	// init key, IV
-	cxset 3
-	mov $r4 #ctx_key
-	sethi $r4 0x70000
-	xdst $r0 $r4
-	mov $r4 #ctx_iv
-	sethi $r4 0x60000
-	xdst $r0 $r4
-	xdwait
-	ckeyreg $c7
-
-	// prepare the targets
-	mov $r4 0x2100
-	mov $xtargets $r4
-
-	// prepare src address
-	ld b32 $r4 D[$r0 + #ctx_src_address_high]
-	ld b32 $r5 D[$r0 + #ctx_src_address_low]
-	shr b32 $r8 $r5 8
-	shl b32 $r4 0x18
-	or $r4 $r8
-	and $r5 $r5 0xff
-
-	// prepare dst address
-	ld b32 $r6 D[$r0 + #ctx_dst_address_high]
-	ld b32 $r7 D[$r0 + #ctx_dst_address_low]
-	shr b32 $r8 $r7 8
-	shl b32 $r6 0x18
-	or $r6 $r8
-	and $r7 $r7 0xff
-
-	// find the proper prep & do functions
-	ld b32 $r8 D[$r0 + #ctx_mode]
-	shl b32 $r8 2
-
-	// run prep
-	ld b16 $r9 D[$r8 + #crypt_dtable]
-	call $r9
-
-	// do it
-	ld b16 $r9 D[$r8 + #crypt_dtable + 2]
-	call $r9
-	cxset 1
-	xdwait
-	cxset 0x61
-	xdwait
-	xdwait
-
-	// update src address
-	shr b32 $r8 $r4 0x18
-	shl b32 $r9 $r4 8
-	add b32 $r9 $r5
-	adc b32 $r8 0
-	st b32 D[$r0 + #ctx_src_address_high] $r8
-	st b32 D[$r0 + #ctx_src_address_low] $r9
-
-	// update dst address
-	shr b32 $r8 $r6 0x18
-	shl b32 $r9 $r6 8
-	add b32 $r9 $r7
-	adc b32 $r8 0
-	st b32 D[$r0 + #ctx_dst_address_high] $r8
-	st b32 D[$r0 + #ctx_dst_address_low] $r9
-
-	// pull updated IV
-	cxset 2
-	mov $r4 #ctx_iv
-	sethi $r4 0x60000
-	xdld $r0 $r4
-	xdwait
-
-	ret
-
-
-crypt_copy_prep:
-	cs0begin 2
-		cxsin $c0
-		cxsout $c0
-	ret
-
-crypt_store_prep:
-	cs0begin 1
-		cxsout $c6
-	ret
-
-crypt_ecb_e_prep:
-	cs0begin 3
-		cxsin $c0
-		cenc $c0 $c0
-		cxsout $c0
-	ret
-
-crypt_ecb_d_prep:
-	ckexp $c7 $c7
-	cs0begin 3
-		cxsin $c0
-		cdec $c0 $c0
-		cxsout $c0
-	ret
-
-crypt_cbc_e_prep:
-	cs0begin 4
-		cxsin $c0
-		cxor $c6 $c0
-		cenc $c6 $c6
-		cxsout $c6
-	ret
-
-crypt_cbc_d_prep:
-	ckexp $c7 $c7
-	cs0begin 5
-		cmov $c2 $c6
-		cxsin $c6
-		cdec $c0 $c6
-		cxor $c0 $c2
-		cxsout $c0
-	ret
-
-crypt_pcbc_e_prep:
-	cs0begin 5
-		cxsin $c0
-		cxor $c6 $c0
-		cenc $c6 $c6
-		cxsout $c6
-		cxor $c6 $c0
-	ret
-
-crypt_pcbc_d_prep:
-	ckexp $c7 $c7
-	cs0begin 5
-		cxsin $c0
-		cdec $c1 $c0
-		cxor $c6 $c1
-		cxsout $c6
-		cxor $c6 $c0
-	ret
-
-crypt_cfb_e_prep:
-	cs0begin 4
-		cenc $c6 $c6
-		cxsin $c0
-		cxor $c6 $c0
-		cxsout $c6
-	ret
-
-crypt_cfb_d_prep:
-	cs0begin 4
-		cenc $c0 $c6
-		cxsin $c6
-		cxor $c0 $c6
-		cxsout $c0
-	ret
-
-crypt_ofb_prep:
-	cs0begin 4
-		cenc $c6 $c6
-		cxsin $c0
-		cxor $c0 $c6
-		cxsout $c0
-	ret
-
-crypt_ctr_prep:
-	cs0begin 5
-		cenc $c1 $c6
-		cadd $c6 1
-		cxsin $c0
-		cxor $c0 $c1
-		cxsout $c0
-	ret
-
-crypt_cbc_mac_prep:
-	cs0begin 3
-		cxsin $c0
-		cxor $c6 $c0
-		cenc $c6 $c6
-	ret
-
-crypt_cmac_finish_complete_prep:
-	cs0begin 7
-		cxsin $c0
-		cxor $c6 $c0
-		cxor $c0 $c0
-		cenc $c0 $c0
-		cprecmac $c0 $c0
-		cxor $c6 $c0
-		cenc $c6 $c6
-	ret
-
-crypt_cmac_finish_partial_prep:
-	cs0begin 8
-		cxsin $c0
-		cxor $c6 $c0
-		cxor $c0 $c0
-		cenc $c0 $c0
-		cprecmac $c0 $c0
-		cprecmac $c0 $c0
-		cxor $c6 $c0
-		cenc $c6 $c6
-	ret
-
-// TODO
-crypt_do_in:
-	add b32 $r3 $r5
-	mov $xdbase $r4
-	mov $r9 #swap
-	sethi $r9 0x20000
-	crypt_do_in_loop:
-		xdld $r5 $r9
-		xdwait
-		cxset 0x22
-		xdst $r0 $r9
-		cs0exec 1
-		xdwait
-		add b32 $r5 0x10
-		cmpu b32 $r5 $r3
-	bra ne #crypt_do_in_loop
-	cxset 1
-	xdwait
-	ret
-
-crypt_do_out:
-	add b32 $r3 $r7
-	mov $xdbase $r6
-	mov $r9 #swap
-	sethi $r9 0x20000
-	crypt_do_out_loop:
-		cs0exec 1
-		cxset 0x61
-		xdld $r7 $r9
-		xdst $r7 $r9
-		cxset 1
-		xdwait
-		add b32 $r7 0x10
-		cmpu b32 $r7 $r3
-	bra ne #crypt_do_out_loop
-	ret
-
-crypt_do_inout:
-	add b32 $r3 $r5
-	mov $r9 #swap
-	sethi $r9 0x20000
-	crypt_do_inout_loop:
-		mov $xdbase $r4
-		xdld $r5 $r9
-		xdwait
-		cxset 0x21
-		xdst $r0 $r9
-		cs0exec 1
-		cxset 0x61
-		mov $xdbase $r6
-		xdld $r7 $r9
-		xdst $r7 $r9
-		cxset 1
-		xdwait
-		add b32 $r5 0x10
-		add b32 $r7 0x10
-		cmpu b32 $r5 $r3
-	bra ne #crypt_do_inout_loop
-	ret
-
-.align 0x100
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
deleted file mode 100644
index 38676c7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
+++ /dev/null
@@ -1,584 +0,0 @@
-uint32_t nv98_pcrypt_data[] = {
-/* 0x0000: ctx_dma */
-/* 0x0000: ctx_dma_query */
-	0x00000000,
-/* 0x0004: ctx_dma_src */
-	0x00000000,
-/* 0x0008: ctx_dma_dst */
-	0x00000000,
-/* 0x000c: ctx_query_address_high */
-	0x00000000,
-/* 0x0010: ctx_query_address_low */
-	0x00000000,
-/* 0x0014: ctx_query_counter */
-	0x00000000,
-/* 0x0018: ctx_cond_address_high */
-	0x00000000,
-/* 0x001c: ctx_cond_address_low */
-	0x00000000,
-/* 0x0020: ctx_cond_off */
-	0x00000000,
-/* 0x0024: ctx_src_address_high */
-	0x00000000,
-/* 0x0028: ctx_src_address_low */
-	0x00000000,
-/* 0x002c: ctx_dst_address_high */
-	0x00000000,
-/* 0x0030: ctx_dst_address_low */
-	0x00000000,
-/* 0x0034: ctx_mode */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0040: ctx_key */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0050: ctx_iv */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0080: swap */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x00a0: common_cmd_dtable */
-	0x0002000c,
-	0xffffff00,
-	0x00020010,
-	0x0000000f,
-	0x00020014,
-	0x00000000,
-	0x00000192,
-	0xfffffffe,
-	0x00020018,
-	0xffffff00,
-	0x0002001c,
-	0x0000000f,
-	0x000001d7,
-	0xfffffff8,
-	0x00000260,
-	0xffffffff,
-/* 0x00e0: engine_cmd_dtable */
-	0x00020040,
-	0x00000000,
-	0x00020044,
-	0x00000000,
-	0x00020048,
-	0x00000000,
-	0x0002004c,
-	0x00000000,
-	0x00020050,
-	0x00000000,
-	0x00020054,
-	0x00000000,
-	0x00020058,
-	0x00000000,
-	0x0002005c,
-	0x00000000,
-	0x00020024,
-	0xffffff00,
-	0x00020028,
-	0x0000000f,
-	0x0002002c,
-	0xffffff00,
-	0x00020030,
-	0x0000000f,
-	0x00000271,
-	0xfffffff0,
-	0x00010285,
-	0xf000000f,
-/* 0x0150: crypt_dtable */
-	0x04db0321,
-	0x04b1032f,
-	0x04db0339,
-	0x04db034b,
-	0x04db0361,
-	0x04db0377,
-	0x04db0395,
-	0x04db03af,
-	0x04db03cd,
-	0x04db03e3,
-	0x04db03f9,
-	0x04db040f,
-	0x04830429,
-	0x0483043b,
-	0x0483045d,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nv98_pcrypt_code[] = {
-	0x17f004bd,
-	0x0010fe35,
-	0xf10004fe,
-	0xf0fff017,
-	0x27f10013,
-	0x21d00400,
-	0x0c15f0c0,
-	0xf00021d0,
-	0x27f10317,
-	0x21d01200,
-	0x1031f400,
-/* 0x002f: spin */
-	0xf40031f4,
-	0x0ef40028,
-/* 0x0035: ih */
-	0x8001cffd,
-	0xb00812c4,
-	0x0bf40024,
-	0x0027f167,
-	0x002bfe77,
-	0xf00007fe,
-	0x23f00027,
-	0x0037f105,
-	0x0034cf14,
-	0xb0014594,
-	0x18f40055,
-	0x0602fa17,
-	0x4af003f8,
-	0x0034d01e,
-	0xd00147f0,
-	0x0ef48034,
-/* 0x0075: ctxload */
-	0x4034cf33,
-	0xb0014f94,
-	0x18f400f5,
-	0x0502fa21,
-	0x57f003f8,
-	0x0267f000,
-/* 0x008c: ctxload_dma_loop */
-	0xa07856bc,
-	0xb6018068,
-	0x87d00884,
-	0x0162b600,
-/* 0x009f: dummyload */
-	0xf0f018f4,
-	0x35d00257,
-/* 0x00a5: noctx */
-	0x0412c480,
-	0xf50024b0,
-	0xf100df0b,
-	0xcf190037,
-	0x33cf4032,
-	0xff24e400,
-	0x1024b607,
-	0x07bf45e4,
-	0xf50054b0,
-	0xf100b90b,
-	0xf1fae057,
-	0xb000ce67,
-	0x18f4c044,
-	0xa057f14d,
-	0x8867f1fc,
-	0x8044b000,
-	0xb03f18f4,
-	0x18f46044,
-	0x5044b019,
-	0xf1741bf4,
-	0xbd220027,
-	0x0233f034,
-	0xf50023d0,
-/* 0x0103: dma_cmd */
-	0xb000810e,
-	0x18f46344,
-	0x0245945e,
-	0xfe8050b7,
-	0x801e39f0,
-	0x40b70053,
-	0x44b60120,
-	0x0043d008,
-/* 0x0123: dtable_cmd */
-	0xb8600ef4,
-	0x18f40446,
-	0x0344b63e,
-	0x980045bb,
-	0x53fd0145,
-	0x0054b004,
-	0x58291bf4,
-	0x46580045,
-	0x0264b001,
-	0x98170bf4,
-	0x67fd0807,
-	0x0164b004,
-	0xf9300bf4,
-	0x0f01f455,
-/* 0x015b: cmd_setctx */
-	0x80280ef4,
-	0x0ef40053,
-/* 0x0161: invalid_bitfield */
-	0x0125f022,
-/* 0x0164: dispatch_error */
-/* 0x0164: illegal_mthd */
-	0x100047f1,
-	0xd00042d0,
-	0x47f04043,
-	0x0004d040,
-/* 0x0174: im_loop */
-	0xf08004cf,
-	0x44b04044,
-	0xf71bf400,
-/* 0x0180: cmddone */
-	0x1d0037f1,
-	0xd00147f0,
-/* 0x018a: nocmd */
-	0x11c40034,
-	0x4001d00c,
-/* 0x0192: cmd_query_get */
-	0x38f201f8,
-	0x0325f001,
-	0x0b0047f1,
-/* 0x019c: ptimer_retry */
-	0xcf4046cf,
-	0x47cf0045,
-	0x0467b840,
-	0x98f41bf4,
-	0x04800504,
-	0x21008020,
-	0x80220580,
-	0x0bfe2306,
-	0x03049800,
-	0xfe1844b6,
-	0x04980047,
-	0x8057f104,
-	0x0253f000,
-	0xf80645fa,
-/* 0x01d7: cmd_cond_mode */
-	0xf400f803,
-	0x25f00131,
-	0x0534b002,
-	0xf41218f4,
-	0x34b00132,
-	0x0b18f402,
-	0x800136f0,
-/* 0x01f2: return */
-	0x00f80803,
-/* 0x01f4: cmd_cond_mode_queryful */
-	0x98060498,
-	0x56c40705,
-	0x0855b6ff,
-	0xfd1844b6,
-	0x47fe0545,
-	0x000bfe00,
-	0x008057f1,
-	0xfa0253f0,
-	0x34b00565,
-	0x131bf402,
-	0x049803f8,
-	0x0044b021,
-	0x800b4cf0,
-	0x00f80804,
-/* 0x022c: cmd_cond_mode_double */
-	0xb61060b6,
-	0x65fa1050,
-	0x9803f805,
-	0x06982005,
-	0x0456b824,
-	0x980b4cf0,
-	0x06982105,
-	0x0456b825,
-	0xfd0b5cf0,
-	0x34b00445,
-	0x0b5cf003,
-	0x800645fd,
-	0x00f80804,
-/* 0x0260: cmd_wrcache_flush */
-	0xf10132f4,
-	0xbd220027,
-	0x0133f034,
-	0xf80023d0,
-/* 0x0271: crypt_cmd_mode */
-	0x0131f400,
-	0xb00225f0,
-	0x18f40f34,
-	0x0132f409,
-/* 0x0283: crypt_cmd_mode_return */
-	0xf80d0380,
-/* 0x0285: crypt_cmd_length */
-	0x0034b000,
-	0xf4fb0bf4,
-	0x47f0033c,
-	0x0743f040,
-	0xf00604fa,
-	0x43f05047,
-	0x0604fa06,
-	0x3cf503f8,
-	0x47f1c407,
-	0x4bfe2100,
-	0x09049800,
-	0x950a0598,
-	0x44b60858,
-	0x0548fd18,
-	0x98ff55c4,
-	0x07980b06,
-	0x0878950c,
-	0xfd1864b6,
-	0x77c40568,
-	0x0d0898ff,
-	0x580284b6,
-	0x95f9a889,
-	0xf9a98958,
-	0x013cf495,
-	0x3cf403f8,
-	0xf803f861,
-	0x18489503,
-	0xbb084994,
-	0x81b60095,
-	0x09088000,
-	0x950a0980,
-	0x69941868,
-	0x0097bb08,
-	0x800081b6,
-	0x09800b08,
-	0x023cf40c,
-	0xf05047f0,
-	0x04fa0643,
-	0xf803f805,
-/* 0x0321: crypt_copy_prep */
-	0x203cf500,
-	0x003cf594,
-	0x003cf588,
-/* 0x032f: crypt_store_prep */
-	0xf500f88c,
-	0xf594103c,
-	0xf88c063c,
-/* 0x0339: crypt_ecb_e_prep */
-	0x303cf500,
-	0x003cf594,
-	0x003cf588,
-	0x003cf5d0,
-/* 0x034b: crypt_ecb_d_prep */
-	0xf500f88c,
-	0xf5c8773c,
-	0xf594303c,
-	0xf588003c,
-	0xf5d4003c,
-	0xf88c003c,
-/* 0x0361: crypt_cbc_e_prep */
-	0x403cf500,
-	0x003cf594,
-	0x063cf588,
-	0x663cf5ac,
-	0x063cf5d0,
-/* 0x0377: crypt_cbc_d_prep */
-	0xf500f88c,
-	0xf5c8773c,
-	0xf594503c,
-	0xf584623c,
-	0xf588063c,
-	0xf5d4603c,
-	0xf5ac203c,
-	0xf88c003c,
-/* 0x0395: crypt_pcbc_e_prep */
-	0x503cf500,
-	0x003cf594,
-	0x063cf588,
-	0x663cf5ac,
-	0x063cf5d0,
-	0x063cf58c,
-/* 0x03af: crypt_pcbc_d_prep */
-	0xf500f8ac,
-	0xf5c8773c,
-	0xf594503c,
-	0xf588003c,
-	0xf5d4013c,
-	0xf5ac163c,
-	0xf58c063c,
-	0xf8ac063c,
-/* 0x03cd: crypt_cfb_e_prep */
-	0x403cf500,
-	0x663cf594,
-	0x003cf5d0,
-	0x063cf588,
-	0x063cf5ac,
-/* 0x03e3: crypt_cfb_d_prep */
-	0xf500f88c,
-	0xf594403c,
-	0xf5d0603c,
-	0xf588063c,
-	0xf5ac603c,
-	0xf88c003c,
-/* 0x03f9: crypt_ofb_prep */
-	0x403cf500,
-	0x663cf594,
-	0x003cf5d0,
-	0x603cf588,
-	0x003cf5ac,
-/* 0x040f: crypt_ctr_prep */
-	0xf500f88c,
-	0xf594503c,
-	0xf5d0613c,
-	0xf5b0163c,
-	0xf588003c,
-	0xf5ac103c,
-	0xf88c003c,
-/* 0x0429: crypt_cbc_mac_prep */
-	0x303cf500,
-	0x003cf594,
-	0x063cf588,
-	0x663cf5ac,
-/* 0x043b: crypt_cmac_finish_complete_prep */
-	0xf500f8d0,
-	0xf594703c,
-	0xf588003c,
-	0xf5ac063c,
-	0xf5ac003c,
-	0xf5d0003c,
-	0xf5bc003c,
-	0xf5ac063c,
-	0xf8d0663c,
-/* 0x045d: crypt_cmac_finish_partial_prep */
-	0x803cf500,
-	0x003cf594,
-	0x063cf588,
-	0x003cf5ac,
-	0x003cf5ac,
-	0x003cf5d0,
-	0x003cf5bc,
-	0x063cf5bc,
-	0x663cf5ac,
-/* 0x0483: crypt_do_in */
-	0xbb00f8d0,
-	0x47fe0035,
-	0x8097f100,
-	0x0293f000,
-/* 0x0490: crypt_do_in_loop */
-	0xf80559fa,
-	0x223cf403,
-	0xf50609fa,
-	0xf898103c,
-	0x1050b603,
-	0xf40453b8,
-	0x3cf4e91b,
-	0xf803f801,
-/* 0x04b1: crypt_do_out */
-	0x0037bb00,
-	0xf10067fe,
-	0xf0008097,
-/* 0x04be: crypt_do_out_loop */
-	0x3cf50293,
-	0x3cf49810,
-	0x0579fa61,
-	0xf40679fa,
-	0x03f8013c,
-	0xb81070b6,
-	0x1bf40473,
-/* 0x04db: crypt_do_inout */
-	0xbb00f8e8,
-	0x97f10035,
-	0x93f00080,
-/* 0x04e5: crypt_do_inout_loop */
-	0x0047fe02,
-	0xf80559fa,
-	0x213cf403,
-	0xf50609fa,
-	0xf498103c,
-	0x67fe613c,
-	0x0579fa00,
-	0xf40679fa,
-	0x03f8013c,
-	0xb61050b6,
-	0x53b81070,
-	0xd41bf404,
-	0x000000f8,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
deleted file mode 100644
index ea5c42f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-#include <engine/crypt.h>
-
-struct nv84_crypt_priv {
-	struct nouveau_engine base;
-};
-
-/*******************************************************************************
- * Crypt object classes
- ******************************************************************************/
-
-static int
-nv84_crypt_object_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    16, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv84_crypt_ofuncs = {
-	.ctor = nv84_crypt_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv84_crypt_sclass[] = {
-	{ 0x74c1, &nv84_crypt_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PCRYPT context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_crypt_cclass = {
-	.handle = NV_ENGCTX(CRYPT, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
-	},
-};
-
-/*******************************************************************************
- * PCRYPT engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_bitfield nv84_crypt_intr_mask[] = {
-	{ 0x00000001, "INVALID_STATE" },
-	{ 0x00000002, "ILLEGAL_MTHD" },
-	{ 0x00000004, "ILLEGAL_CLASS" },
-	{ 0x00000080, "QUERY" },
-	{ 0x00000100, "FAULT" },
-	{}
-};
-
-static void
-nv84_crypt_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nv84_crypt_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, 0x102130);
-	u32 mthd = nv_rd32(priv, 0x102190);
-	u32 data = nv_rd32(priv, 0x102194);
-	u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat) {
-		nv_error(priv, "%s", "");
-		nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
-		pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
-		       chid, (u64)inst << 12, nouveau_client_name(engctx),
-		       mthd, data);
-	}
-
-	nv_wr32(priv, 0x102130, stat);
-	nv_wr32(priv, 0x10200c, 0x10);
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv84_crypt_priv *priv;
-	int ret;
-
-	ret = nouveau_engine_create(parent, engine, oclass, true,
-				    "PCRYPT", "crypt", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00004000;
-	nv_subdev(priv)->intr = nv84_crypt_intr;
-	nv_engine(priv)->cclass = &nv84_crypt_cclass;
-	nv_engine(priv)->sclass = nv84_crypt_sclass;
-	return 0;
-}
-
-static int
-nv84_crypt_init(struct nouveau_object *object)
-{
-	struct nv84_crypt_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_engine_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x102130, 0xffffffff);
-	nv_wr32(priv, 0x102140, 0xffffffbf);
-	nv_wr32(priv, 0x10200c, 0x00000010);
-	return 0;
-}
-
-struct nouveau_oclass
-nv84_crypt_oclass = {
-	.handle = NV_ENGINE(CRYPT, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_crypt_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = nv84_crypt_init,
-		.fini = _nouveau_engine_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
deleted file mode 100644
index 5571c09..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/crypt.h>
-
-#include "fuc/nv98.fuc.h"
-
-struct nv98_crypt_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Crypt object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_crypt_sclass[] = {
-	{ 0x88b4, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PCRYPT context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_crypt_cclass = {
-	.handle = NV_ENGCTX(CRYPT, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PCRYPT engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_enum nv98_crypt_isr_error_name[] = {
-	{ 0x0000, "ILLEGAL_MTHD" },
-	{ 0x0001, "INVALID_BITFIELD" },
-	{ 0x0002, "INVALID_ENUM" },
-	{ 0x0003, "QUERY" },
-	{}
-};
-
-static void
-nv98_crypt_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nv98_crypt_priv *priv = (void *)subdev;
-	u32 disp = nv_rd32(priv, 0x08701c);
-	u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
-	u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
-	u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
-	u32 addr = nv_rd32(priv, 0x087040) >> 16;
-	u32 mthd = (addr & 0x07ff) << 2;
-	u32 subc = (addr & 0x3800) >> 11;
-	u32 data = nv_rd32(priv, 0x087044);
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x00000040) {
-		nv_error(priv, "DISPATCH_ERROR [");
-		nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
-		pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
-		       chid, (u64)inst << 12, nouveau_client_name(engctx),
-		       subc, mthd, data);
-		nv_wr32(priv, 0x087004, 0x00000040);
-		stat &= ~0x00000040;
-	}
-
-	if (stat) {
-		nv_error(priv, "unhandled intr 0x%08x\n", stat);
-		nv_wr32(priv, 0x087004, stat);
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv98_crypt_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x087000, true,
-				    "PCRYPT", "crypt", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00004000;
-	nv_subdev(priv)->intr = nv98_crypt_intr;
-	nv_engine(priv)->cclass = &nv98_crypt_cclass;
-	nv_engine(priv)->sclass = nv98_crypt_sclass;
-	nv_falcon(priv)->code.data = nv98_pcrypt_code;
-	nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
-	nv_falcon(priv)->data.data = nv98_pcrypt_data;
-	nv_falcon(priv)->data.size = sizeof(nv98_pcrypt_data);
-	return 0;
-}
-
-struct nouveau_oclass
-nv98_crypt_oclass = {
-	.handle = NV_ENGINE(CRYPT, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv98_crypt_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = _nouveau_falcon_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.c b/drivers/gpu/drm/nouveau/core/engine/device/acpi.c
deleted file mode 100644
index 4dbf0ba..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/acpi.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "acpi.h"
-
-#ifdef CONFIG_ACPI
-static int
-nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
-{
-	struct nouveau_device *device =
-		container_of(nb, typeof(*device), acpi.nb);
-	struct acpi_bus_event *info = data;
-
-	if (!strcmp(info->device_class, "ac_adapter"))
-		nvkm_event_send(&device->event, 1, 0, NULL, 0);
-
-	return NOTIFY_DONE;
-}
-#endif
-
-int
-nvkm_acpi_fini(struct nouveau_device *device, bool suspend)
-{
-#ifdef CONFIG_ACPI
-	unregister_acpi_notifier(&device->acpi.nb);
-#endif
-	return 0;
-}
-
-int
-nvkm_acpi_init(struct nouveau_device *device)
-{
-#ifdef CONFIG_ACPI
-	device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
-	register_acpi_notifier(&device->acpi.nb);
-#endif
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.h b/drivers/gpu/drm/nouveau/core/engine/device/acpi.h
deleted file mode 100644
index cc49f4f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/acpi.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVKM_DEVICE_ACPI_H__
-#define __NVKM_DEVICE_ACPI_H__
-
-#include <engine/device.h>
-
-int nvkm_acpi_init(struct nouveau_device *);
-int nvkm_acpi_fini(struct nouveau_device *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c
deleted file mode 100644
index 137e0b0..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/base.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/client.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-
-#include "priv.h"
-#include "acpi.h"
-
-static DEFINE_MUTEX(nv_devices_mutex);
-static LIST_HEAD(nv_devices);
-
-struct nouveau_device *
-nouveau_device_find(u64 name)
-{
-	struct nouveau_device *device, *match = NULL;
-	mutex_lock(&nv_devices_mutex);
-	list_for_each_entry(device, &nv_devices, head) {
-		if (device->handle == name) {
-			match = device;
-			break;
-		}
-	}
-	mutex_unlock(&nv_devices_mutex);
-	return match;
-}
-
-int
-nouveau_device_list(u64 *name, int size)
-{
-	struct nouveau_device *device;
-	int nr = 0;
-	mutex_lock(&nv_devices_mutex);
-	list_for_each_entry(device, &nv_devices, head) {
-		if (nr++ < size)
-			name[nr - 1] = device->handle;
-	}
-	mutex_unlock(&nv_devices_mutex);
-	return nr;
-}
-
-/******************************************************************************
- * nouveau_devobj (0x0080): class implementation
- *****************************************************************************/
-
-struct nouveau_devobj {
-	struct nouveau_parent base;
-	struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
-};
-
-static int
-nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nouveau_fb *pfb = nouveau_fb(device);
-	struct nouveau_instmem *imem = nouveau_instmem(device);
-	union {
-		struct nv_device_info_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "device info size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "device info vers %d\n", args->v0.version);
-	} else
-		return ret;
-
-	switch (device->chipset) {
-	case 0x01a:
-	case 0x01f:
-	case 0x04c:
-	case 0x04e:
-	case 0x063:
-	case 0x067:
-	case 0x068:
-	case 0x0aa:
-	case 0x0ac:
-	case 0x0af:
-		args->v0.platform = NV_DEVICE_INFO_V0_IGP;
-		break;
-	default:
-		if (device->pdev) {
-			if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
-				args->v0.platform = NV_DEVICE_INFO_V0_AGP;
-			else
-			if (pci_is_pcie(device->pdev))
-				args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
-			else
-				args->v0.platform = NV_DEVICE_INFO_V0_PCI;
-		} else {
-			args->v0.platform = NV_DEVICE_INFO_V0_SOC;
-		}
-		break;
-	}
-
-	switch (device->card_type) {
-	case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
-	case NV_10:
-	case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
-	case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
-	case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
-	case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
-	case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
-	case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
-	case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
-	case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
-	default:
-		args->v0.family = 0;
-		break;
-	}
-
-	args->v0.chipset  = device->chipset;
-	args->v0.revision = device->chiprev;
-	if (pfb)  args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
-	else      args->v0.ram_size = args->v0.ram_user = 0;
-	if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
-	return 0;
-}
-
-static int
-nouveau_devobj_mthd(struct nouveau_object *object, u32 mthd,
-		    void *data, u32 size)
-{
-	switch (mthd) {
-	case NV_DEVICE_V0_INFO:
-		return nouveau_devobj_info(object, data, size);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static u8
-nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
-{
-	return nv_rd08(object->engine, addr);
-}
-
-static u16
-nouveau_devobj_rd16(struct nouveau_object *object, u64 addr)
-{
-	return nv_rd16(object->engine, addr);
-}
-
-static u32
-nouveau_devobj_rd32(struct nouveau_object *object, u64 addr)
-{
-	return nv_rd32(object->engine, addr);
-}
-
-static void
-nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data)
-{
-	nv_wr08(object->engine, addr, data);
-}
-
-static void
-nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data)
-{
-	nv_wr16(object->engine, addr, data);
-}
-
-static void
-nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	nv_wr32(object->engine, addr, data);
-}
-
-static int
-nouveau_devobj_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
-	struct nouveau_device *device = nv_device(object);
-	*addr = nv_device_resource_start(device, 0);
-	*size = nv_device_resource_len(device, 0);
-	return 0;
-}
-
-static const u64 disable_map[] = {
-	[NVDEV_SUBDEV_VBIOS]	= NV_DEVICE_V0_DISABLE_VBIOS,
-	[NVDEV_SUBDEV_DEVINIT]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_GPIO]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_I2C]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_CLOCK]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_MXM]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_MC]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_BUS]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_TIMER]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_FB]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_LTC]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_IBUS]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_INSTMEM]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_VM]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_BAR]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_VOLT]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_THERM]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_PWR]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_SUBDEV_FUSE]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_ENGINE_DMAOBJ]	= NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_ENGINE_PERFMON]  = NV_DEVICE_V0_DISABLE_CORE,
-	[NVDEV_ENGINE_FIFO]	= NV_DEVICE_V0_DISABLE_FIFO,
-	[NVDEV_ENGINE_SW]	= NV_DEVICE_V0_DISABLE_FIFO,
-	[NVDEV_ENGINE_GR]	= NV_DEVICE_V0_DISABLE_GRAPH,
-	[NVDEV_ENGINE_MPEG]	= NV_DEVICE_V0_DISABLE_MPEG,
-	[NVDEV_ENGINE_ME]	= NV_DEVICE_V0_DISABLE_ME,
-	[NVDEV_ENGINE_VP]	= NV_DEVICE_V0_DISABLE_VP,
-	[NVDEV_ENGINE_CRYPT]	= NV_DEVICE_V0_DISABLE_CRYPT,
-	[NVDEV_ENGINE_BSP]	= NV_DEVICE_V0_DISABLE_BSP,
-	[NVDEV_ENGINE_PPP]	= NV_DEVICE_V0_DISABLE_PPP,
-	[NVDEV_ENGINE_COPY0]	= NV_DEVICE_V0_DISABLE_COPY0,
-	[NVDEV_ENGINE_COPY1]	= NV_DEVICE_V0_DISABLE_COPY1,
-	[NVDEV_ENGINE_COPY2]	= NV_DEVICE_V0_DISABLE_COPY1,
-	[NVDEV_ENGINE_VIC]	= NV_DEVICE_V0_DISABLE_VIC,
-	[NVDEV_ENGINE_VENC]	= NV_DEVICE_V0_DISABLE_VENC,
-	[NVDEV_ENGINE_DISP]	= NV_DEVICE_V0_DISABLE_DISP,
-	[NVDEV_SUBDEV_NR]	= 0,
-};
-
-static void
-nouveau_devobj_dtor(struct nouveau_object *object)
-{
-	struct nouveau_devobj *devobj = (void *)object;
-	int i;
-
-	for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
-		nouveau_object_ref(NULL, &devobj->subdev[i]);
-
-	nouveau_parent_destroy(&devobj->base);
-}
-
-static struct nouveau_oclass
-nouveau_devobj_oclass_super = {
-	.handle = NV_DEVICE,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.dtor = nouveau_devobj_dtor,
-		.init = _nouveau_parent_init,
-		.fini = _nouveau_parent_fini,
-		.mthd = nouveau_devobj_mthd,
-		.map  = nouveau_devobj_map,
-		.rd08 = nouveau_devobj_rd08,
-		.rd16 = nouveau_devobj_rd16,
-		.rd32 = nouveau_devobj_rd32,
-		.wr08 = nouveau_devobj_wr08,
-		.wr16 = nouveau_devobj_wr16,
-		.wr32 = nouveau_devobj_wr32,
-	}
-};
-
-static int
-nouveau_devobj_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv_device_v0 v0;
-	} *args = data;
-	struct nouveau_client *client = nv_client(parent);
-	struct nouveau_device *device;
-	struct nouveau_devobj *devobj;
-	u32 boot0, strap;
-	u64 disable, mmio_base, mmio_size;
-	void __iomem *map;
-	int ret, i, c;
-
-	nv_ioctl(parent, "create device size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create device v%d device %016llx "
-				 "disable %016llx debug0 %016llx\n",
-			 args->v0.version, args->v0.device,
-			 args->v0.disable, args->v0.debug0);
-	} else
-		return ret;
-
-	/* give priviledged clients register access */
-	if (client->super)
-		oclass = &nouveau_devobj_oclass_super;
-
-	/* find the device subdev that matches what the client requested */
-	device = nv_device(client->device);
-	if (args->v0.device != ~0) {
-		device = nouveau_device_find(args->v0.device);
-		if (!device)
-			return -ENODEV;
-	}
-
-	ret = nouveau_parent_create(parent, nv_object(device), oclass, 0,
-				    nouveau_control_oclass,
-				    (1ULL << NVDEV_ENGINE_DMAOBJ) |
-				    (1ULL << NVDEV_ENGINE_FIFO) |
-				    (1ULL << NVDEV_ENGINE_DISP) |
-				    (1ULL << NVDEV_ENGINE_PERFMON), &devobj);
-	*pobject = nv_object(devobj);
-	if (ret)
-		return ret;
-
-	mmio_base = nv_device_resource_start(device, 0);
-	mmio_size = nv_device_resource_len(device, 0);
-
-	/* translate api disable mask into internal mapping */
-	disable = args->v0.debug0;
-	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
-		if (args->v0.disable & disable_map[i])
-			disable |= (1ULL << i);
-	}
-
-	/* identify the chipset, and determine classes of subdev/engines */
-	if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
-	    !device->card_type) {
-		map = ioremap(mmio_base, 0x102000);
-		if (map == NULL)
-			return -ENOMEM;
-
-		/* switch mmio to cpu's native endianness */
-#ifndef __BIG_ENDIAN
-		if (ioread32_native(map + 0x000004) != 0x00000000)
-#else
-		if (ioread32_native(map + 0x000004) == 0x00000000)
-#endif
-			iowrite32_native(0x01000001, map + 0x000004);
-
-		/* read boot0 and strapping information */
-		boot0 = ioread32_native(map + 0x000000);
-		strap = ioread32_native(map + 0x101000);
-		iounmap(map);
-
-		/* determine chipset and derive architecture from it */
-		if ((boot0 & 0x1f000000) > 0) {
-			device->chipset = (boot0 & 0x1ff00000) >> 20;
-			device->chiprev = (boot0 & 0x000000ff);
-			switch (device->chipset & 0x1f0) {
-			case 0x010: {
-				if (0x461 & (1 << (device->chipset & 0xf)))
-					device->card_type = NV_10;
-				else
-					device->card_type = NV_11;
-				device->chiprev = 0x00;
-				break;
-			}
-			case 0x020: device->card_type = NV_20; break;
-			case 0x030: device->card_type = NV_30; break;
-			case 0x040:
-			case 0x060: device->card_type = NV_40; break;
-			case 0x050:
-			case 0x080:
-			case 0x090:
-			case 0x0a0: device->card_type = NV_50; break;
-			case 0x0c0:
-			case 0x0d0: device->card_type = NV_C0; break;
-			case 0x0e0:
-			case 0x0f0:
-			case 0x100: device->card_type = NV_E0; break;
-			case 0x110:
-			case 0x120: device->card_type = GM100; break;
-			default:
-				break;
-			}
-		} else
-		if ((boot0 & 0xff00fff0) == 0x20004000) {
-			if (boot0 & 0x00f00000)
-				device->chipset = 0x05;
-			else
-				device->chipset = 0x04;
-			device->card_type = NV_04;
-		}
-
-		switch (device->card_type) {
-		case NV_04: ret = nv04_identify(device); break;
-		case NV_10:
-		case NV_11: ret = nv10_identify(device); break;
-		case NV_20: ret = nv20_identify(device); break;
-		case NV_30: ret = nv30_identify(device); break;
-		case NV_40: ret = nv40_identify(device); break;
-		case NV_50: ret = nv50_identify(device); break;
-		case NV_C0: ret = nvc0_identify(device); break;
-		case NV_E0: ret = nve0_identify(device); break;
-		case GM100: ret = gm100_identify(device); break;
-		default:
-			ret = -EINVAL;
-			break;
-		}
-
-		if (ret) {
-			nv_error(device, "unknown chipset, 0x%08x\n", boot0);
-			return ret;
-		}
-
-		nv_info(device, "BOOT0  : 0x%08x\n", boot0);
-		nv_info(device, "Chipset: %s (NV%02X)\n",
-			device->cname, device->chipset);
-		nv_info(device, "Family : NV%02X\n", device->card_type);
-
-		/* determine frequency of timing crystal */
-		if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
-		    (device->chipset >= 0x20 && device->chipset < 0x25))
-			strap &= 0x00000040;
-		else
-			strap &= 0x00400040;
-
-		switch (strap) {
-		case 0x00000000: device->crystal = 13500; break;
-		case 0x00000040: device->crystal = 14318; break;
-		case 0x00400000: device->crystal = 27000; break;
-		case 0x00400040: device->crystal = 25000; break;
-		}
-
-		nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
-	} else
-	if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
-		device->cname = "NULL";
-		device->oclass[NVDEV_SUBDEV_VBIOS] = &nouveau_bios_oclass;
-	}
-
-	if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
-	    !nv_subdev(device)->mmio) {
-		nv_subdev(device)->mmio  = ioremap(mmio_base, mmio_size);
-		if (!nv_subdev(device)->mmio) {
-			nv_error(device, "unable to map device registers\n");
-			return -ENOMEM;
-		}
-	}
-
-	/* ensure requested subsystems are available for use */
-	for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
-		if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
-			continue;
-
-		if (device->subdev[i]) {
-			nouveau_object_ref(device->subdev[i],
-					  &devobj->subdev[i]);
-			continue;
-		}
-
-		ret = nouveau_object_ctor(nv_object(device), NULL,
-					  oclass, NULL, i,
-					  &devobj->subdev[i]);
-		if (ret == -ENODEV)
-			continue;
-		if (ret)
-			return ret;
-
-		device->subdev[i] = devobj->subdev[i];
-
-		/* note: can't init *any* subdevs until devinit has been run
-		 * due to not knowing exactly what the vbios init tables will
-		 * mess with.  devinit also can't be run until all of its
-		 * dependencies have been created.
-		 *
-		 * this code delays init of any subdev until all of devinit's
-		 * dependencies have been created, and then initialises each
-		 * subdev in turn as they're created.
-		 */
-		while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
-			struct nouveau_object *subdev = devobj->subdev[c++];
-			if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
-				ret = nouveau_object_inc(subdev);
-				if (ret)
-					return ret;
-				atomic_dec(&nv_object(device)->usecount);
-			} else
-			if (subdev) {
-				nouveau_subdev_reset(subdev);
-			}
-		}
-	}
-
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nouveau_devobj_ofuncs = {
-	.ctor = nouveau_devobj_ctor,
-	.dtor = nouveau_devobj_dtor,
-	.init = _nouveau_parent_init,
-	.fini = _nouveau_parent_fini,
-	.mthd = nouveau_devobj_mthd,
-};
-
-/******************************************************************************
- * nouveau_device: engine functions
- *****************************************************************************/
-
-static struct nouveau_oclass
-nouveau_device_sclass[] = {
-	{ 0x0080, &nouveau_devobj_ofuncs },
-	{}
-};
-
-static int
-nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size,
-			  struct nvkm_notify *notify)
-{
-	if (!WARN_ON(size != 0)) {
-		notify->size  = 0;
-		notify->types = 1;
-		notify->index = 0;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static const struct nvkm_event_func
-nouveau_device_event_func = {
-	.ctor = nouveau_device_event_ctor,
-};
-
-static int
-nouveau_device_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_device *device = (void *)object;
-	struct nouveau_object *subdev;
-	int ret, i;
-
-	for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
-		if ((subdev = device->subdev[i])) {
-			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-				ret = nouveau_object_dec(subdev, suspend);
-				if (ret && suspend)
-					goto fail;
-			}
-		}
-	}
-
-	ret = nvkm_acpi_fini(device, suspend);
-fail:
-	for (; ret && i < NVDEV_SUBDEV_NR; i++) {
-		if ((subdev = device->subdev[i])) {
-			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-				ret = nouveau_object_inc(subdev);
-				if (ret) {
-					/* XXX */
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-static int
-nouveau_device_init(struct nouveau_object *object)
-{
-	struct nouveau_device *device = (void *)object;
-	struct nouveau_object *subdev;
-	int ret, i = 0;
-
-	ret = nvkm_acpi_init(device);
-	if (ret)
-		goto fail;
-
-	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
-		if ((subdev = device->subdev[i])) {
-			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-				ret = nouveau_object_inc(subdev);
-				if (ret)
-					goto fail;
-			} else {
-				nouveau_subdev_reset(subdev);
-			}
-		}
-	}
-
-	ret = 0;
-fail:
-	for (--i; ret && i >= 0; i--) {
-		if ((subdev = device->subdev[i])) {
-			if (!nv_iclass(subdev, NV_ENGINE_CLASS))
-				nouveau_object_dec(subdev, false);
-		}
-	}
-
-	if (ret)
-		nvkm_acpi_fini(device, false);
-	return ret;
-}
-
-static void
-nouveau_device_dtor(struct nouveau_object *object)
-{
-	struct nouveau_device *device = (void *)object;
-
-	nvkm_event_fini(&device->event);
-
-	mutex_lock(&nv_devices_mutex);
-	list_del(&device->head);
-	mutex_unlock(&nv_devices_mutex);
-
-	if (nv_subdev(device)->mmio)
-		iounmap(nv_subdev(device)->mmio);
-
-	nouveau_engine_destroy(&device->base);
-}
-
-resource_size_t
-nv_device_resource_start(struct nouveau_device *device, unsigned int bar)
-{
-	if (nv_device_is_pci(device)) {
-		return pci_resource_start(device->pdev, bar);
-	} else {
-		struct resource *res;
-		res = platform_get_resource(device->platformdev,
-					    IORESOURCE_MEM, bar);
-		if (!res)
-			return 0;
-		return res->start;
-	}
-}
-
-resource_size_t
-nv_device_resource_len(struct nouveau_device *device, unsigned int bar)
-{
-	if (nv_device_is_pci(device)) {
-		return pci_resource_len(device->pdev, bar);
-	} else {
-		struct resource *res;
-		res = platform_get_resource(device->platformdev,
-					    IORESOURCE_MEM, bar);
-		if (!res)
-			return 0;
-		return resource_size(res);
-	}
-}
-
-int
-nv_device_get_irq(struct nouveau_device *device, bool stall)
-{
-	if (nv_device_is_pci(device)) {
-		return device->pdev->irq;
-	} else {
-		return platform_get_irq_byname(device->platformdev,
-					       stall ? "stall" : "nonstall");
-	}
-}
-
-static struct nouveau_oclass
-nouveau_device_oclass = {
-	.handle = NV_ENGINE(DEVICE, 0x00),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.dtor = nouveau_device_dtor,
-		.init = nouveau_device_init,
-		.fini = nouveau_device_fini,
-	},
-};
-
-int
-nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
-		       const char *sname, const char *cfg, const char *dbg,
-		       int length, void **pobject)
-{
-	struct nouveau_device *device;
-	int ret = -EEXIST;
-
-	mutex_lock(&nv_devices_mutex);
-	list_for_each_entry(device, &nv_devices, head) {
-		if (device->handle == name)
-			goto done;
-	}
-
-	ret = nouveau_engine_create_(NULL, NULL, &nouveau_device_oclass, true,
-				     "DEVICE", "device", length, pobject);
-	device = *pobject;
-	if (ret)
-		goto done;
-
-	switch (type) {
-	case NOUVEAU_BUS_PCI:
-		device->pdev = dev;
-		break;
-	case NOUVEAU_BUS_PLATFORM:
-		device->platformdev = dev;
-		break;
-	}
-	device->handle = name;
-	device->cfgopt = cfg;
-	device->dbgopt = dbg;
-	device->name = sname;
-
-	nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE");
-	nv_engine(device)->sclass = nouveau_device_sclass;
-	list_add(&device->head, &nv_devices);
-
-	ret = nvkm_event_init(&nouveau_device_event_func, 1, 1,
-			      &device->event);
-done:
-	mutex_unlock(&nv_devices_mutex);
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
deleted file mode 100644
index e34101a3..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/client.h>
-#include <core/object.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/ioctl.h>
-
-#include <subdev/clock.h>
-
-#include "priv.h"
-
-static int
-nouveau_control_mthd_pstate_info(struct nouveau_object *object,
-				 void *data, u32 size)
-{
-	union {
-		struct nvif_control_pstate_info_v0 v0;
-	} *args = data;
-	struct nouveau_clock *clk = nouveau_clock(object);
-	int ret;
-
-	nv_ioctl(object, "control pstate info size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "control pstate info vers %d\n",
-			 args->v0.version);
-	} else
-		return ret;
-
-	if (clk) {
-		args->v0.count = clk->state_nr;
-		args->v0.ustate_ac = clk->ustate_ac;
-		args->v0.ustate_dc = clk->ustate_dc;
-		args->v0.pwrsrc = clk->pwrsrc;
-		args->v0.pstate = clk->pstate;
-	} else {
-		args->v0.count = 0;
-		args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
-		args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
-		args->v0.pwrsrc = -ENOSYS;
-		args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
-	}
-
-	return 0;
-}
-
-static int
-nouveau_control_mthd_pstate_attr(struct nouveau_object *object,
-				 void *data, u32 size)
-{
-	union {
-		struct nvif_control_pstate_attr_v0 v0;
-	} *args = data;
-	struct nouveau_clock *clk = nouveau_clock(object);
-	struct nouveau_clocks *domain;
-	struct nouveau_pstate *pstate;
-	struct nouveau_cstate *cstate;
-	int i = 0, j = -1;
-	u32 lo, hi;
-	int ret;
-
-	nv_ioctl(object, "control pstate attr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "control pstate attr vers %d state %d "
-				 "index %d\n",
-			 args->v0.version, args->v0.state, args->v0.index);
-		if (!clk)
-			return -ENODEV;
-		if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
-			return -EINVAL;
-		if (args->v0.state >= clk->state_nr)
-			return -EINVAL;
-	} else
-		return ret;
-	domain = clk->domains;
-
-	while (domain->name != nv_clk_src_max) {
-		if (domain->mname && ++j == args->v0.index)
-			break;
-		domain++;
-	}
-
-	if (domain->name == nv_clk_src_max)
-		return -EINVAL;
-
-	if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
-		list_for_each_entry(pstate, &clk->states, head) {
-			if (i++ == args->v0.state)
-				break;
-		}
-
-		lo = pstate->base.domain[domain->name];
-		hi = lo;
-		list_for_each_entry(cstate, &pstate->list, head) {
-			lo = min(lo, cstate->domain[domain->name]);
-			hi = max(hi, cstate->domain[domain->name]);
-		}
-
-		args->v0.state = pstate->pstate;
-	} else {
-		lo = max(clk->read(clk, domain->name), 0);
-		hi = lo;
-	}
-
-	snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
-	snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
-	args->v0.min = lo / domain->mdiv;
-	args->v0.max = hi / domain->mdiv;
-
-	args->v0.index = 0;
-	while ((++domain)->name != nv_clk_src_max) {
-		if (domain->mname) {
-			args->v0.index = ++j;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int
-nouveau_control_mthd_pstate_user(struct nouveau_object *object,
-				 void *data, u32 size)
-{
-	union {
-		struct nvif_control_pstate_user_v0 v0;
-	} *args = data;
-	struct nouveau_clock *clk = nouveau_clock(object);
-	int ret;
-
-	nv_ioctl(object, "control pstate user size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "control pstate user vers %d ustate %d "
-				 "pwrsrc %d\n", args->v0.version,
-			 args->v0.ustate, args->v0.pwrsrc);
-		if (!clk)
-			return -ENODEV;
-	} else
-		return ret;
-
-	if (args->v0.pwrsrc >= 0) {
-		ret |= nouveau_clock_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
-	} else {
-		ret |= nouveau_clock_ustate(clk, args->v0.ustate, 0);
-		ret |= nouveau_clock_ustate(clk, args->v0.ustate, 1);
-	}
-
-	return ret;
-}
-
-static int
-nouveau_control_mthd(struct nouveau_object *object, u32 mthd,
-		     void *data, u32 size)
-{
-	switch (mthd) {
-	case NVIF_CONTROL_PSTATE_INFO:
-		return nouveau_control_mthd_pstate_info(object, data, size);
-	case NVIF_CONTROL_PSTATE_ATTR:
-		return nouveau_control_mthd_pstate_attr(object, data, size);
-	case NVIF_CONTROL_PSTATE_USER:
-		return nouveau_control_mthd_pstate_user(object, data, size);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static struct nouveau_ofuncs
-nouveau_control_ofuncs = {
-	.ctor = _nouveau_object_ctor,
-	.dtor = nouveau_object_destroy,
-	.init = nouveau_object_init,
-	.fini = nouveau_object_fini,
-	.mthd = nouveau_control_mthd,
-};
-
-struct nouveau_oclass
-nouveau_control_oclass[] = {
-	{ .handle = NVIF_IOCTL_NEW_V0_CONTROL,
-	  .ofuncs = &nouveau_control_ofuncs
-	},
-	{}
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
deleted file mode 100644
index 4e74a33..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-#include <engine/copy.h>
-#include <engine/bsp.h>
-#include <engine/vp.h>
-#include <engine/ppp.h>
-#include <engine/perfmon.h>
-
-int
-gm100_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x117:
-		device->cname = "GM107";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm107_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
-
-#if 0
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-#endif
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm107_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  gm107_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-#if 0
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-#endif
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-#if 0
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-#endif
-		break;
-	case 0x124:
-		device->cname = "GM204";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
-#if 0
-		/* looks to be some non-trivial changes */
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		/* priv ring says no to 0x10eb14 writes */
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
-#endif
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
-#if 0
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-#endif
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-#if 0
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm107_graph_oclass;
-#endif
-		device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
-#if 0
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &gm204_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &gm204_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &gm204_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-#endif
-		break;
-	default:
-		nv_fatal(device, "unknown Maxwell chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
deleted file mode 100644
index 573b55f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv04_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x04:
-		device->cname = "NV04";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv04_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x05:
-		device->cname = "NV05";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv05_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown RIVA chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
deleted file mode 100644
index 183a85a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv10_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x10:
-		device->cname = "NV10";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x15:
-		device->cname = "NV15";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x16:
-		device->cname = "NV16";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x1a:
-		device->cname = "nForce";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x11:
-		device->cname = "NV11";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x17:
-		device->cname = "NV17";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x1f:
-		device->cname = "nForce2";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x18:
-		device->cname = "NV18";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Celsius chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
deleted file mode 100644
index aa564c6..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv20_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x20:
-		device->cname = "NV20";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv20_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv20_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x25:
-		device->cname = "NV25";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x28:
-		device->cname = "NV28";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x2a:
-		device->cname = "NV2A";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Kelvin chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
deleted file mode 100644
index 11bd31d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/disp.h>
-
-int
-nv30_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x30:
-		device->cname = "NV30";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x35:
-		device->cname = "NV35";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv35_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x31:
-		device->cname = "NV31";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x36:
-		device->cname = "NV36";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv36_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	case 0x34:
-		device->cname = "NV34";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv34_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Rankine chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
deleted file mode 100644
index e96c223..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/vm.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nv40_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x40:
-		device->cname = "NV40";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x41:
-		device->cname = "NV41";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x42:
-		device->cname = "NV42";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x43:
-		device->cname = "NV43";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x45:
-		device->cname = "NV45";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x47:
-		device->cname = "G70";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv47_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x49:
-		device->cname = "G71";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x4b:
-		device->cname = "G73";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x44:
-		device->cname = "NV44";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x46:
-		device->cname = "G72";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x4a:
-		device->cname = "NV44A";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x4c:
-		device->cname = "C61";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x4e:
-		device->cname = "C51";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv4e_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x63:
-		device->cname = "C73";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x67:
-		device->cname = "C67";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	case 0x68:
-		device->cname = "C68";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Curie chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
deleted file mode 100644
index 96f568d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/vp.h>
-#include <engine/crypt.h>
-#include <engine/bsp.h>
-#include <engine/ppp.h>
-#include <engine/copy.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nv50_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0x50:
-		device->cname = "G80";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv50_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv50_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv50_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv50_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv50_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv50_perfmon_oclass;
-		break;
-	case 0x84:
-		device->cname = "G84";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0x86:
-		device->cname = "G86";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0x92:
-		device->cname = "G92";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0x94:
-		device->cname = "G94";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0x96:
-		device->cname = "G96";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0x98:
-		device->cname = "G98";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0xa0:
-		device->cname = "G200";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0xaa:
-		device->cname = "MCP77/MCP78";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0xac:
-		device->cname = "MCP79/MCP7A";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
-		break;
-	case 0xa3:
-		device->cname = "GT215";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nva3_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
-		break;
-	case 0xa5:
-		device->cname = "GT216";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nva3_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
-		break;
-	case 0xa8:
-		device->cname = "GT218";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nva3_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
-		break;
-	case 0xaf:
-		device->cname = "MCP89";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &g80_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvaf_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvaf_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nva3_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Tesla chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
deleted file mode 100644
index 72a40f9..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/vp.h>
-#include <engine/bsp.h>
-#include <engine/ppp.h>
-#include <engine/copy.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nvc0_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0xc0:
-		device->cname = "GF100";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc0_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xc4:
-		device->cname = "GF104";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xc3:
-		device->cname = "GF106";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xce:
-		device->cname = "GF114";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xcf:
-		device->cname = "GF116";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xc1:
-		device->cname = "GF108";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc1_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xc8:
-		device->cname = "GF110";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv94_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv94_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvc0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvc0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvc8_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xd9:
-		device->cname = "GF119";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nvd0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvd0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvd9_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvd0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	case 0xd7:
-		device->cname = "GF117";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nvd0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  gf117_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvd7_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvd0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Fermi chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-	}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
deleted file mode 100644
index 7329226..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-#include <engine/copy.h>
-#include <engine/bsp.h>
-#include <engine/vp.h>
-#include <engine/ppp.h>
-#include <engine/perfmon.h>
-
-int
-nve0_identify(struct nouveau_device *device)
-{
-	switch (device->chipset) {
-	case 0xe4:
-		device->cname = "GK104";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  gk104_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
-		break;
-	case 0xe7:
-		device->cname = "GK107";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvd0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
-		break;
-	case 0xe6:
-		device->cname = "GK106";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  gk104_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
-		break;
-	case 0xea:
-		device->cname = "GK20A";
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &gk20a_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk20a_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &gk20a_bar_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk20a_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk20a_graph_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &gk20a_volt_oclass;
-		break;
-	case 0xf0:
-		device->cname = "GK110";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvd0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
-		break;
-	case 0xf1:
-		device->cname = "GK110B";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nvd0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nvd0_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk110b_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
-		break;
-	case 0x106:
-		device->cname = "GK208B";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nv108_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		break;
-	case 0x108:
-		device->cname = "GK208";
-		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
-		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
-		device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
-		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
-		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
-		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
-		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
-		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
-		device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
-		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
-		device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
-		device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
-		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
-		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
-		device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
-		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
-		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
-		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
-		device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  nv108_graph_oclass;
-		device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
-		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
-		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
-		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
-		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
-		break;
-	default:
-		nv_fatal(device, "unknown Kepler chipset\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/priv.h b/drivers/gpu/drm/nouveau/core/engine/device/priv.h
deleted file mode 100644
index 035fd5b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/priv.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NVKM_DEVICE_PRIV_H__
-#define __NVKM_DEVICE_PRIV_H__
-
-#include <engine/device.h>
-
-extern struct nouveau_oclass nouveau_control_oclass[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
deleted file mode 100644
index 64b8466..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include "priv.h"
-#include "outp.h"
-#include "conn.h"
-
-int
-nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size,
-			 struct nvkm_notify *notify)
-{
-	struct nouveau_disp *disp =
-		container_of(notify->event, typeof(*disp), vblank);
-	union {
-		struct nvif_notify_head_req_v0 v0;
-	} *req = data;
-	int ret;
-
-	if (nvif_unpack(req->v0, 0, 0, false)) {
-		notify->size = sizeof(struct nvif_notify_head_rep_v0);
-		if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
-			notify->types = 1;
-			notify->index = req->v0.head;
-			return 0;
-		}
-	}
-
-	return ret;
-}
-
-void
-nouveau_disp_vblank(struct nouveau_disp *disp, int head)
-{
-	struct nvif_notify_head_rep_v0 rep = {};
-	nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
-}
-
-static int
-nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size,
-		      struct nvkm_notify *notify)
-{
-	struct nouveau_disp *disp =
-		container_of(notify->event, typeof(*disp), hpd);
-	union {
-		struct nvif_notify_conn_req_v0 v0;
-	} *req = data;
-	struct nvkm_output *outp;
-	int ret;
-
-	if (nvif_unpack(req->v0, 0, 0, false)) {
-		notify->size = sizeof(struct nvif_notify_conn_rep_v0);
-		list_for_each_entry(outp, &disp->outp, head) {
-			if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
-				if (ret = -ENODEV, outp->conn->hpd.event) {
-					notify->types = req->v0.mask;
-					notify->index = req->v0.conn;
-					ret = 0;
-				}
-				break;
-			}
-		}
-	}
-
-	return ret;
-}
-
-static const struct nvkm_event_func
-nouveau_disp_hpd_func = {
-	.ctor = nouveau_disp_hpd_ctor
-};
-
-int
-nouveau_disp_ntfy(struct nouveau_object *object, u32 type,
-		  struct nvkm_event **event)
-{
-	struct nouveau_disp *disp = (void *)object->engine;
-	switch (type) {
-	case NV04_DISP_NTFY_VBLANK:
-		*event = &disp->vblank;
-		return 0;
-	case NV04_DISP_NTFY_CONN:
-		*event = &disp->hpd;
-		return 0;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-int
-_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_disp *disp = (void *)object;
-	struct nvkm_output *outp;
-	int ret;
-
-	list_for_each_entry(outp, &disp->outp, head) {
-		ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
-		if (ret && suspend)
-			goto fail_outp;
-	}
-
-	return nouveau_engine_fini(&disp->base, suspend);
-
-fail_outp:
-	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
-		nv_ofuncs(outp)->init(nv_object(outp));
-	}
-
-	return ret;
-}
-
-int
-_nouveau_disp_init(struct nouveau_object *object)
-{
-	struct nouveau_disp *disp = (void *)object;
-	struct nvkm_output *outp;
-	int ret;
-
-	ret = nouveau_engine_init(&disp->base);
-	if (ret)
-		return ret;
-
-	list_for_each_entry(outp, &disp->outp, head) {
-		ret = nv_ofuncs(outp)->init(nv_object(outp));
-		if (ret)
-			goto fail_outp;
-	}
-
-	return ret;
-
-fail_outp:
-	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
-		nv_ofuncs(outp)->fini(nv_object(outp), false);
-	}
-
-	return ret;
-}
-
-void
-_nouveau_disp_dtor(struct nouveau_object *object)
-{
-	struct nouveau_disp *disp = (void *)object;
-	struct nvkm_output *outp, *outt;
-
-	nvkm_event_fini(&disp->vblank);
-	nvkm_event_fini(&disp->hpd);
-
-	if (disp->outp.next) {
-		list_for_each_entry_safe(outp, outt, &disp->outp, head) {
-			nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
-		}
-	}
-
-	nouveau_engine_destroy(&disp->base);
-}
-
-int
-nouveau_disp_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, int heads,
-		     const char *intname, const char *extname,
-		     int length, void **pobject)
-{
-	struct nouveau_disp_impl *impl = (void *)oclass;
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nouveau_disp *disp;
-	struct nouveau_oclass **sclass;
-	struct nouveau_object *object;
-	struct dcb_output dcbE;
-	u8  hpd = 0, ver, hdr;
-	u32 data;
-	int ret, i;
-
-	ret = nouveau_engine_create_(parent, engine, oclass, true,
-				     intname, extname, length, pobject);
-	disp = *pobject;
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&disp->outp);
-
-	/* create output objects for each display path in the vbios */
-	i = -1;
-	while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
-		if (dcbE.type == DCB_OUTPUT_UNUSED)
-			continue;
-		if (dcbE.type == DCB_OUTPUT_EOL)
-			break;
-		data = dcbE.location << 4 | dcbE.type;
-
-		oclass = nvkm_output_oclass;
-		sclass = impl->outp;
-		while (sclass && sclass[0]) {
-			if (sclass[0]->handle == data) {
-				oclass = sclass[0];
-				break;
-			}
-			sclass++;
-		}
-
-		nouveau_object_ctor(*pobject, *pobject, oclass,
-				    &dcbE, i, &object);
-		hpd = max(hpd, (u8)(dcbE.connector + 1));
-	}
-
-	ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
-	if (ret)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
deleted file mode 100644
index 1496b56..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/event.h>
-
-#include <subdev/gpio.h>
-
-#include "conn.h"
-#include "outp.h"
-
-static int
-nvkm_connector_hpd(struct nvkm_notify *notify)
-{
-	struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
-	struct nouveau_disp *disp = nouveau_disp(conn);
-	struct nouveau_gpio *gpio = nouveau_gpio(conn);
-	const struct nvkm_gpio_ntfy_rep *line = notify->data;
-	struct nvif_notify_conn_rep_v0 rep;
-	int index = conn->index;
-
-	DBG("HPD: %d\n", line->mask);
-
-	if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
-		rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
-	else
-		rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
-	rep.version = 0;
-
-	nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
-	return NVKM_NOTIFY_KEEP;
-}
-
-int
-_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvkm_connector *conn = (void *)object;
-	nvkm_notify_put(&conn->hpd);
-	return nouveau_object_fini(&conn->base, suspend);
-}
-
-int
-_nvkm_connector_init(struct nouveau_object *object)
-{
-	struct nvkm_connector *conn = (void *)object;
-	int ret = nouveau_object_init(&conn->base);
-	if (ret == 0)
-		nvkm_notify_get(&conn->hpd);
-	return ret;
-}
-
-void
-_nvkm_connector_dtor(struct nouveau_object *object)
-{
-	struct nvkm_connector *conn = (void *)object;
-	nvkm_notify_fini(&conn->hpd);
-	nouveau_object_destroy(&conn->base);
-}
-
-int
-nvkm_connector_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass,
-		       struct nvbios_connE *info, int index,
-		       int length, void **pobject)
-{
-	static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
-	struct nouveau_gpio *gpio = nouveau_gpio(parent);
-	struct nouveau_disp *disp = (void *)engine;
-	struct nvkm_connector *conn;
-	struct nvkm_output *outp;
-	struct dcb_gpio_func func;
-	int ret;
-
-	list_for_each_entry(outp, &disp->outp, head) {
-		if (outp->conn && outp->conn->index == index) {
-			atomic_inc(&nv_object(outp->conn)->refcount);
-			*pobject = outp->conn;
-			return 1;
-		}
-	}
-
-	ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
-	conn = *pobject;
-	if (ret)
-		return ret;
-
-	conn->info = *info;
-	conn->index = index;
-
-	DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
-	    info->type, info->location, info->hpd, info->dp,
-	    info->di, info->sr, info->lcdid);
-
-	if ((info->hpd = ffs(info->hpd))) {
-		if (--info->hpd >= ARRAY_SIZE(hpd)) {
-			ERR("hpd %02x unknown\n", info->hpd);
-			return 0;
-		}
-		info->hpd = hpd[info->hpd];
-
-		ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
-		if (ret) {
-			ERR("func %02x lookup failed, %d\n", info->hpd, ret);
-			return 0;
-		}
-
-		ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
-				       true, &(struct nvkm_gpio_ntfy_req) {
-					.mask = NVKM_GPIO_TOGGLED,
-					.line = func.line,
-				       },
-				       sizeof(struct nvkm_gpio_ntfy_req),
-				       sizeof(struct nvkm_gpio_ntfy_rep),
-				       &conn->hpd);
-		if (ret) {
-			ERR("func %02x failed, %d\n", info->hpd, ret);
-		} else {
-			DBG("func %02x (HPD)\n", info->hpd);
-		}
-	}
-
-	return 0;
-}
-
-int
-_nvkm_connector_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *info, u32 index,
-		     struct nouveau_object **pobject)
-{
-	struct nvkm_connector *conn;
-	int ret;
-
-	ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
-	*pobject = nv_object(conn);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nvkm_connector_oclass = &(struct nvkm_connector_impl) {
-	.base = {
-		.handle = 0,
-		.ofuncs = &(struct nouveau_ofuncs) {
-			.ctor = _nvkm_connector_ctor,
-			.dtor = _nvkm_connector_dtor,
-			.init = _nvkm_connector_init,
-			.fini = _nvkm_connector_fini,
-		},
-	},
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
deleted file mode 100644
index 55e5f5c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NVKM_DISP_CONN_H__
-#define __NVKM_DISP_CONN_H__
-
-#include "priv.h"
-
-struct nvkm_connector {
-	struct nouveau_object base;
-	struct list_head head;
-
-	struct nvbios_connE info;
-	int index;
-
-	struct nvkm_notify hpd;
-};
-
-#define nvkm_connector_create(p,e,c,b,i,d)                                     \
-	nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_connector_destroy(d) ({                                           \
-	struct nvkm_connector *disp = (d);                                     \
-	_nvkm_connector_dtor(nv_object(disp));                                 \
-})
-#define nvkm_connector_init(d) ({                                              \
-	struct nvkm_connector *disp = (d);                                     \
-	_nvkm_connector_init(nv_object(disp));                                 \
-})
-#define nvkm_connector_fini(d,s) ({                                            \
-	struct nvkm_connector *disp = (d);                                     \
-	_nvkm_connector_fini(nv_object(disp), (s));                            \
-})
-
-int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *, struct nvbios_connE *,
-			   int, int, void **);
-
-int  _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, void *, u32,
-			  struct nouveau_object **);
-void _nvkm_connector_dtor(struct nouveau_object *);
-int  _nvkm_connector_init(struct nouveau_object *);
-int  _nvkm_connector_fini(struct nouveau_object *, bool);
-
-struct nvkm_connector_impl {
-	struct nouveau_oclass base;
-};
-
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-	struct nvkm_connector *_conn = (void *)conn;                           \
-	nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index,      \
-	       _conn->info.location, _conn->info.type, ##a);                   \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
deleted file mode 100644
index b36addf..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nv50_dac_power(NV50_DISP_MTHD_V1)
-{
-	const u32 doff = outp->or * 0x800;
-	union {
-		struct nv50_disp_dac_pwr_v0 v0;
-	} *args = data;
-	u32 stat;
-	int ret;
-
-	nv_ioctl(object, "disp dac pwr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
-				 "vsync %d hsync %d\n",
-			 args->v0.version, args->v0.state, args->v0.data,
-			 args->v0.vsync, args->v0.hsync);
-		stat  = 0x00000040 * !args->v0.state;
-		stat |= 0x00000010 * !args->v0.data;
-		stat |= 0x00000004 * !args->v0.vsync;
-		stat |= 0x00000001 * !args->v0.hsync;
-	} else
-		return ret;
-
-	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-	nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
-	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-	return 0;
-}
-
-int
-nv50_dac_sense(NV50_DISP_MTHD_V1)
-{
-	union {
-		struct nv50_disp_dac_load_v0 v0;
-	} *args = data;
-	const u32 doff = outp->or * 0x800;
-	u32 loadval;
-	int ret;
-
-	nv_ioctl(object, "disp dac load size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp dac load vers %d data %08x\n",
-			 args->v0.version, args->v0.data);
-		if (args->v0.data & 0xfff00000)
-			return -EINVAL;
-		loadval = args->v0.data;
-	} else
-		return ret;
-
-	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
-	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-
-	nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
-	mdelay(9);
-	udelay(500);
-	loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
-
-	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
-	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-
-	nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
-	if (!(loadval & 0x80000000))
-		return -ETIMEDOUT;
-
-	args->v0.load = (loadval & 0x38000000) >> 27;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
deleted file mode 100644
index 16db08d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/i2c.h>
-
-#include "nv50.h"
-
-#include <nvif/class.h>
-
-#include "dport.h"
-#include "outpdp.h"
-
-/******************************************************************************
- * link training
- *****************************************************************************/
-struct dp_state {
-	struct nvkm_output_dp *outp;
-	int link_nr;
-	u32 link_bw;
-	u8  stat[6];
-	u8  conf[4];
-	bool pc2;
-	u8  pc2stat;
-	u8  pc2conf[2];
-};
-
-static int
-dp_set_link_config(struct dp_state *dp)
-{
-	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
-	struct nvkm_output_dp *outp = dp->outp;
-	struct nouveau_disp *disp = nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(disp);
-	struct nvbios_init init = {
-		.subdev = nv_subdev(disp),
-		.bios = bios,
-		.offset = 0x0000,
-		.outp = &outp->base.info,
-		.crtc = -1,
-		.execute = 1,
-	};
-	u32 lnkcmp;
-	u8 sink[2];
-	int ret;
-
-	DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
-
-	/* set desired link configuration on the source */
-	if ((lnkcmp = dp->outp->info.lnkcmp)) {
-		if (outp->version < 0x30) {
-			while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
-				lnkcmp += 4;
-			init.offset = nv_ro16(bios, lnkcmp + 2);
-		} else {
-			while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
-				lnkcmp += 3;
-			init.offset = nv_ro16(bios, lnkcmp + 1);
-		}
-
-		nvbios_exec(&init);
-	}
-
-	ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
-			    outp->dpcd[DPCD_RC02] &
-				       DPCD_RC02_ENHANCED_FRAME_CAP);
-	if (ret) {
-		if (ret < 0)
-			ERR("lnk_ctl failed with %d\n", ret);
-		return ret;
-	}
-
-	impl->lnk_pwr(outp, dp->link_nr);
-
-	/* set desired link configuration on the sink */
-	sink[0] = dp->link_bw / 27000;
-	sink[1] = dp->link_nr;
-	if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
-		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
-
-	return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
-}
-
-static void
-dp_set_training_pattern(struct dp_state *dp, u8 pattern)
-{
-	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
-	struct nvkm_output_dp *outp = dp->outp;
-	u8 sink_tp;
-
-	DBG("training pattern %d\n", pattern);
-	impl->pattern(outp, pattern);
-
-	nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
-	sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
-	sink_tp |= pattern;
-	nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
-}
-
-static int
-dp_link_train_commit(struct dp_state *dp, bool pc)
-{
-	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
-	struct nvkm_output_dp *outp = dp->outp;
-	int ret, i;
-
-	for (i = 0; i < dp->link_nr; i++) {
-		u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
-		u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
-		u8 lpre = (lane & 0x0c) >> 2;
-		u8 lvsw = (lane & 0x03) >> 0;
-		u8 hivs = 3 - lpre;
-		u8 hipe = 3;
-		u8 hipc = 3;
-
-		if (lpc2 >= hipc)
-			lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
-		if (lpre >= hipe) {
-			lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
-			lvsw = hivs = 3 - (lpre & 3);
-		} else
-		if (lvsw >= hivs) {
-			lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
-		}
-
-		dp->conf[i] = (lpre << 3) | lvsw;
-		dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
-
-		DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
-		impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
-	}
-
-	ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
-	if (ret)
-		return ret;
-
-	if (pc) {
-		ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int
-dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
-{
-	struct nvkm_output_dp *outp = dp->outp;
-	int ret;
-
-	if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
-		mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
-	else
-		udelay(delay);
-
-	ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
-	if (ret)
-		return ret;
-
-	if (pc) {
-		ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
-		if (ret)
-			dp->pc2stat = 0x00;
-		DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
-	} else {
-		DBG("status %6ph\n", dp->stat);
-	}
-
-	return 0;
-}
-
-static int
-dp_link_train_cr(struct dp_state *dp)
-{
-	bool cr_done = false, abort = false;
-	int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
-	int tries = 0, i;
-
-	dp_set_training_pattern(dp, 1);
-
-	do {
-		if (dp_link_train_commit(dp, false) ||
-		    dp_link_train_update(dp, false, 100))
-			break;
-
-		cr_done = true;
-		for (i = 0; i < dp->link_nr; i++) {
-			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
-			if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
-				cr_done = false;
-				if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
-					abort = true;
-				break;
-			}
-		}
-
-		if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
-			voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
-			tries = 0;
-		}
-	} while (!cr_done && !abort && ++tries < 5);
-
-	return cr_done ? 0 : -1;
-}
-
-static int
-dp_link_train_eq(struct dp_state *dp)
-{
-	struct nvkm_output_dp *outp = dp->outp;
-	bool eq_done = false, cr_done = true;
-	int tries = 0, i;
-
-	if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
-		dp_set_training_pattern(dp, 3);
-	else
-		dp_set_training_pattern(dp, 2);
-
-	do {
-		if ((tries &&
-		    dp_link_train_commit(dp, dp->pc2)) ||
-		    dp_link_train_update(dp, dp->pc2, 400))
-			break;
-
-		eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
-		for (i = 0; i < dp->link_nr && eq_done; i++) {
-			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
-			if (!(lane & DPCD_LS02_LANE0_CR_DONE))
-				cr_done = false;
-			if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
-			    !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
-				eq_done = false;
-		}
-	} while (!eq_done && cr_done && ++tries <= 5);
-
-	return eq_done ? 0 : -1;
-}
-
-static void
-dp_link_train_init(struct dp_state *dp, bool spread)
-{
-	struct nvkm_output_dp *outp = dp->outp;
-	struct nouveau_disp *disp = nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(disp);
-	struct nvbios_init init = {
-		.subdev = nv_subdev(disp),
-		.bios = bios,
-		.outp = &outp->base.info,
-		.crtc = -1,
-		.execute = 1,
-	};
-
-	/* set desired spread */
-	if (spread)
-		init.offset = outp->info.script[2];
-	else
-		init.offset = outp->info.script[3];
-	nvbios_exec(&init);
-
-	/* pre-train script */
-	init.offset = outp->info.script[0];
-	nvbios_exec(&init);
-}
-
-static void
-dp_link_train_fini(struct dp_state *dp)
-{
-	struct nvkm_output_dp *outp = dp->outp;
-	struct nouveau_disp *disp = nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(disp);
-	struct nvbios_init init = {
-		.subdev = nv_subdev(disp),
-		.bios = bios,
-		.outp = &outp->base.info,
-		.crtc = -1,
-		.execute = 1,
-	};
-
-	/* post-train script */
-	init.offset = outp->info.script[1],
-	nvbios_exec(&init);
-}
-
-static const struct dp_rates {
-	u32 rate;
-	u8  bw;
-	u8  nr;
-} nouveau_dp_rates[] = {
-	{ 2160000, 0x14, 4 },
-	{ 1080000, 0x0a, 4 },
-	{ 1080000, 0x14, 2 },
-	{  648000, 0x06, 4 },
-	{  540000, 0x0a, 2 },
-	{  540000, 0x14, 1 },
-	{  324000, 0x06, 2 },
-	{  270000, 0x0a, 1 },
-	{  162000, 0x06, 1 },
-	{}
-};
-
-void
-nouveau_dp_train(struct work_struct *w)
-{
-	struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const struct dp_rates *cfg = nouveau_dp_rates;
-	struct dp_state _dp = {
-		.outp = outp,
-	}, *dp = &_dp;
-	u32 datarate = 0;
-	int ret;
-
-	if (!outp->base.info.location && priv->sor.magic)
-		priv->sor.magic(&outp->base);
-
-	/* bring capabilities within encoder limits */
-	if (nv_mclass(priv) < GF110_DISP)
-		outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
-	if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
-		outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
-		outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
-	}
-	if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
-		outp->dpcd[1] = outp->base.info.dpconf.link_bw;
-	dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
-
-	/* restrict link config to the lowest required rate, if requested */
-	if (datarate) {
-		datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
-		while (cfg[1].rate >= datarate)
-			cfg++;
-	}
-	cfg--;
-
-	/* disable link interrupt handling during link training */
-	nvkm_notify_put(&outp->irq);
-
-	/* enable down-spreading and execute pre-train script from vbios */
-	dp_link_train_init(dp, outp->dpcd[3] & 0x01);
-
-	while (ret = -EIO, (++cfg)->rate) {
-		/* select next configuration supported by encoder and sink */
-		while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
-		       cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
-			cfg++;
-		dp->link_bw = cfg->bw * 27000;
-		dp->link_nr = cfg->nr;
-
-		/* program selected link configuration */
-		ret = dp_set_link_config(dp);
-		if (ret == 0) {
-			/* attempt to train the link at this configuration */
-			memset(dp->stat, 0x00, sizeof(dp->stat));
-			if (!dp_link_train_cr(dp) &&
-			    !dp_link_train_eq(dp))
-				break;
-		} else
-		if (ret) {
-			/* dp_set_link_config() handled training, or
-			 * we failed to communicate with the sink.
-			 */
-			break;
-		}
-	}
-
-	/* finish link training and execute post-train script from vbios */
-	dp_set_training_pattern(dp, 0);
-	if (ret < 0)
-		ERR("link training failed\n");
-
-	dp_link_train_fini(dp);
-
-	/* signal completion and enable link interrupt handling */
-	DBG("training complete\n");
-	atomic_set(&outp->lt.done, 1);
-	wake_up(&outp->lt.wait);
-	nvkm_notify_get(&outp->irq);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
deleted file mode 100644
index 5628d2d5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef __NVKM_DISP_DPORT_H__
-#define __NVKM_DISP_DPORT_H__
-
-/* DPCD Receiver Capabilities */
-#define DPCD_RC00_DPCD_REV                                              0x00000
-#define DPCD_RC01_MAX_LINK_RATE                                         0x00001
-#define DPCD_RC02                                                       0x00002
-#define DPCD_RC02_ENHANCED_FRAME_CAP                                       0x80
-#define DPCD_RC02_TPS3_SUPPORTED                                           0x40
-#define DPCD_RC02_MAX_LANE_COUNT                                           0x1f
-#define DPCD_RC03                                                       0x00003
-#define DPCD_RC03_MAX_DOWNSPREAD                                           0x01
-#define DPCD_RC0E_AUX_RD_INTERVAL                                       0x0000e
-
-/* DPCD Link Configuration */
-#define DPCD_LC00_LINK_BW_SET                                           0x00100
-#define DPCD_LC01                                                       0x00101
-#define DPCD_LC01_ENHANCED_FRAME_EN                                        0x80
-#define DPCD_LC01_LANE_COUNT_SET                                           0x1f
-#define DPCD_LC02                                                       0x00102
-#define DPCD_LC02_TRAINING_PATTERN_SET                                     0x03
-#define DPCD_LC03(l)                                            ((l) +  0x00103)
-#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED                                 0x20
-#define DPCD_LC03_PRE_EMPHASIS_SET                                         0x18
-#define DPCD_LC03_MAX_SWING_REACHED                                        0x04
-#define DPCD_LC03_VOLTAGE_SWING_SET                                        0x03
-#define DPCD_LC0F                                                       0x0010f
-#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED                           0x40
-#define DPCD_LC0F_LANE1_POST_CURSOR2_SET                                   0x30
-#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED                           0x04
-#define DPCD_LC0F_LANE0_POST_CURSOR2_SET                                   0x03
-#define DPCD_LC10                                                       0x00110
-#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED                           0x40
-#define DPCD_LC10_LANE3_POST_CURSOR2_SET                                   0x30
-#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED                           0x04
-#define DPCD_LC10_LANE2_POST_CURSOR2_SET                                   0x03
-
-/* DPCD Link/Sink Status */
-#define DPCD_LS02                                                       0x00202
-#define DPCD_LS02_LANE1_SYMBOL_LOCKED                                      0x40
-#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE                                    0x20
-#define DPCD_LS02_LANE1_CR_DONE                                            0x10
-#define DPCD_LS02_LANE0_SYMBOL_LOCKED                                      0x04
-#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE                                    0x02
-#define DPCD_LS02_LANE0_CR_DONE                                            0x01
-#define DPCD_LS03                                                       0x00203
-#define DPCD_LS03_LANE3_SYMBOL_LOCKED                                      0x40
-#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE                                    0x20
-#define DPCD_LS03_LANE3_CR_DONE                                            0x10
-#define DPCD_LS03_LANE2_SYMBOL_LOCKED                                      0x04
-#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE                                    0x02
-#define DPCD_LS03_LANE2_CR_DONE                                            0x01
-#define DPCD_LS04                                                       0x00204
-#define DPCD_LS04_LINK_STATUS_UPDATED                                      0x80
-#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED                           0x40
-#define DPCD_LS04_INTERLANE_ALIGN_DONE                                     0x01
-#define DPCD_LS06                                                       0x00206
-#define DPCD_LS06_LANE1_PRE_EMPHASIS                                       0xc0
-#define DPCD_LS06_LANE1_VOLTAGE_SWING                                      0x30
-#define DPCD_LS06_LANE0_PRE_EMPHASIS                                       0x0c
-#define DPCD_LS06_LANE0_VOLTAGE_SWING                                      0x03
-#define DPCD_LS07                                                       0x00207
-#define DPCD_LS07_LANE3_PRE_EMPHASIS                                       0xc0
-#define DPCD_LS07_LANE3_VOLTAGE_SWING                                      0x30
-#define DPCD_LS07_LANE2_PRE_EMPHASIS                                       0x0c
-#define DPCD_LS07_LANE2_VOLTAGE_SWING                                      0x03
-#define DPCD_LS0C                                                       0x0020c
-#define DPCD_LS0C_LANE3_POST_CURSOR2                                       0xc0
-#define DPCD_LS0C_LANE2_POST_CURSOR2                                       0x30
-#define DPCD_LS0C_LANE1_POST_CURSOR2                                       0x0c
-#define DPCD_LS0C_LANE0_POST_CURSOR2                                       0x03
-
-void nouveau_dp_train(struct work_struct *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
deleted file mode 100644
index e2ad054..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm107_disp_sclass[] = {
-	{ GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
-	{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
-	{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
-	{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
-	{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-gm107_disp_main_oclass[] = {
-	{ GM107_DISP, &nvd0_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int heads = nv_rd32(parent, 0x022448);
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, heads,
-				  "PDISP", "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = gm107_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nvd0_disp_intr;
-	INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
-	priv->sclass = gm107_disp_sclass;
-	priv->head.nr = heads;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nvd0_hda_eld;
-	priv->sor.hdmi = nve0_hdmi_ctrl;
-	return 0;
-}
-
-struct nouveau_oclass *
-gm107_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x07),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm107_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nvd0_disp_vblank_func,
-	.base.outp =  nvd0_disp_outp_sclass,
-	.mthd.core = &nve0_disp_core_mthd_chan,
-	.mthd.base = &nvd0_disp_base_mthd_chan,
-	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
-	.mthd.prev = -0x020000,
-	.head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c
deleted file mode 100644
index 672ded7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm204_disp_sclass[] = {
-	{ GM204_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
-	{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
-	{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
-	{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
-	{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-gm204_disp_main_oclass[] = {
-	{ GM204_DISP, &nvd0_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-gm204_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int heads = nv_rd32(parent, 0x022448);
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, heads,
-				  "PDISP", "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = gm204_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nvd0_disp_intr;
-	INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
-	priv->sclass = gm204_disp_sclass;
-	priv->head.nr = heads;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nvd0_hda_eld;
-	priv->sor.hdmi = nvd0_hdmi_ctrl;
-	priv->sor.magic = gm204_sor_magic;
-	return 0;
-}
-
-struct nouveau_oclass *
-gm204_disp_outp_sclass[] = {
-	&gm204_sor_dp_impl.base.base,
-	NULL
-};
-
-struct nouveau_oclass *
-gm204_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x07),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm204_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nvd0_disp_vblank_func,
-	.base.outp =  gm204_disp_outp_sclass,
-	.mthd.core = &nve0_disp_core_mthd_chan,
-	.mthd.base = &nvd0_disp_base_mthd_chan,
-	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
-	.mthd.prev = -0x020000,
-	.head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
deleted file mode 100644
index fe9ef58..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nva3_hda_eld(NV50_DISP_MTHD_V1)
-{
-	union {
-		struct nv50_disp_sor_hda_eld_v0 v0;
-	} *args = data;
-	const u32 soff = outp->or * 0x800;
-	int ret, i;
-
-	nv_ioctl(object, "disp sor hda eld size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
-		if (size > 0x60)
-			return -E2BIG;
-	} else
-		return ret;
-
-	if (size && args->v0.data[0]) {
-		if (outp->info.type == DCB_OUTPUT_DP) {
-			nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
-			nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
-		}
-		for (i = 0; i < size; i++)
-			nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
-		for (; i < 0x60; i++)
-			nv_wr32(priv, 0x61c440 + soff, (i << 8));
-		nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
-	} else {
-		if (outp->info.type == DCB_OUTPUT_DP) {
-			nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
-			nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
-		}
-		nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
deleted file mode 100644
index 1d4e843..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nvd0_hda_eld(NV50_DISP_MTHD_V1)
-{
-	union {
-		struct nv50_disp_sor_hda_eld_v0 v0;
-	} *args = data;
-	const u32 soff = outp->or * 0x030;
-	const u32 hoff = head * 0x800;
-	int ret, i;
-
-	nv_ioctl(object, "disp sor hda eld size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
-		if (size > 0x60)
-			return -E2BIG;
-	} else
-		return ret;
-
-	if (size && args->v0.data[0]) {
-		if (outp->info.type == DCB_OUTPUT_DP) {
-			nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
-			nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
-		}
-		nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
-		for (i = 0; i < size; i++)
-			nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
-		for (; i < 0x60; i++)
-			nv_wr32(priv, 0x10ec00 + soff, (i << 8));
-		nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
-	} else {
-		if (outp->info.type == DCB_OUTPUT_DP) {
-			nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
-			nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
-		}
-		nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
deleted file mode 100644
index fa276de..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nv84_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
-	const u32 hoff = (head * 0x800);
-	union {
-		struct nv50_disp_sor_hdmi_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl;
-	int ret;
-
-	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
-				 "max_ac_packet %d rekey %d\n",
-			 args->v0.version, args->v0.state,
-			 args->v0.max_ac_packet, args->v0.rekey);
-		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
-			return -EINVAL;
-		ctrl  = 0x40000000 * !!args->v0.state;
-		ctrl |= args->v0.max_ac_packet << 16;
-		ctrl |= args->v0.rekey;
-		ctrl |= 0x1f000000; /* ??? */
-	} else
-		return ret;
-
-	if (!(ctrl & 0x40000000)) {
-		nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
-		nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
-		nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
-		return 0;
-	}
-
-	/* AVI InfoFrame */
-	nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
-	nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
-	nv_wr32(priv, 0x616530 + hoff, 0x00000000);
-	nv_wr32(priv, 0x616534 + hoff, 0x00000000);
-	nv_wr32(priv, 0x616538 + hoff, 0x00000000);
-	nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
-
-	/* Audio InfoFrame */
-	nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
-	nv_wr32(priv, 0x61650c + hoff, 0x00000071);
-	nv_wr32(priv, 0x616510 + hoff, 0x00000000);
-	nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
-
-	nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
-	nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
-	nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
-
-	/* ??? */
-	nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
-	nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
-	nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
-	/* HDMI_CTRL */
-	nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
deleted file mode 100644
index 57eeed1..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nva3_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
-	const u32 soff = outp->or * 0x800;
-	union {
-		struct nv50_disp_sor_hdmi_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl;
-	int ret;
-
-	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
-				 "max_ac_packet %d rekey %d\n",
-			 args->v0.version, args->v0.state,
-			 args->v0.max_ac_packet, args->v0.rekey);
-		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
-			return -EINVAL;
-		ctrl  = 0x40000000 * !!args->v0.state;
-		ctrl |= args->v0.max_ac_packet << 16;
-		ctrl |= args->v0.rekey;
-		ctrl |= 0x1f000000; /* ??? */
-	} else
-		return ret;
-
-	if (!(ctrl & 0x40000000)) {
-		nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
-		nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
-		nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
-		return 0;
-	}
-
-	/* AVI InfoFrame */
-	nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
-	nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
-	nv_wr32(priv, 0x61c530 + soff, 0x00000000);
-	nv_wr32(priv, 0x61c534 + soff, 0x00000000);
-	nv_wr32(priv, 0x61c538 + soff, 0x00000000);
-	nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
-
-	/* Audio InfoFrame */
-	nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
-	nv_wr32(priv, 0x61c50c + soff, 0x00000071);
-	nv_wr32(priv, 0x61c510 + soff, 0x00000000);
-	nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
-
-	nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
-	nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
-	nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
-
-	/* ??? */
-	nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
-	nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
-	nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
-	/* HDMI_CTRL */
-	nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
deleted file mode 100644
index bac4fc4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
-	const u32 hoff = (head * 0x800);
-	union {
-		struct nv50_disp_sor_hdmi_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl;
-	int ret;
-
-	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
-				 "max_ac_packet %d rekey %d\n",
-			 args->v0.version, args->v0.state,
-			 args->v0.max_ac_packet, args->v0.rekey);
-		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
-			return -EINVAL;
-		ctrl  = 0x40000000 * !!args->v0.state;
-		ctrl |= args->v0.max_ac_packet << 16;
-		ctrl |= args->v0.rekey;
-	} else
-		return ret;
-
-	if (!(ctrl & 0x40000000)) {
-		nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
-		nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
-		nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
-		return 0;
-	}
-
-	/* AVI InfoFrame */
-	nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
-	nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
-	nv_wr32(priv, 0x616724 + hoff, 0x00000000);
-	nv_wr32(priv, 0x616728 + hoff, 0x00000000);
-	nv_wr32(priv, 0x61672c + hoff, 0x00000000);
-	nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
-
-	/* ??? InfoFrame? */
-	nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
-	nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
-
-	/* HDMI_CTRL */
-	nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
deleted file mode 100644
index 528d14e..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nve0_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
-	const u32 hoff = (head * 0x800);
-	const u32 hdmi = (head * 0x400);
-	union {
-		struct nv50_disp_sor_hdmi_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl;
-	int ret;
-
-	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
-				 "max_ac_packet %d rekey %d\n",
-			 args->v0.version, args->v0.state,
-			 args->v0.max_ac_packet, args->v0.rekey);
-		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
-			return -EINVAL;
-		ctrl  = 0x40000000 * !!args->v0.state;
-		ctrl |= args->v0.max_ac_packet << 16;
-		ctrl |= args->v0.rekey;
-	} else
-		return ret;
-
-	if (!(ctrl & 0x40000000)) {
-		nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
-		nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
-		nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
-		return 0;
-	}
-
-	/* AVI InfoFrame */
-	nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
-	nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
-	nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
-	nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
-	nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
-	nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
-
-	/* ??? InfoFrame? */
-	nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
-	nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
-
-	/* ??? */
-	nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
-
-	/* HDMI_CTRL */
-	nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
deleted file mode 100644
index 366f315..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#include <core/client.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-struct nv04_disp_priv {
-	struct nouveau_disp base;
-};
-
-static int
-nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
-		     void *data, u32 size, int head)
-{
-	const u32 hoff = head * 0x2000;
-	union {
-		struct nv04_disp_scanoutpos_v0 v0;
-	} *args = data;
-	u32 line;
-	int ret;
-
-	nv_ioctl(object, "disp scanoutpos size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
-		args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
-		args->v0.vtotal  = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
-		args->v0.vblanke = args->v0.vtotal - 1;
-
-		args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
-		args->v0.htotal  = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
-		args->v0.hblanke = args->v0.htotal - 1;
-
-		/*
-		 * If output is vga instead of digital then vtotal/htotal is
-		 * invalid so we have to give up and trigger the timestamping
-		 * fallback in the drm core.
-		 */
-		if (!args->v0.vtotal || !args->v0.htotal)
-			return -ENOTSUPP;
-
-		args->v0.time[0] = ktime_to_ns(ktime_get());
-		line = nv_rd32(priv, 0x600868 + hoff);
-		args->v0.time[1] = ktime_to_ns(ktime_get());
-		args->v0.hline = (line & 0xffff0000) >> 16;
-		args->v0.vline = (line & 0x0000ffff);
-	} else
-		return ret;
-
-	return 0;
-}
-
-static int
-nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
-{
-	union {
-		struct nv04_disp_mthd_v0 v0;
-	} *args = data;
-	struct nv04_disp_priv *priv = (void *)object->engine;
-	int head, ret;
-
-	nv_ioctl(object, "disp mthd size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
-			 args->v0.version, args->v0.method, args->v0.head);
-		mthd = args->v0.method;
-		head = args->v0.head;
-	} else
-		return ret;
-
-	if (head < 0 || head >= 2)
-		return -ENXIO;
-
-	switch (mthd) {
-	case NV04_DISP_SCANOUTPOS:
-		return nv04_disp_scanoutpos(object, priv, data, size, head);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static struct nouveau_ofuncs
-nv04_disp_ofuncs = {
-	.ctor = _nouveau_object_ctor,
-	.dtor = nouveau_object_destroy,
-	.init = nouveau_object_init,
-	.fini = nouveau_object_fini,
-	.mthd = nv04_disp_mthd,
-	.ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nv04_disp_sclass[] = {
-	{ NV04_DISP, &nv04_disp_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
-}
-
-static void
-nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
-}
-
-static const struct nvkm_event_func
-nv04_disp_vblank_func = {
-	.ctor = nouveau_disp_vblank_ctor,
-	.init = nv04_disp_vblank_init,
-	.fini = nv04_disp_vblank_fini,
-};
-
-static void
-nv04_disp_intr(struct nouveau_subdev *subdev)
-{
-	struct nv04_disp_priv *priv = (void *)subdev;
-	u32 crtc0 = nv_rd32(priv, 0x600100);
-	u32 crtc1 = nv_rd32(priv, 0x602100);
-	u32 pvideo;
-
-	if (crtc0 & 0x00000001) {
-		nouveau_disp_vblank(&priv->base, 0);
-		nv_wr32(priv, 0x600100, 0x00000001);
-	}
-
-	if (crtc1 & 0x00000001) {
-		nouveau_disp_vblank(&priv->base, 1);
-		nv_wr32(priv, 0x602100, 0x00000001);
-	}
-
-	if (nv_device(priv)->chipset >= 0x10 &&
-	    nv_device(priv)->chipset <= 0x40) {
-		pvideo = nv_rd32(priv, 0x8100);
-		if (pvideo & ~0x11)
-			nv_info(priv, "PVIDEO intr: %08x\n", pvideo);
-		nv_wr32(priv, 0x8100, pvideo);
-	}
-}
-
-static int
-nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv04_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nv04_disp_sclass;
-	nv_subdev(priv)->intr = nv04_disp_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_disp_oclass = &(struct nouveau_disp_impl) {
-	.base.handle = NV_ENGINE(DISP, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.vblank = &nv04_disp_vblank_func,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
deleted file mode 100644
index 44a8290..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ /dev/null
@@ -1,2017 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <core/enum.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/pll.h>
-#include <subdev/devinit.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_chan_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, int head,
-		       int length, void **pobject)
-{
-	const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
-	struct nv50_disp_base *base = (void *)parent;
-	struct nv50_disp_chan *chan;
-	int chid = impl->chid + head;
-	int ret;
-
-	if (base->chan & (1 << chid))
-		return -EBUSY;
-	base->chan |= (1 << chid);
-
-	ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
-				     (1ULL << NVDEV_ENGINE_DMAOBJ),
-				     length, pobject);
-	chan = *pobject;
-	if (ret)
-		return ret;
-	chan->chid = chid;
-
-	nv_parent(chan)->object_attach = impl->attach;
-	nv_parent(chan)->object_detach = impl->detach;
-	return 0;
-}
-
-static void
-nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
-{
-	struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
-	base->chan &= ~(1 << chan->chid);
-	nouveau_namedb_destroy(&chan->base);
-}
-
-static void
-nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
-	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
-	nv_wr32(priv, 0x610020, 0x00000001 << index);
-}
-
-static void
-nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
-{
-	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
-	nv_wr32(priv, 0x610020, 0x00000001 << index);
-	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
-}
-
-void
-nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
-{
-	struct nvif_notify_uevent_rep {
-	} rep;
-
-	nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
-}
-
-int
-nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
-			   struct nvkm_notify *notify)
-{
-	struct nv50_disp_dmac *dmac = (void *)object;
-	union {
-		struct nvif_notify_uevent_req none;
-	} *args = data;
-	int ret;
-
-	if (nvif_unvers(args->none)) {
-		notify->size  = sizeof(struct nvif_notify_uevent_rep);
-		notify->types = 1;
-		notify->index = dmac->base.chid;
-		return 0;
-	}
-
-	return ret;
-}
-
-const struct nvkm_event_func
-nv50_disp_chan_uevent = {
-	.ctor = nv50_disp_chan_uevent_ctor,
-	.init = nv50_disp_chan_uevent_init,
-	.fini = nv50_disp_chan_uevent_fini,
-};
-
-int
-nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type,
-		    struct nvkm_event **pevent)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	switch (type) {
-	case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
-		*pevent = &priv->uevent;
-		return 0;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-int
-nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
-	struct nv50_disp_chan *chan = (void *)object;
-	*addr = nv_device_resource_start(nv_device(object), 0) +
-		0x640000 + (chan->chid * 0x1000);
-	*size = 0x001000;
-	return 0;
-}
-
-u32
-nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_chan *chan = (void *)object;
-	return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
-}
-
-void
-nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_chan *chan = (void *)object;
-	nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
-}
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_dmac_object_attach(struct nouveau_object *parent,
-			     struct nouveau_object *object, u32 name)
-{
-	struct nv50_disp_base *base = (void *)parent->parent;
-	struct nv50_disp_chan *chan = (void *)parent;
-	u32 addr = nv_gpuobj(object)->node->offset;
-	u32 chid = chan->chid;
-	u32 data = (chid << 28) | (addr << 10) | chid;
-	return nouveau_ramht_insert(base->ramht, chid, name, data);
-}
-
-static void
-nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
-	struct nv50_disp_base *base = (void *)parent->parent;
-	nouveau_ramht_remove(base->ramht, cookie);
-}
-
-static int
-nv50_disp_dmac_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pushbuf, int head,
-		       int length, void **pobject)
-{
-	struct nv50_disp_dmac *dmac;
-	int ret;
-
-	ret = nv50_disp_chan_create_(parent, engine, oclass, head,
-				     length, pobject);
-	dmac = *pobject;
-	if (ret)
-		return ret;
-
-	dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
-	if (!dmac->pushdma)
-		return -ENOENT;
-
-	switch (nv_mclass(dmac->pushdma)) {
-	case 0x0002:
-	case 0x003d:
-		if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
-			return -EINVAL;
-
-		switch (dmac->pushdma->target) {
-		case NV_MEM_TARGET_VRAM:
-			dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
-			break;
-		case NV_MEM_TARGET_PCI_NOSNOOP:
-			dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
-			break;
-		default:
-			return -EINVAL;
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-void
-nv50_disp_dmac_dtor(struct nouveau_object *object)
-{
-	struct nv50_disp_dmac *dmac = (void *)object;
-	nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
-	nv50_disp_chan_destroy(&dmac->base);
-}
-
-static int
-nv50_disp_dmac_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *dmac = (void *)object;
-	int chid = dmac->base.chid;
-	int ret;
-
-	ret = nv50_disp_chan_init(&dmac->base);
-	if (ret)
-		return ret;
-
-	/* enable error reporting */
-	nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
-
-	/* initialise channel for dma command submission */
-	nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
-	nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
-	nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
-	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
-	nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
-	nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
-
-	/* wait for it to go inactive */
-	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
-		nv_error(dmac, "init timeout, 0x%08x\n",
-			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *dmac = (void *)object;
-	int chid = dmac->base.chid;
-
-	/* deactivate channel */
-	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
-	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
-	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
-		nv_error(dmac, "fini timeout, 0x%08x\n",
-			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	/* disable error reporting and completion notifications */
-	nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
-
-	return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static void
-nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
-		    const struct nv50_disp_mthd_list *list, int inst)
-{
-	struct nouveau_object *disp = nv_object(priv);
-	int i;
-
-	for (i = 0; list->data[i].mthd; i++) {
-		if (list->data[i].addr) {
-			u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
-			u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
-			u32 mthd = list->data[i].mthd + (list->mthd * inst);
-			const char *name = list->data[i].name;
-			char mods[16];
-
-			if (prev != next)
-				snprintf(mods, sizeof(mods), "-> 0x%08x", next);
-			else
-				snprintf(mods, sizeof(mods), "%13c", ' ');
-
-			nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
-				   mthd, prev, mods, name ? " // " : "",
-				   name ? name : "");
-		}
-	}
-}
-
-void
-nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
-		    const struct nv50_disp_mthd_chan *chan)
-{
-	struct nouveau_object *disp = nv_object(priv);
-	const struct nv50_disp_impl *impl = (void *)disp->oclass;
-	const struct nv50_disp_mthd_list *list;
-	int i, j;
-
-	if (debug > nv_subdev(priv)->debug)
-		return;
-
-	for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
-		u32 base = head * chan->addr;
-		for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
-			const char *cname = chan->name;
-			const char *sname = "";
-			char cname_[16], sname_[16];
-
-			if (chan->addr) {
-				snprintf(cname_, sizeof(cname_), "%s %d",
-					 chan->name, head);
-				cname = cname_;
-			}
-
-			if (chan->data[i].nr > 1) {
-				snprintf(sname_, sizeof(sname_), " - %s %d",
-					 chan->data[i].name, j);
-				sname = sname_;
-			}
-
-			nv_printk_(disp, debug, "%s%s:\n", cname, sname);
-			nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
-					    list, j);
-		}
-	}
-}
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x610bb8 },
-		{ 0x0088, 0x610b9c },
-		{ 0x008c, 0x000000 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_dac = {
-	.mthd = 0x0080,
-	.addr = 0x000008,
-	.data = {
-		{ 0x0400, 0x610b58 },
-		{ 0x0404, 0x610bdc },
-		{ 0x0420, 0x610828 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_sor = {
-	.mthd = 0x0040,
-	.addr = 0x000008,
-	.data = {
-		{ 0x0600, 0x610b70 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_pior = {
-	.mthd = 0x0040,
-	.addr = 0x000008,
-	.data = {
-		{ 0x0700, 0x610b80 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_head = {
-	.mthd = 0x0400,
-	.addr = 0x000540,
-	.data = {
-		{ 0x0800, 0x610ad8 },
-		{ 0x0804, 0x610ad0 },
-		{ 0x0808, 0x610a48 },
-		{ 0x080c, 0x610a78 },
-		{ 0x0810, 0x610ac0 },
-		{ 0x0814, 0x610af8 },
-		{ 0x0818, 0x610b00 },
-		{ 0x081c, 0x610ae8 },
-		{ 0x0820, 0x610af0 },
-		{ 0x0824, 0x610b08 },
-		{ 0x0828, 0x610b10 },
-		{ 0x082c, 0x610a68 },
-		{ 0x0830, 0x610a60 },
-		{ 0x0834, 0x000000 },
-		{ 0x0838, 0x610a40 },
-		{ 0x0840, 0x610a24 },
-		{ 0x0844, 0x610a2c },
-		{ 0x0848, 0x610aa8 },
-		{ 0x084c, 0x610ab0 },
-		{ 0x0860, 0x610a84 },
-		{ 0x0864, 0x610a90 },
-		{ 0x0868, 0x610b18 },
-		{ 0x086c, 0x610b20 },
-		{ 0x0870, 0x610ac8 },
-		{ 0x0874, 0x610a38 },
-		{ 0x0880, 0x610a58 },
-		{ 0x0884, 0x610a9c },
-		{ 0x08a0, 0x610a70 },
-		{ 0x08a4, 0x610a50 },
-		{ 0x08a8, 0x610ae0 },
-		{ 0x08c0, 0x610b28 },
-		{ 0x08c4, 0x610b30 },
-		{ 0x08c8, 0x610b40 },
-		{ 0x08d4, 0x610b38 },
-		{ 0x08d8, 0x610b48 },
-		{ 0x08dc, 0x610b50 },
-		{ 0x0900, 0x610a18 },
-		{ 0x0904, 0x610ab8 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_core_mthd_chan = {
-	.name = "Core",
-	.addr = 0x000000,
-	.data = {
-		{ "Global", 1, &nv50_disp_core_mthd_base },
-		{    "DAC", 3, &nv50_disp_core_mthd_dac  },
-		{    "SOR", 2, &nv50_disp_core_mthd_sor  },
-		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
-		{   "HEAD", 2, &nv50_disp_core_mthd_head },
-		{}
-	}
-};
-
-int
-nv50_disp_core_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_disp_core_channel_dma_v0 v0;
-	} *args = data;
-	struct nv50_disp_dmac *mast;
-	int ret;
-
-	nv_ioctl(parent, "create disp core channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create disp core channel dma vers %d "
-				 "pushbuf %08x\n",
-			 args->v0.version, args->v0.pushbuf);
-	} else
-		return ret;
-
-	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
-				     0, sizeof(*mast), (void **)&mast);
-	*pobject = nv_object(mast);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nv50_disp_core_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *mast = (void *)object;
-	int ret;
-
-	ret = nv50_disp_chan_init(&mast->base);
-	if (ret)
-		return ret;
-
-	/* enable error reporting */
-	nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
-
-	/* attempt to unstick channel from some unknown state */
-	if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
-		nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
-	if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
-		nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
-
-	/* initialise channel for dma command submission */
-	nv_wr32(priv, 0x610204, mast->push);
-	nv_wr32(priv, 0x610208, 0x00010000);
-	nv_wr32(priv, 0x61020c, 0x00000000);
-	nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
-	nv_wr32(priv, 0x640000, 0x00000000);
-	nv_wr32(priv, 0x610200, 0x01000013);
-
-	/* wait for it to go inactive */
-	if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
-		nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nv50_disp_core_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *mast = (void *)object;
-
-	/* deactivate channel */
-	nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
-	nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
-	if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
-		nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	/* disable error reporting and completion notifications */
-	nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
-
-	return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_core_ofuncs = {
-	.base.ctor = nv50_disp_core_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nv50_disp_core_init,
-	.base.fini = nv50_disp_core_fini,
-	.base.map  = nv50_disp_chan_map,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 0,
-	.attach = nv50_disp_dmac_object_attach,
-	.detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv50_disp_base_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x0008c4 },
-		{ 0x0088, 0x0008d0 },
-		{ 0x008c, 0x0008dc },
-		{ 0x0090, 0x0008e4 },
-		{ 0x0094, 0x610884 },
-		{ 0x00a0, 0x6108a0 },
-		{ 0x00a4, 0x610878 },
-		{ 0x00c0, 0x61086c },
-		{ 0x00e0, 0x610858 },
-		{ 0x00e4, 0x610860 },
-		{ 0x00e8, 0x6108ac },
-		{ 0x00ec, 0x6108b4 },
-		{ 0x0100, 0x610894 },
-		{ 0x0110, 0x6108bc },
-		{ 0x0114, 0x61088c },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_base_mthd_image = {
-	.mthd = 0x0400,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0800, 0x6108f0 },
-		{ 0x0804, 0x6108fc },
-		{ 0x0808, 0x61090c },
-		{ 0x080c, 0x610914 },
-		{ 0x0810, 0x610904 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_base_mthd_chan = {
-	.name = "Base",
-	.addr = 0x000540,
-	.data = {
-		{ "Global", 1, &nv50_disp_base_mthd_base },
-		{  "Image", 2, &nv50_disp_base_mthd_image },
-		{}
-	}
-};
-
-int
-nv50_disp_base_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_disp_base_channel_dma_v0 v0;
-	} *args = data;
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nv50_disp_dmac *dmac;
-	int ret;
-
-	nv_ioctl(parent, "create disp base channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create disp base channel dma vers %d "
-				 "pushbuf %08x head %d\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.head);
-		if (args->v0.head > priv->head.nr)
-			return -EINVAL;
-	} else
-		return ret;
-
-	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
-				     args->v0.head, sizeof(*dmac),
-				     (void **)&dmac);
-	*pobject = nv_object(dmac);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_base_ofuncs = {
-	.base.ctor = nv50_disp_base_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nv50_disp_dmac_init,
-	.base.fini = nv50_disp_dmac_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 1,
-	.attach = nv50_disp_dmac_object_attach,
-	.detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv50_disp_ovly_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x0009a0 },
-		{ 0x0088, 0x0009c0 },
-		{ 0x008c, 0x0009c8 },
-		{ 0x0090, 0x6109b4 },
-		{ 0x0094, 0x610970 },
-		{ 0x00a0, 0x610998 },
-		{ 0x00a4, 0x610964 },
-		{ 0x00c0, 0x610958 },
-		{ 0x00e0, 0x6109a8 },
-		{ 0x00e4, 0x6109d0 },
-		{ 0x00e8, 0x6109d8 },
-		{ 0x0100, 0x61094c },
-		{ 0x0104, 0x610984 },
-		{ 0x0108, 0x61098c },
-		{ 0x0800, 0x6109f8 },
-		{ 0x0808, 0x610a08 },
-		{ 0x080c, 0x610a10 },
-		{ 0x0810, 0x610a00 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_ovly_mthd_chan = {
-	.name = "Overlay",
-	.addr = 0x000540,
-	.data = {
-		{ "Global", 1, &nv50_disp_ovly_mthd_base },
-		{}
-	}
-};
-
-int
-nv50_disp_ovly_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_disp_overlay_channel_dma_v0 v0;
-	} *args = data;
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nv50_disp_dmac *dmac;
-	int ret;
-
-	nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create disp overlay channel dma vers %d "
-				 "pushbuf %08x head %d\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.head);
-		if (args->v0.head > priv->head.nr)
-			return -EINVAL;
-	} else
-		return ret;
-
-	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
-				     args->v0.head, sizeof(*dmac),
-				     (void **)&dmac);
-	*pobject = nv_object(dmac);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_ovly_ofuncs = {
-	.base.ctor = nv50_disp_ovly_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nv50_disp_dmac_init,
-	.base.fini = nv50_disp_dmac_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 3,
-	.attach = nv50_disp_dmac_object_attach,
-	.detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_pioc_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, int head,
-		       int length, void **pobject)
-{
-	return nv50_disp_chan_create_(parent, engine, oclass, head,
-				      length, pobject);
-}
-
-void
-nv50_disp_pioc_dtor(struct nouveau_object *object)
-{
-	struct nv50_disp_pioc *pioc = (void *)object;
-	nv50_disp_chan_destroy(&pioc->base);
-}
-
-static int
-nv50_disp_pioc_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_pioc *pioc = (void *)object;
-	int chid = pioc->base.chid;
-	int ret;
-
-	ret = nv50_disp_chan_init(&pioc->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
-	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
-		nv_error(pioc, "timeout0: 0x%08x\n",
-			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
-		return -EBUSY;
-	}
-
-	nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
-	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
-		nv_error(pioc, "timeout1: 0x%08x\n",
-			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_pioc *pioc = (void *)object;
-	int chid = pioc->base.chid;
-
-	nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
-	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
-		nv_error(pioc, "timeout: 0x%08x\n",
-			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-int
-nv50_disp_oimm_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_disp_overlay_v0 v0;
-	} *args = data;
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nv50_disp_pioc *pioc;
-	int ret;
-
-	nv_ioctl(parent, "create disp overlay size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create disp overlay vers %d head %d\n",
-			 args->v0.version, args->v0.head);
-		if (args->v0.head > priv->head.nr)
-			return -EINVAL;
-	} else
-		return ret;
-
-	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
-				     sizeof(*pioc), (void **)&pioc);
-	*pobject = nv_object(pioc);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_oimm_ofuncs = {
-	.base.ctor = nv50_disp_oimm_ctor,
-	.base.dtor = nv50_disp_pioc_dtor,
-	.base.init = nv50_disp_pioc_init,
-	.base.fini = nv50_disp_pioc_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 5,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-int
-nv50_disp_curs_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_disp_cursor_v0 v0;
-	} *args = data;
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nv50_disp_pioc *pioc;
-	int ret;
-
-	nv_ioctl(parent, "create disp cursor size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create disp cursor vers %d head %d\n",
-			 args->v0.version, args->v0.head);
-		if (args->v0.head > priv->head.nr)
-			return -EINVAL;
-	} else
-		return ret;
-
-	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
-				     sizeof(*pioc), (void **)&pioc);
-	*pobject = nv_object(pioc);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_curs_ofuncs = {
-	.base.ctor = nv50_disp_curs_ctor,
-	.base.dtor = nv50_disp_pioc_dtor,
-	.base.init = nv50_disp_pioc_init,
-	.base.fini = nv50_disp_pioc_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 7,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-int
-nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
-{
-	const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
-	const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
-	const u32 total  = nv_rd32(priv, 0x610afc + (head * 0x540));
-	union {
-		struct nv04_disp_scanoutpos_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "disp scanoutpos size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
-		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
-		args->v0.hblanke = (blanke & 0x0000ffff);
-		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
-		args->v0.hblanks = (blanks & 0x0000ffff);
-		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
-		args->v0.htotal  = ( total & 0x0000ffff);
-		args->v0.time[0] = ktime_to_ns(ktime_get());
-		args->v0.vline = /* vline read locks hline */
-			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
-		args->v0.time[1] = ktime_to_ns(ktime_get());
-		args->v0.hline =
-			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
-	} else
-		return ret;
-
-	return 0;
-}
-
-int
-nv50_disp_main_mthd(struct nouveau_object *object, u32 mthd,
-		    void *data, u32 size)
-{
-	const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
-	union {
-		struct nv50_disp_mthd_v0 v0;
-		struct nv50_disp_mthd_v1 v1;
-	} *args = data;
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nvkm_output *outp = NULL;
-	struct nvkm_output *temp;
-	u16 type, mask = 0;
-	int head, ret;
-
-	if (mthd != NV50_DISP_MTHD)
-		return -EINVAL;
-
-	nv_ioctl(object, "disp mthd size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
-			 args->v0.version, args->v0.method, args->v0.head);
-		mthd = args->v0.method;
-		head = args->v0.head;
-	} else
-	if (nvif_unpack(args->v1, 1, 1, true)) {
-		nv_ioctl(object, "disp mthd vers %d mthd %02x "
-				 "type %04x mask %04x\n",
-			 args->v1.version, args->v1.method,
-			 args->v1.hasht, args->v1.hashm);
-		mthd = args->v1.method;
-		type = args->v1.hasht;
-		mask = args->v1.hashm;
-		head = ffs((mask >> 8) & 0x0f) - 1;
-	} else
-		return ret;
-
-	if (head < 0 || head >= priv->head.nr)
-		return -ENXIO;
-
-	if (mask) {
-		list_for_each_entry(temp, &priv->base.outp, head) {
-			if ((temp->info.hasht         == type) &&
-			    (temp->info.hashm & mask) == mask) {
-				outp = temp;
-				break;
-			}
-		}
-		if (outp == NULL)
-			return -ENXIO;
-	}
-
-	switch (mthd) {
-	case NV50_DISP_SCANOUTPOS:
-		return impl->head.scanoutpos(object, priv, data, size, head);
-	default:
-		break;
-	}
-
-	switch (mthd * !!outp) {
-	case NV50_DISP_MTHD_V1_DAC_PWR:
-		return priv->dac.power(object, priv, data, size, head, outp);
-	case NV50_DISP_MTHD_V1_DAC_LOAD:
-		return priv->dac.sense(object, priv, data, size, head, outp);
-	case NV50_DISP_MTHD_V1_SOR_PWR:
-		return priv->sor.power(object, priv, data, size, head, outp);
-	case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
-		if (!priv->sor.hda_eld)
-			return -ENODEV;
-		return priv->sor.hda_eld(object, priv, data, size, head, outp);
-	case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
-		if (!priv->sor.hdmi)
-			return -ENODEV;
-		return priv->sor.hdmi(object, priv, data, size, head, outp);
-	case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
-		union {
-			struct nv50_disp_sor_lvds_script_v0 v0;
-		} *args = data;
-		nv_ioctl(object, "disp sor lvds script size %d\n", size);
-		if (nvif_unpack(args->v0, 0, 0, false)) {
-			nv_ioctl(object, "disp sor lvds script "
-					 "vers %d name %04x\n",
-				 args->v0.version, args->v0.script);
-			priv->sor.lvdsconf = args->v0.script;
-			return 0;
-		} else
-			return ret;
-	}
-		break;
-	case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
-		struct nvkm_output_dp *outpdp = (void *)outp;
-		union {
-			struct nv50_disp_sor_dp_pwr_v0 v0;
-		} *args = data;
-		nv_ioctl(object, "disp sor dp pwr size %d\n", size);
-		if (nvif_unpack(args->v0, 0, 0, false)) {
-			nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
-				 args->v0.version, args->v0.state);
-			if (args->v0.state == 0) {
-				nvkm_notify_put(&outpdp->irq);
-				((struct nvkm_output_dp_impl *)nv_oclass(outp))
-					->lnk_pwr(outpdp, 0);
-				atomic_set(&outpdp->lt.done, 0);
-				return 0;
-			} else
-			if (args->v0.state != 0) {
-				nvkm_output_dp_train(&outpdp->base, 0, true);
-				return 0;
-			}
-		} else
-			return ret;
-	}
-		break;
-	case NV50_DISP_MTHD_V1_PIOR_PWR:
-		if (!priv->pior.power)
-			return -ENODEV;
-		return priv->pior.power(object, priv, data, size, head, outp);
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-int
-nv50_disp_main_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nv50_disp_base *base;
-	int ret;
-
-	ret = nouveau_parent_create(parent, engine, oclass, 0,
-				    priv->sclass, 0, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
-				&base->ramht);
-}
-
-void
-nv50_disp_main_dtor(struct nouveau_object *object)
-{
-	struct nv50_disp_base *base = (void *)object;
-	nouveau_ramht_ref(NULL, &base->ramht);
-	nouveau_parent_destroy(&base->base);
-}
-
-static int
-nv50_disp_main_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_base *base = (void *)object;
-	int ret, i;
-	u32 tmp;
-
-	ret = nouveau_parent_init(&base->base);
-	if (ret)
-		return ret;
-
-	/* The below segments of code copying values from one register to
-	 * another appear to inform EVO of the display capabilities or
-	 * something similar.  NFI what the 0x614004 caps are for..
-	 */
-	tmp = nv_rd32(priv, 0x614004);
-	nv_wr32(priv, 0x610184, tmp);
-
-	/* ... CRTC caps */
-	for (i = 0; i < priv->head.nr; i++) {
-		tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
-		nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
-		tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
-		nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
-		tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
-		nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
-		tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
-		nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
-	}
-
-	/* ... DAC caps */
-	for (i = 0; i < priv->dac.nr; i++) {
-		tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
-		nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
-	}
-
-	/* ... SOR caps */
-	for (i = 0; i < priv->sor.nr; i++) {
-		tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
-		nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
-	}
-
-	/* ... PIOR caps */
-	for (i = 0; i < priv->pior.nr; i++) {
-		tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
-		nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
-	}
-
-	/* steal display away from vbios, or something like that */
-	if (nv_rd32(priv, 0x610024) & 0x00000100) {
-		nv_wr32(priv, 0x610024, 0x00000100);
-		nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
-		if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
-			nv_error(priv, "timeout acquiring display\n");
-			return -EBUSY;
-		}
-	}
-
-	/* point at display engine memory area (hash table, objects) */
-	nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
-
-	/* enable supervisor interrupts, disable everything else */
-	nv_wr32(priv, 0x61002c, 0x00000370);
-	nv_wr32(priv, 0x610028, 0x00000000);
-	return 0;
-}
-
-static int
-nv50_disp_main_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_base *base = (void *)object;
-
-	/* disable all interrupts */
-	nv_wr32(priv, 0x610024, 0x00000000);
-	nv_wr32(priv, 0x610020, 0x00000000);
-
-	return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nv50_disp_main_ofuncs = {
-	.ctor = nv50_disp_main_ctor,
-	.dtor = nv50_disp_main_dtor,
-	.init = nv50_disp_main_init,
-	.fini = nv50_disp_main_fini,
-	.mthd = nv50_disp_main_mthd,
-	.ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nv50_disp_main_oclass[] = {
-	{ NV50_DISP, &nv50_disp_main_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nv50_disp_sclass[] = {
-	{ NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
-	{ NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
-	{ NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
-	{ NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
-	{ NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
-	{}
-};
-
-/*******************************************************************************
- * Display context, tracks instmem allocation and prevents more than one
- * client using the display hardware at any time.
- ******************************************************************************/
-
-static int
-nv50_disp_data_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv = (void *)engine;
-	struct nouveau_engctx *ectx;
-	int ret = -EBUSY;
-
-	/* no context needed for channel objects... */
-	if (nv_mclass(parent) != NV_DEVICE) {
-		atomic_inc(&parent->refcount);
-		*pobject = parent;
-		return 1;
-	}
-
-	/* allocate display hardware to client */
-	mutex_lock(&nv_subdev(priv)->mutex);
-	if (list_empty(&nv_engine(priv)->contexts)) {
-		ret = nouveau_engctx_create(parent, engine, oclass, NULL,
-					    0x10000, 0x10000,
-					    NVOBJ_FLAG_HEAP, &ectx);
-		*pobject = nv_object(ectx);
-	}
-	mutex_unlock(&nv_subdev(priv)->mutex);
-	return ret;
-}
-
-struct nouveau_oclass
-nv50_disp_cclass = {
-	.handle = NV_ENGCTX(DISP, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_disp_data_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
-	},
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_mask(disp, 0x61002c, (4 << head), 0);
-}
-
-static void
-nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_mask(disp, 0x61002c, (4 << head), (4 << head));
-}
-
-const struct nvkm_event_func
-nv50_disp_vblank_func = {
-	.ctor = nouveau_disp_vblank_ctor,
-	.init = nv50_disp_vblank_init,
-	.fini = nv50_disp_vblank_fini,
-};
-
-static const struct nouveau_enum
-nv50_disp_intr_error_type[] = {
-	{ 3, "ILLEGAL_MTHD" },
-	{ 4, "INVALID_VALUE" },
-	{ 5, "INVALID_STATE" },
-	{ 7, "INVALID_HANDLE" },
-	{}
-};
-
-static const struct nouveau_enum
-nv50_disp_intr_error_code[] = {
-	{ 0x00, "" },
-	{}
-};
-
-static void
-nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
-{
-	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
-	u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
-	u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
-	u32 code = (addr & 0x00ff0000) >> 16;
-	u32 type = (addr & 0x00007000) >> 12;
-	u32 mthd = (addr & 0x00000ffc);
-	const struct nouveau_enum *ec, *et;
-	char ecunk[6], etunk[6];
-
-	et = nouveau_enum_find(nv50_disp_intr_error_type, type);
-	if (!et)
-		snprintf(etunk, sizeof(etunk), "UNK%02X", type);
-
-	ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
-	if (!ec)
-		snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
-
-	nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
-		 et ? et->name : etunk, ec ? ec->name : ecunk,
-		 chid, mthd, data);
-
-	if (chid == 0) {
-		switch (mthd) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
-					    impl->mthd.core);
-			break;
-		default:
-			break;
-		}
-	} else
-	if (chid <= 2) {
-		switch (mthd) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
-					    impl->mthd.base);
-			break;
-		default:
-			break;
-		}
-	} else
-	if (chid <= 4) {
-		switch (mthd) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
-					    impl->mthd.ovly);
-			break;
-		default:
-			break;
-		}
-	}
-
-	nv_wr32(priv, 0x610020, 0x00010000 << chid);
-	nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
-}
-
-static struct nvkm_output *
-exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
-	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	    struct nvbios_outp *info)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	u16 mask, type;
-
-	if (or < 4) {
-		type = DCB_OUTPUT_ANALOG;
-		mask = 0;
-	} else
-	if (or < 8) {
-		switch (ctrl & 0x00000f00) {
-		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
-		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
-		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
-		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
-		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
-		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
-		default:
-			nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
-			return NULL;
-		}
-		or  -= 4;
-	} else {
-		or   = or - 8;
-		type = 0x0010;
-		mask = 0;
-		switch (ctrl & 0x00000f00) {
-		case 0x00000000: type |= priv->pior.type[or]; break;
-		default:
-			nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
-			return NULL;
-		}
-	}
-
-	mask  = 0x00c0 & (mask << 6);
-	mask |= 0x0001 << or;
-	mask |= 0x0100 << head;
-
-	list_for_each_entry(outp, &priv->base.outp, head) {
-		if ((outp->info.hasht & 0xff) == type &&
-		    (outp->info.hashm & mask) == mask) {
-			*data = nvbios_outp_match(bios, outp->info.hasht,
-							outp->info.hashm,
-						  ver, hdr, cnt, len, info);
-			if (!*data)
-				return NULL;
-			return outp;
-		}
-	}
-
-	return NULL;
-}
-
-static struct nvkm_output *
-exec_script(struct nv50_disp_priv *priv, int head, int id)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	struct nvbios_outp info;
-	u8  ver, hdr, cnt, len;
-	u32 data, ctrl = 0;
-	u32 reg;
-	int i;
-
-	/* DAC */
-	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
-		ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
-
-	/* SOR */
-	if (!(ctrl & (1 << head))) {
-		if (nv_device(priv)->chipset  < 0x90 ||
-		    nv_device(priv)->chipset == 0x92 ||
-		    nv_device(priv)->chipset == 0xa0) {
-			reg = 0x610b74;
-		} else {
-			reg = 0x610798;
-		}
-		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
-			ctrl = nv_rd32(priv, reg + (i * 8));
-		i += 4;
-	}
-
-	/* PIOR */
-	if (!(ctrl & (1 << head))) {
-		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
-			ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
-		i += 8;
-	}
-
-	if (!(ctrl & (1 << head)))
-		return NULL;
-	i--;
-
-	outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
-	if (outp) {
-		struct nvbios_init init = {
-			.subdev = nv_subdev(priv),
-			.bios = bios,
-			.offset = info.script[id],
-			.outp = &outp->info,
-			.crtc = head,
-			.execute = 1,
-		};
-
-		nvbios_exec(&init);
-	}
-
-	return outp;
-}
-
-static struct nvkm_output *
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	struct nvbios_outp info1;
-	struct nvbios_ocfg info2;
-	u8  ver, hdr, cnt, len;
-	u32 data, ctrl = 0;
-	u32 reg;
-	int i;
-
-	/* DAC */
-	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
-		ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
-
-	/* SOR */
-	if (!(ctrl & (1 << head))) {
-		if (nv_device(priv)->chipset  < 0x90 ||
-		    nv_device(priv)->chipset == 0x92 ||
-		    nv_device(priv)->chipset == 0xa0) {
-			reg = 0x610b70;
-		} else {
-			reg = 0x610794;
-		}
-		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
-			ctrl = nv_rd32(priv, reg + (i * 8));
-		i += 4;
-	}
-
-	/* PIOR */
-	if (!(ctrl & (1 << head))) {
-		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
-			ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
-		i += 8;
-	}
-
-	if (!(ctrl & (1 << head)))
-		return NULL;
-	i--;
-
-	outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
-	if (!outp)
-		return NULL;
-
-	if (outp->info.location == 0) {
-		switch (outp->info.type) {
-		case DCB_OUTPUT_TMDS:
-			*conf = (ctrl & 0x00000f00) >> 8;
-			if (pclk >= 165000)
-				*conf |= 0x0100;
-			break;
-		case DCB_OUTPUT_LVDS:
-			*conf = priv->sor.lvdsconf;
-			break;
-		case DCB_OUTPUT_DP:
-			*conf = (ctrl & 0x00000f00) >> 8;
-			break;
-		case DCB_OUTPUT_ANALOG:
-		default:
-			*conf = 0x00ff;
-			break;
-		}
-	} else {
-		*conf = (ctrl & 0x00000f00) >> 8;
-		pclk = pclk / 2;
-	}
-
-	data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
-	if (data && id < 0xff) {
-		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
-		if (data) {
-			struct nvbios_init init = {
-				.subdev = nv_subdev(priv),
-				.bios = bios,
-				.offset = data,
-				.outp = &outp->info,
-				.crtc = head,
-				.execute = 1,
-			};
-
-			nvbios_exec(&init);
-		}
-	}
-
-	return outp;
-}
-
-static void
-nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
-{
-	exec_script(priv, head, 1);
-}
-
-static void
-nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
-{
-	struct nvkm_output *outp = exec_script(priv, head, 2);
-
-	/* the binary driver does this outside of the supervisor handling
-	 * (after the third supervisor from a detach).  we (currently?)
-	 * allow both detach/attach to happen in the same set of
-	 * supervisor interrupts, so it would make sense to execute this
-	 * (full power down?) script after all the detach phases of the
-	 * supervisor handling.  like with training if needed from the
-	 * second supervisor, nvidia doesn't do this, so who knows if it's
-	 * entirely safe, but it does appear to work..
-	 *
-	 * without this script being run, on some configurations i've
-	 * seen, switching from DP to TMDS on a DP connector may result
-	 * in a blank screen (SOR_PWR off/on can restore it)
-	 */
-	if (outp && outp->info.type == DCB_OUTPUT_DP) {
-		struct nvkm_output_dp *outpdp = (void *)outp;
-		struct nvbios_init init = {
-			.subdev = nv_subdev(priv),
-			.bios = nouveau_bios(priv),
-			.outp = &outp->info,
-			.crtc = head,
-			.offset = outpdp->info.script[4],
-			.execute = 1,
-		};
-
-		nvbios_exec(&init);
-		atomic_set(&outpdp->lt.done, 0);
-	}
-}
-
-static void
-nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(priv);
-	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
-	if (pclk)
-		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
-}
-
-static void
-nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
-			  struct dcb_output *outp, u32 pclk)
-{
-	const int link = !(outp->sorconf.link & 1);
-	const int   or = ffs(outp->or) - 1;
-	const u32 soff = (  or * 0x800);
-	const u32 loff = (link * 0x080) + soff;
-	const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
-	const u32 symbol = 100000;
-	const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
-	const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
-	const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
-	u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
-	u32 clksor = nv_rd32(priv, 0x614300 + soff);
-	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
-	int TU, VTUi, VTUf, VTUa;
-	u64 link_data_rate, link_ratio, unk;
-	u32 best_diff = 64 * symbol;
-	u32 link_nr, link_bw, bits;
-	u64 value;
-
-	link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
-	link_nr = hweight32(dpctrl & 0x000f0000);
-
-	/* symbols/hblank - algorithm taken from comments in tegra driver */
-	value = vblanke + vactive - vblanks - 7;
-	value = value * link_bw;
-	do_div(value, pclk);
-	value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
-	nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
-
-	/* symbols/vblank - algorithm taken from comments in tegra driver */
-	value = vblanks - vblanke - 25;
-	value = value * link_bw;
-	do_div(value, pclk);
-	value = value - ((36 / link_nr) + 3) - 1;
-	nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
-
-	/* watermark / activesym */
-	if      ((ctrl & 0xf0000) == 0x60000) bits = 30;
-	else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
-	else                                  bits = 18;
-
-	link_data_rate = (pclk * bits / 8) / link_nr;
-
-	/* calculate ratio of packed data rate to link symbol rate */
-	link_ratio = link_data_rate * symbol;
-	do_div(link_ratio, link_bw);
-
-	for (TU = 64; TU >= 32; TU--) {
-		/* calculate average number of valid symbols in each TU */
-		u32 tu_valid = link_ratio * TU;
-		u32 calc, diff;
-
-		/* find a hw representation for the fraction.. */
-		VTUi = tu_valid / symbol;
-		calc = VTUi * symbol;
-		diff = tu_valid - calc;
-		if (diff) {
-			if (diff >= (symbol / 2)) {
-				VTUf = symbol / (symbol - diff);
-				if (symbol - (VTUf * diff))
-					VTUf++;
-
-				if (VTUf <= 15) {
-					VTUa  = 1;
-					calc += symbol - (symbol / VTUf);
-				} else {
-					VTUa  = 0;
-					VTUf  = 1;
-					calc += symbol;
-				}
-			} else {
-				VTUa  = 0;
-				VTUf  = min((int)(symbol / diff), 15);
-				calc += symbol / VTUf;
-			}
-
-			diff = calc - tu_valid;
-		} else {
-			/* no remainder, but the hw doesn't like the fractional
-			 * part to be zero.  decrement the integer part and
-			 * have the fraction add a whole symbol back
-			 */
-			VTUa = 0;
-			VTUf = 1;
-			VTUi--;
-		}
-
-		if (diff < best_diff) {
-			best_diff = diff;
-			bestTU = TU;
-			bestVTUa = VTUa;
-			bestVTUf = VTUf;
-			bestVTUi = VTUi;
-			if (diff == 0)
-				break;
-		}
-	}
-
-	if (!bestTU) {
-		nv_error(priv, "unable to find suitable dp config\n");
-		return;
-	}
-
-	/* XXX close to vbios numbers, but not right */
-	unk  = (symbol - link_ratio) * bestTU;
-	unk *= link_ratio;
-	do_div(unk, symbol);
-	do_div(unk, symbol);
-	unk += 6;
-
-	nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
-	nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
-						   bestVTUf << 16 |
-						   bestVTUi << 8 | unk);
-}
-
-static void
-nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
-{
-	struct nvkm_output *outp;
-	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
-	u32 hval, hreg = 0x614200 + (head * 0x800);
-	u32 oval, oreg;
-	u32 mask, conf;
-
-	outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
-	if (!outp)
-		return;
-
-	/* we allow both encoder attach and detach operations to occur
-	 * within a single supervisor (ie. modeset) sequence.  the
-	 * encoder detach scripts quite often switch off power to the
-	 * lanes, which requires the link to be re-trained.
-	 *
-	 * this is not generally an issue as the sink "must" (heh)
-	 * signal an irq when it's lost sync so the driver can
-	 * re-train.
-	 *
-	 * however, on some boards, if one does not configure at least
-	 * the gpu side of the link *before* attaching, then various
-	 * things can go horribly wrong (PDISP disappearing from mmio,
-	 * third supervisor never happens, etc).
-	 *
-	 * the solution is simply to retrain here, if necessary.  last
-	 * i checked, the binary driver userspace does not appear to
-	 * trigger this situation (it forces an UPDATE between steps).
-	 */
-	if (outp->info.type == DCB_OUTPUT_DP) {
-		u32 soff = (ffs(outp->info.or) - 1) * 0x08;
-		u32 ctrl, datarate;
-
-		if (outp->info.location == 0) {
-			ctrl = nv_rd32(priv, 0x610794 + soff);
-			soff = 1;
-		} else {
-			ctrl = nv_rd32(priv, 0x610b80 + soff);
-			soff = 2;
-		}
-
-		switch ((ctrl & 0x000f0000) >> 16) {
-		case 6: datarate = pclk * 30; break;
-		case 5: datarate = pclk * 24; break;
-		case 2:
-		default:
-			datarate = pclk * 18;
-			break;
-		}
-
-		if (nvkm_output_dp_train(outp, datarate / soff, true))
-			ERR("link not trained before attach\n");
-	}
-
-	exec_clkcmp(priv, head, 0, pclk, &conf);
-
-	if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
-		oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
-		oval = 0x00000000;
-		hval = 0x00000000;
-		mask = 0xffffffff;
-	} else
-	if (!outp->info.location) {
-		if (outp->info.type == DCB_OUTPUT_DP)
-			nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
-		oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
-		oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
-		hval = 0x00000000;
-		mask = 0x00000707;
-	} else {
-		oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
-		oval = 0x00000001;
-		hval = 0x00000001;
-		mask = 0x00000707;
-	}
-
-	nv_mask(priv, hreg, 0x0000000f, hval);
-	nv_mask(priv, oreg, mask, oval);
-}
-
-/* If programming a TMDS output on a SOR that can also be configured for
- * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
- *
- * It looks like the VBIOS TMDS scripts make an attempt at this, however,
- * the VBIOS scripts on at least one board I have only switch it off on
- * link 0, causing a blank display if the output has previously been
- * programmed for DisplayPort.
- */
-static void
-nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	const int link = !(outp->sorconf.link & 1);
-	const int   or = ffs(outp->or) - 1;
-	const u32 loff = (or * 0x800) + (link * 0x80);
-	const u16 mask = (outp->sorconf.link << 6) | outp->or;
-	struct dcb_output match;
-	u8  ver, hdr;
-
-	if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
-		nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
-}
-
-static void
-nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
-{
-	struct nvkm_output *outp;
-	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
-	u32 conf;
-
-	outp = exec_clkcmp(priv, head, 1, pclk, &conf);
-	if (!outp)
-		return;
-
-	if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
-		nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
-}
-
-void
-nv50_disp_intr_supervisor(struct work_struct *work)
-{
-	struct nv50_disp_priv *priv =
-		container_of(work, struct nv50_disp_priv, supervisor);
-	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
-	u32 super = nv_rd32(priv, 0x610030);
-	int head;
-
-	nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
-
-	if (priv->super & 0x00000010) {
-		nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(super & (0x00000020 << head)))
-				continue;
-			if (!(super & (0x00000080 << head)))
-				continue;
-			nv50_disp_intr_unk10_0(priv, head);
-		}
-	} else
-	if (priv->super & 0x00000020) {
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(super & (0x00000080 << head)))
-				continue;
-			nv50_disp_intr_unk20_0(priv, head);
-		}
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(super & (0x00000200 << head)))
-				continue;
-			nv50_disp_intr_unk20_1(priv, head);
-		}
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(super & (0x00000080 << head)))
-				continue;
-			nv50_disp_intr_unk20_2(priv, head);
-		}
-	} else
-	if (priv->super & 0x00000040) {
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(super & (0x00000080 << head)))
-				continue;
-			nv50_disp_intr_unk40_0(priv, head);
-		}
-	}
-
-	nv_wr32(priv, 0x610030, 0x80000000);
-}
-
-void
-nv50_disp_intr(struct nouveau_subdev *subdev)
-{
-	struct nv50_disp_priv *priv = (void *)subdev;
-	u32 intr0 = nv_rd32(priv, 0x610020);
-	u32 intr1 = nv_rd32(priv, 0x610024);
-
-	while (intr0 & 0x001f0000) {
-		u32 chid = __ffs(intr0 & 0x001f0000) - 16;
-		nv50_disp_intr_error(priv, chid);
-		intr0 &= ~(0x00010000 << chid);
-	}
-
-	while (intr0 & 0x0000001f) {
-		u32 chid = __ffs(intr0 & 0x0000001f);
-		nv50_disp_chan_uevent_send(priv, chid);
-		intr0 &= ~(0x00000001 << chid);
-	}
-
-	if (intr1 & 0x00000004) {
-		nouveau_disp_vblank(&priv->base, 0);
-		nv_wr32(priv, 0x610024, 0x00000004);
-		intr1 &= ~0x00000004;
-	}
-
-	if (intr1 & 0x00000008) {
-		nouveau_disp_vblank(&priv->base, 1);
-		nv_wr32(priv, 0x610024, 0x00000008);
-		intr1 &= ~0x00000008;
-	}
-
-	if (intr1 & 0x00000070) {
-		priv->super = (intr1 & 0x00000070);
-		schedule_work(&priv->supervisor);
-		nv_wr32(priv, 0x610024, priv->super);
-		intr1 &= ~0x00000070;
-	}
-}
-
-static int
-nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nv50_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nv50_disp_intr;
-	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
-	priv->sclass = nv50_disp_sclass;
-	priv->head.nr = 2;
-	priv->dac.nr = 3;
-	priv->sor.nr = 2;
-	priv->pior.nr = 3;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->pior.power = nv50_pior_power;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_disp_outp_sclass[] = {
-	&nv50_pior_dp_impl.base.base,
-	NULL
-};
-
-struct nouveau_oclass *
-nv50_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x50),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nv50_disp_vblank_func,
-	.base.outp =  nv50_disp_outp_sclass,
-	.mthd.core = &nv50_disp_core_mthd_chan,
-	.mthd.base = &nv50_disp_base_mthd_chan,
-	.mthd.ovly = &nv50_disp_ovly_mthd_chan,
-	.mthd.prev = 0x000004,
-	.head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
deleted file mode 100644
index 7f08078..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ /dev/null
@@ -1,252 +0,0 @@
-#ifndef __NV50_DISP_H__
-#define __NV50_DISP_H__
-
-#include <core/parent.h>
-#include <core/namedb.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <core/event.h>
-
-#include <engine/dmaobj.h>
-
-#include "dport.h"
-#include "priv.h"
-#include "outp.h"
-#include "outpdp.h"
-
-#define NV50_DISP_MTHD_ struct nouveau_object *object,                         \
-	struct nv50_disp_priv *priv, void *data, u32 size
-#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
-#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
-
-struct nv50_disp_priv {
-	struct nouveau_disp base;
-	struct nouveau_oclass *sclass;
-
-	struct work_struct supervisor;
-	u32 super;
-
-	struct nvkm_event uevent;
-
-	struct {
-		int nr;
-	} head;
-	struct {
-		int nr;
-		int (*power)(NV50_DISP_MTHD_V1);
-		int (*sense)(NV50_DISP_MTHD_V1);
-	} dac;
-	struct {
-		int nr;
-		int (*power)(NV50_DISP_MTHD_V1);
-		int (*hda_eld)(NV50_DISP_MTHD_V1);
-		int (*hdmi)(NV50_DISP_MTHD_V1);
-		u32 lvdsconf;
-		void (*magic)(struct nvkm_output *);
-	} sor;
-	struct {
-		int nr;
-		int (*power)(NV50_DISP_MTHD_V1);
-		u8 type[3];
-	} pior;
-};
-
-struct nv50_disp_impl {
-	struct nouveau_disp_impl base;
-	struct {
-		const struct nv50_disp_mthd_chan *core;
-		const struct nv50_disp_mthd_chan *base;
-		const struct nv50_disp_mthd_chan *ovly;
-		int prev;
-	} mthd;
-	struct {
-		int (*scanoutpos)(NV50_DISP_MTHD_V0);
-	} head;
-};
-
-int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
-int nv50_disp_main_mthd(struct nouveau_object *, u32, void *, u32);
-
-int nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
-
-int nv50_dac_power(NV50_DISP_MTHD_V1);
-int nv50_dac_sense(NV50_DISP_MTHD_V1);
-
-int nva3_hda_eld(NV50_DISP_MTHD_V1);
-int nvd0_hda_eld(NV50_DISP_MTHD_V1);
-
-int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1);
-
-int nv50_sor_power(NV50_DISP_MTHD_V1);
-
-int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16,
-		           u32, struct dcb_output *);
-int nv94_sor_dp_train_fini(struct nv50_disp_priv *, int, int, int, u16, u16,
-		           u32, struct dcb_output *);
-int nv94_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
-		      struct dcb_output *);
-int nv94_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
-		       struct dcb_output *);
-int nv94_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
-		       struct dcb_output *);
-
-int nvd0_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
-		      struct dcb_output *);
-int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
-		       struct dcb_output *);
-int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
-		       struct dcb_output *);
-
-int nv50_pior_power(NV50_DISP_MTHD_V1);
-
-struct nv50_disp_base {
-	struct nouveau_parent base;
-	struct nouveau_ramht *ramht;
-	u32 chan;
-};
-
-struct nv50_disp_chan_impl {
-	struct nouveau_ofuncs base;
-	int chid;
-	int  (*attach)(struct nouveau_object *, struct nouveau_object *, u32);
-	void (*detach)(struct nouveau_object *, int);
-};
-
-struct nv50_disp_chan {
-	struct nouveau_namedb base;
-	int chid;
-};
-
-int  nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-int  nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
-u32  nv50_disp_chan_rd32(struct nouveau_object *, u64);
-void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
-extern const struct nvkm_event_func nv50_disp_chan_uevent;
-int  nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
-				struct nvkm_notify *);
-void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
-
-extern const struct nvkm_event_func nvd0_disp_chan_uevent;
-
-#define nv50_disp_chan_init(a)                                                 \
-	nouveau_namedb_init(&(a)->base)
-#define nv50_disp_chan_fini(a,b)                                               \
-	nouveau_namedb_fini(&(a)->base, (b))
-
-struct nv50_disp_dmac {
-	struct nv50_disp_chan base;
-	struct nouveau_dmaobj *pushdma;
-	u32 push;
-};
-
-void nv50_disp_dmac_dtor(struct nouveau_object *);
-
-struct nv50_disp_pioc {
-	struct nv50_disp_chan base;
-};
-
-void nv50_disp_pioc_dtor(struct nouveau_object *);
-
-struct nv50_disp_mthd_list {
-	u32 mthd;
-	u32 addr;
-	struct {
-		u32 mthd;
-		u32 addr;
-		const char *name;
-	} data[];
-};
-
-struct nv50_disp_mthd_chan {
-	const char *name;
-	u32 addr;
-	struct {
-		const char *name;
-		int nr;
-		const struct nv50_disp_mthd_list *mthd;
-	} data[];
-};
-
-extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
-int nv50_disp_core_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
-extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
-int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
-extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
-int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
-extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs;
-int nv50_disp_oimm_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
-int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-extern struct nouveau_ofuncs nv50_disp_main_ofuncs;
-int  nv50_disp_main_ctor(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, void *, u32,
-			 struct nouveau_object **);
-void nv50_disp_main_dtor(struct nouveau_object *);
-extern struct nouveau_omthds nv50_disp_main_omthds[];
-extern struct nouveau_oclass nv50_disp_cclass;
-void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
-			 const struct nv50_disp_mthd_chan *);
-void nv50_disp_intr_supervisor(struct work_struct *);
-void nv50_disp_intr(struct nouveau_subdev *);
-extern const struct nvkm_event_func nv50_disp_vblank_func;
-
-extern const struct nv50_disp_mthd_chan nv84_disp_core_mthd_chan;
-extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_dac;
-extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_head;
-extern const struct nv50_disp_mthd_chan nv84_disp_base_mthd_chan;
-extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
-
-extern const struct nv50_disp_mthd_chan nv94_disp_core_mthd_chan;
-
-extern struct nv50_disp_chan_impl nvd0_disp_core_ofuncs;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_base;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_dac;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_sor;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_pior;
-extern struct nv50_disp_chan_impl nvd0_disp_base_ofuncs;
-extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
-extern const struct nv50_disp_mthd_chan nvd0_disp_base_mthd_chan;
-extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
-extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_main_ofuncs;
-extern struct nouveau_oclass nvd0_disp_cclass;
-void nvd0_disp_intr_supervisor(struct work_struct *);
-void nvd0_disp_intr(struct nouveau_subdev *);
-extern const struct nvkm_event_func nvd0_disp_vblank_func;
-
-extern const struct nv50_disp_mthd_chan nve0_disp_core_mthd_chan;
-extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
-
-extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
-extern struct nouveau_oclass *nv50_disp_outp_sclass[];
-
-extern struct nvkm_output_dp_impl nv94_sor_dp_impl;
-int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
-extern struct nouveau_oclass *nv94_disp_outp_sclass[];
-
-extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
-int nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
-extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
-
-void gm204_sor_magic(struct nvkm_output *outp);
-extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
deleted file mode 100644
index 13eff5e..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv84_disp_core_mthd_dac = {
-	.mthd = 0x0080,
-	.addr = 0x000008,
-	.data = {
-		{ 0x0400, 0x610b58 },
-		{ 0x0404, 0x610bdc },
-		{ 0x0420, 0x610bc4 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nv84_disp_core_mthd_head = {
-	.mthd = 0x0400,
-	.addr = 0x000540,
-	.data = {
-		{ 0x0800, 0x610ad8 },
-		{ 0x0804, 0x610ad0 },
-		{ 0x0808, 0x610a48 },
-		{ 0x080c, 0x610a78 },
-		{ 0x0810, 0x610ac0 },
-		{ 0x0814, 0x610af8 },
-		{ 0x0818, 0x610b00 },
-		{ 0x081c, 0x610ae8 },
-		{ 0x0820, 0x610af0 },
-		{ 0x0824, 0x610b08 },
-		{ 0x0828, 0x610b10 },
-		{ 0x082c, 0x610a68 },
-		{ 0x0830, 0x610a60 },
-		{ 0x0834, 0x000000 },
-		{ 0x0838, 0x610a40 },
-		{ 0x0840, 0x610a24 },
-		{ 0x0844, 0x610a2c },
-		{ 0x0848, 0x610aa8 },
-		{ 0x084c, 0x610ab0 },
-		{ 0x085c, 0x610c5c },
-		{ 0x0860, 0x610a84 },
-		{ 0x0864, 0x610a90 },
-		{ 0x0868, 0x610b18 },
-		{ 0x086c, 0x610b20 },
-		{ 0x0870, 0x610ac8 },
-		{ 0x0874, 0x610a38 },
-		{ 0x0878, 0x610c50 },
-		{ 0x0880, 0x610a58 },
-		{ 0x0884, 0x610a9c },
-		{ 0x089c, 0x610c68 },
-		{ 0x08a0, 0x610a70 },
-		{ 0x08a4, 0x610a50 },
-		{ 0x08a8, 0x610ae0 },
-		{ 0x08c0, 0x610b28 },
-		{ 0x08c4, 0x610b30 },
-		{ 0x08c8, 0x610b40 },
-		{ 0x08d4, 0x610b38 },
-		{ 0x08d8, 0x610b48 },
-		{ 0x08dc, 0x610b50 },
-		{ 0x0900, 0x610a18 },
-		{ 0x0904, 0x610ab8 },
-		{ 0x0910, 0x610c70 },
-		{ 0x0914, 0x610c78 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_core_mthd_chan = {
-	.name = "Core",
-	.addr = 0x000000,
-	.data = {
-		{ "Global", 1, &nv50_disp_core_mthd_base },
-		{    "DAC", 3, &nv84_disp_core_mthd_dac  },
-		{    "SOR", 2, &nv50_disp_core_mthd_sor  },
-		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
-		{   "HEAD", 2, &nv84_disp_core_mthd_head },
-		{}
-	}
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv84_disp_base_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x0008c4 },
-		{ 0x0088, 0x0008d0 },
-		{ 0x008c, 0x0008dc },
-		{ 0x0090, 0x0008e4 },
-		{ 0x0094, 0x610884 },
-		{ 0x00a0, 0x6108a0 },
-		{ 0x00a4, 0x610878 },
-		{ 0x00c0, 0x61086c },
-		{ 0x00c4, 0x610800 },
-		{ 0x00c8, 0x61080c },
-		{ 0x00cc, 0x610818 },
-		{ 0x00e0, 0x610858 },
-		{ 0x00e4, 0x610860 },
-		{ 0x00e8, 0x6108ac },
-		{ 0x00ec, 0x6108b4 },
-		{ 0x00fc, 0x610824 },
-		{ 0x0100, 0x610894 },
-		{ 0x0104, 0x61082c },
-		{ 0x0110, 0x6108bc },
-		{ 0x0114, 0x61088c },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_base_mthd_chan = {
-	.name = "Base",
-	.addr = 0x000540,
-	.data = {
-		{ "Global", 1, &nv84_disp_base_mthd_base },
-		{  "Image", 2, &nv50_disp_base_mthd_image },
-		{}
-	}
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv84_disp_ovly_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x6109a0 },
-		{ 0x0088, 0x6109c0 },
-		{ 0x008c, 0x6109c8 },
-		{ 0x0090, 0x6109b4 },
-		{ 0x0094, 0x610970 },
-		{ 0x00a0, 0x610998 },
-		{ 0x00a4, 0x610964 },
-		{ 0x00c0, 0x610958 },
-		{ 0x00e0, 0x6109a8 },
-		{ 0x00e4, 0x6109d0 },
-		{ 0x00e8, 0x6109d8 },
-		{ 0x0100, 0x61094c },
-		{ 0x0104, 0x610984 },
-		{ 0x0108, 0x61098c },
-		{ 0x0800, 0x6109f8 },
-		{ 0x0808, 0x610a08 },
-		{ 0x080c, 0x610a10 },
-		{ 0x0810, 0x610a00 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_ovly_mthd_chan = {
-	.name = "Overlay",
-	.addr = 0x000540,
-	.data = {
-		{ "Global", 1, &nv84_disp_ovly_mthd_base },
-		{}
-	}
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_disp_sclass[] = {
-	{ G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
-	{ G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
-	{ G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
-	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
-	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nv84_disp_main_oclass[] = {
-	{ G82_DISP, &nv50_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nv84_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nv50_disp_intr;
-	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
-	priv->sclass = nv84_disp_sclass;
-	priv->head.nr = 2;
-	priv->dac.nr = 3;
-	priv->sor.nr = 2;
-	priv->pior.nr = 3;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hdmi = nv84_hdmi_ctrl;
-	priv->pior.power = nv50_pior_power;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv84_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x82),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nv50_disp_vblank_func,
-	.base.outp =  nv50_disp_outp_sclass,
-	.mthd.core = &nv84_disp_core_mthd_chan,
-	.mthd.base = &nv84_disp_base_mthd_chan,
-	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
-	.mthd.prev = 0x000004,
-	.head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
deleted file mode 100644
index 2bb7ac5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv94_disp_core_mthd_sor = {
-	.mthd = 0x0040,
-	.addr = 0x000008,
-	.data = {
-		{ 0x0600, 0x610794 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nv94_disp_core_mthd_chan = {
-	.name = "Core",
-	.addr = 0x000000,
-	.data = {
-		{ "Global", 1, &nv50_disp_core_mthd_base },
-		{    "DAC", 3, &nv84_disp_core_mthd_dac  },
-		{    "SOR", 4, &nv94_disp_core_mthd_sor  },
-		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
-		{   "HEAD", 2, &nv84_disp_core_mthd_head },
-		{}
-	}
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv94_disp_sclass[] = {
-	{ GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
-	{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
-	{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
-	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
-	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nv94_disp_main_oclass[] = {
-	{ GT206_DISP, &nv50_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nv94_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nv50_disp_intr;
-	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
-	priv->sclass = nv94_disp_sclass;
-	priv->head.nr = 2;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->pior.nr = 3;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hdmi = nv84_hdmi_ctrl;
-	priv->pior.power = nv50_pior_power;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv94_disp_outp_sclass[] = {
-	&nv50_pior_dp_impl.base.base,
-	&nv94_sor_dp_impl.base.base,
-	NULL
-};
-
-struct nouveau_oclass *
-nv94_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x88),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv94_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nv50_disp_vblank_func,
-	.base.outp =  nv94_disp_outp_sclass,
-	.mthd.core = &nv94_disp_core_mthd_chan,
-	.mthd.base = &nv84_disp_base_mthd_chan,
-	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
-	.mthd.prev = 0x000004,
-	.head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
deleted file mode 100644
index b32456c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nva0_disp_ovly_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x000000 },
-		{ 0x0084, 0x6109a0 },
-		{ 0x0088, 0x6109c0 },
-		{ 0x008c, 0x6109c8 },
-		{ 0x0090, 0x6109b4 },
-		{ 0x0094, 0x610970 },
-		{ 0x00a0, 0x610998 },
-		{ 0x00a4, 0x610964 },
-		{ 0x00b0, 0x610c98 },
-		{ 0x00b4, 0x610ca4 },
-		{ 0x00b8, 0x610cac },
-		{ 0x00c0, 0x610958 },
-		{ 0x00e0, 0x6109a8 },
-		{ 0x00e4, 0x6109d0 },
-		{ 0x00e8, 0x6109d8 },
-		{ 0x0100, 0x61094c },
-		{ 0x0104, 0x610984 },
-		{ 0x0108, 0x61098c },
-		{ 0x0800, 0x6109f8 },
-		{ 0x0808, 0x610a08 },
-		{ 0x080c, 0x610a10 },
-		{ 0x0810, 0x610a00 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nva0_disp_ovly_mthd_chan = {
-	.name = "Overlay",
-	.addr = 0x000540,
-	.data = {
-		{ "Global", 1, &nva0_disp_ovly_mthd_base },
-		{}
-	}
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva0_disp_sclass[] = {
-	{ GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
-	{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
-	{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
-	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
-	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nva0_disp_main_oclass[] = {
-	{ GT200_DISP, &nv50_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nva0_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nv50_disp_intr;
-	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
-	priv->sclass = nva0_disp_sclass;
-	priv->head.nr = 2;
-	priv->dac.nr = 3;
-	priv->sor.nr = 2;
-	priv->pior.nr = 3;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hdmi = nv84_hdmi_ctrl;
-	priv->pior.power = nv50_pior_power;
-	return 0;
-}
-
-struct nouveau_oclass *
-nva0_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x83),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva0_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nv50_disp_vblank_func,
-	.base.outp =  nv50_disp_outp_sclass,
-	.mthd.core = &nv84_disp_core_mthd_chan,
-	.mthd.base = &nv84_disp_base_mthd_chan,
-	.mthd.ovly = &nva0_disp_ovly_mthd_chan,
-	.mthd.prev = 0x000004,
-	.head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
deleted file mode 100644
index 951d79f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_disp_sclass[] = {
-	{ GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
-	{ GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
-	{ GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
-	{ GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
-	{ GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nva3_disp_main_oclass[] = {
-	{ GT214_DISP, &nv50_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
-				  "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nva3_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nv50_disp_intr;
-	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
-	priv->sclass = nva3_disp_sclass;
-	priv->head.nr = 2;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->pior.nr = 3;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nva3_hda_eld;
-	priv->sor.hdmi = nva3_hdmi_ctrl;
-	priv->pior.power = nv50_pior_power;
-	return 0;
-}
-
-struct nouveau_oclass *
-nva3_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x85),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nv50_disp_vblank_func,
-	.base.outp =  nv94_disp_outp_sclass,
-	.mthd.core = &nv94_disp_core_mthd_chan,
-	.mthd.base = &nv84_disp_base_mthd_chan,
-	.mthd.ovly = &nv84_disp_ovly_mthd_chan,
-	.mthd.prev = 0x000004,
-	.head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
deleted file mode 100644
index 181a2d5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <engine/disp.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/pll.h>
-#include <subdev/devinit.h>
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO channel base class
- ******************************************************************************/
-
-static void
-nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
-	nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
-	nv_wr32(priv, 0x61008c, 0x00000001 << index);
-}
-
-static void
-nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
-{
-	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
-	nv_wr32(priv, 0x61008c, 0x00000001 << index);
-	nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
-}
-
-const struct nvkm_event_func
-nvd0_disp_chan_uevent = {
-	.ctor = nv50_disp_chan_uevent_ctor,
-	.init = nvd0_disp_chan_uevent_init,
-	.fini = nvd0_disp_chan_uevent_fini,
-};
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_dmac_object_attach(struct nouveau_object *parent,
-			     struct nouveau_object *object, u32 name)
-{
-	struct nv50_disp_base *base = (void *)parent->parent;
-	struct nv50_disp_chan *chan = (void *)parent;
-	u32 addr = nv_gpuobj(object)->node->offset;
-	u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
-	return nouveau_ramht_insert(base->ramht, chan->chid, name, data);
-}
-
-static void
-nvd0_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
-	struct nv50_disp_base *base = (void *)parent->parent;
-	nouveau_ramht_remove(base->ramht, cookie);
-}
-
-static int
-nvd0_disp_dmac_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *dmac = (void *)object;
-	int chid = dmac->base.chid;
-	int ret;
-
-	ret = nv50_disp_chan_init(&dmac->base);
-	if (ret)
-		return ret;
-
-	/* enable error reporting */
-	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
-	/* initialise channel for dma command submission */
-	nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
-	nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
-	nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
-	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
-	nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
-	nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
-
-	/* wait for it to go inactive */
-	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
-		nv_error(dmac, "init: 0x%08x\n",
-			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *dmac = (void *)object;
-	int chid = dmac->base.chid;
-
-	/* deactivate channel */
-	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
-	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
-	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
-		nv_error(dmac, "fini: 0x%08x\n",
-			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	/* disable error reporting and completion notification */
-	nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
-	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
-	return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x660080 },
-		{ 0x0084, 0x660084 },
-		{ 0x0088, 0x660088 },
-		{ 0x008c, 0x000000 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_dac = {
-	.mthd = 0x0020,
-	.addr = 0x000020,
-	.data = {
-		{ 0x0180, 0x660180 },
-		{ 0x0184, 0x660184 },
-		{ 0x0188, 0x660188 },
-		{ 0x0190, 0x660190 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_sor = {
-	.mthd = 0x0020,
-	.addr = 0x000020,
-	.data = {
-		{ 0x0200, 0x660200 },
-		{ 0x0204, 0x660204 },
-		{ 0x0208, 0x660208 },
-		{ 0x0210, 0x660210 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_pior = {
-	.mthd = 0x0020,
-	.addr = 0x000020,
-	.data = {
-		{ 0x0300, 0x660300 },
-		{ 0x0304, 0x660304 },
-		{ 0x0308, 0x660308 },
-		{ 0x0310, 0x660310 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_head = {
-	.mthd = 0x0300,
-	.addr = 0x000300,
-	.data = {
-		{ 0x0400, 0x660400 },
-		{ 0x0404, 0x660404 },
-		{ 0x0408, 0x660408 },
-		{ 0x040c, 0x66040c },
-		{ 0x0410, 0x660410 },
-		{ 0x0414, 0x660414 },
-		{ 0x0418, 0x660418 },
-		{ 0x041c, 0x66041c },
-		{ 0x0420, 0x660420 },
-		{ 0x0424, 0x660424 },
-		{ 0x0428, 0x660428 },
-		{ 0x042c, 0x66042c },
-		{ 0x0430, 0x660430 },
-		{ 0x0434, 0x660434 },
-		{ 0x0438, 0x660438 },
-		{ 0x0440, 0x660440 },
-		{ 0x0444, 0x660444 },
-		{ 0x0448, 0x660448 },
-		{ 0x044c, 0x66044c },
-		{ 0x0450, 0x660450 },
-		{ 0x0454, 0x660454 },
-		{ 0x0458, 0x660458 },
-		{ 0x045c, 0x66045c },
-		{ 0x0460, 0x660460 },
-		{ 0x0468, 0x660468 },
-		{ 0x046c, 0x66046c },
-		{ 0x0470, 0x660470 },
-		{ 0x0474, 0x660474 },
-		{ 0x0480, 0x660480 },
-		{ 0x0484, 0x660484 },
-		{ 0x048c, 0x66048c },
-		{ 0x0490, 0x660490 },
-		{ 0x0494, 0x660494 },
-		{ 0x0498, 0x660498 },
-		{ 0x04b0, 0x6604b0 },
-		{ 0x04b8, 0x6604b8 },
-		{ 0x04bc, 0x6604bc },
-		{ 0x04c0, 0x6604c0 },
-		{ 0x04c4, 0x6604c4 },
-		{ 0x04c8, 0x6604c8 },
-		{ 0x04d0, 0x6604d0 },
-		{ 0x04d4, 0x6604d4 },
-		{ 0x04e0, 0x6604e0 },
-		{ 0x04e4, 0x6604e4 },
-		{ 0x04e8, 0x6604e8 },
-		{ 0x04ec, 0x6604ec },
-		{ 0x04f0, 0x6604f0 },
-		{ 0x04f4, 0x6604f4 },
-		{ 0x04f8, 0x6604f8 },
-		{ 0x04fc, 0x6604fc },
-		{ 0x0500, 0x660500 },
-		{ 0x0504, 0x660504 },
-		{ 0x0508, 0x660508 },
-		{ 0x050c, 0x66050c },
-		{ 0x0510, 0x660510 },
-		{ 0x0514, 0x660514 },
-		{ 0x0518, 0x660518 },
-		{ 0x051c, 0x66051c },
-		{ 0x052c, 0x66052c },
-		{ 0x0530, 0x660530 },
-		{ 0x054c, 0x66054c },
-		{ 0x0550, 0x660550 },
-		{ 0x0554, 0x660554 },
-		{ 0x0558, 0x660558 },
-		{ 0x055c, 0x66055c },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nvd0_disp_core_mthd_chan = {
-	.name = "Core",
-	.addr = 0x000000,
-	.data = {
-		{ "Global", 1, &nvd0_disp_core_mthd_base },
-		{    "DAC", 3, &nvd0_disp_core_mthd_dac  },
-		{    "SOR", 8, &nvd0_disp_core_mthd_sor  },
-		{   "PIOR", 4, &nvd0_disp_core_mthd_pior },
-		{   "HEAD", 4, &nvd0_disp_core_mthd_head },
-		{}
-	}
-};
-
-static int
-nvd0_disp_core_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *mast = (void *)object;
-	int ret;
-
-	ret = nv50_disp_chan_init(&mast->base);
-	if (ret)
-		return ret;
-
-	/* enable error reporting */
-	nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
-
-	/* initialise channel for dma command submission */
-	nv_wr32(priv, 0x610494, mast->push);
-	nv_wr32(priv, 0x610498, 0x00010000);
-	nv_wr32(priv, 0x61049c, 0x00000001);
-	nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
-	nv_wr32(priv, 0x640000, 0x00000000);
-	nv_wr32(priv, 0x610490, 0x01000013);
-
-	/* wait for it to go inactive */
-	if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
-		nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nvd0_disp_core_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_dmac *mast = (void *)object;
-
-	/* deactivate channel */
-	nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
-	nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
-	if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
-		nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	/* disable error reporting and completion notification */
-	nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
-	nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
-
-	return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nv50_disp_chan_impl
-nvd0_disp_core_ofuncs = {
-	.base.ctor = nv50_disp_core_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nvd0_disp_core_init,
-	.base.fini = nvd0_disp_core_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 0,
-	.attach = nvd0_disp_dmac_object_attach,
-	.detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_base_mthd_base = {
-	.mthd = 0x0000,
-	.addr = 0x000000,
-	.data = {
-		{ 0x0080, 0x661080 },
-		{ 0x0084, 0x661084 },
-		{ 0x0088, 0x661088 },
-		{ 0x008c, 0x66108c },
-		{ 0x0090, 0x661090 },
-		{ 0x0094, 0x661094 },
-		{ 0x00a0, 0x6610a0 },
-		{ 0x00a4, 0x6610a4 },
-		{ 0x00c0, 0x6610c0 },
-		{ 0x00c4, 0x6610c4 },
-		{ 0x00c8, 0x6610c8 },
-		{ 0x00cc, 0x6610cc },
-		{ 0x00e0, 0x6610e0 },
-		{ 0x00e4, 0x6610e4 },
-		{ 0x00e8, 0x6610e8 },
-		{ 0x00ec, 0x6610ec },
-		{ 0x00fc, 0x6610fc },
-		{ 0x0100, 0x661100 },
-		{ 0x0104, 0x661104 },
-		{ 0x0108, 0x661108 },
-		{ 0x010c, 0x66110c },
-		{ 0x0110, 0x661110 },
-		{ 0x0114, 0x661114 },
-		{ 0x0118, 0x661118 },
-		{ 0x011c, 0x66111c },
-		{ 0x0130, 0x661130 },
-		{ 0x0134, 0x661134 },
-		{ 0x0138, 0x661138 },
-		{ 0x013c, 0x66113c },
-		{ 0x0140, 0x661140 },
-		{ 0x0144, 0x661144 },
-		{ 0x0148, 0x661148 },
-		{ 0x014c, 0x66114c },
-		{ 0x0150, 0x661150 },
-		{ 0x0154, 0x661154 },
-		{ 0x0158, 0x661158 },
-		{ 0x015c, 0x66115c },
-		{ 0x0160, 0x661160 },
-		{ 0x0164, 0x661164 },
-		{ 0x0168, 0x661168 },
-		{ 0x016c, 0x66116c },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_base_mthd_image = {
-	.mthd = 0x0400,
-	.addr = 0x000400,
-	.data = {
-		{ 0x0400, 0x661400 },
-		{ 0x0404, 0x661404 },
-		{ 0x0408, 0x661408 },
-		{ 0x040c, 0x66140c },
-		{ 0x0410, 0x661410 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nvd0_disp_base_mthd_chan = {
-	.name = "Base",
-	.addr = 0x001000,
-	.data = {
-		{ "Global", 1, &nvd0_disp_base_mthd_base },
-		{  "Image", 2, &nvd0_disp_base_mthd_image },
-		{}
-	}
-};
-
-struct nv50_disp_chan_impl
-nvd0_disp_base_ofuncs = {
-	.base.ctor = nv50_disp_base_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nvd0_disp_dmac_init,
-	.base.fini = nvd0_disp_dmac_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 1,
-	.attach = nvd0_disp_dmac_object_attach,
-	.detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_ovly_mthd_base = {
-	.mthd = 0x0000,
-	.data = {
-		{ 0x0080, 0x665080 },
-		{ 0x0084, 0x665084 },
-		{ 0x0088, 0x665088 },
-		{ 0x008c, 0x66508c },
-		{ 0x0090, 0x665090 },
-		{ 0x0094, 0x665094 },
-		{ 0x00a0, 0x6650a0 },
-		{ 0x00a4, 0x6650a4 },
-		{ 0x00b0, 0x6650b0 },
-		{ 0x00b4, 0x6650b4 },
-		{ 0x00b8, 0x6650b8 },
-		{ 0x00c0, 0x6650c0 },
-		{ 0x00e0, 0x6650e0 },
-		{ 0x00e4, 0x6650e4 },
-		{ 0x00e8, 0x6650e8 },
-		{ 0x0100, 0x665100 },
-		{ 0x0104, 0x665104 },
-		{ 0x0108, 0x665108 },
-		{ 0x010c, 0x66510c },
-		{ 0x0110, 0x665110 },
-		{ 0x0118, 0x665118 },
-		{ 0x011c, 0x66511c },
-		{ 0x0120, 0x665120 },
-		{ 0x0124, 0x665124 },
-		{ 0x0130, 0x665130 },
-		{ 0x0134, 0x665134 },
-		{ 0x0138, 0x665138 },
-		{ 0x013c, 0x66513c },
-		{ 0x0140, 0x665140 },
-		{ 0x0144, 0x665144 },
-		{ 0x0148, 0x665148 },
-		{ 0x014c, 0x66514c },
-		{ 0x0150, 0x665150 },
-		{ 0x0154, 0x665154 },
-		{ 0x0158, 0x665158 },
-		{ 0x015c, 0x66515c },
-		{ 0x0160, 0x665160 },
-		{ 0x0164, 0x665164 },
-		{ 0x0168, 0x665168 },
-		{ 0x016c, 0x66516c },
-		{ 0x0400, 0x665400 },
-		{ 0x0408, 0x665408 },
-		{ 0x040c, 0x66540c },
-		{ 0x0410, 0x665410 },
-		{}
-	}
-};
-
-static const struct nv50_disp_mthd_chan
-nvd0_disp_ovly_mthd_chan = {
-	.name = "Overlay",
-	.addr = 0x001000,
-	.data = {
-		{ "Global", 1, &nvd0_disp_ovly_mthd_base },
-		{}
-	}
-};
-
-struct nv50_disp_chan_impl
-nvd0_disp_ovly_ofuncs = {
-	.base.ctor = nv50_disp_ovly_ctor,
-	.base.dtor = nv50_disp_dmac_dtor,
-	.base.init = nvd0_disp_dmac_init,
-	.base.fini = nvd0_disp_dmac_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 5,
-	.attach = nvd0_disp_dmac_object_attach,
-	.detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_pioc_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_pioc *pioc = (void *)object;
-	int chid = pioc->base.chid;
-	int ret;
-
-	ret = nv50_disp_chan_init(&pioc->base);
-	if (ret)
-		return ret;
-
-	/* enable error reporting */
-	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
-	/* activate channel */
-	nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
-	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
-		nv_error(pioc, "init: 0x%08x\n",
-			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int
-nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_pioc *pioc = (void *)object;
-	int chid = pioc->base.chid;
-
-	nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
-	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
-		nv_error(pioc, "timeout: 0x%08x\n",
-			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	/* disable error reporting and completion notification */
-	nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
-	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
-	return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-struct nv50_disp_chan_impl
-nvd0_disp_oimm_ofuncs = {
-	.base.ctor = nv50_disp_oimm_ctor,
-	.base.dtor = nv50_disp_pioc_dtor,
-	.base.init = nvd0_disp_pioc_init,
-	.base.fini = nvd0_disp_pioc_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 9,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-struct nv50_disp_chan_impl
-nvd0_disp_curs_ofuncs = {
-	.base.ctor = nv50_disp_curs_ctor,
-	.base.dtor = nv50_disp_pioc_dtor,
-	.base.init = nvd0_disp_pioc_init,
-	.base.fini = nvd0_disp_pioc_fini,
-	.base.ntfy = nv50_disp_chan_ntfy,
-	.base.map  = nv50_disp_chan_map,
-	.base.rd32 = nv50_disp_chan_rd32,
-	.base.wr32 = nv50_disp_chan_wr32,
-	.chid = 13,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-int
-nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
-{
-	const u32 total  = nv_rd32(priv, 0x640414 + (head * 0x300));
-	const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
-	const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
-	union {
-		struct nv04_disp_scanoutpos_v0 v0;
-	} *args = data;
-	int ret;
-
-	nv_ioctl(object, "disp scanoutpos size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
-		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
-		args->v0.hblanke = (blanke & 0x0000ffff);
-		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
-		args->v0.hblanks = (blanks & 0x0000ffff);
-		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
-		args->v0.htotal  = ( total & 0x0000ffff);
-		args->v0.time[0] = ktime_to_ns(ktime_get());
-		args->v0.vline = /* vline read locks hline */
-			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
-		args->v0.time[1] = ktime_to_ns(ktime_get());
-		args->v0.hline =
-			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
-	} else
-		return ret;
-
-	return 0;
-}
-
-static int
-nvd0_disp_main_init(struct nouveau_object *object)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_base *base = (void *)object;
-	int ret, i;
-	u32 tmp;
-
-	ret = nouveau_parent_init(&base->base);
-	if (ret)
-		return ret;
-
-	/* The below segments of code copying values from one register to
-	 * another appear to inform EVO of the display capabilities or
-	 * something similar.
-	 */
-
-	/* ... CRTC caps */
-	for (i = 0; i < priv->head.nr; i++) {
-		tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
-		nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
-		tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
-		nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
-		tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
-		nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
-	}
-
-	/* ... DAC caps */
-	for (i = 0; i < priv->dac.nr; i++) {
-		tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
-		nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
-	}
-
-	/* ... SOR caps */
-	for (i = 0; i < priv->sor.nr; i++) {
-		tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
-		nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
-	}
-
-	/* steal display away from vbios, or something like that */
-	if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
-		nv_wr32(priv, 0x6100ac, 0x00000100);
-		nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
-		if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
-			nv_error(priv, "timeout acquiring display\n");
-			return -EBUSY;
-		}
-	}
-
-	/* point at display engine memory area (hash table, objects) */
-	nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
-
-	/* enable supervisor interrupts, disable everything else */
-	nv_wr32(priv, 0x610090, 0x00000000);
-	nv_wr32(priv, 0x6100a0, 0x00000000);
-	nv_wr32(priv, 0x6100b0, 0x00000307);
-
-	/* disable underflow reporting, preventing an intermittent issue
-	 * on some nve4 boards where the production vbios left this
-	 * setting enabled by default.
-	 *
-	 * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
-	 */
-	for (i = 0; i < priv->head.nr; i++)
-		nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010);
-
-	return 0;
-}
-
-static int
-nvd0_disp_main_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_disp_priv *priv = (void *)object->engine;
-	struct nv50_disp_base *base = (void *)object;
-
-	/* disable all interrupts */
-	nv_wr32(priv, 0x6100b0, 0x00000000);
-
-	return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nvd0_disp_main_ofuncs = {
-	.ctor = nv50_disp_main_ctor,
-	.dtor = nv50_disp_main_dtor,
-	.init = nvd0_disp_main_init,
-	.fini = nvd0_disp_main_fini,
-	.mthd = nv50_disp_main_mthd,
-	.ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nvd0_disp_main_oclass[] = {
-	{ GF110_DISP, &nvd0_disp_main_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nvd0_disp_sclass[] = {
-	{ GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
-	{ GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
-	{ GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
-	{ GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
-	{ GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
-}
-
-static void
-nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
-	struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
-	nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
-}
-
-const struct nvkm_event_func
-nvd0_disp_vblank_func = {
-	.ctor = nouveau_disp_vblank_ctor,
-	.init = nvd0_disp_vblank_init,
-	.fini = nvd0_disp_vblank_fini,
-};
-
-static struct nvkm_output *
-exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
-	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	    struct nvbios_outp *info)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	u16 mask, type;
-
-	if (or < 4) {
-		type = DCB_OUTPUT_ANALOG;
-		mask = 0;
-	} else {
-		or -= 4;
-		switch (ctrl & 0x00000f00) {
-		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
-		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
-		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
-		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
-		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
-		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
-		default:
-			nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
-			return 0x0000;
-		}
-	}
-
-	mask  = 0x00c0 & (mask << 6);
-	mask |= 0x0001 << or;
-	mask |= 0x0100 << head;
-
-	list_for_each_entry(outp, &priv->base.outp, head) {
-		if ((outp->info.hasht & 0xff) == type &&
-		    (outp->info.hashm & mask) == mask) {
-			*data = nvbios_outp_match(bios, outp->info.hasht,
-							outp->info.hashm,
-						  ver, hdr, cnt, len, info);
-			if (!*data)
-				return NULL;
-			return outp;
-		}
-	}
-
-	return NULL;
-}
-
-static struct nvkm_output *
-exec_script(struct nv50_disp_priv *priv, int head, int id)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	struct nvbios_outp info;
-	u8  ver, hdr, cnt, len;
-	u32 data, ctrl = 0;
-	int or;
-
-	for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
-		ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
-		if (ctrl & (1 << head))
-			break;
-	}
-
-	if (or == 8)
-		return NULL;
-
-	outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
-	if (outp) {
-		struct nvbios_init init = {
-			.subdev = nv_subdev(priv),
-			.bios = bios,
-			.offset = info.script[id],
-			.outp = &outp->info,
-			.crtc = head,
-			.execute = 1,
-		};
-
-		nvbios_exec(&init);
-	}
-
-	return outp;
-}
-
-static struct nvkm_output *
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvkm_output *outp;
-	struct nvbios_outp info1;
-	struct nvbios_ocfg info2;
-	u8  ver, hdr, cnt, len;
-	u32 data, ctrl = 0;
-	int or;
-
-	for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
-		ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
-		if (ctrl & (1 << head))
-			break;
-	}
-
-	if (or == 8)
-		return NULL;
-
-	outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
-	if (!outp)
-		return NULL;
-
-	switch (outp->info.type) {
-	case DCB_OUTPUT_TMDS:
-		*conf = (ctrl & 0x00000f00) >> 8;
-		if (pclk >= 165000)
-			*conf |= 0x0100;
-		break;
-	case DCB_OUTPUT_LVDS:
-		*conf = priv->sor.lvdsconf;
-		break;
-	case DCB_OUTPUT_DP:
-		*conf = (ctrl & 0x00000f00) >> 8;
-		break;
-	case DCB_OUTPUT_ANALOG:
-	default:
-		*conf = 0x00ff;
-		break;
-	}
-
-	data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
-	if (data && id < 0xff) {
-		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
-		if (data) {
-			struct nvbios_init init = {
-				.subdev = nv_subdev(priv),
-				.bios = bios,
-				.offset = data,
-				.outp = &outp->info,
-				.crtc = head,
-				.execute = 1,
-			};
-
-			nvbios_exec(&init);
-		}
-	}
-
-	return outp;
-}
-
-static void
-nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
-{
-	exec_script(priv, head, 1);
-}
-
-static void
-nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
-{
-	struct nvkm_output *outp = exec_script(priv, head, 2);
-
-	/* see note in nv50_disp_intr_unk20_0() */
-	if (outp && outp->info.type == DCB_OUTPUT_DP) {
-		struct nvkm_output_dp *outpdp = (void *)outp;
-		struct nvbios_init init = {
-			.subdev = nv_subdev(priv),
-			.bios = nouveau_bios(priv),
-			.outp = &outp->info,
-			.crtc = head,
-			.offset = outpdp->info.script[4],
-			.execute = 1,
-		};
-
-		nvbios_exec(&init);
-		atomic_set(&outpdp->lt.done, 0);
-	}
-}
-
-static void
-nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(priv);
-	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
-	if (pclk)
-		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
-	nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
-}
-
-static void
-nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
-			 struct dcb_output *outp)
-{
-	const int or = ffs(outp->or) - 1;
-	const u32 ctrl = nv_rd32(priv, 0x660200 + (or   * 0x020));
-	const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
-	const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
-	const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
-	const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
-	const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
-	const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
-	const u32 hoff = (head * 0x800);
-	const u32 soff = (  or * 0x800);
-	const u32 loff = (link * 0x080) + soff;
-	const u32 symbol = 100000;
-	const u32 TU = 64;
-	u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
-	u32 clksor = nv_rd32(priv, 0x612300 + soff);
-	u32 datarate, link_nr, link_bw, bits;
-	u64 ratio, value;
-
-	link_nr  = hweight32(dpctrl & 0x000f0000);
-	link_bw  = (clksor & 0x007c0000) >> 18;
-	link_bw *= 27000;
-
-	/* symbols/hblank - algorithm taken from comments in tegra driver */
-	value = vblanke + vactive - vblanks - 7;
-	value = value * link_bw;
-	do_div(value, pclk);
-	value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
-	nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
-
-	/* symbols/vblank - algorithm taken from comments in tegra driver */
-	value = vblanks - vblanke - 25;
-	value = value * link_bw;
-	do_div(value, pclk);
-	value = value - ((36 / link_nr) + 3) - 1;
-	nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
-
-	/* watermark */
-	if      ((conf & 0x3c0) == 0x180) bits = 30;
-	else if ((conf & 0x3c0) == 0x140) bits = 24;
-	else                              bits = 18;
-	datarate = (pclk * bits) / 8;
-
-	ratio  = datarate;
-	ratio *= symbol;
-	do_div(ratio, link_nr * link_bw);
-
-	value  = (symbol - ratio) * TU;
-	value *= ratio;
-	do_div(value, symbol);
-	do_div(value, symbol);
-
-	value += 5;
-	value |= 0x08000000;
-
-	nv_wr32(priv, 0x616610 + hoff, value);
-}
-
-static void
-nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
-{
-	struct nvkm_output *outp;
-	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
-	u32 conf, addr, data;
-
-	outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
-	if (!outp)
-		return;
-
-	/* see note in nv50_disp_intr_unk20_2() */
-	if (outp->info.type == DCB_OUTPUT_DP) {
-		u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
-		switch ((sync & 0x000003c0) >> 6) {
-		case 6: pclk = pclk * 30; break;
-		case 5: pclk = pclk * 24; break;
-		case 2:
-		default:
-			pclk = pclk * 18;
-			break;
-		}
-
-		if (nvkm_output_dp_train(outp, pclk, true))
-			ERR("link not trained before attach\n");
-	} else {
-		if (priv->sor.magic)
-			priv->sor.magic(outp);
-	}
-
-	exec_clkcmp(priv, head, 0, pclk, &conf);
-
-	if (outp->info.type == DCB_OUTPUT_ANALOG) {
-		addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
-		data = 0x00000000;
-	} else {
-		addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
-		data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
-		switch (outp->info.type) {
-		case DCB_OUTPUT_TMDS:
-			nv_mask(priv, addr, 0x007c0000, 0x00280000);
-			break;
-		case DCB_OUTPUT_DP:
-			nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
-			break;
-		default:
-			break;
-		}
-	}
-
-	nv_mask(priv, addr, 0x00000707, data);
-}
-
-static void
-nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
-{
-	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
-	u32 conf;
-
-	exec_clkcmp(priv, head, 1, pclk, &conf);
-}
-
-void
-nvd0_disp_intr_supervisor(struct work_struct *work)
-{
-	struct nv50_disp_priv *priv =
-		container_of(work, struct nv50_disp_priv, supervisor);
-	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
-	u32 mask[4];
-	int head;
-
-	nv_debug(priv, "supervisor %d\n", ffs(priv->super));
-	for (head = 0; head < priv->head.nr; head++) {
-		mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
-		nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
-	}
-
-	if (priv->super & 0x00000001) {
-		nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(mask[head] & 0x00001000))
-				continue;
-			nv_debug(priv, "supervisor 1.0 - head %d\n", head);
-			nvd0_disp_intr_unk1_0(priv, head);
-		}
-	} else
-	if (priv->super & 0x00000002) {
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(mask[head] & 0x00001000))
-				continue;
-			nv_debug(priv, "supervisor 2.0 - head %d\n", head);
-			nvd0_disp_intr_unk2_0(priv, head);
-		}
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(mask[head] & 0x00010000))
-				continue;
-			nv_debug(priv, "supervisor 2.1 - head %d\n", head);
-			nvd0_disp_intr_unk2_1(priv, head);
-		}
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(mask[head] & 0x00001000))
-				continue;
-			nv_debug(priv, "supervisor 2.2 - head %d\n", head);
-			nvd0_disp_intr_unk2_2(priv, head);
-		}
-	} else
-	if (priv->super & 0x00000004) {
-		for (head = 0; head < priv->head.nr; head++) {
-			if (!(mask[head] & 0x00001000))
-				continue;
-			nv_debug(priv, "supervisor 3.0 - head %d\n", head);
-			nvd0_disp_intr_unk4_0(priv, head);
-		}
-	}
-
-	for (head = 0; head < priv->head.nr; head++)
-		nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000);
-	nv_wr32(priv, 0x6101d0, 0x80000000);
-}
-
-static void
-nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
-{
-	const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
-	u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
-	u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
-	u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
-
-	nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
-		       "0x%08x 0x%08x\n",
-		 chid, (mthd & 0x0000ffc), data, mthd, unkn);
-
-	if (chid == 0) {
-		switch (mthd & 0xffc) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
-					    impl->mthd.core);
-			break;
-		default:
-			break;
-		}
-	} else
-	if (chid <= 4) {
-		switch (mthd & 0xffc) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
-					    impl->mthd.base);
-			break;
-		default:
-			break;
-		}
-	} else
-	if (chid <= 8) {
-		switch (mthd & 0xffc) {
-		case 0x0080:
-			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
-					    impl->mthd.ovly);
-			break;
-		default:
-			break;
-		}
-	}
-
-	nv_wr32(priv, 0x61009c, (1 << chid));
-	nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
-}
-
-void
-nvd0_disp_intr(struct nouveau_subdev *subdev)
-{
-	struct nv50_disp_priv *priv = (void *)subdev;
-	u32 intr = nv_rd32(priv, 0x610088);
-	int i;
-
-	if (intr & 0x00000001) {
-		u32 stat = nv_rd32(priv, 0x61008c);
-		while (stat) {
-			int chid = __ffs(stat); stat &= ~(1 << chid);
-			nv50_disp_chan_uevent_send(priv, chid);
-			nv_wr32(priv, 0x61008c, 1 << chid);
-		}
-		intr &= ~0x00000001;
-	}
-
-	if (intr & 0x00000002) {
-		u32 stat = nv_rd32(priv, 0x61009c);
-		int chid = ffs(stat) - 1;
-		if (chid >= 0)
-			nvd0_disp_intr_error(priv, chid);
-		intr &= ~0x00000002;
-	}
-
-	if (intr & 0x00100000) {
-		u32 stat = nv_rd32(priv, 0x6100ac);
-		if (stat & 0x00000007) {
-			priv->super = (stat & 0x00000007);
-			schedule_work(&priv->supervisor);
-			nv_wr32(priv, 0x6100ac, priv->super);
-			stat &= ~0x00000007;
-		}
-
-		if (stat) {
-			nv_info(priv, "unknown intr24 0x%08x\n", stat);
-			nv_wr32(priv, 0x6100ac, stat);
-		}
-
-		intr &= ~0x00100000;
-	}
-
-	for (i = 0; i < priv->head.nr; i++) {
-		u32 mask = 0x01000000 << i;
-		if (mask & intr) {
-			u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
-			if (stat & 0x00000001)
-				nouveau_disp_vblank(&priv->base, i);
-			nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
-			nv_rd32(priv, 0x6100c0 + (i * 0x800));
-		}
-	}
-}
-
-static int
-nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int heads = nv_rd32(parent, 0x022448);
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, heads,
-				  "PDISP", "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nvd0_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nvd0_disp_intr;
-	INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
-	priv->sclass = nvd0_disp_sclass;
-	priv->head.nr = heads;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nvd0_hda_eld;
-	priv->sor.hdmi = nvd0_hdmi_ctrl;
-	return 0;
-}
-
-struct nouveau_oclass *
-nvd0_disp_outp_sclass[] = {
-	&nvd0_sor_dp_impl.base.base,
-	NULL
-};
-
-struct nouveau_oclass *
-nvd0_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x90),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvd0_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nvd0_disp_vblank_func,
-	.base.outp =  nvd0_disp_outp_sclass,
-	.mthd.core = &nvd0_disp_core_mthd_chan,
-	.mthd.base = &nvd0_disp_base_mthd_chan,
-	.mthd.ovly = &nvd0_disp_ovly_mthd_chan,
-	.mthd.prev = -0x020000,
-	.head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
deleted file mode 100644
index 55debec..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nve0_disp_core_mthd_head = {
-	.mthd = 0x0300,
-	.addr = 0x000300,
-	.data = {
-		{ 0x0400, 0x660400 },
-		{ 0x0404, 0x660404 },
-		{ 0x0408, 0x660408 },
-		{ 0x040c, 0x66040c },
-		{ 0x0410, 0x660410 },
-		{ 0x0414, 0x660414 },
-		{ 0x0418, 0x660418 },
-		{ 0x041c, 0x66041c },
-		{ 0x0420, 0x660420 },
-		{ 0x0424, 0x660424 },
-		{ 0x0428, 0x660428 },
-		{ 0x042c, 0x66042c },
-		{ 0x0430, 0x660430 },
-		{ 0x0434, 0x660434 },
-		{ 0x0438, 0x660438 },
-		{ 0x0440, 0x660440 },
-		{ 0x0444, 0x660444 },
-		{ 0x0448, 0x660448 },
-		{ 0x044c, 0x66044c },
-		{ 0x0450, 0x660450 },
-		{ 0x0454, 0x660454 },
-		{ 0x0458, 0x660458 },
-		{ 0x045c, 0x66045c },
-		{ 0x0460, 0x660460 },
-		{ 0x0468, 0x660468 },
-		{ 0x046c, 0x66046c },
-		{ 0x0470, 0x660470 },
-		{ 0x0474, 0x660474 },
-		{ 0x047c, 0x66047c },
-		{ 0x0480, 0x660480 },
-		{ 0x0484, 0x660484 },
-		{ 0x0488, 0x660488 },
-		{ 0x048c, 0x66048c },
-		{ 0x0490, 0x660490 },
-		{ 0x0494, 0x660494 },
-		{ 0x0498, 0x660498 },
-		{ 0x04a0, 0x6604a0 },
-		{ 0x04b0, 0x6604b0 },
-		{ 0x04b8, 0x6604b8 },
-		{ 0x04bc, 0x6604bc },
-		{ 0x04c0, 0x6604c0 },
-		{ 0x04c4, 0x6604c4 },
-		{ 0x04c8, 0x6604c8 },
-		{ 0x04d0, 0x6604d0 },
-		{ 0x04d4, 0x6604d4 },
-		{ 0x04e0, 0x6604e0 },
-		{ 0x04e4, 0x6604e4 },
-		{ 0x04e8, 0x6604e8 },
-		{ 0x04ec, 0x6604ec },
-		{ 0x04f0, 0x6604f0 },
-		{ 0x04f4, 0x6604f4 },
-		{ 0x04f8, 0x6604f8 },
-		{ 0x04fc, 0x6604fc },
-		{ 0x0500, 0x660500 },
-		{ 0x0504, 0x660504 },
-		{ 0x0508, 0x660508 },
-		{ 0x050c, 0x66050c },
-		{ 0x0510, 0x660510 },
-		{ 0x0514, 0x660514 },
-		{ 0x0518, 0x660518 },
-		{ 0x051c, 0x66051c },
-		{ 0x0520, 0x660520 },
-		{ 0x0524, 0x660524 },
-		{ 0x052c, 0x66052c },
-		{ 0x0530, 0x660530 },
-		{ 0x054c, 0x66054c },
-		{ 0x0550, 0x660550 },
-		{ 0x0554, 0x660554 },
-		{ 0x0558, 0x660558 },
-		{ 0x055c, 0x66055c },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nve0_disp_core_mthd_chan = {
-	.name = "Core",
-	.addr = 0x000000,
-	.data = {
-		{ "Global", 1, &nvd0_disp_core_mthd_base },
-		{    "DAC", 3, &nvd0_disp_core_mthd_dac  },
-		{    "SOR", 8, &nvd0_disp_core_mthd_sor  },
-		{   "PIOR", 4, &nvd0_disp_core_mthd_pior },
-		{   "HEAD", 4, &nve0_disp_core_mthd_head },
-		{}
-	}
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nve0_disp_ovly_mthd_base = {
-	.mthd = 0x0000,
-	.data = {
-		{ 0x0080, 0x665080 },
-		{ 0x0084, 0x665084 },
-		{ 0x0088, 0x665088 },
-		{ 0x008c, 0x66508c },
-		{ 0x0090, 0x665090 },
-		{ 0x0094, 0x665094 },
-		{ 0x00a0, 0x6650a0 },
-		{ 0x00a4, 0x6650a4 },
-		{ 0x00b0, 0x6650b0 },
-		{ 0x00b4, 0x6650b4 },
-		{ 0x00b8, 0x6650b8 },
-		{ 0x00c0, 0x6650c0 },
-		{ 0x00c4, 0x6650c4 },
-		{ 0x00e0, 0x6650e0 },
-		{ 0x00e4, 0x6650e4 },
-		{ 0x00e8, 0x6650e8 },
-		{ 0x0100, 0x665100 },
-		{ 0x0104, 0x665104 },
-		{ 0x0108, 0x665108 },
-		{ 0x010c, 0x66510c },
-		{ 0x0110, 0x665110 },
-		{ 0x0118, 0x665118 },
-		{ 0x011c, 0x66511c },
-		{ 0x0120, 0x665120 },
-		{ 0x0124, 0x665124 },
-		{ 0x0130, 0x665130 },
-		{ 0x0134, 0x665134 },
-		{ 0x0138, 0x665138 },
-		{ 0x013c, 0x66513c },
-		{ 0x0140, 0x665140 },
-		{ 0x0144, 0x665144 },
-		{ 0x0148, 0x665148 },
-		{ 0x014c, 0x66514c },
-		{ 0x0150, 0x665150 },
-		{ 0x0154, 0x665154 },
-		{ 0x0158, 0x665158 },
-		{ 0x015c, 0x66515c },
-		{ 0x0160, 0x665160 },
-		{ 0x0164, 0x665164 },
-		{ 0x0168, 0x665168 },
-		{ 0x016c, 0x66516c },
-		{ 0x0400, 0x665400 },
-		{ 0x0404, 0x665404 },
-		{ 0x0408, 0x665408 },
-		{ 0x040c, 0x66540c },
-		{ 0x0410, 0x665410 },
-		{}
-	}
-};
-
-const struct nv50_disp_mthd_chan
-nve0_disp_ovly_mthd_chan = {
-	.name = "Overlay",
-	.addr = 0x001000,
-	.data = {
-		{ "Global", 1, &nve0_disp_ovly_mthd_base },
-		{}
-	}
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_disp_sclass[] = {
-	{ GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
-	{ GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
-	{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
-	{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
-	{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nve0_disp_main_oclass[] = {
-	{ GK104_DISP, &nvd0_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int heads = nv_rd32(parent, 0x022448);
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, heads,
-				  "PDISP", "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nve0_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nvd0_disp_intr;
-	INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
-	priv->sclass = nve0_disp_sclass;
-	priv->head.nr = heads;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nvd0_hda_eld;
-	priv->sor.hdmi = nve0_hdmi_ctrl;
-	return 0;
-}
-
-struct nouveau_oclass *
-nve0_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x91),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nvd0_disp_vblank_func,
-	.base.outp =  nvd0_disp_outp_sclass,
-	.mthd.core = &nve0_disp_core_mthd_chan,
-	.mthd.base = &nvd0_disp_base_mthd_chan,
-	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
-	.mthd.prev = -0x020000,
-	.head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
deleted file mode 100644
index 3e7e2d2..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvf0_disp_sclass[] = {
-	{ GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
-	{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
-	{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
-	{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
-	{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
-	{}
-};
-
-static struct nouveau_oclass
-nvf0_disp_main_oclass[] = {
-	{ GK110_DISP, &nvd0_disp_main_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_disp_priv *priv;
-	int heads = nv_rd32(parent, 0x022448);
-	int ret;
-
-	ret = nouveau_disp_create(parent, engine, oclass, heads,
-				  "PDISP", "display", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->sclass = nvf0_disp_main_oclass;
-	nv_engine(priv)->cclass = &nv50_disp_cclass;
-	nv_subdev(priv)->intr = nvd0_disp_intr;
-	INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
-	priv->sclass = nvf0_disp_sclass;
-	priv->head.nr = heads;
-	priv->dac.nr = 3;
-	priv->sor.nr = 4;
-	priv->dac.power = nv50_dac_power;
-	priv->dac.sense = nv50_dac_sense;
-	priv->sor.power = nv50_sor_power;
-	priv->sor.hda_eld = nvd0_hda_eld;
-	priv->sor.hdmi = nve0_hdmi_ctrl;
-	return 0;
-}
-
-struct nouveau_oclass *
-nvf0_disp_oclass = &(struct nv50_disp_impl) {
-	.base.base.handle = NV_ENGINE(DISP, 0x92),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvf0_disp_ctor,
-		.dtor = _nouveau_disp_dtor,
-		.init = _nouveau_disp_init,
-		.fini = _nouveau_disp_fini,
-	},
-	.base.vblank = &nvd0_disp_vblank_func,
-	.base.outp =  nvd0_disp_outp_sclass,
-	.mthd.core = &nve0_disp_core_mthd_chan,
-	.mthd.base = &nvd0_disp_base_mthd_chan,
-	.mthd.ovly = &nve0_disp_ovly_mthd_chan,
-	.mthd.prev = -0x020000,
-	.head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
deleted file mode 100644
index bbd9b6f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/i2c.h>
-#include <subdev/bios.h>
-#include <subdev/bios/conn.h>
-
-#include "outp.h"
-
-int
-_nvkm_output_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvkm_output *outp = (void *)object;
-	nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
-	return nouveau_object_fini(&outp->base, suspend);
-}
-
-int
-_nvkm_output_init(struct nouveau_object *object)
-{
-	struct nvkm_output *outp = (void *)object;
-	int ret = nouveau_object_init(&outp->base);
-	if (ret == 0)
-		nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
-	return 0;
-}
-
-void
-_nvkm_output_dtor(struct nouveau_object *object)
-{
-	struct nvkm_output *outp = (void *)object;
-	list_del(&outp->head);
-	nouveau_object_ref(NULL, (void *)&outp->conn);
-	nouveau_object_destroy(&outp->base);
-}
-
-int
-nvkm_output_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass,
-		    struct dcb_output *dcbE, int index,
-		    int length, void **pobject)
-{
-	struct nouveau_bios *bios = nouveau_bios(engine);
-	struct nouveau_i2c *i2c = nouveau_i2c(parent);
-	struct nouveau_disp *disp = (void *)engine;
-	struct nvbios_connE connE;
-	struct nvkm_output *outp;
-	u8  ver, hdr;
-	u32 data;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
-	outp = *pobject;
-	if (ret)
-		return ret;
-
-	outp->info = *dcbE;
-	outp->index = index;
-	outp->or = ffs(outp->info.or) - 1;
-
-	DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
-	    dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
-	    dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
-	    dcbE->bus, dcbE->heads);
-
-	if (outp->info.type != DCB_OUTPUT_DP)
-		outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
-	else
-		outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
-	outp->edid = outp->port;
-
-	data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
-	if (!data) {
-		DBG("vbios connector data not found\n");
-		memset(&connE, 0x00, sizeof(connE));
-		connE.type = DCB_CONNECTOR_NONE;
-	}
-
-	ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
-				 &connE, outp->info.connector,
-				 (struct nouveau_object **)&outp->conn);
-	if (ret < 0) {
-		ERR("error %d creating connector, disabling\n", ret);
-		return ret;
-	}
-
-	list_add_tail(&outp->head, &disp->outp);
-	return 0;
-}
-
-int
-_nvkm_output_ctor(struct nouveau_object *parent,
-		  struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *dcbE, u32 index,
-		  struct nouveau_object **pobject)
-{
-	struct nvkm_output *outp;
-	int ret;
-
-	ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
-	*pobject = nv_object(outp);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nvkm_output_oclass = &(struct nvkm_output_impl) {
-	.base = {
-		.handle = 0,
-		.ofuncs = &(struct nouveau_ofuncs) {
-			.ctor = _nvkm_output_ctor,
-			.dtor = _nvkm_output_dtor,
-			.init = _nvkm_output_init,
-			.fini = _nvkm_output_fini,
-		},
-	},
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
deleted file mode 100644
index 187f435..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __NVKM_DISP_OUTP_H__
-#define __NVKM_DISP_OUTP_H__
-
-#include "priv.h"
-
-struct nvkm_output {
-	struct nouveau_object base;
-	struct list_head head;
-
-	struct dcb_output info;
-	int index;
-	int or;
-
-	struct nouveau_i2c_port *port;
-	struct nouveau_i2c_port *edid;
-
-	struct nvkm_connector *conn;
-};
-
-#define nvkm_output_create(p,e,c,b,i,d)                                        \
-	nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_destroy(d) ({                                              \
-	struct nvkm_output *_outp = (d);                                       \
-	_nvkm_output_dtor(nv_object(_outp));                                   \
-})
-#define nvkm_output_init(d) ({                                                 \
-	struct nvkm_output *_outp = (d);                                       \
-	_nvkm_output_init(nv_object(_outp));                                   \
-})
-#define nvkm_output_fini(d,s) ({                                               \
-	struct nvkm_output *_outp = (d);                                       \
-	_nvkm_output_fini(nv_object(_outp), (s));                              \
-})
-
-int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, struct dcb_output *,
-			int, int, void **);
-
-int  _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, void *, u32,
-		       struct nouveau_object **);
-void _nvkm_output_dtor(struct nouveau_object *);
-int  _nvkm_output_init(struct nouveau_object *);
-int  _nvkm_output_fini(struct nouveau_object *, bool);
-
-struct nvkm_output_impl {
-	struct nouveau_oclass base;
-};
-
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-	struct nvkm_output *_outp = (void *)outp;                              \
-	nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index,     \
-	       _outp->info.hasht, _outp->info.hashm, ##a);                     \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
deleted file mode 100644
index 667a907..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/event.h>
-
-#include <subdev/i2c.h>
-
-#include "outpdp.h"
-#include "conn.h"
-#include "dport.h"
-
-int
-nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
-{
-	struct nvkm_output_dp *outp = (void *)base;
-	bool retrain = true;
-	u8 link[2], stat[3];
-	u32 linkrate;
-	int ret, i;
-
-	/* check that the link is trained at a high enough rate */
-	ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
-	if (ret) {
-		DBG("failed to read link config, assuming no sink\n");
-		goto done;
-	}
-
-	linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
-	linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
-	datarate = (datarate + 9) / 10; /* -> decakilobits */
-	if (linkrate < datarate) {
-		DBG("link not trained at sufficient rate\n");
-		goto done;
-	}
-
-	/* check that link is still trained */
-	ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
-	if (ret) {
-		DBG("failed to read link status, assuming no sink\n");
-		goto done;
-	}
-
-	if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
-		for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
-			u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
-			if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
-			    !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
-			    !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
-				DBG("lane %d not equalised\n", lane);
-				goto done;
-			}
-		}
-		retrain = false;
-	} else {
-		DBG("no inter-lane alignment\n");
-	}
-
-done:
-	if (retrain || !atomic_read(&outp->lt.done)) {
-		/* no sink, but still need to configure source */
-		if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
-			outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
-				outp->base.info.dpconf.link_bw;
-			outp->dpcd[DPCD_RC02] =
-				outp->base.info.dpconf.link_nr;
-		}
-		atomic_set(&outp->lt.done, 0);
-		schedule_work(&outp->lt.work);
-	} else {
-		nvkm_notify_get(&outp->irq);
-	}
-
-	if (wait) {
-		if (!wait_event_timeout(outp->lt.wait,
-					atomic_read(&outp->lt.done),
-					msecs_to_jiffies(2000)))
-			ret = -ETIMEDOUT;
-	}
-
-	return ret;
-}
-
-static void
-nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
-{
-	struct nouveau_i2c_port *port = outp->base.edid;
-	if (present) {
-		if (!outp->present) {
-			nouveau_i2c(port)->acquire_pad(port, 0);
-			DBG("aux power -> always\n");
-			outp->present = true;
-		}
-		nvkm_output_dp_train(&outp->base, 0, true);
-	} else {
-		if (outp->present) {
-			nouveau_i2c(port)->release_pad(port);
-			DBG("aux power -> demand\n");
-			outp->present = false;
-		}
-		atomic_set(&outp->lt.done, 0);
-	}
-}
-
-static void
-nvkm_output_dp_detect(struct nvkm_output_dp *outp)
-{
-	struct nouveau_i2c_port *port = outp->base.edid;
-	int ret = nouveau_i2c(port)->acquire_pad(port, 0);
-	if (ret == 0) {
-		ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
-			       outp->dpcd, sizeof(outp->dpcd));
-		nvkm_output_dp_enable(outp, ret == 0);
-		nouveau_i2c(port)->release_pad(port);
-	}
-}
-
-static int
-nvkm_output_dp_hpd(struct nvkm_notify *notify)
-{
-	struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
-	struct nvkm_output_dp *outp;
-	struct nouveau_disp *disp = nouveau_disp(conn);
-	const struct nvkm_i2c_ntfy_rep *line = notify->data;
-	struct nvif_notify_conn_rep_v0 rep = {};
-
-	list_for_each_entry(outp, &disp->outp, base.head) {
-		if (outp->base.conn == conn &&
-		    outp->info.type == DCB_OUTPUT_DP) {
-			DBG("HPD: %d\n", line->mask);
-			nvkm_output_dp_detect(outp);
-
-			if (line->mask & NVKM_I2C_UNPLUG)
-				rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
-			if (line->mask & NVKM_I2C_PLUG)
-				rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
-
-			nvkm_event_send(&disp->hpd, rep.mask, conn->index,
-					&rep, sizeof(rep));
-			return NVKM_NOTIFY_KEEP;
-		}
-	}
-
-	WARN_ON(1);
-	return NVKM_NOTIFY_DROP;
-}
-
-static int
-nvkm_output_dp_irq(struct nvkm_notify *notify)
-{
-	struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
-	struct nouveau_disp *disp = nouveau_disp(outp);
-	const struct nvkm_i2c_ntfy_rep *line = notify->data;
-	struct nvif_notify_conn_rep_v0 rep = {
-		.mask = NVIF_NOTIFY_CONN_V0_IRQ,
-	};
-	int index = outp->base.info.connector;
-
-	DBG("IRQ: %d\n", line->mask);
-	nvkm_output_dp_train(&outp->base, 0, true);
-
-	nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
-	return NVKM_NOTIFY_DROP;
-}
-
-int
-_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvkm_output_dp *outp = (void *)object;
-	nvkm_notify_put(&outp->irq);
-	nvkm_output_dp_enable(outp, false);
-	return nvkm_output_fini(&outp->base, suspend);
-}
-
-int
-_nvkm_output_dp_init(struct nouveau_object *object)
-{
-	struct nvkm_output_dp *outp = (void *)object;
-	nvkm_output_dp_detect(outp);
-	return nvkm_output_init(&outp->base);
-}
-
-void
-_nvkm_output_dp_dtor(struct nouveau_object *object)
-{
-	struct nvkm_output_dp *outp = (void *)object;
-	nvkm_notify_fini(&outp->irq);
-	nvkm_output_destroy(&outp->base);
-}
-
-int
-nvkm_output_dp_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass,
-		       struct dcb_output *info, int index,
-		       int length, void **pobject)
-{
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nouveau_i2c *i2c = nouveau_i2c(parent);
-	struct nvkm_output_dp *outp;
-	u8  hdr, cnt, len;
-	u32 data;
-	int ret;
-
-	ret = nvkm_output_create_(parent, engine, oclass, info, index,
-				  length, pobject);
-	outp = *pobject;
-	if (ret)
-		return ret;
-
-	nvkm_notify_fini(&outp->base.conn->hpd);
-
-	/* access to the aux channel is not optional... */
-	if (!outp->base.edid) {
-		ERR("aux channel not found\n");
-		return -ENODEV;
-	}
-
-	/* nor is the bios data for this output... */
-	data = nvbios_dpout_match(bios, outp->base.info.hasht,
-				  outp->base.info.hashm, &outp->version,
-				  &hdr, &cnt, &len, &outp->info);
-	if (!data) {
-		ERR("no bios dp data\n");
-		return -ENODEV;
-	}
-
-	DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
-
-	/* link training */
-	INIT_WORK(&outp->lt.work, nouveau_dp_train);
-	init_waitqueue_head(&outp->lt.wait);
-	atomic_set(&outp->lt.done, 0);
-
-	/* link maintenance */
-	ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
-			       &(struct nvkm_i2c_ntfy_req) {
-				.mask = NVKM_I2C_IRQ,
-				.port = outp->base.edid->index,
-			       },
-			       sizeof(struct nvkm_i2c_ntfy_req),
-			       sizeof(struct nvkm_i2c_ntfy_rep),
-			       &outp->irq);
-	if (ret) {
-		ERR("error monitoring aux irq event: %d\n", ret);
-		return ret;
-	}
-
-	/* hotplug detect, replaces gpio-based mechanism with aux events */
-	ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
-			       &(struct nvkm_i2c_ntfy_req) {
-				.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
-				.port = outp->base.edid->index,
-			       },
-			       sizeof(struct nvkm_i2c_ntfy_req),
-			       sizeof(struct nvkm_i2c_ntfy_rep),
-			       &outp->base.conn->hpd);
-	if (ret) {
-		ERR("error monitoring aux hpd events: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-_nvkm_output_dp_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *info, u32 index,
-		     struct nouveau_object **pobject)
-{
-	struct nvkm_output_dp *outp;
-	int ret;
-
-	ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
-	*pobject = nv_object(outp);
-	if (ret)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
deleted file mode 100644
index 1fac367..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NVKM_DISP_OUTP_DP_H__
-#define __NVKM_DISP_OUTP_DP_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/dp.h>
-
-#include "outp.h"
-
-struct nvkm_output_dp {
-	struct nvkm_output base;
-
-	struct nvbios_dpout info;
-	u8 version;
-
-	struct nvkm_notify irq;
-	bool present;
-	u8 dpcd[16];
-
-	struct {
-		struct work_struct work;
-		wait_queue_head_t wait;
-		atomic_t done;
-	} lt;
-};
-
-#define nvkm_output_dp_create(p,e,c,b,i,d)                                     \
-	nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_dp_destroy(d) ({                                           \
-	struct nvkm_output_dp *_outp = (d);                                    \
-	_nvkm_output_dp_dtor(nv_object(_outp));                                \
-})
-#define nvkm_output_dp_init(d) ({                                              \
-	struct nvkm_output_dp *_outp = (d);                                    \
-	_nvkm_output_dp_init(nv_object(_outp));                                \
-})
-#define nvkm_output_dp_fini(d,s) ({                                            \
-	struct nvkm_output_dp *_outp = (d);                                    \
-	_nvkm_output_dp_fini(nv_object(_outp), (s));                           \
-})
-
-int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *, struct dcb_output *,
-			   int, int, void **);
-
-int  _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, void *, u32,
-			  struct nouveau_object **);
-void _nvkm_output_dp_dtor(struct nouveau_object *);
-int  _nvkm_output_dp_init(struct nouveau_object *);
-int  _nvkm_output_dp_fini(struct nouveau_object *, bool);
-
-struct nvkm_output_dp_impl {
-	struct nvkm_output_impl base;
-	int (*pattern)(struct nvkm_output_dp *, int);
-	int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
-	int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
-	int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
-};
-
-int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
deleted file mode 100644
index d00f89a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-#include <subdev/i2c.h>
-
-#include "nv50.h"
-
-/******************************************************************************
- * TMDS
- *****************************************************************************/
-
-static int
-nv50_pior_tmds_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *info, u32 index,
-		    struct nouveau_object **pobject)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(parent);
-	struct nvkm_output *outp;
-	int ret;
-
-	ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
-	*pobject = nv_object(outp);
-	if (ret)
-		return ret;
-
-	outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
-	return 0;
-}
-
-struct nvkm_output_impl
-nv50_pior_tmds_impl = {
-	.base.handle = DCB_OUTPUT_TMDS | 0x0100,
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_pior_tmds_ctor,
-		.dtor = _nvkm_output_dtor,
-		.init = _nvkm_output_init,
-		.fini = _nvkm_output_fini,
-	},
-};
-
-/******************************************************************************
- * DisplayPort
- *****************************************************************************/
-
-static int
-nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
-	struct nouveau_i2c_port *port = outp->base.edid;
-	if (port && port->func->pattern)
-		return port->func->pattern(port, pattern);
-	return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
-	return 0;
-}
-
-static int
-nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
-	struct nouveau_i2c_port *port = outp->base.edid;
-	if (port && port->func->lnk_ctl)
-		return port->func->lnk_ctl(port, nr, bw, ef);
-	return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
-	struct nouveau_i2c_port *port = outp->base.edid;
-	if (port && port->func->drv_ctl)
-		return port->func->drv_ctl(port, ln, vs, pe);
-	return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_ctor(struct nouveau_object *parent,
-		  struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *info, u32 index,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(parent);
-	struct nvkm_output_dp *outp;
-	int ret;
-
-	ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
-	*pobject = nv_object(outp);
-	if (ret)
-		return ret;
-
-	outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
-					 outp->base.info.extdev));
-	return 0;
-}
-
-struct nvkm_output_dp_impl
-nv50_pior_dp_impl = {
-	.base.base.handle = DCB_OUTPUT_DP | 0x0010,
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_pior_dp_ctor,
-		.dtor = _nvkm_output_dp_dtor,
-		.init = _nvkm_output_dp_init,
-		.fini = _nvkm_output_dp_fini,
-	},
-	.pattern = nv50_pior_dp_pattern,
-	.lnk_pwr = nv50_pior_dp_lnk_pwr,
-	.lnk_ctl = nv50_pior_dp_lnk_ctl,
-	.drv_ctl = nv50_pior_dp_drv_ctl,
-};
-
-/******************************************************************************
- * General PIOR handling
- *****************************************************************************/
-
-int
-nv50_pior_power(NV50_DISP_MTHD_V1)
-{
-	const u32 soff = outp->or * 0x800;
-	union {
-		struct nv50_disp_pior_pwr_v0 v0;
-	} *args = data;
-	u32 ctrl, type;
-	int ret;
-
-	nv_ioctl(object, "disp pior pwr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
-			 args->v0.version, args->v0.state, args->v0.type);
-		if (args->v0.type > 0x0f)
-			return -EINVAL;
-		ctrl = !!args->v0.state;
-		type = args->v0.type;
-	} else
-		return ret;
-
-	nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
-	nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
-	nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
-	priv->pior.type[outp->or] = type;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
deleted file mode 100644
index 6a0511d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVKM_DISP_PRIV_H__
-#define __NVKM_DISP_PRIV_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/conn.h>
-
-#include <engine/disp.h>
-
-struct nouveau_disp_impl {
-	struct nouveau_oclass base;
-	struct nouveau_oclass **outp;
-	struct nouveau_oclass **conn;
-	const struct nvkm_event_func *vblank;
-};
-
-#define nouveau_disp_create(p,e,c,h,i,x,d)                                     \
-	nouveau_disp_create_((p), (e), (c), (h), (i), (x),                     \
-			     sizeof(**d), (void **)d)
-#define nouveau_disp_destroy(d) ({                                             \
-	struct nouveau_disp *disp = (d);                                       \
-	_nouveau_disp_dtor(nv_object(disp));                                   \
-})
-#define nouveau_disp_init(d) ({                                                \
-	struct nouveau_disp *disp = (d);                                       \
-	_nouveau_disp_init(nv_object(disp));                                   \
-})
-#define nouveau_disp_fini(d,s) ({                                              \
-	struct nouveau_disp *disp = (d);                                       \
-	_nouveau_disp_fini(nv_object(disp), (s));                              \
-})
-
-int  nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, int heads,
-			  const char *, const char *, int, void **);
-void _nouveau_disp_dtor(struct nouveau_object *);
-int  _nouveau_disp_init(struct nouveau_object *);
-int  _nouveau_disp_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass *nvkm_output_oclass;
-extern struct nouveau_oclass *nvkm_connector_oclass;
-
-int  nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size,
-			      struct nvkm_notify *);
-void nouveau_disp_vblank(struct nouveau_disp *, int head);
-int  nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c
deleted file mode 100644
index 0b4fad3..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-static inline u32
-gm204_sor_soff(struct nvkm_output_dp *outp)
-{
-	return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-gm204_sor_loff(struct nvkm_output_dp *outp)
-{
-	return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-void
-gm204_sor_magic(struct nvkm_output *outp)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = outp->or * 0x100;
-	const u32 data = outp->or + 1;
-	if (outp->info.sorconf.link & 1)
-		nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
-	if (outp->info.sorconf.link & 2)
-		nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
-}
-
-static inline u32
-gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
-	return lane * 0x08;
-}
-
-static int
-gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = gm204_sor_soff(outp);
-	const u32 data = 0x01010101 * pattern;
-	if (outp->base.info.sorconf.link & 1)
-		nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
-	else
-		nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
-	return 0;
-}
-
-static int
-gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = gm204_sor_soff(outp);
-	const u32 loff = gm204_sor_loff(outp);
-	u32 mask = 0, i;
-
-	for (i = 0; i < nr; i++)
-		mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
-
-	nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
-	nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
-	nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
-	return 0;
-}
-
-static int
-gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	const u32 shift = gm204_sor_dp_lane_map(priv, ln);
-	const u32 loff = gm204_sor_loff(outp);
-	u32 addr, data[4];
-	u8  ver, hdr, cnt, len;
-	struct nvbios_dpout info;
-	struct nvbios_dpcfg ocfg;
-
-	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
-					outp->base.info.hashm,
-				 &ver, &hdr, &cnt, &len, &info);
-	if (!addr)
-		return -ENODEV;
-
-	addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
-				 &ver, &hdr, &cnt, &len, &ocfg);
-	if (!addr)
-		return -EINVAL;
-
-	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
-	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
-	data[2] = nv_rd32(priv, 0x61c130 + loff);
-	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
-		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
-	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
-	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
-	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
-	data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
-	nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
-	return 0;
-}
-
-struct nvkm_output_dp_impl
-gm204_sor_dp_impl = {
-	.base.base.handle = DCB_OUTPUT_DP,
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_output_dp_ctor,
-		.dtor = _nvkm_output_dp_dtor,
-		.init = _nvkm_output_dp_init,
-		.fini = _nvkm_output_dp_fini,
-	},
-	.pattern = gm204_sor_dp_pattern,
-	.lnk_pwr = gm204_sor_dp_lnk_pwr,
-	.lnk_ctl = nvd0_sor_dp_lnk_ctl,
-	.drv_ctl = gm204_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
deleted file mode 100644
index ddf1760..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nv50_sor_power(NV50_DISP_MTHD_V1)
-{
-	union {
-		struct nv50_disp_sor_pwr_v0 v0;
-	} *args = data;
-	const u32 soff = outp->or * 0x800;
-	u32 stat;
-	int ret;
-
-	nv_ioctl(object, "disp sor pwr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "disp sor pwr vers %d state %d\n",
-			 args->v0.version, args->v0.state);
-		stat = !!args->v0.state;
-	} else
-		return ret;
-
-	nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
-	nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
-	nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
-	nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
deleted file mode 100644
index 39f85d6..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-#include "outpdp.h"
-
-static inline u32
-nv94_sor_soff(struct nvkm_output_dp *outp)
-{
-	return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-nv94_sor_loff(struct nvkm_output_dp *outp)
-{
-	return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-static inline u32
-nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
-	static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
-	static const u8 nv94[] = { 16, 8, 0, 24 };
-	if (nv_device(priv)->chipset == 0xaf)
-		return nvaf[lane];
-	return nv94[lane];
-}
-
-static int
-nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 loff = nv94_sor_loff(outp);
-	nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
-	return 0;
-}
-
-int
-nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = nv94_sor_soff(outp);
-	const u32 loff = nv94_sor_loff(outp);
-	u32 mask = 0, i;
-
-	for (i = 0; i < nr; i++)
-		mask |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
-
-	nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
-	nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
-	nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
-	return 0;
-}
-
-static int
-nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = nv94_sor_soff(outp);
-	const u32 loff = nv94_sor_loff(outp);
-	u32 dpctrl = 0x00000000;
-	u32 clksor = 0x00000000;
-
-	dpctrl |= ((1 << nr) - 1) << 16;
-	if (ef)
-		dpctrl |= 0x00004000;
-	if (bw > 0x06)
-		clksor |= 0x00040000;
-
-	nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
-	nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
-	return 0;
-}
-
-static int
-nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	const u32 shift = nv94_sor_dp_lane_map(priv, ln);
-	const u32 loff = nv94_sor_loff(outp);
-	u32 addr, data[3];
-	u8  ver, hdr, cnt, len;
-	struct nvbios_dpout info;
-	struct nvbios_dpcfg ocfg;
-
-	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
-					outp->base.info.hashm,
-				 &ver, &hdr, &cnt, &len, &info);
-	if (!addr)
-		return -ENODEV;
-
-	addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
-				 &ver, &hdr, &cnt, &len, &ocfg);
-	if (!addr)
-		return -EINVAL;
-
-	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
-	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
-	data[2] = nv_rd32(priv, 0x61c130 + loff);
-	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
-		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
-	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
-	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
-	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
-	return 0;
-}
-
-struct nvkm_output_dp_impl
-nv94_sor_dp_impl = {
-	.base.base.handle = DCB_OUTPUT_DP,
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_output_dp_ctor,
-		.dtor = _nvkm_output_dp_dtor,
-		.init = _nvkm_output_dp_init,
-		.fini = _nvkm_output_dp_fini,
-	},
-	.pattern = nv94_sor_dp_pattern,
-	.lnk_pwr = nv94_sor_dp_lnk_pwr,
-	.lnk_ctl = nv94_sor_dp_lnk_ctl,
-	.drv_ctl = nv94_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
deleted file mode 100644
index fdab293..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-static inline u32
-nvd0_sor_soff(struct nvkm_output_dp *outp)
-{
-	return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-nvd0_sor_loff(struct nvkm_output_dp *outp)
-{
-	return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-static inline u32
-nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
-	static const u8 nvd0[] = { 16, 8, 0, 24 };
-	return nvd0[lane];
-}
-
-static int
-nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 loff = nvd0_sor_loff(outp);
-	nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
-	return 0;
-}
-
-int
-nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	const u32 soff = nvd0_sor_soff(outp);
-	const u32 loff = nvd0_sor_loff(outp);
-	u32 dpctrl = 0x00000000;
-	u32 clksor = 0x00000000;
-
-	clksor |= bw << 18;
-	dpctrl |= ((1 << nr) - 1) << 16;
-	if (ef)
-		dpctrl |= 0x00004000;
-
-	nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
-	nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
-	return 0;
-}
-
-static int
-nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
-	struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	const u32 shift = nvd0_sor_dp_lane_map(priv, ln);
-	const u32 loff = nvd0_sor_loff(outp);
-	u32 addr, data[4];
-	u8  ver, hdr, cnt, len;
-	struct nvbios_dpout info;
-	struct nvbios_dpcfg ocfg;
-
-	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
-					outp->base.info.hashm,
-				 &ver, &hdr, &cnt, &len, &info);
-	if (!addr)
-		return -ENODEV;
-
-	addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
-				 &ver, &hdr, &cnt, &len, &ocfg);
-	if (!addr)
-		return -EINVAL;
-
-	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
-	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
-	data[2] = nv_rd32(priv, 0x61c130 + loff);
-	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
-		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
-	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
-	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
-	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
-	data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
-	nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
-	return 0;
-}
-
-struct nvkm_output_dp_impl
-nvd0_sor_dp_impl = {
-	.base.base.handle = DCB_OUTPUT_DP,
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_output_dp_ctor,
-		.dtor = _nvkm_output_dp_dtor,
-		.init = _nvkm_output_dp_init,
-		.fini = _nvkm_output_dp_fini,
-	},
-	.pattern = nvd0_sor_dp_pattern,
-	.lnk_pwr = nv94_sor_dp_lnk_pwr,
-	.lnk_ctl = nvd0_sor_dp_lnk_ctl,
-	.drv_ctl = nvd0_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c
deleted file mode 100644
index 8836c3c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <subdev/vga.h>
-
-u8
-nv_rdport(void *obj, int head, u16 port)
-{
-	struct nouveau_device *device = nv_device(obj);
-
-	if (device->card_type >= NV_50)
-		return nv_rd08(obj, 0x601000 + port);
-
-	if (port == 0x03c0 || port == 0x03c1 ||	/* AR */
-	    port == 0x03c2 || port == 0x03da ||	/* INP0 */
-	    port == 0x03d4 || port == 0x03d5)	/* CR */
-		return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
-
-	if (port == 0x03c2 || port == 0x03cc ||	/* MISC */
-	    port == 0x03c4 || port == 0x03c5 ||	/* SR */
-	    port == 0x03ce || port == 0x03cf) {	/* GR */
-		if (device->card_type < NV_40)
-			head = 0; /* CR44 selects head */
-		return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
-	}
-
-	nv_error(obj, "unknown vga port 0x%04x\n", port);
-	return 0x00;
-}
-
-void
-nv_wrport(void *obj, int head, u16 port, u8 data)
-{
-	struct nouveau_device *device = nv_device(obj);
-
-	if (device->card_type >= NV_50)
-		nv_wr08(obj, 0x601000 + port, data);
-	else
-	if (port == 0x03c0 || port == 0x03c1 ||	/* AR */
-	    port == 0x03c2 || port == 0x03da ||	/* INP0 */
-	    port == 0x03d4 || port == 0x03d5)	/* CR */
-		nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
-	else
-	if (port == 0x03c2 || port == 0x03cc ||	/* MISC */
-	    port == 0x03c4 || port == 0x03c5 ||	/* SR */
-	    port == 0x03ce || port == 0x03cf) {	/* GR */
-		if (device->card_type < NV_40)
-			head = 0; /* CR44 selects head */
-		nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
-	} else
-		nv_error(obj, "unknown vga port 0x%04x\n", port);
-}
-
-u8
-nv_rdvgas(void *obj, int head, u8 index)
-{
-	nv_wrport(obj, head, 0x03c4, index);
-	return nv_rdport(obj, head, 0x03c5);
-}
-
-void
-nv_wrvgas(void *obj, int head, u8 index, u8 value)
-{
-	nv_wrport(obj, head, 0x03c4, index);
-	nv_wrport(obj, head, 0x03c5, value);
-}
-
-u8
-nv_rdvgag(void *obj, int head, u8 index)
-{
-	nv_wrport(obj, head, 0x03ce, index);
-	return nv_rdport(obj, head, 0x03cf);
-}
-
-void
-nv_wrvgag(void *obj, int head, u8 index, u8 value)
-{
-	nv_wrport(obj, head, 0x03ce, index);
-	nv_wrport(obj, head, 0x03cf, value);
-}
-
-u8
-nv_rdvgac(void *obj, int head, u8 index)
-{
-	nv_wrport(obj, head, 0x03d4, index);
-	return nv_rdport(obj, head, 0x03d5);
-}
-
-void
-nv_wrvgac(void *obj, int head, u8 index, u8 value)
-{
-	nv_wrport(obj, head, 0x03d4, index);
-	nv_wrport(obj, head, 0x03d5, value);
-}
-
-u8
-nv_rdvgai(void *obj, int head, u16 port, u8 index)
-{
-	if (port == 0x03c4) return nv_rdvgas(obj, head, index);
-	if (port == 0x03ce) return nv_rdvgag(obj, head, index);
-	if (port == 0x03d4) return nv_rdvgac(obj, head, index);
-	nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
-	return 0x00;
-}
-
-void
-nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
-{
-	if      (port == 0x03c4) nv_wrvgas(obj, head, index, value);
-	else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
-	else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
-	else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
-}
-
-bool
-nv_lockvgac(void *obj, bool lock)
-{
-	struct nouveau_device *dev = nv_device(obj);
-
-	bool locked = !nv_rdvgac(obj, 0, 0x1f);
-	u8 data = lock ? 0x99 : 0x57;
-	if (dev->card_type < NV_50)
-		nv_wrvgac(obj, 0, 0x1f, data);
-	else
-		nv_wrvgac(obj, 0, 0x3f, data);
-	if (dev->chipset == 0x11) {
-		if (!(nv_rd32(obj, 0x001084) & 0x10000000))
-			nv_wrvgac(obj, 1, 0x1f, data);
-	}
-	return locked;
-}
-
-/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
- * it affects only the 8 bit vga io regs, which we access using mmio at
- * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
- * in general, the set value of cr44 does not matter: reg access works as
- * expected and values can be set for the appropriate head by using a 0x2000
- * offset as required
- * however:
- * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
- *    cr44 must be set to 0 or 3 for accessing values on the correct head
- *    through the common 0xc03c* addresses
- * b) in tied mode (4) head B is programmed to the values set on head A, and
- *    access using the head B addresses can have strange results, ergo we leave
- *    tied mode in init once we know to what cr44 should be restored on exit
- *
- * the owner parameter is slightly abused:
- * 0 and 1 are treated as head values and so the set value is (owner * 3)
- * other values are treated as literal values to set
- */
-u8
-nv_rdvgaowner(void *obj)
-{
-	if (nv_device(obj)->card_type < NV_50) {
-		if (nv_device(obj)->chipset == 0x11) {
-			u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
-			if (tied == 0) {
-				u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
-				u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
-				u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
-				u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
-				if (slA && !tvA) return 0x00;
-				if (slB && !tvB) return 0x03;
-				if (slA) return 0x00;
-				if (slB) return 0x03;
-				return 0x00;
-			}
-			return 0x04;
-		}
-
-		return nv_rdvgac(obj, 0, 0x44);
-	}
-
-	nv_error(obj, "rdvgaowner after nv4x\n");
-	return 0x00;
-}
-
-void
-nv_wrvgaowner(void *obj, u8 select)
-{
-	if (nv_device(obj)->card_type < NV_50) {
-		u8 owner = (select == 1) ? 3 : select;
-		if (nv_device(obj)->chipset == 0x11) {
-			/* workaround hw lockup bug */
-			nv_rdvgac(obj, 0, 0x1f);
-			nv_rdvgac(obj, 1, 0x1f);
-		}
-
-		nv_wrvgac(obj, 0, 0x44, owner);
-
-		if (nv_device(obj)->chipset == 0x11) {
-			nv_wrvgac(obj, 0, 0x2e, owner);
-			nv_wrvgac(obj, 0, 0x2e, owner);
-		}
-	} else
-		nv_error(obj, "wrvgaowner after nv4x\n");
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
deleted file mode 100644
index e1500f7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-
-#include "priv.h"
-
-static int
-nvkm_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent,
-		 struct nouveau_gpuobj **pgpuobj)
-{
-	const struct nvkm_dmaeng_impl *impl = (void *)
-		nv_oclass(nv_object(dmaobj)->engine);
-	int ret = 0;
-
-	if (nv_object(dmaobj) == parent) { /* ctor bind */
-		if (nv_mclass(parent->parent) == NV_DEVICE) {
-			/* delayed, or no, binding */
-			return 0;
-		}
-		ret = impl->bind(dmaobj, parent, pgpuobj);
-		if (ret == 0)
-			nouveau_object_ref(NULL, &parent);
-		return ret;
-	}
-
-	return impl->bind(dmaobj, parent, pgpuobj);
-}
-
-int
-nvkm_dmaobj_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void **pdata, u32 *psize,
-		    int length, void **pobject)
-{
-	union {
-		struct nv_dma_v0 v0;
-	} *args = *pdata;
-	struct nouveau_instmem *instmem = nouveau_instmem(parent);
-	struct nouveau_client *client = nouveau_client(parent);
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_dmaobj *dmaobj;
-	void *data = *pdata;
-	u32 size = *psize;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
-	dmaobj = *pobject;
-	if (ret)
-		return ret;
-
-	nv_ioctl(parent, "create dma size %d\n", *psize);
-	if (nvif_unpack(args->v0, 0, 0, true)) {
-		nv_ioctl(parent, "create dma vers %d target %d access %d "
-				 "start %016llx limit %016llx\n",
-			 args->v0.version, args->v0.target, args->v0.access,
-			 args->v0.start, args->v0.limit);
-		dmaobj->target = args->v0.target;
-		dmaobj->access = args->v0.access;
-		dmaobj->start  = args->v0.start;
-		dmaobj->limit  = args->v0.limit;
-	} else
-		return ret;
-
-	*pdata = data;
-	*psize = size;
-
-	if (dmaobj->start > dmaobj->limit)
-		return -EINVAL;
-
-	switch (dmaobj->target) {
-	case NV_DMA_V0_TARGET_VM:
-		dmaobj->target = NV_MEM_TARGET_VM;
-		break;
-	case NV_DMA_V0_TARGET_VRAM:
-		if (!client->super) {
-			if (dmaobj->limit >= pfb->ram->size - instmem->reserved)
-				return -EACCES;
-			if (device->card_type >= NV_50)
-				return -EACCES;
-		}
-		dmaobj->target = NV_MEM_TARGET_VRAM;
-		break;
-	case NV_DMA_V0_TARGET_PCI:
-		if (!client->super)
-			return -EACCES;
-		dmaobj->target = NV_MEM_TARGET_PCI;
-		break;
-	case NV_DMA_V0_TARGET_PCI_US:
-	case NV_DMA_V0_TARGET_AGP:
-		if (!client->super)
-			return -EACCES;
-		dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (dmaobj->access) {
-	case NV_DMA_V0_ACCESS_VM:
-		dmaobj->access = NV_MEM_ACCESS_VM;
-		break;
-	case NV_DMA_V0_ACCESS_RD:
-		dmaobj->access = NV_MEM_ACCESS_RO;
-		break;
-	case NV_DMA_V0_ACCESS_WR:
-		dmaobj->access = NV_MEM_ACCESS_WO;
-		break;
-	case NV_DMA_V0_ACCESS_RDWR:
-		dmaobj->access = NV_MEM_ACCESS_RW;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-int
-_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	const struct nvkm_dmaeng_impl *impl = (void *)oclass;
-	struct nouveau_dmaeng *dmaeng;
-	int ret;
-
-	ret = nouveau_engine_create(parent, engine, oclass, true, "DMAOBJ",
-				    "dmaobj", &dmaeng);
-	*pobject = nv_object(dmaeng);
-	if (ret)
-		return ret;
-
-	nv_engine(dmaeng)->sclass = impl->sclass;
-	dmaeng->bind = nvkm_dmaobj_bind;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
deleted file mode 100644
index 20c9dbf..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm/nv04.h>
-
-#include "priv.h"
-
-struct nv04_dmaobj_priv {
-	struct nouveau_dmaobj base;
-	bool clone;
-	u32 flags0;
-	u32 flags2;
-};
-
-static int
-nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
-		 struct nouveau_object *parent,
-		 struct nouveau_gpuobj **pgpuobj)
-{
-	struct nv04_dmaobj_priv *priv = (void *)dmaobj;
-	struct nouveau_gpuobj *gpuobj;
-	u64 offset = priv->base.start & 0xfffff000;
-	u64 adjust = priv->base.start & 0x00000fff;
-	u32 length = priv->base.limit - priv->base.start;
-	int ret;
-
-	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
-		switch (nv_mclass(parent->parent)) {
-		case NV03_CHANNEL_DMA:
-		case NV10_CHANNEL_DMA:
-		case NV17_CHANNEL_DMA:
-		case NV40_CHANNEL_DMA:
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	if (priv->clone) {
-		struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj);
-		struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
-		if (!dmaobj->start)
-			return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
-		offset  = nv_ro32(pgt, 8 + (offset >> 10));
-		offset &= 0xfffff000;
-	}
-
-	ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
-	*pgpuobj = gpuobj;
-	if (ret == 0) {
-		nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
-		nv_wo32(*pgpuobj, 0x04, length);
-		nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
-		nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
-	}
-
-	return ret;
-}
-
-static int
-nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, void *data, u32 size,
-		 struct nouveau_object **pobject)
-{
-	struct nouveau_dmaeng *dmaeng = (void *)engine;
-	struct nv04_vmmgr_priv *vmm = nv04_vmmgr(engine);
-	struct nv04_dmaobj_priv *priv;
-	int ret;
-
-	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
-	*pobject = nv_object(priv);
-	if (ret || (ret = -ENOSYS, size))
-		return ret;
-
-	if (priv->base.target == NV_MEM_TARGET_VM) {
-		if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass)
-			priv->clone = true;
-		priv->base.target = NV_MEM_TARGET_PCI;
-		priv->base.access = NV_MEM_ACCESS_RW;
-	}
-
-	priv->flags0 = nv_mclass(priv);
-	switch (priv->base.target) {
-	case NV_MEM_TARGET_VRAM:
-		priv->flags0 |= 0x00003000;
-		break;
-	case NV_MEM_TARGET_PCI:
-		priv->flags0 |= 0x00023000;
-		break;
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		priv->flags0 |= 0x00033000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (priv->base.access) {
-	case NV_MEM_ACCESS_RO:
-		priv->flags0 |= 0x00004000;
-		break;
-	case NV_MEM_ACCESS_WO:
-		priv->flags0 |= 0x00008000;
-	case NV_MEM_ACCESS_RW:
-		priv->flags2 |= 0x00000002;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nv04_dmaobj_ofuncs = {
-	.ctor =  nv04_dmaobj_ctor,
-	.dtor = _nvkm_dmaobj_dtor,
-	.init = _nvkm_dmaobj_init,
-	.fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nv04_dmaeng_sclass[] = {
-	{ NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs },
-	{ NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs },
-	{ NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs },
-	{}
-};
-
-struct nouveau_oclass *
-nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
-	.base.handle = NV_ENGINE(DMAOBJ, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_dmaeng_ctor,
-		.dtor = _nvkm_dmaeng_dtor,
-		.init = _nvkm_dmaeng_init,
-		.fini = _nvkm_dmaeng_fini,
-	},
-	.sclass = nv04_dmaeng_sclass,
-	.bind = nv04_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
deleted file mode 100644
index a740ddb..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nv50_dmaobj_priv {
-	struct nouveau_dmaobj base;
-	u32 flags0;
-	u32 flags5;
-};
-
-static int
-nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
-		 struct nouveau_object *parent,
-		 struct nouveau_gpuobj **pgpuobj)
-{
-	struct nv50_dmaobj_priv *priv = (void *)dmaobj;
-	int ret;
-
-	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
-		switch (nv_mclass(parent->parent)) {
-		case NV40_CHANNEL_DMA:
-		case NV50_CHANNEL_GPFIFO:
-		case G82_CHANNEL_GPFIFO:
-		case NV50_DISP_CORE_CHANNEL_DMA:
-		case G82_DISP_CORE_CHANNEL_DMA:
-		case GT206_DISP_CORE_CHANNEL_DMA:
-		case GT200_DISP_CORE_CHANNEL_DMA:
-		case GT214_DISP_CORE_CHANNEL_DMA:
-		case NV50_DISP_BASE_CHANNEL_DMA:
-		case G82_DISP_BASE_CHANNEL_DMA:
-		case GT200_DISP_BASE_CHANNEL_DMA:
-		case GT214_DISP_BASE_CHANNEL_DMA:
-		case NV50_DISP_OVERLAY_CHANNEL_DMA:
-		case G82_DISP_OVERLAY_CHANNEL_DMA:
-		case GT200_DISP_OVERLAY_CHANNEL_DMA:
-		case GT214_DISP_OVERLAY_CHANNEL_DMA:
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
-	if (ret == 0) {
-		nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
-		nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
-		nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
-		nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
-					upper_32_bits(priv->base.start));
-		nv_wo32(*pgpuobj, 0x10, 0x00000000);
-		nv_wo32(*pgpuobj, 0x14, priv->flags5);
-	}
-
-	return ret;
-}
-
-static int
-nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, void *data, u32 size,
-		 struct nouveau_object **pobject)
-{
-	struct nouveau_dmaeng *dmaeng = (void *)engine;
-	union {
-		struct nv50_dma_v0 v0;
-	} *args;
-	struct nv50_dmaobj_priv *priv;
-	u32 user, part, comp, kind;
-	int ret;
-
-	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-	args = data;
-
-	nv_ioctl(parent, "create nv50 dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
-				 "comp %d kind %02x\n", args->v0.version,
-			 args->v0.priv, args->v0.part, args->v0.comp,
-			 args->v0.kind);
-		user = args->v0.priv;
-		part = args->v0.part;
-		comp = args->v0.comp;
-		kind = args->v0.kind;
-	} else
-	if (size == 0) {
-		if (priv->base.target != NV_MEM_TARGET_VM) {
-			user = NV50_DMA_V0_PRIV_US;
-			part = NV50_DMA_V0_PART_256;
-			comp = NV50_DMA_V0_COMP_NONE;
-			kind = NV50_DMA_V0_KIND_PITCH;
-		} else {
-			user = NV50_DMA_V0_PRIV_VM;
-			part = NV50_DMA_V0_PART_VM;
-			comp = NV50_DMA_V0_COMP_VM;
-			kind = NV50_DMA_V0_KIND_VM;
-		}
-	} else
-		return ret;
-
-	if (user > 2 || part > 2 || comp > 3 || kind > 0x7f)
-		return -EINVAL;
-	priv->flags0 = (comp << 29) | (kind << 22) | (user << 20);
-	priv->flags5 = (part << 16);
-
-	switch (priv->base.target) {
-	case NV_MEM_TARGET_VM:
-		priv->flags0 |= 0x00000000;
-		break;
-	case NV_MEM_TARGET_VRAM:
-		priv->flags0 |= 0x00010000;
-		break;
-	case NV_MEM_TARGET_PCI:
-		priv->flags0 |= 0x00020000;
-		break;
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		priv->flags0 |= 0x00030000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (priv->base.access) {
-	case NV_MEM_ACCESS_VM:
-		break;
-	case NV_MEM_ACCESS_RO:
-		priv->flags0 |= 0x00040000;
-		break;
-	case NV_MEM_ACCESS_WO:
-	case NV_MEM_ACCESS_RW:
-		priv->flags0 |= 0x00080000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nv50_dmaobj_ofuncs = {
-	.ctor =  nv50_dmaobj_ctor,
-	.dtor = _nvkm_dmaobj_dtor,
-	.init = _nvkm_dmaobj_init,
-	.fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nv50_dmaeng_sclass[] = {
-	{ NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs },
-	{ NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs },
-	{ NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs },
-	{}
-};
-
-struct nouveau_oclass *
-nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
-	.base.handle = NV_ENGINE(DMAOBJ, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_dmaeng_ctor,
-		.dtor = _nvkm_dmaeng_dtor,
-		.init = _nvkm_dmaeng_init,
-		.fini = _nvkm_dmaeng_fini,
-	},
-	.sclass = nv50_dmaeng_sclass,
-	.bind = nv50_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
deleted file mode 100644
index 88ec33b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/device.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nvc0_dmaobj_priv {
-	struct nouveau_dmaobj base;
-	u32 flags0;
-	u32 flags5;
-};
-
-static int
-nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
-		 struct nouveau_object *parent,
-		 struct nouveau_gpuobj **pgpuobj)
-{
-	struct nvc0_dmaobj_priv *priv = (void *)dmaobj;
-	int ret;
-
-	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
-		switch (nv_mclass(parent->parent)) {
-		case GT214_DISP_CORE_CHANNEL_DMA:
-		case GT214_DISP_BASE_CHANNEL_DMA:
-		case GT214_DISP_OVERLAY_CHANNEL_DMA:
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else
-		return 0;
-
-	ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
-	if (ret == 0) {
-		nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
-		nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
-		nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
-		nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
-					upper_32_bits(priv->base.start));
-		nv_wo32(*pgpuobj, 0x10, 0x00000000);
-		nv_wo32(*pgpuobj, 0x14, priv->flags5);
-	}
-
-	return ret;
-}
-
-static int
-nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, void *data, u32 size,
-		 struct nouveau_object **pobject)
-{
-	struct nouveau_dmaeng *dmaeng = (void *)engine;
-	union {
-		struct gf100_dma_v0 v0;
-	} *args;
-	struct nvc0_dmaobj_priv *priv;
-	u32 kind, user, unkn;
-	int ret;
-
-	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-	args = data;
-
-	nv_ioctl(parent, "create gf100 dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n",
-			 args->v0.version, args->v0.priv, args->v0.kind);
-		kind = args->v0.kind;
-		user = args->v0.priv;
-		unkn = 0;
-	} else
-	if (size == 0) {
-		if (priv->base.target != NV_MEM_TARGET_VM) {
-			kind = GF100_DMA_V0_KIND_PITCH;
-			user = GF100_DMA_V0_PRIV_US;
-			unkn = 2;
-		} else {
-			kind = GF100_DMA_V0_KIND_VM;
-			user = GF100_DMA_V0_PRIV_VM;
-			unkn = 0;
-		}
-	} else
-		return ret;
-
-	if (user > 2)
-		return -EINVAL;
-	priv->flags0 |= (kind << 22) | (user << 20);
-	priv->flags5 |= (unkn << 16);
-
-	switch (priv->base.target) {
-	case NV_MEM_TARGET_VM:
-		priv->flags0 |= 0x00000000;
-		break;
-	case NV_MEM_TARGET_VRAM:
-		priv->flags0 |= 0x00010000;
-		break;
-	case NV_MEM_TARGET_PCI:
-		priv->flags0 |= 0x00020000;
-		break;
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		priv->flags0 |= 0x00030000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (priv->base.access) {
-	case NV_MEM_ACCESS_VM:
-		break;
-	case NV_MEM_ACCESS_RO:
-		priv->flags0 |= 0x00040000;
-		break;
-	case NV_MEM_ACCESS_WO:
-	case NV_MEM_ACCESS_RW:
-		priv->flags0 |= 0x00080000;
-		break;
-	}
-
-	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nvc0_dmaobj_ofuncs = {
-	.ctor =  nvc0_dmaobj_ctor,
-	.dtor = _nvkm_dmaobj_dtor,
-	.init = _nvkm_dmaobj_init,
-	.fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nvc0_dmaeng_sclass[] = {
-	{ NV_DMA_FROM_MEMORY, &nvc0_dmaobj_ofuncs },
-	{ NV_DMA_TO_MEMORY, &nvc0_dmaobj_ofuncs },
-	{ NV_DMA_IN_MEMORY, &nvc0_dmaobj_ofuncs },
-	{}
-};
-
-struct nouveau_oclass *
-nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
-	.base.handle = NV_ENGINE(DMAOBJ, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_dmaeng_ctor,
-		.dtor = _nvkm_dmaeng_dtor,
-		.init = _nvkm_dmaeng_init,
-		.fini = _nvkm_dmaeng_fini,
-	},
-	.sclass = nvc0_dmaeng_sclass,
-	.bind = nvc0_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
deleted file mode 100644
index 19f5f65..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/device.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nvd0_dmaobj_priv {
-	struct nouveau_dmaobj base;
-	u32 flags0;
-};
-
-static int
-nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
-		 struct nouveau_object *parent,
-		 struct nouveau_gpuobj **pgpuobj)
-{
-	struct nvd0_dmaobj_priv *priv = (void *)dmaobj;
-	int ret;
-
-	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
-		switch (nv_mclass(parent->parent)) {
-		case GF110_DISP_CORE_CHANNEL_DMA:
-		case GK104_DISP_CORE_CHANNEL_DMA:
-		case GK110_DISP_CORE_CHANNEL_DMA:
-		case GM107_DISP_CORE_CHANNEL_DMA:
-		case GM204_DISP_CORE_CHANNEL_DMA:
-		case GF110_DISP_BASE_CHANNEL_DMA:
-		case GK104_DISP_BASE_CHANNEL_DMA:
-		case GK110_DISP_BASE_CHANNEL_DMA:
-		case GF110_DISP_OVERLAY_CONTROL_DMA:
-		case GK104_DISP_OVERLAY_CONTROL_DMA:
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else
-		return 0;
-
-	ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
-	if (ret == 0) {
-		nv_wo32(*pgpuobj, 0x00, priv->flags0);
-		nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
-		nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
-		nv_wo32(*pgpuobj, 0x0c, 0x00000000);
-		nv_wo32(*pgpuobj, 0x10, 0x00000000);
-		nv_wo32(*pgpuobj, 0x14, 0x00000000);
-	}
-
-	return ret;
-}
-
-static int
-nvd0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, void *data, u32 size,
-		 struct nouveau_object **pobject)
-{
-	struct nouveau_dmaeng *dmaeng = (void *)engine;
-	union {
-		struct gf110_dma_v0 v0;
-	} *args;
-	struct nvd0_dmaobj_priv *priv;
-	u32 kind, page;
-	int ret;
-
-	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-	args = data;
-
-	nv_ioctl(parent, "create gf110 dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n",
-			 args->v0.version, args->v0.page, args->v0.kind);
-		kind = args->v0.kind;
-		page = args->v0.page;
-	} else
-	if (size == 0) {
-		if (priv->base.target != NV_MEM_TARGET_VM) {
-			kind = GF110_DMA_V0_KIND_PITCH;
-			page = GF110_DMA_V0_PAGE_SP;
-		} else {
-			kind = GF110_DMA_V0_KIND_VM;
-			page = GF110_DMA_V0_PAGE_LP;
-		}
-	} else
-		return ret;
-
-	if (page > 1)
-		return -EINVAL;
-	priv->flags0 = (kind << 20) | (page << 6);
-
-	switch (priv->base.target) {
-	case NV_MEM_TARGET_VRAM:
-		priv->flags0 |= 0x00000009;
-		break;
-	case NV_MEM_TARGET_VM:
-	case NV_MEM_TARGET_PCI:
-	case NV_MEM_TARGET_PCI_NOSNOOP:
-		/* XXX: don't currently know how to construct a real one
-		 *      of these.  we only use them to represent pushbufs
-		 *      on these chipsets, and the classes that use them
-		 *      deal with the target themselves.
-		 */
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nvd0_dmaobj_ofuncs = {
-	.ctor =  nvd0_dmaobj_ctor,
-	.dtor = _nvkm_dmaobj_dtor,
-	.init = _nvkm_dmaobj_init,
-	.fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nvd0_dmaeng_sclass[] = {
-	{ NV_DMA_FROM_MEMORY, &nvd0_dmaobj_ofuncs },
-	{ NV_DMA_TO_MEMORY, &nvd0_dmaobj_ofuncs },
-	{ NV_DMA_IN_MEMORY, &nvd0_dmaobj_ofuncs },
-	{}
-};
-
-struct nouveau_oclass *
-nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
-	.base.handle = NV_ENGINE(DMAOBJ, 0xd0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_dmaeng_ctor,
-		.dtor = _nvkm_dmaeng_dtor,
-		.init = _nvkm_dmaeng_init,
-		.fini = _nvkm_dmaeng_fini,
-	},
-	.sclass = nvd0_dmaeng_sclass,
-	.bind = nvd0_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h
deleted file mode 100644
index 36f7438..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVKM_DMAOBJ_PRIV_H__
-#define __NVKM_DMAOBJ_PRIV_H__
-
-#include <engine/dmaobj.h>
-
-#define nvkm_dmaobj_create(p,e,c,pa,sa,d)                                      \
-	nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
-
-int nvkm_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void **, u32 *,
-			int, void **);
-#define _nvkm_dmaobj_dtor nouveau_object_destroy
-#define _nvkm_dmaobj_init nouveau_object_init
-#define _nvkm_dmaobj_fini nouveau_object_fini
-
-int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, void *, u32,
-		      struct nouveau_object **);
-#define _nvkm_dmaeng_dtor _nouveau_engine_dtor
-#define _nvkm_dmaeng_init _nouveau_engine_init
-#define _nvkm_dmaeng_fini _nouveau_engine_fini
-
-struct nvkm_dmaeng_impl {
-	struct nouveau_oclass base;
-	struct nouveau_oclass *sclass;
-	int (*bind)(struct nouveau_dmaobj *, struct nouveau_object *,
-		    struct nouveau_gpuobj **);
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c
deleted file mode 100644
index 2914646..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/falcon.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 <engine/falcon.h>
-#include <subdev/timer.h>
-
-void
-nouveau_falcon_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_falcon *falcon = (void *)subdev;
-	u32 dispatch = nv_ro32(falcon, 0x01c);
-	u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
-
-	if (intr & 0x00000010) {
-		nv_debug(falcon, "ucode halted\n");
-		nv_wo32(falcon, 0x004, 0x00000010);
-		intr &= ~0x00000010;
-	}
-
-	if (intr)  {
-		nv_error(falcon, "unhandled intr 0x%08x\n", intr);
-		nv_wo32(falcon, 0x004, intr);
-	}
-}
-
-u32
-_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_falcon *falcon = (void *)object;
-	return nv_rd32(falcon, falcon->addr + addr);
-}
-
-void
-_nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_falcon *falcon = (void *)object;
-	nv_wr32(falcon, falcon->addr + addr, data);
-}
-
-static void *
-vmemdup(const void *src, size_t len)
-{
-	void *p = vmalloc(len);
-
-	if (p)
-		memcpy(p, src, len);
-	return p;
-}
-
-int
-_nouveau_falcon_init(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nouveau_falcon *falcon = (void *)object;
-	const struct firmware *fw;
-	char name[32] = "internal";
-	int ret, i;
-	u32 caps;
-
-	/* enable engine, and determine its capabilities */
-	ret = nouveau_engine_init(&falcon->base);
-	if (ret)
-		return ret;
-
-	if (device->chipset <  0xa3 ||
-	    device->chipset == 0xaa || device->chipset == 0xac) {
-		falcon->version = 0;
-		falcon->secret  = (falcon->addr == 0x087000) ? 1 : 0;
-	} else {
-		caps = nv_ro32(falcon, 0x12c);
-		falcon->version = (caps & 0x0000000f);
-		falcon->secret  = (caps & 0x00000030) >> 4;
-	}
-
-	caps = nv_ro32(falcon, 0x108);
-	falcon->code.limit = (caps & 0x000001ff) << 8;
-	falcon->data.limit = (caps & 0x0003fe00) >> 1;
-
-	nv_debug(falcon, "falcon version: %d\n", falcon->version);
-	nv_debug(falcon, "secret level: %d\n", falcon->secret);
-	nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
-	nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
-
-	/* wait for 'uc halted' to be signalled before continuing */
-	if (falcon->secret && falcon->version < 4) {
-		if (!falcon->version)
-			nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
-		else
-			nv_wait(falcon, 0x180, 0x80000000, 0);
-		nv_wo32(falcon, 0x004, 0x00000010);
-	}
-
-	/* disable all interrupts */
-	nv_wo32(falcon, 0x014, 0xffffffff);
-
-	/* no default ucode provided by the engine implementation, try and
-	 * locate a "self-bootstrapping" firmware image for the engine
-	 */
-	if (!falcon->code.data) {
-		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
-			 device->chipset, falcon->addr >> 12);
-
-		ret = request_firmware(&fw, name, nv_device_base(device));
-		if (ret == 0) {
-			falcon->code.data = vmemdup(fw->data, fw->size);
-			falcon->code.size = fw->size;
-			falcon->data.data = NULL;
-			falcon->data.size = 0;
-			release_firmware(fw);
-		}
-
-		falcon->external = true;
-	}
-
-	/* next step is to try and load "static code/data segment" firmware
-	 * images for the engine
-	 */
-	if (!falcon->code.data) {
-		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
-			 device->chipset, falcon->addr >> 12);
-
-		ret = request_firmware(&fw, name, nv_device_base(device));
-		if (ret) {
-			nv_error(falcon, "unable to load firmware data\n");
-			return ret;
-		}
-
-		falcon->data.data = vmemdup(fw->data, fw->size);
-		falcon->data.size = fw->size;
-		release_firmware(fw);
-		if (!falcon->data.data)
-			return -ENOMEM;
-
-		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
-			 device->chipset, falcon->addr >> 12);
-
-		ret = request_firmware(&fw, name, nv_device_base(device));
-		if (ret) {
-			nv_error(falcon, "unable to load firmware code\n");
-			return ret;
-		}
-
-		falcon->code.data = vmemdup(fw->data, fw->size);
-		falcon->code.size = fw->size;
-		release_firmware(fw);
-		if (!falcon->code.data)
-			return -ENOMEM;
-	}
-
-	nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
-		 "static code/data segments" : "self-bootstrapping");
-
-	/* ensure any "self-bootstrapping" firmware image is in vram */
-	if (!falcon->data.data && !falcon->core) {
-		ret = nouveau_gpuobj_new(object->parent, NULL,
-					 falcon->code.size, 256, 0,
-					&falcon->core);
-		if (ret) {
-			nv_error(falcon, "core allocation failed, %d\n", ret);
-			return ret;
-		}
-
-		for (i = 0; i < falcon->code.size; i += 4)
-			nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
-	}
-
-	/* upload firmware bootloader (or the full code segments) */
-	if (falcon->core) {
-		if (device->card_type < NV_C0)
-			nv_wo32(falcon, 0x618, 0x04000000);
-		else
-			nv_wo32(falcon, 0x618, 0x00000114);
-		nv_wo32(falcon, 0x11c, 0);
-		nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
-		nv_wo32(falcon, 0x114, 0);
-		nv_wo32(falcon, 0x118, 0x00006610);
-	} else {
-		if (falcon->code.size > falcon->code.limit ||
-		    falcon->data.size > falcon->data.limit) {
-			nv_error(falcon, "ucode exceeds falcon limit(s)\n");
-			return -EINVAL;
-		}
-
-		if (falcon->version < 3) {
-			nv_wo32(falcon, 0xff8, 0x00100000);
-			for (i = 0; i < falcon->code.size / 4; i++)
-				nv_wo32(falcon, 0xff4, falcon->code.data[i]);
-		} else {
-			nv_wo32(falcon, 0x180, 0x01000000);
-			for (i = 0; i < falcon->code.size / 4; i++) {
-				if ((i & 0x3f) == 0)
-					nv_wo32(falcon, 0x188, i >> 6);
-				nv_wo32(falcon, 0x184, falcon->code.data[i]);
-			}
-		}
-	}
-
-	/* upload data segment (if necessary), zeroing the remainder */
-	if (falcon->version < 3) {
-		nv_wo32(falcon, 0xff8, 0x00000000);
-		for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
-			nv_wo32(falcon, 0xff4, falcon->data.data[i]);
-		for (; i < falcon->data.limit; i += 4)
-			nv_wo32(falcon, 0xff4, 0x00000000);
-	} else {
-		nv_wo32(falcon, 0x1c0, 0x01000000);
-		for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
-			nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
-		for (; i < falcon->data.limit / 4; i++)
-			nv_wo32(falcon, 0x1c4, 0x00000000);
-	}
-
-	/* start it running */
-	nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
-	nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
-	nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
-	nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
-	return 0;
-}
-
-int
-_nouveau_falcon_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_falcon *falcon = (void *)object;
-
-	if (!suspend) {
-		nouveau_gpuobj_ref(NULL, &falcon->core);
-		if (falcon->external) {
-			vfree(falcon->data.data);
-			vfree(falcon->code.data);
-			falcon->code.data = NULL;
-		}
-	}
-
-	nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
-	nv_wo32(falcon, 0x014, 0xffffffff);
-
-	return nouveau_engine_fini(&falcon->base, suspend);
-}
-
-int
-nouveau_falcon_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 addr, bool enable,
-		       const char *iname, const char *fname,
-		       int length, void **pobject)
-{
-	struct nouveau_falcon *falcon;
-	int ret;
-
-	ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
-				     fname, length, pobject);
-	falcon = *pobject;
-	if (ret)
-		return ret;
-
-	falcon->addr = addr;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
deleted file mode 100644
index ac8375c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/object.h>
-#include <core/handle.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-static int
-nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size,
-			struct nvkm_notify *notify)
-{
-	if (size == 0) {
-		notify->size  = 0;
-		notify->types = 1;
-		notify->index = 0;
-		return 0;
-	}
-	return -ENOSYS;
-}
-
-static const struct nvkm_event_func
-nouveau_fifo_event_func = {
-	.ctor = nouveau_fifo_event_ctor,
-};
-
-int
-nouveau_fifo_channel_create_(struct nouveau_object *parent,
-			     struct nouveau_object *engine,
-			     struct nouveau_oclass *oclass,
-			     int bar, u32 addr, u32 size, u32 pushbuf,
-			     u64 engmask, int len, void **ptr)
-{
-	struct nouveau_device *device = nv_device(engine);
-	struct nouveau_fifo *priv = (void *)engine;
-	struct nouveau_fifo_chan *chan;
-	struct nouveau_dmaeng *dmaeng;
-	unsigned long flags;
-	int ret;
-
-	/* create base object class */
-	ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
-				     engmask, len, ptr);
-	chan = *ptr;
-	if (ret)
-		return ret;
-
-	/* validate dma object representing push buffer */
-	chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
-	if (!chan->pushdma)
-		return -ENOENT;
-
-	dmaeng = (void *)chan->pushdma->base.engine;
-	switch (chan->pushdma->base.oclass->handle) {
-	case NV_DMA_FROM_MEMORY:
-	case NV_DMA_IN_MEMORY:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
-	if (ret)
-		return ret;
-
-	/* find a free fifo channel */
-	spin_lock_irqsave(&priv->lock, flags);
-	for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
-		if (!priv->channel[chan->chid]) {
-			priv->channel[chan->chid] = nv_object(chan);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (chan->chid == priv->max) {
-		nv_error(priv, "no free channels\n");
-		return -ENOSPC;
-	}
-
-	chan->addr = nv_device_resource_start(device, bar) +
-		     addr + size * chan->chid;
-	chan->size = size;
-	nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
-	return 0;
-}
-
-void
-nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
-{
-	struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
-	unsigned long flags;
-
-	if (chan->user)
-		iounmap(chan->user);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->channel[chan->chid] = NULL;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	nouveau_gpuobj_ref(NULL, &chan->pushgpu);
-	nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
-	nouveau_namedb_destroy(&chan->base);
-}
-
-void
-_nouveau_fifo_channel_dtor(struct nouveau_object *object)
-{
-	struct nouveau_fifo_chan *chan = (void *)object;
-	nouveau_fifo_channel_destroy(chan);
-}
-
-int
-_nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
-	struct nouveau_fifo_chan *chan = (void *)object;
-	*addr = chan->addr;
-	*size = chan->size;
-	return 0;
-}
-
-u32
-_nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_fifo_chan *chan = (void *)object;
-	if (unlikely(!chan->user)) {
-		chan->user = ioremap(chan->addr, chan->size);
-		if (WARN_ON_ONCE(chan->user == NULL))
-			return 0;
-	}
-	return ioread32_native(chan->user + addr);
-}
-
-void
-_nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_fifo_chan *chan = (void *)object;
-	if (unlikely(!chan->user)) {
-		chan->user = ioremap(chan->addr, chan->size);
-		if (WARN_ON_ONCE(chan->user == NULL))
-			return;
-	}
-	iowrite32_native(data, chan->user + addr);
-}
-
-int
-nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
-			 struct nvkm_notify *notify)
-{
-	union {
-		struct nvif_notify_uevent_req none;
-	} *req = data;
-	int ret;
-
-	if (nvif_unvers(req->none)) {
-		notify->size  = sizeof(struct nvif_notify_uevent_rep);
-		notify->types = 1;
-		notify->index = 0;
-	}
-
-	return ret;
-}
-
-void
-nouveau_fifo_uevent(struct nouveau_fifo *fifo)
-{
-	struct nvif_notify_uevent_rep rep = {
-	};
-	nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
-}
-
-int
-_nouveau_fifo_channel_ntfy(struct nouveau_object *object, u32 type,
-			   struct nvkm_event **event)
-{
-	struct nouveau_fifo *fifo = (void *)object->engine;
-	switch (type) {
-	case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
-		if (nv_mclass(object) >= G82_CHANNEL_DMA) {
-			*event = &fifo->uevent;
-			return 0;
-		}
-		break;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static int
-nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object)
-{
-	int engidx = nv_hclass(priv) & 0xff;
-
-	while (object && object->parent) {
-		if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
-		    (nv_hclass(object->parent) & 0xff) == engidx)
-			return nouveau_fifo_chan(object)->chid;
-		object = object->parent;
-	}
-
-	return -1;
-}
-
-const char *
-nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid)
-{
-	struct nouveau_fifo_chan *chan = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&fifo->lock, flags);
-	if (chid >= fifo->min && chid <= fifo->max)
-		chan = (void *)fifo->channel[chid];
-	spin_unlock_irqrestore(&fifo->lock, flags);
-
-	return nouveau_client_name(chan);
-}
-
-void
-nouveau_fifo_destroy(struct nouveau_fifo *priv)
-{
-	kfree(priv->channel);
-	nvkm_event_fini(&priv->uevent);
-	nvkm_event_fini(&priv->cevent);
-	nouveau_engine_destroy(&priv->base);
-}
-
-int
-nouveau_fifo_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass,
-		     int min, int max, int length, void **pobject)
-{
-	struct nouveau_fifo *priv;
-	int ret;
-
-	ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
-				     "fifo", length, pobject);
-	priv = *pobject;
-	if (ret)
-		return ret;
-
-	priv->min = min;
-	priv->max = max;
-	priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
-	if (!priv->channel)
-		return -ENOMEM;
-
-	ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
-	if (ret)
-		return ret;
-
-	priv->chid = nouveau_fifo_chid;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c
deleted file mode 100644
index 327456e..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "nve0.h"
-
-struct nouveau_oclass *
-gk20a_fifo_oclass = &(struct nve0_fifo_impl) {
-	.base.handle = NV_ENGINE(FIFO, 0xea),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_fifo_ctor,
-		.dtor = nve0_fifo_dtor,
-		.init = nve0_fifo_init,
-		.fini = nve0_fifo_fini,
-	},
-	.channels = 128,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
deleted file mode 100644
index 1931057..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/ramht.h>
-#include <core/event.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv04_ramfc[] = {
-	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
-	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
-	{ 16,  0, 0x08,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
-	{ 16, 16, 0x08,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
-	{ 32,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_STATE },
-	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
-	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_ENGINE },
-	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_PULL1 },
-	{}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-int
-nv04_fifo_object_attach(struct nouveau_object *parent,
-			struct nouveau_object *object, u32 handle)
-{
-	struct nv04_fifo_priv *priv = (void *)parent->engine;
-	struct nv04_fifo_chan *chan = (void *)parent;
-	u32 context, chid = chan->base.chid;
-	int ret;
-
-	if (nv_iclass(object, NV_GPUOBJ_CLASS))
-		context = nv_gpuobj(object)->addr >> 4;
-	else
-		context = 0x00000004; /* just non-zero */
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_DMAOBJ:
-	case NVDEV_ENGINE_SW:
-		context |= 0x00000000;
-		break;
-	case NVDEV_ENGINE_GR:
-		context |= 0x00010000;
-		break;
-	case NVDEV_ENGINE_MPEG:
-		context |= 0x00020000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	context |= 0x80000000; /* valid */
-	context |= chid << 24;
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-	return ret;
-}
-
-void
-nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
-{
-	struct nv04_fifo_priv *priv = (void *)parent->engine;
-	mutex_lock(&nv_subdev(priv)->mutex);
-	nouveau_ramht_remove(priv->ramht, cookie);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-int
-nv04_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *object)
-{
-	nv_engctx(object)->addr = nouveau_fifo_chan(parent)->chid;
-	return 0;
-}
-
-static int
-nv04_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nv04_fifo_priv *priv = (void *)engine;
-	struct nv04_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
-					  0x10000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
-	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
-	chan->ramfc = chan->base.chid * 32;
-
-	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x10,
-			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
-			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
-			     NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
-			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-	return 0;
-}
-
-void
-nv04_fifo_chan_dtor(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object->engine;
-	struct nv04_fifo_chan *chan = (void *)object;
-	struct ramfc_desc *c = priv->ramfc_desc;
-
-	do {
-		nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
-	} while ((++c)->bits);
-
-	nouveau_fifo_channel_destroy(&chan->base);
-}
-
-int
-nv04_fifo_chan_init(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object->engine;
-	struct nv04_fifo_chan *chan = (void *)object;
-	u32 mask = 1 << chan->base.chid;
-	unsigned long flags;
-	int ret;
-
-	ret = nouveau_fifo_channel_init(&chan->base);
-	if (ret)
-		return ret;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return 0;
-}
-
-int
-nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv04_fifo_priv *priv = (void *)object->engine;
-	struct nv04_fifo_chan *chan = (void *)object;
-	struct nouveau_gpuobj *fctx = priv->ramfc;
-	struct ramfc_desc *c;
-	unsigned long flags;
-	u32 data = chan->ramfc;
-	u32 chid;
-
-	/* prevent fifo context switches */
-	spin_lock_irqsave(&priv->base.lock, flags);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-	/* if this channel is active, replace it with a null context */
-	chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-	if (chid == chan->base.chid) {
-		nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
-		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
-		nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
-
-		c = priv->ramfc_desc;
-		do {
-			u32 rm = ((1ULL << c->bits) - 1) << c->regs;
-			u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
-			u32 rv = (nv_rd32(priv, c->regp) &  rm) >> c->regs;
-			u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
-			nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
-		} while ((++c)->bits);
-
-		c = priv->ramfc_desc;
-		do {
-			nv_wr32(priv, c->regp, 0x00000000);
-		} while ((++c)->bits);
-
-		nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
-		nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
-		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
-		nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-	}
-
-	/* restore normal operation, after disabling dma mode */
-	nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-
-	return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nv04_fifo_ofuncs = {
-	.ctor = nv04_fifo_chan_ctor,
-	.dtor = nv04_fifo_chan_dtor,
-	.init = nv04_fifo_chan_init,
-	.fini = nv04_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv04_fifo_sclass[] = {
-	{ NV03_CHANNEL_DMA, &nv04_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-int
-nv04_fifo_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nv04_fifo_base *base;
-	int ret;
-
-	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
-				          0x1000, NVOBJ_FLAG_HEAP, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static struct nouveau_oclass
-nv04_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fifo_context_ctor,
-		.dtor = _nouveau_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-void
-nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
-__acquires(priv->base.lock)
-{
-	struct nv04_fifo_priv *priv = (void *)pfifo;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	*pflags = flags;
-
-	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
-	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
-
-	/* in some cases the puller may be left in an inconsistent state
-	 * if you try to stop it while it's busy translating handles.
-	 * sometimes you get a CACHE_ERROR, sometimes it just fails
-	 * silently; sending incorrect instance offsets to PGRAPH after
-	 * it's started up again.
-	 *
-	 * to avoid this, we invalidate the most recently calculated
-	 * instance.
-	 */
-	if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
-			   NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
-		nv_warn(priv, "timeout idling puller\n");
-
-	if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
-			  NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
-		nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
-
-	nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
-}
-
-void
-nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
-__releases(priv->base.lock)
-{
-	struct nv04_fifo_priv *priv = (void *)pfifo;
-	unsigned long flags = *pflags;
-
-	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
-
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-}
-
-static const char *
-nv_dma_state_err(u32 state)
-{
-	static const char * const desc[] = {
-		"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
-		"INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
-	};
-	return desc[(state >> 29) & 0x7];
-}
-
-static bool
-nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
-{
-	struct nv04_fifo_chan *chan = NULL;
-	struct nouveau_handle *bind;
-	const int subc = (addr >> 13) & 0x7;
-	const int mthd = addr & 0x1ffc;
-	bool handled = false;
-	unsigned long flags;
-	u32 engine;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	if (likely(chid >= priv->base.min && chid <= priv->base.max))
-		chan = (void *)priv->base.channel[chid];
-	if (unlikely(!chan))
-		goto out;
-
-	switch (mthd) {
-	case 0x0000:
-		bind = nouveau_namedb_get(nv_namedb(chan), data);
-		if (unlikely(!bind))
-			break;
-
-		if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
-			engine = 0x0000000f << (subc * 4);
-			chan->subc[subc] = data;
-			handled = true;
-
-			nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
-		}
-
-		nouveau_namedb_put(bind);
-		break;
-	default:
-		engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
-		if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
-			break;
-
-		bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
-		if (likely(bind)) {
-			if (!nv_call(bind->object, mthd, data))
-				handled = true;
-			nouveau_namedb_put(bind);
-		}
-		break;
-	}
-
-out:
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return handled;
-}
-
-static void
-nv04_fifo_cache_error(struct nouveau_device *device,
-		struct nv04_fifo_priv *priv, u32 chid, u32 get)
-{
-	u32 mthd, data;
-	int ptr;
-
-	/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
-	 * G80 chips, but CACHE1 isn't big enough for this much data.. Tests
-	 * show that it wraps around to the start at GET=0x800.. No clue as to
-	 * why..
-	 */
-	ptr = (get & 0x7ff) >> 2;
-
-	if (device->card_type < NV_40) {
-		mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
-		data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
-	} else {
-		mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
-		data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
-	}
-
-	if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
-		const char *client_name =
-			nouveau_client_name_for_fifo_chid(&priv->base, chid);
-		nv_error(priv,
-			 "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
-			 chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
-			 data);
-	}
-
-	nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
-	nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
-		nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
-	nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
-		nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
-	nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
-
-	nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
-		nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
-	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-}
-
-static void
-nv04_fifo_dma_pusher(struct nouveau_device *device, struct nv04_fifo_priv *priv,
-		u32 chid)
-{
-	const char *client_name;
-	u32 dma_get = nv_rd32(priv, 0x003244);
-	u32 dma_put = nv_rd32(priv, 0x003240);
-	u32 push = nv_rd32(priv, 0x003220);
-	u32 state = nv_rd32(priv, 0x003228);
-
-	client_name = nouveau_client_name_for_fifo_chid(&priv->base, chid);
-
-	if (device->card_type == NV_50) {
-		u32 ho_get = nv_rd32(priv, 0x003328);
-		u32 ho_put = nv_rd32(priv, 0x003320);
-		u32 ib_get = nv_rd32(priv, 0x003334);
-		u32 ib_put = nv_rd32(priv, 0x003330);
-
-		nv_error(priv,
-			 "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
-			 chid, client_name, ho_get, dma_get, ho_put, dma_put,
-			 ib_get, ib_put, state, nv_dma_state_err(state), push);
-
-		/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
-		nv_wr32(priv, 0x003364, 0x00000000);
-		if (dma_get != dma_put || ho_get != ho_put) {
-			nv_wr32(priv, 0x003244, dma_put);
-			nv_wr32(priv, 0x003328, ho_put);
-		} else
-		if (ib_get != ib_put)
-			nv_wr32(priv, 0x003334, ib_put);
-	} else {
-		nv_error(priv,
-			 "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
-			 chid, client_name, dma_get, dma_put, state,
-			 nv_dma_state_err(state), push);
-
-		if (dma_get != dma_put)
-			nv_wr32(priv, 0x003244, dma_put);
-	}
-
-	nv_wr32(priv, 0x003228, 0x00000000);
-	nv_wr32(priv, 0x003220, 0x00000001);
-	nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
-}
-
-void
-nv04_fifo_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_device *device = nv_device(subdev);
-	struct nv04_fifo_priv *priv = (void *)subdev;
-	uint32_t status, reassign;
-	int cnt = 0;
-
-	reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
-	while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
-		uint32_t chid, get;
-
-		nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
-		chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
-		get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
-
-		if (status & NV_PFIFO_INTR_CACHE_ERROR) {
-			nv04_fifo_cache_error(device, priv, chid, get);
-			status &= ~NV_PFIFO_INTR_CACHE_ERROR;
-		}
-
-		if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-			nv04_fifo_dma_pusher(device, priv, chid);
-			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-		}
-
-		if (status & NV_PFIFO_INTR_SEMAPHORE) {
-			uint32_t sem;
-
-			status &= ~NV_PFIFO_INTR_SEMAPHORE;
-			nv_wr32(priv, NV03_PFIFO_INTR_0,
-				NV_PFIFO_INTR_SEMAPHORE);
-
-			sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
-			nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
-
-			nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
-			nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-		}
-
-		if (device->card_type == NV_50) {
-			if (status & 0x00000010) {
-				status &= ~0x00000010;
-				nv_wr32(priv, 0x002100, 0x00000010);
-			}
-
-			if (status & 0x40000000) {
-				nv_wr32(priv, 0x002100, 0x40000000);
-				nouveau_fifo_uevent(&priv->base);
-				status &= ~0x40000000;
-			}
-		}
-
-		if (status) {
-			nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
-				status, chid);
-			nv_wr32(priv, NV03_PFIFO_INTR_0, status);
-			status = 0;
-		}
-
-		nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
-	}
-
-	if (status) {
-		nv_error(priv, "still angry after %d spins, halt\n", cnt);
-		nv_wr32(priv, 0x002140, 0);
-		nv_wr32(priv, 0x000140, 0);
-	}
-
-	nv_wr32(priv, 0x000100, 0x00000100);
-}
-
-static int
-nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *imem = nv04_instmem(parent);
-	struct nv04_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nouveau_ramht_ref(imem->ramht, &priv->ramht);
-	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
-	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv04_fifo_cclass;
-	nv_engine(priv)->sclass = nv04_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	priv->ramfc_desc = nv04_ramfc;
-	return 0;
-}
-
-void
-nv04_fifo_dtor(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object;
-	nouveau_gpuobj_ref(NULL, &priv->ramfc);
-	nouveau_gpuobj_ref(NULL, &priv->ramro);
-	nouveau_ramht_ref(NULL, &priv->ramht);
-	nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nv04_fifo_init(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
-	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
-
-	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((priv->ramht->bits - 9) << 16) |
-				        (priv->ramht->base.addr >> 8));
-	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
-	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fifo_ctor,
-		.dtor = nv04_fifo_dtor,
-		.init = nv04_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
deleted file mode 100644
index 496a4b4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
+++ /dev/null
@@ -1,178 +0,0 @@
-#ifndef __NV04_FIFO_H__
-#define __NV04_FIFO_H__
-
-#include <engine/fifo.h>
-
-#define NV04_PFIFO_DELAY_0                                 0x00002040
-#define NV04_PFIFO_DMA_TIMESLICE                           0x00002044
-#define NV04_PFIFO_NEXT_CHANNEL                            0x00002050
-#define NV03_PFIFO_INTR_0                                  0x00002100
-#define NV03_PFIFO_INTR_EN_0                               0x00002140
-#    define NV_PFIFO_INTR_CACHE_ERROR                          (1<<0)
-#    define NV_PFIFO_INTR_RUNOUT                               (1<<4)
-#    define NV_PFIFO_INTR_RUNOUT_OVERFLOW                      (1<<8)
-#    define NV_PFIFO_INTR_DMA_PUSHER                          (1<<12)
-#    define NV_PFIFO_INTR_DMA_PT                              (1<<16)
-#    define NV_PFIFO_INTR_SEMAPHORE                           (1<<20)
-#    define NV_PFIFO_INTR_ACQUIRE_TIMEOUT                     (1<<24)
-#define NV03_PFIFO_RAMHT                                   0x00002210
-#define NV03_PFIFO_RAMFC                                   0x00002214
-#define NV03_PFIFO_RAMRO                                   0x00002218
-#define NV40_PFIFO_RAMFC                                   0x00002220
-#define NV03_PFIFO_CACHES                                  0x00002500
-#define NV04_PFIFO_MODE                                    0x00002504
-#define NV04_PFIFO_DMA                                     0x00002508
-#define NV04_PFIFO_SIZE                                    0x0000250c
-#define NV50_PFIFO_CTX_TABLE(c)                        (0x2600+(c)*4)
-#define NV50_PFIFO_CTX_TABLE__SIZE                                128
-#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED                  (1<<31)
-#define NV50_PFIFO_CTX_TABLE_UNK30_BAD                        (1<<30)
-#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80             0x0FFFFFFF
-#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84             0x00FFFFFF
-#define NV03_PFIFO_CACHE0_PUSH0                            0x00003000
-#define NV03_PFIFO_CACHE0_PULL0                            0x00003040
-#define NV04_PFIFO_CACHE0_PULL0                            0x00003050
-#define NV04_PFIFO_CACHE0_PULL1                            0x00003054
-#define NV03_PFIFO_CACHE1_PUSH0                            0x00003200
-#define NV03_PFIFO_CACHE1_PUSH1                            0x00003204
-#define NV03_PFIFO_CACHE1_PUSH1_DMA                            (1<<8)
-#define NV40_PFIFO_CACHE1_PUSH1_DMA                           (1<<16)
-#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000000f
-#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000001f
-#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000007f
-#define NV03_PFIFO_CACHE1_PUT                              0x00003210
-#define NV04_PFIFO_CACHE1_DMA_PUSH                         0x00003220
-#define NV04_PFIFO_CACHE1_DMA_FETCH                        0x00003224
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES         0x00000000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES        0x00000008
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES        0x00000010
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES        0x00000018
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES        0x00000020
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES        0x00000028
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES        0x00000030
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES        0x00000038
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES        0x00000040
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES        0x00000048
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES        0x00000050
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES        0x00000058
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES       0x00000060
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES       0x00000068
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES       0x00000070
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES       0x00000078
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES       0x00000080
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES       0x00000088
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES       0x00000090
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES       0x00000098
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES       0x000000A0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES       0x000000A8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES       0x000000B0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES       0x000000B8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES       0x000000C0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES       0x000000C8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES       0x000000D0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES       0x000000D8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES       0x000000E0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES       0x000000E8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES       0x000000F0
-#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES       0x000000F8
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE                 0x0000E000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES        0x00000000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES        0x00002000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES        0x00004000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES       0x00006000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES       0x00008000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES       0x0000A000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES       0x0000C000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES       0x0000E000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS             0x001F0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0           0x00000000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1           0x00010000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2           0x00020000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3           0x00030000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4           0x00040000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5           0x00050000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6           0x00060000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7           0x00070000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8           0x00080000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9           0x00090000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10          0x000A0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11          0x000B0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12          0x000C0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13          0x000D0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14          0x000E0000
-#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15          0x000F0000
-#    define NV_PFIFO_CACHE1_ENDIAN                         0x80000000
-#    define NV_PFIFO_CACHE1_LITTLE_ENDIAN                  0x7FFFFFFF
-#    define NV_PFIFO_CACHE1_BIG_ENDIAN                     0x80000000
-#define NV04_PFIFO_CACHE1_DMA_STATE                        0x00003228
-#define NV04_PFIFO_CACHE1_DMA_INSTANCE                     0x0000322c
-#define NV04_PFIFO_CACHE1_DMA_CTL                          0x00003230
-#define NV04_PFIFO_CACHE1_DMA_PUT                          0x00003240
-#define NV04_PFIFO_CACHE1_DMA_GET                          0x00003244
-#define NV10_PFIFO_CACHE1_REF_CNT                          0x00003248
-#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE                   0x0000324C
-#define NV03_PFIFO_CACHE1_PULL0                            0x00003240
-#define NV04_PFIFO_CACHE1_PULL0                            0x00003250
-#    define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED            0x00000010
-#    define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY              0x00001000
-#define NV03_PFIFO_CACHE1_PULL1                            0x00003250
-#define NV04_PFIFO_CACHE1_PULL1                            0x00003254
-#define NV04_PFIFO_CACHE1_HASH                             0x00003258
-#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT                  0x00003260
-#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP                0x00003264
-#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE                    0x00003268
-#define NV10_PFIFO_CACHE1_SEMAPHORE                        0x0000326C
-#define NV03_PFIFO_CACHE1_GET                              0x00003270
-#define NV04_PFIFO_CACHE1_ENGINE                           0x00003280
-#define NV04_PFIFO_CACHE1_DMA_DCOUNT                       0x000032A0
-#define NV40_PFIFO_GRCTX_INSTANCE                          0x000032E0
-#define NV40_PFIFO_UNK32E4                                 0x000032E4
-#define NV04_PFIFO_CACHE1_METHOD(i)                (0x00003800+(i*8))
-#define NV04_PFIFO_CACHE1_DATA(i)                  (0x00003804+(i*8))
-#define NV40_PFIFO_CACHE1_METHOD(i)                (0x00090000+(i*8))
-#define NV40_PFIFO_CACHE1_DATA(i)                  (0x00090004+(i*8))
-
-struct ramfc_desc {
-	unsigned bits:6;
-	unsigned ctxs:5;
-	unsigned ctxp:8;
-	unsigned regs:5;
-	unsigned regp;
-};
-
-struct nv04_fifo_priv {
-	struct nouveau_fifo base;
-	struct ramfc_desc *ramfc_desc;
-	struct nouveau_ramht  *ramht;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
-
-struct nv04_fifo_base {
-	struct nouveau_fifo_base base;
-};
-
-struct nv04_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 subc[8];
-	u32 ramfc;
-};
-
-int  nv04_fifo_object_attach(struct nouveau_object *,
-			     struct nouveau_object *, u32);
-void nv04_fifo_object_detach(struct nouveau_object *, int);
-
-void nv04_fifo_chan_dtor(struct nouveau_object *);
-int  nv04_fifo_chan_init(struct nouveau_object *);
-int  nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
-
-int  nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, void *, u32,
-			    struct nouveau_object **);
-
-void nv04_fifo_dtor(struct nouveau_object *);
-int  nv04_fifo_init(struct nouveau_object *);
-void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
-void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
deleted file mode 100644
index 2a32add..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv10_ramfc[] = {
-	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
-	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
-	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
-	{ 16,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
-	{ 16, 16, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
-	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_STATE },
-	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
-	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_ENGINE },
-	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_PULL1 },
-	{}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv10_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nv04_fifo_priv *priv = (void *)engine;
-	struct nv04_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
-					  0x10000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
-	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
-	chan->ramfc = chan->base.chid * 32;
-
-	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
-			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
-			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
-			     NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
-			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv10_fifo_ofuncs = {
-	.ctor = nv10_fifo_chan_ctor,
-	.dtor = nv04_fifo_chan_dtor,
-	.init = nv04_fifo_chan_init,
-	.fini = nv04_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv10_fifo_sclass[] = {
-	{ NV10_CHANNEL_DMA, &nv10_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv10_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x10),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fifo_context_ctor,
-		.dtor = _nouveau_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *imem = nv04_instmem(parent);
-	struct nv04_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nouveau_ramht_ref(imem->ramht, &priv->ramht);
-	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
-	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv10_fifo_cclass;
-	nv_engine(priv)->sclass = nv10_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	priv->ramfc_desc = nv10_ramfc;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv10_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x10),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_fifo_ctor,
-		.dtor = nv04_fifo_dtor,
-		.init = nv04_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c
deleted file mode 100644
index 09362a5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nve0.h"
-
-struct nouveau_oclass *
-nv108_fifo_oclass = &(struct nve0_fifo_impl) {
-	.base.handle = NV_ENGINE(FIFO, 0x08),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_fifo_ctor,
-		.dtor = nve0_fifo_dtor,
-		.init = nve0_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-	.channels = 1024,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
deleted file mode 100644
index 12d76c8..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv17_ramfc[] = {
-	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
-	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
-	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
-	{ 16,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
-	{ 16, 16, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
-	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_STATE },
-	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
-	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_ENGINE },
-	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_PULL1 },
-	{ 32,  0, 0x20,  0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
-	{ 32,  0, 0x24,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
-	{ 32,  0, 0x28,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
-	{ 32,  0, 0x2c,  0, NV10_PFIFO_CACHE1_SEMAPHORE },
-	{ 32,  0, 0x30,  0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
-	{}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv17_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nv04_fifo_priv *priv = (void *)engine;
-	struct nv04_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
-					  0x10000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
-					  &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
-	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
-	chan->ramfc = chan->base.chid * 64;
-
-	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
-			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
-			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
-			     NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
-			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv17_fifo_ofuncs = {
-	.ctor = nv17_fifo_chan_ctor,
-	.dtor = nv04_fifo_chan_dtor,
-	.init = nv04_fifo_chan_init,
-	.fini = nv04_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv17_fifo_sclass[] = {
-	{ NV17_CHANNEL_DMA, &nv17_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv17_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x17),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fifo_context_ctor,
-		.dtor = _nouveau_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *imem = nv04_instmem(parent);
-	struct nv04_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nouveau_ramht_ref(imem->ramht, &priv->ramht);
-	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
-	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv17_fifo_cclass;
-	nv_engine(priv)->sclass = nv17_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	priv->ramfc_desc = nv17_ramfc;
-	return 0;
-}
-
-static int
-nv17_fifo_init(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
-	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
-
-	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((priv->ramht->bits - 9) << 16) |
-				        (priv->ramht->base.addr >> 8));
-	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
-	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv17_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x17),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv17_fifo_ctor,
-		.dtor = nv04_fifo_dtor,
-		.init = nv17_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
deleted file mode 100644
index 9f49c3a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv40_ramfc[] = {
-	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
-	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
-	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
-	{ 32,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
-	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
-	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_STATE },
-	{ 28,  0, 0x18,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
-	{  2, 28, 0x18, 28, 0x002058 },
-	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_ENGINE },
-	{ 32,  0, 0x20,  0, NV04_PFIFO_CACHE1_PULL1 },
-	{ 32,  0, 0x24,  0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
-	{ 32,  0, 0x28,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
-	{ 32,  0, 0x2c,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
-	{ 32,  0, 0x30,  0, NV10_PFIFO_CACHE1_SEMAPHORE },
-	{ 32,  0, 0x34,  0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
-	{ 32,  0, 0x38,  0, NV40_PFIFO_GRCTX_INSTANCE },
-	{ 17,  0, 0x3c,  0, NV04_PFIFO_DMA_TIMESLICE },
-	{ 32,  0, 0x40,  0, 0x0032e4 },
-	{ 32,  0, 0x44,  0, 0x0032e8 },
-	{ 32,  0, 0x4c,  0, 0x002088 },
-	{ 32,  0, 0x50,  0, 0x003300 },
-	{ 32,  0, 0x54,  0, 0x00330c },
-	{}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv40_fifo_object_attach(struct nouveau_object *parent,
-			struct nouveau_object *object, u32 handle)
-{
-	struct nv04_fifo_priv *priv = (void *)parent->engine;
-	struct nv04_fifo_chan *chan = (void *)parent;
-	u32 context, chid = chan->base.chid;
-	int ret;
-
-	if (nv_iclass(object, NV_GPUOBJ_CLASS))
-		context = nv_gpuobj(object)->addr >> 4;
-	else
-		context = 0x00000004; /* just non-zero */
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_DMAOBJ:
-	case NVDEV_ENGINE_SW:
-		context |= 0x00000000;
-		break;
-	case NVDEV_ENGINE_GR:
-		context |= 0x00100000;
-		break;
-	case NVDEV_ENGINE_MPEG:
-		context |= 0x00200000;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	context |= chid << 23;
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-	return ret;
-}
-
-static int
-nv40_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *engctx)
-{
-	struct nv04_fifo_priv *priv = (void *)parent->engine;
-	struct nv04_fifo_chan *chan = (void *)parent;
-	unsigned long flags;
-	u32 reg, ctx;
-
-	switch (nv_engidx(engctx->engine)) {
-	case NVDEV_ENGINE_SW:
-		return 0;
-	case NVDEV_ENGINE_GR:
-		reg = 0x32e0;
-		ctx = 0x38;
-		break;
-	case NVDEV_ENGINE_MPEG:
-		reg = 0x330c;
-		ctx = 0x54;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
-	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
-
-	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
-		nv_wr32(priv, reg, nv_engctx(engctx)->addr);
-	nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
-
-	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return 0;
-}
-
-static int
-nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
-			 struct nouveau_object *engctx)
-{
-	struct nv04_fifo_priv *priv = (void *)parent->engine;
-	struct nv04_fifo_chan *chan = (void *)parent;
-	unsigned long flags;
-	u32 reg, ctx;
-
-	switch (nv_engidx(engctx->engine)) {
-	case NVDEV_ENGINE_SW:
-		return 0;
-	case NVDEV_ENGINE_GR:
-		reg = 0x32e0;
-		ctx = 0x38;
-		break;
-	case NVDEV_ENGINE_MPEG:
-		reg = 0x330c;
-		ctx = 0x54;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
-
-	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
-		nv_wr32(priv, reg, 0x00000000);
-	nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
-
-	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return 0;
-}
-
-static int
-nv40_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nv04_fifo_priv *priv = (void *)engine;
-	struct nv04_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
-					  0x1000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->context_attach = nv40_fifo_context_attach;
-	nv_parent(chan)->context_detach = nv40_fifo_context_detach;
-	nv_parent(chan)->object_attach = nv40_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
-	chan->ramfc = chan->base.chid * 128;
-
-	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
-			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
-			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
-			     NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
-			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
-	nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv40_fifo_ofuncs = {
-	.ctor = nv40_fifo_chan_ctor,
-	.dtor = nv04_fifo_chan_dtor,
-	.init = nv04_fifo_chan_init,
-	.fini = nv04_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv40_fifo_sclass[] = {
-	{ NV40_CHANNEL_DMA, &nv40_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv40_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fifo_context_ctor,
-		.dtor = _nouveau_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *imem = nv04_instmem(parent);
-	struct nv04_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nouveau_ramht_ref(imem->ramht, &priv->ramht);
-	nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
-	nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv40_fifo_cclass;
-	nv_engine(priv)->sclass = nv40_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	priv->ramfc_desc = nv40_ramfc;
-	return 0;
-}
-
-static int
-nv40_fifo_init(struct nouveau_object *object)
-{
-	struct nv04_fifo_priv *priv = (void *)object;
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	int ret;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x002040, 0x000000ff);
-	nv_wr32(priv, 0x002044, 0x2101ffff);
-	nv_wr32(priv, 0x002058, 0x00000001);
-
-	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((priv->ramht->bits - 9) << 16) |
-				        (priv->ramht->base.addr >> 8));
-	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-
-	switch (nv_device(priv)->chipset) {
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		nv_wr32(priv, 0x002230, 0x00000001);
-	case 0x40:
-	case 0x41:
-	case 0x42:
-	case 0x43:
-	case 0x45:
-	case 0x48:
-		nv_wr32(priv, 0x002220, 0x00030002);
-		break;
-	default:
-		nv_wr32(priv, 0x002230, 0x00000000);
-		nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
-					 priv->ramfc->addr) >> 16) |
-					0x00030000);
-		break;
-	}
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
-	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
-	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
-	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
-	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv40_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_fifo_ctor,
-		.dtor = nv04_fifo_dtor,
-		.init = nv40_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
deleted file mode 100644
index 5d1e86b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-#include "nv04.h"
-#include "nv50.h"
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
-{
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nouveau_gpuobj *cur;
-	int i, p;
-
-	cur = priv->playlist[priv->cur_playlist];
-	priv->cur_playlist = !priv->cur_playlist;
-
-	for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
-		if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
-			nv_wo32(cur, p++ * 4, i);
-	}
-
-	bar->flush(bar);
-
-	nv_wr32(priv, 0x0032f4, cur->addr >> 12);
-	nv_wr32(priv, 0x0032ec, p);
-	nv_wr32(priv, 0x002500, 0x00000101);
-}
-
-void
-nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
-{
-	mutex_lock(&nv_subdev(priv)->mutex);
-	nv50_fifo_playlist_update_locked(priv);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nv50_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent->parent;
-	struct nouveau_gpuobj *ectx = (void *)object;
-	u64 limit = ectx->addr + ectx->size - 1;
-	u64 start = ectx->addr;
-	u32 addr;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
-	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
-	default:
-		return -EINVAL;
-	}
-
-	nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
-	nv_wo32(base->eng, addr + 0x00, 0x00190000);
-	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
-	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
-	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
-					upper_32_bits(start));
-	nv_wo32(base->eng, addr + 0x10, 0x00000000);
-	nv_wo32(base->eng, addr + 0x14, 0x00000000);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_priv *priv = (void *)parent->engine;
-	struct nv50_fifo_base *base = (void *)parent->parent;
-	struct nv50_fifo_chan *chan = (void *)parent;
-	u32 addr, me;
-	int ret = 0;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
-	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
-	default:
-		return -EINVAL;
-	}
-
-	/* HW bug workaround:
-	 *
-	 * PFIFO will hang forever if the connected engines don't report
-	 * that they've processed the context switch request.
-	 *
-	 * In order for the kickoff to work, we need to ensure all the
-	 * connected engines are in a state where they can answer.
-	 *
-	 * Newer chipsets don't seem to suffer from this issue, and well,
-	 * there's also a "ignore these engines" bitmask reg we can use
-	 * if we hit the issue there..
-	 */
-	me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
-
-	/* do the kickoff... */
-	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
-	if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
-		nv_error(priv, "channel %d [%s] unload timeout\n",
-			 chan->base.chid, nouveau_client_name(chan));
-		if (suspend)
-			ret = -EBUSY;
-	}
-	nv_wr32(priv, 0x00b860, me);
-
-	if (ret == 0) {
-		nv_wo32(base->eng, addr + 0x00, 0x00000000);
-		nv_wo32(base->eng, addr + 0x04, 0x00000000);
-		nv_wo32(base->eng, addr + 0x08, 0x00000000);
-		nv_wo32(base->eng, addr + 0x0c, 0x00000000);
-		nv_wo32(base->eng, addr + 0x10, 0x00000000);
-		nv_wo32(base->eng, addr + 0x14, 0x00000000);
-		bar->flush(bar);
-	}
-
-	return ret;
-}
-
-static int
-nv50_fifo_object_attach(struct nouveau_object *parent,
-			struct nouveau_object *object, u32 handle)
-{
-	struct nv50_fifo_chan *chan = (void *)parent;
-	u32 context;
-
-	if (nv_iclass(object, NV_GPUOBJ_CLASS))
-		context = nv_gpuobj(object)->node->offset >> 4;
-	else
-		context = 0x00000004; /* just non-zero */
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_DMAOBJ:
-	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
-	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
-	case NVDEV_ENGINE_MPEG  : context |= 0x00200000; break;
-	default:
-		return -EINVAL;
-	}
-
-	return nouveau_ramht_insert(chan->ramht, 0, handle, context);
-}
-
-void
-nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
-{
-	struct nv50_fifo_chan *chan = (void *)parent;
-	nouveau_ramht_remove(chan->ramht, cookie);
-}
-
-static int
-nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent;
-	struct nv50_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
-					  0x2000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->context_attach = nv50_fifo_context_attach;
-	nv_parent(chan)->context_detach = nv50_fifo_context_detach;
-	nv_parent(chan)->object_attach = nv50_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
-	ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
-				&chan->ramht);
-	if (ret)
-		return ret;
-
-	nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x3c, 0x003f6078);
-	nv_wo32(base->ramfc, 0x44, 0x01003fff);
-	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
-	nv_wo32(base->ramfc, 0x4c, 0xffffffff);
-	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
-	nv_wo32(base->ramfc, 0x78, 0x00000000);
-	nv_wo32(base->ramfc, 0x7c, 0x30000001);
-	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
-				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->base.node->offset >> 4));
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_channel_gpfifo_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent;
-	struct nv50_fifo_chan *chan;
-	u64 ioffset, ilength;
-	int ret;
-
-	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
-				 "ioffset %016llx ilength %08x\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
-			 args->v0.ilength);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
-					  0x2000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->context_attach = nv50_fifo_context_attach;
-	nv_parent(chan)->context_detach = nv50_fifo_context_detach;
-	nv_parent(chan)->object_attach = nv50_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
-	ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
-			       &chan->ramht);
-	if (ret)
-		return ret;
-
-	ioffset = args->v0.ioffset;
-	ilength = order_base_2(args->v0.ilength / 8);
-
-	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
-	nv_wo32(base->ramfc, 0x44, 0x01003fff);
-	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
-	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
-	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
-	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
-	nv_wo32(base->ramfc, 0x78, 0x00000000);
-	nv_wo32(base->ramfc, 0x7c, 0x30000001);
-	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
-				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->base.node->offset >> 4));
-	bar->flush(bar);
-	return 0;
-}
-
-void
-nv50_fifo_chan_dtor(struct nouveau_object *object)
-{
-	struct nv50_fifo_chan *chan = (void *)object;
-	nouveau_ramht_ref(NULL, &chan->ramht);
-	nouveau_fifo_channel_destroy(&chan->base);
-}
-
-static int
-nv50_fifo_chan_init(struct nouveau_object *object)
-{
-	struct nv50_fifo_priv *priv = (void *)object->engine;
-	struct nv50_fifo_base *base = (void *)object->parent;
-	struct nv50_fifo_chan *chan = (void *)object;
-	struct nouveau_gpuobj *ramfc = base->ramfc;
-	u32 chid = chan->base.chid;
-	int ret;
-
-	ret = nouveau_fifo_channel_init(&chan->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
-	nv50_fifo_playlist_update(priv);
-	return 0;
-}
-
-int
-nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_fifo_priv *priv = (void *)object->engine;
-	struct nv50_fifo_chan *chan = (void *)object;
-	u32 chid = chan->base.chid;
-
-	/* remove channel from playlist, fifo will unload context */
-	nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
-	nv50_fifo_playlist_update(priv);
-	nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
-
-	return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nv50_fifo_ofuncs_dma = {
-	.ctor = nv50_fifo_chan_ctor_dma,
-	.dtor = nv50_fifo_chan_dtor,
-	.init = nv50_fifo_chan_init,
-	.fini = nv50_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_ofuncs
-nv50_fifo_ofuncs_ind = {
-	.ctor = nv50_fifo_chan_ctor_ind,
-	.dtor = nv50_fifo_chan_dtor,
-	.init = nv50_fifo_chan_init,
-	.fini = nv50_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv50_fifo_sclass[] = {
-	{ NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma },
-	{ NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static int
-nv50_fifo_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nv50_fifo_base *base;
-	int ret;
-
-	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
-				          0x1000, NVOBJ_FLAG_HEAP, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
-				 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
-				&base->pgd);
-	if (ret)
-		return ret;
-
-	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-void
-nv50_fifo_context_dtor(struct nouveau_object *object)
-{
-	struct nv50_fifo_base *base = (void *)object;
-	nouveau_vm_ref(NULL, &base->vm, base->pgd);
-	nouveau_gpuobj_ref(NULL, &base->pgd);
-	nouveau_gpuobj_ref(NULL, &base->eng);
-	nouveau_gpuobj_ref(NULL, &base->ramfc);
-	nouveau_gpuobj_ref(NULL, &base->cache);
-	nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nv50_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fifo_context_ctor,
-		.dtor = nv50_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
-				&priv->playlist[0]);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
-				&priv->playlist[1]);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv50_fifo_cclass;
-	nv_engine(priv)->sclass = nv50_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	return 0;
-}
-
-void
-nv50_fifo_dtor(struct nouveau_object *object)
-{
-	struct nv50_fifo_priv *priv = (void *)object;
-
-	nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
-	nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
-
-	nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nv50_fifo_init(struct nouveau_object *object)
-{
-	struct nv50_fifo_priv *priv = (void *)object;
-	int ret, i;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(priv, 0x00250c, 0x6f3cfc34);
-	nv_wr32(priv, 0x002044, 0x01003fff);
-
-	nv_wr32(priv, 0x002100, 0xffffffff);
-	nv_wr32(priv, 0x002140, 0xbfffffff);
-
-	for (i = 0; i < 128; i++)
-		nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
-	nv50_fifo_playlist_update_locked(priv);
-
-	nv_wr32(priv, 0x003200, 0x00000001);
-	nv_wr32(priv, 0x003250, 0x00000001);
-	nv_wr32(priv, 0x002500, 0x00000001);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fifo_ctor,
-		.dtor = nv50_fifo_dtor,
-		.init = nv50_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
deleted file mode 100644
index 3a9ceb3..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __NV50_FIFO_H__
-#define __NV50_FIFO_H__
-
-struct nv50_fifo_priv {
-	struct nouveau_fifo base;
-	struct nouveau_gpuobj *playlist[2];
-	int cur_playlist;
-};
-
-struct nv50_fifo_base {
-	struct nouveau_fifo_base base;
-	struct nouveau_gpuobj *ramfc;
-	struct nouveau_gpuobj *cache;
-	struct nouveau_gpuobj *eng;
-	struct nouveau_gpuobj *pgd;
-	struct nouveau_vm *vm;
-};
-
-struct nv50_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 subc[8];
-	struct nouveau_ramht *ramht;
-};
-
-void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
-
-void nv50_fifo_object_detach(struct nouveau_object *, int);
-void nv50_fifo_chan_dtor(struct nouveau_object *);
-int  nv50_fifo_chan_fini(struct nouveau_object *, bool);
-
-void nv50_fifo_context_dtor(struct nouveau_object *);
-
-void nv50_fifo_dtor(struct nouveau_object *);
-int  nv50_fifo_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
deleted file mode 100644
index 1f42996..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-#include "nv04.h"
-#include "nv50.h"
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv84_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent->parent;
-	struct nouveau_gpuobj *ectx = (void *)object;
-	u64 limit = ectx->addr + ectx->size - 1;
-	u64 start = ectx->addr;
-	u32 addr;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0020; break;
-	case NVDEV_ENGINE_VP   : addr = 0x0040; break;
-	case NVDEV_ENGINE_PPP  :
-	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
-	case NVDEV_ENGINE_BSP  : addr = 0x0080; break;
-	case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
-	case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
-	default:
-		return -EINVAL;
-	}
-
-	nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
-	nv_wo32(base->eng, addr + 0x00, 0x00190000);
-	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
-	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
-	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
-					upper_32_bits(start));
-	nv_wo32(base->eng, addr + 0x10, 0x00000000);
-	nv_wo32(base->eng, addr + 0x14, 0x00000000);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_priv *priv = (void *)parent->engine;
-	struct nv50_fifo_base *base = (void *)parent->parent;
-	struct nv50_fifo_chan *chan = (void *)parent;
-	u32 addr, save, engn;
-	bool done;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : engn = 0; addr = 0x0020; break;
-	case NVDEV_ENGINE_VP   : engn = 3; addr = 0x0040; break;
-	case NVDEV_ENGINE_PPP  :
-	case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
-	case NVDEV_ENGINE_BSP  : engn = 5; addr = 0x0080; break;
-	case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
-	case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
-	default:
-		return -EINVAL;
-	}
-
-	save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
-	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
-	done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
-	nv_wr32(priv, 0x002520, save);
-	if (!done) {
-		nv_error(priv, "channel %d [%s] unload timeout\n",
-			 chan->base.chid, nouveau_client_name(chan));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	nv_wo32(base->eng, addr + 0x00, 0x00000000);
-	nv_wo32(base->eng, addr + 0x04, 0x00000000);
-	nv_wo32(base->eng, addr + 0x08, 0x00000000);
-	nv_wo32(base->eng, addr + 0x0c, 0x00000000);
-	nv_wo32(base->eng, addr + 0x10, 0x00000000);
-	nv_wo32(base->eng, addr + 0x14, 0x00000000);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv84_fifo_object_attach(struct nouveau_object *parent,
-			struct nouveau_object *object, u32 handle)
-{
-	struct nv50_fifo_chan *chan = (void *)parent;
-	u32 context;
-
-	if (nv_iclass(object, NV_GPUOBJ_CLASS))
-		context = nv_gpuobj(object)->node->offset >> 4;
-	else
-		context = 0x00000004; /* just non-zero */
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_DMAOBJ:
-	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
-	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
-	case NVDEV_ENGINE_MPEG  :
-	case NVDEV_ENGINE_PPP   : context |= 0x00200000; break;
-	case NVDEV_ENGINE_ME    :
-	case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
-	case NVDEV_ENGINE_VP    : context |= 0x00400000; break;
-	case NVDEV_ENGINE_CRYPT :
-	case NVDEV_ENGINE_VIC   : context |= 0x00500000; break;
-	case NVDEV_ENGINE_BSP   : context |= 0x00600000; break;
-	default:
-		return -EINVAL;
-	}
-
-	return nouveau_ramht_insert(chan->ramht, 0, handle, context);
-}
-
-static int
-nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	union {
-		struct nv03_channel_dma_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent;
-	struct nv50_fifo_chan *chan;
-	int ret;
-
-	nv_ioctl(parent, "create channel dma size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
-				 "offset %016llx\n", args->v0.version,
-			 args->v0.pushbuf, args->v0.offset);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
-					  0x2000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG) |
-					  (1ULL << NVDEV_ENGINE_ME) |
-					  (1ULL << NVDEV_ENGINE_VP) |
-					  (1ULL << NVDEV_ENGINE_CRYPT) |
-					  (1ULL << NVDEV_ENGINE_BSP) |
-					  (1ULL << NVDEV_ENGINE_PPP) |
-					  (1ULL << NVDEV_ENGINE_COPY0) |
-					  (1ULL << NVDEV_ENGINE_VIC), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
-			       &chan->ramht);
-	if (ret)
-		return ret;
-
-	nv_parent(chan)->context_attach = nv84_fifo_context_attach;
-	nv_parent(chan)->context_detach = nv84_fifo_context_detach;
-	nv_parent(chan)->object_attach = nv84_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
-	nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
-	nv_wo32(base->ramfc, 0x3c, 0x003f6078);
-	nv_wo32(base->ramfc, 0x44, 0x01003fff);
-	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
-	nv_wo32(base->ramfc, 0x4c, 0xffffffff);
-	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
-	nv_wo32(base->ramfc, 0x78, 0x00000000);
-	nv_wo32(base->ramfc, 0x7c, 0x30000001);
-	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
-				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->base.node->offset >> 4));
-	nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
-	nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_channel_gpfifo_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_fifo_base *base = (void *)parent;
-	struct nv50_fifo_chan *chan;
-	u64 ioffset, ilength;
-	int ret;
-
-	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
-				 "ioffset %016llx ilength %08x\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
-			 args->v0.ilength);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
-					  0x2000, args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_DMAOBJ) |
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_MPEG) |
-					  (1ULL << NVDEV_ENGINE_ME) |
-					  (1ULL << NVDEV_ENGINE_VP) |
-					  (1ULL << NVDEV_ENGINE_CRYPT) |
-					  (1ULL << NVDEV_ENGINE_BSP) |
-					  (1ULL << NVDEV_ENGINE_PPP) |
-					  (1ULL << NVDEV_ENGINE_COPY0) |
-					  (1ULL << NVDEV_ENGINE_VIC), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
-			       &chan->ramht);
-	if (ret)
-		return ret;
-
-	nv_parent(chan)->context_attach = nv84_fifo_context_attach;
-	nv_parent(chan)->context_detach = nv84_fifo_context_detach;
-	nv_parent(chan)->object_attach = nv84_fifo_object_attach;
-	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
-	ioffset = args->v0.ioffset;
-	ilength = order_base_2(args->v0.ilength / 8);
-
-	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
-	nv_wo32(base->ramfc, 0x44, 0x01003fff);
-	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
-	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
-	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
-	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
-	nv_wo32(base->ramfc, 0x78, 0x00000000);
-	nv_wo32(base->ramfc, 0x7c, 0x30000001);
-	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
-				   (4 << 24) /* SEARCH_FULL */ |
-				   (chan->ramht->base.node->offset >> 4));
-	nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
-	nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nv84_fifo_chan_init(struct nouveau_object *object)
-{
-	struct nv50_fifo_priv *priv = (void *)object->engine;
-	struct nv50_fifo_base *base = (void *)object->parent;
-	struct nv50_fifo_chan *chan = (void *)object;
-	struct nouveau_gpuobj *ramfc = base->ramfc;
-	u32 chid = chan->base.chid;
-	int ret;
-
-	ret = nouveau_fifo_channel_init(&chan->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
-	nv50_fifo_playlist_update(priv);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv84_fifo_ofuncs_dma = {
-	.ctor = nv84_fifo_chan_ctor_dma,
-	.dtor = nv50_fifo_chan_dtor,
-	.init = nv84_fifo_chan_init,
-	.fini = nv50_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_ofuncs
-nv84_fifo_ofuncs_ind = {
-	.ctor = nv84_fifo_chan_ctor_ind,
-	.dtor = nv50_fifo_chan_dtor,
-	.init = nv84_fifo_chan_init,
-	.fini = nv50_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv84_fifo_sclass[] = {
-	{ G82_CHANNEL_DMA, &nv84_fifo_ofuncs_dma },
-	{ G82_CHANNEL_GPFIFO, &nv84_fifo_ofuncs_ind },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static int
-nv84_fifo_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nv50_fifo_base *base;
-	int ret;
-
-	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
-				          0x1000, NVOBJ_FLAG_HEAP, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0,
-				 0, &base->pgd);
-	if (ret)
-		return ret;
-
-	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1000,
-				 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0100,
-				 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static struct nouveau_oclass
-nv84_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_fifo_context_ctor,
-		.dtor = nv50_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static void
-nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
-}
-
-static void
-nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nv84_fifo_uevent_func = {
-	.ctor = nouveau_fifo_uevent_ctor,
-	.init = nv84_fifo_uevent_init,
-	.fini = nv84_fifo_uevent_fini,
-};
-
-static int
-nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
-				&priv->playlist[0]);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
-				&priv->playlist[1]);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nv04_fifo_intr;
-	nv_engine(priv)->cclass = &nv84_fifo_cclass;
-	nv_engine(priv)->sclass = nv84_fifo_sclass;
-	priv->base.pause = nv04_fifo_pause;
-	priv->base.start = nv04_fifo_start;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv84_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_fifo_ctor,
-		.dtor = nv50_fifo_dtor,
-		.init = nv50_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
deleted file mode 100644
index 074d434..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engctx.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-struct nvc0_fifo_priv {
-	struct nouveau_fifo base;
-
-	struct work_struct fault;
-	u64 mask;
-
-	struct {
-		struct nouveau_gpuobj *mem[2];
-		int active;
-		wait_queue_head_t wait;
-	} runlist;
-
-	struct {
-		struct nouveau_gpuobj *mem;
-		struct nouveau_vma bar;
-	} user;
-	int spoon_nr;
-};
-
-struct nvc0_fifo_base {
-	struct nouveau_fifo_base base;
-	struct nouveau_gpuobj *pgd;
-	struct nouveau_vm *vm;
-};
-
-struct nvc0_fifo_chan {
-	struct nouveau_fifo_chan base;
-	enum {
-		STOPPED,
-		RUNNING,
-		KILLED
-	} state;
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv)
-{
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nouveau_gpuobj *cur;
-	int i, p;
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	cur = priv->runlist.mem[priv->runlist.active];
-	priv->runlist.active = !priv->runlist.active;
-
-	for (i = 0, p = 0; i < 128; i++) {
-		struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i];
-		if (chan && chan->state == RUNNING) {
-			nv_wo32(cur, p + 0, i);
-			nv_wo32(cur, p + 4, 0x00000004);
-			p += 8;
-		}
-	}
-	bar->flush(bar);
-
-	nv_wr32(priv, 0x002270, cur->addr >> 12);
-	nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
-
-	if (wait_event_timeout(priv->runlist.wait,
-			       !(nv_rd32(priv, 0x00227c) & 0x00100000),
-			       msecs_to_jiffies(2000)) == 0)
-		nv_error(priv, "runlist update timeout\n");
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nvc0_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nvc0_fifo_base *base = (void *)parent->parent;
-	struct nouveau_engctx *ectx = (void *)object;
-	u32 addr;
-	int ret;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
-	case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
-	case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
-	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
-	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
-	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
-	default:
-		return -EINVAL;
-	}
-
-	if (!ectx->vma.node) {
-		ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
-					    NV_MEM_ACCESS_RW, &ectx->vma);
-		if (ret)
-			return ret;
-
-		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
-	}
-
-	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
-	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nvc0_fifo_priv *priv = (void *)parent->engine;
-	struct nvc0_fifo_base *base = (void *)parent->parent;
-	struct nvc0_fifo_chan *chan = (void *)parent;
-	u32 addr;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
-	case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
-	case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
-	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
-	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
-	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
-	default:
-		return -EINVAL;
-	}
-
-	nv_wr32(priv, 0x002634, chan->base.chid);
-	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
-		nv_error(priv, "channel %d [%s] kick timeout\n",
-			 chan->base.chid, nouveau_client_name(chan));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	nv_wo32(base, addr + 0x00, 0x00000000);
-	nv_wo32(base, addr + 0x04, 0x00000000);
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nvc0_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct nv50_channel_gpfifo_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nvc0_fifo_priv *priv = (void *)engine;
-	struct nvc0_fifo_base *base = (void *)parent;
-	struct nvc0_fifo_chan *chan;
-	u64 usermem, ioffset, ilength;
-	int ret, i;
-
-	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
-				 "ioffset %016llx ilength %08x\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
-			 args->v0.ilength);
-	} else
-		return ret;
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
-					  priv->user.bar.offset, 0x1000,
-					  args->v0.pushbuf,
-					  (1ULL << NVDEV_ENGINE_SW) |
-					  (1ULL << NVDEV_ENGINE_GR) |
-					  (1ULL << NVDEV_ENGINE_COPY0) |
-					  (1ULL << NVDEV_ENGINE_COPY1) |
-					  (1ULL << NVDEV_ENGINE_BSP) |
-					  (1ULL << NVDEV_ENGINE_VP) |
-					  (1ULL << NVDEV_ENGINE_PPP), &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
-	nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
-
-	usermem = chan->base.chid * 0x1000;
-	ioffset = args->v0.ioffset;
-	ilength = order_base_2(args->v0.ilength / 8);
-
-	for (i = 0; i < 0x1000; i += 4)
-		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
-
-	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
-	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
-	nv_wo32(base, 0x10, 0x0000face);
-	nv_wo32(base, 0x30, 0xfffff902);
-	nv_wo32(base, 0x48, lower_32_bits(ioffset));
-	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
-	nv_wo32(base, 0x54, 0x00000002);
-	nv_wo32(base, 0x84, 0x20400000);
-	nv_wo32(base, 0x94, 0x30000001);
-	nv_wo32(base, 0x9c, 0x00000100);
-	nv_wo32(base, 0xa4, 0x1f1f1f1f);
-	nv_wo32(base, 0xa8, 0x1f1f1f1f);
-	nv_wo32(base, 0xac, 0x0000001f);
-	nv_wo32(base, 0xb8, 0xf8000000);
-	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
-	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nvc0_fifo_chan_init(struct nouveau_object *object)
-{
-	struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
-	struct nvc0_fifo_priv *priv = (void *)object->engine;
-	struct nvc0_fifo_chan *chan = (void *)object;
-	u32 chid = chan->base.chid;
-	int ret;
-
-	ret = nouveau_fifo_channel_init(&chan->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
-
-	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
-		nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
-		nvc0_fifo_runlist_update(priv);
-	}
-
-	return 0;
-}
-
-static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv);
-
-static int
-nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvc0_fifo_priv *priv = (void *)object->engine;
-	struct nvc0_fifo_chan *chan = (void *)object;
-	u32 chid = chan->base.chid;
-
-	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
-		nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
-		nvc0_fifo_runlist_update(priv);
-	}
-
-	nvc0_fifo_intr_engine(priv);
-
-	nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
-	return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nvc0_fifo_ofuncs = {
-	.ctor = nvc0_fifo_chan_ctor,
-	.dtor = _nouveau_fifo_channel_dtor,
-	.init = nvc0_fifo_chan_init,
-	.fini = nvc0_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nvc0_fifo_sclass[] = {
-	{ FERMI_CHANNEL_GPFIFO, &nvc0_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - instmem heap and vm setup
- ******************************************************************************/
-
-static int
-nvc0_fifo_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nvc0_fifo_base *base;
-	int ret;
-
-	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
-				          0x1000, NVOBJ_FLAG_ZERO_ALLOC |
-					  NVOBJ_FLAG_HEAP, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
-				&base->pgd);
-	if (ret)
-		return ret;
-
-	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
-	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
-	nv_wo32(base, 0x0208, 0xffffffff);
-	nv_wo32(base, 0x020c, 0x000000ff);
-
-	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static void
-nvc0_fifo_context_dtor(struct nouveau_object *object)
-{
-	struct nvc0_fifo_base *base = (void *)object;
-	nouveau_vm_ref(NULL, &base->vm, base->pgd);
-	nouveau_gpuobj_ref(NULL, &base->pgd);
-	nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nvc0_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_fifo_context_ctor,
-		.dtor = nvc0_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static inline int
-nvc0_fifo_engidx(struct nvc0_fifo_priv *priv, u32 engn)
-{
-	switch (engn) {
-	case NVDEV_ENGINE_GR   : engn = 0; break;
-	case NVDEV_ENGINE_BSP  : engn = 1; break;
-	case NVDEV_ENGINE_PPP  : engn = 2; break;
-	case NVDEV_ENGINE_VP   : engn = 3; break;
-	case NVDEV_ENGINE_COPY0: engn = 4; break;
-	case NVDEV_ENGINE_COPY1: engn = 5; break;
-	default:
-		return -1;
-	}
-
-	return engn;
-}
-
-static inline struct nouveau_engine *
-nvc0_fifo_engine(struct nvc0_fifo_priv *priv, u32 engn)
-{
-	switch (engn) {
-	case 0: engn = NVDEV_ENGINE_GR; break;
-	case 1: engn = NVDEV_ENGINE_BSP; break;
-	case 2: engn = NVDEV_ENGINE_PPP; break;
-	case 3: engn = NVDEV_ENGINE_VP; break;
-	case 4: engn = NVDEV_ENGINE_COPY0; break;
-	case 5: engn = NVDEV_ENGINE_COPY1; break;
-	default:
-		return NULL;
-	}
-
-	return nouveau_engine(priv, engn);
-}
-
-static void
-nvc0_fifo_recover_work(struct work_struct *work)
-{
-	struct nvc0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
-	struct nouveau_object *engine;
-	unsigned long flags;
-	u32 engn, engm = 0;
-	u64 mask, todo;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	mask = priv->mask;
-	priv->mask = 0ULL;
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-
-	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
-		engm |= 1 << nvc0_fifo_engidx(priv, engn);
-	nv_mask(priv, 0x002630, engm, engm);
-
-	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
-		if ((engine = (void *)nouveau_engine(priv, engn))) {
-			nv_ofuncs(engine)->fini(engine, false);
-			WARN_ON(nv_ofuncs(engine)->init(engine));
-		}
-	}
-
-	nvc0_fifo_runlist_update(priv);
-	nv_wr32(priv, 0x00262c, engm);
-	nv_mask(priv, 0x002630, engm, 0x00000000);
-}
-
-static void
-nvc0_fifo_recover(struct nvc0_fifo_priv *priv, struct nouveau_engine *engine,
-		  struct nvc0_fifo_chan *chan)
-{
-	struct nouveau_object *engobj = nv_object(engine);
-	u32 chid = chan->base.chid;
-	unsigned long flags;
-
-	nv_error(priv, "%s engine fault on channel %d, recovering...\n",
-		       nv_subdev(engine)->name, chid);
-
-	nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
-	chan->state = KILLED;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	priv->mask |= 1ULL << nv_engidx(engobj);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	schedule_work(&priv->fault);
-}
-
-static int
-nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
-	struct nvc0_fifo_chan *chan = NULL;
-	struct nouveau_handle *bind;
-	unsigned long flags;
-	int ret = -EINVAL;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	if (likely(chid >= priv->base.min && chid <= priv->base.max))
-		chan = (void *)priv->base.channel[chid];
-	if (unlikely(!chan))
-		goto out;
-
-	bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
-	if (likely(bind)) {
-		if (!mthd || !nv_call(bind->object, mthd, data))
-			ret = 0;
-		nouveau_namedb_put(bind);
-	}
-
-out:
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return ret;
-}
-
-static const struct nouveau_enum
-nvc0_fifo_sched_reason[] = {
-	{ 0x0a, "CTXSW_TIMEOUT" },
-	{}
-};
-
-static void
-nvc0_fifo_intr_sched_ctxsw(struct nvc0_fifo_priv *priv)
-{
-	struct nouveau_engine *engine;
-	struct nvc0_fifo_chan *chan;
-	u32 engn;
-
-	for (engn = 0; engn < 6; engn++) {
-		u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
-		u32 busy = (stat & 0x80000000);
-		u32 save = (stat & 0x00100000); /* maybe? */
-		u32 unk0 = (stat & 0x00040000);
-		u32 unk1 = (stat & 0x00001000);
-		u32 chid = (stat & 0x0000007f);
-		(void)save;
-
-		if (busy && unk0 && unk1) {
-			if (!(chan = (void *)priv->base.channel[chid]))
-				continue;
-			if (!(engine = nvc0_fifo_engine(priv, engn)))
-				continue;
-			nvc0_fifo_recover(priv, engine, chan);
-		}
-	}
-}
-
-static void
-nvc0_fifo_intr_sched(struct nvc0_fifo_priv *priv)
-{
-	u32 intr = nv_rd32(priv, 0x00254c);
-	u32 code = intr & 0x000000ff;
-	const struct nouveau_enum *en;
-	char enunk[6] = "";
-
-	en = nouveau_enum_find(nvc0_fifo_sched_reason, code);
-	if (!en)
-		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
-	nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
-
-	switch (code) {
-	case 0x0a:
-		nvc0_fifo_intr_sched_ctxsw(priv);
-		break;
-	default:
-		break;
-	}
-}
-
-static const struct nouveau_enum
-nvc0_fifo_fault_engine[] = {
-	{ 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
-	{ 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB },
-	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
-	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
-	{ 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
-	{ 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP },
-	{ 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP },
-	{ 0x13, "PCOUNTER" },
-	{ 0x14, "PVP", NULL, NVDEV_ENGINE_VP },
-	{ 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 },
-	{ 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 },
-	{ 0x17, "PDAEMON" },
-	{}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_reason[] = {
-	{ 0x00, "PT_NOT_PRESENT" },
-	{ 0x01, "PT_TOO_SHORT" },
-	{ 0x02, "PAGE_NOT_PRESENT" },
-	{ 0x03, "VM_LIMIT_EXCEEDED" },
-	{ 0x04, "NO_CHANNEL" },
-	{ 0x05, "PAGE_SYSTEM_ONLY" },
-	{ 0x06, "PAGE_READ_ONLY" },
-	{ 0x0a, "COMPRESSED_SYSRAM" },
-	{ 0x0c, "INVALID_STORAGE_TYPE" },
-	{}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_hubclient[] = {
-	{ 0x01, "PCOPY0" },
-	{ 0x02, "PCOPY1" },
-	{ 0x04, "DISPATCH" },
-	{ 0x05, "CTXCTL" },
-	{ 0x06, "PFIFO" },
-	{ 0x07, "BAR_READ" },
-	{ 0x08, "BAR_WRITE" },
-	{ 0x0b, "PVP" },
-	{ 0x0c, "PPPP" },
-	{ 0x0d, "PBSP" },
-	{ 0x11, "PCOUNTER" },
-	{ 0x12, "PDAEMON" },
-	{ 0x14, "CCACHE" },
-	{ 0x15, "CCACHE_POST" },
-	{}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_gpcclient[] = {
-	{ 0x01, "TEX" },
-	{ 0x0c, "ESETUP" },
-	{ 0x0e, "CTXCTL" },
-	{ 0x0f, "PROP" },
-	{}
-};
-
-static void
-nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit)
-{
-	u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
-	u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
-	u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
-	u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
-	u32 gpc    = (stat & 0x1f000000) >> 24;
-	u32 client = (stat & 0x00001f00) >> 8;
-	u32 write  = (stat & 0x00000080);
-	u32 hub    = (stat & 0x00000040);
-	u32 reason = (stat & 0x0000000f);
-	struct nouveau_object *engctx = NULL, *object;
-	struct nouveau_engine *engine = NULL;
-	const struct nouveau_enum *er, *eu, *ec;
-	char erunk[6] = "";
-	char euunk[6] = "";
-	char ecunk[6] = "";
-	char gpcid[3] = "";
-
-	er = nouveau_enum_find(nvc0_fifo_fault_reason, reason);
-	if (!er)
-		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
-
-	eu = nouveau_enum_find(nvc0_fifo_fault_engine, unit);
-	if (eu) {
-		switch (eu->data2) {
-		case NVDEV_SUBDEV_BAR:
-			nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
-			break;
-		case NVDEV_SUBDEV_INSTMEM:
-			nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
-			break;
-		case NVDEV_ENGINE_IFB:
-			nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
-			break;
-		default:
-			engine = nouveau_engine(priv, eu->data2);
-			if (engine)
-				engctx = nouveau_engctx_get(engine, inst);
-			break;
-		}
-	} else {
-		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
-	}
-
-	if (hub) {
-		ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client);
-	} else {
-		ec = nouveau_enum_find(nvc0_fifo_fault_gpcclient, client);
-		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
-	}
-
-	if (!ec)
-		snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
-
-	nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
-		       "channel 0x%010llx [%s]\n", write ? "write" : "read",
-		 (u64)vahi << 32 | valo, er ? er->name : erunk,
-		 eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
-		 ec ? ec->name : ecunk, (u64)inst << 12,
-		 nouveau_client_name(engctx));
-
-	object = engctx;
-	while (object) {
-		switch (nv_mclass(object)) {
-		case FERMI_CHANNEL_GPFIFO:
-			nvc0_fifo_recover(priv, engine, (void *)object);
-			break;
-		}
-		object = object->parent;
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static const struct nouveau_bitfield
-nvc0_fifo_pbdma_intr[] = {
-/*	{ 0x00008000, "" }	seen with null ib push */
-	{ 0x00200000, "ILLEGAL_MTHD" },
-	{ 0x00800000, "EMPTY_SUBC" },
-	{}
-};
-
-static void
-nvc0_fifo_intr_pbdma(struct nvc0_fifo_priv *priv, int unit)
-{
-	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
-	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
-	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
-	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00003ffc);
-	u32 show = stat;
-
-	if (stat & 0x00800000) {
-		if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
-			show &= ~0x00800000;
-	}
-
-	if (show) {
-		nv_error(priv, "PBDMA%d:", unit);
-		nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show);
-		pr_cont("\n");
-		nv_error(priv,
-			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
-			 unit, chid,
-			 nouveau_client_name_for_fifo_chid(&priv->base, chid),
-			 subc, mthd, data);
-	}
-
-	nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
-	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
-}
-
-static void
-nvc0_fifo_intr_runlist(struct nvc0_fifo_priv *priv)
-{
-	u32 intr = nv_rd32(priv, 0x002a00);
-
-	if (intr & 0x10000000) {
-		wake_up(&priv->runlist.wait);
-		nv_wr32(priv, 0x002a00, 0x10000000);
-		intr &= ~0x10000000;
-	}
-
-	if (intr) {
-		nv_error(priv, "RUNLIST 0x%08x\n", intr);
-		nv_wr32(priv, 0x002a00, intr);
-	}
-}
-
-static void
-nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
-{
-	u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
-	u32 inte = nv_rd32(priv, 0x002628);
-	u32 unkn;
-
-	nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
-
-	for (unkn = 0; unkn < 8; unkn++) {
-		u32 ints = (intr >> (unkn * 0x04)) & inte;
-		if (ints & 0x1) {
-			nouveau_fifo_uevent(&priv->base);
-			ints &= ~1;
-		}
-		if (ints) {
-			nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
-			nv_mask(priv, 0x002628, ints, 0);
-		}
-	}
-}
-
-static void
-nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv)
-{
-	u32 mask = nv_rd32(priv, 0x0025a4);
-	while (mask) {
-		u32 unit = __ffs(mask);
-		nvc0_fifo_intr_engine_unit(priv, unit);
-		mask &= ~(1 << unit);
-	}
-}
-
-static void
-nvc0_fifo_intr(struct nouveau_subdev *subdev)
-{
-	struct nvc0_fifo_priv *priv = (void *)subdev;
-	u32 mask = nv_rd32(priv, 0x002140);
-	u32 stat = nv_rd32(priv, 0x002100) & mask;
-
-	if (stat & 0x00000001) {
-		u32 intr = nv_rd32(priv, 0x00252c);
-		nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
-		nv_wr32(priv, 0x002100, 0x00000001);
-		stat &= ~0x00000001;
-	}
-
-	if (stat & 0x00000100) {
-		nvc0_fifo_intr_sched(priv);
-		nv_wr32(priv, 0x002100, 0x00000100);
-		stat &= ~0x00000100;
-	}
-
-	if (stat & 0x00010000) {
-		u32 intr = nv_rd32(priv, 0x00256c);
-		nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
-		nv_wr32(priv, 0x002100, 0x00010000);
-		stat &= ~0x00010000;
-	}
-
-	if (stat & 0x01000000) {
-		u32 intr = nv_rd32(priv, 0x00258c);
-		nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
-		nv_wr32(priv, 0x002100, 0x01000000);
-		stat &= ~0x01000000;
-	}
-
-	if (stat & 0x10000000) {
-		u32 mask = nv_rd32(priv, 0x00259c);
-		while (mask) {
-			u32 unit = __ffs(mask);
-			nvc0_fifo_intr_fault(priv, unit);
-			nv_wr32(priv, 0x00259c, (1 << unit));
-			mask &= ~(1 << unit);
-		}
-		stat &= ~0x10000000;
-	}
-
-	if (stat & 0x20000000) {
-		u32 mask = nv_rd32(priv, 0x0025a0);
-		while (mask) {
-			u32 unit = __ffs(mask);
-			nvc0_fifo_intr_pbdma(priv, unit);
-			nv_wr32(priv, 0x0025a0, (1 << unit));
-			mask &= ~(1 << unit);
-		}
-		stat &= ~0x20000000;
-	}
-
-	if (stat & 0x40000000) {
-		nvc0_fifo_intr_runlist(priv);
-		stat &= ~0x40000000;
-	}
-
-	if (stat & 0x80000000) {
-		nvc0_fifo_intr_engine(priv);
-		stat &= ~0x80000000;
-	}
-
-	if (stat) {
-		nv_error(priv, "INTR 0x%08x\n", stat);
-		nv_mask(priv, 0x002140, stat, 0x00000000);
-		nv_wr32(priv, 0x002100, stat);
-	}
-}
-
-static void
-nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
-}
-
-static void
-nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nvc0_fifo_uevent_func = {
-	.ctor = nouveau_fifo_uevent_ctor,
-	.init = nvc0_fifo_uevent_init,
-	.fini = nvc0_fifo_uevent_fini,
-};
-
-static int
-nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nvc0_fifo_priv *priv;
-	int ret;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	INIT_WORK(&priv->fault, nvc0_fifo_recover_work);
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
-				&priv->runlist.mem[0]);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
-				&priv->runlist.mem[1]);
-	if (ret)
-		return ret;
-
-	init_waitqueue_head(&priv->runlist.wait);
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
-				&priv->user.mem);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
-				&priv->user.bar);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nvc0_fifo_intr;
-	nv_engine(priv)->cclass = &nvc0_fifo_cclass;
-	nv_engine(priv)->sclass = nvc0_fifo_sclass;
-	return 0;
-}
-
-static void
-nvc0_fifo_dtor(struct nouveau_object *object)
-{
-	struct nvc0_fifo_priv *priv = (void *)object;
-
-	nouveau_gpuobj_unmap(&priv->user.bar);
-	nouveau_gpuobj_ref(NULL, &priv->user.mem);
-	nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]);
-	nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]);
-
-	nouveau_fifo_destroy(&priv->base);
-}
-
-static int
-nvc0_fifo_init(struct nouveau_object *object)
-{
-	struct nvc0_fifo_priv *priv = (void *)object;
-	int ret, i;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x000204, 0xffffffff);
-	nv_wr32(priv, 0x002204, 0xffffffff);
-
-	priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
-	nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
-
-	/* assign engines to PBDMAs */
-	if (priv->spoon_nr >= 3) {
-		nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
-		nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
-		nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
-		nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
-		nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
-		nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
-	}
-
-	/* PBDMA[n] */
-	for (i = 0; i < priv->spoon_nr; i++) {
-		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
-		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
-		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
-	}
-
-	nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
-	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
-	nv_wr32(priv, 0x002100, 0xffffffff);
-	nv_wr32(priv, 0x002140, 0x7fffffff);
-	nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
-	return 0;
-}
-
-struct nouveau_oclass *
-nvc0_fifo_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(FIFO, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_fifo_ctor,
-		.dtor = nvc0_fifo_dtor,
-		.init = nvc0_fifo_init,
-		.fini = _nouveau_fifo_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
deleted file mode 100644
index 6a8db7c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ /dev/null
@@ -1,1147 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engctx.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <engine/dmaobj.h>
-
-#include "nve0.h"
-
-#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
-static const struct {
-	u64 subdev;
-	u64 mask;
-} fifo_engine[] = {
-	_(NVDEV_ENGINE_GR      , (1ULL << NVDEV_ENGINE_SW) |
-				 (1ULL << NVDEV_ENGINE_COPY2)),
-	_(NVDEV_ENGINE_VP      , 0),
-	_(NVDEV_ENGINE_PPP     , 0),
-	_(NVDEV_ENGINE_BSP     , 0),
-	_(NVDEV_ENGINE_COPY0   , 0),
-	_(NVDEV_ENGINE_COPY1   , 0),
-	_(NVDEV_ENGINE_VENC    , 0),
-};
-#undef _
-#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
-
-struct nve0_fifo_engn {
-	struct nouveau_gpuobj *runlist[2];
-	int cur_runlist;
-	wait_queue_head_t wait;
-};
-
-struct nve0_fifo_priv {
-	struct nouveau_fifo base;
-
-	struct work_struct fault;
-	u64 mask;
-
-	struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
-	struct {
-		struct nouveau_gpuobj *mem;
-		struct nouveau_vma bar;
-	} user;
-	int spoon_nr;
-};
-
-struct nve0_fifo_base {
-	struct nouveau_fifo_base base;
-	struct nouveau_gpuobj *pgd;
-	struct nouveau_vm *vm;
-};
-
-struct nve0_fifo_chan {
-	struct nouveau_fifo_chan base;
-	u32 engine;
-	enum {
-		STOPPED,
-		RUNNING,
-		KILLED
-	} state;
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
-{
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nve0_fifo_engn *engn = &priv->engine[engine];
-	struct nouveau_gpuobj *cur;
-	int i, p;
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	cur = engn->runlist[engn->cur_runlist];
-	engn->cur_runlist = !engn->cur_runlist;
-
-	for (i = 0, p = 0; i < priv->base.max; i++) {
-		struct nve0_fifo_chan *chan = (void *)priv->base.channel[i];
-		if (chan && chan->state == RUNNING && chan->engine == engine) {
-			nv_wo32(cur, p + 0, i);
-			nv_wo32(cur, p + 4, 0x00000000);
-			p += 8;
-		}
-	}
-	bar->flush(bar);
-
-	nv_wr32(priv, 0x002270, cur->addr >> 12);
-	nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
-
-	if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
-			       (engine * 0x08)) & 0x00100000),
-				msecs_to_jiffies(2000)) == 0)
-		nv_error(priv, "runlist %d update timeout\n", engine);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nve0_fifo_context_attach(struct nouveau_object *parent,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nve0_fifo_base *base = (void *)parent->parent;
-	struct nouveau_engctx *ectx = (void *)object;
-	u32 addr;
-	int ret;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   :
-		return 0;
-	case NVDEV_ENGINE_COPY0:
-	case NVDEV_ENGINE_COPY1:
-	case NVDEV_ENGINE_COPY2:
-		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
-		return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
-	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
-	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
-	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
-	default:
-		return -EINVAL;
-	}
-
-	if (!ectx->vma.node) {
-		ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
-					    NV_MEM_ACCESS_RW, &ectx->vma);
-		if (ret)
-			return ret;
-
-		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
-	}
-
-	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
-	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
-			 struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nve0_fifo_priv *priv = (void *)parent->engine;
-	struct nve0_fifo_base *base = (void *)parent->parent;
-	struct nve0_fifo_chan *chan = (void *)parent;
-	u32 addr;
-
-	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_COPY0:
-	case NVDEV_ENGINE_COPY1:
-	case NVDEV_ENGINE_COPY2: addr = 0x0000; break;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
-	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
-	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
-	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
-	default:
-		return -EINVAL;
-	}
-
-	nv_wr32(priv, 0x002634, chan->base.chid);
-	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
-		nv_error(priv, "channel %d [%s] kick timeout\n",
-			 chan->base.chid, nouveau_client_name(chan));
-		if (suspend)
-			return -EBUSY;
-	}
-
-	if (addr) {
-		nv_wo32(base, addr + 0x00, 0x00000000);
-		nv_wo32(base, addr + 0x04, 0x00000000);
-		bar->flush(bar);
-	}
-
-	return 0;
-}
-
-static int
-nve0_fifo_chan_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	union {
-		struct kepler_channel_gpfifo_a_v0 v0;
-	} *args = data;
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nve0_fifo_priv *priv = (void *)engine;
-	struct nve0_fifo_base *base = (void *)parent;
-	struct nve0_fifo_chan *chan;
-	u64 usermem, ioffset, ilength;
-	int ret, i;
-
-	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
-				 "ioffset %016llx ilength %08x engine %08x\n",
-			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
-			 args->v0.ilength, args->v0.engine);
-	} else
-		return ret;
-
-	for (i = 0; i < FIFO_ENGINE_NR; i++) {
-		if (args->v0.engine & (1 << i)) {
-			if (nouveau_engine(parent, fifo_engine[i].subdev)) {
-				args->v0.engine = (1 << i);
-				break;
-			}
-		}
-	}
-
-	if (i == FIFO_ENGINE_NR) {
-		nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine);
-		return -ENODEV;
-	}
-
-	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
-					  priv->user.bar.offset, 0x200,
-					  args->v0.pushbuf,
-					  fifo_engine[i].mask, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	args->v0.chid = chan->base.chid;
-
-	nv_parent(chan)->context_attach = nve0_fifo_context_attach;
-	nv_parent(chan)->context_detach = nve0_fifo_context_detach;
-	chan->engine = i;
-
-	usermem = chan->base.chid * 0x200;
-	ioffset = args->v0.ioffset;
-	ilength = order_base_2(args->v0.ilength / 8);
-
-	for (i = 0; i < 0x200; i += 4)
-		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
-
-	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
-	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
-	nv_wo32(base, 0x10, 0x0000face);
-	nv_wo32(base, 0x30, 0xfffff902);
-	nv_wo32(base, 0x48, lower_32_bits(ioffset));
-	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
-	nv_wo32(base, 0x84, 0x20400000);
-	nv_wo32(base, 0x94, 0x30000001);
-	nv_wo32(base, 0x9c, 0x00000100);
-	nv_wo32(base, 0xac, 0x0000001f);
-	nv_wo32(base, 0xe8, chan->base.chid);
-	nv_wo32(base, 0xb8, 0xf8000000);
-	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
-	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
-	bar->flush(bar);
-	return 0;
-}
-
-static int
-nve0_fifo_chan_init(struct nouveau_object *object)
-{
-	struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
-	struct nve0_fifo_priv *priv = (void *)object->engine;
-	struct nve0_fifo_chan *chan = (void *)object;
-	u32 chid = chan->base.chid;
-	int ret;
-
-	ret = nouveau_fifo_channel_init(&chan->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
-	nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
-
-	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
-		nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
-		nve0_fifo_runlist_update(priv, chan->engine);
-		nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
-	}
-
-	return 0;
-}
-
-static int
-nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nve0_fifo_priv *priv = (void *)object->engine;
-	struct nve0_fifo_chan *chan = (void *)object;
-	u32 chid = chan->base.chid;
-
-	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
-		nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
-		nve0_fifo_runlist_update(priv, chan->engine);
-	}
-
-	nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
-	return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nve0_fifo_ofuncs = {
-	.ctor = nve0_fifo_chan_ctor,
-	.dtor = _nouveau_fifo_channel_dtor,
-	.init = nve0_fifo_chan_init,
-	.fini = nve0_fifo_chan_fini,
-	.map  = _nouveau_fifo_channel_map,
-	.rd32 = _nouveau_fifo_channel_rd32,
-	.wr32 = _nouveau_fifo_channel_wr32,
-	.ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nve0_fifo_sclass[] = {
-	{ KEPLER_CHANNEL_GPFIFO_A, &nve0_fifo_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * FIFO context - instmem heap and vm setup
- ******************************************************************************/
-
-static int
-nve0_fifo_context_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	struct nve0_fifo_base *base;
-	int ret;
-
-	ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
-				          0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
-	*pobject = nv_object(base);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
-				&base->pgd);
-	if (ret)
-		return ret;
-
-	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
-	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
-	nv_wo32(base, 0x0208, 0xffffffff);
-	nv_wo32(base, 0x020c, 0x000000ff);
-
-	ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static void
-nve0_fifo_context_dtor(struct nouveau_object *object)
-{
-	struct nve0_fifo_base *base = (void *)object;
-	nouveau_vm_ref(NULL, &base->vm, base->pgd);
-	nouveau_gpuobj_ref(NULL, &base->pgd);
-	nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nve0_fifo_cclass = {
-	.handle = NV_ENGCTX(FIFO, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_fifo_context_ctor,
-		.dtor = nve0_fifo_context_dtor,
-		.init = _nouveau_fifo_context_init,
-		.fini = _nouveau_fifo_context_fini,
-		.rd32 = _nouveau_fifo_context_rd32,
-		.wr32 = _nouveau_fifo_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static inline int
-nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn)
-{
-	switch (engn) {
-	case NVDEV_ENGINE_GR   :
-	case NVDEV_ENGINE_COPY2: engn = 0; break;
-	case NVDEV_ENGINE_BSP  : engn = 1; break;
-	case NVDEV_ENGINE_PPP  : engn = 2; break;
-	case NVDEV_ENGINE_VP   : engn = 3; break;
-	case NVDEV_ENGINE_COPY0: engn = 4; break;
-	case NVDEV_ENGINE_COPY1: engn = 5; break;
-	case NVDEV_ENGINE_VENC : engn = 6; break;
-	default:
-		return -1;
-	}
-
-	return engn;
-}
-
-static inline struct nouveau_engine *
-nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn)
-{
-	if (engn >= ARRAY_SIZE(fifo_engine))
-		return NULL;
-	return nouveau_engine(priv, fifo_engine[engn].subdev);
-}
-
-static void
-nve0_fifo_recover_work(struct work_struct *work)
-{
-	struct nve0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
-	struct nouveau_object *engine;
-	unsigned long flags;
-	u32 engn, engm = 0;
-	u64 mask, todo;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	mask = priv->mask;
-	priv->mask = 0ULL;
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-
-	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
-		engm |= 1 << nve0_fifo_engidx(priv, engn);
-	nv_mask(priv, 0x002630, engm, engm);
-
-	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
-		if ((engine = (void *)nouveau_engine(priv, engn))) {
-			nv_ofuncs(engine)->fini(engine, false);
-			WARN_ON(nv_ofuncs(engine)->init(engine));
-		}
-		nve0_fifo_runlist_update(priv, nve0_fifo_engidx(priv, engn));
-	}
-
-	nv_wr32(priv, 0x00262c, engm);
-	nv_mask(priv, 0x002630, engm, 0x00000000);
-}
-
-static void
-nve0_fifo_recover(struct nve0_fifo_priv *priv, struct nouveau_engine *engine,
-		  struct nve0_fifo_chan *chan)
-{
-	struct nouveau_object *engobj = nv_object(engine);
-	u32 chid = chan->base.chid;
-	unsigned long flags;
-
-	nv_error(priv, "%s engine fault on channel %d, recovering...\n",
-		       nv_subdev(engine)->name, chid);
-
-	nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
-	chan->state = KILLED;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	priv->mask |= 1ULL << nv_engidx(engobj);
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	schedule_work(&priv->fault);
-}
-
-static int
-nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
-	struct nve0_fifo_chan *chan = NULL;
-	struct nouveau_handle *bind;
-	unsigned long flags;
-	int ret = -EINVAL;
-
-	spin_lock_irqsave(&priv->base.lock, flags);
-	if (likely(chid >= priv->base.min && chid <= priv->base.max))
-		chan = (void *)priv->base.channel[chid];
-	if (unlikely(!chan))
-		goto out;
-
-	bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
-	if (likely(bind)) {
-		if (!mthd || !nv_call(bind->object, mthd, data))
-			ret = 0;
-		nouveau_namedb_put(bind);
-	}
-
-out:
-	spin_unlock_irqrestore(&priv->base.lock, flags);
-	return ret;
-}
-
-static const struct nouveau_enum
-nve0_fifo_bind_reason[] = {
-	{ 0x01, "BIND_NOT_UNBOUND" },
-	{ 0x02, "SNOOP_WITHOUT_BAR1" },
-	{ 0x03, "UNBIND_WHILE_RUNNING" },
-	{ 0x05, "INVALID_RUNLIST" },
-	{ 0x06, "INVALID_CTX_TGT" },
-	{ 0x0b, "UNBIND_WHILE_PARKED" },
-	{}
-};
-
-static void
-nve0_fifo_intr_bind(struct nve0_fifo_priv *priv)
-{
-	u32 intr = nv_rd32(priv, 0x00252c);
-	u32 code = intr & 0x000000ff;
-	const struct nouveau_enum *en;
-	char enunk[6] = "";
-
-	en = nouveau_enum_find(nve0_fifo_bind_reason, code);
-	if (!en)
-		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
-	nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
-}
-
-static const struct nouveau_enum
-nve0_fifo_sched_reason[] = {
-	{ 0x0a, "CTXSW_TIMEOUT" },
-	{}
-};
-
-static void
-nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv)
-{
-	struct nouveau_engine *engine;
-	struct nve0_fifo_chan *chan;
-	u32 engn;
-
-	for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
-		u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
-		u32 busy = (stat & 0x80000000);
-		u32 next = (stat & 0x07ff0000) >> 16;
-		u32 chsw = (stat & 0x00008000);
-		u32 save = (stat & 0x00004000);
-		u32 load = (stat & 0x00002000);
-		u32 prev = (stat & 0x000007ff);
-		u32 chid = load ? next : prev;
-		(void)save;
-
-		if (busy && chsw) {
-			if (!(chan = (void *)priv->base.channel[chid]))
-				continue;
-			if (!(engine = nve0_fifo_engine(priv, engn)))
-				continue;
-			nve0_fifo_recover(priv, engine, chan);
-		}
-	}
-}
-
-static void
-nve0_fifo_intr_sched(struct nve0_fifo_priv *priv)
-{
-	u32 intr = nv_rd32(priv, 0x00254c);
-	u32 code = intr & 0x000000ff;
-	const struct nouveau_enum *en;
-	char enunk[6] = "";
-
-	en = nouveau_enum_find(nve0_fifo_sched_reason, code);
-	if (!en)
-		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
-	nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
-
-	switch (code) {
-	case 0x0a:
-		nve0_fifo_intr_sched_ctxsw(priv);
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv)
-{
-	u32 stat = nv_rd32(priv, 0x00256c);
-	nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
-	nv_wr32(priv, 0x00256c, stat);
-}
-
-static void
-nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv)
-{
-	u32 stat = nv_rd32(priv, 0x00259c);
-	nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
-}
-
-static const struct nouveau_enum
-nve0_fifo_fault_engine[] = {
-	{ 0x00, "GR", NULL, NVDEV_ENGINE_GR },
-	{ 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
-	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
-	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
-	{ 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
-	{ 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
-	{ 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
-	{ 0x10, "MSVLD", NULL, NVDEV_ENGINE_BSP },
-	{ 0x11, "MSPPP", NULL, NVDEV_ENGINE_PPP },
-	{ 0x13, "PERF" },
-	{ 0x14, "MSPDEC", NULL, NVDEV_ENGINE_VP },
-	{ 0x15, "CE0", NULL, NVDEV_ENGINE_COPY0 },
-	{ 0x16, "CE1", NULL, NVDEV_ENGINE_COPY1 },
-	{ 0x17, "PMU" },
-	{ 0x19, "MSENC", NULL, NVDEV_ENGINE_VENC },
-	{ 0x1b, "CE2", NULL, NVDEV_ENGINE_COPY2 },
-	{}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_reason[] = {
-	{ 0x00, "PDE" },
-	{ 0x01, "PDE_SIZE" },
-	{ 0x02, "PTE" },
-	{ 0x03, "VA_LIMIT_VIOLATION" },
-	{ 0x04, "UNBOUND_INST_BLOCK" },
-	{ 0x05, "PRIV_VIOLATION" },
-	{ 0x06, "RO_VIOLATION" },
-	{ 0x07, "WO_VIOLATION" },
-	{ 0x08, "PITCH_MASK_VIOLATION" },
-	{ 0x09, "WORK_CREATION" },
-	{ 0x0a, "UNSUPPORTED_APERTURE" },
-	{ 0x0b, "COMPRESSION_FAILURE" },
-	{ 0x0c, "UNSUPPORTED_KIND" },
-	{ 0x0d, "REGION_VIOLATION" },
-	{ 0x0e, "BOTH_PTES_VALID" },
-	{ 0x0f, "INFO_TYPE_POISONED" },
-	{}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_hubclient[] = {
-	{ 0x00, "VIP" },
-	{ 0x01, "CE0" },
-	{ 0x02, "CE1" },
-	{ 0x03, "DNISO" },
-	{ 0x04, "FE" },
-	{ 0x05, "FECS" },
-	{ 0x06, "HOST" },
-	{ 0x07, "HOST_CPU" },
-	{ 0x08, "HOST_CPU_NB" },
-	{ 0x09, "ISO" },
-	{ 0x0a, "MMU" },
-	{ 0x0b, "MSPDEC" },
-	{ 0x0c, "MSPPP" },
-	{ 0x0d, "MSVLD" },
-	{ 0x0e, "NISO" },
-	{ 0x0f, "P2P" },
-	{ 0x10, "PD" },
-	{ 0x11, "PERF" },
-	{ 0x12, "PMU" },
-	{ 0x13, "RASTERTWOD" },
-	{ 0x14, "SCC" },
-	{ 0x15, "SCC_NB" },
-	{ 0x16, "SEC" },
-	{ 0x17, "SSYNC" },
-	{ 0x18, "GR_COPY" },
-	{ 0x19, "CE2" },
-	{ 0x1a, "XV" },
-	{ 0x1b, "MMU_NB" },
-	{ 0x1c, "MSENC" },
-	{ 0x1d, "DFALCON" },
-	{ 0x1e, "SKED" },
-	{ 0x1f, "AFALCON" },
-	{}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_gpcclient[] = {
-	{ 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
-	{ 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
-	{ 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
-	{ 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
-	{ 0x0c, "RAST" },
-	{ 0x0d, "GCC" },
-	{ 0x0e, "GPCCS" },
-	{ 0x0f, "PROP_0" },
-	{ 0x10, "PROP_1" },
-	{ 0x11, "PROP_2" },
-	{ 0x12, "PROP_3" },
-	{ 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
-	{ 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
-	{ 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
-	{ 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
-	{ 0x1f, "GPM" },
-	{ 0x20, "LTP_UTLB_0" },
-	{ 0x21, "LTP_UTLB_1" },
-	{ 0x22, "LTP_UTLB_2" },
-	{ 0x23, "LTP_UTLB_3" },
-	{ 0x24, "GPC_RGG_UTLB" },
-	{}
-};
-
-static void
-nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
-{
-	u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
-	u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
-	u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
-	u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
-	u32 gpc    = (stat & 0x1f000000) >> 24;
-	u32 client = (stat & 0x00001f00) >> 8;
-	u32 write  = (stat & 0x00000080);
-	u32 hub    = (stat & 0x00000040);
-	u32 reason = (stat & 0x0000000f);
-	struct nouveau_object *engctx = NULL, *object;
-	struct nouveau_engine *engine = NULL;
-	const struct nouveau_enum *er, *eu, *ec;
-	char erunk[6] = "";
-	char euunk[6] = "";
-	char ecunk[6] = "";
-	char gpcid[3] = "";
-
-	er = nouveau_enum_find(nve0_fifo_fault_reason, reason);
-	if (!er)
-		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
-
-	eu = nouveau_enum_find(nve0_fifo_fault_engine, unit);
-	if (eu) {
-		switch (eu->data2) {
-		case NVDEV_SUBDEV_BAR:
-			nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
-			break;
-		case NVDEV_SUBDEV_INSTMEM:
-			nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
-			break;
-		case NVDEV_ENGINE_IFB:
-			nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
-			break;
-		default:
-			engine = nouveau_engine(priv, eu->data2);
-			if (engine)
-				engctx = nouveau_engctx_get(engine, inst);
-			break;
-		}
-	} else {
-		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
-	}
-
-	if (hub) {
-		ec = nouveau_enum_find(nve0_fifo_fault_hubclient, client);
-	} else {
-		ec = nouveau_enum_find(nve0_fifo_fault_gpcclient, client);
-		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
-	}
-
-	if (!ec)
-		snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
-
-	nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
-		       "channel 0x%010llx [%s]\n", write ? "write" : "read",
-		 (u64)vahi << 32 | valo, er ? er->name : erunk,
-		 eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
-		 ec ? ec->name : ecunk, (u64)inst << 12,
-		 nouveau_client_name(engctx));
-
-	object = engctx;
-	while (object) {
-		switch (nv_mclass(object)) {
-		case KEPLER_CHANNEL_GPFIFO_A:
-			nve0_fifo_recover(priv, engine, (void *)object);
-			break;
-		}
-		object = object->parent;
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static const struct nouveau_bitfield nve0_fifo_pbdma_intr_0[] = {
-	{ 0x00000001, "MEMREQ" },
-	{ 0x00000002, "MEMACK_TIMEOUT" },
-	{ 0x00000004, "MEMACK_EXTRA" },
-	{ 0x00000008, "MEMDAT_TIMEOUT" },
-	{ 0x00000010, "MEMDAT_EXTRA" },
-	{ 0x00000020, "MEMFLUSH" },
-	{ 0x00000040, "MEMOP" },
-	{ 0x00000080, "LBCONNECT" },
-	{ 0x00000100, "LBREQ" },
-	{ 0x00000200, "LBACK_TIMEOUT" },
-	{ 0x00000400, "LBACK_EXTRA" },
-	{ 0x00000800, "LBDAT_TIMEOUT" },
-	{ 0x00001000, "LBDAT_EXTRA" },
-	{ 0x00002000, "GPFIFO" },
-	{ 0x00004000, "GPPTR" },
-	{ 0x00008000, "GPENTRY" },
-	{ 0x00010000, "GPCRC" },
-	{ 0x00020000, "PBPTR" },
-	{ 0x00040000, "PBENTRY" },
-	{ 0x00080000, "PBCRC" },
-	{ 0x00100000, "XBARCONNECT" },
-	{ 0x00200000, "METHOD" },
-	{ 0x00400000, "METHODCRC" },
-	{ 0x00800000, "DEVICE" },
-	{ 0x02000000, "SEMAPHORE" },
-	{ 0x04000000, "ACQUIRE" },
-	{ 0x08000000, "PRI" },
-	{ 0x20000000, "NO_CTXSW_SEG" },
-	{ 0x40000000, "PBSEG" },
-	{ 0x80000000, "SIGNATURE" },
-	{}
-};
-
-static void
-nve0_fifo_intr_pbdma_0(struct nve0_fifo_priv *priv, int unit)
-{
-	u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
-	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
-	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
-	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
-	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00003ffc);
-	u32 show = stat;
-
-	if (stat & 0x00800000) {
-		if (!nve0_fifo_swmthd(priv, chid, mthd, data))
-			show &= ~0x00800000;
-		nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
-	}
-
-	if (show) {
-		nv_error(priv, "PBDMA%d:", unit);
-		nouveau_bitfield_print(nve0_fifo_pbdma_intr_0, show);
-		pr_cont("\n");
-		nv_error(priv,
-			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
-			 unit, chid,
-			 nouveau_client_name_for_fifo_chid(&priv->base, chid),
-			 subc, mthd, data);
-	}
-
-	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
-}
-
-static const struct nouveau_bitfield nve0_fifo_pbdma_intr_1[] = {
-	{ 0x00000001, "HCE_RE_ILLEGAL_OP" },
-	{ 0x00000002, "HCE_RE_ALIGNB" },
-	{ 0x00000004, "HCE_PRIV" },
-	{ 0x00000008, "HCE_ILLEGAL_MTHD" },
-	{ 0x00000010, "HCE_ILLEGAL_CLASS" },
-	{}
-};
-
-static void
-nve0_fifo_intr_pbdma_1(struct nve0_fifo_priv *priv, int unit)
-{
-	u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
-	u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
-	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
-
-	if (stat) {
-		nv_error(priv, "PBDMA%d:", unit);
-		nouveau_bitfield_print(nve0_fifo_pbdma_intr_1, stat);
-		pr_cont("\n");
-		nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
-			 nv_rd32(priv, 0x040150 + (unit * 0x2000)),
-			 nv_rd32(priv, 0x040154 + (unit * 0x2000)));
-	}
-
-	nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
-}
-
-static void
-nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
-{
-	u32 mask = nv_rd32(priv, 0x002a00);
-	while (mask) {
-		u32 engn = __ffs(mask);
-		wake_up(&priv->engine[engn].wait);
-		nv_wr32(priv, 0x002a00, 1 << engn);
-		mask &= ~(1 << engn);
-	}
-}
-
-static void
-nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
-{
-	nouveau_fifo_uevent(&priv->base);
-}
-
-static void
-nve0_fifo_intr(struct nouveau_subdev *subdev)
-{
-	struct nve0_fifo_priv *priv = (void *)subdev;
-	u32 mask = nv_rd32(priv, 0x002140);
-	u32 stat = nv_rd32(priv, 0x002100) & mask;
-
-	if (stat & 0x00000001) {
-		nve0_fifo_intr_bind(priv);
-		nv_wr32(priv, 0x002100, 0x00000001);
-		stat &= ~0x00000001;
-	}
-
-	if (stat & 0x00000010) {
-		nv_error(priv, "PIO_ERROR\n");
-		nv_wr32(priv, 0x002100, 0x00000010);
-		stat &= ~0x00000010;
-	}
-
-	if (stat & 0x00000100) {
-		nve0_fifo_intr_sched(priv);
-		nv_wr32(priv, 0x002100, 0x00000100);
-		stat &= ~0x00000100;
-	}
-
-	if (stat & 0x00010000) {
-		nve0_fifo_intr_chsw(priv);
-		nv_wr32(priv, 0x002100, 0x00010000);
-		stat &= ~0x00010000;
-	}
-
-	if (stat & 0x00800000) {
-		nv_error(priv, "FB_FLUSH_TIMEOUT\n");
-		nv_wr32(priv, 0x002100, 0x00800000);
-		stat &= ~0x00800000;
-	}
-
-	if (stat & 0x01000000) {
-		nv_error(priv, "LB_ERROR\n");
-		nv_wr32(priv, 0x002100, 0x01000000);
-		stat &= ~0x01000000;
-	}
-
-	if (stat & 0x08000000) {
-		nve0_fifo_intr_dropped_fault(priv);
-		nv_wr32(priv, 0x002100, 0x08000000);
-		stat &= ~0x08000000;
-	}
-
-	if (stat & 0x10000000) {
-		u32 mask = nv_rd32(priv, 0x00259c);
-		while (mask) {
-			u32 unit = __ffs(mask);
-			nve0_fifo_intr_fault(priv, unit);
-			nv_wr32(priv, 0x00259c, (1 << unit));
-			mask &= ~(1 << unit);
-		}
-		stat &= ~0x10000000;
-	}
-
-	if (stat & 0x20000000) {
-		u32 mask = nv_rd32(priv, 0x0025a0);
-		while (mask) {
-			u32 unit = __ffs(mask);
-			nve0_fifo_intr_pbdma_0(priv, unit);
-			nve0_fifo_intr_pbdma_1(priv, unit);
-			nv_wr32(priv, 0x0025a0, (1 << unit));
-			mask &= ~(1 << unit);
-		}
-		stat &= ~0x20000000;
-	}
-
-	if (stat & 0x40000000) {
-		nve0_fifo_intr_runlist(priv);
-		stat &= ~0x40000000;
-	}
-
-	if (stat & 0x80000000) {
-		nv_wr32(priv, 0x002100, 0x80000000);
-		nve0_fifo_intr_engine(priv);
-		stat &= ~0x80000000;
-	}
-
-	if (stat) {
-		nv_error(priv, "INTR 0x%08x\n", stat);
-		nv_mask(priv, 0x002140, stat, 0x00000000);
-		nv_wr32(priv, 0x002100, stat);
-	}
-}
-
-static void
-nve0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
-}
-
-static void
-nve0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
-	nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nve0_fifo_uevent_func = {
-	.ctor = nouveau_fifo_uevent_ctor,
-	.init = nve0_fifo_uevent_init,
-	.fini = nve0_fifo_uevent_fini,
-};
-
-int
-nve0_fifo_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nve0_fifo_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fifo_fini(&priv->base, suspend);
-	if (ret)
-		return ret;
-
-	/* allow mmu fault interrupts, even when we're not using fifo */
-	nv_mask(priv, 0x002140, 0x10000000, 0x10000000);
-	return 0;
-}
-
-int
-nve0_fifo_init(struct nouveau_object *object)
-{
-	struct nve0_fifo_priv *priv = (void *)object;
-	int ret, i;
-
-	ret = nouveau_fifo_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* enable all available PBDMA units */
-	nv_wr32(priv, 0x000204, 0xffffffff);
-	priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
-	nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
-
-	/* PBDMA[n] */
-	for (i = 0; i < priv->spoon_nr; i++) {
-		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
-		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
-		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
-	}
-
-	/* PBDMA[n].HCE */
-	for (i = 0; i < priv->spoon_nr; i++) {
-		nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
-		nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
-	}
-
-	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
-	nv_wr32(priv, 0x002100, 0xffffffff);
-	nv_wr32(priv, 0x002140, 0x7fffffff);
-	return 0;
-}
-
-void
-nve0_fifo_dtor(struct nouveau_object *object)
-{
-	struct nve0_fifo_priv *priv = (void *)object;
-	int i;
-
-	nouveau_gpuobj_unmap(&priv->user.bar);
-	nouveau_gpuobj_ref(NULL, &priv->user.mem);
-
-	for (i = 0; i < FIFO_ENGINE_NR; i++) {
-		nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[1]);
-		nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[0]);
-	}
-
-	nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nve0_fifo_impl *impl = (void *)oclass;
-	struct nve0_fifo_priv *priv;
-	int ret, i;
-
-	ret = nouveau_fifo_create(parent, engine, oclass, 0,
-				  impl->channels - 1, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	INIT_WORK(&priv->fault, nve0_fifo_recover_work);
-
-	for (i = 0; i < FIFO_ENGINE_NR; i++) {
-		ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
-					 0, &priv->engine[i].runlist[0]);
-		if (ret)
-			return ret;
-
-		ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
-					 0, &priv->engine[i].runlist[1]);
-		if (ret)
-			return ret;
-
-		init_waitqueue_head(&priv->engine[i].wait);
-	}
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200,
-				0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
-				&priv->user.bar);
-	if (ret)
-		return ret;
-
-	ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000100;
-	nv_subdev(priv)->intr = nve0_fifo_intr;
-	nv_engine(priv)->cclass = &nve0_fifo_cclass;
-	nv_engine(priv)->sclass = nve0_fifo_sclass;
-	return 0;
-}
-
-struct nouveau_oclass *
-nve0_fifo_oclass = &(struct nve0_fifo_impl) {
-	.base.handle = NV_ENGINE(FIFO, 0xe0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_fifo_ctor,
-		.dtor = nve0_fifo_dtor,
-		.init = nve0_fifo_init,
-		.fini = nve0_fifo_fini,
-	},
-	.channels = 4096,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h
deleted file mode 100644
index e96b32b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVKM_FIFO_NVE0_H__
-#define __NVKM_FIFO_NVE0_H__
-
-#include <engine/fifo.h>
-
-int  nve0_fifo_ctor(struct nouveau_object *, struct nouveau_object *,
-		    struct nouveau_oclass *, void *, u32,
-		    struct nouveau_object **);
-void nve0_fifo_dtor(struct nouveau_object *);
-int  nve0_fifo_init(struct nouveau_object *);
-int  nve0_fifo_fini(struct nouveau_object *, bool);
-
-struct nve0_fifo_impl {
-	struct nouveau_oclass base;
-	u32 channels;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
deleted file mode 100644
index e194701..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef __NOUVEAU_GRCTX_H__
-#define __NOUVEAU_GRCTX_H__
-
-struct nouveau_grctx {
-	struct nouveau_device *device;
-
-	enum {
-		NOUVEAU_GRCTX_PROG,
-		NOUVEAU_GRCTX_VALS
-	} mode;
-	void *data;
-
-	u32 ctxprog_max;
-	u32 ctxprog_len;
-	u32 ctxprog_reg;
-	int ctxprog_label[32];
-	u32 ctxvals_pos;
-	u32 ctxvals_base;
-};
-
-static inline void
-cp_out(struct nouveau_grctx *ctx, u32 inst)
-{
-	u32 *ctxprog = ctx->data;
-
-	if (ctx->mode != NOUVEAU_GRCTX_PROG)
-		return;
-
-	BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
-	ctxprog[ctx->ctxprog_len++] = inst;
-}
-
-static inline void
-cp_lsr(struct nouveau_grctx *ctx, u32 val)
-{
-	cp_out(ctx, CP_LOAD_SR | val);
-}
-
-static inline void
-cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
-{
-	ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
-
-	ctx->ctxvals_base = ctx->ctxvals_pos;
-	ctx->ctxvals_pos = ctx->ctxvals_base + length;
-
-	if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
-		cp_lsr(ctx, length);
-		length = 0;
-	}
-
-	cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
-}
-
-static inline void
-cp_name(struct nouveau_grctx *ctx, int name)
-{
-	u32 *ctxprog = ctx->data;
-	int i;
-
-	if (ctx->mode != NOUVEAU_GRCTX_PROG)
-		return;
-
-	ctx->ctxprog_label[name] = ctx->ctxprog_len;
-	for (i = 0; i < ctx->ctxprog_len; i++) {
-		if ((ctxprog[i] & 0xfff00000) != 0xff400000)
-			continue;
-		if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
-			continue;
-		ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
-			     (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
-	}
-}
-
-static inline void
-_cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
-{
-	int ip = 0;
-
-	if (mod != 2) {
-		ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
-		if (ip == 0)
-			ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
-	}
-
-	cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
-		    (state ? 0 : CP_BRA_IF_CLEAR));
-}
-#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
-
-static inline void
-_cp_wait(struct nouveau_grctx *ctx, int flag, int state)
-{
-	cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
-}
-#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
-
-static inline void
-_cp_set(struct nouveau_grctx *ctx, int flag, int state)
-{
-	cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
-}
-#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
-
-static inline void
-cp_pos(struct nouveau_grctx *ctx, int offset)
-{
-	ctx->ctxvals_pos = offset;
-	ctx->ctxvals_base = ctx->ctxvals_pos;
-
-	cp_lsr(ctx, ctx->ctxvals_pos);
-	cp_out(ctx, CP_SET_CONTEXT_POINTER);
-}
-
-static inline void
-gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
-{
-	if (ctx->mode != NOUVEAU_GRCTX_VALS)
-		return;
-
-	reg = (reg - 0x00400000) / 4;
-	reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
-
-	nv_wo32(ctx->data, reg * 4, val);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c
deleted file mode 100644
index 3adb7fe..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gk110b_grctx_init_sm_0[] = {
-	{ 0x419e04,   1, 0x04, 0x00000000 },
-	{ 0x419e08,   1, 0x04, 0x0000001d },
-	{ 0x419e0c,   1, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00001c02 },
-	{ 0x419e44,   1, 0x04, 0x0013eff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000007f },
-	{ 0x419e50,   2, 0x04, 0x00000000 },
-	{ 0x419e58,   1, 0x04, 0x00000001 },
-	{ 0x419e5c,   3, 0x04, 0x00000000 },
-	{ 0x419e68,   1, 0x04, 0x00000002 },
-	{ 0x419e6c,  12, 0x04, 0x00000000 },
-	{ 0x419eac,   1, 0x04, 0x00001f8f },
-	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
-	{ 0x419eb8,   1, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x0001304f },
-	{ 0x419f30,   4, 0x04, 0x00000000 },
-	{ 0x419f40,   1, 0x04, 0x00000018 },
-	{ 0x419f44,   3, 0x04, 0x00000000 },
-	{ 0x419f58,   1, 0x04, 0x00000000 },
-	{ 0x419f70,   1, 0x04, 0x00006300 },
-	{ 0x419f78,   1, 0x04, 0x000000eb },
-	{ 0x419f7c,   1, 0x04, 0x00000404 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gk110b_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ nvf0_grctx_init_tex_0 },
-	{ nvf0_grctx_init_mpc_0 },
-	{ nvf0_grctx_init_l1c_0 },
-	{ gk110b_grctx_init_sm_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-gk110b_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xf1),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nve4_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nvf0_grctx_pack_hub,
-	.gpc   = nvf0_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = gk110b_grctx_pack_tpc,
-	.ppc   = nvf0_grctx_pack_ppc,
-	.icmd  = nvf0_grctx_pack_icmd,
-	.mthd  = nvf0_grctx_pack_mthd,
-	.bundle = nve4_grctx_generate_bundle,
-	.bundle_size = 0x3000,
-	.bundle_min_gpm_fifo_depth = 0x180,
-	.bundle_token_limit = 0x600,
-	.pagepool = nve4_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x7ff,
-	.alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c
deleted file mode 100644
index 36fc983..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "ctxnvc0.h"
-
-static const struct nvc0_graph_pack
-gk20a_grctx_pack_mthd[] = {
-	{ nve4_grctx_init_a097_0, 0xa297 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{}
-};
-
-struct nouveau_oclass *
-gk20a_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xea),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nve4_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nve4_grctx_pack_hub,
-	.gpc   = nve4_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nve4_grctx_pack_tpc,
-	.ppc   = nve4_grctx_pack_ppc,
-	.icmd  = nve4_grctx_pack_icmd,
-	.mthd  = gk20a_grctx_pack_mthd,
-	.bundle = nve4_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.bundle_min_gpm_fifo_depth = 0x62,
-	.bundle_token_limit = 0x100,
-	.pagepool = nve4_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x240,
-	.attrib_nr = 0x240,
-	.alpha_nr_max = 0x648 + (0x648 / 2),
-	.alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c
deleted file mode 100644
index 62e918b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gm107_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x0000b1,   2, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000a8,   1, 0x01, 0x0000ffff },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002f2,   2, 0x01, 0x00000001 },
-	{ 0x0002f5,   1, 0x01, 0x00000001 },
-	{ 0x0002f7,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x0000de,   1, 0x01, 0x00000001 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000383,   1, 0x01, 0x00000011 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x0005d0,   1, 0x01, 0x20181008 },
-	{ 0x0005d1,   1, 0x01, 0x40383028 },
-	{ 0x0005d2,   1, 0x01, 0x60585048 },
-	{ 0x0005d3,   1, 0x01, 0x80787068 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000550,  32, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x000595,   1, 0x01, 0x00400040 },
-	{ 0x000596,   1, 0x01, 0x00000492 },
-	{ 0x000597,   1, 0x01, 0x08080203 },
-	{ 0x0005ad,   1, 0x01, 0x00000008 },
-	{ 0x000598,   1, 0x01, 0x00020001 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000662,   1, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x000a0d,   1, 0x01, 0x00000006 },
-	{ 0x00097d,   1, 0x01, 0x0000000c },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000687,   1, 0x01, 0x003fffff },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00400008 },
-	{ 0x000841,   1, 0x01, 0x08000080 },
-	{ 0x000842,   1, 0x01, 0x00400008 },
-	{ 0x000843,   1, 0x01, 0x08000080 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000008 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_icmd[] = {
-	{ gm107_grctx_init_icmd_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_b097_0[] = {
-	{ 0x000800,   8, 0x40, 0x00000000 },
-	{ 0x000804,   8, 0x40, 0x00000000 },
-	{ 0x000808,   8, 0x40, 0x00000400 },
-	{ 0x00080c,   8, 0x40, 0x00000300 },
-	{ 0x000810,   1, 0x04, 0x000000cf },
-	{ 0x000850,   7, 0x40, 0x00000000 },
-	{ 0x000814,   8, 0x40, 0x00000040 },
-	{ 0x000818,   8, 0x40, 0x00000001 },
-	{ 0x00081c,   8, 0x40, 0x00000000 },
-	{ 0x000820,   8, 0x40, 0x00000000 },
-	{ 0x001c00,  16, 0x10, 0x00000000 },
-	{ 0x001c04,  16, 0x10, 0x00000000 },
-	{ 0x001c08,  16, 0x10, 0x00000000 },
-	{ 0x001c0c,  16, 0x10, 0x00000000 },
-	{ 0x001d00,  16, 0x10, 0x00000000 },
-	{ 0x001d04,  16, 0x10, 0x00000000 },
-	{ 0x001d08,  16, 0x10, 0x00000000 },
-	{ 0x001d0c,  16, 0x10, 0x00000000 },
-	{ 0x001f00,  16, 0x08, 0x00000000 },
-	{ 0x001f04,  16, 0x08, 0x00000000 },
-	{ 0x001f80,  16, 0x08, 0x00000000 },
-	{ 0x001f84,  16, 0x08, 0x00000000 },
-	{ 0x002000,   1, 0x04, 0x00000000 },
-	{ 0x002040,   1, 0x04, 0x00000011 },
-	{ 0x002080,   1, 0x04, 0x00000020 },
-	{ 0x0020c0,   1, 0x04, 0x00000030 },
-	{ 0x002100,   1, 0x04, 0x00000040 },
-	{ 0x002140,   1, 0x04, 0x00000051 },
-	{ 0x00200c,   6, 0x40, 0x00000001 },
-	{ 0x002010,   1, 0x04, 0x00000000 },
-	{ 0x002050,   1, 0x04, 0x00000000 },
-	{ 0x002090,   1, 0x04, 0x00000001 },
-	{ 0x0020d0,   1, 0x04, 0x00000002 },
-	{ 0x002110,   1, 0x04, 0x00000003 },
-	{ 0x002150,   1, 0x04, 0x00000004 },
-	{ 0x000380,   4, 0x20, 0x00000000 },
-	{ 0x000384,   4, 0x20, 0x00000000 },
-	{ 0x000388,   4, 0x20, 0x00000000 },
-	{ 0x00038c,   4, 0x20, 0x00000000 },
-	{ 0x000700,   4, 0x10, 0x00000000 },
-	{ 0x000704,   4, 0x10, 0x00000000 },
-	{ 0x000708,   4, 0x10, 0x00000000 },
-	{ 0x002800, 128, 0x04, 0x00000000 },
-	{ 0x000a00,  16, 0x20, 0x00000000 },
-	{ 0x000a04,  16, 0x20, 0x00000000 },
-	{ 0x000a08,  16, 0x20, 0x00000000 },
-	{ 0x000a0c,  16, 0x20, 0x00000000 },
-	{ 0x000a10,  16, 0x20, 0x00000000 },
-	{ 0x000a14,  16, 0x20, 0x00000000 },
-	{ 0x000c00,  16, 0x10, 0x00000000 },
-	{ 0x000c04,  16, 0x10, 0x00000000 },
-	{ 0x000c08,  16, 0x10, 0x00000000 },
-	{ 0x000c0c,  16, 0x10, 0x3f800000 },
-	{ 0x000d00,   8, 0x08, 0xffff0000 },
-	{ 0x000d04,   8, 0x08, 0xffff0000 },
-	{ 0x000e00,  16, 0x10, 0x00000000 },
-	{ 0x000e04,  16, 0x10, 0xffff0000 },
-	{ 0x000e08,  16, 0x10, 0xffff0000 },
-	{ 0x000d40,   4, 0x08, 0x00000000 },
-	{ 0x000d44,   4, 0x08, 0x00000000 },
-	{ 0x001e00,   8, 0x20, 0x00000001 },
-	{ 0x001e04,   8, 0x20, 0x00000001 },
-	{ 0x001e08,   8, 0x20, 0x00000002 },
-	{ 0x001e0c,   8, 0x20, 0x00000001 },
-	{ 0x001e10,   8, 0x20, 0x00000001 },
-	{ 0x001e14,   8, 0x20, 0x00000002 },
-	{ 0x001e18,   8, 0x20, 0x00000001 },
-	{ 0x001480,   8, 0x10, 0x00000000 },
-	{ 0x001484,   8, 0x10, 0x00000000 },
-	{ 0x001488,   8, 0x10, 0x00000000 },
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x001514,   1, 0x04, 0x00000000 },
-	{ 0x000d68,   1, 0x04, 0x0000ffff },
-	{ 0x00121c,   1, 0x04, 0x0fac6881 },
-	{ 0x000fac,   1, 0x04, 0x00000001 },
-	{ 0x001538,   1, 0x04, 0x00000001 },
-	{ 0x000fe0,   2, 0x04, 0x00000000 },
-	{ 0x000fe8,   1, 0x04, 0x00000014 },
-	{ 0x000fec,   1, 0x04, 0x00000040 },
-	{ 0x000ff0,   1, 0x04, 0x00000000 },
-	{ 0x00179c,   1, 0x04, 0x00000000 },
-	{ 0x001228,   1, 0x04, 0x00000400 },
-	{ 0x00122c,   1, 0x04, 0x00000300 },
-	{ 0x001230,   1, 0x04, 0x00010001 },
-	{ 0x0007f8,   1, 0x04, 0x00000000 },
-	{ 0x0015b4,   1, 0x04, 0x00000001 },
-	{ 0x0015cc,   1, 0x04, 0x00000000 },
-	{ 0x001534,   1, 0x04, 0x00000000 },
-	{ 0x000754,   1, 0x04, 0x00000001 },
-	{ 0x000fb0,   1, 0x04, 0x00000000 },
-	{ 0x0015d0,   1, 0x04, 0x00000000 },
-	{ 0x00153c,   1, 0x04, 0x00000000 },
-	{ 0x0016b4,   1, 0x04, 0x00000003 },
-	{ 0x000fbc,   4, 0x04, 0x0000ffff },
-	{ 0x000df8,   2, 0x04, 0x00000000 },
-	{ 0x001948,   1, 0x04, 0x00000000 },
-	{ 0x001970,   1, 0x04, 0x00000001 },
-	{ 0x00161c,   1, 0x04, 0x000009f0 },
-	{ 0x000dcc,   1, 0x04, 0x00000010 },
-	{ 0x0015e4,   1, 0x04, 0x00000000 },
-	{ 0x001160,  32, 0x04, 0x25e00040 },
-	{ 0x001880,  32, 0x04, 0x00000000 },
-	{ 0x000f84,   2, 0x04, 0x00000000 },
-	{ 0x0017c8,   2, 0x04, 0x00000000 },
-	{ 0x0017d0,   1, 0x04, 0x000000ff },
-	{ 0x0017d4,   1, 0x04, 0xffffffff },
-	{ 0x0017d8,   1, 0x04, 0x00000002 },
-	{ 0x0017dc,   1, 0x04, 0x00000000 },
-	{ 0x0015f4,   2, 0x04, 0x00000000 },
-	{ 0x001434,   2, 0x04, 0x00000000 },
-	{ 0x000d74,   1, 0x04, 0x00000000 },
-	{ 0x0013a4,   1, 0x04, 0x00000000 },
-	{ 0x001318,   1, 0x04, 0x00000001 },
-	{ 0x001080,   2, 0x04, 0x00000000 },
-	{ 0x001088,   2, 0x04, 0x00000001 },
-	{ 0x001090,   1, 0x04, 0x00000000 },
-	{ 0x001094,   1, 0x04, 0x00000001 },
-	{ 0x001098,   1, 0x04, 0x00000000 },
-	{ 0x00109c,   1, 0x04, 0x00000001 },
-	{ 0x0010a0,   2, 0x04, 0x00000000 },
-	{ 0x001644,   1, 0x04, 0x00000000 },
-	{ 0x000748,   1, 0x04, 0x00000000 },
-	{ 0x000de8,   1, 0x04, 0x00000000 },
-	{ 0x001648,   1, 0x04, 0x00000000 },
-	{ 0x0012a4,   1, 0x04, 0x00000000 },
-	{ 0x001120,   4, 0x04, 0x00000000 },
-	{ 0x001118,   1, 0x04, 0x00000000 },
-	{ 0x00164c,   1, 0x04, 0x00000000 },
-	{ 0x001658,   1, 0x04, 0x00000000 },
-	{ 0x001910,   1, 0x04, 0x00000290 },
-	{ 0x001518,   1, 0x04, 0x00000000 },
-	{ 0x00165c,   1, 0x04, 0x00000001 },
-	{ 0x001520,   1, 0x04, 0x00000000 },
-	{ 0x001604,   1, 0x04, 0x00000000 },
-	{ 0x001570,   1, 0x04, 0x00000000 },
-	{ 0x0013b0,   2, 0x04, 0x3f800000 },
-	{ 0x00020c,   1, 0x04, 0x00000000 },
-	{ 0x001670,   1, 0x04, 0x30201000 },
-	{ 0x001674,   1, 0x04, 0x70605040 },
-	{ 0x001678,   1, 0x04, 0xb8a89888 },
-	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-	{ 0x00166c,   1, 0x04, 0x00000000 },
-	{ 0x001680,   1, 0x04, 0x00ffff00 },
-	{ 0x0012d0,   1, 0x04, 0x00000003 },
-	{ 0x0012d4,   1, 0x04, 0x00000002 },
-	{ 0x001684,   2, 0x04, 0x00000000 },
-	{ 0x000dac,   2, 0x04, 0x00001b02 },
-	{ 0x000db4,   1, 0x04, 0x00000000 },
-	{ 0x00168c,   1, 0x04, 0x00000000 },
-	{ 0x0015bc,   1, 0x04, 0x00000000 },
-	{ 0x00156c,   1, 0x04, 0x00000000 },
-	{ 0x00187c,   1, 0x04, 0x00000000 },
-	{ 0x001110,   1, 0x04, 0x00000001 },
-	{ 0x000dc0,   3, 0x04, 0x00000000 },
-	{ 0x000f40,   5, 0x04, 0x00000000 },
-	{ 0x001234,   1, 0x04, 0x00000000 },
-	{ 0x001690,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x001000,   1, 0x04, 0x00000010 },
-	{ 0x0010fc,   1, 0x04, 0x00000000 },
-	{ 0x001290,   1, 0x04, 0x00000000 },
-	{ 0x000218,   1, 0x04, 0x00000010 },
-	{ 0x0012d8,   1, 0x04, 0x00000000 },
-	{ 0x0012dc,   1, 0x04, 0x00000010 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x00155c,   2, 0x04, 0x00000000 },
-	{ 0x001564,   1, 0x04, 0x00000fff },
-	{ 0x001574,   2, 0x04, 0x00000000 },
-	{ 0x00157c,   1, 0x04, 0x000fffff },
-	{ 0x001354,   1, 0x04, 0x00000000 },
-	{ 0x001610,   1, 0x04, 0x00000012 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x00260c,   1, 0x04, 0x00000000 },
-	{ 0x0007ac,   1, 0x04, 0x00000000 },
-	{ 0x00162c,   1, 0x04, 0x00000003 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000324,   6, 0x04, 0x3f800000 },
-	{ 0x000750,   1, 0x04, 0x00000000 },
-	{ 0x000760,   1, 0x04, 0x39291909 },
-	{ 0x000764,   1, 0x04, 0x79695949 },
-	{ 0x000768,   1, 0x04, 0xb9a99989 },
-	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x000770,   1, 0x04, 0x30201000 },
-	{ 0x000774,   1, 0x04, 0x70605040 },
-	{ 0x000778,   1, 0x04, 0x00009080 },
-	{ 0x000780,   1, 0x04, 0x39291909 },
-	{ 0x000784,   1, 0x04, 0x79695949 },
-	{ 0x000788,   1, 0x04, 0xb9a99989 },
-	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x0007d0,   1, 0x04, 0x30201000 },
-	{ 0x0007d4,   1, 0x04, 0x70605040 },
-	{ 0x0007d8,   1, 0x04, 0x00009080 },
-	{ 0x00037c,   1, 0x04, 0x00000001 },
-	{ 0x000740,   2, 0x04, 0x00000000 },
-	{ 0x002600,   1, 0x04, 0x00000000 },
-	{ 0x001918,   1, 0x04, 0x00000000 },
-	{ 0x00191c,   1, 0x04, 0x00000900 },
-	{ 0x001920,   1, 0x04, 0x00000405 },
-	{ 0x001308,   1, 0x04, 0x00000001 },
-	{ 0x001924,   1, 0x04, 0x00000000 },
-	{ 0x0013ac,   1, 0x04, 0x00000000 },
-	{ 0x00192c,   1, 0x04, 0x00000001 },
-	{ 0x00193c,   1, 0x04, 0x00002c1c },
-	{ 0x000d7c,   1, 0x04, 0x00000000 },
-	{ 0x000f8c,   1, 0x04, 0x00000000 },
-	{ 0x0002c0,   1, 0x04, 0x00000001 },
-	{ 0x001510,   1, 0x04, 0x00000000 },
-	{ 0x001940,   1, 0x04, 0x00000000 },
-	{ 0x000ff4,   2, 0x04, 0x00000000 },
-	{ 0x00194c,   2, 0x04, 0x00000000 },
-	{ 0x001968,   1, 0x04, 0x00000000 },
-	{ 0x001590,   1, 0x04, 0x0000003f },
-	{ 0x0007e8,   4, 0x04, 0x00000000 },
-	{ 0x00196c,   1, 0x04, 0x00000011 },
-	{ 0x0002e4,   1, 0x04, 0x0000b001 },
-	{ 0x00036c,   2, 0x04, 0x00000000 },
-	{ 0x00197c,   1, 0x04, 0x00000000 },
-	{ 0x000fcc,   2, 0x04, 0x00000000 },
-	{ 0x0002d8,   1, 0x04, 0x00000040 },
-	{ 0x001980,   1, 0x04, 0x00000080 },
-	{ 0x001504,   1, 0x04, 0x00000080 },
-	{ 0x001984,   1, 0x04, 0x00000000 },
-	{ 0x000f60,   1, 0x04, 0x00000000 },
-	{ 0x000f64,   1, 0x04, 0x00400040 },
-	{ 0x000f68,   1, 0x04, 0x00002212 },
-	{ 0x000f6c,   1, 0x04, 0x08080203 },
-	{ 0x001108,   1, 0x04, 0x00000008 },
-	{ 0x000f70,   1, 0x04, 0x00080001 },
-	{ 0x000ffc,   1, 0x04, 0x00000000 },
-	{ 0x000300,   1, 0x04, 0x00000001 },
-	{ 0x0013a8,   1, 0x04, 0x00000000 },
-	{ 0x0012ec,   1, 0x04, 0x00000000 },
-	{ 0x001310,   1, 0x04, 0x00000000 },
-	{ 0x001314,   1, 0x04, 0x00000001 },
-	{ 0x001380,   1, 0x04, 0x00000000 },
-	{ 0x001384,   4, 0x04, 0x00000001 },
-	{ 0x001394,   1, 0x04, 0x00000000 },
-	{ 0x00139c,   1, 0x04, 0x00000000 },
-	{ 0x001398,   1, 0x04, 0x00000000 },
-	{ 0x001594,   1, 0x04, 0x00000000 },
-	{ 0x001598,   4, 0x04, 0x00000001 },
-	{ 0x000f54,   3, 0x04, 0x00000000 },
-	{ 0x0019bc,   1, 0x04, 0x00000000 },
-	{ 0x000f9c,   2, 0x04, 0x00000000 },
-	{ 0x0012cc,   1, 0x04, 0x00000000 },
-	{ 0x0012e8,   1, 0x04, 0x00000000 },
-	{ 0x00130c,   1, 0x04, 0x00000001 },
-	{ 0x001360,   8, 0x04, 0x00000000 },
-	{ 0x00133c,   2, 0x04, 0x00000001 },
-	{ 0x001344,   1, 0x04, 0x00000002 },
-	{ 0x001348,   2, 0x04, 0x00000001 },
-	{ 0x001350,   1, 0x04, 0x00000002 },
-	{ 0x001358,   1, 0x04, 0x00000001 },
-	{ 0x0012e4,   1, 0x04, 0x00000000 },
-	{ 0x00131c,   4, 0x04, 0x00000000 },
-	{ 0x0019c0,   1, 0x04, 0x00000000 },
-	{ 0x001140,   1, 0x04, 0x00000000 },
-	{ 0x000dd0,   1, 0x04, 0x00000000 },
-	{ 0x000dd4,   1, 0x04, 0x00000001 },
-	{ 0x0002f4,   1, 0x04, 0x00000000 },
-	{ 0x0019c4,   1, 0x04, 0x00000000 },
-	{ 0x0019c8,   1, 0x04, 0x00001500 },
-	{ 0x00135c,   1, 0x04, 0x00000000 },
-	{ 0x000f90,   1, 0x04, 0x00000000 },
-	{ 0x0019e0,   8, 0x04, 0x00000001 },
-	{ 0x0019cc,   1, 0x04, 0x00000001 },
-	{ 0x0015b8,   1, 0x04, 0x00000000 },
-	{ 0x001a00,   1, 0x04, 0x00001111 },
-	{ 0x001a04,   7, 0x04, 0x00000000 },
-	{ 0x000d6c,   2, 0x04, 0xffff0000 },
-	{ 0x0010f8,   1, 0x04, 0x00001010 },
-	{ 0x000d80,   5, 0x04, 0x00000000 },
-	{ 0x000da0,   1, 0x04, 0x00000000 },
-	{ 0x0007a4,   2, 0x04, 0x00000000 },
-	{ 0x001508,   1, 0x04, 0x80000000 },
-	{ 0x00150c,   1, 0x04, 0x40000000 },
-	{ 0x001668,   1, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000008 },
-	{ 0x000d9c,   1, 0x04, 0x00000001 },
-	{ 0x000f14,   1, 0x04, 0x00000000 },
-	{ 0x000374,   1, 0x04, 0x00000000 },
-	{ 0x000378,   1, 0x04, 0x0000000c },
-	{ 0x0007dc,   1, 0x04, 0x00000000 },
-	{ 0x00074c,   1, 0x04, 0x00000055 },
-	{ 0x001420,   1, 0x04, 0x00000003 },
-	{ 0x001008,   1, 0x04, 0x00000008 },
-	{ 0x00100c,   1, 0x04, 0x00000040 },
-	{ 0x001010,   1, 0x04, 0x0000012c },
-	{ 0x000d60,   1, 0x04, 0x00000040 },
-	{ 0x001018,   1, 0x04, 0x00000020 },
-	{ 0x00101c,   1, 0x04, 0x00000001 },
-	{ 0x001020,   1, 0x04, 0x00000020 },
-	{ 0x001024,   1, 0x04, 0x00000001 },
-	{ 0x001444,   3, 0x04, 0x00000000 },
-	{ 0x000360,   1, 0x04, 0x20164010 },
-	{ 0x000364,   1, 0x04, 0x00000020 },
-	{ 0x000368,   1, 0x04, 0x00000000 },
-	{ 0x000da8,   1, 0x04, 0x00000030 },
-	{ 0x000de4,   1, 0x04, 0x00000000 },
-	{ 0x000204,   1, 0x04, 0x00000006 },
-	{ 0x0002d0,   1, 0x04, 0x003fffff },
-	{ 0x001220,   1, 0x04, 0x00000005 },
-	{ 0x000fdc,   1, 0x04, 0x00000000 },
-	{ 0x000f98,   1, 0x04, 0x00400008 },
-	{ 0x001284,   1, 0x04, 0x08000080 },
-	{ 0x001450,   1, 0x04, 0x00400008 },
-	{ 0x001454,   1, 0x04, 0x08000080 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_mthd[] = {
-	{ gm107_grctx_init_b097_0, 0xb097 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_fe_0[] = {
-	{ 0x404004,   8, 0x04, 0x00000000 },
-	{ 0x404024,   1, 0x04, 0x0000e000 },
-	{ 0x404028,   8, 0x04, 0x00000000 },
-	{ 0x4040a8,   8, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf800008f },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404100,  10, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000045 },
-	{ 0x40417c,   2, 0x04, 0x00000000 },
-	{ 0x404194,   1, 0x04, 0x01000700 },
-	{ 0x4041a0,   4, 0x04, 0x00000000 },
-	{ 0x404200,   4, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8001bf },
-	{ 0x405830,   1, 0x04, 0x0aa01000 },
-	{ 0x405834,   1, 0x04, 0x08000000 },
-	{ 0x405838,   1, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{ 0x405a1c,   1, 0x04, 0x000000ff },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x07410001 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b0,   3, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x80400280 },
-	{ 0x4064c4,   1, 0x04, 0x0400ffff },
-	{ 0x4064c8,   1, 0x04, 0x018001ff },
-	{ 0x4064cc,   9, 0x04, 0x00000000 },
-	{ 0x4064fc,   1, 0x04, 0x0000022a },
-	{ 0x406500,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x32802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1003e005 },
-	{ 0x408840,   1, 0x04, 0x0000000b },
-	{ 0x408900,   1, 0x04, 0xb080b801 },
-	{ 0x408904,   1, 0x04, 0x63038001 },
-	{ 0x408908,   1, 0x04, 0x02c8102f },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ gm107_grctx_init_fe_0 },
-	{ nvf0_grctx_init_pri_0 },
-	{ nve4_grctx_init_memfmt_0 },
-	{ gm107_grctx_init_ds_0 },
-	{ nvf0_grctx_init_cwd_0 },
-	{ gm107_grctx_init_pd_0 },
-	{ nv108_grctx_init_rstr2d_0 },
-	{ nve4_grctx_init_scc_0 },
-	{ gm107_grctx_init_be_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_0[] = {
-	{ 0x418380,   1, 0x04, 0x00000056 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_1[] = {
-	{ 0x418600,   1, 0x04, 0x0000007f },
-	{ 0x418684,   1, 0x04, 0x0000001f },
-	{ 0x418700,   1, 0x04, 0x00000002 },
-	{ 0x418704,   1, 0x04, 0x00000080 },
-	{ 0x418708,   1, 0x04, 0x40000000 },
-	{ 0x41870c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006863a },
-	{ 0x418810,   1, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00000044 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100058 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_2[] = {
-	{ 0x418d24,   1, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x90000000 },
-	{ 0x418e24,   1, 0x04, 0x00000000 },
-	{ 0x418e28,   1, 0x04, 0x00000030 },
-	{ 0x418e30,   1, 0x04, 0x00000000 },
-	{ 0x418e34,   1, 0x04, 0x00010000 },
-	{ 0x418e38,   1, 0x04, 0x00000000 },
-	{ 0x418e40,  22, 0x04, 0x00000000 },
-	{ 0x418ea0,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_gpc[] = {
-	{ gm107_grctx_init_gpc_unk_0 },
-	{ nv108_grctx_init_prop_0 },
-	{ gm107_grctx_init_gpc_unk_1 },
-	{ gm107_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nv108_grctx_init_crstr_0 },
-	{ nve4_grctx_init_gpm_0 },
-	{ gm107_grctx_init_gpc_unk_2 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000300f0 },
-	{ 0x419a04,   1, 0x04, 0x00000005 },
-	{ 0x419a08,   1, 0x04, 0x00000421 },
-	{ 0x419a0c,   1, 0x04, 0x00120000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00002200 },
-	{ 0x419a1c,   1, 0x04, 0x0000c000 },
-	{ 0x419a20,   1, 0x04, 0x20008a00 },
-	{ 0x419a30,   1, 0x04, 0x00000001 },
-	{ 0x419a3c,   1, 0x04, 0x00000002 },
-	{ 0x419ac4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x0000001a },
-	{ 0x419c04,   1, 0x04, 0x80000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{ 0x419c24,   1, 0x04, 0x00084210 },
-	{ 0x419c28,   1, 0x04, 0x3efbefbe },
-	{ 0x419c2c,   1, 0x04, 0x00000000 },
-	{ 0x419c34,   1, 0x04, 0x01ff1ff3 },
-	{ 0x419c3c,   1, 0x04, 0x00001919 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_l1c_0[] = {
-	{ 0x419c84,   1, 0x04, 0x00000020 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_sm_0[] = {
-	{ 0x419e04,   3, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00001c02 },
-	{ 0x419e44,   1, 0x04, 0x00d3eff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000007f },
-	{ 0x419e50,   1, 0x04, 0x00000000 },
-	{ 0x419e60,   4, 0x04, 0x00000000 },
-	{ 0x419e74,  10, 0x04, 0x00000000 },
-	{ 0x419eac,   1, 0x04, 0x0001cf8b },
-	{ 0x419eb0,   1, 0x04, 0x00030300 },
-	{ 0x419eb8,   1, 0x04, 0x00000000 },
-	{ 0x419ef0,  24, 0x04, 0x00000000 },
-	{ 0x419f68,   2, 0x04, 0x00000000 },
-	{ 0x419f70,   1, 0x04, 0x00000020 },
-	{ 0x419f78,   1, 0x04, 0x000003eb },
-	{ 0x419f7c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ gm107_grctx_init_tex_0 },
-	{ gm107_grctx_init_mpc_0 },
-	{ gm107_grctx_init_l1c_0 },
-	{ gm107_grctx_init_sm_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_cbm_0[] = {
-	{ 0x41bec0,   1, 0x04, 0x00000000 },
-	{ 0x41bec4,   1, 0x04, 0x01050000 },
-	{ 0x41bee4,   1, 0x04, 0x00000000 },
-	{ 0x41bef0,   1, 0x04, 0x000003ff },
-	{ 0x41bef4,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_wwdx_0[] = {
-	{ 0x41bf00,   1, 0x04, 0x0a418820 },
-	{ 0x41bf04,   1, 0x04, 0x062080e6 },
-	{ 0x41bf08,   1, 0x04, 0x020398a4 },
-	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
-	{ 0x41bf10,   1, 0x04, 0x0a418820 },
-	{ 0x41bf14,   1, 0x04, 0x000000e6 },
-	{ 0x41bfd0,   1, 0x04, 0x00900103 },
-	{ 0x41bfe0,   1, 0x04, 0x80000000 },
-	{ 0x41bfe4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_ppc[] = {
-	{ nve4_grctx_init_pes_0 },
-	{ gm107_grctx_init_cbm_0 },
-	{ gm107_grctx_init_wwdx_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-static void
-gm107_grctx_generate_bundle(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
-				    impl->bundle_size / 0x20);
-	const u32 token_limit = impl->bundle_token_limit;
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
-	mmio_refn(info, 0x408004, 0x00000000, s, b);
-	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
-	mmio_refn(info, 0x418e24, 0x00000000, s, b);
-	mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
-	mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
-}
-
-static void
-gm107_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
-	mmio_refn(info, 0x40800c, 0x00000000, s, b);
-	mmio_wr32(info, 0x408010, 0x80000000);
-	mmio_refn(info, 0x419004, 0x00000000, s, b);
-	mmio_wr32(info, 0x419008, 0x00000000);
-	mmio_wr32(info, 0x4064cc, 0x80000000);
-	mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
-}
-
-static void
-gm107_grctx_generate_attrib(struct nvc0_grctx *info)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-	const struct nvc0_grctx_oclass *impl = (void *)nvc0_grctx_impl(priv);
-	const u32  alpha = impl->alpha_nr;
-	const u32 attrib = impl->attrib_nr;
-	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
-	const u32 access = NV_MEM_ACCESS_RW;
-	const int s = 12;
-	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
-	const int max_batches = 0xffff;
-	u32 bo = 0;
-	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
-	int gpc, ppc, n = 0;
-
-	mmio_refn(info, 0x418810, 0x80000000, s, b);
-	mmio_refn(info, 0x419848, 0x10000000, s, b);
-	mmio_refn(info, 0x419c2c, 0x10000000, s, b);
-	mmio_wr32(info, 0x405830, (attrib << 16) | alpha);
-	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) {
-			const u32 as =  alpha * priv->ppc_tpc_nr[gpc][ppc];
-			const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc];
-			const u32 u = 0x418ea0 + (n * 0x04);
-			const u32 o = PPC_UNIT(gpc, ppc, 0);
-			mmio_wr32(info, o + 0xc0, bs);
-			mmio_wr32(info, o + 0xf4, bo);
-			bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
-			mmio_wr32(info, o + 0xe4, as);
-			mmio_wr32(info, o + 0xf8, ao);
-			ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
-			mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs);
-		}
-	}
-}
-
-static void
-gm107_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
-{
-	int gpc, tpc, id;
-
-	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			if (tpc < priv->tpc_nr[gpc]) {
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
-				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
-				id++;
-			}
-
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
-		}
-	}
-}
-
-static void
-gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
-	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-	int i;
-
-	nvc0_graph_mmio(priv, oclass->hub);
-	nvc0_graph_mmio(priv, oclass->gpc);
-	nvc0_graph_mmio(priv, oclass->zcull);
-	nvc0_graph_mmio(priv, oclass->tpc);
-	nvc0_graph_mmio(priv, oclass->ppc);
-
-	nv_wr32(priv, 0x404154, 0x00000000);
-
-	oclass->bundle(info);
-	oclass->pagepool(info);
-	oclass->attrib(info);
-	oclass->unkn(priv);
-
-	gm107_grctx_generate_tpcid(priv);
-	nvc0_grctx_generate_r406028(priv);
-	nve4_grctx_generate_r418bb8(priv);
-	nvc0_grctx_generate_r406800(priv);
-
-	nv_wr32(priv, 0x4064d0, 0x00000001);
-	for (i = 1; i < 8; i++)
-		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-	nv_wr32(priv, 0x406500, 0x00000001);
-
-	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
-
-	if (priv->gpc_nr == 1) {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
-	} else {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
-	}
-
-	nvc0_graph_icmd(priv, oclass->icmd);
-	nv_wr32(priv, 0x404154, 0x00000400);
-	nvc0_graph_mthd(priv, oclass->mthd);
-
-	nv_mask(priv, 0x419e00, 0x00808080, 0x00808080);
-	nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000);
-	nv_mask(priv, 0x419f80, 0x80000000, 0x80000000);
-	nv_mask(priv, 0x419f88, 0x80000000, 0x80000000);
-}
-
-struct nouveau_oclass *
-gm107_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0x08),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = gm107_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = gm107_grctx_pack_hub,
-	.gpc   = gm107_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = gm107_grctx_pack_tpc,
-	.ppc   = gm107_grctx_pack_ppc,
-	.icmd  = gm107_grctx_pack_icmd,
-	.mthd  = gm107_grctx_pack_mthd,
-	.bundle = gm107_grctx_generate_bundle,
-	.bundle_size = 0x3000,
-	.bundle_min_gpm_fifo_depth = 0x180,
-	.bundle_token_limit = 0x2c0,
-	.pagepool = gm107_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = gm107_grctx_generate_attrib,
-	.attrib_nr_max = 0xff0,
-	.attrib_nr = 0xaa0,
-	.alpha_nr_max = 0x1800,
-	.alpha_nr = 0x1000,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
deleted file mode 100644
index ce252ad..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nv108_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x0002f2,   2, 0x01, 0x00000001 },
-	{ 0x0002f5,   1, 0x01, 0x00000001 },
-	{ 0x0002f7,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000383,   1, 0x01, 0x00000011 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000662,   1, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x00080b,   1, 0x01, 0x00000002 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x000a0d,   1, 0x01, 0x00000006 },
-	{ 0x00097d,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x003fffff },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00400008 },
-	{ 0x000841,   1, 0x01, 0x08000080 },
-	{ 0x000842,   1, 0x01, 0x00400008 },
-	{ 0x000843,   1, 0x01, 0x08000080 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000008 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_icmd[] = {
-	{ nv108_grctx_init_icmd_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_fe_0[] = {
-	{ 0x404004,   8, 0x04, 0x00000000 },
-	{ 0x404024,   1, 0x04, 0x0000e000 },
-	{ 0x404028,   8, 0x04, 0x00000000 },
-	{ 0x4040a8,   8, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf800008f },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040e8,   1, 0x04, 0x00001000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404100,  10, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404138,   1, 0x04, 0x20000040 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000055 },
-	{ 0x40417c,   2, 0x04, 0x00000000 },
-	{ 0x404194,   1, 0x04, 0x01000700 },
-	{ 0x4041a0,   4, 0x04, 0x00000000 },
-	{ 0x404200,   1, 0x04, 0x0000a197 },
-	{ 0x404204,   1, 0x04, 0x0000a1c0 },
-	{ 0x404208,   1, 0x04, 0x0000a140 },
-	{ 0x40420c,   1, 0x04, 0x0000902d },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8000bf },
-	{ 0x405830,   1, 0x04, 0x02180648 },
-	{ 0x405834,   1, 0x04, 0x08000000 },
-	{ 0x405838,   1, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{ 0x405a1c,   1, 0x04, 0x000000ff },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x034103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b0,   3, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x802000f0 },
-	{ 0x4064c4,   1, 0x04, 0x0192ffff },
-	{ 0x4064c8,   1, 0x04, 0x00c20200 },
-	{ 0x4064cc,   9, 0x04, 0x00000000 },
-	{ 0x4064fc,   1, 0x04, 0x0000022a },
-	{}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_rstr2d_0[] = {
-	{ 0x407804,   1, 0x04, 0x00000063 },
-	{ 0x40780c,   1, 0x04, 0x0a418820 },
-	{ 0x407810,   1, 0x04, 0x062080e6 },
-	{ 0x407814,   1, 0x04, 0x020398a4 },
-	{ 0x407818,   1, 0x04, 0x0e629062 },
-	{ 0x40781c,   1, 0x04, 0x0a418820 },
-	{ 0x407820,   1, 0x04, 0x000000e6 },
-	{ 0x4078bc,   1, 0x04, 0x00000103 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x32802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1003e005 },
-	{ 0x408840,   1, 0x04, 0x0000000b },
-	{ 0x408900,   1, 0x04, 0xb080b801 },
-	{ 0x408904,   1, 0x04, 0x62000001 },
-	{ 0x408908,   1, 0x04, 0x02c8102f },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nv108_grctx_init_fe_0 },
-	{ nvf0_grctx_init_pri_0 },
-	{ nve4_grctx_init_memfmt_0 },
-	{ nv108_grctx_init_ds_0 },
-	{ nvf0_grctx_init_cwd_0 },
-	{ nv108_grctx_init_pd_0 },
-	{ nv108_grctx_init_rstr2d_0 },
-	{ nve4_grctx_init_scc_0 },
-	{ nv108_grctx_init_be_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_prop_0[] = {
-	{ 0x418400,   1, 0x04, 0x38005e00 },
-	{ 0x418404,   1, 0x04, 0x71e0ffff },
-	{ 0x41840c,   1, 0x04, 0x00001008 },
-	{ 0x418410,   1, 0x04, 0x0fff0fff },
-	{ 0x418414,   1, 0x04, 0x02200fff },
-	{ 0x418450,   6, 0x04, 0x00000000 },
-	{ 0x418468,   1, 0x04, 0x00000001 },
-	{ 0x41846c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_gpc_unk_1[] = {
-	{ 0x418600,   1, 0x04, 0x0000007f },
-	{ 0x418684,   1, 0x04, 0x0000001f },
-	{ 0x418700,   1, 0x04, 0x00000002 },
-	{ 0x418704,   2, 0x04, 0x00000080 },
-	{ 0x41870c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006863a },
-	{ 0x418808,   1, 0x04, 0x00000000 },
-	{ 0x41880c,   1, 0x04, 0x00000030 },
-	{ 0x418810,   1, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00000044 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100058 },
-	{}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_crstr_0[] = {
-	{ 0x418b00,   1, 0x04, 0x0000001e },
-	{ 0x418b08,   1, 0x04, 0x0a418820 },
-	{ 0x418b0c,   1, 0x04, 0x062080e6 },
-	{ 0x418b10,   1, 0x04, 0x020398a4 },
-	{ 0x418b14,   1, 0x04, 0x0e629062 },
-	{ 0x418b18,   1, 0x04, 0x0a418820 },
-	{ 0x418b1c,   1, 0x04, 0x000000e6 },
-	{ 0x418bb8,   1, 0x04, 0x00000103 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_gpm_0[] = {
-	{ 0x418c08,   1, 0x04, 0x00000001 },
-	{ 0x418c10,   8, 0x04, 0x00000000 },
-	{ 0x418c40,   1, 0x04, 0xffffffff },
-	{ 0x418c6c,   1, 0x04, 0x00000001 },
-	{ 0x418c80,   1, 0x04, 0x2020000c },
-	{ 0x418c8c,   1, 0x04, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nv108_grctx_init_prop_0 },
-	{ nv108_grctx_init_gpc_unk_1 },
-	{ nv108_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nv108_grctx_init_crstr_0 },
-	{ nv108_grctx_init_gpm_0 },
-	{ nvf0_grctx_init_gpc_unk_2 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000100f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000421 },
-	{ 0x419a0c,   1, 0x04, 0x00120000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x0000c000 },
-	{ 0x419a20,   1, 0x04, 0x00000800 },
-	{ 0x419a30,   1, 0x04, 0x00000001 },
-	{ 0x419ac4,   1, 0x04, 0x0037f440 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_sm_0[] = {
-	{ 0x419e04,   1, 0x04, 0x00000000 },
-	{ 0x419e08,   1, 0x04, 0x0000001d },
-	{ 0x419e0c,   1, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00001c02 },
-	{ 0x419e44,   1, 0x04, 0x0013eff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000007f },
-	{ 0x419e50,   2, 0x04, 0x00000000 },
-	{ 0x419e58,   1, 0x04, 0x00000001 },
-	{ 0x419e5c,   3, 0x04, 0x00000000 },
-	{ 0x419e68,   1, 0x04, 0x00000002 },
-	{ 0x419e6c,  12, 0x04, 0x00000000 },
-	{ 0x419eac,   1, 0x04, 0x00001f8f },
-	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
-	{ 0x419eb8,   1, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x0001304f },
-	{ 0x419f30,   4, 0x04, 0x00000000 },
-	{ 0x419f40,   1, 0x04, 0x00000018 },
-	{ 0x419f44,   3, 0x04, 0x00000000 },
-	{ 0x419f58,   1, 0x04, 0x00000020 },
-	{ 0x419f70,   1, 0x04, 0x00000000 },
-	{ 0x419f78,   1, 0x04, 0x000001eb },
-	{ 0x419f7c,   1, 0x04, 0x00000404 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ nv108_grctx_init_tex_0 },
-	{ nvf0_grctx_init_mpc_0 },
-	{ nvf0_grctx_init_l1c_0 },
-	{ nv108_grctx_init_sm_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_cbm_0[] = {
-	{ 0x41bec0,   1, 0x04, 0x10000000 },
-	{ 0x41bec4,   1, 0x04, 0x00037f7f },
-	{ 0x41bee4,   1, 0x04, 0x00000000 },
-	{ 0x41bef0,   1, 0x04, 0x000003ff },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_ppc[] = {
-	{ nve4_grctx_init_pes_0 },
-	{ nv108_grctx_init_cbm_0 },
-	{ nvd7_grctx_init_wwdx_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nv108_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0x08),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nve4_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nv108_grctx_pack_hub,
-	.gpc   = nv108_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nv108_grctx_pack_tpc,
-	.ppc   = nv108_grctx_pack_ppc,
-	.icmd  = nv108_grctx_pack_icmd,
-	.mthd  = nvf0_grctx_pack_mthd,
-	.bundle = nve4_grctx_generate_bundle,
-	.bundle_size = 0x3000,
-	.bundle_min_gpm_fifo_depth = 0xc2,
-	.bundle_token_limit = 0x200,
-	.pagepool = nve4_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x7ff,
-	.alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
deleted file mode 100644
index 7bbb1e1..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * Copyright 2009 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-/* NVIDIA context programs handle a number of other conditions which are
- * not implemented in our versions.  It's not clear why NVIDIA context
- * programs have this code, nor whether it's strictly necessary for
- * correct operation.  We'll implement additional handling if/when we
- * discover it's necessary.
- *
- * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
- *   flag is set, this gets saved into the context.
- * - On context save, the context program for all cards load nsource
- *   into a flag register and check for ILLEGAL_MTHD.  If it's set,
- *   opcode 0x60000d is called before resuming normal operation.
- * - Some context programs check more conditions than the above.  NV44
- *   checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
- *   and calls 0x60000d before resuming normal operation.
- * - At the very beginning of NVIDIA's context programs, flag 9 is checked
- *   and if true 0x800001 is called with count=0, pos=0, the flag is cleared
- *   and then the ctxprog is aborted.  It looks like a complicated NOP,
- *   its purpose is unknown.
- * - In the section of code that loads the per-vs state, NVIDIA check
- *   flag 10.  If it's set, they only transfer the small 0x300 byte block
- *   of state + the state for a single vs as opposed to the state for
- *   all vs units.  It doesn't seem likely that it'll occur in normal
- *   operation, especially seeing as it appears NVIDIA may have screwed
- *   up the ctxprogs for some cards and have an invalid instruction
- *   rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
- * - There's a number of places where context offset 0 (where we place
- *   the PRAMIN offset of the context) is loaded into either 0x408000,
- *   0x408004 or 0x408008.  Not sure what's up there either.
- * - The ctxprogs for some cards save 0x400a00 again during the cleanup
- *   path for auto-loadctx.
- */
-
-#define CP_FLAG_CLEAR                 0
-#define CP_FLAG_SET                   1
-#define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
-#define CP_FLAG_SWAP_DIRECTION_LOAD   0
-#define CP_FLAG_SWAP_DIRECTION_SAVE   1
-#define CP_FLAG_USER_SAVE             ((0 * 32) + 5)
-#define CP_FLAG_USER_SAVE_NOT_PENDING 0
-#define CP_FLAG_USER_SAVE_PENDING     1
-#define CP_FLAG_USER_LOAD             ((0 * 32) + 6)
-#define CP_FLAG_USER_LOAD_NOT_PENDING 0
-#define CP_FLAG_USER_LOAD_PENDING     1
-#define CP_FLAG_STATUS                ((3 * 32) + 0)
-#define CP_FLAG_STATUS_IDLE           0
-#define CP_FLAG_STATUS_BUSY           1
-#define CP_FLAG_AUTO_SAVE             ((3 * 32) + 4)
-#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
-#define CP_FLAG_AUTO_SAVE_PENDING     1
-#define CP_FLAG_AUTO_LOAD             ((3 * 32) + 5)
-#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
-#define CP_FLAG_AUTO_LOAD_PENDING     1
-#define CP_FLAG_UNK54                 ((3 * 32) + 6)
-#define CP_FLAG_UNK54_CLEAR           0
-#define CP_FLAG_UNK54_SET             1
-#define CP_FLAG_ALWAYS                ((3 * 32) + 8)
-#define CP_FLAG_ALWAYS_FALSE          0
-#define CP_FLAG_ALWAYS_TRUE           1
-#define CP_FLAG_UNK57                 ((3 * 32) + 9)
-#define CP_FLAG_UNK57_CLEAR           0
-#define CP_FLAG_UNK57_SET             1
-
-#define CP_CTX                   0x00100000
-#define CP_CTX_COUNT             0x000fc000
-#define CP_CTX_COUNT_SHIFT               14
-#define CP_CTX_REG               0x00003fff
-#define CP_LOAD_SR               0x00200000
-#define CP_LOAD_SR_VALUE         0x000fffff
-#define CP_BRA                   0x00400000
-#define CP_BRA_IP                0x0000ff00
-#define CP_BRA_IP_SHIFT                   8
-#define CP_BRA_IF_CLEAR          0x00000080
-#define CP_BRA_FLAG              0x0000007f
-#define CP_WAIT                  0x00500000
-#define CP_WAIT_SET              0x00000080
-#define CP_WAIT_FLAG             0x0000007f
-#define CP_SET                   0x00700000
-#define CP_SET_1                 0x00000080
-#define CP_SET_FLAG              0x0000007f
-#define CP_NEXT_TO_SWAP          0x00600007
-#define CP_NEXT_TO_CURRENT       0x00600009
-#define CP_SET_CONTEXT_POINTER   0x0060000a
-#define CP_END                   0x0060000e
-#define CP_LOAD_MAGIC_UNK01      0x00800001 /* unknown */
-#define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
-#define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
-
-#include "nv40.h"
-#include "ctx.h"
-
-/* TODO:
- *  - get vs count from 0x1540
- */
-
-static int
-nv40_graph_vs_count(struct nouveau_device *device)
-{
-
-	switch (device->chipset) {
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		return 8;
-	case 0x40:
-		return 6;
-	case 0x41:
-	case 0x42:
-		return 5;
-	case 0x43:
-	case 0x44:
-	case 0x46:
-	case 0x4a:
-		return 3;
-	case 0x4c:
-	case 0x4e:
-	case 0x67:
-	default:
-		return 1;
-	}
-}
-
-
-enum cp_label {
-	cp_check_load = 1,
-	cp_setup_auto_load,
-	cp_setup_load,
-	cp_setup_save,
-	cp_swap_state,
-	cp_swap_state3d_3_is_save,
-	cp_prepare_exit,
-	cp_exit,
-};
-
-static void
-nv40_graph_construct_general(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-
-	cp_ctx(ctx, 0x4000a4, 1);
-	gr_def(ctx, 0x4000a4, 0x00000008);
-	cp_ctx(ctx, 0x400144, 58);
-	gr_def(ctx, 0x400144, 0x00000001);
-	cp_ctx(ctx, 0x400314, 1);
-	gr_def(ctx, 0x400314, 0x00000000);
-	cp_ctx(ctx, 0x400400, 10);
-	cp_ctx(ctx, 0x400480, 10);
-	cp_ctx(ctx, 0x400500, 19);
-	gr_def(ctx, 0x400514, 0x00040000);
-	gr_def(ctx, 0x400524, 0x55555555);
-	gr_def(ctx, 0x400528, 0x55555555);
-	gr_def(ctx, 0x40052c, 0x55555555);
-	gr_def(ctx, 0x400530, 0x55555555);
-	cp_ctx(ctx, 0x400560, 6);
-	gr_def(ctx, 0x400568, 0x0000ffff);
-	gr_def(ctx, 0x40056c, 0x0000ffff);
-	cp_ctx(ctx, 0x40057c, 5);
-	cp_ctx(ctx, 0x400710, 3);
-	gr_def(ctx, 0x400710, 0x20010001);
-	gr_def(ctx, 0x400714, 0x0f73ef00);
-	cp_ctx(ctx, 0x400724, 1);
-	gr_def(ctx, 0x400724, 0x02008821);
-	cp_ctx(ctx, 0x400770, 3);
-	if (device->chipset == 0x40) {
-		cp_ctx(ctx, 0x400814, 4);
-		cp_ctx(ctx, 0x400828, 5);
-		cp_ctx(ctx, 0x400840, 5);
-		gr_def(ctx, 0x400850, 0x00000040);
-		cp_ctx(ctx, 0x400858, 4);
-		gr_def(ctx, 0x400858, 0x00000040);
-		gr_def(ctx, 0x40085c, 0x00000040);
-		gr_def(ctx, 0x400864, 0x80000000);
-		cp_ctx(ctx, 0x40086c, 9);
-		gr_def(ctx, 0x40086c, 0x80000000);
-		gr_def(ctx, 0x400870, 0x80000000);
-		gr_def(ctx, 0x400874, 0x80000000);
-		gr_def(ctx, 0x400878, 0x80000000);
-		gr_def(ctx, 0x400888, 0x00000040);
-		gr_def(ctx, 0x40088c, 0x80000000);
-		cp_ctx(ctx, 0x4009c0, 8);
-		gr_def(ctx, 0x4009cc, 0x80000000);
-		gr_def(ctx, 0x4009dc, 0x80000000);
-	} else {
-		cp_ctx(ctx, 0x400840, 20);
-		if (nv44_graph_class(ctx->device)) {
-			for (i = 0; i < 8; i++)
-				gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
-		}
-		gr_def(ctx, 0x400880, 0x00000040);
-		gr_def(ctx, 0x400884, 0x00000040);
-		gr_def(ctx, 0x400888, 0x00000040);
-		cp_ctx(ctx, 0x400894, 11);
-		gr_def(ctx, 0x400894, 0x00000040);
-		if (!nv44_graph_class(ctx->device)) {
-			for (i = 0; i < 8; i++)
-				gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
-		}
-		cp_ctx(ctx, 0x4008e0, 2);
-		cp_ctx(ctx, 0x4008f8, 2);
-		if (device->chipset == 0x4c ||
-		    (device->chipset & 0xf0) == 0x60)
-			cp_ctx(ctx, 0x4009f8, 1);
-	}
-	cp_ctx(ctx, 0x400a00, 73);
-	gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
-	cp_ctx(ctx, 0x401000, 4);
-	cp_ctx(ctx, 0x405004, 1);
-	switch (device->chipset) {
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		cp_ctx(ctx, 0x403448, 1);
-		gr_def(ctx, 0x403448, 0x00001010);
-		break;
-	default:
-		cp_ctx(ctx, 0x403440, 1);
-		switch (device->chipset) {
-		case 0x40:
-			gr_def(ctx, 0x403440, 0x00000010);
-			break;
-		case 0x44:
-		case 0x46:
-		case 0x4a:
-			gr_def(ctx, 0x403440, 0x00003010);
-			break;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x4c:
-		case 0x4e:
-		case 0x67:
-		default:
-			gr_def(ctx, 0x403440, 0x00001010);
-			break;
-		}
-		break;
-	}
-}
-
-static void
-nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-
-	if (device->chipset == 0x40) {
-		cp_ctx(ctx, 0x401880, 51);
-		gr_def(ctx, 0x401940, 0x00000100);
-	} else
-	if (device->chipset == 0x46 || device->chipset == 0x47 ||
-	    device->chipset == 0x49 || device->chipset == 0x4b) {
-		cp_ctx(ctx, 0x401880, 32);
-		for (i = 0; i < 16; i++)
-			gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
-		if (device->chipset == 0x46)
-			cp_ctx(ctx, 0x401900, 16);
-		cp_ctx(ctx, 0x401940, 3);
-	}
-	cp_ctx(ctx, 0x40194c, 18);
-	gr_def(ctx, 0x401954, 0x00000111);
-	gr_def(ctx, 0x401958, 0x00080060);
-	gr_def(ctx, 0x401974, 0x00000080);
-	gr_def(ctx, 0x401978, 0xffff0000);
-	gr_def(ctx, 0x40197c, 0x00000001);
-	gr_def(ctx, 0x401990, 0x46400000);
-	if (device->chipset == 0x40) {
-		cp_ctx(ctx, 0x4019a0, 2);
-		cp_ctx(ctx, 0x4019ac, 5);
-	} else {
-		cp_ctx(ctx, 0x4019a0, 1);
-		cp_ctx(ctx, 0x4019b4, 3);
-	}
-	gr_def(ctx, 0x4019bc, 0xffff0000);
-	switch (device->chipset) {
-	case 0x46:
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		cp_ctx(ctx, 0x4019c0, 18);
-		for (i = 0; i < 16; i++)
-			gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
-		break;
-	}
-	cp_ctx(ctx, 0x401a08, 8);
-	gr_def(ctx, 0x401a10, 0x0fff0000);
-	gr_def(ctx, 0x401a14, 0x0fff0000);
-	gr_def(ctx, 0x401a1c, 0x00011100);
-	cp_ctx(ctx, 0x401a2c, 4);
-	cp_ctx(ctx, 0x401a44, 26);
-	for (i = 0; i < 16; i++)
-		gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
-	gr_def(ctx, 0x401a8c, 0x4b7fffff);
-	if (device->chipset == 0x40) {
-		cp_ctx(ctx, 0x401ab8, 3);
-	} else {
-		cp_ctx(ctx, 0x401ab8, 1);
-		cp_ctx(ctx, 0x401ac0, 1);
-	}
-	cp_ctx(ctx, 0x401ad0, 8);
-	gr_def(ctx, 0x401ad0, 0x30201000);
-	gr_def(ctx, 0x401ad4, 0x70605040);
-	gr_def(ctx, 0x401ad8, 0xb8a89888);
-	gr_def(ctx, 0x401adc, 0xf8e8d8c8);
-	cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
-	gr_def(ctx, 0x401b10, 0x40100000);
-	cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
-	gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
-			      0x00000004 : 0x00000000);
-	cp_ctx(ctx, 0x401b30, 25);
-	gr_def(ctx, 0x401b34, 0x0000ffff);
-	gr_def(ctx, 0x401b68, 0x435185d6);
-	gr_def(ctx, 0x401b6c, 0x2155b699);
-	gr_def(ctx, 0x401b70, 0xfedcba98);
-	gr_def(ctx, 0x401b74, 0x00000098);
-	gr_def(ctx, 0x401b84, 0xffffffff);
-	gr_def(ctx, 0x401b88, 0x00ff7000);
-	gr_def(ctx, 0x401b8c, 0x0000ffff);
-	if (device->chipset != 0x44 && device->chipset != 0x4a &&
-	    device->chipset != 0x4e)
-		cp_ctx(ctx, 0x401b94, 1);
-	cp_ctx(ctx, 0x401b98, 8);
-	gr_def(ctx, 0x401b9c, 0x00ff0000);
-	cp_ctx(ctx, 0x401bc0, 9);
-	gr_def(ctx, 0x401be0, 0x00ffff00);
-	cp_ctx(ctx, 0x401c00, 192);
-	for (i = 0; i < 16; i++) { /* fragment texture units */
-		gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
-		gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
-		gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
-		gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
-		gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
-		gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
-	}
-	for (i = 0; i < 4; i++) { /* vertex texture units */
-		gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
-		gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
-		gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
-		gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
-	}
-	cp_ctx(ctx, 0x400f5c, 3);
-	gr_def(ctx, 0x400f5c, 0x00000002);
-	cp_ctx(ctx, 0x400f84, 1);
-}
-
-static void
-nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-
-	cp_ctx(ctx, 0x402000, 1);
-	cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
-	switch (device->chipset) {
-	case 0x40:
-		gr_def(ctx, 0x402404, 0x00000001);
-		break;
-	case 0x4c:
-	case 0x4e:
-	case 0x67:
-		gr_def(ctx, 0x402404, 0x00000020);
-		break;
-	case 0x46:
-	case 0x49:
-	case 0x4b:
-		gr_def(ctx, 0x402404, 0x00000421);
-		break;
-	default:
-		gr_def(ctx, 0x402404, 0x00000021);
-	}
-	if (device->chipset != 0x40)
-		gr_def(ctx, 0x402408, 0x030c30c3);
-	switch (device->chipset) {
-	case 0x44:
-	case 0x46:
-	case 0x4a:
-	case 0x4c:
-	case 0x4e:
-	case 0x67:
-		cp_ctx(ctx, 0x402440, 1);
-		gr_def(ctx, 0x402440, 0x00011001);
-		break;
-	default:
-		break;
-	}
-	cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
-	gr_def(ctx, 0x402488, 0x3e020200);
-	gr_def(ctx, 0x40248c, 0x00ffffff);
-	switch (device->chipset) {
-	case 0x40:
-		gr_def(ctx, 0x402490, 0x60103f00);
-		break;
-	case 0x47:
-		gr_def(ctx, 0x402490, 0x40103f00);
-		break;
-	case 0x41:
-	case 0x42:
-	case 0x49:
-	case 0x4b:
-		gr_def(ctx, 0x402490, 0x20103f00);
-		break;
-	default:
-		gr_def(ctx, 0x402490, 0x0c103f00);
-		break;
-	}
-	gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
-			      0x00020000 : 0x00040000);
-	cp_ctx(ctx, 0x402500, 31);
-	gr_def(ctx, 0x402530, 0x00008100);
-	if (device->chipset == 0x40)
-		cp_ctx(ctx, 0x40257c, 6);
-	cp_ctx(ctx, 0x402594, 16);
-	cp_ctx(ctx, 0x402800, 17);
-	gr_def(ctx, 0x402800, 0x00000001);
-	switch (device->chipset) {
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		cp_ctx(ctx, 0x402864, 1);
-		gr_def(ctx, 0x402864, 0x00001001);
-		cp_ctx(ctx, 0x402870, 3);
-		gr_def(ctx, 0x402878, 0x00000003);
-		if (device->chipset != 0x47) { /* belong at end!! */
-			cp_ctx(ctx, 0x402900, 1);
-			cp_ctx(ctx, 0x402940, 1);
-			cp_ctx(ctx, 0x402980, 1);
-			cp_ctx(ctx, 0x4029c0, 1);
-			cp_ctx(ctx, 0x402a00, 1);
-			cp_ctx(ctx, 0x402a40, 1);
-			cp_ctx(ctx, 0x402a80, 1);
-			cp_ctx(ctx, 0x402ac0, 1);
-		}
-		break;
-	case 0x40:
-		cp_ctx(ctx, 0x402844, 1);
-		gr_def(ctx, 0x402844, 0x00000001);
-		cp_ctx(ctx, 0x402850, 1);
-		break;
-	default:
-		cp_ctx(ctx, 0x402844, 1);
-		gr_def(ctx, 0x402844, 0x00001001);
-		cp_ctx(ctx, 0x402850, 2);
-		gr_def(ctx, 0x402854, 0x00000003);
-		break;
-	}
-
-	cp_ctx(ctx, 0x402c00, 4);
-	gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
-			      0x80800001 : 0x00888001);
-	switch (device->chipset) {
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		cp_ctx(ctx, 0x402c20, 40);
-		for (i = 0; i < 32; i++)
-			gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
-		cp_ctx(ctx, 0x4030b8, 13);
-		gr_def(ctx, 0x4030dc, 0x00000005);
-		gr_def(ctx, 0x4030e8, 0x0000ffff);
-		break;
-	default:
-		cp_ctx(ctx, 0x402c10, 4);
-		if (device->chipset == 0x40)
-			cp_ctx(ctx, 0x402c20, 36);
-		else
-		if (device->chipset <= 0x42)
-			cp_ctx(ctx, 0x402c20, 24);
-		else
-		if (device->chipset <= 0x4a)
-			cp_ctx(ctx, 0x402c20, 16);
-		else
-			cp_ctx(ctx, 0x402c20, 8);
-		cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
-		gr_def(ctx, 0x402cd4, 0x00000005);
-		if (device->chipset != 0x40)
-			gr_def(ctx, 0x402ce0, 0x0000ffff);
-		break;
-	}
-
-	cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
-	for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
-		gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
-
-	if (device->chipset != 0x40) {
-		cp_ctx(ctx, 0x403600, 1);
-		gr_def(ctx, 0x403600, 0x00000001);
-	}
-	cp_ctx(ctx, 0x403800, 1);
-
-	cp_ctx(ctx, 0x403c18, 1);
-	gr_def(ctx, 0x403c18, 0x00000001);
-	switch (device->chipset) {
-	case 0x46:
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-		cp_ctx(ctx, 0x405018, 1);
-		gr_def(ctx, 0x405018, 0x08e00001);
-		cp_ctx(ctx, 0x405c24, 1);
-		gr_def(ctx, 0x405c24, 0x000e3000);
-		break;
-	}
-	if (device->chipset != 0x4e)
-		cp_ctx(ctx, 0x405800, 11);
-	cp_ctx(ctx, 0x407000, 1);
-}
-
-static void
-nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
-{
-	int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
-
-	cp_out (ctx, 0x300000);
-	cp_lsr (ctx, len - 4);
-	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
-	cp_lsr (ctx, len);
-	cp_name(ctx, cp_swap_state3d_3_is_save);
-	cp_out (ctx, 0x800001);
-
-	ctx->ctxvals_pos += len;
-}
-
-static void
-nv40_graph_construct_shader(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	struct nouveau_gpuobj *obj = ctx->data;
-	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
-	int offset, i;
-
-	vs_nr    = nv40_graph_vs_count(ctx->device);
-	vs_nr_b0 = 363;
-	vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
-	if (device->chipset == 0x40) {
-		b0_offset = 0x2200/4; /* 33a0 */
-		b1_offset = 0x55a0/4; /* 1500 */
-		vs_len = 0x6aa0/4;
-	} else
-	if (device->chipset == 0x41 || device->chipset == 0x42) {
-		b0_offset = 0x2200/4; /* 2200 */
-		b1_offset = 0x4400/4; /* 0b00 */
-		vs_len = 0x4f00/4;
-	} else {
-		b0_offset = 0x1d40/4; /* 2200 */
-		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
-		vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
-	}
-
-	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
-	cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
-
-	offset = ctx->ctxvals_pos;
-	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
-
-	if (ctx->mode != NOUVEAU_GRCTX_VALS)
-		return;
-
-	offset += 0x0280/4;
-	for (i = 0; i < 16; i++, offset += 2)
-		nv_wo32(obj, offset * 4, 0x3f800000);
-
-	for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
-		for (i = 0; i < vs_nr_b0 * 6; i += 6)
-			nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
-		for (i = 0; i < vs_nr_b1 * 4; i += 4)
-			nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
-	}
-}
-
-static void
-nv40_grctx_generate(struct nouveau_grctx *ctx)
-{
-	/* decide whether we're loading/unloading the context */
-	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
-	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
-
-	cp_name(ctx, cp_check_load);
-	cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
-	cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
-	cp_bra (ctx, ALWAYS, TRUE, cp_exit);
-
-	/* setup for context load */
-	cp_name(ctx, cp_setup_auto_load);
-	cp_wait(ctx, STATUS, IDLE);
-	cp_out (ctx, CP_NEXT_TO_SWAP);
-	cp_name(ctx, cp_setup_load);
-	cp_wait(ctx, STATUS, IDLE);
-	cp_set (ctx, SWAP_DIRECTION, LOAD);
-	cp_out (ctx, 0x00910880); /* ?? */
-	cp_out (ctx, 0x00901ffe); /* ?? */
-	cp_out (ctx, 0x01940000); /* ?? */
-	cp_lsr (ctx, 0x20);
-	cp_out (ctx, 0x0060000b); /* ?? */
-	cp_wait(ctx, UNK57, CLEAR);
-	cp_out (ctx, 0x0060000c); /* ?? */
-	cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
-
-	/* setup for context save */
-	cp_name(ctx, cp_setup_save);
-	cp_set (ctx, SWAP_DIRECTION, SAVE);
-
-	/* general PGRAPH state */
-	cp_name(ctx, cp_swap_state);
-	cp_pos (ctx, 0x00020/4);
-	nv40_graph_construct_general(ctx);
-	cp_wait(ctx, STATUS, IDLE);
-
-	/* 3D state, block 1 */
-	cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
-	nv40_graph_construct_state3d(ctx);
-	cp_wait(ctx, STATUS, IDLE);
-
-	/* 3D state, block 2 */
-	nv40_graph_construct_state3d_2(ctx);
-
-	/* Some other block of "random" state */
-	nv40_graph_construct_state3d_3(ctx);
-
-	/* Per-vertex shader state */
-	cp_pos (ctx, ctx->ctxvals_pos);
-	nv40_graph_construct_shader(ctx);
-
-	/* pre-exit state updates */
-	cp_name(ctx, cp_prepare_exit);
-	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
-	cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
-	cp_out (ctx, CP_NEXT_TO_CURRENT);
-
-	cp_name(ctx, cp_exit);
-	cp_set (ctx, USER_SAVE, NOT_PENDING);
-	cp_set (ctx, USER_LOAD, NOT_PENDING);
-	cp_out (ctx, CP_END);
-}
-
-void
-nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
-{
-	nv40_grctx_generate(&(struct nouveau_grctx) {
-			     .device = device,
-			     .mode = NOUVEAU_GRCTX_VALS,
-			     .data = mem,
-			   });
-}
-
-int
-nv40_grctx_init(struct nouveau_device *device, u32 *size)
-{
-	u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;
-	struct nouveau_grctx ctx = {
-		.device = device,
-		.mode = NOUVEAU_GRCTX_PROG,
-		.data = ctxprog,
-		.ctxprog_max = 256,
-	};
-
-	if (!ctxprog)
-		return -ENOMEM;
-
-	nv40_grctx_generate(&ctx);
-
-	nv_wr32(device, 0x400324, 0);
-	for (i = 0; i < ctx.ctxprog_len; i++)
-		nv_wr32(device, 0x400328, ctxprog[i]);
-	*size = ctx.ctxvals_pos * 4;
-
-	kfree(ctxprog);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
deleted file mode 100644
index 1d0e33f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
+++ /dev/null
@@ -1,3347 +0,0 @@
-/*
- * Copyright 2009 Marcin Kościelnicki
- *
- * 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 <core/gpuobj.h>
-
-#define CP_FLAG_CLEAR                 0
-#define CP_FLAG_SET                   1
-#define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
-#define CP_FLAG_SWAP_DIRECTION_LOAD   0
-#define CP_FLAG_SWAP_DIRECTION_SAVE   1
-#define CP_FLAG_UNK01                 ((0 * 32) + 1)
-#define CP_FLAG_UNK01_CLEAR           0
-#define CP_FLAG_UNK01_SET             1
-#define CP_FLAG_UNK03                 ((0 * 32) + 3)
-#define CP_FLAG_UNK03_CLEAR           0
-#define CP_FLAG_UNK03_SET             1
-#define CP_FLAG_USER_SAVE             ((0 * 32) + 5)
-#define CP_FLAG_USER_SAVE_NOT_PENDING 0
-#define CP_FLAG_USER_SAVE_PENDING     1
-#define CP_FLAG_USER_LOAD             ((0 * 32) + 6)
-#define CP_FLAG_USER_LOAD_NOT_PENDING 0
-#define CP_FLAG_USER_LOAD_PENDING     1
-#define CP_FLAG_UNK0B                 ((0 * 32) + 0xb)
-#define CP_FLAG_UNK0B_CLEAR           0
-#define CP_FLAG_UNK0B_SET             1
-#define CP_FLAG_XFER_SWITCH           ((0 * 32) + 0xe)
-#define CP_FLAG_XFER_SWITCH_DISABLE   0
-#define CP_FLAG_XFER_SWITCH_ENABLE    1
-#define CP_FLAG_STATE                 ((0 * 32) + 0x1c)
-#define CP_FLAG_STATE_STOPPED         0
-#define CP_FLAG_STATE_RUNNING         1
-#define CP_FLAG_UNK1D                 ((0 * 32) + 0x1d)
-#define CP_FLAG_UNK1D_CLEAR           0
-#define CP_FLAG_UNK1D_SET             1
-#define CP_FLAG_UNK20                 ((1 * 32) + 0)
-#define CP_FLAG_UNK20_CLEAR           0
-#define CP_FLAG_UNK20_SET             1
-#define CP_FLAG_STATUS                ((2 * 32) + 0)
-#define CP_FLAG_STATUS_BUSY           0
-#define CP_FLAG_STATUS_IDLE           1
-#define CP_FLAG_AUTO_SAVE             ((2 * 32) + 4)
-#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
-#define CP_FLAG_AUTO_SAVE_PENDING     1
-#define CP_FLAG_AUTO_LOAD             ((2 * 32) + 5)
-#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
-#define CP_FLAG_AUTO_LOAD_PENDING     1
-#define CP_FLAG_NEWCTX                ((2 * 32) + 10)
-#define CP_FLAG_NEWCTX_BUSY           0
-#define CP_FLAG_NEWCTX_DONE           1
-#define CP_FLAG_XFER                  ((2 * 32) + 11)
-#define CP_FLAG_XFER_IDLE             0
-#define CP_FLAG_XFER_BUSY             1
-#define CP_FLAG_ALWAYS                ((2 * 32) + 13)
-#define CP_FLAG_ALWAYS_FALSE          0
-#define CP_FLAG_ALWAYS_TRUE           1
-#define CP_FLAG_INTR                  ((2 * 32) + 15)
-#define CP_FLAG_INTR_NOT_PENDING      0
-#define CP_FLAG_INTR_PENDING          1
-
-#define CP_CTX                   0x00100000
-#define CP_CTX_COUNT             0x000f0000
-#define CP_CTX_COUNT_SHIFT               16
-#define CP_CTX_REG               0x00003fff
-#define CP_LOAD_SR               0x00200000
-#define CP_LOAD_SR_VALUE         0x000fffff
-#define CP_BRA                   0x00400000
-#define CP_BRA_IP                0x0001ff00
-#define CP_BRA_IP_SHIFT                   8
-#define CP_BRA_IF_CLEAR          0x00000080
-#define CP_BRA_FLAG              0x0000007f
-#define CP_WAIT                  0x00500000
-#define CP_WAIT_SET              0x00000080
-#define CP_WAIT_FLAG             0x0000007f
-#define CP_SET                   0x00700000
-#define CP_SET_1                 0x00000080
-#define CP_SET_FLAG              0x0000007f
-#define CP_NEWCTX                0x00600004
-#define CP_NEXT_TO_SWAP          0x00600005
-#define CP_SET_CONTEXT_POINTER   0x00600006
-#define CP_SET_XFER_POINTER      0x00600007
-#define CP_ENABLE                0x00600009
-#define CP_END                   0x0060000c
-#define CP_NEXT_TO_CURRENT       0x0060000d
-#define CP_DISABLE1              0x0090ffff
-#define CP_DISABLE2              0x0091ffff
-#define CP_XFER_1      0x008000ff
-#define CP_XFER_2      0x008800ff
-#define CP_SEEK_1      0x00c000ff
-#define CP_SEEK_2      0x00c800ff
-
-#include "nv50.h"
-#include "ctx.h"
-
-#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
-#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
-
-#include <subdev/fb.h>
-
-/*
- * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
- * the GPU itself that does context-switching, but it needs a special
- * microcode to do it. And it's the driver's task to supply this microcode,
- * further known as ctxprog, as well as the initial context values, known
- * as ctxvals.
- *
- * Without ctxprog, you cannot switch contexts. Not even in software, since
- * the majority of context [xfer strands] isn't accessible directly. You're
- * stuck with a single channel, and you also suffer all the problems resulting
- * from missing ctxvals, since you cannot load them.
- *
- * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
- * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
- * since you don't have... some sort of needed setup.
- *
- * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
- * it's too much hassle to handle no-ctxprog as a special case.
- */
-
-/*
- * How ctxprogs work.
- *
- * The ctxprog is written in its own kind of microcode, with very small and
- * crappy set of available commands. You upload it to a small [512 insns]
- * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
- * switch channel. or when the driver explicitely requests it. Stuff visible
- * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
- * the per-channel context save area in VRAM [known as ctxvals or grctx],
- * 4 flags registers, a scratch register, two grctx pointers, plus many
- * random poorly-understood details.
- *
- * When ctxprog runs, it's supposed to check what operations are asked of it,
- * save old context if requested, optionally reset PGRAPH and switch to the
- * new channel, and load the new context. Context consists of three major
- * parts: subset of MMIO registers and two "xfer areas".
- */
-
-/* TODO:
- *  - document unimplemented bits compared to nvidia
- *  - NVAx: make a TP subroutine, use it.
- *  - use 0x4008fc instead of 0x1540?
- */
-
-enum cp_label {
-	cp_check_load = 1,
-	cp_setup_auto_load,
-	cp_setup_load,
-	cp_setup_save,
-	cp_swap_state,
-	cp_prepare_exit,
-	cp_exit,
-};
-
-static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx);
-
-/* Main function: construct the ctxprog skeleton, call the other functions. */
-
-static int
-nv50_grctx_generate(struct nouveau_grctx *ctx)
-{
-	cp_set (ctx, STATE, RUNNING);
-	cp_set (ctx, XFER_SWITCH, ENABLE);
-	/* decide whether we're loading/unloading the context */
-	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
-	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
-
-	cp_name(ctx, cp_check_load);
-	cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
-	cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
-	cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit);
-
-	/* setup for context load */
-	cp_name(ctx, cp_setup_auto_load);
-	cp_out (ctx, CP_DISABLE1);
-	cp_out (ctx, CP_DISABLE2);
-	cp_out (ctx, CP_ENABLE);
-	cp_out (ctx, CP_NEXT_TO_SWAP);
-	cp_set (ctx, UNK01, SET);
-	cp_name(ctx, cp_setup_load);
-	cp_out (ctx, CP_NEWCTX);
-	cp_wait(ctx, NEWCTX, BUSY);
-	cp_set (ctx, UNK1D, CLEAR);
-	cp_set (ctx, SWAP_DIRECTION, LOAD);
-	cp_bra (ctx, UNK0B, SET, cp_prepare_exit);
-	cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
-
-	/* setup for context save */
-	cp_name(ctx, cp_setup_save);
-	cp_set (ctx, UNK1D, SET);
-	cp_wait(ctx, STATUS, BUSY);
-	cp_wait(ctx, INTR, PENDING);
-	cp_bra (ctx, STATUS, BUSY, cp_setup_save);
-	cp_set (ctx, UNK01, SET);
-	cp_set (ctx, SWAP_DIRECTION, SAVE);
-
-	/* general PGRAPH state */
-	cp_name(ctx, cp_swap_state);
-	cp_set (ctx, UNK03, SET);
-	cp_pos (ctx, 0x00004/4);
-	cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */
-	cp_pos (ctx, 0x00100/4);
-	nv50_graph_construct_mmio(ctx);
-	nv50_graph_construct_xfer1(ctx);
-	nv50_graph_construct_xfer2(ctx);
-
-	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
-
-	cp_set (ctx, UNK20, SET);
-	cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */
-	cp_lsr (ctx, ctx->ctxvals_base);
-	cp_out (ctx, CP_SET_XFER_POINTER);
-	cp_lsr (ctx, 4);
-	cp_out (ctx, CP_SEEK_1);
-	cp_out (ctx, CP_XFER_1);
-	cp_wait(ctx, XFER, BUSY);
-
-	/* pre-exit state updates */
-	cp_name(ctx, cp_prepare_exit);
-	cp_set (ctx, UNK01, CLEAR);
-	cp_set (ctx, UNK03, CLEAR);
-	cp_set (ctx, UNK1D, CLEAR);
-
-	cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
-	cp_out (ctx, CP_NEXT_TO_CURRENT);
-
-	cp_name(ctx, cp_exit);
-	cp_set (ctx, USER_SAVE, NOT_PENDING);
-	cp_set (ctx, USER_LOAD, NOT_PENDING);
-	cp_set (ctx, XFER_SWITCH, DISABLE);
-	cp_set (ctx, STATE, STOPPED);
-	cp_out (ctx, CP_END);
-	ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
-
-	return 0;
-}
-
-void
-nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
-{
-	nv50_grctx_generate(&(struct nouveau_grctx) {
-			     .device = device,
-			     .mode = NOUVEAU_GRCTX_VALS,
-			     .data = mem,
-			   });
-}
-
-int
-nv50_grctx_init(struct nouveau_device *device, u32 *size)
-{
-	u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
-	struct nouveau_grctx ctx = {
-		.device = device,
-		.mode = NOUVEAU_GRCTX_PROG,
-		.data = ctxprog,
-		.ctxprog_max = 512,
-	};
-
-	if (!ctxprog)
-		return -ENOMEM;
-	nv50_grctx_generate(&ctx);
-
-	nv_wr32(device, 0x400324, 0);
-	for (i = 0; i < ctx.ctxprog_len; i++)
-		nv_wr32(device, 0x400328, ctxprog[i]);
-	*size = ctx.ctxvals_pos * 4;
-	kfree(ctxprog);
-	return 0;
-}
-
-/*
- * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
- * registers to save/restore and the default values for them.
- */
-
-static void
-nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx);
-
-static void
-nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i, j;
-	int offset, base;
-	u32 units = nv_rd32 (ctx->device, 0x1540);
-
-	/* 0800: DISPATCH */
-	cp_ctx(ctx, 0x400808, 7);
-	gr_def(ctx, 0x400814, 0x00000030);
-	cp_ctx(ctx, 0x400834, 0x32);
-	if (device->chipset == 0x50) {
-		gr_def(ctx, 0x400834, 0xff400040);
-		gr_def(ctx, 0x400838, 0xfff00080);
-		gr_def(ctx, 0x40083c, 0xfff70090);
-		gr_def(ctx, 0x400840, 0xffe806a8);
-	}
-	gr_def(ctx, 0x400844, 0x00000002);
-	if (IS_NVA3F(device->chipset))
-		gr_def(ctx, 0x400894, 0x00001000);
-	gr_def(ctx, 0x4008e8, 0x00000003);
-	gr_def(ctx, 0x4008ec, 0x00001000);
-	if (device->chipset == 0x50)
-		cp_ctx(ctx, 0x400908, 0xb);
-	else if (device->chipset < 0xa0)
-		cp_ctx(ctx, 0x400908, 0xc);
-	else
-		cp_ctx(ctx, 0x400908, 0xe);
-
-	if (device->chipset >= 0xa0)
-		cp_ctx(ctx, 0x400b00, 0x1);
-	if (IS_NVA3F(device->chipset)) {
-		cp_ctx(ctx, 0x400b10, 0x1);
-		gr_def(ctx, 0x400b10, 0x0001629d);
-		cp_ctx(ctx, 0x400b20, 0x1);
-		gr_def(ctx, 0x400b20, 0x0001629d);
-	}
-
-	nv50_graph_construct_mmio_ddata(ctx);
-
-	/* 0C00: VFETCH */
-	cp_ctx(ctx, 0x400c08, 0x2);
-	gr_def(ctx, 0x400c08, 0x0000fe0c);
-
-	/* 1000 */
-	if (device->chipset < 0xa0) {
-		cp_ctx(ctx, 0x401008, 0x4);
-		gr_def(ctx, 0x401014, 0x00001000);
-	} else if (!IS_NVA3F(device->chipset)) {
-		cp_ctx(ctx, 0x401008, 0x5);
-		gr_def(ctx, 0x401018, 0x00001000);
-	} else {
-		cp_ctx(ctx, 0x401008, 0x5);
-		gr_def(ctx, 0x401018, 0x00004000);
-	}
-
-	/* 1400 */
-	cp_ctx(ctx, 0x401400, 0x8);
-	cp_ctx(ctx, 0x401424, 0x3);
-	if (device->chipset == 0x50)
-		gr_def(ctx, 0x40142c, 0x0001fd87);
-	else
-		gr_def(ctx, 0x40142c, 0x00000187);
-	cp_ctx(ctx, 0x401540, 0x5);
-	gr_def(ctx, 0x401550, 0x00001018);
-
-	/* 1800: STREAMOUT */
-	cp_ctx(ctx, 0x401814, 0x1);
-	gr_def(ctx, 0x401814, 0x000000ff);
-	if (device->chipset == 0x50) {
-		cp_ctx(ctx, 0x40181c, 0xe);
-		gr_def(ctx, 0x401850, 0x00000004);
-	} else if (device->chipset < 0xa0) {
-		cp_ctx(ctx, 0x40181c, 0xf);
-		gr_def(ctx, 0x401854, 0x00000004);
-	} else {
-		cp_ctx(ctx, 0x40181c, 0x13);
-		gr_def(ctx, 0x401864, 0x00000004);
-	}
-
-	/* 1C00 */
-	cp_ctx(ctx, 0x401c00, 0x1);
-	switch (device->chipset) {
-	case 0x50:
-		gr_def(ctx, 0x401c00, 0x0001005f);
-		break;
-	case 0x84:
-	case 0x86:
-	case 0x94:
-		gr_def(ctx, 0x401c00, 0x044d00df);
-		break;
-	case 0x92:
-	case 0x96:
-	case 0x98:
-	case 0xa0:
-	case 0xaa:
-	case 0xac:
-		gr_def(ctx, 0x401c00, 0x042500df);
-		break;
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-	case 0xaf:
-		gr_def(ctx, 0x401c00, 0x142500df);
-		break;
-	}
-
-	/* 2000 */
-
-	/* 2400 */
-	cp_ctx(ctx, 0x402400, 0x1);
-	if (device->chipset == 0x50)
-		cp_ctx(ctx, 0x402408, 0x1);
-	else
-		cp_ctx(ctx, 0x402408, 0x2);
-	gr_def(ctx, 0x402408, 0x00000600);
-
-	/* 2800: CSCHED */
-	cp_ctx(ctx, 0x402800, 0x1);
-	if (device->chipset == 0x50)
-		gr_def(ctx, 0x402800, 0x00000006);
-
-	/* 2C00: ZCULL */
-	cp_ctx(ctx, 0x402c08, 0x6);
-	if (device->chipset != 0x50)
-		gr_def(ctx, 0x402c14, 0x01000000);
-	gr_def(ctx, 0x402c18, 0x000000ff);
-	if (device->chipset == 0x50)
-		cp_ctx(ctx, 0x402ca0, 0x1);
-	else
-		cp_ctx(ctx, 0x402ca0, 0x2);
-	if (device->chipset < 0xa0)
-		gr_def(ctx, 0x402ca0, 0x00000400);
-	else if (!IS_NVA3F(device->chipset))
-		gr_def(ctx, 0x402ca0, 0x00000800);
-	else
-		gr_def(ctx, 0x402ca0, 0x00000400);
-	cp_ctx(ctx, 0x402cac, 0x4);
-
-	/* 3000: ENG2D */
-	cp_ctx(ctx, 0x403004, 0x1);
-	gr_def(ctx, 0x403004, 0x00000001);
-
-	/* 3400 */
-	if (device->chipset >= 0xa0) {
-		cp_ctx(ctx, 0x403404, 0x1);
-		gr_def(ctx, 0x403404, 0x00000001);
-	}
-
-	/* 5000: CCACHE */
-	cp_ctx(ctx, 0x405000, 0x1);
-	switch (device->chipset) {
-	case 0x50:
-		gr_def(ctx, 0x405000, 0x00300080);
-		break;
-	case 0x84:
-	case 0xa0:
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-	case 0xaa:
-	case 0xac:
-	case 0xaf:
-		gr_def(ctx, 0x405000, 0x000e0080);
-		break;
-	case 0x86:
-	case 0x92:
-	case 0x94:
-	case 0x96:
-	case 0x98:
-		gr_def(ctx, 0x405000, 0x00000080);
-		break;
-	}
-	cp_ctx(ctx, 0x405014, 0x1);
-	gr_def(ctx, 0x405014, 0x00000004);
-	cp_ctx(ctx, 0x40501c, 0x1);
-	cp_ctx(ctx, 0x405024, 0x1);
-	cp_ctx(ctx, 0x40502c, 0x1);
-
-	/* 6000? */
-	if (device->chipset == 0x50)
-		cp_ctx(ctx, 0x4063e0, 0x1);
-
-	/* 6800: M2MF */
-	if (device->chipset < 0x90) {
-		cp_ctx(ctx, 0x406814, 0x2b);
-		gr_def(ctx, 0x406818, 0x00000f80);
-		gr_def(ctx, 0x406860, 0x007f0080);
-		gr_def(ctx, 0x40689c, 0x007f0080);
-	} else {
-		cp_ctx(ctx, 0x406814, 0x4);
-		if (device->chipset == 0x98)
-			gr_def(ctx, 0x406818, 0x00000f80);
-		else
-			gr_def(ctx, 0x406818, 0x00001f80);
-		if (IS_NVA3F(device->chipset))
-			gr_def(ctx, 0x40681c, 0x00000030);
-		cp_ctx(ctx, 0x406830, 0x3);
-	}
-
-	/* 7000: per-ROP group state */
-	for (i = 0; i < 8; i++) {
-		if (units & (1<<(i+16))) {
-			cp_ctx(ctx, 0x407000 + (i<<8), 3);
-			if (device->chipset == 0x50)
-				gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
-			else if (device->chipset != 0xa5)
-				gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
-			else
-				gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
-			gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
-
-			if (device->chipset == 0x50) {
-				cp_ctx(ctx, 0x407010 + (i<<8), 1);
-			} else if (device->chipset < 0xa0) {
-				cp_ctx(ctx, 0x407010 + (i<<8), 2);
-				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
-				gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
-			} else {
-				cp_ctx(ctx, 0x407010 + (i<<8), 3);
-				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
-				if (device->chipset != 0xa5)
-					gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
-				else
-					gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
-			}
-
-			cp_ctx(ctx, 0x407080 + (i<<8), 4);
-			if (device->chipset != 0xa5)
-				gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
-			else
-				gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
-			if (device->chipset == 0x50)
-				gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
-			else
-				gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
-			gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
-
-			if (device->chipset < 0xa0)
-				cp_ctx(ctx, 0x407094 + (i<<8), 1);
-			else if (!IS_NVA3F(device->chipset))
-				cp_ctx(ctx, 0x407094 + (i<<8), 3);
-			else {
-				cp_ctx(ctx, 0x407094 + (i<<8), 4);
-				gr_def(ctx, 0x4070a0 + (i<<8), 1);
-			}
-		}
-	}
-
-	cp_ctx(ctx, 0x407c00, 0x3);
-	if (device->chipset < 0x90)
-		gr_def(ctx, 0x407c00, 0x00010040);
-	else if (device->chipset < 0xa0)
-		gr_def(ctx, 0x407c00, 0x00390040);
-	else
-		gr_def(ctx, 0x407c00, 0x003d0040);
-	gr_def(ctx, 0x407c08, 0x00000022);
-	if (device->chipset >= 0xa0) {
-		cp_ctx(ctx, 0x407c10, 0x3);
-		cp_ctx(ctx, 0x407c20, 0x1);
-		cp_ctx(ctx, 0x407c2c, 0x1);
-	}
-
-	if (device->chipset < 0xa0) {
-		cp_ctx(ctx, 0x407d00, 0x9);
-	} else {
-		cp_ctx(ctx, 0x407d00, 0x15);
-	}
-	if (device->chipset == 0x98)
-		gr_def(ctx, 0x407d08, 0x00380040);
-	else {
-		if (device->chipset < 0x90)
-			gr_def(ctx, 0x407d08, 0x00010040);
-		else if (device->chipset < 0xa0)
-			gr_def(ctx, 0x407d08, 0x00390040);
-		else {
-			if (nouveau_fb(device)->ram->type != NV_MEM_TYPE_GDDR5)
-				gr_def(ctx, 0x407d08, 0x003d0040);
-			else
-				gr_def(ctx, 0x407d08, 0x003c0040);
-		}
-		gr_def(ctx, 0x407d0c, 0x00000022);
-	}
-
-	/* 8000+: per-TP state */
-	for (i = 0; i < 10; i++) {
-		if (units & (1<<i)) {
-			if (device->chipset < 0xa0)
-				base = 0x408000 + (i<<12);
-			else
-				base = 0x408000 + (i<<11);
-			if (device->chipset < 0xa0)
-				offset = base + 0xc00;
-			else
-				offset = base + 0x80;
-			cp_ctx(ctx, offset + 0x00, 1);
-			gr_def(ctx, offset + 0x00, 0x0000ff0a);
-			cp_ctx(ctx, offset + 0x08, 1);
-
-			/* per-MP state */
-			for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
-				if (!(units & (1 << (j+24)))) continue;
-				if (device->chipset < 0xa0)
-					offset = base + 0x200 + (j<<7);
-				else
-					offset = base + 0x100 + (j<<7);
-				cp_ctx(ctx, offset, 0x20);
-				gr_def(ctx, offset + 0x00, 0x01800000);
-				gr_def(ctx, offset + 0x04, 0x00160000);
-				gr_def(ctx, offset + 0x08, 0x01800000);
-				gr_def(ctx, offset + 0x18, 0x0003ffff);
-				switch (device->chipset) {
-				case 0x50:
-					gr_def(ctx, offset + 0x1c, 0x00080000);
-					break;
-				case 0x84:
-					gr_def(ctx, offset + 0x1c, 0x00880000);
-					break;
-				case 0x86:
-					gr_def(ctx, offset + 0x1c, 0x018c0000);
-					break;
-				case 0x92:
-				case 0x96:
-				case 0x98:
-					gr_def(ctx, offset + 0x1c, 0x118c0000);
-					break;
-				case 0x94:
-					gr_def(ctx, offset + 0x1c, 0x10880000);
-					break;
-				case 0xa0:
-				case 0xa5:
-					gr_def(ctx, offset + 0x1c, 0x310c0000);
-					break;
-				case 0xa3:
-				case 0xa8:
-				case 0xaa:
-				case 0xac:
-				case 0xaf:
-					gr_def(ctx, offset + 0x1c, 0x300c0000);
-					break;
-				}
-				gr_def(ctx, offset + 0x40, 0x00010401);
-				if (device->chipset == 0x50)
-					gr_def(ctx, offset + 0x48, 0x00000040);
-				else
-					gr_def(ctx, offset + 0x48, 0x00000078);
-				gr_def(ctx, offset + 0x50, 0x000000bf);
-				gr_def(ctx, offset + 0x58, 0x00001210);
-				if (device->chipset == 0x50)
-					gr_def(ctx, offset + 0x5c, 0x00000080);
-				else
-					gr_def(ctx, offset + 0x5c, 0x08000080);
-				if (device->chipset >= 0xa0)
-					gr_def(ctx, offset + 0x68, 0x0000003e);
-			}
-
-			if (device->chipset < 0xa0)
-				cp_ctx(ctx, base + 0x300, 0x4);
-			else
-				cp_ctx(ctx, base + 0x300, 0x5);
-			if (device->chipset == 0x50)
-				gr_def(ctx, base + 0x304, 0x00007070);
-			else if (device->chipset < 0xa0)
-				gr_def(ctx, base + 0x304, 0x00027070);
-			else if (!IS_NVA3F(device->chipset))
-				gr_def(ctx, base + 0x304, 0x01127070);
-			else
-				gr_def(ctx, base + 0x304, 0x05127070);
-
-			if (device->chipset < 0xa0)
-				cp_ctx(ctx, base + 0x318, 1);
-			else
-				cp_ctx(ctx, base + 0x320, 1);
-			if (device->chipset == 0x50)
-				gr_def(ctx, base + 0x318, 0x0003ffff);
-			else if (device->chipset < 0xa0)
-				gr_def(ctx, base + 0x318, 0x03ffffff);
-			else
-				gr_def(ctx, base + 0x320, 0x07ffffff);
-
-			if (device->chipset < 0xa0)
-				cp_ctx(ctx, base + 0x324, 5);
-			else
-				cp_ctx(ctx, base + 0x328, 4);
-
-			if (device->chipset < 0xa0) {
-				cp_ctx(ctx, base + 0x340, 9);
-				offset = base + 0x340;
-			} else if (!IS_NVA3F(device->chipset)) {
-				cp_ctx(ctx, base + 0x33c, 0xb);
-				offset = base + 0x344;
-			} else {
-				cp_ctx(ctx, base + 0x33c, 0xd);
-				offset = base + 0x344;
-			}
-			gr_def(ctx, offset + 0x0, 0x00120407);
-			gr_def(ctx, offset + 0x4, 0x05091507);
-			if (device->chipset == 0x84)
-				gr_def(ctx, offset + 0x8, 0x05100202);
-			else
-				gr_def(ctx, offset + 0x8, 0x05010202);
-			gr_def(ctx, offset + 0xc, 0x00030201);
-			if (device->chipset == 0xa3)
-				cp_ctx(ctx, base + 0x36c, 1);
-
-			cp_ctx(ctx, base + 0x400, 2);
-			gr_def(ctx, base + 0x404, 0x00000040);
-			cp_ctx(ctx, base + 0x40c, 2);
-			gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
-			gr_def(ctx, base + 0x410, 0x00141210);
-
-			if (device->chipset < 0xa0)
-				offset = base + 0x800;
-			else
-				offset = base + 0x500;
-			cp_ctx(ctx, offset, 6);
-			gr_def(ctx, offset + 0x0, 0x000001f0);
-			gr_def(ctx, offset + 0x4, 0x00000001);
-			gr_def(ctx, offset + 0x8, 0x00000003);
-			if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
-				gr_def(ctx, offset + 0xc, 0x00008000);
-			gr_def(ctx, offset + 0x14, 0x00039e00);
-			cp_ctx(ctx, offset + 0x1c, 2);
-			if (device->chipset == 0x50)
-				gr_def(ctx, offset + 0x1c, 0x00000040);
-			else
-				gr_def(ctx, offset + 0x1c, 0x00000100);
-			gr_def(ctx, offset + 0x20, 0x00003800);
-
-			if (device->chipset >= 0xa0) {
-				cp_ctx(ctx, base + 0x54c, 2);
-				if (!IS_NVA3F(device->chipset))
-					gr_def(ctx, base + 0x54c, 0x003fe006);
-				else
-					gr_def(ctx, base + 0x54c, 0x003fe007);
-				gr_def(ctx, base + 0x550, 0x003fe000);
-			}
-
-			if (device->chipset < 0xa0)
-				offset = base + 0xa00;
-			else
-				offset = base + 0x680;
-			cp_ctx(ctx, offset, 1);
-			gr_def(ctx, offset, 0x00404040);
-
-			if (device->chipset < 0xa0)
-				offset = base + 0xe00;
-			else
-				offset = base + 0x700;
-			cp_ctx(ctx, offset, 2);
-			if (device->chipset < 0xa0)
-				gr_def(ctx, offset, 0x0077f005);
-			else if (device->chipset == 0xa5)
-				gr_def(ctx, offset, 0x6cf7f007);
-			else if (device->chipset == 0xa8)
-				gr_def(ctx, offset, 0x6cfff007);
-			else if (device->chipset == 0xac)
-				gr_def(ctx, offset, 0x0cfff007);
-			else
-				gr_def(ctx, offset, 0x0cf7f007);
-			if (device->chipset == 0x50)
-				gr_def(ctx, offset + 0x4, 0x00007fff);
-			else if (device->chipset < 0xa0)
-				gr_def(ctx, offset + 0x4, 0x003f7fff);
-			else
-				gr_def(ctx, offset + 0x4, 0x02bf7fff);
-			cp_ctx(ctx, offset + 0x2c, 1);
-			if (device->chipset == 0x50) {
-				cp_ctx(ctx, offset + 0x50, 9);
-				gr_def(ctx, offset + 0x54, 0x000003ff);
-				gr_def(ctx, offset + 0x58, 0x00000003);
-				gr_def(ctx, offset + 0x5c, 0x00000003);
-				gr_def(ctx, offset + 0x60, 0x000001ff);
-				gr_def(ctx, offset + 0x64, 0x0000001f);
-				gr_def(ctx, offset + 0x68, 0x0000000f);
-				gr_def(ctx, offset + 0x6c, 0x0000000f);
-			} else if (device->chipset < 0xa0) {
-				cp_ctx(ctx, offset + 0x50, 1);
-				cp_ctx(ctx, offset + 0x70, 1);
-			} else {
-				cp_ctx(ctx, offset + 0x50, 1);
-				cp_ctx(ctx, offset + 0x60, 5);
-			}
-		}
-	}
-}
-
-static void
-dd_emit(struct nouveau_grctx *ctx, int num, u32 val) {
-	int i;
-	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
-		for (i = 0; i < num; i++)
-			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
-	ctx->ctxvals_pos += num;
-}
-
-static void
-nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int base, num;
-	base = ctx->ctxvals_pos;
-
-	/* tesla state */
-	dd_emit(ctx, 1, 0);	/* 00000001 UNK0F90 */
-	dd_emit(ctx, 1, 0);	/* 00000001 UNK135C */
-
-	/* SRC_TIC state */
-	dd_emit(ctx, 1, 0);	/* 00000007 SRC_TILE_MODE_Z */
-	dd_emit(ctx, 1, 2);	/* 00000007 SRC_TILE_MODE_Y */
-	dd_emit(ctx, 1, 1);	/* 00000001 SRC_LINEAR #1 */
-	dd_emit(ctx, 1, 0);	/* 000000ff SRC_ADDRESS_HIGH */
-	dd_emit(ctx, 1, 0);	/* 00000001 SRC_SRGB */
-	if (device->chipset >= 0x94)
-		dd_emit(ctx, 1, 0);	/* 00000003 eng2d UNK0258 */
-	dd_emit(ctx, 1, 1);	/* 00000fff SRC_DEPTH */
-	dd_emit(ctx, 1, 0x100);	/* 0000ffff SRC_HEIGHT */
-
-	/* turing state */
-	dd_emit(ctx, 1, 0);		/* 0000000f TEXTURES_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 0000000f SAMPLERS_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
-	dd_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
-	dd_emit(ctx, 1, 0);		/* ffffffff SHARED_SIZE */
-	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
-	dd_emit(ctx, 1, 1);		/* 0000ffff BLOCK_ALLOC_THREADS */
-	dd_emit(ctx, 1, 1);		/* 00000001 LANES32 */
-	dd_emit(ctx, 1, 0);		/* 000000ff UNK370 */
-	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_UNK */
-	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_COUNT */
-	dd_emit(ctx, 1, 1);		/* 000000ff UNK384 bits 8-15 */
-	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
-	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
-	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
-	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_X */
-	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_XMY */
-	dd_emit(ctx, 1, 0);		/* 00000001 BLOCKDIM_XMY_OVERFLOW */
-	dd_emit(ctx, 1, 1);		/* 0003ffff BLOCKDIM_XMYMZ */
-	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_Y */
-	dd_emit(ctx, 1, 1);		/* 0000007f BLOCKDIM_Z */
-	dd_emit(ctx, 1, 4);		/* 000000ff CP_REG_ALLOC_TEMP */
-	dd_emit(ctx, 1, 1);		/* 00000001 BLOCKDIM_DIRTY */
-	if (IS_NVA3F(device->chipset))
-		dd_emit(ctx, 1, 0);	/* 00000003 UNK03E8 */
-	dd_emit(ctx, 1, 1);		/* 0000007f BLOCK_ALLOC_HALFWARPS */
-	dd_emit(ctx, 1, 1);		/* 00000007 LOCAL_WARPS_NO_CLAMP */
-	dd_emit(ctx, 1, 7);		/* 00000007 LOCAL_WARPS_LOG_ALLOC */
-	dd_emit(ctx, 1, 1);		/* 00000007 STACK_WARPS_NO_CLAMP */
-	dd_emit(ctx, 1, 7);		/* 00000007 STACK_WARPS_LOG_ALLOC */
-	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
-	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
-	dd_emit(ctx, 1, 1);		/* 000007ff BLOCK_ALLOC_THREADS */
-
-	/* compat 2d state */
-	if (device->chipset == 0x50) {
-		dd_emit(ctx, 4, 0);		/* 0000ffff clip X, Y, W, H */
-
-		dd_emit(ctx, 1, 1);		/* ffffffff chroma COLOR_FORMAT */
-
-		dd_emit(ctx, 1, 1);		/* ffffffff pattern COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff pattern SHAPE */
-		dd_emit(ctx, 1, 1);		/* ffffffff pattern PATTERN_SELECT */
-
-		dd_emit(ctx, 1, 0xa);		/* ffffffff surf2d SRC_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff surf2d DMA_SRC */
-		dd_emit(ctx, 1, 0);		/* 000000ff surf2d SRC_ADDRESS_HIGH */
-		dd_emit(ctx, 1, 0);		/* ffffffff surf2d SRC_ADDRESS_LOW */
-		dd_emit(ctx, 1, 0x40);		/* 0000ffff surf2d SRC_PITCH */
-		dd_emit(ctx, 1, 0);		/* 0000000f surf2d SRC_TILE_MODE_Z */
-		dd_emit(ctx, 1, 2);		/* 0000000f surf2d SRC_TILE_MODE_Y */
-		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_HEIGHT */
-		dd_emit(ctx, 1, 1);		/* 00000001 surf2d SRC_LINEAR */
-		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_WIDTH */
-
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_X */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_Y */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_X */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_Y */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_X */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_Y */
-		dd_emit(ctx, 1, 1);		/* ffffffff gdirect COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff gdirect OPERATION */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_X */
-		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_Y */
-
-		dd_emit(ctx, 1, 0);		/* 0000ffff blit SRC_Y */
-		dd_emit(ctx, 1, 0);		/* ffffffff blit OPERATION */
-
-		dd_emit(ctx, 1, 0);		/* ffffffff ifc OPERATION */
-
-		dd_emit(ctx, 1, 0);		/* ffffffff iifc INDEX_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff iifc LUT_OFFSET */
-		dd_emit(ctx, 1, 4);		/* ffffffff iifc COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff iifc OPERATION */
-	}
-
-	/* m2mf state */
-	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_COUNT */
-	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_LENGTH_IN */
-	dd_emit(ctx, 2, 0);		/* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
-	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_OUT */
-	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_OUT */
-	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_OUT_Z */
-	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_OUT */
-	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
-	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_OUT */
-	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_IN */
-	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_IN */
-	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_IN_Z */
-	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_IN */
-	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_IN_X, Y */
-	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_IN */
-
-	/* more compat 2d state */
-	if (device->chipset == 0x50) {
-		dd_emit(ctx, 1, 1);		/* ffffffff line COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff line OPERATION */
-
-		dd_emit(ctx, 1, 1);		/* ffffffff triangle COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff triangle OPERATION */
-
-		dd_emit(ctx, 1, 0);		/* 0000000f sifm TILE_MODE_Z */
-		dd_emit(ctx, 1, 2);		/* 0000000f sifm TILE_MODE_Y */
-		dd_emit(ctx, 1, 0);		/* 000000ff sifm FORMAT_FILTER */
-		dd_emit(ctx, 1, 1);		/* 000000ff sifm FORMAT_ORIGIN */
-		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_PITCH */
-		dd_emit(ctx, 1, 1);		/* 00000001 sifm SRC_LINEAR */
-		dd_emit(ctx, 1, 0);		/* 000000ff sifm SRC_OFFSET_HIGH */
-		dd_emit(ctx, 1, 0);		/* ffffffff sifm SRC_OFFSET */
-		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_HEIGHT */
-		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_WIDTH */
-		dd_emit(ctx, 1, 3);		/* ffffffff sifm COLOR_FORMAT */
-		dd_emit(ctx, 1, 0);		/* ffffffff sifm OPERATION */
-
-		dd_emit(ctx, 1, 0);		/* ffffffff sifc OPERATION */
-	}
-
-	/* tesla state */
-	dd_emit(ctx, 1, 0);		/* 0000000f GP_TEXTURES_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 0000000f GP_SAMPLERS_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 000000ff */
-	dd_emit(ctx, 1, 0);		/* ffffffff */
-	dd_emit(ctx, 1, 4);		/* 000000ff UNK12B0_0 */
-	dd_emit(ctx, 1, 0x70);		/* 000000ff UNK12B0_1 */
-	dd_emit(ctx, 1, 0x80);		/* 000000ff UNK12B0_3 */
-	dd_emit(ctx, 1, 0);		/* 000000ff UNK12B0_2 */
-	dd_emit(ctx, 1, 0);		/* 0000000f FP_TEXTURES_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 0000000f FP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(device->chipset)) {
-		dd_emit(ctx, 1, 0);	/* ffffffff */
-		dd_emit(ctx, 1, 0);	/* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
-	} else {
-		dd_emit(ctx, 1, 0);	/* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
-	}
-	dd_emit(ctx, 1, 0xc);		/* 000000ff SEMANTIC_COLOR.BFC0_ID */
-	if (device->chipset != 0x50)
-		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_COLOR.CLMP_EN */
-	dd_emit(ctx, 1, 8);		/* 000000ff SEMANTIC_COLOR.COLR_NR */
-	dd_emit(ctx, 1, 0x14);		/* 000000ff SEMANTIC_COLOR.FFC0_ID */
-	if (device->chipset == 0x50) {
-		dd_emit(ctx, 1, 0);	/* 000000ff SEMANTIC_LAYER */
-		dd_emit(ctx, 1, 0);	/* 00000001 */
-	} else {
-		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_PTSZ.ENABLE */
-		dd_emit(ctx, 1, 0x29);	/* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
-		dd_emit(ctx, 1, 0x27);	/* 000000ff SEMANTIC_PRIM */
-		dd_emit(ctx, 1, 0x26);	/* 000000ff SEMANTIC_LAYER */
-		dd_emit(ctx, 1, 8);	/* 0000000f SMENATIC_CLIP.CLIP_HIGH */
-		dd_emit(ctx, 1, 4);	/* 000000ff SEMANTIC_CLIP.CLIP_LO */
-		dd_emit(ctx, 1, 0x27);	/* 000000ff UNK0FD4 */
-		dd_emit(ctx, 1, 0);	/* 00000001 UNK1900 */
-	}
-	dd_emit(ctx, 1, 0);		/* 00000007 RT_CONTROL_MAP0 */
-	dd_emit(ctx, 1, 1);		/* 00000007 RT_CONTROL_MAP1 */
-	dd_emit(ctx, 1, 2);		/* 00000007 RT_CONTROL_MAP2 */
-	dd_emit(ctx, 1, 3);		/* 00000007 RT_CONTROL_MAP3 */
-	dd_emit(ctx, 1, 4);		/* 00000007 RT_CONTROL_MAP4 */
-	dd_emit(ctx, 1, 5);		/* 00000007 RT_CONTROL_MAP5 */
-	dd_emit(ctx, 1, 6);		/* 00000007 RT_CONTROL_MAP6 */
-	dd_emit(ctx, 1, 7);		/* 00000007 RT_CONTROL_MAP7 */
-	dd_emit(ctx, 1, 1);		/* 0000000f RT_CONTROL_COUNT */
-	dd_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_UNK */
-	dd_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
-	dd_emit(ctx, 1, 0xcf);		/* 000000ff RT_FORMAT */
-	dd_emit(ctx, 7, 0);		/* 000000ff RT_FORMAT */
-	if (device->chipset != 0x50)
-		dd_emit(ctx, 3, 0);	/* 1, 1, 1 */
-	else
-		dd_emit(ctx, 2, 0);	/* 1, 1 */
-	dd_emit(ctx, 1, 0);		/* ffffffff GP_ENABLE */
-	dd_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
-	dd_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
-	dd_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	if (IS_NVA3F(device->chipset)) {
-		dd_emit(ctx, 1, 3);	/* 00000003 */
-		dd_emit(ctx, 1, 0);	/* 00000001 UNK1418. Alone. */
-	}
-	if (device->chipset != 0x50)
-		dd_emit(ctx, 1, 3);	/* 00000003 UNK15AC */
-	dd_emit(ctx, 1, 1);		/* ffffffff RASTERIZE_ENABLE */
-	dd_emit(ctx, 1, 0);		/* 00000001 FP_CONTROL.EXPORTS_Z */
-	if (device->chipset != 0x50)
-		dd_emit(ctx, 1, 0);	/* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
-	dd_emit(ctx, 1, 0x12);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT */
-	dd_emit(ctx, 1, 0x10);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
-	dd_emit(ctx, 1, 0xc);		/* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
-	dd_emit(ctx, 1, 1);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
-	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
-	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
-	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
-	dd_emit(ctx, 1, 4);		/* 000000ff FP_RESULT_COUNT */
-	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
-	dd_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
-	if (device->chipset >= 0xa0)
-		dd_emit(ctx, 1, 0);	/* ffffffff */
-	dd_emit(ctx, 1, 0);		/* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
-	dd_emit(ctx, 1, 0);		/* ffffffff STRMOUT_ENABLE */
-	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
-	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
-	dd_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE*/
-	if (device->chipset != 0x50)
-		dd_emit(ctx, 8, 0);	/* 00000001 */
-	if (device->chipset >= 0xa0) {
-		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.COMP */
-		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.SIZE */
-		dd_emit(ctx, 1, 2);	/* 00000007 VTX_ATTR_DEFINE.TYPE */
-		dd_emit(ctx, 1, 0);	/* 000000ff VTX_ATTR_DEFINE.ATTR */
-	}
-	dd_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	dd_emit(ctx, 1, 0x14);		/* 0000001f ZETA_FORMAT */
-	dd_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	dd_emit(ctx, 1, 0);		/* 0000000f VP_TEXTURES_LOG2 */
-	dd_emit(ctx, 1, 0);		/* 0000000f VP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(device->chipset))
-		dd_emit(ctx, 1, 0);	/* 00000001 */
-	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_BACK */
-	if (device->chipset >= 0xa0)
-		dd_emit(ctx, 1, 0);	/* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
-	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
-	if (device->chipset >= 0xa0)
-		dd_emit(ctx, 1, 0);	/* 00000003 */
-	dd_emit(ctx, 1, 0);		/* 00000001 CULL_FACE_ENABLE */
-	dd_emit(ctx, 1, 1);		/* 00000003 CULL_FACE */
-	dd_emit(ctx, 1, 0);		/* 00000001 FRONT_FACE */
-	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_FRONT */
-	dd_emit(ctx, 1, 0x1000);	/* 00007fff UNK141C */
-	if (device->chipset != 0x50) {
-		dd_emit(ctx, 1, 0xe00);		/* 7fff */
-		dd_emit(ctx, 1, 0x1000);	/* 7fff */
-		dd_emit(ctx, 1, 0x1e00);	/* 7fff */
-	}
-	dd_emit(ctx, 1, 0);		/* 00000001 BEGIN_END_ACTIVE */
-	dd_emit(ctx, 1, 1);		/* 00000001 POLYGON_MODE_??? */
-	dd_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
-	dd_emit(ctx, 1, 1);		/* 000000ff FP_REG_ALLOC_TEMP... without /4? */
-	dd_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
-	dd_emit(ctx, 1, 1);		/* 00000001 */
-	dd_emit(ctx, 1, 0);		/* 00000001 */
-	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
-	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
-	dd_emit(ctx, 1, 0x200);		/* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
-	if (IS_NVA3F(device->chipset))
-		dd_emit(ctx, 1, 0x200);
-	dd_emit(ctx, 1, 0);		/* 00000001 */
-	if (device->chipset < 0xa0) {
-		dd_emit(ctx, 1, 1);	/* 00000001 */
-		dd_emit(ctx, 1, 0x70);	/* 000000ff */
-		dd_emit(ctx, 1, 0x80);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 00000001 */
-		dd_emit(ctx, 1, 1);	/* 00000001 */
-		dd_emit(ctx, 1, 0x70);	/* 000000ff */
-		dd_emit(ctx, 1, 0x80);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 000000ff */
-	} else {
-		dd_emit(ctx, 1, 1);	/* 00000001 */
-		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
-		dd_emit(ctx, 1, 0xff);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 00000001 */
-		dd_emit(ctx, 1, 1);	/* 00000001 */
-		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
-		dd_emit(ctx, 1, 0xff);	/* 000000ff */
-		dd_emit(ctx, 1, 0);	/* 000000ff */
-		dd_emit(ctx, 1, 9);	/* 0000003f UNK114C.COMP,SIZE */
-	}
-
-	/* eng2d state */
-	dd_emit(ctx, 1, 0);		/* 00000001 eng2d COLOR_KEY_ENABLE */
-	dd_emit(ctx, 1, 0);		/* 00000007 eng2d COLOR_KEY_FORMAT */
-	dd_emit(ctx, 1, 1);		/* ffffffff eng2d DST_DEPTH */
-	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DST_FORMAT */
-	dd_emit(ctx, 1, 0);		/* ffffffff eng2d DST_LAYER */
-	dd_emit(ctx, 1, 1);		/* 00000001 eng2d DST_LINEAR */
-	dd_emit(ctx, 1, 0);		/* 00000007 eng2d PATTERN_COLOR_FORMAT */
-	dd_emit(ctx, 1, 0);		/* 00000007 eng2d OPERATION */
-	dd_emit(ctx, 1, 0);		/* 00000003 eng2d PATTERN_SELECT */
-	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SIFC_FORMAT */
-	dd_emit(ctx, 1, 0);		/* 00000001 eng2d SIFC_BITMAP_ENABLE */
-	dd_emit(ctx, 1, 2);		/* 00000003 eng2d SIFC_BITMAP_UNK808 */
-	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DU_DX_FRACT */
-	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DU_DX_INT */
-	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DV_DY_FRACT */
-	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DV_DY_INT */
-	dd_emit(ctx, 1, 0);		/* 00000001 eng2d BLIT_CONTROL_FILTER */
-	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DRAW_COLOR_FORMAT */
-	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SRC_FORMAT */
-	dd_emit(ctx, 1, 1);		/* 00000001 eng2d SRC_LINEAR #2 */
-
-	num = ctx->ctxvals_pos - base;
-	ctx->ctxvals_pos = base;
-	if (IS_NVA3F(device->chipset))
-		cp_ctx(ctx, 0x404800, num);
-	else
-		cp_ctx(ctx, 0x405400, num);
-}
-
-/*
- * xfer areas. These are a pain.
- *
- * There are 2 xfer areas: the first one is big and contains all sorts of
- * stuff, the second is small and contains some per-TP context.
- *
- * Each area is split into 8 "strands". The areas, when saved to grctx,
- * are made of 8-word blocks. Each block contains a single word from
- * each strand. The strands are independent of each other, their
- * addresses are unrelated to each other, and data in them is closely
- * packed together. The strand layout varies a bit between cards: here
- * and there, a single word is thrown out in the middle and the whole
- * strand is offset by a bit from corresponding one on another chipset.
- * For this reason, addresses of stuff in strands are almost useless.
- * Knowing sequence of stuff and size of gaps between them is much more
- * useful, and that's how we build the strands in our generator.
- *
- * NVA0 takes this mess to a whole new level by cutting the old strands
- * into a few dozen pieces [known as genes], rearranging them randomly,
- * and putting them back together to make new strands. Hopefully these
- * genes correspond more or less directly to the same PGRAPH subunits
- * as in 400040 register.
- *
- * The most common value in default context is 0, and when the genes
- * are separated by 0's, gene bounduaries are quite speculative...
- * some of them can be clearly deduced, others can be guessed, and yet
- * others won't be resolved without figuring out the real meaning of
- * given ctxval. For the same reason, ending point of each strand
- * is unknown. Except for strand 0, which is the longest strand and
- * its end corresponds to end of the whole xfer.
- *
- * An unsolved mystery is the seek instruction: it takes an argument
- * in bits 8-18, and that argument is clearly the place in strands to
- * seek to... but the offsets don't seem to correspond to offsets as
- * seen in grctx. Perhaps there's another, real, not randomly-changing
- * addressing in strands, and the xfer insn just happens to skip over
- * the unused bits? NV10-NV30 PIPE comes to mind...
- *
- * As far as I know, there's no way to access the xfer areas directly
- * without the help of ctxprog.
- */
-
-static void
-xf_emit(struct nouveau_grctx *ctx, int num, u32 val) {
-	int i;
-	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
-		for (i = 0; i < num; i++)
-			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
-	ctx->ctxvals_pos += num << 3;
-}
-
-/* Gene declarations... */
-
-static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
-
-static void
-nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-	int offset;
-	int size = 0;
-	u32 units = nv_rd32 (ctx->device, 0x1540);
-
-	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
-	ctx->ctxvals_base = offset;
-
-	if (device->chipset < 0xa0) {
-		/* Strand 0 */
-		ctx->ctxvals_pos = offset;
-		nv50_graph_construct_gene_dispatch(ctx);
-		nv50_graph_construct_gene_m2mf(ctx);
-		nv50_graph_construct_gene_unk24xx(ctx);
-		nv50_graph_construct_gene_clipid(ctx);
-		nv50_graph_construct_gene_zcull(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 1 */
-		ctx->ctxvals_pos = offset + 0x1;
-		nv50_graph_construct_gene_vfetch(ctx);
-		nv50_graph_construct_gene_eng2d(ctx);
-		nv50_graph_construct_gene_csched(ctx);
-		nv50_graph_construct_gene_ropm1(ctx);
-		nv50_graph_construct_gene_ropm2(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 2 */
-		ctx->ctxvals_pos = offset + 0x2;
-		nv50_graph_construct_gene_ccache(ctx);
-		nv50_graph_construct_gene_unk1cxx(ctx);
-		nv50_graph_construct_gene_strmout(ctx);
-		nv50_graph_construct_gene_unk14xx(ctx);
-		nv50_graph_construct_gene_unk10xx(ctx);
-		nv50_graph_construct_gene_unk34xx(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 3: per-ROP group state */
-		ctx->ctxvals_pos = offset + 3;
-		for (i = 0; i < 6; i++)
-			if (units & (1 << (i + 16)))
-				nv50_graph_construct_gene_ropc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strands 4-7: per-TP state */
-		for (i = 0; i < 4; i++) {
-			ctx->ctxvals_pos = offset + 4 + i;
-			if (units & (1 << (2 * i)))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << (2 * i + 1)))
-				nv50_graph_construct_xfer_tp(ctx);
-			if ((ctx->ctxvals_pos-offset)/8 > size)
-				size = (ctx->ctxvals_pos-offset)/8;
-		}
-	} else {
-		/* Strand 0 */
-		ctx->ctxvals_pos = offset;
-		nv50_graph_construct_gene_dispatch(ctx);
-		nv50_graph_construct_gene_m2mf(ctx);
-		nv50_graph_construct_gene_unk34xx(ctx);
-		nv50_graph_construct_gene_csched(ctx);
-		nv50_graph_construct_gene_unk1cxx(ctx);
-		nv50_graph_construct_gene_strmout(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 1 */
-		ctx->ctxvals_pos = offset + 1;
-		nv50_graph_construct_gene_unk10xx(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 2 */
-		ctx->ctxvals_pos = offset + 2;
-		if (device->chipset == 0xa0)
-			nv50_graph_construct_gene_unk14xx(ctx);
-		nv50_graph_construct_gene_unk24xx(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 3 */
-		ctx->ctxvals_pos = offset + 3;
-		nv50_graph_construct_gene_vfetch(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 4 */
-		ctx->ctxvals_pos = offset + 4;
-		nv50_graph_construct_gene_ccache(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 5 */
-		ctx->ctxvals_pos = offset + 5;
-		nv50_graph_construct_gene_ropm2(ctx);
-		nv50_graph_construct_gene_ropm1(ctx);
-		/* per-ROP context */
-		for (i = 0; i < 8; i++)
-			if (units & (1<<(i+16)))
-				nv50_graph_construct_gene_ropc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 6 */
-		ctx->ctxvals_pos = offset + 6;
-		nv50_graph_construct_gene_zcull(ctx);
-		nv50_graph_construct_gene_clipid(ctx);
-		nv50_graph_construct_gene_eng2d(ctx);
-		if (units & (1 << 0))
-			nv50_graph_construct_xfer_tp(ctx);
-		if (units & (1 << 1))
-			nv50_graph_construct_xfer_tp(ctx);
-		if (units & (1 << 2))
-			nv50_graph_construct_xfer_tp(ctx);
-		if (units & (1 << 3))
-			nv50_graph_construct_xfer_tp(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 7 */
-		ctx->ctxvals_pos = offset + 7;
-		if (device->chipset == 0xa0) {
-			if (units & (1 << 4))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << 5))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << 6))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << 7))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << 8))
-				nv50_graph_construct_xfer_tp(ctx);
-			if (units & (1 << 9))
-				nv50_graph_construct_xfer_tp(ctx);
-		} else {
-			nv50_graph_construct_gene_unk14xx(ctx);
-		}
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-	}
-
-	ctx->ctxvals_pos = offset + size * 8;
-	ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
-	cp_lsr (ctx, offset);
-	cp_out (ctx, CP_SET_XFER_POINTER);
-	cp_lsr (ctx, size);
-	cp_out (ctx, CP_SEEK_1);
-	cp_out (ctx, CP_XFER_1);
-	cp_wait(ctx, XFER, BUSY);
-}
-
-/*
- * non-trivial demagiced parts of ctx init go here
- */
-
-static void
-nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
-{
-	/* start of strand 0 */
-	struct nouveau_device *device = ctx->device;
-	/* SEEK */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 5, 0);
-	else if (!IS_NVA3F(device->chipset))
-		xf_emit(ctx, 6, 0);
-	else
-		xf_emit(ctx, 4, 0);
-	/* SEEK */
-	/* the PGRAPH's internal FIFO */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 8*3, 0);
-	else
-		xf_emit(ctx, 0x100*3, 0);
-	/* and another bonus slot?!? */
-	xf_emit(ctx, 3, 0);
-	/* and YET ANOTHER bonus slot? */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 3, 0);
-	/* SEEK */
-	/* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
-	xf_emit(ctx, 9, 0);
-	/* SEEK */
-	xf_emit(ctx, 9, 0);
-	/* SEEK */
-	xf_emit(ctx, 9, 0);
-	/* SEEK */
-	xf_emit(ctx, 9, 0);
-	/* SEEK */
-	if (device->chipset < 0x90)
-		xf_emit(ctx, 4, 0);
-	/* SEEK */
-	xf_emit(ctx, 2, 0);
-	/* SEEK */
-	xf_emit(ctx, 6*2, 0);
-	xf_emit(ctx, 2, 0);
-	/* SEEK */
-	xf_emit(ctx, 2, 0);
-	/* SEEK */
-	xf_emit(ctx, 6*2, 0);
-	xf_emit(ctx, 2, 0);
-	/* SEEK */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 0x1c, 0);
-	else if (device->chipset < 0xa0)
-		xf_emit(ctx, 0x1e, 0);
-	else
-		xf_emit(ctx, 0x22, 0);
-	/* SEEK */
-	xf_emit(ctx, 0x15, 0);
-}
-
-static void
-nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
-{
-	/* Strand 0, right after dispatch */
-	struct nouveau_device *device = ctx->device;
-	int smallm2mf = 0;
-	if (device->chipset < 0x92 || device->chipset == 0x98)
-		smallm2mf = 1;
-	/* SEEK */
-	xf_emit (ctx, 1, 0);		/* DMA_NOTIFY instance >> 4 */
-	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_IN instance >> 4 */
-	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_OUT instance >> 4 */
-	xf_emit (ctx, 1, 0);		/* OFFSET_IN */
-	xf_emit (ctx, 1, 0);		/* OFFSET_OUT */
-	xf_emit (ctx, 1, 0);		/* PITCH_IN */
-	xf_emit (ctx, 1, 0);		/* PITCH_OUT */
-	xf_emit (ctx, 1, 0);		/* LINE_LENGTH */
-	xf_emit (ctx, 1, 0);		/* LINE_COUNT */
-	xf_emit (ctx, 1, 0x21);		/* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */
-	xf_emit (ctx, 1, 1);		/* LINEAR_IN */
-	xf_emit (ctx, 1, 0x2);		/* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */
-	xf_emit (ctx, 1, 0x100);	/* TILING_PITCH_IN */
-	xf_emit (ctx, 1, 0x100);	/* TILING_HEIGHT_IN */
-	xf_emit (ctx, 1, 1);		/* TILING_DEPTH_IN */
-	xf_emit (ctx, 1, 0);		/* TILING_POSITION_IN_Z */
-	xf_emit (ctx, 1, 0);		/* TILING_POSITION_IN */
-	xf_emit (ctx, 1, 1);		/* LINEAR_OUT */
-	xf_emit (ctx, 1, 0x2);		/* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */
-	xf_emit (ctx, 1, 0x100);	/* TILING_PITCH_OUT */
-	xf_emit (ctx, 1, 0x100);	/* TILING_HEIGHT_OUT */
-	xf_emit (ctx, 1, 1);		/* TILING_DEPTH_OUT */
-	xf_emit (ctx, 1, 0);		/* TILING_POSITION_OUT_Z */
-	xf_emit (ctx, 1, 0);		/* TILING_POSITION_OUT */
-	xf_emit (ctx, 1, 0);		/* OFFSET_IN_HIGH */
-	xf_emit (ctx, 1, 0);		/* OFFSET_OUT_HIGH */
-	/* SEEK */
-	if (smallm2mf)
-		xf_emit(ctx, 0x40, 0);	/* 20 * ffffffff, 3ffff */
-	else
-		xf_emit(ctx, 0x100, 0);	/* 80 * ffffffff, 3ffff */
-	xf_emit(ctx, 4, 0);		/* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
-	/* SEEK */
-	if (smallm2mf)
-		xf_emit(ctx, 0x400, 0);	/* ffffffff */
-	else
-		xf_emit(ctx, 0x800, 0);	/* ffffffff */
-	xf_emit(ctx, 4, 0);		/* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
-	/* SEEK */
-	xf_emit(ctx, 0x40, 0);		/* 20 * bits ffffffff, 3ffff */
-	xf_emit(ctx, 0x6, 0);		/* 1f, 0, 1f, 0, 1f, 0 */
-}
-
-static void
-nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 2, 0);		/* RO */
-	xf_emit(ctx, 0x800, 0);		/* ffffffff */
-	switch (device->chipset) {
-	case 0x50:
-	case 0x92:
-	case 0xa0:
-		xf_emit(ctx, 0x2b, 0);
-		break;
-	case 0x84:
-		xf_emit(ctx, 0x29, 0);
-		break;
-	case 0x94:
-	case 0x96:
-	case 0xa3:
-		xf_emit(ctx, 0x27, 0);
-		break;
-	case 0x86:
-	case 0x98:
-	case 0xa5:
-	case 0xa8:
-	case 0xaa:
-	case 0xac:
-	case 0xaf:
-		xf_emit(ctx, 0x25, 0);
-		break;
-	}
-	/* CB bindings, 0x80 of them. first word is address >> 8, second is
-	 * size >> 4 | valid << 24 */
-	xf_emit(ctx, 0x100, 0);		/* ffffffff CB_DEF */
-	xf_emit(ctx, 1, 0);		/* 0000007f CB_ADDR_BUFFER */
-	xf_emit(ctx, 1, 0);		/* 0 */
-	xf_emit(ctx, 0x30, 0);		/* ff SET_PROGRAM_CB */
-	xf_emit(ctx, 1, 0);		/* 3f last SET_PROGRAM_CB */
-	xf_emit(ctx, 4, 0);		/* RO */
-	xf_emit(ctx, 0x100, 0);		/* ffffffff */
-	xf_emit(ctx, 8, 0);		/* 1f, 0, 0, ... */
-	xf_emit(ctx, 8, 0);		/* ffffffff */
-	xf_emit(ctx, 4, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 3 */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CODE_CB */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TIC */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TSC */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
-	xf_emit(ctx, 1, 0);		/* 000000ff TIC_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff TIC_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
-	xf_emit(ctx, 1, 0);		/* 000000ff TSC_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff TSC_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
-	xf_emit(ctx, 1, 0);		/* 000000ff VP_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff VP_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 00ffffff VP_START_ID */
-	xf_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 000000ff GP_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff GP_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 00ffffff GP_START_ID */
-	xf_emit(ctx, 1, 0);		/* 000000ff FP_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff FP_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 00ffffff FP_START_ID */
-}
-
-static void
-nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-	/* end of area 2 on pre-NVA0, area 1 on NVAx */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
-	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);
-	else
-		xf_emit(ctx, 1, 0x7ff);	/* 000007ff */
-	xf_emit(ctx, 1, 0);		/* 111/113 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	for (i = 0; i < 8; i++) {
-		switch (device->chipset) {
-		case 0x50:
-		case 0x86:
-		case 0x98:
-		case 0xaa:
-		case 0xac:
-			xf_emit(ctx, 0xa0, 0);	/* ffffffff */
-			break;
-		case 0x84:
-		case 0x92:
-		case 0x94:
-		case 0x96:
-			xf_emit(ctx, 0x120, 0);
-			break;
-		case 0xa5:
-		case 0xa8:
-			xf_emit(ctx, 0x100, 0);	/* ffffffff */
-			break;
-		case 0xa0:
-		case 0xa3:
-		case 0xaf:
-			xf_emit(ctx, 0x400, 0);	/* ffffffff */
-			break;
-		}
-		xf_emit(ctx, 4, 0);	/* 3f, 0, 0, 0 */
-		xf_emit(ctx, 4, 0);	/* ffffffff */
-	}
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_TEMP */
-	xf_emit(ctx, 1, 1);		/* 00000001 RASTERIZE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0x27);		/* 000000ff UNK0FD4 */
-	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0x26);		/* 000000ff SEMANTIC_LAYER */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-}
-
-static void
-nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* end of area 2 on pre-NVA0, area 1 on NVAx */
-	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000003 VIEWPORT_CLIP_MODE */
-	xf_emit(ctx, 0x10, 0x04000000);	/* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
-	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
-	xf_emit(ctx, 0x20, 0);		/* ffffffff POLYGON_STIPPLE */
-	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
-	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
-	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0x1fe21);	/* 0001ffff tesla UNK0FAC */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0x0fac6881);
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 3, 0);
-	}
-}
-
-static void
-nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
-	if (device->chipset != 0x50) {
-		xf_emit(ctx, 5, 0);		/* ffffffff */
-		xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
-		xf_emit(ctx, 1, 0);		/* 00000001 */
-		xf_emit(ctx, 1, 0);		/* 000003ff */
-		xf_emit(ctx, 1, 0x804);		/* 00000fff SEMANTIC_CLIP */
-		xf_emit(ctx, 1, 0);		/* 00000001 */
-		xf_emit(ctx, 2, 4);		/* 7f, ff */
-		xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	}
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);			/* 000000ff VP_CLIP_DISTANCE_ENABLE */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0);		/* 3ff */
-	xf_emit(ctx, 1, 0);			/* 000000ff tesla UNK1940 */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
-	xf_emit(ctx, 1, 0x804);			/* 00000fff SEMANTIC_CLIP */
-	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
-	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0x7f);		/* 000000ff tesla UNK0FFC */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 1);			/* 00000001 SHADE_MODEL */
-	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0F8C */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
-	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 4, 0);			/* ffffffff NOPERSPECTIVE_BITMAP */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0);			/* 0000000f */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);		/* 000003ff tesla UNK0D68 */
-	else
-		xf_emit(ctx, 1, 0x7ff);		/* 000007ff tesla UNK0D68 */
-	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
-	xf_emit(ctx, 1, 0);			/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
-	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
-	xf_emit(ctx, 3, 0);			/* ffffffff last VIEWPORT_SCALE? */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
-	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);			/* 00000001 */
-	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_TRANSLATE */
-	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
-	xf_emit(ctx, 3, 0);			/* ffffffff */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 2, 0x88);			/* 000001ff tesla UNK19D8 */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 4);			/* 0000000f CULL_MODE */
-	xf_emit(ctx, 2, 0);			/* 07ffffff SCREEN_SCISSOR */
-	xf_emit(ctx, 2, 0);			/* 00007fff WINDOW_OFFSET_XY */
-	xf_emit(ctx, 1, 0);			/* 00000003 WINDOW_ORIGIN */
-	xf_emit(ctx, 0x10, 0);			/* 00000001 SCISSOR_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0);			/* 0000000f */
-	xf_emit(ctx, 1, 0x3f800000);		/* ffffffff LINE_WIDTH */
-	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 0);		/* 00000001 */
-	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
-	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
-	if (device->chipset != 0x50) {
-		xf_emit(ctx, 1, 0);		/* ffffffff */
-		xf_emit(ctx, 1, 0);		/* 00000001 */
-		xf_emit(ctx, 1, 0);		/* 000003ff */
-	}
-	xf_emit(ctx, 0x20, 0);			/* 10xbits ffffffff, 3fffff. SCISSOR_* */
-	xf_emit(ctx, 1, 0);			/* f */
-	xf_emit(ctx, 1, 0);			/* 0? */
-	xf_emit(ctx, 1, 0);			/* ffffffff */
-	xf_emit(ctx, 1, 0);			/* 003fffff */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0x52);			/* 000001ff SEMANTIC_PTSZ */
-	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
-	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0x00ffff00);		/* 00ffffff LINE_STIPPLE_PATTERN */
-	xf_emit(ctx, 1, 0);			/* 0000000f */
-}
-
-static void
-nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
-	/* SEEK */
-	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
-	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
-	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
-	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
-	xf_emit(ctx, 1, 0);		/* 00000001 */
-	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
-	xf_emit(ctx, 1, 0);		/* 0000ffff */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FB0 */
-	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1108 */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
-	/* SEEK */
-	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
-	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
-	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
-	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
-	xf_emit(ctx, 1, 0x10);		/* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
-	xf_emit(ctx, 1, 3);		/* 00000003 FP_CTRL_UNK196C */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1968 */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0);	/* 0fffffff tesla UNK1104 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK151C */
-}
-
-static void
-nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx)
-{
-	/* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000007 UNK0FB4 */
-	/* SEEK */
-	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_HORIZ */
-	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_VERT */
-	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
-	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff UNK1508 */
-	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
-	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_WIDTH */
-	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ID */
-	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff CLIPID_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_HEIGHT */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CLIPID */
-}
-
-static void
-nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-	/* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
-	/* SEEK */
-	xf_emit(ctx, 0x33, 0);
-	/* SEEK */
-	xf_emit(ctx, 2, 0);
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 4, 0);	/* RO */
-		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
-		xf_emit(ctx, 1, 0);	/* 1ff */
-		xf_emit(ctx, 8, 0);	/* 0? */
-		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
-
-		xf_emit(ctx, 4, 0);	/* RO */
-		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
-		xf_emit(ctx, 1, 0);	/* 1ff */
-		xf_emit(ctx, 8, 0);	/* 0? */
-		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
-	} else {
-		xf_emit(ctx, 0xc, 0);	/* RO */
-		/* SEEK */
-		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
-		xf_emit(ctx, 1, 0);	/* 1ff */
-		xf_emit(ctx, 8, 0);	/* 0? */
-
-		/* SEEK */
-		xf_emit(ctx, 0xc, 0);	/* RO */
-		/* SEEK */
-		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
-		xf_emit(ctx, 1, 0);	/* 1ff */
-		xf_emit(ctx, 8, 0);	/* 0? */
-	}
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
-	xf_emit(ctx, 1, 1);		/* 00000001 */
-	/* SEEK */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 2, 4);	/* 000000ff */
-	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
-	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 0x27);		/* 000000ff SEMANTIC_PRIM_ID */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f */
-	xf_emit(ctx, 1, 1);		/* 00000001 */
-	for (i = 0; i < 10; i++) {
-		/* SEEK */
-		xf_emit(ctx, 0x40, 0);		/* ffffffff */
-		xf_emit(ctx, 0x10, 0);		/* 3, 0, 0.... */
-		xf_emit(ctx, 0x10, 0);		/* ffffffff */
-	}
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_CTRL */
-	xf_emit(ctx, 1, 1);		/* 00000001 */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 4, 0);		/* ffffffff NOPERSPECTIVE_BITMAP */
-	xf_emit(ctx, 0x10, 0);		/* 00ffffff POINT_COORD_REPLACE_MAP */
-	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0);	/* 000003ff */
-}
-
-static void
-nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int acnt = 0x10, rep, i;
-	/* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
-	if (IS_NVA3F(device->chipset))
-		acnt = 0x20;
-	/* SEEK */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK13A4 */
-		xf_emit(ctx, 1, 1);	/* 00000fff tesla UNK1318 */
-	}
-	xf_emit(ctx, 1, 0);		/* ffffffff VERTEX_BUFFER_FIRST */
-	xf_emit(ctx, 1, 0);		/* 00000001 PRIMITIVE_RESTART_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK0DE8 */
-	xf_emit(ctx, 1, 0);		/* ffffffff PRIMITIVE_RESTART_INDEX */
-	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATR_MASK_UNK0DD0 */
-	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	xf_emit(ctx, 1, 0x20);		/* 0000ffff tesla UNK129C */
-	xf_emit(ctx, 1, 0);		/* 000000ff turing UNK370??? */
-	xf_emit(ctx, 1, 0);		/* 0000ffff turing USER_PARAM_COUNT */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0xb, 0);	/* RO */
-	else if (device->chipset >= 0xa0)
-		xf_emit(ctx, 0x9, 0);	/* RO */
-	else
-		xf_emit(ctx, 0x8, 0);	/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 00000001 EDGE_FLAG */
-	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
-	/* SEEK */
-	xf_emit(ctx, 0xc, 0);		/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 7f/ff */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	xf_emit(ctx, 1, 4);		/* 000001ff UNK1A28 */
-	xf_emit(ctx, 1, 8);		/* 000001ff UNK0DF0 */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);	/* 3ff tesla UNK0D68 */
-	else
-		xf_emit(ctx, 1, 0x7ff);	/* 7ff tesla UNK0D68 */
-	if (device->chipset == 0xa8)
-		xf_emit(ctx, 1, 0x1e00);	/* 7fff */
-	/* SEEK */
-	xf_emit(ctx, 0xc, 0);		/* RO or close */
-	/* SEEK */
-	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	if (device->chipset > 0x50 && device->chipset < 0xa0)
-		xf_emit(ctx, 2, 0);	/* ffffffff */
-	else
-		xf_emit(ctx, 1, 0);	/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0FD8 */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 0x10, 0);	/* 0? */
-		xf_emit(ctx, 2, 0);	/* weird... */
-		xf_emit(ctx, 2, 0);	/* RO */
-	} else {
-		xf_emit(ctx, 8, 0);	/* 0? */
-		xf_emit(ctx, 1, 0);	/* weird... */
-		xf_emit(ctx, 2, 0);	/* RO */
-	}
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* ffffffff VB_ELEMENT_BASE */
-	xf_emit(ctx, 1, 0);		/* ffffffff UNK1438 */
-	xf_emit(ctx, acnt, 0);		/* 1 tesla UNK1000 */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1118? */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
-	xf_emit(ctx, 1, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
-	xf_emit(ctx, 1, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* RO */
-	xf_emit(ctx, 2, 0);		/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK111C? */
-	xf_emit(ctx, 1, 0);		/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 000000ff UNK15F4_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff UNK15F4_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 000000ff UNK0F84_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff UNK0F84_ADDRESS_LOW */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* 00000fff VERTEX_ARRAY_STRIDE */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_LOW */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_ARRAY_HIGH */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_LIMIT_LOW */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_LIMIT_HIGH */
-	xf_emit(ctx, 3, 0);		/* f/1f */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, acnt, 0);		/* f */
-		xf_emit(ctx, 3, 0);		/* f/1f */
-	}
-	/* SEEK */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 2, 0);	/* RO */
-	else
-		xf_emit(ctx, 5, 0);	/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* ffff DMA_VTXBUF */
-	/* SEEK */
-	if (device->chipset < 0xa0) {
-		xf_emit(ctx, 0x41, 0);	/* RO */
-		/* SEEK */
-		xf_emit(ctx, 0x11, 0);	/* RO */
-	} else if (!IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0x50, 0);	/* RO */
-	else
-		xf_emit(ctx, 0x58, 0);	/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, 1, 1);		/* 1 UNK0DEC */
-	/* SEEK */
-	xf_emit(ctx, acnt*4, 0);	/* ffffffff VTX_ATTR */
-	xf_emit(ctx, 4, 0);		/* f/1f, 0, 0, 0 */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0x1d, 0);	/* RO */
-	else
-		xf_emit(ctx, 0x16, 0);	/* RO */
-	/* SEEK */
-	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
-	/* SEEK */
-	if (device->chipset < 0xa0)
-		xf_emit(ctx, 8, 0);	/* RO */
-	else if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0xc, 0);	/* RO */
-	else
-		xf_emit(ctx, 7, 0);	/* RO */
-	/* SEEK */
-	xf_emit(ctx, 0xa, 0);		/* RO */
-	if (device->chipset == 0xa0)
-		rep = 0xc;
-	else
-		rep = 4;
-	for (i = 0; i < rep; i++) {
-		/* SEEK */
-		if (IS_NVA3F(device->chipset))
-			xf_emit(ctx, 0x20, 0);	/* ffffffff */
-		xf_emit(ctx, 0x200, 0);	/* ffffffff */
-		xf_emit(ctx, 4, 0);	/* 7f/ff, 0, 0, 0 */
-		xf_emit(ctx, 4, 0);	/* ffffffff */
-	}
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 113/111 */
-	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
-	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATTR_MASK_UNK0DD0 */
-	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	/* SEEK */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 7, 0);	/* weird... */
-	else
-		xf_emit(ctx, 5, 0);	/* weird... */
-}
-
-static void
-nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
-	/* SEEK */
-	xf_emit(ctx, 2, 0);		/* 0001ffff CLIP_X, CLIP_Y */
-	xf_emit(ctx, 2, 0);		/* 0000ffff CLIP_W, CLIP_H */
-	xf_emit(ctx, 1, 0);		/* 00000001 CLIP_ENABLE */
-	if (device->chipset < 0xa0) {
-		/* this is useless on everything but the original NV50,
-		 * guess they forgot to nuke it. Or just didn't bother. */
-		xf_emit(ctx, 2, 0);	/* 0000ffff IFC_CLIP_X, Y */
-		xf_emit(ctx, 2, 1);	/* 0000ffff IFC_CLIP_W, H */
-		xf_emit(ctx, 1, 0);	/* 00000001 IFC_CLIP_ENABLE */
-	}
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
-	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
-	xf_emit(ctx, 1, 0x11);		/* 3f[NV50]/7f[NV84+] DST_FORMAT */
-	xf_emit(ctx, 1, 0);		/* 0001ffff DRAW_POINT_X */
-	xf_emit(ctx, 1, 8);		/* 0000000f DRAW_UNK58C */
-	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_X_FRACT */
-	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_X_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_Y_FRACT */
-	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_Y_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DX_DU_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DX_DU_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DY_DV_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DY_DV_INT */
-	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_WIDTH */
-	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_HEIGHT */
-	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
-	xf_emit(ctx, 1, 2);		/* 00000003 SIFC_BITMAP_UNK808 */
-	xf_emit(ctx, 1, 0);		/* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
-	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_LSB_FIRST */
-	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_X */
-	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_Y */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
-	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_W */
-	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_H */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_X_FRACT */
-	xf_emit(ctx, 1, 0);		/* 0001ffff BLIT_SRC_X_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_Y_FRACT */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK888 */
-	xf_emit(ctx, 1, 4);		/* 0000003f UNK884 */
-	xf_emit(ctx, 1, 0);		/* 00000007 UNK880 */
-	xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK0FB8 */
-	xf_emit(ctx, 1, 0x15);		/* 000000ff tesla UNK128C */
-	xf_emit(ctx, 2, 0);		/* 00000007, ffff0ff3 */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK260 */
-	xf_emit(ctx, 1, 0x4444480);	/* 1fffffff UNK870 */
-	/* SEEK */
-	xf_emit(ctx, 0x10, 0);
-	/* SEEK */
-	xf_emit(ctx, 0x27, 0);
-}
-
-static void
-nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
-	/* SEEK */
-	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1924 */
-	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 0);		/* 000003ff */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* ffffffff turing UNK364 */
-	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK36C */
-	xf_emit(ctx, 1, 0);		/* 0000ffff USER_PARAM_COUNT */
-	xf_emit(ctx, 1, 0x100);		/* 00ffffff turing UNK384 */
-	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK2A0 */
-	xf_emit(ctx, 1, 0);		/* 0000ffff GRIDID */
-	xf_emit(ctx, 1, 0x10001);	/* ffffffff GRIDDIM_XY */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0x10001);	/* ffffffff BLOCKDIM_XY */
-	xf_emit(ctx, 1, 1);		/* 0000ffff BLOCKDIM_Z */
-	xf_emit(ctx, 1, 0x10001);	/* 00ffffff BLOCK_ALLOC */
-	xf_emit(ctx, 1, 1);		/* 00000001 LANES32 */
-	xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
-	xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
-	/* SEEK */
-	xf_emit(ctx, 0x40, 0);		/* ffffffff USER_PARAM */
-	switch (device->chipset) {
-	case 0x50:
-	case 0x92:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0x80, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 0x10*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0x84:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0x60, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0x94:
-	case 0x96:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0x40, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 8*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0x86:
-	case 0x98:
-		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
-		xf_emit(ctx, 0x10, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0xa0:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0xf0, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 0x1e*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0xa3:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0x60, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0xa5:
-	case 0xaf:
-		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
-		xf_emit(ctx, 0x30, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 6*2, 0);	/* ffffffff, 1f */
-		break;
-	case 0xaa:
-		xf_emit(ctx, 0x12, 0);
-		break;
-	case 0xa8:
-	case 0xac:
-		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
-		xf_emit(ctx, 0x10, 0);	/* fff */
-		xf_emit(ctx, 2, 0);	/* ff, fff */
-		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
-		break;
-	}
-	xf_emit(ctx, 1, 0);		/* 0000000f */
-	xf_emit(ctx, 1, 0);		/* 00000000 */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 0000001f */
-	xf_emit(ctx, 4, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 4, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 000000ff */
-}
-
-static void
-nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
-	xf_emit(ctx, 1, 0x3f800000);	/* ffffffff LINE_WIDTH */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
-	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
-	xf_emit(ctx, 3, 0);		/* 00000001 POLYGON_OFFSET_*_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
-	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
-	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
-	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_UNITS */
-	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_FACTOR */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
-	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0x11);		/* 0000007f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 0000007f RT_FORMAT */
-	xf_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_LINEAR */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 3);	/* 00000003 UNK16B4 */
-	else if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 1);	/* 00000001 UNK16B4 */
-	xf_emit(ctx, 1, 0);		/* 00000003 MULTISAMPLE_CTRL */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0F90 */
-	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
-	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 5);		/* 0000000f UNK1408 */
-	xf_emit(ctx, 1, 0x52);		/* 000001ff SEMANTIC_PTSZ */
-	xf_emit(ctx, 1, 0);		/* ffffffff POINT_SIZE */
-	xf_emit(ctx, 1, 0);		/* 00000001 */
-	xf_emit(ctx, 1, 0);		/* 00000007 tesla UNK0FB4 */
-	if (device->chipset != 0x50) {
-		xf_emit(ctx, 1, 0);	/* 3ff */
-		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK1110 */
-	}
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1928 */
-	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
-	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
-	xf_emit(ctx, 1, 0x10);		/* 000000ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 0x20, 0);		/* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK187C */
-	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
-	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 5);		/* 0000000f tesla UNK1220 */
-	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 000000ff tesla UNK1A20 */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
-	if (device->chipset < 0xa0)
-		xf_emit(ctx, 0x1c, 0);	/* RO */
-	else if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0x9, 0);
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
-	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
-	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	if (device->chipset != 0x50) {
-		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
-		xf_emit(ctx, 1, 0);	/* 3ff */
-	}
-	/* XXX: the following block could belong either to unk1cxx, or
-	 * to STRMOUT. Rather hard to tell. */
-	if (device->chipset < 0xa0)
-		xf_emit(ctx, 0x25, 0);
-	else
-		xf_emit(ctx, 0x3b, 0);
-}
-
-static void
-nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
-	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
-	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
-		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
-	}
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);	/* 000003ff tesla UNK0D68 */
-	else
-		xf_emit(ctx, 1, 0x7ff);	/* 000007ff tesla UNK0D68 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	/* SEEK */
-	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
-	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
-	xf_emit(ctx, 4, 0);		/* 000000ff STRMOUT_ADDRESS_HIGH */
-	xf_emit(ctx, 4, 0);		/* ffffffff STRMOUT_ADDRESS_LOW */
-	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
-		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
-	}
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STRMOUT */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
-	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
-	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
-	xf_emit(ctx, 2, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	/* SEEK */
-	xf_emit(ctx, 0x20, 0);		/* ffffffff STRMOUT_MAP */
-	xf_emit(ctx, 1, 0);		/* 0000000f */
-	xf_emit(ctx, 1, 0);		/* 00000000? */
-	xf_emit(ctx, 2, 0);		/* ffffffff */
-}
-
-static void
-nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
-	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0);		/* 000003ff */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-}
-
-static void
-nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 2, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
-	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 7 */
-	/* SEEK */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
-	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
-	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
-	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
-	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
-	xf_emit(ctx, 1, 0);		/* 00000001 eng2d UNK260 */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-}
-
-static void
-nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int magic2;
-	if (device->chipset == 0x50) {
-		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(device->chipset)) {
-		magic2 = 0x001ffe67;
-	} else {
-		magic2 = 0x00087e67;
-	}
-	xf_emit(ctx, 1, 0);		/* f/7 MUTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
-		xf_emit(ctx, 1, 0x15);	/* 000000ff */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 0x10);		/* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
-		xf_emit(ctx, 3, 0);	/* ff, ffffffff, ffffffff */
-		xf_emit(ctx, 1, 4);	/* 7 */
-		xf_emit(ctx, 1, 0x400);	/* fffffff */
-		xf_emit(ctx, 1, 0x300);	/* ffff */
-		xf_emit(ctx, 1, 0x1001);	/* 1fff */
-		if (device->chipset != 0xa0) {
-			if (IS_NVA3F(device->chipset))
-				xf_emit(ctx, 1, 0);	/* 0000000f UNK15C8 */
-			else
-				xf_emit(ctx, 1, 0x15);	/* ff */
-		}
-	}
-	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
-	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
-	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
-	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
-	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 2, 0);		/* ffff0ff3, ffff */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
-	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 2, 0);
-		xf_emit(ctx, 1, 0x1001);
-		xf_emit(ctx, 0xb, 0);
-	} else {
-		xf_emit(ctx, 1, 0);	/* 00000007 */
-		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1534 */
-		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-		xf_emit(ctx, 8, 0);	/* 00000001 BLEND_ENABLE */
-		xf_emit(ctx, 1, 0);	/* ffff0ff3 */
-	}
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f */
-	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (device->chipset != 0x50) {
-		xf_emit(ctx, 1, 0);	/* 0000000f LOGIC_OP */
-		xf_emit(ctx, 1, 0);	/* 000000ff */
-	}
-	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
-	xf_emit(ctx, 2, 1);		/* 00000007 BLEND_EQUATION_RGB, ALPHA */
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
-	xf_emit(ctx, 1, 0);		/* 00000001 */
-	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK12E4 */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
-		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
-		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
-		xf_emit(ctx, 2, 0);	/* 00000001 */
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-		xf_emit(ctx, 1, 0);	/* 0000000f */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* ffffffff */
-		xf_emit(ctx, 2, 0);	/* 00000001 */
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-		xf_emit(ctx, 1, 0);	/* 00000001 */
-		xf_emit(ctx, 1, 0);	/* 000003ff */
-	} else if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 2, 0);	/* 00000001 */
-		xf_emit(ctx, 1, 0);	/* 00000007 */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* ffffffff */
-		xf_emit(ctx, 2, 0);	/* 00000001 */
-	} else {
-		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1430 */
-		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A3C */
-	}
-	xf_emit(ctx, 4, 0);		/* ffffffff CLEAR_COLOR */
-	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR A R G B */
-	xf_emit(ctx, 1, 0);		/* 00000fff eng2d UNK2B0 */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 2, 0);	/* 00000001 */
-	xf_emit(ctx, 1, 0);		/* 000003ff */
-	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f LOGIC_OP */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4? NVA3+ only? */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
-		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK15C4 */
-		xf_emit(ctx, 1, 0);	/* 00000001 */
-		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
-	}
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	xf_emit(ctx, 1, 0);		/* 00000007 PATTERN_COLOR_FORMAT */
-	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_COLOR */
-	xf_emit(ctx, 1, 0);		/* 00000001 PATTERN_MONO_FORMAT */
-	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_BITMAP */
-	xf_emit(ctx, 1, 0);		/* 00000003 PATTERN_SELECT */
-	xf_emit(ctx, 1, 0);		/* 000000ff ROP */
-	xf_emit(ctx, 1, 0);		/* ffffffff BETA1 */
-	xf_emit(ctx, 1, 0);		/* ffffffff BETA4 */
-	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
-	xf_emit(ctx, 0x50, 0);		/* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
-}
-
-static void
-nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int magic3;
-	switch (device->chipset) {
-	case 0x50:
-		magic3 = 0x1000;
-		break;
-	case 0x86:
-	case 0x98:
-	case 0xa8:
-	case 0xaa:
-	case 0xac:
-	case 0xaf:
-		magic3 = 0x1e00;
-		break;
-	default:
-		magic3 = 0;
-	}
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 111/113[NVA0+] */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0x1f, 0);	/* ffffffff */
-	else if (device->chipset >= 0xa0)
-		xf_emit(ctx, 0x0f, 0);	/* ffffffff */
-	else
-		xf_emit(ctx, 0x10, 0);	/* fffffff VP_RESULT_MAP_1 up */
-	xf_emit(ctx, 2, 0);		/* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0x03020100);	/* ffffffff */
-	else
-		xf_emit(ctx, 1, 0x00608080);	/* fffffff VP_RESULT_MAP_0 */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 2, 0);		/* 111/113, 7f/ff */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
-	if (magic3)
-		xf_emit(ctx, 1, magic3);	/* 00007fff tesla UNK141C */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 111/113 */
-	xf_emit(ctx, 0x1f, 0);		/* ffffffff GP_RESULT_MAP_1 up */
-	xf_emit(ctx, 1, 0);		/* 0000001f */
-	xf_emit(ctx, 1, 0);		/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0x03020100);	/* ffffffff GP_RESULT_MAP_0 */
-	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
-	if (magic3)
-		xf_emit(ctx, 1, magic3);	/* 7fff tesla UNK141C */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 111/113 */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
-	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK13A0 */
-	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-	xf_emit(ctx, 1, 0);		/* 111/113 */
-	if (device->chipset == 0x94 || device->chipset == 0x96)
-		xf_emit(ctx, 0x1020, 0);	/* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (device->chipset < 0xa0)
-		xf_emit(ctx, 0xa20, 0);	/* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (!IS_NVA3F(device->chipset))
-		xf_emit(ctx, 0x210, 0);	/* ffffffff */
-	else
-		xf_emit(ctx, 0x410, 0);	/* ffffffff */
-	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
-	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-}
-
-static void
-nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int magic1, magic2;
-	if (device->chipset == 0x50) {
-		magic1 = 0x3ff;
-		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(device->chipset)) {
-		magic1 = 0x7ff;
-		magic2 = 0x001ffe67;
-	} else {
-		magic1 = 0x7ff;
-		magic2 = 0x00087e67;
-	}
-	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* ffffffff ALPHA_TEST_REF */
-	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000000f UNK16A0 */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FDC */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ff[NV50]/3ff[NV84+] */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
-	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
-	xf_emit(ctx, 1, 0);		/* 7 */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff COLOR_KEY */
-	xf_emit(ctx, 1, 0);		/* 00000001 COLOR_KEY_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 COLOR_KEY_FORMAT */
-	xf_emit(ctx, 2, 0);		/* ffffffff SIFC_BITMAP_COLOR */
-	xf_emit(ctx, 1, 1);		/* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
-	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK16B4 */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1298 */
-	} else if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK16B4 */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-	} else {
-		xf_emit(ctx, 1, 0);	/* 00000003 MULTISAMPLE_CTRL */
-	}
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4 */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
-		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
-		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_RGB */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_RGB */
-		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_ALPHA */
-		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_ALPHA */
-		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
-	}
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
-	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
-	xf_emit(ctx, 1, 0);		/* 7 */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
-	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
-	xf_emit(ctx, 1, 0xcf);		/* 000000ff DRAW_COLOR_FORMAT */
-	xf_emit(ctx, 1, 0xcf);		/* 000000ff SRC_FORMAT */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	xf_emit(ctx, 1, 0);		/* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
-	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
-	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
-	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 8, 1);		/* 00000001 UNK19E0 */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0);	/* ff */
-	else
-		xf_emit(ctx, 3, 0);	/* 1, 7, 3ff */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
-	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
-	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, magic1);	/* 3ff/7ff tesla UNK0D68 */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 8, 0);		/* 0000ffff DMA_COLOR */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_GLOBAL */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_LOCAL */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STACK */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_DST */
-	xf_emit(ctx, 1, 0);		/* 7 */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 8, 0);		/* 000000ff RT_ADDRESS_HIGH */
-	xf_emit(ctx, 8, 0);		/* ffffffff RT_LAYER_STRIDE */
-	xf_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
-	xf_emit(ctx, 8, 8);		/* 0000007f RT_TILE_MODE */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 8, 0x400);		/* 0fffffff RT_HORIZ */
-	xf_emit(ctx, 8, 0x300);		/* 0000ffff RT_VERT */
-	xf_emit(ctx, 1, 1);		/* 00001fff RT_ARRAY_MODE */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, 0x20);		/* 00000fff DST_TILE_MODE */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
-	xf_emit(ctx, 1, 0);		/* 000007ff DST_LAYER */
-	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	xf_emit(ctx, 1, 0);		/* ffffffff DST_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0);		/* 000000ff DST_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0x40);		/* 0007ffff DST_PITCH */
-	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
-	xf_emit(ctx, 1, 0);		/* 0000ffff */
-	xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK15AC */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_ZETA */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 2, 0);		/* ffff, ff/3ff */
-	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_LAYER_STRIDE */
-	xf_emit(ctx, 1, 0);		/* 000000ff ZETA_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_ADDRESS_LOW */
-	xf_emit(ctx, 1, 4);		/* 00000007 ZETA_TILE_MODE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	xf_emit(ctx, 1, 0x400);		/* 0fffffff ZETA_HORIZ */
-	xf_emit(ctx, 1, 0x300);		/* 0000ffff ZETA_VERT */
-	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 0);	/* 00000001 */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
-	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
-	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
-	xf_emit(ctx, 1, 0);		/* 7 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	}
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	if (device->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0x0fac6881);	/* fffffff */
-	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
-	xf_emit(ctx, 1, 0);		/* ff/3ff */
-	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
-	xf_emit(ctx, 1, 0);		/* 00000007 */
-	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
-	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-		xf_emit(ctx, 1, 0);	/* 0000000f tesla UNK15C8 */
-	}
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 3, 0);		/* 7/f, 1, ffff0ff3 */
-		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
-		xf_emit(ctx, 4, 0);		/* 1, 1, 1, 3ff */
-		xf_emit(ctx, 1, 4);		/* 7 */
-		xf_emit(ctx, 1, 0);		/* 1 */
-		xf_emit(ctx, 2, 1);		/* 1 */
-		xf_emit(ctx, 2, 0);		/* 7, f */
-		xf_emit(ctx, 1, 1);		/* 1 */
-		xf_emit(ctx, 1, 0);		/* 7/f */
-		if (IS_NVA3F(device->chipset))
-			xf_emit(ctx, 0x9, 0);	/* 1 */
-		else
-			xf_emit(ctx, 0x8, 0);	/* 1 */
-		xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-		xf_emit(ctx, 8, 1);		/* 1 */
-		xf_emit(ctx, 1, 0x11);		/* 7f */
-		xf_emit(ctx, 7, 0);		/* 7f */
-		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
-		xf_emit(ctx, 1, 0xf);		/* f */
-		xf_emit(ctx, 7, 0);		/* f */
-		xf_emit(ctx, 1, 0x11);		/* 7f */
-		xf_emit(ctx, 1, 1);		/* 1 */
-		xf_emit(ctx, 5, 0);		/* 1, 7, 3ff, 3, 7 */
-		if (IS_NVA3F(device->chipset)) {
-			xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
-			xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-		}
-	}
-}
-
-static void
-nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 2, 0);		/* 1 LINKED_TSC. yes, 2. */
-	if (device->chipset != 0x50)
-		xf_emit(ctx, 1, 0);	/* 3 */
-	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DU_DX_INT */
-	xf_emit(ctx, 1, 0);		/* fffff BLIT_DU_DX_FRACT */
-	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DV_DY_INT */
-	xf_emit(ctx, 1, 0);		/* fffff BLIT_DV_DY_FRACT */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 1, 0);	/* 3 BLIT_CONTROL */
-	else
-		xf_emit(ctx, 2, 0);	/* 3ff, 1 */
-	xf_emit(ctx, 1, 0x2a712488);	/* ffffffff SRC_TIC_0 */
-	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_1 */
-	xf_emit(ctx, 1, 0x4085c000);	/* ffffffff SRC_TIC_2 */
-	xf_emit(ctx, 1, 0x40);		/* ffffffff SRC_TIC_3 */
-	xf_emit(ctx, 1, 0x100);		/* ffffffff SRC_TIC_4 */
-	xf_emit(ctx, 1, 0x10100);	/* ffffffff SRC_TIC_5 */
-	xf_emit(ctx, 1, 0x02800000);	/* ffffffff SRC_TIC_6 */
-	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_7 */
-	if (device->chipset == 0x50) {
-		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK358 */
-		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
-		xf_emit(ctx, 1, 0);	/* 00000003 turing UNK37C tesla UNK1690 */
-		xf_emit(ctx, 1, 0);	/* 00000003 BLIT_CONTROL */
-		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK32C tesla UNK0F94 */
-	} else if (!IS_NVAAF(device->chipset)) {
-		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* 000003ff */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* 000003ff */
-		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1664 / turing UNK03E8 */
-		xf_emit(ctx, 1, 0);	/* 00000003 */
-		xf_emit(ctx, 1, 0);	/* 000003ff */
-	} else {
-		xf_emit(ctx, 0x6, 0);
-	}
-	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A34 */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TEXTURE */
-	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_SRC */
-}
-
-static void
-nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 2, 0);		/* 7, ffff0ff3 */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
-	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
-	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK0F98 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
-	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
-	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
-	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
-	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
-	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
-	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
-	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
-	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
-	xf_emit(ctx, 1, 0x30201000);	/* ffffffff tesla UNK1670 */
-	xf_emit(ctx, 1, 0x70605040);	/* ffffffff tesla UNK1670 */
-	xf_emit(ctx, 1, 0xb8a89888);	/* ffffffff tesla UNK1670 */
-	xf_emit(ctx, 1, 0xf8e8d8c8);	/* ffffffff tesla UNK1670 */
-	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
-}
-
-static void
-nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	if (device->chipset < 0xa0) {
-		nv50_graph_construct_xfer_unk84xx(ctx);
-		nv50_graph_construct_xfer_tprop(ctx);
-		nv50_graph_construct_xfer_tex(ctx);
-		nv50_graph_construct_xfer_unk8cxx(ctx);
-	} else {
-		nv50_graph_construct_xfer_tex(ctx);
-		nv50_graph_construct_xfer_tprop(ctx);
-		nv50_graph_construct_xfer_unk8cxx(ctx);
-		nv50_graph_construct_xfer_unk84xx(ctx);
-	}
-}
-
-static void
-nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i, mpcnt = 2;
-	switch (device->chipset) {
-		case 0x98:
-		case 0xaa:
-			mpcnt = 1;
-			break;
-		case 0x50:
-		case 0x84:
-		case 0x86:
-		case 0x92:
-		case 0x94:
-		case 0x96:
-		case 0xa8:
-		case 0xac:
-			mpcnt = 2;
-			break;
-		case 0xa0:
-		case 0xa3:
-		case 0xa5:
-		case 0xaf:
-			mpcnt = 3;
-			break;
-	}
-	for (i = 0; i < mpcnt; i++) {
-		xf_emit(ctx, 1, 0);		/* ff */
-		xf_emit(ctx, 1, 0x80);		/* ffffffff tesla UNK1404 */
-		xf_emit(ctx, 1, 0x80007004);	/* ffffffff tesla UNK12B0 */
-		xf_emit(ctx, 1, 0x04000400);	/* ffffffff */
-		if (device->chipset >= 0xa0)
-			xf_emit(ctx, 1, 0xc0);	/* 00007fff tesla UNK152C */
-		xf_emit(ctx, 1, 0x1000);	/* 0000ffff tesla UNK0D60 */
-		xf_emit(ctx, 1, 0);		/* ff/3ff */
-		xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-		if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
-			xf_emit(ctx, 1, 0xe00);		/* 7fff */
-			xf_emit(ctx, 1, 0x1e00);	/* 7fff */
-		}
-		xf_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP */
-		xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
-		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-		if (device->chipset == 0x50)
-			xf_emit(ctx, 2, 0x1000);	/* 7fff tesla UNK141C */
-		xf_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP */
-		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-		xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
-		xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
-		if (IS_NVAAF(device->chipset))
-			xf_emit(ctx, 0xb, 0);	/* RO */
-		else if (device->chipset >= 0xa0)
-			xf_emit(ctx, 0xc, 0);	/* RO */
-		else
-			xf_emit(ctx, 0xa, 0);	/* RO */
-	}
-	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 0);			/* ff/3ff */
-	if (device->chipset >= 0xa0) {
-		xf_emit(ctx, 1, 0x1fe21);	/* 0003ffff tesla UNK0FAC */
-	}
-	xf_emit(ctx, 3, 0);			/* 7fff, 0, 0 */
-	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1534 */
-	xf_emit(ctx, 1, 0);			/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	xf_emit(ctx, 4, 0xffff);		/* 0000ffff MSAA_MASK */
-	xf_emit(ctx, 1, 1);			/* 00000001 LANES32 */
-	xf_emit(ctx, 1, 0x10001);		/* 00ffffff BLOCK_ALLOC */
-	xf_emit(ctx, 1, 0x10001);		/* ffffffff BLOCKDIM_XY */
-	xf_emit(ctx, 1, 1);			/* 0000ffff BLOCKDIM_Z */
-	xf_emit(ctx, 1, 0);			/* ffffffff SHARED_SIZE */
-	xf_emit(ctx, 1, 0x1fe21);		/* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
-	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A34 */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK169C */
-	xf_emit(ctx, 1, 0);			/* ff/3ff */
-	xf_emit(ctx, 1, 0);			/* 1 LINKED_TSC */
-	xf_emit(ctx, 1, 0);			/* ff FP_ADDRESS_HIGH */
-	xf_emit(ctx, 1, 0);			/* ffffffff FP_ADDRESS_LOW */
-	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
-	xf_emit(ctx, 1, 4);			/* 00000007 FP_CONTROL */
-	xf_emit(ctx, 1, 0);			/* 000000ff FRAG_COLOR_CLAMP_EN */
-	xf_emit(ctx, 1, 2);			/* 00000003 REG_MODE */
-	xf_emit(ctx, 1, 0x11);			/* 0000007f RT_FORMAT */
-	xf_emit(ctx, 7, 0);			/* 0000007f RT_FORMAT */
-	xf_emit(ctx, 1, 0);			/* 00000007 */
-	xf_emit(ctx, 1, 0xfac6881);		/* 0fffffff RT_CONTROL */
-	xf_emit(ctx, 1, 0);			/* 00000003 MULTISAMPLE_CTRL */
-	if (IS_NVA3F(device->chipset))
-		xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK16B4 */
-	xf_emit(ctx, 1, 0);			/* 00000001 ALPHA_TEST_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 00000007 ALPHA_TEST_FUNC */
-	xf_emit(ctx, 1, 0);			/* 00000001 FRAMEBUFFER_SRGB */
-	xf_emit(ctx, 1, 4);			/* ffffffff tesla UNK1400 */
-	xf_emit(ctx, 8, 0);			/* 00000001 BLEND_ENABLE */
-	xf_emit(ctx, 1, 0);			/* 00000001 LOGIC_OP_ENABLE */
-	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_RGB */
-	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_RGB */
-	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_RGB */
-	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_ALPHA */
-	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_ALPHA */
-	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_ALPHA */
-	xf_emit(ctx, 1, 1);			/* 00000001 UNK133C */
-	if (IS_NVA3F(device->chipset)) {
-		xf_emit(ctx, 1, 0);		/* 00000001 UNK12E4 */
-		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_RGB */
-		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_RGB */
-		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_RGB */
-		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_ALPHA */
-		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_ALPHA */
-		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_ALPHA */
-		xf_emit(ctx, 8, 1);		/* 00000001 IBLEND_UNK00 */
-		xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1928 */
-		xf_emit(ctx, 1, 0);		/* 00000001 UNK1140 */
-	}
-	xf_emit(ctx, 1, 0);			/* 00000003 tesla UNK0F90 */
-	xf_emit(ctx, 1, 4);			/* 000000ff FP_RESULT_COUNT */
-	/* XXX: demagic this part some day */
-	if (device->chipset == 0x50)
-		xf_emit(ctx, 0x3a0, 0);
-	else if (device->chipset < 0x94)
-		xf_emit(ctx, 0x3a2, 0);
-	else if (device->chipset == 0x98 || device->chipset == 0xaa)
-		xf_emit(ctx, 0x39f, 0);
-	else
-		xf_emit(ctx, 0x3a3, 0);
-	xf_emit(ctx, 1, 0x11);			/* 3f/7f DST_FORMAT */
-	xf_emit(ctx, 1, 0);			/* 7 OPERATION */
-	xf_emit(ctx, 1, 1);			/* 1 DST_LINEAR */
-	xf_emit(ctx, 0x2d, 0);
-}
-
-static void
-nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
-{
-	struct nouveau_device *device = ctx->device;
-	int i;
-	u32 offset;
-	u32 units = nv_rd32 (ctx->device, 0x1540);
-	int size = 0;
-
-	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
-
-	if (device->chipset < 0xa0) {
-		for (i = 0; i < 8; i++) {
-			ctx->ctxvals_pos = offset + i;
-			/* that little bugger belongs to csched. No idea
-			 * what it's doing here. */
-			if (i == 0)
-				xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
-			if (units & (1 << i))
-				nv50_graph_construct_xfer_mpc(ctx);
-			if ((ctx->ctxvals_pos-offset)/8 > size)
-				size = (ctx->ctxvals_pos-offset)/8;
-		}
-	} else {
-		/* Strand 0: TPs 0, 1 */
-		ctx->ctxvals_pos = offset;
-		/* that little bugger belongs to csched. No idea
-		 * what it's doing here. */
-		xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
-		if (units & (1 << 0))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 1))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 1: TPs 2, 3 */
-		ctx->ctxvals_pos = offset + 1;
-		if (units & (1 << 2))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 3))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 2: TPs 4, 5, 6 */
-		ctx->ctxvals_pos = offset + 2;
-		if (units & (1 << 4))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 5))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 6))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-
-		/* Strand 3: TPs 7, 8, 9 */
-		ctx->ctxvals_pos = offset + 3;
-		if (units & (1 << 7))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 8))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if (units & (1 << 9))
-			nv50_graph_construct_xfer_mpc(ctx);
-		if ((ctx->ctxvals_pos-offset)/8 > size)
-			size = (ctx->ctxvals_pos-offset)/8;
-	}
-	ctx->ctxvals_pos = offset + size * 8;
-	ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
-	cp_lsr (ctx, offset);
-	cp_out (ctx, CP_SET_XFER_POINTER);
-	cp_lsr (ctx, size);
-	cp_out (ctx, CP_SEEK_2);
-	cp_out (ctx, CP_XFER_2);
-	cp_wait(ctx, XFER, BUSY);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
deleted file mode 100644
index b8e5fe6..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ /dev/null
@@ -1,1386 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000b2,  40, 0x01, 0x00000000 },
-	{ 0x000210,   8, 0x01, 0x00000040 },
-	{ 0x000218,   8, 0x01, 0x0000c080 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00001fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x003fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x0005e0,   5, 0x01, 0x00000022 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x00000c48 },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00300008 },
-	{ 0x000841,   1, 0x01, 0x04000080 },
-	{ 0x000842,   1, 0x01, 0x00300008 },
-	{ 0x000843,   1, 0x01, 0x04000080 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x000944,   1, 0x01, 0x00000022 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000014 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_icmd[] = {
-	{ nvc0_grctx_init_icmd_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_9097_0[] = {
-	{ 0x000800,   8, 0x40, 0x00000000 },
-	{ 0x000804,   8, 0x40, 0x00000000 },
-	{ 0x000808,   8, 0x40, 0x00000400 },
-	{ 0x00080c,   8, 0x40, 0x00000300 },
-	{ 0x000810,   1, 0x04, 0x000000cf },
-	{ 0x000850,   7, 0x40, 0x00000000 },
-	{ 0x000814,   8, 0x40, 0x00000040 },
-	{ 0x000818,   8, 0x40, 0x00000001 },
-	{ 0x00081c,   8, 0x40, 0x00000000 },
-	{ 0x000820,   8, 0x40, 0x00000000 },
-	{ 0x002700,   8, 0x20, 0x00000000 },
-	{ 0x002704,   8, 0x20, 0x00000000 },
-	{ 0x002708,   8, 0x20, 0x00000000 },
-	{ 0x00270c,   8, 0x20, 0x00000000 },
-	{ 0x002710,   8, 0x20, 0x00014000 },
-	{ 0x002714,   8, 0x20, 0x00000040 },
-	{ 0x001c00,  16, 0x10, 0x00000000 },
-	{ 0x001c04,  16, 0x10, 0x00000000 },
-	{ 0x001c08,  16, 0x10, 0x00000000 },
-	{ 0x001c0c,  16, 0x10, 0x00000000 },
-	{ 0x001d00,  16, 0x10, 0x00000000 },
-	{ 0x001d04,  16, 0x10, 0x00000000 },
-	{ 0x001d08,  16, 0x10, 0x00000000 },
-	{ 0x001d0c,  16, 0x10, 0x00000000 },
-	{ 0x001f00,  16, 0x08, 0x00000000 },
-	{ 0x001f04,  16, 0x08, 0x00000000 },
-	{ 0x001f80,  16, 0x08, 0x00000000 },
-	{ 0x001f84,  16, 0x08, 0x00000000 },
-	{ 0x002200,   5, 0x10, 0x00000022 },
-	{ 0x002000,   1, 0x04, 0x00000000 },
-	{ 0x002040,   1, 0x04, 0x00000011 },
-	{ 0x002080,   1, 0x04, 0x00000020 },
-	{ 0x0020c0,   1, 0x04, 0x00000030 },
-	{ 0x002100,   1, 0x04, 0x00000040 },
-	{ 0x002140,   1, 0x04, 0x00000051 },
-	{ 0x00200c,   6, 0x40, 0x00000001 },
-	{ 0x002010,   1, 0x04, 0x00000000 },
-	{ 0x002050,   1, 0x04, 0x00000000 },
-	{ 0x002090,   1, 0x04, 0x00000001 },
-	{ 0x0020d0,   1, 0x04, 0x00000002 },
-	{ 0x002110,   1, 0x04, 0x00000003 },
-	{ 0x002150,   1, 0x04, 0x00000004 },
-	{ 0x000380,   4, 0x20, 0x00000000 },
-	{ 0x000384,   4, 0x20, 0x00000000 },
-	{ 0x000388,   4, 0x20, 0x00000000 },
-	{ 0x00038c,   4, 0x20, 0x00000000 },
-	{ 0x000700,   4, 0x10, 0x00000000 },
-	{ 0x000704,   4, 0x10, 0x00000000 },
-	{ 0x000708,   4, 0x10, 0x00000000 },
-	{ 0x002800, 128, 0x04, 0x00000000 },
-	{ 0x000a00,  16, 0x20, 0x00000000 },
-	{ 0x000a04,  16, 0x20, 0x00000000 },
-	{ 0x000a08,  16, 0x20, 0x00000000 },
-	{ 0x000a0c,  16, 0x20, 0x00000000 },
-	{ 0x000a10,  16, 0x20, 0x00000000 },
-	{ 0x000a14,  16, 0x20, 0x00000000 },
-	{ 0x000c00,  16, 0x10, 0x00000000 },
-	{ 0x000c04,  16, 0x10, 0x00000000 },
-	{ 0x000c08,  16, 0x10, 0x00000000 },
-	{ 0x000c0c,  16, 0x10, 0x3f800000 },
-	{ 0x000d00,   8, 0x08, 0xffff0000 },
-	{ 0x000d04,   8, 0x08, 0xffff0000 },
-	{ 0x000e00,  16, 0x10, 0x00000000 },
-	{ 0x000e04,  16, 0x10, 0xffff0000 },
-	{ 0x000e08,  16, 0x10, 0xffff0000 },
-	{ 0x000d40,   4, 0x08, 0x00000000 },
-	{ 0x000d44,   4, 0x08, 0x00000000 },
-	{ 0x001e00,   8, 0x20, 0x00000001 },
-	{ 0x001e04,   8, 0x20, 0x00000001 },
-	{ 0x001e08,   8, 0x20, 0x00000002 },
-	{ 0x001e0c,   8, 0x20, 0x00000001 },
-	{ 0x001e10,   8, 0x20, 0x00000001 },
-	{ 0x001e14,   8, 0x20, 0x00000002 },
-	{ 0x001e18,   8, 0x20, 0x00000001 },
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x001514,   1, 0x04, 0x00000000 },
-	{ 0x000d68,   1, 0x04, 0x0000ffff },
-	{ 0x00121c,   1, 0x04, 0x0fac6881 },
-	{ 0x000fac,   1, 0x04, 0x00000001 },
-	{ 0x001538,   1, 0x04, 0x00000001 },
-	{ 0x000fe0,   2, 0x04, 0x00000000 },
-	{ 0x000fe8,   1, 0x04, 0x00000014 },
-	{ 0x000fec,   1, 0x04, 0x00000040 },
-	{ 0x000ff0,   1, 0x04, 0x00000000 },
-	{ 0x00179c,   1, 0x04, 0x00000000 },
-	{ 0x001228,   1, 0x04, 0x00000400 },
-	{ 0x00122c,   1, 0x04, 0x00000300 },
-	{ 0x001230,   1, 0x04, 0x00010001 },
-	{ 0x0007f8,   1, 0x04, 0x00000000 },
-	{ 0x0015b4,   1, 0x04, 0x00000001 },
-	{ 0x0015cc,   1, 0x04, 0x00000000 },
-	{ 0x001534,   1, 0x04, 0x00000000 },
-	{ 0x000fb0,   1, 0x04, 0x00000000 },
-	{ 0x0015d0,   1, 0x04, 0x00000000 },
-	{ 0x00153c,   1, 0x04, 0x00000000 },
-	{ 0x0016b4,   1, 0x04, 0x00000003 },
-	{ 0x000fbc,   4, 0x04, 0x0000ffff },
-	{ 0x000df8,   2, 0x04, 0x00000000 },
-	{ 0x001948,   1, 0x04, 0x00000000 },
-	{ 0x001970,   1, 0x04, 0x00000001 },
-	{ 0x00161c,   1, 0x04, 0x000009f0 },
-	{ 0x000dcc,   1, 0x04, 0x00000010 },
-	{ 0x00163c,   1, 0x04, 0x00000000 },
-	{ 0x0015e4,   1, 0x04, 0x00000000 },
-	{ 0x001160,  32, 0x04, 0x25e00040 },
-	{ 0x001880,  32, 0x04, 0x00000000 },
-	{ 0x000f84,   2, 0x04, 0x00000000 },
-	{ 0x0017c8,   2, 0x04, 0x00000000 },
-	{ 0x0017d0,   1, 0x04, 0x000000ff },
-	{ 0x0017d4,   1, 0x04, 0xffffffff },
-	{ 0x0017d8,   1, 0x04, 0x00000002 },
-	{ 0x0017dc,   1, 0x04, 0x00000000 },
-	{ 0x0015f4,   2, 0x04, 0x00000000 },
-	{ 0x001434,   2, 0x04, 0x00000000 },
-	{ 0x000d74,   1, 0x04, 0x00000000 },
-	{ 0x000dec,   1, 0x04, 0x00000001 },
-	{ 0x0013a4,   1, 0x04, 0x00000000 },
-	{ 0x001318,   1, 0x04, 0x00000001 },
-	{ 0x001644,   1, 0x04, 0x00000000 },
-	{ 0x000748,   1, 0x04, 0x00000000 },
-	{ 0x000de8,   1, 0x04, 0x00000000 },
-	{ 0x001648,   1, 0x04, 0x00000000 },
-	{ 0x0012a4,   1, 0x04, 0x00000000 },
-	{ 0x001120,   4, 0x04, 0x00000000 },
-	{ 0x001118,   1, 0x04, 0x00000000 },
-	{ 0x00164c,   1, 0x04, 0x00000000 },
-	{ 0x001658,   1, 0x04, 0x00000000 },
-	{ 0x001910,   1, 0x04, 0x00000290 },
-	{ 0x001518,   1, 0x04, 0x00000000 },
-	{ 0x00165c,   1, 0x04, 0x00000001 },
-	{ 0x001520,   1, 0x04, 0x00000000 },
-	{ 0x001604,   1, 0x04, 0x00000000 },
-	{ 0x001570,   1, 0x04, 0x00000000 },
-	{ 0x0013b0,   2, 0x04, 0x3f800000 },
-	{ 0x00020c,   1, 0x04, 0x00000000 },
-	{ 0x001670,   1, 0x04, 0x30201000 },
-	{ 0x001674,   1, 0x04, 0x70605040 },
-	{ 0x001678,   1, 0x04, 0xb8a89888 },
-	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-	{ 0x00166c,   1, 0x04, 0x00000000 },
-	{ 0x001680,   1, 0x04, 0x00ffff00 },
-	{ 0x0012d0,   1, 0x04, 0x00000003 },
-	{ 0x0012d4,   1, 0x04, 0x00000002 },
-	{ 0x001684,   2, 0x04, 0x00000000 },
-	{ 0x000dac,   2, 0x04, 0x00001b02 },
-	{ 0x000db4,   1, 0x04, 0x00000000 },
-	{ 0x00168c,   1, 0x04, 0x00000000 },
-	{ 0x0015bc,   1, 0x04, 0x00000000 },
-	{ 0x00156c,   1, 0x04, 0x00000000 },
-	{ 0x00187c,   1, 0x04, 0x00000000 },
-	{ 0x001110,   1, 0x04, 0x00000001 },
-	{ 0x000dc0,   3, 0x04, 0x00000000 },
-	{ 0x001234,   1, 0x04, 0x00000000 },
-	{ 0x001690,   1, 0x04, 0x00000000 },
-	{ 0x0012ac,   1, 0x04, 0x00000001 },
-	{ 0x0002c4,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x001000,   1, 0x04, 0x00000010 },
-	{ 0x0010fc,   1, 0x04, 0x00000000 },
-	{ 0x001290,   1, 0x04, 0x00000000 },
-	{ 0x000218,   1, 0x04, 0x00000010 },
-	{ 0x0012d8,   1, 0x04, 0x00000000 },
-	{ 0x0012dc,   1, 0x04, 0x00000010 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x00155c,   2, 0x04, 0x00000000 },
-	{ 0x001564,   1, 0x04, 0x00001fff },
-	{ 0x001574,   2, 0x04, 0x00000000 },
-	{ 0x00157c,   1, 0x04, 0x003fffff },
-	{ 0x001354,   1, 0x04, 0x00000000 },
-	{ 0x001664,   1, 0x04, 0x00000000 },
-	{ 0x001610,   1, 0x04, 0x00000012 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x00162c,   1, 0x04, 0x00000003 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000324,   6, 0x04, 0x3f800000 },
-	{ 0x000750,   1, 0x04, 0x00000000 },
-	{ 0x000760,   1, 0x04, 0x39291909 },
-	{ 0x000764,   1, 0x04, 0x79695949 },
-	{ 0x000768,   1, 0x04, 0xb9a99989 },
-	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x000770,   1, 0x04, 0x30201000 },
-	{ 0x000774,   1, 0x04, 0x70605040 },
-	{ 0x000778,   1, 0x04, 0x00009080 },
-	{ 0x000780,   1, 0x04, 0x39291909 },
-	{ 0x000784,   1, 0x04, 0x79695949 },
-	{ 0x000788,   1, 0x04, 0xb9a99989 },
-	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x0007d0,   1, 0x04, 0x30201000 },
-	{ 0x0007d4,   1, 0x04, 0x70605040 },
-	{ 0x0007d8,   1, 0x04, 0x00009080 },
-	{ 0x00037c,   1, 0x04, 0x00000001 },
-	{ 0x000740,   2, 0x04, 0x00000000 },
-	{ 0x002600,   1, 0x04, 0x00000000 },
-	{ 0x001918,   1, 0x04, 0x00000000 },
-	{ 0x00191c,   1, 0x04, 0x00000900 },
-	{ 0x001920,   1, 0x04, 0x00000405 },
-	{ 0x001308,   1, 0x04, 0x00000001 },
-	{ 0x001924,   1, 0x04, 0x00000000 },
-	{ 0x0013ac,   1, 0x04, 0x00000000 },
-	{ 0x00192c,   1, 0x04, 0x00000001 },
-	{ 0x00193c,   1, 0x04, 0x00002c1c },
-	{ 0x000d7c,   1, 0x04, 0x00000000 },
-	{ 0x000f8c,   1, 0x04, 0x00000000 },
-	{ 0x0002c0,   1, 0x04, 0x00000001 },
-	{ 0x001510,   1, 0x04, 0x00000000 },
-	{ 0x001940,   1, 0x04, 0x00000000 },
-	{ 0x000ff4,   2, 0x04, 0x00000000 },
-	{ 0x00194c,   2, 0x04, 0x00000000 },
-	{ 0x001968,   1, 0x04, 0x00000000 },
-	{ 0x001590,   1, 0x04, 0x0000003f },
-	{ 0x0007e8,   4, 0x04, 0x00000000 },
-	{ 0x00196c,   1, 0x04, 0x00000011 },
-	{ 0x00197c,   1, 0x04, 0x00000000 },
-	{ 0x000fcc,   2, 0x04, 0x00000000 },
-	{ 0x0002d8,   1, 0x04, 0x00000040 },
-	{ 0x001980,   1, 0x04, 0x00000080 },
-	{ 0x001504,   1, 0x04, 0x00000080 },
-	{ 0x001984,   1, 0x04, 0x00000000 },
-	{ 0x000300,   1, 0x04, 0x00000001 },
-	{ 0x0013a8,   1, 0x04, 0x00000000 },
-	{ 0x0012ec,   1, 0x04, 0x00000000 },
-	{ 0x001310,   1, 0x04, 0x00000000 },
-	{ 0x001314,   1, 0x04, 0x00000001 },
-	{ 0x001380,   1, 0x04, 0x00000000 },
-	{ 0x001384,   4, 0x04, 0x00000001 },
-	{ 0x001394,   1, 0x04, 0x00000000 },
-	{ 0x00139c,   1, 0x04, 0x00000000 },
-	{ 0x001398,   1, 0x04, 0x00000000 },
-	{ 0x001594,   1, 0x04, 0x00000000 },
-	{ 0x001598,   4, 0x04, 0x00000001 },
-	{ 0x000f54,   3, 0x04, 0x00000000 },
-	{ 0x0019bc,   1, 0x04, 0x00000000 },
-	{ 0x000f9c,   2, 0x04, 0x00000000 },
-	{ 0x0012cc,   1, 0x04, 0x00000000 },
-	{ 0x0012e8,   1, 0x04, 0x00000000 },
-	{ 0x00130c,   1, 0x04, 0x00000001 },
-	{ 0x001360,   8, 0x04, 0x00000000 },
-	{ 0x00133c,   2, 0x04, 0x00000001 },
-	{ 0x001344,   1, 0x04, 0x00000002 },
-	{ 0x001348,   2, 0x04, 0x00000001 },
-	{ 0x001350,   1, 0x04, 0x00000002 },
-	{ 0x001358,   1, 0x04, 0x00000001 },
-	{ 0x0012e4,   1, 0x04, 0x00000000 },
-	{ 0x00131c,   4, 0x04, 0x00000000 },
-	{ 0x0019c0,   1, 0x04, 0x00000000 },
-	{ 0x001140,   1, 0x04, 0x00000000 },
-	{ 0x0019c4,   1, 0x04, 0x00000000 },
-	{ 0x0019c8,   1, 0x04, 0x00001500 },
-	{ 0x00135c,   1, 0x04, 0x00000000 },
-	{ 0x000f90,   1, 0x04, 0x00000000 },
-	{ 0x0019e0,   8, 0x04, 0x00000001 },
-	{ 0x0019cc,   1, 0x04, 0x00000001 },
-	{ 0x0015b8,   1, 0x04, 0x00000000 },
-	{ 0x001a00,   1, 0x04, 0x00001111 },
-	{ 0x001a04,   7, 0x04, 0x00000000 },
-	{ 0x000d6c,   2, 0x04, 0xffff0000 },
-	{ 0x0010f8,   1, 0x04, 0x00001010 },
-	{ 0x000d80,   5, 0x04, 0x00000000 },
-	{ 0x000da0,   1, 0x04, 0x00000000 },
-	{ 0x001508,   1, 0x04, 0x80000000 },
-	{ 0x00150c,   1, 0x04, 0x40000000 },
-	{ 0x001668,   1, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000008 },
-	{ 0x000d9c,   1, 0x04, 0x00000001 },
-	{ 0x0007dc,   1, 0x04, 0x00000000 },
-	{ 0x00074c,   1, 0x04, 0x00000055 },
-	{ 0x001420,   1, 0x04, 0x00000003 },
-	{ 0x0017bc,   2, 0x04, 0x00000000 },
-	{ 0x0017c4,   1, 0x04, 0x00000001 },
-	{ 0x001008,   1, 0x04, 0x00000008 },
-	{ 0x00100c,   1, 0x04, 0x00000040 },
-	{ 0x001010,   1, 0x04, 0x0000012c },
-	{ 0x000d60,   1, 0x04, 0x00000040 },
-	{ 0x00075c,   1, 0x04, 0x00000003 },
-	{ 0x001018,   1, 0x04, 0x00000020 },
-	{ 0x00101c,   1, 0x04, 0x00000001 },
-	{ 0x001020,   1, 0x04, 0x00000020 },
-	{ 0x001024,   1, 0x04, 0x00000001 },
-	{ 0x001444,   3, 0x04, 0x00000000 },
-	{ 0x000360,   1, 0x04, 0x20164010 },
-	{ 0x000364,   1, 0x04, 0x00000020 },
-	{ 0x000368,   1, 0x04, 0x00000000 },
-	{ 0x000de4,   1, 0x04, 0x00000000 },
-	{ 0x000204,   1, 0x04, 0x00000006 },
-	{ 0x000208,   1, 0x04, 0x00000000 },
-	{ 0x0002cc,   1, 0x04, 0x003fffff },
-	{ 0x0002d0,   1, 0x04, 0x00000c48 },
-	{ 0x001220,   1, 0x04, 0x00000005 },
-	{ 0x000fdc,   1, 0x04, 0x00000000 },
-	{ 0x000f98,   1, 0x04, 0x00300008 },
-	{ 0x001284,   1, 0x04, 0x04000080 },
-	{ 0x001450,   1, 0x04, 0x00300008 },
-	{ 0x001454,   1, 0x04, 0x04000080 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_902d_0[] = {
-	{ 0x000200,   1, 0x04, 0x000000cf },
-	{ 0x000204,   1, 0x04, 0x00000001 },
-	{ 0x000208,   1, 0x04, 0x00000020 },
-	{ 0x00020c,   1, 0x04, 0x00000001 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000214,   1, 0x04, 0x00000080 },
-	{ 0x000218,   2, 0x04, 0x00000100 },
-	{ 0x000220,   2, 0x04, 0x00000000 },
-	{ 0x000230,   1, 0x04, 0x000000cf },
-	{ 0x000234,   1, 0x04, 0x00000001 },
-	{ 0x000238,   1, 0x04, 0x00000020 },
-	{ 0x00023c,   1, 0x04, 0x00000001 },
-	{ 0x000244,   1, 0x04, 0x00000080 },
-	{ 0x000248,   2, 0x04, 0x00000100 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_9039_0[] = {
-	{ 0x00030c,   3, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000238,   2, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_90c0_0[] = {
-	{ 0x00270c,   8, 0x20, 0x00000000 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x000758,   1, 0x04, 0x00000100 },
-	{ 0x0002c4,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x000204,   3, 0x04, 0x00000000 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{ 0x00024c,   1, 0x04, 0x00000000 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x001664,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_mthd[] = {
-	{ nvc0_grctx_init_9097_0, 0x9097 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{ nvc0_grctx_init_9039_0, 0x9039 },
-	{ nvc0_grctx_init_90c0_0, 0x90c0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_main_0[] = {
-	{ 0x400204,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_fe_0[] = {
-	{ 0x404004,  11, 0x04, 0x00000000 },
-	{ 0x404044,   1, 0x04, 0x00000000 },
-	{ 0x404094,  13, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf0000087 },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040e8,   1, 0x04, 0x00001000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404138,   1, 0x04, 0x20000040 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000055 },
-	{ 0x404168,   1, 0x04, 0x00000000 },
-	{ 0x404174,   3, 0x04, 0x00000000 },
-	{ 0x404200,   8, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_pri_0[] = {
-	{ 0x404404,  14, 0x04, 0x00000000 },
-	{ 0x404460,   2, 0x04, 0x00000000 },
-	{ 0x404468,   1, 0x04, 0x00ffffff },
-	{ 0x40446c,   1, 0x04, 0x00000000 },
-	{ 0x404480,   1, 0x04, 0x00000001 },
-	{ 0x404498,   1, 0x04, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_memfmt_0[] = {
-	{ 0x404604,   1, 0x04, 0x00000015 },
-	{ 0x404608,   1, 0x04, 0x00000000 },
-	{ 0x40460c,   1, 0x04, 0x00002e00 },
-	{ 0x404610,   1, 0x04, 0x00000100 },
-	{ 0x404618,   8, 0x04, 0x00000000 },
-	{ 0x404638,   1, 0x04, 0x00000004 },
-	{ 0x40463c,   8, 0x04, 0x00000000 },
-	{ 0x40465c,   1, 0x04, 0x007f0100 },
-	{ 0x404660,   7, 0x04, 0x00000000 },
-	{ 0x40467c,   1, 0x04, 0x00000002 },
-	{ 0x404680,   8, 0x04, 0x00000000 },
-	{ 0x4046a0,   1, 0x04, 0x007f0080 },
-	{ 0x4046a4,  18, 0x04, 0x00000000 },
-	{ 0x4046f0,   2, 0x04, 0x00000000 },
-	{ 0x404700,  13, 0x04, 0x00000000 },
-	{ 0x404734,   1, 0x04, 0x00000100 },
-	{ 0x404738,   8, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x078000bf },
-	{ 0x405830,   1, 0x04, 0x02180000 },
-	{ 0x405834,   2, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x000103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b4,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_rstr2d_0[] = {
-	{ 0x407804,   1, 0x04, 0x00000023 },
-	{ 0x40780c,   1, 0x04, 0x0a418820 },
-	{ 0x407810,   1, 0x04, 0x062080e6 },
-	{ 0x407814,   1, 0x04, 0x020398a4 },
-	{ 0x407818,   1, 0x04, 0x0e629062 },
-	{ 0x40781c,   1, 0x04, 0x0a418820 },
-	{ 0x407820,   1, 0x04, 0x000000e6 },
-	{ 0x4078bc,   1, 0x04, 0x00000103 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_scc_0[] = {
-	{ 0x408000,   2, 0x04, 0x00000000 },
-	{ 0x408008,   1, 0x04, 0x00000018 },
-	{ 0x40800c,   2, 0x04, 0x00000000 },
-	{ 0x408014,   1, 0x04, 0x00000069 },
-	{ 0x408018,   1, 0x04, 0xe100e100 },
-	{ 0x408064,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x02802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x0003e00d },
-	{ 0x408900,   1, 0x04, 0x3080b801 },
-	{ 0x408904,   1, 0x04, 0x02000001 },
-	{ 0x408908,   1, 0x04, 0x00c80929 },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nvc0_grctx_init_fe_0 },
-	{ nvc0_grctx_init_pri_0 },
-	{ nvc0_grctx_init_memfmt_0 },
-	{ nvc0_grctx_init_ds_0 },
-	{ nvc0_grctx_init_pd_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nvc0_grctx_init_scc_0 },
-	{ nvc0_grctx_init_be_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpc_unk_0[] = {
-	{ 0x418380,   1, 0x04, 0x00000016 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_prop_0[] = {
-	{ 0x418400,   1, 0x04, 0x38004e00 },
-	{ 0x418404,   1, 0x04, 0x71e0ffff },
-	{ 0x418408,   1, 0x04, 0x00000000 },
-	{ 0x41840c,   1, 0x04, 0x00001008 },
-	{ 0x418410,   1, 0x04, 0x0fff0fff },
-	{ 0x418414,   1, 0x04, 0x00200fff },
-	{ 0x418450,   6, 0x04, 0x00000000 },
-	{ 0x418468,   1, 0x04, 0x00000001 },
-	{ 0x41846c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpc_unk_1[] = {
-	{ 0x418600,   1, 0x04, 0x0000001f },
-	{ 0x418684,   1, 0x04, 0x0000000f },
-	{ 0x418700,   1, 0x04, 0x00000002 },
-	{ 0x418704,   1, 0x04, 0x00000080 },
-	{ 0x418708,   1, 0x04, 0x00000000 },
-	{ 0x41870c,   1, 0x04, 0x07c80000 },
-	{ 0x418710,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x0006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00008442 },
-	{ 0x418830,   1, 0x04, 0x00000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x00100000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_zcull_0[] = {
-	{ 0x41891c,   1, 0x04, 0x00ff00ff },
-	{ 0x418924,   1, 0x04, 0x00000000 },
-	{ 0x418928,   1, 0x04, 0x00ffff00 },
-	{ 0x41892c,   1, 0x04, 0x0000ff00 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_crstr_0[] = {
-	{ 0x418b00,   1, 0x04, 0x00000000 },
-	{ 0x418b08,   1, 0x04, 0x0a418820 },
-	{ 0x418b0c,   1, 0x04, 0x062080e6 },
-	{ 0x418b10,   1, 0x04, 0x020398a4 },
-	{ 0x418b14,   1, 0x04, 0x0e629062 },
-	{ 0x418b18,   1, 0x04, 0x0a418820 },
-	{ 0x418b1c,   1, 0x04, 0x000000e6 },
-	{ 0x418bb8,   1, 0x04, 0x00000103 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpm_0[] = {
-	{ 0x418c08,   1, 0x04, 0x00000001 },
-	{ 0x418c10,   8, 0x04, 0x00000000 },
-	{ 0x418c80,   1, 0x04, 0x20200004 },
-	{ 0x418c8c,   1, 0x04, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gcc_0[] = {
-	{ 0x419000,   1, 0x04, 0x00000780 },
-	{ 0x419004,   2, 0x04, 0x00000000 },
-	{ 0x419014,   1, 0x04, 0x00000004 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvc0_grctx_init_prop_0 },
-	{ nvc0_grctx_init_gpc_unk_1 },
-	{ nvc0_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvc0_grctx_init_crstr_0 },
-	{ nvc0_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_zcullr_0[] = {
-	{ 0x418a00,   3, 0x04, 0x00000000 },
-	{ 0x418a0c,   1, 0x04, 0x00010000 },
-	{ 0x418a10,   3, 0x04, 0x00000000 },
-	{ 0x418a20,   3, 0x04, 0x00000000 },
-	{ 0x418a2c,   1, 0x04, 0x00010000 },
-	{ 0x418a30,   3, 0x04, 0x00000000 },
-	{ 0x418a40,   3, 0x04, 0x00000000 },
-	{ 0x418a4c,   1, 0x04, 0x00010000 },
-	{ 0x418a50,   3, 0x04, 0x00000000 },
-	{ 0x418a60,   3, 0x04, 0x00000000 },
-	{ 0x418a6c,   1, 0x04, 0x00010000 },
-	{ 0x418a70,   3, 0x04, 0x00000000 },
-	{ 0x418a80,   3, 0x04, 0x00000000 },
-	{ 0x418a8c,   1, 0x04, 0x00010000 },
-	{ 0x418a90,   3, 0x04, 0x00000000 },
-	{ 0x418aa0,   3, 0x04, 0x00000000 },
-	{ 0x418aac,   1, 0x04, 0x00010000 },
-	{ 0x418ab0,   3, 0x04, 0x00000000 },
-	{ 0x418ac0,   3, 0x04, 0x00000000 },
-	{ 0x418acc,   1, 0x04, 0x00010000 },
-	{ 0x418ad0,   3, 0x04, 0x00000000 },
-	{ 0x418ae0,   3, 0x04, 0x00000000 },
-	{ 0x418aec,   1, 0x04, 0x00010000 },
-	{ 0x418af0,   3, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_zcull[] = {
-	{ nvc0_grctx_init_zcullr_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_pe_0[] = {
-	{ 0x419818,   1, 0x04, 0x00000000 },
-	{ 0x41983c,   1, 0x04, 0x00038bc7 },
-	{ 0x419848,   1, 0x04, 0x00000000 },
-	{ 0x419864,   1, 0x04, 0x0000012a },
-	{ 0x419888,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000001f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000023 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_wwdx_0[] = {
-	{ 0x419b00,   1, 0x04, 0x0a418820 },
-	{ 0x419b04,   1, 0x04, 0x062080e6 },
-	{ 0x419b08,   1, 0x04, 0x020398a4 },
-	{ 0x419b0c,   1, 0x04, 0x0e629062 },
-	{ 0x419b10,   1, 0x04, 0x0a418820 },
-	{ 0x419b14,   1, 0x04, 0x000000e6 },
-	{ 0x419bd0,   1, 0x04, 0x00900103 },
-	{ 0x419be0,   1, 0x04, 0x00000001 },
-	{ 0x419be4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x00000002 },
-	{ 0x419c04,   1, 0x04, 0x00000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_l1c_0[] = {
-	{ 0x419cb0,   1, 0x04, 0x00060048 },
-	{ 0x419ce8,   1, 0x04, 0x00000000 },
-	{ 0x419cf4,   1, 0x04, 0x00000183 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_tpccs_0[] = {
-	{ 0x419d20,   1, 0x04, 0x02180000 },
-	{ 0x419d24,   1, 0x04, 0x00001fff },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_sm_0[] = {
-	{ 0x419e04,   3, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00000002 },
-	{ 0x419e44,   1, 0x04, 0x001beff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000000f },
-	{ 0x419e50,  17, 0x04, 0x00000000 },
-	{ 0x419e98,   1, 0x04, 0x00000000 },
-	{ 0x419f50,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_tpc[] = {
-	{ nvc0_grctx_init_pe_0 },
-	{ nvc0_grctx_init_tex_0 },
-	{ nvc0_grctx_init_wwdx_0 },
-	{ nvc0_grctx_init_mpc_0 },
-	{ nvc0_grctx_init_l1c_0 },
-	{ nvc0_grctx_init_tpccs_0 },
-	{ nvc0_grctx_init_sm_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-int
-nvc0_grctx_mmio_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access)
-{
-	if (info->data) {
-		info->buffer[info->buffer_nr] = round_up(info->addr, align);
-		info->addr = info->buffer[info->buffer_nr] + size;
-		info->data->size = size;
-		info->data->align = align;
-		info->data->access = access;
-		info->data++;
-		return info->buffer_nr++;
-	}
-	return -1;
-}
-
-void
-nvc0_grctx_mmio_item(struct nvc0_grctx *info, u32 addr, u32 data,
-		     int shift, int buffer)
-{
-	if (info->data) {
-		if (shift >= 0) {
-			info->mmio->addr = addr;
-			info->mmio->data = data;
-			info->mmio->shift = shift;
-			info->mmio->buffer = buffer;
-			if (buffer >= 0)
-				data |= info->buffer[buffer] >> shift;
-			info->mmio++;
-		} else
-			return;
-	} else {
-		if (buffer >= 0)
-			return;
-	}
-
-	nv_wr32(info->priv, addr, data);
-}
-
-void
-nvc0_grctx_generate_bundle(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
-	mmio_refn(info, 0x408004, 0x00000000, s, b);
-	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
-	mmio_refn(info, 0x418808, 0x00000000, s, b);
-	mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
-}
-
-void
-nvc0_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
-	mmio_refn(info, 0x40800c, 0x00000000, s, b);
-	mmio_wr32(info, 0x408010, 0x80000000);
-	mmio_refn(info, 0x419004, 0x00000000, s, b);
-	mmio_wr32(info, 0x419008, 0x00000000);
-}
-
-void
-nvc0_grctx_generate_attrib(struct nvc0_grctx *info)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
-	const u32 attrib = impl->attrib_nr;
-	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
-	const u32 access = NV_MEM_ACCESS_RW;
-	const int s = 12;
-	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
-	int gpc, tpc;
-	u32 bo = 0;
-
-	mmio_refn(info, 0x418810, 0x80000000, s, b);
-	mmio_refn(info, 0x419848, 0x10000000, s, b);
-	mmio_wr32(info, 0x405830, (attrib << 16));
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			const u32 o = TPC_UNIT(gpc, tpc, 0x0520);
-			mmio_skip(info, o, (attrib << 16) | ++bo);
-			mmio_wr32(info, o, (attrib << 16) | --bo);
-			bo += impl->attrib_nr_max;
-		}
-	}
-}
-
-void
-nvc0_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
-}
-
-void
-nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
-{
-	int gpc, tpc, id;
-
-	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			if (tpc < priv->tpc_nr[gpc]) {
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
-				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
-				id++;
-			}
-
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
-		}
-	}
-}
-
-void
-nvc0_grctx_generate_r406028(struct nvc0_graph_priv *priv)
-{
-	u32 tmp[GPC_MAX / 8] = {}, i = 0;
-	for (i = 0; i < priv->gpc_nr; i++)
-		tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
-	for (i = 0; i < 4; i++) {
-		nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
-		nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
-	}
-}
-
-void
-nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *priv)
-{
-	u8  tpcnr[GPC_MAX], data[TPC_MAX];
-	int gpc, tpc, i;
-
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	memset(data, 0x1f, sizeof(data));
-
-	gpc = -1;
-	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpcnr[gpc]--;
-		data[tpc] = gpc;
-	}
-
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
-}
-
-void
-nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
-{
-	u32 data[6] = {}, data2[2] = {};
-	u8  tpcnr[GPC_MAX];
-	u8  shift, ntpcv;
-	int gpc, tpc, i;
-
-	/* calculate first set of magics */
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
-	gpc = -1;
-	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpcnr[gpc]--;
-
-		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
-	}
-
-	for (; tpc < 32; tpc++)
-		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
-	/* and the second... */
-	shift = 0;
-	ntpcv = priv->tpc_total;
-	while (!(ntpcv & (1 << 4))) {
-		ntpcv <<= 1;
-		shift++;
-	}
-
-	data2[0]  = (ntpcv << 16);
-	data2[0] |= (shift << 21);
-	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-	for (i = 1; i < 7; i++)
-		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
-	/* GPC_BROADCAST */
-	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
-	/* GPC_BROADCAST.TP_BROADCAST */
-	nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr | data2[0]);
-	nv_wr32(priv, 0x419be4, data2[1]);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
-
-	/* UNK78xx */
-	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-}
-
-void
-nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
-{
-	u64 tpc_mask = 0, tpc_set = 0;
-	u8  tpcnr[GPC_MAX];
-	int gpc, tpc;
-	int i, a, b;
-
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++)
-		tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
-	for (i = 0, gpc = -1, b = -1; i < 32; i++) {
-		a = (i * (priv->tpc_total - 1)) / 32;
-		if (a != b) {
-			b = a;
-			do {
-				gpc = (gpc + 1) % priv->gpc_nr;
-			} while (!tpcnr[gpc]);
-			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-			tpc_set |= 1ULL << ((gpc * 8) + tpc);
-		}
-
-		nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
-		nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
-		if (priv->gpc_nr > 4) {
-			nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
-			nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
-		}
-	}
-}
-
-void
-nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
-	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
-	nvc0_graph_mmio(priv, oclass->hub);
-	nvc0_graph_mmio(priv, oclass->gpc);
-	nvc0_graph_mmio(priv, oclass->zcull);
-	nvc0_graph_mmio(priv, oclass->tpc);
-	nvc0_graph_mmio(priv, oclass->ppc);
-
-	nv_wr32(priv, 0x404154, 0x00000000);
-
-	oclass->bundle(info);
-	oclass->pagepool(info);
-	oclass->attrib(info);
-	oclass->unkn(priv);
-
-	nvc0_grctx_generate_tpcid(priv);
-	nvc0_grctx_generate_r406028(priv);
-	nvc0_grctx_generate_r4060a8(priv);
-	nvc0_grctx_generate_r418bb8(priv);
-	nvc0_grctx_generate_r406800(priv);
-
-	nvc0_graph_icmd(priv, oclass->icmd);
-	nv_wr32(priv, 0x404154, 0x00000400);
-	nvc0_graph_mthd(priv, oclass->mthd);
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-}
-
-int
-nvc0_grctx_generate(struct nvc0_graph_priv *priv)
-{
-	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nouveau_gpuobj *chan;
-	struct nvc0_grctx info;
-	int ret, i;
-
-	/* allocate memory to for a "channel", which we'll use to generate
-	 * the default context values
-	 */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
-				 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	if (ret) {
-		nv_error(priv, "failed to allocate channel memory, %d\n", ret);
-		return ret;
-	}
-
-	/* PGD pointer */
-	nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
-	nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
-	nv_wo32(chan, 0x0208, 0xffffffff);
-	nv_wo32(chan, 0x020c, 0x000000ff);
-
-	/* PGT[0] pointer */
-	nv_wo32(chan, 0x1000, 0x00000000);
-	nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
-
-	/* identity-map the whole "channel" into its own vm */
-	for (i = 0; i < chan->size / 4096; i++) {
-		u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
-		nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
-		nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
-	}
-
-	/* context pointer (virt) */
-	nv_wo32(chan, 0x0210, 0x00080004);
-	nv_wo32(chan, 0x0214, 0x00000000);
-
-	bar->flush(bar);
-
-	nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
-	nv_wr32(priv, 0x100cbc, 0x80000001);
-	nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
-
-	/* setup default state for mmio list construction */
-	info.priv = priv;
-	info.data = priv->mmio_data;
-	info.mmio = priv->mmio_list;
-	info.addr = 0x2000 + (i * 8);
-	info.buffer_nr = 0;
-
-	/* make channel current */
-	if (priv->firmware) {
-		nv_wr32(priv, 0x409840, 0x00000030);
-		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
-		nv_wr32(priv, 0x409504, 0x00000003);
-		if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
-			nv_error(priv, "load_ctx timeout\n");
-
-		nv_wo32(chan, 0x8001c, 1);
-		nv_wo32(chan, 0x80020, 0);
-		nv_wo32(chan, 0x80028, 0);
-		nv_wo32(chan, 0x8002c, 0);
-		bar->flush(bar);
-	} else {
-		nv_wr32(priv, 0x409840, 0x80000000);
-		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
-		nv_wr32(priv, 0x409504, 0x00000001);
-		if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
-			nv_error(priv, "HUB_SET_CHAN timeout\n");
-	}
-
-	oclass->main(priv, &info);
-
-	/* trigger a context unload by unsetting the "next channel valid" bit
-	 * and faking a context switch interrupt
-	 */
-	nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
-	nv_wr32(priv, 0x409000, 0x00000100);
-	if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
-		nv_error(priv, "grctx template channel unload timeout\n");
-		ret = -EBUSY;
-		goto done;
-	}
-
-	priv->data = kmalloc(priv->size, GFP_KERNEL);
-	if (priv->data) {
-		for (i = 0; i < priv->size; i += 4)
-			priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
-		ret = 0;
-	} else {
-		ret = -ENOMEM;
-	}
-
-done:
-	nouveau_gpuobj_ref(NULL, &chan);
-	return ret;
-}
-
-struct nouveau_oclass *
-nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvc0_grctx_generate_main,
-	.unkn  = nvc0_grctx_generate_unkn,
-	.hub   = nvc0_grctx_pack_hub,
-	.gpc   = nvc0_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvc0_grctx_pack_tpc,
-	.icmd  = nvc0_grctx_pack_icmd,
-	.mthd  = nvc0_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvc0_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h
deleted file mode 100644
index c776cd7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h
+++ /dev/null
@@ -1,202 +0,0 @@
-#ifndef __NVKM_GRCTX_NVC0_H__
-#define __NVKM_GRCTX_NVC0_H__
-
-#include "nvc0.h"
-
-struct nvc0_grctx {
-	struct nvc0_graph_priv *priv;
-	struct nvc0_graph_data *data;
-	struct nvc0_graph_mmio *mmio;
-	int buffer_nr;
-	u64 buffer[4];
-	u64 addr;
-};
-
-int  nvc0_grctx_mmio_data(struct nvc0_grctx *, u32 size, u32 align, u32 access);
-void nvc0_grctx_mmio_item(struct nvc0_grctx *, u32 addr, u32 data, int s, int);
-
-#define mmio_vram(a,b,c,d) nvc0_grctx_mmio_data((a), (b), (c), (d))
-#define mmio_refn(a,b,c,d,e) nvc0_grctx_mmio_item((a), (b), (c), (d), (e))
-#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1)
-#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c),  0, -1)
-
-struct nvc0_grctx_oclass {
-	struct nouveau_oclass base;
-	/* main context generation function */
-	void  (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
-	/* context-specific modify-on-first-load list generation function */
-	void  (*unkn)(struct nvc0_graph_priv *);
-	/* mmio context data */
-	const struct nvc0_graph_pack *hub;
-	const struct nvc0_graph_pack *gpc;
-	const struct nvc0_graph_pack *zcull;
-	const struct nvc0_graph_pack *tpc;
-	const struct nvc0_graph_pack *ppc;
-	/* indirect context data, generated with icmds/mthds */
-	const struct nvc0_graph_pack *icmd;
-	const struct nvc0_graph_pack *mthd;
-	/* bundle circular buffer */
-	void (*bundle)(struct nvc0_grctx *);
-	u32 bundle_size;
-	u32 bundle_min_gpm_fifo_depth;
-	u32 bundle_token_limit;
-	/* pagepool */
-	void (*pagepool)(struct nvc0_grctx *);
-	u32 pagepool_size;
-	/* attribute(/alpha) circular buffer */
-	void (*attrib)(struct nvc0_grctx *);
-	u32 attrib_nr_max;
-	u32 attrib_nr;
-	u32 alpha_nr_max;
-	u32 alpha_nr;
-};
-
-static inline const struct nvc0_grctx_oclass *
-nvc0_grctx_impl(struct nvc0_graph_priv *priv)
-{
-	return (void *)nv_engine(priv)->cclass;
-}
-
-extern struct nouveau_oclass *nvc0_grctx_oclass;
-int  nvc0_grctx_generate(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_generate_bundle(struct nvc0_grctx *);
-void nvc0_grctx_generate_pagepool(struct nvc0_grctx *);
-void nvc0_grctx_generate_attrib(struct nvc0_grctx *);
-void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvc1_grctx_oclass;
-void nvc1_grctx_generate_attrib(struct nvc0_grctx *);
-void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvc4_grctx_oclass;
-extern struct nouveau_oclass *nvc8_grctx_oclass;
-
-extern struct nouveau_oclass *nvd7_grctx_oclass;
-void nvd7_grctx_generate_attrib(struct nvc0_grctx *);
-
-extern struct nouveau_oclass *nvd9_grctx_oclass;
-
-extern struct nouveau_oclass *nve4_grctx_oclass;
-extern struct nouveau_oclass *gk20a_grctx_oclass;
-void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nve4_grctx_generate_bundle(struct nvc0_grctx *);
-void nve4_grctx_generate_pagepool(struct nvc0_grctx *);
-void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
-void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvf0_grctx_oclass;
-extern struct nouveau_oclass *gk110b_grctx_oclass;
-extern struct nouveau_oclass *nv108_grctx_oclass;
-extern struct nouveau_oclass *gm107_grctx_oclass;
-
-/* context init value lists */
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_mthd[];
-extern const struct nvc0_graph_init nvc0_grctx_init_902d_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_9039_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_90c0_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_hub[];
-extern const struct nvc0_graph_init nvc0_grctx_init_main_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_fe_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_pri_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_memfmt_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_rstr2d_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_scc_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_gpc[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvc0_grctx_init_zcull_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_crstr_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpm_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gcc_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_zcull[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_tpc[];
-extern const struct nvc0_graph_init nvc0_grctx_init_pe_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_mpc_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_tpccs_0[];
-
-extern const struct nvc0_graph_init nvc4_grctx_init_tex_0[];
-extern const struct nvc0_graph_init nvc4_grctx_init_l1c_0[];
-extern const struct nvc0_graph_init nvc4_grctx_init_sm_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_9097_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_gpm_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_pe_0[];
-extern const struct nvc0_graph_init nvc1_grctx_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc1_grctx_init_tpccs_0[];
-
-extern const struct nvc0_graph_init nvc8_grctx_init_9197_0[];
-extern const struct nvc0_graph_init nvc8_grctx_init_9297_0[];
-
-extern const struct nvc0_graph_pack nvd9_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvd9_grctx_pack_mthd[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_fe_0[];
-extern const struct nvc0_graph_init nvd9_grctx_init_be_0[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nvd9_grctx_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvd9_grctx_init_crstr_0[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_sm_0[];
-
-extern const struct nvc0_graph_init nvd7_grctx_init_pe_0[];
-
-extern const struct nvc0_graph_init nvd7_grctx_init_wwdx_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_memfmt_0[];
-extern const struct nvc0_graph_init nve4_grctx_init_ds_0[];
-extern const struct nvc0_graph_init nve4_grctx_init_scc_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_gpm_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_pes_0[];
-
-extern const struct nvc0_graph_pack nve4_grctx_pack_hub[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_gpc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_tpc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_ppc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_icmd[];
-extern const struct nvc0_graph_init nve4_grctx_init_a097_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_mthd[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_hub[];
-extern const struct nvc0_graph_init nvf0_grctx_init_pri_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_cwd_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_gpc[];
-extern const struct nvc0_graph_init nvf0_grctx_init_gpc_unk_2[];
-
-extern const struct nvc0_graph_init nvf0_grctx_init_tex_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_mpc_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_l1c_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_ppc[];
-
-extern const struct nvc0_graph_init nv108_grctx_init_rstr2d_0[];
-
-extern const struct nvc0_graph_init nv108_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nv108_grctx_init_crstr_0[];
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
deleted file mode 100644
index c6ba8fe..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000b2,  40, 0x01, 0x00000000 },
-	{ 0x000210,   8, 0x01, 0x00000040 },
-	{ 0x000218,   8, 0x01, 0x0000c080 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00001fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x003fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x0005e0,   5, 0x01, 0x00000022 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x00000c48 },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00300008 },
-	{ 0x000841,   1, 0x01, 0x04000080 },
-	{ 0x000842,   1, 0x01, 0x00300008 },
-	{ 0x000843,   1, 0x01, 0x04000080 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x000944,   1, 0x01, 0x00000022 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000014 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_icmd[] = {
-	{ nvc1_grctx_init_icmd_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_9097_0[] = {
-	{ 0x000800,   8, 0x40, 0x00000000 },
-	{ 0x000804,   8, 0x40, 0x00000000 },
-	{ 0x000808,   8, 0x40, 0x00000400 },
-	{ 0x00080c,   8, 0x40, 0x00000300 },
-	{ 0x000810,   1, 0x04, 0x000000cf },
-	{ 0x000850,   7, 0x40, 0x00000000 },
-	{ 0x000814,   8, 0x40, 0x00000040 },
-	{ 0x000818,   8, 0x40, 0x00000001 },
-	{ 0x00081c,   8, 0x40, 0x00000000 },
-	{ 0x000820,   8, 0x40, 0x00000000 },
-	{ 0x002700,   8, 0x20, 0x00000000 },
-	{ 0x002704,   8, 0x20, 0x00000000 },
-	{ 0x002708,   8, 0x20, 0x00000000 },
-	{ 0x00270c,   8, 0x20, 0x00000000 },
-	{ 0x002710,   8, 0x20, 0x00014000 },
-	{ 0x002714,   8, 0x20, 0x00000040 },
-	{ 0x001c00,  16, 0x10, 0x00000000 },
-	{ 0x001c04,  16, 0x10, 0x00000000 },
-	{ 0x001c08,  16, 0x10, 0x00000000 },
-	{ 0x001c0c,  16, 0x10, 0x00000000 },
-	{ 0x001d00,  16, 0x10, 0x00000000 },
-	{ 0x001d04,  16, 0x10, 0x00000000 },
-	{ 0x001d08,  16, 0x10, 0x00000000 },
-	{ 0x001d0c,  16, 0x10, 0x00000000 },
-	{ 0x001f00,  16, 0x08, 0x00000000 },
-	{ 0x001f04,  16, 0x08, 0x00000000 },
-	{ 0x001f80,  16, 0x08, 0x00000000 },
-	{ 0x001f84,  16, 0x08, 0x00000000 },
-	{ 0x002200,   5, 0x10, 0x00000022 },
-	{ 0x002000,   1, 0x04, 0x00000000 },
-	{ 0x002040,   1, 0x04, 0x00000011 },
-	{ 0x002080,   1, 0x04, 0x00000020 },
-	{ 0x0020c0,   1, 0x04, 0x00000030 },
-	{ 0x002100,   1, 0x04, 0x00000040 },
-	{ 0x002140,   1, 0x04, 0x00000051 },
-	{ 0x00200c,   6, 0x40, 0x00000001 },
-	{ 0x002010,   1, 0x04, 0x00000000 },
-	{ 0x002050,   1, 0x04, 0x00000000 },
-	{ 0x002090,   1, 0x04, 0x00000001 },
-	{ 0x0020d0,   1, 0x04, 0x00000002 },
-	{ 0x002110,   1, 0x04, 0x00000003 },
-	{ 0x002150,   1, 0x04, 0x00000004 },
-	{ 0x000380,   4, 0x20, 0x00000000 },
-	{ 0x000384,   4, 0x20, 0x00000000 },
-	{ 0x000388,   4, 0x20, 0x00000000 },
-	{ 0x00038c,   4, 0x20, 0x00000000 },
-	{ 0x000700,   4, 0x10, 0x00000000 },
-	{ 0x000704,   4, 0x10, 0x00000000 },
-	{ 0x000708,   4, 0x10, 0x00000000 },
-	{ 0x002800, 128, 0x04, 0x00000000 },
-	{ 0x000a00,  16, 0x20, 0x00000000 },
-	{ 0x000a04,  16, 0x20, 0x00000000 },
-	{ 0x000a08,  16, 0x20, 0x00000000 },
-	{ 0x000a0c,  16, 0x20, 0x00000000 },
-	{ 0x000a10,  16, 0x20, 0x00000000 },
-	{ 0x000a14,  16, 0x20, 0x00000000 },
-	{ 0x000c00,  16, 0x10, 0x00000000 },
-	{ 0x000c04,  16, 0x10, 0x00000000 },
-	{ 0x000c08,  16, 0x10, 0x00000000 },
-	{ 0x000c0c,  16, 0x10, 0x3f800000 },
-	{ 0x000d00,   8, 0x08, 0xffff0000 },
-	{ 0x000d04,   8, 0x08, 0xffff0000 },
-	{ 0x000e00,  16, 0x10, 0x00000000 },
-	{ 0x000e04,  16, 0x10, 0xffff0000 },
-	{ 0x000e08,  16, 0x10, 0xffff0000 },
-	{ 0x000d40,   4, 0x08, 0x00000000 },
-	{ 0x000d44,   4, 0x08, 0x00000000 },
-	{ 0x001e00,   8, 0x20, 0x00000001 },
-	{ 0x001e04,   8, 0x20, 0x00000001 },
-	{ 0x001e08,   8, 0x20, 0x00000002 },
-	{ 0x001e0c,   8, 0x20, 0x00000001 },
-	{ 0x001e10,   8, 0x20, 0x00000001 },
-	{ 0x001e14,   8, 0x20, 0x00000002 },
-	{ 0x001e18,   8, 0x20, 0x00000001 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x001514,   1, 0x04, 0x00000000 },
-	{ 0x000d68,   1, 0x04, 0x0000ffff },
-	{ 0x00121c,   1, 0x04, 0x0fac6881 },
-	{ 0x000fac,   1, 0x04, 0x00000001 },
-	{ 0x001538,   1, 0x04, 0x00000001 },
-	{ 0x000fe0,   2, 0x04, 0x00000000 },
-	{ 0x000fe8,   1, 0x04, 0x00000014 },
-	{ 0x000fec,   1, 0x04, 0x00000040 },
-	{ 0x000ff0,   1, 0x04, 0x00000000 },
-	{ 0x00179c,   1, 0x04, 0x00000000 },
-	{ 0x001228,   1, 0x04, 0x00000400 },
-	{ 0x00122c,   1, 0x04, 0x00000300 },
-	{ 0x001230,   1, 0x04, 0x00010001 },
-	{ 0x0007f8,   1, 0x04, 0x00000000 },
-	{ 0x0015b4,   1, 0x04, 0x00000001 },
-	{ 0x0015cc,   1, 0x04, 0x00000000 },
-	{ 0x001534,   1, 0x04, 0x00000000 },
-	{ 0x000fb0,   1, 0x04, 0x00000000 },
-	{ 0x0015d0,   1, 0x04, 0x00000000 },
-	{ 0x00153c,   1, 0x04, 0x00000000 },
-	{ 0x0016b4,   1, 0x04, 0x00000003 },
-	{ 0x000fbc,   4, 0x04, 0x0000ffff },
-	{ 0x000df8,   2, 0x04, 0x00000000 },
-	{ 0x001948,   1, 0x04, 0x00000000 },
-	{ 0x001970,   1, 0x04, 0x00000001 },
-	{ 0x00161c,   1, 0x04, 0x000009f0 },
-	{ 0x000dcc,   1, 0x04, 0x00000010 },
-	{ 0x00163c,   1, 0x04, 0x00000000 },
-	{ 0x0015e4,   1, 0x04, 0x00000000 },
-	{ 0x001160,  32, 0x04, 0x25e00040 },
-	{ 0x001880,  32, 0x04, 0x00000000 },
-	{ 0x000f84,   2, 0x04, 0x00000000 },
-	{ 0x0017c8,   2, 0x04, 0x00000000 },
-	{ 0x0017d0,   1, 0x04, 0x000000ff },
-	{ 0x0017d4,   1, 0x04, 0xffffffff },
-	{ 0x0017d8,   1, 0x04, 0x00000002 },
-	{ 0x0017dc,   1, 0x04, 0x00000000 },
-	{ 0x0015f4,   2, 0x04, 0x00000000 },
-	{ 0x001434,   2, 0x04, 0x00000000 },
-	{ 0x000d74,   1, 0x04, 0x00000000 },
-	{ 0x000dec,   1, 0x04, 0x00000001 },
-	{ 0x0013a4,   1, 0x04, 0x00000000 },
-	{ 0x001318,   1, 0x04, 0x00000001 },
-	{ 0x001644,   1, 0x04, 0x00000000 },
-	{ 0x000748,   1, 0x04, 0x00000000 },
-	{ 0x000de8,   1, 0x04, 0x00000000 },
-	{ 0x001648,   1, 0x04, 0x00000000 },
-	{ 0x0012a4,   1, 0x04, 0x00000000 },
-	{ 0x001120,   4, 0x04, 0x00000000 },
-	{ 0x001118,   1, 0x04, 0x00000000 },
-	{ 0x00164c,   1, 0x04, 0x00000000 },
-	{ 0x001658,   1, 0x04, 0x00000000 },
-	{ 0x001910,   1, 0x04, 0x00000290 },
-	{ 0x001518,   1, 0x04, 0x00000000 },
-	{ 0x00165c,   1, 0x04, 0x00000001 },
-	{ 0x001520,   1, 0x04, 0x00000000 },
-	{ 0x001604,   1, 0x04, 0x00000000 },
-	{ 0x001570,   1, 0x04, 0x00000000 },
-	{ 0x0013b0,   2, 0x04, 0x3f800000 },
-	{ 0x00020c,   1, 0x04, 0x00000000 },
-	{ 0x001670,   1, 0x04, 0x30201000 },
-	{ 0x001674,   1, 0x04, 0x70605040 },
-	{ 0x001678,   1, 0x04, 0xb8a89888 },
-	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-	{ 0x00166c,   1, 0x04, 0x00000000 },
-	{ 0x001680,   1, 0x04, 0x00ffff00 },
-	{ 0x0012d0,   1, 0x04, 0x00000003 },
-	{ 0x0012d4,   1, 0x04, 0x00000002 },
-	{ 0x001684,   2, 0x04, 0x00000000 },
-	{ 0x000dac,   2, 0x04, 0x00001b02 },
-	{ 0x000db4,   1, 0x04, 0x00000000 },
-	{ 0x00168c,   1, 0x04, 0x00000000 },
-	{ 0x0015bc,   1, 0x04, 0x00000000 },
-	{ 0x00156c,   1, 0x04, 0x00000000 },
-	{ 0x00187c,   1, 0x04, 0x00000000 },
-	{ 0x001110,   1, 0x04, 0x00000001 },
-	{ 0x000dc0,   3, 0x04, 0x00000000 },
-	{ 0x001234,   1, 0x04, 0x00000000 },
-	{ 0x001690,   1, 0x04, 0x00000000 },
-	{ 0x0012ac,   1, 0x04, 0x00000001 },
-	{ 0x0002c4,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x001000,   1, 0x04, 0x00000010 },
-	{ 0x0010fc,   1, 0x04, 0x00000000 },
-	{ 0x001290,   1, 0x04, 0x00000000 },
-	{ 0x000218,   1, 0x04, 0x00000010 },
-	{ 0x0012d8,   1, 0x04, 0x00000000 },
-	{ 0x0012dc,   1, 0x04, 0x00000010 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x00155c,   2, 0x04, 0x00000000 },
-	{ 0x001564,   1, 0x04, 0x00001fff },
-	{ 0x001574,   2, 0x04, 0x00000000 },
-	{ 0x00157c,   1, 0x04, 0x003fffff },
-	{ 0x001354,   1, 0x04, 0x00000000 },
-	{ 0x001664,   1, 0x04, 0x00000000 },
-	{ 0x001610,   1, 0x04, 0x00000012 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x00162c,   1, 0x04, 0x00000003 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000324,   6, 0x04, 0x3f800000 },
-	{ 0x000750,   1, 0x04, 0x00000000 },
-	{ 0x000760,   1, 0x04, 0x39291909 },
-	{ 0x000764,   1, 0x04, 0x79695949 },
-	{ 0x000768,   1, 0x04, 0xb9a99989 },
-	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x000770,   1, 0x04, 0x30201000 },
-	{ 0x000774,   1, 0x04, 0x70605040 },
-	{ 0x000778,   1, 0x04, 0x00009080 },
-	{ 0x000780,   1, 0x04, 0x39291909 },
-	{ 0x000784,   1, 0x04, 0x79695949 },
-	{ 0x000788,   1, 0x04, 0xb9a99989 },
-	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x0007d0,   1, 0x04, 0x30201000 },
-	{ 0x0007d4,   1, 0x04, 0x70605040 },
-	{ 0x0007d8,   1, 0x04, 0x00009080 },
-	{ 0x00037c,   1, 0x04, 0x00000001 },
-	{ 0x000740,   2, 0x04, 0x00000000 },
-	{ 0x002600,   1, 0x04, 0x00000000 },
-	{ 0x001918,   1, 0x04, 0x00000000 },
-	{ 0x00191c,   1, 0x04, 0x00000900 },
-	{ 0x001920,   1, 0x04, 0x00000405 },
-	{ 0x001308,   1, 0x04, 0x00000001 },
-	{ 0x001924,   1, 0x04, 0x00000000 },
-	{ 0x0013ac,   1, 0x04, 0x00000000 },
-	{ 0x00192c,   1, 0x04, 0x00000001 },
-	{ 0x00193c,   1, 0x04, 0x00002c1c },
-	{ 0x000d7c,   1, 0x04, 0x00000000 },
-	{ 0x000f8c,   1, 0x04, 0x00000000 },
-	{ 0x0002c0,   1, 0x04, 0x00000001 },
-	{ 0x001510,   1, 0x04, 0x00000000 },
-	{ 0x001940,   1, 0x04, 0x00000000 },
-	{ 0x000ff4,   2, 0x04, 0x00000000 },
-	{ 0x00194c,   2, 0x04, 0x00000000 },
-	{ 0x001968,   1, 0x04, 0x00000000 },
-	{ 0x001590,   1, 0x04, 0x0000003f },
-	{ 0x0007e8,   4, 0x04, 0x00000000 },
-	{ 0x00196c,   1, 0x04, 0x00000011 },
-	{ 0x00197c,   1, 0x04, 0x00000000 },
-	{ 0x000fcc,   2, 0x04, 0x00000000 },
-	{ 0x0002d8,   1, 0x04, 0x00000040 },
-	{ 0x001980,   1, 0x04, 0x00000080 },
-	{ 0x001504,   1, 0x04, 0x00000080 },
-	{ 0x001984,   1, 0x04, 0x00000000 },
-	{ 0x000300,   1, 0x04, 0x00000001 },
-	{ 0x0013a8,   1, 0x04, 0x00000000 },
-	{ 0x0012ec,   1, 0x04, 0x00000000 },
-	{ 0x001310,   1, 0x04, 0x00000000 },
-	{ 0x001314,   1, 0x04, 0x00000001 },
-	{ 0x001380,   1, 0x04, 0x00000000 },
-	{ 0x001384,   4, 0x04, 0x00000001 },
-	{ 0x001394,   1, 0x04, 0x00000000 },
-	{ 0x00139c,   1, 0x04, 0x00000000 },
-	{ 0x001398,   1, 0x04, 0x00000000 },
-	{ 0x001594,   1, 0x04, 0x00000000 },
-	{ 0x001598,   4, 0x04, 0x00000001 },
-	{ 0x000f54,   3, 0x04, 0x00000000 },
-	{ 0x0019bc,   1, 0x04, 0x00000000 },
-	{ 0x000f9c,   2, 0x04, 0x00000000 },
-	{ 0x0012cc,   1, 0x04, 0x00000000 },
-	{ 0x0012e8,   1, 0x04, 0x00000000 },
-	{ 0x00130c,   1, 0x04, 0x00000001 },
-	{ 0x001360,   8, 0x04, 0x00000000 },
-	{ 0x00133c,   2, 0x04, 0x00000001 },
-	{ 0x001344,   1, 0x04, 0x00000002 },
-	{ 0x001348,   2, 0x04, 0x00000001 },
-	{ 0x001350,   1, 0x04, 0x00000002 },
-	{ 0x001358,   1, 0x04, 0x00000001 },
-	{ 0x0012e4,   1, 0x04, 0x00000000 },
-	{ 0x00131c,   4, 0x04, 0x00000000 },
-	{ 0x0019c0,   1, 0x04, 0x00000000 },
-	{ 0x001140,   1, 0x04, 0x00000000 },
-	{ 0x0019c4,   1, 0x04, 0x00000000 },
-	{ 0x0019c8,   1, 0x04, 0x00001500 },
-	{ 0x00135c,   1, 0x04, 0x00000000 },
-	{ 0x000f90,   1, 0x04, 0x00000000 },
-	{ 0x0019e0,   8, 0x04, 0x00000001 },
-	{ 0x0019cc,   1, 0x04, 0x00000001 },
-	{ 0x0015b8,   1, 0x04, 0x00000000 },
-	{ 0x001a00,   1, 0x04, 0x00001111 },
-	{ 0x001a04,   7, 0x04, 0x00000000 },
-	{ 0x000d6c,   2, 0x04, 0xffff0000 },
-	{ 0x0010f8,   1, 0x04, 0x00001010 },
-	{ 0x000d80,   5, 0x04, 0x00000000 },
-	{ 0x000da0,   1, 0x04, 0x00000000 },
-	{ 0x001508,   1, 0x04, 0x80000000 },
-	{ 0x00150c,   1, 0x04, 0x40000000 },
-	{ 0x001668,   1, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000008 },
-	{ 0x000d9c,   1, 0x04, 0x00000001 },
-	{ 0x0007dc,   1, 0x04, 0x00000000 },
-	{ 0x00074c,   1, 0x04, 0x00000055 },
-	{ 0x001420,   1, 0x04, 0x00000003 },
-	{ 0x0017bc,   2, 0x04, 0x00000000 },
-	{ 0x0017c4,   1, 0x04, 0x00000001 },
-	{ 0x001008,   1, 0x04, 0x00000008 },
-	{ 0x00100c,   1, 0x04, 0x00000040 },
-	{ 0x001010,   1, 0x04, 0x0000012c },
-	{ 0x000d60,   1, 0x04, 0x00000040 },
-	{ 0x00075c,   1, 0x04, 0x00000003 },
-	{ 0x001018,   1, 0x04, 0x00000020 },
-	{ 0x00101c,   1, 0x04, 0x00000001 },
-	{ 0x001020,   1, 0x04, 0x00000020 },
-	{ 0x001024,   1, 0x04, 0x00000001 },
-	{ 0x001444,   3, 0x04, 0x00000000 },
-	{ 0x000360,   1, 0x04, 0x20164010 },
-	{ 0x000364,   1, 0x04, 0x00000020 },
-	{ 0x000368,   1, 0x04, 0x00000000 },
-	{ 0x000de4,   1, 0x04, 0x00000000 },
-	{ 0x000204,   1, 0x04, 0x00000006 },
-	{ 0x000208,   1, 0x04, 0x00000000 },
-	{ 0x0002cc,   1, 0x04, 0x003fffff },
-	{ 0x0002d0,   1, 0x04, 0x00000c48 },
-	{ 0x001220,   1, 0x04, 0x00000005 },
-	{ 0x000fdc,   1, 0x04, 0x00000000 },
-	{ 0x000f98,   1, 0x04, 0x00300008 },
-	{ 0x001284,   1, 0x04, 0x04000080 },
-	{ 0x001450,   1, 0x04, 0x00300008 },
-	{ 0x001454,   1, 0x04, 0x04000080 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_9197_0[] = {
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x0002e4,   1, 0x04, 0x0000b001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_mthd[] = {
-	{ nvc1_grctx_init_9097_0, 0x9097 },
-	{ nvc1_grctx_init_9197_0, 0x9197 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{ nvc0_grctx_init_9039_0, 0x9039 },
-	{ nvc0_grctx_init_90c0_0, 0x90c0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8000bf },
-	{ 0x405830,   1, 0x04, 0x02180218 },
-	{ 0x405834,   2, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x000103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b4,   2, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x80140078 },
-	{ 0x4064c4,   1, 0x04, 0x0086ffff },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x02802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1003e005 },
-	{ 0x408900,   1, 0x04, 0x3080b801 },
-	{ 0x408904,   1, 0x04, 0x62000001 },
-	{ 0x408908,   1, 0x04, 0x00c80929 },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nvc0_grctx_init_fe_0 },
-	{ nvc0_grctx_init_pri_0 },
-	{ nvc0_grctx_init_memfmt_0 },
-	{ nvc1_grctx_init_ds_0 },
-	{ nvc1_grctx_init_pd_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nvc0_grctx_init_scc_0 },
-	{ nvc1_grctx_init_be_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x0006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00008442 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x00100018 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_gpm_0[] = {
-	{ 0x418c08,   1, 0x04, 0x00000001 },
-	{ 0x418c10,   8, 0x04, 0x00000000 },
-	{ 0x418c6c,   1, 0x04, 0x00000001 },
-	{ 0x418c80,   1, 0x04, 0x20200004 },
-	{ 0x418c8c,   1, 0x04, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvc0_grctx_init_prop_0 },
-	{ nvc0_grctx_init_gpc_unk_1 },
-	{ nvc1_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvc0_grctx_init_crstr_0 },
-	{ nvc1_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_pe_0[] = {
-	{ 0x419818,   1, 0x04, 0x00000000 },
-	{ 0x41983c,   1, 0x04, 0x00038bc7 },
-	{ 0x419848,   1, 0x04, 0x00000000 },
-	{ 0x419864,   1, 0x04, 0x00000129 },
-	{ 0x419888,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_wwdx_0[] = {
-	{ 0x419b00,   1, 0x04, 0x0a418820 },
-	{ 0x419b04,   1, 0x04, 0x062080e6 },
-	{ 0x419b08,   1, 0x04, 0x020398a4 },
-	{ 0x419b0c,   1, 0x04, 0x0e629062 },
-	{ 0x419b10,   1, 0x04, 0x0a418820 },
-	{ 0x419b14,   1, 0x04, 0x000000e6 },
-	{ 0x419bd0,   1, 0x04, 0x00900103 },
-	{ 0x419be0,   1, 0x04, 0x00400001 },
-	{ 0x419be4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_tpccs_0[] = {
-	{ 0x419d20,   1, 0x04, 0x12180000 },
-	{ 0x419d24,   1, 0x04, 0x00001fff },
-	{ 0x419d44,   1, 0x04, 0x02180218 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_tpc[] = {
-	{ nvc1_grctx_init_pe_0 },
-	{ nvc4_grctx_init_tex_0 },
-	{ nvc1_grctx_init_wwdx_0 },
-	{ nvc0_grctx_init_mpc_0 },
-	{ nvc4_grctx_init_l1c_0 },
-	{ nvc1_grctx_init_tpccs_0 },
-	{ nvc4_grctx_init_sm_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nvc1_grctx_generate_attrib(struct nvc0_grctx *info)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
-	const u32  alpha = impl->alpha_nr;
-	const u32   beta = impl->attrib_nr;
-	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
-	const u32 access = NV_MEM_ACCESS_RW;
-	const int s = 12;
-	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
-	const int timeslice_mode = 1;
-	const int max_batches = 0xffff;
-	u32 bo = 0;
-	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
-	int gpc, tpc;
-
-	mmio_refn(info, 0x418810, 0x80000000, s, b);
-	mmio_refn(info, 0x419848, 0x10000000, s, b);
-	mmio_wr32(info, 0x405830, (beta << 16) | alpha);
-	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			const u32 a = alpha;
-			const u32 b =  beta;
-			const u32 t = timeslice_mode;
-			const u32 o = TPC_UNIT(gpc, tpc, 0x500);
-			mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo);
-			mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo);
-			bo += impl->attrib_nr_max;
-			mmio_wr32(info, o + 0x44, (a << 16) | ao);
-			ao += impl->alpha_nr_max;
-		}
-	}
-}
-
-void
-nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
-	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
-	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
-	nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
-	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
-	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
-	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
-}
-
-struct nouveau_oclass *
-nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xc1),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvc0_grctx_generate_main,
-	.unkn  = nvc1_grctx_generate_unkn,
-	.hub   = nvc1_grctx_pack_hub,
-	.gpc   = nvc1_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvc1_grctx_pack_tpc,
-	.icmd  = nvc1_grctx_pack_icmd,
-	.mthd  = nvc1_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvc1_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x324,
-	.alpha_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c
deleted file mode 100644
index 41705c6..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc4_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000001f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000023 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x00000000 },
-	{ 0x419a20,   1, 0x04, 0x00000800 },
-	{ 0x419ac4,   1, 0x04, 0x0007f440 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc4_grctx_init_l1c_0[] = {
-	{ 0x419cb0,   1, 0x04, 0x00020048 },
-	{ 0x419ce8,   1, 0x04, 0x00000000 },
-	{ 0x419cf4,   1, 0x04, 0x00000183 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc4_grctx_init_sm_0[] = {
-	{ 0x419e04,   3, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00000002 },
-	{ 0x419e44,   1, 0x04, 0x001beff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000000f },
-	{ 0x419e50,  17, 0x04, 0x00000000 },
-	{ 0x419e98,   1, 0x04, 0x00000000 },
-	{ 0x419ee0,   1, 0x04, 0x00011110 },
-	{ 0x419f30,  11, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc4_grctx_pack_tpc[] = {
-	{ nvc0_grctx_init_pe_0 },
-	{ nvc4_grctx_init_tex_0 },
-	{ nvc0_grctx_init_wwdx_0 },
-	{ nvc0_grctx_init_mpc_0 },
-	{ nvc4_grctx_init_l1c_0 },
-	{ nvc0_grctx_init_tpccs_0 },
-	{ nvc4_grctx_init_sm_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xc3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvc0_grctx_generate_main,
-	.unkn  = nvc0_grctx_generate_unkn,
-	.hub   = nvc0_grctx_pack_hub,
-	.gpc   = nvc0_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvc4_grctx_pack_tpc,
-	.icmd  = nvc0_grctx_pack_icmd,
-	.mthd  = nvc0_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvc0_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
deleted file mode 100644
index 8f804cd..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc8_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000b2,  40, 0x01, 0x00000000 },
-	{ 0x000210,   8, 0x01, 0x00000040 },
-	{ 0x000218,   8, 0x01, 0x0000c080 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00001fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x003fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x0005e0,   5, 0x01, 0x00000022 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x00097d,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x00000c48 },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00300008 },
-	{ 0x000841,   1, 0x01, 0x04000080 },
-	{ 0x000842,   1, 0x01, 0x00300008 },
-	{ 0x000843,   1, 0x01, 0x04000080 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x000944,   1, 0x01, 0x00000022 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000014 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_icmd[] = {
-	{ nvc8_grctx_init_icmd_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc8_grctx_init_9197_0[] = {
-	{ 0x0002e4,   1, 0x04, 0x0000b001 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc8_grctx_init_9297_0[] = {
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x00036c,   2, 0x04, 0x00000000 },
-	{ 0x0007a4,   2, 0x04, 0x00000000 },
-	{ 0x000374,   1, 0x04, 0x00000000 },
-	{ 0x000378,   1, 0x04, 0x00000020 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_mthd[] = {
-	{ nvc1_grctx_init_9097_0, 0x9097 },
-	{ nvc8_grctx_init_9197_0, 0x9197 },
-	{ nvc8_grctx_init_9297_0, 0x9297 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{ nvc0_grctx_init_9039_0, 0x9039 },
-	{ nvc0_grctx_init_90c0_0, 0x90c0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc8_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x0006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00008442 },
-	{ 0x418830,   1, 0x04, 0x00000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvc0_grctx_init_prop_0 },
-	{ nvc0_grctx_init_gpc_unk_1 },
-	{ nvc8_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvc0_grctx_init_crstr_0 },
-	{ nvc0_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xc8),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvc0_grctx_generate_main,
-	.unkn  = nvc0_grctx_generate_unkn,
-	.hub   = nvc0_grctx_pack_hub,
-	.gpc   = nvc8_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvc0_grctx_pack_tpc,
-	.icmd  = nvc8_grctx_pack_icmd,
-	.mthd  = nvc8_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvc0_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
deleted file mode 100644
index fcf534f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8000bf },
-	{ 0x405830,   1, 0x04, 0x02180324 },
-	{ 0x405834,   1, 0x04, 0x08000000 },
-	{ 0x405838,   1, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x000103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b4,   3, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x801a0078 },
-	{ 0x4064c4,   1, 0x04, 0x00c9ffff },
-	{ 0x4064d0,   8, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nvd9_grctx_init_fe_0 },
-	{ nvc0_grctx_init_pri_0 },
-	{ nvc0_grctx_init_memfmt_0 },
-	{ nvd7_grctx_init_ds_0 },
-	{ nvd7_grctx_init_pd_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nvc0_grctx_init_scc_0 },
-	{ nvd9_grctx_init_be_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00008442 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100018 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvd9_grctx_init_prop_0 },
-	{ nvd9_grctx_init_gpc_unk_1 },
-	{ nvd7_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvd9_grctx_init_crstr_0 },
-	{ nvc1_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd7_grctx_init_pe_0[] = {
-	{ 0x419848,   1, 0x04, 0x00000000 },
-	{ 0x419864,   1, 0x04, 0x00000129 },
-	{ 0x419888,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000001f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000023 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x00008000 },
-	{ 0x419a20,   1, 0x04, 0x00000800 },
-	{ 0x419ac4,   1, 0x04, 0x0017f440 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x0000000a },
-	{ 0x419c04,   1, 0x04, 0x00000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{ 0x419c24,   1, 0x04, 0x00084210 },
-	{ 0x419c28,   1, 0x04, 0x3efbefbe },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ nvd7_grctx_init_tex_0 },
-	{ nvd7_grctx_init_mpc_0 },
-	{ nvc4_grctx_init_l1c_0 },
-	{ nvd9_grctx_init_sm_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_pes_0[] = {
-	{ 0x41be24,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_cbm_0[] = {
-	{ 0x41bec0,   1, 0x04, 0x12180000 },
-	{ 0x41bec4,   1, 0x04, 0x00003fff },
-	{ 0x41bee4,   1, 0x04, 0x03240218 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd7_grctx_init_wwdx_0[] = {
-	{ 0x41bf00,   1, 0x04, 0x0a418820 },
-	{ 0x41bf04,   1, 0x04, 0x062080e6 },
-	{ 0x41bf08,   1, 0x04, 0x020398a4 },
-	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
-	{ 0x41bf10,   1, 0x04, 0x0a418820 },
-	{ 0x41bf14,   1, 0x04, 0x000000e6 },
-	{ 0x41bfd0,   1, 0x04, 0x00900103 },
-	{ 0x41bfe0,   1, 0x04, 0x00400001 },
-	{ 0x41bfe4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_ppc[] = {
-	{ nvd7_grctx_init_pes_0 },
-	{ nvd7_grctx_init_cbm_0 },
-	{ nvd7_grctx_init_wwdx_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nvd7_grctx_generate_attrib(struct nvc0_grctx *info)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
-	const u32  alpha = impl->alpha_nr;
-	const u32   beta = impl->attrib_nr;
-	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
-	const u32 access = NV_MEM_ACCESS_RW;
-	const int s = 12;
-	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
-	const int timeslice_mode = 1;
-	const int max_batches = 0xffff;
-	u32 bo = 0;
-	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
-	int gpc, ppc;
-
-	mmio_refn(info, 0x418810, 0x80000000, s, b);
-	mmio_refn(info, 0x419848, 0x10000000, s, b);
-	mmio_wr32(info, 0x405830, (beta << 16) | alpha);
-	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) {
-			const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc];
-			const u32 b =  beta * priv->ppc_tpc_nr[gpc][ppc];
-			const u32 t = timeslice_mode;
-			const u32 o = PPC_UNIT(gpc, ppc, 0);
-			mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
-			mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
-			bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
-			mmio_wr32(info, o + 0xe4, (a << 16) | ao);
-			ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
-		}
-	}
-}
-
-void
-nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
-	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-	int i;
-
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
-	nvc0_graph_mmio(priv, oclass->hub);
-	nvc0_graph_mmio(priv, oclass->gpc);
-	nvc0_graph_mmio(priv, oclass->zcull);
-	nvc0_graph_mmio(priv, oclass->tpc);
-	nvc0_graph_mmio(priv, oclass->ppc);
-
-	nv_wr32(priv, 0x404154, 0x00000000);
-
-	oclass->bundle(info);
-	oclass->pagepool(info);
-	oclass->attrib(info);
-	oclass->unkn(priv);
-
-	nvc0_grctx_generate_tpcid(priv);
-	nvc0_grctx_generate_r406028(priv);
-	nvc0_grctx_generate_r4060a8(priv);
-	nve4_grctx_generate_r418bb8(priv);
-	nvc0_grctx_generate_r406800(priv);
-
-	for (i = 0; i < 8; i++)
-		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
-	nvc0_graph_icmd(priv, oclass->icmd);
-	nv_wr32(priv, 0x404154, 0x00000400);
-	nvc0_graph_mthd(priv, oclass->mthd);
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-}
-
-struct nouveau_oclass *
-nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xd7),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvd7_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nvd7_grctx_pack_hub,
-	.gpc   = nvd7_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvd7_grctx_pack_tpc,
-	.ppc   = nvd7_grctx_pack_ppc,
-	.icmd  = nvd9_grctx_pack_icmd,
-	.mthd  = nvd9_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x7ff,
-	.alpha_nr = 0x324,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
deleted file mode 100644
index b9a301b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000b2,  40, 0x01, 0x00000000 },
-	{ 0x000210,   8, 0x01, 0x00000040 },
-	{ 0x000400,  24, 0x01, 0x00000040 },
-	{ 0x000218,   8, 0x01, 0x0000c080 },
-	{ 0x000440,  24, 0x01, 0x0000c080 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00001fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x003fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x0005e0,   5, 0x01, 0x00000022 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x00097d,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x00000c48 },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00300008 },
-	{ 0x000841,   1, 0x01, 0x04000080 },
-	{ 0x000842,   1, 0x01, 0x00300008 },
-	{ 0x000843,   1, 0x01, 0x04000080 },
-	{ 0x000818,   8, 0x01, 0x00000000 },
-	{ 0x000848,  16, 0x01, 0x00000000 },
-	{ 0x000738,   1, 0x01, 0x00000000 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x000944,   1, 0x01, 0x00000022 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000014 },
-	{ 0x000351,   1, 0x01, 0x00000100 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095d,   1, 0x01, 0x00000001 },
-	{ 0x00082b,   1, 0x01, 0x00000004 },
-	{ 0x000942,   1, 0x01, 0x00010001 },
-	{ 0x000943,   1, 0x01, 0x00000001 },
-	{ 0x0007c5,   1, 0x01, 0x00010001 },
-	{ 0x000834,   1, 0x01, 0x00000001 },
-	{ 0x0007c7,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x00080c,   1, 0x01, 0x00000002 },
-	{ 0x00080d,   2, 0x01, 0x00000100 },
-	{ 0x00080f,   1, 0x01, 0x00000001 },
-	{ 0x000823,   1, 0x01, 0x00000002 },
-	{ 0x000824,   2, 0x01, 0x00000100 },
-	{ 0x000826,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvd9_grctx_pack_icmd[] = {
-	{ nvd9_grctx_init_icmd_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_90c0_0[] = {
-	{ 0x002700,   8, 0x20, 0x00000000 },
-	{ 0x002704,   8, 0x20, 0x00000000 },
-	{ 0x002708,   8, 0x20, 0x00000000 },
-	{ 0x00270c,   8, 0x20, 0x00000000 },
-	{ 0x002710,   8, 0x20, 0x00014000 },
-	{ 0x002714,   8, 0x20, 0x00000040 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x000758,   1, 0x04, 0x00000100 },
-	{ 0x0002c4,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x000204,   3, 0x04, 0x00000000 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{ 0x00024c,   1, 0x04, 0x00000000 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x001664,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvd9_grctx_pack_mthd[] = {
-	{ nvc1_grctx_init_9097_0, 0x9097 },
-	{ nvc8_grctx_init_9197_0, 0x9197 },
-	{ nvc8_grctx_init_9297_0, 0x9297 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{ nvc0_grctx_init_9039_0, 0x9039 },
-	{ nvd9_grctx_init_90c0_0, 0x90c0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_fe_0[] = {
-	{ 0x404004,  10, 0x04, 0x00000000 },
-	{ 0x404044,   1, 0x04, 0x00000000 },
-	{ 0x404094,  13, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf0000087 },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040e8,   1, 0x04, 0x00001000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404138,   1, 0x04, 0x20000040 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000055 },
-	{ 0x404168,   1, 0x04, 0x00000000 },
-	{ 0x404178,   2, 0x04, 0x00000000 },
-	{ 0x404200,   8, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8000bf },
-	{ 0x405830,   1, 0x04, 0x02180218 },
-	{ 0x405834,   1, 0x04, 0x08000000 },
-	{ 0x405838,   1, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x000103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b4,   3, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x80140078 },
-	{ 0x4064c4,   1, 0x04, 0x0086ffff },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x02802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1043e005 },
-	{ 0x408900,   1, 0x04, 0x3080b801 },
-	{ 0x408904,   1, 0x04, 0x62000001 },
-	{ 0x408908,   1, 0x04, 0x00c8102f },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nvd9_grctx_init_fe_0 },
-	{ nvc0_grctx_init_pri_0 },
-	{ nvc0_grctx_init_memfmt_0 },
-	{ nvd9_grctx_init_ds_0 },
-	{ nvd9_grctx_init_pd_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nvc0_grctx_init_scc_0 },
-	{ nvd9_grctx_init_be_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_prop_0[] = {
-	{ 0x418400,   1, 0x04, 0x38004e00 },
-	{ 0x418404,   1, 0x04, 0x71e0ffff },
-	{ 0x41840c,   1, 0x04, 0x00001008 },
-	{ 0x418410,   1, 0x04, 0x0fff0fff },
-	{ 0x418414,   1, 0x04, 0x02200fff },
-	{ 0x418450,   6, 0x04, 0x00000000 },
-	{ 0x418468,   1, 0x04, 0x00000001 },
-	{ 0x41846c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_gpc_unk_1[] = {
-	{ 0x418600,   1, 0x04, 0x0000001f },
-	{ 0x418684,   1, 0x04, 0x0000000f },
-	{ 0x418700,   1, 0x04, 0x00000002 },
-	{ 0x418704,   1, 0x04, 0x00000080 },
-	{ 0x418708,   3, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00008442 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100008 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_crstr_0[] = {
-	{ 0x418b00,   1, 0x04, 0x00000006 },
-	{ 0x418b08,   1, 0x04, 0x0a418820 },
-	{ 0x418b0c,   1, 0x04, 0x062080e6 },
-	{ 0x418b10,   1, 0x04, 0x020398a4 },
-	{ 0x418b14,   1, 0x04, 0x0e629062 },
-	{ 0x418b18,   1, 0x04, 0x0a418820 },
-	{ 0x418b1c,   1, 0x04, 0x000000e6 },
-	{ 0x418bb8,   1, 0x04, 0x00000103 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvd9_grctx_init_prop_0 },
-	{ nvd9_grctx_init_gpc_unk_1 },
-	{ nvd9_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvd9_grctx_init_crstr_0 },
-	{ nvc1_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000001f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000023 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x00000000 },
-	{ 0x419a20,   1, 0x04, 0x00000800 },
-	{ 0x419ac4,   1, 0x04, 0x0017f440 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x0000000a },
-	{ 0x419c04,   1, 0x04, 0x00000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{ 0x419c24,   1, 0x04, 0x00084210 },
-	{ 0x419c28,   1, 0x04, 0x3cf3cf3c },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_sm_0[] = {
-	{ 0x419e04,   3, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00000002 },
-	{ 0x419e44,   1, 0x04, 0x001beff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000000f },
-	{ 0x419e50,  17, 0x04, 0x00000000 },
-	{ 0x419e98,   1, 0x04, 0x00000000 },
-	{ 0x419ee0,   1, 0x04, 0x00010110 },
-	{ 0x419f30,  11, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_tpc[] = {
-	{ nvc1_grctx_init_pe_0 },
-	{ nvd9_grctx_init_tex_0 },
-	{ nvc1_grctx_init_wwdx_0 },
-	{ nvd9_grctx_init_mpc_0 },
-	{ nvc4_grctx_init_l1c_0 },
-	{ nvc1_grctx_init_tpccs_0 },
-	{ nvd9_grctx_init_sm_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xd9),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nvc0_grctx_generate_main,
-	.unkn  = nvc1_grctx_generate_unkn,
-	.hub   = nvd9_grctx_pack_hub,
-	.gpc   = nvd9_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvd9_grctx_pack_tpc,
-	.icmd  = nvd9_grctx_pack_icmd,
-	.mthd  = nvd9_grctx_pack_mthd,
-	.bundle = nvc0_grctx_generate_bundle,
-	.bundle_size = 0x1800,
-	.pagepool = nvc0_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvc1_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x324,
-	.alpha_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
deleted file mode 100644
index ccac2ee..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nve4_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000383,   1, 0x01, 0x00000011 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x00097d,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x003fffff },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00400008 },
-	{ 0x000841,   1, 0x01, 0x08000080 },
-	{ 0x000842,   1, 0x01, 0x00400008 },
-	{ 0x000843,   1, 0x01, 0x08000080 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000008 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_icmd[] = {
-	{ nve4_grctx_init_icmd_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_a097_0[] = {
-	{ 0x000800,   8, 0x40, 0x00000000 },
-	{ 0x000804,   8, 0x40, 0x00000000 },
-	{ 0x000808,   8, 0x40, 0x00000400 },
-	{ 0x00080c,   8, 0x40, 0x00000300 },
-	{ 0x000810,   1, 0x04, 0x000000cf },
-	{ 0x000850,   7, 0x40, 0x00000000 },
-	{ 0x000814,   8, 0x40, 0x00000040 },
-	{ 0x000818,   8, 0x40, 0x00000001 },
-	{ 0x00081c,   8, 0x40, 0x00000000 },
-	{ 0x000820,   8, 0x40, 0x00000000 },
-	{ 0x001c00,  16, 0x10, 0x00000000 },
-	{ 0x001c04,  16, 0x10, 0x00000000 },
-	{ 0x001c08,  16, 0x10, 0x00000000 },
-	{ 0x001c0c,  16, 0x10, 0x00000000 },
-	{ 0x001d00,  16, 0x10, 0x00000000 },
-	{ 0x001d04,  16, 0x10, 0x00000000 },
-	{ 0x001d08,  16, 0x10, 0x00000000 },
-	{ 0x001d0c,  16, 0x10, 0x00000000 },
-	{ 0x001f00,  16, 0x08, 0x00000000 },
-	{ 0x001f04,  16, 0x08, 0x00000000 },
-	{ 0x001f80,  16, 0x08, 0x00000000 },
-	{ 0x001f84,  16, 0x08, 0x00000000 },
-	{ 0x002000,   1, 0x04, 0x00000000 },
-	{ 0x002040,   1, 0x04, 0x00000011 },
-	{ 0x002080,   1, 0x04, 0x00000020 },
-	{ 0x0020c0,   1, 0x04, 0x00000030 },
-	{ 0x002100,   1, 0x04, 0x00000040 },
-	{ 0x002140,   1, 0x04, 0x00000051 },
-	{ 0x00200c,   6, 0x40, 0x00000001 },
-	{ 0x002010,   1, 0x04, 0x00000000 },
-	{ 0x002050,   1, 0x04, 0x00000000 },
-	{ 0x002090,   1, 0x04, 0x00000001 },
-	{ 0x0020d0,   1, 0x04, 0x00000002 },
-	{ 0x002110,   1, 0x04, 0x00000003 },
-	{ 0x002150,   1, 0x04, 0x00000004 },
-	{ 0x000380,   4, 0x20, 0x00000000 },
-	{ 0x000384,   4, 0x20, 0x00000000 },
-	{ 0x000388,   4, 0x20, 0x00000000 },
-	{ 0x00038c,   4, 0x20, 0x00000000 },
-	{ 0x000700,   4, 0x10, 0x00000000 },
-	{ 0x000704,   4, 0x10, 0x00000000 },
-	{ 0x000708,   4, 0x10, 0x00000000 },
-	{ 0x002800, 128, 0x04, 0x00000000 },
-	{ 0x000a00,  16, 0x20, 0x00000000 },
-	{ 0x000a04,  16, 0x20, 0x00000000 },
-	{ 0x000a08,  16, 0x20, 0x00000000 },
-	{ 0x000a0c,  16, 0x20, 0x00000000 },
-	{ 0x000a10,  16, 0x20, 0x00000000 },
-	{ 0x000a14,  16, 0x20, 0x00000000 },
-	{ 0x000c00,  16, 0x10, 0x00000000 },
-	{ 0x000c04,  16, 0x10, 0x00000000 },
-	{ 0x000c08,  16, 0x10, 0x00000000 },
-	{ 0x000c0c,  16, 0x10, 0x3f800000 },
-	{ 0x000d00,   8, 0x08, 0xffff0000 },
-	{ 0x000d04,   8, 0x08, 0xffff0000 },
-	{ 0x000e00,  16, 0x10, 0x00000000 },
-	{ 0x000e04,  16, 0x10, 0xffff0000 },
-	{ 0x000e08,  16, 0x10, 0xffff0000 },
-	{ 0x000d40,   4, 0x08, 0x00000000 },
-	{ 0x000d44,   4, 0x08, 0x00000000 },
-	{ 0x001e00,   8, 0x20, 0x00000001 },
-	{ 0x001e04,   8, 0x20, 0x00000001 },
-	{ 0x001e08,   8, 0x20, 0x00000002 },
-	{ 0x001e0c,   8, 0x20, 0x00000001 },
-	{ 0x001e10,   8, 0x20, 0x00000001 },
-	{ 0x001e14,   8, 0x20, 0x00000002 },
-	{ 0x001e18,   8, 0x20, 0x00000001 },
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x001514,   1, 0x04, 0x00000000 },
-	{ 0x000d68,   1, 0x04, 0x0000ffff },
-	{ 0x00121c,   1, 0x04, 0x0fac6881 },
-	{ 0x000fac,   1, 0x04, 0x00000001 },
-	{ 0x001538,   1, 0x04, 0x00000001 },
-	{ 0x000fe0,   2, 0x04, 0x00000000 },
-	{ 0x000fe8,   1, 0x04, 0x00000014 },
-	{ 0x000fec,   1, 0x04, 0x00000040 },
-	{ 0x000ff0,   1, 0x04, 0x00000000 },
-	{ 0x00179c,   1, 0x04, 0x00000000 },
-	{ 0x001228,   1, 0x04, 0x00000400 },
-	{ 0x00122c,   1, 0x04, 0x00000300 },
-	{ 0x001230,   1, 0x04, 0x00010001 },
-	{ 0x0007f8,   1, 0x04, 0x00000000 },
-	{ 0x0015b4,   1, 0x04, 0x00000001 },
-	{ 0x0015cc,   1, 0x04, 0x00000000 },
-	{ 0x001534,   1, 0x04, 0x00000000 },
-	{ 0x000fb0,   1, 0x04, 0x00000000 },
-	{ 0x0015d0,   1, 0x04, 0x00000000 },
-	{ 0x00153c,   1, 0x04, 0x00000000 },
-	{ 0x0016b4,   1, 0x04, 0x00000003 },
-	{ 0x000fbc,   4, 0x04, 0x0000ffff },
-	{ 0x000df8,   2, 0x04, 0x00000000 },
-	{ 0x001948,   1, 0x04, 0x00000000 },
-	{ 0x001970,   1, 0x04, 0x00000001 },
-	{ 0x00161c,   1, 0x04, 0x000009f0 },
-	{ 0x000dcc,   1, 0x04, 0x00000010 },
-	{ 0x00163c,   1, 0x04, 0x00000000 },
-	{ 0x0015e4,   1, 0x04, 0x00000000 },
-	{ 0x001160,  32, 0x04, 0x25e00040 },
-	{ 0x001880,  32, 0x04, 0x00000000 },
-	{ 0x000f84,   2, 0x04, 0x00000000 },
-	{ 0x0017c8,   2, 0x04, 0x00000000 },
-	{ 0x0017d0,   1, 0x04, 0x000000ff },
-	{ 0x0017d4,   1, 0x04, 0xffffffff },
-	{ 0x0017d8,   1, 0x04, 0x00000002 },
-	{ 0x0017dc,   1, 0x04, 0x00000000 },
-	{ 0x0015f4,   2, 0x04, 0x00000000 },
-	{ 0x001434,   2, 0x04, 0x00000000 },
-	{ 0x000d74,   1, 0x04, 0x00000000 },
-	{ 0x000dec,   1, 0x04, 0x00000001 },
-	{ 0x0013a4,   1, 0x04, 0x00000000 },
-	{ 0x001318,   1, 0x04, 0x00000001 },
-	{ 0x001644,   1, 0x04, 0x00000000 },
-	{ 0x000748,   1, 0x04, 0x00000000 },
-	{ 0x000de8,   1, 0x04, 0x00000000 },
-	{ 0x001648,   1, 0x04, 0x00000000 },
-	{ 0x0012a4,   1, 0x04, 0x00000000 },
-	{ 0x001120,   4, 0x04, 0x00000000 },
-	{ 0x001118,   1, 0x04, 0x00000000 },
-	{ 0x00164c,   1, 0x04, 0x00000000 },
-	{ 0x001658,   1, 0x04, 0x00000000 },
-	{ 0x001910,   1, 0x04, 0x00000290 },
-	{ 0x001518,   1, 0x04, 0x00000000 },
-	{ 0x00165c,   1, 0x04, 0x00000001 },
-	{ 0x001520,   1, 0x04, 0x00000000 },
-	{ 0x001604,   1, 0x04, 0x00000000 },
-	{ 0x001570,   1, 0x04, 0x00000000 },
-	{ 0x0013b0,   2, 0x04, 0x3f800000 },
-	{ 0x00020c,   1, 0x04, 0x00000000 },
-	{ 0x001670,   1, 0x04, 0x30201000 },
-	{ 0x001674,   1, 0x04, 0x70605040 },
-	{ 0x001678,   1, 0x04, 0xb8a89888 },
-	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-	{ 0x00166c,   1, 0x04, 0x00000000 },
-	{ 0x001680,   1, 0x04, 0x00ffff00 },
-	{ 0x0012d0,   1, 0x04, 0x00000003 },
-	{ 0x0012d4,   1, 0x04, 0x00000002 },
-	{ 0x001684,   2, 0x04, 0x00000000 },
-	{ 0x000dac,   2, 0x04, 0x00001b02 },
-	{ 0x000db4,   1, 0x04, 0x00000000 },
-	{ 0x00168c,   1, 0x04, 0x00000000 },
-	{ 0x0015bc,   1, 0x04, 0x00000000 },
-	{ 0x00156c,   1, 0x04, 0x00000000 },
-	{ 0x00187c,   1, 0x04, 0x00000000 },
-	{ 0x001110,   1, 0x04, 0x00000001 },
-	{ 0x000dc0,   3, 0x04, 0x00000000 },
-	{ 0x001234,   1, 0x04, 0x00000000 },
-	{ 0x001690,   1, 0x04, 0x00000000 },
-	{ 0x0012ac,   1, 0x04, 0x00000001 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x001000,   1, 0x04, 0x00000010 },
-	{ 0x0010fc,   1, 0x04, 0x00000000 },
-	{ 0x001290,   1, 0x04, 0x00000000 },
-	{ 0x000218,   1, 0x04, 0x00000010 },
-	{ 0x0012d8,   1, 0x04, 0x00000000 },
-	{ 0x0012dc,   1, 0x04, 0x00000010 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x00155c,   2, 0x04, 0x00000000 },
-	{ 0x001564,   1, 0x04, 0x00000fff },
-	{ 0x001574,   2, 0x04, 0x00000000 },
-	{ 0x00157c,   1, 0x04, 0x000fffff },
-	{ 0x001354,   1, 0x04, 0x00000000 },
-	{ 0x001610,   1, 0x04, 0x00000012 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x00260c,   1, 0x04, 0x00000000 },
-	{ 0x0007ac,   1, 0x04, 0x00000000 },
-	{ 0x00162c,   1, 0x04, 0x00000003 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000324,   6, 0x04, 0x3f800000 },
-	{ 0x000750,   1, 0x04, 0x00000000 },
-	{ 0x000760,   1, 0x04, 0x39291909 },
-	{ 0x000764,   1, 0x04, 0x79695949 },
-	{ 0x000768,   1, 0x04, 0xb9a99989 },
-	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x000770,   1, 0x04, 0x30201000 },
-	{ 0x000774,   1, 0x04, 0x70605040 },
-	{ 0x000778,   1, 0x04, 0x00009080 },
-	{ 0x000780,   1, 0x04, 0x39291909 },
-	{ 0x000784,   1, 0x04, 0x79695949 },
-	{ 0x000788,   1, 0x04, 0xb9a99989 },
-	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x0007d0,   1, 0x04, 0x30201000 },
-	{ 0x0007d4,   1, 0x04, 0x70605040 },
-	{ 0x0007d8,   1, 0x04, 0x00009080 },
-	{ 0x00037c,   1, 0x04, 0x00000001 },
-	{ 0x000740,   2, 0x04, 0x00000000 },
-	{ 0x002600,   1, 0x04, 0x00000000 },
-	{ 0x001918,   1, 0x04, 0x00000000 },
-	{ 0x00191c,   1, 0x04, 0x00000900 },
-	{ 0x001920,   1, 0x04, 0x00000405 },
-	{ 0x001308,   1, 0x04, 0x00000001 },
-	{ 0x001924,   1, 0x04, 0x00000000 },
-	{ 0x0013ac,   1, 0x04, 0x00000000 },
-	{ 0x00192c,   1, 0x04, 0x00000001 },
-	{ 0x00193c,   1, 0x04, 0x00002c1c },
-	{ 0x000d7c,   1, 0x04, 0x00000000 },
-	{ 0x000f8c,   1, 0x04, 0x00000000 },
-	{ 0x0002c0,   1, 0x04, 0x00000001 },
-	{ 0x001510,   1, 0x04, 0x00000000 },
-	{ 0x001940,   1, 0x04, 0x00000000 },
-	{ 0x000ff4,   2, 0x04, 0x00000000 },
-	{ 0x00194c,   2, 0x04, 0x00000000 },
-	{ 0x001968,   1, 0x04, 0x00000000 },
-	{ 0x001590,   1, 0x04, 0x0000003f },
-	{ 0x0007e8,   4, 0x04, 0x00000000 },
-	{ 0x00196c,   1, 0x04, 0x00000011 },
-	{ 0x0002e4,   1, 0x04, 0x0000b001 },
-	{ 0x00036c,   2, 0x04, 0x00000000 },
-	{ 0x00197c,   1, 0x04, 0x00000000 },
-	{ 0x000fcc,   2, 0x04, 0x00000000 },
-	{ 0x0002d8,   1, 0x04, 0x00000040 },
-	{ 0x001980,   1, 0x04, 0x00000080 },
-	{ 0x001504,   1, 0x04, 0x00000080 },
-	{ 0x001984,   1, 0x04, 0x00000000 },
-	{ 0x000300,   1, 0x04, 0x00000001 },
-	{ 0x0013a8,   1, 0x04, 0x00000000 },
-	{ 0x0012ec,   1, 0x04, 0x00000000 },
-	{ 0x001310,   1, 0x04, 0x00000000 },
-	{ 0x001314,   1, 0x04, 0x00000001 },
-	{ 0x001380,   1, 0x04, 0x00000000 },
-	{ 0x001384,   4, 0x04, 0x00000001 },
-	{ 0x001394,   1, 0x04, 0x00000000 },
-	{ 0x00139c,   1, 0x04, 0x00000000 },
-	{ 0x001398,   1, 0x04, 0x00000000 },
-	{ 0x001594,   1, 0x04, 0x00000000 },
-	{ 0x001598,   4, 0x04, 0x00000001 },
-	{ 0x000f54,   3, 0x04, 0x00000000 },
-	{ 0x0019bc,   1, 0x04, 0x00000000 },
-	{ 0x000f9c,   2, 0x04, 0x00000000 },
-	{ 0x0012cc,   1, 0x04, 0x00000000 },
-	{ 0x0012e8,   1, 0x04, 0x00000000 },
-	{ 0x00130c,   1, 0x04, 0x00000001 },
-	{ 0x001360,   8, 0x04, 0x00000000 },
-	{ 0x00133c,   2, 0x04, 0x00000001 },
-	{ 0x001344,   1, 0x04, 0x00000002 },
-	{ 0x001348,   2, 0x04, 0x00000001 },
-	{ 0x001350,   1, 0x04, 0x00000002 },
-	{ 0x001358,   1, 0x04, 0x00000001 },
-	{ 0x0012e4,   1, 0x04, 0x00000000 },
-	{ 0x00131c,   4, 0x04, 0x00000000 },
-	{ 0x0019c0,   1, 0x04, 0x00000000 },
-	{ 0x001140,   1, 0x04, 0x00000000 },
-	{ 0x0019c4,   1, 0x04, 0x00000000 },
-	{ 0x0019c8,   1, 0x04, 0x00001500 },
-	{ 0x00135c,   1, 0x04, 0x00000000 },
-	{ 0x000f90,   1, 0x04, 0x00000000 },
-	{ 0x0019e0,   8, 0x04, 0x00000001 },
-	{ 0x0019cc,   1, 0x04, 0x00000001 },
-	{ 0x0015b8,   1, 0x04, 0x00000000 },
-	{ 0x001a00,   1, 0x04, 0x00001111 },
-	{ 0x001a04,   7, 0x04, 0x00000000 },
-	{ 0x000d6c,   2, 0x04, 0xffff0000 },
-	{ 0x0010f8,   1, 0x04, 0x00001010 },
-	{ 0x000d80,   5, 0x04, 0x00000000 },
-	{ 0x000da0,   1, 0x04, 0x00000000 },
-	{ 0x0007a4,   2, 0x04, 0x00000000 },
-	{ 0x001508,   1, 0x04, 0x80000000 },
-	{ 0x00150c,   1, 0x04, 0x40000000 },
-	{ 0x001668,   1, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000008 },
-	{ 0x000d9c,   1, 0x04, 0x00000001 },
-	{ 0x000374,   1, 0x04, 0x00000000 },
-	{ 0x000378,   1, 0x04, 0x00000020 },
-	{ 0x0007dc,   1, 0x04, 0x00000000 },
-	{ 0x00074c,   1, 0x04, 0x00000055 },
-	{ 0x001420,   1, 0x04, 0x00000003 },
-	{ 0x0017bc,   2, 0x04, 0x00000000 },
-	{ 0x0017c4,   1, 0x04, 0x00000001 },
-	{ 0x001008,   1, 0x04, 0x00000008 },
-	{ 0x00100c,   1, 0x04, 0x00000040 },
-	{ 0x001010,   1, 0x04, 0x0000012c },
-	{ 0x000d60,   1, 0x04, 0x00000040 },
-	{ 0x00075c,   1, 0x04, 0x00000003 },
-	{ 0x001018,   1, 0x04, 0x00000020 },
-	{ 0x00101c,   1, 0x04, 0x00000001 },
-	{ 0x001020,   1, 0x04, 0x00000020 },
-	{ 0x001024,   1, 0x04, 0x00000001 },
-	{ 0x001444,   3, 0x04, 0x00000000 },
-	{ 0x000360,   1, 0x04, 0x20164010 },
-	{ 0x000364,   1, 0x04, 0x00000020 },
-	{ 0x000368,   1, 0x04, 0x00000000 },
-	{ 0x000de4,   1, 0x04, 0x00000000 },
-	{ 0x000204,   1, 0x04, 0x00000006 },
-	{ 0x000208,   1, 0x04, 0x00000000 },
-	{ 0x0002cc,   2, 0x04, 0x003fffff },
-	{ 0x001220,   1, 0x04, 0x00000005 },
-	{ 0x000fdc,   1, 0x04, 0x00000000 },
-	{ 0x000f98,   1, 0x04, 0x00400008 },
-	{ 0x001284,   1, 0x04, 0x08000080 },
-	{ 0x001450,   1, 0x04, 0x00400008 },
-	{ 0x001454,   1, 0x04, 0x08000080 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nve4_grctx_pack_mthd[] = {
-	{ nve4_grctx_init_a097_0, 0xa097 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_fe_0[] = {
-	{ 0x404010,   5, 0x04, 0x00000000 },
-	{ 0x404024,   1, 0x04, 0x0000e000 },
-	{ 0x404028,   1, 0x04, 0x00000000 },
-	{ 0x4040a8,   8, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf800008f },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040e8,   1, 0x04, 0x00001000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404138,   1, 0x04, 0x20000040 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000055 },
-	{ 0x4041a0,   4, 0x04, 0x00000000 },
-	{ 0x404200,   4, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_memfmt_0[] = {
-	{ 0x404604,   1, 0x04, 0x00000014 },
-	{ 0x404608,   1, 0x04, 0x00000000 },
-	{ 0x40460c,   1, 0x04, 0x00003fff },
-	{ 0x404610,   1, 0x04, 0x00000100 },
-	{ 0x404618,   4, 0x04, 0x00000000 },
-	{ 0x40462c,   2, 0x04, 0x00000000 },
-	{ 0x404640,   1, 0x04, 0x00000000 },
-	{ 0x404654,   1, 0x04, 0x00000000 },
-	{ 0x404660,   1, 0x04, 0x00000000 },
-	{ 0x404678,   1, 0x04, 0x00000000 },
-	{ 0x40467c,   1, 0x04, 0x00000002 },
-	{ 0x404680,   8, 0x04, 0x00000000 },
-	{ 0x4046a0,   1, 0x04, 0x007f0080 },
-	{ 0x4046a4,   8, 0x04, 0x00000000 },
-	{ 0x4046c8,   3, 0x04, 0x00000000 },
-	{ 0x404700,   3, 0x04, 0x00000000 },
-	{ 0x404718,   7, 0x04, 0x00000000 },
-	{ 0x404734,   1, 0x04, 0x00000100 },
-	{ 0x404738,   2, 0x04, 0x00000000 },
-	{ 0x404744,   2, 0x04, 0x00000000 },
-	{ 0x404754,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_ds_0[] = {
-	{ 0x405800,   1, 0x04, 0x0f8000bf },
-	{ 0x405830,   1, 0x04, 0x02180648 },
-	{ 0x405834,   1, 0x04, 0x08000000 },
-	{ 0x405838,   1, 0x04, 0x00000000 },
-	{ 0x405854,   1, 0x04, 0x00000000 },
-	{ 0x405870,   4, 0x04, 0x00000001 },
-	{ 0x405a00,   2, 0x04, 0x00000000 },
-	{ 0x405a18,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_cwd_0[] = {
-	{ 0x405b00,   1, 0x04, 0x00000000 },
-	{ 0x405b10,   1, 0x04, 0x00001000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x004103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b4,   2, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x801a00f0 },
-	{ 0x4064c4,   1, 0x04, 0x0192ffff },
-	{ 0x4064c8,   1, 0x04, 0x01800600 },
-	{ 0x4064cc,   9, 0x04, 0x00000000 },
-	{ 0x4064fc,   1, 0x04, 0x0000022a },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_sked_0[] = {
-	{ 0x407040,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_scc_0[] = {
-	{ 0x408000,   2, 0x04, 0x00000000 },
-	{ 0x408008,   1, 0x04, 0x00000030 },
-	{ 0x40800c,   2, 0x04, 0x00000000 },
-	{ 0x408014,   1, 0x04, 0x00000069 },
-	{ 0x408018,   1, 0x04, 0xe100e100 },
-	{ 0x408064,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x02802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1043e005 },
-	{ 0x408840,   1, 0x04, 0x0000000b },
-	{ 0x408900,   1, 0x04, 0x3080b801 },
-	{ 0x408904,   1, 0x04, 0x62000001 },
-	{ 0x408908,   1, 0x04, 0x00c8102f },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nve4_grctx_init_fe_0 },
-	{ nvc0_grctx_init_pri_0 },
-	{ nve4_grctx_init_memfmt_0 },
-	{ nve4_grctx_init_ds_0 },
-	{ nve4_grctx_init_cwd_0 },
-	{ nve4_grctx_init_pd_0 },
-	{ nve4_grctx_init_sked_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nve4_grctx_init_scc_0 },
-	{ nve4_grctx_init_be_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006860a },
-	{ 0x418808,   3, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00000044 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100018 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_gpm_0[] = {
-	{ 0x418c08,   1, 0x04, 0x00000001 },
-	{ 0x418c10,   8, 0x04, 0x00000000 },
-	{ 0x418c40,   1, 0x04, 0xffffffff },
-	{ 0x418c6c,   1, 0x04, 0x00000001 },
-	{ 0x418c80,   1, 0x04, 0x20200004 },
-	{ 0x418c8c,   1, 0x04, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvd9_grctx_init_prop_0 },
-	{ nvd9_grctx_init_gpc_unk_1 },
-	{ nve4_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvd9_grctx_init_crstr_0 },
-	{ nve4_grctx_init_gpm_0 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000000f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000021 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x0000c000 },
-	{ 0x419a20,   1, 0x04, 0x00000800 },
-	{ 0x419a30,   1, 0x04, 0x00000001 },
-	{ 0x419ac4,   1, 0x04, 0x0037f440 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x0000000a },
-	{ 0x419c04,   1, 0x04, 0x80000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{ 0x419c24,   1, 0x04, 0x00084210 },
-	{ 0x419c28,   1, 0x04, 0x3efbefbe },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_l1c_0[] = {
-	{ 0x419ce8,   1, 0x04, 0x00000000 },
-	{ 0x419cf4,   1, 0x04, 0x00003203 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_sm_0[] = {
-	{ 0x419e04,   3, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00000402 },
-	{ 0x419e44,   1, 0x04, 0x0013eff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000007f },
-	{ 0x419e50,  19, 0x04, 0x00000000 },
-	{ 0x419eac,   1, 0x04, 0x00001f8f },
-	{ 0x419eb0,   1, 0x04, 0x00000d3f },
-	{ 0x419ec8,   1, 0x04, 0x0001304f },
-	{ 0x419f30,   8, 0x04, 0x00000000 },
-	{ 0x419f58,   1, 0x04, 0x00000000 },
-	{ 0x419f70,   1, 0x04, 0x00000000 },
-	{ 0x419f78,   1, 0x04, 0x0000000b },
-	{ 0x419f7c,   1, 0x04, 0x0000027c },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ nve4_grctx_init_tex_0 },
-	{ nve4_grctx_init_mpc_0 },
-	{ nve4_grctx_init_l1c_0 },
-	{ nve4_grctx_init_sm_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_pes_0[] = {
-	{ 0x41be24,   1, 0x04, 0x00000006 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_cbm_0[] = {
-	{ 0x41bec0,   1, 0x04, 0x12180000 },
-	{ 0x41bec4,   1, 0x04, 0x00037f7f },
-	{ 0x41bee4,   1, 0x04, 0x06480430 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_ppc[] = {
-	{ nve4_grctx_init_pes_0 },
-	{ nve4_grctx_init_cbm_0 },
-	{ nvd7_grctx_init_wwdx_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nve4_grctx_generate_bundle(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
-				    impl->bundle_size / 0x20);
-	const u32 token_limit = impl->bundle_token_limit;
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
-	mmio_refn(info, 0x408004, 0x00000000, s, b);
-	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
-	mmio_refn(info, 0x418808, 0x00000000, s, b);
-	mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
-	mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
-}
-
-void
-nve4_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
-	const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
-	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
-	const int s = 8;
-	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
-	mmio_refn(info, 0x40800c, 0x00000000, s, b);
-	mmio_wr32(info, 0x408010, 0x80000000);
-	mmio_refn(info, 0x419004, 0x00000000, s, b);
-	mmio_wr32(info, 0x419008, 0x00000000);
-	mmio_wr32(info, 0x4064cc, 0x80000000);
-}
-
-void
-nve4_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
-	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
-	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
-	nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
-	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
-	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
-	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
-}
-
-void
-nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
-{
-	u32 data[6] = {}, data2[2] = {};
-	u8  tpcnr[GPC_MAX];
-	u8  shift, ntpcv;
-	int gpc, tpc, i;
-
-	/* calculate first set of magics */
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
-	gpc = -1;
-	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpcnr[gpc]--;
-
-		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
-	}
-
-	for (; tpc < 32; tpc++)
-		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
-	/* and the second... */
-	shift = 0;
-	ntpcv = priv->tpc_total;
-	while (!(ntpcv & (1 << 4))) {
-		ntpcv <<= 1;
-		shift++;
-	}
-
-	data2[0]  = (ntpcv << 16);
-	data2[0] |= (shift << 21);
-	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-	for (i = 1; i < 7; i++)
-		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
-	/* GPC_BROADCAST */
-	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
-	/* GPC_BROADCAST.TP_BROADCAST */
-	nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr | data2[0]);
-	nv_wr32(priv, 0x41bfe4, data2[1]);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
-
-	/* UNK78xx */
-	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
-				 priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-}
-
-void
-nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
-	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-	int i;
-
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
-	nvc0_graph_mmio(priv, oclass->hub);
-	nvc0_graph_mmio(priv, oclass->gpc);
-	nvc0_graph_mmio(priv, oclass->zcull);
-	nvc0_graph_mmio(priv, oclass->tpc);
-	nvc0_graph_mmio(priv, oclass->ppc);
-
-	nv_wr32(priv, 0x404154, 0x00000000);
-
-	oclass->bundle(info);
-	oclass->pagepool(info);
-	oclass->attrib(info);
-	oclass->unkn(priv);
-
-	nvc0_grctx_generate_tpcid(priv);
-	nvc0_grctx_generate_r406028(priv);
-	nve4_grctx_generate_r418bb8(priv);
-	nvc0_grctx_generate_r406800(priv);
-
-	for (i = 0; i < 8; i++)
-		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
-	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
-	if (priv->gpc_nr == 1) {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
-	} else {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
-	}
-	nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
-
-	nvc0_graph_icmd(priv, oclass->icmd);
-	nv_wr32(priv, 0x404154, 0x00000400);
-	nvc0_graph_mthd(priv, oclass->mthd);
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
-	nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
-	nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
-}
-
-struct nouveau_oclass *
-nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xe4),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nve4_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nve4_grctx_pack_hub,
-	.gpc   = nve4_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nve4_grctx_pack_tpc,
-	.ppc   = nve4_grctx_pack_ppc,
-	.icmd  = nve4_grctx_pack_icmd,
-	.mthd  = nve4_grctx_pack_mthd,
-	.bundle = nve4_grctx_generate_bundle,
-	.bundle_size = 0x3000,
-	.bundle_min_gpm_fifo_depth = 0x180,
-	.bundle_token_limit = 0x600,
-	.pagepool = nve4_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x7ff,
-	.alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
deleted file mode 100644
index e9b0dcf..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_icmd_0[] = {
-	{ 0x001000,   1, 0x01, 0x00000004 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x0000a9,   1, 0x01, 0x0000ffff },
-	{ 0x000038,   1, 0x01, 0x0fac6881 },
-	{ 0x00003d,   1, 0x01, 0x00000001 },
-	{ 0x0000e8,   8, 0x01, 0x00000400 },
-	{ 0x000078,   8, 0x01, 0x00000300 },
-	{ 0x000050,   1, 0x01, 0x00000011 },
-	{ 0x000058,   8, 0x01, 0x00000008 },
-	{ 0x000208,   8, 0x01, 0x00000001 },
-	{ 0x000081,   1, 0x01, 0x00000001 },
-	{ 0x000085,   1, 0x01, 0x00000004 },
-	{ 0x000088,   1, 0x01, 0x00000400 },
-	{ 0x000090,   1, 0x01, 0x00000300 },
-	{ 0x000098,   1, 0x01, 0x00001001 },
-	{ 0x0000e3,   1, 0x01, 0x00000001 },
-	{ 0x0000da,   1, 0x01, 0x00000001 },
-	{ 0x0000f8,   1, 0x01, 0x00000003 },
-	{ 0x0000fa,   1, 0x01, 0x00000001 },
-	{ 0x00009f,   4, 0x01, 0x0000ffff },
-	{ 0x0000b1,   1, 0x01, 0x00000001 },
-	{ 0x0000ad,   1, 0x01, 0x0000013e },
-	{ 0x0000e1,   1, 0x01, 0x00000010 },
-	{ 0x000290,  16, 0x01, 0x00000000 },
-	{ 0x0003b0,  16, 0x01, 0x00000000 },
-	{ 0x0002a0,  16, 0x01, 0x00000000 },
-	{ 0x000420,  16, 0x01, 0x00000000 },
-	{ 0x0002b0,  16, 0x01, 0x00000000 },
-	{ 0x000430,  16, 0x01, 0x00000000 },
-	{ 0x0002c0,  16, 0x01, 0x00000000 },
-	{ 0x0004d0,  16, 0x01, 0x00000000 },
-	{ 0x000720,  16, 0x01, 0x00000000 },
-	{ 0x0008c0,  16, 0x01, 0x00000000 },
-	{ 0x000890,  16, 0x01, 0x00000000 },
-	{ 0x0008e0,  16, 0x01, 0x00000000 },
-	{ 0x0008a0,  16, 0x01, 0x00000000 },
-	{ 0x0008f0,  16, 0x01, 0x00000000 },
-	{ 0x00094c,   1, 0x01, 0x000000ff },
-	{ 0x00094d,   1, 0x01, 0xffffffff },
-	{ 0x00094e,   1, 0x01, 0x00000002 },
-	{ 0x0002ec,   1, 0x01, 0x00000001 },
-	{ 0x0002f2,   2, 0x01, 0x00000001 },
-	{ 0x0002f5,   1, 0x01, 0x00000001 },
-	{ 0x0002f7,   1, 0x01, 0x00000001 },
-	{ 0x000303,   1, 0x01, 0x00000001 },
-	{ 0x0002e6,   1, 0x01, 0x00000001 },
-	{ 0x000466,   1, 0x01, 0x00000052 },
-	{ 0x000301,   1, 0x01, 0x3f800000 },
-	{ 0x000304,   1, 0x01, 0x30201000 },
-	{ 0x000305,   1, 0x01, 0x70605040 },
-	{ 0x000306,   1, 0x01, 0xb8a89888 },
-	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
-	{ 0x00030a,   1, 0x01, 0x00ffff00 },
-	{ 0x00030b,   1, 0x01, 0x0000001a },
-	{ 0x00030c,   1, 0x01, 0x00000001 },
-	{ 0x000318,   1, 0x01, 0x00000001 },
-	{ 0x000340,   1, 0x01, 0x00000000 },
-	{ 0x000375,   1, 0x01, 0x00000001 },
-	{ 0x00037d,   1, 0x01, 0x00000006 },
-	{ 0x0003a0,   1, 0x01, 0x00000002 },
-	{ 0x0003aa,   1, 0x01, 0x00000001 },
-	{ 0x0003a9,   1, 0x01, 0x00000001 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000383,   1, 0x01, 0x00000011 },
-	{ 0x000360,   1, 0x01, 0x00000040 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x00037a,   1, 0x01, 0x00000012 },
-	{ 0x000619,   1, 0x01, 0x00000003 },
-	{ 0x000811,   1, 0x01, 0x00000003 },
-	{ 0x000812,   1, 0x01, 0x00000004 },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000815,   1, 0x01, 0x0000000b },
-	{ 0x000800,   6, 0x01, 0x00000001 },
-	{ 0x000632,   1, 0x01, 0x00000001 },
-	{ 0x000633,   1, 0x01, 0x00000002 },
-	{ 0x000634,   1, 0x01, 0x00000003 },
-	{ 0x000635,   1, 0x01, 0x00000004 },
-	{ 0x000654,   1, 0x01, 0x3f800000 },
-	{ 0x000657,   1, 0x01, 0x3f800000 },
-	{ 0x000655,   2, 0x01, 0x3f800000 },
-	{ 0x0006cd,   1, 0x01, 0x3f800000 },
-	{ 0x0007f5,   1, 0x01, 0x3f800000 },
-	{ 0x0007dc,   1, 0x01, 0x39291909 },
-	{ 0x0007dd,   1, 0x01, 0x79695949 },
-	{ 0x0007de,   1, 0x01, 0xb9a99989 },
-	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007e8,   1, 0x01, 0x00003210 },
-	{ 0x0007e9,   1, 0x01, 0x00007654 },
-	{ 0x0007ea,   1, 0x01, 0x00000098 },
-	{ 0x0007ec,   1, 0x01, 0x39291909 },
-	{ 0x0007ed,   1, 0x01, 0x79695949 },
-	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
-	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
-	{ 0x0007f0,   1, 0x01, 0x00003210 },
-	{ 0x0007f1,   1, 0x01, 0x00007654 },
-	{ 0x0007f2,   1, 0x01, 0x00000098 },
-	{ 0x0005a5,   1, 0x01, 0x00000001 },
-	{ 0x000980, 128, 0x01, 0x00000000 },
-	{ 0x000468,   1, 0x01, 0x00000004 },
-	{ 0x00046c,   1, 0x01, 0x00000001 },
-	{ 0x000470,  96, 0x01, 0x00000000 },
-	{ 0x000510,  16, 0x01, 0x3f800000 },
-	{ 0x000520,   1, 0x01, 0x000002b6 },
-	{ 0x000529,   1, 0x01, 0x00000001 },
-	{ 0x000530,  16, 0x01, 0xffff0000 },
-	{ 0x000585,   1, 0x01, 0x0000003f },
-	{ 0x000576,   1, 0x01, 0x00000003 },
-	{ 0x00057b,   1, 0x01, 0x00000059 },
-	{ 0x000586,   1, 0x01, 0x00000040 },
-	{ 0x000582,   2, 0x01, 0x00000080 },
-	{ 0x0005c2,   1, 0x01, 0x00000001 },
-	{ 0x000638,   2, 0x01, 0x00000001 },
-	{ 0x00063a,   1, 0x01, 0x00000002 },
-	{ 0x00063b,   2, 0x01, 0x00000001 },
-	{ 0x00063d,   1, 0x01, 0x00000002 },
-	{ 0x00063e,   1, 0x01, 0x00000001 },
-	{ 0x0008b8,   8, 0x01, 0x00000001 },
-	{ 0x000900,   8, 0x01, 0x00000001 },
-	{ 0x000908,   8, 0x01, 0x00000002 },
-	{ 0x000910,  16, 0x01, 0x00000001 },
-	{ 0x000920,   8, 0x01, 0x00000002 },
-	{ 0x000928,   8, 0x01, 0x00000001 },
-	{ 0x000662,   1, 0x01, 0x00000001 },
-	{ 0x000648,   9, 0x01, 0x00000001 },
-	{ 0x000658,   1, 0x01, 0x0000000f },
-	{ 0x0007ff,   1, 0x01, 0x0000000a },
-	{ 0x00066a,   1, 0x01, 0x40000000 },
-	{ 0x00066b,   1, 0x01, 0x10000000 },
-	{ 0x00066c,   2, 0x01, 0xffff0000 },
-	{ 0x0007af,   2, 0x01, 0x00000008 },
-	{ 0x0007f6,   1, 0x01, 0x00000001 },
-	{ 0x00080b,   1, 0x01, 0x00000002 },
-	{ 0x0006b2,   1, 0x01, 0x00000055 },
-	{ 0x0007ad,   1, 0x01, 0x00000003 },
-	{ 0x000937,   1, 0x01, 0x00000001 },
-	{ 0x000971,   1, 0x01, 0x00000008 },
-	{ 0x000972,   1, 0x01, 0x00000040 },
-	{ 0x000973,   1, 0x01, 0x0000012c },
-	{ 0x00097c,   1, 0x01, 0x00000040 },
-	{ 0x000979,   1, 0x01, 0x00000003 },
-	{ 0x000975,   1, 0x01, 0x00000020 },
-	{ 0x000976,   1, 0x01, 0x00000001 },
-	{ 0x000977,   1, 0x01, 0x00000020 },
-	{ 0x000978,   1, 0x01, 0x00000001 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x00095e,   1, 0x01, 0x20164010 },
-	{ 0x00095f,   1, 0x01, 0x00000020 },
-	{ 0x000a0d,   1, 0x01, 0x00000006 },
-	{ 0x00097d,   1, 0x01, 0x00000020 },
-	{ 0x000683,   1, 0x01, 0x00000006 },
-	{ 0x000685,   1, 0x01, 0x003fffff },
-	{ 0x000687,   1, 0x01, 0x003fffff },
-	{ 0x0006a0,   1, 0x01, 0x00000005 },
-	{ 0x000840,   1, 0x01, 0x00400008 },
-	{ 0x000841,   1, 0x01, 0x08000080 },
-	{ 0x000842,   1, 0x01, 0x00400008 },
-	{ 0x000843,   1, 0x01, 0x08000080 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ab,   1, 0x01, 0x00000002 },
-	{ 0x0006ac,   1, 0x01, 0x00000080 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x0006bb,   1, 0x01, 0x000000cf },
-	{ 0x0006ce,   1, 0x01, 0x2a712488 },
-	{ 0x000739,   1, 0x01, 0x4085c000 },
-	{ 0x00073a,   1, 0x01, 0x00000080 },
-	{ 0x000786,   1, 0x01, 0x80000100 },
-	{ 0x00073c,   1, 0x01, 0x00010100 },
-	{ 0x00073d,   1, 0x01, 0x02800000 },
-	{ 0x000787,   1, 0x01, 0x000000cf },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x000836,   1, 0x01, 0x00000001 },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c1b0,   8, 0x01, 0x0000000f },
-	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
-	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000002 },
-	{ 0x0006aa,   1, 0x01, 0x00000001 },
-	{ 0x0006ad,   2, 0x01, 0x00000100 },
-	{ 0x0006b1,   1, 0x01, 0x00000011 },
-	{ 0x00078c,   1, 0x01, 0x00000008 },
-	{ 0x000792,   1, 0x01, 0x00000001 },
-	{ 0x000794,   3, 0x01, 0x00000001 },
-	{ 0x000797,   1, 0x01, 0x000000cf },
-	{ 0x00079a,   1, 0x01, 0x00000002 },
-	{ 0x000833,   1, 0x01, 0x04444480 },
-	{ 0x0007a1,   1, 0x01, 0x00000001 },
-	{ 0x0007a3,   3, 0x01, 0x00000001 },
-	{ 0x000831,   1, 0x01, 0x00000004 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000008 },
-	{ 0x000039,   3, 0x01, 0x00000000 },
-	{ 0x000380,   1, 0x01, 0x00000001 },
-	{ 0x000366,   2, 0x01, 0x00000000 },
-	{ 0x000368,   1, 0x01, 0x00000fff },
-	{ 0x000370,   2, 0x01, 0x00000000 },
-	{ 0x000372,   1, 0x01, 0x000fffff },
-	{ 0x000813,   1, 0x01, 0x00000006 },
-	{ 0x000814,   1, 0x01, 0x00000008 },
-	{ 0x000957,   1, 0x01, 0x00000003 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x000a04,   1, 0x01, 0x000000ff },
-	{ 0x000a0b,   1, 0x01, 0x00000040 },
-	{ 0x00097f,   1, 0x01, 0x00000100 },
-	{ 0x000a02,   1, 0x01, 0x00000001 },
-	{ 0x000809,   1, 0x01, 0x00000007 },
-	{ 0x00c221,   1, 0x01, 0x00000040 },
-	{ 0x00c401,   1, 0x01, 0x00000001 },
-	{ 0x00c402,   1, 0x01, 0x00010001 },
-	{ 0x00c403,   2, 0x01, 0x00000001 },
-	{ 0x00c40e,   1, 0x01, 0x00000020 },
-	{ 0x00c500,   1, 0x01, 0x00000003 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{ 0x001000,   1, 0x01, 0x00000001 },
-	{ 0x000b07,   1, 0x01, 0x00000002 },
-	{ 0x000b08,   2, 0x01, 0x00000100 },
-	{ 0x000b0a,   1, 0x01, 0x00000001 },
-	{ 0x01e100,   1, 0x01, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_icmd[] = {
-	{ nvf0_grctx_init_icmd_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_a197_0[] = {
-	{ 0x000800,   8, 0x40, 0x00000000 },
-	{ 0x000804,   8, 0x40, 0x00000000 },
-	{ 0x000808,   8, 0x40, 0x00000400 },
-	{ 0x00080c,   8, 0x40, 0x00000300 },
-	{ 0x000810,   1, 0x04, 0x000000cf },
-	{ 0x000850,   7, 0x40, 0x00000000 },
-	{ 0x000814,   8, 0x40, 0x00000040 },
-	{ 0x000818,   8, 0x40, 0x00000001 },
-	{ 0x00081c,   8, 0x40, 0x00000000 },
-	{ 0x000820,   8, 0x40, 0x00000000 },
-	{ 0x001c00,  16, 0x10, 0x00000000 },
-	{ 0x001c04,  16, 0x10, 0x00000000 },
-	{ 0x001c08,  16, 0x10, 0x00000000 },
-	{ 0x001c0c,  16, 0x10, 0x00000000 },
-	{ 0x001d00,  16, 0x10, 0x00000000 },
-	{ 0x001d04,  16, 0x10, 0x00000000 },
-	{ 0x001d08,  16, 0x10, 0x00000000 },
-	{ 0x001d0c,  16, 0x10, 0x00000000 },
-	{ 0x001f00,  16, 0x08, 0x00000000 },
-	{ 0x001f04,  16, 0x08, 0x00000000 },
-	{ 0x001f80,  16, 0x08, 0x00000000 },
-	{ 0x001f84,  16, 0x08, 0x00000000 },
-	{ 0x002000,   1, 0x04, 0x00000000 },
-	{ 0x002040,   1, 0x04, 0x00000011 },
-	{ 0x002080,   1, 0x04, 0x00000020 },
-	{ 0x0020c0,   1, 0x04, 0x00000030 },
-	{ 0x002100,   1, 0x04, 0x00000040 },
-	{ 0x002140,   1, 0x04, 0x00000051 },
-	{ 0x00200c,   6, 0x40, 0x00000001 },
-	{ 0x002010,   1, 0x04, 0x00000000 },
-	{ 0x002050,   1, 0x04, 0x00000000 },
-	{ 0x002090,   1, 0x04, 0x00000001 },
-	{ 0x0020d0,   1, 0x04, 0x00000002 },
-	{ 0x002110,   1, 0x04, 0x00000003 },
-	{ 0x002150,   1, 0x04, 0x00000004 },
-	{ 0x000380,   4, 0x20, 0x00000000 },
-	{ 0x000384,   4, 0x20, 0x00000000 },
-	{ 0x000388,   4, 0x20, 0x00000000 },
-	{ 0x00038c,   4, 0x20, 0x00000000 },
-	{ 0x000700,   4, 0x10, 0x00000000 },
-	{ 0x000704,   4, 0x10, 0x00000000 },
-	{ 0x000708,   4, 0x10, 0x00000000 },
-	{ 0x002800, 128, 0x04, 0x00000000 },
-	{ 0x000a00,  16, 0x20, 0x00000000 },
-	{ 0x000a04,  16, 0x20, 0x00000000 },
-	{ 0x000a08,  16, 0x20, 0x00000000 },
-	{ 0x000a0c,  16, 0x20, 0x00000000 },
-	{ 0x000a10,  16, 0x20, 0x00000000 },
-	{ 0x000a14,  16, 0x20, 0x00000000 },
-	{ 0x000c00,  16, 0x10, 0x00000000 },
-	{ 0x000c04,  16, 0x10, 0x00000000 },
-	{ 0x000c08,  16, 0x10, 0x00000000 },
-	{ 0x000c0c,  16, 0x10, 0x3f800000 },
-	{ 0x000d00,   8, 0x08, 0xffff0000 },
-	{ 0x000d04,   8, 0x08, 0xffff0000 },
-	{ 0x000e00,  16, 0x10, 0x00000000 },
-	{ 0x000e04,  16, 0x10, 0xffff0000 },
-	{ 0x000e08,  16, 0x10, 0xffff0000 },
-	{ 0x000d40,   4, 0x08, 0x00000000 },
-	{ 0x000d44,   4, 0x08, 0x00000000 },
-	{ 0x001e00,   8, 0x20, 0x00000001 },
-	{ 0x001e04,   8, 0x20, 0x00000001 },
-	{ 0x001e08,   8, 0x20, 0x00000002 },
-	{ 0x001e0c,   8, 0x20, 0x00000001 },
-	{ 0x001e10,   8, 0x20, 0x00000001 },
-	{ 0x001e14,   8, 0x20, 0x00000002 },
-	{ 0x001e18,   8, 0x20, 0x00000001 },
-	{ 0x003400, 128, 0x04, 0x00000000 },
-	{ 0x00030c,   1, 0x04, 0x00000001 },
-	{ 0x001944,   1, 0x04, 0x00000000 },
-	{ 0x001514,   1, 0x04, 0x00000000 },
-	{ 0x000d68,   1, 0x04, 0x0000ffff },
-	{ 0x00121c,   1, 0x04, 0x0fac6881 },
-	{ 0x000fac,   1, 0x04, 0x00000001 },
-	{ 0x001538,   1, 0x04, 0x00000001 },
-	{ 0x000fe0,   2, 0x04, 0x00000000 },
-	{ 0x000fe8,   1, 0x04, 0x00000014 },
-	{ 0x000fec,   1, 0x04, 0x00000040 },
-	{ 0x000ff0,   1, 0x04, 0x00000000 },
-	{ 0x00179c,   1, 0x04, 0x00000000 },
-	{ 0x001228,   1, 0x04, 0x00000400 },
-	{ 0x00122c,   1, 0x04, 0x00000300 },
-	{ 0x001230,   1, 0x04, 0x00010001 },
-	{ 0x0007f8,   1, 0x04, 0x00000000 },
-	{ 0x0015b4,   1, 0x04, 0x00000001 },
-	{ 0x0015cc,   1, 0x04, 0x00000000 },
-	{ 0x001534,   1, 0x04, 0x00000000 },
-	{ 0x000fb0,   1, 0x04, 0x00000000 },
-	{ 0x0015d0,   1, 0x04, 0x00000000 },
-	{ 0x00153c,   1, 0x04, 0x00000000 },
-	{ 0x0016b4,   1, 0x04, 0x00000003 },
-	{ 0x000fbc,   4, 0x04, 0x0000ffff },
-	{ 0x000df8,   2, 0x04, 0x00000000 },
-	{ 0x001948,   1, 0x04, 0x00000000 },
-	{ 0x001970,   1, 0x04, 0x00000001 },
-	{ 0x00161c,   1, 0x04, 0x000009f0 },
-	{ 0x000dcc,   1, 0x04, 0x00000010 },
-	{ 0x00163c,   1, 0x04, 0x00000000 },
-	{ 0x0015e4,   1, 0x04, 0x00000000 },
-	{ 0x001160,  32, 0x04, 0x25e00040 },
-	{ 0x001880,  32, 0x04, 0x00000000 },
-	{ 0x000f84,   2, 0x04, 0x00000000 },
-	{ 0x0017c8,   2, 0x04, 0x00000000 },
-	{ 0x0017d0,   1, 0x04, 0x000000ff },
-	{ 0x0017d4,   1, 0x04, 0xffffffff },
-	{ 0x0017d8,   1, 0x04, 0x00000002 },
-	{ 0x0017dc,   1, 0x04, 0x00000000 },
-	{ 0x0015f4,   2, 0x04, 0x00000000 },
-	{ 0x001434,   2, 0x04, 0x00000000 },
-	{ 0x000d74,   1, 0x04, 0x00000000 },
-	{ 0x000dec,   1, 0x04, 0x00000001 },
-	{ 0x0013a4,   1, 0x04, 0x00000000 },
-	{ 0x001318,   1, 0x04, 0x00000001 },
-	{ 0x001644,   1, 0x04, 0x00000000 },
-	{ 0x000748,   1, 0x04, 0x00000000 },
-	{ 0x000de8,   1, 0x04, 0x00000000 },
-	{ 0x001648,   1, 0x04, 0x00000000 },
-	{ 0x0012a4,   1, 0x04, 0x00000000 },
-	{ 0x001120,   4, 0x04, 0x00000000 },
-	{ 0x001118,   1, 0x04, 0x00000000 },
-	{ 0x00164c,   1, 0x04, 0x00000000 },
-	{ 0x001658,   1, 0x04, 0x00000000 },
-	{ 0x001910,   1, 0x04, 0x00000290 },
-	{ 0x001518,   1, 0x04, 0x00000000 },
-	{ 0x00165c,   1, 0x04, 0x00000001 },
-	{ 0x001520,   1, 0x04, 0x00000000 },
-	{ 0x001604,   1, 0x04, 0x00000000 },
-	{ 0x001570,   1, 0x04, 0x00000000 },
-	{ 0x0013b0,   2, 0x04, 0x3f800000 },
-	{ 0x00020c,   1, 0x04, 0x00000000 },
-	{ 0x001670,   1, 0x04, 0x30201000 },
-	{ 0x001674,   1, 0x04, 0x70605040 },
-	{ 0x001678,   1, 0x04, 0xb8a89888 },
-	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-	{ 0x00166c,   1, 0x04, 0x00000000 },
-	{ 0x001680,   1, 0x04, 0x00ffff00 },
-	{ 0x0012d0,   1, 0x04, 0x00000003 },
-	{ 0x0012d4,   1, 0x04, 0x00000002 },
-	{ 0x001684,   2, 0x04, 0x00000000 },
-	{ 0x000dac,   2, 0x04, 0x00001b02 },
-	{ 0x000db4,   1, 0x04, 0x00000000 },
-	{ 0x00168c,   1, 0x04, 0x00000000 },
-	{ 0x0015bc,   1, 0x04, 0x00000000 },
-	{ 0x00156c,   1, 0x04, 0x00000000 },
-	{ 0x00187c,   1, 0x04, 0x00000000 },
-	{ 0x001110,   1, 0x04, 0x00000001 },
-	{ 0x000dc0,   3, 0x04, 0x00000000 },
-	{ 0x001234,   1, 0x04, 0x00000000 },
-	{ 0x001690,   1, 0x04, 0x00000000 },
-	{ 0x0012ac,   1, 0x04, 0x00000001 },
-	{ 0x0002c4,   1, 0x04, 0x00000000 },
-	{ 0x000790,   5, 0x04, 0x00000000 },
-	{ 0x00077c,   1, 0x04, 0x00000000 },
-	{ 0x001000,   1, 0x04, 0x00000010 },
-	{ 0x0010fc,   1, 0x04, 0x00000000 },
-	{ 0x001290,   1, 0x04, 0x00000000 },
-	{ 0x000218,   1, 0x04, 0x00000010 },
-	{ 0x0012d8,   1, 0x04, 0x00000000 },
-	{ 0x0012dc,   1, 0x04, 0x00000010 },
-	{ 0x000d94,   1, 0x04, 0x00000001 },
-	{ 0x00155c,   2, 0x04, 0x00000000 },
-	{ 0x001564,   1, 0x04, 0x00000fff },
-	{ 0x001574,   2, 0x04, 0x00000000 },
-	{ 0x00157c,   1, 0x04, 0x000fffff },
-	{ 0x001354,   1, 0x04, 0x00000000 },
-	{ 0x001610,   1, 0x04, 0x00000012 },
-	{ 0x001608,   2, 0x04, 0x00000000 },
-	{ 0x00260c,   1, 0x04, 0x00000000 },
-	{ 0x0007ac,   1, 0x04, 0x00000000 },
-	{ 0x00162c,   1, 0x04, 0x00000003 },
-	{ 0x000210,   1, 0x04, 0x00000000 },
-	{ 0x000320,   1, 0x04, 0x00000000 },
-	{ 0x000324,   6, 0x04, 0x3f800000 },
-	{ 0x000750,   1, 0x04, 0x00000000 },
-	{ 0x000760,   1, 0x04, 0x39291909 },
-	{ 0x000764,   1, 0x04, 0x79695949 },
-	{ 0x000768,   1, 0x04, 0xb9a99989 },
-	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x000770,   1, 0x04, 0x30201000 },
-	{ 0x000774,   1, 0x04, 0x70605040 },
-	{ 0x000778,   1, 0x04, 0x00009080 },
-	{ 0x000780,   1, 0x04, 0x39291909 },
-	{ 0x000784,   1, 0x04, 0x79695949 },
-	{ 0x000788,   1, 0x04, 0xb9a99989 },
-	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-	{ 0x0007d0,   1, 0x04, 0x30201000 },
-	{ 0x0007d4,   1, 0x04, 0x70605040 },
-	{ 0x0007d8,   1, 0x04, 0x00009080 },
-	{ 0x00037c,   1, 0x04, 0x00000001 },
-	{ 0x000740,   2, 0x04, 0x00000000 },
-	{ 0x002600,   1, 0x04, 0x00000000 },
-	{ 0x001918,   1, 0x04, 0x00000000 },
-	{ 0x00191c,   1, 0x04, 0x00000900 },
-	{ 0x001920,   1, 0x04, 0x00000405 },
-	{ 0x001308,   1, 0x04, 0x00000001 },
-	{ 0x001924,   1, 0x04, 0x00000000 },
-	{ 0x0013ac,   1, 0x04, 0x00000000 },
-	{ 0x00192c,   1, 0x04, 0x00000001 },
-	{ 0x00193c,   1, 0x04, 0x00002c1c },
-	{ 0x000d7c,   1, 0x04, 0x00000000 },
-	{ 0x000f8c,   1, 0x04, 0x00000000 },
-	{ 0x0002c0,   1, 0x04, 0x00000001 },
-	{ 0x001510,   1, 0x04, 0x00000000 },
-	{ 0x001940,   1, 0x04, 0x00000000 },
-	{ 0x000ff4,   2, 0x04, 0x00000000 },
-	{ 0x00194c,   2, 0x04, 0x00000000 },
-	{ 0x001968,   1, 0x04, 0x00000000 },
-	{ 0x001590,   1, 0x04, 0x0000003f },
-	{ 0x0007e8,   4, 0x04, 0x00000000 },
-	{ 0x00196c,   1, 0x04, 0x00000011 },
-	{ 0x0002e4,   1, 0x04, 0x0000b001 },
-	{ 0x00036c,   2, 0x04, 0x00000000 },
-	{ 0x00197c,   1, 0x04, 0x00000000 },
-	{ 0x000fcc,   2, 0x04, 0x00000000 },
-	{ 0x0002d8,   1, 0x04, 0x00000040 },
-	{ 0x001980,   1, 0x04, 0x00000080 },
-	{ 0x001504,   1, 0x04, 0x00000080 },
-	{ 0x001984,   1, 0x04, 0x00000000 },
-	{ 0x000300,   1, 0x04, 0x00000001 },
-	{ 0x0013a8,   1, 0x04, 0x00000000 },
-	{ 0x0012ec,   1, 0x04, 0x00000000 },
-	{ 0x001310,   1, 0x04, 0x00000000 },
-	{ 0x001314,   1, 0x04, 0x00000001 },
-	{ 0x001380,   1, 0x04, 0x00000000 },
-	{ 0x001384,   4, 0x04, 0x00000001 },
-	{ 0x001394,   1, 0x04, 0x00000000 },
-	{ 0x00139c,   1, 0x04, 0x00000000 },
-	{ 0x001398,   1, 0x04, 0x00000000 },
-	{ 0x001594,   1, 0x04, 0x00000000 },
-	{ 0x001598,   4, 0x04, 0x00000001 },
-	{ 0x000f54,   3, 0x04, 0x00000000 },
-	{ 0x0019bc,   1, 0x04, 0x00000000 },
-	{ 0x000f9c,   2, 0x04, 0x00000000 },
-	{ 0x0012cc,   1, 0x04, 0x00000000 },
-	{ 0x0012e8,   1, 0x04, 0x00000000 },
-	{ 0x00130c,   1, 0x04, 0x00000001 },
-	{ 0x001360,   8, 0x04, 0x00000000 },
-	{ 0x00133c,   2, 0x04, 0x00000001 },
-	{ 0x001344,   1, 0x04, 0x00000002 },
-	{ 0x001348,   2, 0x04, 0x00000001 },
-	{ 0x001350,   1, 0x04, 0x00000002 },
-	{ 0x001358,   1, 0x04, 0x00000001 },
-	{ 0x0012e4,   1, 0x04, 0x00000000 },
-	{ 0x00131c,   4, 0x04, 0x00000000 },
-	{ 0x0019c0,   1, 0x04, 0x00000000 },
-	{ 0x001140,   1, 0x04, 0x00000000 },
-	{ 0x0019c4,   1, 0x04, 0x00000000 },
-	{ 0x0019c8,   1, 0x04, 0x00001500 },
-	{ 0x00135c,   1, 0x04, 0x00000000 },
-	{ 0x000f90,   1, 0x04, 0x00000000 },
-	{ 0x0019e0,   8, 0x04, 0x00000001 },
-	{ 0x0019cc,   1, 0x04, 0x00000001 },
-	{ 0x0015b8,   1, 0x04, 0x00000000 },
-	{ 0x001a00,   1, 0x04, 0x00001111 },
-	{ 0x001a04,   7, 0x04, 0x00000000 },
-	{ 0x000d6c,   2, 0x04, 0xffff0000 },
-	{ 0x0010f8,   1, 0x04, 0x00001010 },
-	{ 0x000d80,   5, 0x04, 0x00000000 },
-	{ 0x000da0,   1, 0x04, 0x00000000 },
-	{ 0x0007a4,   2, 0x04, 0x00000000 },
-	{ 0x001508,   1, 0x04, 0x80000000 },
-	{ 0x00150c,   1, 0x04, 0x40000000 },
-	{ 0x001668,   1, 0x04, 0x00000000 },
-	{ 0x000318,   2, 0x04, 0x00000008 },
-	{ 0x000d9c,   1, 0x04, 0x00000001 },
-	{ 0x000ddc,   1, 0x04, 0x00000002 },
-	{ 0x000374,   1, 0x04, 0x00000000 },
-	{ 0x000378,   1, 0x04, 0x00000020 },
-	{ 0x0007dc,   1, 0x04, 0x00000000 },
-	{ 0x00074c,   1, 0x04, 0x00000055 },
-	{ 0x001420,   1, 0x04, 0x00000003 },
-	{ 0x0017bc,   2, 0x04, 0x00000000 },
-	{ 0x0017c4,   1, 0x04, 0x00000001 },
-	{ 0x001008,   1, 0x04, 0x00000008 },
-	{ 0x00100c,   1, 0x04, 0x00000040 },
-	{ 0x001010,   1, 0x04, 0x0000012c },
-	{ 0x000d60,   1, 0x04, 0x00000040 },
-	{ 0x00075c,   1, 0x04, 0x00000003 },
-	{ 0x001018,   1, 0x04, 0x00000020 },
-	{ 0x00101c,   1, 0x04, 0x00000001 },
-	{ 0x001020,   1, 0x04, 0x00000020 },
-	{ 0x001024,   1, 0x04, 0x00000001 },
-	{ 0x001444,   3, 0x04, 0x00000000 },
-	{ 0x000360,   1, 0x04, 0x20164010 },
-	{ 0x000364,   1, 0x04, 0x00000020 },
-	{ 0x000368,   1, 0x04, 0x00000000 },
-	{ 0x000de4,   1, 0x04, 0x00000000 },
-	{ 0x000204,   1, 0x04, 0x00000006 },
-	{ 0x000208,   1, 0x04, 0x00000000 },
-	{ 0x0002cc,   2, 0x04, 0x003fffff },
-	{ 0x001220,   1, 0x04, 0x00000005 },
-	{ 0x000fdc,   1, 0x04, 0x00000000 },
-	{ 0x000f98,   1, 0x04, 0x00400008 },
-	{ 0x001284,   1, 0x04, 0x08000080 },
-	{ 0x001450,   1, 0x04, 0x00400008 },
-	{ 0x001454,   1, 0x04, 0x08000080 },
-	{ 0x000214,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_mthd[] = {
-	{ nvf0_grctx_init_a197_0, 0xa197 },
-	{ nvc0_grctx_init_902d_0, 0x902d },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_fe_0[] = {
-	{ 0x404004,   8, 0x04, 0x00000000 },
-	{ 0x404024,   1, 0x04, 0x0000e000 },
-	{ 0x404028,   8, 0x04, 0x00000000 },
-	{ 0x4040a8,   8, 0x04, 0x00000000 },
-	{ 0x4040c8,   1, 0x04, 0xf800008f },
-	{ 0x4040d0,   6, 0x04, 0x00000000 },
-	{ 0x4040e8,   1, 0x04, 0x00001000 },
-	{ 0x4040f8,   1, 0x04, 0x00000000 },
-	{ 0x404100,  10, 0x04, 0x00000000 },
-	{ 0x404130,   2, 0x04, 0x00000000 },
-	{ 0x404138,   1, 0x04, 0x20000040 },
-	{ 0x404150,   1, 0x04, 0x0000002e },
-	{ 0x404154,   1, 0x04, 0x00000400 },
-	{ 0x404158,   1, 0x04, 0x00000200 },
-	{ 0x404164,   1, 0x04, 0x00000055 },
-	{ 0x40417c,   2, 0x04, 0x00000000 },
-	{ 0x4041a0,   4, 0x04, 0x00000000 },
-	{ 0x404200,   1, 0x04, 0x0000a197 },
-	{ 0x404204,   1, 0x04, 0x0000a1c0 },
-	{ 0x404208,   1, 0x04, 0x0000a140 },
-	{ 0x40420c,   1, 0x04, 0x0000902d },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_pri_0[] = {
-	{ 0x404404,  12, 0x04, 0x00000000 },
-	{ 0x404438,   1, 0x04, 0x00000000 },
-	{ 0x404460,   2, 0x04, 0x00000000 },
-	{ 0x404468,   1, 0x04, 0x00ffffff },
-	{ 0x40446c,   1, 0x04, 0x00000000 },
-	{ 0x404480,   1, 0x04, 0x00000001 },
-	{ 0x404498,   1, 0x04, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_cwd_0[] = {
-	{ 0x405b00,   1, 0x04, 0x00000000 },
-	{ 0x405b10,   1, 0x04, 0x00001000 },
-	{ 0x405b20,   1, 0x04, 0x04000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_pd_0[] = {
-	{ 0x406020,   1, 0x04, 0x034103c1 },
-	{ 0x406028,   4, 0x04, 0x00000001 },
-	{ 0x4064a8,   1, 0x04, 0x00000000 },
-	{ 0x4064ac,   1, 0x04, 0x00003fff },
-	{ 0x4064b0,   3, 0x04, 0x00000000 },
-	{ 0x4064c0,   1, 0x04, 0x802000f0 },
-	{ 0x4064c4,   1, 0x04, 0x0192ffff },
-	{ 0x4064c8,   1, 0x04, 0x018007c0 },
-	{ 0x4064cc,   9, 0x04, 0x00000000 },
-	{ 0x4064fc,   1, 0x04, 0x0000022a },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_be_0[] = {
-	{ 0x408800,   1, 0x04, 0x12802a3c },
-	{ 0x408804,   1, 0x04, 0x00000040 },
-	{ 0x408808,   1, 0x04, 0x1003e005 },
-	{ 0x408840,   1, 0x04, 0x0000000b },
-	{ 0x408900,   1, 0x04, 0x3080b801 },
-	{ 0x408904,   1, 0x04, 0x62000001 },
-	{ 0x408908,   1, 0x04, 0x00c8102f },
-	{ 0x408980,   1, 0x04, 0x0000011d },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_hub[] = {
-	{ nvc0_grctx_init_main_0 },
-	{ nvf0_grctx_init_fe_0 },
-	{ nvf0_grctx_init_pri_0 },
-	{ nve4_grctx_init_memfmt_0 },
-	{ nve4_grctx_init_ds_0 },
-	{ nvf0_grctx_init_cwd_0 },
-	{ nvf0_grctx_init_pd_0 },
-	{ nvc0_grctx_init_rstr2d_0 },
-	{ nve4_grctx_init_scc_0 },
-	{ nvf0_grctx_init_be_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_setup_0[] = {
-	{ 0x418800,   1, 0x04, 0x7006860a },
-	{ 0x418808,   1, 0x04, 0x00000000 },
-	{ 0x41880c,   1, 0x04, 0x00000030 },
-	{ 0x418810,   1, 0x04, 0x00000000 },
-	{ 0x418828,   1, 0x04, 0x00000044 },
-	{ 0x418830,   1, 0x04, 0x10000001 },
-	{ 0x4188d8,   1, 0x04, 0x00000008 },
-	{ 0x4188e0,   1, 0x04, 0x01000000 },
-	{ 0x4188e8,   5, 0x04, 0x00000000 },
-	{ 0x4188fc,   1, 0x04, 0x20100018 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_gpc_unk_2[] = {
-	{ 0x418d24,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_gpc[] = {
-	{ nvc0_grctx_init_gpc_unk_0 },
-	{ nvd9_grctx_init_prop_0 },
-	{ nvd9_grctx_init_gpc_unk_1 },
-	{ nvf0_grctx_init_setup_0 },
-	{ nvc0_grctx_init_zcull_0 },
-	{ nvd9_grctx_init_crstr_0 },
-	{ nve4_grctx_init_gpm_0 },
-	{ nvf0_grctx_init_gpc_unk_2 },
-	{ nvc0_grctx_init_gcc_0 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_tex_0[] = {
-	{ 0x419a00,   1, 0x04, 0x000000f0 },
-	{ 0x419a04,   1, 0x04, 0x00000001 },
-	{ 0x419a08,   1, 0x04, 0x00000021 },
-	{ 0x419a0c,   1, 0x04, 0x00020000 },
-	{ 0x419a10,   1, 0x04, 0x00000000 },
-	{ 0x419a14,   1, 0x04, 0x00000200 },
-	{ 0x419a1c,   1, 0x04, 0x0000c000 },
-	{ 0x419a20,   1, 0x04, 0x00020800 },
-	{ 0x419a30,   1, 0x04, 0x00000001 },
-	{ 0x419ac4,   1, 0x04, 0x0037f440 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_mpc_0[] = {
-	{ 0x419c00,   1, 0x04, 0x0000001a },
-	{ 0x419c04,   1, 0x04, 0x80000006 },
-	{ 0x419c08,   1, 0x04, 0x00000002 },
-	{ 0x419c20,   1, 0x04, 0x00000000 },
-	{ 0x419c24,   1, 0x04, 0x00084210 },
-	{ 0x419c28,   1, 0x04, 0x3efbefbe },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_l1c_0[] = {
-	{ 0x419ce8,   1, 0x04, 0x00000000 },
-	{ 0x419cf4,   1, 0x04, 0x00000203 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_sm_0[] = {
-	{ 0x419e04,   1, 0x04, 0x00000000 },
-	{ 0x419e08,   1, 0x04, 0x0000001d },
-	{ 0x419e0c,   1, 0x04, 0x00000000 },
-	{ 0x419e10,   1, 0x04, 0x00001c02 },
-	{ 0x419e44,   1, 0x04, 0x0013eff2 },
-	{ 0x419e48,   1, 0x04, 0x00000000 },
-	{ 0x419e4c,   1, 0x04, 0x0000007f },
-	{ 0x419e50,   2, 0x04, 0x00000000 },
-	{ 0x419e58,   1, 0x04, 0x00000001 },
-	{ 0x419e5c,   3, 0x04, 0x00000000 },
-	{ 0x419e68,   1, 0x04, 0x00000002 },
-	{ 0x419e6c,  12, 0x04, 0x00000000 },
-	{ 0x419eac,   1, 0x04, 0x00001f8f },
-	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
-	{ 0x419eb8,   1, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x0001304f },
-	{ 0x419f30,   4, 0x04, 0x00000000 },
-	{ 0x419f40,   1, 0x04, 0x00000018 },
-	{ 0x419f44,   3, 0x04, 0x00000000 },
-	{ 0x419f58,   1, 0x04, 0x00000000 },
-	{ 0x419f70,   1, 0x04, 0x00007300 },
-	{ 0x419f78,   1, 0x04, 0x000000eb },
-	{ 0x419f7c,   1, 0x04, 0x00000404 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvf0_grctx_pack_tpc[] = {
-	{ nvd7_grctx_init_pe_0 },
-	{ nvf0_grctx_init_tex_0 },
-	{ nvf0_grctx_init_mpc_0 },
-	{ nvf0_grctx_init_l1c_0 },
-	{ nvf0_grctx_init_sm_0 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_cbm_0[] = {
-	{ 0x41bec0,   1, 0x04, 0x10000000 },
-	{ 0x41bec4,   1, 0x04, 0x00037f7f },
-	{ 0x41bee4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_ppc[] = {
-	{ nve4_grctx_init_pes_0 },
-	{ nvf0_grctx_init_cbm_0 },
-	{ nvd7_grctx_init_wwdx_0 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
-	.base.handle = NV_ENGCTX(GR, 0xf0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-	.main  = nve4_grctx_generate_main,
-	.unkn  = nve4_grctx_generate_unkn,
-	.hub   = nvf0_grctx_pack_hub,
-	.gpc   = nvf0_grctx_pack_gpc,
-	.zcull = nvc0_grctx_pack_zcull,
-	.tpc   = nvf0_grctx_pack_tpc,
-	.ppc   = nvf0_grctx_pack_ppc,
-	.icmd  = nvf0_grctx_pack_icmd,
-	.mthd  = nvf0_grctx_pack_mthd,
-	.bundle = nve4_grctx_generate_bundle,
-	.bundle_size = 0x3000,
-	.bundle_min_gpm_fifo_depth = 0x180,
-	.bundle_token_limit = 0x7c0,
-	.pagepool = nve4_grctx_generate_pagepool,
-	.pagepool_size = 0x8000,
-	.attrib = nvd7_grctx_generate_attrib,
-	.attrib_nr_max = 0x324,
-	.attrib_nr = 0x218,
-	.alpha_nr_max = 0x7ff,
-	.alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
deleted file mode 100644
index e37d810..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
+++ /dev/null
@@ -1,335 +0,0 @@
-/* fuc microcode util functions for nvc0 PGRAPH
- *
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#ifdef INCLUDE_CODE
-// queue_put - add request to queue
-//
-// In : $r13 queue pointer
-//	$r14 command
-//	$r15 data
-//
-queue_put:
-	// make sure we have space..
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	xor $r8 8
-	cmpu b32 $r8 $r9
-	bra ne #queue_put_next
-		mov $r15 E_CMD_OVERFLOW
-		call(error)
-		ret
-
-	// store cmd/data on queue
-	queue_put_next:
-	and $r8 $r9 7
-	shl b32 $r8 3
-	add b32 $r8 $r13
-	add b32 $r8 8
-	st b32 D[$r8 + 0x0] $r14
-	st b32 D[$r8 + 0x4] $r15
-
-	// update PUT
-	add b32 $r9 1
-	and $r9 0xf
-	st b32 D[$r13 + 0x4] $r9
-	ret
-
-// queue_get - fetch request from queue
-//
-// In : $r13 queue pointer
-//
-// Out:	$p1  clear on success (data available)
-//	$r14 command
-// 	$r15 data
-//
-queue_get:
-	bset $flags $p1
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	cmpu b32 $r8 $r9
-	bra e #queue_get_done
-		// fetch first cmd/data pair
-		and $r9 $r8 7
-		shl b32 $r9 3
-		add b32 $r9 $r13
-		add b32 $r9 8
-		ld b32 $r14 D[$r9 + 0x0]
-		ld b32 $r15 D[$r9 + 0x4]
-
-		// update GET
-		add b32 $r8 1
-		and $r8 0xf
-		st b32 D[$r13 + 0x0] $r8
-		bclr $flags $p1
-queue_get_done:
-	ret
-
-// nv_rd32 - read 32-bit value from nv register
-//
-// In : $r14 register
-// Out: $r15 value
-//
-nv_rd32:
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
-	nv_rd32_wait:
-		nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
-		xbit $r12 $r12 31
-		bra ne #nv_rd32_wait
-	mov $r10 6			// DONE_MMIO_RD
-	call(wait_doneo)
-	nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0)
-	ret
-
-// nv_wr32 - write 32-bit value to nv register
-//
-// In : $r14 register
-//      $r15 value
-//
-nv_wr32:
-	nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15)
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	bset $r12 30			// MMIO_CTRL_WRITE
-	nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
-	nv_wr32_wait:
-		nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
-		xbit $r12 $r12 31
-		bra ne #nv_wr32_wait
-	ret
-
-// wait_donez - wait on FUC_DONE bit to become clear
-//
-// In : $r10 bit to wait on
-//
-wait_donez:
-	trace_set(T_WAIT);
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
-	wait_donez_ne:
-		nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
-		xbit $r8 $r8 $r10
-		bra ne #wait_donez_ne
-	trace_clr(T_WAIT)
-	ret
-
-// wait_doneo - wait on FUC_DONE bit to become set
-//
-// In : $r10 bit to wait on
-//
-wait_doneo:
-	trace_set(T_WAIT);
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
-	wait_doneo_e:
-		nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
-		xbit $r8 $r8 $r10
-		bra e #wait_doneo_e
-	trace_clr(T_WAIT)
-	ret
-
-// mmctx_size - determine size of a mmio list transfer
-//
-// In : $r14 mmio list head
-//      $r15 mmio list tail
-// Out: $r15 transfer size (in bytes)
-//
-mmctx_size:
-	clear b32 $r9
-	nv_mmctx_size_loop:
-		ld b32 $r8 D[$r14]
-		shr b32 $r8 26
-		add b32 $r8 1
-		shl b32 $r8 2
-		add b32 $r9 $r8
-		add b32 $r14 4
-		cmpu b32 $r14 $r15
-		bra ne #nv_mmctx_size_loop
-	mov b32 $r15 $r9
-	ret
-
-// mmctx_xfer - execute a list of mmio transfers
-//
-// In : $r10 flags
-//		bit 0: direction (0 = save, 1 = load)
-//		bit 1: set if first transfer
-//		bit 2: set if last transfer
-//	$r11 base
-//	$r12 mmio list head
-//	$r13 mmio list tail
-//	$r14 multi_stride
-//	$r15 multi_mask
-//
-mmctx_xfer:
-	trace_set(T_MMCTX)
-	clear b32 $r9
-	or $r11 $r11
-	bra e #mmctx_base_disabled
-		nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11)
-		bset $r9 0			// BASE_EN
-	mmctx_base_disabled:
-	or $r14 $r14
-	bra e #mmctx_multi_disabled
-		nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14)
-		nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15)
-		bset $r9 1			// MULTI_EN
-	mmctx_multi_disabled:
-
-	xbit $r11 $r10 0
-	shl b32 $r11 16			// DIR
-	bset $r11 12			// QLIMIT = 0x10
-	xbit $r14 $r10 1
-	shl b32 $r14 17
-	or $r11 $r14			// START_TRIGGER
-	nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
-
-	// loop over the mmio list, and send requests to the hw
-	mmctx_exec_loop:
-		// wait for space in mmctx queue
-		mmctx_wait_free:
-			nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
-			and $r14 0x1f
-			bra e #mmctx_wait_free
-
-		// queue up an entry
-		ld b32 $r14 D[$r12]
-		or $r14 $r9
-		nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14)
-		add b32 $r12 4
-		cmpu b32 $r12 $r13
-		bra ne #mmctx_exec_loop
-
-	xbit $r11 $r10 2
-	bra ne #mmctx_stop
-		// wait for queue to empty
-		mmctx_fini_wait:
-			nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
-			and $r11 0x1f
-			cmpu b32 $r11 0x10
-			bra ne #mmctx_fini_wait
-		mov $r10 5			// DONE_MMCTX
-		call(wait_donez)
-		bra #mmctx_done
-	mmctx_stop:
-		xbit $r11 $r10 0
-		shl b32 $r11 16			// DIR
-		bset $r11 12			// QLIMIT = 0x10
-		bset $r11 18			// STOP_TRIGGER
-		nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
-		mmctx_stop_wait:
-			// wait for STOP_TRIGGER to clear
-			nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
-			xbit $r11 $r11 18
-			bra ne #mmctx_stop_wait
-	mmctx_done:
-	trace_clr(T_MMCTX)
-	ret
-
-// Wait for DONE_STRAND
-//
-strand_wait:
-	push $r10
-	mov $r10 2
-	call(wait_donez)
-	pop $r10
-	ret
-
-// unknown - call before issuing strand commands
-//
-strand_pre:
-	mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
-	call(strand_wait)
-	ret
-
-// unknown - call after issuing strand commands
-//
-strand_post:
-	mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
-	call(strand_wait)
-	ret
-
-// Selects strand set?!
-//
-// In: $r14 id
-//
-strand_set:
-	mov $r12 0xf
-	nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12)
-	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
-	nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14)
-	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
-	call(strand_wait)
-	ret
-
-// Initialise strand context data
-//
-// In : $r15 context base
-// Out: $r15 context size (in bytes)
-//
-// Strandset(?) 3 hardcoded currently
-//
-strand_ctx_init:
-	trace_set(T_STRINIT)
-	call(strand_pre)
-	mov $r14 3
-	call(strand_set)
-
-	clear b32 $r12
-	nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12)
-	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
-	call(strand_wait)
-	sub b32 $r12 $r0 1
-	nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12)
-	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
-	call(strand_wait)
-	call(strand_post)
-
-	// read the size of each strand, poke the context offset of
-	// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
-	// about it later then.
-	nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00)
-	nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00)
-	shr b32 $r14 $r15 8
-	ctx_init_strand_loop:
-		iowr I[$r8 + 0x000] $r14	// STRAND_SAVE_SWBASE
-		iowr I[$r8 + 0x100] $r14	// STRAND_LOAD_SWBASE
-		iord $r10 I[$r8 + 0x200]	// STRAND_SIZE
-		shr b32 $r10 6
-		add b32 $r10 1
-		add b32 $r14 $r10
-		add b32 $r8 4
-		sub b32 $r9 1
-		bra ne #ctx_init_strand_loop
-
-	shl b32 $r14 8
-	sub b32 $r15 $r14 $r15
-	trace_clr(T_STRINIT)
-	ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
deleted file mode 100644
index 7445f12..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
+++ /dev/null
@@ -1,378 +0,0 @@
-/* fuc microcode for nvc0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
-
-#ifdef INCLUDE_DATA
-gpc_mmio_list_head:	.b32 #mmio_list_base
-gpc_mmio_list_tail:
-tpc_mmio_list_head:	.b32 #mmio_list_base
-tpc_mmio_list_tail:
-unk_mmio_list_head:	.b32 #mmio_list_base
-unk_mmio_list_tail:	.b32 #mmio_list_base
-
-gpc_id:			.b32 0
-
-tpc_count:		.b32 0
-tpc_mask:		.b32 0
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
-unk_count:		.b32 0
-unk_mask:		.b32 0
-#endif
-
-cmd_queue:		queue_init
-
-mmio_list_base:
-#endif
-
-#ifdef INCLUDE_CODE
-// reports an exception to the host
-//
-// In: $r15 error code (see os.h)
-//
-error:
-	push $r14
-	nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
-	mov $r15 1
-	nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
-	pop $r14
-	ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[1]: context base
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: GPC context size
-//
-init:
-	clear b32 $r0
-
-	// setup stack
-	nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
-	extr $r1 $r1 9:17
-	shl b32 $r1 8
-	mov $sp $r1
-
-	// enable fifo access
-	mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
-
-	// enable fifo interrupt
-	mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
-
-	// enable interrupts
-	bset $flags ie0
-
-	// figure out which GPC we are, and how many TPCs we have
-	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
-	mov $r3 1
-	and $r2 0x1f
-	shl b32 $r3 $r2
-	sub b32 $r3 1
-	st b32 D[$r0 + #tpc_count] $r2
-	st b32 D[$r0 + #tpc_mask] $r3
-	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
-	st b32 D[$r0 + #gpc_id] $r2
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
-	// figure out which, and how many, UNKs are actually present
-	imm32($r14, 0x500c30)
-	clear b32 $r2
-	clear b32 $r3
-	clear b32 $r4
-	init_unk_loop:
-		call(nv_rd32)
-		cmp b32 $r15 0
-		bra z #init_unk_next
-			mov $r15 1
-			shl b32 $r15 $r2
-			or $r4 $r15
-			add b32 $r3 1
-		init_unk_next:
-		add b32 $r2 1
-		add b32 $r14 4
-		cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
-		bra ne #init_unk_loop
-	init_unk_done:
-	st b32 D[$r0 + #unk_count] $r3
-	st b32 D[$r0 + #unk_mask] $r4
-#endif
-
-	// initialise context base, and size tracking
-	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
-	clear b32 $r3		// track GPC context size here
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't currently ever change
-	shr b32 $r5 $r2 8
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
-
-	// calculate GPC mmio context size
-	ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
-	call(mmctx_size)
-	add b32 $r2 $r15
-	add b32 $r3 $r15
-
-	// calculate per-TPC mmio context size
-	ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
-	call(mmctx_size)
-	ld b32 $r14 D[$r0 + #tpc_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
-	// calculate per-UNK mmio context size
-	ld b32 $r14 D[$r0 + #unk_mmio_list_head]
-	ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
-	call(mmctx_size)
-	ld b32 $r14 D[$r0 + #unk_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-#endif
-
-	// round up base/size to 256 byte boundary (for strand SWBASE)
-	shr b32 $r3 2
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
-	shr b32 $r2 8
-	shr b32 $r3 6
-	add b32 $r2 1
-	add b32 $r3 1
-	shl b32 $r2 8
-	shl b32 $r3 8
-
-	// calculate size of strand context data
-	mov b32 $r15 $r2
-	call(strand_ctx_init)
-	add b32 $r3 $r15
-
-	// save context size, and tell HUB we're done
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
-	clear b32 $r2
-	bset $r2 31
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call(queue_get)
-	bra $p1 #main
-
-	// 0x0000-0x0003 are all context transfers
-	cmpu b32 $r14 0x04
-	bra nc #main_not_ctx_xfer
-		// fetch $flags and mask off $p1/$p2
-		mov $r1 $flags
-		mov $r2 0x0006
-		not b32 $r2
-		and $r1 $r2
-		// set $p1/$p2 according to transfer type
-		shl b32 $r14 1
-		or $r1 $r14
-		mov $flags $r1
-		// transfer context data
-		call(ctx_xfer)
-		bra #main
-
-	main_not_ctx_xfer:
-	shl b32 $r15 $r14 16
-	or $r15 E_BAD_COMMAND
-	call(error)
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-	clear b32 $r0
-
-	// incoming fifo command?
-	nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
-	and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r13 #cmd_queue
-		nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
-		nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
-		call(queue_put)
-		mov $r14 1
-		nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
-
-	// ack, and wake up main()
-	ih_no_fifo:
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
-	mov $r15 1
-	ld b32 $r14 D[$r0 + #gpc_id]
-	shl b32 $r15 $r14
-	nv_wr32(0x409418, $r15)	// 0x409418 - HUB_BAR_SET
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
-	mov $r14 8
-	ctx_redswitch_delay:
-		sub b32 $r14 1
-		bra ne #ctx_redswitch_delay
-	or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
-	or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
-	ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// set context base address
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
-	bra not $p1 #ctx_xfer_not_load
-		call(ctx_redswitch)
-	ctx_xfer_not_load:
-
-	// strands
-	call(strand_pre)
-	clear b32 $r2
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
-	xbit $r2 $flags $p1	// SAVE/LOAD
-	add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
-	nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 2		// first
-	imm32($r11,0x500000)
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
-	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
-	mov $r14 0		// not multi
-	call(mmctx_xfer)
-
-	// per-TPC mmio context
-	xbit $r10 $flags $p1	// direction
-#if !NV_PGRAPH_GPCX_UNK__SIZE
-	or $r10 4		// last
-#endif
-	imm32($r11, 0x504000)
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
-	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #tpc_mask]
-	mov $r14 0x800		// stride = 0x800
-	call(mmctx_xfer)
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
-	// per-UNK mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 4		// last
-	imm32($r11, 0x503000)
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_UNK0
-	ld b32 $r12 D[$r0 + #unk_mmio_list_head]
-	ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #unk_mask]
-	mov $r14 0x200		// stride = 0x200
-	call(mmctx_xfer)
-#endif
-
-	// wait for strands to finish
-	call(strand_wait)
-
-	// if load, or a save without a load following, do some
-	// unknown stuff that's done after finishing a block of
-	// strand commands
-	bra $p1 #ctx_xfer_post
-	bra not $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		call(strand_post)
-
-	// mark completion in HUB's barrier
-	ctx_xfer_done:
-	call(hub_barrier_done)
-	ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5
deleted file mode 100644
index bd30262..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
-
-#define CHIPSET GK208
-#include "macros.fuc"
-
-.section #nv108_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nv108_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
deleted file mode 100644
index 3192270..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
+++ /dev/null
@@ -1,473 +0,0 @@
-uint32_t nv108_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
-	0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
-	0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
-	0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
-	0x0000006c,
-/* 0x0010: gpc_id */
-	0x00000000,
-/* 0x0014: tpc_count */
-	0x00000000,
-/* 0x0018: tpc_mask */
-	0x00000000,
-/* 0x001c: unk_count */
-	0x00000000,
-/* 0x0020: unk_mask */
-	0x00000000,
-/* 0x0024: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nv108_grgpc_code[] = {
-	0x03140ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0xf489a408,
-	0x020f0b1b,
-	0x0002f87e,
-/* 0x001a: queue_put_next */
-	0x98c400f8,
-	0x0384b607,
-	0xb6008dbb,
-	0x8eb50880,
-	0x018fb500,
-	0xf00190b6,
-	0xd9b50f94,
-/* 0x0037: queue_get */
-	0xf400f801,
-	0xd8980131,
-	0x01d99800,
-	0x0bf489a4,
-	0x0789c421,
-	0xbb0394b6,
-	0x90b6009d,
-	0x009e9808,
-	0xb6019f98,
-	0x84f00180,
-	0x00d8b50f,
-/* 0x0063: queue_get_done */
-	0xf80132f4,
-/* 0x0065: nv_rd32 */
-	0xf0ecb200,
-	0x00801fc9,
-	0x0cf601ca,
-/* 0x0073: nv_rd32_wait */
-	0x8c04bd00,
-	0xcf01ca00,
-	0xccc800cc,
-	0xf61bf41f,
-	0xec7e060a,
-	0x008f0000,
-	0xffcf01cb,
-/* 0x008f: nv_wr32 */
-	0x8000f800,
-	0xf601cc00,
-	0x04bd000f,
-	0xc9f0ecb2,
-	0x1ec9f01f,
-	0x01ca0080,
-	0xbd000cf6,
-/* 0x00a9: nv_wr32_wait */
-	0xca008c04,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f61b,
-/* 0x00b8: wait_donez */
-	0x99f094bd,
-	0x37008000,
-	0x0009f602,
-	0x008004bd,
-	0x0af60206,
-/* 0x00cf: wait_donez_ne */
-	0x8804bd00,
-	0xcf010000,
-	0x8aff0088,
-	0xf61bf488,
-	0x99f094bd,
-	0x17008000,
-	0x0009f602,
-	0x00f804bd,
-/* 0x00ec: wait_doneo */
-	0x99f094bd,
-	0x37008000,
-	0x0009f602,
-	0x008004bd,
-	0x0af60206,
-/* 0x0103: wait_doneo_e */
-	0x8804bd00,
-	0xcf010000,
-	0x8aff0088,
-	0xf60bf488,
-	0x99f094bd,
-	0x17008000,
-	0x0009f602,
-	0x00f804bd,
-/* 0x0120: mmctx_size */
-/* 0x0122: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0x1bf4efa4,
-	0xf89fb2ec,
-/* 0x013d: mmctx_xfer */
-	0xf094bd00,
-	0x00800199,
-	0x09f60237,
-	0xbd04bd00,
-	0x05bbfd94,
-	0x800f0bf4,
-	0xf601c400,
-	0x04bd000b,
-/* 0x015f: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0xc6008018,
-	0x000ef601,
-	0x008004bd,
-	0x0ff601c7,
-	0xf004bd00,
-/* 0x017a: mmctx_multi_disabled */
-	0xabc80199,
-	0x10b4b600,
-	0xc80cb9f0,
-	0xe4b601ae,
-	0x05befd11,
-	0x01c50080,
-	0xbd000bf6,
-/* 0x0195: mmctx_exec_loop */
-/* 0x0195: mmctx_wait_free */
-	0xc5008e04,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f60b,
-	0x05e9fd00,
-	0x01c80080,
-	0xbd000ef6,
-	0x04c0b604,
-	0x1bf4cda4,
-	0x02abc8df,
-/* 0x01bf: mmctx_fini_wait */
-	0x8b1c1bf4,
-	0xcf01c500,
-	0xb4f000bb,
-	0x10b4b01f,
-	0x0af31bf4,
-	0x00b87e05,
-	0x250ef400,
-/* 0x01d8: mmctx_stop */
-	0xb600abc8,
-	0xb9f010b4,
-	0x12b9f00c,
-	0x01c50080,
-	0xbd000bf6,
-/* 0x01ed: mmctx_stop_wait */
-	0xc5008b04,
-	0x00bbcf01,
-	0xf412bbc8,
-/* 0x01fa: mmctx_done */
-	0x94bdf61b,
-	0x800199f0,
-	0xf6021700,
-	0x04bd0009,
-/* 0x020a: strand_wait */
-	0xa0f900f8,
-	0xb87e020a,
-	0xa0fc0000,
-/* 0x0216: strand_pre */
-	0x0c0900f8,
-	0x024afc80,
-	0xbd0009f6,
-	0x020a7e04,
-/* 0x0227: strand_post */
-	0x0900f800,
-	0x4afc800d,
-	0x0009f602,
-	0x0a7e04bd,
-	0x00f80002,
-/* 0x0238: strand_set */
-	0xfc800f0c,
-	0x0cf6024f,
-	0x0c04bd00,
-	0x4afc800b,
-	0x000cf602,
-	0xfc8004bd,
-	0x0ef6024f,
-	0x0c04bd00,
-	0x4afc800a,
-	0x000cf602,
-	0x0a7e04bd,
-	0x00f80002,
-/* 0x0268: strand_ctx_init */
-	0x99f094bd,
-	0x37008003,
-	0x0009f602,
-	0x167e04bd,
-	0x030e0002,
-	0x0002387e,
-	0xfc80c4bd,
-	0x0cf60247,
-	0x0c04bd00,
-	0x4afc8001,
-	0x000cf602,
-	0x0a7e04bd,
-	0x0c920002,
-	0x46fc8001,
-	0x000cf602,
-	0x020c04bd,
-	0x024afc80,
-	0xbd000cf6,
-	0x020a7e04,
-	0x02277e00,
-	0x42008800,
-	0x20008902,
-	0x0099cf02,
-/* 0x02c7: ctx_init_strand_loop */
-	0xf608fe95,
-	0x8ef6008e,
-	0x808acf40,
-	0xb606a5b6,
-	0xeabb01a0,
-	0x0480b600,
-	0xf40192b6,
-	0xe4b6e81b,
-	0xf2efbc08,
-	0x99f094bd,
-	0x17008003,
-	0x0009f602,
-	0x00f804bd,
-/* 0x02f8: error */
-	0xffb2e0f9,
-	0x4098148e,
-	0x00008f7e,
-	0xffb2010f,
-	0x409c1c8e,
-	0x00008f7e,
-	0x00f8e0fc,
-/* 0x0314: init */
-	0x004104bd,
-	0x0011cf42,
-	0x010911e7,
-	0xfe0814b6,
-	0x02020014,
-	0xf6120040,
-	0x04bd0002,
-	0xfe047241,
-	0x00400010,
-	0x0000f607,
-	0x040204bd,
-	0xf6040040,
-	0x04bd0002,
-	0x821031f4,
-	0xcf018200,
-	0x01030022,
-	0xbb1f24f0,
-	0x32b60432,
-	0x0502b501,
-	0x820603b5,
-	0xcf018600,
-	0x02b50022,
-	0x0c308e04,
-	0xbd24bd50,
-/* 0x0377: init_unk_loop */
-	0x7e44bd34,
-	0xb0000065,
-	0x0bf400f6,
-	0xbb010f0e,
-	0x4ffd04f2,
-	0x0130b605,
-/* 0x038c: init_unk_next */
-	0xb60120b6,
-	0x26b004e0,
-	0xe21bf401,
-/* 0x0398: init_unk_done */
-	0xb50703b5,
-	0x00820804,
-	0x22cf0201,
-	0x9534bd00,
-	0x00800825,
-	0x05f601c0,
-	0x8004bd00,
-	0xf601c100,
-	0x04bd0005,
-	0x98000e98,
-	0x207e010f,
-	0x2fbb0001,
-	0x003fbb00,
-	0x98010e98,
-	0x207e020f,
-	0x0e980001,
-	0x00effd05,
-	0xbb002ebb,
-	0x0e98003e,
-	0x030f9802,
-	0x0001207e,
-	0xfd070e98,
-	0x2ebb00ef,
-	0x003ebb00,
-	0x800235b6,
-	0xf601d300,
-	0x04bd0003,
-	0xb60825b6,
-	0x20b60635,
-	0x0130b601,
-	0xb60824b6,
-	0x2fb20834,
-	0x0002687e,
-	0x80003fbb,
-	0xf6020100,
-	0x04bd0003,
-	0x29f024bd,
-	0x3000801f,
-	0x0002f602,
-/* 0x0436: main */
-	0x31f404bd,
-	0x0028f400,
-	0x377e240d,
-	0x01f40000,
-	0x04e4b0f4,
-	0xfe1d18f4,
-	0x06020181,
-	0x12fd20bd,
-	0x01e4b604,
-	0xfe051efd,
-	0x097e0018,
-	0x0ef40005,
-/* 0x0465: main_not_ctx_xfer */
-	0x10ef94d4,
-	0x7e01f5f0,
-	0xf40002f8,
-/* 0x0472: ih */
-	0x80f9c70e,
-	0xf90188fe,
-	0xf990f980,
-	0xf9b0f9a0,
-	0xf9e0f9d0,
-	0x4a04bdf0,
-	0xaacf0200,
-	0x04abc400,
-	0x0d1f0bf4,
-	0x1a004e24,
-	0x4f00eecf,
-	0xffcf1900,
-	0x00047e00,
-	0x40010e00,
-	0x0ef61d00,
-/* 0x04af: ih_no_fifo */
-	0x4004bd00,
-	0x0af60100,
-	0xfc04bd00,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x04cf: hub_barrier_done */
-	0x0f01f800,
-	0x040e9801,
-	0xb204febb,
-	0x94188eff,
-	0x008f7e40,
-/* 0x04e3: ctx_redswitch */
-	0x0f00f800,
-	0x85008020,
-	0x000ff601,
-	0x080e04bd,
-/* 0x04f0: ctx_redswitch_delay */
-	0xf401e2b6,
-	0xf5f1fd1b,
-	0xf5f10800,
-	0x00800200,
-	0x0ff60185,
-	0xf804bd00,
-/* 0x0509: ctx_xfer */
-	0x81008000,
-	0x000ff602,
-	0x11f404bd,
-	0x04e37e07,
-/* 0x0519: ctx_xfer_not_load */
-	0x02167e00,
-	0x8024bd00,
-	0xf60247fc,
-	0x04bd0002,
-	0xb6012cf0,
-	0xfc800320,
-	0x02f6024a,
-	0xf004bd00,
-	0xa5f001ac,
-	0x00008b02,
-	0x040c9850,
-	0xbb0fc4b6,
-	0x0c9800bc,
-	0x010d9800,
-	0x3d7e000e,
-	0xacf00001,
-	0x40008b01,
-	0x040c9850,
-	0xbb0fc4b6,
-	0x0c9800bc,
-	0x020d9801,
-	0x4e060f98,
-	0x3d7e0800,
-	0xacf00001,
-	0x04a5f001,
-	0x5030008b,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x020c9800,
-	0x98030d98,
-	0x004e080f,
-	0x013d7e02,
-	0x020a7e00,
-	0x0601f400,
-/* 0x05a3: ctx_xfer_post */
-	0x7e0712f4,
-/* 0x05a7: ctx_xfer_done */
-	0x7e000227,
-	0xf80004cf,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
deleted file mode 100644
index 5ae06a2..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000000
-
-#define CHIPSET GF100
-#include "macros.fuc"
-
-.section #nvc0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvc0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
deleted file mode 100644
index 325cc7b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
+++ /dev/null
@@ -1,530 +0,0 @@
-uint32_t nvc0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
-	0x00000064,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
-	0x00000064,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
-	0x00000064,
-/* 0x000c: unk_mmio_list_tail */
-	0x00000064,
-/* 0x0010: gpc_id */
-	0x00000000,
-/* 0x0014: tpc_count */
-	0x00000000,
-/* 0x0018: tpc_mask */
-	0x00000000,
-/* 0x001c: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nvc0_grgpc_code[] = {
-	0x03a10ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0xe0f900f8,
-	0xf102ffb9,
-	0xf09814e7,
-	0x21f440e3,
-	0x01f7f09d,
-	0xf102ffb9,
-	0xf09c1ce7,
-	0x21f440e3,
-	0xf8e0fc9d,
-/* 0x03a1: init */
-	0xf104bd00,
-	0xf0420017,
-	0x11cf0013,
-	0x0911e700,
-	0x0814b601,
-	0xf00014fe,
-	0x07f10227,
-	0x03f01200,
-	0x0002d000,
-	0x17f104bd,
-	0x10fe04e6,
-	0x0007f100,
-	0x0003f007,
-	0xbd0000d0,
-	0x0427f004,
-	0x040007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0xf11031f4,
-	0xf0820027,
-	0x22cf0123,
-	0x0137f000,
-	0xbb1f24f0,
-	0x32b60432,
-	0x05028001,
-	0xf1060380,
-	0xf0860027,
-	0x22cf0123,
-	0x04028000,
-	0x010027f1,
-	0xcf0223f0,
-	0x34bd0022,
-	0xf1082595,
-	0xf0c00007,
-	0x05d00103,
-	0xf104bd00,
-	0xf0c10007,
-	0x05d00103,
-	0x9804bd00,
-	0x0f98000e,
-	0x5021f501,
-	0x002fbb01,
-	0x98003fbb,
-	0x0f98010e,
-	0x5021f502,
-	0x050e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x0235b600,
-	0xd30007f1,
-	0xd00103f0,
-	0x04bd0003,
-	0xb60825b6,
-	0x20b60635,
-	0x0130b601,
-	0xb60824b6,
-	0x2fb90834,
-	0xd321f502,
-	0x003fbb02,
-	0x010007f1,
-	0xd00203f0,
-	0x04bd0003,
-	0x29f024bd,
-	0x0007f11f,
-	0x0203f008,
-	0xbd0002d0,
-/* 0x04a9: main */
-	0x0031f404,
-	0xf00028f4,
-	0x21f41cd7,
-	0xf401f439,
-	0xf404e4b0,
-	0x81fe1e18,
-	0x0627f001,
-	0x12fd20bd,
-	0x01e4b604,
-	0xfe051efd,
-	0x21f50018,
-	0x0ef4059e,
-/* 0x04d9: main_not_ctx_xfer */
-	0x10ef94d3,
-	0xf501f5f0,
-	0xf4037e21,
-/* 0x04e6: ih */
-	0x80f9c60e,
-	0xf90188fe,
-	0xf990f980,
-	0xf9b0f9a0,
-	0xf9e0f9d0,
-	0xf104bdf0,
-	0xf00200a7,
-	0xaacf00a3,
-	0x04abc400,
-	0xf02c0bf4,
-	0xe7f11cd7,
-	0xe3f01a00,
-	0x00eecf00,
-	0x1900f7f1,
-	0xcf00f3f0,
-	0x21f400ff,
-	0x01e7f004,
-	0x1d0007f1,
-	0xd00003f0,
-	0x04bd000e,
-/* 0x0534: ih_no_fifo */
-	0x010007f1,
-	0xd00003f0,
-	0x04bd000a,
-	0xe0fcf0fc,
-	0xb0fcd0fc,
-	0x90fca0fc,
-	0x88fe80fc,
-	0xf480fc00,
-	0x01f80032,
-/* 0x0558: hub_barrier_done */
-	0x9801f7f0,
-	0xfebb040e,
-	0x02ffb904,
-	0x9418e7f1,
-	0xf440e3f0,
-	0x00f89d21,
-/* 0x0570: ctx_redswitch */
-	0xf120f7f0,
-	0xf0850007,
-	0x0fd00103,
-	0xf004bd00,
-/* 0x0582: ctx_redswitch_delay */
-	0xe2b608e7,
-	0xfd1bf401,
-	0x0800f5f1,
-	0x0200f5f1,
-	0x850007f1,
-	0xd00103f0,
-	0x04bd000f,
-/* 0x059e: ctx_xfer */
-	0x07f100f8,
-	0x03f08100,
-	0x000fd002,
-	0x11f404bd,
-	0x7021f507,
-/* 0x05b1: ctx_xfer_not_load */
-	0x6a21f505,
-	0xf124bd02,
-	0xf047fc07,
-	0x02d00203,
-	0xf004bd00,
-	0x20b6012c,
-	0xfc07f103,
-	0x0203f04a,
-	0xbd0002d0,
-	0x01acf004,
-	0xf102a5f0,
-	0xf00000b7,
-	0x0c9850b3,
-	0x0fc4b604,
-	0x9800bcbb,
-	0x0d98000c,
-	0x00e7f001,
-	0x016f21f5,
-	0xf001acf0,
-	0xb7f104a5,
-	0xb3f04000,
-	0x040c9850,
-	0xbb0fc4b6,
-	0x0c9800bc,
-	0x020d9801,
-	0xf1060f98,
-	0xf50800e7,
-	0xf5016f21,
-	0xf4025e21,
-	0x12f40601,
-/* 0x0629: ctx_xfer_post */
-	0x7f21f507,
-/* 0x062d: ctx_xfer_done */
-	0x5821f502,
-	0x0000f805,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
deleted file mode 100644
index c2f754e..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
-
-#define CHIPSET GF117
-#include "macros.fuc"
-
-.section #nvd7_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvd7_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
deleted file mode 100644
index d1504a4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nvd7_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
-	0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
-	0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
-	0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
-	0x0000006c,
-/* 0x0010: gpc_id */
-	0x00000000,
-/* 0x0014: tpc_count */
-	0x00000000,
-/* 0x0018: tpc_mask */
-	0x00000000,
-/* 0x001c: unk_count */
-	0x00000000,
-/* 0x0020: unk_mask */
-	0x00000000,
-/* 0x0024: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nvd7_grgpc_code[] = {
-	0x03a10ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0xe0f900f8,
-	0xf102ffb9,
-	0xf09814e7,
-	0x21f440e3,
-	0x01f7f09d,
-	0xf102ffb9,
-	0xf09c1ce7,
-	0x21f440e3,
-	0xf8e0fc9d,
-/* 0x03a1: init */
-	0xf104bd00,
-	0xf0420017,
-	0x11cf0013,
-	0x0911e700,
-	0x0814b601,
-	0xf00014fe,
-	0x07f10227,
-	0x03f01200,
-	0x0002d000,
-	0x17f104bd,
-	0x10fe0530,
-	0x0007f100,
-	0x0003f007,
-	0xbd0000d0,
-	0x0427f004,
-	0x040007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0xf11031f4,
-	0xf0820027,
-	0x22cf0123,
-	0x0137f000,
-	0xbb1f24f0,
-	0x32b60432,
-	0x05028001,
-	0xf1060380,
-	0xf0860027,
-	0x22cf0123,
-	0x04028000,
-	0x0c30e7f1,
-	0xbd50e3f0,
-	0xbd34bd24,
-/* 0x0421: init_unk_loop */
-	0x6821f444,
-	0xf400f6b0,
-	0xf7f00f0b,
-	0x04f2bb01,
-	0xb6054ffd,
-/* 0x0436: init_unk_next */
-	0x20b60130,
-	0x04e0b601,
-	0xf40126b0,
-/* 0x0442: init_unk_done */
-	0x0380e21b,
-	0x08048007,
-	0x010027f1,
-	0xcf0223f0,
-	0x34bd0022,
-	0xf1082595,
-	0xf0c00007,
-	0x05d00103,
-	0xf104bd00,
-	0xf0c10007,
-	0x05d00103,
-	0x9804bd00,
-	0x0f98000e,
-	0x5021f501,
-	0x002fbb01,
-	0x98003fbb,
-	0x0f98010e,
-	0x5021f502,
-	0x050e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x020e9800,
-	0xf5030f98,
-	0x98015021,
-	0xeffd070e,
-	0x002ebb00,
-	0xb6003ebb,
-	0x07f10235,
-	0x03f0d300,
-	0x0003d001,
-	0x25b604bd,
-	0x0635b608,
-	0xb60120b6,
-	0x24b60130,
-	0x0834b608,
-	0xf5022fb9,
-	0xbb02d321,
-	0x07f1003f,
-	0x03f00100,
-	0x0003d002,
-	0x24bd04bd,
-	0xf11f29f0,
-	0xf0080007,
-	0x02d00203,
-/* 0x04f3: main */
-	0xf404bd00,
-	0x28f40031,
-	0x24d7f000,
-	0xf43921f4,
-	0xe4b0f401,
-	0x1e18f404,
-	0xf00181fe,
-	0x20bd0627,
-	0xb60412fd,
-	0x1efd01e4,
-	0x0018fe05,
-	0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-	0x94d30ef4,
-	0xf5f010ef,
-	0x7e21f501,
-	0xc60ef403,
-/* 0x0530: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x24d7f02c,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xf00421f4,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x057e: ih_no_fifo */
-	0x07f104bd,
-	0x03f00100,
-	0x000ad000,
-	0xf0fc04bd,
-	0xd0fce0fc,
-	0xa0fcb0fc,
-	0x80fc90fc,
-	0xfc0088fe,
-	0x0032f480,
-/* 0x05a2: hub_barrier_done */
-	0xf7f001f8,
-	0x040e9801,
-	0xb904febb,
-	0xe7f102ff,
-	0xe3f09418,
-	0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-	0xf7f000f8,
-	0x0007f120,
-	0x0103f085,
-	0xbd000fd0,
-	0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-	0xf401e2b6,
-	0xf5f1fd1b,
-	0xf5f10800,
-	0x07f10200,
-	0x03f08500,
-	0x000fd001,
-	0x00f804bd,
-/* 0x05e8: ctx_xfer */
-	0x810007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-	0xf505ba21,
-	0xbd026a21,
-	0xfc07f124,
-	0x0203f047,
-	0xbd0002d0,
-	0x012cf004,
-	0xf10320b6,
-	0xf04afc07,
-	0x02d00203,
-	0xf004bd00,
-	0xa5f001ac,
-	0x00b7f102,
-	0x50b3f000,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x000c9800,
-	0xf0010d98,
-	0x21f500e7,
-	0xacf0016f,
-	0x00b7f101,
-	0x50b3f040,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x010c9800,
-	0x98020d98,
-	0xe7f1060f,
-	0x21f50800,
-	0xacf0016f,
-	0x04a5f001,
-	0x3000b7f1,
-	0x9850b3f0,
-	0xc4b6040c,
-	0x00bcbb0f,
-	0x98020c98,
-	0x0f98030d,
-	0x00e7f108,
-	0x6f21f502,
-	0x5e21f501,
-	0x0601f402,
-/* 0x0697: ctx_xfer_post */
-	0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-	0xf5027f21,
-	0xf805a221,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
deleted file mode 100644
index 6b906cd..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
-
-#define CHIPSET GK100
-#include "macros.fuc"
-
-.section #nve0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nve0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
deleted file mode 100644
index 855b220..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nve0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
-	0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
-	0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
-	0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
-	0x0000006c,
-/* 0x0010: gpc_id */
-	0x00000000,
-/* 0x0014: tpc_count */
-	0x00000000,
-/* 0x0018: tpc_mask */
-	0x00000000,
-/* 0x001c: unk_count */
-	0x00000000,
-/* 0x0020: unk_mask */
-	0x00000000,
-/* 0x0024: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nve0_grgpc_code[] = {
-	0x03a10ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0xe0f900f8,
-	0xf102ffb9,
-	0xf09814e7,
-	0x21f440e3,
-	0x01f7f09d,
-	0xf102ffb9,
-	0xf09c1ce7,
-	0x21f440e3,
-	0xf8e0fc9d,
-/* 0x03a1: init */
-	0xf104bd00,
-	0xf0420017,
-	0x11cf0013,
-	0x0911e700,
-	0x0814b601,
-	0xf00014fe,
-	0x07f10227,
-	0x03f01200,
-	0x0002d000,
-	0x17f104bd,
-	0x10fe0530,
-	0x0007f100,
-	0x0003f007,
-	0xbd0000d0,
-	0x0427f004,
-	0x040007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0xf11031f4,
-	0xf0820027,
-	0x22cf0123,
-	0x0137f000,
-	0xbb1f24f0,
-	0x32b60432,
-	0x05028001,
-	0xf1060380,
-	0xf0860027,
-	0x22cf0123,
-	0x04028000,
-	0x0c30e7f1,
-	0xbd50e3f0,
-	0xbd34bd24,
-/* 0x0421: init_unk_loop */
-	0x6821f444,
-	0xf400f6b0,
-	0xf7f00f0b,
-	0x04f2bb01,
-	0xb6054ffd,
-/* 0x0436: init_unk_next */
-	0x20b60130,
-	0x04e0b601,
-	0xf40126b0,
-/* 0x0442: init_unk_done */
-	0x0380e21b,
-	0x08048007,
-	0x010027f1,
-	0xcf0223f0,
-	0x34bd0022,
-	0xf1082595,
-	0xf0c00007,
-	0x05d00103,
-	0xf104bd00,
-	0xf0c10007,
-	0x05d00103,
-	0x9804bd00,
-	0x0f98000e,
-	0x5021f501,
-	0x002fbb01,
-	0x98003fbb,
-	0x0f98010e,
-	0x5021f502,
-	0x050e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x020e9800,
-	0xf5030f98,
-	0x98015021,
-	0xeffd070e,
-	0x002ebb00,
-	0xb6003ebb,
-	0x07f10235,
-	0x03f0d300,
-	0x0003d001,
-	0x25b604bd,
-	0x0635b608,
-	0xb60120b6,
-	0x24b60130,
-	0x0834b608,
-	0xf5022fb9,
-	0xbb02d321,
-	0x07f1003f,
-	0x03f00100,
-	0x0003d002,
-	0x24bd04bd,
-	0xf11f29f0,
-	0xf0080007,
-	0x02d00203,
-/* 0x04f3: main */
-	0xf404bd00,
-	0x28f40031,
-	0x24d7f000,
-	0xf43921f4,
-	0xe4b0f401,
-	0x1e18f404,
-	0xf00181fe,
-	0x20bd0627,
-	0xb60412fd,
-	0x1efd01e4,
-	0x0018fe05,
-	0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-	0x94d30ef4,
-	0xf5f010ef,
-	0x7e21f501,
-	0xc60ef403,
-/* 0x0530: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x24d7f02c,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xf00421f4,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x057e: ih_no_fifo */
-	0x07f104bd,
-	0x03f00100,
-	0x000ad000,
-	0xf0fc04bd,
-	0xd0fce0fc,
-	0xa0fcb0fc,
-	0x80fc90fc,
-	0xfc0088fe,
-	0x0032f480,
-/* 0x05a2: hub_barrier_done */
-	0xf7f001f8,
-	0x040e9801,
-	0xb904febb,
-	0xe7f102ff,
-	0xe3f09418,
-	0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-	0xf7f000f8,
-	0x0007f120,
-	0x0103f085,
-	0xbd000fd0,
-	0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-	0xf401e2b6,
-	0xf5f1fd1b,
-	0xf5f10800,
-	0x07f10200,
-	0x03f08500,
-	0x000fd001,
-	0x00f804bd,
-/* 0x05e8: ctx_xfer */
-	0x810007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-	0xf505ba21,
-	0xbd026a21,
-	0xfc07f124,
-	0x0203f047,
-	0xbd0002d0,
-	0x012cf004,
-	0xf10320b6,
-	0xf04afc07,
-	0x02d00203,
-	0xf004bd00,
-	0xa5f001ac,
-	0x00b7f102,
-	0x50b3f000,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x000c9800,
-	0xf0010d98,
-	0x21f500e7,
-	0xacf0016f,
-	0x00b7f101,
-	0x50b3f040,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x010c9800,
-	0x98020d98,
-	0xe7f1060f,
-	0x21f50800,
-	0xacf0016f,
-	0x04a5f001,
-	0x3000b7f1,
-	0x9850b3f0,
-	0xc4b6040c,
-	0x00bcbb0f,
-	0x98020c98,
-	0x0f98030d,
-	0x00e7f108,
-	0x6f21f502,
-	0x5e21f501,
-	0x0601f402,
-/* 0x0697: ctx_xfer_post */
-	0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-	0xf5027f21,
-	0xf805a221,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
deleted file mode 100644
index 90bbe52..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000002
-
-#define CHIPSET GK110
-#include "macros.fuc"
-
-.section #nvf0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvf0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
deleted file mode 100644
index 1b80319..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nvf0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
-	0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
-	0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
-	0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
-	0x0000006c,
-/* 0x0010: gpc_id */
-	0x00000000,
-/* 0x0014: tpc_count */
-	0x00000000,
-/* 0x0018: tpc_mask */
-	0x00000000,
-/* 0x001c: unk_count */
-	0x00000000,
-/* 0x0020: unk_mask */
-	0x00000000,
-/* 0x0024: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nvf0_grgpc_code[] = {
-	0x03a10ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f037,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f037,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x370007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x370007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0xe0f900f8,
-	0xf102ffb9,
-	0xf09814e7,
-	0x21f440e3,
-	0x01f7f09d,
-	0xf102ffb9,
-	0xf09c1ce7,
-	0x21f440e3,
-	0xf8e0fc9d,
-/* 0x03a1: init */
-	0xf104bd00,
-	0xf0420017,
-	0x11cf0013,
-	0x0911e700,
-	0x0814b601,
-	0xf00014fe,
-	0x07f10227,
-	0x03f01200,
-	0x0002d000,
-	0x17f104bd,
-	0x10fe0530,
-	0x0007f100,
-	0x0003f007,
-	0xbd0000d0,
-	0x0427f004,
-	0x040007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0xf11031f4,
-	0xf0820027,
-	0x22cf0123,
-	0x0137f000,
-	0xbb1f24f0,
-	0x32b60432,
-	0x05028001,
-	0xf1060380,
-	0xf0860027,
-	0x22cf0123,
-	0x04028000,
-	0x0c30e7f1,
-	0xbd50e3f0,
-	0xbd34bd24,
-/* 0x0421: init_unk_loop */
-	0x6821f444,
-	0xf400f6b0,
-	0xf7f00f0b,
-	0x04f2bb01,
-	0xb6054ffd,
-/* 0x0436: init_unk_next */
-	0x20b60130,
-	0x04e0b601,
-	0xf40226b0,
-/* 0x0442: init_unk_done */
-	0x0380e21b,
-	0x08048007,
-	0x010027f1,
-	0xcf0223f0,
-	0x34bd0022,
-	0xf1082595,
-	0xf0c00007,
-	0x05d00103,
-	0xf104bd00,
-	0xf0c10007,
-	0x05d00103,
-	0x9804bd00,
-	0x0f98000e,
-	0x5021f501,
-	0x002fbb01,
-	0x98003fbb,
-	0x0f98010e,
-	0x5021f502,
-	0x050e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x020e9800,
-	0xf5030f98,
-	0x98015021,
-	0xeffd070e,
-	0x002ebb00,
-	0xb6003ebb,
-	0x07f10235,
-	0x03f0d300,
-	0x0003d001,
-	0x25b604bd,
-	0x0635b608,
-	0xb60120b6,
-	0x24b60130,
-	0x0834b608,
-	0xf5022fb9,
-	0xbb02d321,
-	0x07f1003f,
-	0x03f00100,
-	0x0003d002,
-	0x24bd04bd,
-	0xf11f29f0,
-	0xf0300007,
-	0x02d00203,
-/* 0x04f3: main */
-	0xf404bd00,
-	0x28f40031,
-	0x24d7f000,
-	0xf43921f4,
-	0xe4b0f401,
-	0x1e18f404,
-	0xf00181fe,
-	0x20bd0627,
-	0xb60412fd,
-	0x1efd01e4,
-	0x0018fe05,
-	0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
-	0x94d30ef4,
-	0xf5f010ef,
-	0x7e21f501,
-	0xc60ef403,
-/* 0x0530: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x24d7f02c,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xf00421f4,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x057e: ih_no_fifo */
-	0x07f104bd,
-	0x03f00100,
-	0x000ad000,
-	0xf0fc04bd,
-	0xd0fce0fc,
-	0xa0fcb0fc,
-	0x80fc90fc,
-	0xfc0088fe,
-	0x0032f480,
-/* 0x05a2: hub_barrier_done */
-	0xf7f001f8,
-	0x040e9801,
-	0xb904febb,
-	0xe7f102ff,
-	0xe3f09418,
-	0x9d21f440,
-/* 0x05ba: ctx_redswitch */
-	0xf7f000f8,
-	0x0007f120,
-	0x0103f085,
-	0xbd000fd0,
-	0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
-	0xf401e2b6,
-	0xf5f1fd1b,
-	0xf5f10800,
-	0x07f10200,
-	0x03f08500,
-	0x000fd001,
-	0x00f804bd,
-/* 0x05e8: ctx_xfer */
-	0x810007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
-	0xf505ba21,
-	0xbd026a21,
-	0xfc07f124,
-	0x0203f047,
-	0xbd0002d0,
-	0x012cf004,
-	0xf10320b6,
-	0xf04afc07,
-	0x02d00203,
-	0xf004bd00,
-	0xa5f001ac,
-	0x00b7f102,
-	0x50b3f000,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x000c9800,
-	0xf0010d98,
-	0x21f500e7,
-	0xacf0016f,
-	0x00b7f101,
-	0x50b3f040,
-	0xb6040c98,
-	0xbcbb0fc4,
-	0x010c9800,
-	0x98020d98,
-	0xe7f1060f,
-	0x21f50800,
-	0xacf0016f,
-	0x04a5f001,
-	0x3000b7f1,
-	0x9850b3f0,
-	0xc4b6040c,
-	0x00bcbb0f,
-	0x98020c98,
-	0x0f98030d,
-	0x00e7f108,
-	0x6f21f502,
-	0x5e21f501,
-	0x0601f402,
-/* 0x0697: ctx_xfer_post */
-	0xf50712f4,
-/* 0x069b: ctx_xfer_done */
-	0xf5027f21,
-	0xf805a221,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
deleted file mode 100644
index b4ad18b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
+++ /dev/null
@@ -1,696 +0,0 @@
-/* fuc microcode for nvc0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#ifdef INCLUDE_DATA
-hub_mmio_list_head:	.b32 #hub_mmio_list_base
-hub_mmio_list_tail:	.b32 #hub_mmio_list_next
-
-gpc_count:		.b32 0
-rop_count:		.b32 0
-cmd_queue:		queue_init
-
-ctx_current:		.b32 0
-
-.align 256
-chan_data:
-chan_mmio_count:	.b32 0
-chan_mmio_address:	.b32 0
-
-.align 256
-xfer_data: 		.skip 256
-
-hub_mmio_list_base:
-.b32 0x0417e91c // 0x17e91c, 2
-hub_mmio_list_next:
-#endif
-
-#ifdef INCLUDE_CODE
-// reports an exception to the host
-//
-// In: $r15 error code (see os.h)
-//
-error:
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
-	mov $r15 1
-	nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
-	ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: total PGRAPH context size
-//
-init:
-	clear b32 $r0
-	mov $xdbase $r0
-
-	// setup stack
-	nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0)
-	extr $r1 $r1 9:17
-	shl b32 $r1 8
-	mov $sp $r1
-
-	// enable fifo access
-	mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO
-	nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2)
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-
-	clear b32 $r2
-	nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2)
-
-	// route HUB_CHSW_PULSE to fuc interrupt 8
-	mov $r2 0x2003		// { HUB_CHSW_PULSE, ZERO } -> intr 8
-	nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2)
-
-	// not sure what these are, route them because NVIDIA does, and
-	// the IRQ handler will signal the host if we ever get one.. we
-	// may find out if/why we need to handle these if so..
-	//
-	mov $r2 0x2004		// { 0x04, ZERO } -> intr 9
-	nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2)
-	mov $r2 0x200b		// { HUB_FIRMWARE_MTHD, ZERO } -> intr 10
-	nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2)
-	mov $r2 0x200c		// { 0x0c, ZERO } -> intr 15
-	nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2)
-
-	// enable all INTR_UP interrupts
-	sub b32 $r3 $r0 1
-	nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3)
-
-	// enable fifo, ctxsw, 9, fwmthd, 15 interrupts
-	imm32($r2, 0x8704)
-	nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2)
-
-	// fifo level triggered, rest edge
-	mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL
-	nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2)
-
-	// enable interrupts
-	bset $flags ie0
-
-	// fetch enabled GPC/ROP counts
-	nv_rd32($r14, 0x409604)
-	extr $r1 $r15 16:20
-	st b32 D[$r0 + #rop_count] $r1
-	and $r15 0x1f
-	st b32 D[$r0 + #gpc_count] $r15
-
-	// set BAR_REQMASK to GPC mask
-	mov $r1 1
-	shl b32 $r1 $r15
-	sub b32 $r1 1
-	nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1)
-	nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1)
-
-	// context size calculation, reserve first 256 bytes for use by fuc
-	mov $r1 256
-
-	//
-	mov $r15 2
-	call(ctx_4170s)
-	call(ctx_4170w)
-	mov $r15 0x10
-	call(ctx_86c)
-
-	// calculate size of mmio context data
-	ld b32 $r14 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
-	call(mmctx_size)
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't (currently) ever change
-	shr b32 $r4 $r1 8
-	nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4)
-	nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4)
-	add b32 $r3 0x1300
-	add b32 $r1 $r15
-	shr b32 $r15 2
-	nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf??
-
-	// strands, base offset needs to be aligned to 256 bytes
-	shr b32 $r1 8
-	add b32 $r1 1
-	shl b32 $r1 8
-	mov b32 $r15 $r1
-	call(strand_ctx_init)
-	add b32 $r1 $r15
-
-	// initialise each GPC in sequence by passing in the offset of its
-	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
-	// has previously been uploaded by the host) running.
-	//
-	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
-	// when it has completed, and return the size of its context data
-	// in GPCn_CC_SCRATCH[1]
-	//
-	ld b32 $r3 D[$r0 + #gpc_count]
-	imm32($r4, 0x502000)
-	init_gpc:
-		// setup, and start GPC ucode running
-		add b32 $r14 $r4 0x804
-		mov b32 $r15 $r1
-		call(nv_wr32)			// CC_SCRATCH[1] = ctx offset
-		add b32 $r14 $r4 0x10c
-		clear b32 $r15
-		call(nv_wr32)
-		add b32 $r14 $r4 0x104
-		call(nv_wr32)			// ENTRY
-		add b32 $r14 $r4 0x100
-		mov $r15 2			// CTRL_START_TRIGGER
-		call(nv_wr32)			// CTRL
-
-		// wait for it to complete, and adjust context size
-		add b32 $r14 $r4 0x800
-		init_gpc_wait:
-			call(nv_rd32)
-			xbit $r15 $r15 31
-			bra e #init_gpc_wait
-		add b32 $r14 $r4 0x804
-		call(nv_rd32)
-		add b32 $r1 $r15
-
-		// next!
-		add b32 $r4 0x8000
-		sub b32 $r3 1
-		bra ne #init_gpc
-
-	//
-	mov $r15 0
-	call(ctx_86c)
-	mov $r15 0
-	call(ctx_4170s)
-
-	// save context size, and tell host we're ready
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
-	clear b32 $r1
-	bset $r1 31
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	// sleep until we have something to do
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call(queue_get)
-	bra $p1 #main
-
-	// context switch, requested by GPU?
-	cmpu b32 $r14 0x4001
-	bra ne #main_not_ctx_switch
-		trace_set(T_AUTO)
-		nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0)
-		nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0)
-
-		xbit $r3 $r1 31
-		bra e #chsw_no_prev
-			xbit $r3 $r2 31
-			bra e #chsw_prev_no_next
-				push $r2
-				mov b32 $r2 $r1
-				trace_set(T_SAVE)
-				bclr $flags $p1
-				bset $flags $p2
-				call(ctx_xfer)
-				trace_clr(T_SAVE);
-				pop $r2
-				trace_set(T_LOAD);
-				bset $flags $p1
-				call(ctx_xfer)
-				trace_clr(T_LOAD);
-				bra #chsw_done
-			chsw_prev_no_next:
-				push $r2
-				mov b32 $r2 $r1
-				bclr $flags $p1
-				bclr $flags $p2
-				call(ctx_xfer)
-				pop $r2
-				nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
-				bra #chsw_done
-		chsw_no_prev:
-			xbit $r3 $r2 31
-			bra e #chsw_done
-				bset $flags $p1
-				bclr $flags $p2
-				call(ctx_xfer)
-
-		// ack the context switch request
-		chsw_done:
-		mov $r2 NV_PGRAPH_FECS_CHSW_ACK
-		nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2)
-		trace_clr(T_AUTO)
-		bra #main
-
-	// request to set current channel? (*not* a context switch)
-	main_not_ctx_switch:
-	cmpu b32 $r14 0x0001
-	bra ne #main_not_ctx_chan
-		mov b32 $r2 $r15
-		call(ctx_chan)
-		bra #main_done
-
-	// request to store current channel context?
-	main_not_ctx_chan:
-	cmpu b32 $r14 0x0002
-	bra ne #main_not_ctx_save
-		trace_set(T_SAVE)
-		bclr $flags $p1
-		bclr $flags $p2
-		call(ctx_xfer)
-		trace_clr(T_SAVE)
-		bra #main_done
-
-	main_not_ctx_save:
-		shl b32 $r15 $r14 16
-		or $r15 E_BAD_COMMAND
-		call(error)
-		bra #main
-
-	main_done:
-	clear b32 $r2
-	bset $r2 31
-	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-	clear b32 $r0
-
-	// incoming fifo command?
-	nv_iord($r10, NV_PGRAPH_FECS_INTR, 0)
-	and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r13 #cmd_queue
-		nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0)
-		nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0)
-		call(queue_put)
-		add b32 $r11 0x400
-		mov $r14 1
-		nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14)
-
-	// context switch request?
-	ih_no_fifo:
-	and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW
-	bra e #ih_no_ctxsw
-		// enqueue a context switch for later processing
-		mov $r13 #cmd_queue
-		mov $r14 0x4001
-		call(queue_put)
-
-	// firmware method?
-	ih_no_ctxsw:
-	and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD
-	bra e #ih_no_fwmthd
-		// none we handle; report to host and ack
-		nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO)
-		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15)
-		nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR)
-		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15)
-		extr $r14 $r15 16:18
-		shl b32 $r14 $r14 2
-		imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0))
-		add b32 $r14 $r15
-		call(nv_rd32)
-		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15)
-		mov $r15 E_BAD_FWMTHD
-		call(error)
-		mov $r11 0x100
-		nv_wr32(0x400144, $r11)
-
-	// anything we didn't handle, bring it to the host's attention
-	ih_no_fwmthd:
-	mov $r11 0x504 // FIFO | CHSW | FWMTHD
-	not b32 $r11
-	and $r11 $r10 $r11
-	bra e #ih_no_other
-		nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11)
-
-	// ack, and wake up main()
-	ih_no_other:
-	nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10)
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-#if CHIPSET < GK100
-// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
-ctx_4160s:
-	mov $r15 1
-	nv_wr32(0x404160, $r15)
-	ctx_4160s_wait:
-		nv_rd32($r15, 0x404160)
-		xbit $r15 $r15 4
-		bra e #ctx_4160s_wait
-	ret
-
-// Without clearing again at end of xfer, some things cause PGRAPH
-// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
-// still function with it set however...
-ctx_4160c:
-	clear b32 $r15
-	nv_wr32(0x404160, $r15)
-	ret
-#endif
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
-	or $r15 0x10
-	nv_wr32(0x404170, $r15)
-	ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
-	nv_rd32($r15, 0x404170)
-	and $r15 0x10
-	bra ne #ctx_4170w
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC
-	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP
-	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC
-	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN
-	nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP
-	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN
-	nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
-	ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
-	nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15)
-	nv_wr32(0x408a14, $r15)
-	nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15)
-	ret
-
-// In: $r15 NV_PGRAPH_FECS_MEM_CMD_*
-ctx_mem:
-	nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15)
-	ctx_mem_wait:
-		nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0)
-		or $r15 $r15
-		bra ne #ctx_mem_wait
-	ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
-	trace_set(T_CHAN)
-
-	// switch to channel, somewhat magic in parts..
-	mov $r10 12		// DONE_UNK12
-	call(wait_donez)
-	clear b32 $r15
-	nv_iowr(0x409a24, 0, $r15)
-	nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2)
-	nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2)
-	mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN
-	call(ctx_mem)
-	nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
-
-	// load channel header, fetch PGRAPH context pointer
-	mov $xtargets $r0
-	bclr $r2 31
-	shl b32 $r2 4
-	add b32 $r2 2
-
-	trace_set(T_LCHAN)
-	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2)
-	imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31)
-	or  $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM
-	nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
-	mov $r1 0x10			// chan + 0x0210
-	mov $r2 #xfer_data
-	sethi $r2 0x00020000		// 16 bytes
-	xdld $r1 $r2
-	xdwait
-	trace_clr(T_LCHAN)
-
-	// update current context
-	ld b32 $r1 D[$r0 + #xfer_data + 4]
-	shl b32 $r1 24
-	ld b32 $r2 D[$r0 + #xfer_data + 0]
-	shr b32 $r2 8
-	or $r1 $r2
-	st b32 D[$r0 + #ctx_current] $r1
-
-	// set transfer base to start of context, and fetch context header
-	trace_set(T_LCTXH)
-	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1)
-	mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM
-	nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdld $r0 $r1
-	xdwait
-	trace_clr(T_LCTXH)
-
-	trace_clr(T_CHAN)
-	ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-//            the active channel for ctxctl, but not actually transfer
-//            any context data.  intended for use only during initial
-//            context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-#if CHIPSET < GK100
-	call(ctx_4160s)
-#endif
-	call(ctx_load)
-	mov $r10 12			// DONE_UNK12
-	call(wait_donez)
-	mov $r15 5 // MEM_CMD 5 ???
-	call(ctx_mem)
-#if CHIPSET < GK100
-	call(ctx_4160c)
-#endif
-	ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel.  Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state...  The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
-	// set transfer base to be the mmio list
-	ld b32 $r3 D[$r0 + #chan_mmio_address]
-	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
-
-	clear b32 $r3
-	ctx_mmio_loop:
-		// fetch next 256 bytes of mmio list if necessary
-		and $r4 $r3 0xff
-		bra ne #ctx_mmio_pull
-			mov $r5 #xfer_data
-			sethi $r5 0x00060000	// 256 bytes
-			xdld $r3 $r5
-			xdwait
-
-		// execute a single list entry
-		ctx_mmio_pull:
-		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
-		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-		call(nv_wr32)
-
-		// next!
-		add b32 $r3 8
-		sub b32 $r1 1
-		bra ne #ctx_mmio_loop
-
-	// set transfer base back to the current context
-	ctx_mmio_done:
-	ld b32 $r3 D[$r0 + #ctx_current]
-	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
-
-	// disable the mmio list now, we don't need/want to execute it again
-	st b32 D[$r0 + #chan_mmio_count] $r0
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdst $r0 $r1
-	xdwait
-	ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// according to mwk, some kind of wait for idle
-	mov $r14 4
-	nv_iowr(0x409c08, 0, $r14)
-	ctx_xfer_idle:
-		nv_iord($r14, 0x409c00, 0)
-		and $r14 0x2000
-		bra ne #ctx_xfer_idle
-
-	bra not $p1 #ctx_xfer_pre
-	bra $p2 #ctx_xfer_pre_load
-	ctx_xfer_pre:
-		mov $r15 0x10
-		call(ctx_86c)
-#if CHIPSET < GK100
-		call(ctx_4160s)
-#endif
-		bra not $p1 #ctx_xfer_exec
-
-	ctx_xfer_pre_load:
-		mov $r15 2
-		call(ctx_4170s)
-		call(ctx_4170w)
-		call(ctx_redswitch)
-		clear b32 $r15
-		call(ctx_4170s)
-		call(ctx_load)
-
-	// fetch context pointer, and initiate xfer on all GPCs
-	ctx_xfer_exec:
-	ld b32 $r1 D[$r0 + #ctx_current]
-
-	clear b32 $r2
-	nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2)
-
-	nv_wr32(0x41a500, $r1)	// GPC_BCAST_WRCMD_DATA = ctx pointer
-	xbit $r15 $flags $p1
-	xbit $r2 $flags $p2
-	shl b32 $r2 1
-	or $r15 $r2
-	nv_wr32(0x41a504, $r15)	// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
-	// strands
-	call(strand_pre)
-	clear b32 $r2
-	nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2)
-	xbit $r2 $flags $p1	// SAVE/LOAD
-	add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE
-	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 6		// first, last
-	mov $r11 0		// base = 0
-	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
-	mov $r14 0		// not multi
-	call(mmctx_xfer)
-
-	// wait for GPCs to all complete
-	mov $r10 8		// DONE_BAR
-	call(wait_doneo)
-
-	// wait for strand xfer to complete
-	call(strand_wait)
-
-	// post-op
-	bra $p1 #ctx_xfer_post
-		mov $r10 12		// DONE_UNK12
-		call(wait_donez)
-		mov $r15 5 // MEM_CMD 5 ???
-		call(ctx_mem)
-
-	bra $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r15 2
-		call(ctx_4170s)
-		clear b32 $r15
-		call(ctx_86c)
-		call(strand_post)
-		call(ctx_4170w)
-		clear b32 $r15
-		call(ctx_4170s)
-
-		bra not $p1 #ctx_xfer_no_post_mmio
-		ld b32 $r1 D[$r0 + #chan_mmio_count]
-		or $r1 $r1
-		bra e #ctx_xfer_no_post_mmio
-			call(ctx_mmio_exec)
-
-		ctx_xfer_no_post_mmio:
-#if CHIPSET < GK100
-		call(ctx_4160c)
-#endif
-
-	ctx_xfer_done:
-	ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5
deleted file mode 100644
index 7c5d256..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK208
-#include "macros.fuc"
-
-.section #nv108_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nv108_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
deleted file mode 100644
index e49b5a8..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
+++ /dev/null
@@ -1,916 +0,0 @@
-uint32_t nv108_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
-	0x00000300,
-/* 0x0004: hub_mmio_list_tail */
-	0x00000304,
-/* 0x0008: gpc_count */
-	0x00000000,
-/* 0x000c: rop_count */
-	0x00000000,
-/* 0x0010: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: ctx_current */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
-	0x00000000,
-/* 0x0104: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: xfer_data */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: hub_mmio_list_base */
-	0x0417e91c,
-};
-
-uint32_t nv108_grhub_code[] = {
-	0x030e0ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0xf489a408,
-	0x020f0b1b,
-	0x0002f87e,
-/* 0x001a: queue_put_next */
-	0x98c400f8,
-	0x0384b607,
-	0xb6008dbb,
-	0x8eb50880,
-	0x018fb500,
-	0xf00190b6,
-	0xd9b50f94,
-/* 0x0037: queue_get */
-	0xf400f801,
-	0xd8980131,
-	0x01d99800,
-	0x0bf489a4,
-	0x0789c421,
-	0xbb0394b6,
-	0x90b6009d,
-	0x009e9808,
-	0xb6019f98,
-	0x84f00180,
-	0x00d8b50f,
-/* 0x0063: queue_get_done */
-	0xf80132f4,
-/* 0x0065: nv_rd32 */
-	0xf0ecb200,
-	0x00801fc9,
-	0x0cf601ca,
-/* 0x0073: nv_rd32_wait */
-	0x8c04bd00,
-	0xcf01ca00,
-	0xccc800cc,
-	0xf61bf41f,
-	0xec7e060a,
-	0x008f0000,
-	0xffcf01cb,
-/* 0x008f: nv_wr32 */
-	0x8000f800,
-	0xf601cc00,
-	0x04bd000f,
-	0xc9f0ecb2,
-	0x1ec9f01f,
-	0x01ca0080,
-	0xbd000cf6,
-/* 0x00a9: nv_wr32_wait */
-	0xca008c04,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f61b,
-/* 0x00b8: wait_donez */
-	0x99f094bd,
-	0x37008000,
-	0x0009f602,
-	0x008004bd,
-	0x0af60206,
-/* 0x00cf: wait_donez_ne */
-	0x8804bd00,
-	0xcf010000,
-	0x8aff0088,
-	0xf61bf488,
-	0x99f094bd,
-	0x17008000,
-	0x0009f602,
-	0x00f804bd,
-/* 0x00ec: wait_doneo */
-	0x99f094bd,
-	0x37008000,
-	0x0009f602,
-	0x008004bd,
-	0x0af60206,
-/* 0x0103: wait_doneo_e */
-	0x8804bd00,
-	0xcf010000,
-	0x8aff0088,
-	0xf60bf488,
-	0x99f094bd,
-	0x17008000,
-	0x0009f602,
-	0x00f804bd,
-/* 0x0120: mmctx_size */
-/* 0x0122: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0x1bf4efa4,
-	0xf89fb2ec,
-/* 0x013d: mmctx_xfer */
-	0xf094bd00,
-	0x00800199,
-	0x09f60237,
-	0xbd04bd00,
-	0x05bbfd94,
-	0x800f0bf4,
-	0xf601c400,
-	0x04bd000b,
-/* 0x015f: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0xc6008018,
-	0x000ef601,
-	0x008004bd,
-	0x0ff601c7,
-	0xf004bd00,
-/* 0x017a: mmctx_multi_disabled */
-	0xabc80199,
-	0x10b4b600,
-	0xc80cb9f0,
-	0xe4b601ae,
-	0x05befd11,
-	0x01c50080,
-	0xbd000bf6,
-/* 0x0195: mmctx_exec_loop */
-/* 0x0195: mmctx_wait_free */
-	0xc5008e04,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f60b,
-	0x05e9fd00,
-	0x01c80080,
-	0xbd000ef6,
-	0x04c0b604,
-	0x1bf4cda4,
-	0x02abc8df,
-/* 0x01bf: mmctx_fini_wait */
-	0x8b1c1bf4,
-	0xcf01c500,
-	0xb4f000bb,
-	0x10b4b01f,
-	0x0af31bf4,
-	0x00b87e05,
-	0x250ef400,
-/* 0x01d8: mmctx_stop */
-	0xb600abc8,
-	0xb9f010b4,
-	0x12b9f00c,
-	0x01c50080,
-	0xbd000bf6,
-/* 0x01ed: mmctx_stop_wait */
-	0xc5008b04,
-	0x00bbcf01,
-	0xf412bbc8,
-/* 0x01fa: mmctx_done */
-	0x94bdf61b,
-	0x800199f0,
-	0xf6021700,
-	0x04bd0009,
-/* 0x020a: strand_wait */
-	0xa0f900f8,
-	0xb87e020a,
-	0xa0fc0000,
-/* 0x0216: strand_pre */
-	0x0c0900f8,
-	0x024afc80,
-	0xbd0009f6,
-	0x020a7e04,
-/* 0x0227: strand_post */
-	0x0900f800,
-	0x4afc800d,
-	0x0009f602,
-	0x0a7e04bd,
-	0x00f80002,
-/* 0x0238: strand_set */
-	0xfc800f0c,
-	0x0cf6024f,
-	0x0c04bd00,
-	0x4afc800b,
-	0x000cf602,
-	0xfc8004bd,
-	0x0ef6024f,
-	0x0c04bd00,
-	0x4afc800a,
-	0x000cf602,
-	0x0a7e04bd,
-	0x00f80002,
-/* 0x0268: strand_ctx_init */
-	0x99f094bd,
-	0x37008003,
-	0x0009f602,
-	0x167e04bd,
-	0x030e0002,
-	0x0002387e,
-	0xfc80c4bd,
-	0x0cf60247,
-	0x0c04bd00,
-	0x4afc8001,
-	0x000cf602,
-	0x0a7e04bd,
-	0x0c920002,
-	0x46fc8001,
-	0x000cf602,
-	0x020c04bd,
-	0x024afc80,
-	0xbd000cf6,
-	0x020a7e04,
-	0x02277e00,
-	0x42008800,
-	0x20008902,
-	0x0099cf02,
-/* 0x02c7: ctx_init_strand_loop */
-	0xf608fe95,
-	0x8ef6008e,
-	0x808acf40,
-	0xb606a5b6,
-	0xeabb01a0,
-	0x0480b600,
-	0xf40192b6,
-	0xe4b6e81b,
-	0xf2efbc08,
-	0x99f094bd,
-	0x17008003,
-	0x0009f602,
-	0x00f804bd,
-/* 0x02f8: error */
-	0x02050080,
-	0xbd000ff6,
-	0x80010f04,
-	0xf6030700,
-	0x04bd000f,
-/* 0x030e: init */
-	0x04bd00f8,
-	0x410007fe,
-	0x11cf4200,
-	0x0911e700,
-	0x0814b601,
-	0x020014fe,
-	0x12004002,
-	0xbd0002f6,
-	0x05c94104,
-	0xbd0010fe,
-	0x07004024,
-	0xbd0002f6,
-	0x20034204,
-	0x01010080,
-	0xbd0002f6,
-	0x20044204,
-	0x01010480,
-	0xbd0002f6,
-	0x200b4204,
-	0x01010880,
-	0xbd0002f6,
-	0x200c4204,
-	0x01011c80,
-	0xbd0002f6,
-	0x01039204,
-	0x03090080,
-	0xbd0003f6,
-	0x87044204,
-	0xf6040040,
-	0x04bd0002,
-	0x00400402,
-	0x0002f603,
-	0x31f404bd,
-	0x96048e10,
-	0x00657e40,
-	0xc7feb200,
-	0x01b590f1,
-	0x1ff4f003,
-	0x01020fb5,
-	0x041fbb01,
-	0x800112b6,
-	0xf6010300,
-	0x04bd0001,
-	0x01040080,
-	0xbd0001f6,
-	0x01004104,
-	0xa87e020f,
-	0xb77e0006,
-	0x100f0006,
-	0x0006f97e,
-	0x98000e98,
-	0x207e010f,
-	0x14950001,
-	0xc0008008,
-	0x0004f601,
-	0x008004bd,
-	0x04f601c1,
-	0xb704bd00,
-	0xbb130030,
-	0xf5b6001f,
-	0xd3008002,
-	0x000ff601,
-	0x15b604bd,
-	0x0110b608,
-	0xb20814b6,
-	0x02687e1f,
-	0x001fbb00,
-	0x84020398,
-/* 0x041f: init_gpc */
-	0xb8502000,
-	0x0008044e,
-	0x8f7e1fb2,
-	0x4eb80000,
-	0xbd00010c,
-	0x008f7ef4,
-	0x044eb800,
-	0x8f7e0001,
-	0x4eb80000,
-	0x0f000100,
-	0x008f7e02,
-	0x004eb800,
-/* 0x044e: init_gpc_wait */
-	0x657e0008,
-	0xffc80000,
-	0xf90bf41f,
-	0x08044eb8,
-	0x00657e00,
-	0x001fbb00,
-	0x800040b7,
-	0xf40132b6,
-	0x000fb41b,
-	0x0006f97e,
-	0xa87e000f,
-	0x00800006,
-	0x01f60201,
-	0xbd04bd00,
-	0x1f19f014,
-	0x02300080,
-	0xbd0001f6,
-/* 0x0491: main */
-	0x0031f404,
-	0x0d0028f4,
-	0x00377e10,
-	0xf401f400,
-	0x4001e4b1,
-	0x00c71bf5,
-	0x99f094bd,
-	0x37008004,
-	0x0009f602,
-	0x008104bd,
-	0x11cf02c0,
-	0xc1008200,
-	0x0022cf02,
-	0xf41f13c8,
-	0x23c8770b,
-	0x550bf41f,
-	0x12b220f9,
-	0x99f094bd,
-	0x37008007,
-	0x0009f602,
-	0x32f404bd,
-	0x0231f401,
-	0x00087c7e,
-	0x99f094bd,
-	0x17008007,
-	0x0009f602,
-	0x20fc04bd,
-	0x99f094bd,
-	0x37008006,
-	0x0009f602,
-	0x31f404bd,
-	0x087c7e01,
-	0xf094bd00,
-	0x00800699,
-	0x09f60217,
-	0xf404bd00,
-/* 0x0522: chsw_prev_no_next */
-	0x20f92f0e,
-	0x32f412b2,
-	0x0232f401,
-	0x00087c7e,
-	0x008020fc,
-	0x02f602c0,
-	0xf404bd00,
-/* 0x053e: chsw_no_prev */
-	0x23c8130e,
-	0x0d0bf41f,
-	0xf40131f4,
-	0x7c7e0232,
-/* 0x054e: chsw_done */
-	0x01020008,
-	0x02c30080,
-	0xbd0002f6,
-	0xf094bd04,
-	0x00800499,
-	0x09f60217,
-	0xf504bd00,
-/* 0x056b: main_not_ctx_switch */
-	0xb0ff2a0e,
-	0x1bf401e4,
-	0x7ef2b20c,
-	0xf400081c,
-/* 0x057a: main_not_ctx_chan */
-	0xe4b0400e,
-	0x2c1bf402,
-	0x99f094bd,
-	0x37008007,
-	0x0009f602,
-	0x32f404bd,
-	0x0232f401,
-	0x00087c7e,
-	0x99f094bd,
-	0x17008007,
-	0x0009f602,
-	0x0ef404bd,
-/* 0x05a9: main_not_ctx_save */
-	0x10ef9411,
-	0x7e01f5f0,
-	0xf50002f8,
-/* 0x05b7: main_done */
-	0xbdfede0e,
-	0x1f29f024,
-	0x02300080,
-	0xbd0002f6,
-	0xcc0ef504,
-/* 0x05c9: ih */
-	0xfe80f9fe,
-	0x80f90188,
-	0xa0f990f9,
-	0xd0f9b0f9,
-	0xf0f9e0f9,
-	0x004a04bd,
-	0x00aacf02,
-	0xf404abc4,
-	0x100d230b,
-	0xcf1a004e,
-	0x004f00ee,
-	0x00ffcf19,
-	0x0000047e,
-	0x0400b0b7,
-	0x0040010e,
-	0x000ef61d,
-/* 0x060a: ih_no_fifo */
-	0xabe404bd,
-	0x0bf40100,
-	0x4e100d0c,
-	0x047e4001,
-/* 0x061a: ih_no_ctxsw */
-	0xabe40000,
-	0x0bf40400,
-	0x07088e56,
-	0x00657e40,
-	0x80ffb200,
-	0xf6020400,
-	0x04bd000f,
-	0x4007048e,
-	0x0000657e,
-	0x0080ffb2,
-	0x0ff60203,
-	0xc704bd00,
-	0xee9450fe,
-	0x07008f02,
-	0x00efbb40,
-	0x0000657e,
-	0x02020080,
-	0xbd000ff6,
-	0x7e030f04,
-	0x4b0002f8,
-	0xbfb20100,
-	0x4001448e,
-	0x00008f7e,
-/* 0x0674: ih_no_fwmthd */
-	0xbd05044b,
-	0xb4abffb0,
-	0x800c0bf4,
-	0xf6030700,
-	0x04bd000b,
-/* 0x0688: ih_no_other */
-	0xf6010040,
-	0x04bd000a,
-	0xe0fcf0fc,
-	0xb0fcd0fc,
-	0x90fca0fc,
-	0x88fe80fc,
-	0xf480fc00,
-	0x01f80032,
-/* 0x06a8: ctx_4170s */
-	0xb210f5f0,
-	0x41708eff,
-	0x008f7e40,
-/* 0x06b7: ctx_4170w */
-	0x8e00f800,
-	0x7e404170,
-	0xb2000065,
-	0x10f4f0ff,
-	0xf8f31bf4,
-/* 0x06c9: ctx_redswitch */
-	0x02004e00,
-	0xf040e5f0,
-	0xe5f020e5,
-	0x85008010,
-	0x000ef601,
-	0x080f04bd,
-/* 0x06e0: ctx_redswitch_delay */
-	0xf401f2b6,
-	0xe5f1fd1b,
-	0xe5f10400,
-	0x00800100,
-	0x0ef60185,
-	0xf804bd00,
-/* 0x06f9: ctx_86c */
-	0x23008000,
-	0x000ff602,
-	0xffb204bd,
-	0x408a148e,
-	0x00008f7e,
-	0x8c8effb2,
-	0x8f7e41a8,
-	0x00f80000,
-/* 0x0718: ctx_mem */
-	0x02840080,
-	0xbd000ff6,
-/* 0x0721: ctx_mem_wait */
-	0x84008f04,
-	0x00ffcf02,
-	0xf405fffd,
-	0x00f8f61b,
-/* 0x0730: ctx_load */
-	0x99f094bd,
-	0x37008005,
-	0x0009f602,
-	0x0c0a04bd,
-	0x0000b87e,
-	0x0080f4bd,
-	0x0ff60289,
-	0x8004bd00,
-	0xf602c100,
-	0x04bd0002,
-	0x02830080,
-	0xbd0002f6,
-	0x7e070f04,
-	0x80000718,
-	0xf602c000,
-	0x04bd0002,
-	0xf0000bfe,
-	0x24b61f2a,
-	0x0220b604,
-	0x99f094bd,
-	0x37008008,
-	0x0009f602,
-	0x008004bd,
-	0x02f60281,
-	0xd204bd00,
-	0x80000000,
-	0x800225f0,
-	0xf6028800,
-	0x04bd0002,
-	0x00421001,
-	0x0223f002,
-	0xf80512fa,
-	0xf094bd03,
-	0x00800899,
-	0x09f60217,
-	0x9804bd00,
-	0x14b68101,
-	0x80029818,
-	0xfd0825b6,
-	0x01b50512,
-	0xf094bd16,
-	0x00800999,
-	0x09f60237,
-	0x8004bd00,
-	0xf6028100,
-	0x04bd0001,
-	0x00800102,
-	0x02f60288,
-	0x4104bd00,
-	0x13f00100,
-	0x0501fa06,
-	0x94bd03f8,
-	0x800999f0,
-	0xf6021700,
-	0x04bd0009,
-	0x99f094bd,
-	0x17008005,
-	0x0009f602,
-	0x00f804bd,
-/* 0x081c: ctx_chan */
-	0x0007307e,
-	0xb87e0c0a,
-	0x050f0000,
-	0x0007187e,
-/* 0x082e: ctx_mmio_exec */
-	0x039800f8,
-	0x81008041,
-	0x0003f602,
-	0x34bd04bd,
-/* 0x083c: ctx_mmio_loop */
-	0xf4ff34c4,
-	0x00450e1b,
-	0x0653f002,
-	0xf80535fa,
-/* 0x084d: ctx_mmio_pull */
-	0x804e9803,
-	0x7e814f98,
-	0xb600008f,
-	0x12b60830,
-	0xdf1bf401,
-/* 0x0860: ctx_mmio_done */
-	0x80160398,
-	0xf6028100,
-	0x04bd0003,
-	0x414000b5,
-	0x13f00100,
-	0x0601fa06,
-	0x00f803f8,
-/* 0x087c: ctx_xfer */
-	0x0080040e,
-	0x0ef60302,
-/* 0x0887: ctx_xfer_idle */
-	0x8e04bd00,
-	0xcf030000,
-	0xe4f100ee,
-	0x1bf42000,
-	0x0611f4f5,
-/* 0x089b: ctx_xfer_pre */
-	0x0f0c02f4,
-	0x06f97e10,
-	0x1b11f400,
-/* 0x08a4: ctx_xfer_pre_load */
-	0xa87e020f,
-	0xb77e0006,
-	0xc97e0006,
-	0xf4bd0006,
-	0x0006a87e,
-	0x0007307e,
-/* 0x08bc: ctx_xfer_exec */
-	0xbd160198,
-	0x05008024,
-	0x0002f601,
-	0x1fb204bd,
-	0x41a5008e,
-	0x00008f7e,
-	0xf001fcf0,
-	0x24b6022c,
-	0x05f2fd01,
-	0x048effb2,
-	0x8f7e41a5,
-	0x167e0000,
-	0x24bd0002,
-	0x0247fc80,
-	0xbd0002f6,
-	0x012cf004,
-	0x800320b6,
-	0xf6024afc,
-	0x04bd0002,
-	0xf001acf0,
-	0x000b06a5,
-	0x98000c98,
-	0x000e010d,
-	0x00013d7e,
-	0xec7e080a,
-	0x0a7e0000,
-	0x01f40002,
-	0x7e0c0a12,
-	0x0f0000b8,
-	0x07187e05,
-	0x2d02f400,
-/* 0x0938: ctx_xfer_post */
-	0xa87e020f,
-	0xf4bd0006,
-	0x0006f97e,
-	0x0002277e,
-	0x0006b77e,
-	0xa87ef4bd,
-	0x11f40006,
-	0x40019810,
-	0xf40511fd,
-	0x2e7e070b,
-/* 0x0962: ctx_xfer_no_post_mmio */
-/* 0x0962: ctx_xfer_done */
-	0x00f80008,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
deleted file mode 100644
index 3ff52ba..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GF100
-#include "macros.fuc"
-
-.section #nvc0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvc0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
deleted file mode 100644
index 92dfe6a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
+++ /dev/null
@@ -1,1047 +0,0 @@
-uint32_t nvc0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
-	0x00000300,
-/* 0x0004: hub_mmio_list_tail */
-	0x00000304,
-/* 0x0008: gpc_count */
-	0x00000000,
-/* 0x000c: rop_count */
-	0x00000000,
-/* 0x0010: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: ctx_current */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
-	0x00000000,
-/* 0x0104: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: xfer_data */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: hub_mmio_list_base */
-	0x0417e91c,
-};
-
-uint32_t nvc0_grhub_code[] = {
-	0x039b0ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0x07f100f8,
-	0x03f00500,
-	0x000fd002,
-	0xf7f004bd,
-	0x0007f101,
-	0x0303f007,
-	0xbd000fd0,
-/* 0x039b: init */
-	0xbd00f804,
-	0x0007fe04,
-	0x420017f1,
-	0xcf0013f0,
-	0x11e70011,
-	0x14b60109,
-	0x0014fe08,
-	0xf10227f0,
-	0xf0120007,
-	0x02d00003,
-	0xf104bd00,
-	0xfe06c817,
-	0x24bd0010,
-	0x070007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0x200327f1,
-	0x010007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200427f1,
-	0x010407f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200b27f1,
-	0x010807f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200c27f1,
-	0x011c07f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1010392,
-	0xf0090007,
-	0x03d00303,
-	0xf104bd00,
-	0xf0870427,
-	0x07f10023,
-	0x03f00400,
-	0x0002d000,
-	0x27f004bd,
-	0x0007f104,
-	0x0003f003,
-	0xbd0002d0,
-	0x1031f404,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xfeb96821,
-	0x90f1c702,
-	0xf0030180,
-	0x0f801ff4,
-	0x0117f002,
-	0xb6041fbb,
-	0x07f10112,
-	0x03f00300,
-	0x0001d001,
-	0x07f104bd,
-	0x03f00400,
-	0x0001d001,
-	0x17f104bd,
-	0xf7f00100,
-	0x0d21f502,
-	0x1f21f508,
-	0x10f7f008,
-	0x086c21f5,
-	0x98000e98,
-	0x21f5010f,
-	0x14950150,
-	0x0007f108,
-	0x0103f0c0,
-	0xbd0004d0,
-	0x0007f104,
-	0x0103f0c1,
-	0xbd0004d0,
-	0x0030b704,
-	0x001fbb13,
-	0xf102f5b6,
-	0xf0d30007,
-	0x0fd00103,
-	0xb604bd00,
-	0x10b60815,
-	0x0814b601,
-	0xf5021fb9,
-	0xbb02d321,
-	0x0398001f,
-	0x0047f102,
-	0x5043f020,
-/* 0x04f4: init_gpc */
-	0x08044ea0,
-	0xf4021fb9,
-	0x4ea09d21,
-	0xf4bd010c,
-	0xa09d21f4,
-	0xf401044e,
-	0x4ea09d21,
-	0xf7f00100,
-	0x9d21f402,
-	0x08004ea0,
-/* 0x051c: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x00f7f0be,
-	0x086c21f5,
-	0xf500f7f0,
-	0xf1080d21,
-	0xf0010007,
-	0x01d00203,
-	0xbd04bd00,
-	0x1f19f014,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0001,
-/* 0x0564: main */
-	0xf40031f4,
-	0xd7f00028,
-	0x3921f410,
-	0xb1f401f4,
-	0xf54001e4,
-	0xbd00e91b,
-	0x0499f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xc00017f1,
-	0xcf0213f0,
-	0x27f10011,
-	0x23f0c100,
-	0x0022cf02,
-	0xf51f13c8,
-	0xc800890b,
-	0x0bf41f23,
-	0xb920f962,
-	0x94bd0212,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x31f40132,
-	0x4021f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x20fc04bd,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0131f404,
-	0x0a4021f5,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f017,
-	0xbd0009d0,
-	0x330ef404,
-/* 0x060c: chsw_prev_no_next */
-	0x12b920f9,
-	0x0132f402,
-	0xf50232f4,
-	0xfc0a4021,
-	0x0007f120,
-	0x0203f0c0,
-	0xbd0002d0,
-	0x130ef404,
-/* 0x062c: chsw_no_prev */
-	0xf41f23c8,
-	0x31f40d0b,
-	0x0232f401,
-	0x0a4021f5,
-/* 0x063c: chsw_done */
-	0xf10127f0,
-	0xf0c30007,
-	0x02d00203,
-	0xbd04bd00,
-	0x0499f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
-	0xf401e4b0,
-	0xf2b90d1b,
-	0xd021f502,
-	0x460ef409,
-/* 0x0670: main_not_ctx_chan */
-	0xf402e4b0,
-	0x94bd321b,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x32f40132,
-	0x4021f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
-	0x10ef9411,
-	0xf501f5f0,
-	0xf5037e21,
-/* 0x06b3: main_done */
-	0xbdfeb50e,
-	0x1f29f024,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xfea00ef5,
-/* 0x06c8: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x10d7f030,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xb70421f4,
-	0xf00400b0,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x071a: ih_no_fifo */
-	0xabe404bd,
-	0x0bf40100,
-	0x10d7f00d,
-	0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
-	0xe40421f4,
-	0xf40400ab,
-	0xe7f16c0b,
-	0xe3f00708,
-	0x6821f440,
-	0xf102ffb9,
-	0xf0040007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf00704e7,
-	0x21f440e3,
-	0x02ffb968,
-	0x030007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0x9450fec7,
-	0xf7f102ee,
-	0xf3f00700,
-	0x00efbb40,
-	0xf16821f4,
-	0xf0020007,
-	0x0fd00203,
-	0xf004bd00,
-	0x21f503f7,
-	0xb7f1037e,
-	0xbfb90100,
-	0x44e7f102,
-	0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
-	0xf19d21f4,
-	0xbd0504b7,
-	0xb4abffb0,
-	0xf10f0bf4,
-	0xf0070007,
-	0x0bd00303,
-/* 0x07b3: ih_no_other */
-	0xf104bd00,
-	0xf0010007,
-	0x0ad00003,
-	0xfc04bd00,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x07d7: ctx_4160s */
-	0xf001f800,
-	0xffb901f7,
-	0x60e7f102,
-	0x40e3f041,
-/* 0x07e7: ctx_4160s_wait */
-	0xf19d21f4,
-	0xf04160e7,
-	0x21f440e3,
-	0x02ffb968,
-	0xf404ffc8,
-	0x00f8f00b,
-/* 0x07fc: ctx_4160c */
-	0xffb9f4bd,
-	0x60e7f102,
-	0x40e3f041,
-	0xf89d21f4,
-/* 0x080d: ctx_4170s */
-	0x10f5f000,
-	0xf102ffb9,
-	0xf04170e7,
-	0x21f440e3,
-/* 0x081f: ctx_4170w */
-	0xf100f89d,
-	0xf04170e7,
-	0x21f440e3,
-	0x02ffb968,
-	0xf410f4f0,
-	0x00f8f01b,
-/* 0x0834: ctx_redswitch */
-	0x0200e7f1,
-	0xf040e5f0,
-	0xe5f020e5,
-	0x0007f110,
-	0x0103f085,
-	0xbd000ed0,
-	0x08f7f004,
-/* 0x0850: ctx_redswitch_delay */
-	0xf401f2b6,
-	0xe5f1fd1b,
-	0xe5f10400,
-	0x07f10100,
-	0x03f08500,
-	0x000ed001,
-	0x00f804bd,
-/* 0x086c: ctx_86c */
-	0x1b0007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0xf102ffb9,
-	0xf08a14e7,
-	0x21f440e3,
-	0x02ffb99d,
-	0xa86ce7f1,
-	0xf441e3f0,
-	0x00f89d21,
-/* 0x0894: ctx_mem */
-	0x840007f1,
-	0xd00203f0,
-	0x04bd000f,
-/* 0x08a0: ctx_mem_wait */
-	0x8400f7f1,
-	0xcf02f3f0,
-	0xfffd00ff,
-	0xf31bf405,
-/* 0x08b2: ctx_load */
-	0x94bd00f8,
-	0xf10599f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf004bd00,
-	0x21f40ca7,
-	0xf1f4bdd0,
-	0xf0890007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf0c10007,
-	0x02d00203,
-	0xf104bd00,
-	0xf0830007,
-	0x02d00203,
-	0xf004bd00,
-	0x21f507f7,
-	0x07f10894,
-	0x03f0c000,
-	0x0002d002,
-	0x0bfe04bd,
-	0x1f2af000,
-	0xb60424b6,
-	0x94bd0220,
-	0xf10899f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf104bd00,
-	0xf0810007,
-	0x02d00203,
-	0xf104bd00,
-	0xf1000027,
-	0xf0800023,
-	0x07f10225,
-	0x03f08800,
-	0x0002d002,
-	0x17f004bd,
-	0x0027f110,
-	0x0223f002,
-	0xf80512fa,
-	0xf094bd03,
-	0x07f10899,
-	0x03f01700,
-	0x0009d002,
-	0x019804bd,
-	0x1814b681,
-	0xb6800298,
-	0x12fd0825,
-	0x16018005,
-	0x99f094bd,
-	0x0007f109,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f081,
-	0xbd0001d0,
-	0x0127f004,
-	0x880007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0x010017f1,
-	0xfa0613f0,
-	0x03f80501,
-	0x99f094bd,
-	0x0007f109,
-	0x0203f017,
-	0xbd0009d0,
-	0xf094bd04,
-	0x07f10599,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x09d0: ctx_chan */
-	0x07d721f5,
-	0x08b221f5,
-	0xf40ca7f0,
-	0xf7f0d021,
-	0x9421f505,
-	0xfc21f508,
-/* 0x09eb: ctx_mmio_exec */
-	0x9800f807,
-	0x07f14103,
-	0x03f08100,
-	0x0003d002,
-	0x34bd04bd,
-/* 0x09fc: ctx_mmio_loop */
-	0xf4ff34c4,
-	0x57f10f1b,
-	0x53f00200,
-	0x0535fa06,
-/* 0x0a0e: ctx_mmio_pull */
-	0x4e9803f8,
-	0x814f9880,
-	0xb69d21f4,
-	0x12b60830,
-	0xdf1bf401,
-/* 0x0a20: ctx_mmio_done */
-	0xf1160398,
-	0xf0810007,
-	0x03d00203,
-	0x8004bd00,
-	0x17f14000,
-	0x13f00100,
-	0x0601fa06,
-	0x00f803f8,
-/* 0x0a40: ctx_xfer */
-	0xf104e7f0,
-	0xf0020007,
-	0x0ed00303,
-/* 0x0a4f: ctx_xfer_idle */
-	0xf104bd00,
-	0xf00000e7,
-	0xeecf03e3,
-	0x00e4f100,
-	0xf21bf420,
-	0xf40611f4,
-/* 0x0a66: ctx_xfer_pre */
-	0xf7f01102,
-	0x6c21f510,
-	0xd721f508,
-	0x1c11f407,
-/* 0x0a74: ctx_xfer_pre_load */
-	0xf502f7f0,
-	0xf5080d21,
-	0xf5081f21,
-	0xbd083421,
-	0x0d21f5f4,
-	0xb221f508,
-/* 0x0a8d: ctx_xfer_exec */
-	0x16019808,
-	0x07f124bd,
-	0x03f00500,
-	0x0002d001,
-	0x1fb904bd,
-	0x00e7f102,
-	0x41e3f0a5,
-	0xf09d21f4,
-	0x2cf001fc,
-	0x0124b602,
-	0xb905f2fd,
-	0xe7f102ff,
-	0xe3f0a504,
-	0x9d21f441,
-	0x026a21f5,
-	0x07f124bd,
-	0x03f047fc,
-	0x0002d002,
-	0x2cf004bd,
-	0x0320b601,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf001acf0,
-	0xb7f006a5,
-	0x000c9800,
-	0xf0010d98,
-	0x21f500e7,
-	0xa7f0016f,
-	0x1021f508,
-	0x5e21f501,
-	0x1301f402,
-	0xf40ca7f0,
-	0xf7f0d021,
-	0x9421f505,
-	0x3202f408,
-/* 0x0b1c: ctx_xfer_post */
-	0xf502f7f0,
-	0xbd080d21,
-	0x6c21f5f4,
-	0x7f21f508,
-	0x1f21f502,
-	0xf5f4bd08,
-	0xf4080d21,
-	0x01981011,
-	0x0511fd40,
-	0xf5070bf4,
-/* 0x0b47: ctx_xfer_no_post_mmio */
-	0xf509eb21,
-/* 0x0b4b: ctx_xfer_done */
-	0xf807fc21,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
deleted file mode 100644
index afbe03a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GF117
-#include "macros.fuc"
-
-.section #nvd7_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvd7_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
deleted file mode 100644
index 62b0c76..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
+++ /dev/null
@@ -1,1047 +0,0 @@
-uint32_t nvd7_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
-	0x00000300,
-/* 0x0004: hub_mmio_list_tail */
-	0x00000304,
-/* 0x0008: gpc_count */
-	0x00000000,
-/* 0x000c: rop_count */
-	0x00000000,
-/* 0x0010: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: ctx_current */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
-	0x00000000,
-/* 0x0104: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: xfer_data */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: hub_mmio_list_base */
-	0x0417e91c,
-};
-
-uint32_t nvd7_grhub_code[] = {
-	0x039b0ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0x07f100f8,
-	0x03f00500,
-	0x000fd002,
-	0xf7f004bd,
-	0x0007f101,
-	0x0303f007,
-	0xbd000fd0,
-/* 0x039b: init */
-	0xbd00f804,
-	0x0007fe04,
-	0x420017f1,
-	0xcf0013f0,
-	0x11e70011,
-	0x14b60109,
-	0x0014fe08,
-	0xf10227f0,
-	0xf0120007,
-	0x02d00003,
-	0xf104bd00,
-	0xfe06c817,
-	0x24bd0010,
-	0x070007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0x200327f1,
-	0x010007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200427f1,
-	0x010407f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200b27f1,
-	0x010807f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200c27f1,
-	0x011c07f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1010392,
-	0xf0090007,
-	0x03d00303,
-	0xf104bd00,
-	0xf0870427,
-	0x07f10023,
-	0x03f00400,
-	0x0002d000,
-	0x27f004bd,
-	0x0007f104,
-	0x0003f003,
-	0xbd0002d0,
-	0x1031f404,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xfeb96821,
-	0x90f1c702,
-	0xf0030180,
-	0x0f801ff4,
-	0x0117f002,
-	0xb6041fbb,
-	0x07f10112,
-	0x03f00300,
-	0x0001d001,
-	0x07f104bd,
-	0x03f00400,
-	0x0001d001,
-	0x17f104bd,
-	0xf7f00100,
-	0x0d21f502,
-	0x1f21f508,
-	0x10f7f008,
-	0x086c21f5,
-	0x98000e98,
-	0x21f5010f,
-	0x14950150,
-	0x0007f108,
-	0x0103f0c0,
-	0xbd0004d0,
-	0x0007f104,
-	0x0103f0c1,
-	0xbd0004d0,
-	0x0030b704,
-	0x001fbb13,
-	0xf102f5b6,
-	0xf0d30007,
-	0x0fd00103,
-	0xb604bd00,
-	0x10b60815,
-	0x0814b601,
-	0xf5021fb9,
-	0xbb02d321,
-	0x0398001f,
-	0x0047f102,
-	0x5043f020,
-/* 0x04f4: init_gpc */
-	0x08044ea0,
-	0xf4021fb9,
-	0x4ea09d21,
-	0xf4bd010c,
-	0xa09d21f4,
-	0xf401044e,
-	0x4ea09d21,
-	0xf7f00100,
-	0x9d21f402,
-	0x08004ea0,
-/* 0x051c: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x00f7f0be,
-	0x086c21f5,
-	0xf500f7f0,
-	0xf1080d21,
-	0xf0010007,
-	0x01d00203,
-	0xbd04bd00,
-	0x1f19f014,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0001,
-/* 0x0564: main */
-	0xf40031f4,
-	0xd7f00028,
-	0x3921f410,
-	0xb1f401f4,
-	0xf54001e4,
-	0xbd00e91b,
-	0x0499f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xc00017f1,
-	0xcf0213f0,
-	0x27f10011,
-	0x23f0c100,
-	0x0022cf02,
-	0xf51f13c8,
-	0xc800890b,
-	0x0bf41f23,
-	0xb920f962,
-	0x94bd0212,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x31f40132,
-	0x4021f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x20fc04bd,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0131f404,
-	0x0a4021f5,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f017,
-	0xbd0009d0,
-	0x330ef404,
-/* 0x060c: chsw_prev_no_next */
-	0x12b920f9,
-	0x0132f402,
-	0xf50232f4,
-	0xfc0a4021,
-	0x0007f120,
-	0x0203f0c0,
-	0xbd0002d0,
-	0x130ef404,
-/* 0x062c: chsw_no_prev */
-	0xf41f23c8,
-	0x31f40d0b,
-	0x0232f401,
-	0x0a4021f5,
-/* 0x063c: chsw_done */
-	0xf10127f0,
-	0xf0c30007,
-	0x02d00203,
-	0xbd04bd00,
-	0x0499f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
-	0xf401e4b0,
-	0xf2b90d1b,
-	0xd021f502,
-	0x460ef409,
-/* 0x0670: main_not_ctx_chan */
-	0xf402e4b0,
-	0x94bd321b,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x32f40132,
-	0x4021f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
-	0x10ef9411,
-	0xf501f5f0,
-	0xf5037e21,
-/* 0x06b3: main_done */
-	0xbdfeb50e,
-	0x1f29f024,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xfea00ef5,
-/* 0x06c8: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x10d7f030,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xb70421f4,
-	0xf00400b0,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x071a: ih_no_fifo */
-	0xabe404bd,
-	0x0bf40100,
-	0x10d7f00d,
-	0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
-	0xe40421f4,
-	0xf40400ab,
-	0xe7f16c0b,
-	0xe3f00708,
-	0x6821f440,
-	0xf102ffb9,
-	0xf0040007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf00704e7,
-	0x21f440e3,
-	0x02ffb968,
-	0x030007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0x9450fec7,
-	0xf7f102ee,
-	0xf3f00700,
-	0x00efbb40,
-	0xf16821f4,
-	0xf0020007,
-	0x0fd00203,
-	0xf004bd00,
-	0x21f503f7,
-	0xb7f1037e,
-	0xbfb90100,
-	0x44e7f102,
-	0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
-	0xf19d21f4,
-	0xbd0504b7,
-	0xb4abffb0,
-	0xf10f0bf4,
-	0xf0070007,
-	0x0bd00303,
-/* 0x07b3: ih_no_other */
-	0xf104bd00,
-	0xf0010007,
-	0x0ad00003,
-	0xfc04bd00,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x07d7: ctx_4160s */
-	0xf001f800,
-	0xffb901f7,
-	0x60e7f102,
-	0x40e3f041,
-/* 0x07e7: ctx_4160s_wait */
-	0xf19d21f4,
-	0xf04160e7,
-	0x21f440e3,
-	0x02ffb968,
-	0xf404ffc8,
-	0x00f8f00b,
-/* 0x07fc: ctx_4160c */
-	0xffb9f4bd,
-	0x60e7f102,
-	0x40e3f041,
-	0xf89d21f4,
-/* 0x080d: ctx_4170s */
-	0x10f5f000,
-	0xf102ffb9,
-	0xf04170e7,
-	0x21f440e3,
-/* 0x081f: ctx_4170w */
-	0xf100f89d,
-	0xf04170e7,
-	0x21f440e3,
-	0x02ffb968,
-	0xf410f4f0,
-	0x00f8f01b,
-/* 0x0834: ctx_redswitch */
-	0x0200e7f1,
-	0xf040e5f0,
-	0xe5f020e5,
-	0x0007f110,
-	0x0103f085,
-	0xbd000ed0,
-	0x08f7f004,
-/* 0x0850: ctx_redswitch_delay */
-	0xf401f2b6,
-	0xe5f1fd1b,
-	0xe5f10400,
-	0x07f10100,
-	0x03f08500,
-	0x000ed001,
-	0x00f804bd,
-/* 0x086c: ctx_86c */
-	0x1b0007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0xf102ffb9,
-	0xf08a14e7,
-	0x21f440e3,
-	0x02ffb99d,
-	0xa86ce7f1,
-	0xf441e3f0,
-	0x00f89d21,
-/* 0x0894: ctx_mem */
-	0x840007f1,
-	0xd00203f0,
-	0x04bd000f,
-/* 0x08a0: ctx_mem_wait */
-	0x8400f7f1,
-	0xcf02f3f0,
-	0xfffd00ff,
-	0xf31bf405,
-/* 0x08b2: ctx_load */
-	0x94bd00f8,
-	0xf10599f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf004bd00,
-	0x21f40ca7,
-	0xf1f4bdd0,
-	0xf0890007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf0c10007,
-	0x02d00203,
-	0xf104bd00,
-	0xf0830007,
-	0x02d00203,
-	0xf004bd00,
-	0x21f507f7,
-	0x07f10894,
-	0x03f0c000,
-	0x0002d002,
-	0x0bfe04bd,
-	0x1f2af000,
-	0xb60424b6,
-	0x94bd0220,
-	0xf10899f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf104bd00,
-	0xf0810007,
-	0x02d00203,
-	0xf104bd00,
-	0xf1000027,
-	0xf0800023,
-	0x07f10225,
-	0x03f08800,
-	0x0002d002,
-	0x17f004bd,
-	0x0027f110,
-	0x0223f002,
-	0xf80512fa,
-	0xf094bd03,
-	0x07f10899,
-	0x03f01700,
-	0x0009d002,
-	0x019804bd,
-	0x1814b681,
-	0xb6800298,
-	0x12fd0825,
-	0x16018005,
-	0x99f094bd,
-	0x0007f109,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f081,
-	0xbd0001d0,
-	0x0127f004,
-	0x880007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0x010017f1,
-	0xfa0613f0,
-	0x03f80501,
-	0x99f094bd,
-	0x0007f109,
-	0x0203f017,
-	0xbd0009d0,
-	0xf094bd04,
-	0x07f10599,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x09d0: ctx_chan */
-	0x07d721f5,
-	0x08b221f5,
-	0xf40ca7f0,
-	0xf7f0d021,
-	0x9421f505,
-	0xfc21f508,
-/* 0x09eb: ctx_mmio_exec */
-	0x9800f807,
-	0x07f14103,
-	0x03f08100,
-	0x0003d002,
-	0x34bd04bd,
-/* 0x09fc: ctx_mmio_loop */
-	0xf4ff34c4,
-	0x57f10f1b,
-	0x53f00200,
-	0x0535fa06,
-/* 0x0a0e: ctx_mmio_pull */
-	0x4e9803f8,
-	0x814f9880,
-	0xb69d21f4,
-	0x12b60830,
-	0xdf1bf401,
-/* 0x0a20: ctx_mmio_done */
-	0xf1160398,
-	0xf0810007,
-	0x03d00203,
-	0x8004bd00,
-	0x17f14000,
-	0x13f00100,
-	0x0601fa06,
-	0x00f803f8,
-/* 0x0a40: ctx_xfer */
-	0xf104e7f0,
-	0xf0020007,
-	0x0ed00303,
-/* 0x0a4f: ctx_xfer_idle */
-	0xf104bd00,
-	0xf00000e7,
-	0xeecf03e3,
-	0x00e4f100,
-	0xf21bf420,
-	0xf40611f4,
-/* 0x0a66: ctx_xfer_pre */
-	0xf7f01102,
-	0x6c21f510,
-	0xd721f508,
-	0x1c11f407,
-/* 0x0a74: ctx_xfer_pre_load */
-	0xf502f7f0,
-	0xf5080d21,
-	0xf5081f21,
-	0xbd083421,
-	0x0d21f5f4,
-	0xb221f508,
-/* 0x0a8d: ctx_xfer_exec */
-	0x16019808,
-	0x07f124bd,
-	0x03f00500,
-	0x0002d001,
-	0x1fb904bd,
-	0x00e7f102,
-	0x41e3f0a5,
-	0xf09d21f4,
-	0x2cf001fc,
-	0x0124b602,
-	0xb905f2fd,
-	0xe7f102ff,
-	0xe3f0a504,
-	0x9d21f441,
-	0x026a21f5,
-	0x07f124bd,
-	0x03f047fc,
-	0x0002d002,
-	0x2cf004bd,
-	0x0320b601,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf001acf0,
-	0xb7f006a5,
-	0x000c9800,
-	0xf0010d98,
-	0x21f500e7,
-	0xa7f0016f,
-	0x1021f508,
-	0x5e21f501,
-	0x1301f402,
-	0xf40ca7f0,
-	0xf7f0d021,
-	0x9421f505,
-	0x3202f408,
-/* 0x0b1c: ctx_xfer_post */
-	0xf502f7f0,
-	0xbd080d21,
-	0x6c21f5f4,
-	0x7f21f508,
-	0x1f21f502,
-	0xf5f4bd08,
-	0xf4080d21,
-	0x01981011,
-	0x0511fd40,
-	0xf5070bf4,
-/* 0x0b47: ctx_xfer_no_post_mmio */
-	0xf509eb21,
-/* 0x0b4b: ctx_xfer_done */
-	0xf807fc21,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
deleted file mode 100644
index d4840f1..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK100
-#include "macros.fuc"
-
-.section #nve0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nve0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
deleted file mode 100644
index 51c3797..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
+++ /dev/null
@@ -1,1044 +0,0 @@
-uint32_t nve0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
-	0x00000300,
-/* 0x0004: hub_mmio_list_tail */
-	0x00000304,
-/* 0x0008: gpc_count */
-	0x00000000,
-/* 0x000c: rop_count */
-	0x00000000,
-/* 0x0010: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: ctx_current */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
-	0x00000000,
-/* 0x0104: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: xfer_data */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: hub_mmio_list_base */
-	0x0417e91c,
-};
-
-uint32_t nve0_grhub_code[] = {
-	0x039b0ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0x07f100f8,
-	0x03f00500,
-	0x000fd002,
-	0xf7f004bd,
-	0x0007f101,
-	0x0303f007,
-	0xbd000fd0,
-/* 0x039b: init */
-	0xbd00f804,
-	0x0007fe04,
-	0x420017f1,
-	0xcf0013f0,
-	0x11e70011,
-	0x14b60109,
-	0x0014fe08,
-	0xf10227f0,
-	0xf0120007,
-	0x02d00003,
-	0xf104bd00,
-	0xfe06c817,
-	0x24bd0010,
-	0x070007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0x200327f1,
-	0x010007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200427f1,
-	0x010407f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200b27f1,
-	0x010807f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200c27f1,
-	0x011c07f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1010392,
-	0xf0090007,
-	0x03d00303,
-	0xf104bd00,
-	0xf0870427,
-	0x07f10023,
-	0x03f00400,
-	0x0002d000,
-	0x27f004bd,
-	0x0007f104,
-	0x0003f003,
-	0xbd0002d0,
-	0x1031f404,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xfeb96821,
-	0x90f1c702,
-	0xf0030180,
-	0x0f801ff4,
-	0x0117f002,
-	0xb6041fbb,
-	0x07f10112,
-	0x03f00300,
-	0x0001d001,
-	0x07f104bd,
-	0x03f00400,
-	0x0001d001,
-	0x17f104bd,
-	0xf7f00100,
-	0xd721f502,
-	0xe921f507,
-	0x10f7f007,
-	0x083621f5,
-	0x98000e98,
-	0x21f5010f,
-	0x14950150,
-	0x0007f108,
-	0x0103f0c0,
-	0xbd0004d0,
-	0x0007f104,
-	0x0103f0c1,
-	0xbd0004d0,
-	0x0030b704,
-	0x001fbb13,
-	0xf102f5b6,
-	0xf0d30007,
-	0x0fd00103,
-	0xb604bd00,
-	0x10b60815,
-	0x0814b601,
-	0xf5021fb9,
-	0xbb02d321,
-	0x0398001f,
-	0x0047f102,
-	0x5043f020,
-/* 0x04f4: init_gpc */
-	0x08044ea0,
-	0xf4021fb9,
-	0x4ea09d21,
-	0xf4bd010c,
-	0xa09d21f4,
-	0xf401044e,
-	0x4ea09d21,
-	0xf7f00100,
-	0x9d21f402,
-	0x08004ea0,
-/* 0x051c: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x00f7f0be,
-	0x083621f5,
-	0xf500f7f0,
-	0xf107d721,
-	0xf0010007,
-	0x01d00203,
-	0xbd04bd00,
-	0x1f19f014,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0001,
-/* 0x0564: main */
-	0xf40031f4,
-	0xd7f00028,
-	0x3921f410,
-	0xb1f401f4,
-	0xf54001e4,
-	0xbd00e91b,
-	0x0499f094,
-	0x0f0007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xc00017f1,
-	0xcf0213f0,
-	0x27f10011,
-	0x23f0c100,
-	0x0022cf02,
-	0xf51f13c8,
-	0xc800890b,
-	0x0bf41f23,
-	0xb920f962,
-	0x94bd0212,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x31f40132,
-	0x0221f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x20fc04bd,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0131f404,
-	0x0a0221f5,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f017,
-	0xbd0009d0,
-	0x330ef404,
-/* 0x060c: chsw_prev_no_next */
-	0x12b920f9,
-	0x0132f402,
-	0xf50232f4,
-	0xfc0a0221,
-	0x0007f120,
-	0x0203f0c0,
-	0xbd0002d0,
-	0x130ef404,
-/* 0x062c: chsw_no_prev */
-	0xf41f23c8,
-	0x31f40d0b,
-	0x0232f401,
-	0x0a0221f5,
-/* 0x063c: chsw_done */
-	0xf10127f0,
-	0xf0c30007,
-	0x02d00203,
-	0xbd04bd00,
-	0x0499f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
-	0xf401e4b0,
-	0xf2b90d1b,
-	0x9a21f502,
-	0x460ef409,
-/* 0x0670: main_not_ctx_chan */
-	0xf402e4b0,
-	0x94bd321b,
-	0xf10799f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf404bd00,
-	0x32f40132,
-	0x0221f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
-	0x10ef9411,
-	0xf501f5f0,
-	0xf5037e21,
-/* 0x06b3: main_done */
-	0xbdfeb50e,
-	0x1f29f024,
-	0x080007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xfea00ef5,
-/* 0x06c8: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x10d7f030,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xb70421f4,
-	0xf00400b0,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x071a: ih_no_fifo */
-	0xabe404bd,
-	0x0bf40100,
-	0x10d7f00d,
-	0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
-	0xe40421f4,
-	0xf40400ab,
-	0xe7f16c0b,
-	0xe3f00708,
-	0x6821f440,
-	0xf102ffb9,
-	0xf0040007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf00704e7,
-	0x21f440e3,
-	0x02ffb968,
-	0x030007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0x9450fec7,
-	0xf7f102ee,
-	0xf3f00700,
-	0x00efbb40,
-	0xf16821f4,
-	0xf0020007,
-	0x0fd00203,
-	0xf004bd00,
-	0x21f503f7,
-	0xb7f1037e,
-	0xbfb90100,
-	0x44e7f102,
-	0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
-	0xf19d21f4,
-	0xbd0504b7,
-	0xb4abffb0,
-	0xf10f0bf4,
-	0xf0070007,
-	0x0bd00303,
-/* 0x07b3: ih_no_other */
-	0xf104bd00,
-	0xf0010007,
-	0x0ad00003,
-	0xfc04bd00,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x07d7: ctx_4170s */
-	0xf001f800,
-	0xffb910f5,
-	0x70e7f102,
-	0x40e3f041,
-	0xf89d21f4,
-/* 0x07e9: ctx_4170w */
-	0x70e7f100,
-	0x40e3f041,
-	0xb96821f4,
-	0xf4f002ff,
-	0xf01bf410,
-/* 0x07fe: ctx_redswitch */
-	0xe7f100f8,
-	0xe5f00200,
-	0x20e5f040,
-	0xf110e5f0,
-	0xf0850007,
-	0x0ed00103,
-	0xf004bd00,
-/* 0x081a: ctx_redswitch_delay */
-	0xf2b608f7,
-	0xfd1bf401,
-	0x0400e5f1,
-	0x0100e5f1,
-	0x850007f1,
-	0xd00103f0,
-	0x04bd000e,
-/* 0x0836: ctx_86c */
-	0x07f100f8,
-	0x03f01b00,
-	0x000fd002,
-	0xffb904bd,
-	0x14e7f102,
-	0x40e3f08a,
-	0xb99d21f4,
-	0xe7f102ff,
-	0xe3f0a86c,
-	0x9d21f441,
-/* 0x085e: ctx_mem */
-	0x07f100f8,
-	0x03f08400,
-	0x000fd002,
-/* 0x086a: ctx_mem_wait */
-	0xf7f104bd,
-	0xf3f08400,
-	0x00ffcf02,
-	0xf405fffd,
-	0x00f8f31b,
-/* 0x087c: ctx_load */
-	0x99f094bd,
-	0x0007f105,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0ca7f004,
-	0xbdd021f4,
-	0x0007f1f4,
-	0x0203f089,
-	0xbd000fd0,
-	0x0007f104,
-	0x0203f0c1,
-	0xbd0002d0,
-	0x0007f104,
-	0x0203f083,
-	0xbd0002d0,
-	0x07f7f004,
-	0x085e21f5,
-	0xc00007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf0000bfe,
-	0x24b61f2a,
-	0x0220b604,
-	0x99f094bd,
-	0x0007f108,
-	0x0203f00f,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f081,
-	0xbd0002d0,
-	0x0027f104,
-	0x0023f100,
-	0x0225f080,
-	0x880007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf11017f0,
-	0xf0020027,
-	0x12fa0223,
-	0xbd03f805,
-	0x0899f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xb6810198,
-	0x02981814,
-	0x0825b680,
-	0x800512fd,
-	0x94bd1601,
-	0xf10999f0,
-	0xf00f0007,
-	0x09d00203,
-	0xf104bd00,
-	0xf0810007,
-	0x01d00203,
-	0xf004bd00,
-	0x07f10127,
-	0x03f08800,
-	0x0002d002,
-	0x17f104bd,
-	0x13f00100,
-	0x0501fa06,
-	0x94bd03f8,
-	0xf10999f0,
-	0xf0170007,
-	0x09d00203,
-	0xbd04bd00,
-	0x0599f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x099a: ctx_chan */
-	0x21f500f8,
-	0xa7f0087c,
-	0xd021f40c,
-	0xf505f7f0,
-	0xf8085e21,
-/* 0x09ad: ctx_mmio_exec */
-	0x41039800,
-	0x810007f1,
-	0xd00203f0,
-	0x04bd0003,
-/* 0x09be: ctx_mmio_loop */
-	0x34c434bd,
-	0x0f1bf4ff,
-	0x020057f1,
-	0xfa0653f0,
-	0x03f80535,
-/* 0x09d0: ctx_mmio_pull */
-	0x98804e98,
-	0x21f4814f,
-	0x0830b69d,
-	0xf40112b6,
-/* 0x09e2: ctx_mmio_done */
-	0x0398df1b,
-	0x0007f116,
-	0x0203f081,
-	0xbd0003d0,
-	0x40008004,
-	0x010017f1,
-	0xfa0613f0,
-	0x03f80601,
-/* 0x0a02: ctx_xfer */
-	0xe7f000f8,
-	0x0007f104,
-	0x0303f002,
-	0xbd000ed0,
-/* 0x0a11: ctx_xfer_idle */
-	0x00e7f104,
-	0x03e3f000,
-	0xf100eecf,
-	0xf42000e4,
-	0x11f4f21b,
-	0x0d02f406,
-/* 0x0a28: ctx_xfer_pre */
-	0xf510f7f0,
-	0xf4083621,
-/* 0x0a32: ctx_xfer_pre_load */
-	0xf7f01c11,
-	0xd721f502,
-	0xe921f507,
-	0xfe21f507,
-	0xf5f4bd07,
-	0xf507d721,
-/* 0x0a4b: ctx_xfer_exec */
-	0x98087c21,
-	0x24bd1601,
-	0x050007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1021fb9,
-	0xf0a500e7,
-	0x21f441e3,
-	0x01fcf09d,
-	0xb6022cf0,
-	0xf2fd0124,
-	0x02ffb905,
-	0xa504e7f1,
-	0xf441e3f0,
-	0x21f59d21,
-	0x24bd026a,
-	0x47fc07f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xb6012cf0,
-	0x07f10320,
-	0x03f04afc,
-	0x0002d002,
-	0xacf004bd,
-	0x06a5f001,
-	0x9800b7f0,
-	0x0d98000c,
-	0x00e7f001,
-	0x016f21f5,
-	0xf508a7f0,
-	0xf5011021,
-	0xf4025e21,
-	0xa7f01301,
-	0xd021f40c,
-	0xf505f7f0,
-	0xf4085e21,
-/* 0x0ada: ctx_xfer_post */
-	0xf7f02e02,
-	0xd721f502,
-	0xf5f4bd07,
-	0xf5083621,
-	0xf5027f21,
-	0xbd07e921,
-	0xd721f5f4,
-	0x1011f407,
-	0xfd400198,
-	0x0bf40511,
-	0xad21f507,
-/* 0x0b05: ctx_xfer_no_post_mmio */
-/* 0x0b05: ctx_xfer_done */
-	0x0000f809,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
deleted file mode 100644
index ec42ed2..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK110
-#include "macros.fuc"
-
-.section #nvf0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvf0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
deleted file mode 100644
index a0af4b7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
+++ /dev/null
@@ -1,1044 +0,0 @@
-uint32_t nvf0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
-	0x00000300,
-/* 0x0004: hub_mmio_list_tail */
-	0x00000304,
-/* 0x0008: gpc_count */
-	0x00000000,
-/* 0x000c: rop_count */
-	0x00000000,
-/* 0x0010: cmd_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: ctx_current */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
-	0x00000000,
-/* 0x0104: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: xfer_data */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: hub_mmio_list_base */
-	0x0417e91c,
-};
-
-uint32_t nvf0_grhub_code[] = {
-	0x039b0ef5,
-/* 0x0004: queue_put */
-	0x9800d898,
-	0x86f001d9,
-	0x0489b808,
-	0xf00c1bf4,
-	0x21f502f7,
-	0x00f8037e,
-/* 0x001c: queue_put_next */
-	0xb60798c4,
-	0x8dbb0384,
-	0x0880b600,
-	0x80008e80,
-	0x90b6018f,
-	0x0f94f001,
-	0xf801d980,
-/* 0x0039: queue_get */
-	0x0131f400,
-	0x9800d898,
-	0x89b801d9,
-	0x210bf404,
-	0xb60789c4,
-	0x9dbb0394,
-	0x0890b600,
-	0x98009e98,
-	0x80b6019f,
-	0x0f84f001,
-	0xf400d880,
-/* 0x0066: queue_get_done */
-	0x00f80132,
-/* 0x0068: nv_rd32 */
-	0xf002ecb9,
-	0x07f11fc9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x007a: nv_rd32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0xa7f0f31b,
-	0x1021f506,
-	0x00f7f101,
-	0x01f3f0cb,
-	0xf800ffcf,
-/* 0x009d: nv_wr32 */
-	0x0007f100,
-	0x0103f0cc,
-	0xbd000fd0,
-	0x02ecb904,
-	0xf01fc9f0,
-	0x07f11ec9,
-	0x03f0ca00,
-	0x000cd001,
-/* 0x00be: nv_wr32_wait */
-	0xc7f104bd,
-	0xc3f0ca00,
-	0x00cccf01,
-	0xf41fccc8,
-	0x00f8f31b,
-/* 0x00d0: wait_donez */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f037,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x1bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0110: wait_doneo */
-	0x99f094bd,
-	0x0007f100,
-	0x0203f037,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f006,
-	0xbd000ad0,
-/* 0x012d: wait_doneo_e */
-	0x0087f104,
-	0x0183f000,
-	0xff0088cf,
-	0x0bf4888a,
-	0xf094bdf3,
-	0x07f10099,
-	0x03f01700,
-	0x0009d002,
-	0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
-	0xe89894bd,
-	0x1a85b600,
-	0xb60180b6,
-	0x98bb0284,
-	0x04e0b600,
-	0xf404efb8,
-	0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
-	0xbd00f802,
-	0x0199f094,
-	0x370007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xbbfd94bd,
-	0x120bf405,
-	0xc40007f1,
-	0xd00103f0,
-	0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
-	0xfd0099f0,
-	0x0bf405ee,
-	0x0007f11e,
-	0x0103f0c6,
-	0xbd000ed0,
-	0x0007f104,
-	0x0103f0c7,
-	0xbd000fd0,
-	0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
-	0xb600abc8,
-	0xb9f010b4,
-	0x01aec80c,
-	0xfd11e4b6,
-	0x07f105be,
-	0x03f0c500,
-	0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
-	0xe7f104bd,
-	0xe3f0c500,
-	0x00eecf01,
-	0xf41fe4f0,
-	0xce98f30b,
-	0x05e9fd00,
-	0xc80007f1,
-	0xd00103f0,
-	0x04bd000e,
-	0xb804c0b6,
-	0x1bf404cd,
-	0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
-	0xf11f1bf4,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x1fb4f000,
-	0xf410b4b0,
-	0xa7f0f01b,
-	0xd021f405,
-/* 0x0223: mmctx_stop */
-	0xc82b0ef4,
-	0xb4b600ab,
-	0x0cb9f010,
-	0xf112b9f0,
-	0xf0c50007,
-	0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
-	0xf104bd00,
-	0xf0c500b7,
-	0xbbcf01b3,
-	0x12bbc800,
-/* 0x024b: mmctx_done */
-	0xbdf31bf4,
-	0x0199f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x025e: strand_wait */
-	0xa0f900f8,
-	0xf402a7f0,
-	0xa0fcd021,
-/* 0x026a: strand_pre */
-	0x97f000f8,
-	0xfc07f10c,
-	0x0203f04a,
-	0xbd0009d0,
-	0x5e21f504,
-/* 0x027f: strand_post */
-	0xf000f802,
-	0x07f10d97,
-	0x03f04afc,
-	0x0009d002,
-	0x21f504bd,
-	0x00f8025e,
-/* 0x0294: strand_set */
-	0xf10fc7f0,
-	0xf04ffc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f10bc7,
-	0x03f04afc,
-	0x000cd002,
-	0x07f104bd,
-	0x03f04ffc,
-	0x000ed002,
-	0xc7f004bd,
-	0xfc07f10a,
-	0x0203f04a,
-	0xbd000cd0,
-	0x5e21f504,
-/* 0x02d3: strand_ctx_init */
-	0xbd00f802,
-	0x0399f094,
-	0x370007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0x026a21f5,
-	0xf503e7f0,
-	0xbd029421,
-	0xfc07f1c4,
-	0x0203f047,
-	0xbd000cd0,
-	0x01c7f004,
-	0x4afc07f1,
-	0xd00203f0,
-	0x04bd000c,
-	0x025e21f5,
-	0xf1010c92,
-	0xf046fc07,
-	0x0cd00203,
-	0xf004bd00,
-	0x07f102c7,
-	0x03f04afc,
-	0x000cd002,
-	0x21f504bd,
-	0x21f5025e,
-	0x87f1027f,
-	0x83f04200,
-	0x0097f102,
-	0x0293f020,
-	0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
-	0x8ed008fe,
-	0x408ed000,
-	0xb6808acf,
-	0xa0b606a5,
-	0x00eabb01,
-	0xb60480b6,
-	0x1bf40192,
-	0x08e4b6e8,
-	0xbdf2efbc,
-	0x0399f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x037e: error */
-	0x07f100f8,
-	0x03f00500,
-	0x000fd002,
-	0xf7f004bd,
-	0x0007f101,
-	0x0303f007,
-	0xbd000fd0,
-/* 0x039b: init */
-	0xbd00f804,
-	0x0007fe04,
-	0x420017f1,
-	0xcf0013f0,
-	0x11e70011,
-	0x14b60109,
-	0x0014fe08,
-	0xf10227f0,
-	0xf0120007,
-	0x02d00003,
-	0xf104bd00,
-	0xfe06c817,
-	0x24bd0010,
-	0x070007f1,
-	0xd00003f0,
-	0x04bd0002,
-	0x200327f1,
-	0x010007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200427f1,
-	0x010407f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200b27f1,
-	0x010807f1,
-	0xd00103f0,
-	0x04bd0002,
-	0x200c27f1,
-	0x011c07f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1010392,
-	0xf0090007,
-	0x03d00303,
-	0xf104bd00,
-	0xf0870427,
-	0x07f10023,
-	0x03f00400,
-	0x0002d000,
-	0x27f004bd,
-	0x0007f104,
-	0x0003f003,
-	0xbd0002d0,
-	0x1031f404,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xfeb96821,
-	0x90f1c702,
-	0xf0030180,
-	0x0f801ff4,
-	0x0117f002,
-	0xb6041fbb,
-	0x07f10112,
-	0x03f00300,
-	0x0001d001,
-	0x07f104bd,
-	0x03f00400,
-	0x0001d001,
-	0x17f104bd,
-	0xf7f00100,
-	0xd721f502,
-	0xe921f507,
-	0x10f7f007,
-	0x083621f5,
-	0x98000e98,
-	0x21f5010f,
-	0x14950150,
-	0x0007f108,
-	0x0103f0c0,
-	0xbd0004d0,
-	0x0007f104,
-	0x0103f0c1,
-	0xbd0004d0,
-	0x0030b704,
-	0x001fbb13,
-	0xf102f5b6,
-	0xf0d30007,
-	0x0fd00103,
-	0xb604bd00,
-	0x10b60815,
-	0x0814b601,
-	0xf5021fb9,
-	0xbb02d321,
-	0x0398001f,
-	0x0047f102,
-	0x5043f020,
-/* 0x04f4: init_gpc */
-	0x08044ea0,
-	0xf4021fb9,
-	0x4ea09d21,
-	0xf4bd010c,
-	0xa09d21f4,
-	0xf401044e,
-	0x4ea09d21,
-	0xf7f00100,
-	0x9d21f402,
-	0x08004ea0,
-/* 0x051c: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x00f7f0be,
-	0x083621f5,
-	0xf500f7f0,
-	0xf107d721,
-	0xf0010007,
-	0x01d00203,
-	0xbd04bd00,
-	0x1f19f014,
-	0x300007f1,
-	0xd00203f0,
-	0x04bd0001,
-/* 0x0564: main */
-	0xf40031f4,
-	0xd7f00028,
-	0x3921f410,
-	0xb1f401f4,
-	0xf54001e4,
-	0xbd00e91b,
-	0x0499f094,
-	0x370007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xc00017f1,
-	0xcf0213f0,
-	0x27f10011,
-	0x23f0c100,
-	0x0022cf02,
-	0xf51f13c8,
-	0xc800890b,
-	0x0bf41f23,
-	0xb920f962,
-	0x94bd0212,
-	0xf10799f0,
-	0xf0370007,
-	0x09d00203,
-	0xf404bd00,
-	0x31f40132,
-	0x0221f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x20fc04bd,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f037,
-	0xbd0009d0,
-	0x0131f404,
-	0x0a0221f5,
-	0x99f094bd,
-	0x0007f106,
-	0x0203f017,
-	0xbd0009d0,
-	0x330ef404,
-/* 0x060c: chsw_prev_no_next */
-	0x12b920f9,
-	0x0132f402,
-	0xf50232f4,
-	0xfc0a0221,
-	0x0007f120,
-	0x0203f0c0,
-	0xbd0002d0,
-	0x130ef404,
-/* 0x062c: chsw_no_prev */
-	0xf41f23c8,
-	0x31f40d0b,
-	0x0232f401,
-	0x0a0221f5,
-/* 0x063c: chsw_done */
-	0xf10127f0,
-	0xf0c30007,
-	0x02d00203,
-	0xbd04bd00,
-	0x0499f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
-	0xf401e4b0,
-	0xf2b90d1b,
-	0x9a21f502,
-	0x460ef409,
-/* 0x0670: main_not_ctx_chan */
-	0xf402e4b0,
-	0x94bd321b,
-	0xf10799f0,
-	0xf0370007,
-	0x09d00203,
-	0xf404bd00,
-	0x32f40132,
-	0x0221f502,
-	0xf094bd0a,
-	0x07f10799,
-	0x03f01700,
-	0x0009d002,
-	0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
-	0x10ef9411,
-	0xf501f5f0,
-	0xf5037e21,
-/* 0x06b3: main_done */
-	0xbdfeb50e,
-	0x1f29f024,
-	0x300007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xfea00ef5,
-/* 0x06c8: ih */
-	0x88fe80f9,
-	0xf980f901,
-	0xf9a0f990,
-	0xf9d0f9b0,
-	0xbdf0f9e0,
-	0x00a7f104,
-	0x00a3f002,
-	0xc400aacf,
-	0x0bf404ab,
-	0x10d7f030,
-	0x1a00e7f1,
-	0xcf00e3f0,
-	0xf7f100ee,
-	0xf3f01900,
-	0x00ffcf00,
-	0xb70421f4,
-	0xf00400b0,
-	0x07f101e7,
-	0x03f01d00,
-	0x000ed000,
-/* 0x071a: ih_no_fifo */
-	0xabe404bd,
-	0x0bf40100,
-	0x10d7f00d,
-	0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
-	0xe40421f4,
-	0xf40400ab,
-	0xe7f16c0b,
-	0xe3f00708,
-	0x6821f440,
-	0xf102ffb9,
-	0xf0040007,
-	0x0fd00203,
-	0xf104bd00,
-	0xf00704e7,
-	0x21f440e3,
-	0x02ffb968,
-	0x030007f1,
-	0xd00203f0,
-	0x04bd000f,
-	0x9450fec7,
-	0xf7f102ee,
-	0xf3f00700,
-	0x00efbb40,
-	0xf16821f4,
-	0xf0020007,
-	0x0fd00203,
-	0xf004bd00,
-	0x21f503f7,
-	0xb7f1037e,
-	0xbfb90100,
-	0x44e7f102,
-	0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
-	0xf19d21f4,
-	0xbd0504b7,
-	0xb4abffb0,
-	0xf10f0bf4,
-	0xf0070007,
-	0x0bd00303,
-/* 0x07b3: ih_no_other */
-	0xf104bd00,
-	0xf0010007,
-	0x0ad00003,
-	0xfc04bd00,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x07d7: ctx_4170s */
-	0xf001f800,
-	0xffb910f5,
-	0x70e7f102,
-	0x40e3f041,
-	0xf89d21f4,
-/* 0x07e9: ctx_4170w */
-	0x70e7f100,
-	0x40e3f041,
-	0xb96821f4,
-	0xf4f002ff,
-	0xf01bf410,
-/* 0x07fe: ctx_redswitch */
-	0xe7f100f8,
-	0xe5f00200,
-	0x20e5f040,
-	0xf110e5f0,
-	0xf0850007,
-	0x0ed00103,
-	0xf004bd00,
-/* 0x081a: ctx_redswitch_delay */
-	0xf2b608f7,
-	0xfd1bf401,
-	0x0400e5f1,
-	0x0100e5f1,
-	0x850007f1,
-	0xd00103f0,
-	0x04bd000e,
-/* 0x0836: ctx_86c */
-	0x07f100f8,
-	0x03f02300,
-	0x000fd002,
-	0xffb904bd,
-	0x14e7f102,
-	0x40e3f08a,
-	0xb99d21f4,
-	0xe7f102ff,
-	0xe3f0a88c,
-	0x9d21f441,
-/* 0x085e: ctx_mem */
-	0x07f100f8,
-	0x03f08400,
-	0x000fd002,
-/* 0x086a: ctx_mem_wait */
-	0xf7f104bd,
-	0xf3f08400,
-	0x00ffcf02,
-	0xf405fffd,
-	0x00f8f31b,
-/* 0x087c: ctx_load */
-	0x99f094bd,
-	0x0007f105,
-	0x0203f037,
-	0xbd0009d0,
-	0x0ca7f004,
-	0xbdd021f4,
-	0x0007f1f4,
-	0x0203f089,
-	0xbd000fd0,
-	0x0007f104,
-	0x0203f0c1,
-	0xbd0002d0,
-	0x0007f104,
-	0x0203f083,
-	0xbd0002d0,
-	0x07f7f004,
-	0x085e21f5,
-	0xc00007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf0000bfe,
-	0x24b61f2a,
-	0x0220b604,
-	0x99f094bd,
-	0x0007f108,
-	0x0203f037,
-	0xbd0009d0,
-	0x0007f104,
-	0x0203f081,
-	0xbd0002d0,
-	0x0027f104,
-	0x0023f100,
-	0x0225f080,
-	0x880007f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xf11017f0,
-	0xf0020027,
-	0x12fa0223,
-	0xbd03f805,
-	0x0899f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-	0xb6810198,
-	0x02981814,
-	0x0825b680,
-	0x800512fd,
-	0x94bd1601,
-	0xf10999f0,
-	0xf0370007,
-	0x09d00203,
-	0xf104bd00,
-	0xf0810007,
-	0x01d00203,
-	0xf004bd00,
-	0x07f10127,
-	0x03f08800,
-	0x0002d002,
-	0x17f104bd,
-	0x13f00100,
-	0x0501fa06,
-	0x94bd03f8,
-	0xf10999f0,
-	0xf0170007,
-	0x09d00203,
-	0xbd04bd00,
-	0x0599f094,
-	0x170007f1,
-	0xd00203f0,
-	0x04bd0009,
-/* 0x099a: ctx_chan */
-	0x21f500f8,
-	0xa7f0087c,
-	0xd021f40c,
-	0xf505f7f0,
-	0xf8085e21,
-/* 0x09ad: ctx_mmio_exec */
-	0x41039800,
-	0x810007f1,
-	0xd00203f0,
-	0x04bd0003,
-/* 0x09be: ctx_mmio_loop */
-	0x34c434bd,
-	0x0f1bf4ff,
-	0x020057f1,
-	0xfa0653f0,
-	0x03f80535,
-/* 0x09d0: ctx_mmio_pull */
-	0x98804e98,
-	0x21f4814f,
-	0x0830b69d,
-	0xf40112b6,
-/* 0x09e2: ctx_mmio_done */
-	0x0398df1b,
-	0x0007f116,
-	0x0203f081,
-	0xbd0003d0,
-	0x40008004,
-	0x010017f1,
-	0xfa0613f0,
-	0x03f80601,
-/* 0x0a02: ctx_xfer */
-	0xe7f000f8,
-	0x0007f104,
-	0x0303f002,
-	0xbd000ed0,
-/* 0x0a11: ctx_xfer_idle */
-	0x00e7f104,
-	0x03e3f000,
-	0xf100eecf,
-	0xf42000e4,
-	0x11f4f21b,
-	0x0d02f406,
-/* 0x0a28: ctx_xfer_pre */
-	0xf510f7f0,
-	0xf4083621,
-/* 0x0a32: ctx_xfer_pre_load */
-	0xf7f01c11,
-	0xd721f502,
-	0xe921f507,
-	0xfe21f507,
-	0xf5f4bd07,
-	0xf507d721,
-/* 0x0a4b: ctx_xfer_exec */
-	0x98087c21,
-	0x24bd1601,
-	0x050007f1,
-	0xd00103f0,
-	0x04bd0002,
-	0xf1021fb9,
-	0xf0a500e7,
-	0x21f441e3,
-	0x01fcf09d,
-	0xb6022cf0,
-	0xf2fd0124,
-	0x02ffb905,
-	0xa504e7f1,
-	0xf441e3f0,
-	0x21f59d21,
-	0x24bd026a,
-	0x47fc07f1,
-	0xd00203f0,
-	0x04bd0002,
-	0xb6012cf0,
-	0x07f10320,
-	0x03f04afc,
-	0x0002d002,
-	0xacf004bd,
-	0x06a5f001,
-	0x9800b7f0,
-	0x0d98000c,
-	0x00e7f001,
-	0x016f21f5,
-	0xf508a7f0,
-	0xf5011021,
-	0xf4025e21,
-	0xa7f01301,
-	0xd021f40c,
-	0xf505f7f0,
-	0xf4085e21,
-/* 0x0ada: ctx_xfer_post */
-	0xf7f02e02,
-	0xd721f502,
-	0xf5f4bd07,
-	0xf5083621,
-	0xf5027f21,
-	0xbd07e921,
-	0xd721f5f4,
-	0x1011f407,
-	0xfd400198,
-	0x0bf40511,
-	0xad21f507,
-/* 0x0b05: ctx_xfer_no_post_mmio */
-/* 0x0b05: ctx_xfer_done */
-	0x0000f809,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c
deleted file mode 100644
index d07b19d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gk110b_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419ca8,   1, 0x04, 0x00000000 },
-	{ 0x419cb0,   1, 0x04, 0x09000000 },
-	{ 0x419cb4,   1, 0x04, 0x00000000 },
-	{ 0x419cb8,   1, 0x04, 0x00b08bea },
-	{ 0x419c84,   1, 0x04, 0x00010384 },
-	{ 0x419cbc,   1, 0x04, 0x281b3646 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{ 0x419c80,   1, 0x04, 0x00020230 },
-	{ 0x419ccc,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gk110b_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000080 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ee4,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00000000 },
-	{ 0x419eb4,   1, 0x04, 0x00000000 },
-	{ 0x419ebc,   2, 0x04, 0x00000000 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419ed0,   1, 0x04, 0x00002616 },
-	{ 0x419f74,   1, 0x04, 0x00015555 },
-	{ 0x419f80,   4, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gk110b_graph_pack_mmio[] = {
-	{ nve4_graph_init_main_0 },
-	{ nvf0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nvf0_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvf0_graph_init_sked_0 },
-	{ nvf0_graph_init_cwd_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nvf0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nve4_graph_init_tpccs_0 },
-	{ nvf0_graph_init_tex_0 },
-	{ nve4_graph_init_pe_0 },
-	{ gk110b_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ gk110b_graph_init_sm_0 },
-	{ nvd7_graph_init_pes_0 },
-	{ nvd7_graph_init_wwdx_0 },
-	{ nvd7_graph_init_cbm_0 },
-	{ nve4_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-gk110b_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xf1),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve4_graph_init,
-		.fini = nvf0_graph_fini,
-	},
-	.cclass = &gk110b_grctx_oclass,
-	.sclass =  nvf0_graph_sclass,
-	.mmio = gk110b_graph_pack_mmio,
-	.fecs.ucode = &nvf0_graph_fecs_ucode,
-	.gpccs.ucode = &nvf0_graph_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c
deleted file mode 100644
index 7d0abe9..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "nvc0.h"
-#include "ctxnvc0.h"
-
-static struct nouveau_oclass
-gk20a_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa040, &nouveau_object_ofuncs },
-	{ KEPLER_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-struct nouveau_oclass *
-gk20a_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xea),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve4_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &gk20a_grctx_oclass,
-	.sclass = gk20a_graph_sclass,
-	.mmio = nve4_graph_pack_mmio,
-	.ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c
deleted file mode 100644
index 4bdbdab..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/P0260.h>
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm107_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa140, &nouveau_object_ofuncs },
-	{ MAXWELL_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ MAXWELL_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gm107_graph_init_main_0[] = {
-	{ 0x400080,   1, 0x04, 0x003003c2 },
-	{ 0x400088,   1, 0x04, 0x0001bfe7 },
-	{ 0x40008c,   1, 0x04, 0x00060000 },
-	{ 0x400090,   1, 0x04, 0x00000030 },
-	{ 0x40013c,   1, 0x04, 0x003901f3 },
-	{ 0x400140,   1, 0x04, 0x00000100 },
-	{ 0x400144,   1, 0x04, 0x00000000 },
-	{ 0x400148,   1, 0x04, 0x00000110 },
-	{ 0x400138,   1, 0x04, 0x00000000 },
-	{ 0x400130,   2, 0x04, 0x00000000 },
-	{ 0x400124,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x00000000 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_scc_0[] = {
-	{ 0x40803c,   1, 0x04, 0x00000010 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sked_0[] = {
-	{ 0x407010,   1, 0x04, 0x00000000 },
-	{ 0x407040,   1, 0x04, 0x40440424 },
-	{ 0x407048,   1, 0x04, 0x0000000a },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_prop_0[] = {
-	{ 0x418408,   1, 0x04, 0x00000000 },
-	{ 0x4184a0,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_setup_1[] = {
-	{ 0x4188c8,   2, 0x04, 0x00000000 },
-	{ 0x4188d0,   1, 0x04, 0x00010000 },
-	{ 0x4188d4,   1, 0x04, 0x00010201 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_zcull_0[] = {
-	{ 0x418910,   1, 0x04, 0x00010001 },
-	{ 0x418914,   1, 0x04, 0x00000301 },
-	{ 0x418918,   1, 0x04, 0x00800000 },
-	{ 0x418930,   2, 0x04, 0x00000000 },
-	{ 0x418980,   1, 0x04, 0x77777770 },
-	{ 0x418984,   3, 0x04, 0x77777777 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418f00,   1, 0x04, 0x00000400 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_tpccs_0[] = {
-	{ 0x419dc4,   1, 0x04, 0x00000000 },
-	{ 0x419dc8,   1, 0x04, 0x00000501 },
-	{ 0x419dd0,   1, 0x04, 0x00000000 },
-	{ 0x419dd4,   1, 0x04, 0x00000100 },
-	{ 0x419dd8,   1, 0x04, 0x00000001 },
-	{ 0x419ddc,   1, 0x04, 0x00000002 },
-	{ 0x419de0,   1, 0x04, 0x00000001 },
-	{ 0x419d0c,   1, 0x04, 0x00000000 },
-	{ 0x419d10,   1, 0x04, 0x00000014 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419abc,   1, 0x04, 0x00000000 },
-	{ 0x419acc,   1, 0x04, 0x000000ff },
-	{ 0x419ac0,   1, 0x04, 0x00000000 },
-	{ 0x419aa8,   2, 0x04, 0x00000000 },
-	{ 0x419ad0,   2, 0x04, 0x00000000 },
-	{ 0x419ae0,   2, 0x04, 0x00000000 },
-	{ 0x419af0,   4, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_pe_0[] = {
-	{ 0x419900,   1, 0x04, 0x000000ff },
-	{ 0x41980c,   1, 0x04, 0x00000010 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x419838,   1, 0x04, 0x000000ff },
-	{ 0x419850,   1, 0x04, 0x00000004 },
-	{ 0x419854,   2, 0x04, 0x00000000 },
-	{ 0x419894,   3, 0x04, 0x00100401 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sm_0[] = {
-	{ 0x419e30,   1, 0x04, 0x000000ff },
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ee4,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x01000000 },
-	{ 0x419ee8,   1, 0x04, 0x00000091 },
-	{ 0x419eb4,   1, 0x04, 0x00000000 },
-	{ 0x419ebc,   2, 0x04, 0x00000000 },
-	{ 0x419edc,   1, 0x04, 0x000c1810 },
-	{ 0x419ed8,   1, 0x04, 0x00000000 },
-	{ 0x419ee0,   1, 0x04, 0x00000000 },
-	{ 0x419f74,   1, 0x04, 0x00005155 },
-	{ 0x419f80,   4, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_l1c_1[] = {
-	{ 0x419ccc,   2, 0x04, 0x00000000 },
-	{ 0x419c80,   1, 0x04, 0x3f006022 },
-	{ 0x419c88,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_pes_0[] = {
-	{ 0x41be50,   1, 0x04, 0x000000ff },
-	{ 0x41be04,   1, 0x04, 0x00000000 },
-	{ 0x41be08,   1, 0x04, 0x00000004 },
-	{ 0x41be0c,   1, 0x04, 0x00000008 },
-	{ 0x41be10,   1, 0x04, 0x0e3b8bc7 },
-	{ 0x41be14,   2, 0x04, 0x00000000 },
-	{ 0x41be3c,   5, 0x04, 0x00100401 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_wwdx_0[] = {
-	{ 0x41bfd4,   1, 0x04, 0x00800000 },
-	{ 0x41bfdc,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_cbm_0[] = {
-	{ 0x41becc,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_be_0[] = {
-	{ 0x408890,   1, 0x04, 0x000000ff },
-	{ 0x40880c,   1, 0x04, 0x00000000 },
-	{ 0x408850,   1, 0x04, 0x00000004 },
-	{ 0x408878,   1, 0x04, 0x00c81603 },
-	{ 0x40887c,   1, 0x04, 0x80543432 },
-	{ 0x408880,   1, 0x04, 0x0010581e },
-	{ 0x408884,   1, 0x04, 0x00001205 },
-	{ 0x408974,   1, 0x04, 0x000000ff },
-	{ 0x408910,   9, 0x04, 0x00000000 },
-	{ 0x408950,   1, 0x04, 0x00000000 },
-	{ 0x408954,   1, 0x04, 0x0000ffff },
-	{ 0x408958,   1, 0x04, 0x00000034 },
-	{ 0x40895c,   1, 0x04, 0x8531a003 },
-	{ 0x408960,   1, 0x04, 0x0561985a },
-	{ 0x408964,   1, 0x04, 0x04e15c4f },
-	{ 0x408968,   1, 0x04, 0x02808833 },
-	{ 0x40896c,   1, 0x04, 0x01f02438 },
-	{ 0x408970,   1, 0x04, 0x00012c00 },
-	{ 0x408984,   1, 0x04, 0x00000000 },
-	{ 0x408988,   1, 0x04, 0x08040201 },
-	{ 0x40898c,   1, 0x04, 0x80402010 },
-	{}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sm_1[] = {
-	{ 0x419e5c,   1, 0x04, 0x00000000 },
-	{ 0x419e58,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-gm107_graph_pack_mmio[] = {
-	{ gm107_graph_init_main_0 },
-	{ nvf0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvc0_graph_init_pd_0 },
-	{ gm107_graph_init_ds_0 },
-	{ gm107_graph_init_scc_0 },
-	{ gm107_graph_init_sked_0 },
-	{ nvf0_graph_init_cwd_0 },
-	{ gm107_graph_init_prop_0 },
-	{ nv108_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ gm107_graph_init_setup_1 },
-	{ gm107_graph_init_zcull_0 },
-	{ nvc0_graph_init_gpm_0 },
-	{ gm107_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ gm107_graph_init_tpccs_0 },
-	{ gm107_graph_init_tex_0 },
-	{ gm107_graph_init_pe_0 },
-	{ gm107_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ gm107_graph_init_sm_0 },
-	{ gm107_graph_init_l1c_1 },
-	{ gm107_graph_init_pes_0 },
-	{ gm107_graph_init_wwdx_0 },
-	{ gm107_graph_init_cbm_0 },
-	{ gm107_graph_init_be_0 },
-	{ gm107_graph_init_sm_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-gm107_graph_init_bios(struct nvc0_graph_priv *priv)
-{
-	static const struct {
-		u32 ctrl;
-		u32 data;
-	} regs[] = {
-		{ 0x419ed8, 0x419ee0 },
-		{ 0x419ad0, 0x419ad4 },
-		{ 0x419ae0, 0x419ae4 },
-		{ 0x419af0, 0x419af4 },
-		{ 0x419af8, 0x419afc },
-	};
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_P0260E infoE;
-	struct nvbios_P0260X infoX;
-	int E = -1, X;
-	u8 ver, hdr;
-
-	while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) {
-		if (X = -1, E < ARRAY_SIZE(regs)) {
-			nv_wr32(priv, regs[E].ctrl, infoE.data);
-			while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX))
-				nv_wr32(priv, regs[E].data, infoX.data);
-		}
-	}
-}
-
-int
-gm107_graph_init(struct nouveau_object *object)
-{
-	struct nvc0_graph_oclass *oclass = (void *)object->oclass;
-	struct nvc0_graph_priv *priv = (void *)object;
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8] = {};
-	u8  tpcnr[GPC_MAX];
-	int gpc, tpc, ppc, rop;
-	int ret, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
-	nvc0_graph_mmio(priv, oclass->mmio);
-
-	gm107_graph_init_bios(priv);
-
-	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
-			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
-			priv->tpc_total);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
-	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-	nv_wr32(priv, 0x400124, 0x00000002);
-	nv_wr32(priv, 0x409c24, 0x000e0000);
-
-	nv_wr32(priv, 0x404000, 0xc0000000);
-	nv_wr32(priv, 0x404600, 0xc0000000);
-	nv_wr32(priv, 0x408030, 0xc0000000);
-	nv_wr32(priv, 0x404490, 0xc0000000);
-	nv_wr32(priv, 0x406018, 0xc0000000);
-	nv_wr32(priv, 0x407020, 0x40000000);
-	nv_wr32(priv, 0x405840, 0xc0000000);
-	nv_wr32(priv, 0x405844, 0x00ffffff);
-	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++)
-			nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
-		}
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400118, 0xffffffff);
-	nv_wr32(priv, 0x400130, 0xffffffff);
-	nv_wr32(priv, 0x40011c, 0xffffffff);
-	nv_wr32(priv, 0x400134, 0xffffffff);
-
-	nv_wr32(priv, 0x400054, 0x2c350f63);
-
-	nvc0_graph_zbc_init(priv);
-
-	return nvc0_graph_init_ctxctl(priv);
-}
-
-#include "fuc/hubgm107.fuc5.h"
-
-static struct nvc0_graph_ucode
-gm107_graph_fecs_ucode = {
-	.code.data = gm107_grhub_code,
-	.code.size = sizeof(gm107_grhub_code),
-	.data.data = gm107_grhub_data,
-	.data.size = sizeof(gm107_grhub_data),
-};
-
-#include "fuc/gpcgm107.fuc5.h"
-
-static struct nvc0_graph_ucode
-gm107_graph_gpccs_ucode = {
-	.code.data = gm107_grgpc_code,
-	.code.size = sizeof(gm107_grgpc_code),
-	.data.data = gm107_grgpc_data,
-	.data.size = sizeof(gm107_grgpc_data),
-};
-
-struct nouveau_oclass *
-gm107_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x07),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = gm107_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &gm107_grctx_oclass,
-	.sclass =  gm107_graph_sclass,
-	.mmio = gm107_graph_pack_mmio,
-	.fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL,
-	.gpccs.ucode = &gm107_graph_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
deleted file mode 100644
index f70e2f6..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * Copyright 2007 Stephane Marchesin
- * All Rights Reserved.
- *
- * 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
- * PRECISION INSIGHT 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.
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "regs.h"
-
-static u32
-nv04_graph_ctx_regs[] = {
-	0x0040053c,
-	0x00400544,
-	0x00400540,
-	0x00400548,
-	NV04_PGRAPH_CTX_SWITCH1,
-	NV04_PGRAPH_CTX_SWITCH2,
-	NV04_PGRAPH_CTX_SWITCH3,
-	NV04_PGRAPH_CTX_SWITCH4,
-	NV04_PGRAPH_CTX_CACHE1,
-	NV04_PGRAPH_CTX_CACHE2,
-	NV04_PGRAPH_CTX_CACHE3,
-	NV04_PGRAPH_CTX_CACHE4,
-	0x00400184,
-	0x004001a4,
-	0x004001c4,
-	0x004001e4,
-	0x00400188,
-	0x004001a8,
-	0x004001c8,
-	0x004001e8,
-	0x0040018c,
-	0x004001ac,
-	0x004001cc,
-	0x004001ec,
-	0x00400190,
-	0x004001b0,
-	0x004001d0,
-	0x004001f0,
-	0x00400194,
-	0x004001b4,
-	0x004001d4,
-	0x004001f4,
-	0x00400198,
-	0x004001b8,
-	0x004001d8,
-	0x004001f8,
-	0x0040019c,
-	0x004001bc,
-	0x004001dc,
-	0x004001fc,
-	0x00400174,
-	NV04_PGRAPH_DMA_START_0,
-	NV04_PGRAPH_DMA_START_1,
-	NV04_PGRAPH_DMA_LENGTH,
-	NV04_PGRAPH_DMA_MISC,
-	NV04_PGRAPH_DMA_PITCH,
-	NV04_PGRAPH_BOFFSET0,
-	NV04_PGRAPH_BBASE0,
-	NV04_PGRAPH_BLIMIT0,
-	NV04_PGRAPH_BOFFSET1,
-	NV04_PGRAPH_BBASE1,
-	NV04_PGRAPH_BLIMIT1,
-	NV04_PGRAPH_BOFFSET2,
-	NV04_PGRAPH_BBASE2,
-	NV04_PGRAPH_BLIMIT2,
-	NV04_PGRAPH_BOFFSET3,
-	NV04_PGRAPH_BBASE3,
-	NV04_PGRAPH_BLIMIT3,
-	NV04_PGRAPH_BOFFSET4,
-	NV04_PGRAPH_BBASE4,
-	NV04_PGRAPH_BLIMIT4,
-	NV04_PGRAPH_BOFFSET5,
-	NV04_PGRAPH_BBASE5,
-	NV04_PGRAPH_BLIMIT5,
-	NV04_PGRAPH_BPITCH0,
-	NV04_PGRAPH_BPITCH1,
-	NV04_PGRAPH_BPITCH2,
-	NV04_PGRAPH_BPITCH3,
-	NV04_PGRAPH_BPITCH4,
-	NV04_PGRAPH_SURFACE,
-	NV04_PGRAPH_STATE,
-	NV04_PGRAPH_BSWIZZLE2,
-	NV04_PGRAPH_BSWIZZLE5,
-	NV04_PGRAPH_BPIXEL,
-	NV04_PGRAPH_NOTIFY,
-	NV04_PGRAPH_PATT_COLOR0,
-	NV04_PGRAPH_PATT_COLOR1,
-	NV04_PGRAPH_PATT_COLORRAM+0x00,
-	NV04_PGRAPH_PATT_COLORRAM+0x04,
-	NV04_PGRAPH_PATT_COLORRAM+0x08,
-	NV04_PGRAPH_PATT_COLORRAM+0x0c,
-	NV04_PGRAPH_PATT_COLORRAM+0x10,
-	NV04_PGRAPH_PATT_COLORRAM+0x14,
-	NV04_PGRAPH_PATT_COLORRAM+0x18,
-	NV04_PGRAPH_PATT_COLORRAM+0x1c,
-	NV04_PGRAPH_PATT_COLORRAM+0x20,
-	NV04_PGRAPH_PATT_COLORRAM+0x24,
-	NV04_PGRAPH_PATT_COLORRAM+0x28,
-	NV04_PGRAPH_PATT_COLORRAM+0x2c,
-	NV04_PGRAPH_PATT_COLORRAM+0x30,
-	NV04_PGRAPH_PATT_COLORRAM+0x34,
-	NV04_PGRAPH_PATT_COLORRAM+0x38,
-	NV04_PGRAPH_PATT_COLORRAM+0x3c,
-	NV04_PGRAPH_PATT_COLORRAM+0x40,
-	NV04_PGRAPH_PATT_COLORRAM+0x44,
-	NV04_PGRAPH_PATT_COLORRAM+0x48,
-	NV04_PGRAPH_PATT_COLORRAM+0x4c,
-	NV04_PGRAPH_PATT_COLORRAM+0x50,
-	NV04_PGRAPH_PATT_COLORRAM+0x54,
-	NV04_PGRAPH_PATT_COLORRAM+0x58,
-	NV04_PGRAPH_PATT_COLORRAM+0x5c,
-	NV04_PGRAPH_PATT_COLORRAM+0x60,
-	NV04_PGRAPH_PATT_COLORRAM+0x64,
-	NV04_PGRAPH_PATT_COLORRAM+0x68,
-	NV04_PGRAPH_PATT_COLORRAM+0x6c,
-	NV04_PGRAPH_PATT_COLORRAM+0x70,
-	NV04_PGRAPH_PATT_COLORRAM+0x74,
-	NV04_PGRAPH_PATT_COLORRAM+0x78,
-	NV04_PGRAPH_PATT_COLORRAM+0x7c,
-	NV04_PGRAPH_PATT_COLORRAM+0x80,
-	NV04_PGRAPH_PATT_COLORRAM+0x84,
-	NV04_PGRAPH_PATT_COLORRAM+0x88,
-	NV04_PGRAPH_PATT_COLORRAM+0x8c,
-	NV04_PGRAPH_PATT_COLORRAM+0x90,
-	NV04_PGRAPH_PATT_COLORRAM+0x94,
-	NV04_PGRAPH_PATT_COLORRAM+0x98,
-	NV04_PGRAPH_PATT_COLORRAM+0x9c,
-	NV04_PGRAPH_PATT_COLORRAM+0xa0,
-	NV04_PGRAPH_PATT_COLORRAM+0xa4,
-	NV04_PGRAPH_PATT_COLORRAM+0xa8,
-	NV04_PGRAPH_PATT_COLORRAM+0xac,
-	NV04_PGRAPH_PATT_COLORRAM+0xb0,
-	NV04_PGRAPH_PATT_COLORRAM+0xb4,
-	NV04_PGRAPH_PATT_COLORRAM+0xb8,
-	NV04_PGRAPH_PATT_COLORRAM+0xbc,
-	NV04_PGRAPH_PATT_COLORRAM+0xc0,
-	NV04_PGRAPH_PATT_COLORRAM+0xc4,
-	NV04_PGRAPH_PATT_COLORRAM+0xc8,
-	NV04_PGRAPH_PATT_COLORRAM+0xcc,
-	NV04_PGRAPH_PATT_COLORRAM+0xd0,
-	NV04_PGRAPH_PATT_COLORRAM+0xd4,
-	NV04_PGRAPH_PATT_COLORRAM+0xd8,
-	NV04_PGRAPH_PATT_COLORRAM+0xdc,
-	NV04_PGRAPH_PATT_COLORRAM+0xe0,
-	NV04_PGRAPH_PATT_COLORRAM+0xe4,
-	NV04_PGRAPH_PATT_COLORRAM+0xe8,
-	NV04_PGRAPH_PATT_COLORRAM+0xec,
-	NV04_PGRAPH_PATT_COLORRAM+0xf0,
-	NV04_PGRAPH_PATT_COLORRAM+0xf4,
-	NV04_PGRAPH_PATT_COLORRAM+0xf8,
-	NV04_PGRAPH_PATT_COLORRAM+0xfc,
-	NV04_PGRAPH_PATTERN,
-	0x0040080c,
-	NV04_PGRAPH_PATTERN_SHAPE,
-	0x00400600,
-	NV04_PGRAPH_ROP3,
-	NV04_PGRAPH_CHROMA,
-	NV04_PGRAPH_BETA_AND,
-	NV04_PGRAPH_BETA_PREMULT,
-	NV04_PGRAPH_CONTROL0,
-	NV04_PGRAPH_CONTROL1,
-	NV04_PGRAPH_CONTROL2,
-	NV04_PGRAPH_BLEND,
-	NV04_PGRAPH_STORED_FMT,
-	NV04_PGRAPH_SOURCE_COLOR,
-	0x00400560,
-	0x00400568,
-	0x00400564,
-	0x0040056c,
-	0x00400400,
-	0x00400480,
-	0x00400404,
-	0x00400484,
-	0x00400408,
-	0x00400488,
-	0x0040040c,
-	0x0040048c,
-	0x00400410,
-	0x00400490,
-	0x00400414,
-	0x00400494,
-	0x00400418,
-	0x00400498,
-	0x0040041c,
-	0x0040049c,
-	0x00400420,
-	0x004004a0,
-	0x00400424,
-	0x004004a4,
-	0x00400428,
-	0x004004a8,
-	0x0040042c,
-	0x004004ac,
-	0x00400430,
-	0x004004b0,
-	0x00400434,
-	0x004004b4,
-	0x00400438,
-	0x004004b8,
-	0x0040043c,
-	0x004004bc,
-	0x00400440,
-	0x004004c0,
-	0x00400444,
-	0x004004c4,
-	0x00400448,
-	0x004004c8,
-	0x0040044c,
-	0x004004cc,
-	0x00400450,
-	0x004004d0,
-	0x00400454,
-	0x004004d4,
-	0x00400458,
-	0x004004d8,
-	0x0040045c,
-	0x004004dc,
-	0x00400460,
-	0x004004e0,
-	0x00400464,
-	0x004004e4,
-	0x00400468,
-	0x004004e8,
-	0x0040046c,
-	0x004004ec,
-	0x00400470,
-	0x004004f0,
-	0x00400474,
-	0x004004f4,
-	0x00400478,
-	0x004004f8,
-	0x0040047c,
-	0x004004fc,
-	0x00400534,
-	0x00400538,
-	0x00400514,
-	0x00400518,
-	0x0040051c,
-	0x00400520,
-	0x00400524,
-	0x00400528,
-	0x0040052c,
-	0x00400530,
-	0x00400d00,
-	0x00400d40,
-	0x00400d80,
-	0x00400d04,
-	0x00400d44,
-	0x00400d84,
-	0x00400d08,
-	0x00400d48,
-	0x00400d88,
-	0x00400d0c,
-	0x00400d4c,
-	0x00400d8c,
-	0x00400d10,
-	0x00400d50,
-	0x00400d90,
-	0x00400d14,
-	0x00400d54,
-	0x00400d94,
-	0x00400d18,
-	0x00400d58,
-	0x00400d98,
-	0x00400d1c,
-	0x00400d5c,
-	0x00400d9c,
-	0x00400d20,
-	0x00400d60,
-	0x00400da0,
-	0x00400d24,
-	0x00400d64,
-	0x00400da4,
-	0x00400d28,
-	0x00400d68,
-	0x00400da8,
-	0x00400d2c,
-	0x00400d6c,
-	0x00400dac,
-	0x00400d30,
-	0x00400d70,
-	0x00400db0,
-	0x00400d34,
-	0x00400d74,
-	0x00400db4,
-	0x00400d38,
-	0x00400d78,
-	0x00400db8,
-	0x00400d3c,
-	0x00400d7c,
-	0x00400dbc,
-	0x00400590,
-	0x00400594,
-	0x00400598,
-	0x0040059c,
-	0x004005a8,
-	0x004005ac,
-	0x004005b0,
-	0x004005b4,
-	0x004005c0,
-	0x004005c4,
-	0x004005c8,
-	0x004005cc,
-	0x004005d0,
-	0x004005d4,
-	0x004005d8,
-	0x004005dc,
-	0x004005e0,
-	NV04_PGRAPH_PASSTHRU_0,
-	NV04_PGRAPH_PASSTHRU_1,
-	NV04_PGRAPH_PASSTHRU_2,
-	NV04_PGRAPH_DVD_COLORFMT,
-	NV04_PGRAPH_SCALED_FORMAT,
-	NV04_PGRAPH_MISC24_0,
-	NV04_PGRAPH_MISC24_1,
-	NV04_PGRAPH_MISC24_2,
-	0x00400500,
-	0x00400504,
-	NV04_PGRAPH_VALID1,
-	NV04_PGRAPH_VALID2,
-	NV04_PGRAPH_DEBUG_3
-};
-
-struct nv04_graph_priv {
-	struct nouveau_graph base;
-	struct nv04_graph_chan *chan[16];
-	spinlock_t lock;
-};
-
-struct nv04_graph_chan {
-	struct nouveau_object base;
-	int chid;
-	u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
-};
-
-
-static inline struct nv04_graph_priv *
-nv04_graph_priv(struct nv04_graph_chan *chan)
-{
-	return (void *)nv_object(chan)->engine;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-/*
- * Software methods, why they are needed, and how they all work:
- *
- * NV04 and NV05 keep most of the state in PGRAPH context itself, but some
- * 2d engine settings are kept inside the grobjs themselves. The grobjs are
- * 3 words long on both. grobj format on NV04 is:
- *
- * word 0:
- *  - bits 0-7: class
- *  - bit 12: color key active
- *  - bit 13: clip rect active
- *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
- *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
- *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
- *            NV03_CONTEXT_SURFACE_DST].
- *  - bits 15-17: 2d operation [aka patch config]
- *  - bit 24: patch valid [enables rendering using this object]
- *  - bit 25: surf3d valid [for tex_tri and multitex_tri only]
- * word 1:
- *  - bits 0-1: mono format
- *  - bits 8-13: color format
- *  - bits 16-31: DMA_NOTIFY instance
- * word 2:
- *  - bits 0-15: DMA_A instance
- *  - bits 16-31: DMA_B instance
- *
- * On NV05 it's:
- *
- * word 0:
- *  - bits 0-7: class
- *  - bit 12: color key active
- *  - bit 13: clip rect active
- *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
- *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
- *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
- *            NV03_CONTEXT_SURFACE_DST].
- *  - bits 15-17: 2d operation [aka patch config]
- *  - bits 20-22: dither mode
- *  - bit 24: patch valid [enables rendering using this object]
- *  - bit 25: surface_dst/surface_color/surf2d/surf3d valid
- *  - bit 26: surface_src/surface_zeta valid
- *  - bit 27: pattern valid
- *  - bit 28: rop valid
- *  - bit 29: beta1 valid
- *  - bit 30: beta4 valid
- * word 1:
- *  - bits 0-1: mono format
- *  - bits 8-13: color format
- *  - bits 16-31: DMA_NOTIFY instance
- * word 2:
- *  - bits 0-15: DMA_A instance
- *  - bits 16-31: DMA_B instance
- *
- * NV05 will set/unset the relevant valid bits when you poke the relevant
- * object-binding methods with object of the proper type, or with the NULL
- * type. It'll only allow rendering using the grobj if all needed objects
- * are bound. The needed set of objects depends on selected operation: for
- * example rop object is needed by ROP_AND, but not by SRCCOPY_AND.
- *
- * NV04 doesn't have these methods implemented at all, and doesn't have the
- * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24
- * is set. So we have to emulate them in software, internally keeping the
- * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04,
- * but the last word isn't actually used for anything, we abuse it for this
- * purpose.
- *
- * Actually, NV05 can optionally check bit 24 too, but we disable this since
- * there's no use for it.
- *
- * For unknown reasons, NV04 implements surf3d binding in hardware as an
- * exception. Also for unknown reasons, NV04 doesn't implement the clipping
- * methods on the surf3d object, so we have to emulate them too.
- */
-
-static void
-nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value)
-{
-	struct nv04_graph_priv *priv = (void *)object->engine;
-	int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
-	u32 tmp;
-
-	tmp  = nv_ro32(object, 0x00);
-	tmp &= ~mask;
-	tmp |= value;
-	nv_wo32(object, 0x00, tmp);
-
-	nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
-	nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
-}
-
-static void
-nv04_graph_set_ctx_val(struct nouveau_object *object, u32 mask, u32 value)
-{
-	int class, op, valid = 1;
-	u32 tmp, ctx1;
-
-	ctx1 = nv_ro32(object, 0x00);
-	class = ctx1 & 0xff;
-	op = (ctx1 >> 15) & 7;
-
-	tmp = nv_ro32(object, 0x0c);
-	tmp &= ~mask;
-	tmp |= value;
-	nv_wo32(object, 0x0c, tmp);
-
-	/* check for valid surf2d/surf_dst/surf_color */
-	if (!(tmp & 0x02000000))
-		valid = 0;
-	/* check for valid surf_src/surf_zeta */
-	if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
-		valid = 0;
-
-	switch (op) {
-	/* SRCCOPY_AND, SRCCOPY: no extra objects required */
-	case 0:
-	case 3:
-		break;
-	/* ROP_AND: requires pattern and rop */
-	case 1:
-		if (!(tmp & 0x18000000))
-			valid = 0;
-		break;
-	/* BLEND_AND: requires beta1 */
-	case 2:
-		if (!(tmp & 0x20000000))
-			valid = 0;
-		break;
-	/* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
-	case 4:
-	case 5:
-		if (!(tmp & 0x40000000))
-			valid = 0;
-		break;
-	}
-
-	nv04_graph_set_ctx1(object, 0x01000000, valid << 24);
-}
-
-static int
-nv04_graph_mthd_set_operation(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	u32 class = nv_ro32(object, 0) & 0xff;
-	u32 data = *(u32 *)args;
-	if (data > 5)
-		return 1;
-	/* Old versions of the objects only accept first three operations. */
-	if (data > 2 && class < 0x40)
-		return 1;
-	nv04_graph_set_ctx1(object, 0x00038000, data << 15);
-	/* changing operation changes set of objects needed for validation */
-	nv04_graph_set_ctx_val(object, 0, 0);
-	return 0;
-}
-
-static int
-nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	struct nv04_graph_priv *priv = (void *)object->engine;
-	u32 data = *(u32 *)args;
-	u32 min = data & 0xffff, max;
-	u32 w = data >> 16;
-	if (min & 0x8000)
-		/* too large */
-		return 1;
-	if (w & 0x8000)
-		/* yes, it accepts negative for some reason. */
-		w |= 0xffff0000;
-	max = min + w;
-	max &= 0x3ffff;
-	nv_wr32(priv, 0x40053c, min);
-	nv_wr32(priv, 0x400544, max);
-	return 0;
-}
-
-static int
-nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	struct nv04_graph_priv *priv = (void *)object->engine;
-	u32 data = *(u32 *)args;
-	u32 min = data & 0xffff, max;
-	u32 w = data >> 16;
-	if (min & 0x8000)
-		/* too large */
-		return 1;
-	if (w & 0x8000)
-		/* yes, it accepts negative for some reason. */
-		w |= 0xffff0000;
-	max = min + w;
-	max &= 0x3ffff;
-	nv_wr32(priv, 0x400540, min);
-	nv_wr32(priv, 0x400548, max);
-	return 0;
-}
-
-static u16
-nv04_graph_mthd_bind_class(struct nouveau_object *object, u32 *args, u32 size)
-{
-	struct nouveau_instmem *imem = nouveau_instmem(object);
-	u32 inst = *(u32 *)args << 4;
-	return nv_ro32(imem, inst);
-}
-
-static int
-nv04_graph_mthd_bind_surf2d(struct nouveau_object *object, u32 mthd,
-			    void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx1(object, 0x00004000, 0);
-		nv04_graph_set_ctx_val(object, 0x02000000, 0);
-		return 0;
-	case 0x42:
-		nv04_graph_set_ctx1(object, 0x00004000, 0);
-		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_object *object, u32 mthd,
-				    void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx1(object, 0x00004000, 0);
-		nv04_graph_set_ctx_val(object, 0x02000000, 0);
-		return 0;
-	case 0x42:
-		nv04_graph_set_ctx1(object, 0x00004000, 0);
-		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
-		return 0;
-	case 0x52:
-		nv04_graph_set_ctx1(object, 0x00004000, 0x00004000);
-		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
-			  void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x08000000, 0);
-		return 0;
-	case 0x18:
-		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
-			  void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x08000000, 0);
-		return 0;
-	case 0x44:
-		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd,
-			 void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x10000000, 0);
-		return 0;
-	case 0x43:
-		nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd,
-			   void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x20000000, 0);
-		return 0;
-	case 0x12:
-		nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd,
-			   void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x40000000, 0);
-		return 0;
-	case 0x72:
-		nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x02000000, 0);
-		return 0;
-	case 0x58:
-		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x04000000, 0);
-		return 0;
-	case 0x59:
-		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd,
-				void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x02000000, 0);
-		return 0;
-	case 0x5a:
-		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd,
-			       void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx_val(object, 0x04000000, 0);
-		return 0;
-	case 0x5b:
-		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd,
-			  void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx1(object, 0x2000, 0);
-		return 0;
-	case 0x19:
-		nv04_graph_set_ctx1(object, 0x2000, 0x2000);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd,
-			    void *args, u32 size)
-{
-	switch (nv04_graph_mthd_bind_class(object, args, size)) {
-	case 0x30:
-		nv04_graph_set_ctx1(object, 0x1000, 0);
-		return 0;
-	/* Yes, for some reason even the old versions of objects
-	 * accept 0x57 and not 0x17. Consistency be damned.
-	 */
-	case 0x57:
-		nv04_graph_set_ctx1(object, 0x1000, 0x1000);
-		return 0;
-	}
-	return 1;
-}
-
-static struct nouveau_omthds
-nv03_graph_gdi_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_patt },
-	{ 0x0188, 0x0188, nv04_graph_mthd_bind_rop },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_beta1 },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_surf_dst },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_gdi_omthds[] = {
-	{ 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv01_graph_blit_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
-	{ 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
-	{ 0x019c, 0x019c, nv04_graph_mthd_bind_surf_src },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_blit_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
-	{ 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_iifc_omthds[] = {
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_chroma },
-	{ 0x018c, 0x018c, nv01_graph_mthd_bind_clip },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_patt },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_rop },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_beta1 },
-	{ 0x019c, 0x019c, nv04_graph_mthd_bind_beta4 },
-	{ 0x01a0, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
-	{ 0x03e4, 0x03e4, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv01_graph_ifc_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
-	{ 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_ifc_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
-	{ 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv03_graph_sifc_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_sifc_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
-	{ 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv03_graph_sifm_omthds[] = {
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
-	{ 0x0304, 0x0304, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_sifm_omthds[] = {
-	{ 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
-	{ 0x0304, 0x0304, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_surf3d_omthds[] = {
-	{ 0x02f8, 0x02f8, nv04_graph_mthd_surf3d_clip_h },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_surf3d_clip_v },
-	{}
-};
-
-static struct nouveau_omthds
-nv03_graph_ttri_omthds[] = {
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_surf_color },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_surf_zeta },
-	{}
-};
-
-static struct nouveau_omthds
-nv01_graph_prim_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
-	{ 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static struct nouveau_omthds
-nv04_graph_prim_omthds[] = {
-	{ 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
-	{ 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
-	{ 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
-	{ 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
-	{ 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
-	{ 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
-	{ 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
-	{}
-};
-
-static int
-nv04_graph_object_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    16, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-#ifdef __BIG_ENDIAN
-	nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
-#endif
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-	return 0;
-}
-
-struct nouveau_ofuncs
-nv04_graph_ofuncs = {
-	.ctor = nv04_graph_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv04_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
-	{ 0x0017, &nv04_graph_ofuncs }, /* chroma */
-	{ 0x0018, &nv04_graph_ofuncs }, /* pattern (nv01) */
-	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
-	{ 0x001c, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* line */
-	{ 0x001d, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* tri */
-	{ 0x001e, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* rect */
-	{ 0x001f, &nv04_graph_ofuncs, nv01_graph_blit_omthds },
-	{ 0x0021, &nv04_graph_ofuncs, nv01_graph_ifc_omthds },
-	{ 0x0030, &nv04_graph_ofuncs }, /* null */
-	{ 0x0036, &nv04_graph_ofuncs, nv03_graph_sifc_omthds },
-	{ 0x0037, &nv04_graph_ofuncs, nv03_graph_sifm_omthds },
-	{ 0x0038, &nv04_graph_ofuncs }, /* dvd subpicture */
-	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
-	{ 0x0042, &nv04_graph_ofuncs }, /* surf2d */
-	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
-	{ 0x0048, &nv04_graph_ofuncs, nv03_graph_ttri_omthds },
-	{ 0x004a, &nv04_graph_ofuncs, nv04_graph_gdi_omthds },
-	{ 0x004b, &nv04_graph_ofuncs, nv03_graph_gdi_omthds },
-	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
-	{ 0x0053, &nv04_graph_ofuncs, nv04_graph_surf3d_omthds },
-	{ 0x0054, &nv04_graph_ofuncs }, /* ttri */
-	{ 0x0055, &nv04_graph_ofuncs }, /* mtri */
-	{ 0x0057, &nv04_graph_ofuncs }, /* chroma */
-	{ 0x0058, &nv04_graph_ofuncs }, /* surf_dst */
-	{ 0x0059, &nv04_graph_ofuncs }, /* surf_src */
-	{ 0x005a, &nv04_graph_ofuncs }, /* surf_color */
-	{ 0x005b, &nv04_graph_ofuncs }, /* surf_zeta */
-	{ 0x005c, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* line */
-	{ 0x005d, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* tri */
-	{ 0x005e, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* rect */
-	{ 0x005f, &nv04_graph_ofuncs, nv04_graph_blit_omthds },
-	{ 0x0060, &nv04_graph_ofuncs, nv04_graph_iifc_omthds },
-	{ 0x0061, &nv04_graph_ofuncs, nv04_graph_ifc_omthds },
-	{ 0x0064, &nv04_graph_ofuncs }, /* iifc (nv05) */
-	{ 0x0065, &nv04_graph_ofuncs }, /* ifc (nv05) */
-	{ 0x0066, &nv04_graph_ofuncs }, /* sifc (nv05) */
-	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
-	{ 0x0076, &nv04_graph_ofuncs, nv04_graph_sifc_omthds },
-	{ 0x0077, &nv04_graph_ofuncs, nv04_graph_sifm_omthds },
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nv04_graph_chan *
-nv04_graph_channel(struct nv04_graph_priv *priv)
-{
-	struct nv04_graph_chan *chan = NULL;
-	if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
-		int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
-		if (chid < ARRAY_SIZE(priv->chan))
-			chan = priv->chan[chid];
-	}
-	return chan;
-}
-
-static int
-nv04_graph_load_context(struct nv04_graph_chan *chan, int chid)
-{
-	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		nv_wr32(priv, nv04_graph_ctx_regs[i], chan->nv04[i]);
-
-	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
-	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
-	nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
-	return 0;
-}
-
-static int
-nv04_graph_unload_context(struct nv04_graph_chan *chan)
-{
-	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		chan->nv04[i] = nv_rd32(priv, nv04_graph_ctx_regs[i]);
-
-	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
-	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
-	return 0;
-}
-
-static void
-nv04_graph_context_switch(struct nv04_graph_priv *priv)
-{
-	struct nv04_graph_chan *prev = NULL;
-	struct nv04_graph_chan *next = NULL;
-	unsigned long flags;
-	int chid;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv04_graph_idle(priv);
-
-	/* If previous context is valid, we need to save it */
-	prev = nv04_graph_channel(priv);
-	if (prev)
-		nv04_graph_unload_context(prev);
-
-	/* load context for next channel */
-	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
-	next = priv->chan[chid];
-	if (next)
-		nv04_graph_load_context(next, chid);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static u32 *ctx_reg(struct nv04_graph_chan *chan, u32 reg)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
-		if (nv04_graph_ctx_regs[i] == reg)
-			return &chan->nv04[i];
-	}
-
-	return NULL;
-}
-
-static int
-nv04_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nouveau_fifo_chan *fifo = (void *)parent;
-	struct nv04_graph_priv *priv = (void *)engine;
-	struct nv04_graph_chan *chan;
-	unsigned long flags;
-	int ret;
-
-	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (priv->chan[fifo->chid]) {
-		*pobject = nv_object(priv->chan[fifo->chid]);
-		atomic_inc(&(*pobject)->refcount);
-		spin_unlock_irqrestore(&priv->lock, flags);
-		nouveau_object_destroy(&chan->base);
-		return 1;
-	}
-
-	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-	priv->chan[fifo->chid] = chan;
-	chan->chid = fifo->chid;
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return 0;
-}
-
-static void
-nv04_graph_context_dtor(struct nouveau_object *object)
-{
-	struct nv04_graph_priv *priv = (void *)object->engine;
-	struct nv04_graph_chan *chan = (void *)object;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->chan[chan->chid] = NULL;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	nouveau_object_destroy(&chan->base);
-}
-
-static int
-nv04_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv04_graph_priv *priv = (void *)object->engine;
-	struct nv04_graph_chan *chan = (void *)object;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (nv04_graph_channel(priv) == chan)
-		nv04_graph_unload_context(chan);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return nouveau_object_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv04_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_graph_context_ctor,
-		.dtor = nv04_graph_context_dtor,
-		.init = nouveau_object_init,
-		.fini = nv04_graph_context_fini,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-bool
-nv04_graph_idle(void *obj)
-{
-	struct nouveau_graph *graph = nouveau_graph(obj);
-	u32 mask = 0xffffffff;
-
-	if (nv_device(obj)->card_type == NV_40)
-		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
-
-	if (!nv_wait(graph, NV04_PGRAPH_STATUS, mask, 0)) {
-		nv_error(graph, "idle timed out with status 0x%08x\n",
-			 nv_rd32(graph, NV04_PGRAPH_STATUS));
-		return false;
-	}
-
-	return true;
-}
-
-static const struct nouveau_bitfield
-nv04_graph_intr_name[] = {
-	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
-	{}
-};
-
-static const struct nouveau_bitfield
-nv04_graph_nstatus[] = {
-	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
-	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
-	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
-	{ NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
-	{}
-};
-
-const struct nouveau_bitfield
-nv04_graph_nsource[] = {
-	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
-	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
-	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
-	{ NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
-	{ NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
-	{ NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
-	{ NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
-	{ NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
-	{ NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
-	{ NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
-	{ NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
-	{ NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
-	{ NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
-	{ NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
-	{ NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
-	{ NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
-	{ NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
-	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
-	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
-	{}
-};
-
-static void
-nv04_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nv04_graph_priv *priv = (void *)subdev;
-	struct nv04_graph_chan *chan = NULL;
-	struct nouveau_namedb *namedb = NULL;
-	struct nouveau_handle *handle = NULL;
-	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
-	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
-	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
-	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
-	u32 chid = (addr & 0x0f000000) >> 24;
-	u32 subc = (addr & 0x0000e000) >> 13;
-	u32 mthd = (addr & 0x00001ffc);
-	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
-	u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
-	u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
-	u32 show = stat;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chan = priv->chan[chid];
-	if (chan)
-		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (stat & NV_PGRAPH_INTR_NOTIFY) {
-		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
-			handle = nouveau_namedb_get_vinst(namedb, inst);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~NV_PGRAPH_INTR_NOTIFY;
-		}
-	}
-
-	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-		nv04_graph_context_switch(priv);
-	}
-
-	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
-	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
-	if (show) {
-		nv_error(priv, "%s", "");
-		nouveau_bitfield_print(nv04_graph_intr_name, show);
-		pr_cont(" nsource:");
-		nouveau_bitfield_print(nv04_graph_nsource, nsource);
-		pr_cont(" nstatus:");
-		nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-		pr_cont("\n");
-		nv_error(priv,
-			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, nouveau_client_name(chan), subc, class, mthd,
-			 data);
-	}
-
-	nouveau_namedb_put(handle);
-}
-
-static int
-nv04_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv04_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv04_graph_intr;
-	nv_engine(priv)->cclass = &nv04_graph_cclass;
-	nv_engine(priv)->sclass = nv04_graph_sclass;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-static int
-nv04_graph_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nv04_graph_priv *priv = (void *)engine;
-	int ret;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* Enable PGRAPH interrupts */
-	nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
-	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
-	nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
-	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
-	/*1231C000 blob, 001 haiku*/
-	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
-	/*0x72111100 blob , 01 haiku*/
-	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
-	/*haiku same*/
-
-	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
-	/*haiku and blob 10d4*/
-
-	nv_wr32(priv, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
-	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
-	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
-
-	/* These don't belong here, they're part of a per-channel context */
-	nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
-	nv_wr32(priv, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
-	return 0;
-}
-
-struct nouveau_oclass
-nv04_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_graph_ctor,
-		.dtor = _nouveau_graph_dtor,
-		.init = nv04_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
deleted file mode 100644
index 2b12b09..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
- * All Rights Reserved.
- *
- * 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
- * PRECISION INSIGHT 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.
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "regs.h"
-
-struct pipe_state {
-	u32 pipe_0x0000[0x040/4];
-	u32 pipe_0x0040[0x010/4];
-	u32 pipe_0x0200[0x0c0/4];
-	u32 pipe_0x4400[0x080/4];
-	u32 pipe_0x6400[0x3b0/4];
-	u32 pipe_0x6800[0x2f0/4];
-	u32 pipe_0x6c00[0x030/4];
-	u32 pipe_0x7000[0x130/4];
-	u32 pipe_0x7400[0x0c0/4];
-	u32 pipe_0x7800[0x0c0/4];
-};
-
-static int nv10_graph_ctx_regs[] = {
-	NV10_PGRAPH_CTX_SWITCH(0),
-	NV10_PGRAPH_CTX_SWITCH(1),
-	NV10_PGRAPH_CTX_SWITCH(2),
-	NV10_PGRAPH_CTX_SWITCH(3),
-	NV10_PGRAPH_CTX_SWITCH(4),
-	NV10_PGRAPH_CTX_CACHE(0, 0),
-	NV10_PGRAPH_CTX_CACHE(0, 1),
-	NV10_PGRAPH_CTX_CACHE(0, 2),
-	NV10_PGRAPH_CTX_CACHE(0, 3),
-	NV10_PGRAPH_CTX_CACHE(0, 4),
-	NV10_PGRAPH_CTX_CACHE(1, 0),
-	NV10_PGRAPH_CTX_CACHE(1, 1),
-	NV10_PGRAPH_CTX_CACHE(1, 2),
-	NV10_PGRAPH_CTX_CACHE(1, 3),
-	NV10_PGRAPH_CTX_CACHE(1, 4),
-	NV10_PGRAPH_CTX_CACHE(2, 0),
-	NV10_PGRAPH_CTX_CACHE(2, 1),
-	NV10_PGRAPH_CTX_CACHE(2, 2),
-	NV10_PGRAPH_CTX_CACHE(2, 3),
-	NV10_PGRAPH_CTX_CACHE(2, 4),
-	NV10_PGRAPH_CTX_CACHE(3, 0),
-	NV10_PGRAPH_CTX_CACHE(3, 1),
-	NV10_PGRAPH_CTX_CACHE(3, 2),
-	NV10_PGRAPH_CTX_CACHE(3, 3),
-	NV10_PGRAPH_CTX_CACHE(3, 4),
-	NV10_PGRAPH_CTX_CACHE(4, 0),
-	NV10_PGRAPH_CTX_CACHE(4, 1),
-	NV10_PGRAPH_CTX_CACHE(4, 2),
-	NV10_PGRAPH_CTX_CACHE(4, 3),
-	NV10_PGRAPH_CTX_CACHE(4, 4),
-	NV10_PGRAPH_CTX_CACHE(5, 0),
-	NV10_PGRAPH_CTX_CACHE(5, 1),
-	NV10_PGRAPH_CTX_CACHE(5, 2),
-	NV10_PGRAPH_CTX_CACHE(5, 3),
-	NV10_PGRAPH_CTX_CACHE(5, 4),
-	NV10_PGRAPH_CTX_CACHE(6, 0),
-	NV10_PGRAPH_CTX_CACHE(6, 1),
-	NV10_PGRAPH_CTX_CACHE(6, 2),
-	NV10_PGRAPH_CTX_CACHE(6, 3),
-	NV10_PGRAPH_CTX_CACHE(6, 4),
-	NV10_PGRAPH_CTX_CACHE(7, 0),
-	NV10_PGRAPH_CTX_CACHE(7, 1),
-	NV10_PGRAPH_CTX_CACHE(7, 2),
-	NV10_PGRAPH_CTX_CACHE(7, 3),
-	NV10_PGRAPH_CTX_CACHE(7, 4),
-	NV10_PGRAPH_CTX_USER,
-	NV04_PGRAPH_DMA_START_0,
-	NV04_PGRAPH_DMA_START_1,
-	NV04_PGRAPH_DMA_LENGTH,
-	NV04_PGRAPH_DMA_MISC,
-	NV10_PGRAPH_DMA_PITCH,
-	NV04_PGRAPH_BOFFSET0,
-	NV04_PGRAPH_BBASE0,
-	NV04_PGRAPH_BLIMIT0,
-	NV04_PGRAPH_BOFFSET1,
-	NV04_PGRAPH_BBASE1,
-	NV04_PGRAPH_BLIMIT1,
-	NV04_PGRAPH_BOFFSET2,
-	NV04_PGRAPH_BBASE2,
-	NV04_PGRAPH_BLIMIT2,
-	NV04_PGRAPH_BOFFSET3,
-	NV04_PGRAPH_BBASE3,
-	NV04_PGRAPH_BLIMIT3,
-	NV04_PGRAPH_BOFFSET4,
-	NV04_PGRAPH_BBASE4,
-	NV04_PGRAPH_BLIMIT4,
-	NV04_PGRAPH_BOFFSET5,
-	NV04_PGRAPH_BBASE5,
-	NV04_PGRAPH_BLIMIT5,
-	NV04_PGRAPH_BPITCH0,
-	NV04_PGRAPH_BPITCH1,
-	NV04_PGRAPH_BPITCH2,
-	NV04_PGRAPH_BPITCH3,
-	NV04_PGRAPH_BPITCH4,
-	NV10_PGRAPH_SURFACE,
-	NV10_PGRAPH_STATE,
-	NV04_PGRAPH_BSWIZZLE2,
-	NV04_PGRAPH_BSWIZZLE5,
-	NV04_PGRAPH_BPIXEL,
-	NV10_PGRAPH_NOTIFY,
-	NV04_PGRAPH_PATT_COLOR0,
-	NV04_PGRAPH_PATT_COLOR1,
-	NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */
-	0x00400904,
-	0x00400908,
-	0x0040090c,
-	0x00400910,
-	0x00400914,
-	0x00400918,
-	0x0040091c,
-	0x00400920,
-	0x00400924,
-	0x00400928,
-	0x0040092c,
-	0x00400930,
-	0x00400934,
-	0x00400938,
-	0x0040093c,
-	0x00400940,
-	0x00400944,
-	0x00400948,
-	0x0040094c,
-	0x00400950,
-	0x00400954,
-	0x00400958,
-	0x0040095c,
-	0x00400960,
-	0x00400964,
-	0x00400968,
-	0x0040096c,
-	0x00400970,
-	0x00400974,
-	0x00400978,
-	0x0040097c,
-	0x00400980,
-	0x00400984,
-	0x00400988,
-	0x0040098c,
-	0x00400990,
-	0x00400994,
-	0x00400998,
-	0x0040099c,
-	0x004009a0,
-	0x004009a4,
-	0x004009a8,
-	0x004009ac,
-	0x004009b0,
-	0x004009b4,
-	0x004009b8,
-	0x004009bc,
-	0x004009c0,
-	0x004009c4,
-	0x004009c8,
-	0x004009cc,
-	0x004009d0,
-	0x004009d4,
-	0x004009d8,
-	0x004009dc,
-	0x004009e0,
-	0x004009e4,
-	0x004009e8,
-	0x004009ec,
-	0x004009f0,
-	0x004009f4,
-	0x004009f8,
-	0x004009fc,
-	NV04_PGRAPH_PATTERN,	/* 2 values from 0x400808 to 0x40080c */
-	0x0040080c,
-	NV04_PGRAPH_PATTERN_SHAPE,
-	NV03_PGRAPH_MONO_COLOR0,
-	NV04_PGRAPH_ROP3,
-	NV04_PGRAPH_CHROMA,
-	NV04_PGRAPH_BETA_AND,
-	NV04_PGRAPH_BETA_PREMULT,
-	0x00400e70,
-	0x00400e74,
-	0x00400e78,
-	0x00400e7c,
-	0x00400e80,
-	0x00400e84,
-	0x00400e88,
-	0x00400e8c,
-	0x00400ea0,
-	0x00400ea4,
-	0x00400ea8,
-	0x00400e90,
-	0x00400e94,
-	0x00400e98,
-	0x00400e9c,
-	NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */
-	NV10_PGRAPH_WINDOWCLIP_VERTICAL,   /* 8 values from 0x400f20-0x400f3c */
-	0x00400f04,
-	0x00400f24,
-	0x00400f08,
-	0x00400f28,
-	0x00400f0c,
-	0x00400f2c,
-	0x00400f10,
-	0x00400f30,
-	0x00400f14,
-	0x00400f34,
-	0x00400f18,
-	0x00400f38,
-	0x00400f1c,
-	0x00400f3c,
-	NV10_PGRAPH_XFMODE0,
-	NV10_PGRAPH_XFMODE1,
-	NV10_PGRAPH_GLOBALSTATE0,
-	NV10_PGRAPH_GLOBALSTATE1,
-	NV04_PGRAPH_STORED_FMT,
-	NV04_PGRAPH_SOURCE_COLOR,
-	NV03_PGRAPH_ABS_X_RAM,	/* 32 values from 0x400400 to 0x40047c */
-	NV03_PGRAPH_ABS_Y_RAM,	/* 32 values from 0x400480 to 0x4004fc */
-	0x00400404,
-	0x00400484,
-	0x00400408,
-	0x00400488,
-	0x0040040c,
-	0x0040048c,
-	0x00400410,
-	0x00400490,
-	0x00400414,
-	0x00400494,
-	0x00400418,
-	0x00400498,
-	0x0040041c,
-	0x0040049c,
-	0x00400420,
-	0x004004a0,
-	0x00400424,
-	0x004004a4,
-	0x00400428,
-	0x004004a8,
-	0x0040042c,
-	0x004004ac,
-	0x00400430,
-	0x004004b0,
-	0x00400434,
-	0x004004b4,
-	0x00400438,
-	0x004004b8,
-	0x0040043c,
-	0x004004bc,
-	0x00400440,
-	0x004004c0,
-	0x00400444,
-	0x004004c4,
-	0x00400448,
-	0x004004c8,
-	0x0040044c,
-	0x004004cc,
-	0x00400450,
-	0x004004d0,
-	0x00400454,
-	0x004004d4,
-	0x00400458,
-	0x004004d8,
-	0x0040045c,
-	0x004004dc,
-	0x00400460,
-	0x004004e0,
-	0x00400464,
-	0x004004e4,
-	0x00400468,
-	0x004004e8,
-	0x0040046c,
-	0x004004ec,
-	0x00400470,
-	0x004004f0,
-	0x00400474,
-	0x004004f4,
-	0x00400478,
-	0x004004f8,
-	0x0040047c,
-	0x004004fc,
-	NV03_PGRAPH_ABS_UCLIP_XMIN,
-	NV03_PGRAPH_ABS_UCLIP_XMAX,
-	NV03_PGRAPH_ABS_UCLIP_YMIN,
-	NV03_PGRAPH_ABS_UCLIP_YMAX,
-	0x00400550,
-	0x00400558,
-	0x00400554,
-	0x0040055c,
-	NV03_PGRAPH_ABS_UCLIPA_XMIN,
-	NV03_PGRAPH_ABS_UCLIPA_XMAX,
-	NV03_PGRAPH_ABS_UCLIPA_YMIN,
-	NV03_PGRAPH_ABS_UCLIPA_YMAX,
-	NV03_PGRAPH_ABS_ICLIP_XMAX,
-	NV03_PGRAPH_ABS_ICLIP_YMAX,
-	NV03_PGRAPH_XY_LOGIC_MISC0,
-	NV03_PGRAPH_XY_LOGIC_MISC1,
-	NV03_PGRAPH_XY_LOGIC_MISC2,
-	NV03_PGRAPH_XY_LOGIC_MISC3,
-	NV03_PGRAPH_CLIPX_0,
-	NV03_PGRAPH_CLIPX_1,
-	NV03_PGRAPH_CLIPY_0,
-	NV03_PGRAPH_CLIPY_1,
-	NV10_PGRAPH_COMBINER0_IN_ALPHA,
-	NV10_PGRAPH_COMBINER1_IN_ALPHA,
-	NV10_PGRAPH_COMBINER0_IN_RGB,
-	NV10_PGRAPH_COMBINER1_IN_RGB,
-	NV10_PGRAPH_COMBINER_COLOR0,
-	NV10_PGRAPH_COMBINER_COLOR1,
-	NV10_PGRAPH_COMBINER0_OUT_ALPHA,
-	NV10_PGRAPH_COMBINER1_OUT_ALPHA,
-	NV10_PGRAPH_COMBINER0_OUT_RGB,
-	NV10_PGRAPH_COMBINER1_OUT_RGB,
-	NV10_PGRAPH_COMBINER_FINAL0,
-	NV10_PGRAPH_COMBINER_FINAL1,
-	0x00400e00,
-	0x00400e04,
-	0x00400e08,
-	0x00400e0c,
-	0x00400e10,
-	0x00400e14,
-	0x00400e18,
-	0x00400e1c,
-	0x00400e20,
-	0x00400e24,
-	0x00400e28,
-	0x00400e2c,
-	0x00400e30,
-	0x00400e34,
-	0x00400e38,
-	0x00400e3c,
-	NV04_PGRAPH_PASSTHRU_0,
-	NV04_PGRAPH_PASSTHRU_1,
-	NV04_PGRAPH_PASSTHRU_2,
-	NV10_PGRAPH_DIMX_TEXTURE,
-	NV10_PGRAPH_WDIMX_TEXTURE,
-	NV10_PGRAPH_DVD_COLORFMT,
-	NV10_PGRAPH_SCALED_FORMAT,
-	NV04_PGRAPH_MISC24_0,
-	NV04_PGRAPH_MISC24_1,
-	NV04_PGRAPH_MISC24_2,
-	NV03_PGRAPH_X_MISC,
-	NV03_PGRAPH_Y_MISC,
-	NV04_PGRAPH_VALID1,
-	NV04_PGRAPH_VALID2,
-};
-
-static int nv17_graph_ctx_regs[] = {
-	NV10_PGRAPH_DEBUG_4,
-	0x004006b0,
-	0x00400eac,
-	0x00400eb0,
-	0x00400eb4,
-	0x00400eb8,
-	0x00400ebc,
-	0x00400ec0,
-	0x00400ec4,
-	0x00400ec8,
-	0x00400ecc,
-	0x00400ed0,
-	0x00400ed4,
-	0x00400ed8,
-	0x00400edc,
-	0x00400ee0,
-	0x00400a00,
-	0x00400a04,
-};
-
-struct nv10_graph_priv {
-	struct nouveau_graph base;
-	struct nv10_graph_chan *chan[32];
-	spinlock_t lock;
-};
-
-struct nv10_graph_chan {
-	struct nouveau_object base;
-	int chid;
-	int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
-	int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
-	struct pipe_state pipe_state;
-	u32 lma_window[4];
-};
-
-
-static inline struct nv10_graph_priv *
-nv10_graph_priv(struct nv10_graph_chan *chan)
-{
-	return (void *)nv_object(chan)->engine;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-#define PIPE_SAVE(priv, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
-	} while (0)
-
-#define PIPE_RESTORE(priv, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
-	} while (0)
-
-static struct nouveau_oclass
-nv10_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
-	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
-	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
-	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
-	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
-	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
-	{ 0x0056, &nv04_graph_ofuncs }, /* celcius */
-	{},
-};
-
-static struct nouveau_oclass
-nv15_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
-	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
-	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
-	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
-	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
-	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
-	{ 0x0096, &nv04_graph_ofuncs }, /* celcius */
-	{},
-};
-
-static int
-nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd,
-			   void *args, u32 size)
-{
-	struct nv10_graph_chan *chan = (void *)object->parent;
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	struct pipe_state *pipe = &chan->pipe_state;
-	u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
-	u32 xfmode0, xfmode1;
-	u32 data = *(u32 *)args;
-	int i;
-
-	chan->lma_window[(mthd - 0x1638) / 4] = data;
-
-	if (mthd != 0x1644)
-		return 0;
-
-	nv04_graph_idle(priv);
-
-	PIPE_SAVE(priv, pipe_0x0040, 0x0040);
-	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
-
-	PIPE_RESTORE(priv, chan->lma_window, 0x6790);
-
-	nv04_graph_idle(priv);
-
-	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
-
-	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
-	PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
-	PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
-
-	nv04_graph_idle(priv);
-
-	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
-	for (i = 0; i < 3; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
-	for (i = 0; i < 3; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
-
-	nv04_graph_idle(priv);
-
-	PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
-
-	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
-
-	PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
-	PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
-	PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
-	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
-	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv04_graph_idle(priv);
-
-	return 0;
-}
-
-static int
-nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
-			   void *args, u32 size)
-{
-	struct nv10_graph_chan *chan = (void *)object->parent;
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-
-	nv04_graph_idle(priv);
-
-	nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
-	nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
-	return 0;
-}
-
-static struct nouveau_omthds
-nv17_celcius_omthds[] = {
-	{ 0x1638, 0x1638, nv17_graph_mthd_lma_window },
-	{ 0x163c, 0x163c, nv17_graph_mthd_lma_window },
-	{ 0x1640, 0x1640, nv17_graph_mthd_lma_window },
-	{ 0x1644, 0x1644, nv17_graph_mthd_lma_window },
-	{ 0x1658, 0x1658, nv17_graph_mthd_lma_enable },
-	{}
-};
-
-static struct nouveau_oclass
-nv17_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
-	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
-	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
-	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
-	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
-	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
-	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
-	{ 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds },
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nv10_graph_chan *
-nv10_graph_channel(struct nv10_graph_priv *priv)
-{
-	struct nv10_graph_chan *chan = NULL;
-	if (nv_rd32(priv, 0x400144) & 0x00010000) {
-		int chid = nv_rd32(priv, 0x400148) >> 24;
-		if (chid < ARRAY_SIZE(priv->chan))
-			chan = priv->chan[chid];
-	}
-	return chan;
-}
-
-static void
-nv10_graph_save_pipe(struct nv10_graph_chan *chan)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	struct pipe_state *pipe = &chan->pipe_state;
-
-	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
-	PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
-	PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
-	PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
-	PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
-	PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
-	PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
-	PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
-}
-
-static void
-nv10_graph_load_pipe(struct nv10_graph_chan *chan)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	struct pipe_state *pipe = &chan->pipe_state;
-	u32 xfmode0, xfmode1;
-	int i;
-
-	nv04_graph_idle(priv);
-	/* XXX check haiku comments */
-	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
-	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
-	for (i = 0; i < 3; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
-	for (i = 0; i < 3; i++)
-		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-
-	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
-	nv04_graph_idle(priv);
-
-	/* restore XFMODE */
-	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
-	PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
-	PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
-	PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
-	PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
-	PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
-	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
-	PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
-	PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
-	nv04_graph_idle(priv);
-}
-
-static void
-nv10_graph_create_pipe(struct nv10_graph_chan *chan)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	struct pipe_state *pipe_state = &chan->pipe_state;
-	u32 *pipe_state_addr;
-	int i;
-#define PIPE_INIT(addr) \
-	do { \
-		pipe_state_addr = pipe_state->pipe_##addr; \
-	} while (0)
-#define PIPE_INIT_END(addr) \
-	do { \
-		u32 *__end_addr = pipe_state->pipe_##addr + \
-				ARRAY_SIZE(pipe_state->pipe_##addr); \
-		if (pipe_state_addr != __end_addr) \
-			nv_error(priv, "incomplete pipe init for 0x%x :  %p/%p\n", \
-				addr, pipe_state_addr, __end_addr); \
-	} while (0)
-#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
-
-	PIPE_INIT(0x0200);
-	for (i = 0; i < 48; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x0200);
-
-	PIPE_INIT(0x6400);
-	for (i = 0; i < 211; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x40000000);
-	NV_WRITE_PIPE_INIT(0x40000000);
-	NV_WRITE_PIPE_INIT(0x40000000);
-	NV_WRITE_PIPE_INIT(0x40000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f000000);
-	NV_WRITE_PIPE_INIT(0x3f000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	PIPE_INIT_END(0x6400);
-
-	PIPE_INIT(0x6800);
-	for (i = 0; i < 162; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x3f800000);
-	for (i = 0; i < 25; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x6800);
-
-	PIPE_INIT(0x6c00);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0xbf800000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x6c00);
-
-	PIPE_INIT(0x7000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x00000000);
-	NV_WRITE_PIPE_INIT(0x7149f2ca);
-	for (i = 0; i < 35; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x7000);
-
-	PIPE_INIT(0x7400);
-	for (i = 0; i < 48; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x7400);
-
-	PIPE_INIT(0x7800);
-	for (i = 0; i < 48; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x7800);
-
-	PIPE_INIT(0x4400);
-	for (i = 0; i < 32; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x4400);
-
-	PIPE_INIT(0x0000);
-	for (i = 0; i < 16; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x0000);
-
-	PIPE_INIT(0x0040);
-	for (i = 0; i < 4; i++)
-		NV_WRITE_PIPE_INIT(0x00000000);
-	PIPE_INIT_END(0x0040);
-
-#undef PIPE_INIT
-#undef PIPE_INIT_END
-#undef NV_WRITE_PIPE_INIT
-}
-
-static int
-nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) {
-		if (nv10_graph_ctx_regs[i] == reg)
-			return i;
-	}
-	nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
-	return -1;
-}
-
-static int
-nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
-{
-	int i;
-	for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) {
-		if (nv17_graph_ctx_regs[i] == reg)
-			return i;
-	}
-	nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
-	return -1;
-}
-
-static void
-nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
-	u32 ctx_user, ctx_switch[5];
-	int i, subchan = -1;
-
-	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
-	 * that cannot be restored via MMIO. Do it through the FIFO
-	 * instead.
-	 */
-
-	/* Look for a celsius object */
-	for (i = 0; i < 8; i++) {
-		int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
-
-		if (class == 0x56 || class == 0x96 || class == 0x99) {
-			subchan = i;
-			break;
-		}
-	}
-
-	if (subchan < 0 || !inst)
-		return;
-
-	/* Save the current ctx object */
-	ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
-	for (i = 0; i < 5; i++)
-		ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
-
-	/* Save the FIFO state */
-	st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
-	st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
-	st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
-	fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
-
-	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
-
-	/* Switch to the celsius subchannel */
-	for (i = 0; i < 5; i++)
-		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
-			nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
-	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
-
-	/* Inject NV10TCL_DMA_VTXBUF */
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
-		0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
-	nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-	/* Restore the FIFO state */
-	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
-
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
-
-	/* Restore the current ctx object */
-	for (i = 0; i < 5; i++)
-		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
-	nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
-}
-
-static int
-nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	u32 inst;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
-
-	if (nv_device(priv)->card_type >= NV_11 &&
-	    nv_device(priv)->chipset >= 0x17) {
-		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
-	}
-
-	nv10_graph_load_pipe(chan);
-
-	inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
-	nv10_graph_load_dma_vtxbuf(chan, chid, inst);
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
-	nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
-	return 0;
-}
-
-static int
-nv10_graph_unload_context(struct nv10_graph_chan *chan)
-{
-	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
-
-	if (nv_device(priv)->card_type >= NV_11 &&
-	    nv_device(priv)->chipset >= 0x17) {
-		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
-	}
-
-	nv10_graph_save_pipe(chan);
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
-	return 0;
-}
-
-static void
-nv10_graph_context_switch(struct nv10_graph_priv *priv)
-{
-	struct nv10_graph_chan *prev = NULL;
-	struct nv10_graph_chan *next = NULL;
-	unsigned long flags;
-	int chid;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv04_graph_idle(priv);
-
-	/* If previous context is valid, we need to save it */
-	prev = nv10_graph_channel(priv);
-	if (prev)
-		nv10_graph_unload_context(prev);
-
-	/* load context for next channel */
-	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
-	next = priv->chan[chid];
-	if (next)
-		nv10_graph_load_context(next, chid);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-#define NV_WRITE_CTX(reg, val) do { \
-	int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \
-	if (offset > 0) \
-		chan->nv10[offset] = val; \
-	} while (0)
-
-#define NV17_WRITE_CTX(reg, val) do { \
-	int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \
-	if (offset > 0) \
-		chan->nv17[offset] = val; \
-	} while (0)
-
-static int
-nv10_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nouveau_fifo_chan *fifo = (void *)parent;
-	struct nv10_graph_priv *priv = (void *)engine;
-	struct nv10_graph_chan *chan;
-	unsigned long flags;
-	int ret;
-
-	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (priv->chan[fifo->chid]) {
-		*pobject = nv_object(priv->chan[fifo->chid]);
-		atomic_inc(&(*pobject)->refcount);
-		spin_unlock_irqrestore(&priv->lock, flags);
-		nouveau_object_destroy(&chan->base);
-		return 1;
-	}
-
-	NV_WRITE_CTX(0x00400e88, 0x08000000);
-	NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
-	NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff);
-	NV_WRITE_CTX(0x00400e10, 0x00001000);
-	NV_WRITE_CTX(0x00400e14, 0x00001000);
-	NV_WRITE_CTX(0x00400e30, 0x00080008);
-	NV_WRITE_CTX(0x00400e34, 0x00080008);
-	if (nv_device(priv)->card_type >= NV_11 &&
-	    nv_device(priv)->chipset >= 0x17) {
-		/* is it really needed ??? */
-		NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
-					nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
-		NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
-		NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
-		NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
-		NV17_WRITE_CTX(0x00400ec0, 0x00000080);
-		NV17_WRITE_CTX(0x00400ed0, 0x00000080);
-	}
-	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
-
-	nv10_graph_create_pipe(chan);
-
-	priv->chan[fifo->chid] = chan;
-	chan->chid = fifo->chid;
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return 0;
-}
-
-static void
-nv10_graph_context_dtor(struct nouveau_object *object)
-{
-	struct nv10_graph_priv *priv = (void *)object->engine;
-	struct nv10_graph_chan *chan = (void *)object;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->chan[chan->chid] = NULL;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	nouveau_object_destroy(&chan->base);
-}
-
-static int
-nv10_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv10_graph_priv *priv = (void *)object->engine;
-	struct nv10_graph_chan *chan = (void *)object;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (nv10_graph_channel(priv) == chan)
-		nv10_graph_unload_context(chan);
-	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return nouveau_object_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv10_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x10),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_graph_context_ctor,
-		.dtor = nv10_graph_context_dtor,
-		.init = nouveau_object_init,
-		.fini = nv10_graph_context_fini,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nv10_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
-	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
-	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
-	struct nv10_graph_priv *priv = (void *)engine;
-	unsigned long flags;
-
-	pfifo->pause(pfifo, &flags);
-	nv04_graph_idle(priv);
-
-	nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
-
-	pfifo->start(pfifo, &flags);
-}
-
-const struct nouveau_bitfield nv10_graph_intr_name[] = {
-	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
-	{ NV_PGRAPH_INTR_ERROR,  "ERROR"  },
-	{}
-};
-
-const struct nouveau_bitfield nv10_graph_nstatus[] = {
-	{ NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
-	{ NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
-	{ NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
-	{ NV10_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
-	{}
-};
-
-static void
-nv10_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nv10_graph_priv *priv = (void *)subdev;
-	struct nv10_graph_chan *chan = NULL;
-	struct nouveau_namedb *namedb = NULL;
-	struct nouveau_handle *handle = NULL;
-	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
-	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
-	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
-	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
-	u32 chid = (addr & 0x01f00000) >> 20;
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00001ffc);
-	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
-	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
-	u32 show = stat;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	chan = priv->chan[chid];
-	if (chan)
-		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (stat & NV_PGRAPH_INTR_ERROR) {
-		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
-			handle = nouveau_namedb_get_class(namedb, class);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~NV_PGRAPH_INTR_ERROR;
-		}
-	}
-
-	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-		nv10_graph_context_switch(priv);
-	}
-
-	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
-	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
-	if (show) {
-		nv_error(priv, "%s", "");
-		nouveau_bitfield_print(nv10_graph_intr_name, show);
-		pr_cont(" nsource:");
-		nouveau_bitfield_print(nv04_graph_nsource, nsource);
-		pr_cont(" nstatus:");
-		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-		pr_cont("\n");
-		nv_error(priv,
-			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, nouveau_client_name(chan), subc, class, mthd,
-			 data);
-	}
-
-	nouveau_namedb_put(handle);
-}
-
-static int
-nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv10_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv10_graph_intr;
-	nv_engine(priv)->cclass = &nv10_graph_cclass;
-
-	if (nv_device(priv)->chipset <= 0x10)
-		nv_engine(priv)->sclass = nv10_graph_sclass;
-	else
-	if (nv_device(priv)->chipset <  0x17 ||
-	    nv_device(priv)->card_type < NV_11)
-		nv_engine(priv)->sclass = nv15_graph_sclass;
-	else
-		nv_engine(priv)->sclass = nv17_graph_sclass;
-
-	nv_engine(priv)->tile_prog = nv10_graph_tile_prog;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-static void
-nv10_graph_dtor(struct nouveau_object *object)
-{
-	struct nv10_graph_priv *priv = (void *)object;
-	nouveau_graph_destroy(&priv->base);
-}
-
-static int
-nv10_graph_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	struct nv10_graph_priv *priv = (void *)engine;
-	int ret, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	/* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
-
-	if (nv_device(priv)->card_type >= NV_11 &&
-	    nv_device(priv)->chipset >= 0x17) {
-		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
-		nv_wr32(priv, 0x400a10, 0x03ff3fb6);
-		nv_wr32(priv, 0x400838, 0x002f8684);
-		nv_wr32(priv, 0x40083c, 0x00115f3f);
-		nv_wr32(priv, 0x4006b0, 0x40000020);
-	} else {
-		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
-	}
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < pfb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
-	nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
-
-	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
-	return 0;
-}
-
-static int
-nv10_graph_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv10_graph_priv *priv = (void *)object;
-	return nouveau_graph_fini(&priv->base, suspend);
-}
-
-struct nouveau_oclass
-nv10_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x10),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_graph_ctor,
-		.dtor = nv10_graph_dtor,
-		.init = nv10_graph_init,
-		.fini = nv10_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
deleted file mode 100644
index 2b0e8f4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv108_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa140, &nouveau_object_ofuncs },
-	{ KEPLER_B, &nvc0_fermi_ofuncs },
-	{ 0xa1c0, &nouveau_object_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nv108_graph_init_main_0[] = {
-	{ 0x400080,   1, 0x04, 0x003083c2 },
-	{ 0x400088,   1, 0x04, 0x0001bfe7 },
-	{ 0x40008c,   1, 0x04, 0x00000000 },
-	{ 0x400090,   1, 0x04, 0x00000030 },
-	{ 0x40013c,   1, 0x04, 0x003901f7 },
-	{ 0x400140,   1, 0x04, 0x00000100 },
-	{ 0x400144,   1, 0x04, 0x00000000 },
-	{ 0x400148,   1, 0x04, 0x00000110 },
-	{ 0x400138,   1, 0x04, 0x00000000 },
-	{ 0x400130,   2, 0x04, 0x00000000 },
-	{ 0x400124,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x00000000 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{ 0x405928,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nv108_graph_init_gpc_unk_0[] = {
-	{ 0x418604,   1, 0x04, 0x00000000 },
-	{ 0x418680,   1, 0x04, 0x00000000 },
-	{ 0x418714,   1, 0x04, 0x00000000 },
-	{ 0x418384,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_setup_1[] = {
-	{ 0x4188c8,   2, 0x04, 0x00000000 },
-	{ 0x4188d0,   1, 0x04, 0x00010000 },
-	{ 0x4188d4,   1, 0x04, 0x00000201 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ac8,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419abc,   2, 0x04, 0x00000000 },
-	{ 0x419ab4,   1, 0x04, 0x00000000 },
-	{ 0x419aa8,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419ca8,   1, 0x04, 0x00000000 },
-	{ 0x419cb0,   1, 0x04, 0x01000000 },
-	{ 0x419cb4,   1, 0x04, 0x00000000 },
-	{ 0x419cb8,   1, 0x04, 0x00b08bea },
-	{ 0x419c84,   1, 0x04, 0x00010384 },
-	{ 0x419cbc,   1, 0x04, 0x281b3646 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{ 0x419c80,   1, 0x04, 0x00000230 },
-	{ 0x419ccc,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nv108_graph_pack_mmio[] = {
-	{ nv108_graph_init_main_0 },
-	{ nvf0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nv108_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvf0_graph_init_sked_0 },
-	{ nvf0_graph_init_cwd_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nv108_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nv108_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nvf0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nve4_graph_init_tpccs_0 },
-	{ nv108_graph_init_tex_0 },
-	{ nve4_graph_init_pe_0 },
-	{ nv108_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvf0_graph_init_sm_0 },
-	{ nvd7_graph_init_pes_0 },
-	{ nvd7_graph_init_wwdx_0 },
-	{ nvd7_graph_init_cbm_0 },
-	{ nve4_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv108_graph_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
-	static const struct {
-		u32 addr;
-		u32 data;
-	} magic[] = {
-		{ 0x020520, 0xfffffffc },
-		{ 0x020524, 0xfffffffe },
-		{ 0x020524, 0xfffffffc },
-		{ 0x020524, 0xfffffff8 },
-		{ 0x020524, 0xffffffe0 },
-		{ 0x020530, 0xfffffffe },
-		{ 0x02052c, 0xfffffffa },
-		{ 0x02052c, 0xfffffff0 },
-		{ 0x02052c, 0xffffffc0 },
-		{ 0x02052c, 0xffffff00 },
-		{ 0x02052c, 0xfffffc00 },
-		{ 0x02052c, 0xfffcfc00 },
-		{ 0x02052c, 0xfff0fc00 },
-		{ 0x02052c, 0xff80fc00 },
-		{ 0x020528, 0xfffffffe },
-		{ 0x020528, 0xfffffffc },
-	};
-	int i;
-
-	nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
-	nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
-	for (i = 0; i < ARRAY_SIZE(magic); i++) {
-		nv_wr32(priv, magic[i].addr, magic[i].data);
-		nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
-	}
-
-	return nouveau_graph_fini(&priv->base, suspend);
-}
-
-#include "fuc/hubnv108.fuc5.h"
-
-static struct nvc0_graph_ucode
-nv108_graph_fecs_ucode = {
-	.code.data = nv108_grhub_code,
-	.code.size = sizeof(nv108_grhub_code),
-	.data.data = nv108_grhub_data,
-	.data.size = sizeof(nv108_grhub_data),
-};
-
-#include "fuc/gpcnv108.fuc5.h"
-
-static struct nvc0_graph_ucode
-nv108_graph_gpccs_ucode = {
-	.code.data = nv108_grgpc_code,
-	.code.size = sizeof(nv108_grgpc_code),
-	.data.data = nv108_grgpc_data,
-	.data.size = sizeof(nv108_grgpc_data),
-};
-
-struct nouveau_oclass *
-nv108_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x08),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve4_graph_init,
-		.fini = nv108_graph_fini,
-	},
-	.cclass = &nv108_grctx_oclass,
-	.sclass =  nv108_graph_sclass,
-	.mmio = nv108_graph_pack_mmio,
-	.fecs.ucode = &nv108_graph_fecs_ucode,
-	.gpccs.ucode = &nv108_graph_gpccs_ucode,
-	.ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
deleted file mode 100644
index ceb9c74..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
+++ /dev/null
@@ -1,383 +0,0 @@
-#include <core/client.h>
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv20_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
-	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
-	{ 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */
-	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
-	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv20_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
-					   0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC,
-					   &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x033c, 0xffff0000);
-	nv_wo32(chan, 0x03a0, 0x0fff0000);
-	nv_wo32(chan, 0x03a4, 0x0fff0000);
-	nv_wo32(chan, 0x047c, 0x00000101);
-	nv_wo32(chan, 0x0490, 0x00000111);
-	nv_wo32(chan, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(chan, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(chan, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x05a4, 0x4b7fffff);
-	nv_wo32(chan, 0x05fc, 0x00000001);
-	nv_wo32(chan, 0x0604, 0x00004000);
-	nv_wo32(chan, 0x0610, 0x00000001);
-	nv_wo32(chan, 0x0618, 0x00040000);
-	nv_wo32(chan, 0x061c, 0x00010000);
-	for (i = 0x1c1c; i <= 0x248c; i += 16) {
-		nv_wo32(chan, (i + 0), 0x10700ff9);
-		nv_wo32(chan, (i + 4), 0x0436086c);
-		nv_wo32(chan, (i + 8), 0x000c001b);
-	}
-	nv_wo32(chan, 0x281c, 0x3f800000);
-	nv_wo32(chan, 0x2830, 0x3f800000);
-	nv_wo32(chan, 0x285c, 0x40000000);
-	nv_wo32(chan, 0x2860, 0x3f800000);
-	nv_wo32(chan, 0x2864, 0x3f000000);
-	nv_wo32(chan, 0x286c, 0x40000000);
-	nv_wo32(chan, 0x2870, 0x3f800000);
-	nv_wo32(chan, 0x2878, 0xbf800000);
-	nv_wo32(chan, 0x2880, 0xbf800000);
-	nv_wo32(chan, 0x34a4, 0x000fe000);
-	nv_wo32(chan, 0x3530, 0x000003f8);
-	nv_wo32(chan, 0x3540, 0x002fe000);
-	for (i = 0x355c; i <= 0x3578; i += 4)
-		nv_wo32(chan, i, 0x001c527c);
-	return 0;
-}
-
-int
-nv20_graph_context_init(struct nouveau_object *object)
-{
-	struct nv20_graph_priv *priv = (void *)object->engine;
-	struct nv20_graph_chan *chan = (void *)object;
-	int ret;
-
-	ret = nouveau_graph_context_init(&chan->base);
-	if (ret)
-		return ret;
-
-	nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
-	return 0;
-}
-
-int
-nv20_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv20_graph_priv *priv = (void *)object->engine;
-	struct nv20_graph_chan *chan = (void *)object;
-	int chid = -1;
-
-	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
-	if (nv_rd32(priv, 0x400144) & 0x00010000)
-		chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
-	if (chan->chid == chid) {
-		nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
-		nv_wr32(priv, 0x400788, 0x00000002);
-		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
-		nv_wr32(priv, 0x400144, 0x10000000);
-		nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
-	}
-	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
-
-	nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
-	return nouveau_graph_context_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv20_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x20),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv20_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-void
-nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
-	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
-	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
-	struct nv20_graph_priv *priv = (void *)engine;
-	unsigned long flags;
-
-	pfifo->pause(pfifo, &flags);
-	nv04_graph_idle(priv);
-
-	nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
-
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
-
-	if (nv_device(engine)->chipset != 0x34) {
-		nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
-	}
-
-	pfifo->start(pfifo, &flags);
-}
-
-void
-nv20_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle;
-	struct nv20_graph_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
-	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
-	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
-	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
-	u32 chid = (addr & 0x01f00000) >> 20;
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00001ffc);
-	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
-	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
-	u32 show = stat;
-
-	engctx = nouveau_engctx_get(engine, chid);
-	if (stat & NV_PGRAPH_INTR_ERROR) {
-		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-			handle = nouveau_handle_get_class(engctx, class);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~NV_PGRAPH_INTR_ERROR;
-			nouveau_handle_put(handle);
-		}
-	}
-
-	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
-	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
-	if (show) {
-		nv_error(priv, "%s", "");
-		nouveau_bitfield_print(nv10_graph_intr_name, show);
-		pr_cont(" nsource:");
-		nouveau_bitfield_print(nv04_graph_nsource, nsource);
-		pr_cont(" nstatus:");
-		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-		pr_cont("\n");
-		nv_error(priv,
-			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, nouveau_client_name(engctx), subc, class, mthd,
-			 data);
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv20_graph_cclass;
-	nv_engine(priv)->sclass = nv20_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-void
-nv20_graph_dtor(struct nouveau_object *object)
-{
-	struct nv20_graph_priv *priv = (void *)object;
-	nouveau_gpuobj_ref(NULL, &priv->ctxtab);
-	nouveau_graph_destroy(&priv->base);
-}
-
-int
-nv20_graph_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nv20_graph_priv *priv = (void *)engine;
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	u32 tmp, vramsz;
-	int ret, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
-
-	if (nv_device(priv)->chipset == 0x20) {
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
-		for (i = 0; i < 15; i++)
-			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
-		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
-	} else {
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
-		for (i = 0; i < 32; i++)
-			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
-		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
-	}
-
-	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
-	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
-	nv_wr32(priv, 0x40009C           , 0x00000040);
-
-	if (nv_device(priv)->chipset >= 0x25) {
-		nv_wr32(priv, 0x400890, 0x00a8cfff);
-		nv_wr32(priv, 0x400610, 0x304B1FB6);
-		nv_wr32(priv, 0x400B80, 0x1cbd3883);
-		nv_wr32(priv, 0x400B84, 0x44000000);
-		nv_wr32(priv, 0x400098, 0x40000080);
-		nv_wr32(priv, 0x400B88, 0x000000ff);
-
-	} else {
-		nv_wr32(priv, 0x400880, 0x0008c7df);
-		nv_wr32(priv, 0x400094, 0x00000005);
-		nv_wr32(priv, 0x400B80, 0x45eae20e);
-		nv_wr32(priv, 0x400B84, 0x24000000);
-		nv_wr32(priv, 0x400098, 0x00000040);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
-	}
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < pfb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
-	nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
-
-	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
-	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
-	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
-	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
-
-	/* begin RAM config */
-	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
-	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
-	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
-	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
-	nv_wr32(priv, 0x400820, 0);
-	nv_wr32(priv, 0x400824, 0);
-	nv_wr32(priv, 0x400864, vramsz - 1);
-	nv_wr32(priv, 0x400868, vramsz - 1);
-
-	/* interesting.. the below overwrites some of the tile setup above.. */
-	nv_wr32(priv, 0x400B20, 0x00000000);
-	nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
-	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
-	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
-	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
-	return 0;
-}
-
-struct nouveau_oclass
-nv20_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x20),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv20_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv20_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
deleted file mode 100644
index 2bea731..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NV20_GRAPH_H__
-#define __NV20_GRAPH_H__
-
-#include <core/enum.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-struct nv20_graph_priv {
-	struct nouveau_graph base;
-	struct nouveau_gpuobj *ctxtab;
-};
-
-struct nv20_graph_chan {
-	struct nouveau_graph_chan base;
-	int chid;
-};
-
-extern struct nouveau_oclass nv25_graph_sclass[];
-int  nv20_graph_context_init(struct nouveau_object *);
-int  nv20_graph_context_fini(struct nouveau_object *, bool);
-
-void nv20_graph_tile_prog(struct nouveau_engine *, int);
-void nv20_graph_intr(struct nouveau_subdev *);
-
-void nv20_graph_dtor(struct nouveau_object *);
-int  nv20_graph_init(struct nouveau_object *);
-
-int  nv30_graph_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
deleted file mode 100644
index f8a6fdd..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nv25_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
-	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
-	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
-	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv25_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
-					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x035c, 0xffff0000);
-	nv_wo32(chan, 0x03c0, 0x0fff0000);
-	nv_wo32(chan, 0x03c4, 0x0fff0000);
-	nv_wo32(chan, 0x049c, 0x00000101);
-	nv_wo32(chan, 0x04b0, 0x00000111);
-	nv_wo32(chan, 0x04c8, 0x00000080);
-	nv_wo32(chan, 0x04cc, 0xffff0000);
-	nv_wo32(chan, 0x04d0, 0x00000001);
-	nv_wo32(chan, 0x04e4, 0x44400000);
-	nv_wo32(chan, 0x04fc, 0x4b800000);
-	for (i = 0x0510; i <= 0x051c; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x0530; i <= 0x053c; i += 4)
-		nv_wo32(chan, i, 0x00080000);
-	for (i = 0x0548; i <= 0x0554; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x0558; i <= 0x0564; i += 4)
-		nv_wo32(chan, i, 0x000105b8);
-	for (i = 0x0568; i <= 0x0574; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	for (i = 0x0598; i <= 0x05d4; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x05e0, 0x4b7fffff);
-	nv_wo32(chan, 0x0620, 0x00000080);
-	nv_wo32(chan, 0x0624, 0x30201000);
-	nv_wo32(chan, 0x0628, 0x70605040);
-	nv_wo32(chan, 0x062c, 0xb0a09080);
-	nv_wo32(chan, 0x0630, 0xf0e0d0c0);
-	nv_wo32(chan, 0x0664, 0x00000001);
-	nv_wo32(chan, 0x066c, 0x00004000);
-	nv_wo32(chan, 0x0678, 0x00000001);
-	nv_wo32(chan, 0x0680, 0x00040000);
-	nv_wo32(chan, 0x0684, 0x00010000);
-	for (i = 0x1b04; i <= 0x2374; i += 16) {
-		nv_wo32(chan, (i + 0), 0x10700ff9);
-		nv_wo32(chan, (i + 4), 0x0436086c);
-		nv_wo32(chan, (i + 8), 0x000c001b);
-	}
-	nv_wo32(chan, 0x2704, 0x3f800000);
-	nv_wo32(chan, 0x2718, 0x3f800000);
-	nv_wo32(chan, 0x2744, 0x40000000);
-	nv_wo32(chan, 0x2748, 0x3f800000);
-	nv_wo32(chan, 0x274c, 0x3f000000);
-	nv_wo32(chan, 0x2754, 0x40000000);
-	nv_wo32(chan, 0x2758, 0x3f800000);
-	nv_wo32(chan, 0x2760, 0xbf800000);
-	nv_wo32(chan, 0x2768, 0xbf800000);
-	nv_wo32(chan, 0x308c, 0x000fe000);
-	nv_wo32(chan, 0x3108, 0x000003f8);
-	nv_wo32(chan, 0x3468, 0x002fe000);
-	for (i = 0x3484; i <= 0x34a0; i += 4)
-		nv_wo32(chan, i, 0x001c527c);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv25_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x25),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv25_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv25_graph_cclass;
-	nv_engine(priv)->sclass = nv25_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv25_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x25),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv25_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv20_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
deleted file mode 100644
index 5de9caa..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv2a_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
-					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x033c, 0xffff0000);
-	nv_wo32(chan, 0x03a0, 0x0fff0000);
-	nv_wo32(chan, 0x03a4, 0x0fff0000);
-	nv_wo32(chan, 0x047c, 0x00000101);
-	nv_wo32(chan, 0x0490, 0x00000111);
-	nv_wo32(chan, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(chan, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(chan, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x05a4, 0x4b7fffff);
-	nv_wo32(chan, 0x05fc, 0x00000001);
-	nv_wo32(chan, 0x0604, 0x00004000);
-	nv_wo32(chan, 0x0610, 0x00000001);
-	nv_wo32(chan, 0x0618, 0x00040000);
-	nv_wo32(chan, 0x061c, 0x00010000);
-	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
-		nv_wo32(chan, (i + 0), 0x10700ff9);
-		nv_wo32(chan, (i + 4), 0x0436086c);
-		nv_wo32(chan, (i + 8), 0x000c001b);
-	}
-	nv_wo32(chan, 0x269c, 0x3f800000);
-	nv_wo32(chan, 0x26b0, 0x3f800000);
-	nv_wo32(chan, 0x26dc, 0x40000000);
-	nv_wo32(chan, 0x26e0, 0x3f800000);
-	nv_wo32(chan, 0x26e4, 0x3f000000);
-	nv_wo32(chan, 0x26ec, 0x40000000);
-	nv_wo32(chan, 0x26f0, 0x3f800000);
-	nv_wo32(chan, 0x26f8, 0xbf800000);
-	nv_wo32(chan, 0x2700, 0xbf800000);
-	nv_wo32(chan, 0x3024, 0x000fe000);
-	nv_wo32(chan, 0x30a0, 0x000003f8);
-	nv_wo32(chan, 0x33fc, 0x002fe000);
-	for (i = 0x341c; i <= 0x3438; i += 4)
-		nv_wo32(chan, i, 0x001c527c);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv2a_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x2a),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv2a_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv2a_graph_cclass;
-	nv_engine(priv)->sclass = nv25_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv2a_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x2a),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv2a_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv20_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
deleted file mode 100644
index 2f9dbc7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
+++ /dev/null
@@ -1,237 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv30_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
-	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
-	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
-	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
-	{ 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv30_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
-					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x0410, 0x00000101);
-	nv_wo32(chan, 0x0424, 0x00000111);
-	nv_wo32(chan, 0x0428, 0x00000060);
-	nv_wo32(chan, 0x0444, 0x00000080);
-	nv_wo32(chan, 0x0448, 0xffff0000);
-	nv_wo32(chan, 0x044c, 0x00000001);
-	nv_wo32(chan, 0x0460, 0x44400000);
-	nv_wo32(chan, 0x048c, 0xffff0000);
-	for (i = 0x04e0; i < 0x04e8; i += 4)
-		nv_wo32(chan, i, 0x0fff0000);
-	nv_wo32(chan, 0x04ec, 0x00011100);
-	for (i = 0x0508; i < 0x0548; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x0550, 0x4b7fffff);
-	nv_wo32(chan, 0x058c, 0x00000080);
-	nv_wo32(chan, 0x0590, 0x30201000);
-	nv_wo32(chan, 0x0594, 0x70605040);
-	nv_wo32(chan, 0x0598, 0xb8a89888);
-	nv_wo32(chan, 0x059c, 0xf8e8d8c8);
-	nv_wo32(chan, 0x05b0, 0xb0000000);
-	for (i = 0x0600; i < 0x0640; i += 4)
-		nv_wo32(chan, i, 0x00010588);
-	for (i = 0x0640; i < 0x0680; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x06c0; i < 0x0700; i += 4)
-		nv_wo32(chan, i, 0x0008aae4);
-	for (i = 0x0700; i < 0x0740; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x0740; i < 0x0780; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	nv_wo32(chan, 0x085c, 0x00040000);
-	nv_wo32(chan, 0x0860, 0x00010000);
-	for (i = 0x0864; i < 0x0874; i += 4)
-		nv_wo32(chan, i, 0x00040004);
-	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
-		nv_wo32(chan, i + 0, 0x10700ff9);
-		nv_wo32(chan, i + 1, 0x0436086c);
-		nv_wo32(chan, i + 2, 0x000c001b);
-	}
-	for (i = 0x30b8; i < 0x30c8; i += 4)
-		nv_wo32(chan, i, 0x0000ffff);
-	nv_wo32(chan, 0x344c, 0x3f800000);
-	nv_wo32(chan, 0x3808, 0x3f800000);
-	nv_wo32(chan, 0x381c, 0x3f800000);
-	nv_wo32(chan, 0x3848, 0x40000000);
-	nv_wo32(chan, 0x384c, 0x3f800000);
-	nv_wo32(chan, 0x3850, 0x3f000000);
-	nv_wo32(chan, 0x3858, 0x40000000);
-	nv_wo32(chan, 0x385c, 0x3f800000);
-	nv_wo32(chan, 0x3864, 0xbf800000);
-	nv_wo32(chan, 0x386c, 0xbf800000);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv30_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x30),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv30_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv30_graph_cclass;
-	nv_engine(priv)->sclass = nv30_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-int
-nv30_graph_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nv20_graph_priv *priv = (void *)engine;
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	int ret, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
-
-	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(priv, 0x400890, 0x01b463ff);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
-	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
-	nv_wr32(priv, 0x400B80, 0x1003d888);
-	nv_wr32(priv, 0x400B84, 0x0c000000);
-	nv_wr32(priv, 0x400098, 0x00000000);
-	nv_wr32(priv, 0x40009C, 0x0005ad00);
-	nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
-	nv_wr32(priv, 0x4000a0, 0x00000000);
-	nv_wr32(priv, 0x4000a4, 0x00000008);
-	nv_wr32(priv, 0x4008a8, 0xb784a400);
-	nv_wr32(priv, 0x400ba0, 0x002f8685);
-	nv_wr32(priv, 0x400ba4, 0x00231f3f);
-	nv_wr32(priv, 0x4008a4, 0x40000020);
-
-	if (nv_device(priv)->chipset == 0x34) {
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
-		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
-		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
-	}
-
-	nv_wr32(priv, 0x4000c0, 0x00000016);
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < pfb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
-	nv_wr32(priv, 0x0040075c             , 0x00000001);
-
-	/* begin RAM config */
-	/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
-	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
-	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
-	if (nv_device(priv)->chipset != 0x34) {
-		nv_wr32(priv, 0x400750, 0x00EA0000);
-		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
-		nv_wr32(priv, 0x400750, 0x00EA0004);
-		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
-	}
-	return 0;
-}
-
-struct nouveau_oclass
-nv30_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x30),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv30_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv30_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
deleted file mode 100644
index 34dd26c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
+++ /dev/null
@@ -1,167 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv34_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
-	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
-	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
-	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
-	{ 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv34_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
-					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x040c, 0x01000101);
-	nv_wo32(chan, 0x0420, 0x00000111);
-	nv_wo32(chan, 0x0424, 0x00000060);
-	nv_wo32(chan, 0x0440, 0x00000080);
-	nv_wo32(chan, 0x0444, 0xffff0000);
-	nv_wo32(chan, 0x0448, 0x00000001);
-	nv_wo32(chan, 0x045c, 0x44400000);
-	nv_wo32(chan, 0x0480, 0xffff0000);
-	for (i = 0x04d4; i < 0x04dc; i += 4)
-		nv_wo32(chan, i, 0x0fff0000);
-	nv_wo32(chan, 0x04e0, 0x00011100);
-	for (i = 0x04fc; i < 0x053c; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x0544, 0x4b7fffff);
-	nv_wo32(chan, 0x057c, 0x00000080);
-	nv_wo32(chan, 0x0580, 0x30201000);
-	nv_wo32(chan, 0x0584, 0x70605040);
-	nv_wo32(chan, 0x0588, 0xb8a89888);
-	nv_wo32(chan, 0x058c, 0xf8e8d8c8);
-	nv_wo32(chan, 0x05a0, 0xb0000000);
-	for (i = 0x05f0; i < 0x0630; i += 4)
-		nv_wo32(chan, i, 0x00010588);
-	for (i = 0x0630; i < 0x0670; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x06b0; i < 0x06f0; i += 4)
-		nv_wo32(chan, i, 0x0008aae4);
-	for (i = 0x06f0; i < 0x0730; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x0730; i < 0x0770; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	nv_wo32(chan, 0x0850, 0x00040000);
-	nv_wo32(chan, 0x0854, 0x00010000);
-	for (i = 0x0858; i < 0x0868; i += 4)
-		nv_wo32(chan, i, 0x00040004);
-	for (i = 0x15ac; i <= 0x271c ; i += 16) {
-		nv_wo32(chan, i + 0, 0x10700ff9);
-		nv_wo32(chan, i + 1, 0x0436086c);
-		nv_wo32(chan, i + 2, 0x000c001b);
-	}
-	for (i = 0x274c; i < 0x275c; i += 4)
-		nv_wo32(chan, i, 0x0000ffff);
-	nv_wo32(chan, 0x2ae0, 0x3f800000);
-	nv_wo32(chan, 0x2e9c, 0x3f800000);
-	nv_wo32(chan, 0x2eb0, 0x3f800000);
-	nv_wo32(chan, 0x2edc, 0x40000000);
-	nv_wo32(chan, 0x2ee0, 0x3f800000);
-	nv_wo32(chan, 0x2ee4, 0x3f000000);
-	nv_wo32(chan, 0x2eec, 0x40000000);
-	nv_wo32(chan, 0x2ef0, 0x3f800000);
-	nv_wo32(chan, 0x2ef8, 0xbf800000);
-	nv_wo32(chan, 0x2f00, 0xbf800000);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv34_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x34),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv34_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv34_graph_cclass;
-	nv_engine(priv)->sclass = nv34_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv34_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x34),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv34_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv30_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
deleted file mode 100644
index 2fb5756..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
+++ /dev/null
@@ -1,165 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv35_graph_sclass[] = {
-	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
-	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
-	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
-	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
-	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
-	{ 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv35_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv20_graph_chan *chan;
-	int ret, i;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c,
-					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	chan->chid = nouveau_fifo_chan(parent)->chid;
-
-	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
-	nv_wo32(chan, 0x040c, 0x00000101);
-	nv_wo32(chan, 0x0420, 0x00000111);
-	nv_wo32(chan, 0x0424, 0x00000060);
-	nv_wo32(chan, 0x0440, 0x00000080);
-	nv_wo32(chan, 0x0444, 0xffff0000);
-	nv_wo32(chan, 0x0448, 0x00000001);
-	nv_wo32(chan, 0x045c, 0x44400000);
-	nv_wo32(chan, 0x0488, 0xffff0000);
-	for (i = 0x04dc; i < 0x04e4; i += 4)
-		nv_wo32(chan, i, 0x0fff0000);
-	nv_wo32(chan, 0x04e8, 0x00011100);
-	for (i = 0x0504; i < 0x0544; i += 4)
-		nv_wo32(chan, i, 0x07ff0000);
-	nv_wo32(chan, 0x054c, 0x4b7fffff);
-	nv_wo32(chan, 0x0588, 0x00000080);
-	nv_wo32(chan, 0x058c, 0x30201000);
-	nv_wo32(chan, 0x0590, 0x70605040);
-	nv_wo32(chan, 0x0594, 0xb8a89888);
-	nv_wo32(chan, 0x0598, 0xf8e8d8c8);
-	nv_wo32(chan, 0x05ac, 0xb0000000);
-	for (i = 0x0604; i < 0x0644; i += 4)
-		nv_wo32(chan, i, 0x00010588);
-	for (i = 0x0644; i < 0x0684; i += 4)
-		nv_wo32(chan, i, 0x00030303);
-	for (i = 0x06c4; i < 0x0704; i += 4)
-		nv_wo32(chan, i, 0x0008aae4);
-	for (i = 0x0704; i < 0x0744; i += 4)
-		nv_wo32(chan, i, 0x01012000);
-	for (i = 0x0744; i < 0x0784; i += 4)
-		nv_wo32(chan, i, 0x00080008);
-	nv_wo32(chan, 0x0860, 0x00040000);
-	nv_wo32(chan, 0x0864, 0x00010000);
-	for (i = 0x0868; i < 0x0878; i += 4)
-		nv_wo32(chan, i, 0x00040004);
-	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
-		nv_wo32(chan, i + 0, 0x10700ff9);
-		nv_wo32(chan, i + 4, 0x0436086c);
-		nv_wo32(chan, i + 8, 0x000c001b);
-	}
-	for (i = 0x30bc; i < 0x30cc; i += 4)
-		nv_wo32(chan, i, 0x0000ffff);
-	nv_wo32(chan, 0x3450, 0x3f800000);
-	nv_wo32(chan, 0x380c, 0x3f800000);
-	nv_wo32(chan, 0x3820, 0x3f800000);
-	nv_wo32(chan, 0x384c, 0x40000000);
-	nv_wo32(chan, 0x3850, 0x3f800000);
-	nv_wo32(chan, 0x3854, 0x3f000000);
-	nv_wo32(chan, 0x385c, 0x40000000);
-	nv_wo32(chan, 0x3860, 0x3f800000);
-	nv_wo32(chan, 0x3868, 0xbf800000);
-	nv_wo32(chan, 0x3870, 0xbf800000);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv35_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x35),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv35_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = nv20_graph_context_init,
-		.fini = nv20_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv20_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv20_graph_intr;
-	nv_engine(priv)->cclass = &nv35_graph_cclass;
-	nv_engine(priv)->sclass = nv35_graph_sclass;
-	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv35_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x35),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv35_graph_ctor,
-		.dtor = nv20_graph_dtor,
-		.init = nv30_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
deleted file mode 100644
index 4f40117..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-#include <core/engctx.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-#include "nv40.h"
-#include "regs.h"
-
-struct nv40_graph_priv {
-	struct nouveau_graph base;
-	u32 size;
-};
-
-struct nv40_graph_chan {
-	struct nouveau_graph_chan base;
-};
-
-static u64
-nv40_graph_units(struct nouveau_graph *graph)
-{
-	struct nv40_graph_priv *priv = (void *)graph;
-
-	return nv_rd32(priv, 0x1540);
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nv40_graph_object_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    20, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-#ifdef __BIG_ENDIAN
-	nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
-#endif
-	nv_wo32(obj, 0x0c, 0x00000000);
-	nv_wo32(obj, 0x10, 0x00000000);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv40_graph_ofuncs = {
-	.ctor = nv40_graph_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv40_graph_sclass[] = {
-	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
-	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
-	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
-	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
-	{ 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */
-	{},
-};
-
-static struct nouveau_oclass
-nv44_graph_sclass[] = {
-	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
-	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
-	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
-	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
-	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
-	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
-	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
-	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
-	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
-	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
-	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
-	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
-	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
-	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
-	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
-	{ 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */
-	{},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv40_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv40_graph_priv *priv = (void *)engine;
-	struct nv40_graph_chan *chan;
-	int ret;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
-					   priv->size, 16,
-					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
-	nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
-	return 0;
-}
-
-static int
-nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv40_graph_priv *priv = (void *)object->engine;
-	struct nv40_graph_chan *chan = (void *)object;
-	u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
-	int ret = 0;
-
-	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
-
-	if (nv_rd32(priv, 0x40032c) == inst) {
-		if (suspend) {
-			nv_wr32(priv, 0x400720, 0x00000000);
-			nv_wr32(priv, 0x400784, inst);
-			nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
-			nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
-			if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
-				u32 insn = nv_rd32(priv, 0x400308);
-				nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
-				ret = -EBUSY;
-			}
-		}
-
-		nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
-	}
-
-	if (nv_rd32(priv, 0x400330) == inst)
-		nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
-
-	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
-	return ret;
-}
-
-static struct nouveau_oclass
-nv40_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = nv40_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
-	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
-	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
-	struct nv40_graph_priv *priv = (void *)engine;
-	unsigned long flags;
-
-	pfifo->pause(pfifo, &flags);
-	nv04_graph_idle(priv);
-
-	switch (nv_device(priv)->chipset) {
-	case 0x40:
-	case 0x41:
-	case 0x42:
-	case 0x43:
-	case 0x45:
-	case 0x4e:
-		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
-		switch (nv_device(priv)->chipset) {
-		case 0x40:
-		case 0x45:
-			nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
-			nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);
-			break;
-		case 0x41:
-		case 0x42:
-		case 0x43:
-			nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);
-			nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);
-			break;
-		default:
-			break;
-		}
-		break;
-	case 0x44:
-	case 0x4a:
-		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
-		break;
-	case 0x46:
-	case 0x4c:
-	case 0x47:
-	case 0x49:
-	case 0x4b:
-	case 0x63:
-	case 0x67:
-	case 0x68:
-		nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
-		switch (nv_device(priv)->chipset) {
-		case 0x47:
-		case 0x49:
-		case 0x4b:
-			nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
-			nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-	pfifo->start(pfifo, &flags);
-}
-
-static void
-nv40_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle = NULL;
-	struct nv40_graph_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
-	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
-	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
-	u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff;
-	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00001ffc);
-	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
-	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
-	u32 show = stat;
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & NV_PGRAPH_INTR_ERROR) {
-		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-			handle = nouveau_handle_get_class(engctx, class);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~NV_PGRAPH_INTR_ERROR;
-			nouveau_handle_put(handle);
-		}
-
-		if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
-			nv_mask(priv, 0x402000, 0, 0);
-		}
-	}
-
-	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
-	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
-	if (show) {
-		nv_error(priv, "%s", "");
-		nouveau_bitfield_print(nv10_graph_intr_name, show);
-		pr_cont(" nsource:");
-		nouveau_bitfield_print(nv04_graph_nsource, nsource);
-		pr_cont(" nstatus:");
-		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-		pr_cont("\n");
-		nv_error(priv,
-			 "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, inst << 4, nouveau_client_name(engctx), subc,
-			 class, mthd, data);
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv40_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00001000;
-	nv_subdev(priv)->intr = nv40_graph_intr;
-	nv_engine(priv)->cclass = &nv40_graph_cclass;
-	if (nv44_graph_class(priv))
-		nv_engine(priv)->sclass = nv44_graph_sclass;
-	else
-		nv_engine(priv)->sclass = nv40_graph_sclass;
-	nv_engine(priv)->tile_prog = nv40_graph_tile_prog;
-
-	priv->base.units = nv40_graph_units;
-	return 0;
-}
-
-static int
-nv40_graph_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	struct nv40_graph_priv *priv = (void *)engine;
-	int ret, i, j;
-	u32 vramsz;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* generate and upload context program */
-	ret = nv40_grctx_init(nv_device(priv), &priv->size);
-	if (ret)
-		return ret;
-
-	/* No context present currently */
-	nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
-
-	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
-	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
-
-	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
-
-	j = nv_rd32(priv, 0x1540) & 0xff;
-	if (j) {
-		for (i = 0; !(j & 1); j >>= 1, i++)
-			;
-		nv_wr32(priv, 0x405000, i);
-	}
-
-	if (nv_device(priv)->chipset == 0x40) {
-		nv_wr32(priv, 0x4009b0, 0x83280fff);
-		nv_wr32(priv, 0x4009b4, 0x000000a0);
-	} else {
-		nv_wr32(priv, 0x400820, 0x83280eff);
-		nv_wr32(priv, 0x400824, 0x000000a0);
-	}
-
-	switch (nv_device(priv)->chipset) {
-	case 0x40:
-	case 0x45:
-		nv_wr32(priv, 0x4009b8, 0x0078e366);
-		nv_wr32(priv, 0x4009bc, 0x0000014c);
-		break;
-	case 0x41:
-	case 0x42: /* pciid also 0x00Cx */
-	/* case 0x0120: XXX (pciid) */
-		nv_wr32(priv, 0x400828, 0x007596ff);
-		nv_wr32(priv, 0x40082c, 0x00000108);
-		break;
-	case 0x43:
-		nv_wr32(priv, 0x400828, 0x0072cb77);
-		nv_wr32(priv, 0x40082c, 0x00000108);
-		break;
-	case 0x44:
-	case 0x46: /* G72 */
-	case 0x4a:
-	case 0x4c: /* G7x-based C51 */
-	case 0x4e:
-		nv_wr32(priv, 0x400860, 0);
-		nv_wr32(priv, 0x400864, 0);
-		break;
-	case 0x47: /* G70 */
-	case 0x49: /* G71 */
-	case 0x4b: /* G73 */
-		nv_wr32(priv, 0x400828, 0x07830610);
-		nv_wr32(priv, 0x40082c, 0x0000016A);
-		break;
-	default:
-		break;
-	}
-
-	nv_wr32(priv, 0x400b38, 0x2ffff800);
-	nv_wr32(priv, 0x400b3c, 0x00006000);
-
-	/* Tiling related stuff. */
-	switch (nv_device(priv)->chipset) {
-	case 0x44:
-	case 0x4a:
-		nv_wr32(priv, 0x400bc4, 0x1003d888);
-		nv_wr32(priv, 0x400bbc, 0xb7a7b500);
-		break;
-	case 0x46:
-		nv_wr32(priv, 0x400bc4, 0x0000e024);
-		nv_wr32(priv, 0x400bbc, 0xb7a7b520);
-		break;
-	case 0x4c:
-	case 0x4e:
-	case 0x67:
-		nv_wr32(priv, 0x400bc4, 0x1003d888);
-		nv_wr32(priv, 0x400bbc, 0xb7a7b540);
-		break;
-	default:
-		break;
-	}
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < pfb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
-	/* begin RAM config */
-	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
-	switch (nv_device(priv)->chipset) {
-	case 0x40:
-		nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
-		nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
-		nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
-		nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
-		nv_wr32(priv, 0x400820, 0);
-		nv_wr32(priv, 0x400824, 0);
-		nv_wr32(priv, 0x400864, vramsz);
-		nv_wr32(priv, 0x400868, vramsz);
-		break;
-	default:
-		switch (nv_device(priv)->chipset) {
-		case 0x41:
-		case 0x42:
-		case 0x43:
-		case 0x45:
-		case 0x4e:
-		case 0x44:
-		case 0x4a:
-			nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
-			nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
-			break;
-		default:
-			nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
-			nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
-			break;
-		}
-		nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
-		nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
-		nv_wr32(priv, 0x400840, 0);
-		nv_wr32(priv, 0x400844, 0);
-		nv_wr32(priv, 0x4008A0, vramsz);
-		nv_wr32(priv, 0x4008A4, vramsz);
-		break;
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-nv40_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_graph_ctor,
-		.dtor = _nouveau_graph_dtor,
-		.init = nv40_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
deleted file mode 100644
index ad82093..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __NV40_GRAPH_H__
-#define __NV40_GRAPH_H__
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-/* returns 1 if device is one of the nv4x using the 0x4497 object class,
- * helpful to determine a number of other hardware features
- */
-static inline int
-nv44_graph_class(void *priv)
-{
-	struct nouveau_device *device = nv_device(priv);
-
-	if ((device->chipset & 0xf0) == 0x60)
-		return 1;
-
-	return !(0x0baf & (1 << (device->chipset & 0x0f)));
-}
-
-int  nv40_grctx_init(struct nouveau_device *, u32 *size);
-void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
deleted file mode 100644
index 38e0aa2..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "nv50.h"
-
-struct nv50_graph_priv {
-	struct nouveau_graph base;
-	spinlock_t lock;
-	u32 size;
-};
-
-struct nv50_graph_chan {
-	struct nouveau_graph_chan base;
-};
-
-static u64
-nv50_graph_units(struct nouveau_graph *graph)
-{
-	struct nv50_graph_priv *priv = (void *)graph;
-
-	return nv_rd32(priv, 0x1540);
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nv50_graph_object_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    16, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nv50_graph_ofuncs = {
-	.ctor = nv50_graph_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv50_graph_sclass[] = {
-	{ 0x0030, &nv50_graph_ofuncs },
-	{ 0x502d, &nv50_graph_ofuncs },
-	{ 0x5039, &nv50_graph_ofuncs },
-	{ 0x5097, &nv50_graph_ofuncs },
-	{ 0x50c0, &nv50_graph_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nv84_graph_sclass[] = {
-	{ 0x0030, &nv50_graph_ofuncs },
-	{ 0x502d, &nv50_graph_ofuncs },
-	{ 0x5039, &nv50_graph_ofuncs },
-	{ 0x50c0, &nv50_graph_ofuncs },
-	{ 0x8297, &nv50_graph_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nva0_graph_sclass[] = {
-	{ 0x0030, &nv50_graph_ofuncs },
-	{ 0x502d, &nv50_graph_ofuncs },
-	{ 0x5039, &nv50_graph_ofuncs },
-	{ 0x50c0, &nv50_graph_ofuncs },
-	{ 0x8397, &nv50_graph_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nva3_graph_sclass[] = {
-	{ 0x0030, &nv50_graph_ofuncs },
-	{ 0x502d, &nv50_graph_ofuncs },
-	{ 0x5039, &nv50_graph_ofuncs },
-	{ 0x50c0, &nv50_graph_ofuncs },
-	{ 0x8597, &nv50_graph_ofuncs },
-	{ 0x85c0, &nv50_graph_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nvaf_graph_sclass[] = {
-	{ 0x0030, &nv50_graph_ofuncs },
-	{ 0x502d, &nv50_graph_ofuncs },
-	{ 0x5039, &nv50_graph_ofuncs },
-	{ 0x50c0, &nv50_graph_ofuncs },
-	{ 0x85c0, &nv50_graph_ofuncs },
-	{ 0x8697, &nv50_graph_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv50_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *data, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nv50_graph_priv *priv = (void *)engine;
-	struct nv50_graph_chan *chan;
-	int ret;
-
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
-					   priv->size, 0,
-					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
-	return 0;
-}
-
-static struct nouveau_oclass
-nv50_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_graph_context_ctor,
-		.dtor = _nouveau_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_bitfield nv50_pgraph_status[] = {
-	{ 0x00000001, "BUSY" }, /* set when any bit is set */
-	{ 0x00000002, "DISPATCH" },
-	{ 0x00000004, "UNK2" },
-	{ 0x00000008, "UNK3" },
-	{ 0x00000010, "UNK4" },
-	{ 0x00000020, "UNK5" },
-	{ 0x00000040, "M2MF" },
-	{ 0x00000080, "UNK7" },
-	{ 0x00000100, "CTXPROG" },
-	{ 0x00000200, "VFETCH" },
-	{ 0x00000400, "CCACHE_PREGEOM" },
-	{ 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
-	{ 0x00001000, "VCLIP" },
-	{ 0x00002000, "RATTR_APLANE" },
-	{ 0x00004000, "TRAST" },
-	{ 0x00008000, "CLIPID" },
-	{ 0x00010000, "ZCULL" },
-	{ 0x00020000, "ENG2D" },
-	{ 0x00040000, "RMASK" },
-	{ 0x00080000, "TPC_RAST" },
-	{ 0x00100000, "TPC_PROP" },
-	{ 0x00200000, "TPC_TEX" },
-	{ 0x00400000, "TPC_GEOM" },
-	{ 0x00800000, "TPC_MP" },
-	{ 0x01000000, "ROP" },
-	{}
-};
-
-static const char *const nv50_pgraph_vstatus_0[] = {
-	"VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
-	NULL
-};
-
-static const char *const nv50_pgraph_vstatus_1[] = {
-	"TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
-};
-
-static const char *const nv50_pgraph_vstatus_2[] = {
-	"RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
-	"ROP", NULL
-};
-
-static void nouveau_pgraph_vstatus_print(struct nv50_graph_priv *priv, int r,
-		const char *const units[], u32 status)
-{
-	int i;
-
-	nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
-
-	for (i = 0; units[i] && status; i++) {
-		if ((status & 7) == 1)
-			pr_cont(" %s", units[i]);
-		status >>= 3;
-	}
-	if (status)
-		pr_cont(" (invalid: 0x%x)", status);
-	pr_cont("\n");
-}
-
-static int
-nv84_graph_tlb_flush(struct nouveau_engine *engine)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(engine);
-	struct nv50_graph_priv *priv = (void *)engine;
-	bool idle, timeout = false;
-	unsigned long flags;
-	u64 start;
-	u32 tmp;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
-
-	start = ptimer->read(ptimer);
-	do {
-		idle = true;
-
-		for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-
-		for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-
-		for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-	} while (!idle &&
-		 !(timeout = ptimer->read(ptimer) - start > 2000000000));
-
-	if (timeout) {
-		nv_error(priv, "PGRAPH TLB flush idle timeout fail\n");
-
-		tmp = nv_rd32(priv, 0x400700);
-		nv_error(priv, "PGRAPH_STATUS  : 0x%08x", tmp);
-		nouveau_bitfield_print(nv50_pgraph_status, tmp);
-		pr_cont("\n");
-
-		nouveau_pgraph_vstatus_print(priv, 0, nv50_pgraph_vstatus_0,
-				nv_rd32(priv, 0x400380));
-		nouveau_pgraph_vstatus_print(priv, 1, nv50_pgraph_vstatus_1,
-				nv_rd32(priv, 0x400384));
-		nouveau_pgraph_vstatus_print(priv, 2, nv50_pgraph_vstatus_2,
-				nv_rd32(priv, 0x400388));
-	}
-
-
-	nv_wr32(priv, 0x100c80, 0x00000001);
-	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
-		nv_error(priv, "vm flush timeout\n");
-	nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return timeout ? -EBUSY : 0;
-}
-
-static const struct nouveau_bitfield nv50_mp_exec_errors[] = {
-	{ 0x01, "STACK_UNDERFLOW" },
-	{ 0x02, "STACK_MISMATCH" },
-	{ 0x04, "QUADON_ACTIVE" },
-	{ 0x08, "TIMEOUT" },
-	{ 0x10, "INVALID_OPCODE" },
-	{ 0x20, "PM_OVERFLOW" },
-	{ 0x40, "BREAKPOINT" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_mpc_traps[] = {
-	{ 0x0000001, "LOCAL_LIMIT_READ" },
-	{ 0x0000010, "LOCAL_LIMIT_WRITE" },
-	{ 0x0000040, "STACK_LIMIT" },
-	{ 0x0000100, "GLOBAL_LIMIT_READ" },
-	{ 0x0001000, "GLOBAL_LIMIT_WRITE" },
-	{ 0x0010000, "MP0" },
-	{ 0x0020000, "MP1" },
-	{ 0x0040000, "GLOBAL_LIMIT_RED" },
-	{ 0x0400000, "GLOBAL_LIMIT_ATOM" },
-	{ 0x4000000, "MP2" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_tex_traps[] = {
-	{ 0x00000001, "" }, /* any bit set? */
-	{ 0x00000002, "FAULT" },
-	{ 0x00000004, "STORAGE_TYPE_MISMATCH" },
-	{ 0x00000008, "LINEAR_MISMATCH" },
-	{ 0x00000020, "WRONG_MEMTYPE" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_m2mf[] = {
-	{ 0x00000001, "NOTIFY" },
-	{ 0x00000002, "IN" },
-	{ 0x00000004, "OUT" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_vfetch[] = {
-	{ 0x00000001, "FAULT" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_strmout[] = {
-	{ 0x00000001, "FAULT" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_ccache[] = {
-	{ 0x00000001, "FAULT" },
-	{}
-};
-
-/* There must be a *lot* of these. Will take some time to gather them up. */
-const struct nouveau_enum nv50_data_error_names[] = {
-	{ 0x00000003, "INVALID_OPERATION", NULL },
-	{ 0x00000004, "INVALID_VALUE", NULL },
-	{ 0x00000005, "INVALID_ENUM", NULL },
-	{ 0x00000008, "INVALID_OBJECT", NULL },
-	{ 0x00000009, "READ_ONLY_OBJECT", NULL },
-	{ 0x0000000a, "SUPERVISOR_OBJECT", NULL },
-	{ 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
-	{ 0x0000000c, "INVALID_BITFIELD", NULL },
-	{ 0x0000000d, "BEGIN_END_ACTIVE", NULL },
-	{ 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
-	{ 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
-	{ 0x00000010, "RT_DOUBLE_BIND", NULL },
-	{ 0x00000011, "RT_TYPES_MISMATCH", NULL },
-	{ 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
-	{ 0x00000015, "FP_TOO_FEW_REGS", NULL },
-	{ 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
-	{ 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
-	{ 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
-	{ 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
-	{ 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
-	{ 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
-	{ 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
-	{ 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
-	{ 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
-	{ 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
-	{ 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
-	{ 0x00000024, "VP_ZERO_INPUTS", NULL },
-	{ 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
-	{ 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
-	{ 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
-	{ 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
-	{ 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
-	{ 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
-	{ 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
-	{ 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
-	{ 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
-	{ 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
-	{ 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
-	{ 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
-	{ 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
-	{ 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
-	{ 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_intr_name[] = {
-	{ 0x00000001, "NOTIFY" },
-	{ 0x00000002, "COMPUTE_QUERY" },
-	{ 0x00000010, "ILLEGAL_MTHD" },
-	{ 0x00000020, "ILLEGAL_CLASS" },
-	{ 0x00000040, "DOUBLE_NOTIFY" },
-	{ 0x00001000, "CONTEXT_SWITCH" },
-	{ 0x00010000, "BUFFER_NOTIFY" },
-	{ 0x00100000, "DATA_ERROR" },
-	{ 0x00200000, "TRAP" },
-	{ 0x01000000, "SINGLE_STEP" },
-	{}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_prop[] = {
-	{ 0x00000004, "SURF_WIDTH_OVERRUN" },
-	{ 0x00000008, "SURF_HEIGHT_OVERRUN" },
-	{ 0x00000010, "DST2D_FAULT" },
-	{ 0x00000020, "ZETA_FAULT" },
-	{ 0x00000040, "RT_FAULT" },
-	{ 0x00000080, "CUDA_FAULT" },
-	{ 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
-	{ 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
-	{ 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
-	{ 0x00000800, "DST2D_LINEAR_MISMATCH" },
-	{ 0x00001000, "RT_LINEAR_MISMATCH" },
-	{}
-};
-
-static void
-nv50_priv_prop_trap(struct nv50_graph_priv *priv,
-		    u32 ustatus_addr, u32 ustatus, u32 tp)
-{
-	u32 e0c = nv_rd32(priv, ustatus_addr + 0x04);
-	u32 e10 = nv_rd32(priv, ustatus_addr + 0x08);
-	u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c);
-	u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
-	u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
-	u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
-	u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
-
-	/* CUDA memory: l[], g[] or stack. */
-	if (ustatus & 0x00000080) {
-		if (e18 & 0x80000000) {
-			/* g[] read fault? */
-			nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
-					 tp, e14, e10 | ((e18 >> 24) & 0x1f));
-			e18 &= ~0x1f000000;
-		} else if (e18 & 0xc) {
-			/* g[] write fault? */
-			nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
-				 tp, e14, e10 | ((e18 >> 7) & 0x1f));
-			e18 &= ~0x00000f80;
-		} else {
-			nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
-				 tp, e14, e10);
-		}
-		ustatus &= ~0x00000080;
-	}
-	if (ustatus) {
-		nv_error(priv, "TRAP_PROP - TP %d -", tp);
-		nouveau_bitfield_print(nv50_graph_trap_prop, ustatus);
-		pr_cont(" - Address %02x%08x\n", e14, e10);
-	}
-	nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
-		 tp, e0c, e18, e1c, e20, e24);
-}
-
-static void
-nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
-{
-	u32 units = nv_rd32(priv, 0x1540);
-	u32 addr, mp10, status, pc, oplow, ophigh;
-	int i;
-	int mps = 0;
-	for (i = 0; i < 4; i++) {
-		if (!(units & 1 << (i+24)))
-			continue;
-		if (nv_device(priv)->chipset < 0xa0)
-			addr = 0x408200 + (tpid << 12) + (i << 7);
-		else
-			addr = 0x408100 + (tpid << 11) + (i << 7);
-		mp10 = nv_rd32(priv, addr + 0x10);
-		status = nv_rd32(priv, addr + 0x14);
-		if (!status)
-			continue;
-		if (display) {
-			nv_rd32(priv, addr + 0x20);
-			pc = nv_rd32(priv, addr + 0x24);
-			oplow = nv_rd32(priv, addr + 0x70);
-			ophigh = nv_rd32(priv, addr + 0x74);
-			nv_error(priv, "TRAP_MP_EXEC - "
-					"TP %d MP %d:", tpid, i);
-			nouveau_bitfield_print(nv50_mp_exec_errors, status);
-			pr_cont(" at %06x warp %d, opcode %08x %08x\n",
-					pc&0xffffff, pc >> 24,
-					oplow, ophigh);
-		}
-		nv_wr32(priv, addr + 0x10, mp10);
-		nv_wr32(priv, addr + 0x14, 0);
-		mps++;
-	}
-	if (!mps && display)
-		nv_error(priv, "TRAP_MP_EXEC - TP %d: "
-				"No MPs claiming errors?\n", tpid);
-}
-
-static void
-nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
-		u32 ustatus_new, int display, const char *name)
-{
-	int tps = 0;
-	u32 units = nv_rd32(priv, 0x1540);
-	int i, r;
-	u32 ustatus_addr, ustatus;
-	for (i = 0; i < 16; i++) {
-		if (!(units & (1 << i)))
-			continue;
-		if (nv_device(priv)->chipset < 0xa0)
-			ustatus_addr = ustatus_old + (i << 12);
-		else
-			ustatus_addr = ustatus_new + (i << 11);
-		ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
-		if (!ustatus)
-			continue;
-		tps++;
-		switch (type) {
-		case 6: /* texture error... unknown for now */
-			if (display) {
-				nv_error(priv, "magic set %d:\n", i);
-				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
-					nv_error(priv, "\t0x%08x: 0x%08x\n", r,
-						nv_rd32(priv, r));
-				if (ustatus) {
-					nv_error(priv, "%s - TP%d:", name, i);
-					nouveau_bitfield_print(nv50_tex_traps,
-							       ustatus);
-					pr_cont("\n");
-					ustatus = 0;
-				}
-			}
-			break;
-		case 7: /* MP error */
-			if (ustatus & 0x04030000) {
-				nv50_priv_mp_trap(priv, i, display);
-				ustatus &= ~0x04030000;
-			}
-			if (ustatus && display) {
-				nv_error(priv, "%s - TP%d:", name, i);
-				nouveau_bitfield_print(nv50_mpc_traps, ustatus);
-				pr_cont("\n");
-				ustatus = 0;
-			}
-			break;
-		case 8: /* PROP error */
-			if (display)
-				nv50_priv_prop_trap(
-						priv, ustatus_addr, ustatus, i);
-			ustatus = 0;
-			break;
-		}
-		if (ustatus) {
-			if (display)
-				nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
-		}
-		nv_wr32(priv, ustatus_addr, 0xc0000000);
-	}
-
-	if (!tps && display)
-		nv_warn(priv, "%s - No TPs claiming errors?\n", name);
-}
-
-static int
-nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
-			int chid, u64 inst, struct nouveau_object *engctx)
-{
-	u32 status = nv_rd32(priv, 0x400108);
-	u32 ustatus;
-
-	if (!status && display) {
-		nv_error(priv, "TRAP: no units reporting traps?\n");
-		return 1;
-	}
-
-	/* DISPATCH: Relays commands to other units and handles NOTIFY,
-	 * COND, QUERY. If you get a trap from it, the command is still stuck
-	 * in DISPATCH and you need to do something about it. */
-	if (status & 0x001) {
-		ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
-		if (!ustatus && display) {
-			nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
-		}
-
-		nv_wr32(priv, 0x400500, 0x00000000);
-
-		/* Known to be triggered by screwed up NOTIFY and COND... */
-		if (ustatus & 0x00000001) {
-			u32 addr = nv_rd32(priv, 0x400808);
-			u32 subc = (addr & 0x00070000) >> 16;
-			u32 mthd = (addr & 0x00001ffc);
-			u32 datal = nv_rd32(priv, 0x40080c);
-			u32 datah = nv_rd32(priv, 0x400810);
-			u32 class = nv_rd32(priv, 0x400814);
-			u32 r848 = nv_rd32(priv, 0x400848);
-
-			nv_error(priv, "TRAP DISPATCH_FAULT\n");
-			if (display && (addr & 0x80000000)) {
-				nv_error(priv,
-					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
-					 chid, inst,
-					 nouveau_client_name(engctx), subc,
-					 class, mthd, datah, datal, addr, r848);
-			} else
-			if (display) {
-				nv_error(priv, "no stuck command?\n");
-			}
-
-			nv_wr32(priv, 0x400808, 0);
-			nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
-			nv_wr32(priv, 0x400848, 0);
-			ustatus &= ~0x00000001;
-		}
-
-		if (ustatus & 0x00000002) {
-			u32 addr = nv_rd32(priv, 0x40084c);
-			u32 subc = (addr & 0x00070000) >> 16;
-			u32 mthd = (addr & 0x00001ffc);
-			u32 data = nv_rd32(priv, 0x40085c);
-			u32 class = nv_rd32(priv, 0x400814);
-
-			nv_error(priv, "TRAP DISPATCH_QUERY\n");
-			if (display && (addr & 0x80000000)) {
-				nv_error(priv,
-					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
-					 chid, inst,
-					 nouveau_client_name(engctx), subc,
-					 class, mthd, data, addr);
-			} else
-			if (display) {
-				nv_error(priv, "no stuck command?\n");
-			}
-
-			nv_wr32(priv, 0x40084c, 0);
-			ustatus &= ~0x00000002;
-		}
-
-		if (ustatus && display) {
-			nv_error(priv, "TRAP_DISPATCH (unknown "
-				      "0x%08x)\n", ustatus);
-		}
-
-		nv_wr32(priv, 0x400804, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x001);
-		status &= ~0x001;
-		if (!status)
-			return 0;
-	}
-
-	/* M2MF: Memory to memory copy engine. */
-	if (status & 0x002) {
-		u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
-		if (display) {
-			nv_error(priv, "TRAP_M2MF");
-			nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
-			pr_cont("\n");
-			nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
-				nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
-				nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
-
-		}
-
-		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(priv, 0x400040, 2);
-		nv_wr32(priv, 0x400040, 0);
-		nv_wr32(priv, 0x406800, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x002);
-		status &= ~0x002;
-	}
-
-	/* VFETCH: Fetches data from vertex buffers. */
-	if (status & 0x004) {
-		u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
-		if (display) {
-			nv_error(priv, "TRAP_VFETCH");
-			nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
-			pr_cont("\n");
-			nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
-				nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
-				nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
-		}
-
-		nv_wr32(priv, 0x400c04, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x004);
-		status &= ~0x004;
-	}
-
-	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
-	if (status & 0x008) {
-		ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
-		if (display) {
-			nv_error(priv, "TRAP_STRMOUT");
-			nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
-			pr_cont("\n");
-			nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
-				nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
-				nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
-
-		}
-
-		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(priv, 0x400040, 0x80);
-		nv_wr32(priv, 0x400040, 0);
-		nv_wr32(priv, 0x401800, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x008);
-		status &= ~0x008;
-	}
-
-	/* CCACHE: Handles code and c[] caches and fills them. */
-	if (status & 0x010) {
-		ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
-		if (display) {
-			nv_error(priv, "TRAP_CCACHE");
-			nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
-			pr_cont("\n");
-			nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
-				     " %08x %08x %08x\n",
-				nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
-				nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
-				nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
-				nv_rd32(priv, 0x40501c));
-
-		}
-
-		nv_wr32(priv, 0x405018, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x010);
-		status &= ~0x010;
-	}
-
-	/* Unknown, not seen yet... 0x402000 is the only trap status reg
-	 * remaining, so try to handle it anyway. Perhaps related to that
-	 * unknown DMA slot on tesla? */
-	if (status & 0x20) {
-		ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
-		if (display)
-			nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
-		nv_wr32(priv, 0x402000, 0xc0000000);
-		/* no status modifiction on purpose */
-	}
-
-	/* TEXTURE: CUDA texturing units */
-	if (status & 0x040) {
-		nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
-				    "TRAP_TEXTURE");
-		nv_wr32(priv, 0x400108, 0x040);
-		status &= ~0x040;
-	}
-
-	/* MP: CUDA execution engines. */
-	if (status & 0x080) {
-		nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
-				    "TRAP_MP");
-		nv_wr32(priv, 0x400108, 0x080);
-		status &= ~0x080;
-	}
-
-	/* PROP:  Handles TP-initiated uncached memory accesses:
-	 * l[], g[], stack, 2d surfaces, render targets. */
-	if (status & 0x100) {
-		nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
-				    "TRAP_PROP");
-		nv_wr32(priv, 0x400108, 0x100);
-		status &= ~0x100;
-	}
-
-	if (status) {
-		if (display)
-			nv_error(priv, "TRAP: unknown 0x%08x\n", status);
-		nv_wr32(priv, 0x400108, status);
-	}
-
-	return 1;
-}
-
-static void
-nv50_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle = NULL;
-	struct nv50_graph_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, 0x400100);
-	u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff;
-	u32 addr = nv_rd32(priv, 0x400704);
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 mthd = (addr & 0x00001ffc);
-	u32 data = nv_rd32(priv, 0x400708);
-	u32 class = nv_rd32(priv, 0x400814);
-	u32 show = stat, show_bitfield = stat;
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x00000010) {
-		handle = nouveau_handle_get_class(engctx, class);
-		if (handle && !nv_call(handle->object, mthd, data))
-			show &= ~0x00000010;
-		nouveau_handle_put(handle);
-	}
-
-	if (show & 0x00100000) {
-		u32 ecode = nv_rd32(priv, 0x400110);
-		nv_error(priv, "DATA_ERROR ");
-		nouveau_enum_print(nv50_data_error_names, ecode);
-		pr_cont("\n");
-		show_bitfield &= ~0x00100000;
-	}
-
-	if (stat & 0x00200000) {
-		if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12,
-				engctx))
-			show &= ~0x00200000;
-		show_bitfield &= ~0x00200000;
-	}
-
-	nv_wr32(priv, 0x400100, stat);
-	nv_wr32(priv, 0x400500, 0x00010001);
-
-	if (show) {
-		show &= show_bitfield;
-		if (show) {
-			nv_error(priv, "%s", "");
-			nouveau_bitfield_print(nv50_graph_intr_name, show);
-			pr_cont("\n");
-		}
-		nv_error(priv,
-			 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, (u64)inst << 12, nouveau_client_name(engctx),
-			 subc, class, mthd, data);
-	}
-
-	if (nv_rd32(priv, 0x400824) & (1 << 31))
-		nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
-
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_graph_priv *priv;
-	int ret;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00201000;
-	nv_subdev(priv)->intr = nv50_graph_intr;
-	nv_engine(priv)->cclass = &nv50_graph_cclass;
-
-	priv->base.units = nv50_graph_units;
-
-	switch (nv_device(priv)->chipset) {
-	case 0x50:
-		nv_engine(priv)->sclass = nv50_graph_sclass;
-		break;
-	case 0x84:
-	case 0x86:
-	case 0x92:
-	case 0x94:
-	case 0x96:
-	case 0x98:
-		nv_engine(priv)->sclass = nv84_graph_sclass;
-		break;
-	case 0xa0:
-	case 0xaa:
-	case 0xac:
-		nv_engine(priv)->sclass = nva0_graph_sclass;
-		break;
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-		nv_engine(priv)->sclass = nva3_graph_sclass;
-		break;
-	case 0xaf:
-		nv_engine(priv)->sclass = nvaf_graph_sclass;
-		break;
-
-	}
-
-	/* unfortunate hw bug workaround... */
-	if (nv_device(priv)->chipset != 0x50 &&
-	    nv_device(priv)->chipset != 0xac)
-		nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
-
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-static int
-nv50_graph_init(struct nouveau_object *object)
-{
-	struct nv50_graph_priv *priv = (void *)object;
-	int ret, units, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
-	nv_wr32(priv, 0x40008c, 0x00000004);
-
-	/* reset/enable traps and interrupts */
-	nv_wr32(priv, 0x400804, 0xc0000000);
-	nv_wr32(priv, 0x406800, 0xc0000000);
-	nv_wr32(priv, 0x400c04, 0xc0000000);
-	nv_wr32(priv, 0x401800, 0xc0000000);
-	nv_wr32(priv, 0x405018, 0xc0000000);
-	nv_wr32(priv, 0x402000, 0xc0000000);
-
-	units = nv_rd32(priv, 0x001540);
-	for (i = 0; i < 16; i++) {
-		if (!(units & (1 << i)))
-			continue;
-
-		if (nv_device(priv)->chipset < 0xa0) {
-			nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
-			nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
-			nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
-		} else {
-			nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
-			nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
-			nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
-		}
-	}
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-	nv_wr32(priv, 0x400500, 0x00010001);
-
-	/* upload context program, initialise ctxctl defaults */
-	ret = nv50_grctx_init(nv_device(priv), &priv->size);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x400824, 0x00000000);
-	nv_wr32(priv, 0x400828, 0x00000000);
-	nv_wr32(priv, 0x40082c, 0x00000000);
-	nv_wr32(priv, 0x400830, 0x00000000);
-	nv_wr32(priv, 0x40032c, 0x00000000);
-	nv_wr32(priv, 0x400330, 0x00000000);
-
-	/* some unknown zcull magic */
-	switch (nv_device(priv)->chipset & 0xf0) {
-	case 0x50:
-	case 0x80:
-	case 0x90:
-		nv_wr32(priv, 0x402ca8, 0x00000800);
-		break;
-	case 0xa0:
-	default:
-		if (nv_device(priv)->chipset == 0xa0 ||
-		    nv_device(priv)->chipset == 0xaa ||
-		    nv_device(priv)->chipset == 0xac) {
-			nv_wr32(priv, 0x402ca8, 0x00000802);
-		} else {
-			nv_wr32(priv, 0x402cc0, 0x00000000);
-			nv_wr32(priv, 0x402ca8, 0x00000002);
-		}
-
-		break;
-	}
-
-	/* zero out zcull regions */
-	for (i = 0; i < 8; i++) {
-		nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000);
-		nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000);
-		nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000);
-		nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000);
-	}
-	return 0;
-}
-
-struct nouveau_oclass
-nv50_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_graph_ctor,
-		.dtor = _nouveau_graph_dtor,
-		.init = nv50_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
deleted file mode 100644
index 0505fb4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NV50_GRAPH_H__
-#define __NV50_GRAPH_H__
-
-int  nv50_grctx_init(struct nouveau_device *, u32 *size);
-void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
deleted file mode 100644
index 17251e4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ /dev/null
@@ -1,1667 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Zero Bandwidth Clear
- ******************************************************************************/
-
-static void
-nvc0_graph_zbc_clear_color(struct nvc0_graph_priv *priv, int zbc)
-{
-	if (priv->zbc_color[zbc].format) {
-		nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]);
-		nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]);
-		nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]);
-		nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]);
-	}
-	nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format);
-	nv_wr32(priv, 0x405820, zbc);
-	nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */
-}
-
-static int
-nvc0_graph_zbc_color_get(struct nvc0_graph_priv *priv, int format,
-			 const u32 ds[4], const u32 l2[4])
-{
-	struct nouveau_ltc *ltc = nouveau_ltc(priv);
-	int zbc = -ENOSPC, i;
-
-	for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
-		if (priv->zbc_color[i].format) {
-			if (priv->zbc_color[i].format != format)
-				continue;
-			if (memcmp(priv->zbc_color[i].ds, ds, sizeof(
-				   priv->zbc_color[i].ds)))
-				continue;
-			if (memcmp(priv->zbc_color[i].l2, l2, sizeof(
-				   priv->zbc_color[i].l2))) {
-				WARN_ON(1);
-				return -EINVAL;
-			}
-			return i;
-		} else {
-			zbc = (zbc < 0) ? i : zbc;
-		}
-	}
-
-	if (zbc < 0)
-		return zbc;
-
-	memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
-	memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
-	priv->zbc_color[zbc].format = format;
-	ltc->zbc_color_get(ltc, zbc, l2);
-	nvc0_graph_zbc_clear_color(priv, zbc);
-	return zbc;
-}
-
-static void
-nvc0_graph_zbc_clear_depth(struct nvc0_graph_priv *priv, int zbc)
-{
-	if (priv->zbc_depth[zbc].format)
-		nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds);
-	nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format);
-	nv_wr32(priv, 0x405820, zbc);
-	nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */
-}
-
-static int
-nvc0_graph_zbc_depth_get(struct nvc0_graph_priv *priv, int format,
-			 const u32 ds, const u32 l2)
-{
-	struct nouveau_ltc *ltc = nouveau_ltc(priv);
-	int zbc = -ENOSPC, i;
-
-	for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
-		if (priv->zbc_depth[i].format) {
-			if (priv->zbc_depth[i].format != format)
-				continue;
-			if (priv->zbc_depth[i].ds != ds)
-				continue;
-			if (priv->zbc_depth[i].l2 != l2) {
-				WARN_ON(1);
-				return -EINVAL;
-			}
-			return i;
-		} else {
-			zbc = (zbc < 0) ? i : zbc;
-		}
-	}
-
-	if (zbc < 0)
-		return zbc;
-
-	priv->zbc_depth[zbc].format = format;
-	priv->zbc_depth[zbc].ds = ds;
-	priv->zbc_depth[zbc].l2 = l2;
-	ltc->zbc_depth_get(ltc, zbc, l2);
-	nvc0_graph_zbc_clear_depth(priv, zbc);
-	return zbc;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nvc0_fermi_mthd_zbc_color(struct nouveau_object *object, void *data, u32 size)
-{
-	struct nvc0_graph_priv *priv = (void *)object->engine;
-	union {
-		struct fermi_a_zbc_color_v0 v0;
-	} *args = data;
-	int ret;
-
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		switch (args->v0.format) {
-		case FERMI_A_ZBC_COLOR_V0_FMT_ZERO:
-		case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE:
-		case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32:
-		case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16:
-		case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16:
-		case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16:
-		case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16:
-		case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10:
-		case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8:
-		case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10:
-		case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11:
-			ret = nvc0_graph_zbc_color_get(priv, args->v0.format,
-							     args->v0.ds,
-							     args->v0.l2);
-			if (ret >= 0) {
-				args->v0.index = ret;
-				return 0;
-			}
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvc0_fermi_mthd_zbc_depth(struct nouveau_object *object, void *data, u32 size)
-{
-	struct nvc0_graph_priv *priv = (void *)object->engine;
-	union {
-		struct fermi_a_zbc_depth_v0 v0;
-	} *args = data;
-	int ret;
-
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		switch (args->v0.format) {
-		case FERMI_A_ZBC_DEPTH_V0_FMT_FP32:
-			ret = nvc0_graph_zbc_depth_get(priv, args->v0.format,
-							     args->v0.ds,
-							     args->v0.l2);
-			return (ret >= 0) ? 0 : -ENOSPC;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	return ret;
-}
-
-static int
-nvc0_fermi_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
-{
-	switch (mthd) {
-	case FERMI_A_ZBC_COLOR:
-		return nvc0_fermi_mthd_zbc_color(object, data, size);
-	case FERMI_A_ZBC_DEPTH:
-		return nvc0_fermi_mthd_zbc_depth(object, data, size);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-struct nouveau_ofuncs
-nvc0_fermi_ofuncs = {
-	.ctor = _nouveau_object_ctor,
-	.dtor = nouveau_object_destroy,
-	.init = nouveau_object_init,
-	.fini = nouveau_object_fini,
-	.mthd = nvc0_fermi_mthd,
-};
-
-static int
-nvc0_graph_set_shader_exceptions(struct nouveau_object *object, u32 mthd,
-				 void *pdata, u32 size)
-{
-	struct nvc0_graph_priv *priv = (void *)nv_engine(object);
-	if (size >= sizeof(u32)) {
-		u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000;
-		nv_wr32(priv, 0x419e44, data);
-		nv_wr32(priv, 0x419e4c, data);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-struct nouveau_omthds
-nvc0_graph_9097_omthds[] = {
-	{ 0x1528, 0x1528, nvc0_graph_set_shader_exceptions },
-	{}
-};
-
-struct nouveau_omthds
-nvc0_graph_90c0_omthds[] = {
-	{ 0x1528, 0x1528, nvc0_graph_set_shader_exceptions },
-	{}
-};
-
-struct nouveau_oclass
-nvc0_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0x9039, &nouveau_object_ofuncs },
-	{ FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-int
-nvc0_graph_context_ctor(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass, void *args, u32 size,
-			struct nouveau_object **pobject)
-{
-	struct nouveau_vm *vm = nouveau_client(parent)->vm;
-	struct nvc0_graph_priv *priv = (void *)engine;
-	struct nvc0_graph_data *data = priv->mmio_data;
-	struct nvc0_graph_mmio *mmio = priv->mmio_list;
-	struct nvc0_graph_chan *chan;
-	int ret, i;
-
-	/* allocate memory for context, and fill with default values */
-	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
-					   priv->size, 0x100,
-					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	/* allocate memory for a "mmio list" buffer that's used by the HUB
-	 * fuc to modify some per-context register settings on first load
-	 * of the context.
-	 */
-	ret = nouveau_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0,
-				&chan->mmio);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
-				    NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
-				    &chan->mmio_vma);
-	if (ret)
-		return ret;
-
-	/* allocate buffers referenced by mmio list */
-	for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
-		ret = nouveau_gpuobj_new(nv_object(chan), NULL, data->size,
-					 data->align, 0, &chan->data[i].mem);
-		if (ret)
-			return ret;
-
-		ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
-					   &chan->data[i].vma);
-		if (ret)
-			return ret;
-
-		data++;
-	}
-
-	/* finally, fill in the mmio list and point the context at it */
-	for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) {
-		u32 addr = mmio->addr;
-		u32 data = mmio->data;
-
-		if (mmio->buffer >= 0) {
-			u64 info = chan->data[mmio->buffer].vma.offset;
-			data |= info >> mmio->shift;
-		}
-
-		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
-		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
-		mmio++;
-	}
-
-	for (i = 0; i < priv->size; i += 4)
-		nv_wo32(chan, i, priv->data[i / 4]);
-
-	if (!priv->firmware) {
-		nv_wo32(chan, 0x00, chan->mmio_nr / 2);
-		nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
-	} else {
-		nv_wo32(chan, 0xf4, 0);
-		nv_wo32(chan, 0xf8, 0);
-		nv_wo32(chan, 0x10, chan->mmio_nr / 2);
-		nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
-		nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
-		nv_wo32(chan, 0x1c, 1);
-		nv_wo32(chan, 0x20, 0);
-		nv_wo32(chan, 0x28, 0);
-		nv_wo32(chan, 0x2c, 0);
-	}
-
-	return 0;
-}
-
-void
-nvc0_graph_context_dtor(struct nouveau_object *object)
-{
-	struct nvc0_graph_chan *chan = (void *)object;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
-		nouveau_gpuobj_unmap(&chan->data[i].vma);
-		nouveau_gpuobj_ref(NULL, &chan->data[i].mem);
-	}
-
-	nouveau_gpuobj_unmap(&chan->mmio_vma);
-	nouveau_gpuobj_ref(NULL, &chan->mmio);
-
-	nouveau_graph_context_destroy(&chan->base);
-}
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc0_graph_init_main_0[] = {
-	{ 0x400080,   1, 0x04, 0x003083c2 },
-	{ 0x400088,   1, 0x04, 0x00006fe7 },
-	{ 0x40008c,   1, 0x04, 0x00000000 },
-	{ 0x400090,   1, 0x04, 0x00000030 },
-	{ 0x40013c,   1, 0x04, 0x013901f7 },
-	{ 0x400140,   1, 0x04, 0x00000100 },
-	{ 0x400144,   1, 0x04, 0x00000000 },
-	{ 0x400148,   1, 0x04, 0x00000110 },
-	{ 0x400138,   1, 0x04, 0x00000000 },
-	{ 0x400130,   2, 0x04, 0x00000000 },
-	{ 0x400124,   1, 0x04, 0x00000002 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_fe_0[] = {
-	{ 0x40415c,   1, 0x04, 0x00000000 },
-	{ 0x404170,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pri_0[] = {
-	{ 0x404488,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_rstr2d_0[] = {
-	{ 0x407808,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pd_0[] = {
-	{ 0x406024,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_scc_0[] = {
-	{ 0x40803c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_prop_0[] = {
-	{ 0x4184a0,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpc_unk_0[] = {
-	{ 0x418604,   1, 0x04, 0x00000000 },
-	{ 0x418680,   1, 0x04, 0x00000000 },
-	{ 0x418714,   1, 0x04, 0x80000000 },
-	{ 0x418384,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_setup_0[] = {
-	{ 0x418814,   3, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_crstr_0[] = {
-	{ 0x418b04,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_setup_1[] = {
-	{ 0x4188c8,   1, 0x04, 0x80000000 },
-	{ 0x4188cc,   1, 0x04, 0x00000000 },
-	{ 0x4188d0,   1, 0x04, 0x00010000 },
-	{ 0x4188d4,   1, 0x04, 0x00000001 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_zcull_0[] = {
-	{ 0x418910,   1, 0x04, 0x00010001 },
-	{ 0x418914,   1, 0x04, 0x00000301 },
-	{ 0x418918,   1, 0x04, 0x00800000 },
-	{ 0x418980,   1, 0x04, 0x77777770 },
-	{ 0x418984,   3, 0x04, 0x77777777 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpm_0[] = {
-	{ 0x418c04,   1, 0x04, 0x00000000 },
-	{ 0x418c88,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x00000050 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gcc_0[] = {
-	{ 0x41900c,   1, 0x04, 0x00000000 },
-	{ 0x419018,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tpccs_0[] = {
-	{ 0x419d08,   2, 0x04, 0x00000000 },
-	{ 0x419d10,   1, 0x04, 0x00000014 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419abc,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pe_0[] = {
-	{ 0x41980c,   3, 0x04, 0x00000000 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x41984c,   1, 0x04, 0x00005bc5 },
-	{ 0x419850,   4, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419ca8,   1, 0x04, 0x80000000 },
-	{ 0x419cb4,   1, 0x04, 0x00000000 },
-	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
-	{ 0x419cbc,   1, 0x04, 0x28137606 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_wwdx_0[] = {
-	{ 0x419bd4,   1, 0x04, 0x00800000 },
-	{ 0x419bdc,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tpccs_1[] = {
-	{ 0x419d2c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_mpc_0[] = {
-	{ 0x419c0c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc0_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00001100 },
-	{ 0x419eac,   1, 0x04, 0x11100702 },
-	{ 0x419eb0,   1, 0x04, 0x00000003 },
-	{ 0x419eb4,   4, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x06060618 },
-	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
-	{ 0x419ed4,   1, 0x04, 0x011104f1 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419f2c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_be_0[] = {
-	{ 0x40880c,   1, 0x04, 0x00000000 },
-	{ 0x408910,   9, 0x04, 0x00000000 },
-	{ 0x408950,   1, 0x04, 0x00000000 },
-	{ 0x408954,   1, 0x04, 0x0000ffff },
-	{ 0x408984,   1, 0x04, 0x00000000 },
-	{ 0x408988,   1, 0x04, 0x08040201 },
-	{ 0x40898c,   1, 0x04, 0x80402010 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_fe_1[] = {
-	{ 0x4040f0,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pe_1[] = {
-	{ 0x419880,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc0_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvc0_graph_init_pd_0 },
-	{ nvc0_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvc0_graph_init_prop_0 },
-	{ nvc0_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc0_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvc0_graph_init_gpm_0 },
-	{ nvc0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvc0_graph_init_tex_0 },
-	{ nvc0_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvc0_graph_init_wwdx_0 },
-	{ nvc0_graph_init_tpccs_1 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvc0_graph_init_sm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{ nvc0_graph_init_pe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-void
-nvc0_graph_zbc_init(struct nvc0_graph_priv *priv)
-{
-	const u32  zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-			      0x00000000, 0x00000000, 0x00000000, 0x00000000 };
-	const u32   one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
-			      0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
-	const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-			      0x00000000, 0x00000000, 0x00000000, 0x00000000 };
-	const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
-			      0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
-	struct nouveau_ltc *ltc = nouveau_ltc(priv);
-	int index;
-
-	if (!priv->zbc_color[0].format) {
-		nvc0_graph_zbc_color_get(priv, 1,  & zero[0],   &zero[4]);
-		nvc0_graph_zbc_color_get(priv, 2,  &  one[0],    &one[4]);
-		nvc0_graph_zbc_color_get(priv, 4,  &f32_0[0],  &f32_0[4]);
-		nvc0_graph_zbc_color_get(priv, 4,  &f32_1[0],  &f32_1[4]);
-		nvc0_graph_zbc_depth_get(priv, 1, 0x00000000, 0x00000000);
-		nvc0_graph_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000);
-	}
-
-	for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
-		nvc0_graph_zbc_clear_color(priv, index);
-	for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
-		nvc0_graph_zbc_clear_depth(priv, index);
-}
-
-void
-nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
-	const struct nvc0_graph_pack *pack;
-	const struct nvc0_graph_init *init;
-
-	pack_for_each_init(init, pack, p) {
-		u32 next = init->addr + init->count * init->pitch;
-		u32 addr = init->addr;
-		while (addr < next) {
-			nv_wr32(priv, addr, init->data);
-			addr += init->pitch;
-		}
-	}
-}
-
-void
-nvc0_graph_icmd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
-	const struct nvc0_graph_pack *pack;
-	const struct nvc0_graph_init *init;
-	u32 data = 0;
-
-	nv_wr32(priv, 0x400208, 0x80000000);
-
-	pack_for_each_init(init, pack, p) {
-		u32 next = init->addr + init->count * init->pitch;
-		u32 addr = init->addr;
-
-		if ((pack == p && init == p->init) || data != init->data) {
-			nv_wr32(priv, 0x400204, init->data);
-			data = init->data;
-		}
-
-		while (addr < next) {
-			nv_wr32(priv, 0x400200, addr);
-			nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
-			addr += init->pitch;
-		}
-	}
-
-	nv_wr32(priv, 0x400208, 0x00000000);
-}
-
-void
-nvc0_graph_mthd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
-	const struct nvc0_graph_pack *pack;
-	const struct nvc0_graph_init *init;
-	u32 data = 0;
-
-	pack_for_each_init(init, pack, p) {
-		u32 ctrl = 0x80000000 | pack->type;
-		u32 next = init->addr + init->count * init->pitch;
-		u32 addr = init->addr;
-
-		if ((pack == p && init == p->init) || data != init->data) {
-			nv_wr32(priv, 0x40448c, init->data);
-			data = init->data;
-		}
-
-		while (addr < next) {
-			nv_wr32(priv, 0x404488, ctrl | (addr << 14));
-			addr += init->pitch;
-		}
-	}
-}
-
-u64
-nvc0_graph_units(struct nouveau_graph *graph)
-{
-	struct nvc0_graph_priv *priv = (void *)graph;
-	u64 cfg;
-
-	cfg  = (u32)priv->gpc_nr;
-	cfg |= (u32)priv->tpc_total << 8;
-	cfg |= (u64)priv->rop_nr << 32;
-
-	return cfg;
-}
-
-static const struct nouveau_enum nve0_sked_error[] = {
-	{ 7, "CONSTANT_BUFFER_SIZE" },
-	{ 9, "LOCAL_MEMORY_SIZE_POS" },
-	{ 10, "LOCAL_MEMORY_SIZE_NEG" },
-	{ 11, "WARP_CSTACK_SIZE" },
-	{ 12, "TOTAL_TEMP_SIZE" },
-	{ 13, "REGISTER_COUNT" },
-	{ 18, "TOTAL_THREADS" },
-	{ 20, "PROGRAM_OFFSET" },
-	{ 21, "SHARED_MEMORY_SIZE" },
-	{ 25, "SHARED_CONFIG_TOO_SMALL" },
-	{ 26, "TOTAL_REGISTER_COUNT" },
-	{}
-};
-
-static const struct nouveau_enum nvc0_gpc_rop_error[] = {
-	{ 1, "RT_PITCH_OVERRUN" },
-	{ 4, "RT_WIDTH_OVERRUN" },
-	{ 5, "RT_HEIGHT_OVERRUN" },
-	{ 7, "ZETA_STORAGE_TYPE_MISMATCH" },
-	{ 8, "RT_STORAGE_TYPE_MISMATCH" },
-	{ 10, "RT_LINEAR_MISMATCH" },
-	{}
-};
-
-static void
-nvc0_graph_trap_gpc_rop(struct nvc0_graph_priv *priv, int gpc)
-{
-	u32 trap[4];
-	int i;
-
-	trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
-	trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
-	trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
-	trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
-
-	nv_error(priv, "GPC%d/PROP trap:", gpc);
-	for (i = 0; i <= 29; ++i) {
-		if (!(trap[0] & (1 << i)))
-			continue;
-		pr_cont(" ");
-		nouveau_enum_print(nvc0_gpc_rop_error, i);
-	}
-	pr_cont("\n");
-
-	nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
-		 trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
-		 trap[3] & 0xff);
-	nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-}
-
-static const struct nouveau_enum nvc0_mp_warp_error[] = {
-	{ 0x00, "NO_ERROR" },
-	{ 0x01, "STACK_MISMATCH" },
-	{ 0x05, "MISALIGNED_PC" },
-	{ 0x08, "MISALIGNED_GPR" },
-	{ 0x09, "INVALID_OPCODE" },
-	{ 0x0d, "GPR_OUT_OF_BOUNDS" },
-	{ 0x0e, "MEM_OUT_OF_BOUNDS" },
-	{ 0x0f, "UNALIGNED_MEM_ACCESS" },
-	{ 0x11, "INVALID_PARAM" },
-	{}
-};
-
-static const struct nouveau_bitfield nvc0_mp_global_error[] = {
-	{ 0x00000004, "MULTIPLE_WARP_ERRORS" },
-	{ 0x00000008, "OUT_OF_STACK_SPACE" },
-	{}
-};
-
-static void
-nvc0_graph_trap_mp(struct nvc0_graph_priv *priv, int gpc, int tpc)
-{
-	u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
-	u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
-
-	nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
-	nouveau_bitfield_print(nvc0_mp_global_error, gerr);
-	if (werr) {
-		pr_cont(" ");
-		nouveau_enum_print(nvc0_mp_warp_error, werr & 0xffff);
-	}
-	pr_cont("\n");
-
-	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
-	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
-}
-
-static void
-nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc)
-{
-	u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508));
-
-	if (stat & 0x00000001) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
-		nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
-		stat &= ~0x00000001;
-	}
-
-	if (stat & 0x00000002) {
-		nvc0_graph_trap_mp(priv, gpc, tpc);
-		stat &= ~0x00000002;
-	}
-
-	if (stat & 0x00000004) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
-		nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
-		stat &= ~0x00000004;
-	}
-
-	if (stat & 0x00000008) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
-		nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
-		stat &= ~0x00000008;
-	}
-
-	if (stat) {
-		nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
-	}
-}
-
-static void
-nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
-{
-	u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
-	int tpc;
-
-	if (stat & 0x00000001) {
-		nvc0_graph_trap_gpc_rop(priv, gpc);
-		stat &= ~0x00000001;
-	}
-
-	if (stat & 0x00000002) {
-		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
-		nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		stat &= ~0x00000002;
-	}
-
-	if (stat & 0x00000004) {
-		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
-		nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		stat &= ~0x00000004;
-	}
-
-	if (stat & 0x00000008) {
-		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
-		nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		stat &= ~0x00000009;
-	}
-
-	for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-		u32 mask = 0x00010000 << tpc;
-		if (stat & mask) {
-			nvc0_graph_trap_tpc(priv, gpc, tpc);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask);
-			stat &= ~mask;
-		}
-	}
-
-	if (stat) {
-		nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
-	}
-}
-
-static void
-nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
-{
-	u32 trap = nv_rd32(priv, 0x400108);
-	int rop, gpc, i;
-
-	if (trap & 0x00000001) {
-		u32 stat = nv_rd32(priv, 0x404000);
-		nv_error(priv, "DISPATCH 0x%08x\n", stat);
-		nv_wr32(priv, 0x404000, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000001);
-		trap &= ~0x00000001;
-	}
-
-	if (trap & 0x00000002) {
-		u32 stat = nv_rd32(priv, 0x404600);
-		nv_error(priv, "M2MF 0x%08x\n", stat);
-		nv_wr32(priv, 0x404600, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000002);
-		trap &= ~0x00000002;
-	}
-
-	if (trap & 0x00000008) {
-		u32 stat = nv_rd32(priv, 0x408030);
-		nv_error(priv, "CCACHE 0x%08x\n", stat);
-		nv_wr32(priv, 0x408030, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000008);
-		trap &= ~0x00000008;
-	}
-
-	if (trap & 0x00000010) {
-		u32 stat = nv_rd32(priv, 0x405840);
-		nv_error(priv, "SHADER 0x%08x\n", stat);
-		nv_wr32(priv, 0x405840, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000010);
-		trap &= ~0x00000010;
-	}
-
-	if (trap & 0x00000040) {
-		u32 stat = nv_rd32(priv, 0x40601c);
-		nv_error(priv, "UNK6 0x%08x\n", stat);
-		nv_wr32(priv, 0x40601c, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000040);
-		trap &= ~0x00000040;
-	}
-
-	if (trap & 0x00000080) {
-		u32 stat = nv_rd32(priv, 0x404490);
-		nv_error(priv, "MACRO 0x%08x\n", stat);
-		nv_wr32(priv, 0x404490, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000080);
-		trap &= ~0x00000080;
-	}
-
-	if (trap & 0x00000100) {
-		u32 stat = nv_rd32(priv, 0x407020);
-
-		nv_error(priv, "SKED:");
-		for (i = 0; i <= 29; ++i) {
-			if (!(stat & (1 << i)))
-				continue;
-			pr_cont(" ");
-			nouveau_enum_print(nve0_sked_error, i);
-		}
-		pr_cont("\n");
-
-		if (stat & 0x3fffffff)
-			nv_wr32(priv, 0x407020, 0x40000000);
-		nv_wr32(priv, 0x400108, 0x00000100);
-		trap &= ~0x00000100;
-	}
-
-	if (trap & 0x01000000) {
-		u32 stat = nv_rd32(priv, 0x400118);
-		for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
-			u32 mask = 0x00000001 << gpc;
-			if (stat & mask) {
-				nvc0_graph_trap_gpc(priv, gpc);
-				nv_wr32(priv, 0x400118, mask);
-				stat &= ~mask;
-			}
-		}
-		nv_wr32(priv, 0x400108, 0x01000000);
-		trap &= ~0x01000000;
-	}
-
-	if (trap & 0x02000000) {
-		for (rop = 0; rop < priv->rop_nr; rop++) {
-			u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
-			u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
-			nv_error(priv, "ROP%d 0x%08x 0x%08x\n",
-				 rop, statz, statc);
-			nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-			nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		}
-		nv_wr32(priv, 0x400108, 0x02000000);
-		trap &= ~0x02000000;
-	}
-
-	if (trap) {
-		nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap);
-		nv_wr32(priv, 0x400108, trap);
-	}
-}
-
-static void
-nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
-{
-	nv_error(priv, "%06x - done 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x400));
-	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
-		 nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
-	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
-		 nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
-}
-
-void
-nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
-{
-	u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
-	u32 gpc;
-
-	nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
-}
-
-static void
-nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
-{
-	u32 stat = nv_rd32(priv, 0x409c18);
-
-	if (stat & 0x00000001) {
-		u32 code = nv_rd32(priv, 0x409814);
-		if (code == E_BAD_FWMTHD) {
-			u32 class = nv_rd32(priv, 0x409808);
-			u32  addr = nv_rd32(priv, 0x40980c);
-			u32  subc = (addr & 0x00070000) >> 16;
-			u32  mthd = (addr & 0x00003ffc);
-			u32  data = nv_rd32(priv, 0x409810);
-
-			nv_error(priv, "FECS MTHD subc %d class 0x%04x "
-				       "mthd 0x%04x data 0x%08x\n",
-				 subc, class, mthd, data);
-
-			nv_wr32(priv, 0x409c20, 0x00000001);
-			stat &= ~0x00000001;
-		} else {
-			nv_error(priv, "FECS ucode error %d\n", code);
-		}
-	}
-
-	if (stat & 0x00080000) {
-		nv_error(priv, "FECS watchdog timeout\n");
-		nvc0_graph_ctxctl_debug(priv);
-		nv_wr32(priv, 0x409c20, 0x00080000);
-		stat &= ~0x00080000;
-	}
-
-	if (stat) {
-		nv_error(priv, "FECS 0x%08x\n", stat);
-		nvc0_graph_ctxctl_debug(priv);
-		nv_wr32(priv, 0x409c20, stat);
-	}
-}
-
-static void
-nvc0_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle;
-	struct nvc0_graph_priv *priv = (void *)subdev;
-	u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
-	u32 stat = nv_rd32(priv, 0x400100);
-	u32 addr = nv_rd32(priv, 0x400704);
-	u32 mthd = (addr & 0x00003ffc);
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 data = nv_rd32(priv, 0x400708);
-	u32 code = nv_rd32(priv, 0x400110);
-	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x00000010) {
-		handle = nouveau_handle_get_class(engctx, class);
-		if (!handle || nv_call(handle->object, mthd, data)) {
-			nv_error(priv,
-				 "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-				 chid, inst << 12, nouveau_client_name(engctx),
-				 subc, class, mthd, data);
-		}
-		nouveau_handle_put(handle);
-		nv_wr32(priv, 0x400100, 0x00000010);
-		stat &= ~0x00000010;
-	}
-
-	if (stat & 0x00000020) {
-		nv_error(priv,
-			 "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, inst << 12, nouveau_client_name(engctx), subc,
-			 class, mthd, data);
-		nv_wr32(priv, 0x400100, 0x00000020);
-		stat &= ~0x00000020;
-	}
-
-	if (stat & 0x00100000) {
-		nv_error(priv, "DATA_ERROR [");
-		nouveau_enum_print(nv50_data_error_names, code);
-		pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst << 12, nouveau_client_name(engctx), subc,
-			class, mthd, data);
-		nv_wr32(priv, 0x400100, 0x00100000);
-		stat &= ~0x00100000;
-	}
-
-	if (stat & 0x00200000) {
-		nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12,
-			 nouveau_client_name(engctx));
-		nvc0_graph_trap_intr(priv);
-		nv_wr32(priv, 0x400100, 0x00200000);
-		stat &= ~0x00200000;
-	}
-
-	if (stat & 0x00080000) {
-		nvc0_graph_ctxctl_isr(priv);
-		nv_wr32(priv, 0x400100, 0x00080000);
-		stat &= ~0x00080000;
-	}
-
-	if (stat) {
-		nv_error(priv, "unknown stat 0x%08x\n", stat);
-		nv_wr32(priv, 0x400100, stat);
-	}
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-	nouveau_engctx_put(engctx);
-}
-
-void
-nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
-		   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, fuc_base + 0x0188, i >> 6);
-		nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
-	}
-
-	/* code must be padded to 0x40 words */
-	for (; i & 0x3f; i++)
-		nv_wr32(priv, fuc_base + 0x0184, 0);
-}
-
-static void
-nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
-		       const struct nvc0_graph_pack *pack,
-		       u32 falcon, u32 starstar, u32 base)
-{
-	const struct nvc0_graph_pack *iter;
-	const struct nvc0_graph_init *init;
-	u32 addr = ~0, prev = ~0, xfer = 0;
-	u32 star, temp;
-
-	nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
-	star = nv_rd32(priv, falcon + 0x01c4);
-	temp = nv_rd32(priv, falcon + 0x01c4);
-	if (temp > star)
-		star = temp;
-	nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
-
-	pack_for_each_init(init, iter, pack) {
-		u32 head = init->addr - base;
-		u32 tail = head + init->count * init->pitch;
-		while (head < tail) {
-			if (head != prev + 4 || xfer >= 32) {
-				if (xfer) {
-					u32 data = ((--xfer << 26) | addr);
-					nv_wr32(priv, falcon + 0x01c4, data);
-					star += 4;
-				}
-				addr = head;
-				xfer = 0;
-			}
-			prev = head;
-			xfer = xfer + 1;
-			head = head + init->pitch;
-		}
-	}
-
-	nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr);
-	nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
-	nv_wr32(priv, falcon + 0x01c4, star + 4);
-}
-
-int
-nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
-{
-	struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass;
-	struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
-	int i;
-
-	if (priv->firmware) {
-		/* load fuc microcode */
-		nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-		nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c,
-						   &priv->fuc409d);
-		nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac,
-						   &priv->fuc41ad);
-		nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
-		/* start both of them running */
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x41a10c, 0x00000000);
-		nv_wr32(priv, 0x40910c, 0x00000000);
-		nv_wr32(priv, 0x41a100, 0x00000002);
-		nv_wr32(priv, 0x409100, 0x00000002);
-		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
-			nv_warn(priv, "0x409800 wait failed\n");
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x7fffffff);
-		nv_wr32(priv, 0x409504, 0x00000021);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000010);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x10 timeout\n");
-			return -EBUSY;
-		}
-		priv->size = nv_rd32(priv, 0x409800);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000016);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x16 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000025);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x25 timeout\n");
-			return -EBUSY;
-		}
-
-		if (nv_device(priv)->chipset >= 0xe0) {
-			nv_wr32(priv, 0x409800, 0x00000000);
-			nv_wr32(priv, 0x409500, 0x00000001);
-			nv_wr32(priv, 0x409504, 0x00000030);
-			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-				nv_error(priv, "fuc09 req 0x30 timeout\n");
-				return -EBUSY;
-			}
-
-			nv_wr32(priv, 0x409810, 0xb00095c8);
-			nv_wr32(priv, 0x409800, 0x00000000);
-			nv_wr32(priv, 0x409500, 0x00000001);
-			nv_wr32(priv, 0x409504, 0x00000031);
-			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-				nv_error(priv, "fuc09 req 0x31 timeout\n");
-				return -EBUSY;
-			}
-
-			nv_wr32(priv, 0x409810, 0x00080420);
-			nv_wr32(priv, 0x409800, 0x00000000);
-			nv_wr32(priv, 0x409500, 0x00000001);
-			nv_wr32(priv, 0x409504, 0x00000032);
-			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-				nv_error(priv, "fuc09 req 0x32 timeout\n");
-				return -EBUSY;
-			}
-
-			nv_wr32(priv, 0x409614, 0x00000070);
-			nv_wr32(priv, 0x409614, 0x00000770);
-			nv_wr32(priv, 0x40802c, 0x00000001);
-		}
-
-		if (priv->data == NULL) {
-			int ret = nvc0_grctx_generate(priv);
-			if (ret) {
-				nv_error(priv, "failed to construct context\n");
-				return ret;
-			}
-		}
-
-		return 0;
-	} else
-	if (!oclass->fecs.ucode) {
-		return -ENOSYS;
-	}
-
-	/* load HUB microcode */
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-	nv_wr32(priv, 0x4091c0, 0x01000000);
-	for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
-		nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
-
-	nv_wr32(priv, 0x409180, 0x01000000);
-	for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x409188, i >> 6);
-		nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
-	}
-
-	/* load GPC microcode */
-	nv_wr32(priv, 0x41a1c0, 0x01000000);
-	for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
-		nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
-
-	nv_wr32(priv, 0x41a180, 0x01000000);
-	for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x41a188, i >> 6);
-		nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
-	}
-	nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
-	/* load register lists */
-	nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000);
-	nvc0_graph_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000);
-	nvc0_graph_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800);
-	nvc0_graph_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00);
-
-	/* start HUB ucode running, it'll init the GPCs */
-	nv_wr32(priv, 0x40910c, 0x00000000);
-	nv_wr32(priv, 0x409100, 0x00000002);
-	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
-		nv_error(priv, "HUB_INIT timed out\n");
-		nvc0_graph_ctxctl_debug(priv);
-		return -EBUSY;
-	}
-
-	priv->size = nv_rd32(priv, 0x409804);
-	if (priv->data == NULL) {
-		int ret = nvc0_grctx_generate(priv);
-		if (ret) {
-			nv_error(priv, "failed to construct context\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-int
-nvc0_graph_init(struct nouveau_object *object)
-{
-	struct nvc0_graph_oclass *oclass = (void *)object->oclass;
-	struct nvc0_graph_priv *priv = (void *)object;
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8] = {};
-	u8  tpcnr[GPC_MAX];
-	int gpc, tpc, rop;
-	int ret, i;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
-	nvc0_graph_mmio(priv, oclass->mmio);
-
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
-			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
-			priv->tpc_total);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	if (nv_device(priv)->chipset != 0xd7)
-		nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
-	else
-		nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
-
-	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-
-	nv_wr32(priv, 0x409c24, 0x000f0000);
-	nv_wr32(priv, 0x404000, 0xc0000000);
-	nv_wr32(priv, 0x404600, 0xc0000000);
-	nv_wr32(priv, 0x408030, 0xc0000000);
-	nv_wr32(priv, 0x40601c, 0xc0000000);
-	nv_wr32(priv, 0x404490, 0xc0000000);
-	nv_wr32(priv, 0x406018, 0xc0000000);
-	nv_wr32(priv, 0x405840, 0xc0000000);
-	nv_wr32(priv, 0x405844, 0x00ffffff);
-	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400118, 0xffffffff);
-	nv_wr32(priv, 0x400130, 0xffffffff);
-	nv_wr32(priv, 0x40011c, 0xffffffff);
-	nv_wr32(priv, 0x400134, 0xffffffff);
-
-	nv_wr32(priv, 0x400054, 0x34ce3464);
-
-	nvc0_graph_zbc_init(priv);
-
-	return nvc0_graph_init_ctxctl(priv);
-}
-
-static void
-nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
-{
-	kfree(fuc->data);
-	fuc->data = NULL;
-}
-
-int
-nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
-		   struct nvc0_graph_fuc *fuc)
-{
-	struct nouveau_device *device = nv_device(priv);
-	const struct firmware *fw;
-	char f[32];
-	int ret;
-
-	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
-	ret = request_firmware(&fw, f, nv_device_base(device));
-	if (ret) {
-		snprintf(f, sizeof(f), "nouveau/%s", fwname);
-		ret = request_firmware(&fw, f, nv_device_base(device));
-		if (ret) {
-			nv_error(priv, "failed to load %s\n", fwname);
-			return ret;
-		}
-	}
-
-	fuc->size = fw->size;
-	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
-	release_firmware(fw);
-	return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
-
-void
-nvc0_graph_dtor(struct nouveau_object *object)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
-
-	kfree(priv->data);
-
-	nvc0_graph_dtor_fw(&priv->fuc409c);
-	nvc0_graph_dtor_fw(&priv->fuc409d);
-	nvc0_graph_dtor_fw(&priv->fuc41ac);
-	nvc0_graph_dtor_fw(&priv->fuc41ad);
-
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-	nouveau_graph_destroy(&priv->base);
-}
-
-int
-nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *bclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvc0_graph_oclass *oclass = (void *)bclass;
-	struct nouveau_device *device = nv_device(parent);
-	struct nvc0_graph_priv *priv;
-	bool use_ext_fw, enable;
-	int ret, i, j;
-
-	use_ext_fw = nouveau_boolopt(device->cfgopt, "NvGrUseFW",
-				     oclass->fecs.ucode == NULL);
-	enable = use_ext_fw || oclass->fecs.ucode != NULL;
-
-	ret = nouveau_graph_create(parent, engine, bclass, enable, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x08001000;
-	nv_subdev(priv)->intr = nvc0_graph_intr;
-
-	priv->base.units = nvc0_graph_units;
-
-	if (use_ext_fw) {
-		nv_info(priv, "using external firmware\n");
-		if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
-		    nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
-		    nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
-		    nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
-			return -ENODEV;
-		priv->firmware = true;
-	}
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
-				&priv->unk4188b4);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
-				&priv->unk4188b8);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < 0x1000; i += 4) {
-		nv_wo32(priv->unk4188b4, i, 0x00000010);
-		nv_wo32(priv->unk4188b8, i, 0x00000010);
-	}
-
-	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
-	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
-	for (i = 0; i < priv->gpc_nr; i++) {
-		priv->tpc_nr[i]  = nv_rd32(priv, GPC_UNIT(i, 0x2608));
-		priv->tpc_total += priv->tpc_nr[i];
-		priv->ppc_nr[i]  = oclass->ppc_nr;
-		for (j = 0; j < priv->ppc_nr[i]; j++) {
-			u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4)));
-			priv->ppc_tpc_nr[i][j] = hweight8(mask);
-		}
-	}
-
-	/*XXX: these need figuring out... though it might not even matter */
-	switch (nv_device(priv)->chipset) {
-	case 0xc0:
-		if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
-			priv->magic_not_rop_nr = 0x07;
-		} else
-		if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
-			priv->magic_not_rop_nr = 0x05;
-		} else
-		if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
-			priv->magic_not_rop_nr = 0x06;
-		}
-		break;
-	case 0xc3: /* 450, 4/0/0/0, 2 */
-		priv->magic_not_rop_nr = 0x03;
-		break;
-	case 0xc4: /* 460, 3/4/0/0, 4 */
-		priv->magic_not_rop_nr = 0x01;
-		break;
-	case 0xc1: /* 2/0/0/0, 1 */
-		priv->magic_not_rop_nr = 0x01;
-		break;
-	case 0xc8: /* 4/4/3/4, 5 */
-		priv->magic_not_rop_nr = 0x06;
-		break;
-	case 0xce: /* 4/4/0/0, 4 */
-		priv->magic_not_rop_nr = 0x03;
-		break;
-	case 0xcf: /* 4/0/0/0, 3 */
-		priv->magic_not_rop_nr = 0x03;
-		break;
-	case 0xd7:
-	case 0xd9: /* 1/0/0/0, 1 */
-		priv->magic_not_rop_nr = 0x01;
-		break;
-	}
-
-	nv_engine(priv)->cclass = *oclass->cclass;
-	nv_engine(priv)->sclass =  oclass->sclass;
-	return 0;
-}
-
-#include "fuc/hubnvc0.fuc.h"
-
-struct nvc0_graph_ucode
-nvc0_graph_fecs_ucode = {
-	.code.data = nvc0_grhub_code,
-	.code.size = sizeof(nvc0_grhub_code),
-	.data.data = nvc0_grhub_data,
-	.data.size = sizeof(nvc0_grhub_data),
-};
-
-#include "fuc/gpcnvc0.fuc.h"
-
-struct nvc0_graph_ucode
-nvc0_graph_gpccs_ucode = {
-	.code.data = nvc0_grgpc_code,
-	.code.size = sizeof(nvc0_grgpc_code),
-	.data.data = nvc0_grgpc_data,
-	.data.size = sizeof(nvc0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvc0_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvc0_grctx_oclass,
-	.sclass =  nvc0_graph_sclass,
-	.mmio = nvc0_graph_pack_mmio,
-	.fecs.ucode = &nvc0_graph_fecs_ucode,
-	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
deleted file mode 100644
index 7ed9e89..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NVC0_GRAPH_H__
-#define __NVC0_GRAPH_H__
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-#include <subdev/mc.h>
-#include <subdev/ltc.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "fuc/os.h"
-
-#define GPC_MAX 32
-#define TPC_MAX (GPC_MAX * 8)
-
-#define ROP_BCAST(r)      (0x408800 + (r))
-#define ROP_UNIT(u, r)    (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r)      (0x418000 + (r))
-#define GPC_UNIT(t, r)    (0x500000 + (t) * 0x8000 + (r))
-#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
-#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
-
-struct nvc0_graph_data {
-	u32 size;
-	u32 align;
-	u32 access;
-};
-
-struct nvc0_graph_mmio {
-	u32 addr;
-	u32 data;
-	u32 shift;
-	int buffer;
-};
-
-struct nvc0_graph_fuc {
-	u32 *data;
-	u32  size;
-};
-
-struct nvc0_graph_zbc_color {
-	u32 format;
-	u32 ds[4];
-	u32 l2[4];
-};
-
-struct nvc0_graph_zbc_depth {
-	u32 format;
-	u32 ds;
-	u32 l2;
-};
-
-struct nvc0_graph_priv {
-	struct nouveau_graph base;
-
-	struct nvc0_graph_fuc fuc409c;
-	struct nvc0_graph_fuc fuc409d;
-	struct nvc0_graph_fuc fuc41ac;
-	struct nvc0_graph_fuc fuc41ad;
-	bool firmware;
-
-	struct nvc0_graph_zbc_color zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT];
-	struct nvc0_graph_zbc_depth zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT];
-
-	u8 rop_nr;
-	u8 gpc_nr;
-	u8 tpc_nr[GPC_MAX];
-	u8 tpc_total;
-	u8 ppc_nr[GPC_MAX];
-	u8 ppc_tpc_nr[GPC_MAX][4];
-
-	struct nouveau_gpuobj *unk4188b4;
-	struct nouveau_gpuobj *unk4188b8;
-
-	struct nvc0_graph_data mmio_data[4];
-	struct nvc0_graph_mmio mmio_list[4096/8];
-	u32  size;
-	u32 *data;
-
-	u8 magic_not_rop_nr;
-};
-
-struct nvc0_graph_chan {
-	struct nouveau_graph_chan base;
-
-	struct nouveau_gpuobj *mmio;
-	struct nouveau_vma mmio_vma;
-	int mmio_nr;
-	struct {
-		struct nouveau_gpuobj *mem;
-		struct nouveau_vma vma;
-	} data[4];
-};
-
-int  nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
-			     struct nouveau_oclass *, void *, u32,
-			     struct nouveau_object **);
-void nvc0_graph_context_dtor(struct nouveau_object *);
-
-void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
-
-u64  nvc0_graph_units(struct nouveau_graph *);
-int  nvc0_graph_ctor(struct nouveau_object *, struct nouveau_object *,
-		     struct nouveau_oclass *, void *data, u32 size,
-		     struct nouveau_object **);
-void nvc0_graph_dtor(struct nouveau_object *);
-int  nvc0_graph_init(struct nouveau_object *);
-void nvc0_graph_zbc_init(struct nvc0_graph_priv *);
-
-int  nve4_graph_fini(struct nouveau_object *, bool);
-int  nve4_graph_init(struct nouveau_object *);
-
-int  nvf0_graph_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_ofuncs nvc0_fermi_ofuncs;
-
-extern struct nouveau_oclass nvc0_graph_sclass[];
-extern struct nouveau_omthds nvc0_graph_9097_omthds[];
-extern struct nouveau_omthds nvc0_graph_90c0_omthds[];
-extern struct nouveau_oclass nvc8_graph_sclass[];
-extern struct nouveau_oclass nvf0_graph_sclass[];
-
-struct nvc0_graph_init {
-	u32 addr;
-	u8  count;
-	u8  pitch;
-	u32 data;
-};
-
-struct nvc0_graph_pack {
-	const struct nvc0_graph_init *init;
-	u32 type;
-};
-
-#define pack_for_each_init(init, pack, head)                                   \
-	for (pack = head; pack && pack->init; pack++)                          \
-		  for (init = pack->init; init && init->count; init++)
-
-struct nvc0_graph_ucode {
-	struct nvc0_graph_fuc code;
-	struct nvc0_graph_fuc data;
-};
-
-extern struct nvc0_graph_ucode nvc0_graph_fecs_ucode;
-extern struct nvc0_graph_ucode nvc0_graph_gpccs_ucode;
-
-extern struct nvc0_graph_ucode nvf0_graph_fecs_ucode;
-extern struct nvc0_graph_ucode nvf0_graph_gpccs_ucode;
-
-struct nvc0_graph_oclass {
-	struct nouveau_oclass base;
-	struct nouveau_oclass **cclass;
-	struct nouveau_oclass *sclass;
-	const struct nvc0_graph_pack *mmio;
-	struct {
-		struct nvc0_graph_ucode *ucode;
-	} fecs;
-	struct {
-		struct nvc0_graph_ucode *ucode;
-	} gpccs;
-	int ppc_nr;
-};
-
-void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-void nvc0_graph_icmd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-void nvc0_graph_mthd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-int  nvc0_graph_init_ctxctl(struct nvc0_graph_priv *);
-
-/* register init value lists */
-
-extern const struct nvc0_graph_init nvc0_graph_init_main_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_fe_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pri_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_rstr2d_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pd_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_scc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_prop_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_setup_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_crstr_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_setup_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_zcull_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpm_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_gcc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tpccs_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pe_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_l1c_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tpccs_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_mpc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_be_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_fe_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_pe_1[];
-
-extern const struct nvc0_graph_init nvc4_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvc4_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvc4_graph_init_sm_0[];
-
-extern const struct nvc0_graph_init nvc1_graph_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc1_graph_init_setup_1[];
-
-extern const struct nvc0_graph_init nvd9_graph_init_pd_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_prop_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_gpm_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvd9_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_sm_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_fe_1[];
-
-extern const struct nvc0_graph_init nvd7_graph_init_pes_0[];
-extern const struct nvc0_graph_init nvd7_graph_init_wwdx_0[];
-extern const struct nvc0_graph_init nvd7_graph_init_cbm_0[];
-
-extern const struct nvc0_graph_init nve4_graph_init_main_0[];
-extern const struct nvc0_graph_init nve4_graph_init_tpccs_0[];
-extern const struct nvc0_graph_init nve4_graph_init_pe_0[];
-extern const struct nvc0_graph_init nve4_graph_init_be_0[];
-extern const struct nvc0_graph_pack nve4_graph_pack_mmio[];
-
-extern const struct nvc0_graph_init nvf0_graph_init_fe_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_sked_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_cwd_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvf0_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_sm_0[];
-
-extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[];
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
deleted file mode 100644
index 93d58e5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc1_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0x9039, &nouveau_object_ofuncs },
-	{ FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc1_graph_init_gpc_unk_0[] = {
-	{ 0x418604,   1, 0x04, 0x00000000 },
-	{ 0x418680,   1, 0x04, 0x00000000 },
-	{ 0x418714,   1, 0x04, 0x00000000 },
-	{ 0x418384,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc1_graph_init_setup_1[] = {
-	{ 0x4188c8,   2, 0x04, 0x00000000 },
-	{ 0x4188d0,   1, 0x04, 0x00010000 },
-	{ 0x4188d4,   1, 0x04, 0x00000001 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x00000003 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc1_graph_init_pe_0[] = {
-	{ 0x41980c,   1, 0x04, 0x00000010 },
-	{ 0x419810,   1, 0x04, 0x00000000 },
-	{ 0x419814,   1, 0x04, 0x00000004 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x41984c,   1, 0x04, 0x00005bc5 },
-	{ 0x419850,   4, 0x04, 0x00000000 },
-	{ 0x419880,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc1_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvc0_graph_init_pd_0 },
-	{ nvc4_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvc0_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvc0_graph_init_gpm_0 },
-	{ nvc1_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvc4_graph_init_tex_0 },
-	{ nvc1_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvc0_graph_init_wwdx_0 },
-	{ nvc0_graph_init_tpccs_1 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvc4_graph_init_sm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc1),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvc1_grctx_oclass,
-	.sclass = nvc1_graph_sclass,
-	.mmio = nvc1_graph_pack_mmio,
-	.fecs.ucode = &nvc0_graph_fecs_ucode,
-	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c
deleted file mode 100644
index e82e70c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc4_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x00002834 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc4_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ac8,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419abc,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvc4_graph_init_pe_0[] = {
-	{ 0x41980c,   3, 0x04, 0x00000000 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x41984c,   1, 0x04, 0x00005bc5 },
-	{ 0x419850,   4, 0x04, 0x00000000 },
-	{ 0x419880,   1, 0x04, 0x00000002 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvc4_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00001100 },
-	{ 0x419eac,   1, 0x04, 0x11100702 },
-	{ 0x419eb0,   1, 0x04, 0x00000003 },
-	{ 0x419eb4,   4, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x0e063818 },
-	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
-	{ 0x419ed0,   1, 0x04, 0x00003818 },
-	{ 0x419ed4,   1, 0x04, 0x011104f1 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419f2c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc4_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvc0_graph_init_pd_0 },
-	{ nvc4_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvc0_graph_init_prop_0 },
-	{ nvc0_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc0_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvc0_graph_init_gpm_0 },
-	{ nvc0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvc4_graph_init_tex_0 },
-	{ nvc4_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvc0_graph_init_wwdx_0 },
-	{ nvc0_graph_init_tpccs_1 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvc4_graph_init_sm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc4_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvc4_grctx_oclass,
-	.sclass = nvc0_graph_sclass,
-	.mmio = nvc4_graph_pack_mmio,
-	.fecs.ucode = &nvc0_graph_fecs_ucode,
-	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
deleted file mode 100644
index 692e1ed..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nvc8_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0x9039, &nouveau_object_ofuncs },
-	{ FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc8_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00001100 },
-	{ 0x419eac,   1, 0x04, 0x11100f02 },
-	{ 0x419eb0,   1, 0x04, 0x00000003 },
-	{ 0x419eb4,   4, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x06060618 },
-	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
-	{ 0x419ed4,   1, 0x04, 0x011104f1 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419f2c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvc8_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvc0_graph_init_pd_0 },
-	{ nvc0_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvc0_graph_init_prop_0 },
-	{ nvc0_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvc0_graph_init_gpm_0 },
-	{ nvc0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvc0_graph_init_tex_0 },
-	{ nvc0_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvc0_graph_init_wwdx_0 },
-	{ nvc0_graph_init_tpccs_1 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvc8_graph_init_sm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{ nvc0_graph_init_pe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc8),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvc8_grctx_oclass,
-	.sclass = nvc8_graph_sclass,
-	.mmio = nvc8_graph_pack_mmio,
-	.fecs.ucode = &nvc0_graph_fecs_ucode,
-	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
deleted file mode 100644
index 41e8445..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd7_graph_init_pe_0[] = {
-	{ 0x41980c,   1, 0x04, 0x00000010 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x41984c,   1, 0x04, 0x00005bc8 },
-	{ 0x419850,   3, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_pes_0[] = {
-	{ 0x41be04,   1, 0x04, 0x00000000 },
-	{ 0x41be08,   1, 0x04, 0x00000004 },
-	{ 0x41be0c,   1, 0x04, 0x00000000 },
-	{ 0x41be10,   1, 0x04, 0x003b8bc7 },
-	{ 0x41be14,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_wwdx_0[] = {
-	{ 0x41bfd4,   1, 0x04, 0x00800000 },
-	{ 0x41bfdc,   1, 0x04, 0x00000000 },
-	{ 0x41bff8,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_cbm_0[] = {
-	{ 0x41becc,   1, 0x04, 0x00000000 },
-	{ 0x41bee8,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd7_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nvd9_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nvd9_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvd9_graph_init_tex_0 },
-	{ nvd7_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvd9_graph_init_sm_0 },
-	{ nvd7_graph_init_pes_0 },
-	{ nvd7_graph_init_wwdx_0 },
-	{ nvd7_graph_init_cbm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvd9_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-#include "fuc/hubnvd7.fuc.h"
-
-struct nvc0_graph_ucode
-nvd7_graph_fecs_ucode = {
-	.code.data = nvd7_grhub_code,
-	.code.size = sizeof(nvd7_grhub_code),
-	.data.data = nvd7_grhub_data,
-	.data.size = sizeof(nvd7_grhub_data),
-};
-
-#include "fuc/gpcnvd7.fuc.h"
-
-struct nvc0_graph_ucode
-nvd7_graph_gpccs_ucode = {
-	.code.data = nvd7_grgpc_code,
-	.code.size = sizeof(nvd7_grgpc_code),
-	.data.data = nvd7_grgpc_data,
-	.data.size = sizeof(nvd7_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xd7),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvd7_grctx_oclass,
-	.sclass = nvc8_graph_sclass,
-	.mmio = nvd7_graph_pack_mmio,
-	.fecs.ucode = &nvd7_graph_fecs_ucode,
-	.gpccs.ucode = &nvd7_graph_gpccs_ucode,
-	.ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
deleted file mode 100644
index 00fdf20..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvd9_graph_init_pd_0[] = {
-	{ 0x406024,   1, 0x04, 0x00000000 },
-	{ 0x4064f0,   3, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x00002834 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{ 0x405928,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_prop_0[] = {
-	{ 0x418408,   1, 0x04, 0x00000000 },
-	{ 0x4184a0,   3, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_gpm_0[] = {
-	{ 0x418c04,   1, 0x04, 0x00000000 },
-	{ 0x418c64,   2, 0x04, 0x00000000 },
-	{ 0x418c88,   1, 0x04, 0x00000000 },
-	{ 0x418cb4,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418d28,   2, 0x04, 0x00000000 },
-	{ 0x418f00,   1, 0x04, 0x00000000 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418f20,   2, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x00000003 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{ 0x418e1c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ac8,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419abc,   2, 0x04, 0x00000000 },
-	{ 0x419ab4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_pe_0[] = {
-	{ 0x41980c,   1, 0x04, 0x00000010 },
-	{ 0x419810,   1, 0x04, 0x00000000 },
-	{ 0x419814,   1, 0x04, 0x00000004 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x41984c,   1, 0x04, 0x0000a918 },
-	{ 0x419850,   4, 0x04, 0x00000000 },
-	{ 0x419880,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_wwdx_0[] = {
-	{ 0x419bd4,   1, 0x04, 0x00800000 },
-	{ 0x419bdc,   1, 0x04, 0x00000000 },
-	{ 0x419bf8,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_tpccs_1[] = {
-	{ 0x419d2c,   1, 0x04, 0x00000000 },
-	{ 0x419d48,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x02001100 },
-	{ 0x419eac,   1, 0x04, 0x11100702 },
-	{ 0x419eb0,   1, 0x04, 0x00000003 },
-	{ 0x419eb4,   4, 0x04, 0x00000000 },
-	{ 0x419ec8,   1, 0x04, 0x0e063818 },
-	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
-	{ 0x419ed0,   1, 0x04, 0x00003818 },
-	{ 0x419ed4,   1, 0x04, 0x011104f1 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419f2c,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_fe_1[] = {
-	{ 0x40402c,   1, 0x04, 0x00000000 },
-	{ 0x4040f0,   1, 0x04, 0x00000000 },
-	{ 0x404174,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvd9_graph_pack_mmio[] = {
-	{ nvc0_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nvd9_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nvd9_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nvc0_graph_init_tpccs_0 },
-	{ nvd9_graph_init_tex_0 },
-	{ nvd9_graph_init_pe_0 },
-	{ nvc0_graph_init_l1c_0 },
-	{ nvd9_graph_init_wwdx_0 },
-	{ nvd9_graph_init_tpccs_1 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvd9_graph_init_sm_0 },
-	{ nvc0_graph_init_be_0 },
-	{ nvd9_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xd9),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nvc0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nvd9_grctx_oclass,
-	.sclass = nvc8_graph_sclass,
-	.mmio = nvd9_graph_pack_mmio,
-	.fecs.ucode = &nvc0_graph_fecs_ucode,
-	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
deleted file mode 100644
index 0c71f5c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/pwr.h>
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve4_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa040, &nouveau_object_ofuncs },
-	{ KEPLER_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nve4_graph_init_main_0[] = {
-	{ 0x400080,   1, 0x04, 0x003083c2 },
-	{ 0x400088,   1, 0x04, 0x0001ffe7 },
-	{ 0x40008c,   1, 0x04, 0x00000000 },
-	{ 0x400090,   1, 0x04, 0x00000030 },
-	{ 0x40013c,   1, 0x04, 0x003901f7 },
-	{ 0x400140,   1, 0x04, 0x00000100 },
-	{ 0x400144,   1, 0x04, 0x00000000 },
-	{ 0x400148,   1, 0x04, 0x00000110 },
-	{ 0x400138,   1, 0x04, 0x00000000 },
-	{ 0x400130,   2, 0x04, 0x00000000 },
-	{ 0x400124,   1, 0x04, 0x00000002 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x0000ff34 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{ 0x405928,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_sked_0[] = {
-	{ 0x407010,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_cwd_0[] = {
-	{ 0x405b50,   1, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418d28,   2, 0x04, 0x00000000 },
-	{ 0x418f00,   1, 0x04, 0x00000000 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418f20,   2, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x00000060 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{ 0x418e1c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_tpccs_0[] = {
-	{ 0x419d0c,   1, 0x04, 0x00000000 },
-	{ 0x419d10,   1, 0x04, 0x00000014 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_pe_0[] = {
-	{ 0x41980c,   1, 0x04, 0x00000010 },
-	{ 0x419844,   1, 0x04, 0x00000000 },
-	{ 0x419850,   1, 0x04, 0x00000004 },
-	{ 0x419854,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419ca8,   1, 0x04, 0x00000000 },
-	{ 0x419cb0,   1, 0x04, 0x01000000 },
-	{ 0x419cb4,   1, 0x04, 0x00000000 },
-	{ 0x419cb8,   1, 0x04, 0x00b08bea },
-	{ 0x419c84,   1, 0x04, 0x00010384 },
-	{ 0x419cbc,   1, 0x04, 0x28137646 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{ 0x419c80,   1, 0x04, 0x00020232 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000000 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ee4,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00000000 },
-	{ 0x419eb4,   4, 0x04, 0x00000000 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419f74,   1, 0x04, 0x00000555 },
-	{}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_be_0[] = {
-	{ 0x40880c,   1, 0x04, 0x00000000 },
-	{ 0x408850,   1, 0x04, 0x00000004 },
-	{ 0x408910,   9, 0x04, 0x00000000 },
-	{ 0x408950,   1, 0x04, 0x00000000 },
-	{ 0x408954,   1, 0x04, 0x0000ffff },
-	{ 0x408958,   1, 0x04, 0x00000034 },
-	{ 0x408984,   1, 0x04, 0x00000000 },
-	{ 0x408988,   1, 0x04, 0x08040201 },
-	{ 0x40898c,   1, 0x04, 0x80402010 },
-	{}
-};
-
-const struct nvc0_graph_pack
-nve4_graph_pack_mmio[] = {
-	{ nve4_graph_init_main_0 },
-	{ nvc0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nve4_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nve4_graph_init_sked_0 },
-	{ nve4_graph_init_cwd_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nve4_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nve4_graph_init_tpccs_0 },
-	{ nvd9_graph_init_tex_0 },
-	{ nve4_graph_init_pe_0 },
-	{ nve4_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nve4_graph_init_sm_0 },
-	{ nvd7_graph_init_pes_0 },
-	{ nvd7_graph_init_wwdx_0 },
-	{ nvd7_graph_init_cbm_0 },
-	{ nve4_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-int
-nve4_graph_init(struct nouveau_object *object)
-{
-	struct nvc0_graph_oclass *oclass = (void *)object->oclass;
-	struct nvc0_graph_priv *priv = (void *)object;
-	struct nouveau_pwr *ppwr = nouveau_pwr(priv);
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8] = {};
-	u8  tpcnr[GPC_MAX];
-	int gpc, tpc, rop;
-	int ret, i;
-
-	if (ppwr)
-		ppwr->pgob(ppwr, false);
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
-	nvc0_graph_mmio(priv, oclass->mmio);
-
-	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
-			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
-			priv->tpc_total);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
-	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-
-	nv_wr32(priv, 0x409ffc, 0x00000000);
-	nv_wr32(priv, 0x409c14, 0x00003e3e);
-	nv_wr32(priv, 0x409c24, 0x000f0001);
-	nv_wr32(priv, 0x404000, 0xc0000000);
-	nv_wr32(priv, 0x404600, 0xc0000000);
-	nv_wr32(priv, 0x408030, 0xc0000000);
-	nv_wr32(priv, 0x404490, 0xc0000000);
-	nv_wr32(priv, 0x406018, 0xc0000000);
-	nv_wr32(priv, 0x407020, 0x40000000);
-	nv_wr32(priv, 0x405840, 0xc0000000);
-	nv_wr32(priv, 0x405844, 0x00ffffff);
-	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400118, 0xffffffff);
-	nv_wr32(priv, 0x400130, 0xffffffff);
-	nv_wr32(priv, 0x40011c, 0xffffffff);
-	nv_wr32(priv, 0x400134, 0xffffffff);
-
-	nv_wr32(priv, 0x400054, 0x34ce3464);
-
-	nvc0_graph_zbc_init(priv);
-
-	return nvc0_graph_init_ctxctl(priv);
-}
-
-#include "fuc/hubnve0.fuc.h"
-
-static struct nvc0_graph_ucode
-nve4_graph_fecs_ucode = {
-	.code.data = nve0_grhub_code,
-	.code.size = sizeof(nve0_grhub_code),
-	.data.data = nve0_grhub_data,
-	.data.size = sizeof(nve0_grhub_data),
-};
-
-#include "fuc/gpcnve0.fuc.h"
-
-static struct nvc0_graph_ucode
-nve4_graph_gpccs_ucode = {
-	.code.data = nve0_grgpc_code,
-	.code.size = sizeof(nve0_grgpc_code),
-	.data.data = nve0_grgpc_data,
-	.data.size = sizeof(nve0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nve4_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xe4),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve4_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-	.cclass = &nve4_grctx_oclass,
-	.sclass = nve4_graph_sclass,
-	.mmio = nve4_graph_pack_mmio,
-	.fecs.ucode = &nve4_graph_fecs_ucode,
-	.gpccs.ucode = &nve4_graph_gpccs_ucode,
-	.ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
deleted file mode 100644
index c306c0f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nvf0_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa140, &nouveau_object_ofuncs },
-	{ KEPLER_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
-	{ KEPLER_COMPUTE_B, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvf0_graph_init_fe_0[] = {
-	{ 0x40415c,   1, 0x04, 0x00000000 },
-	{ 0x404170,   1, 0x04, 0x00000000 },
-	{ 0x4041b4,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_ds_0[] = {
-	{ 0x405844,   1, 0x04, 0x00ffffff },
-	{ 0x405850,   1, 0x04, 0x00000000 },
-	{ 0x405900,   1, 0x04, 0x0000ff00 },
-	{ 0x405908,   1, 0x04, 0x00000000 },
-	{ 0x405928,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_sked_0[] = {
-	{ 0x407010,   1, 0x04, 0x00000000 },
-	{ 0x407040,   1, 0x04, 0x80440424 },
-	{ 0x407048,   1, 0x04, 0x0000000a },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_cwd_0[] = {
-	{ 0x405b44,   1, 0x04, 0x00000000 },
-	{ 0x405b50,   1, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_gpc_unk_1[] = {
-	{ 0x418d00,   1, 0x04, 0x00000000 },
-	{ 0x418d28,   2, 0x04, 0x00000000 },
-	{ 0x418f00,   1, 0x04, 0x00000400 },
-	{ 0x418f08,   1, 0x04, 0x00000000 },
-	{ 0x418f20,   2, 0x04, 0x00000000 },
-	{ 0x418e00,   1, 0x04, 0x00000000 },
-	{ 0x418e08,   1, 0x04, 0x00000000 },
-	{ 0x418e1c,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_tex_0[] = {
-	{ 0x419ab0,   1, 0x04, 0x00000000 },
-	{ 0x419ac8,   1, 0x04, 0x00000000 },
-	{ 0x419ab8,   1, 0x04, 0x000000e7 },
-	{ 0x419aec,   1, 0x04, 0x00000000 },
-	{ 0x419abc,   2, 0x04, 0x00000000 },
-	{ 0x419ab4,   1, 0x04, 0x00000000 },
-	{ 0x419aa8,   2, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_init
-nvf0_graph_init_l1c_0[] = {
-	{ 0x419c98,   1, 0x04, 0x00000000 },
-	{ 0x419ca8,   1, 0x04, 0x00000000 },
-	{ 0x419cb0,   1, 0x04, 0x01000000 },
-	{ 0x419cb4,   1, 0x04, 0x00000000 },
-	{ 0x419cb8,   1, 0x04, 0x00b08bea },
-	{ 0x419c84,   1, 0x04, 0x00010384 },
-	{ 0x419cbc,   1, 0x04, 0x281b3646 },
-	{ 0x419cc0,   2, 0x04, 0x00000000 },
-	{ 0x419c80,   1, 0x04, 0x00020230 },
-	{ 0x419ccc,   2, 0x04, 0x00000000 },
-	{}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_sm_0[] = {
-	{ 0x419e00,   1, 0x04, 0x00000080 },
-	{ 0x419ea0,   1, 0x04, 0x00000000 },
-	{ 0x419ee4,   1, 0x04, 0x00000000 },
-	{ 0x419ea4,   1, 0x04, 0x00000100 },
-	{ 0x419ea8,   1, 0x04, 0x00000000 },
-	{ 0x419eb4,   1, 0x04, 0x00000000 },
-	{ 0x419ebc,   2, 0x04, 0x00000000 },
-	{ 0x419edc,   1, 0x04, 0x00000000 },
-	{ 0x419f00,   1, 0x04, 0x00000000 },
-	{ 0x419ed0,   1, 0x04, 0x00003234 },
-	{ 0x419f74,   1, 0x04, 0x00015555 },
-	{ 0x419f80,   4, 0x04, 0x00000000 },
-	{}
-};
-
-static const struct nvc0_graph_pack
-nvf0_graph_pack_mmio[] = {
-	{ nve4_graph_init_main_0 },
-	{ nvf0_graph_init_fe_0 },
-	{ nvc0_graph_init_pri_0 },
-	{ nvc0_graph_init_rstr2d_0 },
-	{ nvd9_graph_init_pd_0 },
-	{ nvf0_graph_init_ds_0 },
-	{ nvc0_graph_init_scc_0 },
-	{ nvf0_graph_init_sked_0 },
-	{ nvf0_graph_init_cwd_0 },
-	{ nvd9_graph_init_prop_0 },
-	{ nvc1_graph_init_gpc_unk_0 },
-	{ nvc0_graph_init_setup_0 },
-	{ nvc0_graph_init_crstr_0 },
-	{ nvc1_graph_init_setup_1 },
-	{ nvc0_graph_init_zcull_0 },
-	{ nvd9_graph_init_gpm_0 },
-	{ nvf0_graph_init_gpc_unk_1 },
-	{ nvc0_graph_init_gcc_0 },
-	{ nve4_graph_init_tpccs_0 },
-	{ nvf0_graph_init_tex_0 },
-	{ nve4_graph_init_pe_0 },
-	{ nvf0_graph_init_l1c_0 },
-	{ nvc0_graph_init_mpc_0 },
-	{ nvf0_graph_init_sm_0 },
-	{ nvd7_graph_init_pes_0 },
-	{ nvd7_graph_init_wwdx_0 },
-	{ nvd7_graph_init_cbm_0 },
-	{ nve4_graph_init_be_0 },
-	{ nvc0_graph_init_fe_1 },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-int
-nvf0_graph_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
-	static const struct {
-		u32 addr;
-		u32 data;
-	} magic[] = {
-		{ 0x020520, 0xfffffffc },
-		{ 0x020524, 0xfffffffe },
-		{ 0x020524, 0xfffffffc },
-		{ 0x020524, 0xfffffff8 },
-		{ 0x020524, 0xffffffe0 },
-		{ 0x020530, 0xfffffffe },
-		{ 0x02052c, 0xfffffffa },
-		{ 0x02052c, 0xfffffff0 },
-		{ 0x02052c, 0xffffffc0 },
-		{ 0x02052c, 0xffffff00 },
-		{ 0x02052c, 0xfffffc00 },
-		{ 0x02052c, 0xfffcfc00 },
-		{ 0x02052c, 0xfff0fc00 },
-		{ 0x02052c, 0xff80fc00 },
-		{ 0x020528, 0xfffffffe },
-		{ 0x020528, 0xfffffffc },
-	};
-	int i;
-
-	nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
-	nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
-	for (i = 0; i < ARRAY_SIZE(magic); i++) {
-		nv_wr32(priv, magic[i].addr, magic[i].data);
-		nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
-	}
-
-	return nouveau_graph_fini(&priv->base, suspend);
-}
-
-#include "fuc/hubnvf0.fuc.h"
-
-struct nvc0_graph_ucode
-nvf0_graph_fecs_ucode = {
-	.code.data = nvf0_grhub_code,
-	.code.size = sizeof(nvf0_grhub_code),
-	.data.data = nvf0_grhub_data,
-	.data.size = sizeof(nvf0_grhub_data),
-};
-
-#include "fuc/gpcnvf0.fuc.h"
-
-struct nvc0_graph_ucode
-nvf0_graph_gpccs_ucode = {
-	.code.data = nvf0_grgpc_code,
-	.code.size = sizeof(nvf0_grgpc_code),
-	.data.data = nvf0_grgpc_data,
-	.data.size = sizeof(nvf0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xf0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve4_graph_init,
-		.fini = nvf0_graph_fini,
-	},
-	.cclass = &nvf0_grctx_oclass,
-	.sclass =  nvf0_graph_sclass,
-	.mmio = nvf0_graph_pack_mmio,
-	.fecs.ucode = &nvf0_graph_fecs_ucode,
-	.gpccs.ucode = &nvf0_graph_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
deleted file mode 100644
index fde8e24..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef __NOUVEAU_GRAPH_REGS_H__
-#define __NOUVEAU_GRAPH_REGS_H__
-
-#define NV04_PGRAPH_DEBUG_0                                0x00400080
-#define NV04_PGRAPH_DEBUG_1                                0x00400084
-#define NV04_PGRAPH_DEBUG_2                                0x00400088
-#define NV04_PGRAPH_DEBUG_3                                0x0040008c
-#define NV10_PGRAPH_DEBUG_4                                0x00400090
-#define NV03_PGRAPH_INTR                                   0x00400100
-#define NV03_PGRAPH_NSTATUS                                0x00400104
-#    define NV04_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<11)
-#    define NV04_PGRAPH_NSTATUS_INVALID_STATE                 (1<<12)
-#    define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<13)
-#    define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<14)
-#    define NV10_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<23)
-#    define NV10_PGRAPH_NSTATUS_INVALID_STATE                 (1<<24)
-#    define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<25)
-#    define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<26)
-#define NV03_PGRAPH_NSOURCE                                0x00400108
-#    define NV03_PGRAPH_NSOURCE_NOTIFICATION                   (1<<0)
-#    define NV03_PGRAPH_NSOURCE_DATA_ERROR                     (1<<1)
-#    define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR               (1<<2)
-#    define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION                (1<<3)
-#    define NV03_PGRAPH_NSOURCE_LIMIT_COLOR                    (1<<4)
-#    define NV03_PGRAPH_NSOURCE_LIMIT_ZETA                     (1<<5)
-#    define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD                   (1<<6)
-#    define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION               (1<<7)
-#    define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION               (1<<8)
-#    define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION               (1<<9)
-#    define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION               (1<<10)
-#    define NV03_PGRAPH_NSOURCE_STATE_INVALID                 (1<<11)
-#    define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY                 (1<<12)
-#    define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE                 (1<<13)
-#    define NV03_PGRAPH_NSOURCE_METHOD_CNT                    (1<<14)
-#    define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION              (1<<15)
-#    define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION            (1<<16)
-#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A                   (1<<17)
-#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B                   (1<<18)
-#define NV03_PGRAPH_INTR_EN                                0x00400140
-#define NV40_PGRAPH_INTR_EN                                0x0040013C
-#    define NV_PGRAPH_INTR_NOTIFY                              (1<<0)
-#    define NV_PGRAPH_INTR_MISSING_HW                          (1<<4)
-#    define NV_PGRAPH_INTR_CONTEXT_SWITCH                     (1<<12)
-#    define NV_PGRAPH_INTR_BUFFER_NOTIFY                      (1<<16)
-#    define NV_PGRAPH_INTR_ERROR                              (1<<20)
-#define NV10_PGRAPH_CTX_CONTROL                            0x00400144
-#define NV10_PGRAPH_CTX_USER                               0x00400148
-#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
-#define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
-#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160	\
-							   + 0x4*(i) + 0x20*(j))
-#define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
-#define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
-#define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
-#define NV04_PGRAPH_CTX_CONTROL                            0x00400170
-#define NV04_PGRAPH_CTX_USER                               0x00400174
-#define NV04_PGRAPH_CTX_CACHE1                             0x00400180
-#define NV03_PGRAPH_CTX_CONTROL                            0x00400190
-#define NV03_PGRAPH_CTX_USER                               0x00400194
-#define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
-#define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
-#define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
-#define NV40_PGRAPH_CTXCTL_0304                            0x00400304
-#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK              0xff000000
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT                     24
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK              0x00ffffff
-#define NV40_PGRAPH_CTXCTL_0310                            0x00400310
-#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE                  0x00000020
-#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD                  0x00000040
-#define NV40_PGRAPH_CTXCTL_030C                            0x0040030c
-#define NV40_PGRAPH_CTXCTL_UCODE_INDEX                     0x00400324
-#define NV40_PGRAPH_CTXCTL_UCODE_DATA                      0x00400328
-#define NV40_PGRAPH_CTXCTL_CUR                             0x0040032c
-#define NV40_PGRAPH_CTXCTL_CUR_LOADED                      0x01000000
-#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE                    0x000FFFFF
-#define NV40_PGRAPH_CTXCTL_NEXT                            0x00400330
-#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x000fffff
-#define NV50_PGRAPH_CTXCTL_CUR                             0x0040032c
-#define NV50_PGRAPH_CTXCTL_CUR_LOADED                      0x80000000
-#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE                    0x00ffffff
-#define NV50_PGRAPH_CTXCTL_NEXT                            0x00400330
-#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x00ffffff
-#define NV03_PGRAPH_ABS_X_RAM                              0x00400400
-#define NV03_PGRAPH_ABS_Y_RAM                              0x00400480
-#define NV03_PGRAPH_X_MISC                                 0x00400500
-#define NV03_PGRAPH_Y_MISC                                 0x00400504
-#define NV04_PGRAPH_VALID1                                 0x00400508
-#define NV04_PGRAPH_SOURCE_COLOR                           0x0040050C
-#define NV04_PGRAPH_MISC24_0                               0x00400510
-#define NV03_PGRAPH_XY_LOGIC_MISC0                         0x00400514
-#define NV03_PGRAPH_XY_LOGIC_MISC1                         0x00400518
-#define NV03_PGRAPH_XY_LOGIC_MISC2                         0x0040051C
-#define NV03_PGRAPH_XY_LOGIC_MISC3                         0x00400520
-#define NV03_PGRAPH_CLIPX_0                                0x00400524
-#define NV03_PGRAPH_CLIPX_1                                0x00400528
-#define NV03_PGRAPH_CLIPY_0                                0x0040052C
-#define NV03_PGRAPH_CLIPY_1                                0x00400530
-#define NV03_PGRAPH_ABS_ICLIP_XMAX                         0x00400534
-#define NV03_PGRAPH_ABS_ICLIP_YMAX                         0x00400538
-#define NV03_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C
-#define NV03_PGRAPH_ABS_UCLIP_YMIN                         0x00400540
-#define NV03_PGRAPH_ABS_UCLIP_XMAX                         0x00400544
-#define NV03_PGRAPH_ABS_UCLIP_YMAX                         0x00400548
-#define NV03_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560
-#define NV03_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564
-#define NV03_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568
-#define NV03_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C
-#define NV04_PGRAPH_MISC24_1                               0x00400570
-#define NV04_PGRAPH_MISC24_2                               0x00400574
-#define NV04_PGRAPH_VALID2                                 0x00400578
-#define NV04_PGRAPH_PASSTHRU_0                             0x0040057C
-#define NV04_PGRAPH_PASSTHRU_1                             0x00400580
-#define NV04_PGRAPH_PASSTHRU_2                             0x00400584
-#define NV10_PGRAPH_DIMX_TEXTURE                           0x00400588
-#define NV10_PGRAPH_WDIMX_TEXTURE                          0x0040058C
-#define NV04_PGRAPH_COMBINE_0_ALPHA                        0x00400590
-#define NV04_PGRAPH_COMBINE_0_COLOR                        0x00400594
-#define NV04_PGRAPH_COMBINE_1_ALPHA                        0x00400598
-#define NV04_PGRAPH_COMBINE_1_COLOR                        0x0040059C
-#define NV04_PGRAPH_FORMAT_0                               0x004005A8
-#define NV04_PGRAPH_FORMAT_1                               0x004005AC
-#define NV04_PGRAPH_FILTER_0                               0x004005B0
-#define NV04_PGRAPH_FILTER_1                               0x004005B4
-#define NV03_PGRAPH_MONO_COLOR0                            0x00400600
-#define NV04_PGRAPH_ROP3                                   0x00400604
-#define NV04_PGRAPH_BETA_AND                               0x00400608
-#define NV04_PGRAPH_BETA_PREMULT                           0x0040060C
-#define NV04_PGRAPH_LIMIT_VIOL_PIX                         0x00400610
-#define NV04_PGRAPH_FORMATS                                0x00400618
-#define NV10_PGRAPH_DEBUG_2                                0x00400620
-#define NV04_PGRAPH_BOFFSET0                               0x00400640
-#define NV04_PGRAPH_BOFFSET1                               0x00400644
-#define NV04_PGRAPH_BOFFSET2                               0x00400648
-#define NV04_PGRAPH_BOFFSET3                               0x0040064C
-#define NV04_PGRAPH_BOFFSET4                               0x00400650
-#define NV04_PGRAPH_BOFFSET5                               0x00400654
-#define NV04_PGRAPH_BBASE0                                 0x00400658
-#define NV04_PGRAPH_BBASE1                                 0x0040065C
-#define NV04_PGRAPH_BBASE2                                 0x00400660
-#define NV04_PGRAPH_BBASE3                                 0x00400664
-#define NV04_PGRAPH_BBASE4                                 0x00400668
-#define NV04_PGRAPH_BBASE5                                 0x0040066C
-#define NV04_PGRAPH_BPITCH0                                0x00400670
-#define NV04_PGRAPH_BPITCH1                                0x00400674
-#define NV04_PGRAPH_BPITCH2                                0x00400678
-#define NV04_PGRAPH_BPITCH3                                0x0040067C
-#define NV04_PGRAPH_BPITCH4                                0x00400680
-#define NV04_PGRAPH_BLIMIT0                                0x00400684
-#define NV04_PGRAPH_BLIMIT1                                0x00400688
-#define NV04_PGRAPH_BLIMIT2                                0x0040068C
-#define NV04_PGRAPH_BLIMIT3                                0x00400690
-#define NV04_PGRAPH_BLIMIT4                                0x00400694
-#define NV04_PGRAPH_BLIMIT5                                0x00400698
-#define NV04_PGRAPH_BSWIZZLE2                              0x0040069C
-#define NV04_PGRAPH_BSWIZZLE5                              0x004006A0
-#define NV03_PGRAPH_STATUS                                 0x004006B0
-#define NV04_PGRAPH_STATUS                                 0x00400700
-#    define NV40_PGRAPH_STATUS_SYNC_STALL                  0x00004000
-#define NV04_PGRAPH_TRAPPED_ADDR                           0x00400704
-#define NV04_PGRAPH_TRAPPED_DATA                           0x00400708
-#define NV04_PGRAPH_SURFACE                                0x0040070C
-#define NV10_PGRAPH_TRAPPED_DATA_HIGH                      0x0040070C
-#define NV04_PGRAPH_STATE                                  0x00400710
-#define NV10_PGRAPH_SURFACE                                0x00400710
-#define NV04_PGRAPH_NOTIFY                                 0x00400714
-#define NV10_PGRAPH_STATE                                  0x00400714
-#define NV10_PGRAPH_NOTIFY                                 0x00400718
-
-#define NV04_PGRAPH_FIFO                                   0x00400720
-
-#define NV04_PGRAPH_BPIXEL                                 0x00400724
-#define NV10_PGRAPH_RDI_INDEX                              0x00400750
-#define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
-#define NV10_PGRAPH_RDI_DATA                               0x00400754
-#define NV04_PGRAPH_DMA_PITCH                              0x00400760
-#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
-#define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
-#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
-#define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
-#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
-#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
-#define NV10_PGRAPH_DMA_PITCH                              0x00400770
-#define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
-#define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
-#define NV20_PGRAPH_CHANNEL_CTX_TABLE                      0x00400780
-#define NV20_PGRAPH_CHANNEL_CTX_POINTER                    0x00400784
-#define NV20_PGRAPH_CHANNEL_CTX_XFER                       0x00400788
-#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD                  0x00000001
-#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE                  0x00000002
-#define NV04_PGRAPH_PATT_COLOR0                            0x00400800
-#define NV04_PGRAPH_PATT_COLOR1                            0x00400804
-#define NV04_PGRAPH_PATTERN                                0x00400808
-#define NV04_PGRAPH_PATTERN_SHAPE                          0x00400810
-#define NV04_PGRAPH_CHROMA                                 0x00400814
-#define NV04_PGRAPH_CONTROL0                               0x00400818
-#define NV04_PGRAPH_CONTROL1                               0x0040081C
-#define NV04_PGRAPH_CONTROL2                               0x00400820
-#define NV04_PGRAPH_BLEND                                  0x00400824
-#define NV04_PGRAPH_STORED_FMT                             0x00400830
-#define NV04_PGRAPH_PATT_COLORRAM                          0x00400900
-#define NV20_PGRAPH_TILE(i)                                (0x00400900 + (i*16))
-#define NV20_PGRAPH_TLIMIT(i)                              (0x00400904 + (i*16))
-#define NV20_PGRAPH_TSIZE(i)                               (0x00400908 + (i*16))
-#define NV20_PGRAPH_TSTATUS(i)                             (0x0040090C + (i*16))
-#define NV20_PGRAPH_ZCOMP(i)                               (0x00400980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP0(i)                              (0x004009c0 + 4*(i))
-#define NV10_PGRAPH_TILE(i)                                (0x00400B00 + (i*16))
-#define NV10_PGRAPH_TLIMIT(i)                              (0x00400B04 + (i*16))
-#define NV10_PGRAPH_TSIZE(i)                               (0x00400B08 + (i*16))
-#define NV10_PGRAPH_TSTATUS(i)                             (0x00400B0C + (i*16))
-#define NV04_PGRAPH_U_RAM                                  0x00400D00
-#define NV47_PGRAPH_TILE(i)                                (0x00400D00 + (i*16))
-#define NV47_PGRAPH_TLIMIT(i)                              (0x00400D04 + (i*16))
-#define NV47_PGRAPH_TSIZE(i)                               (0x00400D08 + (i*16))
-#define NV47_PGRAPH_TSTATUS(i)                             (0x00400D0C + (i*16))
-#define NV04_PGRAPH_V_RAM                                  0x00400D40
-#define NV04_PGRAPH_W_RAM                                  0x00400D80
-#define NV47_PGRAPH_ZCOMP0(i)                              (0x00400e00 + 4*(i))
-#define NV10_PGRAPH_COMBINER0_IN_ALPHA                     0x00400E40
-#define NV10_PGRAPH_COMBINER1_IN_ALPHA                     0x00400E44
-#define NV10_PGRAPH_COMBINER0_IN_RGB                       0x00400E48
-#define NV10_PGRAPH_COMBINER1_IN_RGB                       0x00400E4C
-#define NV10_PGRAPH_COMBINER_COLOR0                        0x00400E50
-#define NV10_PGRAPH_COMBINER_COLOR1                        0x00400E54
-#define NV10_PGRAPH_COMBINER0_OUT_ALPHA                    0x00400E58
-#define NV10_PGRAPH_COMBINER1_OUT_ALPHA                    0x00400E5C
-#define NV10_PGRAPH_COMBINER0_OUT_RGB                      0x00400E60
-#define NV10_PGRAPH_COMBINER1_OUT_RGB                      0x00400E64
-#define NV10_PGRAPH_COMBINER_FINAL0                        0x00400E68
-#define NV10_PGRAPH_COMBINER_FINAL1                        0x00400E6C
-#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL                  0x00400F00
-#define NV10_PGRAPH_WINDOWCLIP_VERTICAL                    0x00400F20
-#define NV10_PGRAPH_XFMODE0                                0x00400F40
-#define NV10_PGRAPH_XFMODE1                                0x00400F44
-#define NV10_PGRAPH_GLOBALSTATE0                           0x00400F48
-#define NV10_PGRAPH_GLOBALSTATE1                           0x00400F4C
-#define NV10_PGRAPH_PIPE_ADDRESS                           0x00400F50
-#define NV10_PGRAPH_PIPE_DATA                              0x00400F54
-#define NV04_PGRAPH_DMA_START_0                            0x00401000
-#define NV04_PGRAPH_DMA_START_1                            0x00401004
-#define NV04_PGRAPH_DMA_LENGTH                             0x00401008
-#define NV04_PGRAPH_DMA_MISC                               0x0040100C
-#define NV04_PGRAPH_DMA_DATA_0                             0x00401020
-#define NV04_PGRAPH_DMA_DATA_1                             0x00401024
-#define NV04_PGRAPH_DMA_RM                                 0x00401030
-#define NV04_PGRAPH_DMA_A_XLATE_INST                       0x00401040
-#define NV04_PGRAPH_DMA_A_CONTROL                          0x00401044
-#define NV04_PGRAPH_DMA_A_LIMIT                            0x00401048
-#define NV04_PGRAPH_DMA_A_TLB_PTE                          0x0040104C
-#define NV04_PGRAPH_DMA_A_TLB_TAG                          0x00401050
-#define NV04_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054
-#define NV04_PGRAPH_DMA_A_OFFSET                           0x00401058
-#define NV04_PGRAPH_DMA_A_SIZE                             0x0040105C
-#define NV04_PGRAPH_DMA_A_Y_SIZE                           0x00401060
-#define NV04_PGRAPH_DMA_B_XLATE_INST                       0x00401080
-#define NV04_PGRAPH_DMA_B_CONTROL                          0x00401084
-#define NV04_PGRAPH_DMA_B_LIMIT                            0x00401088
-#define NV04_PGRAPH_DMA_B_TLB_PTE                          0x0040108C
-#define NV04_PGRAPH_DMA_B_TLB_TAG                          0x00401090
-#define NV04_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094
-#define NV04_PGRAPH_DMA_B_OFFSET                           0x00401098
-#define NV04_PGRAPH_DMA_B_SIZE                             0x0040109C
-#define NV04_PGRAPH_DMA_B_Y_SIZE                           0x004010A0
-#define NV47_PGRAPH_ZCOMP1(i)                              (0x004068c0 + 4*(i))
-#define NV40_PGRAPH_TILE1(i)                               (0x00406900 + (i*16))
-#define NV40_PGRAPH_TLIMIT1(i)                             (0x00406904 + (i*16))
-#define NV40_PGRAPH_TSIZE1(i)                              (0x00406908 + (i*16))
-#define NV40_PGRAPH_TSTATUS1(i)                            (0x0040690C + (i*16))
-#define NV40_PGRAPH_ZCOMP1(i)                              (0x00406980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP1(i)                              (0x004069c0 + 4*(i))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
deleted file mode 100644
index d88c700..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/fifo.h>
-#include <engine/mpeg.h>
-#include <engine/mpeg/nv31.h>
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv31_mpeg_object_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 size,
-		      struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    20, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-	return 0;
-}
-
-static int
-nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
-{
-	struct nouveau_instmem *imem = nouveau_instmem(object);
-	struct nv31_mpeg_priv *priv = (void *)object->engine;
-	u32 inst = *(u32 *)arg << 4;
-	u32 dma0 = nv_ro32(imem, inst + 0);
-	u32 dma1 = nv_ro32(imem, inst + 4);
-	u32 dma2 = nv_ro32(imem, inst + 8);
-	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
-	u32 size = dma1 + 1;
-
-	/* only allow linear DMA objects */
-	if (!(dma0 & 0x00002000))
-		return -EINVAL;
-
-	if (mthd == 0x0190) {
-		/* DMA_CMD */
-		nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0);
-		nv_wr32(priv, 0x00b334, base);
-		nv_wr32(priv, 0x00b324, size);
-	} else
-	if (mthd == 0x01a0) {
-		/* DMA_DATA */
-		nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0);
-		nv_wr32(priv, 0x00b360, base);
-		nv_wr32(priv, 0x00b364, size);
-	} else {
-		/* DMA_IMAGE, VRAM only */
-		if (dma0 & 0x00030000)
-			return -EINVAL;
-
-		nv_wr32(priv, 0x00b370, base);
-		nv_wr32(priv, 0x00b374, size);
-	}
-
-	return 0;
-}
-
-struct nouveau_ofuncs
-nv31_mpeg_ofuncs = {
-	.ctor = nv31_mpeg_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_omthds
-nv31_mpeg_omthds[] = {
-	{ 0x0190, 0x0190, nv31_mpeg_mthd_dma },
-	{ 0x01a0, 0x01a0, nv31_mpeg_mthd_dma },
-	{ 0x01b0, 0x01b0, nv31_mpeg_mthd_dma },
-	{}
-};
-
-struct nouveau_oclass
-nv31_mpeg_sclass[] = {
-	{ 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static int
-nv31_mpeg_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nv31_mpeg_priv *priv = (void *)engine;
-	struct nv31_mpeg_chan *chan;
-	unsigned long flags;
-	int ret;
-
-	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
-	if (priv->chan) {
-		spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
-		nouveau_object_destroy(&chan->base);
-		*pobject = NULL;
-		return -EBUSY;
-	}
-	priv->chan = chan;
-	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
-	return 0;
-}
-
-static void
-nv31_mpeg_context_dtor(struct nouveau_object *object)
-{
-	struct nv31_mpeg_priv *priv = (void *)object->engine;
-	struct nv31_mpeg_chan *chan = (void *)object;
-	unsigned long flags;
-
-	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
-	priv->chan = NULL;
-	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
-	nouveau_object_destroy(&chan->base);
-}
-
-struct nouveau_oclass
-nv31_mpeg_cclass = {
-	.handle = NV_ENGCTX(MPEG, 0x31),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv31_mpeg_context_ctor,
-		.dtor = nv31_mpeg_context_dtor,
-		.init = nouveau_object_init,
-		.fini = nouveau_object_fini,
-	},
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-void
-nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i)
-{
-	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
-	struct nv31_mpeg_priv *priv = (void *)engine;
-
-	nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
-	nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
-	nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
-}
-
-void
-nv31_mpeg_intr(struct nouveau_subdev *subdev)
-{
-	struct nv31_mpeg_priv *priv = (void *)subdev;
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_handle *handle;
-	struct nouveau_object *engctx;
-	u32 stat = nv_rd32(priv, 0x00b100);
-	u32 type = nv_rd32(priv, 0x00b230);
-	u32 mthd = nv_rd32(priv, 0x00b234);
-	u32 data = nv_rd32(priv, 0x00b238);
-	u32 show = stat;
-	unsigned long flags;
-
-	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
-	engctx = nv_object(priv->chan);
-
-	if (stat & 0x01000000) {
-		/* happens on initial binding of the object */
-		if (type == 0x00000020 && mthd == 0x0000) {
-			nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
-			show &= ~0x01000000;
-		}
-
-		if (type == 0x00000010 && engctx) {
-			handle = nouveau_handle_get_class(engctx, 0x3174);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~0x01000000;
-			nouveau_handle_put(handle);
-		}
-	}
-
-	nv_wr32(priv, 0x00b100, stat);
-	nv_wr32(priv, 0x00b230, 0x00000001);
-
-	if (show) {
-		nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			 pfifo->chid(pfifo, engctx),
-			 nouveau_client_name(engctx), stat, type, mthd, data);
-	}
-
-	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
-}
-
-static int
-nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv31_mpeg_priv *priv;
-	int ret;
-
-	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000002;
-	nv_subdev(priv)->intr = nv31_mpeg_intr;
-	nv_engine(priv)->cclass = &nv31_mpeg_cclass;
-	nv_engine(priv)->sclass = nv31_mpeg_sclass;
-	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
-	return 0;
-}
-
-int
-nv31_mpeg_init(struct nouveau_object *object)
-{
-	struct nouveau_engine *engine = nv_engine(object);
-	struct nv31_mpeg_priv *priv = (void *)object;
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	int ret, i;
-
-	ret = nouveau_mpeg_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* VPE init */
-	nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
-	nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
-
-	for (i = 0; i < pfb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
-	/* PMPEG init */
-	nv_wr32(priv, 0x00b32c, 0x00000000);
-	nv_wr32(priv, 0x00b314, 0x00000100);
-	nv_wr32(priv, 0x00b220, 0x00000031);
-	nv_wr32(priv, 0x00b300, 0x02001ec1);
-	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-
-	nv_wr32(priv, 0x00b100, 0xffffffff);
-	nv_wr32(priv, 0x00b140, 0xffffffff);
-
-	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
-		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-nv31_mpeg_oclass = {
-	.handle = NV_ENGINE(MPEG, 0x31),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv31_mpeg_ctor,
-		.dtor = _nouveau_mpeg_dtor,
-		.init = nv31_mpeg_init,
-		.fini = _nouveau_mpeg_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h
deleted file mode 100644
index d08629d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __NV31_MPEG_H__
-#define __NV31_MPEG_H__
-
-#include <engine/mpeg.h>
-
-struct nv31_mpeg_chan {
-	struct nouveau_object base;
-};
-
-struct nv31_mpeg_priv {
-	struct nouveau_mpeg base;
-	struct nv31_mpeg_chan *chan;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
deleted file mode 100644
index bdb2f20..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/mpeg.h>
-#include <engine/mpeg/nv31.h>
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv40_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
-{
-	struct nouveau_instmem *imem = nouveau_instmem(object);
-	struct nv31_mpeg_priv *priv = (void *)object->engine;
-	u32 inst = *(u32 *)arg << 4;
-	u32 dma0 = nv_ro32(imem, inst + 0);
-	u32 dma1 = nv_ro32(imem, inst + 4);
-	u32 dma2 = nv_ro32(imem, inst + 8);
-	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
-	u32 size = dma1 + 1;
-
-	/* only allow linear DMA objects */
-	if (!(dma0 & 0x00002000))
-		return -EINVAL;
-
-	if (mthd == 0x0190) {
-		/* DMA_CMD */
-		nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
-		nv_wr32(priv, 0x00b334, base);
-		nv_wr32(priv, 0x00b324, size);
-	} else
-	if (mthd == 0x01a0) {
-		/* DMA_DATA */
-		nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
-		nv_wr32(priv, 0x00b360, base);
-		nv_wr32(priv, 0x00b364, size);
-	} else {
-		/* DMA_IMAGE, VRAM only */
-		if (dma0 & 0x00030000)
-			return -EINVAL;
-
-		nv_wr32(priv, 0x00b370, base);
-		nv_wr32(priv, 0x00b374, size);
-	}
-
-	return 0;
-}
-
-static struct nouveau_omthds
-nv40_mpeg_omthds[] = {
-	{ 0x0190, 0x0190, nv40_mpeg_mthd_dma },
-	{ 0x01a0, 0x01a0, nv40_mpeg_mthd_dma },
-	{ 0x01b0, 0x01b0, nv40_mpeg_mthd_dma },
-	{}
-};
-
-struct nouveau_oclass
-nv40_mpeg_sclass[] = {
-	{ 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds },
-	{}
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_mpeg_intr(struct nouveau_subdev *subdev)
-{
-	struct nv31_mpeg_priv *priv = (void *)subdev;
-	u32 stat;
-
-	if ((stat = nv_rd32(priv, 0x00b100)))
-		nv31_mpeg_intr(subdev);
-
-	if ((stat = nv_rd32(priv, 0x00b800))) {
-		nv_error(priv, "PMSRCH 0x%08x\n", stat);
-		nv_wr32(priv, 0x00b800, stat);
-	}
-}
-
-static int
-nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv31_mpeg_priv *priv;
-	int ret;
-
-	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000002;
-	nv_subdev(priv)->intr = nv40_mpeg_intr;
-	nv_engine(priv)->cclass = &nv31_mpeg_cclass;
-	nv_engine(priv)->sclass = nv40_mpeg_sclass;
-	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv40_mpeg_oclass = {
-	.handle = NV_ENGINE(MPEG, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_mpeg_ctor,
-		.dtor = _nouveau_mpeg_dtor,
-		.init = nv31_mpeg_init,
-		.fini = _nouveau_mpeg_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c
deleted file mode 100644
index 72c7f33..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/fifo.h>
-#include <engine/mpeg.h>
-
-struct nv44_mpeg_priv {
-	struct nouveau_mpeg base;
-};
-
-struct nv44_mpeg_chan {
-	struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static int
-nv44_mpeg_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nv44_mpeg_chan *chan;
-	int ret;
-
-	ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
-					  264 * 4, 16,
-					  NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
-	return 0;
-}
-
-static int
-nv44_mpeg_context_fini(struct nouveau_object *object, bool suspend)
-{
-
-	struct nv44_mpeg_priv *priv = (void *)object->engine;
-	struct nv44_mpeg_chan *chan = (void *)object;
-	u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
-
-	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
-	if (nv_rd32(priv, 0x00b318) == inst)
-		nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
-	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv44_mpeg_cclass = {
-	.handle = NV_ENGCTX(MPEG, 0x44),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv44_mpeg_context_ctor,
-		.dtor = _nouveau_mpeg_context_dtor,
-		.init = _nouveau_mpeg_context_init,
-		.fini = nv44_mpeg_context_fini,
-		.rd32 = _nouveau_mpeg_context_rd32,
-		.wr32 = _nouveau_mpeg_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static void
-nv44_mpeg_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle;
-	struct nv44_mpeg_priv *priv = (void *)subdev;
-	u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
-	u32 stat = nv_rd32(priv, 0x00b100);
-	u32 type = nv_rd32(priv, 0x00b230);
-	u32 mthd = nv_rd32(priv, 0x00b234);
-	u32 data = nv_rd32(priv, 0x00b238);
-	u32 show = stat;
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x01000000) {
-		/* happens on initial binding of the object */
-		if (type == 0x00000020 && mthd == 0x0000) {
-			nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
-			show &= ~0x01000000;
-		}
-
-		if (type == 0x00000010) {
-			handle = nouveau_handle_get_class(engctx, 0x3174);
-			if (handle && !nv_call(handle->object, mthd, data))
-				show &= ~0x01000000;
-			nouveau_handle_put(handle);
-		}
-	}
-
-	nv_wr32(priv, 0x00b100, stat);
-	nv_wr32(priv, 0x00b230, 0x00000001);
-
-	if (show) {
-		nv_error(priv,
-			 "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			 chid, inst << 4, nouveau_client_name(engctx), stat,
-			 type, mthd, data);
-	}
-
-	nouveau_engctx_put(engctx);
-}
-
-static void
-nv44_mpeg_me_intr(struct nouveau_subdev *subdev)
-{
-	struct nv44_mpeg_priv *priv = (void *)subdev;
-	u32 stat;
-
-	if ((stat = nv_rd32(priv, 0x00b100)))
-		nv44_mpeg_intr(subdev);
-
-	if ((stat = nv_rd32(priv, 0x00b800))) {
-		nv_error(priv, "PMSRCH 0x%08x\n", stat);
-		nv_wr32(priv, 0x00b800, stat);
-	}
-}
-
-static int
-nv44_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv44_mpeg_priv *priv;
-	int ret;
-
-	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000002;
-	nv_subdev(priv)->intr = nv44_mpeg_me_intr;
-	nv_engine(priv)->cclass = &nv44_mpeg_cclass;
-	nv_engine(priv)->sclass = nv40_mpeg_sclass;
-	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv44_mpeg_oclass = {
-	.handle = NV_ENGINE(MPEG, 0x44),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv44_mpeg_ctor,
-		.dtor = _nouveau_mpeg_dtor,
-		.init = nv31_mpeg_init,
-		.fini = _nouveau_mpeg_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
deleted file mode 100644
index cae33f8..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-
-#include <engine/mpeg.h>
-
-struct nv50_mpeg_priv {
-	struct nouveau_mpeg base;
-};
-
-struct nv50_mpeg_chan {
-	struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv50_mpeg_object_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 size,
-		      struct nouveau_object **pobject)
-{
-	struct nouveau_gpuobj *obj;
-	int ret;
-
-	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
-				    16, 16, 0, &obj);
-	*pobject = nv_object(obj);
-	if (ret)
-		return ret;
-
-	nv_wo32(obj, 0x00, nv_mclass(obj));
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-	return 0;
-}
-
-struct nouveau_ofuncs
-nv50_mpeg_ofuncs = {
-	.ctor = nv50_mpeg_object_ctor,
-	.dtor = _nouveau_gpuobj_dtor,
-	.init = _nouveau_gpuobj_init,
-	.fini = _nouveau_gpuobj_fini,
-	.rd32 = _nouveau_gpuobj_rd32,
-	.wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv50_mpeg_sclass[] = {
-	{ 0x3174, &nv50_mpeg_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-int
-nv50_mpeg_context_ctor(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, void *data, u32 size,
-		       struct nouveau_object **pobject)
-{
-	struct nouveau_bar *bar = nouveau_bar(parent);
-	struct nv50_mpeg_chan *chan;
-	int ret;
-
-	ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
-					  0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	nv_wo32(chan, 0x0070, 0x00801ec1);
-	nv_wo32(chan, 0x007c, 0x0000037c);
-	bar->flush(bar);
-	return 0;
-}
-
-static struct nouveau_oclass
-nv50_mpeg_cclass = {
-	.handle = NV_ENGCTX(MPEG, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_mpeg_context_ctor,
-		.dtor = _nouveau_mpeg_context_dtor,
-		.init = _nouveau_mpeg_context_init,
-		.fini = _nouveau_mpeg_context_fini,
-		.rd32 = _nouveau_mpeg_context_rd32,
-		.wr32 = _nouveau_mpeg_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-void
-nv50_mpeg_intr(struct nouveau_subdev *subdev)
-{
-	struct nv50_mpeg_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, 0x00b100);
-	u32 type = nv_rd32(priv, 0x00b230);
-	u32 mthd = nv_rd32(priv, 0x00b234);
-	u32 data = nv_rd32(priv, 0x00b238);
-	u32 show = stat;
-
-	if (stat & 0x01000000) {
-		/* happens on initial binding of the object */
-		if (type == 0x00000020 && mthd == 0x0000) {
-			nv_wr32(priv, 0x00b308, 0x00000100);
-			show &= ~0x01000000;
-		}
-	}
-
-	if (show) {
-		nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
-			stat, type, mthd, data);
-	}
-
-	nv_wr32(priv, 0x00b100, stat);
-	nv_wr32(priv, 0x00b230, 0x00000001);
-}
-
-static void
-nv50_vpe_intr(struct nouveau_subdev *subdev)
-{
-	struct nv50_mpeg_priv *priv = (void *)subdev;
-
-	if (nv_rd32(priv, 0x00b100))
-		nv50_mpeg_intr(subdev);
-
-	if (nv_rd32(priv, 0x00b800)) {
-		u32 stat = nv_rd32(priv, 0x00b800);
-		nv_info(priv, "PMSRCH: 0x%08x\n", stat);
-		nv_wr32(priv, 0xb800, stat);
-	}
-}
-
-static int
-nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv50_mpeg_priv *priv;
-	int ret;
-
-	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00400002;
-	nv_subdev(priv)->intr = nv50_vpe_intr;
-	nv_engine(priv)->cclass = &nv50_mpeg_cclass;
-	nv_engine(priv)->sclass = nv50_mpeg_sclass;
-	return 0;
-}
-
-int
-nv50_mpeg_init(struct nouveau_object *object)
-{
-	struct nv50_mpeg_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_mpeg_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x00b32c, 0x00000000);
-	nv_wr32(priv, 0x00b314, 0x00000100);
-	nv_wr32(priv, 0x00b0e0, 0x0000001a);
-
-	nv_wr32(priv, 0x00b220, 0x00000044);
-	nv_wr32(priv, 0x00b300, 0x00801ec1);
-	nv_wr32(priv, 0x00b390, 0x00000000);
-	nv_wr32(priv, 0x00b394, 0x00000000);
-	nv_wr32(priv, 0x00b398, 0x00000000);
-	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-
-	nv_wr32(priv, 0x00b100, 0xffffffff);
-	nv_wr32(priv, 0x00b140, 0xffffffff);
-
-	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
-		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-nv50_mpeg_oclass = {
-	.handle = NV_ENGINE(MPEG, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_mpeg_ctor,
-		.dtor = _nouveau_mpeg_dtor,
-		.init = nv50_mpeg_init,
-		.fini = _nouveau_mpeg_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
deleted file mode 100644
index e9cc8b1..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-
-#include <engine/mpeg.h>
-
-struct nv84_mpeg_priv {
-	struct nouveau_mpeg base;
-};
-
-struct nv84_mpeg_chan {
-	struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_mpeg_sclass[] = {
-	{ 0x8274, &nv50_mpeg_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_mpeg_cclass = {
-	.handle = NV_ENGCTX(MPEG, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_mpeg_context_ctor,
-		.dtor = _nouveau_mpeg_context_dtor,
-		.init = _nouveau_mpeg_context_init,
-		.fini = _nouveau_mpeg_context_fini,
-		.rd32 = _nouveau_mpeg_context_rd32,
-		.wr32 = _nouveau_mpeg_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv84_mpeg_priv *priv;
-	int ret;
-
-	ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000002;
-	nv_subdev(priv)->intr = nv50_mpeg_intr;
-	nv_engine(priv)->cclass = &nv84_mpeg_cclass;
-	nv_engine(priv)->sclass = nv84_mpeg_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nv84_mpeg_oclass = {
-	.handle = NV_ENGINE(MPEG, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_mpeg_ctor,
-		.dtor = _nouveau_mpeg_dtor,
-		.init = nv50_mpeg_init,
-		.fini = _nouveau_mpeg_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
deleted file mode 100644
index 6301381..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/ioctl.h>
-
-#include <subdev/clock.h>
-
-#include "priv.h"
-
-#define QUAD_MASK 0x0f
-#define QUAD_FREE 0x01
-
-static struct nouveau_perfsig *
-nouveau_perfsig_find_(struct nouveau_perfdom *dom, const char *name, u32 size)
-{
-	char path[64];
-	int i;
-
-	if (name[0] != '/') {
-		for (i = 0; i < dom->signal_nr; i++) {
-			if ( dom->signal[i].name &&
-			    !strncmp(name, dom->signal[i].name, size))
-				return &dom->signal[i];
-		}
-	} else {
-		for (i = 0; i < dom->signal_nr; i++) {
-			snprintf(path, sizeof(path), "/%s/%02x", dom->name, i);
-			if (!strncmp(name, path, size))
-				return &dom->signal[i];
-		}
-	}
-
-	return NULL;
-}
-
-struct nouveau_perfsig *
-nouveau_perfsig_find(struct nouveau_perfmon *ppm, const char *name, u32 size,
-		     struct nouveau_perfdom **pdom)
-{
-	struct nouveau_perfdom *dom = *pdom;
-	struct nouveau_perfsig *sig;
-
-	if (dom == NULL) {
-		list_for_each_entry(dom, &ppm->domains, head) {
-			sig = nouveau_perfsig_find_(dom, name, size);
-			if (sig) {
-				*pdom = dom;
-				return sig;
-			}
-		}
-
-		return NULL;
-	}
-
-	return nouveau_perfsig_find_(dom, name, size);
-}
-
-struct nouveau_perfctr *
-nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name,
-		     struct nouveau_perfdom **pdom)
-{
-	struct nouveau_perfsig *sig;
-	struct nouveau_perfctr *ctr;
-
-	sig = nouveau_perfsig_find(ppm, name, strlen(name), pdom);
-	if (!sig)
-		return NULL;
-
-	ctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
-	if (ctr) {
-		ctr->signal[0] = sig;
-		ctr->logic_op = 0xaaaa;
-	}
-
-	return ctr;
-}
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-static int
-nouveau_perfctr_query(struct nouveau_object *object, void *data, u32 size)
-{
-	union {
-		struct nvif_perfctr_query_v0 v0;
-	} *args = data;
-	struct nouveau_device *device = nv_device(object);
-	struct nouveau_perfmon *ppm = (void *)object->engine;
-	struct nouveau_perfdom *dom = NULL, *chk;
-	const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false);
-	const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all);
-	const char *name;
-	int tmp = 0, di, si;
-	int ret;
-
-	nv_ioctl(object, "perfctr query size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "perfctr query vers %d iter %08x\n",
-			 args->v0.version, args->v0.iter);
-		di = (args->v0.iter & 0xff000000) >> 24;
-		si = (args->v0.iter & 0x00ffffff) - 1;
-	} else
-		return ret;
-
-	list_for_each_entry(chk, &ppm->domains, head) {
-		if (tmp++ == di) {
-			dom = chk;
-			break;
-		}
-	}
-
-	if (dom == NULL || si >= (int)dom->signal_nr)
-		return -EINVAL;
-
-	if (si >= 0) {
-		if (raw || !(name = dom->signal[si].name)) {
-			snprintf(args->v0.name, sizeof(args->v0.name),
-				 "/%s/%02x", dom->name, si);
-		} else {
-			strncpy(args->v0.name, name, sizeof(args->v0.name));
-		}
-	}
-
-	do {
-		while (++si < dom->signal_nr) {
-			if (all || dom->signal[si].name) {
-				args->v0.iter = (di << 24) | ++si;
-				return 0;
-			}
-		}
-		si = -1;
-		di = di + 1;
-		dom = list_entry(dom->head.next, typeof(*dom), head);
-	} while (&dom->head != &ppm->domains);
-
-	args->v0.iter = 0xffffffff;
-	return 0;
-}
-
-static int
-nouveau_perfctr_sample(struct nouveau_object *object, void *data, u32 size)
-{
-	union {
-		struct nvif_perfctr_sample none;
-	} *args = data;
-	struct nouveau_perfmon *ppm = (void *)object->engine;
-	struct nouveau_perfctr *ctr, *tmp;
-	struct nouveau_perfdom *dom;
-	int ret;
-
-	nv_ioctl(object, "perfctr sample size %d\n", size);
-	if (nvif_unvers(args->none)) {
-		nv_ioctl(object, "perfctr sample\n");
-	} else
-		return ret;
-	ppm->sequence++;
-
-	list_for_each_entry(dom, &ppm->domains, head) {
-		/* sample previous batch of counters */
-		if (dom->quad != QUAD_MASK) {
-			dom->func->next(ppm, dom);
-			tmp = NULL;
-			while (!list_empty(&dom->list)) {
-				ctr = list_first_entry(&dom->list,
-							typeof(*ctr), head);
-				if (ctr->slot < 0) break;
-				if ( tmp && tmp == ctr) break;
-				if (!tmp) tmp = ctr;
-				dom->func->read(ppm, dom, ctr);
-				ctr->slot  = -1;
-				list_move_tail(&ctr->head, &dom->list);
-			}
-		}
-
-		dom->quad = QUAD_MASK;
-
-		/* setup next batch of counters for sampling */
-		list_for_each_entry(ctr, &dom->list, head) {
-			ctr->slot = ffs(dom->quad) - 1;
-			if (ctr->slot < 0)
-				break;
-			dom->quad &= ~(QUAD_FREE << ctr->slot);
-			dom->func->init(ppm, dom, ctr);
-		}
-
-		if (dom->quad != QUAD_MASK)
-			dom->func->next(ppm, dom);
-	}
-
-	return 0;
-}
-
-static int
-nouveau_perfctr_read(struct nouveau_object *object, void *data, u32 size)
-{
-	union {
-		struct nvif_perfctr_read_v0 v0;
-	} *args = data;
-	struct nouveau_perfctr *ctr = (void *)object;
-	int ret;
-
-	nv_ioctl(object, "perfctr read size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
-	} else
-		return ret;
-
-	if (!ctr->clk)
-		return -EAGAIN;
-
-	args->v0.clk = ctr->clk;
-	args->v0.ctr = ctr->ctr;
-	return 0;
-}
-
-static int
-nouveau_perfctr_mthd(struct nouveau_object *object, u32 mthd,
-		     void *data, u32 size)
-{
-	switch (mthd) {
-	case NVIF_PERFCTR_V0_QUERY:
-		return nouveau_perfctr_query(object, data, size);
-	case NVIF_PERFCTR_V0_SAMPLE:
-		return nouveau_perfctr_sample(object, data, size);
-	case NVIF_PERFCTR_V0_READ:
-		return nouveau_perfctr_read(object, data, size);
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
-static void
-nouveau_perfctr_dtor(struct nouveau_object *object)
-{
-	struct nouveau_perfctr *ctr = (void *)object;
-	if (ctr->head.next)
-		list_del(&ctr->head);
-	nouveau_object_destroy(&ctr->base);
-}
-
-static int
-nouveau_perfctr_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	union {
-		struct nvif_perfctr_v0 v0;
-	} *args = data;
-	struct nouveau_perfmon *ppm = (void *)engine;
-	struct nouveau_perfdom *dom = NULL;
-	struct nouveau_perfsig *sig[4] = {};
-	struct nouveau_perfctr *ctr;
-	int ret, i;
-
-	nv_ioctl(parent, "create perfctr size %d\n", size);
-	if (nvif_unpack(args->v0, 0, 0, false)) {
-		nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
-			 args->v0.version, args->v0.logic_op);
-	} else
-		return ret;
-
-	for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
-		sig[i] = nouveau_perfsig_find(ppm, args->v0.name[i],
-					      strnlen(args->v0.name[i],
-					      sizeof(args->v0.name[i])),
-					      &dom);
-		if (!sig[i])
-			return -EINVAL;
-	}
-
-	ret = nouveau_object_create(parent, engine, oclass, 0, &ctr);
-	*pobject = nv_object(ctr);
-	if (ret)
-		return ret;
-
-	ctr->slot = -1;
-	ctr->logic_op = args->v0.logic_op;
-	ctr->signal[0] = sig[0];
-	ctr->signal[1] = sig[1];
-	ctr->signal[2] = sig[2];
-	ctr->signal[3] = sig[3];
-	if (dom)
-		list_add_tail(&ctr->head, &dom->list);
-	return 0;
-}
-
-static struct nouveau_ofuncs
-nouveau_perfctr_ofuncs = {
-	.ctor = nouveau_perfctr_ctor,
-	.dtor = nouveau_perfctr_dtor,
-	.init = nouveau_object_init,
-	.fini = nouveau_object_fini,
-	.mthd = nouveau_perfctr_mthd,
-};
-
-struct nouveau_oclass
-nouveau_perfmon_sclass[] = {
-	{ .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
-	  .ofuncs = &nouveau_perfctr_ofuncs,
-	},
-	{},
-};
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-static void
-nouveau_perfctx_dtor(struct nouveau_object *object)
-{
-	struct nouveau_perfmon *ppm = (void *)object->engine;
-	mutex_lock(&nv_subdev(ppm)->mutex);
-	nouveau_engctx_destroy(&ppm->context->base);
-	ppm->context = NULL;
-	mutex_unlock(&nv_subdev(ppm)->mutex);
-}
-
-static int
-nouveau_perfctx_ctor(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, void *data, u32 size,
-		     struct nouveau_object **pobject)
-{
-	struct nouveau_perfmon *ppm = (void *)engine;
-	struct nouveau_perfctx *ctx;
-	int ret;
-
-	ret = nouveau_engctx_create(parent, engine, oclass, NULL,
-				    0, 0, 0, &ctx);
-	*pobject = nv_object(ctx);
-	if (ret)
-		return ret;
-
-	mutex_lock(&nv_subdev(ppm)->mutex);
-	if (ppm->context == NULL)
-		ppm->context = ctx;
-	mutex_unlock(&nv_subdev(ppm)->mutex);
-
-	if (ctx != ppm->context)
-		return -EBUSY;
-
-	return 0;
-}
-
-struct nouveau_oclass
-nouveau_perfmon_cclass = {
-	.handle = NV_ENGCTX(PERFMON, 0x00),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nouveau_perfctx_ctor,
-		.dtor = nouveau_perfctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-	},
-};
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-int
-nouveau_perfdom_new(struct nouveau_perfmon *ppm, const char *name, u32 mask,
-		    u32 base, u32 size_unit, u32 size_domain,
-		    const struct nouveau_specdom *spec)
-{
-	const struct nouveau_specdom *sdom;
-	const struct nouveau_specsig *ssig;
-	struct nouveau_perfdom *dom;
-	int i;
-
-	for (i = 0; i == 0 || mask; i++) {
-		u32 addr = base + (i * size_unit);
-		if (i && !(mask & (1 << i)))
-			continue;
-
-		sdom = spec;
-		while (sdom->signal_nr) {
-			dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
-				      sizeof(*dom->signal), GFP_KERNEL);
-			if (!dom)
-				return -ENOMEM;
-
-			if (mask) {
-				snprintf(dom->name, sizeof(dom->name),
-					 "%s/%02x/%02x", name, i,
-					 (int)(sdom - spec));
-			} else {
-				snprintf(dom->name, sizeof(dom->name),
-					 "%s/%02x", name, (int)(sdom - spec));
-			}
-
-			list_add_tail(&dom->head, &ppm->domains);
-			INIT_LIST_HEAD(&dom->list);
-			dom->func = sdom->func;
-			dom->addr = addr;
-			dom->quad = QUAD_MASK;
-			dom->signal_nr = sdom->signal_nr;
-
-			ssig = (sdom++)->signal;
-			while (ssig->name) {
-				dom->signal[ssig->signal].name = ssig->name;
-				ssig++;
-			}
-
-			addr += size_domain;
-		}
-
-		mask &= ~(1 << i);
-	}
-
-	return 0;
-}
-
-int
-_nouveau_perfmon_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_perfmon *ppm = (void *)object;
-	return nouveau_engine_fini(&ppm->base, suspend);
-}
-
-int
-_nouveau_perfmon_init(struct nouveau_object *object)
-{
-	struct nouveau_perfmon *ppm = (void *)object;
-	return nouveau_engine_init(&ppm->base);
-}
-
-void
-_nouveau_perfmon_dtor(struct nouveau_object *object)
-{
-	struct nouveau_perfmon *ppm = (void *)object;
-	struct nouveau_perfdom *dom, *tmp;
-
-	list_for_each_entry_safe(dom, tmp, &ppm->domains, head) {
-		list_del(&dom->head);
-		kfree(dom);
-	}
-
-	nouveau_engine_destroy(&ppm->base);
-}
-
-int
-nouveau_perfmon_create_(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass,
-			int length, void **pobject)
-{
-	struct nouveau_perfmon *ppm;
-	int ret;
-
-	ret = nouveau_engine_create_(parent, engine, oclass, true, "PPM",
-				     "perfmon", length, pobject);
-	ppm = *pobject;
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&ppm->domains);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c
deleted file mode 100644
index 50696cc..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static void
-pwr_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		 struct nouveau_perfctr *ctr)
-{
-	u32 mask = 0x00000000;
-	u32 ctrl = 0x00000001;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++)
-		mask |= 1 << (ctr->signal[i] - dom->signal);
-
-	nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask);
-	nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl);
-	nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003);
-}
-
-static void
-pwr_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		 struct nouveau_perfctr *ctr)
-{
-	ctr->ctr = ppm->pwr[ctr->slot];
-	ctr->clk = ppm->pwr[ppm->last];
-}
-
-static void
-pwr_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
-	int i;
-
-	for (i = 0; i <= ppm->last; i++) {
-		ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10));
-		nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000);
-	}
-}
-
-static const struct nouveau_funcdom
-pwr_perfctr_func = {
-	.init = pwr_perfctr_init,
-	.read = pwr_perfctr_read,
-	.next = pwr_perfctr_next,
-};
-
-const struct nouveau_specdom
-nva3_perfmon_pwr[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{ 0x00, "pwr_gr_idle" },
-			{ 0x04, "pwr_bsp_idle" },
-			{ 0x05, "pwr_vp_idle" },
-			{ 0x06, "pwr_ppp_idle" },
-			{ 0x13, "pwr_ce0_idle" },
-			{}
-		}, &pwr_perfctr_func },
-	{}
-};
-
-const struct nouveau_specdom
-nvc0_perfmon_pwr[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{ 0x00, "pwr_gr_idle" },
-			{ 0x04, "pwr_bsp_idle" },
-			{ 0x05, "pwr_vp_idle" },
-			{ 0x06, "pwr_ppp_idle" },
-			{ 0x13, "pwr_ce0_idle" },
-			{ 0x14, "pwr_ce1_idle" },
-			{}
-		}, &pwr_perfctr_func },
-	{}
-};
-
-const struct nouveau_specdom
-nve0_perfmon_pwr[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{ 0x00, "pwr_gr_idle" },
-			{ 0x04, "pwr_bsp_idle" },
-			{ 0x05, "pwr_vp_idle" },
-			{ 0x06, "pwr_ppp_idle" },
-			{ 0x13, "pwr_ce0_idle" },
-			{ 0x14, "pwr_ce1_idle" },
-			{ 0x15, "pwr_ce2_idle" },
-			{}
-		}, &pwr_perfctr_func },
-	{}
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c
deleted file mode 100644
index b2a1078..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		  struct nouveau_perfctr *ctr)
-{
-	struct nv40_perfmon_priv *priv = (void *)ppm;
-	struct nv40_perfmon_cntr *cntr = (void *)ctr;
-	u32 log = ctr->logic_op;
-	u32 src = 0x00000000;
-	int i;
-
-	for (i = 0; i < 4 && ctr->signal[i]; i++)
-		src |= (ctr->signal[i] - dom->signal) << (i * 8);
-
-	nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
-	nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
-	nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
-}
-
-static void
-nv40_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		  struct nouveau_perfctr *ctr)
-{
-	struct nv40_perfmon_priv *priv = (void *)ppm;
-	struct nv40_perfmon_cntr *cntr = (void *)ctr;
-
-	switch (cntr->base.slot) {
-	case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
-	case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
-	case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
-	case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
-	}
-	cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
-}
-
-static void
-nv40_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
-	struct nv40_perfmon_priv *priv = (void *)ppm;
-	if (priv->sequence != ppm->sequence) {
-		nv_wr32(priv, 0x400084, 0x00000020);
-		priv->sequence = ppm->sequence;
-	}
-}
-
-const struct nouveau_funcdom
-nv40_perfctr_func = {
-	.init = nv40_perfctr_init,
-	.read = nv40_perfctr_read,
-	.next = nv40_perfctr_next,
-};
-
-static const struct nouveau_specdom
-nv40_perfmon[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{}
-};
-
-int
-nv40_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv40_perfmon_oclass *mclass = (void *)oclass;
-	struct nv40_perfmon_priv *priv;
-	int ret;
-
-	ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
-	nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv40_perfmon_oclass = &(struct nv40_perfmon_oclass) {
-	.base.handle = NV_ENGINE(PERFMON, 0x40),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = _nouveau_perfmon_fini,
-	},
-	.doms = nv40_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h
deleted file mode 100644
index 1b5792d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __NVKM_PM_NV40_H__
-#define __NVKM_PM_NV40_H__
-
-#include "priv.h"
-
-struct nv40_perfmon_oclass {
-	struct nouveau_oclass base;
-	const struct nouveau_specdom *doms;
-};
-
-struct nv40_perfmon_priv {
-	struct nouveau_perfmon base;
-	u32 sequence;
-};
-
-int nv40_perfmon_ctor(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, void *data, u32 size,
-		      struct nouveau_object **pobject);
-
-struct nv40_perfmon_cntr {
-	struct nouveau_perfctr base;
-};
-
-extern const struct nouveau_funcdom nv40_perfctr_func;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c
deleted file mode 100644
index 9421769..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nv50_perfmon[] = {
-	{ 0x040, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x100, (const struct nouveau_specsig[]) {
-			{ 0xc8, "gr_idle" },
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x100, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x020, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x040, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{}
-};
-
-struct nouveau_oclass *
-nv50_perfmon_oclass = &(struct nv40_perfmon_oclass) {
-	.base.handle = NV_ENGINE(PERFMON, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = _nouveau_perfmon_fini,
-	},
-	.doms = nv50_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c
deleted file mode 100644
index 9232c7f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nv84_perfmon[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{}
-};
-
-struct nouveau_oclass *
-nv84_perfmon_oclass = &(struct nv40_perfmon_oclass) {
-	.base.handle = NV_ENGINE(PERFMON, 0x84),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = _nouveau_perfmon_fini,
-	},
-	.doms = nv84_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c
deleted file mode 100644
index 6197ebd..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nva3_perfmon[] = {
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{ 0x20, (const struct nouveau_specsig[]) {
-			{}
-		}, &nv40_perfctr_func },
-	{}
-};
-
-static int
-nva3_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **object)
-{
-	int ret = nv40_perfmon_ctor(parent, engine, oclass, data, size, object);
-	if (ret == 0) {
-		struct nv40_perfmon_priv *priv = (void *)*object;
-		ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
-					   nva3_perfmon_pwr);
-		if (ret)
-			return ret;
-
-		priv->base.last = 3;
-	}
-	return ret;
-}
-
-struct nouveau_oclass *
-nva3_perfmon_oclass = &(struct nv40_perfmon_oclass) {
-	.base.handle = NV_ENGINE(PERFMON, 0xa3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = _nouveau_perfmon_fini,
-	},
-	.doms = nva3_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c
deleted file mode 100644
index 74b2410..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nvc0_perfmon_hub[] = {
-	{}
-};
-
-static const struct nouveau_specdom
-nvc0_perfmon_gpc[] = {
-	{}
-};
-
-static const struct nouveau_specdom
-nvc0_perfmon_part[] = {
-	{}
-};
-
-static void
-nvc0_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		  struct nouveau_perfctr *ctr)
-{
-	struct nvc0_perfmon_priv *priv = (void *)ppm;
-	struct nvc0_perfmon_cntr *cntr = (void *)ctr;
-	u32 log = ctr->logic_op;
-	u32 src = 0x00000000;
-	int i;
-
-	for (i = 0; i < 4 && ctr->signal[i]; i++)
-		src |= (ctr->signal[i] - dom->signal) << (i * 8);
-
-	nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
-	nv_wr32(priv, dom->addr + 0x100, 0x00000000);
-	nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
-	nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
-}
-
-static void
-nvc0_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
-		  struct nouveau_perfctr *ctr)
-{
-	struct nvc0_perfmon_priv *priv = (void *)ppm;
-	struct nvc0_perfmon_cntr *cntr = (void *)ctr;
-
-	switch (cntr->base.slot) {
-	case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break;
-	case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break;
-	case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
-	case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
-	}
-	cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
-}
-
-static void
-nvc0_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
-	struct nvc0_perfmon_priv *priv = (void *)ppm;
-	nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
-	nv_wr32(priv, dom->addr + 0x0ec, 0x00000011);
-}
-
-const struct nouveau_funcdom
-nvc0_perfctr_func = {
-	.init = nvc0_perfctr_init,
-	.read = nvc0_perfctr_read,
-	.next = nvc0_perfctr_next,
-};
-
-int
-nvc0_perfmon_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvc0_perfmon_priv *priv = (void *)object;
-	nv_mask(priv, 0x000200, 0x10000000, 0x00000000);
-	nv_mask(priv, 0x000200, 0x10000000, 0x10000000);
-	return nouveau_perfmon_fini(&priv->base, suspend);
-}
-
-static int
-nvc0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nvc0_perfmon_priv *priv;
-	u32 mask;
-	int ret;
-
-	ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
-				   nvc0_perfmon_pwr);
-	if (ret)
-		return ret;
-
-	/* HUB */
-	ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
-				   nvc0_perfmon_hub);
-	if (ret)
-		return ret;
-
-	/* GPC */
-	mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
-	mask &= ~nv_rd32(priv, 0x022504);
-	mask &= ~nv_rd32(priv, 0x022584);
-
-	ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
-				  0x1000, 0x200, nvc0_perfmon_gpc);
-	if (ret)
-		return ret;
-
-	/* PART */
-	mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
-	mask &= ~nv_rd32(priv, 0x022548);
-	mask &= ~nv_rd32(priv, 0x0225c8);
-
-	ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
-				  0x1000, 0x200, nvc0_perfmon_part);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
-	nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
-	priv->base.last = 7;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_perfmon_oclass = {
-	.handle = NV_ENGINE(PERFMON, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = nvc0_perfmon_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h
deleted file mode 100644
index f66bca4..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_PM_NVC0_H__
-#define __NVKM_PM_NVC0_H__
-
-#include "priv.h"
-
-struct nvc0_perfmon_priv {
-	struct nouveau_perfmon base;
-};
-
-struct nvc0_perfmon_cntr {
-	struct nouveau_perfctr base;
-};
-
-extern const struct nouveau_funcdom nvc0_perfctr_func;
-int nvc0_perfmon_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c
deleted file mode 100644
index 71d718c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nve0_perfmon_hub[] = {
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "hub00_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x40, (const struct nouveau_specsig[]) {
-			{ 0x27, "hub01_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "hub02_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "hub03_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x40, (const struct nouveau_specsig[]) {
-			{ 0x03, "host_mmio_rd" },
-			{ 0x27, "hub04_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "hub05_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0xc0, (const struct nouveau_specsig[]) {
-			{ 0x74, "host_fb_rd3x" },
-			{ 0x75, "host_fb_rd3x_2" },
-			{ 0xa7, "hub06_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "hub07_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{}
-};
-
-static const struct nouveau_specdom
-nve0_perfmon_gpc[] = {
-	{ 0xe0, (const struct nouveau_specsig[]) {
-			{ 0xc7, "gpc00_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{}
-};
-
-static const struct nouveau_specdom
-nve0_perfmon_part[] = {
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "part00_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{ 0x60, (const struct nouveau_specsig[]) {
-			{ 0x47, "part01_user_0" },
-			{}
-		}, &nvc0_perfctr_func },
-	{}
-};
-
-static int
-nve0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nvc0_perfmon_priv *priv;
-	u32 mask;
-	int ret;
-
-	ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	/* PDAEMON */
-	ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
-				   nve0_perfmon_pwr);
-	if (ret)
-		return ret;
-
-	/* HUB */
-	ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
-				   nve0_perfmon_hub);
-	if (ret)
-		return ret;
-
-	/* GPC */
-	mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
-	mask &= ~nv_rd32(priv, 0x022504);
-	mask &= ~nv_rd32(priv, 0x022584);
-
-	ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
-				  0x1000, 0x200, nve0_perfmon_gpc);
-	if (ret)
-		return ret;
-
-	/* PART */
-	mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
-	mask &= ~nv_rd32(priv, 0x022548);
-	mask &= ~nv_rd32(priv, 0x0225c8);
-
-	ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
-				  0x1000, 0x200, nve0_perfmon_part);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
-	nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
-	priv->base.last = 7;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_perfmon_oclass = {
-	.handle = NV_ENGINE(PERFMON, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = nvc0_perfmon_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c
deleted file mode 100644
index 47256f7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static int
-nvf0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nvc0_perfmon_priv *priv;
-	int ret;
-
-	ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
-				   nve0_perfmon_pwr);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
-	nv_engine(priv)->sclass =  nouveau_perfmon_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nvf0_perfmon_oclass = {
-	.handle = NV_ENGINE(PERFMON, 0xf0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvf0_perfmon_ctor,
-		.dtor = _nouveau_perfmon_dtor,
-		.init = _nouveau_perfmon_init,
-		.fini = nvc0_perfmon_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h
deleted file mode 100644
index 0ac8714..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef __NVKM_PERFMON_PRIV_H__
-#define __NVKM_PERFMON_PRIV_H__
-
-#include <engine/perfmon.h>
-
-struct nouveau_perfctr {
-	struct nouveau_object base;
-	struct list_head head;
-	struct nouveau_perfsig *signal[4];
-	int slot;
-	u32 logic_op;
-	u32 clk;
-	u32 ctr;
-};
-
-extern struct nouveau_oclass nouveau_perfmon_sclass[];
-
-struct nouveau_perfctx {
-	struct nouveau_engctx base;
-};
-
-extern struct nouveau_oclass nouveau_perfmon_cclass;
-
-struct nouveau_specsig {
-	u8 signal;
-	const char *name;
-};
-
-struct nouveau_perfsig {
-	const char *name;
-};
-
-struct nouveau_perfdom;
-struct nouveau_perfctr *
-nouveau_perfsig_wrap(struct nouveau_perfmon *, const char *,
-		     struct nouveau_perfdom **);
-
-struct nouveau_specdom {
-	u16 signal_nr;
-	const struct nouveau_specsig *signal;
-	const struct nouveau_funcdom *func;
-};
-
-extern const struct nouveau_specdom nva3_perfmon_pwr[];
-extern const struct nouveau_specdom nvc0_perfmon_pwr[];
-extern const struct nouveau_specdom nve0_perfmon_pwr[];
-
-struct nouveau_perfdom {
-	struct list_head head;
-	struct list_head list;
-	const struct nouveau_funcdom *func;
-	char name[32];
-	u32 addr;
-	u8  quad;
-	u32 signal_nr;
-	struct nouveau_perfsig signal[];
-};
-
-struct nouveau_funcdom {
-	void (*init)(struct nouveau_perfmon *, struct nouveau_perfdom *,
-		     struct nouveau_perfctr *);
-	void (*read)(struct nouveau_perfmon *, struct nouveau_perfdom *,
-		     struct nouveau_perfctr *);
-	void (*next)(struct nouveau_perfmon *, struct nouveau_perfdom *);
-};
-
-int nouveau_perfdom_new(struct nouveau_perfmon *, const char *, u32,
-			u32, u32, u32, const struct nouveau_specdom *);
-
-#define nouveau_perfmon_create(p,e,o,d)                                        \
-	nouveau_perfmon_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_perfmon_dtor(p) ({                                             \
-	struct nouveau_perfmon *c = (p);                                       \
-	_nouveau_perfmon_dtor(nv_object(c));                                   \
-})
-#define nouveau_perfmon_init(p) ({                                             \
-	struct nouveau_perfmon *c = (p);                                       \
-	_nouveau_perfmon_init(nv_object(c));                                   \
-})
-#define nouveau_perfmon_fini(p,s) ({                                           \
-	struct nouveau_perfmon *c = (p);                                       \
-	_nouveau_perfmon_fini(nv_object(c), (s));                              \
-})
-
-int nouveau_perfmon_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, int, void **);
-void _nouveau_perfmon_dtor(struct nouveau_object *);
-int  _nouveau_perfmon_init(struct nouveau_object *);
-int  _nouveau_perfmon_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
deleted file mode 100644
index 13bf31c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/ppp.h>
-
-struct nv98_ppp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * PPP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_ppp_sclass[] = {
-	{ 0x88b3, &nouveau_object_ofuncs },
-	{ 0x85b3, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PPPP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_ppp_cclass = {
-	.handle = NV_ENGCTX(PPP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PPPP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_ppp_init(struct nouveau_object *object)
-{
-	struct nv98_ppp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x086010, 0x0000ffd2);
-	nv_wr32(priv, 0x08601c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv98_ppp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
-				    "PPPP", "ppp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00400002;
-	nv_engine(priv)->cclass = &nv98_ppp_cclass;
-	nv_engine(priv)->sclass = nv98_ppp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nv98_ppp_oclass = {
-	.handle = NV_ENGINE(PPP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv98_ppp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nv98_ppp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
deleted file mode 100644
index 73719aa..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/ppp.h>
-
-struct nvc0_ppp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * PPP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_sclass[] = {
-	{ 0x90b3, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PPPP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_cclass = {
-	.handle = NV_ENGCTX(PPP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PPPP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_ppp_init(struct nouveau_object *object)
-{
-	struct nvc0_ppp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x086010, 0x0000fff2);
-	nv_wr32(priv, 0x08601c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nvc0_ppp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
-				    "PPPP", "ppp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00000002;
-	nv_subdev(priv)->intr = nouveau_falcon_intr;
-	nv_engine(priv)->cclass = &nvc0_ppp_cclass;
-	nv_engine(priv)->sclass = nvc0_ppp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_ppp_oclass = {
-	.handle = NV_ENGINE(PPP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_ppp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nvc0_ppp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
deleted file mode 100644
index 64df15c..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <engine/software.h>
-#include <engine/fifo.h>
-
-struct nv04_software_priv {
-	struct nouveau_software base;
-};
-
-struct nv04_software_chan {
-	struct nouveau_software_chan base;
-};
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv04_software_set_ref(struct nouveau_object *object, u32 mthd,
-		      void *data, u32 size)
-{
-	struct nouveau_object *channel = (void *)nv_engctx(object->parent);
-	struct nouveau_fifo_chan *fifo = (void *)channel->parent;
-	atomic_set(&fifo->refcnt, *(u32*)data);
-	return 0;
-}
-
-static int
-nv04_software_flip(struct nouveau_object *object, u32 mthd,
-		   void *args, u32 size)
-{
-	struct nv04_software_chan *chan = (void *)nv_engctx(object->parent);
-	if (chan->base.flip)
-		return chan->base.flip(chan->base.flip_data);
-	return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv04_software_omthds[] = {
-	{ 0x0150, 0x0150, nv04_software_set_ref },
-	{ 0x0500, 0x0500, nv04_software_flip },
-	{}
-};
-
-static struct nouveau_oclass
-nv04_software_sclass[] = {
-	{ 0x006e, &nouveau_object_ofuncs, nv04_software_omthds },
-	{}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv04_software_context_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 size,
-		      struct nouveau_object **pobject)
-{
-	struct nv04_software_chan *chan;
-	int ret;
-
-	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static struct nouveau_oclass
-nv04_software_cclass = {
-	.handle = NV_ENGCTX(SW, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_software_context_ctor,
-		.dtor = _nouveau_software_context_dtor,
-		.init = _nouveau_software_context_init,
-		.fini = _nouveau_software_context_fini,
-	},
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-void
-nv04_software_intr(struct nouveau_subdev *subdev)
-{
-	nv_mask(subdev, 0x000100, 0x80000000, 0x00000000);
-}
-
-static int
-nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv04_software_priv *priv;
-	int ret;
-
-	ret = nouveau_software_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nv04_software_cclass;
-	nv_engine(priv)->sclass = nv04_software_sclass;
-	nv_subdev(priv)->intr = nv04_software_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_software_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(SW, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_software_ctor,
-		.dtor = _nouveau_software_dtor,
-		.init = _nouveau_software_init,
-		.fini = _nouveau_software_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
deleted file mode 100644
index f54a225..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <engine/software.h>
-
-struct nv10_software_priv {
-	struct nouveau_software base;
-};
-
-struct nv10_software_chan {
-	struct nouveau_software_chan base;
-};
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv10_software_flip(struct nouveau_object *object, u32 mthd,
-		   void *args, u32 size)
-{
-	struct nv10_software_chan *chan = (void *)nv_engctx(object->parent);
-	if (chan->base.flip)
-		return chan->base.flip(chan->base.flip_data);
-	return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv10_software_omthds[] = {
-	{ 0x0500, 0x0500, nv10_software_flip },
-	{}
-};
-
-static struct nouveau_oclass
-nv10_software_sclass[] = {
-	{ 0x016e, &nouveau_object_ofuncs, nv10_software_omthds },
-	{}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv10_software_context_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 size,
-		      struct nouveau_object **pobject)
-{
-	struct nv10_software_chan *chan;
-	int ret;
-
-	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static struct nouveau_oclass
-nv10_software_cclass = {
-	.handle = NV_ENGCTX(SW, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_software_context_ctor,
-		.dtor = _nouveau_software_context_dtor,
-		.init = _nouveau_software_context_init,
-		.fini = _nouveau_software_context_fini,
-	},
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-static int
-nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv10_software_priv *priv;
-	int ret;
-
-	ret = nouveau_software_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = &nv10_software_cclass;
-	nv_engine(priv)->sclass = nv10_software_sclass;
-	nv_subdev(priv)->intr = nv04_software_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv10_software_oclass = &(struct nouveau_oclass) {
-	.handle = NV_ENGINE(SW, 0x10),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_software_ctor,
-		.dtor = _nouveau_software_dtor,
-		.init = _nouveau_software_init,
-		.fini = _nouveau_software_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
deleted file mode 100644
index a0fec20..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-#include <core/event.h>
-#include <nvif/event.h>
-
-#include <subdev/bar.h>
-
-#include <engine/disp.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd,
-			      void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	struct nouveau_fifo_chan *fifo = (void *)nv_object(chan)->parent;
-	struct nouveau_handle *handle;
-	int ret = -EINVAL;
-
-	handle = nouveau_namedb_get(nv_namedb(fifo), *(u32 *)args);
-	if (!handle)
-		return -ENOENT;
-
-	if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
-		struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object);
-		chan->vblank.ctxdma = gpuobj->node->offset >> 4;
-		ret = 0;
-	}
-	nouveau_namedb_put(handle);
-	return ret;
-}
-
-static int
-nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
-				 void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	chan->vblank.offset = *(u32 *)args;
-	return 0;
-}
-
-int
-nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
-				void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	chan->vblank.value = *(u32 *)args;
-	return 0;
-}
-
-int
-nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
-				  void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	u32 head = *(u32 *)args;
-	if (head >= nouveau_disp(chan)->vblank.index_nr)
-		return -EINVAL;
-
-	nvkm_notify_get(&chan->vblank.notify[head]);
-	return 0;
-}
-
-int
-nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
-			void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	if (chan->base.flip)
-		return chan->base.flip(chan->base.flip_data);
-	return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv50_software_omthds[] = {
-	{ 0x018c, 0x018c, nv50_software_mthd_dma_vblsem },
-	{ 0x0400, 0x0400, nv50_software_mthd_vblsem_offset },
-	{ 0x0404, 0x0404, nv50_software_mthd_vblsem_value },
-	{ 0x0408, 0x0408, nv50_software_mthd_vblsem_release },
-	{ 0x0500, 0x0500, nv50_software_mthd_flip },
-	{}
-};
-
-static struct nouveau_oclass
-nv50_software_sclass[] = {
-	{ 0x506e, &nouveau_object_ofuncs, nv50_software_omthds },
-	{}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv50_software_vblsem_release(struct nvkm_notify *notify)
-{
-	struct nv50_software_chan *chan =
-		container_of(notify, typeof(*chan), vblank.notify[notify->index]);
-	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
-	struct nouveau_bar *bar = nouveau_bar(priv);
-
-	nv_wr32(priv, 0x001704, chan->vblank.channel);
-	nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
-	bar->flush(bar);
-
-	if (nv_device(priv)->chipset == 0x50) {
-		nv_wr32(priv, 0x001570, chan->vblank.offset);
-		nv_wr32(priv, 0x001574, chan->vblank.value);
-	} else {
-		nv_wr32(priv, 0x060010, chan->vblank.offset);
-		nv_wr32(priv, 0x060014, chan->vblank.value);
-	}
-
-	return NVKM_NOTIFY_DROP;
-}
-
-void
-nv50_software_context_dtor(struct nouveau_object *object)
-{
-	struct nv50_software_chan *chan = (void *)object;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
-		nvkm_notify_fini(&chan->vblank.notify[i]);
-
-	nouveau_software_context_destroy(&chan->base);
-}
-
-int
-nv50_software_context_ctor(struct nouveau_object *parent,
-			   struct nouveau_object *engine,
-			   struct nouveau_oclass *oclass, void *data, u32 size,
-			   struct nouveau_object **pobject)
-{
-	struct nouveau_disp *pdisp = nouveau_disp(parent);
-	struct nv50_software_cclass *pclass = (void *)oclass;
-	struct nv50_software_chan *chan;
-	int ret, i;
-
-	ret = nouveau_software_context_create(parent, engine, oclass, &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
-		ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
-				       false,
-				       &(struct nvif_notify_head_req_v0) {
-					.head = i,
-				       },
-				       sizeof(struct nvif_notify_head_req_v0),
-				       sizeof(struct nvif_notify_head_rep_v0),
-				       &chan->vblank.notify[i]);
-		if (ret)
-			return ret;
-	}
-
-	chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
-	return 0;
-}
-
-static struct nv50_software_cclass
-nv50_software_cclass = {
-	.base.handle = NV_ENGCTX(SW, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_software_context_ctor,
-		.dtor = nv50_software_context_dtor,
-		.init = _nouveau_software_context_init,
-		.fini = _nouveau_software_context_fini,
-	},
-	.vblank = nv50_software_vblsem_release,
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-int
-nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 size,
-		   struct nouveau_object **pobject)
-{
-	struct nv50_software_oclass *pclass = (void *)oclass;
-	struct nv50_software_priv *priv;
-	int ret;
-
-	ret = nouveau_software_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_engine(priv)->cclass = pclass->cclass;
-	nv_engine(priv)->sclass = pclass->sclass;
-	nv_subdev(priv)->intr = nv04_software_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_software_oclass = &(struct nv50_software_oclass) {
-	.base.handle = NV_ENGINE(SW, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_software_ctor,
-		.dtor = _nouveau_software_dtor,
-		.init = _nouveau_software_init,
-		.fini = _nouveau_software_fini,
-	},
-	.cclass = &nv50_software_cclass.base,
-	.sclass =  nv50_software_sclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
deleted file mode 100644
index 41542e7..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __NVKM_SW_NV50_H__
-#define __NVKM_SW_NV50_H__
-
-#include <engine/software.h>
-
-struct nv50_software_oclass {
-	struct nouveau_oclass base;
-	struct nouveau_oclass *cclass;
-	struct nouveau_oclass *sclass;
-};
-
-struct nv50_software_priv {
-	struct nouveau_software base;
-};
-
-int  nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-
-struct nv50_software_cclass {
-	struct nouveau_oclass base;
-	int (*vblank)(struct nvkm_notify *);
-};
-
-struct nv50_software_chan {
-	struct nouveau_software_chan base;
-	struct {
-		struct nvkm_notify notify[4];
-		u32 channel;
-		u32 ctxdma;
-		u64 offset;
-		u32 value;
-	} vblank;
-};
-
-int  nv50_software_context_ctor(struct nouveau_object *,
-				struct nouveau_object *,
-				struct nouveau_oclass *, void *, u32,
-				struct nouveau_object **);
-void nv50_software_context_dtor(struct nouveau_object *);
-
-int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32);
-int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32);
-int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
deleted file mode 100644
index 6af370d..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/event.h>
-
-#include <subdev/bar.h>
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
-				 void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	u64 data = *(u32 *)args;
-	if (mthd == 0x0400) {
-		chan->vblank.offset &= 0x00ffffffffULL;
-		chan->vblank.offset |= data << 32;
-	} else {
-		chan->vblank.offset &= 0xff00000000ULL;
-		chan->vblank.offset |= data;
-	}
-	return 0;
-}
-
-static int
-nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
-                              void *args, u32 size)
-{
-	struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
-	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
-	u32 data = *(u32 *)args;
-
-	switch (mthd) {
-	case 0x600:
-		nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */
-		break;
-	case 0x644:
-		if (data & ~0x1ffffe)
-			return -EINVAL;
-		nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */
-		break;
-	case 0x6ac:
-		nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static struct nouveau_omthds
-nvc0_software_omthds[] = {
-	{ 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
-	{ 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
-	{ 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
-	{ 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
-	{ 0x0500, 0x0500, nv50_software_mthd_flip },
-	{ 0x0600, 0x0600, nvc0_software_mthd_mp_control },
-	{ 0x0644, 0x0644, nvc0_software_mthd_mp_control },
-	{ 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
-	{}
-};
-
-static struct nouveau_oclass
-nvc0_software_sclass[] = {
-	{ 0x906e, &nouveau_object_ofuncs, nvc0_software_omthds },
-	{}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nvc0_software_vblsem_release(struct nvkm_notify *notify)
-{
-	struct nv50_software_chan *chan =
-		container_of(notify, typeof(*chan), vblank.notify[notify->index]);
-	struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
-	struct nouveau_bar *bar = nouveau_bar(priv);
-
-	nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
-	bar->flush(bar);
-	nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
-	nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
-	nv_wr32(priv, 0x060014, chan->vblank.value);
-
-	return NVKM_NOTIFY_DROP;
-}
-
-static struct nv50_software_cclass
-nvc0_software_cclass = {
-	.base.handle = NV_ENGCTX(SW, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_software_context_ctor,
-		.dtor = nv50_software_context_dtor,
-		.init = _nouveau_software_context_init,
-		.fini = _nouveau_software_context_fini,
-	},
-	.vblank = nvc0_software_vblsem_release,
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc0_software_oclass = &(struct nv50_software_oclass) {
-	.base.handle = NV_ENGINE(SW, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_software_ctor,
-		.dtor = _nouveau_software_dtor,
-		.init = _nouveau_software_init,
-		.fini = _nouveau_software_fini,
-	},
-	.cclass = &nvc0_software_cclass.base,
-	.sclass =  nvc0_software_sclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
deleted file mode 100644
index fd6272b..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs, Ilia Mirkin
- */
-
-#include <engine/xtensa.h>
-#include <engine/vp.h>
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_vp_sclass[] = {
-	{ 0x7476, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_vp_cclass = {
-	.handle = NV_ENGCTX(VP, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_xtensa_engctx_ctor,
-		.dtor = _nouveau_engctx_dtor,
-		.init = _nouveau_engctx_init,
-		.fini = _nouveau_engctx_fini,
-		.rd32 = _nouveau_engctx_rd32,
-		.wr32 = _nouveau_engctx_wr32,
-	},
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nouveau_xtensa *priv;
-	int ret;
-
-	ret = nouveau_xtensa_create(parent, engine, oclass, 0xf000, true,
-				    "PVP", "vp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x01020000;
-	nv_engine(priv)->cclass = &nv84_vp_cclass;
-	nv_engine(priv)->sclass = nv84_vp_sclass;
-	priv->fifo_val = 0x111;
-	priv->unkd28 = 0x9c544;
-	return 0;
-}
-
-struct nouveau_oclass
-nv84_vp_oclass = {
-	.handle = NV_ENGINE(VP, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_vp_ctor,
-		.dtor = _nouveau_xtensa_dtor,
-		.init = _nouveau_xtensa_init,
-		.fini = _nouveau_xtensa_fini,
-		.rd32 = _nouveau_xtensa_rd32,
-		.wr32 = _nouveau_xtensa_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
deleted file mode 100644
index fc9ae0f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nv98_vp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_vp_sclass[] = {
-	{ 0x88b2, &nouveau_object_ofuncs },
-	{ 0x85b2, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_vp_cclass = {
-	.handle = NV_ENGCTX(VP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_vp_init(struct nouveau_object *object)
-{
-	struct nv98_vp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x085010, 0x0000ffd2);
-	nv_wr32(priv, 0x08501c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nv98_vp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
-				    "PVP", "vp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x01020000;
-	nv_engine(priv)->cclass = &nv98_vp_cclass;
-	nv_engine(priv)->sclass = nv98_vp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nv98_vp_oclass = {
-	.handle = NV_ENGINE(VP, 0x98),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv98_vp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nv98_vp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
deleted file mode 100644
index ac1f62a..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * 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.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nvc0_vp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_sclass[] = {
-	{ 0x90b2, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_cclass = {
-	.handle = NV_ENGCTX(VP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_vp_init(struct nouveau_object *object)
-{
-	struct nvc0_vp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x085010, 0x0000fff2);
-	nv_wr32(priv, 0x08501c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nvc0_vp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
-				    "PVP", "vp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00020000;
-	nv_subdev(priv)->intr = nouveau_falcon_intr;
-	nv_engine(priv)->cclass = &nvc0_vp_cclass;
-	nv_engine(priv)->sclass = nvc0_vp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_vp_oclass = {
-	.handle = NV_ENGINE(VP, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_vp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nvc0_vp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
deleted file mode 100644
index d4c3108..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nve0_vp_priv {
-	struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_sclass[] = {
-	{ 0x95b2, &nouveau_object_ofuncs },
-	{},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_cclass = {
-	.handle = NV_ENGCTX(VP, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_falcon_context_ctor,
-		.dtor = _nouveau_falcon_context_dtor,
-		.init = _nouveau_falcon_context_init,
-		.fini = _nouveau_falcon_context_fini,
-		.rd32 = _nouveau_falcon_context_rd32,
-		.wr32 = _nouveau_falcon_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_vp_init(struct nouveau_object *object)
-{
-	struct nve0_vp_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_falcon_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x085010, 0x0000fff2);
-	nv_wr32(priv, 0x08501c, 0x0000fff2);
-	return 0;
-}
-
-static int
-nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nve0_vp_priv *priv;
-	int ret;
-
-	ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
-				    "PVP", "vp", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x00020000;
-	nv_subdev(priv)->intr = nouveau_falcon_intr;
-	nv_engine(priv)->cclass = &nve0_vp_cclass;
-	nv_engine(priv)->sclass = nve0_vp_sclass;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_vp_oclass = {
-	.handle = NV_ENGINE(VP, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_vp_ctor,
-		.dtor = _nouveau_falcon_dtor,
-		.init = nve0_vp_init,
-		.fini = _nouveau_falcon_fini,
-		.rd32 = _nouveau_falcon_rd32,
-		.wr32 = _nouveau_falcon_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
deleted file mode 100644
index 9238475..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2013 Ilia Mirkin
- *
- * 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 <engine/xtensa.h>
-
-u32
-_nouveau_xtensa_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_xtensa *xtensa = (void *)object;
-	return nv_rd32(xtensa, xtensa->addr + addr);
-}
-
-void
-_nouveau_xtensa_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_xtensa *xtensa = (void *)object;
-	nv_wr32(xtensa, xtensa->addr + addr, data);
-}
-
-int
-_nouveau_xtensa_engctx_ctor(struct nouveau_object *parent,
-			    struct nouveau_object *engine,
-			    struct nouveau_oclass *oclass, void *data, u32 size,
-			    struct nouveau_object **pobject)
-{
-	struct nouveau_engctx *engctx;
-	int ret;
-
-	ret = nouveau_engctx_create(parent, engine, oclass, NULL,
-				    0x10000, 0x1000,
-				    NVOBJ_FLAG_ZERO_ALLOC, &engctx);
-	*pobject = nv_object(engctx);
-	return ret;
-}
-
-void
-_nouveau_xtensa_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_xtensa *xtensa = (void *)subdev;
-	u32 unk104 = nv_ro32(xtensa, 0xd04);
-	u32 intr = nv_ro32(xtensa, 0xc20);
-	u32 chan = nv_ro32(xtensa, 0xc28);
-	u32 unk10c = nv_ro32(xtensa, 0xd0c);
-
-	if (intr & 0x10)
-		nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
-	nv_wo32(xtensa, 0xc20, intr);
-	intr = nv_ro32(xtensa, 0xc20);
-	if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
-		nv_debug(xtensa, "Enabling FIFO_CTRL\n");
-		nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
-	}
-}
-
-int
-nouveau_xtensa_create_(struct nouveau_object *parent,
-		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 addr, bool enable,
-		       const char *iname, const char *fname,
-		       int length, void **pobject)
-{
-	struct nouveau_xtensa *xtensa;
-	int ret;
-
-	ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
-				     fname, length, pobject);
-	xtensa = *pobject;
-	if (ret)
-		return ret;
-
-	nv_subdev(xtensa)->intr = _nouveau_xtensa_intr;
-
-	xtensa->addr = addr;
-
-	return 0;
-}
-
-int
-_nouveau_xtensa_init(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nouveau_xtensa *xtensa = (void *)object;
-	const struct firmware *fw;
-	char name[32];
-	int i, ret;
-	u32 tmp;
-
-	ret = nouveau_engine_init(&xtensa->base);
-	if (ret)
-		return ret;
-
-	if (!xtensa->gpu_fw) {
-		snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
-			 xtensa->addr >> 12);
-
-		ret = request_firmware(&fw, name, nv_device_base(device));
-		if (ret) {
-			nv_warn(xtensa, "unable to load firmware %s\n", name);
-			return ret;
-		}
-
-		if (fw->size > 0x40000) {
-			nv_warn(xtensa, "firmware %s too large\n", name);
-			release_firmware(fw);
-			return -EINVAL;
-		}
-
-		ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
-					 &xtensa->gpu_fw);
-		if (ret) {
-			release_firmware(fw);
-			return ret;
-		}
-
-		nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
-			 xtensa->gpu_fw->addr);
-
-		for (i = 0; i < fw->size / 4; i++)
-			nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
-		release_firmware(fw);
-	}
-
-	nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
-	nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
-
-	nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
-	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
-	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
-
-	nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
-	nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
-	nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
-
-	tmp = nv_rd32(xtensa, 0x0);
-	nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
-
-	nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
-
-	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
-	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
-
-	return 0;
-}
-
-int
-_nouveau_xtensa_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_xtensa *xtensa = (void *)object;
-
-	nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
-	nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
-
-	if (!suspend)
-		nouveau_gpuobj_ref(NULL, &xtensa->gpu_fw);
-
-	return nouveau_engine_fini(&xtensa->base, suspend);
-}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h
deleted file mode 100644
index b0ce9f6..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/client.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __NOUVEAU_CLIENT_H__
-#define __NOUVEAU_CLIENT_H__
-
-#include <core/namedb.h>
-
-struct nouveau_client {
-	struct nouveau_namedb base;
-	struct nouveau_handle *root;
-	struct nouveau_object *device;
-	char name[32];
-	u32 debug;
-	struct nouveau_vm *vm;
-	bool super;
-	void *data;
-
-	int (*ntfy)(const void *, u32, const void *, u32);
-	struct nvkm_client_notify *notify[16];
-};
-
-static inline struct nouveau_client *
-nv_client(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS)))
-		nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-static inline struct nouveau_client *
-nouveau_client(void *obj)
-{
-	struct nouveau_object *client = nv_object(obj);
-	while (client && !(nv_iclass(client, NV_CLIENT_CLASS)))
-		client = client->parent;
-	return (void *)client;
-}
-
-#define nouveau_client_create(n,c,oc,od,d)                                     \
-	nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)
-
-int  nouveau_client_create_(const char *name, u64 device, const char *cfg,
-			    const char *dbg, int, void **);
-#define nouveau_client_destroy(p)                                              \
-	nouveau_namedb_destroy(&(p)->base)
-
-int  nouveau_client_init(struct nouveau_client *);
-int  nouveau_client_fini(struct nouveau_client *, bool suspend);
-const char *nouveau_client_name(void *obj);
-
-int nvkm_client_notify_new(struct nouveau_object *, struct nvkm_event *,
-			   void *data, u32 size);
-int nvkm_client_notify_del(struct nouveau_client *, int index);
-int nvkm_client_notify_get(struct nouveau_client *, int index);
-int nvkm_client_notify_put(struct nouveau_client *, int index);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/debug.h b/drivers/gpu/drm/nouveau/core/include/core/debug.h
deleted file mode 100644
index 8092e2e..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/debug.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NOUVEAU_DEBUG_H__
-#define __NOUVEAU_DEBUG_H__
-
-extern int nv_info_debug_level;
-
-#define NV_DBG_FATAL    0
-#define NV_DBG_ERROR    1
-#define NV_DBG_WARN     2
-#define NV_DBG_INFO     nv_info_debug_level
-#define NV_DBG_DEBUG    4
-#define NV_DBG_TRACE    5
-#define NV_DBG_PARANOIA 6
-#define NV_DBG_SPAM     7
-
-#define NV_DBG_INFO_NORMAL 3
-#define NV_DBG_INFO_SILENT NV_DBG_DEBUG
-
-#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
deleted file mode 100644
index 2ec2e50..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef __NOUVEAU_DEVICE_H__
-#define __NOUVEAU_DEVICE_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/engine.h>
-#include <core/event.h>
-
-enum nv_subdev_type {
-	NVDEV_ENGINE_DEVICE,
-	NVDEV_SUBDEV_VBIOS,
-
-	/* All subdevs from DEVINIT to DEVINIT_LAST will be created before
-	 * *any* of them are initialised.  This subdev category is used
-	 * for any subdevs that the VBIOS init table parsing may call out
-	 * to during POST.
-	 */
-	NVDEV_SUBDEV_DEVINIT,
-	NVDEV_SUBDEV_IBUS,
-	NVDEV_SUBDEV_GPIO,
-	NVDEV_SUBDEV_I2C,
-	NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
-
-	/* This grouping of subdevs are initialised right after they've
-	 * been created, and are allowed to assume any subdevs in the
-	 * list above them exist and have been initialised.
-	 */
-	NVDEV_SUBDEV_FUSE,
-	NVDEV_SUBDEV_MXM,
-	NVDEV_SUBDEV_MC,
-	NVDEV_SUBDEV_BUS,
-	NVDEV_SUBDEV_TIMER,
-	NVDEV_SUBDEV_FB,
-	NVDEV_SUBDEV_LTC,
-	NVDEV_SUBDEV_INSTMEM,
-	NVDEV_SUBDEV_VM,
-	NVDEV_SUBDEV_BAR,
-	NVDEV_SUBDEV_PWR,
-	NVDEV_SUBDEV_VOLT,
-	NVDEV_SUBDEV_THERM,
-	NVDEV_SUBDEV_CLOCK,
-
-	NVDEV_ENGINE_FIRST,
-	NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
-	NVDEV_ENGINE_IFB,
-	NVDEV_ENGINE_FIFO,
-	NVDEV_ENGINE_SW,
-	NVDEV_ENGINE_GR,
-	NVDEV_ENGINE_MPEG,
-	NVDEV_ENGINE_ME,
-	NVDEV_ENGINE_VP,
-	NVDEV_ENGINE_CRYPT,
-	NVDEV_ENGINE_BSP,
-	NVDEV_ENGINE_PPP,
-	NVDEV_ENGINE_COPY0,
-	NVDEV_ENGINE_COPY1,
-	NVDEV_ENGINE_COPY2,
-	NVDEV_ENGINE_VIC,
-	NVDEV_ENGINE_VENC,
-	NVDEV_ENGINE_DISP,
-	NVDEV_ENGINE_PERFMON,
-
-	NVDEV_SUBDEV_NR,
-};
-
-struct nouveau_device {
-	struct nouveau_engine base;
-	struct list_head head;
-
-	struct pci_dev *pdev;
-	struct platform_device *platformdev;
-	u64 handle;
-
-	struct nvkm_event event;
-
-	const char *cfgopt;
-	const char *dbgopt;
-	const char *name;
-	const char *cname;
-	u64 disable_mask;
-
-	enum {
-		NV_04    = 0x04,
-		NV_10    = 0x10,
-		NV_11    = 0x11,
-		NV_20    = 0x20,
-		NV_30    = 0x30,
-		NV_40    = 0x40,
-		NV_50    = 0x50,
-		NV_C0    = 0xc0,
-		NV_E0    = 0xe0,
-		GM100    = 0x110,
-	} card_type;
-	u32 chipset;
-	u8  chiprev;
-	u32 crystal;
-
-	struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR];
-	struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
-
-	struct {
-		struct notifier_block nb;
-	} acpi;
-};
-
-int nouveau_device_list(u64 *name, int size);
-
-static inline struct nouveau_device *
-nv_device(void *obj)
-{
-	struct nouveau_object *object = nv_object(obj);
-	struct nouveau_object *device = object;
-
-	if (device->engine)
-		device = device->engine;
-	if (device->parent)
-		device = device->parent;
-
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(device, NV_SUBDEV_CLASS) ||
-		     (nv_hclass(device) & 0xff) != NVDEV_ENGINE_DEVICE)) {
-		nv_assert("BAD CAST -> NvDevice, 0x%08x 0x%08x",
-			  nv_hclass(object), nv_hclass(device));
-	}
-#endif
-
-	return (void *)device;
-}
-
-static inline struct nouveau_subdev *
-nouveau_subdev(void *obj, int sub)
-{
-	if (nv_device(obj)->subdev[sub])
-		return nv_subdev(nv_device(obj)->subdev[sub]);
-	return NULL;
-}
-
-static inline struct nouveau_engine *
-nouveau_engine(void *obj, int sub)
-{
-	struct nouveau_subdev *subdev = nouveau_subdev(obj, sub);
-	if (subdev && nv_iclass(subdev, NV_ENGINE_CLASS))
-		return nv_engine(subdev);
-	return NULL;
-}
-
-static inline bool
-nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub)
-{
-	struct nouveau_device *device = nv_device(object);
-	return device->pdev->device == dev &&
-	       device->pdev->subsystem_vendor == ven &&
-	       device->pdev->subsystem_device == sub;
-}
-
-static inline bool
-nv_device_is_pci(struct nouveau_device *device)
-{
-	return device->pdev != NULL;
-}
-
-static inline bool
-nv_device_is_cpu_coherent(struct nouveau_device *device)
-{
-	return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
-}
-
-static inline struct device *
-nv_device_base(struct nouveau_device *device)
-{
-	return nv_device_is_pci(device) ? &device->pdev->dev :
-					  &device->platformdev->dev;
-}
-
-resource_size_t
-nv_device_resource_start(struct nouveau_device *device, unsigned int bar);
-
-resource_size_t
-nv_device_resource_len(struct nouveau_device *device, unsigned int bar);
-
-int
-nv_device_get_irq(struct nouveau_device *device, bool stall);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/engctx.h b/drivers/gpu/drm/nouveau/core/include/core/engctx.h
deleted file mode 100644
index 2fd48b5..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/engctx.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef __NOUVEAU_ENGCTX_H__
-#define __NOUVEAU_ENGCTX_H__
-
-#include <core/object.h>
-#include <core/gpuobj.h>
-
-#include <subdev/vm.h>
-
-#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng))
-#define NV_ENGCTX(name,var)  NV_ENGCTX_(NVDEV_ENGINE_##name, (var))
-
-struct nouveau_engctx {
-	struct nouveau_gpuobj base;
-	struct nouveau_vma vma;
-	struct list_head head;
-	unsigned long save;
-	u64 addr;
-};
-
-static inline struct nouveau_engctx *
-nv_engctx(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS)))
-		nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-#define nouveau_engctx_create(p,e,c,g,s,a,f,d)                                 \
-	nouveau_engctx_create_((p), (e), (c), (g), (s), (a), (f),              \
-			       sizeof(**d), (void **)d)
-
-int  nouveau_engctx_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, struct nouveau_object *,
-			    u32 size, u32 align, u32 flags,
-			    int length, void **data);
-void nouveau_engctx_destroy(struct nouveau_engctx *);
-int  nouveau_engctx_init(struct nouveau_engctx *);
-int  nouveau_engctx_fini(struct nouveau_engctx *, bool suspend);
-
-int  _nouveau_engctx_ctor(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, void *, u32,
-			  struct nouveau_object **);
-void _nouveau_engctx_dtor(struct nouveau_object *);
-int  _nouveau_engctx_init(struct nouveau_object *);
-int  _nouveau_engctx_fini(struct nouveau_object *, bool suspend);
-#define _nouveau_engctx_rd32 _nouveau_gpuobj_rd32
-#define _nouveau_engctx_wr32 _nouveau_gpuobj_wr32
-
-struct nouveau_object *nouveau_engctx_get(struct nouveau_engine *, u64 addr);
-void nouveau_engctx_put(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/engine.h b/drivers/gpu/drm/nouveau/core/include/core/engine.h
deleted file mode 100644
index 666d06d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/engine.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __NOUVEAU_ENGINE_H__
-#define __NOUVEAU_ENGINE_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-
-#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng))
-#define NV_ENGINE(name,var)  NV_ENGINE_(NVDEV_ENGINE_##name, (var))
-
-struct nouveau_engine {
-	struct nouveau_subdev base;
-	struct nouveau_oclass *cclass;
-	struct nouveau_oclass *sclass;
-
-	struct list_head contexts;
-	spinlock_t lock;
-
-	void (*tile_prog)(struct nouveau_engine *, int region);
-	int  (*tlb_flush)(struct nouveau_engine *);
-};
-
-static inline struct nouveau_engine *
-nv_engine(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS)))
-		nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-static inline int
-nv_engidx(struct nouveau_object *object)
-{
-	return nv_subidx(object);
-}
-
-#define nouveau_engine_create(p,e,c,d,i,f,r)                                   \
-	nouveau_engine_create_((p), (e), (c), (d), (i), (f),                   \
-			       sizeof(**r),(void **)r)
-
-#define nouveau_engine_destroy(p)                                              \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_engine_init(p)                                                 \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_engine_fini(p,s)                                               \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_engine_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *, bool, const char *,
-			   const char *, int, void **);
-
-#define _nouveau_engine_dtor _nouveau_subdev_dtor
-#define _nouveau_engine_init _nouveau_subdev_init
-#define _nouveau_engine_fini _nouveau_subdev_fini
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/enum.h b/drivers/gpu/drm/nouveau/core/include/core/enum.h
deleted file mode 100644
index 4fc62bb..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/enum.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __NOUVEAU_ENUM_H__
-#define __NOUVEAU_ENUM_H__
-
-struct nouveau_enum {
-	u32 value;
-	const char *name;
-	const void *data;
-	u32 data2;
-};
-
-const struct nouveau_enum *
-nouveau_enum_find(const struct nouveau_enum *, u32 value);
-
-const struct nouveau_enum *
-nouveau_enum_print(const struct nouveau_enum *en, u32 value);
-
-struct nouveau_bitfield {
-	u32 mask;
-	const char *name;
-};
-
-void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h
deleted file mode 100644
index 9287652..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/event.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NVKM_EVENT_H__
-#define __NVKM_EVENT_H__
-
-#include <core/notify.h>
-
-struct nvkm_event_func {
-	int  (*ctor)(struct nouveau_object *, void *data, u32 size,
-		     struct nvkm_notify *);
-	void (*send)(void *data, u32 size, struct nvkm_notify *);
-	void (*init)(struct nvkm_event *, int type, int index);
-	void (*fini)(struct nvkm_event *, int type, int index);
-};
-
-struct nvkm_event {
-	const struct nvkm_event_func *func;
-
-	int types_nr;
-	int index_nr;
-
-	spinlock_t refs_lock;
-	spinlock_t list_lock;
-	struct list_head list;
-	int *refs;
-};
-
-int  nvkm_event_init(const struct nvkm_event_func *func,
-		     int types_nr, int index_nr,
-		     struct nvkm_event *);
-void nvkm_event_fini(struct nvkm_event *);
-void nvkm_event_get(struct nvkm_event *, u32 types, int index);
-void nvkm_event_put(struct nvkm_event *, u32 types, int index);
-void nvkm_event_send(struct nvkm_event *, u32 types, int index,
-		     void *data, u32 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h b/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
deleted file mode 100644
index b3b9ce4..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __NOUVEAU_GPUOBJ_H__
-#define __NOUVEAU_GPUOBJ_H__
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/parent.h>
-#include <core/mm.h>
-
-struct nouveau_vma;
-struct nouveau_vm;
-
-#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001
-#define NVOBJ_FLAG_ZERO_FREE  0x00000002
-#define NVOBJ_FLAG_HEAP       0x00000004
-
-struct nouveau_gpuobj {
-	struct nouveau_object base;
-	struct nouveau_object *parent;
-	struct nouveau_mm_node *node;
-	struct nouveau_mm heap;
-
-	u32 flags;
-	u64 addr;
-	u32 size;
-};
-
-static inline struct nouveau_gpuobj *
-nv_gpuobj(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS)))
-		nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-#define nouveau_gpuobj_create(p,e,c,v,g,s,a,f,d)                               \
-	nouveau_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f),         \
-			       sizeof(**d), (void **)d)
-#define nouveau_gpuobj_init(p) nouveau_object_init(&(p)->base)
-#define nouveau_gpuobj_fini(p,s) nouveau_object_fini(&(p)->base, (s))
-int  nouveau_gpuobj_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, u32 pclass,
-			    struct nouveau_object *, u32 size, u32 align,
-			    u32 flags, int length, void **);
-void nouveau_gpuobj_destroy(struct nouveau_gpuobj *);
-
-int nouveau_gpuobj_new(struct nouveau_object *, struct nouveau_object *,
-		       u32 size, u32 align, u32 flags,
-		       struct nouveau_gpuobj **);
-int nouveau_gpuobj_dup(struct nouveau_object *, struct nouveau_gpuobj *,
-		       struct nouveau_gpuobj **);
-
-int nouveau_gpuobj_map(struct nouveau_gpuobj *, u32 acc, struct nouveau_vma *);
-int nouveau_gpuobj_map_vm(struct nouveau_gpuobj *, struct nouveau_vm *,
-			  u32 access, struct nouveau_vma *);
-void nouveau_gpuobj_unmap(struct nouveau_vma *);
-
-static inline void
-nouveau_gpuobj_ref(struct nouveau_gpuobj *obj, struct nouveau_gpuobj **ref)
-{
-	nouveau_object_ref(&obj->base, (struct nouveau_object **)ref);
-}
-
-void _nouveau_gpuobj_dtor(struct nouveau_object *);
-int  _nouveau_gpuobj_init(struct nouveau_object *);
-int  _nouveau_gpuobj_fini(struct nouveau_object *, bool);
-u32  _nouveau_gpuobj_rd32(struct nouveau_object *, u64);
-void _nouveau_gpuobj_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/handle.h b/drivers/gpu/drm/nouveau/core/include/core/handle.h
deleted file mode 100644
index d22a591..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/handle.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __NOUVEAU_HANDLE_H__
-#define __NOUVEAU_HANDLE_H__
-
-struct nouveau_handle {
-	struct nouveau_namedb *namedb;
-	struct list_head node;
-
-	struct list_head head;
-	struct list_head tree;
-	u32 name;
-	u32 priv;
-
-	u8  route;
-	u64 token;
-
-	struct nouveau_handle *parent;
-	struct nouveau_object *object;
-};
-
-int  nouveau_handle_create(struct nouveau_object *, u32 parent, u32 handle,
-			   struct nouveau_object *, struct nouveau_handle **);
-void nouveau_handle_destroy(struct nouveau_handle *);
-int  nouveau_handle_init(struct nouveau_handle *);
-int  nouveau_handle_fini(struct nouveau_handle *, bool suspend);
-
-struct nouveau_object *
-nouveau_handle_ref(struct nouveau_object *, u32 name);
-
-struct nouveau_handle *nouveau_handle_get_class(struct nouveau_object *, u16);
-struct nouveau_handle *nouveau_handle_get_vinst(struct nouveau_object *, u64);
-struct nouveau_handle *nouveau_handle_get_cinst(struct nouveau_object *, u32);
-void nouveau_handle_put(struct nouveau_handle *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h
deleted file mode 100644
index ac7935c..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __NVKM_IOCTL_H__
-#define __NVKM_IOCTL_H__
-
-int nvkm_ioctl(struct nouveau_client *, bool, void *, u32, void **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h
deleted file mode 100644
index bfe6931..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NOUVEAU_MM_H__
-#define __NOUVEAU_MM_H__
-
-struct nouveau_mm_node {
-	struct list_head nl_entry;
-	struct list_head fl_entry;
-	struct list_head rl_entry;
-
-#define NVKM_MM_HEAP_ANY 0x00
-	u8  heap;
-#define NVKM_MM_TYPE_NONE 0x00
-#define NVKM_MM_TYPE_HOLE 0xff
-	u8  type;
-	u32 offset;
-	u32 length;
-};
-
-struct nouveau_mm {
-	struct list_head nodes;
-	struct list_head free;
-
-	u32 block_size;
-	int heap_nodes;
-};
-
-static inline bool
-nouveau_mm_initialised(struct nouveau_mm *mm)
-{
-	return mm->block_size != 0;
-}
-
-int  nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
-int  nouveau_mm_fini(struct nouveau_mm *);
-int  nouveau_mm_head(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
-		     u32 size_min, u32 align, struct nouveau_mm_node **);
-int  nouveau_mm_tail(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
-		     u32 size_min, u32 align, struct nouveau_mm_node **);
-void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/namedb.h b/drivers/gpu/drm/nouveau/core/include/core/namedb.h
deleted file mode 100644
index f5b5fd8..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/namedb.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NOUVEAU_NAMEDB_H__
-#define __NOUVEAU_NAMEDB_H__
-
-#include <core/parent.h>
-
-struct nouveau_handle;
-
-struct nouveau_namedb {
-	struct nouveau_parent base;
-	rwlock_t lock;
-	struct list_head list;
-};
-
-static inline struct nouveau_namedb *
-nv_namedb(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS)))
-		nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-#define nouveau_namedb_create(p,e,c,v,s,m,d)                                   \
-	nouveau_namedb_create_((p), (e), (c), (v), (s), (m),                   \
-			       sizeof(**d), (void **)d)
-#define nouveau_namedb_init(p)                                                 \
-	nouveau_parent_init(&(p)->base)
-#define nouveau_namedb_fini(p,s)                                               \
-	nouveau_parent_fini(&(p)->base, (s))
-#define nouveau_namedb_destroy(p)                                              \
-	nouveau_parent_destroy(&(p)->base)
-
-int  nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, u32 pclass,
-			    struct nouveau_oclass *, u64 engcls,
-			    int size, void **);
-
-int  _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, void *, u32,
-			  struct nouveau_object **);
-#define _nouveau_namedb_dtor _nouveau_parent_dtor
-#define _nouveau_namedb_init _nouveau_parent_init
-#define _nouveau_namedb_fini _nouveau_parent_fini
-
-int  nouveau_namedb_insert(struct nouveau_namedb *, u32 name,
-			   struct nouveau_object *, struct nouveau_handle *);
-void nouveau_namedb_remove(struct nouveau_handle *);
-
-struct nouveau_handle *nouveau_namedb_get(struct nouveau_namedb *, u32);
-struct nouveau_handle *nouveau_namedb_get_class(struct nouveau_namedb *, u16);
-struct nouveau_handle *nouveau_namedb_get_vinst(struct nouveau_namedb *, u64);
-struct nouveau_handle *nouveau_namedb_get_cinst(struct nouveau_namedb *, u32);
-void nouveau_namedb_put(struct nouveau_handle *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/notify.h b/drivers/gpu/drm/nouveau/core/include/core/notify.h
deleted file mode 100644
index a7c3c5f..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/notify.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NVKM_NOTIFY_H__
-#define __NVKM_NOTIFY_H__
-
-struct nvkm_notify {
-	struct nvkm_event *event;
-	struct list_head head;
-#define NVKM_NOTIFY_USER 0
-#define NVKM_NOTIFY_WORK 1
-	unsigned long flags;
-	int block;
-#define NVKM_NOTIFY_DROP 0
-#define NVKM_NOTIFY_KEEP 1
-	int (*func)(struct nvkm_notify *);
-
-	/* set by nvkm_event ctor */
-	u32 types;
-	int index;
-	u32 size;
-
-	struct work_struct work;
-	/* this is const for a *very* good reason - the data might be on the
-	 * stack from an irq handler.  if you're not core/notify.c then you
-	 * should probably think twice before casting it away...
-	 */
-	const void *data;
-};
-
-int  nvkm_notify_init(struct nouveau_object *, struct nvkm_event *,
-		      int (*func)(struct nvkm_notify *), bool work,
-		      void *data, u32 size, u32 reply,
-		      struct nvkm_notify *);
-void nvkm_notify_fini(struct nvkm_notify *);
-void nvkm_notify_get(struct nvkm_notify *);
-void nvkm_notify_put(struct nvkm_notify *);
-void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h
deleted file mode 100644
index 2e2afa5..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ /dev/null
@@ -1,206 +0,0 @@
-#ifndef __NOUVEAU_OBJECT_H__
-#define __NOUVEAU_OBJECT_H__
-
-#include <core/os.h>
-#include <core/printk.h>
-
-#define NV_PARENT_CLASS 0x80000000
-#define NV_NAMEDB_CLASS 0x40000000
-#define NV_CLIENT_CLASS 0x20000000
-#define NV_SUBDEV_CLASS 0x10000000
-#define NV_ENGINE_CLASS 0x08000000
-#define NV_MEMOBJ_CLASS 0x04000000
-#define NV_GPUOBJ_CLASS 0x02000000
-#define NV_ENGCTX_CLASS 0x01000000
-#define NV_OBJECT_CLASS 0x0000ffff
-
-struct nouveau_object {
-	struct nouveau_oclass *oclass;
-	struct nouveau_object *parent;
-	struct nouveau_object *engine;
-	atomic_t refcount;
-	atomic_t usecount;
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-#define NOUVEAU_OBJECT_MAGIC 0x75ef0bad
-	struct list_head list;
-	u32 _magic;
-#endif
-};
-
-static inline struct nouveau_object *
-nv_object(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (likely(obj)) {
-		struct nouveau_object *object = obj;
-		if (unlikely(object->_magic != NOUVEAU_OBJECT_MAGIC))
-			nv_assert("BAD CAST -> NvObject, invalid magic");
-	}
-#endif
-	return obj;
-}
-
-#define nouveau_object_create(p,e,c,s,d)                                       \
-	nouveau_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d)
-int  nouveau_object_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, u32, int size, void **);
-void nouveau_object_destroy(struct nouveau_object *);
-int  nouveau_object_init(struct nouveau_object *);
-int  nouveau_object_fini(struct nouveau_object *, bool suspend);
-
-int _nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, void *, u32,
-			 struct nouveau_object **);
-
-extern struct nouveau_ofuncs nouveau_object_ofuncs;
-
-/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
- * ".data". */
-struct nouveau_oclass {
-	u32 handle;
-	struct nouveau_ofuncs * const ofuncs;
-	struct nouveau_omthds * const omthds;
-	struct lock_class_key lock_class_key;
-};
-
-#define nv_oclass(o)    nv_object(o)->oclass
-#define nv_hclass(o)    nv_oclass(o)->handle
-#define nv_iclass(o,i) (nv_hclass(o) & (i))
-#define nv_mclass(o)    nv_iclass(o, NV_OBJECT_CLASS)
-
-static inline struct nouveau_object *
-nv_pclass(struct nouveau_object *parent, u32 oclass)
-{
-	while (parent && !nv_iclass(parent, oclass))
-		parent = parent->parent;
-	return parent;
-}
-
-struct nouveau_omthds {
-	u32 start;
-	u32 limit;
-	int (*call)(struct nouveau_object *, u32, void *, u32);
-};
-
-struct nvkm_event;
-struct nouveau_ofuncs {
-	int  (*ctor)(struct nouveau_object *, struct nouveau_object *,
-		     struct nouveau_oclass *, void *data, u32 size,
-		     struct nouveau_object **);
-	void (*dtor)(struct nouveau_object *);
-	int  (*init)(struct nouveau_object *);
-	int  (*fini)(struct nouveau_object *, bool suspend);
-	int  (*mthd)(struct nouveau_object *, u32, void *, u32);
-	int  (*ntfy)(struct nouveau_object *, u32, struct nvkm_event **);
-	int  (* map)(struct nouveau_object *, u64 *, u32 *);
-	u8   (*rd08)(struct nouveau_object *, u64 offset);
-	u16  (*rd16)(struct nouveau_object *, u64 offset);
-	u32  (*rd32)(struct nouveau_object *, u64 offset);
-	void (*wr08)(struct nouveau_object *, u64 offset, u8 data);
-	void (*wr16)(struct nouveau_object *, u64 offset, u16 data);
-	void (*wr32)(struct nouveau_object *, u64 offset, u32 data);
-};
-
-static inline struct nouveau_ofuncs *
-nv_ofuncs(void *obj)
-{
-	return nv_oclass(obj)->ofuncs;
-}
-
-int  nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, void *, u32,
-			 struct nouveau_object **);
-void nouveau_object_ref(struct nouveau_object *, struct nouveau_object **);
-int nouveau_object_inc(struct nouveau_object *);
-int nouveau_object_dec(struct nouveau_object *, bool suspend);
-
-void nouveau_object_debug(void);
-
-static inline int
-nv_exec(void *obj, u32 mthd, void *data, u32 size)
-{
-	struct nouveau_omthds *method = nv_oclass(obj)->omthds;
-
-	while (method && method->call) {
-		if (mthd >= method->start && mthd <= method->limit)
-			return method->call(obj, mthd, data, size);
-		method++;
-	}
-
-	return -EINVAL;
-}
-
-static inline int
-nv_call(void *obj, u32 mthd, u32 data)
-{
-	return nv_exec(obj, mthd, &data, sizeof(data));
-}
-
-static inline u8
-nv_ro08(void *obj, u64 addr)
-{
-	u8 data = nv_ofuncs(obj)->rd08(obj, addr);
-	nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data);
-	return data;
-}
-
-static inline u16
-nv_ro16(void *obj, u64 addr)
-{
-	u16 data = nv_ofuncs(obj)->rd16(obj, addr);
-	nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data);
-	return data;
-}
-
-static inline u32
-nv_ro32(void *obj, u64 addr)
-{
-	u32 data = nv_ofuncs(obj)->rd32(obj, addr);
-	nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data);
-	return data;
-}
-
-static inline void
-nv_wo08(void *obj, u64 addr, u8 data)
-{
-	nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data);
-	nv_ofuncs(obj)->wr08(obj, addr, data);
-}
-
-static inline void
-nv_wo16(void *obj, u64 addr, u16 data)
-{
-	nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data);
-	nv_ofuncs(obj)->wr16(obj, addr, data);
-}
-
-static inline void
-nv_wo32(void *obj, u64 addr, u32 data)
-{
-	nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data);
-	nv_ofuncs(obj)->wr32(obj, addr, data);
-}
-
-static inline u32
-nv_mo32(void *obj, u64 addr, u32 mask, u32 data)
-{
-	u32 temp = nv_ro32(obj, addr);
-	nv_wo32(obj, addr, (temp & ~mask) | data);
-	return temp;
-}
-
-static inline int
-nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
-{
-	unsigned char c1, c2;
-
-	while (len--) {
-		c1 = nv_ro08(obj, addr++);
-		c2 = *(str++);
-		if (c1 != c2)
-			return c1 - c2;
-	}
-	return 0;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/option.h b/drivers/gpu/drm/nouveau/core/include/core/option.h
deleted file mode 100644
index ed05584..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/option.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NOUVEAU_OPTION_H__
-#define __NOUVEAU_OPTION_H__
-
-#include <core/os.h>
-
-const char *nouveau_stropt(const char *optstr, const char *opt, int *len);
-bool nouveau_boolopt(const char *optstr, const char *opt, bool value);
-
-int nouveau_dbgopt(const char *optstr, const char *sub);
-
-/* compares unterminated string 'str' with zero-terminated string 'cmp' */
-static inline int
-strncasecmpz(const char *str, const char *cmp, size_t len)
-{
-	if (strlen(cmp) != len)
-		return len;
-	return strncasecmp(str, cmp, len);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h
deleted file mode 100644
index 12da418..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/parent.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NOUVEAU_PARENT_H__
-#define __NOUVEAU_PARENT_H__
-
-#include <core/device.h>
-#include <core/object.h>
-
-struct nouveau_sclass {
-	struct nouveau_sclass *sclass;
-	struct nouveau_engine *engine;
-	struct nouveau_oclass *oclass;
-};
-
-struct nouveau_parent {
-	struct nouveau_object base;
-
-	struct nouveau_sclass *sclass;
-	u64 engine;
-
-	int  (*context_attach)(struct nouveau_object *,
-			       struct nouveau_object *);
-	int  (*context_detach)(struct nouveau_object *, bool suspend,
-			       struct nouveau_object *);
-
-	int  (*object_attach)(struct nouveau_object *parent,
-			      struct nouveau_object *object, u32 name);
-	void (*object_detach)(struct nouveau_object *parent, int cookie);
-};
-
-static inline struct nouveau_parent *
-nv_parent(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS))))
-		nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-#define nouveau_parent_create(p,e,c,v,s,m,d)                                   \
-	nouveau_parent_create_((p), (e), (c), (v), (s), (m),                   \
-			       sizeof(**d), (void **)d)
-#define nouveau_parent_init(p)                                                 \
-	nouveau_object_init(&(p)->base)
-#define nouveau_parent_fini(p,s)                                               \
-	nouveau_object_fini(&(p)->base, (s))
-
-int  nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, u32 pclass,
-			    struct nouveau_oclass *, u64 engcls,
-			    int size, void **);
-void nouveau_parent_destroy(struct nouveau_parent *);
-
-void _nouveau_parent_dtor(struct nouveau_object *);
-#define _nouveau_parent_init nouveau_object_init
-#define _nouveau_parent_fini nouveau_object_fini
-
-int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
-			  struct nouveau_object **pengine,
-			  struct nouveau_oclass **poclass);
-int nouveau_parent_lclass(struct nouveau_object *, u32 *, int);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h
deleted file mode 100644
index 451b6ed..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/printk.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NOUVEAU_PRINTK_H__
-#define __NOUVEAU_PRINTK_H__
-
-#include <core/os.h>
-#include <core/debug.h>
-
-struct nouveau_object;
-
-void __printf(3, 4)
-nv_printk_(struct nouveau_object *, int, const char *, ...);
-
-#define nv_printk(o,l,f,a...) do {                                             \
-	if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG)                                \
-		nv_printk_(nv_object(o), NV_DBG_##l, f, ##a);                  \
-} while(0)
-
-#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
-#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a)
-#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a)
-#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a)
-#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
-#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
-#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
-#define nv_ioctl(o,f,a...) nv_trace(nouveau_client(o), "ioctl: "f, ##a)
-
-#define nv_assert(f,a...) do {                                                 \
-	if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG)                              \
-		nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a);                   \
-	BUG_ON(1);                                                             \
-} while(0)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ramht.h b/drivers/gpu/drm/nouveau/core/include/core/ramht.h
deleted file mode 100644
index 47e4cac..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/ramht.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NOUVEAU_RAMHT_H__
-#define __NOUVEAU_RAMHT_H__
-
-#include <core/gpuobj.h>
-
-struct nouveau_ramht {
-	struct nouveau_gpuobj base;
-	int bits;
-};
-
-int  nouveau_ramht_insert(struct nouveau_ramht *, int chid,
-			  u32 handle, u32 context);
-void nouveau_ramht_remove(struct nouveau_ramht *, int cookie);
-int  nouveau_ramht_new(struct nouveau_object *, struct nouveau_object *,
-		       u32 size, u32 align, struct nouveau_ramht **);
-
-static inline void
-nouveau_ramht_ref(struct nouveau_ramht *obj, struct nouveau_ramht **ref)
-{
-	nouveau_gpuobj_ref(&obj->base, (struct nouveau_gpuobj **)ref);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/subdev.h b/drivers/gpu/drm/nouveau/core/include/core/subdev.h
deleted file mode 100644
index e9632e9..0000000
--- a/drivers/gpu/drm/nouveau/core/include/core/subdev.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef __NOUVEAU_SUBDEV_H__
-#define __NOUVEAU_SUBDEV_H__
-
-#include <core/object.h>
-
-#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub))
-#define NV_SUBDEV(name,var)  NV_SUBDEV_(NVDEV_SUBDEV_##name, (var))
-
-struct nouveau_subdev {
-	struct nouveau_object base;
-	struct mutex mutex;
-	const char *name;
-	void __iomem *mmio;
-	u32 debug;
-	u32 unit;
-
-	void (*intr)(struct nouveau_subdev *);
-};
-
-static inline struct nouveau_subdev *
-nv_subdev(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS)))
-		nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-static inline int
-nv_subidx(struct nouveau_object *object)
-{
-	return nv_hclass(nv_subdev(object)) & 0xff;
-}
-
-#define nouveau_subdev_create(p,e,o,v,s,f,d)                                   \
-	nouveau_subdev_create_((p), (e), (o), (v), (s), (f),                   \
-			       sizeof(**d),(void **)d)
-
-int  nouveau_subdev_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, u32 pclass,
-			    const char *sname, const char *fname,
-			    int size, void **);
-void nouveau_subdev_destroy(struct nouveau_subdev *);
-int  nouveau_subdev_init(struct nouveau_subdev *);
-int  nouveau_subdev_fini(struct nouveau_subdev *, bool suspend);
-void nouveau_subdev_reset(struct nouveau_object *);
-
-void _nouveau_subdev_dtor(struct nouveau_object *);
-int  _nouveau_subdev_init(struct nouveau_object *);
-int  _nouveau_subdev_fini(struct nouveau_object *, bool suspend);
-
-#define s_printk(s,l,f,a...) do {                                              \
-	if ((s)->debug >= OS_DBG_##l) {                                        \
-		nv_printk((s)->base.parent, (s)->name, l, f, ##a);             \
-	}                                                                      \
-} while(0)
-
-static inline u8
-nv_rd08(void *obj, u32 addr)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	u8 data = ioread8(subdev->mmio + addr);
-	nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data);
-	return data;
-}
-
-static inline u16
-nv_rd16(void *obj, u32 addr)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	u16 data = ioread16_native(subdev->mmio + addr);
-	nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data);
-	return data;
-}
-
-static inline u32
-nv_rd32(void *obj, u32 addr)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	u32 data = ioread32_native(subdev->mmio + addr);
-	nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data);
-	return data;
-}
-
-static inline void
-nv_wr08(void *obj, u32 addr, u8 data)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data);
-	iowrite8(data, subdev->mmio + addr);
-}
-
-static inline void
-nv_wr16(void *obj, u32 addr, u16 data)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data);
-	iowrite16_native(data, subdev->mmio + addr);
-}
-
-static inline void
-nv_wr32(void *obj, u32 addr, u32 data)
-{
-	struct nouveau_subdev *subdev = nv_subdev(obj);
-	nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data);
-	iowrite32_native(data, subdev->mmio + addr);
-}
-
-static inline u32
-nv_mask(void *obj, u32 addr, u32 mask, u32 data)
-{
-	u32 temp = nv_rd32(obj, addr);
-	nv_wr32(obj, addr, (temp & ~mask) | data);
-	return temp;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
deleted file mode 100644
index 67662e2..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_BSP_H__
-#define __NOUVEAU_BSP_H__
-
-extern struct nouveau_oclass nv84_bsp_oclass;
-extern struct nouveau_oclass nv98_bsp_oclass;
-extern struct nouveau_oclass nvc0_bsp_oclass;
-extern struct nouveau_oclass nve0_bsp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
deleted file mode 100644
index 316a28a..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/copy.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NOUVEAU_COPY_H__
-#define __NOUVEAU_COPY_H__
-
-void nva3_copy_intr(struct nouveau_subdev *);
-
-extern struct nouveau_oclass nva3_copy_oclass;
-extern struct nouveau_oclass nvc0_copy0_oclass;
-extern struct nouveau_oclass nvc0_copy1_oclass;
-extern struct nouveau_oclass nve0_copy0_oclass;
-extern struct nouveau_oclass nve0_copy1_oclass;
-extern struct nouveau_oclass nve0_copy2_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
deleted file mode 100644
index db97561..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NOUVEAU_CRYPT_H__
-#define __NOUVEAU_CRYPT_H__
-
-extern struct nouveau_oclass nv84_crypt_oclass;
-extern struct nouveau_oclass nv98_crypt_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/device.h b/drivers/gpu/drm/nouveau/core/include/engine/device.h
deleted file mode 100644
index 672d3c8..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/device.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NOUVEAU_SUBDEV_DEVICE_H__
-#define __NOUVEAU_SUBDEV_DEVICE_H__
-
-#include <core/device.h>
-
-struct platform_device;
-
-enum nv_bus_type {
-	NOUVEAU_BUS_PCI,
-	NOUVEAU_BUS_PLATFORM,
-};
-
-#define nouveau_device_create(p,t,n,s,c,d,u)                                   \
-	nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
-			       sizeof(**u), (void **)u)
-
-int  nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
-			    const char *sname, const char *cfg, const char *dbg,
-			    int, void **);
-
-int nv04_identify(struct nouveau_device *);
-int nv10_identify(struct nouveau_device *);
-int nv20_identify(struct nouveau_device *);
-int nv30_identify(struct nouveau_device *);
-int nv40_identify(struct nouveau_device *);
-int nv50_identify(struct nouveau_device *);
-int nvc0_identify(struct nouveau_device *);
-int nve0_identify(struct nouveau_device *);
-int gm100_identify(struct nouveau_device *);
-
-struct nouveau_device *nouveau_device_find(u64 name);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
deleted file mode 100644
index fc307f1..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __NOUVEAU_DISP_H__
-#define __NOUVEAU_DISP_H__
-
-#include <core/object.h>
-#include <core/engine.h>
-#include <core/device.h>
-#include <core/event.h>
-
-struct nouveau_disp {
-	struct nouveau_engine base;
-
-	struct list_head outp;
-
-	struct nvkm_event hpd;
-	struct nvkm_event vblank;
-};
-
-static inline struct nouveau_disp *
-nouveau_disp(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
-}
-
-extern struct nouveau_oclass *nv04_disp_oclass;
-extern struct nouveau_oclass *nv50_disp_oclass;
-extern struct nouveau_oclass *nv84_disp_oclass;
-extern struct nouveau_oclass *nva0_disp_oclass;
-extern struct nouveau_oclass *nv94_disp_oclass;
-extern struct nouveau_oclass *nva3_disp_oclass;
-extern struct nouveau_oclass *nvd0_disp_oclass;
-extern struct nouveau_oclass *nve0_disp_oclass;
-extern struct nouveau_oclass *nvf0_disp_oclass;
-extern struct nouveau_oclass *gm107_disp_oclass;
-extern struct nouveau_oclass *gm204_disp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
deleted file mode 100644
index 1b283a7..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NOUVEAU_DMAOBJ_H__
-#define __NOUVEAU_DMAOBJ_H__
-
-#include <core/object.h>
-#include <core/engine.h>
-
-struct nouveau_gpuobj;
-
-struct nouveau_dmaobj {
-	struct nouveau_object base;
-	u32 target;
-	u32 access;
-	u64 start;
-	u64 limit;
-};
-
-struct nouveau_dmaeng {
-	struct nouveau_engine base;
-
-	/* creates a "physical" dma object from a struct nouveau_dmaobj */
-	int (*bind)(struct nouveau_dmaobj *dmaobj,
-		    struct nouveau_object *parent,
-		    struct nouveau_gpuobj **);
-};
-
-extern struct nouveau_oclass *nv04_dmaeng_oclass;
-extern struct nouveau_oclass *nv50_dmaeng_oclass;
-extern struct nouveau_oclass *nvc0_dmaeng_oclass;
-extern struct nouveau_oclass *nvd0_dmaeng_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
deleted file mode 100644
index 181aa7d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __NOUVEAU_FALCON_H__
-#define __NOUVEAU_FALCON_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-struct nouveau_falcon_chan {
-	struct nouveau_engctx base;
-};
-
-#define nouveau_falcon_context_create(p,e,c,g,s,a,f,d)                         \
-	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_falcon_context_destroy(d)                                      \
-	nouveau_engctx_destroy(&(d)->base)
-#define nouveau_falcon_context_init(d)                                         \
-	nouveau_engctx_init(&(d)->base)
-#define nouveau_falcon_context_fini(d,s)                                       \
-	nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_falcon_context_ctor _nouveau_engctx_ctor
-#define _nouveau_falcon_context_dtor _nouveau_engctx_dtor
-#define _nouveau_falcon_context_init _nouveau_engctx_init
-#define _nouveau_falcon_context_fini _nouveau_engctx_fini
-#define _nouveau_falcon_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_falcon_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_falcon_data {
-	bool external;
-};
-
-struct nouveau_falcon {
-	struct nouveau_engine base;
-
-	u32 addr;
-	u8  version;
-	u8  secret;
-
-	struct nouveau_gpuobj *core;
-	bool external;
-
-	struct {
-		u32 limit;
-		u32 *data;
-		u32  size;
-	} code;
-
-	struct {
-		u32 limit;
-		u32 *data;
-		u32  size;
-	} data;
-};
-
-#define nv_falcon(priv) (&(priv)->base)
-
-#define nouveau_falcon_create(p,e,c,b,d,i,f,r)                                 \
-	nouveau_falcon_create_((p), (e), (c), (b), (d), (i), (f),              \
-			       sizeof(**r),(void **)r)
-#define nouveau_falcon_destroy(p)                                              \
-	nouveau_engine_destroy(&(p)->base)
-#define nouveau_falcon_init(p) ({                                              \
-	struct nouveau_falcon *falcon = (p);                                   \
-	_nouveau_falcon_init(nv_object(falcon));                               \
-})
-#define nouveau_falcon_fini(p,s) ({                                            \
-	struct nouveau_falcon *falcon = (p);                                   \
-	_nouveau_falcon_fini(nv_object(falcon), (s));                          \
-})
-
-int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *, u32, bool, const char *,
-			   const char *, int, void **);
-
-void nouveau_falcon_intr(struct nouveau_subdev *subdev);
-
-#define _nouveau_falcon_dtor _nouveau_engine_dtor
-int  _nouveau_falcon_init(struct nouveau_object *);
-int  _nouveau_falcon_fini(struct nouveau_object *, bool);
-u32  _nouveau_falcon_rd32(struct nouveau_object *, u64);
-void _nouveau_falcon_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
deleted file mode 100644
index 2007453..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef __NOUVEAU_FIFO_H__
-#define __NOUVEAU_FIFO_H__
-
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engine.h>
-#include <core/event.h>
-
-struct nouveau_fifo_chan {
-	struct nouveau_namedb base;
-	struct nouveau_dmaobj *pushdma;
-	struct nouveau_gpuobj *pushgpu;
-	void __iomem *user;
-	u64 addr;
-	u32 size;
-	u16 chid;
-	atomic_t refcnt; /* NV04_NVSW_SET_REF */
-};
-
-static inline struct nouveau_fifo_chan *
-nouveau_fifo_chan(void *obj)
-{
-	return (void *)nv_namedb(obj);
-}
-
-#define nouveau_fifo_channel_create(p,e,c,b,a,s,n,m,d)                         \
-	nouveau_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n),        \
-				     (m), sizeof(**d), (void **)d)
-#define nouveau_fifo_channel_init(p)                                           \
-	nouveau_namedb_init(&(p)->base)
-#define nouveau_fifo_channel_fini(p,s)                                         \
-	nouveau_namedb_fini(&(p)->base, (s))
-
-int  nouveau_fifo_channel_create_(struct nouveau_object *,
-				  struct nouveau_object *,
-				  struct nouveau_oclass *,
-				  int bar, u32 addr, u32 size, u32 push,
-				  u64 engmask, int len, void **);
-void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
-
-#define _nouveau_fifo_channel_init _nouveau_namedb_init
-#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
-
-void _nouveau_fifo_channel_dtor(struct nouveau_object *);
-int  _nouveau_fifo_channel_map(struct nouveau_object *, u64 *, u32 *);
-u32  _nouveau_fifo_channel_rd32(struct nouveau_object *, u64);
-void _nouveau_fifo_channel_wr32(struct nouveau_object *, u64, u32);
-int  _nouveau_fifo_channel_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-
-struct nouveau_fifo_base {
-	struct nouveau_gpuobj base;
-};
-
-#define nouveau_fifo_context_create(p,e,c,g,s,a,f,d)                           \
-	nouveau_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
-#define nouveau_fifo_context_destroy(p)                                        \
-	nouveau_gpuobj_destroy(&(p)->base)
-#define nouveau_fifo_context_init(p)                                           \
-	nouveau_gpuobj_init(&(p)->base)
-#define nouveau_fifo_context_fini(p,s)                                         \
-	nouveau_gpuobj_fini(&(p)->base, (s))
-
-#define _nouveau_fifo_context_dtor _nouveau_gpuobj_dtor
-#define _nouveau_fifo_context_init _nouveau_gpuobj_init
-#define _nouveau_fifo_context_fini _nouveau_gpuobj_fini
-#define _nouveau_fifo_context_rd32 _nouveau_gpuobj_rd32
-#define _nouveau_fifo_context_wr32 _nouveau_gpuobj_wr32
-
-struct nouveau_fifo {
-	struct nouveau_engine base;
-
-	struct nvkm_event cevent; /* channel creation event */
-	struct nvkm_event uevent; /* async user trigger */
-
-	struct nouveau_object **channel;
-	spinlock_t lock;
-	u16 min;
-	u16 max;
-
-	int  (*chid)(struct nouveau_fifo *, struct nouveau_object *);
-	void (*pause)(struct nouveau_fifo *, unsigned long *);
-	void (*start)(struct nouveau_fifo *, unsigned long *);
-};
-
-static inline struct nouveau_fifo *
-nouveau_fifo(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_FIFO];
-}
-
-#define nouveau_fifo_create(o,e,c,fc,lc,d)                                     \
-	nouveau_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
-#define nouveau_fifo_init(p)                                                   \
-	nouveau_engine_init(&(p)->base)
-#define nouveau_fifo_fini(p,s)                                                 \
-	nouveau_engine_fini(&(p)->base, (s))
-
-int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, int min, int max,
-			 int size, void **);
-void nouveau_fifo_destroy(struct nouveau_fifo *);
-const char *
-nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid);
-
-#define _nouveau_fifo_init _nouveau_engine_init
-#define _nouveau_fifo_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass *nv04_fifo_oclass;
-extern struct nouveau_oclass *nv10_fifo_oclass;
-extern struct nouveau_oclass *nv17_fifo_oclass;
-extern struct nouveau_oclass *nv40_fifo_oclass;
-extern struct nouveau_oclass *nv50_fifo_oclass;
-extern struct nouveau_oclass *nv84_fifo_oclass;
-extern struct nouveau_oclass *nvc0_fifo_oclass;
-extern struct nouveau_oclass *nve0_fifo_oclass;
-extern struct nouveau_oclass *gk20a_fifo_oclass;
-extern struct nouveau_oclass *nv108_fifo_oclass;
-
-int  nouveau_fifo_uevent_ctor(struct nouveau_object *, void *, u32,
-			      struct nvkm_notify *);
-void nouveau_fifo_uevent(struct nouveau_fifo *);
-
-void nv04_fifo_intr(struct nouveau_subdev *);
-int  nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
deleted file mode 100644
index d505557..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef __NOUVEAU_GRAPH_H__
-#define __NOUVEAU_GRAPH_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-struct nouveau_graph_chan {
-	struct nouveau_engctx base;
-};
-
-#define nouveau_graph_context_create(p,e,c,g,s,a,f,d)                          \
-	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_graph_context_destroy(d)                                       \
-	nouveau_engctx_destroy(&(d)->base)
-#define nouveau_graph_context_init(d)                                          \
-	nouveau_engctx_init(&(d)->base)
-#define nouveau_graph_context_fini(d,s)                                        \
-	nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_graph_context_dtor _nouveau_engctx_dtor
-#define _nouveau_graph_context_init _nouveau_engctx_init
-#define _nouveau_graph_context_fini _nouveau_engctx_fini
-#define _nouveau_graph_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_graph_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_graph {
-	struct nouveau_engine base;
-
-	/* Returns chipset-specific counts of units packed into an u64.
-	 */
-	u64 (*units)(struct nouveau_graph *);
-};
-
-static inline struct nouveau_graph *
-nouveau_graph(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_GR];
-}
-
-#define nouveau_graph_create(p,e,c,y,d)                                        \
-	nouveau_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d))
-#define nouveau_graph_destroy(d)                                               \
-	nouveau_engine_destroy(&(d)->base)
-#define nouveau_graph_init(d)                                                  \
-	nouveau_engine_init(&(d)->base)
-#define nouveau_graph_fini(d,s)                                                \
-	nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_graph_dtor _nouveau_engine_dtor
-#define _nouveau_graph_init _nouveau_engine_init
-#define _nouveau_graph_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass nv04_graph_oclass;
-extern struct nouveau_oclass nv10_graph_oclass;
-extern struct nouveau_oclass nv20_graph_oclass;
-extern struct nouveau_oclass nv25_graph_oclass;
-extern struct nouveau_oclass nv2a_graph_oclass;
-extern struct nouveau_oclass nv30_graph_oclass;
-extern struct nouveau_oclass nv34_graph_oclass;
-extern struct nouveau_oclass nv35_graph_oclass;
-extern struct nouveau_oclass nv40_graph_oclass;
-extern struct nouveau_oclass nv50_graph_oclass;
-extern struct nouveau_oclass *nvc0_graph_oclass;
-extern struct nouveau_oclass *nvc1_graph_oclass;
-extern struct nouveau_oclass *nvc4_graph_oclass;
-extern struct nouveau_oclass *nvc8_graph_oclass;
-extern struct nouveau_oclass *nvd7_graph_oclass;
-extern struct nouveau_oclass *nvd9_graph_oclass;
-extern struct nouveau_oclass *nve4_graph_oclass;
-extern struct nouveau_oclass *gk20a_graph_oclass;
-extern struct nouveau_oclass *nvf0_graph_oclass;
-extern struct nouveau_oclass *gk110b_graph_oclass;
-extern struct nouveau_oclass *nv108_graph_oclass;
-extern struct nouveau_oclass *gm107_graph_oclass;
-
-extern const struct nouveau_bitfield nv04_graph_nsource[];
-extern struct nouveau_ofuncs nv04_graph_ofuncs;
-bool nv04_graph_idle(void *obj);
-
-extern const struct nouveau_bitfield nv10_graph_intr_name[];
-extern const struct nouveau_bitfield nv10_graph_nstatus[];
-
-extern const struct nouveau_enum nv50_data_error_names[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
deleted file mode 100644
index 9b0d938..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef __NOUVEAU_MPEG_H__
-#define __NOUVEAU_MPEG_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_mpeg_chan {
-	struct nouveau_engctx base;
-};
-
-#define nouveau_mpeg_context_create(p,e,c,g,s,a,f,d)                           \
-	nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_mpeg_context_destroy(d)                                        \
-	nouveau_engctx_destroy(&(d)->base)
-#define nouveau_mpeg_context_init(d)                                           \
-	nouveau_engctx_init(&(d)->base)
-#define nouveau_mpeg_context_fini(d,s)                                         \
-	nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_mpeg_context_dtor _nouveau_engctx_dtor
-#define _nouveau_mpeg_context_init _nouveau_engctx_init
-#define _nouveau_mpeg_context_fini _nouveau_engctx_fini
-#define _nouveau_mpeg_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_mpeg_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_mpeg {
-	struct nouveau_engine base;
-};
-
-#define nouveau_mpeg_create(p,e,c,d)                                           \
-	nouveau_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
-#define nouveau_mpeg_destroy(d)                                                \
-	nouveau_engine_destroy(&(d)->base)
-#define nouveau_mpeg_init(d)                                                   \
-	nouveau_engine_init(&(d)->base)
-#define nouveau_mpeg_fini(d,s)                                                 \
-	nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_mpeg_dtor _nouveau_engine_dtor
-#define _nouveau_mpeg_init _nouveau_engine_init
-#define _nouveau_mpeg_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass nv31_mpeg_oclass;
-extern struct nouveau_oclass nv40_mpeg_oclass;
-extern struct nouveau_oclass nv44_mpeg_oclass;
-extern struct nouveau_oclass nv50_mpeg_oclass;
-extern struct nouveau_oclass nv84_mpeg_oclass;
-extern struct nouveau_ofuncs nv31_mpeg_ofuncs;
-extern struct nouveau_oclass nv31_mpeg_cclass;
-extern struct nouveau_oclass nv31_mpeg_sclass[];
-extern struct nouveau_oclass nv40_mpeg_sclass[];
-void nv31_mpeg_intr(struct nouveau_subdev *);
-void nv31_mpeg_tile_prog(struct nouveau_engine *, int);
-int  nv31_mpeg_init(struct nouveau_object *);
-
-extern struct nouveau_ofuncs nv50_mpeg_ofuncs;
-int  nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, void *, u32,
-			    struct nouveau_object **);
-void nv50_mpeg_intr(struct nouveau_subdev *);
-int  nv50_mpeg_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h
deleted file mode 100644
index 88cc812..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NVKM_PERFMON_H__
-#define __NVKM_PERFMON_H__
-
-#include <core/device.h>
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_perfdom;
-struct nouveau_perfctr;
-struct nouveau_perfmon {
-	struct nouveau_engine base;
-
-	struct nouveau_perfctx *context;
-	void *profile_data;
-
-	struct list_head domains;
-	u32 sequence;
-
-	/*XXX: temp for daemon backend */
-	u32 pwr[8];
-	u32 last;
-};
-
-static inline struct nouveau_perfmon *
-nouveau_perfmon(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_PERFMON];
-}
-
-extern struct nouveau_oclass *nv40_perfmon_oclass;
-extern struct nouveau_oclass *nv50_perfmon_oclass;
-extern struct nouveau_oclass *nv84_perfmon_oclass;
-extern struct nouveau_oclass *nva3_perfmon_oclass;
-extern struct nouveau_oclass nvc0_perfmon_oclass;
-extern struct nouveau_oclass nve0_perfmon_oclass;
-extern struct nouveau_oclass nvf0_perfmon_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
deleted file mode 100644
index 0a66781..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NOUVEAU_PPP_H__
-#define __NOUVEAU_PPP_H__
-
-extern struct nouveau_oclass nv98_ppp_oclass;
-extern struct nouveau_oclass nvc0_ppp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h
deleted file mode 100644
index 23a462b..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/software.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __NOUVEAU_SOFTWARE_H__
-#define __NOUVEAU_SOFTWARE_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_software_chan {
-	struct nouveau_engctx base;
-
-	int (*flip)(void *);
-	void *flip_data;
-};
-
-#define nouveau_software_context_create(p,e,c,d)                               \
-	nouveau_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
-#define nouveau_software_context_destroy(d)                                    \
-	nouveau_engctx_destroy(&(d)->base)
-#define nouveau_software_context_init(d)                                       \
-	nouveau_engctx_init(&(d)->base)
-#define nouveau_software_context_fini(d,s)                                     \
-	nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_software_context_dtor _nouveau_engctx_dtor
-#define _nouveau_software_context_init _nouveau_engctx_init
-#define _nouveau_software_context_fini _nouveau_engctx_fini
-
-struct nouveau_software {
-	struct nouveau_engine base;
-};
-
-#define nouveau_software_create(p,e,c,d)                                       \
-	nouveau_engine_create((p), (e), (c), true, "SW", "software", (d))
-#define nouveau_software_destroy(d)                                            \
-	nouveau_engine_destroy(&(d)->base)
-#define nouveau_software_init(d)                                               \
-	nouveau_engine_init(&(d)->base)
-#define nouveau_software_fini(d,s)                                             \
-	nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_software_dtor _nouveau_engine_dtor
-#define _nouveau_software_init _nouveau_engine_init
-#define _nouveau_software_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass *nv04_software_oclass;
-extern struct nouveau_oclass *nv10_software_oclass;
-extern struct nouveau_oclass *nv50_software_oclass;
-extern struct nouveau_oclass *nvc0_software_oclass;
-
-void nv04_software_intr(struct nouveau_subdev *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
deleted file mode 100644
index 39baebe..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/vp.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_VP_H__
-#define __NOUVEAU_VP_H__
-
-extern struct nouveau_oclass nv84_vp_oclass;
-extern struct nouveau_oclass nv98_vp_oclass;
-extern struct nouveau_oclass nvc0_vp_oclass;
-extern struct nouveau_oclass nve0_vp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
deleted file mode 100644
index 306100f..0000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NOUVEAU_XTENSA_H__
-#define __NOUVEAU_XTENSA_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-struct nouveau_xtensa {
-	struct nouveau_engine base;
-
-	u32 addr;
-	struct nouveau_gpuobj *gpu_fw;
-	u32 fifo_val;
-	u32 unkd28;
-};
-
-#define nouveau_xtensa_create(p,e,c,b,d,i,f,r)				\
-	nouveau_xtensa_create_((p), (e), (c), (b), (d), (i), (f),	\
-			       sizeof(**r),(void **)r)
-
-int _nouveau_xtensa_engctx_ctor(struct nouveau_object *,
-				struct nouveau_object *,
-				struct nouveau_oclass *, void *, u32,
-				struct nouveau_object **);
-
-void _nouveau_xtensa_intr(struct nouveau_subdev *);
-int nouveau_xtensa_create_(struct nouveau_object *,
-			   struct nouveau_object *,
-			   struct nouveau_oclass *, u32, bool,
-			   const char *, const char *,
-			   int, void **);
-#define _nouveau_xtensa_dtor _nouveau_engine_dtor
-int _nouveau_xtensa_init(struct nouveau_object *);
-int _nouveau_xtensa_fini(struct nouveau_object *, bool);
-u32  _nouveau_xtensa_rd32(struct nouveau_object *, u64);
-void _nouveau_xtensa_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/class.h b/drivers/gpu/drm/nouveau/core/include/nvif/class.h
deleted file mode 120000
index f1ac485..0000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/class.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/class.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/event.h b/drivers/gpu/drm/nouveau/core/include/nvif/event.h
deleted file mode 120000
index 1b79853..0000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/event.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/event.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h
deleted file mode 120000
index 8569c86..0000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/ioctl.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h b/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h
deleted file mode 120000
index 69d9929..0000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/unpack.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h
deleted file mode 100644
index 257ddf6..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NOUVEAU_BAR_H__
-#define __NOUVEAU_BAR_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_mem;
-struct nouveau_vma;
-
-struct nouveau_bar {
-	struct nouveau_subdev base;
-
-	int (*alloc)(struct nouveau_bar *, struct nouveau_object *,
-		     struct nouveau_mem *, struct nouveau_object **);
-
-	int (*kmap)(struct nouveau_bar *, struct nouveau_mem *,
-		    u32 flags, struct nouveau_vma *);
-	int (*umap)(struct nouveau_bar *, struct nouveau_mem *,
-		    u32 flags, struct nouveau_vma *);
-	void (*unmap)(struct nouveau_bar *, struct nouveau_vma *);
-	void (*flush)(struct nouveau_bar *);
-
-	/* whether the BAR supports to be ioremapped WC or should be uncached */
-	bool iomap_uncached;
-};
-
-static inline struct nouveau_bar *
-nouveau_bar(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BAR];
-}
-
-extern struct nouveau_oclass nv50_bar_oclass;
-extern struct nouveau_oclass nvc0_bar_oclass;
-extern struct nouveau_oclass gk20a_bar_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h
deleted file mode 100644
index 5bd1ca8..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_BIOS_H__
-#define __NOUVEAU_BIOS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_bios {
-	struct nouveau_subdev base;
-	u32 size;
-	u8 *data;
-
-	u32 bmp_offset;
-	u32 bit_offset;
-
-	struct {
-		u8 major;
-		u8 chip;
-		u8 minor;
-		u8 micro;
-		u8 patch;
-	} version;
-};
-
-static inline struct nouveau_bios *
-nouveau_bios(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VBIOS];
-}
-
-u8  nvbios_checksum(const u8 *data, int size);
-u16 nvbios_findstr(const u8 *data, int size, const char *str, int len);
-
-extern struct nouveau_oclass nouveau_bios_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h
deleted file mode 100644
index 1f84d36..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVBIOS_M0203_H__
-#define __NVBIOS_M0203_H__
-
-struct nvbios_M0203T {
-#define M0203T_TYPE_RAMCFG 0x00
-	u8  type;
-	u16 pointer;
-};
-
-u32 nvbios_M0203Te(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0203Tp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_M0203T *);
-
-struct nvbios_M0203E {
-#define M0203E_TYPE_DDR2  0x0
-#define M0203E_TYPE_DDR3  0x1
-#define M0203E_TYPE_GDDR3 0x2
-#define M0203E_TYPE_GDDR5 0x3
-#define M0203E_TYPE_SKIP  0xf
-	u8 type;
-	u8 strap;
-	u8 group;
-};
-
-u32 nvbios_M0203Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0203Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_M0203E *);
-u32 nvbios_M0203Em(struct nouveau_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
-		   struct nvbios_M0203E *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
deleted file mode 100644
index e171120..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NVBIOS_M0205_H__
-#define __NVBIOS_M0205_H__
-
-struct nvbios_M0205T {
-	u16 freq;
-};
-
-u32 nvbios_M0205Te(struct nouveau_bios *,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-u32 nvbios_M0205Tp(struct nouveau_bios *,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
-		   struct nvbios_M0205T *);
-
-struct nvbios_M0205E {
-	u8 type;
-};
-
-u32 nvbios_M0205Ee(struct nouveau_bios *, int idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0205Ep(struct nouveau_bios *, int idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_M0205E *);
-
-struct nvbios_M0205S {
-	u8 data;
-};
-
-u32 nvbios_M0205Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0205Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_M0205S *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
deleted file mode 100644
index 67dc50d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVBIOS_M0209_H__
-#define __NVBIOS_M0209_H__
-
-u32 nvbios_M0209Te(struct nouveau_bios *,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-struct nvbios_M0209E {
-	u8 v00_40;
-	u8 bits;
-	u8 modulo;
-	u8 v02_40;
-	u8 v02_07;
-	u8 v03;
-};
-
-u32 nvbios_M0209Ee(struct nouveau_bios *, int idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0209Ep(struct nouveau_bios *, int idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_M0209E *);
-
-struct nvbios_M0209S {
-	u32 data[0x200];
-};
-
-u32 nvbios_M0209Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0209Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_M0209S *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h
deleted file mode 100644
index bba01ab..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVBIOS_P0260_H__
-#define __NVBIOS_P0260_H__
-
-u32 nvbios_P0260Te(struct nouveau_bios *,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
-
-struct nvbios_P0260E {
-	u32 data;
-};
-
-u32 nvbios_P0260Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_P0260Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_P0260E *);
-
-struct nvbios_P0260X {
-	u32 data;
-};
-
-u32 nvbios_P0260Xe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_P0260Xp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_P0260X *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h
deleted file mode 100644
index 73f060b..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NVBIOS_BIT_H__
-#define __NVBIOS_BIT_H__
-
-struct bit_entry {
-	u8  id;
-	u8  version;
-	u16 length;
-	u16 offset;
-};
-
-int bit_entry(struct nouveau_bios *, u8 id, struct bit_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h
deleted file mode 100644
index 10e4dbc..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __NVBIOS_BMP_H__
-#define __NVBIOS_BMP_H__
-
-static inline u16
-bmp_version(struct nouveau_bios *bios)
-{
-	if (bios->bmp_offset) {
-		return nv_ro08(bios, bios->bmp_offset + 5) << 8 |
-		       nv_ro08(bios, bios->bmp_offset + 6);
-	}
-
-	return 0x0000;
-}
-
-static inline u16
-bmp_mem_init_table(struct nouveau_bios *bios)
-{
-	if (bmp_version(bios) >= 0x0300)
-		return nv_ro16(bios, bios->bmp_offset + 24);
-	return 0x0000;
-}
-
-static inline u16
-bmp_sdr_seq_table(struct nouveau_bios *bios)
-{
-	if (bmp_version(bios) >= 0x0300)
-		return nv_ro16(bios, bios->bmp_offset + 26);
-	return 0x0000;
-}
-
-static inline u16
-bmp_ddr_seq_table(struct nouveau_bios *bios)
-{
-	if (bmp_version(bios) >= 0x0300)
-		return nv_ro16(bios, bios->bmp_offset + 28);
-	return 0x0000;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h
deleted file mode 100644
index 662b207..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __NVBIOS_BOOST_H__
-#define __NVBIOS_BOOST_H__
-
-u16 nvbios_boostTe(struct nouveau_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
-
-struct nvbios_boostE {
-	u8  pstate;
-	u32 min;
-	u32 max;
-};
-
-u16 nvbios_boostEe(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *);
-u16 nvbios_boostEp(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *,
-		   struct nvbios_boostE *);
-u16 nvbios_boostEm(struct nouveau_bios *, u8, u8 *, u8 *, u8 *, u8 *,
-		   struct nvbios_boostE *);
-
-struct nvbios_boostS {
-	u8  domain;
-	u8  percent;
-	u32 min;
-	u32 max;
-};
-
-u16 nvbios_boostSe(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8);
-u16 nvbios_boostSp(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8,
-		   struct nvbios_boostS *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
deleted file mode 100644
index f3930c2..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __NVBIOS_CONN_H__
-#define __NVBIOS_CONN_H__
-
-enum dcb_connector_type {
-	DCB_CONNECTOR_VGA = 0x00,
-	DCB_CONNECTOR_TV_0 = 0x10,
-	DCB_CONNECTOR_TV_1 = 0x11,
-	DCB_CONNECTOR_TV_3 = 0x13,
-	DCB_CONNECTOR_DVI_I = 0x30,
-	DCB_CONNECTOR_DVI_D = 0x31,
-	DCB_CONNECTOR_DMS59_0 = 0x38,
-	DCB_CONNECTOR_DMS59_1 = 0x39,
-	DCB_CONNECTOR_LVDS = 0x40,
-	DCB_CONNECTOR_LVDS_SPWG = 0x41,
-	DCB_CONNECTOR_DP = 0x46,
-	DCB_CONNECTOR_eDP = 0x47,
-	DCB_CONNECTOR_HDMI_0 = 0x60,
-	DCB_CONNECTOR_HDMI_1 = 0x61,
-	DCB_CONNECTOR_HDMI_C = 0x63,
-	DCB_CONNECTOR_DMS59_DP0 = 0x64,
-	DCB_CONNECTOR_DMS59_DP1 = 0x65,
-	DCB_CONNECTOR_NONE = 0xff
-};
-
-struct nvbios_connT {
-};
-
-u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_connT *info);
-
-struct nvbios_connE {
-	u8 type;
-	u8 location;
-	u8 hpd;
-	u8 dp;
-	u8 di;
-	u8 sr;
-	u8 lcdid;
-};
-
-u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr);
-u32 nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr,
-		  struct nvbios_connE *info);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h
deleted file mode 100644
index a80a4380..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __NVBIOS_CSTEP_H__
-#define __NVBIOS_CSTEP_H__
-
-u16 nvbios_cstepTe(struct nouveau_bios *,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
-
-struct nvbios_cstepE {
-	u8  pstate;
-	u8  index;
-};
-
-u16 nvbios_cstepEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u16 nvbios_cstepEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_cstepE *);
-u16 nvbios_cstepEm(struct nouveau_bios *, u8 pstate, u8 *ver, u8 *hdr,
-		   struct nvbios_cstepE *);
-
-struct nvbios_cstepX {
-	u32 freq;
-	u8  unkn[2];
-	u8  voltage;
-};
-
-u16 nvbios_cstepXe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u16 nvbios_cstepXp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		   struct nvbios_cstepX *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
deleted file mode 100644
index 123270e9..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef __NVBIOS_DCB_H__
-#define __NVBIOS_DCB_H__
-
-struct nouveau_bios;
-
-enum dcb_output_type {
-	DCB_OUTPUT_ANALOG	= 0x0,
-	DCB_OUTPUT_TV		= 0x1,
-	DCB_OUTPUT_TMDS		= 0x2,
-	DCB_OUTPUT_LVDS		= 0x3,
-	DCB_OUTPUT_DP		= 0x6,
-	DCB_OUTPUT_EOL		= 0xe,
-	DCB_OUTPUT_UNUSED	= 0xf,
-	DCB_OUTPUT_ANY = -1,
-};
-
-struct dcb_output {
-	int index;	/* may not be raw dcb index if merging has happened */
-	u16 hasht;
-	u16 hashm;
-	enum dcb_output_type type;
-	uint8_t i2c_index;
-	uint8_t heads;
-	uint8_t connector;
-	uint8_t bus;
-	uint8_t location;
-	uint8_t or;
-	uint8_t link;
-	bool duallink_possible;
-	uint8_t extdev;
-	union {
-		struct sor_conf {
-			int link;
-		} sorconf;
-		struct {
-			int maxfreq;
-		} crtconf;
-		struct {
-			struct sor_conf sor;
-			bool use_straps_for_mode;
-			bool use_acpi_for_edid;
-			bool use_power_scripts;
-		} lvdsconf;
-		struct {
-			bool has_component_output;
-		} tvconf;
-		struct {
-			struct sor_conf sor;
-			int link_nr;
-			int link_bw;
-		} dpconf;
-		struct {
-			struct sor_conf sor;
-			int slave_addr;
-		} tmdsconf;
-	};
-	bool i2c_upper_default;
-};
-
-u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
-u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
-u16 dcb_outp_parse(struct nouveau_bios *, u8 idx, u8 *, u8 *,
-		   struct dcb_output *);
-u16 dcb_outp_match(struct nouveau_bios *, u16 type, u16 mask, u8 *, u8 *,
-		   struct dcb_output *);
-int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
-		     (struct nouveau_bios *, void *, int index, u16 entry));
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
deleted file mode 100644
index c35937e..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVBIOS_DISP_H__
-#define __NVBIOS_DISP_H__
-
-u16 nvbios_disp_table(struct nouveau_bios *,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub);
-
-struct nvbios_disp {
-	u16 data;
-};
-
-u16 nvbios_disp_entry(struct nouveau_bios *, u8 idx,
-		      u8 *ver, u8 *hdr__, u8 *sub);
-u16 nvbios_disp_parse(struct nouveau_bios *, u8 idx,
-		      u8 *ver, u8 *hdr__, u8 *sub,
-		      struct nvbios_disp *);
-
-struct nvbios_outp {
-	u16 type;
-	u16 mask;
-	u16 script[3];
-};
-
-u16 nvbios_outp_entry(struct nouveau_bios *, u8 idx,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_outp_parse(struct nouveau_bios *, u8 idx,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_outp *);
-u16 nvbios_outp_match(struct nouveau_bios *, u16 type, u16 mask,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_outp *);
-
-
-struct nvbios_ocfg {
-	u16 match;
-	u16 clkcmp[2];
-};
-
-u16 nvbios_ocfg_entry(struct nouveau_bios *, u16 outp, u8 idx,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_ocfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_ocfg *);
-u16 nvbios_ocfg_match(struct nouveau_bios *, u16 outp, u16 type,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_ocfg *);
-u16 nvbios_oclk_match(struct nouveau_bios *, u16 cmp, u32 khz);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
deleted file mode 100644
index 728206e..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NVBIOS_DP_H__
-#define __NVBIOS_DP_H__
-
-struct nvbios_dpout {
-	u16 type;
-	u16 mask;
-	u8  flags;
-	u32 script[5];
-	u32 lnkcmp;
-};
-
-u16 nvbios_dpout_parse(struct nouveau_bios *, u8 idx,
-		       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		       struct nvbios_dpout *);
-u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask,
-		       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		       struct nvbios_dpout *);
-
-struct nvbios_dpcfg {
-	u8 pc;
-	u8 dc;
-	u8 pe;
-	u8 tx_pu;
-};
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpcfg *);
-u16
-nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
deleted file mode 100644
index 949fee3..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVBIOS_EXTDEV_H__
-#define __NVBIOS_EXTDEV_H__
-
-struct nouveau_bios;
-
-enum nvbios_extdev_type {
-	NVBIOS_EXTDEV_LM89		= 0x02,
-	NVBIOS_EXTDEV_VT1103M		= 0x40,
-	NVBIOS_EXTDEV_PX3540		= 0x41,
-	NVBIOS_EXTDEV_VT1105M		= 0x42, /* or close enough... */
-	NVBIOS_EXTDEV_ADT7473		= 0x70, /* can also be a LM64 */
-	NVBIOS_EXTDEV_HDCP_EEPROM	= 0x90,
-	NVBIOS_EXTDEV_NONE		= 0xff,
-};
-
-struct nvbios_extdev_func {
-	u8 type;
-	u8 addr;
-	u8 bus;
-};
-
-int
-nvbios_extdev_parse(struct nouveau_bios *, int, struct nvbios_extdev_func *);
-
-int
-nvbios_extdev_find(struct nouveau_bios *, enum nvbios_extdev_type,
-		   struct nvbios_extdev_func *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
deleted file mode 100644
index 119d087..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NVBIOS_FAN_H__
-#define __NVBIOS_FAN_H__
-
-#include <subdev/bios/therm.h>
-
-u16 nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
deleted file mode 100644
index c7b2e58..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVBIOS_GPIO_H__
-#define __NVBIOS_GPIO_H__
-
-enum dcb_gpio_func_name {
-	DCB_GPIO_PANEL_POWER = 0x01,
-	DCB_GPIO_TVDAC0 = 0x0c,
-	DCB_GPIO_TVDAC1 = 0x2d,
-	DCB_GPIO_FAN = 0x09,
-	DCB_GPIO_FAN_SENSE = 0x3d,
-	DCB_GPIO_UNUSED = 0xff,
-	DCB_GPIO_VID0 = 0x04,
-	DCB_GPIO_VID1 = 0x05,
-	DCB_GPIO_VID2 = 0x06,
-	DCB_GPIO_VID3 = 0x1a,
-	DCB_GPIO_VID4 = 0x73,
-	DCB_GPIO_VID5 = 0x74,
-	DCB_GPIO_VID6 = 0x75,
-	DCB_GPIO_VID7 = 0x76,
-};
-
-#define DCB_GPIO_LOG_DIR     0x02
-#define DCB_GPIO_LOG_DIR_OUT 0x00
-#define DCB_GPIO_LOG_DIR_IN  0x02
-#define DCB_GPIO_LOG_VAL     0x01
-#define DCB_GPIO_LOG_VAL_LO  0x00
-#define DCB_GPIO_LOG_VAL_HI  0x01
-
-struct dcb_gpio_func {
-	u8 func;
-	u8 line;
-	u8 log[2];
-
-	/* so far, "param" seems to only have an influence on PWM-related
-	 * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL.
-	 * if param equals 1, hardware PWM is available
-	 * if param equals 0, the host should toggle the GPIO itself
-	 */
-	u8 param;
-};
-
-u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len);
-u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len,
-		   struct dcb_gpio_func *);
-u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line,
-		   u8 *ver, u8 *len, struct dcb_gpio_func *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
deleted file mode 100644
index c9bb112..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __NVBIOS_I2C_H__
-#define __NVBIOS_I2C_H__
-
-struct nouveau_bios;
-
-enum dcb_i2c_type {
-	/* matches bios type field prior to ccb 4.1 */
-	DCB_I2C_NV04_BIT = 0x00,
-	DCB_I2C_NV4E_BIT = 0x04,
-	DCB_I2C_NVIO_BIT = 0x05,
-	DCB_I2C_NVIO_AUX = 0x06,
-	/* made up - mostly */
-	DCB_I2C_PMGR     = 0x80,
-	DCB_I2C_UNUSED   = 0xff
-};
-
-struct dcb_i2c_entry {
-	enum dcb_i2c_type type;
-	u8 drive;
-	u8 sense;
-	u8 share;
-	u8 auxch;
-};
-
-u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_i2c_entry(struct nouveau_bios *, u8 index, u8 *ver, u8 *len);
-int dcb_i2c_parse(struct nouveau_bios *, u8 index, struct dcb_i2c_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h
deleted file mode 100644
index 3348b45..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NVBIOS_IMAGE_H__
-#define __NVBIOS_IMAGE_H__
-
-struct nvbios_image {
-	u32  base;
-	u32  size;
-	u8   type;
-	bool last;
-};
-
-bool nvbios_image(struct nouveau_bios *, int, struct nvbios_image *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
deleted file mode 100644
index ca2f6bf..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVBIOS_INIT_H__
-#define __NVBIOS_INIT_H__
-
-struct nvbios_init {
-	struct nouveau_subdev *subdev;
-	struct nouveau_bios *bios;
-	u16 offset;
-	struct dcb_output *outp;
-	int crtc;
-
-	/* internal state used during parsing */
-	u8 execute;
-	u32 nested;
-	u16 repeat;
-	u16 repend;
-	u32 ramcfg;
-};
-
-int nvbios_exec(struct nvbios_init *);
-int nvbios_init(struct nouveau_subdev *, bool execute);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
deleted file mode 100644
index 5572e60..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVBIOS_MXM_H__
-#define __NVBIOS_MXM_H__
-
-u16 mxm_table(struct nouveau_bios *, u8 *ver, u8 *hdr);
-
-u8  mxm_sor_map(struct nouveau_bios *, u8 conn);
-u8  mxm_ddc_map(struct nouveau_bios *, u8 port);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h
deleted file mode 100644
index b18413d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __NVBIOS_NPDE_H__
-#define __NVBIOS_NPDE_H__
-
-struct nvbios_npdeT {
-	u32 image_size;
-	bool last;
-};
-
-u32 nvbios_npdeTe(struct nouveau_bios *, u32);
-u32 nvbios_npdeTp(struct nouveau_bios *, u32, struct nvbios_npdeT *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h
deleted file mode 100644
index 3d634a0..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVBIOS_PCIR_H__
-#define __NVBIOS_PCIR_H__
-
-struct nvbios_pcirT {
-	u16 vendor_id;
-	u16 device_id;
-	u8  class_code[3];
-	u32 image_size;
-	u16 image_rev;
-	u8  image_type;
-	bool last;
-};
-
-u32 nvbios_pcirTe(struct nouveau_bios *, u32, u8 *ver, u16 *hdr);
-u32 nvbios_pcirTp(struct nouveau_bios *, u32, u8 *ver, u16 *hdr,
-		  struct nvbios_pcirT *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h
deleted file mode 100644
index 16ff06e..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __NVBIOS_PERF_H__
-#define __NVBIOS_PERF_H__
-
-struct nouveau_bios;
-
-u16 nvbios_perf_table(struct nouveau_bios *, u8 *ver, u8 *hdr,
-		      u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-struct nvbios_perfE {
-	u8  pstate;
-	u8  fanspeed;
-	u8  voltage;
-	u32 core;
-	u32 shader;
-	u32 memory;
-	u32 vdec;
-	u32 disp;
-	u32 script;
-};
-
-u16 nvbios_perf_entry(struct nouveau_bios *, int idx,
-		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_perfEp(struct nouveau_bios *, int idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *);
-
-struct nvbios_perfS {
-	union {
-		struct {
-			u32 freq;
-		} v40;
-	};
-};
-
-u32 nvbios_perfSe(struct nouveau_bios *, u32 data, int idx,
-		  u8 *ver, u8 *hdr, u8 cnt, u8 len);
-u32 nvbios_perfSp(struct nouveau_bios *, u32 data, int idx,
-		  u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *);
-
-struct nvbios_perf_fan {
-	u32 pwm_divisor;
-};
-
-int
-nvbios_perf_fan_parse(struct nouveau_bios *, struct nvbios_perf_fan *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h
deleted file mode 100644
index b2f3d4d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef __NVBIOS_PLL_H__
-#define __NVBIOS_PLL_H__
-
-/*XXX: kill me */
-struct nouveau_pll_vals {
-	union {
-		struct {
-#ifdef __BIG_ENDIAN
-			uint8_t N1, M1, N2, M2;
-#else
-			uint8_t M1, N1, M2, N2;
-#endif
-		};
-		struct {
-			uint16_t NM1, NM2;
-		} __attribute__((packed));
-	};
-	int log2P;
-
-	int refclk;
-};
-
-struct nouveau_bios;
-
-/* these match types in pll limits table version 0x40,
- * nouveau uses them on all chipsets internally where a
- * specific pll needs to be referenced, but the exact
- * register isn't known.
- */
-enum nvbios_pll_type {
-	PLL_CORE   = 0x01,
-	PLL_SHADER = 0x02,
-	PLL_UNK03  = 0x03,
-	PLL_MEMORY = 0x04,
-	PLL_VDEC   = 0x05,
-	PLL_UNK40  = 0x40,
-	PLL_UNK41  = 0x41,
-	PLL_UNK42  = 0x42,
-	PLL_VPLL0  = 0x80,
-	PLL_VPLL1  = 0x81,
-	PLL_VPLL2  = 0x82,
-	PLL_VPLL3  = 0x83,
-	PLL_MAX    = 0xff
-};
-
-struct nvbios_pll {
-	enum nvbios_pll_type type;
-	u32 reg;
-	u32 refclk;
-
-	u8 min_p;
-	u8 max_p;
-	u8 bias_p;
-
-	/*
-	 * for most pre nv50 cards setting a log2P of 7 (the common max_log2p
-	 * value) is no different to 6 (at least for vplls) so allowing the MNP
-	 * calc to use 7 causes the generated clock to be out by a factor of 2.
-	 * however, max_log2p cannot be fixed-up during parsing as the
-	 * unmodified max_log2p value is still needed for setting mplls, hence
-	 * an additional max_usable_log2p member
-	 */
-	u8 max_p_usable;
-
-	struct {
-		u32 min_freq;
-		u32 max_freq;
-		u32 min_inputfreq;
-		u32 max_inputfreq;
-		u8  min_m;
-		u8  max_m;
-		u8  min_n;
-		u8  max_n;
-	} vco1, vco2;
-};
-
-int nvbios_pll_parse(struct nouveau_bios *, u32 type, struct nvbios_pll *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h
deleted file mode 100644
index 9de593d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NVBIOS_PMU_H__
-#define __NVBIOS_PMU_H__
-
-struct nvbios_pmuT {
-};
-
-u32 nvbios_pmuTe(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_pmuTp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		 struct nvbios_pmuT *);
-
-struct nvbios_pmuE {
-	u8  type;
-	u32 data;
-};
-
-u32 nvbios_pmuEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_pmuEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
-		 struct nvbios_pmuE *);
-
-struct nvbios_pmuR {
-	u32 boot_addr_pmu;
-	u32 boot_addr;
-	u32 boot_size;
-	u32 code_addr_pmu;
-	u32 code_addr;
-	u32 code_size;
-	u32 init_addr_pmu;
-
-	u32 data_addr_pmu;
-	u32 data_addr;
-	u32 data_size;
-	u32 args_addr_pmu;
-};
-
-bool nvbios_pmuRm(struct nouveau_bios *, u8 type, struct nvbios_pmuR *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
deleted file mode 100644
index 4a0e0ce..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef __NVBIOS_RAMCFG_H__
-#define __NVBIOS_RAMCFG_H__
-
-struct nouveau_bios;
-
-struct nvbios_ramcfg {
-	unsigned rammap_ver;
-	unsigned rammap_hdr;
-	unsigned rammap_min;
-	unsigned rammap_max;
-	union {
-		struct {
-			unsigned rammap_10_04_02:1;
-			unsigned rammap_10_04_08:1;
-		};
-		struct {
-			unsigned rammap_11_08_01:1;
-			unsigned rammap_11_08_0c:2;
-			unsigned rammap_11_08_10:1;
-			unsigned rammap_11_09_01ff:9;
-			unsigned rammap_11_0a_03fe:9;
-			unsigned rammap_11_0a_0400:1;
-			unsigned rammap_11_0a_0800:1;
-			unsigned rammap_11_0b_01f0:5;
-			unsigned rammap_11_0b_0200:1;
-			unsigned rammap_11_0b_0400:1;
-			unsigned rammap_11_0b_0800:1;
-			unsigned rammap_11_0d:8;
-			unsigned rammap_11_0e:8;
-			unsigned rammap_11_0f:8;
-			unsigned rammap_11_11_0c:2;
-		};
-	};
-
-	unsigned ramcfg_ver;
-	unsigned ramcfg_hdr;
-	unsigned ramcfg_timing;
-	union {
-		struct {
-			unsigned ramcfg_10_02_01:1;
-			unsigned ramcfg_10_02_02:1;
-			unsigned ramcfg_10_02_04:1;
-			unsigned ramcfg_10_02_08:1;
-			unsigned ramcfg_10_02_10:1;
-			unsigned ramcfg_10_02_20:1;
-			unsigned ramcfg_10_DLLoff:1;
-			unsigned ramcfg_10_03_0f:4;
-			unsigned ramcfg_10_04_01:1;
-			unsigned ramcfg_10_05:8;
-			unsigned ramcfg_10_06:8;
-			unsigned ramcfg_10_07:8;
-			unsigned ramcfg_10_08:8;
-			unsigned ramcfg_10_09_0f:4;
-			unsigned ramcfg_10_09_f0:4;
-		};
-		struct {
-			unsigned ramcfg_11_01_01:1;
-			unsigned ramcfg_11_01_02:1;
-			unsigned ramcfg_11_01_04:1;
-			unsigned ramcfg_11_01_08:1;
-			unsigned ramcfg_11_01_10:1;
-			unsigned ramcfg_11_01_20:1;
-			unsigned ramcfg_11_01_40:1;
-			unsigned ramcfg_11_01_80:1;
-			unsigned ramcfg_11_02_03:2;
-			unsigned ramcfg_11_02_04:1;
-			unsigned ramcfg_11_02_08:1;
-			unsigned ramcfg_11_02_10:1;
-			unsigned ramcfg_11_02_40:1;
-			unsigned ramcfg_11_02_80:1;
-			unsigned ramcfg_11_03_0f:4;
-			unsigned ramcfg_11_03_30:2;
-			unsigned ramcfg_11_03_c0:2;
-			unsigned ramcfg_11_03_f0:4;
-			unsigned ramcfg_11_04:8;
-			unsigned ramcfg_11_06:8;
-			unsigned ramcfg_11_07_02:1;
-			unsigned ramcfg_11_07_04:1;
-			unsigned ramcfg_11_07_08:1;
-			unsigned ramcfg_11_07_10:1;
-			unsigned ramcfg_11_07_40:1;
-			unsigned ramcfg_11_07_80:1;
-			unsigned ramcfg_11_08_01:1;
-			unsigned ramcfg_11_08_02:1;
-			unsigned ramcfg_11_08_04:1;
-			unsigned ramcfg_11_08_08:1;
-			unsigned ramcfg_11_08_10:1;
-			unsigned ramcfg_11_08_20:1;
-			unsigned ramcfg_11_09:8;
-		};
-	};
-
-	unsigned timing_ver;
-	unsigned timing_hdr;
-	unsigned timing[11];
-	union {
-		struct {
-			unsigned timing_10_WR:8;
-			unsigned timing_10_WTR:8;
-			unsigned timing_10_CL:8;
-			unsigned timing_10_RC:8;
-			/*empty: 4 */
-			unsigned timing_10_RFC:8;        /* Byte 5 */
-			/*empty: 6 */
-			unsigned timing_10_RAS:8;        /* Byte 7 */
-			/*empty: 8 */
-			unsigned timing_10_RP:8;         /* Byte 9 */
-			unsigned timing_10_RCDRD:8;
-			unsigned timing_10_RCDWR:8;
-			unsigned timing_10_RRD:8;
-			unsigned timing_10_13:8;
-			unsigned timing_10_ODT:3;
-			/* empty: 15 */
-			unsigned timing_10_16:8;
-			/* empty: 17 */
-			unsigned timing_10_18:8;
-			unsigned timing_10_CWL:8;
-			unsigned timing_10_20:8;
-			unsigned timing_10_21:8;
-			/* empty: 22, 23 */
-			unsigned timing_10_24:8;
-		};
-		struct {
-			unsigned timing_20_2e_03:2;
-			unsigned timing_20_2e_30:2;
-			unsigned timing_20_2e_c0:2;
-			unsigned timing_20_2f_03:2;
-			unsigned timing_20_2c_003f:6;
-			unsigned timing_20_2c_1fc0:7;
-			unsigned timing_20_30_f8:5;
-			unsigned timing_20_30_07:3;
-			unsigned timing_20_31_0007:3;
-			unsigned timing_20_31_0078:4;
-			unsigned timing_20_31_0780:4;
-			unsigned timing_20_31_0800:1;
-			unsigned timing_20_31_7000:3;
-			unsigned timing_20_31_8000:1;
-		};
-	};
-};
-
-u8 nvbios_ramcfg_count(struct nouveau_bios *);
-u8 nvbios_ramcfg_index(struct nouveau_subdev *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
deleted file mode 100644
index 47e021d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __NVBIOS_RAMMAP_H__
-#define __NVBIOS_RAMMAP_H__
-
-struct nvbios_ramcfg;
-
-u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr,
-		    u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-u32 nvbios_rammapEe(struct nouveau_bios *, int idx,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_rammapEp(struct nouveau_bios *, int idx,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		    struct nvbios_ramcfg *);
-u32 nvbios_rammapEm(struct nouveau_bios *, u16 mhz,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		    struct nvbios_ramcfg *);
-
-u32 nvbios_rammapSe(struct nouveau_bios *, u32 data,
-		    u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
-		    u8 *ver, u8 *hdr);
-u32 nvbios_rammapSp(struct nouveau_bios *, u32 data,
-		    u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
-		    u8 *ver, u8 *hdr,
-		    struct nvbios_ramcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
deleted file mode 100644
index 295d093..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef __NVBIOS_THERM_H__
-#define __NVBIOS_THERM_H__
-
-struct nouveau_bios;
-
-struct nvbios_therm_threshold {
-	u8 temp;
-	u8 hysteresis;
-};
-
-struct nvbios_therm_sensor {
-	/* diode */
-	s16 slope_mult;
-	s16 slope_div;
-	s16 offset_num;
-	s16 offset_den;
-	s8 offset_constant;
-
-	/* thresholds */
-	struct nvbios_therm_threshold thrs_fan_boost;
-	struct nvbios_therm_threshold thrs_down_clock;
-	struct nvbios_therm_threshold thrs_critical;
-	struct nvbios_therm_threshold thrs_shutdown;
-};
-
-enum nvbios_therm_fan_type {
-	NVBIOS_THERM_FAN_UNK = 0,
-	NVBIOS_THERM_FAN_TOGGLE = 1,
-	NVBIOS_THERM_FAN_PWM = 2,
-};
-
-/* no vbios have more than 6 */
-#define NOUVEAU_TEMP_FAN_TRIP_MAX 10
-struct nouveau_therm_trip_point {
-	int fan_duty;
-	int temp;
-	int hysteresis;
-};
-
-enum nvbios_therm_fan_mode {
-	NVBIOS_THERM_FAN_TRIP = 0,
-	NVBIOS_THERM_FAN_LINEAR = 1,
-	NVBIOS_THERM_FAN_OTHER = 2,
-};
-
-struct nvbios_therm_fan {
-	enum nvbios_therm_fan_type type;
-
-	u32 pwm_freq;
-
-	u8 min_duty;
-	u8 max_duty;
-
-	u16 bump_period;
-	u16 slow_down_period;
-
-	enum nvbios_therm_fan_mode fan_mode;
-	struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX];
-	u8 nr_fan_trip;
-	u8 linear_min_temp;
-	u8 linear_max_temp;
-};
-
-enum nvbios_therm_domain {
-	NVBIOS_THERM_DOMAIN_CORE,
-	NVBIOS_THERM_DOMAIN_AMBIENT,
-};
-
-int
-nvbios_therm_sensor_parse(struct nouveau_bios *, enum nvbios_therm_domain,
-			  struct nvbios_therm_sensor *);
-
-int
-nvbios_therm_fan_parse(struct nouveau_bios *, struct nvbios_therm_fan *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
deleted file mode 100644
index 76d914b..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __NVBIOS_TIMING_H__
-#define __NVBIOS_TIMING_H__
-
-struct nvbios_ramcfg;
-
-u16 nvbios_timingTe(struct nouveau_bios *,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-u16 nvbios_timingEe(struct nouveau_bios *, int idx,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_timingEp(struct nouveau_bios *, int idx,
-		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		    struct nvbios_ramcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h
deleted file mode 100644
index ad5a8f2..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __NVBIOS_VMAP_H__
-#define __NVBIOS_VMAP_H__
-
-struct nouveau_bios;
-
-struct nvbios_vmap {
-};
-
-u16 nvbios_vmap_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_vmap_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_vmap *);
-
-struct nvbios_vmap_entry {
-	u8  unk0;
-	u8  link;
-	u32 min;
-	u32 max;
-	s32 arg[6];
-};
-
-u16 nvbios_vmap_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
-u16 nvbios_vmap_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
-			    struct nvbios_vmap_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h
deleted file mode 100644
index 6a11dcd..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __NVBIOS_VOLT_H__
-#define __NVBIOS_VOLT_H__
-
-struct nouveau_bios;
-
-struct nvbios_volt {
-	u8  vidmask;
-	u32 min;
-	u32 max;
-	u32 base;
-	s16 step;
-};
-
-u16 nvbios_volt_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_volt_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		      struct nvbios_volt *);
-
-struct nvbios_volt_entry {
-	u32 voltage;
-	u8  vid;
-};
-
-u16 nvbios_volt_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
-u16 nvbios_volt_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
-			    struct nvbios_volt_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
deleted file mode 100644
index 360baab..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __NVBIOS_XPIO_H__
-#define __NVBIOS_XPIO_H__
-
-#define NVBIOS_XPIO_FLAG_AUX  0x10
-#define NVBIOS_XPIO_FLAG_AUX0 0x00
-#define NVBIOS_XPIO_FLAG_AUX1 0x10
-
-struct nvbios_xpio {
-	u8 type;
-	u8 addr;
-	u8 flags;
-};
-
-u16 dcb_xpio_table(struct nouveau_bios *, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_xpio_parse(struct nouveau_bios *, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h
deleted file mode 100644
index 697f7ce..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef __NOUVEAU_BUS_H__
-#define __NOUVEAU_BUS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_bus_intr {
-	u32 stat;
-	u32 unit;
-};
-
-struct nouveau_bus {
-	struct nouveau_subdev base;
-	int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
-	u32 hwsq_size;
-};
-
-static inline struct nouveau_bus *
-nouveau_bus(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BUS];
-}
-
-#define nouveau_bus_create(p, e, o, d)                                         \
-	nouveau_subdev_create_((p), (e), (o), 0, "PBUS", "master",             \
-			       sizeof(**d), (void **)d)
-#define nouveau_bus_destroy(p)                                                 \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_bus_init(p)                                                    \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_bus_fini(p, s)                                                 \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_bus_dtor _nouveau_subdev_dtor
-#define _nouveau_bus_init _nouveau_subdev_init
-#define _nouveau_bus_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass *nv04_bus_oclass;
-extern struct nouveau_oclass *nv31_bus_oclass;
-extern struct nouveau_oclass *nv50_bus_oclass;
-extern struct nouveau_oclass *nv94_bus_oclass;
-extern struct nouveau_oclass *nvc0_bus_oclass;
-
-/* interface to sequencer */
-struct nouveau_hwsq;
-int  nouveau_hwsq_init(struct nouveau_bus *, struct nouveau_hwsq **);
-int  nouveau_hwsq_fini(struct nouveau_hwsq **, bool exec);
-void nouveau_hwsq_wr32(struct nouveau_hwsq *, u32 addr, u32 data);
-void nouveau_hwsq_setf(struct nouveau_hwsq *, u8 flag, int data);
-void nouveau_hwsq_wait(struct nouveau_hwsq *, u8 flag, u8 data);
-void nouveau_hwsq_nsec(struct nouveau_hwsq *, u32 nsec);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
deleted file mode 100644
index 36ed035..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef __NOUVEAU_CLOCK_H__
-#define __NOUVEAU_CLOCK_H__
-
-#include <core/device.h>
-#include <core/subdev.h>
-
-struct nouveau_pll_vals;
-struct nvbios_pll;
-
-enum nv_clk_src {
-	nv_clk_src_crystal,
-	nv_clk_src_href,
-
-	nv_clk_src_hclk,
-	nv_clk_src_hclkm3,
-	nv_clk_src_hclkm3d2,
-	nv_clk_src_hclkm2d3, /* NVAA */
-	nv_clk_src_hclkm4, /* NVAA */
-	nv_clk_src_cclk, /* NVAA */
-
-	nv_clk_src_host,
-
-	nv_clk_src_sppll0,
-	nv_clk_src_sppll1,
-
-	nv_clk_src_mpllsrcref,
-	nv_clk_src_mpllsrc,
-	nv_clk_src_mpll,
-	nv_clk_src_mdiv,
-
-	nv_clk_src_core,
-	nv_clk_src_core_intm,
-	nv_clk_src_shader,
-
-	nv_clk_src_mem,
-
-	nv_clk_src_gpc,
-	nv_clk_src_rop,
-	nv_clk_src_hubk01,
-	nv_clk_src_hubk06,
-	nv_clk_src_hubk07,
-	nv_clk_src_copy,
-	nv_clk_src_daemon,
-	nv_clk_src_disp,
-	nv_clk_src_vdec,
-
-	nv_clk_src_dom6,
-
-	nv_clk_src_max,
-};
-
-struct nouveau_cstate {
-	struct list_head head;
-	u8  voltage;
-	u32 domain[nv_clk_src_max];
-};
-
-struct nouveau_pstate {
-	struct list_head head;
-	struct list_head list; /* c-states */
-	struct nouveau_cstate base;
-	u8 pstate;
-	u8 fanspeed;
-};
-
-struct nouveau_clock {
-	struct nouveau_subdev base;
-
-	struct nouveau_clocks *domains;
-	struct nouveau_pstate bstate;
-
-	struct list_head states;
-	int state_nr;
-
-	struct work_struct work;
-	wait_queue_head_t wait;
-	atomic_t waiting;
-
-	struct nvkm_notify pwrsrc_ntfy;
-	int pwrsrc;
-	int pstate; /* current */
-	int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
-	int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
-	int astate; /* perfmon adjustment (base) */
-	int tstate; /* thermal adjustment (max-) */
-	int dstate; /* display adjustment (min+) */
-
-	bool allow_reclock;
-
-	int  (*read)(struct nouveau_clock *, enum nv_clk_src);
-	int  (*calc)(struct nouveau_clock *, struct nouveau_cstate *);
-	int  (*prog)(struct nouveau_clock *);
-	void (*tidy)(struct nouveau_clock *);
-
-	/*XXX: die, these are here *only* to support the completely
-	 *     bat-shit insane what-was-nouveau_hw.c code
-	 */
-	int (*pll_calc)(struct nouveau_clock *, struct nvbios_pll *,
-			int clk, struct nouveau_pll_vals *pv);
-	int (*pll_prog)(struct nouveau_clock *, u32 reg1,
-			struct nouveau_pll_vals *pv);
-};
-
-static inline struct nouveau_clock *
-nouveau_clock(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_CLOCK];
-}
-
-struct nouveau_clocks {
-	enum nv_clk_src name;
-	u8 bios; /* 0xff for none */
-#define NVKM_CLK_DOM_FLAG_CORE 0x01
-	u8 flags;
-	const char *mname;
-	int mdiv;
-};
-
-#define nouveau_clock_create(p,e,o,i,r,s,n,d)                                  \
-	nouveau_clock_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d),  \
-			      (void **)d)
-#define nouveau_clock_destroy(p) ({                                            \
-	struct nouveau_clock *clk = (p);                                       \
-	_nouveau_clock_dtor(nv_object(clk));                                   \
-})
-#define nouveau_clock_init(p) ({                                               \
-	struct nouveau_clock *clk = (p);                                       \
-	_nouveau_clock_init(nv_object(clk));                                   \
-})
-#define nouveau_clock_fini(p,s) ({                                             \
-	struct nouveau_clock *clk = (p);                                       \
-	_nouveau_clock_fini(nv_object(clk), (s));                              \
-})
-
-int  nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *,
-			   struct nouveau_clocks *, struct nouveau_pstate *,
-			   int, bool, int, void **);
-void _nouveau_clock_dtor(struct nouveau_object *);
-int  _nouveau_clock_init(struct nouveau_object *);
-int  _nouveau_clock_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass nv04_clock_oclass;
-extern struct nouveau_oclass nv40_clock_oclass;
-extern struct nouveau_oclass *nv50_clock_oclass;
-extern struct nouveau_oclass *nv84_clock_oclass;
-extern struct nouveau_oclass *nvaa_clock_oclass;
-extern struct nouveau_oclass nva3_clock_oclass;
-extern struct nouveau_oclass nvc0_clock_oclass;
-extern struct nouveau_oclass nve0_clock_oclass;
-extern struct nouveau_oclass gk20a_clock_oclass;
-
-int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq);
-int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
-			int clk, struct nouveau_pll_vals *);
-int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
-			struct nouveau_pll_vals *);
-int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
-			int clk, struct nouveau_pll_vals *);
-
-int nouveau_clock_ustate(struct nouveau_clock *, int req, int pwr);
-int nouveau_clock_astate(struct nouveau_clock *, int req, int rel);
-int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel);
-int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
deleted file mode 100644
index e007a9d..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_DEVINIT_H__
-#define __NOUVEAU_DEVINIT_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_devinit {
-	struct nouveau_subdev base;
-	bool post;
-	void (*meminit)(struct nouveau_devinit *);
-	int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
-	u32  (*mmio)(struct nouveau_devinit *, u32 addr);
-};
-
-static inline struct nouveau_devinit *
-nouveau_devinit(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT];
-}
-
-extern struct nouveau_oclass *nv04_devinit_oclass;
-extern struct nouveau_oclass *nv05_devinit_oclass;
-extern struct nouveau_oclass *nv10_devinit_oclass;
-extern struct nouveau_oclass *nv1a_devinit_oclass;
-extern struct nouveau_oclass *nv20_devinit_oclass;
-extern struct nouveau_oclass *nv50_devinit_oclass;
-extern struct nouveau_oclass *nv84_devinit_oclass;
-extern struct nouveau_oclass *nv98_devinit_oclass;
-extern struct nouveau_oclass *nva3_devinit_oclass;
-extern struct nouveau_oclass *nvaf_devinit_oclass;
-extern struct nouveau_oclass *nvc0_devinit_oclass;
-extern struct nouveau_oclass *gm107_devinit_oclass;
-extern struct nouveau_oclass *gm204_devinit_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
deleted file mode 100644
index 8d0032f..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef __NOUVEAU_FB_H__
-#define __NOUVEAU_FB_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-#include <subdev/vm.h>
-
-/* memory type/access flags, do not match hardware values */
-#define NV_MEM_ACCESS_RO  1
-#define NV_MEM_ACCESS_WO  2
-#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
-#define NV_MEM_ACCESS_SYS 4
-#define NV_MEM_ACCESS_VM  8
-#define NV_MEM_ACCESS_NOSNOOP 16
-
-#define NV_MEM_TARGET_VRAM        0
-#define NV_MEM_TARGET_PCI         1
-#define NV_MEM_TARGET_PCI_NOSNOOP 2
-#define NV_MEM_TARGET_VM          3
-#define NV_MEM_TARGET_GART        4
-
-#define NV_MEM_TYPE_VM 0x7f
-#define NV_MEM_COMP_VM 0x03
-
-struct nouveau_mem {
-	struct drm_device *dev;
-
-	struct nouveau_vma bar_vma;
-	struct nouveau_vma vma[2];
-	u8  page_shift;
-
-	struct nouveau_mm_node *tag;
-	struct list_head regions;
-	dma_addr_t *pages;
-	u32 memtype;
-	u64 offset;
-	u64 size;
-	struct sg_table *sg;
-};
-
-struct nouveau_fb_tile {
-	struct nouveau_mm_node *tag;
-	u32 addr;
-	u32 limit;
-	u32 pitch;
-	u32 zcomp;
-};
-
-struct nouveau_fb {
-	struct nouveau_subdev base;
-
-	bool (*memtype_valid)(struct nouveau_fb *, u32 memtype);
-
-	struct nouveau_ram *ram;
-
-	struct nouveau_mm vram;
-	struct nouveau_mm tags;
-
-	struct {
-		struct nouveau_fb_tile region[16];
-		int regions;
-		void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
-			     u32 pitch, u32 flags, struct nouveau_fb_tile *);
-		void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
-			     struct nouveau_fb_tile *);
-		void (*fini)(struct nouveau_fb *, int i,
-			     struct nouveau_fb_tile *);
-		void (*prog)(struct nouveau_fb *, int i,
-			     struct nouveau_fb_tile *);
-	} tile;
-};
-
-static inline struct nouveau_fb *
-nouveau_fb(void *obj)
-{
-	/* fbram uses this before device subdev pointer is valid */
-	if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
-	    nv_subidx(obj) == NVDEV_SUBDEV_FB)
-		return obj;
-
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
-}
-
-extern struct nouveau_oclass *nv04_fb_oclass;
-extern struct nouveau_oclass *nv10_fb_oclass;
-extern struct nouveau_oclass *nv1a_fb_oclass;
-extern struct nouveau_oclass *nv20_fb_oclass;
-extern struct nouveau_oclass *nv25_fb_oclass;
-extern struct nouveau_oclass *nv30_fb_oclass;
-extern struct nouveau_oclass *nv35_fb_oclass;
-extern struct nouveau_oclass *nv36_fb_oclass;
-extern struct nouveau_oclass *nv40_fb_oclass;
-extern struct nouveau_oclass *nv41_fb_oclass;
-extern struct nouveau_oclass *nv44_fb_oclass;
-extern struct nouveau_oclass *nv46_fb_oclass;
-extern struct nouveau_oclass *nv47_fb_oclass;
-extern struct nouveau_oclass *nv49_fb_oclass;
-extern struct nouveau_oclass *nv4e_fb_oclass;
-extern struct nouveau_oclass *nv50_fb_oclass;
-extern struct nouveau_oclass *nv84_fb_oclass;
-extern struct nouveau_oclass *nva3_fb_oclass;
-extern struct nouveau_oclass *nvaa_fb_oclass;
-extern struct nouveau_oclass *nvaf_fb_oclass;
-extern struct nouveau_oclass *nvc0_fb_oclass;
-extern struct nouveau_oclass *nve0_fb_oclass;
-extern struct nouveau_oclass *gk20a_fb_oclass;
-extern struct nouveau_oclass *gm107_fb_oclass;
-
-#include <subdev/bios/ramcfg.h>
-
-struct nouveau_ram_data {
-	struct list_head head;
-	struct nvbios_ramcfg bios;
-	u32 freq;
-};
-
-struct nouveau_ram {
-	struct nouveau_object base;
-	enum {
-		NV_MEM_TYPE_UNKNOWN = 0,
-		NV_MEM_TYPE_STOLEN,
-		NV_MEM_TYPE_SGRAM,
-		NV_MEM_TYPE_SDRAM,
-		NV_MEM_TYPE_DDR1,
-		NV_MEM_TYPE_DDR2,
-		NV_MEM_TYPE_DDR3,
-		NV_MEM_TYPE_GDDR2,
-		NV_MEM_TYPE_GDDR3,
-		NV_MEM_TYPE_GDDR4,
-		NV_MEM_TYPE_GDDR5
-	} type;
-	u64 stolen;
-	u64 size;
-	u32 tags;
-
-	int ranks;
-	int parts;
-	int part_mask;
-
-	int  (*get)(struct nouveau_fb *, u64 size, u32 align,
-		    u32 size_nc, u32 type, struct nouveau_mem **);
-	void (*put)(struct nouveau_fb *, struct nouveau_mem **);
-
-	int  (*calc)(struct nouveau_fb *, u32 freq);
-	int  (*prog)(struct nouveau_fb *);
-	void (*tidy)(struct nouveau_fb *);
-	u32 freq;
-	u32 mr[16];
-	u32 mr1_nuts;
-
-	struct nouveau_ram_data *next;
-	struct nouveau_ram_data former;
-	struct nouveau_ram_data xition;
-	struct nouveau_ram_data target;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
deleted file mode 100644
index 0f7fc0c..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __NOUVEAU_FB_REGS_04_H__
-#define __NOUVEAU_FB_REGS_04_H__
-
-#define NV04_PFB_BOOT_0						0x00100000
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT			0x00000003
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB			0x00000000
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB			0x00000001
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB			0x00000002
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB			0x00000003
-#	define NV04_PFB_BOOT_0_RAM_WIDTH_128			0x00000004
-#	define NV04_PFB_BOOT_0_RAM_TYPE				0x00000028
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT		0x00000000
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT		0x00000008
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK	0x00000010
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT		0x00000018
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT		0x00000020
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16		0x00000028
-#	define NV04_PFB_BOOT_0_UMA_ENABLE			0x00000100
-#	define NV04_PFB_BOOT_0_UMA_SIZE				0x0000f000
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h b/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
deleted file mode 100644
index 2b1ddb2..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NOUVEAU_FUSE_H__
-#define __NOUVEAU_FUSE_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_fuse {
-	struct nouveau_subdev base;
-};
-
-static inline struct nouveau_fuse *
-nouveau_fuse(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FUSE];
-}
-
-#define nouveau_fuse_create(p, e, o, d)                                        \
-	nouveau_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
-
-int  nouveau_fuse_create_(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, int, void **);
-void _nouveau_fuse_dtor(struct nouveau_object *);
-int  _nouveau_fuse_init(struct nouveau_object *);
-#define _nouveau_fuse_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass g80_fuse_oclass;
-extern struct nouveau_oclass gf100_fuse_oclass;
-extern struct nouveau_oclass gm107_fuse_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
deleted file mode 100644
index f855140..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __NOUVEAU_GPIO_H__
-#define __NOUVEAU_GPIO_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-
-struct nvkm_gpio_ntfy_req {
-#define NVKM_GPIO_HI                                                       0x01
-#define NVKM_GPIO_LO                                                       0x02
-#define NVKM_GPIO_TOGGLED                                                  0x03
-	u8 mask;
-	u8 line;
-};
-
-struct nvkm_gpio_ntfy_rep {
-	u8 mask;
-};
-
-struct nouveau_gpio {
-	struct nouveau_subdev base;
-
-	struct nvkm_event event;
-
-	void (*reset)(struct nouveau_gpio *, u8 func);
-	int  (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
-		     struct dcb_gpio_func *);
-	int  (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
-	int  (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
-};
-
-static inline struct nouveau_gpio *
-nouveau_gpio(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
-}
-
-extern struct nouveau_oclass *nv10_gpio_oclass;
-extern struct nouveau_oclass *nv50_gpio_oclass;
-extern struct nouveau_oclass *nv94_gpio_oclass;
-extern struct nouveau_oclass *nvd0_gpio_oclass;
-extern struct nouveau_oclass *nve0_gpio_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
deleted file mode 100644
index d94ccac..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef __NOUVEAU_I2C_H__
-#define __NOUVEAU_I2C_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/i2c.h>
-
-#define NV_I2C_PORT(n)    (0x00 + (n))
-#define NV_I2C_AUX(n)     (0x10 + (n))
-#define NV_I2C_EXT(n)     (0x20 + (n))
-#define NV_I2C_DEFAULT(n) (0x80 + (n))
-
-#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
-#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
-#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
-
-struct nvkm_i2c_ntfy_req {
-#define NVKM_I2C_PLUG                                                      0x01
-#define NVKM_I2C_UNPLUG                                                    0x02
-#define NVKM_I2C_IRQ                                                       0x04
-#define NVKM_I2C_DONE                                                      0x08
-#define NVKM_I2C_ANY                                                       0x0f
-	u8 mask;
-	u8 port;
-};
-
-struct nvkm_i2c_ntfy_rep {
-	u8 mask;
-};
-
-struct nouveau_i2c_port {
-	struct nouveau_object base;
-	struct i2c_adapter adapter;
-	struct mutex mutex;
-
-	struct list_head head;
-	u8  index;
-	int aux;
-
-	const struct nouveau_i2c_func *func;
-};
-
-struct nouveau_i2c_func {
-	void (*drive_scl)(struct nouveau_i2c_port *, int);
-	void (*drive_sda)(struct nouveau_i2c_port *, int);
-	int  (*sense_scl)(struct nouveau_i2c_port *);
-	int  (*sense_sda)(struct nouveau_i2c_port *);
-
-	int  (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
-	int  (*pattern)(struct nouveau_i2c_port *, int pattern);
-	int  (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
-	int  (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
-};
-
-struct nouveau_i2c_board_info {
-	struct i2c_board_info dev;
-	u8 udelay; /* set to 0 to use the standard delay */
-};
-
-struct nouveau_i2c {
-	struct nouveau_subdev base;
-	struct nvkm_event event;
-
-	struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
-	struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
-	int  (*acquire_pad)(struct nouveau_i2c_port *, unsigned long timeout);
-	void (*release_pad)(struct nouveau_i2c_port *);
-	int  (*acquire)(struct nouveau_i2c_port *, unsigned long timeout);
-	void (*release)(struct nouveau_i2c_port *);
-	int (*identify)(struct nouveau_i2c *, int index,
-			const char *what, struct nouveau_i2c_board_info *,
-			bool (*match)(struct nouveau_i2c_port *,
-				      struct i2c_board_info *, void *), void *);
-
-	wait_queue_head_t wait;
-	struct list_head ports;
-};
-
-static inline struct nouveau_i2c *
-nouveau_i2c(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
-}
-
-extern struct nouveau_oclass *nv04_i2c_oclass;
-extern struct nouveau_oclass *nv4e_i2c_oclass;
-extern struct nouveau_oclass *nv50_i2c_oclass;
-extern struct nouveau_oclass *nv94_i2c_oclass;
-extern struct nouveau_oclass *nvd0_i2c_oclass;
-extern struct nouveau_oclass *gf117_i2c_oclass;
-extern struct nouveau_oclass *nve0_i2c_oclass;
-extern struct nouveau_oclass *gm204_i2c_oclass;
-
-static inline int
-nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
-{
-	u8 val;
-	struct i2c_msg msgs[] = {
-		{ .addr = addr, .flags = 0, .len = 1, .buf = &reg },
-		{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
-	};
-
-	int ret = i2c_transfer(&port->adapter, msgs, 2);
-	if (ret != 2)
-		return -EIO;
-
-	return val;
-}
-
-static inline int
-nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
-{
-	u8 buf[2] = { reg, val };
-	struct i2c_msg msgs[] = {
-		{ .addr = addr, .flags = 0, .len = 2, .buf = buf },
-	};
-
-	int ret = i2c_transfer(&port->adapter, msgs, 1);
-	if (ret != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static inline bool
-nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
-{
-	return nv_rdi2cr(port, addr, 0) >= 0;
-}
-
-int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
-int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h
deleted file mode 100644
index 31df634..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_IBUS_H__
-#define __NOUVEAU_IBUS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_ibus {
-	struct nouveau_subdev base;
-};
-
-static inline struct nouveau_ibus *
-nouveau_ibus(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_IBUS];
-}
-
-#define nouveau_ibus_create(p,e,o,d)                                           \
-	nouveau_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus",              \
-			       sizeof(**d), (void **)d)
-#define nouveau_ibus_destroy(p)                                                \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_ibus_init(p)                                                   \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_ibus_fini(p,s)                                                 \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_ibus_dtor _nouveau_subdev_dtor
-#define _nouveau_ibus_init _nouveau_subdev_init
-#define _nouveau_ibus_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nvc0_ibus_oclass;
-extern struct nouveau_oclass nve0_ibus_oclass;
-extern struct nouveau_oclass gk20a_ibus_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
deleted file mode 100644
index c1df26f..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef __NOUVEAU_INSTMEM_H__
-#define __NOUVEAU_INSTMEM_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-struct nouveau_instobj {
-	struct nouveau_object base;
-	struct list_head head;
-	u32 *suspend;
-	u64 addr;
-	u32 size;
-};
-
-static inline struct nouveau_instobj *
-nv_memobj(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS)))
-		nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj));
-#endif
-	return obj;
-}
-
-struct nouveau_instmem {
-	struct nouveau_subdev base;
-	struct list_head list;
-
-	u32 reserved;
-	int (*alloc)(struct nouveau_instmem *, struct nouveau_object *,
-		     u32 size, u32 align, struct nouveau_object **);
-};
-
-static inline struct nouveau_instmem *
-nouveau_instmem(void *obj)
-{
-	/* nv04/nv40 impls need to create objects in their constructor,
-	 * which is before the subdev pointer is valid
-	 */
-	if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
-	    nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM)
-		return obj;
-
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_INSTMEM];
-}
-
-extern struct nouveau_oclass *nv04_instmem_oclass;
-extern struct nouveau_oclass *nv40_instmem_oclass;
-extern struct nouveau_oclass *nv50_instmem_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h
deleted file mode 100644
index b909a73..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_LTC_H__
-#define __NOUVEAU_LTC_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#define NOUVEAU_LTC_MAX_ZBC_CNT 16
-
-struct nouveau_mm_node;
-
-struct nouveau_ltc {
-	struct nouveau_subdev base;
-
-	int  (*tags_alloc)(struct nouveau_ltc *, u32 count,
-	                   struct nouveau_mm_node **);
-	void (*tags_free)(struct nouveau_ltc *, struct nouveau_mm_node **);
-	void (*tags_clear)(struct nouveau_ltc *, u32 first, u32 count);
-
-	int zbc_min;
-	int zbc_max;
-	int (*zbc_color_get)(struct nouveau_ltc *, int index, const u32[4]);
-	int (*zbc_depth_get)(struct nouveau_ltc *, int index, const u32);
-};
-
-static inline struct nouveau_ltc *
-nouveau_ltc(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTC];
-}
-
-extern struct nouveau_oclass *gf100_ltc_oclass;
-extern struct nouveau_oclass *gk104_ltc_oclass;
-extern struct nouveau_oclass *gm107_ltc_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
deleted file mode 100644
index 568e4df..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NOUVEAU_MC_H__
-#define __NOUVEAU_MC_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_mc {
-	struct nouveau_subdev base;
-	bool use_msi;
-	unsigned int irq;
-	void (*unk260)(struct nouveau_mc *, u32);
-};
-
-static inline struct nouveau_mc *
-nouveau_mc(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
-}
-
-extern struct nouveau_oclass *nv04_mc_oclass;
-extern struct nouveau_oclass *nv40_mc_oclass;
-extern struct nouveau_oclass *nv44_mc_oclass;
-extern struct nouveau_oclass *nv4c_mc_oclass;
-extern struct nouveau_oclass *nv50_mc_oclass;
-extern struct nouveau_oclass *nv94_mc_oclass;
-extern struct nouveau_oclass *nv98_mc_oclass;
-extern struct nouveau_oclass *nvc0_mc_oclass;
-extern struct nouveau_oclass *nvc3_mc_oclass;
-extern struct nouveau_oclass *gk20a_mc_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
deleted file mode 100644
index b93b152..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NOUVEAU_MXM_H__
-#define __NOUVEAU_MXM_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#define MXM_SANITISE_DCB 0x00000001
-
-struct nouveau_mxm {
-	struct nouveau_subdev base;
-	u32 action;
-	u8 *mxms;
-};
-
-static inline struct nouveau_mxm *
-nouveau_mxm(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MXM];
-}
-
-#define nouveau_mxm_create(p,e,o,d)                                            \
-	nouveau_mxm_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_mxm_init(p)                                                    \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_mxm_fini(p,s)                                                  \
-	nouveau_subdev_fini(&(p)->base, (s))
-int  nouveau_mxm_create_(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, int, void **);
-void nouveau_mxm_destroy(struct nouveau_mxm *);
-
-#define _nouveau_mxm_dtor _nouveau_subdev_dtor
-#define _nouveau_mxm_init _nouveau_subdev_init
-#define _nouveau_mxm_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv50_mxm_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
deleted file mode 100644
index f2427bf..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NOUVEAU_PWR_H__
-#define __NOUVEAU_PWR_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_pwr {
-	struct nouveau_subdev base;
-
-	struct {
-		u32 base;
-		u32 size;
-	} send;
-
-	struct {
-		u32 base;
-		u32 size;
-
-		struct work_struct work;
-		wait_queue_head_t wait;
-		u32 process;
-		u32 message;
-		u32 data[2];
-	} recv;
-
-	int  (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32);
-	void (*pgob)(struct nouveau_pwr *, bool);
-};
-
-static inline struct nouveau_pwr *
-nouveau_pwr(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_PWR];
-}
-
-extern struct nouveau_oclass *nva3_pwr_oclass;
-extern struct nouveau_oclass *nvc0_pwr_oclass;
-extern struct nouveau_oclass *nvd0_pwr_oclass;
-extern struct nouveau_oclass *gk104_pwr_oclass;
-extern struct nouveau_oclass *nv108_pwr_oclass;
-
-/* interface to MEMX process running on PPWR */
-struct nouveau_memx;
-int  nouveau_memx_init(struct nouveau_pwr *, struct nouveau_memx **);
-int  nouveau_memx_fini(struct nouveau_memx **, bool exec);
-void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data);
-void nouveau_memx_wait(struct nouveau_memx *,
-		       u32 addr, u32 mask, u32 data, u32 nsec);
-void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
-void nouveau_memx_wait_vblank(struct nouveau_memx *);
-void nouveau_memx_train(struct nouveau_memx *);
-int  nouveau_memx_train_result(struct nouveau_pwr *, u32 *, int);
-void nouveau_memx_block(struct nouveau_memx *);
-void nouveau_memx_unblock(struct nouveau_memx *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
deleted file mode 100644
index a437597..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __NOUVEAU_THERM_H__
-#define __NOUVEAU_THERM_H__
-
-#include <core/device.h>
-#include <core/subdev.h>
-
-enum nouveau_therm_fan_mode {
-	NOUVEAU_THERM_CTRL_NONE = 0,
-	NOUVEAU_THERM_CTRL_MANUAL = 1,
-	NOUVEAU_THERM_CTRL_AUTO = 2,
-};
-
-enum nouveau_therm_attr_type {
-	NOUVEAU_THERM_ATTR_FAN_MIN_DUTY = 0,
-	NOUVEAU_THERM_ATTR_FAN_MAX_DUTY = 1,
-	NOUVEAU_THERM_ATTR_FAN_MODE = 2,
-
-	NOUVEAU_THERM_ATTR_THRS_FAN_BOOST = 10,
-	NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
-	NOUVEAU_THERM_ATTR_THRS_DOWN_CLK = 12,
-	NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
-	NOUVEAU_THERM_ATTR_THRS_CRITICAL = 14,
-	NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST = 15,
-	NOUVEAU_THERM_ATTR_THRS_SHUTDOWN = 16,
-	NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
-};
-
-struct nouveau_therm {
-	struct nouveau_subdev base;
-
-	int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
-	int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
-	int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
-	int (*pwm_clock)(struct nouveau_therm *, int line);
-
-	int (*fan_get)(struct nouveau_therm *);
-	int (*fan_set)(struct nouveau_therm *, int);
-	int (*fan_sense)(struct nouveau_therm *);
-
-	int (*temp_get)(struct nouveau_therm *);
-
-	int (*attr_get)(struct nouveau_therm *, enum nouveau_therm_attr_type);
-	int (*attr_set)(struct nouveau_therm *,
-			enum nouveau_therm_attr_type, int);
-};
-
-static inline struct nouveau_therm *
-nouveau_therm(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_THERM];
-}
-
-#define nouveau_therm_create(p,e,o,d)                                          \
-	nouveau_therm_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_therm_destroy(p) ({                                            \
-	struct nouveau_therm *therm = (p);                                     \
-        _nouveau_therm_dtor(nv_object(therm));                                 \
-})
-#define nouveau_therm_init(p) ({                                               \
-	struct nouveau_therm *therm = (p);                                     \
-        _nouveau_therm_init(nv_object(therm));                                 \
-})
-#define nouveau_therm_fini(p,s) ({                                             \
-	struct nouveau_therm *therm = (p);                                     \
-        _nouveau_therm_init(nv_object(therm), (s));                            \
-})
-
-int  nouveau_therm_create_(struct nouveau_object *, struct nouveau_object *,
-			   struct nouveau_oclass *, int, void **);
-void _nouveau_therm_dtor(struct nouveau_object *);
-int  _nouveau_therm_init(struct nouveau_object *);
-int  _nouveau_therm_fini(struct nouveau_object *, bool);
-
-int  nouveau_therm_cstate(struct nouveau_therm *, int, int);
-
-extern struct nouveau_oclass nv40_therm_oclass;
-extern struct nouveau_oclass nv50_therm_oclass;
-extern struct nouveau_oclass nv84_therm_oclass;
-extern struct nouveau_oclass nva3_therm_oclass;
-extern struct nouveau_oclass nvd0_therm_oclass;
-extern struct nouveau_oclass gm107_therm_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
deleted file mode 100644
index db9be80..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __NOUVEAU_TIMER_H__
-#define __NOUVEAU_TIMER_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_alarm {
-	struct list_head head;
-	u64 timestamp;
-	void (*func)(struct nouveau_alarm *);
-};
-
-static inline void
-nouveau_alarm_init(struct nouveau_alarm *alarm,
-		   void (*func)(struct nouveau_alarm *))
-{
-	INIT_LIST_HEAD(&alarm->head);
-	alarm->func = func;
-}
-
-bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
-void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
-void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *);
-
-#define NV_WAIT_DEFAULT 2000000000ULL
-#define nv_wait(o,a,m,v)                                                       \
-	nouveau_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
-#define nv_wait_ne(o,a,m,v)                                                    \
-	nouveau_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v))
-#define nv_wait_cb(o,c,d)                                                      \
-	nouveau_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d))
-
-struct nouveau_timer {
-	struct nouveau_subdev base;
-	u64  (*read)(struct nouveau_timer *);
-	void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
-	void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *);
-};
-
-static inline struct nouveau_timer *
-nouveau_timer(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_TIMER];
-}
-
-#define nouveau_timer_create(p,e,o,d)                                          \
-	nouveau_subdev_create_((p), (e), (o), 0, "PTIMER", "timer",            \
-			       sizeof(**d), (void **)d)
-#define nouveau_timer_destroy(p)                                               \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_timer_init(p)                                                  \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_timer_fini(p,s)                                                \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *,
-			  struct nouveau_oclass *, int size, void **);
-
-extern struct nouveau_oclass nv04_timer_oclass;
-extern struct nouveau_oclass gk20a_timer_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
deleted file mode 100644
index c950903..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NOUVEAU_VM_H__
-#define __NOUVEAU_VM_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-struct nouveau_vm_pgt {
-	struct nouveau_gpuobj *obj[2];
-	u32 refcount[2];
-};
-
-struct nouveau_vm_pgd {
-	struct list_head head;
-	struct nouveau_gpuobj *obj;
-};
-
-struct nouveau_gpuobj;
-struct nouveau_mem;
-
-struct nouveau_vma {
-	struct list_head head;
-	int refcount;
-	struct nouveau_vm *vm;
-	struct nouveau_mm_node *node;
-	u64 offset;
-	u32 access;
-};
-
-struct nouveau_vm {
-	struct nouveau_vmmgr *vmm;
-	struct nouveau_mm mm;
-	struct kref refcount;
-
-	struct list_head pgd_list;
-	atomic_t engref[NVDEV_SUBDEV_NR];
-
-	struct nouveau_vm_pgt *pgt;
-	u32 fpde;
-	u32 lpde;
-};
-
-struct nouveau_vmmgr {
-	struct nouveau_subdev base;
-
-	u64 limit;
-	u8  dma_bits;
-	u32 pgt_bits;
-	u8  spg_shift;
-	u8  lpg_shift;
-
-	int  (*create)(struct nouveau_vmmgr *, u64 offset, u64 length,
-		       u64 mm_offset, struct nouveau_vm **);
-
-	void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde,
-			struct nouveau_gpuobj *pgt[2]);
-	void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *,
-		    struct nouveau_mem *, u32 pte, u32 cnt,
-		    u64 phys, u64 delta);
-	void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *,
-		       struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
-	void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt);
-	void (*flush)(struct nouveau_vm *);
-};
-
-static inline struct nouveau_vmmgr *
-nouveau_vmmgr(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VM];
-}
-
-#define nouveau_vmmgr_create(p,e,o,i,f,d)                                      \
-	nouveau_subdev_create((p), (e), (o), 0, (i), (f), (d))
-#define nouveau_vmmgr_destroy(p)                                               \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_vmmgr_init(p)                                                  \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_vmmgr_fini(p,s)                                                \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_vmmgr_dtor _nouveau_subdev_dtor
-#define _nouveau_vmmgr_init _nouveau_subdev_init
-#define _nouveau_vmmgr_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv04_vmmgr_oclass;
-extern struct nouveau_oclass nv41_vmmgr_oclass;
-extern struct nouveau_oclass nv44_vmmgr_oclass;
-extern struct nouveau_oclass nv50_vmmgr_oclass;
-extern struct nouveau_oclass nvc0_vmmgr_oclass;
-
-int  nv04_vm_create(struct nouveau_vmmgr *, u64, u64, u64,
-		    struct nouveau_vm **);
-void nv04_vmmgr_dtor(struct nouveau_object *);
-
-/* nouveau_vm.c */
-int  nouveau_vm_create(struct nouveau_vmmgr *, u64 offset, u64 length,
-		       u64 mm_offset, u32 block, struct nouveau_vm **);
-int  nouveau_vm_new(struct nouveau_device *, u64 offset, u64 length,
-		    u64 mm_offset, struct nouveau_vm **);
-int  nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **,
-		    struct nouveau_gpuobj *pgd);
-int  nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift,
-		    u32 access, struct nouveau_vma *);
-void nouveau_vm_put(struct nouveau_vma *);
-void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *);
-void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *);
-void nouveau_vm_unmap(struct nouveau_vma *);
-void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
deleted file mode 100644
index 67db5e5..0000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __NOUVEAU_VOLT_H__
-#define __NOUVEAU_VOLT_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_voltage {
-	u32 uv;
-	u8  id;
-};
-
-struct nouveau_volt {
-	struct nouveau_subdev base;
-
-	int (*vid_get)(struct nouveau_volt *);
-	int (*get)(struct nouveau_volt *);
-	int (*vid_set)(struct nouveau_volt *, u8 vid);
-	int (*set)(struct nouveau_volt *, u32 uv);
-	int (*set_id)(struct nouveau_volt *, u8 id, int condition);
-
-	u8 vid_mask;
-	u8 vid_nr;
-	struct {
-		u32 uv;
-		u8 vid;
-	} vid[256];
-};
-
-static inline struct nouveau_volt *
-nouveau_volt(void *obj)
-{
-	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VOLT];
-}
-
-#define nouveau_volt_create(p, e, o, d)                                        \
-	nouveau_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_volt_destroy(p) ({                                             \
-	struct nouveau_volt *v = (p);                                          \
-	_nouveau_volt_dtor(nv_object(v));                                      \
-})
-#define nouveau_volt_init(p) ({                                                \
-	struct nouveau_volt *v = (p);                                          \
-	_nouveau_volt_init(nv_object(v));                                      \
-})
-#define nouveau_volt_fini(p,s)                                                 \
-	nouveau_subdev_fini((p), (s))
-
-int  nouveau_volt_create_(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, int, void **);
-void _nouveau_volt_dtor(struct nouveau_object *);
-int  _nouveau_volt_init(struct nouveau_object *);
-#define _nouveau_volt_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv40_volt_oclass;
-extern struct nouveau_oclass gk20a_volt_oclass;
-
-int nouveau_voltgpio_init(struct nouveau_volt *);
-int nouveau_voltgpio_get(struct nouveau_volt *);
-int nouveau_voltgpio_set(struct nouveau_volt *, u8);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
deleted file mode 100644
index b1adc69..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nouveau_barobj {
-	struct nouveau_object base;
-	struct nouveau_vma vma;
-	void __iomem *iomem;
-};
-
-static int
-nouveau_barobj_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 size,
-		    struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_bar *bar = (void *)engine;
-	struct nouveau_mem *mem = data;
-	struct nouveau_barobj *barobj;
-	int ret;
-
-	ret = nouveau_object_create(parent, engine, oclass, 0, &barobj);
-	*pobject = nv_object(barobj);
-	if (ret)
-		return ret;
-
-	ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma);
-	if (ret)
-		return ret;
-
-	barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
-				(u32)barobj->vma.offset, mem->size << 12);
-	if (!barobj->iomem) {
-		nv_warn(bar, "PRAMIN ioremap failed\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void
-nouveau_barobj_dtor(struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = (void *)object->engine;
-	struct nouveau_barobj *barobj = (void *)object;
-	if (barobj->vma.node) {
-		if (barobj->iomem)
-			iounmap(barobj->iomem);
-		bar->unmap(bar, &barobj->vma);
-	}
-	nouveau_object_destroy(&barobj->base);
-}
-
-static u32
-nouveau_barobj_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_barobj *barobj = (void *)object;
-	return ioread32_native(barobj->iomem + addr);
-}
-
-static void
-nouveau_barobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_barobj *barobj = (void *)object;
-	iowrite32_native(data, barobj->iomem + addr);
-}
-
-static struct nouveau_oclass
-nouveau_barobj_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nouveau_barobj_ctor,
-		.dtor = nouveau_barobj_dtor,
-		.init = nouveau_object_init,
-		.fini = nouveau_object_fini,
-		.rd32 = nouveau_barobj_rd32,
-		.wr32 = nouveau_barobj_wr32,
-	},
-};
-
-int
-nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
-		  struct nouveau_mem *mem, struct nouveau_object **pobject)
-{
-	struct nouveau_object *engine = nv_object(bar);
-	struct nouveau_object *gpuobj;
-	int ret = nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
-				      mem, 0, &gpuobj);
-	if (ret == 0)
-		*pobject = gpuobj;
-	return ret;
-}
-
-int
-nouveau_bar_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_bar *bar;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "BARCTL",
-				     "bar", length, pobject);
-	bar = *pobject;
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-void
-nouveau_bar_destroy(struct nouveau_bar *bar)
-{
-	nouveau_subdev_destroy(&bar->base);
-}
-
-void
-_nouveau_bar_dtor(struct nouveau_object *object)
-{
-	struct nouveau_bar *bar = (void *)object;
-	nouveau_bar_destroy(bar);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c
deleted file mode 100644
index bf877af..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 <subdev/bar.h>
-
-#include "priv.h"
-
-int
-gk20a_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nouveau_bar *bar;
-	int ret;
-
-	ret = nvc0_bar_ctor(parent, engine, oclass, data, size, pobject);
-	if (ret)
-		return ret;
-
-	bar = (struct nouveau_bar *)*pobject;
-	bar->iomap_uncached = true;
-
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_bar_oclass = {
-	.handle = NV_SUBDEV(BAR, 0xea),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_bar_ctor,
-		.dtor = nvc0_bar_dtor,
-		.init = nvc0_bar_init,
-		.fini = _nouveau_bar_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
deleted file mode 100644
index f748ba4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nv50_bar_priv {
-	struct nouveau_bar base;
-	spinlock_t lock;
-	struct nouveau_gpuobj *mem;
-	struct nouveau_gpuobj *pad;
-	struct nouveau_gpuobj *pgd;
-	struct nouveau_vm *bar1_vm;
-	struct nouveau_gpuobj *bar1;
-	struct nouveau_vm *bar3_vm;
-	struct nouveau_gpuobj *bar3;
-};
-
-static int
-nv50_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
-	      u32 flags, struct nouveau_vma *vma)
-{
-	struct nv50_bar_priv *priv = (void *)bar;
-	int ret;
-
-	ret = nouveau_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma);
-	if (ret)
-		return ret;
-
-	nouveau_vm_map(vma, mem);
-	return 0;
-}
-
-static int
-nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
-	      u32 flags, struct nouveau_vma *vma)
-{
-	struct nv50_bar_priv *priv = (void *)bar;
-	int ret;
-
-	ret = nouveau_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma);
-	if (ret)
-		return ret;
-
-	nouveau_vm_map(vma, mem);
-	return 0;
-}
-
-static void
-nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
-{
-	nouveau_vm_unmap(vma);
-	nouveau_vm_put(vma);
-}
-
-static void
-nv50_bar_flush(struct nouveau_bar *bar)
-{
-	struct nv50_bar_priv *priv = (void *)bar;
-	unsigned long flags;
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_wr32(priv, 0x00330c, 0x00000001);
-	if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000))
-		nv_warn(priv, "flush timeout\n");
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-void
-nv84_bar_flush(struct nouveau_bar *bar)
-{
-	struct nv50_bar_priv *priv = (void *)bar;
-	unsigned long flags;
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_wr32(bar, 0x070000, 0x00000001);
-	if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000))
-		nv_warn(priv, "flush timeout\n");
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int
-nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_object *heap;
-	struct nouveau_vm *vm;
-	struct nv50_bar_priv *priv;
-	u64 start, limit;
-	int ret;
-
-	ret = nouveau_bar_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
-				 NVOBJ_FLAG_HEAP, &priv->mem);
-	heap = nv_object(priv->mem);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), heap,
-				(device->chipset == 0x50) ? 0x1400 : 0x0200,
-				 0, 0, &priv->pad);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), heap, 0x4000, 0,
-				 0, &priv->pgd);
-	if (ret)
-		return ret;
-
-	/* BAR3 */
-	start = 0x0100000000ULL;
-	limit = start + nv_device_resource_len(device, 3);
-
-	ret = nouveau_vm_new(device, start, limit, start, &vm);
-	if (ret)
-		return ret;
-
-	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
-	ret = nouveau_gpuobj_new(nv_object(priv), heap,
-				 ((limit-- - start) >> 12) * 8, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
-	vm->pgt[0].refcount[0] = 1;
-	if (ret)
-		return ret;
-
-	ret = nouveau_vm_ref(vm, &priv->bar3_vm, priv->pgd);
-	nouveau_vm_ref(NULL, &vm, NULL);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3);
-	if (ret)
-		return ret;
-
-	nv_wo32(priv->bar3, 0x00, 0x7fc00000);
-	nv_wo32(priv->bar3, 0x04, lower_32_bits(limit));
-	nv_wo32(priv->bar3, 0x08, lower_32_bits(start));
-	nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 |
-				  upper_32_bits(start));
-	nv_wo32(priv->bar3, 0x10, 0x00000000);
-	nv_wo32(priv->bar3, 0x14, 0x00000000);
-
-	/* BAR1 */
-	start = 0x0000000000ULL;
-	limit = start + nv_device_resource_len(device, 1);
-
-	ret = nouveau_vm_new(device, start, limit--, start, &vm);
-	if (ret)
-		return ret;
-
-	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
-	ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd);
-	nouveau_vm_ref(NULL, &vm, NULL);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1);
-	if (ret)
-		return ret;
-
-	nv_wo32(priv->bar1, 0x00, 0x7fc00000);
-	nv_wo32(priv->bar1, 0x04, lower_32_bits(limit));
-	nv_wo32(priv->bar1, 0x08, lower_32_bits(start));
-	nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 |
-				  upper_32_bits(start));
-	nv_wo32(priv->bar1, 0x10, 0x00000000);
-	nv_wo32(priv->bar1, 0x14, 0x00000000);
-
-	priv->base.alloc = nouveau_bar_alloc;
-	priv->base.kmap = nv50_bar_kmap;
-	priv->base.umap = nv50_bar_umap;
-	priv->base.unmap = nv50_bar_unmap;
-	if (device->chipset == 0x50)
-		priv->base.flush = nv50_bar_flush;
-	else
-		priv->base.flush = nv84_bar_flush;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-static void
-nv50_bar_dtor(struct nouveau_object *object)
-{
-	struct nv50_bar_priv *priv = (void *)object;
-	nouveau_gpuobj_ref(NULL, &priv->bar1);
-	nouveau_vm_ref(NULL, &priv->bar1_vm, priv->pgd);
-	nouveau_gpuobj_ref(NULL, &priv->bar3);
-	if (priv->bar3_vm) {
-		nouveau_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]);
-		nouveau_vm_ref(NULL, &priv->bar3_vm, priv->pgd);
-	}
-	nouveau_gpuobj_ref(NULL, &priv->pgd);
-	nouveau_gpuobj_ref(NULL, &priv->pad);
-	nouveau_gpuobj_ref(NULL, &priv->mem);
-	nouveau_bar_destroy(&priv->base);
-}
-
-static int
-nv50_bar_init(struct nouveau_object *object)
-{
-	struct nv50_bar_priv *priv = (void *)object;
-	int ret, i;
-
-	ret = nouveau_bar_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
-	nv_wr32(priv, 0x100c80, 0x00060001);
-	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
-		nv_error(priv, "vm flush timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
-	nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
-	nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4);
-	nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4);
-	for (i = 0; i < 8; i++)
-		nv_wr32(priv, 0x001900 + (i * 4), 0x00000000);
-	return 0;
-}
-
-static int
-nv50_bar_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_bar_priv *priv = (void *)object;
-	return nouveau_bar_fini(&priv->base, suspend);
-}
-
-struct nouveau_oclass
-nv50_bar_oclass = {
-	.handle = NV_SUBDEV(BAR, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_bar_ctor,
-		.dtor = nv50_bar_dtor,
-		.init = nv50_bar_init,
-		.fini = nv50_bar_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
deleted file mode 100644
index 05a278b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nvc0_bar_priv_vm {
-	struct nouveau_gpuobj *mem;
-	struct nouveau_gpuobj *pgd;
-	struct nouveau_vm *vm;
-};
-
-struct nvc0_bar_priv {
-	struct nouveau_bar base;
-	spinlock_t lock;
-	struct nvc0_bar_priv_vm bar[2];
-};
-
-static int
-nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
-	      u32 flags, struct nouveau_vma *vma)
-{
-	struct nvc0_bar_priv *priv = (void *)bar;
-	int ret;
-
-	ret = nouveau_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma);
-	if (ret)
-		return ret;
-
-	nouveau_vm_map(vma, mem);
-	return 0;
-}
-
-static int
-nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
-	      u32 flags, struct nouveau_vma *vma)
-{
-	struct nvc0_bar_priv *priv = (void *)bar;
-	int ret;
-
-	ret = nouveau_vm_get(priv->bar[1].vm, mem->size << 12,
-			     mem->page_shift, flags, vma);
-	if (ret)
-		return ret;
-
-	nouveau_vm_map(vma, mem);
-	return 0;
-}
-
-static void
-nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
-{
-	nouveau_vm_unmap(vma);
-	nouveau_vm_put(vma);
-}
-
-static int
-nvc0_bar_init_vm(struct nvc0_bar_priv *priv, struct nvc0_bar_priv_vm *bar_vm,
-		 int bar_nr)
-{
-	struct nouveau_device *device = nv_device(&priv->base);
-	struct nouveau_vm *vm;
-	resource_size_t bar_len;
-	int ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
-				&bar_vm->mem);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
-				&bar_vm->pgd);
-	if (ret)
-		return ret;
-
-	bar_len = nv_device_resource_len(device, bar_nr);
-
-	ret = nouveau_vm_new(device, 0, bar_len, 0, &vm);
-	if (ret)
-		return ret;
-
-	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
-	/*
-	 * Bootstrap page table lookup.
-	 */
-	if (bar_nr == 3) {
-		ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-					 (bar_len >> 12) * 8, 0x1000,
-					 NVOBJ_FLAG_ZERO_ALLOC,
-					&vm->pgt[0].obj[0]);
-		vm->pgt[0].refcount[0] = 1;
-		if (ret)
-			return ret;
-	}
-
-	ret = nouveau_vm_ref(vm, &bar_vm->vm, bar_vm->pgd);
-	nouveau_vm_ref(NULL, &vm, NULL);
-	if (ret)
-		return ret;
-
-	nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr));
-	nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr));
-	nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1));
-	nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1));
-
-	return 0;
-}
-
-int
-nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nvc0_bar_priv *priv;
-	bool has_bar3 = nv_device_resource_len(device, 3) != 0;
-	int ret;
-
-	ret = nouveau_bar_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	/* BAR3 */
-	if (has_bar3) {
-		ret = nvc0_bar_init_vm(priv, &priv->bar[0], 3);
-		if (ret)
-			return ret;
-		priv->base.alloc = nouveau_bar_alloc;
-		priv->base.kmap = nvc0_bar_kmap;
-	}
-
-	/* BAR1 */
-	ret = nvc0_bar_init_vm(priv, &priv->bar[1], 1);
-	if (ret)
-		return ret;
-
-	priv->base.umap = nvc0_bar_umap;
-	priv->base.unmap = nvc0_bar_unmap;
-	priv->base.flush = nv84_bar_flush;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-void
-nvc0_bar_dtor(struct nouveau_object *object)
-{
-	struct nvc0_bar_priv *priv = (void *)object;
-
-	nouveau_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd);
-	nouveau_gpuobj_ref(NULL, &priv->bar[1].pgd);
-	nouveau_gpuobj_ref(NULL, &priv->bar[1].mem);
-
-	if (priv->bar[0].vm) {
-		nouveau_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]);
-		nouveau_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd);
-	}
-	nouveau_gpuobj_ref(NULL, &priv->bar[0].pgd);
-	nouveau_gpuobj_ref(NULL, &priv->bar[0].mem);
-
-	nouveau_bar_destroy(&priv->base);
-}
-
-int
-nvc0_bar_init(struct nouveau_object *object)
-{
-	struct nvc0_bar_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_bar_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
-	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
-
-	nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
-	if (priv->bar[0].mem)
-		nv_wr32(priv, 0x001714,
-			0xc0000000 | priv->bar[0].mem->addr >> 12);
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_bar_oclass = {
-	.handle = NV_SUBDEV(BAR, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_bar_ctor,
-		.dtor = nvc0_bar_dtor,
-		.init = nvc0_bar_init,
-		.fini = _nouveau_bar_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h
deleted file mode 100644
index 3ee8b14..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NVKM_BAR_PRIV_H__
-#define __NVKM_BAR_PRIV_H__
-
-#include <subdev/bar.h>
-
-#define nouveau_bar_create(p,e,o,d)                                            \
-	nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_bar_init(p)                                                    \
-	nouveau_subdev_init(&(p)->base)
-#define nouveau_bar_fini(p,s)                                                  \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, int, void **);
-void nouveau_bar_destroy(struct nouveau_bar *);
-
-void _nouveau_bar_dtor(struct nouveau_object *);
-#define _nouveau_bar_init _nouveau_subdev_init
-#define _nouveau_bar_fini _nouveau_subdev_fini
-
-int  nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *,
-		       struct nouveau_mem *, struct nouveau_object **);
-
-void nv84_bar_flush(struct nouveau_bar *);
-
-int nvc0_bar_ctor(struct nouveau_object *, struct nouveau_object *,
-		  struct nouveau_oclass *, void *, u32,
-		  struct nouveau_object **);
-void nvc0_bar_dtor(struct nouveau_object *);
-int nvc0_bar_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c
deleted file mode 100644
index 28906b1..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0203.h>
-
-u32
-nvbios_M0203Te(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_M;
-	u32 data = 0x00000000;
-
-	if (!bit_entry(bios, 'M', &bit_M)) {
-		if (bit_M.version == 2 && bit_M.length > 0x04)
-			data = nv_ro16(bios, bit_M.offset + 0x03);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0x00);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, data + 0x01);
-				*len = nv_ro08(bios, data + 0x02);
-				*cnt = nv_ro08(bios, data + 0x03);
-				return data;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x00000000;
-}
-
-u32
-nvbios_M0203Tp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	       struct nvbios_M0203T *info)
-{
-	u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->type    = nv_ro08(bios, data + 0x04);
-		info->pointer = nv_ro16(bios, data + 0x05);
-		break;
-	default:
-		break;
-	}
-	return data;
-}
-
-u32
-nvbios_M0203Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
-	u8  cnt, len;
-	u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
-	if (data && idx < cnt) {
-		data = data + *hdr + idx * len;
-		*hdr = len;
-		return data;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0203Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_M0203E *info)
-{
-	u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->type  = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
-		info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
-		info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0203Em(struct nouveau_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
-	       struct nvbios_M0203E *info)
-{
-	struct nvbios_M0203T M0203T;
-	u8  cnt, len, idx = 0xff;
-	u32 data;
-
-	if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
-		nv_warn(bios, "M0203T not found\n");
-		return 0x00000000;
-	}
-
-	while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
-		switch (M0203T.type) {
-		case M0203T_TYPE_RAMCFG:
-			if (info->strap != ramcfg)
-				continue;
-			return data;
-		default:
-			nv_warn(bios, "M0203T type %02x\n", M0203T.type);
-			return 0x00000000;
-		}
-	}
-
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
deleted file mode 100644
index ac9617c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0205.h>
-
-u32
-nvbios_M0205Te(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_M;
-	u32 data = 0x00000000;
-
-	if (!bit_entry(bios, 'M', &bit_M)) {
-		if (bit_M.version == 2 && bit_M.length > 0x08)
-			data = nv_ro32(bios, bit_M.offset + 0x05);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0x00);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, data + 0x01);
-				*len = nv_ro08(bios, data + 0x02);
-				*ssz = nv_ro08(bios, data + 0x03);
-				*snr = nv_ro08(bios, data + 0x04);
-				*cnt = nv_ro08(bios, data + 0x05);
-				return data;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x00000000;
-}
-
-u32
-nvbios_M0205Tp(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
-	       struct nvbios_M0205T *info)
-{
-	u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->freq = nv_ro16(bios, data + 0x06);
-		break;
-	default:
-		break;
-	}
-	return data;
-}
-
-u32
-nvbios_M0205Ee(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (data && idx < *cnt) {
-		data = data + *hdr + idx * (*len + (snr * ssz));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return data;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0205Ep(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	       struct nvbios_M0205E *info)
-{
-	u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->type = nv_ro08(bios, data + 0x00) & 0x0f;
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0205Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
-{
-
-	u8  cnt, len;
-	u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
-	if (data && idx < cnt) {
-		data = data + *hdr + idx * len;
-		*hdr = len;
-		return data;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0205Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_M0205S *info)
-{
-	u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->data = nv_ro08(bios, data + 0x00);
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
deleted file mode 100644
index b142a51..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0209.h>
-
-u32
-nvbios_M0209Te(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_M;
-	u32 data = 0x00000000;
-
-	if (!bit_entry(bios, 'M', &bit_M)) {
-		if (bit_M.version == 2 && bit_M.length > 0x0c)
-			data = nv_ro32(bios, bit_M.offset + 0x09);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0x00);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, data + 0x01);
-				*len = nv_ro08(bios, data + 0x02);
-				*ssz = nv_ro08(bios, data + 0x03);
-				*snr = 1;
-				*cnt = nv_ro08(bios, data + 0x04);
-				return data;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x00000000;
-}
-
-u32
-nvbios_M0209Ee(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (data && idx < *cnt) {
-		data = data + *hdr + idx * (*len + (snr * ssz));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return data;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0209Ep(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	       struct nvbios_M0209E *info)
-{
-	u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
-		info->bits   =  nv_ro08(bios, data + 0x00) & 0x3f;
-		info->modulo =  nv_ro08(bios, data + 0x01);
-		info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
-		info->v02_07 =  nv_ro08(bios, data + 0x02) & 0x07;
-		info->v03    =  nv_ro08(bios, data + 0x03);
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0209Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
-{
-
-	u8  cnt, len;
-	u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
-	if (data && idx < cnt) {
-		data = data + *hdr + idx * len;
-		*hdr = len;
-		return data;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_M0209Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_M0209S *info)
-{
-	struct nvbios_M0209E M0209E;
-	u8  cnt, len;
-	u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
-	if (data) {
-		u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
-		memset(info, 0x00, sizeof(*info));
-		switch (!!data * *ver) {
-		case 0x10:
-			for (i = 0; i < ARRAY_SIZE(info->data); i++) {
-				u32 bits = (i % M0209E.modulo) * M0209E.bits;
-				u32 mask = (1ULL << M0209E.bits) - 1;
-				u16  off = bits / 8;
-				u8   mod = bits % 8;
-				info->data[i] = nv_ro32(bios, data + off);
-				info->data[i] = info->data[i] >> mod;
-				info->data[i] = info->data[i] & mask;
-			}
-			return data;
-		default:
-			break;
-		}
-	}
-	return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c
deleted file mode 100644
index 199f4e5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/P0260.h>
-
-u32
-nvbios_P0260Te(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
-{
-	struct bit_entry bit_P;
-	u32 data = 0x00000000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2 && bit_P.length > 0x63)
-			data = nv_ro32(bios, bit_P.offset + 0x60);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, data + 1);
-				*cnt = nv_ro08(bios, data + 2);
-				*len = 4;
-				*xnr = nv_ro08(bios, data + 3);
-				*xsz = 4;
-				return data;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x00000000;
-}
-
-u32
-nvbios_P0260Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt, xnr, xsz;
-	u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz);
-	if (data && idx < cnt)
-		return data + hdr + (idx * *len);
-	return 0x00000000;
-}
-
-u32
-nvbios_P0260Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
-	       struct nvbios_P0260E *info)
-{
-	u32 data = nvbios_P0260Ee(bios, idx, ver, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->data = nv_ro32(bios, data);
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_P0260Xe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *xsz)
-{
-	u8  hdr, cnt, len, xnr;
-	u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz);
-	if (data && idx < xnr)
-		return data + hdr + (cnt * len) + (idx * *xsz);
-	return 0x00000000;
-}
-
-u32
-nvbios_P0260Xp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_P0260X *info)
-{
-	u32 data = nvbios_P0260Xe(bios, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x10:
-		info->data = nv_ro32(bios, data);
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
deleted file mode 100644
index 7df3a27..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/subdev.h>
-#include <core/option.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/bit.h>
-
-#include "priv.h"
-
-u8
-nvbios_checksum(const u8 *data, int size)
-{
-	u8 sum = 0;
-	while (size--)
-		sum += *data++;
-	return sum;
-}
-
-u16
-nvbios_findstr(const u8 *data, int size, const char *str, int len)
-{
-	int i, j;
-
-	for (i = 0; i <= (size - len); i++) {
-		for (j = 0; j < len; j++)
-			if ((char)data[i + j] != str[j])
-				break;
-		if (j == len)
-			return i;
-	}
-
-	return 0;
-}
-
-int
-nvbios_extend(struct nouveau_bios *bios, u32 length)
-{
-	if (bios->size < length) {
-		u8 *prev = bios->data;
-		if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
-			bios->data = prev;
-			return -ENOMEM;
-		}
-		memcpy(bios->data, prev, bios->size);
-		bios->size = length;
-		kfree(prev);
-		return 1;
-	}
-	return 0;
-}
-
-static u8
-nouveau_bios_rd08(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	return bios->data[addr];
-}
-
-static u16
-nouveau_bios_rd16(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	return get_unaligned_le16(&bios->data[addr]);
-}
-
-static u32
-nouveau_bios_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	return get_unaligned_le32(&bios->data[addr]);
-}
-
-static void
-nouveau_bios_wr08(struct nouveau_object *object, u64 addr, u8 data)
-{
-	struct nouveau_bios *bios = (void *)object;
-	bios->data[addr] = data;
-}
-
-static void
-nouveau_bios_wr16(struct nouveau_object *object, u64 addr, u16 data)
-{
-	struct nouveau_bios *bios = (void *)object;
-	put_unaligned_le16(data, &bios->data[addr]);
-}
-
-static void
-nouveau_bios_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nouveau_bios *bios = (void *)object;
-	put_unaligned_le32(data, &bios->data[addr]);
-}
-
-static int
-nouveau_bios_ctor(struct nouveau_object *parent,
-		  struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_bios *bios;
-	struct bit_entry bit_i;
-	int ret;
-
-	ret = nouveau_subdev_create(parent, engine, oclass, 0,
-				    "VBIOS", "bios", &bios);
-	*pobject = nv_object(bios);
-	if (ret)
-		return ret;
-
-	ret = nvbios_shadow(bios);
-	if (ret)
-		return ret;
-
-	/* detect type of vbios we're dealing with */
-	bios->bmp_offset = nvbios_findstr(bios->data, bios->size,
-					  "\xff\x7f""NV\0", 5);
-	if (bios->bmp_offset) {
-		nv_info(bios, "BMP version %x.%x\n",
-			bmp_version(bios) >> 8,
-			bmp_version(bios) & 0xff);
-	}
-
-	bios->bit_offset = nvbios_findstr(bios->data, bios->size,
-					  "\xff\xb8""BIT", 5);
-	if (bios->bit_offset)
-		nv_info(bios, "BIT signature found\n");
-
-	/* determine the vbios version number */
-	if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) {
-		bios->version.major = nv_ro08(bios, bit_i.offset + 3);
-		bios->version.chip  = nv_ro08(bios, bit_i.offset + 2);
-		bios->version.minor = nv_ro08(bios, bit_i.offset + 1);
-		bios->version.micro = nv_ro08(bios, bit_i.offset + 0);
-		bios->version.patch = nv_ro08(bios, bit_i.offset + 4);
-	} else
-	if (bmp_version(bios)) {
-		bios->version.major = nv_ro08(bios, bios->bmp_offset + 13);
-		bios->version.chip  = nv_ro08(bios, bios->bmp_offset + 12);
-		bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11);
-		bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10);
-	}
-
-	nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n",
-		bios->version.major, bios->version.chip,
-		bios->version.minor, bios->version.micro, bios->version.patch);
-
-	return 0;
-}
-
-static void
-nouveau_bios_dtor(struct nouveau_object *object)
-{
-	struct nouveau_bios *bios = (void *)object;
-	kfree(bios->data);
-	nouveau_subdev_destroy(&bios->base);
-}
-
-static int
-nouveau_bios_init(struct nouveau_object *object)
-{
-	struct nouveau_bios *bios = (void *)object;
-	return nouveau_subdev_init(&bios->base);
-}
-
-static int
-nouveau_bios_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_bios *bios = (void *)object;
-	return nouveau_subdev_fini(&bios->base, suspend);
-}
-
-struct nouveau_oclass
-nouveau_bios_oclass = {
-	.handle = NV_SUBDEV(VBIOS, 0x00),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nouveau_bios_ctor,
-		.dtor = nouveau_bios_dtor,
-		.init = nouveau_bios_init,
-		.fini = nouveau_bios_fini,
-		.rd08 = nouveau_bios_rd08,
-		.rd16 = nouveau_bios_rd16,
-		.rd32 = nouveau_bios_rd32,
-		.wr08 = nouveau_bios_wr08,
-		.wr16 = nouveau_bios_wr16,
-		.wr32 = nouveau_bios_wr32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c
deleted file mode 100644
index 1d03a3f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/object.h"
-
-#include "subdev/bios.h"
-#include "subdev/bios/bit.h"
-
-int
-bit_entry(struct nouveau_bios *bios, u8 id, struct bit_entry *bit)
-{
-	if (likely(bios->bit_offset)) {
-		u8  entries = nv_ro08(bios, bios->bit_offset + 10);
-		u32 entry   = bios->bit_offset + 12;
-		while (entries--) {
-			if (nv_ro08(bios, entry + 0) == id) {
-				bit->id      = nv_ro08(bios, entry + 0);
-				bit->version = nv_ro08(bios, entry + 1);
-				bit->length  = nv_ro16(bios, entry + 2);
-				bit->offset  = nv_ro16(bios, entry + 4);
-				return 0;
-			}
-
-			entry += nv_ro08(bios, bios->bit_offset + 9);
-		}
-
-		return -ENOENT;
-	}
-
-	return -EINVAL;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c
deleted file mode 100644
index c1835e5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/boost.h>
-
-u16
-nvbios_boostTe(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_P;
-	u16 boost = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2)
-			boost = nv_ro16(bios, bit_P.offset + 0x30);
-
-		if (boost) {
-			*ver = nv_ro08(bios, boost + 0);
-			switch (*ver) {
-			case 0x11:
-				*hdr = nv_ro08(bios, boost + 1);
-				*cnt = nv_ro08(bios, boost + 5);
-				*len = nv_ro08(bios, boost + 2);
-				*snr = nv_ro08(bios, boost + 4);
-				*ssz = nv_ro08(bios, boost + 3);
-				return boost;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_boostEe(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u16 data = nvbios_boostTe(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (data && idx < *cnt) {
-		data = data + *hdr + (idx * (*len + (snr * ssz)));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_boostEp(struct nouveau_bios *bios, int idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
-{
-	u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
-		info->min    =  nv_ro16(bios, data + 0x02) * 1000;
-		info->max    =  nv_ro16(bios, data + 0x04) * 1000;
-	}
-	return data;
-}
-
-u16
-nvbios_boostEm(struct nouveau_bios *bios, u8 pstate,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
-{
-	u32 data, idx = 0;
-	while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) {
-		if (info->pstate == pstate)
-			break;
-	}
-	return data;
-}
-
-u16
-nvbios_boostSe(struct nouveau_bios *bios, int idx,
-	       u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len)
-{
-	if (data && idx < cnt) {
-		data = data + *hdr + (idx * len);
-		*hdr = len;
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_boostSp(struct nouveau_bios *bios, int idx,
-	       u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len,
-	       struct nvbios_boostS *info)
-{
-	data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->domain  = nv_ro08(bios, data + 0x00);
-		info->percent = nv_ro08(bios, data + 0x01);
-		info->min     = nv_ro16(bios, data + 0x02) * 1000;
-		info->max     = nv_ro16(bios, data + 0x04) * 1000;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
deleted file mode 100644
index 2ede3bc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/conn.h>
-
-u32
-nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
-	if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
-		u32 data = nv_ro16(bios, dcb + 0x14);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0);
-			*hdr = nv_ro08(bios, data + 1);
-			*cnt = nv_ro08(bios, data + 2);
-			*len = nv_ro08(bios, data + 3);
-			return data;
-		}
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	      struct nvbios_connT *info)
-{
-	u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x30:
-	case 0x40:
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
-
-u32
-nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt;
-	u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
-	if (data && idx < cnt)
-		return data + hdr + (idx * *len);
-	return 0x00000000;
-}
-
-u32
-nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
-	      struct nvbios_connE *info)
-{
-	u32 data = nvbios_connEe(bios, idx, ver, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x30:
-	case 0x40:
-		info->type     =  nv_ro08(bios, data + 0x00);
-		info->location =  nv_ro08(bios, data + 0x01) & 0x0f;
-		info->hpd      = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
-		info->dp       = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
-		if (*len < 4)
-			return data;
-		info->hpd     |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
-		info->dp      |=  nv_ro08(bios, data + 0x02) & 0x0c;
-		info->di       = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
-		info->hpd     |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
-		info->sr       = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
-		info->lcdid    = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
-		return data;
-	default:
-		break;
-	}
-	return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c
deleted file mode 100644
index d3b1532..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/cstep.h>
-
-u16
-nvbios_cstepTe(struct nouveau_bios *bios,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
-{
-	struct bit_entry bit_P;
-	u16 cstep = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2)
-			cstep = nv_ro16(bios, bit_P.offset + 0x34);
-
-		if (cstep) {
-			*ver = nv_ro08(bios, cstep + 0);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, cstep + 1);
-				*cnt = nv_ro08(bios, cstep + 3);
-				*len = nv_ro08(bios, cstep + 2);
-				*xnr = nv_ro08(bios, cstep + 5);
-				*xsz = nv_ro08(bios, cstep + 4);
-				return cstep;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_cstepEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
-	u8  cnt, len, xnr, xsz;
-	u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
-	if (data && idx < cnt) {
-		data = data + *hdr + (idx * len);
-		*hdr = len;
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_cstepEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_cstepE *info)
-{
-	u16 data = nvbios_cstepEe(bios, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
-		info->index   = nv_ro08(bios, data + 0x03);
-	}
-	return data;
-}
-
-u16
-nvbios_cstepEm(struct nouveau_bios *bios, u8 pstate, u8 *ver, u8 *hdr,
-	       struct nvbios_cstepE *info)
-{
-	u32 data, idx = 0;
-	while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) {
-		if (info->pstate == pstate)
-			break;
-	}
-	return data;
-}
-
-u16
-nvbios_cstepXe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
-	u8  cnt, len, xnr, xsz;
-	u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
-	if (data && idx < xnr) {
-		data = data + *hdr + (cnt * len) + (idx * xsz);
-		*hdr = xsz;
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_cstepXp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-	       struct nvbios_cstepX *info)
-{
-	u16 data = nvbios_cstepXe(bios, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->freq    = nv_ro16(bios, data + 0x00) * 1000;
-		info->unkn[0] = nv_ro08(bios, data + 0x02);
-		info->unkn[1] = nv_ro08(bios, data + 0x03);
-		info->voltage = nv_ro08(bios, data + 0x04);
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
deleted file mode 100644
index 96099af..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/device.h"
-
-#include "subdev/bios.h"
-#include "subdev/bios/dcb.h"
-
-u16
-dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct nouveau_device *device = nv_device(bios);
-	u16 dcb = 0x0000;
-
-	if (device->card_type > NV_04)
-		dcb = nv_ro16(bios, 0x36);
-	if (!dcb) {
-		nv_warn(bios, "DCB table not found\n");
-		return dcb;
-	}
-
-	*ver = nv_ro08(bios, dcb);
-
-	if (*ver >= 0x42) {
-		nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
-		return 0x0000;
-	} else
-	if (*ver >= 0x30) {
-		if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) {
-			*hdr = nv_ro08(bios, dcb + 1);
-			*cnt = nv_ro08(bios, dcb + 2);
-			*len = nv_ro08(bios, dcb + 3);
-			return dcb;
-		}
-	} else
-	if (*ver >= 0x20) {
-		if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) {
-			u16 i2c = nv_ro16(bios, dcb + 2);
-			*hdr = 8;
-			*cnt = (i2c - dcb) / 8;
-			*len = 8;
-			return dcb;
-		}
-	} else
-	if (*ver >= 0x15) {
-		if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
-			u16 i2c = nv_ro16(bios, dcb + 2);
-			*hdr = 4;
-			*cnt = (i2c - dcb) / 10;
-			*len = 10;
-			return dcb;
-		}
-	} else {
-		/*
-		 * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but
-		 * always has the same single (crt) entry, even when tv-out
-		 * present, so the conclusion is this version cannot really
-		 * be used.
-		 *
-		 * v1.2 tables (some NV6/10, and NV15+) normally have the
-		 * same 5 entries, which are not specific to the card and so
-		 * no use.
-		 *
-		 * v1.2 does have an I2C table that read_dcb_i2c_table can
-		 * handle, but cards exist (nv11 in #14821) with a bad i2c
-		 * table pointer, so use the indices parsed in
-		 * parse_bmp_structure.
-		 *
-		 * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
-		 */
-		nv_warn(bios, "DCB contains no useful data\n");
-		return 0x0000;
-	}
-
-	nv_warn(bios, "DCB header validation failed\n");
-	return 0x0000;
-}
-
-u16
-dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt;
-	u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
-	if (dcb && idx < cnt)
-		return dcb + hdr + (idx * *len);
-	return 0x0000;
-}
-
-static inline u16
-dcb_outp_hasht(struct dcb_output *outp)
-{
-	return (outp->extdev << 8) | (outp->location << 4) | outp->type;
-}
-
-static inline u16
-dcb_outp_hashm(struct dcb_output *outp)
-{
-	return (outp->heads << 8) | (outp->link << 6) | outp->or;
-}
-
-u16
-dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
-	       struct dcb_output *outp)
-{
-	u16 dcb = dcb_outp(bios, idx, ver, len);
-	memset(outp, 0x00, sizeof(*outp));
-	if (dcb) {
-		if (*ver >= 0x20) {
-			u32 conn = nv_ro32(bios, dcb + 0x00);
-			outp->or        = (conn & 0x0f000000) >> 24;
-			outp->location  = (conn & 0x00300000) >> 20;
-			outp->bus       = (conn & 0x000f0000) >> 16;
-			outp->connector = (conn & 0x0000f000) >> 12;
-			outp->heads     = (conn & 0x00000f00) >> 8;
-			outp->i2c_index = (conn & 0x000000f0) >> 4;
-			outp->type      = (conn & 0x0000000f);
-			outp->link      = 0;
-		} else {
-			dcb = 0x0000;
-		}
-
-		if (*ver >= 0x40) {
-			u32 conf = nv_ro32(bios, dcb + 0x04);
-			switch (outp->type) {
-			case DCB_OUTPUT_DP:
-				switch (conf & 0x00e00000) {
-				case 0x00000000:
-					outp->dpconf.link_bw = 0x06;
-					break;
-				case 0x00200000:
-					outp->dpconf.link_bw = 0x0a;
-					break;
-				case 0x00400000:
-				default:
-					outp->dpconf.link_bw = 0x14;
-					break;
-				}
-
-				outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
-				if (*ver < 0x41) {
-					switch (outp->dpconf.link_nr) {
-					case 0x0f:
-						outp->dpconf.link_nr = 4;
-						break;
-					case 0x03:
-						outp->dpconf.link_nr = 2;
-						break;
-					case 0x01:
-					default:
-						outp->dpconf.link_nr = 1;
-						break;
-					}
-				}
-
-				/* fall-through... */
-			case DCB_OUTPUT_TMDS:
-			case DCB_OUTPUT_LVDS:
-				outp->link = (conf & 0x00000030) >> 4;
-				outp->sorconf.link = outp->link; /*XXX*/
-				outp->extdev = 0x00;
-				if (outp->location != 0)
-					outp->extdev = (conf & 0x0000ff00) >> 8;
-				break;
-			default:
-				break;
-			}
-		}
-
-		outp->hasht = dcb_outp_hasht(outp);
-		outp->hashm = dcb_outp_hashm(outp);
-	}
-	return dcb;
-}
-
-u16
-dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
-	       u8 *ver, u8 *len, struct dcb_output *outp)
-{
-	u16 dcb, idx = 0;
-	while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
-		if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
-			if ((dcb_outp_hashm(outp) & mask) == mask)
-				break;
-		}
-	}
-	return dcb;
-}
-
-int
-dcb_outp_foreach(struct nouveau_bios *bios, void *data,
-		 int (*exec)(struct nouveau_bios *, void *, int, u16))
-{
-	int ret, idx = -1;
-	u8  ver, len;
-	u16 outp;
-
-	while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
-		if (nv_ro32(bios, outp) == 0x00000000)
-			break; /* seen on an NV11 with DCB v1.5 */
-		if (nv_ro32(bios, outp) == 0xffffffff)
-			break; /* seen on an NV17 with DCB v2.0 */
-
-		if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED)
-			continue;
-		if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL)
-			break;
-
-		ret = exec(bios, data, idx, outp);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
deleted file mode 100644
index 51f3555..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/disp.h>
-
-u16
-nvbios_disp_table(struct nouveau_bios *bios,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub)
-{
-	struct bit_entry U;
-
-	if (!bit_entry(bios, 'U', &U)) {
-		if (U.version == 1) {
-			u16 data = nv_ro16(bios, U.offset);
-			if (data) {
-				*ver = nv_ro08(bios, data + 0x00);
-				switch (*ver) {
-				case 0x20:
-				case 0x21:
-				case 0x22:
-					*hdr = nv_ro08(bios, data + 0x01);
-					*len = nv_ro08(bios, data + 0x02);
-					*cnt = nv_ro08(bios, data + 0x03);
-					*sub = nv_ro08(bios, data + 0x04);
-					return data;
-				default:
-					break;
-				}
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_disp_entry(struct nouveau_bios *bios, u8 idx,
-		  u8 *ver, u8 *len, u8 *sub)
-{
-	u8  hdr, cnt;
-	u16 data = nvbios_disp_table(bios, ver, &hdr, &cnt, len, sub);
-	if (data && idx < cnt)
-		return data + hdr + (idx * *len);
-	*ver = 0x00;
-	return 0x0000;
-}
-
-u16
-nvbios_disp_parse(struct nouveau_bios *bios, u8 idx,
-		  u8 *ver, u8 *len, u8 *sub,
-		  struct nvbios_disp *info)
-{
-	u16 data = nvbios_disp_entry(bios, idx, ver, len, sub);
-	if (data && *len >= 2) {
-		info->data = nv_ro16(bios, data + 0);
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_outp_entry(struct nouveau_bios *bios, u8 idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct nvbios_disp info;
-	u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info);
-	if (data) {
-		*cnt = nv_ro08(bios, info.data + 0x05);
-		*len = 0x06;
-		data = info.data;
-	}
-	return data;
-}
-
-u16
-nvbios_outp_parse(struct nouveau_bios *bios, u8 idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_outp *info)
-{
-	u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len);
-	if (data && *hdr >= 0x0a) {
-		info->type      = nv_ro16(bios, data + 0x00);
-		info->mask      = nv_ro32(bios, data + 0x02);
-		if (*ver <= 0x20) /* match any link */
-			info->mask |= 0x00c0;
-		info->script[0] = nv_ro16(bios, data + 0x06);
-		info->script[1] = nv_ro16(bios, data + 0x08);
-		info->script[2] = 0x0000;
-		if (*hdr >= 0x0c)
-			info->script[2] = nv_ro16(bios, data + 0x0a);
-		return data;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_outp *info)
-{
-	u16 data, idx = 0;
-	while ((data = nvbios_outp_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
-		if (data && info->type == type) {
-			if ((info->mask & mask) == mask)
-				break;
-		}
-	}
-	return data;
-}
-
-u16
-nvbios_ocfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	if (idx < *cnt)
-		return outp + *hdr + (idx * *len);
-	return 0x0000;
-}
-
-u16
-nvbios_ocfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_ocfg *info)
-{
-	u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
-	if (data) {
-		info->match     = nv_ro16(bios, data + 0x00);
-		info->clkcmp[0] = nv_ro16(bios, data + 0x02);
-		info->clkcmp[1] = nv_ro16(bios, data + 0x04);
-	}
-	return data;
-}
-
-u16
-nvbios_ocfg_match(struct nouveau_bios *bios, u16 outp, u16 type,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_ocfg *info)
-{
-	u16 data, idx = 0;
-	while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
-		if (info->match == type)
-			break;
-	}
-	return data;
-}
-
-u16
-nvbios_oclk_match(struct nouveau_bios *bios, u16 cmp, u32 khz)
-{
-	while (cmp) {
-		if (khz / 10 >= nv_ro16(bios, cmp + 0x00))
-			return  nv_ro16(bios, cmp + 0x02);
-		cmp += 0x04;
-	}
-	return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
deleted file mode 100644
index cef53f8..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-
-#include "subdev/bios.h"
-#include "subdev/bios/bit.h"
-#include "subdev/bios/dp.h"
-
-static u16
-nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry d;
-
-	if (!bit_entry(bios, 'd', &d)) {
-		if (d.version == 1 && d.length >= 2) {
-			u16 data = nv_ro16(bios, d.offset);
-			if (data) {
-				*ver = nv_ro08(bios, data + 0x00);
-				switch (*ver) {
-				case 0x21:
-				case 0x30:
-				case 0x40:
-				case 0x41:
-					*hdr = nv_ro08(bios, data + 0x01);
-					*len = nv_ro08(bios, data + 0x02);
-					*cnt = nv_ro08(bios, data + 0x03);
-					return data;
-				default:
-					break;
-				}
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-static u16
-nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
-	if (data && idx < *cnt) {
-		u16 outp = nv_ro16(bios, data + *hdr + idx * *len);
-		switch (*ver * !!outp) {
-		case 0x21:
-		case 0x30:
-			*hdr = nv_ro08(bios, data + 0x04);
-			*len = nv_ro08(bios, data + 0x05);
-			*cnt = nv_ro08(bios, outp + 0x04);
-			break;
-		case 0x40:
-		case 0x41:
-			*hdr = nv_ro08(bios, data + 0x04);
-			*cnt = 0;
-			*len = 0;
-			break;
-		default:
-			break;
-		}
-		return outp;
-	}
-	*ver = 0x00;
-	return 0x0000;
-}
-
-u16
-nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpout *info)
-{
-	u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	if (data && *ver) {
-		info->type = nv_ro16(bios, data + 0x00);
-		info->mask = nv_ro16(bios, data + 0x02);
-		switch (*ver) {
-		case 0x21:
-		case 0x30:
-			info->flags     = nv_ro08(bios, data + 0x05);
-			info->script[0] = nv_ro16(bios, data + 0x06);
-			info->script[1] = nv_ro16(bios, data + 0x08);
-			info->lnkcmp    = nv_ro16(bios, data + 0x0a);
-			if (*len >= 0x0f) {
-				info->script[2] = nv_ro16(bios, data + 0x0c);
-				info->script[3] = nv_ro16(bios, data + 0x0e);
-			}
-			if (*len >= 0x11)
-				info->script[4] = nv_ro16(bios, data + 0x10);
-			break;
-		case 0x40:
-		case 0x41:
-			info->flags     = nv_ro08(bios, data + 0x04);
-			info->script[0] = nv_ro16(bios, data + 0x05);
-			info->script[1] = nv_ro16(bios, data + 0x07);
-			info->lnkcmp    = nv_ro16(bios, data + 0x09);
-			info->script[2] = nv_ro16(bios, data + 0x0b);
-			info->script[3] = nv_ro16(bios, data + 0x0d);
-			info->script[4] = nv_ro16(bios, data + 0x0f);
-			break;
-		default:
-			data = 0x0000;
-			break;
-		}
-	}
-	return data;
-}
-
-u16
-nvbios_dpout_match(struct nouveau_bios *bios, u16 type, u16 mask,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpout *info)
-{
-	u16 data, idx = 0;
-	while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
-		if (data && info->type == type) {
-			if ((info->mask & mask) == mask)
-				break;
-		}
-	}
-	return data;
-}
-
-static u16
-nvbios_dpcfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	if (*ver >= 0x40) {
-		outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
-		*hdr = *hdr + (*len * * cnt);
-		*len = nv_ro08(bios, outp + 0x06);
-		*cnt = nv_ro08(bios, outp + 0x07);
-	}
-
-	if (idx < *cnt)
-		return outp + *hdr + (idx * *len);
-
-	return 0x0000;
-}
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpcfg *info)
-{
-	u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		switch (*ver) {
-		case 0x21:
-			info->dc    = nv_ro08(bios, data + 0x02);
-			info->pe    = nv_ro08(bios, data + 0x03);
-			info->tx_pu = nv_ro08(bios, data + 0x04);
-			break;
-		case 0x30:
-		case 0x40:
-		case 0x41:
-			info->pc    = nv_ro08(bios, data + 0x00);
-			info->dc    = nv_ro08(bios, data + 0x01);
-			info->pe    = nv_ro08(bios, data + 0x02);
-			info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
-			break;
-		default:
-			data = 0x0000;
-			break;
-		}
-	}
-	return data;
-}
-
-u16
-nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
-		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		   struct nvbios_dpcfg *info)
-{
-	u8 idx = 0xff;
-	u16 data;
-
-	if (*ver >= 0x30) {
-		/*XXX: there's a second set of these on at least 4.1, that
-		 *     i've witnessed nvidia using instead of the first
-		 *     on gm204.  figure out what/why
-		 */
-		const u8 vsoff[] = { 0, 4, 7, 9 };
-		idx = (pc * 10) + vsoff[vs] + pe;
-	} else {
-		while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
-						  ver, hdr, cnt, len))) {
-			if (nv_ro08(bios, data + 0x00) == vs &&
-			    nv_ro08(bios, data + 0x01) == pe)
-				break;
-		}
-	}
-
-	return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
deleted file mode 100644
index 49285d4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/extdev.h>
-
-static u16
-extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
-{
-	u8  dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
-	u16 dcb, extdev = 0;
-
-	dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
-	if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40))
-		return 0x0000;
-
-	extdev = nv_ro16(bios, dcb + 18);
-	if (!extdev)
-		return 0x0000;
-
-	*ver = nv_ro08(bios, extdev + 0);
-	*hdr = nv_ro08(bios, extdev + 1);
-	*cnt = nv_ro08(bios, extdev + 2);
-	*len = nv_ro08(bios, extdev + 3);
-
-	return extdev + *hdr;
-}
-
-static u16
-nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
-	u8 hdr, cnt;
-	u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
-	if (extdev && idx < cnt)
-		return extdev + idx * *len;
-	return 0x0000;
-}
-
-static void
-extdev_parse_entry(struct nouveau_bios *bios, u16 offset,
-			  struct nvbios_extdev_func *entry)
-{
-	entry->type = nv_ro08(bios, offset + 0);
-	entry->addr = nv_ro08(bios, offset + 1);
-	entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1;
-}
-
-int
-nvbios_extdev_parse(struct nouveau_bios *bios, int idx,
-		    struct nvbios_extdev_func *func)
-{
-	u8 ver, len;
-	u16 entry;
-
-	if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
-		return -EINVAL;
-
-	extdev_parse_entry(bios, entry, func);
-
-	return 0;
-}
-
-int
-nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type,
-		   struct nvbios_extdev_func *func)
-{
-	u8 ver, len, i;
-	u16 entry;
-
-	i = 0;
-	while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
-		extdev_parse_entry(bios, entry, func);
-		if (func->type == type)
-			return 0;
-	}
-
-	return -EINVAL;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
deleted file mode 100644
index e419892..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/fan.h>
-
-u16
-nvbios_fan_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_P;
-	u16 fan = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2 && bit_P.length >= 0x5a)
-			fan = nv_ro16(bios, bit_P.offset + 0x58);
-
-		if (fan) {
-			*ver = nv_ro08(bios, fan + 0);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, fan + 1);
-				*len = nv_ro08(bios, fan + 2);
-				*cnt = nv_ro08(bios, fan + 3);
-				return fan;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_fan_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-		 u8 *cnt, u8 *len)
-{
-	u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
-	if (data && idx < *cnt)
-		return data + *hdr + (idx * (*len));
-	return 0x0000;
-}
-
-u16
-nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan)
-{
-	u8 ver, hdr, cnt, len;
-
-	u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
-	if (data) {
-		u8 type = nv_ro08(bios, data + 0x00);
-		switch (type) {
-		case 0:
-			fan->type = NVBIOS_THERM_FAN_TOGGLE;
-			break;
-		case 1:
-		case 2:
-			/* TODO: Understand the difference between the two! */
-			fan->type = NVBIOS_THERM_FAN_PWM;
-			break;
-		default:
-			fan->type = NVBIOS_THERM_FAN_UNK;
-		}
-
-		fan->min_duty = nv_ro08(bios, data + 0x02);
-		fan->max_duty = nv_ro08(bios, data + 0x03);
-
-		fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
deleted file mode 100644
index 172a4f9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/xpio.h>
-
-u16
-dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u16 data = 0x0000;
-	u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
-	if (dcb) {
-		if (*ver >= 0x30 && *hdr >= 0x0c)
-			data = nv_ro16(bios, dcb + 0x0a);
-		else
-		if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
-			data = nv_ro16(bios, dcb - 0x0f);
-
-		if (data) {
-			*ver = nv_ro08(bios, data + 0x00);
-			if (*ver < 0x30) {
-				*hdr = 3;
-				*cnt = nv_ro08(bios, data + 0x02);
-				*len = nv_ro08(bios, data + 0x01);
-			} else
-			if (*ver <= 0x41) {
-				*hdr = nv_ro08(bios, data + 0x01);
-				*cnt = nv_ro08(bios, data + 0x02);
-				*len = nv_ro08(bios, data + 0x03);
-			} else {
-				data = 0x0000;
-			}
-		}
-	}
-	return data;
-}
-
-u16
-dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt, xver; /* use gpio version for xpio entry parsing */
-	u16 gpio;
-
-	if (!idx--)
-		gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len);
-	else
-		gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len);
-
-	if (gpio && ent < cnt)
-		return gpio + hdr + (ent * *len);
-	return 0x0000;
-}
-
-u16
-dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len,
-	       struct dcb_gpio_func *gpio)
-{
-	u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
-	if (data) {
-		if (*ver < 0x40) {
-			u16 info = nv_ro16(bios, data);
-			*gpio = (struct dcb_gpio_func) {
-				.line = (info & 0x001f) >> 0,
-				.func = (info & 0x07e0) >> 5,
-				.log[0] = (info & 0x1800) >> 11,
-				.log[1] = (info & 0x6000) >> 13,
-				.param = !!(info & 0x8000),
-			};
-		} else
-		if (*ver < 0x41) {
-			u32 info = nv_ro32(bios, data);
-			*gpio = (struct dcb_gpio_func) {
-				.line = (info & 0x0000001f) >> 0,
-				.func = (info & 0x0000ff00) >> 8,
-				.log[0] = (info & 0x18000000) >> 27,
-				.log[1] = (info & 0x60000000) >> 29,
-				.param = !!(info & 0x80000000),
-			};
-		} else {
-			u32 info = nv_ro32(bios, data + 0);
-			u8 info1 = nv_ro32(bios, data + 4);
-			*gpio = (struct dcb_gpio_func) {
-				.line = (info & 0x0000003f) >> 0,
-				.func = (info & 0x0000ff00) >> 8,
-				.log[0] = (info1 & 0x30) >> 4,
-				.log[1] = (info1 & 0xc0) >> 6,
-				.param = !!(info & 0x80000000),
-			};
-		}
-	}
-
-	return data;
-}
-
-u16
-dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line,
-	       u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
-{
-	u8  hdr, cnt, i = 0;
-	u16 data;
-
-	while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
-		if ((line == 0xff || line == gpio->line) &&
-		    (func == 0xff || func == gpio->func))
-			return data;
-	}
-
-	/* DCB 2.2, fixed TVDAC GPIO data */
-	if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
-		if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
-			u8 conf = nv_ro08(bios, data - 5);
-			u8 addr = nv_ro08(bios, data - 4);
-			if (conf & 0x01) {
-				*gpio = (struct dcb_gpio_func) {
-					.func = DCB_GPIO_TVDAC0,
-					.line = addr >> 4,
-					.log[0] = !!(conf & 0x02),
-					.log[1] =  !(conf & 0x02),
-				};
-				*ver = 0x00;
-				return data;
-			}
-		}
-	}
-
-	return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
deleted file mode 100644
index 282320b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-
-#include "subdev/bios.h"
-#include "subdev/bios/dcb.h"
-#include "subdev/bios/i2c.h"
-
-u16
-dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u16 i2c = 0x0000;
-	u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
-	if (dcb) {
-		if (*ver >= 0x15)
-			i2c = nv_ro16(bios, dcb + 2);
-		if (*ver >= 0x30)
-			i2c = nv_ro16(bios, dcb + 4);
-	}
-
-	if (i2c && *ver >= 0x42) {
-		nv_warn(bios, "ccb %02x not supported\n", *ver);
-		return 0x0000;
-	}
-
-	if (i2c && *ver >= 0x30) {
-		*ver = nv_ro08(bios, i2c + 0);
-		*hdr = nv_ro08(bios, i2c + 1);
-		*cnt = nv_ro08(bios, i2c + 2);
-		*len = nv_ro08(bios, i2c + 3);
-	} else {
-		*ver = *ver; /* use DCB version */
-		*hdr = 0;
-		*cnt = 16;
-		*len = 4;
-	}
-
-	return i2c;
-}
-
-u16
-dcb_i2c_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt;
-	u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len);
-	if (i2c && idx < cnt)
-		return i2c + hdr + (idx * *len);
-	return 0x0000;
-}
-
-int
-dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
-{
-	u8  ver, len;
-	u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
-	if (ent) {
-		if (ver >= 0x41) {
-			if (!(nv_ro32(bios, ent) & 0x80000000))
-				info->type = DCB_I2C_UNUSED;
-			else
-				info->type = DCB_I2C_PMGR;
-		} else
-		if (ver >= 0x30) {
-			info->type = nv_ro08(bios, ent + 0x03);
-		} else {
-			info->type = nv_ro08(bios, ent + 0x03) & 0x07;
-			if (info->type == 0x07)
-				info->type = DCB_I2C_UNUSED;
-		}
-
-		info->drive = DCB_I2C_UNUSED;
-		info->sense = DCB_I2C_UNUSED;
-		info->share = DCB_I2C_UNUSED;
-		info->auxch = DCB_I2C_UNUSED;
-
-		switch (info->type) {
-		case DCB_I2C_NV04_BIT:
-			info->drive = nv_ro08(bios, ent + 0);
-			info->sense = nv_ro08(bios, ent + 1);
-			return 0;
-		case DCB_I2C_NV4E_BIT:
-			info->drive = nv_ro08(bios, ent + 1);
-			return 0;
-		case DCB_I2C_NVIO_BIT:
-			info->drive = nv_ro08(bios, ent + 0) & 0x0f;
-			if (nv_ro08(bios, ent + 1) & 0x01)
-				info->share = nv_ro08(bios, ent + 1) >> 1;
-			return 0;
-		case DCB_I2C_NVIO_AUX:
-			info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
-			if (nv_ro08(bios, ent + 1) & 0x01)
-					info->share = info->auxch;
-			return 0;
-		case DCB_I2C_PMGR:
-			info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
-			if (info->drive == 0x1f)
-				info->drive = DCB_I2C_UNUSED;
-			info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
-			if (info->auxch == 0x1f)
-				info->auxch = DCB_I2C_UNUSED;
-			info->share = info->auxch;
-			return 0;
-		case DCB_I2C_UNUSED:
-			return 0;
-		default:
-			nv_warn(bios, "unknown i2c type %d\n", info->type);
-			info->type = DCB_I2C_UNUSED;
-			return 0;
-		}
-	}
-
-	if (bios->bmp_offset && idx < 2) {
-		/* BMP (from v4.0 has i2c info in the structure, it's in a
-		 * fixed location on earlier VBIOS
-		 */
-		if (nv_ro08(bios, bios->bmp_offset + 5) < 4)
-			ent = 0x0048;
-		else
-			ent = 0x0036 + bios->bmp_offset;
-
-		if (idx == 0) {
-			info->drive = nv_ro08(bios, ent + 4);
-			if (!info->drive) info->drive = 0x3f;
-			info->sense = nv_ro08(bios, ent + 5);
-			if (!info->sense) info->sense = 0x3e;
-		} else
-		if (idx == 1) {
-			info->drive = nv_ro08(bios, ent + 6);
-			if (!info->drive) info->drive = 0x37;
-			info->sense = nv_ro08(bios, ent + 7);
-			if (!info->sense) info->sense = 0x36;
-		}
-
-		info->type  = DCB_I2C_NV04_BIT;
-		info->share = DCB_I2C_UNUSED;
-		return 0;
-	}
-
-	return -ENOENT;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/image.c b/drivers/gpu/drm/nouveau/core/subdev/bios/image.c
deleted file mode 100644
index 373f9a5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/image.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/image.h>
-#include <subdev/bios/pcir.h>
-#include <subdev/bios/npde.h>
-
-static bool
-nvbios_imagen(struct nouveau_bios *bios, struct nvbios_image *image)
-{
-	struct nvbios_pcirT pcir;
-	struct nvbios_npdeT npde;
-	u8  ver;
-	u16 hdr;
-	u32 data;
-
-	switch ((data = nv_ro16(bios, image->base + 0x00))) {
-	case 0xaa55:
-	case 0xbb77:
-	case 0x4e56: /* NV */
-		break;
-	default:
-		nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
-			 image->base, data);
-		return false;
-	}
-
-	if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
-		return false;
-	image->size = pcir.image_size;
-	image->type = pcir.image_type;
-	image->last = pcir.last;
-
-	if (image->type != 0x70) {
-		if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
-			return true;
-		image->size = npde.image_size;
-		image->last = npde.last;
-	} else {
-		image->last = true;
-	}
-
-	return true;
-}
-
-bool
-nvbios_image(struct nouveau_bios *bios, int idx, struct nvbios_image *image)
-{
-	memset(image, 0x00, sizeof(*image));
-	do {
-		image->base += image->size;
-		if (image->last || !nvbios_imagen(bios, image))
-			return false;
-	} while(idx--);
-	return true;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
deleted file mode 100644
index c6579ef..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ /dev/null
@@ -1,2227 +0,0 @@
-#include <core/engine.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/conn.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/devinit.h>
-#include <subdev/i2c.h>
-#include <subdev/vga.h>
-#include <subdev/gpio.h>
-
-#define bioslog(lvl, fmt, args...) do {                                        \
-	nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset,            \
-		  init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args);   \
-} while(0)
-#define cont(fmt, args...) do {                                                \
-	if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE)                      \
-		printk(fmt, ##args);                                           \
-} while(0)
-#define trace(fmt, args...) bioslog(TRACE, fmt, ##args)
-#define warn(fmt, args...) bioslog(WARN, fmt, ##args)
-#define error(fmt, args...) bioslog(ERROR, fmt, ##args)
-
-/******************************************************************************
- * init parser control flow helpers
- *****************************************************************************/
-
-static inline bool
-init_exec(struct nvbios_init *init)
-{
-	return (init->execute == 1) || ((init->execute & 5) == 5);
-}
-
-static inline void
-init_exec_set(struct nvbios_init *init, bool exec)
-{
-	if (exec) init->execute &= 0xfd;
-	else      init->execute |= 0x02;
-}
-
-static inline void
-init_exec_inv(struct nvbios_init *init)
-{
-	init->execute ^= 0x02;
-}
-
-static inline void
-init_exec_force(struct nvbios_init *init, bool exec)
-{
-	if (exec) init->execute |= 0x04;
-	else      init->execute &= 0xfb;
-}
-
-/******************************************************************************
- * init parser wrappers for normal register/i2c/whatever accessors
- *****************************************************************************/
-
-static inline int
-init_or(struct nvbios_init *init)
-{
-	if (init_exec(init)) {
-		if (init->outp)
-			return ffs(init->outp->or) - 1;
-		error("script needs OR!!\n");
-	}
-	return 0;
-}
-
-static inline int
-init_link(struct nvbios_init *init)
-{
-	if (init_exec(init)) {
-		if (init->outp)
-			return !(init->outp->sorconf.link & 1);
-		error("script needs OR link\n");
-	}
-	return 0;
-}
-
-static inline int
-init_crtc(struct nvbios_init *init)
-{
-	if (init_exec(init)) {
-		if (init->crtc >= 0)
-			return init->crtc;
-		error("script needs crtc\n");
-	}
-	return 0;
-}
-
-static u8
-init_conn(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	struct nvbios_connE connE;
-	u8  ver, hdr;
-	u32 conn;
-
-	if (init_exec(init)) {
-		if (init->outp) {
-			conn = init->outp->connector;
-			conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
-			if (conn)
-				return connE.type;
-		}
-
-		error("script needs connector type\n");
-	}
-
-	return 0xff;
-}
-
-static inline u32
-init_nvreg(struct nvbios_init *init, u32 reg)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
-
-	/* C51 (at least) sometimes has the lower bits set which the VBIOS
-	 * interprets to mean that access needs to go through certain IO
-	 * ports instead.  The NVIDIA binary driver has been seen to access
-	 * these through the NV register address, so lets assume we can
-	 * do the same
-	 */
-	reg &= ~0x00000003;
-
-	/* GF8+ display scripts need register addresses mangled a bit to
-	 * select a specific CRTC/OR
-	 */
-	if (nv_device(init->bios)->card_type >= NV_50) {
-		if (reg & 0x80000000) {
-			reg += init_crtc(init) * 0x800;
-			reg &= ~0x80000000;
-		}
-
-		if (reg & 0x40000000) {
-			reg += init_or(init) * 0x800;
-			reg &= ~0x40000000;
-			if (reg & 0x20000000) {
-				reg += init_link(init) * 0x80;
-				reg &= ~0x20000000;
-			}
-		}
-	}
-
-	if (reg & ~0x00fffffc)
-		warn("unknown bits in register 0x%08x\n", reg);
-
-	if (devinit->mmio)
-		reg = devinit->mmio(devinit, reg);
-	return reg;
-}
-
-static u32
-init_rd32(struct nvbios_init *init, u32 reg)
-{
-	reg = init_nvreg(init, reg);
-	if (reg != ~0 && init_exec(init))
-		return nv_rd32(init->subdev, reg);
-	return 0x00000000;
-}
-
-static void
-init_wr32(struct nvbios_init *init, u32 reg, u32 val)
-{
-	reg = init_nvreg(init, reg);
-	if (reg != ~0 && init_exec(init))
-		nv_wr32(init->subdev, reg, val);
-}
-
-static u32
-init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
-{
-	reg = init_nvreg(init, reg);
-	if (reg != ~0 && init_exec(init)) {
-		u32 tmp = nv_rd32(init->subdev, reg);
-		nv_wr32(init->subdev, reg, (tmp & ~mask) | val);
-		return tmp;
-	}
-	return 0x00000000;
-}
-
-static u8
-init_rdport(struct nvbios_init *init, u16 port)
-{
-	if (init_exec(init))
-		return nv_rdport(init->subdev, init->crtc, port);
-	return 0x00;
-}
-
-static void
-init_wrport(struct nvbios_init *init, u16 port, u8 value)
-{
-	if (init_exec(init))
-		nv_wrport(init->subdev, init->crtc, port, value);
-}
-
-static u8
-init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
-{
-	struct nouveau_subdev *subdev = init->subdev;
-	if (init_exec(init)) {
-		int head = init->crtc < 0 ? 0 : init->crtc;
-		return nv_rdvgai(subdev, head, port, index);
-	}
-	return 0x00;
-}
-
-static void
-init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
-{
-	/* force head 0 for updates to cr44, it only exists on first head */
-	if (nv_device(init->subdev)->card_type < NV_50) {
-		if (port == 0x03d4 && index == 0x44)
-			init->crtc = 0;
-	}
-
-	if (init_exec(init)) {
-		int head = init->crtc < 0 ? 0 : init->crtc;
-		nv_wrvgai(init->subdev, head, port, index, value);
-	}
-
-	/* select head 1 if cr44 write selected it */
-	if (nv_device(init->subdev)->card_type < NV_50) {
-		if (port == 0x03d4 && index == 0x44 && value == 3)
-			init->crtc = 1;
-	}
-}
-
-static struct nouveau_i2c_port *
-init_i2c(struct nvbios_init *init, int index)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(init->bios);
-
-	if (index == 0xff) {
-		index = NV_I2C_DEFAULT(0);
-		if (init->outp && init->outp->i2c_upper_default)
-			index = NV_I2C_DEFAULT(1);
-	} else
-	if (index < 0) {
-		if (!init->outp) {
-			if (init_exec(init))
-				error("script needs output for i2c\n");
-			return NULL;
-		}
-
-		if (index == -2 && init->outp->location) {
-			index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
-			return i2c->find_type(i2c, index);
-		}
-
-		index = init->outp->i2c_index;
-		if (init->outp->type == DCB_OUTPUT_DP)
-			index += NV_I2C_AUX(0);
-	}
-
-	return i2c->find(i2c, index);
-}
-
-static int
-init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg)
-{
-	struct nouveau_i2c_port *port = init_i2c(init, index);
-	if (port && init_exec(init))
-		return nv_rdi2cr(port, addr, reg);
-	return -ENODEV;
-}
-
-static int
-init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
-{
-	struct nouveau_i2c_port *port = init_i2c(init, index);
-	if (port && init_exec(init))
-		return nv_wri2cr(port, addr, reg, val);
-	return -ENODEV;
-}
-
-static u8
-init_rdauxr(struct nvbios_init *init, u32 addr)
-{
-	struct nouveau_i2c_port *port = init_i2c(init, -2);
-	u8 data;
-
-	if (port && init_exec(init)) {
-		int ret = nv_rdaux(port, addr, &data, 1);
-		if (ret == 0)
-			return data;
-		trace("auxch read failed with %d\n", ret);
-	}
-
-	return 0x00;
-}
-
-static int
-init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
-{
-	struct nouveau_i2c_port *port = init_i2c(init, -2);
-	if (port && init_exec(init)) {
-		int ret = nv_wraux(port, addr, &data, 1);
-		if (ret)
-			trace("auxch write failed with %d\n", ret);
-		return ret;
-	}
-	return -ENODEV;
-}
-
-static void
-init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
-	if (devinit->pll_set && init_exec(init)) {
-		int ret = devinit->pll_set(devinit, id, freq);
-		if (ret)
-			warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
-	}
-}
-
-/******************************************************************************
- * parsing of bios structures that are required to execute init tables
- *****************************************************************************/
-
-static u16
-init_table(struct nouveau_bios *bios, u16 *len)
-{
-	struct bit_entry bit_I;
-
-	if (!bit_entry(bios, 'I', &bit_I)) {
-		*len = bit_I.length;
-		return bit_I.offset;
-	}
-
-	if (bmp_version(bios) >= 0x0510) {
-		*len = 14;
-		return bios->bmp_offset + 75;
-	}
-
-	return 0x0000;
-}
-
-static u16
-init_table_(struct nvbios_init *init, u16 offset, const char *name)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 len, data = init_table(bios, &len);
-	if (data) {
-		if (len >= offset + 2) {
-			data = nv_ro16(bios, data + offset);
-			if (data)
-				return data;
-
-			warn("%s pointer invalid\n", name);
-			return 0x0000;
-		}
-
-		warn("init data too short for %s pointer", name);
-		return 0x0000;
-	}
-
-	warn("init data not found\n");
-	return 0x0000;
-}
-
-#define init_script_table(b) init_table_((b), 0x00, "script table")
-#define init_macro_index_table(b) init_table_((b), 0x02, "macro index table")
-#define init_macro_table(b) init_table_((b), 0x04, "macro table")
-#define init_condition_table(b) init_table_((b), 0x06, "condition table")
-#define init_io_condition_table(b) init_table_((b), 0x08, "io condition table")
-#define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag conditon table")
-#define init_function_table(b) init_table_((b), 0x0c, "function table")
-#define init_xlat_table(b) init_table_((b), 0x10, "xlat table");
-
-static u16
-init_script(struct nouveau_bios *bios, int index)
-{
-	struct nvbios_init init = { .bios = bios };
-	u16 bmp_ver = bmp_version(bios), data;
-
-	if (bmp_ver && bmp_ver < 0x0510) {
-		if (index > 1 || bmp_ver < 0x0100)
-			return 0x0000;
-
-		data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
-		return nv_ro16(bios, data + (index * 2));
-	}
-
-	data = init_script_table(&init);
-	if (data)
-		return nv_ro16(bios, data + (index * 2));
-
-	return 0x0000;
-}
-
-static u16
-init_unknown_script(struct nouveau_bios *bios)
-{
-	u16 len, data = init_table(bios, &len);
-	if (data && len >= 16)
-		return nv_ro16(bios, data + 14);
-	return 0x0000;
-}
-
-static u8
-init_ram_restrict_group_count(struct nvbios_init *init)
-{
-	return nvbios_ramcfg_count(init->bios);
-}
-
-static u8
-init_ram_restrict(struct nvbios_init *init)
-{
-	/* This appears to be the behaviour of the VBIOS parser, and *is*
-	 * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
-	 * avoid fucking up the memory controller (somehow) by reading it
-	 * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
-	 *
-	 * Preserving the non-caching behaviour on earlier chipsets just
-	 * in case *not* re-reading the strap causes similar breakage.
-	 */
-	if (!init->ramcfg || init->bios->version.major < 0x70)
-		init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
-	return (init->ramcfg & 0x7fffffff);
-}
-
-static u8
-init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 table = init_xlat_table(init);
-	if (table) {
-		u16 data = nv_ro16(bios, table + (index * 2));
-		if (data)
-			return nv_ro08(bios, data + offset);
-		warn("xlat table pointer %d invalid\n", index);
-	}
-	return 0x00;
-}
-
-/******************************************************************************
- * utility functions used by various init opcode handlers
- *****************************************************************************/
-
-static bool
-init_condition_met(struct nvbios_init *init, u8 cond)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 table = init_condition_table(init);
-	if (table) {
-		u32 reg = nv_ro32(bios, table + (cond * 12) + 0);
-		u32 msk = nv_ro32(bios, table + (cond * 12) + 4);
-		u32 val = nv_ro32(bios, table + (cond * 12) + 8);
-		trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n",
-		      cond, reg, msk, val);
-		return (init_rd32(init, reg) & msk) == val;
-	}
-	return false;
-}
-
-static bool
-init_io_condition_met(struct nvbios_init *init, u8 cond)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 table = init_io_condition_table(init);
-	if (table) {
-		u16 port = nv_ro16(bios, table + (cond * 5) + 0);
-		u8 index = nv_ro08(bios, table + (cond * 5) + 2);
-		u8  mask = nv_ro08(bios, table + (cond * 5) + 3);
-		u8 value = nv_ro08(bios, table + (cond * 5) + 4);
-		trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n",
-		      cond, port, index, mask, value);
-		return (init_rdvgai(init, port, index) & mask) == value;
-	}
-	return false;
-}
-
-static bool
-init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 table = init_io_flag_condition_table(init);
-	if (table) {
-		u16 port = nv_ro16(bios, table + (cond * 9) + 0);
-		u8 index = nv_ro08(bios, table + (cond * 9) + 2);
-		u8  mask = nv_ro08(bios, table + (cond * 9) + 3);
-		u8 shift = nv_ro08(bios, table + (cond * 9) + 4);
-		u16 data = nv_ro16(bios, table + (cond * 9) + 5);
-		u8 dmask = nv_ro08(bios, table + (cond * 9) + 7);
-		u8 value = nv_ro08(bios, table + (cond * 9) + 8);
-		u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift;
-		return (nv_ro08(bios, data + ioval) & dmask) == value;
-	}
-	return false;
-}
-
-static inline u32
-init_shift(u32 data, u8 shift)
-{
-	if (shift < 0x80)
-		return data >> shift;
-	return data << (0x100 - shift);
-}
-
-static u32
-init_tmds_reg(struct nvbios_init *init, u8 tmds)
-{
-	/* For mlv < 0x80, it is an index into a table of TMDS base addresses.
-	 * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
-	 * CR58 for CR57 = 0 to index a table of offsets to the basic
-	 * 0x6808b0 address.
-	 * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
-	 * CR58 for CR57 = 0 to index a table of offsets to the basic
-	 * 0x6808b0 address, and then flip the offset by 8.
-	 */
-
-	const int pramdac_offset[13] = {
-		0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
-	const u32 pramdac_table[4] = {
-		0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
-
-	if (tmds >= 0x80) {
-		if (init->outp) {
-			u32 dacoffset = pramdac_offset[init->outp->or];
-			if (tmds == 0x81)
-				dacoffset ^= 8;
-			return 0x6808b0 + dacoffset;
-		}
-
-		if (init_exec(init))
-			error("tmds opcodes need dcb\n");
-	} else {
-		if (tmds < ARRAY_SIZE(pramdac_table))
-			return pramdac_table[tmds];
-
-		error("tmds selector 0x%02x unknown\n", tmds);
-	}
-
-	return 0;
-}
-
-/******************************************************************************
- * init opcode handlers
- *****************************************************************************/
-
-/**
- * init_reserved - stub for various unknown/unused single-byte opcodes
- *
- */
-static void
-init_reserved(struct nvbios_init *init)
-{
-	u8 opcode = nv_ro08(init->bios, init->offset);
-	u8 length, i;
-
-	switch (opcode) {
-	case 0xaa:
-		length = 4;
-		break;
-	default:
-		length = 1;
-		break;
-	}
-
-	trace("RESERVED 0x%02x\t", opcode);
-	for (i = 1; i < length; i++)
-		cont(" 0x%02x", nv_ro08(init->bios, init->offset + i));
-	cont("\n");
-	init->offset += length;
-}
-
-/**
- * INIT_DONE - opcode 0x71
- *
- */
-static void
-init_done(struct nvbios_init *init)
-{
-	trace("DONE\n");
-	init->offset = 0x0000;
-}
-
-/**
- * INIT_IO_RESTRICT_PROG - opcode 0x32
- *
- */
-static void
-init_io_restrict_prog(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8 index = nv_ro08(bios, init->offset + 3);
-	u8  mask = nv_ro08(bios, init->offset + 4);
-	u8 shift = nv_ro08(bios, init->offset + 5);
-	u8 count = nv_ro08(bios, init->offset + 6);
-	u32  reg = nv_ro32(bios, init->offset + 7);
-	u8 conf, i;
-
-	trace("IO_RESTRICT_PROG\tR[0x%06x] = "
-	      "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n",
-	      reg, port, index, mask, shift);
-	init->offset += 11;
-
-	conf = (init_rdvgai(init, port, index) & mask) >> shift;
-	for (i = 0; i < count; i++) {
-		u32 data = nv_ro32(bios, init->offset);
-
-		if (i == conf) {
-			trace("\t0x%08x *\n", data);
-			init_wr32(init, reg, data);
-		} else {
-			trace("\t0x%08x\n", data);
-		}
-
-		init->offset += 4;
-	}
-	trace("}]\n");
-}
-
-/**
- * INIT_REPEAT - opcode 0x33
- *
- */
-static void
-init_repeat(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 count = nv_ro08(bios, init->offset + 1);
-	u16 repeat = init->repeat;
-
-	trace("REPEAT\t0x%02x\n", count);
-	init->offset += 2;
-
-	init->repeat = init->offset;
-	init->repend = init->offset;
-	while (count--) {
-		init->offset = init->repeat;
-		nvbios_exec(init);
-		if (count)
-			trace("REPEAT\t0x%02x\n", count);
-	}
-	init->offset = init->repend;
-	init->repeat = repeat;
-}
-
-/**
- * INIT_IO_RESTRICT_PLL - opcode 0x34
- *
- */
-static void
-init_io_restrict_pll(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8 index = nv_ro08(bios, init->offset + 3);
-	u8  mask = nv_ro08(bios, init->offset + 4);
-	u8 shift = nv_ro08(bios, init->offset + 5);
-	s8  iofc = nv_ro08(bios, init->offset + 6);
-	u8 count = nv_ro08(bios, init->offset + 7);
-	u32  reg = nv_ro32(bios, init->offset + 8);
-	u8 conf, i;
-
-	trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= "
-	      "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n",
-	      reg, port, index, mask, shift, iofc);
-	init->offset += 12;
-
-	conf = (init_rdvgai(init, port, index) & mask) >> shift;
-	for (i = 0; i < count; i++) {
-		u32 freq = nv_ro16(bios, init->offset) * 10;
-
-		if (i == conf) {
-			trace("\t%dkHz *\n", freq);
-			if (iofc > 0 && init_io_flag_condition_met(init, iofc))
-				freq *= 2;
-			init_prog_pll(init, reg, freq);
-		} else {
-			trace("\t%dkHz\n", freq);
-		}
-
-		init->offset += 2;
-	}
-	trace("}]\n");
-}
-
-/**
- * INIT_END_REPEAT - opcode 0x36
- *
- */
-static void
-init_end_repeat(struct nvbios_init *init)
-{
-	trace("END_REPEAT\n");
-	init->offset += 1;
-
-	if (init->repeat) {
-		init->repend = init->offset;
-		init->offset = 0;
-	}
-}
-
-/**
- * INIT_COPY - opcode 0x37
- *
- */
-static void
-init_copy(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u8 shift = nv_ro08(bios, init->offset + 5);
-	u8 smask = nv_ro08(bios, init->offset + 6);
-	u16 port = nv_ro16(bios, init->offset + 7);
-	u8 index = nv_ro08(bios, init->offset + 9);
-	u8  mask = nv_ro08(bios, init->offset + 10);
-	u8  data;
-
-	trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= "
-	      "((R[0x%06x] %s 0x%02x) & 0x%02x)\n",
-	      port, index, mask, reg, (shift & 0x80) ? "<<" : ">>",
-	      (shift & 0x80) ? (0x100 - shift) : shift, smask);
-	init->offset += 11;
-
-	data  = init_rdvgai(init, port, index) & mask;
-	data |= init_shift(init_rd32(init, reg), shift) & smask;
-	init_wrvgai(init, port, index, data);
-}
-
-/**
- * INIT_NOT - opcode 0x38
- *
- */
-static void
-init_not(struct nvbios_init *init)
-{
-	trace("NOT\n");
-	init->offset += 1;
-	init_exec_inv(init);
-}
-
-/**
- * INIT_IO_FLAG_CONDITION - opcode 0x39
- *
- */
-static void
-init_io_flag_condition(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 cond = nv_ro08(bios, init->offset + 1);
-
-	trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
-	init->offset += 2;
-
-	if (!init_io_flag_condition_met(init, cond))
-		init_exec_set(init, false);
-}
-
-/**
- * INIT_DP_CONDITION - opcode 0x3a
- *
- */
-static void
-init_dp_condition(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	struct nvbios_dpout info;
-	u8  cond = nv_ro08(bios, init->offset + 1);
-	u8  unkn = nv_ro08(bios, init->offset + 2);
-	u8  ver, hdr, cnt, len;
-	u16 data;
-
-	trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn);
-	init->offset += 3;
-
-	switch (cond) {
-	case 0:
-		if (init_conn(init) != DCB_CONNECTOR_eDP)
-			init_exec_set(init, false);
-		break;
-	case 1:
-	case 2:
-		if ( init->outp &&
-		    (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
-					       (init->outp->or << 0) |
-					       (init->outp->sorconf.link << 6),
-					       &ver, &hdr, &cnt, &len, &info)))
-		{
-			if (!(info.flags & cond))
-				init_exec_set(init, false);
-			break;
-		}
-
-		if (init_exec(init))
-			warn("script needs dp output table data\n");
-		break;
-	case 5:
-		if (!(init_rdauxr(init, 0x0d) & 1))
-			init_exec_set(init, false);
-		break;
-	default:
-		warn("unknown dp condition 0x%02x\n", cond);
-		break;
-	}
-}
-
-/**
- * INIT_IO_MASK_OR - opcode 0x3b
- *
- */
-static void
-init_io_mask_or(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8    or = init_or(init);
-	u8  data;
-
-	trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)\n", index, or);
-	init->offset += 2;
-
-	data = init_rdvgai(init, 0x03d4, index);
-	init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
-}
-
-/**
- * INIT_IO_OR - opcode 0x3c
- *
- */
-static void
-init_io_or(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8    or = init_or(init);
-	u8  data;
-
-	trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)\n", index, or);
-	init->offset += 2;
-
-	data = init_rdvgai(init, 0x03d4, index);
-	init_wrvgai(init, 0x03d4, index, data | (1 << or));
-}
-
-/**
- * INIT_ANDN_REG - opcode 0x47
- *
- */
-static void
-init_andn_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u32 mask = nv_ro32(bios, init->offset + 5);
-
-	trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
-	init->offset += 9;
-
-	init_mask(init, reg, mask, 0);
-}
-
-/**
- * INIT_OR_REG - opcode 0x48
- *
- */
-static void
-init_or_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u32 mask = nv_ro32(bios, init->offset + 5);
-
-	trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
-	init->offset += 9;
-
-	init_mask(init, reg, 0, mask);
-}
-
-/**
- * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
- *
- */
-static void
-init_idx_addr_latched(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 creg = nv_ro32(bios, init->offset + 1);
-	u32 dreg = nv_ro32(bios, init->offset + 5);
-	u32 mask = nv_ro32(bios, init->offset + 9);
-	u32 data = nv_ro32(bios, init->offset + 13);
-	u8 count = nv_ro08(bios, init->offset + 17);
-
-	trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
-	trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
-	init->offset += 18;
-
-	while (count--) {
-		u8 iaddr = nv_ro08(bios, init->offset + 0);
-		u8 idata = nv_ro08(bios, init->offset + 1);
-
-		trace("\t[0x%02x] = 0x%02x\n", iaddr, idata);
-		init->offset += 2;
-
-		init_wr32(init, dreg, idata);
-		init_mask(init, creg, ~mask, data | iaddr);
-	}
-}
-
-/**
- * INIT_IO_RESTRICT_PLL2 - opcode 0x4a
- *
- */
-static void
-init_io_restrict_pll2(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8 index = nv_ro08(bios, init->offset + 3);
-	u8  mask = nv_ro08(bios, init->offset + 4);
-	u8 shift = nv_ro08(bios, init->offset + 5);
-	u8 count = nv_ro08(bios, init->offset + 6);
-	u32  reg = nv_ro32(bios, init->offset + 7);
-	u8  conf, i;
-
-	trace("IO_RESTRICT_PLL2\t"
-	      "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n",
-	      reg, port, index, mask, shift);
-	init->offset += 11;
-
-	conf = (init_rdvgai(init, port, index) & mask) >> shift;
-	for (i = 0; i < count; i++) {
-		u32 freq = nv_ro32(bios, init->offset);
-		if (i == conf) {
-			trace("\t%dkHz *\n", freq);
-			init_prog_pll(init, reg, freq);
-		} else {
-			trace("\t%dkHz\n", freq);
-		}
-		init->offset += 4;
-	}
-	trace("}]\n");
-}
-
-/**
- * INIT_PLL2 - opcode 0x4b
- *
- */
-static void
-init_pll2(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u32 freq = nv_ro32(bios, init->offset + 5);
-
-	trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
-	init->offset += 9;
-
-	init_prog_pll(init, reg, freq);
-}
-
-/**
- * INIT_I2C_BYTE - opcode 0x4c
- *
- */
-static void
-init_i2c_byte(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
-	u8 count = nv_ro08(bios, init->offset + 3);
-
-	trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
-	init->offset += 4;
-
-	while (count--) {
-		u8  reg = nv_ro08(bios, init->offset + 0);
-		u8 mask = nv_ro08(bios, init->offset + 1);
-		u8 data = nv_ro08(bios, init->offset + 2);
-		int val;
-
-		trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data);
-		init->offset += 3;
-
-		val = init_rdi2cr(init, index, addr, reg);
-		if (val < 0)
-			continue;
-		init_wri2cr(init, index, addr, reg, (val & mask) | data);
-	}
-}
-
-/**
- * INIT_ZM_I2C_BYTE - opcode 0x4d
- *
- */
-static void
-init_zm_i2c_byte(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
-	u8 count = nv_ro08(bios, init->offset + 3);
-
-	trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
-	init->offset += 4;
-
-	while (count--) {
-		u8  reg = nv_ro08(bios, init->offset + 0);
-		u8 data = nv_ro08(bios, init->offset + 1);
-
-		trace("\t[0x%02x] = 0x%02x\n", reg, data);
-		init->offset += 2;
-
-		init_wri2cr(init, index, addr, reg, data);
-	}
-
-}
-
-/**
- * INIT_ZM_I2C - opcode 0x4e
- *
- */
-static void
-init_zm_i2c(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
-	u8 count = nv_ro08(bios, init->offset + 3);
-	u8 data[256], i;
-
-	trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr);
-	init->offset += 4;
-
-	for (i = 0; i < count; i++) {
-		data[i] = nv_ro08(bios, init->offset);
-		trace("\t0x%02x\n", data[i]);
-		init->offset++;
-	}
-
-	if (init_exec(init)) {
-		struct nouveau_i2c_port *port = init_i2c(init, index);
-		struct i2c_msg msg = {
-			.addr = addr, .flags = 0, .len = count, .buf = data,
-		};
-		int ret;
-
-		if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1)
-			warn("i2c wr failed, %d\n", ret);
-	}
-}
-
-/**
- * INIT_TMDS - opcode 0x4f
- *
- */
-static void
-init_tmds(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 tmds = nv_ro08(bios, init->offset + 1);
-	u8 addr = nv_ro08(bios, init->offset + 2);
-	u8 mask = nv_ro08(bios, init->offset + 3);
-	u8 data = nv_ro08(bios, init->offset + 4);
-	u32 reg = init_tmds_reg(init, tmds);
-
-	trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n",
-	      tmds, addr, mask, data);
-	init->offset += 5;
-
-	if (reg == 0)
-		return;
-
-	init_wr32(init, reg + 0, addr | 0x00010000);
-	init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask));
-	init_wr32(init, reg + 0, addr);
-}
-
-/**
- * INIT_ZM_TMDS_GROUP - opcode 0x50
- *
- */
-static void
-init_zm_tmds_group(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8  tmds = nv_ro08(bios, init->offset + 1);
-	u8 count = nv_ro08(bios, init->offset + 2);
-	u32  reg = init_tmds_reg(init, tmds);
-
-	trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds);
-	init->offset += 3;
-
-	while (count--) {
-		u8 addr = nv_ro08(bios, init->offset + 0);
-		u8 data = nv_ro08(bios, init->offset + 1);
-
-		trace("\t[0x%02x] = 0x%02x\n", addr, data);
-		init->offset += 2;
-
-		init_wr32(init, reg + 4, data);
-		init_wr32(init, reg + 0, addr);
-	}
-}
-
-/**
- * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
- *
- */
-static void
-init_cr_idx_adr_latch(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 addr0 = nv_ro08(bios, init->offset + 1);
-	u8 addr1 = nv_ro08(bios, init->offset + 2);
-	u8  base = nv_ro08(bios, init->offset + 3);
-	u8 count = nv_ro08(bios, init->offset + 4);
-	u8 save0;
-
-	trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1);
-	init->offset += 5;
-
-	save0 = init_rdvgai(init, 0x03d4, addr0);
-	while (count--) {
-		u8 data = nv_ro08(bios, init->offset);
-
-		trace("\t\t[0x%02x] = 0x%02x\n", base, data);
-		init->offset += 1;
-
-		init_wrvgai(init, 0x03d4, addr0, base++);
-		init_wrvgai(init, 0x03d4, addr1, data);
-	}
-	init_wrvgai(init, 0x03d4, addr0, save0);
-}
-
-/**
- * INIT_CR - opcode 0x52
- *
- */
-static void
-init_cr(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 addr = nv_ro08(bios, init->offset + 1);
-	u8 mask = nv_ro08(bios, init->offset + 2);
-	u8 data = nv_ro08(bios, init->offset + 3);
-	u8 val;
-
-	trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
-	init->offset += 4;
-
-	val = init_rdvgai(init, 0x03d4, addr) & mask;
-	init_wrvgai(init, 0x03d4, addr, val | data);
-}
-
-/**
- * INIT_ZM_CR - opcode 0x53
- *
- */
-static void
-init_zm_cr(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 addr = nv_ro08(bios, init->offset + 1);
-	u8 data = nv_ro08(bios, init->offset + 2);
-
-	trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr,  data);
-	init->offset += 3;
-
-	init_wrvgai(init, 0x03d4, addr, data);
-}
-
-/**
- * INIT_ZM_CR_GROUP - opcode 0x54
- *
- */
-static void
-init_zm_cr_group(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 count = nv_ro08(bios, init->offset + 1);
-
-	trace("ZM_CR_GROUP\n");
-	init->offset += 2;
-
-	while (count--) {
-		u8 addr = nv_ro08(bios, init->offset + 0);
-		u8 data = nv_ro08(bios, init->offset + 1);
-
-		trace("\t\tC[0x%02x] = 0x%02x\n", addr, data);
-		init->offset += 2;
-
-		init_wrvgai(init, 0x03d4, addr, data);
-	}
-}
-
-/**
- * INIT_CONDITION_TIME - opcode 0x56
- *
- */
-static void
-init_condition_time(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8  cond = nv_ro08(bios, init->offset + 1);
-	u8 retry = nv_ro08(bios, init->offset + 2);
-	u8  wait = min((u16)retry * 50, 100);
-
-	trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry);
-	init->offset += 3;
-
-	if (!init_exec(init))
-		return;
-
-	while (wait--) {
-		if (init_condition_met(init, cond))
-			return;
-		mdelay(20);
-	}
-
-	init_exec_set(init, false);
-}
-
-/**
- * INIT_LTIME - opcode 0x57
- *
- */
-static void
-init_ltime(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 msec = nv_ro16(bios, init->offset + 1);
-
-	trace("LTIME\t0x%04x\n", msec);
-	init->offset += 3;
-
-	if (init_exec(init))
-		mdelay(msec);
-}
-
-/**
- * INIT_ZM_REG_SEQUENCE - opcode 0x58
- *
- */
-static void
-init_zm_reg_sequence(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 base = nv_ro32(bios, init->offset + 1);
-	u8 count = nv_ro08(bios, init->offset + 5);
-
-	trace("ZM_REG_SEQUENCE\t0x%02x\n", count);
-	init->offset += 6;
-
-	while (count--) {
-		u32 data = nv_ro32(bios, init->offset);
-
-		trace("\t\tR[0x%06x] = 0x%08x\n", base, data);
-		init->offset += 4;
-
-		init_wr32(init, base, data);
-		base += 4;
-	}
-}
-
-/**
- * INIT_SUB_DIRECT - opcode 0x5b
- *
- */
-static void
-init_sub_direct(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 addr = nv_ro16(bios, init->offset + 1);
-	u16 save;
-
-	trace("SUB_DIRECT\t0x%04x\n", addr);
-
-	if (init_exec(init)) {
-		save = init->offset;
-		init->offset = addr;
-		if (nvbios_exec(init)) {
-			error("error parsing sub-table\n");
-			return;
-		}
-		init->offset = save;
-	}
-
-	init->offset += 3;
-}
-
-/**
- * INIT_JUMP - opcode 0x5c
- *
- */
-static void
-init_jump(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 offset = nv_ro16(bios, init->offset + 1);
-
-	trace("JUMP\t0x%04x\n", offset);
-
-	if (init_exec(init))
-		init->offset = offset;
-	else
-		init->offset += 3;
-}
-
-/**
- * INIT_I2C_IF - opcode 0x5e
- *
- */
-static void
-init_i2c_if(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8  addr = nv_ro08(bios, init->offset + 2);
-	u8   reg = nv_ro08(bios, init->offset + 3);
-	u8  mask = nv_ro08(bios, init->offset + 4);
-	u8  data = nv_ro08(bios, init->offset + 5);
-	u8 value;
-
-	trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n",
-	      index, addr, reg, mask, data);
-	init->offset += 6;
-	init_exec_force(init, true);
-
-	value = init_rdi2cr(init, index, addr, reg);
-	if ((value & mask) != data)
-		init_exec_set(init, false);
-
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_COPY_NV_REG - opcode 0x5f
- *
- */
-static void
-init_copy_nv_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  sreg = nv_ro32(bios, init->offset + 1);
-	u8  shift = nv_ro08(bios, init->offset + 5);
-	u32 smask = nv_ro32(bios, init->offset + 6);
-	u32  sxor = nv_ro32(bios, init->offset + 10);
-	u32  dreg = nv_ro32(bios, init->offset + 14);
-	u32 dmask = nv_ro32(bios, init->offset + 18);
-	u32 data;
-
-	trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= "
-	      "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n",
-	      dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>",
-	      (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor);
-	init->offset += 22;
-
-	data = init_shift(init_rd32(init, sreg), shift);
-	init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
-}
-
-/**
- * INIT_ZM_INDEX_IO - opcode 0x62
- *
- */
-static void
-init_zm_index_io(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8 index = nv_ro08(bios, init->offset + 3);
-	u8  data = nv_ro08(bios, init->offset + 4);
-
-	trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data);
-	init->offset += 5;
-
-	init_wrvgai(init, port, index, data);
-}
-
-/**
- * INIT_COMPUTE_MEM - opcode 0x63
- *
- */
-static void
-init_compute_mem(struct nvbios_init *init)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
-
-	trace("COMPUTE_MEM\n");
-	init->offset += 1;
-
-	init_exec_force(init, true);
-	if (init_exec(init) && devinit->meminit)
-		devinit->meminit(devinit);
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_RESET - opcode 0x65
- *
- */
-static void
-init_reset(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32   reg = nv_ro32(bios, init->offset + 1);
-	u32 data1 = nv_ro32(bios, init->offset + 5);
-	u32 data2 = nv_ro32(bios, init->offset + 9);
-	u32 savepci19;
-
-	trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2);
-	init->offset += 13;
-	init_exec_force(init, true);
-
-	savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000);
-	init_wr32(init, reg, data1);
-	udelay(10);
-	init_wr32(init, reg, data2);
-	init_wr32(init, 0x00184c, savepci19);
-	init_mask(init, 0x001850, 0x00000001, 0x00000000);
-
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_MEM - opcode 0x66
- *
- */
-static u16
-init_configure_mem_clk(struct nvbios_init *init)
-{
-	u16 mdata = bmp_mem_init_table(init->bios);
-	if (mdata)
-		mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
-	return mdata;
-}
-
-static void
-init_configure_mem(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 mdata, sdata;
-	u32 addr, data;
-
-	trace("CONFIGURE_MEM\n");
-	init->offset += 1;
-
-	if (bios->version.major > 2) {
-		init_done(init);
-		return;
-	}
-	init_exec_force(init, true);
-
-	mdata = init_configure_mem_clk(init);
-	sdata = bmp_sdr_seq_table(bios);
-	if (nv_ro08(bios, mdata) & 0x01)
-		sdata = bmp_ddr_seq_table(bios);
-	mdata += 6; /* skip to data */
-
-	data = init_rdvgai(init, 0x03c4, 0x01);
-	init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
-
-	for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) {
-		switch (addr) {
-		case 0x10021c: /* CKE_NORMAL */
-		case 0x1002d0: /* CMD_REFRESH */
-		case 0x1002d4: /* CMD_PRECHARGE */
-			data = 0x00000001;
-			break;
-		default:
-			data = nv_ro32(bios, mdata);
-			mdata += 4;
-			if (data == 0xffffffff)
-				continue;
-			break;
-		}
-
-		init_wr32(init, addr, data);
-	}
-
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_CLK - opcode 0x67
- *
- */
-static void
-init_configure_clk(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 mdata, clock;
-
-	trace("CONFIGURE_CLK\n");
-	init->offset += 1;
-
-	if (bios->version.major > 2) {
-		init_done(init);
-		return;
-	}
-	init_exec_force(init, true);
-
-	mdata = init_configure_mem_clk(init);
-
-	/* NVPLL */
-	clock = nv_ro16(bios, mdata + 4) * 10;
-	init_prog_pll(init, 0x680500, clock);
-
-	/* MPLL */
-	clock = nv_ro16(bios, mdata + 2) * 10;
-	if (nv_ro08(bios, mdata) & 0x01)
-		clock *= 2;
-	init_prog_pll(init, 0x680504, clock);
-
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_PREINIT - opcode 0x68
- *
- */
-static void
-init_configure_preinit(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 strap;
-
-	trace("CONFIGURE_PREINIT\n");
-	init->offset += 1;
-
-	if (bios->version.major > 2) {
-		init_done(init);
-		return;
-	}
-	init_exec_force(init, true);
-
-	strap = init_rd32(init, 0x101000);
-	strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6);
-	init_wrvgai(init, 0x03d4, 0x3c, strap);
-
-	init_exec_force(init, false);
-}
-
-/**
- * INIT_IO - opcode 0x69
- *
- */
-static void
-init_io(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8  mask = nv_ro16(bios, init->offset + 3);
-	u8  data = nv_ro16(bios, init->offset + 4);
-	u8 value;
-
-	trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data);
-	init->offset += 5;
-
-	/* ummm.. yes.. should really figure out wtf this is and why it's
-	 * needed some day..  it's almost certainly wrong, but, it also
-	 * somehow makes things work...
-	 */
-	if (nv_device(init->bios)->card_type >= NV_50 &&
-	    port == 0x03c3 && data == 0x01) {
-		init_mask(init, 0x614100, 0xf0800000, 0x00800000);
-		init_mask(init, 0x00e18c, 0x00020000, 0x00020000);
-		init_mask(init, 0x614900, 0xf0800000, 0x00800000);
-		init_mask(init, 0x000200, 0x40000000, 0x00000000);
-		mdelay(10);
-		init_mask(init, 0x00e18c, 0x00020000, 0x00000000);
-		init_mask(init, 0x000200, 0x40000000, 0x40000000);
-		init_wr32(init, 0x614100, 0x00800018);
-		init_wr32(init, 0x614900, 0x00800018);
-		mdelay(10);
-		init_wr32(init, 0x614100, 0x10000018);
-		init_wr32(init, 0x614900, 0x10000018);
-	}
-
-	value = init_rdport(init, port) & mask;
-	init_wrport(init, port, data | value);
-}
-
-/**
- * INIT_SUB - opcode 0x6b
- *
- */
-static void
-init_sub(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u16 addr, save;
-
-	trace("SUB\t0x%02x\n", index);
-
-	addr = init_script(bios, index);
-	if (addr && init_exec(init)) {
-		save = init->offset;
-		init->offset = addr;
-		if (nvbios_exec(init)) {
-			error("error parsing sub-table\n");
-			return;
-		}
-		init->offset = save;
-	}
-
-	init->offset += 2;
-}
-
-/**
- * INIT_RAM_CONDITION - opcode 0x6d
- *
- */
-static void
-init_ram_condition(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8  mask = nv_ro08(bios, init->offset + 1);
-	u8 value = nv_ro08(bios, init->offset + 2);
-
-	trace("RAM_CONDITION\t"
-	      "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value);
-	init->offset += 3;
-
-	if ((init_rd32(init, 0x100000) & mask) != value)
-		init_exec_set(init, false);
-}
-
-/**
- * INIT_NV_REG - opcode 0x6e
- *
- */
-static void
-init_nv_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u32 mask = nv_ro32(bios, init->offset + 5);
-	u32 data = nv_ro32(bios, init->offset + 9);
-
-	trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data);
-	init->offset += 13;
-
-	init_mask(init, reg, ~mask, data);
-}
-
-/**
- * INIT_MACRO - opcode 0x6f
- *
- */
-static void
-init_macro(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8  macro = nv_ro08(bios, init->offset + 1);
-	u16 table;
-
-	trace("MACRO\t0x%02x\n", macro);
-
-	table = init_macro_table(init);
-	if (table) {
-		u32 addr = nv_ro32(bios, table + (macro * 8) + 0);
-		u32 data = nv_ro32(bios, table + (macro * 8) + 4);
-		trace("\t\tR[0x%06x] = 0x%08x\n", addr, data);
-		init_wr32(init, addr, data);
-	}
-
-	init->offset += 2;
-}
-
-/**
- * INIT_RESUME - opcode 0x72
- *
- */
-static void
-init_resume(struct nvbios_init *init)
-{
-	trace("RESUME\n");
-	init->offset += 1;
-	init_exec_set(init, true);
-}
-
-/**
- * INIT_TIME - opcode 0x74
- *
- */
-static void
-init_time(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 usec = nv_ro16(bios, init->offset + 1);
-
-	trace("TIME\t0x%04x\n", usec);
-	init->offset += 3;
-
-	if (init_exec(init)) {
-		if (usec < 1000)
-			udelay(usec);
-		else
-			mdelay((usec + 900) / 1000);
-	}
-}
-
-/**
- * INIT_CONDITION - opcode 0x75
- *
- */
-static void
-init_condition(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 cond = nv_ro08(bios, init->offset + 1);
-
-	trace("CONDITION\t0x%02x\n", cond);
-	init->offset += 2;
-
-	if (!init_condition_met(init, cond))
-		init_exec_set(init, false);
-}
-
-/**
- * INIT_IO_CONDITION - opcode 0x76
- *
- */
-static void
-init_io_condition(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 cond = nv_ro08(bios, init->offset + 1);
-
-	trace("IO_CONDITION\t0x%02x\n", cond);
-	init->offset += 2;
-
-	if (!init_io_condition_met(init, cond))
-		init_exec_set(init, false);
-}
-
-/**
- * INIT_INDEX_IO - opcode 0x78
- *
- */
-static void
-init_index_io(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u16 port = nv_ro16(bios, init->offset + 1);
-	u8 index = nv_ro16(bios, init->offset + 3);
-	u8  mask = nv_ro08(bios, init->offset + 4);
-	u8  data = nv_ro08(bios, init->offset + 5);
-	u8 value;
-
-	trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n",
-	      port, index, mask, data);
-	init->offset += 6;
-
-	value = init_rdvgai(init, port, index) & mask;
-	init_wrvgai(init, port, index, data | value);
-}
-
-/**
- * INIT_PLL - opcode 0x79
- *
- */
-static void
-init_pll(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32  reg = nv_ro32(bios, init->offset + 1);
-	u32 freq = nv_ro16(bios, init->offset + 5) * 10;
-
-	trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
-	init->offset += 7;
-
-	init_prog_pll(init, reg, freq);
-}
-
-/**
- * INIT_ZM_REG - opcode 0x7a
- *
- */
-static void
-init_zm_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u32 data = nv_ro32(bios, init->offset + 5);
-
-	trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data);
-	init->offset += 9;
-
-	if (addr == 0x000200)
-		data |= 0x00000001;
-
-	init_wr32(init, addr, data);
-}
-
-/**
- * INIT_RAM_RESTRICT_PLL - opcde 0x87
- *
- */
-static void
-init_ram_restrict_pll(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8  type = nv_ro08(bios, init->offset + 1);
-	u8 count = init_ram_restrict_group_count(init);
-	u8 strap = init_ram_restrict(init);
-	u8 cconf;
-
-	trace("RAM_RESTRICT_PLL\t0x%02x\n", type);
-	init->offset += 2;
-
-	for (cconf = 0; cconf < count; cconf++) {
-		u32 freq = nv_ro32(bios, init->offset);
-
-		if (cconf == strap) {
-			trace("%dkHz *\n", freq);
-			init_prog_pll(init, type, freq);
-		} else {
-			trace("%dkHz\n", freq);
-		}
-
-		init->offset += 4;
-	}
-}
-
-/**
- * INIT_GPIO - opcode 0x8e
- *
- */
-static void
-init_gpio(struct nvbios_init *init)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(init->bios);
-
-	trace("GPIO\n");
-	init->offset += 1;
-
-	if (init_exec(init) && gpio && gpio->reset)
-		gpio->reset(gpio, DCB_GPIO_UNUSED);
-}
-
-/**
- * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
- *
- */
-static void
-init_ram_restrict_zm_reg_group(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u8  incr = nv_ro08(bios, init->offset + 5);
-	u8   num = nv_ro08(bios, init->offset + 6);
-	u8 count = init_ram_restrict_group_count(init);
-	u8 index = init_ram_restrict(init);
-	u8 i, j;
-
-	trace("RAM_RESTRICT_ZM_REG_GROUP\t"
-	      "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
-	init->offset += 7;
-
-	for (i = 0; i < num; i++) {
-		trace("\tR[0x%06x] = {\n", addr);
-		for (j = 0; j < count; j++) {
-			u32 data = nv_ro32(bios, init->offset);
-
-			if (j == index) {
-				trace("\t\t0x%08x *\n", data);
-				init_wr32(init, addr, data);
-			} else {
-				trace("\t\t0x%08x\n", data);
-			}
-
-			init->offset += 4;
-		}
-		trace("\t}\n");
-		addr += incr;
-	}
-}
-
-/**
- * INIT_COPY_ZM_REG - opcode 0x90
- *
- */
-static void
-init_copy_zm_reg(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 sreg = nv_ro32(bios, init->offset + 1);
-	u32 dreg = nv_ro32(bios, init->offset + 5);
-
-	trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
-	init->offset += 9;
-
-	init_wr32(init, dreg, init_rd32(init, sreg));
-}
-
-/**
- * INIT_ZM_REG_GROUP - opcode 0x91
- *
- */
-static void
-init_zm_reg_group(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u8 count = nv_ro08(bios, init->offset + 5);
-
-	trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
-	init->offset += 6;
-
-	while (count--) {
-		u32 data = nv_ro32(bios, init->offset);
-		trace("\t0x%08x\n", data);
-		init_wr32(init, addr, data);
-		init->offset += 4;
-	}
-}
-
-/**
- * INIT_XLAT - opcode 0x96
- *
- */
-static void
-init_xlat(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 saddr = nv_ro32(bios, init->offset + 1);
-	u8 sshift = nv_ro08(bios, init->offset + 5);
-	u8  smask = nv_ro08(bios, init->offset + 6);
-	u8  index = nv_ro08(bios, init->offset + 7);
-	u32 daddr = nv_ro32(bios, init->offset + 8);
-	u32 dmask = nv_ro32(bios, init->offset + 12);
-	u8  shift = nv_ro08(bios, init->offset + 16);
-	u32 data;
-
-	trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= "
-	      "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n",
-	      daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>",
-	      (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift);
-	init->offset += 17;
-
-	data = init_shift(init_rd32(init, saddr), sshift) & smask;
-	data = init_xlat_(init, index, data) << shift;
-	init_mask(init, daddr, ~dmask, data);
-}
-
-/**
- * INIT_ZM_MASK_ADD - opcode 0x97
- *
- */
-static void
-init_zm_mask_add(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u32 mask = nv_ro32(bios, init->offset + 5);
-	u32  add = nv_ro32(bios, init->offset + 9);
-	u32 data;
-
-	trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
-	init->offset += 13;
-
-	data =  init_rd32(init, addr);
-	data = (data & mask) | ((data + add) & ~mask);
-	init_wr32(init, addr, data);
-}
-
-/**
- * INIT_AUXCH - opcode 0x98
- *
- */
-static void
-init_auxch(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u8 count = nv_ro08(bios, init->offset + 5);
-
-	trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
-	init->offset += 6;
-
-	while (count--) {
-		u8 mask = nv_ro08(bios, init->offset + 0);
-		u8 data = nv_ro08(bios, init->offset + 1);
-		trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
-		mask = init_rdauxr(init, addr) & mask;
-		init_wrauxr(init, addr, mask | data);
-		init->offset += 2;
-	}
-}
-
-/**
- * INIT_AUXCH - opcode 0x99
- *
- */
-static void
-init_zm_auxch(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u32 addr = nv_ro32(bios, init->offset + 1);
-	u8 count = nv_ro08(bios, init->offset + 5);
-
-	trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
-	init->offset += 6;
-
-	while (count--) {
-		u8 data = nv_ro08(bios, init->offset + 0);
-		trace("\tAUX[0x%08x] = 0x%02x\n", addr, data);
-		init_wrauxr(init, addr, data);
-		init->offset += 1;
-	}
-}
-
-/**
- * INIT_I2C_LONG_IF - opcode 0x9a
- *
- */
-static void
-init_i2c_long_if(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	u8 index = nv_ro08(bios, init->offset + 1);
-	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
-	u8 reglo = nv_ro08(bios, init->offset + 3);
-	u8 reghi = nv_ro08(bios, init->offset + 4);
-	u8  mask = nv_ro08(bios, init->offset + 5);
-	u8  data = nv_ro08(bios, init->offset + 6);
-	struct nouveau_i2c_port *port;
-
-	trace("I2C_LONG_IF\t"
-	      "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n",
-	      index, addr, reglo, reghi, mask, data);
-	init->offset += 7;
-
-	port = init_i2c(init, index);
-	if (port) {
-		u8 i[2] = { reghi, reglo };
-		u8 o[1] = {};
-		struct i2c_msg msg[] = {
-			{ .addr = addr, .flags = 0, .len = 2, .buf = i },
-			{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o }
-		};
-		int ret;
-
-		ret = i2c_transfer(&port->adapter, msg, 2);
-		if (ret == 2 && ((o[0] & mask) == data))
-			return;
-	}
-
-	init_exec_set(init, false);
-}
-
-/**
- * INIT_GPIO_NE - opcode 0xa9
- *
- */
-static void
-init_gpio_ne(struct nvbios_init *init)
-{
-	struct nouveau_bios *bios = init->bios;
-	struct nouveau_gpio *gpio = nouveau_gpio(bios);
-	struct dcb_gpio_func func;
-	u8 count = nv_ro08(bios, init->offset + 1);
-	u8 idx = 0, ver, len;
-	u16 data, i;
-
-	trace("GPIO_NE\t");
-	init->offset += 2;
-
-	for (i = init->offset; i < init->offset + count; i++)
-		cont("0x%02x ", nv_ro08(bios, i));
-	cont("\n");
-
-	while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
-		if (func.func != DCB_GPIO_UNUSED) {
-			for (i = init->offset; i < init->offset + count; i++) {
-				if (func.func == nv_ro08(bios, i))
-					break;
-			}
-
-			trace("\tFUNC[0x%02x]", func.func);
-			if (i == (init->offset + count)) {
-				cont(" *");
-				if (init_exec(init) && gpio && gpio->reset)
-					gpio->reset(gpio, func.func);
-			}
-			cont("\n");
-		}
-	}
-
-	init->offset += count;
-}
-
-static struct nvbios_init_opcode {
-	void (*exec)(struct nvbios_init *);
-} init_opcode[] = {
-	[0x32] = { init_io_restrict_prog },
-	[0x33] = { init_repeat },
-	[0x34] = { init_io_restrict_pll },
-	[0x36] = { init_end_repeat },
-	[0x37] = { init_copy },
-	[0x38] = { init_not },
-	[0x39] = { init_io_flag_condition },
-	[0x3a] = { init_dp_condition },
-	[0x3b] = { init_io_mask_or },
-	[0x3c] = { init_io_or },
-	[0x47] = { init_andn_reg },
-	[0x48] = { init_or_reg },
-	[0x49] = { init_idx_addr_latched },
-	[0x4a] = { init_io_restrict_pll2 },
-	[0x4b] = { init_pll2 },
-	[0x4c] = { init_i2c_byte },
-	[0x4d] = { init_zm_i2c_byte },
-	[0x4e] = { init_zm_i2c },
-	[0x4f] = { init_tmds },
-	[0x50] = { init_zm_tmds_group },
-	[0x51] = { init_cr_idx_adr_latch },
-	[0x52] = { init_cr },
-	[0x53] = { init_zm_cr },
-	[0x54] = { init_zm_cr_group },
-	[0x56] = { init_condition_time },
-	[0x57] = { init_ltime },
-	[0x58] = { init_zm_reg_sequence },
-	[0x5b] = { init_sub_direct },
-	[0x5c] = { init_jump },
-	[0x5e] = { init_i2c_if },
-	[0x5f] = { init_copy_nv_reg },
-	[0x62] = { init_zm_index_io },
-	[0x63] = { init_compute_mem },
-	[0x65] = { init_reset },
-	[0x66] = { init_configure_mem },
-	[0x67] = { init_configure_clk },
-	[0x68] = { init_configure_preinit },
-	[0x69] = { init_io },
-	[0x6b] = { init_sub },
-	[0x6d] = { init_ram_condition },
-	[0x6e] = { init_nv_reg },
-	[0x6f] = { init_macro },
-	[0x71] = { init_done },
-	[0x72] = { init_resume },
-	[0x74] = { init_time },
-	[0x75] = { init_condition },
-	[0x76] = { init_io_condition },
-	[0x78] = { init_index_io },
-	[0x79] = { init_pll },
-	[0x7a] = { init_zm_reg },
-	[0x87] = { init_ram_restrict_pll },
-	[0x8c] = { init_reserved },
-	[0x8d] = { init_reserved },
-	[0x8e] = { init_gpio },
-	[0x8f] = { init_ram_restrict_zm_reg_group },
-	[0x90] = { init_copy_zm_reg },
-	[0x91] = { init_zm_reg_group },
-	[0x92] = { init_reserved },
-	[0x96] = { init_xlat },
-	[0x97] = { init_zm_mask_add },
-	[0x98] = { init_auxch },
-	[0x99] = { init_zm_auxch },
-	[0x9a] = { init_i2c_long_if },
-	[0xa9] = { init_gpio_ne },
-	[0xaa] = { init_reserved },
-};
-
-#define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
-
-int
-nvbios_exec(struct nvbios_init *init)
-{
-	init->nested++;
-	while (init->offset) {
-		u8 opcode = nv_ro08(init->bios, init->offset);
-		if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) {
-			error("unknown opcode 0x%02x\n", opcode);
-			return -EINVAL;
-		}
-
-		init_opcode[opcode].exec(init);
-	}
-	init->nested--;
-	return 0;
-}
-
-int
-nvbios_init(struct nouveau_subdev *subdev, bool execute)
-{
-	struct nouveau_bios *bios = nouveau_bios(subdev);
-	int ret = 0;
-	int i = -1;
-	u16 data;
-
-	if (execute)
-		nv_info(bios, "running init tables\n");
-	while (!ret && (data = (init_script(bios, ++i)))) {
-		struct nvbios_init init = {
-			.subdev = subdev,
-			.bios = bios,
-			.offset = data,
-			.outp = NULL,
-			.crtc = -1,
-			.execute = execute ? 1 : 0,
-		};
-
-		ret = nvbios_exec(&init);
-	}
-
-	/* the vbios parser will run this right after the normal init
-	 * tables, whereas the binary driver appears to run it later.
-	 */
-	if (!ret && (data = init_unknown_script(bios))) {
-		struct nvbios_init init = {
-			.subdev = subdev,
-			.bios = bios,
-			.offset = data,
-			.outp = NULL,
-			.crtc = -1,
-			.execute = execute ? 1 : 0,
-		};
-
-		ret = nvbios_exec(&init);
-	}
-
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
deleted file mode 100644
index 2610b11..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/mxm.h>
-
-u16
-mxm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr)
-{
-	struct bit_entry x;
-
-	if (bit_entry(bios, 'x', &x)) {
-		nv_debug(bios, "BIT 'x' table not present\n");
-		return 0x0000;
-	}
-
-	*ver = x.version;
-	*hdr = x.length;
-	if (*ver != 1 || *hdr < 3) {
-		nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr);
-		return 0x0000;
-	}
-
-	return x.offset;
-}
-
-/* These map MXM v2.x digital connection values to the appropriate SOR/link,
- * hopefully they're correct for all boards within the same chipset...
- *
- * MXM v3.x VBIOS are nicer and provide pointers to these tables.
- */
-static u8 nv84_sor_map[16] = {
-	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv92_sor_map[16] = {
-	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
-	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv94_sor_map[16] = {
-	0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
-	0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv98_sor_map[16] = {
-	0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
-	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-u8
-mxm_sor_map(struct nouveau_bios *bios, u8 conn)
-{
-	u8  ver, hdr;
-	u16 mxm = mxm_table(bios, &ver, &hdr);
-	if (mxm && hdr >= 6) {
-		u16 map = nv_ro16(bios, mxm + 4);
-		if (map) {
-			ver = nv_ro08(bios, map);
-			if (ver == 0x10) {
-				if (conn < nv_ro08(bios, map + 3)) {
-					map += nv_ro08(bios, map + 1);
-					map += conn;
-					return nv_ro08(bios, map);
-				}
-
-				return 0x00;
-			}
-
-			nv_warn(bios, "unknown sor map v%02x\n", ver);
-		}
-	}
-
-	if (bios->version.chip == 0x84 || bios->version.chip == 0x86)
-		return nv84_sor_map[conn];
-	if (bios->version.chip == 0x92)
-		return nv92_sor_map[conn];
-	if (bios->version.chip == 0x94 || bios->version.chip == 0x96)
-		return nv94_sor_map[conn];
-	if (bios->version.chip == 0x98)
-		return nv98_sor_map[conn];
-
-	nv_warn(bios, "missing sor map\n");
-	return 0x00;
-}
-
-u8
-mxm_ddc_map(struct nouveau_bios *bios, u8 port)
-{
-	u8  ver, hdr;
-	u16 mxm = mxm_table(bios, &ver, &hdr);
-	if (mxm && hdr >= 8) {
-		u16 map = nv_ro16(bios, mxm + 6);
-		if (map) {
-			ver = nv_ro08(bios, map);
-			if (ver == 0x10) {
-				if (port < nv_ro08(bios, map + 3)) {
-					map += nv_ro08(bios, map + 1);
-					map += port;
-					return nv_ro08(bios, map);
-				}
-
-				return 0x00;
-			}
-
-			nv_warn(bios, "unknown ddc map v%02x\n", ver);
-		}
-	}
-
-	/* v2.x: directly write port as dcb i2cidx */
-	return (port << 4) | port;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c
deleted file mode 100644
index d694716..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/npde.h>
-#include <subdev/bios/pcir.h>
-
-u32
-nvbios_npdeTe(struct nouveau_bios *bios, u32 base)
-{
-	struct nvbios_pcirT pcir;
-	u8  ver; u16 hdr;
-	u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
-	if (data = (data + hdr + 0x0f) & ~0x0f, data) {
-		switch (nv_ro32(bios, data + 0x00)) {
-		case 0x4544504e: /* NPDE */
-			break;
-		default:
-			nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
-				 data, nv_ro32(bios, data + 0x00));
-			data = 0;
-			break;
-		}
-	}
-	return data;
-}
-
-u32
-nvbios_npdeTp(struct nouveau_bios *bios, u32 base, struct nvbios_npdeT *info)
-{
-	u32 data = nvbios_npdeTe(bios, base);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->image_size = nv_ro16(bios, data + 0x08) * 512;
-		info->last = nv_ro08(bios, data + 0x0a) & 0x80;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c
deleted file mode 100644
index 91dae26..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pcir.h>
-
-u32
-nvbios_pcirTe(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr)
-{
-	u32 data = nv_ro16(bios, base + 0x18);
-	if (data) {
-		data += base;
-		switch (nv_ro32(bios, data + 0x00)) {
-		case 0x52494350: /* PCIR */
-		case 0x53494752: /* RGIS */
-		case 0x5344504e: /* NPDS */
-			*hdr = nv_ro16(bios, data + 0x0a);
-			*ver = nv_ro08(bios, data + 0x0c);
-			break;
-		default:
-			nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
-				 data, nv_ro32(bios, data + 0x00));
-			data = 0;
-			break;
-		}
-	}
-	return data;
-}
-
-u32
-nvbios_pcirTp(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr,
-	      struct nvbios_pcirT *info)
-{
-	u32 data = nvbios_pcirTe(bios, base, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	if (data) {
-		info->vendor_id = nv_ro16(bios, data + 0x04);
-		info->device_id = nv_ro16(bios, data + 0x06);
-		info->class_code[0] = nv_ro08(bios, data + 0x0d);
-		info->class_code[1] = nv_ro08(bios, data + 0x0e);
-		info->class_code[2] = nv_ro08(bios, data + 0x0f);
-		info->image_size = nv_ro16(bios, data + 0x10) * 512;
-		info->image_rev = nv_ro16(bios, data + 0x12);
-		info->image_type = nv_ro08(bios, data + 0x14);
-		info->last = nv_ro08(bios, data + 0x15) & 0x80;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c
deleted file mode 100644
index 675e221..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/perf.h>
-
-u16
-nvbios_perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
-		  u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_P;
-	u16 perf = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version <= 2) {
-			perf = nv_ro16(bios, bit_P.offset + 0);
-			if (perf) {
-				*ver = nv_ro08(bios, perf + 0);
-				*hdr = nv_ro08(bios, perf + 1);
-				if (*ver >= 0x40 && *ver < 0x41) {
-					*cnt = nv_ro08(bios, perf + 5);
-					*len = nv_ro08(bios, perf + 2);
-					*snr = nv_ro08(bios, perf + 4);
-					*ssz = nv_ro08(bios, perf + 3);
-					return perf;
-				} else
-				if (*ver >= 0x20 && *ver < 0x40) {
-					*cnt = nv_ro08(bios, perf + 2);
-					*len = nv_ro08(bios, perf + 3);
-					*snr = nv_ro08(bios, perf + 4);
-					*ssz = nv_ro08(bios, perf + 5);
-					return perf;
-				}
-			}
-		}
-	}
-
-	if (bios->bmp_offset) {
-		if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) {
-			perf = nv_ro16(bios, bios->bmp_offset + 0x94);
-			if (perf) {
-				*hdr = nv_ro08(bios, perf + 0);
-				*ver = nv_ro08(bios, perf + 1);
-				*cnt = nv_ro08(bios, perf + 2);
-				*len = nv_ro08(bios, perf + 3);
-				*snr = 0;
-				*ssz = 0;
-				return perf;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_perf_entry(struct nouveau_bios *bios, int idx,
-		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (perf && idx < *cnt) {
-		perf = perf + *hdr + (idx * (*len + (snr * ssz)));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return perf;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_perfEp(struct nouveau_bios *bios, int idx,
-	      u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	      struct nvbios_perfE *info)
-{
-	u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	info->pstate = nv_ro08(bios, perf + 0x00);
-	switch (!!perf * *ver) {
-	case 0x12:
-	case 0x13:
-	case 0x14:
-		info->core     = nv_ro32(bios, perf + 0x01) * 10;
-		info->memory   = nv_ro32(bios, perf + 0x05) * 20;
-		info->fanspeed = nv_ro08(bios, perf + 0x37);
-		if (*hdr > 0x38)
-			info->voltage = nv_ro08(bios, perf + 0x38);
-		break;
-	case 0x21:
-	case 0x23:
-	case 0x24:
-		info->fanspeed = nv_ro08(bios, perf + 0x04);
-		info->voltage  = nv_ro08(bios, perf + 0x05);
-		info->shader   = nv_ro16(bios, perf + 0x06) * 1000;
-		info->core     = info->shader + (signed char)
-				 nv_ro08(bios, perf + 0x08) * 1000;
-		switch (nv_device(bios)->chipset) {
-		case 0x49:
-		case 0x4b:
-			info->memory = nv_ro16(bios, perf + 0x0b) * 1000;
-			break;
-		default:
-			info->memory = nv_ro16(bios, perf + 0x0b) * 2000;
-			break;
-		}
-		break;
-	case 0x25:
-		info->fanspeed = nv_ro08(bios, perf + 0x04);
-		info->voltage  = nv_ro08(bios, perf + 0x05);
-		info->core     = nv_ro16(bios, perf + 0x06) * 1000;
-		info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
-		info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
-		break;
-	case 0x30:
-		info->script   = nv_ro16(bios, perf + 0x02);
-	case 0x35:
-		info->fanspeed = nv_ro08(bios, perf + 0x06);
-		info->voltage  = nv_ro08(bios, perf + 0x07);
-		info->core     = nv_ro16(bios, perf + 0x08) * 1000;
-		info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
-		info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
-		info->vdec     = nv_ro16(bios, perf + 0x10) * 1000;
-		info->disp     = nv_ro16(bios, perf + 0x14) * 1000;
-		break;
-	case 0x40:
-		info->voltage  = nv_ro08(bios, perf + 0x02);
-		break;
-	default:
-		return 0x0000;
-	}
-	return perf;
-}
-
-u32
-nvbios_perfSe(struct nouveau_bios *bios, u32 perfE, int idx,
-	      u8 *ver, u8 *hdr, u8 cnt, u8 len)
-{
-	u32 data = 0x00000000;
-	if (idx < cnt) {
-		data = perfE + *hdr + (idx * len);
-		*hdr = len;
-	}
-	return data;
-}
-
-u32
-nvbios_perfSp(struct nouveau_bios *bios, u32 perfE, int idx,
-	      u8 *ver, u8 *hdr, u8 cnt, u8 len,
-	      struct nvbios_perfS *info)
-{
-	u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	case 0x40:
-		info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000;
-		break;
-	default:
-		break;
-	}
-	return data;
-}
-
-int
-nvbios_perf_fan_parse(struct nouveau_bios *bios,
-		      struct nvbios_perf_fan *fan)
-{
-	u8  ver, hdr, cnt, len, snr, ssz;
-	u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
-	if (!perf)
-		return -ENODEV;
-
-	if (ver >= 0x20 && ver < 0x40 && hdr > 6)
-		fan->pwm_divisor = nv_ro16(bios, perf + 6);
-	else
-		fan->pwm_divisor = 0;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c
deleted file mode 100644
index 1f76de5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright 2005-2006 Erik Waling
- * Copyright 2006 Stephane Marchesin
- * Copyright 2007-2009 Stuart Bennett
- *
- * 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 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 <subdev/vga.h>
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/pll.h>
-
-struct pll_mapping {
-	u8  type;
-	u32 reg;
-};
-
-static struct pll_mapping
-nv04_pll_mapping[] = {
-	{ PLL_CORE  , 0x680500 },
-	{ PLL_MEMORY, 0x680504 },
-	{ PLL_VPLL0 , 0x680508 },
-	{ PLL_VPLL1 , 0x680520 },
-	{}
-};
-
-static struct pll_mapping
-nv40_pll_mapping[] = {
-	{ PLL_CORE  , 0x004000 },
-	{ PLL_MEMORY, 0x004020 },
-	{ PLL_VPLL0 , 0x680508 },
-	{ PLL_VPLL1 , 0x680520 },
-	{}
-};
-
-static struct pll_mapping
-nv50_pll_mapping[] = {
-	{ PLL_CORE  , 0x004028 },
-	{ PLL_SHADER, 0x004020 },
-	{ PLL_UNK03 , 0x004000 },
-	{ PLL_MEMORY, 0x004008 },
-	{ PLL_UNK40 , 0x00e810 },
-	{ PLL_UNK41 , 0x00e818 },
-	{ PLL_UNK42 , 0x00e824 },
-	{ PLL_VPLL0 , 0x614100 },
-	{ PLL_VPLL1 , 0x614900 },
-	{}
-};
-
-static struct pll_mapping
-nv84_pll_mapping[] = {
-	{ PLL_CORE  , 0x004028 },
-	{ PLL_SHADER, 0x004020 },
-	{ PLL_MEMORY, 0x004008 },
-	{ PLL_VDEC  , 0x004030 },
-	{ PLL_UNK41 , 0x00e818 },
-	{ PLL_VPLL0 , 0x614100 },
-	{ PLL_VPLL1 , 0x614900 },
-	{}
-};
-
-static u16
-pll_limits_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_C;
-
-	if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) {
-		u16 data = nv_ro16(bios, bit_C.offset + 8);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0);
-			*hdr = nv_ro08(bios, data + 1);
-			*len = nv_ro08(bios, data + 2);
-			*cnt = nv_ro08(bios, data + 3);
-			return data;
-		}
-	}
-
-	if (bmp_version(bios) >= 0x0524) {
-		u16 data = nv_ro16(bios, bios->bmp_offset + 142);
-		if (data) {
-			*ver = nv_ro08(bios, data + 0);
-			*hdr = 1;
-			*cnt = 1;
-			*len = 0x18;
-			return data;
-		}
-	}
-
-	*ver = 0x00;
-	return 0x0000;
-}
-
-static struct pll_mapping *
-pll_map(struct nouveau_bios *bios)
-{
-	switch (nv_device(bios)->card_type) {
-	case NV_04:
-	case NV_10:
-	case NV_11:
-	case NV_20:
-	case NV_30:
-		return nv04_pll_mapping;
-		break;
-	case NV_40:
-		return nv40_pll_mapping;
-	case NV_50:
-		if (nv_device(bios)->chipset == 0x50)
-			return nv50_pll_mapping;
-		else
-		if (nv_device(bios)->chipset <  0xa3 ||
-		    nv_device(bios)->chipset == 0xaa ||
-		    nv_device(bios)->chipset == 0xac)
-			return nv84_pll_mapping;
-	default:
-		return NULL;
-	}
-}
-
-static u16
-pll_map_reg(struct nouveau_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len)
-{
-	struct pll_mapping *map;
-	u8  hdr, cnt;
-	u16 data;
-
-	data = pll_limits_table(bios, ver, &hdr, &cnt, len);
-	if (data && *ver >= 0x30) {
-		data += hdr;
-		while (cnt--) {
-			if (nv_ro32(bios, data + 3) == reg) {
-				*type = nv_ro08(bios, data + 0);
-				return data;
-			}
-			data += *len;
-		}
-		return 0x0000;
-	}
-
-	map = pll_map(bios);
-	while (map->reg) {
-		if (map->reg == reg && *ver >= 0x20) {
-			u16 addr = (data += hdr);
-			*type = map->type;
-			while (cnt--) {
-				if (nv_ro32(bios, data) == map->reg)
-					return data;
-				data += *len;
-			}
-			return addr;
-		} else
-		if (map->reg == reg) {
-			*type = map->type;
-			return data + 1;
-		}
-		map++;
-	}
-
-	return 0x0000;
-}
-
-static u16
-pll_map_type(struct nouveau_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len)
-{
-	struct pll_mapping *map;
-	u8  hdr, cnt;
-	u16 data;
-
-	data = pll_limits_table(bios, ver, &hdr, &cnt, len);
-	if (data && *ver >= 0x30) {
-		data += hdr;
-		while (cnt--) {
-			if (nv_ro08(bios, data + 0) == type) {
-				*reg = nv_ro32(bios, data + 3);
-				return data;
-			}
-			data += *len;
-		}
-		return 0x0000;
-	}
-
-	map = pll_map(bios);
-	while (map->reg) {
-		if (map->type == type && *ver >= 0x20) {
-			u16 addr = (data += hdr);
-			*reg = map->reg;
-			while (cnt--) {
-				if (nv_ro32(bios, data) == map->reg)
-					return data;
-				data += *len;
-			}
-			return addr;
-		} else
-		if (map->type == type) {
-			*reg = map->reg;
-			return data + 1;
-		}
-		map++;
-	}
-
-	return 0x0000;
-}
-
-int
-nvbios_pll_parse(struct nouveau_bios *bios, u32 type, struct nvbios_pll *info)
-{
-	u8  ver, len;
-	u32 reg = type;
-	u16 data;
-
-	if (type > PLL_MAX) {
-		reg  = type;
-		data = pll_map_reg(bios, reg, &type, &ver, &len);
-	} else {
-		data = pll_map_type(bios, type, &reg, &ver, &len);
-	}
-
-	if (ver && !data)
-		return -ENOENT;
-
-	memset(info, 0, sizeof(*info));
-	info->type = type;
-	info->reg = reg;
-
-	switch (ver) {
-	case 0x00:
-		break;
-	case 0x10:
-	case 0x11:
-		info->vco1.min_freq = nv_ro32(bios, data + 0);
-		info->vco1.max_freq = nv_ro32(bios, data + 4);
-		info->vco2.min_freq = nv_ro32(bios, data + 8);
-		info->vco2.max_freq = nv_ro32(bios, data + 12);
-		info->vco1.min_inputfreq = nv_ro32(bios, data + 16);
-		info->vco2.min_inputfreq = nv_ro32(bios, data + 20);
-		info->vco1.max_inputfreq = INT_MAX;
-		info->vco2.max_inputfreq = INT_MAX;
-
-		info->max_p = 0x7;
-		info->max_p_usable = 0x6;
-
-		/* these values taken from nv30/31/36 */
-		switch (bios->version.chip) {
-		case 0x36:
-			info->vco1.min_n = 0x5;
-			break;
-		default:
-			info->vco1.min_n = 0x1;
-			break;
-		}
-		info->vco1.max_n = 0xff;
-		info->vco1.min_m = 0x1;
-		info->vco1.max_m = 0xd;
-
-		/*
-		 * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this
-		 * table version (apart from nv35)), N2 is compared to
-		 * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and
-		 * save a comparison
-		 */
-		info->vco2.min_n = 0x4;
-		switch (bios->version.chip) {
-		case 0x30:
-		case 0x35:
-			info->vco2.max_n = 0x1f;
-			break;
-		default:
-			info->vco2.max_n = 0x28;
-			break;
-		}
-		info->vco2.min_m = 0x1;
-		info->vco2.max_m = 0x4;
-		break;
-	case 0x20:
-	case 0x21:
-		info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000;
-		info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000;
-		info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000;
-		info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000;
-		info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000;
-		info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000;
-		info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000;
-		info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000;
-		info->vco1.min_n = nv_ro08(bios, data + 20);
-		info->vco1.max_n = nv_ro08(bios, data + 21);
-		info->vco1.min_m = nv_ro08(bios, data + 22);
-		info->vco1.max_m = nv_ro08(bios, data + 23);
-		info->vco2.min_n = nv_ro08(bios, data + 24);
-		info->vco2.max_n = nv_ro08(bios, data + 25);
-		info->vco2.min_m = nv_ro08(bios, data + 26);
-		info->vco2.max_m = nv_ro08(bios, data + 27);
-
-		info->max_p = nv_ro08(bios, data + 29);
-		info->max_p_usable = info->max_p;
-		if (bios->version.chip < 0x60)
-			info->max_p_usable = 0x6;
-		info->bias_p = nv_ro08(bios, data + 30);
-
-		if (len > 0x22)
-			info->refclk = nv_ro32(bios, data + 31);
-		break;
-	case 0x30:
-		data = nv_ro16(bios, data + 1);
-
-		info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
-		info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
-		info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000;
-		info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000;
-		info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000;
-		info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000;
-		info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000;
-		info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000;
-		info->vco1.min_n = nv_ro08(bios, data + 16);
-		info->vco1.max_n = nv_ro08(bios, data + 17);
-		info->vco1.min_m = nv_ro08(bios, data + 18);
-		info->vco1.max_m = nv_ro08(bios, data + 19);
-		info->vco2.min_n = nv_ro08(bios, data + 20);
-		info->vco2.max_n = nv_ro08(bios, data + 21);
-		info->vco2.min_m = nv_ro08(bios, data + 22);
-		info->vco2.max_m = nv_ro08(bios, data + 23);
-		info->max_p_usable = info->max_p = nv_ro08(bios, data + 25);
-		info->bias_p = nv_ro08(bios, data + 27);
-		info->refclk = nv_ro32(bios, data + 28);
-		break;
-	case 0x40:
-		info->refclk = nv_ro16(bios, data + 9) * 1000;
-		data = nv_ro16(bios, data + 1);
-
-		info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
-		info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
-		info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000;
-		info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000;
-		info->vco1.min_m = nv_ro08(bios, data + 8);
-		info->vco1.max_m = nv_ro08(bios, data + 9);
-		info->vco1.min_n = nv_ro08(bios, data + 10);
-		info->vco1.max_n = nv_ro08(bios, data + 11);
-		info->min_p = nv_ro08(bios, data + 12);
-		info->max_p = nv_ro08(bios, data + 13);
-		break;
-	default:
-		nv_error(bios, "unknown pll limits version 0x%02x\n", ver);
-		return -EINVAL;
-	}
-
-	if (!info->refclk) {
-		info->refclk = nv_device(bios)->crystal;
-		if (bios->version.chip == 0x51) {
-			u32 sel_clk = nv_rd32(bios, 0x680524);
-			if ((info->reg == 0x680508 && sel_clk & 0x20) ||
-			    (info->reg == 0x680520 && sel_clk & 0x80)) {
-				if (nv_rdvgac(bios, 0, 0x27) < 0xa3)
-					info->refclk = 200000;
-				else
-					info->refclk = 25000;
-			}
-		}
-	}
-
-	/*
-	 * By now any valid limit table ought to have set a max frequency for
-	 * vco1, so if it's zero it's either a pre limit table bios, or one
-	 * with an empty limit table (seen on nv18)
-	 */
-	if (!info->vco1.max_freq) {
-		info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67);
-		info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71);
-		if (bmp_version(bios) < 0x0506) {
-			info->vco1.max_freq = 256000;
-			info->vco1.min_freq = 128000;
-		}
-
-		info->vco1.min_inputfreq = 0;
-		info->vco1.max_inputfreq = INT_MAX;
-		info->vco1.min_n = 0x1;
-		info->vco1.max_n = 0xff;
-		info->vco1.min_m = 0x1;
-
-		if (nv_device(bios)->crystal == 13500) {
-			/* nv05 does this, nv11 doesn't, nv10 unknown */
-			if (bios->version.chip < 0x11)
-				info->vco1.min_m = 0x7;
-			info->vco1.max_m = 0xd;
-		} else {
-			if (bios->version.chip < 0x11)
-				info->vco1.min_m = 0x8;
-			info->vco1.max_m = 0xe;
-		}
-
-		if (bios->version.chip <  0x17 ||
-		    bios->version.chip == 0x1a ||
-		    bios->version.chip == 0x20)
-			info->max_p = 4;
-		else
-			info->max_p = 5;
-		info->max_p_usable = info->max_p;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c
deleted file mode 100644
index 66c56ba..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/image.h>
-#include <subdev/bios/pmu.h>
-
-static u32
-weirdo_pointer(struct nouveau_bios *bios, u32 data)
-{
-	struct nvbios_image image;
-	int idx = 0;
-	if (nvbios_image(bios, idx++, &image)) {
-		data -= image.size;
-		while (nvbios_image(bios, idx++, &image)) {
-			if (image.type == 0xe0)
-				return image.base + data;
-		}
-	}
-	return 0;
-}
-
-u32
-nvbios_pmuTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_p;
-	u32 data = 0;
-
-	if (!bit_entry(bios, 'p', &bit_p)) {
-		if (bit_p.version == 2 && bit_p.length >= 4)
-			data = nv_ro32(bios, bit_p.offset + 0x00);
-		if ((data = weirdo_pointer(bios, data))) {
-			*ver = nv_ro08(bios, data + 0x00); /* maybe? */
-			*hdr = nv_ro08(bios, data + 0x01);
-			*len = nv_ro08(bios, data + 0x02);
-			*cnt = nv_ro08(bios, data + 0x03);
-		}
-	}
-
-	return data;
-}
-
-u32
-nvbios_pmuTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	     struct nvbios_pmuT *info)
-{
-	u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	default:
-		break;
-	}
-	return data;
-}
-
-u32
-nvbios_pmuEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
-	u8  cnt, len;
-	u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
-	if (data && idx < cnt) {
-		data = data + *hdr + (idx * len);
-		*hdr = len;
-		return data;
-	}
-	return 0;
-}
-
-u32
-nvbios_pmuEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
-	     struct nvbios_pmuE *info)
-{
-	u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!data * *ver) {
-	default:
-		info->type = nv_ro08(bios, data + 0x00);
-		info->data = nv_ro32(bios, data + 0x02);
-		break;
-	}
-	return data;
-}
-
-bool
-nvbios_pmuRm(struct nouveau_bios *bios, u8 type, struct nvbios_pmuR *info)
-{
-	struct nvbios_pmuE pmuE;
-	u8  ver, hdr, idx = 0;
-	u32 data;
-	memset(info, 0x00, sizeof(*info));
-	while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
-		if ( pmuE.type == type &&
-		    (data = weirdo_pointer(bios, pmuE.data))) {
-			info->init_addr_pmu = nv_ro32(bios, data + 0x08);
-			info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
-			info->boot_addr     = data + 0x30;
-			info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
-					      nv_ro32(bios, data + 0x18);
-			info->boot_size     = nv_ro32(bios, data + 0x1c) -
-					      nv_ro32(bios, data + 0x18);
-			info->code_addr     = info->boot_addr + info->boot_size;
-			info->code_addr_pmu = info->boot_addr_pmu +
-					      info->boot_size;
-			info->code_size     = nv_ro32(bios, data + 0x20);
-			info->data_addr     = data + 0x30 +
-					      nv_ro32(bios, data + 0x24);
-			info->data_addr_pmu = nv_ro32(bios, data + 0x28);
-			info->data_size     = nv_ro32(bios, data + 0x2c);
-			return true;
-		}
-	}
-	return false;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h
deleted file mode 100644
index 187d225..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __NVKM_BIOS_PRIV_H__
-#define __NVKM_BIOS_PRIV_H__
-
-#include <subdev/bios.h>
-
-struct nvbios_source {
-	const char *name;
-	void *(*init)(struct nouveau_bios *, const char *);
-	void  (*fini)(void *);
-	u32   (*read)(void *, u32 offset, u32 length, struct nouveau_bios *);
-	bool rw;
-};
-
-int nvbios_extend(struct nouveau_bios *, u32 length);
-int nvbios_shadow(struct nouveau_bios *);
-
-extern const struct nvbios_source nvbios_rom;
-extern const struct nvbios_source nvbios_ramin;
-extern const struct nvbios_source nvbios_acpi_fast;
-extern const struct nvbios_source nvbios_acpi_slow;
-extern const struct nvbios_source nvbios_pcirom;
-extern const struct nvbios_source nvbios_platform;
-extern const struct nvbios_source nvbios_of;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
deleted file mode 100644
index 1623c8d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/M0203.h>
-
-static u8
-nvbios_ramcfg_strap(struct nouveau_subdev *subdev)
-{
-	return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2;
-}
-
-u8
-nvbios_ramcfg_count(struct nouveau_bios *bios)
-{
-	struct bit_entry bit_M;
-
-	if (!bit_entry(bios, 'M', &bit_M)) {
-		if (bit_M.version == 1 && bit_M.length >= 5)
-			return nv_ro08(bios, bit_M.offset + 2);
-		if (bit_M.version == 2 && bit_M.length >= 3)
-			return nv_ro08(bios, bit_M.offset + 0);
-	}
-
-	return 0x00;
-}
-
-u8
-nvbios_ramcfg_index(struct nouveau_subdev *subdev)
-{
-	struct nouveau_bios *bios = nouveau_bios(subdev);
-	u8 strap = nvbios_ramcfg_strap(subdev);
-	u32 xlat = 0x00000000;
-	struct bit_entry bit_M;
-	struct nvbios_M0203E M0203E;
-	u8 ver, hdr;
-
-	if (!bit_entry(bios, 'M', &bit_M)) {
-		if (bit_M.version == 1 && bit_M.length >= 5)
-			xlat = nv_ro16(bios, bit_M.offset + 3);
-		if (bit_M.version == 2 && bit_M.length >= 3) {
-			/*XXX: is M ever shorter than this?
-			 *     if not - what is xlat used for now?
-			 *     also - sigh..
-			 */
-			if (bit_M.length >= 7 &&
-			    nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
-				return M0203E.group;
-			xlat = nv_ro16(bios, bit_M.offset + 1);
-		}
-	}
-
-	if (xlat)
-		strap = nv_ro08(bios, xlat + strap);
-	return strap;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
deleted file mode 100644
index c568522..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/rammap.h>
-
-u32
-nvbios_rammapTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
-		u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_P;
-	u16 rammap = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2)
-			rammap = nv_ro16(bios, bit_P.offset + 4);
-
-		if (rammap) {
-			*ver = nv_ro08(bios, rammap + 0);
-			switch (*ver) {
-			case 0x10:
-			case 0x11:
-				*hdr = nv_ro08(bios, rammap + 1);
-				*cnt = nv_ro08(bios, rammap + 5);
-				*len = nv_ro08(bios, rammap + 2);
-				*snr = nv_ro08(bios, rammap + 4);
-				*ssz = nv_ro08(bios, rammap + 3);
-				return rammap;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u32
-nvbios_rammapEe(struct nouveau_bios *bios, int idx,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (rammap && idx < *cnt) {
-		rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return rammap;
-	}
-	return 0x0000;
-}
-
-u32
-nvbios_rammapEp(struct nouveau_bios *bios, int idx,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		struct nvbios_ramcfg *p)
-{
-	u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
-	memset(p, 0x00, sizeof(*p));
-	p->rammap_ver = *ver;
-	p->rammap_hdr = *hdr;
-	switch (!!data * *ver) {
-	case 0x10:
-		p->rammap_min      =  nv_ro16(bios, data + 0x00);
-		p->rammap_max      =  nv_ro16(bios, data + 0x02);
-		p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
-		p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
-		break;
-	case 0x11:
-		p->rammap_min      =  nv_ro16(bios, data + 0x00);
-		p->rammap_max      =  nv_ro16(bios, data + 0x02);
-		p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
-		p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
-		p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
-		temp = nv_ro32(bios, data + 0x09);
-		p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
-		p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
-		p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
-		p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
-		p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
-		p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
-		p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
-		p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
-		p->rammap_11_0d    =  nv_ro08(bios, data + 0x0d);
-		p->rammap_11_0e    =  nv_ro08(bios, data + 0x0e);
-		p->rammap_11_0f    =  nv_ro08(bios, data + 0x0f);
-		p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
-		break;
-	default:
-		data = 0;
-		break;
-	}
-	return data;
-}
-
-u32
-nvbios_rammapEm(struct nouveau_bios *bios, u16 mhz,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		struct nvbios_ramcfg *info)
-{
-	int idx = 0;
-	u32 data;
-	while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
-		if (mhz >= info->rammap_min && mhz <= info->rammap_max)
-			break;
-	}
-	return data;
-}
-
-u32
-nvbios_rammapSe(struct nouveau_bios *bios, u32 data,
-		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
-		u8 *ver, u8 *hdr)
-{
-	if (idx < ecnt) {
-		data = data + ehdr + (idx * elen);
-		*ver = ever;
-		*hdr = elen;
-		return data;
-	}
-	return 0;
-}
-
-u32
-nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
-		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
-		u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
-{
-	data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
-	p->ramcfg_ver = *ver;
-	p->ramcfg_hdr = *hdr;
-	switch (!!data * *ver) {
-	case 0x10:
-		p->ramcfg_timing   =  nv_ro08(bios, data + 0x01);
-		p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
-		p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
-		p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
-		p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
-		p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
-		p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
-		p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
-		p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
-		p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
-		p->ramcfg_10_05    = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
-		p->ramcfg_10_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
-		p->ramcfg_10_07    = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
-		p->ramcfg_10_08    = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
-		p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
-		p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
-		break;
-	case 0x11:
-		p->ramcfg_timing   =  nv_ro08(bios, data + 0x00);
-		p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
-		p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
-		p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
-		p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3;
-		p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4;
-		p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5;
-		p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6;
-		p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7;
-		p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0;
-		p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
-		p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
-		p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
-		p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
-		p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7;
-		p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
-		p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4;
-		p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6;
-		p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4;
-		p->ramcfg_11_04    = (nv_ro08(bios, data + 0x04) & 0xff) >> 0;
-		p->ramcfg_11_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
-		p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1;
-		p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2;
-		p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3;
-		p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4;
-		p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6;
-		p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7;
-		p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
-		p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1;
-		p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2;
-		p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3;
-		p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
-		p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5;
-		p->ramcfg_11_09    = (nv_ro08(bios, data + 0x09) & 0xff) >> 0;
-		break;
-	default:
-		data = 0;
-		break;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c
deleted file mode 100644
index bb9e001..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "priv.h"
-#include <core/option.h>
-#include <subdev/bios/image.h>
-
-struct shadow {
-	struct nouveau_oclass base;
-	u32 skip;
-	const struct nvbios_source *func;
-	void *data;
-	u32 size;
-	int score;
-};
-
-static bool
-shadow_fetch(struct nouveau_bios *bios, u32 upto)
-{
-	struct shadow *mthd = (void *)nv_object(bios)->oclass;
-	const u32 limit = (upto + 3) & ~3;
-	const u32 start = bios->size;
-	void *data = mthd->data;
-	if (nvbios_extend(bios, limit) > 0) {
-		u32 read = mthd->func->read(data, start, limit - start, bios);
-		bios->size = start + read;
-	}
-	return bios->size >= limit;
-}
-
-static u8
-shadow_rd08(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	if (shadow_fetch(bios, addr + 1))
-		return bios->data[addr];
-	return 0x00;
-}
-
-static u16
-shadow_rd16(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	if (shadow_fetch(bios, addr + 2))
-		return get_unaligned_le16(&bios->data[addr]);
-	return 0x0000;
-}
-
-static u32
-shadow_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nouveau_bios *bios = (void *)object;
-	if (shadow_fetch(bios, addr + 4))
-		return get_unaligned_le32(&bios->data[addr]);
-	return 0x00000000;
-}
-
-static struct nouveau_oclass
-shadow_class = {
-	.handle = NV_SUBDEV(VBIOS, 0x00),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.rd08 = shadow_rd08,
-		.rd16 = shadow_rd16,
-		.rd32 = shadow_rd32,
-	},
-};
-
-static int
-shadow_image(struct nouveau_bios *bios, int idx, struct shadow *mthd)
-{
-	struct nvbios_image image;
-	int score = 1;
-
-	if (!nvbios_image(bios, idx, &image)) {
-		nv_debug(bios, "image %d invalid\n", idx);
-		return 0;
-	}
-	nv_debug(bios, "%08x: type %02x, %d bytes\n",
-		 image.base, image.type, image.size);
-
-	if (!shadow_fetch(bios, image.size)) {
-		nv_debug(bios, "%08x: fetch failed\n", image.base);
-		return 0;
-	}
-
-	switch (image.type) {
-	case 0x00:
-		if (nvbios_checksum(&bios->data[image.base], image.size)) {
-			nv_debug(bios, "%08x: checksum failed\n", image.base);
-			if (mthd->func->rw)
-				score += 1;
-			score += 1;
-		} else {
-			score += 3;
-		}
-		break;
-	default:
-		score += 3;
-		break;
-	}
-
-	if (!image.last)
-		score += shadow_image(bios, idx + 1, mthd);
-	return score;
-}
-
-static int
-shadow_score(struct nouveau_bios *bios, struct shadow *mthd)
-{
-	struct nouveau_oclass *oclass = nv_object(bios)->oclass;
-	int score;
-	nv_object(bios)->oclass = &mthd->base;
-	score = shadow_image(bios, 0, mthd);
-	nv_object(bios)->oclass = oclass;
-	return score;
-
-}
-
-static int
-shadow_method(struct nouveau_bios *bios, struct shadow *mthd, const char *name)
-{
-	const struct nvbios_source *func = mthd->func;
-	if (func->name) {
-		nv_debug(bios, "trying %s...\n", name ? name : func->name);
-		if (func->init) {
-			mthd->data = func->init(bios, name);
-			if (IS_ERR(mthd->data)) {
-				mthd->data = NULL;
-				return 0;
-			}
-		}
-		mthd->score = shadow_score(bios, mthd);
-		if (func->fini)
-			func->fini(mthd->data);
-		nv_debug(bios, "scored %d\n", mthd->score);
-		mthd->data = bios->data;
-		mthd->size = bios->size;
-		bios->data  = NULL;
-		bios->size  = 0;
-	}
-	return mthd->score;
-}
-
-static u32
-shadow_fw_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	const struct firmware *fw = data;
-	if (offset + length <= fw->size) {
-		memcpy(bios->data + offset, fw->data + offset, length);
-		return length;
-	}
-	return 0;
-}
-
-static void *
-shadow_fw_init(struct nouveau_bios *bios, const char *name)
-{
-	struct device *dev = &nv_device(bios)->pdev->dev;
-	const struct firmware *fw;
-	int ret = request_firmware(&fw, name, dev);
-	if (ret)
-		return ERR_PTR(-ENOENT);
-	return (void *)fw;
-}
-
-static const struct nvbios_source
-shadow_fw = {
-	.name = "firmware",
-	.init = shadow_fw_init,
-	.fini = (void(*)(void *))release_firmware,
-	.read = shadow_fw_read,
-	.rw = false,
-};
-
-int
-nvbios_shadow(struct nouveau_bios *bios)
-{
-	struct shadow mthds[] = {
-		{ shadow_class, 0, &nvbios_of },
-		{ shadow_class, 0, &nvbios_ramin },
-		{ shadow_class, 0, &nvbios_rom },
-		{ shadow_class, 0, &nvbios_acpi_fast },
-		{ shadow_class, 4, &nvbios_acpi_slow },
-		{ shadow_class, 1, &nvbios_pcirom },
-		{ shadow_class, 1, &nvbios_platform },
-		{ shadow_class }
-	}, *mthd = mthds, *best = NULL;
-	const char *optarg;
-	char *source;
-	int optlen;
-
-	/* handle user-specified bios source */
-	optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
-	source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
-	if (source) {
-		/* try to match one of the built-in methods */
-		for (mthd = mthds; mthd->func; mthd++) {
-			if (mthd->func->name &&
-			    !strcasecmp(source, mthd->func->name)) {
-				best = mthd;
-				if (shadow_method(bios, mthd, NULL))
-					break;
-			}
-		}
-
-		/* otherwise, attempt to load as firmware */
-		if (!best && (best = mthd)) {
-			mthd->func = &shadow_fw;
-			shadow_method(bios, mthd, source);
-			mthd->func = NULL;
-		}
-
-		if (!best->score) {
-			nv_error(bios, "%s invalid\n", source);
-			kfree(source);
-			source = NULL;
-		}
-	}
-
-	/* scan all potential bios sources, looking for best image */
-	if (!best || !best->score) {
-		for (mthd = mthds, best = mthd; mthd->func; mthd++) {
-			if (!mthd->skip || best->score < mthd->skip) {
-				if (shadow_method(bios, mthd, NULL)) {
-					if (mthd->score > best->score)
-						best = mthd;
-				}
-			}
-		}
-	}
-
-	/* cleanup the ones we didn't use */
-	for (mthd = mthds; mthd->func; mthd++) {
-		if (mthd != best)
-			kfree(mthd->data);
-	}
-
-	if (!best->score) {
-		nv_fatal(bios, "unable to locate usable image\n");
-		return -EINVAL;
-	}
-
-	nv_info(bios, "using image from %s\n", best->func ?
-		best->func->name : source);
-	bios->data = best->data;
-	bios->size = best->size;
-	kfree(source);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c
deleted file mode 100644
index bc130c1..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 "priv.h"
-
-#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
-int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
-bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
-#else
-static inline bool
-nouveau_acpi_rom_supported(struct pci_dev *pdev)
-{
-	return false;
-}
-
-static inline int
-nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
-{
-	return -EINVAL;
-}
-#endif
-
-/* This version of the shadow function disobeys the ACPI spec and tries
- * to fetch in units of more than 4KiB at a time.  This is a LOT faster
- * on some systems, such as Lenovo W530.
- */
-static u32
-acpi_read_fast(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	u32 limit = (offset + length + 0xfff) & ~0xfff;
-	u32 start = offset & ~0x00000fff;
-	u32 fetch = limit - start;
-
-	if (nvbios_extend(bios, limit) > 0) {
-		int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
-		if (ret == fetch)
-			return fetch;
-	}
-
-	return 0;
-}
-
-/* Other systems, such as the one in fdo#55948, will report a success
- * but only return 4KiB of data.  The common bios fetching logic will
- * detect an invalid image, and fall back to this version of the read
- * function.
- */
-static u32
-acpi_read_slow(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	u32 limit = (offset + length + 0xfff) & ~0xfff;
-	u32 start = offset & ~0xfff;
-	u32 fetch = 0;
-
-	if (nvbios_extend(bios, limit) > 0) {
-		while (start + fetch < limit) {
-			int ret = nouveau_acpi_get_bios_chunk(bios->data,
-							      start + fetch,
-							      0x1000);
-			if (ret != 0x1000)
-				break;
-			fetch += 0x1000;
-		}
-	}
-
-	return fetch;
-}
-
-static void *
-acpi_init(struct nouveau_bios *bios, const char *name)
-{
-	if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
-		return ERR_PTR(-ENODEV);
-	return NULL;
-}
-
-const struct nvbios_source
-nvbios_acpi_fast = {
-	.name = "ACPI",
-	.init = acpi_init,
-	.read = acpi_read_fast,
-	.rw = false,
-};
-
-const struct nvbios_source
-nvbios_acpi_slow = {
-	.name = "ACPI",
-	.init = acpi_init,
-	.read = acpi_read_slow,
-	.rw = false,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c
deleted file mode 100644
index 3abe487..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 "priv.h"
-
-#if defined(__powerpc__)
-struct priv {
-	const void __iomem *data;
-	int size;
-};
-
-static u32
-of_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	struct priv *priv = data;
-	if (offset + length <= priv->size) {
-		memcpy_fromio(bios->data + offset, priv->data + offset, length);
-		return length;
-	}
-	return 0;
-}
-
-static void *
-of_init(struct nouveau_bios *bios, const char *name)
-{
-	struct pci_dev *pdev = nv_device(bios)->pdev;
-	struct device_node *dn;
-	struct priv *priv;
-	if (!(dn = pci_device_to_OF_node(pdev)))
-		return ERR_PTR(-ENODEV);
-	if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
-		return ERR_PTR(-ENOMEM);
-	if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
-		return priv;
-	kfree(priv);
-	return ERR_PTR(-EINVAL);
-}
-
-const struct nvbios_source
-nvbios_of = {
-	.name = "OpenFirmware",
-	.init = of_init,
-	.fini = (void(*)(void *))kfree,
-	.read = of_read,
-	.rw = false,
-};
-#else
-const struct nvbios_source
-nvbios_of = {
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c
deleted file mode 100644
index 1d0389c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 "priv.h"
-
-struct priv {
-	struct pci_dev *pdev;
-	void __iomem *rom;
-	size_t size;
-};
-
-static u32
-pcirom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	struct priv *priv = data;
-	if (offset + length <= priv->size) {
-		memcpy_fromio(bios->data + offset, priv->rom + offset, length);
-		return length;
-	}
-	return 0;
-}
-
-static void
-pcirom_fini(void *data)
-{
-	struct priv *priv = data;
-	pci_unmap_rom(priv->pdev, priv->rom);
-	pci_disable_rom(priv->pdev);
-	kfree(priv);
-}
-
-static void *
-pcirom_init(struct nouveau_bios *bios, const char *name)
-{
-	struct pci_dev *pdev = nv_device(bios)->pdev;
-	struct priv *priv = NULL;
-	int ret;
-
-	if (!(ret = pci_enable_rom(pdev))) {
-		if (ret = -ENOMEM,
-		    (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
-			if (ret = -EFAULT,
-			    (priv->rom = pci_map_rom(pdev, &priv->size))) {
-				priv->pdev = pdev;
-				return priv;
-			}
-			kfree(priv);
-		}
-		pci_disable_rom(pdev);
-	}
-
-	return ERR_PTR(ret);
-}
-
-const struct nvbios_source
-nvbios_pcirom = {
-	.name = "PCIROM",
-	.init = pcirom_init,
-	.fini = pcirom_fini,
-	.read = pcirom_read,
-	.rw = true,
-};
-
-static void *
-platform_init(struct nouveau_bios *bios, const char *name)
-{
-	struct pci_dev *pdev = nv_device(bios)->pdev;
-	struct priv *priv;
-	int ret = -ENOMEM;
-
-	if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
-		if (ret = -ENODEV,
-		    (priv->rom = pci_platform_rom(pdev, &priv->size)))
-			return priv;
-		kfree(priv);
-	}
-
-	return ERR_PTR(ret);
-}
-
-const struct nvbios_source
-nvbios_platform = {
-	.name = "PLATFORM",
-	.init = platform_init,
-	.fini = (void(*)(void *))kfree,
-	.read = pcirom_read,
-	.rw = true,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
deleted file mode 100644
index a7a890f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 "priv.h"
-
-struct priv {
-	struct nouveau_bios *bios;
-	u32 bar0;
-};
-
-static u32
-pramin_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	u32 i;
-	if (offset + length <= 0x00100000) {
-		for (i = offset; i < offset + length; i += 4)
-			*(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
-		return length;
-	}
-	return 0;
-}
-
-static void
-pramin_fini(void *data)
-{
-	struct priv *priv = data;
-	if (priv) {
-		nv_wr32(priv->bios, 0x001700, priv->bar0);
-		kfree(priv);
-	}
-}
-
-static void *
-pramin_init(struct nouveau_bios *bios, const char *name)
-{
-	struct priv *priv = NULL;
-	u64 addr = 0;
-
-	/* PRAMIN always potentially available prior to nv50 */
-	if (nv_device(bios)->card_type < NV_50)
-		return NULL;
-
-	/* we can't get the bios image pointer without PDISP */
-	if (nv_device(bios)->card_type >= GM100)
-		addr = nv_rd32(bios, 0x021c04);
-	else
-	if (nv_device(bios)->card_type >= NV_C0)
-		addr = nv_rd32(bios, 0x022500);
-	if (addr & 0x00000001) {
-		nv_debug(bios, "... display disabled\n");
-		return ERR_PTR(-ENODEV);
-	}
-
-	/* check that the window is enabled and in vram, particularly
-	 * important as we don't want to be touching vram on an
-	 * uninitialised board
-	 */
-	addr = nv_rd32(bios, 0x619f04);
-	if (!(addr & 0x00000008)) {
-		nv_debug(bios, "... not enabled\n");
-		return ERR_PTR(-ENODEV);
-	}
-	if ( (addr & 0x00000003) != 1) {
-		nv_debug(bios, "... not in vram\n");
-		return ERR_PTR(-ENODEV);
-	}
-
-	/* some alternate method inherited from xf86-video-nv... */
-	addr = (addr & 0xffffff00) << 8;
-	if (!addr) {
-		addr  = (u64)nv_rd32(bios, 0x001700) << 16;
-		addr += 0xf0000;
-	}
-
-	/* modify bar0 PRAMIN window to cover the bios image */
-	if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
-		nv_error(bios, "... out of memory\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	priv->bios = bios;
-	priv->bar0 = nv_rd32(bios, 0x001700);
-	nv_wr32(bios, 0x001700, addr >> 16);
-	return priv;
-}
-
-const struct nvbios_source
-nvbios_ramin = {
-	.name = "PRAMIN",
-	.init = pramin_init,
-	.fini = pramin_fini,
-	.read = pramin_read,
-	.rw = true,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c
deleted file mode 100644
index b7992bc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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 "priv.h"
-
-static u32
-prom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
-	u32 i;
-	if (offset + length <= 0x00100000) {
-		for (i = offset; i < offset + length; i += 4)
-			*(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
-		return length;
-	}
-	return 0;
-}
-
-static void
-prom_fini(void *data)
-{
-	struct nouveau_bios *bios = data;
-	if (nv_device(bios)->card_type < NV_50)
-		nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
-	else
-		nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
-}
-
-static void *
-prom_init(struct nouveau_bios *bios, const char *name)
-{
-	if (nv_device(bios)->card_type < NV_50) {
-		if (nv_device(bios)->card_type == NV_40 &&
-		    nv_device(bios)->chipset >= 0x4c)
-			return ERR_PTR(-ENODEV);
-		nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
-	} else {
-		nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
-	}
-	return bios;
-}
-
-const struct nvbios_source
-nvbios_rom = {
-	.name = "PROM",
-	.init = prom_init,
-	.fini = prom_fini,
-	.read = prom_read,
-	.rw = false,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
deleted file mode 100644
index d158540..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/therm.h>
-
-static u16
-therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
-{
-	struct bit_entry bit_P;
-	u16 therm = 0;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 1)
-			therm = nv_ro16(bios, bit_P.offset + 12);
-		else if (bit_P.version == 2)
-			therm = nv_ro16(bios, bit_P.offset + 16);
-		else
-			nv_error(bios,
-				"unknown offset for thermal in BIT P %d\n",
-				bit_P.version);
-	}
-
-	/* exit now if we haven't found the thermal table */
-	if (!therm)
-		return 0x0000;
-
-	*ver = nv_ro08(bios, therm + 0);
-	*hdr = nv_ro08(bios, therm + 1);
-	*len = nv_ro08(bios, therm + 2);
-	*cnt = nv_ro08(bios, therm + 3);
-
-	return therm + nv_ro08(bios, therm + 1);
-}
-
-static u16
-nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
-	u8 hdr, cnt;
-	u16 therm = therm_table(bios, ver, &hdr, len, &cnt);
-	if (therm && idx < cnt)
-		return therm + idx * *len;
-	return 0x0000;
-}
-
-int
-nvbios_therm_sensor_parse(struct nouveau_bios *bios,
-			  enum nvbios_therm_domain domain,
-			  struct nvbios_therm_sensor *sensor)
-{
-	s8 thrs_section, sensor_section, offset;
-	u8 ver, len, i;
-	u16 entry;
-
-	/* we only support the core domain for now */
-	if (domain != NVBIOS_THERM_DOMAIN_CORE)
-		return -EINVAL;
-
-	/* Read the entries from the table */
-	thrs_section = 0;
-	sensor_section = -1;
-	i = 0;
-	while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
-		s16 value = nv_ro16(bios, entry + 1);
-
-		switch (nv_ro08(bios, entry + 0)) {
-		case 0x0:
-			thrs_section = value;
-			if (value > 0)
-				return 0; /* we do not try to support ambient */
-			break;
-		case 0x01:
-			sensor_section++;
-			if (sensor_section == 0) {
-				offset = ((s8) nv_ro08(bios, entry + 2)) / 2;
-				sensor->offset_constant = offset;
-			}
-			break;
-
-		case 0x04:
-			if (thrs_section == 0) {
-				sensor->thrs_critical.temp = (value & 0xff0) >> 4;
-				sensor->thrs_critical.hysteresis = value & 0xf;
-			}
-			break;
-
-		case 0x07:
-			if (thrs_section == 0) {
-				sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
-				sensor->thrs_down_clock.hysteresis = value & 0xf;
-			}
-			break;
-
-		case 0x08:
-			if (thrs_section == 0) {
-				sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
-				sensor->thrs_fan_boost.hysteresis = value & 0xf;
-			}
-			break;
-
-		case 0x10:
-			if (sensor_section == 0)
-				sensor->offset_num = value;
-			break;
-
-		case 0x11:
-			if (sensor_section == 0)
-				sensor->offset_den = value;
-			break;
-
-		case 0x12:
-			if (sensor_section == 0)
-				sensor->slope_mult = value;
-			break;
-
-		case 0x13:
-			if (sensor_section == 0)
-				sensor->slope_div = value;
-			break;
-		case 0x32:
-			if (thrs_section == 0) {
-				sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
-				sensor->thrs_shutdown.hysteresis = value & 0xf;
-			}
-			break;
-		}
-	}
-
-	return 0;
-}
-
-int
-nvbios_therm_fan_parse(struct nouveau_bios *bios,
-			  struct nvbios_therm_fan *fan)
-{
-	struct nouveau_therm_trip_point *cur_trip = NULL;
-	u8 ver, len, i;
-	u16 entry;
-
-	uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
-				75, 0, 85, 0, 100, 0, 100, 0 };
-
-	i = 0;
-	fan->nr_fan_trip = 0;
-	fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
-	while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
-		s16 value = nv_ro16(bios, entry + 1);
-
-		switch (nv_ro08(bios, entry + 0)) {
-		case 0x22:
-			fan->min_duty = value & 0xff;
-			fan->max_duty = (value & 0xff00) >> 8;
-			break;
-		case 0x24:
-			fan->nr_fan_trip++;
-			if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
-				fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
-			cur_trip = &fan->trip[fan->nr_fan_trip - 1];
-			cur_trip->hysteresis = value & 0xf;
-			cur_trip->temp = (value & 0xff0) >> 4;
-			cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
-			break;
-		case 0x25:
-			cur_trip = &fan->trip[fan->nr_fan_trip - 1];
-			cur_trip->fan_duty = value;
-			break;
-		case 0x26:
-			if (!fan->pwm_freq)
-				fan->pwm_freq = value;
-			break;
-		case 0x3b:
-			fan->bump_period = value;
-			break;
-		case 0x3c:
-			fan->slow_down_period = value;
-			break;
-		case 0x46:
-			if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
-				fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
-			fan->linear_min_temp = nv_ro08(bios, entry + 1);
-			fan->linear_max_temp = nv_ro08(bios, entry + 2);
-			break;
-		}
-	}
-
-	/* starting from fermi, fan management is always linear */
-	if (nv_device(bios)->card_type >= NV_C0 &&
-		fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
-		fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
deleted file mode 100644
index 8521eca..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/timing.h>
-
-u16
-nvbios_timingTe(struct nouveau_bios *bios,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
-	struct bit_entry bit_P;
-	u16 timing = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 1)
-			timing = nv_ro16(bios, bit_P.offset + 4);
-		else
-		if (bit_P.version == 2)
-			timing = nv_ro16(bios, bit_P.offset + 8);
-
-		if (timing) {
-			*ver = nv_ro08(bios, timing + 0);
-			switch (*ver) {
-			case 0x10:
-				*hdr = nv_ro08(bios, timing + 1);
-				*cnt = nv_ro08(bios, timing + 2);
-				*len = nv_ro08(bios, timing + 3);
-				*snr = 0;
-				*ssz = 0;
-				return timing;
-			case 0x20:
-				*hdr = nv_ro08(bios, timing + 1);
-				*cnt = nv_ro08(bios, timing + 5);
-				*len = nv_ro08(bios, timing + 2);
-				*snr = nv_ro08(bios, timing + 4);
-				*ssz = nv_ro08(bios, timing + 3);
-				return timing;
-			default:
-				break;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_timingEe(struct nouveau_bios *bios, int idx,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u8  snr, ssz;
-	u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz);
-	if (timing && idx < *cnt) {
-		timing += *hdr + idx * (*len + (snr * ssz));
-		*hdr = *len;
-		*cnt = snr;
-		*len = ssz;
-		return timing;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_timingEp(struct nouveau_bios *bios, int idx,
-		u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		struct nvbios_ramcfg *p)
-{
-	u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
-	p->timing_ver = *ver;
-	p->timing_hdr = *hdr;
-	switch (!!data * *ver) {
-	case 0x10:
-		p->timing_10_WR    = nv_ro08(bios, data + 0x00);
-		p->timing_10_WTR   = nv_ro08(bios, data + 0x01);
-		p->timing_10_CL    = nv_ro08(bios, data + 0x02);
-		p->timing_10_RC    = nv_ro08(bios, data + 0x03);
-		p->timing_10_RFC   = nv_ro08(bios, data + 0x05);
-		p->timing_10_RAS   = nv_ro08(bios, data + 0x07);
-		p->timing_10_RP    = nv_ro08(bios, data + 0x09);
-		p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
-		p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
-		p->timing_10_RRD   = nv_ro08(bios, data + 0x0c);
-		p->timing_10_13    = nv_ro08(bios, data + 0x0d);
-		p->timing_10_ODT   = nv_ro08(bios, data + 0x0e) & 0x07;
-
-		p->timing_10_24  = 0xff;
-		p->timing_10_21  = 0;
-		p->timing_10_20  = 0;
-		p->timing_10_CWL = 0;
-		p->timing_10_18  = 0;
-		p->timing_10_16  = 0;
-
-		switch (min_t(u8, *hdr, 25)) {
-		case 25:
-			p->timing_10_24  = nv_ro08(bios, data + 0x18);
-		case 24:
-		case 23:
-		case 22:
-			p->timing_10_21  = nv_ro08(bios, data + 0x15);
-		case 21:
-			p->timing_10_20  = nv_ro08(bios, data + 0x14);
-		case 20:
-			p->timing_10_CWL = nv_ro08(bios, data + 0x13);
-		case 19:
-			p->timing_10_18  = nv_ro08(bios, data + 0x12);
-		case 18:
-		case 17:
-			p->timing_10_16  = nv_ro08(bios, data + 0x10);
-		}
-
-		break;
-	case 0x20:
-		p->timing[0] = nv_ro32(bios, data + 0x00);
-		p->timing[1] = nv_ro32(bios, data + 0x04);
-		p->timing[2] = nv_ro32(bios, data + 0x08);
-		p->timing[3] = nv_ro32(bios, data + 0x0c);
-		p->timing[4] = nv_ro32(bios, data + 0x10);
-		p->timing[5] = nv_ro32(bios, data + 0x14);
-		p->timing[6] = nv_ro32(bios, data + 0x18);
-		p->timing[7] = nv_ro32(bios, data + 0x1c);
-		p->timing[8] = nv_ro32(bios, data + 0x20);
-		p->timing[9] = nv_ro32(bios, data + 0x24);
-		p->timing[10] = nv_ro32(bios, data + 0x28);
-		p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0;
-		p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4;
-		p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6;
-		p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0;
-		temp = nv_ro16(bios, data + 0x2c);
-		p->timing_20_2c_003f = (temp & 0x003f) >> 0;
-		p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6;
-		p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0;
-		p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3;
-		temp = nv_ro16(bios, data + 0x31);
-		p->timing_20_31_0007 = (temp & 0x0007) >> 0;
-		p->timing_20_31_0078 = (temp & 0x0078) >> 3;
-		p->timing_20_31_0780 = (temp & 0x0780) >> 7;
-		p->timing_20_31_0800 = (temp & 0x0800) >> 11;
-		p->timing_20_31_7000 = (temp & 0x7000) >> 12;
-		p->timing_20_31_8000 = (temp & 0x8000) >> 15;
-		break;
-	default:
-		data = 0;
-		break;
-	}
-	return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c
deleted file mode 100644
index f343a1b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/vmap.h>
-
-u16
-nvbios_vmap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_P;
-	u16 vmap = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2) {
-			vmap = nv_ro16(bios, bit_P.offset + 0x20);
-			if (vmap) {
-				*ver = nv_ro08(bios, vmap + 0);
-				switch (*ver) {
-				case 0x10:
-				case 0x20:
-					*hdr = nv_ro08(bios, vmap + 1);
-					*cnt = nv_ro08(bios, vmap + 3);
-					*len = nv_ro08(bios, vmap + 2);
-					return vmap;
-				default:
-					break;
-				}
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_vmap_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_vmap *info)
-{
-	u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!vmap * *ver) {
-	case 0x10:
-	case 0x20:
-		break;
-	}
-	return vmap;
-}
-
-u16
-nvbios_vmap_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt;
-	u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len);
-	if (vmap && idx < cnt) {
-		vmap = vmap + hdr + (idx * *len);
-		return vmap;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_vmap_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
-			struct nvbios_vmap_entry *info)
-{
-	u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!vmap * *ver) {
-	case 0x10:
-		info->link   = 0xff;
-		info->min    = nv_ro32(bios, vmap + 0x00);
-		info->max    = nv_ro32(bios, vmap + 0x04);
-		info->arg[0] = nv_ro32(bios, vmap + 0x08);
-		info->arg[1] = nv_ro32(bios, vmap + 0x0c);
-		info->arg[2] = nv_ro32(bios, vmap + 0x10);
-		break;
-	case 0x20:
-		info->unk0   = nv_ro08(bios, vmap + 0x00);
-		info->link   = nv_ro08(bios, vmap + 0x01);
-		info->min    = nv_ro32(bios, vmap + 0x02);
-		info->max    = nv_ro32(bios, vmap + 0x06);
-		info->arg[0] = nv_ro32(bios, vmap + 0x0a);
-		info->arg[1] = nv_ro32(bios, vmap + 0x0e);
-		info->arg[2] = nv_ro32(bios, vmap + 0x12);
-		info->arg[3] = nv_ro32(bios, vmap + 0x16);
-		info->arg[4] = nv_ro32(bios, vmap + 0x1a);
-		info->arg[5] = nv_ro32(bios, vmap + 0x1e);
-		break;
-	}
-	return vmap;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c
deleted file mode 100644
index bb590de..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/volt.h>
-
-u16
-nvbios_volt_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	struct bit_entry bit_P;
-	u16 volt = 0x0000;
-
-	if (!bit_entry(bios, 'P', &bit_P)) {
-		if (bit_P.version == 2)
-			volt = nv_ro16(bios, bit_P.offset + 0x0c);
-		else
-		if (bit_P.version == 1)
-			volt = nv_ro16(bios, bit_P.offset + 0x10);
-
-		if (volt) {
-			*ver = nv_ro08(bios, volt + 0);
-			switch (*ver) {
-			case 0x12:
-				*hdr = 5;
-				*cnt = nv_ro08(bios, volt + 2);
-				*len = nv_ro08(bios, volt + 1);
-				return volt;
-			case 0x20:
-				*hdr = nv_ro08(bios, volt + 1);
-				*cnt = nv_ro08(bios, volt + 2);
-				*len = nv_ro08(bios, volt + 3);
-				return volt;
-			case 0x30:
-			case 0x40:
-			case 0x50:
-				*hdr = nv_ro08(bios, volt + 1);
-				*cnt = nv_ro08(bios, volt + 3);
-				*len = nv_ro08(bios, volt + 2);
-				return volt;
-			}
-		}
-	}
-
-	return 0x0000;
-}
-
-u16
-nvbios_volt_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-		  struct nvbios_volt *info)
-{
-	u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!volt * *ver) {
-	case 0x12:
-		info->vidmask = nv_ro08(bios, volt + 0x04);
-		break;
-	case 0x20:
-		info->vidmask = nv_ro08(bios, volt + 0x05);
-		break;
-	case 0x30:
-		info->vidmask = nv_ro08(bios, volt + 0x04);
-		break;
-	case 0x40:
-		info->base    = nv_ro32(bios, volt + 0x04);
-		info->step    = nv_ro16(bios, volt + 0x08);
-		info->vidmask = nv_ro08(bios, volt + 0x0b);
-		/*XXX*/
-		info->min     = 0;
-		info->max     = info->base;
-		break;
-	case 0x50:
-		info->vidmask = nv_ro08(bios, volt + 0x06);
-		info->min     = nv_ro32(bios, volt + 0x0a);
-		info->max     = nv_ro32(bios, volt + 0x0e);
-		info->base    = nv_ro32(bios, volt + 0x12) & 0x00ffffff;
-		info->step    = nv_ro16(bios, volt + 0x16);
-		break;
-	}
-	return volt;
-}
-
-u16
-nvbios_volt_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
-	u8  hdr, cnt;
-	u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len);
-	if (volt && idx < cnt) {
-		volt = volt + hdr + (idx * *len);
-		return volt;
-	}
-	return 0x0000;
-}
-
-u16
-nvbios_volt_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
-			struct nvbios_volt_entry *info)
-{
-	u16 volt = nvbios_volt_entry(bios, idx, ver, len);
-	memset(info, 0x00, sizeof(*info));
-	switch (!!volt * *ver) {
-	case 0x12:
-	case 0x20:
-		info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
-		info->vid     = nv_ro08(bios, volt + 0x01);
-		break;
-	case 0x30:
-		info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
-		info->vid     = nv_ro08(bios, volt + 0x01) >> 2;
-		break;
-	case 0x40:
-	case 0x50:
-		break;
-	}
-	return volt;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
deleted file mode 100644
index e9b8e5d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/xpio.h>
-
-static u16
-dcb_xpiod_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len);
-	if (data && *ver >= 0x40 && *hdr >= 0x06) {
-		u16 xpio = nv_ro16(bios, data + 0x04);
-		if (xpio) {
-			*ver = nv_ro08(bios, data + 0x00);
-			*hdr = nv_ro08(bios, data + 0x01);
-			*cnt = nv_ro08(bios, data + 0x02);
-			*len = nv_ro08(bios, data + 0x03);
-			return xpio;
-		}
-	}
-	return 0x0000;
-}
-
-u16
-dcb_xpio_table(struct nouveau_bios *bios, u8 idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
-	u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len);
-	if (data && idx < *cnt) {
-		u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len));
-		if (xpio) {
-			*ver = nv_ro08(bios, data + 0x00);
-			*hdr = nv_ro08(bios, data + 0x01);
-			*cnt = nv_ro08(bios, data + 0x02);
-			*len = nv_ro08(bios, data + 0x03);
-			return xpio;
-		}
-	}
-	return 0x0000;
-}
-
-u16
-dcb_xpio_parse(struct nouveau_bios *bios, u8 idx,
-	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
-	       struct nvbios_xpio *info)
-{
-	u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len);
-	if (data && *len >= 6) {
-		info->type = nv_ro08(bios, data + 0x04);
-		info->addr = nv_ro08(bios, data + 0x05);
-		info->flags = nv_ro08(bios, data + 0x06);
-	}
-	return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c
deleted file mode 100644
index f757470..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/timer.h>
-#include <subdev/bus.h>
-
-struct nouveau_hwsq {
-	struct nouveau_bus *pbus;
-	u32 addr;
-	u32 data;
-	struct {
-		u8 data[512];
-		u8 size;
-	} c;
-};
-
-static void
-hwsq_cmd(struct nouveau_hwsq *hwsq, int size, u8 data[])
-{
-	memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
-	hwsq->c.size += size;
-}
-
-int
-nouveau_hwsq_init(struct nouveau_bus *pbus, struct nouveau_hwsq **phwsq)
-{
-	struct nouveau_hwsq *hwsq;
-
-	hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
-	if (hwsq) {
-		hwsq->pbus = pbus;
-		hwsq->addr = ~0;
-		hwsq->data = ~0;
-		memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
-		hwsq->c.size = 0;
-	}
-
-	return hwsq ? 0 : -ENOMEM;
-}
-
-int
-nouveau_hwsq_fini(struct nouveau_hwsq **phwsq, bool exec)
-{
-	struct nouveau_hwsq *hwsq = *phwsq;
-	int ret = 0, i;
-	if (hwsq) {
-		struct nouveau_bus *pbus = hwsq->pbus;
-		hwsq->c.size = (hwsq->c.size + 4) / 4;
-		if (hwsq->c.size <= pbus->hwsq_size) {
-			if (exec)
-				ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data,
-						      hwsq->c.size);
-			if (ret)
-				nv_error(pbus, "hwsq exec failed: %d\n", ret);
-		} else {
-			nv_error(pbus, "hwsq ucode too large\n");
-			ret = -ENOSPC;
-		}
-
-		for (i = 0; ret && i < hwsq->c.size; i++)
-			nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]);
-
-		*phwsq = NULL;
-		kfree(hwsq);
-	}
-	return ret;
-}
-
-void
-nouveau_hwsq_wr32(struct nouveau_hwsq *hwsq, u32 addr, u32 data)
-{
-	nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data);
-
-	if (hwsq->data != data) {
-		if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
-			hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
-						  data >> 16, data >> 24 });
-		} else {
-			hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
-		}
-	}
-
-	if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
-		hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
-					  addr >> 16, addr >> 24 });
-	} else {
-		hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
-	}
-
-	hwsq->addr = addr;
-	hwsq->data = data;
-}
-
-void
-nouveau_hwsq_setf(struct nouveau_hwsq *hwsq, u8 flag, int data)
-{
-	nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data);
-	flag += 0x80;
-	if (data >= 0)
-		flag += 0x20;
-	if (data >= 1)
-		flag += 0x20;
-	hwsq_cmd(hwsq, 1, (u8[]){ flag });
-}
-
-void
-nouveau_hwsq_wait(struct nouveau_hwsq *hwsq, u8 flag, u8 data)
-{
-	nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data);
-	hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
-}
-
-void
-nouveau_hwsq_nsec(struct nouveau_hwsq *hwsq, u32 nsec)
-{
-	u8 shift = 0, usec = nsec / 1000;
-	while (usec & ~3) {
-		usec >>= 2;
-		shift++;
-	}
-
-	nv_debug(hwsq->pbus, "    DELAY = %d ns\n", nsec);
-	hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h
deleted file mode 100644
index 12176f9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef __NVKM_BUS_HWSQ_H__
-#define __NVKM_BUS_HWSQ_H__
-
-#include <subdev/bus.h>
-
-struct hwsq {
-	struct nouveau_subdev *subdev;
-	struct nouveau_hwsq *hwsq;
-	int sequence;
-};
-
-struct hwsq_reg {
-	int sequence;
-	bool force;
-	u32 addr[2];
-	u32 data;
-};
-
-static inline struct hwsq_reg
-hwsq_reg2(u32 addr1, u32 addr2)
-{
-	return (struct hwsq_reg) {
-		.sequence = 0,
-		.force = 0,
-		.addr = { addr1, addr2 },
-		.data = 0xdeadbeef,
-	};
-}
-
-static inline struct hwsq_reg
-hwsq_reg(u32 addr)
-{
-	return hwsq_reg2(addr, addr);
-}
-
-static inline int
-hwsq_init(struct hwsq *ram, struct nouveau_subdev *subdev)
-{
-	struct nouveau_bus *pbus = nouveau_bus(subdev);
-	int ret;
-
-	ret = nouveau_hwsq_init(pbus, &ram->hwsq);
-	if (ret)
-		return ret;
-
-	ram->sequence++;
-	ram->subdev = subdev;
-	return 0;
-}
-
-static inline int
-hwsq_exec(struct hwsq *ram, bool exec)
-{
-	int ret = 0;
-	if (ram->subdev) {
-		ret = nouveau_hwsq_fini(&ram->hwsq, exec);
-		ram->subdev = NULL;
-	}
-	return ret;
-}
-
-static inline u32
-hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
-{
-	if (reg->sequence != ram->sequence)
-		reg->data = nv_rd32(ram->subdev, reg->addr[0]);
-	return reg->data;
-}
-
-static inline void
-hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
-{
-	reg->sequence = ram->sequence;
-	reg->data = data;
-	if (reg->addr[0] != reg->addr[1])
-		nouveau_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
-	nouveau_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
-}
-
-static inline void
-hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg)
-{
-	reg->force = true;
-}
-
-static inline u32
-hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data)
-{
-	u32 temp = hwsq_rd32(ram, reg);
-	if (temp != ((temp & ~mask) | data) || reg->force)
-		hwsq_wr32(ram, reg, (temp & ~mask) | data);
-	return temp;
-}
-
-static inline void
-hwsq_setf(struct hwsq *ram, u8 flag, int data)
-{
-	nouveau_hwsq_setf(ram->hwsq, flag, data);
-}
-
-static inline void
-hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
-{
-	nouveau_hwsq_wait(ram->hwsq, flag, data);
-}
-
-static inline void
-hwsq_nsec(struct hwsq *ram, u32 nsec)
-{
-	nouveau_hwsq_nsec(ram->hwsq, nsec);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
deleted file mode 100644
index 23921b5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- *          Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nv04_bus_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_bus *pbus = nouveau_bus(subdev);
-	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
-	if (stat & 0x00000001) {
-		nv_error(pbus, "BUS ERROR\n");
-		stat &= ~0x00000001;
-		nv_wr32(pbus, 0x001100, 0x00000001);
-	}
-
-	if (stat & 0x00000110) {
-		subdev = nouveau_subdev(subdev, NVDEV_SUBDEV_GPIO);
-		if (subdev && subdev->intr)
-			subdev->intr(subdev);
-		stat &= ~0x00000110;
-		nv_wr32(pbus, 0x001100, 0x00000110);
-	}
-
-	if (stat) {
-		nv_error(pbus, "unknown intr 0x%08x\n", stat);
-		nv_mask(pbus, 0x001140, stat, 0x00000000);
-	}
-}
-
-static int
-nv04_bus_init(struct nouveau_object *object)
-{
-	struct nv04_bus_priv *priv = (void *)object;
-
-	nv_wr32(priv, 0x001100, 0xffffffff);
-	nv_wr32(priv, 0x001140, 0x00000111);
-
-	return nouveau_bus_init(&priv->base);
-}
-
-int
-nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv04_bus_impl *impl = (void *)oclass;
-	struct nv04_bus_priv *priv;
-	int ret;
-
-	ret = nouveau_bus_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->intr = impl->intr;
-	priv->base.hwsq_exec = impl->hwsq_exec;
-	priv->base.hwsq_size = impl->hwsq_size;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_bus_oclass = &(struct nv04_bus_impl) {
-	.base.handle = NV_SUBDEV(BUS, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_bus_ctor,
-		.dtor = _nouveau_bus_dtor,
-		.init = nv04_bus_init,
-		.fini = _nouveau_bus_fini,
-	},
-	.intr = nv04_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h
deleted file mode 100644
index 4d76024..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_BUS_NV04_H__
-#define __NVKM_BUS_NV04_H__
-
-#include <subdev/bus.h>
-
-struct nv04_bus_priv {
-	struct nouveau_bus base;
-};
-
-int  nv04_bus_ctor(struct nouveau_object *, struct nouveau_object *,
-		   struct nouveau_oclass *, void *, u32,
-		   struct nouveau_object **);
-int  nv50_bus_init(struct nouveau_object *);
-void nv50_bus_intr(struct nouveau_subdev *);
-
-struct nv04_bus_impl {
-	struct nouveau_oclass base;
-	void (*intr)(struct nouveau_subdev *);
-	int  (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
-	u32  hwsq_size;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
deleted file mode 100644
index 94da46f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- *          Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nv31_bus_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_bus *pbus = nouveau_bus(subdev);
-	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-	u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144);
-
-	if (gpio) {
-		subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_GPIO);
-		if (subdev && subdev->intr)
-			subdev->intr(subdev);
-	}
-
-	if (stat & 0x00000008) {  /* NV41- */
-		u32 addr = nv_rd32(pbus, 0x009084);
-		u32 data = nv_rd32(pbus, 0x009088);
-
-		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
-			 (addr & 0x00000002) ? "write" : "read", data,
-			 (addr & 0x00fffffc));
-
-		stat &= ~0x00000008;
-		nv_wr32(pbus, 0x001100, 0x00000008);
-	}
-
-	if (stat & 0x00070000) {
-		subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
-		if (subdev && subdev->intr)
-			subdev->intr(subdev);
-		stat &= ~0x00070000;
-		nv_wr32(pbus, 0x001100, 0x00070000);
-	}
-
-	if (stat) {
-		nv_error(pbus, "unknown intr 0x%08x\n", stat);
-		nv_mask(pbus, 0x001140, stat, 0x00000000);
-	}
-}
-
-static int
-nv31_bus_init(struct nouveau_object *object)
-{
-	struct nv04_bus_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_bus_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x001100, 0xffffffff);
-	nv_wr32(priv, 0x001140, 0x00070008);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv31_bus_oclass = &(struct nv04_bus_impl) {
-	.base.handle = NV_SUBDEV(BUS, 0x31),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_bus_ctor,
-		.dtor = _nouveau_bus_dtor,
-		.init = nv31_bus_init,
-		.fini = _nouveau_bus_fini,
-	},
-	.intr = nv31_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
deleted file mode 100644
index 11918f7..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- *          Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "nv04.h"
-
-static int
-nv50_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
-{
-	struct nv50_bus_priv *priv = (void *)pbus;
-	int i;
-
-	nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
-	nv_wr32(pbus, 0x001304, 0x00000000);
-	for (i = 0; i < size; i++)
-		nv_wr32(priv, 0x001400 + (i * 4), data[i]);
-	nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
-	nv_wr32(pbus, 0x00130c, 0x00000003);
-
-	return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
-}
-
-void
-nv50_bus_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_bus *pbus = nouveau_bus(subdev);
-	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
-	if (stat & 0x00000008) {
-		u32 addr = nv_rd32(pbus, 0x009084);
-		u32 data = nv_rd32(pbus, 0x009088);
-
-		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
-			 (addr & 0x00000002) ? "write" : "read", data,
-			 (addr & 0x00fffffc));
-
-		stat &= ~0x00000008;
-		nv_wr32(pbus, 0x001100, 0x00000008);
-	}
-
-	if (stat & 0x00010000) {
-		subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
-		if (subdev && subdev->intr)
-			subdev->intr(subdev);
-		stat &= ~0x00010000;
-		nv_wr32(pbus, 0x001100, 0x00010000);
-	}
-
-	if (stat) {
-		nv_error(pbus, "unknown intr 0x%08x\n", stat);
-		nv_mask(pbus, 0x001140, stat, 0);
-	}
-}
-
-int
-nv50_bus_init(struct nouveau_object *object)
-{
-	struct nv04_bus_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_bus_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x001100, 0xffffffff);
-	nv_wr32(priv, 0x001140, 0x00010008);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_bus_oclass = &(struct nv04_bus_impl) {
-	.base.handle = NV_SUBDEV(BUS, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_bus_ctor,
-		.dtor = _nouveau_bus_dtor,
-		.init = nv50_bus_init,
-		.fini = _nouveau_bus_fini,
-	},
-	.intr = nv50_bus_intr,
-	.hwsq_exec = nv50_bus_hwsq_exec,
-	.hwsq_size = 64,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c
deleted file mode 100644
index d365905..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- *          Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "nv04.h"
-
-static int
-nv94_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
-{
-	struct nv50_bus_priv *priv = (void *)pbus;
-	int i;
-
-	nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
-	nv_wr32(pbus, 0x001304, 0x00000000);
-	nv_wr32(pbus, 0x001318, 0x00000000);
-	for (i = 0; i < size; i++)
-		nv_wr32(priv, 0x080000 + (i * 4), data[i]);
-	nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
-	nv_wr32(pbus, 0x00130c, 0x00000001);
-
-	return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
-}
-
-struct nouveau_oclass *
-nv94_bus_oclass = &(struct nv04_bus_impl) {
-	.base.handle = NV_SUBDEV(BUS, 0x94),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_bus_ctor,
-		.dtor = _nouveau_bus_dtor,
-		.init = nv50_bus_init,
-		.fini = _nouveau_bus_fini,
-	},
-	.intr = nv50_bus_intr,
-	.hwsq_exec = nv94_bus_hwsq_exec,
-	.hwsq_size = 128,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
deleted file mode 100644
index 73839d7..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * 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.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- *          Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nvc0_bus_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_bus *pbus = nouveau_bus(subdev);
-	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
-	if (stat & 0x0000000e) {
-		u32 addr = nv_rd32(pbus, 0x009084);
-		u32 data = nv_rd32(pbus, 0x009088);
-
-		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n",
-			 (addr & 0x00000002) ? "write" : "read", data,
-			 (addr & 0x00fffffc),
-			 (stat & 0x00000002) ? "!ENGINE " : "",
-			 (stat & 0x00000004) ? "IBUS " : "",
-			 (stat & 0x00000008) ? "TIMEOUT " : "");
-
-		nv_wr32(pbus, 0x009084, 0x00000000);
-		nv_wr32(pbus, 0x001100, (stat & 0x0000000e));
-		stat &= ~0x0000000e;
-	}
-
-	if (stat) {
-		nv_error(pbus, "unknown intr 0x%08x\n", stat);
-		nv_mask(pbus, 0x001140, stat, 0x00000000);
-	}
-}
-
-static int
-nvc0_bus_init(struct nouveau_object *object)
-{
-	struct nv04_bus_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_bus_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x001100, 0xffffffff);
-	nv_wr32(priv, 0x001140, 0x0000000e);
-	return 0;
-}
-
-struct nouveau_oclass *
-nvc0_bus_oclass = &(struct nv04_bus_impl) {
-	.base.handle = NV_SUBDEV(BUS, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_bus_ctor,
-		.dtor = _nouveau_bus_dtor,
-		.init = nvc0_bus_init,
-		.fini = _nouveau_bus_fini,
-	},
-	.intr = nvc0_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
deleted file mode 100644
index e51b72d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/volt.h>
-#include <subdev/fb.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/boost.h>
-#include <subdev/bios/cstep.h>
-#include <subdev/bios/perf.h>
-
-/******************************************************************************
- * misc
- *****************************************************************************/
-static u32
-nouveau_clock_adjust(struct nouveau_clock *clk, bool adjust,
-		     u8 pstate, u8 domain, u32 input)
-{
-	struct nouveau_bios *bios = nouveau_bios(clk);
-	struct nvbios_boostE boostE;
-	u8  ver, hdr, cnt, len;
-	u16 data;
-
-	data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE);
-	if (data) {
-		struct nvbios_boostS boostS;
-		u8  idx = 0, sver, shdr;
-		u16 subd;
-
-		input = max(boostE.min, input);
-		input = min(boostE.max, input);
-		do {
-			sver = ver;
-			shdr = hdr;
-			subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr,
-					      cnt, len, &boostS);
-			if (subd && boostS.domain == domain) {
-				if (adjust)
-					input = input * boostS.percent / 100;
-				input = max(boostS.min, input);
-				input = min(boostS.max, input);
-				break;
-			}
-		} while (subd);
-	}
-
-	return input;
-}
-
-/******************************************************************************
- * C-States
- *****************************************************************************/
-static int
-nouveau_cstate_prog(struct nouveau_clock *clk,
-		    struct nouveau_pstate *pstate, int cstatei)
-{
-	struct nouveau_therm *ptherm = nouveau_therm(clk);
-	struct nouveau_volt *volt = nouveau_volt(clk);
-	struct nouveau_cstate *cstate;
-	int ret;
-
-	if (!list_empty(&pstate->list)) {
-		cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
-	} else {
-		cstate = &pstate->base;
-	}
-
-	if (ptherm) {
-		ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1);
-		if (ret && ret != -ENODEV) {
-			nv_error(clk, "failed to raise fan speed: %d\n", ret);
-			return ret;
-		}
-	}
-
-	if (volt) {
-		ret = volt->set_id(volt, cstate->voltage, +1);
-		if (ret && ret != -ENODEV) {
-			nv_error(clk, "failed to raise voltage: %d\n", ret);
-			return ret;
-		}
-	}
-
-	ret = clk->calc(clk, cstate);
-	if (ret == 0) {
-		ret = clk->prog(clk);
-		clk->tidy(clk);
-	}
-
-	if (volt) {
-		ret = volt->set_id(volt, cstate->voltage, -1);
-		if (ret && ret != -ENODEV)
-			nv_error(clk, "failed to lower voltage: %d\n", ret);
-	}
-
-	if (ptherm) {
-		ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1);
-		if (ret && ret != -ENODEV)
-			nv_error(clk, "failed to lower fan speed: %d\n", ret);
-	}
-
-	return 0;
-}
-
-static void
-nouveau_cstate_del(struct nouveau_cstate *cstate)
-{
-	list_del(&cstate->head);
-	kfree(cstate);
-}
-
-static int
-nouveau_cstate_new(struct nouveau_clock *clk, int idx,
-		   struct nouveau_pstate *pstate)
-{
-	struct nouveau_bios *bios = nouveau_bios(clk);
-	struct nouveau_clocks *domain = clk->domains;
-	struct nouveau_cstate *cstate = NULL;
-	struct nvbios_cstepX cstepX;
-	u8  ver, hdr;
-	u16 data;
-
-	data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX);
-	if (!data)
-		return -ENOENT;
-
-	cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
-	if (!cstate)
-		return -ENOMEM;
-
-	*cstate = pstate->base;
-	cstate->voltage = cstepX.voltage;
-
-	while (domain && domain->name != nv_clk_src_max) {
-		if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
-			u32 freq = nouveau_clock_adjust(clk, true,
-							pstate->pstate,
-							domain->bios,
-							cstepX.freq);
-			cstate->domain[domain->name] = freq;
-		}
-		domain++;
-	}
-
-	list_add(&cstate->head, &pstate->list);
-	return 0;
-}
-
-/******************************************************************************
- * P-States
- *****************************************************************************/
-static int
-nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei)
-{
-	struct nouveau_fb *pfb = nouveau_fb(clk);
-	struct nouveau_pstate *pstate;
-	int ret, idx = 0;
-
-	list_for_each_entry(pstate, &clk->states, head) {
-		if (idx++ == pstatei)
-			break;
-	}
-
-	nv_debug(clk, "setting performance state %d\n", pstatei);
-	clk->pstate = pstatei;
-
-	if (pfb->ram->calc) {
-		int khz = pstate->base.domain[nv_clk_src_mem];
-		do {
-			ret = pfb->ram->calc(pfb, khz);
-			if (ret == 0)
-				ret = pfb->ram->prog(pfb);
-		} while (ret > 0);
-		pfb->ram->tidy(pfb);
-	}
-
-	return nouveau_cstate_prog(clk, pstate, 0);
-}
-
-static void
-nouveau_pstate_work(struct work_struct *work)
-{
-	struct nouveau_clock *clk = container_of(work, typeof(*clk), work);
-	int pstate;
-
-	if (!atomic_xchg(&clk->waiting, 0))
-		return;
-	clk->pwrsrc = power_supply_is_system_supplied();
-
-	nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
-		 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
-		 clk->astate, clk->tstate, clk->dstate);
-
-	pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
-	if (clk->state_nr && pstate != -1) {
-		pstate = (pstate < 0) ? clk->astate : pstate;
-		pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
-		pstate = max(pstate, clk->dstate);
-	} else {
-		pstate = clk->pstate = -1;
-	}
-
-	nv_trace(clk, "-> %d\n", pstate);
-	if (pstate != clk->pstate) {
-		int ret = nouveau_pstate_prog(clk, pstate);
-		if (ret) {
-			nv_error(clk, "error setting pstate %d: %d\n",
-				 pstate, ret);
-		}
-	}
-
-	wake_up_all(&clk->wait);
-	nvkm_notify_get(&clk->pwrsrc_ntfy);
-}
-
-static int
-nouveau_pstate_calc(struct nouveau_clock *clk, bool wait)
-{
-	atomic_set(&clk->waiting, 1);
-	schedule_work(&clk->work);
-	if (wait)
-		wait_event(clk->wait, !atomic_read(&clk->waiting));
-	return 0;
-}
-
-static void
-nouveau_pstate_info(struct nouveau_clock *clk, struct nouveau_pstate *pstate)
-{
-	struct nouveau_clocks *clock = clk->domains - 1;
-	struct nouveau_cstate *cstate;
-	char info[3][32] = { "", "", "" };
-	char name[4] = "--";
-	int i = -1;
-
-	if (pstate->pstate != 0xff)
-		snprintf(name, sizeof(name), "%02x", pstate->pstate);
-
-	while ((++clock)->name != nv_clk_src_max) {
-		u32 lo = pstate->base.domain[clock->name];
-		u32 hi = lo;
-		if (hi == 0)
-			continue;
-
-		nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo);
-		list_for_each_entry(cstate, &pstate->list, head) {
-			u32 freq = cstate->domain[clock->name];
-			lo = min(lo, freq);
-			hi = max(hi, freq);
-			nv_debug(clk, "%10d KHz\n", freq);
-		}
-
-		if (clock->mname && ++i < ARRAY_SIZE(info)) {
-			lo /= clock->mdiv;
-			hi /= clock->mdiv;
-			if (lo == hi) {
-				snprintf(info[i], sizeof(info[i]), "%s %d MHz",
-					 clock->mname, lo);
-			} else {
-				snprintf(info[i], sizeof(info[i]),
-					 "%s %d-%d MHz", clock->mname, lo, hi);
-			}
-		}
-	}
-
-	nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]);
-}
-
-static void
-nouveau_pstate_del(struct nouveau_pstate *pstate)
-{
-	struct nouveau_cstate *cstate, *temp;
-
-	list_for_each_entry_safe(cstate, temp, &pstate->list, head) {
-		nouveau_cstate_del(cstate);
-	}
-
-	list_del(&pstate->head);
-	kfree(pstate);
-}
-
-static int
-nouveau_pstate_new(struct nouveau_clock *clk, int idx)
-{
-	struct nouveau_bios *bios = nouveau_bios(clk);
-	struct nouveau_clocks *domain = clk->domains - 1;
-	struct nouveau_pstate *pstate;
-	struct nouveau_cstate *cstate;
-	struct nvbios_cstepE cstepE;
-	struct nvbios_perfE perfE;
-	u8  ver, hdr, cnt, len;
-	u16 data;
-
-	data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE);
-	if (!data)
-		return -EINVAL;
-	if (perfE.pstate == 0xff)
-		return 0;
-
-	pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
-	cstate = &pstate->base;
-	if (!pstate)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&pstate->list);
-
-	pstate->pstate = perfE.pstate;
-	pstate->fanspeed = perfE.fanspeed;
-	cstate->voltage = perfE.voltage;
-	cstate->domain[nv_clk_src_core] = perfE.core;
-	cstate->domain[nv_clk_src_shader] = perfE.shader;
-	cstate->domain[nv_clk_src_mem] = perfE.memory;
-	cstate->domain[nv_clk_src_vdec] = perfE.vdec;
-	cstate->domain[nv_clk_src_dom6] = perfE.disp;
-
-	while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) {
-		struct nvbios_perfS perfS;
-		u8  sver = ver, shdr = hdr;
-		u32 perfSe = nvbios_perfSp(bios, data, domain->bios,
-					  &sver, &shdr, cnt, len, &perfS);
-		if (perfSe == 0 || sver != 0x40)
-			continue;
-
-		if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
-			perfS.v40.freq = nouveau_clock_adjust(clk, false,
-							      pstate->pstate,
-							      domain->bios,
-							      perfS.v40.freq);
-		}
-
-		cstate->domain[domain->name] = perfS.v40.freq;
-	}
-
-	data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE);
-	if (data) {
-		int idx = cstepE.index;
-		do {
-			nouveau_cstate_new(clk, idx, pstate);
-		} while(idx--);
-	}
-
-	nouveau_pstate_info(clk, pstate);
-	list_add_tail(&pstate->head, &clk->states);
-	clk->state_nr++;
-	return 0;
-}
-
-/******************************************************************************
- * Adjustment triggers
- *****************************************************************************/
-static int
-nouveau_clock_ustate_update(struct nouveau_clock *clk, int req)
-{
-	struct nouveau_pstate *pstate;
-	int i = 0;
-
-	if (!clk->allow_reclock)
-		return -ENOSYS;
-
-	if (req != -1 && req != -2) {
-		list_for_each_entry(pstate, &clk->states, head) {
-			if (pstate->pstate == req)
-				break;
-			i++;
-		}
-
-		if (pstate->pstate != req)
-			return -EINVAL;
-		req = i;
-	}
-
-	return req + 2;
-}
-
-static int
-nouveau_clock_nstate(struct nouveau_clock *clk, const char *mode, int arglen)
-{
-	int ret = 1;
-
-	if (strncasecmpz(mode, "disabled", arglen)) {
-		char save = mode[arglen];
-		long v;
-
-		((char *)mode)[arglen] = '\0';
-		if (!kstrtol(mode, 0, &v)) {
-			ret = nouveau_clock_ustate_update(clk, v);
-			if (ret < 0)
-				ret = 1;
-		}
-		((char *)mode)[arglen] = save;
-	}
-
-	return ret - 2;
-}
-
-int
-nouveau_clock_ustate(struct nouveau_clock *clk, int req, int pwr)
-{
-	int ret = nouveau_clock_ustate_update(clk, req);
-	if (ret >= 0) {
-		if (ret -= 2, pwr) clk->ustate_ac = ret;
-		else		   clk->ustate_dc = ret;
-		return nouveau_pstate_calc(clk, true);
-	}
-	return ret;
-}
-
-int
-nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel)
-{
-	if (!rel) clk->astate  = req;
-	if ( rel) clk->astate += rel;
-	clk->astate = min(clk->astate, clk->state_nr - 1);
-	clk->astate = max(clk->astate, 0);
-	return nouveau_pstate_calc(clk, true);
-}
-
-int
-nouveau_clock_tstate(struct nouveau_clock *clk, int req, int rel)
-{
-	if (!rel) clk->tstate  = req;
-	if ( rel) clk->tstate += rel;
-	clk->tstate = min(clk->tstate, 0);
-	clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
-	return nouveau_pstate_calc(clk, true);
-}
-
-int
-nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
-{
-	if (!rel) clk->dstate  = req;
-	if ( rel) clk->dstate += rel;
-	clk->dstate = min(clk->dstate, clk->state_nr - 1);
-	clk->dstate = max(clk->dstate, 0);
-	return nouveau_pstate_calc(clk, true);
-}
-
-static int
-nouveau_clock_pwrsrc(struct nvkm_notify *notify)
-{
-	struct nouveau_clock *clk =
-		container_of(notify, typeof(*clk), pwrsrc_ntfy);
-	nouveau_pstate_calc(clk, false);
-	return NVKM_NOTIFY_DROP;
-}
-
-/******************************************************************************
- * subdev base class implementation
- *****************************************************************************/
-
-int
-_nouveau_clock_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_clock *clk = (void *)object;
-	nvkm_notify_put(&clk->pwrsrc_ntfy);
-	return nouveau_subdev_fini(&clk->base, suspend);
-}
-
-int
-_nouveau_clock_init(struct nouveau_object *object)
-{
-	struct nouveau_clock *clk = (void *)object;
-	struct nouveau_clocks *clock = clk->domains;
-	int ret;
-
-	ret = nouveau_subdev_init(&clk->base);
-	if (ret)
-		return ret;
-
-	memset(&clk->bstate, 0x00, sizeof(clk->bstate));
-	INIT_LIST_HEAD(&clk->bstate.list);
-	clk->bstate.pstate = 0xff;
-
-	while (clock->name != nv_clk_src_max) {
-		ret = clk->read(clk, clock->name);
-		if (ret < 0) {
-			nv_error(clk, "%02x freq unknown\n", clock->name);
-			return ret;
-		}
-		clk->bstate.base.domain[clock->name] = ret;
-		clock++;
-	}
-
-	nouveau_pstate_info(clk, &clk->bstate);
-
-	clk->astate = clk->state_nr - 1;
-	clk->tstate = 0;
-	clk->dstate = 0;
-	clk->pstate = -1;
-	nouveau_pstate_calc(clk, true);
-	return 0;
-}
-
-void
-_nouveau_clock_dtor(struct nouveau_object *object)
-{
-	struct nouveau_clock *clk = (void *)object;
-	struct nouveau_pstate *pstate, *temp;
-
-	nvkm_notify_fini(&clk->pwrsrc_ntfy);
-
-	list_for_each_entry_safe(pstate, temp, &clk->states, head) {
-		nouveau_pstate_del(pstate);
-	}
-
-	nouveau_subdev_destroy(&clk->base);
-}
-
-int
-nouveau_clock_create_(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass,
-		      struct nouveau_clocks *clocks,
-		      struct nouveau_pstate *pstates, int nb_pstates,
-		      bool allow_reclock,
-		      int length, void **object)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_clock *clk;
-	int ret, idx, arglen;
-	const char *mode;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "CLK",
-				     "clock", length, object);
-	clk = *object;
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&clk->states);
-	clk->domains = clocks;
-	clk->ustate_ac = -1;
-	clk->ustate_dc = -1;
-
-	INIT_WORK(&clk->work, nouveau_pstate_work);
-	init_waitqueue_head(&clk->wait);
-	atomic_set(&clk->waiting, 0);
-
-	/* If no pstates are provided, try and fetch them from the BIOS */
-	if (!pstates) {
-		idx = 0;
-		do {
-			ret = nouveau_pstate_new(clk, idx++);
-		} while (ret == 0);
-	} else {
-		for (idx = 0; idx < nb_pstates; idx++)
-			list_add_tail(&pstates[idx].head, &clk->states);
-		clk->state_nr = nb_pstates;
-	}
-
-	clk->allow_reclock = allow_reclock;
-
-	ret = nvkm_notify_init(NULL, &device->event, nouveau_clock_pwrsrc, true,
-			       NULL, 0, 0, &clk->pwrsrc_ntfy);
-	if (ret)
-		return ret;
-
-	mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen);
-	if (mode) {
-		clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
-		clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
-	}
-
-	mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen);
-	if (mode)
-		clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
-
-	mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen);
-	if (mode)
-		clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
-
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c
deleted file mode 100644
index fb4fad3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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.
- *
- * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c
- *
- */
-
-#define MHZ (1000 * 1000)
-
-#define MASK(w)	((1 << w) - 1)
-
-#define SYS_GPCPLL_CFG_BASE			0x00137000
-#define GPC_BCASE_GPCPLL_CFG_BASE		0x00132800
-
-#define GPCPLL_CFG		(SYS_GPCPLL_CFG_BASE + 0)
-#define GPCPLL_CFG_ENABLE	BIT(0)
-#define GPCPLL_CFG_IDDQ		BIT(1)
-#define GPCPLL_CFG_LOCK_DET_OFF	BIT(4)
-#define GPCPLL_CFG_LOCK		BIT(17)
-
-#define GPCPLL_COEFF		(SYS_GPCPLL_CFG_BASE + 4)
-#define GPCPLL_COEFF_M_SHIFT	0
-#define GPCPLL_COEFF_M_WIDTH	8
-#define GPCPLL_COEFF_N_SHIFT	8
-#define GPCPLL_COEFF_N_WIDTH	8
-#define GPCPLL_COEFF_P_SHIFT	16
-#define GPCPLL_COEFF_P_WIDTH	6
-
-#define GPCPLL_CFG2			(SYS_GPCPLL_CFG_BASE + 0xc)
-#define GPCPLL_CFG2_SETUP2_SHIFT	16
-#define GPCPLL_CFG2_PLL_STEPA_SHIFT	24
-
-#define GPCPLL_CFG3			(SYS_GPCPLL_CFG_BASE + 0x18)
-#define GPCPLL_CFG3_PLL_STEPB_SHIFT	16
-
-#define GPCPLL_NDIV_SLOWDOWN			(SYS_GPCPLL_CFG_BASE + 0x1c)
-#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT	0
-#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT	8
-#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT	16
-#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT	22
-#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT	31
-
-#define SEL_VCO				(SYS_GPCPLL_CFG_BASE + 0x100)
-#define SEL_VCO_GPC2CLK_OUT_SHIFT	0
-
-#define GPC2CLK_OUT			(SYS_GPCPLL_CFG_BASE + 0x250)
-#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH	1
-#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT	31
-#define GPC2CLK_OUT_SDIV14_INDIV4_MODE	1
-#define GPC2CLK_OUT_VCODIV_WIDTH	6
-#define GPC2CLK_OUT_VCODIV_SHIFT	8
-#define GPC2CLK_OUT_VCODIV1		0
-#define GPC2CLK_OUT_VCODIV_MASK		(MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \
-					GPC2CLK_OUT_VCODIV_SHIFT)
-#define	GPC2CLK_OUT_BYPDIV_WIDTH	6
-#define GPC2CLK_OUT_BYPDIV_SHIFT	0
-#define GPC2CLK_OUT_BYPDIV31		0x3c
-#define GPC2CLK_OUT_INIT_MASK	((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \
-		GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\
-		| (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\
-		| (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT))
-#define GPC2CLK_OUT_INIT_VAL	((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \
-		GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \
-		| (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \
-		| (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT))
-
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG	(GPC_BCASE_GPCPLL_CFG_BASE + 0xa0)
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT	24
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \
-	    (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT)
-
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-
-#ifdef __KERNEL__
-#include <nouveau_platform.h>
-#endif
-
-static const u8 pl_to_div[] = {
-/* PL:   0, 1, 2, 3, 4, 5, 6,  7,  8,  9, 10, 11, 12, 13, 14 */
-/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32,
-};
-
-/* All frequencies in Mhz */
-struct gk20a_clk_pllg_params {
-	u32 min_vco, max_vco;
-	u32 min_u, max_u;
-	u32 min_m, max_m;
-	u32 min_n, max_n;
-	u32 min_pl, max_pl;
-};
-
-static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
-	.min_vco = 1000, .max_vco = 2064,
-	.min_u = 12, .max_u = 38,
-	.min_m = 1, .max_m = 255,
-	.min_n = 8, .max_n = 255,
-	.min_pl = 1, .max_pl = 32,
-};
-
-struct gk20a_clock_priv {
-	struct nouveau_clock base;
-	const struct gk20a_clk_pllg_params *params;
-	u32 m, n, pl;
-	u32 parent_rate;
-};
-#define to_gk20a_clock(base) container_of(base, struct gk20a_clock_priv, base)
-
-static void
-gk20a_pllg_read_mnp(struct gk20a_clock_priv *priv)
-{
-	u32 val;
-
-	val = nv_rd32(priv, GPCPLL_COEFF);
-	priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
-	priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH);
-	priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
-}
-
-static u32
-gk20a_pllg_calc_rate(struct gk20a_clock_priv *priv)
-{
-	u32 rate;
-	u32 divider;
-
-	rate = priv->parent_rate * priv->n;
-	divider = priv->m * pl_to_div[priv->pl];
-	do_div(rate, divider);
-
-	return rate / 2;
-}
-
-static int
-gk20a_pllg_calc_mnp(struct gk20a_clock_priv *priv, unsigned long rate)
-{
-	u32 target_clk_f, ref_clk_f, target_freq;
-	u32 min_vco_f, max_vco_f;
-	u32 low_pl, high_pl, best_pl;
-	u32 target_vco_f, vco_f;
-	u32 best_m, best_n;
-	u32 u_f;
-	u32 m, n, n2;
-	u32 delta, lwv, best_delta = ~0;
-	u32 pl;
-
-	target_clk_f = rate * 2 / MHZ;
-	ref_clk_f = priv->parent_rate / MHZ;
-
-	max_vco_f = priv->params->max_vco;
-	min_vco_f = priv->params->min_vco;
-	best_m = priv->params->max_m;
-	best_n = priv->params->min_n;
-	best_pl = priv->params->min_pl;
-
-	target_vco_f = target_clk_f + target_clk_f / 50;
-	if (max_vco_f < target_vco_f)
-		max_vco_f = target_vco_f;
-
-	/* min_pl <= high_pl <= max_pl */
-	high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f;
-	high_pl = min(high_pl, priv->params->max_pl);
-	high_pl = max(high_pl, priv->params->min_pl);
-
-	/* min_pl <= low_pl <= max_pl */
-	low_pl = min_vco_f / target_vco_f;
-	low_pl = min(low_pl, priv->params->max_pl);
-	low_pl = max(low_pl, priv->params->min_pl);
-
-	/* Find Indices of high_pl and low_pl */
-	for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
-		if (pl_to_div[pl] >= low_pl) {
-			low_pl = pl;
-			break;
-		}
-	}
-	for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
-		if (pl_to_div[pl] >= high_pl) {
-			high_pl = pl;
-			break;
-		}
-	}
-
-	nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl,
-		 pl_to_div[low_pl], high_pl, pl_to_div[high_pl]);
-
-	/* Select lowest possible VCO */
-	for (pl = low_pl; pl <= high_pl; pl++) {
-		target_vco_f = target_clk_f * pl_to_div[pl];
-		for (m = priv->params->min_m; m <= priv->params->max_m; m++) {
-			u_f = ref_clk_f / m;
-
-			if (u_f < priv->params->min_u)
-				break;
-			if (u_f > priv->params->max_u)
-				continue;
-
-			n = (target_vco_f * m) / ref_clk_f;
-			n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;
-
-			if (n > priv->params->max_n)
-				break;
-
-			for (; n <= n2; n++) {
-				if (n < priv->params->min_n)
-					continue;
-				if (n > priv->params->max_n)
-					break;
-
-				vco_f = ref_clk_f * n / m;
-
-				if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
-					lwv = (vco_f + (pl_to_div[pl] / 2))
-						/ pl_to_div[pl];
-					delta = abs(lwv - target_clk_f);
-
-					if (delta < best_delta) {
-						best_delta = delta;
-						best_m = m;
-						best_n = n;
-						best_pl = pl;
-
-						if (best_delta == 0)
-							goto found_match;
-					}
-				}
-			}
-		}
-	}
-
-found_match:
-	WARN_ON(best_delta == ~0);
-
-	if (best_delta != 0)
-		nv_debug(priv, "no best match for target @ %dMHz on gpc_pll",
-			 target_clk_f);
-
-	priv->m = best_m;
-	priv->n = best_n;
-	priv->pl = best_pl;
-
-	target_freq = gk20a_pllg_calc_rate(priv) / MHZ;
-
-	nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n",
-		 target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]);
-
-	return 0;
-}
-
-static int
-gk20a_pllg_slide(struct gk20a_clock_priv *priv, u32 n)
-{
-	u32 val;
-	int ramp_timeout;
-
-	/* get old coefficients */
-	val = nv_rd32(priv, GPCPLL_COEFF);
-	/* do nothing if NDIV is the same */
-	if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH)))
-		return 0;
-
-	/* setup */
-	nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT,
-		0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT);
-	nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT,
-		0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT);
-
-	/* pll slowdown mode */
-	nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
-		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT),
-		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT));
-
-	/* new ndiv ready for ramp */
-	val = nv_rd32(priv, GPCPLL_COEFF);
-	val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT);
-	val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT;
-	udelay(1);
-	nv_wr32(priv, GPCPLL_COEFF, val);
-
-	/* dynamic ramp to new ndiv */
-	val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
-	val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT;
-	udelay(1);
-	nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val);
-
-	for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) {
-		udelay(1);
-		val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG);
-		if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK)
-			break;
-	}
-
-	/* exit slowdown mode */
-	nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
-		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) |
-		BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0);
-	nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
-
-	if (ramp_timeout <= 0) {
-		nv_error(priv, "gpcpll dynamic ramp timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static void
-_gk20a_pllg_enable(struct gk20a_clock_priv *priv)
-{
-	nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE);
-	nv_rd32(priv, GPCPLL_CFG);
-}
-
-static void
-_gk20a_pllg_disable(struct gk20a_clock_priv *priv)
-{
-	nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0);
-	nv_rd32(priv, GPCPLL_CFG);
-}
-
-static int
-_gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv, bool allow_slide)
-{
-	u32 val, cfg;
-	u32 m_old, pl_old, n_lo;
-
-	/* get old coefficients */
-	val = nv_rd32(priv, GPCPLL_COEFF);
-	m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
-	pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
-
-	/* do NDIV slide if there is no change in M and PL */
-	cfg = nv_rd32(priv, GPCPLL_CFG);
-	if (allow_slide && priv->m == m_old && priv->pl == pl_old &&
-	    (cfg & GPCPLL_CFG_ENABLE)) {
-		return gk20a_pllg_slide(priv, priv->n);
-	}
-
-	/* slide down to NDIV_LO */
-	n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco,
-			    priv->parent_rate / MHZ);
-	if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) {
-		int ret = gk20a_pllg_slide(priv, n_lo);
-
-		if (ret)
-			return ret;
-	}
-
-	/* split FO-to-bypass jump in halfs by setting out divider 1:2 */
-	nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK,
-		0x2 << GPC2CLK_OUT_VCODIV_SHIFT);
-
-	/* put PLL in bypass before programming it */
-	val = nv_rd32(priv, SEL_VCO);
-	val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
-	udelay(2);
-	nv_wr32(priv, SEL_VCO, val);
-
-	/* get out from IDDQ */
-	val = nv_rd32(priv, GPCPLL_CFG);
-	if (val & GPCPLL_CFG_IDDQ) {
-		val &= ~GPCPLL_CFG_IDDQ;
-		nv_wr32(priv, GPCPLL_CFG, val);
-		nv_rd32(priv, GPCPLL_CFG);
-		udelay(2);
-	}
-
-	_gk20a_pllg_disable(priv);
-
-	nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n,
-		 priv->pl);
-
-	n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco,
-			    priv->parent_rate / MHZ);
-	val = priv->m << GPCPLL_COEFF_M_SHIFT;
-	val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT;
-	val |= priv->pl << GPCPLL_COEFF_P_SHIFT;
-	nv_wr32(priv, GPCPLL_COEFF, val);
-
-	_gk20a_pllg_enable(priv);
-
-	val = nv_rd32(priv, GPCPLL_CFG);
-	if (val & GPCPLL_CFG_LOCK_DET_OFF) {
-		val &= ~GPCPLL_CFG_LOCK_DET_OFF;
-		nv_wr32(priv, GPCPLL_CFG, val);
-	}
-
-	if (!nouveau_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK,
-				   GPCPLL_CFG_LOCK)) {
-		nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__);
-		return -ETIMEDOUT;
-	}
-
-	/* switch to VCO mode */
-	nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
-
-	/* restore out divider 1:1 */
-	val = nv_rd32(priv, GPC2CLK_OUT);
-	val &= ~GPC2CLK_OUT_VCODIV_MASK;
-	udelay(2);
-	nv_wr32(priv, GPC2CLK_OUT, val);
-
-	/* slide up to new NDIV */
-	return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0;
-}
-
-static int
-gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv)
-{
-	int err;
-
-	err = _gk20a_pllg_program_mnp(priv, true);
-	if (err)
-		err = _gk20a_pllg_program_mnp(priv, false);
-
-	return err;
-}
-
-static void
-gk20a_pllg_disable(struct gk20a_clock_priv *priv)
-{
-	u32 val;
-
-	/* slide to VCO min */
-	val = nv_rd32(priv, GPCPLL_CFG);
-	if (val & GPCPLL_CFG_ENABLE) {
-		u32 coeff, m, n_lo;
-
-		coeff = nv_rd32(priv, GPCPLL_COEFF);
-		m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
-		n_lo = DIV_ROUND_UP(m * priv->params->min_vco,
-				    priv->parent_rate / MHZ);
-		gk20a_pllg_slide(priv, n_lo);
-	}
-
-	/* put PLL in bypass before disabling it */
-	nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0);
-
-	_gk20a_pllg_disable(priv);
-}
-
-#define GK20A_CLK_GPC_MDIV 1000
-
-static struct nouveau_clocks
-gk20a_domains[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV },
-	{ nv_clk_src_max }
-};
-
-static struct nouveau_pstate
-gk20a_pstates[] = {
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 72000,
-			.voltage = 0,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 108000,
-			.voltage = 1,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 180000,
-			.voltage = 2,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 252000,
-			.voltage = 3,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 324000,
-			.voltage = 4,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 396000,
-			.voltage = 5,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 468000,
-			.voltage = 6,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 540000,
-			.voltage = 7,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 612000,
-			.voltage = 8,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 648000,
-			.voltage = 9,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 684000,
-			.voltage = 10,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 708000,
-			.voltage = 11,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 756000,
-			.voltage = 12,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 804000,
-			.voltage = 13,
-		},
-	},
-	{
-		.base = {
-			.domain[nv_clk_src_gpc] = 852000,
-			.voltage = 14,
-		},
-	},
-};
-
-static int
-gk20a_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct gk20a_clock_priv *priv = (void *)clk;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return nv_device(clk)->crystal;
-	case nv_clk_src_gpc:
-		gk20a_pllg_read_mnp(priv);
-		return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV;
-	default:
-		nv_error(clk, "invalid clock source %d\n", src);
-		return -EINVAL;
-	}
-}
-
-static int
-gk20a_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct gk20a_clock_priv *priv = (void *)clk;
-
-	return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] *
-					 GK20A_CLK_GPC_MDIV);
-}
-
-static int
-gk20a_clock_prog(struct nouveau_clock *clk)
-{
-	struct gk20a_clock_priv *priv = (void *)clk;
-
-	return gk20a_pllg_program_mnp(priv);
-}
-
-static void
-gk20a_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static int
-gk20a_clock_fini(struct nouveau_object *object, bool suspend)
-{
-	struct gk20a_clock_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_clock_fini(&priv->base, false);
-
-	gk20a_pllg_disable(priv);
-
-	return ret;
-}
-
-static int
-gk20a_clock_init(struct nouveau_object *object)
-{
-	struct gk20a_clock_priv *priv = (void *)object;
-	int ret;
-
-	nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL);
-
-	ret = nouveau_clock_init(&priv->base);
-	if (ret)
-		return ret;
-
-	ret = gk20a_clock_prog(&priv->base);
-	if (ret) {
-		nv_error(priv, "cannot initialize clock\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int
-gk20a_clock_ctor(struct nouveau_object *parent,  struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, void *data, u32 size,
-		 struct nouveau_object **pobject)
-{
-	struct gk20a_clock_priv *priv;
-	struct nouveau_platform_device *plat;
-	int ret;
-	int i;
-
-	/* Finish initializing the pstates */
-	for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) {
-		INIT_LIST_HEAD(&gk20a_pstates[i].list);
-		gk20a_pstates[i].pstate = i + 1;
-	}
-
-	ret = nouveau_clock_create(parent, engine, oclass, gk20a_domains,
-			gk20a_pstates, ARRAY_SIZE(gk20a_pstates), true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->params = &gk20a_pllg_params;
-
-	plat = nv_device_to_platform(nv_device(parent));
-	priv->parent_rate = clk_get_rate(plat->gpu->clk);
-	nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ);
-
-	priv->base.read = gk20a_clock_read;
-	priv->base.calc = gk20a_clock_calc;
-	priv->base.prog = gk20a_clock_prog;
-	priv->base.tidy = gk20a_clock_tidy;
-
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0xea),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_clock_ctor,
-		.dtor = _nouveau_subdev_dtor,
-		.init = gk20a_clock_init,
-		.fini = gk20a_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
deleted file mode 100644
index 4c48232..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-#include <subdev/devinit/nv04.h>
-
-#include "pll.h"
-
-struct nv04_clock_priv {
-	struct nouveau_clock base;
-};
-
-int
-nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
-		    int clk, struct nouveau_pll_vals *pv)
-{
-	int N1, M1, N2, M2, P;
-	int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
-	if (ret) {
-		pv->refclk = info->refclk;
-		pv->N1 = N1;
-		pv->M1 = M1;
-		pv->N2 = N2;
-		pv->M2 = M2;
-		pv->log2P = P;
-	}
-	return ret;
-}
-
-int
-nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
-		    struct nouveau_pll_vals *pv)
-{
-	struct nouveau_devinit *devinit = nouveau_devinit(clk);
-	int cv = nouveau_bios(clk)->version.chip;
-
-	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
-	    cv >= 0x40) {
-		if (reg1 > 0x405c)
-			setPLL_double_highregs(devinit, reg1, pv);
-		else
-			setPLL_double_lowregs(devinit, reg1, pv);
-	} else
-		setPLL_single(devinit, reg1, pv);
-
-	return 0;
-}
-
-static struct nouveau_clocks
-nv04_domain[] = {
-	{ nv_clk_src_max }
-};
-
-static int
-nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv04_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, NULL, 0,
-				   false, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.pll_calc = nv04_clock_pll_calc;
-	priv->base.pll_prog = nv04_clock_pll_prog;
-	return 0;
-}
-
-struct nouveau_oclass
-nv04_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
deleted file mode 100644
index 08368fe..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-struct nv40_clock_priv {
-	struct nouveau_clock base;
-	u32 ctrl;
-	u32 npll_ctrl;
-	u32 npll_coef;
-	u32 spll;
-};
-
-static struct nouveau_clocks
-nv40_domain[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
-	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
-	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
-	{ nv_clk_src_max }
-};
-
-static u32
-read_pll_1(struct nv40_clock_priv *priv, u32 reg)
-{
-	u32 ctrl = nv_rd32(priv, reg + 0x00);
-	int P = (ctrl & 0x00070000) >> 16;
-	int N = (ctrl & 0x0000ff00) >> 8;
-	int M = (ctrl & 0x000000ff) >> 0;
-	u32 ref = 27000, clk = 0;
-
-	if (ctrl & 0x80000000)
-		clk = ref * N / M;
-
-	return clk >> P;
-}
-
-static u32
-read_pll_2(struct nv40_clock_priv *priv, u32 reg)
-{
-	u32 ctrl = nv_rd32(priv, reg + 0x00);
-	u32 coef = nv_rd32(priv, reg + 0x04);
-	int N2 = (coef & 0xff000000) >> 24;
-	int M2 = (coef & 0x00ff0000) >> 16;
-	int N1 = (coef & 0x0000ff00) >> 8;
-	int M1 = (coef & 0x000000ff) >> 0;
-	int P = (ctrl & 0x00070000) >> 16;
-	u32 ref = 27000, clk = 0;
-
-	if ((ctrl & 0x80000000) && M1) {
-		clk = ref * N1 / M1;
-		if ((ctrl & 0x40000100) == 0x40000000) {
-			if (M2)
-				clk = clk * N2 / M2;
-			else
-				clk = 0;
-		}
-	}
-
-	return clk >> P;
-}
-
-static u32
-read_clk(struct nv40_clock_priv *priv, u32 src)
-{
-	switch (src) {
-	case 3:
-		return read_pll_2(priv, 0x004000);
-	case 2:
-		return read_pll_1(priv, 0x004008);
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int
-nv40_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nv40_clock_priv *priv = (void *)clk;
-	u32 mast = nv_rd32(priv, 0x00c040);
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return nv_device(priv)->crystal;
-	case nv_clk_src_href:
-		return 100000; /*XXX: PCIE/AGP differ*/
-	case nv_clk_src_core:
-		return read_clk(priv, (mast & 0x00000003) >> 0);
-	case nv_clk_src_shader:
-		return read_clk(priv, (mast & 0x00000030) >> 4);
-	case nv_clk_src_mem:
-		return read_pll_2(priv, 0x4020);
-	default:
-		break;
-	}
-
-	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
-	return -EINVAL;
-}
-
-static int
-nv40_clock_calc_pll(struct nv40_clock_priv *priv, u32 reg, u32 clk,
-		    int *N1, int *M1, int *N2, int *M2, int *log2P)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll pll;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, reg, &pll);
-	if (ret)
-		return ret;
-
-	if (clk < pll.vco1.max_freq)
-		pll.vco2.max_freq = 0;
-
-	ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P);
-	if (ret == 0)
-		return -ERANGE;
-	return ret;
-}
-
-static int
-nv40_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nv40_clock_priv *priv = (void *)clk;
-	int gclk = cstate->domain[nv_clk_src_core];
-	int sclk = cstate->domain[nv_clk_src_shader];
-	int N1, M1, N2, M2, log2P;
-	int ret;
-
-	/* core/geometric clock */
-	ret = nv40_clock_calc_pll(priv, 0x004000, gclk,
-				 &N1, &M1, &N2, &M2, &log2P);
-	if (ret < 0)
-		return ret;
-
-	if (N2 == M2) {
-		priv->npll_ctrl = 0x80000100 | (log2P << 16);
-		priv->npll_coef = (N1 << 8) | M1;
-	} else {
-		priv->npll_ctrl = 0xc0000000 | (log2P << 16);
-		priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
-	}
-
-	/* use the second pll for shader/rop clock, if it differs from core */
-	if (sclk && sclk != gclk) {
-		ret = nv40_clock_calc_pll(priv, 0x004008, sclk,
-					 &N1, &M1, NULL, NULL, &log2P);
-		if (ret < 0)
-			return ret;
-
-		priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
-		priv->ctrl = 0x00000223;
-	} else {
-		priv->spll = 0x00000000;
-		priv->ctrl = 0x00000333;
-	}
-
-	return 0;
-}
-
-static int
-nv40_clock_prog(struct nouveau_clock *clk)
-{
-	struct nv40_clock_priv *priv = (void *)clk;
-	nv_mask(priv, 0x00c040, 0x00000333, 0x00000000);
-	nv_wr32(priv, 0x004004, priv->npll_coef);
-	nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl);
-	nv_mask(priv, 0x004008, 0xc007ffff, priv->spll);
-	mdelay(5);
-	nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl);
-	return 0;
-}
-
-static void
-nv40_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static int
-nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv40_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, NULL, 0,
-				   true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.pll_calc = nv04_clock_pll_calc;
-	priv->base.pll_prog = nv04_clock_pll_prog;
-	priv->base.read = nv40_clock_read;
-	priv->base.calc = nv40_clock_calc;
-	priv->base.prog = nv40_clock_prog;
-	priv->base.tidy = nv40_clock_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nv40_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
deleted file mode 100644
index 5070ebc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "nv50.h"
-#include "pll.h"
-#include "seq.h"
-
-static u32
-read_div(struct nv50_clock_priv *priv)
-{
-	switch (nv_device(priv)->chipset) {
-	case 0x50: /* it exists, but only has bit 31, not the dividers.. */
-	case 0x84:
-	case 0x86:
-	case 0x98:
-	case 0xa0:
-		return nv_rd32(priv, 0x004700);
-	case 0x92:
-	case 0x94:
-	case 0x96:
-		return nv_rd32(priv, 0x004800);
-	default:
-		return 0x00000000;
-	}
-}
-
-static u32
-read_pll_src(struct nv50_clock_priv *priv, u32 base)
-{
-	struct nouveau_clock *clk = &priv->base;
-	u32 coef, ref = clk->read(clk, nv_clk_src_crystal);
-	u32 rsel = nv_rd32(priv, 0x00e18c);
-	int P, N, M, id;
-
-	switch (nv_device(priv)->chipset) {
-	case 0x50:
-	case 0xa0:
-		switch (base) {
-		case 0x4020:
-		case 0x4028: id = !!(rsel & 0x00000004); break;
-		case 0x4008: id = !!(rsel & 0x00000008); break;
-		case 0x4030: id = 0; break;
-		default:
-			nv_error(priv, "ref: bad pll 0x%06x\n", base);
-			return 0;
-		}
-
-		coef = nv_rd32(priv, 0x00e81c + (id * 0x0c));
-		ref *=  (coef & 0x01000000) ? 2 : 4;
-		P    =  (coef & 0x00070000) >> 16;
-		N    = ((coef & 0x0000ff00) >> 8) + 1;
-		M    = ((coef & 0x000000ff) >> 0) + 1;
-		break;
-	case 0x84:
-	case 0x86:
-	case 0x92:
-		coef = nv_rd32(priv, 0x00e81c);
-		P    = (coef & 0x00070000) >> 16;
-		N    = (coef & 0x0000ff00) >> 8;
-		M    = (coef & 0x000000ff) >> 0;
-		break;
-	case 0x94:
-	case 0x96:
-	case 0x98:
-		rsel = nv_rd32(priv, 0x00c050);
-		switch (base) {
-		case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
-		case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
-		case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
-		case 0x4030: rsel = 3; break;
-		default:
-			nv_error(priv, "ref: bad pll 0x%06x\n", base);
-			return 0;
-		}
-
-		switch (rsel) {
-		case 0: id = 1; break;
-		case 1: return clk->read(clk, nv_clk_src_crystal);
-		case 2: return clk->read(clk, nv_clk_src_href);
-		case 3: id = 0; break;
-		}
-
-		coef =  nv_rd32(priv, 0x00e81c + (id * 0x28));
-		P    = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7;
-		P   += (coef & 0x00070000) >> 16;
-		N    = (coef & 0x0000ff00) >> 8;
-		M    = (coef & 0x000000ff) >> 0;
-		break;
-	default:
-		BUG_ON(1);
-	}
-
-	if (M)
-		return (ref * N / M) >> P;
-	return 0;
-}
-
-static u32
-read_pll_ref(struct nv50_clock_priv *priv, u32 base)
-{
-	struct nouveau_clock *clk = &priv->base;
-	u32 src, mast = nv_rd32(priv, 0x00c040);
-
-	switch (base) {
-	case 0x004028:
-		src = !!(mast & 0x00200000);
-		break;
-	case 0x004020:
-		src = !!(mast & 0x00400000);
-		break;
-	case 0x004008:
-		src = !!(mast & 0x00010000);
-		break;
-	case 0x004030:
-		src = !!(mast & 0x02000000);
-		break;
-	case 0x00e810:
-		return clk->read(clk, nv_clk_src_crystal);
-	default:
-		nv_error(priv, "bad pll 0x%06x\n", base);
-		return 0;
-	}
-
-	if (src)
-		return clk->read(clk, nv_clk_src_href);
-	return read_pll_src(priv, base);
-}
-
-static u32
-read_pll(struct nv50_clock_priv *priv, u32 base)
-{
-	struct nouveau_clock *clk = &priv->base;
-	u32 mast = nv_rd32(priv, 0x00c040);
-	u32 ctrl = nv_rd32(priv, base + 0);
-	u32 coef = nv_rd32(priv, base + 4);
-	u32 ref = read_pll_ref(priv, base);
-	u32 freq = 0;
-	int N1, N2, M1, M2;
-
-	if (base == 0x004028 && (mast & 0x00100000)) {
-		/* wtf, appears to only disable post-divider on nva0 */
-		if (nv_device(priv)->chipset != 0xa0)
-			return clk->read(clk, nv_clk_src_dom6);
-	}
-
-	N2 = (coef & 0xff000000) >> 24;
-	M2 = (coef & 0x00ff0000) >> 16;
-	N1 = (coef & 0x0000ff00) >> 8;
-	M1 = (coef & 0x000000ff);
-	if ((ctrl & 0x80000000) && M1) {
-		freq = ref * N1 / M1;
-		if ((ctrl & 0x40000100) == 0x40000000) {
-			if (M2)
-				freq = freq * N2 / M2;
-			else
-				freq = 0;
-		}
-	}
-
-	return freq;
-}
-
-static int
-nv50_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nv50_clock_priv *priv = (void *)clk;
-	u32 mast = nv_rd32(priv, 0x00c040);
-	u32 P = 0;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return nv_device(priv)->crystal;
-	case nv_clk_src_href:
-		return 100000; /* PCIE reference clock */
-	case nv_clk_src_hclk:
-		return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000);
-	case nv_clk_src_hclkm3:
-		return clk->read(clk, nv_clk_src_hclk) * 3;
-	case nv_clk_src_hclkm3d2:
-		return clk->read(clk, nv_clk_src_hclk) * 3 / 2;
-	case nv_clk_src_host:
-		switch (mast & 0x30000000) {
-		case 0x00000000: return clk->read(clk, nv_clk_src_href);
-		case 0x10000000: break;
-		case 0x20000000: /* !0x50 */
-		case 0x30000000: return clk->read(clk, nv_clk_src_hclk);
-		}
-		break;
-	case nv_clk_src_core:
-		if (!(mast & 0x00100000))
-			P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16;
-		switch (mast & 0x00000003) {
-		case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
-		case 0x00000001: return clk->read(clk, nv_clk_src_dom6);
-		case 0x00000002: return read_pll(priv, 0x004020) >> P;
-		case 0x00000003: return read_pll(priv, 0x004028) >> P;
-		}
-		break;
-	case nv_clk_src_shader:
-		P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16;
-		switch (mast & 0x00000030) {
-		case 0x00000000:
-			if (mast & 0x00000080)
-				return clk->read(clk, nv_clk_src_host) >> P;
-			return clk->read(clk, nv_clk_src_crystal) >> P;
-		case 0x00000010: break;
-		case 0x00000020: return read_pll(priv, 0x004028) >> P;
-		case 0x00000030: return read_pll(priv, 0x004020) >> P;
-		}
-		break;
-	case nv_clk_src_mem:
-		P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16;
-		if (nv_rd32(priv, 0x004008) & 0x00000200) {
-			switch (mast & 0x0000c000) {
-			case 0x00000000:
-				return clk->read(clk, nv_clk_src_crystal) >> P;
-			case 0x00008000:
-			case 0x0000c000:
-				return clk->read(clk, nv_clk_src_href) >> P;
-			}
-		} else {
-			return read_pll(priv, 0x004008) >> P;
-		}
-		break;
-	case nv_clk_src_vdec:
-		P = (read_div(priv) & 0x00000700) >> 8;
-		switch (nv_device(priv)->chipset) {
-		case 0x84:
-		case 0x86:
-		case 0x92:
-		case 0x94:
-		case 0x96:
-		case 0xa0:
-			switch (mast & 0x00000c00) {
-			case 0x00000000:
-				if (nv_device(priv)->chipset == 0xa0) /* wtf?? */
-					return clk->read(clk, nv_clk_src_core) >> P;
-				return clk->read(clk, nv_clk_src_crystal) >> P;
-			case 0x00000400:
-				return 0;
-			case 0x00000800:
-				if (mast & 0x01000000)
-					return read_pll(priv, 0x004028) >> P;
-				return read_pll(priv, 0x004030) >> P;
-			case 0x00000c00:
-				return clk->read(clk, nv_clk_src_core) >> P;
-			}
-			break;
-		case 0x98:
-			switch (mast & 0x00000c00) {
-			case 0x00000000:
-				return clk->read(clk, nv_clk_src_core) >> P;
-			case 0x00000400:
-				return 0;
-			case 0x00000800:
-				return clk->read(clk, nv_clk_src_hclkm3d2) >> P;
-			case 0x00000c00:
-				return clk->read(clk, nv_clk_src_mem) >> P;
-			}
-			break;
-		}
-		break;
-	case nv_clk_src_dom6:
-		switch (nv_device(priv)->chipset) {
-		case 0x50:
-		case 0xa0:
-			return read_pll(priv, 0x00e810) >> 2;
-		case 0x84:
-		case 0x86:
-		case 0x92:
-		case 0x94:
-		case 0x96:
-		case 0x98:
-			P = (read_div(priv) & 0x00000007) >> 0;
-			switch (mast & 0x0c000000) {
-			case 0x00000000: return clk->read(clk, nv_clk_src_href);
-			case 0x04000000: break;
-			case 0x08000000: return clk->read(clk, nv_clk_src_hclk);
-			case 0x0c000000:
-				return clk->read(clk, nv_clk_src_hclkm3) >> P;
-			}
-			break;
-		default:
-			break;
-		}
-	default:
-		break;
-	}
-
-	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
-	return -EINVAL;
-}
-
-static u32
-calc_pll(struct nv50_clock_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll pll;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, reg, &pll);
-	if (ret)
-		return 0;
-
-	pll.vco2.max_freq = 0;
-	pll.refclk = read_pll_ref(priv, reg);
-	if (!pll.refclk)
-		return 0;
-
-	return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P);
-}
-
-static inline u32
-calc_div(u32 src, u32 target, int *div)
-{
-	u32 clk0 = src, clk1 = src;
-	for (*div = 0; *div <= 7; (*div)++) {
-		if (clk0 <= target) {
-			clk1 = clk0 << (*div ? 1 : 0);
-			break;
-		}
-		clk0 >>= 1;
-	}
-
-	if (target - clk0 <= clk1 - target)
-		return clk0;
-	(*div)--;
-	return clk1;
-}
-
-static inline u32
-clk_same(u32 a, u32 b)
-{
-	return ((a / 1000) == (b / 1000));
-}
-
-static int
-nv50_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nv50_clock_priv *priv = (void *)clk;
-	struct nv50_clock_hwsq *hwsq = &priv->hwsq;
-	const int shader = cstate->domain[nv_clk_src_shader];
-	const int core = cstate->domain[nv_clk_src_core];
-	const int vdec = cstate->domain[nv_clk_src_vdec];
-	const int dom6 = cstate->domain[nv_clk_src_dom6];
-	u32 mastm = 0, mastv = 0;
-	u32 divsm = 0, divsv = 0;
-	int N, M, P1, P2;
-	int freq, out;
-
-	/* prepare a hwsq script from which we'll perform the reclock */
-	out = clk_init(hwsq, nv_subdev(clk));
-	if (out)
-		return out;
-
-	clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */
-	clk_nsec(hwsq, 8000);
-	clk_setf(hwsq, 0x10, 0x00); /* disable fb */
-	clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
-
-	/* vdec: avoid modifying xpll until we know exactly how the other
-	 * clock domains work, i suspect at least some of them can also be
-	 * tied to xpll...
-	 */
-	if (vdec) {
-		/* see how close we can get using nvclk as a source */
-		freq = calc_div(core, vdec, &P1);
-
-		/* see how close we can get using xpll/hclk as a source */
-		if (nv_device(priv)->chipset != 0x98)
-			out = read_pll(priv, 0x004030);
-		else
-			out = clk->read(clk, nv_clk_src_hclkm3d2);
-		out = calc_div(out, vdec, &P2);
-
-		/* select whichever gets us closest */
-		if (abs(vdec - freq) <= abs(vdec - out)) {
-			if (nv_device(priv)->chipset != 0x98)
-				mastv |= 0x00000c00;
-			divsv |= P1 << 8;
-		} else {
-			mastv |= 0x00000800;
-			divsv |= P2 << 8;
-		}
-
-		mastm |= 0x00000c00;
-		divsm |= 0x00000700;
-	}
-
-	/* dom6: nfi what this is, but we're limited to various combinations
-	 * of the host clock frequency
-	 */
-	if (dom6) {
-		if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) {
-			mastv |= 0x00000000;
-		} else
-		if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) {
-			mastv |= 0x08000000;
-		} else {
-			freq = clk->read(clk, nv_clk_src_hclk) * 3;
-			freq = calc_div(freq, dom6, &P1);
-
-			mastv |= 0x0c000000;
-			divsv |= P1;
-		}
-
-		mastm |= 0x0c000000;
-		divsm |= 0x00000007;
-	}
-
-	/* vdec/dom6: switch to "safe" clocks temporarily, update dividers
-	 * and then switch to target clocks
-	 */
-	clk_mask(hwsq, mast, mastm, 0x00000000);
-	clk_mask(hwsq, divs, divsm, divsv);
-	clk_mask(hwsq, mast, mastm, mastv);
-
-	/* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6,
-	 * sclk to hclk) before reprogramming
-	 */
-	if (nv_device(priv)->chipset < 0x92)
-		clk_mask(hwsq, mast, 0x001000b0, 0x00100080);
-	else
-		clk_mask(hwsq, mast, 0x000000b3, 0x00000081);
-
-	/* core: for the moment at least, always use nvpll */
-	freq = calc_pll(priv, 0x4028, core, &N, &M, &P1);
-	if (freq == 0)
-		return -ERANGE;
-
-	clk_mask(hwsq, nvpll[0], 0xc03f0100,
-				 0x80000000 | (P1 << 19) | (P1 << 16));
-	clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M);
-
-	/* shader: tie to nvclk if possible, otherwise use spll.  have to be
-	 * very careful that the shader clock is at least twice the core, or
-	 * some chipsets will be very unhappy.  i expect most or all of these
-	 * cases will be handled by tying to nvclk, but it's possible there's
-	 * corners
-	 */
-	if (P1-- && shader == (core << 1)) {
-		clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16));
-		clk_mask(hwsq, mast, 0x00100033, 0x00000023);
-	} else {
-		freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
-		if (freq == 0)
-			return -ERANGE;
-
-		clk_mask(hwsq, spll[0], 0xc03f0100,
-					0x80000000 | (P1 << 19) | (P1 << 16));
-		clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M);
-		clk_mask(hwsq, mast, 0x00100033, 0x00000033);
-	}
-
-	/* restore normal operation */
-	clk_setf(hwsq, 0x10, 0x01); /* enable fb */
-	clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
-	clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */
-	return 0;
-}
-
-static int
-nv50_clock_prog(struct nouveau_clock *clk)
-{
-	struct nv50_clock_priv *priv = (void *)clk;
-	return clk_exec(&priv->hwsq, true);
-}
-
-static void
-nv50_clock_tidy(struct nouveau_clock *clk)
-{
-	struct nv50_clock_priv *priv = (void *)clk;
-	clk_exec(&priv->hwsq, false);
-}
-
-int
-nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv50_clock_oclass *pclass = (void *)oclass;
-	struct nv50_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, pclass->domains,
-				   NULL, 0, false, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->hwsq.r_fifo = hwsq_reg(0x002504);
-	priv->hwsq.r_spll[0] = hwsq_reg(0x004020);
-	priv->hwsq.r_spll[1] = hwsq_reg(0x004024);
-	priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028);
-	priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c);
-	switch (nv_device(priv)->chipset) {
-	case 0x92:
-	case 0x94:
-	case 0x96:
-		priv->hwsq.r_divs = hwsq_reg(0x004800);
-		break;
-	default:
-		priv->hwsq.r_divs = hwsq_reg(0x004700);
-		break;
-	}
-	priv->hwsq.r_mast = hwsq_reg(0x00c040);
-
-	priv->base.read = nv50_clock_read;
-	priv->base.calc = nv50_clock_calc;
-	priv->base.prog = nv50_clock_prog;
-	priv->base.tidy = nv50_clock_tidy;
-	return 0;
-}
-
-static struct nouveau_clocks
-nv50_domains[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
-	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
-	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
-	{ nv_clk_src_max }
-};
-
-struct nouveau_oclass *
-nv50_clock_oclass = &(struct nv50_clock_oclass) {
-	.base.handle = NV_SUBDEV(CLOCK, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-	.domains = nv50_domains,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h
deleted file mode 100644
index f10917d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVKM_CLK_NV50_H__
-#define __NVKM_CLK_NV50_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-#include <subdev/clock.h>
-
-struct nv50_clock_hwsq {
-	struct hwsq base;
-	struct hwsq_reg r_fifo;
-	struct hwsq_reg r_spll[2];
-	struct hwsq_reg r_nvpll[2];
-	struct hwsq_reg r_divs;
-	struct hwsq_reg r_mast;
-};
-
-struct nv50_clock_priv {
-	struct nouveau_clock base;
-	struct nv50_clock_hwsq hwsq;
-};
-
-int  nv50_clock_ctor(struct nouveau_object *, struct nouveau_object *,
-		     struct nouveau_oclass *, void *, u32,
-		     struct nouveau_object **);
-
-struct nv50_clock_oclass {
-	struct nouveau_oclass base;
-	struct nouveau_clocks *domains;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c
deleted file mode 100644
index b0b7c14..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nv50.h"
-
-static struct nouveau_clocks
-nv84_domains[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
-	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
-	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
-	{ nv_clk_src_vdec   , 0xff },
-	{ nv_clk_src_max }
-};
-
-struct nouveau_oclass *
-nv84_clock_oclass = &(struct nv50_clock_oclass) {
-	.base.handle = NV_SUBDEV(CLOCK, 0x84),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-	.domains = nv84_domains,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
deleted file mode 100644
index 07ad012..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- *          Roy Spliet
- */
-
-#include <engine/fifo.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-
-#include "pll.h"
-
-#include "nva3.h"
-
-struct nva3_clock_priv {
-	struct nouveau_clock base;
-	struct nva3_clock_info eng[nv_clk_src_max];
-};
-
-static u32 read_clk(struct nva3_clock_priv *, int, bool);
-static u32 read_pll(struct nva3_clock_priv *, int, u32);
-
-static u32
-read_vco(struct nva3_clock_priv *priv, int clk)
-{
-	u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
-
-	switch (sctl & 0x00000030) {
-	case 0x00000000:
-		return nv_device(priv)->crystal;
-	case 0x00000020:
-		return read_pll(priv, 0x41, 0x00e820);
-	case 0x00000030:
-		return read_pll(priv, 0x42, 0x00e8a0);
-	default:
-		return 0;
-	}
-}
-
-static u32
-read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en)
-{
-	u32 sctl, sdiv, sclk;
-
-	/* refclk for the 0xe8xx plls is a fixed frequency */
-	if (clk >= 0x40) {
-		if (nv_device(priv)->chipset == 0xaf) {
-			/* no joke.. seriously.. sigh.. */
-			return nv_rd32(priv, 0x00471c) * 1000;
-		}
-
-		return nv_device(priv)->crystal;
-	}
-
-	sctl = nv_rd32(priv, 0x4120 + (clk * 4));
-	if (!ignore_en && !(sctl & 0x00000100))
-		return 0;
-
-	/* out_alt */
-	if (sctl & 0x00000400)
-		return 108000;
-
-	/* vco_out */
-	switch (sctl & 0x00003000) {
-	case 0x00000000:
-		if (!(sctl & 0x00000200))
-			return nv_device(priv)->crystal;
-		return 0;
-	case 0x00002000:
-		if (sctl & 0x00000040)
-			return 108000;
-		return 100000;
-	case 0x00003000:
-		/* vco_enable */
-		if (!(sctl & 0x00000001))
-			return 0;
-
-		sclk = read_vco(priv, clk);
-		sdiv = ((sctl & 0x003f0000) >> 16) + 2;
-		return (sclk * 2) / sdiv;
-	default:
-		return 0;
-	}
-}
-
-static u32
-read_pll(struct nva3_clock_priv *priv, int clk, u32 pll)
-{
-	u32 ctrl = nv_rd32(priv, pll + 0);
-	u32 sclk = 0, P = 1, N = 1, M = 1;
-
-	if (!(ctrl & 0x00000008)) {
-		if (ctrl & 0x00000001) {
-			u32 coef = nv_rd32(priv, pll + 4);
-			M = (coef & 0x000000ff) >> 0;
-			N = (coef & 0x0000ff00) >> 8;
-			P = (coef & 0x003f0000) >> 16;
-
-			/* no post-divider on these..
-			 * XXX: it looks more like two post-"dividers" that
-			 * cross each other out in the default RPLL config */
-			if ((pll & 0x00ff00) == 0x00e800)
-				P = 1;
-
-			sclk = read_clk(priv, 0x00 + clk, false);
-		}
-	} else {
-		sclk = read_clk(priv, 0x10 + clk, false);
-	}
-
-	if (M * P)
-		return sclk * N / (M * P);
-	return 0;
-}
-
-static int
-nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nva3_clock_priv *priv = (void *)clk;
-	u32 hsrc;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return nv_device(priv)->crystal;
-	case nv_clk_src_core:
-	case nv_clk_src_core_intm:
-		return read_pll(priv, 0x00, 0x4200);
-	case nv_clk_src_shader:
-		return read_pll(priv, 0x01, 0x4220);
-	case nv_clk_src_mem:
-		return read_pll(priv, 0x02, 0x4000);
-	case nv_clk_src_disp:
-		return read_clk(priv, 0x20, false);
-	case nv_clk_src_vdec:
-		return read_clk(priv, 0x21, false);
-	case nv_clk_src_daemon:
-		return read_clk(priv, 0x25, false);
-	case nv_clk_src_host:
-		hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
-		switch (hsrc) {
-		case 0:
-			return read_clk(priv, 0x1d, false);
-		case 2:
-		case 3:
-			return 277000;
-		default:
-			nv_error(clk, "unknown HOST clock source %d\n", hsrc);
-			return -EINVAL;
-		}
-	default:
-		nv_error(clk, "invalid clock source %d\n", src);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-int
-nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz,
-		struct nva3_clock_info *info)
-{
-	struct nva3_clock_priv *priv = (void *)clock;
-	u32 oclk, sclk, sdiv, diff;
-
-	info->clk = 0;
-
-	switch (khz) {
-	case 27000:
-		info->clk = 0x00000100;
-		return khz;
-	case 100000:
-		info->clk = 0x00002100;
-		return khz;
-	case 108000:
-		info->clk = 0x00002140;
-		return khz;
-	default:
-		sclk = read_vco(priv, clk);
-		sdiv = min((sclk * 2) / khz, (u32)65);
-		oclk = (sclk * 2) / sdiv;
-		diff = ((khz + 3000) - oclk);
-
-		/* When imprecise, play it safe and aim for a clock lower than
-		 * desired rather than higher */
-		if (diff < 0) {
-			sdiv++;
-			oclk = (sclk * 2) / sdiv;
-		}
-
-		/* divider can go as low as 2, limited here because NVIDIA
-		 * and the VBIOS on my NVA8 seem to prefer using the PLL
-		 * for 810MHz - is there a good reason?
-		 * XXX: PLLs with refclk 810MHz?  */
-		if (sdiv > 4) {
-			info->clk = (((sdiv - 2) << 16) | 0x00003100);
-			return oclk;
-		}
-
-		break;
-	}
-
-	return -ERANGE;
-}
-
-int
-nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
-		struct nva3_clock_info *info)
-{
-	struct nouveau_bios *bios = nouveau_bios(clock);
-	struct nva3_clock_priv *priv = (void *)clock;
-	struct nvbios_pll limits;
-	int P, N, M, diff;
-	int ret;
-
-	info->pll = 0;
-
-	/* If we can get a within [-2, 3) MHz of a divider, we'll disable the
-	 * PLL and use the divider instead. */
-	ret = nva3_clk_info(clock, clk, khz, info);
-	diff = khz - ret;
-	if (!pll || (diff >= -2000 && diff < 3000)) {
-		goto out;
-	}
-
-	/* Try with PLL */
-	ret = nvbios_pll_parse(bios, pll, &limits);
-	if (ret)
-		return ret;
-
-	ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info);
-	if (ret != limits.refclk)
-		return -EINVAL;
-
-	ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
-	if (ret >= 0) {
-		info->pll = (P << 16) | (N << 8) | M;
-	}
-
-out:
-	info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
-
-	return ret ? ret : -ERANGE;
-}
-
-static int
-calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
-	 int clk, u32 pll, int idx)
-{
-	int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx],
-				  &priv->eng[idx]);
-	if (ret >= 0)
-		return 0;
-	return ret;
-}
-
-static int
-calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate)
-{
-	int ret = 0;
-	u32 kHz = cstate->domain[nv_clk_src_host];
-	struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
-
-	if (kHz == 277000) {
-		info->clk = 0;
-		info->host_out = NVA3_HOST_277;
-		return 0;
-	}
-
-	info->host_out = NVA3_HOST_CLK;
-
-	ret = nva3_clk_info(&priv->base, 0x1d, kHz, info);
-	if (ret >= 0)
-		return 0;
-	return ret;
-}
-
-int
-nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(clk);
-
-	/* halt and idle execution engines */
-	nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
-	nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
-	/* Wait until the interrupt handler is finished */
-	if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
-		return -EBUSY;
-
-	if (pfifo)
-		pfifo->pause(pfifo, flags);
-
-	if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
-		return -EIO;
-	if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
-		return -EIO;
-
-	return 0;
-}
-
-void
-nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(clk);
-
-	if (pfifo && flags)
-		pfifo->start(pfifo, flags);
-
-	nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
-	nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
-}
-
-static void
-disable_clk_src(struct nva3_clock_priv *priv, u32 src)
-{
-	nv_mask(priv, src, 0x00000100, 0x00000000);
-	nv_mask(priv, src, 0x00000001, 0x00000000);
-}
-
-static void
-prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
-{
-	struct nva3_clock_info *info = &priv->eng[idx];
-	const u32 src0 = 0x004120 + (clk * 4);
-	const u32 src1 = 0x004160 + (clk * 4);
-	const u32 ctrl = pll + 0;
-	const u32 coef = pll + 4;
-	u32 bypass;
-
-	if (info->pll) {
-		/* Always start from a non-PLL clock */
-		bypass = nv_rd32(priv, ctrl)  & 0x00000008;
-		if (!bypass) {
-			nv_mask(priv, src1, 0x00000101, 0x00000101);
-			nv_mask(priv, ctrl, 0x00000008, 0x00000008);
-			udelay(20);
-		}
-
-		nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
-		nv_wr32(priv, coef, info->pll);
-		nv_mask(priv, ctrl, 0x00000015, 0x00000015);
-		nv_mask(priv, ctrl, 0x00000010, 0x00000000);
-		if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
-			nv_mask(priv, ctrl, 0x00000010, 0x00000010);
-			nv_mask(priv, src0, 0x00000101, 0x00000000);
-			return;
-		}
-		nv_mask(priv, ctrl, 0x00000010, 0x00000010);
-		nv_mask(priv, ctrl, 0x00000008, 0x00000000);
-		disable_clk_src(priv, src1);
-	} else {
-		nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
-		nv_mask(priv, ctrl, 0x00000018, 0x00000018);
-		udelay(20);
-		nv_mask(priv, ctrl, 0x00000001, 0x00000000);
-		disable_clk_src(priv, src0);
-	}
-}
-
-static void
-prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
-{
-	struct nva3_clock_info *info = &priv->eng[idx];
-	nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
-}
-
-static void
-prog_host(struct nva3_clock_priv *priv)
-{
-	struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
-	u32 hsrc = (nv_rd32(priv, 0xc040));
-
-	switch (info->host_out) {
-	case NVA3_HOST_277:
-		if ((hsrc & 0x30000000) == 0) {
-			nv_wr32(priv, 0xc040, hsrc | 0x20000000);
-			disable_clk_src(priv, 0x4194);
-		}
-		break;
-	case NVA3_HOST_CLK:
-		prog_clk(priv, 0x1d, nv_clk_src_host);
-		if ((hsrc & 0x30000000) >= 0x20000000) {
-			nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
-		}
-		break;
-	default:
-		break;
-	}
-
-	/* This seems to be a clock gating factor on idle, always set to 64 */
-	nv_wr32(priv, 0xc044, 0x3e);
-}
-
-static void
-prog_core(struct nva3_clock_priv *priv, int idx)
-{
-	struct nva3_clock_info *info = &priv->eng[idx];
-	u32 fb_delay = nv_rd32(priv, 0x10002c);
-
-	if (fb_delay < info->fb_delay)
-		nv_wr32(priv, 0x10002c, info->fb_delay);
-
-	prog_pll(priv, 0x00, 0x004200, idx);
-
-	if (fb_delay > info->fb_delay)
-		nv_wr32(priv, 0x10002c, info->fb_delay);
-}
-
-static int
-nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nva3_clock_priv *priv = (void *)clk;
-	struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
-	int ret;
-
-	if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
-	    (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
-	    (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
-	    (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
-	    (ret = calc_host(priv, cstate)))
-		return ret;
-
-	/* XXX: Should be reading the highest bit in the VBIOS clock to decide
-	 * whether to use a PLL or not... but using a PLL defeats the purpose */
-	if (core->pll) {
-		ret = nva3_clk_info(clk, 0x10,
-				cstate->domain[nv_clk_src_core_intm],
-				&priv->eng[nv_clk_src_core_intm]);
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static int
-nva3_clock_prog(struct nouveau_clock *clk)
-{
-	struct nva3_clock_priv *priv = (void *)clk;
-	struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
-	int ret = 0;
-	unsigned long flags;
-	unsigned long *f = &flags;
-
-	ret = nva3_clock_pre(clk, f);
-	if (ret)
-		goto out;
-
-	if (core->pll)
-		prog_core(priv, nv_clk_src_core_intm);
-
-	prog_core(priv,  nv_clk_src_core);
-	prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
-	prog_clk(priv, 0x20, nv_clk_src_disp);
-	prog_clk(priv, 0x21, nv_clk_src_vdec);
-	prog_host(priv);
-
-out:
-	if (ret == -EBUSY)
-		f = NULL;
-
-	nva3_clock_post(clk, f);
-
-	return ret;
-}
-
-static void
-nva3_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static struct nouveau_clocks
-nva3_domain[] = {
-	{ nv_clk_src_crystal  , 0xff },
-	{ nv_clk_src_core     , 0x00, 0, "core", 1000 },
-	{ nv_clk_src_shader   , 0x01, 0, "shader", 1000 },
-	{ nv_clk_src_mem      , 0x02, 0, "memory", 1000 },
-	{ nv_clk_src_vdec     , 0x03 },
-	{ nv_clk_src_disp     , 0x04 },
-	{ nv_clk_src_host     , 0x05 },
-	{ nv_clk_src_core_intm, 0x06 },
-	{ nv_clk_src_max }
-};
-
-static int
-nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nva3_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0,
-				   true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.read = nva3_clock_read;
-	priv->base.calc = nva3_clock_calc;
-	priv->base.prog = nva3_clock_prog;
-	priv->base.tidy = nva3_clock_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nva3_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0xa3),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
deleted file mode 100644
index a45a103..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NVKM_CLK_NVA3_H__
-#define __NVKM_CLK_NVA3_H__
-
-#include <subdev/clock.h>
-
-struct nva3_clock_info {
-	u32 clk;
-	u32 pll;
-	enum {
-		NVA3_HOST_277,
-		NVA3_HOST_CLK,
-	} host_out;
-	u32 fb_delay;
-};
-
-int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
-		    struct nva3_clock_info *);
-int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags);
-void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags);
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c
deleted file mode 100644
index 54aeab8..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/fifo.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-#include <subdev/clock.h>
-
-#include "nva3.h"
-#include "pll.h"
-
-struct nvaa_clock_priv {
-	struct nouveau_clock base;
-	enum nv_clk_src csrc, ssrc, vsrc;
-	u32 cctrl, sctrl;
-	u32 ccoef, scoef;
-	u32 cpost, spost;
-	u32 vdiv;
-};
-
-static u32
-read_div(struct nouveau_clock *clk)
-{
-	return nv_rd32(clk, 0x004600);
-}
-
-static u32
-read_pll(struct nouveau_clock *clk, u32 base)
-{
-	u32 ctrl = nv_rd32(clk, base + 0);
-	u32 coef = nv_rd32(clk, base + 4);
-	u32 ref = clk->read(clk, nv_clk_src_href);
-	u32 post_div = 0;
-	u32 clock = 0;
-	int N1, M1;
-
-	switch (base){
-	case 0x4020:
-		post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16);
-		break;
-	case 0x4028:
-		post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16;
-		break;
-	default:
-		break;
-	}
-
-	N1 = (coef & 0x0000ff00) >> 8;
-	M1 = (coef & 0x000000ff);
-	if ((ctrl & 0x80000000) && M1) {
-		clock = ref * N1 / M1;
-		clock = clock / post_div;
-	}
-
-	return clock;
-}
-
-static int
-nvaa_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nvaa_clock_priv *priv = (void *)clk;
-	u32 mast = nv_rd32(clk, 0x00c054);
-	u32 P = 0;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return nv_device(priv)->crystal;
-	case nv_clk_src_href:
-		return 100000; /* PCIE reference clock */
-	case nv_clk_src_hclkm4:
-		return clk->read(clk, nv_clk_src_href) * 4;
-	case nv_clk_src_hclkm2d3:
-		return clk->read(clk, nv_clk_src_href) * 2 / 3;
-	case nv_clk_src_host:
-		switch (mast & 0x000c0000) {
-		case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3);
-		case 0x00040000: break;
-		case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4);
-		case 0x000c0000: return clk->read(clk, nv_clk_src_cclk);
-		}
-		break;
-	case nv_clk_src_core:
-		P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16;
-
-		switch (mast & 0x00000003) {
-		case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
-		case 0x00000001: return 0;
-		case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P;
-		case 0x00000003: return read_pll(clk, 0x004028) >> P;
-		}
-		break;
-	case nv_clk_src_cclk:
-		if ((mast & 0x03000000) != 0x03000000)
-			return clk->read(clk, nv_clk_src_core);
-
-		if ((mast & 0x00000200) == 0x00000000)
-			return clk->read(clk, nv_clk_src_core);
-
-		switch (mast & 0x00000c00) {
-		case 0x00000000: return clk->read(clk, nv_clk_src_href);
-		case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4);
-		case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3);
-		default: return 0;
-		}
-	case nv_clk_src_shader:
-		P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16;
-		switch (mast & 0x00000030) {
-		case 0x00000000:
-			if (mast & 0x00000040)
-				return clk->read(clk, nv_clk_src_href) >> P;
-			return clk->read(clk, nv_clk_src_crystal) >> P;
-		case 0x00000010: break;
-		case 0x00000020: return read_pll(clk, 0x004028) >> P;
-		case 0x00000030: return read_pll(clk, 0x004020) >> P;
-		}
-		break;
-	case nv_clk_src_mem:
-		return 0;
-		break;
-	case nv_clk_src_vdec:
-		P = (read_div(clk) & 0x00000700) >> 8;
-
-		switch (mast & 0x00400000) {
-		case 0x00400000:
-			return clk->read(clk, nv_clk_src_core) >> P;
-			break;
-		default:
-			return 500000 >> P;
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-
-	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
-	return 0;
-}
-
-static u32
-calc_pll(struct nvaa_clock_priv *priv, u32 reg,
-	 u32 clock, int *N, int *M, int *P)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll pll;
-	struct nouveau_clock *clk = &priv->base;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, reg, &pll);
-	if (ret)
-		return 0;
-
-	pll.vco2.max_freq = 0;
-	pll.refclk = clk->read(clk, nv_clk_src_href);
-	if (!pll.refclk)
-		return 0;
-
-	return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P);
-}
-
-static inline u32
-calc_P(u32 src, u32 target, int *div)
-{
-	u32 clk0 = src, clk1 = src;
-	for (*div = 0; *div <= 7; (*div)++) {
-		if (clk0 <= target) {
-			clk1 = clk0 << (*div ? 1 : 0);
-			break;
-		}
-		clk0 >>= 1;
-	}
-
-	if (target - clk0 <= clk1 - target)
-		return clk0;
-	(*div)--;
-	return clk1;
-}
-
-static int
-nvaa_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nvaa_clock_priv *priv = (void *)clk;
-	const int shader = cstate->domain[nv_clk_src_shader];
-	const int core = cstate->domain[nv_clk_src_core];
-	const int vdec = cstate->domain[nv_clk_src_vdec];
-	u32 out = 0, clock = 0;
-	int N, M, P1, P2 = 0;
-	int divs = 0;
-
-	/* cclk: find suitable source, disable PLL if we can */
-	if (core < clk->read(clk, nv_clk_src_hclkm4))
-		out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs);
-
-	/* Calculate clock * 2, so shader clock can use it too */
-	clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1);
-
-	if (abs(core - out) <=
-	    abs(core - (clock >> 1))) {
-		priv->csrc = nv_clk_src_hclkm4;
-		priv->cctrl = divs << 16;
-	} else {
-		/* NVCTRL is actually used _after_ NVPOST, and after what we
-		 * call NVPLL. To make matters worse, NVPOST is an integer
-		 * divider instead of a right-shift number. */
-		if(P1 > 2) {
-			P2 = P1 - 2;
-			P1 = 2;
-		}
-
-		priv->csrc = nv_clk_src_core;
-		priv->ccoef = (N << 8) | M;
-
-		priv->cctrl = (P2 + 1) << 16;
-		priv->cpost = (1 << P1) << 16;
-	}
-
-	/* sclk: nvpll + divisor, href or spll */
-	out = 0;
-	if (shader == clk->read(clk, nv_clk_src_href)) {
-		priv->ssrc = nv_clk_src_href;
-	} else {
-		clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
-		if (priv->csrc == nv_clk_src_core) {
-			out = calc_P((core << 1), shader, &divs);
-		}
-
-		if (abs(shader - out) <=
-		    abs(shader - clock) &&
-		   (divs + P2) <= 7) {
-			priv->ssrc = nv_clk_src_core;
-			priv->sctrl = (divs + P2) << 16;
-		} else {
-			priv->ssrc = nv_clk_src_shader;
-			priv->scoef = (N << 8) | M;
-			priv->sctrl = P1 << 16;
-		}
-	}
-
-	/* vclk */
-	out = calc_P(core, vdec, &divs);
-	clock = calc_P(500000, vdec, &P1);
-	if(abs(vdec - out) <=
-	   abs(vdec - clock)) {
-		priv->vsrc = nv_clk_src_cclk;
-		priv->vdiv = divs << 16;
-	} else {
-		priv->vsrc = nv_clk_src_vdec;
-		priv->vdiv = P1 << 16;
-	}
-
-	/* Print strategy! */
-	nv_debug(priv, "nvpll: %08x %08x %08x\n",
-			priv->ccoef, priv->cpost, priv->cctrl);
-	nv_debug(priv, " spll: %08x %08x %08x\n",
-			priv->scoef, priv->spost, priv->sctrl);
-	nv_debug(priv, " vdiv: %08x\n", priv->vdiv);
-	if (priv->csrc == nv_clk_src_hclkm4)
-		nv_debug(priv, "core: hrefm4\n");
-	else
-		nv_debug(priv, "core: nvpll\n");
-
-	if (priv->ssrc == nv_clk_src_hclkm4)
-		nv_debug(priv, "shader: hrefm4\n");
-	else if (priv->ssrc == nv_clk_src_core)
-		nv_debug(priv, "shader: nvpll\n");
-	else
-		nv_debug(priv, "shader: spll\n");
-
-	if (priv->vsrc == nv_clk_src_hclkm4)
-		nv_debug(priv, "vdec: 500MHz\n");
-	else
-		nv_debug(priv, "vdec: core\n");
-
-	return 0;
-}
-
-static int
-nvaa_clock_prog(struct nouveau_clock *clk)
-{
-	struct nvaa_clock_priv *priv = (void *)clk;
-	u32 pllmask = 0, mast;
-	unsigned long flags;
-	unsigned long *f = &flags;
-	int ret = 0;
-
-	ret = nva3_clock_pre(clk, f);
-	if (ret)
-		goto out;
-
-	/* First switch to safe clocks: href */
-	mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
-	mast &= ~0x00400e73;
-	mast |= 0x03000000;
-
-	switch (priv->csrc) {
-	case nv_clk_src_hclkm4:
-		nv_mask(clk, 0x4028, 0x00070000, priv->cctrl);
-		mast |= 0x00000002;
-		break;
-	case nv_clk_src_core:
-		nv_wr32(clk, 0x402c, priv->ccoef);
-		nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl);
-		nv_wr32(clk, 0x4040, priv->cpost);
-		pllmask |= (0x3 << 8);
-		mast |= 0x00000003;
-		break;
-	default:
-		nv_warn(priv,"Reclocking failed: unknown core clock\n");
-		goto resume;
-	}
-
-	switch (priv->ssrc) {
-	case nv_clk_src_href:
-		nv_mask(clk, 0x4020, 0x00070000, 0x00000000);
-		/* mast |= 0x00000000; */
-		break;
-	case nv_clk_src_core:
-		nv_mask(clk, 0x4020, 0x00070000, priv->sctrl);
-		mast |= 0x00000020;
-		break;
-	case nv_clk_src_shader:
-		nv_wr32(clk, 0x4024, priv->scoef);
-		nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl);
-		nv_wr32(clk, 0x4070, priv->spost);
-		pllmask |= (0x3 << 12);
-		mast |= 0x00000030;
-		break;
-	default:
-		nv_warn(priv,"Reclocking failed: unknown sclk clock\n");
-		goto resume;
-	}
-
-	if (!nv_wait(clk, 0x004080, pllmask, pllmask)) {
-		nv_warn(priv,"Reclocking failed: unstable PLLs\n");
-		goto resume;
-	}
-
-	switch (priv->vsrc) {
-	case nv_clk_src_cclk:
-		mast |= 0x00400000;
-	default:
-		nv_wr32(clk, 0x4600, priv->vdiv);
-	}
-
-	nv_wr32(clk, 0xc054, mast);
-
-resume:
-	/* Disable some PLLs and dividers when unused */
-	if (priv->csrc != nv_clk_src_core) {
-		nv_wr32(clk, 0x4040, 0x00000000);
-		nv_mask(clk, 0x4028, 0x80000000, 0x00000000);
-	}
-
-	if (priv->ssrc != nv_clk_src_shader) {
-		nv_wr32(clk, 0x4070, 0x00000000);
-		nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
-	}
-
-out:
-	if (ret == -EBUSY)
-		f = NULL;
-
-	nva3_clock_post(clk, f);
-
-	return ret;
-}
-
-static void
-nvaa_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static struct nouveau_clocks
-nvaa_domains[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
-	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
-	{ nv_clk_src_vdec   , 0xff, 0, "vdec", 1000 },
-	{ nv_clk_src_max }
-};
-
-static int
-nvaa_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvaa_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, NULL,
-				   0, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.read = nvaa_clock_read;
-	priv->base.calc = nvaa_clock_calc;
-	priv->base.prog = nvaa_clock_prog;
-	priv->base.tidy = nvaa_clock_tidy;
-	return 0;
-}
-
-struct nouveau_oclass *
-nvaa_clock_oclass = &(struct nouveau_oclass) {
-	.handle = NV_SUBDEV(CLOCK, 0xaa),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvaa_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
deleted file mode 100644
index 1234aba..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-
-#include "pll.h"
-
-struct nvc0_clock_info {
-	u32 freq;
-	u32 ssel;
-	u32 mdiv;
-	u32 dsrc;
-	u32 ddiv;
-	u32 coef;
-};
-
-struct nvc0_clock_priv {
-	struct nouveau_clock base;
-	struct nvc0_clock_info eng[16];
-};
-
-static u32 read_div(struct nvc0_clock_priv *, int, u32, u32);
-
-static u32
-read_vco(struct nvc0_clock_priv *priv, u32 dsrc)
-{
-	struct nouveau_clock *clk = &priv->base;
-	u32 ssrc = nv_rd32(priv, dsrc);
-	if (!(ssrc & 0x00000100))
-		return clk->read(clk, nv_clk_src_sppll0);
-	return clk->read(clk, nv_clk_src_sppll1);
-}
-
-static u32
-read_pll(struct nvc0_clock_priv *priv, u32 pll)
-{
-	struct nouveau_clock *clk = &priv->base;
-	u32 ctrl = nv_rd32(priv, pll + 0x00);
-	u32 coef = nv_rd32(priv, pll + 0x04);
-	u32 P = (coef & 0x003f0000) >> 16;
-	u32 N = (coef & 0x0000ff00) >> 8;
-	u32 M = (coef & 0x000000ff) >> 0;
-	u32 sclk;
-
-	if (!(ctrl & 0x00000001))
-		return 0;
-
-	switch (pll) {
-	case 0x00e800:
-	case 0x00e820:
-		sclk = nv_device(priv)->crystal;
-		P = 1;
-		break;
-	case 0x132000:
-		sclk = clk->read(clk, nv_clk_src_mpllsrc);
-		break;
-	case 0x132020:
-		sclk = clk->read(clk, nv_clk_src_mpllsrcref);
-		break;
-	case 0x137000:
-	case 0x137020:
-	case 0x137040:
-	case 0x1370e0:
-		sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
-		break;
-	default:
-		return 0;
-	}
-
-	return sclk * N / M / P;
-}
-
-static u32
-read_div(struct nvc0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
-{
-	u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
-	u32 sctl = nv_rd32(priv, dctl + (doff * 4));
-
-	switch (ssrc & 0x00000003) {
-	case 0:
-		if ((ssrc & 0x00030000) != 0x00030000)
-			return nv_device(priv)->crystal;
-		return 108000;
-	case 2:
-		return 100000;
-	case 3:
-		if (sctl & 0x80000000) {
-			u32 sclk = read_vco(priv, dsrc + (doff * 4));
-			u32 sdiv = (sctl & 0x0000003f) + 2;
-			return (sclk * 2) / sdiv;
-		}
-
-		return read_vco(priv, dsrc + (doff * 4));
-	default:
-		return 0;
-	}
-}
-
-static u32
-read_clk(struct nvc0_clock_priv *priv, int clk)
-{
-	u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
-	u32 ssel = nv_rd32(priv, 0x137100);
-	u32 sclk, sdiv;
-
-	if (ssel & (1 << clk)) {
-		if (clk < 7)
-			sclk = read_pll(priv, 0x137000 + (clk * 0x20));
-		else
-			sclk = read_pll(priv, 0x1370e0);
-		sdiv = ((sctl & 0x00003f00) >> 8) + 2;
-	} else {
-		sclk = read_div(priv, clk, 0x137160, 0x1371d0);
-		sdiv = ((sctl & 0x0000003f) >> 0) + 2;
-	}
-
-	if (sctl & 0x80000000)
-		return (sclk * 2) / sdiv;
-
-	return sclk;
-}
-
-static int
-nvc0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nouveau_device *device = nv_device(clk);
-	struct nvc0_clock_priv *priv = (void *)clk;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return device->crystal;
-	case nv_clk_src_href:
-		return 100000;
-	case nv_clk_src_sppll0:
-		return read_pll(priv, 0x00e800);
-	case nv_clk_src_sppll1:
-		return read_pll(priv, 0x00e820);
-
-	case nv_clk_src_mpllsrcref:
-		return read_div(priv, 0, 0x137320, 0x137330);
-	case nv_clk_src_mpllsrc:
-		return read_pll(priv, 0x132020);
-	case nv_clk_src_mpll:
-		return read_pll(priv, 0x132000);
-	case nv_clk_src_mdiv:
-		return read_div(priv, 0, 0x137300, 0x137310);
-	case nv_clk_src_mem:
-		if (nv_rd32(priv, 0x1373f0) & 0x00000002)
-			return clk->read(clk, nv_clk_src_mpll);
-		return clk->read(clk, nv_clk_src_mdiv);
-
-	case nv_clk_src_gpc:
-		return read_clk(priv, 0x00);
-	case nv_clk_src_rop:
-		return read_clk(priv, 0x01);
-	case nv_clk_src_hubk07:
-		return read_clk(priv, 0x02);
-	case nv_clk_src_hubk06:
-		return read_clk(priv, 0x07);
-	case nv_clk_src_hubk01:
-		return read_clk(priv, 0x08);
-	case nv_clk_src_copy:
-		return read_clk(priv, 0x09);
-	case nv_clk_src_daemon:
-		return read_clk(priv, 0x0c);
-	case nv_clk_src_vdec:
-		return read_clk(priv, 0x0e);
-	default:
-		nv_error(clk, "invalid clock source %d\n", src);
-		return -EINVAL;
-	}
-}
-
-static u32
-calc_div(struct nvc0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
-{
-	u32 div = min((ref * 2) / freq, (u32)65);
-	if (div < 2)
-		div = 2;
-
-	*ddiv = div - 2;
-	return (ref * 2) / div;
-}
-
-static u32
-calc_src(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
-{
-	u32 sclk;
-
-	/* use one of the fixed frequencies if possible */
-	*ddiv = 0x00000000;
-	switch (freq) {
-	case  27000:
-	case 108000:
-		*dsrc = 0x00000000;
-		if (freq == 108000)
-			*dsrc |= 0x00030000;
-		return freq;
-	case 100000:
-		*dsrc = 0x00000002;
-		return freq;
-	default:
-		*dsrc = 0x00000003;
-		break;
-	}
-
-	/* otherwise, calculate the closest divider */
-	sclk = read_vco(priv, 0x137160 + (clk * 4));
-	if (clk < 7)
-		sclk = calc_div(priv, clk, sclk, freq, ddiv);
-	return sclk;
-}
-
-static u32
-calc_pll(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *coef)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll limits;
-	int N, M, P, ret;
-
-	ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
-	if (ret)
-		return 0;
-
-	limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
-	if (!limits.refclk)
-		return 0;
-
-	ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
-	if (ret <= 0)
-		return 0;
-
-	*coef = (P << 16) | (N << 8) | M;
-	return ret;
-}
-
-static int
-calc_clk(struct nvc0_clock_priv *priv,
-	 struct nouveau_cstate *cstate, int clk, int dom)
-{
-	struct nvc0_clock_info *info = &priv->eng[clk];
-	u32 freq = cstate->domain[dom];
-	u32 src0, div0, div1D, div1P = 0;
-	u32 clk0, clk1 = 0;
-
-	/* invalid clock domain */
-	if (!freq)
-		return 0;
-
-	/* first possible path, using only dividers */
-	clk0 = calc_src(priv, clk, freq, &src0, &div0);
-	clk0 = calc_div(priv, clk, clk0, freq, &div1D);
-
-	/* see if we can get any closer using PLLs */
-	if (clk0 != freq && (0x00004387 & (1 << clk))) {
-		if (clk <= 7)
-			clk1 = calc_pll(priv, clk, freq, &info->coef);
-		else
-			clk1 = cstate->domain[nv_clk_src_hubk06];
-		clk1 = calc_div(priv, clk, clk1, freq, &div1P);
-	}
-
-	/* select the method which gets closest to target freq */
-	if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
-		info->dsrc = src0;
-		if (div0) {
-			info->ddiv |= 0x80000000;
-			info->ddiv |= div0 << 8;
-			info->ddiv |= div0;
-		}
-		if (div1D) {
-			info->mdiv |= 0x80000000;
-			info->mdiv |= div1D;
-		}
-		info->ssel = info->coef = 0;
-		info->freq = clk0;
-	} else {
-		if (div1P) {
-			info->mdiv |= 0x80000000;
-			info->mdiv |= div1P << 8;
-		}
-		info->ssel = (1 << clk);
-		info->freq = clk1;
-	}
-
-	return 0;
-}
-
-static int
-nvc0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nvc0_clock_priv *priv = (void *)clk;
-	int ret;
-
-	if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
-	    (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
-	    (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
-	    (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
-	    (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
-	    (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) ||
-	    (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
-	    (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
-		return ret;
-
-	return 0;
-}
-
-static void
-nvc0_clock_prog_0(struct nvc0_clock_priv *priv, int clk)
-{
-	struct nvc0_clock_info *info = &priv->eng[clk];
-	if (clk < 7 && !info->ssel) {
-		nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
-		nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
-	}
-}
-
-static void
-nvc0_clock_prog_1(struct nvc0_clock_priv *priv, int clk)
-{
-	nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
-	nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
-}
-
-static void
-nvc0_clock_prog_2(struct nvc0_clock_priv *priv, int clk)
-{
-	struct nvc0_clock_info *info = &priv->eng[clk];
-	const u32 addr = 0x137000 + (clk * 0x20);
-	if (clk <= 7) {
-		nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
-		nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
-		if (info->coef) {
-			nv_wr32(priv, addr + 0x04, info->coef);
-			nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
-			nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
-			nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
-		}
-	}
-}
-
-static void
-nvc0_clock_prog_3(struct nvc0_clock_priv *priv, int clk)
-{
-	struct nvc0_clock_info *info = &priv->eng[clk];
-	if (info->ssel) {
-		nv_mask(priv, 0x137100, (1 << clk), info->ssel);
-		nv_wait(priv, 0x137100, (1 << clk), info->ssel);
-	}
-}
-
-static void
-nvc0_clock_prog_4(struct nvc0_clock_priv *priv, int clk)
-{
-	struct nvc0_clock_info *info = &priv->eng[clk];
-	nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
-}
-
-static int
-nvc0_clock_prog(struct nouveau_clock *clk)
-{
-	struct nvc0_clock_priv *priv = (void *)clk;
-	struct {
-		void (*exec)(struct nvc0_clock_priv *, int);
-	} stage[] = {
-		{ nvc0_clock_prog_0 }, /* div programming */
-		{ nvc0_clock_prog_1 }, /* select div mode */
-		{ nvc0_clock_prog_2 }, /* (maybe) program pll */
-		{ nvc0_clock_prog_3 }, /* (maybe) select pll mode */
-		{ nvc0_clock_prog_4 }, /* final divider */
-	};
-	int i, j;
-
-	for (i = 0; i < ARRAY_SIZE(stage); i++) {
-		for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
-			if (!priv->eng[j].freq)
-				continue;
-			stage[i].exec(priv, j);
-		}
-	}
-
-	return 0;
-}
-
-static void
-nvc0_clock_tidy(struct nouveau_clock *clk)
-{
-	struct nvc0_clock_priv *priv = (void *)clk;
-	memset(priv->eng, 0x00, sizeof(priv->eng));
-}
-
-static struct nouveau_clocks
-nvc0_domain[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_hubk06 , 0x00 },
-	{ nv_clk_src_hubk01 , 0x01 },
-	{ nv_clk_src_copy   , 0x02 },
-	{ nv_clk_src_gpc    , 0x03, 0, "core", 2000 },
-	{ nv_clk_src_rop    , 0x04 },
-	{ nv_clk_src_mem    , 0x05, 0, "memory", 1000 },
-	{ nv_clk_src_vdec   , 0x06 },
-	{ nv_clk_src_daemon , 0x0a },
-	{ nv_clk_src_hubk07 , 0x0b },
-	{ nv_clk_src_max }
-};
-
-static int
-nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvc0_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, NULL, 0,
-				   false, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.read = nvc0_clock_read;
-	priv->base.calc = nvc0_clock_calc;
-	priv->base.prog = nvc0_clock_prog;
-	priv->base.tidy = nvc0_clock_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
deleted file mode 100644
index 7eccad5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-struct nve0_clock_info {
-	u32 freq;
-	u32 ssel;
-	u32 mdiv;
-	u32 dsrc;
-	u32 ddiv;
-	u32 coef;
-};
-
-struct nve0_clock_priv {
-	struct nouveau_clock base;
-	struct nve0_clock_info eng[16];
-};
-
-static u32 read_div(struct nve0_clock_priv *, int, u32, u32);
-static u32 read_pll(struct nve0_clock_priv *, u32);
-
-static u32
-read_vco(struct nve0_clock_priv *priv, u32 dsrc)
-{
-	u32 ssrc = nv_rd32(priv, dsrc);
-	if (!(ssrc & 0x00000100))
-		return read_pll(priv, 0x00e800);
-	return read_pll(priv, 0x00e820);
-}
-
-static u32
-read_pll(struct nve0_clock_priv *priv, u32 pll)
-{
-	u32 ctrl = nv_rd32(priv, pll + 0x00);
-	u32 coef = nv_rd32(priv, pll + 0x04);
-	u32 P = (coef & 0x003f0000) >> 16;
-	u32 N = (coef & 0x0000ff00) >> 8;
-	u32 M = (coef & 0x000000ff) >> 0;
-	u32 sclk;
-	u16 fN = 0xf000;
-
-	if (!(ctrl & 0x00000001))
-		return 0;
-
-	switch (pll) {
-	case 0x00e800:
-	case 0x00e820:
-		sclk = nv_device(priv)->crystal;
-		P = 1;
-		break;
-	case 0x132000:
-		sclk = read_pll(priv, 0x132020);
-		P = (coef & 0x10000000) ? 2 : 1;
-		break;
-	case 0x132020:
-		sclk = read_div(priv, 0, 0x137320, 0x137330);
-		fN   = nv_rd32(priv, pll + 0x10) >> 16;
-		break;
-	case 0x137000:
-	case 0x137020:
-	case 0x137040:
-	case 0x1370e0:
-		sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
-		break;
-	default:
-		return 0;
-	}
-
-	if (P == 0)
-		P = 1;
-
-	sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13);
-	return sclk / (M * P);
-}
-
-static u32
-read_div(struct nve0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
-{
-	u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
-	u32 sctl = nv_rd32(priv, dctl + (doff * 4));
-
-	switch (ssrc & 0x00000003) {
-	case 0:
-		if ((ssrc & 0x00030000) != 0x00030000)
-			return nv_device(priv)->crystal;
-		return 108000;
-	case 2:
-		return 100000;
-	case 3:
-		if (sctl & 0x80000000) {
-			u32 sclk = read_vco(priv, dsrc + (doff * 4));
-			u32 sdiv = (sctl & 0x0000003f) + 2;
-			return (sclk * 2) / sdiv;
-		}
-
-		return read_vco(priv, dsrc + (doff * 4));
-	default:
-		return 0;
-	}
-}
-
-static u32
-read_mem(struct nve0_clock_priv *priv)
-{
-	switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
-	case 1: return read_pll(priv, 0x132020);
-	case 2: return read_pll(priv, 0x132000);
-	default:
-		return 0;
-	}
-}
-
-static u32
-read_clk(struct nve0_clock_priv *priv, int clk)
-{
-	u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
-	u32 sclk, sdiv;
-
-	if (clk < 7) {
-		u32 ssel = nv_rd32(priv, 0x137100);
-		if (ssel & (1 << clk)) {
-			sclk = read_pll(priv, 0x137000 + (clk * 0x20));
-			sdiv = 1;
-		} else {
-			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
-			sdiv = 0;
-		}
-	} else {
-		u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
-		if ((ssrc & 0x00000003) == 0x00000003) {
-			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
-			if (ssrc & 0x00000100) {
-				if (ssrc & 0x40000000)
-					sclk = read_pll(priv, 0x1370e0);
-				sdiv = 1;
-			} else {
-				sdiv = 0;
-			}
-		} else {
-			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
-			sdiv = 0;
-		}
-	}
-
-	if (sctl & 0x80000000) {
-		if (sdiv)
-			sdiv = ((sctl & 0x00003f00) >> 8) + 2;
-		else
-			sdiv = ((sctl & 0x0000003f) >> 0) + 2;
-		return (sclk * 2) / sdiv;
-	}
-
-	return sclk;
-}
-
-static int
-nve0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
-	struct nouveau_device *device = nv_device(clk);
-	struct nve0_clock_priv *priv = (void *)clk;
-
-	switch (src) {
-	case nv_clk_src_crystal:
-		return device->crystal;
-	case nv_clk_src_href:
-		return 100000;
-	case nv_clk_src_mem:
-		return read_mem(priv);
-	case nv_clk_src_gpc:
-		return read_clk(priv, 0x00);
-	case nv_clk_src_rop:
-		return read_clk(priv, 0x01);
-	case nv_clk_src_hubk07:
-		return read_clk(priv, 0x02);
-	case nv_clk_src_hubk06:
-		return read_clk(priv, 0x07);
-	case nv_clk_src_hubk01:
-		return read_clk(priv, 0x08);
-	case nv_clk_src_daemon:
-		return read_clk(priv, 0x0c);
-	case nv_clk_src_vdec:
-		return read_clk(priv, 0x0e);
-	default:
-		nv_error(clk, "invalid clock source %d\n", src);
-		return -EINVAL;
-	}
-}
-
-static u32
-calc_div(struct nve0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
-{
-	u32 div = min((ref * 2) / freq, (u32)65);
-	if (div < 2)
-		div = 2;
-
-	*ddiv = div - 2;
-	return (ref * 2) / div;
-}
-
-static u32
-calc_src(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
-{
-	u32 sclk;
-
-	/* use one of the fixed frequencies if possible */
-	*ddiv = 0x00000000;
-	switch (freq) {
-	case  27000:
-	case 108000:
-		*dsrc = 0x00000000;
-		if (freq == 108000)
-			*dsrc |= 0x00030000;
-		return freq;
-	case 100000:
-		*dsrc = 0x00000002;
-		return freq;
-	default:
-		*dsrc = 0x00000003;
-		break;
-	}
-
-	/* otherwise, calculate the closest divider */
-	sclk = read_vco(priv, 0x137160 + (clk * 4));
-	if (clk < 7)
-		sclk = calc_div(priv, clk, sclk, freq, ddiv);
-	return sclk;
-}
-
-static u32
-calc_pll(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *coef)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll limits;
-	int N, M, P, ret;
-
-	ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
-	if (ret)
-		return 0;
-
-	limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
-	if (!limits.refclk)
-		return 0;
-
-	ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
-	if (ret <= 0)
-		return 0;
-
-	*coef = (P << 16) | (N << 8) | M;
-	return ret;
-}
-
-static int
-calc_clk(struct nve0_clock_priv *priv,
-	 struct nouveau_cstate *cstate, int clk, int dom)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	u32 freq = cstate->domain[dom];
-	u32 src0, div0, div1D, div1P = 0;
-	u32 clk0, clk1 = 0;
-
-	/* invalid clock domain */
-	if (!freq)
-		return 0;
-
-	/* first possible path, using only dividers */
-	clk0 = calc_src(priv, clk, freq, &src0, &div0);
-	clk0 = calc_div(priv, clk, clk0, freq, &div1D);
-
-	/* see if we can get any closer using PLLs */
-	if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
-		if (clk <= 7)
-			clk1 = calc_pll(priv, clk, freq, &info->coef);
-		else
-			clk1 = cstate->domain[nv_clk_src_hubk06];
-		clk1 = calc_div(priv, clk, clk1, freq, &div1P);
-	}
-
-	/* select the method which gets closest to target freq */
-	if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
-		info->dsrc = src0;
-		if (div0) {
-			info->ddiv |= 0x80000000;
-			info->ddiv |= div0;
-		}
-		if (div1D) {
-			info->mdiv |= 0x80000000;
-			info->mdiv |= div1D;
-		}
-		info->ssel = 0;
-		info->freq = clk0;
-	} else {
-		if (div1P) {
-			info->mdiv |= 0x80000000;
-			info->mdiv |= div1P << 8;
-		}
-		info->ssel = (1 << clk);
-		info->dsrc = 0x40000100;
-		info->freq = clk1;
-	}
-
-	return 0;
-}
-
-static int
-nve0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
-	struct nve0_clock_priv *priv = (void *)clk;
-	int ret;
-
-	if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
-	    (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
-	    (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
-	    (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
-	    (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
-	    (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
-	    (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
-		return ret;
-
-	return 0;
-}
-
-static void
-nve0_clock_prog_0(struct nve0_clock_priv *priv, int clk)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	if (!info->ssel) {
-		nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv);
-		nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
-	}
-}
-
-static void
-nve0_clock_prog_1_0(struct nve0_clock_priv *priv, int clk)
-{
-	nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
-	nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
-}
-
-static void
-nve0_clock_prog_1_1(struct nve0_clock_priv *priv, int clk)
-{
-	nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
-}
-
-static void
-nve0_clock_prog_2(struct nve0_clock_priv *priv, int clk)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	const u32 addr = 0x137000 + (clk * 0x20);
-	nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
-	nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
-	if (info->coef) {
-		nv_wr32(priv, addr + 0x04, info->coef);
-		nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
-		nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
-		nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
-	}
-}
-
-static void
-nve0_clock_prog_3(struct nve0_clock_priv *priv, int clk)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	if (info->ssel)
-		nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv);
-	else
-		nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv);
-}
-
-static void
-nve0_clock_prog_4_0(struct nve0_clock_priv *priv, int clk)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	if (info->ssel) {
-		nv_mask(priv, 0x137100, (1 << clk), info->ssel);
-		nv_wait(priv, 0x137100, (1 << clk), info->ssel);
-	}
-}
-
-static void
-nve0_clock_prog_4_1(struct nve0_clock_priv *priv, int clk)
-{
-	struct nve0_clock_info *info = &priv->eng[clk];
-	if (info->ssel) {
-		nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
-		nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
-	}
-}
-
-static int
-nve0_clock_prog(struct nouveau_clock *clk)
-{
-	struct nve0_clock_priv *priv = (void *)clk;
-	struct {
-		u32 mask;
-		void (*exec)(struct nve0_clock_priv *, int);
-	} stage[] = {
-		{ 0x007f, nve0_clock_prog_0   }, /* div programming */
-		{ 0x007f, nve0_clock_prog_1_0 }, /* select div mode */
-		{ 0xff80, nve0_clock_prog_1_1 },
-		{ 0x00ff, nve0_clock_prog_2   }, /* (maybe) program pll */
-		{ 0xff80, nve0_clock_prog_3   }, /* final divider */
-		{ 0x007f, nve0_clock_prog_4_0 }, /* (maybe) select pll mode */
-		{ 0xff80, nve0_clock_prog_4_1 },
-	};
-	int i, j;
-
-	for (i = 0; i < ARRAY_SIZE(stage); i++) {
-		for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
-			if (!(stage[i].mask & (1 << j)))
-				continue;
-			if (!priv->eng[j].freq)
-				continue;
-			stage[i].exec(priv, j);
-		}
-	}
-
-	return 0;
-}
-
-static void
-nve0_clock_tidy(struct nouveau_clock *clk)
-{
-	struct nve0_clock_priv *priv = (void *)clk;
-	memset(priv->eng, 0x00, sizeof(priv->eng));
-}
-
-static struct nouveau_clocks
-nve0_domain[] = {
-	{ nv_clk_src_crystal, 0xff },
-	{ nv_clk_src_href   , 0xff },
-	{ nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
-	{ nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
-	{ nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
-	{ nv_clk_src_mem    , 0x03, 0, "memory", 500 },
-	{ nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
-	{ nv_clk_src_hubk01 , 0x05 },
-	{ nv_clk_src_vdec   , 0x06 },
-	{ nv_clk_src_daemon , 0x07 },
-	{ nv_clk_src_max }
-};
-
-static int
-nve0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nve0_clock_priv *priv;
-	int ret;
-
-	ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, NULL, 0,
-				   true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.read = nve0_clock_read;
-	priv->base.calc = nve0_clock_calc;
-	priv->base.prog = nve0_clock_prog;
-	priv->base.tidy = nve0_clock_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_clock_oclass = {
-	.handle = NV_SUBDEV(CLOCK, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_clock_ctor,
-		.dtor = _nouveau_clock_dtor,
-		.init = _nouveau_clock_init,
-		.fini = _nouveau_clock_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
deleted file mode 100644
index 445b14c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_PLL_H__
-#define __NOUVEAU_PLL_H__
-
-int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
-		  int *N1, int *M1, int *N2, int *M2, int *P);
-int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
-		  int *N, int *fN, int *M, int *P);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
deleted file mode 100644
index b47d543..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 1993-2003 NVIDIA, Corporation
- * Copyright 2007-2009 Stuart Bennett
- *
- * 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 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 <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-static int
-getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
-	      int *pN, int *pM, int *pP)
-{
-	/* Find M, N and P for a single stage PLL
-	 *
-	 * Note that some bioses (NV3x) have lookup tables of precomputed MNP
-	 * values, but we're too lazy to use those atm
-	 *
-	 * "clk" parameter in kHz
-	 * returns calculated clock
-	 */
-	struct nouveau_bios *bios = nouveau_bios(subdev);
-	int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
-	int minM = info->vco1.min_m, maxM = info->vco1.max_m;
-	int minN = info->vco1.min_n, maxN = info->vco1.max_n;
-	int minU = info->vco1.min_inputfreq;
-	int maxU = info->vco1.max_inputfreq;
-	int minP = info->min_p;
-	int maxP = info->max_p_usable;
-	int crystal = info->refclk;
-	int M, N, thisP, P;
-	int clkP, calcclk;
-	int delta, bestdelta = INT_MAX;
-	int bestclk = 0;
-
-	/* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
-	/* possibly correlated with introduction of 27MHz crystal */
-	if (bios->version.major < 0x60) {
-		int cv = bios->version.chip;
-		if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
-			if (clk > 250000)
-				maxM = 6;
-			if (clk > 340000)
-				maxM = 2;
-		} else if (cv < 0x40) {
-			if (clk > 150000)
-				maxM = 6;
-			if (clk > 200000)
-				maxM = 4;
-			if (clk > 340000)
-				maxM = 2;
-		}
-	}
-
-	P = 1 << maxP;
-	if ((clk * P) < minvco) {
-		minvco = clk * maxP;
-		maxvco = minvco * 2;
-	}
-
-	if (clk + clk/200 > maxvco)	/* +0.5% */
-		maxvco = clk + clk/200;
-
-	/* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
-	for (thisP = minP; thisP <= maxP; thisP++) {
-		P = 1 << thisP;
-		clkP = clk * P;
-
-		if (clkP < minvco)
-			continue;
-		if (clkP > maxvco)
-			return bestclk;
-
-		for (M = minM; M <= maxM; M++) {
-			if (crystal/M < minU)
-				return bestclk;
-			if (crystal/M > maxU)
-				continue;
-
-			/* add crystal/2 to round better */
-			N = (clkP * M + crystal/2) / crystal;
-
-			if (N < minN)
-				continue;
-			if (N > maxN)
-				break;
-
-			/* more rounding additions */
-			calcclk = ((N * crystal + P/2) / P + M/2) / M;
-			delta = abs(calcclk - clk);
-			/* we do an exhaustive search rather than terminating
-			 * on an optimality condition...
-			 */
-			if (delta < bestdelta) {
-				bestdelta = delta;
-				bestclk = calcclk;
-				*pN = N;
-				*pM = M;
-				*pP = thisP;
-				if (delta == 0)	/* except this one */
-					return bestclk;
-			}
-		}
-	}
-
-	return bestclk;
-}
-
-static int
-getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
-	      int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
-{
-	/* Find M, N and P for a two stage PLL
-	 *
-	 * Note that some bioses (NV30+) have lookup tables of precomputed MNP
-	 * values, but we're too lazy to use those atm
-	 *
-	 * "clk" parameter in kHz
-	 * returns calculated clock
-	 */
-	int chip_version = nouveau_bios(subdev)->version.chip;
-	int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
-	int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
-	int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
-	int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
-	int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
-	int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
-	int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
-	int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;
-	int maxlog2P = info->max_p_usable;
-	int crystal = info->refclk;
-	bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
-	int M1, N1, M2, N2, log2P;
-	int clkP, calcclk1, calcclk2, calcclkout;
-	int delta, bestdelta = INT_MAX;
-	int bestclk = 0;
-
-	int vco2 = (maxvco2 - maxvco2/200) / 2;
-	for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
-		;
-	clkP = clk << log2P;
-
-	if (maxvco2 < clk + clk/200)	/* +0.5% */
-		maxvco2 = clk + clk/200;
-
-	for (M1 = minM1; M1 <= maxM1; M1++) {
-		if (crystal/M1 < minU1)
-			return bestclk;
-		if (crystal/M1 > maxU1)
-			continue;
-
-		for (N1 = minN1; N1 <= maxN1; N1++) {
-			calcclk1 = crystal * N1 / M1;
-			if (calcclk1 < minvco1)
-				continue;
-			if (calcclk1 > maxvco1)
-				break;
-
-			for (M2 = minM2; M2 <= maxM2; M2++) {
-				if (calcclk1/M2 < minU2)
-					break;
-				if (calcclk1/M2 > maxU2)
-					continue;
-
-				/* add calcclk1/2 to round better */
-				N2 = (clkP * M2 + calcclk1/2) / calcclk1;
-				if (N2 < minN2)
-					continue;
-				if (N2 > maxN2)
-					break;
-
-				if (!fixedgain2) {
-					if (chip_version < 0x60)
-						if (N2/M2 < 4 || N2/M2 > 10)
-							continue;
-
-					calcclk2 = calcclk1 * N2 / M2;
-					if (calcclk2 < minvco2)
-						break;
-					if (calcclk2 > maxvco2)
-						continue;
-				} else
-					calcclk2 = calcclk1;
-
-				calcclkout = calcclk2 >> log2P;
-				delta = abs(calcclkout - clk);
-				/* we do an exhaustive search rather than terminating
-				 * on an optimality condition...
-				 */
-				if (delta < bestdelta) {
-					bestdelta = delta;
-					bestclk = calcclkout;
-					*pN1 = N1;
-					*pM1 = M1;
-					*pN2 = N2;
-					*pM2 = M2;
-					*pP = log2P;
-					if (delta == 0)	/* except this one */
-						return bestclk;
-				}
-			}
-		}
-	}
-
-	return bestclk;
-}
-
-int
-nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq,
-	      int *N1, int *M1, int *N2, int *M2, int *P)
-{
-	int ret;
-
-	if (!info->vco2.max_freq || !N2) {
-		ret = getMNP_single(subdev, info, freq, N1, M1, P);
-		if (N2) {
-			*N2 = 1;
-			*M2 = 1;
-		}
-	} else {
-		ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
-	}
-
-	if (!ret)
-		nv_error(subdev, "unable to compute acceptable pll values\n");
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
deleted file mode 100644
index 8eca457..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-int
-nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info,
-	      u32 freq, int *pN, int *pfN, int *pM, int *P)
-{
-	u32 best_err = ~0, err;
-	int M, lM, hM, N, fN;
-
-	*P = info->vco1.max_freq / freq;
-	if (*P > info->max_p)
-		*P = info->max_p;
-	if (*P < info->min_p)
-		*P = info->min_p;
-
-	lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq;
-	lM = max(lM, (int)info->vco1.min_m);
-	hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq;
-	hM = min(hM, (int)info->vco1.max_m);
-	lM = min(lM, hM);
-
-	for (M = lM; M <= hM; M++) {
-		u32 tmp = freq * *P * M;
-		N  = tmp / info->refclk;
-		fN = tmp % info->refclk;
-
-		if (!pfN) {
-			if (fN >= info->refclk / 2)
-				N++;
-		} else {
-			if (fN <  info->refclk / 2)
-				N--;
-			fN = tmp - (N * info->refclk);
-		}
-
-		if (N < info->vco1.min_n)
-			continue;
-		if (N > info->vco1.max_n)
-			break;
-
-		err = abs(freq - (info->refclk * N / M / *P));
-		if (err < best_err) {
-			best_err = err;
-			*pN = N;
-			*pM = M;
-		}
-
-		if (pfN) {
-			*pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
-			*pfN = (*pfN - 4096) & 0xffff;
-			return freq;
-		}
-	}
-
-	if (unlikely(best_err == ~0)) {
-		nv_error(subdev, "unable to find matching pll values\n");
-		return -EINVAL;
-	}
-
-	return info->refclk * *pN / *pM / *P;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h b/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h
deleted file mode 100644
index fb33f06..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_CLK_SEQ_H__
-#define __NVKM_CLK_SEQ_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-
-#define clk_init(s,p)       hwsq_init(&(s)->base, (p))
-#define clk_exec(s,e)       hwsq_exec(&(s)->base, (e))
-#define clk_have(s,r)       ((s)->r_##r.addr != 0x000000)
-#define clk_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
-#define clk_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
-#define clk_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define clk_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
-#define clk_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
-#define clk_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
deleted file mode 100644
index 0e45cee..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-int
-_nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_devinit *devinit = (void *)object;
-
-	/* force full reinit on resume */
-	if (suspend)
-		devinit->post = true;
-
-	/* unlock the extended vga crtc regs */
-	nv_lockvgac(devinit, false);
-
-	return nouveau_subdev_fini(&devinit->base, suspend);
-}
-
-int
-_nouveau_devinit_init(struct nouveau_object *object)
-{
-	struct nouveau_devinit_impl *impl = (void *)object->oclass;
-	struct nouveau_devinit *devinit = (void *)object;
-	int ret;
-
-	ret = nouveau_subdev_init(&devinit->base);
-	if (ret)
-		return ret;
-
-	ret = impl->post(&devinit->base, devinit->post);
-	if (ret)
-		return ret;
-
-	if (impl->disable)
-		nv_device(devinit)->disable_mask |= impl->disable(devinit);
-	return 0;
-}
-
-void
-_nouveau_devinit_dtor(struct nouveau_object *object)
-{
-	struct nouveau_devinit *devinit = (void *)object;
-
-	/* lock crtc regs */
-	nv_lockvgac(devinit, true);
-
-	nouveau_subdev_destroy(&devinit->base);
-}
-
-int
-nouveau_devinit_create_(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass,
-			int size, void **pobject)
-{
-	struct nouveau_devinit_impl *impl = (void *)oclass;
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_devinit *devinit;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "DEVINIT",
-				     "init", size, pobject);
-	devinit = *pobject;
-	if (ret)
-		return ret;
-
-	devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false);
-	devinit->meminit = impl->meminit;
-	devinit->pll_set = impl->pll_set;
-	devinit->mmio    = impl->mmio;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
deleted file mode 100644
index 6103484f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include <core/device.h>
-
-#include <subdev/fb/regsnv04.h>
-
-#define NV04_PFB_DEBUG_0					0x00100080
-#	define NV04_PFB_DEBUG_0_PAGE_MODE			0x00000001
-#	define NV04_PFB_DEBUG_0_REFRESH_OFF			0x00000010
-#	define NV04_PFB_DEBUG_0_REFRESH_COUNTX64		0x00003f00
-#	define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK		0x00004000
-#	define NV04_PFB_DEBUG_0_SAFE_MODE			0x00008000
-#	define NV04_PFB_DEBUG_0_ALOM_ENABLE			0x00010000
-#	define NV04_PFB_DEBUG_0_CASOE				0x00100000
-#	define NV04_PFB_DEBUG_0_CKE_INVERT			0x10000000
-#	define NV04_PFB_DEBUG_0_REFINC				0x20000000
-#	define NV04_PFB_DEBUG_0_SAVE_POWER_OFF			0x40000000
-#define NV04_PFB_CFG0						0x00100200
-#	define NV04_PFB_CFG0_SCRAMBLE				0x20000000
-#define NV04_PFB_CFG1						0x00100204
-#define NV04_PFB_SCRAMBLE(i)                         (0x00100400 + 4 * (i))
-
-#define NV10_PFB_REFCTRL					0x00100210
-#	define NV10_PFB_REFCTRL_VALID_1				(1 << 31)
-
-static inline struct io_mapping *
-fbmem_init(struct nouveau_device *dev)
-{
-	return io_mapping_create_wc(nv_device_resource_start(dev, 1),
-				    nv_device_resource_len(dev, 1));
-}
-
-static inline void
-fbmem_fini(struct io_mapping *fb)
-{
-	io_mapping_free(fb);
-}
-
-static inline u32
-fbmem_peek(struct io_mapping *fb, u32 off)
-{
-	u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
-	u32 val = ioread32(p + (off & ~PAGE_MASK));
-	io_mapping_unmap_atomic(p);
-	return val;
-}
-
-static inline void
-fbmem_poke(struct io_mapping *fb, u32 off, u32 val)
-{
-	u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
-	iowrite32(val, p + (off & ~PAGE_MASK));
-	wmb();
-	io_mapping_unmap_atomic(p);
-}
-
-static inline bool
-fbmem_readback(struct io_mapping *fb, u32 off, u32 val)
-{
-	fbmem_poke(fb, off, val);
-	return val == fbmem_peek(fb, off);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
deleted file mode 100644
index 4ba43d6..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-u64
-gm107_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r021c00 = nv_rd32(priv, 0x021c00);
-	u32 r021c04 = nv_rd32(priv, 0x021c04);
-	u64 disable = 0ULL;
-
-	if (r021c00 & 0x00000001)
-		disable |= (1ULL << NVDEV_ENGINE_COPY0);
-	if (r021c00 & 0x00000004)
-		disable |= (1ULL << NVDEV_ENGINE_COPY2);
-	if (r021c04 & 0x00000001)
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-
-	return disable;
-}
-
-struct nouveau_oclass *
-gm107_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x07),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nvc0_devinit_pll_set,
-	.disable = gm107_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c
deleted file mode 100644
index e44a866..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pmu.h>
-
-#include "nv50.h"
-
-static void
-pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	int i;
-
-	nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
-	for (i = 0; i < len; i += 4) {
-		if ((i & 0xff) == 0)
-			nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
-		nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
-	}
-
-	while (i & 0xff) {
-		nv_wr32(priv, 0x10a184, 0x00000000);
-		i += 4;
-	}
-}
-
-static void
-pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	int i;
-
-	nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
-	for (i = 0; i < len; i += 4)
-		nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
-}
-
-static u32
-pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
-{
-	nv_wr32(priv, 0x10a1c0, argp);
-	nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
-	return nv_rd32(priv, 0x10a1c4);
-}
-
-static void
-pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
-{
-	nv_wr32(priv, 0x10a104, init_addr);
-	nv_wr32(priv, 0x10a10c, 0x00000000);
-	nv_wr32(priv, 0x10a100, 0x00000002);
-}
-
-static int
-pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
-	 u32 *init_addr_pmu, u32 *args_addr_pmu)
-{
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pmuR pmu;
-
-	if (!nvbios_pmuRm(bios, type, &pmu)) {
-		nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
-		return -EINVAL;
-	}
-
-	if (!post)
-		return 0;
-
-	pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
-	pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
-	pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
-
-	if (init_addr_pmu) {
-		*init_addr_pmu = pmu.init_addr_pmu;
-		*args_addr_pmu = pmu.args_addr_pmu;
-		return 0;
-	}
-
-	return pmu_exec(priv, pmu.init_addr_pmu), 0;
-}
-
-static int
-gm204_devinit_post(struct nouveau_subdev *subdev, bool post)
-{
-	struct nv50_devinit_priv *priv = (void *)nouveau_devinit(subdev);
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct bit_entry bit_I;
-	u32 init, args;
-	int ret;
-
-	if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
-					    bit_I.length < 0x1c) {
-		nv_error(priv, "VBIOS PMU init data not found\n");
-		return -EINVAL;
-	}
-
-	/* reset PMU and load init table parser ucode */
-	if (post) {
-		nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
-		nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
-		nv_rd32(priv, 0x000200);
-		while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
-		}
-	}
-
-	ret = pmu_load(priv, 0x04, post, &init, &args);
-	if (ret)
-		return ret;
-
-	/* upload first chunk of init data */
-	if (post) {
-		u32 pmu = pmu_args(priv, args + 0x08, 0x08);
-		u32 img = nv_ro16(bios, bit_I.offset + 0x14);
-		u32 len = nv_ro16(bios, bit_I.offset + 0x16);
-		pmu_data(priv, pmu, img, len);
-	}
-
-	/* upload second chunk of init data */
-	if (post) {
-		u32 pmu = pmu_args(priv, args + 0x08, 0x10);
-		u32 img = nv_ro16(bios, bit_I.offset + 0x18);
-		u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
-		pmu_data(priv, pmu, img, len);
-	}
-
-	/* execute init tables */
-	if (post) {
-		nv_wr32(priv, 0x10a040, 0x00005000);
-		pmu_exec(priv, init);
-		while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
-		}
-	}
-
-	/* load and execute some other ucode image (bios therm?) */
-	return pmu_load(priv, 0x01, post, NULL, NULL);
-}
-
-struct nouveau_oclass *
-gm204_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x07),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nvc0_devinit_pll_set,
-	.disable = gm107_devinit_disable,
-	.post = gm204_devinit_post,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
deleted file mode 100644
index 65651c5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv04_devinit_meminit(struct nouveau_devinit *devinit)
-{
-	struct nv04_devinit_priv *priv = (void *)devinit;
-	u32 patt = 0xdeadbeef;
-	struct io_mapping *fb;
-	int i;
-
-	/* Map the framebuffer aperture */
-	fb = fbmem_init(nv_device(priv));
-	if (!fb) {
-		nv_error(priv, "failed to map fb\n");
-		return;
-	}
-
-	/* Sequencer and refresh off */
-	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
-	nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
-
-	nv_mask(priv, NV04_PFB_BOOT_0, ~0,
-		      NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
-		      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-		      NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
-
-	for (i = 0; i < 4; i++)
-		fbmem_poke(fb, 4 * i, patt);
-
-	fbmem_poke(fb, 0x400000, patt + 1);
-
-	if (fbmem_peek(fb, 0) == patt + 1) {
-		nv_mask(priv, NV04_PFB_BOOT_0,
-			      NV04_PFB_BOOT_0_RAM_TYPE,
-			      NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
-		nv_mask(priv, NV04_PFB_DEBUG_0,
-			      NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-
-		for (i = 0; i < 4; i++)
-			fbmem_poke(fb, 4 * i, patt);
-
-		if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff))
-			nv_mask(priv, NV04_PFB_BOOT_0,
-				      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-				      NV04_PFB_BOOT_0_RAM_AMOUNT,
-				      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-	} else
-	if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) {
-		nv_mask(priv, NV04_PFB_BOOT_0,
-			      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
-			      NV04_PFB_BOOT_0_RAM_AMOUNT,
-			      NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-	} else
-	if (fbmem_peek(fb, 0) != patt) {
-		if (fbmem_readback(fb, 0x800000, patt))
-			nv_mask(priv, NV04_PFB_BOOT_0,
-				      NV04_PFB_BOOT_0_RAM_AMOUNT,
-				      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-		else
-			nv_mask(priv, NV04_PFB_BOOT_0,
-				      NV04_PFB_BOOT_0_RAM_AMOUNT,
-				      NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-
-		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
-			      NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
-	} else
-	if (!fbmem_readback(fb, 0x800000, patt)) {
-		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-			      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-
-	}
-
-	/* Refresh on, sequencer on */
-	nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
-	fbmem_fini(fb);
-}
-
-static int
-powerctrl_1_shift(int chip_version, int reg)
-{
-	int shift = -4;
-
-	if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
-		return shift;
-
-	switch (reg) {
-	case 0x680520:
-		shift += 4;
-	case 0x680508:
-		shift += 4;
-	case 0x680504:
-		shift += 4;
-	case 0x680500:
-		shift += 4;
-	}
-
-	/*
-	 * the shift for vpll regs is only used for nv3x chips with a single
-	 * stage pll
-	 */
-	if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
-			  chip_version == 0x36 || chip_version >= 0x40))
-		shift = -4;
-
-	return shift;
-}
-
-void
-setPLL_single(struct nouveau_devinit *devinit, u32 reg,
-	      struct nouveau_pll_vals *pv)
-{
-	int chip_version = nouveau_bios(devinit)->version.chip;
-	uint32_t oldpll = nv_rd32(devinit, reg);
-	int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
-	uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-	uint32_t saved_powerctrl_1 = 0;
-	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
-
-	if (oldpll == pll)
-		return;	/* already set */
-
-	if (shift_powerctrl_1 >= 0) {
-		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
-		nv_wr32(devinit, 0x001584,
-			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-			1 << shift_powerctrl_1);
-	}
-
-	if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
-		/* upclock -- write new post divider first */
-		nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
-	else
-		/* downclock -- write new NM first */
-		nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
-
-	if ((chip_version < 0x17 || chip_version == 0x1a) &&
-	    chip_version != 0x11)
-		/* wait a bit on older chips */
-		msleep(64);
-	nv_rd32(devinit, reg);
-
-	/* then write the other half as well */
-	nv_wr32(devinit, reg, pll);
-
-	if (shift_powerctrl_1 >= 0)
-		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
-}
-
-static uint32_t
-new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
-{
-	bool head_a = (reg1 == 0x680508);
-
-	if (ss)	/* single stage pll mode */
-		ramdac580 |= head_a ? 0x00000100 : 0x10000000;
-	else
-		ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
-
-	return ramdac580;
-}
-
-void
-setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1,
-		       struct nouveau_pll_vals *pv)
-{
-	int chip_version = nouveau_bios(devinit)->version.chip;
-	bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
-	uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
-	uint32_t oldpll1 = nv_rd32(devinit, reg1);
-	uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
-	uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-	uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
-	uint32_t oldramdac580 = 0, ramdac580 = 0;
-	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;	/* nv41+ only */
-	uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
-	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
-
-	/* model specific additions to generic pll1 and pll2 set up above */
-	if (nv3035) {
-		pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
-		       (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
-		pll2 = 0;
-	}
-	if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
-		oldramdac580 = nv_rd32(devinit, 0x680580);
-		ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
-		if (oldramdac580 != ramdac580)
-			oldpll1 = ~0;	/* force mismatch */
-		if (single_stage)
-			/* magic value used by nvidia in single stage mode */
-			pll2 |= 0x011f;
-	}
-	if (chip_version > 0x70)
-		/* magic bits set by the blob (but not the bios) on g71-73 */
-		pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
-
-	if (oldpll1 == pll1 && oldpll2 == pll2)
-		return;	/* already set */
-
-	if (shift_powerctrl_1 >= 0) {
-		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
-		nv_wr32(devinit, 0x001584,
-			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-			1 << shift_powerctrl_1);
-	}
-
-	if (chip_version >= 0x40) {
-		int shift_c040 = 14;
-
-		switch (reg1) {
-		case 0x680504:
-			shift_c040 += 2;
-		case 0x680500:
-			shift_c040 += 2;
-		case 0x680520:
-			shift_c040 += 2;
-		case 0x680508:
-			shift_c040 += 2;
-		}
-
-		savedc040 = nv_rd32(devinit, 0xc040);
-		if (shift_c040 != 14)
-			nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
-	}
-
-	if (oldramdac580 != ramdac580)
-		nv_wr32(devinit, 0x680580, ramdac580);
-
-	if (!nv3035)
-		nv_wr32(devinit, reg2, pll2);
-	nv_wr32(devinit, reg1, pll1);
-
-	if (shift_powerctrl_1 >= 0)
-		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
-	if (chip_version >= 0x40)
-		nv_wr32(devinit, 0xc040, savedc040);
-}
-
-void
-setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg,
-		      struct nouveau_pll_vals *pv)
-{
-	/* When setting PLLs, there is a merry game of disabling and enabling
-	 * various bits of hardware during the process. This function is a
-	 * synthesis of six nv4x traces, nearly each card doing a subtly
-	 * different thing. With luck all the necessary bits for each card are
-	 * combined herein. Without luck it deviates from each card's formula
-	 * so as to not work on any :)
-	 */
-
-	uint32_t Preg = NMNMreg - 4;
-	bool mpll = Preg == 0x4020;
-	uint32_t oldPval = nv_rd32(devinit, Preg);
-	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
-	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
-			0xc << 28 | pv->log2P << 16;
-	uint32_t saved4600 = 0;
-	/* some cards have different maskc040s */
-	uint32_t maskc040 = ~(3 << 14), savedc040;
-	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
-
-	if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
-		return;
-
-	if (Preg == 0x4000)
-		maskc040 = ~0x333;
-	if (Preg == 0x4058)
-		maskc040 = ~(0xc << 24);
-
-	if (mpll) {
-		struct nvbios_pll info;
-		uint8_t Pval2;
-
-		if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info))
-			return;
-
-		Pval2 = pv->log2P + info.bias_p;
-		if (Pval2 > info.max_p)
-			Pval2 = info.max_p;
-		Pval |= 1 << 28 | Pval2 << 20;
-
-		saved4600 = nv_rd32(devinit, 0x4600);
-		nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
-	}
-	if (single_stage)
-		Pval |= mpll ? 1 << 12 : 1 << 8;
-
-	nv_wr32(devinit, Preg, oldPval | 1 << 28);
-	nv_wr32(devinit, Preg, Pval & ~(4 << 28));
-	if (mpll) {
-		Pval |= 8 << 20;
-		nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
-		nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
-	}
-
-	savedc040 = nv_rd32(devinit, 0xc040);
-	nv_wr32(devinit, 0xc040, savedc040 & maskc040);
-
-	nv_wr32(devinit, NMNMreg, NMNM);
-	if (NMNMreg == 0x4024)
-		nv_wr32(devinit, 0x403c, NMNM);
-
-	nv_wr32(devinit, Preg, Pval);
-	if (mpll) {
-		Pval &= ~(8 << 20);
-		nv_wr32(devinit, 0x4020, Pval);
-		nv_wr32(devinit, 0x4038, Pval);
-		nv_wr32(devinit, 0x4600, saved4600);
-	}
-
-	nv_wr32(devinit, 0xc040, savedc040);
-
-	if (mpll) {
-		nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
-		nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
-	}
-}
-
-int
-nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
-	struct nouveau_bios *bios = nouveau_bios(devinit);
-	struct nouveau_pll_vals pv;
-	struct nvbios_pll info;
-	int cv = bios->version.chip;
-	int N1, M1, N2, M2, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
-	if (ret)
-		return ret;
-
-	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
-			   &N1, &M1, &N2, &M2, &P);
-	if (!ret)
-		return -EINVAL;
-
-	pv.refclk = info.refclk;
-	pv.N1 = N1;
-	pv.M1 = M1;
-	pv.N2 = N2;
-	pv.M2 = M2;
-	pv.log2P = P;
-
-	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
-	    cv >= 0x40) {
-		if (type > 0x405c)
-			setPLL_double_highregs(devinit, type, &pv);
-		else
-			setPLL_double_lowregs(devinit, type, &pv);
-	} else
-		setPLL_single(devinit, type, &pv);
-
-	return 0;
-}
-
-int
-nv04_devinit_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv04_devinit_priv *priv = (void *)object;
-	int ret;
-
-	/* make i2c busses accessible */
-	nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
-
-	ret = nouveau_devinit_fini(&priv->base, suspend);
-	if (ret)
-		return ret;
-
-	/* unslave crtcs */
-	if (priv->owner < 0)
-		priv->owner = nv_rdvgaowner(priv);
-	nv_wrvgaowner(priv, 0);
-
-	return 0;
-}
-
-int
-nv04_devinit_init(struct nouveau_object *object)
-{
-	struct nv04_devinit_priv *priv = (void *)object;
-
-	if (!priv->base.post) {
-		u32 htotal = nv_rdvgac(priv, 0, 0x06);
-		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
-		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
-		htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
-		htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
-		if (!htotal) {
-			nv_info(priv, "adaptor not initialised\n");
-			priv->base.post = true;
-		}
-	}
-
-	return nouveau_devinit_init(&priv->base);
-}
-
-void
-nv04_devinit_dtor(struct nouveau_object *object)
-{
-	struct nv04_devinit_priv *priv = (void *)object;
-
-	/* restore vga owner saved at first init */
-	nv_wrvgaowner(priv, priv->owner);
-
-	nouveau_devinit_destroy(&priv->base);
-}
-
-int
-nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv04_devinit_priv *priv;
-	int ret;
-
-	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->owner = -1;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_devinit_ctor,
-		.dtor = nv04_devinit_dtor,
-		.init = nv04_devinit_init,
-		.fini = nv04_devinit_fini,
-	},
-	.meminit = nv04_devinit_meminit,
-	.pll_set = nv04_devinit_pll_set,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h
deleted file mode 100644
index 23470a5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_DEVINIT_NV04_H__
-#define __NVKM_DEVINIT_NV04_H__
-
-#include "priv.h"
-
-struct nv04_devinit_priv {
-	struct nouveau_devinit base;
-	u8 owner;
-};
-
-int  nv04_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, void *, u32,
-		       struct nouveau_object **);
-void nv04_devinit_dtor(struct nouveau_object *);
-int  nv04_devinit_init(struct nouveau_object *);
-int  nv04_devinit_fini(struct nouveau_object *, bool);
-int  nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
deleted file mode 100644
index a2007a3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv05_devinit_meminit(struct nouveau_devinit *devinit)
-{
-	static const u8 default_config_tab[][2] = {
-		{ 0x24, 0x00 },
-		{ 0x28, 0x00 },
-		{ 0x24, 0x01 },
-		{ 0x1f, 0x00 },
-		{ 0x0f, 0x00 },
-		{ 0x17, 0x00 },
-		{ 0x06, 0x00 },
-		{ 0x00, 0x00 }
-	};
-	struct nv04_devinit_priv *priv = (void *)devinit;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct io_mapping *fb;
-	u32 patt = 0xdeadbeef;
-	u16 data;
-	u8 strap, ramcfg[2];
-	int i, v;
-
-	/* Map the framebuffer aperture */
-	fb = fbmem_init(nv_device(priv));
-	if (!fb) {
-		nv_error(priv, "failed to map fb\n");
-		return;
-	}
-
-	strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2;
-	if ((data = bmp_mem_init_table(bios))) {
-		ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0);
-		ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1);
-	} else {
-		ramcfg[0] = default_config_tab[strap][0];
-		ramcfg[1] = default_config_tab[strap][1];
-	}
-
-	/* Sequencer off */
-	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
-
-	if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
-		goto out;
-
-	nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-
-	/* If present load the hardcoded scrambling table */
-	if (data) {
-		for (i = 0, data += 0x10; i < 8; i++, data += 4) {
-			u32 scramble = nv_ro32(bios, data);
-			nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble);
-		}
-	}
-
-	/* Set memory type/width/length defaults depending on the straps */
-	nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
-
-	if (ramcfg[1] & 0x80)
-		nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
-
-	nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
-	nv_mask(priv, NV04_PFB_CFG1, 0, 1);
-
-	/* Probe memory bus width */
-	for (i = 0; i < 4; i++)
-		fbmem_poke(fb, 4 * i, patt);
-
-	if (fbmem_peek(fb, 0xc) != patt)
-		nv_mask(priv, NV04_PFB_BOOT_0,
-			  NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
-
-	/* Probe memory length */
-	v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
-
-	if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
-	    (!fbmem_readback(fb, 0x1000000, ++patt) ||
-	     !fbmem_readback(fb, 0, ++patt)))
-		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-			  NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
-
-	if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
-	    !fbmem_readback(fb, 0x800000, ++patt))
-		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-			  NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-
-	if (!fbmem_readback(fb, 0x400000, ++patt))
-		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
-			  NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-
-out:
-	/* Sequencer on */
-	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
-	fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv05_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x05),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_devinit_ctor,
-		.dtor = nv04_devinit_dtor,
-		.init = nv04_devinit_init,
-		.fini = nv04_devinit_fini,
-	},
-	.meminit = nv05_devinit_meminit,
-	.pll_set = nv04_devinit_pll_set,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
deleted file mode 100644
index 178b46f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv10_devinit_meminit(struct nouveau_devinit *devinit)
-{
-	struct nv04_devinit_priv *priv = (void *)devinit;
-	static const int mem_width[] = { 0x10, 0x00, 0x20 };
-	int mem_width_count;
-	uint32_t patt = 0xdeadbeef;
-	struct io_mapping *fb;
-	int i, j, k;
-
-	if (nv_device(priv)->card_type >= NV_11 &&
-	    nv_device(priv)->chipset >= 0x17)
-		mem_width_count = 3;
-	else
-		mem_width_count = 2;
-
-	/* Map the framebuffer aperture */
-	fb = fbmem_init(nv_device(priv));
-	if (!fb) {
-		nv_error(priv, "failed to map fb\n");
-		return;
-	}
-
-	nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-
-	/* Probe memory bus width */
-	for (i = 0; i < mem_width_count; i++) {
-		nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]);
-
-		for (j = 0; j < 4; j++) {
-			for (k = 0; k < 4; k++)
-				fbmem_poke(fb, 0x1c, 0);
-
-			fbmem_poke(fb, 0x1c, patt);
-			fbmem_poke(fb, 0x3c, 0);
-
-			if (fbmem_peek(fb, 0x1c) == patt)
-				goto mem_width_found;
-		}
-	}
-
-mem_width_found:
-	patt <<= 1;
-
-	/* Probe amount of installed memory */
-	for (i = 0; i < 4; i++) {
-		int off = nv_rd32(priv, 0x10020c) - 0x100000;
-
-		fbmem_poke(fb, off, patt);
-		fbmem_poke(fb, 0, 0);
-
-		fbmem_peek(fb, 0);
-		fbmem_peek(fb, 0);
-		fbmem_peek(fb, 0);
-		fbmem_peek(fb, 0);
-
-		if (fbmem_peek(fb, off) == patt)
-			goto amount_found;
-	}
-
-	/* IC missing - disable the upper half memory space. */
-	nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0);
-
-amount_found:
-	fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv10_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x10),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_devinit_ctor,
-		.dtor = nv04_devinit_dtor,
-		.init = nv04_devinit_init,
-		.fini = nv04_devinit_fini,
-	},
-	.meminit = nv10_devinit_meminit,
-	.pll_set = nv04_devinit_pll_set,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
deleted file mode 100644
index 995dd97..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv1a_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x1a),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_devinit_ctor,
-		.dtor = nv04_devinit_dtor,
-		.init = nv04_devinit_init,
-		.fini = nv04_devinit_fini,
-	},
-	.pll_set = nv04_devinit_pll_set,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
deleted file mode 100644
index 915089f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-#include "fbmem.h"
-
-static void
-nv20_devinit_meminit(struct nouveau_devinit *devinit)
-{
-	struct nv04_devinit_priv *priv = (void *)devinit;
-	struct nouveau_device *device = nv_device(priv);
-	uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900);
-	uint32_t amount, off;
-	struct io_mapping *fb;
-
-	/* Map the framebuffer aperture */
-	fb = fbmem_init(nv_device(priv));
-	if (!fb) {
-		nv_error(priv, "failed to map fb\n");
-		return;
-	}
-
-	nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-
-	/* Allow full addressing */
-	nv_mask(priv, NV04_PFB_CFG0, 0, mask);
-
-	amount = nv_rd32(priv, 0x10020c);
-	for (off = amount; off > 0x2000000; off -= 0x2000000)
-		fbmem_poke(fb, off - 4, off);
-
-	amount = nv_rd32(priv, 0x10020c);
-	if (amount != fbmem_peek(fb, amount - 4))
-		/* IC missing - disable the upper half memory space. */
-		nv_mask(priv, NV04_PFB_CFG0, mask, 0);
-
-	fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv20_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x20),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_devinit_ctor,
-		.dtor = nv04_devinit_dtor,
-		.init = nv04_devinit_init,
-		.fini = nv04_devinit_fini,
-	},
-	.meminit = nv20_devinit_meminit,
-	.pll_set = nv04_devinit_pll_set,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
deleted file mode 100644
index 968334d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/ibus.h>
-#include <subdev/vga.h>
-
-#include "nv50.h"
-
-int
-nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N1, M1, N2, M2, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret) {
-		nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
-		return ret;
-	}
-
-	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
-	if (!ret) {
-		nv_error(devinit, "failed pll calculation\n");
-		return ret;
-	}
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-		nv_wr32(priv, info.reg + 0, 0x10000611);
-		nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
-		nv_mask(priv, info.reg + 8, 0x7fff00ff, (P  << 28) |
-							(M2 << 16) | N2);
-		break;
-	case PLL_MEMORY:
-		nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
-						        (info.bias_p << 19) |
-							(P << 16));
-		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
-		break;
-	default:
-		nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
-		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
-		break;
-	}
-
-	return 0;
-}
-
-static u64
-nv50_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r001540 = nv_rd32(priv, 0x001540);
-	u64 disable = 0ULL;
-
-	if (!(r001540 & 0x40000000))
-		disable |= (1ULL << NVDEV_ENGINE_MPEG);
-
-	return disable;
-}
-
-int
-nv50_devinit_init(struct nouveau_object *object)
-{
-	struct nouveau_bios *bios = nouveau_bios(object);
-	struct nouveau_ibus *ibus = nouveau_ibus(object);
-	struct nv50_devinit_priv *priv = (void *)object;
-	struct nvbios_outp info;
-	struct dcb_output outp;
-	u8  ver = 0xff, hdr, cnt, len;
-	int ret, i = 0;
-
-	if (!priv->base.post) {
-		if (!nv_rdvgac(priv, 0, 0x00) &&
-		    !nv_rdvgac(priv, 0, 0x1a)) {
-			nv_info(priv, "adaptor not initialised\n");
-			priv->base.post = true;
-		}
-	}
-
-	/* some boards appear to require certain priv register timeouts
-	 * to be bumped before runing devinit scripts.  not a clue why
-	 * the vbios engineers didn't make the scripts just work...
-	 */
-	if (priv->base.post && ibus)
-		nv_ofuncs(ibus)->init(nv_object(ibus));
-
-	ret = nouveau_devinit_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* if we ran the init tables, we have to execute the first script
-	 * pointer of each dcb entry's display encoder table in order
-	 * to properly initialise each encoder.
-	 */
-	while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
-		if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
-				     &ver, &hdr, &cnt, &len, &info)) {
-			struct nvbios_init init = {
-				.subdev = nv_subdev(priv),
-				.bios = bios,
-				.offset = info.script[0],
-				.outp = &outp,
-				.crtc = -1,
-				.execute = 1,
-			};
-
-			nvbios_exec(&init);
-		}
-		i++;
-	}
-
-	return 0;
-}
-
-int
-nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv50_devinit_priv *priv;
-	int ret;
-
-	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nv50_devinit_pll_set,
-	.disable = nv50_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
deleted file mode 100644
index f412bb7..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_DEVINIT_NV50_H__
-#define __NVKM_DEVINIT_NV50_H__
-
-#include "priv.h"
-
-struct nv50_devinit_priv {
-	struct nouveau_devinit base;
-	u32 r001540;
-};
-
-int  nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, void *, u32,
-		       struct nouveau_object **);
-int  nv50_devinit_init(struct nouveau_object *);
-int  nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-int  nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-int  nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-u64  gm107_devinit_disable(struct nouveau_devinit *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
deleted file mode 100644
index a7c80de..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nv84_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r001540 = nv_rd32(priv, 0x001540);
-	u32 r00154c = nv_rd32(priv, 0x00154c);
-	u64 disable = 0ULL;
-
-	if (!(r001540 & 0x40000000)) {
-		disable |= (1ULL << NVDEV_ENGINE_MPEG);
-		disable |= (1ULL << NVDEV_ENGINE_VP);
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-		disable |= (1ULL << NVDEV_ENGINE_CRYPT);
-	}
-
-	if (!(r00154c & 0x00000004))
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-	if (!(r00154c & 0x00000020))
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-	if (!(r00154c & 0x00000040))
-		disable |= (1ULL << NVDEV_ENGINE_CRYPT);
-
-	return disable;
-}
-
-struct nouveau_oclass *
-nv84_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x84),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nv50_devinit_pll_set,
-	.disable = nv84_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
deleted file mode 100644
index a773253..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nv98_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r001540 = nv_rd32(priv, 0x001540);
-	u32 r00154c = nv_rd32(priv, 0x00154c);
-	u64 disable = 0ULL;
-
-	if (!(r001540 & 0x40000000)) {
-		disable |= (1ULL << NVDEV_ENGINE_VP);
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-		disable |= (1ULL << NVDEV_ENGINE_PPP);
-	}
-
-	if (!(r00154c & 0x00000004))
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-	if (!(r00154c & 0x00000020))
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-	if (!(r00154c & 0x00000040))
-		disable |= (1ULL << NVDEV_ENGINE_CRYPT);
-
-	return disable;
-}
-
-struct nouveau_oclass *
-nv98_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0x98),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nv50_devinit_pll_set,
-	.disable = nv98_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
deleted file mode 100644
index b9cd9e5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-int
-nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N, fN, M, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret)
-		return ret;
-
-	ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
-	if (ret < 0)
-		return ret;
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-		nv_wr32(priv, info.reg + 0, 0x50000610);
-		nv_mask(priv, info.reg + 4, 0x003fffff,
-					    (P << 16) | (M << 8) | N);
-		nv_wr32(priv, info.reg + 8, fN);
-		break;
-	default:
-		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static u64
-nva3_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r001540 = nv_rd32(priv, 0x001540);
-	u32 r00154c = nv_rd32(priv, 0x00154c);
-	u64 disable = 0ULL;
-
-	if (!(r001540 & 0x40000000)) {
-		disable |= (1ULL << NVDEV_ENGINE_VP);
-		disable |= (1ULL << NVDEV_ENGINE_PPP);
-	}
-
-	if (!(r00154c & 0x00000004))
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-	if (!(r00154c & 0x00000020))
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-	if (!(r00154c & 0x00000200))
-		disable |= (1ULL << NVDEV_ENGINE_COPY0);
-
-	return disable;
-}
-
-static u32
-nva3_devinit_mmio_part[] = {
-	0x100720, 0x1008bc, 4,
-	0x100a20, 0x100adc, 4,
-	0x100d80, 0x100ddc, 4,
-	0x110000, 0x110f9c, 4,
-	0x111000, 0x11103c, 8,
-	0x111080, 0x1110fc, 4,
-	0x111120, 0x1111fc, 4,
-	0x111300, 0x1114bc, 4,
-	0,
-};
-
-static u32
-nva3_devinit_mmio(struct nouveau_devinit *devinit, u32 addr)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 *mmio = nva3_devinit_mmio_part;
-
-	/* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP
-	 * instructions which touch registers that may not even exist on
-	 * some configurations (Quadro 400), which causes the register
-	 * interface to screw up for some amount of time after attempting to
-	 * write to one of these, and results in all sorts of things going
-	 * horribly wrong.
-	 *
-	 * the binary driver avoids touching these registers at all, however,
-	 * the video bios doesn't care and does what the scripts say.  it's
-	 * presumed that the io-port access to priv registers isn't effected
-	 * by the screw-up bug mentioned above.
-	 *
-	 * really, a new opcode should've been invented to handle these
-	 * requirements, but whatever, it's too late for that now.
-	 */
-	while (mmio[0]) {
-		if (addr >= mmio[0] && addr <= mmio[1]) {
-			u32 part = (addr / mmio[2]) & 7;
-			if (!priv->r001540)
-				priv->r001540 = nv_rd32(priv, 0x001540);
-			if (part >= hweight8((priv->r001540 >> 16) & 0xff))
-				return ~0;
-			return addr;
-		}
-		mmio += 3;
-	}
-
-	return addr;
-}
-
-struct nouveau_oclass *
-nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0xa3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nva3_devinit_pll_set,
-	.disable = nva3_devinit_disable,
-	.mmio    = nva3_devinit_mmio,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
deleted file mode 100644
index 3729846..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nvaf_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r001540 = nv_rd32(priv, 0x001540);
-	u32 r00154c = nv_rd32(priv, 0x00154c);
-	u64 disable = 0;
-
-	if (!(r001540 & 0x40000000)) {
-		disable |= (1ULL << NVDEV_ENGINE_VP);
-		disable |= (1ULL << NVDEV_ENGINE_PPP);
-	}
-
-	if (!(r00154c & 0x00000004))
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-	if (!(r00154c & 0x00000020))
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-	if (!(r00154c & 0x00000040))
-		disable |= (1ULL << NVDEV_ENGINE_VIC);
-	if (!(r00154c & 0x00000200))
-		disable |= (1ULL << NVDEV_ENGINE_COPY0);
-
-	return disable;
-}
-
-struct nouveau_oclass *
-nvaf_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0xaf),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nva3_devinit_pll_set,
-	.disable = nvaf_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
deleted file mode 100644
index 80bd7f5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-int
-nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N, fN, M, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret)
-		return ret;
-
-	ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
-	if (ret < 0)
-		return ret;
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-	case PLL_VPLL2:
-	case PLL_VPLL3:
-		nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
-		nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
-		nv_wr32(priv, info.reg + 0x10, fN << 16);
-		break;
-	default:
-		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static u64
-nvc0_devinit_disable(struct nouveau_devinit *devinit)
-{
-	struct nv50_devinit_priv *priv = (void *)devinit;
-	u32 r022500 = nv_rd32(priv, 0x022500);
-	u64 disable = 0ULL;
-
-	if (r022500 & 0x00000001)
-		disable |= (1ULL << NVDEV_ENGINE_DISP);
-
-	if (r022500 & 0x00000002) {
-		disable |= (1ULL << NVDEV_ENGINE_VP);
-		disable |= (1ULL << NVDEV_ENGINE_PPP);
-	}
-
-	if (r022500 & 0x00000004)
-		disable |= (1ULL << NVDEV_ENGINE_BSP);
-	if (r022500 & 0x00000008)
-		disable |= (1ULL << NVDEV_ENGINE_VENC);
-	if (r022500 & 0x00000100)
-		disable |= (1ULL << NVDEV_ENGINE_COPY0);
-	if (r022500 & 0x00000200)
-		disable |= (1ULL << NVDEV_ENGINE_COPY1);
-
-	return disable;
-}
-
-static int
-nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv50_devinit_priv *priv;
-	int ret;
-
-	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	if (nv_rd32(priv, 0x022500) & 0x00000001)
-		priv->base.post = true;
-	return 0;
-}
-
-struct nouveau_oclass *
-nvc0_devinit_oclass = &(struct nouveau_devinit_impl) {
-	.base.handle = NV_SUBDEV(DEVINIT, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_devinit_ctor,
-		.dtor = _nouveau_devinit_dtor,
-		.init = nv50_devinit_init,
-		.fini = _nouveau_devinit_fini,
-	},
-	.pll_set = nvc0_devinit_pll_set,
-	.disable = nvc0_devinit_disable,
-	.post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
deleted file mode 100644
index cbcd518..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NVKM_DEVINIT_PRIV_H__
-#define __NVKM_DEVINIT_PRIV_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/clock/pll.h>
-#include <subdev/devinit.h>
-
-struct nouveau_devinit_impl {
-	struct nouveau_oclass base;
-	void (*meminit)(struct nouveau_devinit *);
-	int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
-	u64  (*disable)(struct nouveau_devinit *);
-	u32  (*mmio)(struct nouveau_devinit *, u32);
-	int  (*post)(struct nouveau_subdev *, bool);
-};
-
-#define nouveau_devinit_create(p,e,o,d)                                        \
-	nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_devinit_destroy(p) ({                                          \
-	struct nouveau_devinit *d = (p);                                       \
-	_nouveau_devinit_dtor(nv_object(d));                                   \
-})
-#define nouveau_devinit_init(p) ({                                             \
-	struct nouveau_devinit *d = (p);                                       \
-	_nouveau_devinit_init(nv_object(d));                                   \
-})
-#define nouveau_devinit_fini(p,s) ({                                           \
-	struct nouveau_devinit *d = (p);                                       \
-	_nouveau_devinit_fini(nv_object(d), (s));                              \
-})
-
-int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, int, void **);
-void _nouveau_devinit_dtor(struct nouveau_object *);
-int _nouveau_devinit_init(struct nouveau_object *);
-int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
deleted file mode 100644
index c866148..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/M0203.h>
-
-#include "priv.h"
-
-int
-nouveau_fb_bios_memtype(struct nouveau_bios *bios)
-{
-	const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
-	struct nvbios_M0203E M0203E;
-	u8 ver, hdr;
-
-	if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
-		switch (M0203E.type) {
-		case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
-		case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
-		case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
-		case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
-		default:
-			nv_warn(bios, "M0203E type %02x\n", M0203E.type);
-			return NV_MEM_TYPE_UNKNOWN;
-		}
-	}
-
-	nv_warn(bios, "M0203E not matched!\n");
-	return NV_MEM_TYPE_UNKNOWN;
-}
-
-int
-_nouveau_fb_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_fb *pfb = (void *)object;
-	int ret;
-
-	ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
-	if (ret && suspend)
-		return ret;
-
-	return nouveau_subdev_fini(&pfb->base, suspend);
-}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object;
-	int ret, i;
-
-	ret = nouveau_subdev_init(&pfb->base);
-	if (ret)
-		return ret;
-
-	ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
-	if (ret)
-		return ret;
-
-	for (i = 0; i < pfb->tile.regions; i++)
-		pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
-
-	return 0;
-}
-
-void
-_nouveau_fb_dtor(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object;
-	int i;
-
-	for (i = 0; i < pfb->tile.regions; i++)
-		pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
-	nouveau_mm_fini(&pfb->tags);
-	nouveau_mm_fini(&pfb->vram);
-
-	nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram);
-	nouveau_subdev_destroy(&pfb->base);
-}
-
-int
-nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_fb_impl *impl = (void *)oclass;
-	static const char *name[] = {
-		[NV_MEM_TYPE_UNKNOWN] = "unknown",
-		[NV_MEM_TYPE_STOLEN ] = "stolen system memory",
-		[NV_MEM_TYPE_SGRAM  ] = "SGRAM",
-		[NV_MEM_TYPE_SDRAM  ] = "SDRAM",
-		[NV_MEM_TYPE_DDR1   ] = "DDR1",
-		[NV_MEM_TYPE_DDR2   ] = "DDR2",
-		[NV_MEM_TYPE_DDR3   ] = "DDR3",
-		[NV_MEM_TYPE_GDDR2  ] = "GDDR2",
-		[NV_MEM_TYPE_GDDR3  ] = "GDDR3",
-		[NV_MEM_TYPE_GDDR4  ] = "GDDR4",
-		[NV_MEM_TYPE_GDDR5  ] = "GDDR5",
-	};
-	struct nouveau_object *ram;
-	struct nouveau_fb *pfb;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
-				     length, pobject);
-	pfb = *pobject;
-	if (ret)
-		return ret;
-
-	pfb->memtype_valid = impl->memtype;
-
-	ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
-				  impl->ram, NULL, 0, &ram);
-	if (ret) {
-		nv_fatal(pfb, "error detecting memory configuration!!\n");
-		return ret;
-	}
-
-	atomic_dec(&ram->parent->refcount);
-	atomic_dec(&ram->engine->refcount);
-	pfb->ram = (void *)ram;
-
-	if (!nouveau_mm_initialised(&pfb->vram)) {
-		ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
-		if (ret)
-			return ret;
-	}
-
-	if (!nouveau_mm_initialised(&pfb->tags)) {
-		ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ?
-				     ++pfb->ram->tags : 0, 1);
-		if (ret)
-			return ret;
-	}
-
-	nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
-	nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
-	nv_info(pfb, "   ZCOMP: %d tags\n", pfb->ram->tags);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c
deleted file mode 100644
index d85a25d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- * 	    Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include <subdev/bios.h>
-#include "priv.h"
-
-struct ramxlat {
-	int id;
-	u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
-	while (xlat->id >= 0) {
-		if (xlat->id == id)
-			return xlat->enc;
-		xlat++;
-	}
-	return -EINVAL;
-}
-
-static const struct ramxlat
-ramgddr3_cl_lo[] = {
-	{ 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
-	/* the below are mentioned in some, but not all, gddr3 docs */
-	{ 12, 4 }, { 13, 5 }, { 14, 6 },
-	/* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
-	/* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
-	 * { 15, 11 }, */
-	{ -1 }
-};
-
-static const struct ramxlat
-ramgddr3_cl_hi[] = {
-	{ 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
-	{ 16, 0 }, { 17, 1 },
-	{ -1 }
-};
-
-static const struct ramxlat
-ramgddr3_wr_lo[] = {
-	{ 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
-	{ 11, 0 },
-	/* the below are mentioned in some, but not all, gddr3 docs */
-	{ 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
-	{ -1 }
-};
-
-int
-nouveau_gddr3_calc(struct nouveau_ram *ram)
-{
-	int CL, WR, CWL, DLL = 0, ODT = 0, hi;
-
-	switch (ram->next->bios.timing_ver) {
-	case 0x10:
-		CWL = ram->next->bios.timing_10_CWL;
-		CL  = ram->next->bios.timing_10_CL;
-		WR  = ram->next->bios.timing_10_WR;
-		DLL = !ram->next->bios.ramcfg_10_DLLoff;
-		ODT = ram->next->bios.timing_10_ODT;
-		break;
-	case 0x20:
-		CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
-		CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
-		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
-		/* XXX: Get these values from the VBIOS instead */
-		DLL = !(ram->mr[1] & 0x1);
-		ODT =  (ram->mr[1] & 0x004) >> 2 |
-		       (ram->mr[1] & 0x040) >> 5 |
-		       (ram->mr[1] & 0x200) >> 7;
-		break;
-	default:
-		return -ENOSYS;
-	}
-
-	hi = ram->mr[2] & 0x1;
-	CL  = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
-	WR  = ramxlat(ramgddr3_wr_lo, WR);
-	if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
-		return -EINVAL;
-
-	ram->mr[0] &= ~0xf74;
-	ram->mr[0] |= (CWL & 0x07) << 9;
-	ram->mr[0] |= (CL & 0x07) << 4;
-	ram->mr[0] |= (CL & 0x08) >> 1;
-
-	ram->mr[1] &= ~0x3fc;
-	ram->mr[1] |= (ODT & 0x03) << 2;
-	ram->mr[1] |= (ODT & 0x03) << 8;
-	ram->mr[1] |= (WR  & 0x03) << 4;
-	ram->mr[1] |= (WR  & 0x04) << 5;
-	ram->mr[1] |= !DLL << 6;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
deleted file mode 100644
index 7fbbe05..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include "priv.h"
-
-/* binary driver only executes this path if the condition (a) is true
- * for any configuration (combination of rammap+ramcfg+timing) that
- * can be reached on a given card.  for now, we will execute the branch
- * unconditionally in the hope that a "false everywhere" in the bios
- * tables doesn't actually mean "don't touch this".
- */
-#define NOTE00(a) 1
-
-int
-nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
-{
-	int pd, lf, xd, vh, vr, vo, l3;
-	int WL, CL, WR, at[2], dt, ds;
-	int rq = ram->freq < 1000000; /* XXX */
-
-	switch (ram->next->bios.ramcfg_ver) {
-	case 0x11:
-		pd =  ram->next->bios.ramcfg_11_01_80;
-		lf =  ram->next->bios.ramcfg_11_01_40;
-		xd = !ram->next->bios.ramcfg_11_01_20;
-		vh =  ram->next->bios.ramcfg_11_02_10;
-		vr =  ram->next->bios.ramcfg_11_02_04;
-		vo =  ram->next->bios.ramcfg_11_06;
-		l3 = !ram->next->bios.ramcfg_11_07_02;
-		break;
-	default:
-		return -ENOSYS;
-	}
-
-	switch (ram->next->bios.timing_ver) {
-	case 0x20:
-		WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
-		CL = (ram->next->bios.timing[1] & 0x0000001f);
-		WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
-		at[0] = ram->next->bios.timing_20_2e_c0;
-		at[1] = ram->next->bios.timing_20_2e_30;
-		dt =  ram->next->bios.timing_20_2e_03;
-		ds =  ram->next->bios.timing_20_2f_03;
-		break;
-	default:
-		return -ENOSYS;
-	}
-
-	if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
-		return -EINVAL;
-	CL -= 5;
-	WR -= 4;
-
-	ram->mr[0] &= ~0xf7f;
-	ram->mr[0] |= (WR & 0x0f) << 8;
-	ram->mr[0] |= (CL & 0x0f) << 3;
-	ram->mr[0] |= (WL & 0x07) << 0;
-
-	ram->mr[1] &= ~0x0bf;
-	ram->mr[1] |= (xd & 0x01) << 7;
-	ram->mr[1] |= (at[0] & 0x03) << 4;
-	ram->mr[1] |= (dt & 0x03) << 2;
-	ram->mr[1] |= (ds & 0x03) << 0;
-
-	/* this seems wrong, alternate field used for the broadcast
-	 * on nuts vs non-nuts configs..  meh, it matches for now.
-	 */
-	ram->mr1_nuts = ram->mr[1];
-	if (nuts) {
-		ram->mr[1] &= ~0x030;
-		ram->mr[1] |= (at[1] & 0x03) << 4;
-	}
-
-	ram->mr[3] &= ~0x020;
-	ram->mr[3] |= (rq & 0x01) << 5;
-
-	ram->mr[5] &= ~0x004;
-	ram->mr[5] |= (l3 << 2);
-
-	if (!vo)
-		vo = (ram->mr[6] & 0xff0) >> 4;
-	if (ram->mr[6] & 0x001)
-		pd = 1; /* binary driver does this.. bug? */
-	ram->mr[6] &= ~0xff1;
-	ram->mr[6] |= (vo & 0xff) << 4;
-	ram->mr[6] |= (pd & 0x01) << 0;
-
-	if (NOTE00(vr)) {
-		ram->mr[7] &= ~0x300;
-		ram->mr[7] |= (vr & 0x03) << 8;
-	}
-	ram->mr[7] &= ~0x088;
-	ram->mr[7] |= (vh & 0x01) << 7;
-	ram->mr[7] |= (lf & 0x01) << 3;
-
-	ram->mr[8] &= ~0x003;
-	ram->mr[8] |= (WR & 0x10) >> 3;
-	ram->mr[8] |= (CL & 0x10) >> 4;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c
deleted file mode 100644
index fde42e4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "nvc0.h"
-
-struct gk20a_fb_priv {
-	struct nouveau_fb base;
-};
-
-static int
-gk20a_fb_init(struct nouveau_object *object)
-{
-	struct gk20a_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
-	return 0;
-}
-
-static int
-gk20a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct gk20a_fb_priv *priv;
-	int ret;
-
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-gk20a_fb_oclass = &(struct nouveau_fb_impl) {
-	.base.handle = NV_SUBDEV(FB, 0xea),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = gk20a_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.memtype = nvc0_fb_memtype_valid,
-	.ram = &gk20a_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c
deleted file mode 100644
index c4840ae..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct nouveau_oclass *
-gm107_fb_oclass = &(struct nouveau_fb_impl) {
-	.base.handle = NV_SUBDEV(FB, 0x07),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_fb_ctor,
-		.dtor = nvc0_fb_dtor,
-		.init = nvc0_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.memtype = nvc0_fb_memtype_valid,
-	.ram = &gm107_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
deleted file mode 100644
index 8309fe3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-#define NV04_PFB_CFG0						0x00100200
-
-bool
-nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
-{
-	if (!(tile_flags & 0xff00))
-		return true;
-
-	return false;
-}
-
-static int
-nv04_fb_init(struct nouveau_object *object)
-{
-	struct nv04_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
-	 * nvidia reading PFB_CFG_0, then writing back its original value.
-	 * (which was 0x701114 in this case)
-	 */
-	nv_wr32(priv, NV04_PFB_CFG0, 0x1114);
-	return 0;
-}
-
-int
-nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nv04_fb_impl *impl = (void *)oclass;
-	struct nv04_fb_priv *priv;
-	int ret;
-
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.tile.regions = impl->tile.regions;
-	priv->base.tile.init = impl->tile.init;
-	priv->base.tile.comp = impl->tile.comp;
-	priv->base.tile.fini = impl->tile.fini;
-	priv->base.tile.prog = impl->tile.prog;
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x04),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv04_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv04_ram_oclass,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h
deleted file mode 100644
index 06ce71f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __NVKM_FB_NV04_H__
-#define __NVKM_FB_NV04_H__
-
-#include "priv.h"
-
-struct nv04_fb_priv {
-	struct nouveau_fb base;
-};
-
-int  nv04_fb_ctor(struct nouveau_object *, struct nouveau_object *,
-		  struct nouveau_oclass *, void *, u32,
-		  struct nouveau_object **);
-
-struct nv04_fb_impl {
-	struct nouveau_fb_impl base;
-	struct {
-		int regions;
-		void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
-			     u32 pitch, u32 flags, struct nouveau_fb_tile *);
-		void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
-			     struct nouveau_fb_tile *);
-		void (*fini)(struct nouveau_fb *, int i,
-			     struct nouveau_fb_tile *);
-		void (*prog)(struct nouveau_fb *, int i,
-			     struct nouveau_fb_tile *);
-	} tile;
-};
-
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv30_fb_init(struct nouveau_object *);
-void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
-		       struct nouveau_fb_tile *);
-
-int  nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
deleted file mode 100644
index ffb7ec6..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
-		  u32 flags, struct nouveau_fb_tile *tile)
-{
-	tile->addr  = 0x80000000 | addr;
-	tile->limit = max(1u, addr + size) - 1;
-	tile->pitch = pitch;
-}
-
-void
-nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	tile->addr  = 0;
-	tile->limit = 0;
-	tile->pitch = 0;
-	tile->zcomp = 0;
-}
-
-void
-nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
-	nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
-	nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
-	nv_rd32(pfb, 0x100240 + (i * 0x10));
-}
-
-struct nouveau_oclass *
-nv10_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x10),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = _nouveau_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv10_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv10_fb_tile_init,
-	.tile.fini = nv10_fb_tile_fini,
-	.tile.prog = nv10_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
deleted file mode 100644
index 265d125..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv1a_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x1a),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = _nouveau_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv1a_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv10_fb_tile_init,
-	.tile.fini = nv10_fb_tile_fini,
-	.tile.prog = nv10_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
deleted file mode 100644
index 2209ade..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
-		  u32 flags, struct nouveau_fb_tile *tile)
-{
-	tile->addr  = 0x00000001 | addr;
-	tile->limit = max(1u, addr + size) - 1;
-	tile->pitch = pitch;
-	if (flags & 4) {
-		pfb->tile.comp(pfb, i, size, flags, tile);
-		tile->addr |= 2;
-	}
-}
-
-static void
-nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-	if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
-		else              tile->zcomp = 0x04000000; /* Z24S8 */
-		tile->zcomp |= tile->tag->offset;
-		tile->zcomp |= 0x80000000; /* enable */
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x08000000;
-#endif
-	}
-}
-
-void
-nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	tile->addr  = 0;
-	tile->limit = 0;
-	tile->pitch = 0;
-	tile->zcomp = 0;
-	nouveau_mm_free(&pfb->tags, &tile->tag);
-}
-
-void
-nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
-	nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
-	nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
-	nv_rd32(pfb, 0x100240 + (i * 0x10));
-	nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
-}
-
-struct nouveau_oclass *
-nv20_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x20),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = _nouveau_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv20_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv20_fb_tile_init,
-	.tile.comp = nv20_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
deleted file mode 100644
index e2a66c3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-	if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
-		else              tile->zcomp = 0x00200000; /* Z24S8 */
-		tile->zcomp |= tile->tag->offset;
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x01000000;
-#endif
-	}
-}
-
-struct nouveau_oclass *
-nv25_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x25),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = _nouveau_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv20_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv20_fb_tile_init,
-	.tile.comp = nv25_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
deleted file mode 100644
index cbec402..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
-		  u32 flags, struct nouveau_fb_tile *tile)
-{
-	/* for performance, select alternate bank offset for zeta */
-	if (!(flags & 4)) {
-		tile->addr = (0 << 4);
-	} else {
-		if (pfb->tile.comp) /* z compression */
-			pfb->tile.comp(pfb, i, size, flags, tile);
-		tile->addr = (1 << 4);
-	}
-
-	tile->addr |= 0x00000001; /* enable */
-	tile->addr |= addr;
-	tile->limit = max(1u, addr + size) - 1;
-	tile->pitch = pitch;
-}
-
-static void
-nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-	if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
-		else           tile->zcomp |= 0x02000000; /* Z24S8 */
-		tile->zcomp |= ((tile->tag->offset           ) >> 6);
-		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x10000000;
-#endif
-	}
-}
-
-static int
-calc_bias(struct nv04_fb_priv *priv, int k, int i, int j)
-{
-	struct nouveau_device *device = nv_device(priv);
-	int b = (device->chipset > 0x30 ?
-		 nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
-		 0) & 0xf;
-
-	return 2 * (b & 0x8 ? b - 0x10 : b);
-}
-
-static int
-calc_ref(struct nv04_fb_priv *priv, int l, int k, int i)
-{
-	int j, x = 0;
-
-	for (j = 0; j < 4; j++) {
-		int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j);
-
-		x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
-	}
-
-	return x;
-}
-
-int
-nv30_fb_init(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nv04_fb_priv *priv = (void *)object;
-	int ret, i, j;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* Init the memory timing regs at 0x10037c/0x1003ac */
-	if (device->chipset == 0x30 ||
-	    device->chipset == 0x31 ||
-	    device->chipset == 0x35) {
-		/* Related to ROP count */
-		int n = (device->chipset == 0x31 ? 2 : 4);
-		int l = nv_rd32(priv, 0x1003d0);
-
-		for (i = 0; i < n; i++) {
-			for (j = 0; j < 3; j++)
-				nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j,
-					calc_ref(priv, l, 0, j));
-
-			for (j = 0; j < 2; j++)
-				nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j,
-					calc_ref(priv, l, 1, j));
-		}
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nv30_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x30),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv30_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv20_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv30_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
deleted file mode 100644
index b2cf8c6..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-	if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
-		else           tile->zcomp |= 0x08000000; /* Z24S8 */
-		tile->zcomp |= ((tile->tag->offset           ) >> 6);
-		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x40000000;
-#endif
-	}
-}
-
-struct nouveau_oclass *
-nv35_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x35),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv30_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv20_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv35_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
deleted file mode 100644
index b4cdae2a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
-	if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
-		else           tile->zcomp |= 0x20000000; /* Z24S8 */
-		tile->zcomp |= ((tile->tag->offset           ) >> 6);
-		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x80000000;
-#endif
-	}
-}
-
-struct nouveau_oclass *
-nv36_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x36),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv30_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv20_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv36_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
deleted file mode 100644
index 5281425..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
-		  struct nouveau_fb_tile *tile)
-{
-	u32 tiles = DIV_ROUND_UP(size, 0x80);
-	u32 tags  = round_up(tiles / pfb->ram->parts, 0x100);
-	if ( (flags & 2) &&
-	    !nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
-		tile->zcomp  = 0x28000000; /* Z24S8_SPLIT_GRAD */
-		tile->zcomp |= ((tile->tag->offset           ) >> 8);
-		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
-#ifdef __BIG_ENDIAN
-		tile->zcomp |= 0x40000000;
-#endif
-	}
-}
-
-static int
-nv40_fb_init(struct nouveau_object *object)
-{
-	struct nv04_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv40_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x40),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv40_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv40_ram_oclass,
-	.tile.regions = 8,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv40_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h
deleted file mode 100644
index 581f808..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_FB_NV40_H__
-#define __NVKM_FB_NV40_H__
-
-#include "priv.h"
-
-struct nv40_ram {
-	struct nouveau_ram base;
-	u32 ctrl;
-	u32 coef;
-};
-
-
-int  nv40_ram_calc(struct nouveau_fb *, u32);
-int  nv40_ram_prog(struct nouveau_fb *);
-void nv40_ram_tidy(struct nouveau_fb *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
deleted file mode 100644
index b239a86..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
-	nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
-	nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
-	nv_rd32(pfb, 0x100600 + (i * 0x10));
-	nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp);
-}
-
-int
-nv41_fb_init(struct nouveau_object *object)
-{
-	struct nv04_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x100800, 0x00000001);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv41_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x41),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv41_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv41_ram_oclass,
-	.tile.regions = 12,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv40_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
deleted file mode 100644
index d847820..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
-		  u32 flags, struct nouveau_fb_tile *tile)
-{
-	tile->addr  = 0x00000001; /* mode = vram */
-	tile->addr |= addr;
-	tile->limit = max(1u, addr + size) - 1;
-	tile->pitch = pitch;
-}
-
-void
-nv44_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
-	nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
-	nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
-	nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
-	nv_rd32(pfb, 0x100600 + (i * 0x10));
-}
-
-int
-nv44_fb_init(struct nouveau_object *object)
-{
-	struct nv04_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x100850, 0x80000000);
-	nv_wr32(priv, 0x100800, 0x00000001);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv44_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x44),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv44_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv44_ram_oclass,
-	.tile.regions = 12,
-	.tile.init = nv44_fb_tile_init,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
deleted file mode 100644
index a5b7751..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-void
-nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
-		  u32 flags, struct nouveau_fb_tile *tile)
-{
-	/* for performance, select alternate bank offset for zeta */
-	if (!(flags & 4)) tile->addr = (0 << 3);
-	else              tile->addr = (1 << 3);
-
-	tile->addr |= 0x00000001; /* mode = vram */
-	tile->addr |= addr;
-	tile->limit = max(1u, addr + size) - 1;
-	tile->pitch = pitch;
-}
-
-struct nouveau_oclass *
-nv46_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x46),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv44_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv44_ram_oclass,
-	.tile.regions = 15,
-	.tile.init = nv46_fb_tile_init,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
deleted file mode 100644
index 3bea142..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv47_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x47),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv41_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv41_ram_oclass,
-	.tile.regions = 15,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv40_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
deleted file mode 100644
index 666cbd5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv49_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x49),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv41_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv49_ram_oclass,
-	.tile.regions = 15,
-	.tile.init = nv30_fb_tile_init,
-	.tile.comp = nv40_fb_tile_comp,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
deleted file mode 100644
index 42e64f3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv4e_fb_oclass = &(struct nv04_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x4e),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_fb_ctor,
-		.dtor = _nouveau_fb_dtor,
-		.init = nv44_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv04_fb_memtype_valid,
-	.base.ram = &nv4e_ram_oclass,
-	.tile.regions = 12,
-	.tile.init = nv46_fb_tile_init,
-	.tile.fini = nv20_fb_tile_fini,
-	.tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
deleted file mode 100644
index 4150b0d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-#include <core/object.h>
-
-#include <subdev/bios.h>
-
-#include "nv50.h"
-
-int
-nv50_fb_memtype[0x80] = {
-	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
-	1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
-	0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-	1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
-};
-
-bool
-nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
-{
-	return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
-}
-
-static const struct nouveau_enum vm_dispatch_subclients[] = {
-	{ 0x00000000, "GRCTX", NULL },
-	{ 0x00000001, "NOTIFY", NULL },
-	{ 0x00000002, "QUERY", NULL },
-	{ 0x00000003, "COND", NULL },
-	{ 0x00000004, "M2M_IN", NULL },
-	{ 0x00000005, "M2M_OUT", NULL },
-	{ 0x00000006, "M2M_NOTIFY", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_ccache_subclients[] = {
-	{ 0x00000000, "CB", NULL },
-	{ 0x00000001, "TIC", NULL },
-	{ 0x00000002, "TSC", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_prop_subclients[] = {
-	{ 0x00000000, "RT0", NULL },
-	{ 0x00000001, "RT1", NULL },
-	{ 0x00000002, "RT2", NULL },
-	{ 0x00000003, "RT3", NULL },
-	{ 0x00000004, "RT4", NULL },
-	{ 0x00000005, "RT5", NULL },
-	{ 0x00000006, "RT6", NULL },
-	{ 0x00000007, "RT7", NULL },
-	{ 0x00000008, "ZETA", NULL },
-	{ 0x00000009, "LOCAL", NULL },
-	{ 0x0000000a, "GLOBAL", NULL },
-	{ 0x0000000b, "STACK", NULL },
-	{ 0x0000000c, "DST2D", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_pfifo_subclients[] = {
-	{ 0x00000000, "PUSHBUF", NULL },
-	{ 0x00000001, "SEMAPHORE", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_bar_subclients[] = {
-	{ 0x00000000, "FB", NULL },
-	{ 0x00000001, "IN", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_client[] = {
-	{ 0x00000000, "STRMOUT", NULL },
-	{ 0x00000003, "DISPATCH", vm_dispatch_subclients },
-	{ 0x00000004, "PFIFO_WRITE", NULL },
-	{ 0x00000005, "CCACHE", vm_ccache_subclients },
-	{ 0x00000006, "PPPP", NULL },
-	{ 0x00000007, "CLIPID", NULL },
-	{ 0x00000008, "PFIFO_READ", NULL },
-	{ 0x00000009, "VFETCH", NULL },
-	{ 0x0000000a, "TEXTURE", NULL },
-	{ 0x0000000b, "PROP", vm_prop_subclients },
-	{ 0x0000000c, "PVP", NULL },
-	{ 0x0000000d, "PBSP", NULL },
-	{ 0x0000000e, "PCRYPT", NULL },
-	{ 0x0000000f, "PCOUNTER", NULL },
-	{ 0x00000011, "PDAEMON", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_engine[] = {
-	{ 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
-	{ 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
-	{ 0x00000004, "PEEPHOLE", NULL },
-	{ 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
-	{ 0x00000006, "BAR", vm_bar_subclients },
-	{ 0x00000008, "PPPP", NULL, NVDEV_ENGINE_PPP },
-	{ 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
-	{ 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
-	{ 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CRYPT },
-	{ 0x0000000b, "PCOUNTER", NULL },
-	{ 0x0000000c, "SEMAPHORE_BG", NULL },
-	{ 0x0000000d, "PCOPY", NULL, NVDEV_ENGINE_COPY0 },
-	{ 0x0000000e, "PDAEMON", NULL },
-	{}
-};
-
-static const struct nouveau_enum vm_fault[] = {
-	{ 0x00000000, "PT_NOT_PRESENT", NULL },
-	{ 0x00000001, "PT_TOO_SHORT", NULL },
-	{ 0x00000002, "PAGE_NOT_PRESENT", NULL },
-	{ 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
-	{ 0x00000004, "PAGE_READ_ONLY", NULL },
-	{ 0x00000006, "NULL_DMAOBJ", NULL },
-	{ 0x00000007, "WRONG_MEMTYPE", NULL },
-	{ 0x0000000b, "VRAM_LIMIT", NULL },
-	{ 0x0000000f, "DMAOBJ_LIMIT", NULL },
-	{}
-};
-
-static void
-nv50_fb_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_device *device = nv_device(subdev);
-	struct nouveau_engine *engine;
-	struct nv50_fb_priv *priv = (void *)subdev;
-	const struct nouveau_enum *en, *cl;
-	struct nouveau_object *engctx = NULL;
-	u32 trap[6], idx, chan;
-	u8 st0, st1, st2, st3;
-	int i;
-
-	idx = nv_rd32(priv, 0x100c90);
-	if (!(idx & 0x80000000))
-		return;
-	idx &= 0x00ffffff;
-
-	for (i = 0; i < 6; i++) {
-		nv_wr32(priv, 0x100c90, idx | i << 24);
-		trap[i] = nv_rd32(priv, 0x100c94);
-	}
-	nv_wr32(priv, 0x100c90, idx | 0x80000000);
-
-	/* decode status bits into something more useful */
-	if (device->chipset  < 0xa3 ||
-	    device->chipset == 0xaa || device->chipset == 0xac) {
-		st0 = (trap[0] & 0x0000000f) >> 0;
-		st1 = (trap[0] & 0x000000f0) >> 4;
-		st2 = (trap[0] & 0x00000f00) >> 8;
-		st3 = (trap[0] & 0x0000f000) >> 12;
-	} else {
-		st0 = (trap[0] & 0x000000ff) >> 0;
-		st1 = (trap[0] & 0x0000ff00) >> 8;
-		st2 = (trap[0] & 0x00ff0000) >> 16;
-		st3 = (trap[0] & 0xff000000) >> 24;
-	}
-	chan = (trap[2] << 16) | trap[1];
-
-	en = nouveau_enum_find(vm_engine, st0);
-
-	if (en && en->data2) {
-		const struct nouveau_enum *orig_en = en;
-		while (en->name && en->value == st0 && en->data2) {
-			engine = nouveau_engine(subdev, en->data2);
-			if (engine) {
-				engctx = nouveau_engctx_get(engine, chan);
-				if (engctx)
-					break;
-			}
-			en++;
-		}
-		if (!engctx)
-			en = orig_en;
-	}
-
-	nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
-		 (trap[5] & 0x00000100) ? "read" : "write",
-		 trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
-		 nouveau_client_name(engctx));
-
-	nouveau_engctx_put(engctx);
-
-	if (en)
-		pr_cont("%s/", en->name);
-	else
-		pr_cont("%02x/", st0);
-
-	cl = nouveau_enum_find(vm_client, st2);
-	if (cl)
-		pr_cont("%s/", cl->name);
-	else
-		pr_cont("%02x/", st2);
-
-	if      (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
-	else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
-	else                     cl = NULL;
-	if (cl)
-		pr_cont("%s", cl->name);
-	else
-		pr_cont("%02x", st3);
-
-	pr_cont(" reason: ");
-	en = nouveau_enum_find(vm_fault, st1);
-	if (en)
-		pr_cont("%s\n", en->name);
-	else
-		pr_cont("0x%08x\n", st1);
-}
-
-int
-nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nv50_fb_priv *priv;
-	int ret;
-
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (priv->r100c08_page) {
-		priv->r100c08 = dma_map_page(nv_device_base(device),
-					     priv->r100c08_page, 0, PAGE_SIZE,
-					     DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(nv_device_base(device), priv->r100c08))
-			return -EFAULT;
-	} else {
-		nv_warn(priv, "failed 0x100c08 page alloc\n");
-	}
-
-	nv_subdev(priv)->intr = nv50_fb_intr;
-	return 0;
-}
-
-void
-nv50_fb_dtor(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nv50_fb_priv *priv = (void *)object;
-
-	if (priv->r100c08_page) {
-		dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE,
-			       DMA_BIDIRECTIONAL);
-		__free_page(priv->r100c08_page);
-	}
-
-	nouveau_fb_destroy(&priv->base);
-}
-
-int
-nv50_fb_init(struct nouveau_object *object)
-{
-	struct nv50_fb_impl *impl = (void *)object->oclass;
-	struct nv50_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* Not a clue what this is exactly.  Without pointing it at a
-	 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
-	 * cause IOMMU "read from address 0" errors (rh#561267)
-	 */
-	nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
-
-	/* This is needed to get meaningful information from 100c90
-	 * on traps. No idea what these values mean exactly. */
-	nv_wr32(priv, 0x100c90, impl->trap);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_fb_oclass = &(struct nv50_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x50),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fb_ctor,
-		.dtor = nv50_fb_dtor,
-		.init = nv50_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv50_fb_memtype_valid,
-	.base.ram = &nv50_ram_oclass,
-	.trap = 0x000707ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h
deleted file mode 100644
index c5e5a88..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NVKM_FB_NV50_H__
-#define __NVKM_FB_NV50_H__
-
-#include "priv.h"
-
-struct nv50_fb_priv {
-	struct nouveau_fb base;
-	struct page *r100c08_page;
-	dma_addr_t r100c08;
-};
-
-int  nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *,
-		  struct nouveau_oclass *, void *, u32,
-		  struct nouveau_object **);
-void nv50_fb_dtor(struct nouveau_object *);
-int  nv50_fb_init(struct nouveau_object *);
-
-struct nv50_fb_impl {
-	struct nouveau_fb_impl base;
-	u32 trap;
-};
-
-#define nv50_ram_create(p,e,o,d)                                               \
-	nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
-int  nv50_ram_create_(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, int, void **);
-int  nv50_ram_get(struct nouveau_fb *, u64 size, u32 align, u32 ncmin,
-		  u32 memtype, struct nouveau_mem **);
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
-void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
-extern int nv50_fb_memtype[0x80];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c
deleted file mode 100644
index cf0e767..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nv84_fb_oclass = &(struct nv50_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0x84),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fb_ctor,
-		.dtor = nv50_fb_dtor,
-		.init = nv50_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv50_fb_memtype_valid,
-	.base.ram = &nv50_ram_oclass,
-	.trap = 0x001d07ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c
deleted file mode 100644
index dab6e1c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nva3_fb_oclass = &(struct nv50_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0xa3),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fb_ctor,
-		.dtor = nv50_fb_dtor,
-		.init = nv50_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv50_fb_memtype_valid,
-	.base.ram = &nva3_ram_oclass,
-	.trap = 0x000d0fff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c
deleted file mode 100644
index cba8e68..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nvaa_fb_oclass = &(struct nv50_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0xaa),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fb_ctor,
-		.dtor = nv50_fb_dtor,
-		.init = nv50_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv50_fb_memtype_valid,
-	.base.ram = &nvaa_ram_oclass,
-	.trap = 0x001d07ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c
deleted file mode 100644
index 5423faa..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nvaf_fb_oclass = &(struct nv50_fb_impl) {
-	.base.base.handle = NV_SUBDEV(FB, 0xaf),
-	.base.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_fb_ctor,
-		.dtor = nv50_fb_dtor,
-		.init = nv50_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.base.memtype = nv50_fb_memtype_valid,
-	.base.ram = &nvaa_ram_oclass,
-	.trap = 0x089d1fff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
deleted file mode 100644
index 32f28dc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-extern const u8 nvc0_pte_storage_type_map[256];
-
-bool
-nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
-{
-	u8 memtype = (tile_flags & 0x0000ff00) >> 8;
-	return likely((nvc0_pte_storage_type_map[memtype] != 0xff));
-}
-
-static void
-nvc0_fb_intr(struct nouveau_subdev *subdev)
-{
-	struct nvc0_fb_priv *priv = (void *)subdev;
-	u32 intr = nv_rd32(priv, 0x000100);
-	if (intr & 0x08000000) {
-		nv_debug(priv, "PFFB intr\n");
-		intr &= ~0x08000000;
-	}
-	if (intr & 0x00002000) {
-		nv_debug(priv, "PBFB intr\n");
-		intr &= ~0x00002000;
-	}
-}
-
-int
-nvc0_fb_init(struct nouveau_object *object)
-{
-	struct nvc0_fb_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_fb_init(&priv->base);
-	if (ret)
-		return ret;
-
-	if (priv->r100c10_page)
-		nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
-	nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
-	return 0;
-}
-
-void
-nvc0_fb_dtor(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nvc0_fb_priv *priv = (void *)object;
-
-	if (priv->r100c10_page) {
-		dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE,
-			       DMA_BIDIRECTIONAL);
-		__free_page(priv->r100c10_page);
-	}
-
-	nouveau_fb_destroy(&priv->base);
-}
-
-int
-nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nvc0_fb_priv *priv;
-	int ret;
-
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (priv->r100c10_page) {
-		priv->r100c10 = dma_map_page(nv_device_base(device),
-					     priv->r100c10_page, 0, PAGE_SIZE,
-					     DMA_BIDIRECTIONAL);
-		if (dma_mapping_error(nv_device_base(device), priv->r100c10))
-			return -EFAULT;
-	}
-
-	nv_subdev(priv)->intr = nvc0_fb_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-nvc0_fb_oclass = &(struct nouveau_fb_impl) {
-	.base.handle = NV_SUBDEV(FB, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_fb_ctor,
-		.dtor = nvc0_fb_dtor,
-		.init = nvc0_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.memtype = nvc0_fb_memtype_valid,
-	.ram = &nvc0_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
deleted file mode 100644
index 705a06d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVKM_RAM_NVC0_H__
-#define __NVKM_RAM_NVC0_H__
-
-#include "priv.h"
-#include "nv50.h"
-
-struct nvc0_fb_priv {
-	struct nouveau_fb base;
-	struct page *r100c10_page;
-	dma_addr_t r100c10;
-};
-
-int  nvc0_fb_ctor(struct nouveau_object *, struct nouveau_object *,
-		  struct nouveau_oclass *, void *, u32,
-		  struct nouveau_object **);
-void nvc0_fb_dtor(struct nouveau_object *);
-int  nvc0_fb_init(struct nouveau_object *);
-bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32);
-
-
-#define nvc0_ram_create(p,e,o,m,d)                                             \
-	nvc0_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
-int  nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, u32, int, void **);
-int  nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32,
-		  struct nouveau_mem **);
-void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **);
-
-int  nve0_ram_init(struct nouveau_object*);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c
deleted file mode 100644
index 595db50..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct nouveau_oclass *
-nve0_fb_oclass = &(struct nouveau_fb_impl) {
-	.base.handle = NV_SUBDEV(FB, 0xe0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_fb_ctor,
-		.dtor = nvc0_fb_dtor,
-		.init = nvc0_fb_init,
-		.fini = _nouveau_fb_fini,
-	},
-	.memtype = nvc0_fb_memtype_valid,
-	.ram = &nve0_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
deleted file mode 100644
index 283863f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef __NVKM_FB_PRIV_H__
-#define __NVKM_FB_PRIV_H__
-
-#include <subdev/fb.h>
-
-#define nouveau_ram_create(p,e,o,d)                                            \
-	nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
-#define nouveau_ram_destroy(p)                                                 \
-	nouveau_object_destroy(&(p)->base)
-#define nouveau_ram_init(p)                                                    \
-	nouveau_object_init(&(p)->base)
-#define nouveau_ram_fini(p,s)                                                  \
-	nouveau_object_fini(&(p)->base, (s))
-
-#define nouveau_ram_create_(p,e,o,s,d)                                         \
-	nouveau_object_create_((p), (e), (o), 0, (s), (void **)d)
-#define _nouveau_ram_dtor nouveau_object_destroy
-#define _nouveau_ram_init nouveau_object_init
-#define _nouveau_ram_fini nouveau_object_fini
-
-extern struct nouveau_oclass nv04_ram_oclass;
-extern struct nouveau_oclass nv10_ram_oclass;
-extern struct nouveau_oclass nv1a_ram_oclass;
-extern struct nouveau_oclass nv20_ram_oclass;
-extern struct nouveau_oclass nv40_ram_oclass;
-extern struct nouveau_oclass nv41_ram_oclass;
-extern struct nouveau_oclass nv44_ram_oclass;
-extern struct nouveau_oclass nv49_ram_oclass;
-extern struct nouveau_oclass nv4e_ram_oclass;
-extern struct nouveau_oclass nv50_ram_oclass;
-extern struct nouveau_oclass nva3_ram_oclass;
-extern struct nouveau_oclass nvaa_ram_oclass;
-extern struct nouveau_oclass nvc0_ram_oclass;
-extern struct nouveau_oclass nve0_ram_oclass;
-extern struct nouveau_oclass gk20a_ram_oclass;
-extern struct nouveau_oclass gm107_ram_oclass;
-
-int nouveau_sddr2_calc(struct nouveau_ram *ram);
-int nouveau_sddr3_calc(struct nouveau_ram *ram);
-int nouveau_gddr3_calc(struct nouveau_ram *ram);
-int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
-
-#define nouveau_fb_create(p,e,c,d)                                             \
-	nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
-#define nouveau_fb_destroy(p) ({                                               \
-	struct nouveau_fb *pfb = (p);                                          \
-	_nouveau_fb_dtor(nv_object(pfb));                                      \
-})
-#define nouveau_fb_init(p) ({                                                  \
-	struct nouveau_fb *pfb = (p);                                          \
-	_nouveau_fb_init(nv_object(pfb));                                      \
-})
-#define nouveau_fb_fini(p,s) ({                                                \
-	struct nouveau_fb *pfb = (p);                                          \
-	_nouveau_fb_fini(nv_object(pfb), (s));                                 \
-})
-
-int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, int, void **);
-void _nouveau_fb_dtor(struct nouveau_object *);
-int  _nouveau_fb_init(struct nouveau_object *);
-int  _nouveau_fb_fini(struct nouveau_object *, bool);
-
-struct nouveau_fb_impl {
-	struct nouveau_oclass base;
-	struct nouveau_oclass *ram;
-	bool (*memtype)(struct nouveau_fb *, u32);
-};
-
-bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-bool nv50_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-
-struct nouveau_bios;
-int  nouveau_fb_bios_memtype(struct nouveau_bios *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
deleted file mode 100644
index 0ac7256..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef __NVKM_FBRAM_FUC_H__
-#define __NVKM_FBRAM_FUC_H__
-
-#include <subdev/pwr.h>
-
-struct ramfuc {
-	struct nouveau_memx *memx;
-	struct nouveau_fb *pfb;
-	int sequence;
-};
-
-struct ramfuc_reg {
-	int sequence;
-	bool force;
-	u32 addr;
-	u32 stride; /* in bytes */
-	u32 mask;
-	u32 data;
-};
-
-static inline struct ramfuc_reg
-ramfuc_stride(u32 addr, u32 stride, u32 mask)
-{
-	return (struct ramfuc_reg) {
-		.sequence = 0,
-		.addr = addr,
-		.stride = stride,
-		.mask = mask,
-		.data = 0xdeadbeef,
-	};
-}
-
-static inline struct ramfuc_reg
-ramfuc_reg2(u32 addr1, u32 addr2)
-{
-	return (struct ramfuc_reg) {
-		.sequence = 0,
-		.addr = addr1,
-		.stride = addr2 - addr1,
-		.mask = 0x3,
-		.data = 0xdeadbeef,
-	};
-}
-
-static noinline struct ramfuc_reg
-ramfuc_reg(u32 addr)
-{
-	return (struct ramfuc_reg) {
-		.sequence = 0,
-		.addr = addr,
-		.stride = 0,
-		.mask = 0x1,
-		.data = 0xdeadbeef,
-	};
-}
-
-static inline int
-ramfuc_init(struct ramfuc *ram, struct nouveau_fb *pfb)
-{
-	struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
-	int ret;
-
-	ret = nouveau_memx_init(ppwr, &ram->memx);
-	if (ret)
-		return ret;
-
-	ram->sequence++;
-	ram->pfb = pfb;
-	return 0;
-}
-
-static inline int
-ramfuc_exec(struct ramfuc *ram, bool exec)
-{
-	int ret = 0;
-	if (ram->pfb) {
-		ret = nouveau_memx_fini(&ram->memx, exec);
-		ram->pfb = NULL;
-	}
-	return ret;
-}
-
-static inline u32
-ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
-{
-	if (reg->sequence != ram->sequence)
-		reg->data = nv_rd32(ram->pfb, reg->addr);
-	return reg->data;
-}
-
-static inline void
-ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
-{
-	unsigned int mask, off = 0;
-
-	reg->sequence = ram->sequence;
-	reg->data = data;
-
-	for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
-		if (mask & 1) {
-			nouveau_memx_wr32(ram->memx, reg->addr+off, reg->data);
-		}
-
-		off += reg->stride;
-	}
-}
-
-static inline void
-ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
-{
-	reg->force = true;
-}
-
-static inline u32
-ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
-{
-	u32 temp = ramfuc_rd32(ram, reg);
-	if (temp != ((temp & ~mask) | data) || reg->force) {
-		ramfuc_wr32(ram, reg, (temp & ~mask) | data);
-		reg->force = false;
-	}
-	return temp;
-}
-
-static inline void
-ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
-{
-	nouveau_memx_wait(ram->memx, addr, mask, data, nsec);
-}
-
-static inline void
-ramfuc_nsec(struct ramfuc *ram, u32 nsec)
-{
-	nouveau_memx_nsec(ram->memx, nsec);
-}
-
-static inline void
-ramfuc_wait_vblank(struct ramfuc *ram)
-{
-	nouveau_memx_wait_vblank(ram->memx);
-}
-
-static inline void
-ramfuc_train(struct ramfuc *ram)
-{
-	nouveau_memx_train(ram->memx);
-}
-
-static inline int
-ramfuc_train_result(struct nouveau_fb *pfb, u32 *result, u32 rsize)
-{
-	struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
-
-	return nouveau_memx_train_result(ppwr, result, rsize);
-}
-
-static inline void
-ramfuc_block(struct ramfuc *ram)
-{
-	nouveau_memx_block(ram->memx);
-}
-
-static inline void
-ramfuc_unblock(struct ramfuc *ram)
-{
-	nouveau_memx_unblock(ram->memx);
-}
-
-#define ram_init(s,p)        ramfuc_init(&(s)->base, (p))
-#define ram_exec(s,e)        ramfuc_exec(&(s)->base, (e))
-#define ram_have(s,r)        ((s)->r_##r.addr != 0x000000)
-#define ram_rd32(s,r)        ramfuc_rd32(&(s)->base, &(s)->r_##r)
-#define ram_wr32(s,r,d)      ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
-#define ram_nuke(s,r)        ramfuc_nuke(&(s)->base, &(s)->r_##r)
-#define ram_mask(s,r,m,d)    ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define ram_wait(s,r,m,d,n)  ramfuc_wait(&(s)->base, (r), (m), (d), (n))
-#define ram_nsec(s,n)        ramfuc_nsec(&(s)->base, (n))
-#define ram_wait_vblank(s)   ramfuc_wait_vblank(&(s)->base)
-#define ram_train(s)         ramfuc_train(&(s)->base)
-#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
-#define ram_block(s)         ramfuc_block(&(s)->base)
-#define ram_unblock(s)       ramfuc_unblock(&(s)->base)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c
deleted file mode 100644
index 4d77d75..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 "priv.h"
-
-#include <subdev/fb.h>
-
-struct gk20a_mem {
-	struct nouveau_mem base;
-	void *cpuaddr;
-	dma_addr_t handle;
-};
-#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base)
-
-static void
-gk20a_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
-	struct device *dev = nv_device_base(nv_device(pfb));
-	struct gk20a_mem *mem = to_gk20a_mem(*pmem);
-
-	*pmem = NULL;
-	if (unlikely(mem == NULL))
-		return;
-
-	if (likely(mem->cpuaddr))
-		dma_free_coherent(dev, mem->base.size << PAGE_SHIFT,
-				  mem->cpuaddr, mem->handle);
-
-	kfree(mem->base.pages);
-	kfree(mem);
-}
-
-static int
-gk20a_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
-	     u32 memtype, struct nouveau_mem **pmem)
-{
-	struct device *dev = nv_device_base(nv_device(pfb));
-	struct gk20a_mem *mem;
-	u32 type = memtype & 0xff;
-	u32 npages, order;
-	int i;
-
-	nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
-		 align, ncmin);
-
-	npages = size >> PAGE_SHIFT;
-	if (npages == 0)
-		npages = 1;
-
-	if (align == 0)
-		align = PAGE_SIZE;
-	align >>= PAGE_SHIFT;
-
-	/* round alignment to the next power of 2, if needed */
-	order = fls(align);
-	if ((align & (align - 1)) == 0)
-		order--;
-	align = BIT(order);
-
-	/* ensure returned address is correctly aligned */
-	npages = max(align, npages);
-
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	mem->base.size = npages;
-	mem->base.memtype = type;
-
-	mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
-	if (!mem->base.pages) {
-		kfree(mem);
-		return -ENOMEM;
-	}
-
-	*pmem = &mem->base;
-
-	mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
-					  &mem->handle, GFP_KERNEL);
-	if (!mem->cpuaddr) {
-		nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
-		gk20a_ram_put(pfb, pmem);
-		return -ENOMEM;
-	}
-
-	align <<= PAGE_SHIFT;
-
-	/* alignment check */
-	if (unlikely(mem->handle & (align - 1)))
-		nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
-			&mem->handle, align);
-
-	nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
-		 npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);
-
-	for (i = 0; i < npages; i++)
-		mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);
-
-	mem->base.offset = (u64)mem->base.pages[0];
-
-	return 0;
-}
-
-static int
-gk20a_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 datasize,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_ram *ram;
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-	ram->type = NV_MEM_TYPE_STOLEN;
-	ram->size = get_num_physpages() << PAGE_SHIFT;
-
-	ram->get = gk20a_ram_get;
-	ram->put = gk20a_ram_put;
-
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_ram_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c
deleted file mode 100644
index 4c63635..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct gm107_ram {
-	struct nouveau_ram base;
-};
-
-static int
-gm107_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct gm107_ram *ram;
-	int ret;
-
-	ret = nvc0_ram_create(parent, engine, oclass, 0x021c14, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass
-gm107_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm107_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = nve0_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
deleted file mode 100644
index 1972268..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb/regsnv04.h>
-
-#include "priv.h"
-
-static int
-nv04_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	if (boot0 & 0x00000100) {
-		ram->size  = ((boot0 >> 12) & 0xf) * 2 + 2;
-		ram->size *= 1024 * 1024;
-	} else {
-		switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
-			ram->size = 32 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
-			ram->size = 16 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
-			ram->size = 8 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
-			ram->size = 4 * 1024 * 1024;
-			break;
-		}
-	}
-
-	if ((boot0 & 0x00000038) <= 0x10)
-		ram->type = NV_MEM_TYPE_SGRAM;
-	else
-		ram->type = NV_MEM_TYPE_SDRAM;
-	return 0;
-}
-
-struct nouveau_oclass
-nv04_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
deleted file mode 100644
index 8311f37..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv10_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	u32 cfg0 = nv_rd32(pfb, 0x100200);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	if (cfg0 & 0x00000001)
-		ram->type = NV_MEM_TYPE_DDR1;
-	else
-		ram->type = NV_MEM_TYPE_SDRAM;
-
-	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	return 0;
-}
-
-
-struct nouveau_oclass
-nv10_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv10_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
deleted file mode 100644
index d0caddf..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv1a_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	struct pci_dev *bridge;
-	u32 mem, mib;
-	int ret;
-
-	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
-	if (!bridge) {
-		nv_fatal(pfb, "no bridge device\n");
-		return -ENODEV;
-	}
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	if (nv_device(pfb)->chipset == 0x1a) {
-		pci_read_config_dword(bridge, 0x7c, &mem);
-		mib = ((mem >> 6) & 31) + 1;
-	} else {
-		pci_read_config_dword(bridge, 0x84, &mem);
-		mib = ((mem >> 4) & 127) + 1;
-	}
-
-	ram->type = NV_MEM_TYPE_STOLEN;
-	ram->size = mib * 1024 * 1024;
-	return 0;
-}
-
-struct nouveau_oclass
-nv1a_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv1a_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
deleted file mode 100644
index fdc11bb..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv20_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	u32 pbus1218 = nv_rd32(pfb, 0x001218);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	switch (pbus1218 & 0x00000300) {
-	case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
-	case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
-	}
-	ram->size  = (nv_rd32(pfb, 0x10020c) & 0xff000000);
-	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	ram->tags  = nv_rd32(pfb, 0x100320);
-	return 0;
-}
-
-struct nouveau_oclass
-nv20_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv20_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
deleted file mode 100644
index 7648beb..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-
-#include "nv40.h"
-
-int
-nv40_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nv40_ram *ram = (void *)pfb->ram;
-	struct nvbios_pll pll;
-	int N1, M1, N2, M2;
-	int log2P, ret;
-
-	ret = nvbios_pll_parse(bios, 0x04, &pll);
-	if (ret) {
-		nv_error(pfb, "mclk pll data not found\n");
-		return ret;
-	}
-
-	ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq,
-			    &N1, &M1, &N2, &M2, &log2P);
-	if (ret < 0)
-		return ret;
-
-	ram->ctrl  = 0x80000000 | (log2P << 16);
-	ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
-	if (N2 == M2) {
-		ram->ctrl |= 0x00000100;
-		ram->coef  = (N1 << 8) | M1;
-	} else {
-		ram->ctrl |= 0x40000000;
-		ram->coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
-	}
-
-	return 0;
-}
-
-int
-nv40_ram_prog(struct nouveau_fb *pfb)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nv40_ram *ram = (void *)pfb->ram;
-	struct bit_entry M;
-	u32 crtc_mask = 0;
-	u8  sr1[2];
-	int i;
-
-	/* determine which CRTCs are active, fetch VGA_SR1 for each */
-	for (i = 0; i < 2; i++) {
-		u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000));
-		u32 cnt = 0;
-		do {
-			if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) {
-				nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
-				sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000));
-				if (!(sr1[i] & 0x20))
-					crtc_mask |= (1 << i);
-				break;
-			}
-			udelay(1);
-		} while (cnt++ < 32);
-	}
-
-	/* wait for vblank start on active crtcs, disable memory access */
-	for (i = 0; i < 2; i++) {
-		if (!(crtc_mask & (1 << i)))
-			continue;
-		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
-		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-		nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
-		nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
-	}
-
-	/* prepare ram for reclocking */
-	nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */
-	nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
-	nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
-	nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
-	nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */
-
-	/* change the PLL of each memory partition */
-	nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000);
-	switch (nv_device(pfb)->chipset) {
-	case 0x40:
-	case 0x45:
-	case 0x41:
-	case 0x42:
-	case 0x47:
-		nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl);
-		nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl);
-		nv_wr32(pfb, 0x004048, ram->coef);
-		nv_wr32(pfb, 0x004030, ram->coef);
-	case 0x43:
-	case 0x49:
-	case 0x4b:
-		nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl);
-		nv_wr32(pfb, 0x00403c, ram->coef);
-	default:
-		nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl);
-		nv_wr32(pfb, 0x004024, ram->coef);
-		break;
-	}
-	udelay(100);
-	nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000);
-
-	/* re-enable normal operation of memory controller */
-	nv_wr32(pfb, 0x1002dc, 0x00000000);
-	nv_mask(pfb, 0x100210, 0x80000000, 0x80000000);
-	udelay(100);
-
-	/* execute memory reset script from vbios */
-	if (!bit_entry(bios, 'M', &M)) {
-		struct nvbios_init init = {
-			.subdev = nv_subdev(pfb),
-			.bios = bios,
-			.offset = nv_ro16(bios, M.offset + 0x00),
-			.execute = 1,
-		};
-
-		nvbios_exec(&init);
-	}
-
-	/* make sure we're in vblank (hopefully the same one as before), and
-	 * then re-enable crtc memory access
-	 */
-	for (i = 0; i < 2; i++) {
-		if (!(crtc_mask & (1 << i)))
-			continue;
-		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
-		nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
-		nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]);
-	}
-
-	return 0;
-}
-
-void
-nv40_ram_tidy(struct nouveau_fb *pfb)
-{
-}
-
-static int
-nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nv40_ram *ram;
-	u32 pbus1218 = nv_rd32(pfb, 0x001218);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	switch (pbus1218 & 0x00000300) {
-	case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break;
-	case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break;
-	}
-
-	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	ram->base.tags  =  nv_rd32(pfb, 0x100320);
-	ram->base.calc = nv40_ram_calc;
-	ram->base.prog = nv40_ram_prog;
-	ram->base.tidy = nv40_ram_tidy;
-	return 0;
-}
-
-
-struct nouveau_oclass
-nv40_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
deleted file mode 100644
index d64498a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nv40_ram *ram;
-	u32 pfb474 = nv_rd32(pfb, 0x100474);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	if (pfb474 & 0x00000004)
-		ram->base.type = NV_MEM_TYPE_GDDR3;
-	if (pfb474 & 0x00000002)
-		ram->base.type = NV_MEM_TYPE_DDR2;
-	if (pfb474 & 0x00000001)
-		ram->base.type = NV_MEM_TYPE_DDR1;
-
-	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	ram->base.tags  =  nv_rd32(pfb, 0x100320);
-	ram->base.calc = nv40_ram_calc;
-	ram->base.prog = nv40_ram_prog;
-	ram->base.tidy = nv40_ram_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nv41_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv41_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
deleted file mode 100644
index 089acac..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nv40_ram *ram;
-	u32 pfb474 = nv_rd32(pfb, 0x100474);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	if (pfb474 & 0x00000004)
-		ram->base.type = NV_MEM_TYPE_GDDR3;
-	if (pfb474 & 0x00000002)
-		ram->base.type = NV_MEM_TYPE_DDR2;
-	if (pfb474 & 0x00000001)
-		ram->base.type = NV_MEM_TYPE_DDR1;
-
-	ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	ram->base.calc = nv40_ram_calc;
-	ram->base.prog = nv40_ram_prog;
-	ram->base.tidy = nv40_ram_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nv44_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv44_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
deleted file mode 100644
index baa013a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nv40_ram *ram;
-	u32 pfb914 = nv_rd32(pfb, 0x100914);
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	switch (pfb914 & 0x00000003) {
-	case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break;
-	case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000003: break;
-	}
-
-	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	ram->base.tags  =  nv_rd32(pfb, 0x100320);
-	ram->base.calc = nv40_ram_calc;
-	ram->base.prog = nv40_ram_prog;
-	ram->base.tidy = nv40_ram_tidy;
-	return 0;
-}
-
-struct nouveau_oclass
-nv49_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv49_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
deleted file mode 100644
index 63a6aab..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	ram->type = NV_MEM_TYPE_STOLEN;
-	return 0;
-}
-
-struct nouveau_oclass
-nv4e_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv4e_ram_create,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
deleted file mode 100644
index 64a983c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/perf.h>
-#include <subdev/bios/timing.h>
-#include <subdev/clock/pll.h>
-#include <subdev/fb.h>
-
-#include <core/option.h>
-#include <core/mm.h>
-
-#include "ramseq.h"
-
-#include "nv50.h"
-
-struct nv50_ramseq {
-	struct hwsq base;
-	struct hwsq_reg r_0x002504;
-	struct hwsq_reg r_0x004008;
-	struct hwsq_reg r_0x00400c;
-	struct hwsq_reg r_0x00c040;
-	struct hwsq_reg r_0x100210;
-	struct hwsq_reg r_0x1002d0;
-	struct hwsq_reg r_0x1002d4;
-	struct hwsq_reg r_0x1002dc;
-	struct hwsq_reg r_0x100da0[8];
-	struct hwsq_reg r_0x100e20;
-	struct hwsq_reg r_0x100e24;
-	struct hwsq_reg r_0x611200;
-	struct hwsq_reg r_timing[9];
-	struct hwsq_reg r_mr[4];
-};
-
-struct nv50_ram {
-	struct nouveau_ram base;
-	struct nv50_ramseq hwsq;
-};
-
-#define QFX5800NVA0 1
-
-static int
-nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nv50_ram *ram = (void *)pfb->ram;
-	struct nv50_ramseq *hwsq = &ram->hwsq;
-	struct nvbios_perfE perfE;
-	struct nvbios_pll mpll;
-	struct {
-		u32 data;
-		u8  size;
-	} ramcfg, timing;
-	u8  ver, hdr, cnt, len, strap;
-	int N1, M1, N2, M2, P;
-	int ret, i;
-
-	/* lookup closest matching performance table entry for frequency */
-	i = 0;
-	do {
-		ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
-					   &ramcfg.size, &perfE);
-		if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) ||
-		    (ramcfg.size < 2)) {
-			nv_error(pfb, "invalid/missing perftab entry\n");
-			return -EINVAL;
-		}
-	} while (perfE.memory < freq);
-
-	/* locate specific data set for the attached memory */
-	strap = nvbios_ramcfg_index(nv_subdev(pfb));
-	if (strap >= cnt) {
-		nv_error(pfb, "invalid ramcfg strap\n");
-		return -EINVAL;
-	}
-
-	ramcfg.data += hdr + (strap * ramcfg.size);
-
-	/* lookup memory timings, if bios says they're present */
-	strap = nv_ro08(bios, ramcfg.data + 0x01);
-	if (strap != 0xff) {
-		timing.data = nvbios_timingEe(bios, strap, &ver, &hdr,
-					     &cnt, &len);
-		if (!timing.data || ver != 0x10 || hdr < 0x12) {
-			nv_error(pfb, "invalid/missing timing entry "
-				 "%02x %04x %02x %02x\n",
-				 strap, timing.data, ver, hdr);
-			return -EINVAL;
-		}
-	} else {
-		timing.data = 0;
-	}
-
-	ret = ram_init(hwsq, nv_subdev(pfb));
-	if (ret)
-		return ret;
-
-	ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
-	ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
-	ram_wr32(hwsq, 0x611200, 0x00003300);
-	ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
-	ram_nsec(hwsq, 8000);
-	ram_setf(hwsq, 0x10, 0x00); /* disable fb */
-	ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
-
-	ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
-	ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
-	ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
-	ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
-	ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
-
-	ret = nvbios_pll_parse(bios, 0x004008, &mpll);
-	mpll.vco2.max_freq = 0;
-	if (ret == 0) {
-		ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq,
-				   &N1, &M1, &N2, &M2, &P);
-		if (ret == 0)
-			ret = -EINVAL;
-	}
-
-	if (ret < 0)
-		return ret;
-
-	ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
-	ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200);
-	ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
-	ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) |
-					     (P << 22) | (P << 16));
-#if QFX5800NVA0
-	for (i = 0; i < 8; i++)
-		ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/
-#endif
-	ram_nsec(hwsq, 96000); /*XXX*/
-	ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
-
-	ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
-	ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
-
-	ram_nsec(hwsq, 12000);
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-		ram_nuke(hwsq, mr[0]); /* force update */
-		ram_mask(hwsq, mr[0], 0x000, 0x000);
-		break;
-	case NV_MEM_TYPE_GDDR3:
-		ram_mask(hwsq, mr[2], 0x000, 0x000);
-		ram_nuke(hwsq, mr[0]); /* force update */
-		ram_mask(hwsq, mr[0], 0x000, 0x000);
-		break;
-	default:
-		break;
-	}
-
-	ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/
-	ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/
-
-	ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
-
-#if QFX5800NVA0
-	ram_nuke(hwsq, 0x100e24);
-	ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000);
-	ram_nuke(hwsq, 0x100e20);
-	ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000);
-#endif
-
-	ram_mask(hwsq, mr[0], 0x100, 0x100);
-	ram_mask(hwsq, mr[0], 0x100, 0x000);
-
-	ram_setf(hwsq, 0x10, 0x01); /* enable fb */
-	ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
-	ram_wr32(hwsq, 0x611200, 0x00003330);
-	ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
-	return 0;
-}
-
-static int
-nv50_ram_prog(struct nouveau_fb *pfb)
-{
-	struct nouveau_device *device = nv_device(pfb);
-	struct nv50_ram *ram = (void *)pfb->ram;
-	struct nv50_ramseq *hwsq = &ram->hwsq;
-
-	ram_exec(hwsq, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
-	return 0;
-}
-
-static void
-nv50_ram_tidy(struct nouveau_fb *pfb)
-{
-	struct nv50_ram *ram = (void *)pfb->ram;
-	struct nv50_ramseq *hwsq = &ram->hwsq;
-	ram_exec(hwsq, false);
-}
-
-void
-__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
-{
-	struct nouveau_mm_node *this;
-
-	while (!list_empty(&mem->regions)) {
-		this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
-
-		list_del(&this->rl_entry);
-		nouveau_mm_free(&pfb->vram, &this);
-	}
-
-	nouveau_mm_free(&pfb->tags, &mem->tag);
-}
-
-void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
-	struct nouveau_mem *mem = *pmem;
-
-	*pmem = NULL;
-	if (unlikely(mem == NULL))
-		return;
-
-	mutex_lock(&pfb->base.mutex);
-	__nv50_ram_put(pfb, mem);
-	mutex_unlock(&pfb->base.mutex);
-
-	kfree(mem);
-}
-
-int
-nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
-	     u32 memtype, struct nouveau_mem **pmem)
-{
-	struct nouveau_mm *heap = &pfb->vram;
-	struct nouveau_mm *tags = &pfb->tags;
-	struct nouveau_mm_node *r;
-	struct nouveau_mem *mem;
-	int comp = (memtype & 0x300) >> 8;
-	int type = (memtype & 0x07f);
-	int back = (memtype & 0x800);
-	int min, max, ret;
-
-	max = (size >> 12);
-	min = ncmin ? (ncmin >> 12) : max;
-	align >>= 12;
-
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	mutex_lock(&pfb->base.mutex);
-	if (comp) {
-		if (align == 16) {
-			int n = (max >> 4) * comp;
-
-			ret = nouveau_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
-			if (ret)
-				mem->tag = NULL;
-		}
-
-		if (unlikely(!mem->tag))
-			comp = 0;
-	}
-
-	INIT_LIST_HEAD(&mem->regions);
-	mem->memtype = (comp << 7) | type;
-	mem->size = max;
-
-	type = nv50_fb_memtype[type];
-	do {
-		if (back)
-			ret = nouveau_mm_tail(heap, 0, type, max, min, align, &r);
-		else
-			ret = nouveau_mm_head(heap, 0, type, max, min, align, &r);
-		if (ret) {
-			mutex_unlock(&pfb->base.mutex);
-			pfb->ram->put(pfb, &mem);
-			return ret;
-		}
-
-		list_add_tail(&r->rl_entry, &mem->regions);
-		max -= r->length;
-	} while (max);
-	mutex_unlock(&pfb->base.mutex);
-
-	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
-	mem->offset = (u64)r->offset << 12;
-	*pmem = mem;
-	return 0;
-}
-
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
-{
-	int colbits, rowbitsa, rowbitsb, banks;
-	u64 rowsize, predicted;
-	u32 r0, r4, rt, rblock_size;
-
-	r0 = nv_rd32(pfb, 0x100200);
-	r4 = nv_rd32(pfb, 0x100204);
-	rt = nv_rd32(pfb, 0x100250);
-	nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt,
-			nv_rd32(pfb, 0x001540));
-
-	colbits  =  (r4 & 0x0000f000) >> 12;
-	rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
-	rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
-	banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
-	rowsize = ram->parts * banks * (1 << colbits) * 8;
-	predicted = rowsize << rowbitsa;
-	if (r0 & 0x00000004)
-		predicted += rowsize << rowbitsb;
-
-	if (predicted != ram->size) {
-		nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
-			(u32)(ram->size >> 20));
-	}
-
-	rblock_size = rowsize;
-	if (rt & 1)
-		rblock_size *= 3;
-
-	nv_debug(pfb, "rblock %d bytes\n", rblock_size);
-	return rblock_size;
-}
-
-int
-nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
-	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_ram *ram;
-	int ret;
-
-	ret = nouveau_ram_create_(parent, engine, oclass, length, pobject);
-	ram = *pobject;
-	if (ret)
-		return ret;
-
-	ram->size = nv_rd32(pfb, 0x10020c);
-	ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
-
-	ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
-	ram->parts = hweight8(ram->part_mask);
-
-	switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
-	case 0: ram->type = NV_MEM_TYPE_DDR1; break;
-	case 1:
-		if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
-			ram->type = NV_MEM_TYPE_DDR3;
-		else
-			ram->type = NV_MEM_TYPE_DDR2;
-		break;
-	case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
-	case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
-	case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
-	default:
-		break;
-	}
-
-	ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
-			      (rsvd_head + rsvd_tail),
-			      nv50_fb_vram_rblock(pfb, ram) >> 12);
-	if (ret)
-		return ret;
-
-	ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
-	ram->tags  =  nv_rd32(pfb, 0x100320);
-	ram->get = nv50_ram_get;
-	ram->put = nv50_ram_put;
-	return 0;
-}
-
-static int
-nv50_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 datasize,
-	      struct nouveau_object **pobject)
-{
-	struct nv50_ram *ram;
-	int ret, i;
-
-	ret = nv50_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-	case NV_MEM_TYPE_GDDR3:
-		ram->base.calc = nv50_ram_calc;
-		ram->base.prog = nv50_ram_prog;
-		ram->base.tidy = nv50_ram_tidy;
-		break;
-	default:
-		nv_warn(ram, "reclocking of this ram type unsupported\n");
-		return 0;
-	}
-
-	ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
-	ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
-	ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
-	ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
-	ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
-	ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
-	ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
-	ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
-	for (i = 0; i < 8; i++)
-		ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04));
-	ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
-	ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
-	ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
-
-	for (i = 0; i < 9; i++)
-		ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
-
-	if (ram->base.ranks > 1) {
-		ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
-		ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
-		ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
-		ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
-	} else {
-		ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
-		ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
-		ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
-		ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-nv50_ram_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = _nouveau_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
deleted file mode 100644
index 3b38a53..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/M0205.h>
-#include <subdev/bios/timing.h>
-
-#include <subdev/clock/nva3.h>
-#include <subdev/clock/pll.h>
-
-#include <subdev/gpio.h>
-
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-
-#include <core/option.h>
-
-#include "ramfuc.h"
-
-#include "nv50.h"
-
-/* XXX: Remove when memx gains GPIO support */
-extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
-
-struct nva3_ramfuc {
-	struct ramfuc base;
-	struct ramfuc_reg r_0x001610;
-	struct ramfuc_reg r_0x001700;
-	struct ramfuc_reg r_0x002504;
-	struct ramfuc_reg r_0x004000;
-	struct ramfuc_reg r_0x004004;
-	struct ramfuc_reg r_0x004018;
-	struct ramfuc_reg r_0x004128;
-	struct ramfuc_reg r_0x004168;
-	struct ramfuc_reg r_0x100080;
-	struct ramfuc_reg r_0x100200;
-	struct ramfuc_reg r_0x100210;
-	struct ramfuc_reg r_0x100220[9];
-	struct ramfuc_reg r_0x100264;
-	struct ramfuc_reg r_0x1002d0;
-	struct ramfuc_reg r_0x1002d4;
-	struct ramfuc_reg r_0x1002dc;
-	struct ramfuc_reg r_0x10053c;
-	struct ramfuc_reg r_0x1005a0;
-	struct ramfuc_reg r_0x1005a4;
-	struct ramfuc_reg r_0x100700;
-	struct ramfuc_reg r_0x100714;
-	struct ramfuc_reg r_0x100718;
-	struct ramfuc_reg r_0x10071c;
-	struct ramfuc_reg r_0x100720;
-	struct ramfuc_reg r_0x100760;
-	struct ramfuc_reg r_0x1007a0;
-	struct ramfuc_reg r_0x1007e0;
-	struct ramfuc_reg r_0x100da0;
-	struct ramfuc_reg r_0x10f804;
-	struct ramfuc_reg r_0x1110e0;
-	struct ramfuc_reg r_0x111100;
-	struct ramfuc_reg r_0x111104;
-	struct ramfuc_reg r_0x1111e0;
-	struct ramfuc_reg r_0x111400;
-	struct ramfuc_reg r_0x611200;
-	struct ramfuc_reg r_mr[4];
-	struct ramfuc_reg r_gpioFBVREF;
-};
-
-struct nva3_ltrain {
-	enum {
-		NVA3_TRAIN_UNKNOWN,
-		NVA3_TRAIN_UNSUPPORTED,
-		NVA3_TRAIN_ONCE,
-		NVA3_TRAIN_EXEC,
-		NVA3_TRAIN_DONE
-	} state;
-	u32 r_100720;
-	u32 r_1111e0;
-	u32 r_111400;
-	struct nouveau_mem *mem;
-};
-
-struct nva3_ram {
-	struct nouveau_ram base;
-	struct nva3_ramfuc fuc;
-	struct nva3_ltrain ltrain;
-};
-
-void
-nva3_link_train_calc(u32 *vals, struct nva3_ltrain *train)
-{
-	int i, lo, hi;
-	u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
-
-	for (i = 0; i < 8; i++) {
-		for (lo = 0; lo < 0x40; lo++) {
-			if (!(vals[lo] & 0x80000000))
-				continue;
-			if (vals[lo] & (0x101 << i))
-				break;
-		}
-
-		if (lo == 0x40)
-			return;
-
-		for (hi = lo + 1; hi < 0x40; hi++) {
-			if (!(vals[lo] & 0x80000000))
-				continue;
-			if (!(vals[hi] & (0x101 << i))) {
-				hi--;
-				break;
-			}
-		}
-
-		median[i] = ((hi - lo) >> 1) + lo;
-		bins[(median[i] & 0xf0) >> 4]++;
-		median[i] += 0x30;
-	}
-
-	/* Find the best value for 0x1111e0 */
-	for (i = 0; i < 4; i++) {
-		if (bins[i] > qty) {
-			bin = i + 3;
-			qty = bins[i];
-		}
-	}
-
-	train->r_100720 = 0;
-	for (i = 0; i < 8; i++) {
-		median[i] = max(median[i], (u8) (bin << 4));
-		median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
-
-		train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
-	}
-
-	train->r_1111e0 = 0x02000000 | (bin * 0x101);
-	train->r_111400 = 0x0;
-}
-
-/*
- * Link training for (at least) DDR3
- */
-int
-nva3_link_train(struct nouveau_fb *pfb)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nouveau_clock *clk = nouveau_clock(pfb);
-	struct nva3_ltrain *train = &ram->ltrain;
-	struct nouveau_device *device = nv_device(pfb);
-	struct nva3_ramfuc *fuc = &ram->fuc;
-	u32 *result, r1700;
-	int ret, i;
-	struct nvbios_M0205T M0205T = { 0 };
-	u8 ver, hdr, cnt, len, snr, ssz;
-	unsigned int clk_current;
-	unsigned long flags;
-	unsigned long *f = &flags;
-
-	if (nouveau_boolopt(device->cfgopt, "NvMemExec", true) != true)
-		return -ENOSYS;
-
-	/* XXX: Multiple partitions? */
-	result = kmalloc(64 * sizeof(u32), GFP_KERNEL);
-	if (!result)
-		return -ENOMEM;
-
-	train->state = NVA3_TRAIN_EXEC;
-
-	/* Clock speeds for training and back */
-	nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
-	if (M0205T.freq == 0)
-		return -ENOENT;
-
-	clk_current = clk->read(clk, nv_clk_src_mem);
-
-	ret = nva3_clock_pre(clk, f);
-	if (ret)
-		goto out;
-
-	/* First: clock up/down */
-	ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000);
-	if (ret)
-		goto out;
-
-	/* Do this *after* calc, eliminates write in script */
-	nv_wr32(pfb, 0x111400, 0x00000000);
-	/* XXX: Magic writes that improve train reliability? */
-	nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000);
-	nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000);
-	nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000);
-	nv_wr32(pfb, 0x100c04, 0x00000400);
-
-	/* Now the training script */
-	r1700 = ram_rd32(fuc, 0x001700);
-
-	ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
-	ram_wr32(fuc, 0x611200, 0x3300);
-	ram_wait_vblank(fuc);
-	ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
-	ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
-	ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
-	ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
-	ram_wr32(fuc, 0x001700, 0x00000000);
-
-	ram_train(fuc);
-
-	/* Reset */
-	ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
-	ram_wr32(fuc, 0x10053c, 0x0);
-	ram_wr32(fuc, 0x100720, train->r_100720);
-	ram_wr32(fuc, 0x1111e0, train->r_1111e0);
-	ram_wr32(fuc, 0x111400, train->r_111400);
-	ram_nuke(fuc, 0x100080);
-	ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
-	ram_nsec(fuc, 1000);
-
-	ram_wr32(fuc, 0x001700, r1700);
-	ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
-	ram_wr32(fuc, 0x611200, 0x3330);
-	ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
-
-	ram_exec(fuc, true);
-
-	ram->base.calc(pfb, clk_current);
-	ram_exec(fuc, true);
-
-	/* Post-processing, avoids flicker */
-	nv_mask(pfb, 0x616308, 0x10, 0x10);
-	nv_mask(pfb, 0x616b08, 0x10, 0x10);
-
-	nva3_clock_post(clk, f);
-
-	ram_train_result(pfb, result, 64);
-	for (i = 0; i < 64; i++)
-		nv_debug(pfb, "Train: %08x", result[i]);
-	nva3_link_train_calc(result, train);
-
-	nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720,
-			train->r_1111e0, train->r_111400);
-
-	kfree(result);
-
-	train->state = NVA3_TRAIN_DONE;
-
-	return ret;
-
-out:
-	if(ret == -EBUSY)
-		f = NULL;
-
-	train->state = NVA3_TRAIN_UNSUPPORTED;
-
-	nva3_clock_post(clk, f);
-	return ret;
-}
-
-int
-nva3_link_train_init(struct nouveau_fb *pfb)
-{
-	static const u32 pattern[16] = {
-		0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
-		0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
-		0x33333333, 0x55555555, 0x77777777, 0x66666666,
-		0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
-	};
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nva3_ltrain *train = &ram->ltrain;
-	struct nouveau_mem *mem;
-	struct nvbios_M0205E M0205E;
-	u8 ver, hdr, cnt, len;
-	u32 r001700;
-	int ret, i = 0;
-
-	train->state = NVA3_TRAIN_UNSUPPORTED;
-
-	/* We support type "5"
-	 * XXX: training pattern table appears to be unused for this routine */
-	if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
-		return -ENOENT;
-
-	if (M0205E.type != 5)
-		return 0;
-
-	train->state = NVA3_TRAIN_ONCE;
-
-	ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem);
-	if (ret)
-		return ret;
-
-	mem = ram->ltrain.mem;
-
-	nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16));
-	nv_wr32(pfb, 0x1005a8, 0x0000ffff);
-	nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
-
-	for (i = 0; i < 0x30; i++) {
-		nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
-		nv_wr32(pfb, 0x10f900, pattern[i % 16]);
-	}
-
-	for (i = 0; i < 0x30; i++) {
-		nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
-		nv_wr32(pfb, 0x10f920, pattern[i % 16]);
-	}
-
-	/* And upload the pattern */
-	r001700 = nv_rd32(pfb, 0x1700);
-	nv_wr32(pfb, 0x1700, mem->offset >> 16);
-	for (i = 0; i < 16; i++)
-		nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]);
-	for (i = 0; i < 16; i++)
-		nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]);
-	nv_wr32(pfb, 0x1700, r001700);
-
-	train->r_100720 = nv_rd32(pfb, 0x100720);
-	train->r_1111e0 = nv_rd32(pfb, 0x1111e0);
-	train->r_111400 = nv_rd32(pfb, 0x111400);
-
-	return 0;
-}
-
-void
-nva3_link_train_fini(struct nouveau_fb *pfb)
-{
-	struct nva3_ram *ram = (void *)pfb->ram;
-
-	if (ram->ltrain.mem)
-		pfb->ram->put(pfb, &ram->ltrain.mem);
-}
-
-/*
- * RAM reclocking
- */
-#define T(t) cfg->timing_10_##t
-static int
-nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
-{
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nvbios_ramcfg *cfg = &ram->base.target.bios;
-	int tUNK_base, tUNK_40_0, prevCL;
-	u32 cur2, cur3, cur7, cur8;
-
-	cur2 = nv_rd32(pfb, 0x100228);
-	cur3 = nv_rd32(pfb, 0x10022c);
-	cur7 = nv_rd32(pfb, 0x10023c);
-	cur8 = nv_rd32(pfb, 0x100240);
-
-
-	switch ((!T(CWL)) * ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-		T(CWL) = T(CL) - 1;
-		break;
-	case NV_MEM_TYPE_GDDR3:
-		T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
-		break;
-	}
-
-	prevCL = (cur3 & 0x000000ff) + 1;
-	tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
-
-	timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
-	timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
-		    max_t(u8,T(18), 1) << 16 |
-		    (T(WTR) + 1 + T(CWL)) << 8 |
-		    (5 + T(CL) - T(CWL));
-	timing[2] = (T(CWL) - 1) << 24 |
-		    (T(RRD) << 16) |
-		    (T(RCDWR) << 8) |
-		    T(RCDRD);
-	timing[3] = (cur3 & 0x00ff0000) |
-		    (0x30 + T(CL)) << 24 |
-		    (0xb + T(CL)) << 8 |
-		    (T(CL) - 1);
-	timing[4] = T(20) << 24 |
-		    T(21) << 16 |
-		    T(13) << 8 |
-		    T(13);
-	timing[5] = T(RFC) << 24 |
-		    max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
-		    max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
-		    T(RP);
-	timing[6] = (0x5a + T(CL)) << 16 |
-		    max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
-		    (0x50 + T(CL) - T(CWL));
-	timing[7] = (cur7 & 0xff000000) |
-		    ((tUNK_base + T(CL)) << 16) |
-		    0x202;
-	timing[8] = cur8 & 0xffffff00;
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-	case NV_MEM_TYPE_GDDR3:
-		tUNK_40_0 = prevCL - (cur8 & 0xff);
-		if (tUNK_40_0 > 0)
-			timing[8] |= T(CL);
-		break;
-	default:
-		break;
-	}
-
-	nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n",
-			timing[0], timing[1], timing[2], timing[3]);
-	nv_debug(pfb, "  230: %08x %08x %08x %08x\n",
-			timing[4], timing[5], timing[6], timing[7]);
-	nv_debug(pfb, "  240: %08x\n", timing[8]);
-	return 0;
-}
-#undef T
-
-static void
-nouveau_sddr2_dll_reset(struct nva3_ramfuc *fuc)
-{
-	ram_mask(fuc, mr[0], 0x100, 0x100);
-	ram_nsec(fuc, 1000);
-	ram_mask(fuc, mr[0], 0x100, 0x000);
-	ram_nsec(fuc, 1000);
-}
-
-static void
-nouveau_sddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
-{
-	u32 mr1_old = ram_rd32(fuc, mr[1]);
-
-	if (!(mr1_old & 0x1)) {
-		ram_wr32(fuc, 0x1002d4, 0x00000001);
-		ram_wr32(fuc, mr[1], mr[1]);
-		ram_nsec(fuc, 1000);
-	}
-}
-
-static void
-nouveau_gddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
-{
-	u32 mr1_old = ram_rd32(fuc, mr[1]);
-
-	if (!(mr1_old & 0x40)) {
-		ram_wr32(fuc, mr[1], mr[1]);
-		ram_nsec(fuc, 1000);
-	}
-}
-
-static void
-nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
-{
-	ram_wr32(fuc, 0x004004, mclk->pll);
-	ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
-	ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
-	ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
-	ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
-}
-
-static void
-nva3_ram_fbvref(struct nva3_ramfuc *fuc, u32 val)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(fuc->base.pfb);
-	struct dcb_gpio_func func;
-	u32 reg, sh, gpio_val;
-	int ret;
-
-	if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
-		ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
-		if (ret)
-			return;
-
-		nv50_gpio_location(func.line, &reg, &sh);
-		gpio_val = ram_rd32(fuc, gpioFBVREF);
-		if (gpio_val & (8 << sh))
-			val = !val;
-
-		ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
-		ram_nsec(fuc, 20000);
-	}
-}
-
-static int
-nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nva3_ramfuc *fuc = &ram->fuc;
-	struct nva3_ltrain *train = &ram->ltrain;
-	struct nva3_clock_info mclk;
-	struct nouveau_ram_data *next;
-	u8  ver, hdr, cnt, len, strap;
-	u32 data;
-	u32 r004018, r100760, r100da0, r111100, ctrl;
-	u32 unk714, unk718, unk71c;
-	int ret, i;
-	u32 timing[9];
-	bool pll2pll;
-
-	next = &ram->base.target;
-	next->freq = freq;
-	ram->base.next = next;
-
-	if (ram->ltrain.state == NVA3_TRAIN_ONCE)
-		nva3_link_train(pfb);
-
-	/* lookup memory config data relevant to the target frequency */
-	i = 0;
-	data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
-				      &next->bios);
-	if (!data || ver != 0x10 || hdr < 0x05) {
-		nv_error(pfb, "invalid/missing rammap entry\n");
-		return -EINVAL;
-	}
-
-	/* locate specific data set for the attached memory */
-	strap = nvbios_ramcfg_index(nv_subdev(pfb));
-	if (strap >= cnt) {
-		nv_error(pfb, "invalid ramcfg strap\n");
-		return -EINVAL;
-	}
-
-	data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
-			       &ver, &hdr, &next->bios);
-	if (!data || ver != 0x10 || hdr < 0x09) {
-		nv_error(pfb, "invalid/missing ramcfg entry\n");
-		return -EINVAL;
-	}
-
-	/* lookup memory timings, if bios says they're present */
-	if (next->bios.ramcfg_timing != 0xff) {
-		data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
-				       &ver, &hdr, &cnt, &len,
-				       &next->bios);
-		if (!data || ver != 0x10 || hdr < 0x17) {
-			nv_error(pfb, "invalid/missing timing entry\n");
-			return -EINVAL;
-		}
-	}
-
-	ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
-	if (ret < 0) {
-		nv_error(pfb, "failed mclk calculation\n");
-		return ret;
-	}
-
-	nva3_ram_timing_calc(pfb, timing);
-
-	ret = ram_init(fuc, pfb);
-	if (ret)
-		return ret;
-
-	/* Determine ram-specific MR values */
-	ram->base.mr[0] = ram_rd32(fuc, mr[0]);
-	ram->base.mr[1] = ram_rd32(fuc, mr[1]);
-	ram->base.mr[2] = ram_rd32(fuc, mr[2]);
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-		ret = nouveau_sddr2_calc(&ram->base);
-		break;
-	case NV_MEM_TYPE_DDR3:
-		ret = nouveau_sddr3_calc(&ram->base);
-		break;
-	case NV_MEM_TYPE_GDDR3:
-		ret = nouveau_gddr3_calc(&ram->base);
-		break;
-	default:
-		ret = -ENOSYS;
-		break;
-	}
-
-	if (ret)
-		return ret;
-
-	/* XXX: where the fuck does 750MHz come from? */
-	if (freq <= 750000) {
-		r004018 = 0x10000000;
-		r100760 = 0x22222222;
-		r100da0 = 0x00000010;
-	} else {
-		r004018 = 0x00000000;
-		r100760 = 0x00000000;
-		r100da0 = 0x00000000;
-	}
-
-	if (!next->bios.ramcfg_10_DLLoff)
-		r004018 |= 0x00004000;
-
-	/* pll2pll requires to switch to a safe clock first */
-	ctrl = ram_rd32(fuc, 0x004000);
-	pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
-
-	/* Pre, NVIDIA does this outside the script */
-	if (next->bios.ramcfg_10_02_10) {
-		ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
-	} else {
-		ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
-		ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
-	}
-	/* Always disable this bit during reclock */
-	ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
-
-	/* If switching from non-pll to pll, lock before disabling FB */
-	if (mclk.pll && !pll2pll) {
-		ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
-		nva3_ram_lock_pll(fuc, &mclk);
-	}
-
-	/* Start with disabling some CRTCs and PFIFO? */
-	ram_wait_vblank(fuc);
-	ram_wr32(fuc, 0x611200, 0x3300);
-	ram_mask(fuc, 0x002504, 0x1, 0x1);
-	ram_nsec(fuc, 10000);
-	ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
-	ram_block(fuc);
-	ram_nsec(fuc, 2000);
-
-	if (!next->bios.ramcfg_10_02_10) {
-		if (ram->base.type == NV_MEM_TYPE_GDDR3)
-			ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
-		else
-			ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
-	}
-
-	/* If we're disabling the DLL, do it now */
-	switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
-	case NV_MEM_TYPE_DDR3:
-		nouveau_sddr3_dll_disable(fuc, ram->base.mr);
-		break;
-	case NV_MEM_TYPE_GDDR3:
-		nouveau_gddr3_dll_disable(fuc, ram->base.mr);
-		break;
-	}
-
-	if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
-		nva3_ram_fbvref(fuc, 0);
-
-	/* Brace RAM for impact */
-	ram_wr32(fuc, 0x1002d4, 0x00000001);
-	ram_wr32(fuc, 0x1002d0, 0x00000001);
-	ram_wr32(fuc, 0x1002d0, 0x00000001);
-	ram_wr32(fuc, 0x100210, 0x00000000);
-	ram_wr32(fuc, 0x1002dc, 0x00000001);
-	ram_nsec(fuc, 2000);
-
-	if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000)
-		ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
-
-	/* Fiddle with clocks */
-	/* There's 4 scenario's
-	 * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
-	 * clk->pll: Set up new PLL, switch
-	 * pll->clk: Set up clock, switch
-	 * clk->clk: Overwrite ctrl and other bits, switch */
-
-	/* Switch to regular clock - 324MHz */
-	if (pll2pll) {
-		ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
-		ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
-		ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
-		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
-		ram_wr32(fuc, 0x004018, 0x00001000);
-		nva3_ram_lock_pll(fuc, &mclk);
-	}
-
-	if (mclk.pll) {
-		ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
-		ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
-		ram_wr32(fuc, 0x100da0, r100da0);
-	} else {
-		ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
-		ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
-		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
-		ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
-		ram_wr32(fuc, 0x100da0, r100da0);
-	}
-	ram_nsec(fuc, 20000);
-
-	if (next->bios.rammap_10_04_08) {
-		ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
-					next->bios.ramcfg_10_05 << 8 |
-					next->bios.ramcfg_10_05);
-		ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
-					next->bios.ramcfg_10_07);
-		ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
-					next->bios.ramcfg_10_03_0f << 16 |
-					next->bios.ramcfg_10_09_0f |
-					0x80000000);
-		ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
-	} else {
-		if (train->state == NVA3_TRAIN_DONE) {
-			ram_wr32(fuc, 0x100080, 0x1020);
-			ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
-			ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
-			ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
-		}
-		ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
-		ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
-		ram_mask(fuc, 0x100760, 0x22222222, r100760);
-		ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
-		ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
-	}
-
-	if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) {
-		ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
-	}
-
-	/* Final switch */
-	if (mclk.pll) {
-		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
-		ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
-	}
-
-	ram_wr32(fuc, 0x1002dc, 0x00000000);
-	ram_wr32(fuc, 0x1002d4, 0x00000001);
-	ram_wr32(fuc, 0x100210, 0x80000000);
-	ram_nsec(fuc, 2000);
-
-	/* Set RAM MR parameters and timings */
-	for (i = 2; i >= 0; i--) {
-		if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
-			ram_wr32(fuc, mr[i], ram->base.mr[i]);
-			ram_nsec(fuc, 1000);
-		}
-	}
-
-	ram_wr32(fuc, 0x100220[3], timing[3]);
-	ram_wr32(fuc, 0x100220[1], timing[1]);
-	ram_wr32(fuc, 0x100220[6], timing[6]);
-	ram_wr32(fuc, 0x100220[7], timing[7]);
-	ram_wr32(fuc, 0x100220[2], timing[2]);
-	ram_wr32(fuc, 0x100220[4], timing[4]);
-	ram_wr32(fuc, 0x100220[5], timing[5]);
-	ram_wr32(fuc, 0x100220[0], timing[0]);
-	ram_wr32(fuc, 0x100220[8], timing[8]);
-
-	/* Misc */
-	ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
-
-	/* XXX: A lot of "chipset"/"ram type" specific stuff...? */
-	unk714  = ram_rd32(fuc, 0x100714) & ~0xf0000130;
-	unk718  = ram_rd32(fuc, 0x100718) & ~0x00000100;
-	unk71c  = ram_rd32(fuc, 0x10071c) & ~0x00000100;
-	r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
-
-	if (next->bios.ramcfg_10_02_04) {
-		switch (ram->base.type) {
-		case NV_MEM_TYPE_DDR3:
-			if (nv_device(pfb)->chipset != 0xa8)
-				r111100 |= 0x00000004;
-			/* no break */
-		case NV_MEM_TYPE_DDR2:
-			r111100 |= 0x08000000;
-			break;
-		default:
-			break;
-		}
-	} else {
-		switch (ram->base.type) {
-		case NV_MEM_TYPE_DDR2:
-			r111100 |= 0x1a800000;
-			unk714  |= 0x00000010;
-			break;
-		case NV_MEM_TYPE_DDR3:
-			if (nv_device(pfb)->chipset == 0xa8) {
-				r111100 |=  0x08000000;
-			} else {
-				r111100 &= ~0x00000004;
-				r111100 |=  0x12800000;
-			}
-			unk714  |= 0x00000010;
-			break;
-		case NV_MEM_TYPE_GDDR3:
-			r111100 |= 0x30000000;
-			unk714  |= 0x00000020;
-			break;
-		default:
-			break;
-		}
-	}
-
-	unk714 |= (next->bios.ramcfg_10_04_01) << 8;
-
-	if (next->bios.ramcfg_10_02_20)
-		unk714 |= 0xf0000000;
-	if (next->bios.ramcfg_10_02_02)
-		unk718 |= 0x00000100;
-	if (next->bios.ramcfg_10_02_01)
-		unk71c |= 0x00000100;
-	if (next->bios.timing_10_24 != 0xff) {
-		unk718 &= ~0xf0000000;
-		unk718 |= next->bios.timing_10_24 << 28;
-	}
-	if (next->bios.ramcfg_10_02_10)
-		r111100 &= ~0x04020000;
-
-	ram_mask(fuc, 0x100714, 0xffffffff, unk714);
-	ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
-	ram_mask(fuc, 0x100718, 0xffffffff, unk718);
-	ram_mask(fuc, 0x111100, 0xffffffff, r111100);
-
-	if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
-		nva3_ram_fbvref(fuc, 1);
-
-	/* Reset DLL */
-	if (!next->bios.ramcfg_10_DLLoff)
-		nouveau_sddr2_dll_reset(fuc);
-
-	if (ram->base.type == NV_MEM_TYPE_GDDR3) {
-		ram_nsec(fuc, 31000);
-	} else {
-		ram_nsec(fuc, 14000);
-	}
-
-	if (ram->base.type == NV_MEM_TYPE_DDR3) {
-		ram_wr32(fuc, 0x100264, 0x1);
-		ram_nsec(fuc, 2000);
-	}
-
-	ram_nuke(fuc, 0x100700);
-	ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
-	ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
-
-	/* Re-enable FB */
-	ram_unblock(fuc);
-	ram_wr32(fuc, 0x611200, 0x3330);
-
-	/* Post fiddlings */
-	if (next->bios.rammap_10_04_02)
-		ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
-	if (next->bios.ramcfg_10_02_10) {
-		ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
-		ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
-	} else {
-		ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
-	}
-
-	if (mclk.pll) {
-		ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
-	} else {
-		ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
-	}
-
-	return 0;
-}
-
-static int
-nva3_ram_prog(struct nouveau_fb *pfb)
-{
-	struct nouveau_device *device = nv_device(pfb);
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nva3_ramfuc *fuc = &ram->fuc;
-	bool exec = nouveau_boolopt(device->cfgopt, "NvMemExec", true);
-
-	if (exec) {
-		nv_mask(pfb, 0x001534, 0x2, 0x2);
-
-		ram_exec(fuc, true);
-
-		/* Post-processing, avoids flicker */
-		nv_mask(pfb, 0x002504, 0x1, 0x0);
-		nv_mask(pfb, 0x001534, 0x2, 0x0);
-
-		nv_mask(pfb, 0x616308, 0x10, 0x10);
-		nv_mask(pfb, 0x616b08, 0x10, 0x10);
-	} else {
-		ram_exec(fuc, false);
-	}
-	return 0;
-}
-
-static void
-nva3_ram_tidy(struct nouveau_fb *pfb)
-{
-	struct nva3_ram *ram = (void *)pfb->ram;
-	struct nva3_ramfuc *fuc = &ram->fuc;
-	ram_exec(fuc, false);
-}
-
-static int
-nva3_ram_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object->parent;
-	struct nva3_ram   *ram = (void *)object;
-	int ret;
-
-	ret = nouveau_ram_init(&ram->base);
-	if (ret)
-		return ret;
-
-	nva3_link_train_init(pfb);
-
-	return 0;
-}
-
-static int
-nva3_ram_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_fb *pfb = (void *)object->parent;
-
-	if (!suspend)
-		nva3_link_train_fini(pfb);
-
-	return 0;
-}
-
-static int
-nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 datasize,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_gpio *gpio = nouveau_gpio(pfb);
-	struct dcb_gpio_func func;
-	struct nva3_ram *ram;
-	int ret, i;
-	u32 reg, shift;
-
-	ret = nv50_ram_create(parent, engine, oclass, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR2:
-	case NV_MEM_TYPE_DDR3:
-	case NV_MEM_TYPE_GDDR3:
-		ram->base.calc = nva3_ram_calc;
-		ram->base.prog = nva3_ram_prog;
-		ram->base.tidy = nva3_ram_tidy;
-		break;
-	default:
-		nv_warn(ram, "reclocking of this ram type unsupported\n");
-		return 0;
-	}
-
-	ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
-	ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
-	ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
-	ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
-	ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
-	ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
-	ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
-	ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
-	ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
-	ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
-	ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
-	for (i = 0; i < 9; i++)
-		ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
-	ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
-	ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
-	ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
-	ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
-	ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
-	ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
-	ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
-	ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
-	ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
-	ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
-	ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
-	ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
-	ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
-	ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
-	ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
-	ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
-	ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
-	ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
-	ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
-	ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
-	ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
-	ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
-	ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
-
-	if (ram->base.ranks > 1) {
-		ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
-		ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
-		ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
-		ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
-	} else {
-		ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
-		ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
-		ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
-		ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
-	}
-
-	ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
-	if (ret == 0) {
-		nv50_gpio_location(func.line, &reg, &shift);
-		ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-nva3_ram_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = nva3_ram_init,
-		.fini = nva3_ram_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
deleted file mode 100644
index 033a8e9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nvaa_ram_priv {
-	struct nouveau_ram base;
-	u64 poller_base;
-};
-
-static int
-nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 datasize,
-	      struct nouveau_object **pobject)
-{
-	u32 rsvd_head = ( 256 * 1024); /* vga memory */
-	u32 rsvd_tail = (1024 * 1024); /* vbios etc */
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nvaa_ram_priv *priv;
-	int ret;
-
-	ret = nouveau_ram_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.type   = NV_MEM_TYPE_STOLEN;
-	priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
-	priv->base.size   = (u64)nv_rd32(pfb, 0x100e14) << 12;
-
-	rsvd_tail += 0x1000;
-	priv->poller_base = priv->base.size - rsvd_tail;
-
-	ret = nouveau_mm_init(&pfb->vram, rsvd_head >> 12,
-			      (priv->base.size  - (rsvd_head + rsvd_tail)) >> 12,
-			      1);
-	if (ret)
-		return ret;
-
-	priv->base.get = nv50_ram_get;
-	priv->base.put = nv50_ram_put;
-	return 0;
-}
-
-static int
-nvaa_ram_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	struct nvaa_ram_priv *priv = (void *)object;
-	int ret;
-	u64 dniso, hostnb, flush;
-
-	ret = nouveau_ram_init(&priv->base);
-	if (ret)
-		return ret;
-
-	dniso  = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1;
-	hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1;
-	flush  = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1;
-
-	/* Enable NISO poller for various clients and set their associated
-	 * read address, only for MCP77/78 and MCP79/7A. (fd#25701)
-	 */
-	nv_wr32(pfb, 0x100c18, dniso);
-	nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001);
-	nv_wr32(pfb, 0x100c1c, hostnb);
-	nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002);
-	nv_wr32(pfb, 0x100c24, flush);
-	nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000);
-
-	return 0;
-}
-
-struct nouveau_oclass
-nvaa_ram_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvaa_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = nvaa_ram_init,
-		.fini = _nouveau_ram_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
deleted file mode 100644
index 735cb95..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/timing.h>
-#include <subdev/ltc.h>
-
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-
-#include <core/option.h>
-
-#include "ramfuc.h"
-
-#include "nvc0.h"
-
-struct nvc0_ramfuc {
-	struct ramfuc base;
-
-	struct ramfuc_reg r_0x10fe20;
-	struct ramfuc_reg r_0x10fe24;
-	struct ramfuc_reg r_0x137320;
-	struct ramfuc_reg r_0x137330;
-
-	struct ramfuc_reg r_0x132000;
-	struct ramfuc_reg r_0x132004;
-	struct ramfuc_reg r_0x132100;
-
-	struct ramfuc_reg r_0x137390;
-
-	struct ramfuc_reg r_0x10f290;
-	struct ramfuc_reg r_0x10f294;
-	struct ramfuc_reg r_0x10f298;
-	struct ramfuc_reg r_0x10f29c;
-	struct ramfuc_reg r_0x10f2a0;
-
-	struct ramfuc_reg r_0x10f300;
-	struct ramfuc_reg r_0x10f338;
-	struct ramfuc_reg r_0x10f340;
-	struct ramfuc_reg r_0x10f344;
-	struct ramfuc_reg r_0x10f348;
-
-	struct ramfuc_reg r_0x10f910;
-	struct ramfuc_reg r_0x10f914;
-
-	struct ramfuc_reg r_0x100b0c;
-	struct ramfuc_reg r_0x10f050;
-	struct ramfuc_reg r_0x10f090;
-	struct ramfuc_reg r_0x10f200;
-	struct ramfuc_reg r_0x10f210;
-	struct ramfuc_reg r_0x10f310;
-	struct ramfuc_reg r_0x10f314;
-	struct ramfuc_reg r_0x10f610;
-	struct ramfuc_reg r_0x10f614;
-	struct ramfuc_reg r_0x10f800;
-	struct ramfuc_reg r_0x10f808;
-	struct ramfuc_reg r_0x10f824;
-	struct ramfuc_reg r_0x10f830;
-	struct ramfuc_reg r_0x10f988;
-	struct ramfuc_reg r_0x10f98c;
-	struct ramfuc_reg r_0x10f990;
-	struct ramfuc_reg r_0x10f998;
-	struct ramfuc_reg r_0x10f9b0;
-	struct ramfuc_reg r_0x10f9b4;
-	struct ramfuc_reg r_0x10fb04;
-	struct ramfuc_reg r_0x10fb08;
-	struct ramfuc_reg r_0x137300;
-	struct ramfuc_reg r_0x137310;
-	struct ramfuc_reg r_0x137360;
-	struct ramfuc_reg r_0x1373ec;
-	struct ramfuc_reg r_0x1373f0;
-	struct ramfuc_reg r_0x1373f8;
-
-	struct ramfuc_reg r_0x61c140;
-	struct ramfuc_reg r_0x611200;
-
-	struct ramfuc_reg r_0x13d8f4;
-};
-
-struct nvc0_ram {
-	struct nouveau_ram base;
-	struct nvc0_ramfuc fuc;
-	struct nvbios_pll refpll;
-	struct nvbios_pll mempll;
-};
-
-static void
-nvc0_ram_train(struct nvc0_ramfuc *fuc, u32 magic)
-{
-	struct nvc0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-	struct nouveau_fb *pfb = nouveau_fb(ram);
-	u32 part = nv_rd32(pfb, 0x022438), i;
-	u32 mask = nv_rd32(pfb, 0x022554);
-	u32 addr = 0x110974;
-
-	ram_wr32(fuc, 0x10f910, magic);
-	ram_wr32(fuc, 0x10f914, magic);
-
-	for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
-		if (mask & (1 << i))
-			continue;
-		ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
-	}
-}
-
-static int
-nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nouveau_clock *clk = nouveau_clock(pfb);
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nvc0_ram *ram = (void *)pfb->ram;
-	struct nvc0_ramfuc *fuc = &ram->fuc;
-	struct nvbios_ramcfg cfg;
-	u8  ver, cnt, len, strap;
-	struct {
-		u32 data;
-		u8  size;
-	} rammap, ramcfg, timing;
-	int ref, div, out;
-	int from, mode;
-	int N1, M1, P;
-	int ret;
-
-	/* lookup memory config data relevant to the target frequency */
-	rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
-				     &cnt, &ramcfg.size, &cfg);
-	if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
-		nv_error(pfb, "invalid/missing rammap entry\n");
-		return -EINVAL;
-	}
-
-	/* locate specific data set for the attached memory */
-	strap = nvbios_ramcfg_index(nv_subdev(pfb));
-	if (strap >= cnt) {
-		nv_error(pfb, "invalid ramcfg strap\n");
-		return -EINVAL;
-	}
-
-	ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
-	if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
-		nv_error(pfb, "invalid/missing ramcfg entry\n");
-		return -EINVAL;
-	}
-
-	/* lookup memory timings, if bios says they're present */
-	strap = nv_ro08(bios, ramcfg.data + 0x01);
-	if (strap != 0xff) {
-		timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
-					     &cnt, &len);
-		if (!timing.data || ver != 0x10 || timing.size < 0x19) {
-			nv_error(pfb, "invalid/missing timing entry\n");
-			return -EINVAL;
-		}
-	} else {
-		timing.data = 0;
-	}
-
-	ret = ram_init(fuc, pfb);
-	if (ret)
-		return ret;
-
-	/* determine current mclk configuration */
-	from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
-
-	/* determine target mclk configuration */
-	if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
-		ref = clk->read(clk, nv_clk_src_sppll0);
-	else
-		ref = clk->read(clk, nv_clk_src_sppll1);
-	div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
-	out = (ref * 2) / (div + 2);
-	mode = freq != out;
-
-	ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
-
-	if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
-		ram_nuke(fuc, 0x132000);
-		ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
-		ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
-	}
-
-	if (mode == 1) {
-		ram_nuke(fuc, 0x10fe20);
-		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
-		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
-	}
-
-// 0x00020034 // 0x0000000a
-	ram_wr32(fuc, 0x132100, 0x00000001);
-
-	if (mode == 1 && from == 0) {
-		/* calculate refpll */
-		ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll,
-				    ram->mempll.refclk, &N1, NULL, &M1, &P);
-		if (ret <= 0) {
-			nv_error(pfb, "unable to calc refpll\n");
-			return ret ? ret : -ERANGE;
-		}
-
-		ram_wr32(fuc, 0x10fe20, 0x20010000);
-		ram_wr32(fuc, 0x137320, 0x00000003);
-		ram_wr32(fuc, 0x137330, 0x81200006);
-		ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
-		ram_wr32(fuc, 0x10fe20, 0x20010001);
-		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
-
-		/* calculate mempll */
-		ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
-				   &N1, NULL, &M1, &P);
-		if (ret <= 0) {
-			nv_error(pfb, "unable to calc refpll\n");
-			return ret ? ret : -ERANGE;
-		}
-
-		ram_wr32(fuc, 0x10fe20, 0x20010005);
-		ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
-		ram_wr32(fuc, 0x132000, 0x18010101);
-		ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
-	} else
-	if (mode == 0) {
-		ram_wr32(fuc, 0x137300, 0x00000003);
-	}
-
-	if (from == 0) {
-		ram_nuke(fuc, 0x10fb04);
-		ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
-		ram_nuke(fuc, 0x10fb08);
-		ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
-		ram_wr32(fuc, 0x10f988, 0x2004ff00);
-		ram_wr32(fuc, 0x10f98c, 0x003fc040);
-		ram_wr32(fuc, 0x10f990, 0x20012001);
-		ram_wr32(fuc, 0x10f998, 0x00011a00);
-		ram_wr32(fuc, 0x13d8f4, 0x00000000);
-	} else {
-		ram_wr32(fuc, 0x10f988, 0x20010000);
-		ram_wr32(fuc, 0x10f98c, 0x00000000);
-		ram_wr32(fuc, 0x10f990, 0x20012001);
-		ram_wr32(fuc, 0x10f998, 0x00010a00);
-	}
-
-	if (from == 0) {
-// 0x00020039 // 0x000000ba
-	}
-
-// 0x0002003a // 0x00000002
-	ram_wr32(fuc, 0x100b0c, 0x00080012);
-// 0x00030014 // 0x00000000 // 0x02b5f070
-// 0x00030014 // 0x00010000 // 0x02b5f070
-	ram_wr32(fuc, 0x611200, 0x00003300);
-// 0x00020034 // 0x0000000a
-// 0x00030020 // 0x00000001 // 0x00000000
-
-	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
-	ram_wr32(fuc, 0x10f210, 0x00000000);
-	ram_nsec(fuc, 1000);
-	if (mode == 0)
-		nvc0_ram_train(fuc, 0x000c1001);
-	ram_wr32(fuc, 0x10f310, 0x00000001);
-	ram_nsec(fuc, 1000);
-	ram_wr32(fuc, 0x10f090, 0x00000061);
-	ram_wr32(fuc, 0x10f090, 0xc000007f);
-	ram_nsec(fuc, 1000);
-
-	if (from == 0) {
-		ram_wr32(fuc, 0x10f824, 0x00007fd4);
-	} else {
-		ram_wr32(fuc, 0x1373ec, 0x00020404);
-	}
-
-	if (mode == 0) {
-		ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
-		ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
-		ram_wr32(fuc, 0x10f830, 0x41500010);
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
-		ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
-		ram_wr32(fuc, 0x10f050, 0xff000090);
-		ram_wr32(fuc, 0x1373ec, 0x00020f0f);
-		ram_wr32(fuc, 0x1373f0, 0x00000003);
-		ram_wr32(fuc, 0x137310, 0x81201616);
-		ram_wr32(fuc, 0x132100, 0x00000001);
-// 0x00020039 // 0x000000ba
-		ram_wr32(fuc, 0x10f830, 0x00300017);
-		ram_wr32(fuc, 0x1373f0, 0x00000001);
-		ram_wr32(fuc, 0x10f824, 0x00007e77);
-		ram_wr32(fuc, 0x132000, 0x18030001);
-		ram_wr32(fuc, 0x10f090, 0x4000007e);
-		ram_nsec(fuc, 2000);
-		ram_wr32(fuc, 0x10f314, 0x00000001);
-		ram_wr32(fuc, 0x10f210, 0x80000000);
-		ram_wr32(fuc, 0x10f338, 0x00300220);
-		ram_wr32(fuc, 0x10f300, 0x0000011d);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f290, 0x02060505);
-		ram_wr32(fuc, 0x10f294, 0x34208288);
-		ram_wr32(fuc, 0x10f298, 0x44050411);
-		ram_wr32(fuc, 0x10f29c, 0x0000114c);
-		ram_wr32(fuc, 0x10f2a0, 0x42e10069);
-		ram_wr32(fuc, 0x10f614, 0x40044f77);
-		ram_wr32(fuc, 0x10f610, 0x40044f77);
-		ram_wr32(fuc, 0x10f344, 0x00600009);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f348, 0x00700008);
-		ram_wr32(fuc, 0x61c140, 0x19240000);
-		ram_wr32(fuc, 0x10f830, 0x00300017);
-		nvc0_ram_train(fuc, 0x80021001);
-		nvc0_ram_train(fuc, 0x80081001);
-		ram_wr32(fuc, 0x10f340, 0x00500004);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f830, 0x01300017);
-		ram_wr32(fuc, 0x10f830, 0x00300017);
-// 0x00030020 // 0x00000000 // 0x00000000
-// 0x00020034 // 0x0000000b
-		ram_wr32(fuc, 0x100b0c, 0x00080028);
-		ram_wr32(fuc, 0x611200, 0x00003330);
-	} else {
-		ram_wr32(fuc, 0x10f800, 0x00001800);
-		ram_wr32(fuc, 0x13d8f4, 0x00000000);
-		ram_wr32(fuc, 0x1373ec, 0x00020404);
-		ram_wr32(fuc, 0x1373f0, 0x00000003);
-		ram_wr32(fuc, 0x10f830, 0x40700010);
-		ram_wr32(fuc, 0x10f830, 0x40500010);
-		ram_wr32(fuc, 0x13d8f4, 0x00000000);
-		ram_wr32(fuc, 0x1373f8, 0x00000000);
-		ram_wr32(fuc, 0x132100, 0x00000101);
-		ram_wr32(fuc, 0x137310, 0x89201616);
-		ram_wr32(fuc, 0x10f050, 0xff000090);
-		ram_wr32(fuc, 0x1373ec, 0x00030404);
-		ram_wr32(fuc, 0x1373f0, 0x00000002);
-	// 0x00020039 // 0x00000011
-		ram_wr32(fuc, 0x132100, 0x00000001);
-		ram_wr32(fuc, 0x1373f8, 0x00002000);
-		ram_nsec(fuc, 2000);
-		ram_wr32(fuc, 0x10f808, 0x7aaa0050);
-		ram_wr32(fuc, 0x10f830, 0x00500010);
-		ram_wr32(fuc, 0x10f200, 0x00ce1000);
-		ram_wr32(fuc, 0x10f090, 0x4000007e);
-		ram_nsec(fuc, 2000);
-		ram_wr32(fuc, 0x10f314, 0x00000001);
-		ram_wr32(fuc, 0x10f210, 0x80000000);
-		ram_wr32(fuc, 0x10f338, 0x00300200);
-		ram_wr32(fuc, 0x10f300, 0x0000084d);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f290, 0x0b343825);
-		ram_wr32(fuc, 0x10f294, 0x3483028e);
-		ram_wr32(fuc, 0x10f298, 0x440c0600);
-		ram_wr32(fuc, 0x10f29c, 0x0000214c);
-		ram_wr32(fuc, 0x10f2a0, 0x42e20069);
-		ram_wr32(fuc, 0x10f200, 0x00ce0000);
-		ram_wr32(fuc, 0x10f614, 0x60044e77);
-		ram_wr32(fuc, 0x10f610, 0x60044e77);
-		ram_wr32(fuc, 0x10f340, 0x00500000);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f344, 0x00600228);
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f348, 0x00700000);
-		ram_wr32(fuc, 0x13d8f4, 0x00000000);
-		ram_wr32(fuc, 0x61c140, 0x09a40000);
-
-		nvc0_ram_train(fuc, 0x800e1008);
-
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f800, 0x00001804);
-	// 0x00030020 // 0x00000000 // 0x00000000
-	// 0x00020034 // 0x0000000b
-		ram_wr32(fuc, 0x13d8f4, 0x00000000);
-		ram_wr32(fuc, 0x100b0c, 0x00080028);
-		ram_wr32(fuc, 0x611200, 0x00003330);
-		ram_nsec(fuc, 100000);
-		ram_wr32(fuc, 0x10f9b0, 0x05313f41);
-		ram_wr32(fuc, 0x10f9b4, 0x00002f50);
-
-		nvc0_ram_train(fuc, 0x010c1001);
-	}
-
-	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
-// 0x00020016 // 0x00000000
-
-	if (mode == 0)
-		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
-	return 0;
-}
-
-static int
-nvc0_ram_prog(struct nouveau_fb *pfb)
-{
-	struct nouveau_device *device = nv_device(pfb);
-	struct nvc0_ram *ram = (void *)pfb->ram;
-	struct nvc0_ramfuc *fuc = &ram->fuc;
-	ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
-	return 0;
-}
-
-static void
-nvc0_ram_tidy(struct nouveau_fb *pfb)
-{
-	struct nvc0_ram *ram = (void *)pfb->ram;
-	struct nvc0_ramfuc *fuc = &ram->fuc;
-	ram_exec(fuc, false);
-}
-
-extern const u8 nvc0_pte_storage_type_map[256];
-
-void
-nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
-	struct nouveau_ltc *ltc = nouveau_ltc(pfb);
-	struct nouveau_mem *mem = *pmem;
-
-	*pmem = NULL;
-	if (unlikely(mem == NULL))
-		return;
-
-	mutex_lock(&pfb->base.mutex);
-	if (mem->tag)
-		ltc->tags_free(ltc, &mem->tag);
-	__nv50_ram_put(pfb, mem);
-	mutex_unlock(&pfb->base.mutex);
-
-	kfree(mem);
-}
-
-int
-nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
-	     u32 memtype, struct nouveau_mem **pmem)
-{
-	struct nouveau_mm *mm = &pfb->vram;
-	struct nouveau_mm_node *r;
-	struct nouveau_mem *mem;
-	int type = (memtype & 0x0ff);
-	int back = (memtype & 0x800);
-	const bool comp = nvc0_pte_storage_type_map[type] != type;
-	int ret;
-
-	size  >>= 12;
-	align >>= 12;
-	ncmin >>= 12;
-	if (!ncmin)
-		ncmin = size;
-
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&mem->regions);
-	mem->size = size;
-
-	mutex_lock(&pfb->base.mutex);
-	if (comp) {
-		struct nouveau_ltc *ltc = nouveau_ltc(pfb);
-
-		/* compression only works with lpages */
-		if (align == (1 << (17 - 12))) {
-			int n = size >> 5;
-			ltc->tags_alloc(ltc, n, &mem->tag);
-		}
-
-		if (unlikely(!mem->tag))
-			type = nvc0_pte_storage_type_map[type];
-	}
-	mem->memtype = type;
-
-	do {
-		if (back)
-			ret = nouveau_mm_tail(mm, 0, 1, size, ncmin, align, &r);
-		else
-			ret = nouveau_mm_head(mm, 0, 1, size, ncmin, align, &r);
-		if (ret) {
-			mutex_unlock(&pfb->base.mutex);
-			pfb->ram->put(pfb, &mem);
-			return ret;
-		}
-
-		list_add_tail(&r->rl_entry, &mem->regions);
-		size -= r->length;
-	} while (size);
-	mutex_unlock(&pfb->base.mutex);
-
-	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
-	mem->offset = (u64)r->offset << 12;
-	*pmem = mem;
-	return 0;
-}
-
-int
-nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, u32 maskaddr, int size,
-		 void **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nouveau_ram *ram;
-	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
-	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	u32 parts = nv_rd32(pfb, 0x022438);
-	u32 pmask = nv_rd32(pfb, maskaddr);
-	u32 bsize = nv_rd32(pfb, 0x10f20c);
-	u32 offset, length;
-	bool uniform = true;
-	int ret, part;
-
-	ret = nouveau_ram_create_(parent, engine, oclass, size, pobject);
-	ram = *pobject;
-	if (ret)
-		return ret;
-
-	nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
-	nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
-	ram->type = nouveau_fb_bios_memtype(bios);
-	ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
-	/* read amount of vram attached to each memory controller */
-	for (part = 0; part < parts; part++) {
-		if (!(pmask & (1 << part))) {
-			u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
-			if (psize != bsize) {
-				if (psize < bsize)
-					bsize = psize;
-				uniform = false;
-			}
-
-			nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
-			ram->size += (u64)psize << 20;
-		}
-	}
-
-	/* if all controllers have the same amount attached, there's no holes */
-	if (uniform) {
-		offset = rsvd_head;
-		length = (ram->size >> 12) - rsvd_head - rsvd_tail;
-		ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
-	} else {
-		/* otherwise, address lowest common amount from 0GiB */
-		ret = nouveau_mm_init(&pfb->vram, rsvd_head,
-				      (bsize << 8) * parts - rsvd_head, 1);
-		if (ret)
-			return ret;
-
-		/* and the rest starting from (8GiB + common_size) */
-		offset = (0x0200000000ULL >> 12) + (bsize << 8);
-		length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
-
-		ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
-		if (ret)
-			nouveau_mm_fini(&pfb->vram);
-	}
-
-	if (ret)
-		return ret;
-
-	ram->get = nvc0_ram_get;
-	ram->put = nvc0_ram_put;
-	return 0;
-}
-
-static int
-nvc0_ram_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object->parent;
-	struct nvc0_ram   *ram = (void *)object;
-	int ret, i;
-
-	ret = nouveau_ram_init(&ram->base);
-	if (ret)
-		return ret;
-
-	/* prepare for ddr link training, and load training patterns */
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_GDDR5: {
-		static const u8  train0[] = {
-			0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
-			0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
-		};
-		static const u32 train1[] = {
-			0x00000000, 0xffffffff,
-			0x55555555, 0xaaaaaaaa,
-			0x33333333, 0xcccccccc,
-			0xf0f0f0f0, 0x0f0f0f0f,
-			0x00ff00ff, 0xff00ff00,
-			0x0000ffff, 0xffff0000,
-		};
-
-		for (i = 0; i < 0x30; i++) {
-			nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
-			nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
-			nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
-			nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
-			nv_wr32(pfb, 0x10f918,              train1[i % 12]);
-			nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
-			nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
-			nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
-			nv_wr32(pfb, 0x10f918,              train1[i % 12]);
-			nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
-		}
-	}	break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int
-nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nvc0_ram *ram;
-	int ret;
-
-	ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
-	if (ret) {
-		nv_error(ram, "mclk refpll data not found\n");
-		return ret;
-	}
-
-	ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
-	if (ret) {
-		nv_error(ram, "mclk pll data not found\n");
-		return ret;
-	}
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_GDDR5:
-		ram->base.calc = nvc0_ram_calc;
-		ram->base.prog = nvc0_ram_prog;
-		ram->base.tidy = nvc0_ram_tidy;
-		break;
-	default:
-		nv_warn(ram, "reclocking of this ram type unsupported\n");
-		return 0;
-	}
-
-	ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
-	ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
-	ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
-	ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
-
-	ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
-	ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
-	ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
-
-	ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
-
-	ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
-	ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
-	ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
-	ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
-	ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
-
-	ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
-	ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
-	ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
-	ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
-	ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
-
-	ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
-	ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
-
-	ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
-	ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
-	ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
-	ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
-	ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
-	ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
-	ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
-	ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
-	ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
-	ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
-	ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
-	ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
-	ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
-	ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
-	ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
-	ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
-	ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
-	ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
-	ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
-	ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
-	ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
-	ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
-	ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
-	ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
-	ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
-	ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
-	ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
-
-	ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
-	ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
-
-	ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_ram_ctor,
-		.dtor = _nouveau_ram_dtor,
-		.init = nvc0_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
deleted file mode 100644
index 6bae474..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/gpio.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/timing.h>
-#include <subdev/bios/M0205.h>
-#include <subdev/bios/M0209.h>
-
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-
-#include <subdev/timer.h>
-
-#include <core/option.h>
-
-#include "nvc0.h"
-
-#include "ramfuc.h"
-
-struct nve0_ramfuc {
-	struct ramfuc base;
-
-	struct nvbios_pll refpll;
-	struct nvbios_pll mempll;
-
-	struct ramfuc_reg r_gpioMV;
-	u32 r_funcMV[2];
-	struct ramfuc_reg r_gpio2E;
-	u32 r_func2E[2];
-	struct ramfuc_reg r_gpiotrig;
-
-	struct ramfuc_reg r_0x132020;
-	struct ramfuc_reg r_0x132028;
-	struct ramfuc_reg r_0x132024;
-	struct ramfuc_reg r_0x132030;
-	struct ramfuc_reg r_0x132034;
-	struct ramfuc_reg r_0x132000;
-	struct ramfuc_reg r_0x132004;
-	struct ramfuc_reg r_0x132040;
-
-	struct ramfuc_reg r_0x10f248;
-	struct ramfuc_reg r_0x10f290;
-	struct ramfuc_reg r_0x10f294;
-	struct ramfuc_reg r_0x10f298;
-	struct ramfuc_reg r_0x10f29c;
-	struct ramfuc_reg r_0x10f2a0;
-	struct ramfuc_reg r_0x10f2a4;
-	struct ramfuc_reg r_0x10f2a8;
-	struct ramfuc_reg r_0x10f2ac;
-	struct ramfuc_reg r_0x10f2cc;
-	struct ramfuc_reg r_0x10f2e8;
-	struct ramfuc_reg r_0x10f250;
-	struct ramfuc_reg r_0x10f24c;
-	struct ramfuc_reg r_0x10fec4;
-	struct ramfuc_reg r_0x10fec8;
-	struct ramfuc_reg r_0x10f604;
-	struct ramfuc_reg r_0x10f614;
-	struct ramfuc_reg r_0x10f610;
-	struct ramfuc_reg r_0x100770;
-	struct ramfuc_reg r_0x100778;
-	struct ramfuc_reg r_0x10f224;
-
-	struct ramfuc_reg r_0x10f870;
-	struct ramfuc_reg r_0x10f698;
-	struct ramfuc_reg r_0x10f694;
-	struct ramfuc_reg r_0x10f6b8;
-	struct ramfuc_reg r_0x10f808;
-	struct ramfuc_reg r_0x10f670;
-	struct ramfuc_reg r_0x10f60c;
-	struct ramfuc_reg r_0x10f830;
-	struct ramfuc_reg r_0x1373ec;
-	struct ramfuc_reg r_0x10f800;
-	struct ramfuc_reg r_0x10f82c;
-
-	struct ramfuc_reg r_0x10f978;
-	struct ramfuc_reg r_0x10f910;
-	struct ramfuc_reg r_0x10f914;
-
-	struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
-
-	struct ramfuc_reg r_0x62c000;
-
-	struct ramfuc_reg r_0x10f200;
-
-	struct ramfuc_reg r_0x10f210;
-	struct ramfuc_reg r_0x10f310;
-	struct ramfuc_reg r_0x10f314;
-	struct ramfuc_reg r_0x10f318;
-	struct ramfuc_reg r_0x10f090;
-	struct ramfuc_reg r_0x10f69c;
-	struct ramfuc_reg r_0x10f824;
-	struct ramfuc_reg r_0x1373f0;
-	struct ramfuc_reg r_0x1373f4;
-	struct ramfuc_reg r_0x137320;
-	struct ramfuc_reg r_0x10f65c;
-	struct ramfuc_reg r_0x10f6bc;
-	struct ramfuc_reg r_0x100710;
-	struct ramfuc_reg r_0x100750;
-};
-
-struct nve0_ram {
-	struct nouveau_ram base;
-	struct nve0_ramfuc fuc;
-
-	struct list_head cfg;
-	u32 parts;
-	u32 pmask;
-	u32 pnuts;
-
-	struct nvbios_ramcfg diff;
-	int from;
-	int mode;
-	int N1, fN1, M1, P1;
-	int N2, M2, P2;
-};
-
-/*******************************************************************************
- * GDDR5
- ******************************************************************************/
-static void
-nve0_ram_train(struct nve0_ramfuc *fuc, u32 mask, u32 data)
-{
-	struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-	u32 addr = 0x110974, i;
-
-	ram_mask(fuc, 0x10f910, mask, data);
-	ram_mask(fuc, 0x10f914, mask, data);
-
-	for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
-		if (ram->pmask & (1 << i))
-			continue;
-		ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
-	}
-}
-
-static void
-r1373f4_init(struct nve0_ramfuc *fuc)
-{
-	struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-	const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2);
-	const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
-	const u32 runk0 = ram->fN1 << 16;
-	const u32 runk1 = ram->fN1;
-
-	if (ram->from == 2) {
-		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
-		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
-	} else {
-		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
-	}
-
-	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
-	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
-
-	/* (re)program refpll, if required */
-	if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
-	    (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
-		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
-		ram_wr32(fuc, 0x137320, 0x00000000);
-		ram_mask(fuc, 0x132030, 0xffff0000, runk0);
-		ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
-		ram_wr32(fuc, 0x132024, rcoef);
-		ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
-		ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
-		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
-		ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
-	}
-
-	/* (re)program mempll, if required */
-	if (ram->mode == 2) {
-		ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
-		ram_mask(fuc, 0x132000, 0x80000000, 0x80000000);
-		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x132004, 0x103fffff, mcoef);
-		ram_mask(fuc, 0x132000, 0x00000001, 0x00000001);
-		ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
-		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
-	} else {
-		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100);
-	}
-
-	ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
-}
-
-static void
-r1373f4_fini(struct nve0_ramfuc *fuc)
-{
-	struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-	struct nouveau_ram_data *next = ram->base.next;
-	u8 v0 = next->bios.ramcfg_11_03_c0;
-	u8 v1 = next->bios.ramcfg_11_03_30;
-	u32 tmp;
-
-	tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
-	ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
-	ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
-	if (ram->mode == 2) {
-		ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
-		ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
-	} else {
-		ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
-		ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
-	}
-	ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
-}
-
-static void
-nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
-	      u32 _mask, u32 _data, u32 _copy)
-{
-	struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
-	struct ramfuc *fuc = &ram->fuc.base;
-	u32 addr = 0x110000 + (reg->addr & 0xfff);
-	u32 mask = _mask | _copy;
-	u32 data = (_data & _mask) | (reg->data & _copy);
-	u32 i;
-
-	for (i = 0; i < 16; i++, addr += 0x1000) {
-		if (ram->pnuts & (1 << i)) {
-			u32 prev = nv_rd32(priv, addr);
-			u32 next = (prev & ~mask) | data;
-			nouveau_memx_wr32(fuc->memx, addr, next);
-		}
-	}
-}
-#define ram_nuts(s,r,m,d,c)                                                    \
-	nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
-
-static int
-nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nve0_ramfuc *fuc = &ram->fuc;
-	struct nouveau_ram_data *next = ram->base.next;
-	int vc = !next->bios.ramcfg_11_02_08;
-	int mv = !next->bios.ramcfg_11_02_04;
-	u32 mask, data;
-
-	ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
-	ram_block(fuc);
-	ram_wr32(fuc, 0x62c000, 0x0f0f0000);
-
-	/* MR1: turn termination on early, for some reason.. */
-	if ((ram->base.mr[1] & 0x03c) != 0x030) {
-		ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
-		ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
-	}
-
-	if (vc == 1 && ram_have(fuc, gpio2E)) {
-		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
-		if (temp != ram_rd32(fuc, gpio2E)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 20000);
-		}
-	}
-
-	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
-
-	nve0_ram_train(fuc, 0x01020000, 0x000c0000);
-
-	ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
-	ram_nsec(fuc, 1000);
-	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-	ram_nsec(fuc, 1000);
-
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
-	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
-	ram_wr32(fuc, 0x10f090, 0x00000061);
-	ram_wr32(fuc, 0x10f090, 0xc000007f);
-	ram_nsec(fuc, 1000);
-
-	ram_wr32(fuc, 0x10f698, 0x00000000);
-	ram_wr32(fuc, 0x10f69c, 0x00000000);
-
-	/*XXX: there does appear to be some kind of condition here, simply
-	 *     modifying these bits in the vbios from the default pl0
-	 *     entries shows no change.  however, the data does appear to
-	 *     be correct and may be required for the transition back
-	 */
-	mask = 0x800f07e0;
-	data = 0x00030000;
-	if (ram_rd32(fuc, 0x10f978) & 0x00800000)
-		data |= 0x00040000;
-
-	if (1) {
-		data |= 0x800807e0;
-		switch (next->bios.ramcfg_11_03_c0) {
-		case 3: data &= ~0x00000040; break;
-		case 2: data &= ~0x00000100; break;
-		case 1: data &= ~0x80000000; break;
-		case 0: data &= ~0x00000400; break;
-		}
-
-		switch (next->bios.ramcfg_11_03_30) {
-		case 3: data &= ~0x00000020; break;
-		case 2: data &= ~0x00000080; break;
-		case 1: data &= ~0x00080000; break;
-		case 0: data &= ~0x00000200; break;
-		}
-	}
-
-	if (next->bios.ramcfg_11_02_80)
-		mask |= 0x03000000;
-	if (next->bios.ramcfg_11_02_40)
-		mask |= 0x00002000;
-	if (next->bios.ramcfg_11_07_10)
-		mask |= 0x00004000;
-	if (next->bios.ramcfg_11_07_08)
-		mask |= 0x00000003;
-	else {
-		mask |= 0x34000000;
-		if (ram_rd32(fuc, 0x10f978) & 0x00800000)
-			mask |= 0x40000000;
-	}
-	ram_mask(fuc, 0x10f824, mask, data);
-
-	ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
-
-	if (ram->from == 2 && ram->mode != 2) {
-		ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
-		ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000);
-		ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
-		ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
-		r1373f4_init(fuc);
-		ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
-		r1373f4_fini(fuc);
-		ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
-	} else
-	if (ram->from != 2 && ram->mode != 2) {
-		r1373f4_init(fuc);
-		r1373f4_fini(fuc);
-	}
-
-	if (ram_have(fuc, gpioMV)) {
-		u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
-		if (temp != ram_rd32(fuc, gpioMV)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 64000);
-		}
-	}
-
-	if (next->bios.ramcfg_11_02_40 ||
-	    next->bios.ramcfg_11_07_10) {
-		ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
-		ram_nsec(fuc, 20000);
-	}
-
-	if (ram->from != 2 && ram->mode == 2) {
-		if (0 /*XXX: Titan */)
-			ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000);
-		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
-		ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
-		ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
-		r1373f4_init(fuc);
-		r1373f4_fini(fuc);
-		ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
-		ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
-	} else
-	if (ram->from == 2 && ram->mode == 2) {
-		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
-		r1373f4_init(fuc);
-		r1373f4_fini(fuc);
-	}
-
-	if (ram->mode != 2) /*XXX*/ {
-		if (next->bios.ramcfg_11_07_40)
-			ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
-	}
-
-	ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
-	ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
-	ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
-
-	if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) {
-		ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04);
-		ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04);
-	} else
-	if (!next->bios.ramcfg_11_07_08) {
-		ram_wr32(fuc, 0x10f698, 0x00000000);
-		ram_wr32(fuc, 0x10f69c, 0x00000000);
-	}
-
-	if (ram->mode != 2) {
-		u32 data = 0x01000100 * next->bios.ramcfg_11_04;
-		ram_nuke(fuc, 0x10f694);
-		ram_mask(fuc, 0x10f694, 0xff00ff00, data);
-	}
-
-	if (ram->mode == 2 && next->bios.ramcfg_11_08_10)
-		data = 0x00000080;
-	else
-		data = 0x00000000;
-	ram_mask(fuc, 0x10f60c, 0x00000080, data);
-
-	mask = 0x00070000;
-	data = 0x00000000;
-	if (!next->bios.ramcfg_11_02_80)
-		data |= 0x03000000;
-	if (!next->bios.ramcfg_11_02_40)
-		data |= 0x00002000;
-	if (!next->bios.ramcfg_11_07_10)
-		data |= 0x00004000;
-	if (!next->bios.ramcfg_11_07_08)
-		data |= 0x00000003;
-	else
-		data |= 0x74000000;
-	ram_mask(fuc, 0x10f824, mask, data);
-
-	if (next->bios.ramcfg_11_01_08)
-		data = 0x00000000;
-	else
-		data = 0x00001000;
-	ram_mask(fuc, 0x10f200, 0x00001000, data);
-
-	if (ram_rd32(fuc, 0x10f670) & 0x80000000) {
-		ram_nsec(fuc, 10000);
-		ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
-	}
-
-	if (next->bios.ramcfg_11_08_01)
-		data = 0x00100000;
-	else
-		data = 0x00000000;
-	ram_mask(fuc, 0x10f82c, 0x00100000, data);
-
-	data = 0x00000000;
-	if (next->bios.ramcfg_11_08_08)
-		data |= 0x00002000;
-	if (next->bios.ramcfg_11_08_04)
-		data |= 0x00001000;
-	if (next->bios.ramcfg_11_08_02)
-		data |= 0x00004000;
-	ram_mask(fuc, 0x10f830, 0x00007000, data);
-
-	/* PFB timing */
-	ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
-	ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
-	ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
-	ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
-	ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
-	ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
-	ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
-	ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
-	ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
-	ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
-	ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
-
-	data = mask = 0x00000000;
-	if (ram->diff.ramcfg_11_08_20) {
-		if (next->bios.ramcfg_11_08_20)
-			data |= 0x01000000;
-		mask |= 0x01000000;
-	}
-	ram_mask(fuc, 0x10f200, mask, data);
-
-	data = mask = 0x00000000;
-	if (ram->diff.ramcfg_11_02_03) {
-		data |= next->bios.ramcfg_11_02_03 << 8;
-		mask |= 0x00000300;
-	}
-	if (ram->diff.ramcfg_11_01_10) {
-		if (next->bios.ramcfg_11_01_10)
-			data |= 0x70000000;
-		mask |= 0x70000000;
-	}
-	ram_mask(fuc, 0x10f604, mask, data);
-
-	data = mask = 0x00000000;
-	if (ram->diff.timing_20_30_07) {
-		data |= next->bios.timing_20_30_07 << 28;
-		mask |= 0x70000000;
-	}
-	if (ram->diff.ramcfg_11_01_01) {
-		if (next->bios.ramcfg_11_01_01)
-			data |= 0x00000100;
-		mask |= 0x00000100;
-	}
-	ram_mask(fuc, 0x10f614, mask, data);
-
-	data = mask = 0x00000000;
-	if (ram->diff.timing_20_30_07) {
-		data |= next->bios.timing_20_30_07 << 28;
-		mask |= 0x70000000;
-	}
-	if (ram->diff.ramcfg_11_01_02) {
-		if (next->bios.ramcfg_11_01_02)
-			data |= 0x00000100;
-		mask |= 0x00000100;
-	}
-	ram_mask(fuc, 0x10f610, mask, data);
-
-	mask = 0x33f00000;
-	data = 0x00000000;
-	if (!next->bios.ramcfg_11_01_04)
-		data |= 0x20200000;
-	if (!next->bios.ramcfg_11_07_80)
-		data |= 0x12800000;
-	/*XXX: see note above about there probably being some condition
-	 *     for the 10f824 stuff that uses ramcfg 3...
-	 */
-	if (next->bios.ramcfg_11_03_f0) {
-		if (next->bios.rammap_11_08_0c) {
-			if (!next->bios.ramcfg_11_07_80)
-				mask |= 0x00000020;
-			else
-				data |= 0x00000020;
-			mask |= 0x00000004;
-		}
-	} else {
-		mask |= 0x40000020;
-		data |= 0x00000004;
-	}
-
-	ram_mask(fuc, 0x10f808, mask, data);
-
-	ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
-
-	data = mask = 0x00000000;
-	if (ram->diff.ramcfg_11_02_03) {
-		data |= next->bios.ramcfg_11_02_03;
-		mask |= 0x00000003;
-	}
-	if (ram->diff.ramcfg_11_01_10) {
-		if (next->bios.ramcfg_11_01_10)
-			data |= 0x00000004;
-		mask |= 0x00000004;
-	}
-
-	if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) {
-		ram_mask(fuc, 0x100750, 0x00000008, 0x00000008);
-		ram_wr32(fuc, 0x100710, 0x00000000);
-		ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
-	}
-
-	data = next->bios.timing_20_30_07 << 8;
-	if (next->bios.ramcfg_11_01_01)
-		data |= 0x80000000;
-	ram_mask(fuc, 0x100778, 0x00000700, data);
-
-	ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
-	data = (next->bios.timing[10] & 0x7f000000) >> 24;
-	if (data < next->bios.timing_20_2c_1fc0)
-		data = next->bios.timing_20_2c_1fc0;
-	ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
-	ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
-
-	ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 |
-					    next->bios.timing_20_31_0780 << 17 |
-					    next->bios.timing_20_31_0078 << 8 |
-					    next->bios.timing_20_31_0007);
-	ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 |
-					    next->bios.timing_20_31_7000);
-
-	ram_wr32(fuc, 0x10f090, 0x4000007e);
-	ram_nsec(fuc, 2000);
-	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
-	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-	ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
-
-	if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) {
-		u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
-		nve0_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/
-		ram_nsec(fuc, 1000);
-		ram_wr32(fuc, 0x10f294, temp);
-	}
-
-	ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]);
-	ram_wr32(fuc, mr[0], ram->base.mr[0]);
-	ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
-	ram_nsec(fuc, 1000);
-	ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
-	ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */
-	ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
-	ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
-
-	if (vc == 0 && ram_have(fuc, gpio2E)) {
-		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
-		if (temp != ram_rd32(fuc, gpio2E)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 20000);
-		}
-	}
-
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
-	ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
-	ram_nsec(fuc, 1000);
-	ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800);
-
-	data  = ram_rd32(fuc, 0x10f978);
-	data &= ~0x00046144;
-	data |=  0x0000000b;
-	if (!next->bios.ramcfg_11_07_08) {
-		if (!next->bios.ramcfg_11_07_04)
-			data |= 0x0000200c;
-		else
-			data |= 0x00000000;
-	} else {
-		data |= 0x00040044;
-	}
-	ram_wr32(fuc, 0x10f978, data);
-
-	if (ram->mode == 1) {
-		data = ram_rd32(fuc, 0x10f830) | 0x00000001;
-		ram_wr32(fuc, 0x10f830, data);
-	}
-
-	if (!next->bios.ramcfg_11_07_08) {
-		data = 0x88020000;
-		if ( next->bios.ramcfg_11_07_04)
-			data |= 0x10000000;
-		if (!next->bios.rammap_11_08_10)
-			data |= 0x00080000;
-	} else {
-		data = 0xa40e0000;
-	}
-	nve0_ram_train(fuc, 0xbc0f0000, data);
-	if (1) /* XXX: not always? */
-		ram_nsec(fuc, 1000);
-
-	if (ram->mode == 2) { /*XXX*/
-		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
-	}
-
-	/* LP3 */
-	if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5])
-		ram_nsec(fuc, 1000);
-
-	if (ram->mode != 2) {
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
-	}
-
-	if (next->bios.ramcfg_11_07_02)
-		nve0_ram_train(fuc, 0x80020000, 0x01000000);
-
-	ram_unblock(fuc);
-	ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
-
-	if (next->bios.rammap_11_08_01)
-		data = 0x00000800;
-	else
-		data = 0x00000000;
-	ram_mask(fuc, 0x10f200, 0x00000800, data);
-	ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800);
-	return 0;
-}
-
-/*******************************************************************************
- * DDR3
- ******************************************************************************/
-
-static int
-nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nve0_ramfuc *fuc = &ram->fuc;
-	const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
-	const u32 runk0 = ram->fN1 << 16;
-	const u32 runk1 = ram->fN1;
-	struct nouveau_ram_data *next = ram->base.next;
-	int vc = !next->bios.ramcfg_11_02_08;
-	int mv = !next->bios.ramcfg_11_02_04;
-	u32 mask, data;
-
-	ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
-	ram_block(fuc);
-	ram_wr32(fuc, 0x62c000, 0x0f0f0000);
-
-	if (vc == 1 && ram_have(fuc, gpio2E)) {
-		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
-		if (temp != ram_rd32(fuc, gpio2E)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 20000);
-		}
-	}
-
-	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
-	if (next->bios.ramcfg_11_03_f0)
-		ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
-
-	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
-	ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
-	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
-	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
-	ram_nsec(fuc, 1000);
-
-	ram_wr32(fuc, 0x10f090, 0x00000060);
-	ram_wr32(fuc, 0x10f090, 0xc000007e);
-
-	/*XXX: there does appear to be some kind of condition here, simply
-	 *     modifying these bits in the vbios from the default pl0
-	 *     entries shows no change.  however, the data does appear to
-	 *     be correct and may be required for the transition back
-	 */
-	mask = 0x00010000;
-	data = 0x00010000;
-
-	if (1) {
-		mask |= 0x800807e0;
-		data |= 0x800807e0;
-		switch (next->bios.ramcfg_11_03_c0) {
-		case 3: data &= ~0x00000040; break;
-		case 2: data &= ~0x00000100; break;
-		case 1: data &= ~0x80000000; break;
-		case 0: data &= ~0x00000400; break;
-		}
-
-		switch (next->bios.ramcfg_11_03_30) {
-		case 3: data &= ~0x00000020; break;
-		case 2: data &= ~0x00000080; break;
-		case 1: data &= ~0x00080000; break;
-		case 0: data &= ~0x00000200; break;
-		}
-	}
-
-	if (next->bios.ramcfg_11_02_80)
-		mask |= 0x03000000;
-	if (next->bios.ramcfg_11_02_40)
-		mask |= 0x00002000;
-	if (next->bios.ramcfg_11_07_10)
-		mask |= 0x00004000;
-	if (next->bios.ramcfg_11_07_08)
-		mask |= 0x00000003;
-	else
-		mask |= 0x14000000;
-	ram_mask(fuc, 0x10f824, mask, data);
-
-	ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
-
-	ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
-	data  = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
-	data |= next->bios.ramcfg_11_03_30 << 16;
-	ram_wr32(fuc, 0x1373ec, data);
-	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
-	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
-
-	/* (re)program refpll, if required */
-	if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
-	    (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
-		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
-		ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
-		ram_wr32(fuc, 0x137320, 0x00000000);
-		ram_mask(fuc, 0x132030, 0xffff0000, runk0);
-		ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
-		ram_wr32(fuc, 0x132024, rcoef);
-		ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
-		ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
-		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
-		ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
-	}
-
-	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010);
-	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
-	ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
-
-	if (ram_have(fuc, gpioMV)) {
-		u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
-		if (temp != ram_rd32(fuc, gpioMV)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 64000);
-		}
-	}
-
-	if (next->bios.ramcfg_11_02_40 ||
-	    next->bios.ramcfg_11_07_10) {
-		ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
-		ram_nsec(fuc, 20000);
-	}
-
-	if (ram->mode != 2) /*XXX*/ {
-		if (next->bios.ramcfg_11_07_40)
-			ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
-	}
-
-	ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
-	ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
-	ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
-
-	mask = 0x00010000;
-	data = 0x00000000;
-	if (!next->bios.ramcfg_11_02_80)
-		data |= 0x03000000;
-	if (!next->bios.ramcfg_11_02_40)
-		data |= 0x00002000;
-	if (!next->bios.ramcfg_11_07_10)
-		data |= 0x00004000;
-	if (!next->bios.ramcfg_11_07_08)
-		data |= 0x00000003;
-	else
-		data |= 0x14000000;
-	ram_mask(fuc, 0x10f824, mask, data);
-	ram_nsec(fuc, 1000);
-
-	if (next->bios.ramcfg_11_08_01)
-		data = 0x00100000;
-	else
-		data = 0x00000000;
-	ram_mask(fuc, 0x10f82c, 0x00100000, data);
-
-	/* PFB timing */
-	ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
-	ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
-	ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
-	ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
-	ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
-	ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
-	ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
-	ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
-	ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
-	ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
-	ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
-
-	mask = 0x33f00000;
-	data = 0x00000000;
-	if (!next->bios.ramcfg_11_01_04)
-		data |= 0x20200000;
-	if (!next->bios.ramcfg_11_07_80)
-		data |= 0x12800000;
-	/*XXX: see note above about there probably being some condition
-	 *     for the 10f824 stuff that uses ramcfg 3...
-	 */
-	if (next->bios.ramcfg_11_03_f0) {
-		if (next->bios.rammap_11_08_0c) {
-			if (!next->bios.ramcfg_11_07_80)
-				mask |= 0x00000020;
-			else
-				data |= 0x00000020;
-			mask |= 0x08000004;
-		}
-		data |= 0x04000000;
-	} else {
-		mask |= 0x44000020;
-		data |= 0x08000004;
-	}
-
-	ram_mask(fuc, 0x10f808, mask, data);
-
-	ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
-
-	ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
-
-	data = (next->bios.timing[10] & 0x7f000000) >> 24;
-	if (data < next->bios.timing_20_2c_1fc0)
-		data = next->bios.timing_20_2c_1fc0;
-	ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
-
-	ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
-
-	ram_wr32(fuc, 0x10f090, 0x4000007f);
-	ram_nsec(fuc, 1000);
-
-	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
-	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-	ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
-	ram_nsec(fuc, 1000);
-
-	ram_nuke(fuc, mr[0]);
-	ram_mask(fuc, mr[0], 0x100, 0x100);
-	ram_mask(fuc, mr[0], 0x100, 0x000);
-
-	ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
-	ram_wr32(fuc, mr[0], ram->base.mr[0]);
-	ram_nsec(fuc, 1000);
-
-	ram_nuke(fuc, mr[0]);
-	ram_mask(fuc, mr[0], 0x100, 0x100);
-	ram_mask(fuc, mr[0], 0x100, 0x000);
-
-	if (vc == 0 && ram_have(fuc, gpio2E)) {
-		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
-		if (temp != ram_rd32(fuc, gpio2E)) {
-			ram_wr32(fuc, gpiotrig, 1);
-			ram_nsec(fuc, 20000);
-		}
-	}
-
-	if (ram->mode != 2) {
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
-		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
-	}
-
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
-	ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
-	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
-	ram_nsec(fuc, 1000);
-
-	ram_unblock(fuc);
-	ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
-
-	if (next->bios.rammap_11_08_01)
-		data = 0x00000800;
-	else
-		data = 0x00000000;
-	ram_mask(fuc, 0x10f200, 0x00000800, data);
-	return 0;
-}
-
-/*******************************************************************************
- * main hooks
- ******************************************************************************/
-
-static int
-nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
-		   struct nouveau_ram_data *data)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nouveau_ram_data *cfg;
-	u32 mhz = khz / 1000;
-
-	list_for_each_entry(cfg, &ram->cfg, head) {
-		if (mhz >= cfg->bios.rammap_min &&
-		    mhz <= cfg->bios.rammap_max) {
-			*data = *cfg;
-			data->freq = khz;
-			return 0;
-		}
-	}
-
-	nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
-	return -EINVAL;
-}
-
-static int
-nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nve0_ramfuc *fuc = &ram->fuc;
-	int refclk, i;
-	int ret;
-
-	ret = ram_init(fuc, pfb);
-	if (ret)
-		return ret;
-
-	ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
-	ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
-
-	/* XXX: this is *not* what nvidia do.  on fermi nvidia generally
-	 * select, based on some unknown condition, one of the two possible
-	 * reference frequencies listed in the vbios table for mempll and
-	 * program refpll to that frequency.
-	 *
-	 * so far, i've seen very weird values being chosen by nvidia on
-	 * kepler boards, no idea how/why they're chosen.
-	 */
-	refclk = next->freq;
-	if (ram->mode == 2)
-		refclk = fuc->mempll.refclk;
-
-	/* calculate refpll coefficients */
-	ret = nva3_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
-			   &ram->fN1, &ram->M1, &ram->P1);
-	fuc->mempll.refclk = ret;
-	if (ret <= 0) {
-		nv_error(pfb, "unable to calc refpll\n");
-		return -EINVAL;
-	}
-
-	/* calculate mempll coefficients, if we're using it */
-	if (ram->mode == 2) {
-		/* post-divider doesn't work... the reg takes the values but
-		 * appears to completely ignore it.  there *is* a bit at
-		 * bit 28 that appears to divide the clock by 2 if set.
-		 */
-		fuc->mempll.min_p = 1;
-		fuc->mempll.max_p = 2;
-
-		ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
-				   &ram->N2, NULL, &ram->M2, &ram->P2);
-		if (ret <= 0) {
-			nv_error(pfb, "unable to calc mempll\n");
-			return -EINVAL;
-		}
-	}
-
-	for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) {
-		if (ram_have(fuc, mr[i]))
-			ram->base.mr[i] = ram_rd32(fuc, mr[i]);
-	}
-	ram->base.freq = next->freq;
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR3:
-		ret = nouveau_sddr3_calc(&ram->base);
-		if (ret == 0)
-			ret = nve0_ram_calc_sddr3(pfb, next->freq);
-		break;
-	case NV_MEM_TYPE_GDDR5:
-		ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0);
-		if (ret == 0)
-			ret = nve0_ram_calc_gddr5(pfb, next->freq);
-		break;
-	default:
-		ret = -ENOSYS;
-		break;
-	}
-
-	return ret;
-}
-
-static int
-nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nouveau_clock *clk = nouveau_clock(pfb);
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nouveau_ram_data *xits = &ram->base.xition;
-	struct nouveau_ram_data *copy;
-	int ret;
-
-	if (ram->base.next == NULL) {
-		ret = nve0_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
-					&ram->base.former);
-		if (ret)
-			return ret;
-
-		ret = nve0_ram_calc_data(pfb, freq, &ram->base.target);
-		if (ret)
-			return ret;
-
-		if (ram->base.target.freq < ram->base.former.freq) {
-			*xits = ram->base.target;
-			copy = &ram->base.former;
-		} else {
-			*xits = ram->base.former;
-			copy = &ram->base.target;
-		}
-
-		xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04;
-		xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03;
-		xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07;
-
-		ram->base.next = &ram->base.target;
-		if (memcmp(xits, &ram->base.former, sizeof(xits->bios)))
-			ram->base.next = &ram->base.xition;
-	} else {
-		BUG_ON(ram->base.next != &ram->base.xition);
-		ram->base.next = &ram->base.target;
-	}
-
-	return nve0_ram_calc_xits(pfb, ram->base.next);
-}
-
-static void
-nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nouveau_ram_data *cfg;
-	u32 mhz = freq / 1000;
-	u32 mask, data;
-
-	list_for_each_entry(cfg, &ram->cfg, head) {
-		if (mhz >= cfg->bios.rammap_min &&
-		    mhz <= cfg->bios.rammap_max)
-			break;
-	}
-
-	if (&cfg->head == &ram->cfg)
-		return;
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
-		data |= cfg->bios.rammap_11_0a_03fe << 12;
-		mask |= 0x001ff000;
-	}
-	if (ram->diff.rammap_11_09_01ff) {
-		data |= cfg->bios.rammap_11_09_01ff;
-		mask |= 0x000001ff;
-	}
-	nv_mask(pfb, 0x10f468, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
-		data |= cfg->bios.rammap_11_0a_0400;
-		mask |= 0x00000001;
-	}
-	nv_mask(pfb, 0x10f420, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
-		data |= cfg->bios.rammap_11_0a_0800;
-		mask |= 0x00000001;
-	}
-	nv_mask(pfb, 0x10f430, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
-		data |= cfg->bios.rammap_11_0b_01f0;
-		mask |= 0x0000001f;
-	}
-	nv_mask(pfb, 0x10f400, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
-		data |= cfg->bios.rammap_11_0b_0200 << 9;
-		mask |= 0x00000200;
-	}
-	nv_mask(pfb, 0x10f410, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
-		data |= cfg->bios.rammap_11_0d << 16;
-		mask |= 0x00ff0000;
-	}
-	if (ram->diff.rammap_11_0f) {
-		data |= cfg->bios.rammap_11_0f << 8;
-		mask |= 0x0000ff00;
-	}
-	nv_mask(pfb, 0x10f440, mask, data);
-
-	if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
-		data |= cfg->bios.rammap_11_0e << 8;
-		mask |= 0x0000ff00;
-	}
-	if (ram->diff.rammap_11_0b_0800) {
-		data |= cfg->bios.rammap_11_0b_0800 << 7;
-		mask |= 0x00000080;
-	}
-	if (ram->diff.rammap_11_0b_0400) {
-		data |= cfg->bios.rammap_11_0b_0400 << 5;
-		mask |= 0x00000020;
-	}
-	nv_mask(pfb, 0x10f444, mask, data);
-}
-
-static int
-nve0_ram_prog(struct nouveau_fb *pfb)
-{
-	struct nouveau_device *device = nv_device(pfb);
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nve0_ramfuc *fuc = &ram->fuc;
-	struct nouveau_ram_data *next = ram->base.next;
-
-	if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) {
-		ram_exec(fuc, false);
-		return (ram->base.next == &ram->base.xition);
-	}
-
-	nve0_ram_prog_0(pfb, 1000);
-	ram_exec(fuc, true);
-	nve0_ram_prog_0(pfb, next->freq);
-
-	return (ram->base.next == &ram->base.xition);
-}
-
-static void
-nve0_ram_tidy(struct nouveau_fb *pfb)
-{
-	struct nve0_ram *ram = (void *)pfb->ram;
-	struct nve0_ramfuc *fuc = &ram->fuc;
-	ram->base.next = NULL;
-	ram_exec(fuc, false);
-}
-
-struct nve0_ram_train {
-	u16 mask;
-	struct nvbios_M0209S remap;
-	struct nvbios_M0209S type00;
-	struct nvbios_M0209S type01;
-	struct nvbios_M0209S type04;
-	struct nvbios_M0209S type06;
-	struct nvbios_M0209S type07;
-	struct nvbios_M0209S type08;
-	struct nvbios_M0209S type09;
-};
-
-static int
-nve0_ram_train_type(struct nouveau_fb *pfb, int i, u8 ramcfg,
-		    struct nve0_ram_train *train)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nvbios_M0205E M0205E;
-	struct nvbios_M0205S M0205S;
-	struct nvbios_M0209E M0209E;
-	struct nvbios_M0209S *remap = &train->remap;
-	struct nvbios_M0209S *value;
-	u8  ver, hdr, cnt, len;
-	u32 data;
-
-	/* determine type of data for this index */
-	if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
-		return -ENOENT;
-
-	switch (M0205E.type) {
-	case 0x00: value = &train->type00; break;
-	case 0x01: value = &train->type01; break;
-	case 0x04: value = &train->type04; break;
-	case 0x06: value = &train->type06; break;
-	case 0x07: value = &train->type07; break;
-	case 0x08: value = &train->type08; break;
-	case 0x09: value = &train->type09; break;
-	default:
-		return 0;
-	}
-
-	/* training data index determined by ramcfg strap */
-	if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
-		return -EINVAL;
-	i = M0205S.data;
-
-	/* training data format information */
-	if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
-		return -EINVAL;
-
-	/* ... and the raw data */
-	if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
-		return -EINVAL;
-
-	if (M0209E.v02_07 == 2) {
-		/* of course! why wouldn't we have a pointer to another entry
-		 * in the same table, and use the first one as an array of
-		 * remap indices...
-		 */
-		if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
-					    remap)))
-			return -EINVAL;
-
-		for (i = 0; i < ARRAY_SIZE(value->data); i++)
-			value->data[i] = remap->data[value->data[i]];
-	} else
-	if (M0209E.v02_07 != 1)
-		return -EINVAL;
-
-	train->mask |= 1 << M0205E.type;
-	return 0;
-}
-
-static int
-nve0_ram_train_init_0(struct nouveau_fb *pfb, struct nve0_ram_train *train)
-{
-	int i, j;
-
-	if ((train->mask & 0x03d3) != 0x03d3) {
-		nv_warn(pfb, "missing link training data\n");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < 0x30; i++) {
-		for (j = 0; j < 8; j += 4) {
-			nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
-			nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
-						   train->type08.data[i] << 4 |
-						   train->type06.data[i]);
-			nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
-			nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
-						   train->type09.data[i] << 4 |
-						   train->type07.data[i]);
-			nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
-		}
-	}
-
-	for (j = 0; j < 8; j += 4) {
-		for (i = 0; i < 0x100; i++) {
-			nv_wr32(pfb, 0x10f968 + j, i);
-			nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
-		}
-	}
-
-	return 0;
-}
-
-static int
-nve0_ram_train_init(struct nouveau_fb *pfb)
-{
-	u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
-	struct nve0_ram_train *train;
-	int ret = -ENOMEM, i;
-
-	if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
-		for (i = 0; i < 0x100; i++) {
-			ret = nve0_ram_train_type(pfb, i, ramcfg, train);
-			if (ret && ret != -ENOENT)
-				break;
-		}
-	}
-
-	switch (pfb->ram->type) {
-	case NV_MEM_TYPE_GDDR5:
-		ret = nve0_ram_train_init_0(pfb, train);
-		break;
-	default:
-		ret = 0;
-		break;
-	}
-
-	kfree(train);
-	return ret;
-}
-
-int
-nve0_ram_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object->parent;
-	struct nve0_ram *ram   = (void *)object;
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	u8  ver, hdr, cnt, len, snr, ssz;
-	u32 data, save;
-	int ret, i;
-
-	ret = nouveau_ram_init(&ram->base);
-	if (ret)
-		return ret;
-
-	/* run a bunch of tables from rammap table.  there's actually
-	 * individual pointers for each rammap entry too, but, nvidia
-	 * seem to just run the last two entries' scripts early on in
-	 * their init, and never again.. we'll just run 'em all once
-	 * for now.
-	 *
-	 * i strongly suspect that each script is for a separate mode
-	 * (likely selected by 0x10f65c's lower bits?), and the
-	 * binary driver skips the one that's already been setup by
-	 * the init tables.
-	 */
-	data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
-	if (!data || hdr < 0x15)
-		return -EINVAL;
-
-	cnt  = nv_ro08(bios, data + 0x14); /* guess at count */
-	data = nv_ro32(bios, data + 0x10); /* guess u32... */
-	save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
-	for (i = 0; i < cnt; i++, data += 4) {
-		if (i != save >> 4) {
-			nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
-			nvbios_exec(&(struct nvbios_init) {
-					.subdev = nv_subdev(pfb),
-					.bios = bios,
-					.offset = nv_ro32(bios, data),
-					.execute = 1,
-				    });
-		}
-	}
-	nv_mask(pfb, 0x10f65c, 0x000000f0, save);
-	nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
-	nv_wr32(pfb, 0x10ecc0, 0xffffffff);
-	nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
-
-	return nve0_ram_train_init(pfb);
-}
-
-static int
-nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
-{
-	struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nouveau_ram_data *cfg;
-	struct nvbios_ramcfg *d = &ram->diff;
-	struct nvbios_ramcfg *p, *n;
-	u8  ver, hdr, cnt, len;
-	u32 data;
-	int ret;
-
-	if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
-		return -ENOMEM;
-	p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
-	n = &cfg->bios;
-
-	/* memory config data for a range of target frequencies */
-	data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
-	if (ret = -ENOENT, !data)
-		goto done;
-	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
-		goto done;
-
-	/* ... and a portion specific to the attached memory */
-	data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
-			       &ver, &hdr, &cfg->bios);
-	if (ret = -EINVAL, !data)
-		goto done;
-	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
-		goto done;
-
-	/* lookup memory timings, if bios says they're present */
-	if (cfg->bios.ramcfg_timing != 0xff) {
-		data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
-				       &ver, &hdr, &cnt, &len,
-				       &cfg->bios);
-		if (ret = -EINVAL, !data)
-			goto done;
-		if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
-			goto done;
-	}
-
-	list_add_tail(&cfg->head, &ram->cfg);
-	if (ret = 0, i == 0)
-		goto done;
-
-	d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
-	d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
-	d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
-	d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
-	d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
-	d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
-	d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
-	d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
-	d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
-	d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
-	d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
-	d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
-	d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
-	d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
-	d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
-	d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
-	d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
-done:
-	if (ret)
-		kfree(cfg);
-	return ret;
-}
-
-static void
-nve0_ram_dtor(struct nouveau_object *object)
-{
-	struct nve0_ram *ram = (void *)object;
-	struct nouveau_ram_data *cfg, *tmp;
-
-	list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
-		kfree(cfg);
-	}
-
-	nouveau_ram_destroy(&ram->base);
-}
-
-static int
-nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	struct nouveau_gpio *gpio = nouveau_gpio(pfb);
-	struct dcb_gpio_func func;
-	struct nve0_ram *ram;
-	int ret, i;
-	u8  ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
-	u32 tmp;
-
-	ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
-	*pobject = nv_object(ram);
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&ram->cfg);
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_DDR3:
-	case NV_MEM_TYPE_GDDR5:
-		ram->base.calc = nve0_ram_calc;
-		ram->base.prog = nve0_ram_prog;
-		ram->base.tidy = nve0_ram_tidy;
-		break;
-	default:
-		nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
-		break;
-	}
-
-	/* calculate a mask of differently configured memory partitions,
-	 * because, of course reclocking wasn't complicated enough
-	 * already without having to treat some of them differently to
-	 * the others....
-	 */
-	ram->parts = nv_rd32(pfb, 0x022438);
-	ram->pmask = nv_rd32(pfb, 0x022554);
-	ram->pnuts = 0;
-	for (i = 0, tmp = 0; i < ram->parts; i++) {
-		if (!(ram->pmask & (1 << i))) {
-			u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
-			if (tmp && tmp != cfg1) {
-				ram->pnuts |= (1 << i);
-				continue;
-			}
-			tmp = cfg1;
-		}
-	}
-
-	/* parse bios data for all rammap table entries up-front, and
-	 * build information on whether certain fields differ between
-	 * any of the entries.
-	 *
-	 * the binary driver appears to completely ignore some fields
-	 * when all entries contain the same value.  at first, it was
-	 * hoped that these were mere optimisations and the bios init
-	 * tables had configured as per the values here, but there is
-	 * evidence now to suggest that this isn't the case and we do
-	 * need to treat this condition as a "don't touch" indicator.
-	 */
-	for (i = 0; !ret; i++) {
-		ret = nve0_ram_ctor_data(ram, ramcfg, i);
-		if (ret && ret != -ENOENT) {
-			nv_error(pfb, "failed to parse ramcfg data\n");
-			return ret;
-		}
-	}
-
-	/* parse bios data for both pll's */
-	ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
-	if (ret) {
-		nv_error(pfb, "mclk refpll data not found\n");
-		return ret;
-	}
-
-	ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
-	if (ret) {
-		nv_error(pfb, "mclk pll data not found\n");
-		return ret;
-	}
-
-	/* lookup memory voltage gpios */
-	ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
-	if (ret == 0) {
-		ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
-		ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
-		ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
-	}
-
-	ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
-	if (ret == 0) {
-		ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
-		ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
-		ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
-	}
-
-	ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
-
-	ram->fuc.r_0x132020 = ramfuc_reg(0x132020);
-	ram->fuc.r_0x132028 = ramfuc_reg(0x132028);
-	ram->fuc.r_0x132024 = ramfuc_reg(0x132024);
-	ram->fuc.r_0x132030 = ramfuc_reg(0x132030);
-	ram->fuc.r_0x132034 = ramfuc_reg(0x132034);
-	ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
-	ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
-	ram->fuc.r_0x132040 = ramfuc_reg(0x132040);
-
-	ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248);
-	ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
-	ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
-	ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
-	ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
-	ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
-	ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4);
-	ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8);
-	ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac);
-	ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc);
-	ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8);
-	ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250);
-	ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c);
-	ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4);
-	ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8);
-	ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604);
-	ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
-	ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
-	ram->fuc.r_0x100770 = ramfuc_reg(0x100770);
-	ram->fuc.r_0x100778 = ramfuc_reg(0x100778);
-	ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224);
-
-	ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870);
-	ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698);
-	ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694);
-	ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8);
-	ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
-	ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670);
-	ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c);
-	ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
-	ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
-	ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
-	ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c);
-
-	ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978);
-	ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
-	ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
-
-	switch (ram->base.type) {
-	case NV_MEM_TYPE_GDDR5:
-		ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
-		ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
-		ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
-		ram->fuc.r_mr[3] = ramfuc_reg(0x10f338);
-		ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c);
-		ram->fuc.r_mr[5] = ramfuc_reg(0x10f340);
-		ram->fuc.r_mr[6] = ramfuc_reg(0x10f344);
-		ram->fuc.r_mr[7] = ramfuc_reg(0x10f348);
-		ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
-		ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
-		break;
-	case NV_MEM_TYPE_DDR3:
-		ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
-		ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
-		break;
-	default:
-		break;
-	}
-
-	ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000);
-	ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
-	ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
-	ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
-	ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
-	ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318);
-	ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
-	ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c);
-	ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
-	ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
-	ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4);
-	ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
-	ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
-	ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
-	ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
-	ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_ram_oclass = {
-	.handle = 0,
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_ram_ctor,
-		.dtor = nve0_ram_dtor,
-		.init = nve0_ram_init,
-		.fini = _nouveau_ram_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h
deleted file mode 100644
index 571077e..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVKM_FBRAM_SEQ_H__
-#define __NVKM_FBRAM_SEQ_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-
-#define ram_init(s,p)       hwsq_init(&(s)->base, (p))
-#define ram_exec(s,e)       hwsq_exec(&(s)->base, (e))
-#define ram_have(s,r)       ((s)->r_##r.addr != 0x000000)
-#define ram_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
-#define ram_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
-#define ram_nuke(s,r)       hwsq_nuke(&(s)->base, &(s)->r_##r)
-#define ram_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define ram_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
-#define ram_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
-#define ram_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
deleted file mode 100644
index 252575f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 Roy Spliet
- *
- * 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.
- *
- * Authors: Roy Spliet <rspliet@eclipso.eu>
- *          Ben Skeggs
- */
-
-#include "priv.h"
-
-struct ramxlat {
-	int id;
-	u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
-	while (xlat->id >= 0) {
-		if (xlat->id == id)
-			return xlat->enc;
-		xlat++;
-	}
-	return -EINVAL;
-}
-
-static const struct ramxlat
-ramddr2_cl[] = {
-	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
-	/* The following are available in some, but not all DDR2 docs */
-	{ 7, 7 },
-	{ -1 }
-};
-
-static const struct ramxlat
-ramddr2_wr[] = {
-	{ 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
-	/* The following are available in some, but not all DDR2 docs */
-	{ 7, 6 },
-	{ -1 }
-};
-
-int
-nouveau_sddr2_calc(struct nouveau_ram *ram)
-{
-	int CL, WR, DLL = 0, ODT = 0;
-
-	switch (ram->next->bios.timing_ver) {
-	case 0x10:
-		CL  = ram->next->bios.timing_10_CL;
-		WR  = ram->next->bios.timing_10_WR;
-		DLL = !ram->next->bios.ramcfg_10_DLLoff;
-		ODT = ram->next->bios.timing_10_ODT & 3;
-		break;
-	case 0x20:
-		CL  = (ram->next->bios.timing[1] & 0x0000001f);
-		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
-		break;
-	default:
-		return -ENOSYS;
-	}
-
-	CL  = ramxlat(ramddr2_cl, CL);
-	WR  = ramxlat(ramddr2_wr, WR);
-	if (CL < 0 || WR < 0)
-		return -EINVAL;
-
-	ram->mr[0] &= ~0xf70;
-	ram->mr[0] |= (WR & 0x07) << 9;
-	ram->mr[0] |= (CL & 0x07) << 4;
-
-	ram->mr[1] &= ~0x045;
-	ram->mr[1] |= (ODT & 0x1) << 2;
-	ram->mr[1] |= (ODT & 0x2) << 5;
-	ram->mr[1] |= !DLL;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
deleted file mode 100644
index a2dca48..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- * 	    Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include "priv.h"
-
-struct ramxlat {
-	int id;
-	u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
-	while (xlat->id >= 0) {
-		if (xlat->id == id)
-			return xlat->enc;
-		xlat++;
-	}
-	return -EINVAL;
-}
-
-static const struct ramxlat
-ramddr3_cl[] = {
-	{ 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
-	{ 11, 14 },
-	/* the below are mentioned in some, but not all, ddr3 docs */
-	{ 12, 1 }, { 13, 3 }, { 14, 5 },
-	{ -1 }
-};
-
-static const struct ramxlat
-ramddr3_wr[] = {
-	{ 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
-	/* the below are mentioned in some, but not all, ddr3 docs */
-	{ 14, 7 }, { 16, 0 },
-	{ -1 }
-};
-
-static const struct ramxlat
-ramddr3_cwl[] = {
-	{ 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
-	/* the below are mentioned in some, but not all, ddr3 docs */
-	{ 9, 4 },
-	{ -1 }
-};
-
-int
-nouveau_sddr3_calc(struct nouveau_ram *ram)
-{
-	int CWL, CL, WR, DLL = 0, ODT = 0;
-
-	switch (ram->next->bios.timing_ver) {
-	case 0x10:
-		if (ram->next->bios.timing_hdr < 0x17) {
-			/* XXX: NV50: Get CWL from the timing register */
-			return -ENOSYS;
-		}
-		CWL = ram->next->bios.timing_10_CWL;
-		CL  = ram->next->bios.timing_10_CL;
-		WR  = ram->next->bios.timing_10_WR;
-		DLL = !ram->next->bios.ramcfg_10_DLLoff;
-		ODT = ram->next->bios.timing_10_ODT;
-		break;
-	case 0x20:
-		CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
-		CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
-		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
-		/* XXX: Get these values from the VBIOS instead */
-		DLL = !(ram->mr[1] & 0x1);
-		ODT =   (ram->mr[1] & 0x004) >> 2 |
-			(ram->mr[1] & 0x040) >> 5 |
-		        (ram->mr[1] & 0x200) >> 7;
-		break;
-	default:
-		return -ENOSYS;
-	}
-
-	CWL = ramxlat(ramddr3_cwl, CWL);
-	CL  = ramxlat(ramddr3_cl, CL);
-	WR  = ramxlat(ramddr3_wr, WR);
-	if (CL < 0 || CWL < 0 || WR < 0)
-		return -EINVAL;
-
-	ram->mr[0] &= ~0xf74;
-	ram->mr[0] |= (WR & 0x07) << 9;
-	ram->mr[0] |= (CL & 0x0e) << 3;
-	ram->mr[0] |= (CL & 0x01) << 2;
-
-	ram->mr[1] &= ~0x245;
-	ram->mr[1] |= (ODT & 0x1) << 2;
-	ram->mr[1] |= (ODT & 0x2) << 5;
-	ram->mr[1] |= (ODT & 0x4) << 7;
-	ram->mr[1] |= !DLL;
-
-	ram->mr[2] &= ~0x038;
-	ram->mr[2] |= (CWL & 0x07) << 3;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
deleted file mode 100644
index 9e8e921..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/fuse.h>
-
-int
-_nouveau_fuse_init(struct nouveau_object *object)
-{
-	struct nouveau_fuse *fuse = (void *)object;
-	return nouveau_subdev_init(&fuse->base);
-}
-
-void
-_nouveau_fuse_dtor(struct nouveau_object *object)
-{
-	struct nouveau_fuse *fuse = (void *)object;
-	nouveau_subdev_destroy(&fuse->base);
-}
-
-int
-nouveau_fuse_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_fuse *fuse;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "FUSE",
-				     "fuse", length, pobject);
-	fuse = *pobject;
-
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
deleted file mode 100644
index a374ade..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct g80_fuse_priv {
-	struct nouveau_fuse base;
-
-	spinlock_t fuse_enable_lock;
-};
-
-static u32
-g80_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct g80_fuse_priv *priv = (void *)object;
-	unsigned long flags;
-	u32 fuse_enable, val;
-
-	spin_lock_irqsave(&priv->fuse_enable_lock, flags);
-
-	/* racy if another part of nouveau start writing to this reg */
-	fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
-	val = nv_rd32(priv, 0x21000 + addr);
-	nv_wr32(priv, 0x1084, fuse_enable);
-
-	spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
-
-	return val;
-}
-
-
-static int
-g80_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct g80_fuse_priv *priv;
-	int ret;
-
-	ret = nouveau_fuse_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	spin_lock_init(&priv->fuse_enable_lock);
-
-	return 0;
-}
-
-struct nouveau_oclass
-g80_fuse_oclass = {
-	.handle = NV_SUBDEV(FUSE, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = g80_fuse_ctor,
-		.dtor = _nouveau_fuse_dtor,
-		.init = _nouveau_fuse_init,
-		.fini = _nouveau_fuse_fini,
-		.rd32 = g80_fuse_rd32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
deleted file mode 100644
index 5ed03f5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gf100_fuse_priv {
-	struct nouveau_fuse base;
-
-	spinlock_t fuse_enable_lock;
-};
-
-static u32
-gf100_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct gf100_fuse_priv *priv = (void *)object;
-	unsigned long flags;
-	u32 fuse_enable, unk, val;
-
-	spin_lock_irqsave(&priv->fuse_enable_lock, flags);
-
-	/* racy if another part of nouveau start writing to these regs */
-	fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
-	unk = nv_mask(priv, 0x21000, 0x1, 0x1);
-	val = nv_rd32(priv, 0x21100 + addr);
-	nv_wr32(priv, 0x21000, unk);
-	nv_wr32(priv, 0x22400, fuse_enable);
-
-	spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
-
-	return val;
-}
-
-
-static int
-gf100_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct gf100_fuse_priv *priv;
-	int ret;
-
-	ret = nouveau_fuse_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	spin_lock_init(&priv->fuse_enable_lock);
-
-	return 0;
-}
-
-struct nouveau_oclass
-gf100_fuse_oclass = {
-	.handle = NV_SUBDEV(FUSE, 0xC0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gf100_fuse_ctor,
-		.dtor = _nouveau_fuse_dtor,
-		.init = _nouveau_fuse_init,
-		.fini = _nouveau_fuse_fini,
-		.rd32 = gf100_fuse_rd32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
deleted file mode 100644
index 4f1a636..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gm107_fuse_priv {
-	struct nouveau_fuse base;
-};
-
-static u32
-gm107_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct gf100_fuse_priv *priv = (void *)object;
-
-	return nv_rd32(priv, 0x21100 + addr);
-}
-
-
-static int
-gm107_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct gm107_fuse_priv *priv;
-	int ret;
-
-	ret = nouveau_fuse_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass
-gm107_fuse_oclass = {
-	.handle = NV_SUBDEV(FUSE, 0x117),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm107_fuse_ctor,
-		.dtor = _nouveau_fuse_dtor,
-		.init = _nouveau_fuse_init,
-		.fini = _nouveau_fuse_fini,
-		.rd32 = gm107_fuse_rd32,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
deleted file mode 100644
index d208541..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVKM_FUSE_PRIV_H__
-#define __NVKM_FUSE_PRIV_H__
-
-#include <subdev/fuse.h>
-
-int _nouveau_fuse_init(struct nouveau_object *object);
-void _nouveau_fuse_dtor(struct nouveau_object *object);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
deleted file mode 100644
index 7ad99b7..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-
-#include "priv.h"
-
-static int
-nouveau_gpio_drive(struct nouveau_gpio *gpio,
-		   int idx, int line, int dir, int out)
-{
-	const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-	return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
-}
-
-static int
-nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
-{
-	const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-	return impl->sense ? impl->sense(gpio, line) : -ENODEV;
-}
-
-static int
-nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
-		  struct dcb_gpio_func *func)
-{
-	struct nouveau_bios *bios = nouveau_bios(gpio);
-	u8  ver, len;
-	u16 data;
-
-	if (line == 0xff && tag == 0xff)
-		return -EINVAL;
-
-	data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
-	if (data)
-		return 0;
-
-	/* Apple iMac G4 NV18 */
-	if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
-		if (tag == DCB_GPIO_TVDAC0) {
-			*func = (struct dcb_gpio_func) {
-				.func = DCB_GPIO_TVDAC0,
-				.line = 4,
-				.log[0] = 0,
-				.log[1] = 1,
-			};
-			return 0;
-		}
-	}
-
-	return -ENOENT;
-}
-
-static int
-nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state)
-{
-	struct dcb_gpio_func func;
-	int ret;
-
-	ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
-	if (ret == 0) {
-		int dir = !!(func.log[state] & 0x02);
-		int out = !!(func.log[state] & 0x01);
-		ret = nouveau_gpio_drive(gpio, idx, func.line, dir, out);
-	}
-
-	return ret;
-}
-
-static int
-nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
-{
-	struct dcb_gpio_func func;
-	int ret;
-
-	ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
-	if (ret == 0) {
-		ret = nouveau_gpio_sense(gpio, idx, func.line);
-		if (ret >= 0)
-			ret = (ret == (func.log[1] & 1));
-	}
-
-	return ret;
-}
-
-static void
-nouveau_gpio_intr_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
-	const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-	impl->intr_mask(gpio, type, 1 << index, 0);
-}
-
-static void
-nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
-	const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-	impl->intr_mask(gpio, type, 1 << index, 1 << index);
-}
-
-static int
-nouveau_gpio_intr_ctor(struct nouveau_object *object, void *data, u32 size,
-		       struct nvkm_notify *notify)
-{
-	struct nvkm_gpio_ntfy_req *req = data;
-	if (!WARN_ON(size != sizeof(*req))) {
-		notify->size  = sizeof(struct nvkm_gpio_ntfy_rep);
-		notify->types = req->mask;
-		notify->index = req->line;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static void
-nouveau_gpio_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(subdev);
-	const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
-	u32 hi, lo, i;
-
-	impl->intr_stat(gpio, &hi, &lo);
-
-	for (i = 0; (hi | lo) && i < impl->lines; i++) {
-		struct nvkm_gpio_ntfy_rep rep = {
-			.mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
-				(NVKM_GPIO_LO * !!(lo & (1 << i))),
-		};
-		nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
-	}
-}
-
-static const struct nvkm_event_func
-nouveau_gpio_intr_func = {
-	.ctor = nouveau_gpio_intr_ctor,
-	.init = nouveau_gpio_intr_init,
-	.fini = nouveau_gpio_intr_fini,
-};
-
-int
-_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
-{
-	const struct nouveau_gpio_impl *impl = (void *)object->oclass;
-	struct nouveau_gpio *gpio = nouveau_gpio(object);
-	u32 mask = (1 << impl->lines) - 1;
-
-	impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
-	impl->intr_stat(gpio, &mask, &mask);
-
-	return nouveau_subdev_fini(&gpio->base, suspend);
-}
-
-static struct dmi_system_id gpio_reset_ids[] = {
-	{
-		.ident = "Apple Macbook 10,1",
-		.matches = {
-			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
-		}
-	},
-	{ }
-};
-
-int
-_nouveau_gpio_init(struct nouveau_object *object)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(object);
-	int ret;
-
-	ret = nouveau_subdev_init(&gpio->base);
-	if (ret)
-		return ret;
-
-	if (gpio->reset && dmi_check_system(gpio_reset_ids))
-		gpio->reset(gpio, DCB_GPIO_UNUSED);
-
-	return ret;
-}
-
-void
-_nouveau_gpio_dtor(struct nouveau_object *object)
-{
-	struct nouveau_gpio *gpio = (void *)object;
-	nvkm_event_fini(&gpio->event);
-	nouveau_subdev_destroy(&gpio->base);
-}
-
-int
-nouveau_gpio_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass,
-		     int length, void **pobject)
-{
-	const struct nouveau_gpio_impl *impl = (void *)oclass;
-	struct nouveau_gpio *gpio;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio",
-				     length, pobject);
-	gpio = *pobject;
-	if (ret)
-		return ret;
-
-	gpio->find = nouveau_gpio_find;
-	gpio->set  = nouveau_gpio_set;
-	gpio->get  = nouveau_gpio_get;
-	gpio->reset = impl->reset;
-
-	ret = nvkm_event_init(&nouveau_gpio_intr_func, 2, impl->lines,
-			      &gpio->event);
-	if (ret)
-		return ret;
-
-	nv_subdev(gpio)->intr = nouveau_gpio_intr;
-	return 0;
-}
-
-int
-_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 size,
-		   struct nouveau_object **pobject)
-{
-	struct nouveau_gpio *gpio;
-	int ret;
-
-	ret = nouveau_gpio_create(parent, engine, oclass, &gpio);
-	*pobject = nv_object(gpio);
-	if (ret)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
deleted file mode 100644
index 27ad23e..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2009 Francisco Jerez.
- * All Rights Reserved.
- *
- * 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.
- *
- */
-
-#include "priv.h"
-
-static int
-nv10_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
-	if (line < 2) {
-		line = line * 16;
-		line = nv_rd32(gpio, 0x600818) >> line;
-		return !!(line & 0x0100);
-	} else
-	if (line < 10) {
-		line = (line - 2) * 4;
-		line = nv_rd32(gpio, 0x60081c) >> line;
-		return !!(line & 0x04);
-	} else
-	if (line < 14) {
-		line = (line - 10) * 4;
-		line = nv_rd32(gpio, 0x600850) >> line;
-		return !!(line & 0x04);
-	}
-
-	return -EINVAL;
-}
-
-static int
-nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
-	u32 reg, mask, data;
-
-	if (line < 2) {
-		line = line * 16;
-		reg  = 0x600818;
-		mask = 0x00000011;
-		data = (dir << 4) | out;
-	} else
-	if (line < 10) {
-		line = (line - 2) * 4;
-		reg  = 0x60081c;
-		mask = 0x00000003;
-		data = (dir << 1) | out;
-	} else
-	if (line < 14) {
-		line = (line - 10) * 4;
-		reg  = 0x600850;
-		mask = 0x00000003;
-		data = (dir << 1) | out;
-	} else {
-		return -EINVAL;
-	}
-
-	nv_mask(gpio, reg, mask << line, data << line);
-	return 0;
-}
-
-static void
-nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
-	u32 intr = nv_rd32(gpio, 0x001104);
-	u32 stat = nv_rd32(gpio, 0x001144) & intr;
-	*lo = (stat & 0xffff0000) >> 16;
-	*hi = (stat & 0x0000ffff);
-	nv_wr32(gpio, 0x001104, intr);
-}
-
-static void
-nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
-	u32 inte = nv_rd32(gpio, 0x001144);
-	if (type & NVKM_GPIO_LO)
-		inte = (inte & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte = (inte & ~mask) | data;
-	nv_wr32(gpio, 0x001144, inte);
-}
-
-struct nouveau_oclass *
-nv10_gpio_oclass = &(struct nouveau_gpio_impl) {
-	.base.handle = NV_SUBDEV(GPIO, 0x10),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpio_ctor,
-		.dtor = _nouveau_gpio_dtor,
-		.init = _nouveau_gpio_init,
-		.fini = _nouveau_gpio_fini,
-	},
-	.lines = 16,
-	.intr_stat = nv10_gpio_intr_stat,
-	.intr_mask = nv10_gpio_intr_mask,
-	.drive = nv10_gpio_drive,
-	.sense = nv10_gpio_sense,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
deleted file mode 100644
index 2e30d5a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
-{
-	struct nouveau_bios *bios = nouveau_bios(gpio);
-	u8 ver, len;
-	u16 entry;
-	int ent = -1;
-
-	while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
-		static const u32 regs[] = { 0xe100, 0xe28c };
-		u32 data = nv_ro32(bios, entry);
-		u8  line =   (data & 0x0000001f);
-		u8  func =   (data & 0x0000ff00) >> 8;
-		u8  defs = !!(data & 0x01000000);
-		u8  unk0 = !!(data & 0x02000000);
-		u8  unk1 = !!(data & 0x04000000);
-		u32 val = (unk1 << 16) | unk0;
-		u32 reg = regs[line >> 4];
-		u32 lsh = line & 0x0f;
-
-		if ( func  == DCB_GPIO_UNUSED ||
-		    (match != DCB_GPIO_UNUSED && match != func))
-			continue;
-
-		gpio->set(gpio, 0, func, line, defs);
-
-		nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
-	}
-}
-
-int
-nv50_gpio_location(int line, u32 *reg, u32 *shift)
-{
-	const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
-
-	if (line >= 32)
-		return -EINVAL;
-
-	*reg = nv50_gpio_reg[line >> 3];
-	*shift = (line & 7) << 2;
-	return 0;
-}
-
-int
-nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
-	u32 reg, shift;
-
-	if (nv50_gpio_location(line, &reg, &shift))
-		return -EINVAL;
-
-	nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
-	return 0;
-}
-
-int
-nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
-	u32 reg, shift;
-
-	if (nv50_gpio_location(line, &reg, &shift))
-		return -EINVAL;
-
-	return !!(nv_rd32(gpio, reg) & (4 << shift));
-}
-
-static void
-nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
-	u32 intr = nv_rd32(gpio, 0x00e054);
-	u32 stat = nv_rd32(gpio, 0x00e050) & intr;
-	*lo = (stat & 0xffff0000) >> 16;
-	*hi = (stat & 0x0000ffff);
-	nv_wr32(gpio, 0x00e054, intr);
-}
-
-static void
-nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
-	u32 inte = nv_rd32(gpio, 0x00e050);
-	if (type & NVKM_GPIO_LO)
-		inte = (inte & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte = (inte & ~mask) | data;
-	nv_wr32(gpio, 0x00e050, inte);
-}
-
-struct nouveau_oclass *
-nv50_gpio_oclass = &(struct nouveau_gpio_impl) {
-	.base.handle = NV_SUBDEV(GPIO, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpio_ctor,
-		.dtor = _nouveau_gpio_dtor,
-		.init = _nouveau_gpio_init,
-		.fini = _nouveau_gpio_fini,
-	},
-	.lines = 16,
-	.intr_stat = nv50_gpio_intr_stat,
-	.intr_mask = nv50_gpio_intr_mask,
-	.drive = nv50_gpio_drive,
-	.sense = nv50_gpio_sense,
-	.reset = nv50_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c
deleted file mode 100644
index cae404c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nv94_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
-	u32 intr0 = nv_rd32(gpio, 0x00e054);
-	u32 intr1 = nv_rd32(gpio, 0x00e074);
-	u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
-	u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
-	*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
-	*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
-	nv_wr32(gpio, 0x00e054, intr0);
-	nv_wr32(gpio, 0x00e074, intr1);
-}
-
-void
-nv94_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
-	u32 inte0 = nv_rd32(gpio, 0x00e050);
-	u32 inte1 = nv_rd32(gpio, 0x00e070);
-	if (type & NVKM_GPIO_LO)
-		inte0 = (inte0 & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
-	mask >>= 16;
-	data >>= 16;
-	if (type & NVKM_GPIO_LO)
-		inte1 = (inte1 & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte1 = (inte1 & ~mask) | data;
-	nv_wr32(gpio, 0x00e050, inte0);
-	nv_wr32(gpio, 0x00e070, inte1);
-}
-
-struct nouveau_oclass *
-nv94_gpio_oclass = &(struct nouveau_gpio_impl) {
-	.base.handle = NV_SUBDEV(GPIO, 0x94),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpio_ctor,
-		.dtor = _nouveau_gpio_dtor,
-		.init = _nouveau_gpio_init,
-		.fini = _nouveau_gpio_fini,
-	},
-	.lines = 32,
-	.intr_stat = nv94_gpio_intr_stat,
-	.intr_mask = nv94_gpio_intr_mask,
-	.drive = nv50_gpio_drive,
-	.sense = nv50_gpio_sense,
-	.reset = nv50_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
deleted file mode 100644
index 480d6d2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
-{
-	struct nouveau_bios *bios = nouveau_bios(gpio);
-	u8 ver, len;
-	u16 entry;
-	int ent = -1;
-
-	while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
-		u32 data = nv_ro32(bios, entry);
-		u8  line =   (data & 0x0000003f);
-		u8  defs = !!(data & 0x00000080);
-		u8  func =   (data & 0x0000ff00) >> 8;
-		u8  unk0 =   (data & 0x00ff0000) >> 16;
-		u8  unk1 =   (data & 0x1f000000) >> 24;
-
-		if ( func  == DCB_GPIO_UNUSED ||
-		    (match != DCB_GPIO_UNUSED && match != func))
-			continue;
-
-		gpio->set(gpio, 0, func, line, defs);
-
-		nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0);
-		if (unk1--)
-			nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line);
-	}
-}
-
-int
-nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
-	u32 data = ((dir ^ 1) << 13) | (out << 12);
-	nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data);
-	nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */
-	return 0;
-}
-
-int
-nvd0_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
-	return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
-}
-
-struct nouveau_oclass *
-nvd0_gpio_oclass = &(struct nouveau_gpio_impl) {
-	.base.handle = NV_SUBDEV(GPIO, 0xd0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpio_ctor,
-		.dtor = _nouveau_gpio_dtor,
-		.init = _nouveau_gpio_init,
-		.fini = _nouveau_gpio_fini,
-	},
-	.lines = 32,
-	.intr_stat = nv94_gpio_intr_stat,
-	.intr_mask = nv94_gpio_intr_mask,
-	.drive = nvd0_gpio_drive,
-	.sense = nvd0_gpio_sense,
-	.reset = nvd0_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
deleted file mode 100644
index e1145b4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static void
-nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
-	u32 intr0 = nv_rd32(gpio, 0x00dc00);
-	u32 intr1 = nv_rd32(gpio, 0x00dc80);
-	u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0;
-	u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1;
-	*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
-	*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
-	nv_wr32(gpio, 0x00dc00, intr0);
-	nv_wr32(gpio, 0x00dc80, intr1);
-}
-
-void
-nve0_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
-	u32 inte0 = nv_rd32(gpio, 0x00dc08);
-	u32 inte1 = nv_rd32(gpio, 0x00dc88);
-	if (type & NVKM_GPIO_LO)
-		inte0 = (inte0 & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
-	mask >>= 16;
-	data >>= 16;
-	if (type & NVKM_GPIO_LO)
-		inte1 = (inte1 & ~(mask << 16)) | (data << 16);
-	if (type & NVKM_GPIO_HI)
-		inte1 = (inte1 & ~mask) | data;
-	nv_wr32(gpio, 0x00dc08, inte0);
-	nv_wr32(gpio, 0x00dc88, inte1);
-}
-
-struct nouveau_oclass *
-nve0_gpio_oclass = &(struct nouveau_gpio_impl) {
-	.base.handle = NV_SUBDEV(GPIO, 0xe0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_gpio_ctor,
-		.dtor = _nouveau_gpio_dtor,
-		.init = _nouveau_gpio_init,
-		.fini = _nouveau_gpio_fini,
-	},
-	.lines = 32,
-	.intr_stat = nve0_gpio_intr_stat,
-	.intr_mask = nve0_gpio_intr_mask,
-	.drive = nvd0_gpio_drive,
-	.sense = nvd0_gpio_sense,
-	.reset = nvd0_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
deleted file mode 100644
index bff98b8..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef __NVKM_GPIO_H__
-#define __NVKM_GPIO_H__
-
-#include <subdev/gpio.h>
-
-#define nouveau_gpio_create(p,e,o,d)                                           \
-	nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_gpio_destroy(p) ({                                             \
-	struct nouveau_gpio *gpio = (p);                                       \
-	_nouveau_gpio_dtor(nv_object(gpio));                                   \
-})
-#define nouveau_gpio_init(p) ({                                                \
-	struct nouveau_gpio *gpio = (p);                                       \
-	_nouveau_gpio_init(nv_object(gpio));                                   \
-})
-#define nouveau_gpio_fini(p,s) ({                                              \
-	struct nouveau_gpio *gpio = (p);                                       \
-	_nouveau_gpio_fini(nv_object(gpio), (s));                              \
-})
-
-int  nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
-			  struct nouveau_oclass *, int, void **);
-int  _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-void _nouveau_gpio_dtor(struct nouveau_object *);
-int  _nouveau_gpio_init(struct nouveau_object *);
-int  _nouveau_gpio_fini(struct nouveau_object *, bool);
-
-struct nouveau_gpio_impl {
-	struct nouveau_oclass base;
-	int lines;
-
-	/* read and ack pending interrupts, returning only data
-	 * for lines that have not been masked off, while still
-	 * performing the ack for anything that was pending.
-	 */
-	void (*intr_stat)(struct nouveau_gpio *, u32 *, u32 *);
-
-	/* mask on/off interrupts for hi/lo transitions on a
-	 * given set of gpio lines
-	 */
-	void (*intr_mask)(struct nouveau_gpio *, u32, u32, u32);
-
-	/* configure gpio direction and output value */
-	int  (*drive)(struct nouveau_gpio *, int line, int dir, int out);
-
-	/* sense current state of given gpio line */
-	int  (*sense)(struct nouveau_gpio *, int line);
-
-	/*XXX*/
-	void (*reset)(struct nouveau_gpio *, u8);
-};
-
-void nv50_gpio_reset(struct nouveau_gpio *, u8);
-int  nv50_gpio_drive(struct nouveau_gpio *, int, int, int);
-int  nv50_gpio_sense(struct nouveau_gpio *, int);
-
-void nv94_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
-void nv94_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
-
-void nvd0_gpio_reset(struct nouveau_gpio *, u8);
-int  nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
-int  nvd0_gpio_sense(struct nouveau_gpio *, int);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
deleted file mode 100644
index 2c2731a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "port.h"
-
-struct anx9805_i2c_port {
-	struct nouveau_i2c_port base;
-	u32 addr;
-	u32 ctrl;
-};
-
-static int
-anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
-{
-	struct anx9805_i2c_port *chan = (void *)port;
-	struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
-	u8 tmp, i;
-
-	DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh);
-
-	nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
-	nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
-	nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
-	nv_wri2cr(mast, chan->addr, 0xa8, 0x01);
-
-	i = 0;
-	while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) {
-		mdelay(5);
-		if (i++ == 100) {
-			nv_error(port, "link training timed out\n");
-			return -ETIMEDOUT;
-		}
-	}
-
-	if (tmp & 0x70) {
-		nv_error(port, "link training failed: 0x%02x\n", tmp);
-		return -EIO;
-	}
-
-	return 1;
-}
-
-static int
-anx9805_aux(struct nouveau_i2c_port *port, bool retry,
-	    u8 type, u32 addr, u8 *data, u8 size)
-{
-	struct anx9805_i2c_port *chan = (void *)port;
-	struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
-	int i, ret = -ETIMEDOUT;
-	u8 buf[16] = {};
-	u8 tmp;
-
-	DBG("%02x %05x %d\n", type, addr, size);
-
-	tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
-	nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
-	nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
-	nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
-
-	nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
-	if (!(type & 1)) {
-		memcpy(buf, data, size);
-		DBG("%16ph", buf);
-		for (i = 0; i < size; i++)
-			nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]);
-	}
-	nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
-	nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >>  0);
-	nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >>  8);
-	nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16);
-	nv_wri2cr(mast, chan->addr, 0xe9, 0x01);
-
-	i = 0;
-	while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) {
-		mdelay(5);
-		if (i++ == 32)
-			goto done;
-	}
-
-	if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) {
-		ret = -EIO;
-		goto done;
-	}
-
-	if (type & 1) {
-		for (i = 0; i < size; i++)
-			buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
-		DBG("%16ph", buf);
-		memcpy(data, buf, size);
-	}
-
-	ret = 0;
-done:
-	nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
-	return ret;
-}
-
-static const struct nouveau_i2c_func
-anx9805_aux_func = {
-	.aux = anx9805_aux,
-	.lnk_ctl = anx9805_train,
-};
-
-static int
-anx9805_aux_chan_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 index,
-		      struct nouveau_object **pobject)
-{
-	struct nouveau_i2c_port *mast = (void *)parent;
-	struct anx9805_i2c_port *chan;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_aux_algo, &anx9805_aux_func,
-				      &chan);
-	*pobject = nv_object(chan);
-	if (ret)
-		return ret;
-
-	switch ((oclass->handle & 0xff00) >> 8) {
-	case 0x0d:
-		chan->addr = 0x38;
-		chan->ctrl = 0x39;
-		break;
-	case 0x0e:
-		chan->addr = 0x3c;
-		chan->ctrl = 0x3b;
-		break;
-	default:
-		BUG_ON(1);
-	}
-
-	if (mast->adapter.algo == &i2c_bit_algo) {
-		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
-		algo->udelay = max(algo->udelay, 40);
-	}
-	return 0;
-}
-
-static struct nouveau_ofuncs
-anx9805_aux_ofuncs = {
-	.ctor =  anx9805_aux_chan_ctor,
-	.dtor = _nouveau_i2c_port_dtor,
-	.init = _nouveau_i2c_port_init,
-	.fini = _nouveau_i2c_port_fini,
-};
-
-static int
-anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-	struct anx9805_i2c_port *port = adap->algo_data;
-	struct nouveau_i2c_port *mast = (void *)nv_object(port)->parent;
-	struct i2c_msg *msg = msgs;
-	int ret = -ETIMEDOUT;
-	int i, j, cnt = num;
-	u8 seg = 0x00, off = 0x00, tmp;
-
-	tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10;
-	nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10);
-	nv_wri2cr(mast, port->ctrl, 0x07, tmp);
-	nv_wri2cr(mast, port->addr, 0x43, 0x05);
-	mdelay(5);
-
-	while (cnt--) {
-		if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
-			nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1);
-			nv_wri2cr(mast, port->addr, 0x41, seg);
-			nv_wri2cr(mast, port->addr, 0x42, off);
-			nv_wri2cr(mast, port->addr, 0x44, msg->len);
-			nv_wri2cr(mast, port->addr, 0x45, 0x00);
-			nv_wri2cr(mast, port->addr, 0x43, 0x01);
-			for (i = 0; i < msg->len; i++) {
-				j = 0;
-				while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) {
-					mdelay(5);
-					if (j++ == 32)
-						goto done;
-				}
-				msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47);
-			}
-		} else
-		if (!(msg->flags & I2C_M_RD)) {
-			if (msg->addr == 0x50 && msg->len == 0x01) {
-				off = msg->buf[0];
-			} else
-			if (msg->addr == 0x30 && msg->len == 0x01) {
-				seg = msg->buf[0];
-			} else
-				goto done;
-		} else {
-			goto done;
-		}
-		msg++;
-	}
-
-	ret = num;
-done:
-	nv_wri2cr(mast, port->addr, 0x43, 0x00);
-	return ret;
-}
-
-static u32
-anx9805_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm
-anx9805_i2c_algo = {
-	.master_xfer = anx9805_xfer,
-	.functionality = anx9805_func
-};
-
-static const struct nouveau_i2c_func
-anx9805_i2c_func = {
-};
-
-static int
-anx9805_ddc_port_ctor(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass, void *data, u32 index,
-		      struct nouveau_object **pobject)
-{
-	struct nouveau_i2c_port *mast = (void *)parent;
-	struct anx9805_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &anx9805_i2c_algo, &anx9805_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	switch ((oclass->handle & 0xff00) >> 8) {
-	case 0x0d:
-		port->addr = 0x3d;
-		port->ctrl = 0x39;
-		break;
-	case 0x0e:
-		port->addr = 0x3f;
-		port->ctrl = 0x3b;
-		break;
-	default:
-		BUG_ON(1);
-	}
-
-	if (mast->adapter.algo == &i2c_bit_algo) {
-		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
-		algo->udelay = max(algo->udelay, 40);
-	}
-	return 0;
-}
-
-static struct nouveau_ofuncs
-anx9805_ddc_ofuncs = {
-	.ctor =  anx9805_ddc_port_ctor,
-	.dtor = _nouveau_i2c_port_dtor,
-	.init = _nouveau_i2c_port_init,
-	.fini = _nouveau_i2c_port_fini,
-};
-
-struct nouveau_oclass
-nouveau_anx9805_sclass[] = {
-	{ .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs },
-	{ .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs },
-	{ .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs },
-	{ .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs },
-	{}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
deleted file mode 100644
index 02eb42b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2009 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-int
-nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(port);
-	if (port->func->aux) {
-		int ret = i2c->acquire(port, 0);
-		if (ret == 0) {
-			ret = port->func->aux(port, true, 9, addr, data, size);
-			i2c->release(port);
-		}
-		return ret;
-	}
-	return -ENODEV;
-}
-
-int
-nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(port);
-	if (port->func->aux) {
-		int ret = i2c->acquire(port, 0);
-		if (ret == 0) {
-			ret = port->func->aux(port, true, 8, addr, data, size);
-			i2c->release(port);
-		}
-		return ret;
-	}
-	return -ENODEV;
-}
-
-static int
-aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-	struct nouveau_i2c_port *port = adap->algo_data;
-	struct nouveau_i2c *i2c = nouveau_i2c(port);
-	struct i2c_msg *msg = msgs;
-	int ret, mcnt = num;
-
-	if (!port->func->aux)
-		return -ENODEV;
-
-	ret = i2c->acquire(port, 0);
-	if (ret)
-		return ret;
-
-	while (mcnt--) {
-		u8 remaining = msg->len;
-		u8 *ptr = msg->buf;
-
-		while (remaining) {
-			u8 cnt = (remaining > 16) ? 16 : remaining;
-			u8 cmd;
-
-			if (msg->flags & I2C_M_RD)
-				cmd = 1;
-			else
-				cmd = 0;
-
-			if (mcnt || remaining > 16)
-				cmd |= 4; /* MOT */
-
-			ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
-			if (ret < 0) {
-				i2c->release(port);
-				return ret;
-			}
-
-			ptr += cnt;
-			remaining -= cnt;
-		}
-
-		msg++;
-	}
-
-	i2c->release(port);
-	return num;
-}
-
-static u32
-aux_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_i2c_aux_algo = {
-	.master_xfer = aux_xfer,
-	.functionality = aux_func
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
deleted file mode 100644
index 0dc605d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-#include <core/object.h>
-#include <core/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/i2c.h>
-#include <subdev/vga.h>
-
-#include "priv.h"
-#include "pad.h"
-
-/******************************************************************************
- * interface to linux i2c bit-banging algorithm
- *****************************************************************************/
-
-#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
-#define CSTMSEL true
-#else
-#define CSTMSEL false
-#endif
-
-static int
-nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
-{
-	struct i2c_algo_bit_data *bit = adap->algo_data;
-	struct nouveau_i2c_port *port = bit->data;
-	return nouveau_i2c(port)->acquire(port, bit->timeout);
-}
-
-static void
-nouveau_i2c_post_xfer(struct i2c_adapter *adap)
-{
-	struct i2c_algo_bit_data *bit = adap->algo_data;
-	struct nouveau_i2c_port *port = bit->data;
-	return nouveau_i2c(port)->release(port);
-}
-
-static void
-nouveau_i2c_setscl(void *data, int state)
-{
-	struct nouveau_i2c_port *port = data;
-	port->func->drive_scl(port, state);
-}
-
-static void
-nouveau_i2c_setsda(void *data, int state)
-{
-	struct nouveau_i2c_port *port = data;
-	port->func->drive_sda(port, state);
-}
-
-static int
-nouveau_i2c_getscl(void *data)
-{
-	struct nouveau_i2c_port *port = data;
-	return port->func->sense_scl(port);
-}
-
-static int
-nouveau_i2c_getsda(void *data)
-{
-	struct nouveau_i2c_port *port = data;
-	return port->func->sense_sda(port);
-}
-
-/******************************************************************************
- * base i2c "port" class implementation
- *****************************************************************************/
-
-int
-_nouveau_i2c_port_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_i2c_port *port = (void *)object;
-	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
-	nv_ofuncs(pad)->fini(nv_object(pad), suspend);
-	return nouveau_object_fini(&port->base, suspend);
-}
-
-void
-_nouveau_i2c_port_dtor(struct nouveau_object *object)
-{
-	struct nouveau_i2c_port *port = (void *)object;
-	i2c_del_adapter(&port->adapter);
-	nouveau_object_destroy(&port->base);
-}
-
-int
-nouveau_i2c_port_create_(struct nouveau_object *parent,
-			 struct nouveau_object *engine,
-			 struct nouveau_oclass *oclass, u8 index,
-			 const struct i2c_algorithm *algo,
-			 const struct nouveau_i2c_func *func,
-			 int size, void **pobject)
-{
-	struct nouveau_device *device = nv_device(engine);
-	struct nouveau_i2c *i2c = (void *)engine;
-	struct nouveau_i2c_port *port;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
-	port = *pobject;
-	if (ret)
-		return ret;
-
-	snprintf(port->adapter.name, sizeof(port->adapter.name),
-		 "nouveau-%s-%d", device->name, index);
-	port->adapter.owner = THIS_MODULE;
-	port->adapter.dev.parent = nv_device_base(device);
-	port->index = index;
-	port->aux = -1;
-	port->func = func;
-	mutex_init(&port->mutex);
-
-	if ( algo == &nouveau_i2c_bit_algo &&
-	    !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
-		struct i2c_algo_bit_data *bit;
-
-		bit = kzalloc(sizeof(*bit), GFP_KERNEL);
-		if (!bit)
-			return -ENOMEM;
-
-		bit->udelay = 10;
-		bit->timeout = usecs_to_jiffies(2200);
-		bit->data = port;
-		bit->pre_xfer = nouveau_i2c_pre_xfer;
-		bit->post_xfer = nouveau_i2c_post_xfer;
-		bit->setsda = nouveau_i2c_setsda;
-		bit->setscl = nouveau_i2c_setscl;
-		bit->getsda = nouveau_i2c_getsda;
-		bit->getscl = nouveau_i2c_getscl;
-
-		port->adapter.algo_data = bit;
-		ret = i2c_bit_add_bus(&port->adapter);
-	} else {
-		port->adapter.algo_data = port;
-		port->adapter.algo = algo;
-		ret = i2c_add_adapter(&port->adapter);
-	}
-
-	if (ret == 0)
-		list_add_tail(&port->head, &i2c->ports);
-	return ret;
-}
-
-/******************************************************************************
- * base i2c subdev class implementation
- *****************************************************************************/
-
-static struct nouveau_i2c_port *
-nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
-{
-	struct nouveau_bios *bios = nouveau_bios(i2c);
-	struct nouveau_i2c_port *port;
-
-	if (index == NV_I2C_DEFAULT(0) ||
-	    index == NV_I2C_DEFAULT(1)) {
-		u8  ver, hdr, cnt, len;
-		u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
-		if (i2c && ver >= 0x30) {
-			u8 auxidx = nv_ro08(bios, i2c + 4);
-			if (index == NV_I2C_DEFAULT(0))
-				index = (auxidx & 0x0f) >> 0;
-			else
-				index = (auxidx & 0xf0) >> 4;
-		} else {
-			index = 2;
-		}
-	}
-
-	list_for_each_entry(port, &i2c->ports, head) {
-		if (port->index == index)
-			return port;
-	}
-
-	return NULL;
-}
-
-static struct nouveau_i2c_port *
-nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
-{
-	struct nouveau_i2c_port *port;
-
-	list_for_each_entry(port, &i2c->ports, head) {
-		if (nv_hclass(port) == type)
-			return port;
-	}
-
-	return NULL;
-}
-
-static void
-nouveau_i2c_release_pad(struct nouveau_i2c_port *port)
-{
-	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
-	struct nouveau_i2c *i2c = nouveau_i2c(port);
-
-	if (atomic_dec_and_test(&nv_object(pad)->usecount)) {
-		nv_ofuncs(pad)->fini(nv_object(pad), false);
-		wake_up_all(&i2c->wait);
-	}
-}
-
-static int
-nouveau_i2c_try_acquire_pad(struct nouveau_i2c_port *port)
-{
-	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
-
-	if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) {
-		struct nouveau_object *owner = (void *)pad->port;
-		do {
-			if (owner == (void *)port)
-				return 0;
-			owner = owner->parent;
-		} while(owner);
-		nouveau_i2c_release_pad(port);
-		return -EBUSY;
-	}
-
-	pad->next = port;
-	nv_ofuncs(pad)->init(nv_object(pad));
-	return 0;
-}
-
-static int
-nouveau_i2c_acquire_pad(struct nouveau_i2c_port *port, unsigned long timeout)
-{
-	struct nouveau_i2c *i2c = nouveau_i2c(port);
-
-	if (timeout) {
-		if (wait_event_timeout(i2c->wait,
-				       nouveau_i2c_try_acquire_pad(port) == 0,
-				       timeout) == 0)
-			return -EBUSY;
-	} else {
-		wait_event(i2c->wait, nouveau_i2c_try_acquire_pad(port) == 0);
-	}
-
-	return 0;
-}
-
-static void
-nouveau_i2c_release(struct nouveau_i2c_port *port)
-__releases(pad->mutex)
-{
-	nouveau_i2c(port)->release_pad(port);
-	mutex_unlock(&port->mutex);
-}
-
-static int
-nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout)
-__acquires(pad->mutex)
-{
-	int ret;
-	mutex_lock(&port->mutex);
-	if ((ret = nouveau_i2c(port)->acquire_pad(port, timeout)))
-		mutex_unlock(&port->mutex);
-	return ret;
-}
-
-static int
-nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
-		     struct nouveau_i2c_board_info *info,
-		     bool (*match)(struct nouveau_i2c_port *,
-				   struct i2c_board_info *, void *), void *data)
-{
-	struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index);
-	int i;
-
-	if (!port) {
-		nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
-		return -ENODEV;
-	}
-
-	nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
-	for (i = 0; info[i].dev.addr; i++) {
-		u8 orig_udelay = 0;
-
-		if ((port->adapter.algo == &i2c_bit_algo) &&
-		    (info[i].udelay != 0)) {
-			struct i2c_algo_bit_data *algo = port->adapter.algo_data;
-			nv_debug(i2c, "using custom udelay %d instead of %d\n",
-			         info[i].udelay, algo->udelay);
-			orig_udelay = algo->udelay;
-			algo->udelay = info[i].udelay;
-		}
-
-		if (nv_probe_i2c(port, info[i].dev.addr) &&
-		    (!match || match(port, &info[i].dev, data))) {
-			nv_info(i2c, "detected %s: %s\n", what,
-				info[i].dev.type);
-			return i;
-		}
-
-		if (orig_udelay) {
-			struct i2c_algo_bit_data *algo = port->adapter.algo_data;
-			algo->udelay = orig_udelay;
-		}
-	}
-
-	nv_debug(i2c, "no devices found.\n");
-	return -ENODEV;
-}
-
-static void
-nouveau_i2c_intr_fini(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
-	struct nouveau_i2c_port *port = i2c->find(i2c, index);
-	const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
-	if (port && port->aux >= 0)
-		impl->aux_mask(i2c, type, 1 << port->aux, 0);
-}
-
-static void
-nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
-{
-	struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
-	struct nouveau_i2c_port *port = i2c->find(i2c, index);
-	const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
-	if (port && port->aux >= 0)
-		impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
-}
-
-static int
-nouveau_i2c_intr_ctor(struct nouveau_object *object, void *data, u32 size,
-		      struct nvkm_notify *notify)
-{
-	struct nvkm_i2c_ntfy_req *req = data;
-	if (!WARN_ON(size != sizeof(*req))) {
-		notify->size  = sizeof(struct nvkm_i2c_ntfy_rep);
-		notify->types = req->mask;
-		notify->index = req->port;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static void
-nouveau_i2c_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev);
-	struct nouveau_i2c *i2c = nouveau_i2c(subdev);
-	struct nouveau_i2c_port *port;
-	u32 hi, lo, rq, tx, e;
-
-	if (impl->aux_stat) {
-		impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
-		if (hi || lo || rq || tx) {
-			list_for_each_entry(port, &i2c->ports, head) {
-				if (e = 0, port->aux < 0)
-					continue;
-
-				if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
-				if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
-				if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
-				if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
-				if (e) {
-					struct nvkm_i2c_ntfy_rep rep = {
-						.mask = e,
-					};
-					nvkm_event_send(&i2c->event, rep.mask,
-							port->index, &rep,
-							sizeof(rep));
-				}
-			}
-		}
-	}
-}
-
-static const struct nvkm_event_func
-nouveau_i2c_intr_func = {
-	.ctor = nouveau_i2c_intr_ctor,
-	.init = nouveau_i2c_intr_init,
-	.fini = nouveau_i2c_intr_fini,
-};
-
-int
-_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_i2c_impl *impl = (void *)nv_oclass(object);
-	struct nouveau_i2c *i2c = (void *)object;
-	struct nouveau_i2c_port *port;
-	u32 mask;
-	int ret;
-
-	list_for_each_entry(port, &i2c->ports, head) {
-		ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
-		if (ret && suspend)
-			goto fail;
-	}
-
-	if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
-		impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
-		impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
-	}
-
-	return nouveau_subdev_fini(&i2c->base, suspend);
-fail:
-	list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
-		nv_ofuncs(port)->init(nv_object(port));
-	}
-
-	return ret;
-}
-
-int
-_nouveau_i2c_init(struct nouveau_object *object)
-{
-	struct nouveau_i2c *i2c = (void *)object;
-	struct nouveau_i2c_port *port;
-	int ret;
-
-	ret = nouveau_subdev_init(&i2c->base);
-	if (ret == 0) {
-		list_for_each_entry(port, &i2c->ports, head) {
-			ret = nv_ofuncs(port)->init(nv_object(port));
-			if (ret)
-				goto fail;
-		}
-	}
-
-	return ret;
-fail:
-	list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
-		nv_ofuncs(port)->fini(nv_object(port), false);
-	}
-
-	return ret;
-}
-
-void
-_nouveau_i2c_dtor(struct nouveau_object *object)
-{
-	struct nouveau_i2c *i2c = (void *)object;
-	struct nouveau_i2c_port *port, *temp;
-
-	nvkm_event_fini(&i2c->event);
-
-	list_for_each_entry_safe(port, temp, &i2c->ports, head) {
-		nouveau_object_ref(NULL, (struct nouveau_object **)&port);
-	}
-
-	nouveau_subdev_destroy(&i2c->base);
-}
-
-static struct nouveau_oclass *
-nouveau_i2c_extdev_sclass[] = {
-	nouveau_anx9805_sclass,
-};
-
-static void
-nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
-			struct dcb_i2c_entry *info)
-{
-	const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
-	struct nouveau_oclass *oclass;
-	struct nouveau_object *parent;
-	struct nouveau_object *object;
-	int ret, pad;
-
-	if (info->share != DCB_I2C_UNUSED) {
-		pad    = info->share;
-		oclass = impl->pad_s;
-	} else {
-		if (type != DCB_I2C_NVIO_AUX)
-			pad = 0x100 + info->drive;
-		else
-			pad = 0x100 + info->auxch;
-		oclass = impl->pad_x;
-	}
-
-	ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
-				 &parent);
-	if (ret < 0)
-		return;
-
-	oclass = impl->sclass;
-	do {
-		ret = -EINVAL;
-		if (oclass->handle == type) {
-			ret = nouveau_object_ctor(parent, nv_object(i2c),
-						  oclass, info, index,
-						 &object);
-		}
-	} while (ret && (++oclass)->handle);
-
-	nouveau_object_ref(NULL, &parent);
-}
-
-int
-nouveau_i2c_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass,
-		    int length, void **pobject)
-{
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nouveau_i2c *i2c;
-	struct nouveau_object *object;
-	struct dcb_i2c_entry info;
-	int ret, i, j, index = -1;
-	struct dcb_output outp;
-	u8  ver, hdr;
-	u32 data;
-
-	ret = nouveau_subdev_create(parent, engine, oclass, 0,
-				    "I2C", "i2c", &i2c);
-	*pobject = nv_object(i2c);
-	if (ret)
-		return ret;
-
-	nv_subdev(i2c)->intr = nouveau_i2c_intr;
-	i2c->find = nouveau_i2c_find;
-	i2c->find_type = nouveau_i2c_find_type;
-	i2c->acquire_pad = nouveau_i2c_acquire_pad;
-	i2c->release_pad = nouveau_i2c_release_pad;
-	i2c->acquire = nouveau_i2c_acquire;
-	i2c->release = nouveau_i2c_release;
-	i2c->identify = nouveau_i2c_identify;
-	init_waitqueue_head(&i2c->wait);
-	INIT_LIST_HEAD(&i2c->ports);
-
-	while (!dcb_i2c_parse(bios, ++index, &info)) {
-		switch (info.type) {
-		case DCB_I2C_NV04_BIT:
-		case DCB_I2C_NV4E_BIT:
-		case DCB_I2C_NVIO_BIT:
-			nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
-						info.type, &info);
-			break;
-		case DCB_I2C_NVIO_AUX:
-			nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
-						info.type, &info);
-			break;
-		case DCB_I2C_PMGR:
-			if (info.drive != DCB_I2C_UNUSED) {
-				nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
-							DCB_I2C_NVIO_BIT,
-							&info);
-			}
-			if (info.auxch != DCB_I2C_UNUSED) {
-				nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
-							DCB_I2C_NVIO_AUX,
-							&info);
-			}
-			break;
-		case DCB_I2C_UNUSED:
-		default:
-			continue;
-		}
-	}
-
-	/* in addition to the busses specified in the i2c table, there
-	 * may be ddc/aux channels hiding behind external tmds/dp/etc
-	 * transmitters.
-	 */
-	index = NV_I2C_EXT(0);
-	i = -1;
-	while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
-		if (!outp.location || !outp.extdev)
-			continue;
-
-		switch (outp.type) {
-		case DCB_OUTPUT_TMDS:
-			info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
-			break;
-		case DCB_OUTPUT_DP:
-			info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
-			break;
-		default:
-			continue;
-		}
-
-		ret = -ENODEV;
-		j = -1;
-		while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) {
-			parent = nv_object(i2c->find(i2c, outp.i2c_index));
-			oclass = nouveau_i2c_extdev_sclass[j];
-			do {
-				if (oclass->handle != info.type)
-					continue;
-				ret = nouveau_object_ctor(parent, *pobject,
-							  oclass, NULL,
-							  index++, &object);
-			} while (ret && (++oclass)->handle);
-		}
-	}
-
-	ret = nvkm_event_init(&nouveau_i2c_intr_func, 4, index, &i2c->event);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-int
-_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_i2c *i2c;
-	int ret;
-
-	ret = nouveau_i2c_create(parent, engine, oclass, &i2c);
-	*pobject = nv_object(i2c);
-	if (ret)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
deleted file mode 100644
index 813ffc9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
-#define T_TIMEOUT  2200000
-#define T_RISEFALL 1000
-#define T_HOLD     5000
-
-static inline void
-i2c_drive_scl(struct nouveau_i2c_port *port, int state)
-{
-	port->func->drive_scl(port, state);
-}
-
-static inline void
-i2c_drive_sda(struct nouveau_i2c_port *port, int state)
-{
-	port->func->drive_sda(port, state);
-}
-
-static inline int
-i2c_sense_scl(struct nouveau_i2c_port *port)
-{
-	return port->func->sense_scl(port);
-}
-
-static inline int
-i2c_sense_sda(struct nouveau_i2c_port *port)
-{
-	return port->func->sense_sda(port);
-}
-
-static void
-i2c_delay(struct nouveau_i2c_port *port, u32 nsec)
-{
-	udelay((nsec + 500) / 1000);
-}
-
-static bool
-i2c_raise_scl(struct nouveau_i2c_port *port)
-{
-	u32 timeout = T_TIMEOUT / T_RISEFALL;
-
-	i2c_drive_scl(port, 1);
-	do {
-		i2c_delay(port, T_RISEFALL);
-	} while (!i2c_sense_scl(port) && --timeout);
-
-	return timeout != 0;
-}
-
-static int
-i2c_start(struct nouveau_i2c_port *port)
-{
-	int ret = 0;
-
-	if (!i2c_sense_scl(port) ||
-	    !i2c_sense_sda(port)) {
-		i2c_drive_scl(port, 0);
-		i2c_drive_sda(port, 1);
-		if (!i2c_raise_scl(port))
-			ret = -EBUSY;
-	}
-
-	i2c_drive_sda(port, 0);
-	i2c_delay(port, T_HOLD);
-	i2c_drive_scl(port, 0);
-	i2c_delay(port, T_HOLD);
-	return ret;
-}
-
-static void
-i2c_stop(struct nouveau_i2c_port *port)
-{
-	i2c_drive_scl(port, 0);
-	i2c_drive_sda(port, 0);
-	i2c_delay(port, T_RISEFALL);
-
-	i2c_drive_scl(port, 1);
-	i2c_delay(port, T_HOLD);
-	i2c_drive_sda(port, 1);
-	i2c_delay(port, T_HOLD);
-}
-
-static int
-i2c_bitw(struct nouveau_i2c_port *port, int sda)
-{
-	i2c_drive_sda(port, sda);
-	i2c_delay(port, T_RISEFALL);
-
-	if (!i2c_raise_scl(port))
-		return -ETIMEDOUT;
-	i2c_delay(port, T_HOLD);
-
-	i2c_drive_scl(port, 0);
-	i2c_delay(port, T_HOLD);
-	return 0;
-}
-
-static int
-i2c_bitr(struct nouveau_i2c_port *port)
-{
-	int sda;
-
-	i2c_drive_sda(port, 1);
-	i2c_delay(port, T_RISEFALL);
-
-	if (!i2c_raise_scl(port))
-		return -ETIMEDOUT;
-	i2c_delay(port, T_HOLD);
-
-	sda = i2c_sense_sda(port);
-
-	i2c_drive_scl(port, 0);
-	i2c_delay(port, T_HOLD);
-	return sda;
-}
-
-static int
-i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last)
-{
-	int i, bit;
-
-	*byte = 0;
-	for (i = 7; i >= 0; i--) {
-		bit = i2c_bitr(port);
-		if (bit < 0)
-			return bit;
-		*byte |= bit << i;
-	}
-
-	return i2c_bitw(port, last ? 1 : 0);
-}
-
-static int
-i2c_put_byte(struct nouveau_i2c_port *port, u8 byte)
-{
-	int i, ret;
-	for (i = 7; i >= 0; i--) {
-		ret = i2c_bitw(port, !!(byte & (1 << i)));
-		if (ret < 0)
-			return ret;
-	}
-
-	ret = i2c_bitr(port);
-	if (ret == 1) /* nack */
-		ret = -EIO;
-	return ret;
-}
-
-static int
-i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
-{
-	u32 addr = msg->addr << 1;
-	if (msg->flags & I2C_M_RD)
-		addr |= 1;
-	return i2c_put_byte(port, addr);
-}
-
-static int
-i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-	struct nouveau_i2c_port *port = adap->algo_data;
-	struct i2c_msg *msg = msgs;
-	int ret = 0, mcnt = num;
-
-	ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
-	if (ret)
-		return ret;
-
-	while (!ret && mcnt--) {
-		u8 remaining = msg->len;
-		u8 *ptr = msg->buf;
-
-		ret = i2c_start(port);
-		if (ret == 0)
-			ret = i2c_addr(port, msg);
-
-		if (msg->flags & I2C_M_RD) {
-			while (!ret && remaining--)
-				ret = i2c_get_byte(port, ptr++, !remaining);
-		} else {
-			while (!ret && remaining--)
-				ret = i2c_put_byte(port, *ptr++);
-		}
-
-		msg++;
-	}
-
-	i2c_stop(port);
-	nouveau_i2c(port)->release(port);
-	return (ret < 0) ? ret : num;
-}
-#else
-static int
-i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-	return -ENODEV;
-}
-#endif
-
-static u32
-i2c_bit_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_i2c_bit_algo = {
-	.master_xfer = i2c_bit_xfer,
-	.functionality = i2c_bit_func
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c
deleted file mode 100644
index fa891c3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-gf117_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0xd7),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nvd0_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-	.pad_s = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c
deleted file mode 100644
index 06a2b87..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
-#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct nouveau_i2c *aux, int ch)
-{
-	nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct nouveau_i2c *aux, int ch)
-{
-	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
-	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
-	const u32 urep = unksel ? 0x01000000 : 0x02000000;
-	u32 ctrl, timeout;
-
-	/* wait up to 1ms for any previous transaction to be done... */
-	timeout = 1000;
-	do {
-		ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
-		udelay(1);
-		if (!timeout--) {
-			AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
-			return -EBUSY;
-		}
-	} while (ctrl & 0x03010000);
-
-	/* set some magic, and wait up to 1ms for it to appear */
-	nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
-	timeout = 1000;
-	do {
-		ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
-		udelay(1);
-		if (!timeout--) {
-			AUX_ERR("magic wait 0x%08x\n", ctrl);
-			auxch_fini(aux, ch);
-			return -EBUSY;
-		}
-	} while ((ctrl & 0x03000000) != urep);
-
-	return 0;
-}
-
-int
-gm204_aux(struct nouveau_i2c_port *base, bool retry,
-	 u8 type, u32 addr, u8 *data, u8 size)
-{
-	struct nouveau_i2c *aux = nouveau_i2c(base);
-	struct nv50_i2c_port *port = (void *)base;
-	u32 ctrl, stat, timeout, retries;
-	u32 xbuf[4] = {};
-	int ch = port->addr;
-	int ret, i;
-
-	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
-	ret = auxch_init(aux, ch);
-	if (ret)
-		goto out;
-
-	stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
-	if (!(stat & 0x10000000)) {
-		AUX_DBG("sink not detected\n");
-		ret = -ENXIO;
-		goto out;
-	}
-
-	if (!(type & 1)) {
-		memcpy(xbuf, data, size);
-		for (i = 0; i < 16; i += 4) {
-			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
-			nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
-		}
-	}
-
-	ctrl  = nv_rd32(aux, 0x00d954 + (ch * 0x50));
-	ctrl &= ~0x0001f0ff;
-	ctrl |= type << 12;
-	ctrl |= size - 1;
-	nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
-
-	/* (maybe) retry transaction a number of times on failure... */
-	for (retries = 0; !ret && retries < 32; retries++) {
-		/* reset, and delay a while if this is a retry */
-		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
-		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
-		if (retries)
-			udelay(400);
-
-		/* transaction request, wait up to 1ms for it to complete */
-		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
-
-		timeout = 1000;
-		do {
-			ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
-			udelay(1);
-			if (!timeout--) {
-				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
-				ret = -EIO;
-				goto out;
-			}
-		} while (ctrl & 0x00010000);
-		ret = 1;
-
-		/* read status, and check if transaction completed ok */
-		stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
-		if ((stat & 0x000f0000) == 0x00080000 ||
-		    (stat & 0x000f0000) == 0x00020000)
-			ret = retry ? 0 : 1;
-		if ((stat & 0x00000100))
-			ret = -ETIMEDOUT;
-		if ((stat & 0x00000e00))
-			ret = -EIO;
-
-		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
-	}
-
-	if (type & 1) {
-		for (i = 0; i < 16; i += 4) {
-			xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
-			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
-		}
-		memcpy(data, xbuf, size);
-	}
-
-out:
-	auxch_fini(aux, ch);
-	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
-}
-
-static const struct nouveau_i2c_func
-gm204_aux_func = {
-	.aux       = gm204_aux,
-};
-
-int
-gm204_aux_port_ctor(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, void *data, u32 index,
-		    struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv50_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_aux_algo, &gm204_aux_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	port->base.aux = info->auxch;
-	port->addr = info->auxch;
-	return 0;
-}
-
-struct nouveau_oclass
-gm204_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nvd0_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = nv50_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = gm204_aux_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = _nouveau_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-gm204_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0x24),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = gm204_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-	.pad_s = &gm204_i2c_pad_oclass,
-	.aux = 8,
-	.aux_stat = nve0_aux_stat,
-	.aux_mask = nve0_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
deleted file mode 100644
index b1725bd..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-struct nv04_i2c_priv {
-	struct nouveau_i2c base;
-};
-
-struct nv04_i2c_port {
-	struct nouveau_i2c_port base;
-	u8 drive;
-	u8 sense;
-};
-
-static void
-nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
-	struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv04_i2c_port *port = (void *)base;
-	u8 val = nv_rdvgac(priv, 0, port->drive);
-	if (state) val |= 0x20;
-	else	   val &= 0xdf;
-	nv_wrvgac(priv, 0, port->drive, val | 0x01);
-}
-
-static void
-nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
-	struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv04_i2c_port *port = (void *)base;
-	u8 val = nv_rdvgac(priv, 0, port->drive);
-	if (state) val |= 0x10;
-	else	   val &= 0xef;
-	nv_wrvgac(priv, 0, port->drive, val | 0x01);
-}
-
-static int
-nv04_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
-	struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv04_i2c_port *port = (void *)base;
-	return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
-}
-
-static int
-nv04_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
-	struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv04_i2c_port *port = (void *)base;
-	return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
-}
-
-static const struct nouveau_i2c_func
-nv04_i2c_func = {
-	.drive_scl = nv04_i2c_drive_scl,
-	.drive_sda = nv04_i2c_drive_sda,
-	.sense_scl = nv04_i2c_sense_scl,
-	.sense_sda = nv04_i2c_sense_sda,
-};
-
-static int
-nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv04_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_bit_algo, &nv04_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	port->drive = info->drive;
-	port->sense = info->sense;
-	return 0;
-}
-
-static struct nouveau_oclass
-nv04_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv04_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = _nouveau_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-nv04_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nv04_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
deleted file mode 100644
index f16c87c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-struct nv4e_i2c_priv {
-	struct nouveau_i2c base;
-};
-
-struct nv4e_i2c_port {
-	struct nouveau_i2c_port base;
-	u32 addr;
-};
-
-static void
-nv4e_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
-	struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv4e_i2c_port *port = (void *)base;
-	nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
-}
-
-static void
-nv4e_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
-	struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv4e_i2c_port *port = (void *)base;
-	nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
-}
-
-static int
-nv4e_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
-	struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv4e_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00040000);
-}
-
-static int
-nv4e_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
-	struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv4e_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00080000);
-}
-
-static const struct nouveau_i2c_func
-nv4e_i2c_func = {
-	.drive_scl = nv4e_i2c_drive_scl,
-	.drive_sda = nv4e_i2c_drive_sda,
-	.sense_scl = nv4e_i2c_sense_scl,
-	.sense_sda = nv4e_i2c_sense_sda,
-};
-
-static int
-nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv4e_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_bit_algo, &nv4e_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	port->addr = 0x600800 + info->drive;
-	return 0;
-}
-
-static struct nouveau_oclass
-nv4e_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv4e_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = _nouveau_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-nv4e_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0x4e),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nv4e_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
deleted file mode 100644
index 7b8756d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nv50_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	if (state) port->state |= 0x01;
-	else	   port->state &= 0xfe;
-	nv_wr32(priv, port->addr, port->state);
-}
-
-void
-nv50_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	if (state) port->state |= 0x02;
-	else	   port->state &= 0xfd;
-	nv_wr32(priv, port->addr, port->state);
-}
-
-int
-nv50_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00000001);
-}
-
-int
-nv50_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00000002);
-}
-
-static const struct nouveau_i2c_func
-nv50_i2c_func = {
-	.drive_scl = nv50_i2c_drive_scl,
-	.drive_sda = nv50_i2c_drive_sda,
-	.sense_scl = nv50_i2c_sense_scl,
-	.sense_sda = nv50_i2c_sense_sda,
-};
-
-const u32 nv50_i2c_addr[] = {
-	0x00e138, 0x00e150, 0x00e168, 0x00e180,
-	0x00e254, 0x00e274, 0x00e764, 0x00e780,
-	0x00e79c, 0x00e7b8
-};
-const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
-
-static int
-nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv50_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_bit_algo, &nv50_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	if (info->drive >= nv50_i2c_addr_nr)
-		return -EINVAL;
-
-	port->state = 0x00000007;
-	port->addr = nv50_i2c_addr[info->drive];
-	return 0;
-}
-
-int
-nv50_i2c_port_init(struct nouveau_object *object)
-{
-	struct nv50_i2c_priv *priv = (void *)object->engine;
-	struct nv50_i2c_port *port = (void *)object;
-	nv_wr32(priv, port->addr, port->state);
-	return nouveau_i2c_port_init(&port->base);
-}
-
-static struct nouveau_oclass
-nv50_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv50_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = nv50_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-nv50_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nv50_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
deleted file mode 100644
index 9ef9656..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __NV50_I2C_H__
-#define __NV50_I2C_H__
-
-#include "priv.h"
-
-struct nv50_i2c_priv {
-	struct nouveau_i2c base;
-};
-
-struct nv50_i2c_port {
-	struct nouveau_i2c_port base;
-	u32 addr;
-	u32 state;
-};
-
-extern const u32 nv50_i2c_addr[];
-extern const int nv50_i2c_addr_nr;
-int  nv50_i2c_port_init(struct nouveau_object *);
-int  nv50_i2c_sense_scl(struct nouveau_i2c_port *);
-int  nv50_i2c_sense_sda(struct nouveau_i2c_port *);
-void nv50_i2c_drive_scl(struct nouveau_i2c_port *, int state);
-void nv50_i2c_drive_sda(struct nouveau_i2c_port *, int state);
-
-int  nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-void nv94_i2c_acquire(struct nouveau_i2c_port *);
-void nv94_i2c_release(struct nouveau_i2c_port *);
-
-int  nvd0_i2c_port_ctor(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, void *, u32,
-			struct nouveau_object **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
deleted file mode 100644
index e383ee8..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
-{
-	u32 intr = nv_rd32(i2c, 0x00e06c);
-	u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
-	for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
-		if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
-		if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
-		if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
-		if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
-	}
-	nv_wr32(i2c, 0x00e06c, intr);
-}
-
-void
-nv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
-{
-	u32 temp = nv_rd32(i2c, 0x00e068), i;
-	for (i = 0; i < 8; i++) {
-		if (mask & (1 << i)) {
-			if (!(data & (1 << i))) {
-				temp &= ~(type << (i * 4));
-				continue;
-			}
-			temp |= type << (i * 4);
-		}
-	}
-	nv_wr32(i2c, 0x00e068, temp);
-}
-
-#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
-#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct nouveau_i2c *aux, int ch)
-{
-	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct nouveau_i2c *aux, int ch)
-{
-	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
-	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
-	const u32 urep = unksel ? 0x01000000 : 0x02000000;
-	u32 ctrl, timeout;
-
-	/* wait up to 1ms for any previous transaction to be done... */
-	timeout = 1000;
-	do {
-		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
-		udelay(1);
-		if (!timeout--) {
-			AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
-			return -EBUSY;
-		}
-	} while (ctrl & 0x03010000);
-
-	/* set some magic, and wait up to 1ms for it to appear */
-	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
-	timeout = 1000;
-	do {
-		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
-		udelay(1);
-		if (!timeout--) {
-			AUX_ERR("magic wait 0x%08x\n", ctrl);
-			auxch_fini(aux, ch);
-			return -EBUSY;
-		}
-	} while ((ctrl & 0x03000000) != urep);
-
-	return 0;
-}
-
-int
-nv94_aux(struct nouveau_i2c_port *base, bool retry,
-	 u8 type, u32 addr, u8 *data, u8 size)
-{
-	struct nouveau_i2c *aux = nouveau_i2c(base);
-	struct nv50_i2c_port *port = (void *)base;
-	u32 ctrl, stat, timeout, retries;
-	u32 xbuf[4] = {};
-	int ch = port->addr;
-	int ret, i;
-
-	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
-	ret = auxch_init(aux, ch);
-	if (ret)
-		goto out;
-
-	stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
-	if (!(stat & 0x10000000)) {
-		AUX_DBG("sink not detected\n");
-		ret = -ENXIO;
-		goto out;
-	}
-
-	if (!(type & 1)) {
-		memcpy(xbuf, data, size);
-		for (i = 0; i < 16; i += 4) {
-			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
-			nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
-		}
-	}
-
-	ctrl  = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
-	ctrl &= ~0x0001f0ff;
-	ctrl |= type << 12;
-	ctrl |= size - 1;
-	nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
-
-	/* (maybe) retry transaction a number of times on failure... */
-	for (retries = 0; !ret && retries < 32; retries++) {
-		/* reset, and delay a while if this is a retry */
-		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
-		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
-		if (retries)
-			udelay(400);
-
-		/* transaction request, wait up to 1ms for it to complete */
-		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-
-		timeout = 1000;
-		do {
-			ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
-			udelay(1);
-			if (!timeout--) {
-				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
-				ret = -EIO;
-				goto out;
-			}
-		} while (ctrl & 0x00010000);
-		ret = 1;
-
-		/* read status, and check if transaction completed ok */
-		stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
-		if ((stat & 0x000f0000) == 0x00080000 ||
-		    (stat & 0x000f0000) == 0x00020000)
-			ret = retry ? 0 : 1;
-		if ((stat & 0x00000100))
-			ret = -ETIMEDOUT;
-		if ((stat & 0x00000e00))
-			ret = -EIO;
-
-		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
-	}
-
-	if (type & 1) {
-		for (i = 0; i < 16; i += 4) {
-			xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
-			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
-		}
-		memcpy(data, xbuf, size);
-	}
-
-out:
-	auxch_fini(aux, ch);
-	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
-}
-
-static const struct nouveau_i2c_func
-nv94_i2c_func = {
-	.drive_scl = nv50_i2c_drive_scl,
-	.drive_sda = nv50_i2c_drive_sda,
-	.sense_scl = nv50_i2c_sense_scl,
-	.sense_sda = nv50_i2c_sense_sda,
-};
-
-static int
-nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv50_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_bit_algo, &nv94_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	if (info->drive >= nv50_i2c_addr_nr)
-		return -EINVAL;
-
-	port->state = 7;
-	port->addr = nv50_i2c_addr[info->drive];
-	return 0;
-}
-
-static const struct nouveau_i2c_func
-nv94_aux_func = {
-	.aux       = nv94_aux,
-};
-
-int
-nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv50_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_aux_algo, &nv94_aux_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	port->base.aux = info->auxch;
-	port->addr = info->auxch;
-	return 0;
-}
-
-static struct nouveau_oclass
-nv94_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv94_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = nv50_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv94_aux_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = _nouveau_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-nv94_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0x94),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nv94_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-	.pad_s = &nv94_i2c_pad_oclass,
-	.aux = 4,
-	.aux_stat = nv94_aux_stat,
-	.aux_mask = nv94_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
deleted file mode 100644
index fd99380..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static int
-nvd0_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00000010);
-}
-
-static int
-nvd0_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
-	struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
-	struct nv50_i2c_port *port = (void *)base;
-	return !!(nv_rd32(priv, port->addr) & 0x00000020);
-}
-
-static const struct nouveau_i2c_func
-nvd0_i2c_func = {
-	.drive_scl = nv50_i2c_drive_scl,
-	.drive_sda = nv50_i2c_drive_sda,
-	.sense_scl = nvd0_i2c_sense_scl,
-	.sense_sda = nvd0_i2c_sense_sda,
-};
-
-int
-nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct dcb_i2c_entry *info = data;
-	struct nv50_i2c_port *port;
-	int ret;
-
-	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
-				      &nouveau_i2c_bit_algo, &nvd0_i2c_func,
-				      &port);
-	*pobject = nv_object(port);
-	if (ret)
-		return ret;
-
-	port->state = 0x00000007;
-	port->addr = 0x00d014 + (info->drive * 0x20);
-	return 0;
-}
-
-struct nouveau_oclass
-nvd0_i2c_sclass[] = {
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nvd0_i2c_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = nv50_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
-	  .ofuncs = &(struct nouveau_ofuncs) {
-		  .ctor = nv94_aux_port_ctor,
-		  .dtor = _nouveau_i2c_port_dtor,
-		  .init = _nouveau_i2c_port_init,
-		  .fini = _nouveau_i2c_port_fini,
-	  },
-	},
-	{}
-};
-
-struct nouveau_oclass *
-nvd0_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0xd0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nvd0_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-	.pad_s = &nv94_i2c_pad_oclass,
-	.aux = 4,
-	.aux_stat = nv94_aux_stat,
-	.aux_mask = nv94_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
deleted file mode 100644
index 25fe5c2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
-{
-	u32 intr = nv_rd32(i2c, 0x00dc60);
-	u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i;
-	for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
-		if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
-		if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
-		if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
-		if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
-	}
-	nv_wr32(i2c, 0x00dc60, intr);
-}
-
-void
-nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
-{
-	u32 temp = nv_rd32(i2c, 0x00dc68), i;
-	for (i = 0; i < 8; i++) {
-		if (mask & (1 << i)) {
-			if (!(data & (1 << i))) {
-				temp &= ~(type << (i * 4));
-				continue;
-			}
-			temp |= type << (i * 4);
-		}
-	}
-	nv_wr32(i2c, 0x00dc68, temp);
-}
-
-struct nouveau_oclass *
-nve0_i2c_oclass = &(struct nouveau_i2c_impl) {
-	.base.handle = NV_SUBDEV(I2C, 0xe0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_i2c_ctor,
-		.dtor = _nouveau_i2c_dtor,
-		.init = _nouveau_i2c_init,
-		.fini = _nouveau_i2c_fini,
-	},
-	.sclass = nvd0_i2c_sclass,
-	.pad_x = &nv04_i2c_pad_oclass,
-	.pad_s = &nv94_i2c_pad_oclass,
-	.aux = 4,
-	.aux_stat = nve0_aux_stat,
-	.aux_mask = nve0_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
deleted file mode 100644
index e9e4124..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-int
-_nvkm_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nvkm_i2c_pad *pad = (void *)object;
-	DBG("-> NULL\n");
-	pad->port = NULL;
-	return nouveau_object_fini(&pad->base, suspend);
-}
-
-int
-_nvkm_i2c_pad_init(struct nouveau_object *object)
-{
-	struct nvkm_i2c_pad *pad = (void *)object;
-	DBG("-> PORT:%02x\n", pad->next->index);
-	pad->port = pad->next;
-	return nouveau_object_init(&pad->base);
-}
-
-int
-nvkm_i2c_pad_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, int index,
-		     int size, void **pobject)
-{
-	struct nouveau_i2c *i2c = (void *)engine;
-	struct nouveau_i2c_port *port;
-	struct nvkm_i2c_pad *pad;
-	int ret;
-
-	list_for_each_entry(port, &i2c->ports, head) {
-		pad = nvkm_i2c_pad(port);
-		if (pad->index == index) {
-			atomic_inc(&nv_object(pad)->refcount);
-			*pobject = pad;
-			return 1;
-		}
-	}
-
-	ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
-	pad = *pobject;
-	if (ret)
-		return ret;
-
-	pad->index = index;
-	return 0;
-}
-
-int
-_nvkm_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, void *data, u32 index,
-		   struct nouveau_object **pobject)
-{
-	struct nvkm_i2c_pad *pad;
-	int ret;
-	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
-	*pobject = nv_object(pad);
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
deleted file mode 100644
index 452ac10..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef __NVKM_I2C_PAD_H__
-#define __NVKM_I2C_PAD_H__
-
-#include "priv.h"
-
-struct nvkm_i2c_pad {
-	struct nouveau_object base;
-	int index;
-	struct nouveau_i2c_port *port;
-	struct nouveau_i2c_port *next;
-};
-
-static inline struct nvkm_i2c_pad *
-nvkm_i2c_pad(struct nouveau_i2c_port *port)
-{
-	struct nouveau_object *pad = nv_object(port);
-	while (pad->parent)
-		pad = pad->parent;
-	return (void *)pad;
-}
-
-#define nvkm_i2c_pad_create(p,e,o,i,d)                                         \
-	nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
-#define nvkm_i2c_pad_destroy(p) ({                                             \
-	struct nvkm_i2c_pad *_p = (p);                                         \
-	_nvkm_i2c_pad_dtor(nv_object(_p));                                     \
-})
-#define nvkm_i2c_pad_init(p) ({                                                \
-	struct nvkm_i2c_pad *_p = (p);                                         \
-	_nvkm_i2c_pad_init(nv_object(_p));                                     \
-})
-#define nvkm_i2c_pad_fini(p,s) ({                                              \
-	struct nvkm_i2c_pad *_p = (p);                                         \
-	_nvkm_i2c_pad_fini(nv_object(_p), (s));                                \
-})
-
-int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *,
-			 struct nouveau_oclass *, int index, int, void **);
-
-int _nvkm_i2c_pad_ctor(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, void *, u32,
-		       struct nouveau_object **);
-#define _nvkm_i2c_pad_dtor nouveau_object_destroy
-int _nvkm_i2c_pad_init(struct nouveau_object *);
-int _nvkm_i2c_pad_fini(struct nouveau_object *, bool);
-
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-	struct nvkm_i2c_pad *_pad = (void *)pad;                               \
-	nv_##l(nv_object(_pad)->engine, "PAD:%c:%02x: "f,                      \
-	       _pad->index >= 0x100 ? 'X' : 'S',                               \
-	       _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c
deleted file mode 100644
index f0e6fbb..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct gm204_i2c_pad {
-	struct nvkm_i2c_pad base;
-	int addr;
-};
-
-static int
-gm204_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_i2c *i2c = (void *)object->engine;
-	struct gm204_i2c_pad *pad = (void *)object;
-	nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001);
-	return nvkm_i2c_pad_fini(&pad->base, suspend);
-}
-
-static int
-gm204_i2c_pad_init(struct nouveau_object *object)
-{
-	struct nouveau_i2c *i2c = (void *)object->engine;
-	struct gm204_i2c_pad *pad = (void *)object;
-
-	switch (nv_oclass(pad->base.next)->handle) {
-	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
-		nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002);
-		break;
-	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
-	default:
-		nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001);
-		break;
-	}
-
-	nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000);
-	return nvkm_i2c_pad_init(&pad->base);
-}
-
-static int
-gm204_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 index,
-		  struct nouveau_object **pobject)
-{
-	struct gm204_i2c_pad *pad;
-	int ret;
-
-	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
-	*pobject = nv_object(pad);
-	if (ret)
-		return ret;
-
-	pad->addr = index * 0x50;;
-	return 0;
-}
-
-struct nouveau_oclass
-gm204_i2c_pad_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm204_i2c_pad_ctor,
-		.dtor = _nvkm_i2c_pad_dtor,
-		.init = gm204_i2c_pad_init,
-		.fini = gm204_i2c_pad_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
deleted file mode 100644
index 2c4b612..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct nouveau_oclass
-nv04_i2c_pad_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nvkm_i2c_pad_ctor,
-		.dtor = _nvkm_i2c_pad_dtor,
-		.init = _nvkm_i2c_pad_init,
-		.fini = _nvkm_i2c_pad_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
deleted file mode 100644
index 0dc6753..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct nv94_i2c_pad {
-	struct nvkm_i2c_pad base;
-	int addr;
-};
-
-static int
-nv94_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_i2c *i2c = (void *)object->engine;
-	struct nv94_i2c_pad *pad = (void *)object;
-	nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001);
-	return nvkm_i2c_pad_fini(&pad->base, suspend);
-}
-
-static int
-nv94_i2c_pad_init(struct nouveau_object *object)
-{
-	struct nouveau_i2c *i2c = (void *)object->engine;
-	struct nv94_i2c_pad *pad = (void *)object;
-
-	switch (nv_oclass(pad->base.next)->handle) {
-	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
-		nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002);
-		break;
-	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
-	default:
-		nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001);
-		break;
-	}
-
-	nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000);
-	return nvkm_i2c_pad_init(&pad->base);
-}
-
-static int
-nv94_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 index,
-		  struct nouveau_object **pobject)
-{
-	struct nv94_i2c_pad *pad;
-	int ret;
-
-	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
-	*pobject = nv_object(pad);
-	if (ret)
-		return ret;
-
-	pad->addr = index * 0x50;;
-	return 0;
-}
-
-struct nouveau_oclass
-nv94_i2c_pad_oclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv94_i2c_pad_ctor,
-		.dtor = _nvkm_i2c_pad_dtor,
-		.init = nv94_i2c_pad_init,
-		.fini = nv94_i2c_pad_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
deleted file mode 100644
index a8ff6e0..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __NVKM_I2C_PORT_H__
-#define __NVKM_I2C_PORT_H__
-
-#include "priv.h"
-
-#ifndef MSG
-#define MSG(l,f,a...) do {                                                     \
-	struct nouveau_i2c_port *_port = (void *)port;                         \
-	nv_##l(nv_object(_port)->engine, "PORT:%02x: "f, _port->index, ##a);   \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
deleted file mode 100644
index 4fe7ae3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef __NVKM_I2C_H__
-#define __NVKM_I2C_H__
-
-#include <subdev/i2c.h>
-
-extern struct nouveau_oclass nv04_i2c_pad_oclass;
-extern struct nouveau_oclass nv94_i2c_pad_oclass;
-extern struct nouveau_oclass gm204_i2c_pad_oclass;
-
-#define nouveau_i2c_port_create(p,e,o,i,a,f,d)                                 \
-	nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f),                 \
-				 sizeof(**d), (void **)d)
-#define nouveau_i2c_port_destroy(p) ({                                         \
-	struct nouveau_i2c_port *port = (p);                                   \
-	_nouveau_i2c_port_dtor(nv_object(i2c));                                \
-})
-#define nouveau_i2c_port_init(p)                                               \
-	nouveau_object_init(&(p)->base)
-#define nouveau_i2c_port_fini(p,s)                                             \
-	nouveau_object_fini(&(p)->base, (s))
-
-int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
-			     struct nouveau_oclass *, u8,
-			     const struct i2c_algorithm *,
-			     const struct nouveau_i2c_func *,
-			     int, void **);
-void _nouveau_i2c_port_dtor(struct nouveau_object *);
-#define _nouveau_i2c_port_init nouveau_object_init
-int  _nouveau_i2c_port_fini(struct nouveau_object *, bool);
-
-#define nouveau_i2c_create(p,e,o,d)                                            \
-	nouveau_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_i2c_destroy(p) ({                                              \
-	struct nouveau_i2c *i2c = (p);                                         \
-	_nouveau_i2c_dtor(nv_object(i2c));                                     \
-})
-#define nouveau_i2c_init(p) ({                                                 \
-	struct nouveau_i2c *i2c = (p);                                         \
-	_nouveau_i2c_init(nv_object(i2c));                                     \
-})
-#define nouveau_i2c_fini(p,s) ({                                               \
-	struct nouveau_i2c *i2c = (p);                                         \
-	_nouveau_i2c_fini(nv_object(i2c), (s));                                \
-})
-
-int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, int, void **);
-int  _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *,
-		       struct nouveau_oclass *, void *, u32,
-		       struct nouveau_object **);
-void _nouveau_i2c_dtor(struct nouveau_object *);
-int  _nouveau_i2c_init(struct nouveau_object *);
-int  _nouveau_i2c_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass nouveau_anx9805_sclass[];
-extern struct nouveau_oclass nvd0_i2c_sclass[];
-
-extern const struct i2c_algorithm nouveau_i2c_bit_algo;
-extern const struct i2c_algorithm nouveau_i2c_aux_algo;
-
-struct nouveau_i2c_impl {
-	struct nouveau_oclass base;
-
-	/* supported i2c port classes */
-	struct nouveau_oclass *sclass;
-	struct nouveau_oclass *pad_x;
-	struct nouveau_oclass *pad_s;
-
-	/* number of native dp aux channels present */
-	int aux;
-
-	/* read and ack pending interrupts, returning only data
-	 * for ports that have not been masked off, while still
-	 * performing the ack for anything that was pending.
-	 */
-	void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-
-	/* mask on/off interrupt types for a given set of auxch
-	 */
-	void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32);
-};
-
-void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32);
-
-void nve0_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-void nve0_aux_mask(struct nouveau_i2c *, u32, u32, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c
deleted file mode 100644
index 245f0eb..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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 <subdev/ibus.h>
-#include <subdev/timer.h>
-
-struct gk20a_ibus_priv {
-	struct nouveau_ibus base;
-};
-
-static void
-gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
-{
-	nv_mask(priv, 0x137250, 0x3f, 0);
-
-	nv_mask(priv, 0x000200, 0x20, 0);
-	usleep_range(20, 30);
-	nv_mask(priv, 0x000200, 0x20, 0x20);
-
-	nv_wr32(priv, 0x12004c, 0x4);
-	nv_wr32(priv, 0x122204, 0x2);
-	nv_rd32(priv, 0x122204);
-}
-
-static void
-gk20a_ibus_intr(struct nouveau_subdev *subdev)
-{
-	struct gk20a_ibus_priv *priv = (void *)subdev;
-	u32 status0 = nv_rd32(priv, 0x120058);
-
-	if (status0 & 0x7) {
-		nv_debug(priv, "resetting priv ring\n");
-		gk20a_ibus_init_priv_ring(priv);
-	}
-
-	/* Acknowledge interrupt */
-	nv_mask(priv, 0x12004c, 0x2, 0x2);
-
-	if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00))
-		nv_warn(priv, "timeout waiting for ringmaster ack\n");
-}
-
-static int
-gk20a_ibus_init(struct nouveau_object *object)
-{
-	struct gk20a_ibus_priv *priv = (void *)object;
-	int ret;
-
-	ret = _nouveau_ibus_init(object);
-	if (ret)
-		return ret;
-
-	gk20a_ibus_init_priv_ring(priv);
-
-	return 0;
-}
-
-static int
-gk20a_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct gk20a_ibus_priv *priv;
-	int ret;
-
-	ret = nouveau_ibus_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->intr = gk20a_ibus_intr;
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_ibus_oclass = {
-	.handle = NV_SUBDEV(IBUS, 0xea),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_ibus_ctor,
-		.dtor = _nouveau_ibus_dtor,
-		.init = gk20a_ibus_init,
-		.fini = _nouveau_ibus_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c
deleted file mode 100644
index 4e977ff..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/ibus.h>
-
-struct nvc0_ibus_priv {
-	struct nouveau_ibus base;
-};
-
-static void
-nvc0_ibus_intr_hub(struct nvc0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400));
-	u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400));
-	u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400));
-	nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr_rop(struct nvc0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400));
-	u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400));
-	u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400));
-	nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr_gpc(struct nvc0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400));
-	u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400));
-	u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400));
-	nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr(struct nouveau_subdev *subdev)
-{
-	struct nvc0_ibus_priv *priv = (void *)subdev;
-	u32 intr0 = nv_rd32(priv, 0x121c58);
-	u32 intr1 = nv_rd32(priv, 0x121c5c);
-	u32 hubnr = nv_rd32(priv, 0x121c70);
-	u32 ropnr = nv_rd32(priv, 0x121c74);
-	u32 gpcnr = nv_rd32(priv, 0x121c78);
-	u32 i;
-
-	for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
-		u32 stat = 0x00000100 << i;
-		if (intr0 & stat) {
-			nvc0_ibus_intr_hub(priv, i);
-			intr0 &= ~stat;
-		}
-	}
-
-	for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
-		u32 stat = 0x00010000 << i;
-		if (intr0 & stat) {
-			nvc0_ibus_intr_rop(priv, i);
-			intr0 &= ~stat;
-		}
-	}
-
-	for (i = 0; intr1 && i < gpcnr; i++) {
-		u32 stat = 0x00000001 << i;
-		if (intr1 & stat) {
-			nvc0_ibus_intr_gpc(priv, i);
-			intr1 &= ~stat;
-		}
-	}
-}
-
-static int
-nvc0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nvc0_ibus_priv *priv;
-	int ret;
-
-	ret = nouveau_ibus_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->intr = nvc0_ibus_intr;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_ibus_oclass = {
-	.handle = NV_SUBDEV(IBUS, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_ibus_ctor,
-		.dtor = _nouveau_ibus_dtor,
-		.init = _nouveau_ibus_init,
-		.fini = _nouveau_ibus_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c
deleted file mode 100644
index ebef970..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/ibus.h>
-
-struct nve0_ibus_priv {
-	struct nouveau_ibus base;
-};
-
-static void
-nve0_ibus_intr_hub(struct nve0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800));
-	u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800));
-	u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800));
-	nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr_rop(struct nve0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800));
-	u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800));
-	u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800));
-	nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr_gpc(struct nve0_ibus_priv *priv, int i)
-{
-	u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800));
-	u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800));
-	u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800));
-	nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
-	nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr(struct nouveau_subdev *subdev)
-{
-	struct nve0_ibus_priv *priv = (void *)subdev;
-	u32 intr0 = nv_rd32(priv, 0x120058);
-	u32 intr1 = nv_rd32(priv, 0x12005c);
-	u32 hubnr = nv_rd32(priv, 0x120070);
-	u32 ropnr = nv_rd32(priv, 0x120074);
-	u32 gpcnr = nv_rd32(priv, 0x120078);
-	u32 i;
-
-	for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
-		u32 stat = 0x00000100 << i;
-		if (intr0 & stat) {
-			nve0_ibus_intr_hub(priv, i);
-			intr0 &= ~stat;
-		}
-	}
-
-	for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
-		u32 stat = 0x00010000 << i;
-		if (intr0 & stat) {
-			nve0_ibus_intr_rop(priv, i);
-			intr0 &= ~stat;
-		}
-	}
-
-	for (i = 0; intr1 && i < gpcnr; i++) {
-		u32 stat = 0x00000001 << i;
-		if (intr1 & stat) {
-			nve0_ibus_intr_gpc(priv, i);
-			intr1 &= ~stat;
-		}
-	}
-}
-
-static int
-nve0_ibus_init(struct nouveau_object *object)
-{
-	struct nve0_ibus_priv *priv = (void *)object;
-	int ret = nouveau_ibus_init(&priv->base);
-	if (ret == 0) {
-		nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000);
-		nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200);
-		nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800);
-		nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100);
-		nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff);
-		nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200);
-		nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880);
-	}
-	return ret;
-}
-
-static int
-nve0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nve0_ibus_priv *priv;
-	int ret;
-
-	ret = nouveau_ibus_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->intr = nve0_ibus_intr;
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_ibus_oclass = {
-	.handle = NV_SUBDEV(IBUS, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_ibus_ctor,
-		.dtor = _nouveau_ibus_dtor,
-		.init = nve0_ibus_init,
-		.fini = _nouveau_ibus_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
deleted file mode 100644
index 14706d9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-/******************************************************************************
- * instmem object base implementation
- *****************************************************************************/
-
-void
-_nouveau_instobj_dtor(struct nouveau_object *object)
-{
-	struct nouveau_instmem *imem = (void *)object->engine;
-	struct nouveau_instobj *iobj = (void *)object;
-
-	mutex_lock(&nv_subdev(imem)->mutex);
-	list_del(&iobj->head);
-	mutex_unlock(&nv_subdev(imem)->mutex);
-
-	return nouveau_object_destroy(&iobj->base);
-}
-
-int
-nouveau_instobj_create_(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass,
-			int length, void **pobject)
-{
-	struct nouveau_instmem *imem = (void *)engine;
-	struct nouveau_instobj *iobj;
-	int ret;
-
-	ret = nouveau_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS,
-				     length, pobject);
-	iobj = *pobject;
-	if (ret)
-		return ret;
-
-	mutex_lock(&imem->base.mutex);
-	list_add(&iobj->head, &imem->list);
-	mutex_unlock(&imem->base.mutex);
-	return 0;
-}
-
-/******************************************************************************
- * instmem subdev base implementation
- *****************************************************************************/
-
-static int
-nouveau_instmem_alloc(struct nouveau_instmem *imem,
-		      struct nouveau_object *parent, u32 size, u32 align,
-		      struct nouveau_object **pobject)
-{
-	struct nouveau_object *engine = nv_object(imem);
-	struct nouveau_instmem_impl *impl = (void *)engine->oclass;
-	struct nouveau_instobj_args args = { .size = size, .align = align };
-	return nouveau_object_ctor(parent, engine, impl->instobj, &args,
-				   sizeof(args), pobject);
-}
-
-int
-_nouveau_instmem_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_instmem *imem = (void *)object;
-	struct nouveau_instobj *iobj;
-	int i, ret = 0;
-
-	if (suspend) {
-		mutex_lock(&imem->base.mutex);
-
-		list_for_each_entry(iobj, &imem->list, head) {
-			iobj->suspend = vmalloc(iobj->size);
-			if (!iobj->suspend) {
-				ret = -ENOMEM;
-				break;
-			}
-
-			for (i = 0; i < iobj->size; i += 4)
-				iobj->suspend[i / 4] = nv_ro32(iobj, i);
-		}
-
-		mutex_unlock(&imem->base.mutex);
-
-		if (ret)
-			return ret;
-	}
-
-	return nouveau_subdev_fini(&imem->base, suspend);
-}
-
-int
-_nouveau_instmem_init(struct nouveau_object *object)
-{
-	struct nouveau_instmem *imem = (void *)object;
-	struct nouveau_instobj *iobj;
-	int ret, i;
-
-	ret = nouveau_subdev_init(&imem->base);
-	if (ret)
-		return ret;
-
-	mutex_lock(&imem->base.mutex);
-
-	list_for_each_entry(iobj, &imem->list, head) {
-		if (iobj->suspend) {
-			for (i = 0; i < iobj->size; i += 4)
-				nv_wo32(iobj, i, iobj->suspend[i / 4]);
-			vfree(iobj->suspend);
-			iobj->suspend = NULL;
-		}
-	}
-
-	mutex_unlock(&imem->base.mutex);
-
-	return 0;
-}
-
-int
-nouveau_instmem_create_(struct nouveau_object *parent,
-			struct nouveau_object *engine,
-			struct nouveau_oclass *oclass,
-			int length, void **pobject)
-{
-	struct nouveau_instmem *imem;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0,
-				     "INSTMEM", "instmem", length, pobject);
-	imem = *pobject;
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&imem->list);
-	imem->alloc = nouveau_instmem_alloc;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
deleted file mode 100644
index e8b1401..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-/******************************************************************************
- * instmem object implementation
- *****************************************************************************/
-
-static u32
-nv04_instobj_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nv04_instobj_priv *node = (void *)object;
-	return nv_ro32(object->engine, node->mem->offset + addr);
-}
-
-static void
-nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nv04_instobj_priv *node = (void *)object;
-	nv_wo32(object->engine, node->mem->offset + addr, data);
-}
-
-static void
-nv04_instobj_dtor(struct nouveau_object *object)
-{
-	struct nv04_instmem_priv *priv = (void *)object->engine;
-	struct nv04_instobj_priv *node = (void *)object;
-	nouveau_mm_free(&priv->heap, &node->mem);
-	nouveau_instobj_destroy(&node->base);
-}
-
-static int
-nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *priv = (void *)engine;
-	struct nv04_instobj_priv *node;
-	struct nouveau_instobj_args *args = data;
-	int ret;
-
-	if (!args->align)
-		args->align = 1;
-
-	ret = nouveau_instobj_create(parent, engine, oclass, &node);
-	*pobject = nv_object(node);
-	if (ret)
-		return ret;
-
-	ret = nouveau_mm_head(&priv->heap, 0, 1, args->size, args->size,
-			      args->align, &node->mem);
-	if (ret)
-		return ret;
-
-	node->base.addr = node->mem->offset;
-	node->base.size = node->mem->length;
-	return 0;
-}
-
-struct nouveau_instobj_impl
-nv04_instobj_oclass = {
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_instobj_ctor,
-		.dtor = nv04_instobj_dtor,
-		.init = _nouveau_instobj_init,
-		.fini = _nouveau_instobj_fini,
-		.rd32 = nv04_instobj_rd32,
-		.wr32 = nv04_instobj_wr32,
-	},
-};
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static u32
-nv04_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
-	return nv_rd32(object, 0x700000 + addr);
-}
-
-static void
-nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	return nv_wr32(object, 0x700000 + addr, data);
-}
-
-void
-nv04_instmem_dtor(struct nouveau_object *object)
-{
-	struct nv04_instmem_priv *priv = (void *)object;
-	nouveau_gpuobj_ref(NULL, &priv->ramfc);
-	nouveau_gpuobj_ref(NULL, &priv->ramro);
-	nouveau_ramht_ref(NULL, &priv->ramht);
-	nouveau_gpuobj_ref(NULL, &priv->vbios);
-	nouveau_mm_fini(&priv->heap);
-	if (priv->iomem)
-		iounmap(priv->iomem);
-	nouveau_instmem_destroy(&priv->base);
-}
-
-static int
-nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv04_instmem_priv *priv;
-	int ret;
-
-	ret = nouveau_instmem_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	/* PRAMIN aperture maps over the end of VRAM, reserve it */
-	priv->base.reserved = 512 * 1024;
-
-	ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
-	if (ret)
-		return ret;
-
-	/* 0x00000-0x10000: reserve for probable vbios image */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
-				&priv->vbios);
-	if (ret)
-		return ret;
-
-	/* 0x10000-0x18000: reserve for RAMHT */
-	ret = nouveau_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
-	if (ret)
-		return ret;
-
-	/* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x00800, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
-	if (ret)
-		return ret;
-
-	/* 0x18800-0x18a00: reserve for RAMRO */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0,
-				&priv->ramro);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_instmem_oclass = &(struct nouveau_instmem_impl) {
-	.base.handle = NV_SUBDEV(INSTMEM, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_instmem_ctor,
-		.dtor = nv04_instmem_dtor,
-		.init = _nouveau_instmem_init,
-		.fini = _nouveau_instmem_fini,
-		.rd32 = nv04_instmem_rd32,
-		.wr32 = nv04_instmem_wr32,
-	},
-	.instobj = &nv04_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
deleted file mode 100644
index 095fbc6..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NV04_INSTMEM_H__
-#define __NV04_INSTMEM_H__
-
-#include <core/gpuobj.h>
-#include <core/ramht.h>
-#include <core/mm.h>
-
-#include "priv.h"
-
-extern struct nouveau_instobj_impl nv04_instobj_oclass;
-
-struct nv04_instmem_priv {
-	struct nouveau_instmem base;
-
-	void __iomem *iomem;
-	struct nouveau_mm heap;
-
-	struct nouveau_gpuobj *vbios;
-	struct nouveau_ramht  *ramht;
-	struct nouveau_gpuobj *ramro;
-	struct nouveau_gpuobj *ramfc;
-};
-
-static inline struct nv04_instmem_priv *
-nv04_instmem(void *obj)
-{
-	return (void *)nouveau_instmem(obj);
-}
-
-struct nv04_instobj_priv {
-	struct nouveau_instobj base;
-	struct nouveau_mm_node *mem;
-};
-
-void nv04_instmem_dtor(struct nouveau_object *);
-
-int nv04_instmem_alloc(struct nouveau_instmem *, struct nouveau_object *,
-		       u32 size, u32 align, struct nouveau_object **pobject);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
deleted file mode 100644
index 8803809..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/graph/nv40.h>
-
-#include "nv04.h"
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static u32
-nv40_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
-	struct nv04_instmem_priv *priv = (void *)object;
-	return ioread32_native(priv->iomem + addr);
-}
-
-static void
-nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-	struct nv04_instmem_priv *priv = (void *)object;
-	iowrite32_native(data, priv->iomem + addr);
-}
-
-static int
-nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nv04_instmem_priv *priv;
-	int ret, bar, vs;
-
-	ret = nouveau_instmem_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	/* map bar */
-	if (nv_device_resource_len(device, 2))
-		bar = 2;
-	else
-		bar = 3;
-
-	priv->iomem = ioremap(nv_device_resource_start(device, bar),
-			      nv_device_resource_len(device, bar));
-	if (!priv->iomem) {
-		nv_error(priv, "unable to map PRAMIN BAR\n");
-		return -EFAULT;
-	}
-
-	/* PRAMIN aperture maps over the end of vram, reserve enough space
-	 * to fit graphics contexts for every channel, the magics come
-	 * from engine/graph/nv40.c
-	 */
-	vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8);
-	if      (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs;
-	else if (device->chipset  < 0x43) priv->base.reserved = 0x4f00 * vs;
-	else if (nv44_graph_class(priv))  priv->base.reserved = 0x4980 * vs;
-	else				  priv->base.reserved = 0x4a40 * vs;
-	priv->base.reserved += 16 * 1024;
-	priv->base.reserved *= 32;		/* per-channel */
-	priv->base.reserved += 512 * 1024;	/* pci(e)gart table */
-	priv->base.reserved += 512 * 1024;	/* object storage */
-
-	priv->base.reserved = round_up(priv->base.reserved, 4096);
-
-	ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
-	if (ret)
-		return ret;
-
-	/* 0x00000-0x10000: reserve for probable vbios image */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
-				&priv->vbios);
-	if (ret)
-		return ret;
-
-	/* 0x10000-0x18000: reserve for RAMHT */
-	ret = nouveau_ramht_new(nv_object(priv), NULL, 0x08000, 0,
-			       &priv->ramht);
-	if (ret)
-		return ret;
-
-	/* 0x18000-0x18200: reserve for RAMRO
-	 * 0x18200-0x20000: padding
-	 */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0,
-				&priv->ramro);
-	if (ret)
-		return ret;
-
-	/* 0x20000-0x21000: reserve for RAMFC
-	 * 0x21000-0x40000: padding and some unknown crap
-	 */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nv40_instmem_oclass = &(struct nouveau_instmem_impl) {
-	.base.handle = NV_SUBDEV(INSTMEM, 0x40),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_instmem_ctor,
-		.dtor = nv04_instmem_dtor,
-		.init = _nouveau_instmem_init,
-		.fini = _nouveau_instmem_fini,
-		.rd32 = nv40_instmem_rd32,
-		.wr32 = nv40_instmem_wr32,
-	},
-	.instobj = &nv04_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
deleted file mode 100644
index 7cb3b09..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <core/mm.h>
-
-#include "priv.h"
-
-struct nv50_instmem_priv {
-	struct nouveau_instmem base;
-	spinlock_t lock;
-	u64 addr;
-};
-
-struct nv50_instobj_priv {
-	struct nouveau_instobj base;
-	struct nouveau_mem *mem;
-};
-
-/******************************************************************************
- * instmem object implementation
- *****************************************************************************/
-
-static u32
-nv50_instobj_rd32(struct nouveau_object *object, u64 offset)
-{
-	struct nv50_instmem_priv *priv = (void *)object->engine;
-	struct nv50_instobj_priv *node = (void *)object;
-	unsigned long flags;
-	u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
-	u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
-	u32 data;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (unlikely(priv->addr != base)) {
-		nv_wr32(priv, 0x001700, base >> 16);
-		priv->addr = base;
-	}
-	data = nv_rd32(priv, 0x700000 + addr);
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return data;
-}
-
-static void
-nv50_instobj_wr32(struct nouveau_object *object, u64 offset, u32 data)
-{
-	struct nv50_instmem_priv *priv = (void *)object->engine;
-	struct nv50_instobj_priv *node = (void *)object;
-	unsigned long flags;
-	u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
-	u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (unlikely(priv->addr != base)) {
-		nv_wr32(priv, 0x001700, base >> 16);
-		priv->addr = base;
-	}
-	nv_wr32(priv, 0x700000 + addr, data);
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nv50_instobj_dtor(struct nouveau_object *object)
-{
-	struct nv50_instobj_priv *node = (void *)object;
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	pfb->ram->put(pfb, &node->mem);
-	nouveau_instobj_destroy(&node->base);
-}
-
-static int
-nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nouveau_instobj_args *args = data;
-	struct nv50_instobj_priv *node;
-	int ret;
-
-	args->size  = max((args->size  + 4095) & ~4095, (u32)4096);
-	args->align = max((args->align + 4095) & ~4095, (u32)4096);
-
-	ret = nouveau_instobj_create(parent, engine, oclass, &node);
-	*pobject = nv_object(node);
-	if (ret)
-		return ret;
-
-	ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem);
-	if (ret)
-		return ret;
-
-	node->base.addr = node->mem->offset;
-	node->base.size = node->mem->size << 12;
-	node->mem->page_shift = 12;
-	return 0;
-}
-
-static struct nouveau_instobj_impl
-nv50_instobj_oclass = {
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_instobj_ctor,
-		.dtor = nv50_instobj_dtor,
-		.init = _nouveau_instobj_init,
-		.fini = _nouveau_instobj_fini,
-		.rd32 = nv50_instobj_rd32,
-		.wr32 = nv50_instobj_wr32,
-	},
-};
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static int
-nv50_instmem_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv50_instmem_priv *priv = (void *)object;
-	priv->addr = ~0ULL;
-	return nouveau_instmem_fini(&priv->base, suspend);
-}
-
-static int
-nv50_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nv50_instmem_priv *priv;
-	int ret;
-
-	ret = nouveau_instmem_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-struct nouveau_oclass *
-nv50_instmem_oclass = &(struct nouveau_instmem_impl) {
-	.base.handle = NV_SUBDEV(INSTMEM, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_instmem_ctor,
-		.dtor = _nouveau_instmem_dtor,
-		.init = _nouveau_instmem_init,
-		.fini = nv50_instmem_fini,
-	},
-	.instobj = &nv50_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h
deleted file mode 100644
index 8d67ded..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NVKM_INSTMEM_PRIV_H__
-#define __NVKM_INSTMEM_PRIV_H__
-
-#include <subdev/instmem.h>
-
-struct nouveau_instobj_impl {
-	struct nouveau_oclass base;
-};
-
-struct nouveau_instobj_args {
-	u32 size;
-	u32 align;
-};
-
-#define nouveau_instobj_create(p,e,o,d)                                        \
-	nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instobj_destroy(p) ({                                          \
-	struct nouveau_instobj *iobj = (p);                                    \
-	_nouveau_instobj_dtor(nv_object(iobj));                                \
-})
-#define nouveau_instobj_init(p)                                                \
-	nouveau_object_init(&(p)->base)
-#define nouveau_instobj_fini(p,s)                                              \
-	nouveau_object_fini(&(p)->base, (s))
-
-int  nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *,
-			     struct nouveau_oclass *, int, void **);
-void _nouveau_instobj_dtor(struct nouveau_object *);
-#define _nouveau_instobj_init nouveau_object_init
-#define _nouveau_instobj_fini nouveau_object_fini
-
-struct nouveau_instmem_impl {
-	struct nouveau_oclass base;
-	struct nouveau_oclass *instobj;
-};
-
-#define nouveau_instmem_create(p,e,o,d)                                        \
-	nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instmem_destroy(p)                                             \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_instmem_init(p) ({                                             \
-	struct nouveau_instmem *imem = (p);                                    \
-	_nouveau_instmem_init(nv_object(imem));                                \
-})
-#define nouveau_instmem_fini(p,s) ({                                           \
-	struct nouveau_instmem *imem = (p);                                    \
-	_nouveau_instmem_fini(nv_object(imem), (s));                           \
-})
-
-int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *,
-			    struct nouveau_oclass *, int, void **);
-#define _nouveau_instmem_dtor _nouveau_subdev_dtor
-int _nouveau_instmem_init(struct nouveau_object *);
-int _nouveau_instmem_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c
deleted file mode 100644
index 7fa3315..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "priv.h"
-
-static int
-nvkm_ltc_tags_alloc(struct nouveau_ltc *ltc, u32 n,
-		    struct nouveau_mm_node **pnode)
-{
-	struct nvkm_ltc_priv *priv = (void *)ltc;
-	int ret;
-
-	ret = nouveau_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
-	if (ret)
-		*pnode = NULL;
-
-	return ret;
-}
-
-static void
-nvkm_ltc_tags_free(struct nouveau_ltc *ltc, struct nouveau_mm_node **pnode)
-{
-	struct nvkm_ltc_priv *priv = (void *)ltc;
-	nouveau_mm_free(&priv->tags, pnode);
-}
-
-static void
-nvkm_ltc_tags_clear(struct nouveau_ltc *ltc, u32 first, u32 count)
-{
-	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
-	struct nvkm_ltc_priv *priv = (void *)ltc;
-	const u32 limit = first + count - 1;
-
-	BUG_ON((first > limit) || (limit >= priv->num_tags));
-
-	impl->cbc_clear(priv, first, limit);
-	impl->cbc_wait(priv);
-}
-
-static int
-nvkm_ltc_zbc_color_get(struct nouveau_ltc *ltc, int index, const u32 color[4])
-{
-	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
-	struct nvkm_ltc_priv *priv = (void *)ltc;
-	memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index]));
-	impl->zbc_clear_color(priv, index, color);
-	return index;
-}
-
-static int
-nvkm_ltc_zbc_depth_get(struct nouveau_ltc *ltc, int index, const u32 depth)
-{
-	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
-	struct nvkm_ltc_priv *priv = (void *)ltc;
-	priv->zbc_depth[index] = depth;
-	impl->zbc_clear_depth(priv, index, depth);
-	return index;
-}
-
-int
-_nvkm_ltc_init(struct nouveau_object *object)
-{
-	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object);
-	struct nvkm_ltc_priv *priv = (void *)object;
-	int ret, i;
-
-	ret = nouveau_subdev_init(&priv->base.base);
-	if (ret)
-		return ret;
-
-	for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) {
-		impl->zbc_clear_color(priv, i, priv->zbc_color[i]);
-		impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]);
-	}
-
-	return 0;
-}
-
-int
-nvkm_ltc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		 struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	const struct nvkm_ltc_impl *impl = (void *)oclass;
-	struct nvkm_ltc_priv *priv;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PLTCG",
-				     "l2c", length, pobject);
-	priv = *pobject;
-	if (ret)
-		return ret;
-
-	memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color));
-	memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth));
-
-	priv->base.base.intr = impl->intr;
-	priv->base.tags_alloc = nvkm_ltc_tags_alloc;
-	priv->base.tags_free = nvkm_ltc_tags_free;
-	priv->base.tags_clear = nvkm_ltc_tags_clear;
-	priv->base.zbc_min = 1; /* reserve 0 for disabled */
-	priv->base.zbc_max = min(impl->zbc, NOUVEAU_LTC_MAX_ZBC_CNT) - 1;
-	priv->base.zbc_color_get = nvkm_ltc_zbc_color_get;
-	priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
deleted file mode 100644
index 2db0977..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-void
-gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
-{
-	nv_wr32(priv, 0x17e8cc, start);
-	nv_wr32(priv, 0x17e8d0, limit);
-	nv_wr32(priv, 0x17e8c8, 0x00000004);
-}
-
-void
-gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
-{
-	int c, s;
-	for (c = 0; c < priv->ltc_nr; c++) {
-		for (s = 0; s < priv->lts_nr; s++)
-			nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0);
-	}
-}
-
-void
-gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
-{
-	nv_mask(priv, 0x17ea44, 0x0000000f, i);
-	nv_wr32(priv, 0x17ea48, color[0]);
-	nv_wr32(priv, 0x17ea4c, color[1]);
-	nv_wr32(priv, 0x17ea50, color[2]);
-	nv_wr32(priv, 0x17ea54, color[3]);
-}
-
-void
-gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
-{
-	nv_mask(priv, 0x17ea44, 0x0000000f, i);
-	nv_wr32(priv, 0x17ea58, depth);
-}
-
-static const struct nouveau_bitfield
-gf100_ltc_lts_intr_name[] = {
-	{ 0x00000001, "IDLE_ERROR_IQ" },
-	{ 0x00000002, "IDLE_ERROR_CBC" },
-	{ 0x00000004, "IDLE_ERROR_TSTG" },
-	{ 0x00000008, "IDLE_ERROR_DSTG" },
-	{ 0x00000010, "EVICTED_CB" },
-	{ 0x00000020, "ILLEGAL_COMPSTAT" },
-	{ 0x00000040, "BLOCKLINEAR_CB" },
-	{ 0x00000100, "ECC_SEC_ERROR" },
-	{ 0x00000200, "ECC_DED_ERROR" },
-	{ 0x00000400, "DEBUG" },
-	{ 0x00000800, "ATOMIC_TO_Z" },
-	{ 0x00001000, "ILLEGAL_ATOMIC" },
-	{ 0x00002000, "BLKACTIVITY_ERR" },
-	{}
-};
-
-static void
-gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
-{
-	u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
-	u32 intr = nv_rd32(priv, base + 0x020);
-	u32 stat = intr & 0x0000ffff;
-
-	if (stat) {
-		nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
-		nouveau_bitfield_print(gf100_ltc_lts_intr_name, stat);
-		pr_cont("\n");
-	}
-
-	nv_wr32(priv, base + 0x020, intr);
-}
-
-void
-gf100_ltc_intr(struct nouveau_subdev *subdev)
-{
-	struct nvkm_ltc_priv *priv = (void *)subdev;
-	u32 mask;
-
-	mask = nv_rd32(priv, 0x00017c);
-	while (mask) {
-		u32 lts, ltc = __ffs(mask);
-		for (lts = 0; lts < priv->lts_nr; lts++)
-			gf100_ltc_lts_intr(priv, ltc, lts);
-		mask &= ~(1 << ltc);
-	}
-}
-
-static int
-gf100_ltc_init(struct nouveau_object *object)
-{
-	struct nvkm_ltc_priv *priv = (void *)object;
-	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
-	int ret;
-
-	ret = nvkm_ltc_init(priv);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
-	nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
-	nv_wr32(priv, 0x17e8d4, priv->tag_base);
-	nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
-	return 0;
-}
-
-void
-gf100_ltc_dtor(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = nouveau_fb(object);
-	struct nvkm_ltc_priv *priv = (void *)object;
-
-	nouveau_mm_fini(&priv->tags);
-	nouveau_mm_free(&pfb->vram, &priv->tag_ram);
-
-	nvkm_ltc_destroy(priv);
-}
-
-/* TODO: Figure out tag memory details and drop the over-cautious allocation.
- */
-int
-gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
-{
-	u32 tag_size, tag_margin, tag_align;
-	int ret;
-
-	/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
-	priv->num_tags = (pfb->ram->size >> 17) / 4;
-	if (priv->num_tags > (1 << 17))
-		priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
-	priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
-
-	tag_align = priv->ltc_nr * 0x800;
-	tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
-
-	/* 4 part 4 sub: 0x2000 bytes for 56 tags */
-	/* 3 part 4 sub: 0x6000 bytes for 168 tags */
-	/*
-	 * About 147 bytes per tag. Let's be safe and allocate x2, which makes
-	 * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
-	 *
-	 * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
-	 */
-	tag_size  = (priv->num_tags / 64) * 0x6000 + tag_margin;
-	tag_size += tag_align;
-	tag_size  = (tag_size + 0xfff) >> 12; /* round up */
-
-	ret = nouveau_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
-	                      &priv->tag_ram);
-	if (ret) {
-		priv->num_tags = 0;
-	} else {
-		u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
-
-		tag_base += tag_align - 1;
-		ret = do_div(tag_base, tag_align);
-
-		priv->tag_base = tag_base;
-	}
-
-	ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
-	return ret;
-}
-
-int
-gf100_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nvkm_ltc_priv *priv;
-	u32 parts, mask;
-	int ret, i;
-
-	ret = nvkm_ltc_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	parts = nv_rd32(priv, 0x022438);
-	mask = nv_rd32(priv, 0x022554);
-	for (i = 0; i < parts; i++) {
-		if (!(mask & (1 << i)))
-			priv->ltc_nr++;
-	}
-	priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28;
-
-	ret = gf100_ltc_init_tag_ram(pfb, priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->intr = gf100_ltc_intr;
-	return 0;
-}
-
-struct nouveau_oclass *
-gf100_ltc_oclass = &(struct nvkm_ltc_impl) {
-	.base.handle = NV_SUBDEV(LTC, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gf100_ltc_ctor,
-		.dtor = gf100_ltc_dtor,
-		.init = gf100_ltc_init,
-		.fini = _nvkm_ltc_fini,
-	},
-	.intr = gf100_ltc_intr,
-	.cbc_clear = gf100_ltc_cbc_clear,
-	.cbc_wait = gf100_ltc_cbc_wait,
-	.zbc = 16,
-	.zbc_clear_color = gf100_ltc_zbc_clear_color,
-	.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c
deleted file mode 100644
index b39b5d0..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-gk104_ltc_init(struct nouveau_object *object)
-{
-	struct nvkm_ltc_priv *priv = (void *)object;
-	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
-	int ret;
-
-	ret = nvkm_ltc_init(priv);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
-	nv_wr32(priv, 0x17e000, priv->ltc_nr);
-	nv_wr32(priv, 0x17e8d4, priv->tag_base);
-	nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
-	return 0;
-}
-
-struct nouveau_oclass *
-gk104_ltc_oclass = &(struct nvkm_ltc_impl) {
-	.base.handle = NV_SUBDEV(LTC, 0xe4),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gf100_ltc_ctor,
-		.dtor = gf100_ltc_dtor,
-		.init = gk104_ltc_init,
-		.fini = _nvkm_ltc_fini,
-	},
-	.intr = gf100_ltc_intr,
-	.cbc_clear = gf100_ltc_cbc_clear,
-	.cbc_wait = gf100_ltc_cbc_wait,
-	.zbc = 16,
-	.zbc_clear_color = gf100_ltc_zbc_clear_color,
-	.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c
deleted file mode 100644
index 89fc423..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2014 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-static void
-gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
-{
-	nv_wr32(priv, 0x17e270, start);
-	nv_wr32(priv, 0x17e274, limit);
-	nv_wr32(priv, 0x17e26c, 0x00000004);
-}
-
-static void
-gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
-{
-	int c, s;
-	for (c = 0; c < priv->ltc_nr; c++) {
-		for (s = 0; s < priv->lts_nr; s++)
-			nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0);
-	}
-}
-
-static void
-gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
-{
-	nv_mask(priv, 0x17e338, 0x0000000f, i);
-	nv_wr32(priv, 0x17e33c, color[0]);
-	nv_wr32(priv, 0x17e340, color[1]);
-	nv_wr32(priv, 0x17e344, color[2]);
-	nv_wr32(priv, 0x17e348, color[3]);
-}
-
-static void
-gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
-{
-	nv_mask(priv, 0x17e338, 0x0000000f, i);
-	nv_wr32(priv, 0x17e34c, depth);
-}
-
-static void
-gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
-{
-	u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
-	u32 stat = nv_rd32(priv, base + 0x00c);
-
-	if (stat) {
-		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
-		nv_wr32(priv, base + 0x00c, stat);
-	}
-}
-
-static void
-gm107_ltc_intr(struct nouveau_subdev *subdev)
-{
-	struct nvkm_ltc_priv *priv = (void *)subdev;
-	u32 mask;
-
-	mask = nv_rd32(priv, 0x00017c);
-	while (mask) {
-		u32 lts, ltc = __ffs(mask);
-		for (lts = 0; lts < priv->lts_nr; lts++)
-			gm107_ltc_lts_isr(priv, ltc, lts);
-		mask &= ~(1 << ltc);
-	}
-}
-
-static int
-gm107_ltc_init(struct nouveau_object *object)
-{
-	struct nvkm_ltc_priv *priv = (void *)object;
-	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
-	int ret;
-
-	ret = nvkm_ltc_init(priv);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x17e27c, priv->ltc_nr);
-	nv_wr32(priv, 0x17e278, priv->tag_base);
-	nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
-	return 0;
-}
-
-static int
-gm107_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nouveau_fb *pfb = nouveau_fb(parent);
-	struct nvkm_ltc_priv *priv;
-	u32 parts, mask;
-	int ret, i;
-
-	ret = nvkm_ltc_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	parts = nv_rd32(priv, 0x022438);
-	mask = nv_rd32(priv, 0x021c14);
-	for (i = 0; i < parts; i++) {
-		if (!(mask & (1 << i)))
-			priv->ltc_nr++;
-	}
-	priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28;
-
-	ret = gf100_ltc_init_tag_ram(pfb, priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-gm107_ltc_oclass = &(struct nvkm_ltc_impl) {
-	.base.handle = NV_SUBDEV(LTC, 0xff),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm107_ltc_ctor,
-		.dtor = gf100_ltc_dtor,
-		.init = gm107_ltc_init,
-		.fini = _nvkm_ltc_fini,
-	},
-	.intr = gm107_ltc_intr,
-	.cbc_clear = gm107_ltc_cbc_clear,
-	.cbc_wait = gm107_ltc_cbc_wait,
-	.zbc = 16,
-	.zbc_clear_color = gm107_ltc_zbc_clear_color,
-	.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h
deleted file mode 100644
index 41f179d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __NVKM_LTC_PRIV_H__
-#define __NVKM_LTC_PRIV_H__
-
-#include <subdev/ltc.h>
-#include <subdev/fb.h>
-
-#include <core/enum.h>
-
-struct nvkm_ltc_priv {
-	struct nouveau_ltc base;
-	u32 ltc_nr;
-	u32 lts_nr;
-
-	u32 num_tags;
-	u32 tag_base;
-	struct nouveau_mm tags;
-	struct nouveau_mm_node *tag_ram;
-
-	u32 zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT][4];
-	u32 zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT];
-};
-
-#define nvkm_ltc_create(p,e,o,d)                                               \
-	nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nvkm_ltc_destroy(p) ({                                                 \
-	struct nvkm_ltc_priv *_priv = (p);                                     \
-	_nvkm_ltc_dtor(nv_object(_priv));                                      \
-})
-#define nvkm_ltc_init(p) ({                                                    \
-	struct nvkm_ltc_priv *_priv = (p);                                     \
-	_nvkm_ltc_init(nv_object(_priv));                                      \
-})
-#define nvkm_ltc_fini(p,s) ({                                                  \
-	struct nvkm_ltc_priv *_priv = (p);                                     \
-	_nvkm_ltc_fini(nv_object(_priv), (s));                                 \
-})
-
-int  nvkm_ltc_create_(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, int, void **);
-
-#define _nvkm_ltc_dtor _nouveau_subdev_dtor
-int _nvkm_ltc_init(struct nouveau_object *);
-#define _nvkm_ltc_fini _nouveau_subdev_fini
-
-int  gf100_ltc_ctor(struct nouveau_object *, struct nouveau_object *,
-		    struct nouveau_oclass *, void *, u32,
-		    struct nouveau_object **);
-void gf100_ltc_dtor(struct nouveau_object *);
-int  gf100_ltc_init_tag_ram(struct nouveau_fb *, struct nvkm_ltc_priv *);
-int  gf100_ltc_tags_alloc(struct nouveau_ltc *, u32, struct nouveau_mm_node **);
-void gf100_ltc_tags_free(struct nouveau_ltc *, struct nouveau_mm_node **);
-
-struct nvkm_ltc_impl {
-	struct nouveau_oclass base;
-	void (*intr)(struct nouveau_subdev *);
-
-	void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit);
-	void (*cbc_wait)(struct nvkm_ltc_priv *);
-
-	int zbc;
-	void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]);
-	void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32);
-};
-
-void gf100_ltc_intr(struct nouveau_subdev *);
-void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32);
-void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *);
-void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]);
-void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
deleted file mode 100644
index ca7cee3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include <core/option.h>
-
-static inline void
-nouveau_mc_unk260(struct nouveau_mc *pmc, u32 data)
-{
-	const struct nouveau_mc_oclass *impl = (void *)nv_oclass(pmc);
-	if (impl->unk260)
-		impl->unk260(pmc, data);
-}
-
-static inline u32
-nouveau_mc_intr_mask(struct nouveau_mc *pmc)
-{
-	u32 intr = nv_rd32(pmc, 0x000100);
-	if (intr == 0xffffffff) /* likely fallen off the bus */
-		intr = 0x00000000;
-	return intr;
-}
-
-static irqreturn_t
-nouveau_mc_intr(int irq, void *arg)
-{
-	struct nouveau_mc *pmc = arg;
-	const struct nouveau_mc_oclass *oclass = (void *)nv_object(pmc)->oclass;
-	const struct nouveau_mc_intr *map = oclass->intr;
-	struct nouveau_subdev *unit;
-	u32 intr;
-
-	nv_wr32(pmc, 0x000140, 0x00000000);
-	nv_rd32(pmc, 0x000140);
-	intr = nouveau_mc_intr_mask(pmc);
-	if (pmc->use_msi)
-		oclass->msi_rearm(pmc);
-
-	if (intr) {
-		u32 stat = intr = nouveau_mc_intr_mask(pmc);
-		while (map->stat) {
-			if (intr & map->stat) {
-				unit = nouveau_subdev(pmc, map->unit);
-				if (unit && unit->intr)
-					unit->intr(unit);
-				stat &= ~map->stat;
-			}
-			map++;
-		}
-
-		if (stat)
-			nv_error(pmc, "unknown intr 0x%08x\n", stat);
-	}
-
-	nv_wr32(pmc, 0x000140, 0x00000001);
-	return intr ? IRQ_HANDLED : IRQ_NONE;
-}
-
-int
-_nouveau_mc_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_mc *pmc = (void *)object;
-	nv_wr32(pmc, 0x000140, 0x00000000);
-	return nouveau_subdev_fini(&pmc->base, suspend);
-}
-
-int
-_nouveau_mc_init(struct nouveau_object *object)
-{
-	struct nouveau_mc *pmc = (void *)object;
-	int ret = nouveau_subdev_init(&pmc->base);
-	if (ret)
-		return ret;
-	nv_wr32(pmc, 0x000140, 0x00000001);
-	return 0;
-}
-
-void
-_nouveau_mc_dtor(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nouveau_mc *pmc = (void *)object;
-	free_irq(pmc->irq, pmc);
-	if (pmc->use_msi)
-		pci_disable_msi(device->pdev);
-	nouveau_subdev_destroy(&pmc->base);
-}
-
-int
-nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *bclass, int length, void **pobject)
-{
-	const struct nouveau_mc_oclass *oclass = (void *)bclass;
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_mc *pmc;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC",
-				     "master", length, pobject);
-	pmc = *pobject;
-	if (ret)
-		return ret;
-
-	pmc->unk260 = nouveau_mc_unk260;
-
-	if (nv_device_is_pci(device))
-		switch (device->pdev->device & 0x0ff0) {
-		case 0x00f0:
-		case 0x02e0:
-			/* BR02? NFI how these would be handled yet exactly */
-			break;
-		default:
-			switch (device->chipset) {
-			case 0xaa:
-				/* reported broken, nv also disable it */
-				break;
-			default:
-				pmc->use_msi = true;
-				break;
-		}
-
-		pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI",
-					       pmc->use_msi);
-
-		if (pmc->use_msi && oclass->msi_rearm) {
-			pmc->use_msi = pci_enable_msi(device->pdev) == 0;
-			if (pmc->use_msi) {
-				nv_info(pmc, "MSI interrupts enabled\n");
-				oclass->msi_rearm(pmc);
-			}
-		} else {
-			pmc->use_msi = false;
-		}
-	}
-
-	ret = nv_device_get_irq(device, true);
-	if (ret < 0)
-		return ret;
-	pmc->irq = ret;
-
-	ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau",
-			  pmc);
-
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c
deleted file mode 100644
index b8d6cb4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-gk20a_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0xea),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nvc0_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
deleted file mode 100644
index 2d787e4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nv04_mc_intr[] = {
-	{ 0x00000001, NVDEV_ENGINE_MPEG },	/* NV17- MPEG/ME */
-	{ 0x00000100, NVDEV_ENGINE_FIFO },
-	{ 0x00001000, NVDEV_ENGINE_GR },
-	{ 0x00010000, NVDEV_ENGINE_DISP },
-	{ 0x00020000, NVDEV_ENGINE_VP },	/* NV40- */
-	{ 0x00100000, NVDEV_SUBDEV_TIMER },
-	{ 0x01000000, NVDEV_ENGINE_DISP },	/* NV04- PCRTC0 */
-	{ 0x02000000, NVDEV_ENGINE_DISP },	/* NV11- PCRTC1 */
-	{ 0x10000000, NVDEV_SUBDEV_BUS },
-	{ 0x80000000, NVDEV_ENGINE_SW },
-	{}
-};
-
-int
-nv04_mc_init(struct nouveau_object *object)
-{
-	struct nv04_mc_priv *priv = (void *)object;
-
-	nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
-	nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
-
-	return nouveau_mc_init(&priv->base);
-}
-
-int
-nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	     struct nouveau_oclass *oclass, void *data, u32 size,
-	     struct nouveau_object **pobject)
-{
-	struct nv04_mc_priv *priv;
-	int ret;
-
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass *
-nv04_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x04),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv04_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv04_mc_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
deleted file mode 100644
index 4d9ea46..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVKM_MC_NV04_H__
-#define __NVKM_MC_NV04_H__
-
-#include "priv.h"
-
-struct nv04_mc_priv {
-	struct nouveau_mc base;
-};
-
-int  nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
-		  struct nouveau_oclass *, void *, u32,
-		  struct nouveau_object **);
-
-extern const struct nouveau_mc_intr nv04_mc_intr[];
-int  nv04_mc_init(struct nouveau_object *);
-void nv40_mc_msi_rearm(struct nouveau_mc *);
-int  nv44_mc_init(struct nouveau_object *object);
-int  nv50_mc_init(struct nouveau_object *);
-extern const struct nouveau_mc_intr nv50_mc_intr[];
-extern const struct nouveau_mc_intr nvc0_mc_intr[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c
deleted file mode 100644
index 5b1faec..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-void
-nv40_mc_msi_rearm(struct nouveau_mc *pmc)
-{
-	struct nv04_mc_priv *priv = (void *)pmc;
-	nv_wr08(priv, 0x088068, 0xff);
-}
-
-struct nouveau_oclass *
-nv40_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x40),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv04_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv04_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
deleted file mode 100644
index cc4d0d2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-int
-nv44_mc_init(struct nouveau_object *object)
-{
-	struct nv04_mc_priv *priv = (void *)object;
-	u32 tmp = nv_rd32(priv, 0x10020c);
-
-	nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
-
-	nv_wr32(priv, 0x001700, tmp);
-	nv_wr32(priv, 0x001704, 0);
-	nv_wr32(priv, 0x001708, 0);
-	nv_wr32(priv, 0x00170c, tmp);
-
-	return nouveau_mc_init(&priv->base);
-}
-
-struct nouveau_oclass *
-nv44_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x44),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv44_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv04_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
deleted file mode 100644
index 165401c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2014 Ilia Mirkin
- *
- * 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.
- *
- * Authors: Ilia Mirkin
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x4c),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv44_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv04_mc_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
deleted file mode 100644
index 9ca93e2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nv50_mc_intr[] = {
-	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP before FIFO, so pageflip-timestamping works! */
-	{ 0x00000001, NVDEV_ENGINE_MPEG },
-	{ 0x00000100, NVDEV_ENGINE_FIFO },
-	{ 0x00001000, NVDEV_ENGINE_GR },
-	{ 0x00004000, NVDEV_ENGINE_CRYPT },	/* NV84- */
-	{ 0x00008000, NVDEV_ENGINE_BSP },	/* NV84- */
-	{ 0x00020000, NVDEV_ENGINE_VP },	/* NV84- */
-	{ 0x00100000, NVDEV_SUBDEV_TIMER },
-	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
-	{ 0x00200000, NVDEV_SUBDEV_I2C }, 	/* PMGR->I2C/AUX */
-	{ 0x10000000, NVDEV_SUBDEV_BUS },
-	{ 0x80000000, NVDEV_ENGINE_SW },
-	{ 0x0002d101, NVDEV_SUBDEV_FB },
-	{},
-};
-
-static void
-nv50_mc_msi_rearm(struct nouveau_mc *pmc)
-{
-	struct nouveau_device *device = nv_device(pmc);
-	pci_write_config_byte(device->pdev, 0x68, 0xff);
-}
-
-int
-nv50_mc_init(struct nouveau_object *object)
-{
-	struct nv04_mc_priv *priv = (void *)object;
-	nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */
-	return nouveau_mc_init(&priv->base);
-}
-
-struct nouveau_oclass *
-nv50_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x50),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv50_mc_intr,
-	.msi_rearm = nv50_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c
deleted file mode 100644
index 5f45411..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv94_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x94),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv50_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
deleted file mode 100644
index 3c76d90..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static const struct nouveau_mc_intr
-nv98_mc_intr[] = {
-	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP first, so pageflip timestamps work */
-	{ 0x00000001, NVDEV_ENGINE_PPP },
-	{ 0x00000100, NVDEV_ENGINE_FIFO },
-	{ 0x00001000, NVDEV_ENGINE_GR },
-	{ 0x00004000, NVDEV_ENGINE_CRYPT },	/* NV84:NVA3 */
-	{ 0x00008000, NVDEV_ENGINE_BSP },
-	{ 0x00020000, NVDEV_ENGINE_VP },
-	{ 0x00040000, NVDEV_SUBDEV_PWR },	/* NVA3:NVC0 */
-	{ 0x00080000, NVDEV_SUBDEV_THERM },	/* NVA3:NVC0 */
-	{ 0x00100000, NVDEV_SUBDEV_TIMER },
-	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
-	{ 0x00200000, NVDEV_SUBDEV_I2C }, 	/* PMGR->I2C/AUX */
-	{ 0x00400000, NVDEV_ENGINE_COPY0 },	/* NVA3-     */
-	{ 0x10000000, NVDEV_SUBDEV_BUS },
-	{ 0x80000000, NVDEV_ENGINE_SW },
-	{ 0x0042d101, NVDEV_SUBDEV_FB },
-	{},
-};
-
-struct nouveau_oclass *
-nv98_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0x98),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nv98_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
deleted file mode 100644
index 15d41dc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nvc0_mc_intr[] = {
-	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP first, so pageflip timestamps work. */
-	{ 0x00000001, NVDEV_ENGINE_PPP },
-	{ 0x00000020, NVDEV_ENGINE_COPY0 },
-	{ 0x00000040, NVDEV_ENGINE_COPY1 },
-	{ 0x00000080, NVDEV_ENGINE_COPY2 },
-	{ 0x00000100, NVDEV_ENGINE_FIFO },
-	{ 0x00001000, NVDEV_ENGINE_GR },
-	{ 0x00002000, NVDEV_SUBDEV_FB },
-	{ 0x00008000, NVDEV_ENGINE_BSP },
-	{ 0x00040000, NVDEV_SUBDEV_THERM },
-	{ 0x00020000, NVDEV_ENGINE_VP },
-	{ 0x00100000, NVDEV_SUBDEV_TIMER },
-	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
-	{ 0x00200000, NVDEV_SUBDEV_I2C },	/* PMGR->I2C/AUX */
-	{ 0x01000000, NVDEV_SUBDEV_PWR },
-	{ 0x02000000, NVDEV_SUBDEV_LTC },
-	{ 0x08000000, NVDEV_SUBDEV_FB },
-	{ 0x10000000, NVDEV_SUBDEV_BUS },
-	{ 0x40000000, NVDEV_SUBDEV_IBUS },
-	{ 0x80000000, NVDEV_ENGINE_SW },
-	{},
-};
-
-static void
-nvc0_mc_msi_rearm(struct nouveau_mc *pmc)
-{
-	struct nv04_mc_priv *priv = (void *)pmc;
-	nv_wr32(priv, 0x088704, 0x00000000);
-}
-
-void
-nvc0_mc_unk260(struct nouveau_mc *pmc, u32 data)
-{
-	nv_wr32(pmc, 0x000260, data);
-}
-
-struct nouveau_oclass *
-nvc0_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nvc0_mc_intr,
-	.msi_rearm = nvc0_mc_msi_rearm,
-	.unk260 = nvc0_mc_unk260,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c
deleted file mode 100644
index 68b5f61..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nvc3_mc_oclass = &(struct nouveau_mc_oclass) {
-	.base.handle = NV_SUBDEV(MC, 0xc3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_mc_ctor,
-		.dtor = _nouveau_mc_dtor,
-		.init = nv50_mc_init,
-		.fini = _nouveau_mc_fini,
-	},
-	.intr = nvc0_mc_intr,
-	.msi_rearm = nv40_mc_msi_rearm,
-	.unk260 = nvc0_mc_unk260,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h
deleted file mode 100644
index 911e663..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NVKM_MC_PRIV_H__
-#define __NVKM_MC_PRIV_H__
-
-#include <subdev/mc.h>
-
-#define nouveau_mc_create(p,e,o,d)                                             \
-	nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_mc_destroy(p) ({                                               \
-	struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc));        \
-})
-#define nouveau_mc_init(p) ({                                                  \
-	struct nouveau_mc *pmc = (p); _nouveau_mc_init(nv_object(pmc));        \
-})
-#define nouveau_mc_fini(p,s) ({                                                \
-	struct nouveau_mc *pmc = (p); _nouveau_mc_fini(nv_object(pmc), (s));   \
-})
-
-int  nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, int, void **);
-void _nouveau_mc_dtor(struct nouveau_object *);
-int  _nouveau_mc_init(struct nouveau_object *);
-int  _nouveau_mc_fini(struct nouveau_object *, bool);
-
-struct nouveau_mc_intr {
-	u32 stat;
-	u32 unit;
-};
-
-struct nouveau_mc_oclass {
-	struct nouveau_oclass base;
-	const struct nouveau_mc_intr *intr;
-	void (*msi_rearm)(struct nouveau_mc *);
-	void (*unk260)(struct nouveau_mc *, u32);
-};
-
-void nvc0_mc_unk260(struct nouveau_mc *, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
deleted file mode 100644
index 51fcf79..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/i2c.h>
-#include <subdev/mxm.h>
-#include <subdev/bios.h>
-#include <subdev/bios/mxm.h>
-
-#include "mxms.h"
-
-static bool
-mxm_shadow_rom_fetch(struct nouveau_i2c_port *i2c, u8 addr,
-		     u8 offset, u8 size, u8 *data)
-{
-	struct i2c_msg msgs[] = {
-		{ .addr = addr, .flags = 0, .len = 1, .buf = &offset },
-		{ .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
-	};
-
-	return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
-}
-
-static bool
-mxm_shadow_rom(struct nouveau_mxm *mxm, u8 version)
-{
-	struct nouveau_bios *bios = nouveau_bios(mxm);
-	struct nouveau_i2c *i2c = nouveau_i2c(mxm);
-	struct nouveau_i2c_port *port = NULL;
-	u8 i2cidx, mxms[6], addr, size;
-
-	i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f;
-	if (i2cidx < 0x0f)
-		port = i2c->find(i2c, i2cidx);
-	if (!port)
-		return false;
-
-	addr = 0x54;
-	if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) {
-		addr = 0x56;
-		if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms))
-			return false;
-	}
-
-	mxm->mxms = mxms;
-	size = mxms_headerlen(mxm) + mxms_structlen(mxm);
-	mxm->mxms = kmalloc(size, GFP_KERNEL);
-
-	if (mxm->mxms &&
-	    mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms))
-		return true;
-
-	kfree(mxm->mxms);
-	mxm->mxms = NULL;
-	return false;
-}
-
-#if defined(CONFIG_ACPI)
-static bool
-mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)
-{
-	struct nouveau_device *device = nv_device(mxm);
-	static char muid[] = {
-		0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
-		0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
-	};
-	u32 mxms_args[] = { 0x00000000 };
-	union acpi_object argv4 = {
-		.buffer.type = ACPI_TYPE_BUFFER,
-		.buffer.length = sizeof(mxms_args),
-		.buffer.pointer = (char *)mxms_args,
-	};
-	union acpi_object *obj;
-	acpi_handle handle;
-	int rev;
-
-	handle = ACPI_HANDLE(nv_device_base(device));
-	if (!handle)
-		return false;
-
-	/*
-	 * spec says this can be zero to mean "highest revision", but
-	 * of course there's at least one bios out there which fails
-	 * unless you pass in exactly the version it supports..
-	 */
-	rev = (version & 0xf0) << 4 | (version & 0x0f);
-	obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
-	if (!obj) {
-		nv_debug(mxm, "DSM MXMS failed\n");
-		return false;
-	}
-
-	if (obj->type == ACPI_TYPE_BUFFER) {
-		mxm->mxms = kmemdup(obj->buffer.pointer,
-					 obj->buffer.length, GFP_KERNEL);
-	} else if (obj->type == ACPI_TYPE_INTEGER) {
-		nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value);
-	}
-
-	ACPI_FREE(obj);
-	return mxm->mxms != NULL;
-}
-#endif
-
-#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
-
-#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
-
-static u8
-wmi_wmmx_mxmi(struct nouveau_mxm *mxm, u8 version)
-{
-	u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
-	struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
-	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *obj;
-	acpi_status status;
-
-	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
-	if (ACPI_FAILURE(status)) {
-		nv_debug(mxm, "WMMX MXMI returned %d\n", status);
-		return 0x00;
-	}
-
-	obj = retn.pointer;
-	if (obj->type == ACPI_TYPE_INTEGER) {
-		version = obj->integer.value;
-		nv_debug(mxm, "WMMX MXMI version %d.%d\n",
-			     (version >> 4), version & 0x0f);
-	} else {
-		version = 0;
-		nv_debug(mxm, "WMMX MXMI returned non-integer\n");
-	}
-
-	kfree(obj);
-	return version;
-}
-
-static bool
-mxm_shadow_wmi(struct nouveau_mxm *mxm, u8 version)
-{
-	u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 };
-	struct acpi_buffer args = { sizeof(mxms_args), mxms_args };
-	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *obj;
-	acpi_status status;
-
-	if (!wmi_has_guid(WMI_WMMX_GUID)) {
-		nv_debug(mxm, "WMMX GUID not found\n");
-		return false;
-	}
-
-	mxms_args[1] = wmi_wmmx_mxmi(mxm, 0x00);
-	if (!mxms_args[1])
-		mxms_args[1] = wmi_wmmx_mxmi(mxm, version);
-	if (!mxms_args[1])
-		return false;
-
-	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
-	if (ACPI_FAILURE(status)) {
-		nv_debug(mxm, "WMMX MXMS returned %d\n", status);
-		return false;
-	}
-
-	obj = retn.pointer;
-	if (obj->type == ACPI_TYPE_BUFFER) {
-		mxm->mxms = kmemdup(obj->buffer.pointer,
-					 obj->buffer.length, GFP_KERNEL);
-	}
-
-	kfree(obj);
-	return mxm->mxms != NULL;
-}
-#endif
-
-static struct mxm_shadow_h {
-	const char *name;
-	bool (*exec)(struct nouveau_mxm *, u8 version);
-} _mxm_shadow[] = {
-	{ "ROM", mxm_shadow_rom },
-#if defined(CONFIG_ACPI)
-	{ "DSM", mxm_shadow_dsm },
-#endif
-#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
-	{ "WMI", mxm_shadow_wmi },
-#endif
-	{}
-};
-
-static int
-mxm_shadow(struct nouveau_mxm *mxm, u8 version)
-{
-	struct mxm_shadow_h *shadow = _mxm_shadow;
-	do {
-		nv_debug(mxm, "checking %s\n", shadow->name);
-		if (shadow->exec(mxm, version)) {
-			if (mxms_valid(mxm))
-				return 0;
-			kfree(mxm->mxms);
-			mxm->mxms = NULL;
-		}
-	} while ((++shadow)->name);
-	return -ENOENT;
-}
-
-int
-nouveau_mxm_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nouveau_bios *bios = nouveau_bios(device);
-	struct nouveau_mxm *mxm;
-	u8  ver, len;
-	u16 data;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm",
-				     length, pobject);
-	mxm = *pobject;
-	if (ret)
-		return ret;
-
-	data = mxm_table(bios, &ver, &len);
-	if (!data || !(ver = nv_ro08(bios, data))) {
-		nv_debug(mxm, "no VBIOS data, nothing to do\n");
-		return 0;
-	}
-
-	nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f);
-
-	if (mxm_shadow(mxm, ver)) {
-		nv_info(mxm, "failed to locate valid SIS\n");
-#if 0
-		/* we should, perhaps, fall back to some kind of limited
-		 * mode here if the x86 vbios hasn't already done the
-		 * work for us (so we prevent loading with completely
-		 * whacked vbios tables).
-		 */
-		return -EINVAL;
-#else
-		return 0;
-#endif
-	}
-
-	nv_info(mxm, "MXMS Version %d.%d\n",
-		mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff);
-	mxms_foreach(mxm, 0, NULL, NULL);
-
-	if (nouveau_boolopt(device->cfgopt, "NvMXMDCB", true))
-		mxm->action |= MXM_SANITISE_DCB;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
deleted file mode 100644
index 4bde7f7..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/mxm.h>
-#include "mxms.h"
-
-#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
-#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
-
-static u8 *
-mxms_data(struct nouveau_mxm *mxm)
-{
-	return mxm->mxms;
-
-}
-
-u16
-mxms_version(struct nouveau_mxm *mxm)
-{
-	u8 *mxms = mxms_data(mxm);
-	u16 version = (mxms[4] << 8) | mxms[5];
-	switch (version ) {
-	case 0x0200:
-	case 0x0201:
-	case 0x0300:
-		return version;
-	default:
-		break;
-	}
-
-	nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]);
-	return 0x0000;
-}
-
-u16
-mxms_headerlen(struct nouveau_mxm *mxm)
-{
-	return 8;
-}
-
-u16
-mxms_structlen(struct nouveau_mxm *mxm)
-{
-	return *(u16 *)&mxms_data(mxm)[6];
-}
-
-bool
-mxms_checksum(struct nouveau_mxm *mxm)
-{
-	u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
-	u8 *mxms = mxms_data(mxm), sum = 0;
-	while (size--)
-		sum += *mxms++;
-	if (sum) {
-		nv_debug(mxm, "checksum invalid\n");
-		return false;
-	}
-	return true;
-}
-
-bool
-mxms_valid(struct nouveau_mxm *mxm)
-{
-	u8 *mxms = mxms_data(mxm);
-	if (*(u32 *)mxms != 0x5f4d584d) {
-		nv_debug(mxm, "signature invalid\n");
-		return false;
-	}
-
-	if (!mxms_version(mxm) || !mxms_checksum(mxm))
-		return false;
-
-	return true;
-}
-
-bool
-mxms_foreach(struct nouveau_mxm *mxm, u8 types,
-	     bool (*exec)(struct nouveau_mxm *, u8 *, void *), void *info)
-{
-	u8 *mxms = mxms_data(mxm);
-	u8 *desc = mxms + mxms_headerlen(mxm);
-	u8 *fini = desc + mxms_structlen(mxm) - 1;
-	while (desc < fini) {
-		u8 type = desc[0] & 0x0f;
-		u8 headerlen = 0;
-		u8 recordlen = 0;
-		u8 entries = 0;
-
-		switch (type) {
-		case 0: /* Output Device Structure */
-			if (mxms_version(mxm) >= 0x0300)
-				headerlen = 8;
-			else
-				headerlen = 6;
-			break;
-		case 1: /* System Cooling Capability Structure */
-		case 2: /* Thermal Structure */
-		case 3: /* Input Power Structure */
-			headerlen = 4;
-			break;
-		case 4: /* GPIO Device Structure */
-			headerlen = 4;
-			recordlen = 2;
-			entries   = (ROM32(desc[0]) & 0x01f00000) >> 20;
-			break;
-		case 5: /* Vendor Specific Structure */
-			headerlen = 8;
-			break;
-		case 6: /* Backlight Control Structure */
-			if (mxms_version(mxm) >= 0x0300) {
-				headerlen = 4;
-				recordlen = 8;
-				entries   = (desc[1] & 0xf0) >> 4;
-			} else {
-				headerlen = 8;
-			}
-			break;
-		case 7: /* Fan Control Structure */
-			headerlen = 8;
-			recordlen = 4;
-			entries   = desc[1] & 0x07;
-			break;
-		default:
-			nv_debug(mxm, "unknown descriptor type %d\n", type);
-			return false;
-		}
-
-		if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) {
-			static const char * mxms_desc_name[] = {
-				"ODS", "SCCS", "TS", "IPS",
-				"GSD", "VSS", "BCS", "FCS",
-			};
-			u8 *dump = desc;
-			int i, j;
-
-			nv_debug(mxm, "%4s: ", mxms_desc_name[type]);
-			for (j = headerlen - 1; j >= 0; j--)
-				pr_cont("%02x", dump[j]);
-			pr_cont("\n");
-			dump += headerlen;
-
-			for (i = 0; i < entries; i++, dump += recordlen) {
-				nv_debug(mxm, "      ");
-				for (j = recordlen - 1; j >= 0; j--)
-					pr_cont("%02x", dump[j]);
-				pr_cont("\n");
-			}
-		}
-
-		if (types & (1 << type)) {
-			if (!exec(mxm, desc, info))
-				return false;
-		}
-
-		desc += headerlen + (entries * recordlen);
-	}
-
-	return true;
-}
-
-void
-mxms_output_device(struct nouveau_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
-{
-	u64 data = ROM32(pdata[0]);
-	if (mxms_version(mxm) >= 0x0300)
-		data |= (u64)ROM16(pdata[4]) << 32;
-
-	desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
-	desc->ddc_port  = (data & 0x0000000000000f00ULL) >> 8;
-	desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
-	desc->dig_conn  = (data & 0x0000000000780000ULL) >> 19;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
deleted file mode 100644
index 5e0be0c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVMXM_MXMS_H__
-#define __NVMXM_MXMS_H__
-
-struct mxms_odev {
-	u8 outp_type;
-	u8 conn_type;
-	u8 ddc_port;
-	u8 dig_conn;
-};
-
-void mxms_output_device(struct nouveau_mxm *, u8 *, struct mxms_odev *);
-
-u16  mxms_version(struct nouveau_mxm *);
-u16  mxms_headerlen(struct nouveau_mxm *);
-u16  mxms_structlen(struct nouveau_mxm *);
-bool mxms_checksum(struct nouveau_mxm *);
-bool mxms_valid(struct nouveau_mxm *);
-
-bool mxms_foreach(struct nouveau_mxm *, u8,
-		  bool (*)(struct nouveau_mxm *, u8 *, void *), void *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
deleted file mode 100644
index fcaabe8..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2011 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/mxm.h>
-#include <subdev/bios.h>
-#include <subdev/bios/conn.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/mxm.h>
-
-#include "mxms.h"
-
-struct nv50_mxm_priv {
-	struct nouveau_mxm base;
-};
-
-struct context {
-	u32 *outp;
-	struct mxms_odev desc;
-};
-
-static bool
-mxm_match_tmds_partner(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
-	struct context *ctx = info;
-	struct mxms_odev desc;
-
-	mxms_output_device(mxm, data, &desc);
-	if (desc.outp_type == 2 &&
-	    desc.dig_conn == ctx->desc.dig_conn)
-		return false;
-	return true;
-}
-
-static bool
-mxm_match_dcb(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
-	struct nouveau_bios *bios = nouveau_bios(mxm);
-	struct context *ctx = info;
-	u64 desc = *(u64 *)data;
-
-	mxms_output_device(mxm, data, &ctx->desc);
-
-	/* match dcb encoder type to mxm-ods device type */
-	if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
-		return true;
-
-	/* digital output, have some extra stuff to match here, there's a
-	 * table in the vbios that provides a mapping from the mxm digital
-	 * connection enum values to SOR/link
-	 */
-	if ((desc & 0x00000000000000f0) >= 0x20) {
-		/* check against sor index */
-		u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
-		if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
-			return true;
-
-		/* check dcb entry has a compatible link field */
-		link = (link & 0x30) >> 4;
-		if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
-			return true;
-	}
-
-	/* mark this descriptor accounted for by setting invalid device type,
-	 * except of course some manufactures don't follow specs properly and
-	 * we need to avoid killing off the TMDS function on DP connectors
-	 * if MXM-SIS is missing an entry for it.
-	 */
-	data[0] &= ~0xf0;
-	if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
-	    mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
-		data[0] |= 0x20; /* modify descriptor to match TMDS now */
-	} else {
-		data[0] |= 0xf0;
-	}
-
-	return false;
-}
-
-static int
-mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb)
-{
-	struct nouveau_mxm *mxm = data;
-	struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
-	u8 type, i2cidx, link, ver, len;
-	u8 *conn;
-
-	/* look for an output device structure that matches this dcb entry.
-	 * if one isn't found, disable it.
-	 */
-	if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
-		nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n",
-			idx, ctx.outp[0], ctx.outp[1]);
-		ctx.outp[0] |= 0x0000000f;
-		return 0;
-	}
-
-	/* modify the output's ddc/aux port, there's a pointer to a table
-	 * with the mapping from mxm ddc/aux port to dcb i2c_index in the
-	 * vbios mxm table
-	 */
-	i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
-	if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
-		i2cidx = (i2cidx & 0x0f) << 4;
-	else
-		i2cidx = (i2cidx & 0xf0);
-
-	if (i2cidx != 0xf0) {
-		ctx.outp[0] &= ~0x000000f0;
-		ctx.outp[0] |= i2cidx;
-	}
-
-	/* override dcb sorconf.link, based on what mxm data says */
-	switch (ctx.desc.outp_type) {
-	case 0x00: /* Analog CRT */
-	case 0x01: /* Analog TV/HDTV */
-		break;
-	default:
-		link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
-		ctx.outp[1] &= ~0x00000030;
-		ctx.outp[1] |= link;
-		break;
-	}
-
-	/* we may need to fixup various other vbios tables based on what
-	 * the descriptor says the connector type should be.
-	 *
-	 * in a lot of cases, the vbios tables will claim DVI-I is possible,
-	 * and the mxm data says the connector is really HDMI.  another
-	 * common example is DP->eDP.
-	 */
-	conn  = bios->data;
-	conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
-	type  = conn[0];
-	switch (ctx.desc.conn_type) {
-	case 0x01: /* LVDS */
-		ctx.outp[1] |= 0x00000004; /* use_power_scripts */
-		/* XXX: modify default link width in LVDS table */
-		break;
-	case 0x02: /* HDMI */
-		type = DCB_CONNECTOR_HDMI_1;
-		break;
-	case 0x03: /* DVI-D */
-		type = DCB_CONNECTOR_DVI_D;
-		break;
-	case 0x0e: /* eDP, falls through to DPint */
-		ctx.outp[1] |= 0x00010000;
-	case 0x07: /* DP internal, wtf is this?? HP8670w */
-		ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
-		type = DCB_CONNECTOR_eDP;
-		break;
-	default:
-		break;
-	}
-
-	if (mxms_version(mxm) >= 0x0300)
-		conn[0] = type;
-
-	return 0;
-}
-
-static bool
-mxm_show_unmatched(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
-	u64 desc = *(u64 *)data;
-	if ((desc & 0xf0) != 0xf0)
-	nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
-	return true;
-}
-
-static void
-mxm_dcb_sanitise(struct nouveau_mxm *mxm)
-{
-	struct nouveau_bios *bios = nouveau_bios(mxm);
-	u8  ver, hdr, cnt, len;
-	u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
-	if (dcb == 0x0000 || ver != 0x40) {
-		nv_debug(mxm, "unsupported DCB version\n");
-		return;
-	}
-
-	dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
-	mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
-}
-
-static int
-nv50_mxm_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	      struct nouveau_oclass *oclass, void *data, u32 size,
-	      struct nouveau_object **pobject)
-{
-	struct nv50_mxm_priv *priv;
-	int ret;
-
-	ret = nouveau_mxm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	if (priv->base.action & MXM_SANITISE_DCB)
-		mxm_dcb_sanitise(&priv->base);
-	return 0;
-}
-
-struct nouveau_oclass
-nv50_mxm_oclass = {
-	.handle = NV_SUBDEV(MXM, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_mxm_ctor,
-		.dtor = _nouveau_mxm_dtor,
-		.init = _nouveau_mxm_init,
-		.fini = _nouveau_mxm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
deleted file mode 100644
index 0ab55f2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-static void
-nouveau_pwr_pgob(struct nouveau_pwr *ppwr, bool enable)
-{
-	const struct nvkm_pwr_impl *impl = (void *)nv_oclass(ppwr);
-	if (impl->pgob)
-		impl->pgob(ppwr, enable);
-}
-
-static int
-nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
-		 u32 process, u32 message, u32 data0, u32 data1)
-{
-	struct nouveau_subdev *subdev = nv_subdev(ppwr);
-	u32 addr;
-
-	/* wait for a free slot in the fifo */
-	addr  = nv_rd32(ppwr, 0x10a4a0);
-	if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
-		return -EBUSY;
-
-	/* we currently only support a single process at a time waiting
-	 * on a synchronous reply, take the PPWR mutex and tell the
-	 * receive handler what we're waiting for
-	 */
-	if (reply) {
-		mutex_lock(&subdev->mutex);
-		ppwr->recv.message = message;
-		ppwr->recv.process = process;
-	}
-
-	/* acquire data segment access */
-	do {
-		nv_wr32(ppwr, 0x10a580, 0x00000001);
-	} while (nv_rd32(ppwr, 0x10a580) != 0x00000001);
-
-	/* write the packet */
-	nv_wr32(ppwr, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
-				ppwr->send.base));
-	nv_wr32(ppwr, 0x10a1c4, process);
-	nv_wr32(ppwr, 0x10a1c4, message);
-	nv_wr32(ppwr, 0x10a1c4, data0);
-	nv_wr32(ppwr, 0x10a1c4, data1);
-	nv_wr32(ppwr, 0x10a4a0, (addr + 1) & 0x0f);
-
-	/* release data segment access */
-	nv_wr32(ppwr, 0x10a580, 0x00000000);
-
-	/* wait for reply, if requested */
-	if (reply) {
-		wait_event(ppwr->recv.wait, (ppwr->recv.process == 0));
-		reply[0] = ppwr->recv.data[0];
-		reply[1] = ppwr->recv.data[1];
-		mutex_unlock(&subdev->mutex);
-	}
-
-	return 0;
-}
-
-static void
-nouveau_pwr_recv(struct work_struct *work)
-{
-	struct nouveau_pwr *ppwr =
-		container_of(work, struct nouveau_pwr, recv.work);
-	u32 process, message, data0, data1;
-
-	/* nothing to do if GET == PUT */
-	u32 addr =  nv_rd32(ppwr, 0x10a4cc);
-	if (addr == nv_rd32(ppwr, 0x10a4c8))
-		return;
-
-	/* acquire data segment access */
-	do {
-		nv_wr32(ppwr, 0x10a580, 0x00000002);
-	} while (nv_rd32(ppwr, 0x10a580) != 0x00000002);
-
-	/* read the packet */
-	nv_wr32(ppwr, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
-				ppwr->recv.base));
-	process = nv_rd32(ppwr, 0x10a1c4);
-	message = nv_rd32(ppwr, 0x10a1c4);
-	data0   = nv_rd32(ppwr, 0x10a1c4);
-	data1   = nv_rd32(ppwr, 0x10a1c4);
-	nv_wr32(ppwr, 0x10a4cc, (addr + 1) & 0x0f);
-
-	/* release data segment access */
-	nv_wr32(ppwr, 0x10a580, 0x00000000);
-
-	/* wake process if it's waiting on a synchronous reply */
-	if (ppwr->recv.process) {
-		if (process == ppwr->recv.process &&
-		    message == ppwr->recv.message) {
-			ppwr->recv.data[0] = data0;
-			ppwr->recv.data[1] = data1;
-			ppwr->recv.process = 0;
-			wake_up(&ppwr->recv.wait);
-			return;
-		}
-	}
-
-	/* right now there's no other expected responses from the engine,
-	 * so assume that any unexpected message is an error.
-	 */
-	nv_warn(ppwr, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
-		(char)((process & 0x000000ff) >>  0),
-		(char)((process & 0x0000ff00) >>  8),
-		(char)((process & 0x00ff0000) >> 16),
-		(char)((process & 0xff000000) >> 24),
-		process, message, data0, data1);
-}
-
-static void
-nouveau_pwr_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_pwr *ppwr = (void *)subdev;
-	u32 disp = nv_rd32(ppwr, 0x10a01c);
-	u32 intr = nv_rd32(ppwr, 0x10a008) & disp & ~(disp >> 16);
-
-	if (intr & 0x00000020) {
-		u32 stat = nv_rd32(ppwr, 0x10a16c);
-		if (stat & 0x80000000) {
-			nv_error(ppwr, "UAS fault at 0x%06x addr 0x%08x\n",
-				 stat & 0x00ffffff, nv_rd32(ppwr, 0x10a168));
-			nv_wr32(ppwr, 0x10a16c, 0x00000000);
-			intr &= ~0x00000020;
-		}
-	}
-
-	if (intr & 0x00000040) {
-		schedule_work(&ppwr->recv.work);
-		nv_wr32(ppwr, 0x10a004, 0x00000040);
-		intr &= ~0x00000040;
-	}
-
-	if (intr & 0x00000080) {
-		nv_info(ppwr, "wr32 0x%06x 0x%08x\n", nv_rd32(ppwr, 0x10a7a0),
-						      nv_rd32(ppwr, 0x10a7a4));
-		nv_wr32(ppwr, 0x10a004, 0x00000080);
-		intr &= ~0x00000080;
-	}
-
-	if (intr) {
-		nv_error(ppwr, "intr 0x%08x\n", intr);
-		nv_wr32(ppwr, 0x10a004, intr);
-	}
-}
-
-int
-_nouveau_pwr_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_pwr *ppwr = (void *)object;
-
-	nv_wr32(ppwr, 0x10a014, 0x00000060);
-	flush_work(&ppwr->recv.work);
-
-	return nouveau_subdev_fini(&ppwr->base, suspend);
-}
-
-int
-_nouveau_pwr_init(struct nouveau_object *object)
-{
-	const struct nvkm_pwr_impl *impl = (void *)object->oclass;
-	struct nouveau_pwr *ppwr = (void *)object;
-	int ret, i;
-
-	ret = nouveau_subdev_init(&ppwr->base);
-	if (ret)
-		return ret;
-
-	nv_subdev(ppwr)->intr = nouveau_pwr_intr;
-	ppwr->message = nouveau_pwr_send;
-	ppwr->pgob = nouveau_pwr_pgob;
-
-	/* prevent previous ucode from running, wait for idle, reset */
-	nv_wr32(ppwr, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
-	nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
-	nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
-	nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
-	nv_rd32(ppwr, 0x000200);
-	nv_wait(ppwr, 0x10a10c, 0x00000006, 0x00000000);
-
-	/* upload data segment */
-	nv_wr32(ppwr, 0x10a1c0, 0x01000000);
-	for (i = 0; i < impl->data.size / 4; i++)
-		nv_wr32(ppwr, 0x10a1c4, impl->data.data[i]);
-
-	/* upload code segment */
-	nv_wr32(ppwr, 0x10a180, 0x01000000);
-	for (i = 0; i < impl->code.size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(ppwr, 0x10a188, i >> 6);
-		nv_wr32(ppwr, 0x10a184, impl->code.data[i]);
-	}
-
-	/* start it running */
-	nv_wr32(ppwr, 0x10a10c, 0x00000000);
-	nv_wr32(ppwr, 0x10a104, 0x00000000);
-	nv_wr32(ppwr, 0x10a100, 0x00000002);
-
-	/* wait for valid host->pwr ring configuration */
-	if (!nv_wait_ne(ppwr, 0x10a4d0, 0xffffffff, 0x00000000))
-		return -EBUSY;
-	ppwr->send.base = nv_rd32(ppwr, 0x10a4d0) & 0x0000ffff;
-	ppwr->send.size = nv_rd32(ppwr, 0x10a4d0) >> 16;
-
-	/* wait for valid pwr->host ring configuration */
-	if (!nv_wait_ne(ppwr, 0x10a4dc, 0xffffffff, 0x00000000))
-		return -EBUSY;
-	ppwr->recv.base = nv_rd32(ppwr, 0x10a4dc) & 0x0000ffff;
-	ppwr->recv.size = nv_rd32(ppwr, 0x10a4dc) >> 16;
-
-	nv_wr32(ppwr, 0x10a010, 0x000000e0);
-	return 0;
-}
-
-int
-nouveau_pwr_create_(struct nouveau_object *parent,
-		    struct nouveau_object *engine,
-		    struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_pwr *ppwr;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PPWR",
-				     "pwr", length, pobject);
-	ppwr = *pobject;
-	if (ret)
-		return ret;
-
-	INIT_WORK(&ppwr->recv.work, nouveau_pwr_recv);
-	init_waitqueue_head(&ppwr->recv.wait);
-	return 0;
-}
-
-int
-_nouveau_pwr_ctor(struct nouveau_object *parent,
-		  struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
-{
-	struct nouveau_pwr *ppwr;
-	int ret = nouveau_pwr_create(parent, engine, oclass, &ppwr);
-	*pobject = nv_object(ppwr);
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
deleted file mode 100644
index b439519..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GK208
-#define HW_TICKS_PER_US 324
-
-#define NVKM_FALCON_PC24
-#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nv108_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nv108_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
deleted file mode 100644
index 713e11e..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
+++ /dev/null
@@ -1,1731 +0,0 @@
-uint32_t nv108_pwr_data[] = {
-/* 0x0000: proc_kern */
-	0x52544e49,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: proc_list_head */
-	0x54534f48,
-	0x00000453,
-	0x00000404,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x584d454d,
-	0x0000062d,
-	0x0000061f,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x46524550,
-	0x00000631,
-	0x0000062f,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x5f433249,
-	0x00000a35,
-	0x000008dc,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x54534554,
-	0x00000a56,
-	0x00000a37,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x454c4449,
-	0x00000a61,
-	0x00000a5f,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
-	0x00000000,
-/* 0x026c: time_next */
-	0x00000000,
-/* 0x0270: fifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x02f0: rfifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0370: memx_func_head */
-	0x00000001,
-	0x00000000,
-	0x00000483,
-/* 0x037c: memx_func_next */
-	0x00000002,
-	0x00000000,
-	0x00000500,
-	0x00000003,
-	0x00000002,
-	0x00000580,
-	0x00040004,
-	0x00000000,
-	0x0000059d,
-	0x00010005,
-	0x00000000,
-	0x000005b7,
-	0x00010006,
-	0x00000000,
-	0x0000057b,
-	0x00000007,
-	0x00000000,
-	0x000005c3,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
-	0x00000000,
-/* 0x03c8: memx_ts_end */
-	0x00000000,
-/* 0x03cc: memx_data_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
-	0x00000400,
-	0x00000800,
-	0x00001000,
-	0x00002000,
-	0x00004000,
-	0x00008000,
-	0x00010000,
-	0x00020000,
-	0x00040000,
-	0x00080000,
-/* 0x0cf4: i2c_sda_map */
-	0x00100000,
-	0x00200000,
-	0x00400000,
-	0x00800000,
-	0x01000000,
-	0x02000000,
-	0x04000000,
-	0x08000000,
-	0x10000000,
-	0x20000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nv108_pwr_code[] = {
-	0x031c0ef5,
-/* 0x0004: rd32 */
-	0xf607a040,
-	0x04bd000e,
-	0xd3f0010d,
-	0x07ac4001,
-	0xbd000df6,
-/* 0x0019: rd32_wait */
-	0x07ac4d04,
-	0xf100ddcf,
-	0xf47000d4,
-	0xa44df61b,
-	0x00ddcf07,
-/* 0x002e: wr32 */
-	0xa04000f8,
-	0x000ef607,
-	0xa44004bd,
-	0x000df607,
-	0x020d04bd,
-	0xf0f0d5f0,
-	0xac4001d3,
-	0x000df607,
-/* 0x004e: wr32_wait */
-	0xac4d04bd,
-	0x00ddcf07,
-	0x7000d4f1,
-	0xf8f61bf4,
-/* 0x005d: nsec */
-	0xf990f900,
-	0xcf2c0880,
-/* 0x0066: nsec_loop */
-	0x2c090088,
-	0xbb0099cf,
-	0x9ea60298,
-	0xfcf61ef4,
-	0xf890fc80,
-/* 0x0079: wait */
-	0xf990f900,
-	0xcf2c0880,
-/* 0x0082: wait_loop */
-	0xeeb20088,
-	0x0000047e,
-	0xadfddab2,
-	0xf4aca604,
-	0x2c09100b,
-	0xbb0099cf,
-	0x9ba60298,
-/* 0x009f: wait_done */
-	0xfce61ef4,
-	0xf890fc80,
-/* 0x00a5: intr_watchdog */
-	0x03e99800,
-	0xf40096b0,
-	0x0a98280b,
-	0x029abb9a,
-	0x0d0e1cf4,
-	0x02617e01,
-	0xf494bd00,
-/* 0x00c2: intr_watchdog_next_time */
-	0x0a98140e,
-	0x00a6b09b,
-	0xa6080bf4,
-	0x061cf49a,
-/* 0x00d0: intr_watchdog_next_time_set */
-/* 0x00d3: intr_watchdog_next_proc */
-	0xb59b09b5,
-	0xe0b603e9,
-	0x68e6b158,
-	0xc81bf402,
-/* 0x00e2: intr */
-	0x00f900f8,
-	0x80f904bd,
-	0xa0f990f9,
-	0xc0f9b0f9,
-	0xe0f9d0f9,
-	0x000ff0f9,
-	0xf90188fe,
-	0x04504880,
-	0xb60088cf,
-	0x50400180,
-	0x0008f604,
-	0x080804bd,
-	0xc40088cf,
-	0x0bf40289,
-	0x9b00b51f,
-	0xa57e580e,
-	0x09980000,
-	0x0096b09b,
-	0x000d0bf4,
-	0x0009f634,
-	0x09b504bd,
-/* 0x0135: intr_skip_watchdog */
-	0x0089e49a,
-	0x360bf408,
-	0xcf068849,
-	0x9ac40099,
-	0x220bf402,
-	0xcf04c04c,
-	0xc0f900cc,
-	0xf14f484e,
-	0x0d5453e3,
-	0x02c27e00,
-	0x40c0fc00,
-	0x0cf604c0,
-/* 0x0167: intr_subintr_skip_fifo */
-	0x4004bd00,
-	0x09f60688,
-/* 0x016f: intr_skip_subintr */
-	0xc404bd00,
-	0x0bf42089,
-	0xbfa4f107,
-/* 0x0179: intr_skip_pause */
-	0x4089c4ff,
-	0xf1070bf4,
-/* 0x0183: intr_skip_user0 */
-	0x00ffbfa4,
-	0x0008f604,
-	0x80fc04bd,
-	0xfc0088fe,
-	0xfce0fcf0,
-	0xfcc0fcd0,
-	0xfca0fcb0,
-	0xfc80fc90,
-	0x0032f400,
-/* 0x01a6: ticks_from_ns */
-	0xc0f901f8,
-	0xd7f1b0f9,
-	0xd3f00144,
-	0x7721f500,
-	0xe8ccec03,
-	0x00b4b003,
-	0xec120bf4,
-	0xf103e8ee,
-	0xf00144d7,
-	0x21f500d3,
-/* 0x01ce: ticks_from_ns_quit */
-	0xceb20377,
-	0xc0fcb0fc,
-/* 0x01d6: ticks_from_us */
-	0xc0f900f8,
-	0xd7f1b0f9,
-	0xd3f00144,
-	0x7721f500,
-	0xb0ceb203,
-	0x0bf400b4,
-/* 0x01ef: ticks_from_us_quit */
-	0xfce4bd05,
-	0xf8c0fcb0,
-/* 0x01f5: ticks_to_us */
-	0x44d7f100,
-	0x00d3f001,
-	0xf8ecedff,
-/* 0x0201: timer */
-	0xf990f900,
-	0x1032f480,
-	0xb003f898,
-	0x1cf40086,
-	0x0084bd4a,
-	0x0008f638,
-	0x340804bd,
-	0x980088cf,
-	0x98bb9a09,
-	0x00e9bb02,
-	0x0803feb5,
-	0x0088cf08,
-	0xf40284f0,
-	0x34081c1b,
-	0xa60088cf,
-	0x080bf4e0,
-	0x1cf4e8a6,
-/* 0x0245: timer_reset */
-	0xf634000d,
-	0x04bd000e,
-/* 0x024f: timer_enable */
-	0x089a0eb5,
-	0xf6380001,
-	0x04bd0008,
-/* 0x0258: timer_done */
-	0xfc1031f4,
-	0xf890fc80,
-/* 0x0261: send_proc */
-	0xf980f900,
-	0x05e89890,
-	0xf004e998,
-	0x89a60486,
-	0xc42a0bf4,
-	0x88940398,
-	0x1880b604,
-	0x98008ebb,
-	0x8ab500fa,
-	0x018db500,
-	0xb5028cb5,
-	0x90b6038b,
-	0x0794f001,
-	0xf404e9b5,
-/* 0x029a: send_done */
-	0x90fc0231,
-	0x00f880fc,
-/* 0x02a0: find */
-	0x580880f9,
-/* 0x02a7: find_loop */
-	0x980131f4,
-	0xaea6008a,
-	0xb6100bf4,
-	0x86b15880,
-	0x1bf40268,
-	0x0132f4f1,
-/* 0x02bc: find_done */
-	0x80fc8eb2,
-/* 0x02c2: send */
-	0xa07e00f8,
-	0x01f40002,
-/* 0x02cb: recv */
-	0xf900f89b,
-	0x9880f990,
-	0xe99805e8,
-	0x0132f404,
-	0x0bf489a6,
-	0x0389c43c,
-	0xf00180b6,
-	0xe8b50784,
-	0x02ea9805,
-	0x8ffef0f9,
-	0xb2f0f901,
-	0x049994ef,
-	0xb600e9bb,
-	0xeb9818e0,
-	0x02ec9803,
-	0x9801ed98,
-	0xa5f900ee,
-	0xf8fef0fc,
-	0x0131f400,
-/* 0x0316: recv_done */
-	0x80fcf0fc,
-	0x00f890fc,
-/* 0x031c: init */
-	0xcf010841,
-	0x11e70011,
-	0x14b60109,
-	0x0014fe08,
-	0xf000e041,
-	0x1c000013,
-	0xbd0001f6,
-	0x00ff0104,
-	0x0001f614,
-	0x020104bd,
-	0x080015f1,
-	0x01f61000,
-	0x4104bd00,
-	0x13f000e2,
-	0x0010fe00,
-	0x011031f4,
-	0xf6380001,
-	0x04bd0001,
-/* 0x0366: init_proc */
-	0xf198580f,
-	0x0016b001,
-	0xf9fa0bf4,
-	0x58f0b615,
-/* 0x0377: mulu32_32_64 */
-	0xf9f20ef4,
-	0xf920f910,
-	0x9540f930,
-	0xd29510e1,
-	0xbdc4bd10,
-	0xc0edffb4,
-	0xb2301dff,
-	0xff34f134,
-	0x1034b6ff,
-	0xbb1045b6,
-	0xb4bb00c3,
-	0x30e2ff01,
-	0x34f134b2,
-	0x34b6ffff,
-	0x1045b610,
-	0xbb00c3bb,
-	0x12ff01b4,
-	0x00b3bb30,
-	0x30fc40fc,
-	0x10fc20fc,
-/* 0x03c6: host_send */
-	0xb04100f8,
-	0x0011cf04,
-	0xcf04a042,
-	0x12a60022,
-	0xc42e0bf4,
-	0xee94071e,
-	0x70e0b704,
-	0x03eb9802,
-	0x9802ec98,
-	0xee9801ed,
-	0x02c27e00,
-	0x0110b600,
-	0x400f1ec4,
-	0x0ef604b0,
-	0xf404bd00,
-/* 0x0402: host_send_done */
-	0x00f8c70e,
-/* 0x0404: host_recv */
-	0xf14e4941,
-	0xa6525413,
-	0xb90bf4e1,
-/* 0x0410: host_recv_wait */
-	0xcf04cc41,
-	0xc8420011,
-	0x0022cf04,
-	0xa60816f0,
-	0xef0bf412,
-	0xb60723c4,
-	0x30b70434,
-	0x3bb502f0,
-	0x023cb503,
-	0xb5013db5,
-	0x20b6003e,
-	0x0f24f001,
-	0xf604c840,
-	0x04bd0002,
-	0x00004002,
-	0xbd0002f6,
-/* 0x0453: host_init */
-	0x4100f804,
-	0x14b60080,
-	0x7015f110,
-	0x04d04002,
-	0xbd0001f6,
-	0x00804104,
-	0xf11014b6,
-	0x4002f015,
-	0x01f604dc,
-	0x0104bd00,
-	0x04c44001,
-	0xbd0001f6,
-/* 0x0483: memx_func_enter */
-	0xf100f804,
-	0xf1162067,
-	0xf1f55d77,
-	0xb2ffff73,
-	0x00047e6e,
-	0xfdd8b200,
-	0x60f90487,
-	0xd0fc80f9,
-	0x2e7ee0fc,
-	0x77f10000,
-	0x73f1fffe,
-	0x6eb2ffff,
-	0x0000047e,
-	0x87fdd8b2,
-	0xf960f904,
-	0xfcd0fc80,
-	0x002e7ee0,
-	0xf067f100,
-	0x7e6eb226,
-	0xb2000004,
-	0x0487fdd8,
-	0x80f960f9,
-	0xe0fcd0fc,
-	0x00002e7e,
-	0xe0400406,
-	0x0006f607,
-/* 0x04ea: memx_func_enter_wait */
-	0xc04604bd,
-	0x0066cf07,
-	0xf40464f0,
-	0x2c06f70b,
-	0xb50066cf,
-	0x00f8f106,
-/* 0x0500: memx_func_leave */
-	0x66cf2c06,
-	0xf206b500,
-	0xe4400406,
-	0x0006f607,
-/* 0x0512: memx_func_leave_wait */
-	0xc04604bd,
-	0x0066cf07,
-	0xf40464f0,
-	0x67f1f71b,
-	0x77f126f0,
-	0x73f00001,
-	0x7e6eb200,
-	0xb2000004,
-	0x0587fdd8,
-	0x80f960f9,
-	0xe0fcd0fc,
-	0x00002e7e,
-	0x162067f1,
-	0x047e6eb2,
-	0xd8b20000,
-	0xf90587fd,
-	0xfc80f960,
-	0x7ee0fcd0,
-	0xf100002e,
-	0xf00aa277,
-	0x6eb20073,
-	0x0000047e,
-	0x87fdd8b2,
-	0xf960f905,
-	0xfcd0fc80,
-	0x002e7ee0,
-/* 0x057b: memx_func_wait_vblank */
-	0xb600f800,
-	0x00f80410,
-/* 0x0580: memx_func_wr32 */
-	0x98001698,
-	0x10b60115,
-	0xf960f908,
-	0xfcd0fc50,
-	0x002e7ee0,
-	0x0242b600,
-	0xf8e81bf4,
-/* 0x059d: memx_func_wait */
-	0xcf2c0800,
-	0x1e980088,
-	0x011d9800,
-	0x98021c98,
-	0x10b6031b,
-	0x00797e10,
-/* 0x05b7: memx_func_delay */
-	0x9800f800,
-	0x10b6001e,
-	0x005d7e04,
-/* 0x05c3: memx_func_train */
-	0xf800f800,
-/* 0x05c5: memx_exec */
-	0xf9e0f900,
-	0xb2c1b2d0,
-/* 0x05cd: memx_exec_next */
-	0x001398b2,
-	0xe70410b6,
-	0xe701f034,
-	0xb601e033,
-	0x30f00132,
-	0xde35980c,
-	0x12a655f9,
-	0x98e51ef4,
-	0x0c98f10b,
-	0x02cbbbf2,
-	0xcf07c44b,
-	0xd0fc00bb,
-	0xc27ee0fc,
-	0x00f80002,
-/* 0x0604: memx_info */
-	0xf401c670,
-/* 0x060a: memx_info_data */
-	0xcc4c0c0b,
-	0x08004b03,
-/* 0x0613: memx_info_train */
-	0x4c090ef4,
-	0x004b0bcc,
-/* 0x0619: memx_info_send */
-	0x02c27e01,
-/* 0x061f: memx_recv */
-	0xb000f800,
-	0x0bf401d6,
-	0x00d6b0a3,
-	0xf8dc0bf4,
-/* 0x062d: memx_init */
-/* 0x062f: perf_recv */
-	0xf800f800,
-/* 0x0631: perf_init */
-/* 0x0633: i2c_drive_scl */
-	0xb000f800,
-	0x0bf40036,
-	0x07e0400d,
-	0xbd0001f6,
-/* 0x0643: i2c_drive_scl_lo */
-	0x4000f804,
-	0x01f607e4,
-	0xf804bd00,
-/* 0x064d: i2c_drive_sda */
-	0x0036b000,
-	0x400d0bf4,
-	0x02f607e0,
-	0xf804bd00,
-/* 0x065d: i2c_drive_sda_lo */
-	0x07e44000,
-	0xbd0002f6,
-/* 0x0667: i2c_sense_scl */
-	0xf400f804,
-	0xc4430132,
-	0x0033cf07,
-	0xf40431fd,
-	0x31f4060b,
-/* 0x0679: i2c_sense_scl_done */
-/* 0x067b: i2c_sense_sda */
-	0xf400f801,
-	0xc4430132,
-	0x0033cf07,
-	0xf40432fd,
-	0x31f4060b,
-/* 0x068d: i2c_sense_sda_done */
-/* 0x068f: i2c_raise_scl */
-	0xf900f801,
-	0x08984440,
-	0x337e0103,
-/* 0x069a: i2c_raise_scl_wait */
-	0xe84e0006,
-	0x005d7e03,
-	0x06677e00,
-	0x0901f400,
-	0xf40142b6,
-/* 0x06ae: i2c_raise_scl_done */
-	0x40fcef1b,
-/* 0x06b2: i2c_start */
-	0x677e00f8,
-	0x11f40006,
-	0x067b7e0d,
-	0x0611f400,
-/* 0x06c3: i2c_start_rep */
-	0x032e0ef4,
-	0x06337e00,
-	0x7e010300,
-	0xbb00064d,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x00068f7e,
-	0xf40464b6,
-/* 0x06ee: i2c_start_send */
-	0x00031d11,
-	0x00064d7e,
-	0x7e13884e,
-	0x0300005d,
-	0x06337e00,
-	0x13884e00,
-	0x00005d7e,
-/* 0x0708: i2c_start_out */
-/* 0x070a: i2c_stop */
-	0x000300f8,
-	0x0006337e,
-	0x4d7e0003,
-	0xe84e0006,
-	0x005d7e03,
-	0x7e010300,
-	0x4e000633,
-	0x5d7e1388,
-	0x01030000,
-	0x00064d7e,
-	0x7e13884e,
-	0xf800005d,
-/* 0x0739: i2c_bitw */
-	0x064d7e00,
-	0x03e84e00,
-	0x00005d7e,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x068f7e50,
-	0x0464b600,
-	0x4e1711f4,
-	0x5d7e1388,
-	0x00030000,
-	0x0006337e,
-	0x7e13884e,
-/* 0x0777: i2c_bitw_out */
-	0xf800005d,
-/* 0x0779: i2c_bitr */
-	0x7e010300,
-	0x4e00064d,
-	0x5d7e03e8,
-	0x76bb0000,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0x7e50fc04,
-	0xb600068f,
-	0x11f40464,
-	0x067b7e1a,
-	0x7e000300,
-	0x4e000633,
-	0x5d7e1388,
-	0x3cf00000,
-	0x0131f401,
-/* 0x07bc: i2c_bitr_done */
-/* 0x07be: i2c_get_byte */
-	0x000500f8,
-/* 0x07c2: i2c_get_byte_next */
-	0x54b60804,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x797e50fc,
-	0x64b60007,
-	0x2a11f404,
-	0xb60553fd,
-	0x1bf40142,
-	0xbb0103d8,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0007397e,
-/* 0x080b: i2c_get_byte_done */
-	0xf80464b6,
-/* 0x080d: i2c_put_byte */
-/* 0x080f: i2c_put_byte_next */
-	0xb6080400,
-	0x54ff0142,
-	0x0076bb38,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x397e50fc,
-	0x64b60007,
-	0x3411f404,
-	0xf40046b0,
-	0x76bbd81b,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0x7e50fc04,
-	0xb6000779,
-	0x11f40464,
-	0x0076bb0f,
-	0xf40136b0,
-	0x32f4061b,
-/* 0x0865: i2c_put_byte_done */
-/* 0x0867: i2c_addr */
-	0xbb00f801,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0006b27e,
-	0xf40464b6,
-	0xc3e72911,
-	0x34b6012e,
-	0x0553fd01,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x080d7e50,
-	0x0464b600,
-/* 0x08ac: i2c_addr_done */
-/* 0x08ae: i2c_acquire_addr */
-	0xcec700f8,
-	0x05e4b6f8,
-	0xd014e0b7,
-/* 0x08ba: i2c_acquire */
-	0xae7e00f8,
-	0x047e0008,
-	0xd9f00000,
-	0x002e7e03,
-/* 0x08cb: i2c_release */
-	0x7e00f800,
-	0x7e0008ae,
-	0xf0000004,
-	0x2e7e03da,
-	0x00f80000,
-/* 0x08dc: i2c_recv */
-	0xc70132f4,
-	0x14b6f8c1,
-	0x2816b002,
-	0x01371ff5,
-	0x0cf413b8,
-	0x00329800,
-	0x0ccc13b8,
-	0x00319800,
-	0xf90231f4,
-	0xf9e0f9d0,
-	0x0067f1d0,
-	0x0063f100,
-	0x01679210,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x08ba7e50,
-	0x0464b600,
-	0xd6b0d0fc,
-	0xb01bf500,
-	0xbb000500,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0008677e,
-	0xf50464b6,
-	0xc700cc11,
-	0x76bbe0c5,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0x7e50fc04,
-	0xb600080d,
-	0x11f50464,
-	0x010500a9,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x08677e50,
-	0x0464b600,
-	0x008711f5,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x07be7e50,
-	0x0464b600,
-	0xcb6711f4,
-	0x76bbe05b,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0x7e50fc04,
-	0xb600070a,
-	0x5bb20464,
-	0x0ef474bd,
-/* 0x09e1: i2c_recv_not_rd08 */
-	0x01d6b041,
-	0x053b1bf4,
-	0x08677e00,
-	0x3211f400,
-	0x7ee0c5c7,
-	0xf400080d,
-	0x00052811,
-	0x0008677e,
-	0xc71f11f4,
-	0x0d7ee0b5,
-	0x11f40008,
-	0x070a7e15,
-	0xc774bd00,
-	0x1bf408c5,
-	0x0232f409,
-/* 0x0a1f: i2c_recv_not_wr08 */
-/* 0x0a1f: i2c_recv_done */
-	0xc7030ef4,
-	0xcb7ef8ce,
-	0xe0fc0008,
-	0x12f4d0fc,
-	0x7e7cb209,
-/* 0x0a33: i2c_recv_exit */
-	0xf80002c2,
-/* 0x0a35: i2c_init */
-/* 0x0a37: test_recv */
-	0x4100f800,
-	0x11cf0458,
-	0x0110b600,
-	0xf6045840,
-	0x04bd0001,
-	0xd900e7f1,
-	0x134fe3f1,
-	0x0002017e,
-/* 0x0a56: test_init */
-	0x004e00f8,
-	0x02017e08,
-/* 0x0a5f: idle_recv */
-	0xf800f800,
-/* 0x0a61: idle */
-	0x0031f400,
-	0xcf045441,
-	0x10b60011,
-	0x04544001,
-	0xbd0001f6,
-/* 0x0a75: idle_loop */
-	0xf4580104,
-/* 0x0a7a: idle_proc */
-/* 0x0a7a: idle_proc_exec */
-	0x10f90232,
-	0xcb7e1eb2,
-	0x10fc0002,
-	0xf40911f4,
-	0x0ef40231,
-/* 0x0a8d: idle_proc_next */
-	0x5810b6f0,
-	0x1bf41fa6,
-	0xe002f4e8,
-	0xf40028f4,
-	0x0000c60e,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
deleted file mode 100644
index daa06c1..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GT215
-#define HW_TICKS_PER_US 203 // should be 202.5
-
-//#define NVKM_FALCON_PC24
-//#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nva3_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nva3_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
deleted file mode 100644
index d1f9b6c..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
+++ /dev/null
@@ -1,1868 +0,0 @@
-uint32_t nva3_pwr_data[] = {
-/* 0x0000: proc_kern */
-	0x52544e49,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: proc_list_head */
-	0x54534f48,
-	0x00000512,
-	0x000004af,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x584d454d,
-	0x00000842,
-	0x00000834,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x46524550,
-	0x00000846,
-	0x00000844,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x5f433249,
-	0x00000c76,
-	0x00000b19,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x54534554,
-	0x00000c9f,
-	0x00000c78,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x454c4449,
-	0x00000cab,
-	0x00000ca9,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
-	0x00000000,
-/* 0x026c: time_next */
-	0x00000000,
-/* 0x0270: fifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x02f0: rfifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0370: memx_func_head */
-	0x00000001,
-	0x00000000,
-	0x00000551,
-/* 0x037c: memx_func_next */
-	0x00000002,
-	0x00000000,
-	0x000005a8,
-	0x00000003,
-	0x00000002,
-	0x0000063a,
-	0x00040004,
-	0x00000000,
-	0x00000656,
-	0x00010005,
-	0x00000000,
-	0x00000673,
-	0x00010006,
-	0x00000000,
-	0x000005f8,
-	0x00000007,
-	0x00000000,
-	0x0000067e,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
-	0x00000000,
-/* 0x03c8: memx_ts_end */
-	0x00000000,
-/* 0x03cc: memx_data_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
-	0x00001000,
-	0x00004000,
-	0x00010000,
-	0x00000100,
-	0x00040000,
-	0x00100000,
-	0x00400000,
-	0x01000000,
-	0x04000000,
-	0x10000000,
-/* 0x0cf4: i2c_sda_map */
-	0x00002000,
-	0x00008000,
-	0x00020000,
-	0x00000200,
-	0x00080000,
-	0x00200000,
-	0x00800000,
-	0x02000000,
-	0x08000000,
-	0x20000000,
-/* 0x0d1c: i2c_ctrl */
-	0x0000e138,
-	0x0000e150,
-	0x0000e168,
-	0x0000e180,
-	0x0000e254,
-	0x0000e274,
-	0x0000e764,
-	0x0000e780,
-	0x0000e79c,
-	0x0000e7b8,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nva3_pwr_code[] = {
-	0x039e0ef5,
-/* 0x0004: rd32 */
-	0x07a007f1,
-	0xd00604b6,
-	0x04bd000e,
-	0xf001d7f0,
-	0x07f101d3,
-	0x04b607ac,
-	0x000dd006,
-/* 0x0022: rd32_wait */
-	0xd7f104bd,
-	0xd4b607ac,
-	0x00ddcf06,
-	0x7000d4f1,
-	0xf1f21bf4,
-	0xb607a4d7,
-	0xddcf06d4,
-/* 0x003f: wr32 */
-	0xf100f800,
-	0xb607a007,
-	0x0ed00604,
-	0xf104bd00,
-	0xb607a407,
-	0x0dd00604,
-	0xf004bd00,
-	0xd5f002d7,
-	0x01d3f0f0,
-	0x07ac07f1,
-	0xd00604b6,
-	0x04bd000d,
-/* 0x006c: wr32_wait */
-	0x07acd7f1,
-	0xcf06d4b6,
-	0xd4f100dd,
-	0x1bf47000,
-/* 0x007f: nsec */
-	0xf900f8f2,
-	0xf080f990,
-	0x84b62c87,
-	0x0088cf06,
-/* 0x008c: nsec_loop */
-	0xb62c97f0,
-	0x99cf0694,
-	0x0298bb00,
-	0xf4069eb8,
-	0x80fcf11e,
-	0x00f890fc,
-/* 0x00a4: wait */
-	0x80f990f9,
-	0xb62c87f0,
-	0x88cf0684,
-/* 0x00b1: wait_loop */
-	0x02eeb900,
-	0xb90421f4,
-	0xadfd02da,
-	0x06acb804,
-	0xf0150bf4,
-	0x94b62c97,
-	0x0099cf06,
-	0xb80298bb,
-	0x1ef4069b,
-/* 0x00d5: wait_done */
-	0xfc80fcdf,
-/* 0x00db: intr_watchdog */
-	0x9800f890,
-	0x96b003e9,
-	0x2a0bf400,
-	0xbb9a0a98,
-	0x1cf4029a,
-	0x01d7f00f,
-	0x02dd21f5,
-	0x0ef494bd,
-/* 0x00f9: intr_watchdog_next_time */
-	0x9b0a9815,
-	0xf400a6b0,
-	0x9ab8090b,
-	0x061cf406,
-/* 0x0108: intr_watchdog_next_time_set */
-/* 0x010b: intr_watchdog_next_proc */
-	0x809b0980,
-	0xe0b603e9,
-	0x68e6b158,
-	0xc61bf402,
-/* 0x011a: intr */
-	0x00f900f8,
-	0x80f904bd,
-	0xa0f990f9,
-	0xc0f9b0f9,
-	0xe0f9d0f9,
-	0xf7f0f0f9,
-	0x0188fe00,
-	0x87f180f9,
-	0x84b605d0,
-	0x0088cf06,
-	0xf10180b6,
-	0xb605d007,
-	0x08d00604,
-	0xf004bd00,
-	0x84b60887,
-	0x0088cf06,
-	0xf40289c4,
-	0x0080230b,
-	0x58e7f09b,
-	0x98db21f4,
-	0x96b09b09,
-	0x110bf400,
-	0xb63407f0,
-	0x09d00604,
-	0x8004bd00,
-/* 0x017e: intr_skip_watchdog */
-	0x89e49a09,
-	0x0bf40800,
-	0x8897f148,
-	0x0694b606,
-	0xc40099cf,
-	0x0bf4029a,
-	0xc0c7f12c,
-	0x06c4b604,
-	0xf900cccf,
-	0x48e7f1c0,
-	0x53e3f14f,
-	0x00d7f054,
-	0x034221f5,
-	0x07f1c0fc,
-	0x04b604c0,
-	0x000cd006,
-/* 0x01be: intr_subintr_skip_fifo */
-	0x07f104bd,
-	0x04b60688,
-	0x0009d006,
-/* 0x01ca: intr_skip_subintr */
-	0x89c404bd,
-	0x070bf420,
-	0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
-	0xf44089c4,
-	0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
-	0x07f0ffbf,
-	0x0604b604,
-	0xbd0008d0,
-	0xfe80fc04,
-	0xf0fc0088,
-	0xd0fce0fc,
-	0xb0fcc0fc,
-	0x90fca0fc,
-	0x00fc80fc,
-	0xf80032f4,
-/* 0x0205: ticks_from_ns */
-	0xf9c0f901,
-	0xcbd7f1b0,
-	0x00d3f000,
-	0x041321f5,
-	0x03e8ccec,
-	0xf400b4b0,
-	0xeeec120b,
-	0xd7f103e8,
-	0xd3f000cb,
-	0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
-	0x02ceb904,
-	0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
-	0xc0f900f8,
-	0xd7f1b0f9,
-	0xd3f000cb,
-	0x1321f500,
-	0x02ceb904,
-	0xf400b4b0,
-	0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
-	0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
-	0xd7f100f8,
-	0xd3f000cb,
-	0xecedff00,
-/* 0x0262: timer */
-	0x90f900f8,
-	0x32f480f9,
-	0x03f89810,
-	0xf40086b0,
-	0x84bd651c,
-	0xb63807f0,
-	0x08d00604,
-	0xf004bd00,
-	0x84b63487,
-	0x0088cf06,
-	0xbb9a0998,
-	0xe9bb0298,
-	0x03fe8000,
-	0xb60887f0,
-	0x88cf0684,
-	0x0284f000,
-	0xf0261bf4,
-	0x84b63487,
-	0x0088cf06,
-	0xf406e0b8,
-	0xe8b8090b,
-	0x111cf406,
-/* 0x02b8: timer_reset */
-	0xb63407f0,
-	0x0ed00604,
-	0x8004bd00,
-/* 0x02c6: timer_enable */
-	0x87f09a0e,
-	0x3807f001,
-	0xd00604b6,
-	0x04bd0008,
-/* 0x02d4: timer_done */
-	0xfc1031f4,
-	0xf890fc80,
-/* 0x02dd: send_proc */
-	0xf980f900,
-	0x05e89890,
-	0xf004e998,
-	0x89b80486,
-	0x2a0bf406,
-	0x940398c4,
-	0x80b60488,
-	0x008ebb18,
-	0x8000fa98,
-	0x8d80008a,
-	0x028c8001,
-	0xb6038b80,
-	0x94f00190,
-	0x04e98007,
-/* 0x0317: send_done */
-	0xfc0231f4,
-	0xf880fc90,
-/* 0x031d: find */
-	0xf080f900,
-	0x31f45887,
-/* 0x0325: find_loop */
-	0x008a9801,
-	0xf406aeb8,
-	0x80b6100b,
-	0x6886b158,
-	0xf01bf402,
-/* 0x033b: find_done */
-	0xb90132f4,
-	0x80fc028e,
-/* 0x0342: send */
-	0x21f500f8,
-	0x01f4031d,
-/* 0x034b: recv */
-	0xf900f897,
-	0x9880f990,
-	0xe99805e8,
-	0x0132f404,
-	0xf40689b8,
-	0x89c43d0b,
-	0x0180b603,
-	0x800784f0,
-	0xea9805e8,
-	0xfef0f902,
-	0xf0f9018f,
-	0x9402efb9,
-	0xe9bb0499,
-	0x18e0b600,
-	0x9803eb98,
-	0xed9802ec,
-	0x00ee9801,
-	0xf0fca5f9,
-	0xf400f8fe,
-	0xf0fc0131,
-/* 0x0398: recv_done */
-	0x90fc80fc,
-/* 0x039e: init */
-	0x17f100f8,
-	0x14b60108,
-	0x0011cf06,
-	0x010911e7,
-	0xfe0814b6,
-	0x17f10014,
-	0x13f000e0,
-	0x1c07f000,
-	0xd00604b6,
-	0x04bd0001,
-	0xf0ff17f0,
-	0x04b61407,
-	0x0001d006,
-	0x17f004bd,
-	0x0015f102,
-	0x1007f008,
-	0xd00604b6,
-	0x04bd0001,
-	0x011a17f1,
-	0xfe0013f0,
-	0x31f40010,
-	0x0117f010,
-	0xb63807f0,
-	0x01d00604,
-	0xf004bd00,
-/* 0x0402: init_proc */
-	0xf19858f7,
-	0x0016b001,
-	0xf9fa0bf4,
-	0x58f0b615,
-/* 0x0413: mulu32_32_64 */
-	0xf9f20ef4,
-	0xf920f910,
-	0x9540f930,
-	0xd29510e1,
-	0xbdc4bd10,
-	0xc0edffb4,
-	0xb9301dff,
-	0x34f10234,
-	0x34b6ffff,
-	0x1045b610,
-	0xbb00c3bb,
-	0xe2ff01b4,
-	0x0234b930,
-	0xffff34f1,
-	0xb61034b6,
-	0xc3bb1045,
-	0x01b4bb00,
-	0xbb3012ff,
-	0x40fc00b3,
-	0x20fc30fc,
-	0x00f810fc,
-/* 0x0464: host_send */
-	0x04b017f1,
-	0xcf0614b6,
-	0x27f10011,
-	0x24b604a0,
-	0x0022cf06,
-	0xf40612b8,
-	0x1ec4320b,
-	0x04ee9407,
-	0x0270e0b7,
-	0x9803eb98,
-	0xed9802ec,
-	0x00ee9801,
-	0x034221f5,
-	0xc40110b6,
-	0x07f10f1e,
-	0x04b604b0,
-	0x000ed006,
-	0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
-	0xf100f8ba,
-	0xf14e4917,
-	0xb8525413,
-	0x0bf406e1,
-/* 0x04bd: host_recv_wait */
-	0xcc17f1aa,
-	0x0614b604,
-	0xf10011cf,
-	0xb604c827,
-	0x22cf0624,
-	0x0816f000,
-	0xf40612b8,
-	0x23c4e60b,
-	0x0434b607,
-	0x02f030b7,
-	0x80033b80,
-	0x3d80023c,
-	0x003e8001,
-	0xf00120b6,
-	0x07f10f24,
-	0x04b604c8,
-	0x0002d006,
-	0x27f004bd,
-	0x0007f040,
-	0xd00604b6,
-	0x04bd0002,
-/* 0x0512: host_init */
-	0x17f100f8,
-	0x14b60080,
-	0x7015f110,
-	0xd007f102,
-	0x0604b604,
-	0xbd0001d0,
-	0x8017f104,
-	0x1014b600,
-	0x02f015f1,
-	0x04dc07f1,
-	0xd00604b6,
-	0x04bd0001,
-	0xf10117f0,
-	0xb604c407,
-	0x01d00604,
-	0xf804bd00,
-/* 0x0551: memx_func_enter */
-	0x1087f100,
-	0x028eb916,
-	0xb90421f4,
-	0x67f102d7,
-	0x63f1fffc,
-	0x76fdffff,
-	0x0267f104,
-	0x0576fd00,
-	0x70f980f9,
-	0xe0fcd0fc,
-	0xf03f21f4,
-	0x07f10467,
-	0x04b607e0,
-	0x0006d006,
-/* 0x058a: memx_func_enter_wait */
-	0x67f104bd,
-	0x64b607c0,
-	0x0066cf06,
-	0xf40464f0,
-	0x67f0f30b,
-	0x0664b62c,
-	0x800066cf,
-	0x00f8f106,
-/* 0x05a8: memx_func_leave */
-	0xb62c67f0,
-	0x66cf0664,
-	0xf2068000,
-	0xf10467f0,
-	0xb607e407,
-	0x06d00604,
-/* 0x05c3: memx_func_leave_wait */
-	0xf104bd00,
-	0xb607c067,
-	0x66cf0664,
-	0x0464f000,
-	0xf1f31bf4,
-	0xb9161087,
-	0x21f4028e,
-	0x02d7b904,
-	0xffcc67f1,
-	0xffff63f1,
-	0xf90476fd,
-	0xfc70f980,
-	0xf4e0fcd0,
-	0x00f83f21,
-/* 0x05f8: memx_func_wait_vblank */
-	0xb0001698,
-	0x0bf40066,
-	0x0166b013,
-	0xf4060bf4,
-/* 0x060a: memx_func_wait_vblank_head1 */
-	0x77f12e0e,
-	0x0ef40020,
-/* 0x0611: memx_func_wait_vblank_head0 */
-	0x0877f107,
-/* 0x0615: memx_func_wait_vblank_0 */
-	0xc467f100,
-	0x0664b607,
-	0xfd0066cf,
-	0x1bf40467,
-/* 0x0625: memx_func_wait_vblank_1 */
-	0xc467f1f3,
-	0x0664b607,
-	0xfd0066cf,
-	0x0bf40467,
-/* 0x0635: memx_func_wait_vblank_fini */
-	0x0410b6f3,
-/* 0x063a: memx_func_wr32 */
-	0x169800f8,
-	0x01159800,
-	0xf90810b6,
-	0xfc50f960,
-	0xf4e0fcd0,
-	0x42b63f21,
-	0xe91bf402,
-/* 0x0656: memx_func_wait */
-	0x87f000f8,
-	0x0684b62c,
-	0x980088cf,
-	0x1d98001e,
-	0x021c9801,
-	0xb6031b98,
-	0x21f41010,
-/* 0x0673: memx_func_delay */
-	0x9800f8a4,
-	0x10b6001e,
-	0x7f21f404,
-/* 0x067e: memx_func_train */
-	0x57f100f8,
-	0x77f10003,
-	0x97f10000,
-	0x93f00000,
-	0x029eb970,
-	0xb90421f4,
-	0xe7f102d8,
-	0x21f42710,
-/* 0x069d: memx_func_train_loop_outer */
-	0x0158e07f,
-	0x0083f101,
-	0xe097f102,
-	0x1193f011,
-	0x80f990f9,
-	0xe0fcd0fc,
-	0xf93f21f4,
-	0x0067f150,
-/* 0x06bd: memx_func_train_loop_inner */
-	0x1187f100,
-	0x9068ff11,
-	0xfd109894,
-	0x97f10589,
-	0x93f00720,
-	0xf990f910,
-	0xfcd0fc80,
-	0x3f21f4e0,
-	0x008097f1,
-	0xb91093f0,
-	0x21f4029e,
-	0x02d8b904,
-	0xf92088c5,
-	0xfc80f990,
-	0xf4e0fcd0,
-	0x97f13f21,
-	0x93f0053c,
-	0x0287f110,
-	0x0083f130,
-	0xf990f980,
-	0xfcd0fc80,
-	0x3f21f4e0,
-	0x0560e7f1,
-	0xf110e3f0,
-	0xf10000d7,
-	0x908000d3,
-	0xb7f100dc,
-	0xb3f08480,
-	0xa421f41e,
-	0x000057f1,
-	0xffff97f1,
-	0x830093f1,
-/* 0x073c: memx_func_train_loop_4x */
-	0x0080a7f1,
-	0xb910a3f0,
-	0x21f402ae,
-	0x02d8b904,
-	0xffdfb7f1,
-	0xffffb3f1,
-	0xf9048bfd,
-	0xfc80f9a0,
-	0xf4e0fcd0,
-	0xa7f13f21,
-	0xa3f0053c,
-	0x0287f110,
-	0x0083f130,
-	0xf9a0f980,
-	0xfcd0fc80,
-	0x3f21f4e0,
-	0x0560e7f1,
-	0xf110e3f0,
-	0xf10000d7,
-	0xb98000d3,
-	0xb7f102dc,
-	0xb3f02710,
-	0xa421f400,
-	0xf402eeb9,
-	0xddb90421,
-	0x949dff02,
-	0x700150b6,
-	0x1ef40456,
-	0xcc7aa092,
-	0x00a9800b,
-	0xb60160b6,
-	0x66700470,
-	0x001ef510,
-	0xb650fcff,
-	0x56700150,
-	0xd41ef507,
-/* 0x07cf: memx_exec */
-	0xf900f8fe,
-	0xb9d0f9e0,
-	0xb2b902c1,
-/* 0x07d9: memx_exec_next */
-	0x00139802,
-	0xe70410b6,
-	0xe701f034,
-	0xb601e033,
-	0x30f00132,
-	0xde35980c,
-	0x12b855f9,
-	0xe41ef406,
-	0x98f10b98,
-	0xcbbbf20c,
-	0xc4b7f102,
-	0x06b4b607,
-	0xfc00bbcf,
-	0xf5e0fcd0,
-	0xf8034221,
-/* 0x0815: memx_info */
-	0x01c67000,
-/* 0x081b: memx_info_data */
-	0xf10e0bf4,
-	0xf103ccc7,
-	0xf40800b7,
-/* 0x0826: memx_info_train */
-	0xc7f10b0e,
-	0xb7f10bcc,
-/* 0x082e: memx_info_send */
-	0x21f50100,
-	0x00f80342,
-/* 0x0834: memx_recv */
-	0xf401d6b0,
-	0xd6b0980b,
-	0xd80bf400,
-/* 0x0842: memx_init */
-	0x00f800f8,
-/* 0x0844: perf_recv */
-/* 0x0846: perf_init */
-	0x00f800f8,
-/* 0x0848: i2c_drive_scl */
-	0xf40036b0,
-	0x07f1110b,
-	0x04b607e0,
-	0x0001d006,
-	0x00f804bd,
-/* 0x085c: i2c_drive_scl_lo */
-	0x07e407f1,
-	0xd00604b6,
-	0x04bd0001,
-/* 0x086a: i2c_drive_sda */
-	0x36b000f8,
-	0x110bf400,
-	0x07e007f1,
-	0xd00604b6,
-	0x04bd0002,
-/* 0x087e: i2c_drive_sda_lo */
-	0x07f100f8,
-	0x04b607e4,
-	0x0002d006,
-	0x00f804bd,
-/* 0x088c: i2c_sense_scl */
-	0xf10132f4,
-	0xb607c437,
-	0x33cf0634,
-	0x0431fd00,
-	0xf4060bf4,
-/* 0x08a2: i2c_sense_scl_done */
-	0x00f80131,
-/* 0x08a4: i2c_sense_sda */
-	0xf10132f4,
-	0xb607c437,
-	0x33cf0634,
-	0x0432fd00,
-	0xf4060bf4,
-/* 0x08ba: i2c_sense_sda_done */
-	0x00f80131,
-/* 0x08bc: i2c_raise_scl */
-	0x47f140f9,
-	0x37f00898,
-	0x4821f501,
-/* 0x08c9: i2c_raise_scl_wait */
-	0xe8e7f108,
-	0x7f21f403,
-	0x088c21f5,
-	0xb60901f4,
-	0x1bf40142,
-/* 0x08dd: i2c_raise_scl_done */
-	0xf840fcef,
-/* 0x08e1: i2c_start */
-	0x8c21f500,
-	0x0d11f408,
-	0x08a421f5,
-	0xf40611f4,
-/* 0x08f2: i2c_start_rep */
-	0x37f0300e,
-	0x4821f500,
-	0x0137f008,
-	0x086a21f5,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0xbc21f550,
-	0x0464b608,
-/* 0x091f: i2c_start_send */
-	0xf01f11f4,
-	0x21f50037,
-	0xe7f1086a,
-	0x21f41388,
-	0x0037f07f,
-	0x084821f5,
-	0x1388e7f1,
-/* 0x093b: i2c_start_out */
-	0xf87f21f4,
-/* 0x093d: i2c_stop */
-	0x0037f000,
-	0x084821f5,
-	0xf50037f0,
-	0xf1086a21,
-	0xf403e8e7,
-	0x37f07f21,
-	0x4821f501,
-	0x88e7f108,
-	0x7f21f413,
-	0xf50137f0,
-	0xf1086a21,
-	0xf41388e7,
-	0x00f87f21,
-/* 0x0970: i2c_bitw */
-	0x086a21f5,
-	0x03e8e7f1,
-	0xbb7f21f4,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x08bc21f5,
-	0xf40464b6,
-	0xe7f11811,
-	0x21f41388,
-	0x0037f07f,
-	0x084821f5,
-	0x1388e7f1,
-/* 0x09af: i2c_bitw_out */
-	0xf87f21f4,
-/* 0x09b1: i2c_bitr */
-	0x0137f000,
-	0x086a21f5,
-	0x03e8e7f1,
-	0xbb7f21f4,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x08bc21f5,
-	0xf40464b6,
-	0x21f51b11,
-	0x37f008a4,
-	0x4821f500,
-	0x88e7f108,
-	0x7f21f413,
-	0xf4013cf0,
-/* 0x09f6: i2c_bitr_done */
-	0x00f80131,
-/* 0x09f8: i2c_get_byte */
-	0xf00057f0,
-/* 0x09fe: i2c_get_byte_next */
-	0x54b60847,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b609b1,
-	0x2b11f404,
-	0xb60553fd,
-	0x1bf40142,
-	0x0137f0d8,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x7021f550,
-	0x0464b609,
-/* 0x0a48: i2c_get_byte_done */
-/* 0x0a4a: i2c_put_byte */
-	0x47f000f8,
-/* 0x0a4d: i2c_put_byte_next */
-	0x0142b608,
-	0xbb3854ff,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x097021f5,
-	0xf40464b6,
-	0x46b03411,
-	0xd81bf400,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0xb121f550,
-	0x0464b609,
-	0xbb0f11f4,
-	0x36b00076,
-	0x061bf401,
-/* 0x0aa3: i2c_put_byte_done */
-	0xf80132f4,
-/* 0x0aa5: i2c_addr */
-	0x0076bb00,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b608e1,
-	0x2911f404,
-	0x012ec3e7,
-	0xfd0134b6,
-	0x76bb0553,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb60a4a21,
-/* 0x0aea: i2c_addr_done */
-	0x00f80464,
-/* 0x0aec: i2c_acquire_addr */
-	0xb6f8cec7,
-	0xe0b702e4,
-	0xee980d1c,
-/* 0x0afb: i2c_acquire */
-	0xf500f800,
-	0xf40aec21,
-	0xd9f00421,
-	0x3f21f403,
-/* 0x0b0a: i2c_release */
-	0x21f500f8,
-	0x21f40aec,
-	0x03daf004,
-	0xf83f21f4,
-/* 0x0b19: i2c_recv */
-	0x0132f400,
-	0xb6f8c1c7,
-	0x16b00214,
-	0x3a1ff528,
-	0xf413a001,
-	0x0032980c,
-	0x0ccc13a0,
-	0xf4003198,
-	0xd0f90231,
-	0xd0f9e0f9,
-	0x000067f1,
-	0x100063f1,
-	0xbb016792,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0afb21f5,
-	0xfc0464b6,
-	0x00d6b0d0,
-	0x00b31bf5,
-	0xbb0057f0,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0aa521f5,
-	0xf50464b6,
-	0xc700d011,
-	0x76bbe0c5,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb60a4a21,
-	0x11f50464,
-	0x57f000ad,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b60aa5,
-	0x8a11f504,
-	0x0076bb00,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b609f8,
-	0x6a11f404,
-	0xbbe05bcb,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x093d21f5,
-	0xb90464b6,
-	0x74bd025b,
-/* 0x0c1f: i2c_recv_not_rd08 */
-	0xb0430ef4,
-	0x1bf401d6,
-	0x0057f03d,
-	0x0aa521f5,
-	0xc73311f4,
-	0x21f5e0c5,
-	0x11f40a4a,
-	0x0057f029,
-	0x0aa521f5,
-	0xc71f11f4,
-	0x21f5e0b5,
-	0x11f40a4a,
-	0x3d21f515,
-	0xc774bd09,
-	0x1bf408c5,
-	0x0232f409,
-/* 0x0c5f: i2c_recv_not_wr08 */
-/* 0x0c5f: i2c_recv_done */
-	0xc7030ef4,
-	0x21f5f8ce,
-	0xe0fc0b0a,
-	0x12f4d0fc,
-	0x027cb90a,
-	0x034221f5,
-/* 0x0c74: i2c_recv_exit */
-/* 0x0c76: i2c_init */
-	0x00f800f8,
-/* 0x0c78: test_recv */
-	0x05d817f1,
-	0xcf0614b6,
-	0x10b60011,
-	0xd807f101,
-	0x0604b605,
-	0xbd0001d0,
-	0x00e7f104,
-	0x4fe3f1d9,
-	0x6221f513,
-/* 0x0c9f: test_init */
-	0xf100f802,
-	0xf50800e7,
-	0xf8026221,
-/* 0x0ca9: idle_recv */
-/* 0x0cab: idle */
-	0xf400f800,
-	0x17f10031,
-	0x14b605d4,
-	0x0011cf06,
-	0xf10110b6,
-	0xb605d407,
-	0x01d00604,
-/* 0x0cc7: idle_loop */
-	0xf004bd00,
-	0x32f45817,
-/* 0x0ccd: idle_proc */
-/* 0x0ccd: idle_proc_exec */
-	0xb910f902,
-	0x21f5021e,
-	0x10fc034b,
-	0xf40911f4,
-	0x0ef40231,
-/* 0x0ce1: idle_proc_next */
-	0x5810b6ef,
-	0xf4061fb8,
-	0x02f4e61b,
-	0x0028f4dd,
-	0x00bb0ef4,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
deleted file mode 100644
index 21bf8cc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GF100
-#define HW_TICKS_PER_US 203 // should be 202.5
-
-//#define NVKM_FALCON_PC24
-//#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nvc0_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nvc0_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
deleted file mode 100644
index 90221d9..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
+++ /dev/null
@@ -1,1865 +0,0 @@
-uint32_t nvc0_pwr_data[] = {
-/* 0x0000: proc_kern */
-	0x52544e49,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: proc_list_head */
-	0x54534f48,
-	0x00000512,
-	0x000004af,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x584d454d,
-	0x0000075e,
-	0x00000750,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x46524550,
-	0x00000762,
-	0x00000760,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x5f433249,
-	0x00000b92,
-	0x00000a35,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x54534554,
-	0x00000bbb,
-	0x00000b94,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x454c4449,
-	0x00000bc7,
-	0x00000bc5,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
-	0x00000000,
-/* 0x026c: time_next */
-	0x00000000,
-/* 0x0270: fifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x02f0: rfifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0370: memx_func_head */
-	0x00000001,
-	0x00000000,
-	0x00000551,
-/* 0x037c: memx_func_next */
-	0x00000002,
-	0x00000000,
-	0x000005db,
-	0x00000003,
-	0x00000002,
-	0x000006a5,
-	0x00040004,
-	0x00000000,
-	0x000006c1,
-	0x00010005,
-	0x00000000,
-	0x000006de,
-	0x00010006,
-	0x00000000,
-	0x00000663,
-	0x00000007,
-	0x00000000,
-	0x000006e9,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
-	0x00000000,
-/* 0x03c8: memx_ts_end */
-	0x00000000,
-/* 0x03cc: memx_data_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
-	0x00001000,
-	0x00004000,
-	0x00010000,
-	0x00000100,
-	0x00040000,
-	0x00100000,
-	0x00400000,
-	0x01000000,
-	0x04000000,
-	0x10000000,
-/* 0x0cf4: i2c_sda_map */
-	0x00002000,
-	0x00008000,
-	0x00020000,
-	0x00000200,
-	0x00080000,
-	0x00200000,
-	0x00800000,
-	0x02000000,
-	0x08000000,
-	0x20000000,
-/* 0x0d1c: i2c_ctrl */
-	0x0000e138,
-	0x0000e150,
-	0x0000e168,
-	0x0000e180,
-	0x0000e254,
-	0x0000e274,
-	0x0000e764,
-	0x0000e780,
-	0x0000e79c,
-	0x0000e7b8,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nvc0_pwr_code[] = {
-	0x039e0ef5,
-/* 0x0004: rd32 */
-	0x07a007f1,
-	0xd00604b6,
-	0x04bd000e,
-	0xf001d7f0,
-	0x07f101d3,
-	0x04b607ac,
-	0x000dd006,
-/* 0x0022: rd32_wait */
-	0xd7f104bd,
-	0xd4b607ac,
-	0x00ddcf06,
-	0x7000d4f1,
-	0xf1f21bf4,
-	0xb607a4d7,
-	0xddcf06d4,
-/* 0x003f: wr32 */
-	0xf100f800,
-	0xb607a007,
-	0x0ed00604,
-	0xf104bd00,
-	0xb607a407,
-	0x0dd00604,
-	0xf004bd00,
-	0xd5f002d7,
-	0x01d3f0f0,
-	0x07ac07f1,
-	0xd00604b6,
-	0x04bd000d,
-/* 0x006c: wr32_wait */
-	0x07acd7f1,
-	0xcf06d4b6,
-	0xd4f100dd,
-	0x1bf47000,
-/* 0x007f: nsec */
-	0xf900f8f2,
-	0xf080f990,
-	0x84b62c87,
-	0x0088cf06,
-/* 0x008c: nsec_loop */
-	0xb62c97f0,
-	0x99cf0694,
-	0x0298bb00,
-	0xf4069eb8,
-	0x80fcf11e,
-	0x00f890fc,
-/* 0x00a4: wait */
-	0x80f990f9,
-	0xb62c87f0,
-	0x88cf0684,
-/* 0x00b1: wait_loop */
-	0x02eeb900,
-	0xb90421f4,
-	0xadfd02da,
-	0x06acb804,
-	0xf0150bf4,
-	0x94b62c97,
-	0x0099cf06,
-	0xb80298bb,
-	0x1ef4069b,
-/* 0x00d5: wait_done */
-	0xfc80fcdf,
-/* 0x00db: intr_watchdog */
-	0x9800f890,
-	0x96b003e9,
-	0x2a0bf400,
-	0xbb9a0a98,
-	0x1cf4029a,
-	0x01d7f00f,
-	0x02dd21f5,
-	0x0ef494bd,
-/* 0x00f9: intr_watchdog_next_time */
-	0x9b0a9815,
-	0xf400a6b0,
-	0x9ab8090b,
-	0x061cf406,
-/* 0x0108: intr_watchdog_next_time_set */
-/* 0x010b: intr_watchdog_next_proc */
-	0x809b0980,
-	0xe0b603e9,
-	0x68e6b158,
-	0xc61bf402,
-/* 0x011a: intr */
-	0x00f900f8,
-	0x80f904bd,
-	0xa0f990f9,
-	0xc0f9b0f9,
-	0xe0f9d0f9,
-	0xf7f0f0f9,
-	0x0188fe00,
-	0x87f180f9,
-	0x84b605d0,
-	0x0088cf06,
-	0xf10180b6,
-	0xb605d007,
-	0x08d00604,
-	0xf004bd00,
-	0x84b60887,
-	0x0088cf06,
-	0xf40289c4,
-	0x0080230b,
-	0x58e7f09b,
-	0x98db21f4,
-	0x96b09b09,
-	0x110bf400,
-	0xb63407f0,
-	0x09d00604,
-	0x8004bd00,
-/* 0x017e: intr_skip_watchdog */
-	0x89e49a09,
-	0x0bf40800,
-	0x8897f148,
-	0x0694b606,
-	0xc40099cf,
-	0x0bf4029a,
-	0xc0c7f12c,
-	0x06c4b604,
-	0xf900cccf,
-	0x48e7f1c0,
-	0x53e3f14f,
-	0x00d7f054,
-	0x034221f5,
-	0x07f1c0fc,
-	0x04b604c0,
-	0x000cd006,
-/* 0x01be: intr_subintr_skip_fifo */
-	0x07f104bd,
-	0x04b60688,
-	0x0009d006,
-/* 0x01ca: intr_skip_subintr */
-	0x89c404bd,
-	0x070bf420,
-	0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
-	0xf44089c4,
-	0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
-	0x07f0ffbf,
-	0x0604b604,
-	0xbd0008d0,
-	0xfe80fc04,
-	0xf0fc0088,
-	0xd0fce0fc,
-	0xb0fcc0fc,
-	0x90fca0fc,
-	0x00fc80fc,
-	0xf80032f4,
-/* 0x0205: ticks_from_ns */
-	0xf9c0f901,
-	0xcbd7f1b0,
-	0x00d3f000,
-	0x041321f5,
-	0x03e8ccec,
-	0xf400b4b0,
-	0xeeec120b,
-	0xd7f103e8,
-	0xd3f000cb,
-	0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
-	0x02ceb904,
-	0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
-	0xc0f900f8,
-	0xd7f1b0f9,
-	0xd3f000cb,
-	0x1321f500,
-	0x02ceb904,
-	0xf400b4b0,
-	0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
-	0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
-	0xd7f100f8,
-	0xd3f000cb,
-	0xecedff00,
-/* 0x0262: timer */
-	0x90f900f8,
-	0x32f480f9,
-	0x03f89810,
-	0xf40086b0,
-	0x84bd651c,
-	0xb63807f0,
-	0x08d00604,
-	0xf004bd00,
-	0x84b63487,
-	0x0088cf06,
-	0xbb9a0998,
-	0xe9bb0298,
-	0x03fe8000,
-	0xb60887f0,
-	0x88cf0684,
-	0x0284f000,
-	0xf0261bf4,
-	0x84b63487,
-	0x0088cf06,
-	0xf406e0b8,
-	0xe8b8090b,
-	0x111cf406,
-/* 0x02b8: timer_reset */
-	0xb63407f0,
-	0x0ed00604,
-	0x8004bd00,
-/* 0x02c6: timer_enable */
-	0x87f09a0e,
-	0x3807f001,
-	0xd00604b6,
-	0x04bd0008,
-/* 0x02d4: timer_done */
-	0xfc1031f4,
-	0xf890fc80,
-/* 0x02dd: send_proc */
-	0xf980f900,
-	0x05e89890,
-	0xf004e998,
-	0x89b80486,
-	0x2a0bf406,
-	0x940398c4,
-	0x80b60488,
-	0x008ebb18,
-	0x8000fa98,
-	0x8d80008a,
-	0x028c8001,
-	0xb6038b80,
-	0x94f00190,
-	0x04e98007,
-/* 0x0317: send_done */
-	0xfc0231f4,
-	0xf880fc90,
-/* 0x031d: find */
-	0xf080f900,
-	0x31f45887,
-/* 0x0325: find_loop */
-	0x008a9801,
-	0xf406aeb8,
-	0x80b6100b,
-	0x6886b158,
-	0xf01bf402,
-/* 0x033b: find_done */
-	0xb90132f4,
-	0x80fc028e,
-/* 0x0342: send */
-	0x21f500f8,
-	0x01f4031d,
-/* 0x034b: recv */
-	0xf900f897,
-	0x9880f990,
-	0xe99805e8,
-	0x0132f404,
-	0xf40689b8,
-	0x89c43d0b,
-	0x0180b603,
-	0x800784f0,
-	0xea9805e8,
-	0xfef0f902,
-	0xf0f9018f,
-	0x9402efb9,
-	0xe9bb0499,
-	0x18e0b600,
-	0x9803eb98,
-	0xed9802ec,
-	0x00ee9801,
-	0xf0fca5f9,
-	0xf400f8fe,
-	0xf0fc0131,
-/* 0x0398: recv_done */
-	0x90fc80fc,
-/* 0x039e: init */
-	0x17f100f8,
-	0x14b60108,
-	0x0011cf06,
-	0x010911e7,
-	0xfe0814b6,
-	0x17f10014,
-	0x13f000e0,
-	0x1c07f000,
-	0xd00604b6,
-	0x04bd0001,
-	0xf0ff17f0,
-	0x04b61407,
-	0x0001d006,
-	0x17f004bd,
-	0x0015f102,
-	0x1007f008,
-	0xd00604b6,
-	0x04bd0001,
-	0x011a17f1,
-	0xfe0013f0,
-	0x31f40010,
-	0x0117f010,
-	0xb63807f0,
-	0x01d00604,
-	0xf004bd00,
-/* 0x0402: init_proc */
-	0xf19858f7,
-	0x0016b001,
-	0xf9fa0bf4,
-	0x58f0b615,
-/* 0x0413: mulu32_32_64 */
-	0xf9f20ef4,
-	0xf920f910,
-	0x9540f930,
-	0xd29510e1,
-	0xbdc4bd10,
-	0xc0edffb4,
-	0xb9301dff,
-	0x34f10234,
-	0x34b6ffff,
-	0x1045b610,
-	0xbb00c3bb,
-	0xe2ff01b4,
-	0x0234b930,
-	0xffff34f1,
-	0xb61034b6,
-	0xc3bb1045,
-	0x01b4bb00,
-	0xbb3012ff,
-	0x40fc00b3,
-	0x20fc30fc,
-	0x00f810fc,
-/* 0x0464: host_send */
-	0x04b017f1,
-	0xcf0614b6,
-	0x27f10011,
-	0x24b604a0,
-	0x0022cf06,
-	0xf40612b8,
-	0x1ec4320b,
-	0x04ee9407,
-	0x0270e0b7,
-	0x9803eb98,
-	0xed9802ec,
-	0x00ee9801,
-	0x034221f5,
-	0xc40110b6,
-	0x07f10f1e,
-	0x04b604b0,
-	0x000ed006,
-	0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
-	0xf100f8ba,
-	0xf14e4917,
-	0xb8525413,
-	0x0bf406e1,
-/* 0x04bd: host_recv_wait */
-	0xcc17f1aa,
-	0x0614b604,
-	0xf10011cf,
-	0xb604c827,
-	0x22cf0624,
-	0x0816f000,
-	0xf40612b8,
-	0x23c4e60b,
-	0x0434b607,
-	0x02f030b7,
-	0x80033b80,
-	0x3d80023c,
-	0x003e8001,
-	0xf00120b6,
-	0x07f10f24,
-	0x04b604c8,
-	0x0002d006,
-	0x27f004bd,
-	0x0007f040,
-	0xd00604b6,
-	0x04bd0002,
-/* 0x0512: host_init */
-	0x17f100f8,
-	0x14b60080,
-	0x7015f110,
-	0xd007f102,
-	0x0604b604,
-	0xbd0001d0,
-	0x8017f104,
-	0x1014b600,
-	0x02f015f1,
-	0x04dc07f1,
-	0xd00604b6,
-	0x04bd0001,
-	0xf10117f0,
-	0xb604c407,
-	0x01d00604,
-	0xf804bd00,
-/* 0x0551: memx_func_enter */
-	0x2067f100,
-	0x5d77f116,
-	0xff73f1f5,
-	0x026eb9ff,
-	0xb90421f4,
-	0x87fd02d8,
-	0xf960f904,
-	0xfcd0fc80,
-	0x3f21f4e0,
-	0xfffe77f1,
-	0xffff73f1,
-	0xf4026eb9,
-	0xd8b90421,
-	0x0487fd02,
-	0x80f960f9,
-	0xe0fcd0fc,
-	0xf13f21f4,
-	0xb926f067,
-	0x21f4026e,
-	0x02d8b904,
-	0xf90487fd,
-	0xfc80f960,
-	0xf4e0fcd0,
-	0x67f03f21,
-	0xe007f104,
-	0x0604b607,
-	0xbd0006d0,
-/* 0x05bd: memx_func_enter_wait */
-	0xc067f104,
-	0x0664b607,
-	0xf00066cf,
-	0x0bf40464,
-	0x2c67f0f3,
-	0xcf0664b6,
-	0x06800066,
-/* 0x05db: memx_func_leave */
-	0xf000f8f1,
-	0x64b62c67,
-	0x0066cf06,
-	0xf0f20680,
-	0x07f10467,
-	0x04b607e4,
-	0x0006d006,
-/* 0x05f6: memx_func_leave_wait */
-	0x67f104bd,
-	0x64b607c0,
-	0x0066cf06,
-	0xf40464f0,
-	0x67f1f31b,
-	0x77f126f0,
-	0x73f00001,
-	0x026eb900,
-	0xb90421f4,
-	0x87fd02d8,
-	0xf960f905,
-	0xfcd0fc80,
-	0x3f21f4e0,
-	0x162067f1,
-	0xf4026eb9,
-	0xd8b90421,
-	0x0587fd02,
-	0x80f960f9,
-	0xe0fcd0fc,
-	0xf13f21f4,
-	0xf00aa277,
-	0x6eb90073,
-	0x0421f402,
-	0xfd02d8b9,
-	0x60f90587,
-	0xd0fc80f9,
-	0x21f4e0fc,
-/* 0x0663: memx_func_wait_vblank */
-	0x9800f83f,
-	0x66b00016,
-	0x130bf400,
-	0xf40166b0,
-	0x0ef4060b,
-/* 0x0675: memx_func_wait_vblank_head1 */
-	0x2077f12e,
-	0x070ef400,
-/* 0x067c: memx_func_wait_vblank_head0 */
-	0x000877f1,
-/* 0x0680: memx_func_wait_vblank_0 */
-	0x07c467f1,
-	0xcf0664b6,
-	0x67fd0066,
-	0xf31bf404,
-/* 0x0690: memx_func_wait_vblank_1 */
-	0x07c467f1,
-	0xcf0664b6,
-	0x67fd0066,
-	0xf30bf404,
-/* 0x06a0: memx_func_wait_vblank_fini */
-	0xf80410b6,
-/* 0x06a5: memx_func_wr32 */
-	0x00169800,
-	0xb6011598,
-	0x60f90810,
-	0xd0fc50f9,
-	0x21f4e0fc,
-	0x0242b63f,
-	0xf8e91bf4,
-/* 0x06c1: memx_func_wait */
-	0x2c87f000,
-	0xcf0684b6,
-	0x1e980088,
-	0x011d9800,
-	0x98021c98,
-	0x10b6031b,
-	0xa421f410,
-/* 0x06de: memx_func_delay */
-	0x1e9800f8,
-	0x0410b600,
-	0xf87f21f4,
-/* 0x06e9: memx_func_train */
-/* 0x06eb: memx_exec */
-	0xf900f800,
-	0xb9d0f9e0,
-	0xb2b902c1,
-/* 0x06f5: memx_exec_next */
-	0x00139802,
-	0xe70410b6,
-	0xe701f034,
-	0xb601e033,
-	0x30f00132,
-	0xde35980c,
-	0x12b855f9,
-	0xe41ef406,
-	0x98f10b98,
-	0xcbbbf20c,
-	0xc4b7f102,
-	0x06b4b607,
-	0xfc00bbcf,
-	0xf5e0fcd0,
-	0xf8034221,
-/* 0x0731: memx_info */
-	0x01c67000,
-/* 0x0737: memx_info_data */
-	0xf10e0bf4,
-	0xf103ccc7,
-	0xf40800b7,
-/* 0x0742: memx_info_train */
-	0xc7f10b0e,
-	0xb7f10bcc,
-/* 0x074a: memx_info_send */
-	0x21f50100,
-	0x00f80342,
-/* 0x0750: memx_recv */
-	0xf401d6b0,
-	0xd6b0980b,
-	0xd80bf400,
-/* 0x075e: memx_init */
-	0x00f800f8,
-/* 0x0760: perf_recv */
-/* 0x0762: perf_init */
-	0x00f800f8,
-/* 0x0764: i2c_drive_scl */
-	0xf40036b0,
-	0x07f1110b,
-	0x04b607e0,
-	0x0001d006,
-	0x00f804bd,
-/* 0x0778: i2c_drive_scl_lo */
-	0x07e407f1,
-	0xd00604b6,
-	0x04bd0001,
-/* 0x0786: i2c_drive_sda */
-	0x36b000f8,
-	0x110bf400,
-	0x07e007f1,
-	0xd00604b6,
-	0x04bd0002,
-/* 0x079a: i2c_drive_sda_lo */
-	0x07f100f8,
-	0x04b607e4,
-	0x0002d006,
-	0x00f804bd,
-/* 0x07a8: i2c_sense_scl */
-	0xf10132f4,
-	0xb607c437,
-	0x33cf0634,
-	0x0431fd00,
-	0xf4060bf4,
-/* 0x07be: i2c_sense_scl_done */
-	0x00f80131,
-/* 0x07c0: i2c_sense_sda */
-	0xf10132f4,
-	0xb607c437,
-	0x33cf0634,
-	0x0432fd00,
-	0xf4060bf4,
-/* 0x07d6: i2c_sense_sda_done */
-	0x00f80131,
-/* 0x07d8: i2c_raise_scl */
-	0x47f140f9,
-	0x37f00898,
-	0x6421f501,
-/* 0x07e5: i2c_raise_scl_wait */
-	0xe8e7f107,
-	0x7f21f403,
-	0x07a821f5,
-	0xb60901f4,
-	0x1bf40142,
-/* 0x07f9: i2c_raise_scl_done */
-	0xf840fcef,
-/* 0x07fd: i2c_start */
-	0xa821f500,
-	0x0d11f407,
-	0x07c021f5,
-	0xf40611f4,
-/* 0x080e: i2c_start_rep */
-	0x37f0300e,
-	0x6421f500,
-	0x0137f007,
-	0x078621f5,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0xd821f550,
-	0x0464b607,
-/* 0x083b: i2c_start_send */
-	0xf01f11f4,
-	0x21f50037,
-	0xe7f10786,
-	0x21f41388,
-	0x0037f07f,
-	0x076421f5,
-	0x1388e7f1,
-/* 0x0857: i2c_start_out */
-	0xf87f21f4,
-/* 0x0859: i2c_stop */
-	0x0037f000,
-	0x076421f5,
-	0xf50037f0,
-	0xf1078621,
-	0xf403e8e7,
-	0x37f07f21,
-	0x6421f501,
-	0x88e7f107,
-	0x7f21f413,
-	0xf50137f0,
-	0xf1078621,
-	0xf41388e7,
-	0x00f87f21,
-/* 0x088c: i2c_bitw */
-	0x078621f5,
-	0x03e8e7f1,
-	0xbb7f21f4,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x07d821f5,
-	0xf40464b6,
-	0xe7f11811,
-	0x21f41388,
-	0x0037f07f,
-	0x076421f5,
-	0x1388e7f1,
-/* 0x08cb: i2c_bitw_out */
-	0xf87f21f4,
-/* 0x08cd: i2c_bitr */
-	0x0137f000,
-	0x078621f5,
-	0x03e8e7f1,
-	0xbb7f21f4,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x07d821f5,
-	0xf40464b6,
-	0x21f51b11,
-	0x37f007c0,
-	0x6421f500,
-	0x88e7f107,
-	0x7f21f413,
-	0xf4013cf0,
-/* 0x0912: i2c_bitr_done */
-	0x00f80131,
-/* 0x0914: i2c_get_byte */
-	0xf00057f0,
-/* 0x091a: i2c_get_byte_next */
-	0x54b60847,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b608cd,
-	0x2b11f404,
-	0xb60553fd,
-	0x1bf40142,
-	0x0137f0d8,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x8c21f550,
-	0x0464b608,
-/* 0x0964: i2c_get_byte_done */
-/* 0x0966: i2c_put_byte */
-	0x47f000f8,
-/* 0x0969: i2c_put_byte_next */
-	0x0142b608,
-	0xbb3854ff,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x088c21f5,
-	0xf40464b6,
-	0x46b03411,
-	0xd81bf400,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0xcd21f550,
-	0x0464b608,
-	0xbb0f11f4,
-	0x36b00076,
-	0x061bf401,
-/* 0x09bf: i2c_put_byte_done */
-	0xf80132f4,
-/* 0x09c1: i2c_addr */
-	0x0076bb00,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b607fd,
-	0x2911f404,
-	0x012ec3e7,
-	0xfd0134b6,
-	0x76bb0553,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb6096621,
-/* 0x0a06: i2c_addr_done */
-	0x00f80464,
-/* 0x0a08: i2c_acquire_addr */
-	0xb6f8cec7,
-	0xe0b702e4,
-	0xee980d1c,
-/* 0x0a17: i2c_acquire */
-	0xf500f800,
-	0xf40a0821,
-	0xd9f00421,
-	0x3f21f403,
-/* 0x0a26: i2c_release */
-	0x21f500f8,
-	0x21f40a08,
-	0x03daf004,
-	0xf83f21f4,
-/* 0x0a35: i2c_recv */
-	0x0132f400,
-	0xb6f8c1c7,
-	0x16b00214,
-	0x3a1ff528,
-	0xf413a001,
-	0x0032980c,
-	0x0ccc13a0,
-	0xf4003198,
-	0xd0f90231,
-	0xd0f9e0f9,
-	0x000067f1,
-	0x100063f1,
-	0xbb016792,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x0a1721f5,
-	0xfc0464b6,
-	0x00d6b0d0,
-	0x00b31bf5,
-	0xbb0057f0,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x09c121f5,
-	0xf50464b6,
-	0xc700d011,
-	0x76bbe0c5,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb6096621,
-	0x11f50464,
-	0x57f000ad,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b609c1,
-	0x8a11f504,
-	0x0076bb00,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b60914,
-	0x6a11f404,
-	0xbbe05bcb,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x085921f5,
-	0xb90464b6,
-	0x74bd025b,
-/* 0x0b3b: i2c_recv_not_rd08 */
-	0xb0430ef4,
-	0x1bf401d6,
-	0x0057f03d,
-	0x09c121f5,
-	0xc73311f4,
-	0x21f5e0c5,
-	0x11f40966,
-	0x0057f029,
-	0x09c121f5,
-	0xc71f11f4,
-	0x21f5e0b5,
-	0x11f40966,
-	0x5921f515,
-	0xc774bd08,
-	0x1bf408c5,
-	0x0232f409,
-/* 0x0b7b: i2c_recv_not_wr08 */
-/* 0x0b7b: i2c_recv_done */
-	0xc7030ef4,
-	0x21f5f8ce,
-	0xe0fc0a26,
-	0x12f4d0fc,
-	0x027cb90a,
-	0x034221f5,
-/* 0x0b90: i2c_recv_exit */
-/* 0x0b92: i2c_init */
-	0x00f800f8,
-/* 0x0b94: test_recv */
-	0x05d817f1,
-	0xcf0614b6,
-	0x10b60011,
-	0xd807f101,
-	0x0604b605,
-	0xbd0001d0,
-	0x00e7f104,
-	0x4fe3f1d9,
-	0x6221f513,
-/* 0x0bbb: test_init */
-	0xf100f802,
-	0xf50800e7,
-	0xf8026221,
-/* 0x0bc5: idle_recv */
-/* 0x0bc7: idle */
-	0xf400f800,
-	0x17f10031,
-	0x14b605d4,
-	0x0011cf06,
-	0xf10110b6,
-	0xb605d407,
-	0x01d00604,
-/* 0x0be3: idle_loop */
-	0xf004bd00,
-	0x32f45817,
-/* 0x0be9: idle_proc */
-/* 0x0be9: idle_proc_exec */
-	0xb910f902,
-	0x21f5021e,
-	0x10fc034b,
-	0xf40911f4,
-	0x0ef40231,
-/* 0x0bfd: idle_proc_next */
-	0x5810b6ef,
-	0xf4061fb8,
-	0x02f4e61b,
-	0x0028f4dd,
-	0x00bb0ef4,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
deleted file mode 100644
index b854432..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GF119
-#define HW_TICKS_PER_US 324
-
-//#define NVKM_FALCON_PC24
-#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nvd0_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nvd0_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
deleted file mode 100644
index 7e16aab..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
+++ /dev/null
@@ -1,1795 +0,0 @@
-uint32_t nvd0_pwr_data[] = {
-/* 0x0000: proc_kern */
-	0x52544e49,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0058: proc_list_head */
-	0x54534f48,
-	0x0000049d,
-	0x00000446,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x584d454d,
-	0x0000068b,
-	0x0000067d,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x46524550,
-	0x0000068f,
-	0x0000068d,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x5f433249,
-	0x00000aaa,
-	0x0000094d,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x54534554,
-	0x00000acd,
-	0x00000aac,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x454c4449,
-	0x00000ad9,
-	0x00000ad7,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
-	0x00000000,
-/* 0x026c: time_next */
-	0x00000000,
-/* 0x0270: fifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x02f0: rfifo_queue */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0370: memx_func_head */
-	0x00000001,
-	0x00000000,
-	0x000004d3,
-/* 0x037c: memx_func_next */
-	0x00000002,
-	0x00000000,
-	0x00000554,
-	0x00000003,
-	0x00000002,
-	0x000005d8,
-	0x00040004,
-	0x00000000,
-	0x000005f4,
-	0x00010005,
-	0x00000000,
-	0x0000060e,
-	0x00010006,
-	0x00000000,
-	0x000005d3,
-	0x00000007,
-	0x00000000,
-	0x00000619,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
-	0x00000000,
-/* 0x03c8: memx_ts_end */
-	0x00000000,
-/* 0x03cc: memx_data_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
-	0x00000400,
-	0x00000800,
-	0x00001000,
-	0x00002000,
-	0x00004000,
-	0x00008000,
-	0x00010000,
-	0x00020000,
-	0x00040000,
-	0x00080000,
-/* 0x0cf4: i2c_sda_map */
-	0x00100000,
-	0x00200000,
-	0x00400000,
-	0x00800000,
-	0x01000000,
-	0x02000000,
-	0x04000000,
-	0x08000000,
-	0x10000000,
-	0x20000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
-
-uint32_t nvd0_pwr_code[] = {
-	0x034d0ef5,
-/* 0x0004: rd32 */
-	0x07a007f1,
-	0xbd000ed0,
-	0x01d7f004,
-	0xf101d3f0,
-	0xd007ac07,
-	0x04bd000d,
-/* 0x001c: rd32_wait */
-	0x07acd7f1,
-	0xf100ddcf,
-	0xf47000d4,
-	0xd7f1f51b,
-	0xddcf07a4,
-/* 0x0033: wr32 */
-	0xf100f800,
-	0xd007a007,
-	0x04bd000e,
-	0x07a407f1,
-	0xbd000dd0,
-	0x02d7f004,
-	0xf0f0d5f0,
-	0x07f101d3,
-	0x0dd007ac,
-/* 0x0057: wr32_wait */
-	0xf104bd00,
-	0xcf07acd7,
-	0xd4f100dd,
-	0x1bf47000,
-/* 0x0067: nsec */
-	0xf900f8f5,
-	0xf080f990,
-	0x88cf2c87,
-/* 0x0071: nsec_loop */
-	0x2c97f000,
-	0xbb0099cf,
-	0x9eb80298,
-	0xf41ef406,
-	0x90fc80fc,
-/* 0x0086: wait */
-	0x90f900f8,
-	0x87f080f9,
-	0x0088cf2c,
-/* 0x0090: wait_loop */
-	0xf402eeb9,
-	0xdab90421,
-	0x04adfd02,
-	0xf406acb8,
-	0x97f0120b,
-	0x0099cf2c,
-	0xb80298bb,
-	0x1ef4069b,
-/* 0x00b1: wait_done */
-	0xfc80fce2,
-/* 0x00b7: intr_watchdog */
-	0x9800f890,
-	0x96b003e9,
-	0x2a0bf400,
-	0xbb9a0a98,
-	0x1cf4029a,
-	0x01d7f00f,
-	0x028c21f5,
-	0x0ef494bd,
-/* 0x00d5: intr_watchdog_next_time */
-	0x9b0a9815,
-	0xf400a6b0,
-	0x9ab8090b,
-	0x061cf406,
-/* 0x00e4: intr_watchdog_next_time_set */
-/* 0x00e7: intr_watchdog_next_proc */
-	0x809b0980,
-	0xe0b603e9,
-	0x68e6b158,
-	0xc61bf402,
-/* 0x00f6: intr */
-	0x00f900f8,
-	0x80f904bd,
-	0xa0f990f9,
-	0xc0f9b0f9,
-	0xe0f9d0f9,
-	0xf7f0f0f9,
-	0x0188fe00,
-	0x87f180f9,
-	0x88cf05d0,
-	0x0180b600,
-	0x05d007f1,
-	0xbd0008d0,
-	0x0887f004,
-	0xc40088cf,
-	0x0bf40289,
-	0x9b008020,
-	0xf458e7f0,
-	0x0998b721,
-	0x0096b09b,
-	0xf00e0bf4,
-	0x09d03407,
-	0x8004bd00,
-/* 0x014e: intr_skip_watchdog */
-	0x89e49a09,
-	0x0bf40800,
-	0x8897f13c,
-	0x0099cf06,
-	0xf4029ac4,
-	0xc7f1260b,
-	0xcccf04c0,
-	0xf1c0f900,
-	0xf14f48e7,
-	0xf05453e3,
-	0x21f500d7,
-	0xc0fc02f1,
-	0x04c007f1,
-	0xbd000cd0,
-/* 0x0185: intr_subintr_skip_fifo */
-	0x8807f104,
-	0x0009d006,
-/* 0x018e: intr_skip_subintr */
-	0x89c404bd,
-	0x070bf420,
-	0xffbfa4f1,
-/* 0x0198: intr_skip_pause */
-	0xf44089c4,
-	0xa4f1070b,
-/* 0x01a2: intr_skip_user0 */
-	0x07f0ffbf,
-	0x0008d004,
-	0x80fc04bd,
-	0xfc0088fe,
-	0xfce0fcf0,
-	0xfcc0fcd0,
-	0xfca0fcb0,
-	0xfc80fc90,
-	0x0032f400,
-/* 0x01c6: ticks_from_ns */
-	0xc0f901f8,
-	0xd7f1b0f9,
-	0xd3f00144,
-	0xb321f500,
-	0xe8ccec03,
-	0x00b4b003,
-	0xec120bf4,
-	0xf103e8ee,
-	0xf00144d7,
-	0x21f500d3,
-/* 0x01ee: ticks_from_ns_quit */
-	0xceb903b3,
-	0xfcb0fc02,
-/* 0x01f7: ticks_from_us */
-	0xf900f8c0,
-	0xf1b0f9c0,
-	0xf00144d7,
-	0x21f500d3,
-	0xceb903b3,
-	0x00b4b002,
-	0xbd050bf4,
-/* 0x0211: ticks_from_us_quit */
-	0xfcb0fce4,
-/* 0x0217: ticks_to_us */
-	0xf100f8c0,
-	0xf00144d7,
-	0xedff00d3,
-/* 0x0223: timer */
-	0xf900f8ec,
-	0xf480f990,
-	0xf8981032,
-	0x0086b003,
-	0xbd531cf4,
-	0x3807f084,
-	0xbd0008d0,
-	0x3487f004,
-	0x980088cf,
-	0x98bb9a09,
-	0x00e9bb02,
-	0xf003fe80,
-	0x88cf0887,
-	0x0284f000,
-	0xf0201bf4,
-	0x88cf3487,
-	0x06e0b800,
-	0xb8090bf4,
-	0x1cf406e8,
-/* 0x026d: timer_reset */
-	0x3407f00e,
-	0xbd000ed0,
-	0x9a0e8004,
-/* 0x0278: timer_enable */
-	0xf00187f0,
-	0x08d03807,
-/* 0x0283: timer_done */
-	0xf404bd00,
-	0x80fc1031,
-	0x00f890fc,
-/* 0x028c: send_proc */
-	0x90f980f9,
-	0x9805e898,
-	0x86f004e9,
-	0x0689b804,
-	0xc42a0bf4,
-	0x88940398,
-	0x1880b604,
-	0x98008ebb,
-	0x8a8000fa,
-	0x018d8000,
-	0x80028c80,
-	0x90b6038b,
-	0x0794f001,
-	0xf404e980,
-/* 0x02c6: send_done */
-	0x90fc0231,
-	0x00f880fc,
-/* 0x02cc: find */
-	0x87f080f9,
-	0x0131f458,
-/* 0x02d4: find_loop */
-	0xb8008a98,
-	0x0bf406ae,
-	0x5880b610,
-	0x026886b1,
-	0xf4f01bf4,
-/* 0x02ea: find_done */
-	0x8eb90132,
-	0xf880fc02,
-/* 0x02f1: send */
-	0xcc21f500,
-	0x9701f402,
-/* 0x02fa: recv */
-	0x90f900f8,
-	0xe89880f9,
-	0x04e99805,
-	0xb80132f4,
-	0x0bf40689,
-	0x0389c43d,
-	0xf00180b6,
-	0xe8800784,
-	0x02ea9805,
-	0x8ffef0f9,
-	0xb9f0f901,
-	0x999402ef,
-	0x00e9bb04,
-	0x9818e0b6,
-	0xec9803eb,
-	0x01ed9802,
-	0xf900ee98,
-	0xfef0fca5,
-	0x31f400f8,
-/* 0x0347: recv_done */
-	0xfcf0fc01,
-	0xf890fc80,
-/* 0x034d: init */
-	0x0817f100,
-	0x0011cf01,
-	0x010911e7,
-	0xfe0814b6,
-	0x17f10014,
-	0x13f000e0,
-	0x1c07f000,
-	0xbd0001d0,
-	0xff17f004,
-	0xd01407f0,
-	0x04bd0001,
-	0xf10217f0,
-	0xf0080015,
-	0x01d01007,
-	0xf104bd00,
-	0xf000f617,
-	0x10fe0013,
-	0x1031f400,
-	0xf00117f0,
-	0x01d03807,
-	0xf004bd00,
-/* 0x03a2: init_proc */
-	0xf19858f7,
-	0x0016b001,
-	0xf9fa0bf4,
-	0x58f0b615,
-/* 0x03b3: mulu32_32_64 */
-	0xf9f20ef4,
-	0xf920f910,
-	0x9540f930,
-	0xd29510e1,
-	0xbdc4bd10,
-	0xc0edffb4,
-	0xb9301dff,
-	0x34f10234,
-	0x34b6ffff,
-	0x1045b610,
-	0xbb00c3bb,
-	0xe2ff01b4,
-	0x0234b930,
-	0xffff34f1,
-	0xb61034b6,
-	0xc3bb1045,
-	0x01b4bb00,
-	0xbb3012ff,
-	0x40fc00b3,
-	0x20fc30fc,
-	0x00f810fc,
-/* 0x0404: host_send */
-	0x04b017f1,
-	0xf10011cf,
-	0xcf04a027,
-	0x12b80022,
-	0x2f0bf406,
-	0x94071ec4,
-	0xe0b704ee,
-	0xeb980270,
-	0x02ec9803,
-	0x9801ed98,
-	0x21f500ee,
-	0x10b602f1,
-	0x0f1ec401,
-	0x04b007f1,
-	0xbd000ed0,
-	0xc30ef404,
-/* 0x0444: host_send_done */
-/* 0x0446: host_recv */
-	0x17f100f8,
-	0x13f14e49,
-	0xe1b85254,
-	0xb30bf406,
-/* 0x0454: host_recv_wait */
-	0x04cc17f1,
-	0xf10011cf,
-	0xcf04c827,
-	0x16f00022,
-	0x0612b808,
-	0xc4ec0bf4,
-	0x34b60723,
-	0xf030b704,
-	0x033b8002,
-	0x80023c80,
-	0x3e80013d,
-	0x0120b600,
-	0xf10f24f0,
-	0xd004c807,
-	0x04bd0002,
-	0xf04027f0,
-	0x02d00007,
-	0xf804bd00,
-/* 0x049d: host_init */
-	0x8017f100,
-	0x1014b600,
-	0x027015f1,
-	0x04d007f1,
-	0xbd0001d0,
-	0x8017f104,
-	0x1014b600,
-	0x02f015f1,
-	0x04dc07f1,
-	0xbd0001d0,
-	0x0117f004,
-	0x04c407f1,
-	0xbd0001d0,
-/* 0x04d3: memx_func_enter */
-	0xf100f804,
-	0xf1162067,
-	0xf1f55d77,
-	0xb9ffff73,
-	0x21f4026e,
-	0x02d8b904,
-	0xf90487fd,
-	0xfc80f960,
-	0xf4e0fcd0,
-	0x77f13321,
-	0x73f1fffe,
-	0x6eb9ffff,
-	0x0421f402,
-	0xfd02d8b9,
-	0x60f90487,
-	0xd0fc80f9,
-	0x21f4e0fc,
-	0xf067f133,
-	0x026eb926,
-	0xb90421f4,
-	0x87fd02d8,
-	0xf960f904,
-	0xfcd0fc80,
-	0x3321f4e0,
-	0xf10467f0,
-	0xd007e007,
-	0x04bd0006,
-/* 0x053c: memx_func_enter_wait */
-	0x07c067f1,
-	0xf00066cf,
-	0x0bf40464,
-	0x2c67f0f6,
-	0x800066cf,
-	0x00f8f106,
-/* 0x0554: memx_func_leave */
-	0xcf2c67f0,
-	0x06800066,
-	0x0467f0f2,
-	0x07e407f1,
-	0xbd0006d0,
-/* 0x0569: memx_func_leave_wait */
-	0xc067f104,
-	0x0066cf07,
-	0xf40464f0,
-	0x67f1f61b,
-	0x77f126f0,
-	0x73f00001,
-	0x026eb900,
-	0xb90421f4,
-	0x87fd02d8,
-	0xf960f905,
-	0xfcd0fc80,
-	0x3321f4e0,
-	0x162067f1,
-	0xf4026eb9,
-	0xd8b90421,
-	0x0587fd02,
-	0x80f960f9,
-	0xe0fcd0fc,
-	0xf13321f4,
-	0xf00aa277,
-	0x6eb90073,
-	0x0421f402,
-	0xfd02d8b9,
-	0x60f90587,
-	0xd0fc80f9,
-	0x21f4e0fc,
-/* 0x05d3: memx_func_wait_vblank */
-	0xb600f833,
-	0x00f80410,
-/* 0x05d8: memx_func_wr32 */
-	0x98001698,
-	0x10b60115,
-	0xf960f908,
-	0xfcd0fc50,
-	0x3321f4e0,
-	0xf40242b6,
-	0x00f8e91b,
-/* 0x05f4: memx_func_wait */
-	0xcf2c87f0,
-	0x1e980088,
-	0x011d9800,
-	0x98021c98,
-	0x10b6031b,
-	0x8621f410,
-/* 0x060e: memx_func_delay */
-	0x1e9800f8,
-	0x0410b600,
-	0xf86721f4,
-/* 0x0619: memx_func_train */
-/* 0x061b: memx_exec */
-	0xf900f800,
-	0xb9d0f9e0,
-	0xb2b902c1,
-/* 0x0625: memx_exec_next */
-	0x00139802,
-	0xe70410b6,
-	0xe701f034,
-	0xb601e033,
-	0x30f00132,
-	0xde35980c,
-	0x12b855f9,
-	0xe41ef406,
-	0x98f10b98,
-	0xcbbbf20c,
-	0xc4b7f102,
-	0x00bbcf07,
-	0xe0fcd0fc,
-	0x02f121f5,
-/* 0x065e: memx_info */
-	0xc67000f8,
-	0x0e0bf401,
-/* 0x0664: memx_info_data */
-	0x03ccc7f1,
-	0x0800b7f1,
-/* 0x066f: memx_info_train */
-	0xf10b0ef4,
-	0xf10bccc7,
-/* 0x0677: memx_info_send */
-	0xf50100b7,
-	0xf802f121,
-/* 0x067d: memx_recv */
-	0x01d6b000,
-	0xb09b0bf4,
-	0x0bf400d6,
-/* 0x068b: memx_init */
-	0xf800f8d8,
-/* 0x068d: perf_recv */
-/* 0x068f: perf_init */
-	0xf800f800,
-/* 0x0691: i2c_drive_scl */
-	0x0036b000,
-	0xf10e0bf4,
-	0xd007e007,
-	0x04bd0001,
-/* 0x06a2: i2c_drive_scl_lo */
-	0x07f100f8,
-	0x01d007e4,
-	0xf804bd00,
-/* 0x06ad: i2c_drive_sda */
-	0x0036b000,
-	0xf10e0bf4,
-	0xd007e007,
-	0x04bd0002,
-/* 0x06be: i2c_drive_sda_lo */
-	0x07f100f8,
-	0x02d007e4,
-	0xf804bd00,
-/* 0x06c9: i2c_sense_scl */
-	0x0132f400,
-	0x07c437f1,
-	0xfd0033cf,
-	0x0bf40431,
-	0x0131f406,
-/* 0x06dc: i2c_sense_scl_done */
-/* 0x06de: i2c_sense_sda */
-	0x32f400f8,
-	0xc437f101,
-	0x0033cf07,
-	0xf40432fd,
-	0x31f4060b,
-/* 0x06f1: i2c_sense_sda_done */
-/* 0x06f3: i2c_raise_scl */
-	0xf900f801,
-	0x9847f140,
-	0x0137f008,
-	0x069121f5,
-/* 0x0700: i2c_raise_scl_wait */
-	0x03e8e7f1,
-	0xf56721f4,
-	0xf406c921,
-	0x42b60901,
-	0xef1bf401,
-/* 0x0714: i2c_raise_scl_done */
-	0x00f840fc,
-/* 0x0718: i2c_start */
-	0x06c921f5,
-	0xf50d11f4,
-	0xf406de21,
-	0x0ef40611,
-/* 0x0729: i2c_start_rep */
-	0x0037f030,
-	0x069121f5,
-	0xf50137f0,
-	0xbb06ad21,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x06f321f5,
-	0xf40464b6,
-/* 0x0756: i2c_start_send */
-	0x37f01f11,
-	0xad21f500,
-	0x88e7f106,
-	0x6721f413,
-	0xf50037f0,
-	0xf1069121,
-	0xf41388e7,
-/* 0x0772: i2c_start_out */
-	0x00f86721,
-/* 0x0774: i2c_stop */
-	0xf50037f0,
-	0xf0069121,
-	0x21f50037,
-	0xe7f106ad,
-	0x21f403e8,
-	0x0137f067,
-	0x069121f5,
-	0x1388e7f1,
-	0xf06721f4,
-	0x21f50137,
-	0xe7f106ad,
-	0x21f41388,
-/* 0x07a7: i2c_bitw */
-	0xf500f867,
-	0xf106ad21,
-	0xf403e8e7,
-	0x76bb6721,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb606f321,
-	0x11f40464,
-	0x88e7f118,
-	0x6721f413,
-	0xf50037f0,
-	0xf1069121,
-	0xf41388e7,
-/* 0x07e6: i2c_bitw_out */
-	0x00f86721,
-/* 0x07e8: i2c_bitr */
-	0xf50137f0,
-	0xf106ad21,
-	0xf403e8e7,
-	0x76bb6721,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb606f321,
-	0x11f40464,
-	0xde21f51b,
-	0x0037f006,
-	0x069121f5,
-	0x1388e7f1,
-	0xf06721f4,
-	0x31f4013c,
-/* 0x082d: i2c_bitr_done */
-/* 0x082f: i2c_get_byte */
-	0xf000f801,
-	0x47f00057,
-/* 0x0835: i2c_get_byte_next */
-	0x0154b608,
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0xe821f550,
-	0x0464b607,
-	0xfd2b11f4,
-	0x42b60553,
-	0xd81bf401,
-	0xbb0137f0,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x07a721f5,
-/* 0x087f: i2c_get_byte_done */
-	0xf80464b6,
-/* 0x0881: i2c_put_byte */
-	0x0847f000,
-/* 0x0884: i2c_put_byte_next */
-	0xff0142b6,
-	0x76bb3854,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb607a721,
-	0x11f40464,
-	0x0046b034,
-	0xbbd81bf4,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x07e821f5,
-	0xf40464b6,
-	0x76bb0f11,
-	0x0136b000,
-	0xf4061bf4,
-/* 0x08da: i2c_put_byte_done */
-	0x00f80132,
-/* 0x08dc: i2c_addr */
-	0xb60076bb,
-	0x50f90465,
-	0xbb046594,
-	0x50bd0256,
-	0xfc0475fd,
-	0x1821f550,
-	0x0464b607,
-	0xe72911f4,
-	0xb6012ec3,
-	0x53fd0134,
-	0x0076bb05,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b60881,
-/* 0x0921: i2c_addr_done */
-/* 0x0923: i2c_acquire_addr */
-	0xc700f804,
-	0xe4b6f8ce,
-	0x14e0b705,
-/* 0x092f: i2c_acquire */
-	0xf500f8d0,
-	0xf4092321,
-	0xd9f00421,
-	0x3321f403,
-/* 0x093e: i2c_release */
-	0x21f500f8,
-	0x21f40923,
-	0x03daf004,
-	0xf83321f4,
-/* 0x094d: i2c_recv */
-	0x0132f400,
-	0xb6f8c1c7,
-	0x16b00214,
-	0x3a1ff528,
-	0xf413a001,
-	0x0032980c,
-	0x0ccc13a0,
-	0xf4003198,
-	0xd0f90231,
-	0xd0f9e0f9,
-	0x000067f1,
-	0x100063f1,
-	0xbb016792,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x092f21f5,
-	0xfc0464b6,
-	0x00d6b0d0,
-	0x00b31bf5,
-	0xbb0057f0,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x08dc21f5,
-	0xf50464b6,
-	0xc700d011,
-	0x76bbe0c5,
-	0x0465b600,
-	0x659450f9,
-	0x0256bb04,
-	0x75fd50bd,
-	0xf550fc04,
-	0xb6088121,
-	0x11f50464,
-	0x57f000ad,
-	0x0076bb01,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b608dc,
-	0x8a11f504,
-	0x0076bb00,
-	0xf90465b6,
-	0x04659450,
-	0xbd0256bb,
-	0x0475fd50,
-	0x21f550fc,
-	0x64b6082f,
-	0x6a11f404,
-	0xbbe05bcb,
-	0x65b60076,
-	0x9450f904,
-	0x56bb0465,
-	0xfd50bd02,
-	0x50fc0475,
-	0x077421f5,
-	0xb90464b6,
-	0x74bd025b,
-/* 0x0a53: i2c_recv_not_rd08 */
-	0xb0430ef4,
-	0x1bf401d6,
-	0x0057f03d,
-	0x08dc21f5,
-	0xc73311f4,
-	0x21f5e0c5,
-	0x11f40881,
-	0x0057f029,
-	0x08dc21f5,
-	0xc71f11f4,
-	0x21f5e0b5,
-	0x11f40881,
-	0x7421f515,
-	0xc774bd07,
-	0x1bf408c5,
-	0x0232f409,
-/* 0x0a93: i2c_recv_not_wr08 */
-/* 0x0a93: i2c_recv_done */
-	0xc7030ef4,
-	0x21f5f8ce,
-	0xe0fc093e,
-	0x12f4d0fc,
-	0x027cb90a,
-	0x02f121f5,
-/* 0x0aa8: i2c_recv_exit */
-/* 0x0aaa: i2c_init */
-	0x00f800f8,
-/* 0x0aac: test_recv */
-	0x05d817f1,
-	0xb60011cf,
-	0x07f10110,
-	0x01d005d8,
-	0xf104bd00,
-	0xf1d900e7,
-	0xf5134fe3,
-	0xf8022321,
-/* 0x0acd: test_init */
-	0x00e7f100,
-	0x2321f508,
-/* 0x0ad7: idle_recv */
-	0xf800f802,
-/* 0x0ad9: idle */
-	0x0031f400,
-	0x05d417f1,
-	0xb60011cf,
-	0x07f10110,
-	0x01d005d4,
-/* 0x0aef: idle_loop */
-	0xf004bd00,
-	0x32f45817,
-/* 0x0af5: idle_proc */
-/* 0x0af5: idle_proc_exec */
-	0xb910f902,
-	0x21f5021e,
-	0x10fc02fa,
-	0xf40911f4,
-	0x0ef40231,
-/* 0x0b09: idle_proc_next */
-	0x5810b6ef,
-	0xf4061fb8,
-	0x02f4e61b,
-	0x0028f4dd,
-	0x00c10ef4,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c
deleted file mode 100644
index d766129..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#define nvd0_pwr_code gk104_pwr_code
-#define nvd0_pwr_data gk104_pwr_data
-#include "fuc/nvd0.fuc.h"
-
-static void
-gk104_pwr_pgob(struct nouveau_pwr *ppwr, bool enable)
-{
-	nv_mask(ppwr, 0x000200, 0x00001000, 0x00000000);
-	nv_rd32(ppwr, 0x000200);
-	nv_mask(ppwr, 0x000200, 0x08000000, 0x08000000);
-	msleep(50);
-
-	nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000002);
-	nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001);
-	nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000);
-
-	nv_mask(ppwr, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000);
-	msleep(50);
-
-	nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000000);
-	nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001);
-	nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000);
-
-	nv_mask(ppwr, 0x000200, 0x08000000, 0x00000000);
-	nv_mask(ppwr, 0x000200, 0x00001000, 0x00001000);
-	nv_rd32(ppwr, 0x000200);
-}
-
-struct nouveau_oclass *
-gk104_pwr_oclass = &(struct nvkm_pwr_impl) {
-	.base.handle = NV_SUBDEV(PWR, 0xe4),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_pwr_ctor,
-		.dtor = _nouveau_pwr_dtor,
-		.init = _nouveau_pwr_init,
-		.fini = _nouveau_pwr_fini,
-	},
-	.code.data = gk104_pwr_code,
-	.code.size = sizeof(gk104_pwr_code),
-	.data.data = gk104_pwr_data,
-	.data.size = sizeof(gk104_pwr_data),
-	.pgob = gk104_pwr_pgob,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
deleted file mode 100644
index 7a9299d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef __NVKM_PWR_MEMX_H__
-#define __NVKM_PWR_MEMX_H__
-
-#include "priv.h"
-
-struct nouveau_memx {
-	struct nouveau_pwr *ppwr;
-	u32 base;
-	u32 size;
-	struct {
-		u32 mthd;
-		u32 size;
-		u32 data[64];
-	} c;
-};
-
-static void
-memx_out(struct nouveau_memx *memx)
-{
-	struct nouveau_pwr *ppwr = memx->ppwr;
-	int i;
-
-	if (memx->c.mthd) {
-		nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
-		for (i = 0; i < memx->c.size; i++)
-			nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]);
-		memx->c.mthd = 0;
-		memx->c.size = 0;
-	}
-}
-
-static void
-memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[])
-{
-	if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
-	    (memx->c.mthd && memx->c.mthd != mthd))
-		memx_out(memx);
-	memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
-	memx->c.size += size;
-	memx->c.mthd  = mthd;
-}
-
-int
-nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
-{
-	struct nouveau_memx *memx;
-	u32 reply[2];
-	int ret;
-
-	ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
-					MEMX_INFO_DATA, 0);
-	if (ret)
-		return ret;
-
-	memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL);
-	if (!memx)
-		return -ENOMEM;
-	memx->ppwr = ppwr;
-	memx->base = reply[0];
-	memx->size = reply[1];
-
-	/* acquire data segment access */
-	do {
-		nv_wr32(ppwr, 0x10a580, 0x00000003);
-	} while (nv_rd32(ppwr, 0x10a580) != 0x00000003);
-	nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base);
-
-	return 0;
-}
-
-int
-nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec)
-{
-	struct nouveau_memx *memx = *pmemx;
-	struct nouveau_pwr *ppwr = memx->ppwr;
-	u32 finish, reply[2];
-
-	/* flush the cache... */
-	memx_out(memx);
-
-	/* release data segment access */
-	finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff;
-	nv_wr32(ppwr, 0x10a580, 0x00000000);
-
-	/* call MEMX process to execute the script, and wait for reply */
-	if (exec) {
-		ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_EXEC,
-				 memx->base, finish);
-	}
-
-	nv_debug(memx->ppwr, "Exec took %uns, PPWR_IN %08x\n",
-		 reply[0], reply[1]);
-	kfree(memx);
-	return 0;
-}
-
-void
-nouveau_memx_wr32(struct nouveau_memx *memx, u32 addr, u32 data)
-{
-	nv_debug(memx->ppwr, "R[%06x] = 0x%08x\n", addr, data);
-	memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data });
-}
-
-void
-nouveau_memx_wait(struct nouveau_memx *memx,
-		  u32 addr, u32 mask, u32 data, u32 nsec)
-{
-	nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
-				addr, mask, data, nsec);
-	memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec });
-	memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec)
-{
-	nv_debug(memx->ppwr, "    DELAY = %d ns\n", nsec);
-	memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec });
-	memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_wait_vblank(struct nouveau_memx *memx)
-{
-	struct nouveau_pwr *ppwr = memx->ppwr;
-	u32 heads, x, y, px = 0;
-	int i, head_sync;
-
-	if (nv_device(ppwr)->chipset < 0xd0) {
-		heads = nv_rd32(ppwr, 0x610050);
-		for (i = 0; i < 2; i++) {
-			/* Heuristic: sync to head with biggest resolution */
-			if (heads & (2 << (i << 3))) {
-				x = nv_rd32(ppwr, 0x610b40 + (0x540 * i));
-				y = (x & 0xffff0000) >> 16;
-				x &= 0x0000ffff;
-				if ((x * y) > px) {
-					px = (x * y);
-					head_sync = i;
-				}
-			}
-		}
-	}
-
-	if (px == 0) {
-		nv_debug(memx->ppwr, "WAIT VBLANK !NO ACTIVE HEAD\n");
-		return;
-	}
-
-	nv_debug(memx->ppwr, "WAIT VBLANK HEAD%d\n", head_sync);
-	memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync });
-	memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_train(struct nouveau_memx *memx)
-{
-	nv_debug(memx->ppwr, "   MEM TRAIN\n");
-	memx_cmd(memx, MEMX_TRAIN, 0, NULL);
-}
-
-int
-nouveau_memx_train_result(struct nouveau_pwr *ppwr, u32 *res, int rsize)
-{
-	u32 reply[2], base, size, i;
-	int ret;
-
-	ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
-					MEMX_INFO_TRAIN, 0);
-	if (ret)
-		return ret;
-
-	base = reply[0];
-	size = reply[1] >> 2;
-	if (size > rsize)
-		return -ENOMEM;
-
-	/* read the packet */
-	nv_wr32(ppwr, 0x10a1c0, 0x02000000 | base);
-
-	for (i = 0; i < size; i++)
-		res[i] = nv_rd32(ppwr, 0x10a1c4);
-
-	return 0;
-}
-
-void
-nouveau_memx_block(struct nouveau_memx *memx)
-{
-	nv_debug(memx->ppwr, "   HOST BLOCKED\n");
-	memx_cmd(memx, MEMX_ENTER, 0, NULL);
-}
-
-void
-nouveau_memx_unblock(struct nouveau_memx *memx)
-{
-	nv_debug(memx->ppwr, "   HOST UNBLOCKED\n");
-	memx_cmd(memx, MEMX_LEAVE, 0, NULL);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c
deleted file mode 100644
index 04ff7c3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nv108.fuc.h"
-
-struct nouveau_oclass *
-nv108_pwr_oclass = &(struct nvkm_pwr_impl) {
-	.base.handle = NV_SUBDEV(PWR, 0x00),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_pwr_ctor,
-		.dtor = _nouveau_pwr_dtor,
-		.init = _nouveau_pwr_init,
-		.fini = _nouveau_pwr_fini,
-	},
-	.code.data = nv108_pwr_code,
-	.code.size = sizeof(nv108_pwr_code),
-	.data.data = nv108_pwr_data,
-	.data.size = sizeof(nv108_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c
deleted file mode 100644
index 998d530..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nva3.fuc.h"
-
-static int
-nva3_pwr_init(struct nouveau_object *object)
-{
-	struct nouveau_pwr *ppwr = (void *)object;
-	nv_mask(ppwr, 0x022210, 0x00000001, 0x00000000);
-	nv_mask(ppwr, 0x022210, 0x00000001, 0x00000001);
-	return nouveau_pwr_init(ppwr);
-}
-
-struct nouveau_oclass *
-nva3_pwr_oclass = &(struct nvkm_pwr_impl) {
-	.base.handle = NV_SUBDEV(PWR, 0xa3),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_pwr_ctor,
-		.dtor = _nouveau_pwr_dtor,
-		.init = nva3_pwr_init,
-		.fini = _nouveau_pwr_fini,
-	},
-	.code.data = nva3_pwr_code,
-	.code.size = sizeof(nva3_pwr_code),
-	.data.data = nva3_pwr_data,
-	.data.size = sizeof(nva3_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c
deleted file mode 100644
index 9a773e6..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nvc0.fuc.h"
-
-struct nouveau_oclass *
-nvc0_pwr_oclass = &(struct nvkm_pwr_impl) {
-	.base.handle = NV_SUBDEV(PWR, 0xc0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_pwr_ctor,
-		.dtor = _nouveau_pwr_dtor,
-		.init = _nouveau_pwr_init,
-		.fini = _nouveau_pwr_fini,
-	},
-	.code.data = nvc0_pwr_code,
-	.code.size = sizeof(nvc0_pwr_code),
-	.data.data = nvc0_pwr_data,
-	.data.size = sizeof(nvc0_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c
deleted file mode 100644
index 2b29be5..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nvd0.fuc.h"
-
-struct nouveau_oclass *
-nvd0_pwr_oclass = &(struct nvkm_pwr_impl) {
-	.base.handle = NV_SUBDEV(PWR, 0xd0),
-	.base.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_pwr_ctor,
-		.dtor = _nouveau_pwr_dtor,
-		.init = _nouveau_pwr_init,
-		.fini = _nouveau_pwr_fini,
-	},
-	.code.data = nvd0_pwr_code,
-	.code.size = sizeof(nvd0_pwr_code),
-	.data.data = nvd0_pwr_data,
-	.data.size = sizeof(nvd0_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h
deleted file mode 100644
index 3814a34..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __NVKM_PWR_PRIV_H__
-#define __NVKM_PWR_PRIV_H__
-
-#include <subdev/pwr.h>
-#include <subdev/pwr/fuc/os.h>
-
-#define nouveau_pwr_create(p, e, o, d)                                         \
-	nouveau_pwr_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_pwr_destroy(p)                                                 \
-	nouveau_subdev_destroy(&(p)->base)
-#define nouveau_pwr_init(p) ({                                                 \
-	struct nouveau_pwr *_ppwr = (p);                                       \
-	_nouveau_pwr_init(nv_object(_ppwr));                                   \
-})
-#define nouveau_pwr_fini(p,s) ({                                               \
-	struct nouveau_pwr *_ppwr = (p);                                       \
-	_nouveau_pwr_fini(nv_object(_ppwr), (s));                              \
-})
-
-int nouveau_pwr_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, int, void **);
-
-int _nouveau_pwr_ctor(struct nouveau_object *, struct nouveau_object *,
-		      struct nouveau_oclass *, void *, u32,
-		      struct nouveau_object **);
-#define _nouveau_pwr_dtor _nouveau_subdev_dtor
-int _nouveau_pwr_init(struct nouveau_object *);
-int _nouveau_pwr_fini(struct nouveau_object *, bool);
-
-struct nvkm_pwr_impl {
-	struct nouveau_oclass base;
-	struct {
-		u32 *data;
-		u32  size;
-	} code;
-	struct {
-		u32 *data;
-		u32  size;
-	} data;
-
-	void (*pgob)(struct nouveau_pwr *, bool);
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
deleted file mode 100644
index 9ad01da..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-
-#include "priv.h"
-
-static int
-nouveau_therm_update_trip(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_therm_trip_point *trip = priv->fan->bios.trip,
-					*cur_trip = NULL,
-					*last_trip = priv->last_trip;
-	u8  temp = therm->temp_get(therm);
-	u16 duty, i;
-
-	/* look for the trip point corresponding to the current temperature */
-	cur_trip = NULL;
-	for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) {
-		if (temp >= trip[i].temp)
-			cur_trip = &trip[i];
-	}
-
-	/* account for the hysteresis cycle */
-	if (last_trip && temp <= (last_trip->temp) &&
-	    temp > (last_trip->temp - last_trip->hysteresis))
-		cur_trip = last_trip;
-
-	if (cur_trip) {
-		duty = cur_trip->fan_duty;
-		priv->last_trip = cur_trip;
-	} else {
-		duty = 0;
-		priv->last_trip = NULL;
-	}
-
-	return duty;
-}
-
-static int
-nouveau_therm_update_linear(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	u8  linear_min_temp = priv->fan->bios.linear_min_temp;
-	u8  linear_max_temp = priv->fan->bios.linear_max_temp;
-	u8  temp = therm->temp_get(therm);
-	u16 duty;
-
-	/* handle the non-linear part first */
-	if (temp < linear_min_temp)
-		return priv->fan->bios.min_duty;
-	else if (temp > linear_max_temp)
-		return priv->fan->bios.max_duty;
-
-	/* we are in the linear zone */
-	duty  = (temp - linear_min_temp);
-	duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty);
-	duty /= (linear_max_temp - linear_min_temp);
-	duty += priv->fan->bios.min_duty;
-
-	return duty;
-}
-
-static void
-nouveau_therm_update(struct nouveau_therm *therm, int mode)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(therm);
-	struct nouveau_therm_priv *priv = (void *)therm;
-	unsigned long flags;
-	bool immd = true;
-	bool poll = true;
-	int duty = -1;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (mode < 0)
-		mode = priv->mode;
-	priv->mode = mode;
-
-	switch (mode) {
-	case NOUVEAU_THERM_CTRL_MANUAL:
-		ptimer->alarm_cancel(ptimer, &priv->alarm);
-		duty = nouveau_therm_fan_get(therm);
-		if (duty < 0)
-			duty = 100;
-		poll = false;
-		break;
-	case NOUVEAU_THERM_CTRL_AUTO:
-		switch(priv->fan->bios.fan_mode) {
-		case NVBIOS_THERM_FAN_TRIP:
-			duty = nouveau_therm_update_trip(therm);
-			break;
-		case NVBIOS_THERM_FAN_LINEAR:
-			duty = nouveau_therm_update_linear(therm);
-			break;
-		case NVBIOS_THERM_FAN_OTHER:
-			if (priv->cstate)
-				duty = priv->cstate;
-			poll = false;
-			break;
-		}
-		immd = false;
-		break;
-	case NOUVEAU_THERM_CTRL_NONE:
-	default:
-		ptimer->alarm_cancel(ptimer, &priv->alarm);
-		poll = false;
-	}
-
-	if (list_empty(&priv->alarm.head) && poll)
-		ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (duty >= 0) {
-		nv_debug(therm, "FAN target request: %d%%\n", duty);
-		nouveau_therm_fan_set(therm, immd, duty);
-	}
-}
-
-int
-nouveau_therm_cstate(struct nouveau_therm *ptherm, int fan, int dir)
-{
-	struct nouveau_therm_priv *priv = (void *)ptherm;
-	if (!dir || (dir < 0 && fan < priv->cstate) ||
-		    (dir > 0 && fan > priv->cstate)) {
-		nv_debug(ptherm, "default fan speed -> %d%%\n", fan);
-		priv->cstate = fan;
-		nouveau_therm_update(ptherm, -1);
-	}
-	return 0;
-}
-
-static void
-nouveau_therm_alarm(struct nouveau_alarm *alarm)
-{
-	struct nouveau_therm_priv *priv =
-	       container_of(alarm, struct nouveau_therm_priv, alarm);
-	nouveau_therm_update(&priv->base, -1);
-}
-
-int
-nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_device *device = nv_device(therm);
-	static const char *name[] = {
-		"disabled",
-		"manual",
-		"automatic"
-	};
-
-	/* The default PPWR ucode on fermi interferes with fan management */
-	if ((mode >= ARRAY_SIZE(name)) ||
-	    (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0 &&
-	     !nouveau_subdev(device, NVDEV_SUBDEV_PWR)))
-		return -EINVAL;
-
-	/* do not allow automatic fan management if the thermal sensor is
-	 * not available */
-	if (mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
-		return -EINVAL;
-
-	if (priv->mode == mode)
-		return 0;
-
-	nv_info(therm, "fan management: %s\n", name[mode]);
-	nouveau_therm_update(therm, mode);
-	return 0;
-}
-
-int
-nouveau_therm_attr_get(struct nouveau_therm *therm,
-		       enum nouveau_therm_attr_type type)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	switch (type) {
-	case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
-		return priv->fan->bios.min_duty;
-	case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
-		return priv->fan->bios.max_duty;
-	case NOUVEAU_THERM_ATTR_FAN_MODE:
-		return priv->mode;
-	case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
-		return priv->bios_sensor.thrs_fan_boost.temp;
-	case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
-		return priv->bios_sensor.thrs_fan_boost.hysteresis;
-	case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
-		return priv->bios_sensor.thrs_down_clock.temp;
-	case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
-		return priv->bios_sensor.thrs_down_clock.hysteresis;
-	case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
-		return priv->bios_sensor.thrs_critical.temp;
-	case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
-		return priv->bios_sensor.thrs_critical.hysteresis;
-	case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
-		return priv->bios_sensor.thrs_shutdown.temp;
-	case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
-		return priv->bios_sensor.thrs_shutdown.hysteresis;
-	}
-
-	return -EINVAL;
-}
-
-int
-nouveau_therm_attr_set(struct nouveau_therm *therm,
-		       enum nouveau_therm_attr_type type, int value)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	switch (type) {
-	case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
-		if (value < 0)
-			value = 0;
-		if (value > priv->fan->bios.max_duty)
-			value = priv->fan->bios.max_duty;
-		priv->fan->bios.min_duty = value;
-		return 0;
-	case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
-		if (value < 0)
-			value = 0;
-		if (value < priv->fan->bios.min_duty)
-			value = priv->fan->bios.min_duty;
-		priv->fan->bios.max_duty = value;
-		return 0;
-	case NOUVEAU_THERM_ATTR_FAN_MODE:
-		return nouveau_therm_fan_mode(therm, value);
-	case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
-		priv->bios_sensor.thrs_fan_boost.temp = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
-		priv->bios_sensor.thrs_fan_boost.hysteresis = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
-		priv->bios_sensor.thrs_down_clock.temp = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
-		priv->bios_sensor.thrs_down_clock.hysteresis = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
-		priv->bios_sensor.thrs_critical.temp = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
-		priv->bios_sensor.thrs_critical.hysteresis = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
-		priv->bios_sensor.thrs_shutdown.temp = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
-		priv->bios_sensor.thrs_shutdown.hysteresis = value;
-		priv->sensor.program_alarms(therm);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-int
-_nouveau_therm_init(struct nouveau_object *object)
-{
-	struct nouveau_therm *therm = (void *)object;
-	struct nouveau_therm_priv *priv = (void *)therm;
-	int ret;
-
-	ret = nouveau_subdev_init(&therm->base);
-	if (ret)
-		return ret;
-
-	if (priv->suspend >= 0) {
-		/* restore the pwm value only when on manual or auto mode */
-		if (priv->suspend > 0)
-			nouveau_therm_fan_set(therm, true, priv->fan->percent);
-
-		nouveau_therm_fan_mode(therm, priv->suspend);
-	}
-	nouveau_therm_sensor_init(therm);
-	nouveau_therm_fan_init(therm);
-	return 0;
-}
-
-int
-_nouveau_therm_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nouveau_therm *therm = (void *)object;
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	nouveau_therm_fan_fini(therm, suspend);
-	nouveau_therm_sensor_fini(therm, suspend);
-	if (suspend) {
-		priv->suspend = priv->mode;
-		priv->mode = NOUVEAU_THERM_CTRL_NONE;
-	}
-
-	return nouveau_subdev_fini(&therm->base, suspend);
-}
-
-int
-nouveau_therm_create_(struct nouveau_object *parent,
-		      struct nouveau_object *engine,
-		      struct nouveau_oclass *oclass,
-		      int length, void **pobject)
-{
-	struct nouveau_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PTHERM",
-				     "therm", length, pobject);
-	priv = *pobject;
-	if (ret)
-		return ret;
-
-	nouveau_alarm_init(&priv->alarm, nouveau_therm_alarm);
-	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->sensor.alarm_program_lock);
-
-	priv->base.fan_get = nouveau_therm_fan_user_get;
-	priv->base.fan_set = nouveau_therm_fan_user_set;
-	priv->base.fan_sense = nouveau_therm_fan_sense;
-	priv->base.attr_get = nouveau_therm_attr_get;
-	priv->base.attr_set = nouveau_therm_attr_set;
-	priv->mode = priv->suspend = -1; /* undefined */
-	return 0;
-}
-
-int
-nouveau_therm_preinit(struct nouveau_therm *therm)
-{
-	nouveau_therm_sensor_ctor(therm);
-	nouveau_therm_ic_ctor(therm);
-	nouveau_therm_fan_ctor(therm);
-
-	nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
-	nouveau_therm_sensor_preinit(therm);
-	return 0;
-}
-
-void
-_nouveau_therm_dtor(struct nouveau_object *object)
-{
-	struct nouveau_therm_priv *priv = (void *)object;
-	kfree(priv->fan);
-	nouveau_subdev_destroy(&priv->base.base);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
deleted file mode 100644
index 3656d60..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/gpio.h>
-#include <subdev/timer.h>
-
-#include <subdev/bios/fan.h>
-
-static int
-nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
-{
-	struct nouveau_therm *therm = fan->parent;
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_timer *ptimer = nouveau_timer(priv);
-	unsigned long flags;
-	int ret = 0;
-	int duty;
-
-	/* update target fan speed, restricting to allowed range */
-	spin_lock_irqsave(&fan->lock, flags);
-	if (target < 0)
-		target = fan->percent;
-	target = max_t(u8, target, fan->bios.min_duty);
-	target = min_t(u8, target, fan->bios.max_duty);
-	if (fan->percent != target) {
-		nv_debug(therm, "FAN target: %d\n", target);
-		fan->percent = target;
-	}
-
-	/* check that we're not already at the target duty cycle */
-	duty = fan->get(therm);
-	if (duty == target) {
-		spin_unlock_irqrestore(&fan->lock, flags);
-		return 0;
-	}
-
-	/* smooth out the fanspeed increase/decrease */
-	if (!immediate && duty >= 0) {
-		/* the constant "3" is a rough approximation taken from
-		 * nvidia's behaviour.
-		 * it is meant to bump the fan speed more incrementally
-		 */
-		if (duty < target)
-			duty = min(duty + 3, target);
-		else if (duty > target)
-			duty = max(duty - 3, target);
-	} else {
-		duty = target;
-	}
-
-	nv_debug(therm, "FAN update: %d\n", duty);
-	ret = fan->set(therm, duty);
-	if (ret) {
-		spin_unlock_irqrestore(&fan->lock, flags);
-		return ret;
-	}
-
-	/* fan speed updated, drop the fan lock before grabbing the
-	 * alarm-scheduling lock and risking a deadlock
-	 */
-	spin_unlock_irqrestore(&fan->lock, flags);
-
-	/* schedule next fan update, if not at target speed already */
-	if (list_empty(&fan->alarm.head) && target != duty) {
-		u16 bump_period = fan->bios.bump_period;
-		u16 slow_down_period = fan->bios.slow_down_period;
-		u64 delay;
-
-		if (duty > target)
-			delay = slow_down_period;
-		else if (duty == target)
-			delay = min(bump_period, slow_down_period) ;
-		else
-			delay = bump_period;
-
-		ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
-	}
-
-	return ret;
-}
-
-static void
-nouveau_fan_alarm(struct nouveau_alarm *alarm)
-{
-	struct nouveau_fan *fan = container_of(alarm, struct nouveau_fan, alarm);
-	nouveau_fan_update(fan, false, -1);
-}
-
-int
-nouveau_therm_fan_get(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	return priv->fan->get(therm);
-}
-
-int
-nouveau_therm_fan_set(struct nouveau_therm *therm, bool immediate, int percent)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	return nouveau_fan_update(priv->fan, immediate, percent);
-}
-
-int
-nouveau_therm_fan_sense(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_timer *ptimer = nouveau_timer(therm);
-	struct nouveau_gpio *gpio = nouveau_gpio(therm);
-	u32 cycles, cur, prev;
-	u64 start, end, tach;
-
-	if (priv->fan->tach.func == DCB_GPIO_UNUSED)
-		return -ENODEV;
-
-	/* Time a complete rotation and extrapolate to RPM:
-	 * When the fan spins, it changes the value of GPIO FAN_SENSE.
-	 * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
-	 */
-	start = ptimer->read(ptimer);
-	prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
-	cycles = 0;
-	do {
-		usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
-
-		cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
-		if (prev != cur) {
-			if (!start)
-				start = ptimer->read(ptimer);
-			cycles++;
-			prev = cur;
-		}
-	} while (cycles < 5 && ptimer->read(ptimer) - start < 250000000);
-	end = ptimer->read(ptimer);
-
-	if (cycles == 5) {
-		tach = (u64)60000000000ULL;
-		do_div(tach, (end - start));
-		return tach;
-	} else
-		return 0;
-}
-
-int
-nouveau_therm_fan_user_get(struct nouveau_therm *therm)
-{
-	return nouveau_therm_fan_get(therm);
-}
-
-int
-nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	if (priv->mode != NOUVEAU_THERM_CTRL_MANUAL)
-		return -EINVAL;
-
-	return nouveau_therm_fan_set(therm, true, percent);
-}
-
-static void
-nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	priv->fan->bios.pwm_freq = 0;
-	priv->fan->bios.min_duty = 0;
-	priv->fan->bios.max_duty = 100;
-	priv->fan->bios.bump_period = 500;
-	priv->fan->bios.slow_down_period = 2000;
-	priv->fan->bios.linear_min_temp = 40;
-	priv->fan->bios.linear_max_temp = 85;
-}
-
-static void
-nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	if (priv->fan->bios.min_duty > 100)
-		priv->fan->bios.min_duty = 100;
-	if (priv->fan->bios.max_duty > 100)
-		priv->fan->bios.max_duty = 100;
-
-	if (priv->fan->bios.min_duty > priv->fan->bios.max_duty)
-		priv->fan->bios.min_duty = priv->fan->bios.max_duty;
-}
-
-int
-nouveau_therm_fan_init(struct nouveau_therm *therm)
-{
-	return 0;
-}
-
-int
-nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_timer *ptimer = nouveau_timer(therm);
-
-	if (suspend)
-		ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
-	return 0;
-}
-
-int
-nouveau_therm_fan_ctor(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_gpio *gpio = nouveau_gpio(therm);
-	struct nouveau_bios *bios = nouveau_bios(therm);
-	struct dcb_gpio_func func;
-	int ret;
-
-	/* attempt to locate a drivable fan, and determine control method */
-	ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
-	if (ret == 0) {
-		/* FIXME: is this really the place to perform such checks ? */
-		if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
-			nv_debug(therm, "GPIO_FAN is in input mode\n");
-			ret = -EINVAL;
-		} else {
-			ret = nouveau_fanpwm_create(therm, &func);
-			if (ret != 0)
-				ret = nouveau_fantog_create(therm, &func);
-		}
-	}
-
-	/* no controllable fan found, create a dummy fan module */
-	if (ret != 0) {
-		ret = nouveau_fannil_create(therm);
-		if (ret)
-			return ret;
-	}
-
-	nv_info(therm, "FAN control: %s\n", priv->fan->type);
-
-	/* read the current speed, it is useful when resuming */
-	priv->fan->percent = nouveau_therm_fan_get(therm);
-
-	/* attempt to detect a tachometer connection */
-	ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
-	if (ret)
-		priv->fan->tach.func = DCB_GPIO_UNUSED;
-
-	/* initialise fan bump/slow update handling */
-	priv->fan->parent = therm;
-	nouveau_alarm_init(&priv->fan->alarm, nouveau_fan_alarm);
-	spin_lock_init(&priv->fan->lock);
-
-	/* other random init... */
-	nouveau_therm_fan_set_defaults(therm);
-	nvbios_perf_fan_parse(bios, &priv->fan->perf);
-	if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
-		nv_debug(therm, "parsing the fan table failed\n");
-		if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
-			nv_error(therm, "parsing both fan tables failed\n");
-	}
-	nouveau_therm_fan_safety_checks(therm);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c
deleted file mode 100644
index b78c182..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nouveau_fannil_get(struct nouveau_therm *therm)
-{
-	return -ENODEV;
-}
-
-static int
-nouveau_fannil_set(struct nouveau_therm *therm, int percent)
-{
-	return -ENODEV;
-}
-
-int
-nouveau_fannil_create(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fan *priv;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	tpriv->fan = priv;
-	if (!priv)
-		return -ENOMEM;
-
-	priv->type = "none / external";
-	priv->get = nouveau_fannil_get;
-	priv->set = nouveau_fannil_set;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
deleted file mode 100644
index c629d7f..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Martin Peres
- */
-
-#include <core/option.h>
-#include <subdev/gpio.h>
-#include <subdev/bios.h>
-#include <subdev/bios/fan.h>
-
-#include "priv.h"
-
-struct nouveau_fanpwm_priv {
-	struct nouveau_fan base;
-	struct dcb_gpio_func func;
-};
-
-static int
-nouveau_fanpwm_get(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan;
-	struct nouveau_gpio *gpio = nouveau_gpio(therm);
-	int card_type = nv_device(therm)->card_type;
-	u32 divs, duty;
-	int ret;
-
-	ret = therm->pwm_get(therm, priv->func.line, &divs, &duty);
-	if (ret == 0 && divs) {
-		divs = max(divs, duty);
-		if (card_type <= NV_40 || (priv->func.log[0] & 1))
-			duty = divs - duty;
-		return (duty * 100) / divs;
-	}
-
-	return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100;
-}
-
-static int
-nouveau_fanpwm_set(struct nouveau_therm *therm, int percent)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan;
-	int card_type = nv_device(therm)->card_type;
-	u32 divs, duty;
-	int ret;
-
-	divs = priv->base.perf.pwm_divisor;
-	if (priv->base.bios.pwm_freq) {
-		divs = 1;
-		if (therm->pwm_clock)
-			divs = therm->pwm_clock(therm, priv->func.line);
-		divs /= priv->base.bios.pwm_freq;
-	}
-
-	duty = ((divs * percent) + 99) / 100;
-	if (card_type <= NV_40 || (priv->func.log[0] & 1))
-		duty = divs - duty;
-
-	ret = therm->pwm_set(therm, priv->func.line, divs, duty);
-	if (ret == 0)
-		ret = therm->pwm_ctrl(therm, priv->func.line, true);
-	return ret;
-}
-
-int
-nouveau_fanpwm_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
-{
-	struct nouveau_device *device = nv_device(therm);
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_bios *bios = nouveau_bios(therm);
-	struct nouveau_fanpwm_priv *priv;
-	struct nvbios_therm_fan fan;
-	u32 divs, duty;
-
-	nvbios_fan_parse(bios, &fan);
-
-	if (!nouveau_boolopt(device->cfgopt, "NvFanPWM", func->param) ||
-	    !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE ||
-	     therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV)
-		return -ENODEV;
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	tpriv->fan = &priv->base;
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.type = "PWM";
-	priv->base.get = nouveau_fanpwm_get;
-	priv->base.set = nouveau_fanpwm_set;
-	priv->func = *func;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c
deleted file mode 100644
index f69dab1..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/gpio.h>
-#include <subdev/timer.h>
-
-struct nouveau_fantog_priv {
-	struct nouveau_fan base;
-	struct nouveau_alarm alarm;
-	spinlock_t lock;
-	u32 period_us;
-	u32 percent;
-	struct dcb_gpio_func func;
-};
-
-static void
-nouveau_fantog_update(struct nouveau_fantog_priv *priv, int percent)
-{
-	struct nouveau_therm_priv *tpriv = (void *)priv->base.parent;
-	struct nouveau_timer *ptimer = nouveau_timer(tpriv);
-	struct nouveau_gpio *gpio = nouveau_gpio(tpriv);
-	unsigned long flags;
-	int duty;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (percent < 0)
-		percent = priv->percent;
-	priv->percent = percent;
-
-	duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff);
-	gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
-
-	if (list_empty(&priv->alarm.head) && percent != (duty * 100)) {
-		u64 next_change = (percent * priv->period_us) / 100;
-		if (!duty)
-			next_change = priv->period_us - next_change;
-		ptimer->alarm(ptimer, next_change * 1000, &priv->alarm);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nouveau_fantog_alarm(struct nouveau_alarm *alarm)
-{
-	struct nouveau_fantog_priv *priv =
-	       container_of(alarm, struct nouveau_fantog_priv, alarm);
-	nouveau_fantog_update(priv, -1);
-}
-
-static int
-nouveau_fantog_get(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fantog_priv *priv = (void *)tpriv->fan;
-	return priv->percent;
-}
-
-static int
-nouveau_fantog_set(struct nouveau_therm *therm, int percent)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fantog_priv *priv = (void *)tpriv->fan;
-	if (therm->pwm_ctrl)
-		therm->pwm_ctrl(therm, priv->func.line, false);
-	nouveau_fantog_update(priv, percent);
-	return 0;
-}
-
-int
-nouveau_fantog_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
-{
-	struct nouveau_therm_priv *tpriv = (void *)therm;
-	struct nouveau_fantog_priv *priv;
-	int ret;
-
-	if (therm->pwm_ctrl) {
-		ret = therm->pwm_ctrl(therm, func->line, false);
-		if (ret)
-			return ret;
-	}
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	tpriv->fan = &priv->base;
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.type = "toggle";
-	priv->base.get = nouveau_fantog_get;
-	priv->base.set = nouveau_fantog_set;
-	nouveau_alarm_init(&priv->alarm, nouveau_fantog_alarm);
-	priv->period_us = 100000; /* 10Hz */
-	priv->percent = 100;
-	priv->func = *func;
-	spin_lock_init(&priv->lock);
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c
deleted file mode 100644
index 668cf33..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gm107_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-static int
-gm107_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
-	/* nothing to do, it seems hardwired */
-	return 0;
-}
-
-static int
-gm107_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
-	*divs = nv_rd32(therm, 0x10eb20) & 0x1fff;
-	*duty = nv_rd32(therm, 0x10eb24) & 0x1fff;
-	return 0;
-}
-
-static int
-gm107_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
-	nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */
-	nv_wr32(therm, 0x10eb14, duty | 0x80000000);
-	return 0;
-}
-
-static int
-gm107_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
-	return nv_device(therm)->crystal * 1000;
-}
-
-static int
-gm107_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct gm107_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl;
-	priv->base.base.pwm_get = gm107_fan_pwm_get;
-	priv->base.base.pwm_set = gm107_fan_pwm_set;
-	priv->base.base.pwm_clock = gm107_fan_pwm_clock;
-	priv->base.base.temp_get = nv84_temp_get;
-	priv->base.base.fan_sense = nva3_therm_fan_sense;
-	priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-gm107_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0x117),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gm107_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nvd0_therm_init,
-		.fini = nv84_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
deleted file mode 100644
index ca9ad9fd4..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2012 Nouveau community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <subdev/i2c.h>
-#include <subdev/bios/extdev.h>
-
-static bool
-probe_monitoring_device(struct nouveau_i2c_port *i2c,
-			struct i2c_board_info *info, void *data)
-{
-	struct nouveau_therm_priv *priv = data;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	struct i2c_client *client;
-
-	request_module("%s%s", I2C_MODULE_PREFIX, info->type);
-
-	client = i2c_new_device(&i2c->adapter, info);
-	if (!client)
-		return false;
-
-	if (!client->dev.driver ||
-	    to_i2c_driver(client->dev.driver)->detect(client, info)) {
-		i2c_unregister_device(client);
-		return false;
-	}
-
-	nv_info(priv,
-		"Found an %s at address 0x%x (controlled by lm_sensors, "
-		"temp offset %+i C)\n",
-		info->type, info->addr, sensor->offset_constant);
-	priv->ic = client;
-
-	return true;
-}
-
-static struct nouveau_i2c_board_info
-nv_board_infos[] = {
-	{ { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
-	{ { I2C_BOARD_INFO("w83781d", 0x2d) }, 0  },
-	{ { I2C_BOARD_INFO("adt7473", 0x2e) }, 40  },
-	{ { I2C_BOARD_INFO("adt7473", 0x2d) }, 40  },
-	{ { I2C_BOARD_INFO("adt7473", 0x2c) }, 40  },
-	{ { I2C_BOARD_INFO("f75375", 0x2e) }, 0  },
-	{ { I2C_BOARD_INFO("lm99", 0x4c) }, 0  },
-	{ { I2C_BOARD_INFO("lm90", 0x4c) }, 0  },
-	{ { I2C_BOARD_INFO("lm90", 0x4d) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x18) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x19) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x1a) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x29) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x2a) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x2b) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x4c) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x4d) }, 0  },
-	{ { I2C_BOARD_INFO("adm1021", 0x4e) }, 0  },
-	{ { I2C_BOARD_INFO("lm63", 0x18) }, 0  },
-	{ { I2C_BOARD_INFO("lm63", 0x4e) }, 0  },
-	{ }
-};
-
-void
-nouveau_therm_ic_ctor(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_bios *bios = nouveau_bios(therm);
-	struct nouveau_i2c *i2c = nouveau_i2c(therm);
-	struct nvbios_extdev_func extdev_entry;
-
-	if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
-		struct nouveau_i2c_board_info board[] = {
-		  { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
-		  { }
-		};
-
-		i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
-			      board, probe_monitoring_device, therm);
-		if (priv->ic)
-			return;
-	}
-
-	if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
-		struct nouveau_i2c_board_info board[] = {
-		  { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
-		  { }
-		};
-
-		i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
-			      board, probe_monitoring_device, therm);
-		if (priv->ic)
-			return;
-	}
-
-	/* The vbios doesn't provide the address of an exisiting monitoring
-	   device. Let's try our static list.
-	 */
-	i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
-		      nv_board_infos, probe_monitoring_device, therm);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
deleted file mode 100644
index 002e51b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Martin Peres
- */
-
-#include "priv.h"
-
-struct nv40_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
-
-static enum nv40_sensor_style
-nv40_sensor_style(struct nouveau_therm *therm)
-{
-	struct nouveau_device *device = nv_device(therm);
-
-	switch (device->chipset) {
-	case 0x43:
-	case 0x44:
-	case 0x4a:
-	case 0x47:
-		return OLD_STYLE;
-
-	case 0x46:
-	case 0x49:
-	case 0x4b:
-	case 0x4e:
-	case 0x4c:
-	case 0x67:
-	case 0x68:
-	case 0x63:
-		return NEW_STYLE;
-	default:
-		return INVALID_STYLE;
-	}
-}
-
-static int
-nv40_sensor_setup(struct nouveau_therm *therm)
-{
-	enum nv40_sensor_style style = nv40_sensor_style(therm);
-
-	/* enable ADC readout and disable the ALARM threshold */
-	if (style == NEW_STYLE) {
-		nv_mask(therm, 0x15b8, 0x80000000, 0);
-		nv_wr32(therm, 0x15b0, 0x80003fff);
-		mdelay(20); /* wait for the temperature to stabilize */
-		return nv_rd32(therm, 0x15b4) & 0x3fff;
-	} else if (style == OLD_STYLE) {
-		nv_wr32(therm, 0x15b0, 0xff);
-		mdelay(20); /* wait for the temperature to stabilize */
-		return nv_rd32(therm, 0x15b4) & 0xff;
-	} else
-		return -ENODEV;
-}
-
-static int
-nv40_temp_get(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	enum nv40_sensor_style style = nv40_sensor_style(therm);
-	int core_temp;
-
-	if (style == NEW_STYLE) {
-		nv_wr32(therm, 0x15b0, 0x80003fff);
-		core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
-	} else if (style == OLD_STYLE) {
-		nv_wr32(therm, 0x15b0, 0xff);
-		core_temp = nv_rd32(therm, 0x15b4) & 0xff;
-	} else
-		return -ENODEV;
-
-	/* if the slope or the offset is unset, do no use the sensor */
-	if (!sensor->slope_div || !sensor->slope_mult ||
-	    !sensor->offset_num || !sensor->offset_den)
-	    return -ENODEV;
-
-	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
-	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
-	core_temp = core_temp + sensor->offset_constant - 8;
-
-	/* reserve negative temperatures for errors */
-	if (core_temp < 0)
-		core_temp = 0;
-
-	return core_temp;
-}
-
-static int
-nv40_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
-	u32 mask = enable ? 0x80000000 : 0x0000000;
-	if      (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask);
-	else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask);
-	else {
-		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static int
-nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
-	if (line == 2) {
-		u32 reg = nv_rd32(therm, 0x0010f0);
-		if (reg & 0x80000000) {
-			*duty = (reg & 0x7fff0000) >> 16;
-			*divs = (reg & 0x00007fff);
-			return 0;
-		}
-	} else
-	if (line == 9) {
-		u32 reg = nv_rd32(therm, 0x0015f4);
-		if (reg & 0x80000000) {
-			*divs = nv_rd32(therm, 0x0015f8);
-			*duty = (reg & 0x7fffffff);
-			return 0;
-		}
-	} else {
-		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
-		return -ENODEV;
-	}
-
-	return -EINVAL;
-}
-
-static int
-nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
-	if (line == 2) {
-		nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
-	} else
-	if (line == 9) {
-		nv_wr32(therm, 0x0015f8, divs);
-		nv_mask(therm, 0x0015f4, 0x7fffffff, duty);
-	} else {
-		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-void
-nv40_therm_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_therm *therm = nouveau_therm(subdev);
-	uint32_t stat = nv_rd32(therm, 0x1100);
-
-	/* traitement */
-
-	/* ack all IRQs */
-	nv_wr32(therm, 0x1100, 0x70000);
-
-	nv_error(therm, "THERM received an IRQ: stat = %x\n", stat);
-}
-
-static int
-nv40_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv40_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl;
-	priv->base.base.pwm_get = nv40_fan_pwm_get;
-	priv->base.base.pwm_set = nv40_fan_pwm_set;
-	priv->base.base.temp_get = nv40_temp_get;
-	priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
-	nv_subdev(priv)->intr = nv40_therm_intr;
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-static int
-nv40_therm_init(struct nouveau_object *object)
-{
-	struct nouveau_therm *therm = (void *)object;
-
-	nv40_sensor_setup(therm);
-
-	return _nouveau_therm_init(object);
-}
-
-struct nouveau_oclass
-nv40_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nv40_therm_init,
-		.fini = _nouveau_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
deleted file mode 100644
index 321db92..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Martin Peres
- */
-
-#include "priv.h"
-
-struct nv50_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-static int
-pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx)
-{
-	if (*line == 0x04) {
-		*ctrl = 0x00e100;
-		*line = 4;
-		*indx = 0;
-	} else
-	if (*line == 0x09) {
-		*ctrl = 0x00e100;
-		*line = 9;
-		*indx = 1;
-	} else
-	if (*line == 0x10) {
-		*ctrl = 0x00e28c;
-		*line = 0;
-		*indx = 0;
-	} else {
-		nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-int
-nv50_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
-	u32 data = enable ? 0x00000001 : 0x00000000;
-	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
-	if (ret == 0)
-		nv_mask(therm, ctrl, 0x00010001 << line, data << line);
-	return ret;
-}
-
-int
-nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
-	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
-	if (ret)
-		return ret;
-
-	if (nv_rd32(therm, ctrl) & (1 << line)) {
-		*divs = nv_rd32(therm, 0x00e114 + (id * 8));
-		*duty = nv_rd32(therm, 0x00e118 + (id * 8));
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-int
-nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
-	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
-	if (ret)
-		return ret;
-
-	nv_wr32(therm, 0x00e114 + (id * 8), divs);
-	nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
-	return 0;
-}
-
-int
-nv50_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
-	int chipset = nv_device(therm)->chipset;
-	int crystal = nv_device(therm)->crystal;
-	int pwm_clock;
-
-	/* determine the PWM source clock */
-	if (chipset > 0x50 && chipset < 0x94) {
-		u8 pwm_div = nv_rd32(therm, 0x410c);
-		if (nv_rd32(therm, 0xc040) & 0x800000) {
-			/* Use the HOST clock (100 MHz)
-			* Where does this constant(2.4) comes from? */
-			pwm_clock = (100000000 >> pwm_div) * 10 / 24;
-		} else {
-			/* Where does this constant(20) comes from? */
-			pwm_clock = (crystal * 1000) >> pwm_div;
-			pwm_clock /= 20;
-		}
-	} else {
-		pwm_clock = (crystal * 1000) / 20;
-	}
-
-	return pwm_clock;
-}
-
-static void
-nv50_sensor_setup(struct nouveau_therm *therm)
-{
-	nv_mask(therm, 0x20010, 0x40000000, 0x0);
-	mdelay(20); /* wait for the temperature to stabilize */
-}
-
-static int
-nv50_temp_get(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	int core_temp;
-
-	core_temp = nv_rd32(therm, 0x20014) & 0x3fff;
-
-	/* if the slope or the offset is unset, do no use the sensor */
-	if (!sensor->slope_div || !sensor->slope_mult ||
-	    !sensor->offset_num || !sensor->offset_den)
-	    return -ENODEV;
-
-	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
-	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
-	core_temp = core_temp + sensor->offset_constant - 8;
-
-	/* reserve negative temperatures for errors */
-	if (core_temp < 0)
-		core_temp = 0;
-
-	return core_temp;
-}
-
-static int
-nv50_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv50_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
-	priv->base.base.pwm_get = nv50_fan_pwm_get;
-	priv->base.base.pwm_set = nv50_fan_pwm_set;
-	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
-	priv->base.base.temp_get = nv50_temp_get;
-	priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
-	nv_subdev(priv)->intr = nv40_therm_intr;
-
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-static int
-nv50_therm_init(struct nouveau_object *object)
-{
-	struct nouveau_therm *therm = (void *)object;
-
-	nv50_sensor_setup(therm);
-
-	return _nouveau_therm_init(object);
-}
-
-struct nouveau_oclass
-nv50_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nv50_therm_init,
-		.fini = _nouveau_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
deleted file mode 100644
index 14e2e09..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- * 	    Martin Peres
- */
-
-#include "priv.h"
-#include <subdev/fuse.h>
-
-struct nv84_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-int
-nv84_temp_get(struct nouveau_therm *therm)
-{
-	struct nouveau_fuse *fuse = nouveau_fuse(therm);
-
-	if (nv_ro32(fuse, 0x1a8) == 1)
-		return nv_rd32(therm, 0x20400);
-	else
-		return -ENODEV;
-}
-
-void
-nv84_sensor_setup(struct nouveau_therm *therm)
-{
-	struct nouveau_fuse *fuse = nouveau_fuse(therm);
-
-	/* enable temperature reading for cards with insane defaults */
-	if (nv_ro32(fuse, 0x1a8) == 1) {
-		nv_mask(therm, 0x20008, 0x80008000, 0x80000000);
-		nv_mask(therm, 0x2000c, 0x80000003, 0x00000000);
-		mdelay(20); /* wait for the temperature to stabilize */
-	}
-}
-
-static void
-nv84_therm_program_alarms(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
-	/* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */
-	nv_wr32(therm, 0x20000, 0x000003ff);
-
-	/* shutdown: The computer should be shutdown when reached */
-	nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis);
-	nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp);
-
-	/* THRS_1 : fan boost*/
-	nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp);
-
-	/* THRS_2 : critical */
-	nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp);
-
-	/* THRS_4 : down clock */
-	nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp);
-	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-
-	nv_debug(therm,
-		 "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
-		 sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
-		 sensor->thrs_down_clock.temp,
-		 sensor->thrs_down_clock.hysteresis,
-		 sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
-		 sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
-
-}
-
-/* must be called with alarm_program_lock taken ! */
-static void
-nv84_therm_threshold_hyst_emulation(struct nouveau_therm *therm,
-				   uint32_t thrs_reg, u8 status_bit,
-				   const struct nvbios_therm_threshold *thrs,
-				   enum nouveau_therm_thrs thrs_name)
-{
-	enum nouveau_therm_thrs_direction direction;
-	enum nouveau_therm_thrs_state prev_state, new_state;
-	int temp, cur;
-
-	prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name);
-	temp = nv_rd32(therm, thrs_reg);
-
-	/* program the next threshold */
-	if (temp == thrs->temp) {
-		nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis);
-		new_state = NOUVEAU_THERM_THRS_HIGHER;
-	} else {
-		nv_wr32(therm, thrs_reg, thrs->temp);
-		new_state = NOUVEAU_THERM_THRS_LOWER;
-	}
-
-	/* fix the state (in case someone reprogrammed the alarms) */
-	cur = therm->temp_get(therm);
-	if (new_state == NOUVEAU_THERM_THRS_LOWER && cur > thrs->temp)
-		new_state = NOUVEAU_THERM_THRS_HIGHER;
-	else if (new_state == NOUVEAU_THERM_THRS_HIGHER &&
-		cur < thrs->temp - thrs->hysteresis)
-		new_state = NOUVEAU_THERM_THRS_LOWER;
-	nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
-
-	/* find the direction */
-	if (prev_state < new_state)
-		direction = NOUVEAU_THERM_THRS_RISING;
-	else if (prev_state > new_state)
-		direction = NOUVEAU_THERM_THRS_FALLING;
-	else
-		return;
-
-	/* advertise a change in direction */
-	nouveau_therm_sensor_event(therm, thrs_name, direction);
-}
-
-static void
-nv84_therm_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_therm *therm = nouveau_therm(subdev);
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	unsigned long flags;
-	uint32_t intr;
-
-	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
-	intr = nv_rd32(therm, 0x20100) & 0x3ff;
-
-	/* THRS_4: downclock */
-	if (intr & 0x002) {
-		nv84_therm_threshold_hyst_emulation(therm, 0x20414, 24,
-						  &sensor->thrs_down_clock,
-						  NOUVEAU_THERM_THRS_DOWNCLOCK);
-		intr &= ~0x002;
-	}
-
-	/* shutdown */
-	if (intr & 0x004) {
-		nv84_therm_threshold_hyst_emulation(therm, 0x20480, 20,
-						   &sensor->thrs_shutdown,
-						   NOUVEAU_THERM_THRS_SHUTDOWN);
-		intr &= ~0x004;
-	}
-
-	/* THRS_1 : fan boost */
-	if (intr & 0x008) {
-		nv84_therm_threshold_hyst_emulation(therm, 0x204c4, 21,
-						   &sensor->thrs_fan_boost,
-						   NOUVEAU_THERM_THRS_FANBOOST);
-		intr &= ~0x008;
-	}
-
-	/* THRS_2 : critical */
-	if (intr & 0x010) {
-		nv84_therm_threshold_hyst_emulation(therm, 0x204c0, 22,
-						   &sensor->thrs_critical,
-						   NOUVEAU_THERM_THRS_CRITICAL);
-		intr &= ~0x010;
-	}
-
-	if (intr)
-		nv_error(therm, "unhandled intr 0x%08x\n", intr);
-
-	/* ACK everything */
-	nv_wr32(therm, 0x20100, 0xffffffff);
-	nv_wr32(therm, 0x1100, 0x10000); /* PBUS */
-
-	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-}
-
-static int
-nv84_therm_init(struct nouveau_object *object)
-{
-	struct nv84_therm_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_therm_init(&priv->base.base);
-	if (ret)
-		return ret;
-
-	nv84_sensor_setup(&priv->base.base);
-
-	return 0;
-}
-
-static int
-nv84_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv84_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
-	priv->base.base.pwm_get = nv50_fan_pwm_get;
-	priv->base.base.pwm_set = nv50_fan_pwm_set;
-	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
-	priv->base.base.temp_get = nv84_temp_get;
-	priv->base.sensor.program_alarms = nv84_therm_program_alarms;
-	nv_subdev(priv)->intr = nv84_therm_intr;
-
-	/* init the thresholds */
-	nouveau_therm_sensor_set_threshold_state(&priv->base.base,
-						 NOUVEAU_THERM_THRS_SHUTDOWN,
-						 NOUVEAU_THERM_THRS_LOWER);
-	nouveau_therm_sensor_set_threshold_state(&priv->base.base,
-						 NOUVEAU_THERM_THRS_FANBOOST,
-						 NOUVEAU_THERM_THRS_LOWER);
-	nouveau_therm_sensor_set_threshold_state(&priv->base.base,
-						 NOUVEAU_THERM_THRS_CRITICAL,
-						 NOUVEAU_THERM_THRS_LOWER);
-	nouveau_therm_sensor_set_threshold_state(&priv->base.base,
-						 NOUVEAU_THERM_THRS_DOWNCLOCK,
-						 NOUVEAU_THERM_THRS_LOWER);
-
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-int
-nv84_therm_fini(struct nouveau_object *object, bool suspend)
-{
-	/* Disable PTherm IRQs */
-	nv_wr32(object, 0x20000, 0x00000000);
-
-	/* ACK all PTherm IRQs */
-	nv_wr32(object, 0x20100, 0xffffffff);
-	nv_wr32(object, 0x1100, 0x10000); /* PBUS */
-
-	return _nouveau_therm_fini(object, suspend);
-}
-
-struct nouveau_oclass
-nv84_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0x84),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv84_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nv84_therm_init,
-		.fini = nv84_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
deleted file mode 100644
index 7893357..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/gpio.h>
-
-#include "priv.h"
-
-struct nva3_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-int
-nva3_therm_fan_sense(struct nouveau_therm *therm)
-{
-	u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff;
-	u32 ctrl = nv_rd32(therm, 0x00e720);
-	if (ctrl & 0x00000001)
-		return tach * 60 / 2;
-	return -ENODEV;
-}
-
-static int
-nva3_therm_init(struct nouveau_object *object)
-{
-	struct nva3_therm_priv *priv = (void *)object;
-	struct dcb_gpio_func *tach = &priv->base.fan->tach;
-	int ret;
-
-	ret = nouveau_therm_init(&priv->base.base);
-	if (ret)
-		return ret;
-
-	nv84_sensor_setup(&priv->base.base);
-
-	/* enable fan tach, count revolutions per-second */
-	nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
-	if (tach->func != DCB_GPIO_UNUSED) {
-		nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
-		nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16);
-		nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
-	}
-	nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
-
-	return 0;
-}
-
-static int
-nva3_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nva3_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
-	priv->base.base.pwm_get = nv50_fan_pwm_get;
-	priv->base.base.pwm_set = nv50_fan_pwm_set;
-	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
-	priv->base.base.temp_get = nv84_temp_get;
-	priv->base.base.fan_sense = nva3_therm_fan_sense;
-	priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-nva3_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0xa3),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nva3_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nva3_therm_init,
-		.fini = nv84_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
deleted file mode 100644
index b70f7cc..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-struct nvd0_therm_priv {
-	struct nouveau_therm_priv base;
-};
-
-static int
-pwm_info(struct nouveau_therm *therm, int line)
-{
-	u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
-
-	switch (gpio & 0x000000c0) {
-	case 0x00000000: /* normal mode, possibly pwm forced off by us */
-	case 0x00000040: /* nvio special */
-		switch (gpio & 0x0000001f) {
-		case 0x00: return 2;
-		case 0x19: return 1;
-		case 0x1c: return 0;
-		case 0x1e: return 2;
-		default:
-			break;
-		}
-	default:
-		break;
-	}
-
-	nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio);
-	return -ENODEV;
-}
-
-static int
-nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
-	u32 data = enable ? 0x00000040 : 0x00000000;
-	int indx = pwm_info(therm, line);
-	if (indx < 0)
-		return indx;
-	else if (indx < 2)
-		nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
-	/* nothing to do for indx == 2, it seems hardwired to PTHERM */
-	return 0;
-}
-
-static int
-nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
-	int indx = pwm_info(therm, line);
-	if (indx < 0)
-		return indx;
-	else if (indx < 2) {
-		if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
-			*divs = nv_rd32(therm, 0x00e114 + (indx * 8));
-			*duty = nv_rd32(therm, 0x00e118 + (indx * 8));
-			return 0;
-		}
-	} else if (indx == 2) {
-		*divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
-		*duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static int
-nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
-	int indx = pwm_info(therm, line);
-	if (indx < 0)
-		return indx;
-	else if (indx < 2) {
-		nv_wr32(therm, 0x00e114 + (indx * 8), divs);
-		nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
-	} else if (indx == 2) {
-		nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
-		nv_wr32(therm, 0x0200dc, duty | 0x40000000);
-	}
-	return 0;
-}
-
-static int
-nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
-	int indx = pwm_info(therm, line);
-	if (indx < 0)
-		return 0;
-	else if (indx < 2)
-		return (nv_device(therm)->crystal * 1000) / 20;
-	else
-		return nv_device(therm)->crystal * 1000 / 10;
-}
-
-int
-nvd0_therm_init(struct nouveau_object *object)
-{
-	struct nvd0_therm_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_therm_init(&priv->base.base);
-	if (ret)
-		return ret;
-
-	/* enable fan tach, count revolutions per-second */
-	nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
-	if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) {
-		nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line);
-		nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
-		nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
-	}
-	nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
-
-	return 0;
-}
-
-static int
-nvd0_therm_ctor(struct nouveau_object *parent,
-		struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvd0_therm_priv *priv;
-	int ret;
-
-	ret = nouveau_therm_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv84_sensor_setup(&priv->base.base);
-
-	priv->base.base.pwm_ctrl = nvd0_fan_pwm_ctrl;
-	priv->base.base.pwm_get = nvd0_fan_pwm_get;
-	priv->base.base.pwm_set = nvd0_fan_pwm_set;
-	priv->base.base.pwm_clock = nvd0_fan_pwm_clock;
-	priv->base.base.temp_get = nv84_temp_get;
-	priv->base.base.fan_sense = nva3_therm_fan_sense;
-	priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
-	return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-nvd0_therm_oclass = {
-	.handle = NV_SUBDEV(THERM, 0xd0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvd0_therm_ctor,
-		.dtor = _nouveau_therm_dtor,
-		.init = nvd0_therm_init,
-		.fini = nv84_therm_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
deleted file mode 100644
index 7dba8c2..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef __NVTHERM_PRIV_H__
-#define __NVTHERM_PRIV_H__
-
-/*
- * Copyright 2012 The Nouveau community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/therm.h>
-
-#include <subdev/bios/extdev.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/perf.h>
-#include <subdev/bios/therm.h>
-#include <subdev/timer.h>
-
-struct nouveau_fan {
-	struct nouveau_therm *parent;
-	const char *type;
-
-	struct nvbios_therm_fan bios;
-	struct nvbios_perf_fan perf;
-
-	struct nouveau_alarm alarm;
-	spinlock_t lock;
-	int percent;
-
-	int (*get)(struct nouveau_therm *therm);
-	int (*set)(struct nouveau_therm *therm, int percent);
-
-	struct dcb_gpio_func tach;
-};
-
-enum nouveau_therm_thrs_direction {
-	NOUVEAU_THERM_THRS_FALLING = 0,
-	NOUVEAU_THERM_THRS_RISING = 1
-};
-
-enum nouveau_therm_thrs_state {
-	NOUVEAU_THERM_THRS_LOWER = 0,
-	NOUVEAU_THERM_THRS_HIGHER = 1
-};
-
-enum nouveau_therm_thrs {
-	NOUVEAU_THERM_THRS_FANBOOST = 0,
-	NOUVEAU_THERM_THRS_DOWNCLOCK = 1,
-	NOUVEAU_THERM_THRS_CRITICAL = 2,
-	NOUVEAU_THERM_THRS_SHUTDOWN = 3,
-	NOUVEAU_THERM_THRS_NR
-};
-
-struct nouveau_therm_priv {
-	struct nouveau_therm base;
-
-	/* automatic thermal management */
-	struct nouveau_alarm alarm;
-	spinlock_t lock;
-	struct nouveau_therm_trip_point *last_trip;
-	int mode;
-	int cstate;
-	int suspend;
-
-	/* bios */
-	struct nvbios_therm_sensor bios_sensor;
-
-	/* fan priv */
-	struct nouveau_fan *fan;
-
-	/* alarms priv */
-	struct {
-		spinlock_t alarm_program_lock;
-		struct nouveau_alarm therm_poll_alarm;
-		enum nouveau_therm_thrs_state alarm_state[NOUVEAU_THERM_THRS_NR];
-		void (*program_alarms)(struct nouveau_therm *);
-	} sensor;
-
-	/* what should be done if the card overheats */
-	struct {
-		void (*downclock)(struct nouveau_therm *, bool active);
-		void (*pause)(struct nouveau_therm *, bool active);
-	} emergency;
-
-	/* ic */
-	struct i2c_client *ic;
-};
-
-int nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode);
-int nouveau_therm_attr_get(struct nouveau_therm *therm,
-		       enum nouveau_therm_attr_type type);
-int nouveau_therm_attr_set(struct nouveau_therm *therm,
-		       enum nouveau_therm_attr_type type, int value);
-
-void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
-
-int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
-
-int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
-int nouveau_therm_fan_init(struct nouveau_therm *therm);
-int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend);
-int nouveau_therm_fan_get(struct nouveau_therm *therm);
-int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
-int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
-int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent);
-
-int nouveau_therm_fan_sense(struct nouveau_therm *therm);
-
-int nouveau_therm_preinit(struct nouveau_therm *);
-
-int nouveau_therm_sensor_init(struct nouveau_therm *therm);
-int nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend);
-void nouveau_therm_sensor_preinit(struct nouveau_therm *);
-void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
-					     enum nouveau_therm_thrs thrs,
-					     enum nouveau_therm_thrs_state st);
-enum nouveau_therm_thrs_state
-nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm,
-					 enum nouveau_therm_thrs thrs);
-void nouveau_therm_sensor_event(struct nouveau_therm *therm,
-			        enum nouveau_therm_thrs thrs,
-			        enum nouveau_therm_thrs_direction dir);
-void nouveau_therm_program_alarms_polling(struct nouveau_therm *therm);
-
-void nv40_therm_intr(struct nouveau_subdev *);
-int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool);
-int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
-int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
-int nv50_fan_pwm_clock(struct nouveau_therm *, int);
-int nv84_temp_get(struct nouveau_therm *therm);
-void nv84_sensor_setup(struct nouveau_therm *therm);
-int nv84_therm_fini(struct nouveau_object *object, bool suspend);
-
-int nva3_therm_fan_sense(struct nouveau_therm *);
-
-int nvd0_therm_init(struct nouveau_object *object);
-
-int nouveau_fanpwm_create(struct nouveau_therm *, struct dcb_gpio_func *);
-int nouveau_fantog_create(struct nouveau_therm *, struct dcb_gpio_func *);
-int nouveau_fannil_create(struct nouveau_therm *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
deleted file mode 100644
index 6212537..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * 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.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-
-static void
-nouveau_therm_temp_set_defaults(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-
-	priv->bios_sensor.offset_constant = 0;
-
-	priv->bios_sensor.thrs_fan_boost.temp = 90;
-	priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
-
-	priv->bios_sensor.thrs_down_clock.temp = 95;
-	priv->bios_sensor.thrs_down_clock.hysteresis = 3;
-
-	priv->bios_sensor.thrs_critical.temp = 105;
-	priv->bios_sensor.thrs_critical.hysteresis = 5;
-
-	priv->bios_sensor.thrs_shutdown.temp = 135;
-	priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
-}
-
-
-static void
-nouveau_therm_temp_safety_checks(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *s = &priv->bios_sensor;
-
-	/* enforce a minimum hysteresis on thresholds */
-	s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2);
-	s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2);
-	s->thrs_critical.hysteresis = max_t(u8, s->thrs_critical.hysteresis, 2);
-	s->thrs_shutdown.hysteresis = max_t(u8, s->thrs_shutdown.hysteresis, 2);
-}
-
-/* must be called with alarm_program_lock taken ! */
-void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
-					     enum nouveau_therm_thrs thrs,
-					     enum nouveau_therm_thrs_state st)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	priv->sensor.alarm_state[thrs] = st;
-}
-
-/* must be called with alarm_program_lock taken ! */
-enum nouveau_therm_thrs_state
-nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm,
-					 enum nouveau_therm_thrs thrs)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	return priv->sensor.alarm_state[thrs];
-}
-
-static void
-nv_poweroff_work(struct work_struct *work)
-{
-	orderly_poweroff(true);
-	kfree(work);
-}
-
-void nouveau_therm_sensor_event(struct nouveau_therm *therm,
-			        enum nouveau_therm_thrs thrs,
-			        enum nouveau_therm_thrs_direction dir)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	bool active;
-	const char *thresolds[] = {
-		"fanboost", "downclock", "critical", "shutdown"
-	};
-	int temperature = therm->temp_get(therm);
-
-	if (thrs < 0 || thrs > 3)
-		return;
-
-	if (dir == NOUVEAU_THERM_THRS_FALLING)
-		nv_info(therm, "temperature (%i C) went below the '%s' threshold\n",
-			temperature, thresolds[thrs]);
-	else
-		nv_info(therm, "temperature (%i C) hit the '%s' threshold\n",
-			temperature, thresolds[thrs]);
-
-	active = (dir == NOUVEAU_THERM_THRS_RISING);
-	switch (thrs) {
-	case NOUVEAU_THERM_THRS_FANBOOST:
-		if (active) {
-			nouveau_therm_fan_set(therm, true, 100);
-			nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
-		}
-		break;
-	case NOUVEAU_THERM_THRS_DOWNCLOCK:
-		if (priv->emergency.downclock)
-			priv->emergency.downclock(therm, active);
-		break;
-	case NOUVEAU_THERM_THRS_CRITICAL:
-		if (priv->emergency.pause)
-			priv->emergency.pause(therm, active);
-		break;
-	case NOUVEAU_THERM_THRS_SHUTDOWN:
-		if (active) {
-			struct work_struct *work;
-
-			work = kmalloc(sizeof(*work), GFP_ATOMIC);
-			if (work) {
-				INIT_WORK(work, nv_poweroff_work);
-				schedule_work(work);
-			}
-		}
-		break;
-	case NOUVEAU_THERM_THRS_NR:
-		break;
-	}
-
-}
-
-/* must be called with alarm_program_lock taken ! */
-static void
-nouveau_therm_threshold_hyst_polling(struct nouveau_therm *therm,
-				   const struct nvbios_therm_threshold *thrs,
-				   enum nouveau_therm_thrs thrs_name)
-{
-	enum nouveau_therm_thrs_direction direction;
-	enum nouveau_therm_thrs_state prev_state, new_state;
-	int temp = therm->temp_get(therm);
-
-	prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name);
-
-	if (temp >= thrs->temp && prev_state == NOUVEAU_THERM_THRS_LOWER) {
-		direction = NOUVEAU_THERM_THRS_RISING;
-		new_state = NOUVEAU_THERM_THRS_HIGHER;
-	} else if (temp <= thrs->temp - thrs->hysteresis &&
-			prev_state == NOUVEAU_THERM_THRS_HIGHER) {
-		direction = NOUVEAU_THERM_THRS_FALLING;
-		new_state = NOUVEAU_THERM_THRS_LOWER;
-	} else
-		return; /* nothing to do */
-
-	nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
-	nouveau_therm_sensor_event(therm, thrs_name, direction);
-}
-
-static void
-alarm_timer_callback(struct nouveau_alarm *alarm)
-{
-	struct nouveau_therm_priv *priv =
-	container_of(alarm, struct nouveau_therm_priv, sensor.therm_poll_alarm);
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-	struct nouveau_timer *ptimer = nouveau_timer(priv);
-	struct nouveau_therm *therm = &priv->base;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
-	nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
-					     NOUVEAU_THERM_THRS_FANBOOST);
-
-	nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock,
-					     NOUVEAU_THERM_THRS_DOWNCLOCK);
-
-	nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_critical,
-					     NOUVEAU_THERM_THRS_CRITICAL);
-
-	nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown,
-					     NOUVEAU_THERM_THRS_SHUTDOWN);
-
-	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-
-	/* schedule the next poll in one second */
-	if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head))
-		ptimer->alarm(ptimer, 1000000000ULL, alarm);
-}
-
-void
-nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-
-	nv_debug(therm,
-		 "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
-		 sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
-		 sensor->thrs_down_clock.temp,
-		 sensor->thrs_down_clock.hysteresis,
-		 sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
-		 sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
-
-	alarm_timer_callback(&priv->sensor.therm_poll_alarm);
-}
-
-int
-nouveau_therm_sensor_init(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	priv->sensor.program_alarms(therm);
-	return 0;
-}
-
-int
-nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_timer *ptimer = nouveau_timer(therm);
-
-	if (suspend)
-		ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
-	return 0;
-}
-
-void
-nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
-{
-	const char *sensor_avail = "yes";
-
-	if (therm->temp_get(therm) < 0)
-		sensor_avail = "no";
-
-	nv_info(therm, "internal sensor: %s\n", sensor_avail);
-}
-
-int
-nouveau_therm_sensor_ctor(struct nouveau_therm *therm)
-{
-	struct nouveau_therm_priv *priv = (void *)therm;
-	struct nouveau_bios *bios = nouveau_bios(therm);
-
-	nouveau_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback);
-
-	nouveau_therm_temp_set_defaults(therm);
-	if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
-				      &priv->bios_sensor))
-		nv_error(therm, "nvbios_therm_sensor_parse failed\n");
-	nouveau_therm_temp_safety_checks(therm);
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c b/drivers/gpu/drm/nouveau/core/subdev/timer/base.c
deleted file mode 100644
index cf8a0e0..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "subdev/timer.h"
-
-bool
-nouveau_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(obj);
-	u64 time0;
-
-	time0 = ptimer->read(ptimer);
-	do {
-		if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
-			if ((nv_rd32(obj, addr) & mask) == data)
-				return true;
-		} else {
-			if ((nv_ro32(obj, addr) & mask) == data)
-				return true;
-		}
-	} while (ptimer->read(ptimer) - time0 < nsec);
-
-	return false;
-}
-
-bool
-nouveau_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(obj);
-	u64 time0;
-
-	time0 = ptimer->read(ptimer);
-	do {
-		if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
-			if ((nv_rd32(obj, addr) & mask) != data)
-				return true;
-		} else {
-			if ((nv_ro32(obj, addr) & mask) != data)
-				return true;
-		}
-	} while (ptimer->read(ptimer) - time0 < nsec);
-
-	return false;
-}
-
-bool
-nouveau_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(obj);
-	u64 time0;
-
-	time0 = ptimer->read(ptimer);
-	do {
-		if (func(data) == true)
-			return true;
-	} while (ptimer->read(ptimer) - time0 < nsec);
-
-	return false;
-}
-
-void
-nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(obj);
-	ptimer->alarm(ptimer, nsec, alarm);
-}
-
-void
-nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
-{
-	struct nouveau_timer *ptimer = nouveau_timer(obj);
-	ptimer->alarm_cancel(ptimer, alarm);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c
deleted file mode 100644
index 37484db..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static int
-gk20a_timer_init(struct nouveau_object *object)
-{
-	struct nv04_timer_priv *priv = (void *)object;
-	u32 hi = upper_32_bits(priv->suspend_time);
-	u32 lo = lower_32_bits(priv->suspend_time);
-	int ret;
-
-	ret = nouveau_timer_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_debug(priv, "time low        : 0x%08x\n", lo);
-	nv_debug(priv, "time high       : 0x%08x\n", hi);
-
-	/* restore the time before suspend */
-	nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
-	nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_timer_oclass = {
-	.handle = NV_SUBDEV(TIMER, 0xff),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_timer_ctor,
-		.dtor = nv04_timer_dtor,
-		.init = gk20a_timer_init,
-		.fini = nv04_timer_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
deleted file mode 100644
index 240ed0b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static u64
-nv04_timer_read(struct nouveau_timer *ptimer)
-{
-	struct nv04_timer_priv *priv = (void *)ptimer;
-	u32 hi, lo;
-
-	do {
-		hi = nv_rd32(priv, NV04_PTIMER_TIME_1);
-		lo = nv_rd32(priv, NV04_PTIMER_TIME_0);
-	} while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1));
-
-	return ((u64)hi << 32 | lo);
-}
-
-static void
-nv04_timer_alarm_trigger(struct nouveau_timer *ptimer)
-{
-	struct nv04_timer_priv *priv = (void *)ptimer;
-	struct nouveau_alarm *alarm, *atemp;
-	unsigned long flags;
-	LIST_HEAD(exec);
-
-	/* move any due alarms off the pending list */
-	spin_lock_irqsave(&priv->lock, flags);
-	list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) {
-		if (alarm->timestamp <= ptimer->read(ptimer))
-			list_move_tail(&alarm->head, &exec);
-	}
-
-	/* reschedule interrupt for next alarm time */
-	if (!list_empty(&priv->alarms)) {
-		alarm = list_first_entry(&priv->alarms, typeof(*alarm), head);
-		nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp);
-		nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001);
-	} else {
-		nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* execute any pending alarm handlers */
-	list_for_each_entry_safe(alarm, atemp, &exec, head) {
-		list_del_init(&alarm->head);
-		alarm->func(alarm);
-	}
-}
-
-static void
-nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
-		 struct nouveau_alarm *alarm)
-{
-	struct nv04_timer_priv *priv = (void *)ptimer;
-	struct nouveau_alarm *list;
-	unsigned long flags;
-
-	alarm->timestamp = ptimer->read(ptimer) + time;
-
-	/* append new alarm to list, in soonest-alarm-first order */
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!time) {
-		if (!list_empty(&alarm->head))
-			list_del(&alarm->head);
-	} else {
-		list_for_each_entry(list, &priv->alarms, head) {
-			if (list->timestamp > alarm->timestamp)
-				break;
-		}
-		list_add_tail(&alarm->head, &list->head);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* process pending alarms */
-	nv04_timer_alarm_trigger(ptimer);
-}
-
-static void
-nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
-			struct nouveau_alarm *alarm)
-{
-	struct nv04_timer_priv *priv = (void *)ptimer;
-	unsigned long flags;
-	spin_lock_irqsave(&priv->lock, flags);
-	list_del_init(&alarm->head);
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nv04_timer_intr(struct nouveau_subdev *subdev)
-{
-	struct nv04_timer_priv *priv = (void *)subdev;
-	u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0);
-
-	if (stat & 0x00000001) {
-		nv04_timer_alarm_trigger(&priv->base);
-		nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001);
-		stat &= ~0x00000001;
-	}
-
-	if (stat) {
-		nv_error(priv, "unknown stat 0x%08x\n", stat);
-		nv_wr32(priv, NV04_PTIMER_INTR_0, stat);
-	}
-}
-
-int
-nv04_timer_fini(struct nouveau_object *object, bool suspend)
-{
-	struct nv04_timer_priv *priv = (void *)object;
-	if (suspend)
-		priv->suspend_time = nv04_timer_read(&priv->base);
-	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
-	return nouveau_timer_fini(&priv->base, suspend);
-}
-
-static int
-nv04_timer_init(struct nouveau_object *object)
-{
-	struct nouveau_device *device = nv_device(object);
-	struct nv04_timer_priv *priv = (void *)object;
-	u32 m = 1, f, n, d, lo, hi;
-	int ret;
-
-	ret = nouveau_timer_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* aim for 31.25MHz, which gives us nanosecond timestamps */
-	d = 1000000 / 32;
-
-	/* determine base clock for timer source */
-#if 0 /*XXX*/
-	if (device->chipset < 0x40) {
-		n = nouveau_hw_get_clock(device, PLL_CORE);
-	} else
-#endif
-	if (device->chipset <= 0x40) {
-		/*XXX: figure this out */
-		f = -1;
-		n = 0;
-	} else {
-		f = device->crystal;
-		n = f;
-		while (n < (d * 2)) {
-			n += (n / m);
-			m++;
-		}
-
-		nv_wr32(priv, 0x009220, m - 1);
-	}
-
-	if (!n) {
-		nv_warn(priv, "unknown input clock freq\n");
-		if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) ||
-		    !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) {
-			nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1);
-			nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1);
-		}
-		return 0;
-	}
-
-	/* reduce ratio to acceptable values */
-	while (((n % 5) == 0) && ((d % 5) == 0)) {
-		n /= 5;
-		d /= 5;
-	}
-
-	while (((n % 2) == 0) && ((d % 2) == 0)) {
-		n /= 2;
-		d /= 2;
-	}
-
-	while (n > 0xffff || d > 0xffff) {
-		n >>= 1;
-		d >>= 1;
-	}
-
-	/* restore the time before suspend */
-	lo = priv->suspend_time;
-	hi = (priv->suspend_time >> 32);
-
-	nv_debug(priv, "input frequency : %dHz\n", f);
-	nv_debug(priv, "input multiplier: %d\n", m);
-	nv_debug(priv, "numerator       : 0x%08x\n", n);
-	nv_debug(priv, "denominator     : 0x%08x\n", d);
-	nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
-	nv_debug(priv, "time low        : 0x%08x\n", lo);
-	nv_debug(priv, "time high       : 0x%08x\n", hi);
-
-	nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
-	nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
-	nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
-	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
-	nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
-	nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
-
-	return 0;
-}
-
-void
-nv04_timer_dtor(struct nouveau_object *object)
-{
-	struct nv04_timer_priv *priv = (void *)object;
-	return nouveau_timer_destroy(&priv->base);
-}
-
-int
-nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv04_timer_priv *priv;
-	int ret;
-
-	ret = nouveau_timer_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.base.intr = nv04_timer_intr;
-	priv->base.read = nv04_timer_read;
-	priv->base.alarm = nv04_timer_alarm;
-	priv->base.alarm_cancel = nv04_timer_alarm_cancel;
-	priv->suspend_time = 0;
-
-	INIT_LIST_HEAD(&priv->alarms);
-	spin_lock_init(&priv->lock);
-	return 0;
-}
-
-struct nouveau_oclass
-nv04_timer_oclass = {
-	.handle = NV_SUBDEV(TIMER, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_timer_ctor,
-		.dtor = nv04_timer_dtor,
-		.init = nv04_timer_init,
-		.fini = nv04_timer_fini,
-	}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h
deleted file mode 100644
index 4bc1526..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __NVKM_TIMER_NV04_H__
-#define __NVKM_TIMER_NV04_H__
-
-#include "priv.h"
-
-#define NV04_PTIMER_INTR_0      0x009100
-#define NV04_PTIMER_INTR_EN_0   0x009140
-#define NV04_PTIMER_NUMERATOR   0x009200
-#define NV04_PTIMER_DENOMINATOR 0x009210
-#define NV04_PTIMER_TIME_0      0x009400
-#define NV04_PTIMER_TIME_1      0x009410
-#define NV04_PTIMER_ALARM_0     0x009420
-
-struct nv04_timer_priv {
-	struct nouveau_timer base;
-	struct list_head alarms;
-	spinlock_t lock;
-	u64 suspend_time;
-};
-
-int  nv04_timer_ctor(struct nouveau_object *, struct nouveau_object *,
-		     struct nouveau_oclass *, void *, u32,
-		     struct nouveau_object **);
-void nv04_timer_dtor(struct nouveau_object *);
-int  nv04_timer_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h
deleted file mode 100644
index 799dae3..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __NVKM_TIMER_PRIV_H__
-#define __NVKM_TIMER_PRIV_H__
-
-#include <subdev/timer.h>
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
deleted file mode 100644
index f75a683..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/mm.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-void
-nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node)
-{
-	struct nouveau_vm *vm = vma->vm;
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	struct nouveau_mm_node *r;
-	int big = vma->node->type != vmm->spg_shift;
-	u32 offset = vma->node->offset + (delta >> 12);
-	u32 bits = vma->node->type - 12;
-	u32 pde  = (offset >> vmm->pgt_bits) - vm->fpde;
-	u32 pte  = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
-	u32 max  = 1 << (vmm->pgt_bits - bits);
-	u32 end, len;
-
-	delta = 0;
-	list_for_each_entry(r, &node->regions, rl_entry) {
-		u64 phys = (u64)r->offset << 12;
-		u32 num  = r->length >> bits;
-
-		while (num) {
-			struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
-			end = (pte + num);
-			if (unlikely(end >= max))
-				end = max;
-			len = end - pte;
-
-			vmm->map(vma, pgt, node, pte, len, phys, delta);
-
-			num -= len;
-			pte += len;
-			if (unlikely(end >= max)) {
-				phys += len << (bits + 12);
-				pde++;
-				pte = 0;
-			}
-
-			delta += (u64)len << vma->node->type;
-		}
-	}
-
-	vmm->flush(vm);
-}
-
-static void
-nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
-			struct nouveau_mem *mem)
-{
-	struct nouveau_vm *vm = vma->vm;
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	int big = vma->node->type != vmm->spg_shift;
-	u32 offset = vma->node->offset + (delta >> 12);
-	u32 bits = vma->node->type - 12;
-	u32 num  = length >> vma->node->type;
-	u32 pde  = (offset >> vmm->pgt_bits) - vm->fpde;
-	u32 pte  = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
-	u32 max  = 1 << (vmm->pgt_bits - bits);
-	unsigned m, sglen;
-	u32 end, len;
-	int i;
-	struct scatterlist *sg;
-
-	for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
-		struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-		sglen = sg_dma_len(sg) >> PAGE_SHIFT;
-
-		end = pte + sglen;
-		if (unlikely(end >= max))
-			end = max;
-		len = end - pte;
-
-		for (m = 0; m < len; m++) {
-			dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-
-			vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
-			num--;
-			pte++;
-
-			if (num == 0)
-				goto finish;
-		}
-		if (unlikely(end >= max)) {
-			pde++;
-			pte = 0;
-		}
-		if (m < sglen) {
-			for (; m < sglen; m++) {
-				dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-
-				vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
-				num--;
-				pte++;
-				if (num == 0)
-					goto finish;
-			}
-		}
-
-	}
-finish:
-	vmm->flush(vm);
-}
-
-static void
-nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
-		  struct nouveau_mem *mem)
-{
-	struct nouveau_vm *vm = vma->vm;
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	dma_addr_t *list = mem->pages;
-	int big = vma->node->type != vmm->spg_shift;
-	u32 offset = vma->node->offset + (delta >> 12);
-	u32 bits = vma->node->type - 12;
-	u32 num  = length >> vma->node->type;
-	u32 pde  = (offset >> vmm->pgt_bits) - vm->fpde;
-	u32 pte  = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
-	u32 max  = 1 << (vmm->pgt_bits - bits);
-	u32 end, len;
-
-	while (num) {
-		struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
-		end = (pte + num);
-		if (unlikely(end >= max))
-			end = max;
-		len = end - pte;
-
-		vmm->map_sg(vma, pgt, mem, pte, len, list);
-
-		num  -= len;
-		pte  += len;
-		list += len;
-		if (unlikely(end >= max)) {
-			pde++;
-			pte = 0;
-		}
-	}
-
-	vmm->flush(vm);
-}
-
-void
-nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
-{
-	if (node->sg)
-		nouveau_vm_map_sg_table(vma, 0, node->size << 12, node);
-	else
-	if (node->pages)
-		nouveau_vm_map_sg(vma, 0, node->size << 12, node);
-	else
-		nouveau_vm_map_at(vma, 0, node);
-}
-
-void
-nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length)
-{
-	struct nouveau_vm *vm = vma->vm;
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	int big = vma->node->type != vmm->spg_shift;
-	u32 offset = vma->node->offset + (delta >> 12);
-	u32 bits = vma->node->type - 12;
-	u32 num  = length >> vma->node->type;
-	u32 pde  = (offset >> vmm->pgt_bits) - vm->fpde;
-	u32 pte  = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
-	u32 max  = 1 << (vmm->pgt_bits - bits);
-	u32 end, len;
-
-	while (num) {
-		struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
-		end = (pte + num);
-		if (unlikely(end >= max))
-			end = max;
-		len = end - pte;
-
-		vmm->unmap(pgt, pte, len);
-
-		num -= len;
-		pte += len;
-		if (unlikely(end >= max)) {
-			pde++;
-			pte = 0;
-		}
-	}
-
-	vmm->flush(vm);
-}
-
-void
-nouveau_vm_unmap(struct nouveau_vma *vma)
-{
-	nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
-}
-
-static void
-nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
-{
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	struct nouveau_vm_pgd *vpgd;
-	struct nouveau_vm_pgt *vpgt;
-	struct nouveau_gpuobj *pgt;
-	u32 pde;
-
-	for (pde = fpde; pde <= lpde; pde++) {
-		vpgt = &vm->pgt[pde - vm->fpde];
-		if (--vpgt->refcount[big])
-			continue;
-
-		pgt = vpgt->obj[big];
-		vpgt->obj[big] = NULL;
-
-		list_for_each_entry(vpgd, &vm->pgd_list, head) {
-			vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
-		}
-
-		mutex_unlock(&nv_subdev(vmm)->mutex);
-		nouveau_gpuobj_ref(NULL, &pgt);
-		mutex_lock(&nv_subdev(vmm)->mutex);
-	}
-}
-
-static int
-nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
-{
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
-	struct nouveau_vm_pgd *vpgd;
-	struct nouveau_gpuobj *pgt;
-	int big = (type != vmm->spg_shift);
-	u32 pgt_size;
-	int ret;
-
-	pgt_size  = (1 << (vmm->pgt_bits + 12)) >> type;
-	pgt_size *= 8;
-
-	mutex_unlock(&nv_subdev(vmm)->mutex);
-	ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &pgt);
-	mutex_lock(&nv_subdev(vmm)->mutex);
-	if (unlikely(ret))
-		return ret;
-
-	/* someone beat us to filling the PDE while we didn't have the lock */
-	if (unlikely(vpgt->refcount[big]++)) {
-		mutex_unlock(&nv_subdev(vmm)->mutex);
-		nouveau_gpuobj_ref(NULL, &pgt);
-		mutex_lock(&nv_subdev(vmm)->mutex);
-		return 0;
-	}
-
-	vpgt->obj[big] = pgt;
-	list_for_each_entry(vpgd, &vm->pgd_list, head) {
-		vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
-	}
-
-	return 0;
-}
-
-int
-nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
-	       u32 access, struct nouveau_vma *vma)
-{
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	u32 align = (1 << page_shift) >> 12;
-	u32 msize = size >> 12;
-	u32 fpde, lpde, pde;
-	int ret;
-
-	mutex_lock(&nv_subdev(vmm)->mutex);
-	ret = nouveau_mm_head(&vm->mm, 0, page_shift, msize, msize, align,
-			     &vma->node);
-	if (unlikely(ret != 0)) {
-		mutex_unlock(&nv_subdev(vmm)->mutex);
-		return ret;
-	}
-
-	fpde = (vma->node->offset >> vmm->pgt_bits);
-	lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
-
-	for (pde = fpde; pde <= lpde; pde++) {
-		struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
-		int big = (vma->node->type != vmm->spg_shift);
-
-		if (likely(vpgt->refcount[big])) {
-			vpgt->refcount[big]++;
-			continue;
-		}
-
-		ret = nouveau_vm_map_pgt(vm, pde, vma->node->type);
-		if (ret) {
-			if (pde != fpde)
-				nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
-			nouveau_mm_free(&vm->mm, &vma->node);
-			mutex_unlock(&nv_subdev(vmm)->mutex);
-			return ret;
-		}
-	}
-	mutex_unlock(&nv_subdev(vmm)->mutex);
-
-	vma->vm = NULL;
-	nouveau_vm_ref(vm, &vma->vm, NULL);
-	vma->offset = (u64)vma->node->offset << 12;
-	vma->access = access;
-	return 0;
-}
-
-void
-nouveau_vm_put(struct nouveau_vma *vma)
-{
-	struct nouveau_vm *vm = vma->vm;
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	u32 fpde, lpde;
-
-	if (unlikely(vma->node == NULL))
-		return;
-	fpde = (vma->node->offset >> vmm->pgt_bits);
-	lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
-
-	mutex_lock(&nv_subdev(vmm)->mutex);
-	nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde);
-	nouveau_mm_free(&vm->mm, &vma->node);
-	mutex_unlock(&nv_subdev(vmm)->mutex);
-
-	nouveau_vm_ref(NULL, &vma->vm, NULL);
-}
-
-int
-nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
-		  u64 mm_offset, u32 block, struct nouveau_vm **pvm)
-{
-	struct nouveau_vm *vm;
-	u64 mm_length = (offset + length) - mm_offset;
-	int ret;
-
-	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
-	if (!vm)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&vm->pgd_list);
-	vm->vmm = vmm;
-	kref_init(&vm->refcount);
-	vm->fpde = offset >> (vmm->pgt_bits + 12);
-	vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
-
-	vm->pgt  = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
-	if (!vm->pgt) {
-		kfree(vm);
-		return -ENOMEM;
-	}
-
-	ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
-			      block >> 12);
-	if (ret) {
-		vfree(vm->pgt);
-		kfree(vm);
-		return ret;
-	}
-
-	*pvm = vm;
-
-	return 0;
-}
-
-int
-nouveau_vm_new(struct nouveau_device *device, u64 offset, u64 length,
-	       u64 mm_offset, struct nouveau_vm **pvm)
-{
-	struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
-	return vmm->create(vmm, offset, length, mm_offset, pvm);
-}
-
-static int
-nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
-{
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	struct nouveau_vm_pgd *vpgd;
-	int i;
-
-	if (!pgd)
-		return 0;
-
-	vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
-	if (!vpgd)
-		return -ENOMEM;
-
-	nouveau_gpuobj_ref(pgd, &vpgd->obj);
-
-	mutex_lock(&nv_subdev(vmm)->mutex);
-	for (i = vm->fpde; i <= vm->lpde; i++)
-		vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
-	list_add(&vpgd->head, &vm->pgd_list);
-	mutex_unlock(&nv_subdev(vmm)->mutex);
-	return 0;
-}
-
-static void
-nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
-{
-	struct nouveau_vmmgr *vmm = vm->vmm;
-	struct nouveau_vm_pgd *vpgd, *tmp;
-	struct nouveau_gpuobj *pgd = NULL;
-
-	if (!mpgd)
-		return;
-
-	mutex_lock(&nv_subdev(vmm)->mutex);
-	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
-		if (vpgd->obj == mpgd) {
-			pgd = vpgd->obj;
-			list_del(&vpgd->head);
-			kfree(vpgd);
-			break;
-		}
-	}
-	mutex_unlock(&nv_subdev(vmm)->mutex);
-
-	nouveau_gpuobj_ref(NULL, &pgd);
-}
-
-static void
-nouveau_vm_del(struct kref *kref)
-{
-	struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
-	struct nouveau_vm_pgd *vpgd, *tmp;
-
-	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
-		nouveau_vm_unlink(vm, vpgd->obj);
-	}
-
-	nouveau_mm_fini(&vm->mm);
-	vfree(vm->pgt);
-	kfree(vm);
-}
-
-int
-nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
-	       struct nouveau_gpuobj *pgd)
-{
-	if (ref) {
-		int ret = nouveau_vm_link(ref, pgd);
-		if (ret)
-			return ret;
-
-		kref_get(&ref->refcount);
-	}
-
-	if (*ptr) {
-		nouveau_vm_unlink(*ptr, pgd);
-		kref_put(&(*ptr)->refcount, nouveau_vm_del);
-	}
-
-	*ptr = ref;
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
deleted file mode 100644
index ed45437..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include "nv04.h"
-
-#define NV04_PDMA_SIZE (128 * 1024 * 1024)
-#define NV04_PDMA_PAGE (  4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv04_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
-	pte = 0x00008 + (pte * 4);
-	while (cnt) {
-		u32 page = PAGE_SIZE / NV04_PDMA_PAGE;
-		u32 phys = (u32)*list++;
-		while (cnt && page--) {
-			nv_wo32(pgt, pte, phys | 3);
-			phys += NV04_PDMA_PAGE;
-			pte += 4;
-			cnt -= 1;
-		}
-	}
-}
-
-static void
-nv04_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
-	pte = 0x00008 + (pte * 4);
-	while (cnt--) {
-		nv_wo32(pgt, pte, 0x00000000);
-		pte += 4;
-	}
-}
-
-static void
-nv04_vm_flush(struct nouveau_vm *vm)
-{
-}
-
-/*******************************************************************************
- * VM object
- ******************************************************************************/
-
-int
-nv04_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, u64 mmstart,
-	       struct nouveau_vm **pvm)
-{
-	return -EINVAL;
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv04_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv04_vmmgr_priv *priv;
-	struct nouveau_gpuobj *dma;
-	int ret;
-
-	ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIGART",
-				   "pcigart", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.create = nv04_vm_create;
-	priv->base.limit = NV04_PDMA_SIZE;
-	priv->base.dma_bits = 32;
-	priv->base.pgt_bits = 32 - 12;
-	priv->base.spg_shift = 12;
-	priv->base.lpg_shift = 12;
-	priv->base.map_sg = nv04_vm_map_sg;
-	priv->base.unmap = nv04_vm_unmap;
-	priv->base.flush = nv04_vm_flush;
-
-	ret = nouveau_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096,
-				&priv->vm);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-				 (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 +
-				 8, 16, NVOBJ_FLAG_ZERO_ALLOC,
-				 &priv->vm->pgt[0].obj[0]);
-	dma = priv->vm->pgt[0].obj[0];
-	priv->vm->pgt[0].refcount[0] = 1;
-	if (ret)
-		return ret;
-
-	nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */
-	nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1);
-	return 0;
-}
-
-void
-nv04_vmmgr_dtor(struct nouveau_object *object)
-{
-	struct nv04_vmmgr_priv *priv = (void *)object;
-	if (priv->vm) {
-		nouveau_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]);
-		nouveau_vm_ref(NULL, &priv->vm, NULL);
-	}
-	if (priv->nullp) {
-		pci_free_consistent(nv_device(priv)->pdev, 16 * 1024,
-				    priv->nullp, priv->null);
-	}
-	nouveau_vmmgr_destroy(&priv->base);
-}
-
-struct nouveau_oclass
-nv04_vmmgr_oclass = {
-	.handle = NV_SUBDEV(VM, 0x04),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv04_vmmgr_ctor,
-		.dtor = nv04_vmmgr_dtor,
-		.init = _nouveau_vmmgr_init,
-		.fini = _nouveau_vmmgr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
deleted file mode 100644
index ec42d4b..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __NV04_VMMGR_PRIV__
-#define __NV04_VMMGR_PRIV__
-
-#include <subdev/vm.h>
-
-struct nv04_vmmgr_priv {
-	struct nouveau_vmmgr base;
-	struct nouveau_vm *vm;
-	dma_addr_t null;
-	void *nullp;
-};
-
-static inline struct nv04_vmmgr_priv *
-nv04_vmmgr(void *obj)
-{
-	return (void *)nouveau_vmmgr(obj);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
deleted file mode 100644
index 064c762..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <subdev/timer.h>
-#include <subdev/vm.h>
-
-#include "nv04.h"
-
-#define NV41_GART_SIZE (512 * 1024 * 1024)
-#define NV41_GART_PAGE (  4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv41_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
-	pte = pte * 4;
-	while (cnt) {
-		u32 page = PAGE_SIZE / NV41_GART_PAGE;
-		u64 phys = (u64)*list++;
-		while (cnt && page--) {
-			nv_wo32(pgt, pte, (phys >> 7) | 1);
-			phys += NV41_GART_PAGE;
-			pte += 4;
-			cnt -= 1;
-		}
-	}
-}
-
-static void
-nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
-	pte = pte * 4;
-	while (cnt--) {
-		nv_wo32(pgt, pte, 0x00000000);
-		pte += 4;
-	}
-}
-
-static void
-nv41_vm_flush(struct nouveau_vm *vm)
-{
-	struct nv04_vmmgr_priv *priv = (void *)vm->vmm;
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	nv_wr32(priv, 0x100810, 0x00000022);
-	if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) {
-		nv_warn(priv, "flush timeout, 0x%08x\n",
-			nv_rd32(priv, 0x100810));
-	}
-	nv_wr32(priv, 0x100810, 0x00000000);
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv41_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nv04_vmmgr_priv *priv;
-	int ret;
-
-	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
-	    !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {
-		return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,
-					   data, size, pobject);
-	}
-
-	ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART",
-				   "pciegart", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.create = nv04_vm_create;
-	priv->base.limit = NV41_GART_SIZE;
-	priv->base.dma_bits = 39;
-	priv->base.pgt_bits = 32 - 12;
-	priv->base.spg_shift = 12;
-	priv->base.lpg_shift = 12;
-	priv->base.map_sg = nv41_vm_map_sg;
-	priv->base.unmap = nv41_vm_unmap;
-	priv->base.flush = nv41_vm_flush;
-
-	ret = nouveau_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096,
-				&priv->vm);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-				(NV41_GART_SIZE / NV41_GART_PAGE) * 4,
-				 16, NVOBJ_FLAG_ZERO_ALLOC,
-				 &priv->vm->pgt[0].obj[0]);
-	priv->vm->pgt[0].refcount[0] = 1;
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nv41_vmmgr_init(struct nouveau_object *object)
-{
-	struct nv04_vmmgr_priv *priv = (void *)object;
-	struct nouveau_gpuobj *dma = priv->vm->pgt[0].obj[0];
-	int ret;
-
-	ret = nouveau_vmmgr_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nv_wr32(priv, 0x100800, dma->addr | 0x00000002);
-	nv_mask(priv, 0x10008c, 0x00000100, 0x00000100);
-	nv_wr32(priv, 0x100820, 0x00000000);
-	return 0;
-}
-
-struct nouveau_oclass
-nv41_vmmgr_oclass = {
-	.handle = NV_SUBDEV(VM, 0x41),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv41_vmmgr_ctor,
-		.dtor = nv04_vmmgr_dtor,
-		.init = nv41_vmmgr_init,
-		.fini = _nouveau_vmmgr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
deleted file mode 100644
index fae1f67..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2012 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <subdev/timer.h>
-#include <subdev/vm.h>
-
-#include "nv04.h"
-
-#define NV44_GART_SIZE (512 * 1024 * 1024)
-#define NV44_GART_PAGE (  4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null,
-	     dma_addr_t *list, u32 pte, u32 cnt)
-{
-	u32 base = (pte << 2) & ~0x0000000f;
-	u32 tmp[4];
-
-	tmp[0] = nv_ro32(pgt, base + 0x0);
-	tmp[1] = nv_ro32(pgt, base + 0x4);
-	tmp[2] = nv_ro32(pgt, base + 0x8);
-	tmp[3] = nv_ro32(pgt, base + 0xc);
-
-	while (cnt--) {
-		u32 addr = list ? (*list++ >> 12) : (null >> 12);
-		switch (pte++ & 0x3) {
-		case 0:
-			tmp[0] &= ~0x07ffffff;
-			tmp[0] |= addr;
-			break;
-		case 1:
-			tmp[0] &= ~0xf8000000;
-			tmp[0] |= addr << 27;
-			tmp[1] &= ~0x003fffff;
-			tmp[1] |= addr >> 5;
-			break;
-		case 2:
-			tmp[1] &= ~0xffc00000;
-			tmp[1] |= addr << 22;
-			tmp[2] &= ~0x0001ffff;
-			tmp[2] |= addr >> 10;
-			break;
-		case 3:
-			tmp[2] &= ~0xfffe0000;
-			tmp[2] |= addr << 17;
-			tmp[3] &= ~0x00000fff;
-			tmp[3] |= addr >> 15;
-			break;
-		}
-	}
-
-	nv_wo32(pgt, base + 0x0, tmp[0]);
-	nv_wo32(pgt, base + 0x4, tmp[1]);
-	nv_wo32(pgt, base + 0x8, tmp[2]);
-	nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000);
-}
-
-static void
-nv44_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
-	struct nv04_vmmgr_priv *priv = (void *)vma->vm->vmm;
-	u32 tmp[4];
-	int i;
-
-	if (pte & 3) {
-		u32  max = 4 - (pte & 3);
-		u32 part = (cnt > max) ? max : cnt;
-		nv44_vm_fill(pgt, priv->null, list, pte, part);
-		pte  += part;
-		list += part;
-		cnt  -= part;
-	}
-
-	while (cnt >= 4) {
-		for (i = 0; i < 4; i++)
-			tmp[i] = *list++ >> 12;
-		nv_wo32(pgt, pte++ * 4, tmp[0] >>  0 | tmp[1] << 27);
-		nv_wo32(pgt, pte++ * 4, tmp[1] >>  5 | tmp[2] << 22);
-		nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17);
-		nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000);
-		cnt -= 4;
-	}
-
-	if (cnt)
-		nv44_vm_fill(pgt, priv->null, list, pte, cnt);
-}
-
-static void
-nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
-	struct nv04_vmmgr_priv *priv = (void *)nouveau_vmmgr(pgt);
-
-	if (pte & 3) {
-		u32  max = 4 - (pte & 3);
-		u32 part = (cnt > max) ? max : cnt;
-		nv44_vm_fill(pgt, priv->null, NULL, pte, part);
-		pte  += part;
-		cnt  -= part;
-	}
-
-	while (cnt >= 4) {
-		nv_wo32(pgt, pte++ * 4, 0x00000000);
-		nv_wo32(pgt, pte++ * 4, 0x00000000);
-		nv_wo32(pgt, pte++ * 4, 0x00000000);
-		nv_wo32(pgt, pte++ * 4, 0x00000000);
-		cnt -= 4;
-	}
-
-	if (cnt)
-		nv44_vm_fill(pgt, priv->null, NULL, pte, cnt);
-}
-
-static void
-nv44_vm_flush(struct nouveau_vm *vm)
-{
-	struct nv04_vmmgr_priv *priv = (void *)vm->vmm;
-	nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE);
-	nv_wr32(priv, 0x100808, 0x00000020);
-	if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001))
-		nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808));
-	nv_wr32(priv, 0x100808, 0x00000000);
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nv04_vmmgr_priv *priv;
-	int ret;
-
-	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
-	    !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {
-		return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,
-					   data, size, pobject);
-	}
-
-	ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART",
-				   "pciegart", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.create = nv04_vm_create;
-	priv->base.limit = NV44_GART_SIZE;
-	priv->base.dma_bits = 39;
-	priv->base.pgt_bits = 32 - 12;
-	priv->base.spg_shift = 12;
-	priv->base.lpg_shift = 12;
-	priv->base.map_sg = nv44_vm_map_sg;
-	priv->base.unmap = nv44_vm_unmap;
-	priv->base.flush = nv44_vm_flush;
-
-	priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null);
-	if (!priv->nullp) {
-		nv_error(priv, "unable to allocate dummy pages\n");
-		return -ENOMEM;
-	}
-
-	ret = nouveau_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096,
-				&priv->vm);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-				(NV44_GART_SIZE / NV44_GART_PAGE) * 4,
-				 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC,
-				 &priv->vm->pgt[0].obj[0]);
-	priv->vm->pgt[0].refcount[0] = 1;
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static int
-nv44_vmmgr_init(struct nouveau_object *object)
-{
-	struct nv04_vmmgr_priv *priv = (void *)object;
-	struct nouveau_gpuobj *gart = priv->vm->pgt[0].obj[0];
-	u32 addr;
-	int ret;
-
-	ret = nouveau_vmmgr_init(&priv->base);
-	if (ret)
-		return ret;
-
-	/* calculate vram address of this PRAMIN block, object must be
-	 * allocated on 512KiB alignment, and not exceed a total size
-	 * of 512KiB for this to work correctly
-	 */
-	addr  = nv_rd32(priv, 0x10020c);
-	addr -= ((gart->addr >> 19) + 1) << 19;
-
-	nv_wr32(priv, 0x100850, 0x80000000);
-	nv_wr32(priv, 0x100818, priv->null);
-	nv_wr32(priv, 0x100804, NV44_GART_SIZE);
-	nv_wr32(priv, 0x100850, 0x00008000);
-	nv_mask(priv, 0x10008c, 0x00000200, 0x00000200);
-	nv_wr32(priv, 0x100820, 0x00000000);
-	nv_wr32(priv, 0x10082c, 0x00000001);
-	nv_wr32(priv, 0x100800, addr | 0x00000010);
-	return 0;
-}
-
-struct nouveau_oclass
-nv44_vmmgr_oclass = {
-	.handle = NV_SUBDEV(VM, 0x44),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv44_vmmgr_ctor,
-		.dtor = nv04_vmmgr_dtor,
-		.init = nv44_vmmgr_init,
-		.fini = _nouveau_vmmgr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
deleted file mode 100644
index a4aa81a..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/bar.h>
-#include <subdev/vm.h>
-
-struct nv50_vmmgr_priv {
-	struct nouveau_vmmgr base;
-};
-
-static void
-nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
-		struct nouveau_gpuobj *pgt[2])
-{
-	u64 phys = 0xdeadcafe00000000ULL;
-	u32 coverage = 0;
-
-	if (pgt[0]) {
-		phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */
-		coverage = (pgt[0]->size >> 3) << 12;
-	} else
-	if (pgt[1]) {
-		phys = 0x00000001 | pgt[1]->addr; /* present */
-		coverage = (pgt[1]->size >> 3) << 16;
-	}
-
-	if (phys & 1) {
-		if (coverage <= 32 * 1024 * 1024)
-			phys |= 0x60;
-		else if (coverage <= 64 * 1024 * 1024)
-			phys |= 0x40;
-		else if (coverage <= 128 * 1024 * 1024)
-			phys |= 0x20;
-	}
-
-	nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys));
-	nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys));
-}
-
-static inline u64
-vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
-{
-	phys |= 1; /* present */
-	phys |= (u64)memtype << 40;
-	phys |= target << 4;
-	if (vma->access & NV_MEM_ACCESS_SYS)
-		phys |= (1 << 6);
-	if (!(vma->access & NV_MEM_ACCESS_WO))
-		phys |= (1 << 3);
-	return phys;
-}
-
-static void
-nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	    struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
-{
-	u32 comp = (mem->memtype & 0x180) >> 7;
-	u32 block, target;
-	int i;
-
-	/* IGPs don't have real VRAM, re-target to stolen system memory */
-	target = 0;
-	if (nouveau_fb(vma->vm->vmm)->ram->stolen) {
-		phys += nouveau_fb(vma->vm->vmm)->ram->stolen;
-		target = 3;
-	}
-
-	phys  = vm_addr(vma, phys, mem->memtype, target);
-	pte <<= 3;
-	cnt <<= 3;
-
-	while (cnt) {
-		u32 offset_h = upper_32_bits(phys);
-		u32 offset_l = lower_32_bits(phys);
-
-		for (i = 7; i >= 0; i--) {
-			block = 1 << (i + 3);
-			if (cnt >= block && !(pte & (block - 1)))
-				break;
-		}
-		offset_l |= (i << 7);
-
-		phys += block << (vma->node->type - 3);
-		cnt  -= block;
-		if (comp) {
-			u32 tag = mem->tag->offset + ((delta >> 16) * comp);
-			offset_h |= (tag << 17);
-			delta    += block << (vma->node->type - 3);
-		}
-
-		while (block) {
-			nv_wo32(pgt, pte + 0, offset_l);
-			nv_wo32(pgt, pte + 4, offset_h);
-			pte += 8;
-			block -= 8;
-		}
-	}
-}
-
-static void
-nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
-	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
-	pte <<= 3;
-	while (cnt--) {
-		u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
-		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
-		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
-		pte += 8;
-	}
-}
-
-static void
-nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
-	pte <<= 3;
-	while (cnt--) {
-		nv_wo32(pgt, pte + 0, 0x00000000);
-		nv_wo32(pgt, pte + 4, 0x00000000);
-		pte += 8;
-	}
-}
-
-static void
-nv50_vm_flush(struct nouveau_vm *vm)
-{
-	struct nv50_vmmgr_priv *priv = (void *)vm->vmm;
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nouveau_engine *engine;
-	int i, vme;
-
-	bar->flush(bar);
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
-		if (!atomic_read(&vm->engref[i]))
-			continue;
-
-		/* unfortunate hw bug workaround... */
-		engine = nouveau_engine(priv, i);
-		if (engine && engine->tlb_flush) {
-			engine->tlb_flush(engine);
-			continue;
-		}
-
-		switch (i) {
-		case NVDEV_ENGINE_GR   : vme = 0x00; break;
-		case NVDEV_ENGINE_VP   : vme = 0x01; break;
-		case NVDEV_SUBDEV_BAR  : vme = 0x06; break;
-		case NVDEV_ENGINE_PPP  :
-		case NVDEV_ENGINE_MPEG : vme = 0x08; break;
-		case NVDEV_ENGINE_BSP  : vme = 0x09; break;
-		case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;
-		case NVDEV_ENGINE_COPY0: vme = 0x0d; break;
-		default:
-			continue;
-		}
-
-		nv_wr32(priv, 0x100c80, (vme << 16) | 1);
-		if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
-			nv_error(priv, "vm flush timeout: engine %d\n", vme);
-	}
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nv50_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
-	       u64 mm_offset, struct nouveau_vm **pvm)
-{
-	u32 block = (1 << (vmm->pgt_bits + 12));
-	if (block > length)
-		block = length;
-
-	return nouveau_vm_create(vmm, offset, length, mm_offset, block, pvm);
-}
-
-static int
-nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nv50_vmmgr_priv *priv;
-	int ret;
-
-	ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.limit = 1ULL << 40;
-	priv->base.dma_bits = 40;
-	priv->base.pgt_bits  = 29 - 12;
-	priv->base.spg_shift = 12;
-	priv->base.lpg_shift = 16;
-	priv->base.create = nv50_vm_create;
-	priv->base.map_pgt = nv50_vm_map_pgt;
-	priv->base.map = nv50_vm_map;
-	priv->base.map_sg = nv50_vm_map_sg;
-	priv->base.unmap = nv50_vm_unmap;
-	priv->base.flush = nv50_vm_flush;
-	return 0;
-}
-
-struct nouveau_oclass
-nv50_vmmgr_oclass = {
-	.handle = NV_SUBDEV(VM, 0x50),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv50_vmmgr_ctor,
-		.dtor = _nouveau_vmmgr_dtor,
-		.init = _nouveau_vmmgr_init,
-		.fini = _nouveau_vmmgr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
deleted file mode 100644
index 2d09887..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2010 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/ltc.h>
-#include <subdev/bar.h>
-
-struct nvc0_vmmgr_priv {
-	struct nouveau_vmmgr base;
-};
-
-
-/* Map from compressed to corresponding uncompressed storage type.
- * The value 0xff represents an invalid storage type.
- */
-const u8 nvc0_pte_storage_type_map[256] =
-{
-	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, /* 0x00 */
-	0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, /* 0x10 */
-	0x11, 0x11, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x27, /* 0x20 */
-	0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
-	0xff, 0xff, 0x26, 0x27, 0x28, 0x29, 0x26, 0x27,
-	0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0x46, 0xff, /* 0x40 */
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0x46, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, /* 0x50 */
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
-	0xff, 0xff, 0xff, 0x7b, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x7b, /* 0x80 */
-	0x7b, 0x7b, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xa7, /* 0xa0 */
-	0xa8, 0xa9, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7,
-	0xa8, 0xa9, 0xaa, 0xc3, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
-	0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xc3, 0xc3,
-	0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
-	0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
-	0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, /* 0xe0 */
-	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff,
-	0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0 */
-	0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
-};
-
-
-static void
-nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index,
-		struct nouveau_gpuobj *pgt[2])
-{
-	u32 pde[2] = { 0, 0 };
-
-	if (pgt[0])
-		pde[1] = 0x00000001 | (pgt[0]->addr >> 8);
-	if (pgt[1])
-		pde[0] = 0x00000001 | (pgt[1]->addr >> 8);
-
-	nv_wo32(pgd, (index * 8) + 0, pde[0]);
-	nv_wo32(pgd, (index * 8) + 4, pde[1]);
-}
-
-static inline u64
-nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
-{
-	phys >>= 8;
-
-	phys |= 0x00000001; /* present */
-	if (vma->access & NV_MEM_ACCESS_SYS)
-		phys |= 0x00000002;
-
-	phys |= ((u64)target  << 32);
-	phys |= ((u64)memtype << 36);
-
-	return phys;
-}
-
-static void
-nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	    struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
-{
-	u64 next = 1 << (vma->node->type - 8);
-
-	phys  = nvc0_vm_addr(vma, phys, mem->memtype, 0);
-	pte <<= 3;
-
-	if (mem->tag) {
-		struct nouveau_ltc *ltc =
-			nouveau_ltc(vma->vm->vmm->base.base.parent);
-		u32 tag = mem->tag->offset + (delta >> 17);
-		phys |= (u64)tag << (32 + 12);
-		next |= (u64)1   << (32 + 12);
-		ltc->tags_clear(ltc, tag, cnt);
-	}
-
-	while (cnt--) {
-		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
-		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
-		phys += next;
-		pte  += 8;
-	}
-}
-
-static void
-nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
-	       struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
-	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
-	/* compressed storage types are invalid for system memory */
-	u32 memtype = nvc0_pte_storage_type_map[mem->memtype & 0xff];
-
-	pte <<= 3;
-	while (cnt--) {
-		u64 phys = nvc0_vm_addr(vma, *list++, memtype, target);
-		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
-		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
-		pte += 8;
-	}
-}
-
-static void
-nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
-	pte <<= 3;
-	while (cnt--) {
-		nv_wo32(pgt, pte + 0, 0x00000000);
-		nv_wo32(pgt, pte + 4, 0x00000000);
-		pte += 8;
-	}
-}
-
-static void
-nvc0_vm_flush(struct nouveau_vm *vm)
-{
-	struct nvc0_vmmgr_priv *priv = (void *)vm->vmm;
-	struct nouveau_bar *bar = nouveau_bar(priv);
-	struct nouveau_vm_pgd *vpgd;
-	u32 type;
-
-	bar->flush(bar);
-
-	type = 0x00000001; /* PAGE_ALL */
-	if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
-		type |= 0x00000004; /* HUB_ONLY */
-
-	mutex_lock(&nv_subdev(priv)->mutex);
-	list_for_each_entry(vpgd, &vm->pgd_list, head) {
-		/* looks like maybe a "free flush slots" counter, the
-		 * faster you write to 0x100cbc to more it decreases
-		 */
-		if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
-			nv_error(priv, "vm timeout 0: 0x%08x %d\n",
-				 nv_rd32(priv, 0x100c80), type);
-		}
-
-		nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
-		nv_wr32(priv, 0x100cbc, 0x80000000 | type);
-
-		/* wait for flush to be queued? */
-		if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
-			nv_error(priv, "vm timeout 1: 0x%08x %d\n",
-				 nv_rd32(priv, 0x100c80), type);
-		}
-	}
-	mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nvc0_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
-	       u64 mm_offset, struct nouveau_vm **pvm)
-{
-	return nouveau_vm_create(vmm, offset, length, mm_offset, 4096, pvm);
-}
-
-static int
-nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
-		struct nouveau_object **pobject)
-{
-	struct nvc0_vmmgr_priv *priv;
-	int ret;
-
-	ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	priv->base.limit = 1ULL << 40;
-	priv->base.dma_bits = 40;
-	priv->base.pgt_bits  = 27 - 12;
-	priv->base.spg_shift = 12;
-	priv->base.lpg_shift = 17;
-	priv->base.create = nvc0_vm_create;
-	priv->base.map_pgt = nvc0_vm_map_pgt;
-	priv->base.map = nvc0_vm_map;
-	priv->base.map_sg = nvc0_vm_map_sg;
-	priv->base.unmap = nvc0_vm_unmap;
-	priv->base.flush = nvc0_vm_flush;
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_vmmgr_oclass = {
-	.handle = NV_SUBDEV(VM, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_vmmgr_ctor,
-		.dtor = _nouveau_vmmgr_dtor,
-		.init = _nouveau_vmmgr_init,
-		.fini = _nouveau_vmmgr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
deleted file mode 100644
index 26ccd8d..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/vmap.h>
-#include <subdev/bios/volt.h>
-
-static int
-nouveau_volt_get(struct nouveau_volt *volt)
-{
-	if (volt->vid_get) {
-		int ret = volt->vid_get(volt), i;
-		if (ret >= 0) {
-			for (i = 0; i < volt->vid_nr; i++) {
-				if (volt->vid[i].vid == ret)
-					return volt->vid[i].uv;
-			}
-			ret = -EINVAL;
-		}
-		return ret;
-	}
-	return -ENODEV;
-}
-
-static int
-nouveau_volt_set(struct nouveau_volt *volt, u32 uv)
-{
-	if (volt->vid_set) {
-		int i, ret = -EINVAL;
-		for (i = 0; i < volt->vid_nr; i++) {
-			if (volt->vid[i].uv == uv) {
-				ret = volt->vid_set(volt, volt->vid[i].vid);
-				nv_debug(volt, "set %duv: %d\n", uv, ret);
-				break;
-			}
-		}
-		return ret;
-	}
-	return -ENODEV;
-}
-
-static int
-nouveau_volt_map(struct nouveau_volt *volt, u8 id)
-{
-	struct nouveau_bios *bios = nouveau_bios(volt);
-	struct nvbios_vmap_entry info;
-	u8  ver, len;
-	u16 vmap;
-
-	vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
-	if (vmap) {
-		if (info.link != 0xff) {
-			int ret = nouveau_volt_map(volt, info.link);
-			if (ret < 0)
-				return ret;
-			info.min += ret;
-		}
-		return info.min;
-	}
-
-	return id ? id * 10000 : -ENODEV;
-}
-
-static int
-nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
-{
-	int ret = nouveau_volt_map(volt, id);
-	if (ret >= 0) {
-		int prev = nouveau_volt_get(volt);
-		if (!condition || prev < 0 ||
-		    (condition < 0 && ret < prev) ||
-		    (condition > 0 && ret > prev)) {
-			ret = nouveau_volt_set(volt, ret);
-		} else {
-			ret = 0;
-		}
-	}
-	return ret;
-}
-
-static void nouveau_volt_parse_bios(struct nouveau_bios *bios,
-		struct nouveau_volt *volt)
-{
-	struct nvbios_volt_entry ivid;
-	struct nvbios_volt info;
-	u8  ver, hdr, cnt, len;
-	u16 data;
-	int i;
-
-	data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
-	if (data && info.vidmask && info.base && info.step) {
-		for (i = 0; i < info.vidmask + 1; i++) {
-			if (info.base >= info.min &&
-				info.base <= info.max) {
-				volt->vid[volt->vid_nr].uv = info.base;
-				volt->vid[volt->vid_nr].vid = i;
-				volt->vid_nr++;
-			}
-			info.base += info.step;
-		}
-		volt->vid_mask = info.vidmask;
-	} else if (data && info.vidmask) {
-		for (i = 0; i < cnt; i++) {
-			data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
-							  &ivid);
-			if (data) {
-				volt->vid[volt->vid_nr].uv = ivid.voltage;
-				volt->vid[volt->vid_nr].vid = ivid.vid;
-				volt->vid_nr++;
-			}
-		}
-		volt->vid_mask = info.vidmask;
-	}
-}
-
-int
-_nouveau_volt_init(struct nouveau_object *object)
-{
-	struct nouveau_volt *volt = (void *)object;
-	int ret;
-
-	ret = nouveau_subdev_init(&volt->base);
-	if (ret)
-		return ret;
-
-	ret = volt->get(volt);
-	if (ret < 0) {
-		if (ret != -ENODEV)
-			nv_debug(volt, "current voltage unknown\n");
-		return 0;
-	}
-
-	nv_info(volt, "GPU voltage: %duv\n", ret);
-	return 0;
-}
-
-void
-_nouveau_volt_dtor(struct nouveau_object *object)
-{
-	struct nouveau_volt *volt = (void *)object;
-	nouveau_subdev_destroy(&volt->base);
-}
-
-int
-nouveau_volt_create_(struct nouveau_object *parent,
-		     struct nouveau_object *engine,
-		     struct nouveau_oclass *oclass, int length, void **pobject)
-{
-	struct nouveau_bios *bios = nouveau_bios(parent);
-	struct nouveau_volt *volt;
-	int ret, i;
-
-	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
-				     "voltage", length, pobject);
-	volt = *pobject;
-	if (ret)
-		return ret;
-
-	volt->get = nouveau_volt_get;
-	volt->set = nouveau_volt_set;
-	volt->set_id = nouveau_volt_set_id;
-
-	/* Assuming the non-bios device should build the voltage table later */
-	if (bios)
-		nouveau_volt_parse_bios(bios, volt);
-
-	if (volt->vid_nr) {
-		for (i = 0; i < volt->vid_nr; i++) {
-			nv_debug(volt, "VID %02x: %duv\n",
-				 volt->vid[i].vid, volt->vid[i].uv);
-		}
-
-		/*XXX: this is an assumption.. there probably exists boards
-		 * out there with i2c-connected voltage controllers too..
-		 */
-		ret = nouveau_voltgpio_init(volt);
-		if (ret == 0) {
-			volt->vid_get = nouveau_voltgpio_get;
-			volt->vid_set = nouveau_voltgpio_set;
-		}
-	}
-
-	return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c
deleted file mode 100644
index 717368e..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * 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.
- */
-
-#ifdef __KERNEL__
-#include <nouveau_platform.h>
-#endif
-#include <subdev/volt.h>
-
-struct cvb_coef {
-	int c0;
-	int c1;
-	int c2;
-	int c3;
-	int c4;
-	int c5;
-};
-
-struct gk20a_volt_priv {
-	struct nouveau_volt base;
-	struct regulator *vdd;
-};
-
-const struct cvb_coef gk20a_cvb_coef[] = {
-	/* MHz,        c0,     c1,   c2,    c3,     c4,   c5 */
-	/*  72 */ { 1209886, -36468,  515,   417, -13123,  203},
-	/* 108 */ { 1130804, -27659,  296,   298, -10834,  221},
-	/* 180 */ { 1162871, -27110,  247,   238, -10681,  268},
-	/* 252 */ { 1220458, -28654,  247,   179, -10376,  298},
-	/* 324 */ { 1280953, -30204,  247,   119,  -9766,  304},
-	/* 396 */ { 1344547, -31777,  247,   119,  -8545,  292},
-	/* 468 */ { 1420168, -34227,  269,    60,  -7172,  256},
-	/* 540 */ { 1490757, -35955,  274,    60,  -5188,  197},
-	/* 612 */ { 1599112, -42583,  398,     0,  -1831,  119},
-	/* 648 */ { 1366986, -16459, -274,     0,  -3204,   72},
-	/* 684 */ { 1391884, -17078, -274,   -60,  -1526,   30},
-	/* 708 */ { 1415522, -17497, -274,   -60,   -458,    0},
-	/* 756 */ { 1464061, -18331, -274,  -119,   1831,  -72},
-	/* 804 */ { 1524225, -20064, -254,  -119,   4272, -155},
-	/* 852 */ { 1608418, -21643, -269,     0,    763,  -48},
-};
-
-/**
- * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
- */
-static inline int
-gk20a_volt_get_cvb_voltage(int speedo, int s_scale,
-		const struct cvb_coef *coef)
-{
-	int mv;
-
-	mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
-	mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
-	return mv;
-}
-
-/**
- * cvb_t_mv =
- * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
- * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
- */
-static inline int
-gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
-		const struct cvb_coef *coef)
-{
-	int cvb_mv, mv;
-
-	cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
-
-	mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
-		DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
-	mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
-	return mv;
-}
-
-static int
-gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
-{
-	int mv;
-
-	mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
-	mv = DIV_ROUND_UP(mv, 1000);
-
-	return mv * 1000;
-}
-
-static int
-gk20a_volt_vid_get(struct nouveau_volt *volt)
-{
-	struct gk20a_volt_priv *priv = (void *)volt;
-	int i, uv;
-
-	uv = regulator_get_voltage(priv->vdd);
-
-	for (i = 0; i < volt->vid_nr; i++)
-		if (volt->vid[i].uv >= uv)
-			return i;
-
-	return -EINVAL;
-}
-
-static int
-gk20a_volt_vid_set(struct nouveau_volt *volt, u8 vid)
-{
-	struct gk20a_volt_priv *priv = (void *)volt;
-
-	nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv);
-	return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000);
-}
-
-static int
-gk20a_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
-{
-	struct gk20a_volt_priv *priv = (void *)volt;
-	int prev_uv = regulator_get_voltage(priv->vdd);
-	int target_uv = volt->vid[id].uv;
-	int ret;
-
-	nv_debug(volt, "prev=%d, target=%d, condition=%d\n",
-			prev_uv, target_uv, condition);
-	if (!condition ||
-		(condition < 0 && target_uv < prev_uv) ||
-		(condition > 0 && target_uv > prev_uv)) {
-		ret = gk20a_volt_vid_set(volt, volt->vid[id].vid);
-	} else {
-		ret = 0;
-	}
-
-	return ret;
-}
-
-static int
-gk20a_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct gk20a_volt_priv *priv;
-	struct nouveau_volt *volt;
-	struct nouveau_platform_device *plat;
-	int i, ret, uv;
-
-	ret = nouveau_volt_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	volt = &priv->base;
-
-	plat = nv_device_to_platform(nv_device(parent));
-
-	uv = regulator_get_voltage(plat->gpu->vdd);
-	nv_info(priv, "The default voltage is %duV\n", uv);
-
-	priv->vdd = plat->gpu->vdd;
-	priv->base.vid_get = gk20a_volt_vid_get;
-	priv->base.vid_set = gk20a_volt_vid_set;
-	priv->base.set_id = gk20a_volt_set_id;
-
-	volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
-	nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
-	for (i = 0; i < volt->vid_nr; i++) {
-		volt->vid[i].vid = i;
-		volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
-					plat->gpu_speedo);
-		nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
-					volt->vid[i].uv);
-	}
-
-	return 0;
-}
-
-struct nouveau_oclass
-gk20a_volt_oclass = {
-	.handle = NV_SUBDEV(VOLT, 0xea),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = gk20a_volt_ctor,
-		.dtor = _nouveau_volt_dtor,
-		.init = _nouveau_volt_init,
-		.fini = _nouveau_volt_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
deleted file mode 100644
index 755fa91..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-#include <subdev/gpio.h>
-#include <subdev/bios/gpio.h>
-
-static const u8 tags[] = {
-	DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
-	DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
-};
-
-int
-nouveau_voltgpio_get(struct nouveau_volt *volt)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(volt);
-	u8 vid = 0;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(tags); i++) {
-		if (volt->vid_mask & (1 << i)) {
-			int ret = gpio->get(gpio, 0, tags[i], 0xff);
-			if (ret < 0)
-				return ret;
-			vid |= ret << i;
-		}
-	}
-
-	return vid;
-}
-
-int
-nouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(volt);
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
-		if (volt->vid_mask & (1 << i)) {
-			int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
-			if (ret < 0)
-				return ret;
-		}
-	}
-
-	return 0;
-}
-
-int
-nouveau_voltgpio_init(struct nouveau_volt *volt)
-{
-	struct nouveau_gpio *gpio = nouveau_gpio(volt);
-	struct dcb_gpio_func func;
-	int i;
-
-	/* check we have gpio function info for each vid bit.  on some
-	 * boards (ie. nvs295) the vid mask has more bits than there
-	 * are valid gpio functions... from traces, nvidia appear to
-	 * just touch the existing ones, so let's mask off the invalid
-	 * bits and continue with life
-	 */
-	for (i = 0; i < ARRAY_SIZE(tags); i++) {
-		if (volt->vid_mask & (1 << i)) {
-			int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
-			if (ret) {
-				if (ret != -ENOENT)
-					return ret;
-				nv_debug(volt, "VID bit %d has no GPIO\n", i);
-				volt->vid_mask &= ~(1 << i);
-			}
-		}
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
deleted file mode 100644
index 87d5358..0000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 Red Hat 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.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-
-struct nv40_volt_priv {
-	struct nouveau_volt base;
-};
-
-static int
-nv40_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nv40_volt_priv *priv;
-	int ret;
-
-	ret = nouveau_volt_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass
-nv40_volt_oclass = {
-	.handle = NV_SUBDEV(VOLT, 0x40),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nv40_volt_ctor,
-		.dtor = _nouveau_volt_dtor,
-		.init = _nouveau_volt_init,
-		.fini = _nouveau_volt_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/dispnv04/Makefile b/drivers/gpu/drm/nouveau/dispnv04/Kbuild
similarity index 100%
rename from drivers/gpu/drm/nouveau/dispnv04/Makefile
rename to drivers/gpu/drm/nouveau/dispnv04/Kbuild
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 38402ade..542bb266 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -41,7 +41,7 @@
 #include "disp.h"
 
 #include <subdev/bios/pll.h>
-#include <subdev/clock.h>
+#include <subdev/clk.h>
 
 static int
 nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@ -112,12 +112,12 @@
 {
 	struct drm_device *dev = crtc->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_bios *bios = nvkm_bios(&drm->device);
-	struct nouveau_clock *clk = nvkm_clock(&drm->device);
+	struct nvkm_bios *bios = nvxx_bios(&drm->device);
+	struct nvkm_clk *clk = nvxx_clk(&drm->device);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
 	struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index];
-	struct nouveau_pll_vals *pv = &regp->pllvals;
+	struct nvkm_pll_vals *pv = &regp->pllvals;
 	struct nvbios_pll pll_lim;
 
 	if (nvbios_pll_parse(bios, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c
index 2d8056c..d7b495a 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dac.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c
@@ -66,7 +66,7 @@
 static int sample_load_twice(struct drm_device *dev, bool sense[2])
 {
 	struct nvif_device *device = &nouveau_drm(dev)->device;
-	struct nouveau_timer *ptimer = nvkm_timer(device);
+	struct nvkm_timer *ptimer = nvxx_timer(device);
 	int i;
 
 	for (i = 0; i < 2; i++) {
@@ -80,17 +80,17 @@
 		 * use a 10ms timeout (guards against crtc being inactive, in
 		 * which case blank state would never change)
 		 */
-		if (!nouveau_timer_wait_eq(ptimer, 10000000,
-					   NV_PRMCIO_INP0__COLOR,
-					   0x00000001, 0x00000000))
+		if (!nvkm_timer_wait_eq(ptimer, 10000000,
+					NV_PRMCIO_INP0__COLOR,
+					0x00000001, 0x00000000))
 			return -EBUSY;
-		if (!nouveau_timer_wait_eq(ptimer, 10000000,
-					   NV_PRMCIO_INP0__COLOR,
-					   0x00000001, 0x00000001))
+		if (!nvkm_timer_wait_eq(ptimer, 10000000,
+					NV_PRMCIO_INP0__COLOR,
+					0x00000001, 0x00000001))
 			return -EBUSY;
-		if (!nouveau_timer_wait_eq(ptimer, 10000000,
-					   NV_PRMCIO_INP0__COLOR,
-					   0x00000001, 0x00000000))
+		if (!nvkm_timer_wait_eq(ptimer, 10000000,
+					NV_PRMCIO_INP0__COLOR,
+					0x00000001, 0x00000000))
 			return -EBUSY;
 
 		udelay(100);
@@ -232,7 +232,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nvif_device *device = &nouveau_drm(dev)->device;
-	struct nouveau_gpio *gpio = nvkm_gpio(device);
+	struct nvkm_gpio *gpio = nvxx_gpio(device);
 	struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
 	uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
 	uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
index 42a5435..f6ca343 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
@@ -623,9 +623,9 @@
 	struct drm_device *dev = encoder->dev;
 	struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
-	struct nouveau_i2c_port *port = i2c->find(i2c, 2);
-	struct nouveau_i2c_board_info info[] = {
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+	struct nvkm_i2c_port *port = i2c->find(i2c, 2);
+	struct nvkm_i2c_board_info info[] = {
 		{
 		    {
 		        .type = "sil164",
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c
index 3d0afa1..f96237e 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -32,28 +32,10 @@
 #include "nouveau_connector.h"
 
 int
-nv04_display_early_init(struct drm_device *dev)
-{
-	/* ensure vblank interrupts are off, they can't be enabled until
-	 * drm_vblank has been initialised
-	 */
-	NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
-	if (nv_two_heads(dev))
-		NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
-
-	return 0;
-}
-
-void
-nv04_display_late_takedown(struct drm_device *dev)
-{
-}
-
-int
 nv04_display_create(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
 	struct dcb_table *dcb = &drm->vbios.dcb;
 	struct drm_connector *connector, *ct;
 	struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index 17b899d..c910c5d 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -36,7 +36,7 @@
 
 	/* PRAMDAC regs */
 	uint32_t nv10_cursync;
-	struct nouveau_pll_vals pllvals;
+	struct nvkm_pll_vals pllvals;
 	uint32_t ramdac_gen_ctrl;
 	uint32_t ramdac_630;
 	uint32_t ramdac_634;
@@ -90,8 +90,6 @@
 }
 
 /* nv04_display.c */
-int nv04_display_early_init(struct drm_device *);
-void nv04_display_late_takedown(struct drm_device *);
 int nv04_display_create(struct drm_device *);
 void nv04_display_destroy(struct drm_device *);
 int nv04_display_init(struct drm_device *);
@@ -172,7 +170,7 @@
 			    struct dcb_output *outp, int crtc)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_bios *bios = nvkm_bios(&drm->device);
+	struct nvkm_bios *bios = nvxx_bios(&drm->device);
 	struct nvbios_init init = {
 		.subdev = nv_subdev(bios),
 		.bios = bios,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c
index 3d4c193..42e07af 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/hw.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c
@@ -130,7 +130,7 @@
 
 static void
 nouveau_hw_decode_pll(struct drm_device *dev, uint32_t reg1, uint32_t pll1,
-		      uint32_t pll2, struct nouveau_pll_vals *pllvals)
+		      uint32_t pll2, struct nvkm_pll_vals *pllvals)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 
@@ -162,11 +162,11 @@
 
 int
 nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype,
-		       struct nouveau_pll_vals *pllvals)
+		       struct nvkm_pll_vals *pllvals)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nvif_device *device = &drm->device;
-	struct nouveau_bios *bios = nvkm_bios(device);
+	struct nvkm_bios *bios = nvxx_bios(device);
 	uint32_t reg1, pll1, pll2 = 0;
 	struct nvbios_pll pll_lim;
 	int ret;
@@ -202,7 +202,7 @@
 }
 
 int
-nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pv)
+nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pv)
 {
 	/* Avoid divide by zero if called at an inappropriate time */
 	if (!pv->M1 || !pv->M2)
@@ -214,7 +214,7 @@
 int
 nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype)
 {
-	struct nouveau_pll_vals pllvals;
+	struct nvkm_pll_vals pllvals;
 	int ret;
 
 	if (plltype == PLL_MEMORY &&
@@ -253,10 +253,10 @@
 
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nvif_device *device = &drm->device;
-	struct nouveau_clock *clk = nvkm_clock(device);
-	struct nouveau_bios *bios = nvkm_bios(device);
+	struct nvkm_clk *clk = nvxx_clk(device);
+	struct nvkm_bios *bios = nvxx_bios(device);
 	struct nvbios_pll pll_lim;
-	struct nouveau_pll_vals pv;
+	struct nvkm_pll_vals pv;
 	enum nvbios_pll_type pll = head ? PLL_VPLL1 : PLL_VPLL0;
 
 	if (nvbios_pll_parse(bios, pll, &pll_lim))
@@ -463,7 +463,7 @@
 		     struct nv04_mode_state *state)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_clock *clk = nvkm_clock(&drm->device);
+	struct nvkm_clk *clk = nvxx_clk(&drm->device);
 	struct nv04_crtc_reg *regp = &state->crtc_reg[head];
 	uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
 	int i;
@@ -661,7 +661,7 @@
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nvif_device *device = &drm->device;
-	struct nouveau_timer *ptimer = nvkm_timer(device);
+	struct nvkm_timer *ptimer = nvxx_timer(device);
 	struct nv04_crtc_reg *regp = &state->crtc_reg[head];
 	uint32_t reg900;
 	int i;
@@ -741,8 +741,8 @@
 		if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) {
 			/* Not waiting for vertical retrace before modifying
 			   CRE_53/CRE_54 causes lockups. */
-			nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
-			nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
+			nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
+			nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
 		}
 
 		wr_cio_state(dev, head, regp, NV_CIO_CRE_42);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.h b/drivers/gpu/drm/nouveau/dispnv04/hw.h
index 7f53c57..6c79617 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/hw.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/hw.h
@@ -42,8 +42,8 @@
 void NVSetOwner(struct drm_device *, int owner);
 void NVBlankScreen(struct drm_device *, int head, bool blank);
 int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
-			   struct nouveau_pll_vals *pllvals);
-int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
+			   struct nvkm_pll_vals *pllvals);
+int nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals);
 int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
 void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
 void nouveau_hw_save_state(struct drm_device *, int head,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
index 8061d8d..d9664b3 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
@@ -35,7 +35,7 @@
 
 #include <drm/i2c/ch7006.h>
 
-static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = {
+static struct nvkm_i2c_board_info nv04_tv_encoder_info[] = {
 	{
 		{
 			I2C_BOARD_INFO("ch7006", 0x75),
@@ -54,7 +54,7 @@
 int nv04_tv_identify(struct drm_device *dev, int i2c_index)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
 
 	return i2c->identify(i2c, i2c_index, "TV encoder",
 			     nv04_tv_encoder_info, NULL, NULL);
@@ -204,8 +204,8 @@
 	struct drm_encoder *encoder;
 	struct drm_device *dev = connector->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
-	struct nouveau_i2c_port *port = i2c->find(i2c, entry->i2c_index);
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+	struct nvkm_i2c_port *port = i2c->find(i2c, entry->i2c_index);
 	int type, ret;
 
 	/* Ensure that we can talk to this encoder */
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index 72d2ab0..731d74e 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -46,7 +46,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+	struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
 	uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
 	uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
 		fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
@@ -133,14 +133,14 @@
 	struct nvif_device *device = &drm->device;
 
 	/* Zotac FX5200 */
-	if (nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x1035) ||
-	    nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x2035)) {
+	if (nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x1035) ||
+	    nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x2035)) {
 		*pin_mask = 0xc;
 		return false;
 	}
 
 	/* MSI nForce2 IGP */
-	if (nv_device_match(nvkm_object(device), 0x01f0, 0x1462, 0x5710)) {
+	if (nv_device_match(nvxx_object(device), 0x01f0, 0x1462, 0x5710)) {
 		*pin_mask = 0xc;
 		return false;
 	}
@@ -370,7 +370,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+	struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
 	struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
 	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
 
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
new file mode 100644
index 0000000..5ad17fc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -0,0 +1,573 @@
+#ifndef __NVIF_CLASS_H__
+#define __NVIF_CLASS_H__
+
+/*******************************************************************************
+ * class identifiers
+ ******************************************************************************/
+
+/* the below match nvidia-assigned (either in hw, or sw) class numbers */
+#define NV_DEVICE                                                    0x00000080
+
+#define NV_DMA_FROM_MEMORY                                           0x00000002
+#define NV_DMA_TO_MEMORY                                             0x00000003
+#define NV_DMA_IN_MEMORY                                             0x0000003d
+
+#define NV04_DISP                                                    0x00000046
+
+#define NV03_CHANNEL_DMA                                             0x0000006b
+#define NV10_CHANNEL_DMA                                             0x0000006e
+#define NV17_CHANNEL_DMA                                             0x0000176e
+#define NV40_CHANNEL_DMA                                             0x0000406e
+#define NV50_CHANNEL_DMA                                             0x0000506e
+#define G82_CHANNEL_DMA                                              0x0000826e
+
+#define NV50_CHANNEL_GPFIFO                                          0x0000506f
+#define G82_CHANNEL_GPFIFO                                           0x0000826f
+#define FERMI_CHANNEL_GPFIFO                                         0x0000906f
+#define KEPLER_CHANNEL_GPFIFO_A                                      0x0000a06f
+
+#define NV50_DISP                                                    0x00005070
+#define G82_DISP                                                     0x00008270
+#define GT200_DISP                                                   0x00008370
+#define GT214_DISP                                                   0x00008570
+#define GT206_DISP                                                   0x00008870
+#define GF110_DISP                                                   0x00009070
+#define GK104_DISP                                                   0x00009170
+#define GK110_DISP                                                   0x00009270
+#define GM107_DISP                                                   0x00009470
+#define GM204_DISP                                                   0x00009570
+
+#define NV50_DISP_CURSOR                                             0x0000507a
+#define G82_DISP_CURSOR                                              0x0000827a
+#define GT214_DISP_CURSOR                                            0x0000857a
+#define GF110_DISP_CURSOR                                            0x0000907a
+#define GK104_DISP_CURSOR                                            0x0000917a
+
+#define NV50_DISP_OVERLAY                                            0x0000507b
+#define G82_DISP_OVERLAY                                             0x0000827b
+#define GT214_DISP_OVERLAY                                           0x0000857b
+#define GF110_DISP_OVERLAY                                           0x0000907b
+#define GK104_DISP_OVERLAY                                           0x0000917b
+
+#define NV50_DISP_BASE_CHANNEL_DMA                                   0x0000507c
+#define G82_DISP_BASE_CHANNEL_DMA                                    0x0000827c
+#define GT200_DISP_BASE_CHANNEL_DMA                                  0x0000837c
+#define GT214_DISP_BASE_CHANNEL_DMA                                  0x0000857c
+#define GF110_DISP_BASE_CHANNEL_DMA                                  0x0000907c
+#define GK104_DISP_BASE_CHANNEL_DMA                                  0x0000917c
+#define GK110_DISP_BASE_CHANNEL_DMA                                  0x0000927c
+
+#define NV50_DISP_CORE_CHANNEL_DMA                                   0x0000507d
+#define G82_DISP_CORE_CHANNEL_DMA                                    0x0000827d
+#define GT200_DISP_CORE_CHANNEL_DMA                                  0x0000837d
+#define GT214_DISP_CORE_CHANNEL_DMA                                  0x0000857d
+#define GT206_DISP_CORE_CHANNEL_DMA                                  0x0000887d
+#define GF110_DISP_CORE_CHANNEL_DMA                                  0x0000907d
+#define GK104_DISP_CORE_CHANNEL_DMA                                  0x0000917d
+#define GK110_DISP_CORE_CHANNEL_DMA                                  0x0000927d
+#define GM107_DISP_CORE_CHANNEL_DMA                                  0x0000947d
+#define GM204_DISP_CORE_CHANNEL_DMA                                  0x0000957d
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA                                0x0000507e
+#define G82_DISP_OVERLAY_CHANNEL_DMA                                 0x0000827e
+#define GT200_DISP_OVERLAY_CHANNEL_DMA                               0x0000837e
+#define GT214_DISP_OVERLAY_CHANNEL_DMA                               0x0000857e
+#define GF110_DISP_OVERLAY_CONTROL_DMA                               0x0000907e
+#define GK104_DISP_OVERLAY_CONTROL_DMA                               0x0000917e
+
+#define FERMI_A                                                      0x00009097
+#define FERMI_B                                                      0x00009197
+#define FERMI_C                                                      0x00009297
+
+#define KEPLER_A                                                     0x0000a097
+#define KEPLER_B                                                     0x0000a197
+#define KEPLER_C                                                     0x0000a297
+
+#define MAXWELL_A                                                    0x0000b097
+
+#define FERMI_COMPUTE_A                                              0x000090c0
+#define FERMI_COMPUTE_B                                              0x000091c0
+
+#define KEPLER_COMPUTE_A                                             0x0000a0c0
+#define KEPLER_COMPUTE_B                                             0x0000a1c0
+
+#define MAXWELL_COMPUTE_A                                            0x0000b0c0
+
+
+/*******************************************************************************
+ * client
+ ******************************************************************************/
+
+#define NV_CLIENT_DEVLIST                                                  0x00
+
+struct nv_client_devlist_v0 {
+	__u8  version;
+	__u8  count;
+	__u8  pad02[6];
+	__u64 device[];
+};
+
+
+/*******************************************************************************
+ * device
+ ******************************************************************************/
+
+struct nv_device_v0 {
+	__u8  version;
+	__u8  pad01[7];
+	__u64 device;	/* device identifier, ~0 for client default */
+#define NV_DEVICE_V0_DISABLE_IDENTIFY                     0x0000000000000001ULL
+#define NV_DEVICE_V0_DISABLE_MMIO                         0x0000000000000002ULL
+#define NV_DEVICE_V0_DISABLE_VBIOS                        0x0000000000000004ULL
+#define NV_DEVICE_V0_DISABLE_CORE                         0x0000000000000008ULL
+#define NV_DEVICE_V0_DISABLE_DISP                         0x0000000000010000ULL
+#define NV_DEVICE_V0_DISABLE_FIFO                         0x0000000000020000ULL
+#define NV_DEVICE_V0_DISABLE_GR                           0x0000000100000000ULL
+#define NV_DEVICE_V0_DISABLE_MPEG                         0x0000000200000000ULL
+#define NV_DEVICE_V0_DISABLE_ME                           0x0000000400000000ULL
+#define NV_DEVICE_V0_DISABLE_VP                           0x0000000800000000ULL
+#define NV_DEVICE_V0_DISABLE_CIPHER                       0x0000001000000000ULL
+#define NV_DEVICE_V0_DISABLE_BSP                          0x0000002000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSPPP                        0x0000004000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE0                          0x0000008000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE1                          0x0000010000000000ULL
+#define NV_DEVICE_V0_DISABLE_VIC                          0x0000020000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSENC                        0x0000040000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE2                          0x0000080000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSVLD                        0x0000100000000000ULL
+#define NV_DEVICE_V0_DISABLE_SEC                          0x0000200000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSPDEC                       0x0000400000000000ULL
+	__u64 disable;	/* disable particular subsystems */
+	__u64 debug0;	/* as above, but *internal* ids, and *NOT* ABI */
+};
+
+#define NV_DEVICE_V0_INFO                                                  0x00
+
+struct nv_device_info_v0 {
+	__u8  version;
+#define NV_DEVICE_INFO_V0_IGP                                              0x00
+#define NV_DEVICE_INFO_V0_PCI                                              0x01
+#define NV_DEVICE_INFO_V0_AGP                                              0x02
+#define NV_DEVICE_INFO_V0_PCIE                                             0x03
+#define NV_DEVICE_INFO_V0_SOC                                              0x04
+	__u8  platform;
+	__u16 chipset;	/* from NV_PMC_BOOT_0 */
+	__u8  revision;	/* from NV_PMC_BOOT_0 */
+#define NV_DEVICE_INFO_V0_TNT                                              0x01
+#define NV_DEVICE_INFO_V0_CELSIUS                                          0x02
+#define NV_DEVICE_INFO_V0_KELVIN                                           0x03
+#define NV_DEVICE_INFO_V0_RANKINE                                          0x04
+#define NV_DEVICE_INFO_V0_CURIE                                            0x05
+#define NV_DEVICE_INFO_V0_TESLA                                            0x06
+#define NV_DEVICE_INFO_V0_FERMI                                            0x07
+#define NV_DEVICE_INFO_V0_KEPLER                                           0x08
+#define NV_DEVICE_INFO_V0_MAXWELL                                          0x09
+	__u8  family;
+	__u8  pad06[2];
+	__u64 ram_size;
+	__u64 ram_user;
+};
+
+
+/*******************************************************************************
+ * context dma
+ ******************************************************************************/
+
+struct nv_dma_v0 {
+	__u8  version;
+#define NV_DMA_V0_TARGET_VM                                                0x00
+#define NV_DMA_V0_TARGET_VRAM                                              0x01
+#define NV_DMA_V0_TARGET_PCI                                               0x02
+#define NV_DMA_V0_TARGET_PCI_US                                            0x03
+#define NV_DMA_V0_TARGET_AGP                                               0x04
+	__u8  target;
+#define NV_DMA_V0_ACCESS_VM                                                0x00
+#define NV_DMA_V0_ACCESS_RD                                                0x01
+#define NV_DMA_V0_ACCESS_WR                                                0x02
+#define NV_DMA_V0_ACCESS_RDWR                 (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
+	__u8  access;
+	__u8  pad03[5];
+	__u64 start;
+	__u64 limit;
+	/* ... chipset-specific class data */
+};
+
+struct nv50_dma_v0 {
+	__u8  version;
+#define NV50_DMA_V0_PRIV_VM                                                0x00
+#define NV50_DMA_V0_PRIV_US                                                0x01
+#define NV50_DMA_V0_PRIV__S                                                0x02
+	__u8  priv;
+#define NV50_DMA_V0_PART_VM                                                0x00
+#define NV50_DMA_V0_PART_256                                               0x01
+#define NV50_DMA_V0_PART_1KB                                               0x02
+	__u8  part;
+#define NV50_DMA_V0_COMP_NONE                                              0x00
+#define NV50_DMA_V0_COMP_1                                                 0x01
+#define NV50_DMA_V0_COMP_2                                                 0x02
+#define NV50_DMA_V0_COMP_VM                                                0x03
+	__u8  comp;
+#define NV50_DMA_V0_KIND_PITCH                                             0x00
+#define NV50_DMA_V0_KIND_VM                                                0x7f
+	__u8  kind;
+	__u8  pad05[3];
+};
+
+struct gf100_dma_v0 {
+	__u8  version;
+#define GF100_DMA_V0_PRIV_VM                                               0x00
+#define GF100_DMA_V0_PRIV_US                                               0x01
+#define GF100_DMA_V0_PRIV__S                                               0x02
+	__u8  priv;
+#define GF100_DMA_V0_KIND_PITCH                                            0x00
+#define GF100_DMA_V0_KIND_VM                                               0xff
+	__u8  kind;
+	__u8  pad03[5];
+};
+
+struct gf110_dma_v0 {
+	__u8  version;
+#define GF110_DMA_V0_PAGE_LP                                               0x00
+#define GF110_DMA_V0_PAGE_SP                                               0x01
+	__u8  page;
+#define GF110_DMA_V0_KIND_PITCH                                            0x00
+#define GF110_DMA_V0_KIND_VM                                               0xff
+	__u8  kind;
+	__u8  pad03[5];
+};
+
+
+/*******************************************************************************
+ * perfmon
+ ******************************************************************************/
+
+struct nvif_perfctr_v0 {
+	__u8  version;
+	__u8  pad01[1];
+	__u16 logic_op;
+	__u8  pad04[4];
+	char  name[4][64];
+};
+
+#define NVIF_PERFCTR_V0_QUERY                                              0x00
+#define NVIF_PERFCTR_V0_SAMPLE                                             0x01
+#define NVIF_PERFCTR_V0_READ                                               0x02
+
+struct nvif_perfctr_query_v0 {
+	__u8  version;
+	__u8  pad01[3];
+	__u32 iter;
+	char  name[64];
+};
+
+struct nvif_perfctr_sample {
+};
+
+struct nvif_perfctr_read_v0 {
+	__u8  version;
+	__u8  pad01[7];
+	__u32 ctr;
+	__u32 clk;
+};
+
+
+/*******************************************************************************
+ * device control
+ ******************************************************************************/
+
+#define NVIF_CONTROL_PSTATE_INFO                                           0x00
+#define NVIF_CONTROL_PSTATE_ATTR                                           0x01
+#define NVIF_CONTROL_PSTATE_USER                                           0x02
+
+struct nvif_control_pstate_info_v0 {
+	__u8  version;
+	__u8  count; /* out: number of power states */
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE                         (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON                         (-2)
+	__s8  ustate_ac; /* out: target pstate index */
+	__s8  ustate_dc; /* out: target pstate index */
+	__s8  pwrsrc; /* out: current power source */
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN                         (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON                         (-2)
+	__s8  pstate; /* out: current pstate index */
+	__u8  pad06[2];
+};
+
+struct nvif_control_pstate_attr_v0 {
+	__u8  version;
+#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT                          (-1)
+	__s8  state; /*  in: index of pstate to query
+		      * out: pstate identifier
+		      */
+	__u8  index; /*  in: index of attribute to query
+		      * out: index of next attribute, or 0 if no more
+		      */
+	__u8  pad03[5];
+	__u32 min;
+	__u32 max;
+	char  name[32];
+	char  unit[16];
+};
+
+struct nvif_control_pstate_user_v0 {
+	__u8  version;
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN                          (-1)
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON                          (-2)
+	__s8  ustate; /*  in: pstate identifier */
+	__s8  pwrsrc; /*  in: target power source */
+	__u8  pad03[5];
+};
+
+
+/*******************************************************************************
+ * DMA FIFO channels
+ ******************************************************************************/
+
+struct nv03_channel_dma_v0 {
+	__u8  version;
+	__u8  chid;
+	__u8  pad02[2];
+	__u32 pushbuf;
+	__u64 offset;
+};
+
+#define G82_CHANNEL_DMA_V0_NTFY_UEVENT                                     0x00
+
+/*******************************************************************************
+ * GPFIFO channels
+ ******************************************************************************/
+
+struct nv50_channel_gpfifo_v0 {
+	__u8  version;
+	__u8  chid;
+	__u8  pad01[6];
+	__u32 pushbuf;
+	__u32 ilength;
+	__u64 ioffset;
+};
+
+struct kepler_channel_gpfifo_a_v0 {
+	__u8  version;
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR                               0x01
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC                           0x02
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP                            0x04
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD                            0x08
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0                              0x10
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1                              0x20
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC                              0x40
+	__u8  engine;
+	__u16 chid;
+	__u8  pad04[4];
+	__u32 pushbuf;
+	__u32 ilength;
+	__u64 ioffset;
+};
+
+/*******************************************************************************
+ * legacy display
+ ******************************************************************************/
+
+#define NV04_DISP_NTFY_VBLANK                                              0x00
+#define NV04_DISP_NTFY_CONN                                                0x01
+
+struct nv04_disp_mthd_v0 {
+	__u8  version;
+#define NV04_DISP_SCANOUTPOS                                               0x00
+	__u8  method;
+	__u8  head;
+	__u8  pad03[5];
+};
+
+struct nv04_disp_scanoutpos_v0 {
+	__u8  version;
+	__u8  pad01[7];
+	__s64 time[2];
+	__u16 vblanks;
+	__u16 vblanke;
+	__u16 vtotal;
+	__u16 vline;
+	__u16 hblanks;
+	__u16 hblanke;
+	__u16 htotal;
+	__u16 hline;
+};
+
+/*******************************************************************************
+ * display
+ ******************************************************************************/
+
+#define NV50_DISP_MTHD                                                     0x00
+
+struct nv50_disp_mthd_v0 {
+	__u8  version;
+#define NV50_DISP_SCANOUTPOS                                               0x00
+	__u8  method;
+	__u8  head;
+	__u8  pad03[5];
+};
+
+struct nv50_disp_mthd_v1 {
+	__u8  version;
+#define NV50_DISP_MTHD_V1_DAC_PWR                                          0x10
+#define NV50_DISP_MTHD_V1_DAC_LOAD                                         0x11
+#define NV50_DISP_MTHD_V1_SOR_PWR                                          0x20
+#define NV50_DISP_MTHD_V1_SOR_HDA_ELD                                      0x21
+#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR                                     0x22
+#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT                                  0x23
+#define NV50_DISP_MTHD_V1_SOR_DP_PWR                                       0x24
+#define NV50_DISP_MTHD_V1_PIOR_PWR                                         0x30
+	__u8  method;
+	__u16 hasht;
+	__u16 hashm;
+	__u8  pad06[2];
+};
+
+struct nv50_disp_dac_pwr_v0 {
+	__u8  version;
+	__u8  state;
+	__u8  data;
+	__u8  vsync;
+	__u8  hsync;
+	__u8  pad05[3];
+};
+
+struct nv50_disp_dac_load_v0 {
+	__u8  version;
+	__u8  load;
+	__u8  pad02[2];
+	__u32 data;
+};
+
+struct nv50_disp_sor_pwr_v0 {
+	__u8  version;
+	__u8  state;
+	__u8  pad02[6];
+};
+
+struct nv50_disp_sor_hda_eld_v0 {
+	__u8  version;
+	__u8  pad01[7];
+	__u8  data[];
+};
+
+struct nv50_disp_sor_hdmi_pwr_v0 {
+	__u8  version;
+	__u8  state;
+	__u8  max_ac_packet;
+	__u8  rekey;
+	__u8  pad04[4];
+};
+
+struct nv50_disp_sor_lvds_script_v0 {
+	__u8  version;
+	__u8  pad01[1];
+	__u16 script;
+	__u8  pad04[4];
+};
+
+struct nv50_disp_sor_dp_pwr_v0 {
+	__u8  version;
+	__u8  state;
+	__u8  pad02[6];
+};
+
+struct nv50_disp_pior_pwr_v0 {
+	__u8  version;
+	__u8  state;
+	__u8  type;
+	__u8  pad03[5];
+};
+
+/* core */
+struct nv50_disp_core_channel_dma_v0 {
+	__u8  version;
+	__u8  pad01[3];
+	__u32 pushbuf;
+};
+
+#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
+
+/* cursor immediate */
+struct nv50_disp_cursor_v0 {
+	__u8  version;
+	__u8  head;
+	__u8  pad02[6];
+};
+
+#define NV50_DISP_CURSOR_V0_NTFY_UEVENT                                    0x00
+
+/* base */
+struct nv50_disp_base_channel_dma_v0 {
+	__u8  version;
+	__u8  pad01[2];
+	__u8  head;
+	__u32 pushbuf;
+};
+
+#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
+
+/* overlay */
+struct nv50_disp_overlay_channel_dma_v0 {
+	__u8  version;
+	__u8  pad01[2];
+	__u8  head;
+	__u32 pushbuf;
+};
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT                       0x00
+
+/* overlay immediate */
+struct nv50_disp_overlay_v0 {
+	__u8  version;
+	__u8  head;
+	__u8  pad02[6];
+};
+
+#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT                                   0x00
+
+/*******************************************************************************
+ * fermi
+ ******************************************************************************/
+
+#define FERMI_A_ZBC_COLOR                                                  0x00
+#define FERMI_A_ZBC_DEPTH                                                  0x01
+
+struct fermi_a_zbc_color_v0 {
+	__u8  version;
+#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO                                      0x01
+#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE                                 0x02
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32                       0x04
+#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16                           0x08
+#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16                       0x0c
+#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16                       0x10
+#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16                       0x14
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16                       0x16
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8                                  0x18
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8                               0x1c
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10                               0x20
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10                           0x24
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8                                  0x28
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8                               0x2c
+#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8                              0x30
+#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8                              0x34
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8                              0x38
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10                               0x3c
+#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11                              0x40
+	__u8  format;
+	__u8  index;
+	__u8  pad03[5];
+	__u32 ds[4];
+	__u32 l2[4];
+};
+
+struct fermi_a_zbc_depth_v0 {
+	__u8  version;
+#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32                                      0x01
+	__u8  format;
+	__u8  index;
+	__u8  pad03[5];
+	__u32 ds;
+	__u32 l2;
+};
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h
new file mode 100644
index 0000000..eca648e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/client.h
@@ -0,0 +1,39 @@
+#ifndef __NVIF_CLIENT_H__
+#define __NVIF_CLIENT_H__
+
+#include <nvif/object.h>
+
+struct nvif_client {
+	struct nvif_object base;
+	struct nvif_object *object; /*XXX: hack for nvif_object() */
+	const struct nvif_driver *driver;
+	bool super;
+};
+
+static inline struct nvif_client *
+nvif_client(struct nvif_object *object)
+{
+	while (object && object->parent != object)
+		object = object->parent;
+	return (void *)object;
+}
+
+int  nvif_client_init(void (*dtor)(struct nvif_client *), const char *,
+		      const char *, u64, const char *, const char *,
+		      struct nvif_client *);
+void nvif_client_fini(struct nvif_client *);
+int  nvif_client_new(const char *, const char *, u64, const char *,
+		     const char *, struct nvif_client **);
+void nvif_client_ref(struct nvif_client *, struct nvif_client **);
+int  nvif_client_ioctl(struct nvif_client *, void *, u32);
+int  nvif_client_suspend(struct nvif_client *);
+int  nvif_client_resume(struct nvif_client *);
+
+/*XXX*/
+#include <core/client.h>
+#define nvxx_client(a) ({ \
+	struct nvif_client *_client = nvif_client(nvif_object(a)); \
+	nvkm_client(_client->base.priv); \
+})
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h
new file mode 100644
index 0000000..88553a7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/device.h
@@ -0,0 +1,61 @@
+#ifndef __NVIF_DEVICE_H__
+#define __NVIF_DEVICE_H__
+
+#include <nvif/object.h>
+#include <nvif/class.h>
+
+struct nvif_device {
+	struct nvif_object base;
+	struct nvif_object *object; /*XXX: hack for nvif_object() */
+	struct nv_device_info_v0 info;
+};
+
+static inline struct nvif_device *
+nvif_device(struct nvif_object *object)
+{
+	while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ )
+		object = object->parent;
+	return (void *)object;
+}
+
+int  nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *),
+		      u32 handle, u32 oclass, void *, u32,
+		      struct nvif_device *);
+void nvif_device_fini(struct nvif_device *);
+int  nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
+		     void *, u32, struct nvif_device **);
+void nvif_device_ref(struct nvif_device *, struct nvif_device **);
+
+/*XXX*/
+#include <subdev/bios.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/gpio.h>
+#include <subdev/clk.h>
+#include <subdev/i2c.h>
+#include <subdev/timer.h>
+#include <subdev/therm.h>
+
+#define nvxx_device(a) nv_device(nvxx_object((a)))
+#define nvxx_bios(a) nvkm_bios(nvxx_device(a))
+#define nvxx_fb(a) nvkm_fb(nvxx_device(a))
+#define nvxx_mmu(a) nvkm_mmu(nvxx_device(a))
+#define nvxx_bar(a) nvkm_bar(nvxx_device(a))
+#define nvxx_gpio(a) nvkm_gpio(nvxx_device(a))
+#define nvxx_clk(a) nvkm_clk(nvxx_device(a))
+#define nvxx_i2c(a) nvkm_i2c(nvxx_device(a))
+#define nvxx_timer(a) nvkm_timer(nvxx_device(a))
+#define nvxx_wait(a,b,c,d) nv_wait(nvxx_timer(a), (b), (c), (d))
+#define nvxx_wait_cb(a,b,c) nv_wait_cb(nvxx_timer(a), (b), (c))
+#define nvxx_therm(a) nvkm_therm(nvxx_device(a))
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <engine/gr.h>
+#include <engine/sw.h>
+
+#define nvxx_fifo(a) nvkm_fifo(nvxx_device(a))
+#define nvxx_fifo_chan(a) ((struct nvkm_fifo_chan *)nvxx_object(a))
+#define nvxx_gr(a) ((struct nvkm_gr *)nvkm_engine(nvxx_object(a), NVDEV_ENGINE_GR))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/include/nvif/driver.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/driver.h
rename to drivers/gpu/drm/nouveau/include/nvif/driver.h
diff --git a/drivers/gpu/drm/nouveau/nvif/event.h b/drivers/gpu/drm/nouveau/include/nvif/event.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/event.h
rename to drivers/gpu/drm/nouveau/include/nvif/event.h
diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/ioctl.h
rename to drivers/gpu/drm/nouveau/include/nvif/ioctl.h
diff --git a/drivers/gpu/drm/nouveau/nvif/list.h b/drivers/gpu/drm/nouveau/include/nvif/list.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/list.h
rename to drivers/gpu/drm/nouveau/include/nvif/list.h
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.h b/drivers/gpu/drm/nouveau/include/nvif/notify.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/notify.h
rename to drivers/gpu/drm/nouveau/include/nvif/notify.h
diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h
new file mode 100644
index 0000000..04c8747
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/object.h
@@ -0,0 +1,75 @@
+#ifndef __NVIF_OBJECT_H__
+#define __NVIF_OBJECT_H__
+
+#include <nvif/os.h>
+
+struct nvif_object {
+	struct nvif_object *parent;
+	struct nvif_object *object; /*XXX: hack for nvif_object() */
+	struct kref refcount;
+	u32 handle;
+	u32 oclass;
+	void *data;
+	u32   size;
+	void *priv; /*XXX: hack */
+	void (*dtor)(struct nvif_object *);
+	struct {
+		void __iomem *ptr;
+		u32 size;
+	} map;
+};
+
+int  nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *),
+		      u32 handle, u32 oclass, void *, u32,
+		      struct nvif_object *);
+void nvif_object_fini(struct nvif_object *);
+int  nvif_object_new(struct nvif_object *, u32 handle, u32 oclass,
+		     void *, u32, struct nvif_object **);
+void nvif_object_ref(struct nvif_object *, struct nvif_object **);
+int  nvif_object_ioctl(struct nvif_object *, void *, u32, void **);
+int  nvif_object_sclass(struct nvif_object *, u32 *, int);
+u32  nvif_object_rd(struct nvif_object *, int, u64);
+void nvif_object_wr(struct nvif_object *, int, u64, u32);
+int  nvif_object_mthd(struct nvif_object *, u32, void *, u32);
+int  nvif_object_map(struct nvif_object *);
+void nvif_object_unmap(struct nvif_object *);
+
+#define nvif_object(a) (a)->object
+
+#define ioread8_native ioread8
+#define iowrite8_native iowrite8
+#define nvif_rd(a,b,c) ({                                                      \
+	struct nvif_object *_object = nvif_object(a);                          \
+	u32 _data;                                                             \
+	if (likely(_object->map.ptr))                                          \
+		_data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c));      \
+	else                                                                   \
+		_data = nvif_object_rd(_object, (b) / 8, (c));                 \
+	_data;                                                                 \
+})
+#define nvif_wr(a,b,c,d) ({                                                    \
+	struct nvif_object *_object = nvif_object(a);                          \
+	if (likely(_object->map.ptr))                                          \
+		iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c));        \
+	else                                                                   \
+		nvif_object_wr(_object, (b) / 8, (c), (d));                    \
+})
+#define nvif_rd08(a,b) ({ u8  _v = nvif_rd((a), 8, (b)); _v; })
+#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; })
+#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; })
+#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c))
+#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c))
+#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c))
+#define nvif_mask(a,b,c,d) ({                                                  \
+	u32 _v = nvif_rd32(nvif_object(a), (b));                               \
+	nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d));                     \
+	_v;                                                                    \
+})
+
+#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d))
+
+/*XXX*/
+#include <core/object.h>
+#define nvxx_object(a) ((struct nvkm_object *)nvif_object(a)->priv)
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/os.h
rename to drivers/gpu/drm/nouveau/include/nvif/os.h
diff --git a/drivers/gpu/drm/nouveau/nvif/unpack.h b/drivers/gpu/drm/nouveau/include/nvif/unpack.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/nvif/unpack.h
rename to drivers/gpu/drm/nouveau/include/nvif/unpack.h
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
new file mode 100644
index 0000000..a35b382
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
@@ -0,0 +1,55 @@
+#ifndef __NVKM_CLIENT_H__
+#define __NVKM_CLIENT_H__
+#include <core/namedb.h>
+
+struct nvkm_client {
+	struct nvkm_namedb namedb;
+	struct nvkm_handle *root;
+	struct nvkm_object *device;
+	char name[32];
+	u32 debug;
+	struct nvkm_vm *vm;
+	bool super;
+	void *data;
+
+	int (*ntfy)(const void *, u32, const void *, u32);
+	struct nvkm_client_notify *notify[16];
+};
+
+static inline struct nvkm_client *
+nv_client(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS)))
+		nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+static inline struct nvkm_client *
+nvkm_client(void *obj)
+{
+	struct nvkm_object *client = nv_object(obj);
+	while (client && !(nv_iclass(client, NV_CLIENT_CLASS)))
+		client = client->parent;
+	return (void *)client;
+}
+
+#define nvkm_client_create(n,c,oc,od,d)                                     \
+	nvkm_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)
+
+int  nvkm_client_create_(const char *name, u64 device, const char *cfg,
+			    const char *dbg, int, void **);
+#define nvkm_client_destroy(p)                                              \
+	nvkm_namedb_destroy(&(p)->base)
+
+int  nvkm_client_init(struct nvkm_client *);
+int  nvkm_client_fini(struct nvkm_client *, bool suspend);
+const char *nvkm_client_name(void *obj);
+
+int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *,
+			   void *data, u32 size);
+int nvkm_client_notify_del(struct nvkm_client *, int index);
+int nvkm_client_notify_get(struct nvkm_client *, int index);
+int nvkm_client_notify_put(struct nvkm_client *, int index);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h
new file mode 100644
index 0000000..d07cb86
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h
@@ -0,0 +1,18 @@
+#ifndef __NVKM_DEBUG_H__
+#define __NVKM_DEBUG_H__
+extern int nv_info_debug_level;
+
+#define NV_DBG_FATAL    0
+#define NV_DBG_ERROR    1
+#define NV_DBG_WARN     2
+#define NV_DBG_INFO     nv_info_debug_level
+#define NV_DBG_DEBUG    4
+#define NV_DBG_TRACE    5
+#define NV_DBG_PARANOIA 6
+#define NV_DBG_SPAM     7
+
+#define NV_DBG_INFO_NORMAL 3
+#define NV_DBG_INFO_SILENT NV_DBG_DEBUG
+
+#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
new file mode 100644
index 0000000..333db33
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -0,0 +1,101 @@
+#ifndef __NVKM_DEVICE_H__
+#define __NVKM_DEVICE_H__
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_device {
+	struct nvkm_engine engine;
+	struct list_head head;
+
+	struct pci_dev *pdev;
+	struct platform_device *platformdev;
+	u64 handle;
+
+	struct nvkm_event event;
+
+	const char *cfgopt;
+	const char *dbgopt;
+	const char *name;
+	const char *cname;
+	u64 disable_mask;
+
+	enum {
+		NV_04    = 0x04,
+		NV_10    = 0x10,
+		NV_11    = 0x11,
+		NV_20    = 0x20,
+		NV_30    = 0x30,
+		NV_40    = 0x40,
+		NV_50    = 0x50,
+		NV_C0    = 0xc0,
+		NV_E0    = 0xe0,
+		GM100    = 0x110,
+	} card_type;
+	u32 chipset;
+	u8  chiprev;
+	u32 crystal;
+
+	struct nvkm_oclass *oclass[NVDEV_SUBDEV_NR];
+	struct nvkm_object *subdev[NVDEV_SUBDEV_NR];
+
+	struct {
+		struct notifier_block nb;
+	} acpi;
+};
+
+struct nvkm_device *nvkm_device_find(u64 name);
+int nvkm_device_list(u64 *name, int size);
+
+struct nvkm_device *nv_device(void *obj);
+
+static inline bool
+nv_device_match(struct nvkm_object *object, u16 dev, u16 ven, u16 sub)
+{
+	struct nvkm_device *device = nv_device(object);
+	return device->pdev->device == dev &&
+	       device->pdev->subsystem_vendor == ven &&
+	       device->pdev->subsystem_device == sub;
+}
+
+static inline bool
+nv_device_is_pci(struct nvkm_device *device)
+{
+	return device->pdev != NULL;
+}
+
+static inline bool
+nv_device_is_cpu_coherent(struct nvkm_device *device)
+{
+	return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
+}
+
+static inline struct device *
+nv_device_base(struct nvkm_device *device)
+{
+	return nv_device_is_pci(device) ? &device->pdev->dev :
+					  &device->platformdev->dev;
+}
+
+resource_size_t
+nv_device_resource_start(struct nvkm_device *device, unsigned int bar);
+
+resource_size_t
+nv_device_resource_len(struct nvkm_device *device, unsigned int bar);
+
+int
+nv_device_get_irq(struct nvkm_device *device, bool stall);
+
+struct platform_device;
+
+enum nv_bus_type {
+	NVKM_BUS_PCI,
+	NVKM_BUS_PLATFORM,
+};
+
+#define nvkm_device_create(p,t,n,s,c,d,u)                                   \
+	nvkm_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
+			       sizeof(**u), (void **)u)
+int  nvkm_device_create_(void *, enum nv_bus_type type, u64 name,
+			    const char *sname, const char *cfg, const char *dbg,
+			    int, void **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h
new file mode 100644
index 0000000..60c5888
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h
@@ -0,0 +1,62 @@
+#ifndef __NVKM_DEVIDX_H__
+#define __NVKM_DEVIDX_H__
+enum nvkm_devidx {
+	NVDEV_ENGINE_DEVICE,
+	NVDEV_SUBDEV_VBIOS,
+
+	/* All subdevs from DEVINIT to DEVINIT_LAST will be created before
+	 * *any* of them are initialised.  This subdev category is used
+	 * for any subdevs that the VBIOS init table parsing may call out
+	 * to during POST.
+	 */
+	NVDEV_SUBDEV_DEVINIT,
+	NVDEV_SUBDEV_IBUS,
+	NVDEV_SUBDEV_GPIO,
+	NVDEV_SUBDEV_I2C,
+	NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
+
+	/* This grouping of subdevs are initialised right after they've
+	 * been created, and are allowed to assume any subdevs in the
+	 * list above them exist and have been initialised.
+	 */
+	NVDEV_SUBDEV_FUSE,
+	NVDEV_SUBDEV_MXM,
+	NVDEV_SUBDEV_MC,
+	NVDEV_SUBDEV_BUS,
+	NVDEV_SUBDEV_TIMER,
+	NVDEV_SUBDEV_FB,
+	NVDEV_SUBDEV_LTC,
+	NVDEV_SUBDEV_INSTMEM,
+	NVDEV_SUBDEV_MMU,
+	NVDEV_SUBDEV_BAR,
+	NVDEV_SUBDEV_PMU,
+	NVDEV_SUBDEV_VOLT,
+	NVDEV_SUBDEV_THERM,
+	NVDEV_SUBDEV_CLK,
+
+	NVDEV_ENGINE_FIRST,
+	NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
+	NVDEV_ENGINE_IFB,
+	NVDEV_ENGINE_FIFO,
+	NVDEV_ENGINE_SW,
+	NVDEV_ENGINE_GR,
+	NVDEV_ENGINE_MPEG,
+	NVDEV_ENGINE_ME,
+	NVDEV_ENGINE_VP,
+	NVDEV_ENGINE_CIPHER,
+	NVDEV_ENGINE_BSP,
+	NVDEV_ENGINE_MSPPP,
+	NVDEV_ENGINE_CE0,
+	NVDEV_ENGINE_CE1,
+	NVDEV_ENGINE_CE2,
+	NVDEV_ENGINE_VIC,
+	NVDEV_ENGINE_MSENC,
+	NVDEV_ENGINE_DISP,
+	NVDEV_ENGINE_PM,
+	NVDEV_ENGINE_MSVLD,
+	NVDEV_ENGINE_SEC,
+	NVDEV_ENGINE_MSPDEC,
+
+	NVDEV_SUBDEV_NR,
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h
new file mode 100644
index 0000000..1bf2e8e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h
@@ -0,0 +1,51 @@
+#ifndef __NVKM_ENGCTX_H__
+#define __NVKM_ENGCTX_H__
+#include <core/gpuobj.h>
+
+#include <subdev/mmu.h>
+
+#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng))
+#define NV_ENGCTX(name,var)  NV_ENGCTX_(NVDEV_ENGINE_##name, (var))
+
+struct nvkm_engctx {
+	struct nvkm_gpuobj gpuobj;
+	struct nvkm_vma vma;
+	struct list_head head;
+	unsigned long save;
+	u64 addr;
+};
+
+static inline struct nvkm_engctx *
+nv_engctx(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS)))
+		nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+#define nvkm_engctx_create(p,e,c,g,s,a,f,d)                                 \
+	nvkm_engctx_create_((p), (e), (c), (g), (s), (a), (f),              \
+			       sizeof(**d), (void **)d)
+
+int  nvkm_engctx_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, struct nvkm_object *,
+			    u32 size, u32 align, u32 flags,
+			    int length, void **data);
+void nvkm_engctx_destroy(struct nvkm_engctx *);
+int  nvkm_engctx_init(struct nvkm_engctx *);
+int  nvkm_engctx_fini(struct nvkm_engctx *, bool suspend);
+
+int  _nvkm_engctx_ctor(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, void *, u32,
+			  struct nvkm_object **);
+void _nvkm_engctx_dtor(struct nvkm_object *);
+int  _nvkm_engctx_init(struct nvkm_object *);
+int  _nvkm_engctx_fini(struct nvkm_object *, bool suspend);
+#define _nvkm_engctx_rd32 _nvkm_gpuobj_rd32
+#define _nvkm_engctx_wr32 _nvkm_gpuobj_wr32
+
+struct nvkm_object *nvkm_engctx_get(struct nvkm_engine *, u64 addr);
+void nvkm_engctx_put(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
new file mode 100644
index 0000000..faf0fd2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
@@ -0,0 +1,56 @@
+#ifndef __NVKM_ENGINE_H__
+#define __NVKM_ENGINE_H__
+#include <core/subdev.h>
+
+#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng))
+#define NV_ENGINE(name,var)  NV_ENGINE_(NVDEV_ENGINE_##name, (var))
+
+struct nvkm_engine {
+	struct nvkm_subdev subdev;
+	struct nvkm_oclass *cclass;
+	struct nvkm_oclass *sclass;
+
+	struct list_head contexts;
+	spinlock_t lock;
+
+	void (*tile_prog)(struct nvkm_engine *, int region);
+	int  (*tlb_flush)(struct nvkm_engine *);
+};
+
+static inline struct nvkm_engine *
+nv_engine(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS)))
+		nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+static inline int
+nv_engidx(struct nvkm_engine *engine)
+{
+	return nv_subidx(&engine->subdev);
+}
+
+struct nvkm_engine *nvkm_engine(void *obj, int idx);
+
+#define nvkm_engine_create(p,e,c,d,i,f,r)                                   \
+	nvkm_engine_create_((p), (e), (c), (d), (i), (f),                   \
+			       sizeof(**r),(void **)r)
+
+#define nvkm_engine_destroy(p)                                              \
+	nvkm_subdev_destroy(&(p)->subdev)
+#define nvkm_engine_init(p)                                                 \
+	nvkm_subdev_init(&(p)->subdev)
+#define nvkm_engine_fini(p,s)                                               \
+	nvkm_subdev_fini(&(p)->subdev, (s))
+
+int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *, bool, const char *,
+			   const char *, int, void **);
+
+#define _nvkm_engine_dtor _nvkm_subdev_dtor
+#define _nvkm_engine_init _nvkm_subdev_init
+#define _nvkm_engine_fini _nvkm_subdev_fini
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h
new file mode 100644
index 0000000..e76f76f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_ENUM_H__
+#define __NVKM_ENUM_H__
+#include <core/os.h>
+
+struct nvkm_enum {
+	u32 value;
+	const char *name;
+	const void *data;
+	u32 data2;
+};
+
+const struct nvkm_enum *nvkm_enum_find(const struct nvkm_enum *, u32 value);
+const struct nvkm_enum *nvkm_enum_print(const struct nvkm_enum *, u32 value);
+
+struct nvkm_bitfield {
+	u32 mask;
+	const char *name;
+};
+
+void nvkm_bitfield_print(const struct nvkm_bitfield *, u32 value);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
new file mode 100644
index 0000000..b98fe2d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_EVENT_H__
+#define __NVKM_EVENT_H__
+#include <core/os.h>
+struct nvkm_notify;
+struct nvkm_object;
+
+struct nvkm_event {
+	const struct nvkm_event_func *func;
+
+	int types_nr;
+	int index_nr;
+
+	spinlock_t refs_lock;
+	spinlock_t list_lock;
+	struct list_head list;
+	int *refs;
+};
+
+struct nvkm_event_func {
+	int  (*ctor)(struct nvkm_object *, void *data, u32 size,
+		     struct nvkm_notify *);
+	void (*send)(void *data, u32 size, struct nvkm_notify *);
+	void (*init)(struct nvkm_event *, int type, int index);
+	void (*fini)(struct nvkm_event *, int type, int index);
+};
+
+int  nvkm_event_init(const struct nvkm_event_func *func, int types_nr,
+		     int index_nr, struct nvkm_event *);
+void nvkm_event_fini(struct nvkm_event *);
+void nvkm_event_get(struct nvkm_event *, u32 types, int index);
+void nvkm_event_put(struct nvkm_event *, u32 types, int index);
+void nvkm_event_send(struct nvkm_event *, u32 types, int index,
+		     void *data, u32 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h
new file mode 100644
index 0000000..e0187e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h
@@ -0,0 +1,64 @@
+#ifndef __NVKM_GPUOBJ_H__
+#define __NVKM_GPUOBJ_H__
+#include <core/object.h>
+#include <core/mm.h>
+struct nvkm_vma;
+struct nvkm_vm;
+
+#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001
+#define NVOBJ_FLAG_ZERO_FREE  0x00000002
+#define NVOBJ_FLAG_HEAP       0x00000004
+
+struct nvkm_gpuobj {
+	struct nvkm_object object;
+	struct nvkm_object *parent;
+	struct nvkm_mm_node *node;
+	struct nvkm_mm heap;
+
+	u32 flags;
+	u64 addr;
+	u32 size;
+};
+
+static inline struct nvkm_gpuobj *
+nv_gpuobj(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS)))
+		nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+#define nvkm_gpuobj_create(p,e,c,v,g,s,a,f,d)                               \
+	nvkm_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f),         \
+			       sizeof(**d), (void **)d)
+#define nvkm_gpuobj_init(p) nvkm_object_init(&(p)->object)
+#define nvkm_gpuobj_fini(p,s) nvkm_object_fini(&(p)->object, (s))
+int  nvkm_gpuobj_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, u32 pclass,
+			    struct nvkm_object *, u32 size, u32 align,
+			    u32 flags, int length, void **);
+void nvkm_gpuobj_destroy(struct nvkm_gpuobj *);
+
+int  nvkm_gpuobj_new(struct nvkm_object *, struct nvkm_object *, u32 size,
+		     u32 align, u32 flags, struct nvkm_gpuobj **);
+int  nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_gpuobj *,
+		     struct nvkm_gpuobj **);
+int  nvkm_gpuobj_map(struct nvkm_gpuobj *, u32 acc, struct nvkm_vma *);
+int  nvkm_gpuobj_map_vm(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access,
+			struct nvkm_vma *);
+void nvkm_gpuobj_unmap(struct nvkm_vma *);
+
+static inline void
+nvkm_gpuobj_ref(struct nvkm_gpuobj *obj, struct nvkm_gpuobj **ref)
+{
+	nvkm_object_ref(&obj->object, (struct nvkm_object **)ref);
+}
+
+void _nvkm_gpuobj_dtor(struct nvkm_object *);
+int  _nvkm_gpuobj_init(struct nvkm_object *);
+int  _nvkm_gpuobj_fini(struct nvkm_object *, bool);
+u32  _nvkm_gpuobj_rd32(struct nvkm_object *, u64);
+void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h
new file mode 100644
index 0000000..67f384d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_HANDLE_H__
+#define __NVKM_HANDLE_H__
+#include <core/os.h>
+struct nvkm_object;
+
+struct nvkm_handle {
+	struct nvkm_namedb *namedb;
+	struct list_head node;
+
+	struct list_head head;
+	struct list_head tree;
+	u32 name;
+	u32 priv;
+
+	u8  route;
+	u64 token;
+
+	struct nvkm_handle *parent;
+	struct nvkm_object *object;
+};
+
+int  nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle,
+			struct nvkm_object *, struct nvkm_handle **);
+void nvkm_handle_destroy(struct nvkm_handle *);
+int  nvkm_handle_init(struct nvkm_handle *);
+int  nvkm_handle_fini(struct nvkm_handle *, bool suspend);
+
+struct nvkm_object *nvkm_handle_ref(struct nvkm_object *, u32 name);
+
+struct nvkm_handle *nvkm_handle_get_class(struct nvkm_object *, u16);
+struct nvkm_handle *nvkm_handle_get_vinst(struct nvkm_object *, u64);
+struct nvkm_handle *nvkm_handle_get_cinst(struct nvkm_object *, u32);
+void nvkm_handle_put(struct nvkm_handle *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h
new file mode 100644
index 0000000..88971eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_IOCTL_H__
+#define __NVKM_IOCTL_H__
+#include <core/os.h>
+struct nvkm_client;
+
+int nvkm_ioctl(struct nvkm_client *, bool, void *, u32, void **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h
new file mode 100644
index 0000000..096eb1a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h
@@ -0,0 +1,40 @@
+#ifndef __NVKM_MM_H__
+#define __NVKM_MM_H__
+#include <core/os.h>
+
+struct nvkm_mm_node {
+	struct list_head nl_entry;
+	struct list_head fl_entry;
+	struct list_head rl_entry;
+
+#define NVKM_MM_HEAP_ANY 0x00
+	u8  heap;
+#define NVKM_MM_TYPE_NONE 0x00
+#define NVKM_MM_TYPE_HOLE 0xff
+	u8  type;
+	u32 offset;
+	u32 length;
+};
+
+struct nvkm_mm {
+	struct list_head nodes;
+	struct list_head free;
+
+	u32 block_size;
+	int heap_nodes;
+};
+
+static inline bool
+nvkm_mm_initialised(struct nvkm_mm *mm)
+{
+	return mm->block_size != 0;
+}
+
+int  nvkm_mm_init(struct nvkm_mm *, u32 offset, u32 length, u32 block);
+int  nvkm_mm_fini(struct nvkm_mm *);
+int  nvkm_mm_head(struct nvkm_mm *, u8 heap, u8 type, u32 size_max,
+		  u32 size_min, u32 align, struct nvkm_mm_node **);
+int  nvkm_mm_tail(struct nvkm_mm *, u8 heap, u8 type, u32 size_max,
+		  u32 size_min, u32 align, struct nvkm_mm_node **);
+void nvkm_mm_free(struct nvkm_mm *, struct nvkm_mm_node **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h
new file mode 100644
index 0000000..4cfe16f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_NAMEDB_H__
+#define __NVKM_NAMEDB_H__
+#include <core/parent.h>
+struct nvkm_handle;
+
+struct nvkm_namedb {
+	struct nvkm_parent parent;
+	rwlock_t lock;
+	struct list_head list;
+};
+
+static inline struct nvkm_namedb *
+nv_namedb(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS)))
+		nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+#define nvkm_namedb_create(p,e,c,v,s,m,d)                                   \
+	nvkm_namedb_create_((p), (e), (c), (v), (s), (m),                   \
+			       sizeof(**d), (void **)d)
+#define nvkm_namedb_init(p)                                                 \
+	nvkm_parent_init(&(p)->parent)
+#define nvkm_namedb_fini(p,s)                                               \
+	nvkm_parent_fini(&(p)->parent, (s))
+#define nvkm_namedb_destroy(p)                                              \
+	nvkm_parent_destroy(&(p)->parent)
+
+int  nvkm_namedb_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, u32 pclass,
+			    struct nvkm_oclass *, u64 engcls,
+			    int size, void **);
+
+int  _nvkm_namedb_ctor(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, void *, u32,
+			  struct nvkm_object **);
+#define _nvkm_namedb_dtor _nvkm_parent_dtor
+#define _nvkm_namedb_init _nvkm_parent_init
+#define _nvkm_namedb_fini _nvkm_parent_fini
+
+int  nvkm_namedb_insert(struct nvkm_namedb *, u32 name, struct nvkm_object *,
+			struct nvkm_handle *);
+void nvkm_namedb_remove(struct nvkm_handle *);
+
+struct nvkm_handle *nvkm_namedb_get(struct nvkm_namedb *, u32);
+struct nvkm_handle *nvkm_namedb_get_class(struct nvkm_namedb *, u16);
+struct nvkm_handle *nvkm_namedb_get_vinst(struct nvkm_namedb *, u64);
+struct nvkm_handle *nvkm_namedb_get_cinst(struct nvkm_namedb *, u32);
+void nvkm_namedb_put(struct nvkm_handle *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
new file mode 100644
index 0000000..753d08c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
@@ -0,0 +1,38 @@
+#ifndef __NVKM_NOTIFY_H__
+#define __NVKM_NOTIFY_H__
+#include <core/os.h>
+struct nvkm_object;
+
+struct nvkm_notify {
+	struct nvkm_event *event;
+	struct list_head head;
+#define NVKM_NOTIFY_USER 0
+#define NVKM_NOTIFY_WORK 1
+	unsigned long flags;
+	int block;
+#define NVKM_NOTIFY_DROP 0
+#define NVKM_NOTIFY_KEEP 1
+	int (*func)(struct nvkm_notify *);
+
+	/* set by nvkm_event ctor */
+	u32 types;
+	int index;
+	u32 size;
+
+	struct work_struct work;
+	/* this is const for a *very* good reason - the data might be on the
+	 * stack from an irq handler.  if you're not core/notify.c then you
+	 * should probably think twice before casting it away...
+	 */
+	const void *data;
+};
+
+int  nvkm_notify_init(struct nvkm_object *, struct nvkm_event *,
+		      int (*func)(struct nvkm_notify *), bool work,
+		      void *data, u32 size, u32 reply,
+		      struct nvkm_notify *);
+void nvkm_notify_fini(struct nvkm_notify *);
+void nvkm_notify_get(struct nvkm_notify *);
+void nvkm_notify_put(struct nvkm_notify *);
+void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
new file mode 100644
index 0000000..6e3cd39
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
@@ -0,0 +1,203 @@
+#ifndef __NVKM_OBJECT_H__
+#define __NVKM_OBJECT_H__
+#include <core/os.h>
+#include <core/printk.h>
+
+#define NV_PARENT_CLASS 0x80000000
+#define NV_NAMEDB_CLASS 0x40000000
+#define NV_CLIENT_CLASS 0x20000000
+#define NV_SUBDEV_CLASS 0x10000000
+#define NV_ENGINE_CLASS 0x08000000
+#define NV_MEMOBJ_CLASS 0x04000000
+#define NV_GPUOBJ_CLASS 0x02000000
+#define NV_ENGCTX_CLASS 0x01000000
+#define NV_OBJECT_CLASS 0x0000ffff
+
+struct nvkm_object {
+	struct nvkm_oclass *oclass;
+	struct nvkm_object *parent;
+	struct nvkm_engine *engine;
+	atomic_t refcount;
+	atomic_t usecount;
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+#define NVKM_OBJECT_MAGIC 0x75ef0bad
+	struct list_head list;
+	u32 _magic;
+#endif
+};
+
+static inline struct nvkm_object *
+nv_object(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (likely(obj)) {
+		struct nvkm_object *object = obj;
+		if (unlikely(object->_magic != NVKM_OBJECT_MAGIC))
+			nv_assert("BAD CAST -> NvObject, invalid magic");
+	}
+#endif
+	return obj;
+}
+
+#define nvkm_object_create(p,e,c,s,d)                                       \
+	nvkm_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d)
+int  nvkm_object_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, u32, int size, void **);
+void nvkm_object_destroy(struct nvkm_object *);
+int  nvkm_object_init(struct nvkm_object *);
+int  nvkm_object_fini(struct nvkm_object *, bool suspend);
+
+int _nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *,
+			 struct nvkm_oclass *, void *, u32,
+			 struct nvkm_object **);
+
+extern struct nvkm_ofuncs nvkm_object_ofuncs;
+
+/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
+ * ".data". */
+struct nvkm_oclass {
+	u32 handle;
+	struct nvkm_ofuncs * const ofuncs;
+	struct nvkm_omthds * const omthds;
+	struct lock_class_key lock_class_key;
+};
+
+#define nv_oclass(o)    nv_object(o)->oclass
+#define nv_hclass(o)    nv_oclass(o)->handle
+#define nv_iclass(o,i) (nv_hclass(o) & (i))
+#define nv_mclass(o)    nv_iclass(o, NV_OBJECT_CLASS)
+
+static inline struct nvkm_object *
+nv_pclass(struct nvkm_object *parent, u32 oclass)
+{
+	while (parent && !nv_iclass(parent, oclass))
+		parent = parent->parent;
+	return parent;
+}
+
+struct nvkm_omthds {
+	u32 start;
+	u32 limit;
+	int (*call)(struct nvkm_object *, u32, void *, u32);
+};
+
+struct nvkm_event;
+struct nvkm_ofuncs {
+	int  (*ctor)(struct nvkm_object *, struct nvkm_object *,
+		     struct nvkm_oclass *, void *data, u32 size,
+		     struct nvkm_object **);
+	void (*dtor)(struct nvkm_object *);
+	int  (*init)(struct nvkm_object *);
+	int  (*fini)(struct nvkm_object *, bool suspend);
+	int  (*mthd)(struct nvkm_object *, u32, void *, u32);
+	int  (*ntfy)(struct nvkm_object *, u32, struct nvkm_event **);
+	int  (* map)(struct nvkm_object *, u64 *, u32 *);
+	u8   (*rd08)(struct nvkm_object *, u64 offset);
+	u16  (*rd16)(struct nvkm_object *, u64 offset);
+	u32  (*rd32)(struct nvkm_object *, u64 offset);
+	void (*wr08)(struct nvkm_object *, u64 offset, u8 data);
+	void (*wr16)(struct nvkm_object *, u64 offset, u16 data);
+	void (*wr32)(struct nvkm_object *, u64 offset, u32 data);
+};
+
+static inline struct nvkm_ofuncs *
+nv_ofuncs(void *obj)
+{
+	return nv_oclass(obj)->ofuncs;
+}
+
+int  nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, void *, u32,
+		      struct nvkm_object **);
+void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **);
+int  nvkm_object_inc(struct nvkm_object *);
+int  nvkm_object_dec(struct nvkm_object *, bool suspend);
+void nvkm_object_debug(void);
+
+static inline int
+nv_exec(void *obj, u32 mthd, void *data, u32 size)
+{
+	struct nvkm_omthds *method = nv_oclass(obj)->omthds;
+
+	while (method && method->call) {
+		if (mthd >= method->start && mthd <= method->limit)
+			return method->call(obj, mthd, data, size);
+		method++;
+	}
+
+	return -EINVAL;
+}
+
+static inline int
+nv_call(void *obj, u32 mthd, u32 data)
+{
+	return nv_exec(obj, mthd, &data, sizeof(data));
+}
+
+static inline u8
+nv_ro08(void *obj, u64 addr)
+{
+	u8 data = nv_ofuncs(obj)->rd08(obj, addr);
+	nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data);
+	return data;
+}
+
+static inline u16
+nv_ro16(void *obj, u64 addr)
+{
+	u16 data = nv_ofuncs(obj)->rd16(obj, addr);
+	nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data);
+	return data;
+}
+
+static inline u32
+nv_ro32(void *obj, u64 addr)
+{
+	u32 data = nv_ofuncs(obj)->rd32(obj, addr);
+	nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data);
+	return data;
+}
+
+static inline void
+nv_wo08(void *obj, u64 addr, u8 data)
+{
+	nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data);
+	nv_ofuncs(obj)->wr08(obj, addr, data);
+}
+
+static inline void
+nv_wo16(void *obj, u64 addr, u16 data)
+{
+	nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data);
+	nv_ofuncs(obj)->wr16(obj, addr, data);
+}
+
+static inline void
+nv_wo32(void *obj, u64 addr, u32 data)
+{
+	nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data);
+	nv_ofuncs(obj)->wr32(obj, addr, data);
+}
+
+static inline u32
+nv_mo32(void *obj, u64 addr, u32 mask, u32 data)
+{
+	u32 temp = nv_ro32(obj, addr);
+	nv_wo32(obj, addr, (temp & ~mask) | data);
+	return temp;
+}
+
+static inline int
+nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
+{
+	unsigned char c1, c2;
+
+	while (len--) {
+		c1 = nv_ro08(obj, addr++);
+		c2 = *(str++);
+		if (c1 != c2)
+			return c1 - c2;
+	}
+	return 0;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
new file mode 100644
index 0000000..532bfa8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
@@ -0,0 +1,17 @@
+#ifndef __NVKM_OPTION_H__
+#define __NVKM_OPTION_H__
+#include <core/os.h>
+
+const char *nvkm_stropt(const char *optstr, const char *opt, int *len);
+bool nvkm_boolopt(const char *optstr, const char *opt, bool value);
+int  nvkm_dbgopt(const char *optstr, const char *sub);
+
+/* compares unterminated string 'str' with zero-terminated string 'cmp' */
+static inline int
+strncasecmpz(const char *str, const char *cmp, size_t len)
+{
+	if (strlen(cmp) != len)
+		return len;
+	return strncasecmp(str, cmp, len);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
new file mode 100644
index 0000000..cd57e23
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
@@ -0,0 +1,4 @@
+#ifndef __NVKM_OS_H__
+#define __NVKM_OS_H__
+#include <nvif/os.h>
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h
new file mode 100644
index 0000000..837e4fe
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_PARENT_H__
+#define __NVKM_PARENT_H__
+#include <core/object.h>
+
+struct nvkm_sclass {
+	struct nvkm_sclass *sclass;
+	struct nvkm_engine *engine;
+	struct nvkm_oclass *oclass;
+};
+
+struct nvkm_parent {
+	struct nvkm_object object;
+
+	struct nvkm_sclass *sclass;
+	u64 engine;
+
+	int  (*context_attach)(struct nvkm_object *, struct nvkm_object *);
+	int  (*context_detach)(struct nvkm_object *, bool suspend,
+			       struct nvkm_object *);
+
+	int  (*object_attach)(struct nvkm_object *parent,
+			      struct nvkm_object *object, u32 name);
+	void (*object_detach)(struct nvkm_object *parent, int cookie);
+};
+
+static inline struct nvkm_parent *
+nv_parent(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS))))
+		nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+#define nvkm_parent_create(p,e,c,v,s,m,d)                                   \
+	nvkm_parent_create_((p), (e), (c), (v), (s), (m),                   \
+			       sizeof(**d), (void **)d)
+#define nvkm_parent_init(p)                                                 \
+	nvkm_object_init(&(p)->object)
+#define nvkm_parent_fini(p,s)                                               \
+	nvkm_object_fini(&(p)->object, (s))
+
+int  nvkm_parent_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, u32 pclass,
+			    struct nvkm_oclass *, u64 engcls,
+			    int size, void **);
+void nvkm_parent_destroy(struct nvkm_parent *);
+
+void _nvkm_parent_dtor(struct nvkm_object *);
+#define _nvkm_parent_init nvkm_object_init
+#define _nvkm_parent_fini nvkm_object_fini
+
+int nvkm_parent_sclass(struct nvkm_object *, u16 handle,
+		       struct nvkm_object **pengine,
+		       struct nvkm_oclass **poclass);
+int nvkm_parent_lclass(struct nvkm_object *, u32 *, int);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h b/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h
new file mode 100644
index 0000000..8364817
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h
@@ -0,0 +1,29 @@
+#ifndef __NVKM_PRINTK_H__
+#define __NVKM_PRINTK_H__
+#include <core/os.h>
+#include <core/debug.h>
+struct nvkm_object;
+
+void __printf(3, 4)
+nv_printk_(struct nvkm_object *, int, const char *, ...);
+
+#define nv_printk(o,l,f,a...) do {                                             \
+	if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG)                                \
+		nv_printk_(nv_object(o), NV_DBG_##l, f, ##a);                  \
+} while(0)
+
+#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
+#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a)
+#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a)
+#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a)
+#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
+#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
+#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
+#define nv_ioctl(o,f,a...) nv_trace(nvkm_client(o), "ioctl: "f, ##a)
+
+#define nv_assert(f,a...) do {                                                 \
+	if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG)                              \
+		nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a);                   \
+	BUG_ON(1);                                                             \
+} while(0)
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h
new file mode 100644
index 0000000..cc132ea
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h
@@ -0,0 +1,20 @@
+#ifndef __NVKM_RAMHT_H__
+#define __NVKM_RAMHT_H__
+#include <core/gpuobj.h>
+
+struct nvkm_ramht {
+	struct nvkm_gpuobj gpuobj;
+	int bits;
+};
+
+int  nvkm_ramht_insert(struct nvkm_ramht *, int chid, u32 handle, u32 context);
+void nvkm_ramht_remove(struct nvkm_ramht *, int cookie);
+int  nvkm_ramht_new(struct nvkm_object *, struct nvkm_object *, u32 size,
+		    u32 align, struct nvkm_ramht **);
+
+static inline void
+nvkm_ramht_ref(struct nvkm_ramht *obj, struct nvkm_ramht **ref)
+{
+	nvkm_gpuobj_ref(&obj->gpuobj, (struct nvkm_gpuobj **)ref);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
new file mode 100644
index 0000000..6fdc391
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
@@ -0,0 +1,119 @@
+#ifndef __NVKM_SUBDEV_H__
+#define __NVKM_SUBDEV_H__
+#include <core/object.h>
+#include <core/devidx.h>
+
+#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub))
+#define NV_SUBDEV(name,var)  NV_SUBDEV_(NVDEV_SUBDEV_##name, (var))
+
+struct nvkm_subdev {
+	struct nvkm_object object;
+	struct mutex mutex;
+	const char *name;
+	void __iomem *mmio;
+	u32 debug;
+	u32 unit;
+
+	void (*intr)(struct nvkm_subdev *);
+};
+
+static inline struct nvkm_subdev *
+nv_subdev(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS)))
+		nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+static inline int
+nv_subidx(struct nvkm_subdev *subdev)
+{
+	return nv_hclass(subdev) & 0xff;
+}
+
+struct nvkm_subdev *nvkm_subdev(void *obj, int idx);
+
+#define nvkm_subdev_create(p,e,o,v,s,f,d)                                   \
+	nvkm_subdev_create_((p), (e), (o), (v), (s), (f),                   \
+			       sizeof(**d),(void **)d)
+
+int  nvkm_subdev_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, u32 pclass,
+			    const char *sname, const char *fname,
+			    int size, void **);
+void nvkm_subdev_destroy(struct nvkm_subdev *);
+int  nvkm_subdev_init(struct nvkm_subdev *);
+int  nvkm_subdev_fini(struct nvkm_subdev *, bool suspend);
+void nvkm_subdev_reset(struct nvkm_object *);
+
+void _nvkm_subdev_dtor(struct nvkm_object *);
+int  _nvkm_subdev_init(struct nvkm_object *);
+int  _nvkm_subdev_fini(struct nvkm_object *, bool suspend);
+
+#define s_printk(s,l,f,a...) do {                                              \
+	if ((s)->debug >= OS_DBG_##l) {                                        \
+		nv_printk((s)->base.parent, (s)->name, l, f, ##a);             \
+	}                                                                      \
+} while(0)
+
+static inline u8
+nv_rd08(void *obj, u32 addr)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	u8 data = ioread8(subdev->mmio + addr);
+	nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data);
+	return data;
+}
+
+static inline u16
+nv_rd16(void *obj, u32 addr)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	u16 data = ioread16_native(subdev->mmio + addr);
+	nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data);
+	return data;
+}
+
+static inline u32
+nv_rd32(void *obj, u32 addr)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	u32 data = ioread32_native(subdev->mmio + addr);
+	nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data);
+	return data;
+}
+
+static inline void
+nv_wr08(void *obj, u32 addr, u8 data)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data);
+	iowrite8(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr16(void *obj, u32 addr, u16 data)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data);
+	iowrite16_native(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr32(void *obj, u32 addr, u32 data)
+{
+	struct nvkm_subdev *subdev = nv_subdev(obj);
+	nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data);
+	iowrite32_native(data, subdev->mmio + addr);
+}
+
+static inline u32
+nv_mask(void *obj, u32 addr, u32 mask, u32 data)
+{
+	u32 temp = nv_rd32(obj, addr);
+	nv_wr32(obj, addr, (temp & ~mask) | data);
+	return temp;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h
new file mode 100644
index 0000000..e489bee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_BSP_H__
+#define __NVKM_BSP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_bsp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
new file mode 100644
index 0000000..7e29c52
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
@@ -0,0 +1,13 @@
+#ifndef __NVKM_CE_H__
+#define __NVKM_CE_H__
+#include <core/engine.h>
+
+void gt215_ce_intr(struct nvkm_subdev *);
+
+extern struct nvkm_oclass gt215_ce_oclass;
+extern struct nvkm_oclass gf100_ce0_oclass;
+extern struct nvkm_oclass gf100_ce1_oclass;
+extern struct nvkm_oclass gk104_ce0_oclass;
+extern struct nvkm_oclass gk104_ce1_oclass;
+extern struct nvkm_oclass gk104_ce2_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h
new file mode 100644
index 0000000..57c29e9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_CIPHER_H__
+#define __NVKM_CIPHER_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_cipher_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h
new file mode 100644
index 0000000..5d4805e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h
@@ -0,0 +1,30 @@
+#ifndef __NOUVEAU_SUBDEV_DEVICE_H__
+#define __NOUVEAU_SUBDEV_DEVICE_H__
+
+#include <core/device.h>
+
+struct platform_device;
+
+enum nv_bus_type {
+	NOUVEAU_BUS_PCI,
+	NOUVEAU_BUS_PLATFORM,
+};
+
+#define nouveau_device_create(p,t,n,s,c,d,u)                                   \
+	nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
+			       sizeof(**u), (void **)u)
+
+int  nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
+			    const char *sname, const char *cfg, const char *dbg,
+			    int, void **);
+
+int nv04_identify(struct nouveau_device *);
+int nv10_identify(struct nouveau_device *);
+int nv20_identify(struct nouveau_device *);
+int nv30_identify(struct nouveau_device *);
+int nv40_identify(struct nouveau_device *);
+int nv50_identify(struct nouveau_device *);
+int nvc0_identify(struct nouveau_device *);
+int nve0_identify(struct nouveau_device *);
+int gm100_identify(struct nouveau_device *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
new file mode 100644
index 0000000..a5e1ed8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_DISP_H__
+#define __NVKM_DISP_H__
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_disp {
+	struct nvkm_engine base;
+
+	struct list_head outp;
+
+	struct nvkm_event hpd;
+	struct nvkm_event vblank;
+};
+
+static inline struct nvkm_disp *
+nvkm_disp(void *obj)
+{
+	return (void *)nvkm_engine(obj, NVDEV_ENGINE_DISP);
+}
+
+extern struct nvkm_oclass *nv04_disp_oclass;
+extern struct nvkm_oclass *nv50_disp_oclass;
+extern struct nvkm_oclass *g84_disp_oclass;
+extern struct nvkm_oclass *gt200_disp_oclass;
+extern struct nvkm_oclass *g94_disp_oclass;
+extern struct nvkm_oclass *gt215_disp_oclass;
+extern struct nvkm_oclass *gf110_disp_oclass;
+extern struct nvkm_oclass *gk104_disp_oclass;
+extern struct nvkm_oclass *gk110_disp_oclass;
+extern struct nvkm_oclass *gm107_disp_oclass;
+extern struct nvkm_oclass *gm204_disp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h
new file mode 100644
index 0000000..c4fce8a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h
@@ -0,0 +1,26 @@
+#ifndef __NVKM_DMAOBJ_H__
+#define __NVKM_DMAOBJ_H__
+#include <core/engine.h>
+struct nvkm_gpuobj;
+
+struct nvkm_dmaobj {
+	struct nvkm_object base;
+	u32 target;
+	u32 access;
+	u64 start;
+	u64 limit;
+};
+
+struct nvkm_dmaeng {
+	struct nvkm_engine base;
+
+	/* creates a "physical" dma object from a struct nvkm_dmaobj */
+	int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		    struct nvkm_gpuobj **);
+};
+
+extern struct nvkm_oclass *nv04_dmaeng_oclass;
+extern struct nvkm_oclass *nv50_dmaeng_oclass;
+extern struct nvkm_oclass *gf100_dmaeng_oclass;
+extern struct nvkm_oclass *gf110_dmaeng_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
new file mode 100644
index 0000000..bd38cf9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
@@ -0,0 +1,81 @@
+#ifndef __NVKM_FALCON_H__
+#define __NVKM_FALCON_H__
+#include <core/engctx.h>
+
+struct nvkm_falcon_chan {
+	struct nvkm_engctx base;
+};
+
+#define nvkm_falcon_context_create(p,e,c,g,s,a,f,d)                         \
+	nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_falcon_context_destroy(d)                                      \
+	nvkm_engctx_destroy(&(d)->base)
+#define nvkm_falcon_context_init(d)                                         \
+	nvkm_engctx_init(&(d)->base)
+#define nvkm_falcon_context_fini(d,s)                                       \
+	nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_falcon_context_ctor _nvkm_engctx_ctor
+#define _nvkm_falcon_context_dtor _nvkm_engctx_dtor
+#define _nvkm_falcon_context_init _nvkm_engctx_init
+#define _nvkm_falcon_context_fini _nvkm_engctx_fini
+#define _nvkm_falcon_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_falcon_context_wr32 _nvkm_engctx_wr32
+
+struct nvkm_falcon_data {
+	bool external;
+};
+
+#include <core/engine.h>
+
+struct nvkm_falcon {
+	struct nvkm_engine base;
+
+	u32 addr;
+	u8  version;
+	u8  secret;
+
+	struct nvkm_gpuobj *core;
+	bool external;
+
+	struct {
+		u32 limit;
+		u32 *data;
+		u32  size;
+	} code;
+
+	struct {
+		u32 limit;
+		u32 *data;
+		u32  size;
+	} data;
+};
+
+#define nv_falcon(priv) (&(priv)->base)
+
+#define nvkm_falcon_create(p,e,c,b,d,i,f,r)                                 \
+	nvkm_falcon_create_((p), (e), (c), (b), (d), (i), (f),              \
+			       sizeof(**r),(void **)r)
+#define nvkm_falcon_destroy(p)                                              \
+	nvkm_engine_destroy(&(p)->base)
+#define nvkm_falcon_init(p) ({                                              \
+	struct nvkm_falcon *falcon = (p);                                   \
+	_nvkm_falcon_init(nv_object(falcon));                               \
+})
+#define nvkm_falcon_fini(p,s) ({                                            \
+	struct nvkm_falcon *falcon = (p);                                   \
+	_nvkm_falcon_fini(nv_object(falcon), (s));                          \
+})
+
+int nvkm_falcon_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *, u32, bool, const char *,
+			   const char *, int, void **);
+
+void nvkm_falcon_intr(struct nvkm_subdev *subdev);
+
+#define _nvkm_falcon_dtor _nvkm_engine_dtor
+int  _nvkm_falcon_init(struct nvkm_object *);
+int  _nvkm_falcon_fini(struct nvkm_object *, bool);
+u32  _nvkm_falcon_rd32(struct nvkm_object *, u64);
+void _nvkm_falcon_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
new file mode 100644
index 0000000..05321ce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
@@ -0,0 +1,126 @@
+#ifndef __NVKM_FIFO_H__
+#define __NVKM_FIFO_H__
+#include <core/namedb.h>
+
+struct nvkm_fifo_chan {
+	struct nvkm_namedb namedb;
+	struct nvkm_dmaobj *pushdma;
+	struct nvkm_gpuobj *pushgpu;
+	void __iomem *user;
+	u64 addr;
+	u32 size;
+	u16 chid;
+	atomic_t refcnt; /* NV04_NVSW_SET_REF */
+};
+
+static inline struct nvkm_fifo_chan *
+nvkm_fifo_chan(void *obj)
+{
+	return (void *)nv_namedb(obj);
+}
+
+#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d)                         \
+	nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n),        \
+				     (m), sizeof(**d), (void **)d)
+#define nvkm_fifo_channel_init(p)                                           \
+	nvkm_namedb_init(&(p)->namedb)
+#define nvkm_fifo_channel_fini(p,s)                                         \
+	nvkm_namedb_fini(&(p)->namedb, (s))
+
+int  nvkm_fifo_channel_create_(struct nvkm_object *,
+				  struct nvkm_object *,
+				  struct nvkm_oclass *,
+				  int bar, u32 addr, u32 size, u32 push,
+				  u64 engmask, int len, void **);
+void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *);
+
+#define _nvkm_fifo_channel_init _nvkm_namedb_init
+#define _nvkm_fifo_channel_fini _nvkm_namedb_fini
+
+void _nvkm_fifo_channel_dtor(struct nvkm_object *);
+int  _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *);
+u32  _nvkm_fifo_channel_rd32(struct nvkm_object *, u64);
+void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32);
+int  _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+
+#include <core/gpuobj.h>
+
+struct nvkm_fifo_base {
+	struct nvkm_gpuobj gpuobj;
+};
+
+#define nvkm_fifo_context_create(p,e,c,g,s,a,f,d)                           \
+	nvkm_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
+#define nvkm_fifo_context_destroy(p)                                        \
+	nvkm_gpuobj_destroy(&(p)->gpuobj)
+#define nvkm_fifo_context_init(p)                                           \
+	nvkm_gpuobj_init(&(p)->gpuobj)
+#define nvkm_fifo_context_fini(p,s)                                         \
+	nvkm_gpuobj_fini(&(p)->gpuobj, (s))
+
+#define _nvkm_fifo_context_dtor _nvkm_gpuobj_dtor
+#define _nvkm_fifo_context_init _nvkm_gpuobj_init
+#define _nvkm_fifo_context_fini _nvkm_gpuobj_fini
+#define _nvkm_fifo_context_rd32 _nvkm_gpuobj_rd32
+#define _nvkm_fifo_context_wr32 _nvkm_gpuobj_wr32
+
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_fifo {
+	struct nvkm_engine base;
+
+	struct nvkm_event cevent; /* channel creation event */
+	struct nvkm_event uevent; /* async user trigger */
+
+	struct nvkm_object **channel;
+	spinlock_t lock;
+	u16 min;
+	u16 max;
+
+	int  (*chid)(struct nvkm_fifo *, struct nvkm_object *);
+	void (*pause)(struct nvkm_fifo *, unsigned long *);
+	void (*start)(struct nvkm_fifo *, unsigned long *);
+};
+
+static inline struct nvkm_fifo *
+nvkm_fifo(void *obj)
+{
+	return (void *)nvkm_engine(obj, NVDEV_ENGINE_FIFO);
+}
+
+#define nvkm_fifo_create(o,e,c,fc,lc,d)                                     \
+	nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
+#define nvkm_fifo_init(p)                                                   \
+	nvkm_engine_init(&(p)->base)
+#define nvkm_fifo_fini(p,s)                                                 \
+	nvkm_engine_fini(&(p)->base, (s))
+
+int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *,
+			 struct nvkm_oclass *, int min, int max,
+			 int size, void **);
+void nvkm_fifo_destroy(struct nvkm_fifo *);
+const char *
+nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid);
+
+#define _nvkm_fifo_init _nvkm_engine_init
+#define _nvkm_fifo_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass *nv04_fifo_oclass;
+extern struct nvkm_oclass *nv10_fifo_oclass;
+extern struct nvkm_oclass *nv17_fifo_oclass;
+extern struct nvkm_oclass *nv40_fifo_oclass;
+extern struct nvkm_oclass *nv50_fifo_oclass;
+extern struct nvkm_oclass *g84_fifo_oclass;
+extern struct nvkm_oclass *gf100_fifo_oclass;
+extern struct nvkm_oclass *gk104_fifo_oclass;
+extern struct nvkm_oclass *gk20a_fifo_oclass;
+extern struct nvkm_oclass *gk208_fifo_oclass;
+
+int  nvkm_fifo_uevent_ctor(struct nvkm_object *, void *, u32,
+			   struct nvkm_notify *);
+void nvkm_fifo_uevent(struct nvkm_fifo *);
+
+void nv04_fifo_intr(struct nvkm_subdev *);
+int  nv04_fifo_context_attach(struct nvkm_object *, struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
new file mode 100644
index 0000000..93ef1f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
@@ -0,0 +1,86 @@
+#ifndef __NVKM_GR_H__
+#define __NVKM_GR_H__
+#include <core/engctx.h>
+
+struct nvkm_gr_chan {
+	struct nvkm_engctx base;
+};
+
+#define nvkm_gr_context_create(p,e,c,g,s,a,f,d)                          \
+	nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_gr_context_destroy(d)                                       \
+	nvkm_engctx_destroy(&(d)->base)
+#define nvkm_gr_context_init(d)                                          \
+	nvkm_engctx_init(&(d)->base)
+#define nvkm_gr_context_fini(d,s)                                        \
+	nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_gr_context_dtor _nvkm_engctx_dtor
+#define _nvkm_gr_context_init _nvkm_engctx_init
+#define _nvkm_gr_context_fini _nvkm_engctx_fini
+#define _nvkm_gr_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_gr_context_wr32 _nvkm_engctx_wr32
+
+#include <core/engine.h>
+
+struct nvkm_gr {
+	struct nvkm_engine base;
+
+	/* Returns chipset-specific counts of units packed into an u64.
+	 */
+	u64 (*units)(struct nvkm_gr *);
+};
+
+static inline struct nvkm_gr *
+nvkm_gr(void *obj)
+{
+	return (void *)nvkm_engine(obj, NVDEV_ENGINE_GR);
+}
+
+#define nvkm_gr_create(p,e,c,y,d)                                        \
+	nvkm_engine_create((p), (e), (c), (y), "PGR", "graphics", (d))
+#define nvkm_gr_destroy(d)                                               \
+	nvkm_engine_destroy(&(d)->base)
+#define nvkm_gr_init(d)                                                  \
+	nvkm_engine_init(&(d)->base)
+#define nvkm_gr_fini(d,s)                                                \
+	nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_gr_dtor _nvkm_engine_dtor
+#define _nvkm_gr_init _nvkm_engine_init
+#define _nvkm_gr_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass nv04_gr_oclass;
+extern struct nvkm_oclass nv10_gr_oclass;
+extern struct nvkm_oclass nv20_gr_oclass;
+extern struct nvkm_oclass nv25_gr_oclass;
+extern struct nvkm_oclass nv2a_gr_oclass;
+extern struct nvkm_oclass nv30_gr_oclass;
+extern struct nvkm_oclass nv34_gr_oclass;
+extern struct nvkm_oclass nv35_gr_oclass;
+extern struct nvkm_oclass nv40_gr_oclass;
+extern struct nvkm_oclass nv50_gr_oclass;
+extern struct nvkm_oclass *gf100_gr_oclass;
+extern struct nvkm_oclass *gf108_gr_oclass;
+extern struct nvkm_oclass *gf104_gr_oclass;
+extern struct nvkm_oclass *gf110_gr_oclass;
+extern struct nvkm_oclass *gf117_gr_oclass;
+extern struct nvkm_oclass *gf119_gr_oclass;
+extern struct nvkm_oclass *gk104_gr_oclass;
+extern struct nvkm_oclass *gk20a_gr_oclass;
+extern struct nvkm_oclass *gk110_gr_oclass;
+extern struct nvkm_oclass *gk110b_gr_oclass;
+extern struct nvkm_oclass *gk208_gr_oclass;
+extern struct nvkm_oclass *gm107_gr_oclass;
+
+#include <core/enum.h>
+
+extern const struct nvkm_bitfield nv04_gr_nsource[];
+extern struct nvkm_ofuncs nv04_gr_ofuncs;
+bool nv04_gr_idle(void *obj);
+
+extern const struct nvkm_bitfield nv10_gr_intr_name[];
+extern const struct nvkm_bitfield nv10_gr_nstatus[];
+
+extern const struct nvkm_enum nv50_data_error_names[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h
new file mode 100644
index 0000000..4e500b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h
@@ -0,0 +1,62 @@
+#ifndef __NVKM_MPEG_H__
+#define __NVKM_MPEG_H__
+#include <core/engctx.h>
+
+struct nvkm_mpeg_chan {
+	struct nvkm_engctx base;
+};
+
+#define nvkm_mpeg_context_create(p,e,c,g,s,a,f,d)                           \
+	nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_mpeg_context_destroy(d)                                        \
+	nvkm_engctx_destroy(&(d)->base)
+#define nvkm_mpeg_context_init(d)                                           \
+	nvkm_engctx_init(&(d)->base)
+#define nvkm_mpeg_context_fini(d,s)                                         \
+	nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_mpeg_context_dtor _nvkm_engctx_dtor
+#define _nvkm_mpeg_context_init _nvkm_engctx_init
+#define _nvkm_mpeg_context_fini _nvkm_engctx_fini
+#define _nvkm_mpeg_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_mpeg_context_wr32 _nvkm_engctx_wr32
+
+#include <core/engine.h>
+
+struct nvkm_mpeg {
+	struct nvkm_engine base;
+};
+
+#define nvkm_mpeg_create(p,e,c,d)                                           \
+	nvkm_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
+#define nvkm_mpeg_destroy(d)                                                \
+	nvkm_engine_destroy(&(d)->base)
+#define nvkm_mpeg_init(d)                                                   \
+	nvkm_engine_init(&(d)->base)
+#define nvkm_mpeg_fini(d,s)                                                 \
+	nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_mpeg_dtor _nvkm_engine_dtor
+#define _nvkm_mpeg_init _nvkm_engine_init
+#define _nvkm_mpeg_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass nv31_mpeg_oclass;
+extern struct nvkm_oclass nv40_mpeg_oclass;
+extern struct nvkm_oclass nv44_mpeg_oclass;
+extern struct nvkm_oclass nv50_mpeg_oclass;
+extern struct nvkm_oclass g84_mpeg_oclass;
+extern struct nvkm_ofuncs nv31_mpeg_ofuncs;
+extern struct nvkm_oclass nv31_mpeg_cclass;
+extern struct nvkm_oclass nv31_mpeg_sclass[];
+extern struct nvkm_oclass nv40_mpeg_sclass[];
+void nv31_mpeg_intr(struct nvkm_subdev *);
+void nv31_mpeg_tile_prog(struct nvkm_engine *, int);
+int  nv31_mpeg_init(struct nvkm_object *);
+
+extern struct nvkm_ofuncs nv50_mpeg_ofuncs;
+int  nv50_mpeg_context_ctor(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, void *, u32,
+			    struct nvkm_object **);
+void nv50_mpeg_intr(struct nvkm_subdev *);
+int  nv50_mpeg_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h
new file mode 100644
index 0000000..54b7672e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_MSPDEC_H__
+#define __NVKM_MSPDEC_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_mspdec_oclass;
+extern struct nvkm_oclass gf100_mspdec_oclass;
+extern struct nvkm_oclass gk104_mspdec_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h
new file mode 100644
index 0000000..c6c69d0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h
@@ -0,0 +1,6 @@
+#ifndef __NVKM_MSPPP_H__
+#define __NVKM_MSPPP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_msppp_oclass;
+extern struct nvkm_oclass gf100_msppp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h
new file mode 100644
index 0000000..1f193b7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_MSVLD_H__
+#define __NVKM_MSVLD_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_msvld_oclass;
+extern struct nvkm_oclass gf100_msvld_oclass;
+extern struct nvkm_oclass gk104_msvld_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h
new file mode 100644
index 0000000..93181bb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_PM_H__
+#define __NVKM_PM_H__
+#include <core/engine.h>
+
+struct nvkm_perfdom;
+struct nvkm_perfctr;
+struct nvkm_pm {
+	struct nvkm_engine base;
+
+	struct nvkm_perfctx *context;
+	void *profile_data;
+
+	struct list_head domains;
+	u32 sequence;
+
+	/*XXX: temp for daemon backend */
+	u32 pwr[8];
+	u32 last;
+};
+
+static inline struct nvkm_pm *
+nvkm_pm(void *obj)
+{
+	return (void *)nvkm_engine(obj, NVDEV_ENGINE_PM);
+}
+
+extern struct nvkm_oclass *nv40_pm_oclass;
+extern struct nvkm_oclass *nv50_pm_oclass;
+extern struct nvkm_oclass *g84_pm_oclass;
+extern struct nvkm_oclass *gt215_pm_oclass;
+extern struct nvkm_oclass gf100_pm_oclass;
+extern struct nvkm_oclass gk104_pm_oclass;
+extern struct nvkm_oclass gk110_pm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h
new file mode 100644
index 0000000..44590a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_SEC_H__
+#define __NVKM_SEC_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_sec_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h
new file mode 100644
index 0000000..a529013
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h
@@ -0,0 +1,50 @@
+#ifndef __NVKM_SW_H__
+#define __NVKM_SW_H__
+#include <core/engctx.h>
+
+struct nvkm_sw_chan {
+	struct nvkm_engctx base;
+
+	int (*flip)(void *);
+	void *flip_data;
+};
+
+#define nvkm_sw_context_create(p,e,c,d)                               \
+	nvkm_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
+#define nvkm_sw_context_destroy(d)                                    \
+	nvkm_engctx_destroy(&(d)->base)
+#define nvkm_sw_context_init(d)                                       \
+	nvkm_engctx_init(&(d)->base)
+#define nvkm_sw_context_fini(d,s)                                     \
+	nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_sw_context_dtor _nvkm_engctx_dtor
+#define _nvkm_sw_context_init _nvkm_engctx_init
+#define _nvkm_sw_context_fini _nvkm_engctx_fini
+
+#include <core/engine.h>
+
+struct nvkm_sw {
+	struct nvkm_engine base;
+};
+
+#define nvkm_sw_create(p,e,c,d)                                       \
+	nvkm_engine_create((p), (e), (c), true, "SW", "software", (d))
+#define nvkm_sw_destroy(d)                                            \
+	nvkm_engine_destroy(&(d)->base)
+#define nvkm_sw_init(d)                                               \
+	nvkm_engine_init(&(d)->base)
+#define nvkm_sw_fini(d,s)                                             \
+	nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_sw_dtor _nvkm_engine_dtor
+#define _nvkm_sw_init _nvkm_engine_init
+#define _nvkm_sw_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass *nv04_sw_oclass;
+extern struct nvkm_oclass *nv10_sw_oclass;
+extern struct nvkm_oclass *nv50_sw_oclass;
+extern struct nvkm_oclass *gf100_sw_oclass;
+
+void nv04_sw_intr(struct nvkm_subdev *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h
new file mode 100644
index 0000000..7851f18
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_VP_H__
+#define __NVKM_VP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_vp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h
new file mode 100644
index 0000000..7a216cc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h
@@ -0,0 +1,35 @@
+#ifndef __NVKM_XTENSA_H__
+#define __NVKM_XTENSA_H__
+#include <core/engine.h>
+struct nvkm_gpuobj;
+
+struct nvkm_xtensa {
+	struct nvkm_engine base;
+
+	u32 addr;
+	struct nvkm_gpuobj *gpu_fw;
+	u32 fifo_val;
+	u32 unkd28;
+};
+
+#define nvkm_xtensa_create(p,e,c,b,d,i,f,r)				\
+	nvkm_xtensa_create_((p), (e), (c), (b), (d), (i), (f),	\
+			       sizeof(**r),(void **)r)
+
+int _nvkm_xtensa_engctx_ctor(struct nvkm_object *,
+				struct nvkm_object *,
+				struct nvkm_oclass *, void *, u32,
+				struct nvkm_object **);
+
+void _nvkm_xtensa_intr(struct nvkm_subdev *);
+int nvkm_xtensa_create_(struct nvkm_object *,
+			   struct nvkm_object *,
+			   struct nvkm_oclass *, u32, bool,
+			   const char *, const char *,
+			   int, void **);
+#define _nvkm_xtensa_dtor _nvkm_engine_dtor
+int _nvkm_xtensa_init(struct nvkm_object *);
+int _nvkm_xtensa_fini(struct nvkm_object *, bool);
+u32  _nvkm_xtensa_rd32(struct nvkm_object *, u64);
+void _nvkm_xtensa_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
new file mode 100644
index 0000000..c7a007b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
@@ -0,0 +1,33 @@
+#ifndef __NVKM_BAR_H__
+#define __NVKM_BAR_H__
+#include <core/subdev.h>
+struct nvkm_mem;
+struct nvkm_vma;
+
+struct nvkm_bar {
+	struct nvkm_subdev base;
+
+	int  (*alloc)(struct nvkm_bar *, struct nvkm_object *,
+		      struct nvkm_mem *, struct nvkm_object **);
+
+	int  (*kmap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags,
+		     struct nvkm_vma *);
+	int  (*umap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags,
+		     struct nvkm_vma *);
+	void (*unmap)(struct nvkm_bar *, struct nvkm_vma *);
+	void (*flush)(struct nvkm_bar *);
+
+	/* whether the BAR supports to be ioremapped WC or should be uncached */
+	bool iomap_uncached;
+};
+
+static inline struct nvkm_bar *
+nvkm_bar(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BAR);
+}
+
+extern struct nvkm_oclass nv50_bar_oclass;
+extern struct nvkm_oclass gf100_bar_oclass;
+extern struct nvkm_oclass gk20a_bar_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
new file mode 100644
index 0000000..cef287e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_BIOS_H__
+#define __NVKM_BIOS_H__
+#include <core/subdev.h>
+
+struct nvkm_bios {
+	struct nvkm_subdev base;
+	u32 size;
+	u8 *data;
+
+	u32 bmp_offset;
+	u32 bit_offset;
+
+	struct {
+		u8 major;
+		u8 chip;
+		u8 minor;
+		u8 micro;
+		u8 patch;
+	} version;
+};
+
+static inline struct nvkm_bios *
+nvkm_bios(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VBIOS);
+}
+
+u8  nvbios_checksum(const u8 *data, int size);
+u16 nvbios_findstr(const u8 *data, int size, const char *str, int len);
+
+extern struct nvkm_oclass nvkm_bios_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
new file mode 100644
index 0000000..cf202c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
@@ -0,0 +1,29 @@
+#ifndef __NVBIOS_M0203_H__
+#define __NVBIOS_M0203_H__
+struct nvbios_M0203T {
+#define M0203T_TYPE_RAMCFG 0x00
+	u8  type;
+	u16 pointer;
+};
+
+u32 nvbios_M0203Te(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0203Tp(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		   struct nvbios_M0203T *);
+
+struct nvbios_M0203E {
+#define M0203E_TYPE_DDR2  0x0
+#define M0203E_TYPE_DDR3  0x1
+#define M0203E_TYPE_GDDR3 0x2
+#define M0203E_TYPE_GDDR5 0x3
+#define M0203E_TYPE_SKIP  0xf
+	u8 type;
+	u8 strap;
+	u8 group;
+};
+
+u32 nvbios_M0203Ee(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0203Ep(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_M0203E *);
+u32 nvbios_M0203Em(struct nvkm_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
+		   struct nvbios_M0203E *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h
new file mode 100644
index 0000000..d34608f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h
@@ -0,0 +1,29 @@
+#ifndef __NVBIOS_M0205_H__
+#define __NVBIOS_M0205_H__
+struct nvbios_M0205T {
+	u16 freq;
+};
+
+u32 nvbios_M0205Te(struct nvkm_bios *,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u32 nvbios_M0205Tp(struct nvkm_bios *,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+		   struct nvbios_M0205T *);
+
+struct nvbios_M0205E {
+	u8 type;
+};
+
+u32 nvbios_M0205Ee(struct nvkm_bios *, int idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0205Ep(struct nvkm_bios *, int idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0205E *);
+
+struct nvbios_M0205S {
+	u8 data;
+};
+
+u32 nvbios_M0205Se(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0205Sp(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_M0205S *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h
new file mode 100644
index 0000000..c7ff8d9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h
@@ -0,0 +1,27 @@
+#ifndef __NVBIOS_M0209_H__
+#define __NVBIOS_M0209_H__
+u32 nvbios_M0209Te(struct nvkm_bios *,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_M0209E {
+	u8 v00_40;
+	u8 bits;
+	u8 modulo;
+	u8 v02_40;
+	u8 v02_07;
+	u8 v03;
+};
+
+u32 nvbios_M0209Ee(struct nvkm_bios *, int idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0209Ep(struct nvkm_bios *, int idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0209E *);
+
+struct nvbios_M0209S {
+	u32 data[0x200];
+};
+
+u32 nvbios_M0209Se(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0209Sp(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_M0209S *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h
new file mode 100644
index 0000000..1c1c52e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_P0260_H__
+#define __NVBIOS_P0260_H__
+u32 nvbios_P0260Te(struct nvkm_bios *,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_P0260E {
+	u32 data;
+};
+
+u32 nvbios_P0260Ee(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Ep(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_P0260E *);
+
+struct nvbios_P0260X {
+	u32 data;
+};
+
+u32 nvbios_P0260Xe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Xp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_P0260X *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h
new file mode 100644
index 0000000..6711732
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_BIT_H__
+#define __NVBIOS_BIT_H__
+struct bit_entry {
+	u8  id;
+	u8  version;
+	u16 length;
+	u16 offset;
+};
+
+int bit_entry(struct nvkm_bios *, u8 id, struct bit_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h
new file mode 100644
index 0000000..4107aa5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h
@@ -0,0 +1,37 @@
+#ifndef __NVBIOS_BMP_H__
+#define __NVBIOS_BMP_H__
+static inline u16
+bmp_version(struct nvkm_bios *bios)
+{
+	if (bios->bmp_offset) {
+		return nv_ro08(bios, bios->bmp_offset + 5) << 8 |
+		       nv_ro08(bios, bios->bmp_offset + 6);
+	}
+
+	return 0x0000;
+}
+
+static inline u16
+bmp_mem_init_table(struct nvkm_bios *bios)
+{
+	if (bmp_version(bios) >= 0x0300)
+		return nv_ro16(bios, bios->bmp_offset + 24);
+	return 0x0000;
+}
+
+static inline u16
+bmp_sdr_seq_table(struct nvkm_bios *bios)
+{
+	if (bmp_version(bios) >= 0x0300)
+		return nv_ro16(bios, bios->bmp_offset + 26);
+	return 0x0000;
+}
+
+static inline u16
+bmp_ddr_seq_table(struct nvkm_bios *bios)
+{
+	if (bmp_version(bios) >= 0x0300)
+		return nv_ro16(bios, bios->bmp_offset + 28);
+	return 0x0000;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h
new file mode 100644
index 0000000..934b0ae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h
@@ -0,0 +1,27 @@
+#ifndef __NVBIOS_BOOST_H__
+#define __NVBIOS_BOOST_H__
+u16 nvbios_boostTe(struct nvkm_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
+
+struct nvbios_boostE {
+	u8  pstate;
+	u32 min;
+	u32 max;
+};
+
+u16 nvbios_boostEe(struct nvkm_bios *, int idx, u8 *, u8 *, u8 *, u8 *);
+u16 nvbios_boostEp(struct nvkm_bios *, int idx, u8 *, u8 *, u8 *, u8 *,
+		   struct nvbios_boostE *);
+u16 nvbios_boostEm(struct nvkm_bios *, u8, u8 *, u8 *, u8 *, u8 *,
+		   struct nvbios_boostE *);
+
+struct nvbios_boostS {
+	u8  domain;
+	u8  percent;
+	u32 min;
+	u32 max;
+};
+
+u16 nvbios_boostSe(struct nvkm_bios *, int, u16, u8 *, u8 *, u8, u8);
+u16 nvbios_boostSp(struct nvkm_bios *, int, u16, u8 *, u8 *, u8, u8,
+		   struct nvbios_boostS *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
new file mode 100644
index 0000000..e8e77ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
@@ -0,0 +1,44 @@
+#ifndef __NVBIOS_CONN_H__
+#define __NVBIOS_CONN_H__
+enum dcb_connector_type {
+	DCB_CONNECTOR_VGA = 0x00,
+	DCB_CONNECTOR_TV_0 = 0x10,
+	DCB_CONNECTOR_TV_1 = 0x11,
+	DCB_CONNECTOR_TV_3 = 0x13,
+	DCB_CONNECTOR_DVI_I = 0x30,
+	DCB_CONNECTOR_DVI_D = 0x31,
+	DCB_CONNECTOR_DMS59_0 = 0x38,
+	DCB_CONNECTOR_DMS59_1 = 0x39,
+	DCB_CONNECTOR_LVDS = 0x40,
+	DCB_CONNECTOR_LVDS_SPWG = 0x41,
+	DCB_CONNECTOR_DP = 0x46,
+	DCB_CONNECTOR_eDP = 0x47,
+	DCB_CONNECTOR_HDMI_0 = 0x60,
+	DCB_CONNECTOR_HDMI_1 = 0x61,
+	DCB_CONNECTOR_HDMI_C = 0x63,
+	DCB_CONNECTOR_DMS59_DP0 = 0x64,
+	DCB_CONNECTOR_DMS59_DP1 = 0x65,
+	DCB_CONNECTOR_NONE = 0xff
+};
+
+struct nvbios_connT {
+};
+
+u32 nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_connTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		  struct nvbios_connT *info);
+
+struct nvbios_connE {
+	u8 type;
+	u8 location;
+	u8 hpd;
+	u8 dp;
+	u8 di;
+	u8 sr;
+	u8 lcdid;
+};
+
+u32 nvbios_connEe(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr);
+u32 nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr,
+		  struct nvbios_connE *info);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h
new file mode 100644
index 0000000..2f0e0c8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h
@@ -0,0 +1,26 @@
+#ifndef __NVBIOS_CSTEP_H__
+#define __NVBIOS_CSTEP_H__
+u16 nvbios_cstepTe(struct nvkm_bios *,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_cstepE {
+	u8  pstate;
+	u8  index;
+};
+
+u16 nvbios_cstepEe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepEp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_cstepE *);
+u16 nvbios_cstepEm(struct nvkm_bios *, u8 pstate, u8 *ver, u8 *hdr,
+		   struct nvbios_cstepE *);
+
+struct nvbios_cstepX {
+	u32 freq;
+	u8  unkn[2];
+	u8  voltage;
+};
+
+u16 nvbios_cstepXe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepXp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		   struct nvbios_cstepX *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h
new file mode 100644
index 0000000..4892a65
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h
@@ -0,0 +1,65 @@
+#ifndef __NVBIOS_DCB_H__
+#define __NVBIOS_DCB_H__
+enum dcb_output_type {
+	DCB_OUTPUT_ANALOG	= 0x0,
+	DCB_OUTPUT_TV		= 0x1,
+	DCB_OUTPUT_TMDS		= 0x2,
+	DCB_OUTPUT_LVDS		= 0x3,
+	DCB_OUTPUT_DP		= 0x6,
+	DCB_OUTPUT_EOL		= 0xe,
+	DCB_OUTPUT_UNUSED	= 0xf,
+	DCB_OUTPUT_ANY = -1,
+};
+
+struct dcb_output {
+	int index;	/* may not be raw dcb index if merging has happened */
+	u16 hasht;
+	u16 hashm;
+	enum dcb_output_type type;
+	uint8_t i2c_index;
+	uint8_t heads;
+	uint8_t connector;
+	uint8_t bus;
+	uint8_t location;
+	uint8_t or;
+	uint8_t link;
+	bool duallink_possible;
+	uint8_t extdev;
+	union {
+		struct sor_conf {
+			int link;
+		} sorconf;
+		struct {
+			int maxfreq;
+		} crtconf;
+		struct {
+			struct sor_conf sor;
+			bool use_straps_for_mode;
+			bool use_acpi_for_edid;
+			bool use_power_scripts;
+		} lvdsconf;
+		struct {
+			bool has_component_output;
+		} tvconf;
+		struct {
+			struct sor_conf sor;
+			int link_nr;
+			int link_bw;
+		} dpconf;
+		struct {
+			struct sor_conf sor;
+			int slave_addr;
+		} tmdsconf;
+	};
+	bool i2c_upper_default;
+};
+
+u16 dcb_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
+u16 dcb_outp(struct nvkm_bios *, u8 idx, u8 *ver, u8 *len);
+u16 dcb_outp_parse(struct nvkm_bios *, u8 idx, u8 *, u8 *,
+		   struct dcb_output *);
+u16 dcb_outp_match(struct nvkm_bios *, u16 type, u16 mask, u8 *, u8 *,
+		   struct dcb_output *);
+int dcb_outp_foreach(struct nvkm_bios *, void *data, int (*exec)
+		     (struct nvkm_bios *, void *, int index, u16 entry));
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
new file mode 100644
index 0000000..db10c11
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
@@ -0,0 +1,39 @@
+#ifndef __NVBIOS_DISP_H__
+#define __NVBIOS_DISP_H__
+u16 nvbios_disp_table(struct nvkm_bios *,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub);
+
+struct nvbios_disp {
+	u16 data;
+};
+
+u16 nvbios_disp_entry(struct nvkm_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *sub);
+u16 nvbios_disp_parse(struct nvkm_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *sub,
+		      struct nvbios_disp *);
+
+struct nvbios_outp {
+	u16 type;
+	u16 mask;
+	u16 script[3];
+};
+
+u16 nvbios_outp_entry(struct nvkm_bios *, u8 idx,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_outp_parse(struct nvkm_bios *, u8 idx,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *);
+u16 nvbios_outp_match(struct nvkm_bios *, u16 type, u16 mask,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *);
+
+struct nvbios_ocfg {
+	u16 match;
+	u16 clkcmp[2];
+};
+
+u16 nvbios_ocfg_entry(struct nvkm_bios *, u16 outp, u8 idx,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_ocfg_parse(struct nvkm_bios *, u16 outp, u8 idx,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
+u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u16 type,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
+u16 nvbios_oclk_match(struct nvkm_bios *, u16 cmp, u32 khz);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h
new file mode 100644
index 0000000..b4d39df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h
@@ -0,0 +1,31 @@
+#ifndef __NVBIOS_DP_H__
+#define __NVBIOS_DP_H__
+struct nvbios_dpout {
+	u16 type;
+	u16 mask;
+	u8  flags;
+	u32 script[5];
+	u32 lnkcmp;
+};
+
+u16 nvbios_dpout_parse(struct nvkm_bios *, u8 idx,
+		       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		       struct nvbios_dpout *);
+u16 nvbios_dpout_match(struct nvkm_bios *, u16 type, u16 mask,
+		       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		       struct nvbios_dpout *);
+
+struct nvbios_dpcfg {
+	u8 pc;
+	u8 dc;
+	u8 pe;
+	u8 tx_pu;
+};
+
+u16
+nvbios_dpcfg_parse(struct nvkm_bios *, u16 outp, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *);
+u16
+nvbios_dpcfg_match(struct nvkm_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h
new file mode 100644
index 0000000..6d3bedc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_EXTDEV_H__
+#define __NVBIOS_EXTDEV_H__
+enum nvbios_extdev_type {
+	NVBIOS_EXTDEV_LM89		= 0x02,
+	NVBIOS_EXTDEV_VT1103M		= 0x40,
+	NVBIOS_EXTDEV_PX3540		= 0x41,
+	NVBIOS_EXTDEV_VT1105M		= 0x42, /* or close enough... */
+	NVBIOS_EXTDEV_ADT7473		= 0x70, /* can also be a LM64 */
+	NVBIOS_EXTDEV_HDCP_EEPROM	= 0x90,
+	NVBIOS_EXTDEV_NONE		= 0xff,
+};
+
+struct nvbios_extdev_func {
+	u8 type;
+	u8 addr;
+	u8 bus;
+};
+
+int
+nvbios_extdev_parse(struct nvkm_bios *, int, struct nvbios_extdev_func *);
+
+int
+nvbios_extdev_find(struct nvkm_bios *, enum nvbios_extdev_type,
+		   struct nvbios_extdev_func *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h
new file mode 100644
index 0000000..693ea7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h
@@ -0,0 +1,6 @@
+#ifndef __NVBIOS_FAN_H__
+#define __NVBIOS_FAN_H__
+#include <subdev/bios/therm.h>
+
+u16 nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
new file mode 100644
index 0000000..33be260
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
@@ -0,0 +1,46 @@
+#ifndef __NVBIOS_GPIO_H__
+#define __NVBIOS_GPIO_H__
+enum dcb_gpio_func_name {
+	DCB_GPIO_PANEL_POWER = 0x01,
+	DCB_GPIO_TVDAC0 = 0x0c,
+	DCB_GPIO_TVDAC1 = 0x2d,
+	DCB_GPIO_FAN = 0x09,
+	DCB_GPIO_FAN_SENSE = 0x3d,
+	DCB_GPIO_UNUSED = 0xff,
+	DCB_GPIO_VID0 = 0x04,
+	DCB_GPIO_VID1 = 0x05,
+	DCB_GPIO_VID2 = 0x06,
+	DCB_GPIO_VID3 = 0x1a,
+	DCB_GPIO_VID4 = 0x73,
+	DCB_GPIO_VID5 = 0x74,
+	DCB_GPIO_VID6 = 0x75,
+	DCB_GPIO_VID7 = 0x76,
+};
+
+#define DCB_GPIO_LOG_DIR     0x02
+#define DCB_GPIO_LOG_DIR_OUT 0x00
+#define DCB_GPIO_LOG_DIR_IN  0x02
+#define DCB_GPIO_LOG_VAL     0x01
+#define DCB_GPIO_LOG_VAL_LO  0x00
+#define DCB_GPIO_LOG_VAL_HI  0x01
+
+struct dcb_gpio_func {
+	u8 func;
+	u8 line;
+	u8 log[2];
+
+	/* so far, "param" seems to only have an influence on PWM-related
+	 * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL.
+	 * if param equals 1, hardware PWM is available
+	 * if param equals 0, the host should toggle the GPIO itself
+	 */
+	u8 param;
+};
+
+u16 dcb_gpio_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_gpio_entry(struct nvkm_bios *, int idx, int ent, u8 *ver, u8 *len);
+u16 dcb_gpio_parse(struct nvkm_bios *, int idx, int ent, u8 *ver, u8 *len,
+		   struct dcb_gpio_func *);
+u16 dcb_gpio_match(struct nvkm_bios *, int idx, u8 func, u8 line,
+		   u8 *ver, u8 *len, struct dcb_gpio_func *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h
new file mode 100644
index 0000000..85c529e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_I2C_H__
+#define __NVBIOS_I2C_H__
+enum dcb_i2c_type {
+	/* matches bios type field prior to ccb 4.1 */
+	DCB_I2C_NV04_BIT = 0x00,
+	DCB_I2C_NV4E_BIT = 0x04,
+	DCB_I2C_NVIO_BIT = 0x05,
+	DCB_I2C_NVIO_AUX = 0x06,
+	/* made up - mostly */
+	DCB_I2C_PMGR     = 0x80,
+	DCB_I2C_UNUSED   = 0xff
+};
+
+struct dcb_i2c_entry {
+	enum dcb_i2c_type type;
+	u8 drive;
+	u8 sense;
+	u8 share;
+	u8 auxch;
+};
+
+u16 dcb_i2c_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_i2c_entry(struct nvkm_bios *, u8 index, u8 *ver, u8 *len);
+int dcb_i2c_parse(struct nvkm_bios *, u8 index, struct dcb_i2c_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h
new file mode 100644
index 0000000..e15d63b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_IMAGE_H__
+#define __NVBIOS_IMAGE_H__
+struct nvbios_image {
+	u32  base;
+	u32  size;
+	u8   type;
+	bool last;
+};
+
+bool nvbios_image(struct nvkm_bios *, int, struct nvbios_image *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
new file mode 100644
index 0000000..578a667
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
@@ -0,0 +1,20 @@
+#ifndef __NVBIOS_INIT_H__
+#define __NVBIOS_INIT_H__
+struct nvbios_init {
+	struct nvkm_subdev *subdev;
+	struct nvkm_bios *bios;
+	u16 offset;
+	struct dcb_output *outp;
+	int crtc;
+
+	/* internal state used during parsing */
+	u8 execute;
+	u32 nested;
+	u16 repeat;
+	u16 repend;
+	u32 ramcfg;
+};
+
+int nvbios_exec(struct nvbios_init *);
+int nvbios_init(struct nvkm_subdev *, bool execute);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h
new file mode 100644
index 0000000..4e31b64
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h
@@ -0,0 +1,6 @@
+#ifndef __NVBIOS_MXM_H__
+#define __NVBIOS_MXM_H__
+u16 mxm_table(struct nvkm_bios *, u8 *ver, u8 *hdr);
+u8  mxm_sor_map(struct nvkm_bios *, u8 conn);
+u8  mxm_ddc_map(struct nvkm_bios *, u8 port);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h
new file mode 100644
index 0000000..64a5954
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h
@@ -0,0 +1,10 @@
+#ifndef __NVBIOS_NPDE_H__
+#define __NVBIOS_NPDE_H__
+struct nvbios_npdeT {
+	u32 image_size;
+	bool last;
+};
+
+u32 nvbios_npdeTe(struct nvkm_bios *, u32);
+u32 nvbios_npdeTp(struct nvkm_bios *, u32, struct nvbios_npdeT *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h
new file mode 100644
index 0000000..e859315
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h
@@ -0,0 +1,16 @@
+#ifndef __NVBIOS_PCIR_H__
+#define __NVBIOS_PCIR_H__
+struct nvbios_pcirT {
+	u16 vendor_id;
+	u16 device_id;
+	u8  class_code[3];
+	u32 image_size;
+	u16 image_rev;
+	u8  image_type;
+	bool last;
+};
+
+u32 nvbios_pcirTe(struct nvkm_bios *, u32, u8 *ver, u16 *hdr);
+u32 nvbios_pcirTp(struct nvkm_bios *, u32, u8 *ver, u16 *hdr,
+		  struct nvbios_pcirT *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
new file mode 100644
index 0000000..7cc2bec
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
@@ -0,0 +1,41 @@
+#ifndef __NVBIOS_PERF_H__
+#define __NVBIOS_PERF_H__
+u16 nvbios_perf_table(struct nvkm_bios *, u8 *ver, u8 *hdr,
+		      u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_perfE {
+	u8  pstate;
+	u8  fanspeed;
+	u8  voltage;
+	u32 core;
+	u32 shader;
+	u32 memory;
+	u32 vdec;
+	u32 disp;
+	u32 script;
+};
+
+u16 nvbios_perf_entry(struct nvkm_bios *, int idx,
+		      u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_perfEp(struct nvkm_bios *, int idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *);
+
+struct nvbios_perfS {
+	union {
+		struct {
+			u32 freq;
+		} v40;
+	};
+};
+
+u32 nvbios_perfSe(struct nvkm_bios *, u32 data, int idx,
+		  u8 *ver, u8 *hdr, u8 cnt, u8 len);
+u32 nvbios_perfSp(struct nvkm_bios *, u32 data, int idx,
+		  u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *);
+
+struct nvbios_perf_fan {
+	u32 pwm_divisor;
+};
+
+int nvbios_perf_fan_parse(struct nvkm_bios *, struct nvbios_perf_fan *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h
new file mode 100644
index 0000000..5a69978
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h
@@ -0,0 +1,75 @@
+#ifndef __NVBIOS_PLL_H__
+#define __NVBIOS_PLL_H__
+/*XXX: kill me */
+struct nvkm_pll_vals {
+	union {
+		struct {
+#ifdef __BIG_ENDIAN
+			uint8_t N1, M1, N2, M2;
+#else
+			uint8_t M1, N1, M2, N2;
+#endif
+		};
+		struct {
+			uint16_t NM1, NM2;
+		} __attribute__((packed));
+	};
+	int log2P;
+
+	int refclk;
+};
+
+/* these match types in pll limits table version 0x40,
+ * nvkm uses them on all chipsets internally where a
+ * specific pll needs to be referenced, but the exact
+ * register isn't known.
+ */
+enum nvbios_pll_type {
+	PLL_CORE   = 0x01,
+	PLL_SHADER = 0x02,
+	PLL_UNK03  = 0x03,
+	PLL_MEMORY = 0x04,
+	PLL_VDEC   = 0x05,
+	PLL_UNK40  = 0x40,
+	PLL_UNK41  = 0x41,
+	PLL_UNK42  = 0x42,
+	PLL_VPLL0  = 0x80,
+	PLL_VPLL1  = 0x81,
+	PLL_VPLL2  = 0x82,
+	PLL_VPLL3  = 0x83,
+	PLL_MAX    = 0xff
+};
+
+struct nvbios_pll {
+	enum nvbios_pll_type type;
+	u32 reg;
+	u32 refclk;
+
+	u8 min_p;
+	u8 max_p;
+	u8 bias_p;
+
+	/*
+	 * for most pre nv50 cards setting a log2P of 7 (the common max_log2p
+	 * value) is no different to 6 (at least for vplls) so allowing the MNP
+	 * calc to use 7 causes the generated clock to be out by a factor of 2.
+	 * however, max_log2p cannot be fixed-up during parsing as the
+	 * unmodified max_log2p value is still needed for setting mplls, hence
+	 * an additional max_usable_log2p member
+	 */
+	u8 max_p_usable;
+
+	struct {
+		u32 min_freq;
+		u32 max_freq;
+		u32 min_inputfreq;
+		u32 max_inputfreq;
+		u8  min_m;
+		u8  max_m;
+		u8  min_n;
+		u8  max_n;
+	} vco1, vco2;
+};
+
+int nvbios_pll_parse(struct nvkm_bios *, u32 type, struct nvbios_pll *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h
new file mode 100644
index 0000000..d606875
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h
@@ -0,0 +1,35 @@
+#ifndef __NVBIOS_PMU_H__
+#define __NVBIOS_PMU_H__
+struct nvbios_pmuT {
+};
+
+u32 nvbios_pmuTe(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_pmuTp(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		 struct nvbios_pmuT *);
+
+struct nvbios_pmuE {
+	u8  type;
+	u32 data;
+};
+
+u32 nvbios_pmuEe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_pmuEp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+		 struct nvbios_pmuE *);
+
+struct nvbios_pmuR {
+	u32 boot_addr_pmu;
+	u32 boot_addr;
+	u32 boot_size;
+	u32 code_addr_pmu;
+	u32 code_addr;
+	u32 code_size;
+	u32 init_addr_pmu;
+
+	u32 data_addr_pmu;
+	u32 data_addr;
+	u32 data_size;
+	u32 args_addr_pmu;
+};
+
+bool nvbios_pmuRm(struct nvkm_bios *, u8 type, struct nvbios_pmuR *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h
new file mode 100644
index 0000000..4204267
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h
@@ -0,0 +1,141 @@
+#ifndef __NVBIOS_RAMCFG_H__
+#define __NVBIOS_RAMCFG_H__
+struct nvbios_ramcfg {
+	unsigned rammap_ver;
+	unsigned rammap_hdr;
+	unsigned rammap_min;
+	unsigned rammap_max;
+	union {
+		struct {
+			unsigned rammap_10_04_02:1;
+			unsigned rammap_10_04_08:1;
+		};
+		struct {
+			unsigned rammap_11_08_01:1;
+			unsigned rammap_11_08_0c:2;
+			unsigned rammap_11_08_10:1;
+			unsigned rammap_11_09_01ff:9;
+			unsigned rammap_11_0a_03fe:9;
+			unsigned rammap_11_0a_0400:1;
+			unsigned rammap_11_0a_0800:1;
+			unsigned rammap_11_0b_01f0:5;
+			unsigned rammap_11_0b_0200:1;
+			unsigned rammap_11_0b_0400:1;
+			unsigned rammap_11_0b_0800:1;
+			unsigned rammap_11_0d:8;
+			unsigned rammap_11_0e:8;
+			unsigned rammap_11_0f:8;
+			unsigned rammap_11_11_0c:2;
+		};
+	};
+
+	unsigned ramcfg_ver;
+	unsigned ramcfg_hdr;
+	unsigned ramcfg_timing;
+	union {
+		struct {
+			unsigned ramcfg_10_02_01:1;
+			unsigned ramcfg_10_02_02:1;
+			unsigned ramcfg_10_02_04:1;
+			unsigned ramcfg_10_02_08:1;
+			unsigned ramcfg_10_02_10:1;
+			unsigned ramcfg_10_02_20:1;
+			unsigned ramcfg_10_DLLoff:1;
+			unsigned ramcfg_10_03_0f:4;
+			unsigned ramcfg_10_04_01:1;
+			unsigned ramcfg_10_05:8;
+			unsigned ramcfg_10_06:8;
+			unsigned ramcfg_10_07:8;
+			unsigned ramcfg_10_08:8;
+			unsigned ramcfg_10_09_0f:4;
+			unsigned ramcfg_10_09_f0:4;
+		};
+		struct {
+			unsigned ramcfg_11_01_01:1;
+			unsigned ramcfg_11_01_02:1;
+			unsigned ramcfg_11_01_04:1;
+			unsigned ramcfg_11_01_08:1;
+			unsigned ramcfg_11_01_10:1;
+			unsigned ramcfg_11_01_20:1;
+			unsigned ramcfg_11_01_40:1;
+			unsigned ramcfg_11_01_80:1;
+			unsigned ramcfg_11_02_03:2;
+			unsigned ramcfg_11_02_04:1;
+			unsigned ramcfg_11_02_08:1;
+			unsigned ramcfg_11_02_10:1;
+			unsigned ramcfg_11_02_40:1;
+			unsigned ramcfg_11_02_80:1;
+			unsigned ramcfg_11_03_0f:4;
+			unsigned ramcfg_11_03_30:2;
+			unsigned ramcfg_11_03_c0:2;
+			unsigned ramcfg_11_03_f0:4;
+			unsigned ramcfg_11_04:8;
+			unsigned ramcfg_11_06:8;
+			unsigned ramcfg_11_07_02:1;
+			unsigned ramcfg_11_07_04:1;
+			unsigned ramcfg_11_07_08:1;
+			unsigned ramcfg_11_07_10:1;
+			unsigned ramcfg_11_07_40:1;
+			unsigned ramcfg_11_07_80:1;
+			unsigned ramcfg_11_08_01:1;
+			unsigned ramcfg_11_08_02:1;
+			unsigned ramcfg_11_08_04:1;
+			unsigned ramcfg_11_08_08:1;
+			unsigned ramcfg_11_08_10:1;
+			unsigned ramcfg_11_08_20:1;
+			unsigned ramcfg_11_09:8;
+		};
+	};
+
+	unsigned timing_ver;
+	unsigned timing_hdr;
+	unsigned timing[11];
+	union {
+		struct {
+			unsigned timing_10_WR:8;
+			unsigned timing_10_WTR:8;
+			unsigned timing_10_CL:8;
+			unsigned timing_10_RC:8;
+			/*empty: 4 */
+			unsigned timing_10_RFC:8;        /* Byte 5 */
+			/*empty: 6 */
+			unsigned timing_10_RAS:8;        /* Byte 7 */
+			/*empty: 8 */
+			unsigned timing_10_RP:8;         /* Byte 9 */
+			unsigned timing_10_RCDRD:8;
+			unsigned timing_10_RCDWR:8;
+			unsigned timing_10_RRD:8;
+			unsigned timing_10_13:8;
+			unsigned timing_10_ODT:3;
+			/* empty: 15 */
+			unsigned timing_10_16:8;
+			/* empty: 17 */
+			unsigned timing_10_18:8;
+			unsigned timing_10_CWL:8;
+			unsigned timing_10_20:8;
+			unsigned timing_10_21:8;
+			/* empty: 22, 23 */
+			unsigned timing_10_24:8;
+		};
+		struct {
+			unsigned timing_20_2e_03:2;
+			unsigned timing_20_2e_30:2;
+			unsigned timing_20_2e_c0:2;
+			unsigned timing_20_2f_03:2;
+			unsigned timing_20_2c_003f:6;
+			unsigned timing_20_2c_1fc0:7;
+			unsigned timing_20_30_f8:5;
+			unsigned timing_20_30_07:3;
+			unsigned timing_20_31_0007:3;
+			unsigned timing_20_31_0078:4;
+			unsigned timing_20_31_0780:4;
+			unsigned timing_20_31_0800:1;
+			unsigned timing_20_31_7000:3;
+			unsigned timing_20_31_8000:1;
+		};
+	};
+};
+
+u8 nvbios_ramcfg_count(struct nvkm_bios *);
+u8 nvbios_ramcfg_index(struct nvkm_subdev *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h
new file mode 100644
index 0000000..609a905
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_RAMMAP_H__
+#define __NVBIOS_RAMMAP_H__
+#include <subdev/bios/ramcfg.h>
+
+u32 nvbios_rammapTe(struct nvkm_bios *, u8 *ver, u8 *hdr,
+		    u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+u32 nvbios_rammapEe(struct nvkm_bios *, int idx,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_rammapEp(struct nvkm_bios *, int idx,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+u32 nvbios_rammapEm(struct nvkm_bios *, u16 mhz,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+
+u32 nvbios_rammapSe(struct nvkm_bios *, u32 data,
+		    u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+		    u8 *ver, u8 *hdr);
+u32 nvbios_rammapSp(struct nvkm_bios *, u32 data,
+		    u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+		    u8 *ver, u8 *hdr, struct nvbios_ramcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h
new file mode 100644
index 0000000..dd3ba96
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h
@@ -0,0 +1,72 @@
+#ifndef __NVBIOS_THERM_H__
+#define __NVBIOS_THERM_H__
+struct nvbios_therm_threshold {
+	u8 temp;
+	u8 hysteresis;
+};
+
+struct nvbios_therm_sensor {
+	/* diode */
+	s16 slope_mult;
+	s16 slope_div;
+	s16 offset_num;
+	s16 offset_den;
+	s8 offset_constant;
+
+	/* thresholds */
+	struct nvbios_therm_threshold thrs_fan_boost;
+	struct nvbios_therm_threshold thrs_down_clock;
+	struct nvbios_therm_threshold thrs_critical;
+	struct nvbios_therm_threshold thrs_shutdown;
+};
+
+enum nvbios_therm_fan_type {
+	NVBIOS_THERM_FAN_UNK = 0,
+	NVBIOS_THERM_FAN_TOGGLE = 1,
+	NVBIOS_THERM_FAN_PWM = 2,
+};
+
+/* no vbios have more than 6 */
+#define NVKM_TEMP_FAN_TRIP_MAX 10
+struct nvbios_therm_trip_point {
+	int fan_duty;
+	int temp;
+	int hysteresis;
+};
+
+enum nvbios_therm_fan_mode {
+	NVBIOS_THERM_FAN_TRIP = 0,
+	NVBIOS_THERM_FAN_LINEAR = 1,
+	NVBIOS_THERM_FAN_OTHER = 2,
+};
+
+struct nvbios_therm_fan {
+	enum nvbios_therm_fan_type type;
+
+	u32 pwm_freq;
+
+	u8 min_duty;
+	u8 max_duty;
+
+	u16 bump_period;
+	u16 slow_down_period;
+
+	enum nvbios_therm_fan_mode fan_mode;
+	struct nvbios_therm_trip_point trip[NVKM_TEMP_FAN_TRIP_MAX];
+	u8 nr_fan_trip;
+	u8 linear_min_temp;
+	u8 linear_max_temp;
+};
+
+enum nvbios_therm_domain {
+	NVBIOS_THERM_DOMAIN_CORE,
+	NVBIOS_THERM_DOMAIN_AMBIENT,
+};
+
+int
+nvbios_therm_sensor_parse(struct nvkm_bios *, enum nvbios_therm_domain,
+			  struct nvbios_therm_sensor *);
+
+int
+nvbios_therm_fan_parse(struct nvkm_bios *, struct nvbios_therm_fan *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h
new file mode 100644
index 0000000..339a826
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_TIMING_H__
+#define __NVBIOS_TIMING_H__
+#include <subdev/bios/ramcfg.h>
+
+u16 nvbios_timingTe(struct nvkm_bios *,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u16 nvbios_timingEe(struct nvkm_bios *, int idx,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_timingEp(struct nvkm_bios *, int idx,
+		    u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
new file mode 100644
index 0000000..6633c6d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_VMAP_H__
+#define __NVBIOS_VMAP_H__
+struct nvbios_vmap {
+};
+
+u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_vmap_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		      struct nvbios_vmap *);
+
+struct nvbios_vmap_entry {
+	u8  unk0;
+	u8  link;
+	u32 min;
+	u32 max;
+	s32 arg[6];
+};
+
+u16 nvbios_vmap_entry(struct nvkm_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_vmap_entry_parse(struct nvkm_bios *, int idx, u8 *ver, u8 *len,
+			    struct nvbios_vmap_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
new file mode 100644
index 0000000..eb2de4b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
@@ -0,0 +1,23 @@
+#ifndef __NVBIOS_VOLT_H__
+#define __NVBIOS_VOLT_H__
+struct nvbios_volt {
+	u8  vidmask;
+	u32 min;
+	u32 max;
+	u32 base;
+	s16 step;
+};
+
+u16 nvbios_volt_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_volt_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		      struct nvbios_volt *);
+
+struct nvbios_volt_entry {
+	u32 voltage;
+	u8  vid;
+};
+
+u16 nvbios_volt_entry(struct nvkm_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_volt_entry_parse(struct nvkm_bios *, int idx, u8 *ver, u8 *len,
+			    struct nvbios_volt_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h
new file mode 100644
index 0000000..0c0fe23
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h
@@ -0,0 +1,18 @@
+#ifndef __NVBIOS_XPIO_H__
+#define __NVBIOS_XPIO_H__
+
+#define NVBIOS_XPIO_FLAG_AUX  0x10
+#define NVBIOS_XPIO_FLAG_AUX0 0x00
+#define NVBIOS_XPIO_FLAG_AUX1 0x10
+
+struct nvbios_xpio {
+	u8 type;
+	u8 addr;
+	u8 flags;
+};
+
+u16 dcb_xpio_table(struct nvkm_bios *, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_xpio_parse(struct nvkm_bios *, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
new file mode 100644
index 0000000..fba83c0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
@@ -0,0 +1,50 @@
+#ifndef __NVKM_BUS_H__
+#define __NVKM_BUS_H__
+#include <core/subdev.h>
+
+struct nvkm_bus_intr {
+	u32 stat;
+	u32 unit;
+};
+
+struct nvkm_bus {
+	struct nvkm_subdev base;
+	int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32);
+	u32 hwsq_size;
+};
+
+static inline struct nvkm_bus *
+nvkm_bus(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BUS);
+}
+
+#define nvkm_bus_create(p, e, o, d)                                         \
+	nvkm_subdev_create_((p), (e), (o), 0, "PBUS", "master",             \
+			       sizeof(**d), (void **)d)
+#define nvkm_bus_destroy(p)                                                 \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_bus_init(p)                                                    \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_bus_fini(p, s)                                                 \
+	nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_bus_dtor _nvkm_subdev_dtor
+#define _nvkm_bus_init _nvkm_subdev_init
+#define _nvkm_bus_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass *nv04_bus_oclass;
+extern struct nvkm_oclass *nv31_bus_oclass;
+extern struct nvkm_oclass *nv50_bus_oclass;
+extern struct nvkm_oclass *g94_bus_oclass;
+extern struct nvkm_oclass *gf100_bus_oclass;
+
+/* interface to sequencer */
+struct nvkm_hwsq;
+int  nvkm_hwsq_init(struct nvkm_bus *, struct nvkm_hwsq **);
+int  nvkm_hwsq_fini(struct nvkm_hwsq **, bool exec);
+void nvkm_hwsq_wr32(struct nvkm_hwsq *, u32 addr, u32 data);
+void nvkm_hwsq_setf(struct nvkm_hwsq *, u8 flag, int data);
+void nvkm_hwsq_wait(struct nvkm_hwsq *, u8 flag, u8 data);
+void nvkm_hwsq_nsec(struct nvkm_hwsq *, u32 nsec);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
new file mode 100644
index 0000000..f5d30385
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
@@ -0,0 +1,161 @@
+#ifndef __NVKM_CLK_H__
+#define __NVKM_CLK_H__
+#include <core/subdev.h>
+#include <core/notify.h>
+struct nvbios_pll;
+struct nvkm_pll_vals;
+
+enum nv_clk_src {
+	nv_clk_src_crystal,
+	nv_clk_src_href,
+
+	nv_clk_src_hclk,
+	nv_clk_src_hclkm3,
+	nv_clk_src_hclkm3d2,
+	nv_clk_src_hclkm2d3, /* NVAA */
+	nv_clk_src_hclkm4, /* NVAA */
+	nv_clk_src_cclk, /* NVAA */
+
+	nv_clk_src_host,
+
+	nv_clk_src_sppll0,
+	nv_clk_src_sppll1,
+
+	nv_clk_src_mpllsrcref,
+	nv_clk_src_mpllsrc,
+	nv_clk_src_mpll,
+	nv_clk_src_mdiv,
+
+	nv_clk_src_core,
+	nv_clk_src_core_intm,
+	nv_clk_src_shader,
+
+	nv_clk_src_mem,
+
+	nv_clk_src_gpc,
+	nv_clk_src_rop,
+	nv_clk_src_hubk01,
+	nv_clk_src_hubk06,
+	nv_clk_src_hubk07,
+	nv_clk_src_copy,
+	nv_clk_src_daemon,
+	nv_clk_src_disp,
+	nv_clk_src_vdec,
+
+	nv_clk_src_dom6,
+
+	nv_clk_src_max,
+};
+
+struct nvkm_cstate {
+	struct list_head head;
+	u8  voltage;
+	u32 domain[nv_clk_src_max];
+};
+
+struct nvkm_pstate {
+	struct list_head head;
+	struct list_head list; /* c-states */
+	struct nvkm_cstate base;
+	u8 pstate;
+	u8 fanspeed;
+};
+
+struct nvkm_domain {
+	enum nv_clk_src name;
+	u8 bios; /* 0xff for none */
+#define NVKM_CLK_DOM_FLAG_CORE 0x01
+	u8 flags;
+	const char *mname;
+	int mdiv;
+};
+
+struct nvkm_clk {
+	struct nvkm_subdev base;
+
+	struct nvkm_domain *domains;
+	struct nvkm_pstate bstate;
+
+	struct list_head states;
+	int state_nr;
+
+	struct work_struct work;
+	wait_queue_head_t wait;
+	atomic_t waiting;
+
+	struct nvkm_notify pwrsrc_ntfy;
+	int pwrsrc;
+	int pstate; /* current */
+	int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
+	int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
+	int astate; /* perfmon adjustment (base) */
+	int tstate; /* thermal adjustment (max-) */
+	int dstate; /* display adjustment (min+) */
+
+	bool allow_reclock;
+
+	int  (*read)(struct nvkm_clk *, enum nv_clk_src);
+	int  (*calc)(struct nvkm_clk *, struct nvkm_cstate *);
+	int  (*prog)(struct nvkm_clk *);
+	void (*tidy)(struct nvkm_clk *);
+
+	/*XXX: die, these are here *only* to support the completely
+	 *     bat-shit insane what-was-nvkm_hw.c code
+	 */
+	int (*pll_calc)(struct nvkm_clk *, struct nvbios_pll *, int clk,
+			struct nvkm_pll_vals *pv);
+	int (*pll_prog)(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *pv);
+};
+
+static inline struct nvkm_clk *
+nvkm_clk(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_CLK);
+}
+
+#define nvkm_clk_create(p,e,o,i,r,s,n,d)                                  \
+	nvkm_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d),  \
+			      (void **)d)
+#define nvkm_clk_destroy(p) ({                                            \
+	struct nvkm_clk *clk = (p);                                       \
+	_nvkm_clk_dtor(nv_object(clk));                                   \
+})
+#define nvkm_clk_init(p) ({                                               \
+	struct nvkm_clk *clk = (p);                                       \
+	_nvkm_clk_init(nv_object(clk));                                   \
+})
+#define nvkm_clk_fini(p,s) ({                                             \
+	struct nvkm_clk *clk = (p);                                       \
+	_nvkm_clk_fini(nv_object(clk), (s));                              \
+})
+
+int  nvkm_clk_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *,
+			   struct nvkm_domain *, struct nvkm_pstate *,
+			   int, bool, int, void **);
+void _nvkm_clk_dtor(struct nvkm_object *);
+int  _nvkm_clk_init(struct nvkm_object *);
+int  _nvkm_clk_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass nv04_clk_oclass;
+extern struct nvkm_oclass nv40_clk_oclass;
+extern struct nvkm_oclass *nv50_clk_oclass;
+extern struct nvkm_oclass *g84_clk_oclass;
+extern struct nvkm_oclass *mcp77_clk_oclass;
+extern struct nvkm_oclass gt215_clk_oclass;
+extern struct nvkm_oclass gf100_clk_oclass;
+extern struct nvkm_oclass gk104_clk_oclass;
+extern struct nvkm_oclass gk20a_clk_oclass;
+
+int nv04_clk_pll_set(struct nvkm_clk *, u32 type, u32 freq);
+int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk,
+		      struct nvkm_pll_vals *);
+int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *);
+int gt215_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *,
+		       int clk, struct nvkm_pll_vals *);
+
+int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr);
+int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait);
+int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel);
+int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
new file mode 100644
index 0000000..d1bbe0d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_DEVINIT_H__
+#define __NVKM_DEVINIT_H__
+#include <core/subdev.h>
+
+struct nvkm_devinit {
+	struct nvkm_subdev base;
+	bool post;
+	void (*meminit)(struct nvkm_devinit *);
+	int  (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq);
+	u32  (*mmio)(struct nvkm_devinit *, u32 addr);
+};
+
+static inline struct nvkm_devinit *
+nvkm_devinit(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_DEVINIT);
+}
+
+extern struct nvkm_oclass *nv04_devinit_oclass;
+extern struct nvkm_oclass *nv05_devinit_oclass;
+extern struct nvkm_oclass *nv10_devinit_oclass;
+extern struct nvkm_oclass *nv1a_devinit_oclass;
+extern struct nvkm_oclass *nv20_devinit_oclass;
+extern struct nvkm_oclass *nv50_devinit_oclass;
+extern struct nvkm_oclass *g84_devinit_oclass;
+extern struct nvkm_oclass *g98_devinit_oclass;
+extern struct nvkm_oclass *gt215_devinit_oclass;
+extern struct nvkm_oclass *mcp89_devinit_oclass;
+extern struct nvkm_oclass *gf100_devinit_oclass;
+extern struct nvkm_oclass *gm107_devinit_oclass;
+extern struct nvkm_oclass *gm204_devinit_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
new file mode 100644
index 0000000..16da56c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
@@ -0,0 +1,154 @@
+#ifndef __NVKM_FB_H__
+#define __NVKM_FB_H__
+#include <core/subdev.h>
+
+#include <subdev/mmu.h>
+
+/* memory type/access flags, do not match hardware values */
+#define NV_MEM_ACCESS_RO  1
+#define NV_MEM_ACCESS_WO  2
+#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
+#define NV_MEM_ACCESS_SYS 4
+#define NV_MEM_ACCESS_VM  8
+#define NV_MEM_ACCESS_NOSNOOP 16
+
+#define NV_MEM_TARGET_VRAM        0
+#define NV_MEM_TARGET_PCI         1
+#define NV_MEM_TARGET_PCI_NOSNOOP 2
+#define NV_MEM_TARGET_VM          3
+#define NV_MEM_TARGET_GART        4
+
+#define NV_MEM_TYPE_VM 0x7f
+#define NV_MEM_COMP_VM 0x03
+
+struct nvkm_mem {
+	struct drm_device *dev;
+
+	struct nvkm_vma bar_vma;
+	struct nvkm_vma vma[2];
+	u8  page_shift;
+
+	struct nvkm_mm_node *tag;
+	struct list_head regions;
+	dma_addr_t *pages;
+	u32 memtype;
+	u64 offset;
+	u64 size;
+	struct sg_table *sg;
+};
+
+struct nvkm_fb_tile {
+	struct nvkm_mm_node *tag;
+	u32 addr;
+	u32 limit;
+	u32 pitch;
+	u32 zcomp;
+};
+
+struct nvkm_fb {
+	struct nvkm_subdev base;
+
+	bool (*memtype_valid)(struct nvkm_fb *, u32 memtype);
+
+	struct nvkm_ram *ram;
+
+	struct nvkm_mm vram;
+	struct nvkm_mm tags;
+
+	struct {
+		struct nvkm_fb_tile region[16];
+		int regions;
+		void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size,
+			     u32 pitch, u32 flags, struct nvkm_fb_tile *);
+		void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags,
+			     struct nvkm_fb_tile *);
+		void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+		void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+	} tile;
+};
+
+static inline struct nvkm_fb *
+nvkm_fb(void *obj)
+{
+	/* fbram uses this before device subdev pointer is valid */
+	if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
+	    nv_subidx(obj) == NVDEV_SUBDEV_FB)
+		return obj;
+
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FB);
+}
+
+extern struct nvkm_oclass *nv04_fb_oclass;
+extern struct nvkm_oclass *nv10_fb_oclass;
+extern struct nvkm_oclass *nv1a_fb_oclass;
+extern struct nvkm_oclass *nv20_fb_oclass;
+extern struct nvkm_oclass *nv25_fb_oclass;
+extern struct nvkm_oclass *nv30_fb_oclass;
+extern struct nvkm_oclass *nv35_fb_oclass;
+extern struct nvkm_oclass *nv36_fb_oclass;
+extern struct nvkm_oclass *nv40_fb_oclass;
+extern struct nvkm_oclass *nv41_fb_oclass;
+extern struct nvkm_oclass *nv44_fb_oclass;
+extern struct nvkm_oclass *nv46_fb_oclass;
+extern struct nvkm_oclass *nv47_fb_oclass;
+extern struct nvkm_oclass *nv49_fb_oclass;
+extern struct nvkm_oclass *nv4e_fb_oclass;
+extern struct nvkm_oclass *nv50_fb_oclass;
+extern struct nvkm_oclass *g84_fb_oclass;
+extern struct nvkm_oclass *gt215_fb_oclass;
+extern struct nvkm_oclass *mcp77_fb_oclass;
+extern struct nvkm_oclass *mcp89_fb_oclass;
+extern struct nvkm_oclass *gf100_fb_oclass;
+extern struct nvkm_oclass *gk104_fb_oclass;
+extern struct nvkm_oclass *gk20a_fb_oclass;
+extern struct nvkm_oclass *gm107_fb_oclass;
+
+#include <subdev/bios.h>
+#include <subdev/bios/ramcfg.h>
+
+struct nvkm_ram_data {
+	struct list_head head;
+	struct nvbios_ramcfg bios;
+	u32 freq;
+};
+
+struct nvkm_ram {
+	struct nvkm_object base;
+	enum {
+		NV_MEM_TYPE_UNKNOWN = 0,
+		NV_MEM_TYPE_STOLEN,
+		NV_MEM_TYPE_SGRAM,
+		NV_MEM_TYPE_SDRAM,
+		NV_MEM_TYPE_DDR1,
+		NV_MEM_TYPE_DDR2,
+		NV_MEM_TYPE_DDR3,
+		NV_MEM_TYPE_GDDR2,
+		NV_MEM_TYPE_GDDR3,
+		NV_MEM_TYPE_GDDR4,
+		NV_MEM_TYPE_GDDR5
+	} type;
+	u64 stolen;
+	u64 size;
+	u32 tags;
+
+	int ranks;
+	int parts;
+	int part_mask;
+
+	int  (*get)(struct nvkm_fb *, u64 size, u32 align, u32 size_nc,
+		    u32 type, struct nvkm_mem **);
+	void (*put)(struct nvkm_fb *, struct nvkm_mem **);
+
+	int  (*calc)(struct nvkm_fb *, u32 freq);
+	int  (*prog)(struct nvkm_fb *);
+	void (*tidy)(struct nvkm_fb *);
+	u32 freq;
+	u32 mr[16];
+	u32 mr1_nuts;
+
+	struct nvkm_ram_data *next;
+	struct nvkm_ram_data former;
+	struct nvkm_ram_data xition;
+	struct nvkm_ram_data target;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h
new file mode 100644
index 0000000..a138478
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_FUSE_H__
+#define __NVKM_FUSE_H__
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nvkm_fuse {
+	struct nvkm_subdev base;
+};
+
+static inline struct nvkm_fuse *
+nvkm_fuse(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FUSE);
+}
+
+#define nvkm_fuse_create(p, e, o, d)                                        \
+	nvkm_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
+
+int  nvkm_fuse_create_(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, int, void **);
+void _nvkm_fuse_dtor(struct nvkm_object *);
+int  _nvkm_fuse_init(struct nvkm_object *);
+#define _nvkm_fuse_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv50_fuse_oclass;
+extern struct nvkm_oclass gf100_fuse_oclass;
+extern struct nvkm_oclass gm107_fuse_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
new file mode 100644
index 0000000..ca5099a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
@@ -0,0 +1,44 @@
+#ifndef __NVKM_GPIO_H__
+#define __NVKM_GPIO_H__
+#include <core/subdev.h>
+#include <core/event.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+
+struct nvkm_gpio_ntfy_req {
+#define NVKM_GPIO_HI                                                       0x01
+#define NVKM_GPIO_LO                                                       0x02
+#define NVKM_GPIO_TOGGLED                                                  0x03
+	u8 mask;
+	u8 line;
+};
+
+struct nvkm_gpio_ntfy_rep {
+	u8 mask;
+};
+
+struct nvkm_gpio {
+	struct nvkm_subdev base;
+
+	struct nvkm_event event;
+
+	void (*reset)(struct nvkm_gpio *, u8 func);
+	int  (*find)(struct nvkm_gpio *, int idx, u8 tag, u8 line,
+		     struct dcb_gpio_func *);
+	int  (*set)(struct nvkm_gpio *, int idx, u8 tag, u8 line, int state);
+	int  (*get)(struct nvkm_gpio *, int idx, u8 tag, u8 line);
+};
+
+static inline struct nvkm_gpio *
+nvkm_gpio(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_GPIO);
+}
+
+extern struct nvkm_oclass *nv10_gpio_oclass;
+extern struct nvkm_oclass *nv50_gpio_oclass;
+extern struct nvkm_oclass *g94_gpio_oclass;
+extern struct nvkm_oclass *gf110_gpio_oclass;
+extern struct nvkm_oclass *gk104_gpio_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
new file mode 100644
index 0000000..a2e3373
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -0,0 +1,135 @@
+#ifndef __NVKM_I2C_H__
+#define __NVKM_I2C_H__
+#include <core/subdev.h>
+#include <core/event.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/i2c.h>
+
+#define NV_I2C_PORT(n)    (0x00 + (n))
+#define NV_I2C_AUX(n)     (0x10 + (n))
+#define NV_I2C_EXT(n)     (0x20 + (n))
+#define NV_I2C_DEFAULT(n) (0x80 + (n))
+
+#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
+#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
+#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
+
+struct nvkm_i2c_ntfy_req {
+#define NVKM_I2C_PLUG                                                      0x01
+#define NVKM_I2C_UNPLUG                                                    0x02
+#define NVKM_I2C_IRQ                                                       0x04
+#define NVKM_I2C_DONE                                                      0x08
+#define NVKM_I2C_ANY                                                       0x0f
+	u8 mask;
+	u8 port;
+};
+
+struct nvkm_i2c_ntfy_rep {
+	u8 mask;
+};
+
+struct nvkm_i2c_port {
+	struct nvkm_object base;
+	struct i2c_adapter adapter;
+	struct mutex mutex;
+
+	struct list_head head;
+	u8  index;
+	int aux;
+
+	const struct nvkm_i2c_func *func;
+};
+
+struct nvkm_i2c_func {
+	void (*drive_scl)(struct nvkm_i2c_port *, int);
+	void (*drive_sda)(struct nvkm_i2c_port *, int);
+	int  (*sense_scl)(struct nvkm_i2c_port *);
+	int  (*sense_sda)(struct nvkm_i2c_port *);
+
+	int  (*aux)(struct nvkm_i2c_port *, bool, u8, u32, u8 *, u8);
+	int  (*pattern)(struct nvkm_i2c_port *, int pattern);
+	int  (*lnk_ctl)(struct nvkm_i2c_port *, int nr, int bw, bool enh);
+	int  (*drv_ctl)(struct nvkm_i2c_port *, int lane, int sw, int pe);
+};
+
+struct nvkm_i2c_board_info {
+	struct i2c_board_info dev;
+	u8 udelay; /* set to 0 to use the standard delay */
+};
+
+struct nvkm_i2c {
+	struct nvkm_subdev base;
+	struct nvkm_event event;
+
+	struct nvkm_i2c_port *(*find)(struct nvkm_i2c *, u8 index);
+	struct nvkm_i2c_port *(*find_type)(struct nvkm_i2c *, u16 type);
+	int  (*acquire_pad)(struct nvkm_i2c_port *, unsigned long timeout);
+	void (*release_pad)(struct nvkm_i2c_port *);
+	int  (*acquire)(struct nvkm_i2c_port *, unsigned long timeout);
+	void (*release)(struct nvkm_i2c_port *);
+	int  (*identify)(struct nvkm_i2c *, int index,
+			 const char *what, struct nvkm_i2c_board_info *,
+			 bool (*match)(struct nvkm_i2c_port *,
+				       struct i2c_board_info *, void *),
+			 void *);
+
+	wait_queue_head_t wait;
+	struct list_head ports;
+};
+
+static inline struct nvkm_i2c *
+nvkm_i2c(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_I2C);
+}
+
+extern struct nvkm_oclass *nv04_i2c_oclass;
+extern struct nvkm_oclass *nv4e_i2c_oclass;
+extern struct nvkm_oclass *nv50_i2c_oclass;
+extern struct nvkm_oclass *g94_i2c_oclass;
+extern struct nvkm_oclass *gf110_i2c_oclass;
+extern struct nvkm_oclass *gf117_i2c_oclass;
+extern struct nvkm_oclass *gk104_i2c_oclass;
+extern struct nvkm_oclass *gm204_i2c_oclass;
+
+static inline int
+nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg)
+{
+	u8 val;
+	struct i2c_msg msgs[] = {
+		{ .addr = addr, .flags = 0, .len = 1, .buf = &reg },
+		{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
+	};
+
+	int ret = i2c_transfer(&port->adapter, msgs, 2);
+	if (ret != 2)
+		return -EIO;
+
+	return val;
+}
+
+static inline int
+nv_wri2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msgs[] = {
+		{ .addr = addr, .flags = 0, .len = 2, .buf = buf },
+	};
+
+	int ret = i2c_transfer(&port->adapter, msgs, 1);
+	if (ret != 1)
+		return -EIO;
+
+	return 0;
+}
+
+static inline bool
+nv_probe_i2c(struct nvkm_i2c_port *port, u8 addr)
+{
+	return nv_rdi2cr(port, addr, 0) >= 0;
+}
+
+int nv_rdaux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size);
+int nv_wraux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
new file mode 100644
index 0000000..2150d8a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_IBUS_H__
+#define __NVKM_IBUS_H__
+#include <core/subdev.h>
+
+struct nvkm_ibus {
+	struct nvkm_subdev base;
+};
+
+static inline struct nvkm_ibus *
+nvkm_ibus(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_IBUS);
+}
+
+#define nvkm_ibus_create(p,e,o,d)                                           \
+	nvkm_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus",              \
+			       sizeof(**d), (void **)d)
+#define nvkm_ibus_destroy(p)                                                \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_ibus_init(p)                                                   \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_ibus_fini(p,s)                                                 \
+	nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_ibus_dtor _nvkm_subdev_dtor
+#define _nvkm_ibus_init _nvkm_subdev_init
+#define _nvkm_ibus_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass gf100_ibus_oclass;
+extern struct nvkm_oclass gk104_ibus_oclass;
+extern struct nvkm_oclass gk20a_ibus_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
new file mode 100644
index 0000000..d104c1a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
@@ -0,0 +1,48 @@
+#ifndef __NVKM_INSTMEM_H__
+#define __NVKM_INSTMEM_H__
+#include <core/subdev.h>
+
+struct nvkm_instobj {
+	struct nvkm_object base;
+	struct list_head head;
+	u32 *suspend;
+	u64 addr;
+	u32 size;
+};
+
+static inline struct nvkm_instobj *
+nv_memobj(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS)))
+		nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj));
+#endif
+	return obj;
+}
+
+struct nvkm_instmem {
+	struct nvkm_subdev base;
+	struct list_head list;
+
+	u32 reserved;
+	int (*alloc)(struct nvkm_instmem *, struct nvkm_object *,
+		     u32 size, u32 align, struct nvkm_object **);
+};
+
+static inline struct nvkm_instmem *
+nvkm_instmem(void *obj)
+{
+	/* nv04/nv40 impls need to create objects in their constructor,
+	 * which is before the subdev pointer is valid
+	 */
+	if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
+	    nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM)
+		return obj;
+
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_INSTMEM);
+}
+
+extern struct nvkm_oclass *nv04_instmem_oclass;
+extern struct nvkm_oclass *nv40_instmem_oclass;
+extern struct nvkm_oclass *nv50_instmem_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
new file mode 100644
index 0000000..cd5d29f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
@@ -0,0 +1,31 @@
+#ifndef __NVKM_LTC_H__
+#define __NVKM_LTC_H__
+#include <core/subdev.h>
+struct nvkm_mm_node;
+
+#define NVKM_LTC_MAX_ZBC_CNT 16
+
+struct nvkm_ltc {
+	struct nvkm_subdev base;
+
+	int  (*tags_alloc)(struct nvkm_ltc *, u32 count,
+			   struct nvkm_mm_node **);
+	void (*tags_free)(struct nvkm_ltc *, struct nvkm_mm_node **);
+	void (*tags_clear)(struct nvkm_ltc *, u32 first, u32 count);
+
+	int zbc_min;
+	int zbc_max;
+	int (*zbc_color_get)(struct nvkm_ltc *, int index, const u32[4]);
+	int (*zbc_depth_get)(struct nvkm_ltc *, int index, const u32);
+};
+
+static inline struct nvkm_ltc *
+nvkm_ltc(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_LTC);
+}
+
+extern struct nvkm_oclass *gf100_ltc_oclass;
+extern struct nvkm_oclass *gk104_ltc_oclass;
+extern struct nvkm_oclass *gm107_ltc_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
new file mode 100644
index 0000000..055bea7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_MC_H__
+#define __NVKM_MC_H__
+#include <core/subdev.h>
+
+struct nvkm_mc {
+	struct nvkm_subdev base;
+	bool use_msi;
+	unsigned int irq;
+	void (*unk260)(struct nvkm_mc *, u32);
+};
+
+static inline struct nvkm_mc *
+nvkm_mc(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MC);
+}
+
+extern struct nvkm_oclass *nv04_mc_oclass;
+extern struct nvkm_oclass *nv40_mc_oclass;
+extern struct nvkm_oclass *nv44_mc_oclass;
+extern struct nvkm_oclass *nv4c_mc_oclass;
+extern struct nvkm_oclass *nv50_mc_oclass;
+extern struct nvkm_oclass *g94_mc_oclass;
+extern struct nvkm_oclass *g98_mc_oclass;
+extern struct nvkm_oclass *gf100_mc_oclass;
+extern struct nvkm_oclass *gf106_mc_oclass;
+extern struct nvkm_oclass *gk20a_mc_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
new file mode 100644
index 0000000..3a53687
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
@@ -0,0 +1,104 @@
+#ifndef __NVKM_MMU_H__
+#define __NVKM_MMU_H__
+#include <core/subdev.h>
+#include <core/mm.h>
+struct nvkm_device;
+struct nvkm_mem;
+
+struct nvkm_vm_pgt {
+	struct nvkm_gpuobj *obj[2];
+	u32 refcount[2];
+};
+
+struct nvkm_vm_pgd {
+	struct list_head head;
+	struct nvkm_gpuobj *obj;
+};
+
+struct nvkm_vma {
+	struct list_head head;
+	int refcount;
+	struct nvkm_vm *vm;
+	struct nvkm_mm_node *node;
+	u64 offset;
+	u32 access;
+};
+
+struct nvkm_vm {
+	struct nvkm_mmu *mmu;
+	struct nvkm_mm mm;
+	struct kref refcount;
+
+	struct list_head pgd_list;
+	atomic_t engref[NVDEV_SUBDEV_NR];
+
+	struct nvkm_vm_pgt *pgt;
+	u32 fpde;
+	u32 lpde;
+};
+
+struct nvkm_mmu {
+	struct nvkm_subdev base;
+
+	u64 limit;
+	u8  dma_bits;
+	u32 pgt_bits;
+	u8  spg_shift;
+	u8  lpg_shift;
+
+	int  (*create)(struct nvkm_mmu *, u64 offset, u64 length,
+		       u64 mm_offset, struct nvkm_vm **);
+
+	void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde,
+			struct nvkm_gpuobj *pgt[2]);
+	void (*map)(struct nvkm_vma *, struct nvkm_gpuobj *,
+		    struct nvkm_mem *, u32 pte, u32 cnt,
+		    u64 phys, u64 delta);
+	void (*map_sg)(struct nvkm_vma *, struct nvkm_gpuobj *,
+		       struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *);
+	void (*unmap)(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt);
+	void (*flush)(struct nvkm_vm *);
+};
+
+static inline struct nvkm_mmu *
+nvkm_mmu(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MMU);
+}
+
+#define nvkm_mmu_create(p,e,o,i,f,d)                                      \
+	nvkm_subdev_create((p), (e), (o), 0, (i), (f), (d))
+#define nvkm_mmu_destroy(p)                                               \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_mmu_init(p)                                                  \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_mmu_fini(p,s)                                                \
+	nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_mmu_dtor _nvkm_subdev_dtor
+#define _nvkm_mmu_init _nvkm_subdev_init
+#define _nvkm_mmu_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv04_mmu_oclass;
+extern struct nvkm_oclass nv41_mmu_oclass;
+extern struct nvkm_oclass nv44_mmu_oclass;
+extern struct nvkm_oclass nv50_mmu_oclass;
+extern struct nvkm_oclass gf100_mmu_oclass;
+
+int  nv04_vm_create(struct nvkm_mmu *, u64, u64, u64,
+		    struct nvkm_vm **);
+void nv04_mmu_dtor(struct nvkm_object *);
+
+int  nvkm_vm_create(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset,
+		    u32 block, struct nvkm_vm **);
+int  nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset,
+		 struct nvkm_vm **);
+int  nvkm_vm_ref(struct nvkm_vm *, struct nvkm_vm **, struct nvkm_gpuobj *pgd);
+int  nvkm_vm_get(struct nvkm_vm *, u64 size, u32 page_shift, u32 access,
+		 struct nvkm_vma *);
+void nvkm_vm_put(struct nvkm_vma *);
+void nvkm_vm_map(struct nvkm_vma *, struct nvkm_mem *);
+void nvkm_vm_map_at(struct nvkm_vma *, u64 offset, struct nvkm_mem *);
+void nvkm_vm_unmap(struct nvkm_vma *);
+void nvkm_vm_unmap_at(struct nvkm_vma *, u64 offset, u64 length);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h
new file mode 100644
index 0000000..fba6134
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_MXM_H__
+#define __NVKM_MXM_H__
+#include <core/subdev.h>
+
+#define MXM_SANITISE_DCB 0x00000001
+
+struct nvkm_mxm {
+	struct nvkm_subdev base;
+	u32 action;
+	u8 *mxms;
+};
+
+static inline struct nvkm_mxm *
+nvkm_mxm(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MXM);
+}
+
+#define nvkm_mxm_create(p,e,o,d)                                            \
+	nvkm_mxm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_mxm_init(p)                                                    \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_mxm_fini(p,s)                                                  \
+	nvkm_subdev_fini(&(p)->base, (s))
+int  nvkm_mxm_create_(struct nvkm_object *, struct nvkm_object *,
+			 struct nvkm_oclass *, int, void **);
+void nvkm_mxm_destroy(struct nvkm_mxm *);
+
+#define _nvkm_mxm_dtor _nvkm_subdev_dtor
+#define _nvkm_mxm_init _nvkm_subdev_init
+#define _nvkm_mxm_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv50_mxm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
new file mode 100644
index 0000000..7b86acc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_PMU_H__
+#define __NVKM_PMU_H__
+#include <core/subdev.h>
+
+struct nvkm_pmu {
+	struct nvkm_subdev base;
+
+	struct {
+		u32 base;
+		u32 size;
+	} send;
+
+	struct {
+		u32 base;
+		u32 size;
+
+		struct work_struct work;
+		wait_queue_head_t wait;
+		u32 process;
+		u32 message;
+		u32 data[2];
+	} recv;
+
+	int  (*message)(struct nvkm_pmu *, u32[2], u32, u32, u32, u32);
+	void (*pgob)(struct nvkm_pmu *, bool);
+};
+
+static inline struct nvkm_pmu *
+nvkm_pmu(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_PMU);
+}
+
+extern struct nvkm_oclass *gt215_pmu_oclass;
+extern struct nvkm_oclass *gf100_pmu_oclass;
+extern struct nvkm_oclass *gf110_pmu_oclass;
+extern struct nvkm_oclass *gk104_pmu_oclass;
+extern struct nvkm_oclass *gk208_pmu_oclass;
+extern struct nvkm_oclass *gk20a_pmu_oclass;
+
+/* interface to MEMX process running on PMU */
+struct nvkm_memx;
+int  nvkm_memx_init(struct nvkm_pmu *, struct nvkm_memx **);
+int  nvkm_memx_fini(struct nvkm_memx **, bool exec);
+void nvkm_memx_wr32(struct nvkm_memx *, u32 addr, u32 data);
+void nvkm_memx_wait(struct nvkm_memx *, u32 addr, u32 mask, u32 data, u32 nsec);
+void nvkm_memx_nsec(struct nvkm_memx *, u32 nsec);
+void nvkm_memx_wait_vblank(struct nvkm_memx *);
+void nvkm_memx_train(struct nvkm_memx *);
+int  nvkm_memx_train_result(struct nvkm_pmu *, u32 *, int);
+void nvkm_memx_block(struct nvkm_memx *);
+void nvkm_memx_unblock(struct nvkm_memx *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
new file mode 100644
index 0000000..6662829
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
@@ -0,0 +1,79 @@
+#ifndef __NVKM_THERM_H__
+#define __NVKM_THERM_H__
+#include <core/subdev.h>
+
+enum nvkm_therm_fan_mode {
+	NVKM_THERM_CTRL_NONE = 0,
+	NVKM_THERM_CTRL_MANUAL = 1,
+	NVKM_THERM_CTRL_AUTO = 2,
+};
+
+enum nvkm_therm_attr_type {
+	NVKM_THERM_ATTR_FAN_MIN_DUTY = 0,
+	NVKM_THERM_ATTR_FAN_MAX_DUTY = 1,
+	NVKM_THERM_ATTR_FAN_MODE = 2,
+
+	NVKM_THERM_ATTR_THRS_FAN_BOOST = 10,
+	NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
+	NVKM_THERM_ATTR_THRS_DOWN_CLK = 12,
+	NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
+	NVKM_THERM_ATTR_THRS_CRITICAL = 14,
+	NVKM_THERM_ATTR_THRS_CRITICAL_HYST = 15,
+	NVKM_THERM_ATTR_THRS_SHUTDOWN = 16,
+	NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
+};
+
+struct nvkm_therm {
+	struct nvkm_subdev base;
+
+	int (*pwm_ctrl)(struct nvkm_therm *, int line, bool);
+	int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *);
+	int (*pwm_set)(struct nvkm_therm *, int line, u32, u32);
+	int (*pwm_clock)(struct nvkm_therm *, int line);
+
+	int (*fan_get)(struct nvkm_therm *);
+	int (*fan_set)(struct nvkm_therm *, int);
+	int (*fan_sense)(struct nvkm_therm *);
+
+	int (*temp_get)(struct nvkm_therm *);
+
+	int (*attr_get)(struct nvkm_therm *, enum nvkm_therm_attr_type);
+	int (*attr_set)(struct nvkm_therm *, enum nvkm_therm_attr_type, int);
+};
+
+static inline struct nvkm_therm *
+nvkm_therm(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_THERM);
+}
+
+#define nvkm_therm_create(p,e,o,d)                                          \
+	nvkm_therm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_therm_destroy(p) ({                                            \
+	struct nvkm_therm *therm = (p);                                     \
+        _nvkm_therm_dtor(nv_object(therm));                                 \
+})
+#define nvkm_therm_init(p) ({                                               \
+	struct nvkm_therm *therm = (p);                                     \
+        _nvkm_therm_init(nv_object(therm));                                 \
+})
+#define nvkm_therm_fini(p,s) ({                                             \
+	struct nvkm_therm *therm = (p);                                     \
+        _nvkm_therm_init(nv_object(therm), (s));                            \
+})
+
+int  nvkm_therm_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *, int, void **);
+void _nvkm_therm_dtor(struct nvkm_object *);
+int  _nvkm_therm_init(struct nvkm_object *);
+int  _nvkm_therm_fini(struct nvkm_object *, bool);
+
+int  nvkm_therm_cstate(struct nvkm_therm *, int, int);
+
+extern struct nvkm_oclass nv40_therm_oclass;
+extern struct nvkm_oclass nv50_therm_oclass;
+extern struct nvkm_oclass g84_therm_oclass;
+extern struct nvkm_oclass gt215_therm_oclass;
+extern struct nvkm_oclass gf110_therm_oclass;
+extern struct nvkm_oclass gm107_therm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
new file mode 100644
index 0000000..4ad5508
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_TIMER_H__
+#define __NVKM_TIMER_H__
+#include <core/subdev.h>
+
+struct nvkm_alarm {
+	struct list_head head;
+	u64 timestamp;
+	void (*func)(struct nvkm_alarm *);
+};
+
+static inline void
+nvkm_alarm_init(struct nvkm_alarm *alarm,
+		   void (*func)(struct nvkm_alarm *))
+{
+	INIT_LIST_HEAD(&alarm->head);
+	alarm->func = func;
+}
+
+bool nvkm_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
+bool nvkm_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
+bool nvkm_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
+void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *);
+void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *);
+
+#define NV_WAIT_DEFAULT 2000000000ULL
+#define nv_wait(o,a,m,v)                                                       \
+	nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
+#define nv_wait_ne(o,a,m,v)                                                    \
+	nvkm_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v))
+#define nv_wait_cb(o,c,d)                                                      \
+	nvkm_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d))
+
+struct nvkm_timer {
+	struct nvkm_subdev base;
+	u64  (*read)(struct nvkm_timer *);
+	void (*alarm)(struct nvkm_timer *, u64 time, struct nvkm_alarm *);
+	void (*alarm_cancel)(struct nvkm_timer *, struct nvkm_alarm *);
+};
+
+static inline struct nvkm_timer *
+nvkm_timer(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_TIMER);
+}
+
+#define nvkm_timer_create(p,e,o,d)                                          \
+	nvkm_subdev_create_((p), (e), (o), 0, "PTIMER", "timer",            \
+			       sizeof(**d), (void **)d)
+#define nvkm_timer_destroy(p)                                               \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_timer_init(p)                                                  \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_timer_fini(p,s)                                                \
+	nvkm_subdev_fini(&(p)->base, (s))
+
+int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *,
+			  struct nvkm_oclass *, int size, void **);
+
+extern struct nvkm_oclass nv04_timer_oclass;
+extern struct nvkm_oclass gk20a_timer_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vga.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/include/subdev/vga.h
rename to drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
new file mode 100644
index 0000000..e3d7243
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_VOLT_H__
+#define __NVKM_VOLT_H__
+#include <core/subdev.h>
+
+struct nvkm_voltage {
+	u32 uv;
+	u8  id;
+};
+
+struct nvkm_volt {
+	struct nvkm_subdev base;
+
+	int (*vid_get)(struct nvkm_volt *);
+	int (*get)(struct nvkm_volt *);
+	int (*vid_set)(struct nvkm_volt *, u8 vid);
+	int (*set)(struct nvkm_volt *, u32 uv);
+	int (*set_id)(struct nvkm_volt *, u8 id, int condition);
+
+	u8 vid_mask;
+	u8 vid_nr;
+	struct {
+		u32 uv;
+		u8 vid;
+	} vid[256];
+};
+
+static inline struct nvkm_volt *
+nvkm_volt(void *obj)
+{
+	return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VOLT);
+}
+
+#define nvkm_volt_create(p, e, o, d)                                        \
+	nvkm_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_volt_destroy(p) ({                                             \
+	struct nvkm_volt *v = (p);                                          \
+	_nvkm_volt_dtor(nv_object(v));                                      \
+})
+#define nvkm_volt_init(p) ({                                                \
+	struct nvkm_volt *v = (p);                                          \
+	_nvkm_volt_init(nv_object(v));                                      \
+})
+#define nvkm_volt_fini(p,s)                                                 \
+	nvkm_subdev_fini((p), (s))
+
+int  nvkm_volt_create_(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, int, void **);
+void _nvkm_volt_dtor(struct nvkm_object *);
+int  _nvkm_volt_init(struct nvkm_object *);
+#define _nvkm_volt_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv40_volt_oclass;
+extern struct nvkm_oclass gk20a_volt_oclass;
+
+int nvkm_voltgpio_init(struct nvkm_volt *);
+int nvkm_voltgpio_get(struct nvkm_volt *);
+int nvkm_voltgpio_set(struct nvkm_volt *, u8);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index d39a150..d8b0891 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -100,7 +100,7 @@
 nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
 			struct nouveau_abi16_ntfy *ntfy)
 {
-	nouveau_mm_free(&chan->heap, &ntfy->node);
+	nvkm_mm_free(&chan->heap, &ntfy->node);
 	list_del(&ntfy->head);
 	kfree(ntfy);
 }
@@ -128,7 +128,7 @@
 	}
 
 	if (chan->heap.block_size)
-		nouveau_mm_fini(&chan->heap);
+		nvkm_mm_fini(&chan->heap);
 
 	/* destroy channel object, all children will be killed too */
 	if (chan->chan) {
@@ -164,8 +164,8 @@
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nvif_device *device = &drm->device;
-	struct nouveau_timer *ptimer = nvkm_timer(device);
-	struct nouveau_graph *graph = nvkm_gr(device);
+	struct nvkm_timer *ptimer = nvxx_timer(device);
+	struct nvkm_gr *gr = nvxx_gr(device);
 	struct drm_nouveau_getparam *getparam = data;
 
 	switch (getparam->param) {
@@ -173,19 +173,19 @@
 		getparam->value = device->info.chipset;
 		break;
 	case NOUVEAU_GETPARAM_PCI_VENDOR:
-		if (nv_device_is_pci(nvkm_device(device)))
+		if (nv_device_is_pci(nvxx_device(device)))
 			getparam->value = dev->pdev->vendor;
 		else
 			getparam->value = 0;
 		break;
 	case NOUVEAU_GETPARAM_PCI_DEVICE:
-		if (nv_device_is_pci(nvkm_device(device)))
+		if (nv_device_is_pci(nvxx_device(device)))
 			getparam->value = dev->pdev->device;
 		else
 			getparam->value = 0;
 		break;
 	case NOUVEAU_GETPARAM_BUS_TYPE:
-		if (!nv_device_is_pci(nvkm_device(device)))
+		if (!nv_device_is_pci(nvxx_device(device)))
 			getparam->value = 3;
 		else
 		if (drm_pci_device_is_agp(dev))
@@ -215,7 +215,7 @@
 		getparam->value = 1;
 		break;
 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
-		getparam->value = graph->units ? graph->units(graph) : 0;
+		getparam->value = gr->units ? gr->units(gr) : 0;
 		break;
 	default:
 		NV_PRINTK(debug, cli, "unknown parameter %lld\n", getparam->param);
@@ -324,7 +324,7 @@
 	if (ret)
 		goto done;
 
-	ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
+	ret = nvkm_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
 done:
 	if (ret)
 		nouveau_abi16_chan_fini(abi16, chan);
@@ -448,8 +448,8 @@
 	list_add(&ntfy->head, &chan->notifiers);
 	ntfy->handle = info->handle;
 
-	ret = nouveau_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
-			      &ntfy->node);
+	ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
+			   &ntfy->node);
 	if (ret)
 		goto done;
 
@@ -527,7 +527,7 @@
 	/* cleanup extra state if this object was a notifier */
 	list_for_each_entry(ntfy, &chan->notifiers, head) {
 		if (ntfy->handle == fini->handle) {
-			nouveau_mm_free(&chan->heap, &ntfy->node);
+			nvkm_mm_free(&chan->heap, &ntfy->node);
 			list_del(&ntfy->head);
 			break;
 		}
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h
index 39844e6..86eb1ca 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.h
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h
@@ -14,7 +14,7 @@
 
 struct nouveau_abi16_ntfy {
 	struct list_head head;
-	struct nouveau_mm_node *node;
+	struct nvkm_mm_node *node;
 	u32 handle;
 };
 
@@ -23,8 +23,8 @@
 	struct nouveau_channel *chan;
 	struct list_head notifiers;
 	struct nouveau_bo *ntfy;
-	struct nouveau_vma ntfy_vma;
-	struct nouveau_mm  heap;
+	struct nvkm_vma ntfy_vma;
+	struct nvkm_mm  heap;
 };
 
 struct nouveau_abi16 {
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c
index 1f6f6ba..0b59709 100644
--- a/drivers/gpu/drm/nouveau/nouveau_agp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_agp.c
@@ -45,8 +45,8 @@
 	while (agpmode == -1 && quirk->hostbridge_vendor) {
 		if (info->id_vendor == quirk->hostbridge_vendor &&
 		    info->id_device == quirk->hostbridge_device &&
-		    nvkm_device(device)->pdev->vendor == quirk->chip_vendor &&
-		    nvkm_device(device)->pdev->device == quirk->chip_device) {
+		    nvxx_device(device)->pdev->vendor == quirk->chip_vendor &&
+		    nvxx_device(device)->pdev->device == quirk->chip_device) {
 			agpmode = quirk->mode;
 			NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n",
 				agpmode);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 7df6acc..0190b69 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -2009,7 +2009,7 @@
 static bool NVInitVBIOS(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_bios *bios = nvkm_bios(&drm->device);
+	struct nvkm_bios *bios = nvxx_bios(&drm->device);
 	struct nvbios *legacy = &drm->vbios;
 
 	memset(legacy, 0, sizeof(struct nvbios));
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index bba2960..77326e3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -48,9 +48,9 @@
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	int i = reg - drm->tile.reg;
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
-	struct nouveau_fb_tile *tile = &pfb->tile.region[i];
-	struct nouveau_engine *engine;
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
+	struct nvkm_fb_tile *tile = &pfb->tile.region[i];
+	struct nvkm_engine *engine;
 
 	nouveau_fence_unref(&reg->fence);
 
@@ -62,9 +62,9 @@
 
 	pfb->tile.prog(pfb, i, tile);
 
-	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_GR)))
+	if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_GR)))
 		engine->tile_prog(engine, i);
-	if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_MPEG)))
+	if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_MPEG)))
 		engine->tile_prog(engine, i);
 }
 
@@ -105,7 +105,7 @@
 		   u32 size, u32 pitch, u32 flags)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
 	struct nouveau_drm_tile *tile, *found = NULL;
 	int i;
 
@@ -193,7 +193,7 @@
 	int max_size;
 
 	if (drm->client.vm)
-		lpg_shift = drm->client.vm->vmm->lpg_shift;
+		lpg_shift = drm->client.vm->mmu->lpg_shift;
 	max_size = INT_MAX & ~((1 << lpg_shift) - 1);
 
 	if (size <= 0 || size > max_size) {
@@ -214,13 +214,13 @@
 	nvbo->tile_flags = tile_flags;
 	nvbo->bo.bdev = &drm->ttm.bdev;
 
-	if (!nv_device_is_cpu_coherent(nvkm_device(&drm->device)))
+	if (!nv_device_is_cpu_coherent(nvxx_device(&drm->device)))
 		nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED;
 
 	nvbo->page_shift = 12;
 	if (drm->client.vm) {
 		if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
-			nvbo->page_shift = drm->client.vm->vmm->lpg_shift;
+			nvbo->page_shift = drm->client.vm->mmu->lpg_shift;
 	}
 
 	nouveau_bo_fixup_align(nvbo, flags, &align, &size);
@@ -325,7 +325,7 @@
 	    memtype == TTM_PL_FLAG_VRAM && contig) {
 		if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
 			if (bo->mem.mem_type == TTM_PL_VRAM) {
-				struct nouveau_mem *mem = bo->mem.mm_node;
+				struct nvkm_mem *mem = bo->mem.mm_node;
 				if (!list_is_singular(&mem->regions))
 					evict = true;
 			}
@@ -459,7 +459,7 @@
 nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
 {
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
-	struct nouveau_device *device = nvkm_device(&drm->device);
+	struct nvkm_device *device = nvxx_device(&drm->device);
 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
 	int i;
 
@@ -479,7 +479,7 @@
 nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
 {
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
-	struct nouveau_device *device = nvkm_device(&drm->device);
+	struct nvkm_device *device = nvxx_device(&drm->device);
 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
 	int i;
 
@@ -533,20 +533,6 @@
 }
 #define nouveau_bo_mem_index(o, i, m) _nouveau_bo_mem_index(o, i, m, sizeof(*m))
 
-u16
-nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index)
-{
-	bool is_iomem;
-	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-
-	mem = nouveau_bo_mem_index(nvbo, index, mem);
-
-	if (is_iomem)
-		return ioread16_native((void __force __iomem *)mem);
-	else
-		return *mem;
-}
-
 void
 nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
 {
@@ -634,7 +620,7 @@
 
 		if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
 			/* Some BARs do not support being ioremapped WC */
-			if (nvkm_bar(&drm->device)->iomap_uncached) {
+			if (nvxx_bar(&drm->device)->iomap_uncached) {
 				man->available_caching = TTM_PL_FLAG_UNCACHED;
 				man->default_caching = TTM_PL_FLAG_UNCACHED;
 			}
@@ -709,7 +695,7 @@
 nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	int ret = RING_SPACE(chan, 10);
 	if (ret == 0) {
 		BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8);
@@ -741,7 +727,7 @@
 nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	u64 src_offset = node->vma[0].offset;
 	u64 dst_offset = node->vma[1].offset;
 	u32 page_count = new_mem->num_pages;
@@ -779,7 +765,7 @@
 nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	u64 src_offset = node->vma[0].offset;
 	u64 dst_offset = node->vma[1].offset;
 	u32 page_count = new_mem->num_pages;
@@ -818,7 +804,7 @@
 nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	u64 src_offset = node->vma[0].offset;
 	u64 dst_offset = node->vma[1].offset;
 	u32 page_count = new_mem->num_pages;
@@ -856,7 +842,7 @@
 nv98_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	int ret = RING_SPACE(chan, 7);
 	if (ret == 0) {
 		BEGIN_NV04(chan, NvSubCopy, 0x0320, 6);
@@ -874,7 +860,7 @@
 nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	int ret = RING_SPACE(chan, 7);
 	if (ret == 0) {
 		BEGIN_NV04(chan, NvSubCopy, 0x0304, 6);
@@ -908,12 +894,12 @@
 nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_mem *node = old_mem->mm_node;
+	struct nvkm_mem *node = old_mem->mm_node;
 	u64 length = (new_mem->num_pages << PAGE_SHIFT);
 	u64 src_offset = node->vma[0].offset;
 	u64 dst_offset = node->vma[1].offset;
 	int src_tiled = !!node->memtype;
-	int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype;
+	int dst_tiled = !!((struct nvkm_mem *)new_mem->mm_node)->memtype;
 	int ret;
 
 	while (length) {
@@ -1050,25 +1036,25 @@
 nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
 		     struct ttm_mem_reg *mem)
 {
-	struct nouveau_mem *old_node = bo->mem.mm_node;
-	struct nouveau_mem *new_node = mem->mm_node;
+	struct nvkm_mem *old_node = bo->mem.mm_node;
+	struct nvkm_mem *new_node = mem->mm_node;
 	u64 size = (u64)mem->num_pages << PAGE_SHIFT;
 	int ret;
 
-	ret = nouveau_vm_get(drm->client.vm, size, old_node->page_shift,
-			     NV_MEM_ACCESS_RW, &old_node->vma[0]);
+	ret = nvkm_vm_get(drm->client.vm, size, old_node->page_shift,
+			  NV_MEM_ACCESS_RW, &old_node->vma[0]);
 	if (ret)
 		return ret;
 
-	ret = nouveau_vm_get(drm->client.vm, size, new_node->page_shift,
-			     NV_MEM_ACCESS_RW, &old_node->vma[1]);
+	ret = nvkm_vm_get(drm->client.vm, size, new_node->page_shift,
+			  NV_MEM_ACCESS_RW, &old_node->vma[1]);
 	if (ret) {
-		nouveau_vm_put(&old_node->vma[0]);
+		nvkm_vm_put(&old_node->vma[0]);
 		return ret;
 	}
 
-	nouveau_vm_map(&old_node->vma[0], old_node);
-	nouveau_vm_map(&old_node->vma[1], new_node);
+	nvkm_vm_map(&old_node->vma[0], old_node);
+	nvkm_vm_map(&old_node->vma[1], new_node);
 	return 0;
 }
 
@@ -1083,7 +1069,7 @@
 	int ret;
 
 	/* create temporary vmas for the transfer and attach them to the
-	 * old nouveau_mem node, these will get cleaned up after ttm has
+	 * old nvkm_mem node, these will get cleaned up after ttm has
 	 * destroyed the ttm_mem_reg
 	 */
 	if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
@@ -1245,7 +1231,7 @@
 nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
 {
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 
 	/* ttm can now (stupidly) pass the driver bos it didn't create... */
 	if (bo->destroy != nouveau_bo_del_ttm)
@@ -1254,10 +1240,10 @@
 	list_for_each_entry(vma, &nvbo->vma_list, head) {
 		if (new_mem && new_mem->mem_type != TTM_PL_SYSTEM &&
 			      (new_mem->mem_type == TTM_PL_VRAM ||
-			       nvbo->page_shift != vma->vm->vmm->lpg_shift)) {
-			nouveau_vm_map(vma, new_mem->mm_node);
+			       nvbo->page_shift != vma->vm->mmu->lpg_shift)) {
+			nvkm_vm_map(vma, new_mem->mm_node);
 		} else {
-			nouveau_vm_unmap(vma);
+			nvkm_vm_unmap(vma);
 		}
 	}
 }
@@ -1368,7 +1354,7 @@
 {
 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
 	struct nouveau_drm *drm = nouveau_bdev(bdev);
-	struct nouveau_mem *node = mem->mm_node;
+	struct nvkm_mem *node = mem->mm_node;
 	int ret;
 
 	mem->bus.addr = NULL;
@@ -1396,10 +1382,10 @@
 		/* fallthrough, tiled memory */
 	case TTM_PL_VRAM:
 		mem->bus.offset = mem->start << PAGE_SHIFT;
-		mem->bus.base = nv_device_resource_start(nvkm_device(&drm->device), 1);
+		mem->bus.base = nv_device_resource_start(nvxx_device(&drm->device), 1);
 		mem->bus.is_iomem = true;
 		if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-			struct nouveau_bar *bar = nvkm_bar(&drm->device);
+			struct nvkm_bar *bar = nvxx_bar(&drm->device);
 
 			ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
 					&node->bar_vma);
@@ -1419,8 +1405,8 @@
 nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
 	struct nouveau_drm *drm = nouveau_bdev(bdev);
-	struct nouveau_bar *bar = nvkm_bar(&drm->device);
-	struct nouveau_mem *node = mem->mm_node;
+	struct nvkm_bar *bar = nvxx_bar(&drm->device);
+	struct nvkm_mem *node = mem->mm_node;
 
 	if (!node->bar_vma.node)
 		return;
@@ -1434,7 +1420,7 @@
 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nvif_device *device = &drm->device;
-	u32 mappable = nv_device_resource_len(nvkm_device(device), 1) >> PAGE_SHIFT;
+	u32 mappable = nv_device_resource_len(nvxx_device(device), 1) >> PAGE_SHIFT;
 	int i, ret;
 
 	/* as long as the bo isn't in vram, and isn't tiled, we've got
@@ -1479,7 +1465,7 @@
 {
 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
 	struct nouveau_drm *drm;
-	struct nouveau_device *device;
+	struct nvkm_device *device;
 	struct drm_device *dev;
 	struct device *pdev;
 	unsigned i;
@@ -1498,7 +1484,7 @@
 	}
 
 	drm = nouveau_bdev(ttm->bdev);
-	device = nvkm_device(&drm->device);
+	device = nvxx_device(&drm->device);
 	dev = drm->dev;
 	pdev = nv_device_base(device);
 
@@ -1553,7 +1539,7 @@
 {
 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
 	struct nouveau_drm *drm;
-	struct nouveau_device *device;
+	struct nvkm_device *device;
 	struct drm_device *dev;
 	struct device *pdev;
 	unsigned i;
@@ -1563,7 +1549,7 @@
 		return;
 
 	drm = nouveau_bdev(ttm->bdev);
-	device = nvkm_device(&drm->device);
+	device = nvxx_device(&drm->device);
 	dev = drm->dev;
 	pdev = nv_device_base(device);
 
@@ -1627,10 +1613,10 @@
 	.io_mem_free = &nouveau_ttm_io_mem_free,
 };
 
-struct nouveau_vma *
-nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nouveau_vm *vm)
+struct nvkm_vma *
+nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nvkm_vm *vm)
 {
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 	list_for_each_entry(vma, &nvbo->vma_list, head) {
 		if (vma->vm == vm)
 			return vma;
@@ -1640,21 +1626,21 @@
 }
 
 int
-nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
-		   struct nouveau_vma *vma)
+nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nvkm_vm *vm,
+		   struct nvkm_vma *vma)
 {
 	const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
 	int ret;
 
-	ret = nouveau_vm_get(vm, size, nvbo->page_shift,
+	ret = nvkm_vm_get(vm, size, nvbo->page_shift,
 			     NV_MEM_ACCESS_RW, vma);
 	if (ret)
 		return ret;
 
 	if ( nvbo->bo.mem.mem_type != TTM_PL_SYSTEM &&
 	    (nvbo->bo.mem.mem_type == TTM_PL_VRAM ||
-	     nvbo->page_shift != vma->vm->vmm->lpg_shift))
-		nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
+	     nvbo->page_shift != vma->vm->mmu->lpg_shift))
+		nvkm_vm_map(vma, nvbo->bo.mem.mm_node);
 
 	list_add_tail(&vma->head, &nvbo->vma_list);
 	vma->refcount = 1;
@@ -1662,12 +1648,12 @@
 }
 
 void
-nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
 {
 	if (vma->node) {
 		if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM)
-			nouveau_vm_unmap(vma);
-		nouveau_vm_put(vma);
+			nvkm_vm_unmap(vma);
+		nvkm_vm_put(vma);
 		list_del(&vma->head);
 	}
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index 072222e..e423609 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -5,7 +5,7 @@
 
 struct nouveau_channel;
 struct nouveau_fence;
-struct nouveau_vma;
+struct nvkm_vma;
 
 struct nouveau_bo {
 	struct ttm_buffer_object bo;
@@ -78,7 +78,6 @@
 int  nouveau_bo_map(struct nouveau_bo *);
 void nouveau_bo_unmap(struct nouveau_bo *);
 void nouveau_bo_placement_set(struct nouveau_bo *, u32 type, u32 busy);
-u16  nouveau_bo_rd16(struct nouveau_bo *, unsigned index);
 void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val);
 u32  nouveau_bo_rd32(struct nouveau_bo *, unsigned index);
 void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val);
@@ -88,12 +87,12 @@
 void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
 void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
 
-struct nouveau_vma *
-nouveau_bo_vma_find(struct nouveau_bo *, struct nouveau_vm *);
+struct nvkm_vma *
+nouveau_bo_vma_find(struct nouveau_bo *, struct nvkm_vm *);
 
-int  nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *,
-			struct nouveau_vma *);
-void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
+int  nouveau_bo_vma_add(struct nouveau_bo *, struct nvkm_vm *,
+			struct nvkm_vma *);
+void nouveau_bo_vma_del(struct nouveau_bo *, struct nvkm_vma *);
 
 /* TODO: submit equivalent to TTM generic API upstream? */
 static inline void __iomem *
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index aff9099..e581f63 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -54,7 +54,7 @@
 
 	if (ret)
 		NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n",
-			  chan->object->handle, nvkm_client(&cli->base)->name);
+			  chan->object->handle, nvxx_client(&cli->base)->name);
 	return ret;
 }
 
@@ -88,7 +88,7 @@
 		     u32 handle, u32 size, struct nouveau_channel **pchan)
 {
 	struct nouveau_cli *cli = (void *)nvif_client(&device->base);
-	struct nouveau_vmmgr *vmm = nvkm_vmmgr(device);
+	struct nvkm_mmu *mmu = nvxx_mmu(device);
 	struct nv_dma_v0 args = {};
 	struct nouveau_channel *chan;
 	u32 target;
@@ -136,7 +136,7 @@
 		args.target = NV_DMA_V0_TARGET_VM;
 		args.access = NV_DMA_V0_ACCESS_VM;
 		args.start = 0;
-		args.limit = cli->vm->vmm->limit - 1;
+		args.limit = cli->vm->mmu->limit - 1;
 	} else
 	if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
 		if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
@@ -146,7 +146,7 @@
 			 */
 			args.target = NV_DMA_V0_TARGET_PCI;
 			args.access = NV_DMA_V0_ACCESS_RDWR;
-			args.start = nv_device_resource_start(nvkm_device(device), 1);
+			args.start = nv_device_resource_start(nvxx_device(device), 1);
 			args.limit = args.start + device->info.ram_user - 1;
 		} else {
 			args.target = NV_DMA_V0_TARGET_VRAM;
@@ -165,7 +165,7 @@
 			args.target = NV_DMA_V0_TARGET_VM;
 			args.access = NV_DMA_V0_ACCESS_RDWR;
 			args.start = 0;
-			args.limit = vmm->limit - 1;
+			args.limit = mmu->limit - 1;
 		}
 	}
 
@@ -281,8 +281,8 @@
 {
 	struct nvif_device *device = chan->device;
 	struct nouveau_cli *cli = (void *)nvif_client(&device->base);
-	struct nouveau_vmmgr *vmm = nvkm_vmmgr(device);
-	struct nouveau_software_chan *swch;
+	struct nvkm_mmu *mmu = nvxx_mmu(device);
+	struct nvkm_sw_chan *swch;
 	struct nv_dma_v0 args = {};
 	int ret, i;
 
@@ -294,7 +294,7 @@
 			args.target = NV_DMA_V0_TARGET_VM;
 			args.access = NV_DMA_V0_ACCESS_VM;
 			args.start = 0;
-			args.limit = cli->vm->vmm->limit - 1;
+			args.limit = cli->vm->mmu->limit - 1;
 		} else {
 			args.target = NV_DMA_V0_TARGET_VRAM;
 			args.access = NV_DMA_V0_ACCESS_RDWR;
@@ -312,7 +312,7 @@
 			args.target = NV_DMA_V0_TARGET_VM;
 			args.access = NV_DMA_V0_ACCESS_VM;
 			args.start = 0;
-			args.limit = cli->vm->vmm->limit - 1;
+			args.limit = cli->vm->mmu->limit - 1;
 		} else
 		if (chan->drm->agp.stat == ENABLED) {
 			args.target = NV_DMA_V0_TARGET_AGP;
@@ -324,7 +324,7 @@
 			args.target = NV_DMA_V0_TARGET_VM;
 			args.access = NV_DMA_V0_ACCESS_RDWR;
 			args.start = 0;
-			args.limit = vmm->limit - 1;
+			args.limit = mmu->limit - 1;
 		}
 
 		ret = nvif_object_init(chan->object, NULL, gart,
@@ -372,7 +372,7 @@
 		if (ret)
 			return ret;
 
-		swch = (void *)nvkm_object(&chan->nvsw)->parent;
+		swch = (void *)nvxx_object(&chan->nvsw)->parent;
 		swch->flip = nouveau_flip_complete;
 		swch->flip_data = chan;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h
index 8309c24..8b3640f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.h
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.h
@@ -16,7 +16,7 @@
 
 	struct {
 		struct nouveau_bo *buffer;
-		struct nouveau_vma vma;
+		struct nvkm_vma vma;
 		struct nvif_object ctxdma;
 	} push;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index c8ac948..db7095a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -115,7 +115,7 @@
 	struct drm_device *dev = connector->dev;
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+	struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
 	struct nouveau_encoder *nv_encoder;
 	struct drm_encoder *encoder;
 	int i, panel = -ENODEV;
@@ -241,7 +241,7 @@
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = NULL;
 	struct nouveau_encoder *nv_partner;
-	struct nouveau_i2c_port *i2c;
+	struct nvkm_i2c_port *i2c;
 	int type;
 	int ret;
 	enum drm_connector_status conn_status = connector_status_disconnected;
@@ -458,6 +458,28 @@
 
 		switch (value) {
 		case DRM_MODE_SCALE_NONE:
+			/* We allow 'None' for EDID modes, even on a fixed
+			 * panel (some exist with support for lower refresh
+			 * rates, which people might want to use for power
+			 * saving purposes).
+			 *
+			 * Non-EDID modes will force the use of GPU scaling
+			 * to the native mode regardless of this setting.
+			 */
+			switch (nv_connector->type) {
+			case DCB_CONNECTOR_LVDS:
+			case DCB_CONNECTOR_LVDS_SPWG:
+			case DCB_CONNECTOR_eDP:
+				/* ... except prior to G80, where the code
+				 * doesn't support such things.
+				 */
+				if (disp->disp.oclass < NV50_DISP)
+					return -EINVAL;
+				break;
+			default:
+				break;
+			}
+			break;
 		case DRM_MODE_SCALE_FULLSCREEN:
 		case DRM_MODE_SCALE_CENTER:
 		case DRM_MODE_SCALE_ASPECT:
@@ -466,11 +488,6 @@
 			return -EINVAL;
 		}
 
-		/* LVDS always needs gpu scaling */
-		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
-		    value == DRM_MODE_SCALE_NONE)
-			return -EINVAL;
-
 		/* Changing between GPU and panel scaling requires a full
 		 * modeset
 		 */
@@ -655,15 +672,15 @@
 
 	while (mode->hdisplay) {
 		if (mode->hdisplay <= native->hdisplay &&
-		    mode->vdisplay <= native->vdisplay) {
+		    mode->vdisplay <= native->vdisplay &&
+		    (mode->hdisplay != native->hdisplay ||
+		     mode->vdisplay != native->vdisplay)) {
 			m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
 					 drm_mode_vrefresh(native), false,
 					 false, false);
 			if (!m)
 				continue;
 
-			m->type |= DRM_MODE_TYPE_DRIVER;
-
 			drm_mode_probed_add(connector, m);
 			modes++;
 		}
@@ -968,7 +985,7 @@
 	struct nouveau_connector *nv_connector =
 		container_of(aux, typeof(*nv_connector), aux);
 	struct nouveau_encoder *nv_encoder;
-	struct nouveau_i2c_port *port;
+	struct nvkm_i2c_port *port;
 	int ret;
 
 	nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
@@ -979,13 +996,13 @@
 	if (msg->size == 0)
 		return msg->size;
 
-	ret = nouveau_i2c(port)->acquire(port, 0);
+	ret = nvkm_i2c(port)->acquire(port, 0);
 	if (ret)
 		return ret;
 
 	ret = port->func->aux(port, false, msg->request, msg->address,
 			      msg->buffer, msg->size);
-	nouveau_i2c(port)->release(port);
+	nvkm_i2c(port)->release(port);
 	if (ret >= 0) {
 		msg->reply = ret;
 		return msg->size;
@@ -1180,36 +1197,61 @@
 					      disp->color_vibrance_property,
 					      150);
 
+	/* default scaling mode */
 	switch (nv_connector->type) {
-	case DCB_CONNECTOR_VGA:
-		if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-			drm_object_attach_property(&connector->base,
-					dev->mode_config.scaling_mode_property,
-					nv_connector->scaling_mode);
+	case DCB_CONNECTOR_LVDS:
+	case DCB_CONNECTOR_LVDS_SPWG:
+	case DCB_CONNECTOR_eDP:
+		/* see note in nouveau_connector_set_property() */
+		if (disp->disp.oclass < NV50_DISP) {
+			nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
+			break;
 		}
-		/* fall-through */
-	case DCB_CONNECTOR_TV_0:
-	case DCB_CONNECTOR_TV_1:
-	case DCB_CONNECTOR_TV_3:
 		nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
 		break;
 	default:
-		nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
+		nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
+		break;
+	}
 
-		drm_object_attach_property(&connector->base,
-				dev->mode_config.scaling_mode_property,
-				nv_connector->scaling_mode);
+	/* scaling mode property */
+	switch (nv_connector->type) {
+	case DCB_CONNECTOR_TV_0:
+	case DCB_CONNECTOR_TV_1:
+	case DCB_CONNECTOR_TV_3:
+		break;
+	case DCB_CONNECTOR_VGA:
+		if (disp->disp.oclass < NV50_DISP)
+			break; /* can only scale on DFPs */
+		/* fall-through */
+	default:
+		drm_object_attach_property(&connector->base, dev->mode_config.
+					   scaling_mode_property,
+					   nv_connector->scaling_mode);
+		break;
+	}
+
+	/* dithering properties */
+	switch (nv_connector->type) {
+	case DCB_CONNECTOR_TV_0:
+	case DCB_CONNECTOR_TV_1:
+	case DCB_CONNECTOR_TV_3:
+	case DCB_CONNECTOR_VGA:
+		break;
+	default:
 		if (disp->dithering_mode) {
-			nv_connector->dithering_mode = DITHERING_MODE_AUTO;
 			drm_object_attach_property(&connector->base,
-						disp->dithering_mode,
-						nv_connector->dithering_mode);
+						   disp->dithering_mode,
+						   nv_connector->
+						   dithering_mode);
+			nv_connector->dithering_mode = DITHERING_MODE_AUTO;
 		}
 		if (disp->dithering_depth) {
-			nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
 			drm_object_attach_property(&connector->base,
-						disp->dithering_depth,
-						nv_connector->dithering_depth);
+						   disp->dithering_depth,
+						   nv_connector->
+						   dithering_depth);
+			nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
 		}
 		break;
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 629a380..7446ee6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -33,7 +33,7 @@
 #include <drm/drm_dp_helper.h>
 #include "nouveau_crtc.h"
 
-struct nouveau_i2c_port;
+struct nvkm_i2c_port;
 
 enum nouveau_underscan_type {
 	UNDERSCAN_OFF,
@@ -72,6 +72,7 @@
 	int dithering_mode;
 	int dithering_depth;
 	int scaling_mode;
+	bool scaling_full;
 	enum nouveau_underscan_type underscan;
 	u32 underscan_hborder;
 	u32 underscan_vborder;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index f804243..860b0e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -450,7 +450,7 @@
 	drm_mode_create_dvi_i_properties(dev);
 
 	dev->mode_config.funcs = &nouveau_mode_config_funcs;
-	dev->mode_config.fb_base = nv_device_resource_start(nvkm_device(&drm->device), 1);
+	dev->mode_config.fb_base = nv_device_resource_start(nvxx_device(&drm->device), 1);
 
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
@@ -570,7 +570,8 @@
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 		if (nv_crtc->cursor.nvbo) {
-			nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+			if (nv_crtc->cursor.set_offset)
+				nouveau_bo_unmap(nv_crtc->cursor.nvbo);
 			nouveau_bo_unpin(nv_crtc->cursor.nvbo);
 		}
 	}
@@ -604,7 +605,7 @@
 			continue;
 
 		ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
-		if (!ret)
+		if (!ret && nv_crtc->cursor.set_offset)
 			ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
 		if (ret)
 			NV_ERROR(drm, "Could not pin/map cursor.\n");
@@ -637,7 +638,9 @@
 
 		if (!nv_crtc->cursor.nvbo)
 			continue;
-		nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
+
+		if (nv_crtc->cursor.set_offset)
+			nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
 		nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
 						 nv_crtc->cursor_saved_y);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index be3d594..a6213e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -1,14 +1,14 @@
 #ifndef __NOUVEAU_DISPLAY_H__
 #define __NOUVEAU_DISPLAY_H__
 
-#include <subdev/vm.h>
+#include <subdev/mmu.h>
 
 #include "nouveau_drm.h"
 
 struct nouveau_framebuffer {
 	struct drm_framebuffer base;
 	struct nouveau_bo *nvbo;
-	struct nouveau_vma vma;
+	struct nvkm_vma vma;
 	u32 r_handle;
 	u32 r_format;
 	u32 r_pitch;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 8508603..6d9245a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -84,7 +84,7 @@
 {
 	struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base);
 	struct nouveau_bo *pb = chan->push.buffer;
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 	int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
 	u64 offset;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c5137cc..c3ef30b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -31,7 +31,7 @@
 #include "nouveau_crtc.h"
 
 static void
-nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
+nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch,
 		     u8 *dpcd)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
@@ -55,7 +55,7 @@
 {
 	struct drm_device *dev = nv_encoder->base.base.dev;
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_i2c_port *auxch;
+	struct nvkm_i2c_port *auxch;
 	u8 *dpcd = nv_encoder->dp.dpcd;
 	int ret;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 65910e3..8763deb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -52,6 +52,7 @@
 #include "nouveau_debugfs.h"
 #include "nouveau_usif.h"
 #include "nouveau_connector.h"
+#include "nouveau_platform.h"
 
 MODULE_PARM_DESC(config, "option string to pass to driver core");
 static char *nouveau_config;
@@ -123,7 +124,7 @@
 static void
 nouveau_cli_destroy(struct nouveau_cli *cli)
 {
-	nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL);
+	nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
 	nvif_client_fini(&cli->base);
 	usif_client_fini(cli);
 }
@@ -133,7 +134,7 @@
 {
 	nouveau_channel_del(&drm->channel);
 	nvif_object_fini(&drm->ntfy);
-	nouveau_gpuobj_ref(NULL, &drm->notify);
+	nvkm_gpuobj_ref(NULL, &drm->notify);
 	nvif_object_fini(&drm->nvsw);
 	nouveau_channel_del(&drm->cechan);
 	nvif_object_fini(&drm->ttm.copy);
@@ -230,7 +231,7 @@
 	ret = nvif_object_init(drm->channel->object, NULL, NVDRM_NVSW,
 			       nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw);
 	if (ret == 0) {
-		struct nouveau_software_chan *swch;
+		struct nvkm_sw_chan *swch;
 		ret = RING_SPACE(drm->channel, 2);
 		if (ret == 0) {
 			if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
@@ -242,7 +243,7 @@
 				OUT_RING  (drm->channel, 0x001f0000);
 			}
 		}
-		swch = (void *)nvkm_object(&drm->nvsw)->parent;
+		swch = (void *)nvxx_object(&drm->nvsw)->parent;
 		swch->flip = nouveau_flip_complete;
 		swch->flip_data = drm->channel;
 	}
@@ -254,8 +255,8 @@
 	}
 
 	if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
-		ret = nouveau_gpuobj_new(nvkm_object(&drm->device), NULL, 32,
-					 0, 0, &drm->notify);
+		ret = nvkm_gpuobj_new(nvxx_object(&drm->device), NULL, 32,
+				      0, 0, &drm->notify);
 		if (ret) {
 			NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
 			nouveau_accel_fini(drm);
@@ -284,7 +285,7 @@
 static int nouveau_drm_probe(struct pci_dev *pdev,
 			     const struct pci_device_id *pent)
 {
-	struct nouveau_device *device;
+	struct nvkm_device *device;
 	struct apertures_struct *aper;
 	bool boot = false;
 	int ret;
@@ -317,9 +318,9 @@
 		remove_conflicting_framebuffers(aper, "nouveaufb", boot);
 	kfree(aper);
 
-	ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI,
-				    nouveau_pci_name(pdev), pci_name(pdev),
-				    nouveau_config, nouveau_debug, &device);
+	ret = nvkm_device_create(pdev, NVKM_BUS_PCI,
+				 nouveau_pci_name(pdev), pci_name(pdev),
+				 nouveau_config, nouveau_debug, &device);
 	if (ret)
 		return ret;
 
@@ -327,7 +328,7 @@
 
 	ret = drm_get_pci_dev(pdev, pent, &driver_pci);
 	if (ret) {
-		nouveau_object_ref(NULL, (struct nouveau_object **)&device);
+		nvkm_object_ref(NULL, (struct nvkm_object **)&device);
 		return ret;
 	}
 
@@ -378,8 +379,8 @@
 
 	dev->dev_private = drm;
 	drm->dev = dev;
-	nvkm_client(&drm->client.base)->debug =
-		nouveau_dbgopt(nouveau_debug, "DRM");
+	nvxx_client(&drm->client.base)->debug =
+		nvkm_dbgopt(nouveau_debug, "DRM");
 
 	INIT_LIST_HEAD(&drm->clients);
 	spin_lock_init(&drm->tile.lock);
@@ -434,12 +435,12 @@
 	nouveau_agp_init(drm);
 
 	if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-		ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),
-				     0x1000, &drm->client.vm);
+		ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
+				  0x1000, &drm->client.vm);
 		if (ret)
 			goto fail_device;
 
-		nvkm_client(&drm->client.base)->vm = drm->client.vm;
+		nvxx_client(&drm->client.base)->vm = drm->client.vm;
 	}
 
 	ret = nouveau_ttm_init(drm);
@@ -522,18 +523,17 @@
 nouveau_drm_device_remove(struct drm_device *dev)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_client *client;
-	struct nouveau_object *device;
+	struct nvkm_client *client;
+	struct nvkm_object *device;
 
 	dev->irq_enabled = false;
-	client = nvkm_client(&drm->client.base);
+	client = nvxx_client(&drm->client.base);
 	device = client->device;
 	drm_put_dev(dev);
 
-	nouveau_object_ref(NULL, &device);
-	nouveau_object_debug();
+	nvkm_object_ref(NULL, &device);
+	nvkm_object_debug();
 }
-EXPORT_SYMBOL(nouveau_drm_device_remove);
 
 static void
 nouveau_drm_remove(struct pci_dev *pdev)
@@ -831,14 +831,14 @@
 	cli->base.super = false;
 
 	if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-		ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),
-				     0x1000, &cli->vm);
+		ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
+				  0x1000, &cli->vm);
 		if (ret) {
 			nouveau_cli_destroy(cli);
 			goto out_suspend;
 		}
 
-		nvkm_client(&cli->base)->vm = cli->vm;
+		nvxx_client(&cli->base)->vm = cli->vm;
 	}
 
 	fpriv->driver_priv = cli;
@@ -1056,10 +1056,10 @@
 	struct drm_device *drm;
 	int err;
 
-	err = nouveau_device_create_(pdev, NOUVEAU_BUS_PLATFORM,
-				    nouveau_platform_name(pdev),
-				    dev_name(&pdev->dev), nouveau_config,
-				    nouveau_debug, size, pobject);
+	err = nvkm_device_create_(pdev, NVKM_BUS_PLATFORM,
+				  nouveau_platform_name(pdev),
+				  dev_name(&pdev->dev), nouveau_config,
+				  nouveau_debug, size, pobject);
 	if (err)
 		return ERR_PTR(err);
 
@@ -1079,11 +1079,10 @@
 	return drm;
 
 err_free:
-	nouveau_object_ref(NULL, (struct nouveau_object **)pobject);
+	nvkm_object_ref(NULL, (struct nvkm_object **)pobject);
 
 	return ERR_PTR(err);
 }
-EXPORT_SYMBOL(nouveau_platform_device_create_);
 
 static int __init
 nouveau_drm_init(void)
@@ -1105,6 +1104,10 @@
 	if (!nouveau_modeset)
 		return 0;
 
+#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
+	platform_driver_register(&nouveau_platform_driver);
+#endif
+
 	nouveau_register_dsm_handler();
 	return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver);
 }
@@ -1117,6 +1120,10 @@
 
 	drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver);
 	nouveau_unregister_dsm_handler();
+
+#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
+	platform_driver_unregister(&nouveau_platform_driver);
+#endif
 }
 
 module_init(nouveau_drm_init);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 8ae36f2..fc68f09 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -80,7 +80,7 @@
 
 struct nouveau_cli {
 	struct nvif_client base;
-	struct nouveau_vm *vm; /*XXX*/
+	struct nvkm_vm *vm; /*XXX*/
 	struct list_head head;
 	struct mutex mutex;
 	void *abi16;
@@ -142,7 +142,7 @@
 	/* context for accelerated drm-internal operations */
 	struct nouveau_channel *cechan;
 	struct nouveau_channel *channel;
-	struct nouveau_gpuobj *notify;
+	struct nvkm_gpuobj *notify;
 	struct nouveau_fbdev *fbcon;
 	struct nvif_object nvsw;
 	struct nvif_object ntfy;
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index 5f0e37f..c57a37e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -34,14 +34,14 @@
 
 #define NV_DPMS_CLEARED 0x80
 
-struct nouveau_i2c_port;
+struct nvkm_i2c_port;
 
 struct nouveau_encoder {
 	struct drm_encoder_slave base;
 
 	struct dcb_output *dcb;
 	int or;
-	struct nouveau_i2c_port *i2c;
+	struct nvkm_i2c_port *i2c;
 
 	/* different to drm_encoder.crtc, this reflects what's
 	 * actually programmed on the hw, not the proposed crtc */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 3ed12a8..79924e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -370,6 +370,7 @@
 		ret = -ENOMEM;
 		goto out_unlock;
 	}
+	info->skip_vt_switch = 1;
 
 	ret = fb_alloc_cmap(&info->cmap, 256, 0);
 	if (ret) {
@@ -487,30 +488,17 @@
 	.fb_probe = nouveau_fbcon_create,
 };
 
-static void
-nouveau_fbcon_set_suspend_work(struct work_struct *work)
-{
-	struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work);
-	console_lock();
-	nouveau_fbcon_accel_restore(fbcon->dev);
-	nouveau_fbcon_zfill(fbcon->dev, fbcon);
-	fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING);
-	console_unlock();
-}
-
 void
 nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	if (drm->fbcon) {
-		if (state == FBINFO_STATE_RUNNING) {
-			schedule_work(&drm->fbcon->work);
-			return;
-		}
-		flush_work(&drm->fbcon->work);
 		console_lock();
+		if (state == FBINFO_STATE_RUNNING)
+			nouveau_fbcon_accel_restore(dev);
 		fb_set_suspend(drm->fbcon->helper.fbdev, state);
-		nouveau_fbcon_accel_save_disable(dev);
+		if (state != FBINFO_STATE_RUNNING)
+			nouveau_fbcon_accel_save_disable(dev);
 		console_unlock();
 	}
 }
@@ -531,7 +519,6 @@
 	if (!fbcon)
 		return -ENOMEM;
 
-	INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work);
 	fbcon->dev = dev;
 	drm->fbcon = fbcon;
 
@@ -539,12 +526,12 @@
 
 	ret = drm_fb_helper_init(dev, &fbcon->helper,
 				 dev->mode_config.num_crtc, 4);
-	if (ret) {
-		kfree(fbcon);
-		return ret;
-	}
+	if (ret)
+		goto free;
 
-	drm_fb_helper_single_add_all_connectors(&fbcon->helper);
+	ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper);
+	if (ret)
+		goto fini;
 
 	if (drm->device.info.ram_size <= 32 * 1024 * 1024)
 		preferred_bpp = 8;
@@ -557,8 +544,17 @@
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(dev);
 
-	drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
+	ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&fbcon->helper);
+free:
+	kfree(fbcon);
+	return ret;
 }
 
 void
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 6208e70..1e2e9e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -36,7 +36,6 @@
 	struct nouveau_framebuffer nouveau_fb;
 	struct list_head fbdev_list;
 	struct drm_device *dev;
-	struct work_struct work;
 	unsigned int saved_flags;
 	struct nvif_object surf2d;
 	struct nvif_object clip;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index f32a434..c6d56be 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -182,7 +182,7 @@
 	else if (chan == chan->drm->channel)
 		strcpy(fctx->name, "generic kernel channel");
 	else
-		strcpy(fctx->name, nvkm_client(&cli->base)->name);
+		strcpy(fctx->name, nvxx_client(&cli->base)->name);
 
 	kref_init(&fctx->fence_ref);
 	if (!priv->uevent)
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index 96e461c..d9241d8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -89,9 +89,9 @@
 
 struct nv84_fence_chan {
 	struct nouveau_fence_chan base;
-	struct nouveau_vma vma;
-	struct nouveau_vma vma_gart;
-	struct nouveau_vma dispc_vma[4];
+	struct nvkm_vma vma;
+	struct nvkm_vma vma_gart;
+	struct nvkm_vma dispc_vma[4];
 };
 
 struct nv84_fence_priv {
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index bf0f9e21d..7c077fc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -64,7 +64,7 @@
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 	struct device *dev = drm->dev->dev;
 	int ret;
 
@@ -105,14 +105,14 @@
 static void
 nouveau_gem_object_delete(void *data)
 {
-	struct nouveau_vma *vma = data;
-	nouveau_vm_unmap(vma);
-	nouveau_vm_put(vma);
+	struct nvkm_vma *vma = data;
+	nvkm_vm_unmap(vma);
+	nvkm_vm_put(vma);
 	kfree(vma);
 }
 
 static void
-nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
 {
 	const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
 	struct reservation_object *resv = nvbo->bo.resv;
@@ -135,8 +135,8 @@
 		nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
 	} else {
 		if (mapped)
-			nouveau_vm_unmap(vma);
-		nouveau_vm_put(vma);
+			nvkm_vm_unmap(vma);
+		nvkm_vm_put(vma);
 		kfree(vma);
 	}
 }
@@ -148,7 +148,7 @@
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct device *dev = drm->dev->dev;
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 	int ret;
 
 	if (!cli->vm)
@@ -222,7 +222,7 @@
 {
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
 	struct nouveau_bo *nvbo = nouveau_gem_object(gem);
-	struct nouveau_vma *vma;
+	struct nvkm_vma *vma;
 
 	if (nvbo->bo.mem.mem_type == TTM_PL_TT)
 		rep->domain = NOUVEAU_GEM_DOMAIN_GART;
@@ -251,7 +251,7 @@
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	struct nouveau_cli *cli = nouveau_cli(file_priv);
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
 	struct drm_nouveau_gem_new *req = data;
 	struct nouveau_bo *nvbo = NULL;
 	int ret = 0;
@@ -850,19 +850,6 @@
 	return nouveau_abi16_put(abi16, ret);
 }
 
-static inline uint32_t
-domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
-{
-	uint32_t flags = 0;
-
-	if (domain & NOUVEAU_GEM_DOMAIN_VRAM)
-		flags |= TTM_PL_FLAG_VRAM;
-	if (domain & NOUVEAU_GEM_DOMAIN_GART)
-		flags |= TTM_PL_FLAG_TT;
-
-	return flags;
-}
-
 int
 nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
 			   struct drm_file *file_priv)
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
index afb36d6..0dbe006 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
@@ -40,7 +40,7 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int temp = therm->temp_get(therm);
 
 	if (temp < 0)
@@ -66,10 +66,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	      therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000);
+	      therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
@@ -78,13 +78,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST,
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST,
 			value / 1000);
 
 	return count;
@@ -99,10 +99,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	 therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
+	 therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
@@ -111,13 +111,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST,
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST,
 			value / 1000);
 
 	return count;
@@ -131,10 +131,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	       therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
+	       therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
@@ -142,13 +142,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
 
 	return count;
 }
@@ -162,10 +162,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	  therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
+	  therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
@@ -173,13 +173,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST,
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST,
 			value / 1000);
 
 	return count;
@@ -194,10 +194,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	       therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
+	       therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
@@ -206,13 +206,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000);
 
 	return count;
 }
@@ -227,10 +227,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	  therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
+	  therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_critical_temp_hyst(struct device *d,
@@ -240,13 +240,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST,
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST,
 			value / 1000);
 
 	return count;
@@ -260,10 +260,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	       therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000);
+	       therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
@@ -272,13 +272,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
 
 	return count;
 }
@@ -293,10 +293,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n",
-	  therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
+	  therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
 }
 static ssize_t
 nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
@@ -306,13 +306,13 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return count;
 
-	therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST,
+	therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST,
 			value / 1000);
 
 	return count;
@@ -346,7 +346,7 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
 }
@@ -359,10 +359,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int ret;
 
-	ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
+	ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);
 	if (ret < 0)
 		return ret;
 
@@ -375,7 +375,7 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 	int ret;
 
@@ -383,7 +383,7 @@
 	if (ret)
 		return ret;
 
-	ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
+	ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value);
 	if (ret)
 		return ret;
 	else
@@ -398,7 +398,7 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int ret;
 
 	ret = therm->fan_get(therm);
@@ -414,7 +414,7 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int ret = -ENODEV;
 	long value;
 
@@ -438,10 +438,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int ret;
 
-	ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
+	ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY);
 	if (ret < 0)
 		return ret;
 
@@ -454,14 +454,14 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 	int ret;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return -EINVAL;
 
-	ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
+	ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value);
 	if (ret < 0)
 		return ret;
 
@@ -478,10 +478,10 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	int ret;
 
-	ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
+	ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY);
 	if (ret < 0)
 		return ret;
 
@@ -494,14 +494,14 @@
 {
 	struct drm_device *dev = dev_get_drvdata(d);
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	long value;
 	int ret;
 
 	if (kstrtol(buf, 10, &value) == -EINVAL)
 		return -EINVAL;
 
-	ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
+	ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value);
 	if (ret < 0)
 		return ret;
 
@@ -561,7 +561,7 @@
 {
 #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
 	struct nouveau_drm *drm = nouveau_drm(dev);
-	struct nouveau_therm *therm = nvkm_therm(&drm->device);
+	struct nvkm_therm *therm = nvxx_therm(&drm->device);
 	struct nouveau_hwmon *hwmon;
 	struct device *hwmon_dev;
 	int ret = 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c
index 6544b84..ca0ad9d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_nvif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c
@@ -60,22 +60,22 @@
 static int
 nvkm_client_resume(void *priv)
 {
-	return nouveau_client_init(priv);
+	return nvkm_client_init(priv);
 }
 
 static int
 nvkm_client_suspend(void *priv)
 {
-	return nouveau_client_fini(priv, true);
+	return nvkm_client_fini(priv, true);
 }
 
 static void
-nvkm_client_fini(void *priv)
+nvkm_client_driver_fini(void *priv)
 {
-	struct nouveau_object *client = priv;
-	nouveau_client_fini(nv_client(client), false);
+	struct nvkm_object *client = priv;
+	nvkm_client_fini(nv_client(client), false);
 	atomic_set(&client->refcount, 1);
-	nouveau_object_ref(NULL, &client);
+	nvkm_object_ref(NULL, &client);
 }
 
 static int
@@ -107,13 +107,13 @@
 }
 
 static int
-nvkm_client_init(const char *name, u64 device, const char *cfg,
-		 const char *dbg, void **ppriv)
+nvkm_client_driver_init(const char *name, u64 device, const char *cfg,
+			const char *dbg, void **ppriv)
 {
-	struct nouveau_client *client;
+	struct nvkm_client *client;
 	int ret;
 
-	ret = nouveau_client_create(name, device, cfg, dbg, &client);
+	ret = nvkm_client_create(name, device, cfg, dbg, &client);
 	*ppriv = client;
 	if (ret)
 		return ret;
@@ -125,8 +125,8 @@
 const struct nvif_driver
 nvif_driver_nvkm = {
 	.name = "nvkm",
-	.init = nvkm_client_init,
-	.fini = nvkm_client_fini,
+	.init = nvkm_client_driver_init,
+	.fini = nvkm_client_driver_fini,
 	.suspend = nvkm_client_suspend,
 	.resume = nvkm_client_resume,
 	.ioctl = nvkm_client_ioctl,
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c
index b307bbe..dc5900b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.c
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.c
@@ -152,7 +152,7 @@
 {
 	struct drm_device *drm_dev = platform_get_drvdata(pdev);
 	struct nouveau_drm *drm = nouveau_drm(drm_dev);
-	struct nouveau_device *device = nvkm_device(&drm->device);
+	struct nvkm_device *device = nvxx_device(&drm->device);
 	struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
 
 	nouveau_drm_device_remove(drm_dev);
@@ -177,9 +177,3 @@
 	.probe = nouveau_platform_probe,
 	.remove = nouveau_platform_remove,
 };
-
-module_platform_driver(nouveau_platform_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.h b/drivers/gpu/drm/nouveau/nouveau_platform.h
index 58c28b5..268bb72 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.h
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.h
@@ -28,6 +28,7 @@
 struct reset_control;
 struct clk;
 struct regulator;
+struct platform_driver;
 
 struct nouveau_platform_gpu {
 	struct reset_control *rst;
@@ -38,7 +39,7 @@
 };
 
 struct nouveau_platform_device {
-	struct nouveau_device device;
+	struct nvkm_device device;
 
 	struct nouveau_platform_gpu *gpu;
 
@@ -48,4 +49,6 @@
 #define nv_device_to_platform(d)                                               \
 	container_of(d, struct nouveau_platform_device, device)
 
+extern struct platform_driver nouveau_platform_driver;
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b9..7226f1f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -72,7 +72,7 @@
 #    define NV_RAMHT_CONTEXT_VALID                         (1<<31)
 #    define NV_RAMHT_CONTEXT_CHANNEL_SHIFT                 24
 #    define NV_RAMHT_CONTEXT_ENGINE_SHIFT                  16
-#        define NV_RAMHT_CONTEXT_ENGINE_SOFTWARE           0
+#        define NV_RAMHT_CONTEXT_ENGINE_SW           0
 #        define NV_RAMHT_CONTEXT_ENGINE_GRAPHICS           1
 #    define NV_RAMHT_CONTEXT_INSTANCE_SHIFT                0
 #    define NV40_RAMHT_CONTEXT_CHANNEL_SHIFT               23
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 01707e7..8c3053a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -9,8 +9,7 @@
 	 * nouve_bo.c works properly, otherwise have to move them here
 	 */
 	struct ttm_dma_tt ttm;
-	struct drm_device *dev;
-	struct nouveau_mem *node;
+	struct nvkm_mem *node;
 };
 
 static void
@@ -28,7 +27,7 @@
 nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
 {
 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
-	struct nouveau_mem *node = mem->mm_node;
+	struct nvkm_mem *node = mem->mm_node;
 
 	if (ttm->sg) {
 		node->sg    = ttm->sg;
@@ -39,7 +38,7 @@
 	}
 	node->size = (mem->num_pages << PAGE_SHIFT) >> 12;
 
-	nouveau_vm_map(&node->vma[0], node);
+	nvkm_vm_map(&node->vma[0], node);
 	nvbe->node = node;
 	return 0;
 }
@@ -48,7 +47,7 @@
 nv04_sgdma_unbind(struct ttm_tt *ttm)
 {
 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
-	nouveau_vm_unmap(&nvbe->node->vma[0]);
+	nvkm_vm_unmap(&nvbe->node->vma[0]);
 	return 0;
 }
 
@@ -62,7 +61,7 @@
 nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
 {
 	struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
-	struct nouveau_mem *node = mem->mm_node;
+	struct nvkm_mem *node = mem->mm_node;
 
 	/* noop: bound in move_notify() */
 	if (ttm->sg) {
@@ -101,13 +100,17 @@
 	if (!nvbe)
 		return NULL;
 
-	nvbe->dev = drm->dev;
 	if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA)
 		nvbe->ttm.ttm.func = &nv04_sgdma_backend;
 	else
 		nvbe->ttm.ttm.func = &nv50_sgdma_backend;
 
 	if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page))
+		/*
+		 * A failing ttm_dma_tt_init() will call ttm_tt_destroy()
+		 * and thus our nouveau_sgdma_destroy() hook, so we don't need
+		 * to free nvbe here.
+		 */
 		return NULL;
 	return &nvbe->ttm.ttm;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
index 8fbbf30..1ec8f38 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
@@ -165,7 +165,7 @@
 	struct nvif_device *device = &drm->device;
 
 	if (sysfs && sysfs->ctrl.priv) {
-		device_remove_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate);
+		device_remove_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate);
 		nvif_object_fini(&sysfs->ctrl);
 	}
 
@@ -192,7 +192,7 @@
 			       NVIF_IOCTL_NEW_V0_CONTROL, NULL, 0,
 			      &sysfs->ctrl);
 	if (ret == 0)
-		device_create_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate);
+		device_create_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 3d1cfcb..273e501 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -33,7 +33,7 @@
 nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
 	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
 	man->priv = pfb;
 	return 0;
 }
@@ -46,16 +46,16 @@
 }
 
 static inline void
-nouveau_mem_node_cleanup(struct nouveau_mem *node)
+nvkm_mem_node_cleanup(struct nvkm_mem *node)
 {
 	if (node->vma[0].node) {
-		nouveau_vm_unmap(&node->vma[0]);
-		nouveau_vm_put(&node->vma[0]);
+		nvkm_vm_unmap(&node->vma[0]);
+		nvkm_vm_put(&node->vma[0]);
 	}
 
 	if (node->vma[1].node) {
-		nouveau_vm_unmap(&node->vma[1]);
-		nouveau_vm_put(&node->vma[1]);
+		nvkm_vm_unmap(&node->vma[1]);
+		nvkm_vm_put(&node->vma[1]);
 	}
 }
 
@@ -64,9 +64,9 @@
 			 struct ttm_mem_reg *mem)
 {
 	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
-	nouveau_mem_node_cleanup(mem->mm_node);
-	pfb->ram->put(pfb, (struct nouveau_mem **)&mem->mm_node);
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
+	nvkm_mem_node_cleanup(mem->mm_node);
+	pfb->ram->put(pfb, (struct nvkm_mem **)&mem->mm_node);
 }
 
 static int
@@ -76,9 +76,9 @@
 			 struct ttm_mem_reg *mem)
 {
 	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
-	struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+	struct nvkm_fb *pfb = nvxx_fb(&drm->device);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
-	struct nouveau_mem *node;
+	struct nvkm_mem *node;
 	u32 size_nc = 0;
 	int ret;
 
@@ -103,9 +103,9 @@
 static void
 nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
 {
-	struct nouveau_fb *pfb = man->priv;
-	struct nouveau_mm *mm = &pfb->vram;
-	struct nouveau_mm_node *r;
+	struct nvkm_fb *pfb = man->priv;
+	struct nvkm_mm *mm = &pfb->vram;
+	struct nvkm_mm_node *r;
 	u32 total = 0, free = 0;
 
 	mutex_lock(&nv_subdev(pfb)->mutex);
@@ -150,7 +150,7 @@
 nouveau_gart_manager_del(struct ttm_mem_type_manager *man,
 			 struct ttm_mem_reg *mem)
 {
-	nouveau_mem_node_cleanup(mem->mm_node);
+	nvkm_mem_node_cleanup(mem->mm_node);
 	kfree(mem->mm_node);
 	mem->mm_node = NULL;
 }
@@ -163,7 +163,7 @@
 {
 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
-	struct nouveau_mem *node;
+	struct nvkm_mem *node;
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
 	if (!node)
@@ -203,15 +203,15 @@
 };
 
 /*XXX*/
-#include <core/subdev/vm/nv04.h>
+#include <subdev/mmu/nv04.h>
 static int
 nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
 	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
-	struct nouveau_vmmgr *vmm = nvkm_vmmgr(&drm->device);
-	struct nv04_vmmgr_priv *priv = (void *)vmm;
-	struct nouveau_vm *vm = NULL;
-	nouveau_vm_ref(priv->vm, &vm, NULL);
+	struct nvkm_mmu *mmu = nvxx_mmu(&drm->device);
+	struct nv04_mmu_priv *priv = (void *)mmu;
+	struct nvkm_vm *vm = NULL;
+	nvkm_vm_ref(priv->vm, &vm, NULL);
 	man->priv = vm;
 	return 0;
 }
@@ -219,8 +219,8 @@
 static int
 nv04_gart_manager_fini(struct ttm_mem_type_manager *man)
 {
-	struct nouveau_vm *vm = man->priv;
-	nouveau_vm_ref(NULL, &vm, NULL);
+	struct nvkm_vm *vm = man->priv;
+	nvkm_vm_ref(NULL, &vm, NULL);
 	man->priv = NULL;
 	return 0;
 }
@@ -228,9 +228,9 @@
 static void
 nv04_gart_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem)
 {
-	struct nouveau_mem *node = mem->mm_node;
+	struct nvkm_mem *node = mem->mm_node;
 	if (node->vma[0].node)
-		nouveau_vm_put(&node->vma[0]);
+		nvkm_vm_put(&node->vma[0]);
 	kfree(mem->mm_node);
 	mem->mm_node = NULL;
 }
@@ -241,7 +241,7 @@
 		      const struct ttm_place *place,
 		      struct ttm_mem_reg *mem)
 {
-	struct nouveau_mem *node;
+	struct nvkm_mem *node;
 	int ret;
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
@@ -250,8 +250,8 @@
 
 	node->page_shift = 12;
 
-	ret = nouveau_vm_get(man->priv, mem->num_pages << 12, node->page_shift,
-			     NV_MEM_ACCESS_RW, &node->vma[0]);
+	ret = nvkm_vm_get(man->priv, mem->num_pages << 12, node->page_shift,
+			  NV_MEM_ACCESS_RW, &node->vma[0]);
 	if (ret) {
 		kfree(node);
 		return ret;
@@ -354,8 +354,8 @@
 	u32 bits;
 	int ret;
 
-	bits = nvkm_vmmgr(&drm->device)->dma_bits;
-	if (nv_device_is_pci(nvkm_device(&drm->device))) {
+	bits = nvxx_mmu(&drm->device)->dma_bits;
+	if (nv_device_is_pci(nvxx_device(&drm->device))) {
 		if (drm->agp.stat == ENABLED ||
 		     !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
 			bits = 32;
@@ -396,12 +396,12 @@
 		return ret;
 	}
 
-	drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvkm_device(&drm->device), 1),
-					 nv_device_resource_len(nvkm_device(&drm->device), 1));
+	drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvxx_device(&drm->device), 1),
+					 nv_device_resource_len(nvxx_device(&drm->device), 1));
 
 	/* GART init */
 	if (drm->agp.stat != ENABLED) {
-		drm->gem.gart_available = nvkm_vmmgr(&drm->device)->limit;
+		drm->gem.gart_available = nvxx_mmu(&drm->device)->limit;
 	} else {
 		drm->gem.gart_available = drm->agp.size;
 	}
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c
index f9859de..c2e05e6 100644
--- a/drivers/gpu/drm/nouveau/nv04_fence.c
+++ b/drivers/gpu/drm/nouveau/nv04_fence.c
@@ -57,7 +57,7 @@
 static u32
 nv04_fence_read(struct nouveau_channel *chan)
 {
-	struct nouveau_fifo_chan *fifo = nvkm_fifo_chan(chan);;
+	struct nvkm_fifo_chan *fifo = nvxx_fifo_chan(chan);;
 	return atomic_read(&fifo->refcnt);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 490b908..7da7958 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -125,7 +125,6 @@
 
 struct nv50_curs {
 	struct nv50_pioc base;
-	struct nouveau_bo *image;
 };
 
 static int
@@ -201,7 +200,7 @@
 	nv50_chan_destroy(&dmac->base);
 
 	if (dmac->ptr) {
-		struct pci_dev *pdev = nvkm_device(nvif_device(disp))->pdev;
+		struct pci_dev *pdev = nvxx_device(nvif_device(disp))->pdev;
 		pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
 	}
 }
@@ -218,7 +217,7 @@
 
 	mutex_init(&dmac->lock);
 
-	dmac->ptr = pci_alloc_consistent(nvkm_device(device)->pdev,
+	dmac->ptr = pci_alloc_consistent(nvxx_device(device)->pdev,
 					 PAGE_SIZE, &dmac->handle);
 	if (!dmac->ptr)
 		return -ENOMEM;
@@ -421,9 +420,9 @@
 		dmac->ptr[put] = 0x20000000;
 
 		nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
-		if (!nvkm_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
+		if (!nvxx_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
 			mutex_unlock(&dmac->lock);
-			nv_error(nvkm_object(&dmac->base.user), "channel stalled\n");
+			nv_error(nvxx_object(&dmac->base.user), "channel stalled\n");
 			return NULL;
 		}
 
@@ -481,7 +480,7 @@
 		evo_data(push, 0x00000000);
 		evo_data(push, 0x00000000);
 		evo_kick(push, mast);
-		if (nv_wait_cb(nvkm_device(device), evo_sync_wait, disp->sync))
+		if (nv_wait_cb(nvxx_device(device), evo_sync_wait, disp->sync))
 			return 0;
 	}
 
@@ -536,7 +535,7 @@
 		evo_kick(push, flip.chan);
 	}
 
-	nv_wait_cb(nvkm_device(device), nv50_display_flip_wait, &flip);
+	nv_wait_cb(nvxx_device(device), nv50_display_flip_wait, &flip);
 }
 
 int
@@ -550,6 +549,10 @@
 	u32 *push;
 	int ret;
 
+	if (crtc->primary->fb->width != fb->width ||
+	    crtc->primary->fb->height != fb->height)
+		return -EINVAL;
+
 	swap_interval <<= 4;
 	if (swap_interval == 0)
 		swap_interval |= 0x100;
@@ -729,8 +732,11 @@
 	 * effectively handles NONE/FULL scaling
 	 */
 	nv_connector = nouveau_crtc_connector_get(nv_crtc);
-	if (nv_connector && nv_connector->native_mode)
+	if (nv_connector && nv_connector->native_mode) {
 		mode = nv_connector->scaling_mode;
+		if (nv_connector->scaling_full) /* non-EDID LVDS/eDP mode */
+			mode = DRM_MODE_SCALE_FULLSCREEN;
+	}
 
 	if (mode != DRM_MODE_SCALE_NONE)
 		omode = nv_connector->native_mode;
@@ -917,29 +923,29 @@
 nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
 {
 	struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
-	struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
 	u32 *push = evo_wait(mast, 16);
 	if (push) {
 		if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
 			evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
 			evo_data(push, 0x85000000);
-			evo_data(push, curs->image->bo.offset >> 8);
+			evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
 		} else
 		if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
 			evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
 			evo_data(push, 0x85000000);
-			evo_data(push, curs->image->bo.offset >> 8);
+			evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
 			evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
 			evo_data(push, mast->base.vram.handle);
 		} else {
 			evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
 			evo_data(push, 0x85000000);
-			evo_data(push, curs->image->bo.offset >> 8);
+			evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
 			evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
 			evo_data(push, mast->base.vram.handle);
 		}
 		evo_kick(push, mast);
 	}
+	nv_crtc->cursor.visible = true;
 }
 
 static void
@@ -965,15 +971,15 @@
 		}
 		evo_kick(push, mast);
 	}
+	nv_crtc->cursor.visible = false;
 }
 
 static void
 nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
 {
 	struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
-	struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
 
-	if (show && curs->image)
+	if (show && nv_crtc->cursor.nvbo)
 		nv50_crtc_cursor_show(nv_crtc);
 	else
 		nv50_crtc_cursor_hide(nv_crtc);
@@ -1273,7 +1279,6 @@
 		     uint32_t handle, uint32_t width, uint32_t height)
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-	struct nv50_curs *curs = nv50_curs(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct drm_gem_object *gem = NULL;
 	struct nouveau_bo *nvbo = NULL;
@@ -1292,9 +1297,9 @@
 	}
 
 	if (ret == 0) {
-		if (curs->image)
-			nouveau_bo_unpin(curs->image);
-		nouveau_bo_ref(nvbo, &curs->image);
+		if (nv_crtc->cursor.nvbo)
+			nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+		nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo);
 	}
 	drm_gem_object_unreference_unlocked(gem);
 
@@ -1305,10 +1310,14 @@
 static int
 nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
+	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nv50_curs *curs = nv50_curs(crtc);
 	struct nv50_chan *chan = nv50_chan(curs);
 	nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
 	nvif_wr32(&chan->user, 0x0080, 0x00000000);
+
+	nv_crtc->cursor_saved_x = x;
+	nv_crtc->cursor_saved_y = y;
 	return 0;
 }
 
@@ -1330,6 +1339,14 @@
 }
 
 static void
+nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y)
+{
+	nv50_crtc_cursor_move(&nv_crtc->base, x, y);
+
+	nv50_crtc_cursor_show_hide(nv_crtc, true, true);
+}
+
+static void
 nv50_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -1354,9 +1371,9 @@
 	nouveau_bo_ref(NULL, &head->image);
 
 	/*XXX: ditto */
-	if (head->curs.image)
-		nouveau_bo_unpin(head->curs.image);
-	nouveau_bo_ref(NULL, &head->curs.image);
+	if (nv_crtc->cursor.nvbo)
+		nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
 
 	nouveau_bo_unmap(nv_crtc->lut.nvbo);
 	if (nv_crtc->lut.nvbo)
@@ -1406,6 +1423,7 @@
 	head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
 	head->base.color_vibrance = 50;
 	head->base.vibrant_hue = 0;
+	head->base.cursor.set_pos = nv50_crtc_cursor_restore;
 	for (i = 0; i < 256; i++) {
 		head->base.lut.r[i] = i << 8;
 		head->base.lut.g[i] = i << 8;
@@ -1433,8 +1451,6 @@
 	if (ret)
 		goto out;
 
-	nv50_crtc_lut_load(crtc);
-
 	/* allocate cursor resources */
 	ret = nv50_curs_create(disp->disp, index, &head->curs);
 	if (ret)
@@ -1466,6 +1482,41 @@
 }
 
 /******************************************************************************
+ * Encoder helpers
+ *****************************************************************************/
+static bool
+nv50_encoder_mode_fixup(struct drm_encoder *encoder,
+			const struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
+{
+	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+	struct nouveau_connector *nv_connector;
+
+	nv_connector = nouveau_encoder_connector_get(nv_encoder);
+	if (nv_connector && nv_connector->native_mode) {
+		nv_connector->scaling_full = false;
+		if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) {
+			switch (nv_connector->type) {
+			case DCB_CONNECTOR_LVDS:
+			case DCB_CONNECTOR_LVDS_SPWG:
+			case DCB_CONNECTOR_eDP:
+				/* force use of scaler for non-edid modes */
+				if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
+					return true;
+				nv_connector->scaling_full = true;
+				break;
+			default:
+				return true;
+			}
+		}
+
+		drm_mode_copy(adjusted_mode, nv_connector->native_mode);
+	}
+
+	return true;
+}
+
+/******************************************************************************
  * DAC
  *****************************************************************************/
 static void
@@ -1492,26 +1543,6 @@
 	nvif_mthd(disp->disp, 0, &args, sizeof(args));
 }
 
-static bool
-nv50_dac_mode_fixup(struct drm_encoder *encoder,
-		    const struct drm_display_mode *mode,
-		    struct drm_display_mode *adjusted_mode)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nouveau_connector *nv_connector;
-
-	nv_connector = nouveau_encoder_connector_get(nv_encoder);
-	if (nv_connector && nv_connector->native_mode) {
-		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
-			int id = adjusted_mode->base.id;
-			*adjusted_mode = *nv_connector->native_mode;
-			adjusted_mode->base.id = id;
-		}
-	}
-
-	return true;
-}
-
 static void
 nv50_dac_commit(struct drm_encoder *encoder)
 {
@@ -1629,7 +1660,7 @@
 
 static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
 	.dpms = nv50_dac_dpms,
-	.mode_fixup = nv50_dac_mode_fixup,
+	.mode_fixup = nv50_encoder_mode_fixup,
 	.prepare = nv50_dac_disconnect,
 	.commit = nv50_dac_commit,
 	.mode_set = nv50_dac_mode_set,
@@ -1646,7 +1677,7 @@
 nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
 {
 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
 	struct nouveau_encoder *nv_encoder;
 	struct drm_encoder *encoder;
 	int type = DRM_MODE_ENCODER_DAC;
@@ -1834,26 +1865,6 @@
 	}
 }
 
-static bool
-nv50_sor_mode_fixup(struct drm_encoder *encoder,
-		    const struct drm_display_mode *mode,
-		    struct drm_display_mode *adjusted_mode)
-{
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nouveau_connector *nv_connector;
-
-	nv_connector = nouveau_encoder_connector_get(nv_encoder);
-	if (nv_connector && nv_connector->native_mode) {
-		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
-			int id = adjusted_mode->base.id;
-			*adjusted_mode = *nv_connector->native_mode;
-			adjusted_mode->base.id = id;
-		}
-	}
-
-	return true;
-}
-
 static void
 nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
 {
@@ -2035,7 +2046,7 @@
 
 static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
 	.dpms = nv50_sor_dpms,
-	.mode_fixup = nv50_sor_mode_fixup,
+	.mode_fixup = nv50_encoder_mode_fixup,
 	.prepare = nv50_sor_disconnect,
 	.commit = nv50_sor_commit,
 	.mode_set = nv50_sor_mode_set,
@@ -2051,7 +2062,7 @@
 nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
 {
 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
 	struct nouveau_encoder *nv_encoder;
 	struct drm_encoder *encoder;
 	int type;
@@ -2112,18 +2123,8 @@
 		     const struct drm_display_mode *mode,
 		     struct drm_display_mode *adjusted_mode)
 {
-	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-	struct nouveau_connector *nv_connector;
-
-	nv_connector = nouveau_encoder_connector_get(nv_encoder);
-	if (nv_connector && nv_connector->native_mode) {
-		if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
-			int id = adjusted_mode->base.id;
-			*adjusted_mode = *nv_connector->native_mode;
-			adjusted_mode->base.id = id;
-		}
-	}
-
+	if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode))
+		return false;
 	adjusted_mode->clock *= 2;
 	return true;
 }
@@ -2232,8 +2233,8 @@
 nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
 {
 	struct nouveau_drm *drm = nouveau_drm(connector->dev);
-	struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
-	struct nouveau_i2c_port *ddc = NULL;
+	struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+	struct nvkm_i2c_port *ddc = NULL;
 	struct nouveau_encoder *nv_encoder;
 	struct drm_encoder *encoder;
 	int type;
@@ -2427,6 +2428,8 @@
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nv50_sync *sync = nv50_sync(crtc);
+
+		nv50_crtc_lut_load(crtc);
 		nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index cb5b889..bf429ca 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -213,7 +213,7 @@
 int
 nv84_fence_create(struct nouveau_drm *drm)
 {
-	struct nouveau_fifo *pfifo = nvkm_fifo(&drm->device);
+	struct nvkm_fifo *pfifo = nvxx_fifo(&drm->device);
 	struct nv84_fence_priv *priv;
 	int ret;
 
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild
new file mode 100644
index 0000000..ff8ed3a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvif/Kbuild
@@ -0,0 +1,4 @@
+nvif-y := nvif/object.o
+nvif-y += nvif/client.o
+nvif-y += nvif/device.o
+nvif-y += nvif/notify.o
diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h
deleted file mode 100644
index 4e308ea..0000000
--- a/drivers/gpu/drm/nouveau/nvif/class.h
+++ /dev/null
@@ -1,570 +0,0 @@
-#ifndef __NVIF_CLASS_H__
-#define __NVIF_CLASS_H__
-
-/*******************************************************************************
- * class identifiers
- ******************************************************************************/
-
-/* the below match nvidia-assigned (either in hw, or sw) class numbers */
-#define NV_DEVICE                                                    0x00000080
-
-#define NV_DMA_FROM_MEMORY                                           0x00000002
-#define NV_DMA_TO_MEMORY                                             0x00000003
-#define NV_DMA_IN_MEMORY                                             0x0000003d
-
-#define NV04_DISP                                                    0x00000046
-
-#define NV03_CHANNEL_DMA                                             0x0000006b
-#define NV10_CHANNEL_DMA                                             0x0000006e
-#define NV17_CHANNEL_DMA                                             0x0000176e
-#define NV40_CHANNEL_DMA                                             0x0000406e
-#define NV50_CHANNEL_DMA                                             0x0000506e
-#define G82_CHANNEL_DMA                                              0x0000826e
-
-#define NV50_CHANNEL_GPFIFO                                          0x0000506f
-#define G82_CHANNEL_GPFIFO                                           0x0000826f
-#define FERMI_CHANNEL_GPFIFO                                         0x0000906f
-#define KEPLER_CHANNEL_GPFIFO_A                                      0x0000a06f
-
-#define NV50_DISP                                                    0x00005070
-#define G82_DISP                                                     0x00008270
-#define GT200_DISP                                                   0x00008370
-#define GT214_DISP                                                   0x00008570
-#define GT206_DISP                                                   0x00008870
-#define GF110_DISP                                                   0x00009070
-#define GK104_DISP                                                   0x00009170
-#define GK110_DISP                                                   0x00009270
-#define GM107_DISP                                                   0x00009470
-#define GM204_DISP                                                   0x00009570
-
-#define NV50_DISP_CURSOR                                             0x0000507a
-#define G82_DISP_CURSOR                                              0x0000827a
-#define GT214_DISP_CURSOR                                            0x0000857a
-#define GF110_DISP_CURSOR                                            0x0000907a
-#define GK104_DISP_CURSOR                                            0x0000917a
-
-#define NV50_DISP_OVERLAY                                            0x0000507b
-#define G82_DISP_OVERLAY                                             0x0000827b
-#define GT214_DISP_OVERLAY                                           0x0000857b
-#define GF110_DISP_OVERLAY                                           0x0000907b
-#define GK104_DISP_OVERLAY                                           0x0000917b
-
-#define NV50_DISP_BASE_CHANNEL_DMA                                   0x0000507c
-#define G82_DISP_BASE_CHANNEL_DMA                                    0x0000827c
-#define GT200_DISP_BASE_CHANNEL_DMA                                  0x0000837c
-#define GT214_DISP_BASE_CHANNEL_DMA                                  0x0000857c
-#define GF110_DISP_BASE_CHANNEL_DMA                                  0x0000907c
-#define GK104_DISP_BASE_CHANNEL_DMA                                  0x0000917c
-#define GK110_DISP_BASE_CHANNEL_DMA                                  0x0000927c
-
-#define NV50_DISP_CORE_CHANNEL_DMA                                   0x0000507d
-#define G82_DISP_CORE_CHANNEL_DMA                                    0x0000827d
-#define GT200_DISP_CORE_CHANNEL_DMA                                  0x0000837d
-#define GT214_DISP_CORE_CHANNEL_DMA                                  0x0000857d
-#define GT206_DISP_CORE_CHANNEL_DMA                                  0x0000887d
-#define GF110_DISP_CORE_CHANNEL_DMA                                  0x0000907d
-#define GK104_DISP_CORE_CHANNEL_DMA                                  0x0000917d
-#define GK110_DISP_CORE_CHANNEL_DMA                                  0x0000927d
-#define GM107_DISP_CORE_CHANNEL_DMA                                  0x0000947d
-#define GM204_DISP_CORE_CHANNEL_DMA                                  0x0000957d
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA                                0x0000507e
-#define G82_DISP_OVERLAY_CHANNEL_DMA                                 0x0000827e
-#define GT200_DISP_OVERLAY_CHANNEL_DMA                               0x0000837e
-#define GT214_DISP_OVERLAY_CHANNEL_DMA                               0x0000857e
-#define GF110_DISP_OVERLAY_CONTROL_DMA                               0x0000907e
-#define GK104_DISP_OVERLAY_CONTROL_DMA                               0x0000917e
-
-#define FERMI_A                                                      0x00009097
-#define FERMI_B                                                      0x00009197
-#define FERMI_C                                                      0x00009297
-
-#define KEPLER_A                                                     0x0000a097
-#define KEPLER_B                                                     0x0000a197
-#define KEPLER_C                                                     0x0000a297
-
-#define MAXWELL_A                                                    0x0000b097
-
-#define FERMI_COMPUTE_A                                              0x000090c0
-#define FERMI_COMPUTE_B                                              0x000091c0
-
-#define KEPLER_COMPUTE_A                                             0x0000a0c0
-#define KEPLER_COMPUTE_B                                             0x0000a1c0
-
-#define MAXWELL_COMPUTE_A                                            0x0000b0c0
-
-
-/*******************************************************************************
- * client
- ******************************************************************************/
-
-#define NV_CLIENT_DEVLIST                                                  0x00
-
-struct nv_client_devlist_v0 {
-	__u8  version;
-	__u8  count;
-	__u8  pad02[6];
-	__u64 device[];
-};
-
-
-/*******************************************************************************
- * device
- ******************************************************************************/
-
-struct nv_device_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u64 device;	/* device identifier, ~0 for client default */
-#define NV_DEVICE_V0_DISABLE_IDENTIFY                     0x0000000000000001ULL
-#define NV_DEVICE_V0_DISABLE_MMIO                         0x0000000000000002ULL
-#define NV_DEVICE_V0_DISABLE_VBIOS                        0x0000000000000004ULL
-#define NV_DEVICE_V0_DISABLE_CORE                         0x0000000000000008ULL
-#define NV_DEVICE_V0_DISABLE_DISP                         0x0000000000010000ULL
-#define NV_DEVICE_V0_DISABLE_FIFO                         0x0000000000020000ULL
-#define NV_DEVICE_V0_DISABLE_GRAPH                        0x0000000100000000ULL
-#define NV_DEVICE_V0_DISABLE_MPEG                         0x0000000200000000ULL
-#define NV_DEVICE_V0_DISABLE_ME                           0x0000000400000000ULL
-#define NV_DEVICE_V0_DISABLE_VP                           0x0000000800000000ULL
-#define NV_DEVICE_V0_DISABLE_CRYPT                        0x0000001000000000ULL
-#define NV_DEVICE_V0_DISABLE_BSP                          0x0000002000000000ULL
-#define NV_DEVICE_V0_DISABLE_PPP                          0x0000004000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY0                        0x0000008000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY1                        0x0000010000000000ULL
-#define NV_DEVICE_V0_DISABLE_VIC                          0x0000020000000000ULL
-#define NV_DEVICE_V0_DISABLE_VENC                         0x0000040000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY2                        0x0000080000000000ULL
-	__u64 disable;	/* disable particular subsystems */
-	__u64 debug0;	/* as above, but *internal* ids, and *NOT* ABI */
-};
-
-#define NV_DEVICE_V0_INFO                                                  0x00
-
-struct nv_device_info_v0 {
-	__u8  version;
-#define NV_DEVICE_INFO_V0_IGP                                              0x00
-#define NV_DEVICE_INFO_V0_PCI                                              0x01
-#define NV_DEVICE_INFO_V0_AGP                                              0x02
-#define NV_DEVICE_INFO_V0_PCIE                                             0x03
-#define NV_DEVICE_INFO_V0_SOC                                              0x04
-	__u8  platform;
-	__u16 chipset;	/* from NV_PMC_BOOT_0 */
-	__u8  revision;	/* from NV_PMC_BOOT_0 */
-#define NV_DEVICE_INFO_V0_TNT                                              0x01
-#define NV_DEVICE_INFO_V0_CELSIUS                                          0x02
-#define NV_DEVICE_INFO_V0_KELVIN                                           0x03
-#define NV_DEVICE_INFO_V0_RANKINE                                          0x04
-#define NV_DEVICE_INFO_V0_CURIE                                            0x05
-#define NV_DEVICE_INFO_V0_TESLA                                            0x06
-#define NV_DEVICE_INFO_V0_FERMI                                            0x07
-#define NV_DEVICE_INFO_V0_KEPLER                                           0x08
-#define NV_DEVICE_INFO_V0_MAXWELL                                          0x09
-	__u8  family;
-	__u8  pad06[2];
-	__u64 ram_size;
-	__u64 ram_user;
-};
-
-
-/*******************************************************************************
- * context dma
- ******************************************************************************/
-
-struct nv_dma_v0 {
-	__u8  version;
-#define NV_DMA_V0_TARGET_VM                                                0x00
-#define NV_DMA_V0_TARGET_VRAM                                              0x01
-#define NV_DMA_V0_TARGET_PCI                                               0x02
-#define NV_DMA_V0_TARGET_PCI_US                                            0x03
-#define NV_DMA_V0_TARGET_AGP                                               0x04
-	__u8  target;
-#define NV_DMA_V0_ACCESS_VM                                                0x00
-#define NV_DMA_V0_ACCESS_RD                                                0x01
-#define NV_DMA_V0_ACCESS_WR                                                0x02
-#define NV_DMA_V0_ACCESS_RDWR                 (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
-	__u8  access;
-	__u8  pad03[5];
-	__u64 start;
-	__u64 limit;
-	/* ... chipset-specific class data */
-};
-
-struct nv50_dma_v0 {
-	__u8  version;
-#define NV50_DMA_V0_PRIV_VM                                                0x00
-#define NV50_DMA_V0_PRIV_US                                                0x01
-#define NV50_DMA_V0_PRIV__S                                                0x02
-	__u8  priv;
-#define NV50_DMA_V0_PART_VM                                                0x00
-#define NV50_DMA_V0_PART_256                                               0x01
-#define NV50_DMA_V0_PART_1KB                                               0x02
-	__u8  part;
-#define NV50_DMA_V0_COMP_NONE                                              0x00
-#define NV50_DMA_V0_COMP_1                                                 0x01
-#define NV50_DMA_V0_COMP_2                                                 0x02
-#define NV50_DMA_V0_COMP_VM                                                0x03
-	__u8  comp;
-#define NV50_DMA_V0_KIND_PITCH                                             0x00
-#define NV50_DMA_V0_KIND_VM                                                0x7f
-	__u8  kind;
-	__u8  pad05[3];
-};
-
-struct gf100_dma_v0 {
-	__u8  version;
-#define GF100_DMA_V0_PRIV_VM                                               0x00
-#define GF100_DMA_V0_PRIV_US                                               0x01
-#define GF100_DMA_V0_PRIV__S                                               0x02
-	__u8  priv;
-#define GF100_DMA_V0_KIND_PITCH                                            0x00
-#define GF100_DMA_V0_KIND_VM                                               0xff
-	__u8  kind;
-	__u8  pad03[5];
-};
-
-struct gf110_dma_v0 {
-	__u8  version;
-#define GF110_DMA_V0_PAGE_LP                                               0x00
-#define GF110_DMA_V0_PAGE_SP                                               0x01
-	__u8  page;
-#define GF110_DMA_V0_KIND_PITCH                                            0x00
-#define GF110_DMA_V0_KIND_VM                                               0xff
-	__u8  kind;
-	__u8  pad03[5];
-};
-
-
-/*******************************************************************************
- * perfmon
- ******************************************************************************/
-
-struct nvif_perfctr_v0 {
-	__u8  version;
-	__u8  pad01[1];
-	__u16 logic_op;
-	__u8  pad04[4];
-	char  name[4][64];
-};
-
-#define NVIF_PERFCTR_V0_QUERY                                              0x00
-#define NVIF_PERFCTR_V0_SAMPLE                                             0x01
-#define NVIF_PERFCTR_V0_READ                                               0x02
-
-struct nvif_perfctr_query_v0 {
-	__u8  version;
-	__u8  pad01[3];
-	__u32 iter;
-	char  name[64];
-};
-
-struct nvif_perfctr_sample {
-};
-
-struct nvif_perfctr_read_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u32 ctr;
-	__u32 clk;
-};
-
-
-/*******************************************************************************
- * device control
- ******************************************************************************/
-
-#define NVIF_CONTROL_PSTATE_INFO                                           0x00
-#define NVIF_CONTROL_PSTATE_ATTR                                           0x01
-#define NVIF_CONTROL_PSTATE_USER                                           0x02
-
-struct nvif_control_pstate_info_v0 {
-	__u8  version;
-	__u8  count; /* out: number of power states */
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE                         (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON                         (-2)
-	__s8  ustate_ac; /* out: target pstate index */
-	__s8  ustate_dc; /* out: target pstate index */
-	__s8  pwrsrc; /* out: current power source */
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN                         (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON                         (-2)
-	__s8  pstate; /* out: current pstate index */
-	__u8  pad06[2];
-};
-
-struct nvif_control_pstate_attr_v0 {
-	__u8  version;
-#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT                          (-1)
-	__s8  state; /*  in: index of pstate to query
-		      * out: pstate identifier
-		      */
-	__u8  index; /*  in: index of attribute to query
-		      * out: index of next attribute, or 0 if no more
-		      */
-	__u8  pad03[5];
-	__u32 min;
-	__u32 max;
-	char  name[32];
-	char  unit[16];
-};
-
-struct nvif_control_pstate_user_v0 {
-	__u8  version;
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN                          (-1)
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON                          (-2)
-	__s8  ustate; /*  in: pstate identifier */
-	__s8  pwrsrc; /*  in: target power source */
-	__u8  pad03[5];
-};
-
-
-/*******************************************************************************
- * DMA FIFO channels
- ******************************************************************************/
-
-struct nv03_channel_dma_v0 {
-	__u8  version;
-	__u8  chid;
-	__u8  pad02[2];
-	__u32 pushbuf;
-	__u64 offset;
-};
-
-#define G82_CHANNEL_DMA_V0_NTFY_UEVENT                                     0x00
-
-/*******************************************************************************
- * GPFIFO channels
- ******************************************************************************/
-
-struct nv50_channel_gpfifo_v0 {
-	__u8  version;
-	__u8  chid;
-	__u8  pad01[6];
-	__u32 pushbuf;
-	__u32 ilength;
-	__u64 ioffset;
-};
-
-struct kepler_channel_gpfifo_a_v0 {
-	__u8  version;
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR                               0x01
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_VP                               0x02
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_PPP                              0x04
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_BSP                              0x08
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0                              0x10
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1                              0x20
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC                              0x40
-	__u8  engine;
-	__u16 chid;
-	__u8  pad04[4];
-	__u32 pushbuf;
-	__u32 ilength;
-	__u64 ioffset;
-};
-
-/*******************************************************************************
- * legacy display
- ******************************************************************************/
-
-#define NV04_DISP_NTFY_VBLANK                                              0x00
-#define NV04_DISP_NTFY_CONN                                                0x01
-
-struct nv04_disp_mthd_v0 {
-	__u8  version;
-#define NV04_DISP_SCANOUTPOS                                               0x00
-	__u8  method;
-	__u8  head;
-	__u8  pad03[5];
-};
-
-struct nv04_disp_scanoutpos_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__s64 time[2];
-	__u16 vblanks;
-	__u16 vblanke;
-	__u16 vtotal;
-	__u16 vline;
-	__u16 hblanks;
-	__u16 hblanke;
-	__u16 htotal;
-	__u16 hline;
-};
-
-/*******************************************************************************
- * display
- ******************************************************************************/
-
-#define NV50_DISP_MTHD                                                     0x00
-
-struct nv50_disp_mthd_v0 {
-	__u8  version;
-#define NV50_DISP_SCANOUTPOS                                               0x00
-	__u8  method;
-	__u8  head;
-	__u8  pad03[5];
-};
-
-struct nv50_disp_mthd_v1 {
-	__u8  version;
-#define NV50_DISP_MTHD_V1_DAC_PWR                                          0x10
-#define NV50_DISP_MTHD_V1_DAC_LOAD                                         0x11
-#define NV50_DISP_MTHD_V1_SOR_PWR                                          0x20
-#define NV50_DISP_MTHD_V1_SOR_HDA_ELD                                      0x21
-#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR                                     0x22
-#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT                                  0x23
-#define NV50_DISP_MTHD_V1_SOR_DP_PWR                                       0x24
-#define NV50_DISP_MTHD_V1_PIOR_PWR                                         0x30
-	__u8  method;
-	__u16 hasht;
-	__u16 hashm;
-	__u8  pad06[2];
-};
-
-struct nv50_disp_dac_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  data;
-	__u8  vsync;
-	__u8  hsync;
-	__u8  pad05[3];
-};
-
-struct nv50_disp_dac_load_v0 {
-	__u8  version;
-	__u8  load;
-	__u8  pad02[2];
-	__u32 data;
-};
-
-struct nv50_disp_sor_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  pad02[6];
-};
-
-struct nv50_disp_sor_hda_eld_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u8  data[];
-};
-
-struct nv50_disp_sor_hdmi_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  max_ac_packet;
-	__u8  rekey;
-	__u8  pad04[4];
-};
-
-struct nv50_disp_sor_lvds_script_v0 {
-	__u8  version;
-	__u8  pad01[1];
-	__u16 script;
-	__u8  pad04[4];
-};
-
-struct nv50_disp_sor_dp_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  pad02[6];
-};
-
-struct nv50_disp_pior_pwr_v0 {
-	__u8  version;
-	__u8  state;
-	__u8  type;
-	__u8  pad03[5];
-};
-
-/* core */
-struct nv50_disp_core_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[3];
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-
-/* cursor immediate */
-struct nv50_disp_cursor_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_CURSOR_V0_NTFY_UEVENT                                    0x00
-
-/* base */
-struct nv50_disp_base_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[2];
-	__u8  head;
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-
-/* overlay */
-struct nv50_disp_overlay_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[2];
-	__u8  head;
-	__u32 pushbuf;
-};
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT                       0x00
-
-/* overlay immediate */
-struct nv50_disp_overlay_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT                                   0x00
-
-/*******************************************************************************
- * fermi
- ******************************************************************************/
-
-#define FERMI_A_ZBC_COLOR                                                  0x00
-#define FERMI_A_ZBC_DEPTH                                                  0x01
-
-struct fermi_a_zbc_color_v0 {
-	__u8  version;
-#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO                                      0x01
-#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE                                 0x02
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32                       0x04
-#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16                           0x08
-#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16                       0x0c
-#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16                       0x10
-#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16                       0x14
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16                       0x16
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8                                  0x18
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8                               0x1c
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10                               0x20
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10                           0x24
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8                                  0x28
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8                               0x2c
-#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8                              0x30
-#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8                              0x34
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8                              0x38
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10                               0x3c
-#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11                              0x40
-	__u8  format;
-	__u8  index;
-	__u8  pad03[5];
-	__u32 ds[4];
-	__u32 l2[4];
-};
-
-struct fermi_a_zbc_depth_v0 {
-	__u8  version;
-#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32                                      0x01
-	__u8  format;
-	__u8  index;
-	__u8  pad03[5];
-	__u32 ds;
-	__u32 l2;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c
index 3f7ac5b..80b9684 100644
--- a/drivers/gpu/drm/nouveau/nvif/client.c
+++ b/drivers/gpu/drm/nouveau/nvif/client.c
@@ -22,9 +22,9 @@
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "client.h"
-#include "driver.h"
-#include "ioctl.h"
+#include <nvif/client.h>
+#include <nvif/driver.h>
+#include <nvif/ioctl.h>
 
 int
 nvif_client_ioctl(struct nvif_client *client, void *data, u32 size)
diff --git a/drivers/gpu/drm/nouveau/nvif/client.h b/drivers/gpu/drm/nouveau/nvif/client.h
deleted file mode 100644
index 28352f0..0000000
--- a/drivers/gpu/drm/nouveau/nvif/client.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __NVIF_CLIENT_H__
-#define __NVIF_CLIENT_H__
-
-#include "object.h"
-
-struct nvif_client {
-	struct nvif_object base;
-	struct nvif_object *object; /*XXX: hack for nvif_object() */
-	const struct nvif_driver *driver;
-	bool super;
-};
-
-static inline struct nvif_client *
-nvif_client(struct nvif_object *object)
-{
-	while (object && object->parent != object)
-		object = object->parent;
-	return (void *)object;
-}
-
-int  nvif_client_init(void (*dtor)(struct nvif_client *), const char *,
-		      const char *, u64, const char *, const char *,
-		      struct nvif_client *);
-void nvif_client_fini(struct nvif_client *);
-int  nvif_client_new(const char *, const char *, u64, const char *,
-		     const char *, struct nvif_client **);
-void nvif_client_ref(struct nvif_client *, struct nvif_client **);
-int  nvif_client_ioctl(struct nvif_client *, void *, u32);
-int  nvif_client_suspend(struct nvif_client *);
-int  nvif_client_resume(struct nvif_client *);
-
-/*XXX*/
-#include <core/client.h>
-#define nvkm_client(a) ({ \
-	struct nvif_client *_client = nvif_client(nvif_object(a)); \
-	nouveau_client(_client->base.priv); \
-})
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c
index f477579..6f72244 100644
--- a/drivers/gpu/drm/nouveau/nvif/device.c
+++ b/drivers/gpu/drm/nouveau/nvif/device.c
@@ -22,7 +22,7 @@
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "device.h"
+#include <nvif/device.h>
 
 void
 nvif_device_fini(struct nvif_device *device)
diff --git a/drivers/gpu/drm/nouveau/nvif/device.h b/drivers/gpu/drm/nouveau/nvif/device.h
deleted file mode 100644
index 43180f9..0000000
--- a/drivers/gpu/drm/nouveau/nvif/device.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NVIF_DEVICE_H__
-#define __NVIF_DEVICE_H__
-
-#include "object.h"
-#include "class.h"
-
-struct nvif_device {
-	struct nvif_object base;
-	struct nvif_object *object; /*XXX: hack for nvif_object() */
-	struct nv_device_info_v0 info;
-};
-
-static inline struct nvif_device *
-nvif_device(struct nvif_object *object)
-{
-	while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ )
-		object = object->parent;
-	return (void *)object;
-}
-
-int  nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *),
-		      u32 handle, u32 oclass, void *, u32,
-		      struct nvif_device *);
-void nvif_device_fini(struct nvif_device *);
-int  nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
-		     void *, u32, struct nvif_device **);
-void nvif_device_ref(struct nvif_device *, struct nvif_device **);
-
-/*XXX*/
-#include <subdev/bios.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/gpio.h>
-#include <subdev/clock.h>
-#include <subdev/i2c.h>
-#include <subdev/timer.h>
-#include <subdev/therm.h>
-
-#define nvkm_device(a) nv_device(nvkm_object((a)))
-#define nvkm_bios(a) nouveau_bios(nvkm_device(a))
-#define nvkm_fb(a) nouveau_fb(nvkm_device(a))
-#define nvkm_vmmgr(a) nouveau_vmmgr(nvkm_device(a))
-#define nvkm_bar(a) nouveau_bar(nvkm_device(a))
-#define nvkm_gpio(a) nouveau_gpio(nvkm_device(a))
-#define nvkm_clock(a) nouveau_clock(nvkm_device(a))
-#define nvkm_i2c(a) nouveau_i2c(nvkm_device(a))
-#define nvkm_timer(a) nouveau_timer(nvkm_device(a))
-#define nvkm_wait(a,b,c,d) nv_wait(nvkm_timer(a), (b), (c), (d))
-#define nvkm_wait_cb(a,b,c) nv_wait_cb(nvkm_timer(a), (b), (c))
-#define nvkm_therm(a) nouveau_therm(nvkm_device(a))
-
-#include <engine/device.h>
-#include <engine/fifo.h>
-#include <engine/graph.h>
-#include <engine/software.h>
-
-#define nvkm_fifo(a) nouveau_fifo(nvkm_device(a))
-#define nvkm_fifo_chan(a) ((struct nouveau_fifo_chan *)nvkm_object(a))
-#define nvkm_gr(a) ((struct nouveau_graph *)nouveau_engine(nvkm_object(a), NVDEV_ENGINE_GR))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c
index 0898c31..8e34748 100644
--- a/drivers/gpu/drm/nouveau/nvif/notify.c
+++ b/drivers/gpu/drm/nouveau/nvif/notify.c
@@ -92,7 +92,7 @@
 {
 	int ret = notify->func(notify);
 	if (ret == NVIF_NOTIFY_KEEP ||
-	    !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+	    !test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
 		if (!keep)
 			atomic_dec(&notify->putcnt);
 		else
diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c
index dd85b56..3ab4e2f 100644
--- a/drivers/gpu/drm/nouveau/nvif/object.c
+++ b/drivers/gpu/drm/nouveau/nvif/object.c
@@ -22,10 +22,10 @@
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "object.h"
-#include "client.h"
-#include "driver.h"
-#include "ioctl.h"
+#include <nvif/object.h>
+#include <nvif/client.h>
+#include <nvif/driver.h>
+#include <nvif/ioctl.h>
 
 int
 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h
deleted file mode 100644
index fe51917..0000000
--- a/drivers/gpu/drm/nouveau/nvif/object.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef __NVIF_OBJECT_H__
-#define __NVIF_OBJECT_H__
-
-#include <nvif/os.h>
-
-struct nvif_object {
-	struct nvif_object *parent;
-	struct nvif_object *object; /*XXX: hack for nvif_object() */
-	struct kref refcount;
-	u32 handle;
-	u32 oclass;
-	void *data;
-	u32   size;
-	void *priv; /*XXX: hack */
-	void (*dtor)(struct nvif_object *);
-	struct {
-		void __iomem *ptr;
-		u32 size;
-	} map;
-};
-
-int  nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *),
-		      u32 handle, u32 oclass, void *, u32,
-		      struct nvif_object *);
-void nvif_object_fini(struct nvif_object *);
-int  nvif_object_new(struct nvif_object *, u32 handle, u32 oclass,
-		     void *, u32, struct nvif_object **);
-void nvif_object_ref(struct nvif_object *, struct nvif_object **);
-int  nvif_object_ioctl(struct nvif_object *, void *, u32, void **);
-int  nvif_object_sclass(struct nvif_object *, u32 *, int);
-u32  nvif_object_rd(struct nvif_object *, int, u64);
-void nvif_object_wr(struct nvif_object *, int, u64, u32);
-int  nvif_object_mthd(struct nvif_object *, u32, void *, u32);
-int  nvif_object_map(struct nvif_object *);
-void nvif_object_unmap(struct nvif_object *);
-
-#define nvif_object(a) (a)->object
-
-#define ioread8_native ioread8
-#define iowrite8_native iowrite8
-#define nvif_rd(a,b,c) ({                                                      \
-	struct nvif_object *_object = nvif_object(a);                          \
-	u32 _data;                                                             \
-	if (likely(_object->map.ptr))                                          \
-		_data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c));      \
-	else                                                                   \
-		_data = nvif_object_rd(_object, (b) / 8, (c));                 \
-	_data;                                                                 \
-})
-#define nvif_wr(a,b,c,d) ({                                                    \
-	struct nvif_object *_object = nvif_object(a);                          \
-	if (likely(_object->map.ptr))                                          \
-		iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c));        \
-	else                                                                   \
-		nvif_object_wr(_object, (b) / 8, (c), (d));                    \
-})
-#define nvif_rd08(a,b) ({ u8  _v = nvif_rd((a), 8, (b)); _v; })
-#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; })
-#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; })
-#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c))
-#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c))
-#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c))
-#define nvif_mask(a,b,c,d) ({                                                  \
-	u32 _v = nvif_rd32(nvif_object(a), (b));                               \
-	nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d));                     \
-	_v;                                                                    \
-})
-
-#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d))
-
-/*XXX*/
-#include <core/object.h>
-#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/os.h b/drivers/gpu/drm/nouveau/nvif/os.h
deleted file mode 120000
index bd744b2..0000000
--- a/drivers/gpu/drm/nouveau/nvif/os.h
+++ /dev/null
@@ -1 +0,0 @@
-../core/os.h
\ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/nvkm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/Kbuild
new file mode 100644
index 0000000..2832147
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/Kbuild
@@ -0,0 +1,3 @@
+include $(src)/nvkm/core/Kbuild
+include $(src)/nvkm/subdev/Kbuild
+include $(src)/nvkm/engine/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
new file mode 100644
index 0000000..a2bdb20
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
@@ -0,0 +1,17 @@
+nvkm-y := nvkm/core/client.o
+nvkm-y += nvkm/core/engctx.o
+nvkm-y += nvkm/core/engine.o
+nvkm-y += nvkm/core/enum.o
+nvkm-y += nvkm/core/event.o
+nvkm-y += nvkm/core/gpuobj.o
+nvkm-y += nvkm/core/handle.o
+nvkm-y += nvkm/core/ioctl.o
+nvkm-y += nvkm/core/mm.o
+nvkm-y += nvkm/core/namedb.o
+nvkm-y += nvkm/core/notify.o
+nvkm-y += nvkm/core/object.o
+nvkm-y += nvkm/core/option.o
+nvkm-y += nvkm/core/parent.o
+nvkm-y += nvkm/core/printk.o
+nvkm-y += nvkm/core/ramht.o
+nvkm-y += nvkm/core/subdev.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c
new file mode 100644
index 0000000..878a82f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/notify.h>
+#include <core/option.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+struct nvkm_client_notify {
+	struct nvkm_client *client;
+	struct nvkm_notify n;
+	u8 version;
+	u8 size;
+	union {
+		struct nvif_notify_rep_v0 v0;
+	} rep;
+};
+
+static int
+nvkm_client_notify(struct nvkm_notify *n)
+{
+	struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
+	struct nvkm_client *client = notify->client;
+	return client->ntfy(&notify->rep, notify->size, n->data, n->size);
+}
+
+int
+nvkm_client_notify_put(struct nvkm_client *client, int index)
+{
+	if (index < ARRAY_SIZE(client->notify)) {
+		if (client->notify[index]) {
+			nvkm_notify_put(&client->notify[index]->n);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int
+nvkm_client_notify_get(struct nvkm_client *client, int index)
+{
+	if (index < ARRAY_SIZE(client->notify)) {
+		if (client->notify[index]) {
+			nvkm_notify_get(&client->notify[index]->n);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int
+nvkm_client_notify_del(struct nvkm_client *client, int index)
+{
+	if (index < ARRAY_SIZE(client->notify)) {
+		if (client->notify[index]) {
+			nvkm_notify_fini(&client->notify[index]->n);
+			kfree(client->notify[index]);
+			client->notify[index] = NULL;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+int
+nvkm_client_notify_new(struct nvkm_object *object,
+		       struct nvkm_event *event, void *data, u32 size)
+{
+	struct nvkm_client *client = nvkm_client(object);
+	struct nvkm_client_notify *notify;
+	union {
+		struct nvif_notify_req_v0 v0;
+	} *req = data;
+	u8  index, reply;
+	int ret;
+
+	for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
+		if (!client->notify[index])
+			break;
+	}
+
+	if (index == ARRAY_SIZE(client->notify))
+		return -ENOSPC;
+
+	notify = kzalloc(sizeof(*notify), GFP_KERNEL);
+	if (!notify)
+		return -ENOMEM;
+
+	nv_ioctl(client, "notify new size %d\n", size);
+	if (nvif_unpack(req->v0, 0, 0, true)) {
+		nv_ioctl(client, "notify new vers %d reply %d route %02x "
+				 "token %llx\n", req->v0.version,
+			 req->v0.reply, req->v0.route, req->v0.token);
+		notify->version = req->v0.version;
+		notify->size = sizeof(notify->rep.v0);
+		notify->rep.v0.version = req->v0.version;
+		notify->rep.v0.route = req->v0.route;
+		notify->rep.v0.token = req->v0.token;
+		reply = req->v0.reply;
+	}
+
+	if (ret == 0) {
+		ret = nvkm_notify_init(object, event, nvkm_client_notify,
+				       false, data, size, reply, &notify->n);
+		if (ret == 0) {
+			client->notify[index] = notify;
+			notify->client = client;
+			return index;
+		}
+	}
+
+	kfree(notify);
+	return ret;
+}
+
+static int
+nvkm_client_mthd_devlist(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nv_client_devlist_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "client devlist size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "client devlist vers %d count %d\n",
+			 args->v0.version, args->v0.count);
+		if (size == sizeof(args->v0.device[0]) * args->v0.count) {
+			ret = nvkm_device_list(args->v0.device, args->v0.count);
+			if (ret >= 0) {
+				args->v0.count = ret;
+				ret = 0;
+			}
+		} else {
+			ret = -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	switch (mthd) {
+	case NV_CLIENT_DEVLIST:
+		return nvkm_client_mthd_devlist(object, data, size);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static void
+nvkm_client_dtor(struct nvkm_object *object)
+{
+	struct nvkm_client *client = (void *)object;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+		nvkm_client_notify_del(client, i);
+	nvkm_object_ref(NULL, &client->device);
+	nvkm_handle_destroy(client->root);
+	nvkm_namedb_destroy(&client->namedb);
+}
+
+static struct nvkm_oclass
+nvkm_client_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.dtor = nvkm_client_dtor,
+		.mthd = nvkm_client_mthd,
+	},
+};
+
+int
+nvkm_client_create_(const char *name, u64 devname, const char *cfg,
+		    const char *dbg, int length, void **pobject)
+{
+	struct nvkm_object *device;
+	struct nvkm_client *client;
+	int ret;
+
+	device = (void *)nvkm_device_find(devname);
+	if (!device)
+		return -ENODEV;
+
+	ret = nvkm_namedb_create_(NULL, NULL, &nvkm_client_oclass,
+				  NV_CLIENT_CLASS, NULL,
+				  (1ULL << NVDEV_ENGINE_DEVICE),
+				  length, pobject);
+	client = *pobject;
+	if (ret)
+		return ret;
+
+	ret = nvkm_handle_create(nv_object(client), ~0, ~0, nv_object(client),
+				 &client->root);
+	if (ret)
+		return ret;
+
+	/* prevent init/fini being called, os in in charge of this */
+	atomic_set(&nv_object(client)->usecount, 2);
+
+	nvkm_object_ref(device, &client->device);
+	snprintf(client->name, sizeof(client->name), "%s", name);
+	client->debug = nvkm_dbgopt(dbg, "CLIENT");
+	return 0;
+}
+
+int
+nvkm_client_init(struct nvkm_client *client)
+{
+	int ret;
+	nv_debug(client, "init running\n");
+	ret = nvkm_handle_init(client->root);
+	nv_debug(client, "init completed with %d\n", ret);
+	return ret;
+}
+
+int
+nvkm_client_fini(struct nvkm_client *client, bool suspend)
+{
+	const char *name[2] = { "fini", "suspend" };
+	int ret, i;
+	nv_debug(client, "%s running\n", name[suspend]);
+	nv_debug(client, "%s notify\n", name[suspend]);
+	for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+		nvkm_client_notify_put(client, i);
+	nv_debug(client, "%s object\n", name[suspend]);
+	ret = nvkm_handle_fini(client->root, suspend);
+	nv_debug(client, "%s completed with %d\n", name[suspend], ret);
+	return ret;
+}
+
+const char *
+nvkm_client_name(void *obj)
+{
+	const char *client_name = "unknown";
+	struct nvkm_client *client = nvkm_client(obj);
+	if (client)
+		client_name = client->name;
+	return client_name;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c
new file mode 100644
index 0000000..fb2acbc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/engctx.h>
+#include <core/engine.h>
+#include <core/client.h>
+
+static inline int
+nvkm_engctx_exists(struct nvkm_object *parent,
+		   struct nvkm_engine *engine, void **pobject)
+{
+	struct nvkm_engctx *engctx;
+	struct nvkm_object *parctx;
+
+	list_for_each_entry(engctx, &engine->contexts, head) {
+		parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
+		if (parctx == parent) {
+			atomic_inc(&nv_object(engctx)->refcount);
+			*pobject = engctx;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int
+nvkm_engctx_create_(struct nvkm_object *parent, struct nvkm_object *engobj,
+		    struct nvkm_oclass *oclass, struct nvkm_object *pargpu,
+		    u32 size, u32 align, u32 flags, int length, void **pobject)
+{
+	struct nvkm_client *client = nvkm_client(parent);
+	struct nvkm_engine *engine = nv_engine(engobj);
+	struct nvkm_object *engctx;
+	unsigned long save;
+	int ret;
+
+	/* check if this engine already has a context for the parent object,
+	 * and reference it instead of creating a new one
+	 */
+	spin_lock_irqsave(&engine->lock, save);
+	ret = nvkm_engctx_exists(parent, engine, pobject);
+	spin_unlock_irqrestore(&engine->lock, save);
+	if (ret)
+		return ret;
+
+	/* create the new context, supports creating both raw objects and
+	 * objects backed by instance memory
+	 */
+	if (size) {
+		ret = nvkm_gpuobj_create_(parent, engobj, oclass,
+					  NV_ENGCTX_CLASS, pargpu, size,
+					  align, flags, length, pobject);
+	} else {
+		ret = nvkm_object_create_(parent, engobj, oclass,
+					  NV_ENGCTX_CLASS, length, pobject);
+	}
+
+	engctx = *pobject;
+	if (ret)
+		return ret;
+
+	/* must take the lock again and re-check a context doesn't already
+	 * exist (in case of a race) - the lock had to be dropped before as
+	 * it's not possible to allocate the object with it held.
+	 */
+	spin_lock_irqsave(&engine->lock, save);
+	ret = nvkm_engctx_exists(parent, engine, pobject);
+	if (ret) {
+		spin_unlock_irqrestore(&engine->lock, save);
+		nvkm_object_ref(NULL, &engctx);
+		return ret;
+	}
+
+	if (client->vm)
+		atomic_inc(&client->vm->engref[nv_engidx(engine)]);
+	list_add(&nv_engctx(engctx)->head, &engine->contexts);
+	nv_engctx(engctx)->addr = ~0ULL;
+	spin_unlock_irqrestore(&engine->lock, save);
+	return 0;
+}
+
+void
+nvkm_engctx_destroy(struct nvkm_engctx *engctx)
+{
+	struct nvkm_engine *engine = engctx->gpuobj.object.engine;
+	struct nvkm_client *client = nvkm_client(engctx);
+	unsigned long save;
+
+	nvkm_gpuobj_unmap(&engctx->vma);
+	spin_lock_irqsave(&engine->lock, save);
+	list_del(&engctx->head);
+	spin_unlock_irqrestore(&engine->lock, save);
+
+	if (client->vm)
+		atomic_dec(&client->vm->engref[nv_engidx(engine)]);
+
+	if (engctx->gpuobj.size)
+		nvkm_gpuobj_destroy(&engctx->gpuobj);
+	else
+		nvkm_object_destroy(&engctx->gpuobj.object);
+}
+
+int
+nvkm_engctx_init(struct nvkm_engctx *engctx)
+{
+	struct nvkm_object *object = nv_object(engctx);
+	struct nvkm_subdev *subdev = nv_subdev(object->engine);
+	struct nvkm_object *parent;
+	struct nvkm_subdev *pardev;
+	int ret;
+
+	ret = nvkm_gpuobj_init(&engctx->gpuobj);
+	if (ret)
+		return ret;
+
+	parent = nv_pclass(object->parent, NV_PARENT_CLASS);
+	pardev = nv_subdev(parent->engine);
+	if (nv_parent(parent)->context_attach) {
+		mutex_lock(&pardev->mutex);
+		ret = nv_parent(parent)->context_attach(parent, object);
+		mutex_unlock(&pardev->mutex);
+	}
+
+	if (ret) {
+		nv_error(parent, "failed to attach %s context, %d\n",
+			 subdev->name, ret);
+		return ret;
+	}
+
+	nv_debug(parent, "attached %s context\n", subdev->name);
+	return 0;
+}
+
+int
+nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend)
+{
+	struct nvkm_object *object = nv_object(engctx);
+	struct nvkm_subdev *subdev = nv_subdev(object->engine);
+	struct nvkm_object *parent;
+	struct nvkm_subdev *pardev;
+	int ret = 0;
+
+	parent = nv_pclass(object->parent, NV_PARENT_CLASS);
+	pardev = nv_subdev(parent->engine);
+	if (nv_parent(parent)->context_detach) {
+		mutex_lock(&pardev->mutex);
+		ret = nv_parent(parent)->context_detach(parent, suspend, object);
+		mutex_unlock(&pardev->mutex);
+	}
+
+	if (ret) {
+		nv_error(parent, "failed to detach %s context, %d\n",
+			 subdev->name, ret);
+		return ret;
+	}
+
+	nv_debug(parent, "detached %s context\n", subdev->name);
+	return nvkm_gpuobj_fini(&engctx->gpuobj, suspend);
+}
+
+int
+_nvkm_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_engctx *engctx;
+	int ret;
+
+	ret = nvkm_engctx_create(parent, engine, oclass, NULL, 256, 256,
+				 NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+	*pobject = nv_object(engctx);
+	return ret;
+}
+
+void
+_nvkm_engctx_dtor(struct nvkm_object *object)
+{
+	nvkm_engctx_destroy(nv_engctx(object));
+}
+
+int
+_nvkm_engctx_init(struct nvkm_object *object)
+{
+	return nvkm_engctx_init(nv_engctx(object));
+}
+
+int
+_nvkm_engctx_fini(struct nvkm_object *object, bool suspend)
+{
+	return nvkm_engctx_fini(nv_engctx(object), suspend);
+}
+
+struct nvkm_object *
+nvkm_engctx_get(struct nvkm_engine *engine, u64 addr)
+{
+	struct nvkm_engctx *engctx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&engine->lock, flags);
+	list_for_each_entry(engctx, &engine->contexts, head) {
+		if (engctx->addr == addr) {
+			engctx->save = flags;
+			return nv_object(engctx);
+		}
+	}
+	spin_unlock_irqrestore(&engine->lock, flags);
+	return NULL;
+}
+
+void
+nvkm_engctx_put(struct nvkm_object *object)
+{
+	if (object) {
+		struct nvkm_engine *engine = nv_engine(object->engine);
+		struct nvkm_engctx *engctx = nv_engctx(object);
+		spin_unlock_irqrestore(&engine->lock, engctx->save);
+	}
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
new file mode 100644
index 0000000..6082017
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/engine.h>
+#include <core/device.h>
+#include <core/option.h>
+
+struct nvkm_engine *
+nvkm_engine(void *obj, int idx)
+{
+	obj = nvkm_subdev(obj, idx);
+	if (obj && nv_iclass(obj, NV_ENGINE_CLASS))
+		return nv_engine(obj);
+	return NULL;
+}
+
+int
+nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj,
+		    struct nvkm_oclass *oclass, bool enable,
+		    const char *iname, const char *fname,
+		    int length, void **pobject)
+{
+	struct nvkm_engine *engine;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
+				  iname, fname, length, pobject);
+	engine = *pobject;
+	if (ret)
+		return ret;
+
+	if (parent) {
+		struct nvkm_device *device = nv_device(parent);
+		int engidx = nv_engidx(engine);
+
+		if (device->disable_mask & (1ULL << engidx)) {
+			if (!nvkm_boolopt(device->cfgopt, iname, false)) {
+				nv_debug(engine, "engine disabled by hw/fw\n");
+				return -ENODEV;
+			}
+
+			nv_warn(engine, "ignoring hw/fw engine disable\n");
+		}
+
+		if (!nvkm_boolopt(device->cfgopt, iname, enable)) {
+			if (!enable)
+				nv_warn(engine, "disabled, %s=1 to enable\n", iname);
+			return -ENODEV;
+		}
+	}
+
+	INIT_LIST_HEAD(&engine->contexts);
+	spin_lock_init(&engine->lock);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c
new file mode 100644
index 0000000..4f92bfc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Nouveau Project
+ *
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include <core/enum.h>
+
+const struct nvkm_enum *
+nvkm_enum_find(const struct nvkm_enum *en, u32 value)
+{
+	while (en->name) {
+		if (en->value == value)
+			return en;
+		en++;
+	}
+
+	return NULL;
+}
+
+const struct nvkm_enum *
+nvkm_enum_print(const struct nvkm_enum *en, u32 value)
+{
+	en = nvkm_enum_find(en, value);
+	if (en)
+		pr_cont("%s", en->name);
+	else
+		pr_cont("(unknown enum 0x%08x)", value);
+	return en;
+}
+
+void
+nvkm_bitfield_print(const struct nvkm_bitfield *bf, u32 value)
+{
+	while (bf->name) {
+		if (value & bf->mask) {
+			pr_cont(" %s", bf->name);
+			value &= ~bf->mask;
+		}
+
+		bf++;
+	}
+
+	if (value)
+		pr_cont(" (unknown bits 0x%08x)", value);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c
new file mode 100644
index 0000000..4e8d3fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013-2014 Red Hat 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 <core/event.h>
+#include <core/notify.h>
+
+void
+nvkm_event_put(struct nvkm_event *event, u32 types, int index)
+{
+	assert_spin_locked(&event->refs_lock);
+	while (types) {
+		int type = __ffs(types); types &= ~(1 << type);
+		if (--event->refs[index * event->types_nr + type] == 0) {
+			if (event->func->fini)
+				event->func->fini(event, 1 << type, index);
+		}
+	}
+}
+
+void
+nvkm_event_get(struct nvkm_event *event, u32 types, int index)
+{
+	assert_spin_locked(&event->refs_lock);
+	while (types) {
+		int type = __ffs(types); types &= ~(1 << type);
+		if (++event->refs[index * event->types_nr + type] == 1) {
+			if (event->func->init)
+				event->func->init(event, 1 << type, index);
+		}
+	}
+}
+
+void
+nvkm_event_send(struct nvkm_event *event, u32 types, int index,
+		void *data, u32 size)
+{
+	struct nvkm_notify *notify;
+	unsigned long flags;
+
+	if (!event->refs || WARN_ON(index >= event->index_nr))
+		return;
+
+	spin_lock_irqsave(&event->list_lock, flags);
+	list_for_each_entry(notify, &event->list, head) {
+		if (notify->index == index && (notify->types & types)) {
+			if (event->func->send) {
+				event->func->send(data, size, notify);
+				continue;
+			}
+			nvkm_notify_send(notify, data, size);
+		}
+	}
+	spin_unlock_irqrestore(&event->list_lock, flags);
+}
+
+void
+nvkm_event_fini(struct nvkm_event *event)
+{
+	if (event->refs) {
+		kfree(event->refs);
+		event->refs = NULL;
+	}
+}
+
+int
+nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
+		struct nvkm_event *event)
+{
+	event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
+			      GFP_KERNEL);
+	if (!event->refs)
+		return -ENOMEM;
+
+	event->func = func;
+	event->types_nr = types_nr;
+	event->index_nr = index_nr;
+	spin_lock_init(&event->refs_lock);
+	spin_lock_init(&event->list_lock);
+	INIT_LIST_HEAD(&event->list);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c
new file mode 100644
index 0000000..2eba801
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/gpuobj.h>
+#include <core/engine.h>
+
+#include <subdev/instmem.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+
+void
+nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj)
+{
+	int i;
+
+	if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, 0x00000000);
+	}
+
+	if (gpuobj->node)
+		nvkm_mm_free(&nv_gpuobj(gpuobj->parent)->heap, &gpuobj->node);
+
+	if (gpuobj->heap.block_size)
+		nvkm_mm_fini(&gpuobj->heap);
+
+	nvkm_object_destroy(&gpuobj->object);
+}
+
+int
+nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 pclass,
+		    struct nvkm_object *pargpu, u32 size, u32 align, u32 flags,
+		    int length, void **pobject)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(parent);
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nvkm_gpuobj *gpuobj;
+	struct nvkm_mm *heap = NULL;
+	int ret, i;
+	u64 addr;
+
+	*pobject = NULL;
+
+	if (pargpu) {
+		while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
+			if (nv_gpuobj(pargpu)->heap.block_size)
+				break;
+			pargpu = pargpu->parent;
+		}
+
+		if (unlikely(pargpu == NULL)) {
+			nv_error(parent, "no gpuobj heap\n");
+			return -EINVAL;
+		}
+
+		addr =  nv_gpuobj(pargpu)->addr;
+		heap = &nv_gpuobj(pargpu)->heap;
+		atomic_inc(&parent->refcount);
+	} else {
+		ret = imem->alloc(imem, parent, size, align, &parent);
+		pargpu = parent;
+		if (ret)
+			return ret;
+
+		addr = nv_memobj(pargpu)->addr;
+		size = nv_memobj(pargpu)->size;
+
+		if (bar && bar->alloc) {
+			struct nvkm_instobj *iobj = (void *)parent;
+			struct nvkm_mem **mem = (void *)(iobj + 1);
+			struct nvkm_mem *node = *mem;
+			if (!bar->alloc(bar, parent, node, &pargpu)) {
+				nvkm_object_ref(NULL, &parent);
+				parent = pargpu;
+			}
+		}
+	}
+
+	ret = nvkm_object_create_(parent, engine, oclass, pclass |
+				  NV_GPUOBJ_CLASS, length, pobject);
+	nvkm_object_ref(NULL, &parent);
+	gpuobj = *pobject;
+	if (ret)
+		return ret;
+
+	gpuobj->parent = pargpu;
+	gpuobj->flags = flags;
+	gpuobj->addr = addr;
+	gpuobj->size = size;
+
+	if (heap) {
+		ret = nvkm_mm_head(heap, 0, 1, size, size, max(align, (u32)1),
+				   &gpuobj->node);
+		if (ret)
+			return ret;
+
+		gpuobj->addr += gpuobj->node->offset;
+	}
+
+	if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
+		ret = nvkm_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
+		if (ret)
+			return ret;
+	}
+
+	if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, 0x00000000);
+	}
+
+	return ret;
+}
+
+struct nvkm_gpuobj_class {
+	struct nvkm_object *pargpu;
+	u64 size;
+	u32 align;
+	u32 flags;
+};
+
+static int
+_nvkm_gpuobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj_class *args = data;
+	struct nvkm_gpuobj *object;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
+				 args->size, args->align, args->flags,
+				 &object);
+	*pobject = nv_object(object);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void
+_nvkm_gpuobj_dtor(struct nvkm_object *object)
+{
+	nvkm_gpuobj_destroy(nv_gpuobj(object));
+}
+
+int
+_nvkm_gpuobj_init(struct nvkm_object *object)
+{
+	return nvkm_gpuobj_init(nv_gpuobj(object));
+}
+
+int
+_nvkm_gpuobj_fini(struct nvkm_object *object, bool suspend)
+{
+	return nvkm_gpuobj_fini(nv_gpuobj(object), suspend);
+}
+
+u32
+_nvkm_gpuobj_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_gpuobj *gpuobj = nv_gpuobj(object);
+	struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
+	if (gpuobj->node)
+		addr += gpuobj->node->offset;
+	return pfuncs->rd32(gpuobj->parent, addr);
+}
+
+void
+_nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_gpuobj *gpuobj = nv_gpuobj(object);
+	struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
+	if (gpuobj->node)
+		addr += gpuobj->node->offset;
+	pfuncs->wr32(gpuobj->parent, addr, data);
+}
+
+static struct nvkm_oclass
+_nvkm_gpuobj_oclass = {
+	.handle = 0x00000000,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpuobj_ctor,
+		.dtor = _nvkm_gpuobj_dtor,
+		.init = _nvkm_gpuobj_init,
+		.fini = _nvkm_gpuobj_fini,
+		.rd32 = _nvkm_gpuobj_rd32,
+		.wr32 = _nvkm_gpuobj_wr32,
+	},
+};
+
+int
+nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu,
+		u32 size, u32 align, u32 flags,
+		struct nvkm_gpuobj **pgpuobj)
+{
+	struct nvkm_object *engine = parent;
+	struct nvkm_gpuobj_class args = {
+		.pargpu = pargpu,
+		.size = size,
+		.align = align,
+		.flags = flags,
+	};
+
+	if (!nv_iclass(engine, NV_SUBDEV_CLASS))
+		engine = &engine->engine->subdev.object;
+	BUG_ON(engine == NULL);
+
+	return nvkm_object_ctor(parent, engine, &_nvkm_gpuobj_oclass,
+				&args, sizeof(args),
+				(struct nvkm_object **)pgpuobj);
+}
+
+int
+nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, u32 access, struct nvkm_vma *vma)
+{
+	struct nvkm_bar *bar = nvkm_bar(gpuobj);
+	int ret = -EINVAL;
+
+	if (bar && bar->umap) {
+		struct nvkm_instobj *iobj = (void *)
+			nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
+		struct nvkm_mem **mem = (void *)(iobj + 1);
+		ret = bar->umap(bar, *mem, access, vma);
+	}
+
+	return ret;
+}
+
+int
+nvkm_gpuobj_map_vm(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm,
+		   u32 access, struct nvkm_vma *vma)
+{
+	struct nvkm_instobj *iobj = (void *)
+		nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
+	struct nvkm_mem **mem = (void *)(iobj + 1);
+	int ret;
+
+	ret = nvkm_vm_get(vm, gpuobj->size, 12, access, vma);
+	if (ret)
+		return ret;
+
+	nvkm_vm_map(vma, *mem);
+	return 0;
+}
+
+void
+nvkm_gpuobj_unmap(struct nvkm_vma *vma)
+{
+	if (vma->node) {
+		nvkm_vm_unmap(vma);
+		nvkm_vm_put(vma);
+	}
+}
+
+/* the below is basically only here to support sharing the paged dma object
+ * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
+ * anywhere else.
+ */
+
+static void
+nvkm_gpudup_dtor(struct nvkm_object *object)
+{
+	struct nvkm_gpuobj *gpuobj = (void *)object;
+	nvkm_object_ref(NULL, &gpuobj->parent);
+	nvkm_object_destroy(&gpuobj->object);
+}
+
+static struct nvkm_oclass
+nvkm_gpudup_oclass = {
+	.handle = NV_GPUOBJ_CLASS,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.dtor = nvkm_gpudup_dtor,
+		.init = nvkm_object_init,
+		.fini = nvkm_object_fini,
+	},
+};
+
+int
+nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_gpuobj *base,
+		struct nvkm_gpuobj **pgpuobj)
+{
+	struct nvkm_gpuobj *gpuobj;
+	int ret;
+
+	ret = nvkm_object_create(parent, &parent->engine->subdev.object,
+				 &nvkm_gpudup_oclass, 0, &gpuobj);
+	*pgpuobj = gpuobj;
+	if (ret)
+		return ret;
+
+	nvkm_object_ref(nv_object(base), &gpuobj->parent);
+	gpuobj->addr = base->addr;
+	gpuobj->size = base->size;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c
new file mode 100644
index 0000000..dc7ff10
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/handle.h>
+#include <core/client.h>
+
+#define hprintk(h,l,f,a...) do {                                               \
+	struct nvkm_client *c = nvkm_client((h)->object);                      \
+	struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0;         \
+	nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a);               \
+} while(0)
+
+int
+nvkm_handle_init(struct nvkm_handle *handle)
+{
+	struct nvkm_handle *item;
+	int ret;
+
+	hprintk(handle, TRACE, "init running\n");
+	ret = nvkm_object_inc(handle->object);
+	if (ret)
+		return ret;
+
+	hprintk(handle, TRACE, "init children\n");
+	list_for_each_entry(item, &handle->tree, head) {
+		ret = nvkm_handle_init(item);
+		if (ret)
+			goto fail;
+	}
+
+	hprintk(handle, TRACE, "init completed\n");
+	return 0;
+fail:
+	hprintk(handle, ERROR, "init failed with %d\n", ret);
+	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
+		nvkm_handle_fini(item, false);
+	}
+
+	nvkm_object_dec(handle->object, false);
+	return ret;
+}
+
+int
+nvkm_handle_fini(struct nvkm_handle *handle, bool suspend)
+{
+	static char *name[2] = { "fini", "suspend" };
+	struct nvkm_handle *item;
+	int ret;
+
+	hprintk(handle, TRACE, "%s children\n", name[suspend]);
+	list_for_each_entry(item, &handle->tree, head) {
+		ret = nvkm_handle_fini(item, suspend);
+		if (ret && suspend)
+			goto fail;
+	}
+
+	hprintk(handle, TRACE, "%s running\n", name[suspend]);
+	if (handle->object) {
+		ret = nvkm_object_dec(handle->object, suspend);
+		if (ret && suspend)
+			goto fail;
+	}
+
+	hprintk(handle, TRACE, "%s completed\n", name[suspend]);
+	return 0;
+fail:
+	hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
+	list_for_each_entry_continue_reverse(item, &handle->tree, head) {
+		int rret = nvkm_handle_init(item);
+		if (rret)
+			hprintk(handle, FATAL, "failed to restart, %d\n", rret);
+	}
+
+	return ret;
+}
+
+int
+nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle,
+		   struct nvkm_object *object, struct nvkm_handle **phandle)
+{
+	struct nvkm_object *namedb;
+	struct nvkm_handle *handle;
+	int ret;
+
+	namedb = parent;
+	while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
+		namedb = namedb->parent;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&handle->head);
+	INIT_LIST_HEAD(&handle->tree);
+	handle->name = _handle;
+	handle->priv = ~0;
+
+	ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle);
+	if (ret) {
+		kfree(handle);
+		return ret;
+	}
+
+	if (nv_parent(parent)->object_attach) {
+		ret = nv_parent(parent)->object_attach(parent, object, _handle);
+		if (ret < 0) {
+			nvkm_handle_destroy(handle);
+			return ret;
+		}
+
+		handle->priv = ret;
+	}
+
+	if (object != namedb) {
+		while (!nv_iclass(namedb, NV_CLIENT_CLASS))
+			namedb = namedb->parent;
+
+		handle->parent = nvkm_namedb_get(nv_namedb(namedb), _parent);
+		if (handle->parent) {
+			list_add(&handle->head, &handle->parent->tree);
+			nvkm_namedb_put(handle->parent);
+		}
+	}
+
+	hprintk(handle, TRACE, "created\n");
+	*phandle = handle;
+	return 0;
+}
+
+void
+nvkm_handle_destroy(struct nvkm_handle *handle)
+{
+	struct nvkm_handle *item, *temp;
+
+	hprintk(handle, TRACE, "destroy running\n");
+	list_for_each_entry_safe(item, temp, &handle->tree, head) {
+		nvkm_handle_destroy(item);
+	}
+	list_del(&handle->head);
+
+	if (handle->priv != ~0) {
+		struct nvkm_object *parent = handle->parent->object;
+		nv_parent(parent)->object_detach(parent, handle->priv);
+	}
+
+	hprintk(handle, TRACE, "destroy completed\n");
+	nvkm_namedb_remove(handle);
+	kfree(handle);
+}
+
+struct nvkm_object *
+nvkm_handle_ref(struct nvkm_object *parent, u32 name)
+{
+	struct nvkm_object *object = NULL;
+	struct nvkm_handle *handle;
+
+	while (!nv_iclass(parent, NV_NAMEDB_CLASS))
+		parent = parent->parent;
+
+	handle = nvkm_namedb_get(nv_namedb(parent), name);
+	if (handle) {
+		nvkm_object_ref(handle->object, &object);
+		nvkm_namedb_put(handle);
+	}
+
+	return object;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_class(struct nvkm_object *engctx, u16 oclass)
+{
+	struct nvkm_namedb *namedb;
+	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+		return nvkm_namedb_get_class(namedb, oclass);
+	return NULL;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_vinst(struct nvkm_object *engctx, u64 vinst)
+{
+	struct nvkm_namedb *namedb;
+	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+		return nvkm_namedb_get_vinst(namedb, vinst);
+	return NULL;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_cinst(struct nvkm_object *engctx, u32 cinst)
+{
+	struct nvkm_namedb *namedb;
+	if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+		return nvkm_namedb_get_cinst(namedb, cinst);
+	return NULL;
+}
+
+void
+nvkm_handle_put(struct nvkm_handle *handle)
+{
+	if (handle)
+		nvkm_namedb_put(handle);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
new file mode 100644
index 0000000..4459ff5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <core/ioctl.h>
+#include <core/client.h>
+#include <core/engine.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+
+#include <nvif/unpack.h>
+#include <nvif/ioctl.h>
+
+static int
+nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_nop none;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "nop size %d\n", size);
+	if (nvif_unvers(args->none)) {
+		nv_ioctl(object, "nop\n");
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_sclass_v0 v0;
+	} *args = data;
+	int ret;
+
+	if (!nv_iclass(object, NV_PARENT_CLASS)) {
+		nv_debug(object, "cannot have children (sclass)\n");
+		return -ENODEV;
+	}
+
+	nv_ioctl(object, "sclass size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "sclass vers %d count %d\n",
+			 args->v0.version, args->v0.count);
+		if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
+			ret = nvkm_parent_lclass(object, args->v0.oclass,
+							 args->v0.count);
+			if (ret >= 0) {
+				args->v0.count = ret;
+				ret = 0;
+			}
+		} else {
+			ret = -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size)
+{
+	union {
+		struct nvif_ioctl_new_v0 v0;
+	} *args = data;
+	struct nvkm_client *client = nvkm_client(handle->object);
+	struct nvkm_object *engctx = NULL;
+	struct nvkm_object *object = NULL;
+	struct nvkm_parent *parent;
+	struct nvkm_object *engine;
+	struct nvkm_oclass *oclass;
+	u32 _handle, _oclass;
+	int ret;
+
+	nv_ioctl(client, "new size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		_handle = args->v0.handle;
+		_oclass = args->v0.oclass;
+	} else
+		return ret;
+
+	nv_ioctl(client, "new vers %d handle %08x class %08x "
+			 "route %02x token %llx\n",
+		 args->v0.version, _handle, _oclass,
+		 args->v0.route, args->v0.token);
+
+	if (!nv_iclass(handle->object, NV_PARENT_CLASS)) {
+		nv_debug(handle->object, "cannot have children (ctor)\n");
+		ret = -ENODEV;
+		goto fail_class;
+	}
+
+	parent = nv_parent(handle->object);
+
+	/* check that parent supports the requested subclass */
+	ret = nvkm_parent_sclass(&parent->object, _oclass, &engine, &oclass);
+	if (ret) {
+		nv_debug(parent, "illegal class 0x%04x\n", _oclass);
+		goto fail_class;
+	}
+
+	/* make sure engine init has been completed *before* any objects
+	 * it controls are created - the constructors may depend on
+	 * state calculated at init (ie. default context construction)
+	 */
+	if (engine) {
+		ret = nvkm_object_inc(engine);
+		if (ret)
+			goto fail_class;
+	}
+
+	/* if engine requires it, create a context object to insert
+	 * between the parent and its children (eg. PGRAPH context)
+	 */
+	if (engine && nv_engine(engine)->cclass) {
+		ret = nvkm_object_ctor(&parent->object, engine,
+				       nv_engine(engine)->cclass,
+				       data, size, &engctx);
+		if (ret)
+			goto fail_engctx;
+	} else {
+		nvkm_object_ref(&parent->object, &engctx);
+	}
+
+	/* finally, create new object and bind it to its handle */
+	ret = nvkm_object_ctor(engctx, engine, oclass, data, size, &object);
+	client->data = object;
+	if (ret)
+		goto fail_ctor;
+
+	ret = nvkm_object_inc(object);
+	if (ret)
+		goto fail_init;
+
+	ret = nvkm_handle_create(&parent->object, handle->name,
+				 _handle, object, &handle);
+	if (ret)
+		goto fail_handle;
+
+	ret = nvkm_handle_init(handle);
+	handle->route = args->v0.route;
+	handle->token = args->v0.token;
+	if (ret)
+		nvkm_handle_destroy(handle);
+
+fail_handle:
+	nvkm_object_dec(object, false);
+fail_init:
+	nvkm_object_ref(NULL, &object);
+fail_ctor:
+	nvkm_object_ref(NULL, &engctx);
+fail_engctx:
+	if (engine)
+		nvkm_object_dec(engine, false);
+fail_class:
+	return ret;
+}
+
+static int
+nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_del none;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "delete size %d\n", size);
+	if (nvif_unvers(args->none)) {
+		nv_ioctl(object, "delete\n");
+		nvkm_handle_fini(handle, false);
+		nvkm_handle_destroy(handle);
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+	union {
+		struct nvif_ioctl_mthd_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "mthd size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "mthd vers %d mthd %02x\n",
+			 args->v0.version, args->v0.method);
+		if (ret = -ENODEV, ofuncs->mthd)
+			ret = ofuncs->mthd(object, args->v0.method, data, size);
+	}
+
+	return ret;
+}
+
+
+static int
+nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+	union {
+		struct nvif_ioctl_rd_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "rd size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
+			 args->v0.version, args->v0.size, args->v0.addr);
+		switch (args->v0.size) {
+		case 1:
+			if (ret = -ENODEV, ofuncs->rd08) {
+				args->v0.data = nv_ro08(object, args->v0.addr);
+				ret = 0;
+			}
+			break;
+		case 2:
+			if (ret = -ENODEV, ofuncs->rd16) {
+				args->v0.data = nv_ro16(object, args->v0.addr);
+				ret = 0;
+			}
+			break;
+		case 4:
+			if (ret = -ENODEV, ofuncs->rd32) {
+				args->v0.data = nv_ro32(object, args->v0.addr);
+				ret = 0;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+	union {
+		struct nvif_ioctl_wr_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "wr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
+			 args->v0.version, args->v0.size, args->v0.addr,
+			 args->v0.data);
+		switch (args->v0.size) {
+		case 1:
+			if (ret = -ENODEV, ofuncs->wr08) {
+				nv_wo08(object, args->v0.addr, args->v0.data);
+				ret = 0;
+			}
+			break;
+		case 2:
+			if (ret = -ENODEV, ofuncs->wr16) {
+				nv_wo16(object, args->v0.addr, args->v0.data);
+				ret = 0;
+			}
+			break;
+		case 4:
+			if (ret = -ENODEV, ofuncs->wr32) {
+				nv_wo32(object, args->v0.addr, args->v0.data);
+				ret = 0;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+	union {
+		struct nvif_ioctl_map_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "map size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "map vers %d\n", args->v0.version);
+		if (ret = -ENODEV, ofuncs->map) {
+			ret = ofuncs->map(object, &args->v0.handle,
+						  &args->v0.length);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_unmap(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_unmap none;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "unmap size %d\n", size);
+	if (nvif_unvers(args->none)) {
+		nv_ioctl(object, "unmap\n");
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_object *object = handle->object;
+	struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+	union {
+		struct nvif_ioctl_ntfy_new_v0 v0;
+	} *args = data;
+	struct nvkm_event *event;
+	int ret;
+
+	nv_ioctl(object, "ntfy new size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "ntfy new vers %d event %02x\n",
+			 args->v0.version, args->v0.event);
+		if (ret = -ENODEV, ofuncs->ntfy)
+			ret = ofuncs->ntfy(object, args->v0.event, &event);
+		if (ret == 0) {
+			ret = nvkm_client_notify_new(object, event, data, size);
+			if (ret >= 0) {
+				args->v0.index = ret;
+				ret = 0;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_del(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_client *client = nvkm_client(handle->object);
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_ntfy_del_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "ntfy del size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "ntfy del vers %d index %d\n",
+			 args->v0.version, args->v0.index);
+		ret = nvkm_client_notify_del(client, args->v0.index);
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_get(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_client *client = nvkm_client(handle->object);
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_ntfy_get_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "ntfy get size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "ntfy get vers %d index %d\n",
+			 args->v0.version, args->v0.index);
+		ret = nvkm_client_notify_get(client, args->v0.index);
+	}
+
+	return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_put(struct nvkm_handle *handle, void *data, u32 size)
+{
+	struct nvkm_client *client = nvkm_client(handle->object);
+	struct nvkm_object *object = handle->object;
+	union {
+		struct nvif_ioctl_ntfy_put_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "ntfy put size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "ntfy put vers %d index %d\n",
+			 args->v0.version, args->v0.index);
+		ret = nvkm_client_notify_put(client, args->v0.index);
+	}
+
+	return ret;
+}
+
+static struct {
+	int version;
+	int (*func)(struct nvkm_handle *, void *, u32);
+}
+nvkm_ioctl_v0[] = {
+	{ 0x00, nvkm_ioctl_nop },
+	{ 0x00, nvkm_ioctl_sclass },
+	{ 0x00, nvkm_ioctl_new },
+	{ 0x00, nvkm_ioctl_del },
+	{ 0x00, nvkm_ioctl_mthd },
+	{ 0x00, nvkm_ioctl_rd },
+	{ 0x00, nvkm_ioctl_wr },
+	{ 0x00, nvkm_ioctl_map },
+	{ 0x00, nvkm_ioctl_unmap },
+	{ 0x00, nvkm_ioctl_ntfy_new },
+	{ 0x00, nvkm_ioctl_ntfy_del },
+	{ 0x00, nvkm_ioctl_ntfy_get },
+	{ 0x00, nvkm_ioctl_ntfy_put },
+};
+
+static int
+nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path,
+		void *data, u32 size, u8 owner, u8 *route, u64 *token)
+{
+	struct nvkm_handle *handle = parent;
+	struct nvkm_namedb *namedb;
+	struct nvkm_object *object;
+	int ret;
+
+	while ((object = parent->object), nr--) {
+		nv_ioctl(object, "path 0x%08x\n", path[nr]);
+		if (!nv_iclass(object, NV_PARENT_CLASS)) {
+			nv_debug(object, "cannot have children (path)\n");
+			return -EINVAL;
+		}
+
+		if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
+		    !(handle = nvkm_namedb_get(namedb, path[nr]))) {
+			nv_debug(object, "handle 0x%08x not found\n", path[nr]);
+			return -ENOENT;
+		}
+		nvkm_namedb_put(handle);
+		parent = handle;
+	}
+
+	if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != handle->route) {
+		nv_ioctl(object, "object route != owner\n");
+		return -EACCES;
+	}
+	*route = handle->route;
+	*token = handle->token;
+
+	if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
+		if (nvkm_ioctl_v0[type].version == 0)
+			ret = nvkm_ioctl_v0[type].func(handle, data, size);
+	}
+
+	return ret;
+}
+
+int
+nvkm_ioctl(struct nvkm_client *client, bool supervisor,
+	   void *data, u32 size, void **hack)
+{
+	union {
+		struct nvif_ioctl_v0 v0;
+	} *args = data;
+	int ret;
+
+	client->super = supervisor;
+	nv_ioctl(client, "size %d\n", size);
+
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
+			 args->v0.version, args->v0.type, args->v0.path_nr,
+			 args->v0.owner);
+		ret = nvkm_ioctl_path(client->root, args->v0.type,
+				      args->v0.path_nr, args->v0.path,
+				      data, size, args->v0.owner,
+				      &args->v0.route, &args->v0.token);
+	}
+
+	nv_ioctl(client, "return %d\n", ret);
+	if (hack) {
+		*hack = client->data;
+		client->data = NULL;
+	}
+
+	client->super = false;
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/mm.c b/drivers/gpu/drm/nouveau/nvkm/core/mm.c
new file mode 100644
index 0000000..7f458df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/mm.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/mm.h>
+
+#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL :          \
+	list_entry((root)->nl_entry.dir, struct nvkm_mm_node, nl_entry)
+
+static void
+nvkm_mm_dump(struct nvkm_mm *mm, const char *header)
+{
+	struct nvkm_mm_node *node;
+
+	printk(KERN_ERR "nvkm: %s\n", header);
+	printk(KERN_ERR "nvkm: node list:\n");
+	list_for_each_entry(node, &mm->nodes, nl_entry) {
+		printk(KERN_ERR "nvkm: \t%08x %08x %d\n",
+		       node->offset, node->length, node->type);
+	}
+	printk(KERN_ERR "nvkm: free list:\n");
+	list_for_each_entry(node, &mm->free, fl_entry) {
+		printk(KERN_ERR "nvkm: \t%08x %08x %d\n",
+		       node->offset, node->length, node->type);
+	}
+}
+
+void
+nvkm_mm_free(struct nvkm_mm *mm, struct nvkm_mm_node **pthis)
+{
+	struct nvkm_mm_node *this = *pthis;
+
+	if (this) {
+		struct nvkm_mm_node *prev = node(this, prev);
+		struct nvkm_mm_node *next = node(this, next);
+
+		if (prev && prev->type == NVKM_MM_TYPE_NONE) {
+			prev->length += this->length;
+			list_del(&this->nl_entry);
+			kfree(this); this = prev;
+		}
+
+		if (next && next->type == NVKM_MM_TYPE_NONE) {
+			next->offset  = this->offset;
+			next->length += this->length;
+			if (this->type == NVKM_MM_TYPE_NONE)
+				list_del(&this->fl_entry);
+			list_del(&this->nl_entry);
+			kfree(this); this = NULL;
+		}
+
+		if (this && this->type != NVKM_MM_TYPE_NONE) {
+			list_for_each_entry(prev, &mm->free, fl_entry) {
+				if (this->offset < prev->offset)
+					break;
+			}
+
+			list_add_tail(&this->fl_entry, &prev->fl_entry);
+			this->type = NVKM_MM_TYPE_NONE;
+		}
+	}
+
+	*pthis = NULL;
+}
+
+static struct nvkm_mm_node *
+region_head(struct nvkm_mm *mm, struct nvkm_mm_node *a, u32 size)
+{
+	struct nvkm_mm_node *b;
+
+	if (a->length == size)
+		return a;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (unlikely(b == NULL))
+		return NULL;
+
+	b->offset = a->offset;
+	b->length = size;
+	b->heap   = a->heap;
+	b->type   = a->type;
+	a->offset += size;
+	a->length -= size;
+	list_add_tail(&b->nl_entry, &a->nl_entry);
+	if (b->type == NVKM_MM_TYPE_NONE)
+		list_add_tail(&b->fl_entry, &a->fl_entry);
+
+	return b;
+}
+
+int
+nvkm_mm_head(struct nvkm_mm *mm, u8 heap, u8 type, u32 size_max, u32 size_min,
+	     u32 align, struct nvkm_mm_node **pnode)
+{
+	struct nvkm_mm_node *prev, *this, *next;
+	u32 mask = align - 1;
+	u32 splitoff;
+	u32 s, e;
+
+	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
+
+	list_for_each_entry(this, &mm->free, fl_entry) {
+		if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+			if (this->heap != heap)
+				continue;
+		}
+		e = this->offset + this->length;
+		s = this->offset;
+
+		prev = node(this, prev);
+		if (prev && prev->type != type)
+			s = roundup(s, mm->block_size);
+
+		next = node(this, next);
+		if (next && next->type != type)
+			e = rounddown(e, mm->block_size);
+
+		s  = (s + mask) & ~mask;
+		e &= ~mask;
+		if (s > e || e - s < size_min)
+			continue;
+
+		splitoff = s - this->offset;
+		if (splitoff && !region_head(mm, this, splitoff))
+			return -ENOMEM;
+
+		this = region_head(mm, this, min(size_max, e - s));
+		if (!this)
+			return -ENOMEM;
+
+		this->type = type;
+		list_del(&this->fl_entry);
+		*pnode = this;
+		return 0;
+	}
+
+	return -ENOSPC;
+}
+
+static struct nvkm_mm_node *
+region_tail(struct nvkm_mm *mm, struct nvkm_mm_node *a, u32 size)
+{
+	struct nvkm_mm_node *b;
+
+	if (a->length == size)
+		return a;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (unlikely(b == NULL))
+		return NULL;
+
+	a->length -= size;
+	b->offset  = a->offset + a->length;
+	b->length  = size;
+	b->heap    = a->heap;
+	b->type    = a->type;
+
+	list_add(&b->nl_entry, &a->nl_entry);
+	if (b->type == NVKM_MM_TYPE_NONE)
+		list_add(&b->fl_entry, &a->fl_entry);
+
+	return b;
+}
+
+int
+nvkm_mm_tail(struct nvkm_mm *mm, u8 heap, u8 type, u32 size_max, u32 size_min,
+	     u32 align, struct nvkm_mm_node **pnode)
+{
+	struct nvkm_mm_node *prev, *this, *next;
+	u32 mask = align - 1;
+
+	BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
+
+	list_for_each_entry_reverse(this, &mm->free, fl_entry) {
+		u32 e = this->offset + this->length;
+		u32 s = this->offset;
+		u32 c = 0, a;
+		if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+			if (this->heap != heap)
+				continue;
+		}
+
+		prev = node(this, prev);
+		if (prev && prev->type != type)
+			s = roundup(s, mm->block_size);
+
+		next = node(this, next);
+		if (next && next->type != type) {
+			e = rounddown(e, mm->block_size);
+			c = next->offset - e;
+		}
+
+		s = (s + mask) & ~mask;
+		a = e - s;
+		if (s > e || a < size_min)
+			continue;
+
+		a  = min(a, size_max);
+		s  = (e - a) & ~mask;
+		c += (e - s) - a;
+
+		if (c && !region_tail(mm, this, c))
+			return -ENOMEM;
+
+		this = region_tail(mm, this, a);
+		if (!this)
+			return -ENOMEM;
+
+		this->type = type;
+		list_del(&this->fl_entry);
+		*pnode = this;
+		return 0;
+	}
+
+	return -ENOSPC;
+}
+
+int
+nvkm_mm_init(struct nvkm_mm *mm, u32 offset, u32 length, u32 block)
+{
+	struct nvkm_mm_node *node, *prev;
+	u32 next;
+
+	if (nvkm_mm_initialised(mm)) {
+		prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
+		next = prev->offset + prev->length;
+		if (next != offset) {
+			BUG_ON(next > offset);
+			if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
+				return -ENOMEM;
+			node->type   = NVKM_MM_TYPE_HOLE;
+			node->offset = next;
+			node->length = offset - next;
+			list_add_tail(&node->nl_entry, &mm->nodes);
+		}
+		BUG_ON(block != mm->block_size);
+	} else {
+		INIT_LIST_HEAD(&mm->nodes);
+		INIT_LIST_HEAD(&mm->free);
+		mm->block_size = block;
+		mm->heap_nodes = 0;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	if (length) {
+		node->offset  = roundup(offset, mm->block_size);
+		node->length  = rounddown(offset + length, mm->block_size);
+		node->length -= node->offset;
+	}
+
+	list_add_tail(&node->nl_entry, &mm->nodes);
+	list_add_tail(&node->fl_entry, &mm->free);
+	node->heap = ++mm->heap_nodes;
+	return 0;
+}
+
+int
+nvkm_mm_fini(struct nvkm_mm *mm)
+{
+	struct nvkm_mm_node *node, *temp;
+	int nodes = 0;
+
+	if (!nvkm_mm_initialised(mm))
+		return 0;
+
+	list_for_each_entry(node, &mm->nodes, nl_entry) {
+		if (node->type != NVKM_MM_TYPE_HOLE) {
+			if (++nodes > mm->heap_nodes) {
+				nvkm_mm_dump(mm, "mm not clean!");
+				return -EBUSY;
+			}
+		}
+	}
+
+	list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
+		list_del(&node->nl_entry);
+		kfree(node);
+	}
+
+	mm->heap_nodes = 0;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c
new file mode 100644
index 0000000..6400767
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/namedb.h>
+#include <core/gpuobj.h>
+#include <core/handle.h>
+
+static struct nvkm_handle *
+nvkm_namedb_lookup(struct nvkm_namedb *namedb, u32 name)
+{
+	struct nvkm_handle *handle;
+
+	list_for_each_entry(handle, &namedb->list, node) {
+		if (handle->name == name)
+			return handle;
+	}
+
+	return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, u16 oclass)
+{
+	struct nvkm_handle *handle;
+
+	list_for_each_entry(handle, &namedb->list, node) {
+		if (nv_mclass(handle->object) == oclass)
+			return handle;
+	}
+
+	return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_vinst(struct nvkm_namedb *namedb, u64 vinst)
+{
+	struct nvkm_handle *handle;
+
+	list_for_each_entry(handle, &namedb->list, node) {
+		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+			if (nv_gpuobj(handle->object)->addr == vinst)
+				return handle;
+		}
+	}
+
+	return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_cinst(struct nvkm_namedb *namedb, u32 cinst)
+{
+	struct nvkm_handle *handle;
+
+	list_for_each_entry(handle, &namedb->list, node) {
+		if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+			if (nv_gpuobj(handle->object)->node &&
+			    nv_gpuobj(handle->object)->node->offset == cinst)
+				return handle;
+		}
+	}
+
+	return NULL;
+}
+
+int
+nvkm_namedb_insert(struct nvkm_namedb *namedb, u32 name,
+		   struct nvkm_object *object,
+		   struct nvkm_handle *handle)
+{
+	int ret = -EEXIST;
+	write_lock_irq(&namedb->lock);
+	if (!nvkm_namedb_lookup(namedb, name)) {
+		nvkm_object_ref(object, &handle->object);
+		handle->namedb = namedb;
+		list_add(&handle->node, &namedb->list);
+		ret = 0;
+	}
+	write_unlock_irq(&namedb->lock);
+	return ret;
+}
+
+void
+nvkm_namedb_remove(struct nvkm_handle *handle)
+{
+	struct nvkm_namedb *namedb = handle->namedb;
+	struct nvkm_object *object = handle->object;
+	write_lock_irq(&namedb->lock);
+	list_del(&handle->node);
+	write_unlock_irq(&namedb->lock);
+	nvkm_object_ref(NULL, &object);
+}
+
+struct nvkm_handle *
+nvkm_namedb_get(struct nvkm_namedb *namedb, u32 name)
+{
+	struct nvkm_handle *handle;
+	read_lock(&namedb->lock);
+	handle = nvkm_namedb_lookup(namedb, name);
+	if (handle == NULL)
+		read_unlock(&namedb->lock);
+	return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_class(struct nvkm_namedb *namedb, u16 oclass)
+{
+	struct nvkm_handle *handle;
+	read_lock(&namedb->lock);
+	handle = nvkm_namedb_lookup_class(namedb, oclass);
+	if (handle == NULL)
+		read_unlock(&namedb->lock);
+	return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_vinst(struct nvkm_namedb *namedb, u64 vinst)
+{
+	struct nvkm_handle *handle;
+	read_lock(&namedb->lock);
+	handle = nvkm_namedb_lookup_vinst(namedb, vinst);
+	if (handle == NULL)
+		read_unlock(&namedb->lock);
+	return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_cinst(struct nvkm_namedb *namedb, u32 cinst)
+{
+	struct nvkm_handle *handle;
+	read_lock(&namedb->lock);
+	handle = nvkm_namedb_lookup_cinst(namedb, cinst);
+	if (handle == NULL)
+		read_unlock(&namedb->lock);
+	return handle;
+}
+
+void
+nvkm_namedb_put(struct nvkm_handle *handle)
+{
+	if (handle)
+		read_unlock(&handle->namedb->lock);
+}
+
+int
+nvkm_namedb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 pclass,
+		    struct nvkm_oclass *sclass, u64 engcls,
+		    int length, void **pobject)
+{
+	struct nvkm_namedb *namedb;
+	int ret;
+
+	ret = nvkm_parent_create_(parent, engine, oclass, pclass |
+				  NV_NAMEDB_CLASS, sclass, engcls,
+				  length, pobject);
+	namedb = *pobject;
+	if (ret)
+		return ret;
+
+	rwlock_init(&namedb->lock);
+	INIT_LIST_HEAD(&namedb->list);
+	return 0;
+}
+
+int
+_nvkm_namedb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_namedb *object;
+	int ret;
+
+	ret = nvkm_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
+	*pobject = nv_object(object);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/notify.c b/drivers/gpu/drm/nouveau/nvkm/core/notify.c
new file mode 100644
index 0000000..023610d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/notify.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <core/notify.h>
+#include <core/event.h>
+
+static inline void
+nvkm_notify_put_locked(struct nvkm_notify *notify)
+{
+	if (notify->block++ == 0)
+		nvkm_event_put(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_put(struct nvkm_notify *notify)
+{
+	struct nvkm_event *event = notify->event;
+	unsigned long flags;
+	if (likely(event) &&
+	    test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+		spin_lock_irqsave(&event->refs_lock, flags);
+		nvkm_notify_put_locked(notify);
+		spin_unlock_irqrestore(&event->refs_lock, flags);
+		if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
+			flush_work(&notify->work);
+	}
+}
+
+static inline void
+nvkm_notify_get_locked(struct nvkm_notify *notify)
+{
+	if (--notify->block == 0)
+		nvkm_event_get(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_get(struct nvkm_notify *notify)
+{
+	struct nvkm_event *event = notify->event;
+	unsigned long flags;
+	if (likely(event) &&
+	    !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+		spin_lock_irqsave(&event->refs_lock, flags);
+		nvkm_notify_get_locked(notify);
+		spin_unlock_irqrestore(&event->refs_lock, flags);
+	}
+}
+
+static inline void
+nvkm_notify_func(struct nvkm_notify *notify)
+{
+	struct nvkm_event *event = notify->event;
+	int ret = notify->func(notify);
+	unsigned long flags;
+	if ((ret == NVKM_NOTIFY_KEEP) ||
+	    !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+		spin_lock_irqsave(&event->refs_lock, flags);
+		nvkm_notify_get_locked(notify);
+		spin_unlock_irqrestore(&event->refs_lock, flags);
+	}
+}
+
+static void
+nvkm_notify_work(struct work_struct *work)
+{
+	struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
+	nvkm_notify_func(notify);
+}
+
+void
+nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
+{
+	struct nvkm_event *event = notify->event;
+	unsigned long flags;
+
+	assert_spin_locked(&event->list_lock);
+	BUG_ON(size != notify->size);
+
+	spin_lock_irqsave(&event->refs_lock, flags);
+	if (notify->block) {
+		spin_unlock_irqrestore(&event->refs_lock, flags);
+		return;
+	}
+	nvkm_notify_put_locked(notify);
+	spin_unlock_irqrestore(&event->refs_lock, flags);
+
+	if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
+		memcpy((void *)notify->data, data, size);
+		schedule_work(&notify->work);
+	} else {
+		notify->data = data;
+		nvkm_notify_func(notify);
+		notify->data = NULL;
+	}
+}
+
+void
+nvkm_notify_fini(struct nvkm_notify *notify)
+{
+	unsigned long flags;
+	if (notify->event) {
+		nvkm_notify_put(notify);
+		spin_lock_irqsave(&notify->event->list_lock, flags);
+		list_del(&notify->head);
+		spin_unlock_irqrestore(&notify->event->list_lock, flags);
+		kfree((void *)notify->data);
+		notify->event = NULL;
+	}
+}
+
+int
+nvkm_notify_init(struct nvkm_object *object, struct nvkm_event *event,
+		 int (*func)(struct nvkm_notify *), bool work,
+		 void *data, u32 size, u32 reply,
+		 struct nvkm_notify *notify)
+{
+	unsigned long flags;
+	int ret = -ENODEV;
+	if ((notify->event = event), event->refs) {
+		ret = event->func->ctor(object, data, size, notify);
+		if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
+			notify->flags = 0;
+			notify->block = 1;
+			notify->func = func;
+			notify->data = NULL;
+			if (ret = 0, work) {
+				INIT_WORK(&notify->work, nvkm_notify_work);
+				set_bit(NVKM_NOTIFY_WORK, &notify->flags);
+				notify->data = kmalloc(reply, GFP_KERNEL);
+				if (!notify->data)
+					ret = -ENOMEM;
+			}
+		}
+		if (ret == 0) {
+			spin_lock_irqsave(&event->list_lock, flags);
+			list_add_tail(&notify->head, &event->list);
+			spin_unlock_irqrestore(&event->list_lock, flags);
+		}
+	}
+	if (ret)
+		notify->event = NULL;
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c
new file mode 100644
index 0000000..979f362
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/object.h>
+#include <core/engine.h>
+
+#ifdef NVKM_OBJECT_MAGIC
+static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
+static DEFINE_SPINLOCK(_objlist_lock);
+#endif
+
+int
+nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 pclass,
+		    int size, void **pobject)
+{
+	struct nvkm_object *object;
+
+	object = *pobject = kzalloc(size, GFP_KERNEL);
+	if (!object)
+		return -ENOMEM;
+
+	nvkm_object_ref(parent, &object->parent);
+	nvkm_object_ref(engine, (struct nvkm_object **)&object->engine);
+	object->oclass = oclass;
+	object->oclass->handle |= pclass;
+	atomic_set(&object->refcount, 1);
+	atomic_set(&object->usecount, 0);
+
+#ifdef NVKM_OBJECT_MAGIC
+	object->_magic = NVKM_OBJECT_MAGIC;
+	spin_lock(&_objlist_lock);
+	list_add(&object->list, &_objlist);
+	spin_unlock(&_objlist_lock);
+#endif
+	return 0;
+}
+
+int
+_nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	if (size != 0)
+		return -ENOSYS;
+	return nvkm_object_create(parent, engine, oclass, 0, pobject);
+}
+
+void
+nvkm_object_destroy(struct nvkm_object *object)
+{
+#ifdef NVKM_OBJECT_MAGIC
+	spin_lock(&_objlist_lock);
+	list_del(&object->list);
+	spin_unlock(&_objlist_lock);
+#endif
+	nvkm_object_ref(NULL, (struct nvkm_object **)&object->engine);
+	nvkm_object_ref(NULL, &object->parent);
+	kfree(object);
+}
+
+int
+nvkm_object_init(struct nvkm_object *object)
+{
+	return 0;
+}
+
+int
+nvkm_object_fini(struct nvkm_object *object, bool suspend)
+{
+	return 0;
+}
+
+struct nvkm_ofuncs
+nvkm_object_ofuncs = {
+	.ctor = _nvkm_object_ctor,
+	.dtor = nvkm_object_destroy,
+	.init = nvkm_object_init,
+	.fini = nvkm_object_fini,
+};
+
+int
+nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct nvkm_ofuncs *ofuncs = oclass->ofuncs;
+	struct nvkm_object *object = NULL;
+	int ret;
+
+	ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
+	*pobject = object;
+	if (ret < 0) {
+		if (ret != -ENODEV) {
+			nv_error(parent, "failed to create 0x%08x, %d\n",
+				 oclass->handle, ret);
+		}
+
+		if (object) {
+			ofuncs->dtor(object);
+			*pobject = NULL;
+		}
+
+		return ret;
+	}
+
+	if (ret == 0) {
+		nv_trace(object, "created\n");
+		atomic_set(&object->refcount, 1);
+	}
+
+	return 0;
+}
+
+static void
+nvkm_object_dtor(struct nvkm_object *object)
+{
+	nv_trace(object, "destroying\n");
+	nv_ofuncs(object)->dtor(object);
+}
+
+void
+nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref)
+{
+	if (obj) {
+		atomic_inc(&obj->refcount);
+		nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
+	}
+
+	if (*ref) {
+		int dead = atomic_dec_and_test(&(*ref)->refcount);
+		nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
+		if (dead)
+			nvkm_object_dtor(*ref);
+	}
+
+	*ref = obj;
+}
+
+int
+nvkm_object_inc(struct nvkm_object *object)
+{
+	int ref = atomic_add_return(1, &object->usecount);
+	int ret;
+
+	nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
+	if (ref != 1)
+		return 0;
+
+	nv_trace(object, "initialising...\n");
+	if (object->parent) {
+		ret = nvkm_object_inc(object->parent);
+		if (ret) {
+			nv_error(object, "parent failed, %d\n", ret);
+			goto fail_parent;
+		}
+	}
+
+	if (object->engine) {
+		mutex_lock(&nv_subdev(object->engine)->mutex);
+		ret = nvkm_object_inc(&object->engine->subdev.object);
+		mutex_unlock(&nv_subdev(object->engine)->mutex);
+		if (ret) {
+			nv_error(object, "engine failed, %d\n", ret);
+			goto fail_engine;
+		}
+	}
+
+	ret = nv_ofuncs(object)->init(object);
+	atomic_set(&object->usecount, 1);
+	if (ret) {
+		nv_error(object, "init failed, %d\n", ret);
+		goto fail_self;
+	}
+
+	nv_trace(object, "initialised\n");
+	return 0;
+
+fail_self:
+	if (object->engine) {
+		mutex_lock(&nv_subdev(object->engine)->mutex);
+		nvkm_object_dec(&object->engine->subdev.object, false);
+		mutex_unlock(&nv_subdev(object->engine)->mutex);
+	}
+fail_engine:
+	if (object->parent)
+		 nvkm_object_dec(object->parent, false);
+fail_parent:
+	atomic_dec(&object->usecount);
+	return ret;
+}
+
+static int
+nvkm_object_decf(struct nvkm_object *object)
+{
+	int ret;
+
+	nv_trace(object, "stopping...\n");
+
+	ret = nv_ofuncs(object)->fini(object, false);
+	atomic_set(&object->usecount, 0);
+	if (ret)
+		nv_warn(object, "failed fini, %d\n", ret);
+
+	if (object->engine) {
+		mutex_lock(&nv_subdev(object->engine)->mutex);
+		nvkm_object_dec(&object->engine->subdev.object, false);
+		mutex_unlock(&nv_subdev(object->engine)->mutex);
+	}
+
+	if (object->parent)
+		nvkm_object_dec(object->parent, false);
+
+	nv_trace(object, "stopped\n");
+	return 0;
+}
+
+static int
+nvkm_object_decs(struct nvkm_object *object)
+{
+	int ret, rret;
+
+	nv_trace(object, "suspending...\n");
+
+	ret = nv_ofuncs(object)->fini(object, true);
+	atomic_set(&object->usecount, 0);
+	if (ret) {
+		nv_error(object, "failed suspend, %d\n", ret);
+		return ret;
+	}
+
+	if (object->engine) {
+		mutex_lock(&nv_subdev(object->engine)->mutex);
+		ret = nvkm_object_dec(&object->engine->subdev.object, true);
+		mutex_unlock(&nv_subdev(object->engine)->mutex);
+		if (ret) {
+			nv_warn(object, "engine failed suspend, %d\n", ret);
+			goto fail_engine;
+		}
+	}
+
+	if (object->parent) {
+		ret = nvkm_object_dec(object->parent, true);
+		if (ret) {
+			nv_warn(object, "parent failed suspend, %d\n", ret);
+			goto fail_parent;
+		}
+	}
+
+	nv_trace(object, "suspended\n");
+	return 0;
+
+fail_parent:
+	if (object->engine) {
+		mutex_lock(&nv_subdev(object->engine)->mutex);
+		rret = nvkm_object_inc(&object->engine->subdev.object);
+		mutex_unlock(&nv_subdev(object->engine)->mutex);
+		if (rret)
+			nv_fatal(object, "engine failed to reinit, %d\n", rret);
+	}
+
+fail_engine:
+	rret = nv_ofuncs(object)->init(object);
+	if (rret)
+		nv_fatal(object, "failed to reinit, %d\n", rret);
+
+	return ret;
+}
+
+int
+nvkm_object_dec(struct nvkm_object *object, bool suspend)
+{
+	int ref = atomic_add_return(-1, &object->usecount);
+	int ret;
+
+	nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
+
+	if (ref == 0) {
+		if (suspend)
+			ret = nvkm_object_decs(object);
+		else
+			ret = nvkm_object_decf(object);
+
+		if (ret) {
+			atomic_inc(&object->usecount);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+void
+nvkm_object_debug(void)
+{
+#ifdef NVKM_OBJECT_MAGIC
+	struct nvkm_object *object;
+	if (!list_empty(&_objlist)) {
+		nv_fatal(NULL, "*******************************************\n");
+		nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
+		nv_fatal(NULL, "*******************************************\n");
+		list_for_each_entry(object, &_objlist, list) {
+			nv_fatal(object, "%p/%p/%d/%d\n",
+				 object->parent, object->engine,
+				 atomic_read(&object->refcount),
+				 atomic_read(&object->usecount));
+		}
+	}
+#endif
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/option.c b/drivers/gpu/drm/nouveau/nvkm/core/option.c
new file mode 100644
index 0000000..19d153f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/option.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/option.h>
+#include <core/debug.h>
+
+const char *
+nvkm_stropt(const char *optstr, const char *opt, int *arglen)
+{
+	while (optstr && *optstr != '\0') {
+		int len = strcspn(optstr, ",=");
+		switch (optstr[len]) {
+		case '=':
+			if (!strncasecmpz(optstr, opt, len)) {
+				optstr += len + 1;
+				*arglen = strcspn(optstr, ",=");
+				return *arglen ? optstr : NULL;
+			}
+			optstr++;
+			break;
+		case ',':
+			optstr++;
+			break;
+		default:
+			break;
+		}
+		optstr += len;
+	}
+
+	return NULL;
+}
+
+bool
+nvkm_boolopt(const char *optstr, const char *opt, bool value)
+{
+	int arglen;
+
+	optstr = nvkm_stropt(optstr, opt, &arglen);
+	if (optstr) {
+		if (!strncasecmpz(optstr, "0", arglen) ||
+		    !strncasecmpz(optstr, "no", arglen) ||
+		    !strncasecmpz(optstr, "off", arglen) ||
+		    !strncasecmpz(optstr, "false", arglen))
+			value = false;
+		else
+		if (!strncasecmpz(optstr, "1", arglen) ||
+		    !strncasecmpz(optstr, "yes", arglen) ||
+		    !strncasecmpz(optstr, "on", arglen) ||
+		    !strncasecmpz(optstr, "true", arglen))
+			value = true;
+	}
+
+	return value;
+}
+
+int
+nvkm_dbgopt(const char *optstr, const char *sub)
+{
+	int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
+
+	while (optstr) {
+		int len = strcspn(optstr, ",=");
+		switch (optstr[len]) {
+		case '=':
+			if (strncasecmpz(optstr, sub, len))
+				mode = 0;
+			optstr++;
+			break;
+		default:
+			if (mode) {
+				if (!strncasecmpz(optstr, "fatal", len))
+					level = NV_DBG_FATAL;
+				else if (!strncasecmpz(optstr, "error", len))
+					level = NV_DBG_ERROR;
+				else if (!strncasecmpz(optstr, "warn", len))
+					level = NV_DBG_WARN;
+				else if (!strncasecmpz(optstr, "info", len))
+					level = NV_DBG_INFO_NORMAL;
+				else if (!strncasecmpz(optstr, "debug", len))
+					level = NV_DBG_DEBUG;
+				else if (!strncasecmpz(optstr, "trace", len))
+					level = NV_DBG_TRACE;
+				else if (!strncasecmpz(optstr, "paranoia", len))
+					level = NV_DBG_PARANOIA;
+				else if (!strncasecmpz(optstr, "spam", len))
+					level = NV_DBG_SPAM;
+			}
+
+			if (optstr[len] != '\0') {
+				optstr++;
+				mode = 1;
+				break;
+			}
+
+			return level;
+		}
+		optstr += len;
+	}
+
+	return level;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c
new file mode 100644
index 0000000..dd56cd1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/parent.h>
+#include <core/client.h>
+#include <core/engine.h>
+
+int
+nvkm_parent_sclass(struct nvkm_object *parent, u16 handle,
+		   struct nvkm_object **pengine,
+		   struct nvkm_oclass **poclass)
+{
+	struct nvkm_sclass *sclass;
+	struct nvkm_engine *engine;
+	struct nvkm_oclass *oclass;
+	u64 mask;
+
+	sclass = nv_parent(parent)->sclass;
+	while (sclass) {
+		if ((sclass->oclass->handle & 0xffff) == handle) {
+			*pengine = &parent->engine->subdev.object;
+			*poclass = sclass->oclass;
+			return 0;
+		}
+
+		sclass = sclass->sclass;
+	}
+
+	mask = nv_parent(parent)->engine;
+	while (mask) {
+		int i = __ffs64(mask);
+
+		if (nv_iclass(parent, NV_CLIENT_CLASS))
+			engine = nv_engine(nv_client(parent)->device);
+		else
+			engine = nvkm_engine(parent, i);
+
+		if (engine) {
+			oclass = engine->sclass;
+			while (oclass->ofuncs) {
+				if ((oclass->handle & 0xffff) == handle) {
+					*pengine = nv_object(engine);
+					*poclass = oclass;
+					return 0;
+				}
+				oclass++;
+			}
+		}
+
+		mask &= ~(1ULL << i);
+	}
+
+	return -EINVAL;
+}
+
+int
+nvkm_parent_lclass(struct nvkm_object *parent, u32 *lclass, int size)
+{
+	struct nvkm_sclass *sclass;
+	struct nvkm_engine *engine;
+	struct nvkm_oclass *oclass;
+	int nr = -1, i;
+	u64 mask;
+
+	sclass = nv_parent(parent)->sclass;
+	while (sclass) {
+		if (++nr < size)
+			lclass[nr] = sclass->oclass->handle & 0xffff;
+		sclass = sclass->sclass;
+	}
+
+	mask = nv_parent(parent)->engine;
+	while (i = __ffs64(mask), mask) {
+		engine = nvkm_engine(parent, i);
+		if (engine && (oclass = engine->sclass)) {
+			while (oclass->ofuncs) {
+				if (++nr < size)
+					lclass[nr] = oclass->handle & 0xffff;
+				oclass++;
+			}
+		}
+
+		mask &= ~(1ULL << i);
+	}
+
+	return nr + 1;
+}
+
+int
+nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 pclass,
+		    struct nvkm_oclass *sclass, u64 engcls,
+		    int size, void **pobject)
+{
+	struct nvkm_parent *object;
+	struct nvkm_sclass *nclass;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, pclass |
+				  NV_PARENT_CLASS, size, pobject);
+	object = *pobject;
+	if (ret)
+		return ret;
+
+	while (sclass && sclass->ofuncs) {
+		nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
+		if (!nclass)
+			return -ENOMEM;
+
+		nclass->sclass = object->sclass;
+		object->sclass = nclass;
+		nclass->engine = engine ? nv_engine(engine) : NULL;
+		nclass->oclass = sclass;
+		sclass++;
+	}
+
+	object->engine = engcls;
+	return 0;
+}
+
+void
+nvkm_parent_destroy(struct nvkm_parent *parent)
+{
+	struct nvkm_sclass *sclass;
+
+	while ((sclass = parent->sclass)) {
+		parent->sclass = sclass->sclass;
+		kfree(sclass);
+	}
+
+	nvkm_object_destroy(&parent->object);
+}
+
+
+void
+_nvkm_parent_dtor(struct nvkm_object *object)
+{
+	nvkm_parent_destroy(nv_parent(object));
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/printk.c b/drivers/gpu/drm/nouveau/nvkm/core/printk.c
new file mode 100644
index 0000000..4a220eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/printk.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/printk.h>
+#include <core/client.h>
+#include <core/device.h>
+
+int nv_info_debug_level = NV_DBG_INFO_NORMAL;
+
+void
+nv_printk_(struct nvkm_object *object, int level, const char *fmt, ...)
+{
+	static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
+	const char *pfx;
+	char mfmt[256];
+	va_list args;
+
+	switch (level) {
+	case NV_DBG_FATAL:
+		pfx = KERN_CRIT;
+		break;
+	case NV_DBG_ERROR:
+		pfx = KERN_ERR;
+		break;
+	case NV_DBG_WARN:
+		pfx = KERN_WARNING;
+		break;
+	case NV_DBG_INFO_NORMAL:
+		pfx = KERN_INFO;
+		break;
+	case NV_DBG_DEBUG:
+	case NV_DBG_PARANOIA:
+	case NV_DBG_TRACE:
+	case NV_DBG_SPAM:
+	default:
+		pfx = KERN_DEBUG;
+		break;
+	}
+
+	if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
+		struct nvkm_object *device;
+		struct nvkm_object *subdev;
+		char obuf[64], *ofmt = "";
+
+		if (object->engine == NULL) {
+			subdev = object;
+			while (subdev && !nv_iclass(subdev, NV_SUBDEV_CLASS))
+				subdev = subdev->parent;
+		} else {
+			subdev = &object->engine->subdev.object;
+		}
+
+		device = subdev;
+		if (device->parent)
+			device = device->parent;
+
+		if (object != subdev) {
+			snprintf(obuf, sizeof(obuf), "[0x%08x]",
+				 nv_hclass(object));
+			ofmt = obuf;
+		}
+
+		if (level > nv_subdev(subdev)->debug)
+			return;
+
+		snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
+			 name[level], nv_subdev(subdev)->name,
+			 nv_device(device)->name, ofmt, fmt);
+	} else
+	if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
+		if (level > nv_client(object)->debug)
+			return;
+
+		snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
+			 name[level], nv_client(object)->name, fmt);
+	} else {
+		snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
+	}
+
+	va_start(args, fmt);
+	vprintk(mfmt, args);
+	va_end(args);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
new file mode 100644
index 0000000..ebd4d15
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat 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 <core/ramht.h>
+#include <core/engine.h>
+
+#include <subdev/bar.h>
+
+static u32
+nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle)
+{
+	u32 hash = 0;
+
+	while (handle) {
+		hash ^= (handle & ((1 << ramht->bits) - 1));
+		handle >>= ramht->bits;
+	}
+
+	hash ^= chid << (ramht->bits - 4);
+	hash  = hash << 3;
+	return hash;
+}
+
+int
+nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context)
+{
+	struct nvkm_bar *bar = nvkm_bar(ramht);
+	u32 co, ho;
+
+	co = ho = nvkm_ramht_hash(ramht, chid, handle);
+	do {
+		if (!nv_ro32(ramht, co + 4)) {
+			nv_wo32(ramht, co + 0, handle);
+			nv_wo32(ramht, co + 4, context);
+			if (bar)
+				bar->flush(bar);
+			return co;
+		}
+
+		co += 8;
+		if (co >= nv_gpuobj(ramht)->size)
+			co = 0;
+	} while (co != ho);
+
+	return -ENOMEM;
+}
+
+void
+nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie)
+{
+	struct nvkm_bar *bar = nvkm_bar(ramht);
+	nv_wo32(ramht, cookie + 0, 0x00000000);
+	nv_wo32(ramht, cookie + 4, 0x00000000);
+	if (bar)
+		bar->flush(bar);
+}
+
+static struct nvkm_oclass
+nvkm_ramht_oclass = {
+	.handle = 0x0000abcd,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = NULL,
+		.dtor = _nvkm_gpuobj_dtor,
+		.init = _nvkm_gpuobj_init,
+		.fini = _nvkm_gpuobj_fini,
+		.rd32 = _nvkm_gpuobj_rd32,
+		.wr32 = _nvkm_gpuobj_wr32,
+	},
+};
+
+int
+nvkm_ramht_new(struct nvkm_object *parent, struct nvkm_object *pargpu,
+	       u32 size, u32 align, struct nvkm_ramht **pramht)
+{
+	struct nvkm_ramht *ramht;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, parent->engine ?
+				 &parent->engine->subdev.object : parent, /* <nv50 ramht */
+				 &nvkm_ramht_oclass, 0, pargpu, size,
+				 align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+	*pramht = ramht;
+	if (ret)
+		return ret;
+
+	ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
new file mode 100644
index 0000000..c5fb3a79
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/subdev.h>
+#include <core/device.h>
+#include <core/option.h>
+
+struct nvkm_subdev *
+nvkm_subdev(void *obj, int idx)
+{
+	struct nvkm_object *object = nv_object(obj);
+	while (object && !nv_iclass(object, NV_SUBDEV_CLASS))
+		object = object->parent;
+	if (object == NULL || nv_subidx(nv_subdev(object)) != idx)
+		object = nv_device(obj)->subdev[idx];
+	return object ? nv_subdev(object) : NULL;
+}
+
+void
+nvkm_subdev_reset(struct nvkm_object *subdev)
+{
+	nv_trace(subdev, "resetting...\n");
+	nv_ofuncs(subdev)->fini(subdev, false);
+	nv_debug(subdev, "reset\n");
+}
+
+int
+nvkm_subdev_init(struct nvkm_subdev *subdev)
+{
+	int ret = nvkm_object_init(&subdev->object);
+	if (ret)
+		return ret;
+
+	nvkm_subdev_reset(&subdev->object);
+	return 0;
+}
+
+int
+_nvkm_subdev_init(struct nvkm_object *object)
+{
+	return nvkm_subdev_init(nv_subdev(object));
+}
+
+int
+nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
+{
+	if (subdev->unit) {
+		nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
+		nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
+	}
+
+	return nvkm_object_fini(&subdev->object, suspend);
+}
+
+int
+_nvkm_subdev_fini(struct nvkm_object *object, bool suspend)
+{
+	return nvkm_subdev_fini(nv_subdev(object), suspend);
+}
+
+void
+nvkm_subdev_destroy(struct nvkm_subdev *subdev)
+{
+	int subidx = nv_hclass(subdev) & 0xff;
+	nv_device(subdev)->subdev[subidx] = NULL;
+	nvkm_object_destroy(&subdev->object);
+}
+
+void
+_nvkm_subdev_dtor(struct nvkm_object *object)
+{
+	nvkm_subdev_destroy(nv_subdev(object));
+}
+
+int
+nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 pclass,
+		    const char *subname, const char *sysname,
+		    int size, void **pobject)
+{
+	struct nvkm_subdev *subdev;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, pclass |
+				  NV_SUBDEV_CLASS, size, pobject);
+	subdev = *pobject;
+	if (ret)
+		return ret;
+
+	__mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
+	subdev->name = subname;
+
+	if (parent) {
+		struct nvkm_device *device = nv_device(parent);
+		subdev->debug = nvkm_dbgopt(device->dbgopt, subname);
+		subdev->mmio  = nv_subdev(device)->mmio;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
new file mode 100644
index 0000000..6bd3d75
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
@@ -0,0 +1,19 @@
+nvkm-y += nvkm/engine/falcon.o
+nvkm-y += nvkm/engine/xtensa.o
+
+include $(src)/nvkm/engine/bsp/Kbuild
+include $(src)/nvkm/engine/ce/Kbuild
+include $(src)/nvkm/engine/cipher/Kbuild
+include $(src)/nvkm/engine/device/Kbuild
+include $(src)/nvkm/engine/disp/Kbuild
+include $(src)/nvkm/engine/dmaobj/Kbuild
+include $(src)/nvkm/engine/fifo/Kbuild
+include $(src)/nvkm/engine/gr/Kbuild
+include $(src)/nvkm/engine/mpeg/Kbuild
+include $(src)/nvkm/engine/mspdec/Kbuild
+include $(src)/nvkm/engine/msppp/Kbuild
+include $(src)/nvkm/engine/msvld/Kbuild
+include $(src)/nvkm/engine/pm/Kbuild
+include $(src)/nvkm/engine/sec/Kbuild
+include $(src)/nvkm/engine/sw/Kbuild
+include $(src)/nvkm/engine/vp/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild
new file mode 100644
index 0000000..5ac9f9e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/bsp/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
new file mode 100644
index 0000000..a0b1fd8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs, Ilia Mirkin
+ */
+#include <engine/bsp.h>
+#include <engine/xtensa.h>
+
+#include <core/engctx.h>
+
+/*******************************************************************************
+ * BSP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_bsp_sclass[] = {
+	{ 0x74b0, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * BSP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_bsp_cclass = {
+	.handle = NV_ENGCTX(BSP, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_xtensa_engctx_ctor,
+		.dtor = _nvkm_engctx_dtor,
+		.init = _nvkm_engctx_init,
+		.fini = _nvkm_engctx_fini,
+		.rd32 = _nvkm_engctx_rd32,
+		.wr32 = _nvkm_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * BSP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nvkm_xtensa *priv;
+	int ret;
+
+	ret = nvkm_xtensa_create(parent, engine, oclass, 0x103000, true,
+				 "PBSP", "bsp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x04008000;
+	nv_engine(priv)->cclass = &g84_bsp_cclass;
+	nv_engine(priv)->sclass = g84_bsp_sclass;
+	priv->fifo_val = 0x1111;
+	priv->unkd28 = 0x90044;
+	return 0;
+}
+
+struct nvkm_oclass
+g84_bsp_oclass = {
+	.handle = NV_ENGINE(BSP, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_bsp_ctor,
+		.dtor = _nvkm_xtensa_dtor,
+		.init = _nvkm_xtensa_init,
+		.fini = _nvkm_xtensa_fini,
+		.rd32 = _nvkm_xtensa_rd32,
+		.wr32 = _nvkm_xtensa_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
new file mode 100644
index 0000000..8587974
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/ce/gt215.o
+nvkm-y += nvkm/engine/ce/gf100.o
+nvkm-y += nvkm/engine/ce/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc
new file mode 100644
index 0000000..a558dfa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc
@@ -0,0 +1,864 @@
+/* fuc microcode for copy engine on gt215- chipsets
+ *
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef GT215
+.section #gt215_pce_data
+#else
+.section #gf100_pce_data
+#endif
+
+ctx_object:                   .b32 0
+#ifdef GT215
+ctx_dma:
+ctx_dma_query:                .b32 0
+ctx_dma_src:                  .b32 0
+ctx_dma_dst:                  .b32 0
+#endif
+.equ #ctx_dma_count 3
+ctx_query_address_high:       .b32 0
+ctx_query_address_low:        .b32 0
+ctx_query_counter:            .b32 0
+ctx_src_address_high:         .b32 0
+ctx_src_address_low:          .b32 0
+ctx_src_pitch:                .b32 0
+ctx_src_tile_mode:            .b32 0
+ctx_src_xsize:                .b32 0
+ctx_src_ysize:                .b32 0
+ctx_src_zsize:                .b32 0
+ctx_src_zoff:                 .b32 0
+ctx_src_xoff:                 .b32 0
+ctx_src_yoff:                 .b32 0
+ctx_src_cpp:                  .b32 0
+ctx_dst_address_high:         .b32 0
+ctx_dst_address_low:          .b32 0
+ctx_dst_pitch:                .b32 0
+ctx_dst_tile_mode:            .b32 0
+ctx_dst_xsize:                .b32 0
+ctx_dst_ysize:                .b32 0
+ctx_dst_zsize:                .b32 0
+ctx_dst_zoff:                 .b32 0
+ctx_dst_xoff:                 .b32 0
+ctx_dst_yoff:                 .b32 0
+ctx_dst_cpp:                  .b32 0
+ctx_format:                   .b32 0
+ctx_swz_const0:               .b32 0
+ctx_swz_const1:               .b32 0
+ctx_xcnt:                     .b32 0
+ctx_ycnt:                     .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 #ctx_object                     ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + #cmd_nop           ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + #cmd_pm_trigger    ~0xffffffff
+#ifdef GT215
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 #ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + #cmd_dma           ~0xffffffff
+.b32 0x00010000 + #cmd_dma           ~0xffffffff
+.b32 0x00010000 + #cmd_dma           ~0xffffffff
+#endif
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 #ctx_src_tile_mode              ~0x00000fff
+.b32 #ctx_src_xsize                  ~0x0007ffff
+.b32 #ctx_src_ysize                  ~0x00001fff
+.b32 #ctx_src_zsize                  ~0x000007ff
+.b32 #ctx_src_zoff                   ~0x00000fff
+.b32 #ctx_src_xoff                   ~0x0007ffff
+.b32 #ctx_src_yoff                   ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 #ctx_dst_tile_mode              ~0x00000fff
+.b32 #ctx_dst_xsize                  ~0x0007ffff
+.b32 #ctx_dst_ysize                  ~0x00001fff
+.b32 #ctx_dst_zsize                  ~0x000007ff
+.b32 #ctx_dst_zoff                   ~0x00000fff
+.b32 #ctx_dst_xoff                   ~0x0007ffff
+.b32 #ctx_dst_yoff                   ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + #cmd_exec          ~0xffffffff
+.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 #ctx_src_address_high           ~0x000000ff
+.b32 #ctx_src_address_low            ~0xffffffff
+.b32 #ctx_dst_address_high           ~0x000000ff
+.b32 #ctx_dst_address_low            ~0xffffffff
+.b32 #ctx_src_pitch                  ~0x0007ffff
+.b32 #ctx_dst_pitch                  ~0x0007ffff
+.b32 #ctx_xcnt                       ~0x0000ffff
+.b32 #ctx_ycnt                       ~0x00001fff
+.b32 #ctx_format                     ~0x0333ffff
+.b32 #ctx_swz_const0                 ~0xffffffff
+.b32 #ctx_swz_const1                 ~0xffffffff
+.b32 #ctx_query_address_high         ~0x000000ff
+.b32 #ctx_query_address_low          ~0xffffffff
+.b32 #ctx_query_counter              ~0xffffffff
+.b16 0x800 0
+
+#ifdef GT215
+.section #gt215_pce_code
+#else
+.section #gf100_pce_code
+#endif
+
+main:
+   clear b32 $r0
+   mov $sp $r0
+
+   // setup i0 handler and route fifo and ctxswitch to it
+   mov $r1 #ih
+   mov $iv0 $r1
+   mov $r1 0x400
+   movw $r2 0xfff3
+   sethi $r2 0
+   iowr I[$r1 + 0x300] $r2
+
+   // enable interrupts
+   or $r2 0xc
+   iowr I[$r1] $r2
+   bset $flags ie0
+
+   // enable fifo access and context switching
+   mov $r1 0x1200
+   mov $r2 3
+   iowr I[$r1] $r2
+
+   // sleep forever, waking for interrupts
+   bset $flags $p0
+   spin:
+      sleep $p0
+      bra #spin
+
+// i0 handler
+ih:
+   iord $r1 I[$r0 + 0x200]
+
+   and $r2 $r1 0x00000008
+   bra e #ih_no_chsw
+      call #chsw
+   ih_no_chsw:
+   and $r2 $r1 0x00000004
+   bra e #ih_no_cmd
+      call #dispatch
+
+   ih_no_cmd:
+   and $r1 $r1 0x0000000c
+   iowr I[$r0 + 0x100] $r1
+   iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+   mov $r4 0x7700
+   mov $xtargets $r4
+#ifdef GT215
+   // target 7 hardcoded to ctx dma object
+   mov $xdbase $r0
+#else
+   // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+   mov $r4 0x2100
+   iord $r4 I[$r4 + 0]
+   and $r4 1
+   shl b32 $r4 4
+   add b32 $r4 0x30
+
+   // channel is in vram
+   mov $r15 0x61c
+   shl b32 $r15 6
+   mov $r5 0x114
+   iowrs I[$r15] $r5
+
+   // read 16-byte PCOPYn info, containing context pointer, from channel
+   shl b32 $r5 $r3 4
+   add b32 $r5 2
+   mov $xdbase $r5
+   mov $r5 $sp
+   // get a chunk of stack space, aligned to 256 byte boundary
+   sub b32 $r5 0x100
+   mov $r6 0xff
+   not b32 $r6
+   and $r5 $r6
+   sethi $r5 0x00020000
+   xdld $r4 $r5
+   xdwait
+   sethi $r5 0
+
+   // set context pointer, from within channel VM
+   mov $r14 0
+   iowrs I[$r15] $r14
+   ld b32 $r4 D[$r5 + 0]
+   shr b32 $r4 8
+   ld b32 $r6 D[$r5 + 4]
+   shl b32 $r6 24
+   or $r4 $r6
+   mov $xdbase $r4
+#endif
+   // 256-byte context, at start of data segment
+   mov b32 $r4 $r0
+   sethi $r4 0x60000
+
+   // swap!
+   bra $p1 #swctx_load
+      xdst $r0 $r4
+      bra #swctx_done
+   swctx_load:
+      xdld $r0 $r4
+   swctx_done:
+   xdwait
+   ret
+
+chsw:
+   // read current channel
+   mov $r2 0x1400
+   iord $r3 I[$r2]
+
+   // if it's active, unload it and return
+   xbit $r15 $r3 0x1e
+   bra e #chsw_no_unload
+      bclr $flags $p1
+      call #swctx
+      bclr $r3 0x1e
+      iowr I[$r2] $r3
+      mov $r4 1
+      iowr I[$r2 + 0x200] $r4
+      ret
+
+   // read next channel
+   chsw_no_unload:
+   iord $r3 I[$r2 + 0x100]
+
+   // is there a channel waiting to be loaded?
+   xbit $r13 $r3 0x1e
+   bra e #chsw_finish_load
+      bset $flags $p1
+      call #swctx
+#ifdef GT215
+      // load dma objects back into TARGET regs
+      mov $r5 #ctx_dma
+      mov $r6 #ctx_dma_count
+      chsw_load_ctx_dma:
+         ld b32 $r7 D[$r5 + $r6 * 4]
+         add b32 $r8 $r6 0x180
+         shl b32 $r8 8
+         iowr I[$r8] $r7
+         sub b32 $r6 1
+         bra nc #chsw_load_ctx_dma
+#endif
+   chsw_finish_load:
+   mov $r3 2
+   iowr I[$r2 + 0x200] $r3
+   ret
+
+dispatch:
+   // read incoming fifo command
+   mov $r3 0x1900
+   iord $r2 I[$r3 + 0x100]
+   iord $r3 I[$r3 + 0x000]
+   and $r4 $r2 0x7ff
+   // $r2 will be used to store exception data
+   shl b32 $r2 0x10
+
+   // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+   mov $r5 #dispatch_table
+   clear b32 $r6
+   clear b32 $r7
+   dispatch_loop:
+      ld b16 $r6 D[$r5 + 0]
+      ld b16 $r7 D[$r5 + 2]
+      add b32 $r5 4
+      cmpu b32 $r4 $r6
+      bra c #dispatch_illegal_mthd
+      add b32 $r7 $r6
+      cmpu b32 $r4 $r7
+      bra c #dispatch_valid_mthd
+      sub b32 $r7 $r6
+      shl b32 $r7 3
+      add b32 $r5 $r7
+      bra #dispatch_loop
+
+   // ensure no bits set in reserved fields, INVALID_BITFIELD
+   dispatch_valid_mthd:
+   sub b32 $r4 $r6
+   shl b32 $r4 3
+   add b32 $r4 $r5
+   ld b32 $r5 D[$r4 + 4]
+   and $r5 $r3
+   cmpu b32 $r5 0
+   bra ne #dispatch_invalid_bitfield
+
+   // depending on dispatch flags: execute method, or save data as state
+   ld b16 $r5 D[$r4 + 0]
+   ld b16 $r6 D[$r4 + 2]
+   cmpu b32 $r6 0
+   bra ne #dispatch_cmd
+      st b32 D[$r5] $r3
+      bra #dispatch_done
+   dispatch_cmd:
+      bclr $flags $p1
+      call $r5
+      bra $p1 #dispatch_error
+      bra #dispatch_done
+
+   dispatch_invalid_bitfield:
+   or $r2 2
+   dispatch_illegal_mthd:
+   or $r2 1
+
+   // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+   dispatch_error:
+   mov $r4 0x1000
+   iowr I[$r4 + 0x000] $r2
+   iowr I[$r4 + 0x100] $r3
+   mov $r2 0x40
+   iowr I[$r0] $r2
+   hostirq_wait:
+      iord $r2 I[$r0 + 0x200]
+      and $r2 0x40
+      cmpu b32 $r2 0
+      bra ne #hostirq_wait
+
+   dispatch_done:
+   mov $r2 0x1d00
+   mov $r3 1
+   iowr I[$r2] $r3
+   ret
+
+// No-operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_nop:
+   ret
+
+// PM_TRIGGER
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_pm_trigger:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x20000
+   iowr I[$r2] $r3
+   ret
+
+#ifdef GT215
+// SET_DMA_* method handler
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_dma:
+   sub b32 $r4 #dispatch_dma
+   shr b32 $r4 1
+   bset $r3 0x1e
+   st b32 D[$r4 + #ctx_dma] $r3
+   add b32 $r4 0x600
+   shl b32 $r4 6
+   iowr I[$r4] $r3
+   ret
+#endif
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+   // zero out a chunk of the stack to store the swizzle into
+   add $sp -0x10
+   st b32 D[$sp + 0x00] $r0
+   st b32 D[$sp + 0x04] $r0
+   st b32 D[$sp + 0x08] $r0
+   st b32 D[$sp + 0x0c] $r0
+
+   // extract cpp, src_ncomp and dst_ncomp from FORMAT
+   ld b32 $r4 D[$r0 + #ctx_format]
+   extr $r5 $r4 16:17
+   add b32 $r5 1
+   extr $r6 $r4 20:21
+   add b32 $r6 1
+   extr $r7 $r4 24:25
+   add b32 $r7 1
+
+   // convert FORMAT swizzle mask to hw swizzle mask
+   bclr $flags $p2
+   clear b32 $r8
+   clear b32 $r9
+   ncomp_loop:
+      and $r10 $r4 0xf
+      shr b32 $r4 4
+      clear b32 $r11
+      bpc_loop:
+         cmpu b8 $r10 4
+         bra nc #cmp_c0
+            mulu $r12 $r10 $r5
+            add b32 $r12 $r11
+            bset $flags $p2
+            bra #bpc_next
+         cmp_c0:
+         bra ne #cmp_c1
+            mov $r12 0x10
+            add b32 $r12 $r11
+            bra #bpc_next
+         cmp_c1:
+         cmpu b8 $r10 6
+         bra nc #cmp_zero
+            mov $r12 0x14
+            add b32 $r12 $r11
+            bra #bpc_next
+         cmp_zero:
+            mov $r12 0x80
+         bpc_next:
+         st b8 D[$sp + $r8] $r12
+         add b32 $r8 1
+         add b32 $r11 1
+         cmpu b32 $r11 $r5
+         bra c #bpc_loop
+      add b32 $r9 1
+      cmpu b32 $r9 $r7
+      bra c #ncomp_loop
+
+   // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+   mulu $r6 $r5
+   st b32 D[$r0 + #ctx_src_cpp] $r6
+   ld b32 $r8 D[$r0 + #ctx_xcnt]
+   mulu $r6 $r8
+   bra $p2 #dst_xcnt
+   clear b32 $r6
+
+   dst_xcnt:
+   mulu $r7 $r5
+   st b32 D[$r0 + #ctx_dst_cpp] $r7
+   mulu $r7 $r8
+
+   mov $r5 0x810
+   shl b32 $r5 6
+   iowr I[$r5 + 0x000] $r6
+   iowr I[$r5 + 0x100] $r7
+   add b32 $r5 0x800
+   ld b32 $r6 D[$r0 + #ctx_dst_cpp]
+   sub b32 $r6 1
+   shl b32 $r6 8
+   ld b32 $r7 D[$r0 + #ctx_src_cpp]
+   sub b32 $r7 1
+   or $r6 $r7
+   iowr I[$r5 + 0x000] $r6
+   add b32 $r5 0x100
+   ld b32 $r6 D[$sp + 0x00]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$sp + 0x04]
+   iowr I[$r5 + 0x100] $r6
+   ld b32 $r6 D[$sp + 0x08]
+   iowr I[$r5 + 0x200] $r6
+   ld b32 $r6 D[$sp + 0x0c]
+   iowr I[$r5 + 0x300] $r6
+   add b32 $r5 0x400
+   ld b32 $r6 D[$r0 + #ctx_swz_const0]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$r0 + #ctx_swz_const1]
+   iowr I[$r5 + 0x100] $r6
+   add $sp 0x10
+   ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+//    nTx = round_up(w * cpp, 1 << Tp) >> Tp
+//    nTy = round_up(h, 1 << Th) >> Th
+//    Txo = (x * cpp) & ((1 << Tp) - 1)
+//     Tx = (x * cpp) >> Tp
+//    Tyo = y & ((1 << Th) - 1)
+//     Ty = y >> Th
+//    Tzo = z & ((1 << Td) - 1)
+//     Tz = z >> Td
+//
+//    off  = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+//    off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+//    $r4: hw command (0x104800)
+//    $r5: ctx offset adjustment for src/dst selection
+//    $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+   // translate TILE_MODE into Tp, Th, Td shift values
+   ld b32 $r7 D[$r5 + #ctx_src_tile_mode]
+   extr $r9 $r7 8:11
+   extr $r8 $r7 4:7
+#ifdef GT215
+   add b32 $r8 2
+#else
+   add b32 $r8 3
+#endif
+   extr $r7 $r7 0:3
+   cmp b32 $r7 0xe
+   bra ne #xtile64
+   mov $r7 4
+   bra #xtileok
+   xtile64:
+   xbit $r7 $flags $p2
+   add b32 $r7 17
+   bset $r4 $r7
+   mov $r7 6
+   xtileok:
+
+   // Op = (x * cpp) & ((1 << Tp) - 1)
+   // Tx = (x * cpp) >> Tp
+   ld b32 $r10 D[$r5 + #ctx_src_xoff]
+   ld b32 $r11 D[$r5 + #ctx_src_cpp]
+   mulu $r10 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   and $r12 $r10 $r11
+   shr b32 $r10 $r7
+
+   // Tyo = y & ((1 << Th) - 1)
+   // Ty  = y >> Th
+   ld b32 $r13 D[$r5 + #ctx_src_yoff]
+   mov $r14 1
+   shl b32 $r14 $r8
+   sub b32 $r14 1
+   and $r11 $r13 $r14
+   shr b32 $r13 $r8
+
+   // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+   add b32 $r14 1
+   shl b32 $r15 $r14 12
+   sub b32 $r14 $r11
+   or $r15 $r14
+   xbit $r6 $flags $p2
+   add b32 $r6 0x208
+   shl b32 $r6 8
+   iowr I[$r6 + 0x000] $r15
+
+   // Op += Tyo << Tp
+   shl b32 $r11 $r7
+   add b32 $r12 $r11
+
+   // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+   ld b32 $r15 D[$r5 + #ctx_src_xsize]
+   ld b32 $r11 D[$r5 + #ctx_src_cpp]
+   mulu $r15 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r7
+   push $r15
+
+   // nTy = (h + ((1 << Th) - 1)) >> Th
+   ld b32 $r15 D[$r5 + #ctx_src_ysize]
+   mov $r11 1
+   shl b32 $r11 $r8
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r8
+   push $r15
+
+   // Tys = Tp + Th
+   // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+   add b32 $r7 $r8
+   sub b32 $r8 2
+   mov $r11 1
+   shl b32 $r11 $r8
+   shl b32 $r11 $r9
+
+   // Tzo = z & ((1 << Td) - 1)
+   // Tz  = z >> Td
+   // Op += Tzo << Tys
+   // Ts  = Tys + Td
+   ld b32 $r8 D[$r5 + #ctx_src_zoff]
+   mov $r14 1
+   shl b32 $r14 $r9
+   sub b32 $r14 1
+   and $r15 $r8 $r14
+   shl b32 $r15 $r7
+   add b32 $r12 $r15
+   add b32 $r7 $r9
+   shr b32 $r8 $r9
+
+   // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+   pop $r15
+   pop $r9
+   mulu $r13 $r9
+   add b32 $r10 $r13
+   mulu $r8 $r9
+   mulu $r8 $r15
+   add b32 $r10 $r8
+   shl b32 $r10 $r7
+
+   // PITCH = (nTx - 1) << Ts
+   sub b32 $r9 1
+   shl b32 $r9 $r7
+   iowr I[$r6 + 0x200] $r9
+
+   // SRC_ADDRESS_LOW   = (Ot + Op) & 0xffffffff
+   // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+   ld b32 $r7 D[$r5 + #ctx_src_address_low]
+   ld b32 $r8 D[$r5 + #ctx_src_address_high]
+   add b32 $r10 $r12
+   add b32 $r7 $r10
+   adc b32 $r8 0
+   shl b32 $r8 16
+   or $r8 $r11
+   sub b32 $r6 0x600
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   iowr I[$r6 + 0x000] $r8
+   ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+   xbit $r6 $flags $p2
+   add b32 $r6 0x202
+   shl b32 $r6 8
+   ld b32 $r7 D[$r5 + #ctx_src_address_low]
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + #ctx_src_address_high]
+   shl b32 $r7 16
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + #ctx_src_pitch]
+   iowr I[$r6 + 0x000] $r7
+   ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+   push $r0
+   push $r1
+   mov $r0 0x800
+   shl b32 $r0 6
+   loop:
+      iord $r1 I[$r0]
+      and $r1 1
+      bra ne #loop
+   pop $r1
+   pop $r0
+   ret
+
+cmd_exec_query:
+   // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+   xbit $r4 $r3 13
+   bra ne #query_counter
+      call #cmd_exec_wait
+      mov $r4 0x80c
+      shl b32 $r4 6
+      ld b32 $r5 D[$r0 + #ctx_query_address_low]
+      add b32 $r5 4
+      iowr I[$r4 + 0x000] $r5
+      iowr I[$r4 + 0x100] $r0
+      mov $r5 0xc
+      iowr I[$r4 + 0x200] $r5
+      add b32 $r4 0x400
+      ld b32 $r5 D[$r0 + #ctx_query_address_high]
+      shl b32 $r5 16
+      iowr I[$r4 + 0x000] $r5
+      add b32 $r4 0x500
+      mov $r5 0x00000b00
+      sethi $r5 0x00010000
+      iowr I[$r4 + 0x000] $r5
+      mov $r5 0x00004040
+      shl b32 $r5 1
+      sethi $r5 0x80800000
+      iowr I[$r4 + 0x100] $r5
+      mov $r5 0x00001110
+      sethi $r5 0x13120000
+      iowr I[$r4 + 0x200] $r5
+      mov $r5 0x00001514
+      sethi $r5 0x17160000
+      iowr I[$r4 + 0x300] $r5
+      mov $r5 0x00002601
+      sethi $r5 0x00010000
+      mov $r4 0x800
+      shl b32 $r4 6
+      iowr I[$r4 + 0x000] $r5
+
+   // write COUNTER
+   query_counter:
+   call #cmd_exec_wait
+   mov $r4 0x80c
+   shl b32 $r4 6
+   ld b32 $r5 D[$r0 + #ctx_query_address_low]
+   iowr I[$r4 + 0x000] $r5
+   iowr I[$r4 + 0x100] $r0
+   mov $r5 0x4
+   iowr I[$r4 + 0x200] $r5
+   add b32 $r4 0x400
+   ld b32 $r5 D[$r0 + #ctx_query_address_high]
+   shl b32 $r5 16
+   iowr I[$r4 + 0x000] $r5
+   add b32 $r4 0x500
+   mov $r5 0x00000300
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00001110
+   sethi $r5 0x13120000
+   iowr I[$r4 + 0x100] $r5
+   ld b32 $r5 D[$r0 + #ctx_query_counter]
+   add b32 $r4 0x500
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00002601
+   sethi $r5 0x00010000
+   mov $r4 0x800
+   shl b32 $r4 6
+   iowr I[$r4 + 0x000] $r5
+   ret
+
+// Execute a copy operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//       000002000 QUERY_SHORT
+//       000001000 QUERY
+//       000000100 DST_LINEAR
+//       000000010 SRC_LINEAR
+//       000000001 FORMAT
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_exec:
+   call #cmd_exec_wait
+
+   // if format requested, call function to calculate it, otherwise
+   // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+   xbit $r15 $r3 0
+   bra e #cmd_exec_no_format
+      call #cmd_exec_set_format
+      mov $r4 0x200
+      bra #cmd_exec_init_src_surface
+   cmd_exec_no_format:
+      mov $r6 0x810
+      shl b32 $r6 6
+      mov $r7 1
+      st b32 D[$r0 + #ctx_src_cpp] $r7
+      st b32 D[$r0 + #ctx_dst_cpp] $r7
+      ld b32 $r7 D[$r0 + #ctx_xcnt]
+      iowr I[$r6 + 0x000] $r7
+      iowr I[$r6 + 0x100] $r7
+      clear b32 $r4
+
+   cmd_exec_init_src_surface:
+   bclr $flags $p2
+   clear b32 $r5
+   xbit $r15 $r3 4
+   bra e #src_tiled
+      call #cmd_exec_set_surface_linear
+      bra #cmd_exec_init_dst_surface
+   src_tiled:
+      call #cmd_exec_set_surface_tiled
+      bset $r4 7
+
+   cmd_exec_init_dst_surface:
+   bset $flags $p2
+   mov $r5 #ctx_dst_address_high - #ctx_src_address_high
+   xbit $r15 $r3 8
+   bra e #dst_tiled
+      call #cmd_exec_set_surface_linear
+      bra #cmd_exec_kick
+   dst_tiled:
+      call #cmd_exec_set_surface_tiled
+      bset $r4 8
+
+   cmd_exec_kick:
+   mov $r5 0x800
+   shl b32 $r5 6
+   ld b32 $r6 D[$r0 + #ctx_ycnt]
+   iowr I[$r5 + 0x100] $r6
+   mov $r6 0x0041
+   // SRC_TARGET = 1, DST_TARGET = 2
+   sethi $r6 0x44000000
+   or $r4 $r6
+   iowr I[$r5] $r4
+
+   // if requested, queue up a QUERY write after the copy has completed
+   xbit $r15 $r3 12
+   bra e #cmd_exec_done
+      call #cmd_exec_query
+
+   cmd_exec_done:
+   ret
+
+// Flush write cache
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_wrcache_flush:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x10000
+   iowr I[$r2] $r3
+   ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3
new file mode 100644
index 0000000..36f0a99
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3
@@ -0,0 +1,2 @@
+#define GF100
+#include "com.fuc"
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h
new file mode 100644
index 0000000..d9af6e4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h
@@ -0,0 +1,606 @@
+uint32_t gf100_pce_data[] = {
+/* 0x0000: ctx_object */
+	0x00000000,
+/* 0x0004: ctx_query_address_high */
+	0x00000000,
+/* 0x0008: ctx_query_address_low */
+	0x00000000,
+/* 0x000c: ctx_query_counter */
+	0x00000000,
+/* 0x0010: ctx_src_address_high */
+	0x00000000,
+/* 0x0014: ctx_src_address_low */
+	0x00000000,
+/* 0x0018: ctx_src_pitch */
+	0x00000000,
+/* 0x001c: ctx_src_tile_mode */
+	0x00000000,
+/* 0x0020: ctx_src_xsize */
+	0x00000000,
+/* 0x0024: ctx_src_ysize */
+	0x00000000,
+/* 0x0028: ctx_src_zsize */
+	0x00000000,
+/* 0x002c: ctx_src_zoff */
+	0x00000000,
+/* 0x0030: ctx_src_xoff */
+	0x00000000,
+/* 0x0034: ctx_src_yoff */
+	0x00000000,
+/* 0x0038: ctx_src_cpp */
+	0x00000000,
+/* 0x003c: ctx_dst_address_high */
+	0x00000000,
+/* 0x0040: ctx_dst_address_low */
+	0x00000000,
+/* 0x0044: ctx_dst_pitch */
+	0x00000000,
+/* 0x0048: ctx_dst_tile_mode */
+	0x00000000,
+/* 0x004c: ctx_dst_xsize */
+	0x00000000,
+/* 0x0050: ctx_dst_ysize */
+	0x00000000,
+/* 0x0054: ctx_dst_zsize */
+	0x00000000,
+/* 0x0058: ctx_dst_zoff */
+	0x00000000,
+/* 0x005c: ctx_dst_xoff */
+	0x00000000,
+/* 0x0060: ctx_dst_yoff */
+	0x00000000,
+/* 0x0064: ctx_dst_cpp */
+	0x00000000,
+/* 0x0068: ctx_format */
+	0x00000000,
+/* 0x006c: ctx_swz_const0 */
+	0x00000000,
+/* 0x0070: ctx_swz_const1 */
+	0x00000000,
+/* 0x0074: ctx_xcnt */
+	0x00000000,
+/* 0x0078: ctx_ycnt */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: dispatch_table */
+	0x00010000,
+	0x00000000,
+	0x00000000,
+	0x00010040,
+	0x0001019f,
+	0x00000000,
+	0x00010050,
+	0x000101a1,
+	0x00000000,
+	0x00070080,
+	0x0000001c,
+	0xfffff000,
+	0x00000020,
+	0xfff80000,
+	0x00000024,
+	0xffffe000,
+	0x00000028,
+	0xfffff800,
+	0x0000002c,
+	0xfffff000,
+	0x00000030,
+	0xfff80000,
+	0x00000034,
+	0xffffe000,
+	0x00070088,
+	0x00000048,
+	0xfffff000,
+	0x0000004c,
+	0xfff80000,
+	0x00000050,
+	0xffffe000,
+	0x00000054,
+	0xfffff800,
+	0x00000058,
+	0xfffff000,
+	0x0000005c,
+	0xfff80000,
+	0x00000060,
+	0xffffe000,
+	0x000200c0,
+	0x000104b8,
+	0x00000000,
+	0x00010541,
+	0x00000000,
+	0x000e00c3,
+	0x00000010,
+	0xffffff00,
+	0x00000014,
+	0x00000000,
+	0x0000003c,
+	0xffffff00,
+	0x00000040,
+	0x00000000,
+	0x00000018,
+	0xfff80000,
+	0x00000044,
+	0xfff80000,
+	0x00000074,
+	0xffff0000,
+	0x00000078,
+	0xffffe000,
+	0x00000068,
+	0xfccc0000,
+	0x0000006c,
+	0x00000000,
+	0x00000070,
+	0x00000000,
+	0x00000004,
+	0xffffff00,
+	0x00000008,
+	0x00000000,
+	0x0000000c,
+	0x00000000,
+	0x00000800,
+};
+
+uint32_t gf100_pce_code[] = {
+/* 0x0000: main */
+	0x04fe04bd,
+	0x3517f000,
+	0xf10010fe,
+	0xf1040017,
+	0xf0fff327,
+	0x12d00023,
+	0x0c25f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x27f01200,
+	0x0012d003,
+/* 0x002f: spin */
+	0xf40031f4,
+	0x0ef40028,
+/* 0x0035: ih */
+	0x8001cffd,
+	0xf40812c4,
+	0x21f4060b,
+/* 0x0041: ih_no_chsw */
+	0x0412c4ca,
+	0xf5070bf4,
+/* 0x004b: ih_no_cmd */
+	0xc4010221,
+	0x01d00c11,
+/* 0x0053: swctx */
+	0xf101f840,
+	0xfe770047,
+	0x47f1004b,
+	0x44cf2100,
+	0x0144f000,
+	0xb60444b6,
+	0xf7f13040,
+	0xf4b6061c,
+	0x1457f106,
+	0x00f5d101,
+	0xb6043594,
+	0x57fe0250,
+	0x0145fe00,
+	0x010052b7,
+	0x00ff67f1,
+	0x56fd60bd,
+	0x0253f004,
+	0xf80545fa,
+	0x0053f003,
+	0xd100e7f0,
+	0x549800fe,
+	0x0845b600,
+	0xb6015698,
+	0x46fd1864,
+	0x0047fe05,
+	0xf00204b9,
+	0x01f40643,
+	0x0604fa09,
+/* 0x00c3: swctx_load */
+	0xfa060ef4,
+/* 0x00c6: swctx_done */
+	0x03f80504,
+/* 0x00ca: chsw */
+	0x27f100f8,
+	0x23cf1400,
+	0x1e3fc800,
+	0xf4170bf4,
+	0x21f40132,
+	0x1e3af053,
+	0xf00023d0,
+	0x24d00147,
+/* 0x00eb: chsw_no_unload */
+	0xcf00f880,
+	0x3dc84023,
+	0x090bf41e,
+	0xf40131f4,
+/* 0x00fa: chsw_finish_load */
+	0x37f05321,
+	0x8023d002,
+/* 0x0102: dispatch */
+	0x37f100f8,
+	0x32cf1900,
+	0x0033cf40,
+	0x07ff24e4,
+	0xf11024b6,
+	0xbd010057,
+/* 0x011b: dispatch_loop */
+	0x5874bd64,
+	0x57580056,
+	0x0450b601,
+	0xf40446b8,
+	0x76bb4d08,
+	0x0447b800,
+	0xbb0f08f4,
+	0x74b60276,
+	0x0057bb03,
+/* 0x013f: dispatch_valid_mthd */
+	0xbbdf0ef4,
+	0x44b60246,
+	0x0045bb03,
+	0xfd014598,
+	0x54b00453,
+	0x201bf400,
+	0x58004558,
+	0x64b00146,
+	0x091bf400,
+	0xf4005380,
+/* 0x0166: dispatch_cmd */
+	0x32f4300e,
+	0xf455f901,
+	0x0ef40c01,
+/* 0x0171: dispatch_invalid_bitfield */
+	0x0225f025,
+/* 0x0174: dispatch_illegal_mthd */
+/* 0x0177: dispatch_error */
+	0xf10125f0,
+	0xd0100047,
+	0x43d00042,
+	0x4027f040,
+/* 0x0187: hostirq_wait */
+	0xcf0002d0,
+	0x24f08002,
+	0x0024b040,
+/* 0x0193: dispatch_done */
+	0xf1f71bf4,
+	0xf01d0027,
+	0x23d00137,
+/* 0x019f: cmd_nop */
+	0xf800f800,
+/* 0x01a1: cmd_pm_trigger */
+	0x0027f100,
+	0xf034bd22,
+	0x23d00233,
+/* 0x01af: cmd_exec_set_format */
+	0xf400f800,
+	0x01b0f030,
+	0x0101b000,
+	0xb00201b0,
+	0x04980301,
+	0x3045c71a,
+	0xc70150b6,
+	0x60b63446,
+	0x3847c701,
+	0xf40170b6,
+	0x84bd0232,
+/* 0x01da: ncomp_loop */
+	0x4ac494bd,
+	0x0445b60f,
+/* 0x01e2: bpc_loop */
+	0xa430b4bd,
+	0x0f18f404,
+	0xbbc0a5ff,
+	0x31f400cb,
+	0x220ef402,
+/* 0x01f4: cmp_c0 */
+	0xf00c1bf4,
+	0xcbbb10c7,
+	0x160ef400,
+/* 0x0200: cmp_c1 */
+	0xf406a430,
+	0xc7f00c18,
+	0x00cbbb14,
+/* 0x020f: cmp_zero */
+	0xf1070ef4,
+/* 0x0213: bpc_next */
+	0x380080c7,
+	0x80b601c8,
+	0x01b0b601,
+	0xf404b5b8,
+	0x90b6c308,
+	0x0497b801,
+	0xfdb208f4,
+	0x06800065,
+	0x1d08980e,
+	0xf40068fd,
+	0x64bd0502,
+/* 0x023c: dst_xcnt */
+	0x800075fd,
+	0x78fd1907,
+	0x1057f100,
+	0x0654b608,
+	0xd00056d0,
+	0x50b74057,
+	0x06980800,
+	0x0162b619,
+	0x980864b6,
+	0x72b60e07,
+	0x0567fd01,
+	0xb70056d0,
+	0xb4010050,
+	0x56d00060,
+	0x0160b400,
+	0xb44056d0,
+	0x56d00260,
+	0x0360b480,
+	0xb7c056d0,
+	0x98040050,
+	0x56d01b06,
+	0x1c069800,
+	0xf44056d0,
+	0x00f81030,
+/* 0x029c: cmd_exec_set_surface_tiled */
+	0xc7075798,
+	0x78c76879,
+	0x0380b664,
+	0xb06077c7,
+	0x1bf40e76,
+	0x0477f009,
+/* 0x02b7: xtile64 */
+	0xf00f0ef4,
+	0x70b6027c,
+	0x0947fd11,
+/* 0x02c3: xtileok */
+	0x980677f0,
+	0x5b980c5a,
+	0x00abfd0e,
+	0xbb01b7f0,
+	0xb2b604b7,
+	0xc4abff01,
+	0x9805a7bb,
+	0xe7f00d5d,
+	0x04e8bb01,
+	0xff01e2b6,
+	0xd8bbb4de,
+	0x01e0b605,
+	0xbb0cef94,
+	0xfefd02eb,
+	0x026cf005,
+	0x020860b7,
+	0xd00864b6,
+	0xb7bb006f,
+	0x00cbbb04,
+	0x98085f98,
+	0xfbfd0e5b,
+	0x01b7f000,
+	0xb604b7bb,
+	0xfbbb01b2,
+	0x05f7bb00,
+	0x5f98f0f9,
+	0x01b7f009,
+	0xb604b8bb,
+	0xfbbb01b2,
+	0x05f8bb00,
+	0x78bbf0f9,
+	0x0282b600,
+	0xbb01b7f0,
+	0xb9bb04b8,
+	0x0b589804,
+	0xbb01e7f0,
+	0xe2b604e9,
+	0xf48eff01,
+	0xbb04f7bb,
+	0x79bb00cf,
+	0x0589bb00,
+	0x90fcf0fc,
+	0xbb00d9fd,
+	0x89fd00ad,
+	0x008ffd00,
+	0xbb00a8bb,
+	0x92b604a7,
+	0x0497bb01,
+	0x988069d0,
+	0x58980557,
+	0x00acbb04,
+	0xb6007abb,
+	0x84b60081,
+	0x058bfd10,
+	0x060062b7,
+	0xb70067d0,
+	0xd0040060,
+	0x00f80068,
+/* 0x03a8: cmd_exec_set_surface_linear */
+	0xb7026cf0,
+	0xb6020260,
+	0x57980864,
+	0x0067d005,
+	0x040060b7,
+	0xb6045798,
+	0x67d01074,
+	0x0060b700,
+	0x06579804,
+	0xf80067d0,
+/* 0x03d1: cmd_exec_wait */
+	0xf900f900,
+	0x0007f110,
+	0x0604b608,
+/* 0x03dc: loop */
+	0xf00001cf,
+	0x1bf40114,
+	0xfc10fcfa,
+/* 0x03eb: cmd_exec_query */
+	0xc800f800,
+	0x1bf40d34,
+	0xd121f570,
+	0x0c47f103,
+	0x0644b608,
+	0xb6020598,
+	0x45d00450,
+	0x4040d000,
+	0xd00c57f0,
+	0x40b78045,
+	0x05980400,
+	0x1054b601,
+	0xb70045d0,
+	0xf1050040,
+	0xf00b0057,
+	0x45d00153,
+	0x4057f100,
+	0x0154b640,
+	0x808053f1,
+	0xf14045d0,
+	0xf1111057,
+	0xd0131253,
+	0x57f18045,
+	0x53f11514,
+	0x45d01716,
+	0x0157f1c0,
+	0x0153f026,
+	0x080047f1,
+	0xd00644b6,
+/* 0x045e: query_counter */
+	0x21f50045,
+	0x47f103d1,
+	0x44b6080c,
+	0x02059806,
+	0xd00045d0,
+	0x57f04040,
+	0x8045d004,
+	0x040040b7,
+	0xb6010598,
+	0x45d01054,
+	0x0040b700,
+	0x0057f105,
+	0x0045d003,
+	0x111057f1,
+	0x131253f1,
+	0x984045d0,
+	0x40b70305,
+	0x45d00500,
+	0x0157f100,
+	0x0153f026,
+	0x080047f1,
+	0xd00644b6,
+	0x00f80045,
+/* 0x04b8: cmd_exec */
+	0x03d121f5,
+	0xf4003fc8,
+	0x21f50e0b,
+	0x47f101af,
+	0x0ef40200,
+/* 0x04cd: cmd_exec_no_format */
+	0x1067f11e,
+	0x0664b608,
+	0x800177f0,
+	0x07800e07,
+	0x1d079819,
+	0xd00067d0,
+	0x44bd4067,
+/* 0x04e8: cmd_exec_init_src_surface */
+	0xbd0232f4,
+	0x043fc854,
+	0xf50a0bf4,
+	0xf403a821,
+/* 0x04fa: src_tiled */
+	0x21f50a0e,
+	0x49f0029c,
+/* 0x0501: cmd_exec_init_dst_surface */
+	0x0231f407,
+	0xc82c57f0,
+	0x0bf4083f,
+	0xa821f50a,
+	0x0a0ef403,
+/* 0x0514: dst_tiled */
+	0x029c21f5,
+/* 0x051b: cmd_exec_kick */
+	0xf10849f0,
+	0xb6080057,
+	0x06980654,
+	0x4056d01e,
+	0xf14167f0,
+	0xfd440063,
+	0x54d00546,
+	0x0c3fc800,
+	0xf5070bf4,
+/* 0x053f: cmd_exec_done */
+	0xf803eb21,
+/* 0x0541: cmd_wrcache_flush */
+	0x0027f100,
+	0xf034bd22,
+	0x23d00133,
+	0x0000f800,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3
new file mode 100644
index 0000000..07bda93
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3
@@ -0,0 +1,2 @@
+#define GT215
+#include "com.fuc"
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h
new file mode 100644
index 0000000..f42c0d0d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h
@@ -0,0 +1,620 @@
+uint32_t gt215_pce_data[] = {
+/* 0x0000: ctx_object */
+	0x00000000,
+/* 0x0004: ctx_dma */
+/* 0x0004: ctx_dma_query */
+	0x00000000,
+/* 0x0008: ctx_dma_src */
+	0x00000000,
+/* 0x000c: ctx_dma_dst */
+	0x00000000,
+/* 0x0010: ctx_query_address_high */
+	0x00000000,
+/* 0x0014: ctx_query_address_low */
+	0x00000000,
+/* 0x0018: ctx_query_counter */
+	0x00000000,
+/* 0x001c: ctx_src_address_high */
+	0x00000000,
+/* 0x0020: ctx_src_address_low */
+	0x00000000,
+/* 0x0024: ctx_src_pitch */
+	0x00000000,
+/* 0x0028: ctx_src_tile_mode */
+	0x00000000,
+/* 0x002c: ctx_src_xsize */
+	0x00000000,
+/* 0x0030: ctx_src_ysize */
+	0x00000000,
+/* 0x0034: ctx_src_zsize */
+	0x00000000,
+/* 0x0038: ctx_src_zoff */
+	0x00000000,
+/* 0x003c: ctx_src_xoff */
+	0x00000000,
+/* 0x0040: ctx_src_yoff */
+	0x00000000,
+/* 0x0044: ctx_src_cpp */
+	0x00000000,
+/* 0x0048: ctx_dst_address_high */
+	0x00000000,
+/* 0x004c: ctx_dst_address_low */
+	0x00000000,
+/* 0x0050: ctx_dst_pitch */
+	0x00000000,
+/* 0x0054: ctx_dst_tile_mode */
+	0x00000000,
+/* 0x0058: ctx_dst_xsize */
+	0x00000000,
+/* 0x005c: ctx_dst_ysize */
+	0x00000000,
+/* 0x0060: ctx_dst_zsize */
+	0x00000000,
+/* 0x0064: ctx_dst_zoff */
+	0x00000000,
+/* 0x0068: ctx_dst_xoff */
+	0x00000000,
+/* 0x006c: ctx_dst_yoff */
+	0x00000000,
+/* 0x0070: ctx_dst_cpp */
+	0x00000000,
+/* 0x0074: ctx_format */
+	0x00000000,
+/* 0x0078: ctx_swz_const0 */
+	0x00000000,
+/* 0x007c: ctx_swz_const1 */
+	0x00000000,
+/* 0x0080: ctx_xcnt */
+	0x00000000,
+/* 0x0084: ctx_ycnt */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: dispatch_table */
+	0x00010000,
+	0x00000000,
+	0x00000000,
+	0x00010040,
+	0x00010160,
+	0x00000000,
+	0x00010050,
+	0x00010162,
+	0x00000000,
+	0x00030060,
+/* 0x0128: dispatch_dma */
+	0x00010170,
+	0x00000000,
+	0x00010170,
+	0x00000000,
+	0x00010170,
+	0x00000000,
+	0x00070080,
+	0x00000028,
+	0xfffff000,
+	0x0000002c,
+	0xfff80000,
+	0x00000030,
+	0xffffe000,
+	0x00000034,
+	0xfffff800,
+	0x00000038,
+	0xfffff000,
+	0x0000003c,
+	0xfff80000,
+	0x00000040,
+	0xffffe000,
+	0x00070088,
+	0x00000054,
+	0xfffff000,
+	0x00000058,
+	0xfff80000,
+	0x0000005c,
+	0xffffe000,
+	0x00000060,
+	0xfffff800,
+	0x00000064,
+	0xfffff000,
+	0x00000068,
+	0xfff80000,
+	0x0000006c,
+	0xffffe000,
+	0x000200c0,
+	0x00010492,
+	0x00000000,
+	0x0001051b,
+	0x00000000,
+	0x000e00c3,
+	0x0000001c,
+	0xffffff00,
+	0x00000020,
+	0x00000000,
+	0x00000048,
+	0xffffff00,
+	0x0000004c,
+	0x00000000,
+	0x00000024,
+	0xfff80000,
+	0x00000050,
+	0xfff80000,
+	0x00000080,
+	0xffff0000,
+	0x00000084,
+	0xffffe000,
+	0x00000074,
+	0xfccc0000,
+	0x00000078,
+	0x00000000,
+	0x0000007c,
+	0x00000000,
+	0x00000010,
+	0xffffff00,
+	0x00000014,
+	0x00000000,
+	0x00000018,
+	0x00000000,
+	0x00000800,
+};
+
+uint32_t gt215_pce_code[] = {
+/* 0x0000: main */
+	0x04fe04bd,
+	0x3517f000,
+	0xf10010fe,
+	0xf1040017,
+	0xf0fff327,
+	0x12d00023,
+	0x0c25f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x27f01200,
+	0x0012d003,
+/* 0x002f: spin */
+	0xf40031f4,
+	0x0ef40028,
+/* 0x0035: ih */
+	0x8001cffd,
+	0xf40812c4,
+	0x21f4060b,
+/* 0x0041: ih_no_chsw */
+	0x0412c472,
+	0xf4060bf4,
+/* 0x004a: ih_no_cmd */
+	0x11c4c321,
+	0x4001d00c,
+/* 0x0052: swctx */
+	0x47f101f8,
+	0x4bfe7700,
+	0x0007fe00,
+	0xf00204b9,
+	0x01f40643,
+	0x0604fa09,
+/* 0x006b: swctx_load */
+	0xfa060ef4,
+/* 0x006e: swctx_done */
+	0x03f80504,
+/* 0x0072: chsw */
+	0x27f100f8,
+	0x23cf1400,
+	0x1e3fc800,
+	0xf4170bf4,
+	0x21f40132,
+	0x1e3af052,
+	0xf00023d0,
+	0x24d00147,
+/* 0x0093: chsw_no_unload */
+	0xcf00f880,
+	0x3dc84023,
+	0x220bf41e,
+	0xf40131f4,
+	0x57f05221,
+	0x0367f004,
+/* 0x00a8: chsw_load_ctx_dma */
+	0xa07856bc,
+	0xb6018068,
+	0x87d00884,
+	0x0162b600,
+/* 0x00bb: chsw_finish_load */
+	0xf0f018f4,
+	0x23d00237,
+/* 0x00c3: dispatch */
+	0xf100f880,
+	0xcf190037,
+	0x33cf4032,
+	0xff24e400,
+	0x1024b607,
+	0x010057f1,
+	0x74bd64bd,
+/* 0x00dc: dispatch_loop */
+	0x58005658,
+	0x50b60157,
+	0x0446b804,
+	0xbb4d08f4,
+	0x47b80076,
+	0x0f08f404,
+	0xb60276bb,
+	0x57bb0374,
+	0xdf0ef400,
+/* 0x0100: dispatch_valid_mthd */
+	0xb60246bb,
+	0x45bb0344,
+	0x01459800,
+	0xb00453fd,
+	0x1bf40054,
+	0x00455820,
+	0xb0014658,
+	0x1bf40064,
+	0x00538009,
+/* 0x0127: dispatch_cmd */
+	0xf4300ef4,
+	0x55f90132,
+	0xf40c01f4,
+/* 0x0132: dispatch_invalid_bitfield */
+	0x25f0250e,
+/* 0x0135: dispatch_illegal_mthd */
+	0x0125f002,
+/* 0x0138: dispatch_error */
+	0x100047f1,
+	0xd00042d0,
+	0x27f04043,
+	0x0002d040,
+/* 0x0148: hostirq_wait */
+	0xf08002cf,
+	0x24b04024,
+	0xf71bf400,
+/* 0x0154: dispatch_done */
+	0x1d0027f1,
+	0xd00137f0,
+	0x00f80023,
+/* 0x0160: cmd_nop */
+/* 0x0162: cmd_pm_trigger */
+	0x27f100f8,
+	0x34bd2200,
+	0xd00233f0,
+	0x00f80023,
+/* 0x0170: cmd_dma */
+	0x012842b7,
+	0xf00145b6,
+	0x43801e39,
+	0x0040b701,
+	0x0644b606,
+	0xf80043d0,
+/* 0x0189: cmd_exec_set_format */
+	0xf030f400,
+	0xb00001b0,
+	0x01b00101,
+	0x0301b002,
+	0xc71d0498,
+	0x50b63045,
+	0x3446c701,
+	0xc70160b6,
+	0x70b63847,
+	0x0232f401,
+	0x94bd84bd,
+/* 0x01b4: ncomp_loop */
+	0xb60f4ac4,
+	0xb4bd0445,
+/* 0x01bc: bpc_loop */
+	0xf404a430,
+	0xa5ff0f18,
+	0x00cbbbc0,
+	0xf40231f4,
+/* 0x01ce: cmp_c0 */
+	0x1bf4220e,
+	0x10c7f00c,
+	0xf400cbbb,
+/* 0x01da: cmp_c1 */
+	0xa430160e,
+	0x0c18f406,
+	0xbb14c7f0,
+	0x0ef400cb,
+/* 0x01e9: cmp_zero */
+	0x80c7f107,
+/* 0x01ed: bpc_next */
+	0x01c83800,
+	0xb60180b6,
+	0xb5b801b0,
+	0xc308f404,
+	0xb80190b6,
+	0x08f40497,
+	0x0065fdb2,
+	0x98110680,
+	0x68fd2008,
+	0x0502f400,
+/* 0x0216: dst_xcnt */
+	0x75fd64bd,
+	0x1c078000,
+	0xf10078fd,
+	0xb6081057,
+	0x56d00654,
+	0x4057d000,
+	0x080050b7,
+	0xb61c0698,
+	0x64b60162,
+	0x11079808,
+	0xfd0172b6,
+	0x56d00567,
+	0x0050b700,
+	0x0060b401,
+	0xb40056d0,
+	0x56d00160,
+	0x0260b440,
+	0xb48056d0,
+	0x56d00360,
+	0x0050b7c0,
+	0x1e069804,
+	0x980056d0,
+	0x56d01f06,
+	0x1030f440,
+/* 0x0276: cmd_exec_set_surface_tiled */
+	0x579800f8,
+	0x6879c70a,
+	0xb66478c7,
+	0x77c70280,
+	0x0e76b060,
+	0xf0091bf4,
+	0x0ef40477,
+/* 0x0291: xtile64 */
+	0x027cf00f,
+	0xfd1170b6,
+	0x77f00947,
+/* 0x029d: xtileok */
+	0x0f5a9806,
+	0xfd115b98,
+	0xb7f000ab,
+	0x04b7bb01,
+	0xff01b2b6,
+	0xa7bbc4ab,
+	0x105d9805,
+	0xbb01e7f0,
+	0xe2b604e8,
+	0xb4deff01,
+	0xb605d8bb,
+	0xef9401e0,
+	0x02ebbb0c,
+	0xf005fefd,
+	0x60b7026c,
+	0x64b60208,
+	0x006fd008,
+	0xbb04b7bb,
+	0x5f9800cb,
+	0x115b980b,
+	0xf000fbfd,
+	0xb7bb01b7,
+	0x01b2b604,
+	0xbb00fbbb,
+	0xf0f905f7,
+	0xf00c5f98,
+	0xb8bb01b7,
+	0x01b2b604,
+	0xbb00fbbb,
+	0xf0f905f8,
+	0xb60078bb,
+	0xb7f00282,
+	0x04b8bb01,
+	0x9804b9bb,
+	0xe7f00e58,
+	0x04e9bb01,
+	0xff01e2b6,
+	0xf7bbf48e,
+	0x00cfbb04,
+	0xbb0079bb,
+	0xf0fc0589,
+	0xd9fd90fc,
+	0x00adbb00,
+	0xfd0089fd,
+	0xa8bb008f,
+	0x04a7bb00,
+	0xbb0192b6,
+	0x69d00497,
+	0x08579880,
+	0xbb075898,
+	0x7abb00ac,
+	0x0081b600,
+	0xfd1084b6,
+	0x62b7058b,
+	0x67d00600,
+	0x0060b700,
+	0x0068d004,
+/* 0x0382: cmd_exec_set_surface_linear */
+	0x6cf000f8,
+	0x0260b702,
+	0x0864b602,
+	0xd0085798,
+	0x60b70067,
+	0x57980400,
+	0x1074b607,
+	0xb70067d0,
+	0x98040060,
+	0x67d00957,
+/* 0x03ab: cmd_exec_wait */
+	0xf900f800,
+	0xf110f900,
+	0xb6080007,
+/* 0x03b6: loop */
+	0x01cf0604,
+	0x0114f000,
+	0xfcfa1bf4,
+	0xf800fc10,
+/* 0x03c5: cmd_exec_query */
+	0x0d34c800,
+	0xf5701bf4,
+	0xf103ab21,
+	0xb6080c47,
+	0x05980644,
+	0x0450b605,
+	0xd00045d0,
+	0x57f04040,
+	0x8045d00c,
+	0x040040b7,
+	0xb6040598,
+	0x45d01054,
+	0x0040b700,
+	0x0057f105,
+	0x0153f00b,
+	0xf10045d0,
+	0xb6404057,
+	0x53f10154,
+	0x45d08080,
+	0x1057f140,
+	0x1253f111,
+	0x8045d013,
+	0x151457f1,
+	0x171653f1,
+	0xf1c045d0,
+	0xf0260157,
+	0x47f10153,
+	0x44b60800,
+	0x0045d006,
+/* 0x0438: query_counter */
+	0x03ab21f5,
+	0x080c47f1,
+	0x980644b6,
+	0x45d00505,
+	0x4040d000,
+	0xd00457f0,
+	0x40b78045,
+	0x05980400,
+	0x1054b604,
+	0xb70045d0,
+	0xf1050040,
+	0xd0030057,
+	0x57f10045,
+	0x53f11110,
+	0x45d01312,
+	0x06059840,
+	0x050040b7,
+	0xf10045d0,
+	0xf0260157,
+	0x47f10153,
+	0x44b60800,
+	0x0045d006,
+/* 0x0492: cmd_exec */
+	0x21f500f8,
+	0x3fc803ab,
+	0x0e0bf400,
+	0x018921f5,
+	0x020047f1,
+/* 0x04a7: cmd_exec_no_format */
+	0xf11e0ef4,
+	0xb6081067,
+	0x77f00664,
+	0x11078001,
+	0x981c0780,
+	0x67d02007,
+	0x4067d000,
+/* 0x04c2: cmd_exec_init_src_surface */
+	0x32f444bd,
+	0xc854bd02,
+	0x0bf4043f,
+	0x8221f50a,
+	0x0a0ef403,
+/* 0x04d4: src_tiled */
+	0x027621f5,
+/* 0x04db: cmd_exec_init_dst_surface */
+	0xf40749f0,
+	0x57f00231,
+	0x083fc82c,
+	0xf50a0bf4,
+	0xf4038221,
+/* 0x04ee: dst_tiled */
+	0x21f50a0e,
+	0x49f00276,
+/* 0x04f5: cmd_exec_kick */
+	0x0057f108,
+	0x0654b608,
+	0xd0210698,
+	0x67f04056,
+	0x0063f141,
+	0x0546fd44,
+	0xc80054d0,
+	0x0bf40c3f,
+	0xc521f507,
+/* 0x0519: cmd_exec_done */
+/* 0x051b: cmd_wrcache_flush */
+	0xf100f803,
+	0xbd220027,
+	0x0133f034,
+	0xf80023d0,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c
new file mode 100644
index 0000000..2d2e549
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+#include <engine/falcon.h>
+#include "fuc/gf100.fuc3.h"
+
+struct gf100_ce_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_ce0_sclass[] = {
+	{ 0x90b5, &nvkm_object_ofuncs },
+	{},
+};
+
+static struct nvkm_oclass
+gf100_ce1_sclass[] = {
+	{ 0x90b8, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_ofuncs
+gf100_ce_context_ofuncs = {
+	.ctor = _nvkm_falcon_context_ctor,
+	.dtor = _nvkm_falcon_context_dtor,
+	.init = _nvkm_falcon_context_init,
+	.fini = _nvkm_falcon_context_fini,
+	.rd32 = _nvkm_falcon_context_rd32,
+	.wr32 = _nvkm_falcon_context_wr32,
+};
+
+static struct nvkm_oclass
+gf100_ce0_cclass = {
+	.handle = NV_ENGCTX(CE0, 0xc0),
+	.ofuncs = &gf100_ce_context_ofuncs,
+};
+
+static struct nvkm_oclass
+gf100_ce1_cclass = {
+	.handle = NV_ENGCTX(CE1, 0xc0),
+	.ofuncs = &gf100_ce_context_ofuncs,
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_ce_init(struct nvkm_object *object)
+{
+	struct gf100_ce_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv, 0x084, nv_engidx(&priv->base.base) - NVDEV_ENGINE_CE0);
+	return 0;
+}
+
+static int
+gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gf100_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, true,
+				 "PCE0", "ce0", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000040;
+	nv_subdev(priv)->intr = gt215_ce_intr;
+	nv_engine(priv)->cclass = &gf100_ce0_cclass;
+	nv_engine(priv)->sclass = gf100_ce0_sclass;
+	nv_falcon(priv)->code.data = gf100_pce_code;
+	nv_falcon(priv)->code.size = sizeof(gf100_pce_code);
+	nv_falcon(priv)->data.data = gf100_pce_data;
+	nv_falcon(priv)->data.size = sizeof(gf100_pce_data);
+	return 0;
+}
+
+static int
+gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gf100_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x105000, true,
+				 "PCE1", "ce1", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000080;
+	nv_subdev(priv)->intr = gt215_ce_intr;
+	nv_engine(priv)->cclass = &gf100_ce1_cclass;
+	nv_engine(priv)->sclass = gf100_ce1_sclass;
+	nv_falcon(priv)->code.data = gf100_pce_code;
+	nv_falcon(priv)->code.size = sizeof(gf100_pce_code);
+	nv_falcon(priv)->data.data = gf100_pce_data;
+	nv_falcon(priv)->data.size = sizeof(gf100_pce_data);
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_ce0_oclass = {
+	.handle = NV_ENGINE(CE0, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ce0_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gf100_ce_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
+
+struct nvkm_oclass
+gf100_ce1_oclass = {
+	.handle = NV_ENGINE(CE1, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ce1_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gf100_ce_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
new file mode 100644
index 0000000..a998932
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+
+#include <core/engctx.h>
+
+struct gk104_ce_priv {
+	struct nvkm_engine base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_ce_sclass[] = {
+	{ 0xa0b5, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_ofuncs
+gk104_ce_context_ofuncs = {
+	.ctor = _nvkm_engctx_ctor,
+	.dtor = _nvkm_engctx_dtor,
+	.init = _nvkm_engctx_init,
+	.fini = _nvkm_engctx_fini,
+	.rd32 = _nvkm_engctx_rd32,
+	.wr32 = _nvkm_engctx_wr32,
+};
+
+static struct nvkm_oclass
+gk104_ce_cclass = {
+	.handle = NV_ENGCTX(CE0, 0xc0),
+	.ofuncs = &gk104_ce_context_ofuncs,
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static void
+gk104_ce_intr(struct nvkm_subdev *subdev)
+{
+	const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0;
+	struct gk104_ce_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
+
+	if (stat) {
+		nv_warn(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
+	}
+}
+
+static int
+gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk104_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_engine_create(parent, engine, oclass, true,
+				 "PCE0", "ce0", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000040;
+	nv_subdev(priv)->intr = gk104_ce_intr;
+	nv_engine(priv)->cclass = &gk104_ce_cclass;
+	nv_engine(priv)->sclass = gk104_ce_sclass;
+	return 0;
+}
+
+static int
+gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk104_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_engine_create(parent, engine, oclass, true,
+				 "PCE1", "ce1", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000080;
+	nv_subdev(priv)->intr = gk104_ce_intr;
+	nv_engine(priv)->cclass = &gk104_ce_cclass;
+	nv_engine(priv)->sclass = gk104_ce_sclass;
+	return 0;
+}
+
+static int
+gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk104_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_engine_create(parent, engine, oclass, true,
+				 "PCE2", "ce2", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00200000;
+	nv_subdev(priv)->intr = gk104_ce_intr;
+	nv_engine(priv)->cclass = &gk104_ce_cclass;
+	nv_engine(priv)->sclass = gk104_ce_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_ce0_oclass = {
+	.handle = NV_ENGINE(CE0, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_ce0_ctor,
+		.dtor = _nvkm_engine_dtor,
+		.init = _nvkm_engine_init,
+		.fini = _nvkm_engine_fini,
+	},
+};
+
+struct nvkm_oclass
+gk104_ce1_oclass = {
+	.handle = NV_ENGINE(CE1, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_ce1_ctor,
+		.dtor = _nvkm_engine_dtor,
+		.init = _nvkm_engine_init,
+		.fini = _nvkm_engine_fini,
+	},
+};
+
+struct nvkm_oclass
+gk104_ce2_oclass = {
+	.handle = NV_ENGINE(CE2, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_ce2_ctor,
+		.dtor = _nvkm_engine_dtor,
+		.init = _nvkm_engine_init,
+		.fini = _nvkm_engine_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
new file mode 100644
index 0000000..d8bb429
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+#include <engine/falcon.h>
+#include <engine/fifo.h>
+#include "fuc/gt215.fuc3.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/enum.h>
+
+struct gt215_ce_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_ce_sclass[] = {
+	{ 0x85b5, &nvkm_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_ce_cclass = {
+	.handle = NV_ENGCTX(CE0, 0xa3),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+
+	},
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_enum
+gt215_ce_isr_error_name[] = {
+	{ 0x0001, "ILLEGAL_MTHD" },
+	{ 0x0002, "INVALID_ENUM" },
+	{ 0x0003, "INVALID_BITFIELD" },
+	{}
+};
+
+void
+gt215_ce_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_falcon *falcon = (void *)subdev;
+	struct nvkm_object *engctx;
+	u32 dispatch = nv_ro32(falcon, 0x01c);
+	u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+	u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
+	u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
+	u32 addr = nv_ro32(falcon, 0x040) >> 16;
+	u32 mthd = (addr & 0x07ff) << 2;
+	u32 subc = (addr & 0x3800) >> 11;
+	u32 data = nv_ro32(falcon, 0x044);
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & 0x00000040) {
+		nv_error(falcon, "DISPATCH_ERROR [");
+		nvkm_enum_print(gt215_ce_isr_error_name, ssta);
+		pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
+		       chid, inst << 12, nvkm_client_name(engctx), subc,
+		       mthd, data);
+		nv_wo32(falcon, 0x004, 0x00000040);
+		stat &= ~0x00000040;
+	}
+
+	if (stat) {
+		nv_error(falcon, "unhandled intr 0x%08x\n", stat);
+		nv_wo32(falcon, 0x004, stat);
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	bool enable = (nv_device(parent)->chipset != 0xaf);
+	struct gt215_ce_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, enable,
+				 "PCE0", "ce0", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00802000;
+	nv_subdev(priv)->intr = gt215_ce_intr;
+	nv_engine(priv)->cclass = &gt215_ce_cclass;
+	nv_engine(priv)->sclass = gt215_ce_sclass;
+	nv_falcon(priv)->code.data = gt215_pce_code;
+	nv_falcon(priv)->code.size = sizeof(gt215_pce_code);
+	nv_falcon(priv)->data.data = gt215_pce_data;
+	nv_falcon(priv)->data.size = sizeof(gt215_pce_data);
+	return 0;
+}
+
+struct nvkm_oclass
+gt215_ce_oclass = {
+	.handle = NV_ENGINE(CE0, 0xa3),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_ce_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = _nvkm_falcon_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild
new file mode 100644
index 0000000..fa39945
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/cipher/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
new file mode 100644
index 0000000..13f3042
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/cipher.h>
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+struct g84_cipher_priv {
+	struct nvkm_engine base;
+};
+
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
+static int
+g84_cipher_object_ctor(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+g84_cipher_ofuncs = {
+	.ctor = g84_cipher_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+g84_cipher_sclass[] = {
+	{ 0x74c1, &g84_cipher_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PCIPHER context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_cipher_cclass = {
+	.handle = NV_ENGCTX(CIPHER, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_engctx_ctor,
+		.dtor = _nvkm_engctx_dtor,
+		.init = _nvkm_engctx_init,
+		.fini = _nvkm_engctx_fini,
+		.rd32 = _nvkm_engctx_rd32,
+		.wr32 = _nvkm_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PCIPHER engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_bitfield
+g84_cipher_intr_mask[] = {
+	{ 0x00000001, "INVALID_STATE" },
+	{ 0x00000002, "ILLEGAL_MTHD" },
+	{ 0x00000004, "ILLEGAL_CLASS" },
+	{ 0x00000080, "QUERY" },
+	{ 0x00000100, "FAULT" },
+	{}
+};
+
+static void
+g84_cipher_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct g84_cipher_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x102130);
+	u32 mthd = nv_rd32(priv, 0x102190);
+	u32 data = nv_rd32(priv, 0x102194);
+	u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat) {
+		nv_error(priv, "%s", "");
+		nvkm_bitfield_print(g84_cipher_intr_mask, stat);
+		pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
+		       chid, (u64)inst << 12, nvkm_client_name(engctx),
+		       mthd, data);
+	}
+
+	nv_wr32(priv, 0x102130, stat);
+	nv_wr32(priv, 0x10200c, 0x10);
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct g84_cipher_priv *priv;
+	int ret;
+
+	ret = nvkm_engine_create(parent, engine, oclass, true,
+				 "PCIPHER", "cipher", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00004000;
+	nv_subdev(priv)->intr = g84_cipher_intr;
+	nv_engine(priv)->cclass = &g84_cipher_cclass;
+	nv_engine(priv)->sclass = g84_cipher_sclass;
+	return 0;
+}
+
+static int
+g84_cipher_init(struct nvkm_object *object)
+{
+	struct g84_cipher_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_engine_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x102130, 0xffffffff);
+	nv_wr32(priv, 0x102140, 0xffffffbf);
+	nv_wr32(priv, 0x10200c, 0x00000010);
+	return 0;
+}
+
+struct nvkm_oclass
+g84_cipher_oclass = {
+	.handle = NV_ENGINE(CIPHER, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_cipher_ctor,
+		.dtor = _nvkm_engine_dtor,
+		.init = g84_cipher_init,
+		.fini = _nvkm_engine_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild
new file mode 100644
index 0000000..de1bf09
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild
@@ -0,0 +1,12 @@
+nvkm-y += nvkm/engine/device/acpi.o
+nvkm-y += nvkm/engine/device/base.o
+nvkm-y += nvkm/engine/device/ctrl.o
+nvkm-y += nvkm/engine/device/nv04.o
+nvkm-y += nvkm/engine/device/nv10.o
+nvkm-y += nvkm/engine/device/nv20.o
+nvkm-y += nvkm/engine/device/nv30.o
+nvkm-y += nvkm/engine/device/nv40.o
+nvkm-y += nvkm/engine/device/nv50.o
+nvkm-y += nvkm/engine/device/gf100.o
+nvkm-y += nvkm/engine/device/gk104.o
+nvkm-y += nvkm/engine/device/gm100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c
new file mode 100644
index 0000000..f42706e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "acpi.h"
+
+#include <core/device.h>
+
+#ifdef CONFIG_ACPI
+static int
+nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct nvkm_device *device =
+		container_of(nb, typeof(*device), acpi.nb);
+	struct acpi_bus_event *info = data;
+
+	if (!strcmp(info->device_class, "ac_adapter"))
+		nvkm_event_send(&device->event, 1, 0, NULL, 0);
+
+	return NOTIFY_DONE;
+}
+#endif
+
+int
+nvkm_acpi_fini(struct nvkm_device *device, bool suspend)
+{
+#ifdef CONFIG_ACPI
+	unregister_acpi_notifier(&device->acpi.nb);
+#endif
+	return 0;
+}
+
+int
+nvkm_acpi_init(struct nvkm_device *device)
+{
+#ifdef CONFIG_ACPI
+	device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
+	register_acpi_notifier(&device->acpi.nb);
+#endif
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h
new file mode 100644
index 0000000..82dd359
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h
@@ -0,0 +1,8 @@
+#ifndef __NVKM_DEVICE_ACPI_H__
+#define __NVKM_DEVICE_ACPI_H__
+#include <core/os.h>
+struct nvkm_device;
+
+int nvkm_acpi_init(struct nvkm_device *);
+int nvkm_acpi_fini(struct nvkm_device *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
new file mode 100644
index 0000000..29bd539
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "acpi.h"
+
+#include <core/client.h>
+#include <core/option.h>
+#include <core/notify.h>
+#include <core/parent.h>
+#include <subdev/bios.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static DEFINE_MUTEX(nv_devices_mutex);
+static LIST_HEAD(nv_devices);
+
+struct nvkm_device *
+nvkm_device_find(u64 name)
+{
+	struct nvkm_device *device, *match = NULL;
+	mutex_lock(&nv_devices_mutex);
+	list_for_each_entry(device, &nv_devices, head) {
+		if (device->handle == name) {
+			match = device;
+			break;
+		}
+	}
+	mutex_unlock(&nv_devices_mutex);
+	return match;
+}
+
+int
+nvkm_device_list(u64 *name, int size)
+{
+	struct nvkm_device *device;
+	int nr = 0;
+	mutex_lock(&nv_devices_mutex);
+	list_for_each_entry(device, &nv_devices, head) {
+		if (nr++ < size)
+			name[nr - 1] = device->handle;
+	}
+	mutex_unlock(&nv_devices_mutex);
+	return nr;
+}
+
+/******************************************************************************
+ * nvkm_devobj (0x0080): class implementation
+ *****************************************************************************/
+
+struct nvkm_devobj {
+	struct nvkm_parent base;
+	struct nvkm_object *subdev[NVDEV_SUBDEV_NR];
+};
+
+static int
+nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nvkm_fb *pfb = nvkm_fb(device);
+	struct nvkm_instmem *imem = nvkm_instmem(device);
+	union {
+		struct nv_device_info_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "device info size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "device info vers %d\n", args->v0.version);
+	} else
+		return ret;
+
+	switch (device->chipset) {
+	case 0x01a:
+	case 0x01f:
+	case 0x04c:
+	case 0x04e:
+	case 0x063:
+	case 0x067:
+	case 0x068:
+	case 0x0aa:
+	case 0x0ac:
+	case 0x0af:
+		args->v0.platform = NV_DEVICE_INFO_V0_IGP;
+		break;
+	default:
+		if (device->pdev) {
+			if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
+				args->v0.platform = NV_DEVICE_INFO_V0_AGP;
+			else
+			if (pci_is_pcie(device->pdev))
+				args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
+			else
+				args->v0.platform = NV_DEVICE_INFO_V0_PCI;
+		} else {
+			args->v0.platform = NV_DEVICE_INFO_V0_SOC;
+		}
+		break;
+	}
+
+	switch (device->card_type) {
+	case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
+	case NV_10:
+	case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
+	case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
+	case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
+	case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
+	case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
+	case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
+	case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
+	case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
+	default:
+		args->v0.family = 0;
+		break;
+	}
+
+	args->v0.chipset  = device->chipset;
+	args->v0.revision = device->chiprev;
+	if (pfb)  args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
+	else      args->v0.ram_size = args->v0.ram_user = 0;
+	if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
+	return 0;
+}
+
+static int
+nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	switch (mthd) {
+	case NV_DEVICE_V0_INFO:
+		return nvkm_devobj_info(object, data, size);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static u8
+nvkm_devobj_rd08(struct nvkm_object *object, u64 addr)
+{
+	return nv_rd08(object->engine, addr);
+}
+
+static u16
+nvkm_devobj_rd16(struct nvkm_object *object, u64 addr)
+{
+	return nv_rd16(object->engine, addr);
+}
+
+static u32
+nvkm_devobj_rd32(struct nvkm_object *object, u64 addr)
+{
+	return nv_rd32(object->engine, addr);
+}
+
+static void
+nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data)
+{
+	nv_wr08(object->engine, addr, data);
+}
+
+static void
+nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data)
+{
+	nv_wr16(object->engine, addr, data);
+}
+
+static void
+nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	nv_wr32(object->engine, addr, data);
+}
+
+static int
+nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+	struct nvkm_device *device = nv_device(object);
+	*addr = nv_device_resource_start(device, 0);
+	*size = nv_device_resource_len(device, 0);
+	return 0;
+}
+
+static const u64 disable_map[] = {
+	[NVDEV_SUBDEV_VBIOS]	= NV_DEVICE_V0_DISABLE_VBIOS,
+	[NVDEV_SUBDEV_DEVINIT]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_GPIO]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_I2C]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_CLK  ]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_MXM]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_MC]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_BUS]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_TIMER]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_FB]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_LTC]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_IBUS]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_INSTMEM]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_MMU]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_BAR]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_VOLT]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_THERM]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_PMU]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_SUBDEV_FUSE]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_ENGINE_DMAOBJ]	= NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_ENGINE_PM     ]  = NV_DEVICE_V0_DISABLE_CORE,
+	[NVDEV_ENGINE_FIFO]	= NV_DEVICE_V0_DISABLE_FIFO,
+	[NVDEV_ENGINE_SW]	= NV_DEVICE_V0_DISABLE_FIFO,
+	[NVDEV_ENGINE_GR]	= NV_DEVICE_V0_DISABLE_GR,
+	[NVDEV_ENGINE_MPEG]	= NV_DEVICE_V0_DISABLE_MPEG,
+	[NVDEV_ENGINE_ME]	= NV_DEVICE_V0_DISABLE_ME,
+	[NVDEV_ENGINE_VP]	= NV_DEVICE_V0_DISABLE_VP,
+	[NVDEV_ENGINE_CIPHER]	= NV_DEVICE_V0_DISABLE_CIPHER,
+	[NVDEV_ENGINE_BSP]	= NV_DEVICE_V0_DISABLE_BSP,
+	[NVDEV_ENGINE_MSPPP]	= NV_DEVICE_V0_DISABLE_MSPPP,
+	[NVDEV_ENGINE_CE0]	= NV_DEVICE_V0_DISABLE_CE0,
+	[NVDEV_ENGINE_CE1]	= NV_DEVICE_V0_DISABLE_CE1,
+	[NVDEV_ENGINE_CE2]	= NV_DEVICE_V0_DISABLE_CE2,
+	[NVDEV_ENGINE_VIC]	= NV_DEVICE_V0_DISABLE_VIC,
+	[NVDEV_ENGINE_MSENC]	= NV_DEVICE_V0_DISABLE_MSENC,
+	[NVDEV_ENGINE_DISP]	= NV_DEVICE_V0_DISABLE_DISP,
+	[NVDEV_ENGINE_MSVLD]	= NV_DEVICE_V0_DISABLE_MSVLD,
+	[NVDEV_ENGINE_SEC]	= NV_DEVICE_V0_DISABLE_SEC,
+	[NVDEV_SUBDEV_NR]	= 0,
+};
+
+static void
+nvkm_devobj_dtor(struct nvkm_object *object)
+{
+	struct nvkm_devobj *devobj = (void *)object;
+	int i;
+
+	for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
+		nvkm_object_ref(NULL, &devobj->subdev[i]);
+
+	nvkm_parent_destroy(&devobj->base);
+}
+
+static struct nvkm_oclass
+nvkm_devobj_oclass_super = {
+	.handle = NV_DEVICE,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.dtor = nvkm_devobj_dtor,
+		.init = _nvkm_parent_init,
+		.fini = _nvkm_parent_fini,
+		.mthd = nvkm_devobj_mthd,
+		.map  = nvkm_devobj_map,
+		.rd08 = nvkm_devobj_rd08,
+		.rd16 = nvkm_devobj_rd16,
+		.rd32 = nvkm_devobj_rd32,
+		.wr08 = nvkm_devobj_wr08,
+		.wr16 = nvkm_devobj_wr16,
+		.wr32 = nvkm_devobj_wr32,
+	}
+};
+
+static int
+nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	union {
+		struct nv_device_v0 v0;
+	} *args = data;
+	struct nvkm_client *client = nv_client(parent);
+	struct nvkm_device *device;
+	struct nvkm_devobj *devobj;
+	u32 boot0, strap;
+	u64 disable, mmio_base, mmio_size;
+	void __iomem *map;
+	int ret, i, c;
+
+	nv_ioctl(parent, "create device size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create device v%d device %016llx "
+				 "disable %016llx debug0 %016llx\n",
+			 args->v0.version, args->v0.device,
+			 args->v0.disable, args->v0.debug0);
+	} else
+		return ret;
+
+	/* give priviledged clients register access */
+	if (client->super)
+		oclass = &nvkm_devobj_oclass_super;
+
+	/* find the device subdev that matches what the client requested */
+	device = nv_device(client->device);
+	if (args->v0.device != ~0) {
+		device = nvkm_device_find(args->v0.device);
+		if (!device)
+			return -ENODEV;
+	}
+
+	ret = nvkm_parent_create(parent, nv_object(device), oclass, 0,
+				 nvkm_control_oclass,
+				 (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				 (1ULL << NVDEV_ENGINE_FIFO) |
+				 (1ULL << NVDEV_ENGINE_DISP) |
+				 (1ULL << NVDEV_ENGINE_PM), &devobj);
+	*pobject = nv_object(devobj);
+	if (ret)
+		return ret;
+
+	mmio_base = nv_device_resource_start(device, 0);
+	mmio_size = nv_device_resource_len(device, 0);
+
+	/* translate api disable mask into internal mapping */
+	disable = args->v0.debug0;
+	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+		if (args->v0.disable & disable_map[i])
+			disable |= (1ULL << i);
+	}
+
+	/* identify the chipset, and determine classes of subdev/engines */
+	if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
+	    !device->card_type) {
+		map = ioremap(mmio_base, 0x102000);
+		if (map == NULL)
+			return -ENOMEM;
+
+		/* switch mmio to cpu's native endianness */
+#ifndef __BIG_ENDIAN
+		if (ioread32_native(map + 0x000004) != 0x00000000)
+#else
+		if (ioread32_native(map + 0x000004) == 0x00000000)
+#endif
+			iowrite32_native(0x01000001, map + 0x000004);
+
+		/* read boot0 and strapping information */
+		boot0 = ioread32_native(map + 0x000000);
+		strap = ioread32_native(map + 0x101000);
+		iounmap(map);
+
+		/* determine chipset and derive architecture from it */
+		if ((boot0 & 0x1f000000) > 0) {
+			device->chipset = (boot0 & 0x1ff00000) >> 20;
+			device->chiprev = (boot0 & 0x000000ff);
+			switch (device->chipset & 0x1f0) {
+			case 0x010: {
+				if (0x461 & (1 << (device->chipset & 0xf)))
+					device->card_type = NV_10;
+				else
+					device->card_type = NV_11;
+				device->chiprev = 0x00;
+				break;
+			}
+			case 0x020: device->card_type = NV_20; break;
+			case 0x030: device->card_type = NV_30; break;
+			case 0x040:
+			case 0x060: device->card_type = NV_40; break;
+			case 0x050:
+			case 0x080:
+			case 0x090:
+			case 0x0a0: device->card_type = NV_50; break;
+			case 0x0c0:
+			case 0x0d0: device->card_type = NV_C0; break;
+			case 0x0e0:
+			case 0x0f0:
+			case 0x100: device->card_type = NV_E0; break;
+			case 0x110:
+			case 0x120: device->card_type = GM100; break;
+			default:
+				break;
+			}
+		} else
+		if ((boot0 & 0xff00fff0) == 0x20004000) {
+			if (boot0 & 0x00f00000)
+				device->chipset = 0x05;
+			else
+				device->chipset = 0x04;
+			device->card_type = NV_04;
+		}
+
+		switch (device->card_type) {
+		case NV_04: ret = nv04_identify(device); break;
+		case NV_10:
+		case NV_11: ret = nv10_identify(device); break;
+		case NV_20: ret = nv20_identify(device); break;
+		case NV_30: ret = nv30_identify(device); break;
+		case NV_40: ret = nv40_identify(device); break;
+		case NV_50: ret = nv50_identify(device); break;
+		case NV_C0: ret = gf100_identify(device); break;
+		case NV_E0: ret = gk104_identify(device); break;
+		case GM100: ret = gm100_identify(device); break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret) {
+			nv_error(device, "unknown chipset, 0x%08x\n", boot0);
+			return ret;
+		}
+
+		nv_info(device, "BOOT0  : 0x%08x\n", boot0);
+		nv_info(device, "Chipset: %s (NV%02X)\n",
+			device->cname, device->chipset);
+		nv_info(device, "Family : NV%02X\n", device->card_type);
+
+		/* determine frequency of timing crystal */
+		if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
+		    (device->chipset >= 0x20 && device->chipset < 0x25))
+			strap &= 0x00000040;
+		else
+			strap &= 0x00400040;
+
+		switch (strap) {
+		case 0x00000000: device->crystal = 13500; break;
+		case 0x00000040: device->crystal = 14318; break;
+		case 0x00400000: device->crystal = 27000; break;
+		case 0x00400040: device->crystal = 25000; break;
+		}
+
+		nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
+	} else
+	if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
+		device->cname = "NULL";
+		device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass;
+	}
+
+	if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
+	    !nv_subdev(device)->mmio) {
+		nv_subdev(device)->mmio  = ioremap(mmio_base, mmio_size);
+		if (!nv_subdev(device)->mmio) {
+			nv_error(device, "unable to map device registers\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* ensure requested subsystems are available for use */
+	for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
+		if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
+			continue;
+
+		if (device->subdev[i]) {
+			nvkm_object_ref(device->subdev[i], &devobj->subdev[i]);
+			continue;
+		}
+
+		ret = nvkm_object_ctor(nv_object(device), NULL, oclass,
+				       NULL, i, &devobj->subdev[i]);
+		if (ret == -ENODEV)
+			continue;
+		if (ret)
+			return ret;
+
+		device->subdev[i] = devobj->subdev[i];
+
+		/* note: can't init *any* subdevs until devinit has been run
+		 * due to not knowing exactly what the vbios init tables will
+		 * mess with.  devinit also can't be run until all of its
+		 * dependencies have been created.
+		 *
+		 * this code delays init of any subdev until all of devinit's
+		 * dependencies have been created, and then initialises each
+		 * subdev in turn as they're created.
+		 */
+		while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
+			struct nvkm_object *subdev = devobj->subdev[c++];
+			if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
+				ret = nvkm_object_inc(subdev);
+				if (ret)
+					return ret;
+				atomic_dec(&nv_object(device)->usecount);
+			} else
+			if (subdev) {
+				nvkm_subdev_reset(subdev);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nvkm_devobj_ofuncs = {
+	.ctor = nvkm_devobj_ctor,
+	.dtor = nvkm_devobj_dtor,
+	.init = _nvkm_parent_init,
+	.fini = _nvkm_parent_fini,
+	.mthd = nvkm_devobj_mthd,
+};
+
+/******************************************************************************
+ * nvkm_device: engine functions
+ *****************************************************************************/
+
+struct nvkm_device *
+nv_device(void *obj)
+{
+	struct nvkm_object *device = nv_object(obj);
+	if (device->engine == NULL) {
+		while (device && device->parent)
+			device = device->parent;
+	} else {
+		device = &nv_object(obj)->engine->subdev.object;
+		if (device && device->parent)
+			device = device->parent;
+	}
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!device))
+		nv_assert("BAD CAST -> NvDevice, 0x%08x\n", nv_hclass(obj));
+#endif
+	return (void *)device;
+}
+
+static struct nvkm_oclass
+nvkm_device_sclass[] = {
+	{ 0x0080, &nvkm_devobj_ofuncs },
+	{}
+};
+
+static int
+nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
+		       struct nvkm_notify *notify)
+{
+	if (!WARN_ON(size != 0)) {
+		notify->size  = 0;
+		notify->types = 1;
+		notify->index = 0;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static const struct nvkm_event_func
+nvkm_device_event_func = {
+	.ctor = nvkm_device_event_ctor,
+};
+
+static int
+nvkm_device_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_device *device = (void *)object;
+	struct nvkm_object *subdev;
+	int ret, i;
+
+	for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
+		if ((subdev = device->subdev[i])) {
+			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+				ret = nvkm_object_dec(subdev, suspend);
+				if (ret && suspend)
+					goto fail;
+			}
+		}
+	}
+
+	ret = nvkm_acpi_fini(device, suspend);
+fail:
+	for (; ret && i < NVDEV_SUBDEV_NR; i++) {
+		if ((subdev = device->subdev[i])) {
+			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+				ret = nvkm_object_inc(subdev);
+				if (ret) {
+					/* XXX */
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+nvkm_device_init(struct nvkm_object *object)
+{
+	struct nvkm_device *device = (void *)object;
+	struct nvkm_object *subdev;
+	int ret, i = 0;
+
+	ret = nvkm_acpi_init(device);
+	if (ret)
+		goto fail;
+
+	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+		if ((subdev = device->subdev[i])) {
+			if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+				ret = nvkm_object_inc(subdev);
+				if (ret)
+					goto fail;
+			} else {
+				nvkm_subdev_reset(subdev);
+			}
+		}
+	}
+
+	ret = 0;
+fail:
+	for (--i; ret && i >= 0; i--) {
+		if ((subdev = device->subdev[i])) {
+			if (!nv_iclass(subdev, NV_ENGINE_CLASS))
+				nvkm_object_dec(subdev, false);
+		}
+	}
+
+	if (ret)
+		nvkm_acpi_fini(device, false);
+	return ret;
+}
+
+static void
+nvkm_device_dtor(struct nvkm_object *object)
+{
+	struct nvkm_device *device = (void *)object;
+
+	nvkm_event_fini(&device->event);
+
+	mutex_lock(&nv_devices_mutex);
+	list_del(&device->head);
+	mutex_unlock(&nv_devices_mutex);
+
+	if (nv_subdev(device)->mmio)
+		iounmap(nv_subdev(device)->mmio);
+
+	nvkm_engine_destroy(&device->engine);
+}
+
+resource_size_t
+nv_device_resource_start(struct nvkm_device *device, unsigned int bar)
+{
+	if (nv_device_is_pci(device)) {
+		return pci_resource_start(device->pdev, bar);
+	} else {
+		struct resource *res;
+		res = platform_get_resource(device->platformdev,
+					    IORESOURCE_MEM, bar);
+		if (!res)
+			return 0;
+		return res->start;
+	}
+}
+
+resource_size_t
+nv_device_resource_len(struct nvkm_device *device, unsigned int bar)
+{
+	if (nv_device_is_pci(device)) {
+		return pci_resource_len(device->pdev, bar);
+	} else {
+		struct resource *res;
+		res = platform_get_resource(device->platformdev,
+					    IORESOURCE_MEM, bar);
+		if (!res)
+			return 0;
+		return resource_size(res);
+	}
+}
+
+int
+nv_device_get_irq(struct nvkm_device *device, bool stall)
+{
+	if (nv_device_is_pci(device)) {
+		return device->pdev->irq;
+	} else {
+		return platform_get_irq_byname(device->platformdev,
+					       stall ? "stall" : "nonstall");
+	}
+}
+
+static struct nvkm_oclass
+nvkm_device_oclass = {
+	.handle = NV_ENGINE(DEVICE, 0x00),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.dtor = nvkm_device_dtor,
+		.init = nvkm_device_init,
+		.fini = nvkm_device_fini,
+	},
+};
+
+int
+nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name,
+		    const char *sname, const char *cfg, const char *dbg,
+		    int length, void **pobject)
+{
+	struct nvkm_device *device;
+	int ret = -EEXIST;
+
+	mutex_lock(&nv_devices_mutex);
+	list_for_each_entry(device, &nv_devices, head) {
+		if (device->handle == name)
+			goto done;
+	}
+
+	ret = nvkm_engine_create_(NULL, NULL, &nvkm_device_oclass, true,
+				  "DEVICE", "device", length, pobject);
+	device = *pobject;
+	if (ret)
+		goto done;
+
+	switch (type) {
+	case NVKM_BUS_PCI:
+		device->pdev = dev;
+		break;
+	case NVKM_BUS_PLATFORM:
+		device->platformdev = dev;
+		break;
+	}
+	device->handle = name;
+	device->cfgopt = cfg;
+	device->dbgopt = dbg;
+	device->name = sname;
+
+	nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE");
+	nv_engine(device)->sclass = nvkm_device_sclass;
+	list_add(&device->head, &nv_devices);
+
+	ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event);
+done:
+	mutex_unlock(&nv_devices_mutex);
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
new file mode 100644
index 0000000..0b794b1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <subdev/clk.h>
+
+#include <nvif/class.h>
+#include <nvif/ioctl.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_control_pstate_info_v0 v0;
+	} *args = data;
+	struct nvkm_clk *clk = nvkm_clk(object);
+	int ret;
+
+	nv_ioctl(object, "control pstate info size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "control pstate info vers %d\n",
+			 args->v0.version);
+	} else
+		return ret;
+
+	if (clk) {
+		args->v0.count = clk->state_nr;
+		args->v0.ustate_ac = clk->ustate_ac;
+		args->v0.ustate_dc = clk->ustate_dc;
+		args->v0.pwrsrc = clk->pwrsrc;
+		args->v0.pstate = clk->pstate;
+	} else {
+		args->v0.count = 0;
+		args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
+		args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
+		args->v0.pwrsrc = -ENOSYS;
+		args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static int
+nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_control_pstate_attr_v0 v0;
+	} *args = data;
+	struct nvkm_clk *clk = nvkm_clk(object);
+	struct nvkm_domain *domain;
+	struct nvkm_pstate *pstate;
+	struct nvkm_cstate *cstate;
+	int i = 0, j = -1;
+	u32 lo, hi;
+	int ret;
+
+	nv_ioctl(object, "control pstate attr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "control pstate attr vers %d state %d "
+				 "index %d\n",
+			 args->v0.version, args->v0.state, args->v0.index);
+		if (!clk)
+			return -ENODEV;
+		if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
+			return -EINVAL;
+		if (args->v0.state >= clk->state_nr)
+			return -EINVAL;
+	} else
+		return ret;
+	domain = clk->domains;
+
+	while (domain->name != nv_clk_src_max) {
+		if (domain->mname && ++j == args->v0.index)
+			break;
+		domain++;
+	}
+
+	if (domain->name == nv_clk_src_max)
+		return -EINVAL;
+
+	if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
+		list_for_each_entry(pstate, &clk->states, head) {
+			if (i++ == args->v0.state)
+				break;
+		}
+
+		lo = pstate->base.domain[domain->name];
+		hi = lo;
+		list_for_each_entry(cstate, &pstate->list, head) {
+			lo = min(lo, cstate->domain[domain->name]);
+			hi = max(hi, cstate->domain[domain->name]);
+		}
+
+		args->v0.state = pstate->pstate;
+	} else {
+		lo = max(clk->read(clk, domain->name), 0);
+		hi = lo;
+	}
+
+	snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
+	snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
+	args->v0.min = lo / domain->mdiv;
+	args->v0.max = hi / domain->mdiv;
+
+	args->v0.index = 0;
+	while ((++domain)->name != nv_clk_src_max) {
+		if (domain->mname) {
+			args->v0.index = ++j;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int
+nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_control_pstate_user_v0 v0;
+	} *args = data;
+	struct nvkm_clk *clk = nvkm_clk(object);
+	int ret;
+
+	nv_ioctl(object, "control pstate user size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "control pstate user vers %d ustate %d "
+				 "pwrsrc %d\n", args->v0.version,
+			 args->v0.ustate, args->v0.pwrsrc);
+		if (!clk)
+			return -ENODEV;
+	} else
+		return ret;
+
+	if (args->v0.pwrsrc >= 0) {
+		ret |= nvkm_clk_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
+	} else {
+		ret |= nvkm_clk_ustate(clk, args->v0.ustate, 0);
+		ret |= nvkm_clk_ustate(clk, args->v0.ustate, 1);
+	}
+
+	return ret;
+}
+
+static int
+nvkm_control_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	switch (mthd) {
+	case NVIF_CONTROL_PSTATE_INFO:
+		return nvkm_control_mthd_pstate_info(object, data, size);
+	case NVIF_CONTROL_PSTATE_ATTR:
+		return nvkm_control_mthd_pstate_attr(object, data, size);
+	case NVIF_CONTROL_PSTATE_USER:
+		return nvkm_control_mthd_pstate_user(object, data, size);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static struct nvkm_ofuncs
+nvkm_control_ofuncs = {
+	.ctor = _nvkm_object_ctor,
+	.dtor = nvkm_object_destroy,
+	.init = nvkm_object_init,
+	.fini = nvkm_object_fini,
+	.mthd = nvkm_control_mthd,
+};
+
+struct nvkm_oclass
+nvkm_control_oclass[] = {
+	{ .handle = NVIF_IOCTL_NEW_V0_CONTROL,
+	  .ofuncs = &nvkm_control_ofuncs
+	},
+	{}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
new file mode 100644
index 0000000..82b38d7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mspdec.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/msppp.h>
+#include <engine/ce.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+gf100_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0xc0:
+		device->cname = "GF100";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf100_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf100_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gf100_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xc4:
+		device->cname = "GF104";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf100_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gf100_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xc3:
+		device->cname = "GF106";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xce:
+		device->cname = "GF114";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf100_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gf100_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xcf:
+		device->cname = "GF116";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xc1:
+		device->cname = "GF108";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf108_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xc8:
+		device->cname = "GF110";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf100_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf100_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf100_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf110_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gf100_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xd9:
+		device->cname = "GF119";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gf110_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gf110_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf119_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gf110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	case 0xd7:
+		device->cname = "GF117";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gf110_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gf117_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gf100_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gf100_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gf100_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gf100_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gf100_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gf117_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gf100_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gf100_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gf110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gf100_pm_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Fermi chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
new file mode 100644
index 0000000..bf58934
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+#include <engine/ce.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/pm.h>
+
+int
+gk104_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0xe4:
+		device->cname = "GK104";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk104_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk104_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk104_pm_oclass;
+		break;
+	case 0xe7:
+		device->cname = "GK107";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk104_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk104_pm_oclass;
+		break;
+	case 0xe6:
+		device->cname = "GK106";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk104_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk104_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk104_pm_oclass;
+		break;
+	case 0xea:
+		device->cname = "GK20A";
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk20a_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk20a_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gk20a_bar_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk20a_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk20a_gr_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk104_pm_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &gk20a_volt_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk20a_pmu_oclass;
+		break;
+	case 0xf0:
+		device->cname = "GK110";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk110_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk110_pm_oclass;
+		break;
+	case 0xf1:
+		device->cname = "GK110B";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gf110_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gf106_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gf110_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk104_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk110b_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] = &gk110_pm_oclass;
+		break;
+	case 0x106:
+		device->cname = "GK208B";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk208_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		break;
+	case 0x108:
+		device->cname = "GK208";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gk104_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gf110_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gf100_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gk104_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gk208_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gk110_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Kepler chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
new file mode 100644
index 0000000..539561e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+#include <engine/ce.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/pm.h>
+
+int
+gm100_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x117:
+		device->cname = "GM107";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gf110_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm107_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+
+#if 0
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gm107_disp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gk104_ce0_oclass;
+#if 0
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gk104_ce1_oclass;
+#endif
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gk104_ce2_oclass;
+#if 0
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+		break;
+	case 0x124:
+		device->cname = "GM204";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  gk104_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  gm204_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] = &gm107_fuse_oclass;
+#if 0
+		/* looks to be some non-trivial changes */
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gk104_clk_oclass;
+		/* priv ring says no to 0x10eb14 writes */
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gm107_therm_oclass;
+#endif
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm204_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  gf100_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_LTC    ] =  gm107_ltc_oclass;
+		device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk104_ibus_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &gf100_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &gf100_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gk208_pmu_oclass;
+#if 0
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  gf110_dmaeng_oclass;
+#if 0
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  gk208_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
+#endif
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gm204_disp_oclass;
+#if 0
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gm204_ce0_oclass;
+		device->oclass[NVDEV_ENGINE_CE1    ] = &gm204_ce1_oclass;
+		device->oclass[NVDEV_ENGINE_CE2    ] = &gm204_ce2_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &gk104_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &gf100_msppp_oclass;
+#endif
+		break;
+	default:
+		nv_fatal(device, "unknown Maxwell chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
new file mode 100644
index 0000000..5a2ae04
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv04_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x04:
+		device->cname = "NV04";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv04_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x05:
+		device->cname = "NV05";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv05_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown RIVA chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
new file mode 100644
index 0000000..94a1ca4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv10_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x10:
+		device->cname = "NV10";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x15:
+		device->cname = "NV15";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x16:
+		device->cname = "NV16";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x1a:
+		device->cname = "nForce";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x11:
+		device->cname = "NV11";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x17:
+		device->cname = "NV17";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x1f:
+		device->cname = "nForce2";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x18:
+		device->cname = "NV18";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Celsius chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
new file mode 100644
index 0000000..d5ec893
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv20_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x20:
+		device->cname = "NV20";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv20_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv20_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x25:
+		device->cname = "NV25";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x28:
+		device->cname = "NV28";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x2a:
+		device->cname = "NV2A";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Kelvin chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
new file mode 100644
index 0000000..dda0962
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+
+int
+nv30_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x30:
+		device->cname = "NV30";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x35:
+		device->cname = "NV35";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv35_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_gr_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x31:
+		device->cname = "NV31";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x36:
+		device->cname = "NV36";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv36_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	case 0x34:
+		device->cname = "NV34";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv04_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv34_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Rankine chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
new file mode 100644
index 0000000..c630136
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/mmu.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+nv40_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x40:
+		device->cname = "NV40";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x41:
+		device->cname = "NV41";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x42:
+		device->cname = "NV42";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x43:
+		device->cname = "NV43";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x45:
+		device->cname = "NV45";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv04_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x47:
+		device->cname = "G70";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv47_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x49:
+		device->cname = "G71";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x4b:
+		device->cname = "G73";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv41_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x44:
+		device->cname = "NV44";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x46:
+		device->cname = "G72";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x4a:
+		device->cname = "NV44A";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x4c:
+		device->cname = "C61";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x4e:
+		device->cname = "C51";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv4e_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x63:
+		device->cname = "C73";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x67:
+		device->cname = "C67";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	case 0x68:
+		device->cname = "C68";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv10_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv04_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &nv40_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv44_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv04_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Curie chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
new file mode 100644
index 0000000..249b844
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/vp.h>
+#include <engine/cipher.h>
+#include <engine/sec.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/ce.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+nv50_identify(struct nvkm_device *device)
+{
+	switch (device->chipset) {
+	case 0x50:
+		device->cname = "G80";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  nv50_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  nv50_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  nv50_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  nv50_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  nv50_pm_oclass;
+		break;
+	case 0x84:
+		device->cname = "G84";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g84_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0x86:
+		device->cname = "G86";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g84_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0x92:
+		device->cname = "G92";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  nv50_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g84_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0x94:
+		device->cname = "G94";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g94_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g94_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0x96:
+		device->cname = "G96";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g94_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g94_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0x98:
+		device->cname = "G98";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g98_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_SEC    ] = &g98_sec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g94_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0xa0:
+		device->cname = "G200";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  nv50_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  g84_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g84_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  g84_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &g84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &g84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt200_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0xaa:
+		device->cname = "MCP77/MCP78";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  mcp77_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g98_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  mcp77_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_SEC    ] = &g98_sec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g94_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0xac:
+		device->cname = "MCP79/MCP7A";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] =  mcp77_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &g84_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  g98_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  mcp77_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_SEC    ] = &g98_sec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  g94_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
+		break;
+	case 0xa3:
+		device->cname = "GT215";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gt215_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gt215_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gt215_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gt215_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gt215_ce_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
+		break;
+	case 0xa5:
+		device->cname = "GT216";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gt215_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gt215_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gt215_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gt215_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gt215_ce_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
+		break;
+	case 0xa8:
+		device->cname = "GT218";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gt215_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  gt215_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  gt215_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gt215_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gt215_ce_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
+		break;
+	case 0xaf:
+		device->cname = "MCP89";
+		device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nvkm_bios_oclass;
+		device->oclass[NVDEV_SUBDEV_GPIO   ] =  g94_gpio_oclass;
+		device->oclass[NVDEV_SUBDEV_I2C    ] =  g94_i2c_oclass;
+		device->oclass[NVDEV_SUBDEV_FUSE   ] =  &nv50_fuse_oclass;
+		device->oclass[NVDEV_SUBDEV_CLK    ] = &gt215_clk_oclass;
+		device->oclass[NVDEV_SUBDEV_THERM  ] = &gt215_therm_oclass;
+		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] =  mcp89_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_MC     ] =  g98_mc_oclass;
+		device->oclass[NVDEV_SUBDEV_BUS    ] =  g94_bus_oclass;
+		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+		device->oclass[NVDEV_SUBDEV_FB     ] =  mcp89_fb_oclass;
+		device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+		device->oclass[NVDEV_SUBDEV_MMU    ] = &nv50_mmu_oclass;
+		device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+		device->oclass[NVDEV_SUBDEV_PMU    ] =  gt215_pmu_oclass;
+		device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+		device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nv50_dmaeng_oclass;
+		device->oclass[NVDEV_ENGINE_FIFO   ] =  g84_fifo_oclass;
+		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
+		device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+		device->oclass[NVDEV_ENGINE_MSVLD  ] = &g98_msvld_oclass;
+		device->oclass[NVDEV_ENGINE_MSPPP  ] = &g98_msppp_oclass;
+		device->oclass[NVDEV_ENGINE_CE0    ] = &gt215_ce_oclass;
+		device->oclass[NVDEV_ENGINE_DISP   ] =  gt215_disp_oclass;
+		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
+		break;
+	default:
+		nv_fatal(device, "unknown Tesla chipset\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
new file mode 100644
index 0000000..8d3590e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -0,0 +1,16 @@
+#ifndef __NVKM_DEVICE_PRIV_H__
+#define __NVKM_DEVICE_PRIV_H__
+#include <core/device.h>
+
+extern struct nvkm_oclass nvkm_control_oclass[];
+
+int nv04_identify(struct nvkm_device *);
+int nv10_identify(struct nvkm_device *);
+int nv20_identify(struct nvkm_device *);
+int nv30_identify(struct nvkm_device *);
+int nv40_identify(struct nvkm_device *);
+int nv50_identify(struct nvkm_device *);
+int gf100_identify(struct nvkm_device *);
+int gk104_identify(struct nvkm_device *);
+int gm100_identify(struct nvkm_device *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
new file mode 100644
index 0000000..16a4e2a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -0,0 +1,29 @@
+nvkm-y += nvkm/engine/disp/base.o
+nvkm-y += nvkm/engine/disp/conn.o
+nvkm-y += nvkm/engine/disp/outp.o
+nvkm-y += nvkm/engine/disp/outpdp.o
+nvkm-y += nvkm/engine/disp/nv04.o
+nvkm-y += nvkm/engine/disp/nv50.o
+nvkm-y += nvkm/engine/disp/g84.o
+nvkm-y += nvkm/engine/disp/g94.o
+nvkm-y += nvkm/engine/disp/gt200.o
+nvkm-y += nvkm/engine/disp/gt215.o
+nvkm-y += nvkm/engine/disp/gf110.o
+nvkm-y += nvkm/engine/disp/gk104.o
+nvkm-y += nvkm/engine/disp/gk110.o
+nvkm-y += nvkm/engine/disp/gm107.o
+nvkm-y += nvkm/engine/disp/gm204.o
+nvkm-y += nvkm/engine/disp/dacnv50.o
+nvkm-y += nvkm/engine/disp/dport.o
+nvkm-y += nvkm/engine/disp/hdagt215.o
+nvkm-y += nvkm/engine/disp/hdagf110.o
+nvkm-y += nvkm/engine/disp/hdmig84.o
+nvkm-y += nvkm/engine/disp/hdmigt215.o
+nvkm-y += nvkm/engine/disp/hdmigf110.o
+nvkm-y += nvkm/engine/disp/hdmigk104.o
+nvkm-y += nvkm/engine/disp/piornv50.o
+nvkm-y += nvkm/engine/disp/sornv50.o
+nvkm-y += nvkm/engine/disp/sorg94.o
+nvkm-y += nvkm/engine/disp/sorgf110.o
+nvkm-y += nvkm/engine/disp/sorgm204.o
+nvkm-y += nvkm/engine/disp/vga.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
new file mode 100644
index 0000000..23d1b5c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "conn.h"
+#include "outp.h"
+
+#include <core/notify.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+int
+nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size,
+		      struct nvkm_notify *notify)
+{
+	struct nvkm_disp *disp =
+		container_of(notify->event, typeof(*disp), vblank);
+	union {
+		struct nvif_notify_head_req_v0 v0;
+	} *req = data;
+	int ret;
+
+	if (nvif_unpack(req->v0, 0, 0, false)) {
+		notify->size = sizeof(struct nvif_notify_head_rep_v0);
+		if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
+			notify->types = 1;
+			notify->index = req->v0.head;
+			return 0;
+		}
+	}
+
+	return ret;
+}
+
+void
+nvkm_disp_vblank(struct nvkm_disp *disp, int head)
+{
+	struct nvif_notify_head_rep_v0 rep = {};
+	nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
+}
+
+static int
+nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
+		   struct nvkm_notify *notify)
+{
+	struct nvkm_disp *disp =
+		container_of(notify->event, typeof(*disp), hpd);
+	union {
+		struct nvif_notify_conn_req_v0 v0;
+	} *req = data;
+	struct nvkm_output *outp;
+	int ret;
+
+	if (nvif_unpack(req->v0, 0, 0, false)) {
+		notify->size = sizeof(struct nvif_notify_conn_rep_v0);
+		list_for_each_entry(outp, &disp->outp, head) {
+			if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
+				if (ret = -ENODEV, outp->conn->hpd.event) {
+					notify->types = req->v0.mask;
+					notify->index = req->v0.conn;
+					ret = 0;
+				}
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static const struct nvkm_event_func
+nvkm_disp_hpd_func = {
+	.ctor = nvkm_disp_hpd_ctor
+};
+
+int
+nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
+{
+	struct nvkm_disp *disp = (void *)object->engine;
+	switch (type) {
+	case NV04_DISP_NTFY_VBLANK:
+		*event = &disp->vblank;
+		return 0;
+	case NV04_DISP_NTFY_CONN:
+		*event = &disp->hpd;
+		return 0;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+int
+_nvkm_disp_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_disp *disp = (void *)object;
+	struct nvkm_output *outp;
+	int ret;
+
+	list_for_each_entry(outp, &disp->outp, head) {
+		ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
+		if (ret && suspend)
+			goto fail_outp;
+	}
+
+	return nvkm_engine_fini(&disp->base, suspend);
+
+fail_outp:
+	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+		nv_ofuncs(outp)->init(nv_object(outp));
+	}
+
+	return ret;
+}
+
+int
+_nvkm_disp_init(struct nvkm_object *object)
+{
+	struct nvkm_disp *disp = (void *)object;
+	struct nvkm_output *outp;
+	int ret;
+
+	ret = nvkm_engine_init(&disp->base);
+	if (ret)
+		return ret;
+
+	list_for_each_entry(outp, &disp->outp, head) {
+		ret = nv_ofuncs(outp)->init(nv_object(outp));
+		if (ret)
+			goto fail_outp;
+	}
+
+	return ret;
+
+fail_outp:
+	list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+		nv_ofuncs(outp)->fini(nv_object(outp), false);
+	}
+
+	return ret;
+}
+
+void
+_nvkm_disp_dtor(struct nvkm_object *object)
+{
+	struct nvkm_disp *disp = (void *)object;
+	struct nvkm_output *outp, *outt;
+
+	nvkm_event_fini(&disp->vblank);
+	nvkm_event_fini(&disp->hpd);
+
+	if (disp->outp.next) {
+		list_for_each_entry_safe(outp, outt, &disp->outp, head) {
+			nvkm_object_ref(NULL, (struct nvkm_object **)&outp);
+		}
+	}
+
+	nvkm_engine_destroy(&disp->base);
+}
+
+int
+nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, int heads, const char *intname,
+		  const char *extname, int length, void **pobject)
+{
+	struct nvkm_disp_impl *impl = (void *)oclass;
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_disp *disp;
+	struct nvkm_oclass **sclass;
+	struct nvkm_object *object;
+	struct dcb_output dcbE;
+	u8  hpd = 0, ver, hdr;
+	u32 data;
+	int ret, i;
+
+	ret = nvkm_engine_create_(parent, engine, oclass, true, intname,
+				  extname, length, pobject);
+	disp = *pobject;
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&disp->outp);
+
+	/* create output objects for each display path in the vbios */
+	i = -1;
+	while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
+		if (dcbE.type == DCB_OUTPUT_UNUSED)
+			continue;
+		if (dcbE.type == DCB_OUTPUT_EOL)
+			break;
+		data = dcbE.location << 4 | dcbE.type;
+
+		oclass = nvkm_output_oclass;
+		sclass = impl->outp;
+		while (sclass && sclass[0]) {
+			if (sclass[0]->handle == data) {
+				oclass = sclass[0];
+				break;
+			}
+			sclass++;
+		}
+
+		nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object);
+		hpd = max(hpd, (u8)(dcbE.connector + 1));
+	}
+
+	ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
new file mode 100644
index 0000000..cf03e02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "conn.h"
+#include "outp.h"
+#include "priv.h"
+
+#include <subdev/gpio.h>
+
+#include <nvif/event.h>
+
+static int
+nvkm_connector_hpd(struct nvkm_notify *notify)
+{
+	struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
+	struct nvkm_disp *disp = nvkm_disp(conn);
+	struct nvkm_gpio *gpio = nvkm_gpio(conn);
+	const struct nvkm_gpio_ntfy_rep *line = notify->data;
+	struct nvif_notify_conn_rep_v0 rep;
+	int index = conn->index;
+
+	DBG("HPD: %d\n", line->mask);
+
+	if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
+		rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
+	else
+		rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
+	rep.version = 0;
+
+	nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+	return NVKM_NOTIFY_KEEP;
+}
+
+int
+_nvkm_connector_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_connector *conn = (void *)object;
+	nvkm_notify_put(&conn->hpd);
+	return nvkm_object_fini(&conn->base, suspend);
+}
+
+int
+_nvkm_connector_init(struct nvkm_object *object)
+{
+	struct nvkm_connector *conn = (void *)object;
+	int ret = nvkm_object_init(&conn->base);
+	if (ret == 0)
+		nvkm_notify_get(&conn->hpd);
+	return ret;
+}
+
+void
+_nvkm_connector_dtor(struct nvkm_object *object)
+{
+	struct nvkm_connector *conn = (void *)object;
+	nvkm_notify_fini(&conn->hpd);
+	nvkm_object_destroy(&conn->base);
+}
+
+int
+nvkm_connector_create_(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass,
+		       struct nvbios_connE *info, int index,
+		       int length, void **pobject)
+{
+	static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
+	struct nvkm_disp *disp = nvkm_disp(parent);
+	struct nvkm_gpio *gpio = nvkm_gpio(parent);
+	struct nvkm_connector *conn;
+	struct nvkm_output *outp;
+	struct dcb_gpio_func func;
+	int ret;
+
+	list_for_each_entry(outp, &disp->outp, head) {
+		if (outp->conn && outp->conn->index == index) {
+			atomic_inc(&nv_object(outp->conn)->refcount);
+			*pobject = outp->conn;
+			return 1;
+		}
+	}
+
+	ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+	conn = *pobject;
+	if (ret)
+		return ret;
+
+	conn->info = *info;
+	conn->index = index;
+
+	DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
+	    info->type, info->location, info->hpd, info->dp,
+	    info->di, info->sr, info->lcdid);
+
+	if ((info->hpd = ffs(info->hpd))) {
+		if (--info->hpd >= ARRAY_SIZE(hpd)) {
+			ERR("hpd %02x unknown\n", info->hpd);
+			return 0;
+		}
+		info->hpd = hpd[info->hpd];
+
+		ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
+		if (ret) {
+			ERR("func %02x lookup failed, %d\n", info->hpd, ret);
+			return 0;
+		}
+
+		ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
+				       true, &(struct nvkm_gpio_ntfy_req) {
+					.mask = NVKM_GPIO_TOGGLED,
+					.line = func.line,
+				       },
+				       sizeof(struct nvkm_gpio_ntfy_req),
+				       sizeof(struct nvkm_gpio_ntfy_rep),
+				       &conn->hpd);
+		if (ret) {
+			ERR("func %02x failed, %d\n", info->hpd, ret);
+		} else {
+			DBG("func %02x (HPD)\n", info->hpd);
+		}
+	}
+
+	return 0;
+}
+
+int
+_nvkm_connector_ctor(struct nvkm_object *parent,
+		     struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *info, u32 index,
+		     struct nvkm_object **pobject)
+{
+	struct nvkm_connector *conn;
+	int ret;
+
+	ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
+	*pobject = nv_object(conn);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nvkm_connector_oclass = &(struct nvkm_connector_impl) {
+	.base = {
+		.handle = 0,
+		.ofuncs = &(struct nvkm_ofuncs) {
+			.ctor = _nvkm_connector_ctor,
+			.dtor = _nvkm_connector_dtor,
+			.init = _nvkm_connector_init,
+			.fini = _nvkm_connector_fini,
+		},
+	},
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
new file mode 100644
index 0000000..c87a061
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_DISP_CONN_H__
+#define __NVKM_DISP_CONN_H__
+#include <core/object.h>
+#include <core/notify.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+
+struct nvkm_connector {
+	struct nvkm_object base;
+	struct list_head head;
+
+	struct nvbios_connE info;
+	int index;
+
+	struct nvkm_notify hpd;
+};
+
+#define nvkm_connector_create(p,e,c,b,i,d)                                     \
+	nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_connector_destroy(d) ({                                           \
+	struct nvkm_connector *disp = (d);                                     \
+	_nvkm_connector_dtor(nv_object(disp));                                 \
+})
+#define nvkm_connector_init(d) ({                                              \
+	struct nvkm_connector *disp = (d);                                     \
+	_nvkm_connector_init(nv_object(disp));                                 \
+})
+#define nvkm_connector_fini(d,s) ({                                            \
+	struct nvkm_connector *disp = (d);                                     \
+	_nvkm_connector_fini(nv_object(disp), (s));                            \
+})
+
+int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *, struct nvbios_connE *,
+			   int, int, void **);
+
+int  _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, void *, u32,
+			  struct nvkm_object **);
+void _nvkm_connector_dtor(struct nvkm_object *);
+int  _nvkm_connector_init(struct nvkm_object *);
+int  _nvkm_connector_fini(struct nvkm_object *, bool);
+
+struct nvkm_connector_impl {
+	struct nvkm_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+	struct nvkm_connector *_conn = (void *)conn;                           \
+	nv_##l(_conn, "%02x:%02x%02x: "f, _conn->index,                        \
+	       _conn->info.location, _conn->info.type, ##a);                   \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
new file mode 100644
index 0000000..0f7d1ec
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+nv50_dac_power(NV50_DISP_MTHD_V1)
+{
+	const u32 doff = outp->or * 0x800;
+	union {
+		struct nv50_disp_dac_pwr_v0 v0;
+	} *args = data;
+	u32 stat;
+	int ret;
+
+	nv_ioctl(object, "disp dac pwr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
+				 "vsync %d hsync %d\n",
+			 args->v0.version, args->v0.state, args->v0.data,
+			 args->v0.vsync, args->v0.hsync);
+		stat  = 0x00000040 * !args->v0.state;
+		stat |= 0x00000010 * !args->v0.data;
+		stat |= 0x00000004 * !args->v0.vsync;
+		stat |= 0x00000001 * !args->v0.hsync;
+	} else
+		return ret;
+
+	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+	nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
+	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+	return 0;
+}
+
+int
+nv50_dac_sense(NV50_DISP_MTHD_V1)
+{
+	union {
+		struct nv50_disp_dac_load_v0 v0;
+	} *args = data;
+	const u32 doff = outp->or * 0x800;
+	u32 loadval;
+	int ret;
+
+	nv_ioctl(object, "disp dac load size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp dac load vers %d data %08x\n",
+			 args->v0.version, args->v0.data);
+		if (args->v0.data & 0xfff00000)
+			return -EINVAL;
+		loadval = args->v0.data;
+	} else
+		return ret;
+
+	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
+	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+
+	nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
+	mdelay(9);
+	udelay(500);
+	loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
+
+	nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
+	nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+
+	nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
+	if (!(loadval & 0x80000000))
+		return -ETIMEDOUT;
+
+	args->v0.load = (loadval & 0x38000000) >> 27;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
new file mode 100644
index 0000000..6834766
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "dport.h"
+#include "outpdp.h"
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/i2c.h>
+
+#include <nvif/class.h>
+
+/******************************************************************************
+ * link training
+ *****************************************************************************/
+struct dp_state {
+	struct nvkm_output_dp *outp;
+	int link_nr;
+	u32 link_bw;
+	u8  stat[6];
+	u8  conf[4];
+	bool pc2;
+	u8  pc2stat;
+	u8  pc2conf[2];
+};
+
+static int
+dp_set_link_config(struct dp_state *dp)
+{
+	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+	struct nvkm_output_dp *outp = dp->outp;
+	struct nvkm_disp *disp = nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(disp);
+	struct nvbios_init init = {
+		.subdev = nv_subdev(disp),
+		.bios = bios,
+		.offset = 0x0000,
+		.outp = &outp->base.info,
+		.crtc = -1,
+		.execute = 1,
+	};
+	u32 lnkcmp;
+	u8 sink[2];
+	int ret;
+
+	DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
+
+	/* set desired link configuration on the source */
+	if ((lnkcmp = dp->outp->info.lnkcmp)) {
+		if (outp->version < 0x30) {
+			while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
+				lnkcmp += 4;
+			init.offset = nv_ro16(bios, lnkcmp + 2);
+		} else {
+			while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
+				lnkcmp += 3;
+			init.offset = nv_ro16(bios, lnkcmp + 1);
+		}
+
+		nvbios_exec(&init);
+	}
+
+	ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
+			    outp->dpcd[DPCD_RC02] &
+				       DPCD_RC02_ENHANCED_FRAME_CAP);
+	if (ret) {
+		if (ret < 0)
+			ERR("lnk_ctl failed with %d\n", ret);
+		return ret;
+	}
+
+	impl->lnk_pwr(outp, dp->link_nr);
+
+	/* set desired link configuration on the sink */
+	sink[0] = dp->link_bw / 27000;
+	sink[1] = dp->link_nr;
+	if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
+		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
+
+	return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
+}
+
+static void
+dp_set_training_pattern(struct dp_state *dp, u8 pattern)
+{
+	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+	struct nvkm_output_dp *outp = dp->outp;
+	u8 sink_tp;
+
+	DBG("training pattern %d\n", pattern);
+	impl->pattern(outp, pattern);
+
+	nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
+	sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
+	sink_tp |= pattern;
+	nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
+}
+
+static int
+dp_link_train_commit(struct dp_state *dp, bool pc)
+{
+	struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+	struct nvkm_output_dp *outp = dp->outp;
+	int ret, i;
+
+	for (i = 0; i < dp->link_nr; i++) {
+		u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
+		u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
+		u8 lpre = (lane & 0x0c) >> 2;
+		u8 lvsw = (lane & 0x03) >> 0;
+		u8 hivs = 3 - lpre;
+		u8 hipe = 3;
+		u8 hipc = 3;
+
+		if (lpc2 >= hipc)
+			lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
+		if (lpre >= hipe) {
+			lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
+			lvsw = hivs = 3 - (lpre & 3);
+		} else
+		if (lvsw >= hivs) {
+			lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
+		}
+
+		dp->conf[i] = (lpre << 3) | lvsw;
+		dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
+
+		DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
+		impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
+	}
+
+	ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
+	if (ret)
+		return ret;
+
+	if (pc) {
+		ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
+{
+	struct nvkm_output_dp *outp = dp->outp;
+	int ret;
+
+	if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
+		mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
+	else
+		udelay(delay);
+
+	ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
+	if (ret)
+		return ret;
+
+	if (pc) {
+		ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
+		if (ret)
+			dp->pc2stat = 0x00;
+		DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
+	} else {
+		DBG("status %6ph\n", dp->stat);
+	}
+
+	return 0;
+}
+
+static int
+dp_link_train_cr(struct dp_state *dp)
+{
+	bool cr_done = false, abort = false;
+	int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
+	int tries = 0, i;
+
+	dp_set_training_pattern(dp, 1);
+
+	do {
+		if (dp_link_train_commit(dp, false) ||
+		    dp_link_train_update(dp, false, 100))
+			break;
+
+		cr_done = true;
+		for (i = 0; i < dp->link_nr; i++) {
+			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
+			if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
+				cr_done = false;
+				if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
+					abort = true;
+				break;
+			}
+		}
+
+		if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
+			voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
+			tries = 0;
+		}
+	} while (!cr_done && !abort && ++tries < 5);
+
+	return cr_done ? 0 : -1;
+}
+
+static int
+dp_link_train_eq(struct dp_state *dp)
+{
+	struct nvkm_output_dp *outp = dp->outp;
+	bool eq_done = false, cr_done = true;
+	int tries = 0, i;
+
+	if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
+		dp_set_training_pattern(dp, 3);
+	else
+		dp_set_training_pattern(dp, 2);
+
+	do {
+		if ((tries &&
+		    dp_link_train_commit(dp, dp->pc2)) ||
+		    dp_link_train_update(dp, dp->pc2, 400))
+			break;
+
+		eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
+		for (i = 0; i < dp->link_nr && eq_done; i++) {
+			u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
+			if (!(lane & DPCD_LS02_LANE0_CR_DONE))
+				cr_done = false;
+			if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
+			    !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
+				eq_done = false;
+		}
+	} while (!eq_done && cr_done && ++tries <= 5);
+
+	return eq_done ? 0 : -1;
+}
+
+static void
+dp_link_train_init(struct dp_state *dp, bool spread)
+{
+	struct nvkm_output_dp *outp = dp->outp;
+	struct nvkm_disp *disp = nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(disp);
+	struct nvbios_init init = {
+		.subdev = nv_subdev(disp),
+		.bios = bios,
+		.outp = &outp->base.info,
+		.crtc = -1,
+		.execute = 1,
+	};
+
+	/* set desired spread */
+	if (spread)
+		init.offset = outp->info.script[2];
+	else
+		init.offset = outp->info.script[3];
+	nvbios_exec(&init);
+
+	/* pre-train script */
+	init.offset = outp->info.script[0];
+	nvbios_exec(&init);
+}
+
+static void
+dp_link_train_fini(struct dp_state *dp)
+{
+	struct nvkm_output_dp *outp = dp->outp;
+	struct nvkm_disp *disp = nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(disp);
+	struct nvbios_init init = {
+		.subdev = nv_subdev(disp),
+		.bios = bios,
+		.outp = &outp->base.info,
+		.crtc = -1,
+		.execute = 1,
+	};
+
+	/* post-train script */
+	init.offset = outp->info.script[1],
+	nvbios_exec(&init);
+}
+
+static const struct dp_rates {
+	u32 rate;
+	u8  bw;
+	u8  nr;
+} nvkm_dp_rates[] = {
+	{ 2160000, 0x14, 4 },
+	{ 1080000, 0x0a, 4 },
+	{ 1080000, 0x14, 2 },
+	{  648000, 0x06, 4 },
+	{  540000, 0x0a, 2 },
+	{  540000, 0x14, 1 },
+	{  324000, 0x06, 2 },
+	{  270000, 0x0a, 1 },
+	{  162000, 0x06, 1 },
+	{}
+};
+
+void
+nvkm_dp_train(struct work_struct *w)
+{
+	struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const struct dp_rates *cfg = nvkm_dp_rates;
+	struct dp_state _dp = {
+		.outp = outp,
+	}, *dp = &_dp;
+	u32 datarate = 0;
+	int ret;
+
+	if (!outp->base.info.location && priv->sor.magic)
+		priv->sor.magic(&outp->base);
+
+	/* bring capabilities within encoder limits */
+	if (nv_mclass(priv) < GF110_DISP)
+		outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
+	if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
+		outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
+		outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
+	}
+	if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
+		outp->dpcd[1] = outp->base.info.dpconf.link_bw;
+	dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
+
+	/* restrict link config to the lowest required rate, if requested */
+	if (datarate) {
+		datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
+		while (cfg[1].rate >= datarate)
+			cfg++;
+	}
+	cfg--;
+
+	/* disable link interrupt handling during link training */
+	nvkm_notify_put(&outp->irq);
+
+	/* enable down-spreading and execute pre-train script from vbios */
+	dp_link_train_init(dp, outp->dpcd[3] & 0x01);
+
+	while (ret = -EIO, (++cfg)->rate) {
+		/* select next configuration supported by encoder and sink */
+		while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
+		       cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
+			cfg++;
+		dp->link_bw = cfg->bw * 27000;
+		dp->link_nr = cfg->nr;
+
+		/* program selected link configuration */
+		ret = dp_set_link_config(dp);
+		if (ret == 0) {
+			/* attempt to train the link at this configuration */
+			memset(dp->stat, 0x00, sizeof(dp->stat));
+			if (!dp_link_train_cr(dp) &&
+			    !dp_link_train_eq(dp))
+				break;
+		} else
+		if (ret) {
+			/* dp_set_link_config() handled training, or
+			 * we failed to communicate with the sink.
+			 */
+			break;
+		}
+	}
+
+	/* finish link training and execute post-train script from vbios */
+	dp_set_training_pattern(dp, 0);
+	if (ret < 0)
+		ERR("link training failed\n");
+
+	dp_link_train_fini(dp);
+
+	/* signal completion and enable link interrupt handling */
+	DBG("training complete\n");
+	atomic_set(&outp->lt.done, 1);
+	wake_up(&outp->lt.wait);
+	nvkm_notify_get(&outp->irq);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
new file mode 100644
index 0000000..9596290
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
@@ -0,0 +1,75 @@
+#ifndef __NVKM_DISP_DPORT_H__
+#define __NVKM_DISP_DPORT_H__
+#include <core/os.h>
+
+/* DPCD Receiver Capabilities */
+#define DPCD_RC00_DPCD_REV                                              0x00000
+#define DPCD_RC01_MAX_LINK_RATE                                         0x00001
+#define DPCD_RC02                                                       0x00002
+#define DPCD_RC02_ENHANCED_FRAME_CAP                                       0x80
+#define DPCD_RC02_TPS3_SUPPORTED                                           0x40
+#define DPCD_RC02_MAX_LANE_COUNT                                           0x1f
+#define DPCD_RC03                                                       0x00003
+#define DPCD_RC03_MAX_DOWNSPREAD                                           0x01
+#define DPCD_RC0E_AUX_RD_INTERVAL                                       0x0000e
+
+/* DPCD Link Configuration */
+#define DPCD_LC00_LINK_BW_SET                                           0x00100
+#define DPCD_LC01                                                       0x00101
+#define DPCD_LC01_ENHANCED_FRAME_EN                                        0x80
+#define DPCD_LC01_LANE_COUNT_SET                                           0x1f
+#define DPCD_LC02                                                       0x00102
+#define DPCD_LC02_TRAINING_PATTERN_SET                                     0x03
+#define DPCD_LC03(l)                                            ((l) +  0x00103)
+#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED                                 0x20
+#define DPCD_LC03_PRE_EMPHASIS_SET                                         0x18
+#define DPCD_LC03_MAX_SWING_REACHED                                        0x04
+#define DPCD_LC03_VOLTAGE_SWING_SET                                        0x03
+#define DPCD_LC0F                                                       0x0010f
+#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED                           0x40
+#define DPCD_LC0F_LANE1_POST_CURSOR2_SET                                   0x30
+#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED                           0x04
+#define DPCD_LC0F_LANE0_POST_CURSOR2_SET                                   0x03
+#define DPCD_LC10                                                       0x00110
+#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED                           0x40
+#define DPCD_LC10_LANE3_POST_CURSOR2_SET                                   0x30
+#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED                           0x04
+#define DPCD_LC10_LANE2_POST_CURSOR2_SET                                   0x03
+
+/* DPCD Link/Sink Status */
+#define DPCD_LS02                                                       0x00202
+#define DPCD_LS02_LANE1_SYMBOL_LOCKED                                      0x40
+#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE                                    0x20
+#define DPCD_LS02_LANE1_CR_DONE                                            0x10
+#define DPCD_LS02_LANE0_SYMBOL_LOCKED                                      0x04
+#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE                                    0x02
+#define DPCD_LS02_LANE0_CR_DONE                                            0x01
+#define DPCD_LS03                                                       0x00203
+#define DPCD_LS03_LANE3_SYMBOL_LOCKED                                      0x40
+#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE                                    0x20
+#define DPCD_LS03_LANE3_CR_DONE                                            0x10
+#define DPCD_LS03_LANE2_SYMBOL_LOCKED                                      0x04
+#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE                                    0x02
+#define DPCD_LS03_LANE2_CR_DONE                                            0x01
+#define DPCD_LS04                                                       0x00204
+#define DPCD_LS04_LINK_STATUS_UPDATED                                      0x80
+#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED                           0x40
+#define DPCD_LS04_INTERLANE_ALIGN_DONE                                     0x01
+#define DPCD_LS06                                                       0x00206
+#define DPCD_LS06_LANE1_PRE_EMPHASIS                                       0xc0
+#define DPCD_LS06_LANE1_VOLTAGE_SWING                                      0x30
+#define DPCD_LS06_LANE0_PRE_EMPHASIS                                       0x0c
+#define DPCD_LS06_LANE0_VOLTAGE_SWING                                      0x03
+#define DPCD_LS07                                                       0x00207
+#define DPCD_LS07_LANE3_PRE_EMPHASIS                                       0xc0
+#define DPCD_LS07_LANE3_VOLTAGE_SWING                                      0x30
+#define DPCD_LS07_LANE2_PRE_EMPHASIS                                       0x0c
+#define DPCD_LS07_LANE2_VOLTAGE_SWING                                      0x03
+#define DPCD_LS0C                                                       0x0020c
+#define DPCD_LS0C_LANE3_POST_CURSOR2                                       0xc0
+#define DPCD_LS0C_LANE2_POST_CURSOR2                                       0x30
+#define DPCD_LS0C_LANE1_POST_CURSOR2                                       0x0c
+#define DPCD_LS0C_LANE0_POST_CURSOR2                                       0x03
+
+void nvkm_dp_train(struct work_struct *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
new file mode 100644
index 0000000..a0dcf53
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+g84_disp_core_mthd_dac = {
+	.mthd = 0x0080,
+	.addr = 0x000008,
+	.data = {
+		{ 0x0400, 0x610b58 },
+		{ 0x0404, 0x610bdc },
+		{ 0x0420, 0x610bc4 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+g84_disp_core_mthd_head = {
+	.mthd = 0x0400,
+	.addr = 0x000540,
+	.data = {
+		{ 0x0800, 0x610ad8 },
+		{ 0x0804, 0x610ad0 },
+		{ 0x0808, 0x610a48 },
+		{ 0x080c, 0x610a78 },
+		{ 0x0810, 0x610ac0 },
+		{ 0x0814, 0x610af8 },
+		{ 0x0818, 0x610b00 },
+		{ 0x081c, 0x610ae8 },
+		{ 0x0820, 0x610af0 },
+		{ 0x0824, 0x610b08 },
+		{ 0x0828, 0x610b10 },
+		{ 0x082c, 0x610a68 },
+		{ 0x0830, 0x610a60 },
+		{ 0x0834, 0x000000 },
+		{ 0x0838, 0x610a40 },
+		{ 0x0840, 0x610a24 },
+		{ 0x0844, 0x610a2c },
+		{ 0x0848, 0x610aa8 },
+		{ 0x084c, 0x610ab0 },
+		{ 0x085c, 0x610c5c },
+		{ 0x0860, 0x610a84 },
+		{ 0x0864, 0x610a90 },
+		{ 0x0868, 0x610b18 },
+		{ 0x086c, 0x610b20 },
+		{ 0x0870, 0x610ac8 },
+		{ 0x0874, 0x610a38 },
+		{ 0x0878, 0x610c50 },
+		{ 0x0880, 0x610a58 },
+		{ 0x0884, 0x610a9c },
+		{ 0x089c, 0x610c68 },
+		{ 0x08a0, 0x610a70 },
+		{ 0x08a4, 0x610a50 },
+		{ 0x08a8, 0x610ae0 },
+		{ 0x08c0, 0x610b28 },
+		{ 0x08c4, 0x610b30 },
+		{ 0x08c8, 0x610b40 },
+		{ 0x08d4, 0x610b38 },
+		{ 0x08d8, 0x610b48 },
+		{ 0x08dc, 0x610b50 },
+		{ 0x0900, 0x610a18 },
+		{ 0x0904, 0x610ab8 },
+		{ 0x0910, 0x610c70 },
+		{ 0x0914, 0x610c78 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_core_mthd_chan = {
+	.name = "Core",
+	.addr = 0x000000,
+	.data = {
+		{ "Global", 1, &nv50_disp_core_mthd_base },
+		{    "DAC", 3, &g84_disp_core_mthd_dac  },
+		{    "SOR", 2, &nv50_disp_core_mthd_sor  },
+		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
+		{   "HEAD", 2, &g84_disp_core_mthd_head },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+g84_disp_base_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x0008c4 },
+		{ 0x0088, 0x0008d0 },
+		{ 0x008c, 0x0008dc },
+		{ 0x0090, 0x0008e4 },
+		{ 0x0094, 0x610884 },
+		{ 0x00a0, 0x6108a0 },
+		{ 0x00a4, 0x610878 },
+		{ 0x00c0, 0x61086c },
+		{ 0x00c4, 0x610800 },
+		{ 0x00c8, 0x61080c },
+		{ 0x00cc, 0x610818 },
+		{ 0x00e0, 0x610858 },
+		{ 0x00e4, 0x610860 },
+		{ 0x00e8, 0x6108ac },
+		{ 0x00ec, 0x6108b4 },
+		{ 0x00fc, 0x610824 },
+		{ 0x0100, 0x610894 },
+		{ 0x0104, 0x61082c },
+		{ 0x0110, 0x6108bc },
+		{ 0x0114, 0x61088c },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_base_mthd_chan = {
+	.name = "Base",
+	.addr = 0x000540,
+	.data = {
+		{ "Global", 1, &g84_disp_base_mthd_base },
+		{  "Image", 2, &nv50_disp_base_mthd_image },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+g84_disp_ovly_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x6109a0 },
+		{ 0x0088, 0x6109c0 },
+		{ 0x008c, 0x6109c8 },
+		{ 0x0090, 0x6109b4 },
+		{ 0x0094, 0x610970 },
+		{ 0x00a0, 0x610998 },
+		{ 0x00a4, 0x610964 },
+		{ 0x00c0, 0x610958 },
+		{ 0x00e0, 0x6109a8 },
+		{ 0x00e4, 0x6109d0 },
+		{ 0x00e8, 0x6109d8 },
+		{ 0x0100, 0x61094c },
+		{ 0x0104, 0x610984 },
+		{ 0x0108, 0x61098c },
+		{ 0x0800, 0x6109f8 },
+		{ 0x0808, 0x610a08 },
+		{ 0x080c, 0x610a10 },
+		{ 0x0810, 0x610a00 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_ovly_mthd_chan = {
+	.name = "Overlay",
+	.addr = 0x000540,
+	.data = {
+		{ "Global", 1, &g84_disp_ovly_mthd_base },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_disp_sclass[] = {
+	{ G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+	{ G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+	{ G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+g84_disp_main_oclass[] = {
+	{ G82_DISP, &nv50_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = g84_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+	priv->sclass = g84_disp_sclass;
+	priv->head.nr = 2;
+	priv->dac.nr = 3;
+	priv->sor.nr = 2;
+	priv->pior.nr = 3;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hdmi = g84_hdmi_ctrl;
+	priv->pior.power = nv50_pior_power;
+	return 0;
+}
+
+struct nvkm_oclass *
+g84_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x82),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &nv50_disp_vblank_func,
+	.base.outp =  nv50_disp_outp_sclass,
+	.mthd.core = &g84_disp_core_mthd_chan,
+	.mthd.base = &g84_disp_base_mthd_chan,
+	.mthd.ovly = &g84_disp_ovly_mthd_chan,
+	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
new file mode 100644
index 0000000..1ab0d0a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+g94_disp_core_mthd_sor = {
+	.mthd = 0x0040,
+	.addr = 0x000008,
+	.data = {
+		{ 0x0600, 0x610794 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+g94_disp_core_mthd_chan = {
+	.name = "Core",
+	.addr = 0x000000,
+	.data = {
+		{ "Global", 1, &nv50_disp_core_mthd_base },
+		{    "DAC", 3, &g84_disp_core_mthd_dac  },
+		{    "SOR", 4, &g94_disp_core_mthd_sor  },
+		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
+		{   "HEAD", 2, &g84_disp_core_mthd_head },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g94_disp_sclass[] = {
+	{ GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+	{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+	{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+g94_disp_main_oclass[] = {
+	{ GT206_DISP, &nv50_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = g94_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+	priv->sclass = g94_disp_sclass;
+	priv->head.nr = 2;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->pior.nr = 3;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hdmi = g84_hdmi_ctrl;
+	priv->pior.power = nv50_pior_power;
+	return 0;
+}
+
+struct nvkm_oclass *
+g94_disp_outp_sclass[] = {
+	&nv50_pior_dp_impl.base.base,
+	&g94_sor_dp_impl.base.base,
+	NULL
+};
+
+struct nvkm_oclass *
+g94_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x88),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g94_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &nv50_disp_vblank_func,
+	.base.outp =  g94_disp_outp_sclass,
+	.mthd.core = &g94_disp_core_mthd_chan,
+	.mthd.base = &g84_disp_base_mthd_chan,
+	.mthd.ovly = &g84_disp_ovly_mthd_chan,
+	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
new file mode 100644
index 0000000..0ebf466
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
@@ -0,0 +1,1310 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <core/ramht.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * EVO channel base class
+ ******************************************************************************/
+
+static void
+gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+	nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
+	nv_wr32(priv, 0x61008c, 0x00000001 << index);
+}
+
+static void
+gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+	nv_wr32(priv, 0x61008c, 0x00000001 << index);
+	nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
+}
+
+const struct nvkm_event_func
+gf110_disp_chan_uevent = {
+	.ctor = nv50_disp_chan_uevent_ctor,
+	.init = gf110_disp_chan_uevent_init,
+	.fini = gf110_disp_chan_uevent_fini,
+};
+
+/*******************************************************************************
+ * EVO DMA channel base class
+ ******************************************************************************/
+
+static int
+gf110_disp_dmac_object_attach(struct nvkm_object *parent,
+			      struct nvkm_object *object, u32 name)
+{
+	struct nv50_disp_base *base = (void *)parent->parent;
+	struct nv50_disp_chan *chan = (void *)parent;
+	u32 addr = nv_gpuobj(object)->node->offset;
+	u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
+	return nvkm_ramht_insert(base->ramht, chan->chid, name, data);
+}
+
+static void
+gf110_disp_dmac_object_detach(struct nvkm_object *parent, int cookie)
+{
+	struct nv50_disp_base *base = (void *)parent->parent;
+	nvkm_ramht_remove(base->ramht, cookie);
+}
+
+static int
+gf110_disp_dmac_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *dmac = (void *)object;
+	int chid = dmac->base.chid;
+	int ret;
+
+	ret = nv50_disp_chan_init(&dmac->base);
+	if (ret)
+		return ret;
+
+	/* enable error reporting */
+	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
+
+	/* initialise channel for dma command submission */
+	nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
+	nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
+	nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
+	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
+	nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
+	nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
+
+	/* wait for it to go inactive */
+	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
+		nv_error(dmac, "init: 0x%08x\n",
+			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *dmac = (void *)object;
+	int chid = dmac->base.chid;
+
+	/* deactivate channel */
+	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
+	nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
+	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
+		nv_error(dmac, "fini: 0x%08x\n",
+			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	/* disable error reporting and completion notification */
+	nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
+	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
+
+	return nv50_disp_chan_fini(&dmac->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x660080 },
+		{ 0x0084, 0x660084 },
+		{ 0x0088, 0x660088 },
+		{ 0x008c, 0x000000 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_dac = {
+	.mthd = 0x0020,
+	.addr = 0x000020,
+	.data = {
+		{ 0x0180, 0x660180 },
+		{ 0x0184, 0x660184 },
+		{ 0x0188, 0x660188 },
+		{ 0x0190, 0x660190 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_sor = {
+	.mthd = 0x0020,
+	.addr = 0x000020,
+	.data = {
+		{ 0x0200, 0x660200 },
+		{ 0x0204, 0x660204 },
+		{ 0x0208, 0x660208 },
+		{ 0x0210, 0x660210 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_pior = {
+	.mthd = 0x0020,
+	.addr = 0x000020,
+	.data = {
+		{ 0x0300, 0x660300 },
+		{ 0x0304, 0x660304 },
+		{ 0x0308, 0x660308 },
+		{ 0x0310, 0x660310 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_head = {
+	.mthd = 0x0300,
+	.addr = 0x000300,
+	.data = {
+		{ 0x0400, 0x660400 },
+		{ 0x0404, 0x660404 },
+		{ 0x0408, 0x660408 },
+		{ 0x040c, 0x66040c },
+		{ 0x0410, 0x660410 },
+		{ 0x0414, 0x660414 },
+		{ 0x0418, 0x660418 },
+		{ 0x041c, 0x66041c },
+		{ 0x0420, 0x660420 },
+		{ 0x0424, 0x660424 },
+		{ 0x0428, 0x660428 },
+		{ 0x042c, 0x66042c },
+		{ 0x0430, 0x660430 },
+		{ 0x0434, 0x660434 },
+		{ 0x0438, 0x660438 },
+		{ 0x0440, 0x660440 },
+		{ 0x0444, 0x660444 },
+		{ 0x0448, 0x660448 },
+		{ 0x044c, 0x66044c },
+		{ 0x0450, 0x660450 },
+		{ 0x0454, 0x660454 },
+		{ 0x0458, 0x660458 },
+		{ 0x045c, 0x66045c },
+		{ 0x0460, 0x660460 },
+		{ 0x0468, 0x660468 },
+		{ 0x046c, 0x66046c },
+		{ 0x0470, 0x660470 },
+		{ 0x0474, 0x660474 },
+		{ 0x0480, 0x660480 },
+		{ 0x0484, 0x660484 },
+		{ 0x048c, 0x66048c },
+		{ 0x0490, 0x660490 },
+		{ 0x0494, 0x660494 },
+		{ 0x0498, 0x660498 },
+		{ 0x04b0, 0x6604b0 },
+		{ 0x04b8, 0x6604b8 },
+		{ 0x04bc, 0x6604bc },
+		{ 0x04c0, 0x6604c0 },
+		{ 0x04c4, 0x6604c4 },
+		{ 0x04c8, 0x6604c8 },
+		{ 0x04d0, 0x6604d0 },
+		{ 0x04d4, 0x6604d4 },
+		{ 0x04e0, 0x6604e0 },
+		{ 0x04e4, 0x6604e4 },
+		{ 0x04e8, 0x6604e8 },
+		{ 0x04ec, 0x6604ec },
+		{ 0x04f0, 0x6604f0 },
+		{ 0x04f4, 0x6604f4 },
+		{ 0x04f8, 0x6604f8 },
+		{ 0x04fc, 0x6604fc },
+		{ 0x0500, 0x660500 },
+		{ 0x0504, 0x660504 },
+		{ 0x0508, 0x660508 },
+		{ 0x050c, 0x66050c },
+		{ 0x0510, 0x660510 },
+		{ 0x0514, 0x660514 },
+		{ 0x0518, 0x660518 },
+		{ 0x051c, 0x66051c },
+		{ 0x052c, 0x66052c },
+		{ 0x0530, 0x660530 },
+		{ 0x054c, 0x66054c },
+		{ 0x0550, 0x660550 },
+		{ 0x0554, 0x660554 },
+		{ 0x0558, 0x660558 },
+		{ 0x055c, 0x66055c },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+gf110_disp_core_mthd_chan = {
+	.name = "Core",
+	.addr = 0x000000,
+	.data = {
+		{ "Global", 1, &gf110_disp_core_mthd_base },
+		{    "DAC", 3, &gf110_disp_core_mthd_dac  },
+		{    "SOR", 8, &gf110_disp_core_mthd_sor  },
+		{   "PIOR", 4, &gf110_disp_core_mthd_pior },
+		{   "HEAD", 4, &gf110_disp_core_mthd_head },
+		{}
+	}
+};
+
+static int
+gf110_disp_core_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *mast = (void *)object;
+	int ret;
+
+	ret = nv50_disp_chan_init(&mast->base);
+	if (ret)
+		return ret;
+
+	/* enable error reporting */
+	nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
+
+	/* initialise channel for dma command submission */
+	nv_wr32(priv, 0x610494, mast->push);
+	nv_wr32(priv, 0x610498, 0x00010000);
+	nv_wr32(priv, 0x61049c, 0x00000001);
+	nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
+	nv_wr32(priv, 0x640000, 0x00000000);
+	nv_wr32(priv, 0x610490, 0x01000013);
+
+	/* wait for it to go inactive */
+	if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
+		nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+gf110_disp_core_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *mast = (void *)object;
+
+	/* deactivate channel */
+	nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
+	nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
+	if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
+		nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	/* disable error reporting and completion notification */
+	nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
+	nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
+
+	return nv50_disp_chan_fini(&mast->base, suspend);
+}
+
+struct nv50_disp_chan_impl
+gf110_disp_core_ofuncs = {
+	.base.ctor = nv50_disp_core_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = gf110_disp_core_init,
+	.base.fini = gf110_disp_core_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 0,
+	.attach = gf110_disp_dmac_object_attach,
+	.detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gf110_disp_base_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x661080 },
+		{ 0x0084, 0x661084 },
+		{ 0x0088, 0x661088 },
+		{ 0x008c, 0x66108c },
+		{ 0x0090, 0x661090 },
+		{ 0x0094, 0x661094 },
+		{ 0x00a0, 0x6610a0 },
+		{ 0x00a4, 0x6610a4 },
+		{ 0x00c0, 0x6610c0 },
+		{ 0x00c4, 0x6610c4 },
+		{ 0x00c8, 0x6610c8 },
+		{ 0x00cc, 0x6610cc },
+		{ 0x00e0, 0x6610e0 },
+		{ 0x00e4, 0x6610e4 },
+		{ 0x00e8, 0x6610e8 },
+		{ 0x00ec, 0x6610ec },
+		{ 0x00fc, 0x6610fc },
+		{ 0x0100, 0x661100 },
+		{ 0x0104, 0x661104 },
+		{ 0x0108, 0x661108 },
+		{ 0x010c, 0x66110c },
+		{ 0x0110, 0x661110 },
+		{ 0x0114, 0x661114 },
+		{ 0x0118, 0x661118 },
+		{ 0x011c, 0x66111c },
+		{ 0x0130, 0x661130 },
+		{ 0x0134, 0x661134 },
+		{ 0x0138, 0x661138 },
+		{ 0x013c, 0x66113c },
+		{ 0x0140, 0x661140 },
+		{ 0x0144, 0x661144 },
+		{ 0x0148, 0x661148 },
+		{ 0x014c, 0x66114c },
+		{ 0x0150, 0x661150 },
+		{ 0x0154, 0x661154 },
+		{ 0x0158, 0x661158 },
+		{ 0x015c, 0x66115c },
+		{ 0x0160, 0x661160 },
+		{ 0x0164, 0x661164 },
+		{ 0x0168, 0x661168 },
+		{ 0x016c, 0x66116c },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_list
+gf110_disp_base_mthd_image = {
+	.mthd = 0x0400,
+	.addr = 0x000400,
+	.data = {
+		{ 0x0400, 0x661400 },
+		{ 0x0404, 0x661404 },
+		{ 0x0408, 0x661408 },
+		{ 0x040c, 0x66140c },
+		{ 0x0410, 0x661410 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+gf110_disp_base_mthd_chan = {
+	.name = "Base",
+	.addr = 0x001000,
+	.data = {
+		{ "Global", 1, &gf110_disp_base_mthd_base },
+		{  "Image", 2, &gf110_disp_base_mthd_image },
+		{}
+	}
+};
+
+struct nv50_disp_chan_impl
+gf110_disp_base_ofuncs = {
+	.base.ctor = nv50_disp_base_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = gf110_disp_dmac_init,
+	.base.fini = gf110_disp_dmac_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 1,
+	.attach = gf110_disp_dmac_object_attach,
+	.detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gf110_disp_ovly_mthd_base = {
+	.mthd = 0x0000,
+	.data = {
+		{ 0x0080, 0x665080 },
+		{ 0x0084, 0x665084 },
+		{ 0x0088, 0x665088 },
+		{ 0x008c, 0x66508c },
+		{ 0x0090, 0x665090 },
+		{ 0x0094, 0x665094 },
+		{ 0x00a0, 0x6650a0 },
+		{ 0x00a4, 0x6650a4 },
+		{ 0x00b0, 0x6650b0 },
+		{ 0x00b4, 0x6650b4 },
+		{ 0x00b8, 0x6650b8 },
+		{ 0x00c0, 0x6650c0 },
+		{ 0x00e0, 0x6650e0 },
+		{ 0x00e4, 0x6650e4 },
+		{ 0x00e8, 0x6650e8 },
+		{ 0x0100, 0x665100 },
+		{ 0x0104, 0x665104 },
+		{ 0x0108, 0x665108 },
+		{ 0x010c, 0x66510c },
+		{ 0x0110, 0x665110 },
+		{ 0x0118, 0x665118 },
+		{ 0x011c, 0x66511c },
+		{ 0x0120, 0x665120 },
+		{ 0x0124, 0x665124 },
+		{ 0x0130, 0x665130 },
+		{ 0x0134, 0x665134 },
+		{ 0x0138, 0x665138 },
+		{ 0x013c, 0x66513c },
+		{ 0x0140, 0x665140 },
+		{ 0x0144, 0x665144 },
+		{ 0x0148, 0x665148 },
+		{ 0x014c, 0x66514c },
+		{ 0x0150, 0x665150 },
+		{ 0x0154, 0x665154 },
+		{ 0x0158, 0x665158 },
+		{ 0x015c, 0x66515c },
+		{ 0x0160, 0x665160 },
+		{ 0x0164, 0x665164 },
+		{ 0x0168, 0x665168 },
+		{ 0x016c, 0x66516c },
+		{ 0x0400, 0x665400 },
+		{ 0x0408, 0x665408 },
+		{ 0x040c, 0x66540c },
+		{ 0x0410, 0x665410 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+gf110_disp_ovly_mthd_chan = {
+	.name = "Overlay",
+	.addr = 0x001000,
+	.data = {
+		{ "Global", 1, &gf110_disp_ovly_mthd_base },
+		{}
+	}
+};
+
+struct nv50_disp_chan_impl
+gf110_disp_ovly_ofuncs = {
+	.base.ctor = nv50_disp_ovly_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = gf110_disp_dmac_init,
+	.base.fini = gf110_disp_dmac_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 5,
+	.attach = gf110_disp_dmac_object_attach,
+	.detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO PIO channel base class
+ ******************************************************************************/
+
+static int
+gf110_disp_pioc_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_pioc *pioc = (void *)object;
+	int chid = pioc->base.chid;
+	int ret;
+
+	ret = nv50_disp_chan_init(&pioc->base);
+	if (ret)
+		return ret;
+
+	/* enable error reporting */
+	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
+
+	/* activate channel */
+	nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
+	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
+		nv_error(pioc, "init: 0x%08x\n",
+			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_pioc *pioc = (void *)object;
+	int chid = pioc->base.chid;
+
+	nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
+	if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
+		nv_error(pioc, "timeout: 0x%08x\n",
+			 nv_rd32(priv, 0x610490 + (chid * 0x10)));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	/* disable error reporting and completion notification */
+	nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
+	nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
+
+	return nv50_disp_chan_fini(&pioc->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO immediate overlay channel objects
+ ******************************************************************************/
+
+struct nv50_disp_chan_impl
+gf110_disp_oimm_ofuncs = {
+	.base.ctor = nv50_disp_oimm_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = gf110_disp_pioc_init,
+	.base.fini = gf110_disp_pioc_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 9,
+};
+
+/*******************************************************************************
+ * EVO cursor channel objects
+ ******************************************************************************/
+
+struct nv50_disp_chan_impl
+gf110_disp_curs_ofuncs = {
+	.base.ctor = nv50_disp_curs_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = gf110_disp_pioc_init,
+	.base.fini = gf110_disp_pioc_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 13,
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+int
+gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
+{
+	const u32 total  = nv_rd32(priv, 0x640414 + (head * 0x300));
+	const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
+	const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+		args->v0.hblanke = (blanke & 0x0000ffff);
+		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+		args->v0.hblanks = (blanks & 0x0000ffff);
+		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
+		args->v0.htotal  = ( total & 0x0000ffff);
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		args->v0.vline = /* vline read locks hline */
+			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline =
+			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+	} else
+		return ret;
+
+	return 0;
+}
+
+static int
+gf110_disp_main_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_base *base = (void *)object;
+	int ret, i;
+	u32 tmp;
+
+	ret = nvkm_parent_init(&base->base);
+	if (ret)
+		return ret;
+
+	/* The below segments of code copying values from one register to
+	 * another appear to inform EVO of the display capabilities or
+	 * something similar.
+	 */
+
+	/* ... CRTC caps */
+	for (i = 0; i < priv->head.nr; i++) {
+		tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
+		nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
+		tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
+		nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
+		tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
+		nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
+	}
+
+	/* ... DAC caps */
+	for (i = 0; i < priv->dac.nr; i++) {
+		tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
+		nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
+	}
+
+	/* ... SOR caps */
+	for (i = 0; i < priv->sor.nr; i++) {
+		tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
+		nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
+	}
+
+	/* steal display away from vbios, or something like that */
+	if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
+		nv_wr32(priv, 0x6100ac, 0x00000100);
+		nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
+		if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
+			nv_error(priv, "timeout acquiring display\n");
+			return -EBUSY;
+		}
+	}
+
+	/* point at display engine memory area (hash table, objects) */
+	nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
+
+	/* enable supervisor interrupts, disable everything else */
+	nv_wr32(priv, 0x610090, 0x00000000);
+	nv_wr32(priv, 0x6100a0, 0x00000000);
+	nv_wr32(priv, 0x6100b0, 0x00000307);
+
+	/* disable underflow reporting, preventing an intermittent issue
+	 * on some gk104 boards where the production vbios left this
+	 * setting enabled by default.
+	 *
+	 * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
+	 */
+	for (i = 0; i < priv->head.nr; i++)
+		nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010);
+
+	return 0;
+}
+
+static int
+gf110_disp_main_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_base *base = (void *)object;
+
+	/* disable all interrupts */
+	nv_wr32(priv, 0x6100b0, 0x00000000);
+
+	return nvkm_parent_fini(&base->base, suspend);
+}
+
+struct nvkm_ofuncs
+gf110_disp_main_ofuncs = {
+	.ctor = nv50_disp_main_ctor,
+	.dtor = nv50_disp_main_dtor,
+	.init = gf110_disp_main_init,
+	.fini = gf110_disp_main_fini,
+	.mthd = nv50_disp_main_mthd,
+	.ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+gf110_disp_main_oclass[] = {
+	{ GF110_DISP, &gf110_disp_main_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+gf110_disp_sclass[] = {
+	{ GF110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+	{ GF110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+	{ GF110_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+	{ GF110_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+	{ GF110_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+gf110_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
+}
+
+static void
+gf110_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
+}
+
+const struct nvkm_event_func
+gf110_disp_vblank_func = {
+	.ctor = nvkm_disp_vblank_ctor,
+	.init = gf110_disp_vblank_init,
+	.fini = gf110_disp_vblank_fini,
+};
+
+static struct nvkm_output *
+exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
+	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	    struct nvbios_outp *info)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	u16 mask, type;
+
+	if (or < 4) {
+		type = DCB_OUTPUT_ANALOG;
+		mask = 0;
+	} else {
+		or -= 4;
+		switch (ctrl & 0x00000f00) {
+		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
+		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
+		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
+		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
+		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
+		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
+		default:
+			nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
+			return 0x0000;
+		}
+	}
+
+	mask  = 0x00c0 & (mask << 6);
+	mask |= 0x0001 << or;
+	mask |= 0x0100 << head;
+
+	list_for_each_entry(outp, &priv->base.outp, head) {
+		if ((outp->info.hasht & 0xff) == type &&
+		    (outp->info.hashm & mask) == mask) {
+			*data = nvbios_outp_match(bios, outp->info.hasht,
+							outp->info.hashm,
+						  ver, hdr, cnt, len, info);
+			if (!*data)
+				return NULL;
+			return outp;
+		}
+	}
+
+	return NULL;
+}
+
+static struct nvkm_output *
+exec_script(struct nv50_disp_priv *priv, int head, int id)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	struct nvbios_outp info;
+	u8  ver, hdr, cnt, len;
+	u32 data, ctrl = 0;
+	int or;
+
+	for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
+		ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
+		if (ctrl & (1 << head))
+			break;
+	}
+
+	if (or == 8)
+		return NULL;
+
+	outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
+	if (outp) {
+		struct nvbios_init init = {
+			.subdev = nv_subdev(priv),
+			.bios = bios,
+			.offset = info.script[id],
+			.outp = &outp->info,
+			.crtc = head,
+			.execute = 1,
+		};
+
+		nvbios_exec(&init);
+	}
+
+	return outp;
+}
+
+static struct nvkm_output *
+exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	struct nvbios_outp info1;
+	struct nvbios_ocfg info2;
+	u8  ver, hdr, cnt, len;
+	u32 data, ctrl = 0;
+	int or;
+
+	for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
+		ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
+		if (ctrl & (1 << head))
+			break;
+	}
+
+	if (or == 8)
+		return NULL;
+
+	outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
+	if (!outp)
+		return NULL;
+
+	switch (outp->info.type) {
+	case DCB_OUTPUT_TMDS:
+		*conf = (ctrl & 0x00000f00) >> 8;
+		if (pclk >= 165000)
+			*conf |= 0x0100;
+		break;
+	case DCB_OUTPUT_LVDS:
+		*conf = priv->sor.lvdsconf;
+		break;
+	case DCB_OUTPUT_DP:
+		*conf = (ctrl & 0x00000f00) >> 8;
+		break;
+	case DCB_OUTPUT_ANALOG:
+	default:
+		*conf = 0x00ff;
+		break;
+	}
+
+	data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
+	if (data && id < 0xff) {
+		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
+		if (data) {
+			struct nvbios_init init = {
+				.subdev = nv_subdev(priv),
+				.bios = bios,
+				.offset = data,
+				.outp = &outp->info,
+				.crtc = head,
+				.execute = 1,
+			};
+
+			nvbios_exec(&init);
+		}
+	}
+
+	return outp;
+}
+
+static void
+gf110_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
+{
+	exec_script(priv, head, 1);
+}
+
+static void
+gf110_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_output *outp = exec_script(priv, head, 2);
+
+	/* see note in nv50_disp_intr_unk20_0() */
+	if (outp && outp->info.type == DCB_OUTPUT_DP) {
+		struct nvkm_output_dp *outpdp = (void *)outp;
+		struct nvbios_init init = {
+			.subdev = nv_subdev(priv),
+			.bios = nvkm_bios(priv),
+			.outp = &outp->info,
+			.crtc = head,
+			.offset = outpdp->info.script[4],
+			.execute = 1,
+		};
+
+		nvbios_exec(&init);
+		atomic_set(&outpdp->lt.done, 0);
+	}
+}
+
+static void
+gf110_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(priv);
+	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+	if (pclk)
+		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
+	nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
+}
+
+static void
+gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
+			  struct dcb_output *outp)
+{
+	const int or = ffs(outp->or) - 1;
+	const u32 ctrl = nv_rd32(priv, 0x660200 + (or   * 0x020));
+	const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
+	const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
+	const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
+	const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
+	const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+	const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
+	const u32 hoff = (head * 0x800);
+	const u32 soff = (  or * 0x800);
+	const u32 loff = (link * 0x080) + soff;
+	const u32 symbol = 100000;
+	const u32 TU = 64;
+	u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
+	u32 clksor = nv_rd32(priv, 0x612300 + soff);
+	u32 datarate, link_nr, link_bw, bits;
+	u64 ratio, value;
+
+	link_nr  = hweight32(dpctrl & 0x000f0000);
+	link_bw  = (clksor & 0x007c0000) >> 18;
+	link_bw *= 27000;
+
+	/* symbols/hblank - algorithm taken from comments in tegra driver */
+	value = vblanke + vactive - vblanks - 7;
+	value = value * link_bw;
+	do_div(value, pclk);
+	value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+	nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
+
+	/* symbols/vblank - algorithm taken from comments in tegra driver */
+	value = vblanks - vblanke - 25;
+	value = value * link_bw;
+	do_div(value, pclk);
+	value = value - ((36 / link_nr) + 3) - 1;
+	nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
+
+	/* watermark */
+	if      ((conf & 0x3c0) == 0x180) bits = 30;
+	else if ((conf & 0x3c0) == 0x140) bits = 24;
+	else                              bits = 18;
+	datarate = (pclk * bits) / 8;
+
+	ratio  = datarate;
+	ratio *= symbol;
+	do_div(ratio, link_nr * link_bw);
+
+	value  = (symbol - ratio) * TU;
+	value *= ratio;
+	do_div(value, symbol);
+	do_div(value, symbol);
+
+	value += 5;
+	value |= 0x08000000;
+
+	nv_wr32(priv, 0x616610 + hoff, value);
+}
+
+static void
+gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_output *outp;
+	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+	u32 conf, addr, data;
+
+	outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
+	if (!outp)
+		return;
+
+	/* see note in nv50_disp_intr_unk20_2() */
+	if (outp->info.type == DCB_OUTPUT_DP) {
+		u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
+		switch ((sync & 0x000003c0) >> 6) {
+		case 6: pclk = pclk * 30; break;
+		case 5: pclk = pclk * 24; break;
+		case 2:
+		default:
+			pclk = pclk * 18;
+			break;
+		}
+
+		if (nvkm_output_dp_train(outp, pclk, true))
+			ERR("link not trained before attach\n");
+	} else {
+		if (priv->sor.magic)
+			priv->sor.magic(outp);
+	}
+
+	exec_clkcmp(priv, head, 0, pclk, &conf);
+
+	if (outp->info.type == DCB_OUTPUT_ANALOG) {
+		addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
+		data = 0x00000000;
+	} else {
+		addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
+		data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
+		switch (outp->info.type) {
+		case DCB_OUTPUT_TMDS:
+			nv_mask(priv, addr, 0x007c0000, 0x00280000);
+			break;
+		case DCB_OUTPUT_DP:
+			gf110_disp_intr_unk2_2_tu(priv, head, &outp->info);
+			break;
+		default:
+			break;
+		}
+	}
+
+	nv_mask(priv, addr, 0x00000707, data);
+}
+
+static void
+gf110_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
+{
+	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+	u32 conf;
+
+	exec_clkcmp(priv, head, 1, pclk, &conf);
+}
+
+void
+gf110_disp_intr_supervisor(struct work_struct *work)
+{
+	struct nv50_disp_priv *priv =
+		container_of(work, struct nv50_disp_priv, supervisor);
+	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+	u32 mask[4];
+	int head;
+
+	nv_debug(priv, "supervisor %d\n", ffs(priv->super));
+	for (head = 0; head < priv->head.nr; head++) {
+		mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
+		nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
+	}
+
+	if (priv->super & 0x00000001) {
+		nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(mask[head] & 0x00001000))
+				continue;
+			nv_debug(priv, "supervisor 1.0 - head %d\n", head);
+			gf110_disp_intr_unk1_0(priv, head);
+		}
+	} else
+	if (priv->super & 0x00000002) {
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(mask[head] & 0x00001000))
+				continue;
+			nv_debug(priv, "supervisor 2.0 - head %d\n", head);
+			gf110_disp_intr_unk2_0(priv, head);
+		}
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(mask[head] & 0x00010000))
+				continue;
+			nv_debug(priv, "supervisor 2.1 - head %d\n", head);
+			gf110_disp_intr_unk2_1(priv, head);
+		}
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(mask[head] & 0x00001000))
+				continue;
+			nv_debug(priv, "supervisor 2.2 - head %d\n", head);
+			gf110_disp_intr_unk2_2(priv, head);
+		}
+	} else
+	if (priv->super & 0x00000004) {
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(mask[head] & 0x00001000))
+				continue;
+			nv_debug(priv, "supervisor 3.0 - head %d\n", head);
+			gf110_disp_intr_unk4_0(priv, head);
+		}
+	}
+
+	for (head = 0; head < priv->head.nr; head++)
+		nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000);
+	nv_wr32(priv, 0x6101d0, 0x80000000);
+}
+
+static void
+gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+	const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+	u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
+	u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
+	u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
+
+	nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
+		       "0x%08x 0x%08x\n",
+		 chid, (mthd & 0x0000ffc), data, mthd, unkn);
+
+	if (chid == 0) {
+		switch (mthd & 0xffc) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+					    impl->mthd.core);
+			break;
+		default:
+			break;
+		}
+	} else
+	if (chid <= 4) {
+		switch (mthd & 0xffc) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+					    impl->mthd.base);
+			break;
+		default:
+			break;
+		}
+	} else
+	if (chid <= 8) {
+		switch (mthd & 0xffc) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
+					    impl->mthd.ovly);
+			break;
+		default:
+			break;
+		}
+	}
+
+	nv_wr32(priv, 0x61009c, (1 << chid));
+	nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
+}
+
+void
+gf110_disp_intr(struct nvkm_subdev *subdev)
+{
+	struct nv50_disp_priv *priv = (void *)subdev;
+	u32 intr = nv_rd32(priv, 0x610088);
+	int i;
+
+	if (intr & 0x00000001) {
+		u32 stat = nv_rd32(priv, 0x61008c);
+		while (stat) {
+			int chid = __ffs(stat); stat &= ~(1 << chid);
+			nv50_disp_chan_uevent_send(priv, chid);
+			nv_wr32(priv, 0x61008c, 1 << chid);
+		}
+		intr &= ~0x00000001;
+	}
+
+	if (intr & 0x00000002) {
+		u32 stat = nv_rd32(priv, 0x61009c);
+		int chid = ffs(stat) - 1;
+		if (chid >= 0)
+			gf110_disp_intr_error(priv, chid);
+		intr &= ~0x00000002;
+	}
+
+	if (intr & 0x00100000) {
+		u32 stat = nv_rd32(priv, 0x6100ac);
+		if (stat & 0x00000007) {
+			priv->super = (stat & 0x00000007);
+			schedule_work(&priv->supervisor);
+			nv_wr32(priv, 0x6100ac, priv->super);
+			stat &= ~0x00000007;
+		}
+
+		if (stat) {
+			nv_info(priv, "unknown intr24 0x%08x\n", stat);
+			nv_wr32(priv, 0x6100ac, stat);
+		}
+
+		intr &= ~0x00100000;
+	}
+
+	for (i = 0; i < priv->head.nr; i++) {
+		u32 mask = 0x01000000 << i;
+		if (mask & intr) {
+			u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
+			if (stat & 0x00000001)
+				nvkm_disp_vblank(&priv->base, i);
+			nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
+			nv_rd32(priv, 0x6100c0 + (i * 0x800));
+		}
+	}
+}
+
+static int
+gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int heads = nv_rd32(parent, 0x022448);
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, heads,
+			       "PDISP", "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gf110_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = gf110_disp_intr;
+	INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+	priv->sclass = gf110_disp_sclass;
+	priv->head.nr = heads;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gf110_hda_eld;
+	priv->sor.hdmi = gf110_hdmi_ctrl;
+	return 0;
+}
+
+struct nvkm_oclass *
+gf110_disp_outp_sclass[] = {
+	&gf110_sor_dp_impl.base.base,
+	NULL
+};
+
+struct nvkm_oclass *
+gf110_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x90),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf110_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &gf110_disp_vblank_func,
+	.base.outp =  gf110_disp_outp_sclass,
+	.mthd.core = &gf110_disp_core_mthd_chan,
+	.mthd.base = &gf110_disp_base_mthd_chan,
+	.mthd.ovly = &gf110_disp_ovly_mthd_chan,
+	.mthd.prev = -0x020000,
+	.head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
new file mode 100644
index 0000000..6f4019a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gk104_disp_core_mthd_head = {
+	.mthd = 0x0300,
+	.addr = 0x000300,
+	.data = {
+		{ 0x0400, 0x660400 },
+		{ 0x0404, 0x660404 },
+		{ 0x0408, 0x660408 },
+		{ 0x040c, 0x66040c },
+		{ 0x0410, 0x660410 },
+		{ 0x0414, 0x660414 },
+		{ 0x0418, 0x660418 },
+		{ 0x041c, 0x66041c },
+		{ 0x0420, 0x660420 },
+		{ 0x0424, 0x660424 },
+		{ 0x0428, 0x660428 },
+		{ 0x042c, 0x66042c },
+		{ 0x0430, 0x660430 },
+		{ 0x0434, 0x660434 },
+		{ 0x0438, 0x660438 },
+		{ 0x0440, 0x660440 },
+		{ 0x0444, 0x660444 },
+		{ 0x0448, 0x660448 },
+		{ 0x044c, 0x66044c },
+		{ 0x0450, 0x660450 },
+		{ 0x0454, 0x660454 },
+		{ 0x0458, 0x660458 },
+		{ 0x045c, 0x66045c },
+		{ 0x0460, 0x660460 },
+		{ 0x0468, 0x660468 },
+		{ 0x046c, 0x66046c },
+		{ 0x0470, 0x660470 },
+		{ 0x0474, 0x660474 },
+		{ 0x047c, 0x66047c },
+		{ 0x0480, 0x660480 },
+		{ 0x0484, 0x660484 },
+		{ 0x0488, 0x660488 },
+		{ 0x048c, 0x66048c },
+		{ 0x0490, 0x660490 },
+		{ 0x0494, 0x660494 },
+		{ 0x0498, 0x660498 },
+		{ 0x04a0, 0x6604a0 },
+		{ 0x04b0, 0x6604b0 },
+		{ 0x04b8, 0x6604b8 },
+		{ 0x04bc, 0x6604bc },
+		{ 0x04c0, 0x6604c0 },
+		{ 0x04c4, 0x6604c4 },
+		{ 0x04c8, 0x6604c8 },
+		{ 0x04d0, 0x6604d0 },
+		{ 0x04d4, 0x6604d4 },
+		{ 0x04e0, 0x6604e0 },
+		{ 0x04e4, 0x6604e4 },
+		{ 0x04e8, 0x6604e8 },
+		{ 0x04ec, 0x6604ec },
+		{ 0x04f0, 0x6604f0 },
+		{ 0x04f4, 0x6604f4 },
+		{ 0x04f8, 0x6604f8 },
+		{ 0x04fc, 0x6604fc },
+		{ 0x0500, 0x660500 },
+		{ 0x0504, 0x660504 },
+		{ 0x0508, 0x660508 },
+		{ 0x050c, 0x66050c },
+		{ 0x0510, 0x660510 },
+		{ 0x0514, 0x660514 },
+		{ 0x0518, 0x660518 },
+		{ 0x051c, 0x66051c },
+		{ 0x0520, 0x660520 },
+		{ 0x0524, 0x660524 },
+		{ 0x052c, 0x66052c },
+		{ 0x0530, 0x660530 },
+		{ 0x054c, 0x66054c },
+		{ 0x0550, 0x660550 },
+		{ 0x0554, 0x660554 },
+		{ 0x0558, 0x660558 },
+		{ 0x055c, 0x66055c },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+gk104_disp_core_mthd_chan = {
+	.name = "Core",
+	.addr = 0x000000,
+	.data = {
+		{ "Global", 1, &gf110_disp_core_mthd_base },
+		{    "DAC", 3, &gf110_disp_core_mthd_dac  },
+		{    "SOR", 8, &gf110_disp_core_mthd_sor  },
+		{   "PIOR", 4, &gf110_disp_core_mthd_pior },
+		{   "HEAD", 4, &gk104_disp_core_mthd_head },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gk104_disp_ovly_mthd_base = {
+	.mthd = 0x0000,
+	.data = {
+		{ 0x0080, 0x665080 },
+		{ 0x0084, 0x665084 },
+		{ 0x0088, 0x665088 },
+		{ 0x008c, 0x66508c },
+		{ 0x0090, 0x665090 },
+		{ 0x0094, 0x665094 },
+		{ 0x00a0, 0x6650a0 },
+		{ 0x00a4, 0x6650a4 },
+		{ 0x00b0, 0x6650b0 },
+		{ 0x00b4, 0x6650b4 },
+		{ 0x00b8, 0x6650b8 },
+		{ 0x00c0, 0x6650c0 },
+		{ 0x00c4, 0x6650c4 },
+		{ 0x00e0, 0x6650e0 },
+		{ 0x00e4, 0x6650e4 },
+		{ 0x00e8, 0x6650e8 },
+		{ 0x0100, 0x665100 },
+		{ 0x0104, 0x665104 },
+		{ 0x0108, 0x665108 },
+		{ 0x010c, 0x66510c },
+		{ 0x0110, 0x665110 },
+		{ 0x0118, 0x665118 },
+		{ 0x011c, 0x66511c },
+		{ 0x0120, 0x665120 },
+		{ 0x0124, 0x665124 },
+		{ 0x0130, 0x665130 },
+		{ 0x0134, 0x665134 },
+		{ 0x0138, 0x665138 },
+		{ 0x013c, 0x66513c },
+		{ 0x0140, 0x665140 },
+		{ 0x0144, 0x665144 },
+		{ 0x0148, 0x665148 },
+		{ 0x014c, 0x66514c },
+		{ 0x0150, 0x665150 },
+		{ 0x0154, 0x665154 },
+		{ 0x0158, 0x665158 },
+		{ 0x015c, 0x66515c },
+		{ 0x0160, 0x665160 },
+		{ 0x0164, 0x665164 },
+		{ 0x0168, 0x665168 },
+		{ 0x016c, 0x66516c },
+		{ 0x0400, 0x665400 },
+		{ 0x0404, 0x665404 },
+		{ 0x0408, 0x665408 },
+		{ 0x040c, 0x66540c },
+		{ 0x0410, 0x665410 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_chan
+gk104_disp_ovly_mthd_chan = {
+	.name = "Overlay",
+	.addr = 0x001000,
+	.data = {
+		{ "Global", 1, &gk104_disp_ovly_mthd_base },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_disp_sclass[] = {
+	{ GK104_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+	{ GK104_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+	{ GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+	{ GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+	{ GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gk104_disp_main_oclass[] = {
+	{ GK104_DISP, &gf110_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int heads = nv_rd32(parent, 0x022448);
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, heads,
+			       "PDISP", "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gk104_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = gf110_disp_intr;
+	INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+	priv->sclass = gk104_disp_sclass;
+	priv->head.nr = heads;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gf110_hda_eld;
+	priv->sor.hdmi = gk104_hdmi_ctrl;
+	return 0;
+}
+
+struct nvkm_oclass *
+gk104_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x91),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &gf110_disp_vblank_func,
+	.base.outp =  gf110_disp_outp_sclass,
+	.mthd.core = &gk104_disp_core_mthd_chan,
+	.mthd.base = &gf110_disp_base_mthd_chan,
+	.mthd.ovly = &gk104_disp_ovly_mthd_chan,
+	.mthd.prev = -0x020000,
+	.head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
new file mode 100644
index 0000000..daa4b46
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk110_disp_sclass[] = {
+	{ GK110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+	{ GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+	{ GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+	{ GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+	{ GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gk110_disp_main_oclass[] = {
+	{ GK110_DISP, &gf110_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int heads = nv_rd32(parent, 0x022448);
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, heads,
+			       "PDISP", "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gk110_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = gf110_disp_intr;
+	INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+	priv->sclass = gk110_disp_sclass;
+	priv->head.nr = heads;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gf110_hda_eld;
+	priv->sor.hdmi = gk104_hdmi_ctrl;
+	return 0;
+}
+
+struct nvkm_oclass *
+gk110_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x92),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk110_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &gf110_disp_vblank_func,
+	.base.outp =  gf110_disp_outp_sclass,
+	.mthd.core = &gk104_disp_core_mthd_chan,
+	.mthd.base = &gf110_disp_base_mthd_chan,
+	.mthd.ovly = &gk104_disp_ovly_mthd_chan,
+	.mthd.prev = -0x020000,
+	.head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
new file mode 100644
index 0000000..881cc94
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm107_disp_sclass[] = {
+	{ GM107_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+	{ GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+	{ GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+	{ GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+	{ GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gm107_disp_main_oclass[] = {
+	{ GM107_DISP, &gf110_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int heads = nv_rd32(parent, 0x022448);
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, heads,
+			       "PDISP", "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gm107_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = gf110_disp_intr;
+	INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+	priv->sclass = gm107_disp_sclass;
+	priv->head.nr = heads;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gf110_hda_eld;
+	priv->sor.hdmi = gk104_hdmi_ctrl;
+	return 0;
+}
+
+struct nvkm_oclass *
+gm107_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x07),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm107_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &gf110_disp_vblank_func,
+	.base.outp =  gf110_disp_outp_sclass,
+	.mthd.core = &gk104_disp_core_mthd_chan,
+	.mthd.base = &gf110_disp_base_mthd_chan,
+	.mthd.ovly = &gk104_disp_ovly_mthd_chan,
+	.mthd.prev = -0x020000,
+	.head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c
new file mode 100644
index 0000000..67004f8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm204_disp_sclass[] = {
+	{ GM204_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+	{ GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+	{ GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+	{ GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+	{ GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gm204_disp_main_oclass[] = {
+	{ GM204_DISP, &gf110_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int heads = nv_rd32(parent, 0x022448);
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, heads,
+			       "PDISP", "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gm204_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = gf110_disp_intr;
+	INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+	priv->sclass = gm204_disp_sclass;
+	priv->head.nr = heads;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gf110_hda_eld;
+	priv->sor.hdmi = gf110_hdmi_ctrl;
+	priv->sor.magic = gm204_sor_magic;
+	return 0;
+}
+
+struct nvkm_oclass *
+gm204_disp_outp_sclass[] = {
+	&gm204_sor_dp_impl.base.base,
+	NULL
+};
+
+struct nvkm_oclass *
+gm204_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x07),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm204_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &gf110_disp_vblank_func,
+	.base.outp =  gm204_disp_outp_sclass,
+	.mthd.core = &gk104_disp_core_mthd_chan,
+	.mthd.base = &gf110_disp_base_mthd_chan,
+	.mthd.ovly = &gk104_disp_ovly_mthd_chan,
+	.mthd.prev = -0x020000,
+	.head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
new file mode 100644
index 0000000..a453072
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gt200_disp_ovly_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x6109a0 },
+		{ 0x0088, 0x6109c0 },
+		{ 0x008c, 0x6109c8 },
+		{ 0x0090, 0x6109b4 },
+		{ 0x0094, 0x610970 },
+		{ 0x00a0, 0x610998 },
+		{ 0x00a4, 0x610964 },
+		{ 0x00b0, 0x610c98 },
+		{ 0x00b4, 0x610ca4 },
+		{ 0x00b8, 0x610cac },
+		{ 0x00c0, 0x610958 },
+		{ 0x00e0, 0x6109a8 },
+		{ 0x00e4, 0x6109d0 },
+		{ 0x00e8, 0x6109d8 },
+		{ 0x0100, 0x61094c },
+		{ 0x0104, 0x610984 },
+		{ 0x0108, 0x61098c },
+		{ 0x0800, 0x6109f8 },
+		{ 0x0808, 0x610a08 },
+		{ 0x080c, 0x610a10 },
+		{ 0x0810, 0x610a00 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+gt200_disp_ovly_mthd_chan = {
+	.name = "Overlay",
+	.addr = 0x000540,
+	.data = {
+		{ "Global", 1, &gt200_disp_ovly_mthd_base },
+		{}
+	}
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt200_disp_sclass[] = {
+	{ GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+	{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+	{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+	{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+	{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gt200_disp_main_oclass[] = {
+	{ GT200_DISP, &nv50_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gt200_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+	priv->sclass = gt200_disp_sclass;
+	priv->head.nr = 2;
+	priv->dac.nr = 3;
+	priv->sor.nr = 2;
+	priv->pior.nr = 3;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hdmi = g84_hdmi_ctrl;
+	priv->pior.power = nv50_pior_power;
+	return 0;
+}
+
+struct nvkm_oclass *
+gt200_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x83),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt200_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &nv50_disp_vblank_func,
+	.base.outp =  nv50_disp_outp_sclass,
+	.mthd.core = &g84_disp_core_mthd_chan,
+	.mthd.base = &g84_disp_base_mthd_chan,
+	.mthd.ovly = &gt200_disp_ovly_mthd_chan,
+	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
new file mode 100644
index 0000000..55f0d3a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_disp_sclass[] = {
+	{ GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+	{ GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+	{ GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+	{ GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+	{ GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+	{}
+};
+
+static struct nvkm_oclass
+gt215_disp_main_oclass[] = {
+	{ GT214_DISP, &nv50_disp_main_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = gt215_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+	priv->sclass = gt215_disp_sclass;
+	priv->head.nr = 2;
+	priv->dac.nr = 3;
+	priv->sor.nr = 4;
+	priv->pior.nr = 3;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->sor.hda_eld = gt215_hda_eld;
+	priv->sor.hdmi = gt215_hdmi_ctrl;
+	priv->pior.power = nv50_pior_power;
+	return 0;
+}
+
+struct nvkm_oclass *
+gt215_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x85),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &nv50_disp_vblank_func,
+	.base.outp =  g94_disp_outp_sclass,
+	.mthd.core = &g94_disp_core_mthd_chan,
+	.mthd.base = &g84_disp_base_mthd_chan,
+	.mthd.ovly = &g84_disp_ovly_mthd_chan,
+	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c
new file mode 100644
index 0000000..b9813d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gf110_hda_eld(NV50_DISP_MTHD_V1)
+{
+	union {
+		struct nv50_disp_sor_hda_eld_v0 v0;
+	} *args = data;
+	const u32 soff = outp->or * 0x030;
+	const u32 hoff = head * 0x800;
+	int ret, i;
+
+	nv_ioctl(object, "disp sor hda eld size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
+		if (size > 0x60)
+			return -E2BIG;
+	} else
+		return ret;
+
+	if (size && args->v0.data[0]) {
+		if (outp->info.type == DCB_OUTPUT_DP) {
+			nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
+			nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+		}
+		nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
+		for (i = 0; i < size; i++)
+			nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
+		for (; i < 0x60; i++)
+			nv_wr32(priv, 0x10ec00 + soff, (i << 8));
+		nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
+	} else {
+		if (outp->info.type == DCB_OUTPUT_DP) {
+			nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
+			nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+		}
+		nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
new file mode 100644
index 0000000..891d1e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gt215_hda_eld(NV50_DISP_MTHD_V1)
+{
+	union {
+		struct nv50_disp_sor_hda_eld_v0 v0;
+	} *args = data;
+	const u32 soff = outp->or * 0x800;
+	int ret, i;
+
+	nv_ioctl(object, "disp sor hda eld size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
+		if (size > 0x60)
+			return -E2BIG;
+	} else
+		return ret;
+
+	if (size && args->v0.data[0]) {
+		if (outp->info.type == DCB_OUTPUT_DP) {
+			nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
+			nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+		}
+		for (i = 0; i < size; i++)
+			nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
+		for (; i < 0x60; i++)
+			nv_wr32(priv, 0x61c440 + soff, (i << 8));
+		nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
+	} else {
+		if (outp->info.type == DCB_OUTPUT_DP) {
+			nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
+			nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+		}
+		nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
new file mode 100644
index 0000000..621cb0b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+	const u32 hoff = (head * 0x800);
+	union {
+		struct nv50_disp_sor_hdmi_pwr_v0 v0;
+	} *args = data;
+	u32 ctrl;
+	int ret;
+
+	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+				 "max_ac_packet %d rekey %d\n",
+			 args->v0.version, args->v0.state,
+			 args->v0.max_ac_packet, args->v0.rekey);
+		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+			return -EINVAL;
+		ctrl  = 0x40000000 * !!args->v0.state;
+		ctrl |= args->v0.max_ac_packet << 16;
+		ctrl |= args->v0.rekey;
+		ctrl |= 0x1f000000; /* ??? */
+	} else
+		return ret;
+
+	if (!(ctrl & 0x40000000)) {
+		nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
+		nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
+		nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
+		return 0;
+	}
+
+	/* AVI InfoFrame */
+	nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
+	nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
+	nv_wr32(priv, 0x616530 + hoff, 0x00000000);
+	nv_wr32(priv, 0x616534 + hoff, 0x00000000);
+	nv_wr32(priv, 0x616538 + hoff, 0x00000000);
+	nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
+
+	/* Audio InfoFrame */
+	nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
+	nv_wr32(priv, 0x61650c + hoff, 0x00000071);
+	nv_wr32(priv, 0x616510 + hoff, 0x00000000);
+	nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
+
+	nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+	nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+	nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
+	/* ??? */
+	nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+	nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+	nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+
+	/* HDMI_CTRL */
+	nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c
new file mode 100644
index 0000000..c284490
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gf110_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+	const u32 hoff = (head * 0x800);
+	union {
+		struct nv50_disp_sor_hdmi_pwr_v0 v0;
+	} *args = data;
+	u32 ctrl;
+	int ret;
+
+	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+				 "max_ac_packet %d rekey %d\n",
+			 args->v0.version, args->v0.state,
+			 args->v0.max_ac_packet, args->v0.rekey);
+		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+			return -EINVAL;
+		ctrl  = 0x40000000 * !!args->v0.state;
+		ctrl |= args->v0.max_ac_packet << 16;
+		ctrl |= args->v0.rekey;
+	} else
+		return ret;
+
+	if (!(ctrl & 0x40000000)) {
+		nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
+		nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
+		nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
+		return 0;
+	}
+
+	/* AVI InfoFrame */
+	nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
+	nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
+	nv_wr32(priv, 0x616724 + hoff, 0x00000000);
+	nv_wr32(priv, 0x616728 + hoff, 0x00000000);
+	nv_wr32(priv, 0x61672c + hoff, 0x00000000);
+	nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
+
+	/* ??? InfoFrame? */
+	nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
+	nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
+
+	/* HDMI_CTRL */
+	nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
new file mode 100644
index 0000000..ca34ff8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gk104_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+	const u32 hoff = (head * 0x800);
+	const u32 hdmi = (head * 0x400);
+	union {
+		struct nv50_disp_sor_hdmi_pwr_v0 v0;
+	} *args = data;
+	u32 ctrl;
+	int ret;
+
+	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+				 "max_ac_packet %d rekey %d\n",
+			 args->v0.version, args->v0.state,
+			 args->v0.max_ac_packet, args->v0.rekey);
+		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+			return -EINVAL;
+		ctrl  = 0x40000000 * !!args->v0.state;
+		ctrl |= args->v0.max_ac_packet << 16;
+		ctrl |= args->v0.rekey;
+	} else
+		return ret;
+
+	if (!(ctrl & 0x40000000)) {
+		nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
+		nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+		nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+		return 0;
+	}
+
+	/* AVI InfoFrame */
+	nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
+	nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
+	nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
+	nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
+	nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
+	nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
+
+	/* ??? InfoFrame? */
+	nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
+	nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
+
+	/* ??? */
+	nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
+
+	/* HDMI_CTRL */
+	nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
new file mode 100644
index 0000000..b641c16
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+	const u32 soff = outp->or * 0x800;
+	union {
+		struct nv50_disp_sor_hdmi_pwr_v0 v0;
+	} *args = data;
+	u32 ctrl;
+	int ret;
+
+	nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+				 "max_ac_packet %d rekey %d\n",
+			 args->v0.version, args->v0.state,
+			 args->v0.max_ac_packet, args->v0.rekey);
+		if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+			return -EINVAL;
+		ctrl  = 0x40000000 * !!args->v0.state;
+		ctrl |= args->v0.max_ac_packet << 16;
+		ctrl |= args->v0.rekey;
+		ctrl |= 0x1f000000; /* ??? */
+	} else
+		return ret;
+
+	if (!(ctrl & 0x40000000)) {
+		nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
+		nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
+		nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
+		return 0;
+	}
+
+	/* AVI InfoFrame */
+	nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
+	nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
+	nv_wr32(priv, 0x61c530 + soff, 0x00000000);
+	nv_wr32(priv, 0x61c534 + soff, 0x00000000);
+	nv_wr32(priv, 0x61c538 + soff, 0x00000000);
+	nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
+
+	/* Audio InfoFrame */
+	nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
+	nv_wr32(priv, 0x61c50c + soff, 0x00000071);
+	nv_wr32(priv, 0x61c510 + soff, 0x00000000);
+	nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
+
+	nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+	nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+	nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
+	/* ??? */
+	nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+	nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+	nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+
+	/* HDMI_CTRL */
+	nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
new file mode 100644
index 0000000..ff09b26
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct nv04_disp_priv {
+	struct nvkm_disp base;
+};
+
+static int
+nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv,
+		     void *data, u32 size, int head)
+{
+	const u32 hoff = head * 0x2000;
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
+	u32 line;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
+		args->v0.vtotal  = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
+		args->v0.vblanke = args->v0.vtotal - 1;
+
+		args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
+		args->v0.htotal  = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
+		args->v0.hblanke = args->v0.htotal - 1;
+
+		/*
+		 * If output is vga instead of digital then vtotal/htotal is
+		 * invalid so we have to give up and trigger the timestamping
+		 * fallback in the drm core.
+		 */
+		if (!args->v0.vtotal || !args->v0.htotal)
+			return -ENOTSUPP;
+
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		line = nv_rd32(priv, 0x600868 + hoff);
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline = (line & 0xffff0000) >> 16;
+		args->v0.vline = (line & 0x0000ffff);
+	} else
+		return ret;
+
+	return 0;
+}
+
+static int
+nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	union {
+		struct nv04_disp_mthd_v0 v0;
+	} *args = data;
+	struct nv04_disp_priv *priv = (void *)object->engine;
+	int head, ret;
+
+	nv_ioctl(object, "disp mthd size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
+			 args->v0.version, args->v0.method, args->v0.head);
+		mthd = args->v0.method;
+		head = args->v0.head;
+	} else
+		return ret;
+
+	if (head < 0 || head >= 2)
+		return -ENXIO;
+
+	switch (mthd) {
+	case NV04_DISP_SCANOUTPOS:
+		return nv04_disp_scanoutpos(object, priv, data, size, head);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static struct nvkm_ofuncs
+nv04_disp_ofuncs = {
+	.ctor = _nvkm_object_ctor,
+	.dtor = nvkm_object_destroy,
+	.init = nvkm_object_init,
+	.fini = nvkm_object_fini,
+	.mthd = nv04_disp_mthd,
+	.ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+nv04_disp_sclass[] = {
+	{ NV04_DISP, &nv04_disp_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
+}
+
+static void
+nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
+}
+
+static const struct nvkm_event_func
+nv04_disp_vblank_func = {
+	.ctor = nvkm_disp_vblank_ctor,
+	.init = nv04_disp_vblank_init,
+	.fini = nv04_disp_vblank_fini,
+};
+
+static void
+nv04_disp_intr(struct nvkm_subdev *subdev)
+{
+	struct nv04_disp_priv *priv = (void *)subdev;
+	u32 crtc0 = nv_rd32(priv, 0x600100);
+	u32 crtc1 = nv_rd32(priv, 0x602100);
+	u32 pvideo;
+
+	if (crtc0 & 0x00000001) {
+		nvkm_disp_vblank(&priv->base, 0);
+		nv_wr32(priv, 0x600100, 0x00000001);
+	}
+
+	if (crtc1 & 0x00000001) {
+		nvkm_disp_vblank(&priv->base, 1);
+		nv_wr32(priv, 0x602100, 0x00000001);
+	}
+
+	if (nv_device(priv)->chipset >= 0x10 &&
+	    nv_device(priv)->chipset <= 0x40) {
+		pvideo = nv_rd32(priv, 0x8100);
+		if (pvideo & ~0x11)
+			nv_info(priv, "PVIDEO intr: %08x\n", pvideo);
+		nv_wr32(priv, 0x8100, pvideo);
+	}
+}
+
+static int
+nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv04_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "DISPLAY",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = nv04_disp_sclass;
+	nv_subdev(priv)->intr = nv04_disp_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_disp_oclass = &(struct nvkm_disp_impl) {
+	.base.handle = NV_ENGINE(DISP, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.vblank = &nv04_disp_vblank_func,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
new file mode 100644
index 0000000..84ade81
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -0,0 +1,2019 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <core/ramht.h>
+#include <engine/dmaobj.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * EVO channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_chan_create_(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, int head,
+		       int length, void **pobject)
+{
+	const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
+	struct nv50_disp_base *base = (void *)parent;
+	struct nv50_disp_chan *chan;
+	int chid = impl->chid + head;
+	int ret;
+
+	if (base->chan & (1 << chid))
+		return -EBUSY;
+	base->chan |= (1 << chid);
+
+	ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
+				  (1ULL << NVDEV_ENGINE_DMAOBJ),
+				  length, pobject);
+	chan = *pobject;
+	if (ret)
+		return ret;
+	chan->chid = chid;
+
+	nv_parent(chan)->object_attach = impl->attach;
+	nv_parent(chan)->object_detach = impl->detach;
+	return 0;
+}
+
+static void
+nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
+{
+	struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
+	base->chan &= ~(1 << chan->chid);
+	nvkm_namedb_destroy(&chan->base);
+}
+
+static void
+nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
+	nv_wr32(priv, 0x610020, 0x00000001 << index);
+}
+
+static void
+nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+	nv_wr32(priv, 0x610020, 0x00000001 << index);
+	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
+}
+
+void
+nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
+{
+	struct nvif_notify_uevent_rep {
+	} rep;
+
+	nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
+}
+
+int
+nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
+			   struct nvkm_notify *notify)
+{
+	struct nv50_disp_dmac *dmac = (void *)object;
+	union {
+		struct nvif_notify_uevent_req none;
+	} *args = data;
+	int ret;
+
+	if (nvif_unvers(args->none)) {
+		notify->size  = sizeof(struct nvif_notify_uevent_rep);
+		notify->types = 1;
+		notify->index = dmac->base.chid;
+		return 0;
+	}
+
+	return ret;
+}
+
+const struct nvkm_event_func
+nv50_disp_chan_uevent = {
+	.ctor = nv50_disp_chan_uevent_ctor,
+	.init = nv50_disp_chan_uevent_init,
+	.fini = nv50_disp_chan_uevent_fini,
+};
+
+int
+nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
+		    struct nvkm_event **pevent)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	switch (type) {
+	case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
+		*pevent = &priv->uevent;
+		return 0;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+int
+nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+	struct nv50_disp_chan *chan = (void *)object;
+	*addr = nv_device_resource_start(nv_device(object), 0) +
+		0x640000 + (chan->chid * 0x1000);
+	*size = 0x001000;
+	return 0;
+}
+
+u32
+nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_chan *chan = (void *)object;
+	return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
+}
+
+void
+nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_chan *chan = (void *)object;
+	nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
+}
+
+/*******************************************************************************
+ * EVO DMA channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_dmac_object_attach(struct nvkm_object *parent,
+			     struct nvkm_object *object, u32 name)
+{
+	struct nv50_disp_base *base = (void *)parent->parent;
+	struct nv50_disp_chan *chan = (void *)parent;
+	u32 addr = nv_gpuobj(object)->node->offset;
+	u32 chid = chan->chid;
+	u32 data = (chid << 28) | (addr << 10) | chid;
+	return nvkm_ramht_insert(base->ramht, chid, name, data);
+}
+
+static void
+nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie)
+{
+	struct nv50_disp_base *base = (void *)parent->parent;
+	nvkm_ramht_remove(base->ramht, cookie);
+}
+
+static int
+nv50_disp_dmac_create_(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, u32 pushbuf, int head,
+		       int length, void **pobject)
+{
+	struct nv50_disp_dmac *dmac;
+	int ret;
+
+	ret = nv50_disp_chan_create_(parent, engine, oclass, head,
+				     length, pobject);
+	dmac = *pobject;
+	if (ret)
+		return ret;
+
+	dmac->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
+	if (!dmac->pushdma)
+		return -ENOENT;
+
+	switch (nv_mclass(dmac->pushdma)) {
+	case 0x0002:
+	case 0x003d:
+		if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
+			return -EINVAL;
+
+		switch (dmac->pushdma->target) {
+		case NV_MEM_TARGET_VRAM:
+			dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
+			break;
+		case NV_MEM_TARGET_PCI_NOSNOOP:
+			dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void
+nv50_disp_dmac_dtor(struct nvkm_object *object)
+{
+	struct nv50_disp_dmac *dmac = (void *)object;
+	nvkm_object_ref(NULL, (struct nvkm_object **)&dmac->pushdma);
+	nv50_disp_chan_destroy(&dmac->base);
+}
+
+static int
+nv50_disp_dmac_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *dmac = (void *)object;
+	int chid = dmac->base.chid;
+	int ret;
+
+	ret = nv50_disp_chan_init(&dmac->base);
+	if (ret)
+		return ret;
+
+	/* enable error reporting */
+	nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
+
+	/* initialise channel for dma command submission */
+	nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
+	nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
+	nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
+	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
+	nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
+	nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
+
+	/* wait for it to go inactive */
+	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
+		nv_error(dmac, "init timeout, 0x%08x\n",
+			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *dmac = (void *)object;
+	int chid = dmac->base.chid;
+
+	/* deactivate channel */
+	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
+	nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
+	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
+		nv_error(dmac, "fini timeout, 0x%08x\n",
+			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	/* disable error reporting and completion notifications */
+	nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
+
+	return nv50_disp_chan_fini(&dmac->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+static void
+nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
+		    const struct nv50_disp_mthd_list *list, int inst)
+{
+	struct nvkm_object *disp = nv_object(priv);
+	int i;
+
+	for (i = 0; list->data[i].mthd; i++) {
+		if (list->data[i].addr) {
+			u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
+			u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
+			u32 mthd = list->data[i].mthd + (list->mthd * inst);
+			const char *name = list->data[i].name;
+			char mods[16];
+
+			if (prev != next)
+				snprintf(mods, sizeof(mods), "-> 0x%08x", next);
+			else
+				snprintf(mods, sizeof(mods), "%13c", ' ');
+
+			nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
+				   mthd, prev, mods, name ? " // " : "",
+				   name ? name : "");
+		}
+	}
+}
+
+void
+nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
+		    const struct nv50_disp_mthd_chan *chan)
+{
+	struct nvkm_object *disp = nv_object(priv);
+	const struct nv50_disp_impl *impl = (void *)disp->oclass;
+	const struct nv50_disp_mthd_list *list;
+	int i, j;
+
+	if (debug > nv_subdev(priv)->debug)
+		return;
+
+	for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
+		u32 base = head * chan->addr;
+		for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
+			const char *cname = chan->name;
+			const char *sname = "";
+			char cname_[16], sname_[16];
+
+			if (chan->addr) {
+				snprintf(cname_, sizeof(cname_), "%s %d",
+					 chan->name, head);
+				cname = cname_;
+			}
+
+			if (chan->data[i].nr > 1) {
+				snprintf(sname_, sizeof(sname_), " - %s %d",
+					 chan->data[i].name, j);
+				sname = sname_;
+			}
+
+			nv_printk_(disp, debug, "%s%s:\n", cname, sname);
+			nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
+					    list, j);
+		}
+	}
+}
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x610bb8 },
+		{ 0x0088, 0x610b9c },
+		{ 0x008c, 0x000000 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_dac = {
+	.mthd = 0x0080,
+	.addr = 0x000008,
+	.data = {
+		{ 0x0400, 0x610b58 },
+		{ 0x0404, 0x610bdc },
+		{ 0x0420, 0x610828 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_sor = {
+	.mthd = 0x0040,
+	.addr = 0x000008,
+	.data = {
+		{ 0x0600, 0x610b70 },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_pior = {
+	.mthd = 0x0040,
+	.addr = 0x000008,
+	.data = {
+		{ 0x0700, 0x610b80 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_head = {
+	.mthd = 0x0400,
+	.addr = 0x000540,
+	.data = {
+		{ 0x0800, 0x610ad8 },
+		{ 0x0804, 0x610ad0 },
+		{ 0x0808, 0x610a48 },
+		{ 0x080c, 0x610a78 },
+		{ 0x0810, 0x610ac0 },
+		{ 0x0814, 0x610af8 },
+		{ 0x0818, 0x610b00 },
+		{ 0x081c, 0x610ae8 },
+		{ 0x0820, 0x610af0 },
+		{ 0x0824, 0x610b08 },
+		{ 0x0828, 0x610b10 },
+		{ 0x082c, 0x610a68 },
+		{ 0x0830, 0x610a60 },
+		{ 0x0834, 0x000000 },
+		{ 0x0838, 0x610a40 },
+		{ 0x0840, 0x610a24 },
+		{ 0x0844, 0x610a2c },
+		{ 0x0848, 0x610aa8 },
+		{ 0x084c, 0x610ab0 },
+		{ 0x0860, 0x610a84 },
+		{ 0x0864, 0x610a90 },
+		{ 0x0868, 0x610b18 },
+		{ 0x086c, 0x610b20 },
+		{ 0x0870, 0x610ac8 },
+		{ 0x0874, 0x610a38 },
+		{ 0x0880, 0x610a58 },
+		{ 0x0884, 0x610a9c },
+		{ 0x08a0, 0x610a70 },
+		{ 0x08a4, 0x610a50 },
+		{ 0x08a8, 0x610ae0 },
+		{ 0x08c0, 0x610b28 },
+		{ 0x08c4, 0x610b30 },
+		{ 0x08c8, 0x610b40 },
+		{ 0x08d4, 0x610b38 },
+		{ 0x08d8, 0x610b48 },
+		{ 0x08dc, 0x610b50 },
+		{ 0x0900, 0x610a18 },
+		{ 0x0904, 0x610ab8 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_core_mthd_chan = {
+	.name = "Core",
+	.addr = 0x000000,
+	.data = {
+		{ "Global", 1, &nv50_disp_core_mthd_base },
+		{    "DAC", 3, &nv50_disp_core_mthd_dac  },
+		{    "SOR", 2, &nv50_disp_core_mthd_sor  },
+		{   "PIOR", 3, &nv50_disp_core_mthd_pior },
+		{   "HEAD", 2, &nv50_disp_core_mthd_head },
+		{}
+	}
+};
+
+int
+nv50_disp_core_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_disp_core_channel_dma_v0 v0;
+	} *args = data;
+	struct nv50_disp_dmac *mast;
+	int ret;
+
+	nv_ioctl(parent, "create disp core channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create disp core channel dma vers %d "
+				 "pushbuf %08x\n",
+			 args->v0.version, args->v0.pushbuf);
+	} else
+		return ret;
+
+	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+				     0, sizeof(*mast), (void **)&mast);
+	*pobject = nv_object(mast);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv50_disp_core_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *mast = (void *)object;
+	int ret;
+
+	ret = nv50_disp_chan_init(&mast->base);
+	if (ret)
+		return ret;
+
+	/* enable error reporting */
+	nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
+
+	/* attempt to unstick channel from some unknown state */
+	if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
+		nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
+	if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
+		nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
+
+	/* initialise channel for dma command submission */
+	nv_wr32(priv, 0x610204, mast->push);
+	nv_wr32(priv, 0x610208, 0x00010000);
+	nv_wr32(priv, 0x61020c, 0x00000000);
+	nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
+	nv_wr32(priv, 0x640000, 0x00000000);
+	nv_wr32(priv, 0x610200, 0x01000013);
+
+	/* wait for it to go inactive */
+	if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
+		nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+nv50_disp_core_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_dmac *mast = (void *)object;
+
+	/* deactivate channel */
+	nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
+	nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
+	if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
+		nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	/* disable error reporting and completion notifications */
+	nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
+
+	return nv50_disp_chan_fini(&mast->base, suspend);
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_core_ofuncs = {
+	.base.ctor = nv50_disp_core_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_core_init,
+	.base.fini = nv50_disp_core_fini,
+	.base.map  = nv50_disp_chan_map,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 0,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nv50_disp_base_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x0008c4 },
+		{ 0x0088, 0x0008d0 },
+		{ 0x008c, 0x0008dc },
+		{ 0x0090, 0x0008e4 },
+		{ 0x0094, 0x610884 },
+		{ 0x00a0, 0x6108a0 },
+		{ 0x00a4, 0x610878 },
+		{ 0x00c0, 0x61086c },
+		{ 0x00e0, 0x610858 },
+		{ 0x00e4, 0x610860 },
+		{ 0x00e8, 0x6108ac },
+		{ 0x00ec, 0x6108b4 },
+		{ 0x0100, 0x610894 },
+		{ 0x0110, 0x6108bc },
+		{ 0x0114, 0x61088c },
+		{}
+	}
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_base_mthd_image = {
+	.mthd = 0x0400,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0800, 0x6108f0 },
+		{ 0x0804, 0x6108fc },
+		{ 0x0808, 0x61090c },
+		{ 0x080c, 0x610914 },
+		{ 0x0810, 0x610904 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_base_mthd_chan = {
+	.name = "Base",
+	.addr = 0x000540,
+	.data = {
+		{ "Global", 1, &nv50_disp_base_mthd_base },
+		{  "Image", 2, &nv50_disp_base_mthd_image },
+		{}
+	}
+};
+
+int
+nv50_disp_base_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_disp_base_channel_dma_v0 v0;
+	} *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nv50_disp_dmac *dmac;
+	int ret;
+
+	nv_ioctl(parent, "create disp base channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create disp base channel dma vers %d "
+				 "pushbuf %08x head %d\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.head);
+		if (args->v0.head > priv->head.nr)
+			return -EINVAL;
+	} else
+		return ret;
+
+	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+				     args->v0.head, sizeof(*dmac),
+				     (void **)&dmac);
+	*pobject = nv_object(dmac);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_base_ofuncs = {
+	.base.ctor = nv50_disp_base_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_dmac_init,
+	.base.fini = nv50_disp_dmac_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 1,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+nv50_disp_ovly_mthd_base = {
+	.mthd = 0x0000,
+	.addr = 0x000000,
+	.data = {
+		{ 0x0080, 0x000000 },
+		{ 0x0084, 0x0009a0 },
+		{ 0x0088, 0x0009c0 },
+		{ 0x008c, 0x0009c8 },
+		{ 0x0090, 0x6109b4 },
+		{ 0x0094, 0x610970 },
+		{ 0x00a0, 0x610998 },
+		{ 0x00a4, 0x610964 },
+		{ 0x00c0, 0x610958 },
+		{ 0x00e0, 0x6109a8 },
+		{ 0x00e4, 0x6109d0 },
+		{ 0x00e8, 0x6109d8 },
+		{ 0x0100, 0x61094c },
+		{ 0x0104, 0x610984 },
+		{ 0x0108, 0x61098c },
+		{ 0x0800, 0x6109f8 },
+		{ 0x0808, 0x610a08 },
+		{ 0x080c, 0x610a10 },
+		{ 0x0810, 0x610a00 },
+		{}
+	}
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_ovly_mthd_chan = {
+	.name = "Overlay",
+	.addr = 0x000540,
+	.data = {
+		{ "Global", 1, &nv50_disp_ovly_mthd_base },
+		{}
+	}
+};
+
+int
+nv50_disp_ovly_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_disp_overlay_channel_dma_v0 v0;
+	} *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nv50_disp_dmac *dmac;
+	int ret;
+
+	nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create disp overlay channel dma vers %d "
+				 "pushbuf %08x head %d\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.head);
+		if (args->v0.head > priv->head.nr)
+			return -EINVAL;
+	} else
+		return ret;
+
+	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+				     args->v0.head, sizeof(*dmac),
+				     (void **)&dmac);
+	*pobject = nv_object(dmac);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_ovly_ofuncs = {
+	.base.ctor = nv50_disp_ovly_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_dmac_init,
+	.base.fini = nv50_disp_dmac_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 3,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO PIO channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_pioc_create_(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, int head,
+		       int length, void **pobject)
+{
+	return nv50_disp_chan_create_(parent, engine, oclass, head,
+				      length, pobject);
+}
+
+void
+nv50_disp_pioc_dtor(struct nvkm_object *object)
+{
+	struct nv50_disp_pioc *pioc = (void *)object;
+	nv50_disp_chan_destroy(&pioc->base);
+}
+
+static int
+nv50_disp_pioc_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_pioc *pioc = (void *)object;
+	int chid = pioc->base.chid;
+	int ret;
+
+	ret = nv50_disp_chan_init(&pioc->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
+	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
+		nv_error(pioc, "timeout0: 0x%08x\n",
+			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
+	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
+		nv_error(pioc, "timeout1: 0x%08x\n",
+			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int
+nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_pioc *pioc = (void *)object;
+	int chid = pioc->base.chid;
+
+	nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
+	if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
+		nv_error(pioc, "timeout: 0x%08x\n",
+			 nv_rd32(priv, 0x610200 + (chid * 0x10)));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	return nv50_disp_chan_fini(&pioc->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO immediate overlay channel objects
+ ******************************************************************************/
+
+int
+nv50_disp_oimm_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_disp_overlay_v0 v0;
+	} *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nv50_disp_pioc *pioc;
+	int ret;
+
+	nv_ioctl(parent, "create disp overlay size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create disp overlay vers %d head %d\n",
+			 args->v0.version, args->v0.head);
+		if (args->v0.head > priv->head.nr)
+			return -EINVAL;
+	} else
+		return ret;
+
+	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
+				     sizeof(*pioc), (void **)&pioc);
+	*pobject = nv_object(pioc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_oimm_ofuncs = {
+	.base.ctor = nv50_disp_oimm_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = nv50_disp_pioc_init,
+	.base.fini = nv50_disp_pioc_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 5,
+};
+
+/*******************************************************************************
+ * EVO cursor channel objects
+ ******************************************************************************/
+
+int
+nv50_disp_curs_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_disp_cursor_v0 v0;
+	} *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nv50_disp_pioc *pioc;
+	int ret;
+
+	nv_ioctl(parent, "create disp cursor size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create disp cursor vers %d head %d\n",
+			 args->v0.version, args->v0.head);
+		if (args->v0.head > priv->head.nr)
+			return -EINVAL;
+	} else
+		return ret;
+
+	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
+				     sizeof(*pioc), (void **)&pioc);
+	*pobject = nv_object(pioc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_curs_ofuncs = {
+	.base.ctor = nv50_disp_curs_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = nv50_disp_pioc_init,
+	.base.fini = nv50_disp_pioc_fini,
+	.base.ntfy = nv50_disp_chan_ntfy,
+	.base.map  = nv50_disp_chan_map,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 7,
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+int
+nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
+{
+	const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
+	const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
+	const u32 total  = nv_rd32(priv, 0x610afc + (head * 0x540));
+	union {
+		struct nv04_disp_scanoutpos_v0 v0;
+	} *args = data;
+	int ret;
+
+	nv_ioctl(object, "disp scanoutpos size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+		args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+		args->v0.hblanke = (blanke & 0x0000ffff);
+		args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+		args->v0.hblanks = (blanks & 0x0000ffff);
+		args->v0.vtotal  = ( total & 0xffff0000) >> 16;
+		args->v0.htotal  = ( total & 0x0000ffff);
+		args->v0.time[0] = ktime_to_ns(ktime_get());
+		args->v0.vline = /* vline read locks hline */
+			nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+		args->v0.time[1] = ktime_to_ns(ktime_get());
+		args->v0.hline =
+			nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+	} else
+		return ret;
+
+	return 0;
+}
+
+int
+nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
+	union {
+		struct nv50_disp_mthd_v0 v0;
+		struct nv50_disp_mthd_v1 v1;
+	} *args = data;
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nvkm_output *outp = NULL;
+	struct nvkm_output *temp;
+	u16 type, mask = 0;
+	int head, ret;
+
+	if (mthd != NV50_DISP_MTHD)
+		return -EINVAL;
+
+	nv_ioctl(object, "disp mthd size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
+			 args->v0.version, args->v0.method, args->v0.head);
+		mthd = args->v0.method;
+		head = args->v0.head;
+	} else
+	if (nvif_unpack(args->v1, 1, 1, true)) {
+		nv_ioctl(object, "disp mthd vers %d mthd %02x "
+				 "type %04x mask %04x\n",
+			 args->v1.version, args->v1.method,
+			 args->v1.hasht, args->v1.hashm);
+		mthd = args->v1.method;
+		type = args->v1.hasht;
+		mask = args->v1.hashm;
+		head = ffs((mask >> 8) & 0x0f) - 1;
+	} else
+		return ret;
+
+	if (head < 0 || head >= priv->head.nr)
+		return -ENXIO;
+
+	if (mask) {
+		list_for_each_entry(temp, &priv->base.outp, head) {
+			if ((temp->info.hasht         == type) &&
+			    (temp->info.hashm & mask) == mask) {
+				outp = temp;
+				break;
+			}
+		}
+		if (outp == NULL)
+			return -ENXIO;
+	}
+
+	switch (mthd) {
+	case NV50_DISP_SCANOUTPOS:
+		return impl->head.scanoutpos(object, priv, data, size, head);
+	default:
+		break;
+	}
+
+	switch (mthd * !!outp) {
+	case NV50_DISP_MTHD_V1_DAC_PWR:
+		return priv->dac.power(object, priv, data, size, head, outp);
+	case NV50_DISP_MTHD_V1_DAC_LOAD:
+		return priv->dac.sense(object, priv, data, size, head, outp);
+	case NV50_DISP_MTHD_V1_SOR_PWR:
+		return priv->sor.power(object, priv, data, size, head, outp);
+	case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
+		if (!priv->sor.hda_eld)
+			return -ENODEV;
+		return priv->sor.hda_eld(object, priv, data, size, head, outp);
+	case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
+		if (!priv->sor.hdmi)
+			return -ENODEV;
+		return priv->sor.hdmi(object, priv, data, size, head, outp);
+	case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
+		union {
+			struct nv50_disp_sor_lvds_script_v0 v0;
+		} *args = data;
+		nv_ioctl(object, "disp sor lvds script size %d\n", size);
+		if (nvif_unpack(args->v0, 0, 0, false)) {
+			nv_ioctl(object, "disp sor lvds script "
+					 "vers %d name %04x\n",
+				 args->v0.version, args->v0.script);
+			priv->sor.lvdsconf = args->v0.script;
+			return 0;
+		} else
+			return ret;
+	}
+		break;
+	case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
+		struct nvkm_output_dp *outpdp = (void *)outp;
+		union {
+			struct nv50_disp_sor_dp_pwr_v0 v0;
+		} *args = data;
+		nv_ioctl(object, "disp sor dp pwr size %d\n", size);
+		if (nvif_unpack(args->v0, 0, 0, false)) {
+			nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
+				 args->v0.version, args->v0.state);
+			if (args->v0.state == 0) {
+				nvkm_notify_put(&outpdp->irq);
+				((struct nvkm_output_dp_impl *)nv_oclass(outp))
+					->lnk_pwr(outpdp, 0);
+				atomic_set(&outpdp->lt.done, 0);
+				return 0;
+			} else
+			if (args->v0.state != 0) {
+				nvkm_output_dp_train(&outpdp->base, 0, true);
+				return 0;
+			}
+		} else
+			return ret;
+	}
+		break;
+	case NV50_DISP_MTHD_V1_PIOR_PWR:
+		if (!priv->pior.power)
+			return -ENODEV;
+		return priv->pior.power(object, priv, data, size, head, outp);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+int
+nv50_disp_main_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nv50_disp_base *base;
+	int ret;
+
+	ret = nvkm_parent_create(parent, engine, oclass, 0,
+				 priv->sclass, 0, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	return nvkm_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
+			      &base->ramht);
+}
+
+void
+nv50_disp_main_dtor(struct nvkm_object *object)
+{
+	struct nv50_disp_base *base = (void *)object;
+	nvkm_ramht_ref(NULL, &base->ramht);
+	nvkm_parent_destroy(&base->base);
+}
+
+static int
+nv50_disp_main_init(struct nvkm_object *object)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_base *base = (void *)object;
+	int ret, i;
+	u32 tmp;
+
+	ret = nvkm_parent_init(&base->base);
+	if (ret)
+		return ret;
+
+	/* The below segments of code copying values from one register to
+	 * another appear to inform EVO of the display capabilities or
+	 * something similar.  NFI what the 0x614004 caps are for..
+	 */
+	tmp = nv_rd32(priv, 0x614004);
+	nv_wr32(priv, 0x610184, tmp);
+
+	/* ... CRTC caps */
+	for (i = 0; i < priv->head.nr; i++) {
+		tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
+		nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
+		tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
+		nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
+		tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
+		nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
+		tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
+		nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
+	}
+
+	/* ... DAC caps */
+	for (i = 0; i < priv->dac.nr; i++) {
+		tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
+		nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
+	}
+
+	/* ... SOR caps */
+	for (i = 0; i < priv->sor.nr; i++) {
+		tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
+		nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
+	}
+
+	/* ... PIOR caps */
+	for (i = 0; i < priv->pior.nr; i++) {
+		tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
+		nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
+	}
+
+	/* steal display away from vbios, or something like that */
+	if (nv_rd32(priv, 0x610024) & 0x00000100) {
+		nv_wr32(priv, 0x610024, 0x00000100);
+		nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
+		if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
+			nv_error(priv, "timeout acquiring display\n");
+			return -EBUSY;
+		}
+	}
+
+	/* point at display engine memory area (hash table, objects) */
+	nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
+
+	/* enable supervisor interrupts, disable everything else */
+	nv_wr32(priv, 0x61002c, 0x00000370);
+	nv_wr32(priv, 0x610028, 0x00000000);
+	return 0;
+}
+
+static int
+nv50_disp_main_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_disp_priv *priv = (void *)object->engine;
+	struct nv50_disp_base *base = (void *)object;
+
+	/* disable all interrupts */
+	nv_wr32(priv, 0x610024, 0x00000000);
+	nv_wr32(priv, 0x610020, 0x00000000);
+
+	return nvkm_parent_fini(&base->base, suspend);
+}
+
+struct nvkm_ofuncs
+nv50_disp_main_ofuncs = {
+	.ctor = nv50_disp_main_ctor,
+	.dtor = nv50_disp_main_dtor,
+	.init = nv50_disp_main_init,
+	.fini = nv50_disp_main_fini,
+	.mthd = nv50_disp_main_mthd,
+	.ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+nv50_disp_main_oclass[] = {
+	{ NV50_DISP, &nv50_disp_main_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+nv50_disp_sclass[] = {
+	{ NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+	{ NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+	{ NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+	{ NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+	{ NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+	{}
+};
+
+/*******************************************************************************
+ * Display context, tracks instmem allocation and prevents more than one
+ * client using the display hardware at any time.
+ ******************************************************************************/
+
+static int
+nv50_disp_data_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv = (void *)engine;
+	struct nvkm_engctx *ectx;
+	int ret = -EBUSY;
+
+	/* no context needed for channel objects... */
+	if (nv_mclass(parent) != NV_DEVICE) {
+		atomic_inc(&parent->refcount);
+		*pobject = parent;
+		return 1;
+	}
+
+	/* allocate display hardware to client */
+	mutex_lock(&nv_subdev(priv)->mutex);
+	if (list_empty(&nv_engine(priv)->contexts)) {
+		ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000,
+					 0x10000, NVOBJ_FLAG_HEAP, &ectx);
+		*pobject = nv_object(ectx);
+	}
+	mutex_unlock(&nv_subdev(priv)->mutex);
+	return ret;
+}
+
+struct nvkm_oclass
+nv50_disp_cclass = {
+	.handle = NV_ENGCTX(DISP, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_disp_data_ctor,
+		.dtor = _nvkm_engctx_dtor,
+		.init = _nvkm_engctx_init,
+		.fini = _nvkm_engctx_fini,
+		.rd32 = _nvkm_engctx_rd32,
+		.wr32 = _nvkm_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_mask(disp, 0x61002c, (4 << head), 0);
+}
+
+static void
+nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+	struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+	nv_mask(disp, 0x61002c, (4 << head), (4 << head));
+}
+
+const struct nvkm_event_func
+nv50_disp_vblank_func = {
+	.ctor = nvkm_disp_vblank_ctor,
+	.init = nv50_disp_vblank_init,
+	.fini = nv50_disp_vblank_fini,
+};
+
+static const struct nvkm_enum
+nv50_disp_intr_error_type[] = {
+	{ 3, "ILLEGAL_MTHD" },
+	{ 4, "INVALID_VALUE" },
+	{ 5, "INVALID_STATE" },
+	{ 7, "INVALID_HANDLE" },
+	{}
+};
+
+static const struct nvkm_enum
+nv50_disp_intr_error_code[] = {
+	{ 0x00, "" },
+	{}
+};
+
+static void
+nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+	u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
+	u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
+	u32 code = (addr & 0x00ff0000) >> 16;
+	u32 type = (addr & 0x00007000) >> 12;
+	u32 mthd = (addr & 0x00000ffc);
+	const struct nvkm_enum *ec, *et;
+	char ecunk[6], etunk[6];
+
+	et = nvkm_enum_find(nv50_disp_intr_error_type, type);
+	if (!et)
+		snprintf(etunk, sizeof(etunk), "UNK%02X", type);
+
+	ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
+	if (!ec)
+		snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
+
+	nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
+		 et ? et->name : etunk, ec ? ec->name : ecunk,
+		 chid, mthd, data);
+
+	if (chid == 0) {
+		switch (mthd) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+					    impl->mthd.core);
+			break;
+		default:
+			break;
+		}
+	} else
+	if (chid <= 2) {
+		switch (mthd) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+					    impl->mthd.base);
+			break;
+		default:
+			break;
+		}
+	} else
+	if (chid <= 4) {
+		switch (mthd) {
+		case 0x0080:
+			nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
+					    impl->mthd.ovly);
+			break;
+		default:
+			break;
+		}
+	}
+
+	nv_wr32(priv, 0x610020, 0x00010000 << chid);
+	nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
+}
+
+static struct nvkm_output *
+exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
+	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	    struct nvbios_outp *info)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	u16 mask, type;
+
+	if (or < 4) {
+		type = DCB_OUTPUT_ANALOG;
+		mask = 0;
+	} else
+	if (or < 8) {
+		switch (ctrl & 0x00000f00) {
+		case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
+		case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
+		case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
+		case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
+		case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
+		case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
+		default:
+			nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
+			return NULL;
+		}
+		or  -= 4;
+	} else {
+		or   = or - 8;
+		type = 0x0010;
+		mask = 0;
+		switch (ctrl & 0x00000f00) {
+		case 0x00000000: type |= priv->pior.type[or]; break;
+		default:
+			nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
+			return NULL;
+		}
+	}
+
+	mask  = 0x00c0 & (mask << 6);
+	mask |= 0x0001 << or;
+	mask |= 0x0100 << head;
+
+	list_for_each_entry(outp, &priv->base.outp, head) {
+		if ((outp->info.hasht & 0xff) == type &&
+		    (outp->info.hashm & mask) == mask) {
+			*data = nvbios_outp_match(bios, outp->info.hasht,
+							outp->info.hashm,
+						  ver, hdr, cnt, len, info);
+			if (!*data)
+				return NULL;
+			return outp;
+		}
+	}
+
+	return NULL;
+}
+
+static struct nvkm_output *
+exec_script(struct nv50_disp_priv *priv, int head, int id)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	struct nvbios_outp info;
+	u8  ver, hdr, cnt, len;
+	u32 data, ctrl = 0;
+	u32 reg;
+	int i;
+
+	/* DAC */
+	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
+		ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
+
+	/* SOR */
+	if (!(ctrl & (1 << head))) {
+		if (nv_device(priv)->chipset  < 0x90 ||
+		    nv_device(priv)->chipset == 0x92 ||
+		    nv_device(priv)->chipset == 0xa0) {
+			reg = 0x610b74;
+		} else {
+			reg = 0x610798;
+		}
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+			ctrl = nv_rd32(priv, reg + (i * 8));
+		i += 4;
+	}
+
+	/* PIOR */
+	if (!(ctrl & (1 << head))) {
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
+			ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
+		i += 8;
+	}
+
+	if (!(ctrl & (1 << head)))
+		return NULL;
+	i--;
+
+	outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
+	if (outp) {
+		struct nvbios_init init = {
+			.subdev = nv_subdev(priv),
+			.bios = bios,
+			.offset = info.script[id],
+			.outp = &outp->info,
+			.crtc = head,
+			.execute = 1,
+		};
+
+		nvbios_exec(&init);
+	}
+
+	return outp;
+}
+
+static struct nvkm_output *
+exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvkm_output *outp;
+	struct nvbios_outp info1;
+	struct nvbios_ocfg info2;
+	u8  ver, hdr, cnt, len;
+	u32 data, ctrl = 0;
+	u32 reg;
+	int i;
+
+	/* DAC */
+	for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
+		ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
+
+	/* SOR */
+	if (!(ctrl & (1 << head))) {
+		if (nv_device(priv)->chipset  < 0x90 ||
+		    nv_device(priv)->chipset == 0x92 ||
+		    nv_device(priv)->chipset == 0xa0) {
+			reg = 0x610b70;
+		} else {
+			reg = 0x610794;
+		}
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+			ctrl = nv_rd32(priv, reg + (i * 8));
+		i += 4;
+	}
+
+	/* PIOR */
+	if (!(ctrl & (1 << head))) {
+		for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
+			ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
+		i += 8;
+	}
+
+	if (!(ctrl & (1 << head)))
+		return NULL;
+	i--;
+
+	outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
+	if (!outp)
+		return NULL;
+
+	if (outp->info.location == 0) {
+		switch (outp->info.type) {
+		case DCB_OUTPUT_TMDS:
+			*conf = (ctrl & 0x00000f00) >> 8;
+			if (pclk >= 165000)
+				*conf |= 0x0100;
+			break;
+		case DCB_OUTPUT_LVDS:
+			*conf = priv->sor.lvdsconf;
+			break;
+		case DCB_OUTPUT_DP:
+			*conf = (ctrl & 0x00000f00) >> 8;
+			break;
+		case DCB_OUTPUT_ANALOG:
+		default:
+			*conf = 0x00ff;
+			break;
+		}
+	} else {
+		*conf = (ctrl & 0x00000f00) >> 8;
+		pclk = pclk / 2;
+	}
+
+	data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
+	if (data && id < 0xff) {
+		data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
+		if (data) {
+			struct nvbios_init init = {
+				.subdev = nv_subdev(priv),
+				.bios = bios,
+				.offset = data,
+				.outp = &outp->info,
+				.crtc = head,
+				.execute = 1,
+			};
+
+			nvbios_exec(&init);
+		}
+	}
+
+	return outp;
+}
+
+static void
+nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
+{
+	exec_script(priv, head, 1);
+}
+
+static void
+nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_output *outp = exec_script(priv, head, 2);
+
+	/* the binary driver does this outside of the supervisor handling
+	 * (after the third supervisor from a detach).  we (currently?)
+	 * allow both detach/attach to happen in the same set of
+	 * supervisor interrupts, so it would make sense to execute this
+	 * (full power down?) script after all the detach phases of the
+	 * supervisor handling.  like with training if needed from the
+	 * second supervisor, nvidia doesn't do this, so who knows if it's
+	 * entirely safe, but it does appear to work..
+	 *
+	 * without this script being run, on some configurations i've
+	 * seen, switching from DP to TMDS on a DP connector may result
+	 * in a blank screen (SOR_PWR off/on can restore it)
+	 */
+	if (outp && outp->info.type == DCB_OUTPUT_DP) {
+		struct nvkm_output_dp *outpdp = (void *)outp;
+		struct nvbios_init init = {
+			.subdev = nv_subdev(priv),
+			.bios = nvkm_bios(priv),
+			.outp = &outp->info,
+			.crtc = head,
+			.offset = outpdp->info.script[4],
+			.execute = 1,
+		};
+
+		nvbios_exec(&init);
+		atomic_set(&outpdp->lt.done, 0);
+	}
+}
+
+static void
+nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(priv);
+	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+	if (pclk)
+		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
+}
+
+static void
+nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
+			  struct dcb_output *outp, u32 pclk)
+{
+	const int link = !(outp->sorconf.link & 1);
+	const int   or = ffs(outp->or) - 1;
+	const u32 soff = (  or * 0x800);
+	const u32 loff = (link * 0x080) + soff;
+	const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
+	const u32 symbol = 100000;
+	const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
+	const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
+	const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
+	u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
+	u32 clksor = nv_rd32(priv, 0x614300 + soff);
+	int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+	int TU, VTUi, VTUf, VTUa;
+	u64 link_data_rate, link_ratio, unk;
+	u32 best_diff = 64 * symbol;
+	u32 link_nr, link_bw, bits;
+	u64 value;
+
+	link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
+	link_nr = hweight32(dpctrl & 0x000f0000);
+
+	/* symbols/hblank - algorithm taken from comments in tegra driver */
+	value = vblanke + vactive - vblanks - 7;
+	value = value * link_bw;
+	do_div(value, pclk);
+	value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+	nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
+
+	/* symbols/vblank - algorithm taken from comments in tegra driver */
+	value = vblanks - vblanke - 25;
+	value = value * link_bw;
+	do_div(value, pclk);
+	value = value - ((36 / link_nr) + 3) - 1;
+	nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
+
+	/* watermark / activesym */
+	if      ((ctrl & 0xf0000) == 0x60000) bits = 30;
+	else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
+	else                                  bits = 18;
+
+	link_data_rate = (pclk * bits / 8) / link_nr;
+
+	/* calculate ratio of packed data rate to link symbol rate */
+	link_ratio = link_data_rate * symbol;
+	do_div(link_ratio, link_bw);
+
+	for (TU = 64; TU >= 32; TU--) {
+		/* calculate average number of valid symbols in each TU */
+		u32 tu_valid = link_ratio * TU;
+		u32 calc, diff;
+
+		/* find a hw representation for the fraction.. */
+		VTUi = tu_valid / symbol;
+		calc = VTUi * symbol;
+		diff = tu_valid - calc;
+		if (diff) {
+			if (diff >= (symbol / 2)) {
+				VTUf = symbol / (symbol - diff);
+				if (symbol - (VTUf * diff))
+					VTUf++;
+
+				if (VTUf <= 15) {
+					VTUa  = 1;
+					calc += symbol - (symbol / VTUf);
+				} else {
+					VTUa  = 0;
+					VTUf  = 1;
+					calc += symbol;
+				}
+			} else {
+				VTUa  = 0;
+				VTUf  = min((int)(symbol / diff), 15);
+				calc += symbol / VTUf;
+			}
+
+			diff = calc - tu_valid;
+		} else {
+			/* no remainder, but the hw doesn't like the fractional
+			 * part to be zero.  decrement the integer part and
+			 * have the fraction add a whole symbol back
+			 */
+			VTUa = 0;
+			VTUf = 1;
+			VTUi--;
+		}
+
+		if (diff < best_diff) {
+			best_diff = diff;
+			bestTU = TU;
+			bestVTUa = VTUa;
+			bestVTUf = VTUf;
+			bestVTUi = VTUi;
+			if (diff == 0)
+				break;
+		}
+	}
+
+	if (!bestTU) {
+		nv_error(priv, "unable to find suitable dp config\n");
+		return;
+	}
+
+	/* XXX close to vbios numbers, but not right */
+	unk  = (symbol - link_ratio) * bestTU;
+	unk *= link_ratio;
+	do_div(unk, symbol);
+	do_div(unk, symbol);
+	unk += 6;
+
+	nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
+	nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
+						   bestVTUf << 16 |
+						   bestVTUi << 8 | unk);
+}
+
+static void
+nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_output *outp;
+	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+	u32 hval, hreg = 0x614200 + (head * 0x800);
+	u32 oval, oreg;
+	u32 mask, conf;
+
+	outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
+	if (!outp)
+		return;
+
+	/* we allow both encoder attach and detach operations to occur
+	 * within a single supervisor (ie. modeset) sequence.  the
+	 * encoder detach scripts quite often switch off power to the
+	 * lanes, which requires the link to be re-trained.
+	 *
+	 * this is not generally an issue as the sink "must" (heh)
+	 * signal an irq when it's lost sync so the driver can
+	 * re-train.
+	 *
+	 * however, on some boards, if one does not configure at least
+	 * the gpu side of the link *before* attaching, then various
+	 * things can go horribly wrong (PDISP disappearing from mmio,
+	 * third supervisor never happens, etc).
+	 *
+	 * the solution is simply to retrain here, if necessary.  last
+	 * i checked, the binary driver userspace does not appear to
+	 * trigger this situation (it forces an UPDATE between steps).
+	 */
+	if (outp->info.type == DCB_OUTPUT_DP) {
+		u32 soff = (ffs(outp->info.or) - 1) * 0x08;
+		u32 ctrl, datarate;
+
+		if (outp->info.location == 0) {
+			ctrl = nv_rd32(priv, 0x610794 + soff);
+			soff = 1;
+		} else {
+			ctrl = nv_rd32(priv, 0x610b80 + soff);
+			soff = 2;
+		}
+
+		switch ((ctrl & 0x000f0000) >> 16) {
+		case 6: datarate = pclk * 30; break;
+		case 5: datarate = pclk * 24; break;
+		case 2:
+		default:
+			datarate = pclk * 18;
+			break;
+		}
+
+		if (nvkm_output_dp_train(outp, datarate / soff, true))
+			ERR("link not trained before attach\n");
+	}
+
+	exec_clkcmp(priv, head, 0, pclk, &conf);
+
+	if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
+		oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
+		oval = 0x00000000;
+		hval = 0x00000000;
+		mask = 0xffffffff;
+	} else
+	if (!outp->info.location) {
+		if (outp->info.type == DCB_OUTPUT_DP)
+			nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
+		oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
+		oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
+		hval = 0x00000000;
+		mask = 0x00000707;
+	} else {
+		oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
+		oval = 0x00000001;
+		hval = 0x00000001;
+		mask = 0x00000707;
+	}
+
+	nv_mask(priv, hreg, 0x0000000f, hval);
+	nv_mask(priv, oreg, mask, oval);
+}
+
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
+static void
+nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv,
+			    struct dcb_output *outp)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	const int link = !(outp->sorconf.link & 1);
+	const int   or = ffs(outp->or) - 1;
+	const u32 loff = (or * 0x800) + (link * 0x80);
+	const u16 mask = (outp->sorconf.link << 6) | outp->or;
+	struct dcb_output match;
+	u8  ver, hdr;
+
+	if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
+		nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
+}
+
+static void
+nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
+{
+	struct nvkm_output *outp;
+	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+	u32 conf;
+
+	outp = exec_clkcmp(priv, head, 1, pclk, &conf);
+	if (!outp)
+		return;
+
+	if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
+		nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
+}
+
+void
+nv50_disp_intr_supervisor(struct work_struct *work)
+{
+	struct nv50_disp_priv *priv =
+		container_of(work, struct nv50_disp_priv, supervisor);
+	struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+	u32 super = nv_rd32(priv, 0x610030);
+	int head;
+
+	nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
+
+	if (priv->super & 0x00000010) {
+		nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(super & (0x00000020 << head)))
+				continue;
+			if (!(super & (0x00000080 << head)))
+				continue;
+			nv50_disp_intr_unk10_0(priv, head);
+		}
+	} else
+	if (priv->super & 0x00000020) {
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(super & (0x00000080 << head)))
+				continue;
+			nv50_disp_intr_unk20_0(priv, head);
+		}
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(super & (0x00000200 << head)))
+				continue;
+			nv50_disp_intr_unk20_1(priv, head);
+		}
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(super & (0x00000080 << head)))
+				continue;
+			nv50_disp_intr_unk20_2(priv, head);
+		}
+	} else
+	if (priv->super & 0x00000040) {
+		for (head = 0; head < priv->head.nr; head++) {
+			if (!(super & (0x00000080 << head)))
+				continue;
+			nv50_disp_intr_unk40_0(priv, head);
+		}
+	}
+
+	nv_wr32(priv, 0x610030, 0x80000000);
+}
+
+void
+nv50_disp_intr(struct nvkm_subdev *subdev)
+{
+	struct nv50_disp_priv *priv = (void *)subdev;
+	u32 intr0 = nv_rd32(priv, 0x610020);
+	u32 intr1 = nv_rd32(priv, 0x610024);
+
+	while (intr0 & 0x001f0000) {
+		u32 chid = __ffs(intr0 & 0x001f0000) - 16;
+		nv50_disp_intr_error(priv, chid);
+		intr0 &= ~(0x00010000 << chid);
+	}
+
+	while (intr0 & 0x0000001f) {
+		u32 chid = __ffs(intr0 & 0x0000001f);
+		nv50_disp_chan_uevent_send(priv, chid);
+		intr0 &= ~(0x00000001 << chid);
+	}
+
+	if (intr1 & 0x00000004) {
+		nvkm_disp_vblank(&priv->base, 0);
+		nv_wr32(priv, 0x610024, 0x00000004);
+		intr1 &= ~0x00000004;
+	}
+
+	if (intr1 & 0x00000008) {
+		nvkm_disp_vblank(&priv->base, 1);
+		nv_wr32(priv, 0x610024, 0x00000008);
+		intr1 &= ~0x00000008;
+	}
+
+	if (intr1 & 0x00000070) {
+		priv->super = (intr1 & 0x00000070);
+		schedule_work(&priv->supervisor);
+		nv_wr32(priv, 0x610024, priv->super);
+		intr1 &= ~0x00000070;
+	}
+}
+
+static int
+nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv50_disp_priv *priv;
+	int ret;
+
+	ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+			       "display", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->sclass = nv50_disp_main_oclass;
+	nv_engine(priv)->cclass = &nv50_disp_cclass;
+	nv_subdev(priv)->intr = nv50_disp_intr;
+	INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+	priv->sclass = nv50_disp_sclass;
+	priv->head.nr = 2;
+	priv->dac.nr = 3;
+	priv->sor.nr = 2;
+	priv->pior.nr = 3;
+	priv->dac.power = nv50_dac_power;
+	priv->dac.sense = nv50_dac_sense;
+	priv->sor.power = nv50_sor_power;
+	priv->pior.power = nv50_pior_power;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_disp_outp_sclass[] = {
+	&nv50_pior_dp_impl.base.base,
+	NULL
+};
+
+struct nvkm_oclass *
+nv50_disp_oclass = &(struct nv50_disp_impl) {
+	.base.base.handle = NV_ENGINE(DISP, 0x50),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_disp_ctor,
+		.dtor = _nvkm_disp_dtor,
+		.init = _nvkm_disp_init,
+		.fini = _nvkm_disp_fini,
+	},
+	.base.vblank = &nv50_disp_vblank_func,
+	.base.outp =  nv50_disp_outp_sclass,
+	.mthd.core = &nv50_disp_core_mthd_chan,
+	.mthd.base = &nv50_disp_base_mthd_chan,
+	.mthd.ovly = &nv50_disp_ovly_mthd_chan,
+	.mthd.prev = 0x000004,
+	.head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
new file mode 100644
index 0000000..b4ed620
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -0,0 +1,226 @@
+#ifndef __NV50_DISP_H__
+#define __NV50_DISP_H__
+#include "priv.h"
+struct nvkm_output;
+struct nvkm_output_dp;
+
+#define NV50_DISP_MTHD_ struct nvkm_object *object,                            \
+	struct nv50_disp_priv *priv, void *data, u32 size
+#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
+#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
+
+struct nv50_disp_priv {
+	struct nvkm_disp base;
+	struct nvkm_oclass *sclass;
+
+	struct work_struct supervisor;
+	u32 super;
+
+	struct nvkm_event uevent;
+
+	struct {
+		int nr;
+	} head;
+	struct {
+		int nr;
+		int (*power)(NV50_DISP_MTHD_V1);
+		int (*sense)(NV50_DISP_MTHD_V1);
+	} dac;
+	struct {
+		int nr;
+		int (*power)(NV50_DISP_MTHD_V1);
+		int (*hda_eld)(NV50_DISP_MTHD_V1);
+		int (*hdmi)(NV50_DISP_MTHD_V1);
+		u32 lvdsconf;
+		void (*magic)(struct nvkm_output *);
+	} sor;
+	struct {
+		int nr;
+		int (*power)(NV50_DISP_MTHD_V1);
+		u8 type[3];
+	} pior;
+};
+
+struct nv50_disp_impl {
+	struct nvkm_disp_impl base;
+	struct {
+		const struct nv50_disp_mthd_chan *core;
+		const struct nv50_disp_mthd_chan *base;
+		const struct nv50_disp_mthd_chan *ovly;
+		int prev;
+	} mthd;
+	struct {
+		int (*scanoutpos)(NV50_DISP_MTHD_V0);
+	} head;
+};
+
+int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
+int nv50_disp_main_mthd(struct nvkm_object *, u32, void *, u32);
+
+int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
+
+int nv50_dac_power(NV50_DISP_MTHD_V1);
+int nv50_dac_sense(NV50_DISP_MTHD_V1);
+
+int gt215_hda_eld(NV50_DISP_MTHD_V1);
+int gf110_hda_eld(NV50_DISP_MTHD_V1);
+
+int g84_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gf110_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1);
+
+int nv50_sor_power(NV50_DISP_MTHD_V1);
+int nv50_pior_power(NV50_DISP_MTHD_V1);
+
+#include <core/parent.h>
+
+struct nv50_disp_base {
+	struct nvkm_parent base;
+	struct nvkm_ramht *ramht;
+	u32 chan;
+};
+
+struct nv50_disp_chan_impl {
+	struct nvkm_ofuncs base;
+	int chid;
+	int  (*attach)(struct nvkm_object *, struct nvkm_object *, u32);
+	void (*detach)(struct nvkm_object *, int);
+};
+
+#include <core/namedb.h>
+
+struct nv50_disp_chan {
+	struct nvkm_namedb base;
+	int chid;
+};
+
+int  nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+int  nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *);
+u32  nv50_disp_chan_rd32(struct nvkm_object *, u64);
+void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32);
+extern const struct nvkm_event_func nv50_disp_chan_uevent;
+int  nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32,
+				struct nvkm_notify *);
+void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
+
+extern const struct nvkm_event_func gf110_disp_chan_uevent;
+
+#define nv50_disp_chan_init(a)                                                 \
+	nvkm_namedb_init(&(a)->base)
+#define nv50_disp_chan_fini(a,b)                                               \
+	nvkm_namedb_fini(&(a)->base, (b))
+
+struct nv50_disp_dmac {
+	struct nv50_disp_chan base;
+	struct nvkm_dmaobj *pushdma;
+	u32 push;
+};
+
+void nv50_disp_dmac_dtor(struct nvkm_object *);
+
+struct nv50_disp_pioc {
+	struct nv50_disp_chan base;
+};
+
+void nv50_disp_pioc_dtor(struct nvkm_object *);
+
+struct nv50_disp_mthd_list {
+	u32 mthd;
+	u32 addr;
+	struct {
+		u32 mthd;
+		u32 addr;
+		const char *name;
+	} data[];
+};
+
+struct nv50_disp_mthd_chan {
+	const char *name;
+	u32 addr;
+	struct {
+		const char *name;
+		int nr;
+		const struct nv50_disp_mthd_list *mthd;
+	} data[];
+};
+
+extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
+int nv50_disp_core_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
+int nv50_disp_base_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
+extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
+int nv50_disp_ovly_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
+extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs;
+int nv50_disp_oimm_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
+int nv50_disp_curs_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+extern struct nvkm_ofuncs nv50_disp_main_ofuncs;
+int  nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *,
+			 struct nvkm_oclass *, void *, u32,
+			 struct nvkm_object **);
+void nv50_disp_main_dtor(struct nvkm_object *);
+extern struct nvkm_omthds nv50_disp_main_omthds[];
+extern struct nvkm_oclass nv50_disp_cclass;
+void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
+			 const struct nv50_disp_mthd_chan *);
+void nv50_disp_intr_supervisor(struct work_struct *);
+void nv50_disp_intr(struct nvkm_subdev *);
+extern const struct nvkm_event_func nv50_disp_vblank_func;
+
+extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan;
+extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head;
+extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan;
+extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan;
+
+extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan;
+
+extern struct nv50_disp_chan_impl gf110_disp_core_ofuncs;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl gf110_disp_base_ofuncs;
+extern struct nv50_disp_chan_impl gf110_disp_ovly_ofuncs;
+extern const struct nv50_disp_mthd_chan gf110_disp_base_mthd_chan;
+extern struct nv50_disp_chan_impl gf110_disp_oimm_ofuncs;
+extern struct nv50_disp_chan_impl gf110_disp_curs_ofuncs;
+extern struct nvkm_ofuncs gf110_disp_main_ofuncs;
+extern struct nvkm_oclass gf110_disp_cclass;
+void gf110_disp_intr_supervisor(struct work_struct *);
+void gf110_disp_intr(struct nvkm_subdev *);
+extern const struct nvkm_event_func gf110_disp_vblank_func;
+
+extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan;
+extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan;
+
+extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
+extern struct nvkm_oclass *nv50_disp_outp_sclass[];
+
+extern struct nvkm_output_dp_impl g94_sor_dp_impl;
+int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
+extern struct nvkm_oclass *g94_disp_outp_sclass[];
+
+extern struct nvkm_output_dp_impl gf110_sor_dp_impl;
+int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
+extern struct nvkm_oclass *gf110_disp_outp_sclass[];
+
+void gm204_sor_magic(struct nvkm_output *outp);
+extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
new file mode 100644
index 0000000..9224bcb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "outp.h"
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/i2c.h>
+
+int
+_nvkm_output_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_output *outp = (void *)object;
+	nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
+	return nvkm_object_fini(&outp->base, suspend);
+}
+
+int
+_nvkm_output_init(struct nvkm_object *object)
+{
+	struct nvkm_output *outp = (void *)object;
+	int ret = nvkm_object_init(&outp->base);
+	if (ret == 0)
+		nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
+	return 0;
+}
+
+void
+_nvkm_output_dtor(struct nvkm_object *object)
+{
+	struct nvkm_output *outp = (void *)object;
+	list_del(&outp->head);
+	nvkm_object_ref(NULL, (void *)&outp->conn);
+	nvkm_object_destroy(&outp->base);
+}
+
+int
+nvkm_output_create_(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass,
+		    struct dcb_output *dcbE, int index,
+		    int length, void **pobject)
+{
+	struct nvkm_disp *disp = nvkm_disp(parent);
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvbios_connE connE;
+	struct nvkm_output *outp;
+	u8  ver, hdr;
+	u32 data;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+	outp = *pobject;
+	if (ret)
+		return ret;
+
+	outp->info = *dcbE;
+	outp->index = index;
+	outp->or = ffs(outp->info.or) - 1;
+
+	DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
+	    dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
+	    dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
+	    dcbE->bus, dcbE->heads);
+
+	if (outp->info.type != DCB_OUTPUT_DP)
+		outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
+	else
+		outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
+	outp->edid = outp->port;
+
+	data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
+	if (!data) {
+		DBG("vbios connector data not found\n");
+		memset(&connE, 0x00, sizeof(connE));
+		connE.type = DCB_CONNECTOR_NONE;
+	}
+
+	ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass,
+			       &connE, outp->info.connector,
+			       (struct nvkm_object **)&outp->conn);
+	if (ret < 0) {
+		ERR("error %d creating connector, disabling\n", ret);
+		return ret;
+	}
+
+	list_add_tail(&outp->head, &disp->outp);
+	return 0;
+}
+
+int
+_nvkm_output_ctor(struct nvkm_object *parent,
+		  struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *dcbE, u32 index,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_output *outp;
+	int ret;
+
+	ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
+	*pobject = nv_object(outp);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nvkm_output_oclass = &(struct nvkm_output_impl) {
+	.base = {
+		.handle = 0,
+		.ofuncs = &(struct nvkm_ofuncs) {
+			.ctor = _nvkm_output_ctor,
+			.dtor = _nvkm_output_dtor,
+			.init = _nvkm_output_init,
+			.fini = _nvkm_output_fini,
+		},
+	},
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
new file mode 100644
index 0000000..d9253d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_DISP_OUTP_H__
+#define __NVKM_DISP_OUTP_H__
+#include <core/object.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+struct nvkm_output {
+	struct nvkm_object base;
+	struct list_head head;
+
+	struct dcb_output info;
+	int index;
+	int or;
+
+	struct nvkm_i2c_port *port;
+	struct nvkm_i2c_port *edid;
+
+	struct nvkm_connector *conn;
+};
+
+#define nvkm_output_create(p,e,c,b,i,d)                                        \
+	nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_output_destroy(d) ({                                              \
+	struct nvkm_output *_outp = (d);                                       \
+	_nvkm_output_dtor(nv_object(_outp));                                   \
+})
+#define nvkm_output_init(d) ({                                                 \
+	struct nvkm_output *_outp = (d);                                       \
+	_nvkm_output_init(nv_object(_outp));                                   \
+})
+#define nvkm_output_fini(d,s) ({                                               \
+	struct nvkm_output *_outp = (d);                                       \
+	_nvkm_output_fini(nv_object(_outp), (s));                              \
+})
+
+int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, struct dcb_output *,
+			int, int, void **);
+
+int  _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, void *, u32,
+		       struct nvkm_object **);
+void _nvkm_output_dtor(struct nvkm_object *);
+int  _nvkm_output_init(struct nvkm_object *);
+int  _nvkm_output_fini(struct nvkm_object *, bool);
+
+struct nvkm_output_impl {
+	struct nvkm_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+	struct nvkm_output *_outp = (void *)outp;                              \
+	nv_##l(_outp, "%02x:%04x:%04x: "f, _outp->index,                       \
+	       _outp->info.hasht, _outp->info.hashm, ##a);                     \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
new file mode 100644
index 0000000..0bde0fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "outpdp.h"
+#include "conn.h"
+#include "dport.h"
+#include "priv.h"
+
+#include <subdev/i2c.h>
+
+#include <nvif/event.h>
+
+int
+nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
+{
+	struct nvkm_output_dp *outp = (void *)base;
+	bool retrain = true;
+	u8 link[2], stat[3];
+	u32 linkrate;
+	int ret, i;
+
+	/* check that the link is trained at a high enough rate */
+	ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
+	if (ret) {
+		DBG("failed to read link config, assuming no sink\n");
+		goto done;
+	}
+
+	linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
+	linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
+	datarate = (datarate + 9) / 10; /* -> decakilobits */
+	if (linkrate < datarate) {
+		DBG("link not trained at sufficient rate\n");
+		goto done;
+	}
+
+	/* check that link is still trained */
+	ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
+	if (ret) {
+		DBG("failed to read link status, assuming no sink\n");
+		goto done;
+	}
+
+	if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
+		for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
+			u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
+			if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
+			    !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
+			    !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
+				DBG("lane %d not equalised\n", lane);
+				goto done;
+			}
+		}
+		retrain = false;
+	} else {
+		DBG("no inter-lane alignment\n");
+	}
+
+done:
+	if (retrain || !atomic_read(&outp->lt.done)) {
+		/* no sink, but still need to configure source */
+		if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
+			outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
+				outp->base.info.dpconf.link_bw;
+			outp->dpcd[DPCD_RC02] =
+				outp->base.info.dpconf.link_nr;
+		}
+		atomic_set(&outp->lt.done, 0);
+		schedule_work(&outp->lt.work);
+	} else {
+		nvkm_notify_get(&outp->irq);
+	}
+
+	if (wait) {
+		if (!wait_event_timeout(outp->lt.wait,
+					atomic_read(&outp->lt.done),
+					msecs_to_jiffies(2000)))
+			ret = -ETIMEDOUT;
+	}
+
+	return ret;
+}
+
+static void
+nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
+{
+	struct nvkm_i2c_port *port = outp->base.edid;
+	if (present) {
+		if (!outp->present) {
+			nvkm_i2c(port)->acquire_pad(port, 0);
+			DBG("aux power -> always\n");
+			outp->present = true;
+		}
+		nvkm_output_dp_train(&outp->base, 0, true);
+	} else {
+		if (outp->present) {
+			nvkm_i2c(port)->release_pad(port);
+			DBG("aux power -> demand\n");
+			outp->present = false;
+		}
+		atomic_set(&outp->lt.done, 0);
+	}
+}
+
+static void
+nvkm_output_dp_detect(struct nvkm_output_dp *outp)
+{
+	struct nvkm_i2c_port *port = outp->base.edid;
+	int ret = nvkm_i2c(port)->acquire_pad(port, 0);
+	if (ret == 0) {
+		ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
+			       outp->dpcd, sizeof(outp->dpcd));
+		nvkm_output_dp_enable(outp, ret == 0);
+		nvkm_i2c(port)->release_pad(port);
+	}
+}
+
+static int
+nvkm_output_dp_hpd(struct nvkm_notify *notify)
+{
+	struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
+	struct nvkm_output_dp *outp;
+	struct nvkm_disp *disp = nvkm_disp(conn);
+	const struct nvkm_i2c_ntfy_rep *line = notify->data;
+	struct nvif_notify_conn_rep_v0 rep = {};
+
+	list_for_each_entry(outp, &disp->outp, base.head) {
+		if (outp->base.conn == conn &&
+		    outp->info.type == DCB_OUTPUT_DP) {
+			DBG("HPD: %d\n", line->mask);
+			nvkm_output_dp_detect(outp);
+
+			if (line->mask & NVKM_I2C_UNPLUG)
+				rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
+			if (line->mask & NVKM_I2C_PLUG)
+				rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
+
+			nvkm_event_send(&disp->hpd, rep.mask, conn->index,
+					&rep, sizeof(rep));
+			return NVKM_NOTIFY_KEEP;
+		}
+	}
+
+	WARN_ON(1);
+	return NVKM_NOTIFY_DROP;
+}
+
+static int
+nvkm_output_dp_irq(struct nvkm_notify *notify)
+{
+	struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
+	struct nvkm_disp *disp = nvkm_disp(outp);
+	const struct nvkm_i2c_ntfy_rep *line = notify->data;
+	struct nvif_notify_conn_rep_v0 rep = {
+		.mask = NVIF_NOTIFY_CONN_V0_IRQ,
+	};
+	int index = outp->base.info.connector;
+
+	DBG("IRQ: %d\n", line->mask);
+	nvkm_output_dp_train(&outp->base, 0, true);
+
+	nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+	return NVKM_NOTIFY_DROP;
+}
+
+int
+_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_output_dp *outp = (void *)object;
+	nvkm_notify_put(&outp->irq);
+	nvkm_output_dp_enable(outp, false);
+	return nvkm_output_fini(&outp->base, suspend);
+}
+
+int
+_nvkm_output_dp_init(struct nvkm_object *object)
+{
+	struct nvkm_output_dp *outp = (void *)object;
+	nvkm_output_dp_detect(outp);
+	return nvkm_output_init(&outp->base);
+}
+
+void
+_nvkm_output_dp_dtor(struct nvkm_object *object)
+{
+	struct nvkm_output_dp *outp = (void *)object;
+	nvkm_notify_fini(&outp->irq);
+	nvkm_output_destroy(&outp->base);
+}
+
+int
+nvkm_output_dp_create_(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass,
+		       struct dcb_output *info, int index,
+		       int length, void **pobject)
+{
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvkm_output_dp *outp;
+	u8  hdr, cnt, len;
+	u32 data;
+	int ret;
+
+	ret = nvkm_output_create_(parent, engine, oclass, info, index,
+				  length, pobject);
+	outp = *pobject;
+	if (ret)
+		return ret;
+
+	nvkm_notify_fini(&outp->base.conn->hpd);
+
+	/* access to the aux channel is not optional... */
+	if (!outp->base.edid) {
+		ERR("aux channel not found\n");
+		return -ENODEV;
+	}
+
+	/* nor is the bios data for this output... */
+	data = nvbios_dpout_match(bios, outp->base.info.hasht,
+				  outp->base.info.hashm, &outp->version,
+				  &hdr, &cnt, &len, &outp->info);
+	if (!data) {
+		ERR("no bios dp data\n");
+		return -ENODEV;
+	}
+
+	DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
+
+	/* link training */
+	INIT_WORK(&outp->lt.work, nvkm_dp_train);
+	init_waitqueue_head(&outp->lt.wait);
+	atomic_set(&outp->lt.done, 0);
+
+	/* link maintenance */
+	ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
+			       &(struct nvkm_i2c_ntfy_req) {
+				.mask = NVKM_I2C_IRQ,
+				.port = outp->base.edid->index,
+			       },
+			       sizeof(struct nvkm_i2c_ntfy_req),
+			       sizeof(struct nvkm_i2c_ntfy_rep),
+			       &outp->irq);
+	if (ret) {
+		ERR("error monitoring aux irq event: %d\n", ret);
+		return ret;
+	}
+
+	/* hotplug detect, replaces gpio-based mechanism with aux events */
+	ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
+			       &(struct nvkm_i2c_ntfy_req) {
+				.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
+				.port = outp->base.edid->index,
+			       },
+			       sizeof(struct nvkm_i2c_ntfy_req),
+			       sizeof(struct nvkm_i2c_ntfy_rep),
+			       &outp->base.conn->hpd);
+	if (ret) {
+		ERR("error monitoring aux hpd events: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int
+_nvkm_output_dp_ctor(struct nvkm_object *parent,
+		     struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *info, u32 index,
+		     struct nvkm_object **pobject)
+{
+	struct nvkm_output_dp *outp;
+	int ret;
+
+	ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
+	*pobject = nv_object(outp);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
new file mode 100644
index 0000000..70c77ae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_DISP_OUTP_DP_H__
+#define __NVKM_DISP_OUTP_DP_H__
+#include "outp.h"
+
+#include <core/notify.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dp.h>
+
+struct nvkm_output_dp {
+	struct nvkm_output base;
+
+	struct nvbios_dpout info;
+	u8 version;
+
+	struct nvkm_notify irq;
+	bool present;
+	u8 dpcd[16];
+
+	struct {
+		struct work_struct work;
+		wait_queue_head_t wait;
+		atomic_t done;
+	} lt;
+};
+
+#define nvkm_output_dp_create(p,e,c,b,i,d)                                     \
+	nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_output_dp_destroy(d) ({                                           \
+	struct nvkm_output_dp *_outp = (d);                                    \
+	_nvkm_output_dp_dtor(nv_object(_outp));                                \
+})
+#define nvkm_output_dp_init(d) ({                                              \
+	struct nvkm_output_dp *_outp = (d);                                    \
+	_nvkm_output_dp_init(nv_object(_outp));                                \
+})
+#define nvkm_output_dp_fini(d,s) ({                                            \
+	struct nvkm_output_dp *_outp = (d);                                    \
+	_nvkm_output_dp_fini(nv_object(_outp), (s));                           \
+})
+
+int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *,
+			   struct nvkm_oclass *, struct dcb_output *,
+			   int, int, void **);
+
+int  _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, void *, u32,
+			  struct nvkm_object **);
+void _nvkm_output_dp_dtor(struct nvkm_object *);
+int  _nvkm_output_dp_init(struct nvkm_object *);
+int  _nvkm_output_dp_fini(struct nvkm_object *, bool);
+
+struct nvkm_output_dp_impl {
+	struct nvkm_output_impl base;
+	int (*pattern)(struct nvkm_output_dp *, int);
+	int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
+	int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
+	int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
+};
+
+int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
new file mode 100644
index 0000000..2a1d887
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <subdev/i2c.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/******************************************************************************
+ * TMDS
+ *****************************************************************************/
+
+static int
+nv50_pior_tmds_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *info, u32 index,
+		    struct nvkm_object **pobject)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvkm_output *outp;
+	int ret;
+
+	ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
+	*pobject = nv_object(outp);
+	if (ret)
+		return ret;
+
+	outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
+	return 0;
+}
+
+struct nvkm_output_impl
+nv50_pior_tmds_impl = {
+	.base.handle = DCB_OUTPUT_TMDS | 0x0100,
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_pior_tmds_ctor,
+		.dtor = _nvkm_output_dtor,
+		.init = _nvkm_output_init,
+		.fini = _nvkm_output_fini,
+	},
+};
+
+/******************************************************************************
+ * DisplayPort
+ *****************************************************************************/
+
+static int
+nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+	struct nvkm_i2c_port *port = outp->base.edid;
+	if (port && port->func->pattern)
+		return port->func->pattern(port, pattern);
+	return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+	return 0;
+}
+
+static int
+nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+	struct nvkm_i2c_port *port = outp->base.edid;
+	if (port && port->func->lnk_ctl)
+		return port->func->lnk_ctl(port, nr, bw, ef);
+	return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+{
+	struct nvkm_i2c_port *port = outp->base.edid;
+	if (port && port->func->drv_ctl)
+		return port->func->drv_ctl(port, ln, vs, pe);
+	return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_ctor(struct nvkm_object *parent,
+		  struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *info, u32 index,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvkm_output_dp *outp;
+	int ret;
+
+	ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
+	*pobject = nv_object(outp);
+	if (ret)
+		return ret;
+
+	outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
+					 outp->base.info.extdev));
+	return 0;
+}
+
+struct nvkm_output_dp_impl
+nv50_pior_dp_impl = {
+	.base.base.handle = DCB_OUTPUT_DP | 0x0010,
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_pior_dp_ctor,
+		.dtor = _nvkm_output_dp_dtor,
+		.init = _nvkm_output_dp_init,
+		.fini = _nvkm_output_dp_fini,
+	},
+	.pattern = nv50_pior_dp_pattern,
+	.lnk_pwr = nv50_pior_dp_lnk_pwr,
+	.lnk_ctl = nv50_pior_dp_lnk_ctl,
+	.drv_ctl = nv50_pior_dp_drv_ctl,
+};
+
+/******************************************************************************
+ * General PIOR handling
+ *****************************************************************************/
+
+int
+nv50_pior_power(NV50_DISP_MTHD_V1)
+{
+	const u32 soff = outp->or * 0x800;
+	union {
+		struct nv50_disp_pior_pwr_v0 v0;
+	} *args = data;
+	u32 ctrl, type;
+	int ret;
+
+	nv_ioctl(object, "disp pior pwr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
+			 args->v0.version, args->v0.state, args->v0.type);
+		if (args->v0.type > 0x0f)
+			return -EINVAL;
+		ctrl = !!args->v0.state;
+		type = args->v0.type;
+	} else
+		return ret;
+
+	nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
+	nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
+	nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
+	priv->pior.type[outp->or] = type;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
new file mode 100644
index 0000000..961ce8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -0,0 +1,42 @@
+#ifndef __NVKM_DISP_PRIV_H__
+#define __NVKM_DISP_PRIV_H__
+#include <engine/disp.h>
+
+struct nvkm_disp_impl {
+	struct nvkm_oclass base;
+	struct nvkm_oclass **outp;
+	struct nvkm_oclass **conn;
+	const struct nvkm_event_func *vblank;
+};
+
+#define nvkm_disp_create(p,e,c,h,i,x,d)                                     \
+	nvkm_disp_create_((p), (e), (c), (h), (i), (x),                     \
+			     sizeof(**d), (void **)d)
+#define nvkm_disp_destroy(d) ({                                             \
+	struct nvkm_disp *disp = (d);                                       \
+	_nvkm_disp_dtor(nv_object(disp));                                   \
+})
+#define nvkm_disp_init(d) ({                                                \
+	struct nvkm_disp *disp = (d);                                       \
+	_nvkm_disp_init(nv_object(disp));                                   \
+})
+#define nvkm_disp_fini(d,s) ({                                              \
+	struct nvkm_disp *disp = (d);                                       \
+	_nvkm_disp_fini(nv_object(disp), (s));                              \
+})
+
+int  nvkm_disp_create_(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, int heads,
+			  const char *, const char *, int, void **);
+void _nvkm_disp_dtor(struct nvkm_object *);
+int  _nvkm_disp_init(struct nvkm_object *);
+int  _nvkm_disp_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass *nvkm_output_oclass;
+extern struct nvkm_oclass *nvkm_connector_oclass;
+
+int  nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size,
+			   struct nvkm_notify *);
+void nvkm_disp_vblank(struct nvkm_disp *, int head);
+int  nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
new file mode 100644
index 0000000..8918da7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <core/device.h>
+#include <subdev/timer.h>
+
+static inline u32
+g94_sor_soff(struct nvkm_output_dp *outp)
+{
+	return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+g94_sor_loff(struct nvkm_output_dp *outp)
+{
+	return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+static inline u32
+g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+	static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
+	static const u8 g94[] = { 16, 8, 0, 24 };
+	if (nv_device(priv)->chipset == 0xaf)
+		return mcp89[lane];
+	return g94[lane];
+}
+
+static int
+g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 loff = g94_sor_loff(outp);
+	nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
+	return 0;
+}
+
+int
+g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = g94_sor_soff(outp);
+	const u32 loff = g94_sor_loff(outp);
+	u32 mask = 0, i;
+
+	for (i = 0; i < nr; i++)
+		mask |= 1 << (g94_sor_dp_lane_map(priv, i) >> 3);
+
+	nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
+	nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
+	nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
+	return 0;
+}
+
+static int
+g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = g94_sor_soff(outp);
+	const u32 loff = g94_sor_loff(outp);
+	u32 dpctrl = 0x00000000;
+	u32 clksor = 0x00000000;
+
+	dpctrl |= ((1 << nr) - 1) << 16;
+	if (ef)
+		dpctrl |= 0x00004000;
+	if (bw > 0x06)
+		clksor |= 0x00040000;
+
+	nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
+	nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
+	return 0;
+}
+
+static int
+g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	const u32 shift = g94_sor_dp_lane_map(priv, ln);
+	const u32 loff = g94_sor_loff(outp);
+	u32 addr, data[3];
+	u8  ver, hdr, cnt, len;
+	struct nvbios_dpout info;
+	struct nvbios_dpcfg ocfg;
+
+	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+					outp->base.info.hashm,
+				 &ver, &hdr, &cnt, &len, &info);
+	if (!addr)
+		return -ENODEV;
+
+	addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
+				 &ver, &hdr, &cnt, &len, &ocfg);
+	if (!addr)
+		return -EINVAL;
+
+	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+	data[2] = nv_rd32(priv, 0x61c130 + loff);
+	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+	return 0;
+}
+
+struct nvkm_output_dp_impl
+g94_sor_dp_impl = {
+	.base.base.handle = DCB_OUTPUT_DP,
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_output_dp_ctor,
+		.dtor = _nvkm_output_dp_dtor,
+		.init = _nvkm_output_dp_init,
+		.fini = _nvkm_output_dp_fini,
+	},
+	.pattern = g94_sor_dp_pattern,
+	.lnk_pwr = g94_sor_dp_lnk_pwr,
+	.lnk_ctl = g94_sor_dp_lnk_ctl,
+	.drv_ctl = g94_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c
new file mode 100644
index 0000000..52fbe48
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+static inline u32
+gf110_sor_soff(struct nvkm_output_dp *outp)
+{
+	return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+gf110_sor_loff(struct nvkm_output_dp *outp)
+{
+	return gf110_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+static inline u32
+gf110_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+	static const u8 gf110[] = { 16, 8, 0, 24 };
+	return gf110[lane];
+}
+
+static int
+gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 loff = gf110_sor_loff(outp);
+	nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+	return 0;
+}
+
+int
+gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = gf110_sor_soff(outp);
+	const u32 loff = gf110_sor_loff(outp);
+	u32 dpctrl = 0x00000000;
+	u32 clksor = 0x00000000;
+
+	clksor |= bw << 18;
+	dpctrl |= ((1 << nr) - 1) << 16;
+	if (ef)
+		dpctrl |= 0x00004000;
+
+	nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
+	nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
+	return 0;
+}
+
+static int
+gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
+		     int ln, int vs, int pe, int pc)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	const u32 shift = gf110_sor_dp_lane_map(priv, ln);
+	const u32 loff = gf110_sor_loff(outp);
+	u32 addr, data[4];
+	u8  ver, hdr, cnt, len;
+	struct nvbios_dpout info;
+	struct nvbios_dpcfg ocfg;
+
+	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+					outp->base.info.hashm,
+				  &ver, &hdr, &cnt, &len, &info);
+	if (!addr)
+		return -ENODEV;
+
+	addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
+				  &ver, &hdr, &cnt, &len, &ocfg);
+	if (!addr)
+		return -EINVAL;
+
+	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+	data[2] = nv_rd32(priv, 0x61c130 + loff);
+	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+	data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
+	nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
+	return 0;
+}
+
+struct nvkm_output_dp_impl
+gf110_sor_dp_impl = {
+	.base.base.handle = DCB_OUTPUT_DP,
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_output_dp_ctor,
+		.dtor = _nvkm_output_dp_dtor,
+		.init = _nvkm_output_dp_init,
+		.fini = _nvkm_output_dp_fini,
+	},
+	.pattern = gf110_sor_dp_pattern,
+	.lnk_pwr = g94_sor_dp_lnk_pwr,
+	.lnk_ctl = gf110_sor_dp_lnk_ctl,
+	.drv_ctl = gf110_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c
new file mode 100644
index 0000000..1e40dfe
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <subdev/timer.h>
+
+static inline u32
+gm204_sor_soff(struct nvkm_output_dp *outp)
+{
+	return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+gm204_sor_loff(struct nvkm_output_dp *outp)
+{
+	return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+void
+gm204_sor_magic(struct nvkm_output *outp)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = outp->or * 0x100;
+	const u32 data = outp->or + 1;
+	if (outp->info.sorconf.link & 1)
+		nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
+	if (outp->info.sorconf.link & 2)
+		nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
+}
+
+static inline u32
+gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+	return lane * 0x08;
+}
+
+static int
+gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = gm204_sor_soff(outp);
+	const u32 data = 0x01010101 * pattern;
+	if (outp->base.info.sorconf.link & 1)
+		nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
+	else
+		nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
+	return 0;
+}
+
+static int
+gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	const u32 soff = gm204_sor_soff(outp);
+	const u32 loff = gm204_sor_loff(outp);
+	u32 mask = 0, i;
+
+	for (i = 0; i < nr; i++)
+		mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
+
+	nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
+	nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
+	nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
+	return 0;
+}
+
+static int
+gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
+		     int ln, int vs, int pe, int pc)
+{
+	struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	const u32 shift = gm204_sor_dp_lane_map(priv, ln);
+	const u32 loff = gm204_sor_loff(outp);
+	u32 addr, data[4];
+	u8  ver, hdr, cnt, len;
+	struct nvbios_dpout info;
+	struct nvbios_dpcfg ocfg;
+
+	addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+					outp->base.info.hashm,
+				  &ver, &hdr, &cnt, &len, &info);
+	if (!addr)
+		return -ENODEV;
+
+	addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
+				  &ver, &hdr, &cnt, &len, &ocfg);
+	if (!addr)
+		return -EINVAL;
+
+	data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+	data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+	data[2] = nv_rd32(priv, 0x61c130 + loff);
+	if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+		data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+	nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+	nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+	nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+	data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
+	nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
+	return 0;
+}
+
+struct nvkm_output_dp_impl
+gm204_sor_dp_impl = {
+	.base.base.handle = DCB_OUTPUT_DP,
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_output_dp_ctor,
+		.dtor = _nvkm_output_dp_dtor,
+		.init = _nvkm_output_dp_init,
+		.fini = _nvkm_output_dp_fini,
+	},
+	.pattern = gm204_sor_dp_pattern,
+	.lnk_pwr = gm204_sor_dp_lnk_pwr,
+	.lnk_ctl = gf110_sor_dp_lnk_ctl,
+	.drv_ctl = gm204_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
new file mode 100644
index 0000000..b229a31
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+nv50_sor_power(NV50_DISP_MTHD_V1)
+{
+	union {
+		struct nv50_disp_sor_pwr_v0 v0;
+	} *args = data;
+	const u32 soff = outp->or * 0x800;
+	u32 stat;
+	int ret;
+
+	nv_ioctl(object, "disp sor pwr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "disp sor pwr vers %d state %d\n",
+			 args->v0.version, args->v0.state);
+		stat = !!args->v0.state;
+	} else
+		return ret;
+
+	nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
+	nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
+	nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
+	nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c
new file mode 100644
index 0000000..c4622c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/vga.h>
+
+#include <core/device.h>
+
+u8
+nv_rdport(void *obj, int head, u16 port)
+{
+	struct nvkm_device *device = nv_device(obj);
+
+	if (device->card_type >= NV_50)
+		return nv_rd08(obj, 0x601000 + port);
+
+	if (port == 0x03c0 || port == 0x03c1 ||	/* AR */
+	    port == 0x03c2 || port == 0x03da ||	/* INP0 */
+	    port == 0x03d4 || port == 0x03d5)	/* CR */
+		return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
+
+	if (port == 0x03c2 || port == 0x03cc ||	/* MISC */
+	    port == 0x03c4 || port == 0x03c5 ||	/* SR */
+	    port == 0x03ce || port == 0x03cf) {	/* GR */
+		if (device->card_type < NV_40)
+			head = 0; /* CR44 selects head */
+		return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
+	}
+
+	nv_error(obj, "unknown vga port 0x%04x\n", port);
+	return 0x00;
+}
+
+void
+nv_wrport(void *obj, int head, u16 port, u8 data)
+{
+	struct nvkm_device *device = nv_device(obj);
+
+	if (device->card_type >= NV_50)
+		nv_wr08(obj, 0x601000 + port, data);
+	else
+	if (port == 0x03c0 || port == 0x03c1 ||	/* AR */
+	    port == 0x03c2 || port == 0x03da ||	/* INP0 */
+	    port == 0x03d4 || port == 0x03d5)	/* CR */
+		nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
+	else
+	if (port == 0x03c2 || port == 0x03cc ||	/* MISC */
+	    port == 0x03c4 || port == 0x03c5 ||	/* SR */
+	    port == 0x03ce || port == 0x03cf) {	/* GR */
+		if (device->card_type < NV_40)
+			head = 0; /* CR44 selects head */
+		nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
+	} else
+		nv_error(obj, "unknown vga port 0x%04x\n", port);
+}
+
+u8
+nv_rdvgas(void *obj, int head, u8 index)
+{
+	nv_wrport(obj, head, 0x03c4, index);
+	return nv_rdport(obj, head, 0x03c5);
+}
+
+void
+nv_wrvgas(void *obj, int head, u8 index, u8 value)
+{
+	nv_wrport(obj, head, 0x03c4, index);
+	nv_wrport(obj, head, 0x03c5, value);
+}
+
+u8
+nv_rdvgag(void *obj, int head, u8 index)
+{
+	nv_wrport(obj, head, 0x03ce, index);
+	return nv_rdport(obj, head, 0x03cf);
+}
+
+void
+nv_wrvgag(void *obj, int head, u8 index, u8 value)
+{
+	nv_wrport(obj, head, 0x03ce, index);
+	nv_wrport(obj, head, 0x03cf, value);
+}
+
+u8
+nv_rdvgac(void *obj, int head, u8 index)
+{
+	nv_wrport(obj, head, 0x03d4, index);
+	return nv_rdport(obj, head, 0x03d5);
+}
+
+void
+nv_wrvgac(void *obj, int head, u8 index, u8 value)
+{
+	nv_wrport(obj, head, 0x03d4, index);
+	nv_wrport(obj, head, 0x03d5, value);
+}
+
+u8
+nv_rdvgai(void *obj, int head, u16 port, u8 index)
+{
+	if (port == 0x03c4) return nv_rdvgas(obj, head, index);
+	if (port == 0x03ce) return nv_rdvgag(obj, head, index);
+	if (port == 0x03d4) return nv_rdvgac(obj, head, index);
+	nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+	return 0x00;
+}
+
+void
+nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
+{
+	if      (port == 0x03c4) nv_wrvgas(obj, head, index, value);
+	else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
+	else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
+	else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+}
+
+bool
+nv_lockvgac(void *obj, bool lock)
+{
+	struct nvkm_device *dev = nv_device(obj);
+
+	bool locked = !nv_rdvgac(obj, 0, 0x1f);
+	u8 data = lock ? 0x99 : 0x57;
+	if (dev->card_type < NV_50)
+		nv_wrvgac(obj, 0, 0x1f, data);
+	else
+		nv_wrvgac(obj, 0, 0x3f, data);
+	if (dev->chipset == 0x11) {
+		if (!(nv_rd32(obj, 0x001084) & 0x10000000))
+			nv_wrvgac(obj, 1, 0x1f, data);
+	}
+	return locked;
+}
+
+/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
+ * it affects only the 8 bit vga io regs, which we access using mmio at
+ * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
+ * in general, the set value of cr44 does not matter: reg access works as
+ * expected and values can be set for the appropriate head by using a 0x2000
+ * offset as required
+ * however:
+ * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
+ *    cr44 must be set to 0 or 3 for accessing values on the correct head
+ *    through the common 0xc03c* addresses
+ * b) in tied mode (4) head B is programmed to the values set on head A, and
+ *    access using the head B addresses can have strange results, ergo we leave
+ *    tied mode in init once we know to what cr44 should be restored on exit
+ *
+ * the owner parameter is slightly abused:
+ * 0 and 1 are treated as head values and so the set value is (owner * 3)
+ * other values are treated as literal values to set
+ */
+u8
+nv_rdvgaowner(void *obj)
+{
+	if (nv_device(obj)->card_type < NV_50) {
+		if (nv_device(obj)->chipset == 0x11) {
+			u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
+			if (tied == 0) {
+				u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
+				u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
+				u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
+				u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
+				if (slA && !tvA) return 0x00;
+				if (slB && !tvB) return 0x03;
+				if (slA) return 0x00;
+				if (slB) return 0x03;
+				return 0x00;
+			}
+			return 0x04;
+		}
+
+		return nv_rdvgac(obj, 0, 0x44);
+	}
+
+	nv_error(obj, "rdvgaowner after nv4x\n");
+	return 0x00;
+}
+
+void
+nv_wrvgaowner(void *obj, u8 select)
+{
+	if (nv_device(obj)->card_type < NV_50) {
+		u8 owner = (select == 1) ? 3 : select;
+		if (nv_device(obj)->chipset == 0x11) {
+			/* workaround hw lockup bug */
+			nv_rdvgac(obj, 0, 0x1f);
+			nv_rdvgac(obj, 1, 0x1f);
+		}
+
+		nv_wrvgac(obj, 0, 0x44, owner);
+
+		if (nv_device(obj)->chipset == 0x11) {
+			nv_wrvgac(obj, 0, 0x2e, owner);
+			nv_wrvgac(obj, 0, 0x2e, owner);
+		}
+	} else
+		nv_error(obj, "wrvgaowner after nv4x\n");
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild
new file mode 100644
index 0000000..7529632
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild
@@ -0,0 +1,5 @@
+nvkm-y += nvkm/engine/dmaobj/base.o
+nvkm-y += nvkm/engine/dmaobj/nv04.o
+nvkm-y += nvkm/engine/dmaobj/nv50.o
+nvkm-y += nvkm/engine/dmaobj/gf100.o
+nvkm-y += nvkm/engine/dmaobj/gf110.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c
new file mode 100644
index 0000000..a2b60d8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		 struct nvkm_gpuobj **pgpuobj)
+{
+	const struct nvkm_dmaeng_impl *impl = (void *)
+		nv_oclass(nv_object(dmaobj)->engine);
+	int ret = 0;
+
+	if (nv_object(dmaobj) == parent) { /* ctor bind */
+		if (nv_mclass(parent->parent) == NV_DEVICE) {
+			/* delayed, or no, binding */
+			return 0;
+		}
+		ret = impl->bind(dmaobj, parent, pgpuobj);
+		if (ret == 0)
+			nvkm_object_ref(NULL, &parent);
+		return ret;
+	}
+
+	return impl->bind(dmaobj, parent, pgpuobj);
+}
+
+int
+nvkm_dmaobj_create_(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void **pdata, u32 *psize,
+		    int length, void **pobject)
+{
+	union {
+		struct nv_dma_v0 v0;
+	} *args = *pdata;
+	struct nvkm_instmem *instmem = nvkm_instmem(parent);
+	struct nvkm_client *client = nvkm_client(parent);
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_dmaobj *dmaobj;
+	void *data = *pdata;
+	u32 size = *psize;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+	dmaobj = *pobject;
+	if (ret)
+		return ret;
+
+	nv_ioctl(parent, "create dma size %d\n", *psize);
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		nv_ioctl(parent, "create dma vers %d target %d access %d "
+				 "start %016llx limit %016llx\n",
+			 args->v0.version, args->v0.target, args->v0.access,
+			 args->v0.start, args->v0.limit);
+		dmaobj->target = args->v0.target;
+		dmaobj->access = args->v0.access;
+		dmaobj->start  = args->v0.start;
+		dmaobj->limit  = args->v0.limit;
+	} else
+		return ret;
+
+	*pdata = data;
+	*psize = size;
+
+	if (dmaobj->start > dmaobj->limit)
+		return -EINVAL;
+
+	switch (dmaobj->target) {
+	case NV_DMA_V0_TARGET_VM:
+		dmaobj->target = NV_MEM_TARGET_VM;
+		break;
+	case NV_DMA_V0_TARGET_VRAM:
+		if (!client->super) {
+			if (dmaobj->limit >= pfb->ram->size - instmem->reserved)
+				return -EACCES;
+			if (device->card_type >= NV_50)
+				return -EACCES;
+		}
+		dmaobj->target = NV_MEM_TARGET_VRAM;
+		break;
+	case NV_DMA_V0_TARGET_PCI:
+		if (!client->super)
+			return -EACCES;
+		dmaobj->target = NV_MEM_TARGET_PCI;
+		break;
+	case NV_DMA_V0_TARGET_PCI_US:
+	case NV_DMA_V0_TARGET_AGP:
+		if (!client->super)
+			return -EACCES;
+		dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (dmaobj->access) {
+	case NV_DMA_V0_ACCESS_VM:
+		dmaobj->access = NV_MEM_ACCESS_VM;
+		break;
+	case NV_DMA_V0_ACCESS_RD:
+		dmaobj->access = NV_MEM_ACCESS_RO;
+		break;
+	case NV_DMA_V0_ACCESS_WR:
+		dmaobj->access = NV_MEM_ACCESS_WO;
+		break;
+	case NV_DMA_V0_ACCESS_RDWR:
+		dmaobj->access = NV_MEM_ACCESS_RW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int
+_nvkm_dmaeng_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	const struct nvkm_dmaeng_impl *impl = (void *)oclass;
+	struct nvkm_dmaeng *dmaeng;
+	int ret;
+
+	ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ",
+				 "dmaobj", &dmaeng);
+	*pobject = nv_object(dmaeng);
+	if (ret)
+		return ret;
+
+	nv_engine(dmaeng)->sclass = impl->sclass;
+	dmaeng->bind = nvkm_dmaobj_bind;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c
new file mode 100644
index 0000000..f880e51
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf100_dmaobj_priv {
+	struct nvkm_dmaobj base;
+	u32 flags0;
+	u32 flags5;
+};
+
+static int
+gf100_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		  struct nvkm_gpuobj **pgpuobj)
+{
+	struct gf100_dmaobj_priv *priv = (void *)dmaobj;
+	int ret;
+
+	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+		switch (nv_mclass(parent->parent)) {
+		case GT214_DISP_CORE_CHANNEL_DMA:
+		case GT214_DISP_BASE_CHANNEL_DMA:
+		case GT214_DISP_OVERLAY_CHANNEL_DMA:
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else
+		return 0;
+
+	ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
+		nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
+		nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
+		nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
+					upper_32_bits(priv->base.start));
+		nv_wo32(*pgpuobj, 0x10, 0x00000000);
+		nv_wo32(*pgpuobj, 0x14, priv->flags5);
+	}
+
+	return ret;
+}
+
+static int
+gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_dmaeng *dmaeng = (void *)engine;
+	union {
+		struct gf100_dma_v0 v0;
+	} *args;
+	struct gf100_dmaobj_priv *priv;
+	u32 kind, user, unkn;
+	int ret;
+
+	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+	args = data;
+
+	nv_ioctl(parent, "create gf100 dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n",
+			 args->v0.version, args->v0.priv, args->v0.kind);
+		kind = args->v0.kind;
+		user = args->v0.priv;
+		unkn = 0;
+	} else
+	if (size == 0) {
+		if (priv->base.target != NV_MEM_TARGET_VM) {
+			kind = GF100_DMA_V0_KIND_PITCH;
+			user = GF100_DMA_V0_PRIV_US;
+			unkn = 2;
+		} else {
+			kind = GF100_DMA_V0_KIND_VM;
+			user = GF100_DMA_V0_PRIV_VM;
+			unkn = 0;
+		}
+	} else
+		return ret;
+
+	if (user > 2)
+		return -EINVAL;
+	priv->flags0 |= (kind << 22) | (user << 20);
+	priv->flags5 |= (unkn << 16);
+
+	switch (priv->base.target) {
+	case NV_MEM_TARGET_VM:
+		priv->flags0 |= 0x00000000;
+		break;
+	case NV_MEM_TARGET_VRAM:
+		priv->flags0 |= 0x00010000;
+		break;
+	case NV_MEM_TARGET_PCI:
+		priv->flags0 |= 0x00020000;
+		break;
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		priv->flags0 |= 0x00030000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (priv->base.access) {
+	case NV_MEM_ACCESS_VM:
+		break;
+	case NV_MEM_ACCESS_RO:
+		priv->flags0 |= 0x00040000;
+		break;
+	case NV_MEM_ACCESS_WO:
+	case NV_MEM_ACCESS_RW:
+		priv->flags0 |= 0x00080000;
+		break;
+	}
+
+	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+gf100_dmaobj_ofuncs = {
+	.ctor =  gf100_dmaobj_ctor,
+	.dtor = _nvkm_dmaobj_dtor,
+	.init = _nvkm_dmaobj_init,
+	.fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+gf100_dmaeng_sclass[] = {
+	{ NV_DMA_FROM_MEMORY, &gf100_dmaobj_ofuncs },
+	{ NV_DMA_TO_MEMORY, &gf100_dmaobj_ofuncs },
+	{ NV_DMA_IN_MEMORY, &gf100_dmaobj_ofuncs },
+	{}
+};
+
+struct nvkm_oclass *
+gf100_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+	.base.handle = NV_ENGINE(DMAOBJ, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_dmaeng_ctor,
+		.dtor = _nvkm_dmaeng_dtor,
+		.init = _nvkm_dmaeng_init,
+		.fini = _nvkm_dmaeng_fini,
+	},
+	.sclass = gf100_dmaeng_sclass,
+	.bind = gf100_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c
new file mode 100644
index 0000000..bf8f0f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf110_dmaobj_priv {
+	struct nvkm_dmaobj base;
+	u32 flags0;
+};
+
+static int
+gf110_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		  struct nvkm_gpuobj **pgpuobj)
+{
+	struct gf110_dmaobj_priv *priv = (void *)dmaobj;
+	int ret;
+
+	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+		switch (nv_mclass(parent->parent)) {
+		case GF110_DISP_CORE_CHANNEL_DMA:
+		case GK104_DISP_CORE_CHANNEL_DMA:
+		case GK110_DISP_CORE_CHANNEL_DMA:
+		case GM107_DISP_CORE_CHANNEL_DMA:
+		case GM204_DISP_CORE_CHANNEL_DMA:
+		case GF110_DISP_BASE_CHANNEL_DMA:
+		case GK104_DISP_BASE_CHANNEL_DMA:
+		case GK110_DISP_BASE_CHANNEL_DMA:
+		case GF110_DISP_OVERLAY_CONTROL_DMA:
+		case GK104_DISP_OVERLAY_CONTROL_DMA:
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else
+		return 0;
+
+	ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, priv->flags0);
+		nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
+		nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
+		nv_wo32(*pgpuobj, 0x0c, 0x00000000);
+		nv_wo32(*pgpuobj, 0x10, 0x00000000);
+		nv_wo32(*pgpuobj, 0x14, 0x00000000);
+	}
+
+	return ret;
+}
+
+static int
+gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_dmaeng *dmaeng = (void *)engine;
+	union {
+		struct gf110_dma_v0 v0;
+	} *args;
+	struct gf110_dmaobj_priv *priv;
+	u32 kind, page;
+	int ret;
+
+	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+	args = data;
+
+	nv_ioctl(parent, "create gf110 dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n",
+			 args->v0.version, args->v0.page, args->v0.kind);
+		kind = args->v0.kind;
+		page = args->v0.page;
+	} else
+	if (size == 0) {
+		if (priv->base.target != NV_MEM_TARGET_VM) {
+			kind = GF110_DMA_V0_KIND_PITCH;
+			page = GF110_DMA_V0_PAGE_SP;
+		} else {
+			kind = GF110_DMA_V0_KIND_VM;
+			page = GF110_DMA_V0_PAGE_LP;
+		}
+	} else
+		return ret;
+
+	if (page > 1)
+		return -EINVAL;
+	priv->flags0 = (kind << 20) | (page << 6);
+
+	switch (priv->base.target) {
+	case NV_MEM_TARGET_VRAM:
+		priv->flags0 |= 0x00000009;
+		break;
+	case NV_MEM_TARGET_VM:
+	case NV_MEM_TARGET_PCI:
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		/* XXX: don't currently know how to construct a real one
+		 *      of these.  we only use them to represent pushbufs
+		 *      on these chipsets, and the classes that use them
+		 *      deal with the target themselves.
+		 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+gf110_dmaobj_ofuncs = {
+	.ctor =  gf110_dmaobj_ctor,
+	.dtor = _nvkm_dmaobj_dtor,
+	.init = _nvkm_dmaobj_init,
+	.fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+gf110_dmaeng_sclass[] = {
+	{ NV_DMA_FROM_MEMORY, &gf110_dmaobj_ofuncs },
+	{ NV_DMA_TO_MEMORY, &gf110_dmaobj_ofuncs },
+	{ NV_DMA_IN_MEMORY, &gf110_dmaobj_ofuncs },
+	{}
+};
+
+struct nvkm_oclass *
+gf110_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+	.base.handle = NV_ENGINE(DMAOBJ, 0xd0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_dmaeng_ctor,
+		.dtor = _nvkm_dmaeng_dtor,
+		.init = _nvkm_dmaeng_init,
+		.fini = _nvkm_dmaeng_fini,
+	},
+	.sclass = gf110_dmaeng_sclass,
+	.bind = gf110_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c
new file mode 100644
index 0000000..b4379c2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu/nv04.h>
+
+#include <nvif/class.h>
+
+struct nv04_dmaobj_priv {
+	struct nvkm_dmaobj base;
+	bool clone;
+	u32 flags0;
+	u32 flags2;
+};
+
+static int
+nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		 struct nvkm_gpuobj **pgpuobj)
+{
+	struct nv04_dmaobj_priv *priv = (void *)dmaobj;
+	struct nvkm_gpuobj *gpuobj;
+	u64 offset = priv->base.start & 0xfffff000;
+	u64 adjust = priv->base.start & 0x00000fff;
+	u32 length = priv->base.limit - priv->base.start;
+	int ret;
+
+	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+		switch (nv_mclass(parent->parent)) {
+		case NV03_CHANNEL_DMA:
+		case NV10_CHANNEL_DMA:
+		case NV17_CHANNEL_DMA:
+		case NV40_CHANNEL_DMA:
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (priv->clone) {
+		struct nv04_mmu_priv *mmu = nv04_mmu(dmaobj);
+		struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0];
+		if (!dmaobj->start)
+			return nvkm_gpuobj_dup(parent, pgt, pgpuobj);
+		offset  = nv_ro32(pgt, 8 + (offset >> 10));
+		offset &= 0xfffff000;
+	}
+
+	ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
+	*pgpuobj = gpuobj;
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
+		nv_wo32(*pgpuobj, 0x04, length);
+		nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
+		nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
+	}
+
+	return ret;
+}
+
+static int
+nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct nvkm_dmaeng *dmaeng = (void *)engine;
+	struct nv04_mmu_priv *mmu = nv04_mmu(engine);
+	struct nv04_dmaobj_priv *priv;
+	int ret;
+
+	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+	*pobject = nv_object(priv);
+	if (ret || (ret = -ENOSYS, size))
+		return ret;
+
+	if (priv->base.target == NV_MEM_TARGET_VM) {
+		if (nv_object(mmu)->oclass == &nv04_mmu_oclass)
+			priv->clone = true;
+		priv->base.target = NV_MEM_TARGET_PCI;
+		priv->base.access = NV_MEM_ACCESS_RW;
+	}
+
+	priv->flags0 = nv_mclass(priv);
+	switch (priv->base.target) {
+	case NV_MEM_TARGET_VRAM:
+		priv->flags0 |= 0x00003000;
+		break;
+	case NV_MEM_TARGET_PCI:
+		priv->flags0 |= 0x00023000;
+		break;
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		priv->flags0 |= 0x00033000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (priv->base.access) {
+	case NV_MEM_ACCESS_RO:
+		priv->flags0 |= 0x00004000;
+		break;
+	case NV_MEM_ACCESS_WO:
+		priv->flags0 |= 0x00008000;
+	case NV_MEM_ACCESS_RW:
+		priv->flags2 |= 0x00000002;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+nv04_dmaobj_ofuncs = {
+	.ctor =  nv04_dmaobj_ctor,
+	.dtor = _nvkm_dmaobj_dtor,
+	.init = _nvkm_dmaobj_init,
+	.fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+nv04_dmaeng_sclass[] = {
+	{ NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs },
+	{ NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs },
+	{ NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs },
+	{}
+};
+
+struct nvkm_oclass *
+nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+	.base.handle = NV_ENGINE(DMAOBJ, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_dmaeng_ctor,
+		.dtor = _nvkm_dmaeng_dtor,
+		.init = _nvkm_dmaeng_init,
+		.fini = _nvkm_dmaeng_fini,
+	},
+	.sclass = nv04_dmaeng_sclass,
+	.bind = nv04_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c
new file mode 100644
index 0000000..4d3c828
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct nv50_dmaobj_priv {
+	struct nvkm_dmaobj base;
+	u32 flags0;
+	u32 flags5;
+};
+
+static int
+nv50_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+		 struct nvkm_gpuobj **pgpuobj)
+{
+	struct nv50_dmaobj_priv *priv = (void *)dmaobj;
+	int ret;
+
+	if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+		switch (nv_mclass(parent->parent)) {
+		case NV40_CHANNEL_DMA:
+		case NV50_CHANNEL_GPFIFO:
+		case G82_CHANNEL_GPFIFO:
+		case NV50_DISP_CORE_CHANNEL_DMA:
+		case G82_DISP_CORE_CHANNEL_DMA:
+		case GT206_DISP_CORE_CHANNEL_DMA:
+		case GT200_DISP_CORE_CHANNEL_DMA:
+		case GT214_DISP_CORE_CHANNEL_DMA:
+		case NV50_DISP_BASE_CHANNEL_DMA:
+		case G82_DISP_BASE_CHANNEL_DMA:
+		case GT200_DISP_BASE_CHANNEL_DMA:
+		case GT214_DISP_BASE_CHANNEL_DMA:
+		case NV50_DISP_OVERLAY_CHANNEL_DMA:
+		case G82_DISP_OVERLAY_CHANNEL_DMA:
+		case GT200_DISP_OVERLAY_CHANNEL_DMA:
+		case GT214_DISP_OVERLAY_CHANNEL_DMA:
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+	if (ret == 0) {
+		nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
+		nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
+		nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
+		nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
+					upper_32_bits(priv->base.start));
+		nv_wo32(*pgpuobj, 0x10, 0x00000000);
+		nv_wo32(*pgpuobj, 0x14, priv->flags5);
+	}
+
+	return ret;
+}
+
+static int
+nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct nvkm_dmaeng *dmaeng = (void *)engine;
+	union {
+		struct nv50_dma_v0 v0;
+	} *args;
+	struct nv50_dmaobj_priv *priv;
+	u32 user, part, comp, kind;
+	int ret;
+
+	ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+	args = data;
+
+	nv_ioctl(parent, "create nv50 dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
+				 "comp %d kind %02x\n", args->v0.version,
+			 args->v0.priv, args->v0.part, args->v0.comp,
+			 args->v0.kind);
+		user = args->v0.priv;
+		part = args->v0.part;
+		comp = args->v0.comp;
+		kind = args->v0.kind;
+	} else
+	if (size == 0) {
+		if (priv->base.target != NV_MEM_TARGET_VM) {
+			user = NV50_DMA_V0_PRIV_US;
+			part = NV50_DMA_V0_PART_256;
+			comp = NV50_DMA_V0_COMP_NONE;
+			kind = NV50_DMA_V0_KIND_PITCH;
+		} else {
+			user = NV50_DMA_V0_PRIV_VM;
+			part = NV50_DMA_V0_PART_VM;
+			comp = NV50_DMA_V0_COMP_VM;
+			kind = NV50_DMA_V0_KIND_VM;
+		}
+	} else
+		return ret;
+
+	if (user > 2 || part > 2 || comp > 3 || kind > 0x7f)
+		return -EINVAL;
+	priv->flags0 = (comp << 29) | (kind << 22) | (user << 20);
+	priv->flags5 = (part << 16);
+
+	switch (priv->base.target) {
+	case NV_MEM_TARGET_VM:
+		priv->flags0 |= 0x00000000;
+		break;
+	case NV_MEM_TARGET_VRAM:
+		priv->flags0 |= 0x00010000;
+		break;
+	case NV_MEM_TARGET_PCI:
+		priv->flags0 |= 0x00020000;
+		break;
+	case NV_MEM_TARGET_PCI_NOSNOOP:
+		priv->flags0 |= 0x00030000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (priv->base.access) {
+	case NV_MEM_ACCESS_VM:
+		break;
+	case NV_MEM_ACCESS_RO:
+		priv->flags0 |= 0x00040000;
+		break;
+	case NV_MEM_ACCESS_WO:
+	case NV_MEM_ACCESS_RW:
+		priv->flags0 |= 0x00080000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+nv50_dmaobj_ofuncs = {
+	.ctor =  nv50_dmaobj_ctor,
+	.dtor = _nvkm_dmaobj_dtor,
+	.init = _nvkm_dmaobj_init,
+	.fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+nv50_dmaeng_sclass[] = {
+	{ NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs },
+	{ NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs },
+	{ NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs },
+	{}
+};
+
+struct nvkm_oclass *
+nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+	.base.handle = NV_ENGINE(DMAOBJ, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_dmaeng_ctor,
+		.dtor = _nvkm_dmaeng_dtor,
+		.init = _nvkm_dmaeng_init,
+		.fini = _nvkm_dmaeng_fini,
+	},
+	.sclass = nv50_dmaeng_sclass,
+	.bind = nv50_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h
new file mode 100644
index 0000000..44ae8a0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_DMAOBJ_PRIV_H__
+#define __NVKM_DMAOBJ_PRIV_H__
+#include <engine/dmaobj.h>
+
+#define nvkm_dmaobj_create(p,e,c,pa,sa,d)                                      \
+	nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
+
+int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void **, u32 *,
+			int, void **);
+#define _nvkm_dmaobj_dtor nvkm_object_destroy
+#define _nvkm_dmaobj_init nvkm_object_init
+#define _nvkm_dmaobj_fini nvkm_object_fini
+
+int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, void *, u32,
+		      struct nvkm_object **);
+#define _nvkm_dmaeng_dtor _nvkm_engine_dtor
+#define _nvkm_dmaeng_init _nvkm_engine_init
+#define _nvkm_dmaeng_fini _nvkm_engine_fini
+
+struct nvkm_dmaeng_impl {
+	struct nvkm_oclass base;
+	struct nvkm_oclass *sclass;
+	int (*bind)(struct nvkm_dmaobj *, struct nvkm_object *,
+		    struct nvkm_gpuobj **);
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
new file mode 100644
index 0000000..30958c1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2012 Red Hat 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 <engine/falcon.h>
+
+#include <core/device.h>
+#include <subdev/timer.h>
+
+void
+nvkm_falcon_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_falcon *falcon = (void *)subdev;
+	u32 dispatch = nv_ro32(falcon, 0x01c);
+	u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+
+	if (intr & 0x00000010) {
+		nv_debug(falcon, "ucode halted\n");
+		nv_wo32(falcon, 0x004, 0x00000010);
+		intr &= ~0x00000010;
+	}
+
+	if (intr)  {
+		nv_error(falcon, "unhandled intr 0x%08x\n", intr);
+		nv_wo32(falcon, 0x004, intr);
+	}
+}
+
+u32
+_nvkm_falcon_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_falcon *falcon = (void *)object;
+	return nv_rd32(falcon, falcon->addr + addr);
+}
+
+void
+_nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_falcon *falcon = (void *)object;
+	nv_wr32(falcon, falcon->addr + addr, data);
+}
+
+static void *
+vmemdup(const void *src, size_t len)
+{
+	void *p = vmalloc(len);
+
+	if (p)
+		memcpy(p, src, len);
+	return p;
+}
+
+int
+_nvkm_falcon_init(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nvkm_falcon *falcon = (void *)object;
+	const struct firmware *fw;
+	char name[32] = "internal";
+	int ret, i;
+	u32 caps;
+
+	/* enable engine, and determine its capabilities */
+	ret = nvkm_engine_init(&falcon->base);
+	if (ret)
+		return ret;
+
+	if (device->chipset <  0xa3 ||
+	    device->chipset == 0xaa || device->chipset == 0xac) {
+		falcon->version = 0;
+		falcon->secret  = (falcon->addr == 0x087000) ? 1 : 0;
+	} else {
+		caps = nv_ro32(falcon, 0x12c);
+		falcon->version = (caps & 0x0000000f);
+		falcon->secret  = (caps & 0x00000030) >> 4;
+	}
+
+	caps = nv_ro32(falcon, 0x108);
+	falcon->code.limit = (caps & 0x000001ff) << 8;
+	falcon->data.limit = (caps & 0x0003fe00) >> 1;
+
+	nv_debug(falcon, "falcon version: %d\n", falcon->version);
+	nv_debug(falcon, "secret level: %d\n", falcon->secret);
+	nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
+	nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
+
+	/* wait for 'uc halted' to be signalled before continuing */
+	if (falcon->secret && falcon->version < 4) {
+		if (!falcon->version)
+			nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+		else
+			nv_wait(falcon, 0x180, 0x80000000, 0);
+		nv_wo32(falcon, 0x004, 0x00000010);
+	}
+
+	/* disable all interrupts */
+	nv_wo32(falcon, 0x014, 0xffffffff);
+
+	/* no default ucode provided by the engine implementation, try and
+	 * locate a "self-bootstrapping" firmware image for the engine
+	 */
+	if (!falcon->code.data) {
+		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
+			 device->chipset, falcon->addr >> 12);
+
+		ret = request_firmware(&fw, name, nv_device_base(device));
+		if (ret == 0) {
+			falcon->code.data = vmemdup(fw->data, fw->size);
+			falcon->code.size = fw->size;
+			falcon->data.data = NULL;
+			falcon->data.size = 0;
+			release_firmware(fw);
+		}
+
+		falcon->external = true;
+	}
+
+	/* next step is to try and load "static code/data segment" firmware
+	 * images for the engine
+	 */
+	if (!falcon->code.data) {
+		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
+			 device->chipset, falcon->addr >> 12);
+
+		ret = request_firmware(&fw, name, nv_device_base(device));
+		if (ret) {
+			nv_error(falcon, "unable to load firmware data\n");
+			return ret;
+		}
+
+		falcon->data.data = vmemdup(fw->data, fw->size);
+		falcon->data.size = fw->size;
+		release_firmware(fw);
+		if (!falcon->data.data)
+			return -ENOMEM;
+
+		snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
+			 device->chipset, falcon->addr >> 12);
+
+		ret = request_firmware(&fw, name, nv_device_base(device));
+		if (ret) {
+			nv_error(falcon, "unable to load firmware code\n");
+			return ret;
+		}
+
+		falcon->code.data = vmemdup(fw->data, fw->size);
+		falcon->code.size = fw->size;
+		release_firmware(fw);
+		if (!falcon->code.data)
+			return -ENOMEM;
+	}
+
+	nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
+		 "static code/data segments" : "self-bootstrapping");
+
+	/* ensure any "self-bootstrapping" firmware image is in vram */
+	if (!falcon->data.data && !falcon->core) {
+		ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size,
+				      256, 0, &falcon->core);
+		if (ret) {
+			nv_error(falcon, "core allocation failed, %d\n", ret);
+			return ret;
+		}
+
+		for (i = 0; i < falcon->code.size; i += 4)
+			nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
+	}
+
+	/* upload firmware bootloader (or the full code segments) */
+	if (falcon->core) {
+		if (device->card_type < NV_C0)
+			nv_wo32(falcon, 0x618, 0x04000000);
+		else
+			nv_wo32(falcon, 0x618, 0x00000114);
+		nv_wo32(falcon, 0x11c, 0);
+		nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
+		nv_wo32(falcon, 0x114, 0);
+		nv_wo32(falcon, 0x118, 0x00006610);
+	} else {
+		if (falcon->code.size > falcon->code.limit ||
+		    falcon->data.size > falcon->data.limit) {
+			nv_error(falcon, "ucode exceeds falcon limit(s)\n");
+			return -EINVAL;
+		}
+
+		if (falcon->version < 3) {
+			nv_wo32(falcon, 0xff8, 0x00100000);
+			for (i = 0; i < falcon->code.size / 4; i++)
+				nv_wo32(falcon, 0xff4, falcon->code.data[i]);
+		} else {
+			nv_wo32(falcon, 0x180, 0x01000000);
+			for (i = 0; i < falcon->code.size / 4; i++) {
+				if ((i & 0x3f) == 0)
+					nv_wo32(falcon, 0x188, i >> 6);
+				nv_wo32(falcon, 0x184, falcon->code.data[i]);
+			}
+		}
+	}
+
+	/* upload data segment (if necessary), zeroing the remainder */
+	if (falcon->version < 3) {
+		nv_wo32(falcon, 0xff8, 0x00000000);
+		for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
+			nv_wo32(falcon, 0xff4, falcon->data.data[i]);
+		for (; i < falcon->data.limit; i += 4)
+			nv_wo32(falcon, 0xff4, 0x00000000);
+	} else {
+		nv_wo32(falcon, 0x1c0, 0x01000000);
+		for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
+			nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
+		for (; i < falcon->data.limit / 4; i++)
+			nv_wo32(falcon, 0x1c4, 0x00000000);
+	}
+
+	/* start it running */
+	nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
+	nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
+	nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
+	nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
+	return 0;
+}
+
+int
+_nvkm_falcon_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_falcon *falcon = (void *)object;
+
+	if (!suspend) {
+		nvkm_gpuobj_ref(NULL, &falcon->core);
+		if (falcon->external) {
+			vfree(falcon->data.data);
+			vfree(falcon->code.data);
+			falcon->code.data = NULL;
+		}
+	}
+
+	nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
+	nv_wo32(falcon, 0x014, 0xffffffff);
+
+	return nvkm_engine_fini(&falcon->base, suspend);
+}
+
+int
+nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 addr, bool enable,
+		    const char *iname, const char *fname,
+		    int length, void **pobject)
+{
+	struct nvkm_falcon *falcon;
+	int ret;
+
+	ret = nvkm_engine_create_(parent, engine, oclass, enable, iname,
+				  fname, length, pobject);
+	falcon = *pobject;
+	if (ret)
+		return ret;
+
+	falcon->addr = addr;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
new file mode 100644
index 0000000..c5a2d87
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
@@ -0,0 +1,11 @@
+nvkm-y += nvkm/engine/fifo/base.o
+nvkm-y += nvkm/engine/fifo/nv04.o
+nvkm-y += nvkm/engine/fifo/nv10.o
+nvkm-y += nvkm/engine/fifo/nv17.o
+nvkm-y += nvkm/engine/fifo/nv40.o
+nvkm-y += nvkm/engine/fifo/nv50.o
+nvkm-y += nvkm/engine/fifo/g84.o
+nvkm-y += nvkm/engine/fifo/gf100.o
+nvkm-y += nvkm/engine/fifo/gk104.o
+nvkm-y += nvkm/engine/fifo/gk20a.o
+nvkm-y += nvkm/engine/fifo/gk208.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
new file mode 100644
index 0000000..fa223f8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/notify.h>
+#include <engine/dmaobj.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size,
+		     struct nvkm_notify *notify)
+{
+	if (size == 0) {
+		notify->size  = 0;
+		notify->types = 1;
+		notify->index = 0;
+		return 0;
+	}
+	return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nvkm_fifo_event_func = {
+	.ctor = nvkm_fifo_event_ctor,
+};
+
+int
+nvkm_fifo_channel_create_(struct nvkm_object *parent,
+			  struct nvkm_object *engine,
+			  struct nvkm_oclass *oclass,
+			  int bar, u32 addr, u32 size, u32 pushbuf,
+			  u64 engmask, int len, void **ptr)
+{
+	struct nvkm_device *device = nv_device(engine);
+	struct nvkm_fifo *priv = (void *)engine;
+	struct nvkm_fifo_chan *chan;
+	struct nvkm_dmaeng *dmaeng;
+	unsigned long flags;
+	int ret;
+
+	/* create base object class */
+	ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
+				  engmask, len, ptr);
+	chan = *ptr;
+	if (ret)
+		return ret;
+
+	/* validate dma object representing push buffer */
+	chan->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
+	if (!chan->pushdma)
+		return -ENOENT;
+
+	dmaeng = (void *)chan->pushdma->base.engine;
+	switch (chan->pushdma->base.oclass->handle) {
+	case NV_DMA_FROM_MEMORY:
+	case NV_DMA_IN_MEMORY:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
+	if (ret)
+		return ret;
+
+	/* find a free fifo channel */
+	spin_lock_irqsave(&priv->lock, flags);
+	for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
+		if (!priv->channel[chan->chid]) {
+			priv->channel[chan->chid] = nv_object(chan);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (chan->chid == priv->max) {
+		nv_error(priv, "no free channels\n");
+		return -ENOSPC;
+	}
+
+	chan->addr = nv_device_resource_start(device, bar) +
+		     addr + size * chan->chid;
+	chan->size = size;
+	nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
+	return 0;
+}
+
+void
+nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan)
+{
+	struct nvkm_fifo *priv = (void *)nv_object(chan)->engine;
+	unsigned long flags;
+
+	if (chan->user)
+		iounmap(chan->user);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->channel[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nvkm_gpuobj_ref(NULL, &chan->pushgpu);
+	nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma);
+	nvkm_namedb_destroy(&chan->namedb);
+}
+
+void
+_nvkm_fifo_channel_dtor(struct nvkm_object *object)
+{
+	struct nvkm_fifo_chan *chan = (void *)object;
+	nvkm_fifo_channel_destroy(chan);
+}
+
+int
+_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+	struct nvkm_fifo_chan *chan = (void *)object;
+	*addr = chan->addr;
+	*size = chan->size;
+	return 0;
+}
+
+u32
+_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_fifo_chan *chan = (void *)object;
+	if (unlikely(!chan->user)) {
+		chan->user = ioremap(chan->addr, chan->size);
+		if (WARN_ON_ONCE(chan->user == NULL))
+			return 0;
+	}
+	return ioread32_native(chan->user + addr);
+}
+
+void
+_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_fifo_chan *chan = (void *)object;
+	if (unlikely(!chan->user)) {
+		chan->user = ioremap(chan->addr, chan->size);
+		if (WARN_ON_ONCE(chan->user == NULL))
+			return;
+	}
+	iowrite32_native(data, chan->user + addr);
+}
+
+int
+nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
+		      struct nvkm_notify *notify)
+{
+	union {
+		struct nvif_notify_uevent_req none;
+	} *req = data;
+	int ret;
+
+	if (nvif_unvers(req->none)) {
+		notify->size  = sizeof(struct nvif_notify_uevent_rep);
+		notify->types = 1;
+		notify->index = 0;
+	}
+
+	return ret;
+}
+
+void
+nvkm_fifo_uevent(struct nvkm_fifo *fifo)
+{
+	struct nvif_notify_uevent_rep rep = {
+	};
+	nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
+}
+
+int
+_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type,
+			struct nvkm_event **event)
+{
+	struct nvkm_fifo *fifo = (void *)object->engine;
+	switch (type) {
+	case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
+		if (nv_mclass(object) >= G82_CHANNEL_DMA) {
+			*event = &fifo->uevent;
+			return 0;
+		}
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int
+nvkm_fifo_chid(struct nvkm_fifo *priv, struct nvkm_object *object)
+{
+	int engidx = nv_hclass(priv) & 0xff;
+
+	while (object && object->parent) {
+		if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
+		    (nv_hclass(object->parent) & 0xff) == engidx)
+			return nvkm_fifo_chan(object)->chid;
+		object = object->parent;
+	}
+
+	return -1;
+}
+
+const char *
+nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid)
+{
+	struct nvkm_fifo_chan *chan = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fifo->lock, flags);
+	if (chid >= fifo->min && chid <= fifo->max)
+		chan = (void *)fifo->channel[chid];
+	spin_unlock_irqrestore(&fifo->lock, flags);
+
+	return nvkm_client_name(chan);
+}
+
+void
+nvkm_fifo_destroy(struct nvkm_fifo *priv)
+{
+	kfree(priv->channel);
+	nvkm_event_fini(&priv->uevent);
+	nvkm_event_fini(&priv->cevent);
+	nvkm_engine_destroy(&priv->base);
+}
+
+int
+nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass,
+		  int min, int max, int length, void **pobject)
+{
+	struct nvkm_fifo *priv;
+	int ret;
+
+	ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO",
+				  "fifo", length, pobject);
+	priv = *pobject;
+	if (ret)
+		return ret;
+
+	priv->min = min;
+	priv->max = max;
+	priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
+	if (!priv->channel)
+		return -ENOMEM;
+
+	ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &priv->cevent);
+	if (ret)
+		return ret;
+
+	priv->chid = nvkm_fifo_chid;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
new file mode 100644
index 0000000..a04920b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nvkm_gpuobj *ectx = (void *)object;
+	u64 limit = ectx->addr + ectx->size - 1;
+	u64 start = ectx->addr;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW    : return 0;
+	case NVDEV_ENGINE_GR    : addr = 0x0020; break;
+	case NVDEV_ENGINE_VP    :
+	case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break;
+	case NVDEV_ENGINE_MSPPP :
+	case NVDEV_ENGINE_MPEG  : addr = 0x0060; break;
+	case NVDEV_ENGINE_BSP   :
+	case NVDEV_ENGINE_MSVLD : addr = 0x0080; break;
+	case NVDEV_ENGINE_CIPHER:
+	case NVDEV_ENGINE_SEC   : addr = 0x00a0; break;
+	case NVDEV_ENGINE_CE0   : addr = 0x00c0; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+	nv_wo32(base->eng, addr + 0x00, 0x00190000);
+	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+					upper_32_bits(start));
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+g84_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+			struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_priv *priv = (void *)parent->engine;
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 addr, save, engn;
+	bool done;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW    : return 0;
+	case NVDEV_ENGINE_GR    : engn = 0; addr = 0x0020; break;
+	case NVDEV_ENGINE_VP    :
+	case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break;
+	case NVDEV_ENGINE_MSPPP :
+	case NVDEV_ENGINE_MPEG  : engn = 1; addr = 0x0060; break;
+	case NVDEV_ENGINE_BSP   :
+	case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break;
+	case NVDEV_ENGINE_CIPHER:
+	case NVDEV_ENGINE_SEC   : engn = 4; addr = 0x00a0; break;
+	case NVDEV_ENGINE_CE0   : engn = 2; addr = 0x00c0; break;
+	default:
+		return -EINVAL;
+	}
+
+	save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
+	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+	done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
+	nv_wr32(priv, 0x002520, save);
+	if (!done) {
+		nv_error(priv, "channel %d [%s] unload timeout\n",
+			 chan->base.chid, nvkm_client_name(chan));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	nv_wo32(base->eng, addr + 0x00, 0x00000000);
+	nv_wo32(base->eng, addr + 0x04, 0x00000000);
+	nv_wo32(base->eng, addr + 0x08, 0x00000000);
+	nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+g84_fifo_object_attach(struct nvkm_object *parent,
+		       struct nvkm_object *object, u32 handle)
+{
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 context;
+
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->node->offset >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
+	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
+	case NVDEV_ENGINE_MPEG  :
+	case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break;
+	case NVDEV_ENGINE_ME    :
+	case NVDEV_ENGINE_CE0   : context |= 0x00300000; break;
+	case NVDEV_ENGINE_VP    :
+	case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break;
+	case NVDEV_ENGINE_CIPHER:
+	case NVDEV_ENGINE_SEC   :
+	case NVDEV_ENGINE_VIC   : context |= 0x00500000; break;
+	case NVDEV_ENGINE_BSP   :
+	case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break;
+	default:
+		return -EINVAL;
+	}
+
+	return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+}
+
+static int
+g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+				       0x2000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG) |
+				       (1ULL << NVDEV_ENGINE_ME) |
+				       (1ULL << NVDEV_ENGINE_VP) |
+				       (1ULL << NVDEV_ENGINE_CIPHER) |
+				       (1ULL << NVDEV_ENGINE_SEC) |
+				       (1ULL << NVDEV_ENGINE_BSP) |
+				       (1ULL << NVDEV_ENGINE_MSVLD) |
+				       (1ULL << NVDEV_ENGINE_MSPDEC) |
+				       (1ULL << NVDEV_ENGINE_MSPPP) |
+				       (1ULL << NVDEV_ENGINE_CE0) |
+				       (1ULL << NVDEV_ENGINE_VIC), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+			     &chan->ramht);
+	if (ret)
+		return ret;
+
+	nv_parent(chan)->context_attach = g84_fifo_context_attach;
+	nv_parent(chan)->context_detach = g84_fifo_context_detach;
+	nv_parent(chan)->object_attach = g84_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x3c, 0x003f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x4c, 0xffffffff);
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+				   (4 << 24) /* SEARCH_FULL */ |
+				   (chan->ramht->gpuobj.node->offset >> 4));
+	nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
+	nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_channel_gpfifo_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	u64 ioffset, ilength;
+	int ret;
+
+	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+				 "ioffset %016llx ilength %08x\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+			 args->v0.ilength);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+				       0x2000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG) |
+				       (1ULL << NVDEV_ENGINE_ME) |
+				       (1ULL << NVDEV_ENGINE_VP) |
+				       (1ULL << NVDEV_ENGINE_CIPHER) |
+				       (1ULL << NVDEV_ENGINE_SEC) |
+				       (1ULL << NVDEV_ENGINE_BSP) |
+				       (1ULL << NVDEV_ENGINE_MSVLD) |
+				       (1ULL << NVDEV_ENGINE_MSPDEC) |
+				       (1ULL << NVDEV_ENGINE_MSPPP) |
+				       (1ULL << NVDEV_ENGINE_CE0) |
+				       (1ULL << NVDEV_ENGINE_VIC), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+			     &chan->ramht);
+	if (ret)
+		return ret;
+
+	nv_parent(chan)->context_attach = g84_fifo_context_attach;
+	nv_parent(chan)->context_detach = g84_fifo_context_detach;
+	nv_parent(chan)->object_attach = g84_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	ioffset = args->v0.ioffset;
+	ilength = order_base_2(args->v0.ilength / 8);
+
+	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+				   (4 << 24) /* SEARCH_FULL */ |
+				   (chan->ramht->gpuobj.node->offset >> 4));
+	nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
+	nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+g84_fifo_chan_init(struct nvkm_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_base *base = (void *)object->parent;
+	struct nv50_fifo_chan *chan = (void *)object;
+	struct nvkm_gpuobj *ramfc = base->ramfc;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nvkm_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
+	nv50_fifo_playlist_update(priv);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+g84_fifo_ofuncs_dma = {
+	.ctor = g84_fifo_chan_ctor_dma,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = g84_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_ofuncs
+g84_fifo_ofuncs_ind = {
+	.ctor = g84_fifo_chan_ctor_ind,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = g84_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+g84_fifo_sclass[] = {
+	{ G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma },
+	{ G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static int
+g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *data, u32 size,
+		      struct nvkm_object **pobject)
+{
+	struct nv50_fifo_base *base;
+	int ret;
+
+	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+				       0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0,
+			      NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0,
+			      0, &base->pgd);
+	if (ret)
+		return ret;
+
+	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1000,
+			      0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0100,
+			      0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nvkm_oclass
+g84_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_fifo_context_ctor,
+		.dtor = nv50_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static void
+g84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
+}
+
+static void
+g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+g84_fifo_uevent_func = {
+	.ctor = nvkm_fifo_uevent_ctor,
+	.init = g84_fifo_uevent_init,
+	.fini = g84_fifo_uevent_fini,
+};
+
+static int
+g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+			      &priv->playlist[0]);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+			      &priv->playlist[1]);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &priv->base.uevent);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &g84_fifo_cclass;
+	nv_engine(priv)->sclass = g84_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	return 0;
+}
+
+struct nvkm_oclass *
+g84_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_fifo_ctor,
+		.dtor = nv50_fifo_dtor,
+		.init = nv50_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
new file mode 100644
index 0000000..b745252
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
@@ -0,0 +1,967 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf100_fifo_priv {
+	struct nvkm_fifo base;
+
+	struct work_struct fault;
+	u64 mask;
+
+	struct {
+		struct nvkm_gpuobj *mem[2];
+		int active;
+		wait_queue_head_t wait;
+	} runlist;
+
+	struct {
+		struct nvkm_gpuobj *mem;
+		struct nvkm_vma bar;
+	} user;
+	int spoon_nr;
+};
+
+struct gf100_fifo_base {
+	struct nvkm_fifo_base base;
+	struct nvkm_gpuobj *pgd;
+	struct nvkm_vm *vm;
+};
+
+struct gf100_fifo_chan {
+	struct nvkm_fifo_chan base;
+	enum {
+		STOPPED,
+		RUNNING,
+		KILLED
+	} state;
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+gf100_fifo_runlist_update(struct gf100_fifo_priv *priv)
+{
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct nvkm_gpuobj *cur;
+	int i, p;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	cur = priv->runlist.mem[priv->runlist.active];
+	priv->runlist.active = !priv->runlist.active;
+
+	for (i = 0, p = 0; i < 128; i++) {
+		struct gf100_fifo_chan *chan = (void *)priv->base.channel[i];
+		if (chan && chan->state == RUNNING) {
+			nv_wo32(cur, p + 0, i);
+			nv_wo32(cur, p + 4, 0x00000004);
+			p += 8;
+		}
+	}
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x002270, cur->addr >> 12);
+	nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
+
+	if (wait_event_timeout(priv->runlist.wait,
+			       !(nv_rd32(priv, 0x00227c) & 0x00100000),
+			       msecs_to_jiffies(2000)) == 0)
+		nv_error(priv, "runlist update timeout\n");
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gf100_fifo_context_attach(struct nvkm_object *parent,
+			  struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gf100_fifo_base *base = (void *)parent->parent;
+	struct nvkm_engctx *ectx = (void *)object;
+	u32 addr;
+	int ret;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW    : return 0;
+	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
+	case NVDEV_ENGINE_CE0   : addr = 0x0230; break;
+	case NVDEV_ENGINE_CE1   : addr = 0x0240; break;
+	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!ectx->vma.node) {
+		ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+					 NV_MEM_ACCESS_RW, &ectx->vma);
+		if (ret)
+			return ret;
+
+		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+	}
+
+	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+			  struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gf100_fifo_priv *priv = (void *)parent->engine;
+	struct gf100_fifo_base *base = (void *)parent->parent;
+	struct gf100_fifo_chan *chan = (void *)parent;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW    : return 0;
+	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
+	case NVDEV_ENGINE_CE0   : addr = 0x0230; break;
+	case NVDEV_ENGINE_CE1   : addr = 0x0240; break;
+	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wr32(priv, 0x002634, chan->base.chid);
+	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+		nv_error(priv, "channel %d [%s] kick timeout\n",
+			 chan->base.chid, nvkm_client_name(chan));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	nv_wo32(base, addr + 0x00, 0x00000000);
+	nv_wo32(base, addr + 0x04, 0x00000000);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_channel_gpfifo_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gf100_fifo_priv *priv = (void *)engine;
+	struct gf100_fifo_base *base = (void *)parent;
+	struct gf100_fifo_chan *chan;
+	u64 usermem, ioffset, ilength;
+	int ret, i;
+
+	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+				 "ioffset %016llx ilength %08x\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+			 args->v0.ilength);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 1,
+				       priv->user.bar.offset, 0x1000,
+				       args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_CE0) |
+				       (1ULL << NVDEV_ENGINE_CE1) |
+				       (1ULL << NVDEV_ENGINE_MSVLD) |
+				       (1ULL << NVDEV_ENGINE_MSPDEC) |
+				       (1ULL << NVDEV_ENGINE_MSPPP), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->context_attach = gf100_fifo_context_attach;
+	nv_parent(chan)->context_detach = gf100_fifo_context_detach;
+
+	usermem = chan->base.chid * 0x1000;
+	ioffset = args->v0.ioffset;
+	ilength = order_base_2(args->v0.ilength / 8);
+
+	for (i = 0; i < 0x1000; i += 4)
+		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x10, 0x0000face);
+	nv_wo32(base, 0x30, 0xfffff902);
+	nv_wo32(base, 0x48, lower_32_bits(ioffset));
+	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base, 0x54, 0x00000002);
+	nv_wo32(base, 0x84, 0x20400000);
+	nv_wo32(base, 0x94, 0x30000001);
+	nv_wo32(base, 0x9c, 0x00000100);
+	nv_wo32(base, 0xa4, 0x1f1f1f1f);
+	nv_wo32(base, 0xa8, 0x1f1f1f1f);
+	nv_wo32(base, 0xac, 0x0000001f);
+	nv_wo32(base, 0xb8, 0xf8000000);
+	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+gf100_fifo_chan_init(struct nvkm_object *object)
+{
+	struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
+	struct gf100_fifo_priv *priv = (void *)object->engine;
+	struct gf100_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nvkm_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
+
+	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+		nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
+		gf100_fifo_runlist_update(priv);
+	}
+
+	return 0;
+}
+
+static void gf100_fifo_intr_engine(struct gf100_fifo_priv *priv);
+
+static int
+gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gf100_fifo_priv *priv = (void *)object->engine;
+	struct gf100_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+		nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
+		gf100_fifo_runlist_update(priv);
+	}
+
+	gf100_fifo_intr_engine(priv);
+
+	nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
+	return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+gf100_fifo_ofuncs = {
+	.ctor = gf100_fifo_chan_ctor,
+	.dtor = _nvkm_fifo_channel_dtor,
+	.init = gf100_fifo_chan_init,
+	.fini = gf100_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+gf100_fifo_sclass[] = {
+	{ FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+			struct nvkm_oclass *oclass, void *data, u32 size,
+			struct nvkm_object **pobject)
+{
+	struct gf100_fifo_base *base;
+	int ret;
+
+	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				       0x1000, NVOBJ_FLAG_ZERO_ALLOC |
+				       NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
+			      &base->pgd);
+	if (ret)
+		return ret;
+
+	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0208, 0xffffffff);
+	nv_wo32(base, 0x020c, 0x000000ff);
+
+	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void
+gf100_fifo_context_dtor(struct nvkm_object *object)
+{
+	struct gf100_fifo_base *base = (void *)object;
+	nvkm_vm_ref(NULL, &base->vm, base->pgd);
+	nvkm_gpuobj_ref(NULL, &base->pgd);
+	nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+gf100_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fifo_context_ctor,
+		.dtor = gf100_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static inline int
+gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn)
+{
+	switch (engn) {
+	case NVDEV_ENGINE_GR    : engn = 0; break;
+	case NVDEV_ENGINE_MSVLD : engn = 1; break;
+	case NVDEV_ENGINE_MSPPP : engn = 2; break;
+	case NVDEV_ENGINE_MSPDEC: engn = 3; break;
+	case NVDEV_ENGINE_CE0   : engn = 4; break;
+	case NVDEV_ENGINE_CE1   : engn = 5; break;
+	default:
+		return -1;
+	}
+
+	return engn;
+}
+
+static inline struct nvkm_engine *
+gf100_fifo_engine(struct gf100_fifo_priv *priv, u32 engn)
+{
+	switch (engn) {
+	case 0: engn = NVDEV_ENGINE_GR; break;
+	case 1: engn = NVDEV_ENGINE_MSVLD; break;
+	case 2: engn = NVDEV_ENGINE_MSPPP; break;
+	case 3: engn = NVDEV_ENGINE_MSPDEC; break;
+	case 4: engn = NVDEV_ENGINE_CE0; break;
+	case 5: engn = NVDEV_ENGINE_CE1; break;
+	default:
+		return NULL;
+	}
+
+	return nvkm_engine(priv, engn);
+}
+
+static void
+gf100_fifo_recover_work(struct work_struct *work)
+{
+	struct gf100_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+	struct nvkm_object *engine;
+	unsigned long flags;
+	u32 engn, engm = 0;
+	u64 mask, todo;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	mask = priv->mask;
+	priv->mask = 0ULL;
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+
+	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+		engm |= 1 << gf100_fifo_engidx(priv, engn);
+	nv_mask(priv, 0x002630, engm, engm);
+
+	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+		if ((engine = (void *)nvkm_engine(priv, engn))) {
+			nv_ofuncs(engine)->fini(engine, false);
+			WARN_ON(nv_ofuncs(engine)->init(engine));
+		}
+	}
+
+	gf100_fifo_runlist_update(priv);
+	nv_wr32(priv, 0x00262c, engm);
+	nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+gf100_fifo_recover(struct gf100_fifo_priv *priv, struct nvkm_engine *engine,
+		   struct gf100_fifo_chan *chan)
+{
+	u32 chid = chan->base.chid;
+	unsigned long flags;
+
+	nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+		       nv_subdev(engine)->name, chid);
+
+	nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
+	chan->state = KILLED;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	priv->mask |= 1ULL << nv_engidx(engine);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	schedule_work(&priv->fault);
+}
+
+static int
+gf100_fifo_swmthd(struct gf100_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+	struct gf100_fifo_chan *chan = NULL;
+	struct nvkm_handle *bind;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
+	if (likely(bind)) {
+		if (!mthd || !nv_call(bind->object, mthd, data))
+			ret = 0;
+		nvkm_namedb_put(bind);
+	}
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return ret;
+}
+
+static const struct nvkm_enum
+gf100_fifo_sched_reason[] = {
+	{ 0x0a, "CTXSW_TIMEOUT" },
+	{}
+};
+
+static void
+gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv)
+{
+	struct nvkm_engine *engine;
+	struct gf100_fifo_chan *chan;
+	u32 engn;
+
+	for (engn = 0; engn < 6; engn++) {
+		u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+		u32 busy = (stat & 0x80000000);
+		u32 save = (stat & 0x00100000); /* maybe? */
+		u32 unk0 = (stat & 0x00040000);
+		u32 unk1 = (stat & 0x00001000);
+		u32 chid = (stat & 0x0000007f);
+		(void)save;
+
+		if (busy && unk0 && unk1) {
+			if (!(chan = (void *)priv->base.channel[chid]))
+				continue;
+			if (!(engine = gf100_fifo_engine(priv, engn)))
+				continue;
+			gf100_fifo_recover(priv, engine, chan);
+		}
+	}
+}
+
+static void
+gf100_fifo_intr_sched(struct gf100_fifo_priv *priv)
+{
+	u32 intr = nv_rd32(priv, 0x00254c);
+	u32 code = intr & 0x000000ff;
+	const struct nvkm_enum *en;
+	char enunk[6] = "";
+
+	en = nvkm_enum_find(gf100_fifo_sched_reason, code);
+	if (!en)
+		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+	nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+	switch (code) {
+	case 0x0a:
+		gf100_fifo_intr_sched_ctxsw(priv);
+		break;
+	default:
+		break;
+	}
+}
+
+static const struct nvkm_enum
+gf100_fifo_fault_engine[] = {
+	{ 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
+	{ 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB },
+	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
+	{ 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
+	{ 0x10, "PMSVLD", NULL, NVDEV_ENGINE_MSVLD },
+	{ 0x11, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP },
+	{ 0x13, "PCOUNTER" },
+	{ 0x14, "PMSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
+	{ 0x15, "PCE0", NULL, NVDEV_ENGINE_CE0 },
+	{ 0x16, "PCE1", NULL, NVDEV_ENGINE_CE1 },
+	{ 0x17, "PDAEMON" },
+	{}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_reason[] = {
+	{ 0x00, "PT_NOT_PRESENT" },
+	{ 0x01, "PT_TOO_SHORT" },
+	{ 0x02, "PAGE_NOT_PRESENT" },
+	{ 0x03, "VM_LIMIT_EXCEEDED" },
+	{ 0x04, "NO_CHANNEL" },
+	{ 0x05, "PAGE_SYSTEM_ONLY" },
+	{ 0x06, "PAGE_READ_ONLY" },
+	{ 0x0a, "COMPRESSED_SYSRAM" },
+	{ 0x0c, "INVALID_STORAGE_TYPE" },
+	{}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_hubclient[] = {
+	{ 0x01, "PCOPY0" },
+	{ 0x02, "PCOPY1" },
+	{ 0x04, "DISPATCH" },
+	{ 0x05, "CTXCTL" },
+	{ 0x06, "PFIFO" },
+	{ 0x07, "BAR_READ" },
+	{ 0x08, "BAR_WRITE" },
+	{ 0x0b, "PVP" },
+	{ 0x0c, "PMSPPP" },
+	{ 0x0d, "PMSVLD" },
+	{ 0x11, "PCOUNTER" },
+	{ 0x12, "PDAEMON" },
+	{ 0x14, "CCACHE" },
+	{ 0x15, "CCACHE_POST" },
+	{}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_gpcclient[] = {
+	{ 0x01, "TEX" },
+	{ 0x0c, "ESETUP" },
+	{ 0x0e, "CTXCTL" },
+	{ 0x0f, "PROP" },
+	{}
+};
+
+static void
+gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit)
+{
+	u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
+	u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
+	u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
+	u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+	u32 gpc    = (stat & 0x1f000000) >> 24;
+	u32 client = (stat & 0x00001f00) >> 8;
+	u32 write  = (stat & 0x00000080);
+	u32 hub    = (stat & 0x00000040);
+	u32 reason = (stat & 0x0000000f);
+	struct nvkm_object *engctx = NULL, *object;
+	struct nvkm_engine *engine = NULL;
+	const struct nvkm_enum *er, *eu, *ec;
+	char erunk[6] = "";
+	char euunk[6] = "";
+	char ecunk[6] = "";
+	char gpcid[3] = "";
+
+	er = nvkm_enum_find(gf100_fifo_fault_reason, reason);
+	if (!er)
+		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+	eu = nvkm_enum_find(gf100_fifo_fault_engine, unit);
+	if (eu) {
+		switch (eu->data2) {
+		case NVDEV_SUBDEV_BAR:
+			nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+			break;
+		case NVDEV_SUBDEV_INSTMEM:
+			nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+			break;
+		case NVDEV_ENGINE_IFB:
+			nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+			break;
+		default:
+			engine = nvkm_engine(priv, eu->data2);
+			if (engine)
+				engctx = nvkm_engctx_get(engine, inst);
+			break;
+		}
+	} else {
+		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
+	}
+
+	if (hub) {
+		ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client);
+	} else {
+		ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client);
+		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
+	}
+
+	if (!ec)
+		snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+	nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+		       "channel 0x%010llx [%s]\n", write ? "write" : "read",
+		 (u64)vahi << 32 | valo, er ? er->name : erunk,
+		 eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+		 ec ? ec->name : ecunk, (u64)inst << 12,
+		 nvkm_client_name(engctx));
+
+	object = engctx;
+	while (object) {
+		switch (nv_mclass(object)) {
+		case FERMI_CHANNEL_GPFIFO:
+			gf100_fifo_recover(priv, engine, (void *)object);
+			break;
+		}
+		object = object->parent;
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static const struct nvkm_bitfield
+gf100_fifo_pbdma_intr[] = {
+/*	{ 0x00008000, "" }	seen with null ib push */
+	{ 0x00200000, "ILLEGAL_MTHD" },
+	{ 0x00800000, "EMPTY_SUBC" },
+	{}
+};
+
+static void
+gf100_fifo_intr_pbdma(struct gf100_fifo_priv *priv, int unit)
+{
+	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
+	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00003ffc);
+	u32 show = stat;
+
+	if (stat & 0x00800000) {
+		if (!gf100_fifo_swmthd(priv, chid, mthd, data))
+			show &= ~0x00800000;
+	}
+
+	if (show) {
+		nv_error(priv, "PBDMA%d:", unit);
+		nvkm_bitfield_print(gf100_fifo_pbdma_intr, show);
+		pr_cont("\n");
+		nv_error(priv,
+			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+			 unit, chid,
+			 nvkm_client_name_for_fifo_chid(&priv->base, chid),
+			 subc, mthd, data);
+	}
+
+	nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
+}
+
+static void
+gf100_fifo_intr_runlist(struct gf100_fifo_priv *priv)
+{
+	u32 intr = nv_rd32(priv, 0x002a00);
+
+	if (intr & 0x10000000) {
+		wake_up(&priv->runlist.wait);
+		nv_wr32(priv, 0x002a00, 0x10000000);
+		intr &= ~0x10000000;
+	}
+
+	if (intr) {
+		nv_error(priv, "RUNLIST 0x%08x\n", intr);
+		nv_wr32(priv, 0x002a00, intr);
+	}
+}
+
+static void
+gf100_fifo_intr_engine_unit(struct gf100_fifo_priv *priv, int engn)
+{
+	u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
+	u32 inte = nv_rd32(priv, 0x002628);
+	u32 unkn;
+
+	nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
+
+	for (unkn = 0; unkn < 8; unkn++) {
+		u32 ints = (intr >> (unkn * 0x04)) & inte;
+		if (ints & 0x1) {
+			nvkm_fifo_uevent(&priv->base);
+			ints &= ~1;
+		}
+		if (ints) {
+			nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
+			nv_mask(priv, 0x002628, ints, 0);
+		}
+	}
+}
+
+static void
+gf100_fifo_intr_engine(struct gf100_fifo_priv *priv)
+{
+	u32 mask = nv_rd32(priv, 0x0025a4);
+	while (mask) {
+		u32 unit = __ffs(mask);
+		gf100_fifo_intr_engine_unit(priv, unit);
+		mask &= ~(1 << unit);
+	}
+}
+
+static void
+gf100_fifo_intr(struct nvkm_subdev *subdev)
+{
+	struct gf100_fifo_priv *priv = (void *)subdev;
+	u32 mask = nv_rd32(priv, 0x002140);
+	u32 stat = nv_rd32(priv, 0x002100) & mask;
+
+	if (stat & 0x00000001) {
+		u32 intr = nv_rd32(priv, 0x00252c);
+		nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
+		nv_wr32(priv, 0x002100, 0x00000001);
+		stat &= ~0x00000001;
+	}
+
+	if (stat & 0x00000100) {
+		gf100_fifo_intr_sched(priv);
+		nv_wr32(priv, 0x002100, 0x00000100);
+		stat &= ~0x00000100;
+	}
+
+	if (stat & 0x00010000) {
+		u32 intr = nv_rd32(priv, 0x00256c);
+		nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
+		nv_wr32(priv, 0x002100, 0x00010000);
+		stat &= ~0x00010000;
+	}
+
+	if (stat & 0x01000000) {
+		u32 intr = nv_rd32(priv, 0x00258c);
+		nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
+		nv_wr32(priv, 0x002100, 0x01000000);
+		stat &= ~0x01000000;
+	}
+
+	if (stat & 0x10000000) {
+		u32 mask = nv_rd32(priv, 0x00259c);
+		while (mask) {
+			u32 unit = __ffs(mask);
+			gf100_fifo_intr_fault(priv, unit);
+			nv_wr32(priv, 0x00259c, (1 << unit));
+			mask &= ~(1 << unit);
+		}
+		stat &= ~0x10000000;
+	}
+
+	if (stat & 0x20000000) {
+		u32 mask = nv_rd32(priv, 0x0025a0);
+		while (mask) {
+			u32 unit = __ffs(mask);
+			gf100_fifo_intr_pbdma(priv, unit);
+			nv_wr32(priv, 0x0025a0, (1 << unit));
+			mask &= ~(1 << unit);
+		}
+		stat &= ~0x20000000;
+	}
+
+	if (stat & 0x40000000) {
+		gf100_fifo_intr_runlist(priv);
+		stat &= ~0x40000000;
+	}
+
+	if (stat & 0x80000000) {
+		gf100_fifo_intr_engine(priv);
+		stat &= ~0x80000000;
+	}
+
+	if (stat) {
+		nv_error(priv, "INTR 0x%08x\n", stat);
+		nv_mask(priv, 0x002140, stat, 0x00000000);
+		nv_wr32(priv, 0x002100, stat);
+	}
+}
+
+static void
+gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+gf100_fifo_uevent_func = {
+	.ctor = nvkm_fifo_uevent_ctor,
+	.init = gf100_fifo_uevent_init,
+	.fini = gf100_fifo_uevent_fini,
+};
+
+static int
+gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gf100_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	INIT_WORK(&priv->fault, gf100_fifo_recover_work);
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
+			      &priv->runlist.mem[0]);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
+			      &priv->runlist.mem[1]);
+	if (ret)
+		return ret;
+
+	init_waitqueue_head(&priv->runlist.wait);
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
+			      &priv->user.mem);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+			      &priv->user.bar);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &priv->base.uevent);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = gf100_fifo_intr;
+	nv_engine(priv)->cclass = &gf100_fifo_cclass;
+	nv_engine(priv)->sclass = gf100_fifo_sclass;
+	return 0;
+}
+
+static void
+gf100_fifo_dtor(struct nvkm_object *object)
+{
+	struct gf100_fifo_priv *priv = (void *)object;
+
+	nvkm_gpuobj_unmap(&priv->user.bar);
+	nvkm_gpuobj_ref(NULL, &priv->user.mem);
+	nvkm_gpuobj_ref(NULL, &priv->runlist.mem[0]);
+	nvkm_gpuobj_ref(NULL, &priv->runlist.mem[1]);
+
+	nvkm_fifo_destroy(&priv->base);
+}
+
+static int
+gf100_fifo_init(struct nvkm_object *object)
+{
+	struct gf100_fifo_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x000204, 0xffffffff);
+	nv_wr32(priv, 0x002204, 0xffffffff);
+
+	priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
+	nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
+
+	/* assign engines to PBDMAs */
+	if (priv->spoon_nr >= 3) {
+		nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
+		nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
+		nv_wr32(priv, 0x002210, ~(1 << 1)); /* PMSPP */
+		nv_wr32(priv, 0x002214, ~(1 << 1)); /* PMSVLD */
+		nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
+		nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
+	}
+
+	/* PBDMA[n] */
+	for (i = 0; i < priv->spoon_nr; i++) {
+		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+	}
+
+	nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
+	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0x7fffffff);
+	nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
+	return 0;
+}
+
+struct nvkm_oclass *
+gf100_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fifo_ctor,
+		.dtor = gf100_fifo_dtor,
+		.init = gf100_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
new file mode 100644
index 0000000..9585539
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -0,0 +1,1138 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gk104.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
+static const struct {
+	u64 subdev;
+	u64 mask;
+} fifo_engine[] = {
+	_(NVDEV_ENGINE_GR      , (1ULL << NVDEV_ENGINE_SW) |
+				 (1ULL << NVDEV_ENGINE_CE2)),
+	_(NVDEV_ENGINE_MSPDEC  , 0),
+	_(NVDEV_ENGINE_MSPPP   , 0),
+	_(NVDEV_ENGINE_MSVLD   , 0),
+	_(NVDEV_ENGINE_CE0     , 0),
+	_(NVDEV_ENGINE_CE1     , 0),
+	_(NVDEV_ENGINE_MSENC   , 0),
+};
+#undef _
+#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
+
+struct gk104_fifo_engn {
+	struct nvkm_gpuobj *runlist[2];
+	int cur_runlist;
+	wait_queue_head_t wait;
+};
+
+struct gk104_fifo_priv {
+	struct nvkm_fifo base;
+
+	struct work_struct fault;
+	u64 mask;
+
+	struct gk104_fifo_engn engine[FIFO_ENGINE_NR];
+	struct {
+		struct nvkm_gpuobj *mem;
+		struct nvkm_vma bar;
+	} user;
+	int spoon_nr;
+};
+
+struct gk104_fifo_base {
+	struct nvkm_fifo_base base;
+	struct nvkm_gpuobj *pgd;
+	struct nvkm_vm *vm;
+};
+
+struct gk104_fifo_chan {
+	struct nvkm_fifo_chan base;
+	u32 engine;
+	enum {
+		STOPPED,
+		RUNNING,
+		KILLED
+	} state;
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+gk104_fifo_runlist_update(struct gk104_fifo_priv *priv, u32 engine)
+{
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct gk104_fifo_engn *engn = &priv->engine[engine];
+	struct nvkm_gpuobj *cur;
+	int i, p;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	cur = engn->runlist[engn->cur_runlist];
+	engn->cur_runlist = !engn->cur_runlist;
+
+	for (i = 0, p = 0; i < priv->base.max; i++) {
+		struct gk104_fifo_chan *chan = (void *)priv->base.channel[i];
+		if (chan && chan->state == RUNNING && chan->engine == engine) {
+			nv_wo32(cur, p + 0, i);
+			nv_wo32(cur, p + 4, 0x00000000);
+			p += 8;
+		}
+	}
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x002270, cur->addr >> 12);
+	nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
+
+	if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
+			       (engine * 0x08)) & 0x00100000),
+				msecs_to_jiffies(2000)) == 0)
+		nv_error(priv, "runlist %d update timeout\n", engine);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gk104_fifo_context_attach(struct nvkm_object *parent,
+			  struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gk104_fifo_base *base = (void *)parent->parent;
+	struct nvkm_engctx *ectx = (void *)object;
+	u32 addr;
+	int ret;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   :
+		return 0;
+	case NVDEV_ENGINE_CE0:
+	case NVDEV_ENGINE_CE1:
+	case NVDEV_ENGINE_CE2:
+		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+		return 0;
+	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
+	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!ectx->vma.node) {
+		ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+					 NV_MEM_ACCESS_RW, &ectx->vma);
+		if (ret)
+			return ret;
+
+		nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+	}
+
+	nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+	nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+			  struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gk104_fifo_priv *priv = (void *)parent->engine;
+	struct gk104_fifo_base *base = (void *)parent->parent;
+	struct gk104_fifo_chan *chan = (void *)parent;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW    : return 0;
+	case NVDEV_ENGINE_CE0   :
+	case NVDEV_ENGINE_CE1   :
+	case NVDEV_ENGINE_CE2   : addr = 0x0000; break;
+	case NVDEV_ENGINE_GR    : addr = 0x0210; break;
+	case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+	case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+	case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_wr32(priv, 0x002634, chan->base.chid);
+	if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+		nv_error(priv, "channel %d [%s] kick timeout\n",
+			 chan->base.chid, nvkm_client_name(chan));
+		if (suspend)
+			return -EBUSY;
+	}
+
+	if (addr) {
+		nv_wo32(base, addr + 0x00, 0x00000000);
+		nv_wo32(base, addr + 0x04, 0x00000000);
+		bar->flush(bar);
+	}
+
+	return 0;
+}
+
+static int
+gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	union {
+		struct kepler_channel_gpfifo_a_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct gk104_fifo_priv *priv = (void *)engine;
+	struct gk104_fifo_base *base = (void *)parent;
+	struct gk104_fifo_chan *chan;
+	u64 usermem, ioffset, ilength;
+	int ret, i;
+
+	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+				 "ioffset %016llx ilength %08x engine %08x\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+			 args->v0.ilength, args->v0.engine);
+	} else
+		return ret;
+
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
+		if (args->v0.engine & (1 << i)) {
+			if (nvkm_engine(parent, fifo_engine[i].subdev)) {
+				args->v0.engine = (1 << i);
+				break;
+			}
+		}
+	}
+
+	if (i == FIFO_ENGINE_NR) {
+		nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine);
+		return -ENODEV;
+	}
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 1,
+				       priv->user.bar.offset, 0x200,
+				       args->v0.pushbuf,
+				       fifo_engine[i].mask, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->context_attach = gk104_fifo_context_attach;
+	nv_parent(chan)->context_detach = gk104_fifo_context_detach;
+	chan->engine = i;
+
+	usermem = chan->base.chid * 0x200;
+	ioffset = args->v0.ioffset;
+	ilength = order_base_2(args->v0.ilength / 8);
+
+	for (i = 0; i < 0x200; i += 4)
+		nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+	nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+	nv_wo32(base, 0x10, 0x0000face);
+	nv_wo32(base, 0x30, 0xfffff902);
+	nv_wo32(base, 0x48, lower_32_bits(ioffset));
+	nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base, 0x84, 0x20400000);
+	nv_wo32(base, 0x94, 0x30000001);
+	nv_wo32(base, 0x9c, 0x00000100);
+	nv_wo32(base, 0xac, 0x0000001f);
+	nv_wo32(base, 0xe8, chan->base.chid);
+	nv_wo32(base, 0xb8, 0xf8000000);
+	nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+	nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+gk104_fifo_chan_init(struct nvkm_object *object)
+{
+	struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
+	struct gk104_fifo_priv *priv = (void *)object->engine;
+	struct gk104_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nvkm_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
+	nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
+
+	if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+		nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+		gk104_fifo_runlist_update(priv, chan->engine);
+		nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+	}
+
+	return 0;
+}
+
+static int
+gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gk104_fifo_priv *priv = (void *)object->engine;
+	struct gk104_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+		nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
+		gk104_fifo_runlist_update(priv, chan->engine);
+	}
+
+	nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
+	return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+gk104_fifo_ofuncs = {
+	.ctor = gk104_fifo_chan_ctor,
+	.dtor = _nvkm_fifo_channel_dtor,
+	.init = gk104_fifo_chan_init,
+	.fini = gk104_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+gk104_fifo_sclass[] = {
+	{ KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+			struct nvkm_oclass *oclass, void *data, u32 size,
+			struct nvkm_object **pobject)
+{
+	struct gk104_fifo_base *base;
+	int ret;
+
+	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				       0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
+			      &base->pgd);
+	if (ret)
+		return ret;
+
+	nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+	nv_wo32(base, 0x0208, 0xffffffff);
+	nv_wo32(base, 0x020c, 0x000000ff);
+
+	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void
+gk104_fifo_context_dtor(struct nvkm_object *object)
+{
+	struct gk104_fifo_base *base = (void *)object;
+	nvkm_vm_ref(NULL, &base->vm, base->pgd);
+	nvkm_gpuobj_ref(NULL, &base->pgd);
+	nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+gk104_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_fifo_context_ctor,
+		.dtor = gk104_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static inline int
+gk104_fifo_engidx(struct gk104_fifo_priv *priv, u32 engn)
+{
+	switch (engn) {
+	case NVDEV_ENGINE_GR    :
+	case NVDEV_ENGINE_CE2   : engn = 0; break;
+	case NVDEV_ENGINE_MSVLD : engn = 1; break;
+	case NVDEV_ENGINE_MSPPP : engn = 2; break;
+	case NVDEV_ENGINE_MSPDEC: engn = 3; break;
+	case NVDEV_ENGINE_CE0   : engn = 4; break;
+	case NVDEV_ENGINE_CE1   : engn = 5; break;
+	case NVDEV_ENGINE_MSENC : engn = 6; break;
+	default:
+		return -1;
+	}
+
+	return engn;
+}
+
+static inline struct nvkm_engine *
+gk104_fifo_engine(struct gk104_fifo_priv *priv, u32 engn)
+{
+	if (engn >= ARRAY_SIZE(fifo_engine))
+		return NULL;
+	return nvkm_engine(priv, fifo_engine[engn].subdev);
+}
+
+static void
+gk104_fifo_recover_work(struct work_struct *work)
+{
+	struct gk104_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+	struct nvkm_object *engine;
+	unsigned long flags;
+	u32 engn, engm = 0;
+	u64 mask, todo;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	mask = priv->mask;
+	priv->mask = 0ULL;
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+
+	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+		engm |= 1 << gk104_fifo_engidx(priv, engn);
+	nv_mask(priv, 0x002630, engm, engm);
+
+	for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+		if ((engine = (void *)nvkm_engine(priv, engn))) {
+			nv_ofuncs(engine)->fini(engine, false);
+			WARN_ON(nv_ofuncs(engine)->init(engine));
+		}
+		gk104_fifo_runlist_update(priv, gk104_fifo_engidx(priv, engn));
+	}
+
+	nv_wr32(priv, 0x00262c, engm);
+	nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+gk104_fifo_recover(struct gk104_fifo_priv *priv, struct nvkm_engine *engine,
+		  struct gk104_fifo_chan *chan)
+{
+	u32 chid = chan->base.chid;
+	unsigned long flags;
+
+	nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+		       nv_subdev(engine)->name, chid);
+
+	nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
+	chan->state = KILLED;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	priv->mask |= 1ULL << nv_engidx(engine);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	schedule_work(&priv->fault);
+}
+
+static int
+gk104_fifo_swmthd(struct gk104_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+	struct gk104_fifo_chan *chan = NULL;
+	struct nvkm_handle *bind;
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
+	if (likely(bind)) {
+		if (!mthd || !nv_call(bind->object, mthd, data))
+			ret = 0;
+		nvkm_namedb_put(bind);
+	}
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return ret;
+}
+
+static const struct nvkm_enum
+gk104_fifo_bind_reason[] = {
+	{ 0x01, "BIND_NOT_UNBOUND" },
+	{ 0x02, "SNOOP_WITHOUT_BAR1" },
+	{ 0x03, "UNBIND_WHILE_RUNNING" },
+	{ 0x05, "INVALID_RUNLIST" },
+	{ 0x06, "INVALID_CTX_TGT" },
+	{ 0x0b, "UNBIND_WHILE_PARKED" },
+	{}
+};
+
+static void
+gk104_fifo_intr_bind(struct gk104_fifo_priv *priv)
+{
+	u32 intr = nv_rd32(priv, 0x00252c);
+	u32 code = intr & 0x000000ff;
+	const struct nvkm_enum *en;
+	char enunk[6] = "";
+
+	en = nvkm_enum_find(gk104_fifo_bind_reason, code);
+	if (!en)
+		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+	nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
+}
+
+static const struct nvkm_enum
+gk104_fifo_sched_reason[] = {
+	{ 0x0a, "CTXSW_TIMEOUT" },
+	{}
+};
+
+static void
+gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv)
+{
+	struct nvkm_engine *engine;
+	struct gk104_fifo_chan *chan;
+	u32 engn;
+
+	for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
+		u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+		u32 busy = (stat & 0x80000000);
+		u32 next = (stat & 0x07ff0000) >> 16;
+		u32 chsw = (stat & 0x00008000);
+		u32 save = (stat & 0x00004000);
+		u32 load = (stat & 0x00002000);
+		u32 prev = (stat & 0x000007ff);
+		u32 chid = load ? next : prev;
+		(void)save;
+
+		if (busy && chsw) {
+			if (!(chan = (void *)priv->base.channel[chid]))
+				continue;
+			if (!(engine = gk104_fifo_engine(priv, engn)))
+				continue;
+			gk104_fifo_recover(priv, engine, chan);
+		}
+	}
+}
+
+static void
+gk104_fifo_intr_sched(struct gk104_fifo_priv *priv)
+{
+	u32 intr = nv_rd32(priv, 0x00254c);
+	u32 code = intr & 0x000000ff;
+	const struct nvkm_enum *en;
+	char enunk[6] = "";
+
+	en = nvkm_enum_find(gk104_fifo_sched_reason, code);
+	if (!en)
+		snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+	nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+	switch (code) {
+	case 0x0a:
+		gk104_fifo_intr_sched_ctxsw(priv);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+gk104_fifo_intr_chsw(struct gk104_fifo_priv *priv)
+{
+	u32 stat = nv_rd32(priv, 0x00256c);
+	nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
+	nv_wr32(priv, 0x00256c, stat);
+}
+
+static void
+gk104_fifo_intr_dropped_fault(struct gk104_fifo_priv *priv)
+{
+	u32 stat = nv_rd32(priv, 0x00259c);
+	nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
+}
+
+static const struct nvkm_enum
+gk104_fifo_fault_engine[] = {
+	{ 0x00, "GR", NULL, NVDEV_ENGINE_GR },
+	{ 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
+	{ 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+	{ 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
+	{ 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
+	{ 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
+	{ 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
+	{ 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD },
+	{ 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP },
+	{ 0x13, "PERF" },
+	{ 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
+	{ 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 },
+	{ 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 },
+	{ 0x17, "PMU" },
+	{ 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC },
+	{ 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 },
+	{}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_reason[] = {
+	{ 0x00, "PDE" },
+	{ 0x01, "PDE_SIZE" },
+	{ 0x02, "PTE" },
+	{ 0x03, "VA_LIMIT_VIOLATION" },
+	{ 0x04, "UNBOUND_INST_BLOCK" },
+	{ 0x05, "PRIV_VIOLATION" },
+	{ 0x06, "RO_VIOLATION" },
+	{ 0x07, "WO_VIOLATION" },
+	{ 0x08, "PITCH_MASK_VIOLATION" },
+	{ 0x09, "WORK_CREATION" },
+	{ 0x0a, "UNSUPPORTED_APERTURE" },
+	{ 0x0b, "COMPRESSION_FAILURE" },
+	{ 0x0c, "UNSUPPORTED_KIND" },
+	{ 0x0d, "REGION_VIOLATION" },
+	{ 0x0e, "BOTH_PTES_VALID" },
+	{ 0x0f, "INFO_TYPE_POISONED" },
+	{}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_hubclient[] = {
+	{ 0x00, "VIP" },
+	{ 0x01, "CE0" },
+	{ 0x02, "CE1" },
+	{ 0x03, "DNISO" },
+	{ 0x04, "FE" },
+	{ 0x05, "FECS" },
+	{ 0x06, "HOST" },
+	{ 0x07, "HOST_CPU" },
+	{ 0x08, "HOST_CPU_NB" },
+	{ 0x09, "ISO" },
+	{ 0x0a, "MMU" },
+	{ 0x0b, "MSPDEC" },
+	{ 0x0c, "MSPPP" },
+	{ 0x0d, "MSVLD" },
+	{ 0x0e, "NISO" },
+	{ 0x0f, "P2P" },
+	{ 0x10, "PD" },
+	{ 0x11, "PERF" },
+	{ 0x12, "PMU" },
+	{ 0x13, "RASTERTWOD" },
+	{ 0x14, "SCC" },
+	{ 0x15, "SCC_NB" },
+	{ 0x16, "SEC" },
+	{ 0x17, "SSYNC" },
+	{ 0x18, "GR_CE" },
+	{ 0x19, "CE2" },
+	{ 0x1a, "XV" },
+	{ 0x1b, "MMU_NB" },
+	{ 0x1c, "MSENC" },
+	{ 0x1d, "DFALCON" },
+	{ 0x1e, "SKED" },
+	{ 0x1f, "AFALCON" },
+	{}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_gpcclient[] = {
+	{ 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
+	{ 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
+	{ 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
+	{ 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
+	{ 0x0c, "RAST" },
+	{ 0x0d, "GCC" },
+	{ 0x0e, "GPCCS" },
+	{ 0x0f, "PROP_0" },
+	{ 0x10, "PROP_1" },
+	{ 0x11, "PROP_2" },
+	{ 0x12, "PROP_3" },
+	{ 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
+	{ 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
+	{ 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
+	{ 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
+	{ 0x1f, "GPM" },
+	{ 0x20, "LTP_UTLB_0" },
+	{ 0x21, "LTP_UTLB_1" },
+	{ 0x22, "LTP_UTLB_2" },
+	{ 0x23, "LTP_UTLB_3" },
+	{ 0x24, "GPC_RGG_UTLB" },
+	{}
+};
+
+static void
+gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit)
+{
+	u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
+	u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
+	u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
+	u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+	u32 gpc    = (stat & 0x1f000000) >> 24;
+	u32 client = (stat & 0x00001f00) >> 8;
+	u32 write  = (stat & 0x00000080);
+	u32 hub    = (stat & 0x00000040);
+	u32 reason = (stat & 0x0000000f);
+	struct nvkm_object *engctx = NULL, *object;
+	struct nvkm_engine *engine = NULL;
+	const struct nvkm_enum *er, *eu, *ec;
+	char erunk[6] = "";
+	char euunk[6] = "";
+	char ecunk[6] = "";
+	char gpcid[3] = "";
+
+	er = nvkm_enum_find(gk104_fifo_fault_reason, reason);
+	if (!er)
+		snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+	eu = nvkm_enum_find(gk104_fifo_fault_engine, unit);
+	if (eu) {
+		switch (eu->data2) {
+		case NVDEV_SUBDEV_BAR:
+			nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+			break;
+		case NVDEV_SUBDEV_INSTMEM:
+			nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+			break;
+		case NVDEV_ENGINE_IFB:
+			nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+			break;
+		default:
+			engine = nvkm_engine(priv, eu->data2);
+			if (engine)
+				engctx = nvkm_engctx_get(engine, inst);
+			break;
+		}
+	} else {
+		snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
+	}
+
+	if (hub) {
+		ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client);
+	} else {
+		ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client);
+		snprintf(gpcid, sizeof(gpcid), "%d", gpc);
+	}
+
+	if (!ec)
+		snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+	nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+		       "channel 0x%010llx [%s]\n", write ? "write" : "read",
+		 (u64)vahi << 32 | valo, er ? er->name : erunk,
+		 eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+		 ec ? ec->name : ecunk, (u64)inst << 12,
+		 nvkm_client_name(engctx));
+
+	object = engctx;
+	while (object) {
+		switch (nv_mclass(object)) {
+		case KEPLER_CHANNEL_GPFIFO_A:
+			gk104_fifo_recover(priv, engine, (void *)object);
+			break;
+		}
+		object = object->parent;
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
+	{ 0x00000001, "MEMREQ" },
+	{ 0x00000002, "MEMACK_TIMEOUT" },
+	{ 0x00000004, "MEMACK_EXTRA" },
+	{ 0x00000008, "MEMDAT_TIMEOUT" },
+	{ 0x00000010, "MEMDAT_EXTRA" },
+	{ 0x00000020, "MEMFLUSH" },
+	{ 0x00000040, "MEMOP" },
+	{ 0x00000080, "LBCONNECT" },
+	{ 0x00000100, "LBREQ" },
+	{ 0x00000200, "LBACK_TIMEOUT" },
+	{ 0x00000400, "LBACK_EXTRA" },
+	{ 0x00000800, "LBDAT_TIMEOUT" },
+	{ 0x00001000, "LBDAT_EXTRA" },
+	{ 0x00002000, "GPFIFO" },
+	{ 0x00004000, "GPPTR" },
+	{ 0x00008000, "GPENTRY" },
+	{ 0x00010000, "GPCRC" },
+	{ 0x00020000, "PBPTR" },
+	{ 0x00040000, "PBENTRY" },
+	{ 0x00080000, "PBCRC" },
+	{ 0x00100000, "XBARCONNECT" },
+	{ 0x00200000, "METHOD" },
+	{ 0x00400000, "METHODCRC" },
+	{ 0x00800000, "DEVICE" },
+	{ 0x02000000, "SEMAPHORE" },
+	{ 0x04000000, "ACQUIRE" },
+	{ 0x08000000, "PRI" },
+	{ 0x20000000, "NO_CTXSW_SEG" },
+	{ 0x40000000, "PBSEG" },
+	{ 0x80000000, "SIGNATURE" },
+	{}
+};
+
+static void
+gk104_fifo_intr_pbdma_0(struct gk104_fifo_priv *priv, int unit)
+{
+	u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
+	u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
+	u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+	u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00003ffc);
+	u32 show = stat;
+
+	if (stat & 0x00800000) {
+		if (!gk104_fifo_swmthd(priv, chid, mthd, data))
+			show &= ~0x00800000;
+		nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+	}
+
+	if (show) {
+		nv_error(priv, "PBDMA%d:", unit);
+		nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show);
+		pr_cont("\n");
+		nv_error(priv,
+			 "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+			 unit, chid,
+			 nvkm_client_name_for_fifo_chid(&priv->base, chid),
+			 subc, mthd, data);
+	}
+
+	nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
+}
+
+static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
+	{ 0x00000001, "HCE_RE_ILLEGAL_OP" },
+	{ 0x00000002, "HCE_RE_ALIGNB" },
+	{ 0x00000004, "HCE_PRIV" },
+	{ 0x00000008, "HCE_ILLEGAL_MTHD" },
+	{ 0x00000010, "HCE_ILLEGAL_CLASS" },
+	{}
+};
+
+static void
+gk104_fifo_intr_pbdma_1(struct gk104_fifo_priv *priv, int unit)
+{
+	u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
+	u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
+	u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+
+	if (stat) {
+		nv_error(priv, "PBDMA%d:", unit);
+		nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat);
+		pr_cont("\n");
+		nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
+			 nv_rd32(priv, 0x040150 + (unit * 0x2000)),
+			 nv_rd32(priv, 0x040154 + (unit * 0x2000)));
+	}
+
+	nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
+}
+
+static void
+gk104_fifo_intr_runlist(struct gk104_fifo_priv *priv)
+{
+	u32 mask = nv_rd32(priv, 0x002a00);
+	while (mask) {
+		u32 engn = __ffs(mask);
+		wake_up(&priv->engine[engn].wait);
+		nv_wr32(priv, 0x002a00, 1 << engn);
+		mask &= ~(1 << engn);
+	}
+}
+
+static void
+gk104_fifo_intr_engine(struct gk104_fifo_priv *priv)
+{
+	nvkm_fifo_uevent(&priv->base);
+}
+
+static void
+gk104_fifo_intr(struct nvkm_subdev *subdev)
+{
+	struct gk104_fifo_priv *priv = (void *)subdev;
+	u32 mask = nv_rd32(priv, 0x002140);
+	u32 stat = nv_rd32(priv, 0x002100) & mask;
+
+	if (stat & 0x00000001) {
+		gk104_fifo_intr_bind(priv);
+		nv_wr32(priv, 0x002100, 0x00000001);
+		stat &= ~0x00000001;
+	}
+
+	if (stat & 0x00000010) {
+		nv_error(priv, "PIO_ERROR\n");
+		nv_wr32(priv, 0x002100, 0x00000010);
+		stat &= ~0x00000010;
+	}
+
+	if (stat & 0x00000100) {
+		gk104_fifo_intr_sched(priv);
+		nv_wr32(priv, 0x002100, 0x00000100);
+		stat &= ~0x00000100;
+	}
+
+	if (stat & 0x00010000) {
+		gk104_fifo_intr_chsw(priv);
+		nv_wr32(priv, 0x002100, 0x00010000);
+		stat &= ~0x00010000;
+	}
+
+	if (stat & 0x00800000) {
+		nv_error(priv, "FB_FLUSH_TIMEOUT\n");
+		nv_wr32(priv, 0x002100, 0x00800000);
+		stat &= ~0x00800000;
+	}
+
+	if (stat & 0x01000000) {
+		nv_error(priv, "LB_ERROR\n");
+		nv_wr32(priv, 0x002100, 0x01000000);
+		stat &= ~0x01000000;
+	}
+
+	if (stat & 0x08000000) {
+		gk104_fifo_intr_dropped_fault(priv);
+		nv_wr32(priv, 0x002100, 0x08000000);
+		stat &= ~0x08000000;
+	}
+
+	if (stat & 0x10000000) {
+		u32 mask = nv_rd32(priv, 0x00259c);
+		while (mask) {
+			u32 unit = __ffs(mask);
+			gk104_fifo_intr_fault(priv, unit);
+			nv_wr32(priv, 0x00259c, (1 << unit));
+			mask &= ~(1 << unit);
+		}
+		stat &= ~0x10000000;
+	}
+
+	if (stat & 0x20000000) {
+		u32 mask = nv_rd32(priv, 0x0025a0);
+		while (mask) {
+			u32 unit = __ffs(mask);
+			gk104_fifo_intr_pbdma_0(priv, unit);
+			gk104_fifo_intr_pbdma_1(priv, unit);
+			nv_wr32(priv, 0x0025a0, (1 << unit));
+			mask &= ~(1 << unit);
+		}
+		stat &= ~0x20000000;
+	}
+
+	if (stat & 0x40000000) {
+		gk104_fifo_intr_runlist(priv);
+		stat &= ~0x40000000;
+	}
+
+	if (stat & 0x80000000) {
+		nv_wr32(priv, 0x002100, 0x80000000);
+		gk104_fifo_intr_engine(priv);
+		stat &= ~0x80000000;
+	}
+
+	if (stat) {
+		nv_error(priv, "INTR 0x%08x\n", stat);
+		nv_mask(priv, 0x002140, stat, 0x00000000);
+		nv_wr32(priv, 0x002100, stat);
+	}
+}
+
+static void
+gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+	nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+gk104_fifo_uevent_func = {
+	.ctor = nvkm_fifo_uevent_ctor,
+	.init = gk104_fifo_uevent_init,
+	.fini = gk104_fifo_uevent_fini,
+};
+
+int
+gk104_fifo_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gk104_fifo_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fifo_fini(&priv->base, suspend);
+	if (ret)
+		return ret;
+
+	/* allow mmu fault interrupts, even when we're not using fifo */
+	nv_mask(priv, 0x002140, 0x10000000, 0x10000000);
+	return 0;
+}
+
+int
+gk104_fifo_init(struct nvkm_object *object)
+{
+	struct gk104_fifo_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* enable all available PBDMA units */
+	nv_wr32(priv, 0x000204, 0xffffffff);
+	priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
+	nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
+
+	/* PBDMA[n] */
+	for (i = 0; i < priv->spoon_nr; i++) {
+		nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+		nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+		nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+	}
+
+	/* PBDMA[n].HCE */
+	for (i = 0; i < priv->spoon_nr; i++) {
+		nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
+		nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
+	}
+
+	nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0x7fffffff);
+	return 0;
+}
+
+void
+gk104_fifo_dtor(struct nvkm_object *object)
+{
+	struct gk104_fifo_priv *priv = (void *)object;
+	int i;
+
+	nvkm_gpuobj_unmap(&priv->user.bar);
+	nvkm_gpuobj_ref(NULL, &priv->user.mem);
+
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
+		nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[1]);
+		nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[0]);
+	}
+
+	nvkm_fifo_destroy(&priv->base);
+}
+
+int
+gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gk104_fifo_impl *impl = (void *)oclass;
+	struct gk104_fifo_priv *priv;
+	int ret, i;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0,
+			       impl->channels - 1, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	INIT_WORK(&priv->fault, gk104_fifo_recover_work);
+
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
+		ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+				      0, &priv->engine[i].runlist[0]);
+		if (ret)
+			return ret;
+
+		ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+				      0, &priv->engine[i].runlist[1]);
+		if (ret)
+			return ret;
+
+		init_waitqueue_head(&priv->engine[i].wait);
+	}
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200,
+			      0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+			      &priv->user.bar);
+	if (ret)
+		return ret;
+
+	ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &priv->base.uevent);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = gk104_fifo_intr;
+	nv_engine(priv)->cclass = &gk104_fifo_cclass;
+	nv_engine(priv)->sclass = gk104_fifo_sclass;
+	return 0;
+}
+
+struct nvkm_oclass *
+gk104_fifo_oclass = &(struct gk104_fifo_impl) {
+	.base.handle = NV_ENGINE(FIFO, 0xe0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_fifo_ctor,
+		.dtor = gk104_fifo_dtor,
+		.init = gk104_fifo_init,
+		.fini = gk104_fifo_fini,
+	},
+	.channels = 4096,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
new file mode 100644
index 0000000..3046e00
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
@@ -0,0 +1,16 @@
+#ifndef __NVKM_FIFO_NVE0_H__
+#define __NVKM_FIFO_NVE0_H__
+#include <engine/fifo.h>
+
+int  gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *,
+		    struct nvkm_oclass *, void *, u32,
+		    struct nvkm_object **);
+void gk104_fifo_dtor(struct nvkm_object *);
+int  gk104_fifo_init(struct nvkm_object *);
+int  gk104_fifo_fini(struct nvkm_object *, bool);
+
+struct gk104_fifo_impl {
+	struct nvkm_oclass base;
+	u32 channels;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
new file mode 100644
index 0000000..9270922
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gk104.h"
+
+struct nvkm_oclass *
+gk208_fifo_oclass = &(struct gk104_fifo_impl) {
+	.base.handle = NV_ENGINE(FIFO, 0x08),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_fifo_ctor,
+		.dtor = gk104_fifo_dtor,
+		.init = gk104_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+	.channels = 1024,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
new file mode 100644
index 0000000..b30dc87
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "gk104.h"
+
+struct nvkm_oclass *
+gk20a_fifo_oclass = &(struct gk104_fifo_impl) {
+	.base.handle = NV_ENGINE(FIFO, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_fifo_ctor,
+		.dtor = gk104_fifo_dtor,
+		.init = gk104_fifo_init,
+		.fini = gk104_fifo_fini,
+	},
+	.channels = 128,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
new file mode 100644
index 0000000..b038b6e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv04_ramfc[] = {
+	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
+	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
+	{ 16,  0, 0x08,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+	{ 16, 16, 0x08,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+	{ 32,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_STATE },
+	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
+	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_ENGINE },
+	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_PULL1 },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+int
+nv04_fifo_object_attach(struct nvkm_object *parent,
+			struct nvkm_object *object, u32 handle)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	u32 context, chid = chan->base.chid;
+	int ret;
+
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->addr >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW:
+		context |= 0x00000000;
+		break;
+	case NVDEV_ENGINE_GR:
+		context |= 0x00010000;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		context |= 0x00020000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	context |= 0x80000000; /* valid */
+	context |= chid << 24;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	ret = nvkm_ramht_insert(priv->ramht, chid, handle, context);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+	return ret;
+}
+
+void
+nv04_fifo_object_detach(struct nvkm_object *parent, int cookie)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	mutex_lock(&nv_subdev(priv)->mutex);
+	nvkm_ramht_remove(priv->ramht, cookie);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+int
+nv04_fifo_context_attach(struct nvkm_object *parent,
+			 struct nvkm_object *object)
+{
+	nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid;
+	return 0;
+}
+
+static int
+nv04_fifo_chan_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+				       0x10000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+	chan->ramfc = chan->base.chid * 32;
+
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x10,
+			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+			     NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+	return 0;
+}
+
+void
+nv04_fifo_chan_dtor(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
+	struct ramfc_desc *c = priv->ramfc_desc;
+
+	do {
+		nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
+	} while ((++c)->bits);
+
+	nvkm_fifo_channel_destroy(&chan->base);
+}
+
+int
+nv04_fifo_chan_init(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
+	u32 mask = 1 << chan->base.chid;
+	unsigned long flags;
+	int ret;
+
+	ret = nvkm_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return 0;
+}
+
+int
+nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv04_fifo_priv *priv = (void *)object->engine;
+	struct nv04_fifo_chan *chan = (void *)object;
+	struct nvkm_gpuobj *fctx = priv->ramfc;
+	struct ramfc_desc *c;
+	unsigned long flags;
+	u32 data = chan->ramfc;
+	u32 chid;
+
+	/* prevent fifo context switches */
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0);
+
+	/* if this channel is active, replace it with a null context */
+	chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+	if (chid == chan->base.chid) {
+		nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
+		nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
+
+		c = priv->ramfc_desc;
+		do {
+			u32 rm = ((1ULL << c->bits) - 1) << c->regs;
+			u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
+			u32 rv = (nv_rd32(priv, c->regp) &  rm) >> c->regs;
+			u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
+			nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
+		} while ((++c)->bits);
+
+		c = priv->ramfc_desc;
+		do {
+			nv_wr32(priv, c->regp, 0x00000000);
+		} while ((++c)->bits);
+
+		nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+		nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+		nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	}
+
+	/* restore normal operation, after disabling dma mode */
+	nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+
+	return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+nv04_fifo_ofuncs = {
+	.ctor = nv04_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv04_fifo_sclass[] = {
+	{ NV03_CHANNEL_DMA, &nv04_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+int
+nv04_fifo_context_ctor(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nv04_fifo_base *base;
+	int ret;
+
+	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+				       0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nvkm_oclass
+nv04_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nvkm_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+void
+nv04_fifo_pause(struct nvkm_fifo *pfifo, unsigned long *pflags)
+__acquires(priv->base.lock)
+{
+	struct nv04_fifo_priv *priv = (void *)pfifo;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	*pflags = flags;
+
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
+	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
+
+	/* in some cases the puller may be left in an inconsistent state
+	 * if you try to stop it while it's busy translating handles.
+	 * sometimes you get a CACHE_ERROR, sometimes it just fails
+	 * silently; sending incorrect instance offsets to PGRAPH after
+	 * it's started up again.
+	 *
+	 * to avoid this, we invalidate the most recently calculated
+	 * instance.
+	 */
+	if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
+			   NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
+		nv_warn(priv, "timeout idling puller\n");
+
+	if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
+			  NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+		nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
+
+	nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
+}
+
+void
+nv04_fifo_start(struct nvkm_fifo *pfifo, unsigned long *pflags)
+__releases(priv->base.lock)
+{
+	struct nv04_fifo_priv *priv = (void *)pfifo;
+	unsigned long flags = *pflags;
+
+	nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
+
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+}
+
+static const char *
+nv_dma_state_err(u32 state)
+{
+	static const char * const desc[] = {
+		"NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
+		"INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
+	};
+	return desc[(state >> 29) & 0x7];
+}
+
+static bool
+nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
+{
+	struct nv04_fifo_chan *chan = NULL;
+	struct nvkm_handle *bind;
+	const int subc = (addr >> 13) & 0x7;
+	const int mthd = addr & 0x1ffc;
+	bool handled = false;
+	unsigned long flags;
+	u32 engine;
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	if (likely(chid >= priv->base.min && chid <= priv->base.max))
+		chan = (void *)priv->base.channel[chid];
+	if (unlikely(!chan))
+		goto out;
+
+	switch (mthd) {
+	case 0x0000:
+		bind = nvkm_namedb_get(nv_namedb(chan), data);
+		if (unlikely(!bind))
+			break;
+
+		if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
+			engine = 0x0000000f << (subc * 4);
+			chan->subc[subc] = data;
+			handled = true;
+
+			nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
+		}
+
+		nvkm_namedb_put(bind);
+		break;
+	default:
+		engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
+		if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
+			break;
+
+		bind = nvkm_namedb_get(nv_namedb(chan), chan->subc[subc]);
+		if (likely(bind)) {
+			if (!nv_call(bind->object, mthd, data))
+				handled = true;
+			nvkm_namedb_put(bind);
+		}
+		break;
+	}
+
+out:
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return handled;
+}
+
+static void
+nv04_fifo_cache_error(struct nvkm_device *device,
+		      struct nv04_fifo_priv *priv, u32 chid, u32 get)
+{
+	u32 mthd, data;
+	int ptr;
+
+	/* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
+	 * G80 chips, but CACHE1 isn't big enough for this much data.. Tests
+	 * show that it wraps around to the start at GET=0x800.. No clue as to
+	 * why..
+	 */
+	ptr = (get & 0x7ff) >> 2;
+
+	if (device->card_type < NV_40) {
+		mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
+		data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
+	} else {
+		mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
+		data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
+	}
+
+	if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
+		const char *client_name =
+			nvkm_client_name_for_fifo_chid(&priv->base, chid);
+		nv_error(priv,
+			 "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+			 chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
+			 data);
+	}
+
+	nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
+	nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+		nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
+	nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+		nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
+
+	nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
+		nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+}
+
+static void
+nv04_fifo_dma_pusher(struct nvkm_device *device,
+		     struct nv04_fifo_priv *priv, u32 chid)
+{
+	const char *client_name;
+	u32 dma_get = nv_rd32(priv, 0x003244);
+	u32 dma_put = nv_rd32(priv, 0x003240);
+	u32 push = nv_rd32(priv, 0x003220);
+	u32 state = nv_rd32(priv, 0x003228);
+
+	client_name = nvkm_client_name_for_fifo_chid(&priv->base, chid);
+
+	if (device->card_type == NV_50) {
+		u32 ho_get = nv_rd32(priv, 0x003328);
+		u32 ho_put = nv_rd32(priv, 0x003320);
+		u32 ib_get = nv_rd32(priv, 0x003334);
+		u32 ib_put = nv_rd32(priv, 0x003330);
+
+		nv_error(priv,
+			 "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
+			 chid, client_name, ho_get, dma_get, ho_put, dma_put,
+			 ib_get, ib_put, state, nv_dma_state_err(state), push);
+
+		/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+		nv_wr32(priv, 0x003364, 0x00000000);
+		if (dma_get != dma_put || ho_get != ho_put) {
+			nv_wr32(priv, 0x003244, dma_put);
+			nv_wr32(priv, 0x003328, ho_put);
+		} else
+		if (ib_get != ib_put)
+			nv_wr32(priv, 0x003334, ib_put);
+	} else {
+		nv_error(priv,
+			 "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
+			 chid, client_name, dma_get, dma_put, state,
+			 nv_dma_state_err(state), push);
+
+		if (dma_get != dma_put)
+			nv_wr32(priv, 0x003244, dma_put);
+	}
+
+	nv_wr32(priv, 0x003228, 0x00000000);
+	nv_wr32(priv, 0x003220, 0x00000001);
+	nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+}
+
+void
+nv04_fifo_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_device *device = nv_device(subdev);
+	struct nv04_fifo_priv *priv = (void *)subdev;
+	uint32_t status, reassign;
+	int cnt = 0;
+
+	reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
+	while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
+		uint32_t chid, get;
+
+		nv_wr32(priv, NV03_PFIFO_CACHES, 0);
+
+		chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+		get  = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+
+		if (status & NV_PFIFO_INTR_CACHE_ERROR) {
+			nv04_fifo_cache_error(device, priv, chid, get);
+			status &= ~NV_PFIFO_INTR_CACHE_ERROR;
+		}
+
+		if (status & NV_PFIFO_INTR_DMA_PUSHER) {
+			nv04_fifo_dma_pusher(device, priv, chid);
+			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
+		}
+
+		if (status & NV_PFIFO_INTR_SEMAPHORE) {
+			uint32_t sem;
+
+			status &= ~NV_PFIFO_INTR_SEMAPHORE;
+			nv_wr32(priv, NV03_PFIFO_INTR_0,
+				NV_PFIFO_INTR_SEMAPHORE);
+
+			sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+			nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+
+			nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+			nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+		}
+
+		if (device->card_type == NV_50) {
+			if (status & 0x00000010) {
+				status &= ~0x00000010;
+				nv_wr32(priv, 0x002100, 0x00000010);
+			}
+
+			if (status & 0x40000000) {
+				nv_wr32(priv, 0x002100, 0x40000000);
+				nvkm_fifo_uevent(&priv->base);
+				status &= ~0x40000000;
+			}
+		}
+
+		if (status) {
+			nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
+				status, chid);
+			nv_wr32(priv, NV03_PFIFO_INTR_0, status);
+			status = 0;
+		}
+
+		nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
+	}
+
+	if (status) {
+		nv_error(priv, "still angry after %d spins, halt\n", cnt);
+		nv_wr32(priv, 0x002140, 0);
+		nv_wr32(priv, 0x000140, 0);
+	}
+
+	nv_wr32(priv, 0x000100, 0x00000100);
+}
+
+static int
+nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nvkm_ramht_ref(imem->ramht, &priv->ramht);
+	nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+	nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv04_fifo_cclass;
+	nv_engine(priv)->sclass = nv04_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv04_ramfc;
+	return 0;
+}
+
+void
+nv04_fifo_dtor(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object;
+	nvkm_gpuobj_ref(NULL, &priv->ramfc);
+	nvkm_gpuobj_ref(NULL, &priv->ramro);
+	nvkm_ramht_ref(NULL, &priv->ramht);
+	nvkm_fifo_destroy(&priv->base);
+}
+
+int
+nv04_fifo_init(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->gpuobj.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv04_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
new file mode 100644
index 0000000..e0e0c47
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
@@ -0,0 +1,175 @@
+#ifndef __NV04_FIFO_H__
+#define __NV04_FIFO_H__
+#include <engine/fifo.h>
+
+#define NV04_PFIFO_DELAY_0                                 0x00002040
+#define NV04_PFIFO_DMA_TIMESLICE                           0x00002044
+#define NV04_PFIFO_NEXT_CHANNEL                            0x00002050
+#define NV03_PFIFO_INTR_0                                  0x00002100
+#define NV03_PFIFO_INTR_EN_0                               0x00002140
+#    define NV_PFIFO_INTR_CACHE_ERROR                          (1<<0)
+#    define NV_PFIFO_INTR_RUNOUT                               (1<<4)
+#    define NV_PFIFO_INTR_RUNOUT_OVERFLOW                      (1<<8)
+#    define NV_PFIFO_INTR_DMA_PUSHER                          (1<<12)
+#    define NV_PFIFO_INTR_DMA_PT                              (1<<16)
+#    define NV_PFIFO_INTR_SEMAPHORE                           (1<<20)
+#    define NV_PFIFO_INTR_ACQUIRE_TIMEOUT                     (1<<24)
+#define NV03_PFIFO_RAMHT                                   0x00002210
+#define NV03_PFIFO_RAMFC                                   0x00002214
+#define NV03_PFIFO_RAMRO                                   0x00002218
+#define NV40_PFIFO_RAMFC                                   0x00002220
+#define NV03_PFIFO_CACHES                                  0x00002500
+#define NV04_PFIFO_MODE                                    0x00002504
+#define NV04_PFIFO_DMA                                     0x00002508
+#define NV04_PFIFO_SIZE                                    0x0000250c
+#define NV50_PFIFO_CTX_TABLE(c)                        (0x2600+(c)*4)
+#define NV50_PFIFO_CTX_TABLE__SIZE                                128
+#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED                  (1<<31)
+#define NV50_PFIFO_CTX_TABLE_UNK30_BAD                        (1<<30)
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80             0x0FFFFFFF
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84             0x00FFFFFF
+#define NV03_PFIFO_CACHE0_PUSH0                            0x00003000
+#define NV03_PFIFO_CACHE0_PULL0                            0x00003040
+#define NV04_PFIFO_CACHE0_PULL0                            0x00003050
+#define NV04_PFIFO_CACHE0_PULL1                            0x00003054
+#define NV03_PFIFO_CACHE1_PUSH0                            0x00003200
+#define NV03_PFIFO_CACHE1_PUSH1                            0x00003204
+#define NV03_PFIFO_CACHE1_PUSH1_DMA                            (1<<8)
+#define NV40_PFIFO_CACHE1_PUSH1_DMA                           (1<<16)
+#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000000f
+#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000001f
+#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK                  0x0000007f
+#define NV03_PFIFO_CACHE1_PUT                              0x00003210
+#define NV04_PFIFO_CACHE1_DMA_PUSH                         0x00003220
+#define NV04_PFIFO_CACHE1_DMA_FETCH                        0x00003224
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES         0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES        0x00000008
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES        0x00000010
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES        0x00000018
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES        0x00000020
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES        0x00000028
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES        0x00000030
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES        0x00000038
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES        0x00000040
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES        0x00000048
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES        0x00000050
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES        0x00000058
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES       0x00000060
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES       0x00000068
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES       0x00000070
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES       0x00000078
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES       0x00000080
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES       0x00000088
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES       0x00000090
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES       0x00000098
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES       0x000000A0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES       0x000000A8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES       0x000000B0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES       0x000000B8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES       0x000000C0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES       0x000000C8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES       0x000000D0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES       0x000000D8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES       0x000000E0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES       0x000000E8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES       0x000000F0
+#    define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES       0x000000F8
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE                 0x0000E000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES        0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES        0x00002000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES        0x00004000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES       0x00006000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES       0x00008000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES       0x0000A000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES       0x0000C000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES       0x0000E000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS             0x001F0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0           0x00000000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1           0x00010000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2           0x00020000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3           0x00030000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4           0x00040000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5           0x00050000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6           0x00060000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7           0x00070000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8           0x00080000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9           0x00090000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10          0x000A0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11          0x000B0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12          0x000C0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13          0x000D0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14          0x000E0000
+#    define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15          0x000F0000
+#    define NV_PFIFO_CACHE1_ENDIAN                         0x80000000
+#    define NV_PFIFO_CACHE1_LITTLE_ENDIAN                  0x7FFFFFFF
+#    define NV_PFIFO_CACHE1_BIG_ENDIAN                     0x80000000
+#define NV04_PFIFO_CACHE1_DMA_STATE                        0x00003228
+#define NV04_PFIFO_CACHE1_DMA_INSTANCE                     0x0000322c
+#define NV04_PFIFO_CACHE1_DMA_CTL                          0x00003230
+#define NV04_PFIFO_CACHE1_DMA_PUT                          0x00003240
+#define NV04_PFIFO_CACHE1_DMA_GET                          0x00003244
+#define NV10_PFIFO_CACHE1_REF_CNT                          0x00003248
+#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE                   0x0000324C
+#define NV03_PFIFO_CACHE1_PULL0                            0x00003240
+#define NV04_PFIFO_CACHE1_PULL0                            0x00003250
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED            0x00000010
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY              0x00001000
+#define NV03_PFIFO_CACHE1_PULL1                            0x00003250
+#define NV04_PFIFO_CACHE1_PULL1                            0x00003254
+#define NV04_PFIFO_CACHE1_HASH                             0x00003258
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT                  0x00003260
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP                0x00003264
+#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE                    0x00003268
+#define NV10_PFIFO_CACHE1_SEMAPHORE                        0x0000326C
+#define NV03_PFIFO_CACHE1_GET                              0x00003270
+#define NV04_PFIFO_CACHE1_ENGINE                           0x00003280
+#define NV04_PFIFO_CACHE1_DMA_DCOUNT                       0x000032A0
+#define NV40_PFIFO_GRCTX_INSTANCE                          0x000032E0
+#define NV40_PFIFO_UNK32E4                                 0x000032E4
+#define NV04_PFIFO_CACHE1_METHOD(i)                (0x00003800+(i*8))
+#define NV04_PFIFO_CACHE1_DATA(i)                  (0x00003804+(i*8))
+#define NV40_PFIFO_CACHE1_METHOD(i)                (0x00090000+(i*8))
+#define NV40_PFIFO_CACHE1_DATA(i)                  (0x00090004+(i*8))
+
+struct ramfc_desc {
+	unsigned bits:6;
+	unsigned ctxs:5;
+	unsigned ctxp:8;
+	unsigned regs:5;
+	unsigned regp;
+};
+
+struct nv04_fifo_priv {
+	struct nvkm_fifo base;
+	struct ramfc_desc *ramfc_desc;
+	struct nvkm_ramht  *ramht;
+	struct nvkm_gpuobj *ramro;
+	struct nvkm_gpuobj *ramfc;
+};
+
+struct nv04_fifo_base {
+	struct nvkm_fifo_base base;
+};
+
+struct nv04_fifo_chan {
+	struct nvkm_fifo_chan base;
+	u32 subc[8];
+	u32 ramfc;
+};
+
+int  nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32);
+void nv04_fifo_object_detach(struct nvkm_object *, int);
+
+void nv04_fifo_chan_dtor(struct nvkm_object *);
+int  nv04_fifo_chan_init(struct nvkm_object *);
+int  nv04_fifo_chan_fini(struct nvkm_object *, bool suspend);
+
+int  nv04_fifo_context_ctor(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, void *, u32,
+			    struct nvkm_object **);
+
+void nv04_fifo_dtor(struct nvkm_object *);
+int  nv04_fifo_init(struct nvkm_object *);
+void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *);
+void nv04_fifo_start(struct nvkm_fifo *, unsigned long *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
new file mode 100644
index 0000000..48ce4af
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv10_ramfc[] = {
+	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
+	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
+	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
+	{ 16,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+	{ 16, 16, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_STATE },
+	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
+	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_ENGINE },
+	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_PULL1 },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv10_fifo_chan_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+				       0x10000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+	chan->ramfc = chan->base.chid * 32;
+
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
+			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+			     NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nv10_fifo_ofuncs = {
+	.ctor = nv10_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv10_fifo_sclass[] = {
+	{ NV10_CHANNEL_DMA, &nv10_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv10_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x10),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nvkm_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nvkm_ramht_ref(imem->ramht, &priv->ramht);
+	nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+	nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv10_fifo_cclass;
+	nv_engine(priv)->sclass = nv10_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv10_ramfc;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv10_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x10),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv04_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
new file mode 100644
index 0000000..4a20a6f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv17_ramfc[] = {
+	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
+	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
+	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
+	{ 16,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+	{ 16, 16, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_STATE },
+	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
+	{ 32,  0, 0x18,  0, NV04_PFIFO_CACHE1_ENGINE },
+	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_PULL1 },
+	{ 32,  0, 0x20,  0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+	{ 32,  0, 0x24,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+	{ 32,  0, 0x28,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+	{ 32,  0, 0x2c,  0, NV10_PFIFO_CACHE1_SEMAPHORE },
+	{ 32,  0, 0x30,  0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv17_fifo_chan_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+				       0x10000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
+				       &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+	chan->ramfc = chan->base.chid * 64;
+
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x14,
+			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+			     NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nv17_fifo_ofuncs = {
+	.ctor = nv17_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv17_fifo_sclass[] = {
+	{ NV17_CHANNEL_DMA, &nv17_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv17_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x17),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nvkm_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nvkm_ramht_ref(imem->ramht, &priv->ramht);
+	nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+	nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv17_fifo_cclass;
+	nv_engine(priv)->sclass = nv17_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv17_ramfc;
+	return 0;
+}
+
+static int
+nv17_fifo_init(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+	nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->gpuobj.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+	nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv17_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x17),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv17_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv17_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
new file mode 100644
index 0000000..5bfc962
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/fb.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv40_ramfc[] = {
+	{ 32,  0, 0x00,  0, NV04_PFIFO_CACHE1_DMA_PUT },
+	{ 32,  0, 0x04,  0, NV04_PFIFO_CACHE1_DMA_GET },
+	{ 32,  0, 0x08,  0, NV10_PFIFO_CACHE1_REF_CNT },
+	{ 32,  0, 0x0c,  0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+	{ 32,  0, 0x10,  0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+	{ 32,  0, 0x14,  0, NV04_PFIFO_CACHE1_DMA_STATE },
+	{ 28,  0, 0x18,  0, NV04_PFIFO_CACHE1_DMA_FETCH },
+	{  2, 28, 0x18, 28, 0x002058 },
+	{ 32,  0, 0x1c,  0, NV04_PFIFO_CACHE1_ENGINE },
+	{ 32,  0, 0x20,  0, NV04_PFIFO_CACHE1_PULL1 },
+	{ 32,  0, 0x24,  0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+	{ 32,  0, 0x28,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+	{ 32,  0, 0x2c,  0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+	{ 32,  0, 0x30,  0, NV10_PFIFO_CACHE1_SEMAPHORE },
+	{ 32,  0, 0x34,  0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+	{ 32,  0, 0x38,  0, NV40_PFIFO_GRCTX_INSTANCE },
+	{ 17,  0, 0x3c,  0, NV04_PFIFO_DMA_TIMESLICE },
+	{ 32,  0, 0x40,  0, 0x0032e4 },
+	{ 32,  0, 0x44,  0, 0x0032e8 },
+	{ 32,  0, 0x4c,  0, 0x002088 },
+	{ 32,  0, 0x50,  0, 0x003300 },
+	{ 32,  0, 0x54,  0, 0x00330c },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv40_fifo_object_attach(struct nvkm_object *parent,
+			struct nvkm_object *object, u32 handle)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	u32 context, chid = chan->base.chid;
+	int ret;
+
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->addr >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW:
+		context |= 0x00000000;
+		break;
+	case NVDEV_ENGINE_GR:
+		context |= 0x00100000;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		context |= 0x00200000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	context |= chid << 23;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	ret = nvkm_ramht_insert(priv->ramht, chid, handle, context);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+	return ret;
+}
+
+static int
+nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	unsigned long flags;
+	u32 reg, ctx;
+
+	switch (nv_engidx(engctx->engine)) {
+	case NVDEV_ENGINE_SW:
+		return 0;
+	case NVDEV_ENGINE_GR:
+		reg = 0x32e0;
+		ctx = 0x38;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		reg = 0x330c;
+		ctx = 0x54;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+		nv_wr32(priv, reg, nv_engctx(engctx)->addr);
+	nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
+
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return 0;
+}
+
+static int
+nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+			 struct nvkm_object *engctx)
+{
+	struct nv04_fifo_priv *priv = (void *)parent->engine;
+	struct nv04_fifo_chan *chan = (void *)parent;
+	unsigned long flags;
+	u32 reg, ctx;
+
+	switch (nv_engidx(engctx->engine)) {
+	case NVDEV_ENGINE_SW:
+		return 0;
+	case NVDEV_ENGINE_GR:
+		reg = 0x32e0;
+		ctx = 0x38;
+		break;
+	case NVDEV_ENGINE_MPEG:
+		reg = 0x330c;
+		ctx = 0x54;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->base.lock, flags);
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+	if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+		nv_wr32(priv, reg, 0x00000000);
+	nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
+
+	nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->base.lock, flags);
+	return 0;
+}
+
+static int
+nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nv04_fifo_priv *priv = (void *)engine;
+	struct nv04_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+				       0x1000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->context_attach = nv40_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv40_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv40_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+	chan->ramfc = chan->base.chid * 128;
+
+	nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
+			     NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+			     NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+	nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nv40_fifo_ofuncs = {
+	.ctor = nv40_fifo_chan_ctor,
+	.dtor = nv04_fifo_chan_dtor,
+	.init = nv04_fifo_chan_init,
+	.fini = nv04_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv40_fifo_sclass[] = {
+	{ NV40_CHANNEL_DMA, &nv40_fifo_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv40_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fifo_context_ctor,
+		.dtor = _nvkm_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *imem = nv04_instmem(parent);
+	struct nv04_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nvkm_ramht_ref(imem->ramht, &priv->ramht);
+	nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+	nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv40_fifo_cclass;
+	nv_engine(priv)->sclass = nv40_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	priv->ramfc_desc = nv40_ramfc;
+	return 0;
+}
+
+static int
+nv40_fifo_init(struct nvkm_object *object)
+{
+	struct nv04_fifo_priv *priv = (void *)object;
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	int ret;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x002040, 0x000000ff);
+	nv_wr32(priv, 0x002044, 0x2101ffff);
+	nv_wr32(priv, 0x002058, 0x00000001);
+
+	nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+				       ((priv->ramht->bits - 9) << 16) |
+				        (priv->ramht->gpuobj.addr >> 8));
+	nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+
+	switch (nv_device(priv)->chipset) {
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		nv_wr32(priv, 0x002230, 0x00000001);
+	case 0x40:
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x45:
+	case 0x48:
+		nv_wr32(priv, 0x002220, 0x00030002);
+		break;
+	default:
+		nv_wr32(priv, 0x002230, 0x00000000);
+		nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
+					 priv->ramfc->addr) >> 16) |
+					0x00030000);
+		break;
+	}
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+	nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+	nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+	nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+	nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv40_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_fifo_ctor,
+		.dtor = nv04_fifo_dtor,
+		.init = nv40_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
new file mode 100644
index 0000000..f25f0fd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
+{
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct nvkm_gpuobj *cur;
+	int i, p;
+
+	cur = priv->playlist[priv->cur_playlist];
+	priv->cur_playlist = !priv->cur_playlist;
+
+	for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
+		if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
+			nv_wo32(cur, p++ * 4, i);
+	}
+
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x0032f4, cur->addr >> 12);
+	nv_wr32(priv, 0x0032ec, p);
+	nv_wr32(priv, 0x002500, 0x00000101);
+}
+
+void
+nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
+{
+	mutex_lock(&nv_subdev(priv)->mutex);
+	nv50_fifo_playlist_update_locked(priv);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nvkm_gpuobj *ectx = (void *)object;
+	u64 limit = ectx->addr + ectx->size - 1;
+	u64 start = ectx->addr;
+	u32 addr;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	default:
+		return -EINVAL;
+	}
+
+	nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+	nv_wo32(base->eng, addr + 0x00, 0x00190000);
+	nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+	nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+	nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+					upper_32_bits(start));
+	nv_wo32(base->eng, addr + 0x10, 0x00000000);
+	nv_wo32(base->eng, addr + 0x14, 0x00000000);
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+			 struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_priv *priv = (void *)parent->engine;
+	struct nv50_fifo_base *base = (void *)parent->parent;
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 addr, me;
+	int ret = 0;
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_SW   : return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0000; break;
+	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	default:
+		return -EINVAL;
+	}
+
+	/* HW bug workaround:
+	 *
+	 * PFIFO will hang forever if the connected engines don't report
+	 * that they've processed the context switch request.
+	 *
+	 * In order for the kickoff to work, we need to ensure all the
+	 * connected engines are in a state where they can answer.
+	 *
+	 * Newer chipsets don't seem to suffer from this issue, and well,
+	 * there's also a "ignore these engines" bitmask reg we can use
+	 * if we hit the issue there..
+	 */
+	me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
+
+	/* do the kickoff... */
+	nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+	if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
+		nv_error(priv, "channel %d [%s] unload timeout\n",
+			 chan->base.chid, nvkm_client_name(chan));
+		if (suspend)
+			ret = -EBUSY;
+	}
+	nv_wr32(priv, 0x00b860, me);
+
+	if (ret == 0) {
+		nv_wo32(base->eng, addr + 0x00, 0x00000000);
+		nv_wo32(base->eng, addr + 0x04, 0x00000000);
+		nv_wo32(base->eng, addr + 0x08, 0x00000000);
+		nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+		nv_wo32(base->eng, addr + 0x10, 0x00000000);
+		nv_wo32(base->eng, addr + 0x14, 0x00000000);
+		bar->flush(bar);
+	}
+
+	return ret;
+}
+
+static int
+nv50_fifo_object_attach(struct nvkm_object *parent,
+			struct nvkm_object *object, u32 handle)
+{
+	struct nv50_fifo_chan *chan = (void *)parent;
+	u32 context;
+
+	if (nv_iclass(object, NV_GPUOBJ_CLASS))
+		context = nv_gpuobj(object)->node->offset >> 4;
+	else
+		context = 0x00000004; /* just non-zero */
+
+	switch (nv_engidx(object->engine)) {
+	case NVDEV_ENGINE_DMAOBJ:
+	case NVDEV_ENGINE_SW    : context |= 0x00000000; break;
+	case NVDEV_ENGINE_GR    : context |= 0x00100000; break;
+	case NVDEV_ENGINE_MPEG  : context |= 0x00200000; break;
+	default:
+		return -EINVAL;
+	}
+
+	return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+}
+
+void
+nv50_fifo_object_detach(struct nvkm_object *parent, int cookie)
+{
+	struct nv50_fifo_chan *chan = (void *)parent;
+	nvkm_ramht_remove(chan->ramht, cookie);
+}
+
+static int
+nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine,
+			struct nvkm_oclass *oclass, void *data, u32 size,
+			struct nvkm_object **pobject)
+{
+	union {
+		struct nv03_channel_dma_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	int ret;
+
+	nv_ioctl(parent, "create channel dma size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+				 "offset %016llx\n", args->v0.version,
+			 args->v0.pushbuf, args->v0.offset);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+				       0x2000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->context_attach = nv50_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv50_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv50_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+			     &chan->ramht);
+	if (ret)
+		return ret;
+
+	nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
+	nv_wo32(base->ramfc, 0x3c, 0x003f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x4c, 0xffffffff);
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+				   (4 << 24) /* SEARCH_FULL */ |
+				   (chan->ramht->gpuobj.node->offset >> 4));
+	bar->flush(bar);
+	return 0;
+}
+
+static int
+nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine,
+			struct nvkm_oclass *oclass, void *data, u32 size,
+			struct nvkm_object **pobject)
+{
+	union {
+		struct nv50_channel_gpfifo_v0 v0;
+	} *args = data;
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_fifo_base *base = (void *)parent;
+	struct nv50_fifo_chan *chan;
+	u64 ioffset, ilength;
+	int ret;
+
+	nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+				 "ioffset %016llx ilength %08x\n",
+			 args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+			 args->v0.ilength);
+	} else
+		return ret;
+
+	ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+				       0x2000, args->v0.pushbuf,
+				       (1ULL << NVDEV_ENGINE_DMAOBJ) |
+				       (1ULL << NVDEV_ENGINE_SW) |
+				       (1ULL << NVDEV_ENGINE_GR) |
+				       (1ULL << NVDEV_ENGINE_MPEG), &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	args->v0.chid = chan->base.chid;
+
+	nv_parent(chan)->context_attach = nv50_fifo_context_attach;
+	nv_parent(chan)->context_detach = nv50_fifo_context_detach;
+	nv_parent(chan)->object_attach = nv50_fifo_object_attach;
+	nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+	ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+			     &chan->ramht);
+	if (ret)
+		return ret;
+
+	ioffset = args->v0.ioffset;
+	ilength = order_base_2(args->v0.ilength / 8);
+
+	nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+	nv_wo32(base->ramfc, 0x44, 0x01003fff);
+	nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+	nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+	nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+	nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+	nv_wo32(base->ramfc, 0x78, 0x00000000);
+	nv_wo32(base->ramfc, 0x7c, 0x30000001);
+	nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+				   (4 << 24) /* SEARCH_FULL */ |
+				   (chan->ramht->gpuobj.node->offset >> 4));
+	bar->flush(bar);
+	return 0;
+}
+
+void
+nv50_fifo_chan_dtor(struct nvkm_object *object)
+{
+	struct nv50_fifo_chan *chan = (void *)object;
+	nvkm_ramht_ref(NULL, &chan->ramht);
+	nvkm_fifo_channel_destroy(&chan->base);
+}
+
+static int
+nv50_fifo_chan_init(struct nvkm_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_base *base = (void *)object->parent;
+	struct nv50_fifo_chan *chan = (void *)object;
+	struct nvkm_gpuobj *ramfc = base->ramfc;
+	u32 chid = chan->base.chid;
+	int ret;
+
+	ret = nvkm_fifo_channel_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
+	nv50_fifo_playlist_update(priv);
+	return 0;
+}
+
+int
+nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_fifo_priv *priv = (void *)object->engine;
+	struct nv50_fifo_chan *chan = (void *)object;
+	u32 chid = chan->base.chid;
+
+	/* remove channel from playlist, fifo will unload context */
+	nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
+	nv50_fifo_playlist_update(priv);
+	nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
+
+	return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+nv50_fifo_ofuncs_dma = {
+	.ctor = nv50_fifo_chan_ctor_dma,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = nv50_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_ofuncs
+nv50_fifo_ofuncs_ind = {
+	.ctor = nv50_fifo_chan_ctor_ind,
+	.dtor = nv50_fifo_chan_dtor,
+	.init = nv50_fifo_chan_init,
+	.fini = nv50_fifo_chan_fini,
+	.map  = _nvkm_fifo_channel_map,
+	.rd32 = _nvkm_fifo_channel_rd32,
+	.wr32 = _nvkm_fifo_channel_wr32,
+	.ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv50_fifo_sclass[] = {
+	{ NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma },
+	{ NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind },
+	{}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static int
+nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nv50_fifo_base *base;
+	int ret;
+
+	ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+				       0x1000, NVOBJ_FLAG_HEAP, &base);
+	*pobject = nv_object(base);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
+			      0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
+			      NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
+			      &base->pgd);
+	if (ret)
+		return ret;
+
+	ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void
+nv50_fifo_context_dtor(struct nvkm_object *object)
+{
+	struct nv50_fifo_base *base = (void *)object;
+	nvkm_vm_ref(NULL, &base->vm, base->pgd);
+	nvkm_gpuobj_ref(NULL, &base->pgd);
+	nvkm_gpuobj_ref(NULL, &base->eng);
+	nvkm_gpuobj_ref(NULL, &base->ramfc);
+	nvkm_gpuobj_ref(NULL, &base->cache);
+	nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+nv50_fifo_cclass = {
+	.handle = NV_ENGCTX(FIFO, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fifo_context_ctor,
+		.dtor = nv50_fifo_context_dtor,
+		.init = _nvkm_fifo_context_init,
+		.fini = _nvkm_fifo_context_fini,
+		.rd32 = _nvkm_fifo_context_rd32,
+		.wr32 = _nvkm_fifo_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv50_fifo_priv *priv;
+	int ret;
+
+	ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+			      &priv->playlist[0]);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+			      &priv->playlist[1]);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000100;
+	nv_subdev(priv)->intr = nv04_fifo_intr;
+	nv_engine(priv)->cclass = &nv50_fifo_cclass;
+	nv_engine(priv)->sclass = nv50_fifo_sclass;
+	priv->base.pause = nv04_fifo_pause;
+	priv->base.start = nv04_fifo_start;
+	return 0;
+}
+
+void
+nv50_fifo_dtor(struct nvkm_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object;
+
+	nvkm_gpuobj_ref(NULL, &priv->playlist[1]);
+	nvkm_gpuobj_ref(NULL, &priv->playlist[0]);
+
+	nvkm_fifo_destroy(&priv->base);
+}
+
+int
+nv50_fifo_init(struct nvkm_object *object)
+{
+	struct nv50_fifo_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nvkm_fifo_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+	nv_wr32(priv, 0x00250c, 0x6f3cfc34);
+	nv_wr32(priv, 0x002044, 0x01003fff);
+
+	nv_wr32(priv, 0x002100, 0xffffffff);
+	nv_wr32(priv, 0x002140, 0xbfffffff);
+
+	for (i = 0; i < 128; i++)
+		nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
+	nv50_fifo_playlist_update_locked(priv);
+
+	nv_wr32(priv, 0x003200, 0x00000001);
+	nv_wr32(priv, 0x003250, 0x00000001);
+	nv_wr32(priv, 0x002500, 0x00000001);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_fifo_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(FIFO, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fifo_ctor,
+		.dtor = nv50_fifo_dtor,
+		.init = nv50_fifo_init,
+		.fini = _nvkm_fifo_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
new file mode 100644
index 0000000..09ed93c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
@@ -0,0 +1,36 @@
+#ifndef __NV50_FIFO_H__
+#define __NV50_FIFO_H__
+#include <engine/fifo.h>
+
+struct nv50_fifo_priv {
+	struct nvkm_fifo base;
+	struct nvkm_gpuobj *playlist[2];
+	int cur_playlist;
+};
+
+struct nv50_fifo_base {
+	struct nvkm_fifo_base base;
+	struct nvkm_gpuobj *ramfc;
+	struct nvkm_gpuobj *cache;
+	struct nvkm_gpuobj *eng;
+	struct nvkm_gpuobj *pgd;
+	struct nvkm_vm *vm;
+};
+
+struct nv50_fifo_chan {
+	struct nvkm_fifo_chan base;
+	u32 subc[8];
+	struct nvkm_ramht *ramht;
+};
+
+void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
+
+void nv50_fifo_object_detach(struct nvkm_object *, int);
+void nv50_fifo_chan_dtor(struct nvkm_object *);
+int  nv50_fifo_chan_fini(struct nvkm_object *, bool);
+
+void nv50_fifo_context_dtor(struct nvkm_object *);
+
+void nv50_fifo_dtor(struct nvkm_object *);
+int  nv50_fifo_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
new file mode 100644
index 0000000..1771d94
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
@@ -0,0 +1,36 @@
+nvkm-y += nvkm/engine/gr/ctxnv40.o
+nvkm-y += nvkm/engine/gr/ctxnv50.o
+nvkm-y += nvkm/engine/gr/ctxgf100.o
+nvkm-y += nvkm/engine/gr/ctxgf108.o
+nvkm-y += nvkm/engine/gr/ctxgf104.o
+nvkm-y += nvkm/engine/gr/ctxgf110.o
+nvkm-y += nvkm/engine/gr/ctxgf117.o
+nvkm-y += nvkm/engine/gr/ctxgf119.o
+nvkm-y += nvkm/engine/gr/ctxgk104.o
+nvkm-y += nvkm/engine/gr/ctxgk20a.o
+nvkm-y += nvkm/engine/gr/ctxgk110.o
+nvkm-y += nvkm/engine/gr/ctxgk110b.o
+nvkm-y += nvkm/engine/gr/ctxgk208.o
+nvkm-y += nvkm/engine/gr/ctxgm107.o
+nvkm-y += nvkm/engine/gr/nv04.o
+nvkm-y += nvkm/engine/gr/nv10.o
+nvkm-y += nvkm/engine/gr/nv20.o
+nvkm-y += nvkm/engine/gr/nv25.o
+nvkm-y += nvkm/engine/gr/nv2a.o
+nvkm-y += nvkm/engine/gr/nv30.o
+nvkm-y += nvkm/engine/gr/nv34.o
+nvkm-y += nvkm/engine/gr/nv35.o
+nvkm-y += nvkm/engine/gr/nv40.o
+nvkm-y += nvkm/engine/gr/nv50.o
+nvkm-y += nvkm/engine/gr/gf100.o
+nvkm-y += nvkm/engine/gr/gf108.o
+nvkm-y += nvkm/engine/gr/gf104.o
+nvkm-y += nvkm/engine/gr/gf110.o
+nvkm-y += nvkm/engine/gr/gf117.o
+nvkm-y += nvkm/engine/gr/gf119.o
+nvkm-y += nvkm/engine/gr/gk104.o
+nvkm-y += nvkm/engine/gr/gk20a.o
+nvkm-y += nvkm/engine/gr/gk110.o
+nvkm-y += nvkm/engine/gr/gk110b.o
+nvkm-y += nvkm/engine/gr/gk208.o
+nvkm-y += nvkm/engine/gr/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
new file mode 100644
index 0000000..2e7ec38
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "ctxgf100.h"
+
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf100_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_icmd[] = {
+	{ gf100_grctx_init_icmd_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_9097_0[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x002700,   8, 0x20, 0x00000000 },
+	{ 0x002704,   8, 0x20, 0x00000000 },
+	{ 0x002708,   8, 0x20, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   8, 0x20, 0x00014000 },
+	{ 0x002714,   8, 0x20, 0x00000040 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002200,   5, 0x10, 0x00000022 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00001fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x003fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   4, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   1, 0x04, 0x003fffff },
+	{ 0x0002d0,   1, 0x04, 0x00000c48 },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00300008 },
+	{ 0x001284,   1, 0x04, 0x04000080 },
+	{ 0x001450,   1, 0x04, 0x00300008 },
+	{ 0x001454,   1, 0x04, 0x04000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_902d_0[] = {
+	{ 0x000200,   1, 0x04, 0x000000cf },
+	{ 0x000204,   1, 0x04, 0x00000001 },
+	{ 0x000208,   1, 0x04, 0x00000020 },
+	{ 0x00020c,   1, 0x04, 0x00000001 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000080 },
+	{ 0x000218,   2, 0x04, 0x00000100 },
+	{ 0x000220,   2, 0x04, 0x00000000 },
+	{ 0x000230,   1, 0x04, 0x000000cf },
+	{ 0x000234,   1, 0x04, 0x00000001 },
+	{ 0x000238,   1, 0x04, 0x00000020 },
+	{ 0x00023c,   1, 0x04, 0x00000001 },
+	{ 0x000244,   1, 0x04, 0x00000080 },
+	{ 0x000248,   2, 0x04, 0x00000100 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_9039_0[] = {
+	{ 0x00030c,   3, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000238,   2, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_90c0_0[] = {
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x000758,   1, 0x04, 0x00000100 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x000204,   3, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{ 0x00024c,   1, 0x04, 0x00000000 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_mthd[] = {
+	{ gf100_grctx_init_9097_0, 0x9097 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{ gf100_grctx_init_9039_0, 0x9039 },
+	{ gf100_grctx_init_90c0_0, 0x90c0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_main_0[] = {
+	{ 0x400204,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_fe_0[] = {
+	{ 0x404004,  11, 0x04, 0x00000000 },
+	{ 0x404044,   1, 0x04, 0x00000000 },
+	{ 0x404094,  13, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf0000087 },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x404168,   1, 0x04, 0x00000000 },
+	{ 0x404174,   3, 0x04, 0x00000000 },
+	{ 0x404200,   8, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_pri_0[] = {
+	{ 0x404404,  14, 0x04, 0x00000000 },
+	{ 0x404460,   2, 0x04, 0x00000000 },
+	{ 0x404468,   1, 0x04, 0x00ffffff },
+	{ 0x40446c,   1, 0x04, 0x00000000 },
+	{ 0x404480,   1, 0x04, 0x00000001 },
+	{ 0x404498,   1, 0x04, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_memfmt_0[] = {
+	{ 0x404604,   1, 0x04, 0x00000015 },
+	{ 0x404608,   1, 0x04, 0x00000000 },
+	{ 0x40460c,   1, 0x04, 0x00002e00 },
+	{ 0x404610,   1, 0x04, 0x00000100 },
+	{ 0x404618,   8, 0x04, 0x00000000 },
+	{ 0x404638,   1, 0x04, 0x00000004 },
+	{ 0x40463c,   8, 0x04, 0x00000000 },
+	{ 0x40465c,   1, 0x04, 0x007f0100 },
+	{ 0x404660,   7, 0x04, 0x00000000 },
+	{ 0x40467c,   1, 0x04, 0x00000002 },
+	{ 0x404680,   8, 0x04, 0x00000000 },
+	{ 0x4046a0,   1, 0x04, 0x007f0080 },
+	{ 0x4046a4,  18, 0x04, 0x00000000 },
+	{ 0x4046f0,   2, 0x04, 0x00000000 },
+	{ 0x404700,  13, 0x04, 0x00000000 },
+	{ 0x404734,   1, 0x04, 0x00000100 },
+	{ 0x404738,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x078000bf },
+	{ 0x405830,   1, 0x04, 0x02180000 },
+	{ 0x405834,   2, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x000103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_rstr2d_0[] = {
+	{ 0x407804,   1, 0x04, 0x00000023 },
+	{ 0x40780c,   1, 0x04, 0x0a418820 },
+	{ 0x407810,   1, 0x04, 0x062080e6 },
+	{ 0x407814,   1, 0x04, 0x020398a4 },
+	{ 0x407818,   1, 0x04, 0x0e629062 },
+	{ 0x40781c,   1, 0x04, 0x0a418820 },
+	{ 0x407820,   1, 0x04, 0x000000e6 },
+	{ 0x4078bc,   1, 0x04, 0x00000103 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_scc_0[] = {
+	{ 0x408000,   2, 0x04, 0x00000000 },
+	{ 0x408008,   1, 0x04, 0x00000018 },
+	{ 0x40800c,   2, 0x04, 0x00000000 },
+	{ 0x408014,   1, 0x04, 0x00000069 },
+	{ 0x408018,   1, 0x04, 0xe100e100 },
+	{ 0x408064,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x0003e00d },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x02000001 },
+	{ 0x408908,   1, 0x04, 0x00c80929 },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gf100_grctx_init_fe_0 },
+	{ gf100_grctx_init_pri_0 },
+	{ gf100_grctx_init_memfmt_0 },
+	{ gf100_grctx_init_ds_0 },
+	{ gf100_grctx_init_pd_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gf100_grctx_init_scc_0 },
+	{ gf100_grctx_init_be_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpc_unk_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_prop_0[] = {
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x00200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpc_unk_1[] = {
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   1, 0x04, 0x00000000 },
+	{ 0x41870c,   1, 0x04, 0x07c80000 },
+	{ 0x418710,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x0006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x00000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x00100000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_zcull_0[] = {
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_crstr_0[] = {
+	{ 0x418b00,   1, 0x04, 0x00000000 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpm_0[] = {
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gcc_0[] = {
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf100_grctx_init_prop_0 },
+	{ gf100_grctx_init_gpc_unk_1 },
+	{ gf100_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf100_grctx_init_crstr_0 },
+	{ gf100_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_zcullr_0[] = {
+	{ 0x418a00,   3, 0x04, 0x00000000 },
+	{ 0x418a0c,   1, 0x04, 0x00010000 },
+	{ 0x418a10,   3, 0x04, 0x00000000 },
+	{ 0x418a20,   3, 0x04, 0x00000000 },
+	{ 0x418a2c,   1, 0x04, 0x00010000 },
+	{ 0x418a30,   3, 0x04, 0x00000000 },
+	{ 0x418a40,   3, 0x04, 0x00000000 },
+	{ 0x418a4c,   1, 0x04, 0x00010000 },
+	{ 0x418a50,   3, 0x04, 0x00000000 },
+	{ 0x418a60,   3, 0x04, 0x00000000 },
+	{ 0x418a6c,   1, 0x04, 0x00010000 },
+	{ 0x418a70,   3, 0x04, 0x00000000 },
+	{ 0x418a80,   3, 0x04, 0x00000000 },
+	{ 0x418a8c,   1, 0x04, 0x00010000 },
+	{ 0x418a90,   3, 0x04, 0x00000000 },
+	{ 0x418aa0,   3, 0x04, 0x00000000 },
+	{ 0x418aac,   1, 0x04, 0x00010000 },
+	{ 0x418ab0,   3, 0x04, 0x00000000 },
+	{ 0x418ac0,   3, 0x04, 0x00000000 },
+	{ 0x418acc,   1, 0x04, 0x00010000 },
+	{ 0x418ad0,   3, 0x04, 0x00000000 },
+	{ 0x418ae0,   3, 0x04, 0x00000000 },
+	{ 0x418aec,   1, 0x04, 0x00010000 },
+	{ 0x418af0,   3, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_zcull[] = {
+	{ gf100_grctx_init_zcullr_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_pe_0[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x0000012a },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_wwdx_0[] = {
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00000001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x00000002 },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_l1c_0[] = {
+	{ 0x419cb0,   1, 0x04, 0x00060048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_tpccs_0[] = {
+	{ 0x419d20,   1, 0x04, 0x02180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_sm_0[] = {
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419f50,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_tpc[] = {
+	{ gf100_grctx_init_pe_0 },
+	{ gf100_grctx_init_tex_0 },
+	{ gf100_grctx_init_wwdx_0 },
+	{ gf100_grctx_init_mpc_0 },
+	{ gf100_grctx_init_l1c_0 },
+	{ gf100_grctx_init_tpccs_0 },
+	{ gf100_grctx_init_sm_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+int
+gf100_grctx_mmio_data(struct gf100_grctx *info, u32 size, u32 align, u32 access)
+{
+	if (info->data) {
+		info->buffer[info->buffer_nr] = round_up(info->addr, align);
+		info->addr = info->buffer[info->buffer_nr] + size;
+		info->data->size = size;
+		info->data->align = align;
+		info->data->access = access;
+		info->data++;
+		return info->buffer_nr++;
+	}
+	return -1;
+}
+
+void
+gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data,
+		      int shift, int buffer)
+{
+	if (info->data) {
+		if (shift >= 0) {
+			info->mmio->addr = addr;
+			info->mmio->data = data;
+			info->mmio->shift = shift;
+			info->mmio->buffer = buffer;
+			if (buffer >= 0)
+				data |= info->buffer[buffer] >> shift;
+			info->mmio++;
+		} else
+			return;
+	} else {
+		if (buffer >= 0)
+			return;
+	}
+
+	nv_wr32(info->priv, addr, data);
+}
+
+void
+gf100_grctx_generate_bundle(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+	mmio_refn(info, 0x408004, 0x00000000, s, b);
+	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+	mmio_refn(info, 0x418808, 0x00000000, s, b);
+	mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+}
+
+void
+gf100_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+	mmio_refn(info, 0x40800c, 0x00000000, s, b);
+	mmio_wr32(info, 0x408010, 0x80000000);
+	mmio_refn(info, 0x419004, 0x00000000, s, b);
+	mmio_wr32(info, 0x419008, 0x00000000);
+}
+
+void
+gf100_grctx_generate_attrib(struct gf100_grctx *info)
+{
+	struct gf100_gr_priv *priv = info->priv;
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+	const u32 attrib = impl->attrib_nr;
+	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+	const u32 access = NV_MEM_ACCESS_RW;
+	const int s = 12;
+	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+	int gpc, tpc;
+	u32 bo = 0;
+
+	mmio_refn(info, 0x418810, 0x80000000, s, b);
+	mmio_refn(info, 0x419848, 0x10000000, s, b);
+	mmio_wr32(info, 0x405830, (attrib << 16));
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			const u32 o = TPC_UNIT(gpc, tpc, 0x0520);
+			mmio_skip(info, o, (attrib << 16) | ++bo);
+			mmio_wr32(info, o, (attrib << 16) | --bo);
+			bo += impl->attrib_nr_max;
+		}
+	}
+}
+
+void
+gf100_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+}
+
+void
+gf100_grctx_generate_tpcid(struct gf100_gr_priv *priv)
+{
+	int gpc, tpc, id;
+
+	for (tpc = 0, id = 0; tpc < 4; tpc++) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			if (tpc < priv->tpc_nr[gpc]) {
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
+				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+				id++;
+			}
+
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+		}
+	}
+}
+
+void
+gf100_grctx_generate_r406028(struct gf100_gr_priv *priv)
+{
+	u32 tmp[GPC_MAX / 8] = {}, i = 0;
+	for (i = 0; i < priv->gpc_nr; i++)
+		tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
+	for (i = 0; i < 4; i++) {
+		nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
+		nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
+	}
+}
+
+void
+gf100_grctx_generate_r4060a8(struct gf100_gr_priv *priv)
+{
+	u8  tpcnr[GPC_MAX], data[TPC_MAX];
+	int gpc, tpc, i;
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	memset(data, 0x1f, sizeof(data));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+		data[tpc] = gpc;
+	}
+
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+}
+
+void
+gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv)
+{
+	u32 data[6] = {}, data2[2] = {};
+	u8  tpcnr[GPC_MAX];
+	u8  shift, ntpcv;
+	int gpc, tpc, i;
+
+	/* calculate first set of magics */
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+
+		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+	}
+
+	for (; tpc < 32; tpc++)
+		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+	/* and the second... */
+	shift = 0;
+	ntpcv = priv->tpc_total;
+	while (!(ntpcv & (1 << 4))) {
+		ntpcv <<= 1;
+		shift++;
+	}
+
+	data2[0]  = (ntpcv << 16);
+	data2[0] |= (shift << 21);
+	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+	for (i = 1; i < 7; i++)
+		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+	/* GPC_BROADCAST */
+	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+	/* GPC_BROADCAST.TP_BROADCAST */
+	nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr | data2[0]);
+	nv_wr32(priv, 0x419be4, data2[1]);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
+
+	/* UNK78xx */
+	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+gf100_grctx_generate_r406800(struct gf100_gr_priv *priv)
+{
+	u64 tpc_mask = 0, tpc_set = 0;
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc;
+	int i, a, b;
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+		tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
+
+	for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+		a = (i * (priv->tpc_total - 1)) / 32;
+		if (a != b) {
+			b = a;
+			do {
+				gpc = (gpc + 1) % priv->gpc_nr;
+			} while (!tpcnr[gpc]);
+			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+			tpc_set |= 1ULL << ((gpc * 8) + tpc);
+		}
+
+		nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
+		nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
+		if (priv->gpc_nr > 4) {
+			nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
+			nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
+		}
+	}
+}
+
+void
+gf100_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+	struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+	gf100_gr_mmio(priv, oclass->hub);
+	gf100_gr_mmio(priv, oclass->gpc);
+	gf100_gr_mmio(priv, oclass->zcull);
+	gf100_gr_mmio(priv, oclass->tpc);
+	gf100_gr_mmio(priv, oclass->ppc);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->bundle(info);
+	oclass->pagepool(info);
+	oclass->attrib(info);
+	oclass->unkn(priv);
+
+	gf100_grctx_generate_tpcid(priv);
+	gf100_grctx_generate_r406028(priv);
+	gf100_grctx_generate_r4060a8(priv);
+	gf100_grctx_generate_r418bb8(priv);
+	gf100_grctx_generate_r406800(priv);
+
+	gf100_gr_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	gf100_gr_mthd(priv, oclass->mthd);
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+}
+
+int
+gf100_grctx_generate(struct gf100_gr_priv *priv)
+{
+	struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct nvkm_gpuobj *chan;
+	struct gf100_grctx info;
+	int ret, i;
+
+	/* allocate memory to for a "channel", which we'll use to generate
+	 * the default context values
+	 */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
+			      0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	if (ret) {
+		nv_error(priv, "failed to allocate channel memory, %d\n", ret);
+		return ret;
+	}
+
+	/* PGD pointer */
+	nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
+	nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
+	nv_wo32(chan, 0x0208, 0xffffffff);
+	nv_wo32(chan, 0x020c, 0x000000ff);
+
+	/* PGT[0] pointer */
+	nv_wo32(chan, 0x1000, 0x00000000);
+	nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
+
+	/* identity-map the whole "channel" into its own vm */
+	for (i = 0; i < chan->size / 4096; i++) {
+		u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
+		nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
+		nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
+	}
+
+	/* context pointer (virt) */
+	nv_wo32(chan, 0x0210, 0x00080004);
+	nv_wo32(chan, 0x0214, 0x00000000);
+
+	bar->flush(bar);
+
+	nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
+	nv_wr32(priv, 0x100cbc, 0x80000001);
+	nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
+
+	/* setup default state for mmio list construction */
+	info.priv = priv;
+	info.data = priv->mmio_data;
+	info.mmio = priv->mmio_list;
+	info.addr = 0x2000 + (i * 8);
+	info.buffer_nr = 0;
+
+	/* make channel current */
+	if (priv->firmware) {
+		nv_wr32(priv, 0x409840, 0x00000030);
+		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+		nv_wr32(priv, 0x409504, 0x00000003);
+		if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
+			nv_error(priv, "load_ctx timeout\n");
+
+		nv_wo32(chan, 0x8001c, 1);
+		nv_wo32(chan, 0x80020, 0);
+		nv_wo32(chan, 0x80028, 0);
+		nv_wo32(chan, 0x8002c, 0);
+		bar->flush(bar);
+	} else {
+		nv_wr32(priv, 0x409840, 0x80000000);
+		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+		nv_wr32(priv, 0x409504, 0x00000001);
+		if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
+			nv_error(priv, "HUB_SET_CHAN timeout\n");
+	}
+
+	oclass->main(priv, &info);
+
+	/* trigger a context unload by unsetting the "next channel valid" bit
+	 * and faking a context switch interrupt
+	 */
+	nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
+	nv_wr32(priv, 0x409000, 0x00000100);
+	if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
+		nv_error(priv, "grctx template channel unload timeout\n");
+		ret = -EBUSY;
+		goto done;
+	}
+
+	priv->data = kmalloc(priv->size, GFP_KERNEL);
+	if (priv->data) {
+		for (i = 0; i < priv->size; i += 4)
+			priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
+		ret = 0;
+	} else {
+		ret = -ENOMEM;
+	}
+
+done:
+	nvkm_gpuobj_ref(NULL, &chan);
+	return ret;
+}
+
+struct nvkm_oclass *
+gf100_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf100_grctx_generate_main,
+	.unkn  = gf100_grctx_generate_unkn,
+	.hub   = gf100_grctx_pack_hub,
+	.gpc   = gf100_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf100_grctx_pack_tpc,
+	.icmd  = gf100_grctx_pack_icmd,
+	.mthd  = gf100_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf100_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
new file mode 100644
index 0000000..1166b1a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
@@ -0,0 +1,199 @@
+#ifndef __NVKM_GRCTX_NVC0_H__
+#define __NVKM_GRCTX_NVC0_H__
+#include "gf100.h"
+
+struct gf100_grctx {
+	struct gf100_gr_priv *priv;
+	struct gf100_gr_data *data;
+	struct gf100_gr_mmio *mmio;
+	int buffer_nr;
+	u64 buffer[4];
+	u64 addr;
+};
+
+int  gf100_grctx_mmio_data(struct gf100_grctx *, u32 size, u32 align, u32 access);
+void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int);
+
+#define mmio_vram(a,b,c,d) gf100_grctx_mmio_data((a), (b), (c), (d))
+#define mmio_refn(a,b,c,d,e) gf100_grctx_mmio_item((a), (b), (c), (d), (e))
+#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1)
+#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c),  0, -1)
+
+struct gf100_grctx_oclass {
+	struct nvkm_oclass base;
+	/* main context generation function */
+	void  (*main)(struct gf100_gr_priv *, struct gf100_grctx *);
+	/* context-specific modify-on-first-load list generation function */
+	void  (*unkn)(struct gf100_gr_priv *);
+	/* mmio context data */
+	const struct gf100_gr_pack *hub;
+	const struct gf100_gr_pack *gpc;
+	const struct gf100_gr_pack *zcull;
+	const struct gf100_gr_pack *tpc;
+	const struct gf100_gr_pack *ppc;
+	/* indirect context data, generated with icmds/mthds */
+	const struct gf100_gr_pack *icmd;
+	const struct gf100_gr_pack *mthd;
+	/* bundle circular buffer */
+	void (*bundle)(struct gf100_grctx *);
+	u32 bundle_size;
+	u32 bundle_min_gpm_fifo_depth;
+	u32 bundle_token_limit;
+	/* pagepool */
+	void (*pagepool)(struct gf100_grctx *);
+	u32 pagepool_size;
+	/* attribute(/alpha) circular buffer */
+	void (*attrib)(struct gf100_grctx *);
+	u32 attrib_nr_max;
+	u32 attrib_nr;
+	u32 alpha_nr_max;
+	u32 alpha_nr;
+};
+
+static inline const struct gf100_grctx_oclass *
+gf100_grctx_impl(struct gf100_gr_priv *priv)
+{
+	return (void *)nv_engine(priv)->cclass;
+}
+
+extern struct nvkm_oclass *gf100_grctx_oclass;
+int  gf100_grctx_generate(struct gf100_gr_priv *);
+void gf100_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *);
+void gf100_grctx_generate_bundle(struct gf100_grctx *);
+void gf100_grctx_generate_pagepool(struct gf100_grctx *);
+void gf100_grctx_generate_attrib(struct gf100_grctx *);
+void gf100_grctx_generate_unkn(struct gf100_gr_priv *);
+void gf100_grctx_generate_tpcid(struct gf100_gr_priv *);
+void gf100_grctx_generate_r406028(struct gf100_gr_priv *);
+void gf100_grctx_generate_r4060a8(struct gf100_gr_priv *);
+void gf100_grctx_generate_r418bb8(struct gf100_gr_priv *);
+void gf100_grctx_generate_r406800(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gf108_grctx_oclass;
+void gf108_grctx_generate_attrib(struct gf100_grctx *);
+void gf108_grctx_generate_unkn(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gf104_grctx_oclass;
+extern struct nvkm_oclass *gf110_grctx_oclass;
+
+extern struct nvkm_oclass *gf117_grctx_oclass;
+void gf117_grctx_generate_attrib(struct gf100_grctx *);
+
+extern struct nvkm_oclass *gf119_grctx_oclass;
+
+extern struct nvkm_oclass *gk104_grctx_oclass;
+extern struct nvkm_oclass *gk20a_grctx_oclass;
+void gk104_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *);
+void gk104_grctx_generate_bundle(struct gf100_grctx *);
+void gk104_grctx_generate_pagepool(struct gf100_grctx *);
+void gk104_grctx_generate_unkn(struct gf100_gr_priv *);
+void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gk110_grctx_oclass;
+extern struct nvkm_oclass *gk110b_grctx_oclass;
+extern struct nvkm_oclass *gk208_grctx_oclass;
+extern struct nvkm_oclass *gm107_grctx_oclass;
+
+/* context init value lists */
+
+extern const struct gf100_gr_pack gf100_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_mthd[];
+extern const struct gf100_gr_init gf100_grctx_init_902d_0[];
+extern const struct gf100_gr_init gf100_grctx_init_9039_0[];
+extern const struct gf100_gr_init gf100_grctx_init_90c0_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_hub[];
+extern const struct gf100_gr_init gf100_grctx_init_main_0[];
+extern const struct gf100_gr_init gf100_grctx_init_fe_0[];
+extern const struct gf100_gr_init gf100_grctx_init_pri_0[];
+extern const struct gf100_gr_init gf100_grctx_init_memfmt_0[];
+extern const struct gf100_gr_init gf100_grctx_init_rstr2d_0[];
+extern const struct gf100_gr_init gf100_grctx_init_scc_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_gpc[];
+extern const struct gf100_gr_init gf100_grctx_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf100_grctx_init_prop_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf100_grctx_init_zcull_0[];
+extern const struct gf100_gr_init gf100_grctx_init_crstr_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gpm_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gcc_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_zcull[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_tpc[];
+extern const struct gf100_gr_init gf100_grctx_init_pe_0[];
+extern const struct gf100_gr_init gf100_grctx_init_wwdx_0[];
+extern const struct gf100_gr_init gf100_grctx_init_mpc_0[];
+extern const struct gf100_gr_init gf100_grctx_init_tpccs_0[];
+
+extern const struct gf100_gr_init gf104_grctx_init_tex_0[];
+extern const struct gf100_gr_init gf104_grctx_init_l1c_0[];
+extern const struct gf100_gr_init gf104_grctx_init_sm_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_9097_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_gpm_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_pe_0[];
+extern const struct gf100_gr_init gf108_grctx_init_wwdx_0[];
+extern const struct gf100_gr_init gf108_grctx_init_tpccs_0[];
+
+extern const struct gf100_gr_init gf110_grctx_init_9197_0[];
+extern const struct gf100_gr_init gf110_grctx_init_9297_0[];
+
+extern const struct gf100_gr_pack gf119_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gf119_grctx_pack_mthd[];
+
+extern const struct gf100_gr_init gf119_grctx_init_fe_0[];
+extern const struct gf100_gr_init gf119_grctx_init_be_0[];
+
+extern const struct gf100_gr_init gf119_grctx_init_prop_0[];
+extern const struct gf100_gr_init gf119_grctx_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf119_grctx_init_crstr_0[];
+
+extern const struct gf100_gr_init gf119_grctx_init_sm_0[];
+
+extern const struct gf100_gr_init gf117_grctx_init_pe_0[];
+
+extern const struct gf100_gr_init gf117_grctx_init_wwdx_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_memfmt_0[];
+extern const struct gf100_gr_init gk104_grctx_init_ds_0[];
+extern const struct gf100_gr_init gk104_grctx_init_scc_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_gpm_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_pes_0[];
+
+extern const struct gf100_gr_pack gk104_grctx_pack_hub[];
+extern const struct gf100_gr_pack gk104_grctx_pack_gpc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_tpc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_ppc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_icmd[];
+extern const struct gf100_gr_init gk104_grctx_init_a097_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_mthd[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_hub[];
+extern const struct gf100_gr_init gk110_grctx_init_pri_0[];
+extern const struct gf100_gr_init gk110_grctx_init_cwd_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_gpc[];
+extern const struct gf100_gr_init gk110_grctx_init_gpc_unk_2[];
+
+extern const struct gf100_gr_init gk110_grctx_init_tex_0[];
+extern const struct gf100_gr_init gk110_grctx_init_mpc_0[];
+extern const struct gf100_gr_init gk110_grctx_init_l1c_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_ppc[];
+
+extern const struct gf100_gr_init gk208_grctx_init_rstr2d_0[];
+
+extern const struct gf100_gr_init gk208_grctx_init_prop_0[];
+extern const struct gf100_gr_init gk208_grctx_init_crstr_0[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
new file mode 100644
index 0000000..c5a8d55
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf104_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0007f440 },
+	{}
+};
+
+const struct gf100_gr_init
+gf104_grctx_init_l1c_0[] = {
+	{ 0x419cb0,   1, 0x04, 0x00020048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{}
+};
+
+const struct gf100_gr_init
+gf104_grctx_init_sm_0[] = {
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00011110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf104_grctx_pack_tpc[] = {
+	{ gf100_grctx_init_pe_0 },
+	{ gf104_grctx_init_tex_0 },
+	{ gf100_grctx_init_wwdx_0 },
+	{ gf100_grctx_init_mpc_0 },
+	{ gf104_grctx_init_l1c_0 },
+	{ gf100_grctx_init_tpccs_0 },
+	{ gf104_grctx_init_sm_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf104_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf100_grctx_generate_main,
+	.unkn  = gf100_grctx_generate_unkn,
+	.hub   = gf100_grctx_pack_hub,
+	.gpc   = gf100_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf104_grctx_pack_tpc,
+	.icmd  = gf100_grctx_pack_icmd,
+	.mthd  = gf100_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf100_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
new file mode 100644
index 0000000..87c844a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
@@ -0,0 +1,806 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf108_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_icmd[] = {
+	{ gf108_grctx_init_icmd_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_9097_0[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x002700,   8, 0x20, 0x00000000 },
+	{ 0x002704,   8, 0x20, 0x00000000 },
+	{ 0x002708,   8, 0x20, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   8, 0x20, 0x00014000 },
+	{ 0x002714,   8, 0x20, 0x00000040 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002200,   5, 0x10, 0x00000022 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00001fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x003fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   4, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   1, 0x04, 0x003fffff },
+	{ 0x0002d0,   1, 0x04, 0x00000c48 },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00300008 },
+	{ 0x001284,   1, 0x04, 0x04000080 },
+	{ 0x001450,   1, 0x04, 0x00300008 },
+	{ 0x001454,   1, 0x04, 0x04000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_9197_0[] = {
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_mthd[] = {
+	{ gf108_grctx_init_9097_0, 0x9097 },
+	{ gf108_grctx_init_9197_0, 0x9197 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{ gf100_grctx_init_9039_0, 0x9039 },
+	{ gf100_grctx_init_90c0_0, 0x90c0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180218 },
+	{ 0x405834,   2, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x000103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   2, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x80140078 },
+	{ 0x4064c4,   1, 0x04, 0x0086ffff },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c80929 },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gf100_grctx_init_fe_0 },
+	{ gf100_grctx_init_pri_0 },
+	{ gf100_grctx_init_memfmt_0 },
+	{ gf108_grctx_init_ds_0 },
+	{ gf108_grctx_init_pd_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gf100_grctx_init_scc_0 },
+	{ gf108_grctx_init_be_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x0006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x00100018 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_gpm_0[] = {
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf100_grctx_init_prop_0 },
+	{ gf100_grctx_init_gpc_unk_1 },
+	{ gf108_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf100_grctx_init_crstr_0 },
+	{ gf108_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_pe_0[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_wwdx_0[] = {
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00400001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_tpccs_0[] = {
+	{ 0x419d20,   1, 0x04, 0x12180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419d44,   1, 0x04, 0x02180218 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_tpc[] = {
+	{ gf108_grctx_init_pe_0 },
+	{ gf104_grctx_init_tex_0 },
+	{ gf108_grctx_init_wwdx_0 },
+	{ gf100_grctx_init_mpc_0 },
+	{ gf104_grctx_init_l1c_0 },
+	{ gf108_grctx_init_tpccs_0 },
+	{ gf104_grctx_init_sm_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gf108_grctx_generate_attrib(struct gf100_grctx *info)
+{
+	struct gf100_gr_priv *priv = info->priv;
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+	const u32  alpha = impl->alpha_nr;
+	const u32   beta = impl->attrib_nr;
+	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+	const u32 access = NV_MEM_ACCESS_RW;
+	const int s = 12;
+	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+	const int timeslice_mode = 1;
+	const int max_batches = 0xffff;
+	u32 bo = 0;
+	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+	int gpc, tpc;
+
+	mmio_refn(info, 0x418810, 0x80000000, s, b);
+	mmio_refn(info, 0x419848, 0x10000000, s, b);
+	mmio_wr32(info, 0x405830, (beta << 16) | alpha);
+	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			const u32 a = alpha;
+			const u32 b =  beta;
+			const u32 t = timeslice_mode;
+			const u32 o = TPC_UNIT(gpc, tpc, 0x500);
+			mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo);
+			mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo);
+			bo += impl->attrib_nr_max;
+			mmio_wr32(info, o + 0x44, (a << 16) | ao);
+			ao += impl->alpha_nr_max;
+		}
+	}
+}
+
+void
+gf108_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+	nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
+	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+struct nvkm_oclass *
+gf108_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc1),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf100_grctx_generate_main,
+	.unkn  = gf108_grctx_generate_unkn,
+	.hub   = gf108_grctx_pack_hub,
+	.gpc   = gf108_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf108_grctx_pack_tpc,
+	.icmd  = gf108_grctx_pack_icmd,
+	.mthd  = gf108_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf108_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x324,
+	.alpha_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
new file mode 100644
index 0000000..b3acd93
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf110_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_icmd[] = {
+	{ gf110_grctx_init_icmd_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf110_grctx_init_9197_0[] = {
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{}
+};
+
+const struct gf100_gr_init
+gf110_grctx_init_9297_0[] = {
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x00000020 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_mthd[] = {
+	{ gf108_grctx_init_9097_0, 0x9097 },
+	{ gf110_grctx_init_9197_0, 0x9197 },
+	{ gf110_grctx_init_9297_0, 0x9297 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{ gf100_grctx_init_9039_0, 0x9039 },
+	{ gf100_grctx_init_90c0_0, 0x90c0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf110_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x0006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x00000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf100_grctx_init_prop_0 },
+	{ gf100_grctx_init_gpc_unk_1 },
+	{ gf110_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf100_grctx_init_crstr_0 },
+	{ gf100_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf110_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc8),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf100_grctx_generate_main,
+	.unkn  = gf100_grctx_generate_unkn,
+	.hub   = gf100_grctx_pack_hub,
+	.gpc   = gf110_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf100_grctx_pack_tpc,
+	.icmd  = gf110_grctx_pack_icmd,
+	.mthd  = gf110_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf100_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
new file mode 100644
index 0000000..9bbe2c9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf117_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180324 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x000103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x801a0078 },
+	{ 0x4064c4,   1, 0x04, 0x00c9ffff },
+	{ 0x4064d0,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gf119_grctx_init_fe_0 },
+	{ gf100_grctx_init_pri_0 },
+	{ gf100_grctx_init_memfmt_0 },
+	{ gf117_grctx_init_ds_0 },
+	{ gf117_grctx_init_pd_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gf100_grctx_init_scc_0 },
+	{ gf119_grctx_init_be_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf119_grctx_init_prop_0 },
+	{ gf119_grctx_init_gpc_unk_1 },
+	{ gf117_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf119_grctx_init_crstr_0 },
+	{ gf108_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf117_grctx_init_pe_0[] = {
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00008000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0017f440 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gf117_grctx_init_tex_0 },
+	{ gf117_grctx_init_mpc_0 },
+	{ gf104_grctx_init_l1c_0 },
+	{ gf119_grctx_init_sm_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_pes_0[] = {
+	{ 0x41be24,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_cbm_0[] = {
+	{ 0x41bec0,   1, 0x04, 0x12180000 },
+	{ 0x41bec4,   1, 0x04, 0x00003fff },
+	{ 0x41bee4,   1, 0x04, 0x03240218 },
+	{}
+};
+
+const struct gf100_gr_init
+gf117_grctx_init_wwdx_0[] = {
+	{ 0x41bf00,   1, 0x04, 0x0a418820 },
+	{ 0x41bf04,   1, 0x04, 0x062080e6 },
+	{ 0x41bf08,   1, 0x04, 0x020398a4 },
+	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
+	{ 0x41bf10,   1, 0x04, 0x0a418820 },
+	{ 0x41bf14,   1, 0x04, 0x000000e6 },
+	{ 0x41bfd0,   1, 0x04, 0x00900103 },
+	{ 0x41bfe0,   1, 0x04, 0x00400001 },
+	{ 0x41bfe4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_ppc[] = {
+	{ gf117_grctx_init_pes_0 },
+	{ gf117_grctx_init_cbm_0 },
+	{ gf117_grctx_init_wwdx_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gf117_grctx_generate_attrib(struct gf100_grctx *info)
+{
+	struct gf100_gr_priv *priv = info->priv;
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+	const u32  alpha = impl->alpha_nr;
+	const u32   beta = impl->attrib_nr;
+	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+	const u32 access = NV_MEM_ACCESS_RW;
+	const int s = 12;
+	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+	const int timeslice_mode = 1;
+	const int max_batches = 0xffff;
+	u32 bo = 0;
+	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+	int gpc, ppc;
+
+	mmio_refn(info, 0x418810, 0x80000000, s, b);
+	mmio_refn(info, 0x419848, 0x10000000, s, b);
+	mmio_wr32(info, 0x405830, (beta << 16) | alpha);
+	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) {
+			const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc];
+			const u32 b =  beta * priv->ppc_tpc_nr[gpc][ppc];
+			const u32 t = timeslice_mode;
+			const u32 o = PPC_UNIT(gpc, ppc, 0);
+			mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
+			mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
+			bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+			mmio_wr32(info, o + 0xe4, (a << 16) | ao);
+			ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+		}
+	}
+}
+
+void
+gf117_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+	struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+	gf100_gr_mmio(priv, oclass->hub);
+	gf100_gr_mmio(priv, oclass->gpc);
+	gf100_gr_mmio(priv, oclass->zcull);
+	gf100_gr_mmio(priv, oclass->tpc);
+	gf100_gr_mmio(priv, oclass->ppc);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->bundle(info);
+	oclass->pagepool(info);
+	oclass->attrib(info);
+	oclass->unkn(priv);
+
+	gf100_grctx_generate_tpcid(priv);
+	gf100_grctx_generate_r406028(priv);
+	gf100_grctx_generate_r4060a8(priv);
+	gk104_grctx_generate_r418bb8(priv);
+	gf100_grctx_generate_r406800(priv);
+
+	for (i = 0; i < 8; i++)
+		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+	gf100_gr_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	gf100_gr_mthd(priv, oclass->mthd);
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+}
+
+struct nvkm_oclass *
+gf117_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xd7),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf117_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gf117_grctx_pack_hub,
+	.gpc   = gf117_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf117_grctx_pack_tpc,
+	.ppc   = gf117_grctx_pack_ppc,
+	.icmd  = gf119_grctx_pack_icmd,
+	.mthd  = gf119_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x7ff,
+	.alpha_nr = 0x324,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
new file mode 100644
index 0000000..8d87614
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf119_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000400,  24, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x000440,  24, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf119_grctx_pack_icmd[] = {
+	{ gf119_grctx_init_icmd_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_90c0_0[] = {
+	{ 0x002700,   8, 0x20, 0x00000000 },
+	{ 0x002704,   8, 0x20, 0x00000000 },
+	{ 0x002708,   8, 0x20, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   8, 0x20, 0x00014000 },
+	{ 0x002714,   8, 0x20, 0x00000040 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x000758,   1, 0x04, 0x00000100 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x000204,   3, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{ 0x00024c,   1, 0x04, 0x00000000 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gf119_grctx_pack_mthd[] = {
+	{ gf108_grctx_init_9097_0, 0x9097 },
+	{ gf110_grctx_init_9197_0, 0x9197 },
+	{ gf110_grctx_init_9297_0, 0x9297 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{ gf100_grctx_init_9039_0, 0x9039 },
+	{ gf119_grctx_init_90c0_0, 0x90c0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_fe_0[] = {
+	{ 0x404004,  10, 0x04, 0x00000000 },
+	{ 0x404044,   1, 0x04, 0x00000000 },
+	{ 0x404094,  13, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf0000087 },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x404168,   1, 0x04, 0x00000000 },
+	{ 0x404178,   2, 0x04, 0x00000000 },
+	{ 0x404200,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180218 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x000103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x80140078 },
+	{ 0x4064c4,   1, 0x04, 0x0086ffff },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1043e005 },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gf119_grctx_init_fe_0 },
+	{ gf100_grctx_init_pri_0 },
+	{ gf100_grctx_init_memfmt_0 },
+	{ gf119_grctx_init_ds_0 },
+	{ gf119_grctx_init_pd_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gf100_grctx_init_scc_0 },
+	{ gf119_grctx_init_be_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_prop_0[] = {
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_gpc_unk_1[] = {
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   3, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100008 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_crstr_0[] = {
+	{ 0x418b00,   1, 0x04, 0x00000006 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf119_grctx_init_prop_0 },
+	{ gf119_grctx_init_gpc_unk_1 },
+	{ gf119_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf119_grctx_init_crstr_0 },
+	{ gf108_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0017f440 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3cf3cf3c },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_sm_0[] = {
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00010110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_tpc[] = {
+	{ gf108_grctx_init_pe_0 },
+	{ gf119_grctx_init_tex_0 },
+	{ gf108_grctx_init_wwdx_0 },
+	{ gf119_grctx_init_mpc_0 },
+	{ gf104_grctx_init_l1c_0 },
+	{ gf108_grctx_init_tpccs_0 },
+	{ gf119_grctx_init_sm_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf119_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xd9),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gf100_grctx_generate_main,
+	.unkn  = gf108_grctx_generate_unkn,
+	.hub   = gf119_grctx_pack_hub,
+	.gpc   = gf119_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gf119_grctx_pack_tpc,
+	.icmd  = gf119_grctx_pack_icmd,
+	.mthd  = gf119_grctx_pack_mthd,
+	.bundle = gf100_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.pagepool = gf100_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf108_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x324,
+	.alpha_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
new file mode 100644
index 0000000..b52300d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
@@ -0,0 +1,1022 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk104_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000383,   1, 0x01, 0x00000011 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x003fffff },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00400008 },
+	{ 0x000841,   1, 0x01, 0x08000080 },
+	{ 0x000842,   1, 0x01, 0x00400008 },
+	{ 0x000843,   1, 0x01, 0x08000080 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000008 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_icmd[] = {
+	{ gk104_grctx_init_icmd_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_a097_0[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00000fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x000fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00260c,   1, 0x04, 0x00000000 },
+	{ 0x0007ac,   1, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   4, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x00000020 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   2, 0x04, 0x003fffff },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00400008 },
+	{ 0x001284,   1, 0x04, 0x08000080 },
+	{ 0x001450,   1, 0x04, 0x00400008 },
+	{ 0x001454,   1, 0x04, 0x08000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk104_grctx_pack_mthd[] = {
+	{ gk104_grctx_init_a097_0, 0xa097 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_fe_0[] = {
+	{ 0x404010,   5, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   1, 0x04, 0x00000000 },
+	{ 0x4040a8,   8, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   4, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_memfmt_0[] = {
+	{ 0x404604,   1, 0x04, 0x00000014 },
+	{ 0x404608,   1, 0x04, 0x00000000 },
+	{ 0x40460c,   1, 0x04, 0x00003fff },
+	{ 0x404610,   1, 0x04, 0x00000100 },
+	{ 0x404618,   4, 0x04, 0x00000000 },
+	{ 0x40462c,   2, 0x04, 0x00000000 },
+	{ 0x404640,   1, 0x04, 0x00000000 },
+	{ 0x404654,   1, 0x04, 0x00000000 },
+	{ 0x404660,   1, 0x04, 0x00000000 },
+	{ 0x404678,   1, 0x04, 0x00000000 },
+	{ 0x40467c,   1, 0x04, 0x00000002 },
+	{ 0x404680,   8, 0x04, 0x00000000 },
+	{ 0x4046a0,   1, 0x04, 0x007f0080 },
+	{ 0x4046a4,   8, 0x04, 0x00000000 },
+	{ 0x4046c8,   3, 0x04, 0x00000000 },
+	{ 0x404700,   3, 0x04, 0x00000000 },
+	{ 0x404718,   7, 0x04, 0x00000000 },
+	{ 0x404734,   1, 0x04, 0x00000100 },
+	{ 0x404738,   2, 0x04, 0x00000000 },
+	{ 0x404744,   2, 0x04, 0x00000000 },
+	{ 0x404754,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180648 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_cwd_0[] = {
+	{ 0x405b00,   1, 0x04, 0x00000000 },
+	{ 0x405b10,   1, 0x04, 0x00001000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x004103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   2, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x801a00f0 },
+	{ 0x4064c4,   1, 0x04, 0x0192ffff },
+	{ 0x4064c8,   1, 0x04, 0x01800600 },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_sked_0[] = {
+	{ 0x407040,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_scc_0[] = {
+	{ 0x408000,   2, 0x04, 0x00000000 },
+	{ 0x408008,   1, 0x04, 0x00000030 },
+	{ 0x40800c,   2, 0x04, 0x00000000 },
+	{ 0x408014,   1, 0x04, 0x00000069 },
+	{ 0x408018,   1, 0x04, 0xe100e100 },
+	{ 0x408064,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1043e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gk104_grctx_init_fe_0 },
+	{ gf100_grctx_init_pri_0 },
+	{ gk104_grctx_init_memfmt_0 },
+	{ gk104_grctx_init_ds_0 },
+	{ gk104_grctx_init_cwd_0 },
+	{ gk104_grctx_init_pd_0 },
+	{ gk104_grctx_init_sked_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gk104_grctx_init_scc_0 },
+	{ gk104_grctx_init_be_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_gpm_0[] = {
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c40,   1, 0x04, 0xffffffff },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf119_grctx_init_prop_0 },
+	{ gf119_grctx_init_gpc_unk_1 },
+	{ gk104_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf119_grctx_init_crstr_0 },
+	{ gk104_grctx_init_gpm_0 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000000f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000021 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419ac4,   1, 0x04, 0x0037f440 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x80000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_l1c_0[] = {
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00003203 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_sm_0[] = {
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000402 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,  19, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001f8f },
+	{ 0x419eb0,   1, 0x04, 0x00000d3f },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   8, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00000000 },
+	{ 0x419f78,   1, 0x04, 0x0000000b },
+	{ 0x419f7c,   1, 0x04, 0x0000027c },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gk104_grctx_init_tex_0 },
+	{ gk104_grctx_init_mpc_0 },
+	{ gk104_grctx_init_l1c_0 },
+	{ gk104_grctx_init_sm_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_pes_0[] = {
+	{ 0x41be24,   1, 0x04, 0x00000006 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_cbm_0[] = {
+	{ 0x41bec0,   1, 0x04, 0x12180000 },
+	{ 0x41bec4,   1, 0x04, 0x00037f7f },
+	{ 0x41bee4,   1, 0x04, 0x06480430 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_ppc[] = {
+	{ gk104_grctx_init_pes_0 },
+	{ gk104_grctx_init_cbm_0 },
+	{ gf117_grctx_init_wwdx_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gk104_grctx_generate_bundle(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
+				    impl->bundle_size / 0x20);
+	const u32 token_limit = impl->bundle_token_limit;
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+	mmio_refn(info, 0x408004, 0x00000000, s, b);
+	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+	mmio_refn(info, 0x418808, 0x00000000, s, b);
+	mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+	mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+}
+
+void
+gk104_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+	mmio_refn(info, 0x40800c, 0x00000000, s, b);
+	mmio_wr32(info, 0x408010, 0x80000000);
+	mmio_refn(info, 0x419004, 0x00000000, s, b);
+	mmio_wr32(info, 0x419008, 0x00000000);
+	mmio_wr32(info, 0x4064cc, 0x80000000);
+}
+
+void
+gk104_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+	nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
+	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+void
+gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv)
+{
+	u32 data[6] = {}, data2[2] = {};
+	u8  tpcnr[GPC_MAX];
+	u8  shift, ntpcv;
+	int gpc, tpc, i;
+
+	/* calculate first set of magics */
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+
+		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+	}
+
+	for (; tpc < 32; tpc++)
+		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+	/* and the second... */
+	shift = 0;
+	ntpcv = priv->tpc_total;
+	while (!(ntpcv & (1 << 4))) {
+		ntpcv <<= 1;
+		shift++;
+	}
+
+	data2[0]  = (ntpcv << 16);
+	data2[0] |= (shift << 21);
+	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+	for (i = 1; i < 7; i++)
+		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+	/* GPC_BROADCAST */
+	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+	/* GPC_BROADCAST.TP_BROADCAST */
+	nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr | data2[0]);
+	nv_wr32(priv, 0x41bfe4, data2[1]);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
+
+	/* UNK78xx */
+	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+	struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+	gf100_gr_mmio(priv, oclass->hub);
+	gf100_gr_mmio(priv, oclass->gpc);
+	gf100_gr_mmio(priv, oclass->zcull);
+	gf100_gr_mmio(priv, oclass->tpc);
+	gf100_gr_mmio(priv, oclass->ppc);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->bundle(info);
+	oclass->pagepool(info);
+	oclass->attrib(info);
+	oclass->unkn(priv);
+
+	gf100_grctx_generate_tpcid(priv);
+	gf100_grctx_generate_r406028(priv);
+	gk104_grctx_generate_r418bb8(priv);
+	gf100_grctx_generate_r406800(priv);
+
+	for (i = 0; i < 8; i++)
+		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+	if (priv->gpc_nr == 1) {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+	} else {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+	}
+	nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
+
+	gf100_gr_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	gf100_gr_mthd(priv, oclass->mthd);
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+	nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
+	nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
+}
+
+struct nvkm_oclass *
+gk104_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xe4),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gk104_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gk104_grctx_pack_hub,
+	.gpc   = gk104_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gk104_grctx_pack_tpc,
+	.ppc   = gk104_grctx_pack_ppc,
+	.icmd  = gk104_grctx_pack_icmd,
+	.mthd  = gk104_grctx_pack_mthd,
+	.bundle = gk104_grctx_generate_bundle,
+	.bundle_size = 0x3000,
+	.bundle_min_gpm_fifo_depth = 0x180,
+	.bundle_token_limit = 0x600,
+	.pagepool = gk104_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x7ff,
+	.alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
new file mode 100644
index 0000000..b3f58be
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x0002f2,   2, 0x01, 0x00000001 },
+	{ 0x0002f5,   1, 0x01, 0x00000001 },
+	{ 0x0002f7,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000383,   1, 0x01, 0x00000011 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000662,   1, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x00080b,   1, 0x01, 0x00000002 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000a0d,   1, 0x01, 0x00000006 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x003fffff },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00400008 },
+	{ 0x000841,   1, 0x01, 0x08000080 },
+	{ 0x000842,   1, 0x01, 0x00400008 },
+	{ 0x000843,   1, 0x01, 0x08000080 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000008 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_icmd[] = {
+	{ gk110_grctx_init_icmd_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_a197_0[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00000fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x000fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00260c,   1, 0x04, 0x00000000 },
+	{ 0x0007ac,   1, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   4, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x000ddc,   1, 0x04, 0x00000002 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x00000020 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   2, 0x04, 0x003fffff },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00400008 },
+	{ 0x001284,   1, 0x04, 0x08000080 },
+	{ 0x001450,   1, 0x04, 0x00400008 },
+	{ 0x001454,   1, 0x04, 0x08000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_mthd[] = {
+	{ gk110_grctx_init_a197_0, 0xa197 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_fe_0[] = {
+	{ 0x404004,   8, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   8, 0x04, 0x00000000 },
+	{ 0x4040a8,   8, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404100,  10, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x40417c,   2, 0x04, 0x00000000 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   1, 0x04, 0x0000a197 },
+	{ 0x404204,   1, 0x04, 0x0000a1c0 },
+	{ 0x404208,   1, 0x04, 0x0000a140 },
+	{ 0x40420c,   1, 0x04, 0x0000902d },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_pri_0[] = {
+	{ 0x404404,  12, 0x04, 0x00000000 },
+	{ 0x404438,   1, 0x04, 0x00000000 },
+	{ 0x404460,   2, 0x04, 0x00000000 },
+	{ 0x404468,   1, 0x04, 0x00ffffff },
+	{ 0x40446c,   1, 0x04, 0x00000000 },
+	{ 0x404480,   1, 0x04, 0x00000001 },
+	{ 0x404498,   1, 0x04, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_cwd_0[] = {
+	{ 0x405b00,   1, 0x04, 0x00000000 },
+	{ 0x405b10,   1, 0x04, 0x00001000 },
+	{ 0x405b20,   1, 0x04, 0x04000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x034103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b0,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x802000f0 },
+	{ 0x4064c4,   1, 0x04, 0x0192ffff },
+	{ 0x4064c8,   1, 0x04, 0x018007c0 },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x12802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gk110_grctx_init_fe_0 },
+	{ gk110_grctx_init_pri_0 },
+	{ gk104_grctx_init_memfmt_0 },
+	{ gk104_grctx_init_ds_0 },
+	{ gk110_grctx_init_cwd_0 },
+	{ gk110_grctx_init_pd_0 },
+	{ gf100_grctx_init_rstr2d_0 },
+	{ gk104_grctx_init_scc_0 },
+	{ gk110_grctx_init_be_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   1, 0x04, 0x00000000 },
+	{ 0x41880c,   1, 0x04, 0x00000030 },
+	{ 0x418810,   1, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_gpc_unk_2[] = {
+	{ 0x418d24,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gf119_grctx_init_prop_0 },
+	{ gf119_grctx_init_gpc_unk_1 },
+	{ gk110_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gf119_grctx_init_crstr_0 },
+	{ gk104_grctx_init_gpm_0 },
+	{ gk110_grctx_init_gpc_unk_2 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000000f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000021 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x00020800 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419ac4,   1, 0x04, 0x0037f440 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x0000001a },
+	{ 0x419c04,   1, 0x04, 0x80000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_l1c_0[] = {
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000203 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_sm_0[] = {
+	{ 0x419e04,   1, 0x04, 0x00000000 },
+	{ 0x419e08,   1, 0x04, 0x0000001d },
+	{ 0x419e0c,   1, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00001c02 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,   2, 0x04, 0x00000000 },
+	{ 0x419e58,   1, 0x04, 0x00000001 },
+	{ 0x419e5c,   3, 0x04, 0x00000000 },
+	{ 0x419e68,   1, 0x04, 0x00000002 },
+	{ 0x419e6c,  12, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001f8f },
+	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
+	{ 0x419eb8,   1, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   4, 0x04, 0x00000000 },
+	{ 0x419f40,   1, 0x04, 0x00000018 },
+	{ 0x419f44,   3, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00007300 },
+	{ 0x419f78,   1, 0x04, 0x000000eb },
+	{ 0x419f7c,   1, 0x04, 0x00000404 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk110_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gk110_grctx_init_tex_0 },
+	{ gk110_grctx_init_mpc_0 },
+	{ gk110_grctx_init_l1c_0 },
+	{ gk110_grctx_init_sm_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_cbm_0[] = {
+	{ 0x41bec0,   1, 0x04, 0x10000000 },
+	{ 0x41bec4,   1, 0x04, 0x00037f7f },
+	{ 0x41bee4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_ppc[] = {
+	{ gk104_grctx_init_pes_0 },
+	{ gk110_grctx_init_cbm_0 },
+	{ gf117_grctx_init_wwdx_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xf0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gk104_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gk110_grctx_pack_hub,
+	.gpc   = gk110_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gk110_grctx_pack_tpc,
+	.ppc   = gk110_grctx_pack_ppc,
+	.icmd  = gk110_grctx_pack_icmd,
+	.mthd  = gk110_grctx_pack_mthd,
+	.bundle = gk104_grctx_generate_bundle,
+	.bundle_size = 0x3000,
+	.bundle_min_gpm_fifo_depth = 0x180,
+	.bundle_token_limit = 0x7c0,
+	.pagepool = gk104_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x7ff,
+	.alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
new file mode 100644
index 0000000..b11c267
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110b_grctx_init_sm_0[] = {
+	{ 0x419e04,   1, 0x04, 0x00000000 },
+	{ 0x419e08,   1, 0x04, 0x0000001d },
+	{ 0x419e0c,   1, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00001c02 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,   2, 0x04, 0x00000000 },
+	{ 0x419e58,   1, 0x04, 0x00000001 },
+	{ 0x419e5c,   3, 0x04, 0x00000000 },
+	{ 0x419e68,   1, 0x04, 0x00000002 },
+	{ 0x419e6c,  12, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001f8f },
+	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
+	{ 0x419eb8,   1, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   4, 0x04, 0x00000000 },
+	{ 0x419f40,   1, 0x04, 0x00000018 },
+	{ 0x419f44,   3, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00006300 },
+	{ 0x419f78,   1, 0x04, 0x000000eb },
+	{ 0x419f7c,   1, 0x04, 0x00000404 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk110b_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gk110_grctx_init_tex_0 },
+	{ gk110_grctx_init_mpc_0 },
+	{ gk110_grctx_init_l1c_0 },
+	{ gk110b_grctx_init_sm_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110b_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xf1),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gk104_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gk110_grctx_pack_hub,
+	.gpc   = gk110_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gk110b_grctx_pack_tpc,
+	.ppc   = gk110_grctx_pack_ppc,
+	.icmd  = gk110_grctx_pack_icmd,
+	.mthd  = gk110_grctx_pack_mthd,
+	.bundle = gk104_grctx_generate_bundle,
+	.bundle_size = 0x3000,
+	.bundle_min_gpm_fifo_depth = 0x180,
+	.bundle_token_limit = 0x600,
+	.pagepool = gk104_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x7ff,
+	.alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
new file mode 100644
index 0000000..6e8ce9f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk208_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x0002f2,   2, 0x01, 0x00000001 },
+	{ 0x0002f5,   1, 0x01, 0x00000001 },
+	{ 0x0002f7,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000383,   1, 0x01, 0x00000011 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000662,   1, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x00080b,   1, 0x01, 0x00000002 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000a0d,   1, 0x01, 0x00000006 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x003fffff },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00400008 },
+	{ 0x000841,   1, 0x01, 0x08000080 },
+	{ 0x000842,   1, 0x01, 0x00400008 },
+	{ 0x000843,   1, 0x01, 0x08000080 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000008 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_icmd[] = {
+	{ gk208_grctx_init_icmd_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_fe_0[] = {
+	{ 0x404004,   8, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   8, 0x04, 0x00000000 },
+	{ 0x4040a8,   8, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404100,  10, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x40417c,   2, 0x04, 0x00000000 },
+	{ 0x404194,   1, 0x04, 0x01000700 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   1, 0x04, 0x0000a197 },
+	{ 0x404204,   1, 0x04, 0x0000a1c0 },
+	{ 0x404208,   1, 0x04, 0x0000a140 },
+	{ 0x40420c,   1, 0x04, 0x0000902d },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180648 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{ 0x405a1c,   1, 0x04, 0x000000ff },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x034103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b0,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x802000f0 },
+	{ 0x4064c4,   1, 0x04, 0x0192ffff },
+	{ 0x4064c8,   1, 0x04, 0x00c20200 },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_rstr2d_0[] = {
+	{ 0x407804,   1, 0x04, 0x00000063 },
+	{ 0x40780c,   1, 0x04, 0x0a418820 },
+	{ 0x407810,   1, 0x04, 0x062080e6 },
+	{ 0x407814,   1, 0x04, 0x020398a4 },
+	{ 0x407818,   1, 0x04, 0x0e629062 },
+	{ 0x40781c,   1, 0x04, 0x0a418820 },
+	{ 0x407820,   1, 0x04, 0x000000e6 },
+	{ 0x4078bc,   1, 0x04, 0x00000103 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x32802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0xb080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x02c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gk208_grctx_init_fe_0 },
+	{ gk110_grctx_init_pri_0 },
+	{ gk104_grctx_init_memfmt_0 },
+	{ gk208_grctx_init_ds_0 },
+	{ gk110_grctx_init_cwd_0 },
+	{ gk208_grctx_init_pd_0 },
+	{ gk208_grctx_init_rstr2d_0 },
+	{ gk104_grctx_init_scc_0 },
+	{ gk208_grctx_init_be_0 },
+	{}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_prop_0[] = {
+	{ 0x418400,   1, 0x04, 0x38005e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_gpc_unk_1[] = {
+	{ 0x418600,   1, 0x04, 0x0000007f },
+	{ 0x418684,   1, 0x04, 0x0000001f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   2, 0x04, 0x00000080 },
+	{ 0x41870c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006863a },
+	{ 0x418808,   1, 0x04, 0x00000000 },
+	{ 0x41880c,   1, 0x04, 0x00000030 },
+	{ 0x418810,   1, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100058 },
+	{}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_crstr_0[] = {
+	{ 0x418b00,   1, 0x04, 0x0000001e },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_gpm_0[] = {
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c40,   1, 0x04, 0xffffffff },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x2020000c },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_gpc[] = {
+	{ gf100_grctx_init_gpc_unk_0 },
+	{ gk208_grctx_init_prop_0 },
+	{ gk208_grctx_init_gpc_unk_1 },
+	{ gk208_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gk208_grctx_init_crstr_0 },
+	{ gk208_grctx_init_gpm_0 },
+	{ gk110_grctx_init_gpc_unk_2 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000100f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000421 },
+	{ 0x419a0c,   1, 0x04, 0x00120000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419ac4,   1, 0x04, 0x0037f440 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_sm_0[] = {
+	{ 0x419e04,   1, 0x04, 0x00000000 },
+	{ 0x419e08,   1, 0x04, 0x0000001d },
+	{ 0x419e0c,   1, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00001c02 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,   2, 0x04, 0x00000000 },
+	{ 0x419e58,   1, 0x04, 0x00000001 },
+	{ 0x419e5c,   3, 0x04, 0x00000000 },
+	{ 0x419e68,   1, 0x04, 0x00000002 },
+	{ 0x419e6c,  12, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001f8f },
+	{ 0x419eb0,   1, 0x04, 0x0db00d2f },
+	{ 0x419eb8,   1, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   4, 0x04, 0x00000000 },
+	{ 0x419f40,   1, 0x04, 0x00000018 },
+	{ 0x419f44,   3, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000020 },
+	{ 0x419f70,   1, 0x04, 0x00000000 },
+	{ 0x419f78,   1, 0x04, 0x000001eb },
+	{ 0x419f7c,   1, 0x04, 0x00000404 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gk208_grctx_init_tex_0 },
+	{ gk110_grctx_init_mpc_0 },
+	{ gk110_grctx_init_l1c_0 },
+	{ gk208_grctx_init_sm_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_cbm_0[] = {
+	{ 0x41bec0,   1, 0x04, 0x10000000 },
+	{ 0x41bec4,   1, 0x04, 0x00037f7f },
+	{ 0x41bee4,   1, 0x04, 0x00000000 },
+	{ 0x41bef0,   1, 0x04, 0x000003ff },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_ppc[] = {
+	{ gk104_grctx_init_pes_0 },
+	{ gk208_grctx_init_cbm_0 },
+	{ gf117_grctx_init_wwdx_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk208_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0x08),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gk104_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gk208_grctx_pack_hub,
+	.gpc   = gk208_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gk208_grctx_pack_tpc,
+	.ppc   = gk208_grctx_pack_ppc,
+	.icmd  = gk208_grctx_pack_icmd,
+	.mthd  = gk110_grctx_pack_mthd,
+	.bundle = gk104_grctx_generate_bundle,
+	.bundle_size = 0x3000,
+	.bundle_min_gpm_fifo_depth = 0xc2,
+	.bundle_token_limit = 0x200,
+	.pagepool = gk104_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x324,
+	.attrib_nr = 0x218,
+	.alpha_nr_max = 0x7ff,
+	.alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
new file mode 100644
index 0000000..2f241f6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "ctxgf100.h"
+
+static const struct gf100_gr_pack
+gk20a_grctx_pack_mthd[] = {
+	{ gk104_grctx_init_a097_0, 0xa297 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{}
+};
+
+struct nvkm_oclass *
+gk20a_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gk104_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gk104_grctx_pack_hub,
+	.gpc   = gk104_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gk104_grctx_pack_tpc,
+	.ppc   = gk104_grctx_pack_ppc,
+	.icmd  = gk104_grctx_pack_icmd,
+	.mthd  = gk20a_grctx_pack_mthd,
+	.bundle = gk104_grctx_generate_bundle,
+	.bundle_size = 0x1800,
+	.bundle_min_gpm_fifo_depth = 0x62,
+	.bundle_token_limit = 0x100,
+	.pagepool = gk104_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gf117_grctx_generate_attrib,
+	.attrib_nr_max = 0x240,
+	.attrib_nr = 0x240,
+	.alpha_nr_max = 0x648 + (0x648 / 2),
+	.alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
new file mode 100644
index 0000000..956f4dc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
@@ -0,0 +1,1034 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm107_grctx_init_icmd_0[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x0000b1,   2, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000a8,   1, 0x01, 0x0000ffff },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002f2,   2, 0x01, 0x00000001 },
+	{ 0x0002f5,   1, 0x01, 0x00000001 },
+	{ 0x0002f7,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x0000de,   1, 0x01, 0x00000001 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000383,   1, 0x01, 0x00000011 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x0005d0,   1, 0x01, 0x20181008 },
+	{ 0x0005d1,   1, 0x01, 0x40383028 },
+	{ 0x0005d2,   1, 0x01, 0x60585048 },
+	{ 0x0005d3,   1, 0x01, 0x80787068 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000550,  32, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x000595,   1, 0x01, 0x00400040 },
+	{ 0x000596,   1, 0x01, 0x00000492 },
+	{ 0x000597,   1, 0x01, 0x08080203 },
+	{ 0x0005ad,   1, 0x01, 0x00000008 },
+	{ 0x000598,   1, 0x01, 0x00020001 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   2, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000662,   1, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000a0d,   1, 0x01, 0x00000006 },
+	{ 0x00097d,   1, 0x01, 0x0000000c },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000687,   1, 0x01, 0x003fffff },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00400008 },
+	{ 0x000841,   1, 0x01, 0x08000080 },
+	{ 0x000842,   1, 0x01, 0x00400008 },
+	{ 0x000843,   1, 0x01, 0x08000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   3, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   3, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000008 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_icmd[] = {
+	{ gm107_grctx_init_icmd_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_b097_0[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x001480,   8, 0x10, 0x00000000 },
+	{ 0x001484,   8, 0x10, 0x00000000 },
+	{ 0x001488,   8, 0x10, 0x00000000 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000754,   1, 0x04, 0x00000001 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001080,   2, 0x04, 0x00000000 },
+	{ 0x001088,   2, 0x04, 0x00000001 },
+	{ 0x001090,   1, 0x04, 0x00000000 },
+	{ 0x001094,   1, 0x04, 0x00000001 },
+	{ 0x001098,   1, 0x04, 0x00000000 },
+	{ 0x00109c,   1, 0x04, 0x00000001 },
+	{ 0x0010a0,   2, 0x04, 0x00000000 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x000f40,   5, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00000fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x000fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00260c,   1, 0x04, 0x00000000 },
+	{ 0x0007ac,   1, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000f60,   1, 0x04, 0x00000000 },
+	{ 0x000f64,   1, 0x04, 0x00400040 },
+	{ 0x000f68,   1, 0x04, 0x00002212 },
+	{ 0x000f6c,   1, 0x04, 0x08080203 },
+	{ 0x001108,   1, 0x04, 0x00000008 },
+	{ 0x000f70,   1, 0x04, 0x00080001 },
+	{ 0x000ffc,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   4, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x000dd0,   1, 0x04, 0x00000000 },
+	{ 0x000dd4,   1, 0x04, 0x00000001 },
+	{ 0x0002f4,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x000f14,   1, 0x04, 0x00000000 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x0000000c },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000da8,   1, 0x04, 0x00000030 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x0002d0,   1, 0x04, 0x003fffff },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00400008 },
+	{ 0x001284,   1, 0x04, 0x08000080 },
+	{ 0x001450,   1, 0x04, 0x00400008 },
+	{ 0x001454,   1, 0x04, 0x08000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_mthd[] = {
+	{ gm107_grctx_init_b097_0, 0xb097 },
+	{ gf100_grctx_init_902d_0, 0x902d },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_fe_0[] = {
+	{ 0x404004,   8, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   8, 0x04, 0x00000000 },
+	{ 0x4040a8,   8, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404100,  10, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000045 },
+	{ 0x40417c,   2, 0x04, 0x00000000 },
+	{ 0x404194,   1, 0x04, 0x01000700 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_ds_0[] = {
+	{ 0x405800,   1, 0x04, 0x0f8001bf },
+	{ 0x405830,   1, 0x04, 0x0aa01000 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{ 0x405a1c,   1, 0x04, 0x000000ff },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_pd_0[] = {
+	{ 0x406020,   1, 0x04, 0x07410001 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b0,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x80400280 },
+	{ 0x4064c4,   1, 0x04, 0x0400ffff },
+	{ 0x4064c8,   1, 0x04, 0x018001ff },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{ 0x406500,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_be_0[] = {
+	{ 0x408800,   1, 0x04, 0x32802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0xb080b801 },
+	{ 0x408904,   1, 0x04, 0x63038001 },
+	{ 0x408908,   1, 0x04, 0x02c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_hub[] = {
+	{ gf100_grctx_init_main_0 },
+	{ gm107_grctx_init_fe_0 },
+	{ gk110_grctx_init_pri_0 },
+	{ gk104_grctx_init_memfmt_0 },
+	{ gm107_grctx_init_ds_0 },
+	{ gk110_grctx_init_cwd_0 },
+	{ gm107_grctx_init_pd_0 },
+	{ gk208_grctx_init_rstr2d_0 },
+	{ gk104_grctx_init_scc_0 },
+	{ gm107_grctx_init_be_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000056 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_1[] = {
+	{ 0x418600,   1, 0x04, 0x0000007f },
+	{ 0x418684,   1, 0x04, 0x0000001f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   1, 0x04, 0x40000000 },
+	{ 0x41870c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_setup_0[] = {
+	{ 0x418800,   1, 0x04, 0x7006863a },
+	{ 0x418810,   1, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100058 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_2[] = {
+	{ 0x418d24,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x90000000 },
+	{ 0x418e24,   1, 0x04, 0x00000000 },
+	{ 0x418e28,   1, 0x04, 0x00000030 },
+	{ 0x418e30,   1, 0x04, 0x00000000 },
+	{ 0x418e34,   1, 0x04, 0x00010000 },
+	{ 0x418e38,   1, 0x04, 0x00000000 },
+	{ 0x418e40,  22, 0x04, 0x00000000 },
+	{ 0x418ea0,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_gpc[] = {
+	{ gm107_grctx_init_gpc_unk_0 },
+	{ gk208_grctx_init_prop_0 },
+	{ gm107_grctx_init_gpc_unk_1 },
+	{ gm107_grctx_init_setup_0 },
+	{ gf100_grctx_init_zcull_0 },
+	{ gk208_grctx_init_crstr_0 },
+	{ gk104_grctx_init_gpm_0 },
+	{ gm107_grctx_init_gpc_unk_2 },
+	{ gf100_grctx_init_gcc_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_tex_0[] = {
+	{ 0x419a00,   1, 0x04, 0x000300f0 },
+	{ 0x419a04,   1, 0x04, 0x00000005 },
+	{ 0x419a08,   1, 0x04, 0x00000421 },
+	{ 0x419a0c,   1, 0x04, 0x00120000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00002200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x20008a00 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419a3c,   1, 0x04, 0x00000002 },
+	{ 0x419ac4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_mpc_0[] = {
+	{ 0x419c00,   1, 0x04, 0x0000001a },
+	{ 0x419c04,   1, 0x04, 0x80000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{ 0x419c2c,   1, 0x04, 0x00000000 },
+	{ 0x419c34,   1, 0x04, 0x01ff1ff3 },
+	{ 0x419c3c,   1, 0x04, 0x00001919 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_l1c_0[] = {
+	{ 0x419c84,   1, 0x04, 0x00000020 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_sm_0[] = {
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00001c02 },
+	{ 0x419e44,   1, 0x04, 0x00d3eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,   1, 0x04, 0x00000000 },
+	{ 0x419e60,   4, 0x04, 0x00000000 },
+	{ 0x419e74,  10, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x0001cf8b },
+	{ 0x419eb0,   1, 0x04, 0x00030300 },
+	{ 0x419eb8,   1, 0x04, 0x00000000 },
+	{ 0x419ef0,  24, 0x04, 0x00000000 },
+	{ 0x419f68,   2, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00000020 },
+	{ 0x419f78,   1, 0x04, 0x000003eb },
+	{ 0x419f7c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_tpc[] = {
+	{ gf117_grctx_init_pe_0 },
+	{ gm107_grctx_init_tex_0 },
+	{ gm107_grctx_init_mpc_0 },
+	{ gm107_grctx_init_l1c_0 },
+	{ gm107_grctx_init_sm_0 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_cbm_0[] = {
+	{ 0x41bec0,   1, 0x04, 0x00000000 },
+	{ 0x41bec4,   1, 0x04, 0x01050000 },
+	{ 0x41bee4,   1, 0x04, 0x00000000 },
+	{ 0x41bef0,   1, 0x04, 0x000003ff },
+	{ 0x41bef4,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_wwdx_0[] = {
+	{ 0x41bf00,   1, 0x04, 0x0a418820 },
+	{ 0x41bf04,   1, 0x04, 0x062080e6 },
+	{ 0x41bf08,   1, 0x04, 0x020398a4 },
+	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
+	{ 0x41bf10,   1, 0x04, 0x0a418820 },
+	{ 0x41bf14,   1, 0x04, 0x000000e6 },
+	{ 0x41bfd0,   1, 0x04, 0x00900103 },
+	{ 0x41bfe0,   1, 0x04, 0x80000000 },
+	{ 0x41bfe4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_ppc[] = {
+	{ gk104_grctx_init_pes_0 },
+	{ gm107_grctx_init_cbm_0 },
+	{ gm107_grctx_init_wwdx_0 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+static void
+gm107_grctx_generate_bundle(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
+				    impl->bundle_size / 0x20);
+	const u32 token_limit = impl->bundle_token_limit;
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+	mmio_refn(info, 0x408004, 0x00000000, s, b);
+	mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+	mmio_refn(info, 0x418e24, 0x00000000, s, b);
+	mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+	mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+}
+
+static void
+gm107_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+	const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+	const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+	const int s = 8;
+	const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+	mmio_refn(info, 0x40800c, 0x00000000, s, b);
+	mmio_wr32(info, 0x408010, 0x80000000);
+	mmio_refn(info, 0x419004, 0x00000000, s, b);
+	mmio_wr32(info, 0x419008, 0x00000000);
+	mmio_wr32(info, 0x4064cc, 0x80000000);
+	mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
+}
+
+static void
+gm107_grctx_generate_attrib(struct gf100_grctx *info)
+{
+	struct gf100_gr_priv *priv = info->priv;
+	const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(priv);
+	const u32  alpha = impl->alpha_nr;
+	const u32 attrib = impl->attrib_nr;
+	const u32   size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+	const u32 access = NV_MEM_ACCESS_RW;
+	const int s = 12;
+	const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+	const int max_batches = 0xffff;
+	u32 bo = 0;
+	u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+	int gpc, ppc, n = 0;
+
+	mmio_refn(info, 0x418810, 0x80000000, s, b);
+	mmio_refn(info, 0x419848, 0x10000000, s, b);
+	mmio_refn(info, 0x419c2c, 0x10000000, s, b);
+	mmio_wr32(info, 0x405830, (attrib << 16) | alpha);
+	mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) {
+			const u32 as =  alpha * priv->ppc_tpc_nr[gpc][ppc];
+			const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc];
+			const u32 u = 0x418ea0 + (n * 0x04);
+			const u32 o = PPC_UNIT(gpc, ppc, 0);
+			mmio_wr32(info, o + 0xc0, bs);
+			mmio_wr32(info, o + 0xf4, bo);
+			bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+			mmio_wr32(info, o + 0xe4, as);
+			mmio_wr32(info, o + 0xf8, ao);
+			ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+			mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs);
+		}
+	}
+}
+
+static void
+gm107_grctx_generate_tpcid(struct gf100_gr_priv *priv)
+{
+	int gpc, tpc, id;
+
+	for (tpc = 0, id = 0; tpc < 4; tpc++) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			if (tpc < priv->tpc_nr[gpc]) {
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+				id++;
+			}
+
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+		}
+	}
+}
+
+static void
+gm107_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+	struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	gf100_gr_mmio(priv, oclass->hub);
+	gf100_gr_mmio(priv, oclass->gpc);
+	gf100_gr_mmio(priv, oclass->zcull);
+	gf100_gr_mmio(priv, oclass->tpc);
+	gf100_gr_mmio(priv, oclass->ppc);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->bundle(info);
+	oclass->pagepool(info);
+	oclass->attrib(info);
+	oclass->unkn(priv);
+
+	gm107_grctx_generate_tpcid(priv);
+	gf100_grctx_generate_r406028(priv);
+	gk104_grctx_generate_r418bb8(priv);
+	gf100_grctx_generate_r406800(priv);
+
+	nv_wr32(priv, 0x4064d0, 0x00000001);
+	for (i = 1; i < 8; i++)
+		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+	nv_wr32(priv, 0x406500, 0x00000001);
+
+	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+
+	if (priv->gpc_nr == 1) {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+	} else {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+	}
+
+	gf100_gr_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	gf100_gr_mthd(priv, oclass->mthd);
+
+	nv_mask(priv, 0x419e00, 0x00808080, 0x00808080);
+	nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x419f80, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x419f88, 0x80000000, 0x80000000);
+}
+
+struct nvkm_oclass *
+gm107_grctx_oclass = &(struct gf100_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0x08),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_context_ctor,
+		.dtor = gf100_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+	.main  = gm107_grctx_generate_main,
+	.unkn  = gk104_grctx_generate_unkn,
+	.hub   = gm107_grctx_pack_hub,
+	.gpc   = gm107_grctx_pack_gpc,
+	.zcull = gf100_grctx_pack_zcull,
+	.tpc   = gm107_grctx_pack_tpc,
+	.ppc   = gm107_grctx_pack_ppc,
+	.icmd  = gm107_grctx_pack_icmd,
+	.mthd  = gm107_grctx_pack_mthd,
+	.bundle = gm107_grctx_generate_bundle,
+	.bundle_size = 0x3000,
+	.bundle_min_gpm_fifo_depth = 0x180,
+	.bundle_token_limit = 0x2c0,
+	.pagepool = gm107_grctx_generate_pagepool,
+	.pagepool_size = 0x8000,
+	.attrib = gm107_grctx_generate_attrib,
+	.attrib_nr_max = 0xff0,
+	.attrib_nr = 0xaa0,
+	.alpha_nr_max = 0x1800,
+	.alpha_nr = 0x1000,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c
new file mode 100644
index 0000000..dc31462
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright 2009 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* NVIDIA context programs handle a number of other conditions which are
+ * not implemented in our versions.  It's not clear why NVIDIA context
+ * programs have this code, nor whether it's strictly necessary for
+ * correct operation.  We'll implement additional handling if/when we
+ * discover it's necessary.
+ *
+ * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
+ *   flag is set, this gets saved into the context.
+ * - On context save, the context program for all cards load nsource
+ *   into a flag register and check for ILLEGAL_MTHD.  If it's set,
+ *   opcode 0x60000d is called before resuming normal operation.
+ * - Some context programs check more conditions than the above.  NV44
+ *   checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
+ *   and calls 0x60000d before resuming normal operation.
+ * - At the very beginning of NVIDIA's context programs, flag 9 is checked
+ *   and if true 0x800001 is called with count=0, pos=0, the flag is cleared
+ *   and then the ctxprog is aborted.  It looks like a complicated NOP,
+ *   its purpose is unknown.
+ * - In the section of code that loads the per-vs state, NVIDIA check
+ *   flag 10.  If it's set, they only transfer the small 0x300 byte block
+ *   of state + the state for a single vs as opposed to the state for
+ *   all vs units.  It doesn't seem likely that it'll occur in normal
+ *   operation, especially seeing as it appears NVIDIA may have screwed
+ *   up the ctxprogs for some cards and have an invalid instruction
+ *   rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
+ * - There's a number of places where context offset 0 (where we place
+ *   the PRAMIN offset of the context) is loaded into either 0x408000,
+ *   0x408004 or 0x408008.  Not sure what's up there either.
+ * - The ctxprogs for some cards save 0x400a00 again during the cleanup
+ *   path for auto-loadctx.
+ */
+
+#define CP_FLAG_CLEAR                 0
+#define CP_FLAG_SET                   1
+#define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD   0
+#define CP_FLAG_SWAP_DIRECTION_SAVE   1
+#define CP_FLAG_USER_SAVE             ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING     1
+#define CP_FLAG_USER_LOAD             ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING     1
+#define CP_FLAG_STATUS                ((3 * 32) + 0)
+#define CP_FLAG_STATUS_IDLE           0
+#define CP_FLAG_STATUS_BUSY           1
+#define CP_FLAG_AUTO_SAVE             ((3 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING     1
+#define CP_FLAG_AUTO_LOAD             ((3 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING     1
+#define CP_FLAG_UNK54                 ((3 * 32) + 6)
+#define CP_FLAG_UNK54_CLEAR           0
+#define CP_FLAG_UNK54_SET             1
+#define CP_FLAG_ALWAYS                ((3 * 32) + 8)
+#define CP_FLAG_ALWAYS_FALSE          0
+#define CP_FLAG_ALWAYS_TRUE           1
+#define CP_FLAG_UNK57                 ((3 * 32) + 9)
+#define CP_FLAG_UNK57_CLEAR           0
+#define CP_FLAG_UNK57_SET             1
+
+#define CP_CTX                   0x00100000
+#define CP_CTX_COUNT             0x000fc000
+#define CP_CTX_COUNT_SHIFT               14
+#define CP_CTX_REG               0x00003fff
+#define CP_LOAD_SR               0x00200000
+#define CP_LOAD_SR_VALUE         0x000fffff
+#define CP_BRA                   0x00400000
+#define CP_BRA_IP                0x0000ff00
+#define CP_BRA_IP_SHIFT                   8
+#define CP_BRA_IF_CLEAR          0x00000080
+#define CP_BRA_FLAG              0x0000007f
+#define CP_WAIT                  0x00500000
+#define CP_WAIT_SET              0x00000080
+#define CP_WAIT_FLAG             0x0000007f
+#define CP_SET                   0x00700000
+#define CP_SET_1                 0x00000080
+#define CP_SET_FLAG              0x0000007f
+#define CP_NEXT_TO_SWAP          0x00600007
+#define CP_NEXT_TO_CURRENT       0x00600009
+#define CP_SET_CONTEXT_POINTER   0x0060000a
+#define CP_END                   0x0060000e
+#define CP_LOAD_MAGIC_UNK01      0x00800001 /* unknown */
+#define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
+#define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
+
+#include "ctxnv40.h"
+#include "nv40.h"
+#include <core/device.h>
+
+/* TODO:
+ *  - get vs count from 0x1540
+ */
+
+static int
+nv40_gr_vs_count(struct nvkm_device *device)
+{
+
+	switch (device->chipset) {
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		return 8;
+	case 0x40:
+		return 6;
+	case 0x41:
+	case 0x42:
+		return 5;
+	case 0x43:
+	case 0x44:
+	case 0x46:
+	case 0x4a:
+		return 3;
+	case 0x4c:
+	case 0x4e:
+	case 0x67:
+	default:
+		return 1;
+	}
+}
+
+
+enum cp_label {
+	cp_check_load = 1,
+	cp_setup_auto_load,
+	cp_setup_load,
+	cp_setup_save,
+	cp_swap_state,
+	cp_swap_state3d_3_is_save,
+	cp_prepare_exit,
+	cp_exit,
+};
+
+static void
+nv40_gr_construct_general(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+
+	cp_ctx(ctx, 0x4000a4, 1);
+	gr_def(ctx, 0x4000a4, 0x00000008);
+	cp_ctx(ctx, 0x400144, 58);
+	gr_def(ctx, 0x400144, 0x00000001);
+	cp_ctx(ctx, 0x400314, 1);
+	gr_def(ctx, 0x400314, 0x00000000);
+	cp_ctx(ctx, 0x400400, 10);
+	cp_ctx(ctx, 0x400480, 10);
+	cp_ctx(ctx, 0x400500, 19);
+	gr_def(ctx, 0x400514, 0x00040000);
+	gr_def(ctx, 0x400524, 0x55555555);
+	gr_def(ctx, 0x400528, 0x55555555);
+	gr_def(ctx, 0x40052c, 0x55555555);
+	gr_def(ctx, 0x400530, 0x55555555);
+	cp_ctx(ctx, 0x400560, 6);
+	gr_def(ctx, 0x400568, 0x0000ffff);
+	gr_def(ctx, 0x40056c, 0x0000ffff);
+	cp_ctx(ctx, 0x40057c, 5);
+	cp_ctx(ctx, 0x400710, 3);
+	gr_def(ctx, 0x400710, 0x20010001);
+	gr_def(ctx, 0x400714, 0x0f73ef00);
+	cp_ctx(ctx, 0x400724, 1);
+	gr_def(ctx, 0x400724, 0x02008821);
+	cp_ctx(ctx, 0x400770, 3);
+	if (device->chipset == 0x40) {
+		cp_ctx(ctx, 0x400814, 4);
+		cp_ctx(ctx, 0x400828, 5);
+		cp_ctx(ctx, 0x400840, 5);
+		gr_def(ctx, 0x400850, 0x00000040);
+		cp_ctx(ctx, 0x400858, 4);
+		gr_def(ctx, 0x400858, 0x00000040);
+		gr_def(ctx, 0x40085c, 0x00000040);
+		gr_def(ctx, 0x400864, 0x80000000);
+		cp_ctx(ctx, 0x40086c, 9);
+		gr_def(ctx, 0x40086c, 0x80000000);
+		gr_def(ctx, 0x400870, 0x80000000);
+		gr_def(ctx, 0x400874, 0x80000000);
+		gr_def(ctx, 0x400878, 0x80000000);
+		gr_def(ctx, 0x400888, 0x00000040);
+		gr_def(ctx, 0x40088c, 0x80000000);
+		cp_ctx(ctx, 0x4009c0, 8);
+		gr_def(ctx, 0x4009cc, 0x80000000);
+		gr_def(ctx, 0x4009dc, 0x80000000);
+	} else {
+		cp_ctx(ctx, 0x400840, 20);
+		if (nv44_gr_class(ctx->device)) {
+			for (i = 0; i < 8; i++)
+				gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
+		}
+		gr_def(ctx, 0x400880, 0x00000040);
+		gr_def(ctx, 0x400884, 0x00000040);
+		gr_def(ctx, 0x400888, 0x00000040);
+		cp_ctx(ctx, 0x400894, 11);
+		gr_def(ctx, 0x400894, 0x00000040);
+		if (!nv44_gr_class(ctx->device)) {
+			for (i = 0; i < 8; i++)
+				gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
+		}
+		cp_ctx(ctx, 0x4008e0, 2);
+		cp_ctx(ctx, 0x4008f8, 2);
+		if (device->chipset == 0x4c ||
+		    (device->chipset & 0xf0) == 0x60)
+			cp_ctx(ctx, 0x4009f8, 1);
+	}
+	cp_ctx(ctx, 0x400a00, 73);
+	gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
+	cp_ctx(ctx, 0x401000, 4);
+	cp_ctx(ctx, 0x405004, 1);
+	switch (device->chipset) {
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		cp_ctx(ctx, 0x403448, 1);
+		gr_def(ctx, 0x403448, 0x00001010);
+		break;
+	default:
+		cp_ctx(ctx, 0x403440, 1);
+		switch (device->chipset) {
+		case 0x40:
+			gr_def(ctx, 0x403440, 0x00000010);
+			break;
+		case 0x44:
+		case 0x46:
+		case 0x4a:
+			gr_def(ctx, 0x403440, 0x00003010);
+			break;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x4c:
+		case 0x4e:
+		case 0x67:
+		default:
+			gr_def(ctx, 0x403440, 0x00001010);
+			break;
+		}
+		break;
+	}
+}
+
+static void
+nv40_gr_construct_state3d(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+
+	if (device->chipset == 0x40) {
+		cp_ctx(ctx, 0x401880, 51);
+		gr_def(ctx, 0x401940, 0x00000100);
+	} else
+	if (device->chipset == 0x46 || device->chipset == 0x47 ||
+	    device->chipset == 0x49 || device->chipset == 0x4b) {
+		cp_ctx(ctx, 0x401880, 32);
+		for (i = 0; i < 16; i++)
+			gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
+		if (device->chipset == 0x46)
+			cp_ctx(ctx, 0x401900, 16);
+		cp_ctx(ctx, 0x401940, 3);
+	}
+	cp_ctx(ctx, 0x40194c, 18);
+	gr_def(ctx, 0x401954, 0x00000111);
+	gr_def(ctx, 0x401958, 0x00080060);
+	gr_def(ctx, 0x401974, 0x00000080);
+	gr_def(ctx, 0x401978, 0xffff0000);
+	gr_def(ctx, 0x40197c, 0x00000001);
+	gr_def(ctx, 0x401990, 0x46400000);
+	if (device->chipset == 0x40) {
+		cp_ctx(ctx, 0x4019a0, 2);
+		cp_ctx(ctx, 0x4019ac, 5);
+	} else {
+		cp_ctx(ctx, 0x4019a0, 1);
+		cp_ctx(ctx, 0x4019b4, 3);
+	}
+	gr_def(ctx, 0x4019bc, 0xffff0000);
+	switch (device->chipset) {
+	case 0x46:
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		cp_ctx(ctx, 0x4019c0, 18);
+		for (i = 0; i < 16; i++)
+			gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
+		break;
+	}
+	cp_ctx(ctx, 0x401a08, 8);
+	gr_def(ctx, 0x401a10, 0x0fff0000);
+	gr_def(ctx, 0x401a14, 0x0fff0000);
+	gr_def(ctx, 0x401a1c, 0x00011100);
+	cp_ctx(ctx, 0x401a2c, 4);
+	cp_ctx(ctx, 0x401a44, 26);
+	for (i = 0; i < 16; i++)
+		gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
+	gr_def(ctx, 0x401a8c, 0x4b7fffff);
+	if (device->chipset == 0x40) {
+		cp_ctx(ctx, 0x401ab8, 3);
+	} else {
+		cp_ctx(ctx, 0x401ab8, 1);
+		cp_ctx(ctx, 0x401ac0, 1);
+	}
+	cp_ctx(ctx, 0x401ad0, 8);
+	gr_def(ctx, 0x401ad0, 0x30201000);
+	gr_def(ctx, 0x401ad4, 0x70605040);
+	gr_def(ctx, 0x401ad8, 0xb8a89888);
+	gr_def(ctx, 0x401adc, 0xf8e8d8c8);
+	cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
+	gr_def(ctx, 0x401b10, 0x40100000);
+	cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
+	gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
+			      0x00000004 : 0x00000000);
+	cp_ctx(ctx, 0x401b30, 25);
+	gr_def(ctx, 0x401b34, 0x0000ffff);
+	gr_def(ctx, 0x401b68, 0x435185d6);
+	gr_def(ctx, 0x401b6c, 0x2155b699);
+	gr_def(ctx, 0x401b70, 0xfedcba98);
+	gr_def(ctx, 0x401b74, 0x00000098);
+	gr_def(ctx, 0x401b84, 0xffffffff);
+	gr_def(ctx, 0x401b88, 0x00ff7000);
+	gr_def(ctx, 0x401b8c, 0x0000ffff);
+	if (device->chipset != 0x44 && device->chipset != 0x4a &&
+	    device->chipset != 0x4e)
+		cp_ctx(ctx, 0x401b94, 1);
+	cp_ctx(ctx, 0x401b98, 8);
+	gr_def(ctx, 0x401b9c, 0x00ff0000);
+	cp_ctx(ctx, 0x401bc0, 9);
+	gr_def(ctx, 0x401be0, 0x00ffff00);
+	cp_ctx(ctx, 0x401c00, 192);
+	for (i = 0; i < 16; i++) { /* fragment texture units */
+		gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
+		gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
+		gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
+		gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
+		gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
+		gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
+	}
+	for (i = 0; i < 4; i++) { /* vertex texture units */
+		gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
+		gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
+		gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
+		gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
+	}
+	cp_ctx(ctx, 0x400f5c, 3);
+	gr_def(ctx, 0x400f5c, 0x00000002);
+	cp_ctx(ctx, 0x400f84, 1);
+}
+
+static void
+nv40_gr_construct_state3d_2(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+
+	cp_ctx(ctx, 0x402000, 1);
+	cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
+	switch (device->chipset) {
+	case 0x40:
+		gr_def(ctx, 0x402404, 0x00000001);
+		break;
+	case 0x4c:
+	case 0x4e:
+	case 0x67:
+		gr_def(ctx, 0x402404, 0x00000020);
+		break;
+	case 0x46:
+	case 0x49:
+	case 0x4b:
+		gr_def(ctx, 0x402404, 0x00000421);
+		break;
+	default:
+		gr_def(ctx, 0x402404, 0x00000021);
+	}
+	if (device->chipset != 0x40)
+		gr_def(ctx, 0x402408, 0x030c30c3);
+	switch (device->chipset) {
+	case 0x44:
+	case 0x46:
+	case 0x4a:
+	case 0x4c:
+	case 0x4e:
+	case 0x67:
+		cp_ctx(ctx, 0x402440, 1);
+		gr_def(ctx, 0x402440, 0x00011001);
+		break;
+	default:
+		break;
+	}
+	cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
+	gr_def(ctx, 0x402488, 0x3e020200);
+	gr_def(ctx, 0x40248c, 0x00ffffff);
+	switch (device->chipset) {
+	case 0x40:
+		gr_def(ctx, 0x402490, 0x60103f00);
+		break;
+	case 0x47:
+		gr_def(ctx, 0x402490, 0x40103f00);
+		break;
+	case 0x41:
+	case 0x42:
+	case 0x49:
+	case 0x4b:
+		gr_def(ctx, 0x402490, 0x20103f00);
+		break;
+	default:
+		gr_def(ctx, 0x402490, 0x0c103f00);
+		break;
+	}
+	gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
+			      0x00020000 : 0x00040000);
+	cp_ctx(ctx, 0x402500, 31);
+	gr_def(ctx, 0x402530, 0x00008100);
+	if (device->chipset == 0x40)
+		cp_ctx(ctx, 0x40257c, 6);
+	cp_ctx(ctx, 0x402594, 16);
+	cp_ctx(ctx, 0x402800, 17);
+	gr_def(ctx, 0x402800, 0x00000001);
+	switch (device->chipset) {
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		cp_ctx(ctx, 0x402864, 1);
+		gr_def(ctx, 0x402864, 0x00001001);
+		cp_ctx(ctx, 0x402870, 3);
+		gr_def(ctx, 0x402878, 0x00000003);
+		if (device->chipset != 0x47) { /* belong at end!! */
+			cp_ctx(ctx, 0x402900, 1);
+			cp_ctx(ctx, 0x402940, 1);
+			cp_ctx(ctx, 0x402980, 1);
+			cp_ctx(ctx, 0x4029c0, 1);
+			cp_ctx(ctx, 0x402a00, 1);
+			cp_ctx(ctx, 0x402a40, 1);
+			cp_ctx(ctx, 0x402a80, 1);
+			cp_ctx(ctx, 0x402ac0, 1);
+		}
+		break;
+	case 0x40:
+		cp_ctx(ctx, 0x402844, 1);
+		gr_def(ctx, 0x402844, 0x00000001);
+		cp_ctx(ctx, 0x402850, 1);
+		break;
+	default:
+		cp_ctx(ctx, 0x402844, 1);
+		gr_def(ctx, 0x402844, 0x00001001);
+		cp_ctx(ctx, 0x402850, 2);
+		gr_def(ctx, 0x402854, 0x00000003);
+		break;
+	}
+
+	cp_ctx(ctx, 0x402c00, 4);
+	gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
+			      0x80800001 : 0x00888001);
+	switch (device->chipset) {
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		cp_ctx(ctx, 0x402c20, 40);
+		for (i = 0; i < 32; i++)
+			gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
+		cp_ctx(ctx, 0x4030b8, 13);
+		gr_def(ctx, 0x4030dc, 0x00000005);
+		gr_def(ctx, 0x4030e8, 0x0000ffff);
+		break;
+	default:
+		cp_ctx(ctx, 0x402c10, 4);
+		if (device->chipset == 0x40)
+			cp_ctx(ctx, 0x402c20, 36);
+		else
+		if (device->chipset <= 0x42)
+			cp_ctx(ctx, 0x402c20, 24);
+		else
+		if (device->chipset <= 0x4a)
+			cp_ctx(ctx, 0x402c20, 16);
+		else
+			cp_ctx(ctx, 0x402c20, 8);
+		cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
+		gr_def(ctx, 0x402cd4, 0x00000005);
+		if (device->chipset != 0x40)
+			gr_def(ctx, 0x402ce0, 0x0000ffff);
+		break;
+	}
+
+	cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403420, nv40_gr_vs_count(ctx->device));
+	for (i = 0; i < nv40_gr_vs_count(ctx->device); i++)
+		gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
+
+	if (device->chipset != 0x40) {
+		cp_ctx(ctx, 0x403600, 1);
+		gr_def(ctx, 0x403600, 0x00000001);
+	}
+	cp_ctx(ctx, 0x403800, 1);
+
+	cp_ctx(ctx, 0x403c18, 1);
+	gr_def(ctx, 0x403c18, 0x00000001);
+	switch (device->chipset) {
+	case 0x46:
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+		cp_ctx(ctx, 0x405018, 1);
+		gr_def(ctx, 0x405018, 0x08e00001);
+		cp_ctx(ctx, 0x405c24, 1);
+		gr_def(ctx, 0x405c24, 0x000e3000);
+		break;
+	}
+	if (device->chipset != 0x4e)
+		cp_ctx(ctx, 0x405800, 11);
+	cp_ctx(ctx, 0x407000, 1);
+}
+
+static void
+nv40_gr_construct_state3d_3(struct nvkm_grctx *ctx)
+{
+	int len = nv44_gr_class(ctx->device) ? 0x0084 : 0x0684;
+
+	cp_out (ctx, 0x300000);
+	cp_lsr (ctx, len - 4);
+	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
+	cp_lsr (ctx, len);
+	cp_name(ctx, cp_swap_state3d_3_is_save);
+	cp_out (ctx, 0x800001);
+
+	ctx->ctxvals_pos += len;
+}
+
+static void
+nv40_gr_construct_shader(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	struct nvkm_gpuobj *obj = ctx->data;
+	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
+	int offset, i;
+
+	vs_nr    = nv40_gr_vs_count(ctx->device);
+	vs_nr_b0 = 363;
+	vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
+	if (device->chipset == 0x40) {
+		b0_offset = 0x2200/4; /* 33a0 */
+		b1_offset = 0x55a0/4; /* 1500 */
+		vs_len = 0x6aa0/4;
+	} else
+	if (device->chipset == 0x41 || device->chipset == 0x42) {
+		b0_offset = 0x2200/4; /* 2200 */
+		b1_offset = 0x4400/4; /* 0b00 */
+		vs_len = 0x4f00/4;
+	} else {
+		b0_offset = 0x1d40/4; /* 2200 */
+		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
+		vs_len = nv44_gr_class(device) ? 0x4980/4 : 0x4a40/4;
+	}
+
+	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
+	cp_out(ctx, nv44_gr_class(device) ? 0x800029 : 0x800041);
+
+	offset = ctx->ctxvals_pos;
+	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
+
+	if (ctx->mode != NVKM_GRCTX_VALS)
+		return;
+
+	offset += 0x0280/4;
+	for (i = 0; i < 16; i++, offset += 2)
+		nv_wo32(obj, offset * 4, 0x3f800000);
+
+	for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
+		for (i = 0; i < vs_nr_b0 * 6; i += 6)
+			nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
+		for (i = 0; i < vs_nr_b1 * 4; i += 4)
+			nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
+	}
+}
+
+static void
+nv40_grctx_generate(struct nvkm_grctx *ctx)
+{
+	/* decide whether we're loading/unloading the context */
+	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+	cp_name(ctx, cp_check_load);
+	cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+	cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+	cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+
+	/* setup for context load */
+	cp_name(ctx, cp_setup_auto_load);
+	cp_wait(ctx, STATUS, IDLE);
+	cp_out (ctx, CP_NEXT_TO_SWAP);
+	cp_name(ctx, cp_setup_load);
+	cp_wait(ctx, STATUS, IDLE);
+	cp_set (ctx, SWAP_DIRECTION, LOAD);
+	cp_out (ctx, 0x00910880); /* ?? */
+	cp_out (ctx, 0x00901ffe); /* ?? */
+	cp_out (ctx, 0x01940000); /* ?? */
+	cp_lsr (ctx, 0x20);
+	cp_out (ctx, 0x0060000b); /* ?? */
+	cp_wait(ctx, UNK57, CLEAR);
+	cp_out (ctx, 0x0060000c); /* ?? */
+	cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+	/* setup for context save */
+	cp_name(ctx, cp_setup_save);
+	cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+	/* general PGRAPH state */
+	cp_name(ctx, cp_swap_state);
+	cp_pos (ctx, 0x00020/4);
+	nv40_gr_construct_general(ctx);
+	cp_wait(ctx, STATUS, IDLE);
+
+	/* 3D state, block 1 */
+	cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
+	nv40_gr_construct_state3d(ctx);
+	cp_wait(ctx, STATUS, IDLE);
+
+	/* 3D state, block 2 */
+	nv40_gr_construct_state3d_2(ctx);
+
+	/* Some other block of "random" state */
+	nv40_gr_construct_state3d_3(ctx);
+
+	/* Per-vertex shader state */
+	cp_pos (ctx, ctx->ctxvals_pos);
+	nv40_gr_construct_shader(ctx);
+
+	/* pre-exit state updates */
+	cp_name(ctx, cp_prepare_exit);
+	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+	cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+	cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+	cp_name(ctx, cp_exit);
+	cp_set (ctx, USER_SAVE, NOT_PENDING);
+	cp_set (ctx, USER_LOAD, NOT_PENDING);
+	cp_out (ctx, CP_END);
+}
+
+void
+nv40_grctx_fill(struct nvkm_device *device, struct nvkm_gpuobj *mem)
+{
+	nv40_grctx_generate(&(struct nvkm_grctx) {
+			     .device = device,
+			     .mode = NVKM_GRCTX_VALS,
+			     .data = mem,
+			   });
+}
+
+int
+nv40_grctx_init(struct nvkm_device *device, u32 *size)
+{
+	u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;
+	struct nvkm_grctx ctx = {
+		.device = device,
+		.mode = NVKM_GRCTX_PROG,
+		.data = ctxprog,
+		.ctxprog_max = 256,
+	};
+
+	if (!ctxprog)
+		return -ENOMEM;
+
+	nv40_grctx_generate(&ctx);
+
+	nv_wr32(device, 0x400324, 0);
+	for (i = 0; i < ctx.ctxprog_len; i++)
+		nv_wr32(device, 0x400328, ctxprog[i]);
+	*size = ctx.ctxvals_pos * 4;
+
+	kfree(ctxprog);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h
new file mode 100644
index 0000000..8a89961
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h
@@ -0,0 +1,129 @@
+#ifndef __NVKM_GRCTX_H__
+#define __NVKM_GRCTX_H__
+#include <core/gpuobj.h>
+
+struct nvkm_grctx {
+	struct nvkm_device *device;
+
+	enum {
+		NVKM_GRCTX_PROG,
+		NVKM_GRCTX_VALS
+	} mode;
+	void *data;
+
+	u32 ctxprog_max;
+	u32 ctxprog_len;
+	u32 ctxprog_reg;
+	int ctxprog_label[32];
+	u32 ctxvals_pos;
+	u32 ctxvals_base;
+};
+
+static inline void
+cp_out(struct nvkm_grctx *ctx, u32 inst)
+{
+	u32 *ctxprog = ctx->data;
+
+	if (ctx->mode != NVKM_GRCTX_PROG)
+		return;
+
+	BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
+	ctxprog[ctx->ctxprog_len++] = inst;
+}
+
+static inline void
+cp_lsr(struct nvkm_grctx *ctx, u32 val)
+{
+	cp_out(ctx, CP_LOAD_SR | val);
+}
+
+static inline void
+cp_ctx(struct nvkm_grctx *ctx, u32 reg, u32 length)
+{
+	ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
+
+	ctx->ctxvals_base = ctx->ctxvals_pos;
+	ctx->ctxvals_pos = ctx->ctxvals_base + length;
+
+	if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
+		cp_lsr(ctx, length);
+		length = 0;
+	}
+
+	cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
+}
+
+static inline void
+cp_name(struct nvkm_grctx *ctx, int name)
+{
+	u32 *ctxprog = ctx->data;
+	int i;
+
+	if (ctx->mode != NVKM_GRCTX_PROG)
+		return;
+
+	ctx->ctxprog_label[name] = ctx->ctxprog_len;
+	for (i = 0; i < ctx->ctxprog_len; i++) {
+		if ((ctxprog[i] & 0xfff00000) != 0xff400000)
+			continue;
+		if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
+			continue;
+		ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
+			     (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
+	}
+}
+
+static inline void
+_cp_bra(struct nvkm_grctx *ctx, u32 mod, int flag, int state, int name)
+{
+	int ip = 0;
+
+	if (mod != 2) {
+		ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
+		if (ip == 0)
+			ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
+	}
+
+	cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
+		    (state ? 0 : CP_BRA_IF_CLEAR));
+}
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+
+static inline void
+_cp_wait(struct nvkm_grctx *ctx, int flag, int state)
+{
+	cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
+}
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+_cp_set(struct nvkm_grctx *ctx, int flag, int state)
+{
+	cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
+}
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+cp_pos(struct nvkm_grctx *ctx, int offset)
+{
+	ctx->ctxvals_pos = offset;
+	ctx->ctxvals_base = ctx->ctxvals_pos;
+
+	cp_lsr(ctx, ctx->ctxvals_pos);
+	cp_out(ctx, CP_SET_CONTEXT_POINTER);
+}
+
+static inline void
+gr_def(struct nvkm_grctx *ctx, u32 reg, u32 val)
+{
+	if (ctx->mode != NVKM_GRCTX_VALS)
+		return;
+
+	reg = (reg - 0x00400000) / 4;
+	reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
+
+	nv_wo32(ctx->data, reg * 4, val);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c
new file mode 100644
index 0000000..9c9528d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c
@@ -0,0 +1,3345 @@
+/*
+ * Copyright 2009 Marcin Kościelnicki
+ *
+ * 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.
+ */
+
+#define CP_FLAG_CLEAR                 0
+#define CP_FLAG_SET                   1
+#define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD   0
+#define CP_FLAG_SWAP_DIRECTION_SAVE   1
+#define CP_FLAG_UNK01                 ((0 * 32) + 1)
+#define CP_FLAG_UNK01_CLEAR           0
+#define CP_FLAG_UNK01_SET             1
+#define CP_FLAG_UNK03                 ((0 * 32) + 3)
+#define CP_FLAG_UNK03_CLEAR           0
+#define CP_FLAG_UNK03_SET             1
+#define CP_FLAG_USER_SAVE             ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING     1
+#define CP_FLAG_USER_LOAD             ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING     1
+#define CP_FLAG_UNK0B                 ((0 * 32) + 0xb)
+#define CP_FLAG_UNK0B_CLEAR           0
+#define CP_FLAG_UNK0B_SET             1
+#define CP_FLAG_XFER_SWITCH           ((0 * 32) + 0xe)
+#define CP_FLAG_XFER_SWITCH_DISABLE   0
+#define CP_FLAG_XFER_SWITCH_ENABLE    1
+#define CP_FLAG_STATE                 ((0 * 32) + 0x1c)
+#define CP_FLAG_STATE_STOPPED         0
+#define CP_FLAG_STATE_RUNNING         1
+#define CP_FLAG_UNK1D                 ((0 * 32) + 0x1d)
+#define CP_FLAG_UNK1D_CLEAR           0
+#define CP_FLAG_UNK1D_SET             1
+#define CP_FLAG_UNK20                 ((1 * 32) + 0)
+#define CP_FLAG_UNK20_CLEAR           0
+#define CP_FLAG_UNK20_SET             1
+#define CP_FLAG_STATUS                ((2 * 32) + 0)
+#define CP_FLAG_STATUS_BUSY           0
+#define CP_FLAG_STATUS_IDLE           1
+#define CP_FLAG_AUTO_SAVE             ((2 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING     1
+#define CP_FLAG_AUTO_LOAD             ((2 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING     1
+#define CP_FLAG_NEWCTX                ((2 * 32) + 10)
+#define CP_FLAG_NEWCTX_BUSY           0
+#define CP_FLAG_NEWCTX_DONE           1
+#define CP_FLAG_XFER                  ((2 * 32) + 11)
+#define CP_FLAG_XFER_IDLE             0
+#define CP_FLAG_XFER_BUSY             1
+#define CP_FLAG_ALWAYS                ((2 * 32) + 13)
+#define CP_FLAG_ALWAYS_FALSE          0
+#define CP_FLAG_ALWAYS_TRUE           1
+#define CP_FLAG_INTR                  ((2 * 32) + 15)
+#define CP_FLAG_INTR_NOT_PENDING      0
+#define CP_FLAG_INTR_PENDING          1
+
+#define CP_CTX                   0x00100000
+#define CP_CTX_COUNT             0x000f0000
+#define CP_CTX_COUNT_SHIFT               16
+#define CP_CTX_REG               0x00003fff
+#define CP_LOAD_SR               0x00200000
+#define CP_LOAD_SR_VALUE         0x000fffff
+#define CP_BRA                   0x00400000
+#define CP_BRA_IP                0x0001ff00
+#define CP_BRA_IP_SHIFT                   8
+#define CP_BRA_IF_CLEAR          0x00000080
+#define CP_BRA_FLAG              0x0000007f
+#define CP_WAIT                  0x00500000
+#define CP_WAIT_SET              0x00000080
+#define CP_WAIT_FLAG             0x0000007f
+#define CP_SET                   0x00700000
+#define CP_SET_1                 0x00000080
+#define CP_SET_FLAG              0x0000007f
+#define CP_NEWCTX                0x00600004
+#define CP_NEXT_TO_SWAP          0x00600005
+#define CP_SET_CONTEXT_POINTER   0x00600006
+#define CP_SET_XFER_POINTER      0x00600007
+#define CP_ENABLE                0x00600009
+#define CP_END                   0x0060000c
+#define CP_NEXT_TO_CURRENT       0x0060000d
+#define CP_DISABLE1              0x0090ffff
+#define CP_DISABLE2              0x0091ffff
+#define CP_XFER_1      0x008000ff
+#define CP_XFER_2      0x008800ff
+#define CP_SEEK_1      0x00c000ff
+#define CP_SEEK_2      0x00c800ff
+
+#include "ctxnv40.h"
+
+#include <core/device.h>
+#include <subdev/fb.h>
+
+#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
+#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
+
+/*
+ * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
+ * the GPU itself that does context-switching, but it needs a special
+ * microcode to do it. And it's the driver's task to supply this microcode,
+ * further known as ctxprog, as well as the initial context values, known
+ * as ctxvals.
+ *
+ * Without ctxprog, you cannot switch contexts. Not even in software, since
+ * the majority of context [xfer strands] isn't accessible directly. You're
+ * stuck with a single channel, and you also suffer all the problems resulting
+ * from missing ctxvals, since you cannot load them.
+ *
+ * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
+ * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
+ * since you don't have... some sort of needed setup.
+ *
+ * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
+ * it's too much hassle to handle no-ctxprog as a special case.
+ */
+
+/*
+ * How ctxprogs work.
+ *
+ * The ctxprog is written in its own kind of microcode, with very small and
+ * crappy set of available commands. You upload it to a small [512 insns]
+ * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
+ * switch channel. or when the driver explicitely requests it. Stuff visible
+ * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
+ * the per-channel context save area in VRAM [known as ctxvals or grctx],
+ * 4 flags registers, a scratch register, two grctx pointers, plus many
+ * random poorly-understood details.
+ *
+ * When ctxprog runs, it's supposed to check what operations are asked of it,
+ * save old context if requested, optionally reset PGRAPH and switch to the
+ * new channel, and load the new context. Context consists of three major
+ * parts: subset of MMIO registers and two "xfer areas".
+ */
+
+/* TODO:
+ *  - document unimplemented bits compared to nvidia
+ *  - NVAx: make a TP subroutine, use it.
+ *  - use 0x4008fc instead of 0x1540?
+ */
+
+enum cp_label {
+	cp_check_load = 1,
+	cp_setup_auto_load,
+	cp_setup_load,
+	cp_setup_save,
+	cp_swap_state,
+	cp_prepare_exit,
+	cp_exit,
+};
+
+static void nv50_gr_construct_mmio(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer1(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer2(struct nvkm_grctx *ctx);
+
+/* Main function: construct the ctxprog skeleton, call the other functions. */
+
+static int
+nv50_grctx_generate(struct nvkm_grctx *ctx)
+{
+	cp_set (ctx, STATE, RUNNING);
+	cp_set (ctx, XFER_SWITCH, ENABLE);
+	/* decide whether we're loading/unloading the context */
+	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+	cp_name(ctx, cp_check_load);
+	cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+	cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+	cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit);
+
+	/* setup for context load */
+	cp_name(ctx, cp_setup_auto_load);
+	cp_out (ctx, CP_DISABLE1);
+	cp_out (ctx, CP_DISABLE2);
+	cp_out (ctx, CP_ENABLE);
+	cp_out (ctx, CP_NEXT_TO_SWAP);
+	cp_set (ctx, UNK01, SET);
+	cp_name(ctx, cp_setup_load);
+	cp_out (ctx, CP_NEWCTX);
+	cp_wait(ctx, NEWCTX, BUSY);
+	cp_set (ctx, UNK1D, CLEAR);
+	cp_set (ctx, SWAP_DIRECTION, LOAD);
+	cp_bra (ctx, UNK0B, SET, cp_prepare_exit);
+	cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+	/* setup for context save */
+	cp_name(ctx, cp_setup_save);
+	cp_set (ctx, UNK1D, SET);
+	cp_wait(ctx, STATUS, BUSY);
+	cp_wait(ctx, INTR, PENDING);
+	cp_bra (ctx, STATUS, BUSY, cp_setup_save);
+	cp_set (ctx, UNK01, SET);
+	cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+	/* general PGRAPH state */
+	cp_name(ctx, cp_swap_state);
+	cp_set (ctx, UNK03, SET);
+	cp_pos (ctx, 0x00004/4);
+	cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */
+	cp_pos (ctx, 0x00100/4);
+	nv50_gr_construct_mmio(ctx);
+	nv50_gr_construct_xfer1(ctx);
+	nv50_gr_construct_xfer2(ctx);
+
+	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+
+	cp_set (ctx, UNK20, SET);
+	cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */
+	cp_lsr (ctx, ctx->ctxvals_base);
+	cp_out (ctx, CP_SET_XFER_POINTER);
+	cp_lsr (ctx, 4);
+	cp_out (ctx, CP_SEEK_1);
+	cp_out (ctx, CP_XFER_1);
+	cp_wait(ctx, XFER, BUSY);
+
+	/* pre-exit state updates */
+	cp_name(ctx, cp_prepare_exit);
+	cp_set (ctx, UNK01, CLEAR);
+	cp_set (ctx, UNK03, CLEAR);
+	cp_set (ctx, UNK1D, CLEAR);
+
+	cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+	cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+	cp_name(ctx, cp_exit);
+	cp_set (ctx, USER_SAVE, NOT_PENDING);
+	cp_set (ctx, USER_LOAD, NOT_PENDING);
+	cp_set (ctx, XFER_SWITCH, DISABLE);
+	cp_set (ctx, STATE, STOPPED);
+	cp_out (ctx, CP_END);
+	ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
+
+	return 0;
+}
+
+void
+nv50_grctx_fill(struct nvkm_device *device, struct nvkm_gpuobj *mem)
+{
+	nv50_grctx_generate(&(struct nvkm_grctx) {
+			     .device = device,
+			     .mode = NVKM_GRCTX_VALS,
+			     .data = mem,
+			   });
+}
+
+int
+nv50_grctx_init(struct nvkm_device *device, u32 *size)
+{
+	u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
+	struct nvkm_grctx ctx = {
+		.device = device,
+		.mode = NVKM_GRCTX_PROG,
+		.data = ctxprog,
+		.ctxprog_max = 512,
+	};
+
+	if (!ctxprog)
+		return -ENOMEM;
+	nv50_grctx_generate(&ctx);
+
+	nv_wr32(device, 0x400324, 0);
+	for (i = 0; i < ctx.ctxprog_len; i++)
+		nv_wr32(device, 0x400328, ctxprog[i]);
+	*size = ctx.ctxvals_pos * 4;
+	kfree(ctxprog);
+	return 0;
+}
+
+/*
+ * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
+ * registers to save/restore and the default values for them.
+ */
+
+static void
+nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx);
+
+static void
+nv50_gr_construct_mmio(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i, j;
+	int offset, base;
+	u32 units = nv_rd32 (ctx->device, 0x1540);
+
+	/* 0800: DISPATCH */
+	cp_ctx(ctx, 0x400808, 7);
+	gr_def(ctx, 0x400814, 0x00000030);
+	cp_ctx(ctx, 0x400834, 0x32);
+	if (device->chipset == 0x50) {
+		gr_def(ctx, 0x400834, 0xff400040);
+		gr_def(ctx, 0x400838, 0xfff00080);
+		gr_def(ctx, 0x40083c, 0xfff70090);
+		gr_def(ctx, 0x400840, 0xffe806a8);
+	}
+	gr_def(ctx, 0x400844, 0x00000002);
+	if (IS_NVA3F(device->chipset))
+		gr_def(ctx, 0x400894, 0x00001000);
+	gr_def(ctx, 0x4008e8, 0x00000003);
+	gr_def(ctx, 0x4008ec, 0x00001000);
+	if (device->chipset == 0x50)
+		cp_ctx(ctx, 0x400908, 0xb);
+	else if (device->chipset < 0xa0)
+		cp_ctx(ctx, 0x400908, 0xc);
+	else
+		cp_ctx(ctx, 0x400908, 0xe);
+
+	if (device->chipset >= 0xa0)
+		cp_ctx(ctx, 0x400b00, 0x1);
+	if (IS_NVA3F(device->chipset)) {
+		cp_ctx(ctx, 0x400b10, 0x1);
+		gr_def(ctx, 0x400b10, 0x0001629d);
+		cp_ctx(ctx, 0x400b20, 0x1);
+		gr_def(ctx, 0x400b20, 0x0001629d);
+	}
+
+	nv50_gr_construct_mmio_ddata(ctx);
+
+	/* 0C00: VFETCH */
+	cp_ctx(ctx, 0x400c08, 0x2);
+	gr_def(ctx, 0x400c08, 0x0000fe0c);
+
+	/* 1000 */
+	if (device->chipset < 0xa0) {
+		cp_ctx(ctx, 0x401008, 0x4);
+		gr_def(ctx, 0x401014, 0x00001000);
+	} else if (!IS_NVA3F(device->chipset)) {
+		cp_ctx(ctx, 0x401008, 0x5);
+		gr_def(ctx, 0x401018, 0x00001000);
+	} else {
+		cp_ctx(ctx, 0x401008, 0x5);
+		gr_def(ctx, 0x401018, 0x00004000);
+	}
+
+	/* 1400 */
+	cp_ctx(ctx, 0x401400, 0x8);
+	cp_ctx(ctx, 0x401424, 0x3);
+	if (device->chipset == 0x50)
+		gr_def(ctx, 0x40142c, 0x0001fd87);
+	else
+		gr_def(ctx, 0x40142c, 0x00000187);
+	cp_ctx(ctx, 0x401540, 0x5);
+	gr_def(ctx, 0x401550, 0x00001018);
+
+	/* 1800: STREAMOUT */
+	cp_ctx(ctx, 0x401814, 0x1);
+	gr_def(ctx, 0x401814, 0x000000ff);
+	if (device->chipset == 0x50) {
+		cp_ctx(ctx, 0x40181c, 0xe);
+		gr_def(ctx, 0x401850, 0x00000004);
+	} else if (device->chipset < 0xa0) {
+		cp_ctx(ctx, 0x40181c, 0xf);
+		gr_def(ctx, 0x401854, 0x00000004);
+	} else {
+		cp_ctx(ctx, 0x40181c, 0x13);
+		gr_def(ctx, 0x401864, 0x00000004);
+	}
+
+	/* 1C00 */
+	cp_ctx(ctx, 0x401c00, 0x1);
+	switch (device->chipset) {
+	case 0x50:
+		gr_def(ctx, 0x401c00, 0x0001005f);
+		break;
+	case 0x84:
+	case 0x86:
+	case 0x94:
+		gr_def(ctx, 0x401c00, 0x044d00df);
+		break;
+	case 0x92:
+	case 0x96:
+	case 0x98:
+	case 0xa0:
+	case 0xaa:
+	case 0xac:
+		gr_def(ctx, 0x401c00, 0x042500df);
+		break;
+	case 0xa3:
+	case 0xa5:
+	case 0xa8:
+	case 0xaf:
+		gr_def(ctx, 0x401c00, 0x142500df);
+		break;
+	}
+
+	/* 2000 */
+
+	/* 2400 */
+	cp_ctx(ctx, 0x402400, 0x1);
+	if (device->chipset == 0x50)
+		cp_ctx(ctx, 0x402408, 0x1);
+	else
+		cp_ctx(ctx, 0x402408, 0x2);
+	gr_def(ctx, 0x402408, 0x00000600);
+
+	/* 2800: CSCHED */
+	cp_ctx(ctx, 0x402800, 0x1);
+	if (device->chipset == 0x50)
+		gr_def(ctx, 0x402800, 0x00000006);
+
+	/* 2C00: ZCULL */
+	cp_ctx(ctx, 0x402c08, 0x6);
+	if (device->chipset != 0x50)
+		gr_def(ctx, 0x402c14, 0x01000000);
+	gr_def(ctx, 0x402c18, 0x000000ff);
+	if (device->chipset == 0x50)
+		cp_ctx(ctx, 0x402ca0, 0x1);
+	else
+		cp_ctx(ctx, 0x402ca0, 0x2);
+	if (device->chipset < 0xa0)
+		gr_def(ctx, 0x402ca0, 0x00000400);
+	else if (!IS_NVA3F(device->chipset))
+		gr_def(ctx, 0x402ca0, 0x00000800);
+	else
+		gr_def(ctx, 0x402ca0, 0x00000400);
+	cp_ctx(ctx, 0x402cac, 0x4);
+
+	/* 3000: ENG2D */
+	cp_ctx(ctx, 0x403004, 0x1);
+	gr_def(ctx, 0x403004, 0x00000001);
+
+	/* 3400 */
+	if (device->chipset >= 0xa0) {
+		cp_ctx(ctx, 0x403404, 0x1);
+		gr_def(ctx, 0x403404, 0x00000001);
+	}
+
+	/* 5000: CCACHE */
+	cp_ctx(ctx, 0x405000, 0x1);
+	switch (device->chipset) {
+	case 0x50:
+		gr_def(ctx, 0x405000, 0x00300080);
+		break;
+	case 0x84:
+	case 0xa0:
+	case 0xa3:
+	case 0xa5:
+	case 0xa8:
+	case 0xaa:
+	case 0xac:
+	case 0xaf:
+		gr_def(ctx, 0x405000, 0x000e0080);
+		break;
+	case 0x86:
+	case 0x92:
+	case 0x94:
+	case 0x96:
+	case 0x98:
+		gr_def(ctx, 0x405000, 0x00000080);
+		break;
+	}
+	cp_ctx(ctx, 0x405014, 0x1);
+	gr_def(ctx, 0x405014, 0x00000004);
+	cp_ctx(ctx, 0x40501c, 0x1);
+	cp_ctx(ctx, 0x405024, 0x1);
+	cp_ctx(ctx, 0x40502c, 0x1);
+
+	/* 6000? */
+	if (device->chipset == 0x50)
+		cp_ctx(ctx, 0x4063e0, 0x1);
+
+	/* 6800: M2MF */
+	if (device->chipset < 0x90) {
+		cp_ctx(ctx, 0x406814, 0x2b);
+		gr_def(ctx, 0x406818, 0x00000f80);
+		gr_def(ctx, 0x406860, 0x007f0080);
+		gr_def(ctx, 0x40689c, 0x007f0080);
+	} else {
+		cp_ctx(ctx, 0x406814, 0x4);
+		if (device->chipset == 0x98)
+			gr_def(ctx, 0x406818, 0x00000f80);
+		else
+			gr_def(ctx, 0x406818, 0x00001f80);
+		if (IS_NVA3F(device->chipset))
+			gr_def(ctx, 0x40681c, 0x00000030);
+		cp_ctx(ctx, 0x406830, 0x3);
+	}
+
+	/* 7000: per-ROP group state */
+	for (i = 0; i < 8; i++) {
+		if (units & (1<<(i+16))) {
+			cp_ctx(ctx, 0x407000 + (i<<8), 3);
+			if (device->chipset == 0x50)
+				gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
+			else if (device->chipset != 0xa5)
+				gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
+			else
+				gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
+			gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
+
+			if (device->chipset == 0x50) {
+				cp_ctx(ctx, 0x407010 + (i<<8), 1);
+			} else if (device->chipset < 0xa0) {
+				cp_ctx(ctx, 0x407010 + (i<<8), 2);
+				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+				gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
+			} else {
+				cp_ctx(ctx, 0x407010 + (i<<8), 3);
+				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+				if (device->chipset != 0xa5)
+					gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
+				else
+					gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
+			}
+
+			cp_ctx(ctx, 0x407080 + (i<<8), 4);
+			if (device->chipset != 0xa5)
+				gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
+			else
+				gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
+			if (device->chipset == 0x50)
+				gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
+			else
+				gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
+			gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
+
+			if (device->chipset < 0xa0)
+				cp_ctx(ctx, 0x407094 + (i<<8), 1);
+			else if (!IS_NVA3F(device->chipset))
+				cp_ctx(ctx, 0x407094 + (i<<8), 3);
+			else {
+				cp_ctx(ctx, 0x407094 + (i<<8), 4);
+				gr_def(ctx, 0x4070a0 + (i<<8), 1);
+			}
+		}
+	}
+
+	cp_ctx(ctx, 0x407c00, 0x3);
+	if (device->chipset < 0x90)
+		gr_def(ctx, 0x407c00, 0x00010040);
+	else if (device->chipset < 0xa0)
+		gr_def(ctx, 0x407c00, 0x00390040);
+	else
+		gr_def(ctx, 0x407c00, 0x003d0040);
+	gr_def(ctx, 0x407c08, 0x00000022);
+	if (device->chipset >= 0xa0) {
+		cp_ctx(ctx, 0x407c10, 0x3);
+		cp_ctx(ctx, 0x407c20, 0x1);
+		cp_ctx(ctx, 0x407c2c, 0x1);
+	}
+
+	if (device->chipset < 0xa0) {
+		cp_ctx(ctx, 0x407d00, 0x9);
+	} else {
+		cp_ctx(ctx, 0x407d00, 0x15);
+	}
+	if (device->chipset == 0x98)
+		gr_def(ctx, 0x407d08, 0x00380040);
+	else {
+		if (device->chipset < 0x90)
+			gr_def(ctx, 0x407d08, 0x00010040);
+		else if (device->chipset < 0xa0)
+			gr_def(ctx, 0x407d08, 0x00390040);
+		else {
+			if (nvkm_fb(device)->ram->type != NV_MEM_TYPE_GDDR5)
+				gr_def(ctx, 0x407d08, 0x003d0040);
+			else
+				gr_def(ctx, 0x407d08, 0x003c0040);
+		}
+		gr_def(ctx, 0x407d0c, 0x00000022);
+	}
+
+	/* 8000+: per-TP state */
+	for (i = 0; i < 10; i++) {
+		if (units & (1<<i)) {
+			if (device->chipset < 0xa0)
+				base = 0x408000 + (i<<12);
+			else
+				base = 0x408000 + (i<<11);
+			if (device->chipset < 0xa0)
+				offset = base + 0xc00;
+			else
+				offset = base + 0x80;
+			cp_ctx(ctx, offset + 0x00, 1);
+			gr_def(ctx, offset + 0x00, 0x0000ff0a);
+			cp_ctx(ctx, offset + 0x08, 1);
+
+			/* per-MP state */
+			for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
+				if (!(units & (1 << (j+24)))) continue;
+				if (device->chipset < 0xa0)
+					offset = base + 0x200 + (j<<7);
+				else
+					offset = base + 0x100 + (j<<7);
+				cp_ctx(ctx, offset, 0x20);
+				gr_def(ctx, offset + 0x00, 0x01800000);
+				gr_def(ctx, offset + 0x04, 0x00160000);
+				gr_def(ctx, offset + 0x08, 0x01800000);
+				gr_def(ctx, offset + 0x18, 0x0003ffff);
+				switch (device->chipset) {
+				case 0x50:
+					gr_def(ctx, offset + 0x1c, 0x00080000);
+					break;
+				case 0x84:
+					gr_def(ctx, offset + 0x1c, 0x00880000);
+					break;
+				case 0x86:
+					gr_def(ctx, offset + 0x1c, 0x018c0000);
+					break;
+				case 0x92:
+				case 0x96:
+				case 0x98:
+					gr_def(ctx, offset + 0x1c, 0x118c0000);
+					break;
+				case 0x94:
+					gr_def(ctx, offset + 0x1c, 0x10880000);
+					break;
+				case 0xa0:
+				case 0xa5:
+					gr_def(ctx, offset + 0x1c, 0x310c0000);
+					break;
+				case 0xa3:
+				case 0xa8:
+				case 0xaa:
+				case 0xac:
+				case 0xaf:
+					gr_def(ctx, offset + 0x1c, 0x300c0000);
+					break;
+				}
+				gr_def(ctx, offset + 0x40, 0x00010401);
+				if (device->chipset == 0x50)
+					gr_def(ctx, offset + 0x48, 0x00000040);
+				else
+					gr_def(ctx, offset + 0x48, 0x00000078);
+				gr_def(ctx, offset + 0x50, 0x000000bf);
+				gr_def(ctx, offset + 0x58, 0x00001210);
+				if (device->chipset == 0x50)
+					gr_def(ctx, offset + 0x5c, 0x00000080);
+				else
+					gr_def(ctx, offset + 0x5c, 0x08000080);
+				if (device->chipset >= 0xa0)
+					gr_def(ctx, offset + 0x68, 0x0000003e);
+			}
+
+			if (device->chipset < 0xa0)
+				cp_ctx(ctx, base + 0x300, 0x4);
+			else
+				cp_ctx(ctx, base + 0x300, 0x5);
+			if (device->chipset == 0x50)
+				gr_def(ctx, base + 0x304, 0x00007070);
+			else if (device->chipset < 0xa0)
+				gr_def(ctx, base + 0x304, 0x00027070);
+			else if (!IS_NVA3F(device->chipset))
+				gr_def(ctx, base + 0x304, 0x01127070);
+			else
+				gr_def(ctx, base + 0x304, 0x05127070);
+
+			if (device->chipset < 0xa0)
+				cp_ctx(ctx, base + 0x318, 1);
+			else
+				cp_ctx(ctx, base + 0x320, 1);
+			if (device->chipset == 0x50)
+				gr_def(ctx, base + 0x318, 0x0003ffff);
+			else if (device->chipset < 0xa0)
+				gr_def(ctx, base + 0x318, 0x03ffffff);
+			else
+				gr_def(ctx, base + 0x320, 0x07ffffff);
+
+			if (device->chipset < 0xa0)
+				cp_ctx(ctx, base + 0x324, 5);
+			else
+				cp_ctx(ctx, base + 0x328, 4);
+
+			if (device->chipset < 0xa0) {
+				cp_ctx(ctx, base + 0x340, 9);
+				offset = base + 0x340;
+			} else if (!IS_NVA3F(device->chipset)) {
+				cp_ctx(ctx, base + 0x33c, 0xb);
+				offset = base + 0x344;
+			} else {
+				cp_ctx(ctx, base + 0x33c, 0xd);
+				offset = base + 0x344;
+			}
+			gr_def(ctx, offset + 0x0, 0x00120407);
+			gr_def(ctx, offset + 0x4, 0x05091507);
+			if (device->chipset == 0x84)
+				gr_def(ctx, offset + 0x8, 0x05100202);
+			else
+				gr_def(ctx, offset + 0x8, 0x05010202);
+			gr_def(ctx, offset + 0xc, 0x00030201);
+			if (device->chipset == 0xa3)
+				cp_ctx(ctx, base + 0x36c, 1);
+
+			cp_ctx(ctx, base + 0x400, 2);
+			gr_def(ctx, base + 0x404, 0x00000040);
+			cp_ctx(ctx, base + 0x40c, 2);
+			gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
+			gr_def(ctx, base + 0x410, 0x00141210);
+
+			if (device->chipset < 0xa0)
+				offset = base + 0x800;
+			else
+				offset = base + 0x500;
+			cp_ctx(ctx, offset, 6);
+			gr_def(ctx, offset + 0x0, 0x000001f0);
+			gr_def(ctx, offset + 0x4, 0x00000001);
+			gr_def(ctx, offset + 0x8, 0x00000003);
+			if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
+				gr_def(ctx, offset + 0xc, 0x00008000);
+			gr_def(ctx, offset + 0x14, 0x00039e00);
+			cp_ctx(ctx, offset + 0x1c, 2);
+			if (device->chipset == 0x50)
+				gr_def(ctx, offset + 0x1c, 0x00000040);
+			else
+				gr_def(ctx, offset + 0x1c, 0x00000100);
+			gr_def(ctx, offset + 0x20, 0x00003800);
+
+			if (device->chipset >= 0xa0) {
+				cp_ctx(ctx, base + 0x54c, 2);
+				if (!IS_NVA3F(device->chipset))
+					gr_def(ctx, base + 0x54c, 0x003fe006);
+				else
+					gr_def(ctx, base + 0x54c, 0x003fe007);
+				gr_def(ctx, base + 0x550, 0x003fe000);
+			}
+
+			if (device->chipset < 0xa0)
+				offset = base + 0xa00;
+			else
+				offset = base + 0x680;
+			cp_ctx(ctx, offset, 1);
+			gr_def(ctx, offset, 0x00404040);
+
+			if (device->chipset < 0xa0)
+				offset = base + 0xe00;
+			else
+				offset = base + 0x700;
+			cp_ctx(ctx, offset, 2);
+			if (device->chipset < 0xa0)
+				gr_def(ctx, offset, 0x0077f005);
+			else if (device->chipset == 0xa5)
+				gr_def(ctx, offset, 0x6cf7f007);
+			else if (device->chipset == 0xa8)
+				gr_def(ctx, offset, 0x6cfff007);
+			else if (device->chipset == 0xac)
+				gr_def(ctx, offset, 0x0cfff007);
+			else
+				gr_def(ctx, offset, 0x0cf7f007);
+			if (device->chipset == 0x50)
+				gr_def(ctx, offset + 0x4, 0x00007fff);
+			else if (device->chipset < 0xa0)
+				gr_def(ctx, offset + 0x4, 0x003f7fff);
+			else
+				gr_def(ctx, offset + 0x4, 0x02bf7fff);
+			cp_ctx(ctx, offset + 0x2c, 1);
+			if (device->chipset == 0x50) {
+				cp_ctx(ctx, offset + 0x50, 9);
+				gr_def(ctx, offset + 0x54, 0x000003ff);
+				gr_def(ctx, offset + 0x58, 0x00000003);
+				gr_def(ctx, offset + 0x5c, 0x00000003);
+				gr_def(ctx, offset + 0x60, 0x000001ff);
+				gr_def(ctx, offset + 0x64, 0x0000001f);
+				gr_def(ctx, offset + 0x68, 0x0000000f);
+				gr_def(ctx, offset + 0x6c, 0x0000000f);
+			} else if (device->chipset < 0xa0) {
+				cp_ctx(ctx, offset + 0x50, 1);
+				cp_ctx(ctx, offset + 0x70, 1);
+			} else {
+				cp_ctx(ctx, offset + 0x50, 1);
+				cp_ctx(ctx, offset + 0x60, 5);
+			}
+		}
+	}
+}
+
+static void
+dd_emit(struct nvkm_grctx *ctx, int num, u32 val) {
+	int i;
+	if (val && ctx->mode == NVKM_GRCTX_VALS)
+		for (i = 0; i < num; i++)
+			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
+	ctx->ctxvals_pos += num;
+}
+
+static void
+nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int base, num;
+	base = ctx->ctxvals_pos;
+
+	/* tesla state */
+	dd_emit(ctx, 1, 0);	/* 00000001 UNK0F90 */
+	dd_emit(ctx, 1, 0);	/* 00000001 UNK135C */
+
+	/* SRC_TIC state */
+	dd_emit(ctx, 1, 0);	/* 00000007 SRC_TILE_MODE_Z */
+	dd_emit(ctx, 1, 2);	/* 00000007 SRC_TILE_MODE_Y */
+	dd_emit(ctx, 1, 1);	/* 00000001 SRC_LINEAR #1 */
+	dd_emit(ctx, 1, 0);	/* 000000ff SRC_ADDRESS_HIGH */
+	dd_emit(ctx, 1, 0);	/* 00000001 SRC_SRGB */
+	if (device->chipset >= 0x94)
+		dd_emit(ctx, 1, 0);	/* 00000003 eng2d UNK0258 */
+	dd_emit(ctx, 1, 1);	/* 00000fff SRC_DEPTH */
+	dd_emit(ctx, 1, 0x100);	/* 0000ffff SRC_HEIGHT */
+
+	/* turing state */
+	dd_emit(ctx, 1, 0);		/* 0000000f TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f SAMPLERS_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
+	dd_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
+	dd_emit(ctx, 1, 0);		/* ffffffff SHARED_SIZE */
+	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
+	dd_emit(ctx, 1, 1);		/* 0000ffff BLOCK_ALLOC_THREADS */
+	dd_emit(ctx, 1, 1);		/* 00000001 LANES32 */
+	dd_emit(ctx, 1, 0);		/* 000000ff UNK370 */
+	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_UNK */
+	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_COUNT */
+	dd_emit(ctx, 1, 1);		/* 000000ff UNK384 bits 8-15 */
+	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_X */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_XMY */
+	dd_emit(ctx, 1, 0);		/* 00000001 BLOCKDIM_XMY_OVERFLOW */
+	dd_emit(ctx, 1, 1);		/* 0003ffff BLOCKDIM_XMYMZ */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_Y */
+	dd_emit(ctx, 1, 1);		/* 0000007f BLOCKDIM_Z */
+	dd_emit(ctx, 1, 4);		/* 000000ff CP_REG_ALLOC_TEMP */
+	dd_emit(ctx, 1, 1);		/* 00000001 BLOCKDIM_DIRTY */
+	if (IS_NVA3F(device->chipset))
+		dd_emit(ctx, 1, 0);	/* 00000003 UNK03E8 */
+	dd_emit(ctx, 1, 1);		/* 0000007f BLOCK_ALLOC_HALFWARPS */
+	dd_emit(ctx, 1, 1);		/* 00000007 LOCAL_WARPS_NO_CLAMP */
+	dd_emit(ctx, 1, 7);		/* 00000007 LOCAL_WARPS_LOG_ALLOC */
+	dd_emit(ctx, 1, 1);		/* 00000007 STACK_WARPS_NO_CLAMP */
+	dd_emit(ctx, 1, 7);		/* 00000007 STACK_WARPS_LOG_ALLOC */
+	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
+	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCK_ALLOC_THREADS */
+
+	/* compat 2d state */
+	if (device->chipset == 0x50) {
+		dd_emit(ctx, 4, 0);		/* 0000ffff clip X, Y, W, H */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff chroma COLOR_FORMAT */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff pattern COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff pattern SHAPE */
+		dd_emit(ctx, 1, 1);		/* ffffffff pattern PATTERN_SELECT */
+
+		dd_emit(ctx, 1, 0xa);		/* ffffffff surf2d SRC_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff surf2d DMA_SRC */
+		dd_emit(ctx, 1, 0);		/* 000000ff surf2d SRC_ADDRESS_HIGH */
+		dd_emit(ctx, 1, 0);		/* ffffffff surf2d SRC_ADDRESS_LOW */
+		dd_emit(ctx, 1, 0x40);		/* 0000ffff surf2d SRC_PITCH */
+		dd_emit(ctx, 1, 0);		/* 0000000f surf2d SRC_TILE_MODE_Z */
+		dd_emit(ctx, 1, 2);		/* 0000000f surf2d SRC_TILE_MODE_Y */
+		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_HEIGHT */
+		dd_emit(ctx, 1, 1);		/* 00000001 surf2d SRC_LINEAR */
+		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_WIDTH */
+
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_Y */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_Y */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_Y */
+		dd_emit(ctx, 1, 1);		/* ffffffff gdirect COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff gdirect OPERATION */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_Y */
+
+		dd_emit(ctx, 1, 0);		/* 0000ffff blit SRC_Y */
+		dd_emit(ctx, 1, 0);		/* ffffffff blit OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff ifc OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc INDEX_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc LUT_OFFSET */
+		dd_emit(ctx, 1, 4);		/* ffffffff iifc COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc OPERATION */
+	}
+
+	/* m2mf state */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_COUNT */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_LENGTH_IN */
+	dd_emit(ctx, 2, 0);		/* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
+	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_OUT */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_OUT */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_OUT_Z */
+	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_OUT */
+	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_OUT */
+	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_IN */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_IN */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_IN_Z */
+	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_IN */
+	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_IN_X, Y */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_IN */
+
+	/* more compat 2d state */
+	if (device->chipset == 0x50) {
+		dd_emit(ctx, 1, 1);		/* ffffffff line COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff line OPERATION */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff triangle COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff triangle OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* 0000000f sifm TILE_MODE_Z */
+		dd_emit(ctx, 1, 2);		/* 0000000f sifm TILE_MODE_Y */
+		dd_emit(ctx, 1, 0);		/* 000000ff sifm FORMAT_FILTER */
+		dd_emit(ctx, 1, 1);		/* 000000ff sifm FORMAT_ORIGIN */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_PITCH */
+		dd_emit(ctx, 1, 1);		/* 00000001 sifm SRC_LINEAR */
+		dd_emit(ctx, 1, 0);		/* 000000ff sifm SRC_OFFSET_HIGH */
+		dd_emit(ctx, 1, 0);		/* ffffffff sifm SRC_OFFSET */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_HEIGHT */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_WIDTH */
+		dd_emit(ctx, 1, 3);		/* ffffffff sifm COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff sifm OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff sifc OPERATION */
+	}
+
+	/* tesla state */
+	dd_emit(ctx, 1, 0);		/* 0000000f GP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f GP_SAMPLERS_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 000000ff */
+	dd_emit(ctx, 1, 0);		/* ffffffff */
+	dd_emit(ctx, 1, 4);		/* 000000ff UNK12B0_0 */
+	dd_emit(ctx, 1, 0x70);		/* 000000ff UNK12B0_1 */
+	dd_emit(ctx, 1, 0x80);		/* 000000ff UNK12B0_3 */
+	dd_emit(ctx, 1, 0);		/* 000000ff UNK12B0_2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f FP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f FP_SAMPLERS_LOG2 */
+	if (IS_NVA3F(device->chipset)) {
+		dd_emit(ctx, 1, 0);	/* ffffffff */
+		dd_emit(ctx, 1, 0);	/* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
+	} else {
+		dd_emit(ctx, 1, 0);	/* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
+	}
+	dd_emit(ctx, 1, 0xc);		/* 000000ff SEMANTIC_COLOR.BFC0_ID */
+	if (device->chipset != 0x50)
+		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_COLOR.CLMP_EN */
+	dd_emit(ctx, 1, 8);		/* 000000ff SEMANTIC_COLOR.COLR_NR */
+	dd_emit(ctx, 1, 0x14);		/* 000000ff SEMANTIC_COLOR.FFC0_ID */
+	if (device->chipset == 0x50) {
+		dd_emit(ctx, 1, 0);	/* 000000ff SEMANTIC_LAYER */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+	} else {
+		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_PTSZ.ENABLE */
+		dd_emit(ctx, 1, 0x29);	/* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
+		dd_emit(ctx, 1, 0x27);	/* 000000ff SEMANTIC_PRIM */
+		dd_emit(ctx, 1, 0x26);	/* 000000ff SEMANTIC_LAYER */
+		dd_emit(ctx, 1, 8);	/* 0000000f SMENATIC_CLIP.CLIP_HIGH */
+		dd_emit(ctx, 1, 4);	/* 000000ff SEMANTIC_CLIP.CLIP_LO */
+		dd_emit(ctx, 1, 0x27);	/* 000000ff UNK0FD4 */
+		dd_emit(ctx, 1, 0);	/* 00000001 UNK1900 */
+	}
+	dd_emit(ctx, 1, 0);		/* 00000007 RT_CONTROL_MAP0 */
+	dd_emit(ctx, 1, 1);		/* 00000007 RT_CONTROL_MAP1 */
+	dd_emit(ctx, 1, 2);		/* 00000007 RT_CONTROL_MAP2 */
+	dd_emit(ctx, 1, 3);		/* 00000007 RT_CONTROL_MAP3 */
+	dd_emit(ctx, 1, 4);		/* 00000007 RT_CONTROL_MAP4 */
+	dd_emit(ctx, 1, 5);		/* 00000007 RT_CONTROL_MAP5 */
+	dd_emit(ctx, 1, 6);		/* 00000007 RT_CONTROL_MAP6 */
+	dd_emit(ctx, 1, 7);		/* 00000007 RT_CONTROL_MAP7 */
+	dd_emit(ctx, 1, 1);		/* 0000000f RT_CONTROL_COUNT */
+	dd_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_UNK */
+	dd_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff RT_FORMAT */
+	dd_emit(ctx, 7, 0);		/* 000000ff RT_FORMAT */
+	if (device->chipset != 0x50)
+		dd_emit(ctx, 3, 0);	/* 1, 1, 1 */
+	else
+		dd_emit(ctx, 2, 0);	/* 1, 1 */
+	dd_emit(ctx, 1, 0);		/* ffffffff GP_ENABLE */
+	dd_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
+	dd_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	dd_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	if (IS_NVA3F(device->chipset)) {
+		dd_emit(ctx, 1, 3);	/* 00000003 */
+		dd_emit(ctx, 1, 0);	/* 00000001 UNK1418. Alone. */
+	}
+	if (device->chipset != 0x50)
+		dd_emit(ctx, 1, 3);	/* 00000003 UNK15AC */
+	dd_emit(ctx, 1, 1);		/* ffffffff RASTERIZE_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_CONTROL.EXPORTS_Z */
+	if (device->chipset != 0x50)
+		dd_emit(ctx, 1, 0);	/* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
+	dd_emit(ctx, 1, 0x12);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT */
+	dd_emit(ctx, 1, 0x10);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
+	dd_emit(ctx, 1, 0xc);		/* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
+	dd_emit(ctx, 1, 1);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
+	dd_emit(ctx, 1, 4);		/* 000000ff FP_RESULT_COUNT */
+	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
+	dd_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+	if (device->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* ffffffff */
+	dd_emit(ctx, 1, 0);		/* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
+	dd_emit(ctx, 1, 0);		/* ffffffff STRMOUT_ENABLE */
+	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	dd_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE*/
+	if (device->chipset != 0x50)
+		dd_emit(ctx, 8, 0);	/* 00000001 */
+	if (device->chipset >= 0xa0) {
+		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.COMP */
+		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.SIZE */
+		dd_emit(ctx, 1, 2);	/* 00000007 VTX_ATTR_DEFINE.TYPE */
+		dd_emit(ctx, 1, 0);	/* 000000ff VTX_ATTR_DEFINE.ATTR */
+	}
+	dd_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	dd_emit(ctx, 1, 0x14);		/* 0000001f ZETA_FORMAT */
+	dd_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 0000000f VP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f VP_SAMPLERS_LOG2 */
+	if (IS_NVA3F(device->chipset))
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_BACK */
+	if (device->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
+	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
+	if (device->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* 00000003 */
+	dd_emit(ctx, 1, 0);		/* 00000001 CULL_FACE_ENABLE */
+	dd_emit(ctx, 1, 1);		/* 00000003 CULL_FACE */
+	dd_emit(ctx, 1, 0);		/* 00000001 FRONT_FACE */
+	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_FRONT */
+	dd_emit(ctx, 1, 0x1000);	/* 00007fff UNK141C */
+	if (device->chipset != 0x50) {
+		dd_emit(ctx, 1, 0xe00);		/* 7fff */
+		dd_emit(ctx, 1, 0x1000);	/* 7fff */
+		dd_emit(ctx, 1, 0x1e00);	/* 7fff */
+	}
+	dd_emit(ctx, 1, 0);		/* 00000001 BEGIN_END_ACTIVE */
+	dd_emit(ctx, 1, 1);		/* 00000001 POLYGON_MODE_??? */
+	dd_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
+	dd_emit(ctx, 1, 1);		/* 000000ff FP_REG_ALLOC_TEMP... without /4? */
+	dd_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
+	dd_emit(ctx, 1, 1);		/* 00000001 */
+	dd_emit(ctx, 1, 0);		/* 00000001 */
+	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
+	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
+	dd_emit(ctx, 1, 0x200);		/* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
+	if (IS_NVA3F(device->chipset))
+		dd_emit(ctx, 1, 0x200);
+	dd_emit(ctx, 1, 0);		/* 00000001 */
+	if (device->chipset < 0xa0) {
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0x70);	/* 000000ff */
+		dd_emit(ctx, 1, 0x80);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0x70);	/* 000000ff */
+		dd_emit(ctx, 1, 0x80);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+	} else {
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
+		dd_emit(ctx, 1, 0xff);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
+		dd_emit(ctx, 1, 0xff);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 9);	/* 0000003f UNK114C.COMP,SIZE */
+	}
+
+	/* eng2d state */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d COLOR_KEY_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d COLOR_KEY_FORMAT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d DST_DEPTH */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DST_FORMAT */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d DST_LAYER */
+	dd_emit(ctx, 1, 1);		/* 00000001 eng2d DST_LINEAR */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d PATTERN_COLOR_FORMAT */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d OPERATION */
+	dd_emit(ctx, 1, 0);		/* 00000003 eng2d PATTERN_SELECT */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SIFC_FORMAT */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d SIFC_BITMAP_ENABLE */
+	dd_emit(ctx, 1, 2);		/* 00000003 eng2d SIFC_BITMAP_UNK808 */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DU_DX_FRACT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DU_DX_INT */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DV_DY_FRACT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DV_DY_INT */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d BLIT_CONTROL_FILTER */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DRAW_COLOR_FORMAT */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SRC_FORMAT */
+	dd_emit(ctx, 1, 1);		/* 00000001 eng2d SRC_LINEAR #2 */
+
+	num = ctx->ctxvals_pos - base;
+	ctx->ctxvals_pos = base;
+	if (IS_NVA3F(device->chipset))
+		cp_ctx(ctx, 0x404800, num);
+	else
+		cp_ctx(ctx, 0x405400, num);
+}
+
+/*
+ * xfer areas. These are a pain.
+ *
+ * There are 2 xfer areas: the first one is big and contains all sorts of
+ * stuff, the second is small and contains some per-TP context.
+ *
+ * Each area is split into 8 "strands". The areas, when saved to grctx,
+ * are made of 8-word blocks. Each block contains a single word from
+ * each strand. The strands are independent of each other, their
+ * addresses are unrelated to each other, and data in them is closely
+ * packed together. The strand layout varies a bit between cards: here
+ * and there, a single word is thrown out in the middle and the whole
+ * strand is offset by a bit from corresponding one on another chipset.
+ * For this reason, addresses of stuff in strands are almost useless.
+ * Knowing sequence of stuff and size of gaps between them is much more
+ * useful, and that's how we build the strands in our generator.
+ *
+ * NVA0 takes this mess to a whole new level by cutting the old strands
+ * into a few dozen pieces [known as genes], rearranging them randomly,
+ * and putting them back together to make new strands. Hopefully these
+ * genes correspond more or less directly to the same PGRAPH subunits
+ * as in 400040 register.
+ *
+ * The most common value in default context is 0, and when the genes
+ * are separated by 0's, gene bounduaries are quite speculative...
+ * some of them can be clearly deduced, others can be guessed, and yet
+ * others won't be resolved without figuring out the real meaning of
+ * given ctxval. For the same reason, ending point of each strand
+ * is unknown. Except for strand 0, which is the longest strand and
+ * its end corresponds to end of the whole xfer.
+ *
+ * An unsolved mystery is the seek instruction: it takes an argument
+ * in bits 8-18, and that argument is clearly the place in strands to
+ * seek to... but the offsets don't seem to correspond to offsets as
+ * seen in grctx. Perhaps there's another, real, not randomly-changing
+ * addressing in strands, and the xfer insn just happens to skip over
+ * the unused bits? NV10-NV30 PIPE comes to mind...
+ *
+ * As far as I know, there's no way to access the xfer areas directly
+ * without the help of ctxprog.
+ */
+
+static void
+xf_emit(struct nvkm_grctx *ctx, int num, u32 val) {
+	int i;
+	if (val && ctx->mode == NVKM_GRCTX_VALS)
+		for (i = 0; i < num; i++)
+			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
+	ctx->ctxvals_pos += num << 3;
+}
+
+/* Gene declarations... */
+
+static void nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx);
+
+static void
+nv50_gr_construct_xfer1(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+	int offset;
+	int size = 0;
+	u32 units = nv_rd32 (ctx->device, 0x1540);
+
+	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+	ctx->ctxvals_base = offset;
+
+	if (device->chipset < 0xa0) {
+		/* Strand 0 */
+		ctx->ctxvals_pos = offset;
+		nv50_gr_construct_gene_dispatch(ctx);
+		nv50_gr_construct_gene_m2mf(ctx);
+		nv50_gr_construct_gene_unk24xx(ctx);
+		nv50_gr_construct_gene_clipid(ctx);
+		nv50_gr_construct_gene_zcull(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 1 */
+		ctx->ctxvals_pos = offset + 0x1;
+		nv50_gr_construct_gene_vfetch(ctx);
+		nv50_gr_construct_gene_eng2d(ctx);
+		nv50_gr_construct_gene_csched(ctx);
+		nv50_gr_construct_gene_ropm1(ctx);
+		nv50_gr_construct_gene_ropm2(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 2 */
+		ctx->ctxvals_pos = offset + 0x2;
+		nv50_gr_construct_gene_ccache(ctx);
+		nv50_gr_construct_gene_unk1cxx(ctx);
+		nv50_gr_construct_gene_strmout(ctx);
+		nv50_gr_construct_gene_unk14xx(ctx);
+		nv50_gr_construct_gene_unk10xx(ctx);
+		nv50_gr_construct_gene_unk34xx(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 3: per-ROP group state */
+		ctx->ctxvals_pos = offset + 3;
+		for (i = 0; i < 6; i++)
+			if (units & (1 << (i + 16)))
+				nv50_gr_construct_gene_ropc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strands 4-7: per-TP state */
+		for (i = 0; i < 4; i++) {
+			ctx->ctxvals_pos = offset + 4 + i;
+			if (units & (1 << (2 * i)))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << (2 * i + 1)))
+				nv50_gr_construct_xfer_tp(ctx);
+			if ((ctx->ctxvals_pos-offset)/8 > size)
+				size = (ctx->ctxvals_pos-offset)/8;
+		}
+	} else {
+		/* Strand 0 */
+		ctx->ctxvals_pos = offset;
+		nv50_gr_construct_gene_dispatch(ctx);
+		nv50_gr_construct_gene_m2mf(ctx);
+		nv50_gr_construct_gene_unk34xx(ctx);
+		nv50_gr_construct_gene_csched(ctx);
+		nv50_gr_construct_gene_unk1cxx(ctx);
+		nv50_gr_construct_gene_strmout(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 1 */
+		ctx->ctxvals_pos = offset + 1;
+		nv50_gr_construct_gene_unk10xx(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 2 */
+		ctx->ctxvals_pos = offset + 2;
+		if (device->chipset == 0xa0)
+			nv50_gr_construct_gene_unk14xx(ctx);
+		nv50_gr_construct_gene_unk24xx(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 3 */
+		ctx->ctxvals_pos = offset + 3;
+		nv50_gr_construct_gene_vfetch(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 4 */
+		ctx->ctxvals_pos = offset + 4;
+		nv50_gr_construct_gene_ccache(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 5 */
+		ctx->ctxvals_pos = offset + 5;
+		nv50_gr_construct_gene_ropm2(ctx);
+		nv50_gr_construct_gene_ropm1(ctx);
+		/* per-ROP context */
+		for (i = 0; i < 8; i++)
+			if (units & (1<<(i+16)))
+				nv50_gr_construct_gene_ropc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 6 */
+		ctx->ctxvals_pos = offset + 6;
+		nv50_gr_construct_gene_zcull(ctx);
+		nv50_gr_construct_gene_clipid(ctx);
+		nv50_gr_construct_gene_eng2d(ctx);
+		if (units & (1 << 0))
+			nv50_gr_construct_xfer_tp(ctx);
+		if (units & (1 << 1))
+			nv50_gr_construct_xfer_tp(ctx);
+		if (units & (1 << 2))
+			nv50_gr_construct_xfer_tp(ctx);
+		if (units & (1 << 3))
+			nv50_gr_construct_xfer_tp(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 7 */
+		ctx->ctxvals_pos = offset + 7;
+		if (device->chipset == 0xa0) {
+			if (units & (1 << 4))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << 5))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << 6))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << 7))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << 8))
+				nv50_gr_construct_xfer_tp(ctx);
+			if (units & (1 << 9))
+				nv50_gr_construct_xfer_tp(ctx);
+		} else {
+			nv50_gr_construct_gene_unk14xx(ctx);
+		}
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+	}
+
+	ctx->ctxvals_pos = offset + size * 8;
+	ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+	cp_lsr (ctx, offset);
+	cp_out (ctx, CP_SET_XFER_POINTER);
+	cp_lsr (ctx, size);
+	cp_out (ctx, CP_SEEK_1);
+	cp_out (ctx, CP_XFER_1);
+	cp_wait(ctx, XFER, BUSY);
+}
+
+/*
+ * non-trivial demagiced parts of ctx init go here
+ */
+
+static void
+nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx)
+{
+	/* start of strand 0 */
+	struct nvkm_device *device = ctx->device;
+	/* SEEK */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 5, 0);
+	else if (!IS_NVA3F(device->chipset))
+		xf_emit(ctx, 6, 0);
+	else
+		xf_emit(ctx, 4, 0);
+	/* SEEK */
+	/* the PGRAPH's internal FIFO */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 8*3, 0);
+	else
+		xf_emit(ctx, 0x100*3, 0);
+	/* and another bonus slot?!? */
+	xf_emit(ctx, 3, 0);
+	/* and YET ANOTHER bonus slot? */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 3, 0);
+	/* SEEK */
+	/* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	if (device->chipset < 0x90)
+		xf_emit(ctx, 4, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 6*2, 0);
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 6*2, 0);
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 0x1c, 0);
+	else if (device->chipset < 0xa0)
+		xf_emit(ctx, 0x1e, 0);
+	else
+		xf_emit(ctx, 0x22, 0);
+	/* SEEK */
+	xf_emit(ctx, 0x15, 0);
+}
+
+static void
+nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx)
+{
+	/* Strand 0, right after dispatch */
+	struct nvkm_device *device = ctx->device;
+	int smallm2mf = 0;
+	if (device->chipset < 0x92 || device->chipset == 0x98)
+		smallm2mf = 1;
+	/* SEEK */
+	xf_emit (ctx, 1, 0);		/* DMA_NOTIFY instance >> 4 */
+	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_IN instance >> 4 */
+	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_OUT instance >> 4 */
+	xf_emit (ctx, 1, 0);		/* OFFSET_IN */
+	xf_emit (ctx, 1, 0);		/* OFFSET_OUT */
+	xf_emit (ctx, 1, 0);		/* PITCH_IN */
+	xf_emit (ctx, 1, 0);		/* PITCH_OUT */
+	xf_emit (ctx, 1, 0);		/* LINE_LENGTH */
+	xf_emit (ctx, 1, 0);		/* LINE_COUNT */
+	xf_emit (ctx, 1, 0x21);		/* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */
+	xf_emit (ctx, 1, 1);		/* LINEAR_IN */
+	xf_emit (ctx, 1, 0x2);		/* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */
+	xf_emit (ctx, 1, 0x100);	/* TILING_PITCH_IN */
+	xf_emit (ctx, 1, 0x100);	/* TILING_HEIGHT_IN */
+	xf_emit (ctx, 1, 1);		/* TILING_DEPTH_IN */
+	xf_emit (ctx, 1, 0);		/* TILING_POSITION_IN_Z */
+	xf_emit (ctx, 1, 0);		/* TILING_POSITION_IN */
+	xf_emit (ctx, 1, 1);		/* LINEAR_OUT */
+	xf_emit (ctx, 1, 0x2);		/* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */
+	xf_emit (ctx, 1, 0x100);	/* TILING_PITCH_OUT */
+	xf_emit (ctx, 1, 0x100);	/* TILING_HEIGHT_OUT */
+	xf_emit (ctx, 1, 1);		/* TILING_DEPTH_OUT */
+	xf_emit (ctx, 1, 0);		/* TILING_POSITION_OUT_Z */
+	xf_emit (ctx, 1, 0);		/* TILING_POSITION_OUT */
+	xf_emit (ctx, 1, 0);		/* OFFSET_IN_HIGH */
+	xf_emit (ctx, 1, 0);		/* OFFSET_OUT_HIGH */
+	/* SEEK */
+	if (smallm2mf)
+		xf_emit(ctx, 0x40, 0);	/* 20 * ffffffff, 3ffff */
+	else
+		xf_emit(ctx, 0x100, 0);	/* 80 * ffffffff, 3ffff */
+	xf_emit(ctx, 4, 0);		/* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
+	/* SEEK */
+	if (smallm2mf)
+		xf_emit(ctx, 0x400, 0);	/* ffffffff */
+	else
+		xf_emit(ctx, 0x800, 0);	/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
+	/* SEEK */
+	xf_emit(ctx, 0x40, 0);		/* 20 * bits ffffffff, 3ffff */
+	xf_emit(ctx, 0x6, 0);		/* 1f, 0, 1f, 0, 1f, 0 */
+}
+
+static void
+nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 2, 0);		/* RO */
+	xf_emit(ctx, 0x800, 0);		/* ffffffff */
+	switch (device->chipset) {
+	case 0x50:
+	case 0x92:
+	case 0xa0:
+		xf_emit(ctx, 0x2b, 0);
+		break;
+	case 0x84:
+		xf_emit(ctx, 0x29, 0);
+		break;
+	case 0x94:
+	case 0x96:
+	case 0xa3:
+		xf_emit(ctx, 0x27, 0);
+		break;
+	case 0x86:
+	case 0x98:
+	case 0xa5:
+	case 0xa8:
+	case 0xaa:
+	case 0xac:
+	case 0xaf:
+		xf_emit(ctx, 0x25, 0);
+		break;
+	}
+	/* CB bindings, 0x80 of them. first word is address >> 8, second is
+	 * size >> 4 | valid << 24 */
+	xf_emit(ctx, 0x100, 0);		/* ffffffff CB_DEF */
+	xf_emit(ctx, 1, 0);		/* 0000007f CB_ADDR_BUFFER */
+	xf_emit(ctx, 1, 0);		/* 0 */
+	xf_emit(ctx, 0x30, 0);		/* ff SET_PROGRAM_CB */
+	xf_emit(ctx, 1, 0);		/* 3f last SET_PROGRAM_CB */
+	xf_emit(ctx, 4, 0);		/* RO */
+	xf_emit(ctx, 0x100, 0);		/* ffffffff */
+	xf_emit(ctx, 8, 0);		/* 1f, 0, 0, ... */
+	xf_emit(ctx, 8, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 3 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CODE_CB */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TIC */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TSC */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
+	xf_emit(ctx, 1, 0);		/* 000000ff TIC_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff TIC_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	xf_emit(ctx, 1, 0);		/* 000000ff TSC_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff TSC_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	xf_emit(ctx, 1, 0);		/* 000000ff VP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff VP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff VP_START_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff GP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff GP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff GP_START_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff FP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff FP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff FP_START_ID */
+}
+
+static void
+nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+	/* end of area 2 on pre-NVA0, area 1 on NVAx */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);
+	else
+		xf_emit(ctx, 1, 0x7ff);	/* 000007ff */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	for (i = 0; i < 8; i++) {
+		switch (device->chipset) {
+		case 0x50:
+		case 0x86:
+		case 0x98:
+		case 0xaa:
+		case 0xac:
+			xf_emit(ctx, 0xa0, 0);	/* ffffffff */
+			break;
+		case 0x84:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+			xf_emit(ctx, 0x120, 0);
+			break;
+		case 0xa5:
+		case 0xa8:
+			xf_emit(ctx, 0x100, 0);	/* ffffffff */
+			break;
+		case 0xa0:
+		case 0xa3:
+		case 0xaf:
+			xf_emit(ctx, 0x400, 0);	/* ffffffff */
+			break;
+		}
+		xf_emit(ctx, 4, 0);	/* 3f, 0, 0, 0 */
+		xf_emit(ctx, 4, 0);	/* ffffffff */
+	}
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_TEMP */
+	xf_emit(ctx, 1, 1);		/* 00000001 RASTERIZE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0x27);		/* 000000ff UNK0FD4 */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);		/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* end of area 2 on pre-NVA0, area 1 on NVAx */
+	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000003 VIEWPORT_CLIP_MODE */
+	xf_emit(ctx, 0x10, 0x04000000);	/* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
+	xf_emit(ctx, 0x20, 0);		/* ffffffff POLYGON_STIPPLE */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0x1fe21);	/* 0001ffff tesla UNK0FAC */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0x0fac6881);
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 1);
+		xf_emit(ctx, 3, 0);
+	}
+}
+
+static void
+nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
+	if (device->chipset != 0x50) {
+		xf_emit(ctx, 5, 0);		/* ffffffff */
+		xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 1, 0);		/* 000003ff */
+		xf_emit(ctx, 1, 0x804);		/* 00000fff SEMANTIC_CLIP */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 2, 4);		/* 7f, ff */
+		xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	}
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 000000ff VP_CLIP_DISTANCE_ENABLE */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0);		/* 3ff */
+	xf_emit(ctx, 1, 0);			/* 000000ff tesla UNK1940 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
+	xf_emit(ctx, 1, 0x804);			/* 00000fff SEMANTIC_CLIP */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0x7f);		/* 000000ff tesla UNK0FFC */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 SHADE_MODEL */
+	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0F8C */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 4, 0);			/* ffffffff NOPERSPECTIVE_BITMAP */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);		/* 000003ff tesla UNK0D68 */
+	else
+		xf_emit(ctx, 1, 0x7ff);		/* 000007ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);			/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
+	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
+	xf_emit(ctx, 3, 0);			/* ffffffff last VIEWPORT_SCALE? */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 00000001 */
+	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_TRANSLATE */
+	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
+	xf_emit(ctx, 3, 0);			/* ffffffff */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 2, 0x88);			/* 000001ff tesla UNK19D8 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 4);			/* 0000000f CULL_MODE */
+	xf_emit(ctx, 2, 0);			/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 2, 0);			/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0);			/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 0x10, 0);			/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
+	xf_emit(ctx, 1, 0x3f800000);		/* ffffffff LINE_WIDTH */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	if (device->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);		/* ffffffff */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 1, 0);		/* 000003ff */
+	}
+	xf_emit(ctx, 0x20, 0);			/* 10xbits ffffffff, 3fffff. SCISSOR_* */
+	xf_emit(ctx, 1, 0);			/* f */
+	xf_emit(ctx, 1, 0);			/* 0? */
+	xf_emit(ctx, 1, 0);			/* ffffffff */
+	xf_emit(ctx, 1, 0);			/* 003fffff */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0x52);			/* 000001ff SEMANTIC_PTSZ */
+	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);		/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
+}
+
+static void
+nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1108 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
+	/* SEEK */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
+	xf_emit(ctx, 1, 3);		/* 00000003 FP_CTRL_UNK196C */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1968 */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 0fffffff tesla UNK1104 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK151C */
+}
+
+static void
+nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx)
+{
+	/* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000007 UNK0FB4 */
+	/* SEEK */
+	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_HORIZ */
+	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_VERT */
+	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff UNK1508 */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLIPID_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_HEIGHT */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CLIPID */
+}
+
+static void
+nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+	/* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 0x33, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 4, 0);	/* RO */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
+
+		xf_emit(ctx, 4, 0);	/* RO */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
+	} else {
+		xf_emit(ctx, 0xc, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+
+		/* SEEK */
+		xf_emit(ctx, 0xc, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	/* SEEK */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 2, 4);	/* 000000ff */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0x27);		/* 000000ff SEMANTIC_PRIM_ID */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	for (i = 0; i < 10; i++) {
+		/* SEEK */
+		xf_emit(ctx, 0x40, 0);		/* ffffffff */
+		xf_emit(ctx, 0x10, 0);		/* 3, 0, 0.... */
+		xf_emit(ctx, 0x10, 0);		/* ffffffff */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_CTRL */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff NOPERSPECTIVE_BITMAP */
+	xf_emit(ctx, 0x10, 0);		/* 00ffffff POINT_COORD_REPLACE_MAP */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+}
+
+static void
+nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int acnt = 0x10, rep, i;
+	/* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
+	if (IS_NVA3F(device->chipset))
+		acnt = 0x20;
+	/* SEEK */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK13A4 */
+		xf_emit(ctx, 1, 1);	/* 00000fff tesla UNK1318 */
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff VERTEX_BUFFER_FIRST */
+	xf_emit(ctx, 1, 0);		/* 00000001 PRIMITIVE_RESTART_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0DE8 */
+	xf_emit(ctx, 1, 0);		/* ffffffff PRIMITIVE_RESTART_INDEX */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATR_MASK_UNK0DD0 */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0x20);		/* 0000ffff tesla UNK129C */
+	xf_emit(ctx, 1, 0);		/* 000000ff turing UNK370??? */
+	xf_emit(ctx, 1, 0);		/* 0000ffff turing USER_PARAM_COUNT */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0xb, 0);	/* RO */
+	else if (device->chipset >= 0xa0)
+		xf_emit(ctx, 0x9, 0);	/* RO */
+	else
+		xf_emit(ctx, 0x8, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 EDGE_FLAG */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	/* SEEK */
+	xf_emit(ctx, 0xc, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 7f/ff */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 4);		/* 000001ff UNK1A28 */
+	xf_emit(ctx, 1, 8);		/* 000001ff UNK0DF0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);	/* 3ff tesla UNK0D68 */
+	else
+		xf_emit(ctx, 1, 0x7ff);	/* 7ff tesla UNK0D68 */
+	if (device->chipset == 0xa8)
+		xf_emit(ctx, 1, 0x1e00);	/* 7fff */
+	/* SEEK */
+	xf_emit(ctx, 0xc, 0);		/* RO or close */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	if (device->chipset > 0x50 && device->chipset < 0xa0)
+		xf_emit(ctx, 2, 0);	/* ffffffff */
+	else
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0FD8 */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 0x10, 0);	/* 0? */
+		xf_emit(ctx, 2, 0);	/* weird... */
+		xf_emit(ctx, 2, 0);	/* RO */
+	} else {
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 1, 0);	/* weird... */
+		xf_emit(ctx, 2, 0);	/* RO */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff VB_ELEMENT_BASE */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK1438 */
+	xf_emit(ctx, acnt, 0);		/* 1 tesla UNK1000 */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1118? */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
+	xf_emit(ctx, 1, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
+	xf_emit(ctx, 1, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* RO */
+	xf_emit(ctx, 2, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK111C? */
+	xf_emit(ctx, 1, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 000000ff UNK15F4_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK15F4_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 000000ff UNK0F84_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK0F84_ADDRESS_LOW */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 00000fff VERTEX_ARRAY_STRIDE */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_LOW */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_ARRAY_HIGH */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_LIMIT_LOW */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_LIMIT_HIGH */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, acnt, 0);		/* f */
+		xf_emit(ctx, 3, 0);		/* f/1f */
+	}
+	/* SEEK */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 2, 0);	/* RO */
+	else
+		xf_emit(ctx, 5, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffff DMA_VTXBUF */
+	/* SEEK */
+	if (device->chipset < 0xa0) {
+		xf_emit(ctx, 0x41, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0x11, 0);	/* RO */
+	} else if (!IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0x50, 0);	/* RO */
+	else
+		xf_emit(ctx, 0x58, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, 1, 1);		/* 1 UNK0DEC */
+	/* SEEK */
+	xf_emit(ctx, acnt*4, 0);	/* ffffffff VTX_ATTR */
+	xf_emit(ctx, 4, 0);		/* f/1f, 0, 0, 0 */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0x1d, 0);	/* RO */
+	else
+		xf_emit(ctx, 0x16, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	/* SEEK */
+	if (device->chipset < 0xa0)
+		xf_emit(ctx, 8, 0);	/* RO */
+	else if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0xc, 0);	/* RO */
+	else
+		xf_emit(ctx, 7, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 0xa, 0);		/* RO */
+	if (device->chipset == 0xa0)
+		rep = 0xc;
+	else
+		rep = 4;
+	for (i = 0; i < rep; i++) {
+		/* SEEK */
+		if (IS_NVA3F(device->chipset))
+			xf_emit(ctx, 0x20, 0);	/* ffffffff */
+		xf_emit(ctx, 0x200, 0);	/* ffffffff */
+		xf_emit(ctx, 4, 0);	/* 7f/ff, 0, 0, 0 */
+		xf_emit(ctx, 4, 0);	/* ffffffff */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 113/111 */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATTR_MASK_UNK0DD0 */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 7, 0);	/* weird... */
+	else
+		xf_emit(ctx, 5, 0);	/* weird... */
+}
+
+static void
+nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 2, 0);		/* 0001ffff CLIP_X, CLIP_Y */
+	xf_emit(ctx, 2, 0);		/* 0000ffff CLIP_W, CLIP_H */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIP_ENABLE */
+	if (device->chipset < 0xa0) {
+		/* this is useless on everything but the original NV50,
+		 * guess they forgot to nuke it. Or just didn't bother. */
+		xf_emit(ctx, 2, 0);	/* 0000ffff IFC_CLIP_X, Y */
+		xf_emit(ctx, 2, 1);	/* 0000ffff IFC_CLIP_W, H */
+		xf_emit(ctx, 1, 0);	/* 00000001 IFC_CLIP_ENABLE */
+	}
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
+	xf_emit(ctx, 1, 0x11);		/* 3f[NV50]/7f[NV84+] DST_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff DRAW_POINT_X */
+	xf_emit(ctx, 1, 8);		/* 0000000f DRAW_UNK58C */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_X_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_X_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_Y_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_Y_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DX_DU_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DX_DU_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DY_DV_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DY_DV_INT */
+	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_WIDTH */
+	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_HEIGHT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
+	xf_emit(ctx, 1, 2);		/* 00000003 SIFC_BITMAP_UNK808 */
+	xf_emit(ctx, 1, 0);		/* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
+	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_LSB_FIRST */
+	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_X */
+	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_Y */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_W */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_H */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_X_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff BLIT_SRC_X_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_Y_FRACT */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK888 */
+	xf_emit(ctx, 1, 4);		/* 0000003f UNK884 */
+	xf_emit(ctx, 1, 0);		/* 00000007 UNK880 */
+	xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK0FB8 */
+	xf_emit(ctx, 1, 0x15);		/* 000000ff tesla UNK128C */
+	xf_emit(ctx, 2, 0);		/* 00000007, ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK260 */
+	xf_emit(ctx, 1, 0x4444480);	/* 1fffffff UNK870 */
+	/* SEEK */
+	xf_emit(ctx, 0x10, 0);
+	/* SEEK */
+	xf_emit(ctx, 0x27, 0);
+}
+
+static void
+nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff turing UNK364 */
+	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK36C */
+	xf_emit(ctx, 1, 0);		/* 0000ffff USER_PARAM_COUNT */
+	xf_emit(ctx, 1, 0x100);		/* 00ffffff turing UNK384 */
+	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK2A0 */
+	xf_emit(ctx, 1, 0);		/* 0000ffff GRIDID */
+	xf_emit(ctx, 1, 0x10001);	/* ffffffff GRIDDIM_XY */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0x10001);	/* ffffffff BLOCKDIM_XY */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLOCKDIM_Z */
+	xf_emit(ctx, 1, 0x10001);	/* 00ffffff BLOCK_ALLOC */
+	xf_emit(ctx, 1, 1);		/* 00000001 LANES32 */
+	xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+	xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
+	/* SEEK */
+	xf_emit(ctx, 0x40, 0);		/* ffffffff USER_PARAM */
+	switch (device->chipset) {
+	case 0x50:
+	case 0x92:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x80, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0x10*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x84:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x60, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x94:
+	case 0x96:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x40, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 8*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x86:
+	case 0x98:
+		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
+		xf_emit(ctx, 0x10, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa0:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0xf0, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0x1e*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa3:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x60, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa5:
+	case 0xaf:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x30, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 6*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xaa:
+		xf_emit(ctx, 0x12, 0);
+		break;
+	case 0xa8:
+	case 0xac:
+		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
+		xf_emit(ctx, 0x10, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
+		break;
+	}
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000000 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0000001f */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 000000ff */
+}
+
+static void
+nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0x3f800000);	/* ffffffff LINE_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
+	xf_emit(ctx, 3, 0);		/* 00000001 POLYGON_OFFSET_*_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
+	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_UNITS */
+	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_FACTOR */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
+	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0x11);		/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_LINEAR */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 3);	/* 00000003 UNK16B4 */
+	else if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 1);	/* 00000001 UNK16B4 */
+	xf_emit(ctx, 1, 0);		/* 00000003 MULTISAMPLE_CTRL */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0F90 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 5);		/* 0000000f UNK1408 */
+	xf_emit(ctx, 1, 0x52);		/* 000001ff SEMANTIC_PTSZ */
+	xf_emit(ctx, 1, 0);		/* ffffffff POINT_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 00000007 tesla UNK0FB4 */
+	if (device->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);	/* 3ff */
+		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK1110 */
+	}
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1928 */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0x10);		/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 0x20, 0);		/* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK187C */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 5);		/* 0000000f tesla UNK1220 */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 000000ff tesla UNK1A20 */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
+	if (device->chipset < 0xa0)
+		xf_emit(ctx, 0x1c, 0);	/* RO */
+	else if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0x9, 0);
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	if (device->chipset != 0x50) {
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
+		xf_emit(ctx, 1, 0);	/* 3ff */
+	}
+	/* XXX: the following block could belong either to unk1cxx, or
+	 * to STRMOUT. Rather hard to tell. */
+	if (device->chipset < 0xa0)
+		xf_emit(ctx, 0x25, 0);
+	else
+		xf_emit(ctx, 0x3b, 0);
+}
+
+static void
+nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
+	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
+	}
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);	/* 000003ff tesla UNK0D68 */
+	else
+		xf_emit(ctx, 1, 0x7ff);	/* 000007ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
+	xf_emit(ctx, 4, 0);		/* 000000ff STRMOUT_ADDRESS_HIGH */
+	xf_emit(ctx, 4, 0);		/* ffffffff STRMOUT_ADDRESS_LOW */
+	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
+	}
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STRMOUT */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	xf_emit(ctx, 0x20, 0);		/* ffffffff STRMOUT_MAP */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000000? */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+}
+
+static void
+nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 eng2d UNK260 */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int magic2;
+	if (device->chipset == 0x50) {
+		magic2 = 0x00003e60;
+	} else if (!IS_NVA3F(device->chipset)) {
+		magic2 = 0x001ffe67;
+	} else {
+		magic2 = 0x00087e67;
+	}
+	xf_emit(ctx, 1, 0);		/* f/7 MUTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
+		xf_emit(ctx, 1, 0x15);	/* 000000ff */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0x10);		/* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
+		xf_emit(ctx, 3, 0);	/* ff, ffffffff, ffffffff */
+		xf_emit(ctx, 1, 4);	/* 7 */
+		xf_emit(ctx, 1, 0x400);	/* fffffff */
+		xf_emit(ctx, 1, 0x300);	/* ffff */
+		xf_emit(ctx, 1, 0x1001);	/* 1fff */
+		if (device->chipset != 0xa0) {
+			if (IS_NVA3F(device->chipset))
+				xf_emit(ctx, 1, 0);	/* 0000000f UNK15C8 */
+			else
+				xf_emit(ctx, 1, 0x15);	/* ff */
+		}
+	}
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 2, 0);		/* ffff0ff3, ffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 2, 0);
+		xf_emit(ctx, 1, 0x1001);
+		xf_emit(ctx, 0xb, 0);
+	} else {
+		xf_emit(ctx, 1, 0);	/* 00000007 */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1534 */
+		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+		xf_emit(ctx, 8, 0);	/* 00000001 BLEND_ENABLE */
+		xf_emit(ctx, 1, 0);	/* ffff0ff3 */
+	}
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	if (device->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);	/* 0000000f LOGIC_OP */
+		xf_emit(ctx, 1, 0);	/* 000000ff */
+	}
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 2, 1);		/* 00000007 BLEND_EQUATION_RGB, ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK12E4 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 0000000f */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+	} else if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 00000007 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+	} else {
+		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1430 */
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A3C */
+	}
+	xf_emit(ctx, 4, 0);		/* ffffffff CLEAR_COLOR */
+	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR A R G B */
+	xf_emit(ctx, 1, 0);		/* 00000fff eng2d UNK2B0 */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f LOGIC_OP */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4? NVA3+ only? */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK15C4 */
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
+	}
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 00000007 PATTERN_COLOR_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 PATTERN_MONO_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_BITMAP */
+	xf_emit(ctx, 1, 0);		/* 00000003 PATTERN_SELECT */
+	xf_emit(ctx, 1, 0);		/* 000000ff ROP */
+	xf_emit(ctx, 1, 0);		/* ffffffff BETA1 */
+	xf_emit(ctx, 1, 0);		/* ffffffff BETA4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 0x50, 0);		/* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
+}
+
+static void
+nv50_gr_construct_xfer_unk84xx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int magic3;
+	switch (device->chipset) {
+	case 0x50:
+		magic3 = 0x1000;
+		break;
+	case 0x86:
+	case 0x98:
+	case 0xa8:
+	case 0xaa:
+	case 0xac:
+	case 0xaf:
+		magic3 = 0x1e00;
+		break;
+	default:
+		magic3 = 0;
+	}
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113[NVA0+] */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0x1f, 0);	/* ffffffff */
+	else if (device->chipset >= 0xa0)
+		xf_emit(ctx, 0x0f, 0);	/* ffffffff */
+	else
+		xf_emit(ctx, 0x10, 0);	/* fffffff VP_RESULT_MAP_1 up */
+	xf_emit(ctx, 2, 0);		/* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0x03020100);	/* ffffffff */
+	else
+		xf_emit(ctx, 1, 0x00608080);	/* fffffff VP_RESULT_MAP_0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 2, 0);		/* 111/113, 7f/ff */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	if (magic3)
+		xf_emit(ctx, 1, magic3);	/* 00007fff tesla UNK141C */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 0x1f, 0);		/* ffffffff GP_RESULT_MAP_1 up */
+	xf_emit(ctx, 1, 0);		/* 0000001f */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x03020100);	/* ffffffff GP_RESULT_MAP_0 */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+	if (magic3)
+		xf_emit(ctx, 1, magic3);	/* 7fff tesla UNK141C */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK13A0 */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	if (device->chipset == 0x94 || device->chipset == 0x96)
+		xf_emit(ctx, 0x1020, 0);	/* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+	else if (device->chipset < 0xa0)
+		xf_emit(ctx, 0xa20, 0);	/* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+	else if (!IS_NVA3F(device->chipset))
+		xf_emit(ctx, 0x210, 0);	/* ffffffff */
+	else
+		xf_emit(ctx, 0x410, 0);	/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_gr_construct_xfer_tprop(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int magic1, magic2;
+	if (device->chipset == 0x50) {
+		magic1 = 0x3ff;
+		magic2 = 0x00003e60;
+	} else if (!IS_NVA3F(device->chipset)) {
+		magic1 = 0x7ff;
+		magic2 = 0x001ffe67;
+	} else {
+		magic1 = 0x7ff;
+		magic2 = 0x00087e67;
+	}
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* ffffffff ALPHA_TEST_REF */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000000f UNK16A0 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FDC */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ff[NV50]/3ff[NV84+] */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff COLOR_KEY */
+	xf_emit(ctx, 1, 0);		/* 00000001 COLOR_KEY_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 COLOR_KEY_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff SIFC_BITMAP_COLOR */
+	xf_emit(ctx, 1, 1);		/* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK16B4 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1298 */
+	} else if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK16B4 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+	} else {
+		xf_emit(ctx, 1, 0);	/* 00000003 MULTISAMPLE_CTRL */
+	}
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+	}
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff DRAW_COLOR_FORMAT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SRC_FORMAT */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 8, 1);		/* 00000001 UNK19E0 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0);	/* ff */
+	else
+		xf_emit(ctx, 3, 0);	/* 1, 7, 3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, magic1);	/* 3ff/7ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 8, 0);		/* 0000ffff DMA_COLOR */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_GLOBAL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_LOCAL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STACK */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_DST */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 8, 0);		/* 000000ff RT_ADDRESS_HIGH */
+	xf_emit(ctx, 8, 0);		/* ffffffff RT_LAYER_STRIDE */
+	xf_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
+	xf_emit(ctx, 8, 8);		/* 0000007f RT_TILE_MODE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 8, 0x400);		/* 0fffffff RT_HORIZ */
+	xf_emit(ctx, 8, 0x300);		/* 0000ffff RT_VERT */
+	xf_emit(ctx, 1, 1);		/* 00001fff RT_ARRAY_MODE */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x20);		/* 00000fff DST_TILE_MODE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
+	xf_emit(ctx, 1, 0);		/* 000007ff DST_LAYER */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* ffffffff DST_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 000000ff DST_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0x40);		/* 0007ffff DST_PITCH */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 0000ffff */
+	xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK15AC */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_ZETA */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 2, 0);		/* ffff, ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_LAYER_STRIDE */
+	xf_emit(ctx, 1, 0);		/* 000000ff ZETA_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_ADDRESS_LOW */
+	xf_emit(ctx, 1, 4);		/* 00000007 ZETA_TILE_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0x400);		/* 0fffffff ZETA_HORIZ */
+	xf_emit(ctx, 1, 0x300);		/* 0000ffff ZETA_VERT */
+	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	}
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	if (device->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0x0fac6881);	/* fffffff */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 0000000f tesla UNK15C8 */
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 3, 0);		/* 7/f, 1, ffff0ff3 */
+		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
+		xf_emit(ctx, 4, 0);		/* 1, 1, 1, 3ff */
+		xf_emit(ctx, 1, 4);		/* 7 */
+		xf_emit(ctx, 1, 0);		/* 1 */
+		xf_emit(ctx, 2, 1);		/* 1 */
+		xf_emit(ctx, 2, 0);		/* 7, f */
+		xf_emit(ctx, 1, 1);		/* 1 */
+		xf_emit(ctx, 1, 0);		/* 7/f */
+		if (IS_NVA3F(device->chipset))
+			xf_emit(ctx, 0x9, 0);	/* 1 */
+		else
+			xf_emit(ctx, 0x8, 0);	/* 1 */
+		xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+		xf_emit(ctx, 8, 1);		/* 1 */
+		xf_emit(ctx, 1, 0x11);		/* 7f */
+		xf_emit(ctx, 7, 0);		/* 7f */
+		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
+		xf_emit(ctx, 1, 0xf);		/* f */
+		xf_emit(ctx, 7, 0);		/* f */
+		xf_emit(ctx, 1, 0x11);		/* 7f */
+		xf_emit(ctx, 1, 1);		/* 1 */
+		xf_emit(ctx, 5, 0);		/* 1, 7, 3ff, 3, 7 */
+		if (IS_NVA3F(device->chipset)) {
+			xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+			xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		}
+	}
+}
+
+static void
+nv50_gr_construct_xfer_tex(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 2, 0);		/* 1 LINKED_TSC. yes, 2. */
+	if (device->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 3 */
+	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 0);		/* fffff BLIT_DV_DY_FRACT */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 1, 0);	/* 3 BLIT_CONTROL */
+	else
+		xf_emit(ctx, 2, 0);	/* 3ff, 1 */
+	xf_emit(ctx, 1, 0x2a712488);	/* ffffffff SRC_TIC_0 */
+	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_1 */
+	xf_emit(ctx, 1, 0x4085c000);	/* ffffffff SRC_TIC_2 */
+	xf_emit(ctx, 1, 0x40);		/* ffffffff SRC_TIC_3 */
+	xf_emit(ctx, 1, 0x100);		/* ffffffff SRC_TIC_4 */
+	xf_emit(ctx, 1, 0x10100);	/* ffffffff SRC_TIC_5 */
+	xf_emit(ctx, 1, 0x02800000);	/* ffffffff SRC_TIC_6 */
+	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_7 */
+	if (device->chipset == 0x50) {
+		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK358 */
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
+		xf_emit(ctx, 1, 0);	/* 00000003 turing UNK37C tesla UNK1690 */
+		xf_emit(ctx, 1, 0);	/* 00000003 BLIT_CONTROL */
+		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK32C tesla UNK0F94 */
+	} else if (!IS_NVAAF(device->chipset)) {
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1664 / turing UNK03E8 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+	} else {
+		xf_emit(ctx, 0x6, 0);
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A34 */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TEXTURE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_SRC */
+}
+
+static void
+nv50_gr_construct_xfer_unk8cxx(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 2, 0);		/* 7, ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK0F98 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
+	xf_emit(ctx, 1, 0x30201000);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0x70605040);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0xb8a89888);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0xf8e8d8c8);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+}
+
+static void
+nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	if (device->chipset < 0xa0) {
+		nv50_gr_construct_xfer_unk84xx(ctx);
+		nv50_gr_construct_xfer_tprop(ctx);
+		nv50_gr_construct_xfer_tex(ctx);
+		nv50_gr_construct_xfer_unk8cxx(ctx);
+	} else {
+		nv50_gr_construct_xfer_tex(ctx);
+		nv50_gr_construct_xfer_tprop(ctx);
+		nv50_gr_construct_xfer_unk8cxx(ctx);
+		nv50_gr_construct_xfer_unk84xx(ctx);
+	}
+}
+
+static void
+nv50_gr_construct_xfer_mpc(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i, mpcnt = 2;
+	switch (device->chipset) {
+		case 0x98:
+		case 0xaa:
+			mpcnt = 1;
+			break;
+		case 0x50:
+		case 0x84:
+		case 0x86:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+		case 0xa8:
+		case 0xac:
+			mpcnt = 2;
+			break;
+		case 0xa0:
+		case 0xa3:
+		case 0xa5:
+		case 0xaf:
+			mpcnt = 3;
+			break;
+	}
+	for (i = 0; i < mpcnt; i++) {
+		xf_emit(ctx, 1, 0);		/* ff */
+		xf_emit(ctx, 1, 0x80);		/* ffffffff tesla UNK1404 */
+		xf_emit(ctx, 1, 0x80007004);	/* ffffffff tesla UNK12B0 */
+		xf_emit(ctx, 1, 0x04000400);	/* ffffffff */
+		if (device->chipset >= 0xa0)
+			xf_emit(ctx, 1, 0xc0);	/* 00007fff tesla UNK152C */
+		xf_emit(ctx, 1, 0x1000);	/* 0000ffff tesla UNK0D60 */
+		xf_emit(ctx, 1, 0);		/* ff/3ff */
+		xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+		if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
+			xf_emit(ctx, 1, 0xe00);		/* 7fff */
+			xf_emit(ctx, 1, 0x1e00);	/* 7fff */
+		}
+		xf_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
+		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+		if (device->chipset == 0x50)
+			xf_emit(ctx, 2, 0x1000);	/* 7fff tesla UNK141C */
+		xf_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+		xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
+		if (IS_NVAAF(device->chipset))
+			xf_emit(ctx, 0xb, 0);	/* RO */
+		else if (device->chipset >= 0xa0)
+			xf_emit(ctx, 0xc, 0);	/* RO */
+		else
+			xf_emit(ctx, 0xa, 0);	/* RO */
+	}
+	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);			/* ff/3ff */
+	if (device->chipset >= 0xa0) {
+		xf_emit(ctx, 1, 0x1fe21);	/* 0003ffff tesla UNK0FAC */
+	}
+	xf_emit(ctx, 3, 0);			/* 7fff, 0, 0 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);			/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 4, 0xffff);		/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 1, 1);			/* 00000001 LANES32 */
+	xf_emit(ctx, 1, 0x10001);		/* 00ffffff BLOCK_ALLOC */
+	xf_emit(ctx, 1, 0x10001);		/* ffffffff BLOCKDIM_XY */
+	xf_emit(ctx, 1, 1);			/* 0000ffff BLOCKDIM_Z */
+	xf_emit(ctx, 1, 0);			/* ffffffff SHARED_SIZE */
+	xf_emit(ctx, 1, 0x1fe21);		/* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A34 */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);			/* ff/3ff */
+	xf_emit(ctx, 1, 0);			/* 1 LINKED_TSC */
+	xf_emit(ctx, 1, 0);			/* ff FP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);			/* ffffffff FP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 4);			/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);			/* 000000ff FRAG_COLOR_CLAMP_EN */
+	xf_emit(ctx, 1, 2);			/* 00000003 REG_MODE */
+	xf_emit(ctx, 1, 0x11);			/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 7, 0);			/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 1, 0);			/* 00000007 */
+	xf_emit(ctx, 1, 0xfac6881);		/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);			/* 00000003 MULTISAMPLE_CTRL */
+	if (IS_NVA3F(device->chipset))
+		xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK16B4 */
+	xf_emit(ctx, 1, 0);			/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);			/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 4);			/* ffffffff tesla UNK1400 */
+	xf_emit(ctx, 8, 0);			/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 00000001 UNK133C */
+	if (IS_NVA3F(device->chipset)) {
+		xf_emit(ctx, 1, 0);		/* 00000001 UNK12E4 */
+		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1928 */
+		xf_emit(ctx, 1, 0);		/* 00000001 UNK1140 */
+	}
+	xf_emit(ctx, 1, 0);			/* 00000003 tesla UNK0F90 */
+	xf_emit(ctx, 1, 4);			/* 000000ff FP_RESULT_COUNT */
+	/* XXX: demagic this part some day */
+	if (device->chipset == 0x50)
+		xf_emit(ctx, 0x3a0, 0);
+	else if (device->chipset < 0x94)
+		xf_emit(ctx, 0x3a2, 0);
+	else if (device->chipset == 0x98 || device->chipset == 0xaa)
+		xf_emit(ctx, 0x39f, 0);
+	else
+		xf_emit(ctx, 0x3a3, 0);
+	xf_emit(ctx, 1, 0x11);			/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0);			/* 7 OPERATION */
+	xf_emit(ctx, 1, 1);			/* 1 DST_LINEAR */
+	xf_emit(ctx, 0x2d, 0);
+}
+
+static void
+nv50_gr_construct_xfer2(struct nvkm_grctx *ctx)
+{
+	struct nvkm_device *device = ctx->device;
+	int i;
+	u32 offset;
+	u32 units = nv_rd32 (ctx->device, 0x1540);
+	int size = 0;
+
+	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+
+	if (device->chipset < 0xa0) {
+		for (i = 0; i < 8; i++) {
+			ctx->ctxvals_pos = offset + i;
+			/* that little bugger belongs to csched. No idea
+			 * what it's doing here. */
+			if (i == 0)
+				xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
+			if (units & (1 << i))
+				nv50_gr_construct_xfer_mpc(ctx);
+			if ((ctx->ctxvals_pos-offset)/8 > size)
+				size = (ctx->ctxvals_pos-offset)/8;
+		}
+	} else {
+		/* Strand 0: TPs 0, 1 */
+		ctx->ctxvals_pos = offset;
+		/* that little bugger belongs to csched. No idea
+		 * what it's doing here. */
+		xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
+		if (units & (1 << 0))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 1))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 1: TPs 2, 3 */
+		ctx->ctxvals_pos = offset + 1;
+		if (units & (1 << 2))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 3))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 2: TPs 4, 5, 6 */
+		ctx->ctxvals_pos = offset + 2;
+		if (units & (1 << 4))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 5))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 6))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+
+		/* Strand 3: TPs 7, 8, 9 */
+		ctx->ctxvals_pos = offset + 3;
+		if (units & (1 << 7))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 8))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if (units & (1 << 9))
+			nv50_gr_construct_xfer_mpc(ctx);
+		if ((ctx->ctxvals_pos-offset)/8 > size)
+			size = (ctx->ctxvals_pos-offset)/8;
+	}
+	ctx->ctxvals_pos = offset + size * 8;
+	ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+	cp_lsr (ctx, offset);
+	cp_out (ctx, CP_SET_XFER_POINTER);
+	cp_lsr (ctx, size);
+	cp_out (ctx, CP_SEEK_2);
+	cp_out (ctx, CP_XFER_2);
+	cp_wait(ctx, XFER, BUSY);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc
new file mode 100644
index 0000000..64208bf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc
@@ -0,0 +1,335 @@
+/* fuc microcode util functions for gf100 PGRAPH
+ *
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_CODE
+// queue_put - add request to queue
+//
+// In : $r13 queue pointer
+//	$r14 command
+//	$r15 data
+//
+queue_put:
+	// make sure we have space..
+	ld b32 $r8 D[$r13 + 0x0]	// GET
+	ld b32 $r9 D[$r13 + 0x4]	// PUT
+	xor $r8 8
+	cmpu b32 $r8 $r9
+	bra ne #queue_put_next
+		mov $r15 E_CMD_OVERFLOW
+		call(error)
+		ret
+
+	// store cmd/data on queue
+	queue_put_next:
+	and $r8 $r9 7
+	shl b32 $r8 3
+	add b32 $r8 $r13
+	add b32 $r8 8
+	st b32 D[$r8 + 0x0] $r14
+	st b32 D[$r8 + 0x4] $r15
+
+	// update PUT
+	add b32 $r9 1
+	and $r9 0xf
+	st b32 D[$r13 + 0x4] $r9
+	ret
+
+// queue_get - fetch request from queue
+//
+// In : $r13 queue pointer
+//
+// Out:	$p1  clear on success (data available)
+//	$r14 command
+// 	$r15 data
+//
+queue_get:
+	bset $flags $p1
+	ld b32 $r8 D[$r13 + 0x0]	// GET
+	ld b32 $r9 D[$r13 + 0x4]	// PUT
+	cmpu b32 $r8 $r9
+	bra e #queue_get_done
+		// fetch first cmd/data pair
+		and $r9 $r8 7
+		shl b32 $r9 3
+		add b32 $r9 $r13
+		add b32 $r9 8
+		ld b32 $r14 D[$r9 + 0x0]
+		ld b32 $r15 D[$r9 + 0x4]
+
+		// update GET
+		add b32 $r8 1
+		and $r8 0xf
+		st b32 D[$r13 + 0x0] $r8
+		bclr $flags $p1
+queue_get_done:
+	ret
+
+// nv_rd32 - read 32-bit value from nv register
+//
+// In : $r14 register
+// Out: $r15 value
+//
+nv_rd32:
+	mov b32 $r12 $r14
+	bset $r12 31			// MMIO_CTRL_PENDING
+	nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
+	nv_rd32_wait:
+		nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
+		xbit $r12 $r12 31
+		bra ne #nv_rd32_wait
+	mov $r10 6			// DONE_MMIO_RD
+	call(wait_doneo)
+	nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0)
+	ret
+
+// nv_wr32 - write 32-bit value to nv register
+//
+// In : $r14 register
+//      $r15 value
+//
+nv_wr32:
+	nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15)
+	mov b32 $r12 $r14
+	bset $r12 31			// MMIO_CTRL_PENDING
+	bset $r12 30			// MMIO_CTRL_WRITE
+	nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
+	nv_wr32_wait:
+		nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
+		xbit $r12 $r12 31
+		bra ne #nv_wr32_wait
+	ret
+
+// wait_donez - wait on FUC_DONE bit to become clear
+//
+// In : $r10 bit to wait on
+//
+wait_donez:
+	trace_set(T_WAIT);
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+	wait_donez_ne:
+		nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+		xbit $r8 $r8 $r10
+		bra ne #wait_donez_ne
+	trace_clr(T_WAIT)
+	ret
+
+// wait_doneo - wait on FUC_DONE bit to become set
+//
+// In : $r10 bit to wait on
+//
+wait_doneo:
+	trace_set(T_WAIT);
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+	wait_doneo_e:
+		nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+		xbit $r8 $r8 $r10
+		bra e #wait_doneo_e
+	trace_clr(T_WAIT)
+	ret
+
+// mmctx_size - determine size of a mmio list transfer
+//
+// In : $r14 mmio list head
+//      $r15 mmio list tail
+// Out: $r15 transfer size (in bytes)
+//
+mmctx_size:
+	clear b32 $r9
+	nv_mmctx_size_loop:
+		ld b32 $r8 D[$r14]
+		shr b32 $r8 26
+		add b32 $r8 1
+		shl b32 $r8 2
+		add b32 $r9 $r8
+		add b32 $r14 4
+		cmpu b32 $r14 $r15
+		bra ne #nv_mmctx_size_loop
+	mov b32 $r15 $r9
+	ret
+
+// mmctx_xfer - execute a list of mmio transfers
+//
+// In : $r10 flags
+//		bit 0: direction (0 = save, 1 = load)
+//		bit 1: set if first transfer
+//		bit 2: set if last transfer
+//	$r11 base
+//	$r12 mmio list head
+//	$r13 mmio list tail
+//	$r14 multi_stride
+//	$r15 multi_mask
+//
+mmctx_xfer:
+	trace_set(T_MMCTX)
+	clear b32 $r9
+	or $r11 $r11
+	bra e #mmctx_base_disabled
+		nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11)
+		bset $r9 0			// BASE_EN
+	mmctx_base_disabled:
+	or $r14 $r14
+	bra e #mmctx_multi_disabled
+		nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14)
+		nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15)
+		bset $r9 1			// MULTI_EN
+	mmctx_multi_disabled:
+
+	xbit $r11 $r10 0
+	shl b32 $r11 16			// DIR
+	bset $r11 12			// QLIMIT = 0x10
+	xbit $r14 $r10 1
+	shl b32 $r14 17
+	or $r11 $r14			// START_TRIGGER
+	nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
+
+	// loop over the mmio list, and send requests to the hw
+	mmctx_exec_loop:
+		// wait for space in mmctx queue
+		mmctx_wait_free:
+			nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+			and $r14 0x1f
+			bra e #mmctx_wait_free
+
+		// queue up an entry
+		ld b32 $r14 D[$r12]
+		or $r14 $r9
+		nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14)
+		add b32 $r12 4
+		cmpu b32 $r12 $r13
+		bra ne #mmctx_exec_loop
+
+	xbit $r11 $r10 2
+	bra ne #mmctx_stop
+		// wait for queue to empty
+		mmctx_fini_wait:
+			nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+			and $r11 0x1f
+			cmpu b32 $r11 0x10
+			bra ne #mmctx_fini_wait
+		mov $r10 5			// DONE_MMCTX
+		call(wait_donez)
+		bra #mmctx_done
+	mmctx_stop:
+		xbit $r11 $r10 0
+		shl b32 $r11 16			// DIR
+		bset $r11 12			// QLIMIT = 0x10
+		bset $r11 18			// STOP_TRIGGER
+		nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
+		mmctx_stop_wait:
+			// wait for STOP_TRIGGER to clear
+			nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+			xbit $r11 $r11 18
+			bra ne #mmctx_stop_wait
+	mmctx_done:
+	trace_clr(T_MMCTX)
+	ret
+
+// Wait for DONE_STRAND
+//
+strand_wait:
+	push $r10
+	mov $r10 2
+	call(wait_donez)
+	pop $r10
+	ret
+
+// unknown - call before issuing strand commands
+//
+strand_pre:
+	mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+	call(strand_wait)
+	ret
+
+// unknown - call after issuing strand commands
+//
+strand_post:
+	mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+	call(strand_wait)
+	ret
+
+// Selects strand set?!
+//
+// In: $r14 id
+//
+strand_set:
+	mov $r12 0xf
+	nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12)
+	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+	nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14)
+	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+	call(strand_wait)
+	ret
+
+// Initialise strand context data
+//
+// In : $r15 context base
+// Out: $r15 context size (in bytes)
+//
+// Strandset(?) 3 hardcoded currently
+//
+strand_ctx_init:
+	trace_set(T_STRINIT)
+	call(strand_pre)
+	mov $r14 3
+	call(strand_set)
+
+	clear b32 $r12
+	nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12)
+	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+	call(strand_wait)
+	sub b32 $r12 $r0 1
+	nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12)
+	mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+	call(strand_wait)
+	call(strand_post)
+
+	// read the size of each strand, poke the context offset of
+	// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
+	// about it later then.
+	nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00)
+	nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00)
+	shr b32 $r14 $r15 8
+	ctx_init_strand_loop:
+		iowr I[$r8 + 0x000] $r14	// STRAND_SAVE_SWBASE
+		iowr I[$r8 + 0x100] $r14	// STRAND_LOAD_SWBASE
+		iord $r10 I[$r8 + 0x200]	// STRAND_SIZE
+		shr b32 $r10 6
+		add b32 $r10 1
+		add b32 $r14 $r10
+		add b32 $r8 4
+		sub b32 $r9 1
+		bra ne #ctx_init_strand_loop
+
+	shl b32 $r14 8
+	sub b32 $r15 $r14 $r15
+	trace_clr(T_STRINIT)
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
new file mode 100644
index 0000000..eaed159
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
@@ -0,0 +1,378 @@
+/* fuc microcode for gf100 PGRAPH/GPC
+ *
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* TODO
+ * - bracket certain functions with scratch writes, useful for debugging
+ * - watchdog timer around ctx operations
+ */
+
+#ifdef INCLUDE_DATA
+gpc_mmio_list_head:	.b32 #mmio_list_base
+gpc_mmio_list_tail:
+tpc_mmio_list_head:	.b32 #mmio_list_base
+tpc_mmio_list_tail:
+unk_mmio_list_head:	.b32 #mmio_list_base
+unk_mmio_list_tail:	.b32 #mmio_list_base
+
+gpc_id:			.b32 0
+
+tpc_count:		.b32 0
+tpc_mask:		.b32 0
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+unk_count:		.b32 0
+unk_mask:		.b32 0
+#endif
+
+cmd_queue:		queue_init
+
+mmio_list_base:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see os.h)
+//
+error:
+	push $r14
+	nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
+	mov $r15 1
+	nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
+	pop $r14
+	ret
+
+// GPC fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+//   CC_SCRATCH[1]: context base
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: GPC context size
+//
+init:
+	clear b32 $r0
+
+	// setup stack
+	nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
+	extr $r1 $r1 9:17
+	shl b32 $r1 8
+	mov $sp $r1
+
+	// enable fifo access
+	mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
+
+	// enable fifo interrupt
+	mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
+
+	// enable interrupts
+	bset $flags ie0
+
+	// figure out which GPC we are, and how many TPCs we have
+	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
+	mov $r3 1
+	and $r2 0x1f
+	shl b32 $r3 $r2
+	sub b32 $r3 1
+	st b32 D[$r0 + #tpc_count] $r2
+	st b32 D[$r0 + #tpc_mask] $r3
+	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
+	st b32 D[$r0 + #gpc_id] $r2
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// figure out which, and how many, UNKs are actually present
+	imm32($r14, 0x500c30)
+	clear b32 $r2
+	clear b32 $r3
+	clear b32 $r4
+	init_unk_loop:
+		call(nv_rd32)
+		cmp b32 $r15 0
+		bra z #init_unk_next
+			mov $r15 1
+			shl b32 $r15 $r2
+			or $r4 $r15
+			add b32 $r3 1
+		init_unk_next:
+		add b32 $r2 1
+		add b32 $r14 4
+		cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
+		bra ne #init_unk_loop
+	init_unk_done:
+	st b32 D[$r0 + #unk_count] $r3
+	st b32 D[$r0 + #unk_mask] $r4
+#endif
+
+	// initialise context base, and size tracking
+	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
+	clear b32 $r3		// track GPC context size here
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't currently ever change
+	shr b32 $r5 $r2 8
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
+
+	// calculate GPC mmio context size
+	ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
+	ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
+	call(mmctx_size)
+	add b32 $r2 $r15
+	add b32 $r3 $r15
+
+	// calculate per-TPC mmio context size
+	ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
+	ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
+	call(mmctx_size)
+	ld b32 $r14 D[$r0 + #tpc_count]
+	mulu $r14 $r15
+	add b32 $r2 $r14
+	add b32 $r3 $r14
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// calculate per-UNK mmio context size
+	ld b32 $r14 D[$r0 + #unk_mmio_list_head]
+	ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
+	call(mmctx_size)
+	ld b32 $r14 D[$r0 + #unk_count]
+	mulu $r14 $r15
+	add b32 $r2 $r14
+	add b32 $r3 $r14
+#endif
+
+	// round up base/size to 256 byte boundary (for strand SWBASE)
+	shr b32 $r3 2
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
+	shr b32 $r2 8
+	shr b32 $r3 6
+	add b32 $r2 1
+	add b32 $r3 1
+	shl b32 $r2 8
+	shl b32 $r3 8
+
+	// calculate size of strand context data
+	mov b32 $r15 $r2
+	call(strand_ctx_init)
+	add b32 $r3 $r15
+
+	// save context size, and tell HUB we're done
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
+	clear b32 $r2
+	bset $r2 31
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call(queue_get)
+	bra $p1 #main
+
+	// 0x0000-0x0003 are all context transfers
+	cmpu b32 $r14 0x04
+	bra nc #main_not_ctx_xfer
+		// fetch $flags and mask off $p1/$p2
+		mov $r1 $flags
+		mov $r2 0x0006
+		not b32 $r2
+		and $r1 $r2
+		// set $p1/$p2 according to transfer type
+		shl b32 $r14 1
+		or $r1 $r14
+		mov $flags $r1
+		// transfer context data
+		call(ctx_xfer)
+		bra #main
+
+	main_not_ctx_xfer:
+	shl b32 $r15 $r14 16
+	or $r15 E_BAD_COMMAND
+	call(error)
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+	clear b32 $r0
+
+	// incoming fifo command?
+	nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
+	and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r13 #cmd_queue
+		nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
+		nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
+		call(queue_put)
+		mov $r14 1
+		nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
+
+	// ack, and wake up main()
+	ih_no_fifo:
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+// Set this GPC's bit in HUB_BAR, used to signal completion of various
+// activities to the HUB fuc
+//
+hub_barrier_done:
+	mov $r15 1
+	ld b32 $r14 D[$r0 + #gpc_id]
+	shl b32 $r15 $r14
+	nv_wr32(0x409418, $r15)	// 0x409418 - HUB_BAR_SET
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
+	mov $r14 8
+	ctx_redswitch_delay:
+		sub b32 $r14 1
+		bra ne #ctx_redswitch_delay
+	or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
+	or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
+	ret
+
+// Transfer GPC context data between GPU and storage area
+//
+// In: $r15 context base address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// set context base address
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
+	bra not $p1 #ctx_xfer_not_load
+		call(ctx_redswitch)
+	ctx_xfer_not_load:
+
+	// strands
+	call(strand_pre)
+	clear b32 $r2
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
+	xbit $r2 $flags $p1	// SAVE/LOAD
+	add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 2		// first
+	imm32($r11,0x500000)
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
+	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
+	mov $r14 0		// not multi
+	call(mmctx_xfer)
+
+	// per-TPC mmio context
+	xbit $r10 $flags $p1	// direction
+#if !NV_PGRAPH_GPCX_UNK__SIZE
+	or $r10 4		// last
+#endif
+	imm32($r11, 0x504000)
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
+	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
+	ld b32 $r15 D[$r0 + #tpc_mask]
+	mov $r14 0x800		// stride = 0x800
+	call(mmctx_xfer)
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// per-UNK mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 4		// last
+	imm32($r11, 0x503000)
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_UNK0
+	ld b32 $r12 D[$r0 + #unk_mmio_list_head]
+	ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
+	ld b32 $r15 D[$r0 + #unk_mask]
+	mov $r14 0x200		// stride = 0x200
+	call(mmctx_xfer)
+#endif
+
+	// wait for strands to finish
+	call(strand_wait)
+
+	// if load, or a save without a load following, do some
+	// unknown stuff that's done after finishing a block of
+	// strand commands
+	bra $p1 #ctx_xfer_post
+	bra not $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		call(strand_post)
+
+	// mark completion in HUB's barrier
+	ctx_xfer_done:
+	call(hub_barrier_done)
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3
new file mode 100644
index 0000000..7cf2bf9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000000
+
+#define CHIPSET GF100
+#include "macros.fuc"
+
+.section #gf100_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gf100_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
new file mode 100644
index 0000000..ea32f56
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
@@ -0,0 +1,530 @@
+uint32_t gf100_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x00000064,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x00000064,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x00000064,
+/* 0x000c: unk_mmio_list_tail */
+	0x00000064,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gf100_grgpc_code[] = {
+	0x03a10ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0xe0f900f8,
+	0xf102ffb9,
+	0xf09814e7,
+	0x21f440e3,
+	0x01f7f09d,
+	0xf102ffb9,
+	0xf09c1ce7,
+	0x21f440e3,
+	0xf8e0fc9d,
+/* 0x03a1: init */
+	0xf104bd00,
+	0xf0420017,
+	0x11cf0013,
+	0x0911e700,
+	0x0814b601,
+	0xf00014fe,
+	0x07f10227,
+	0x03f01200,
+	0x0002d000,
+	0x17f104bd,
+	0x10fe04e6,
+	0x0007f100,
+	0x0003f007,
+	0xbd0000d0,
+	0x0427f004,
+	0x040007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0xf11031f4,
+	0xf0820027,
+	0x22cf0123,
+	0x0137f000,
+	0xbb1f24f0,
+	0x32b60432,
+	0x05028001,
+	0xf1060380,
+	0xf0860027,
+	0x22cf0123,
+	0x04028000,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0xf1082595,
+	0xf0c00007,
+	0x05d00103,
+	0xf104bd00,
+	0xf0c10007,
+	0x05d00103,
+	0x9804bd00,
+	0x0f98000e,
+	0x5021f501,
+	0x002fbb01,
+	0x98003fbb,
+	0x0f98010e,
+	0x5021f502,
+	0x050e9801,
+	0xbb00effd,
+	0x3ebb002e,
+	0x0235b600,
+	0xd30007f1,
+	0xd00103f0,
+	0x04bd0003,
+	0xb60825b6,
+	0x20b60635,
+	0x0130b601,
+	0xb60824b6,
+	0x2fb90834,
+	0xd321f502,
+	0x003fbb02,
+	0x010007f1,
+	0xd00203f0,
+	0x04bd0003,
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f008,
+	0xbd0002d0,
+/* 0x04a9: main */
+	0x0031f404,
+	0xf00028f4,
+	0x21f41cd7,
+	0xf401f439,
+	0xf404e4b0,
+	0x81fe1e18,
+	0x0627f001,
+	0x12fd20bd,
+	0x01e4b604,
+	0xfe051efd,
+	0x21f50018,
+	0x0ef4059e,
+/* 0x04d9: main_not_ctx_xfer */
+	0x10ef94d3,
+	0xf501f5f0,
+	0xf4037e21,
+/* 0x04e6: ih */
+	0x80f9c60e,
+	0xf90188fe,
+	0xf990f980,
+	0xf9b0f9a0,
+	0xf9e0f9d0,
+	0xf104bdf0,
+	0xf00200a7,
+	0xaacf00a3,
+	0x04abc400,
+	0xf02c0bf4,
+	0xe7f11cd7,
+	0xe3f01a00,
+	0x00eecf00,
+	0x1900f7f1,
+	0xcf00f3f0,
+	0x21f400ff,
+	0x01e7f004,
+	0x1d0007f1,
+	0xd00003f0,
+	0x04bd000e,
+/* 0x0534: ih_no_fifo */
+	0x010007f1,
+	0xd00003f0,
+	0x04bd000a,
+	0xe0fcf0fc,
+	0xb0fcd0fc,
+	0x90fca0fc,
+	0x88fe80fc,
+	0xf480fc00,
+	0x01f80032,
+/* 0x0558: hub_barrier_done */
+	0x9801f7f0,
+	0xfebb040e,
+	0x02ffb904,
+	0x9418e7f1,
+	0xf440e3f0,
+	0x00f89d21,
+/* 0x0570: ctx_redswitch */
+	0xf120f7f0,
+	0xf0850007,
+	0x0fd00103,
+	0xf004bd00,
+/* 0x0582: ctx_redswitch_delay */
+	0xe2b608e7,
+	0xfd1bf401,
+	0x0800f5f1,
+	0x0200f5f1,
+	0x850007f1,
+	0xd00103f0,
+	0x04bd000f,
+/* 0x059e: ctx_xfer */
+	0x07f100f8,
+	0x03f08100,
+	0x000fd002,
+	0x11f404bd,
+	0x7021f507,
+/* 0x05b1: ctx_xfer_not_load */
+	0x6a21f505,
+	0xf124bd02,
+	0xf047fc07,
+	0x02d00203,
+	0xf004bd00,
+	0x20b6012c,
+	0xfc07f103,
+	0x0203f04a,
+	0xbd0002d0,
+	0x01acf004,
+	0xf102a5f0,
+	0xf00000b7,
+	0x0c9850b3,
+	0x0fc4b604,
+	0x9800bcbb,
+	0x0d98000c,
+	0x00e7f001,
+	0x016f21f5,
+	0xf001acf0,
+	0xb7f104a5,
+	0xb3f04000,
+	0x040c9850,
+	0xbb0fc4b6,
+	0x0c9800bc,
+	0x020d9801,
+	0xf1060f98,
+	0xf50800e7,
+	0xf5016f21,
+	0xf4025e21,
+	0x12f40601,
+/* 0x0629: ctx_xfer_post */
+	0x7f21f507,
+/* 0x062d: ctx_xfer_done */
+	0x5821f502,
+	0x0000f805,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3
new file mode 100644
index 0000000..c918f7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #gf117_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gf117_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
new file mode 100644
index 0000000..9a36d9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gf117_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gf117_grgpc_code[] = {
+	0x03a10ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0xe0f900f8,
+	0xf102ffb9,
+	0xf09814e7,
+	0x21f440e3,
+	0x01f7f09d,
+	0xf102ffb9,
+	0xf09c1ce7,
+	0x21f440e3,
+	0xf8e0fc9d,
+/* 0x03a1: init */
+	0xf104bd00,
+	0xf0420017,
+	0x11cf0013,
+	0x0911e700,
+	0x0814b601,
+	0xf00014fe,
+	0x07f10227,
+	0x03f01200,
+	0x0002d000,
+	0x17f104bd,
+	0x10fe0530,
+	0x0007f100,
+	0x0003f007,
+	0xbd0000d0,
+	0x0427f004,
+	0x040007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0xf11031f4,
+	0xf0820027,
+	0x22cf0123,
+	0x0137f000,
+	0xbb1f24f0,
+	0x32b60432,
+	0x05028001,
+	0xf1060380,
+	0xf0860027,
+	0x22cf0123,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0421: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0436: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40126b0,
+/* 0x0442: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0xf1082595,
+	0xf0c00007,
+	0x05d00103,
+	0xf104bd00,
+	0xf0c10007,
+	0x05d00103,
+	0x9804bd00,
+	0x0f98000e,
+	0x5021f501,
+	0x002fbb01,
+	0x98003fbb,
+	0x0f98010e,
+	0x5021f502,
+	0x050e9801,
+	0xbb00effd,
+	0x3ebb002e,
+	0x020e9800,
+	0xf5030f98,
+	0x98015021,
+	0xeffd070e,
+	0x002ebb00,
+	0xb6003ebb,
+	0x07f10235,
+	0x03f0d300,
+	0x0003d001,
+	0x25b604bd,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb02d321,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0080007,
+	0x02d00203,
+/* 0x04f3: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0x7e21f501,
+	0xc60ef403,
+/* 0x0530: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x24d7f02c,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xf00421f4,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x057e: ih_no_fifo */
+	0x07f104bd,
+	0x03f00100,
+	0x000ad000,
+	0xf0fc04bd,
+	0xd0fce0fc,
+	0xa0fcb0fc,
+	0x80fc90fc,
+	0xfc0088fe,
+	0x0032f480,
+/* 0x05a2: hub_barrier_done */
+	0xf7f001f8,
+	0x040e9801,
+	0xb904febb,
+	0xe7f102ff,
+	0xe3f09418,
+	0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+	0xf7f000f8,
+	0x0007f120,
+	0x0103f085,
+	0xbd000fd0,
+	0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+	0xf401e2b6,
+	0xf5f1fd1b,
+	0xf5f10800,
+	0x07f10200,
+	0x03f08500,
+	0x000fd001,
+	0x00f804bd,
+/* 0x05e8: ctx_xfer */
+	0x810007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+	0xf505ba21,
+	0xbd026a21,
+	0xfc07f124,
+	0x0203f047,
+	0xbd0002d0,
+	0x012cf004,
+	0xf10320b6,
+	0xf04afc07,
+	0x02d00203,
+	0xf004bd00,
+	0xa5f001ac,
+	0x00b7f102,
+	0x50b3f000,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf0016f,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x010c9800,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf0016f,
+	0x04a5f001,
+	0x3000b7f1,
+	0x9850b3f0,
+	0xc4b6040c,
+	0x00bcbb0f,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6f21f502,
+	0x5e21f501,
+	0x0601f402,
+/* 0x0697: ctx_xfer_post */
+	0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+	0xf5027f21,
+	0xf805a221,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3
new file mode 100644
index 0000000..b80cdfd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
+
+#define CHIPSET GK100
+#include "macros.fuc"
+
+.section #gk104_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk104_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
new file mode 100644
index 0000000..49020ff
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gk104_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gk104_grgpc_code[] = {
+	0x03a10ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0xe0f900f8,
+	0xf102ffb9,
+	0xf09814e7,
+	0x21f440e3,
+	0x01f7f09d,
+	0xf102ffb9,
+	0xf09c1ce7,
+	0x21f440e3,
+	0xf8e0fc9d,
+/* 0x03a1: init */
+	0xf104bd00,
+	0xf0420017,
+	0x11cf0013,
+	0x0911e700,
+	0x0814b601,
+	0xf00014fe,
+	0x07f10227,
+	0x03f01200,
+	0x0002d000,
+	0x17f104bd,
+	0x10fe0530,
+	0x0007f100,
+	0x0003f007,
+	0xbd0000d0,
+	0x0427f004,
+	0x040007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0xf11031f4,
+	0xf0820027,
+	0x22cf0123,
+	0x0137f000,
+	0xbb1f24f0,
+	0x32b60432,
+	0x05028001,
+	0xf1060380,
+	0xf0860027,
+	0x22cf0123,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0421: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0436: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40126b0,
+/* 0x0442: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0xf1082595,
+	0xf0c00007,
+	0x05d00103,
+	0xf104bd00,
+	0xf0c10007,
+	0x05d00103,
+	0x9804bd00,
+	0x0f98000e,
+	0x5021f501,
+	0x002fbb01,
+	0x98003fbb,
+	0x0f98010e,
+	0x5021f502,
+	0x050e9801,
+	0xbb00effd,
+	0x3ebb002e,
+	0x020e9800,
+	0xf5030f98,
+	0x98015021,
+	0xeffd070e,
+	0x002ebb00,
+	0xb6003ebb,
+	0x07f10235,
+	0x03f0d300,
+	0x0003d001,
+	0x25b604bd,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb02d321,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0080007,
+	0x02d00203,
+/* 0x04f3: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0x7e21f501,
+	0xc60ef403,
+/* 0x0530: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x24d7f02c,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xf00421f4,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x057e: ih_no_fifo */
+	0x07f104bd,
+	0x03f00100,
+	0x000ad000,
+	0xf0fc04bd,
+	0xd0fce0fc,
+	0xa0fcb0fc,
+	0x80fc90fc,
+	0xfc0088fe,
+	0x0032f480,
+/* 0x05a2: hub_barrier_done */
+	0xf7f001f8,
+	0x040e9801,
+	0xb904febb,
+	0xe7f102ff,
+	0xe3f09418,
+	0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+	0xf7f000f8,
+	0x0007f120,
+	0x0103f085,
+	0xbd000fd0,
+	0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+	0xf401e2b6,
+	0xf5f1fd1b,
+	0xf5f10800,
+	0x07f10200,
+	0x03f08500,
+	0x000fd001,
+	0x00f804bd,
+/* 0x05e8: ctx_xfer */
+	0x810007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+	0xf505ba21,
+	0xbd026a21,
+	0xfc07f124,
+	0x0203f047,
+	0xbd0002d0,
+	0x012cf004,
+	0xf10320b6,
+	0xf04afc07,
+	0x02d00203,
+	0xf004bd00,
+	0xa5f001ac,
+	0x00b7f102,
+	0x50b3f000,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf0016f,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x010c9800,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf0016f,
+	0x04a5f001,
+	0x3000b7f1,
+	0x9850b3f0,
+	0xc4b6040c,
+	0x00bcbb0f,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6f21f502,
+	0x5e21f501,
+	0x0601f402,
+/* 0x0697: ctx_xfer_post */
+	0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+	0xf5027f21,
+	0xf805a221,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3
new file mode 100644
index 0000000..98d85fe
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000002
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #gk110_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk110_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
new file mode 100644
index 0000000..c95b07e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gk110_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gk110_grgpc_code[] = {
+	0x03a10ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f037,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f037,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0xe0f900f8,
+	0xf102ffb9,
+	0xf09814e7,
+	0x21f440e3,
+	0x01f7f09d,
+	0xf102ffb9,
+	0xf09c1ce7,
+	0x21f440e3,
+	0xf8e0fc9d,
+/* 0x03a1: init */
+	0xf104bd00,
+	0xf0420017,
+	0x11cf0013,
+	0x0911e700,
+	0x0814b601,
+	0xf00014fe,
+	0x07f10227,
+	0x03f01200,
+	0x0002d000,
+	0x17f104bd,
+	0x10fe0530,
+	0x0007f100,
+	0x0003f007,
+	0xbd0000d0,
+	0x0427f004,
+	0x040007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0xf11031f4,
+	0xf0820027,
+	0x22cf0123,
+	0x0137f000,
+	0xbb1f24f0,
+	0x32b60432,
+	0x05028001,
+	0xf1060380,
+	0xf0860027,
+	0x22cf0123,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0421: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0436: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40226b0,
+/* 0x0442: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0xf1082595,
+	0xf0c00007,
+	0x05d00103,
+	0xf104bd00,
+	0xf0c10007,
+	0x05d00103,
+	0x9804bd00,
+	0x0f98000e,
+	0x5021f501,
+	0x002fbb01,
+	0x98003fbb,
+	0x0f98010e,
+	0x5021f502,
+	0x050e9801,
+	0xbb00effd,
+	0x3ebb002e,
+	0x020e9800,
+	0xf5030f98,
+	0x98015021,
+	0xeffd070e,
+	0x002ebb00,
+	0xb6003ebb,
+	0x07f10235,
+	0x03f0d300,
+	0x0003d001,
+	0x25b604bd,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb02d321,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0300007,
+	0x02d00203,
+/* 0x04f3: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0x7e21f501,
+	0xc60ef403,
+/* 0x0530: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x24d7f02c,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xf00421f4,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x057e: ih_no_fifo */
+	0x07f104bd,
+	0x03f00100,
+	0x000ad000,
+	0xf0fc04bd,
+	0xd0fce0fc,
+	0xa0fcb0fc,
+	0x80fc90fc,
+	0xfc0088fe,
+	0x0032f480,
+/* 0x05a2: hub_barrier_done */
+	0xf7f001f8,
+	0x040e9801,
+	0xb904febb,
+	0xe7f102ff,
+	0xe3f09418,
+	0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+	0xf7f000f8,
+	0x0007f120,
+	0x0103f085,
+	0xbd000fd0,
+	0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+	0xf401e2b6,
+	0xf5f1fd1b,
+	0xf5f10800,
+	0x07f10200,
+	0x03f08500,
+	0x000fd001,
+	0x00f804bd,
+/* 0x05e8: ctx_xfer */
+	0x810007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+	0xf505ba21,
+	0xbd026a21,
+	0xfc07f124,
+	0x0203f047,
+	0xbd0002d0,
+	0x012cf004,
+	0xf10320b6,
+	0xf04afc07,
+	0x02d00203,
+	0xf004bd00,
+	0xa5f001ac,
+	0x00b7f102,
+	0x50b3f000,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf0016f,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x010c9800,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf0016f,
+	0x04a5f001,
+	0x3000b7f1,
+	0x9850b3f0,
+	0xc4b6040c,
+	0x00bcbb0f,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6f21f502,
+	0x5e21f501,
+	0x0601f402,
+/* 0x0697: ctx_xfer_post */
+	0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+	0xf5027f21,
+	0xf805a221,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5
new file mode 100644
index 0000000..8f64299
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gk208_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk208_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
new file mode 100644
index 0000000..7e1c28e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
@@ -0,0 +1,473 @@
+uint32_t gk208_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gk208_grgpc_code[] = {
+	0x03140ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0xf489a408,
+	0x020f0b1b,
+	0x0002f87e,
+/* 0x001a: queue_put_next */
+	0x98c400f8,
+	0x0384b607,
+	0xb6008dbb,
+	0x8eb50880,
+	0x018fb500,
+	0xf00190b6,
+	0xd9b50f94,
+/* 0x0037: queue_get */
+	0xf400f801,
+	0xd8980131,
+	0x01d99800,
+	0x0bf489a4,
+	0x0789c421,
+	0xbb0394b6,
+	0x90b6009d,
+	0x009e9808,
+	0xb6019f98,
+	0x84f00180,
+	0x00d8b50f,
+/* 0x0063: queue_get_done */
+	0xf80132f4,
+/* 0x0065: nv_rd32 */
+	0xf0ecb200,
+	0x00801fc9,
+	0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+	0x8c04bd00,
+	0xcf01ca00,
+	0xccc800cc,
+	0xf61bf41f,
+	0xec7e060a,
+	0x008f0000,
+	0xffcf01cb,
+/* 0x008f: nv_wr32 */
+	0x8000f800,
+	0xf601cc00,
+	0x04bd000f,
+	0xc9f0ecb2,
+	0x1ec9f01f,
+	0x01ca0080,
+	0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+	0xca008c04,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f61b,
+/* 0x00b8: wait_donez */
+	0x99f094bd,
+	0x37008000,
+	0x0009f602,
+	0x008004bd,
+	0x0af60206,
+/* 0x00cf: wait_donez_ne */
+	0x8804bd00,
+	0xcf010000,
+	0x8aff0088,
+	0xf61bf488,
+	0x99f094bd,
+	0x17008000,
+	0x0009f602,
+	0x00f804bd,
+/* 0x00ec: wait_doneo */
+	0x99f094bd,
+	0x37008000,
+	0x0009f602,
+	0x008004bd,
+	0x0af60206,
+/* 0x0103: wait_doneo_e */
+	0x8804bd00,
+	0xcf010000,
+	0x8aff0088,
+	0xf60bf488,
+	0x99f094bd,
+	0x17008000,
+	0x0009f602,
+	0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0x1bf4efa4,
+	0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+	0xf094bd00,
+	0x00800199,
+	0x09f60237,
+	0xbd04bd00,
+	0x05bbfd94,
+	0x800f0bf4,
+	0xf601c400,
+	0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0xc6008018,
+	0x000ef601,
+	0x008004bd,
+	0x0ff601c7,
+	0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+	0xabc80199,
+	0x10b4b600,
+	0xc80cb9f0,
+	0xe4b601ae,
+	0x05befd11,
+	0x01c50080,
+	0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+	0xc5008e04,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f60b,
+	0x05e9fd00,
+	0x01c80080,
+	0xbd000ef6,
+	0x04c0b604,
+	0x1bf4cda4,
+	0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+	0x8b1c1bf4,
+	0xcf01c500,
+	0xb4f000bb,
+	0x10b4b01f,
+	0x0af31bf4,
+	0x00b87e05,
+	0x250ef400,
+/* 0x01d8: mmctx_stop */
+	0xb600abc8,
+	0xb9f010b4,
+	0x12b9f00c,
+	0x01c50080,
+	0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+	0xc5008b04,
+	0x00bbcf01,
+	0xf412bbc8,
+/* 0x01fa: mmctx_done */
+	0x94bdf61b,
+	0x800199f0,
+	0xf6021700,
+	0x04bd0009,
+/* 0x020a: strand_wait */
+	0xa0f900f8,
+	0xb87e020a,
+	0xa0fc0000,
+/* 0x0216: strand_pre */
+	0x0c0900f8,
+	0x024afc80,
+	0xbd0009f6,
+	0x020a7e04,
+/* 0x0227: strand_post */
+	0x0900f800,
+	0x4afc800d,
+	0x0009f602,
+	0x0a7e04bd,
+	0x00f80002,
+/* 0x0238: strand_set */
+	0xfc800f0c,
+	0x0cf6024f,
+	0x0c04bd00,
+	0x4afc800b,
+	0x000cf602,
+	0xfc8004bd,
+	0x0ef6024f,
+	0x0c04bd00,
+	0x4afc800a,
+	0x000cf602,
+	0x0a7e04bd,
+	0x00f80002,
+/* 0x0268: strand_ctx_init */
+	0x99f094bd,
+	0x37008003,
+	0x0009f602,
+	0x167e04bd,
+	0x030e0002,
+	0x0002387e,
+	0xfc80c4bd,
+	0x0cf60247,
+	0x0c04bd00,
+	0x4afc8001,
+	0x000cf602,
+	0x0a7e04bd,
+	0x0c920002,
+	0x46fc8001,
+	0x000cf602,
+	0x020c04bd,
+	0x024afc80,
+	0xbd000cf6,
+	0x020a7e04,
+	0x02277e00,
+	0x42008800,
+	0x20008902,
+	0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+	0xf608fe95,
+	0x8ef6008e,
+	0x808acf40,
+	0xb606a5b6,
+	0xeabb01a0,
+	0x0480b600,
+	0xf40192b6,
+	0xe4b6e81b,
+	0xf2efbc08,
+	0x99f094bd,
+	0x17008003,
+	0x0009f602,
+	0x00f804bd,
+/* 0x02f8: error */
+	0xffb2e0f9,
+	0x4098148e,
+	0x00008f7e,
+	0xffb2010f,
+	0x409c1c8e,
+	0x00008f7e,
+	0x00f8e0fc,
+/* 0x0314: init */
+	0x004104bd,
+	0x0011cf42,
+	0x010911e7,
+	0xfe0814b6,
+	0x02020014,
+	0xf6120040,
+	0x04bd0002,
+	0xfe047241,
+	0x00400010,
+	0x0000f607,
+	0x040204bd,
+	0xf6040040,
+	0x04bd0002,
+	0x821031f4,
+	0xcf018200,
+	0x01030022,
+	0xbb1f24f0,
+	0x32b60432,
+	0x0502b501,
+	0x820603b5,
+	0xcf018600,
+	0x02b50022,
+	0x0c308e04,
+	0xbd24bd50,
+/* 0x0377: init_unk_loop */
+	0x7e44bd34,
+	0xb0000065,
+	0x0bf400f6,
+	0xbb010f0e,
+	0x4ffd04f2,
+	0x0130b605,
+/* 0x038c: init_unk_next */
+	0xb60120b6,
+	0x26b004e0,
+	0xe21bf401,
+/* 0x0398: init_unk_done */
+	0xb50703b5,
+	0x00820804,
+	0x22cf0201,
+	0x9534bd00,
+	0x00800825,
+	0x05f601c0,
+	0x8004bd00,
+	0xf601c100,
+	0x04bd0005,
+	0x98000e98,
+	0x207e010f,
+	0x2fbb0001,
+	0x003fbb00,
+	0x98010e98,
+	0x207e020f,
+	0x0e980001,
+	0x00effd05,
+	0xbb002ebb,
+	0x0e98003e,
+	0x030f9802,
+	0x0001207e,
+	0xfd070e98,
+	0x2ebb00ef,
+	0x003ebb00,
+	0x800235b6,
+	0xf601d300,
+	0x04bd0003,
+	0xb60825b6,
+	0x20b60635,
+	0x0130b601,
+	0xb60824b6,
+	0x2fb20834,
+	0x0002687e,
+	0x80003fbb,
+	0xf6020100,
+	0x04bd0003,
+	0x29f024bd,
+	0x3000801f,
+	0x0002f602,
+/* 0x0436: main */
+	0x31f404bd,
+	0x0028f400,
+	0x377e240d,
+	0x01f40000,
+	0x04e4b0f4,
+	0xfe1d18f4,
+	0x06020181,
+	0x12fd20bd,
+	0x01e4b604,
+	0xfe051efd,
+	0x097e0018,
+	0x0ef40005,
+/* 0x0465: main_not_ctx_xfer */
+	0x10ef94d4,
+	0x7e01f5f0,
+	0xf40002f8,
+/* 0x0472: ih */
+	0x80f9c70e,
+	0xf90188fe,
+	0xf990f980,
+	0xf9b0f9a0,
+	0xf9e0f9d0,
+	0x4a04bdf0,
+	0xaacf0200,
+	0x04abc400,
+	0x0d1f0bf4,
+	0x1a004e24,
+	0x4f00eecf,
+	0xffcf1900,
+	0x00047e00,
+	0x40010e00,
+	0x0ef61d00,
+/* 0x04af: ih_no_fifo */
+	0x4004bd00,
+	0x0af60100,
+	0xfc04bd00,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x04cf: hub_barrier_done */
+	0x0f01f800,
+	0x040e9801,
+	0xb204febb,
+	0x94188eff,
+	0x008f7e40,
+/* 0x04e3: ctx_redswitch */
+	0x0f00f800,
+	0x85008020,
+	0x000ff601,
+	0x080e04bd,
+/* 0x04f0: ctx_redswitch_delay */
+	0xf401e2b6,
+	0xf5f1fd1b,
+	0xf5f10800,
+	0x00800200,
+	0x0ff60185,
+	0xf804bd00,
+/* 0x0509: ctx_xfer */
+	0x81008000,
+	0x000ff602,
+	0x11f404bd,
+	0x04e37e07,
+/* 0x0519: ctx_xfer_not_load */
+	0x02167e00,
+	0x8024bd00,
+	0xf60247fc,
+	0x04bd0002,
+	0xb6012cf0,
+	0xfc800320,
+	0x02f6024a,
+	0xf004bd00,
+	0xa5f001ac,
+	0x00008b02,
+	0x040c9850,
+	0xbb0fc4b6,
+	0x0c9800bc,
+	0x010d9800,
+	0x3d7e000e,
+	0xacf00001,
+	0x40008b01,
+	0x040c9850,
+	0xbb0fc4b6,
+	0x0c9800bc,
+	0x020d9801,
+	0x4e060f98,
+	0x3d7e0800,
+	0xacf00001,
+	0x04a5f001,
+	0x5030008b,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x020c9800,
+	0x98030d98,
+	0x004e080f,
+	0x013d7e02,
+	0x020a7e00,
+	0x0601f400,
+/* 0x05a3: ctx_xfer_post */
+	0x7e0712f4,
+/* 0x05a7: ctx_xfer_done */
+	0x7e000227,
+	0xf80004cf,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc
new file mode 100644
index 0000000..87f99e3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc
@@ -0,0 +1,696 @@
+/* fuc microcode for gf100 PGRAPH/HUB
+ *
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_DATA
+hub_mmio_list_head:	.b32 #hub_mmio_list_base
+hub_mmio_list_tail:	.b32 #hub_mmio_list_next
+
+gpc_count:		.b32 0
+rop_count:		.b32 0
+cmd_queue:		queue_init
+
+ctx_current:		.b32 0
+
+.align 256
+chan_data:
+chan_mmio_count:	.b32 0
+chan_mmio_address:	.b32 0
+
+.align 256
+xfer_data: 		.skip 256
+
+hub_mmio_list_base:
+.b32 0x0417e91c // 0x17e91c, 2
+hub_mmio_list_next:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see os.h)
+//
+error:
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
+	mov $r15 1
+	nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
+	ret
+
+// HUB fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: total PGRAPH context size
+//
+init:
+	clear b32 $r0
+	mov $xdbase $r0
+
+	// setup stack
+	nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0)
+	extr $r1 $r1 9:17
+	shl b32 $r1 8
+	mov $sp $r1
+
+	// enable fifo access
+	mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO
+	nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2)
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+
+	clear b32 $r2
+	nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2)
+
+	// route HUB_CHSW_PULSE to fuc interrupt 8
+	mov $r2 0x2003		// { HUB_CHSW_PULSE, ZERO } -> intr 8
+	nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2)
+
+	// not sure what these are, route them because NVIDIA does, and
+	// the IRQ handler will signal the host if we ever get one.. we
+	// may find out if/why we need to handle these if so..
+	//
+	mov $r2 0x2004		// { 0x04, ZERO } -> intr 9
+	nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2)
+	mov $r2 0x200b		// { HUB_FIRMWARE_MTHD, ZERO } -> intr 10
+	nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2)
+	mov $r2 0x200c		// { 0x0c, ZERO } -> intr 15
+	nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2)
+
+	// enable all INTR_UP interrupts
+	sub b32 $r3 $r0 1
+	nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3)
+
+	// enable fifo, ctxsw, 9, fwmthd, 15 interrupts
+	imm32($r2, 0x8704)
+	nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2)
+
+	// fifo level triggered, rest edge
+	mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL
+	nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2)
+
+	// enable interrupts
+	bset $flags ie0
+
+	// fetch enabled GPC/ROP counts
+	nv_rd32($r14, 0x409604)
+	extr $r1 $r15 16:20
+	st b32 D[$r0 + #rop_count] $r1
+	and $r15 0x1f
+	st b32 D[$r0 + #gpc_count] $r15
+
+	// set BAR_REQMASK to GPC mask
+	mov $r1 1
+	shl b32 $r1 $r15
+	sub b32 $r1 1
+	nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1)
+	nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1)
+
+	// context size calculation, reserve first 256 bytes for use by fuc
+	mov $r1 256
+
+	//
+	mov $r15 2
+	call(ctx_4170s)
+	call(ctx_4170w)
+	mov $r15 0x10
+	call(ctx_86c)
+
+	// calculate size of mmio context data
+	ld b32 $r14 D[$r0 + #hub_mmio_list_head]
+	ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
+	call(mmctx_size)
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't (currently) ever change
+	shr b32 $r4 $r1 8
+	nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4)
+	nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4)
+	add b32 $r3 0x1300
+	add b32 $r1 $r15
+	shr b32 $r15 2
+	nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf??
+
+	// strands, base offset needs to be aligned to 256 bytes
+	shr b32 $r1 8
+	add b32 $r1 1
+	shl b32 $r1 8
+	mov b32 $r15 $r1
+	call(strand_ctx_init)
+	add b32 $r1 $r15
+
+	// initialise each GPC in sequence by passing in the offset of its
+	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
+	// has previously been uploaded by the host) running.
+	//
+	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
+	// when it has completed, and return the size of its context data
+	// in GPCn_CC_SCRATCH[1]
+	//
+	ld b32 $r3 D[$r0 + #gpc_count]
+	imm32($r4, 0x502000)
+	init_gpc:
+		// setup, and start GPC ucode running
+		add b32 $r14 $r4 0x804
+		mov b32 $r15 $r1
+		call(nv_wr32)			// CC_SCRATCH[1] = ctx offset
+		add b32 $r14 $r4 0x10c
+		clear b32 $r15
+		call(nv_wr32)
+		add b32 $r14 $r4 0x104
+		call(nv_wr32)			// ENTRY
+		add b32 $r14 $r4 0x100
+		mov $r15 2			// CTRL_START_TRIGGER
+		call(nv_wr32)			// CTRL
+
+		// wait for it to complete, and adjust context size
+		add b32 $r14 $r4 0x800
+		init_gpc_wait:
+			call(nv_rd32)
+			xbit $r15 $r15 31
+			bra e #init_gpc_wait
+		add b32 $r14 $r4 0x804
+		call(nv_rd32)
+		add b32 $r1 $r15
+
+		// next!
+		add b32 $r4 0x8000
+		sub b32 $r3 1
+		bra ne #init_gpc
+
+	//
+	mov $r15 0
+	call(ctx_86c)
+	mov $r15 0
+	call(ctx_4170s)
+
+	// save context size, and tell host we're ready
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
+	clear b32 $r1
+	bset $r1 31
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	// sleep until we have something to do
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call(queue_get)
+	bra $p1 #main
+
+	// context switch, requested by GPU?
+	cmpu b32 $r14 0x4001
+	bra ne #main_not_ctx_switch
+		trace_set(T_AUTO)
+		nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0)
+		nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0)
+
+		xbit $r3 $r1 31
+		bra e #chsw_no_prev
+			xbit $r3 $r2 31
+			bra e #chsw_prev_no_next
+				push $r2
+				mov b32 $r2 $r1
+				trace_set(T_SAVE)
+				bclr $flags $p1
+				bset $flags $p2
+				call(ctx_xfer)
+				trace_clr(T_SAVE);
+				pop $r2
+				trace_set(T_LOAD);
+				bset $flags $p1
+				call(ctx_xfer)
+				trace_clr(T_LOAD);
+				bra #chsw_done
+			chsw_prev_no_next:
+				push $r2
+				mov b32 $r2 $r1
+				bclr $flags $p1
+				bclr $flags $p2
+				call(ctx_xfer)
+				pop $r2
+				nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
+				bra #chsw_done
+		chsw_no_prev:
+			xbit $r3 $r2 31
+			bra e #chsw_done
+				bset $flags $p1
+				bclr $flags $p2
+				call(ctx_xfer)
+
+		// ack the context switch request
+		chsw_done:
+		mov $r2 NV_PGRAPH_FECS_CHSW_ACK
+		nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2)
+		trace_clr(T_AUTO)
+		bra #main
+
+	// request to set current channel? (*not* a context switch)
+	main_not_ctx_switch:
+	cmpu b32 $r14 0x0001
+	bra ne #main_not_ctx_chan
+		mov b32 $r2 $r15
+		call(ctx_chan)
+		bra #main_done
+
+	// request to store current channel context?
+	main_not_ctx_chan:
+	cmpu b32 $r14 0x0002
+	bra ne #main_not_ctx_save
+		trace_set(T_SAVE)
+		bclr $flags $p1
+		bclr $flags $p2
+		call(ctx_xfer)
+		trace_clr(T_SAVE)
+		bra #main_done
+
+	main_not_ctx_save:
+		shl b32 $r15 $r14 16
+		or $r15 E_BAD_COMMAND
+		call(error)
+		bra #main
+
+	main_done:
+	clear b32 $r2
+	bset $r2 31
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+	clear b32 $r0
+
+	// incoming fifo command?
+	nv_iord($r10, NV_PGRAPH_FECS_INTR, 0)
+	and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r13 #cmd_queue
+		nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0)
+		nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0)
+		call(queue_put)
+		add b32 $r11 0x400
+		mov $r14 1
+		nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14)
+
+	// context switch request?
+	ih_no_fifo:
+	and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW
+	bra e #ih_no_ctxsw
+		// enqueue a context switch for later processing
+		mov $r13 #cmd_queue
+		mov $r14 0x4001
+		call(queue_put)
+
+	// firmware method?
+	ih_no_ctxsw:
+	and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD
+	bra e #ih_no_fwmthd
+		// none we handle; report to host and ack
+		nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO)
+		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15)
+		nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR)
+		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15)
+		extr $r14 $r15 16:18
+		shl b32 $r14 $r14 2
+		imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0))
+		add b32 $r14 $r15
+		call(nv_rd32)
+		nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15)
+		mov $r15 E_BAD_FWMTHD
+		call(error)
+		mov $r11 0x100
+		nv_wr32(0x400144, $r11)
+
+	// anything we didn't handle, bring it to the host's attention
+	ih_no_fwmthd:
+	mov $r11 0x504 // FIFO | CHSW | FWMTHD
+	not b32 $r11
+	and $r11 $r10 $r11
+	bra e #ih_no_other
+		nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11)
+
+	// ack, and wake up main()
+	ih_no_other:
+	nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10)
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+#if CHIPSET < GK100
+// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
+ctx_4160s:
+	mov $r15 1
+	nv_wr32(0x404160, $r15)
+	ctx_4160s_wait:
+		nv_rd32($r15, 0x404160)
+		xbit $r15 $r15 4
+		bra e #ctx_4160s_wait
+	ret
+
+// Without clearing again at end of xfer, some things cause PGRAPH
+// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
+// still function with it set however...
+ctx_4160c:
+	clear b32 $r15
+	nv_wr32(0x404160, $r15)
+	ret
+#endif
+
+// Again, not real sure
+//
+// In: $r15 value to set 0x404170 to
+//
+ctx_4170s:
+	or $r15 0x10
+	nv_wr32(0x404170, $r15)
+	ret
+
+// Waits for a ctx_4170s() call to complete
+//
+ctx_4170w:
+	nv_rd32($r15, 0x404170)
+	and $r15 0x10
+	bra ne #ctx_4170w
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC
+	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP
+	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC
+	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN
+	nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
+	mov $r15 8
+	ctx_redswitch_delay:
+		sub b32 $r15 1
+		bra ne #ctx_redswitch_delay
+	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP
+	or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN
+	nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
+	ret
+
+// Not a clue what this is for, except that unless the value is 0x10, the
+// strand context is saved (and presumably restored) incorrectly..
+//
+// In: $r15 value to set to (0x00/0x10 are used)
+//
+ctx_86c:
+	nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15)
+	nv_wr32(0x408a14, $r15)
+	nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15)
+	ret
+
+// In: $r15 NV_PGRAPH_FECS_MEM_CMD_*
+ctx_mem:
+	nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15)
+	ctx_mem_wait:
+		nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0)
+		or $r15 $r15
+		bra ne #ctx_mem_wait
+	ret
+
+// ctx_load - load's a channel's ctxctl data, and selects its vm
+//
+// In: $r2 channel address
+//
+ctx_load:
+	trace_set(T_CHAN)
+
+	// switch to channel, somewhat magic in parts..
+	mov $r10 12		// DONE_UNK12
+	call(wait_donez)
+	clear b32 $r15
+	nv_iowr(0x409a24, 0, $r15)
+	nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2)
+	nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2)
+	mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN
+	call(ctx_mem)
+	nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
+
+	// load channel header, fetch PGRAPH context pointer
+	mov $xtargets $r0
+	bclr $r2 31
+	shl b32 $r2 4
+	add b32 $r2 2
+
+	trace_set(T_LCHAN)
+	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2)
+	imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31)
+	or  $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM
+	nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
+	mov $r1 0x10			// chan + 0x0210
+	mov $r2 #xfer_data
+	sethi $r2 0x00020000		// 16 bytes
+	xdld $r1 $r2
+	xdwait
+	trace_clr(T_LCHAN)
+
+	// update current context
+	ld b32 $r1 D[$r0 + #xfer_data + 4]
+	shl b32 $r1 24
+	ld b32 $r2 D[$r0 + #xfer_data + 0]
+	shr b32 $r2 8
+	or $r1 $r2
+	st b32 D[$r0 + #ctx_current] $r1
+
+	// set transfer base to start of context, and fetch context header
+	trace_set(T_LCTXH)
+	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1)
+	mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM
+	nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdld $r0 $r1
+	xdwait
+	trace_clr(T_LCTXH)
+
+	trace_clr(T_CHAN)
+	ret
+
+// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
+//            the active channel for ctxctl, but not actually transfer
+//            any context data.  intended for use only during initial
+//            context construction.
+//
+// In: $r2 channel address
+//
+ctx_chan:
+#if CHIPSET < GK100
+	call(ctx_4160s)
+#endif
+	call(ctx_load)
+	mov $r10 12			// DONE_UNK12
+	call(wait_donez)
+	mov $r15 5 // MEM_CMD 5 ???
+	call(ctx_mem)
+#if CHIPSET < GK100
+	call(ctx_4160c)
+#endif
+	ret
+
+// Execute per-context state overrides list
+//
+// Only executed on the first load of a channel.  Might want to look into
+// removing this and having the host directly modify the channel's context
+// to change this state...  The nouveau DRM already builds this list as
+// it's definitely needed for NVIDIA's, so we may as well use it for now
+//
+// Input: $r1 mmio list length
+//
+ctx_mmio_exec:
+	// set transfer base to be the mmio list
+	ld b32 $r3 D[$r0 + #chan_mmio_address]
+	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
+
+	clear b32 $r3
+	ctx_mmio_loop:
+		// fetch next 256 bytes of mmio list if necessary
+		and $r4 $r3 0xff
+		bra ne #ctx_mmio_pull
+			mov $r5 #xfer_data
+			sethi $r5 0x00060000	// 256 bytes
+			xdld $r3 $r5
+			xdwait
+
+		// execute a single list entry
+		ctx_mmio_pull:
+		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
+		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
+		call(nv_wr32)
+
+		// next!
+		add b32 $r3 8
+		sub b32 $r1 1
+		bra ne #ctx_mmio_loop
+
+	// set transfer base back to the current context
+	ctx_mmio_done:
+	ld b32 $r3 D[$r0 + #ctx_current]
+	nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
+
+	// disable the mmio list now, we don't need/want to execute it again
+	st b32 D[$r0 + #chan_mmio_count] $r0
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdst $r0 $r1
+	xdwait
+	ret
+
+// Transfer HUB context data between GPU and storage area
+//
+// In: $r2 channel address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// according to mwk, some kind of wait for idle
+	mov $r14 4
+	nv_iowr(0x409c08, 0, $r14)
+	ctx_xfer_idle:
+		nv_iord($r14, 0x409c00, 0)
+		and $r14 0x2000
+		bra ne #ctx_xfer_idle
+
+	bra not $p1 #ctx_xfer_pre
+	bra $p2 #ctx_xfer_pre_load
+	ctx_xfer_pre:
+		mov $r15 0x10
+		call(ctx_86c)
+#if CHIPSET < GK100
+		call(ctx_4160s)
+#endif
+		bra not $p1 #ctx_xfer_exec
+
+	ctx_xfer_pre_load:
+		mov $r15 2
+		call(ctx_4170s)
+		call(ctx_4170w)
+		call(ctx_redswitch)
+		clear b32 $r15
+		call(ctx_4170s)
+		call(ctx_load)
+
+	// fetch context pointer, and initiate xfer on all GPCs
+	ctx_xfer_exec:
+	ld b32 $r1 D[$r0 + #ctx_current]
+
+	clear b32 $r2
+	nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2)
+
+	nv_wr32(0x41a500, $r1)	// GPC_BCAST_WRCMD_DATA = ctx pointer
+	xbit $r15 $flags $p1
+	xbit $r2 $flags $p2
+	shl b32 $r2 1
+	or $r15 $r2
+	nv_wr32(0x41a504, $r15)	// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+
+	// strands
+	call(strand_pre)
+	clear b32 $r2
+	nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2)
+	xbit $r2 $flags $p1	// SAVE/LOAD
+	add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE
+	nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 6		// first, last
+	mov $r11 0		// base = 0
+	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
+	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
+	mov $r14 0		// not multi
+	call(mmctx_xfer)
+
+	// wait for GPCs to all complete
+	mov $r10 8		// DONE_BAR
+	call(wait_doneo)
+
+	// wait for strand xfer to complete
+	call(strand_wait)
+
+	// post-op
+	bra $p1 #ctx_xfer_post
+		mov $r10 12		// DONE_UNK12
+		call(wait_donez)
+		mov $r15 5 // MEM_CMD 5 ???
+		call(ctx_mem)
+
+	bra $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		mov $r15 2
+		call(ctx_4170s)
+		clear b32 $r15
+		call(ctx_86c)
+		call(strand_post)
+		call(ctx_4170w)
+		clear b32 $r15
+		call(ctx_4170s)
+
+		bra not $p1 #ctx_xfer_no_post_mmio
+		ld b32 $r1 D[$r0 + #chan_mmio_count]
+		or $r1 $r1
+		bra e #ctx_xfer_no_post_mmio
+			call(ctx_mmio_exec)
+
+		ctx_xfer_no_post_mmio:
+#if CHIPSET < GK100
+		call(ctx_4160c)
+#endif
+
+	ctx_xfer_done:
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3
new file mode 100644
index 0000000..2c28e71
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF100
+#include "macros.fuc"
+
+.section #gf100_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gf100_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h
new file mode 100644
index 0000000..f6acda5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h
@@ -0,0 +1,1047 @@
+uint32_t gf100_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t gf100_grhub_code[] = {
+	0x039b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x039b: init */
+	0xbd00f804,
+	0x0007fe04,
+	0x420017f1,
+	0xcf0013f0,
+	0x11e70011,
+	0x14b60109,
+	0x0014fe08,
+	0xf10227f0,
+	0xf0120007,
+	0x02d00003,
+	0xf104bd00,
+	0xfe06c817,
+	0x24bd0010,
+	0x070007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0x200327f1,
+	0x010007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200427f1,
+	0x010407f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200b27f1,
+	0x010807f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200c27f1,
+	0x011c07f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1010392,
+	0xf0090007,
+	0x03d00303,
+	0xf104bd00,
+	0xf0870427,
+	0x07f10023,
+	0x03f00400,
+	0x0002d000,
+	0x27f004bd,
+	0x0007f104,
+	0x0003f003,
+	0xbd0002d0,
+	0x1031f404,
+	0x9604e7f1,
+	0xf440e3f0,
+	0xfeb96821,
+	0x90f1c702,
+	0xf0030180,
+	0x0f801ff4,
+	0x0117f002,
+	0xb6041fbb,
+	0x07f10112,
+	0x03f00300,
+	0x0001d001,
+	0x07f104bd,
+	0x03f00400,
+	0x0001d001,
+	0x17f104bd,
+	0xf7f00100,
+	0x0d21f502,
+	0x1f21f508,
+	0x10f7f008,
+	0x086c21f5,
+	0x98000e98,
+	0x21f5010f,
+	0x14950150,
+	0x0007f108,
+	0x0103f0c0,
+	0xbd0004d0,
+	0x0007f104,
+	0x0103f0c1,
+	0xbd0004d0,
+	0x0030b704,
+	0x001fbb13,
+	0xf102f5b6,
+	0xf0d30007,
+	0x0fd00103,
+	0xb604bd00,
+	0x10b60815,
+	0x0814b601,
+	0xf5021fb9,
+	0xbb02d321,
+	0x0398001f,
+	0x0047f102,
+	0x5043f020,
+/* 0x04f4: init_gpc */
+	0x08044ea0,
+	0xf4021fb9,
+	0x4ea09d21,
+	0xf4bd010c,
+	0xa09d21f4,
+	0xf401044e,
+	0x4ea09d21,
+	0xf7f00100,
+	0x9d21f402,
+	0x08004ea0,
+/* 0x051c: init_gpc_wait */
+	0xc86821f4,
+	0x0bf41fff,
+	0x044ea0fa,
+	0x6821f408,
+	0xb7001fbb,
+	0xb6800040,
+	0x1bf40132,
+	0x00f7f0be,
+	0x086c21f5,
+	0xf500f7f0,
+	0xf1080d21,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0564: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00e91b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xc00017f1,
+	0xcf0213f0,
+	0x27f10011,
+	0x23f0c100,
+	0x0022cf02,
+	0xf51f13c8,
+	0xc800890b,
+	0x0bf41f23,
+	0xb920f962,
+	0x94bd0212,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x31f40132,
+	0x4021f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x20fc04bd,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0131f404,
+	0x0a4021f5,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f017,
+	0xbd0009d0,
+	0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+	0x12b920f9,
+	0x0132f402,
+	0xf50232f4,
+	0xfc0a4021,
+	0x0007f120,
+	0x0203f0c0,
+	0xbd0002d0,
+	0x130ef404,
+/* 0x062c: chsw_no_prev */
+	0xf41f23c8,
+	0x31f40d0b,
+	0x0232f401,
+	0x0a4021f5,
+/* 0x063c: chsw_done */
+	0xf10127f0,
+	0xf0c30007,
+	0x02d00203,
+	0xbd04bd00,
+	0x0499f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+	0xf401e4b0,
+	0xf2b90d1b,
+	0xd021f502,
+	0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+	0xf402e4b0,
+	0x94bd321b,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x32f40132,
+	0x4021f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+	0x10ef9411,
+	0xf501f5f0,
+	0xf5037e21,
+/* 0x06b3: main_done */
+	0xbdfeb50e,
+	0x1f29f024,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xfea00ef5,
+/* 0x06c8: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x10d7f030,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xb70421f4,
+	0xf00400b0,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x071a: ih_no_fifo */
+	0xabe404bd,
+	0x0bf40100,
+	0x10d7f00d,
+	0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+	0xe40421f4,
+	0xf40400ab,
+	0xe7f16c0b,
+	0xe3f00708,
+	0x6821f440,
+	0xf102ffb9,
+	0xf0040007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf00704e7,
+	0x21f440e3,
+	0x02ffb968,
+	0x030007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0x9450fec7,
+	0xf7f102ee,
+	0xf3f00700,
+	0x00efbb40,
+	0xf16821f4,
+	0xf0020007,
+	0x0fd00203,
+	0xf004bd00,
+	0x21f503f7,
+	0xb7f1037e,
+	0xbfb90100,
+	0x44e7f102,
+	0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+	0xf19d21f4,
+	0xbd0504b7,
+	0xb4abffb0,
+	0xf10f0bf4,
+	0xf0070007,
+	0x0bd00303,
+/* 0x07b3: ih_no_other */
+	0xf104bd00,
+	0xf0010007,
+	0x0ad00003,
+	0xfc04bd00,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x07d7: ctx_4160s */
+	0xf001f800,
+	0xffb901f7,
+	0x60e7f102,
+	0x40e3f041,
+/* 0x07e7: ctx_4160s_wait */
+	0xf19d21f4,
+	0xf04160e7,
+	0x21f440e3,
+	0x02ffb968,
+	0xf404ffc8,
+	0x00f8f00b,
+/* 0x07fc: ctx_4160c */
+	0xffb9f4bd,
+	0x60e7f102,
+	0x40e3f041,
+	0xf89d21f4,
+/* 0x080d: ctx_4170s */
+	0x10f5f000,
+	0xf102ffb9,
+	0xf04170e7,
+	0x21f440e3,
+/* 0x081f: ctx_4170w */
+	0xf100f89d,
+	0xf04170e7,
+	0x21f440e3,
+	0x02ffb968,
+	0xf410f4f0,
+	0x00f8f01b,
+/* 0x0834: ctx_redswitch */
+	0x0200e7f1,
+	0xf040e5f0,
+	0xe5f020e5,
+	0x0007f110,
+	0x0103f085,
+	0xbd000ed0,
+	0x08f7f004,
+/* 0x0850: ctx_redswitch_delay */
+	0xf401f2b6,
+	0xe5f1fd1b,
+	0xe5f10400,
+	0x07f10100,
+	0x03f08500,
+	0x000ed001,
+	0x00f804bd,
+/* 0x086c: ctx_86c */
+	0x1b0007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0xf102ffb9,
+	0xf08a14e7,
+	0x21f440e3,
+	0x02ffb99d,
+	0xa86ce7f1,
+	0xf441e3f0,
+	0x00f89d21,
+/* 0x0894: ctx_mem */
+	0x840007f1,
+	0xd00203f0,
+	0x04bd000f,
+/* 0x08a0: ctx_mem_wait */
+	0x8400f7f1,
+	0xcf02f3f0,
+	0xfffd00ff,
+	0xf31bf405,
+/* 0x08b2: ctx_load */
+	0x94bd00f8,
+	0xf10599f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf004bd00,
+	0x21f40ca7,
+	0xf1f4bdd0,
+	0xf0890007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf0c10007,
+	0x02d00203,
+	0xf104bd00,
+	0xf0830007,
+	0x02d00203,
+	0xf004bd00,
+	0x21f507f7,
+	0x07f10894,
+	0x03f0c000,
+	0x0002d002,
+	0x0bfe04bd,
+	0x1f2af000,
+	0xb60424b6,
+	0x94bd0220,
+	0xf10899f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
+	0xf0810007,
+	0x02d00203,
+	0xf104bd00,
+	0xf1000027,
+	0xf0800023,
+	0x07f10225,
+	0x03f08800,
+	0x0002d002,
+	0x17f004bd,
+	0x0027f110,
+	0x0223f002,
+	0xf80512fa,
+	0xf094bd03,
+	0x07f10899,
+	0x03f01700,
+	0x0009d002,
+	0x019804bd,
+	0x1814b681,
+	0xb6800298,
+	0x12fd0825,
+	0x16018005,
+	0x99f094bd,
+	0x0007f109,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f081,
+	0xbd0001d0,
+	0x0127f004,
+	0x880007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0x010017f1,
+	0xfa0613f0,
+	0x03f80501,
+	0x99f094bd,
+	0x0007f109,
+	0x0203f017,
+	0xbd0009d0,
+	0xf094bd04,
+	0x07f10599,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x09d0: ctx_chan */
+	0x07d721f5,
+	0x08b221f5,
+	0xf40ca7f0,
+	0xf7f0d021,
+	0x9421f505,
+	0xfc21f508,
+/* 0x09eb: ctx_mmio_exec */
+	0x9800f807,
+	0x07f14103,
+	0x03f08100,
+	0x0003d002,
+	0x34bd04bd,
+/* 0x09fc: ctx_mmio_loop */
+	0xf4ff34c4,
+	0x57f10f1b,
+	0x53f00200,
+	0x0535fa06,
+/* 0x0a0e: ctx_mmio_pull */
+	0x4e9803f8,
+	0x814f9880,
+	0xb69d21f4,
+	0x12b60830,
+	0xdf1bf401,
+/* 0x0a20: ctx_mmio_done */
+	0xf1160398,
+	0xf0810007,
+	0x03d00203,
+	0x8004bd00,
+	0x17f14000,
+	0x13f00100,
+	0x0601fa06,
+	0x00f803f8,
+/* 0x0a40: ctx_xfer */
+	0xf104e7f0,
+	0xf0020007,
+	0x0ed00303,
+/* 0x0a4f: ctx_xfer_idle */
+	0xf104bd00,
+	0xf00000e7,
+	0xeecf03e3,
+	0x00e4f100,
+	0xf21bf420,
+	0xf40611f4,
+/* 0x0a66: ctx_xfer_pre */
+	0xf7f01102,
+	0x6c21f510,
+	0xd721f508,
+	0x1c11f407,
+/* 0x0a74: ctx_xfer_pre_load */
+	0xf502f7f0,
+	0xf5080d21,
+	0xf5081f21,
+	0xbd083421,
+	0x0d21f5f4,
+	0xb221f508,
+/* 0x0a8d: ctx_xfer_exec */
+	0x16019808,
+	0x07f124bd,
+	0x03f00500,
+	0x0002d001,
+	0x1fb904bd,
+	0x00e7f102,
+	0x41e3f0a5,
+	0xf09d21f4,
+	0x2cf001fc,
+	0x0124b602,
+	0xb905f2fd,
+	0xe7f102ff,
+	0xe3f0a504,
+	0x9d21f441,
+	0x026a21f5,
+	0x07f124bd,
+	0x03f047fc,
+	0x0002d002,
+	0x2cf004bd,
+	0x0320b601,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf001acf0,
+	0xb7f006a5,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xa7f0016f,
+	0x1021f508,
+	0x5e21f501,
+	0x1301f402,
+	0xf40ca7f0,
+	0xf7f0d021,
+	0x9421f505,
+	0x3202f408,
+/* 0x0b1c: ctx_xfer_post */
+	0xf502f7f0,
+	0xbd080d21,
+	0x6c21f5f4,
+	0x7f21f508,
+	0x1f21f502,
+	0xf5f4bd08,
+	0xf4080d21,
+	0x01981011,
+	0x0511fd40,
+	0xf5070bf4,
+/* 0x0b47: ctx_xfer_no_post_mmio */
+	0xf509eb21,
+/* 0x0b4b: ctx_xfer_done */
+	0xf807fc21,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3
new file mode 100644
index 0000000..581b2d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #gf117_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gf117_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h
new file mode 100644
index 0000000..7cb14e5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h
@@ -0,0 +1,1047 @@
+uint32_t gf117_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t gf117_grhub_code[] = {
+	0x039b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x039b: init */
+	0xbd00f804,
+	0x0007fe04,
+	0x420017f1,
+	0xcf0013f0,
+	0x11e70011,
+	0x14b60109,
+	0x0014fe08,
+	0xf10227f0,
+	0xf0120007,
+	0x02d00003,
+	0xf104bd00,
+	0xfe06c817,
+	0x24bd0010,
+	0x070007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0x200327f1,
+	0x010007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200427f1,
+	0x010407f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200b27f1,
+	0x010807f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200c27f1,
+	0x011c07f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1010392,
+	0xf0090007,
+	0x03d00303,
+	0xf104bd00,
+	0xf0870427,
+	0x07f10023,
+	0x03f00400,
+	0x0002d000,
+	0x27f004bd,
+	0x0007f104,
+	0x0003f003,
+	0xbd0002d0,
+	0x1031f404,
+	0x9604e7f1,
+	0xf440e3f0,
+	0xfeb96821,
+	0x90f1c702,
+	0xf0030180,
+	0x0f801ff4,
+	0x0117f002,
+	0xb6041fbb,
+	0x07f10112,
+	0x03f00300,
+	0x0001d001,
+	0x07f104bd,
+	0x03f00400,
+	0x0001d001,
+	0x17f104bd,
+	0xf7f00100,
+	0x0d21f502,
+	0x1f21f508,
+	0x10f7f008,
+	0x086c21f5,
+	0x98000e98,
+	0x21f5010f,
+	0x14950150,
+	0x0007f108,
+	0x0103f0c0,
+	0xbd0004d0,
+	0x0007f104,
+	0x0103f0c1,
+	0xbd0004d0,
+	0x0030b704,
+	0x001fbb13,
+	0xf102f5b6,
+	0xf0d30007,
+	0x0fd00103,
+	0xb604bd00,
+	0x10b60815,
+	0x0814b601,
+	0xf5021fb9,
+	0xbb02d321,
+	0x0398001f,
+	0x0047f102,
+	0x5043f020,
+/* 0x04f4: init_gpc */
+	0x08044ea0,
+	0xf4021fb9,
+	0x4ea09d21,
+	0xf4bd010c,
+	0xa09d21f4,
+	0xf401044e,
+	0x4ea09d21,
+	0xf7f00100,
+	0x9d21f402,
+	0x08004ea0,
+/* 0x051c: init_gpc_wait */
+	0xc86821f4,
+	0x0bf41fff,
+	0x044ea0fa,
+	0x6821f408,
+	0xb7001fbb,
+	0xb6800040,
+	0x1bf40132,
+	0x00f7f0be,
+	0x086c21f5,
+	0xf500f7f0,
+	0xf1080d21,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0564: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00e91b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xc00017f1,
+	0xcf0213f0,
+	0x27f10011,
+	0x23f0c100,
+	0x0022cf02,
+	0xf51f13c8,
+	0xc800890b,
+	0x0bf41f23,
+	0xb920f962,
+	0x94bd0212,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x31f40132,
+	0x4021f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x20fc04bd,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0131f404,
+	0x0a4021f5,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f017,
+	0xbd0009d0,
+	0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+	0x12b920f9,
+	0x0132f402,
+	0xf50232f4,
+	0xfc0a4021,
+	0x0007f120,
+	0x0203f0c0,
+	0xbd0002d0,
+	0x130ef404,
+/* 0x062c: chsw_no_prev */
+	0xf41f23c8,
+	0x31f40d0b,
+	0x0232f401,
+	0x0a4021f5,
+/* 0x063c: chsw_done */
+	0xf10127f0,
+	0xf0c30007,
+	0x02d00203,
+	0xbd04bd00,
+	0x0499f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+	0xf401e4b0,
+	0xf2b90d1b,
+	0xd021f502,
+	0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+	0xf402e4b0,
+	0x94bd321b,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x32f40132,
+	0x4021f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+	0x10ef9411,
+	0xf501f5f0,
+	0xf5037e21,
+/* 0x06b3: main_done */
+	0xbdfeb50e,
+	0x1f29f024,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xfea00ef5,
+/* 0x06c8: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x10d7f030,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xb70421f4,
+	0xf00400b0,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x071a: ih_no_fifo */
+	0xabe404bd,
+	0x0bf40100,
+	0x10d7f00d,
+	0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+	0xe40421f4,
+	0xf40400ab,
+	0xe7f16c0b,
+	0xe3f00708,
+	0x6821f440,
+	0xf102ffb9,
+	0xf0040007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf00704e7,
+	0x21f440e3,
+	0x02ffb968,
+	0x030007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0x9450fec7,
+	0xf7f102ee,
+	0xf3f00700,
+	0x00efbb40,
+	0xf16821f4,
+	0xf0020007,
+	0x0fd00203,
+	0xf004bd00,
+	0x21f503f7,
+	0xb7f1037e,
+	0xbfb90100,
+	0x44e7f102,
+	0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+	0xf19d21f4,
+	0xbd0504b7,
+	0xb4abffb0,
+	0xf10f0bf4,
+	0xf0070007,
+	0x0bd00303,
+/* 0x07b3: ih_no_other */
+	0xf104bd00,
+	0xf0010007,
+	0x0ad00003,
+	0xfc04bd00,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x07d7: ctx_4160s */
+	0xf001f800,
+	0xffb901f7,
+	0x60e7f102,
+	0x40e3f041,
+/* 0x07e7: ctx_4160s_wait */
+	0xf19d21f4,
+	0xf04160e7,
+	0x21f440e3,
+	0x02ffb968,
+	0xf404ffc8,
+	0x00f8f00b,
+/* 0x07fc: ctx_4160c */
+	0xffb9f4bd,
+	0x60e7f102,
+	0x40e3f041,
+	0xf89d21f4,
+/* 0x080d: ctx_4170s */
+	0x10f5f000,
+	0xf102ffb9,
+	0xf04170e7,
+	0x21f440e3,
+/* 0x081f: ctx_4170w */
+	0xf100f89d,
+	0xf04170e7,
+	0x21f440e3,
+	0x02ffb968,
+	0xf410f4f0,
+	0x00f8f01b,
+/* 0x0834: ctx_redswitch */
+	0x0200e7f1,
+	0xf040e5f0,
+	0xe5f020e5,
+	0x0007f110,
+	0x0103f085,
+	0xbd000ed0,
+	0x08f7f004,
+/* 0x0850: ctx_redswitch_delay */
+	0xf401f2b6,
+	0xe5f1fd1b,
+	0xe5f10400,
+	0x07f10100,
+	0x03f08500,
+	0x000ed001,
+	0x00f804bd,
+/* 0x086c: ctx_86c */
+	0x1b0007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0xf102ffb9,
+	0xf08a14e7,
+	0x21f440e3,
+	0x02ffb99d,
+	0xa86ce7f1,
+	0xf441e3f0,
+	0x00f89d21,
+/* 0x0894: ctx_mem */
+	0x840007f1,
+	0xd00203f0,
+	0x04bd000f,
+/* 0x08a0: ctx_mem_wait */
+	0x8400f7f1,
+	0xcf02f3f0,
+	0xfffd00ff,
+	0xf31bf405,
+/* 0x08b2: ctx_load */
+	0x94bd00f8,
+	0xf10599f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf004bd00,
+	0x21f40ca7,
+	0xf1f4bdd0,
+	0xf0890007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf0c10007,
+	0x02d00203,
+	0xf104bd00,
+	0xf0830007,
+	0x02d00203,
+	0xf004bd00,
+	0x21f507f7,
+	0x07f10894,
+	0x03f0c000,
+	0x0002d002,
+	0x0bfe04bd,
+	0x1f2af000,
+	0xb60424b6,
+	0x94bd0220,
+	0xf10899f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
+	0xf0810007,
+	0x02d00203,
+	0xf104bd00,
+	0xf1000027,
+	0xf0800023,
+	0x07f10225,
+	0x03f08800,
+	0x0002d002,
+	0x17f004bd,
+	0x0027f110,
+	0x0223f002,
+	0xf80512fa,
+	0xf094bd03,
+	0x07f10899,
+	0x03f01700,
+	0x0009d002,
+	0x019804bd,
+	0x1814b681,
+	0xb6800298,
+	0x12fd0825,
+	0x16018005,
+	0x99f094bd,
+	0x0007f109,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f081,
+	0xbd0001d0,
+	0x0127f004,
+	0x880007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0x010017f1,
+	0xfa0613f0,
+	0x03f80501,
+	0x99f094bd,
+	0x0007f109,
+	0x0203f017,
+	0xbd0009d0,
+	0xf094bd04,
+	0x07f10599,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x09d0: ctx_chan */
+	0x07d721f5,
+	0x08b221f5,
+	0xf40ca7f0,
+	0xf7f0d021,
+	0x9421f505,
+	0xfc21f508,
+/* 0x09eb: ctx_mmio_exec */
+	0x9800f807,
+	0x07f14103,
+	0x03f08100,
+	0x0003d002,
+	0x34bd04bd,
+/* 0x09fc: ctx_mmio_loop */
+	0xf4ff34c4,
+	0x57f10f1b,
+	0x53f00200,
+	0x0535fa06,
+/* 0x0a0e: ctx_mmio_pull */
+	0x4e9803f8,
+	0x814f9880,
+	0xb69d21f4,
+	0x12b60830,
+	0xdf1bf401,
+/* 0x0a20: ctx_mmio_done */
+	0xf1160398,
+	0xf0810007,
+	0x03d00203,
+	0x8004bd00,
+	0x17f14000,
+	0x13f00100,
+	0x0601fa06,
+	0x00f803f8,
+/* 0x0a40: ctx_xfer */
+	0xf104e7f0,
+	0xf0020007,
+	0x0ed00303,
+/* 0x0a4f: ctx_xfer_idle */
+	0xf104bd00,
+	0xf00000e7,
+	0xeecf03e3,
+	0x00e4f100,
+	0xf21bf420,
+	0xf40611f4,
+/* 0x0a66: ctx_xfer_pre */
+	0xf7f01102,
+	0x6c21f510,
+	0xd721f508,
+	0x1c11f407,
+/* 0x0a74: ctx_xfer_pre_load */
+	0xf502f7f0,
+	0xf5080d21,
+	0xf5081f21,
+	0xbd083421,
+	0x0d21f5f4,
+	0xb221f508,
+/* 0x0a8d: ctx_xfer_exec */
+	0x16019808,
+	0x07f124bd,
+	0x03f00500,
+	0x0002d001,
+	0x1fb904bd,
+	0x00e7f102,
+	0x41e3f0a5,
+	0xf09d21f4,
+	0x2cf001fc,
+	0x0124b602,
+	0xb905f2fd,
+	0xe7f102ff,
+	0xe3f0a504,
+	0x9d21f441,
+	0x026a21f5,
+	0x07f124bd,
+	0x03f047fc,
+	0x0002d002,
+	0x2cf004bd,
+	0x0320b601,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf001acf0,
+	0xb7f006a5,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xa7f0016f,
+	0x1021f508,
+	0x5e21f501,
+	0x1301f402,
+	0xf40ca7f0,
+	0xf7f0d021,
+	0x9421f505,
+	0x3202f408,
+/* 0x0b1c: ctx_xfer_post */
+	0xf502f7f0,
+	0xbd080d21,
+	0x6c21f5f4,
+	0x7f21f508,
+	0x1f21f502,
+	0xf5f4bd08,
+	0xf4080d21,
+	0x01981011,
+	0x0511fd40,
+	0xf5070bf4,
+/* 0x0b47: ctx_xfer_no_post_mmio */
+	0xf509eb21,
+/* 0x0b4b: ctx_xfer_done */
+	0xf807fc21,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3
new file mode 100644
index 0000000..d977d39
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK100
+#include "macros.fuc"
+
+.section #gk104_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk104_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h
new file mode 100644
index 0000000..95ac151
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h
@@ -0,0 +1,1044 @@
+uint32_t gk104_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t gk104_grhub_code[] = {
+	0x039b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x039b: init */
+	0xbd00f804,
+	0x0007fe04,
+	0x420017f1,
+	0xcf0013f0,
+	0x11e70011,
+	0x14b60109,
+	0x0014fe08,
+	0xf10227f0,
+	0xf0120007,
+	0x02d00003,
+	0xf104bd00,
+	0xfe06c817,
+	0x24bd0010,
+	0x070007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0x200327f1,
+	0x010007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200427f1,
+	0x010407f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200b27f1,
+	0x010807f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200c27f1,
+	0x011c07f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1010392,
+	0xf0090007,
+	0x03d00303,
+	0xf104bd00,
+	0xf0870427,
+	0x07f10023,
+	0x03f00400,
+	0x0002d000,
+	0x27f004bd,
+	0x0007f104,
+	0x0003f003,
+	0xbd0002d0,
+	0x1031f404,
+	0x9604e7f1,
+	0xf440e3f0,
+	0xfeb96821,
+	0x90f1c702,
+	0xf0030180,
+	0x0f801ff4,
+	0x0117f002,
+	0xb6041fbb,
+	0x07f10112,
+	0x03f00300,
+	0x0001d001,
+	0x07f104bd,
+	0x03f00400,
+	0x0001d001,
+	0x17f104bd,
+	0xf7f00100,
+	0xd721f502,
+	0xe921f507,
+	0x10f7f007,
+	0x083621f5,
+	0x98000e98,
+	0x21f5010f,
+	0x14950150,
+	0x0007f108,
+	0x0103f0c0,
+	0xbd0004d0,
+	0x0007f104,
+	0x0103f0c1,
+	0xbd0004d0,
+	0x0030b704,
+	0x001fbb13,
+	0xf102f5b6,
+	0xf0d30007,
+	0x0fd00103,
+	0xb604bd00,
+	0x10b60815,
+	0x0814b601,
+	0xf5021fb9,
+	0xbb02d321,
+	0x0398001f,
+	0x0047f102,
+	0x5043f020,
+/* 0x04f4: init_gpc */
+	0x08044ea0,
+	0xf4021fb9,
+	0x4ea09d21,
+	0xf4bd010c,
+	0xa09d21f4,
+	0xf401044e,
+	0x4ea09d21,
+	0xf7f00100,
+	0x9d21f402,
+	0x08004ea0,
+/* 0x051c: init_gpc_wait */
+	0xc86821f4,
+	0x0bf41fff,
+	0x044ea0fa,
+	0x6821f408,
+	0xb7001fbb,
+	0xb6800040,
+	0x1bf40132,
+	0x00f7f0be,
+	0x083621f5,
+	0xf500f7f0,
+	0xf107d721,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0564: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00e91b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xc00017f1,
+	0xcf0213f0,
+	0x27f10011,
+	0x23f0c100,
+	0x0022cf02,
+	0xf51f13c8,
+	0xc800890b,
+	0x0bf41f23,
+	0xb920f962,
+	0x94bd0212,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x31f40132,
+	0x0221f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x20fc04bd,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0131f404,
+	0x0a0221f5,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f017,
+	0xbd0009d0,
+	0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+	0x12b920f9,
+	0x0132f402,
+	0xf50232f4,
+	0xfc0a0221,
+	0x0007f120,
+	0x0203f0c0,
+	0xbd0002d0,
+	0x130ef404,
+/* 0x062c: chsw_no_prev */
+	0xf41f23c8,
+	0x31f40d0b,
+	0x0232f401,
+	0x0a0221f5,
+/* 0x063c: chsw_done */
+	0xf10127f0,
+	0xf0c30007,
+	0x02d00203,
+	0xbd04bd00,
+	0x0499f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+	0xf401e4b0,
+	0xf2b90d1b,
+	0x9a21f502,
+	0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+	0xf402e4b0,
+	0x94bd321b,
+	0xf10799f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf404bd00,
+	0x32f40132,
+	0x0221f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+	0x10ef9411,
+	0xf501f5f0,
+	0xf5037e21,
+/* 0x06b3: main_done */
+	0xbdfeb50e,
+	0x1f29f024,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xfea00ef5,
+/* 0x06c8: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x10d7f030,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xb70421f4,
+	0xf00400b0,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x071a: ih_no_fifo */
+	0xabe404bd,
+	0x0bf40100,
+	0x10d7f00d,
+	0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+	0xe40421f4,
+	0xf40400ab,
+	0xe7f16c0b,
+	0xe3f00708,
+	0x6821f440,
+	0xf102ffb9,
+	0xf0040007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf00704e7,
+	0x21f440e3,
+	0x02ffb968,
+	0x030007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0x9450fec7,
+	0xf7f102ee,
+	0xf3f00700,
+	0x00efbb40,
+	0xf16821f4,
+	0xf0020007,
+	0x0fd00203,
+	0xf004bd00,
+	0x21f503f7,
+	0xb7f1037e,
+	0xbfb90100,
+	0x44e7f102,
+	0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+	0xf19d21f4,
+	0xbd0504b7,
+	0xb4abffb0,
+	0xf10f0bf4,
+	0xf0070007,
+	0x0bd00303,
+/* 0x07b3: ih_no_other */
+	0xf104bd00,
+	0xf0010007,
+	0x0ad00003,
+	0xfc04bd00,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x07d7: ctx_4170s */
+	0xf001f800,
+	0xffb910f5,
+	0x70e7f102,
+	0x40e3f041,
+	0xf89d21f4,
+/* 0x07e9: ctx_4170w */
+	0x70e7f100,
+	0x40e3f041,
+	0xb96821f4,
+	0xf4f002ff,
+	0xf01bf410,
+/* 0x07fe: ctx_redswitch */
+	0xe7f100f8,
+	0xe5f00200,
+	0x20e5f040,
+	0xf110e5f0,
+	0xf0850007,
+	0x0ed00103,
+	0xf004bd00,
+/* 0x081a: ctx_redswitch_delay */
+	0xf2b608f7,
+	0xfd1bf401,
+	0x0400e5f1,
+	0x0100e5f1,
+	0x850007f1,
+	0xd00103f0,
+	0x04bd000e,
+/* 0x0836: ctx_86c */
+	0x07f100f8,
+	0x03f01b00,
+	0x000fd002,
+	0xffb904bd,
+	0x14e7f102,
+	0x40e3f08a,
+	0xb99d21f4,
+	0xe7f102ff,
+	0xe3f0a86c,
+	0x9d21f441,
+/* 0x085e: ctx_mem */
+	0x07f100f8,
+	0x03f08400,
+	0x000fd002,
+/* 0x086a: ctx_mem_wait */
+	0xf7f104bd,
+	0xf3f08400,
+	0x00ffcf02,
+	0xf405fffd,
+	0x00f8f31b,
+/* 0x087c: ctx_load */
+	0x99f094bd,
+	0x0007f105,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0ca7f004,
+	0xbdd021f4,
+	0x0007f1f4,
+	0x0203f089,
+	0xbd000fd0,
+	0x0007f104,
+	0x0203f0c1,
+	0xbd0002d0,
+	0x0007f104,
+	0x0203f083,
+	0xbd0002d0,
+	0x07f7f004,
+	0x085e21f5,
+	0xc00007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf0000bfe,
+	0x24b61f2a,
+	0x0220b604,
+	0x99f094bd,
+	0x0007f108,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f081,
+	0xbd0002d0,
+	0x0027f104,
+	0x0023f100,
+	0x0225f080,
+	0x880007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf11017f0,
+	0xf0020027,
+	0x12fa0223,
+	0xbd03f805,
+	0x0899f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xb6810198,
+	0x02981814,
+	0x0825b680,
+	0x800512fd,
+	0x94bd1601,
+	0xf10999f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
+	0xf0810007,
+	0x01d00203,
+	0xf004bd00,
+	0x07f10127,
+	0x03f08800,
+	0x0002d002,
+	0x17f104bd,
+	0x13f00100,
+	0x0501fa06,
+	0x94bd03f8,
+	0xf10999f0,
+	0xf0170007,
+	0x09d00203,
+	0xbd04bd00,
+	0x0599f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x099a: ctx_chan */
+	0x21f500f8,
+	0xa7f0087c,
+	0xd021f40c,
+	0xf505f7f0,
+	0xf8085e21,
+/* 0x09ad: ctx_mmio_exec */
+	0x41039800,
+	0x810007f1,
+	0xd00203f0,
+	0x04bd0003,
+/* 0x09be: ctx_mmio_loop */
+	0x34c434bd,
+	0x0f1bf4ff,
+	0x020057f1,
+	0xfa0653f0,
+	0x03f80535,
+/* 0x09d0: ctx_mmio_pull */
+	0x98804e98,
+	0x21f4814f,
+	0x0830b69d,
+	0xf40112b6,
+/* 0x09e2: ctx_mmio_done */
+	0x0398df1b,
+	0x0007f116,
+	0x0203f081,
+	0xbd0003d0,
+	0x40008004,
+	0x010017f1,
+	0xfa0613f0,
+	0x03f80601,
+/* 0x0a02: ctx_xfer */
+	0xe7f000f8,
+	0x0007f104,
+	0x0303f002,
+	0xbd000ed0,
+/* 0x0a11: ctx_xfer_idle */
+	0x00e7f104,
+	0x03e3f000,
+	0xf100eecf,
+	0xf42000e4,
+	0x11f4f21b,
+	0x0d02f406,
+/* 0x0a28: ctx_xfer_pre */
+	0xf510f7f0,
+	0xf4083621,
+/* 0x0a32: ctx_xfer_pre_load */
+	0xf7f01c11,
+	0xd721f502,
+	0xe921f507,
+	0xfe21f507,
+	0xf5f4bd07,
+	0xf507d721,
+/* 0x0a4b: ctx_xfer_exec */
+	0x98087c21,
+	0x24bd1601,
+	0x050007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1021fb9,
+	0xf0a500e7,
+	0x21f441e3,
+	0x01fcf09d,
+	0xb6022cf0,
+	0xf2fd0124,
+	0x02ffb905,
+	0xa504e7f1,
+	0xf441e3f0,
+	0x21f59d21,
+	0x24bd026a,
+	0x47fc07f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xb6012cf0,
+	0x07f10320,
+	0x03f04afc,
+	0x0002d002,
+	0xacf004bd,
+	0x06a5f001,
+	0x9800b7f0,
+	0x0d98000c,
+	0x00e7f001,
+	0x016f21f5,
+	0xf508a7f0,
+	0xf5011021,
+	0xf4025e21,
+	0xa7f01301,
+	0xd021f40c,
+	0xf505f7f0,
+	0xf4085e21,
+/* 0x0ada: ctx_xfer_post */
+	0xf7f02e02,
+	0xd721f502,
+	0xf5f4bd07,
+	0xf5083621,
+	0xf5027f21,
+	0xbd07e921,
+	0xd721f5f4,
+	0x1011f407,
+	0xfd400198,
+	0x0bf40511,
+	0xad21f507,
+/* 0x0b05: ctx_xfer_no_post_mmio */
+/* 0x0b05: ctx_xfer_done */
+	0x0000f809,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3
new file mode 100644
index 0000000..760b463
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #gk110_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk110_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h
new file mode 100644
index 0000000..8998687
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h
@@ -0,0 +1,1044 @@
+uint32_t gk110_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t gk110_grhub_code[] = {
+	0x039b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f8037e,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0xf002ecb9,
+	0x07f11fc9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x007a: nv_rd32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0xa7f0f31b,
+	0x1021f506,
+	0x00f7f101,
+	0x01f3f0cb,
+	0xf800ffcf,
+/* 0x009d: nv_wr32 */
+	0x0007f100,
+	0x0103f0cc,
+	0xbd000fd0,
+	0x02ecb904,
+	0xf01fc9f0,
+	0x07f11ec9,
+	0x03f0ca00,
+	0x000cd001,
+/* 0x00be: nv_wr32_wait */
+	0xc7f104bd,
+	0xc3f0ca00,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f31b,
+/* 0x00d0: wait_donez */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f037,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x1bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0110: wait_doneo */
+	0x99f094bd,
+	0x0007f100,
+	0x0203f037,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f006,
+	0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+	0x0087f104,
+	0x0183f000,
+	0xff0088cf,
+	0x0bf4888a,
+	0xf094bdf3,
+	0x07f10099,
+	0x03f01700,
+	0x0009d002,
+	0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0xf404efb8,
+	0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+	0xbd00f802,
+	0x0199f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xbbfd94bd,
+	0x120bf405,
+	0xc40007f1,
+	0xd00103f0,
+	0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0x0007f11e,
+	0x0103f0c6,
+	0xbd000ed0,
+	0x0007f104,
+	0x0103f0c7,
+	0xbd000fd0,
+	0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+	0xb600abc8,
+	0xb9f010b4,
+	0x01aec80c,
+	0xfd11e4b6,
+	0x07f105be,
+	0x03f0c500,
+	0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+	0xe7f104bd,
+	0xe3f0c500,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f30b,
+	0x05e9fd00,
+	0xc80007f1,
+	0xd00103f0,
+	0x04bd000e,
+	0xb804c0b6,
+	0x1bf404cd,
+	0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+	0xf11f1bf4,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x1fb4f000,
+	0xf410b4b0,
+	0xa7f0f01b,
+	0xd021f405,
+/* 0x0223: mmctx_stop */
+	0xc82b0ef4,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xf112b9f0,
+	0xf0c50007,
+	0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+	0xf104bd00,
+	0xf0c500b7,
+	0xbbcf01b3,
+	0x12bbc800,
+/* 0x024b: mmctx_done */
+	0xbdf31bf4,
+	0x0199f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x025e: strand_wait */
+	0xa0f900f8,
+	0xf402a7f0,
+	0xa0fcd021,
+/* 0x026a: strand_pre */
+	0x97f000f8,
+	0xfc07f10c,
+	0x0203f04a,
+	0xbd0009d0,
+	0x5e21f504,
+/* 0x027f: strand_post */
+	0xf000f802,
+	0x07f10d97,
+	0x03f04afc,
+	0x0009d002,
+	0x21f504bd,
+	0x00f8025e,
+/* 0x0294: strand_set */
+	0xf10fc7f0,
+	0xf04ffc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f10bc7,
+	0x03f04afc,
+	0x000cd002,
+	0x07f104bd,
+	0x03f04ffc,
+	0x000ed002,
+	0xc7f004bd,
+	0xfc07f10a,
+	0x0203f04a,
+	0xbd000cd0,
+	0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+	0xbd00f802,
+	0x0399f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x026a21f5,
+	0xf503e7f0,
+	0xbd029421,
+	0xfc07f1c4,
+	0x0203f047,
+	0xbd000cd0,
+	0x01c7f004,
+	0x4afc07f1,
+	0xd00203f0,
+	0x04bd000c,
+	0x025e21f5,
+	0xf1010c92,
+	0xf046fc07,
+	0x0cd00203,
+	0xf004bd00,
+	0x07f102c7,
+	0x03f04afc,
+	0x000cd002,
+	0x21f504bd,
+	0x21f5025e,
+	0x87f1027f,
+	0x83f04200,
+	0x0097f102,
+	0x0293f020,
+	0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x037e: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x039b: init */
+	0xbd00f804,
+	0x0007fe04,
+	0x420017f1,
+	0xcf0013f0,
+	0x11e70011,
+	0x14b60109,
+	0x0014fe08,
+	0xf10227f0,
+	0xf0120007,
+	0x02d00003,
+	0xf104bd00,
+	0xfe06c817,
+	0x24bd0010,
+	0x070007f1,
+	0xd00003f0,
+	0x04bd0002,
+	0x200327f1,
+	0x010007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200427f1,
+	0x010407f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200b27f1,
+	0x010807f1,
+	0xd00103f0,
+	0x04bd0002,
+	0x200c27f1,
+	0x011c07f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1010392,
+	0xf0090007,
+	0x03d00303,
+	0xf104bd00,
+	0xf0870427,
+	0x07f10023,
+	0x03f00400,
+	0x0002d000,
+	0x27f004bd,
+	0x0007f104,
+	0x0003f003,
+	0xbd0002d0,
+	0x1031f404,
+	0x9604e7f1,
+	0xf440e3f0,
+	0xfeb96821,
+	0x90f1c702,
+	0xf0030180,
+	0x0f801ff4,
+	0x0117f002,
+	0xb6041fbb,
+	0x07f10112,
+	0x03f00300,
+	0x0001d001,
+	0x07f104bd,
+	0x03f00400,
+	0x0001d001,
+	0x17f104bd,
+	0xf7f00100,
+	0xd721f502,
+	0xe921f507,
+	0x10f7f007,
+	0x083621f5,
+	0x98000e98,
+	0x21f5010f,
+	0x14950150,
+	0x0007f108,
+	0x0103f0c0,
+	0xbd0004d0,
+	0x0007f104,
+	0x0103f0c1,
+	0xbd0004d0,
+	0x0030b704,
+	0x001fbb13,
+	0xf102f5b6,
+	0xf0d30007,
+	0x0fd00103,
+	0xb604bd00,
+	0x10b60815,
+	0x0814b601,
+	0xf5021fb9,
+	0xbb02d321,
+	0x0398001f,
+	0x0047f102,
+	0x5043f020,
+/* 0x04f4: init_gpc */
+	0x08044ea0,
+	0xf4021fb9,
+	0x4ea09d21,
+	0xf4bd010c,
+	0xa09d21f4,
+	0xf401044e,
+	0x4ea09d21,
+	0xf7f00100,
+	0x9d21f402,
+	0x08004ea0,
+/* 0x051c: init_gpc_wait */
+	0xc86821f4,
+	0x0bf41fff,
+	0x044ea0fa,
+	0x6821f408,
+	0xb7001fbb,
+	0xb6800040,
+	0x1bf40132,
+	0x00f7f0be,
+	0x083621f5,
+	0xf500f7f0,
+	0xf107d721,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x300007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0564: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00e91b,
+	0x0499f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xc00017f1,
+	0xcf0213f0,
+	0x27f10011,
+	0x23f0c100,
+	0x0022cf02,
+	0xf51f13c8,
+	0xc800890b,
+	0x0bf41f23,
+	0xb920f962,
+	0x94bd0212,
+	0xf10799f0,
+	0xf0370007,
+	0x09d00203,
+	0xf404bd00,
+	0x31f40132,
+	0x0221f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x20fc04bd,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f037,
+	0xbd0009d0,
+	0x0131f404,
+	0x0a0221f5,
+	0x99f094bd,
+	0x0007f106,
+	0x0203f017,
+	0xbd0009d0,
+	0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+	0x12b920f9,
+	0x0132f402,
+	0xf50232f4,
+	0xfc0a0221,
+	0x0007f120,
+	0x0203f0c0,
+	0xbd0002d0,
+	0x130ef404,
+/* 0x062c: chsw_no_prev */
+	0xf41f23c8,
+	0x31f40d0b,
+	0x0232f401,
+	0x0a0221f5,
+/* 0x063c: chsw_done */
+	0xf10127f0,
+	0xf0c30007,
+	0x02d00203,
+	0xbd04bd00,
+	0x0499f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+	0xf401e4b0,
+	0xf2b90d1b,
+	0x9a21f502,
+	0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+	0xf402e4b0,
+	0x94bd321b,
+	0xf10799f0,
+	0xf0370007,
+	0x09d00203,
+	0xf404bd00,
+	0x32f40132,
+	0x0221f502,
+	0xf094bd0a,
+	0x07f10799,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+	0x10ef9411,
+	0xf501f5f0,
+	0xf5037e21,
+/* 0x06b3: main_done */
+	0xbdfeb50e,
+	0x1f29f024,
+	0x300007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xfea00ef5,
+/* 0x06c8: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x00a7f104,
+	0x00a3f002,
+	0xc400aacf,
+	0x0bf404ab,
+	0x10d7f030,
+	0x1a00e7f1,
+	0xcf00e3f0,
+	0xf7f100ee,
+	0xf3f01900,
+	0x00ffcf00,
+	0xb70421f4,
+	0xf00400b0,
+	0x07f101e7,
+	0x03f01d00,
+	0x000ed000,
+/* 0x071a: ih_no_fifo */
+	0xabe404bd,
+	0x0bf40100,
+	0x10d7f00d,
+	0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+	0xe40421f4,
+	0xf40400ab,
+	0xe7f16c0b,
+	0xe3f00708,
+	0x6821f440,
+	0xf102ffb9,
+	0xf0040007,
+	0x0fd00203,
+	0xf104bd00,
+	0xf00704e7,
+	0x21f440e3,
+	0x02ffb968,
+	0x030007f1,
+	0xd00203f0,
+	0x04bd000f,
+	0x9450fec7,
+	0xf7f102ee,
+	0xf3f00700,
+	0x00efbb40,
+	0xf16821f4,
+	0xf0020007,
+	0x0fd00203,
+	0xf004bd00,
+	0x21f503f7,
+	0xb7f1037e,
+	0xbfb90100,
+	0x44e7f102,
+	0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+	0xf19d21f4,
+	0xbd0504b7,
+	0xb4abffb0,
+	0xf10f0bf4,
+	0xf0070007,
+	0x0bd00303,
+/* 0x07b3: ih_no_other */
+	0xf104bd00,
+	0xf0010007,
+	0x0ad00003,
+	0xfc04bd00,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x07d7: ctx_4170s */
+	0xf001f800,
+	0xffb910f5,
+	0x70e7f102,
+	0x40e3f041,
+	0xf89d21f4,
+/* 0x07e9: ctx_4170w */
+	0x70e7f100,
+	0x40e3f041,
+	0xb96821f4,
+	0xf4f002ff,
+	0xf01bf410,
+/* 0x07fe: ctx_redswitch */
+	0xe7f100f8,
+	0xe5f00200,
+	0x20e5f040,
+	0xf110e5f0,
+	0xf0850007,
+	0x0ed00103,
+	0xf004bd00,
+/* 0x081a: ctx_redswitch_delay */
+	0xf2b608f7,
+	0xfd1bf401,
+	0x0400e5f1,
+	0x0100e5f1,
+	0x850007f1,
+	0xd00103f0,
+	0x04bd000e,
+/* 0x0836: ctx_86c */
+	0x07f100f8,
+	0x03f02300,
+	0x000fd002,
+	0xffb904bd,
+	0x14e7f102,
+	0x40e3f08a,
+	0xb99d21f4,
+	0xe7f102ff,
+	0xe3f0a88c,
+	0x9d21f441,
+/* 0x085e: ctx_mem */
+	0x07f100f8,
+	0x03f08400,
+	0x000fd002,
+/* 0x086a: ctx_mem_wait */
+	0xf7f104bd,
+	0xf3f08400,
+	0x00ffcf02,
+	0xf405fffd,
+	0x00f8f31b,
+/* 0x087c: ctx_load */
+	0x99f094bd,
+	0x0007f105,
+	0x0203f037,
+	0xbd0009d0,
+	0x0ca7f004,
+	0xbdd021f4,
+	0x0007f1f4,
+	0x0203f089,
+	0xbd000fd0,
+	0x0007f104,
+	0x0203f0c1,
+	0xbd0002d0,
+	0x0007f104,
+	0x0203f083,
+	0xbd0002d0,
+	0x07f7f004,
+	0x085e21f5,
+	0xc00007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf0000bfe,
+	0x24b61f2a,
+	0x0220b604,
+	0x99f094bd,
+	0x0007f108,
+	0x0203f037,
+	0xbd0009d0,
+	0x0007f104,
+	0x0203f081,
+	0xbd0002d0,
+	0x0027f104,
+	0x0023f100,
+	0x0225f080,
+	0x880007f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xf11017f0,
+	0xf0020027,
+	0x12fa0223,
+	0xbd03f805,
+	0x0899f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xb6810198,
+	0x02981814,
+	0x0825b680,
+	0x800512fd,
+	0x94bd1601,
+	0xf10999f0,
+	0xf0370007,
+	0x09d00203,
+	0xf104bd00,
+	0xf0810007,
+	0x01d00203,
+	0xf004bd00,
+	0x07f10127,
+	0x03f08800,
+	0x0002d002,
+	0x17f104bd,
+	0x13f00100,
+	0x0501fa06,
+	0x94bd03f8,
+	0xf10999f0,
+	0xf0170007,
+	0x09d00203,
+	0xbd04bd00,
+	0x0599f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x099a: ctx_chan */
+	0x21f500f8,
+	0xa7f0087c,
+	0xd021f40c,
+	0xf505f7f0,
+	0xf8085e21,
+/* 0x09ad: ctx_mmio_exec */
+	0x41039800,
+	0x810007f1,
+	0xd00203f0,
+	0x04bd0003,
+/* 0x09be: ctx_mmio_loop */
+	0x34c434bd,
+	0x0f1bf4ff,
+	0x020057f1,
+	0xfa0653f0,
+	0x03f80535,
+/* 0x09d0: ctx_mmio_pull */
+	0x98804e98,
+	0x21f4814f,
+	0x0830b69d,
+	0xf40112b6,
+/* 0x09e2: ctx_mmio_done */
+	0x0398df1b,
+	0x0007f116,
+	0x0203f081,
+	0xbd0003d0,
+	0x40008004,
+	0x010017f1,
+	0xfa0613f0,
+	0x03f80601,
+/* 0x0a02: ctx_xfer */
+	0xe7f000f8,
+	0x0007f104,
+	0x0303f002,
+	0xbd000ed0,
+/* 0x0a11: ctx_xfer_idle */
+	0x00e7f104,
+	0x03e3f000,
+	0xf100eecf,
+	0xf42000e4,
+	0x11f4f21b,
+	0x0d02f406,
+/* 0x0a28: ctx_xfer_pre */
+	0xf510f7f0,
+	0xf4083621,
+/* 0x0a32: ctx_xfer_pre_load */
+	0xf7f01c11,
+	0xd721f502,
+	0xe921f507,
+	0xfe21f507,
+	0xf5f4bd07,
+	0xf507d721,
+/* 0x0a4b: ctx_xfer_exec */
+	0x98087c21,
+	0x24bd1601,
+	0x050007f1,
+	0xd00103f0,
+	0x04bd0002,
+	0xf1021fb9,
+	0xf0a500e7,
+	0x21f441e3,
+	0x01fcf09d,
+	0xb6022cf0,
+	0xf2fd0124,
+	0x02ffb905,
+	0xa504e7f1,
+	0xf441e3f0,
+	0x21f59d21,
+	0x24bd026a,
+	0x47fc07f1,
+	0xd00203f0,
+	0x04bd0002,
+	0xb6012cf0,
+	0x07f10320,
+	0x03f04afc,
+	0x0002d002,
+	0xacf004bd,
+	0x06a5f001,
+	0x9800b7f0,
+	0x0d98000c,
+	0x00e7f001,
+	0x016f21f5,
+	0xf508a7f0,
+	0xf5011021,
+	0xf4025e21,
+	0xa7f01301,
+	0xd021f40c,
+	0xf505f7f0,
+	0xf4085e21,
+/* 0x0ada: ctx_xfer_post */
+	0xf7f02e02,
+	0xd721f502,
+	0xf5f4bd07,
+	0xf5083621,
+	0xf5027f21,
+	0xbd07e921,
+	0xd721f5f4,
+	0x1011f407,
+	0xfd400198,
+	0x0bf40511,
+	0xad21f507,
+/* 0x0b05: ctx_xfer_no_post_mmio */
+/* 0x0b05: ctx_xfer_done */
+	0x0000f809,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5
new file mode 100644
index 0000000..43243a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gk208_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk208_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h
new file mode 100644
index 0000000..0e98fa4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h
@@ -0,0 +1,916 @@
+uint32_t gk208_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t gk208_grhub_code[] = {
+	0x030e0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0xf489a408,
+	0x020f0b1b,
+	0x0002f87e,
+/* 0x001a: queue_put_next */
+	0x98c400f8,
+	0x0384b607,
+	0xb6008dbb,
+	0x8eb50880,
+	0x018fb500,
+	0xf00190b6,
+	0xd9b50f94,
+/* 0x0037: queue_get */
+	0xf400f801,
+	0xd8980131,
+	0x01d99800,
+	0x0bf489a4,
+	0x0789c421,
+	0xbb0394b6,
+	0x90b6009d,
+	0x009e9808,
+	0xb6019f98,
+	0x84f00180,
+	0x00d8b50f,
+/* 0x0063: queue_get_done */
+	0xf80132f4,
+/* 0x0065: nv_rd32 */
+	0xf0ecb200,
+	0x00801fc9,
+	0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+	0x8c04bd00,
+	0xcf01ca00,
+	0xccc800cc,
+	0xf61bf41f,
+	0xec7e060a,
+	0x008f0000,
+	0xffcf01cb,
+/* 0x008f: nv_wr32 */
+	0x8000f800,
+	0xf601cc00,
+	0x04bd000f,
+	0xc9f0ecb2,
+	0x1ec9f01f,
+	0x01ca0080,
+	0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+	0xca008c04,
+	0x00cccf01,
+	0xf41fccc8,
+	0x00f8f61b,
+/* 0x00b8: wait_donez */
+	0x99f094bd,
+	0x37008000,
+	0x0009f602,
+	0x008004bd,
+	0x0af60206,
+/* 0x00cf: wait_donez_ne */
+	0x8804bd00,
+	0xcf010000,
+	0x8aff0088,
+	0xf61bf488,
+	0x99f094bd,
+	0x17008000,
+	0x0009f602,
+	0x00f804bd,
+/* 0x00ec: wait_doneo */
+	0x99f094bd,
+	0x37008000,
+	0x0009f602,
+	0x008004bd,
+	0x0af60206,
+/* 0x0103: wait_doneo_e */
+	0x8804bd00,
+	0xcf010000,
+	0x8aff0088,
+	0xf60bf488,
+	0x99f094bd,
+	0x17008000,
+	0x0009f602,
+	0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+	0xe89894bd,
+	0x1a85b600,
+	0xb60180b6,
+	0x98bb0284,
+	0x04e0b600,
+	0x1bf4efa4,
+	0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+	0xf094bd00,
+	0x00800199,
+	0x09f60237,
+	0xbd04bd00,
+	0x05bbfd94,
+	0x800f0bf4,
+	0xf601c400,
+	0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+	0xfd0099f0,
+	0x0bf405ee,
+	0xc6008018,
+	0x000ef601,
+	0x008004bd,
+	0x0ff601c7,
+	0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+	0xabc80199,
+	0x10b4b600,
+	0xc80cb9f0,
+	0xe4b601ae,
+	0x05befd11,
+	0x01c50080,
+	0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+	0xc5008e04,
+	0x00eecf01,
+	0xf41fe4f0,
+	0xce98f60b,
+	0x05e9fd00,
+	0x01c80080,
+	0xbd000ef6,
+	0x04c0b604,
+	0x1bf4cda4,
+	0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+	0x8b1c1bf4,
+	0xcf01c500,
+	0xb4f000bb,
+	0x10b4b01f,
+	0x0af31bf4,
+	0x00b87e05,
+	0x250ef400,
+/* 0x01d8: mmctx_stop */
+	0xb600abc8,
+	0xb9f010b4,
+	0x12b9f00c,
+	0x01c50080,
+	0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+	0xc5008b04,
+	0x00bbcf01,
+	0xf412bbc8,
+/* 0x01fa: mmctx_done */
+	0x94bdf61b,
+	0x800199f0,
+	0xf6021700,
+	0x04bd0009,
+/* 0x020a: strand_wait */
+	0xa0f900f8,
+	0xb87e020a,
+	0xa0fc0000,
+/* 0x0216: strand_pre */
+	0x0c0900f8,
+	0x024afc80,
+	0xbd0009f6,
+	0x020a7e04,
+/* 0x0227: strand_post */
+	0x0900f800,
+	0x4afc800d,
+	0x0009f602,
+	0x0a7e04bd,
+	0x00f80002,
+/* 0x0238: strand_set */
+	0xfc800f0c,
+	0x0cf6024f,
+	0x0c04bd00,
+	0x4afc800b,
+	0x000cf602,
+	0xfc8004bd,
+	0x0ef6024f,
+	0x0c04bd00,
+	0x4afc800a,
+	0x000cf602,
+	0x0a7e04bd,
+	0x00f80002,
+/* 0x0268: strand_ctx_init */
+	0x99f094bd,
+	0x37008003,
+	0x0009f602,
+	0x167e04bd,
+	0x030e0002,
+	0x0002387e,
+	0xfc80c4bd,
+	0x0cf60247,
+	0x0c04bd00,
+	0x4afc8001,
+	0x000cf602,
+	0x0a7e04bd,
+	0x0c920002,
+	0x46fc8001,
+	0x000cf602,
+	0x020c04bd,
+	0x024afc80,
+	0xbd000cf6,
+	0x020a7e04,
+	0x02277e00,
+	0x42008800,
+	0x20008902,
+	0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+	0xf608fe95,
+	0x8ef6008e,
+	0x808acf40,
+	0xb606a5b6,
+	0xeabb01a0,
+	0x0480b600,
+	0xf40192b6,
+	0xe4b6e81b,
+	0xf2efbc08,
+	0x99f094bd,
+	0x17008003,
+	0x0009f602,
+	0x00f804bd,
+/* 0x02f8: error */
+	0x02050080,
+	0xbd000ff6,
+	0x80010f04,
+	0xf6030700,
+	0x04bd000f,
+/* 0x030e: init */
+	0x04bd00f8,
+	0x410007fe,
+	0x11cf4200,
+	0x0911e700,
+	0x0814b601,
+	0x020014fe,
+	0x12004002,
+	0xbd0002f6,
+	0x05c94104,
+	0xbd0010fe,
+	0x07004024,
+	0xbd0002f6,
+	0x20034204,
+	0x01010080,
+	0xbd0002f6,
+	0x20044204,
+	0x01010480,
+	0xbd0002f6,
+	0x200b4204,
+	0x01010880,
+	0xbd0002f6,
+	0x200c4204,
+	0x01011c80,
+	0xbd0002f6,
+	0x01039204,
+	0x03090080,
+	0xbd0003f6,
+	0x87044204,
+	0xf6040040,
+	0x04bd0002,
+	0x00400402,
+	0x0002f603,
+	0x31f404bd,
+	0x96048e10,
+	0x00657e40,
+	0xc7feb200,
+	0x01b590f1,
+	0x1ff4f003,
+	0x01020fb5,
+	0x041fbb01,
+	0x800112b6,
+	0xf6010300,
+	0x04bd0001,
+	0x01040080,
+	0xbd0001f6,
+	0x01004104,
+	0xa87e020f,
+	0xb77e0006,
+	0x100f0006,
+	0x0006f97e,
+	0x98000e98,
+	0x207e010f,
+	0x14950001,
+	0xc0008008,
+	0x0004f601,
+	0x008004bd,
+	0x04f601c1,
+	0xb704bd00,
+	0xbb130030,
+	0xf5b6001f,
+	0xd3008002,
+	0x000ff601,
+	0x15b604bd,
+	0x0110b608,
+	0xb20814b6,
+	0x02687e1f,
+	0x001fbb00,
+	0x84020398,
+/* 0x041f: init_gpc */
+	0xb8502000,
+	0x0008044e,
+	0x8f7e1fb2,
+	0x4eb80000,
+	0xbd00010c,
+	0x008f7ef4,
+	0x044eb800,
+	0x8f7e0001,
+	0x4eb80000,
+	0x0f000100,
+	0x008f7e02,
+	0x004eb800,
+/* 0x044e: init_gpc_wait */
+	0x657e0008,
+	0xffc80000,
+	0xf90bf41f,
+	0x08044eb8,
+	0x00657e00,
+	0x001fbb00,
+	0x800040b7,
+	0xf40132b6,
+	0x000fb41b,
+	0x0006f97e,
+	0xa87e000f,
+	0x00800006,
+	0x01f60201,
+	0xbd04bd00,
+	0x1f19f014,
+	0x02300080,
+	0xbd0001f6,
+/* 0x0491: main */
+	0x0031f404,
+	0x0d0028f4,
+	0x00377e10,
+	0xf401f400,
+	0x4001e4b1,
+	0x00c71bf5,
+	0x99f094bd,
+	0x37008004,
+	0x0009f602,
+	0x008104bd,
+	0x11cf02c0,
+	0xc1008200,
+	0x0022cf02,
+	0xf41f13c8,
+	0x23c8770b,
+	0x550bf41f,
+	0x12b220f9,
+	0x99f094bd,
+	0x37008007,
+	0x0009f602,
+	0x32f404bd,
+	0x0231f401,
+	0x00087c7e,
+	0x99f094bd,
+	0x17008007,
+	0x0009f602,
+	0x20fc04bd,
+	0x99f094bd,
+	0x37008006,
+	0x0009f602,
+	0x31f404bd,
+	0x087c7e01,
+	0xf094bd00,
+	0x00800699,
+	0x09f60217,
+	0xf404bd00,
+/* 0x0522: chsw_prev_no_next */
+	0x20f92f0e,
+	0x32f412b2,
+	0x0232f401,
+	0x00087c7e,
+	0x008020fc,
+	0x02f602c0,
+	0xf404bd00,
+/* 0x053e: chsw_no_prev */
+	0x23c8130e,
+	0x0d0bf41f,
+	0xf40131f4,
+	0x7c7e0232,
+/* 0x054e: chsw_done */
+	0x01020008,
+	0x02c30080,
+	0xbd0002f6,
+	0xf094bd04,
+	0x00800499,
+	0x09f60217,
+	0xf504bd00,
+/* 0x056b: main_not_ctx_switch */
+	0xb0ff2a0e,
+	0x1bf401e4,
+	0x7ef2b20c,
+	0xf400081c,
+/* 0x057a: main_not_ctx_chan */
+	0xe4b0400e,
+	0x2c1bf402,
+	0x99f094bd,
+	0x37008007,
+	0x0009f602,
+	0x32f404bd,
+	0x0232f401,
+	0x00087c7e,
+	0x99f094bd,
+	0x17008007,
+	0x0009f602,
+	0x0ef404bd,
+/* 0x05a9: main_not_ctx_save */
+	0x10ef9411,
+	0x7e01f5f0,
+	0xf50002f8,
+/* 0x05b7: main_done */
+	0xbdfede0e,
+	0x1f29f024,
+	0x02300080,
+	0xbd0002f6,
+	0xcc0ef504,
+/* 0x05c9: ih */
+	0xfe80f9fe,
+	0x80f90188,
+	0xa0f990f9,
+	0xd0f9b0f9,
+	0xf0f9e0f9,
+	0x004a04bd,
+	0x00aacf02,
+	0xf404abc4,
+	0x100d230b,
+	0xcf1a004e,
+	0x004f00ee,
+	0x00ffcf19,
+	0x0000047e,
+	0x0400b0b7,
+	0x0040010e,
+	0x000ef61d,
+/* 0x060a: ih_no_fifo */
+	0xabe404bd,
+	0x0bf40100,
+	0x4e100d0c,
+	0x047e4001,
+/* 0x061a: ih_no_ctxsw */
+	0xabe40000,
+	0x0bf40400,
+	0x07088e56,
+	0x00657e40,
+	0x80ffb200,
+	0xf6020400,
+	0x04bd000f,
+	0x4007048e,
+	0x0000657e,
+	0x0080ffb2,
+	0x0ff60203,
+	0xc704bd00,
+	0xee9450fe,
+	0x07008f02,
+	0x00efbb40,
+	0x0000657e,
+	0x02020080,
+	0xbd000ff6,
+	0x7e030f04,
+	0x4b0002f8,
+	0xbfb20100,
+	0x4001448e,
+	0x00008f7e,
+/* 0x0674: ih_no_fwmthd */
+	0xbd05044b,
+	0xb4abffb0,
+	0x800c0bf4,
+	0xf6030700,
+	0x04bd000b,
+/* 0x0688: ih_no_other */
+	0xf6010040,
+	0x04bd000a,
+	0xe0fcf0fc,
+	0xb0fcd0fc,
+	0x90fca0fc,
+	0x88fe80fc,
+	0xf480fc00,
+	0x01f80032,
+/* 0x06a8: ctx_4170s */
+	0xb210f5f0,
+	0x41708eff,
+	0x008f7e40,
+/* 0x06b7: ctx_4170w */
+	0x8e00f800,
+	0x7e404170,
+	0xb2000065,
+	0x10f4f0ff,
+	0xf8f31bf4,
+/* 0x06c9: ctx_redswitch */
+	0x02004e00,
+	0xf040e5f0,
+	0xe5f020e5,
+	0x85008010,
+	0x000ef601,
+	0x080f04bd,
+/* 0x06e0: ctx_redswitch_delay */
+	0xf401f2b6,
+	0xe5f1fd1b,
+	0xe5f10400,
+	0x00800100,
+	0x0ef60185,
+	0xf804bd00,
+/* 0x06f9: ctx_86c */
+	0x23008000,
+	0x000ff602,
+	0xffb204bd,
+	0x408a148e,
+	0x00008f7e,
+	0x8c8effb2,
+	0x8f7e41a8,
+	0x00f80000,
+/* 0x0718: ctx_mem */
+	0x02840080,
+	0xbd000ff6,
+/* 0x0721: ctx_mem_wait */
+	0x84008f04,
+	0x00ffcf02,
+	0xf405fffd,
+	0x00f8f61b,
+/* 0x0730: ctx_load */
+	0x99f094bd,
+	0x37008005,
+	0x0009f602,
+	0x0c0a04bd,
+	0x0000b87e,
+	0x0080f4bd,
+	0x0ff60289,
+	0x8004bd00,
+	0xf602c100,
+	0x04bd0002,
+	0x02830080,
+	0xbd0002f6,
+	0x7e070f04,
+	0x80000718,
+	0xf602c000,
+	0x04bd0002,
+	0xf0000bfe,
+	0x24b61f2a,
+	0x0220b604,
+	0x99f094bd,
+	0x37008008,
+	0x0009f602,
+	0x008004bd,
+	0x02f60281,
+	0xd204bd00,
+	0x80000000,
+	0x800225f0,
+	0xf6028800,
+	0x04bd0002,
+	0x00421001,
+	0x0223f002,
+	0xf80512fa,
+	0xf094bd03,
+	0x00800899,
+	0x09f60217,
+	0x9804bd00,
+	0x14b68101,
+	0x80029818,
+	0xfd0825b6,
+	0x01b50512,
+	0xf094bd16,
+	0x00800999,
+	0x09f60237,
+	0x8004bd00,
+	0xf6028100,
+	0x04bd0001,
+	0x00800102,
+	0x02f60288,
+	0x4104bd00,
+	0x13f00100,
+	0x0501fa06,
+	0x94bd03f8,
+	0x800999f0,
+	0xf6021700,
+	0x04bd0009,
+	0x99f094bd,
+	0x17008005,
+	0x0009f602,
+	0x00f804bd,
+/* 0x081c: ctx_chan */
+	0x0007307e,
+	0xb87e0c0a,
+	0x050f0000,
+	0x0007187e,
+/* 0x082e: ctx_mmio_exec */
+	0x039800f8,
+	0x81008041,
+	0x0003f602,
+	0x34bd04bd,
+/* 0x083c: ctx_mmio_loop */
+	0xf4ff34c4,
+	0x00450e1b,
+	0x0653f002,
+	0xf80535fa,
+/* 0x084d: ctx_mmio_pull */
+	0x804e9803,
+	0x7e814f98,
+	0xb600008f,
+	0x12b60830,
+	0xdf1bf401,
+/* 0x0860: ctx_mmio_done */
+	0x80160398,
+	0xf6028100,
+	0x04bd0003,
+	0x414000b5,
+	0x13f00100,
+	0x0601fa06,
+	0x00f803f8,
+/* 0x087c: ctx_xfer */
+	0x0080040e,
+	0x0ef60302,
+/* 0x0887: ctx_xfer_idle */
+	0x8e04bd00,
+	0xcf030000,
+	0xe4f100ee,
+	0x1bf42000,
+	0x0611f4f5,
+/* 0x089b: ctx_xfer_pre */
+	0x0f0c02f4,
+	0x06f97e10,
+	0x1b11f400,
+/* 0x08a4: ctx_xfer_pre_load */
+	0xa87e020f,
+	0xb77e0006,
+	0xc97e0006,
+	0xf4bd0006,
+	0x0006a87e,
+	0x0007307e,
+/* 0x08bc: ctx_xfer_exec */
+	0xbd160198,
+	0x05008024,
+	0x0002f601,
+	0x1fb204bd,
+	0x41a5008e,
+	0x00008f7e,
+	0xf001fcf0,
+	0x24b6022c,
+	0x05f2fd01,
+	0x048effb2,
+	0x8f7e41a5,
+	0x167e0000,
+	0x24bd0002,
+	0x0247fc80,
+	0xbd0002f6,
+	0x012cf004,
+	0x800320b6,
+	0xf6024afc,
+	0x04bd0002,
+	0xf001acf0,
+	0x000b06a5,
+	0x98000c98,
+	0x000e010d,
+	0x00013d7e,
+	0xec7e080a,
+	0x0a7e0000,
+	0x01f40002,
+	0x7e0c0a12,
+	0x0f0000b8,
+	0x07187e05,
+	0x2d02f400,
+/* 0x0938: ctx_xfer_post */
+	0xa87e020f,
+	0xf4bd0006,
+	0x0006f97e,
+	0x0002277e,
+	0x0006b77e,
+	0xa87ef4bd,
+	0x11f40006,
+	0x40019810,
+	0xf40511fd,
+	0x2e7e070b,
+/* 0x0962: ctx_xfer_no_post_mmio */
+/* 0x0962: ctx_xfer_done */
+	0x00f80008,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
new file mode 100644
index 0000000..1dd482e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -0,0 +1,1678 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+#include "fuc/os.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/option.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * Zero Bandwidth Clear
+ ******************************************************************************/
+
+static void
+gf100_gr_zbc_clear_color(struct gf100_gr_priv *priv, int zbc)
+{
+	if (priv->zbc_color[zbc].format) {
+		nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]);
+		nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]);
+		nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]);
+		nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]);
+	}
+	nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format);
+	nv_wr32(priv, 0x405820, zbc);
+	nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */
+}
+
+static int
+gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format,
+		       const u32 ds[4], const u32 l2[4])
+{
+	struct nvkm_ltc *ltc = nvkm_ltc(priv);
+	int zbc = -ENOSPC, i;
+
+	for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+		if (priv->zbc_color[i].format) {
+			if (priv->zbc_color[i].format != format)
+				continue;
+			if (memcmp(priv->zbc_color[i].ds, ds, sizeof(
+				   priv->zbc_color[i].ds)))
+				continue;
+			if (memcmp(priv->zbc_color[i].l2, l2, sizeof(
+				   priv->zbc_color[i].l2))) {
+				WARN_ON(1);
+				return -EINVAL;
+			}
+			return i;
+		} else {
+			zbc = (zbc < 0) ? i : zbc;
+		}
+	}
+
+	if (zbc < 0)
+		return zbc;
+
+	memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
+	memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
+	priv->zbc_color[zbc].format = format;
+	ltc->zbc_color_get(ltc, zbc, l2);
+	gf100_gr_zbc_clear_color(priv, zbc);
+	return zbc;
+}
+
+static void
+gf100_gr_zbc_clear_depth(struct gf100_gr_priv *priv, int zbc)
+{
+	if (priv->zbc_depth[zbc].format)
+		nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds);
+	nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format);
+	nv_wr32(priv, 0x405820, zbc);
+	nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */
+}
+
+static int
+gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format,
+		       const u32 ds, const u32 l2)
+{
+	struct nvkm_ltc *ltc = nvkm_ltc(priv);
+	int zbc = -ENOSPC, i;
+
+	for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+		if (priv->zbc_depth[i].format) {
+			if (priv->zbc_depth[i].format != format)
+				continue;
+			if (priv->zbc_depth[i].ds != ds)
+				continue;
+			if (priv->zbc_depth[i].l2 != l2) {
+				WARN_ON(1);
+				return -EINVAL;
+			}
+			return i;
+		} else {
+			zbc = (zbc < 0) ? i : zbc;
+		}
+	}
+
+	if (zbc < 0)
+		return zbc;
+
+	priv->zbc_depth[zbc].format = format;
+	priv->zbc_depth[zbc].ds = ds;
+	priv->zbc_depth[zbc].l2 = l2;
+	ltc->zbc_depth_get(ltc, zbc, l2);
+	gf100_gr_zbc_clear_depth(priv, zbc);
+	return zbc;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
+{
+	struct gf100_gr_priv *priv = (void *)object->engine;
+	union {
+		struct fermi_a_zbc_color_v0 v0;
+	} *args = data;
+	int ret;
+
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		switch (args->v0.format) {
+		case FERMI_A_ZBC_COLOR_V0_FMT_ZERO:
+		case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE:
+		case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32:
+		case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16:
+		case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16:
+		case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16:
+		case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16:
+		case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10:
+		case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8:
+		case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10:
+		case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11:
+			ret = gf100_gr_zbc_color_get(priv, args->v0.format,
+							   args->v0.ds,
+							   args->v0.l2);
+			if (ret >= 0) {
+				args->v0.index = ret;
+				return 0;
+			}
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+static int
+gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
+{
+	struct gf100_gr_priv *priv = (void *)object->engine;
+	union {
+		struct fermi_a_zbc_depth_v0 v0;
+	} *args = data;
+	int ret;
+
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		switch (args->v0.format) {
+		case FERMI_A_ZBC_DEPTH_V0_FMT_FP32:
+			ret = gf100_gr_zbc_depth_get(priv, args->v0.format,
+							   args->v0.ds,
+							   args->v0.l2);
+			return (ret >= 0) ? 0 : -ENOSPC;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+static int
+gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	switch (mthd) {
+	case FERMI_A_ZBC_COLOR:
+		return gf100_fermi_mthd_zbc_color(object, data, size);
+	case FERMI_A_ZBC_DEPTH:
+		return gf100_fermi_mthd_zbc_depth(object, data, size);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+struct nvkm_ofuncs
+gf100_fermi_ofuncs = {
+	.ctor = _nvkm_object_ctor,
+	.dtor = nvkm_object_destroy,
+	.init = nvkm_object_init,
+	.fini = nvkm_object_fini,
+	.mthd = gf100_fermi_mthd,
+};
+
+static int
+gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd,
+			       void *pdata, u32 size)
+{
+	struct gf100_gr_priv *priv = (void *)nv_engine(object);
+	if (size >= sizeof(u32)) {
+		u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000;
+		nv_wr32(priv, 0x419e44, data);
+		nv_wr32(priv, 0x419e4c, data);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+struct nvkm_omthds
+gf100_gr_9097_omthds[] = {
+	{ 0x1528, 0x1528, gf100_gr_set_shader_exceptions },
+	{}
+};
+
+struct nvkm_omthds
+gf100_gr_90c0_omthds[] = {
+	{ 0x1528, 0x1528, gf100_gr_set_shader_exceptions },
+	{}
+};
+
+struct nvkm_oclass
+gf100_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0x9039, &nvkm_object_ofuncs },
+	{ FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+int
+gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *args, u32 size,
+		      struct nvkm_object **pobject)
+{
+	struct nvkm_vm *vm = nvkm_client(parent)->vm;
+	struct gf100_gr_priv *priv = (void *)engine;
+	struct gf100_gr_data *data = priv->mmio_data;
+	struct gf100_gr_mmio *mmio = priv->mmio_list;
+	struct gf100_gr_chan *chan;
+	int ret, i;
+
+	/* allocate memory for context, and fill with default values */
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL,
+				     priv->size, 0x100,
+				     NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	/* allocate memory for a "mmio list" buffer that's used by the HUB
+	 * fuc to modify some per-context register settings on first load
+	 * of the context.
+	 */
+	ret = nvkm_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0,
+			      &chan->mmio);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
+				 NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
+				 &chan->mmio_vma);
+	if (ret)
+		return ret;
+
+	/* allocate buffers referenced by mmio list */
+	for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
+		ret = nvkm_gpuobj_new(nv_object(chan), NULL, data->size,
+				      data->align, 0, &chan->data[i].mem);
+		if (ret)
+			return ret;
+
+		ret = nvkm_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
+					 &chan->data[i].vma);
+		if (ret)
+			return ret;
+
+		data++;
+	}
+
+	/* finally, fill in the mmio list and point the context at it */
+	for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) {
+		u32 addr = mmio->addr;
+		u32 data = mmio->data;
+
+		if (mmio->buffer >= 0) {
+			u64 info = chan->data[mmio->buffer].vma.offset;
+			data |= info >> mmio->shift;
+		}
+
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
+		mmio++;
+	}
+
+	for (i = 0; i < priv->size; i += 4)
+		nv_wo32(chan, i, priv->data[i / 4]);
+
+	if (!priv->firmware) {
+		nv_wo32(chan, 0x00, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
+	} else {
+		nv_wo32(chan, 0xf4, 0);
+		nv_wo32(chan, 0xf8, 0);
+		nv_wo32(chan, 0x10, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x1c, 1);
+		nv_wo32(chan, 0x20, 0);
+		nv_wo32(chan, 0x28, 0);
+		nv_wo32(chan, 0x2c, 0);
+	}
+
+	return 0;
+}
+
+void
+gf100_gr_context_dtor(struct nvkm_object *object)
+{
+	struct gf100_gr_chan *chan = (void *)object;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
+		nvkm_gpuobj_unmap(&chan->data[i].vma);
+		nvkm_gpuobj_ref(NULL, &chan->data[i].mem);
+	}
+
+	nvkm_gpuobj_unmap(&chan->mmio_vma);
+	nvkm_gpuobj_ref(NULL, &chan->mmio);
+
+	nvkm_gr_context_destroy(&chan->base);
+}
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf100_gr_init_main_0[] = {
+	{ 0x400080,   1, 0x04, 0x003083c2 },
+	{ 0x400088,   1, 0x04, 0x00006fe7 },
+	{ 0x40008c,   1, 0x04, 0x00000000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x013901f7 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_fe_0[] = {
+	{ 0x40415c,   1, 0x04, 0x00000000 },
+	{ 0x404170,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pri_0[] = {
+	{ 0x404488,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_rstr2d_0[] = {
+	{ 0x407808,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pd_0[] = {
+	{ 0x406024,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_scc_0[] = {
+	{ 0x40803c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_prop_0[] = {
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpc_unk_0[] = {
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x80000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_setup_0[] = {
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_crstr_0[] = {
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_setup_1[] = {
+	{ 0x4188c8,   1, 0x04, 0x80000000 },
+	{ 0x4188cc,   1, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_zcull_0[] = {
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpm_0[] = {
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000050 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gcc_0[] = {
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tpccs_0[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pe_0[] = {
+	{ 0x41980c,   3, 0x04, 0x00000000 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_wwdx_0[] = {
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tpccs_1[] = {
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_mpc_0[] = {
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf100_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x06060618 },
+	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_be_0[] = {
+	{ 0x40880c,   1, 0x04, 0x00000000 },
+	{ 0x408910,   9, 0x04, 0x00000000 },
+	{ 0x408950,   1, 0x04, 0x00000000 },
+	{ 0x408954,   1, 0x04, 0x0000ffff },
+	{ 0x408984,   1, 0x04, 0x00000000 },
+	{ 0x408988,   1, 0x04, 0x08040201 },
+	{ 0x40898c,   1, 0x04, 0x80402010 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_fe_1[] = {
+	{ 0x4040f0,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pe_1[] = {
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf100_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf100_gr_init_pd_0 },
+	{ gf100_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf100_gr_init_prop_0 },
+	{ gf100_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf100_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf100_gr_init_gpm_0 },
+	{ gf100_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf100_gr_init_tex_0 },
+	{ gf100_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf100_gr_init_wwdx_0 },
+	{ gf100_gr_init_tpccs_1 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf100_gr_init_sm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{ gf100_gr_init_pe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+gf100_gr_zbc_init(struct gf100_gr_priv *priv)
+{
+	const u32  zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			      0x00000000, 0x00000000, 0x00000000, 0x00000000 };
+	const u32   one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+			      0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
+	const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+			      0x00000000, 0x00000000, 0x00000000, 0x00000000 };
+	const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+			      0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
+	struct nvkm_ltc *ltc = nvkm_ltc(priv);
+	int index;
+
+	if (!priv->zbc_color[0].format) {
+		gf100_gr_zbc_color_get(priv, 1,  & zero[0],   &zero[4]);
+		gf100_gr_zbc_color_get(priv, 2,  &  one[0],    &one[4]);
+		gf100_gr_zbc_color_get(priv, 4,  &f32_0[0],  &f32_0[4]);
+		gf100_gr_zbc_color_get(priv, 4,  &f32_1[0],  &f32_1[4]);
+		gf100_gr_zbc_depth_get(priv, 1, 0x00000000, 0x00000000);
+		gf100_gr_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000);
+	}
+
+	for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
+		gf100_gr_zbc_clear_color(priv, index);
+	for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
+		gf100_gr_zbc_clear_depth(priv, index);
+}
+
+void
+gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+	const struct gf100_gr_pack *pack;
+	const struct gf100_gr_init *init;
+
+	pack_for_each_init(init, pack, p) {
+		u32 next = init->addr + init->count * init->pitch;
+		u32 addr = init->addr;
+		while (addr < next) {
+			nv_wr32(priv, addr, init->data);
+			addr += init->pitch;
+		}
+	}
+}
+
+void
+gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+	const struct gf100_gr_pack *pack;
+	const struct gf100_gr_init *init;
+	u32 data = 0;
+
+	nv_wr32(priv, 0x400208, 0x80000000);
+
+	pack_for_each_init(init, pack, p) {
+		u32 next = init->addr + init->count * init->pitch;
+		u32 addr = init->addr;
+
+		if ((pack == p && init == p->init) || data != init->data) {
+			nv_wr32(priv, 0x400204, init->data);
+			data = init->data;
+		}
+
+		while (addr < next) {
+			nv_wr32(priv, 0x400200, addr);
+			nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
+			addr += init->pitch;
+		}
+	}
+
+	nv_wr32(priv, 0x400208, 0x00000000);
+}
+
+void
+gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+	const struct gf100_gr_pack *pack;
+	const struct gf100_gr_init *init;
+	u32 data = 0;
+
+	pack_for_each_init(init, pack, p) {
+		u32 ctrl = 0x80000000 | pack->type;
+		u32 next = init->addr + init->count * init->pitch;
+		u32 addr = init->addr;
+
+		if ((pack == p && init == p->init) || data != init->data) {
+			nv_wr32(priv, 0x40448c, init->data);
+			data = init->data;
+		}
+
+		while (addr < next) {
+			nv_wr32(priv, 0x404488, ctrl | (addr << 14));
+			addr += init->pitch;
+		}
+	}
+}
+
+u64
+gf100_gr_units(struct nvkm_gr *gr)
+{
+	struct gf100_gr_priv *priv = (void *)gr;
+	u64 cfg;
+
+	cfg  = (u32)priv->gpc_nr;
+	cfg |= (u32)priv->tpc_total << 8;
+	cfg |= (u64)priv->rop_nr << 32;
+
+	return cfg;
+}
+
+static const struct nvkm_enum gk104_sked_error[] = {
+	{ 7, "CONSTANT_BUFFER_SIZE" },
+	{ 9, "LOCAL_MEMORY_SIZE_POS" },
+	{ 10, "LOCAL_MEMORY_SIZE_NEG" },
+	{ 11, "WARP_CSTACK_SIZE" },
+	{ 12, "TOTAL_TEMP_SIZE" },
+	{ 13, "REGISTER_COUNT" },
+	{ 18, "TOTAL_THREADS" },
+	{ 20, "PROGRAM_OFFSET" },
+	{ 21, "SHARED_MEMORY_SIZE" },
+	{ 25, "SHARED_CONFIG_TOO_SMALL" },
+	{ 26, "TOTAL_REGISTER_COUNT" },
+	{}
+};
+
+static const struct nvkm_enum gf100_gpc_rop_error[] = {
+	{ 1, "RT_PITCH_OVERRUN" },
+	{ 4, "RT_WIDTH_OVERRUN" },
+	{ 5, "RT_HEIGHT_OVERRUN" },
+	{ 7, "ZETA_STORAGE_TYPE_MISMATCH" },
+	{ 8, "RT_STORAGE_TYPE_MISMATCH" },
+	{ 10, "RT_LINEAR_MISMATCH" },
+	{}
+};
+
+static void
+gf100_gr_trap_gpc_rop(struct gf100_gr_priv *priv, int gpc)
+{
+	u32 trap[4];
+	int i;
+
+	trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
+	trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
+	trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
+	trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
+
+	nv_error(priv, "GPC%d/PROP trap:", gpc);
+	for (i = 0; i <= 29; ++i) {
+		if (!(trap[0] & (1 << i)))
+			continue;
+		pr_cont(" ");
+		nvkm_enum_print(gf100_gpc_rop_error, i);
+	}
+	pr_cont("\n");
+
+	nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
+		 trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
+		 trap[3] & 0xff);
+	nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+}
+
+static const struct nvkm_enum gf100_mp_warp_error[] = {
+	{ 0x00, "NO_ERROR" },
+	{ 0x01, "STACK_MISMATCH" },
+	{ 0x05, "MISALIGNED_PC" },
+	{ 0x08, "MISALIGNED_GPR" },
+	{ 0x09, "INVALID_OPCODE" },
+	{ 0x0d, "GPR_OUT_OF_BOUNDS" },
+	{ 0x0e, "MEM_OUT_OF_BOUNDS" },
+	{ 0x0f, "UNALIGNED_MEM_ACCESS" },
+	{ 0x11, "INVALID_PARAM" },
+	{}
+};
+
+static const struct nvkm_bitfield gf100_mp_global_error[] = {
+	{ 0x00000004, "MULTIPLE_WARP_ERRORS" },
+	{ 0x00000008, "OUT_OF_STACK_SPACE" },
+	{}
+};
+
+static void
+gf100_gr_trap_mp(struct gf100_gr_priv *priv, int gpc, int tpc)
+{
+	u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
+	u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
+
+	nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
+	nvkm_bitfield_print(gf100_mp_global_error, gerr);
+	if (werr) {
+		pr_cont(" ");
+		nvkm_enum_print(gf100_mp_warp_error, werr & 0xffff);
+	}
+	pr_cont("\n");
+
+	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
+	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
+}
+
+static void
+gf100_gr_trap_tpc(struct gf100_gr_priv *priv, int gpc, int tpc)
+{
+	u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508));
+
+	if (stat & 0x00000001) {
+		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
+		nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
+		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
+		stat &= ~0x00000001;
+	}
+
+	if (stat & 0x00000002) {
+		gf100_gr_trap_mp(priv, gpc, tpc);
+		stat &= ~0x00000002;
+	}
+
+	if (stat & 0x00000004) {
+		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
+		nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
+		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
+		stat &= ~0x00000004;
+	}
+
+	if (stat & 0x00000008) {
+		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
+		nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
+		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
+		stat &= ~0x00000008;
+	}
+
+	if (stat) {
+		nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
+	}
+}
+
+static void
+gf100_gr_trap_gpc(struct gf100_gr_priv *priv, int gpc)
+{
+	u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
+	int tpc;
+
+	if (stat & 0x00000001) {
+		gf100_gr_trap_gpc_rop(priv, gpc);
+		stat &= ~0x00000001;
+	}
+
+	if (stat & 0x00000002) {
+		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
+		nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		stat &= ~0x00000002;
+	}
+
+	if (stat & 0x00000004) {
+		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
+		nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		stat &= ~0x00000004;
+	}
+
+	if (stat & 0x00000008) {
+		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
+		nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		stat &= ~0x00000009;
+	}
+
+	for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+		u32 mask = 0x00010000 << tpc;
+		if (stat & mask) {
+			gf100_gr_trap_tpc(priv, gpc, tpc);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask);
+			stat &= ~mask;
+		}
+	}
+
+	if (stat) {
+		nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
+	}
+}
+
+static void
+gf100_gr_trap_intr(struct gf100_gr_priv *priv)
+{
+	u32 trap = nv_rd32(priv, 0x400108);
+	int rop, gpc, i;
+
+	if (trap & 0x00000001) {
+		u32 stat = nv_rd32(priv, 0x404000);
+		nv_error(priv, "DISPATCH 0x%08x\n", stat);
+		nv_wr32(priv, 0x404000, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000001);
+		trap &= ~0x00000001;
+	}
+
+	if (trap & 0x00000002) {
+		u32 stat = nv_rd32(priv, 0x404600);
+		nv_error(priv, "M2MF 0x%08x\n", stat);
+		nv_wr32(priv, 0x404600, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000002);
+		trap &= ~0x00000002;
+	}
+
+	if (trap & 0x00000008) {
+		u32 stat = nv_rd32(priv, 0x408030);
+		nv_error(priv, "CCACHE 0x%08x\n", stat);
+		nv_wr32(priv, 0x408030, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000008);
+		trap &= ~0x00000008;
+	}
+
+	if (trap & 0x00000010) {
+		u32 stat = nv_rd32(priv, 0x405840);
+		nv_error(priv, "SHADER 0x%08x\n", stat);
+		nv_wr32(priv, 0x405840, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000010);
+		trap &= ~0x00000010;
+	}
+
+	if (trap & 0x00000040) {
+		u32 stat = nv_rd32(priv, 0x40601c);
+		nv_error(priv, "UNK6 0x%08x\n", stat);
+		nv_wr32(priv, 0x40601c, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000040);
+		trap &= ~0x00000040;
+	}
+
+	if (trap & 0x00000080) {
+		u32 stat = nv_rd32(priv, 0x404490);
+		nv_error(priv, "MACRO 0x%08x\n", stat);
+		nv_wr32(priv, 0x404490, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000080);
+		trap &= ~0x00000080;
+	}
+
+	if (trap & 0x00000100) {
+		u32 stat = nv_rd32(priv, 0x407020);
+
+		nv_error(priv, "SKED:");
+		for (i = 0; i <= 29; ++i) {
+			if (!(stat & (1 << i)))
+				continue;
+			pr_cont(" ");
+			nvkm_enum_print(gk104_sked_error, i);
+		}
+		pr_cont("\n");
+
+		if (stat & 0x3fffffff)
+			nv_wr32(priv, 0x407020, 0x40000000);
+		nv_wr32(priv, 0x400108, 0x00000100);
+		trap &= ~0x00000100;
+	}
+
+	if (trap & 0x01000000) {
+		u32 stat = nv_rd32(priv, 0x400118);
+		for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
+			u32 mask = 0x00000001 << gpc;
+			if (stat & mask) {
+				gf100_gr_trap_gpc(priv, gpc);
+				nv_wr32(priv, 0x400118, mask);
+				stat &= ~mask;
+			}
+		}
+		nv_wr32(priv, 0x400108, 0x01000000);
+		trap &= ~0x01000000;
+	}
+
+	if (trap & 0x02000000) {
+		for (rop = 0; rop < priv->rop_nr; rop++) {
+			u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
+			u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
+			nv_error(priv, "ROP%d 0x%08x 0x%08x\n",
+				 rop, statz, statc);
+			nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+			nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		}
+		nv_wr32(priv, 0x400108, 0x02000000);
+		trap &= ~0x02000000;
+	}
+
+	if (trap) {
+		nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap);
+		nv_wr32(priv, 0x400108, trap);
+	}
+}
+
+static void
+gf100_gr_ctxctl_debug_unit(struct gf100_gr_priv *priv, u32 base)
+{
+	nv_error(priv, "%06x - done 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x400));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
+		 nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
+		 nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+}
+
+void
+gf100_gr_ctxctl_debug(struct gf100_gr_priv *priv)
+{
+	u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
+	u32 gpc;
+
+	gf100_gr_ctxctl_debug_unit(priv, 0x409000);
+	for (gpc = 0; gpc < gpcnr; gpc++)
+		gf100_gr_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+}
+
+static void
+gf100_gr_ctxctl_isr(struct gf100_gr_priv *priv)
+{
+	u32 stat = nv_rd32(priv, 0x409c18);
+
+	if (stat & 0x00000001) {
+		u32 code = nv_rd32(priv, 0x409814);
+		if (code == E_BAD_FWMTHD) {
+			u32 class = nv_rd32(priv, 0x409808);
+			u32  addr = nv_rd32(priv, 0x40980c);
+			u32  subc = (addr & 0x00070000) >> 16;
+			u32  mthd = (addr & 0x00003ffc);
+			u32  data = nv_rd32(priv, 0x409810);
+
+			nv_error(priv, "FECS MTHD subc %d class 0x%04x "
+				       "mthd 0x%04x data 0x%08x\n",
+				 subc, class, mthd, data);
+
+			nv_wr32(priv, 0x409c20, 0x00000001);
+			stat &= ~0x00000001;
+		} else {
+			nv_error(priv, "FECS ucode error %d\n", code);
+		}
+	}
+
+	if (stat & 0x00080000) {
+		nv_error(priv, "FECS watchdog timeout\n");
+		gf100_gr_ctxctl_debug(priv);
+		nv_wr32(priv, 0x409c20, 0x00080000);
+		stat &= ~0x00080000;
+	}
+
+	if (stat) {
+		nv_error(priv, "FECS 0x%08x\n", stat);
+		gf100_gr_ctxctl_debug(priv);
+		nv_wr32(priv, 0x409c20, stat);
+	}
+}
+
+static void
+gf100_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct nvkm_handle *handle;
+	struct gf100_gr_priv *priv = (void *)subdev;
+	u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u32 addr = nv_rd32(priv, 0x400704);
+	u32 mthd = (addr & 0x00003ffc);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 code = nv_rd32(priv, 0x400110);
+	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & 0x00000010) {
+		handle = nvkm_handle_get_class(engctx, class);
+		if (!handle || nv_call(handle->object, mthd, data)) {
+			nv_error(priv,
+				 "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+				 chid, inst << 12, nvkm_client_name(engctx),
+				 subc, class, mthd, data);
+		}
+		nvkm_handle_put(handle);
+		nv_wr32(priv, 0x400100, 0x00000010);
+		stat &= ~0x00000010;
+	}
+
+	if (stat & 0x00000020) {
+		nv_error(priv,
+			 "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, inst << 12, nvkm_client_name(engctx), subc,
+			 class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00000020);
+		stat &= ~0x00000020;
+	}
+
+	if (stat & 0x00100000) {
+		nv_error(priv, "DATA_ERROR [");
+		nvkm_enum_print(nv50_data_error_names, code);
+		pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			chid, inst << 12, nvkm_client_name(engctx), subc,
+			class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00100000);
+		stat &= ~0x00100000;
+	}
+
+	if (stat & 0x00200000) {
+		nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12,
+			 nvkm_client_name(engctx));
+		gf100_gr_trap_intr(priv);
+		nv_wr32(priv, 0x400100, 0x00200000);
+		stat &= ~0x00200000;
+	}
+
+	if (stat & 0x00080000) {
+		gf100_gr_ctxctl_isr(priv);
+		nv_wr32(priv, 0x400100, 0x00080000);
+		stat &= ~0x00080000;
+	}
+
+	if (stat) {
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, 0x400100, stat);
+	}
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+	nvkm_engctx_put(engctx);
+}
+
+void
+gf100_gr_init_fw(struct gf100_gr_priv *priv, u32 fuc_base,
+		 struct gf100_gr_fuc *code, struct gf100_gr_fuc *data)
+{
+	int i;
+
+	nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
+	for (i = 0; i < data->size / 4; i++)
+		nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
+
+	nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
+	for (i = 0; i < code->size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, fuc_base + 0x0188, i >> 6);
+		nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
+	}
+
+	/* code must be padded to 0x40 words */
+	for (; i & 0x3f; i++)
+		nv_wr32(priv, fuc_base + 0x0184, 0);
+}
+
+static void
+gf100_gr_init_csdata(struct gf100_gr_priv *priv,
+		     const struct gf100_gr_pack *pack,
+		     u32 falcon, u32 starstar, u32 base)
+{
+	const struct gf100_gr_pack *iter;
+	const struct gf100_gr_init *init;
+	u32 addr = ~0, prev = ~0, xfer = 0;
+	u32 star, temp;
+
+	nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
+	star = nv_rd32(priv, falcon + 0x01c4);
+	temp = nv_rd32(priv, falcon + 0x01c4);
+	if (temp > star)
+		star = temp;
+	nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
+
+	pack_for_each_init(init, iter, pack) {
+		u32 head = init->addr - base;
+		u32 tail = head + init->count * init->pitch;
+		while (head < tail) {
+			if (head != prev + 4 || xfer >= 32) {
+				if (xfer) {
+					u32 data = ((--xfer << 26) | addr);
+					nv_wr32(priv, falcon + 0x01c4, data);
+					star += 4;
+				}
+				addr = head;
+				xfer = 0;
+			}
+			prev = head;
+			xfer = xfer + 1;
+			head = head + init->pitch;
+		}
+	}
+
+	nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr);
+	nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
+	nv_wr32(priv, falcon + 0x01c4, star + 4);
+}
+
+int
+gf100_gr_init_ctxctl(struct gf100_gr_priv *priv)
+{
+	struct gf100_gr_oclass *oclass = (void *)nv_object(priv)->oclass;
+	struct gf100_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	if (priv->firmware) {
+		/* load fuc microcode */
+		nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+		gf100_gr_init_fw(priv, 0x409000, &priv->fuc409c,
+						 &priv->fuc409d);
+		gf100_gr_init_fw(priv, 0x41a000, &priv->fuc41ac,
+						 &priv->fuc41ad);
+		nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+		/* start both of them running */
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x41a10c, 0x00000000);
+		nv_wr32(priv, 0x40910c, 0x00000000);
+		nv_wr32(priv, 0x41a100, 0x00000002);
+		nv_wr32(priv, 0x409100, 0x00000002);
+		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
+			nv_warn(priv, "0x409800 wait failed\n");
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x7fffffff);
+		nv_wr32(priv, 0x409504, 0x00000021);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000010);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x10 timeout\n");
+			return -EBUSY;
+		}
+		priv->size = nv_rd32(priv, 0x409800);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000016);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x16 timeout\n");
+			return -EBUSY;
+		}
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000025);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x25 timeout\n");
+			return -EBUSY;
+		}
+
+		if (nv_device(priv)->chipset >= 0xe0) {
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000030);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x30 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409810, 0xb00095c8);
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000031);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x31 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409810, 0x00080420);
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000032);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x32 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409614, 0x00000070);
+			nv_wr32(priv, 0x409614, 0x00000770);
+			nv_wr32(priv, 0x40802c, 0x00000001);
+		}
+
+		if (priv->data == NULL) {
+			int ret = gf100_grctx_generate(priv);
+			if (ret) {
+				nv_error(priv, "failed to construct context\n");
+				return ret;
+			}
+		}
+
+		return 0;
+	} else
+	if (!oclass->fecs.ucode) {
+		return -ENOSYS;
+	}
+
+	/* load HUB microcode */
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+	nv_wr32(priv, 0x4091c0, 0x01000000);
+	for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
+		nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
+
+	nv_wr32(priv, 0x409180, 0x01000000);
+	for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x409188, i >> 6);
+		nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
+	}
+
+	/* load GPC microcode */
+	nv_wr32(priv, 0x41a1c0, 0x01000000);
+	for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
+		nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
+
+	nv_wr32(priv, 0x41a180, 0x01000000);
+	for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x41a188, i >> 6);
+		nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
+	}
+	nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+	/* load register lists */
+	gf100_gr_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000);
+	gf100_gr_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000);
+	gf100_gr_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800);
+	gf100_gr_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00);
+
+	/* start HUB ucode running, it'll init the GPCs */
+	nv_wr32(priv, 0x40910c, 0x00000000);
+	nv_wr32(priv, 0x409100, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+		nv_error(priv, "HUB_INIT timed out\n");
+		gf100_gr_ctxctl_debug(priv);
+		return -EBUSY;
+	}
+
+	priv->size = nv_rd32(priv, 0x409804);
+	if (priv->data == NULL) {
+		int ret = gf100_grctx_generate(priv);
+		if (ret) {
+			nv_error(priv, "failed to construct context\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+gf100_gr_init(struct nvkm_object *object)
+{
+	struct gf100_gr_oclass *oclass = (void *)object->oclass;
+	struct gf100_gr_priv *priv = (void *)object;
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8] = {};
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc, rop;
+	int ret, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+	gf100_gr_mmio(priv, oclass->mmio);
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+			priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	if (nv_device(priv)->chipset != 0xd7)
+		nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+	else
+		nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nv_wr32(priv, 0x409c24, 0x000f0000);
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x40601c, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+
+	gf100_gr_zbc_init(priv);
+
+	return gf100_gr_init_ctxctl(priv);
+}
+
+static void
+gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc)
+{
+	kfree(fuc->data);
+	fuc->data = NULL;
+}
+
+int
+gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname,
+		 struct gf100_gr_fuc *fuc)
+{
+	struct nvkm_device *device = nv_device(priv);
+	const struct firmware *fw;
+	char f[32];
+	int ret;
+
+	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
+	ret = request_firmware(&fw, f, nv_device_base(device));
+	if (ret) {
+		snprintf(f, sizeof(f), "nouveau/%s", fwname);
+		ret = request_firmware(&fw, f, nv_device_base(device));
+		if (ret) {
+			nv_error(priv, "failed to load %s\n", fwname);
+			return ret;
+		}
+	}
+
+	fuc->size = fw->size;
+	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+	release_firmware(fw);
+	return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+void
+gf100_gr_dtor(struct nvkm_object *object)
+{
+	struct gf100_gr_priv *priv = (void *)object;
+
+	kfree(priv->data);
+
+	gf100_gr_dtor_fw(&priv->fuc409c);
+	gf100_gr_dtor_fw(&priv->fuc409d);
+	gf100_gr_dtor_fw(&priv->fuc41ac);
+	gf100_gr_dtor_fw(&priv->fuc41ad);
+
+	nvkm_gpuobj_ref(NULL, &priv->unk4188b8);
+	nvkm_gpuobj_ref(NULL, &priv->unk4188b4);
+
+	nvkm_gr_destroy(&priv->base);
+}
+
+int
+gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *bclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct gf100_gr_oclass *oclass = (void *)bclass;
+	struct nvkm_device *device = nv_device(parent);
+	struct gf100_gr_priv *priv;
+	bool use_ext_fw, enable;
+	int ret, i, j;
+
+	use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
+				  oclass->fecs.ucode == NULL);
+	enable = use_ext_fw || oclass->fecs.ucode != NULL;
+
+	ret = nvkm_gr_create(parent, engine, bclass, enable, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x08001000;
+	nv_subdev(priv)->intr = gf100_gr_intr;
+
+	priv->base.units = gf100_gr_units;
+
+	if (use_ext_fw) {
+		nv_info(priv, "using external firmware\n");
+		if (gf100_gr_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
+		    gf100_gr_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
+		    gf100_gr_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
+		    gf100_gr_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
+			return -ENODEV;
+		priv->firmware = true;
+	}
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+			      &priv->unk4188b4);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+			      &priv->unk4188b8);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 0x1000; i += 4) {
+		nv_wo32(priv->unk4188b4, i, 0x00000010);
+		nv_wo32(priv->unk4188b8, i, 0x00000010);
+	}
+
+	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
+	for (i = 0; i < priv->gpc_nr; i++) {
+		priv->tpc_nr[i]  = nv_rd32(priv, GPC_UNIT(i, 0x2608));
+		priv->tpc_total += priv->tpc_nr[i];
+		priv->ppc_nr[i]  = oclass->ppc_nr;
+		for (j = 0; j < priv->ppc_nr[i]; j++) {
+			u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4)));
+			priv->ppc_tpc_nr[i][j] = hweight8(mask);
+		}
+	}
+
+	/*XXX: these need figuring out... though it might not even matter */
+	switch (nv_device(priv)->chipset) {
+	case 0xc0:
+		if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
+			priv->magic_not_rop_nr = 0x07;
+		} else
+		if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
+			priv->magic_not_rop_nr = 0x05;
+		} else
+		if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
+			priv->magic_not_rop_nr = 0x06;
+		}
+		break;
+	case 0xc3: /* 450, 4/0/0/0, 2 */
+		priv->magic_not_rop_nr = 0x03;
+		break;
+	case 0xc4: /* 460, 3/4/0/0, 4 */
+		priv->magic_not_rop_nr = 0x01;
+		break;
+	case 0xc1: /* 2/0/0/0, 1 */
+		priv->magic_not_rop_nr = 0x01;
+		break;
+	case 0xc8: /* 4/4/3/4, 5 */
+		priv->magic_not_rop_nr = 0x06;
+		break;
+	case 0xce: /* 4/4/0/0, 4 */
+		priv->magic_not_rop_nr = 0x03;
+		break;
+	case 0xcf: /* 4/0/0/0, 3 */
+		priv->magic_not_rop_nr = 0x03;
+		break;
+	case 0xd7:
+	case 0xd9: /* 1/0/0/0, 1 */
+		priv->magic_not_rop_nr = 0x01;
+		break;
+	}
+
+	nv_engine(priv)->cclass = *oclass->cclass;
+	nv_engine(priv)->sclass =  oclass->sclass;
+	return 0;
+}
+
+#include "fuc/hubgf100.fuc3.h"
+
+struct gf100_gr_ucode
+gf100_gr_fecs_ucode = {
+	.code.data = gf100_grhub_code,
+	.code.size = sizeof(gf100_grhub_code),
+	.data.data = gf100_grhub_data,
+	.data.size = sizeof(gf100_grhub_data),
+};
+
+#include "fuc/gpcgf100.fuc3.h"
+
+struct gf100_gr_ucode
+gf100_gr_gpccs_ucode = {
+	.code.data = gf100_grgpc_code,
+	.code.size = sizeof(gf100_grgpc_code),
+	.data.data = gf100_grgpc_data,
+	.data.size = sizeof(gf100_grgpc_data),
+};
+
+struct nvkm_oclass *
+gf100_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf100_grctx_oclass,
+	.sclass =  gf100_gr_sclass,
+	.mmio = gf100_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
new file mode 100644
index 0000000..aeeca1b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#ifndef __NVC0_GR_H__
+#define __NVC0_GR_H__
+#include <engine/gr.h>
+
+#include <subdev/ltc.h>
+
+#define GPC_MAX 32
+#define TPC_MAX (GPC_MAX * 8)
+
+#define ROP_BCAST(r)      (0x408800 + (r))
+#define ROP_UNIT(u, r)    (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r)      (0x418000 + (r))
+#define GPC_UNIT(t, r)    (0x500000 + (t) * 0x8000 + (r))
+#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
+#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct gf100_gr_data {
+	u32 size;
+	u32 align;
+	u32 access;
+};
+
+struct gf100_gr_mmio {
+	u32 addr;
+	u32 data;
+	u32 shift;
+	int buffer;
+};
+
+struct gf100_gr_fuc {
+	u32 *data;
+	u32  size;
+};
+
+struct gf100_gr_zbc_color {
+	u32 format;
+	u32 ds[4];
+	u32 l2[4];
+};
+
+struct gf100_gr_zbc_depth {
+	u32 format;
+	u32 ds;
+	u32 l2;
+};
+
+struct gf100_gr_priv {
+	struct nvkm_gr base;
+
+	struct gf100_gr_fuc fuc409c;
+	struct gf100_gr_fuc fuc409d;
+	struct gf100_gr_fuc fuc41ac;
+	struct gf100_gr_fuc fuc41ad;
+	bool firmware;
+
+	struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT];
+	struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
+
+	u8 rop_nr;
+	u8 gpc_nr;
+	u8 tpc_nr[GPC_MAX];
+	u8 tpc_total;
+	u8 ppc_nr[GPC_MAX];
+	u8 ppc_tpc_nr[GPC_MAX][4];
+
+	struct nvkm_gpuobj *unk4188b4;
+	struct nvkm_gpuobj *unk4188b8;
+
+	struct gf100_gr_data mmio_data[4];
+	struct gf100_gr_mmio mmio_list[4096/8];
+	u32  size;
+	u32 *data;
+
+	u8 magic_not_rop_nr;
+};
+
+struct gf100_gr_chan {
+	struct nvkm_gr_chan base;
+
+	struct nvkm_gpuobj *mmio;
+	struct nvkm_vma mmio_vma;
+	int mmio_nr;
+	struct {
+		struct nvkm_gpuobj *mem;
+		struct nvkm_vma vma;
+	} data[4];
+};
+
+int  gf100_gr_context_ctor(struct nvkm_object *, struct nvkm_object *,
+			     struct nvkm_oclass *, void *, u32,
+			     struct nvkm_object **);
+void gf100_gr_context_dtor(struct nvkm_object *);
+
+void gf100_gr_ctxctl_debug(struct gf100_gr_priv *);
+
+u64  gf100_gr_units(struct nvkm_gr *);
+int  gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *,
+		     struct nvkm_oclass *, void *data, u32 size,
+		     struct nvkm_object **);
+void gf100_gr_dtor(struct nvkm_object *);
+int  gf100_gr_init(struct nvkm_object *);
+void gf100_gr_zbc_init(struct gf100_gr_priv *);
+
+int  gk104_gr_fini(struct nvkm_object *, bool);
+int  gk104_gr_init(struct nvkm_object *);
+
+int  gk110_gr_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_ofuncs gf100_fermi_ofuncs;
+
+extern struct nvkm_oclass gf100_gr_sclass[];
+extern struct nvkm_omthds gf100_gr_9097_omthds[];
+extern struct nvkm_omthds gf100_gr_90c0_omthds[];
+extern struct nvkm_oclass gf110_gr_sclass[];
+extern struct nvkm_oclass gk110_gr_sclass[];
+
+struct gf100_gr_init {
+	u32 addr;
+	u8  count;
+	u8  pitch;
+	u32 data;
+};
+
+struct gf100_gr_pack {
+	const struct gf100_gr_init *init;
+	u32 type;
+};
+
+#define pack_for_each_init(init, pack, head)                                   \
+	for (pack = head; pack && pack->init; pack++)                          \
+		  for (init = pack->init; init && init->count; init++)
+
+struct gf100_gr_ucode {
+	struct gf100_gr_fuc code;
+	struct gf100_gr_fuc data;
+};
+
+extern struct gf100_gr_ucode gf100_gr_fecs_ucode;
+extern struct gf100_gr_ucode gf100_gr_gpccs_ucode;
+
+extern struct gf100_gr_ucode gk110_gr_fecs_ucode;
+extern struct gf100_gr_ucode gk110_gr_gpccs_ucode;
+
+struct gf100_gr_oclass {
+	struct nvkm_oclass base;
+	struct nvkm_oclass **cclass;
+	struct nvkm_oclass *sclass;
+	const struct gf100_gr_pack *mmio;
+	struct {
+		struct gf100_gr_ucode *ucode;
+	} fecs;
+	struct {
+		struct gf100_gr_ucode *ucode;
+	} gpccs;
+	int ppc_nr;
+};
+
+void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+int  gf100_gr_init_ctxctl(struct gf100_gr_priv *);
+
+/* register init value lists */
+
+extern const struct gf100_gr_init gf100_gr_init_main_0[];
+extern const struct gf100_gr_init gf100_gr_init_fe_0[];
+extern const struct gf100_gr_init gf100_gr_init_pri_0[];
+extern const struct gf100_gr_init gf100_gr_init_rstr2d_0[];
+extern const struct gf100_gr_init gf100_gr_init_pd_0[];
+extern const struct gf100_gr_init gf100_gr_init_ds_0[];
+extern const struct gf100_gr_init gf100_gr_init_scc_0[];
+extern const struct gf100_gr_init gf100_gr_init_prop_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf100_gr_init_setup_0[];
+extern const struct gf100_gr_init gf100_gr_init_crstr_0[];
+extern const struct gf100_gr_init gf100_gr_init_setup_1[];
+extern const struct gf100_gr_init gf100_gr_init_zcull_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpm_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf100_gr_init_gcc_0[];
+extern const struct gf100_gr_init gf100_gr_init_tpccs_0[];
+extern const struct gf100_gr_init gf100_gr_init_tex_0[];
+extern const struct gf100_gr_init gf100_gr_init_pe_0[];
+extern const struct gf100_gr_init gf100_gr_init_l1c_0[];
+extern const struct gf100_gr_init gf100_gr_init_wwdx_0[];
+extern const struct gf100_gr_init gf100_gr_init_tpccs_1[];
+extern const struct gf100_gr_init gf100_gr_init_mpc_0[];
+extern const struct gf100_gr_init gf100_gr_init_be_0[];
+extern const struct gf100_gr_init gf100_gr_init_fe_1[];
+extern const struct gf100_gr_init gf100_gr_init_pe_1[];
+
+extern const struct gf100_gr_init gf104_gr_init_ds_0[];
+extern const struct gf100_gr_init gf104_gr_init_tex_0[];
+extern const struct gf100_gr_init gf104_gr_init_sm_0[];
+
+extern const struct gf100_gr_init gf108_gr_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf108_gr_init_setup_1[];
+
+extern const struct gf100_gr_init gf119_gr_init_pd_0[];
+extern const struct gf100_gr_init gf119_gr_init_ds_0[];
+extern const struct gf100_gr_init gf119_gr_init_prop_0[];
+extern const struct gf100_gr_init gf119_gr_init_gpm_0[];
+extern const struct gf100_gr_init gf119_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf119_gr_init_tex_0[];
+extern const struct gf100_gr_init gf119_gr_init_sm_0[];
+extern const struct gf100_gr_init gf119_gr_init_fe_1[];
+
+extern const struct gf100_gr_init gf117_gr_init_pes_0[];
+extern const struct gf100_gr_init gf117_gr_init_wwdx_0[];
+extern const struct gf100_gr_init gf117_gr_init_cbm_0[];
+
+extern const struct gf100_gr_init gk104_gr_init_main_0[];
+extern const struct gf100_gr_init gk104_gr_init_tpccs_0[];
+extern const struct gf100_gr_init gk104_gr_init_pe_0[];
+extern const struct gf100_gr_init gk104_gr_init_be_0[];
+extern const struct gf100_gr_pack gk104_gr_pack_mmio[];
+
+extern const struct gf100_gr_init gk110_gr_init_fe_0[];
+extern const struct gf100_gr_init gk110_gr_init_ds_0[];
+extern const struct gf100_gr_init gk110_gr_init_sked_0[];
+extern const struct gf100_gr_init gk110_gr_init_cwd_0[];
+extern const struct gf100_gr_init gk110_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gk110_gr_init_tex_0[];
+extern const struct gf100_gr_init gk110_gr_init_sm_0[];
+
+extern const struct gf100_gr_init gk208_gr_init_gpc_unk_0[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
new file mode 100644
index 0000000..20d3b85
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf104_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00002834 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf104_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf104_gr_init_pe_0[] = {
+	{ 0x41980c,   3, 0x04, 0x00000000 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{}
+};
+
+const struct gf100_gr_init
+gf104_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf104_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf100_gr_init_pd_0 },
+	{ gf104_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf100_gr_init_prop_0 },
+	{ gf100_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf100_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf100_gr_init_gpm_0 },
+	{ gf100_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf104_gr_init_tex_0 },
+	{ gf104_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf100_gr_init_wwdx_0 },
+	{ gf100_gr_init_tpccs_1 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf104_gr_init_sm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf104_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf104_grctx_oclass,
+	.sclass = gf100_gr_sclass,
+	.mmio = gf104_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
new file mode 100644
index 0000000..5362c81
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf108_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0x9039, &nvkm_object_ofuncs },
+	{ FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf108_gr_init_gpc_unk_0[] = {
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf108_gr_init_setup_1[] = {
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000003 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf108_gr_init_pe_0[] = {
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419810,   1, 0x04, 0x00000000 },
+	{ 0x419814,   1, 0x04, 0x00000004 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf108_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf100_gr_init_pd_0 },
+	{ gf104_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf100_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf100_gr_init_gpm_0 },
+	{ gf108_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf104_gr_init_tex_0 },
+	{ gf108_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf100_gr_init_wwdx_0 },
+	{ gf100_gr_init_tpccs_1 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf104_gr_init_sm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf108_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc1),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf108_grctx_oclass,
+	.sclass = gf108_gr_sclass,
+	.mmio = gf108_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
new file mode 100644
index 0000000..88beb49
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+gf110_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0x9039, &nvkm_object_ofuncs },
+	{ FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf110_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100f02 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x06060618 },
+	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf110_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf100_gr_init_pd_0 },
+	{ gf100_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf100_gr_init_prop_0 },
+	{ gf100_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf100_gr_init_gpm_0 },
+	{ gf100_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf100_gr_init_tex_0 },
+	{ gf100_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf100_gr_init_wwdx_0 },
+	{ gf100_gr_init_tpccs_1 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf110_gr_init_sm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{ gf100_gr_init_pe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf110_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc8),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf110_grctx_oclass,
+	.sclass = gf110_gr_sclass,
+	.mmio = gf110_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
new file mode 100644
index 0000000..871ac5f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf117_gr_init_pe_0[] = {
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc8 },
+	{ 0x419850,   3, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_pes_0[] = {
+	{ 0x41be04,   1, 0x04, 0x00000000 },
+	{ 0x41be08,   1, 0x04, 0x00000004 },
+	{ 0x41be0c,   1, 0x04, 0x00000000 },
+	{ 0x41be10,   1, 0x04, 0x003b8bc7 },
+	{ 0x41be14,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_wwdx_0[] = {
+	{ 0x41bfd4,   1, 0x04, 0x00800000 },
+	{ 0x41bfdc,   1, 0x04, 0x00000000 },
+	{ 0x41bff8,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_cbm_0[] = {
+	{ 0x41becc,   1, 0x04, 0x00000000 },
+	{ 0x41bee8,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf117_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gf119_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gf119_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf119_gr_init_tex_0 },
+	{ gf117_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf119_gr_init_sm_0 },
+	{ gf117_gr_init_pes_0 },
+	{ gf117_gr_init_wwdx_0 },
+	{ gf117_gr_init_cbm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf119_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+#include "fuc/hubgf117.fuc3.h"
+
+struct gf100_gr_ucode
+gf117_gr_fecs_ucode = {
+	.code.data = gf117_grhub_code,
+	.code.size = sizeof(gf117_grhub_code),
+	.data.data = gf117_grhub_data,
+	.data.size = sizeof(gf117_grhub_data),
+};
+
+#include "fuc/gpcgf117.fuc3.h"
+
+struct gf100_gr_ucode
+gf117_gr_gpccs_ucode = {
+	.code.data = gf117_grgpc_code,
+	.code.size = sizeof(gf117_grgpc_code),
+	.data.data = gf117_grgpc_data,
+	.data.size = sizeof(gf117_grgpc_data),
+};
+
+struct nvkm_oclass *
+gf117_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xd7),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf117_grctx_oclass,
+	.sclass = gf110_gr_sclass,
+	.mmio = gf117_gr_pack_mmio,
+	.fecs.ucode = &gf117_gr_fecs_ucode,
+	.gpccs.ucode = &gf117_gr_gpccs_ucode,
+	.ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
new file mode 100644
index 0000000..e6dd651
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf119_gr_init_pd_0[] = {
+	{ 0x406024,   1, 0x04, 0x00000000 },
+	{ 0x4064f0,   3, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00002834 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_prop_0[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   3, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_gpm_0[] = {
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c64,   2, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418cb4,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   2, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000003 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_pe_0[] = {
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419810,   1, 0x04, 0x00000000 },
+	{ 0x419814,   1, 0x04, 0x00000004 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x0000a918 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_wwdx_0[] = {
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419bf8,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_tpccs_1[] = {
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419d48,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x02001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_fe_1[] = {
+	{ 0x40402c,   1, 0x04, 0x00000000 },
+	{ 0x4040f0,   1, 0x04, 0x00000000 },
+	{ 0x404174,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gf119_gr_pack_mmio[] = {
+	{ gf100_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gf119_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gf119_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gf100_gr_init_tpccs_0 },
+	{ gf119_gr_init_tex_0 },
+	{ gf119_gr_init_pe_0 },
+	{ gf100_gr_init_l1c_0 },
+	{ gf119_gr_init_wwdx_0 },
+	{ gf119_gr_init_tpccs_1 },
+	{ gf100_gr_init_mpc_0 },
+	{ gf119_gr_init_sm_0 },
+	{ gf100_gr_init_be_0 },
+	{ gf119_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf119_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xd9),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gf100_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gf119_grctx_oclass,
+	.sclass = gf110_gr_sclass,
+	.mmio = gf119_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
new file mode 100644
index 0000000..489fdd9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/pmu.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0xa040, &nvkm_object_ofuncs },
+	{ KEPLER_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gk104_gr_init_main_0[] = {
+	{ 0x400080,   1, 0x04, 0x003083c2 },
+	{ 0x400088,   1, 0x04, 0x0001ffe7 },
+	{ 0x40008c,   1, 0x04, 0x00000000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x003901f7 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x0000ff34 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_sked_0[] = {
+	{ 0x407010,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_cwd_0[] = {
+	{ 0x405b50,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   2, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000060 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_tpccs_0[] = {
+	{ 0x419d0c,   1, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_pe_0[] = {
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x419850,   1, 0x04, 0x00000004 },
+	{ 0x419854,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x01000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x28137646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00020232 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00000000 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f74,   1, 0x04, 0x00000555 },
+	{}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_be_0[] = {
+	{ 0x40880c,   1, 0x04, 0x00000000 },
+	{ 0x408850,   1, 0x04, 0x00000004 },
+	{ 0x408910,   9, 0x04, 0x00000000 },
+	{ 0x408950,   1, 0x04, 0x00000000 },
+	{ 0x408954,   1, 0x04, 0x0000ffff },
+	{ 0x408958,   1, 0x04, 0x00000034 },
+	{ 0x408984,   1, 0x04, 0x00000000 },
+	{ 0x408988,   1, 0x04, 0x08040201 },
+	{ 0x40898c,   1, 0x04, 0x80402010 },
+	{}
+};
+
+const struct gf100_gr_pack
+gk104_gr_pack_mmio[] = {
+	{ gk104_gr_init_main_0 },
+	{ gf100_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gk104_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gk104_gr_init_sked_0 },
+	{ gk104_gr_init_cwd_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gk104_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gk104_gr_init_tpccs_0 },
+	{ gf119_gr_init_tex_0 },
+	{ gk104_gr_init_pe_0 },
+	{ gk104_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gk104_gr_init_sm_0 },
+	{ gf117_gr_init_pes_0 },
+	{ gf117_gr_init_wwdx_0 },
+	{ gf117_gr_init_cbm_0 },
+	{ gk104_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+int
+gk104_gr_init(struct nvkm_object *object)
+{
+	struct gf100_gr_oclass *oclass = (void *)object->oclass;
+	struct gf100_gr_priv *priv = (void *)object;
+	struct nvkm_pmu *pmu = nvkm_pmu(priv);
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8] = {};
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc, rop;
+	int ret, i;
+
+	if (pmu)
+		pmu->pgob(pmu, false);
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+	gf100_gr_mmio(priv, oclass->mmio);
+
+	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+	memset(data, 0x00, sizeof(data));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+			priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nv_wr32(priv, 0x409ffc, 0x00000000);
+	nv_wr32(priv, 0x409c14, 0x00003e3e);
+	nv_wr32(priv, 0x409c24, 0x000f0001);
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x407020, 0x40000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+
+	gf100_gr_zbc_init(priv);
+
+	return gf100_gr_init_ctxctl(priv);
+}
+
+#include "fuc/hubgk104.fuc3.h"
+
+static struct gf100_gr_ucode
+gk104_gr_fecs_ucode = {
+	.code.data = gk104_grhub_code,
+	.code.size = sizeof(gk104_grhub_code),
+	.data.data = gk104_grhub_data,
+	.data.size = sizeof(gk104_grhub_data),
+};
+
+#include "fuc/gpcgk104.fuc3.h"
+
+static struct gf100_gr_ucode
+gk104_gr_gpccs_ucode = {
+	.code.data = gk104_grgpc_code,
+	.code.size = sizeof(gk104_grgpc_code),
+	.data.data = gk104_grgpc_data,
+	.data.size = sizeof(gk104_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk104_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xe4),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gk104_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gk104_grctx_oclass,
+	.sclass = gk104_gr_sclass,
+	.mmio = gk104_gr_pack_mmio,
+	.fecs.ucode = &gk104_gr_fecs_ucode,
+	.gpccs.ucode = &gk104_gr_gpccs_ucode,
+	.ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
new file mode 100644
index 0000000..78e03ab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+gk110_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0xa140, &nvkm_object_ofuncs },
+	{ KEPLER_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ KEPLER_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gk110_gr_init_fe_0[] = {
+	{ 0x40415c,   1, 0x04, 0x00000000 },
+	{ 0x404170,   1, 0x04, 0x00000000 },
+	{ 0x4041b4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x0000ff00 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_sked_0[] = {
+	{ 0x407010,   1, 0x04, 0x00000000 },
+	{ 0x407040,   1, 0x04, 0x80440424 },
+	{ 0x407048,   1, 0x04, 0x0000000a },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_cwd_0[] = {
+	{ 0x405b44,   1, 0x04, 0x00000000 },
+	{ 0x405b50,   1, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   2, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000400 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000000 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419aec,   1, 0x04, 0x00000000 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x419aa8,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x01000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x281b3646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00020230 },
+	{ 0x419ccc,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000080 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00000000 },
+	{ 0x419eb4,   1, 0x04, 0x00000000 },
+	{ 0x419ebc,   2, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419ed0,   1, 0x04, 0x00003234 },
+	{ 0x419f74,   1, 0x04, 0x00015555 },
+	{ 0x419f80,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk110_gr_pack_mmio[] = {
+	{ gk104_gr_init_main_0 },
+	{ gk110_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gk110_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gk110_gr_init_sked_0 },
+	{ gk110_gr_init_cwd_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gk110_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gk104_gr_init_tpccs_0 },
+	{ gk110_gr_init_tex_0 },
+	{ gk104_gr_init_pe_0 },
+	{ gk110_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gk110_gr_init_sm_0 },
+	{ gf117_gr_init_pes_0 },
+	{ gf117_gr_init_wwdx_0 },
+	{ gf117_gr_init_cbm_0 },
+	{ gk104_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+int
+gk110_gr_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gf100_gr_priv *priv = (void *)object;
+	static const struct {
+		u32 addr;
+		u32 data;
+	} magic[] = {
+		{ 0x020520, 0xfffffffc },
+		{ 0x020524, 0xfffffffe },
+		{ 0x020524, 0xfffffffc },
+		{ 0x020524, 0xfffffff8 },
+		{ 0x020524, 0xffffffe0 },
+		{ 0x020530, 0xfffffffe },
+		{ 0x02052c, 0xfffffffa },
+		{ 0x02052c, 0xfffffff0 },
+		{ 0x02052c, 0xffffffc0 },
+		{ 0x02052c, 0xffffff00 },
+		{ 0x02052c, 0xfffffc00 },
+		{ 0x02052c, 0xfffcfc00 },
+		{ 0x02052c, 0xfff0fc00 },
+		{ 0x02052c, 0xff80fc00 },
+		{ 0x020528, 0xfffffffe },
+		{ 0x020528, 0xfffffffc },
+	};
+	int i;
+
+	nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+	nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+	for (i = 0; i < ARRAY_SIZE(magic); i++) {
+		nv_wr32(priv, magic[i].addr, magic[i].data);
+		nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+	}
+
+	return nvkm_gr_fini(&priv->base, suspend);
+}
+
+#include "fuc/hubgk110.fuc3.h"
+
+struct gf100_gr_ucode
+gk110_gr_fecs_ucode = {
+	.code.data = gk110_grhub_code,
+	.code.size = sizeof(gk110_grhub_code),
+	.data.data = gk110_grhub_data,
+	.data.size = sizeof(gk110_grhub_data),
+};
+
+#include "fuc/gpcgk110.fuc3.h"
+
+struct gf100_gr_ucode
+gk110_gr_gpccs_ucode = {
+	.code.data = gk110_grgpc_code,
+	.code.size = sizeof(gk110_grgpc_code),
+	.data.data = gk110_grgpc_data,
+	.data.size = sizeof(gk110_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk110_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xf0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gk104_gr_init,
+		.fini = gk110_gr_fini,
+	},
+	.cclass = &gk110_grctx_oclass,
+	.sclass =  gk110_gr_sclass,
+	.mmio = gk110_gr_pack_mmio,
+	.fecs.ucode = &gk110_gr_fecs_ucode,
+	.gpccs.ucode = &gk110_gr_gpccs_ucode,
+	.ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
new file mode 100644
index 0000000..5292c5a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110b_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x09000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x281b3646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00020230 },
+	{ 0x419ccc,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk110b_gr_init_sm_0[] = {
+	{ 0x419e00,   1, 0x04, 0x00000080 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00000000 },
+	{ 0x419eb4,   1, 0x04, 0x00000000 },
+	{ 0x419ebc,   2, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419ed0,   1, 0x04, 0x00002616 },
+	{ 0x419f74,   1, 0x04, 0x00015555 },
+	{ 0x419f80,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk110b_gr_pack_mmio[] = {
+	{ gk104_gr_init_main_0 },
+	{ gk110_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gk110_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gk110_gr_init_sked_0 },
+	{ gk110_gr_init_cwd_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gf108_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gf108_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gk110_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gk104_gr_init_tpccs_0 },
+	{ gk110_gr_init_tex_0 },
+	{ gk104_gr_init_pe_0 },
+	{ gk110b_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gk110b_gr_init_sm_0 },
+	{ gf117_gr_init_pes_0 },
+	{ gf117_gr_init_wwdx_0 },
+	{ gf117_gr_init_cbm_0 },
+	{ gk104_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110b_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xf1),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gk104_gr_init,
+		.fini = gk110_gr_fini,
+	},
+	.cclass = &gk110b_grctx_oclass,
+	.sclass =  gk110_gr_sclass,
+	.mmio = gk110b_gr_pack_mmio,
+	.fecs.ucode = &gk110_gr_fecs_ucode,
+	.gpccs.ucode = &gk110_gr_gpccs_ucode,
+	.ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
new file mode 100644
index 0000000..ae6b853
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk208_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0xa140, &nvkm_object_ofuncs },
+	{ KEPLER_B, &gf100_fermi_ofuncs },
+	{ 0xa1c0, &nvkm_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk208_gr_init_main_0[] = {
+	{ 0x400080,   1, 0x04, 0x003083c2 },
+	{ 0x400088,   1, 0x04, 0x0001bfe7 },
+	{ 0x40008c,   1, 0x04, 0x00000000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x003901f7 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00000000 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   2, 0x04, 0x00000000 },
+	{}
+};
+
+const struct gf100_gr_init
+gk208_gr_init_gpc_unk_0[] = {
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_setup_1[] = {
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000201 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x419aa8,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x01000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x281b3646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00000230 },
+	{ 0x419ccc,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gk208_gr_pack_mmio[] = {
+	{ gk208_gr_init_main_0 },
+	{ gk110_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf119_gr_init_pd_0 },
+	{ gk208_gr_init_ds_0 },
+	{ gf100_gr_init_scc_0 },
+	{ gk110_gr_init_sked_0 },
+	{ gk110_gr_init_cwd_0 },
+	{ gf119_gr_init_prop_0 },
+	{ gk208_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gk208_gr_init_setup_1 },
+	{ gf100_gr_init_zcull_0 },
+	{ gf119_gr_init_gpm_0 },
+	{ gk110_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gk104_gr_init_tpccs_0 },
+	{ gk208_gr_init_tex_0 },
+	{ gk104_gr_init_pe_0 },
+	{ gk208_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gk110_gr_init_sm_0 },
+	{ gf117_gr_init_pes_0 },
+	{ gf117_gr_init_wwdx_0 },
+	{ gf117_gr_init_cbm_0 },
+	{ gk104_gr_init_be_0 },
+	{ gf100_gr_init_fe_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk208_gr_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gf100_gr_priv *priv = (void *)object;
+	static const struct {
+		u32 addr;
+		u32 data;
+	} magic[] = {
+		{ 0x020520, 0xfffffffc },
+		{ 0x020524, 0xfffffffe },
+		{ 0x020524, 0xfffffffc },
+		{ 0x020524, 0xfffffff8 },
+		{ 0x020524, 0xffffffe0 },
+		{ 0x020530, 0xfffffffe },
+		{ 0x02052c, 0xfffffffa },
+		{ 0x02052c, 0xfffffff0 },
+		{ 0x02052c, 0xffffffc0 },
+		{ 0x02052c, 0xffffff00 },
+		{ 0x02052c, 0xfffffc00 },
+		{ 0x02052c, 0xfffcfc00 },
+		{ 0x02052c, 0xfff0fc00 },
+		{ 0x02052c, 0xff80fc00 },
+		{ 0x020528, 0xfffffffe },
+		{ 0x020528, 0xfffffffc },
+	};
+	int i;
+
+	nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+	nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+	for (i = 0; i < ARRAY_SIZE(magic); i++) {
+		nv_wr32(priv, magic[i].addr, magic[i].data);
+		nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+	}
+
+	return nvkm_gr_fini(&priv->base, suspend);
+}
+
+#include "fuc/hubgk208.fuc5.h"
+
+static struct gf100_gr_ucode
+gk208_gr_fecs_ucode = {
+	.code.data = gk208_grhub_code,
+	.code.size = sizeof(gk208_grhub_code),
+	.data.data = gk208_grhub_data,
+	.data.size = sizeof(gk208_grhub_data),
+};
+
+#include "fuc/gpcgk208.fuc5.h"
+
+static struct gf100_gr_ucode
+gk208_gr_gpccs_ucode = {
+	.code.data = gk208_grgpc_code,
+	.code.size = sizeof(gk208_grgpc_code),
+	.data.data = gk208_grgpc_data,
+	.data.size = sizeof(gk208_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk208_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0x08),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gk104_gr_init,
+		.fini = gk208_gr_fini,
+	},
+	.cclass = &gk208_grctx_oclass,
+	.sclass =  gk208_gr_sclass,
+	.mmio = gk208_gr_pack_mmio,
+	.fecs.ucode = &gk208_gr_fecs_ucode,
+	.gpccs.ucode = &gk208_gr_gpccs_ucode,
+	.ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
new file mode 100644
index 0000000..2137555
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+static struct nvkm_oclass
+gk20a_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0xa040, &nvkm_object_ofuncs },
+	{ KEPLER_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+struct nvkm_oclass *
+gk20a_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gk104_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gk20a_grctx_oclass,
+	.sclass = gk20a_gr_sclass,
+	.mmio = gk104_gr_pack_mmio,
+	.ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
new file mode 100644
index 0000000..124492b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/P0260.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm107_gr_sclass[] = {
+	{ 0x902d, &nvkm_object_ofuncs },
+	{ 0xa140, &nvkm_object_ofuncs },
+	{ MAXWELL_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+	{ MAXWELL_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm107_gr_init_main_0[] = {
+	{ 0x400080,   1, 0x04, 0x003003c2 },
+	{ 0x400088,   1, 0x04, 0x0001bfe7 },
+	{ 0x40008c,   1, 0x04, 0x00060000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x003901f3 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_ds_0[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00000000 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_scc_0[] = {
+	{ 0x40803c,   1, 0x04, 0x00000010 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sked_0[] = {
+	{ 0x407010,   1, 0x04, 0x00000000 },
+	{ 0x407040,   1, 0x04, 0x40440424 },
+	{ 0x407048,   1, 0x04, 0x0000000a },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_prop_0[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_setup_1[] = {
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00010201 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_zcull_0[] = {
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418930,   2, 0x04, 0x00000000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_gpc_unk_1[] = {
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000400 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_tpccs_0[] = {
+	{ 0x419dc4,   1, 0x04, 0x00000000 },
+	{ 0x419dc8,   1, 0x04, 0x00000501 },
+	{ 0x419dd0,   1, 0x04, 0x00000000 },
+	{ 0x419dd4,   1, 0x04, 0x00000100 },
+	{ 0x419dd8,   1, 0x04, 0x00000001 },
+	{ 0x419ddc,   1, 0x04, 0x00000002 },
+	{ 0x419de0,   1, 0x04, 0x00000001 },
+	{ 0x419d0c,   1, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_tex_0[] = {
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   1, 0x04, 0x00000000 },
+	{ 0x419acc,   1, 0x04, 0x000000ff },
+	{ 0x419ac0,   1, 0x04, 0x00000000 },
+	{ 0x419aa8,   2, 0x04, 0x00000000 },
+	{ 0x419ad0,   2, 0x04, 0x00000000 },
+	{ 0x419ae0,   2, 0x04, 0x00000000 },
+	{ 0x419af0,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_pe_0[] = {
+	{ 0x419900,   1, 0x04, 0x000000ff },
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x419838,   1, 0x04, 0x000000ff },
+	{ 0x419850,   1, 0x04, 0x00000004 },
+	{ 0x419854,   2, 0x04, 0x00000000 },
+	{ 0x419894,   3, 0x04, 0x00100401 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_l1c_0[] = {
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sm_0[] = {
+	{ 0x419e30,   1, 0x04, 0x000000ff },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x01000000 },
+	{ 0x419ee8,   1, 0x04, 0x00000091 },
+	{ 0x419eb4,   1, 0x04, 0x00000000 },
+	{ 0x419ebc,   2, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x000c1810 },
+	{ 0x419ed8,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00000000 },
+	{ 0x419f74,   1, 0x04, 0x00005155 },
+	{ 0x419f80,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_l1c_1[] = {
+	{ 0x419ccc,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x3f006022 },
+	{ 0x419c88,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_pes_0[] = {
+	{ 0x41be50,   1, 0x04, 0x000000ff },
+	{ 0x41be04,   1, 0x04, 0x00000000 },
+	{ 0x41be08,   1, 0x04, 0x00000004 },
+	{ 0x41be0c,   1, 0x04, 0x00000008 },
+	{ 0x41be10,   1, 0x04, 0x0e3b8bc7 },
+	{ 0x41be14,   2, 0x04, 0x00000000 },
+	{ 0x41be3c,   5, 0x04, 0x00100401 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_wwdx_0[] = {
+	{ 0x41bfd4,   1, 0x04, 0x00800000 },
+	{ 0x41bfdc,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_cbm_0[] = {
+	{ 0x41becc,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_be_0[] = {
+	{ 0x408890,   1, 0x04, 0x000000ff },
+	{ 0x40880c,   1, 0x04, 0x00000000 },
+	{ 0x408850,   1, 0x04, 0x00000004 },
+	{ 0x408878,   1, 0x04, 0x00c81603 },
+	{ 0x40887c,   1, 0x04, 0x80543432 },
+	{ 0x408880,   1, 0x04, 0x0010581e },
+	{ 0x408884,   1, 0x04, 0x00001205 },
+	{ 0x408974,   1, 0x04, 0x000000ff },
+	{ 0x408910,   9, 0x04, 0x00000000 },
+	{ 0x408950,   1, 0x04, 0x00000000 },
+	{ 0x408954,   1, 0x04, 0x0000ffff },
+	{ 0x408958,   1, 0x04, 0x00000034 },
+	{ 0x40895c,   1, 0x04, 0x8531a003 },
+	{ 0x408960,   1, 0x04, 0x0561985a },
+	{ 0x408964,   1, 0x04, 0x04e15c4f },
+	{ 0x408968,   1, 0x04, 0x02808833 },
+	{ 0x40896c,   1, 0x04, 0x01f02438 },
+	{ 0x408970,   1, 0x04, 0x00012c00 },
+	{ 0x408984,   1, 0x04, 0x00000000 },
+	{ 0x408988,   1, 0x04, 0x08040201 },
+	{ 0x40898c,   1, 0x04, 0x80402010 },
+	{}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sm_1[] = {
+	{ 0x419e5c,   1, 0x04, 0x00000000 },
+	{ 0x419e58,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static const struct gf100_gr_pack
+gm107_gr_pack_mmio[] = {
+	{ gm107_gr_init_main_0 },
+	{ gk110_gr_init_fe_0 },
+	{ gf100_gr_init_pri_0 },
+	{ gf100_gr_init_rstr2d_0 },
+	{ gf100_gr_init_pd_0 },
+	{ gm107_gr_init_ds_0 },
+	{ gm107_gr_init_scc_0 },
+	{ gm107_gr_init_sked_0 },
+	{ gk110_gr_init_cwd_0 },
+	{ gm107_gr_init_prop_0 },
+	{ gk208_gr_init_gpc_unk_0 },
+	{ gf100_gr_init_setup_0 },
+	{ gf100_gr_init_crstr_0 },
+	{ gm107_gr_init_setup_1 },
+	{ gm107_gr_init_zcull_0 },
+	{ gf100_gr_init_gpm_0 },
+	{ gm107_gr_init_gpc_unk_1 },
+	{ gf100_gr_init_gcc_0 },
+	{ gm107_gr_init_tpccs_0 },
+	{ gm107_gr_init_tex_0 },
+	{ gm107_gr_init_pe_0 },
+	{ gm107_gr_init_l1c_0 },
+	{ gf100_gr_init_mpc_0 },
+	{ gm107_gr_init_sm_0 },
+	{ gm107_gr_init_l1c_1 },
+	{ gm107_gr_init_pes_0 },
+	{ gm107_gr_init_wwdx_0 },
+	{ gm107_gr_init_cbm_0 },
+	{ gm107_gr_init_be_0 },
+	{ gm107_gr_init_sm_1 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+gm107_gr_init_bios(struct gf100_gr_priv *priv)
+{
+	static const struct {
+		u32 ctrl;
+		u32 data;
+	} regs[] = {
+		{ 0x419ed8, 0x419ee0 },
+		{ 0x419ad0, 0x419ad4 },
+		{ 0x419ae0, 0x419ae4 },
+		{ 0x419af0, 0x419af4 },
+		{ 0x419af8, 0x419afc },
+	};
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_P0260E infoE;
+	struct nvbios_P0260X infoX;
+	int E = -1, X;
+	u8 ver, hdr;
+
+	while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) {
+		if (X = -1, E < ARRAY_SIZE(regs)) {
+			nv_wr32(priv, regs[E].ctrl, infoE.data);
+			while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX))
+				nv_wr32(priv, regs[E].data, infoX.data);
+		}
+	}
+}
+
+int
+gm107_gr_init(struct nvkm_object *object)
+{
+	struct gf100_gr_oclass *oclass = (void *)object->oclass;
+	struct gf100_gr_priv *priv = (void *)object;
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8] = {};
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc, ppc, rop;
+	int ret, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+	gf100_gr_mmio(priv, oclass->mmio);
+
+	gm107_gr_init_bios(priv);
+
+	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+	memset(data, 0x00, sizeof(data));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+			priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+	nv_wr32(priv, 0x400124, 0x00000002);
+	nv_wr32(priv, 0x409c24, 0x000e0000);
+
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x407020, 0x40000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++)
+			nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+
+	nv_wr32(priv, 0x400054, 0x2c350f63);
+
+	gf100_gr_zbc_init(priv);
+
+	return gf100_gr_init_ctxctl(priv);
+}
+
+#include "fuc/hubgm107.fuc5.h"
+
+static struct gf100_gr_ucode
+gm107_gr_fecs_ucode = {
+	.code.data = gm107_grhub_code,
+	.code.size = sizeof(gm107_grhub_code),
+	.data.data = gm107_grhub_data,
+	.data.size = sizeof(gm107_grhub_data),
+};
+
+#include "fuc/gpcgm107.fuc5.h"
+
+static struct gf100_gr_ucode
+gm107_gr_gpccs_ucode = {
+	.code.data = gm107_grgpc_code,
+	.code.size = sizeof(gm107_grgpc_code),
+	.data.data = gm107_grgpc_data,
+	.data.size = sizeof(gm107_grgpc_data),
+};
+
+struct nvkm_oclass *
+gm107_gr_oclass = &(struct gf100_gr_oclass) {
+	.base.handle = NV_ENGINE(GR, 0x07),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_gr_ctor,
+		.dtor = gf100_gr_dtor,
+		.init = gm107_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+	.cclass = &gm107_grctx_oclass,
+	.sclass =  gm107_gr_sclass,
+	.mmio = gm107_gr_pack_mmio,
+	.fecs.ucode = 0 ? &gm107_gr_fecs_ucode : NULL,
+	.gpccs.ucode = &gm107_gr_gpccs_ucode,
+	.ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
new file mode 100644
index 0000000..2614510
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
@@ -0,0 +1,1382 @@
+/*
+ * Copyright 2007 Stephane Marchesin
+ * All Rights Reserved.
+ *
+ * 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
+ * paragr) 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
+ * PRECISION INSIGHT 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.
+ */
+#include <engine/gr.h>
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/instmem.h>
+#include <subdev/timer.h>
+
+static u32
+nv04_gr_ctx_regs[] = {
+	0x0040053c,
+	0x00400544,
+	0x00400540,
+	0x00400548,
+	NV04_PGRAPH_CTX_SWITCH1,
+	NV04_PGRAPH_CTX_SWITCH2,
+	NV04_PGRAPH_CTX_SWITCH3,
+	NV04_PGRAPH_CTX_SWITCH4,
+	NV04_PGRAPH_CTX_CACHE1,
+	NV04_PGRAPH_CTX_CACHE2,
+	NV04_PGRAPH_CTX_CACHE3,
+	NV04_PGRAPH_CTX_CACHE4,
+	0x00400184,
+	0x004001a4,
+	0x004001c4,
+	0x004001e4,
+	0x00400188,
+	0x004001a8,
+	0x004001c8,
+	0x004001e8,
+	0x0040018c,
+	0x004001ac,
+	0x004001cc,
+	0x004001ec,
+	0x00400190,
+	0x004001b0,
+	0x004001d0,
+	0x004001f0,
+	0x00400194,
+	0x004001b4,
+	0x004001d4,
+	0x004001f4,
+	0x00400198,
+	0x004001b8,
+	0x004001d8,
+	0x004001f8,
+	0x0040019c,
+	0x004001bc,
+	0x004001dc,
+	0x004001fc,
+	0x00400174,
+	NV04_PGRAPH_DMA_START_0,
+	NV04_PGRAPH_DMA_START_1,
+	NV04_PGRAPH_DMA_LENGTH,
+	NV04_PGRAPH_DMA_MISC,
+	NV04_PGRAPH_DMA_PITCH,
+	NV04_PGRAPH_BOFFSET0,
+	NV04_PGRAPH_BBASE0,
+	NV04_PGRAPH_BLIMIT0,
+	NV04_PGRAPH_BOFFSET1,
+	NV04_PGRAPH_BBASE1,
+	NV04_PGRAPH_BLIMIT1,
+	NV04_PGRAPH_BOFFSET2,
+	NV04_PGRAPH_BBASE2,
+	NV04_PGRAPH_BLIMIT2,
+	NV04_PGRAPH_BOFFSET3,
+	NV04_PGRAPH_BBASE3,
+	NV04_PGRAPH_BLIMIT3,
+	NV04_PGRAPH_BOFFSET4,
+	NV04_PGRAPH_BBASE4,
+	NV04_PGRAPH_BLIMIT4,
+	NV04_PGRAPH_BOFFSET5,
+	NV04_PGRAPH_BBASE5,
+	NV04_PGRAPH_BLIMIT5,
+	NV04_PGRAPH_BPITCH0,
+	NV04_PGRAPH_BPITCH1,
+	NV04_PGRAPH_BPITCH2,
+	NV04_PGRAPH_BPITCH3,
+	NV04_PGRAPH_BPITCH4,
+	NV04_PGRAPH_SURFACE,
+	NV04_PGRAPH_STATE,
+	NV04_PGRAPH_BSWIZZLE2,
+	NV04_PGRAPH_BSWIZZLE5,
+	NV04_PGRAPH_BPIXEL,
+	NV04_PGRAPH_NOTIFY,
+	NV04_PGRAPH_PATT_COLOR0,
+	NV04_PGRAPH_PATT_COLOR1,
+	NV04_PGRAPH_PATT_COLORRAM+0x00,
+	NV04_PGRAPH_PATT_COLORRAM+0x04,
+	NV04_PGRAPH_PATT_COLORRAM+0x08,
+	NV04_PGRAPH_PATT_COLORRAM+0x0c,
+	NV04_PGRAPH_PATT_COLORRAM+0x10,
+	NV04_PGRAPH_PATT_COLORRAM+0x14,
+	NV04_PGRAPH_PATT_COLORRAM+0x18,
+	NV04_PGRAPH_PATT_COLORRAM+0x1c,
+	NV04_PGRAPH_PATT_COLORRAM+0x20,
+	NV04_PGRAPH_PATT_COLORRAM+0x24,
+	NV04_PGRAPH_PATT_COLORRAM+0x28,
+	NV04_PGRAPH_PATT_COLORRAM+0x2c,
+	NV04_PGRAPH_PATT_COLORRAM+0x30,
+	NV04_PGRAPH_PATT_COLORRAM+0x34,
+	NV04_PGRAPH_PATT_COLORRAM+0x38,
+	NV04_PGRAPH_PATT_COLORRAM+0x3c,
+	NV04_PGRAPH_PATT_COLORRAM+0x40,
+	NV04_PGRAPH_PATT_COLORRAM+0x44,
+	NV04_PGRAPH_PATT_COLORRAM+0x48,
+	NV04_PGRAPH_PATT_COLORRAM+0x4c,
+	NV04_PGRAPH_PATT_COLORRAM+0x50,
+	NV04_PGRAPH_PATT_COLORRAM+0x54,
+	NV04_PGRAPH_PATT_COLORRAM+0x58,
+	NV04_PGRAPH_PATT_COLORRAM+0x5c,
+	NV04_PGRAPH_PATT_COLORRAM+0x60,
+	NV04_PGRAPH_PATT_COLORRAM+0x64,
+	NV04_PGRAPH_PATT_COLORRAM+0x68,
+	NV04_PGRAPH_PATT_COLORRAM+0x6c,
+	NV04_PGRAPH_PATT_COLORRAM+0x70,
+	NV04_PGRAPH_PATT_COLORRAM+0x74,
+	NV04_PGRAPH_PATT_COLORRAM+0x78,
+	NV04_PGRAPH_PATT_COLORRAM+0x7c,
+	NV04_PGRAPH_PATT_COLORRAM+0x80,
+	NV04_PGRAPH_PATT_COLORRAM+0x84,
+	NV04_PGRAPH_PATT_COLORRAM+0x88,
+	NV04_PGRAPH_PATT_COLORRAM+0x8c,
+	NV04_PGRAPH_PATT_COLORRAM+0x90,
+	NV04_PGRAPH_PATT_COLORRAM+0x94,
+	NV04_PGRAPH_PATT_COLORRAM+0x98,
+	NV04_PGRAPH_PATT_COLORRAM+0x9c,
+	NV04_PGRAPH_PATT_COLORRAM+0xa0,
+	NV04_PGRAPH_PATT_COLORRAM+0xa4,
+	NV04_PGRAPH_PATT_COLORRAM+0xa8,
+	NV04_PGRAPH_PATT_COLORRAM+0xac,
+	NV04_PGRAPH_PATT_COLORRAM+0xb0,
+	NV04_PGRAPH_PATT_COLORRAM+0xb4,
+	NV04_PGRAPH_PATT_COLORRAM+0xb8,
+	NV04_PGRAPH_PATT_COLORRAM+0xbc,
+	NV04_PGRAPH_PATT_COLORRAM+0xc0,
+	NV04_PGRAPH_PATT_COLORRAM+0xc4,
+	NV04_PGRAPH_PATT_COLORRAM+0xc8,
+	NV04_PGRAPH_PATT_COLORRAM+0xcc,
+	NV04_PGRAPH_PATT_COLORRAM+0xd0,
+	NV04_PGRAPH_PATT_COLORRAM+0xd4,
+	NV04_PGRAPH_PATT_COLORRAM+0xd8,
+	NV04_PGRAPH_PATT_COLORRAM+0xdc,
+	NV04_PGRAPH_PATT_COLORRAM+0xe0,
+	NV04_PGRAPH_PATT_COLORRAM+0xe4,
+	NV04_PGRAPH_PATT_COLORRAM+0xe8,
+	NV04_PGRAPH_PATT_COLORRAM+0xec,
+	NV04_PGRAPH_PATT_COLORRAM+0xf0,
+	NV04_PGRAPH_PATT_COLORRAM+0xf4,
+	NV04_PGRAPH_PATT_COLORRAM+0xf8,
+	NV04_PGRAPH_PATT_COLORRAM+0xfc,
+	NV04_PGRAPH_PATTERN,
+	0x0040080c,
+	NV04_PGRAPH_PATTERN_SHAPE,
+	0x00400600,
+	NV04_PGRAPH_ROP3,
+	NV04_PGRAPH_CHROMA,
+	NV04_PGRAPH_BETA_AND,
+	NV04_PGRAPH_BETA_PREMULT,
+	NV04_PGRAPH_CONTROL0,
+	NV04_PGRAPH_CONTROL1,
+	NV04_PGRAPH_CONTROL2,
+	NV04_PGRAPH_BLEND,
+	NV04_PGRAPH_STORED_FMT,
+	NV04_PGRAPH_SOURCE_COLOR,
+	0x00400560,
+	0x00400568,
+	0x00400564,
+	0x0040056c,
+	0x00400400,
+	0x00400480,
+	0x00400404,
+	0x00400484,
+	0x00400408,
+	0x00400488,
+	0x0040040c,
+	0x0040048c,
+	0x00400410,
+	0x00400490,
+	0x00400414,
+	0x00400494,
+	0x00400418,
+	0x00400498,
+	0x0040041c,
+	0x0040049c,
+	0x00400420,
+	0x004004a0,
+	0x00400424,
+	0x004004a4,
+	0x00400428,
+	0x004004a8,
+	0x0040042c,
+	0x004004ac,
+	0x00400430,
+	0x004004b0,
+	0x00400434,
+	0x004004b4,
+	0x00400438,
+	0x004004b8,
+	0x0040043c,
+	0x004004bc,
+	0x00400440,
+	0x004004c0,
+	0x00400444,
+	0x004004c4,
+	0x00400448,
+	0x004004c8,
+	0x0040044c,
+	0x004004cc,
+	0x00400450,
+	0x004004d0,
+	0x00400454,
+	0x004004d4,
+	0x00400458,
+	0x004004d8,
+	0x0040045c,
+	0x004004dc,
+	0x00400460,
+	0x004004e0,
+	0x00400464,
+	0x004004e4,
+	0x00400468,
+	0x004004e8,
+	0x0040046c,
+	0x004004ec,
+	0x00400470,
+	0x004004f0,
+	0x00400474,
+	0x004004f4,
+	0x00400478,
+	0x004004f8,
+	0x0040047c,
+	0x004004fc,
+	0x00400534,
+	0x00400538,
+	0x00400514,
+	0x00400518,
+	0x0040051c,
+	0x00400520,
+	0x00400524,
+	0x00400528,
+	0x0040052c,
+	0x00400530,
+	0x00400d00,
+	0x00400d40,
+	0x00400d80,
+	0x00400d04,
+	0x00400d44,
+	0x00400d84,
+	0x00400d08,
+	0x00400d48,
+	0x00400d88,
+	0x00400d0c,
+	0x00400d4c,
+	0x00400d8c,
+	0x00400d10,
+	0x00400d50,
+	0x00400d90,
+	0x00400d14,
+	0x00400d54,
+	0x00400d94,
+	0x00400d18,
+	0x00400d58,
+	0x00400d98,
+	0x00400d1c,
+	0x00400d5c,
+	0x00400d9c,
+	0x00400d20,
+	0x00400d60,
+	0x00400da0,
+	0x00400d24,
+	0x00400d64,
+	0x00400da4,
+	0x00400d28,
+	0x00400d68,
+	0x00400da8,
+	0x00400d2c,
+	0x00400d6c,
+	0x00400dac,
+	0x00400d30,
+	0x00400d70,
+	0x00400db0,
+	0x00400d34,
+	0x00400d74,
+	0x00400db4,
+	0x00400d38,
+	0x00400d78,
+	0x00400db8,
+	0x00400d3c,
+	0x00400d7c,
+	0x00400dbc,
+	0x00400590,
+	0x00400594,
+	0x00400598,
+	0x0040059c,
+	0x004005a8,
+	0x004005ac,
+	0x004005b0,
+	0x004005b4,
+	0x004005c0,
+	0x004005c4,
+	0x004005c8,
+	0x004005cc,
+	0x004005d0,
+	0x004005d4,
+	0x004005d8,
+	0x004005dc,
+	0x004005e0,
+	NV04_PGRAPH_PASSTHRU_0,
+	NV04_PGRAPH_PASSTHRU_1,
+	NV04_PGRAPH_PASSTHRU_2,
+	NV04_PGRAPH_DVD_COLORFMT,
+	NV04_PGRAPH_SCALED_FORMAT,
+	NV04_PGRAPH_MISC24_0,
+	NV04_PGRAPH_MISC24_1,
+	NV04_PGRAPH_MISC24_2,
+	0x00400500,
+	0x00400504,
+	NV04_PGRAPH_VALID1,
+	NV04_PGRAPH_VALID2,
+	NV04_PGRAPH_DEBUG_3
+};
+
+struct nv04_gr_priv {
+	struct nvkm_gr base;
+	struct nv04_gr_chan *chan[16];
+	spinlock_t lock;
+};
+
+struct nv04_gr_chan {
+	struct nvkm_object base;
+	int chid;
+	u32 nv04[ARRAY_SIZE(nv04_gr_ctx_regs)];
+};
+
+
+static inline struct nv04_gr_priv *
+nv04_gr_priv(struct nv04_gr_chan *chan)
+{
+	return (void *)nv_object(chan)->engine;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+/*
+ * Software methods, why they are needed, and how they all work:
+ *
+ * NV04 and NV05 keep most of the state in PGRAPH context itself, but some
+ * 2d engine settings are kept inside the grobjs themselves. The grobjs are
+ * 3 words long on both. grobj format on NV04 is:
+ *
+ * word 0:
+ *  - bits 0-7: class
+ *  - bit 12: color key active
+ *  - bit 13: clip rect active
+ *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
+ *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
+ *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
+ *            NV03_CONTEXT_SURFACE_DST].
+ *  - bits 15-17: 2d operation [aka patch config]
+ *  - bit 24: patch valid [enables rendering using this object]
+ *  - bit 25: surf3d valid [for tex_tri and multitex_tri only]
+ * word 1:
+ *  - bits 0-1: mono format
+ *  - bits 8-13: color format
+ *  - bits 16-31: DMA_NOTIFY instance
+ * word 2:
+ *  - bits 0-15: DMA_A instance
+ *  - bits 16-31: DMA_B instance
+ *
+ * On NV05 it's:
+ *
+ * word 0:
+ *  - bits 0-7: class
+ *  - bit 12: color key active
+ *  - bit 13: clip rect active
+ *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
+ *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
+ *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
+ *            NV03_CONTEXT_SURFACE_DST].
+ *  - bits 15-17: 2d operation [aka patch config]
+ *  - bits 20-22: dither mode
+ *  - bit 24: patch valid [enables rendering using this object]
+ *  - bit 25: surface_dst/surface_color/surf2d/surf3d valid
+ *  - bit 26: surface_src/surface_zeta valid
+ *  - bit 27: pattern valid
+ *  - bit 28: rop valid
+ *  - bit 29: beta1 valid
+ *  - bit 30: beta4 valid
+ * word 1:
+ *  - bits 0-1: mono format
+ *  - bits 8-13: color format
+ *  - bits 16-31: DMA_NOTIFY instance
+ * word 2:
+ *  - bits 0-15: DMA_A instance
+ *  - bits 16-31: DMA_B instance
+ *
+ * NV05 will set/unset the relevant valid bits when you poke the relevant
+ * object-binding methods with object of the proper type, or with the NULL
+ * type. It'll only allow rendering using the grobj if all needed objects
+ * are bound. The needed set of objects depends on selected operation: for
+ * example rop object is needed by ROP_AND, but not by SRCCOPY_AND.
+ *
+ * NV04 doesn't have these methods implemented at all, and doesn't have the
+ * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24
+ * is set. So we have to emulate them in software, internally keeping the
+ * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04,
+ * but the last word isn't actually used for anything, we abuse it for this
+ * purpose.
+ *
+ * Actually, NV05 can optionally check bit 24 too, but we disable this since
+ * there's no use for it.
+ *
+ * For unknown reasons, NV04 implements surf3d binding in hardware as an
+ * exception. Also for unknown reasons, NV04 doesn't implement the clipping
+ * methods on the surf3d object, so we have to emulate them too.
+ */
+
+static void
+nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value)
+{
+	struct nv04_gr_priv *priv = (void *)object->engine;
+	int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
+	u32 tmp;
+
+	tmp  = nv_ro32(object, 0x00);
+	tmp &= ~mask;
+	tmp |= value;
+	nv_wo32(object, 0x00, tmp);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
+}
+
+static void
+nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value)
+{
+	int class, op, valid = 1;
+	u32 tmp, ctx1;
+
+	ctx1 = nv_ro32(object, 0x00);
+	class = ctx1 & 0xff;
+	op = (ctx1 >> 15) & 7;
+
+	tmp = nv_ro32(object, 0x0c);
+	tmp &= ~mask;
+	tmp |= value;
+	nv_wo32(object, 0x0c, tmp);
+
+	/* check for valid surf2d/surf_dst/surf_color */
+	if (!(tmp & 0x02000000))
+		valid = 0;
+	/* check for valid surf_src/surf_zeta */
+	if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
+		valid = 0;
+
+	switch (op) {
+	/* SRCCOPY_AND, SRCCOPY: no extra objects required */
+	case 0:
+	case 3:
+		break;
+	/* ROP_AND: requires pattern and rop */
+	case 1:
+		if (!(tmp & 0x18000000))
+			valid = 0;
+		break;
+	/* BLEND_AND: requires beta1 */
+	case 2:
+		if (!(tmp & 0x20000000))
+			valid = 0;
+		break;
+	/* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
+	case 4:
+	case 5:
+		if (!(tmp & 0x40000000))
+			valid = 0;
+		break;
+	}
+
+	nv04_gr_set_ctx1(object, 0x01000000, valid << 24);
+}
+
+static int
+nv04_gr_mthd_set_operation(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	u32 class = nv_ro32(object, 0) & 0xff;
+	u32 data = *(u32 *)args;
+	if (data > 5)
+		return 1;
+	/* Old versions of the objects only accept first three operations. */
+	if (data > 2 && class < 0x40)
+		return 1;
+	nv04_gr_set_ctx1(object, 0x00038000, data << 15);
+	/* changing operation changes set of objects needed for validation */
+	nv04_gr_set_ctx_val(object, 0, 0);
+	return 0;
+}
+
+static int
+nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	struct nv04_gr_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
+	if (min & 0x8000)
+		/* too large */
+		return 1;
+	if (w & 0x8000)
+		/* yes, it accepts negative for some reason. */
+		w |= 0xffff0000;
+	max = min + w;
+	max &= 0x3ffff;
+	nv_wr32(priv, 0x40053c, min);
+	nv_wr32(priv, 0x400544, max);
+	return 0;
+}
+
+static int
+nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	struct nv04_gr_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
+	if (min & 0x8000)
+		/* too large */
+		return 1;
+	if (w & 0x8000)
+		/* yes, it accepts negative for some reason. */
+		w |= 0xffff0000;
+	max = min + w;
+	max &= 0x3ffff;
+	nv_wr32(priv, 0x400540, min);
+	nv_wr32(priv, 0x400548, max);
+	return 0;
+}
+
+static u16
+nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(object);
+	u32 inst = *(u32 *)args << 4;
+	return nv_ro32(imem, inst);
+}
+
+static int
+nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx1(object, 0x00004000, 0);
+		nv04_gr_set_ctx_val(object, 0x02000000, 0);
+		return 0;
+	case 0x42:
+		nv04_gr_set_ctx1(object, 0x00004000, 0);
+		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd,
+				 void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx1(object, 0x00004000, 0);
+		nv04_gr_set_ctx_val(object, 0x02000000, 0);
+		return 0;
+	case 0x42:
+		nv04_gr_set_ctx1(object, 0x00004000, 0);
+		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+		return 0;
+	case 0x52:
+		nv04_gr_set_ctx1(object, 0x00004000, 0x00004000);
+		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
+		       void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x08000000, 0);
+		return 0;
+	case 0x18:
+		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
+		       void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x08000000, 0);
+		return 0;
+	case 0x44:
+		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd,
+		      void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x10000000, 0);
+		return 0;
+	case 0x43:
+		nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x20000000, 0);
+		return 0;
+	case 0x12:
+		nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x40000000, 0);
+		return 0;
+	case 0x72:
+		nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x02000000, 0);
+		return 0;
+	case 0x58:
+		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x04000000, 0);
+		return 0;
+	case 0x59:
+		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd,
+			     void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x02000000, 0);
+		return 0;
+	case 0x5a:
+		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx_val(object, 0x04000000, 0);
+		return 0;
+	case 0x5b:
+		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd,
+		       void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx1(object, 0x2000, 0);
+		return 0;
+	case 0x19:
+		nv04_gr_set_ctx1(object, 0x2000, 0x2000);
+		return 0;
+	}
+	return 1;
+}
+
+static int
+nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd,
+			 void *args, u32 size)
+{
+	switch (nv04_gr_mthd_bind_class(object, args, size)) {
+	case 0x30:
+		nv04_gr_set_ctx1(object, 0x1000, 0);
+		return 0;
+	/* Yes, for some reason even the old versions of objects
+	 * accept 0x57 and not 0x17. Consistency be damned.
+	 */
+	case 0x57:
+		nv04_gr_set_ctx1(object, 0x1000, 0x1000);
+		return 0;
+	}
+	return 1;
+}
+
+static struct nvkm_omthds
+nv03_gr_gdi_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_patt },
+	{ 0x0188, 0x0188, nv04_gr_mthd_bind_rop },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_gdi_omthds[] = {
+	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv01_gr_blit_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
+	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_blit_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
+	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_iifc_omthds[] = {
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_chroma },
+	{ 0x018c, 0x018c, nv01_gr_mthd_bind_clip },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_patt },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_rop },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 },
+	{ 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 },
+	{ 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf },
+	{ 0x03e4, 0x03e4, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv01_gr_ifc_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_ifc_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
+	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv03_gr_sifc_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_sifc_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv03_gr_sifm_omthds[] = {
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_sifm_omthds[] = {
+	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_surf3d_omthds[] = {
+	{ 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v },
+	{}
+};
+
+static struct nvkm_omthds
+nv03_gr_ttri_omthds[] = {
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta },
+	{}
+};
+
+static struct nvkm_omthds
+nv01_gr_prim_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
+	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static struct nvkm_omthds
+nv04_gr_prim_omthds[] = {
+	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
+	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+	{}
+};
+
+static int
+nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
+#endif
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+struct nvkm_ofuncs
+nv04_gr_ofuncs = {
+	.ctor = nv04_gr_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv04_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+	{ 0x0017, &nv04_gr_ofuncs }, /* chroma */
+	{ 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */
+	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
+	{ 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */
+	{ 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */
+	{ 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */
+	{ 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds },
+	{ 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds },
+	{ 0x0030, &nv04_gr_ofuncs }, /* null */
+	{ 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds },
+	{ 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds },
+	{ 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */
+	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+	{ 0x0042, &nv04_gr_ofuncs }, /* surf2d */
+	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
+	{ 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds },
+	{ 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds },
+	{ 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds },
+	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+	{ 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds },
+	{ 0x0054, &nv04_gr_ofuncs }, /* ttri */
+	{ 0x0055, &nv04_gr_ofuncs }, /* mtri */
+	{ 0x0057, &nv04_gr_ofuncs }, /* chroma */
+	{ 0x0058, &nv04_gr_ofuncs }, /* surf_dst */
+	{ 0x0059, &nv04_gr_ofuncs }, /* surf_src */
+	{ 0x005a, &nv04_gr_ofuncs }, /* surf_color */
+	{ 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */
+	{ 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */
+	{ 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */
+	{ 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */
+	{ 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds },
+	{ 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds },
+	{ 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds },
+	{ 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */
+	{ 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */
+	{ 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */
+	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+	{ 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds },
+	{ 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv04_gr_chan *
+nv04_gr_channel(struct nv04_gr_priv *priv)
+{
+	struct nv04_gr_chan *chan = NULL;
+	if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
+		int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static int
+nv04_gr_load_context(struct nv04_gr_chan *chan, int chid)
+{
+	struct nv04_gr_priv *priv = nv04_gr_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
+		nv_wr32(priv, nv04_gr_ctx_regs[i], chan->nv04[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
+	return 0;
+}
+
+static int
+nv04_gr_unload_context(struct nv04_gr_chan *chan)
+{
+	struct nv04_gr_priv *priv = nv04_gr_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
+		chan->nv04[i] = nv_rd32(priv, nv04_gr_ctx_regs[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+	return 0;
+}
+
+static void
+nv04_gr_context_switch(struct nv04_gr_priv *priv)
+{
+	struct nv04_gr_chan *prev = NULL;
+	struct nv04_gr_chan *next = NULL;
+	unsigned long flags;
+	int chid;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_gr_idle(priv);
+
+	/* If previous context is valid, we need to save it */
+	prev = nv04_gr_channel(priv);
+	if (prev)
+		nv04_gr_unload_context(prev);
+
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
+	next = priv->chan[chid];
+	if (next)
+		nv04_gr_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) {
+		if (nv04_gr_ctx_regs[i] == reg)
+			return &chan->nv04[i];
+	}
+
+	return NULL;
+}
+
+static int
+nv04_gr_context_ctor(struct nvkm_object *parent,
+		     struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nvkm_fifo_chan *fifo = (void *)parent;
+	struct nv04_gr_priv *priv = (void *)engine;
+	struct nv04_gr_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nvkm_object_destroy(&chan->base);
+		return 1;
+	}
+
+	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+static void
+nv04_gr_context_dtor(struct nvkm_object *object)
+{
+	struct nv04_gr_priv *priv = (void *)object->engine;
+	struct nv04_gr_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nvkm_object_destroy(&chan->base);
+}
+
+static int
+nv04_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv04_gr_priv *priv = (void *)object->engine;
+	struct nv04_gr_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv04_gr_channel(priv) == chan)
+		nv04_gr_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nvkm_object_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv04_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_gr_context_ctor,
+		.dtor = nv04_gr_context_dtor,
+		.init = nvkm_object_init,
+		.fini = nv04_gr_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+bool
+nv04_gr_idle(void *obj)
+{
+	struct nvkm_gr *gr = nvkm_gr(obj);
+	u32 mask = 0xffffffff;
+
+	if (nv_device(obj)->card_type == NV_40)
+		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
+
+	if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) {
+		nv_error(gr, "idle timed out with status 0x%08x\n",
+			 nv_rd32(gr, NV04_PGRAPH_STATUS));
+		return false;
+	}
+
+	return true;
+}
+
+static const struct nvkm_bitfield
+nv04_gr_intr_name[] = {
+	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+	{}
+};
+
+static const struct nvkm_bitfield
+nv04_gr_nstatus[] = {
+	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+	{ NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
+	{}
+};
+
+const struct nvkm_bitfield
+nv04_gr_nsource[] = {
+	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
+	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
+	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
+	{ NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
+	{ NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
+	{ NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
+	{ NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
+	{ NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
+	{ NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
+	{ NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
+	{ NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
+	{ NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
+	{ NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
+	{ NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
+	{ NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
+	{ NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
+	{ NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
+	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
+	{}
+};
+
+static void
+nv04_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nv04_gr_priv *priv = (void *)subdev;
+	struct nv04_gr_chan *chan = NULL;
+	struct nvkm_namedb *namedb = NULL;
+	struct nvkm_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x0f000000) >> 24;
+	u32 subc = (addr & 0x0000e000) >> 13;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
+	u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
+	u32 show = stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
+	if (chan)
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (stat & NV_PGRAPH_INTR_NOTIFY) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nvkm_namedb_get_vinst(namedb, inst);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_NOTIFY;
+		}
+	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv04_gr_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "%s", "");
+		nvkm_bitfield_print(nv04_gr_intr_name, show);
+		pr_cont(" nsource:");
+		nvkm_bitfield_print(nv04_gr_nsource, nsource);
+		pr_cont(" nstatus:");
+		nvkm_bitfield_print(nv04_gr_nstatus, nstatus);
+		pr_cont("\n");
+		nv_error(priv,
+			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, nvkm_client_name(chan), subc, class, mthd,
+			 data);
+	}
+
+	nvkm_namedb_put(handle);
+}
+
+static int
+nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv04_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv04_gr_intr;
+	nv_engine(priv)->cclass = &nv04_gr_cclass;
+	nv_engine(priv)->sclass = nv04_gr_sclass;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+static int
+nv04_gr_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nv04_gr_priv *priv = (void *)engine;
+	int ret;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* Enable PGRAPH interrupts */
+	nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
+	nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
+	/*1231C000 blob, 001 haiku*/
+	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
+	/*0x72111100 blob , 01 haiku*/
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
+	/*haiku same*/
+
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
+	/*haiku and blob 10d4*/
+
+	nv_wr32(priv, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+
+	/* These don't belong here, they're part of a per-channel context */
+	nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
+	return 0;
+}
+
+struct nvkm_oclass
+nv04_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_gr_ctor,
+		.dtor = _nvkm_gr_dtor,
+		.init = nv04_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
new file mode 100644
index 0000000..389904e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
@@ -0,0 +1,1315 @@
+/*
+ * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
+ * All Rights Reserved.
+ *
+ * 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
+ * paragr) 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
+ * PRECISION INSIGHT 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.
+ */
+#include <engine/gr.h>
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+
+struct pipe_state {
+	u32 pipe_0x0000[0x040/4];
+	u32 pipe_0x0040[0x010/4];
+	u32 pipe_0x0200[0x0c0/4];
+	u32 pipe_0x4400[0x080/4];
+	u32 pipe_0x6400[0x3b0/4];
+	u32 pipe_0x6800[0x2f0/4];
+	u32 pipe_0x6c00[0x030/4];
+	u32 pipe_0x7000[0x130/4];
+	u32 pipe_0x7400[0x0c0/4];
+	u32 pipe_0x7800[0x0c0/4];
+};
+
+static int nv10_gr_ctx_regs[] = {
+	NV10_PGRAPH_CTX_SWITCH(0),
+	NV10_PGRAPH_CTX_SWITCH(1),
+	NV10_PGRAPH_CTX_SWITCH(2),
+	NV10_PGRAPH_CTX_SWITCH(3),
+	NV10_PGRAPH_CTX_SWITCH(4),
+	NV10_PGRAPH_CTX_CACHE(0, 0),
+	NV10_PGRAPH_CTX_CACHE(0, 1),
+	NV10_PGRAPH_CTX_CACHE(0, 2),
+	NV10_PGRAPH_CTX_CACHE(0, 3),
+	NV10_PGRAPH_CTX_CACHE(0, 4),
+	NV10_PGRAPH_CTX_CACHE(1, 0),
+	NV10_PGRAPH_CTX_CACHE(1, 1),
+	NV10_PGRAPH_CTX_CACHE(1, 2),
+	NV10_PGRAPH_CTX_CACHE(1, 3),
+	NV10_PGRAPH_CTX_CACHE(1, 4),
+	NV10_PGRAPH_CTX_CACHE(2, 0),
+	NV10_PGRAPH_CTX_CACHE(2, 1),
+	NV10_PGRAPH_CTX_CACHE(2, 2),
+	NV10_PGRAPH_CTX_CACHE(2, 3),
+	NV10_PGRAPH_CTX_CACHE(2, 4),
+	NV10_PGRAPH_CTX_CACHE(3, 0),
+	NV10_PGRAPH_CTX_CACHE(3, 1),
+	NV10_PGRAPH_CTX_CACHE(3, 2),
+	NV10_PGRAPH_CTX_CACHE(3, 3),
+	NV10_PGRAPH_CTX_CACHE(3, 4),
+	NV10_PGRAPH_CTX_CACHE(4, 0),
+	NV10_PGRAPH_CTX_CACHE(4, 1),
+	NV10_PGRAPH_CTX_CACHE(4, 2),
+	NV10_PGRAPH_CTX_CACHE(4, 3),
+	NV10_PGRAPH_CTX_CACHE(4, 4),
+	NV10_PGRAPH_CTX_CACHE(5, 0),
+	NV10_PGRAPH_CTX_CACHE(5, 1),
+	NV10_PGRAPH_CTX_CACHE(5, 2),
+	NV10_PGRAPH_CTX_CACHE(5, 3),
+	NV10_PGRAPH_CTX_CACHE(5, 4),
+	NV10_PGRAPH_CTX_CACHE(6, 0),
+	NV10_PGRAPH_CTX_CACHE(6, 1),
+	NV10_PGRAPH_CTX_CACHE(6, 2),
+	NV10_PGRAPH_CTX_CACHE(6, 3),
+	NV10_PGRAPH_CTX_CACHE(6, 4),
+	NV10_PGRAPH_CTX_CACHE(7, 0),
+	NV10_PGRAPH_CTX_CACHE(7, 1),
+	NV10_PGRAPH_CTX_CACHE(7, 2),
+	NV10_PGRAPH_CTX_CACHE(7, 3),
+	NV10_PGRAPH_CTX_CACHE(7, 4),
+	NV10_PGRAPH_CTX_USER,
+	NV04_PGRAPH_DMA_START_0,
+	NV04_PGRAPH_DMA_START_1,
+	NV04_PGRAPH_DMA_LENGTH,
+	NV04_PGRAPH_DMA_MISC,
+	NV10_PGRAPH_DMA_PITCH,
+	NV04_PGRAPH_BOFFSET0,
+	NV04_PGRAPH_BBASE0,
+	NV04_PGRAPH_BLIMIT0,
+	NV04_PGRAPH_BOFFSET1,
+	NV04_PGRAPH_BBASE1,
+	NV04_PGRAPH_BLIMIT1,
+	NV04_PGRAPH_BOFFSET2,
+	NV04_PGRAPH_BBASE2,
+	NV04_PGRAPH_BLIMIT2,
+	NV04_PGRAPH_BOFFSET3,
+	NV04_PGRAPH_BBASE3,
+	NV04_PGRAPH_BLIMIT3,
+	NV04_PGRAPH_BOFFSET4,
+	NV04_PGRAPH_BBASE4,
+	NV04_PGRAPH_BLIMIT4,
+	NV04_PGRAPH_BOFFSET5,
+	NV04_PGRAPH_BBASE5,
+	NV04_PGRAPH_BLIMIT5,
+	NV04_PGRAPH_BPITCH0,
+	NV04_PGRAPH_BPITCH1,
+	NV04_PGRAPH_BPITCH2,
+	NV04_PGRAPH_BPITCH3,
+	NV04_PGRAPH_BPITCH4,
+	NV10_PGRAPH_SURFACE,
+	NV10_PGRAPH_STATE,
+	NV04_PGRAPH_BSWIZZLE2,
+	NV04_PGRAPH_BSWIZZLE5,
+	NV04_PGRAPH_BPIXEL,
+	NV10_PGRAPH_NOTIFY,
+	NV04_PGRAPH_PATT_COLOR0,
+	NV04_PGRAPH_PATT_COLOR1,
+	NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */
+	0x00400904,
+	0x00400908,
+	0x0040090c,
+	0x00400910,
+	0x00400914,
+	0x00400918,
+	0x0040091c,
+	0x00400920,
+	0x00400924,
+	0x00400928,
+	0x0040092c,
+	0x00400930,
+	0x00400934,
+	0x00400938,
+	0x0040093c,
+	0x00400940,
+	0x00400944,
+	0x00400948,
+	0x0040094c,
+	0x00400950,
+	0x00400954,
+	0x00400958,
+	0x0040095c,
+	0x00400960,
+	0x00400964,
+	0x00400968,
+	0x0040096c,
+	0x00400970,
+	0x00400974,
+	0x00400978,
+	0x0040097c,
+	0x00400980,
+	0x00400984,
+	0x00400988,
+	0x0040098c,
+	0x00400990,
+	0x00400994,
+	0x00400998,
+	0x0040099c,
+	0x004009a0,
+	0x004009a4,
+	0x004009a8,
+	0x004009ac,
+	0x004009b0,
+	0x004009b4,
+	0x004009b8,
+	0x004009bc,
+	0x004009c0,
+	0x004009c4,
+	0x004009c8,
+	0x004009cc,
+	0x004009d0,
+	0x004009d4,
+	0x004009d8,
+	0x004009dc,
+	0x004009e0,
+	0x004009e4,
+	0x004009e8,
+	0x004009ec,
+	0x004009f0,
+	0x004009f4,
+	0x004009f8,
+	0x004009fc,
+	NV04_PGRAPH_PATTERN,	/* 2 values from 0x400808 to 0x40080c */
+	0x0040080c,
+	NV04_PGRAPH_PATTERN_SHAPE,
+	NV03_PGRAPH_MONO_COLOR0,
+	NV04_PGRAPH_ROP3,
+	NV04_PGRAPH_CHROMA,
+	NV04_PGRAPH_BETA_AND,
+	NV04_PGRAPH_BETA_PREMULT,
+	0x00400e70,
+	0x00400e74,
+	0x00400e78,
+	0x00400e7c,
+	0x00400e80,
+	0x00400e84,
+	0x00400e88,
+	0x00400e8c,
+	0x00400ea0,
+	0x00400ea4,
+	0x00400ea8,
+	0x00400e90,
+	0x00400e94,
+	0x00400e98,
+	0x00400e9c,
+	NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */
+	NV10_PGRAPH_WINDOWCLIP_VERTICAL,   /* 8 values from 0x400f20-0x400f3c */
+	0x00400f04,
+	0x00400f24,
+	0x00400f08,
+	0x00400f28,
+	0x00400f0c,
+	0x00400f2c,
+	0x00400f10,
+	0x00400f30,
+	0x00400f14,
+	0x00400f34,
+	0x00400f18,
+	0x00400f38,
+	0x00400f1c,
+	0x00400f3c,
+	NV10_PGRAPH_XFMODE0,
+	NV10_PGRAPH_XFMODE1,
+	NV10_PGRAPH_GLOBALSTATE0,
+	NV10_PGRAPH_GLOBALSTATE1,
+	NV04_PGRAPH_STORED_FMT,
+	NV04_PGRAPH_SOURCE_COLOR,
+	NV03_PGRAPH_ABS_X_RAM,	/* 32 values from 0x400400 to 0x40047c */
+	NV03_PGRAPH_ABS_Y_RAM,	/* 32 values from 0x400480 to 0x4004fc */
+	0x00400404,
+	0x00400484,
+	0x00400408,
+	0x00400488,
+	0x0040040c,
+	0x0040048c,
+	0x00400410,
+	0x00400490,
+	0x00400414,
+	0x00400494,
+	0x00400418,
+	0x00400498,
+	0x0040041c,
+	0x0040049c,
+	0x00400420,
+	0x004004a0,
+	0x00400424,
+	0x004004a4,
+	0x00400428,
+	0x004004a8,
+	0x0040042c,
+	0x004004ac,
+	0x00400430,
+	0x004004b0,
+	0x00400434,
+	0x004004b4,
+	0x00400438,
+	0x004004b8,
+	0x0040043c,
+	0x004004bc,
+	0x00400440,
+	0x004004c0,
+	0x00400444,
+	0x004004c4,
+	0x00400448,
+	0x004004c8,
+	0x0040044c,
+	0x004004cc,
+	0x00400450,
+	0x004004d0,
+	0x00400454,
+	0x004004d4,
+	0x00400458,
+	0x004004d8,
+	0x0040045c,
+	0x004004dc,
+	0x00400460,
+	0x004004e0,
+	0x00400464,
+	0x004004e4,
+	0x00400468,
+	0x004004e8,
+	0x0040046c,
+	0x004004ec,
+	0x00400470,
+	0x004004f0,
+	0x00400474,
+	0x004004f4,
+	0x00400478,
+	0x004004f8,
+	0x0040047c,
+	0x004004fc,
+	NV03_PGRAPH_ABS_UCLIP_XMIN,
+	NV03_PGRAPH_ABS_UCLIP_XMAX,
+	NV03_PGRAPH_ABS_UCLIP_YMIN,
+	NV03_PGRAPH_ABS_UCLIP_YMAX,
+	0x00400550,
+	0x00400558,
+	0x00400554,
+	0x0040055c,
+	NV03_PGRAPH_ABS_UCLIPA_XMIN,
+	NV03_PGRAPH_ABS_UCLIPA_XMAX,
+	NV03_PGRAPH_ABS_UCLIPA_YMIN,
+	NV03_PGRAPH_ABS_UCLIPA_YMAX,
+	NV03_PGRAPH_ABS_ICLIP_XMAX,
+	NV03_PGRAPH_ABS_ICLIP_YMAX,
+	NV03_PGRAPH_XY_LOGIC_MISC0,
+	NV03_PGRAPH_XY_LOGIC_MISC1,
+	NV03_PGRAPH_XY_LOGIC_MISC2,
+	NV03_PGRAPH_XY_LOGIC_MISC3,
+	NV03_PGRAPH_CLIPX_0,
+	NV03_PGRAPH_CLIPX_1,
+	NV03_PGRAPH_CLIPY_0,
+	NV03_PGRAPH_CLIPY_1,
+	NV10_PGRAPH_COMBINER0_IN_ALPHA,
+	NV10_PGRAPH_COMBINER1_IN_ALPHA,
+	NV10_PGRAPH_COMBINER0_IN_RGB,
+	NV10_PGRAPH_COMBINER1_IN_RGB,
+	NV10_PGRAPH_COMBINER_COLOR0,
+	NV10_PGRAPH_COMBINER_COLOR1,
+	NV10_PGRAPH_COMBINER0_OUT_ALPHA,
+	NV10_PGRAPH_COMBINER1_OUT_ALPHA,
+	NV10_PGRAPH_COMBINER0_OUT_RGB,
+	NV10_PGRAPH_COMBINER1_OUT_RGB,
+	NV10_PGRAPH_COMBINER_FINAL0,
+	NV10_PGRAPH_COMBINER_FINAL1,
+	0x00400e00,
+	0x00400e04,
+	0x00400e08,
+	0x00400e0c,
+	0x00400e10,
+	0x00400e14,
+	0x00400e18,
+	0x00400e1c,
+	0x00400e20,
+	0x00400e24,
+	0x00400e28,
+	0x00400e2c,
+	0x00400e30,
+	0x00400e34,
+	0x00400e38,
+	0x00400e3c,
+	NV04_PGRAPH_PASSTHRU_0,
+	NV04_PGRAPH_PASSTHRU_1,
+	NV04_PGRAPH_PASSTHRU_2,
+	NV10_PGRAPH_DIMX_TEXTURE,
+	NV10_PGRAPH_WDIMX_TEXTURE,
+	NV10_PGRAPH_DVD_COLORFMT,
+	NV10_PGRAPH_SCALED_FORMAT,
+	NV04_PGRAPH_MISC24_0,
+	NV04_PGRAPH_MISC24_1,
+	NV04_PGRAPH_MISC24_2,
+	NV03_PGRAPH_X_MISC,
+	NV03_PGRAPH_Y_MISC,
+	NV04_PGRAPH_VALID1,
+	NV04_PGRAPH_VALID2,
+};
+
+static int nv17_gr_ctx_regs[] = {
+	NV10_PGRAPH_DEBUG_4,
+	0x004006b0,
+	0x00400eac,
+	0x00400eb0,
+	0x00400eb4,
+	0x00400eb8,
+	0x00400ebc,
+	0x00400ec0,
+	0x00400ec4,
+	0x00400ec8,
+	0x00400ecc,
+	0x00400ed0,
+	0x00400ed4,
+	0x00400ed8,
+	0x00400edc,
+	0x00400ee0,
+	0x00400a00,
+	0x00400a04,
+};
+
+struct nv10_gr_priv {
+	struct nvkm_gr base;
+	struct nv10_gr_chan *chan[32];
+	spinlock_t lock;
+};
+
+struct nv10_gr_chan {
+	struct nvkm_object base;
+	int chid;
+	int nv10[ARRAY_SIZE(nv10_gr_ctx_regs)];
+	int nv17[ARRAY_SIZE(nv17_gr_ctx_regs)];
+	struct pipe_state pipe_state;
+	u32 lma_window[4];
+};
+
+
+static inline struct nv10_gr_priv *
+nv10_gr_priv(struct nv10_gr_chan *chan)
+{
+	return (void *)nv_object(chan)->engine;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+#define PIPE_SAVE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
+	} while (0)
+
+#define PIPE_RESTORE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+	} while (0)
+
+static struct nvkm_oclass
+nv10_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
+	{ 0x0056, &nv04_gr_ofuncs }, /* celcius */
+	{},
+};
+
+static struct nvkm_oclass
+nv15_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
+	{ 0x0096, &nv04_gr_ofuncs }, /* celcius */
+	{},
+};
+
+static int
+nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	struct nv10_gr_chan *chan = (void *)object->parent;
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+	u32 xfmode0, xfmode1;
+	u32 data = *(u32 *)args;
+	int i;
+
+	chan->lma_window[(mthd - 0x1638) / 4] = data;
+
+	if (mthd != 0x1644)
+		return 0;
+
+	nv04_gr_idle(priv);
+
+	PIPE_SAVE(priv, pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+
+	PIPE_RESTORE(priv, chan->lma_window, 0x6790);
+
+	nv04_gr_idle(priv);
+
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
+
+	nv04_gr_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+
+	nv04_gr_idle(priv);
+
+	PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+
+	PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv04_gr_idle(priv);
+
+	return 0;
+}
+
+static int
+nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	struct nv10_gr_chan *chan = (void *)object->parent;
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+
+	nv04_gr_idle(priv);
+
+	nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
+	nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
+	return 0;
+}
+
+static struct nvkm_omthds
+nv17_celcius_omthds[] = {
+	{ 0x1638, 0x1638, nv17_gr_mthd_lma_window },
+	{ 0x163c, 0x163c, nv17_gr_mthd_lma_window },
+	{ 0x1640, 0x1640, nv17_gr_mthd_lma_window },
+	{ 0x1644, 0x1644, nv17_gr_mthd_lma_window },
+	{ 0x1658, 0x1658, nv17_gr_mthd_lma_enable },
+	{}
+};
+
+static struct nvkm_oclass
+nv17_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
+	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
+	{ 0x0099, &nv04_gr_ofuncs, nv17_celcius_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv10_gr_chan *
+nv10_gr_channel(struct nv10_gr_priv *priv)
+{
+	struct nv10_gr_chan *chan = NULL;
+	if (nv_rd32(priv, 0x400144) & 0x00010000) {
+		int chid = nv_rd32(priv, 0x400148) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static void
+nv10_gr_save_pipe(struct nv10_gr_chan *chan)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+	PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
+}
+
+static void
+nv10_gr_load_pipe(struct nv10_gr_chan *chan)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 xfmode0, xfmode1;
+	int i;
+
+	nv04_gr_idle(priv);
+	/* XXX check haiku comments */
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+	nv04_gr_idle(priv);
+
+	/* restore XFMODE */
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+	PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
+	PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
+	nv04_gr_idle(priv);
+}
+
+static void
+nv10_gr_create_pipe(struct nv10_gr_chan *chan)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	struct pipe_state *pipe_state = &chan->pipe_state;
+	u32 *pipe_state_addr;
+	int i;
+#define PIPE_INIT(addr) \
+	do { \
+		pipe_state_addr = pipe_state->pipe_##addr; \
+	} while (0)
+#define PIPE_INIT_END(addr) \
+	do { \
+		u32 *__end_addr = pipe_state->pipe_##addr + \
+				ARRAY_SIZE(pipe_state->pipe_##addr); \
+		if (pipe_state_addr != __end_addr) \
+			nv_error(priv, "incomplete pipe init for 0x%x :  %p/%p\n", \
+				addr, pipe_state_addr, __end_addr); \
+	} while (0)
+#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
+
+	PIPE_INIT(0x0200);
+	for (i = 0; i < 48; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x0200);
+
+	PIPE_INIT(0x6400);
+	for (i = 0; i < 211; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x40000000);
+	NV_WRITE_PIPE_INIT(0x40000000);
+	NV_WRITE_PIPE_INIT(0x40000000);
+	NV_WRITE_PIPE_INIT(0x40000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f000000);
+	NV_WRITE_PIPE_INIT(0x3f000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	PIPE_INIT_END(0x6400);
+
+	PIPE_INIT(0x6800);
+	for (i = 0; i < 162; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x3f800000);
+	for (i = 0; i < 25; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x6800);
+
+	PIPE_INIT(0x6c00);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0xbf800000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x6c00);
+
+	PIPE_INIT(0x7000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x00000000);
+	NV_WRITE_PIPE_INIT(0x7149f2ca);
+	for (i = 0; i < 35; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x7000);
+
+	PIPE_INIT(0x7400);
+	for (i = 0; i < 48; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x7400);
+
+	PIPE_INIT(0x7800);
+	for (i = 0; i < 48; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x7800);
+
+	PIPE_INIT(0x4400);
+	for (i = 0; i < 32; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x4400);
+
+	PIPE_INIT(0x0000);
+	for (i = 0; i < 16; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x0000);
+
+	PIPE_INIT(0x0040);
+	for (i = 0; i < 4; i++)
+		NV_WRITE_PIPE_INIT(0x00000000);
+	PIPE_INIT_END(0x0040);
+
+#undef PIPE_INIT
+#undef PIPE_INIT_END
+#undef NV_WRITE_PIPE_INIT
+}
+
+static int
+nv10_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) {
+		if (nv10_gr_ctx_regs[i] == reg)
+			return i;
+	}
+	nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
+	return -1;
+}
+
+static int
+nv17_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) {
+		if (nv17_gr_ctx_regs[i] == reg)
+			return i;
+	}
+	nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
+	return -1;
+}
+
+static void
+nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+	u32 ctx_user, ctx_switch[5];
+	int i, subchan = -1;
+
+	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
+	 * that cannot be restored via MMIO. Do it through the FIFO
+	 * instead.
+	 */
+
+	/* Look for a celsius object */
+	for (i = 0; i < 8; i++) {
+		int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+
+		if (class == 0x56 || class == 0x96 || class == 0x99) {
+			subchan = i;
+			break;
+		}
+	}
+
+	if (subchan < 0 || !inst)
+		return;
+
+	/* Save the current ctx object */
+	ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
+	for (i = 0; i < 5; i++)
+		ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
+
+	/* Save the FIFO state */
+	st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
+	st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
+	st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
+	fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+
+	for (i = 0; i < ARRAY_SIZE(fifo); i++)
+		fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
+
+	/* Switch to the celsius subchannel */
+	for (i = 0; i < 5; i++)
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
+			nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+
+	/* Inject NV10TCL_DMA_VTXBUF */
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
+		0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+	nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+
+	/* Restore the FIFO state */
+	for (i = 0; i < ARRAY_SIZE(fifo); i++)
+		nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
+
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+
+	/* Restore the current ctx object */
+	for (i = 0; i < 5; i++)
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+	nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
+}
+
+static int
+nv10_gr_load_context(struct nv10_gr_chan *chan, int chid)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	u32 inst;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
+		nv_wr32(priv, nv10_gr_ctx_regs[i], chan->nv10[i]);
+
+	if (nv_device(priv)->card_type >= NV_11 &&
+	    nv_device(priv)->chipset >= 0x17) {
+		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
+			nv_wr32(priv, nv17_gr_ctx_regs[i], chan->nv17[i]);
+	}
+
+	nv10_gr_load_pipe(chan);
+
+	inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
+	nv10_gr_load_dma_vtxbuf(chan, chid, inst);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
+	return 0;
+}
+
+static int
+nv10_gr_unload_context(struct nv10_gr_chan *chan)
+{
+	struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
+		chan->nv10[i] = nv_rd32(priv, nv10_gr_ctx_regs[i]);
+
+	if (nv_device(priv)->card_type >= NV_11 &&
+	    nv_device(priv)->chipset >= 0x17) {
+		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
+			chan->nv17[i] = nv_rd32(priv, nv17_gr_ctx_regs[i]);
+	}
+
+	nv10_gr_save_pipe(chan);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+	return 0;
+}
+
+static void
+nv10_gr_context_switch(struct nv10_gr_priv *priv)
+{
+	struct nv10_gr_chan *prev = NULL;
+	struct nv10_gr_chan *next = NULL;
+	unsigned long flags;
+	int chid;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_gr_idle(priv);
+
+	/* If previous context is valid, we need to save it */
+	prev = nv10_gr_channel(priv);
+	if (prev)
+		nv10_gr_unload_context(prev);
+
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
+	next = priv->chan[chid];
+	if (next)
+		nv10_gr_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+#define NV_WRITE_CTX(reg, val) do { \
+	int offset = nv10_gr_ctx_regs_find_offset(priv, reg); \
+	if (offset > 0) \
+		chan->nv10[offset] = val; \
+	} while (0)
+
+#define NV17_WRITE_CTX(reg, val) do { \
+	int offset = nv17_gr_ctx_regs_find_offset(priv, reg); \
+	if (offset > 0) \
+		chan->nv17[offset] = val; \
+	} while (0)
+
+static int
+nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nvkm_fifo_chan *fifo = (void *)parent;
+	struct nv10_gr_priv *priv = (void *)engine;
+	struct nv10_gr_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nvkm_object_destroy(&chan->base);
+		return 1;
+	}
+
+	NV_WRITE_CTX(0x00400e88, 0x08000000);
+	NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
+	NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff);
+	NV_WRITE_CTX(0x00400e10, 0x00001000);
+	NV_WRITE_CTX(0x00400e14, 0x00001000);
+	NV_WRITE_CTX(0x00400e30, 0x00080008);
+	NV_WRITE_CTX(0x00400e34, 0x00080008);
+	if (nv_device(priv)->card_type >= NV_11 &&
+	    nv_device(priv)->chipset >= 0x17) {
+		/* is it really needed ??? */
+		NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
+					nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
+		NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
+		NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
+		NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
+		NV17_WRITE_CTX(0x00400ec0, 0x00000080);
+		NV17_WRITE_CTX(0x00400ed0, 0x00000080);
+	}
+	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
+
+	nv10_gr_create_pipe(chan);
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+static void
+nv10_gr_context_dtor(struct nvkm_object *object)
+{
+	struct nv10_gr_priv *priv = (void *)object->engine;
+	struct nv10_gr_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nvkm_object_destroy(&chan->base);
+}
+
+static int
+nv10_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv10_gr_priv *priv = (void *)object->engine;
+	struct nv10_gr_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv10_gr_channel(priv) == chan)
+		nv10_gr_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nvkm_object_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv10_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x10),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_gr_context_ctor,
+		.dtor = nv10_gr_context_dtor,
+		.init = nvkm_object_init,
+		.fini = nv10_gr_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv10_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+	struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+	struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+	struct nv10_gr_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_gr_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
+
+	pfifo->start(pfifo, &flags);
+}
+
+const struct nvkm_bitfield nv10_gr_intr_name[] = {
+	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+	{ NV_PGRAPH_INTR_ERROR,  "ERROR"  },
+	{}
+};
+
+const struct nvkm_bitfield nv10_gr_nstatus[] = {
+	{ NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+	{ NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+	{ NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+	{ NV10_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
+	{}
+};
+
+static void
+nv10_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nv10_gr_priv *priv = (void *)subdev;
+	struct nv10_gr_chan *chan = NULL;
+	struct nvkm_namedb *namedb = NULL;
+	struct nvkm_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 show = stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
+	if (chan)
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nvkm_namedb_get_class(namedb, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+		}
+	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv10_gr_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "%s", "");
+		nvkm_bitfield_print(nv10_gr_intr_name, show);
+		pr_cont(" nsource:");
+		nvkm_bitfield_print(nv04_gr_nsource, nsource);
+		pr_cont(" nstatus:");
+		nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+		pr_cont("\n");
+		nv_error(priv,
+			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, nvkm_client_name(chan), subc, class, mthd,
+			 data);
+	}
+
+	nvkm_namedb_put(handle);
+}
+
+static int
+nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv10_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv10_gr_intr;
+	nv_engine(priv)->cclass = &nv10_gr_cclass;
+
+	if (nv_device(priv)->chipset <= 0x10)
+		nv_engine(priv)->sclass = nv10_gr_sclass;
+	else
+	if (nv_device(priv)->chipset <  0x17 ||
+	    nv_device(priv)->card_type < NV_11)
+		nv_engine(priv)->sclass = nv15_gr_sclass;
+	else
+		nv_engine(priv)->sclass = nv17_gr_sclass;
+
+	nv_engine(priv)->tile_prog = nv10_gr_tile_prog;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+static void
+nv10_gr_dtor(struct nvkm_object *object)
+{
+	struct nv10_gr_priv *priv = (void *)object;
+	nvkm_gr_destroy(&priv->base);
+}
+
+static int
+nv10_gr_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	struct nv10_gr_priv *priv = (void *)engine;
+	int ret, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	/* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
+
+	if (nv_device(priv)->card_type >= NV_11 &&
+	    nv_device(priv)->chipset >= 0x17) {
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+		nv_wr32(priv, 0x400a10, 0x03ff3fb6);
+		nv_wr32(priv, 0x400838, 0x002f8684);
+		nv_wr32(priv, 0x40083c, 0x00115f3f);
+		nv_wr32(priv, 0x4006b0, 0x40000020);
+	} else {
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+	}
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
+
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
+	return 0;
+}
+
+static int
+nv10_gr_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv10_gr_priv *priv = (void *)object;
+	return nvkm_gr_fini(&priv->base, suspend);
+}
+
+struct nvkm_oclass
+nv10_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x10),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_gr_ctor,
+		.dtor = nv10_gr_dtor,
+		.init = nv10_gr_init,
+		.fini = nv10_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
new file mode 100644
index 0000000..1713ffb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
@@ -0,0 +1,376 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv20_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */
+	{ 0x0097, &nv04_gr_ofuncs, NULL }, /* kelvin */
+	{ 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x37f0,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1c1c; i <= 0x248c; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x281c, 0x3f800000);
+	nv_wo32(chan, 0x2830, 0x3f800000);
+	nv_wo32(chan, 0x285c, 0x40000000);
+	nv_wo32(chan, 0x2860, 0x3f800000);
+	nv_wo32(chan, 0x2864, 0x3f000000);
+	nv_wo32(chan, 0x286c, 0x40000000);
+	nv_wo32(chan, 0x2870, 0x3f800000);
+	nv_wo32(chan, 0x2878, 0xbf800000);
+	nv_wo32(chan, 0x2880, 0xbf800000);
+	nv_wo32(chan, 0x34a4, 0x000fe000);
+	nv_wo32(chan, 0x3530, 0x000003f8);
+	nv_wo32(chan, 0x3540, 0x002fe000);
+	for (i = 0x355c; i <= 0x3578; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+int
+nv20_gr_context_init(struct nvkm_object *object)
+{
+	struct nv20_gr_priv *priv = (void *)object->engine;
+	struct nv20_gr_chan *chan = (void *)object;
+	int ret;
+
+	ret = nvkm_gr_context_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+int
+nv20_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv20_gr_priv *priv = (void *)object->engine;
+	struct nv20_gr_chan *chan = (void *)object;
+	int chid = -1;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+	if (nv_rd32(priv, 0x400144) & 0x00010000)
+		chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
+	if (chan->chid == chid) {
+		nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
+		nv_wr32(priv, 0x400788, 0x00000002);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+		nv_wr32(priv, 0x400144, 0x10000000);
+		nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
+	}
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
+	return nvkm_gr_context_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv20_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x20),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv20_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+nv20_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+	struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+	struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+	struct nv20_gr_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_gr_idle(priv);
+
+	nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
+
+	if (nv_device(engine)->chipset != 0x34) {
+		nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
+	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+void
+nv20_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct nvkm_handle *handle;
+	struct nv20_gr_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 show = stat;
+
+	engctx = nvkm_engctx_get(engine, chid);
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nvkm_handle_get_class(engctx, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nvkm_handle_put(handle);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "%s", "");
+		nvkm_bitfield_print(nv10_gr_intr_name, show);
+		pr_cont(" nsource:");
+		nvkm_bitfield_print(nv04_gr_nsource, nsource);
+		pr_cont(" nstatus:");
+		nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+		pr_cont("\n");
+		nv_error(priv,
+			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, nvkm_client_name(engctx), subc, class, mthd,
+			 data);
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv20_gr_cclass;
+	nv_engine(priv)->sclass = nv20_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+void
+nv20_gr_dtor(struct nvkm_object *object)
+{
+	struct nv20_gr_priv *priv = (void *)object;
+	nvkm_gpuobj_ref(NULL, &priv->ctxtab);
+	nvkm_gr_destroy(&priv->base);
+}
+
+int
+nv20_gr_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nv20_gr_priv *priv = (void *)engine;
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	u32 tmp, vramsz;
+	int ret, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+	if (nv_device(priv)->chipset == 0x20) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
+		for (i = 0; i < 15; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	} else {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
+		for (i = 0; i < 32; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+	nv_wr32(priv, 0x40009C           , 0x00000040);
+
+	if (nv_device(priv)->chipset >= 0x25) {
+		nv_wr32(priv, 0x400890, 0x00a8cfff);
+		nv_wr32(priv, 0x400610, 0x304B1FB6);
+		nv_wr32(priv, 0x400B80, 0x1cbd3883);
+		nv_wr32(priv, 0x400B84, 0x44000000);
+		nv_wr32(priv, 0x400098, 0x40000080);
+		nv_wr32(priv, 0x400B88, 0x000000ff);
+
+	} else {
+		nv_wr32(priv, 0x400880, 0x0008c7df);
+		nv_wr32(priv, 0x400094, 0x00000005);
+		nv_wr32(priv, 0x400B80, 0x45eae20e);
+		nv_wr32(priv, 0x400B84, 0x24000000);
+		nv_wr32(priv, 0x400098, 0x00000040);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+	}
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+
+	/* begin RAM config */
+	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
+	nv_wr32(priv, 0x400820, 0);
+	nv_wr32(priv, 0x400824, 0);
+	nv_wr32(priv, 0x400864, vramsz - 1);
+	nv_wr32(priv, 0x400868, vramsz - 1);
+
+	/* interesting.. the below overwrites some of the tile setup above.. */
+	nv_wr32(priv, 0x400B20, 0x00000000);
+	nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
+	return 0;
+}
+
+struct nvkm_oclass
+nv20_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x20),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv20_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv20_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
new file mode 100644
index 0000000..ac4dc04
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
@@ -0,0 +1,26 @@
+#ifndef __NV20_GR_H__
+#define __NV20_GR_H__
+#include <engine/gr.h>
+
+struct nv20_gr_priv {
+	struct nvkm_gr base;
+	struct nvkm_gpuobj *ctxtab;
+};
+
+struct nv20_gr_chan {
+	struct nvkm_gr_chan base;
+	int chid;
+};
+
+extern struct nvkm_oclass nv25_gr_sclass[];
+int  nv20_gr_context_init(struct nvkm_object *);
+int  nv20_gr_context_fini(struct nvkm_object *, bool);
+
+void nv20_gr_tile_prog(struct nvkm_engine *, int);
+void nv20_gr_intr(struct nvkm_subdev *);
+
+void nv20_gr_dtor(struct nvkm_object *);
+int  nv20_gr_init(struct nvkm_object *);
+
+int  nv30_gr_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
new file mode 100644
index 0000000..bc36251
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
@@ -0,0 +1,158 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+nv25_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */
+	{ 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x0597, &nv04_gr_ofuncs, NULL }, /* kelvin */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x3724,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x035c, 0xffff0000);
+	nv_wo32(chan, 0x03c0, 0x0fff0000);
+	nv_wo32(chan, 0x03c4, 0x0fff0000);
+	nv_wo32(chan, 0x049c, 0x00000101);
+	nv_wo32(chan, 0x04b0, 0x00000111);
+	nv_wo32(chan, 0x04c8, 0x00000080);
+	nv_wo32(chan, 0x04cc, 0xffff0000);
+	nv_wo32(chan, 0x04d0, 0x00000001);
+	nv_wo32(chan, 0x04e4, 0x44400000);
+	nv_wo32(chan, 0x04fc, 0x4b800000);
+	for (i = 0x0510; i <= 0x051c; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x0530; i <= 0x053c; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x0548; i <= 0x0554; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0558; i <= 0x0564; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x0568; i <= 0x0574; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x0598; i <= 0x05d4; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05e0, 0x4b7fffff);
+	nv_wo32(chan, 0x0620, 0x00000080);
+	nv_wo32(chan, 0x0624, 0x30201000);
+	nv_wo32(chan, 0x0628, 0x70605040);
+	nv_wo32(chan, 0x062c, 0xb0a09080);
+	nv_wo32(chan, 0x0630, 0xf0e0d0c0);
+	nv_wo32(chan, 0x0664, 0x00000001);
+	nv_wo32(chan, 0x066c, 0x00004000);
+	nv_wo32(chan, 0x0678, 0x00000001);
+	nv_wo32(chan, 0x0680, 0x00040000);
+	nv_wo32(chan, 0x0684, 0x00010000);
+	for (i = 0x1b04; i <= 0x2374; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x2704, 0x3f800000);
+	nv_wo32(chan, 0x2718, 0x3f800000);
+	nv_wo32(chan, 0x2744, 0x40000000);
+	nv_wo32(chan, 0x2748, 0x3f800000);
+	nv_wo32(chan, 0x274c, 0x3f000000);
+	nv_wo32(chan, 0x2754, 0x40000000);
+	nv_wo32(chan, 0x2758, 0x3f800000);
+	nv_wo32(chan, 0x2760, 0xbf800000);
+	nv_wo32(chan, 0x2768, 0xbf800000);
+	nv_wo32(chan, 0x308c, 0x000fe000);
+	nv_wo32(chan, 0x3108, 0x000003f8);
+	nv_wo32(chan, 0x3468, 0x002fe000);
+	for (i = 0x3484; i <= 0x34a0; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv25_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x25),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv25_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv25_gr_cclass;
+	nv_engine(priv)->sclass = nv25_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv25_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x25),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv25_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv20_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
new file mode 100644
index 0000000..22a5096
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
@@ -0,0 +1,125 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x36b0,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x269c, 0x3f800000);
+	nv_wo32(chan, 0x26b0, 0x3f800000);
+	nv_wo32(chan, 0x26dc, 0x40000000);
+	nv_wo32(chan, 0x26e0, 0x3f800000);
+	nv_wo32(chan, 0x26e4, 0x3f000000);
+	nv_wo32(chan, 0x26ec, 0x40000000);
+	nv_wo32(chan, 0x26f0, 0x3f800000);
+	nv_wo32(chan, 0x26f8, 0xbf800000);
+	nv_wo32(chan, 0x2700, 0xbf800000);
+	nv_wo32(chan, 0x3024, 0x000fe000);
+	nv_wo32(chan, 0x30a0, 0x000003f8);
+	nv_wo32(chan, 0x33fc, 0x002fe000);
+	for (i = 0x341c; i <= 0x3438; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv2a_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x2a),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv2a_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv2a_gr_cclass;
+	nv_engine(priv)->sclass = nv25_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv2a_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x2a),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv2a_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv20_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
new file mode 100644
index 0000000..dcc84eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -0,0 +1,231 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv30_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0397, &nv04_gr_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x5f48,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x0410, 0x00000101);
+	nv_wo32(chan, 0x0424, 0x00000111);
+	nv_wo32(chan, 0x0428, 0x00000060);
+	nv_wo32(chan, 0x0444, 0x00000080);
+	nv_wo32(chan, 0x0448, 0xffff0000);
+	nv_wo32(chan, 0x044c, 0x00000001);
+	nv_wo32(chan, 0x0460, 0x44400000);
+	nv_wo32(chan, 0x048c, 0xffff0000);
+	for (i = 0x04e0; i < 0x04e8; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04ec, 0x00011100);
+	for (i = 0x0508; i < 0x0548; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0550, 0x4b7fffff);
+	nv_wo32(chan, 0x058c, 0x00000080);
+	nv_wo32(chan, 0x0590, 0x30201000);
+	nv_wo32(chan, 0x0594, 0x70605040);
+	nv_wo32(chan, 0x0598, 0xb8a89888);
+	nv_wo32(chan, 0x059c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05b0, 0xb0000000);
+	for (i = 0x0600; i < 0x0640; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0640; i < 0x0680; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c0; i < 0x0700; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0700; i < 0x0740; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0740; i < 0x0780; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x085c, 0x00040000);
+	nv_wo32(chan, 0x0860, 0x00010000);
+	for (i = 0x0864; i < 0x0874; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x30b8; i < 0x30c8; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x344c, 0x3f800000);
+	nv_wo32(chan, 0x3808, 0x3f800000);
+	nv_wo32(chan, 0x381c, 0x3f800000);
+	nv_wo32(chan, 0x3848, 0x40000000);
+	nv_wo32(chan, 0x384c, 0x3f800000);
+	nv_wo32(chan, 0x3850, 0x3f000000);
+	nv_wo32(chan, 0x3858, 0x40000000);
+	nv_wo32(chan, 0x385c, 0x3f800000);
+	nv_wo32(chan, 0x3864, 0xbf800000);
+	nv_wo32(chan, 0x386c, 0xbf800000);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv30_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x30),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv30_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv30_gr_cclass;
+	nv_engine(priv)->sclass = nv30_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+int
+nv30_gr_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nv20_gr_priv *priv = (void *)engine;
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	int ret, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, 0x400890, 0x01b463ff);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
+	nv_wr32(priv, 0x400B80, 0x1003d888);
+	nv_wr32(priv, 0x400B84, 0x0c000000);
+	nv_wr32(priv, 0x400098, 0x00000000);
+	nv_wr32(priv, 0x40009C, 0x0005ad00);
+	nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
+	nv_wr32(priv, 0x4000a0, 0x00000000);
+	nv_wr32(priv, 0x4000a4, 0x00000008);
+	nv_wr32(priv, 0x4008a8, 0xb784a400);
+	nv_wr32(priv, 0x400ba0, 0x002f8685);
+	nv_wr32(priv, 0x400ba4, 0x00231f3f);
+	nv_wr32(priv, 0x4008a4, 0x40000020);
+
+	if (nv_device(priv)->chipset == 0x34) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
+	}
+
+	nv_wr32(priv, 0x4000c0, 0x00000016);
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, 0x0040075c             , 0x00000001);
+
+	/* begin RAM config */
+	/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	if (nv_device(priv)->chipset != 0x34) {
+		nv_wr32(priv, 0x400750, 0x00EA0000);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x400750, 0x00EA0004);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
+	}
+	return 0;
+}
+
+struct nvkm_oclass
+nv30_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x30),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv30_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv30_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
new file mode 100644
index 0000000..985b7f3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -0,0 +1,159 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv34_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0697, &nv04_gr_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x46dc,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x01000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0480, 0xffff0000);
+	for (i = 0x04d4; i < 0x04dc; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e0, 0x00011100);
+	for (i = 0x04fc; i < 0x053c; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0544, 0x4b7fffff);
+	nv_wo32(chan, 0x057c, 0x00000080);
+	nv_wo32(chan, 0x0580, 0x30201000);
+	nv_wo32(chan, 0x0584, 0x70605040);
+	nv_wo32(chan, 0x0588, 0xb8a89888);
+	nv_wo32(chan, 0x058c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05a0, 0xb0000000);
+	for (i = 0x05f0; i < 0x0630; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0630; i < 0x0670; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06b0; i < 0x06f0; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x06f0; i < 0x0730; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0730; i < 0x0770; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0850, 0x00040000);
+	nv_wo32(chan, 0x0854, 0x00010000);
+	for (i = 0x0858; i < 0x0868; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x15ac; i <= 0x271c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x274c; i < 0x275c; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x2ae0, 0x3f800000);
+	nv_wo32(chan, 0x2e9c, 0x3f800000);
+	nv_wo32(chan, 0x2eb0, 0x3f800000);
+	nv_wo32(chan, 0x2edc, 0x40000000);
+	nv_wo32(chan, 0x2ee0, 0x3f800000);
+	nv_wo32(chan, 0x2ee4, 0x3f000000);
+	nv_wo32(chan, 0x2eec, 0x40000000);
+	nv_wo32(chan, 0x2ef0, 0x3f800000);
+	nv_wo32(chan, 0x2ef8, 0xbf800000);
+	nv_wo32(chan, 0x2f00, 0xbf800000);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv34_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x34),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv34_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv34_gr_cclass;
+	nv_engine(priv)->sclass = nv34_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv34_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x34),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv34_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv30_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
new file mode 100644
index 0000000..707625f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
@@ -0,0 +1,159 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv35_gr_sclass[] = {
+	{ 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0497, &nv04_gr_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv20_gr_chan *chan;
+	int ret, i;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x577c,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nvkm_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x00000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0488, 0xffff0000);
+	for (i = 0x04dc; i < 0x04e4; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e8, 0x00011100);
+	for (i = 0x0504; i < 0x0544; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x054c, 0x4b7fffff);
+	nv_wo32(chan, 0x0588, 0x00000080);
+	nv_wo32(chan, 0x058c, 0x30201000);
+	nv_wo32(chan, 0x0590, 0x70605040);
+	nv_wo32(chan, 0x0594, 0xb8a89888);
+	nv_wo32(chan, 0x0598, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05ac, 0xb0000000);
+	for (i = 0x0604; i < 0x0644; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0644; i < 0x0684; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c4; i < 0x0704; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0704; i < 0x0744; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0744; i < 0x0784; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0860, 0x00040000);
+	nv_wo32(chan, 0x0864, 0x00010000);
+	for (i = 0x0868; i < 0x0878; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 4, 0x0436086c);
+		nv_wo32(chan, i + 8, 0x000c001b);
+	}
+	for (i = 0x30bc; i < 0x30cc; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x3450, 0x3f800000);
+	nv_wo32(chan, 0x380c, 0x3f800000);
+	nv_wo32(chan, 0x3820, 0x3f800000);
+	nv_wo32(chan, 0x384c, 0x40000000);
+	nv_wo32(chan, 0x3850, 0x3f800000);
+	nv_wo32(chan, 0x3854, 0x3f000000);
+	nv_wo32(chan, 0x385c, 0x40000000);
+	nv_wo32(chan, 0x3860, 0x3f800000);
+	nv_wo32(chan, 0x3868, 0xbf800000);
+	nv_wo32(chan, 0x3870, 0xbf800000);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv35_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x35),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv35_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = nv20_gr_context_init,
+		.fini = nv20_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv20_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_gr_intr;
+	nv_engine(priv)->cclass = &nv35_gr_cclass;
+	nv_engine(priv)->sclass = nv35_gr_sclass;
+	nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv35_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x35),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv35_gr_ctor,
+		.dtor = nv20_gr_dtor,
+		.init = nv30_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
new file mode 100644
index 0000000..7e19379
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <engine/fifo.h>
+
+struct nv40_gr_priv {
+	struct nvkm_gr base;
+	u32 size;
+};
+
+struct nv40_gr_chan {
+	struct nvkm_gr_chan base;
+};
+
+static u64
+nv40_gr_units(struct nvkm_gr *gr)
+{
+	struct nv40_gr_priv *priv = (void *)gr;
+
+	return nv_rd32(priv, 0x1540);
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+nv40_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 20, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
+#endif
+	nv_wo32(obj, 0x0c, 0x00000000);
+	nv_wo32(obj, 0x10, 0x00000000);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nv40_gr_ofuncs = {
+	.ctor = nv40_gr_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv40_gr_sclass[] = {
+	{ 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4097, &nv40_gr_ofuncs, NULL }, /* curie */
+	{},
+};
+
+static struct nvkm_oclass
+nv44_gr_sclass[] = {
+	{ 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_gr_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4497, &nv40_gr_ofuncs, NULL }, /* curie */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv40_gr_priv *priv = (void *)engine;
+	struct nv40_gr_chan *chan;
+	int ret;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size,
+				     16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+static int
+nv40_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv40_gr_priv *priv = (void *)object->engine;
+	struct nv40_gr_chan *chan = (void *)object;
+	u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
+	int ret = 0;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+
+	if (nv_rd32(priv, 0x40032c) == inst) {
+		if (suspend) {
+			nv_wr32(priv, 0x400720, 0x00000000);
+			nv_wr32(priv, 0x400784, inst);
+			nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
+			nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
+			if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
+				u32 insn = nv_rd32(priv, 0x400308);
+				nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
+				ret = -EBUSY;
+			}
+		}
+
+		nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
+	}
+
+	if (nv_rd32(priv, 0x400330) == inst)
+		nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+	return ret;
+}
+
+static struct nvkm_oclass
+nv40_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = nv40_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+	struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+	struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+	struct nv40_gr_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_gr_idle(priv);
+
+	switch (nv_device(priv)->chipset) {
+	case 0x40:
+	case 0x41:
+	case 0x42:
+	case 0x43:
+	case 0x45:
+	case 0x4e:
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
+		switch (nv_device(priv)->chipset) {
+		case 0x40:
+		case 0x45:
+			nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+			nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);
+			break;
+		case 0x41:
+		case 0x42:
+		case 0x43:
+			nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);
+			nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);
+			break;
+		default:
+			break;
+		}
+		break;
+	case 0x44:
+	case 0x4a:
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+		break;
+	case 0x46:
+	case 0x4c:
+	case 0x47:
+	case 0x49:
+	case 0x4b:
+	case 0x63:
+	case 0x67:
+	case 0x68:
+		nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
+		switch (nv_device(priv)->chipset) {
+		case 0x47:
+		case 0x49:
+		case 0x4b:
+			nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
+			nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+static void
+nv40_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct nvkm_handle *handle = NULL;
+	struct nv40_gr_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff;
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
+	u32 show = stat;
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nvkm_handle_get_class(engctx, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nvkm_handle_put(handle);
+		}
+
+		if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+			nv_mask(priv, 0x402000, 0, 0);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "%s", "");
+		nvkm_bitfield_print(nv10_gr_intr_name, show);
+		pr_cont(" nsource:");
+		nvkm_bitfield_print(nv04_gr_nsource, nsource);
+		pr_cont(" nstatus:");
+		nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+		pr_cont("\n");
+		nv_error(priv,
+			 "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, inst << 4, nvkm_client_name(engctx), subc,
+			 class, mthd, data);
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv40_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv40_gr_intr;
+	nv_engine(priv)->cclass = &nv40_gr_cclass;
+	if (nv44_gr_class(priv))
+		nv_engine(priv)->sclass = nv44_gr_sclass;
+	else
+		nv_engine(priv)->sclass = nv40_gr_sclass;
+	nv_engine(priv)->tile_prog = nv40_gr_tile_prog;
+
+	priv->base.units = nv40_gr_units;
+	return 0;
+}
+
+static int
+nv40_gr_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	struct nv40_gr_priv *priv = (void *)engine;
+	int ret, i, j;
+	u32 vramsz;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* generate and upload context program */
+	ret = nv40_grctx_init(nv_device(priv), &priv->size);
+	if (ret)
+		return ret;
+
+	/* No context present currently */
+	nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+
+	j = nv_rd32(priv, 0x1540) & 0xff;
+	if (j) {
+		for (i = 0; !(j & 1); j >>= 1, i++)
+			;
+		nv_wr32(priv, 0x405000, i);
+	}
+
+	if (nv_device(priv)->chipset == 0x40) {
+		nv_wr32(priv, 0x4009b0, 0x83280fff);
+		nv_wr32(priv, 0x4009b4, 0x000000a0);
+	} else {
+		nv_wr32(priv, 0x400820, 0x83280eff);
+		nv_wr32(priv, 0x400824, 0x000000a0);
+	}
+
+	switch (nv_device(priv)->chipset) {
+	case 0x40:
+	case 0x45:
+		nv_wr32(priv, 0x4009b8, 0x0078e366);
+		nv_wr32(priv, 0x4009bc, 0x0000014c);
+		break;
+	case 0x41:
+	case 0x42: /* pciid also 0x00Cx */
+	/* case 0x0120: XXX (pciid) */
+		nv_wr32(priv, 0x400828, 0x007596ff);
+		nv_wr32(priv, 0x40082c, 0x00000108);
+		break;
+	case 0x43:
+		nv_wr32(priv, 0x400828, 0x0072cb77);
+		nv_wr32(priv, 0x40082c, 0x00000108);
+		break;
+	case 0x44:
+	case 0x46: /* G72 */
+	case 0x4a:
+	case 0x4c: /* G7x-based C51 */
+	case 0x4e:
+		nv_wr32(priv, 0x400860, 0);
+		nv_wr32(priv, 0x400864, 0);
+		break;
+	case 0x47: /* G70 */
+	case 0x49: /* G71 */
+	case 0x4b: /* G73 */
+		nv_wr32(priv, 0x400828, 0x07830610);
+		nv_wr32(priv, 0x40082c, 0x0000016A);
+		break;
+	default:
+		break;
+	}
+
+	nv_wr32(priv, 0x400b38, 0x2ffff800);
+	nv_wr32(priv, 0x400b3c, 0x00006000);
+
+	/* Tiling related stuff. */
+	switch (nv_device(priv)->chipset) {
+	case 0x44:
+	case 0x4a:
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b500);
+		break;
+	case 0x46:
+		nv_wr32(priv, 0x400bc4, 0x0000e024);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b520);
+		break;
+	case 0x4c:
+	case 0x4e:
+	case 0x67:
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b540);
+		break;
+	default:
+		break;
+	}
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	/* begin RAM config */
+	vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
+	switch (nv_device(priv)->chipset) {
+	case 0x40:
+		nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400820, 0);
+		nv_wr32(priv, 0x400824, 0);
+		nv_wr32(priv, 0x400864, vramsz);
+		nv_wr32(priv, 0x400868, vramsz);
+		break;
+	default:
+		switch (nv_device(priv)->chipset) {
+		case 0x41:
+		case 0x42:
+		case 0x43:
+		case 0x45:
+		case 0x4e:
+		case 0x44:
+		case 0x4a:
+			nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
+			break;
+		default:
+			nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
+			break;
+		}
+		nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400840, 0);
+		nv_wr32(priv, 0x400844, 0);
+		nv_wr32(priv, 0x4008A0, vramsz);
+		nv_wr32(priv, 0x4008A4, vramsz);
+		break;
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv40_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_gr_ctor,
+		.dtor = _nvkm_gr_dtor,
+		.init = nv40_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
new file mode 100644
index 0000000..d852bd6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
@@ -0,0 +1,24 @@
+#ifndef __NV40_GR_H__
+#define __NV40_GR_H__
+#include <engine/gr.h>
+
+#include <core/device.h>
+struct nvkm_gpuobj;
+
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_gr_class(void *priv)
+{
+	struct nvkm_device *device = nv_device(priv);
+
+	if ((device->chipset & 0xf0) == 0x60)
+		return 1;
+
+	return !(0x0baf & (1 << (device->chipset & 0x0f)));
+}
+
+int  nv40_grctx_init(struct nvkm_device *, u32 *size);
+void nv40_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
new file mode 100644
index 0000000..270d7cd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/timer.h>
+
+struct nv50_gr_priv {
+	struct nvkm_gr base;
+	spinlock_t lock;
+	u32 size;
+};
+
+struct nv50_gr_chan {
+	struct nvkm_gr_chan base;
+};
+
+static u64
+nv50_gr_units(struct nvkm_gr *gr)
+{
+	struct nv50_gr_priv *priv = (void *)gr;
+
+	return nv_rd32(priv, 0x1540);
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 size,
+		    struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nv50_gr_ofuncs = {
+	.ctor = nv50_gr_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv50_gr_sclass[] = {
+	{ 0x0030, &nv50_gr_ofuncs },
+	{ 0x502d, &nv50_gr_ofuncs },
+	{ 0x5039, &nv50_gr_ofuncs },
+	{ 0x5097, &nv50_gr_ofuncs },
+	{ 0x50c0, &nv50_gr_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+g84_gr_sclass[] = {
+	{ 0x0030, &nv50_gr_ofuncs },
+	{ 0x502d, &nv50_gr_ofuncs },
+	{ 0x5039, &nv50_gr_ofuncs },
+	{ 0x50c0, &nv50_gr_ofuncs },
+	{ 0x8297, &nv50_gr_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+gt200_gr_sclass[] = {
+	{ 0x0030, &nv50_gr_ofuncs },
+	{ 0x502d, &nv50_gr_ofuncs },
+	{ 0x5039, &nv50_gr_ofuncs },
+	{ 0x50c0, &nv50_gr_ofuncs },
+	{ 0x8397, &nv50_gr_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+gt215_gr_sclass[] = {
+	{ 0x0030, &nv50_gr_ofuncs },
+	{ 0x502d, &nv50_gr_ofuncs },
+	{ 0x5039, &nv50_gr_ofuncs },
+	{ 0x50c0, &nv50_gr_ofuncs },
+	{ 0x8597, &nv50_gr_ofuncs },
+	{ 0x85c0, &nv50_gr_ofuncs },
+	{}
+};
+
+static struct nvkm_oclass
+mcp89_gr_sclass[] = {
+	{ 0x0030, &nv50_gr_ofuncs },
+	{ 0x502d, &nv50_gr_ofuncs },
+	{ 0x5039, &nv50_gr_ofuncs },
+	{ 0x50c0, &nv50_gr_ofuncs },
+	{ 0x85c0, &nv50_gr_ofuncs },
+	{ 0x8697, &nv50_gr_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv50_gr_priv *priv = (void *)engine;
+	struct nv50_gr_chan *chan;
+	int ret;
+
+	ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size,
+				     0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	return 0;
+}
+
+static struct nvkm_oclass
+nv50_gr_cclass = {
+	.handle = NV_ENGCTX(GR, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_gr_context_ctor,
+		.dtor = _nvkm_gr_context_dtor,
+		.init = _nvkm_gr_context_init,
+		.fini = _nvkm_gr_context_fini,
+		.rd32 = _nvkm_gr_context_rd32,
+		.wr32 = _nvkm_gr_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_bitfield nv50_pgr_status[] = {
+	{ 0x00000001, "BUSY" }, /* set when any bit is set */
+	{ 0x00000002, "DISPATCH" },
+	{ 0x00000004, "UNK2" },
+	{ 0x00000008, "UNK3" },
+	{ 0x00000010, "UNK4" },
+	{ 0x00000020, "UNK5" },
+	{ 0x00000040, "M2MF" },
+	{ 0x00000080, "UNK7" },
+	{ 0x00000100, "CTXPROG" },
+	{ 0x00000200, "VFETCH" },
+	{ 0x00000400, "CCACHE_PREGEOM" },
+	{ 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
+	{ 0x00001000, "VCLIP" },
+	{ 0x00002000, "RATTR_APLANE" },
+	{ 0x00004000, "TRAST" },
+	{ 0x00008000, "CLIPID" },
+	{ 0x00010000, "ZCULL" },
+	{ 0x00020000, "ENG2D" },
+	{ 0x00040000, "RMASK" },
+	{ 0x00080000, "TPC_RAST" },
+	{ 0x00100000, "TPC_PROP" },
+	{ 0x00200000, "TPC_TEX" },
+	{ 0x00400000, "TPC_GEOM" },
+	{ 0x00800000, "TPC_MP" },
+	{ 0x01000000, "ROP" },
+	{}
+};
+
+static const char *const nv50_pgr_vstatus_0[] = {
+	"VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
+	NULL
+};
+
+static const char *const nv50_pgr_vstatus_1[] = {
+	"TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
+};
+
+static const char *const nv50_pgr_vstatus_2[] = {
+	"RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
+	"ROP", NULL
+};
+
+static void
+nvkm_pgr_vstatus_print(struct nv50_gr_priv *priv, int r,
+		       const char *const units[], u32 status)
+{
+	int i;
+
+	nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
+
+	for (i = 0; units[i] && status; i++) {
+		if ((status & 7) == 1)
+			pr_cont(" %s", units[i]);
+		status >>= 3;
+	}
+	if (status)
+		pr_cont(" (invalid: 0x%x)", status);
+	pr_cont("\n");
+}
+
+static int
+g84_gr_tlb_flush(struct nvkm_engine *engine)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(engine);
+	struct nv50_gr_priv *priv = (void *)engine;
+	bool idle, timeout = false;
+	unsigned long flags;
+	u64 start;
+	u32 tmp;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
+
+	start = ptimer->read(ptimer);
+	do {
+		idle = true;
+
+		for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+	} while (!idle &&
+		 !(timeout = ptimer->read(ptimer) - start > 2000000000));
+
+	if (timeout) {
+		nv_error(priv, "PGRAPH TLB flush idle timeout fail\n");
+
+		tmp = nv_rd32(priv, 0x400700);
+		nv_error(priv, "PGRAPH_STATUS  : 0x%08x", tmp);
+		nvkm_bitfield_print(nv50_pgr_status, tmp);
+		pr_cont("\n");
+
+		nvkm_pgr_vstatus_print(priv, 0, nv50_pgr_vstatus_0,
+				       nv_rd32(priv, 0x400380));
+		nvkm_pgr_vstatus_print(priv, 1, nv50_pgr_vstatus_1,
+				       nv_rd32(priv, 0x400384));
+		nvkm_pgr_vstatus_print(priv, 2, nv50_pgr_vstatus_2,
+				       nv_rd32(priv, 0x400388));
+	}
+
+
+	nv_wr32(priv, 0x100c80, 0x00000001);
+	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+		nv_error(priv, "vm flush timeout\n");
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return timeout ? -EBUSY : 0;
+}
+
+static const struct nvkm_bitfield nv50_mp_exec_errors[] = {
+	{ 0x01, "STACK_UNDERFLOW" },
+	{ 0x02, "STACK_MISMATCH" },
+	{ 0x04, "QUADON_ACTIVE" },
+	{ 0x08, "TIMEOUT" },
+	{ 0x10, "INVALID_OPCODE" },
+	{ 0x20, "PM_OVERFLOW" },
+	{ 0x40, "BREAKPOINT" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_mpc_traps[] = {
+	{ 0x0000001, "LOCAL_LIMIT_READ" },
+	{ 0x0000010, "LOCAL_LIMIT_WRITE" },
+	{ 0x0000040, "STACK_LIMIT" },
+	{ 0x0000100, "GLOBAL_LIMIT_READ" },
+	{ 0x0001000, "GLOBAL_LIMIT_WRITE" },
+	{ 0x0010000, "MP0" },
+	{ 0x0020000, "MP1" },
+	{ 0x0040000, "GLOBAL_LIMIT_RED" },
+	{ 0x0400000, "GLOBAL_LIMIT_ATOM" },
+	{ 0x4000000, "MP2" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_tex_traps[] = {
+	{ 0x00000001, "" }, /* any bit set? */
+	{ 0x00000002, "FAULT" },
+	{ 0x00000004, "STORAGE_TYPE_MISMATCH" },
+	{ 0x00000008, "LINEAR_MISMATCH" },
+	{ 0x00000020, "WRONG_MEMTYPE" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_m2mf[] = {
+	{ 0x00000001, "NOTIFY" },
+	{ 0x00000002, "IN" },
+	{ 0x00000004, "OUT" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_vfetch[] = {
+	{ 0x00000001, "FAULT" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_strmout[] = {
+	{ 0x00000001, "FAULT" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_ccache[] = {
+	{ 0x00000001, "FAULT" },
+	{}
+};
+
+/* There must be a *lot* of these. Will take some time to gather them up. */
+const struct nvkm_enum nv50_data_error_names[] = {
+	{ 0x00000003, "INVALID_OPERATION", NULL },
+	{ 0x00000004, "INVALID_VALUE", NULL },
+	{ 0x00000005, "INVALID_ENUM", NULL },
+	{ 0x00000008, "INVALID_OBJECT", NULL },
+	{ 0x00000009, "READ_ONLY_OBJECT", NULL },
+	{ 0x0000000a, "SUPERVISOR_OBJECT", NULL },
+	{ 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
+	{ 0x0000000c, "INVALID_BITFIELD", NULL },
+	{ 0x0000000d, "BEGIN_END_ACTIVE", NULL },
+	{ 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
+	{ 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
+	{ 0x00000010, "RT_DOUBLE_BIND", NULL },
+	{ 0x00000011, "RT_TYPES_MISMATCH", NULL },
+	{ 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
+	{ 0x00000015, "FP_TOO_FEW_REGS", NULL },
+	{ 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
+	{ 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
+	{ 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
+	{ 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
+	{ 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
+	{ 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
+	{ 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
+	{ 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
+	{ 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
+	{ 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
+	{ 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
+	{ 0x00000024, "VP_ZERO_INPUTS", NULL },
+	{ 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
+	{ 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
+	{ 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
+	{ 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
+	{ 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
+	{ 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
+	{ 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
+	{ 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
+	{ 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
+	{ 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
+	{ 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
+	{ 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
+	{ 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
+	{ 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
+	{ 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_intr_name[] = {
+	{ 0x00000001, "NOTIFY" },
+	{ 0x00000002, "COMPUTE_QUERY" },
+	{ 0x00000010, "ILLEGAL_MTHD" },
+	{ 0x00000020, "ILLEGAL_CLASS" },
+	{ 0x00000040, "DOUBLE_NOTIFY" },
+	{ 0x00001000, "CONTEXT_SWITCH" },
+	{ 0x00010000, "BUFFER_NOTIFY" },
+	{ 0x00100000, "DATA_ERROR" },
+	{ 0x00200000, "TRAP" },
+	{ 0x01000000, "SINGLE_STEP" },
+	{}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_prop[] = {
+	{ 0x00000004, "SURF_WIDTH_OVERRUN" },
+	{ 0x00000008, "SURF_HEIGHT_OVERRUN" },
+	{ 0x00000010, "DST2D_FAULT" },
+	{ 0x00000020, "ZETA_FAULT" },
+	{ 0x00000040, "RT_FAULT" },
+	{ 0x00000080, "CUDA_FAULT" },
+	{ 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
+	{ 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
+	{ 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
+	{ 0x00000800, "DST2D_LINEAR_MISMATCH" },
+	{ 0x00001000, "RT_LINEAR_MISMATCH" },
+	{}
+};
+
+static void
+nv50_priv_prop_trap(struct nv50_gr_priv *priv,
+		    u32 ustatus_addr, u32 ustatus, u32 tp)
+{
+	u32 e0c = nv_rd32(priv, ustatus_addr + 0x04);
+	u32 e10 = nv_rd32(priv, ustatus_addr + 0x08);
+	u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c);
+	u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
+	u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
+	u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
+	u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
+
+	/* CUDA memory: l[], g[] or stack. */
+	if (ustatus & 0x00000080) {
+		if (e18 & 0x80000000) {
+			/* g[] read fault? */
+			nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
+					 tp, e14, e10 | ((e18 >> 24) & 0x1f));
+			e18 &= ~0x1f000000;
+		} else if (e18 & 0xc) {
+			/* g[] write fault? */
+			nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
+				 tp, e14, e10 | ((e18 >> 7) & 0x1f));
+			e18 &= ~0x00000f80;
+		} else {
+			nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
+				 tp, e14, e10);
+		}
+		ustatus &= ~0x00000080;
+	}
+	if (ustatus) {
+		nv_error(priv, "TRAP_PROP - TP %d -", tp);
+		nvkm_bitfield_print(nv50_gr_trap_prop, ustatus);
+		pr_cont(" - Address %02x%08x\n", e14, e10);
+	}
+	nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+		 tp, e0c, e18, e1c, e20, e24);
+}
+
+static void
+nv50_priv_mp_trap(struct nv50_gr_priv *priv, int tpid, int display)
+{
+	u32 units = nv_rd32(priv, 0x1540);
+	u32 addr, mp10, status, pc, oplow, ophigh;
+	int i;
+	int mps = 0;
+	for (i = 0; i < 4; i++) {
+		if (!(units & 1 << (i+24)))
+			continue;
+		if (nv_device(priv)->chipset < 0xa0)
+			addr = 0x408200 + (tpid << 12) + (i << 7);
+		else
+			addr = 0x408100 + (tpid << 11) + (i << 7);
+		mp10 = nv_rd32(priv, addr + 0x10);
+		status = nv_rd32(priv, addr + 0x14);
+		if (!status)
+			continue;
+		if (display) {
+			nv_rd32(priv, addr + 0x20);
+			pc = nv_rd32(priv, addr + 0x24);
+			oplow = nv_rd32(priv, addr + 0x70);
+			ophigh = nv_rd32(priv, addr + 0x74);
+			nv_error(priv, "TRAP_MP_EXEC - "
+					"TP %d MP %d:", tpid, i);
+			nvkm_bitfield_print(nv50_mp_exec_errors, status);
+			pr_cont(" at %06x warp %d, opcode %08x %08x\n",
+					pc&0xffffff, pc >> 24,
+					oplow, ophigh);
+		}
+		nv_wr32(priv, addr + 0x10, mp10);
+		nv_wr32(priv, addr + 0x14, 0);
+		mps++;
+	}
+	if (!mps && display)
+		nv_error(priv, "TRAP_MP_EXEC - TP %d: "
+				"No MPs claiming errors?\n", tpid);
+}
+
+static void
+nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old,
+		  u32 ustatus_new, int display, const char *name)
+{
+	int tps = 0;
+	u32 units = nv_rd32(priv, 0x1540);
+	int i, r;
+	u32 ustatus_addr, ustatus;
+	for (i = 0; i < 16; i++) {
+		if (!(units & (1 << i)))
+			continue;
+		if (nv_device(priv)->chipset < 0xa0)
+			ustatus_addr = ustatus_old + (i << 12);
+		else
+			ustatus_addr = ustatus_new + (i << 11);
+		ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
+		if (!ustatus)
+			continue;
+		tps++;
+		switch (type) {
+		case 6: /* texture error... unknown for now */
+			if (display) {
+				nv_error(priv, "magic set %d:\n", i);
+				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
+					nv_error(priv, "\t0x%08x: 0x%08x\n", r,
+						nv_rd32(priv, r));
+				if (ustatus) {
+					nv_error(priv, "%s - TP%d:", name, i);
+					nvkm_bitfield_print(nv50_tex_traps,
+							       ustatus);
+					pr_cont("\n");
+					ustatus = 0;
+				}
+			}
+			break;
+		case 7: /* MP error */
+			if (ustatus & 0x04030000) {
+				nv50_priv_mp_trap(priv, i, display);
+				ustatus &= ~0x04030000;
+			}
+			if (ustatus && display) {
+				nv_error(priv, "%s - TP%d:", name, i);
+				nvkm_bitfield_print(nv50_mpc_traps, ustatus);
+				pr_cont("\n");
+				ustatus = 0;
+			}
+			break;
+		case 8: /* PROP error */
+			if (display)
+				nv50_priv_prop_trap(
+						priv, ustatus_addr, ustatus, i);
+			ustatus = 0;
+			break;
+		}
+		if (ustatus) {
+			if (display)
+				nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+		}
+		nv_wr32(priv, ustatus_addr, 0xc0000000);
+	}
+
+	if (!tps && display)
+		nv_warn(priv, "%s - No TPs claiming errors?\n", name);
+}
+
+static int
+nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display,
+		     int chid, u64 inst, struct nvkm_object *engctx)
+{
+	u32 status = nv_rd32(priv, 0x400108);
+	u32 ustatus;
+
+	if (!status && display) {
+		nv_error(priv, "TRAP: no units reporting traps?\n");
+		return 1;
+	}
+
+	/* DISPATCH: Relays commands to other units and handles NOTIFY,
+	 * COND, QUERY. If you get a trap from it, the command is still stuck
+	 * in DISPATCH and you need to do something about it. */
+	if (status & 0x001) {
+		ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
+		if (!ustatus && display) {
+			nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
+		}
+
+		nv_wr32(priv, 0x400500, 0x00000000);
+
+		/* Known to be triggered by screwed up NOTIFY and COND... */
+		if (ustatus & 0x00000001) {
+			u32 addr = nv_rd32(priv, 0x400808);
+			u32 subc = (addr & 0x00070000) >> 16;
+			u32 mthd = (addr & 0x00001ffc);
+			u32 datal = nv_rd32(priv, 0x40080c);
+			u32 datah = nv_rd32(priv, 0x400810);
+			u32 class = nv_rd32(priv, 0x400814);
+			u32 r848 = nv_rd32(priv, 0x400848);
+
+			nv_error(priv, "TRAP DISPATCH_FAULT\n");
+			if (display && (addr & 0x80000000)) {
+				nv_error(priv,
+					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
+					 chid, inst,
+					 nvkm_client_name(engctx), subc,
+					 class, mthd, datah, datal, addr, r848);
+			} else
+			if (display) {
+				nv_error(priv, "no stuck command?\n");
+			}
+
+			nv_wr32(priv, 0x400808, 0);
+			nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
+			nv_wr32(priv, 0x400848, 0);
+			ustatus &= ~0x00000001;
+		}
+
+		if (ustatus & 0x00000002) {
+			u32 addr = nv_rd32(priv, 0x40084c);
+			u32 subc = (addr & 0x00070000) >> 16;
+			u32 mthd = (addr & 0x00001ffc);
+			u32 data = nv_rd32(priv, 0x40085c);
+			u32 class = nv_rd32(priv, 0x400814);
+
+			nv_error(priv, "TRAP DISPATCH_QUERY\n");
+			if (display && (addr & 0x80000000)) {
+				nv_error(priv,
+					 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
+					 chid, inst,
+					 nvkm_client_name(engctx), subc,
+					 class, mthd, data, addr);
+			} else
+			if (display) {
+				nv_error(priv, "no stuck command?\n");
+			}
+
+			nv_wr32(priv, 0x40084c, 0);
+			ustatus &= ~0x00000002;
+		}
+
+		if (ustatus && display) {
+			nv_error(priv, "TRAP_DISPATCH (unknown "
+				      "0x%08x)\n", ustatus);
+		}
+
+		nv_wr32(priv, 0x400804, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x001);
+		status &= ~0x001;
+		if (!status)
+			return 0;
+	}
+
+	/* M2MF: Memory to memory copy engine. */
+	if (status & 0x002) {
+		u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
+		if (display) {
+			nv_error(priv, "TRAP_M2MF");
+			nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus);
+			pr_cont("\n");
+			nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
+				nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
+
+		}
+
+		/* No sane way found yet -- just reset the bugger. */
+		nv_wr32(priv, 0x400040, 2);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x406800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x002);
+		status &= ~0x002;
+	}
+
+	/* VFETCH: Fetches data from vertex buffers. */
+	if (status & 0x004) {
+		u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
+		if (display) {
+			nv_error(priv, "TRAP_VFETCH");
+			nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus);
+			pr_cont("\n");
+			nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
+				nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
+		}
+
+		nv_wr32(priv, 0x400c04, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x004);
+		status &= ~0x004;
+	}
+
+	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
+	if (status & 0x008) {
+		ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
+		if (display) {
+			nv_error(priv, "TRAP_STRMOUT");
+			nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus);
+			pr_cont("\n");
+			nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
+				nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
+
+		}
+
+		/* No sane way found yet -- just reset the bugger. */
+		nv_wr32(priv, 0x400040, 0x80);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x401800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x008);
+		status &= ~0x008;
+	}
+
+	/* CCACHE: Handles code and c[] caches and fills them. */
+	if (status & 0x010) {
+		ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
+		if (display) {
+			nv_error(priv, "TRAP_CCACHE");
+			nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus);
+			pr_cont("\n");
+			nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
+				     " %08x %08x %08x\n",
+				nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
+				nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
+				nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
+				nv_rd32(priv, 0x40501c));
+
+		}
+
+		nv_wr32(priv, 0x405018, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x010);
+		status &= ~0x010;
+	}
+
+	/* Unknown, not seen yet... 0x402000 is the only trap status reg
+	 * remaining, so try to handle it anyway. Perhaps related to that
+	 * unknown DMA slot on tesla? */
+	if (status & 0x20) {
+		ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
+		if (display)
+			nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
+		nv_wr32(priv, 0x402000, 0xc0000000);
+		/* no status modifiction on purpose */
+	}
+
+	/* TEXTURE: CUDA texturing units */
+	if (status & 0x040) {
+		nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
+				    "TRAP_TEXTURE");
+		nv_wr32(priv, 0x400108, 0x040);
+		status &= ~0x040;
+	}
+
+	/* MP: CUDA execution engines. */
+	if (status & 0x080) {
+		nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
+				    "TRAP_MP");
+		nv_wr32(priv, 0x400108, 0x080);
+		status &= ~0x080;
+	}
+
+	/* PROP:  Handles TP-initiated uncached memory accesses:
+	 * l[], g[], stack, 2d surfaces, render targets. */
+	if (status & 0x100) {
+		nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
+				    "TRAP_PROP");
+		nv_wr32(priv, 0x400108, 0x100);
+		status &= ~0x100;
+	}
+
+	if (status) {
+		if (display)
+			nv_error(priv, "TRAP: unknown 0x%08x\n", status);
+		nv_wr32(priv, 0x400108, status);
+	}
+
+	return 1;
+}
+
+static void
+nv50_gr_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct nvkm_handle *handle = NULL;
+	struct nv50_gr_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff;
+	u32 addr = nv_rd32(priv, 0x400704);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 class = nv_rd32(priv, 0x400814);
+	u32 show = stat, show_bitfield = stat;
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & 0x00000010) {
+		handle = nvkm_handle_get_class(engctx, class);
+		if (handle && !nv_call(handle->object, mthd, data))
+			show &= ~0x00000010;
+		nvkm_handle_put(handle);
+	}
+
+	if (show & 0x00100000) {
+		u32 ecode = nv_rd32(priv, 0x400110);
+		nv_error(priv, "DATA_ERROR ");
+		nvkm_enum_print(nv50_data_error_names, ecode);
+		pr_cont("\n");
+		show_bitfield &= ~0x00100000;
+	}
+
+	if (stat & 0x00200000) {
+		if (!nv50_gr_trap_handler(priv, show, chid, (u64)inst << 12,
+					  engctx))
+			show &= ~0x00200000;
+		show_bitfield &= ~0x00200000;
+	}
+
+	nv_wr32(priv, 0x400100, stat);
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	if (show) {
+		show &= show_bitfield;
+		if (show) {
+			nv_error(priv, "%s", "");
+			nvkm_bitfield_print(nv50_gr_intr_name, show);
+			pr_cont("\n");
+		}
+		nv_error(priv,
+			 "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			 chid, (u64)inst << 12, nvkm_client_name(engctx),
+			 subc, class, mthd, data);
+	}
+
+	if (nv_rd32(priv, 0x400824) & (1 << 31))
+		nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv50_gr_priv *priv;
+	int ret;
+
+	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00201000;
+	nv_subdev(priv)->intr = nv50_gr_intr;
+	nv_engine(priv)->cclass = &nv50_gr_cclass;
+
+	priv->base.units = nv50_gr_units;
+
+	switch (nv_device(priv)->chipset) {
+	case 0x50:
+		nv_engine(priv)->sclass = nv50_gr_sclass;
+		break;
+	case 0x84:
+	case 0x86:
+	case 0x92:
+	case 0x94:
+	case 0x96:
+	case 0x98:
+		nv_engine(priv)->sclass = g84_gr_sclass;
+		break;
+	case 0xa0:
+	case 0xaa:
+	case 0xac:
+		nv_engine(priv)->sclass = gt200_gr_sclass;
+		break;
+	case 0xa3:
+	case 0xa5:
+	case 0xa8:
+		nv_engine(priv)->sclass = gt215_gr_sclass;
+		break;
+	case 0xaf:
+		nv_engine(priv)->sclass = mcp89_gr_sclass;
+		break;
+
+	}
+
+	/* unfortunate hw bug workaround... */
+	if (nv_device(priv)->chipset != 0x50 &&
+	    nv_device(priv)->chipset != 0xac)
+		nv_engine(priv)->tlb_flush = g84_gr_tlb_flush;
+
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+static int
+nv50_gr_init(struct nvkm_object *object)
+{
+	struct nv50_gr_priv *priv = (void *)object;
+	int ret, units, i;
+
+	ret = nvkm_gr_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
+	nv_wr32(priv, 0x40008c, 0x00000004);
+
+	/* reset/enable traps and interrupts */
+	nv_wr32(priv, 0x400804, 0xc0000000);
+	nv_wr32(priv, 0x406800, 0xc0000000);
+	nv_wr32(priv, 0x400c04, 0xc0000000);
+	nv_wr32(priv, 0x401800, 0xc0000000);
+	nv_wr32(priv, 0x405018, 0xc0000000);
+	nv_wr32(priv, 0x402000, 0xc0000000);
+
+	units = nv_rd32(priv, 0x001540);
+	for (i = 0; i < 16; i++) {
+		if (!(units & (1 << i)))
+			continue;
+
+		if (nv_device(priv)->chipset < 0xa0) {
+			nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
+		} else {
+			nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
+		}
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	/* upload context program, initialise ctxctl defaults */
+	ret = nv50_grctx_init(nv_device(priv), &priv->size);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x400824, 0x00000000);
+	nv_wr32(priv, 0x400828, 0x00000000);
+	nv_wr32(priv, 0x40082c, 0x00000000);
+	nv_wr32(priv, 0x400830, 0x00000000);
+	nv_wr32(priv, 0x40032c, 0x00000000);
+	nv_wr32(priv, 0x400330, 0x00000000);
+
+	/* some unknown zcull magic */
+	switch (nv_device(priv)->chipset & 0xf0) {
+	case 0x50:
+	case 0x80:
+	case 0x90:
+		nv_wr32(priv, 0x402ca8, 0x00000800);
+		break;
+	case 0xa0:
+	default:
+		if (nv_device(priv)->chipset == 0xa0 ||
+		    nv_device(priv)->chipset == 0xaa ||
+		    nv_device(priv)->chipset == 0xac) {
+			nv_wr32(priv, 0x402ca8, 0x00000802);
+		} else {
+			nv_wr32(priv, 0x402cc0, 0x00000000);
+			nv_wr32(priv, 0x402ca8, 0x00000002);
+		}
+
+		break;
+	}
+
+	/* zero out zcull regions */
+	for (i = 0; i < 8; i++) {
+		nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000);
+		nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000);
+		nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000);
+		nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000);
+	}
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_gr_oclass = {
+	.handle = NV_ENGINE(GR, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_gr_ctor,
+		.dtor = _nvkm_gr_dtor,
+		.init = nv50_gr_init,
+		.fini = _nvkm_gr_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
new file mode 100644
index 0000000..bcf786f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
@@ -0,0 +1,9 @@
+#ifndef __NV50_GR_H__
+#define __NV50_GR_H__
+#include <engine/gr.h>
+struct nvkm_device;
+struct nvkm_gpuobj;
+
+int  nv50_grctx_init(struct nvkm_device *, u32 *size);
+void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h
new file mode 100644
index 0000000..90a9873
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h
@@ -0,0 +1,274 @@
+#ifndef __NVKM_GR_REGS_H__
+#define __NVKM_GR_REGS_H__
+
+#define NV04_PGRAPH_DEBUG_0                                0x00400080
+#define NV04_PGRAPH_DEBUG_1                                0x00400084
+#define NV04_PGRAPH_DEBUG_2                                0x00400088
+#define NV04_PGRAPH_DEBUG_3                                0x0040008c
+#define NV10_PGRAPH_DEBUG_4                                0x00400090
+#define NV03_PGRAPH_INTR                                   0x00400100
+#define NV03_PGRAPH_NSTATUS                                0x00400104
+#    define NV04_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<11)
+#    define NV04_PGRAPH_NSTATUS_INVALID_STATE                 (1<<12)
+#    define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<13)
+#    define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<14)
+#    define NV10_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<23)
+#    define NV10_PGRAPH_NSTATUS_INVALID_STATE                 (1<<24)
+#    define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<25)
+#    define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<26)
+#define NV03_PGRAPH_NSOURCE                                0x00400108
+#    define NV03_PGRAPH_NSOURCE_NOTIFICATION                   (1<<0)
+#    define NV03_PGRAPH_NSOURCE_DATA_ERROR                     (1<<1)
+#    define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR               (1<<2)
+#    define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION                (1<<3)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_COLOR                    (1<<4)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_ZETA                     (1<<5)
+#    define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD                   (1<<6)
+#    define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION               (1<<7)
+#    define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION               (1<<8)
+#    define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION               (1<<9)
+#    define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION               (1<<10)
+#    define NV03_PGRAPH_NSOURCE_STATE_INVALID                 (1<<11)
+#    define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY                 (1<<12)
+#    define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE                 (1<<13)
+#    define NV03_PGRAPH_NSOURCE_METHOD_CNT                    (1<<14)
+#    define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION              (1<<15)
+#    define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION            (1<<16)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A                   (1<<17)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B                   (1<<18)
+#define NV03_PGRAPH_INTR_EN                                0x00400140
+#define NV40_PGRAPH_INTR_EN                                0x0040013C
+#    define NV_PGRAPH_INTR_NOTIFY                              (1<<0)
+#    define NV_PGRAPH_INTR_MISSING_HW                          (1<<4)
+#    define NV_PGRAPH_INTR_CONTEXT_SWITCH                     (1<<12)
+#    define NV_PGRAPH_INTR_BUFFER_NOTIFY                      (1<<16)
+#    define NV_PGRAPH_INTR_ERROR                              (1<<20)
+#define NV10_PGRAPH_CTX_CONTROL                            0x00400144
+#define NV10_PGRAPH_CTX_USER                               0x00400148
+#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
+#define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160	\
+							   + 0x4*(i) + 0x20*(j))
+#define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
+#define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
+#define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
+#define NV04_PGRAPH_CTX_CONTROL                            0x00400170
+#define NV04_PGRAPH_CTX_USER                               0x00400174
+#define NV04_PGRAPH_CTX_CACHE1                             0x00400180
+#define NV03_PGRAPH_CTX_CONTROL                            0x00400190
+#define NV03_PGRAPH_CTX_USER                               0x00400194
+#define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
+#define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
+#define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
+#define NV40_PGRAPH_CTXCTL_0304                            0x00400304
+#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK              0xff000000
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT                     24
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK              0x00ffffff
+#define NV40_PGRAPH_CTXCTL_0310                            0x00400310
+#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE                  0x00000020
+#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD                  0x00000040
+#define NV40_PGRAPH_CTXCTL_030C                            0x0040030c
+#define NV40_PGRAPH_CTXCTL_UCODE_INDEX                     0x00400324
+#define NV40_PGRAPH_CTXCTL_UCODE_DATA                      0x00400328
+#define NV40_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV40_PGRAPH_CTXCTL_CUR_LOADED                      0x01000000
+#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE                    0x000FFFFF
+#define NV40_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x000fffff
+#define NV50_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV50_PGRAPH_CTXCTL_CUR_LOADED                      0x80000000
+#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE                    0x00ffffff
+#define NV50_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x00ffffff
+#define NV03_PGRAPH_ABS_X_RAM                              0x00400400
+#define NV03_PGRAPH_ABS_Y_RAM                              0x00400480
+#define NV03_PGRAPH_X_MISC                                 0x00400500
+#define NV03_PGRAPH_Y_MISC                                 0x00400504
+#define NV04_PGRAPH_VALID1                                 0x00400508
+#define NV04_PGRAPH_SOURCE_COLOR                           0x0040050C
+#define NV04_PGRAPH_MISC24_0                               0x00400510
+#define NV03_PGRAPH_XY_LOGIC_MISC0                         0x00400514
+#define NV03_PGRAPH_XY_LOGIC_MISC1                         0x00400518
+#define NV03_PGRAPH_XY_LOGIC_MISC2                         0x0040051C
+#define NV03_PGRAPH_XY_LOGIC_MISC3                         0x00400520
+#define NV03_PGRAPH_CLIPX_0                                0x00400524
+#define NV03_PGRAPH_CLIPX_1                                0x00400528
+#define NV03_PGRAPH_CLIPY_0                                0x0040052C
+#define NV03_PGRAPH_CLIPY_1                                0x00400530
+#define NV03_PGRAPH_ABS_ICLIP_XMAX                         0x00400534
+#define NV03_PGRAPH_ABS_ICLIP_YMAX                         0x00400538
+#define NV03_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C
+#define NV03_PGRAPH_ABS_UCLIP_YMIN                         0x00400540
+#define NV03_PGRAPH_ABS_UCLIP_XMAX                         0x00400544
+#define NV03_PGRAPH_ABS_UCLIP_YMAX                         0x00400548
+#define NV03_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560
+#define NV03_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564
+#define NV03_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568
+#define NV03_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C
+#define NV04_PGRAPH_MISC24_1                               0x00400570
+#define NV04_PGRAPH_MISC24_2                               0x00400574
+#define NV04_PGRAPH_VALID2                                 0x00400578
+#define NV04_PGRAPH_PASSTHRU_0                             0x0040057C
+#define NV04_PGRAPH_PASSTHRU_1                             0x00400580
+#define NV04_PGRAPH_PASSTHRU_2                             0x00400584
+#define NV10_PGRAPH_DIMX_TEXTURE                           0x00400588
+#define NV10_PGRAPH_WDIMX_TEXTURE                          0x0040058C
+#define NV04_PGRAPH_COMBINE_0_ALPHA                        0x00400590
+#define NV04_PGRAPH_COMBINE_0_COLOR                        0x00400594
+#define NV04_PGRAPH_COMBINE_1_ALPHA                        0x00400598
+#define NV04_PGRAPH_COMBINE_1_COLOR                        0x0040059C
+#define NV04_PGRAPH_FORMAT_0                               0x004005A8
+#define NV04_PGRAPH_FORMAT_1                               0x004005AC
+#define NV04_PGRAPH_FILTER_0                               0x004005B0
+#define NV04_PGRAPH_FILTER_1                               0x004005B4
+#define NV03_PGRAPH_MONO_COLOR0                            0x00400600
+#define NV04_PGRAPH_ROP3                                   0x00400604
+#define NV04_PGRAPH_BETA_AND                               0x00400608
+#define NV04_PGRAPH_BETA_PREMULT                           0x0040060C
+#define NV04_PGRAPH_LIMIT_VIOL_PIX                         0x00400610
+#define NV04_PGRAPH_FORMATS                                0x00400618
+#define NV10_PGRAPH_DEBUG_2                                0x00400620
+#define NV04_PGRAPH_BOFFSET0                               0x00400640
+#define NV04_PGRAPH_BOFFSET1                               0x00400644
+#define NV04_PGRAPH_BOFFSET2                               0x00400648
+#define NV04_PGRAPH_BOFFSET3                               0x0040064C
+#define NV04_PGRAPH_BOFFSET4                               0x00400650
+#define NV04_PGRAPH_BOFFSET5                               0x00400654
+#define NV04_PGRAPH_BBASE0                                 0x00400658
+#define NV04_PGRAPH_BBASE1                                 0x0040065C
+#define NV04_PGRAPH_BBASE2                                 0x00400660
+#define NV04_PGRAPH_BBASE3                                 0x00400664
+#define NV04_PGRAPH_BBASE4                                 0x00400668
+#define NV04_PGRAPH_BBASE5                                 0x0040066C
+#define NV04_PGRAPH_BPITCH0                                0x00400670
+#define NV04_PGRAPH_BPITCH1                                0x00400674
+#define NV04_PGRAPH_BPITCH2                                0x00400678
+#define NV04_PGRAPH_BPITCH3                                0x0040067C
+#define NV04_PGRAPH_BPITCH4                                0x00400680
+#define NV04_PGRAPH_BLIMIT0                                0x00400684
+#define NV04_PGRAPH_BLIMIT1                                0x00400688
+#define NV04_PGRAPH_BLIMIT2                                0x0040068C
+#define NV04_PGRAPH_BLIMIT3                                0x00400690
+#define NV04_PGRAPH_BLIMIT4                                0x00400694
+#define NV04_PGRAPH_BLIMIT5                                0x00400698
+#define NV04_PGRAPH_BSWIZZLE2                              0x0040069C
+#define NV04_PGRAPH_BSWIZZLE5                              0x004006A0
+#define NV03_PGRAPH_STATUS                                 0x004006B0
+#define NV04_PGRAPH_STATUS                                 0x00400700
+#    define NV40_PGRAPH_STATUS_SYNC_STALL                  0x00004000
+#define NV04_PGRAPH_TRAPPED_ADDR                           0x00400704
+#define NV04_PGRAPH_TRAPPED_DATA                           0x00400708
+#define NV04_PGRAPH_SURFACE                                0x0040070C
+#define NV10_PGRAPH_TRAPPED_DATA_HIGH                      0x0040070C
+#define NV04_PGRAPH_STATE                                  0x00400710
+#define NV10_PGRAPH_SURFACE                                0x00400710
+#define NV04_PGRAPH_NOTIFY                                 0x00400714
+#define NV10_PGRAPH_STATE                                  0x00400714
+#define NV10_PGRAPH_NOTIFY                                 0x00400718
+
+#define NV04_PGRAPH_FIFO                                   0x00400720
+
+#define NV04_PGRAPH_BPIXEL                                 0x00400724
+#define NV10_PGRAPH_RDI_INDEX                              0x00400750
+#define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
+#define NV10_PGRAPH_RDI_DATA                               0x00400754
+#define NV04_PGRAPH_DMA_PITCH                              0x00400760
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
+#define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
+#define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
+#define NV10_PGRAPH_DMA_PITCH                              0x00400770
+#define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
+#define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
+#define NV20_PGRAPH_CHANNEL_CTX_TABLE                      0x00400780
+#define NV20_PGRAPH_CHANNEL_CTX_POINTER                    0x00400784
+#define NV20_PGRAPH_CHANNEL_CTX_XFER                       0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD                  0x00000001
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE                  0x00000002
+#define NV04_PGRAPH_PATT_COLOR0                            0x00400800
+#define NV04_PGRAPH_PATT_COLOR1                            0x00400804
+#define NV04_PGRAPH_PATTERN                                0x00400808
+#define NV04_PGRAPH_PATTERN_SHAPE                          0x00400810
+#define NV04_PGRAPH_CHROMA                                 0x00400814
+#define NV04_PGRAPH_CONTROL0                               0x00400818
+#define NV04_PGRAPH_CONTROL1                               0x0040081C
+#define NV04_PGRAPH_CONTROL2                               0x00400820
+#define NV04_PGRAPH_BLEND                                  0x00400824
+#define NV04_PGRAPH_STORED_FMT                             0x00400830
+#define NV04_PGRAPH_PATT_COLORRAM                          0x00400900
+#define NV20_PGRAPH_TILE(i)                                (0x00400900 + (i*16))
+#define NV20_PGRAPH_TLIMIT(i)                              (0x00400904 + (i*16))
+#define NV20_PGRAPH_TSIZE(i)                               (0x00400908 + (i*16))
+#define NV20_PGRAPH_TSTATUS(i)                             (0x0040090C + (i*16))
+#define NV20_PGRAPH_ZCOMP(i)                               (0x00400980 + 4*(i))
+#define NV41_PGRAPH_ZCOMP0(i)                              (0x004009c0 + 4*(i))
+#define NV10_PGRAPH_TILE(i)                                (0x00400B00 + (i*16))
+#define NV10_PGRAPH_TLIMIT(i)                              (0x00400B04 + (i*16))
+#define NV10_PGRAPH_TSIZE(i)                               (0x00400B08 + (i*16))
+#define NV10_PGRAPH_TSTATUS(i)                             (0x00400B0C + (i*16))
+#define NV04_PGRAPH_U_RAM                                  0x00400D00
+#define NV47_PGRAPH_TILE(i)                                (0x00400D00 + (i*16))
+#define NV47_PGRAPH_TLIMIT(i)                              (0x00400D04 + (i*16))
+#define NV47_PGRAPH_TSIZE(i)                               (0x00400D08 + (i*16))
+#define NV47_PGRAPH_TSTATUS(i)                             (0x00400D0C + (i*16))
+#define NV04_PGRAPH_V_RAM                                  0x00400D40
+#define NV04_PGRAPH_W_RAM                                  0x00400D80
+#define NV47_PGRAPH_ZCOMP0(i)                              (0x00400e00 + 4*(i))
+#define NV10_PGRAPH_COMBINER0_IN_ALPHA                     0x00400E40
+#define NV10_PGRAPH_COMBINER1_IN_ALPHA                     0x00400E44
+#define NV10_PGRAPH_COMBINER0_IN_RGB                       0x00400E48
+#define NV10_PGRAPH_COMBINER1_IN_RGB                       0x00400E4C
+#define NV10_PGRAPH_COMBINER_COLOR0                        0x00400E50
+#define NV10_PGRAPH_COMBINER_COLOR1                        0x00400E54
+#define NV10_PGRAPH_COMBINER0_OUT_ALPHA                    0x00400E58
+#define NV10_PGRAPH_COMBINER1_OUT_ALPHA                    0x00400E5C
+#define NV10_PGRAPH_COMBINER0_OUT_RGB                      0x00400E60
+#define NV10_PGRAPH_COMBINER1_OUT_RGB                      0x00400E64
+#define NV10_PGRAPH_COMBINER_FINAL0                        0x00400E68
+#define NV10_PGRAPH_COMBINER_FINAL1                        0x00400E6C
+#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL                  0x00400F00
+#define NV10_PGRAPH_WINDOWCLIP_VERTICAL                    0x00400F20
+#define NV10_PGRAPH_XFMODE0                                0x00400F40
+#define NV10_PGRAPH_XFMODE1                                0x00400F44
+#define NV10_PGRAPH_GLOBALSTATE0                           0x00400F48
+#define NV10_PGRAPH_GLOBALSTATE1                           0x00400F4C
+#define NV10_PGRAPH_PIPE_ADDRESS                           0x00400F50
+#define NV10_PGRAPH_PIPE_DATA                              0x00400F54
+#define NV04_PGRAPH_DMA_START_0                            0x00401000
+#define NV04_PGRAPH_DMA_START_1                            0x00401004
+#define NV04_PGRAPH_DMA_LENGTH                             0x00401008
+#define NV04_PGRAPH_DMA_MISC                               0x0040100C
+#define NV04_PGRAPH_DMA_DATA_0                             0x00401020
+#define NV04_PGRAPH_DMA_DATA_1                             0x00401024
+#define NV04_PGRAPH_DMA_RM                                 0x00401030
+#define NV04_PGRAPH_DMA_A_XLATE_INST                       0x00401040
+#define NV04_PGRAPH_DMA_A_CONTROL                          0x00401044
+#define NV04_PGRAPH_DMA_A_LIMIT                            0x00401048
+#define NV04_PGRAPH_DMA_A_TLB_PTE                          0x0040104C
+#define NV04_PGRAPH_DMA_A_TLB_TAG                          0x00401050
+#define NV04_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054
+#define NV04_PGRAPH_DMA_A_OFFSET                           0x00401058
+#define NV04_PGRAPH_DMA_A_SIZE                             0x0040105C
+#define NV04_PGRAPH_DMA_A_Y_SIZE                           0x00401060
+#define NV04_PGRAPH_DMA_B_XLATE_INST                       0x00401080
+#define NV04_PGRAPH_DMA_B_CONTROL                          0x00401084
+#define NV04_PGRAPH_DMA_B_LIMIT                            0x00401088
+#define NV04_PGRAPH_DMA_B_TLB_PTE                          0x0040108C
+#define NV04_PGRAPH_DMA_B_TLB_TAG                          0x00401090
+#define NV04_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094
+#define NV04_PGRAPH_DMA_B_OFFSET                           0x00401098
+#define NV04_PGRAPH_DMA_B_SIZE                             0x0040109C
+#define NV04_PGRAPH_DMA_B_Y_SIZE                           0x004010A0
+#define NV47_PGRAPH_ZCOMP1(i)                              (0x004068c0 + 4*(i))
+#define NV40_PGRAPH_TILE1(i)                               (0x00406900 + (i*16))
+#define NV40_PGRAPH_TLIMIT1(i)                             (0x00406904 + (i*16))
+#define NV40_PGRAPH_TSIZE1(i)                              (0x00406908 + (i*16))
+#define NV40_PGRAPH_TSTATUS1(i)                            (0x0040690C + (i*16))
+#define NV40_PGRAPH_ZCOMP1(i)                              (0x00406980 + 4*(i))
+#define NV41_PGRAPH_ZCOMP1(i)                              (0x004069c0 + 4*(i))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild
new file mode 100644
index 0000000..61b7b5f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild
@@ -0,0 +1,5 @@
+nvkm-y += nvkm/engine/mpeg/nv31.o
+nvkm-y += nvkm/engine/mpeg/nv40.o
+nvkm-y += nvkm/engine/mpeg/nv44.o
+nvkm-y += nvkm/engine/mpeg/nv50.o
+nvkm-y += nvkm/engine/mpeg/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c
new file mode 100644
index 0000000..0df889f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+struct g84_mpeg_priv {
+	struct nvkm_mpeg base;
+};
+
+struct g84_mpeg_chan {
+	struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_mpeg_sclass[] = {
+	{ 0x8274, &nv50_mpeg_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_mpeg_context_ctor,
+		.dtor = _nvkm_mpeg_context_dtor,
+		.init = _nvkm_mpeg_context_init,
+		.fini = _nvkm_mpeg_context_fini,
+		.rd32 = _nvkm_mpeg_context_rd32,
+		.wr32 = _nvkm_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct g84_mpeg_priv *priv;
+	int ret;
+
+	ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv50_mpeg_intr;
+	nv_engine(priv)->cclass = &g84_mpeg_cclass;
+	nv_engine(priv)->sclass = g84_mpeg_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+g84_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_mpeg_ctor,
+		.dtor = _nvkm_mpeg_dtor,
+		.init = nv50_mpeg_init,
+		.fini = _nvkm_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
new file mode 100644
index 0000000..b5bef07
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv31.h"
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/instmem.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv31_mpeg_object_ctor(struct nvkm_object *parent,
+		      struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *data, u32 size,
+		      struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 20, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+static int
+nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(object);
+	struct nv31_mpeg_priv *priv = (void *)object->engine;
+	u32 inst = *(u32 *)arg << 4;
+	u32 dma0 = nv_ro32(imem, inst + 0);
+	u32 dma1 = nv_ro32(imem, inst + 4);
+	u32 dma2 = nv_ro32(imem, inst + 8);
+	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+	u32 size = dma1 + 1;
+
+	/* only allow linear DMA objects */
+	if (!(dma0 & 0x00002000))
+		return -EINVAL;
+
+	if (mthd == 0x0190) {
+		/* DMA_CMD */
+		nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0);
+		nv_wr32(priv, 0x00b334, base);
+		nv_wr32(priv, 0x00b324, size);
+	} else
+	if (mthd == 0x01a0) {
+		/* DMA_DATA */
+		nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0);
+		nv_wr32(priv, 0x00b360, base);
+		nv_wr32(priv, 0x00b364, size);
+	} else {
+		/* DMA_IMAGE, VRAM only */
+		if (dma0 & 0x00030000)
+			return -EINVAL;
+
+		nv_wr32(priv, 0x00b370, base);
+		nv_wr32(priv, 0x00b374, size);
+	}
+
+	return 0;
+}
+
+struct nvkm_ofuncs
+nv31_mpeg_ofuncs = {
+	.ctor = nv31_mpeg_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_omthds
+nv31_mpeg_omthds[] = {
+	{ 0x0190, 0x0190, nv31_mpeg_mthd_dma },
+	{ 0x01a0, 0x01a0, nv31_mpeg_mthd_dma },
+	{ 0x01b0, 0x01b0, nv31_mpeg_mthd_dma },
+	{}
+};
+
+struct nvkm_oclass
+nv31_mpeg_sclass[] = {
+	{ 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv31_mpeg_context_ctor(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nv31_mpeg_priv *priv = (void *)engine;
+	struct nv31_mpeg_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+	if (priv->chan) {
+		spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+		nvkm_object_destroy(&chan->base);
+		*pobject = NULL;
+		return -EBUSY;
+	}
+	priv->chan = chan;
+	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+	return 0;
+}
+
+static void
+nv31_mpeg_context_dtor(struct nvkm_object *object)
+{
+	struct nv31_mpeg_priv *priv = (void *)object->engine;
+	struct nv31_mpeg_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+	priv->chan = NULL;
+	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+	nvkm_object_destroy(&chan->base);
+}
+
+struct nvkm_oclass
+nv31_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x31),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv31_mpeg_context_ctor,
+		.dtor = nv31_mpeg_context_dtor,
+		.init = nvkm_object_init,
+		.fini = nvkm_object_fini,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+void
+nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i)
+{
+	struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+	struct nv31_mpeg_priv *priv = (void *)engine;
+
+	nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
+	nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
+	nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+void
+nv31_mpeg_intr(struct nvkm_subdev *subdev)
+{
+	struct nv31_mpeg_priv *priv = (void *)subdev;
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_handle *handle;
+	struct nvkm_object *engctx;
+	u32 stat = nv_rd32(priv, 0x00b100);
+	u32 type = nv_rd32(priv, 0x00b230);
+	u32 mthd = nv_rd32(priv, 0x00b234);
+	u32 data = nv_rd32(priv, 0x00b238);
+	u32 show = stat;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+	engctx = nv_object(priv->chan);
+
+	if (stat & 0x01000000) {
+		/* happens on initial binding of the object */
+		if (type == 0x00000020 && mthd == 0x0000) {
+			nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
+			show &= ~0x01000000;
+		}
+
+		if (type == 0x00000010 && engctx) {
+			handle = nvkm_handle_get_class(engctx, 0x3174);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~0x01000000;
+			nvkm_handle_put(handle);
+		}
+	}
+
+	nv_wr32(priv, 0x00b100, stat);
+	nv_wr32(priv, 0x00b230, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 pfifo->chid(pfifo, engctx),
+			 nvkm_client_name(engctx), stat, type, mthd, data);
+	}
+
+	spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+}
+
+static int
+nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv31_mpeg_priv *priv;
+	int ret;
+
+	ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv31_mpeg_intr;
+	nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+	nv_engine(priv)->sclass = nv31_mpeg_sclass;
+	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+	return 0;
+}
+
+int
+nv31_mpeg_init(struct nvkm_object *object)
+{
+	struct nvkm_engine *engine = nv_engine(object);
+	struct nv31_mpeg_priv *priv = (void *)object;
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	int ret, i;
+
+	ret = nvkm_mpeg_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* VPE init */
+	nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+	nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	/* PMPEG init */
+	nv_wr32(priv, 0x00b32c, 0x00000000);
+	nv_wr32(priv, 0x00b314, 0x00000100);
+	nv_wr32(priv, 0x00b220, 0x00000031);
+	nv_wr32(priv, 0x00b300, 0x02001ec1);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+	nv_wr32(priv, 0x00b100, 0xffffffff);
+	nv_wr32(priv, 0x00b140, 0xffffffff);
+
+	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv31_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x31),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv31_mpeg_ctor,
+		.dtor = _nvkm_mpeg_dtor,
+		.init = nv31_mpeg_init,
+		.fini = _nvkm_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h
new file mode 100644
index 0000000..782b796
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h
@@ -0,0 +1,13 @@
+#ifndef __NV31_MPEG_H__
+#define __NV31_MPEG_H__
+#include <engine/mpeg.h>
+
+struct nv31_mpeg_chan {
+	struct nvkm_object base;
+};
+
+struct nv31_mpeg_priv {
+	struct nvkm_mpeg base;
+	struct nv31_mpeg_chan *chan;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c
new file mode 100644
index 0000000..9508bf9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv31.h"
+
+#include <subdev/instmem.h>
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(object);
+	struct nv31_mpeg_priv *priv = (void *)object->engine;
+	u32 inst = *(u32 *)arg << 4;
+	u32 dma0 = nv_ro32(imem, inst + 0);
+	u32 dma1 = nv_ro32(imem, inst + 4);
+	u32 dma2 = nv_ro32(imem, inst + 8);
+	u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+	u32 size = dma1 + 1;
+
+	/* only allow linear DMA objects */
+	if (!(dma0 & 0x00002000))
+		return -EINVAL;
+
+	if (mthd == 0x0190) {
+		/* DMA_CMD */
+		nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+		nv_wr32(priv, 0x00b334, base);
+		nv_wr32(priv, 0x00b324, size);
+	} else
+	if (mthd == 0x01a0) {
+		/* DMA_DATA */
+		nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+		nv_wr32(priv, 0x00b360, base);
+		nv_wr32(priv, 0x00b364, size);
+	} else {
+		/* DMA_IMAGE, VRAM only */
+		if (dma0 & 0x00030000)
+			return -EINVAL;
+
+		nv_wr32(priv, 0x00b370, base);
+		nv_wr32(priv, 0x00b374, size);
+	}
+
+	return 0;
+}
+
+static struct nvkm_omthds
+nv40_mpeg_omthds[] = {
+	{ 0x0190, 0x0190, nv40_mpeg_mthd_dma },
+	{ 0x01a0, 0x01a0, nv40_mpeg_mthd_dma },
+	{ 0x01b0, 0x01b0, nv40_mpeg_mthd_dma },
+	{}
+};
+
+struct nvkm_oclass
+nv40_mpeg_sclass[] = {
+	{ 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_mpeg_intr(struct nvkm_subdev *subdev)
+{
+	struct nv31_mpeg_priv *priv = (void *)subdev;
+	u32 stat;
+
+	if ((stat = nv_rd32(priv, 0x00b100)))
+		nv31_mpeg_intr(subdev);
+
+	if ((stat = nv_rd32(priv, 0x00b800))) {
+		nv_error(priv, "PMSRCH 0x%08x\n", stat);
+		nv_wr32(priv, 0x00b800, stat);
+	}
+}
+
+static int
+nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv31_mpeg_priv *priv;
+	int ret;
+
+	ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv40_mpeg_intr;
+	nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+	nv_engine(priv)->sclass = nv40_mpeg_sclass;
+	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv40_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_mpeg_ctor,
+		.dtor = _nvkm_mpeg_dtor,
+		.init = nv31_mpeg_init,
+		.fini = _nvkm_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
new file mode 100644
index 0000000..4720ac8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+
+struct nv44_mpeg_priv {
+	struct nvkm_mpeg base;
+};
+
+struct nv44_mpeg_chan {
+	struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv44_mpeg_context_ctor(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nv44_mpeg_chan *chan;
+	int ret;
+
+	ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 264 * 4,
+				       16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
+	return 0;
+}
+
+static int
+nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend)
+{
+
+	struct nv44_mpeg_priv *priv = (void *)object->engine;
+	struct nv44_mpeg_chan *chan = (void *)object;
+	u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
+
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
+	if (nv_rd32(priv, 0x00b318) == inst)
+		nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv44_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x44),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv44_mpeg_context_ctor,
+		.dtor = _nvkm_mpeg_context_dtor,
+		.init = _nvkm_mpeg_context_init,
+		.fini = nv44_mpeg_context_fini,
+		.rd32 = _nvkm_mpeg_context_rd32,
+		.wr32 = _nvkm_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv44_mpeg_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct nvkm_handle *handle;
+	struct nv44_mpeg_priv *priv = (void *)subdev;
+	u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
+	u32 stat = nv_rd32(priv, 0x00b100);
+	u32 type = nv_rd32(priv, 0x00b230);
+	u32 mthd = nv_rd32(priv, 0x00b234);
+	u32 data = nv_rd32(priv, 0x00b238);
+	u32 show = stat;
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & 0x01000000) {
+		/* happens on initial binding of the object */
+		if (type == 0x00000020 && mthd == 0x0000) {
+			nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
+			show &= ~0x01000000;
+		}
+
+		if (type == 0x00000010) {
+			handle = nvkm_handle_get_class(engctx, 0x3174);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~0x01000000;
+			nvkm_handle_put(handle);
+		}
+	}
+
+	nv_wr32(priv, 0x00b100, stat);
+	nv_wr32(priv, 0x00b230, 0x00000001);
+
+	if (show) {
+		nv_error(priv,
+			 "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 chid, inst << 4, nvkm_client_name(engctx), stat,
+			 type, mthd, data);
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static void
+nv44_mpeg_me_intr(struct nvkm_subdev *subdev)
+{
+	struct nv44_mpeg_priv *priv = (void *)subdev;
+	u32 stat;
+
+	if ((stat = nv_rd32(priv, 0x00b100)))
+		nv44_mpeg_intr(subdev);
+
+	if ((stat = nv_rd32(priv, 0x00b800))) {
+		nv_error(priv, "PMSRCH 0x%08x\n", stat);
+		nv_wr32(priv, 0x00b800, stat);
+	}
+}
+
+static int
+nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv44_mpeg_priv *priv;
+	int ret;
+
+	ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nv44_mpeg_me_intr;
+	nv_engine(priv)->cclass = &nv44_mpeg_cclass;
+	nv_engine(priv)->sclass = nv40_mpeg_sclass;
+	nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv44_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x44),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv44_mpeg_ctor,
+		.dtor = _nvkm_mpeg_dtor,
+		.init = nv31_mpeg_init,
+		.fini = _nvkm_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c
new file mode 100644
index 0000000..b3463f3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+struct nv50_mpeg_priv {
+	struct nvkm_mpeg base;
+};
+
+struct nv50_mpeg_chan {
+	struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv50_mpeg_object_ctor(struct nvkm_object *parent,
+		      struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *data, u32 size,
+		      struct nvkm_object **pobject)
+{
+	struct nvkm_gpuobj *obj;
+	int ret;
+
+	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+				 16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+struct nvkm_ofuncs
+nv50_mpeg_ofuncs = {
+	.ctor = nv50_mpeg_object_ctor,
+	.dtor = _nvkm_gpuobj_dtor,
+	.init = _nvkm_gpuobj_init,
+	.fini = _nvkm_gpuobj_fini,
+	.rd32 = _nvkm_gpuobj_rd32,
+	.wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv50_mpeg_sclass[] = {
+	{ 0x3174, &nv50_mpeg_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+int
+nv50_mpeg_context_ctor(struct nvkm_object *parent,
+		       struct nvkm_object *engine,
+		       struct nvkm_oclass *oclass, void *data, u32 size,
+		       struct nvkm_object **pobject)
+{
+	struct nvkm_bar *bar = nvkm_bar(parent);
+	struct nv50_mpeg_chan *chan;
+	int ret;
+
+	ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
+				       0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv_wo32(chan, 0x0070, 0x00801ec1);
+	nv_wo32(chan, 0x007c, 0x0000037c);
+	bar->flush(bar);
+	return 0;
+}
+
+static struct nvkm_oclass
+nv50_mpeg_cclass = {
+	.handle = NV_ENGCTX(MPEG, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_mpeg_context_ctor,
+		.dtor = _nvkm_mpeg_context_dtor,
+		.init = _nvkm_mpeg_context_init,
+		.fini = _nvkm_mpeg_context_fini,
+		.rd32 = _nvkm_mpeg_context_rd32,
+		.wr32 = _nvkm_mpeg_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+void
+nv50_mpeg_intr(struct nvkm_subdev *subdev)
+{
+	struct nv50_mpeg_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x00b100);
+	u32 type = nv_rd32(priv, 0x00b230);
+	u32 mthd = nv_rd32(priv, 0x00b234);
+	u32 data = nv_rd32(priv, 0x00b238);
+	u32 show = stat;
+
+	if (stat & 0x01000000) {
+		/* happens on initial binding of the object */
+		if (type == 0x00000020 && mthd == 0x0000) {
+			nv_wr32(priv, 0x00b308, 0x00000100);
+			show &= ~0x01000000;
+		}
+	}
+
+	if (show) {
+		nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+			stat, type, mthd, data);
+	}
+
+	nv_wr32(priv, 0x00b100, stat);
+	nv_wr32(priv, 0x00b230, 0x00000001);
+}
+
+static void
+nv50_vpe_intr(struct nvkm_subdev *subdev)
+{
+	struct nv50_mpeg_priv *priv = (void *)subdev;
+
+	if (nv_rd32(priv, 0x00b100))
+		nv50_mpeg_intr(subdev);
+
+	if (nv_rd32(priv, 0x00b800)) {
+		u32 stat = nv_rd32(priv, 0x00b800);
+		nv_info(priv, "PMSRCH: 0x%08x\n", stat);
+		nv_wr32(priv, 0xb800, stat);
+	}
+}
+
+static int
+nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv50_mpeg_priv *priv;
+	int ret;
+
+	ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00400002;
+	nv_subdev(priv)->intr = nv50_vpe_intr;
+	nv_engine(priv)->cclass = &nv50_mpeg_cclass;
+	nv_engine(priv)->sclass = nv50_mpeg_sclass;
+	return 0;
+}
+
+int
+nv50_mpeg_init(struct nvkm_object *object)
+{
+	struct nv50_mpeg_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_mpeg_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x00b32c, 0x00000000);
+	nv_wr32(priv, 0x00b314, 0x00000100);
+	nv_wr32(priv, 0x00b0e0, 0x0000001a);
+
+	nv_wr32(priv, 0x00b220, 0x00000044);
+	nv_wr32(priv, 0x00b300, 0x00801ec1);
+	nv_wr32(priv, 0x00b390, 0x00000000);
+	nv_wr32(priv, 0x00b394, 0x00000000);
+	nv_wr32(priv, 0x00b398, 0x00000000);
+	nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+	nv_wr32(priv, 0x00b100, 0xffffffff);
+	nv_wr32(priv, 0x00b140, 0xffffffff);
+
+	if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+		nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_mpeg_oclass = {
+	.handle = NV_ENGINE(MPEG, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_mpeg_ctor,
+		.dtor = _nvkm_mpeg_dtor,
+		.init = nv50_mpeg_init,
+		.fini = _nvkm_mpeg_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild
new file mode 100644
index 0000000..c59c83a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/mspdec/g98.o
+nvkm-y += nvkm/engine/mspdec/gf100.o
+nvkm-y += nvkm/engine/mspdec/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c
new file mode 100644
index 0000000..2174577
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct g98_mspdec_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_mspdec_sclass[] = {
+	{ 0x88b2, &nvkm_object_ofuncs },
+	{ 0x85b2, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_mspdec_cclass = {
+	.handle = NV_ENGCTX(MSPDEC, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_mspdec_init(struct nvkm_object *object)
+{
+	struct g98_mspdec_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x085010, 0x0000ffd2);
+	nv_wr32(priv, 0x08501c, 0x0000fff2);
+	return 0;
+}
+
+static int
+g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct g98_mspdec_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+				 "PMSPDEC", "mspdec", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x01020000;
+	nv_engine(priv)->cclass = &g98_mspdec_cclass;
+	nv_engine(priv)->sclass = g98_mspdec_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+g98_mspdec_oclass = {
+	.handle = NV_ENGINE(MSPDEC, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g98_mspdec_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = g98_mspdec_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c
new file mode 100644
index 0000000..c814a5f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * 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.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct gf100_mspdec_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_mspdec_sclass[] = {
+	{ 0x90b2, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_mspdec_cclass = {
+	.handle = NV_ENGCTX(MSPDEC, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_mspdec_init(struct nvkm_object *object)
+{
+	struct gf100_mspdec_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x085010, 0x0000fff2);
+	nv_wr32(priv, 0x08501c, 0x0000fff2);
+	return 0;
+}
+
+static int
+gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct gf100_mspdec_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+				 "PMSPDEC", "mspdec", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00020000;
+	nv_subdev(priv)->intr = nvkm_falcon_intr;
+	nv_engine(priv)->cclass = &gf100_mspdec_cclass;
+	nv_engine(priv)->sclass = gf100_mspdec_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_mspdec_oclass = {
+	.handle = NV_ENGINE(MSPDEC, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_mspdec_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gf100_mspdec_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c
new file mode 100644
index 0000000..9799206
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct gk104_mspdec_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_mspdec_sclass[] = {
+	{ 0x95b2, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_mspdec_cclass = {
+	.handle = NV_ENGCTX(MSPDEC, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk104_mspdec_init(struct nvkm_object *object)
+{
+	struct gk104_mspdec_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x085010, 0x0000fff2);
+	nv_wr32(priv, 0x08501c, 0x0000fff2);
+	return 0;
+}
+
+static int
+gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct gk104_mspdec_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+				 "PMSPDEC", "mspdec", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00020000;
+	nv_subdev(priv)->intr = nvkm_falcon_intr;
+	nv_engine(priv)->cclass = &gk104_mspdec_cclass;
+	nv_engine(priv)->sclass = gk104_mspdec_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_mspdec_oclass = {
+	.handle = NV_ENGINE(MSPDEC, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_mspdec_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gk104_mspdec_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild
new file mode 100644
index 0000000..4576a9e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild
@@ -0,0 +1,2 @@
+nvkm-y += nvkm/engine/msppp/g98.o
+nvkm-y += nvkm/engine/msppp/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c
new file mode 100644
index 0000000..7a602a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/msppp.h>
+#include <engine/falcon.h>
+
+struct g98_msppp_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPPP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msppp_sclass[] = {
+	{ 0x88b3, &nvkm_object_ofuncs },
+	{ 0x85b3, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSPPP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msppp_cclass = {
+	.handle = NV_ENGCTX(MSPPP, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSPPP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_msppp_init(struct nvkm_object *object)
+{
+	struct g98_msppp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x086010, 0x0000ffd2);
+	nv_wr32(priv, 0x08601c, 0x0000fff2);
+	return 0;
+}
+
+static int
+g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct g98_msppp_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true,
+				 "PMSPPP", "msppp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00400002;
+	nv_engine(priv)->cclass = &g98_msppp_cclass;
+	nv_engine(priv)->sclass = g98_msppp_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+g98_msppp_oclass = {
+	.handle = NV_ENGINE(MSPPP, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g98_msppp_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = g98_msppp_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c
new file mode 100644
index 0000000..6047bae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * 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.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/msppp.h>
+#include <engine/falcon.h>
+
+struct gf100_msppp_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPPP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msppp_sclass[] = {
+	{ 0x90b3, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSPPP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msppp_cclass = {
+	.handle = NV_ENGCTX(MSPPP, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSPPP engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_msppp_init(struct nvkm_object *object)
+{
+	struct gf100_msppp_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x086010, 0x0000fff2);
+	nv_wr32(priv, 0x08601c, 0x0000fff2);
+	return 0;
+}
+
+static int
+gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gf100_msppp_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true,
+				 "PMSPPP", "msppp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nvkm_falcon_intr;
+	nv_engine(priv)->cclass = &gf100_msppp_cclass;
+	nv_engine(priv)->sclass = gf100_msppp_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_msppp_oclass = {
+	.handle = NV_ENGINE(MSPPP, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_msppp_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gf100_msppp_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild
new file mode 100644
index 0000000..0c98110
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/msvld/g98.o
+nvkm-y += nvkm/engine/msvld/gf100.o
+nvkm-y += nvkm/engine/msvld/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c
new file mode 100644
index 0000000..c8a6b4e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct g98_msvld_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msvld_sclass[] = {
+	{ 0x88b1, &nvkm_object_ofuncs },
+	{ 0x85b1, &nvkm_object_ofuncs },
+	{ 0x86b1, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msvld_cclass = {
+	.handle = NV_ENGCTX(MSVLD, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_msvld_init(struct nvkm_object *object)
+{
+	struct g98_msvld_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x084010, 0x0000ffd2);
+	nv_wr32(priv, 0x08401c, 0x0000fff2);
+	return 0;
+}
+
+static int
+g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct g98_msvld_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+				 "PMSVLD", "msvld", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x04008000;
+	nv_engine(priv)->cclass = &g98_msvld_cclass;
+	nv_engine(priv)->sclass = g98_msvld_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+g98_msvld_oclass = {
+	.handle = NV_ENGINE(MSVLD, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g98_msvld_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = g98_msvld_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c
new file mode 100644
index 0000000..b8d1e0f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * 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.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct gf100_msvld_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msvld_sclass[] = {
+	{ 0x90b1, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msvld_cclass = {
+	.handle = NV_ENGCTX(MSVLD, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_msvld_init(struct nvkm_object *object)
+{
+	struct gf100_msvld_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x084010, 0x0000fff2);
+	nv_wr32(priv, 0x08401c, 0x0000fff2);
+	return 0;
+}
+
+static int
+gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gf100_msvld_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+				 "PMSVLD", "msvld", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00008000;
+	nv_subdev(priv)->intr = nvkm_falcon_intr;
+	nv_engine(priv)->cclass = &gf100_msvld_cclass;
+	nv_engine(priv)->sclass = gf100_msvld_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_msvld_oclass = {
+	.handle = NV_ENGINE(MSVLD, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_msvld_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gf100_msvld_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c
new file mode 100644
index 0000000..a0b0927
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct gk104_msvld_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_msvld_sclass[] = {
+	{ 0x95b1, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_msvld_cclass = {
+	.handle = NV_ENGCTX(MSVLD, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk104_msvld_init(struct nvkm_object *object)
+{
+	struct gk104_msvld_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_falcon_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x084010, 0x0000fff2);
+	nv_wr32(priv, 0x08401c, 0x0000fff2);
+	return 0;
+}
+
+static int
+gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gk104_msvld_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+				 "PMSVLD", "msvld", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00008000;
+	nv_subdev(priv)->intr = nvkm_falcon_intr;
+	nv_engine(priv)->cclass = &gk104_msvld_cclass;
+	nv_engine(priv)->sclass = gk104_msvld_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_msvld_oclass = {
+	.handle = NV_ENGINE(MSVLD, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_msvld_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = gk104_msvld_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild
new file mode 100644
index 0000000..413b609
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild
@@ -0,0 +1,9 @@
+nvkm-y += nvkm/engine/pm/base.o
+nvkm-y += nvkm/engine/pm/daemon.o
+nvkm-y += nvkm/engine/pm/nv40.o
+nvkm-y += nvkm/engine/pm/nv50.o
+nvkm-y += nvkm/engine/pm/g84.o
+nvkm-y += nvkm/engine/pm/gt215.o
+nvkm-y += nvkm/engine/pm/gf100.o
+nvkm-y += nvkm/engine/pm/gk104.o
+nvkm-y += nvkm/engine/pm/gk110.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
new file mode 100644
index 0000000..2006c44
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/option.h>
+
+#include <nvif/class.h>
+#include <nvif/ioctl.h>
+#include <nvif/unpack.h>
+
+#define QUAD_MASK 0x0f
+#define QUAD_FREE 0x01
+
+static struct nvkm_perfsig *
+nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size)
+{
+	char path[64];
+	int i;
+
+	if (name[0] != '/') {
+		for (i = 0; i < dom->signal_nr; i++) {
+			if ( dom->signal[i].name &&
+			    !strncmp(name, dom->signal[i].name, size))
+				return &dom->signal[i];
+		}
+	} else {
+		for (i = 0; i < dom->signal_nr; i++) {
+			snprintf(path, sizeof(path), "/%s/%02x", dom->name, i);
+			if (!strncmp(name, path, size))
+				return &dom->signal[i];
+		}
+	}
+
+	return NULL;
+}
+
+struct nvkm_perfsig *
+nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size,
+		  struct nvkm_perfdom **pdom)
+{
+	struct nvkm_perfdom *dom = *pdom;
+	struct nvkm_perfsig *sig;
+
+	if (dom == NULL) {
+		list_for_each_entry(dom, &ppm->domains, head) {
+			sig = nvkm_perfsig_find_(dom, name, size);
+			if (sig) {
+				*pdom = dom;
+				return sig;
+			}
+		}
+
+		return NULL;
+	}
+
+	return nvkm_perfsig_find_(dom, name, size);
+}
+
+struct nvkm_perfctr *
+nvkm_perfsig_wrap(struct nvkm_pm *ppm, const char *name,
+		  struct nvkm_perfdom **pdom)
+{
+	struct nvkm_perfsig *sig;
+	struct nvkm_perfctr *ctr;
+
+	sig = nvkm_perfsig_find(ppm, name, strlen(name), pdom);
+	if (!sig)
+		return NULL;
+
+	ctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
+	if (ctr) {
+		ctr->signal[0] = sig;
+		ctr->logic_op = 0xaaaa;
+	}
+
+	return ctr;
+}
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+static int
+nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_perfctr_query_v0 v0;
+	} *args = data;
+	struct nvkm_device *device = nv_device(object);
+	struct nvkm_pm *ppm = (void *)object->engine;
+	struct nvkm_perfdom *dom = NULL, *chk;
+	const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false);
+	const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all);
+	const char *name;
+	int tmp = 0, di, si;
+	int ret;
+
+	nv_ioctl(object, "perfctr query size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "perfctr query vers %d iter %08x\n",
+			 args->v0.version, args->v0.iter);
+		di = (args->v0.iter & 0xff000000) >> 24;
+		si = (args->v0.iter & 0x00ffffff) - 1;
+	} else
+		return ret;
+
+	list_for_each_entry(chk, &ppm->domains, head) {
+		if (tmp++ == di) {
+			dom = chk;
+			break;
+		}
+	}
+
+	if (dom == NULL || si >= (int)dom->signal_nr)
+		return -EINVAL;
+
+	if (si >= 0) {
+		if (raw || !(name = dom->signal[si].name)) {
+			snprintf(args->v0.name, sizeof(args->v0.name),
+				 "/%s/%02x", dom->name, si);
+		} else {
+			strncpy(args->v0.name, name, sizeof(args->v0.name));
+		}
+	}
+
+	do {
+		while (++si < dom->signal_nr) {
+			if (all || dom->signal[si].name) {
+				args->v0.iter = (di << 24) | ++si;
+				return 0;
+			}
+		}
+		si = -1;
+		di = di + 1;
+		dom = list_entry(dom->head.next, typeof(*dom), head);
+	} while (&dom->head != &ppm->domains);
+
+	args->v0.iter = 0xffffffff;
+	return 0;
+}
+
+static int
+nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_perfctr_sample none;
+	} *args = data;
+	struct nvkm_pm *ppm = (void *)object->engine;
+	struct nvkm_perfctr *ctr, *tmp;
+	struct nvkm_perfdom *dom;
+	int ret;
+
+	nv_ioctl(object, "perfctr sample size %d\n", size);
+	if (nvif_unvers(args->none)) {
+		nv_ioctl(object, "perfctr sample\n");
+	} else
+		return ret;
+	ppm->sequence++;
+
+	list_for_each_entry(dom, &ppm->domains, head) {
+		/* sample previous batch of counters */
+		if (dom->quad != QUAD_MASK) {
+			dom->func->next(ppm, dom);
+			tmp = NULL;
+			while (!list_empty(&dom->list)) {
+				ctr = list_first_entry(&dom->list,
+						       typeof(*ctr), head);
+				if (ctr->slot < 0) break;
+				if ( tmp && tmp == ctr) break;
+				if (!tmp) tmp = ctr;
+				dom->func->read(ppm, dom, ctr);
+				ctr->slot  = -1;
+				list_move_tail(&ctr->head, &dom->list);
+			}
+		}
+
+		dom->quad = QUAD_MASK;
+
+		/* setup next batch of counters for sampling */
+		list_for_each_entry(ctr, &dom->list, head) {
+			ctr->slot = ffs(dom->quad) - 1;
+			if (ctr->slot < 0)
+				break;
+			dom->quad &= ~(QUAD_FREE << ctr->slot);
+			dom->func->init(ppm, dom, ctr);
+		}
+
+		if (dom->quad != QUAD_MASK)
+			dom->func->next(ppm, dom);
+	}
+
+	return 0;
+}
+
+static int
+nvkm_perfctr_read(struct nvkm_object *object, void *data, u32 size)
+{
+	union {
+		struct nvif_perfctr_read_v0 v0;
+	} *args = data;
+	struct nvkm_perfctr *ctr = (void *)object;
+	int ret;
+
+	nv_ioctl(object, "perfctr read size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
+	} else
+		return ret;
+
+	if (!ctr->clk)
+		return -EAGAIN;
+
+	args->v0.clk = ctr->clk;
+	args->v0.ctr = ctr->ctr;
+	return 0;
+}
+
+static int
+nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	switch (mthd) {
+	case NVIF_PERFCTR_V0_QUERY:
+		return nvkm_perfctr_query(object, data, size);
+	case NVIF_PERFCTR_V0_SAMPLE:
+		return nvkm_perfctr_sample(object, data, size);
+	case NVIF_PERFCTR_V0_READ:
+		return nvkm_perfctr_read(object, data, size);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static void
+nvkm_perfctr_dtor(struct nvkm_object *object)
+{
+	struct nvkm_perfctr *ctr = (void *)object;
+	if (ctr->head.next)
+		list_del(&ctr->head);
+	nvkm_object_destroy(&ctr->base);
+}
+
+static int
+nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	union {
+		struct nvif_perfctr_v0 v0;
+	} *args = data;
+	struct nvkm_pm *ppm = (void *)engine;
+	struct nvkm_perfdom *dom = NULL;
+	struct nvkm_perfsig *sig[4] = {};
+	struct nvkm_perfctr *ctr;
+	int ret, i;
+
+	nv_ioctl(parent, "create perfctr size %d\n", size);
+	if (nvif_unpack(args->v0, 0, 0, false)) {
+		nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
+			 args->v0.version, args->v0.logic_op);
+	} else
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
+		sig[i] = nvkm_perfsig_find(ppm, args->v0.name[i],
+					   strnlen(args->v0.name[i],
+						   sizeof(args->v0.name[i])),
+					   &dom);
+		if (!sig[i])
+			return -EINVAL;
+	}
+
+	ret = nvkm_object_create(parent, engine, oclass, 0, &ctr);
+	*pobject = nv_object(ctr);
+	if (ret)
+		return ret;
+
+	ctr->slot = -1;
+	ctr->logic_op = args->v0.logic_op;
+	ctr->signal[0] = sig[0];
+	ctr->signal[1] = sig[1];
+	ctr->signal[2] = sig[2];
+	ctr->signal[3] = sig[3];
+	if (dom)
+		list_add_tail(&ctr->head, &dom->list);
+	return 0;
+}
+
+static struct nvkm_ofuncs
+nvkm_perfctr_ofuncs = {
+	.ctor = nvkm_perfctr_ctor,
+	.dtor = nvkm_perfctr_dtor,
+	.init = nvkm_object_init,
+	.fini = nvkm_object_fini,
+	.mthd = nvkm_perfctr_mthd,
+};
+
+struct nvkm_oclass
+nvkm_pm_sclass[] = {
+	{ .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
+	  .ofuncs = &nvkm_perfctr_ofuncs,
+	},
+	{},
+};
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+static void
+nvkm_perfctx_dtor(struct nvkm_object *object)
+{
+	struct nvkm_pm *ppm = (void *)object->engine;
+	mutex_lock(&nv_subdev(ppm)->mutex);
+	nvkm_engctx_destroy(&ppm->context->base);
+	ppm->context = NULL;
+	mutex_unlock(&nv_subdev(ppm)->mutex);
+}
+
+static int
+nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_pm *ppm = (void *)engine;
+	struct nvkm_perfctx *ctx;
+	int ret;
+
+	ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0, 0, 0, &ctx);
+	*pobject = nv_object(ctx);
+	if (ret)
+		return ret;
+
+	mutex_lock(&nv_subdev(ppm)->mutex);
+	if (ppm->context == NULL)
+		ppm->context = ctx;
+	mutex_unlock(&nv_subdev(ppm)->mutex);
+
+	if (ctx != ppm->context)
+		return -EBUSY;
+
+	return 0;
+}
+
+struct nvkm_oclass
+nvkm_pm_cclass = {
+	.handle = NV_ENGCTX(PM, 0x00),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nvkm_perfctx_ctor,
+		.dtor = nvkm_perfctx_dtor,
+		.init = _nvkm_engctx_init,
+		.fini = _nvkm_engctx_fini,
+	},
+};
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+int
+nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask,
+		 u32 base, u32 size_unit, u32 size_domain,
+		 const struct nvkm_specdom *spec)
+{
+	const struct nvkm_specdom *sdom;
+	const struct nvkm_specsig *ssig;
+	struct nvkm_perfdom *dom;
+	int i;
+
+	for (i = 0; i == 0 || mask; i++) {
+		u32 addr = base + (i * size_unit);
+		if (i && !(mask & (1 << i)))
+			continue;
+
+		sdom = spec;
+		while (sdom->signal_nr) {
+			dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
+				      sizeof(*dom->signal), GFP_KERNEL);
+			if (!dom)
+				return -ENOMEM;
+
+			if (mask) {
+				snprintf(dom->name, sizeof(dom->name),
+					 "%s/%02x/%02x", name, i,
+					 (int)(sdom - spec));
+			} else {
+				snprintf(dom->name, sizeof(dom->name),
+					 "%s/%02x", name, (int)(sdom - spec));
+			}
+
+			list_add_tail(&dom->head, &ppm->domains);
+			INIT_LIST_HEAD(&dom->list);
+			dom->func = sdom->func;
+			dom->addr = addr;
+			dom->quad = QUAD_MASK;
+			dom->signal_nr = sdom->signal_nr;
+
+			ssig = (sdom++)->signal;
+			while (ssig->name) {
+				dom->signal[ssig->signal].name = ssig->name;
+				ssig++;
+			}
+
+			addr += size_domain;
+		}
+
+		mask &= ~(1 << i);
+	}
+
+	return 0;
+}
+
+int
+_nvkm_pm_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_pm *ppm = (void *)object;
+	return nvkm_engine_fini(&ppm->base, suspend);
+}
+
+int
+_nvkm_pm_init(struct nvkm_object *object)
+{
+	struct nvkm_pm *ppm = (void *)object;
+	return nvkm_engine_init(&ppm->base);
+}
+
+void
+_nvkm_pm_dtor(struct nvkm_object *object)
+{
+	struct nvkm_pm *ppm = (void *)object;
+	struct nvkm_perfdom *dom, *tmp;
+
+	list_for_each_entry_safe(dom, tmp, &ppm->domains, head) {
+		list_del(&dom->head);
+		kfree(dom);
+	}
+
+	nvkm_engine_destroy(&ppm->base);
+}
+
+int
+nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_pm *ppm;
+	int ret;
+
+	ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM",
+				  "pm", length, pobject);
+	ppm = *pobject;
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&ppm->domains);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c
new file mode 100644
index 0000000..a7a5f3a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static void
+pwr_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		 struct nvkm_perfctr *ctr)
+{
+	u32 mask = 0x00000000;
+	u32 ctrl = 0x00000001;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++)
+		mask |= 1 << (ctr->signal[i] - dom->signal);
+
+	nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask);
+	nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl);
+	nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003);
+}
+
+static void
+pwr_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		 struct nvkm_perfctr *ctr)
+{
+	ctr->ctr = ppm->pwr[ctr->slot];
+	ctr->clk = ppm->pwr[ppm->last];
+}
+
+static void
+pwr_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+	int i;
+
+	for (i = 0; i <= ppm->last; i++) {
+		ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10));
+		nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000);
+	}
+}
+
+static const struct nvkm_funcdom
+pwr_perfctr_func = {
+	.init = pwr_perfctr_init,
+	.read = pwr_perfctr_read,
+	.next = pwr_perfctr_next,
+};
+
+const struct nvkm_specdom
+gt215_pm_pwr[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{ 0x00, "pwr_gr_idle" },
+			{ 0x04, "pwr_bsp_idle" },
+			{ 0x05, "pwr_vp_idle" },
+			{ 0x06, "pwr_ppp_idle" },
+			{ 0x13, "pwr_ce0_idle" },
+			{}
+		}, &pwr_perfctr_func },
+	{}
+};
+
+const struct nvkm_specdom
+gf100_pm_pwr[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{ 0x00, "pwr_gr_idle" },
+			{ 0x04, "pwr_bsp_idle" },
+			{ 0x05, "pwr_vp_idle" },
+			{ 0x06, "pwr_ppp_idle" },
+			{ 0x13, "pwr_ce0_idle" },
+			{ 0x14, "pwr_ce1_idle" },
+			{}
+		}, &pwr_perfctr_func },
+	{}
+};
+
+const struct nvkm_specdom
+gk104_pm_pwr[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{ 0x00, "pwr_gr_idle" },
+			{ 0x04, "pwr_bsp_idle" },
+			{ 0x05, "pwr_vp_idle" },
+			{ 0x06, "pwr_ppp_idle" },
+			{ 0x13, "pwr_ce0_idle" },
+			{ 0x14, "pwr_ce1_idle" },
+			{ 0x15, "pwr_ce2_idle" },
+			{}
+		}, &pwr_perfctr_func },
+	{}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c
new file mode 100644
index 0000000..d54c670
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+g84_pm[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{}
+};
+
+struct nvkm_oclass *
+g84_pm_oclass = &(struct nv40_pm_oclass) {
+	.base.handle = NV_ENGINE(PM, 0x84),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = _nvkm_pm_fini,
+	},
+	.doms = g84_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
new file mode 100644
index 0000000..008fed7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static const struct nvkm_specdom
+gf100_pm_hub[] = {
+	{}
+};
+
+static const struct nvkm_specdom
+gf100_pm_gpc[] = {
+	{}
+};
+
+static const struct nvkm_specdom
+gf100_pm_part[] = {
+	{}
+};
+
+static void
+gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		   struct nvkm_perfctr *ctr)
+{
+	struct gf100_pm_priv *priv = (void *)ppm;
+	struct gf100_pm_cntr *cntr = (void *)ctr;
+	u32 log = ctr->logic_op;
+	u32 src = 0x00000000;
+	int i;
+
+	for (i = 0; i < 4 && ctr->signal[i]; i++)
+		src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+	nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
+	nv_wr32(priv, dom->addr + 0x100, 0x00000000);
+	nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
+	nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
+}
+
+static void
+gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		   struct nvkm_perfctr *ctr)
+{
+	struct gf100_pm_priv *priv = (void *)ppm;
+	struct gf100_pm_cntr *cntr = (void *)ctr;
+
+	switch (cntr->base.slot) {
+	case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break;
+	case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break;
+	case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
+	case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
+	}
+	cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
+}
+
+static void
+gf100_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+	struct gf100_pm_priv *priv = (void *)ppm;
+	nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
+	nv_wr32(priv, dom->addr + 0x0ec, 0x00000011);
+}
+
+const struct nvkm_funcdom
+gf100_perfctr_func = {
+	.init = gf100_perfctr_init,
+	.read = gf100_perfctr_read,
+	.next = gf100_perfctr_next,
+};
+
+int
+gf100_pm_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gf100_pm_priv *priv = (void *)object;
+	nv_mask(priv, 0x000200, 0x10000000, 0x00000000);
+	nv_mask(priv, 0x000200, 0x10000000, 0x10000000);
+	return nvkm_pm_fini(&priv->base, suspend);
+}
+
+static int
+gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct gf100_pm_priv *priv;
+	u32 mask;
+	int ret;
+
+	ret = nvkm_pm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gf100_pm_pwr);
+	if (ret)
+		return ret;
+
+	/* HUB */
+	ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+			       gf100_pm_hub);
+	if (ret)
+		return ret;
+
+	/* GPC */
+	mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
+	mask &= ~nv_rd32(priv, 0x022504);
+	mask &= ~nv_rd32(priv, 0x022584);
+
+	ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+			       0x1000, 0x200, gf100_pm_gpc);
+	if (ret)
+		return ret;
+
+	/* PART */
+	mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
+	mask &= ~nv_rd32(priv, 0x022548);
+	mask &= ~nv_rd32(priv, 0x0225c8);
+
+	ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+			       0x1000, 0x200, gf100_pm_part);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nvkm_pm_cclass;
+	nv_engine(priv)->sclass =  nvkm_pm_sclass;
+	priv->base.last = 7;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_pm_oclass = {
+	.handle = NV_ENGINE(PM, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = gf100_pm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h
new file mode 100644
index 0000000..6a01fc7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h
@@ -0,0 +1,15 @@
+#ifndef __NVKM_PM_NVC0_H__
+#define __NVKM_PM_NVC0_H__
+#include "priv.h"
+
+struct gf100_pm_priv {
+	struct nvkm_pm base;
+};
+
+struct gf100_pm_cntr {
+	struct nvkm_perfctr base;
+};
+
+extern const struct nvkm_funcdom gf100_perfctr_func;
+int gf100_pm_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c
new file mode 100644
index 0000000..75b9ff3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static const struct nvkm_specdom
+gk104_pm_hub[] = {
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "hub00_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x40, (const struct nvkm_specsig[]) {
+			{ 0x27, "hub01_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "hub02_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "hub03_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x40, (const struct nvkm_specsig[]) {
+			{ 0x03, "host_mmio_rd" },
+			{ 0x27, "hub04_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "hub05_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0xc0, (const struct nvkm_specsig[]) {
+			{ 0x74, "host_fb_rd3x" },
+			{ 0x75, "host_fb_rd3x_2" },
+			{ 0xa7, "hub06_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "hub07_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{}
+};
+
+static const struct nvkm_specdom
+gk104_pm_gpc[] = {
+	{ 0xe0, (const struct nvkm_specsig[]) {
+			{ 0xc7, "gpc00_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{}
+};
+
+static const struct nvkm_specdom
+gk104_pm_part[] = {
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "part00_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{ 0x60, (const struct nvkm_specsig[]) {
+			{ 0x47, "part01_user_0" },
+			{}
+		}, &gf100_perfctr_func },
+	{}
+};
+
+static int
+gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct gf100_pm_priv *priv;
+	u32 mask;
+	int ret;
+
+	ret = nvkm_pm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	/* PDAEMON */
+	ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr);
+	if (ret)
+		return ret;
+
+	/* HUB */
+	ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+			       gk104_pm_hub);
+	if (ret)
+		return ret;
+
+	/* GPC */
+	mask  = (1 << nv_rd32(priv, 0x022430)) - 1;
+	mask &= ~nv_rd32(priv, 0x022504);
+	mask &= ~nv_rd32(priv, 0x022584);
+
+	ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+			       0x1000, 0x200, gk104_pm_gpc);
+	if (ret)
+		return ret;
+
+	/* PART */
+	mask  = (1 << nv_rd32(priv, 0x022438)) - 1;
+	mask &= ~nv_rd32(priv, 0x022548);
+	mask &= ~nv_rd32(priv, 0x0225c8);
+
+	ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+			       0x1000, 0x200, gk104_pm_part);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nvkm_pm_cclass;
+	nv_engine(priv)->sclass =  nvkm_pm_sclass;
+	priv->base.last = 7;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_pm_oclass = {
+	.handle = NV_ENGINE(PM, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = gf100_pm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c
new file mode 100644
index 0000000..6820176
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static int
+gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct gf100_pm_priv *priv;
+	int ret;
+
+	ret = nvkm_pm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nvkm_pm_cclass;
+	nv_engine(priv)->sclass =  nvkm_pm_sclass;
+	return 0;
+}
+
+struct nvkm_oclass
+gk110_pm_oclass = {
+	.handle = NV_ENGINE(PM, 0xf0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk110_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = gf100_pm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c
new file mode 100644
index 0000000..d065bfc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+gt215_pm[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{}
+};
+
+static int
+gt215_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **object)
+{
+	int ret = nv40_pm_ctor(parent, engine, oclass, data, size, object);
+	if (ret == 0) {
+		struct nv40_pm_priv *priv = (void *)*object;
+		ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+				       gt215_pm_pwr);
+		if (ret)
+			return ret;
+
+		priv->base.last = 3;
+	}
+	return ret;
+}
+
+struct nvkm_oclass *
+gt215_pm_oclass = &(struct nv40_pm_oclass) {
+	.base.handle = NV_ENGINE(PM, 0xa3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = _nvkm_pm_fini,
+	},
+	.doms = gt215_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
new file mode 100644
index 0000000..ff22f06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static void
+nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		  struct nvkm_perfctr *ctr)
+{
+	struct nv40_pm_priv *priv = (void *)ppm;
+	struct nv40_pm_cntr *cntr = (void *)ctr;
+	u32 log = ctr->logic_op;
+	u32 src = 0x00000000;
+	int i;
+
+	for (i = 0; i < 4 && ctr->signal[i]; i++)
+		src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+	nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
+	nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
+	nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
+}
+
+static void
+nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+		  struct nvkm_perfctr *ctr)
+{
+	struct nv40_pm_priv *priv = (void *)ppm;
+	struct nv40_pm_cntr *cntr = (void *)ctr;
+
+	switch (cntr->base.slot) {
+	case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
+	case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
+	case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
+	case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
+	}
+	cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
+}
+
+static void
+nv40_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+	struct nv40_pm_priv *priv = (void *)ppm;
+	if (priv->sequence != ppm->sequence) {
+		nv_wr32(priv, 0x400084, 0x00000020);
+		priv->sequence = ppm->sequence;
+	}
+}
+
+const struct nvkm_funcdom
+nv40_perfctr_func = {
+	.init = nv40_perfctr_init,
+	.read = nv40_perfctr_read,
+	.next = nv40_perfctr_next,
+};
+
+static const struct nvkm_specdom
+nv40_pm[] = {
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x20, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{}
+};
+
+int
+nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv40_pm_oclass *mclass = (void *)oclass;
+	struct nv40_pm_priv *priv;
+	int ret;
+
+	ret = nvkm_pm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nvkm_pm_cclass;
+	nv_engine(priv)->sclass =  nvkm_pm_sclass;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv40_pm_oclass = &(struct nv40_pm_oclass) {
+	.base.handle = NV_ENGINE(PM, 0x40),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = _nvkm_pm_fini,
+	},
+	.doms = nv40_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h
new file mode 100644
index 0000000..2338e15
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h
@@ -0,0 +1,24 @@
+#ifndef __NVKM_PM_NV40_H__
+#define __NVKM_PM_NV40_H__
+#include "priv.h"
+
+struct nv40_pm_oclass {
+	struct nvkm_oclass base;
+	const struct nvkm_specdom *doms;
+};
+
+struct nv40_pm_priv {
+	struct nvkm_pm base;
+	u32 sequence;
+};
+
+int nv40_pm_ctor(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, void *data, u32 size,
+		      struct nvkm_object **pobject);
+
+struct nv40_pm_cntr {
+	struct nvkm_perfctr base;
+};
+
+extern const struct nvkm_funcdom nv40_perfctr_func;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c
new file mode 100644
index 0000000..6af83b5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+nv50_pm[] = {
+	{ 0x040, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x100, (const struct nvkm_specsig[]) {
+			{ 0xc8, "gr_idle" },
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x100, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x020, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{ 0x040, (const struct nvkm_specsig[]) {
+			{}
+		}, &nv40_perfctr_func },
+	{}
+};
+
+struct nvkm_oclass *
+nv50_pm_oclass = &(struct nv40_pm_oclass) {
+	.base.handle = NV_ENGINE(PM, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_pm_ctor,
+		.dtor = _nvkm_pm_dtor,
+		.init = _nvkm_pm_init,
+		.fini = _nvkm_pm_fini,
+	},
+	.doms = nv50_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
new file mode 100644
index 0000000..1e6eff2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
@@ -0,0 +1,90 @@
+#ifndef __NVKM_PM_PRIV_H__
+#define __NVKM_PM_PRIV_H__
+#include <engine/pm.h>
+
+struct nvkm_perfctr {
+	struct nvkm_object base;
+	struct list_head head;
+	struct nvkm_perfsig *signal[4];
+	int slot;
+	u32 logic_op;
+	u32 clk;
+	u32 ctr;
+};
+
+extern struct nvkm_oclass nvkm_pm_sclass[];
+
+#include <core/engctx.h>
+
+struct nvkm_perfctx {
+	struct nvkm_engctx base;
+};
+
+extern struct nvkm_oclass nvkm_pm_cclass;
+
+struct nvkm_specsig {
+	u8 signal;
+	const char *name;
+};
+
+struct nvkm_perfsig {
+	const char *name;
+};
+
+struct nvkm_perfdom;
+struct nvkm_perfctr *
+nvkm_perfsig_wrap(struct nvkm_pm *, const char *, struct nvkm_perfdom **);
+
+struct nvkm_specdom {
+	u16 signal_nr;
+	const struct nvkm_specsig *signal;
+	const struct nvkm_funcdom *func;
+};
+
+extern const struct nvkm_specdom gt215_pm_pwr[];
+extern const struct nvkm_specdom gf100_pm_pwr[];
+extern const struct nvkm_specdom gk104_pm_pwr[];
+
+struct nvkm_perfdom {
+	struct list_head head;
+	struct list_head list;
+	const struct nvkm_funcdom *func;
+	char name[32];
+	u32 addr;
+	u8  quad;
+	u32 signal_nr;
+	struct nvkm_perfsig signal[];
+};
+
+struct nvkm_funcdom {
+	void (*init)(struct nvkm_pm *, struct nvkm_perfdom *,
+		     struct nvkm_perfctr *);
+	void (*read)(struct nvkm_pm *, struct nvkm_perfdom *,
+		     struct nvkm_perfctr *);
+	void (*next)(struct nvkm_pm *, struct nvkm_perfdom *);
+};
+
+int nvkm_perfdom_new(struct nvkm_pm *, const char *, u32, u32, u32, u32,
+		     const struct nvkm_specdom *);
+
+#define nvkm_pm_create(p,e,o,d)                                        \
+	nvkm_pm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_pm_dtor(p) ({                                             \
+	struct nvkm_pm *c = (p);                                       \
+	_nvkm_pm_dtor(nv_object(c));                                   \
+})
+#define nvkm_pm_init(p) ({                                             \
+	struct nvkm_pm *c = (p);                                       \
+	_nvkm_pm_init(nv_object(c));                                   \
+})
+#define nvkm_pm_fini(p,s) ({                                           \
+	struct nvkm_pm *c = (p);                                       \
+	_nvkm_pm_fini(nv_object(c), (s));                              \
+})
+
+int nvkm_pm_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, int, void **);
+void _nvkm_pm_dtor(struct nvkm_object *);
+int  _nvkm_pm_init(struct nvkm_object *);
+int  _nvkm_pm_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild
new file mode 100644
index 0000000..552d40a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/sec/g98.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s
new file mode 100644
index 0000000..06ee060
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s
@@ -0,0 +1,698 @@
+/*
+ *  fuc microcode for g98 psec engine
+ *  Copyright (C) 2010  Marcin Kościelnicki
+ *
+ *  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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+.section #g98_psec_data
+
+ctx_dma:
+ctx_dma_query:		.b32 0
+ctx_dma_src:		.b32 0
+ctx_dma_dst:		.b32 0
+.equ #dma_count 3
+ctx_query_address_high:	.b32 0
+ctx_query_address_low:	.b32 0
+ctx_query_counter:	.b32 0
+ctx_cond_address_high:	.b32 0
+ctx_cond_address_low:	.b32 0
+ctx_cond_off:		.b32 0
+ctx_src_address_high:	.b32 0
+ctx_src_address_low:	.b32 0
+ctx_dst_address_high:	.b32 0
+ctx_dst_address_low:	.b32 0
+ctx_mode:		.b32 0
+.align 16
+ctx_key:		.skip 16
+ctx_iv:			.skip 16
+
+.align 0x80
+swap:
+.skip 32
+
+.align 8
+common_cmd_dtable:
+.b32 #ctx_query_address_high + 0x20000 ~0xff
+.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_query_counter + 0x20000 ~0xffffffff
+.b32 #cmd_query_get + 0x00000 ~1
+.b32 #ctx_cond_address_high + 0x20000 ~0xff
+.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
+.b32 #cmd_cond_mode + 0x00000 ~7
+.b32 #cmd_wrcache_flush + 0x00000 ~0
+.equ #common_cmd_max 0x88
+
+
+.align 8
+engine_cmd_dtable:
+.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_src_address_high + 0x20000 ~0xff
+.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_dst_address_high + 0x20000 ~0xff
+.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
+.b32 #sec_cmd_mode + 0x00000 ~0xf
+.b32 #sec_cmd_length + 0x10000 ~0x0ffffff0
+.equ #engine_cmd_max 0xce
+
+.align 4
+sec_dtable:
+.b16 #sec_copy_prep #sec_do_inout
+.b16 #sec_store_prep #sec_do_out
+.b16 #sec_ecb_e_prep #sec_do_inout
+.b16 #sec_ecb_d_prep #sec_do_inout
+.b16 #sec_cbc_e_prep #sec_do_inout
+.b16 #sec_cbc_d_prep #sec_do_inout
+.b16 #sec_pcbc_e_prep #sec_do_inout
+.b16 #sec_pcbc_d_prep #sec_do_inout
+.b16 #sec_cfb_e_prep #sec_do_inout
+.b16 #sec_cfb_d_prep #sec_do_inout
+.b16 #sec_ofb_prep #sec_do_inout
+.b16 #sec_ctr_prep #sec_do_inout
+.b16 #sec_cbc_mac_prep #sec_do_in
+.b16 #sec_cmac_finish_complete_prep #sec_do_in
+.b16 #sec_cmac_finish_partial_prep #sec_do_in
+
+.align 0x100
+
+.section #g98_psec_code
+
+	// $r0 is always set to 0 in our code - this allows some space savings.
+	clear b32 $r0
+
+	// set up the interrupt handler
+	mov $r1 #ih
+	mov $iv0 $r1
+
+	// init stack pointer
+	mov $sp $r0
+
+	// set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
+	movw $r1 0xfff0
+	sethi $r1 0
+	mov $r2 0x400
+	iowr I[$r2 + 0x300] $r1
+
+	// enable the interrupts
+	or $r1 0xc
+	iowr I[$r2] $r1
+
+	// enable fifo access and context switching
+	mov $r1 3
+	mov $r2 0x1200
+	iowr I[$r2] $r1
+
+	// enable i0 delivery
+	bset $flags ie0
+
+	// sleep forver, waking only for interrupts.
+	bset $flags $p0
+	spin:
+	sleep $p0
+	bra #spin
+
+// i0 handler
+ih:
+	// see which interrupts we got
+	iord $r1 I[$r0 + 0x200]
+
+	and $r2 $r1 0x8
+	cmpu b32 $r2 0
+	bra e #noctx
+
+		// context switch... prepare the regs for xfer
+		mov $r2 0x7700
+		mov $xtargets $r2
+		mov $xdbase $r0
+		// 128-byte context.
+		mov $r2 0
+		sethi $r2 0x50000
+
+		// read current channel
+		mov $r3 0x1400
+		iord $r4 I[$r3]
+		// if bit 30 set, it's active, so we have to unload it first.
+		shl b32 $r5 $r4 1
+		cmps b32 $r5 0
+		bra nc #ctxload
+
+			// unload the current channel - save the context
+			xdst $r0 $r2
+			xdwait
+			// and clear bit 30, then write back
+			bclr $r4 0x1e
+			iowr I[$r3] $r4
+			// tell PFIFO we unloaded
+			mov $r4 1
+			iowr I[$r3 + 0x200] $r4
+
+		bra #noctx
+
+		ctxload:
+			// no channel loaded - perhaps we're requested to load one
+			iord $r4 I[$r3 + 0x100]
+			shl b32 $r15 $r4 1
+			cmps b32 $r15 0
+			// if bit 30 of next channel not set, probably PFIFO is just
+			// killing a context. do a faux load, without the active bit.
+			bra nc #dummyload
+
+				// ok, do a real context load.
+				xdld $r0 $r2
+				xdwait
+				mov $r5 #ctx_dma
+				mov $r6 #dma_count - 1
+				ctxload_dma_loop:
+					ld b32 $r7 D[$r5 + $r6 * 4]
+					add b32 $r8 $r6 0x180
+					shl b32 $r8 8
+					iowr I[$r8] $r7
+					sub b32 $r6 1
+				bra nc #ctxload_dma_loop
+
+			dummyload:
+			// tell PFIFO we're done
+			mov $r5 2
+			iowr I[$r3 + 0x200] $r5
+
+	noctx:
+	and $r2 $r1 0x4
+	cmpu b32 $r2 0
+	bra e #nocmd
+
+		// incoming fifo command.
+		mov $r3 0x1900
+		iord $r2 I[$r3 + 0x100]
+		iord $r3 I[$r3]
+		// extract the method
+		and $r4 $r2 0x7ff
+		// shift the addr to proper position if we need to interrupt later
+		shl b32 $r2 0x10
+
+		// mthd 0 and 0x100 [NAME, NOP]: ignore
+		and $r5 $r4 0x7bf
+		cmpu b32 $r5 0
+		bra e #cmddone
+
+		mov $r5 #engine_cmd_dtable - 0xc0 * 8
+		mov $r6 #engine_cmd_max
+		cmpu b32 $r4 0xc0
+		bra nc #dtable_cmd
+		mov $r5 #common_cmd_dtable - 0x80 * 8
+		mov $r6 #common_cmd_max
+		cmpu b32 $r4 0x80
+		bra nc #dtable_cmd
+		cmpu b32 $r4 0x60
+		bra nc #dma_cmd
+		cmpu b32 $r4 0x50
+		bra ne #illegal_mthd
+
+			// mthd 0x140: PM_TRIGGER
+			mov $r2 0x2200
+			clear b32 $r3
+			sethi $r3 0x20000
+			iowr I[$r2] $r3
+			bra #cmddone
+
+		dma_cmd:
+			// mthd 0x180...: DMA_*
+			cmpu b32 $r4 0x60+#dma_count
+			bra nc #illegal_mthd
+			shl b32 $r5 $r4 2
+			add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
+			bset $r3 0x1e
+			st b32 D[$r5] $r3
+			add b32 $r4 0x180 - 0x60
+			shl b32 $r4 8
+			iowr I[$r4] $r3
+			bra #cmddone
+
+		dtable_cmd:
+			cmpu b32 $r4 $r6
+			bra nc #illegal_mthd
+			shl b32 $r4 3
+			add b32 $r4 $r5
+			ld b32 $r5 D[$r4 + 4]
+			and $r5 $r3
+			cmpu b32 $r5 0
+			bra ne #invalid_bitfield
+			ld b16 $r5 D[$r4]
+			ld b16 $r6 D[$r4 + 2]
+			cmpu b32 $r6 2
+			bra e #cmd_setctx
+			ld b32 $r7 D[$r0 + #ctx_cond_off]
+			and $r6 $r7
+			cmpu b32 $r6 1
+			bra e #cmddone
+			call $r5
+			bra $p1 #dispatch_error
+			bra #cmddone
+
+		cmd_setctx:
+			st b32 D[$r5] $r3
+			bra #cmddone
+
+
+		invalid_bitfield:
+			or $r2 1
+		dispatch_error:
+		illegal_mthd:
+			mov $r4 0x1000
+			iowr I[$r4] $r2
+			iowr I[$r4 + 0x100] $r3
+			mov $r4 0x40
+			iowr I[$r0] $r4
+
+			im_loop:
+				iord $r4 I[$r0 + 0x200]
+				and $r4 0x40
+				cmpu b32 $r4 0
+			bra ne #im_loop
+
+		cmddone:
+		// remove the command from FIFO
+		mov $r3 0x1d00
+		mov $r4 1
+		iowr I[$r3] $r4
+
+	nocmd:
+	// ack the processed interrupts
+	and $r1 $r1 0xc
+	iowr I[$r0 + 0x100] $r1
+iret
+
+cmd_query_get:
+	// if bit 0 of param set, trigger interrupt afterwards.
+	setp $p1 $r3
+	or $r2 3
+
+	// read PTIMER, beware of races...
+	mov $r4 0xb00
+	ptimer_retry:
+		iord $r6 I[$r4 + 0x100]
+		iord $r5 I[$r4]
+		iord $r7 I[$r4 + 0x100]
+		cmpu b32 $r6 $r7
+	bra ne #ptimer_retry
+
+	// prepare the query structure
+	ld b32 $r4 D[$r0 + #ctx_query_counter]
+	st b32 D[$r0 + #swap + 0x0] $r4
+	st b32 D[$r0 + #swap + 0x4] $r0
+	st b32 D[$r0 + #swap + 0x8] $r5
+	st b32 D[$r0 + #swap + 0xc] $r6
+
+	// will use target 0, DMA_QUERY.
+	mov $xtargets $r0
+
+	ld b32 $r4 D[$r0 + #ctx_query_address_high]
+	shl b32 $r4 0x18
+	mov $xdbase $r4
+
+	ld b32 $r4 D[$r0 + #ctx_query_address_low]
+	mov $r5 #swap
+	sethi $r5 0x20000
+	xdst $r4 $r5
+	xdwait
+
+	ret
+
+cmd_cond_mode:
+	// if >= 5, INVALID_ENUM
+	bset $flags $p1
+	or $r2 2
+	cmpu b32 $r3 5
+	bra nc #return
+
+	// otherwise, no error.
+	bclr $flags $p1
+
+	// if < 2, no QUERY object is involved
+	cmpu b32 $r3 2
+	bra nc #cmd_cond_mode_queryful
+
+		xor $r3 1
+		st b32 D[$r0 + #ctx_cond_off] $r3
+	return:
+		ret
+
+	cmd_cond_mode_queryful:
+	// ok, will need to pull a QUERY object, prepare offsets
+	ld b32 $r4 D[$r0 + #ctx_cond_address_high]
+	ld b32 $r5 D[$r0 + #ctx_cond_address_low]
+	and $r6 $r5 0xff
+	shr b32 $r5 8
+	shl b32 $r4 0x18
+	or $r4 $r5
+	mov $xdbase $r4
+	mov $xtargets $r0
+
+	// pull the first one
+	mov $r5 #swap
+	sethi $r5 0x20000
+	xdld $r6 $r5
+
+	// if == 2, only a single QUERY is involved...
+	cmpu b32 $r3 2
+	bra ne #cmd_cond_mode_double
+
+		xdwait
+		ld b32 $r4 D[$r0 + #swap + 4]
+		cmpu b32 $r4 0
+		xbit $r4 $flags z
+		st b32 D[$r0 + #ctx_cond_off] $r4
+		ret
+
+	// ok, we'll need to pull second one too
+	cmd_cond_mode_double:
+	add b32 $r6 0x10
+	add b32 $r5 0x10
+	xdld $r6 $r5
+	xdwait
+
+	// compare COUNTERs
+	ld b32 $r5 D[$r0 + #swap + 0x00]
+	ld b32 $r6 D[$r0 + #swap + 0x10]
+	cmpu b32 $r5 $r6
+	xbit $r4 $flags z
+
+	// compare RESen
+	ld b32 $r5 D[$r0 + #swap + 0x04]
+	ld b32 $r6 D[$r0 + #swap + 0x14]
+	cmpu b32 $r5 $r6
+	xbit $r5 $flags z
+	and $r4 $r5
+
+	// and negate or not, depending on mode
+	cmpu b32 $r3 3
+	xbit $r5 $flags z
+	xor $r4 $r5
+	st b32 D[$r0 + #ctx_cond_off] $r4
+	ret
+
+cmd_wrcache_flush:
+	bclr $flags $p1
+	mov $r2 0x2200
+	clear b32 $r3
+	sethi $r3 0x10000
+	iowr I[$r2] $r3
+	ret
+
+sec_cmd_mode:
+	// if >= 0xf, INVALID_ENUM
+	bset $flags $p1
+	or $r2 2
+	cmpu b32 $r3 0xf
+	bra nc #sec_cmd_mode_return
+
+		bclr $flags $p1
+		st b32 D[$r0 + #ctx_mode] $r3
+
+	sec_cmd_mode_return:
+	ret
+
+sec_cmd_length:
+	// nop if length == 0
+	cmpu b32 $r3 0
+	bra e #sec_cmd_mode_return
+
+	// init key, IV
+	cxset 3
+	mov $r4 #ctx_key
+	sethi $r4 0x70000
+	xdst $r0 $r4
+	mov $r4 #ctx_iv
+	sethi $r4 0x60000
+	xdst $r0 $r4
+	xdwait
+	ckeyreg $c7
+
+	// prepare the targets
+	mov $r4 0x2100
+	mov $xtargets $r4
+
+	// prepare src address
+	ld b32 $r4 D[$r0 + #ctx_src_address_high]
+	ld b32 $r5 D[$r0 + #ctx_src_address_low]
+	shr b32 $r8 $r5 8
+	shl b32 $r4 0x18
+	or $r4 $r8
+	and $r5 $r5 0xff
+
+	// prepare dst address
+	ld b32 $r6 D[$r0 + #ctx_dst_address_high]
+	ld b32 $r7 D[$r0 + #ctx_dst_address_low]
+	shr b32 $r8 $r7 8
+	shl b32 $r6 0x18
+	or $r6 $r8
+	and $r7 $r7 0xff
+
+	// find the proper prep & do functions
+	ld b32 $r8 D[$r0 + #ctx_mode]
+	shl b32 $r8 2
+
+	// run prep
+	ld b16 $r9 D[$r8 + #sec_dtable]
+	call $r9
+
+	// do it
+	ld b16 $r9 D[$r8 + #sec_dtable + 2]
+	call $r9
+	cxset 1
+	xdwait
+	cxset 0x61
+	xdwait
+	xdwait
+
+	// update src address
+	shr b32 $r8 $r4 0x18
+	shl b32 $r9 $r4 8
+	add b32 $r9 $r5
+	adc b32 $r8 0
+	st b32 D[$r0 + #ctx_src_address_high] $r8
+	st b32 D[$r0 + #ctx_src_address_low] $r9
+
+	// update dst address
+	shr b32 $r8 $r6 0x18
+	shl b32 $r9 $r6 8
+	add b32 $r9 $r7
+	adc b32 $r8 0
+	st b32 D[$r0 + #ctx_dst_address_high] $r8
+	st b32 D[$r0 + #ctx_dst_address_low] $r9
+
+	// pull updated IV
+	cxset 2
+	mov $r4 #ctx_iv
+	sethi $r4 0x60000
+	xdld $r0 $r4
+	xdwait
+
+	ret
+
+
+sec_copy_prep:
+	cs0begin 2
+		cxsin $c0
+		cxsout $c0
+	ret
+
+sec_store_prep:
+	cs0begin 1
+		cxsout $c6
+	ret
+
+sec_ecb_e_prep:
+	cs0begin 3
+		cxsin $c0
+		cenc $c0 $c0
+		cxsout $c0
+	ret
+
+sec_ecb_d_prep:
+	ckexp $c7 $c7
+	cs0begin 3
+		cxsin $c0
+		cdec $c0 $c0
+		cxsout $c0
+	ret
+
+sec_cbc_e_prep:
+	cs0begin 4
+		cxsin $c0
+		cxor $c6 $c0
+		cenc $c6 $c6
+		cxsout $c6
+	ret
+
+sec_cbc_d_prep:
+	ckexp $c7 $c7
+	cs0begin 5
+		cmov $c2 $c6
+		cxsin $c6
+		cdec $c0 $c6
+		cxor $c0 $c2
+		cxsout $c0
+	ret
+
+sec_pcbc_e_prep:
+	cs0begin 5
+		cxsin $c0
+		cxor $c6 $c0
+		cenc $c6 $c6
+		cxsout $c6
+		cxor $c6 $c0
+	ret
+
+sec_pcbc_d_prep:
+	ckexp $c7 $c7
+	cs0begin 5
+		cxsin $c0
+		cdec $c1 $c0
+		cxor $c6 $c1
+		cxsout $c6
+		cxor $c6 $c0
+	ret
+
+sec_cfb_e_prep:
+	cs0begin 4
+		cenc $c6 $c6
+		cxsin $c0
+		cxor $c6 $c0
+		cxsout $c6
+	ret
+
+sec_cfb_d_prep:
+	cs0begin 4
+		cenc $c0 $c6
+		cxsin $c6
+		cxor $c0 $c6
+		cxsout $c0
+	ret
+
+sec_ofb_prep:
+	cs0begin 4
+		cenc $c6 $c6
+		cxsin $c0
+		cxor $c0 $c6
+		cxsout $c0
+	ret
+
+sec_ctr_prep:
+	cs0begin 5
+		cenc $c1 $c6
+		cadd $c6 1
+		cxsin $c0
+		cxor $c0 $c1
+		cxsout $c0
+	ret
+
+sec_cbc_mac_prep:
+	cs0begin 3
+		cxsin $c0
+		cxor $c6 $c0
+		cenc $c6 $c6
+	ret
+
+sec_cmac_finish_complete_prep:
+	cs0begin 7
+		cxsin $c0
+		cxor $c6 $c0
+		cxor $c0 $c0
+		cenc $c0 $c0
+		cprecmac $c0 $c0
+		cxor $c6 $c0
+		cenc $c6 $c6
+	ret
+
+sec_cmac_finish_partial_prep:
+	cs0begin 8
+		cxsin $c0
+		cxor $c6 $c0
+		cxor $c0 $c0
+		cenc $c0 $c0
+		cprecmac $c0 $c0
+		cprecmac $c0 $c0
+		cxor $c6 $c0
+		cenc $c6 $c6
+	ret
+
+// TODO
+sec_do_in:
+	add b32 $r3 $r5
+	mov $xdbase $r4
+	mov $r9 #swap
+	sethi $r9 0x20000
+	sec_do_in_loop:
+		xdld $r5 $r9
+		xdwait
+		cxset 0x22
+		xdst $r0 $r9
+		cs0exec 1
+		xdwait
+		add b32 $r5 0x10
+		cmpu b32 $r5 $r3
+	bra ne #sec_do_in_loop
+	cxset 1
+	xdwait
+	ret
+
+sec_do_out:
+	add b32 $r3 $r7
+	mov $xdbase $r6
+	mov $r9 #swap
+	sethi $r9 0x20000
+	sec_do_out_loop:
+		cs0exec 1
+		cxset 0x61
+		xdld $r7 $r9
+		xdst $r7 $r9
+		cxset 1
+		xdwait
+		add b32 $r7 0x10
+		cmpu b32 $r7 $r3
+	bra ne #sec_do_out_loop
+	ret
+
+sec_do_inout:
+	add b32 $r3 $r5
+	mov $r9 #swap
+	sethi $r9 0x20000
+	sec_do_inout_loop:
+		mov $xdbase $r4
+		xdld $r5 $r9
+		xdwait
+		cxset 0x21
+		xdst $r0 $r9
+		cs0exec 1
+		cxset 0x61
+		mov $xdbase $r6
+		xdld $r7 $r9
+		xdst $r7 $r9
+		cxset 1
+		xdwait
+		add b32 $r5 0x10
+		add b32 $r7 0x10
+		cmpu b32 $r5 $r3
+	bra ne #sec_do_inout_loop
+	ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h
new file mode 100644
index 0000000..5d65c4f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h
@@ -0,0 +1,584 @@
+uint32_t g98_psec_data[] = {
+/* 0x0000: ctx_dma */
+/* 0x0000: ctx_dma_query */
+	0x00000000,
+/* 0x0004: ctx_dma_src */
+	0x00000000,
+/* 0x0008: ctx_dma_dst */
+	0x00000000,
+/* 0x000c: ctx_query_address_high */
+	0x00000000,
+/* 0x0010: ctx_query_address_low */
+	0x00000000,
+/* 0x0014: ctx_query_counter */
+	0x00000000,
+/* 0x0018: ctx_cond_address_high */
+	0x00000000,
+/* 0x001c: ctx_cond_address_low */
+	0x00000000,
+/* 0x0020: ctx_cond_off */
+	0x00000000,
+/* 0x0024: ctx_src_address_high */
+	0x00000000,
+/* 0x0028: ctx_src_address_low */
+	0x00000000,
+/* 0x002c: ctx_dst_address_high */
+	0x00000000,
+/* 0x0030: ctx_dst_address_low */
+	0x00000000,
+/* 0x0034: ctx_mode */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0040: ctx_key */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0050: ctx_iv */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0080: swap */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x00a0: common_cmd_dtable */
+	0x0002000c,
+	0xffffff00,
+	0x00020010,
+	0x0000000f,
+	0x00020014,
+	0x00000000,
+	0x00000192,
+	0xfffffffe,
+	0x00020018,
+	0xffffff00,
+	0x0002001c,
+	0x0000000f,
+	0x000001d7,
+	0xfffffff8,
+	0x00000260,
+	0xffffffff,
+/* 0x00e0: engine_cmd_dtable */
+	0x00020040,
+	0x00000000,
+	0x00020044,
+	0x00000000,
+	0x00020048,
+	0x00000000,
+	0x0002004c,
+	0x00000000,
+	0x00020050,
+	0x00000000,
+	0x00020054,
+	0x00000000,
+	0x00020058,
+	0x00000000,
+	0x0002005c,
+	0x00000000,
+	0x00020024,
+	0xffffff00,
+	0x00020028,
+	0x0000000f,
+	0x0002002c,
+	0xffffff00,
+	0x00020030,
+	0x0000000f,
+	0x00000271,
+	0xfffffff0,
+	0x00010285,
+	0xf000000f,
+/* 0x0150: sec_dtable */
+	0x04db0321,
+	0x04b1032f,
+	0x04db0339,
+	0x04db034b,
+	0x04db0361,
+	0x04db0377,
+	0x04db0395,
+	0x04db03af,
+	0x04db03cd,
+	0x04db03e3,
+	0x04db03f9,
+	0x04db040f,
+	0x04830429,
+	0x0483043b,
+	0x0483045d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t g98_psec_code[] = {
+	0x17f004bd,
+	0x0010fe35,
+	0xf10004fe,
+	0xf0fff017,
+	0x27f10013,
+	0x21d00400,
+	0x0c15f0c0,
+	0xf00021d0,
+	0x27f10317,
+	0x21d01200,
+	0x1031f400,
+/* 0x002f: spin */
+	0xf40031f4,
+	0x0ef40028,
+/* 0x0035: ih */
+	0x8001cffd,
+	0xb00812c4,
+	0x0bf40024,
+	0x0027f167,
+	0x002bfe77,
+	0xf00007fe,
+	0x23f00027,
+	0x0037f105,
+	0x0034cf14,
+	0xb0014594,
+	0x18f40055,
+	0x0602fa17,
+	0x4af003f8,
+	0x0034d01e,
+	0xd00147f0,
+	0x0ef48034,
+/* 0x0075: ctxload */
+	0x4034cf33,
+	0xb0014f94,
+	0x18f400f5,
+	0x0502fa21,
+	0x57f003f8,
+	0x0267f000,
+/* 0x008c: ctxload_dma_loop */
+	0xa07856bc,
+	0xb6018068,
+	0x87d00884,
+	0x0162b600,
+/* 0x009f: dummyload */
+	0xf0f018f4,
+	0x35d00257,
+/* 0x00a5: noctx */
+	0x0412c480,
+	0xf50024b0,
+	0xf100df0b,
+	0xcf190037,
+	0x33cf4032,
+	0xff24e400,
+	0x1024b607,
+	0x07bf45e4,
+	0xf50054b0,
+	0xf100b90b,
+	0xf1fae057,
+	0xb000ce67,
+	0x18f4c044,
+	0xa057f14d,
+	0x8867f1fc,
+	0x8044b000,
+	0xb03f18f4,
+	0x18f46044,
+	0x5044b019,
+	0xf1741bf4,
+	0xbd220027,
+	0x0233f034,
+	0xf50023d0,
+/* 0x0103: dma_cmd */
+	0xb000810e,
+	0x18f46344,
+	0x0245945e,
+	0xfe8050b7,
+	0x801e39f0,
+	0x40b70053,
+	0x44b60120,
+	0x0043d008,
+/* 0x0123: dtable_cmd */
+	0xb8600ef4,
+	0x18f40446,
+	0x0344b63e,
+	0x980045bb,
+	0x53fd0145,
+	0x0054b004,
+	0x58291bf4,
+	0x46580045,
+	0x0264b001,
+	0x98170bf4,
+	0x67fd0807,
+	0x0164b004,
+	0xf9300bf4,
+	0x0f01f455,
+/* 0x015b: cmd_setctx */
+	0x80280ef4,
+	0x0ef40053,
+/* 0x0161: invalid_bitfield */
+	0x0125f022,
+/* 0x0164: dispatch_error */
+/* 0x0164: illegal_mthd */
+	0x100047f1,
+	0xd00042d0,
+	0x47f04043,
+	0x0004d040,
+/* 0x0174: im_loop */
+	0xf08004cf,
+	0x44b04044,
+	0xf71bf400,
+/* 0x0180: cmddone */
+	0x1d0037f1,
+	0xd00147f0,
+/* 0x018a: nocmd */
+	0x11c40034,
+	0x4001d00c,
+/* 0x0192: cmd_query_get */
+	0x38f201f8,
+	0x0325f001,
+	0x0b0047f1,
+/* 0x019c: ptimer_retry */
+	0xcf4046cf,
+	0x47cf0045,
+	0x0467b840,
+	0x98f41bf4,
+	0x04800504,
+	0x21008020,
+	0x80220580,
+	0x0bfe2306,
+	0x03049800,
+	0xfe1844b6,
+	0x04980047,
+	0x8057f104,
+	0x0253f000,
+	0xf80645fa,
+/* 0x01d7: cmd_cond_mode */
+	0xf400f803,
+	0x25f00131,
+	0x0534b002,
+	0xf41218f4,
+	0x34b00132,
+	0x0b18f402,
+	0x800136f0,
+/* 0x01f2: return */
+	0x00f80803,
+/* 0x01f4: cmd_cond_mode_queryful */
+	0x98060498,
+	0x56c40705,
+	0x0855b6ff,
+	0xfd1844b6,
+	0x47fe0545,
+	0x000bfe00,
+	0x008057f1,
+	0xfa0253f0,
+	0x34b00565,
+	0x131bf402,
+	0x049803f8,
+	0x0044b021,
+	0x800b4cf0,
+	0x00f80804,
+/* 0x022c: cmd_cond_mode_double */
+	0xb61060b6,
+	0x65fa1050,
+	0x9803f805,
+	0x06982005,
+	0x0456b824,
+	0x980b4cf0,
+	0x06982105,
+	0x0456b825,
+	0xfd0b5cf0,
+	0x34b00445,
+	0x0b5cf003,
+	0x800645fd,
+	0x00f80804,
+/* 0x0260: cmd_wrcache_flush */
+	0xf10132f4,
+	0xbd220027,
+	0x0133f034,
+	0xf80023d0,
+/* 0x0271: sec_cmd_mode */
+	0x0131f400,
+	0xb00225f0,
+	0x18f40f34,
+	0x0132f409,
+/* 0x0283: sec_cmd_mode_return */
+	0xf80d0380,
+/* 0x0285: sec_cmd_length */
+	0x0034b000,
+	0xf4fb0bf4,
+	0x47f0033c,
+	0x0743f040,
+	0xf00604fa,
+	0x43f05047,
+	0x0604fa06,
+	0x3cf503f8,
+	0x47f1c407,
+	0x4bfe2100,
+	0x09049800,
+	0x950a0598,
+	0x44b60858,
+	0x0548fd18,
+	0x98ff55c4,
+	0x07980b06,
+	0x0878950c,
+	0xfd1864b6,
+	0x77c40568,
+	0x0d0898ff,
+	0x580284b6,
+	0x95f9a889,
+	0xf9a98958,
+	0x013cf495,
+	0x3cf403f8,
+	0xf803f861,
+	0x18489503,
+	0xbb084994,
+	0x81b60095,
+	0x09088000,
+	0x950a0980,
+	0x69941868,
+	0x0097bb08,
+	0x800081b6,
+	0x09800b08,
+	0x023cf40c,
+	0xf05047f0,
+	0x04fa0643,
+	0xf803f805,
+/* 0x0321: sec_copy_prep */
+	0x203cf500,
+	0x003cf594,
+	0x003cf588,
+/* 0x032f: sec_store_prep */
+	0xf500f88c,
+	0xf594103c,
+	0xf88c063c,
+/* 0x0339: sec_ecb_e_prep */
+	0x303cf500,
+	0x003cf594,
+	0x003cf588,
+	0x003cf5d0,
+/* 0x034b: sec_ecb_d_prep */
+	0xf500f88c,
+	0xf5c8773c,
+	0xf594303c,
+	0xf588003c,
+	0xf5d4003c,
+	0xf88c003c,
+/* 0x0361: sec_cbc_e_prep */
+	0x403cf500,
+	0x003cf594,
+	0x063cf588,
+	0x663cf5ac,
+	0x063cf5d0,
+/* 0x0377: sec_cbc_d_prep */
+	0xf500f88c,
+	0xf5c8773c,
+	0xf594503c,
+	0xf584623c,
+	0xf588063c,
+	0xf5d4603c,
+	0xf5ac203c,
+	0xf88c003c,
+/* 0x0395: sec_pcbc_e_prep */
+	0x503cf500,
+	0x003cf594,
+	0x063cf588,
+	0x663cf5ac,
+	0x063cf5d0,
+	0x063cf58c,
+/* 0x03af: sec_pcbc_d_prep */
+	0xf500f8ac,
+	0xf5c8773c,
+	0xf594503c,
+	0xf588003c,
+	0xf5d4013c,
+	0xf5ac163c,
+	0xf58c063c,
+	0xf8ac063c,
+/* 0x03cd: sec_cfb_e_prep */
+	0x403cf500,
+	0x663cf594,
+	0x003cf5d0,
+	0x063cf588,
+	0x063cf5ac,
+/* 0x03e3: sec_cfb_d_prep */
+	0xf500f88c,
+	0xf594403c,
+	0xf5d0603c,
+	0xf588063c,
+	0xf5ac603c,
+	0xf88c003c,
+/* 0x03f9: sec_ofb_prep */
+	0x403cf500,
+	0x663cf594,
+	0x003cf5d0,
+	0x603cf588,
+	0x003cf5ac,
+/* 0x040f: sec_ctr_prep */
+	0xf500f88c,
+	0xf594503c,
+	0xf5d0613c,
+	0xf5b0163c,
+	0xf588003c,
+	0xf5ac103c,
+	0xf88c003c,
+/* 0x0429: sec_cbc_mac_prep */
+	0x303cf500,
+	0x003cf594,
+	0x063cf588,
+	0x663cf5ac,
+/* 0x043b: sec_cmac_finish_complete_prep */
+	0xf500f8d0,
+	0xf594703c,
+	0xf588003c,
+	0xf5ac063c,
+	0xf5ac003c,
+	0xf5d0003c,
+	0xf5bc003c,
+	0xf5ac063c,
+	0xf8d0663c,
+/* 0x045d: sec_cmac_finish_partial_prep */
+	0x803cf500,
+	0x003cf594,
+	0x063cf588,
+	0x003cf5ac,
+	0x003cf5ac,
+	0x003cf5d0,
+	0x003cf5bc,
+	0x063cf5bc,
+	0x663cf5ac,
+/* 0x0483: sec_do_in */
+	0xbb00f8d0,
+	0x47fe0035,
+	0x8097f100,
+	0x0293f000,
+/* 0x0490: sec_do_in_loop */
+	0xf80559fa,
+	0x223cf403,
+	0xf50609fa,
+	0xf898103c,
+	0x1050b603,
+	0xf40453b8,
+	0x3cf4e91b,
+	0xf803f801,
+/* 0x04b1: sec_do_out */
+	0x0037bb00,
+	0xf10067fe,
+	0xf0008097,
+/* 0x04be: sec_do_out_loop */
+	0x3cf50293,
+	0x3cf49810,
+	0x0579fa61,
+	0xf40679fa,
+	0x03f8013c,
+	0xb81070b6,
+	0x1bf40473,
+/* 0x04db: sec_do_inout */
+	0xbb00f8e8,
+	0x97f10035,
+	0x93f00080,
+/* 0x04e5: sec_do_inout_loop */
+	0x0047fe02,
+	0xf80559fa,
+	0x213cf403,
+	0xf50609fa,
+	0xf498103c,
+	0x67fe613c,
+	0x0579fa00,
+	0xf40679fa,
+	0x03f8013c,
+	0xb61050b6,
+	0x53b81070,
+	0xd41bf404,
+	0x000000f8,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
new file mode 100644
index 0000000..9d5c1b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sec.h>
+#include <engine/falcon.h>
+#include "fuc/g98.fuc0s.h"
+
+#include <core/client.h>
+#include <core/enum.h>
+#include <engine/fifo.h>
+
+struct g98_sec_priv {
+	struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_sec_sclass[] = {
+	{ 0x88b4, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PSEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_sec_cclass = {
+	.handle = NV_ENGCTX(SEC, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_falcon_context_ctor,
+		.dtor = _nvkm_falcon_context_dtor,
+		.init = _nvkm_falcon_context_init,
+		.fini = _nvkm_falcon_context_fini,
+		.rd32 = _nvkm_falcon_context_rd32,
+		.wr32 = _nvkm_falcon_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PSEC engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_enum g98_sec_isr_error_name[] = {
+	{ 0x0000, "ILLEGAL_MTHD" },
+	{ 0x0001, "INVALID_BITFIELD" },
+	{ 0x0002, "INVALID_ENUM" },
+	{ 0x0003, "QUERY" },
+	{}
+};
+
+static void
+g98_sec_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+	struct nvkm_engine *engine = nv_engine(subdev);
+	struct nvkm_object *engctx;
+	struct g98_sec_priv *priv = (void *)subdev;
+	u32 disp = nv_rd32(priv, 0x08701c);
+	u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
+	u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
+	u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
+	u32 addr = nv_rd32(priv, 0x087040) >> 16;
+	u32 mthd = (addr & 0x07ff) << 2;
+	u32 subc = (addr & 0x3800) >> 11;
+	u32 data = nv_rd32(priv, 0x087044);
+	int chid;
+
+	engctx = nvkm_engctx_get(engine, inst);
+	chid   = pfifo->chid(pfifo, engctx);
+
+	if (stat & 0x00000040) {
+		nv_error(priv, "DISPATCH_ERROR [");
+		nvkm_enum_print(g98_sec_isr_error_name, ssta);
+		pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
+		       chid, (u64)inst << 12, nvkm_client_name(engctx),
+		       subc, mthd, data);
+		nv_wr32(priv, 0x087004, 0x00000040);
+		stat &= ~0x00000040;
+	}
+
+	if (stat) {
+		nv_error(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x087004, stat);
+	}
+
+	nvkm_engctx_put(engctx);
+}
+
+static int
+g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct g98_sec_priv *priv;
+	int ret;
+
+	ret = nvkm_falcon_create(parent, engine, oclass, 0x087000, true,
+				 "PSEC", "sec", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00004000;
+	nv_subdev(priv)->intr = g98_sec_intr;
+	nv_engine(priv)->cclass = &g98_sec_cclass;
+	nv_engine(priv)->sclass = g98_sec_sclass;
+	nv_falcon(priv)->code.data = g98_psec_code;
+	nv_falcon(priv)->code.size = sizeof(g98_psec_code);
+	nv_falcon(priv)->data.data = g98_psec_data;
+	nv_falcon(priv)->data.size = sizeof(g98_psec_data);
+	return 0;
+}
+
+struct nvkm_oclass
+g98_sec_oclass = {
+	.handle = NV_ENGINE(SEC, 0x98),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g98_sec_ctor,
+		.dtor = _nvkm_falcon_dtor,
+		.init = _nvkm_falcon_init,
+		.fini = _nvkm_falcon_fini,
+		.rd32 = _nvkm_falcon_rd32,
+		.wr32 = _nvkm_falcon_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild
new file mode 100644
index 0000000..bdc3a059
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/engine/sw/nv04.o
+nvkm-y += nvkm/engine/sw/nv10.o
+nvkm-y += nvkm/engine/sw/nv50.o
+nvkm-y += nvkm/engine/sw/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
new file mode 100644
index 0000000..533d5d8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bar.h>
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+gf100_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	u64 data = *(u32 *)args;
+	if (mthd == 0x0400) {
+		chan->vblank.offset &= 0x00ffffffffULL;
+		chan->vblank.offset |= data << 32;
+	} else {
+		chan->vblank.offset &= 0xff00000000ULL;
+		chan->vblank.offset |= data;
+	}
+	return 0;
+}
+
+static int
+gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd,
+			 void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+	u32 data = *(u32 *)args;
+
+	switch (mthd) {
+	case 0x600:
+		nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */
+		break;
+	case 0x644:
+		if (data & ~0x1ffffe)
+			return -EINVAL;
+		nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */
+		break;
+	case 0x6ac:
+		nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct nvkm_omthds
+gf100_sw_omthds[] = {
+	{ 0x0400, 0x0400, gf100_sw_mthd_vblsem_offset },
+	{ 0x0404, 0x0404, gf100_sw_mthd_vblsem_offset },
+	{ 0x0408, 0x0408, nv50_sw_mthd_vblsem_value },
+	{ 0x040c, 0x040c, nv50_sw_mthd_vblsem_release },
+	{ 0x0500, 0x0500, nv50_sw_mthd_flip },
+	{ 0x0600, 0x0600, gf100_sw_mthd_mp_control },
+	{ 0x0644, 0x0644, gf100_sw_mthd_mp_control },
+	{ 0x06ac, 0x06ac, gf100_sw_mthd_mp_control },
+	{}
+};
+
+static struct nvkm_oclass
+gf100_sw_sclass[] = {
+	{ 0x906e, &nvkm_object_ofuncs, gf100_sw_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+gf100_sw_vblsem_release(struct nvkm_notify *notify)
+{
+	struct nv50_sw_chan *chan =
+		container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+	struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+	struct nvkm_bar *bar = nvkm_bar(priv);
+
+	nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
+	bar->flush(bar);
+	nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
+	nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
+	nv_wr32(priv, 0x060014, chan->vblank.value);
+
+	return NVKM_NOTIFY_DROP;
+}
+
+static struct nv50_sw_cclass
+gf100_sw_cclass = {
+	.base.handle = NV_ENGCTX(SW, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_sw_context_ctor,
+		.dtor = nv50_sw_context_dtor,
+		.init = _nvkm_sw_context_init,
+		.fini = _nvkm_sw_context_fini,
+	},
+	.vblank = gf100_sw_vblsem_release,
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf100_sw_oclass = &(struct nv50_sw_oclass) {
+	.base.handle = NV_ENGINE(SW, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_sw_ctor,
+		.dtor = _nvkm_sw_dtor,
+		.init = _nvkm_sw_init,
+		.fini = _nvkm_sw_fini,
+	},
+	.cclass = &gf100_sw_cclass.base,
+	.sclass =  gf100_sw_sclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
new file mode 100644
index 0000000..8970244
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sw.h>
+#include <engine/fifo.h>
+
+struct nv04_sw_priv {
+	struct nvkm_sw base;
+};
+
+struct nv04_sw_chan {
+	struct nvkm_sw_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+	struct nvkm_object *channel = (void *)nv_engctx(object->parent);
+	struct nvkm_fifo_chan *fifo = (void *)channel->parent;
+	atomic_set(&fifo->refcnt, *(u32*)data);
+	return 0;
+}
+
+static int
+nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+	struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv04_sw_omthds[] = {
+	{ 0x0150, 0x0150, nv04_sw_set_ref },
+	{ 0x0500, 0x0500, nv04_sw_flip },
+	{}
+};
+
+static struct nvkm_oclass
+nv04_sw_sclass[] = {
+	{ 0x006e, &nvkm_object_ofuncs, nv04_sw_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv04_sw_chan *chan;
+	int ret;
+
+	ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nvkm_oclass
+nv04_sw_cclass = {
+	.handle = NV_ENGCTX(SW, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_sw_context_ctor,
+		.dtor = _nvkm_sw_context_dtor,
+		.init = _nvkm_sw_context_init,
+		.fini = _nvkm_sw_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+void
+nv04_sw_intr(struct nvkm_subdev *subdev)
+{
+	nv_mask(subdev, 0x000100, 0x80000000, 0x00000000);
+}
+
+static int
+nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv04_sw_priv *priv;
+	int ret;
+
+	ret = nvkm_sw_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nv04_sw_cclass;
+	nv_engine(priv)->sclass = nv04_sw_sclass;
+	nv_subdev(priv)->intr = nv04_sw_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_sw_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(SW, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_sw_ctor,
+		.dtor = _nvkm_sw_dtor,
+		.init = _nvkm_sw_init,
+		.fini = _nvkm_sw_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
new file mode 100644
index 0000000..c61153a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sw.h>
+
+struct nv10_sw_priv {
+	struct nvkm_sw base;
+};
+
+struct nv10_sw_chan {
+	struct nvkm_sw_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+	struct nv10_sw_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv10_sw_omthds[] = {
+	{ 0x0500, 0x0500, nv10_sw_flip },
+	{}
+};
+
+static struct nvkm_oclass
+nv10_sw_sclass[] = {
+	{ 0x016e, &nvkm_object_ofuncs, nv10_sw_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nv10_sw_chan *chan;
+	int ret;
+
+	ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct nvkm_oclass
+nv10_sw_cclass = {
+	.handle = NV_ENGCTX(SW, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_sw_context_ctor,
+		.dtor = _nvkm_sw_context_dtor,
+		.init = _nvkm_sw_context_init,
+		.fini = _nvkm_sw_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv10_sw_priv *priv;
+	int ret;
+
+	ret = nvkm_sw_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = &nv10_sw_cclass;
+	nv_engine(priv)->sclass = nv10_sw_sclass;
+	nv_subdev(priv)->intr = nv04_sw_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv10_sw_oclass = &(struct nvkm_oclass) {
+	.handle = NV_ENGINE(SW, 0x10),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_sw_ctor,
+		.dtor = _nvkm_sw_dtor,
+		.init = _nvkm_sw_init,
+		.fini = _nvkm_sw_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
new file mode 100644
index 0000000..401fcd7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+#include <engine/disp.h>
+#include <subdev/bar.h>
+
+#include <nvif/event.h>
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv50_sw_mthd_dma_vblsem(struct nvkm_object *object, u32 mthd,
+			void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent;
+	struct nvkm_handle *handle;
+	int ret = -EINVAL;
+
+	handle = nvkm_namedb_get(nv_namedb(fifo), *(u32 *)args);
+	if (!handle)
+		return -ENOENT;
+
+	if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+		struct nvkm_gpuobj *gpuobj = nv_gpuobj(handle->object);
+		chan->vblank.ctxdma = gpuobj->node->offset >> 4;
+		ret = 0;
+	}
+	nvkm_namedb_put(handle);
+	return ret;
+}
+
+static int
+nv50_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd,
+			   void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	chan->vblank.offset = *(u32 *)args;
+	return 0;
+}
+
+int
+nv50_sw_mthd_vblsem_value(struct nvkm_object *object, u32 mthd,
+			  void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	chan->vblank.value = *(u32 *)args;
+	return 0;
+}
+
+int
+nv50_sw_mthd_vblsem_release(struct nvkm_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	u32 head = *(u32 *)args;
+	if (head >= nvkm_disp(chan)->vblank.index_nr)
+		return -EINVAL;
+
+	nvkm_notify_get(&chan->vblank.notify[head]);
+	return 0;
+}
+
+int
+nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+	struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+	if (chan->base.flip)
+		return chan->base.flip(chan->base.flip_data);
+	return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv50_sw_omthds[] = {
+	{ 0x018c, 0x018c, nv50_sw_mthd_dma_vblsem },
+	{ 0x0400, 0x0400, nv50_sw_mthd_vblsem_offset },
+	{ 0x0404, 0x0404, nv50_sw_mthd_vblsem_value },
+	{ 0x0408, 0x0408, nv50_sw_mthd_vblsem_release },
+	{ 0x0500, 0x0500, nv50_sw_mthd_flip },
+	{}
+};
+
+static struct nvkm_oclass
+nv50_sw_sclass[] = {
+	{ 0x506e, &nvkm_object_ofuncs, nv50_sw_omthds },
+	{}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv50_sw_vblsem_release(struct nvkm_notify *notify)
+{
+	struct nv50_sw_chan *chan =
+		container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+	struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+	struct nvkm_bar *bar = nvkm_bar(priv);
+
+	nv_wr32(priv, 0x001704, chan->vblank.channel);
+	nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+	bar->flush(bar);
+
+	if (nv_device(priv)->chipset == 0x50) {
+		nv_wr32(priv, 0x001570, chan->vblank.offset);
+		nv_wr32(priv, 0x001574, chan->vblank.value);
+	} else {
+		nv_wr32(priv, 0x060010, chan->vblank.offset);
+		nv_wr32(priv, 0x060014, chan->vblank.value);
+	}
+
+	return NVKM_NOTIFY_DROP;
+}
+
+void
+nv50_sw_context_dtor(struct nvkm_object *object)
+{
+	struct nv50_sw_chan *chan = (void *)object;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
+		nvkm_notify_fini(&chan->vblank.notify[i]);
+
+	nvkm_sw_context_destroy(&chan->base);
+}
+
+int
+nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, void *data, u32 size,
+		     struct nvkm_object **pobject)
+{
+	struct nvkm_disp *pdisp = nvkm_disp(parent);
+	struct nv50_sw_cclass *pclass = (void *)oclass;
+	struct nv50_sw_chan *chan;
+	int ret, i;
+
+	ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
+		ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
+				       false,
+				       &(struct nvif_notify_head_req_v0) {
+					.head = i,
+				       },
+				       sizeof(struct nvif_notify_head_req_v0),
+				       sizeof(struct nvif_notify_head_rep_v0),
+				       &chan->vblank.notify[i]);
+		if (ret)
+			return ret;
+	}
+
+	chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+	return 0;
+}
+
+static struct nv50_sw_cclass
+nv50_sw_cclass = {
+	.base.handle = NV_ENGCTX(SW, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_sw_context_ctor,
+		.dtor = nv50_sw_context_dtor,
+		.init = _nvkm_sw_context_init,
+		.fini = _nvkm_sw_context_fini,
+	},
+	.vblank = nv50_sw_vblsem_release,
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+int
+nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv50_sw_oclass *pclass = (void *)oclass;
+	struct nv50_sw_priv *priv;
+	int ret;
+
+	ret = nvkm_sw_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_engine(priv)->cclass = pclass->cclass;
+	nv_engine(priv)->sclass = pclass->sclass;
+	nv_subdev(priv)->intr = nv04_sw_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_sw_oclass = &(struct nv50_sw_oclass) {
+	.base.handle = NV_ENGINE(SW, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_sw_ctor,
+		.dtor = _nvkm_sw_dtor,
+		.init = _nvkm_sw_init,
+		.fini = _nvkm_sw_fini,
+	},
+	.cclass = &nv50_sw_cclass.base,
+	.sclass =  nv50_sw_sclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
new file mode 100644
index 0000000..d8adc11
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
@@ -0,0 +1,45 @@
+#ifndef __NVKM_SW_NV50_H__
+#define __NVKM_SW_NV50_H__
+#include <engine/sw.h>
+#include <core/notify.h>
+
+struct nv50_sw_oclass {
+	struct nvkm_oclass base;
+	struct nvkm_oclass *cclass;
+	struct nvkm_oclass *sclass;
+};
+
+struct nv50_sw_priv {
+	struct nvkm_sw base;
+};
+
+int  nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+
+struct nv50_sw_cclass {
+	struct nvkm_oclass base;
+	int (*vblank)(struct nvkm_notify *);
+};
+
+struct nv50_sw_chan {
+	struct nvkm_sw_chan base;
+	struct {
+		struct nvkm_notify notify[4];
+		u32 channel;
+		u32 ctxdma;
+		u64 offset;
+		u32 value;
+	} vblank;
+};
+
+int  nv50_sw_context_ctor(struct nvkm_object *,
+				struct nvkm_object *,
+				struct nvkm_oclass *, void *, u32,
+				struct nvkm_object **);
+void nv50_sw_context_dtor(struct nvkm_object *);
+
+int nv50_sw_mthd_vblsem_value(struct nvkm_object *, u32, void *, u32);
+int nv50_sw_mthd_vblsem_release(struct nvkm_object *, u32, void *, u32);
+int nv50_sw_mthd_flip(struct nvkm_object *, u32, void *, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild
new file mode 100644
index 0000000..6b390eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/vp/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c
new file mode 100644
index 0000000..45f4e18
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs, Ilia Mirkin
+ */
+#include <engine/vp.h>
+#include <engine/xtensa.h>
+
+#include <core/engctx.h>
+
+/*******************************************************************************
+ * VP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_vp_sclass[] = {
+	{ 0x7476, &nvkm_object_ofuncs },
+	{},
+};
+
+/*******************************************************************************
+ * PVP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_vp_cclass = {
+	.handle = NV_ENGCTX(VP, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_xtensa_engctx_ctor,
+		.dtor = _nvkm_engctx_dtor,
+		.init = _nvkm_engctx_init,
+		.fini = _nvkm_engctx_fini,
+		.rd32 = _nvkm_engctx_rd32,
+		.wr32 = _nvkm_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PVP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	    struct nvkm_oclass *oclass, void *data, u32 size,
+	    struct nvkm_object **pobject)
+{
+	struct nvkm_xtensa *priv;
+	int ret;
+
+	ret = nvkm_xtensa_create(parent, engine, oclass, 0xf000, true,
+				 "PVP", "vp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x01020000;
+	nv_engine(priv)->cclass = &g84_vp_cclass;
+	nv_engine(priv)->sclass = g84_vp_sclass;
+	priv->fifo_val = 0x111;
+	priv->unkd28 = 0x9c544;
+	return 0;
+}
+
+struct nvkm_oclass
+g84_vp_oclass = {
+	.handle = NV_ENGINE(VP, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_vp_ctor,
+		.dtor = _nvkm_xtensa_dtor,
+		.init = _nvkm_xtensa_init,
+		.fini = _nvkm_xtensa_fini,
+		.rd32 = _nvkm_xtensa_rd32,
+		.wr32 = _nvkm_xtensa_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c
new file mode 100644
index 0000000..cea90df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2013 Ilia Mirkin
+ *
+ * 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 <engine/xtensa.h>
+#include <core/device.h>
+
+#include <core/engctx.h>
+
+u32
+_nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_xtensa *xtensa = (void *)object;
+	return nv_rd32(xtensa, xtensa->addr + addr);
+}
+
+void
+_nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_xtensa *xtensa = (void *)object;
+	nv_wr32(xtensa, xtensa->addr + addr, data);
+}
+
+int
+_nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+			 struct nvkm_oclass *oclass, void *data, u32 size,
+			 struct nvkm_object **pobject)
+{
+	struct nvkm_engctx *engctx;
+	int ret;
+
+	ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+	*pobject = nv_object(engctx);
+	return ret;
+}
+
+void
+_nvkm_xtensa_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_xtensa *xtensa = (void *)subdev;
+	u32 unk104 = nv_ro32(xtensa, 0xd04);
+	u32 intr = nv_ro32(xtensa, 0xc20);
+	u32 chan = nv_ro32(xtensa, 0xc28);
+	u32 unk10c = nv_ro32(xtensa, 0xd0c);
+
+	if (intr & 0x10)
+		nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
+	nv_wo32(xtensa, 0xc20, intr);
+	intr = nv_ro32(xtensa, 0xc20);
+	if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
+		nv_debug(xtensa, "Enabling FIFO_CTRL\n");
+		nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
+	}
+}
+
+int
+nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, u32 addr, bool enable,
+		    const char *iname, const char *fname,
+		    int length, void **pobject)
+{
+	struct nvkm_xtensa *xtensa;
+	int ret;
+
+	ret = nvkm_engine_create_(parent, engine, oclass, enable, iname,
+				  fname, length, pobject);
+	xtensa = *pobject;
+	if (ret)
+		return ret;
+
+	nv_subdev(xtensa)->intr = _nvkm_xtensa_intr;
+	xtensa->addr = addr;
+	return 0;
+}
+
+int
+_nvkm_xtensa_init(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nvkm_xtensa *xtensa = (void *)object;
+	const struct firmware *fw;
+	char name[32];
+	int i, ret;
+	u32 tmp;
+
+	ret = nvkm_engine_init(&xtensa->base);
+	if (ret)
+		return ret;
+
+	if (!xtensa->gpu_fw) {
+		snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
+			 xtensa->addr >> 12);
+
+		ret = request_firmware(&fw, name, nv_device_base(device));
+		if (ret) {
+			nv_warn(xtensa, "unable to load firmware %s\n", name);
+			return ret;
+		}
+
+		if (fw->size > 0x40000) {
+			nv_warn(xtensa, "firmware %s too large\n", name);
+			release_firmware(fw);
+			return -EINVAL;
+		}
+
+		ret = nvkm_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
+				      &xtensa->gpu_fw);
+		if (ret) {
+			release_firmware(fw);
+			return ret;
+		}
+
+		nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
+			 xtensa->gpu_fw->addr);
+
+		for (i = 0; i < fw->size / 4; i++)
+			nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
+		release_firmware(fw);
+	}
+
+	nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
+	nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
+
+	nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
+	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+	nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
+	nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
+	nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
+
+	tmp = nv_rd32(xtensa, 0x0);
+	nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
+
+	nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
+
+	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+	return 0;
+}
+
+int
+_nvkm_xtensa_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_xtensa *xtensa = (void *)object;
+
+	nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
+	nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
+
+	if (!suspend)
+		nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw);
+
+	return nvkm_engine_fini(&xtensa->base, suspend);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
new file mode 100644
index 0000000..a1bb3e4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
@@ -0,0 +1,19 @@
+include $(src)/nvkm/subdev/bar/Kbuild
+include $(src)/nvkm/subdev/bios/Kbuild
+include $(src)/nvkm/subdev/bus/Kbuild
+include $(src)/nvkm/subdev/clk/Kbuild
+include $(src)/nvkm/subdev/devinit/Kbuild
+include $(src)/nvkm/subdev/fb/Kbuild
+include $(src)/nvkm/subdev/fuse/Kbuild
+include $(src)/nvkm/subdev/gpio/Kbuild
+include $(src)/nvkm/subdev/i2c/Kbuild
+include $(src)/nvkm/subdev/ibus/Kbuild
+include $(src)/nvkm/subdev/instmem/Kbuild
+include $(src)/nvkm/subdev/ltc/Kbuild
+include $(src)/nvkm/subdev/mc/Kbuild
+include $(src)/nvkm/subdev/mmu/Kbuild
+include $(src)/nvkm/subdev/mxm/Kbuild
+include $(src)/nvkm/subdev/pmu/Kbuild
+include $(src)/nvkm/subdev/therm/Kbuild
+include $(src)/nvkm/subdev/timer/Kbuild
+include $(src)/nvkm/subdev/volt/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
new file mode 100644
index 0000000..1ab554a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/bar/base.o
+nvkm-y += nvkm/subdev/bar/nv50.o
+nvkm-y += nvkm/subdev/bar/gf100.o
+nvkm-y += nvkm/subdev/bar/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c
new file mode 100644
index 0000000..3502d00
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+
+struct nvkm_barobj {
+	struct nvkm_object base;
+	struct nvkm_vma vma;
+	void __iomem *iomem;
+};
+
+static int
+nvkm_barobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_bar *bar = nvkm_bar(device);
+	struct nvkm_mem *mem = data;
+	struct nvkm_barobj *barobj;
+	int ret;
+
+	ret = nvkm_object_create(parent, engine, oclass, 0, &barobj);
+	*pobject = nv_object(barobj);
+	if (ret)
+		return ret;
+
+	ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma);
+	if (ret)
+		return ret;
+
+	barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
+				(u32)barobj->vma.offset, mem->size << 12);
+	if (!barobj->iomem) {
+		nv_warn(bar, "PRAMIN ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void
+nvkm_barobj_dtor(struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = nvkm_bar(object);
+	struct nvkm_barobj *barobj = (void *)object;
+	if (barobj->vma.node) {
+		if (barobj->iomem)
+			iounmap(barobj->iomem);
+		bar->unmap(bar, &barobj->vma);
+	}
+	nvkm_object_destroy(&barobj->base);
+}
+
+static u32
+nvkm_barobj_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_barobj *barobj = (void *)object;
+	return ioread32_native(barobj->iomem + addr);
+}
+
+static void
+nvkm_barobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_barobj *barobj = (void *)object;
+	iowrite32_native(data, barobj->iomem + addr);
+}
+
+static struct nvkm_oclass
+nvkm_barobj_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nvkm_barobj_ctor,
+		.dtor = nvkm_barobj_dtor,
+		.init = nvkm_object_init,
+		.fini = nvkm_object_fini,
+		.rd32 = nvkm_barobj_rd32,
+		.wr32 = nvkm_barobj_wr32,
+	},
+};
+
+int
+nvkm_bar_alloc(struct nvkm_bar *bar, struct nvkm_object *parent,
+	       struct nvkm_mem *mem, struct nvkm_object **pobject)
+{
+	struct nvkm_object *gpuobj;
+	int ret = nvkm_object_ctor(parent, &parent->engine->subdev.object,
+				   &nvkm_barobj_oclass, mem, 0, &gpuobj);
+	if (ret == 0)
+		*pobject = gpuobj;
+	return ret;
+}
+
+int
+nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_bar *bar;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL",
+				  "bar", length, pobject);
+	bar = *pobject;
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void
+nvkm_bar_destroy(struct nvkm_bar *bar)
+{
+	nvkm_subdev_destroy(&bar->base);
+}
+
+void
+_nvkm_bar_dtor(struct nvkm_object *object)
+{
+	struct nvkm_bar *bar = (void *)object;
+	nvkm_bar_destroy(bar);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
new file mode 100644
index 0000000..12a1aeb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+
+struct gf100_bar_priv_vm {
+	struct nvkm_gpuobj *mem;
+	struct nvkm_gpuobj *pgd;
+	struct nvkm_vm *vm;
+};
+
+struct gf100_bar_priv {
+	struct nvkm_bar base;
+	spinlock_t lock;
+	struct gf100_bar_priv_vm bar[2];
+};
+
+static int
+gf100_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+	       struct nvkm_vma *vma)
+{
+	struct gf100_bar_priv *priv = (void *)bar;
+	int ret;
+
+	ret = nvkm_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma);
+	if (ret)
+		return ret;
+
+	nvkm_vm_map(vma, mem);
+	return 0;
+}
+
+static int
+gf100_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+	       struct nvkm_vma *vma)
+{
+	struct gf100_bar_priv *priv = (void *)bar;
+	int ret;
+
+	ret = nvkm_vm_get(priv->bar[1].vm, mem->size << 12,
+			  mem->page_shift, flags, vma);
+	if (ret)
+		return ret;
+
+	nvkm_vm_map(vma, mem);
+	return 0;
+}
+
+static void
+gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma)
+{
+	nvkm_vm_unmap(vma);
+	nvkm_vm_put(vma);
+}
+
+static int
+gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm,
+		  int bar_nr)
+{
+	struct nvkm_device *device = nv_device(&priv->base);
+	struct nvkm_vm *vm;
+	resource_size_t bar_len;
+	int ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
+			      &bar_vm->mem);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
+			      &bar_vm->pgd);
+	if (ret)
+		return ret;
+
+	bar_len = nv_device_resource_len(device, bar_nr);
+
+	ret = nvkm_vm_new(device, 0, bar_len, 0, &vm);
+	if (ret)
+		return ret;
+
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+	/*
+	 * Bootstrap page table lookup.
+	 */
+	if (bar_nr == 3) {
+		ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+				      (bar_len >> 12) * 8, 0x1000,
+				      NVOBJ_FLAG_ZERO_ALLOC,
+				      &vm->pgt[0].obj[0]);
+		vm->pgt[0].refcount[0] = 1;
+		if (ret)
+			return ret;
+	}
+
+	ret = nvkm_vm_ref(vm, &bar_vm->vm, bar_vm->pgd);
+	nvkm_vm_ref(NULL, &vm, NULL);
+	if (ret)
+		return ret;
+
+	nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr));
+	nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr));
+	nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1));
+	nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1));
+	return 0;
+}
+
+int
+gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct gf100_bar_priv *priv;
+	bool has_bar3 = nv_device_resource_len(device, 3) != 0;
+	int ret;
+
+	ret = nvkm_bar_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	/* BAR3 */
+	if (has_bar3) {
+		ret = gf100_bar_ctor_vm(priv, &priv->bar[0], 3);
+		if (ret)
+			return ret;
+	}
+
+	/* BAR1 */
+	ret = gf100_bar_ctor_vm(priv, &priv->bar[1], 1);
+	if (ret)
+		return ret;
+
+	if (has_bar3) {
+		priv->base.alloc = nvkm_bar_alloc;
+		priv->base.kmap = gf100_bar_kmap;
+	}
+	priv->base.umap = gf100_bar_umap;
+	priv->base.unmap = gf100_bar_unmap;
+	priv->base.flush = g84_bar_flush;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+void
+gf100_bar_dtor(struct nvkm_object *object)
+{
+	struct gf100_bar_priv *priv = (void *)object;
+
+	nvkm_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd);
+	nvkm_gpuobj_ref(NULL, &priv->bar[1].pgd);
+	nvkm_gpuobj_ref(NULL, &priv->bar[1].mem);
+
+	if (priv->bar[0].vm) {
+		nvkm_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]);
+		nvkm_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd);
+	}
+	nvkm_gpuobj_ref(NULL, &priv->bar[0].pgd);
+	nvkm_gpuobj_ref(NULL, &priv->bar[0].mem);
+
+	nvkm_bar_destroy(&priv->base);
+}
+
+int
+gf100_bar_init(struct nvkm_object *object)
+{
+	struct gf100_bar_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_bar_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+
+	nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
+	if (priv->bar[0].mem)
+		nv_wr32(priv, 0x001714,
+			0xc0000000 | priv->bar[0].mem->addr >> 12);
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_bar_oclass = {
+	.handle = NV_SUBDEV(BAR, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_bar_ctor,
+		.dtor = gf100_bar_dtor,
+		.init = gf100_bar_init,
+		.fini = _nvkm_bar_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c
new file mode 100644
index 0000000..148f739
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "priv.h"
+
+int
+gk20a_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_bar *bar;
+	int ret;
+
+	ret = gf100_bar_ctor(parent, engine, oclass, data, size, pobject);
+	if (ret)
+		return ret;
+
+	bar = (struct nvkm_bar *)*pobject;
+	bar->iomap_uncached = true;
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_bar_oclass = {
+	.handle = NV_SUBDEV(BAR, 0xea),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_bar_ctor,
+		.dtor = gf100_bar_dtor,
+		.init = gf100_bar_init,
+		.fini = _nvkm_bar_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
new file mode 100644
index 0000000..8548adb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+struct nv50_bar_priv {
+	struct nvkm_bar base;
+	spinlock_t lock;
+	struct nvkm_gpuobj *mem;
+	struct nvkm_gpuobj *pad;
+	struct nvkm_gpuobj *pgd;
+	struct nvkm_vm *bar1_vm;
+	struct nvkm_gpuobj *bar1;
+	struct nvkm_vm *bar3_vm;
+	struct nvkm_gpuobj *bar3;
+};
+
+static int
+nv50_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+	      struct nvkm_vma *vma)
+{
+	struct nv50_bar_priv *priv = (void *)bar;
+	int ret;
+
+	ret = nvkm_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma);
+	if (ret)
+		return ret;
+
+	nvkm_vm_map(vma, mem);
+	return 0;
+}
+
+static int
+nv50_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+	      struct nvkm_vma *vma)
+{
+	struct nv50_bar_priv *priv = (void *)bar;
+	int ret;
+
+	ret = nvkm_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma);
+	if (ret)
+		return ret;
+
+	nvkm_vm_map(vma, mem);
+	return 0;
+}
+
+static void
+nv50_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma)
+{
+	nvkm_vm_unmap(vma);
+	nvkm_vm_put(vma);
+}
+
+static void
+nv50_bar_flush(struct nvkm_bar *bar)
+{
+	struct nv50_bar_priv *priv = (void *)bar;
+	unsigned long flags;
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_wr32(priv, 0x00330c, 0x00000001);
+	if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000))
+		nv_warn(priv, "flush timeout\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void
+g84_bar_flush(struct nvkm_bar *bar)
+{
+	struct nv50_bar_priv *priv = (void *)bar;
+	unsigned long flags;
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_wr32(bar, 0x070000, 0x00000001);
+	if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000))
+		nv_warn(priv, "flush timeout\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int
+nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_object *heap;
+	struct nvkm_vm *vm;
+	struct nv50_bar_priv *priv;
+	u64 start, limit;
+	int ret;
+
+	ret = nvkm_bar_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
+			      NVOBJ_FLAG_HEAP, &priv->mem);
+	heap = nv_object(priv->mem);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), heap,
+			      (device->chipset == 0x50) ? 0x1400 : 0x0200,
+			      0, 0, &priv->pad);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), heap, 0x4000, 0, 0, &priv->pgd);
+	if (ret)
+		return ret;
+
+	/* BAR3 */
+	start = 0x0100000000ULL;
+	limit = start + nv_device_resource_len(device, 3);
+
+	ret = nvkm_vm_new(device, start, limit, start, &vm);
+	if (ret)
+		return ret;
+
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+	ret = nvkm_gpuobj_new(nv_object(priv), heap,
+			      ((limit-- - start) >> 12) * 8, 0x1000,
+			      NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
+	vm->pgt[0].refcount[0] = 1;
+	if (ret)
+		return ret;
+
+	ret = nvkm_vm_ref(vm, &priv->bar3_vm, priv->pgd);
+	nvkm_vm_ref(NULL, &vm, NULL);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv->bar3, 0x00, 0x7fc00000);
+	nv_wo32(priv->bar3, 0x04, lower_32_bits(limit));
+	nv_wo32(priv->bar3, 0x08, lower_32_bits(start));
+	nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 |
+				  upper_32_bits(start));
+	nv_wo32(priv->bar3, 0x10, 0x00000000);
+	nv_wo32(priv->bar3, 0x14, 0x00000000);
+
+	/* BAR1 */
+	start = 0x0000000000ULL;
+	limit = start + nv_device_resource_len(device, 1);
+
+	ret = nvkm_vm_new(device, start, limit--, start, &vm);
+	if (ret)
+		return ret;
+
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+	ret = nvkm_vm_ref(vm, &priv->bar1_vm, priv->pgd);
+	nvkm_vm_ref(NULL, &vm, NULL);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv->bar1, 0x00, 0x7fc00000);
+	nv_wo32(priv->bar1, 0x04, lower_32_bits(limit));
+	nv_wo32(priv->bar1, 0x08, lower_32_bits(start));
+	nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 |
+				  upper_32_bits(start));
+	nv_wo32(priv->bar1, 0x10, 0x00000000);
+	nv_wo32(priv->bar1, 0x14, 0x00000000);
+
+	priv->base.alloc = nvkm_bar_alloc;
+	priv->base.kmap = nv50_bar_kmap;
+	priv->base.umap = nv50_bar_umap;
+	priv->base.unmap = nv50_bar_unmap;
+	if (device->chipset == 0x50)
+		priv->base.flush = nv50_bar_flush;
+	else
+		priv->base.flush = g84_bar_flush;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+static void
+nv50_bar_dtor(struct nvkm_object *object)
+{
+	struct nv50_bar_priv *priv = (void *)object;
+	nvkm_gpuobj_ref(NULL, &priv->bar1);
+	nvkm_vm_ref(NULL, &priv->bar1_vm, priv->pgd);
+	nvkm_gpuobj_ref(NULL, &priv->bar3);
+	if (priv->bar3_vm) {
+		nvkm_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]);
+		nvkm_vm_ref(NULL, &priv->bar3_vm, priv->pgd);
+	}
+	nvkm_gpuobj_ref(NULL, &priv->pgd);
+	nvkm_gpuobj_ref(NULL, &priv->pad);
+	nvkm_gpuobj_ref(NULL, &priv->mem);
+	nvkm_bar_destroy(&priv->base);
+}
+
+static int
+nv50_bar_init(struct nvkm_object *object)
+{
+	struct nv50_bar_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nvkm_bar_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+	nv_wr32(priv, 0x100c80, 0x00060001);
+	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
+		nv_error(priv, "vm flush timeout\n");
+		return -EBUSY;
+	}
+
+	nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
+	nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
+	nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4);
+	nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4);
+	for (i = 0; i < 8; i++)
+		nv_wr32(priv, 0x001900 + (i * 4), 0x00000000);
+	return 0;
+}
+
+static int
+nv50_bar_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_bar_priv *priv = (void *)object;
+	return nvkm_bar_fini(&priv->base, suspend);
+}
+
+struct nvkm_oclass
+nv50_bar_oclass = {
+	.handle = NV_SUBDEV(BAR, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_bar_ctor,
+		.dtor = nv50_bar_dtor,
+		.init = nv50_bar_init,
+		.fini = nv50_bar_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h
new file mode 100644
index 0000000..aa85f61
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h
@@ -0,0 +1,30 @@
+#ifndef __NVKM_BAR_PRIV_H__
+#define __NVKM_BAR_PRIV_H__
+#include <subdev/bar.h>
+
+#define nvkm_bar_create(p,e,o,d)                                            \
+	nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_bar_init(p)                                                    \
+	nvkm_subdev_init(&(p)->base)
+#define nvkm_bar_fini(p,s)                                                  \
+	nvkm_subdev_fini(&(p)->base, (s))
+
+int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, int, void **);
+void nvkm_bar_destroy(struct nvkm_bar *);
+
+void _nvkm_bar_dtor(struct nvkm_object *);
+#define _nvkm_bar_init _nvkm_subdev_init
+#define _nvkm_bar_fini _nvkm_subdev_fini
+
+int  nvkm_bar_alloc(struct nvkm_bar *, struct nvkm_object *,
+		    struct nvkm_mem *, struct nvkm_object **);
+
+void g84_bar_flush(struct nvkm_bar *);
+
+int gf100_bar_ctor(struct nvkm_object *, struct nvkm_object *,
+		  struct nvkm_oclass *, void *, u32,
+		  struct nvkm_object **);
+void gf100_bar_dtor(struct nvkm_object *);
+int gf100_bar_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
new file mode 100644
index 0000000..64730d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
@@ -0,0 +1,37 @@
+nvkm-y += nvkm/subdev/bios/base.o
+nvkm-y += nvkm/subdev/bios/bit.o
+nvkm-y += nvkm/subdev/bios/boost.o
+nvkm-y += nvkm/subdev/bios/conn.o
+nvkm-y += nvkm/subdev/bios/cstep.o
+nvkm-y += nvkm/subdev/bios/dcb.o
+nvkm-y += nvkm/subdev/bios/disp.o
+nvkm-y += nvkm/subdev/bios/dp.o
+nvkm-y += nvkm/subdev/bios/extdev.o
+nvkm-y += nvkm/subdev/bios/fan.o
+nvkm-y += nvkm/subdev/bios/gpio.o
+nvkm-y += nvkm/subdev/bios/i2c.o
+nvkm-y += nvkm/subdev/bios/image.o
+nvkm-y += nvkm/subdev/bios/init.o
+nvkm-y += nvkm/subdev/bios/mxm.o
+nvkm-y += nvkm/subdev/bios/npde.o
+nvkm-y += nvkm/subdev/bios/pcir.o
+nvkm-y += nvkm/subdev/bios/perf.o
+nvkm-y += nvkm/subdev/bios/pll.o
+nvkm-y += nvkm/subdev/bios/pmu.o
+nvkm-y += nvkm/subdev/bios/ramcfg.o
+nvkm-y += nvkm/subdev/bios/rammap.o
+nvkm-y += nvkm/subdev/bios/shadow.o
+nvkm-y += nvkm/subdev/bios/shadowacpi.o
+nvkm-y += nvkm/subdev/bios/shadowof.o
+nvkm-y += nvkm/subdev/bios/shadowpci.o
+nvkm-y += nvkm/subdev/bios/shadowramin.o
+nvkm-y += nvkm/subdev/bios/shadowrom.o
+nvkm-y += nvkm/subdev/bios/timing.o
+nvkm-y += nvkm/subdev/bios/therm.o
+nvkm-y += nvkm/subdev/bios/vmap.o
+nvkm-y += nvkm/subdev/bios/volt.o
+nvkm-y += nvkm/subdev/bios/xpio.o
+nvkm-y += nvkm/subdev/bios/M0203.o
+nvkm-y += nvkm/subdev/bios/M0205.o
+nvkm-y += nvkm/subdev/bios/M0209.o
+nvkm-y += nvkm/subdev/bios/P0260.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c
new file mode 100644
index 0000000..08eb03f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0203.h>
+
+u32
+nvbios_M0203Te(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_M;
+	u32 data = 0x00000000;
+
+	if (!bit_entry(bios, 'M', &bit_M)) {
+		if (bit_M.version == 2 && bit_M.length > 0x04)
+			data = nv_ro16(bios, bit_M.offset + 0x03);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0x00);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, data + 0x01);
+				*len = nv_ro08(bios, data + 0x02);
+				*cnt = nv_ro08(bios, data + 0x03);
+				return data;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x00000000;
+}
+
+u32
+nvbios_M0203Tp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	       struct nvbios_M0203T *info)
+{
+	u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->type    = nv_ro08(bios, data + 0x04);
+		info->pointer = nv_ro16(bios, data + 0x05);
+		break;
+	default:
+		break;
+	}
+	return data;
+}
+
+u32
+nvbios_M0203Ee(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+	u8  cnt, len;
+	u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
+	if (data && idx < cnt) {
+		data = data + *hdr + idx * len;
+		*hdr = len;
+		return data;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0203Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_M0203E *info)
+{
+	u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->type  = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
+		info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
+		info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
+	       struct nvbios_M0203E *info)
+{
+	struct nvbios_M0203T M0203T;
+	u8  cnt, len, idx = 0xff;
+	u32 data;
+
+	if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
+		nv_warn(bios, "M0203T not found\n");
+		return 0x00000000;
+	}
+
+	while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
+		switch (M0203T.type) {
+		case M0203T_TYPE_RAMCFG:
+			if (info->strap != ramcfg)
+				continue;
+			return data;
+		default:
+			nv_warn(bios, "M0203T type %02x\n", M0203T.type);
+			return 0x00000000;
+		}
+	}
+
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c
new file mode 100644
index 0000000..e1a8ad5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0205.h>
+
+u32
+nvbios_M0205Te(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_M;
+	u32 data = 0x00000000;
+
+	if (!bit_entry(bios, 'M', &bit_M)) {
+		if (bit_M.version == 2 && bit_M.length > 0x08)
+			data = nv_ro32(bios, bit_M.offset + 0x05);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0x00);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, data + 0x01);
+				*len = nv_ro08(bios, data + 0x02);
+				*ssz = nv_ro08(bios, data + 0x03);
+				*snr = nv_ro08(bios, data + 0x04);
+				*cnt = nv_ro08(bios, data + 0x05);
+				return data;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x00000000;
+}
+
+u32
+nvbios_M0205Tp(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+	       struct nvbios_M0205T *info)
+{
+	u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->freq = nv_ro16(bios, data + 0x06);
+		break;
+	default:
+		break;
+	}
+	return data;
+}
+
+u32
+nvbios_M0205Ee(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (data && idx < *cnt) {
+		data = data + *hdr + idx * (*len + (snr * ssz));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return data;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0205Ep(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	       struct nvbios_M0205E *info)
+{
+	u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->type = nv_ro08(bios, data + 0x00) & 0x0f;
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0205Se(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+	u8  cnt, len;
+	u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
+	if (data && idx < cnt) {
+		data = data + *hdr + idx * len;
+		*hdr = len;
+		return data;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0205Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_M0205S *info)
+{
+	u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->data = nv_ro08(bios, data + 0x00);
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c
new file mode 100644
index 0000000..3026920
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0209.h>
+
+u32
+nvbios_M0209Te(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_M;
+	u32 data = 0x00000000;
+
+	if (!bit_entry(bios, 'M', &bit_M)) {
+		if (bit_M.version == 2 && bit_M.length > 0x0c)
+			data = nv_ro32(bios, bit_M.offset + 0x09);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0x00);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, data + 0x01);
+				*len = nv_ro08(bios, data + 0x02);
+				*ssz = nv_ro08(bios, data + 0x03);
+				*snr = 1;
+				*cnt = nv_ro08(bios, data + 0x04);
+				return data;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x00000000;
+}
+
+u32
+nvbios_M0209Ee(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (data && idx < *cnt) {
+		data = data + *hdr + idx * (*len + (snr * ssz));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return data;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0209Ep(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0209E *info)
+{
+	u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
+		info->bits   =  nv_ro08(bios, data + 0x00) & 0x3f;
+		info->modulo =  nv_ro08(bios, data + 0x01);
+		info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+		info->v02_07 =  nv_ro08(bios, data + 0x02) & 0x07;
+		info->v03    =  nv_ro08(bios, data + 0x03);
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0209Se(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+	u8  cnt, len;
+	u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
+	if (data && idx < cnt) {
+		data = data + *hdr + idx * len;
+		*hdr = len;
+		return data;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_M0209Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_M0209S *info)
+{
+	struct nvbios_M0209E M0209E;
+	u8  cnt, len;
+	u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
+	if (data) {
+		u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
+		memset(info, 0x00, sizeof(*info));
+		switch (!!data * *ver) {
+		case 0x10:
+			for (i = 0; i < ARRAY_SIZE(info->data); i++) {
+				u32 bits = (i % M0209E.modulo) * M0209E.bits;
+				u32 mask = (1ULL << M0209E.bits) - 1;
+				u16  off = bits / 8;
+				u8   mod = bits % 8;
+				info->data[i] = nv_ro32(bios, data + off);
+				info->data[i] = info->data[i] >> mod;
+				info->data[i] = info->data[i] & mask;
+			}
+			return data;
+		default:
+			break;
+		}
+	}
+	return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c
new file mode 100644
index 0000000..b72edcf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/P0260.h>
+
+u32
+nvbios_P0260Te(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+	struct bit_entry bit_P;
+	u32 data = 0x00000000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2 && bit_P.length > 0x63)
+			data = nv_ro32(bios, bit_P.offset + 0x60);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, data + 1);
+				*cnt = nv_ro08(bios, data + 2);
+				*len = 4;
+				*xnr = nv_ro08(bios, data + 3);
+				*xsz = 4;
+				return data;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x00000000;
+}
+
+u32
+nvbios_P0260Ee(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt, xnr, xsz;
+	u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz);
+	if (data && idx < cnt)
+		return data + hdr + (idx * *len);
+	return 0x00000000;
+}
+
+u32
+nvbios_P0260Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+	       struct nvbios_P0260E *info)
+{
+	u32 data = nvbios_P0260Ee(bios, idx, ver, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->data = nv_ro32(bios, data);
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_P0260Xe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *xsz)
+{
+	u8  hdr, cnt, len, xnr;
+	u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz);
+	if (data && idx < xnr)
+		return data + hdr + (cnt * len) + (idx * *xsz);
+	return 0x00000000;
+}
+
+u32
+nvbios_P0260Xp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_P0260X *info)
+{
+	u32 data = nvbios_P0260Xe(bios, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x10:
+		info->data = nv_ro32(bios, data);
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
new file mode 100644
index 0000000..8db204f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/bit.h>
+
+u8
+nvbios_checksum(const u8 *data, int size)
+{
+	u8 sum = 0;
+	while (size--)
+		sum += *data++;
+	return sum;
+}
+
+u16
+nvbios_findstr(const u8 *data, int size, const char *str, int len)
+{
+	int i, j;
+
+	for (i = 0; i <= (size - len); i++) {
+		for (j = 0; j < len; j++)
+			if ((char)data[i + j] != str[j])
+				break;
+		if (j == len)
+			return i;
+	}
+
+	return 0;
+}
+
+int
+nvbios_extend(struct nvkm_bios *bios, u32 length)
+{
+	if (bios->size < length) {
+		u8 *prev = bios->data;
+		if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
+			bios->data = prev;
+			return -ENOMEM;
+		}
+		memcpy(bios->data, prev, bios->size);
+		bios->size = length;
+		kfree(prev);
+		return 1;
+	}
+	return 0;
+}
+
+static u8
+nvkm_bios_rd08(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	return bios->data[addr];
+}
+
+static u16
+nvkm_bios_rd16(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	return get_unaligned_le16(&bios->data[addr]);
+}
+
+static u32
+nvkm_bios_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	return get_unaligned_le32(&bios->data[addr]);
+}
+
+static void
+nvkm_bios_wr08(struct nvkm_object *object, u64 addr, u8 data)
+{
+	struct nvkm_bios *bios = (void *)object;
+	bios->data[addr] = data;
+}
+
+static void
+nvkm_bios_wr16(struct nvkm_object *object, u64 addr, u16 data)
+{
+	struct nvkm_bios *bios = (void *)object;
+	put_unaligned_le16(data, &bios->data[addr]);
+}
+
+static void
+nvkm_bios_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nvkm_bios *bios = (void *)object;
+	put_unaligned_le32(data, &bios->data[addr]);
+}
+
+static int
+nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_bios *bios;
+	struct bit_entry bit_i;
+	int ret;
+
+	ret = nvkm_subdev_create(parent, engine, oclass, 0,
+				 "VBIOS", "bios", &bios);
+	*pobject = nv_object(bios);
+	if (ret)
+		return ret;
+
+	ret = nvbios_shadow(bios);
+	if (ret)
+		return ret;
+
+	/* detect type of vbios we're dealing with */
+	bios->bmp_offset = nvbios_findstr(bios->data, bios->size,
+					  "\xff\x7f""NV\0", 5);
+	if (bios->bmp_offset) {
+		nv_info(bios, "BMP version %x.%x\n",
+			bmp_version(bios) >> 8,
+			bmp_version(bios) & 0xff);
+	}
+
+	bios->bit_offset = nvbios_findstr(bios->data, bios->size,
+					  "\xff\xb8""BIT", 5);
+	if (bios->bit_offset)
+		nv_info(bios, "BIT signature found\n");
+
+	/* determine the vbios version number */
+	if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) {
+		bios->version.major = nv_ro08(bios, bit_i.offset + 3);
+		bios->version.chip  = nv_ro08(bios, bit_i.offset + 2);
+		bios->version.minor = nv_ro08(bios, bit_i.offset + 1);
+		bios->version.micro = nv_ro08(bios, bit_i.offset + 0);
+		bios->version.patch = nv_ro08(bios, bit_i.offset + 4);
+	} else
+	if (bmp_version(bios)) {
+		bios->version.major = nv_ro08(bios, bios->bmp_offset + 13);
+		bios->version.chip  = nv_ro08(bios, bios->bmp_offset + 12);
+		bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11);
+		bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10);
+	}
+
+	nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n",
+		bios->version.major, bios->version.chip,
+		bios->version.minor, bios->version.micro, bios->version.patch);
+
+	return 0;
+}
+
+static void
+nvkm_bios_dtor(struct nvkm_object *object)
+{
+	struct nvkm_bios *bios = (void *)object;
+	kfree(bios->data);
+	nvkm_subdev_destroy(&bios->base);
+}
+
+static int
+nvkm_bios_init(struct nvkm_object *object)
+{
+	struct nvkm_bios *bios = (void *)object;
+	return nvkm_subdev_init(&bios->base);
+}
+
+static int
+nvkm_bios_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_bios *bios = (void *)object;
+	return nvkm_subdev_fini(&bios->base, suspend);
+}
+
+struct nvkm_oclass
+nvkm_bios_oclass = {
+	.handle = NV_SUBDEV(VBIOS, 0x00),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nvkm_bios_ctor,
+		.dtor = nvkm_bios_dtor,
+		.init = nvkm_bios_init,
+		.fini = nvkm_bios_fini,
+		.rd08 = nvkm_bios_rd08,
+		.rd16 = nvkm_bios_rd16,
+		.rd32 = nvkm_bios_rd32,
+		.wr08 = nvkm_bios_wr08,
+		.wr16 = nvkm_bios_wr16,
+		.wr32 = nvkm_bios_wr32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c
new file mode 100644
index 0000000..eab54049
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+
+int
+bit_entry(struct nvkm_bios *bios, u8 id, struct bit_entry *bit)
+{
+	if (likely(bios->bit_offset)) {
+		u8  entries = nv_ro08(bios, bios->bit_offset + 10);
+		u32 entry   = bios->bit_offset + 12;
+		while (entries--) {
+			if (nv_ro08(bios, entry + 0) == id) {
+				bit->id      = nv_ro08(bios, entry + 0);
+				bit->version = nv_ro08(bios, entry + 1);
+				bit->length  = nv_ro16(bios, entry + 2);
+				bit->offset  = nv_ro16(bios, entry + 4);
+				return 0;
+			}
+
+			entry += nv_ro08(bios, bios->bit_offset + 9);
+		}
+
+		return -ENOENT;
+	}
+
+	return -EINVAL;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c
new file mode 100644
index 0000000..12e9585
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/boost.h>
+
+u16
+nvbios_boostTe(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_P;
+	u16 boost = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2)
+			boost = nv_ro16(bios, bit_P.offset + 0x30);
+
+		if (boost) {
+			*ver = nv_ro08(bios, boost + 0);
+			switch (*ver) {
+			case 0x11:
+				*hdr = nv_ro08(bios, boost + 1);
+				*cnt = nv_ro08(bios, boost + 5);
+				*len = nv_ro08(bios, boost + 2);
+				*snr = nv_ro08(bios, boost + 4);
+				*ssz = nv_ro08(bios, boost + 3);
+				return boost;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_boostEe(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u16 data = nvbios_boostTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (data && idx < *cnt) {
+		data = data + *hdr + (idx * (*len + (snr * ssz)));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_boostEp(struct nvkm_bios *bios, int idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+	u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+		info->min    =  nv_ro16(bios, data + 0x02) * 1000;
+		info->max    =  nv_ro16(bios, data + 0x04) * 1000;
+	}
+	return data;
+}
+
+u16
+nvbios_boostEm(struct nvkm_bios *bios, u8 pstate,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+	u32 data, idx = 0;
+	while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) {
+		if (info->pstate == pstate)
+			break;
+	}
+	return data;
+}
+
+u16
+nvbios_boostSe(struct nvkm_bios *bios, int idx,
+	       u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+	if (data && idx < cnt) {
+		data = data + *hdr + (idx * len);
+		*hdr = len;
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_boostSp(struct nvkm_bios *bios, int idx,
+	       u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len,
+	       struct nvbios_boostS *info)
+{
+	data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->domain  = nv_ro08(bios, data + 0x00);
+		info->percent = nv_ro08(bios, data + 0x01);
+		info->min     = nv_ro16(bios, data + 0x02) * 1000;
+		info->max     = nv_ro16(bios, data + 0x04) * 1000;
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c
new file mode 100644
index 0000000..706a165
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/conn.h>
+
+u32
+nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
+	if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
+		u32 data = nv_ro16(bios, dcb + 0x14);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0);
+			*hdr = nv_ro08(bios, data + 1);
+			*cnt = nv_ro08(bios, data + 2);
+			*len = nv_ro08(bios, data + 3);
+			return data;
+		}
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_connTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	      struct nvbios_connT *info)
+{
+	u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x30:
+	case 0x40:
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
+
+u32
+nvbios_connEe(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt;
+	u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
+	if (data && idx < cnt)
+		return data + hdr + (idx * *len);
+	return 0x00000000;
+}
+
+u32
+nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
+	      struct nvbios_connE *info)
+{
+	u32 data = nvbios_connEe(bios, idx, ver, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x30:
+	case 0x40:
+		info->type     =  nv_ro08(bios, data + 0x00);
+		info->location =  nv_ro08(bios, data + 0x01) & 0x0f;
+		info->hpd      = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
+		info->dp       = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
+		if (*len < 4)
+			return data;
+		info->hpd     |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
+		info->dp      |=  nv_ro08(bios, data + 0x02) & 0x0c;
+		info->di       = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
+		info->hpd     |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
+		info->sr       = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
+		info->lcdid    = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
+		return data;
+	default:
+		break;
+	}
+	return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c
new file mode 100644
index 0000000..16f7ad8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/cstep.h>
+
+u16
+nvbios_cstepTe(struct nvkm_bios *bios,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+	struct bit_entry bit_P;
+	u16 cstep = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2)
+			cstep = nv_ro16(bios, bit_P.offset + 0x34);
+
+		if (cstep) {
+			*ver = nv_ro08(bios, cstep + 0);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, cstep + 1);
+				*cnt = nv_ro08(bios, cstep + 3);
+				*len = nv_ro08(bios, cstep + 2);
+				*xnr = nv_ro08(bios, cstep + 5);
+				*xsz = nv_ro08(bios, cstep + 4);
+				return cstep;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_cstepEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+	u8  cnt, len, xnr, xsz;
+	u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+	if (data && idx < cnt) {
+		data = data + *hdr + (idx * len);
+		*hdr = len;
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_cstepEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_cstepE *info)
+{
+	u16 data = nvbios_cstepEe(bios, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+		info->index   = nv_ro08(bios, data + 0x03);
+	}
+	return data;
+}
+
+u16
+nvbios_cstepEm(struct nvkm_bios *bios, u8 pstate, u8 *ver, u8 *hdr,
+	       struct nvbios_cstepE *info)
+{
+	u32 data, idx = 0;
+	while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) {
+		if (info->pstate == pstate)
+			break;
+	}
+	return data;
+}
+
+u16
+nvbios_cstepXe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+	u8  cnt, len, xnr, xsz;
+	u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+	if (data && idx < xnr) {
+		data = data + *hdr + (cnt * len) + (idx * xsz);
+		*hdr = xsz;
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_cstepXp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+	       struct nvbios_cstepX *info)
+{
+	u16 data = nvbios_cstepXe(bios, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->freq    = nv_ro16(bios, data + 0x00) * 1000;
+		info->unkn[0] = nv_ro08(bios, data + 0x02);
+		info->unkn[1] = nv_ro08(bios, data + 0x03);
+		info->voltage = nv_ro08(bios, data + 0x04);
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
new file mode 100644
index 0000000..8d78140
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+#include <core/device.h>
+
+u16
+dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct nvkm_device *device = nv_device(bios);
+	u16 dcb = 0x0000;
+
+	if (device->card_type > NV_04)
+		dcb = nv_ro16(bios, 0x36);
+	if (!dcb) {
+		nv_warn(bios, "DCB table not found\n");
+		return dcb;
+	}
+
+	*ver = nv_ro08(bios, dcb);
+
+	if (*ver >= 0x42) {
+		nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
+		return 0x0000;
+	} else
+	if (*ver >= 0x30) {
+		if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) {
+			*hdr = nv_ro08(bios, dcb + 1);
+			*cnt = nv_ro08(bios, dcb + 2);
+			*len = nv_ro08(bios, dcb + 3);
+			return dcb;
+		}
+	} else
+	if (*ver >= 0x20) {
+		if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) {
+			u16 i2c = nv_ro16(bios, dcb + 2);
+			*hdr = 8;
+			*cnt = (i2c - dcb) / 8;
+			*len = 8;
+			return dcb;
+		}
+	} else
+	if (*ver >= 0x15) {
+		if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
+			u16 i2c = nv_ro16(bios, dcb + 2);
+			*hdr = 4;
+			*cnt = (i2c - dcb) / 10;
+			*len = 10;
+			return dcb;
+		}
+	} else {
+		/*
+		 * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but
+		 * always has the same single (crt) entry, even when tv-out
+		 * present, so the conclusion is this version cannot really
+		 * be used.
+		 *
+		 * v1.2 tables (some NV6/10, and NV15+) normally have the
+		 * same 5 entries, which are not specific to the card and so
+		 * no use.
+		 *
+		 * v1.2 does have an I2C table that read_dcb_i2c_table can
+		 * handle, but cards exist (nv11 in #14821) with a bad i2c
+		 * table pointer, so use the indices parsed in
+		 * parse_bmp_structure.
+		 *
+		 * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
+		 */
+		nv_warn(bios, "DCB contains no useful data\n");
+		return 0x0000;
+	}
+
+	nv_warn(bios, "DCB header validation failed\n");
+	return 0x0000;
+}
+
+u16
+dcb_outp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt;
+	u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
+	if (dcb && idx < cnt)
+		return dcb + hdr + (idx * *len);
+	return 0x0000;
+}
+
+static inline u16
+dcb_outp_hasht(struct dcb_output *outp)
+{
+	return (outp->extdev << 8) | (outp->location << 4) | outp->type;
+}
+
+static inline u16
+dcb_outp_hashm(struct dcb_output *outp)
+{
+	return (outp->heads << 8) | (outp->link << 6) | outp->or;
+}
+
+u16
+dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
+	       struct dcb_output *outp)
+{
+	u16 dcb = dcb_outp(bios, idx, ver, len);
+	memset(outp, 0x00, sizeof(*outp));
+	if (dcb) {
+		if (*ver >= 0x20) {
+			u32 conn = nv_ro32(bios, dcb + 0x00);
+			outp->or        = (conn & 0x0f000000) >> 24;
+			outp->location  = (conn & 0x00300000) >> 20;
+			outp->bus       = (conn & 0x000f0000) >> 16;
+			outp->connector = (conn & 0x0000f000) >> 12;
+			outp->heads     = (conn & 0x00000f00) >> 8;
+			outp->i2c_index = (conn & 0x000000f0) >> 4;
+			outp->type      = (conn & 0x0000000f);
+			outp->link      = 0;
+		} else {
+			dcb = 0x0000;
+		}
+
+		if (*ver >= 0x40) {
+			u32 conf = nv_ro32(bios, dcb + 0x04);
+			switch (outp->type) {
+			case DCB_OUTPUT_DP:
+				switch (conf & 0x00e00000) {
+				case 0x00000000:
+					outp->dpconf.link_bw = 0x06;
+					break;
+				case 0x00200000:
+					outp->dpconf.link_bw = 0x0a;
+					break;
+				case 0x00400000:
+				default:
+					outp->dpconf.link_bw = 0x14;
+					break;
+				}
+
+				outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
+				if (*ver < 0x41) {
+					switch (outp->dpconf.link_nr) {
+					case 0x0f:
+						outp->dpconf.link_nr = 4;
+						break;
+					case 0x03:
+						outp->dpconf.link_nr = 2;
+						break;
+					case 0x01:
+					default:
+						outp->dpconf.link_nr = 1;
+						break;
+					}
+				}
+
+				/* fall-through... */
+			case DCB_OUTPUT_TMDS:
+			case DCB_OUTPUT_LVDS:
+				outp->link = (conf & 0x00000030) >> 4;
+				outp->sorconf.link = outp->link; /*XXX*/
+				outp->extdev = 0x00;
+				if (outp->location != 0)
+					outp->extdev = (conf & 0x0000ff00) >> 8;
+				break;
+			default:
+				break;
+			}
+		}
+
+		outp->hasht = dcb_outp_hasht(outp);
+		outp->hashm = dcb_outp_hashm(outp);
+	}
+	return dcb;
+}
+
+u16
+dcb_outp_match(struct nvkm_bios *bios, u16 type, u16 mask,
+	       u8 *ver, u8 *len, struct dcb_output *outp)
+{
+	u16 dcb, idx = 0;
+	while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
+		if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
+			if ((dcb_outp_hashm(outp) & mask) == mask)
+				break;
+		}
+	}
+	return dcb;
+}
+
+int
+dcb_outp_foreach(struct nvkm_bios *bios, void *data,
+		 int (*exec)(struct nvkm_bios *, void *, int, u16))
+{
+	int ret, idx = -1;
+	u8  ver, len;
+	u16 outp;
+
+	while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
+		if (nv_ro32(bios, outp) == 0x00000000)
+			break; /* seen on an NV11 with DCB v1.5 */
+		if (nv_ro32(bios, outp) == 0xffffffff)
+			break; /* seen on an NV17 with DCB v2.0 */
+
+		if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED)
+			continue;
+		if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL)
+			break;
+
+		ret = exec(bios, data, idx, outp);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c
new file mode 100644
index 0000000..262c410
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/disp.h>
+
+u16
+nvbios_disp_table(struct nvkm_bios *bios,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub)
+{
+	struct bit_entry U;
+
+	if (!bit_entry(bios, 'U', &U)) {
+		if (U.version == 1) {
+			u16 data = nv_ro16(bios, U.offset);
+			if (data) {
+				*ver = nv_ro08(bios, data + 0x00);
+				switch (*ver) {
+				case 0x20:
+				case 0x21:
+				case 0x22:
+					*hdr = nv_ro08(bios, data + 0x01);
+					*len = nv_ro08(bios, data + 0x02);
+					*cnt = nv_ro08(bios, data + 0x03);
+					*sub = nv_ro08(bios, data + 0x04);
+					return data;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_disp_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub)
+{
+	u8  hdr, cnt;
+	u16 data = nvbios_disp_table(bios, ver, &hdr, &cnt, len, sub);
+	if (data && idx < cnt)
+		return data + hdr + (idx * *len);
+	*ver = 0x00;
+	return 0x0000;
+}
+
+u16
+nvbios_disp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub,
+		  struct nvbios_disp *info)
+{
+	u16 data = nvbios_disp_entry(bios, idx, ver, len, sub);
+	if (data && *len >= 2) {
+		info->data = nv_ro16(bios, data + 0);
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_outp_entry(struct nvkm_bios *bios, u8 idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct nvbios_disp info;
+	u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info);
+	if (data) {
+		*cnt = nv_ro08(bios, info.data + 0x05);
+		*len = 0x06;
+		data = info.data;
+	}
+	return data;
+}
+
+u16
+nvbios_outp_parse(struct nvkm_bios *bios, u8 idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info)
+{
+	u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len);
+	if (data && *hdr >= 0x0a) {
+		info->type      = nv_ro16(bios, data + 0x00);
+		info->mask      = nv_ro32(bios, data + 0x02);
+		if (*ver <= 0x20) /* match any link */
+			info->mask |= 0x00c0;
+		info->script[0] = nv_ro16(bios, data + 0x06);
+		info->script[1] = nv_ro16(bios, data + 0x08);
+		info->script[2] = 0x0000;
+		if (*hdr >= 0x0c)
+			info->script[2] = nv_ro16(bios, data + 0x0a);
+		return data;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_outp_match(struct nvkm_bios *bios, u16 type, u16 mask,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info)
+{
+	u16 data, idx = 0;
+	while ((data = nvbios_outp_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
+		if (data && info->type == type) {
+			if ((info->mask & mask) == mask)
+				break;
+		}
+	}
+	return data;
+}
+
+u16
+nvbios_ocfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	if (idx < *cnt)
+		return outp + *hdr + (idx * *len);
+	return 0x0000;
+}
+
+u16
+nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info)
+{
+	u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
+	if (data) {
+		info->match     = nv_ro16(bios, data + 0x00);
+		info->clkcmp[0] = nv_ro16(bios, data + 0x02);
+		info->clkcmp[1] = nv_ro16(bios, data + 0x04);
+	}
+	return data;
+}
+
+u16
+nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u16 type,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info)
+{
+	u16 data, idx = 0;
+	while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
+		if (info->match == type)
+			break;
+	}
+	return data;
+}
+
+u16
+nvbios_oclk_match(struct nvkm_bios *bios, u16 cmp, u32 khz)
+{
+	while (cmp) {
+		if (khz / 10 >= nv_ro16(bios, cmp + 0x00))
+			return  nv_ro16(bios, cmp + 0x02);
+		cmp += 0x04;
+	}
+	return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
new file mode 100644
index 0000000..95970fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/dp.h>
+
+static u16
+nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry d;
+
+	if (!bit_entry(bios, 'd', &d)) {
+		if (d.version == 1 && d.length >= 2) {
+			u16 data = nv_ro16(bios, d.offset);
+			if (data) {
+				*ver = nv_ro08(bios, data + 0x00);
+				switch (*ver) {
+				case 0x21:
+				case 0x30:
+				case 0x40:
+				case 0x41:
+					*hdr = nv_ro08(bios, data + 0x01);
+					*len = nv_ro08(bios, data + 0x02);
+					*cnt = nv_ro08(bios, data + 0x03);
+					return data;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+static u16
+nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
+	if (data && idx < *cnt) {
+		u16 outp = nv_ro16(bios, data + *hdr + idx * *len);
+		switch (*ver * !!outp) {
+		case 0x21:
+		case 0x30:
+			*hdr = nv_ro08(bios, data + 0x04);
+			*len = nv_ro08(bios, data + 0x05);
+			*cnt = nv_ro08(bios, outp + 0x04);
+			break;
+		case 0x40:
+		case 0x41:
+			*hdr = nv_ro08(bios, data + 0x04);
+			*cnt = 0;
+			*len = 0;
+			break;
+		default:
+			break;
+		}
+		return outp;
+	}
+	*ver = 0x00;
+	return 0x0000;
+}
+
+u16
+nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		   struct nvbios_dpout *info)
+{
+	u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	if (data && *ver) {
+		info->type = nv_ro16(bios, data + 0x00);
+		info->mask = nv_ro16(bios, data + 0x02);
+		switch (*ver) {
+		case 0x21:
+		case 0x30:
+			info->flags     = nv_ro08(bios, data + 0x05);
+			info->script[0] = nv_ro16(bios, data + 0x06);
+			info->script[1] = nv_ro16(bios, data + 0x08);
+			info->lnkcmp    = nv_ro16(bios, data + 0x0a);
+			if (*len >= 0x0f) {
+				info->script[2] = nv_ro16(bios, data + 0x0c);
+				info->script[3] = nv_ro16(bios, data + 0x0e);
+			}
+			if (*len >= 0x11)
+				info->script[4] = nv_ro16(bios, data + 0x10);
+			break;
+		case 0x40:
+		case 0x41:
+			info->flags     = nv_ro08(bios, data + 0x04);
+			info->script[0] = nv_ro16(bios, data + 0x05);
+			info->script[1] = nv_ro16(bios, data + 0x07);
+			info->lnkcmp    = nv_ro16(bios, data + 0x09);
+			info->script[2] = nv_ro16(bios, data + 0x0b);
+			info->script[3] = nv_ro16(bios, data + 0x0d);
+			info->script[4] = nv_ro16(bios, data + 0x0f);
+			break;
+		default:
+			data = 0x0000;
+			break;
+		}
+	}
+	return data;
+}
+
+u16
+nvbios_dpout_match(struct nvkm_bios *bios, u16 type, u16 mask,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		   struct nvbios_dpout *info)
+{
+	u16 data, idx = 0;
+	while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
+		if (data && info->type == type) {
+			if ((info->mask & mask) == mask)
+				break;
+		}
+	}
+	return data;
+}
+
+static u16
+nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	if (*ver >= 0x40) {
+		outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
+		*hdr = *hdr + (*len * * cnt);
+		*len = nv_ro08(bios, outp + 0x06);
+		*cnt = nv_ro08(bios, outp + 0x07);
+	}
+
+	if (idx < *cnt)
+		return outp + *hdr + (idx * *len);
+
+	return 0x0000;
+}
+
+u16
+nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		   struct nvbios_dpcfg *info)
+{
+	u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		switch (*ver) {
+		case 0x21:
+			info->dc    = nv_ro08(bios, data + 0x02);
+			info->pe    = nv_ro08(bios, data + 0x03);
+			info->tx_pu = nv_ro08(bios, data + 0x04);
+			break;
+		case 0x30:
+		case 0x40:
+		case 0x41:
+			info->pc    = nv_ro08(bios, data + 0x00);
+			info->dc    = nv_ro08(bios, data + 0x01);
+			info->pe    = nv_ro08(bios, data + 0x02);
+			info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
+			break;
+		default:
+			data = 0x0000;
+			break;
+		}
+	}
+	return data;
+}
+
+u16
+nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
+		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		   struct nvbios_dpcfg *info)
+{
+	u8 idx = 0xff;
+	u16 data;
+
+	if (*ver >= 0x30) {
+		/*XXX: there's a second set of these on at least 4.1, that
+		 *     i've witnessed nvidia using instead of the first
+		 *     on gm204.  figure out what/why
+		 */
+		const u8 vsoff[] = { 0, 4, 7, 9 };
+		idx = (pc * 10) + vsoff[vs] + pe;
+	} else {
+		while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
+						  ver, hdr, cnt, len))) {
+			if (nv_ro08(bios, data + 0x00) == vs &&
+			    nv_ro08(bios, data + 0x01) == pe)
+				break;
+		}
+	}
+
+	return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c
new file mode 100644
index 0000000..a8503a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/extdev.h>
+
+static u16
+extdev_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
+{
+	u8  dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
+	u16 dcb, extdev = 0;
+
+	dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
+	if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40))
+		return 0x0000;
+
+	extdev = nv_ro16(bios, dcb + 18);
+	if (!extdev)
+		return 0x0000;
+
+	*ver = nv_ro08(bios, extdev + 0);
+	*hdr = nv_ro08(bios, extdev + 1);
+	*cnt = nv_ro08(bios, extdev + 2);
+	*len = nv_ro08(bios, extdev + 3);
+	return extdev + *hdr;
+}
+
+static u16
+nvbios_extdev_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+	u8 hdr, cnt;
+	u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
+	if (extdev && idx < cnt)
+		return extdev + idx * *len;
+	return 0x0000;
+}
+
+static void
+extdev_parse_entry(struct nvkm_bios *bios, u16 offset,
+		   struct nvbios_extdev_func *entry)
+{
+	entry->type = nv_ro08(bios, offset + 0);
+	entry->addr = nv_ro08(bios, offset + 1);
+	entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1;
+}
+
+int
+nvbios_extdev_parse(struct nvkm_bios *bios, int idx,
+		    struct nvbios_extdev_func *func)
+{
+	u8 ver, len;
+	u16 entry;
+
+	if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
+		return -EINVAL;
+
+	extdev_parse_entry(bios, entry, func);
+	return 0;
+}
+
+int
+nvbios_extdev_find(struct nvkm_bios *bios, enum nvbios_extdev_type type,
+		   struct nvbios_extdev_func *func)
+{
+	u8 ver, len, i;
+	u16 entry;
+
+	i = 0;
+	while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
+		extdev_parse_entry(bios, entry, func);
+		if (func->type == type)
+			return 0;
+	}
+
+	return -EINVAL;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
new file mode 100644
index 0000000..8dba70d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/fan.h>
+
+u16
+nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_P;
+	u16 fan = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2 && bit_P.length >= 0x5a)
+			fan = nv_ro16(bios, bit_P.offset + 0x58);
+
+		if (fan) {
+			*ver = nv_ro08(bios, fan + 0);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, fan + 1);
+				*len = nv_ro08(bios, fan + 2);
+				*cnt = nv_ro08(bios, fan + 3);
+				return fan;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_fan_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+		 u8 *cnt, u8 *len)
+{
+	u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
+	if (data && idx < *cnt)
+		return data + *hdr + (idx * (*len));
+	return 0x0000;
+}
+
+u16
+nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
+{
+	u8 ver, hdr, cnt, len;
+
+	u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
+	if (data) {
+		u8 type = nv_ro08(bios, data + 0x00);
+		switch (type) {
+		case 0:
+			fan->type = NVBIOS_THERM_FAN_TOGGLE;
+			break;
+		case 1:
+		case 2:
+			/* TODO: Understand the difference between the two! */
+			fan->type = NVBIOS_THERM_FAN_PWM;
+			break;
+		default:
+			fan->type = NVBIOS_THERM_FAN_UNK;
+		}
+
+		fan->min_duty = nv_ro08(bios, data + 0x02);
+		fan->max_duty = nv_ro08(bios, data + 0x03);
+
+		fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
+	}
+
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c
new file mode 100644
index 0000000..8ce154d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/xpio.h>
+
+u16
+dcb_gpio_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u16 data = 0x0000;
+	u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
+	if (dcb) {
+		if (*ver >= 0x30 && *hdr >= 0x0c)
+			data = nv_ro16(bios, dcb + 0x0a);
+		else
+		if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
+			data = nv_ro16(bios, dcb - 0x0f);
+
+		if (data) {
+			*ver = nv_ro08(bios, data + 0x00);
+			if (*ver < 0x30) {
+				*hdr = 3;
+				*cnt = nv_ro08(bios, data + 0x02);
+				*len = nv_ro08(bios, data + 0x01);
+			} else
+			if (*ver <= 0x41) {
+				*hdr = nv_ro08(bios, data + 0x01);
+				*cnt = nv_ro08(bios, data + 0x02);
+				*len = nv_ro08(bios, data + 0x03);
+			} else {
+				data = 0x0000;
+			}
+		}
+	}
+	return data;
+}
+
+u16
+dcb_gpio_entry(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt, xver; /* use gpio version for xpio entry parsing */
+	u16 gpio;
+
+	if (!idx--)
+		gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len);
+	else
+		gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len);
+
+	if (gpio && ent < cnt)
+		return gpio + hdr + (ent * *len);
+
+	return 0x0000;
+}
+
+u16
+dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len,
+	       struct dcb_gpio_func *gpio)
+{
+	u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
+	if (data) {
+		if (*ver < 0x40) {
+			u16 info = nv_ro16(bios, data);
+			*gpio = (struct dcb_gpio_func) {
+				.line = (info & 0x001f) >> 0,
+				.func = (info & 0x07e0) >> 5,
+				.log[0] = (info & 0x1800) >> 11,
+				.log[1] = (info & 0x6000) >> 13,
+				.param = !!(info & 0x8000),
+			};
+		} else
+		if (*ver < 0x41) {
+			u32 info = nv_ro32(bios, data);
+			*gpio = (struct dcb_gpio_func) {
+				.line = (info & 0x0000001f) >> 0,
+				.func = (info & 0x0000ff00) >> 8,
+				.log[0] = (info & 0x18000000) >> 27,
+				.log[1] = (info & 0x60000000) >> 29,
+				.param = !!(info & 0x80000000),
+			};
+		} else {
+			u32 info = nv_ro32(bios, data + 0);
+			u8 info1 = nv_ro32(bios, data + 4);
+			*gpio = (struct dcb_gpio_func) {
+				.line = (info & 0x0000003f) >> 0,
+				.func = (info & 0x0000ff00) >> 8,
+				.log[0] = (info1 & 0x30) >> 4,
+				.log[1] = (info1 & 0xc0) >> 6,
+				.param = !!(info & 0x80000000),
+			};
+		}
+	}
+
+	return data;
+}
+
+u16
+dcb_gpio_match(struct nvkm_bios *bios, int idx, u8 func, u8 line,
+	       u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
+{
+	u8  hdr, cnt, i = 0;
+	u16 data;
+
+	while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
+		if ((line == 0xff || line == gpio->line) &&
+		    (func == 0xff || func == gpio->func))
+			return data;
+	}
+
+	/* DCB 2.2, fixed TVDAC GPIO data */
+	if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
+		if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
+			u8 conf = nv_ro08(bios, data - 5);
+			u8 addr = nv_ro08(bios, data - 4);
+			if (conf & 0x01) {
+				*gpio = (struct dcb_gpio_func) {
+					.func = DCB_GPIO_TVDAC0,
+					.line = addr >> 4,
+					.log[0] = !!(conf & 0x02),
+					.log[1] =  !(conf & 0x02),
+				};
+				*ver = 0x00;
+				return data;
+			}
+		}
+	}
+
+	return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
new file mode 100644
index 0000000..d1a89b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/i2c.h>
+
+u16
+dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u16 i2c = 0x0000;
+	u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
+	if (dcb) {
+		if (*ver >= 0x15)
+			i2c = nv_ro16(bios, dcb + 2);
+		if (*ver >= 0x30)
+			i2c = nv_ro16(bios, dcb + 4);
+	}
+
+	if (i2c && *ver >= 0x42) {
+		nv_warn(bios, "ccb %02x not supported\n", *ver);
+		return 0x0000;
+	}
+
+	if (i2c && *ver >= 0x30) {
+		*ver = nv_ro08(bios, i2c + 0);
+		*hdr = nv_ro08(bios, i2c + 1);
+		*cnt = nv_ro08(bios, i2c + 2);
+		*len = nv_ro08(bios, i2c + 3);
+	} else {
+		*ver = *ver; /* use DCB version */
+		*hdr = 0;
+		*cnt = 16;
+		*len = 4;
+	}
+
+	return i2c;
+}
+
+u16
+dcb_i2c_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt;
+	u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len);
+	if (i2c && idx < cnt)
+		return i2c + hdr + (idx * *len);
+	return 0x0000;
+}
+
+int
+dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
+{
+	u8  ver, len;
+	u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
+	if (ent) {
+		if (ver >= 0x41) {
+			if (!(nv_ro32(bios, ent) & 0x80000000))
+				info->type = DCB_I2C_UNUSED;
+			else
+				info->type = DCB_I2C_PMGR;
+		} else
+		if (ver >= 0x30) {
+			info->type = nv_ro08(bios, ent + 0x03);
+		} else {
+			info->type = nv_ro08(bios, ent + 0x03) & 0x07;
+			if (info->type == 0x07)
+				info->type = DCB_I2C_UNUSED;
+		}
+
+		info->drive = DCB_I2C_UNUSED;
+		info->sense = DCB_I2C_UNUSED;
+		info->share = DCB_I2C_UNUSED;
+		info->auxch = DCB_I2C_UNUSED;
+
+		switch (info->type) {
+		case DCB_I2C_NV04_BIT:
+			info->drive = nv_ro08(bios, ent + 0);
+			info->sense = nv_ro08(bios, ent + 1);
+			return 0;
+		case DCB_I2C_NV4E_BIT:
+			info->drive = nv_ro08(bios, ent + 1);
+			return 0;
+		case DCB_I2C_NVIO_BIT:
+			info->drive = nv_ro08(bios, ent + 0) & 0x0f;
+			if (nv_ro08(bios, ent + 1) & 0x01)
+				info->share = nv_ro08(bios, ent + 1) >> 1;
+			return 0;
+		case DCB_I2C_NVIO_AUX:
+			info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
+			if (nv_ro08(bios, ent + 1) & 0x01)
+					info->share = info->auxch;
+			return 0;
+		case DCB_I2C_PMGR:
+			info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
+			if (info->drive == 0x1f)
+				info->drive = DCB_I2C_UNUSED;
+			info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
+			if (info->auxch == 0x1f)
+				info->auxch = DCB_I2C_UNUSED;
+			info->share = info->auxch;
+			return 0;
+		case DCB_I2C_UNUSED:
+			return 0;
+		default:
+			nv_warn(bios, "unknown i2c type %d\n", info->type);
+			info->type = DCB_I2C_UNUSED;
+			return 0;
+		}
+	}
+
+	if (bios->bmp_offset && idx < 2) {
+		/* BMP (from v4.0 has i2c info in the structure, it's in a
+		 * fixed location on earlier VBIOS
+		 */
+		if (nv_ro08(bios, bios->bmp_offset + 5) < 4)
+			ent = 0x0048;
+		else
+			ent = 0x0036 + bios->bmp_offset;
+
+		if (idx == 0) {
+			info->drive = nv_ro08(bios, ent + 4);
+			if (!info->drive) info->drive = 0x3f;
+			info->sense = nv_ro08(bios, ent + 5);
+			if (!info->sense) info->sense = 0x3e;
+		} else
+		if (idx == 1) {
+			info->drive = nv_ro08(bios, ent + 6);
+			if (!info->drive) info->drive = 0x37;
+			info->sense = nv_ro08(bios, ent + 7);
+			if (!info->sense) info->sense = 0x36;
+		}
+
+		info->type  = DCB_I2C_NV04_BIT;
+		info->share = DCB_I2C_UNUSED;
+		return 0;
+	}
+
+	return -ENOENT;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
new file mode 100644
index 0000000..1815540
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pcir.h>
+#include <subdev/bios/npde.h>
+
+static bool
+nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image)
+{
+	struct nvbios_pcirT pcir;
+	struct nvbios_npdeT npde;
+	u8  ver;
+	u16 hdr;
+	u32 data;
+
+	switch ((data = nv_ro16(bios, image->base + 0x00))) {
+	case 0xaa55:
+	case 0xbb77:
+	case 0x4e56: /* NV */
+		break;
+	default:
+		nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
+			 image->base, data);
+		return false;
+	}
+
+	if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
+		return false;
+	image->size = pcir.image_size;
+	image->type = pcir.image_type;
+	image->last = pcir.last;
+
+	if (image->type != 0x70) {
+		if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
+			return true;
+		image->size = npde.image_size;
+		image->last = npde.last;
+	} else {
+		image->last = true;
+	}
+
+	return true;
+}
+
+bool
+nvbios_image(struct nvkm_bios *bios, int idx, struct nvbios_image *image)
+{
+	memset(image, 0x00, sizeof(*image));
+	do {
+		image->base += image->size;
+		if (image->last || !nvbios_imagen(bios, image))
+			return false;
+	} while(idx--);
+	return true;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
new file mode 100644
index 0000000..f67cdae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
@@ -0,0 +1,2247 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/dp.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/ramcfg.h>
+
+#include <core/device.h>
+#include <subdev/devinit.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/vga.h>
+
+#define bioslog(lvl, fmt, args...) do {                                        \
+	nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset,            \
+		  init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args);   \
+} while(0)
+#define cont(fmt, args...) do {                                                \
+	if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE)                      \
+		printk(fmt, ##args);                                           \
+} while(0)
+#define trace(fmt, args...) bioslog(TRACE, fmt, ##args)
+#define warn(fmt, args...) bioslog(WARN, fmt, ##args)
+#define error(fmt, args...) bioslog(ERROR, fmt, ##args)
+
+/******************************************************************************
+ * init parser control flow helpers
+ *****************************************************************************/
+
+static inline bool
+init_exec(struct nvbios_init *init)
+{
+	return (init->execute == 1) || ((init->execute & 5) == 5);
+}
+
+static inline void
+init_exec_set(struct nvbios_init *init, bool exec)
+{
+	if (exec) init->execute &= 0xfd;
+	else      init->execute |= 0x02;
+}
+
+static inline void
+init_exec_inv(struct nvbios_init *init)
+{
+	init->execute ^= 0x02;
+}
+
+static inline void
+init_exec_force(struct nvbios_init *init, bool exec)
+{
+	if (exec) init->execute |= 0x04;
+	else      init->execute &= 0xfb;
+}
+
+/******************************************************************************
+ * init parser wrappers for normal register/i2c/whatever accessors
+ *****************************************************************************/
+
+static inline int
+init_or(struct nvbios_init *init)
+{
+	if (init_exec(init)) {
+		if (init->outp)
+			return ffs(init->outp->or) - 1;
+		error("script needs OR!!\n");
+	}
+	return 0;
+}
+
+static inline int
+init_link(struct nvbios_init *init)
+{
+	if (init_exec(init)) {
+		if (init->outp)
+			return !(init->outp->sorconf.link & 1);
+		error("script needs OR link\n");
+	}
+	return 0;
+}
+
+static inline int
+init_crtc(struct nvbios_init *init)
+{
+	if (init_exec(init)) {
+		if (init->crtc >= 0)
+			return init->crtc;
+		error("script needs crtc\n");
+	}
+	return 0;
+}
+
+static u8
+init_conn(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	struct nvbios_connE connE;
+	u8  ver, hdr;
+	u32 conn;
+
+	if (init_exec(init)) {
+		if (init->outp) {
+			conn = init->outp->connector;
+			conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
+			if (conn)
+				return connE.type;
+		}
+
+		error("script needs connector type\n");
+	}
+
+	return 0xff;
+}
+
+static inline u32
+init_nvreg(struct nvbios_init *init, u32 reg)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+
+	/* C51 (at least) sometimes has the lower bits set which the VBIOS
+	 * interprets to mean that access needs to go through certain IO
+	 * ports instead.  The NVIDIA binary driver has been seen to access
+	 * these through the NV register address, so lets assume we can
+	 * do the same
+	 */
+	reg &= ~0x00000003;
+
+	/* GF8+ display scripts need register addresses mangled a bit to
+	 * select a specific CRTC/OR
+	 */
+	if (nv_device(init->bios)->card_type >= NV_50) {
+		if (reg & 0x80000000) {
+			reg += init_crtc(init) * 0x800;
+			reg &= ~0x80000000;
+		}
+
+		if (reg & 0x40000000) {
+			reg += init_or(init) * 0x800;
+			reg &= ~0x40000000;
+			if (reg & 0x20000000) {
+				reg += init_link(init) * 0x80;
+				reg &= ~0x20000000;
+			}
+		}
+	}
+
+	if (reg & ~0x00fffffc)
+		warn("unknown bits in register 0x%08x\n", reg);
+
+	if (devinit->mmio)
+		reg = devinit->mmio(devinit, reg);
+	return reg;
+}
+
+static u32
+init_rd32(struct nvbios_init *init, u32 reg)
+{
+	reg = init_nvreg(init, reg);
+	if (reg != ~0 && init_exec(init))
+		return nv_rd32(init->subdev, reg);
+	return 0x00000000;
+}
+
+static void
+init_wr32(struct nvbios_init *init, u32 reg, u32 val)
+{
+	reg = init_nvreg(init, reg);
+	if (reg != ~0 && init_exec(init))
+		nv_wr32(init->subdev, reg, val);
+}
+
+static u32
+init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
+{
+	reg = init_nvreg(init, reg);
+	if (reg != ~0 && init_exec(init)) {
+		u32 tmp = nv_rd32(init->subdev, reg);
+		nv_wr32(init->subdev, reg, (tmp & ~mask) | val);
+		return tmp;
+	}
+	return 0x00000000;
+}
+
+static u8
+init_rdport(struct nvbios_init *init, u16 port)
+{
+	if (init_exec(init))
+		return nv_rdport(init->subdev, init->crtc, port);
+	return 0x00;
+}
+
+static void
+init_wrport(struct nvbios_init *init, u16 port, u8 value)
+{
+	if (init_exec(init))
+		nv_wrport(init->subdev, init->crtc, port, value);
+}
+
+static u8
+init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
+{
+	struct nvkm_subdev *subdev = init->subdev;
+	if (init_exec(init)) {
+		int head = init->crtc < 0 ? 0 : init->crtc;
+		return nv_rdvgai(subdev, head, port, index);
+	}
+	return 0x00;
+}
+
+static void
+init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
+{
+	/* force head 0 for updates to cr44, it only exists on first head */
+	if (nv_device(init->subdev)->card_type < NV_50) {
+		if (port == 0x03d4 && index == 0x44)
+			init->crtc = 0;
+	}
+
+	if (init_exec(init)) {
+		int head = init->crtc < 0 ? 0 : init->crtc;
+		nv_wrvgai(init->subdev, head, port, index, value);
+	}
+
+	/* select head 1 if cr44 write selected it */
+	if (nv_device(init->subdev)->card_type < NV_50) {
+		if (port == 0x03d4 && index == 0x44 && value == 3)
+			init->crtc = 1;
+	}
+}
+
+static struct nvkm_i2c_port *
+init_i2c(struct nvbios_init *init, int index)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(init->bios);
+
+	if (index == 0xff) {
+		index = NV_I2C_DEFAULT(0);
+		if (init->outp && init->outp->i2c_upper_default)
+			index = NV_I2C_DEFAULT(1);
+	} else
+	if (index < 0) {
+		if (!init->outp) {
+			if (init_exec(init))
+				error("script needs output for i2c\n");
+			return NULL;
+		}
+
+		if (index == -2 && init->outp->location) {
+			index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
+			return i2c->find_type(i2c, index);
+		}
+
+		index = init->outp->i2c_index;
+		if (init->outp->type == DCB_OUTPUT_DP)
+			index += NV_I2C_AUX(0);
+	}
+
+	return i2c->find(i2c, index);
+}
+
+static int
+init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg)
+{
+	struct nvkm_i2c_port *port = init_i2c(init, index);
+	if (port && init_exec(init))
+		return nv_rdi2cr(port, addr, reg);
+	return -ENODEV;
+}
+
+static int
+init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
+{
+	struct nvkm_i2c_port *port = init_i2c(init, index);
+	if (port && init_exec(init))
+		return nv_wri2cr(port, addr, reg, val);
+	return -ENODEV;
+}
+
+static u8
+init_rdauxr(struct nvbios_init *init, u32 addr)
+{
+	struct nvkm_i2c_port *port = init_i2c(init, -2);
+	u8 data;
+
+	if (port && init_exec(init)) {
+		int ret = nv_rdaux(port, addr, &data, 1);
+		if (ret == 0)
+			return data;
+		trace("auxch read failed with %d\n", ret);
+	}
+
+	return 0x00;
+}
+
+static int
+init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
+{
+	struct nvkm_i2c_port *port = init_i2c(init, -2);
+	if (port && init_exec(init)) {
+		int ret = nv_wraux(port, addr, &data, 1);
+		if (ret)
+			trace("auxch write failed with %d\n", ret);
+		return ret;
+	}
+	return -ENODEV;
+}
+
+static void
+init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+	if (devinit->pll_set && init_exec(init)) {
+		int ret = devinit->pll_set(devinit, id, freq);
+		if (ret)
+			warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
+	}
+}
+
+/******************************************************************************
+ * parsing of bios structures that are required to execute init tables
+ *****************************************************************************/
+
+static u16
+init_table(struct nvkm_bios *bios, u16 *len)
+{
+	struct bit_entry bit_I;
+
+	if (!bit_entry(bios, 'I', &bit_I)) {
+		*len = bit_I.length;
+		return bit_I.offset;
+	}
+
+	if (bmp_version(bios) >= 0x0510) {
+		*len = 14;
+		return bios->bmp_offset + 75;
+	}
+
+	return 0x0000;
+}
+
+static u16
+init_table_(struct nvbios_init *init, u16 offset, const char *name)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 len, data = init_table(bios, &len);
+	if (data) {
+		if (len >= offset + 2) {
+			data = nv_ro16(bios, data + offset);
+			if (data)
+				return data;
+
+			warn("%s pointer invalid\n", name);
+			return 0x0000;
+		}
+
+		warn("init data too short for %s pointer", name);
+		return 0x0000;
+	}
+
+	warn("init data not found\n");
+	return 0x0000;
+}
+
+#define init_script_table(b) init_table_((b), 0x00, "script table")
+#define init_macro_index_table(b) init_table_((b), 0x02, "macro index table")
+#define init_macro_table(b) init_table_((b), 0x04, "macro table")
+#define init_condition_table(b) init_table_((b), 0x06, "condition table")
+#define init_io_condition_table(b) init_table_((b), 0x08, "io condition table")
+#define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag conditon table")
+#define init_function_table(b) init_table_((b), 0x0c, "function table")
+#define init_xlat_table(b) init_table_((b), 0x10, "xlat table");
+
+static u16
+init_script(struct nvkm_bios *bios, int index)
+{
+	struct nvbios_init init = { .bios = bios };
+	u16 bmp_ver = bmp_version(bios), data;
+
+	if (bmp_ver && bmp_ver < 0x0510) {
+		if (index > 1 || bmp_ver < 0x0100)
+			return 0x0000;
+
+		data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
+		return nv_ro16(bios, data + (index * 2));
+	}
+
+	data = init_script_table(&init);
+	if (data)
+		return nv_ro16(bios, data + (index * 2));
+
+	return 0x0000;
+}
+
+static u16
+init_unknown_script(struct nvkm_bios *bios)
+{
+	u16 len, data = init_table(bios, &len);
+	if (data && len >= 16)
+		return nv_ro16(bios, data + 14);
+	return 0x0000;
+}
+
+static u8
+init_ram_restrict_group_count(struct nvbios_init *init)
+{
+	return nvbios_ramcfg_count(init->bios);
+}
+
+static u8
+init_ram_restrict(struct nvbios_init *init)
+{
+	/* This appears to be the behaviour of the VBIOS parser, and *is*
+	 * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
+	 * avoid fucking up the memory controller (somehow) by reading it
+	 * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
+	 *
+	 * Preserving the non-caching behaviour on earlier chipsets just
+	 * in case *not* re-reading the strap causes similar breakage.
+	 */
+	if (!init->ramcfg || init->bios->version.major < 0x70)
+		init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
+	return (init->ramcfg & 0x7fffffff);
+}
+
+static u8
+init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 table = init_xlat_table(init);
+	if (table) {
+		u16 data = nv_ro16(bios, table + (index * 2));
+		if (data)
+			return nv_ro08(bios, data + offset);
+		warn("xlat table pointer %d invalid\n", index);
+	}
+	return 0x00;
+}
+
+/******************************************************************************
+ * utility functions used by various init opcode handlers
+ *****************************************************************************/
+
+static bool
+init_condition_met(struct nvbios_init *init, u8 cond)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 table = init_condition_table(init);
+	if (table) {
+		u32 reg = nv_ro32(bios, table + (cond * 12) + 0);
+		u32 msk = nv_ro32(bios, table + (cond * 12) + 4);
+		u32 val = nv_ro32(bios, table + (cond * 12) + 8);
+		trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n",
+		      cond, reg, msk, val);
+		return (init_rd32(init, reg) & msk) == val;
+	}
+	return false;
+}
+
+static bool
+init_io_condition_met(struct nvbios_init *init, u8 cond)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 table = init_io_condition_table(init);
+	if (table) {
+		u16 port = nv_ro16(bios, table + (cond * 5) + 0);
+		u8 index = nv_ro08(bios, table + (cond * 5) + 2);
+		u8  mask = nv_ro08(bios, table + (cond * 5) + 3);
+		u8 value = nv_ro08(bios, table + (cond * 5) + 4);
+		trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n",
+		      cond, port, index, mask, value);
+		return (init_rdvgai(init, port, index) & mask) == value;
+	}
+	return false;
+}
+
+static bool
+init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 table = init_io_flag_condition_table(init);
+	if (table) {
+		u16 port = nv_ro16(bios, table + (cond * 9) + 0);
+		u8 index = nv_ro08(bios, table + (cond * 9) + 2);
+		u8  mask = nv_ro08(bios, table + (cond * 9) + 3);
+		u8 shift = nv_ro08(bios, table + (cond * 9) + 4);
+		u16 data = nv_ro16(bios, table + (cond * 9) + 5);
+		u8 dmask = nv_ro08(bios, table + (cond * 9) + 7);
+		u8 value = nv_ro08(bios, table + (cond * 9) + 8);
+		u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift;
+		return (nv_ro08(bios, data + ioval) & dmask) == value;
+	}
+	return false;
+}
+
+static inline u32
+init_shift(u32 data, u8 shift)
+{
+	if (shift < 0x80)
+		return data >> shift;
+	return data << (0x100 - shift);
+}
+
+static u32
+init_tmds_reg(struct nvbios_init *init, u8 tmds)
+{
+	/* For mlv < 0x80, it is an index into a table of TMDS base addresses.
+	 * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
+	 * CR58 for CR57 = 0 to index a table of offsets to the basic
+	 * 0x6808b0 address.
+	 * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
+	 * CR58 for CR57 = 0 to index a table of offsets to the basic
+	 * 0x6808b0 address, and then flip the offset by 8.
+	 */
+	const int pramdac_offset[13] = {
+		0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
+	const u32 pramdac_table[4] = {
+		0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
+
+	if (tmds >= 0x80) {
+		if (init->outp) {
+			u32 dacoffset = pramdac_offset[init->outp->or];
+			if (tmds == 0x81)
+				dacoffset ^= 8;
+			return 0x6808b0 + dacoffset;
+		}
+
+		if (init_exec(init))
+			error("tmds opcodes need dcb\n");
+	} else {
+		if (tmds < ARRAY_SIZE(pramdac_table))
+			return pramdac_table[tmds];
+
+		error("tmds selector 0x%02x unknown\n", tmds);
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ * init opcode handlers
+ *****************************************************************************/
+
+/**
+ * init_reserved - stub for various unknown/unused single-byte opcodes
+ *
+ */
+static void
+init_reserved(struct nvbios_init *init)
+{
+	u8 opcode = nv_ro08(init->bios, init->offset);
+	u8 length, i;
+
+	switch (opcode) {
+	case 0xaa:
+		length = 4;
+		break;
+	default:
+		length = 1;
+		break;
+	}
+
+	trace("RESERVED 0x%02x\t", opcode);
+	for (i = 1; i < length; i++)
+		cont(" 0x%02x", nv_ro08(init->bios, init->offset + i));
+	cont("\n");
+	init->offset += length;
+}
+
+/**
+ * INIT_DONE - opcode 0x71
+ *
+ */
+static void
+init_done(struct nvbios_init *init)
+{
+	trace("DONE\n");
+	init->offset = 0x0000;
+}
+
+/**
+ * INIT_IO_RESTRICT_PROG - opcode 0x32
+ *
+ */
+static void
+init_io_restrict_prog(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8 index = nv_ro08(bios, init->offset + 3);
+	u8  mask = nv_ro08(bios, init->offset + 4);
+	u8 shift = nv_ro08(bios, init->offset + 5);
+	u8 count = nv_ro08(bios, init->offset + 6);
+	u32  reg = nv_ro32(bios, init->offset + 7);
+	u8 conf, i;
+
+	trace("IO_RESTRICT_PROG\tR[0x%06x] = "
+	      "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n",
+	      reg, port, index, mask, shift);
+	init->offset += 11;
+
+	conf = (init_rdvgai(init, port, index) & mask) >> shift;
+	for (i = 0; i < count; i++) {
+		u32 data = nv_ro32(bios, init->offset);
+
+		if (i == conf) {
+			trace("\t0x%08x *\n", data);
+			init_wr32(init, reg, data);
+		} else {
+			trace("\t0x%08x\n", data);
+		}
+
+		init->offset += 4;
+	}
+	trace("}]\n");
+}
+
+/**
+ * INIT_REPEAT - opcode 0x33
+ *
+ */
+static void
+init_repeat(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 count = nv_ro08(bios, init->offset + 1);
+	u16 repeat = init->repeat;
+
+	trace("REPEAT\t0x%02x\n", count);
+	init->offset += 2;
+
+	init->repeat = init->offset;
+	init->repend = init->offset;
+	while (count--) {
+		init->offset = init->repeat;
+		nvbios_exec(init);
+		if (count)
+			trace("REPEAT\t0x%02x\n", count);
+	}
+	init->offset = init->repend;
+	init->repeat = repeat;
+}
+
+/**
+ * INIT_IO_RESTRICT_PLL - opcode 0x34
+ *
+ */
+static void
+init_io_restrict_pll(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8 index = nv_ro08(bios, init->offset + 3);
+	u8  mask = nv_ro08(bios, init->offset + 4);
+	u8 shift = nv_ro08(bios, init->offset + 5);
+	s8  iofc = nv_ro08(bios, init->offset + 6);
+	u8 count = nv_ro08(bios, init->offset + 7);
+	u32  reg = nv_ro32(bios, init->offset + 8);
+	u8 conf, i;
+
+	trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= "
+	      "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n",
+	      reg, port, index, mask, shift, iofc);
+	init->offset += 12;
+
+	conf = (init_rdvgai(init, port, index) & mask) >> shift;
+	for (i = 0; i < count; i++) {
+		u32 freq = nv_ro16(bios, init->offset) * 10;
+
+		if (i == conf) {
+			trace("\t%dkHz *\n", freq);
+			if (iofc > 0 && init_io_flag_condition_met(init, iofc))
+				freq *= 2;
+			init_prog_pll(init, reg, freq);
+		} else {
+			trace("\t%dkHz\n", freq);
+		}
+
+		init->offset += 2;
+	}
+	trace("}]\n");
+}
+
+/**
+ * INIT_END_REPEAT - opcode 0x36
+ *
+ */
+static void
+init_end_repeat(struct nvbios_init *init)
+{
+	trace("END_REPEAT\n");
+	init->offset += 1;
+
+	if (init->repeat) {
+		init->repend = init->offset;
+		init->offset = 0;
+	}
+}
+
+/**
+ * INIT_COPY - opcode 0x37
+ *
+ */
+static void
+init_copy(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u8 shift = nv_ro08(bios, init->offset + 5);
+	u8 smask = nv_ro08(bios, init->offset + 6);
+	u16 port = nv_ro16(bios, init->offset + 7);
+	u8 index = nv_ro08(bios, init->offset + 9);
+	u8  mask = nv_ro08(bios, init->offset + 10);
+	u8  data;
+
+	trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= "
+	      "((R[0x%06x] %s 0x%02x) & 0x%02x)\n",
+	      port, index, mask, reg, (shift & 0x80) ? "<<" : ">>",
+	      (shift & 0x80) ? (0x100 - shift) : shift, smask);
+	init->offset += 11;
+
+	data  = init_rdvgai(init, port, index) & mask;
+	data |= init_shift(init_rd32(init, reg), shift) & smask;
+	init_wrvgai(init, port, index, data);
+}
+
+/**
+ * INIT_NOT - opcode 0x38
+ *
+ */
+static void
+init_not(struct nvbios_init *init)
+{
+	trace("NOT\n");
+	init->offset += 1;
+	init_exec_inv(init);
+}
+
+/**
+ * INIT_IO_FLAG_CONDITION - opcode 0x39
+ *
+ */
+static void
+init_io_flag_condition(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 cond = nv_ro08(bios, init->offset + 1);
+
+	trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
+	init->offset += 2;
+
+	if (!init_io_flag_condition_met(init, cond))
+		init_exec_set(init, false);
+}
+
+/**
+ * INIT_DP_CONDITION - opcode 0x3a
+ *
+ */
+static void
+init_dp_condition(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	struct nvbios_dpout info;
+	u8  cond = nv_ro08(bios, init->offset + 1);
+	u8  unkn = nv_ro08(bios, init->offset + 2);
+	u8  ver, hdr, cnt, len;
+	u16 data;
+
+	trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn);
+	init->offset += 3;
+
+	switch (cond) {
+	case 0:
+		if (init_conn(init) != DCB_CONNECTOR_eDP)
+			init_exec_set(init, false);
+		break;
+	case 1:
+	case 2:
+		if ( init->outp &&
+		    (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
+					       (init->outp->or << 0) |
+					       (init->outp->sorconf.link << 6),
+					       &ver, &hdr, &cnt, &len, &info)))
+		{
+			if (!(info.flags & cond))
+				init_exec_set(init, false);
+			break;
+		}
+
+		if (init_exec(init))
+			warn("script needs dp output table data\n");
+		break;
+	case 5:
+		if (!(init_rdauxr(init, 0x0d) & 1))
+			init_exec_set(init, false);
+		break;
+	default:
+		warn("unknown dp condition 0x%02x\n", cond);
+		break;
+	}
+}
+
+/**
+ * INIT_IO_MASK_OR - opcode 0x3b
+ *
+ */
+static void
+init_io_mask_or(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8    or = init_or(init);
+	u8  data;
+
+	trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)\n", index, or);
+	init->offset += 2;
+
+	data = init_rdvgai(init, 0x03d4, index);
+	init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
+}
+
+/**
+ * INIT_IO_OR - opcode 0x3c
+ *
+ */
+static void
+init_io_or(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8    or = init_or(init);
+	u8  data;
+
+	trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)\n", index, or);
+	init->offset += 2;
+
+	data = init_rdvgai(init, 0x03d4, index);
+	init_wrvgai(init, 0x03d4, index, data | (1 << or));
+}
+
+/**
+ * INIT_ANDN_REG - opcode 0x47
+ *
+ */
+static void
+init_andn_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u32 mask = nv_ro32(bios, init->offset + 5);
+
+	trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
+	init->offset += 9;
+
+	init_mask(init, reg, mask, 0);
+}
+
+/**
+ * INIT_OR_REG - opcode 0x48
+ *
+ */
+static void
+init_or_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u32 mask = nv_ro32(bios, init->offset + 5);
+
+	trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
+	init->offset += 9;
+
+	init_mask(init, reg, 0, mask);
+}
+
+/**
+ * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
+ *
+ */
+static void
+init_idx_addr_latched(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 creg = nv_ro32(bios, init->offset + 1);
+	u32 dreg = nv_ro32(bios, init->offset + 5);
+	u32 mask = nv_ro32(bios, init->offset + 9);
+	u32 data = nv_ro32(bios, init->offset + 13);
+	u8 count = nv_ro08(bios, init->offset + 17);
+
+	trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
+	trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
+	init->offset += 18;
+
+	while (count--) {
+		u8 iaddr = nv_ro08(bios, init->offset + 0);
+		u8 idata = nv_ro08(bios, init->offset + 1);
+
+		trace("\t[0x%02x] = 0x%02x\n", iaddr, idata);
+		init->offset += 2;
+
+		init_wr32(init, dreg, idata);
+		init_mask(init, creg, ~mask, data | iaddr);
+	}
+}
+
+/**
+ * INIT_IO_RESTRICT_PLL2 - opcode 0x4a
+ *
+ */
+static void
+init_io_restrict_pll2(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8 index = nv_ro08(bios, init->offset + 3);
+	u8  mask = nv_ro08(bios, init->offset + 4);
+	u8 shift = nv_ro08(bios, init->offset + 5);
+	u8 count = nv_ro08(bios, init->offset + 6);
+	u32  reg = nv_ro32(bios, init->offset + 7);
+	u8  conf, i;
+
+	trace("IO_RESTRICT_PLL2\t"
+	      "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n",
+	      reg, port, index, mask, shift);
+	init->offset += 11;
+
+	conf = (init_rdvgai(init, port, index) & mask) >> shift;
+	for (i = 0; i < count; i++) {
+		u32 freq = nv_ro32(bios, init->offset);
+		if (i == conf) {
+			trace("\t%dkHz *\n", freq);
+			init_prog_pll(init, reg, freq);
+		} else {
+			trace("\t%dkHz\n", freq);
+		}
+		init->offset += 4;
+	}
+	trace("}]\n");
+}
+
+/**
+ * INIT_PLL2 - opcode 0x4b
+ *
+ */
+static void
+init_pll2(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u32 freq = nv_ro32(bios, init->offset + 5);
+
+	trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
+	init->offset += 9;
+
+	init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_I2C_BYTE - opcode 0x4c
+ *
+ */
+static void
+init_i2c_byte(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
+	u8 count = nv_ro08(bios, init->offset + 3);
+
+	trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
+	init->offset += 4;
+
+	while (count--) {
+		u8  reg = nv_ro08(bios, init->offset + 0);
+		u8 mask = nv_ro08(bios, init->offset + 1);
+		u8 data = nv_ro08(bios, init->offset + 2);
+		int val;
+
+		trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data);
+		init->offset += 3;
+
+		val = init_rdi2cr(init, index, addr, reg);
+		if (val < 0)
+			continue;
+		init_wri2cr(init, index, addr, reg, (val & mask) | data);
+	}
+}
+
+/**
+ * INIT_ZM_I2C_BYTE - opcode 0x4d
+ *
+ */
+static void
+init_zm_i2c_byte(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
+	u8 count = nv_ro08(bios, init->offset + 3);
+
+	trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
+	init->offset += 4;
+
+	while (count--) {
+		u8  reg = nv_ro08(bios, init->offset + 0);
+		u8 data = nv_ro08(bios, init->offset + 1);
+
+		trace("\t[0x%02x] = 0x%02x\n", reg, data);
+		init->offset += 2;
+
+		init_wri2cr(init, index, addr, reg, data);
+	}
+}
+
+/**
+ * INIT_ZM_I2C - opcode 0x4e
+ *
+ */
+static void
+init_zm_i2c(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
+	u8 count = nv_ro08(bios, init->offset + 3);
+	u8 data[256], i;
+
+	trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr);
+	init->offset += 4;
+
+	for (i = 0; i < count; i++) {
+		data[i] = nv_ro08(bios, init->offset);
+		trace("\t0x%02x\n", data[i]);
+		init->offset++;
+	}
+
+	if (init_exec(init)) {
+		struct nvkm_i2c_port *port = init_i2c(init, index);
+		struct i2c_msg msg = {
+			.addr = addr, .flags = 0, .len = count, .buf = data,
+		};
+		int ret;
+
+		if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1)
+			warn("i2c wr failed, %d\n", ret);
+	}
+}
+
+/**
+ * INIT_TMDS - opcode 0x4f
+ *
+ */
+static void
+init_tmds(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 tmds = nv_ro08(bios, init->offset + 1);
+	u8 addr = nv_ro08(bios, init->offset + 2);
+	u8 mask = nv_ro08(bios, init->offset + 3);
+	u8 data = nv_ro08(bios, init->offset + 4);
+	u32 reg = init_tmds_reg(init, tmds);
+
+	trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n",
+	      tmds, addr, mask, data);
+	init->offset += 5;
+
+	if (reg == 0)
+		return;
+
+	init_wr32(init, reg + 0, addr | 0x00010000);
+	init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask));
+	init_wr32(init, reg + 0, addr);
+}
+
+/**
+ * INIT_ZM_TMDS_GROUP - opcode 0x50
+ *
+ */
+static void
+init_zm_tmds_group(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8  tmds = nv_ro08(bios, init->offset + 1);
+	u8 count = nv_ro08(bios, init->offset + 2);
+	u32  reg = init_tmds_reg(init, tmds);
+
+	trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds);
+	init->offset += 3;
+
+	while (count--) {
+		u8 addr = nv_ro08(bios, init->offset + 0);
+		u8 data = nv_ro08(bios, init->offset + 1);
+
+		trace("\t[0x%02x] = 0x%02x\n", addr, data);
+		init->offset += 2;
+
+		init_wr32(init, reg + 4, data);
+		init_wr32(init, reg + 0, addr);
+	}
+}
+
+/**
+ * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
+ *
+ */
+static void
+init_cr_idx_adr_latch(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 addr0 = nv_ro08(bios, init->offset + 1);
+	u8 addr1 = nv_ro08(bios, init->offset + 2);
+	u8  base = nv_ro08(bios, init->offset + 3);
+	u8 count = nv_ro08(bios, init->offset + 4);
+	u8 save0;
+
+	trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1);
+	init->offset += 5;
+
+	save0 = init_rdvgai(init, 0x03d4, addr0);
+	while (count--) {
+		u8 data = nv_ro08(bios, init->offset);
+
+		trace("\t\t[0x%02x] = 0x%02x\n", base, data);
+		init->offset += 1;
+
+		init_wrvgai(init, 0x03d4, addr0, base++);
+		init_wrvgai(init, 0x03d4, addr1, data);
+	}
+	init_wrvgai(init, 0x03d4, addr0, save0);
+}
+
+/**
+ * INIT_CR - opcode 0x52
+ *
+ */
+static void
+init_cr(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 addr = nv_ro08(bios, init->offset + 1);
+	u8 mask = nv_ro08(bios, init->offset + 2);
+	u8 data = nv_ro08(bios, init->offset + 3);
+	u8 val;
+
+	trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
+	init->offset += 4;
+
+	val = init_rdvgai(init, 0x03d4, addr) & mask;
+	init_wrvgai(init, 0x03d4, addr, val | data);
+}
+
+/**
+ * INIT_ZM_CR - opcode 0x53
+ *
+ */
+static void
+init_zm_cr(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 addr = nv_ro08(bios, init->offset + 1);
+	u8 data = nv_ro08(bios, init->offset + 2);
+
+	trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr,  data);
+	init->offset += 3;
+
+	init_wrvgai(init, 0x03d4, addr, data);
+}
+
+/**
+ * INIT_ZM_CR_GROUP - opcode 0x54
+ *
+ */
+static void
+init_zm_cr_group(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 count = nv_ro08(bios, init->offset + 1);
+
+	trace("ZM_CR_GROUP\n");
+	init->offset += 2;
+
+	while (count--) {
+		u8 addr = nv_ro08(bios, init->offset + 0);
+		u8 data = nv_ro08(bios, init->offset + 1);
+
+		trace("\t\tC[0x%02x] = 0x%02x\n", addr, data);
+		init->offset += 2;
+
+		init_wrvgai(init, 0x03d4, addr, data);
+	}
+}
+
+/**
+ * INIT_CONDITION_TIME - opcode 0x56
+ *
+ */
+static void
+init_condition_time(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8  cond = nv_ro08(bios, init->offset + 1);
+	u8 retry = nv_ro08(bios, init->offset + 2);
+	u8  wait = min((u16)retry * 50, 100);
+
+	trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry);
+	init->offset += 3;
+
+	if (!init_exec(init))
+		return;
+
+	while (wait--) {
+		if (init_condition_met(init, cond))
+			return;
+		mdelay(20);
+	}
+
+	init_exec_set(init, false);
+}
+
+/**
+ * INIT_LTIME - opcode 0x57
+ *
+ */
+static void
+init_ltime(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 msec = nv_ro16(bios, init->offset + 1);
+
+	trace("LTIME\t0x%04x\n", msec);
+	init->offset += 3;
+
+	if (init_exec(init))
+		mdelay(msec);
+}
+
+/**
+ * INIT_ZM_REG_SEQUENCE - opcode 0x58
+ *
+ */
+static void
+init_zm_reg_sequence(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 base = nv_ro32(bios, init->offset + 1);
+	u8 count = nv_ro08(bios, init->offset + 5);
+
+	trace("ZM_REG_SEQUENCE\t0x%02x\n", count);
+	init->offset += 6;
+
+	while (count--) {
+		u32 data = nv_ro32(bios, init->offset);
+
+		trace("\t\tR[0x%06x] = 0x%08x\n", base, data);
+		init->offset += 4;
+
+		init_wr32(init, base, data);
+		base += 4;
+	}
+}
+
+/**
+ * INIT_SUB_DIRECT - opcode 0x5b
+ *
+ */
+static void
+init_sub_direct(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 addr = nv_ro16(bios, init->offset + 1);
+	u16 save;
+
+	trace("SUB_DIRECT\t0x%04x\n", addr);
+
+	if (init_exec(init)) {
+		save = init->offset;
+		init->offset = addr;
+		if (nvbios_exec(init)) {
+			error("error parsing sub-table\n");
+			return;
+		}
+		init->offset = save;
+	}
+
+	init->offset += 3;
+}
+
+/**
+ * INIT_JUMP - opcode 0x5c
+ *
+ */
+static void
+init_jump(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 offset = nv_ro16(bios, init->offset + 1);
+
+	trace("JUMP\t0x%04x\n", offset);
+
+	if (init_exec(init))
+		init->offset = offset;
+	else
+		init->offset += 3;
+}
+
+/**
+ * INIT_I2C_IF - opcode 0x5e
+ *
+ */
+static void
+init_i2c_if(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8  addr = nv_ro08(bios, init->offset + 2);
+	u8   reg = nv_ro08(bios, init->offset + 3);
+	u8  mask = nv_ro08(bios, init->offset + 4);
+	u8  data = nv_ro08(bios, init->offset + 5);
+	u8 value;
+
+	trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n",
+	      index, addr, reg, mask, data);
+	init->offset += 6;
+	init_exec_force(init, true);
+
+	value = init_rdi2cr(init, index, addr, reg);
+	if ((value & mask) != data)
+		init_exec_set(init, false);
+
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_COPY_NV_REG - opcode 0x5f
+ *
+ */
+static void
+init_copy_nv_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  sreg = nv_ro32(bios, init->offset + 1);
+	u8  shift = nv_ro08(bios, init->offset + 5);
+	u32 smask = nv_ro32(bios, init->offset + 6);
+	u32  sxor = nv_ro32(bios, init->offset + 10);
+	u32  dreg = nv_ro32(bios, init->offset + 14);
+	u32 dmask = nv_ro32(bios, init->offset + 18);
+	u32 data;
+
+	trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= "
+	      "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n",
+	      dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>",
+	      (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor);
+	init->offset += 22;
+
+	data = init_shift(init_rd32(init, sreg), shift);
+	init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
+}
+
+/**
+ * INIT_ZM_INDEX_IO - opcode 0x62
+ *
+ */
+static void
+init_zm_index_io(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8 index = nv_ro08(bios, init->offset + 3);
+	u8  data = nv_ro08(bios, init->offset + 4);
+
+	trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data);
+	init->offset += 5;
+
+	init_wrvgai(init, port, index, data);
+}
+
+/**
+ * INIT_COMPUTE_MEM - opcode 0x63
+ *
+ */
+static void
+init_compute_mem(struct nvbios_init *init)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+
+	trace("COMPUTE_MEM\n");
+	init->offset += 1;
+
+	init_exec_force(init, true);
+	if (init_exec(init) && devinit->meminit)
+		devinit->meminit(devinit);
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_RESET - opcode 0x65
+ *
+ */
+static void
+init_reset(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32   reg = nv_ro32(bios, init->offset + 1);
+	u32 data1 = nv_ro32(bios, init->offset + 5);
+	u32 data2 = nv_ro32(bios, init->offset + 9);
+	u32 savepci19;
+
+	trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2);
+	init->offset += 13;
+	init_exec_force(init, true);
+
+	savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000);
+	init_wr32(init, reg, data1);
+	udelay(10);
+	init_wr32(init, reg, data2);
+	init_wr32(init, 0x00184c, savepci19);
+	init_mask(init, 0x001850, 0x00000001, 0x00000000);
+
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_MEM - opcode 0x66
+ *
+ */
+static u16
+init_configure_mem_clk(struct nvbios_init *init)
+{
+	u16 mdata = bmp_mem_init_table(init->bios);
+	if (mdata)
+		mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
+	return mdata;
+}
+
+static void
+init_configure_mem(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 mdata, sdata;
+	u32 addr, data;
+
+	trace("CONFIGURE_MEM\n");
+	init->offset += 1;
+
+	if (bios->version.major > 2) {
+		init_done(init);
+		return;
+	}
+	init_exec_force(init, true);
+
+	mdata = init_configure_mem_clk(init);
+	sdata = bmp_sdr_seq_table(bios);
+	if (nv_ro08(bios, mdata) & 0x01)
+		sdata = bmp_ddr_seq_table(bios);
+	mdata += 6; /* skip to data */
+
+	data = init_rdvgai(init, 0x03c4, 0x01);
+	init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
+
+	for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) {
+		switch (addr) {
+		case 0x10021c: /* CKE_NORMAL */
+		case 0x1002d0: /* CMD_REFRESH */
+		case 0x1002d4: /* CMD_PRECHARGE */
+			data = 0x00000001;
+			break;
+		default:
+			data = nv_ro32(bios, mdata);
+			mdata += 4;
+			if (data == 0xffffffff)
+				continue;
+			break;
+		}
+
+		init_wr32(init, addr, data);
+	}
+
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_CLK - opcode 0x67
+ *
+ */
+static void
+init_configure_clk(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 mdata, clock;
+
+	trace("CONFIGURE_CLK\n");
+	init->offset += 1;
+
+	if (bios->version.major > 2) {
+		init_done(init);
+		return;
+	}
+	init_exec_force(init, true);
+
+	mdata = init_configure_mem_clk(init);
+
+	/* NVPLL */
+	clock = nv_ro16(bios, mdata + 4) * 10;
+	init_prog_pll(init, 0x680500, clock);
+
+	/* MPLL */
+	clock = nv_ro16(bios, mdata + 2) * 10;
+	if (nv_ro08(bios, mdata) & 0x01)
+		clock *= 2;
+	init_prog_pll(init, 0x680504, clock);
+
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_PREINIT - opcode 0x68
+ *
+ */
+static void
+init_configure_preinit(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 strap;
+
+	trace("CONFIGURE_PREINIT\n");
+	init->offset += 1;
+
+	if (bios->version.major > 2) {
+		init_done(init);
+		return;
+	}
+	init_exec_force(init, true);
+
+	strap = init_rd32(init, 0x101000);
+	strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6);
+	init_wrvgai(init, 0x03d4, 0x3c, strap);
+
+	init_exec_force(init, false);
+}
+
+/**
+ * INIT_IO - opcode 0x69
+ *
+ */
+static void
+init_io(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8  mask = nv_ro16(bios, init->offset + 3);
+	u8  data = nv_ro16(bios, init->offset + 4);
+	u8 value;
+
+	trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data);
+	init->offset += 5;
+
+	/* ummm.. yes.. should really figure out wtf this is and why it's
+	 * needed some day..  it's almost certainly wrong, but, it also
+	 * somehow makes things work...
+	 */
+	if (nv_device(init->bios)->card_type >= NV_50 &&
+	    port == 0x03c3 && data == 0x01) {
+		init_mask(init, 0x614100, 0xf0800000, 0x00800000);
+		init_mask(init, 0x00e18c, 0x00020000, 0x00020000);
+		init_mask(init, 0x614900, 0xf0800000, 0x00800000);
+		init_mask(init, 0x000200, 0x40000000, 0x00000000);
+		mdelay(10);
+		init_mask(init, 0x00e18c, 0x00020000, 0x00000000);
+		init_mask(init, 0x000200, 0x40000000, 0x40000000);
+		init_wr32(init, 0x614100, 0x00800018);
+		init_wr32(init, 0x614900, 0x00800018);
+		mdelay(10);
+		init_wr32(init, 0x614100, 0x10000018);
+		init_wr32(init, 0x614900, 0x10000018);
+	}
+
+	value = init_rdport(init, port) & mask;
+	init_wrport(init, port, data | value);
+}
+
+/**
+ * INIT_SUB - opcode 0x6b
+ *
+ */
+static void
+init_sub(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u16 addr, save;
+
+	trace("SUB\t0x%02x\n", index);
+
+	addr = init_script(bios, index);
+	if (addr && init_exec(init)) {
+		save = init->offset;
+		init->offset = addr;
+		if (nvbios_exec(init)) {
+			error("error parsing sub-table\n");
+			return;
+		}
+		init->offset = save;
+	}
+
+	init->offset += 2;
+}
+
+/**
+ * INIT_RAM_CONDITION - opcode 0x6d
+ *
+ */
+static void
+init_ram_condition(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8  mask = nv_ro08(bios, init->offset + 1);
+	u8 value = nv_ro08(bios, init->offset + 2);
+
+	trace("RAM_CONDITION\t"
+	      "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value);
+	init->offset += 3;
+
+	if ((init_rd32(init, 0x100000) & mask) != value)
+		init_exec_set(init, false);
+}
+
+/**
+ * INIT_NV_REG - opcode 0x6e
+ *
+ */
+static void
+init_nv_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u32 mask = nv_ro32(bios, init->offset + 5);
+	u32 data = nv_ro32(bios, init->offset + 9);
+
+	trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data);
+	init->offset += 13;
+
+	init_mask(init, reg, ~mask, data);
+}
+
+/**
+ * INIT_MACRO - opcode 0x6f
+ *
+ */
+static void
+init_macro(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8  macro = nv_ro08(bios, init->offset + 1);
+	u16 table;
+
+	trace("MACRO\t0x%02x\n", macro);
+
+	table = init_macro_table(init);
+	if (table) {
+		u32 addr = nv_ro32(bios, table + (macro * 8) + 0);
+		u32 data = nv_ro32(bios, table + (macro * 8) + 4);
+		trace("\t\tR[0x%06x] = 0x%08x\n", addr, data);
+		init_wr32(init, addr, data);
+	}
+
+	init->offset += 2;
+}
+
+/**
+ * INIT_RESUME - opcode 0x72
+ *
+ */
+static void
+init_resume(struct nvbios_init *init)
+{
+	trace("RESUME\n");
+	init->offset += 1;
+	init_exec_set(init, true);
+}
+
+/**
+ * INIT_TIME - opcode 0x74
+ *
+ */
+static void
+init_time(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 usec = nv_ro16(bios, init->offset + 1);
+
+	trace("TIME\t0x%04x\n", usec);
+	init->offset += 3;
+
+	if (init_exec(init)) {
+		if (usec < 1000)
+			udelay(usec);
+		else
+			mdelay((usec + 900) / 1000);
+	}
+}
+
+/**
+ * INIT_CONDITION - opcode 0x75
+ *
+ */
+static void
+init_condition(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 cond = nv_ro08(bios, init->offset + 1);
+
+	trace("CONDITION\t0x%02x\n", cond);
+	init->offset += 2;
+
+	if (!init_condition_met(init, cond))
+		init_exec_set(init, false);
+}
+
+/**
+ * INIT_IO_CONDITION - opcode 0x76
+ *
+ */
+static void
+init_io_condition(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 cond = nv_ro08(bios, init->offset + 1);
+
+	trace("IO_CONDITION\t0x%02x\n", cond);
+	init->offset += 2;
+
+	if (!init_io_condition_met(init, cond))
+		init_exec_set(init, false);
+}
+
+/**
+ * INIT_INDEX_IO - opcode 0x78
+ *
+ */
+static void
+init_index_io(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u16 port = nv_ro16(bios, init->offset + 1);
+	u8 index = nv_ro16(bios, init->offset + 3);
+	u8  mask = nv_ro08(bios, init->offset + 4);
+	u8  data = nv_ro08(bios, init->offset + 5);
+	u8 value;
+
+	trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n",
+	      port, index, mask, data);
+	init->offset += 6;
+
+	value = init_rdvgai(init, port, index) & mask;
+	init_wrvgai(init, port, index, data | value);
+}
+
+/**
+ * INIT_PLL - opcode 0x79
+ *
+ */
+static void
+init_pll(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32  reg = nv_ro32(bios, init->offset + 1);
+	u32 freq = nv_ro16(bios, init->offset + 5) * 10;
+
+	trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
+	init->offset += 7;
+
+	init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_ZM_REG - opcode 0x7a
+ *
+ */
+static void
+init_zm_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u32 data = nv_ro32(bios, init->offset + 5);
+
+	trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data);
+	init->offset += 9;
+
+	if (addr == 0x000200)
+		data |= 0x00000001;
+
+	init_wr32(init, addr, data);
+}
+
+/**
+ * INIT_RAM_RESTRICT_PLL - opcde 0x87
+ *
+ */
+static void
+init_ram_restrict_pll(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8  type = nv_ro08(bios, init->offset + 1);
+	u8 count = init_ram_restrict_group_count(init);
+	u8 strap = init_ram_restrict(init);
+	u8 cconf;
+
+	trace("RAM_RESTRICT_PLL\t0x%02x\n", type);
+	init->offset += 2;
+
+	for (cconf = 0; cconf < count; cconf++) {
+		u32 freq = nv_ro32(bios, init->offset);
+
+		if (cconf == strap) {
+			trace("%dkHz *\n", freq);
+			init_prog_pll(init, type, freq);
+		} else {
+			trace("%dkHz\n", freq);
+		}
+
+		init->offset += 4;
+	}
+}
+
+/**
+ * INIT_GPIO - opcode 0x8e
+ *
+ */
+static void
+init_gpio(struct nvbios_init *init)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(init->bios);
+
+	trace("GPIO\n");
+	init->offset += 1;
+
+	if (init_exec(init) && gpio && gpio->reset)
+		gpio->reset(gpio, DCB_GPIO_UNUSED);
+}
+
+/**
+ * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
+ *
+ */
+static void
+init_ram_restrict_zm_reg_group(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u8  incr = nv_ro08(bios, init->offset + 5);
+	u8   num = nv_ro08(bios, init->offset + 6);
+	u8 count = init_ram_restrict_group_count(init);
+	u8 index = init_ram_restrict(init);
+	u8 i, j;
+
+	trace("RAM_RESTRICT_ZM_REG_GROUP\t"
+	      "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
+	init->offset += 7;
+
+	for (i = 0; i < num; i++) {
+		trace("\tR[0x%06x] = {\n", addr);
+		for (j = 0; j < count; j++) {
+			u32 data = nv_ro32(bios, init->offset);
+
+			if (j == index) {
+				trace("\t\t0x%08x *\n", data);
+				init_wr32(init, addr, data);
+			} else {
+				trace("\t\t0x%08x\n", data);
+			}
+
+			init->offset += 4;
+		}
+		trace("\t}\n");
+		addr += incr;
+	}
+}
+
+/**
+ * INIT_COPY_ZM_REG - opcode 0x90
+ *
+ */
+static void
+init_copy_zm_reg(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 sreg = nv_ro32(bios, init->offset + 1);
+	u32 dreg = nv_ro32(bios, init->offset + 5);
+
+	trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
+	init->offset += 9;
+
+	init_wr32(init, dreg, init_rd32(init, sreg));
+}
+
+/**
+ * INIT_ZM_REG_GROUP - opcode 0x91
+ *
+ */
+static void
+init_zm_reg_group(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u8 count = nv_ro08(bios, init->offset + 5);
+
+	trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
+	init->offset += 6;
+
+	while (count--) {
+		u32 data = nv_ro32(bios, init->offset);
+		trace("\t0x%08x\n", data);
+		init_wr32(init, addr, data);
+		init->offset += 4;
+	}
+}
+
+/**
+ * INIT_XLAT - opcode 0x96
+ *
+ */
+static void
+init_xlat(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 saddr = nv_ro32(bios, init->offset + 1);
+	u8 sshift = nv_ro08(bios, init->offset + 5);
+	u8  smask = nv_ro08(bios, init->offset + 6);
+	u8  index = nv_ro08(bios, init->offset + 7);
+	u32 daddr = nv_ro32(bios, init->offset + 8);
+	u32 dmask = nv_ro32(bios, init->offset + 12);
+	u8  shift = nv_ro08(bios, init->offset + 16);
+	u32 data;
+
+	trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= "
+	      "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n",
+	      daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>",
+	      (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift);
+	init->offset += 17;
+
+	data = init_shift(init_rd32(init, saddr), sshift) & smask;
+	data = init_xlat_(init, index, data) << shift;
+	init_mask(init, daddr, ~dmask, data);
+}
+
+/**
+ * INIT_ZM_MASK_ADD - opcode 0x97
+ *
+ */
+static void
+init_zm_mask_add(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u32 mask = nv_ro32(bios, init->offset + 5);
+	u32  add = nv_ro32(bios, init->offset + 9);
+	u32 data;
+
+	trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
+	init->offset += 13;
+
+	data =  init_rd32(init, addr);
+	data = (data & mask) | ((data + add) & ~mask);
+	init_wr32(init, addr, data);
+}
+
+/**
+ * INIT_AUXCH - opcode 0x98
+ *
+ */
+static void
+init_auxch(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u8 count = nv_ro08(bios, init->offset + 5);
+
+	trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
+	init->offset += 6;
+
+	while (count--) {
+		u8 mask = nv_ro08(bios, init->offset + 0);
+		u8 data = nv_ro08(bios, init->offset + 1);
+		trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
+		mask = init_rdauxr(init, addr) & mask;
+		init_wrauxr(init, addr, mask | data);
+		init->offset += 2;
+	}
+}
+
+/**
+ * INIT_AUXCH - opcode 0x99
+ *
+ */
+static void
+init_zm_auxch(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u32 addr = nv_ro32(bios, init->offset + 1);
+	u8 count = nv_ro08(bios, init->offset + 5);
+
+	trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
+	init->offset += 6;
+
+	while (count--) {
+		u8 data = nv_ro08(bios, init->offset + 0);
+		trace("\tAUX[0x%08x] = 0x%02x\n", addr, data);
+		init_wrauxr(init, addr, data);
+		init->offset += 1;
+	}
+}
+
+/**
+ * INIT_I2C_LONG_IF - opcode 0x9a
+ *
+ */
+static void
+init_i2c_long_if(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	u8 index = nv_ro08(bios, init->offset + 1);
+	u8  addr = nv_ro08(bios, init->offset + 2) >> 1;
+	u8 reglo = nv_ro08(bios, init->offset + 3);
+	u8 reghi = nv_ro08(bios, init->offset + 4);
+	u8  mask = nv_ro08(bios, init->offset + 5);
+	u8  data = nv_ro08(bios, init->offset + 6);
+	struct nvkm_i2c_port *port;
+
+	trace("I2C_LONG_IF\t"
+	      "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n",
+	      index, addr, reglo, reghi, mask, data);
+	init->offset += 7;
+
+	port = init_i2c(init, index);
+	if (port) {
+		u8 i[2] = { reghi, reglo };
+		u8 o[1] = {};
+		struct i2c_msg msg[] = {
+			{ .addr = addr, .flags = 0, .len = 2, .buf = i },
+			{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o }
+		};
+		int ret;
+
+		ret = i2c_transfer(&port->adapter, msg, 2);
+		if (ret == 2 && ((o[0] & mask) == data))
+			return;
+	}
+
+	init_exec_set(init, false);
+}
+
+/**
+ * INIT_GPIO_NE - opcode 0xa9
+ *
+ */
+static void
+init_gpio_ne(struct nvbios_init *init)
+{
+	struct nvkm_bios *bios = init->bios;
+	struct nvkm_gpio *gpio = nvkm_gpio(bios);
+	struct dcb_gpio_func func;
+	u8 count = nv_ro08(bios, init->offset + 1);
+	u8 idx = 0, ver, len;
+	u16 data, i;
+
+	trace("GPIO_NE\t");
+	init->offset += 2;
+
+	for (i = init->offset; i < init->offset + count; i++)
+		cont("0x%02x ", nv_ro08(bios, i));
+	cont("\n");
+
+	while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
+		if (func.func != DCB_GPIO_UNUSED) {
+			for (i = init->offset; i < init->offset + count; i++) {
+				if (func.func == nv_ro08(bios, i))
+					break;
+			}
+
+			trace("\tFUNC[0x%02x]", func.func);
+			if (i == (init->offset + count)) {
+				cont(" *");
+				if (init_exec(init) && gpio && gpio->reset)
+					gpio->reset(gpio, func.func);
+			}
+			cont("\n");
+		}
+	}
+
+	init->offset += count;
+}
+
+static struct nvbios_init_opcode {
+	void (*exec)(struct nvbios_init *);
+} init_opcode[] = {
+	[0x32] = { init_io_restrict_prog },
+	[0x33] = { init_repeat },
+	[0x34] = { init_io_restrict_pll },
+	[0x36] = { init_end_repeat },
+	[0x37] = { init_copy },
+	[0x38] = { init_not },
+	[0x39] = { init_io_flag_condition },
+	[0x3a] = { init_dp_condition },
+	[0x3b] = { init_io_mask_or },
+	[0x3c] = { init_io_or },
+	[0x47] = { init_andn_reg },
+	[0x48] = { init_or_reg },
+	[0x49] = { init_idx_addr_latched },
+	[0x4a] = { init_io_restrict_pll2 },
+	[0x4b] = { init_pll2 },
+	[0x4c] = { init_i2c_byte },
+	[0x4d] = { init_zm_i2c_byte },
+	[0x4e] = { init_zm_i2c },
+	[0x4f] = { init_tmds },
+	[0x50] = { init_zm_tmds_group },
+	[0x51] = { init_cr_idx_adr_latch },
+	[0x52] = { init_cr },
+	[0x53] = { init_zm_cr },
+	[0x54] = { init_zm_cr_group },
+	[0x56] = { init_condition_time },
+	[0x57] = { init_ltime },
+	[0x58] = { init_zm_reg_sequence },
+	[0x5b] = { init_sub_direct },
+	[0x5c] = { init_jump },
+	[0x5e] = { init_i2c_if },
+	[0x5f] = { init_copy_nv_reg },
+	[0x62] = { init_zm_index_io },
+	[0x63] = { init_compute_mem },
+	[0x65] = { init_reset },
+	[0x66] = { init_configure_mem },
+	[0x67] = { init_configure_clk },
+	[0x68] = { init_configure_preinit },
+	[0x69] = { init_io },
+	[0x6b] = { init_sub },
+	[0x6d] = { init_ram_condition },
+	[0x6e] = { init_nv_reg },
+	[0x6f] = { init_macro },
+	[0x71] = { init_done },
+	[0x72] = { init_resume },
+	[0x74] = { init_time },
+	[0x75] = { init_condition },
+	[0x76] = { init_io_condition },
+	[0x78] = { init_index_io },
+	[0x79] = { init_pll },
+	[0x7a] = { init_zm_reg },
+	[0x87] = { init_ram_restrict_pll },
+	[0x8c] = { init_reserved },
+	[0x8d] = { init_reserved },
+	[0x8e] = { init_gpio },
+	[0x8f] = { init_ram_restrict_zm_reg_group },
+	[0x90] = { init_copy_zm_reg },
+	[0x91] = { init_zm_reg_group },
+	[0x92] = { init_reserved },
+	[0x96] = { init_xlat },
+	[0x97] = { init_zm_mask_add },
+	[0x98] = { init_auxch },
+	[0x99] = { init_zm_auxch },
+	[0x9a] = { init_i2c_long_if },
+	[0xa9] = { init_gpio_ne },
+	[0xaa] = { init_reserved },
+};
+
+#define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
+
+int
+nvbios_exec(struct nvbios_init *init)
+{
+	init->nested++;
+	while (init->offset) {
+		u8 opcode = nv_ro08(init->bios, init->offset);
+		if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) {
+			error("unknown opcode 0x%02x\n", opcode);
+			return -EINVAL;
+		}
+
+		init_opcode[opcode].exec(init);
+	}
+	init->nested--;
+	return 0;
+}
+
+int
+nvbios_init(struct nvkm_subdev *subdev, bool execute)
+{
+	struct nvkm_bios *bios = nvkm_bios(subdev);
+	int ret = 0;
+	int i = -1;
+	u16 data;
+
+	if (execute)
+		nv_info(bios, "running init tables\n");
+	while (!ret && (data = (init_script(bios, ++i)))) {
+		struct nvbios_init init = {
+			.subdev = subdev,
+			.bios = bios,
+			.offset = data,
+			.outp = NULL,
+			.crtc = -1,
+			.execute = execute ? 1 : 0,
+		};
+
+		ret = nvbios_exec(&init);
+	}
+
+	/* the vbios parser will run this right after the normal init
+	 * tables, whereas the binary driver appears to run it later.
+	 */
+	if (!ret && (data = init_unknown_script(bios))) {
+		struct nvbios_init init = {
+			.subdev = subdev,
+			.bios = bios,
+			.offset = data,
+			.outp = NULL,
+			.crtc = -1,
+			.execute = execute ? 1 : 0,
+		};
+
+		ret = nvbios_exec(&init);
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c
new file mode 100644
index 0000000..c4087df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/mxm.h>
+
+u16
+mxm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr)
+{
+	struct bit_entry x;
+
+	if (bit_entry(bios, 'x', &x)) {
+		nv_debug(bios, "BIT 'x' table not present\n");
+		return 0x0000;
+	}
+
+	*ver = x.version;
+	*hdr = x.length;
+	if (*ver != 1 || *hdr < 3) {
+		nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr);
+		return 0x0000;
+	}
+
+	return x.offset;
+}
+
+/* These map MXM v2.x digital connection values to the appropriate SOR/link,
+ * hopefully they're correct for all boards within the same chipset...
+ *
+ * MXM v3.x VBIOS are nicer and provide pointers to these tables.
+ */
+static u8 g84_sor_map[16] = {
+	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g92_sor_map[16] = {
+	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
+	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g94_sor_map[16] = {
+	0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
+	0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g98_sor_map[16] = {
+	0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
+	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8
+mxm_sor_map(struct nvkm_bios *bios, u8 conn)
+{
+	u8  ver, hdr;
+	u16 mxm = mxm_table(bios, &ver, &hdr);
+	if (mxm && hdr >= 6) {
+		u16 map = nv_ro16(bios, mxm + 4);
+		if (map) {
+			ver = nv_ro08(bios, map);
+			if (ver == 0x10) {
+				if (conn < nv_ro08(bios, map + 3)) {
+					map += nv_ro08(bios, map + 1);
+					map += conn;
+					return nv_ro08(bios, map);
+				}
+
+				return 0x00;
+			}
+
+			nv_warn(bios, "unknown sor map v%02x\n", ver);
+		}
+	}
+
+	if (bios->version.chip == 0x84 || bios->version.chip == 0x86)
+		return g84_sor_map[conn];
+	if (bios->version.chip == 0x92)
+		return g92_sor_map[conn];
+	if (bios->version.chip == 0x94 || bios->version.chip == 0x96)
+		return g94_sor_map[conn];
+	if (bios->version.chip == 0x98)
+		return g98_sor_map[conn];
+
+	nv_warn(bios, "missing sor map\n");
+	return 0x00;
+}
+
+u8
+mxm_ddc_map(struct nvkm_bios *bios, u8 port)
+{
+	u8  ver, hdr;
+	u16 mxm = mxm_table(bios, &ver, &hdr);
+	if (mxm && hdr >= 8) {
+		u16 map = nv_ro16(bios, mxm + 6);
+		if (map) {
+			ver = nv_ro08(bios, map);
+			if (ver == 0x10) {
+				if (port < nv_ro08(bios, map + 3)) {
+					map += nv_ro08(bios, map + 1);
+					map += port;
+					return nv_ro08(bios, map);
+				}
+
+				return 0x00;
+			}
+
+			nv_warn(bios, "unknown ddc map v%02x\n", ver);
+		}
+	}
+
+	/* v2.x: directly write port as dcb i2cidx */
+	return (port << 4) | port;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c
new file mode 100644
index 0000000..fd7dd71
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/npde.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_npdeTe(struct nvkm_bios *bios, u32 base)
+{
+	struct nvbios_pcirT pcir;
+	u8  ver; u16 hdr;
+	u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
+	if (data = (data + hdr + 0x0f) & ~0x0f, data) {
+		switch (nv_ro32(bios, data + 0x00)) {
+		case 0x4544504e: /* NPDE */
+			break;
+		default:
+			nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
+				 data, nv_ro32(bios, data + 0x00));
+			data = 0;
+			break;
+		}
+	}
+	return data;
+}
+
+u32
+nvbios_npdeTp(struct nvkm_bios *bios, u32 base, struct nvbios_npdeT *info)
+{
+	u32 data = nvbios_npdeTe(bios, base);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->image_size = nv_ro16(bios, data + 0x08) * 512;
+		info->last = nv_ro08(bios, data + 0x0a) & 0x80;
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c
new file mode 100644
index 0000000..df59787
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_pcirTe(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr)
+{
+	u32 data = nv_ro16(bios, base + 0x18);
+	if (data) {
+		data += base;
+		switch (nv_ro32(bios, data + 0x00)) {
+		case 0x52494350: /* PCIR */
+		case 0x53494752: /* RGIS */
+		case 0x5344504e: /* NPDS */
+			*hdr = nv_ro16(bios, data + 0x0a);
+			*ver = nv_ro08(bios, data + 0x0c);
+			break;
+		default:
+			nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
+				 data, nv_ro32(bios, data + 0x00));
+			data = 0;
+			break;
+		}
+	}
+	return data;
+}
+
+u32
+nvbios_pcirTp(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr,
+	      struct nvbios_pcirT *info)
+{
+	u32 data = nvbios_pcirTe(bios, base, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	if (data) {
+		info->vendor_id = nv_ro16(bios, data + 0x04);
+		info->device_id = nv_ro16(bios, data + 0x06);
+		info->class_code[0] = nv_ro08(bios, data + 0x0d);
+		info->class_code[1] = nv_ro08(bios, data + 0x0e);
+		info->class_code[2] = nv_ro08(bios, data + 0x0f);
+		info->image_size = nv_ro16(bios, data + 0x10) * 512;
+		info->image_rev = nv_ro16(bios, data + 0x12);
+		info->image_type = nv_ro08(bios, data + 0x14);
+		info->last = nv_ro08(bios, data + 0x15) & 0x80;
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
new file mode 100644
index 0000000..382ae9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/perf.h>
+
+#include <core/device.h>
+
+u16
+nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
+		  u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_P;
+	u16 perf = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version <= 2) {
+			perf = nv_ro16(bios, bit_P.offset + 0);
+			if (perf) {
+				*ver = nv_ro08(bios, perf + 0);
+				*hdr = nv_ro08(bios, perf + 1);
+				if (*ver >= 0x40 && *ver < 0x41) {
+					*cnt = nv_ro08(bios, perf + 5);
+					*len = nv_ro08(bios, perf + 2);
+					*snr = nv_ro08(bios, perf + 4);
+					*ssz = nv_ro08(bios, perf + 3);
+					return perf;
+				} else
+				if (*ver >= 0x20 && *ver < 0x40) {
+					*cnt = nv_ro08(bios, perf + 2);
+					*len = nv_ro08(bios, perf + 3);
+					*snr = nv_ro08(bios, perf + 4);
+					*ssz = nv_ro08(bios, perf + 5);
+					return perf;
+				}
+			}
+		}
+	}
+
+	if (bios->bmp_offset) {
+		if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) {
+			perf = nv_ro16(bios, bios->bmp_offset + 0x94);
+			if (perf) {
+				*hdr = nv_ro08(bios, perf + 0);
+				*ver = nv_ro08(bios, perf + 1);
+				*cnt = nv_ro08(bios, perf + 2);
+				*len = nv_ro08(bios, perf + 3);
+				*snr = 0;
+				*ssz = 0;
+				return perf;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_perf_entry(struct nvkm_bios *bios, int idx,
+		  u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (perf && idx < *cnt) {
+		perf = perf + *hdr + (idx * (*len + (snr * ssz)));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return perf;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_perfEp(struct nvkm_bios *bios, int idx,
+	      u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *info)
+{
+	u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	info->pstate = nv_ro08(bios, perf + 0x00);
+	switch (!!perf * *ver) {
+	case 0x12:
+	case 0x13:
+	case 0x14:
+		info->core     = nv_ro32(bios, perf + 0x01) * 10;
+		info->memory   = nv_ro32(bios, perf + 0x05) * 20;
+		info->fanspeed = nv_ro08(bios, perf + 0x37);
+		if (*hdr > 0x38)
+			info->voltage = nv_ro08(bios, perf + 0x38);
+		break;
+	case 0x21:
+	case 0x23:
+	case 0x24:
+		info->fanspeed = nv_ro08(bios, perf + 0x04);
+		info->voltage  = nv_ro08(bios, perf + 0x05);
+		info->shader   = nv_ro16(bios, perf + 0x06) * 1000;
+		info->core     = info->shader + (signed char)
+				 nv_ro08(bios, perf + 0x08) * 1000;
+		switch (nv_device(bios)->chipset) {
+		case 0x49:
+		case 0x4b:
+			info->memory = nv_ro16(bios, perf + 0x0b) * 1000;
+			break;
+		default:
+			info->memory = nv_ro16(bios, perf + 0x0b) * 2000;
+			break;
+		}
+		break;
+	case 0x25:
+		info->fanspeed = nv_ro08(bios, perf + 0x04);
+		info->voltage  = nv_ro08(bios, perf + 0x05);
+		info->core     = nv_ro16(bios, perf + 0x06) * 1000;
+		info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
+		info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
+		break;
+	case 0x30:
+		info->script   = nv_ro16(bios, perf + 0x02);
+	case 0x35:
+		info->fanspeed = nv_ro08(bios, perf + 0x06);
+		info->voltage  = nv_ro08(bios, perf + 0x07);
+		info->core     = nv_ro16(bios, perf + 0x08) * 1000;
+		info->shader   = nv_ro16(bios, perf + 0x0a) * 1000;
+		info->memory   = nv_ro16(bios, perf + 0x0c) * 1000;
+		info->vdec     = nv_ro16(bios, perf + 0x10) * 1000;
+		info->disp     = nv_ro16(bios, perf + 0x14) * 1000;
+		break;
+	case 0x40:
+		info->voltage  = nv_ro08(bios, perf + 0x02);
+		break;
+	default:
+		return 0x0000;
+	}
+	return perf;
+}
+
+u32
+nvbios_perfSe(struct nvkm_bios *bios, u32 perfE, int idx,
+	      u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+	u32 data = 0x00000000;
+	if (idx < cnt) {
+		data = perfE + *hdr + (idx * len);
+		*hdr = len;
+	}
+	return data;
+}
+
+u32
+nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx,
+	      u8 *ver, u8 *hdr, u8 cnt, u8 len,
+	      struct nvbios_perfS *info)
+{
+	u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	case 0x40:
+		info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000;
+		break;
+	default:
+		break;
+	}
+	return data;
+}
+
+int
+nvbios_perf_fan_parse(struct nvkm_bios *bios,
+		      struct nvbios_perf_fan *fan)
+{
+	u8  ver, hdr, cnt, len, snr, ssz;
+	u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+	if (!perf)
+		return -ENODEV;
+
+	if (ver >= 0x20 && ver < 0x40 && hdr > 6)
+		fan->pwm_divisor = nv_ro16(bios, perf + 6);
+	else
+		fan->pwm_divisor = 0;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c
new file mode 100644
index 0000000..ebd402e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2005-2006 Erik Waling
+ * Copyright 2006 Stephane Marchesin
+ * Copyright 2007-2009 Stuart Bennett
+ *
+ * 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 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 <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/pll.h>
+#include <subdev/vga.h>
+
+#include <core/device.h>
+
+struct pll_mapping {
+	u8  type;
+	u32 reg;
+};
+
+static struct pll_mapping
+nv04_pll_mapping[] = {
+	{ PLL_CORE  , 0x680500 },
+	{ PLL_MEMORY, 0x680504 },
+	{ PLL_VPLL0 , 0x680508 },
+	{ PLL_VPLL1 , 0x680520 },
+	{}
+};
+
+static struct pll_mapping
+nv40_pll_mapping[] = {
+	{ PLL_CORE  , 0x004000 },
+	{ PLL_MEMORY, 0x004020 },
+	{ PLL_VPLL0 , 0x680508 },
+	{ PLL_VPLL1 , 0x680520 },
+	{}
+};
+
+static struct pll_mapping
+nv50_pll_mapping[] = {
+	{ PLL_CORE  , 0x004028 },
+	{ PLL_SHADER, 0x004020 },
+	{ PLL_UNK03 , 0x004000 },
+	{ PLL_MEMORY, 0x004008 },
+	{ PLL_UNK40 , 0x00e810 },
+	{ PLL_UNK41 , 0x00e818 },
+	{ PLL_UNK42 , 0x00e824 },
+	{ PLL_VPLL0 , 0x614100 },
+	{ PLL_VPLL1 , 0x614900 },
+	{}
+};
+
+static struct pll_mapping
+g84_pll_mapping[] = {
+	{ PLL_CORE  , 0x004028 },
+	{ PLL_SHADER, 0x004020 },
+	{ PLL_MEMORY, 0x004008 },
+	{ PLL_VDEC  , 0x004030 },
+	{ PLL_UNK41 , 0x00e818 },
+	{ PLL_VPLL0 , 0x614100 },
+	{ PLL_VPLL1 , 0x614900 },
+	{}
+};
+
+static u16
+pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_C;
+
+	if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) {
+		u16 data = nv_ro16(bios, bit_C.offset + 8);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0);
+			*hdr = nv_ro08(bios, data + 1);
+			*len = nv_ro08(bios, data + 2);
+			*cnt = nv_ro08(bios, data + 3);
+			return data;
+		}
+	}
+
+	if (bmp_version(bios) >= 0x0524) {
+		u16 data = nv_ro16(bios, bios->bmp_offset + 142);
+		if (data) {
+			*ver = nv_ro08(bios, data + 0);
+			*hdr = 1;
+			*cnt = 1;
+			*len = 0x18;
+			return data;
+		}
+	}
+
+	*ver = 0x00;
+	return 0x0000;
+}
+
+static struct pll_mapping *
+pll_map(struct nvkm_bios *bios)
+{
+	switch (nv_device(bios)->card_type) {
+	case NV_04:
+	case NV_10:
+	case NV_11:
+	case NV_20:
+	case NV_30:
+		return nv04_pll_mapping;
+		break;
+	case NV_40:
+		return nv40_pll_mapping;
+	case NV_50:
+		if (nv_device(bios)->chipset == 0x50)
+			return nv50_pll_mapping;
+		else
+		if (nv_device(bios)->chipset <  0xa3 ||
+		    nv_device(bios)->chipset == 0xaa ||
+		    nv_device(bios)->chipset == 0xac)
+			return g84_pll_mapping;
+	default:
+		return NULL;
+	}
+}
+
+static u16
+pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len)
+{
+	struct pll_mapping *map;
+	u8  hdr, cnt;
+	u16 data;
+
+	data = pll_limits_table(bios, ver, &hdr, &cnt, len);
+	if (data && *ver >= 0x30) {
+		data += hdr;
+		while (cnt--) {
+			if (nv_ro32(bios, data + 3) == reg) {
+				*type = nv_ro08(bios, data + 0);
+				return data;
+			}
+			data += *len;
+		}
+		return 0x0000;
+	}
+
+	map = pll_map(bios);
+	while (map->reg) {
+		if (map->reg == reg && *ver >= 0x20) {
+			u16 addr = (data += hdr);
+			*type = map->type;
+			while (cnt--) {
+				if (nv_ro32(bios, data) == map->reg)
+					return data;
+				data += *len;
+			}
+			return addr;
+		} else
+		if (map->reg == reg) {
+			*type = map->type;
+			return data + 1;
+		}
+		map++;
+	}
+
+	return 0x0000;
+}
+
+static u16
+pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len)
+{
+	struct pll_mapping *map;
+	u8  hdr, cnt;
+	u16 data;
+
+	data = pll_limits_table(bios, ver, &hdr, &cnt, len);
+	if (data && *ver >= 0x30) {
+		data += hdr;
+		while (cnt--) {
+			if (nv_ro08(bios, data + 0) == type) {
+				*reg = nv_ro32(bios, data + 3);
+				return data;
+			}
+			data += *len;
+		}
+		return 0x0000;
+	}
+
+	map = pll_map(bios);
+	while (map->reg) {
+		if (map->type == type && *ver >= 0x20) {
+			u16 addr = (data += hdr);
+			*reg = map->reg;
+			while (cnt--) {
+				if (nv_ro32(bios, data) == map->reg)
+					return data;
+				data += *len;
+			}
+			return addr;
+		} else
+		if (map->type == type) {
+			*reg = map->reg;
+			return data + 1;
+		}
+		map++;
+	}
+
+	return 0x0000;
+}
+
+int
+nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info)
+{
+	u8  ver, len;
+	u32 reg = type;
+	u16 data;
+
+	if (type > PLL_MAX) {
+		reg  = type;
+		data = pll_map_reg(bios, reg, &type, &ver, &len);
+	} else {
+		data = pll_map_type(bios, type, &reg, &ver, &len);
+	}
+
+	if (ver && !data)
+		return -ENOENT;
+
+	memset(info, 0, sizeof(*info));
+	info->type = type;
+	info->reg = reg;
+
+	switch (ver) {
+	case 0x00:
+		break;
+	case 0x10:
+	case 0x11:
+		info->vco1.min_freq = nv_ro32(bios, data + 0);
+		info->vco1.max_freq = nv_ro32(bios, data + 4);
+		info->vco2.min_freq = nv_ro32(bios, data + 8);
+		info->vco2.max_freq = nv_ro32(bios, data + 12);
+		info->vco1.min_inputfreq = nv_ro32(bios, data + 16);
+		info->vco2.min_inputfreq = nv_ro32(bios, data + 20);
+		info->vco1.max_inputfreq = INT_MAX;
+		info->vco2.max_inputfreq = INT_MAX;
+
+		info->max_p = 0x7;
+		info->max_p_usable = 0x6;
+
+		/* these values taken from nv30/31/36 */
+		switch (bios->version.chip) {
+		case 0x36:
+			info->vco1.min_n = 0x5;
+			break;
+		default:
+			info->vco1.min_n = 0x1;
+			break;
+		}
+		info->vco1.max_n = 0xff;
+		info->vco1.min_m = 0x1;
+		info->vco1.max_m = 0xd;
+
+		/*
+		 * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this
+		 * table version (apart from nv35)), N2 is compared to
+		 * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and
+		 * save a comparison
+		 */
+		info->vco2.min_n = 0x4;
+		switch (bios->version.chip) {
+		case 0x30:
+		case 0x35:
+			info->vco2.max_n = 0x1f;
+			break;
+		default:
+			info->vco2.max_n = 0x28;
+			break;
+		}
+		info->vco2.min_m = 0x1;
+		info->vco2.max_m = 0x4;
+		break;
+	case 0x20:
+	case 0x21:
+		info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000;
+		info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000;
+		info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000;
+		info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000;
+		info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000;
+		info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000;
+		info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000;
+		info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000;
+		info->vco1.min_n = nv_ro08(bios, data + 20);
+		info->vco1.max_n = nv_ro08(bios, data + 21);
+		info->vco1.min_m = nv_ro08(bios, data + 22);
+		info->vco1.max_m = nv_ro08(bios, data + 23);
+		info->vco2.min_n = nv_ro08(bios, data + 24);
+		info->vco2.max_n = nv_ro08(bios, data + 25);
+		info->vco2.min_m = nv_ro08(bios, data + 26);
+		info->vco2.max_m = nv_ro08(bios, data + 27);
+
+		info->max_p = nv_ro08(bios, data + 29);
+		info->max_p_usable = info->max_p;
+		if (bios->version.chip < 0x60)
+			info->max_p_usable = 0x6;
+		info->bias_p = nv_ro08(bios, data + 30);
+
+		if (len > 0x22)
+			info->refclk = nv_ro32(bios, data + 31);
+		break;
+	case 0x30:
+		data = nv_ro16(bios, data + 1);
+
+		info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
+		info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
+		info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000;
+		info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000;
+		info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000;
+		info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000;
+		info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000;
+		info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000;
+		info->vco1.min_n = nv_ro08(bios, data + 16);
+		info->vco1.max_n = nv_ro08(bios, data + 17);
+		info->vco1.min_m = nv_ro08(bios, data + 18);
+		info->vco1.max_m = nv_ro08(bios, data + 19);
+		info->vco2.min_n = nv_ro08(bios, data + 20);
+		info->vco2.max_n = nv_ro08(bios, data + 21);
+		info->vco2.min_m = nv_ro08(bios, data + 22);
+		info->vco2.max_m = nv_ro08(bios, data + 23);
+		info->max_p_usable = info->max_p = nv_ro08(bios, data + 25);
+		info->bias_p = nv_ro08(bios, data + 27);
+		info->refclk = nv_ro32(bios, data + 28);
+		break;
+	case 0x40:
+		info->refclk = nv_ro16(bios, data + 9) * 1000;
+		data = nv_ro16(bios, data + 1);
+
+		info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
+		info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
+		info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000;
+		info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000;
+		info->vco1.min_m = nv_ro08(bios, data + 8);
+		info->vco1.max_m = nv_ro08(bios, data + 9);
+		info->vco1.min_n = nv_ro08(bios, data + 10);
+		info->vco1.max_n = nv_ro08(bios, data + 11);
+		info->min_p = nv_ro08(bios, data + 12);
+		info->max_p = nv_ro08(bios, data + 13);
+		break;
+	default:
+		nv_error(bios, "unknown pll limits version 0x%02x\n", ver);
+		return -EINVAL;
+	}
+
+	if (!info->refclk) {
+		info->refclk = nv_device(bios)->crystal;
+		if (bios->version.chip == 0x51) {
+			u32 sel_clk = nv_rd32(bios, 0x680524);
+			if ((info->reg == 0x680508 && sel_clk & 0x20) ||
+			    (info->reg == 0x680520 && sel_clk & 0x80)) {
+				if (nv_rdvgac(bios, 0, 0x27) < 0xa3)
+					info->refclk = 200000;
+				else
+					info->refclk = 25000;
+			}
+		}
+	}
+
+	/*
+	 * By now any valid limit table ought to have set a max frequency for
+	 * vco1, so if it's zero it's either a pre limit table bios, or one
+	 * with an empty limit table (seen on nv18)
+	 */
+	if (!info->vco1.max_freq) {
+		info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67);
+		info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71);
+		if (bmp_version(bios) < 0x0506) {
+			info->vco1.max_freq = 256000;
+			info->vco1.min_freq = 128000;
+		}
+
+		info->vco1.min_inputfreq = 0;
+		info->vco1.max_inputfreq = INT_MAX;
+		info->vco1.min_n = 0x1;
+		info->vco1.max_n = 0xff;
+		info->vco1.min_m = 0x1;
+
+		if (nv_device(bios)->crystal == 13500) {
+			/* nv05 does this, nv11 doesn't, nv10 unknown */
+			if (bios->version.chip < 0x11)
+				info->vco1.min_m = 0x7;
+			info->vco1.max_m = 0xd;
+		} else {
+			if (bios->version.chip < 0x11)
+				info->vco1.min_m = 0x8;
+			info->vco1.max_m = 0xe;
+		}
+
+		if (bios->version.chip <  0x17 ||
+		    bios->version.chip == 0x1a ||
+		    bios->version.chip == 0x20)
+			info->max_p = 4;
+		else
+			info->max_p = 5;
+		info->max_p_usable = info->max_p;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c
new file mode 100644
index 0000000..20c5ce0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pmu.h>
+
+static u32
+weirdo_pointer(struct nvkm_bios *bios, u32 data)
+{
+	struct nvbios_image image;
+	int idx = 0;
+	if (nvbios_image(bios, idx++, &image)) {
+		data -= image.size;
+		while (nvbios_image(bios, idx++, &image)) {
+			if (image.type == 0xe0)
+				return image.base + data;
+		}
+	}
+	return 0;
+}
+
+u32
+nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_p;
+	u32 data = 0;
+
+	if (!bit_entry(bios, 'p', &bit_p)) {
+		if (bit_p.version == 2 && bit_p.length >= 4)
+			data = nv_ro32(bios, bit_p.offset + 0x00);
+		if ((data = weirdo_pointer(bios, data))) {
+			*ver = nv_ro08(bios, data + 0x00); /* maybe? */
+			*hdr = nv_ro08(bios, data + 0x01);
+			*len = nv_ro08(bios, data + 0x02);
+			*cnt = nv_ro08(bios, data + 0x03);
+		}
+	}
+
+	return data;
+}
+
+u32
+nvbios_pmuTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+	     struct nvbios_pmuT *info)
+{
+	u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	default:
+		break;
+	}
+	return data;
+}
+
+u32
+nvbios_pmuEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+	u8  cnt, len;
+	u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
+	if (data && idx < cnt) {
+		data = data + *hdr + (idx * len);
+		*hdr = len;
+		return data;
+	}
+	return 0;
+}
+
+u32
+nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+	     struct nvbios_pmuE *info)
+{
+	u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!data * *ver) {
+	default:
+		info->type = nv_ro08(bios, data + 0x00);
+		info->data = nv_ro32(bios, data + 0x02);
+		break;
+	}
+	return data;
+}
+
+bool
+nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info)
+{
+	struct nvbios_pmuE pmuE;
+	u8  ver, hdr, idx = 0;
+	u32 data;
+	memset(info, 0x00, sizeof(*info));
+	while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
+		if ( pmuE.type == type &&
+		    (data = weirdo_pointer(bios, pmuE.data))) {
+			info->init_addr_pmu = nv_ro32(bios, data + 0x08);
+			info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
+			info->boot_addr     = data + 0x30;
+			info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
+					      nv_ro32(bios, data + 0x18);
+			info->boot_size     = nv_ro32(bios, data + 0x1c) -
+					      nv_ro32(bios, data + 0x18);
+			info->code_addr     = info->boot_addr + info->boot_size;
+			info->code_addr_pmu = info->boot_addr_pmu +
+					      info->boot_size;
+			info->code_size     = nv_ro32(bios, data + 0x20);
+			info->data_addr     = data + 0x30 +
+					      nv_ro32(bios, data + 0x24);
+			info->data_addr_pmu = nv_ro32(bios, data + 0x28);
+			info->data_size     = nv_ro32(bios, data + 0x2c);
+			return true;
+		}
+	}
+	return false;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
new file mode 100644
index 0000000..95e4fa1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
@@ -0,0 +1,23 @@
+#ifndef __NVKM_BIOS_PRIV_H__
+#define __NVKM_BIOS_PRIV_H__
+#include <subdev/bios.h>
+
+struct nvbios_source {
+	const char *name;
+	void *(*init)(struct nvkm_bios *, const char *);
+	void  (*fini)(void *);
+	u32   (*read)(void *, u32 offset, u32 length, struct nvkm_bios *);
+	bool rw;
+};
+
+int nvbios_extend(struct nvkm_bios *, u32 length);
+int nvbios_shadow(struct nvkm_bios *);
+
+extern const struct nvbios_source nvbios_rom;
+extern const struct nvbios_source nvbios_ramin;
+extern const struct nvbios_source nvbios_acpi_fast;
+extern const struct nvbios_source nvbios_acpi_slow;
+extern const struct nvbios_source nvbios_pcirom;
+extern const struct nvbios_source nvbios_platform;
+extern const struct nvbios_source nvbios_of;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c
new file mode 100644
index 0000000..a17b221
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
+#include <subdev/bios/M0203.h>
+
+static u8
+nvbios_ramcfg_strap(struct nvkm_subdev *subdev)
+{
+	return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2;
+}
+
+u8
+nvbios_ramcfg_count(struct nvkm_bios *bios)
+{
+	struct bit_entry bit_M;
+
+	if (!bit_entry(bios, 'M', &bit_M)) {
+		if (bit_M.version == 1 && bit_M.length >= 5)
+			return nv_ro08(bios, bit_M.offset + 2);
+		if (bit_M.version == 2 && bit_M.length >= 3)
+			return nv_ro08(bios, bit_M.offset + 0);
+	}
+
+	return 0x00;
+}
+
+u8
+nvbios_ramcfg_index(struct nvkm_subdev *subdev)
+{
+	struct nvkm_bios *bios = nvkm_bios(subdev);
+	u8 strap = nvbios_ramcfg_strap(subdev);
+	u32 xlat = 0x00000000;
+	struct bit_entry bit_M;
+	struct nvbios_M0203E M0203E;
+	u8 ver, hdr;
+
+	if (!bit_entry(bios, 'M', &bit_M)) {
+		if (bit_M.version == 1 && bit_M.length >= 5)
+			xlat = nv_ro16(bios, bit_M.offset + 3);
+		if (bit_M.version == 2 && bit_M.length >= 3) {
+			/*XXX: is M ever shorter than this?
+			 *     if not - what is xlat used for now?
+			 *     also - sigh..
+			 */
+			if (bit_M.length >= 7 &&
+			    nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
+				return M0203E.group;
+			xlat = nv_ro16(bios, bit_M.offset + 1);
+		}
+	}
+
+	if (xlat)
+		strap = nv_ro08(bios, xlat + strap);
+	return strap;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c
new file mode 100644
index 0000000..8b17bb4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/rammap.h>
+
+u32
+nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
+		u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_P;
+	u16 rammap = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2)
+			rammap = nv_ro16(bios, bit_P.offset + 4);
+
+		if (rammap) {
+			*ver = nv_ro08(bios, rammap + 0);
+			switch (*ver) {
+			case 0x10:
+			case 0x11:
+				*hdr = nv_ro08(bios, rammap + 1);
+				*cnt = nv_ro08(bios, rammap + 5);
+				*len = nv_ro08(bios, rammap + 2);
+				*snr = nv_ro08(bios, rammap + 4);
+				*ssz = nv_ro08(bios, rammap + 3);
+				return rammap;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u32
+nvbios_rammapEe(struct nvkm_bios *bios, int idx,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (rammap && idx < *cnt) {
+		rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return rammap;
+	}
+	return 0x0000;
+}
+
+u32
+nvbios_rammapEp(struct nvkm_bios *bios, int idx,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p)
+{
+	u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
+	memset(p, 0x00, sizeof(*p));
+	p->rammap_ver = *ver;
+	p->rammap_hdr = *hdr;
+	switch (!!data * *ver) {
+	case 0x10:
+		p->rammap_min      =  nv_ro16(bios, data + 0x00);
+		p->rammap_max      =  nv_ro16(bios, data + 0x02);
+		p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
+		p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
+		break;
+	case 0x11:
+		p->rammap_min      =  nv_ro16(bios, data + 0x00);
+		p->rammap_max      =  nv_ro16(bios, data + 0x02);
+		p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
+		p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
+		p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+		temp = nv_ro32(bios, data + 0x09);
+		p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
+		p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
+		p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
+		p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
+		p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
+		p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
+		p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
+		p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
+		p->rammap_11_0d    =  nv_ro08(bios, data + 0x0d);
+		p->rammap_11_0e    =  nv_ro08(bios, data + 0x0e);
+		p->rammap_11_0f    =  nv_ro08(bios, data + 0x0f);
+		p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
+		break;
+	default:
+		data = 0;
+		break;
+	}
+	return data;
+}
+
+u32
+nvbios_rammapEm(struct nvkm_bios *bios, u16 mhz,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *info)
+{
+	int idx = 0;
+	u32 data;
+	while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
+		if (mhz >= info->rammap_min && mhz <= info->rammap_max)
+			break;
+	}
+	return data;
+}
+
+u32
+nvbios_rammapSe(struct nvkm_bios *bios, u32 data,
+		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr)
+{
+	if (idx < ecnt) {
+		data = data + ehdr + (idx * elen);
+		*ver = ever;
+		*hdr = elen;
+		return data;
+	}
+	return 0;
+}
+
+u32
+nvbios_rammapSp(struct nvkm_bios *bios, u32 data,
+		u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+		u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
+{
+	data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
+	p->ramcfg_ver = *ver;
+	p->ramcfg_hdr = *hdr;
+	switch (!!data * *ver) {
+	case 0x10:
+		p->ramcfg_timing   =  nv_ro08(bios, data + 0x01);
+		p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
+		p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
+		p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+		p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+		p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+		p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
+		p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+		p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+		p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
+		p->ramcfg_10_05    = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
+		p->ramcfg_10_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+		p->ramcfg_10_07    = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
+		p->ramcfg_10_08    = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
+		p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
+		p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
+		break;
+	case 0x11:
+		p->ramcfg_timing   =  nv_ro08(bios, data + 0x00);
+		p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
+		p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
+		p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
+		p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3;
+		p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4;
+		p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5;
+		p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6;
+		p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7;
+		p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0;
+		p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+		p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+		p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+		p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+		p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7;
+		p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+		p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4;
+		p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6;
+		p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4;
+		p->ramcfg_11_04    = (nv_ro08(bios, data + 0x04) & 0xff) >> 0;
+		p->ramcfg_11_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+		p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1;
+		p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2;
+		p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3;
+		p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4;
+		p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6;
+		p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7;
+		p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
+		p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1;
+		p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2;
+		p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3;
+		p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+		p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5;
+		p->ramcfg_11_09    = (nv_ro08(bios, data + 0x09) & 0xff) >> 0;
+		break;
+	default:
+		data = 0;
+		break;
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
new file mode 100644
index 0000000..8c2b7cb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/image.h>
+
+struct shadow {
+	struct nvkm_oclass base;
+	u32 skip;
+	const struct nvbios_source *func;
+	void *data;
+	u32 size;
+	int score;
+};
+
+static bool
+shadow_fetch(struct nvkm_bios *bios, u32 upto)
+{
+	struct shadow *mthd = (void *)nv_object(bios)->oclass;
+	const u32 limit = (upto + 3) & ~3;
+	const u32 start = bios->size;
+	void *data = mthd->data;
+	if (nvbios_extend(bios, limit) > 0) {
+		u32 read = mthd->func->read(data, start, limit - start, bios);
+		bios->size = start + read;
+	}
+	return bios->size >= limit;
+}
+
+static u8
+shadow_rd08(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	if (shadow_fetch(bios, addr + 1))
+		return bios->data[addr];
+	return 0x00;
+}
+
+static u16
+shadow_rd16(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	if (shadow_fetch(bios, addr + 2))
+		return get_unaligned_le16(&bios->data[addr]);
+	return 0x0000;
+}
+
+static u32
+shadow_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nvkm_bios *bios = (void *)object;
+	if (shadow_fetch(bios, addr + 4))
+		return get_unaligned_le32(&bios->data[addr]);
+	return 0x00000000;
+}
+
+static struct nvkm_oclass
+shadow_class = {
+	.handle = NV_SUBDEV(VBIOS, 0x00),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.rd08 = shadow_rd08,
+		.rd16 = shadow_rd16,
+		.rd32 = shadow_rd32,
+	},
+};
+
+static int
+shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd)
+{
+	struct nvbios_image image;
+	int score = 1;
+
+	if (!nvbios_image(bios, idx, &image)) {
+		nv_debug(bios, "image %d invalid\n", idx);
+		return 0;
+	}
+	nv_debug(bios, "%08x: type %02x, %d bytes\n",
+		 image.base, image.type, image.size);
+
+	if (!shadow_fetch(bios, image.size)) {
+		nv_debug(bios, "%08x: fetch failed\n", image.base);
+		return 0;
+	}
+
+	switch (image.type) {
+	case 0x00:
+		if (nvbios_checksum(&bios->data[image.base], image.size)) {
+			nv_debug(bios, "%08x: checksum failed\n", image.base);
+			if (mthd->func->rw)
+				score += 1;
+			score += 1;
+		} else {
+			score += 3;
+		}
+		break;
+	default:
+		score += 3;
+		break;
+	}
+
+	if (!image.last)
+		score += shadow_image(bios, idx + 1, mthd);
+	return score;
+}
+
+static int
+shadow_score(struct nvkm_bios *bios, struct shadow *mthd)
+{
+	struct nvkm_oclass *oclass = nv_object(bios)->oclass;
+	int score;
+	nv_object(bios)->oclass = &mthd->base;
+	score = shadow_image(bios, 0, mthd);
+	nv_object(bios)->oclass = oclass;
+	return score;
+
+}
+
+static int
+shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name)
+{
+	const struct nvbios_source *func = mthd->func;
+	if (func->name) {
+		nv_debug(bios, "trying %s...\n", name ? name : func->name);
+		if (func->init) {
+			mthd->data = func->init(bios, name);
+			if (IS_ERR(mthd->data)) {
+				mthd->data = NULL;
+				return 0;
+			}
+		}
+		mthd->score = shadow_score(bios, mthd);
+		if (func->fini)
+			func->fini(mthd->data);
+		nv_debug(bios, "scored %d\n", mthd->score);
+		mthd->data = bios->data;
+		mthd->size = bios->size;
+		bios->data  = NULL;
+		bios->size  = 0;
+	}
+	return mthd->score;
+}
+
+static u32
+shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	const struct firmware *fw = data;
+	if (offset + length <= fw->size) {
+		memcpy(bios->data + offset, fw->data + offset, length);
+		return length;
+	}
+	return 0;
+}
+
+static void *
+shadow_fw_init(struct nvkm_bios *bios, const char *name)
+{
+	struct device *dev = &nv_device(bios)->pdev->dev;
+	const struct firmware *fw;
+	int ret = request_firmware(&fw, name, dev);
+	if (ret)
+		return ERR_PTR(-ENOENT);
+	return (void *)fw;
+}
+
+static const struct nvbios_source
+shadow_fw = {
+	.name = "firmware",
+	.init = shadow_fw_init,
+	.fini = (void(*)(void *))release_firmware,
+	.read = shadow_fw_read,
+	.rw = false,
+};
+
+int
+nvbios_shadow(struct nvkm_bios *bios)
+{
+	struct shadow mthds[] = {
+		{ shadow_class, 0, &nvbios_of },
+		{ shadow_class, 0, &nvbios_ramin },
+		{ shadow_class, 0, &nvbios_rom },
+		{ shadow_class, 0, &nvbios_acpi_fast },
+		{ shadow_class, 4, &nvbios_acpi_slow },
+		{ shadow_class, 1, &nvbios_pcirom },
+		{ shadow_class, 1, &nvbios_platform },
+		{ shadow_class }
+	}, *mthd = mthds, *best = NULL;
+	const char *optarg;
+	char *source;
+	int optlen;
+
+	/* handle user-specified bios source */
+	optarg = nvkm_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
+	source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
+	if (source) {
+		/* try to match one of the built-in methods */
+		for (mthd = mthds; mthd->func; mthd++) {
+			if (mthd->func->name &&
+			    !strcasecmp(source, mthd->func->name)) {
+				best = mthd;
+				if (shadow_method(bios, mthd, NULL))
+					break;
+			}
+		}
+
+		/* otherwise, attempt to load as firmware */
+		if (!best && (best = mthd)) {
+			mthd->func = &shadow_fw;
+			shadow_method(bios, mthd, source);
+			mthd->func = NULL;
+		}
+
+		if (!best->score) {
+			nv_error(bios, "%s invalid\n", source);
+			kfree(source);
+			source = NULL;
+		}
+	}
+
+	/* scan all potential bios sources, looking for best image */
+	if (!best || !best->score) {
+		for (mthd = mthds, best = mthd; mthd->func; mthd++) {
+			if (!mthd->skip || best->score < mthd->skip) {
+				if (shadow_method(bios, mthd, NULL)) {
+					if (mthd->score > best->score)
+						best = mthd;
+				}
+			}
+		}
+	}
+
+	/* cleanup the ones we didn't use */
+	for (mthd = mthds; mthd->func; mthd++) {
+		if (mthd != best)
+			kfree(mthd->data);
+	}
+
+	if (!best->score) {
+		nv_fatal(bios, "unable to locate usable image\n");
+		return -EINVAL;
+	}
+
+	nv_info(bios, "using image from %s\n", best->func ?
+		best->func->name : source);
+	bios->data = best->data;
+	bios->size = best->size;
+	kfree(source);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
new file mode 100644
index 0000000..1fbd93b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Red Hat 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 "priv.h"
+
+#include <core/device.h>
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
+int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
+bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
+#else
+static inline bool
+nouveau_acpi_rom_supported(struct pci_dev *pdev)
+{
+	return false;
+}
+
+static inline int
+nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
+{
+	return -EINVAL;
+}
+#endif
+
+/* This version of the shadow function disobeys the ACPI spec and tries
+ * to fetch in units of more than 4KiB at a time.  This is a LOT faster
+ * on some systems, such as Lenovo W530.
+ */
+static u32
+acpi_read_fast(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	u32 limit = (offset + length + 0xfff) & ~0xfff;
+	u32 start = offset & ~0x00000fff;
+	u32 fetch = limit - start;
+
+	if (nvbios_extend(bios, limit) > 0) {
+		int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
+		if (ret == fetch)
+			return fetch;
+	}
+
+	return 0;
+}
+
+/* Other systems, such as the one in fdo#55948, will report a success
+ * but only return 4KiB of data.  The common bios fetching logic will
+ * detect an invalid image, and fall back to this version of the read
+ * function.
+ */
+static u32
+acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	u32 limit = (offset + length + 0xfff) & ~0xfff;
+	u32 start = offset & ~0xfff;
+	u32 fetch = 0;
+
+	if (nvbios_extend(bios, limit) > 0) {
+		while (start + fetch < limit) {
+			int ret = nouveau_acpi_get_bios_chunk(bios->data,
+							      start + fetch,
+							      0x1000);
+			if (ret != 0x1000)
+				break;
+			fetch += 0x1000;
+		}
+	}
+
+	return fetch;
+}
+
+static void *
+acpi_init(struct nvkm_bios *bios, const char *name)
+{
+	if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
+		return ERR_PTR(-ENODEV);
+	return NULL;
+}
+
+const struct nvbios_source
+nvbios_acpi_fast = {
+	.name = "ACPI",
+	.init = acpi_init,
+	.read = acpi_read_fast,
+	.rw = false,
+};
+
+const struct nvbios_source
+nvbios_acpi_slow = {
+	.name = "ACPI",
+	.init = acpi_init,
+	.read = acpi_read_slow,
+	.rw = false,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
new file mode 100644
index 0000000..4c19a7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Red Hat 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 "priv.h"
+
+#include <core/device.h>
+
+#if defined(__powerpc__)
+struct priv {
+	const void __iomem *data;
+	int size;
+};
+
+static u32
+of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	struct priv *priv = data;
+	if (offset + length <= priv->size) {
+		memcpy_fromio(bios->data + offset, priv->data + offset, length);
+		return length;
+	}
+	return 0;
+}
+
+static void *
+of_init(struct nvkm_bios *bios, const char *name)
+{
+	struct pci_dev *pdev = nv_device(bios)->pdev;
+	struct device_node *dn;
+	struct priv *priv;
+	if (!(dn = pci_device_to_OF_node(pdev)))
+		return ERR_PTR(-ENODEV);
+	if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
+		return ERR_PTR(-ENOMEM);
+	if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
+		return priv;
+	kfree(priv);
+	return ERR_PTR(-EINVAL);
+}
+
+const struct nvbios_source
+nvbios_of = {
+	.name = "OpenFirmware",
+	.init = of_init,
+	.fini = (void(*)(void *))kfree,
+	.read = of_read,
+	.rw = false,
+};
+#else
+const struct nvbios_source
+nvbios_of = {
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
new file mode 100644
index 0000000..1b04548
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat 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 "priv.h"
+
+#include <core/device.h>
+
+struct priv {
+	struct pci_dev *pdev;
+	void __iomem *rom;
+	size_t size;
+};
+
+static u32
+pcirom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	struct priv *priv = data;
+	if (offset + length <= priv->size) {
+		memcpy_fromio(bios->data + offset, priv->rom + offset, length);
+		return length;
+	}
+	return 0;
+}
+
+static void
+pcirom_fini(void *data)
+{
+	struct priv *priv = data;
+	pci_unmap_rom(priv->pdev, priv->rom);
+	pci_disable_rom(priv->pdev);
+	kfree(priv);
+}
+
+static void *
+pcirom_init(struct nvkm_bios *bios, const char *name)
+{
+	struct pci_dev *pdev = nv_device(bios)->pdev;
+	struct priv *priv = NULL;
+	int ret;
+
+	if (!(ret = pci_enable_rom(pdev))) {
+		if (ret = -ENOMEM,
+		    (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+			if (ret = -EFAULT,
+			    (priv->rom = pci_map_rom(pdev, &priv->size))) {
+				priv->pdev = pdev;
+				return priv;
+			}
+			kfree(priv);
+		}
+		pci_disable_rom(pdev);
+	}
+
+	return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_pcirom = {
+	.name = "PCIROM",
+	.init = pcirom_init,
+	.fini = pcirom_fini,
+	.read = pcirom_read,
+	.rw = true,
+};
+
+static void *
+platform_init(struct nvkm_bios *bios, const char *name)
+{
+	struct pci_dev *pdev = nv_device(bios)->pdev;
+	struct priv *priv;
+	int ret = -ENOMEM;
+
+	if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+		if (ret = -ENODEV,
+		    (priv->rom = pci_platform_rom(pdev, &priv->size)))
+			return priv;
+		kfree(priv);
+	}
+
+	return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_platform = {
+	.name = "PLATFORM",
+	.init = platform_init,
+	.fini = (void(*)(void *))kfree,
+	.read = pcirom_read,
+	.rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c
new file mode 100644
index 0000000..abe8ae4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Red Hat 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 "priv.h"
+
+#include <core/device.h>
+
+struct priv {
+	struct nvkm_bios *bios;
+	u32 bar0;
+};
+
+static u32
+pramin_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	u32 i;
+	if (offset + length <= 0x00100000) {
+		for (i = offset; i < offset + length; i += 4)
+			*(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
+		return length;
+	}
+	return 0;
+}
+
+static void
+pramin_fini(void *data)
+{
+	struct priv *priv = data;
+	if (priv) {
+		nv_wr32(priv->bios, 0x001700, priv->bar0);
+		kfree(priv);
+	}
+}
+
+static void *
+pramin_init(struct nvkm_bios *bios, const char *name)
+{
+	struct priv *priv = NULL;
+	u64 addr = 0;
+
+	/* PRAMIN always potentially available prior to nv50 */
+	if (nv_device(bios)->card_type < NV_50)
+		return NULL;
+
+	/* we can't get the bios image pointer without PDISP */
+	if (nv_device(bios)->card_type >= GM100)
+		addr = nv_rd32(bios, 0x021c04);
+	else
+	if (nv_device(bios)->card_type >= NV_C0)
+		addr = nv_rd32(bios, 0x022500);
+	if (addr & 0x00000001) {
+		nv_debug(bios, "... display disabled\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	/* check that the window is enabled and in vram, particularly
+	 * important as we don't want to be touching vram on an
+	 * uninitialised board
+	 */
+	addr = nv_rd32(bios, 0x619f04);
+	if (!(addr & 0x00000008)) {
+		nv_debug(bios, "... not enabled\n");
+		return ERR_PTR(-ENODEV);
+	}
+	if ( (addr & 0x00000003) != 1) {
+		nv_debug(bios, "... not in vram\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	/* some alternate method inherited from xf86-video-nv... */
+	addr = (addr & 0xffffff00) << 8;
+	if (!addr) {
+		addr  = (u64)nv_rd32(bios, 0x001700) << 16;
+		addr += 0xf0000;
+	}
+
+	/* modify bar0 PRAMIN window to cover the bios image */
+	if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+		nv_error(bios, "... out of memory\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	priv->bios = bios;
+	priv->bar0 = nv_rd32(bios, 0x001700);
+	nv_wr32(bios, 0x001700, addr >> 16);
+	return priv;
+}
+
+const struct nvbios_source
+nvbios_ramin = {
+	.name = "PRAMIN",
+	.init = pramin_init,
+	.fini = pramin_fini,
+	.read = pramin_read,
+	.rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c
new file mode 100644
index 0000000..6ec3b23
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Red Hat 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 "priv.h"
+
+#include <core/device.h>
+
+static u32
+prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+	u32 i;
+	if (offset + length <= 0x00100000) {
+		for (i = offset; i < offset + length; i += 4)
+			*(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
+		return length;
+	}
+	return 0;
+}
+
+static void
+prom_fini(void *data)
+{
+	struct nvkm_bios *bios = data;
+	if (nv_device(bios)->card_type < NV_50)
+		nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
+	else
+		nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
+}
+
+static void *
+prom_init(struct nvkm_bios *bios, const char *name)
+{
+	if (nv_device(bios)->card_type < NV_50) {
+		if (nv_device(bios)->card_type == NV_40 &&
+		    nv_device(bios)->chipset >= 0x4c)
+			return ERR_PTR(-ENODEV);
+		nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
+	} else {
+		nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
+	}
+	return bios;
+}
+
+const struct nvbios_source
+nvbios_rom = {
+	.name = "PROM",
+	.init = prom_init,
+	.fini = prom_fini,
+	.read = prom_read,
+	.rw = false,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c
new file mode 100644
index 0000000..249ff6d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/therm.h>
+
+#include <core/device.h>
+
+static u16
+therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
+{
+	struct bit_entry bit_P;
+	u16 therm = 0;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 1)
+			therm = nv_ro16(bios, bit_P.offset + 12);
+		else if (bit_P.version == 2)
+			therm = nv_ro16(bios, bit_P.offset + 16);
+		else
+			nv_error(bios,
+				"unknown offset for thermal in BIT P %d\n",
+				bit_P.version);
+	}
+
+	/* exit now if we haven't found the thermal table */
+	if (!therm)
+		return 0x0000;
+
+	*ver = nv_ro08(bios, therm + 0);
+	*hdr = nv_ro08(bios, therm + 1);
+	*len = nv_ro08(bios, therm + 2);
+	*cnt = nv_ro08(bios, therm + 3);
+	return therm + nv_ro08(bios, therm + 1);
+}
+
+static u16
+nvbios_therm_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+	u8 hdr, cnt;
+	u16 therm = therm_table(bios, ver, &hdr, len, &cnt);
+	if (therm && idx < cnt)
+		return therm + idx * *len;
+	return 0x0000;
+}
+
+int
+nvbios_therm_sensor_parse(struct nvkm_bios *bios,
+			  enum nvbios_therm_domain domain,
+			  struct nvbios_therm_sensor *sensor)
+{
+	s8 thrs_section, sensor_section, offset;
+	u8 ver, len, i;
+	u16 entry;
+
+	/* we only support the core domain for now */
+	if (domain != NVBIOS_THERM_DOMAIN_CORE)
+		return -EINVAL;
+
+	/* Read the entries from the table */
+	thrs_section = 0;
+	sensor_section = -1;
+	i = 0;
+	while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
+		s16 value = nv_ro16(bios, entry + 1);
+
+		switch (nv_ro08(bios, entry + 0)) {
+		case 0x0:
+			thrs_section = value;
+			if (value > 0)
+				return 0; /* we do not try to support ambient */
+			break;
+		case 0x01:
+			sensor_section++;
+			if (sensor_section == 0) {
+				offset = ((s8) nv_ro08(bios, entry + 2)) / 2;
+				sensor->offset_constant = offset;
+			}
+			break;
+
+		case 0x04:
+			if (thrs_section == 0) {
+				sensor->thrs_critical.temp = (value & 0xff0) >> 4;
+				sensor->thrs_critical.hysteresis = value & 0xf;
+			}
+			break;
+
+		case 0x07:
+			if (thrs_section == 0) {
+				sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
+				sensor->thrs_down_clock.hysteresis = value & 0xf;
+			}
+			break;
+
+		case 0x08:
+			if (thrs_section == 0) {
+				sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
+				sensor->thrs_fan_boost.hysteresis = value & 0xf;
+			}
+			break;
+
+		case 0x10:
+			if (sensor_section == 0)
+				sensor->offset_num = value;
+			break;
+
+		case 0x11:
+			if (sensor_section == 0)
+				sensor->offset_den = value;
+			break;
+
+		case 0x12:
+			if (sensor_section == 0)
+				sensor->slope_mult = value;
+			break;
+
+		case 0x13:
+			if (sensor_section == 0)
+				sensor->slope_div = value;
+			break;
+		case 0x32:
+			if (thrs_section == 0) {
+				sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
+				sensor->thrs_shutdown.hysteresis = value & 0xf;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int
+nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
+{
+	struct nvbios_therm_trip_point *cur_trip = NULL;
+	u8 ver, len, i;
+	u16 entry;
+
+	uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
+				75, 0, 85, 0, 100, 0, 100, 0 };
+
+	i = 0;
+	fan->nr_fan_trip = 0;
+	fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
+	while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
+		s16 value = nv_ro16(bios, entry + 1);
+
+		switch (nv_ro08(bios, entry + 0)) {
+		case 0x22:
+			fan->min_duty = value & 0xff;
+			fan->max_duty = (value & 0xff00) >> 8;
+			break;
+		case 0x24:
+			fan->nr_fan_trip++;
+			if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
+				fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
+			cur_trip = &fan->trip[fan->nr_fan_trip - 1];
+			cur_trip->hysteresis = value & 0xf;
+			cur_trip->temp = (value & 0xff0) >> 4;
+			cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
+			break;
+		case 0x25:
+			cur_trip = &fan->trip[fan->nr_fan_trip - 1];
+			cur_trip->fan_duty = value;
+			break;
+		case 0x26:
+			if (!fan->pwm_freq)
+				fan->pwm_freq = value;
+			break;
+		case 0x3b:
+			fan->bump_period = value;
+			break;
+		case 0x3c:
+			fan->slow_down_period = value;
+			break;
+		case 0x46:
+			if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
+				fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
+			fan->linear_min_temp = nv_ro08(bios, entry + 1);
+			fan->linear_max_temp = nv_ro08(bios, entry + 2);
+			break;
+		}
+	}
+
+	/* starting from fermi, fan management is always linear */
+	if (nv_device(bios)->card_type >= NV_C0 &&
+		fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
+		fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c
new file mode 100644
index 0000000..763fd29
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/timing.h>
+
+u16
+nvbios_timingTe(struct nvkm_bios *bios,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+	struct bit_entry bit_P;
+	u16 timing = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 1)
+			timing = nv_ro16(bios, bit_P.offset + 4);
+		else
+		if (bit_P.version == 2)
+			timing = nv_ro16(bios, bit_P.offset + 8);
+
+		if (timing) {
+			*ver = nv_ro08(bios, timing + 0);
+			switch (*ver) {
+			case 0x10:
+				*hdr = nv_ro08(bios, timing + 1);
+				*cnt = nv_ro08(bios, timing + 2);
+				*len = nv_ro08(bios, timing + 3);
+				*snr = 0;
+				*ssz = 0;
+				return timing;
+			case 0x20:
+				*hdr = nv_ro08(bios, timing + 1);
+				*cnt = nv_ro08(bios, timing + 5);
+				*len = nv_ro08(bios, timing + 2);
+				*snr = nv_ro08(bios, timing + 4);
+				*ssz = nv_ro08(bios, timing + 3);
+				return timing;
+			default:
+				break;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_timingEe(struct nvkm_bios *bios, int idx,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u8  snr, ssz;
+	u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+	if (timing && idx < *cnt) {
+		timing += *hdr + idx * (*len + (snr * ssz));
+		*hdr = *len;
+		*cnt = snr;
+		*len = ssz;
+		return timing;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_timingEp(struct nvkm_bios *bios, int idx,
+		u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p)
+{
+	u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
+	p->timing_ver = *ver;
+	p->timing_hdr = *hdr;
+	switch (!!data * *ver) {
+	case 0x10:
+		p->timing_10_WR    = nv_ro08(bios, data + 0x00);
+		p->timing_10_WTR   = nv_ro08(bios, data + 0x01);
+		p->timing_10_CL    = nv_ro08(bios, data + 0x02);
+		p->timing_10_RC    = nv_ro08(bios, data + 0x03);
+		p->timing_10_RFC   = nv_ro08(bios, data + 0x05);
+		p->timing_10_RAS   = nv_ro08(bios, data + 0x07);
+		p->timing_10_RP    = nv_ro08(bios, data + 0x09);
+		p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
+		p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
+		p->timing_10_RRD   = nv_ro08(bios, data + 0x0c);
+		p->timing_10_13    = nv_ro08(bios, data + 0x0d);
+		p->timing_10_ODT   = nv_ro08(bios, data + 0x0e) & 0x07;
+
+		p->timing_10_24  = 0xff;
+		p->timing_10_21  = 0;
+		p->timing_10_20  = 0;
+		p->timing_10_CWL = 0;
+		p->timing_10_18  = 0;
+		p->timing_10_16  = 0;
+
+		switch (min_t(u8, *hdr, 25)) {
+		case 25:
+			p->timing_10_24  = nv_ro08(bios, data + 0x18);
+		case 24:
+		case 23:
+		case 22:
+			p->timing_10_21  = nv_ro08(bios, data + 0x15);
+		case 21:
+			p->timing_10_20  = nv_ro08(bios, data + 0x14);
+		case 20:
+			p->timing_10_CWL = nv_ro08(bios, data + 0x13);
+		case 19:
+			p->timing_10_18  = nv_ro08(bios, data + 0x12);
+		case 18:
+		case 17:
+			p->timing_10_16  = nv_ro08(bios, data + 0x10);
+		}
+
+		break;
+	case 0x20:
+		p->timing[0] = nv_ro32(bios, data + 0x00);
+		p->timing[1] = nv_ro32(bios, data + 0x04);
+		p->timing[2] = nv_ro32(bios, data + 0x08);
+		p->timing[3] = nv_ro32(bios, data + 0x0c);
+		p->timing[4] = nv_ro32(bios, data + 0x10);
+		p->timing[5] = nv_ro32(bios, data + 0x14);
+		p->timing[6] = nv_ro32(bios, data + 0x18);
+		p->timing[7] = nv_ro32(bios, data + 0x1c);
+		p->timing[8] = nv_ro32(bios, data + 0x20);
+		p->timing[9] = nv_ro32(bios, data + 0x24);
+		p->timing[10] = nv_ro32(bios, data + 0x28);
+		p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0;
+		p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4;
+		p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6;
+		p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0;
+		temp = nv_ro16(bios, data + 0x2c);
+		p->timing_20_2c_003f = (temp & 0x003f) >> 0;
+		p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6;
+		p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0;
+		p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3;
+		temp = nv_ro16(bios, data + 0x31);
+		p->timing_20_31_0007 = (temp & 0x0007) >> 0;
+		p->timing_20_31_0078 = (temp & 0x0078) >> 3;
+		p->timing_20_31_0780 = (temp & 0x0780) >> 7;
+		p->timing_20_31_0800 = (temp & 0x0800) >> 11;
+		p->timing_20_31_7000 = (temp & 0x7000) >> 12;
+		p->timing_20_31_8000 = (temp & 0x8000) >> 15;
+		break;
+	default:
+		data = 0;
+		break;
+	}
+	return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
new file mode 100644
index 0000000..e95b69f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/vmap.h>
+
+u16
+nvbios_vmap_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_P;
+	u16 vmap = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2) {
+			vmap = nv_ro16(bios, bit_P.offset + 0x20);
+			if (vmap) {
+				*ver = nv_ro08(bios, vmap + 0);
+				switch (*ver) {
+				case 0x10:
+				case 0x20:
+					*hdr = nv_ro08(bios, vmap + 1);
+					*cnt = nv_ro08(bios, vmap + 3);
+					*len = nv_ro08(bios, vmap + 2);
+					return vmap;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		  struct nvbios_vmap *info)
+{
+	u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!vmap * *ver) {
+	case 0x10:
+	case 0x20:
+		break;
+	}
+	return vmap;
+}
+
+u16
+nvbios_vmap_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt;
+	u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len);
+	if (vmap && idx < cnt) {
+		vmap = vmap + hdr + (idx * *len);
+		return vmap;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+			struct nvbios_vmap_entry *info)
+{
+	u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!vmap * *ver) {
+	case 0x10:
+		info->link   = 0xff;
+		info->min    = nv_ro32(bios, vmap + 0x00);
+		info->max    = nv_ro32(bios, vmap + 0x04);
+		info->arg[0] = nv_ro32(bios, vmap + 0x08);
+		info->arg[1] = nv_ro32(bios, vmap + 0x0c);
+		info->arg[2] = nv_ro32(bios, vmap + 0x10);
+		break;
+	case 0x20:
+		info->unk0   = nv_ro08(bios, vmap + 0x00);
+		info->link   = nv_ro08(bios, vmap + 0x01);
+		info->min    = nv_ro32(bios, vmap + 0x02);
+		info->max    = nv_ro32(bios, vmap + 0x06);
+		info->arg[0] = nv_ro32(bios, vmap + 0x0a);
+		info->arg[1] = nv_ro32(bios, vmap + 0x0e);
+		info->arg[2] = nv_ro32(bios, vmap + 0x12);
+		info->arg[3] = nv_ro32(bios, vmap + 0x16);
+		info->arg[4] = nv_ro32(bios, vmap + 0x1a);
+		info->arg[5] = nv_ro32(bios, vmap + 0x1e);
+		break;
+	}
+	return vmap;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
new file mode 100644
index 0000000..8454ab7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/volt.h>
+
+u16
+nvbios_volt_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	struct bit_entry bit_P;
+	u16 volt = 0x0000;
+
+	if (!bit_entry(bios, 'P', &bit_P)) {
+		if (bit_P.version == 2)
+			volt = nv_ro16(bios, bit_P.offset + 0x0c);
+		else
+		if (bit_P.version == 1)
+			volt = nv_ro16(bios, bit_P.offset + 0x10);
+
+		if (volt) {
+			*ver = nv_ro08(bios, volt + 0);
+			switch (*ver) {
+			case 0x12:
+				*hdr = 5;
+				*cnt = nv_ro08(bios, volt + 2);
+				*len = nv_ro08(bios, volt + 1);
+				return volt;
+			case 0x20:
+				*hdr = nv_ro08(bios, volt + 1);
+				*cnt = nv_ro08(bios, volt + 2);
+				*len = nv_ro08(bios, volt + 3);
+				return volt;
+			case 0x30:
+			case 0x40:
+			case 0x50:
+				*hdr = nv_ro08(bios, volt + 1);
+				*cnt = nv_ro08(bios, volt + 3);
+				*len = nv_ro08(bios, volt + 2);
+				return volt;
+			}
+		}
+	}
+
+	return 0x0000;
+}
+
+u16
+nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		  struct nvbios_volt *info)
+{
+	u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!volt * *ver) {
+	case 0x12:
+		info->vidmask = nv_ro08(bios, volt + 0x04);
+		break;
+	case 0x20:
+		info->vidmask = nv_ro08(bios, volt + 0x05);
+		break;
+	case 0x30:
+		info->vidmask = nv_ro08(bios, volt + 0x04);
+		break;
+	case 0x40:
+		info->base    = nv_ro32(bios, volt + 0x04);
+		info->step    = nv_ro16(bios, volt + 0x08);
+		info->vidmask = nv_ro08(bios, volt + 0x0b);
+		/*XXX*/
+		info->min     = 0;
+		info->max     = info->base;
+		break;
+	case 0x50:
+		info->vidmask = nv_ro08(bios, volt + 0x06);
+		info->min     = nv_ro32(bios, volt + 0x0a);
+		info->max     = nv_ro32(bios, volt + 0x0e);
+		info->base    = nv_ro32(bios, volt + 0x12) & 0x00ffffff;
+		info->step    = nv_ro16(bios, volt + 0x16);
+		break;
+	}
+	return volt;
+}
+
+u16
+nvbios_volt_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+	u8  hdr, cnt;
+	u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len);
+	if (volt && idx < cnt) {
+		volt = volt + hdr + (idx * *len);
+		return volt;
+	}
+	return 0x0000;
+}
+
+u16
+nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+			struct nvbios_volt_entry *info)
+{
+	u16 volt = nvbios_volt_entry(bios, idx, ver, len);
+	memset(info, 0x00, sizeof(*info));
+	switch (!!volt * *ver) {
+	case 0x12:
+	case 0x20:
+		info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+		info->vid     = nv_ro08(bios, volt + 0x01);
+		break;
+	case 0x30:
+		info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+		info->vid     = nv_ro08(bios, volt + 0x01) >> 2;
+		break;
+	case 0x40:
+	case 0x50:
+		break;
+	}
+	return volt;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c
new file mode 100644
index 0000000..63a5e1b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/xpio.h>
+
+static u16
+dcb_xpiod_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len);
+	if (data && *ver >= 0x40 && *hdr >= 0x06) {
+		u16 xpio = nv_ro16(bios, data + 0x04);
+		if (xpio) {
+			*ver = nv_ro08(bios, data + 0x00);
+			*hdr = nv_ro08(bios, data + 0x01);
+			*cnt = nv_ro08(bios, data + 0x02);
+			*len = nv_ro08(bios, data + 0x03);
+			return xpio;
+		}
+	}
+	return 0x0000;
+}
+
+u16
+dcb_xpio_table(struct nvkm_bios *bios, u8 idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+	u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len);
+	if (data && idx < *cnt) {
+		u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len));
+		if (xpio) {
+			*ver = nv_ro08(bios, data + 0x00);
+			*hdr = nv_ro08(bios, data + 0x01);
+			*cnt = nv_ro08(bios, data + 0x02);
+			*len = nv_ro08(bios, data + 0x03);
+			return xpio;
+		}
+	}
+	return 0x0000;
+}
+
+u16
+dcb_xpio_parse(struct nvkm_bios *bios, u8 idx,
+	       u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *info)
+{
+	u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len);
+	if (data && *len >= 6) {
+		info->type = nv_ro08(bios, data + 0x04);
+		info->addr = nv_ro08(bios, data + 0x05);
+		info->flags = nv_ro08(bios, data + 0x06);
+	}
+	return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild
new file mode 100644
index 0000000..83d80b1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/bus/hwsq.o
+nvkm-y += nvkm/subdev/bus/nv04.o
+nvkm-y += nvkm/subdev/bus/nv31.o
+nvkm-y += nvkm/subdev/bus/nv50.o
+nvkm-y += nvkm/subdev/bus/g94.o
+nvkm-y += nvkm/subdev/bus/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c
new file mode 100644
index 0000000..cbe699e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/timer.h>
+
+static int
+g94_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size)
+{
+	struct nv50_bus_priv *priv = (void *)pbus;
+	int i;
+
+	nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+	nv_wr32(pbus, 0x001304, 0x00000000);
+	nv_wr32(pbus, 0x001318, 0x00000000);
+	for (i = 0; i < size; i++)
+		nv_wr32(priv, 0x080000 + (i * 4), data[i]);
+	nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+	nv_wr32(pbus, 0x00130c, 0x00000001);
+
+	return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+struct nvkm_oclass *
+g94_bus_oclass = &(struct nv04_bus_impl) {
+	.base.handle = NV_SUBDEV(BUS, 0x94),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_bus_ctor,
+		.dtor = _nvkm_bus_dtor,
+		.init = nv50_bus_init,
+		.fini = _nvkm_bus_fini,
+	},
+	.intr = nv50_bus_intr,
+	.hwsq_exec = g94_bus_hwsq_exec,
+	.hwsq_size = 128,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c
new file mode 100644
index 0000000..ebc63ba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+gf100_bus_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_bus *pbus = nvkm_bus(subdev);
+	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+	if (stat & 0x0000000e) {
+		u32 addr = nv_rd32(pbus, 0x009084);
+		u32 data = nv_rd32(pbus, 0x009088);
+
+		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n",
+			 (addr & 0x00000002) ? "write" : "read", data,
+			 (addr & 0x00fffffc),
+			 (stat & 0x00000002) ? "!ENGINE " : "",
+			 (stat & 0x00000004) ? "IBUS " : "",
+			 (stat & 0x00000008) ? "TIMEOUT " : "");
+
+		nv_wr32(pbus, 0x009084, 0x00000000);
+		nv_wr32(pbus, 0x001100, (stat & 0x0000000e));
+		stat &= ~0x0000000e;
+	}
+
+	if (stat) {
+		nv_error(pbus, "unknown intr 0x%08x\n", stat);
+		nv_mask(pbus, 0x001140, stat, 0x00000000);
+	}
+}
+
+static int
+gf100_bus_init(struct nvkm_object *object)
+{
+	struct nv04_bus_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_bus_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x001100, 0xffffffff);
+	nv_wr32(priv, 0x001140, 0x0000000e);
+	return 0;
+}
+
+struct nvkm_oclass *
+gf100_bus_oclass = &(struct nv04_bus_impl) {
+	.base.handle = NV_SUBDEV(BUS, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_bus_ctor,
+		.dtor = _nvkm_bus_dtor,
+		.init = gf100_bus_init,
+		.fini = _nvkm_bus_fini,
+	},
+	.intr = gf100_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
new file mode 100644
index 0000000..b8853bf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bus.h>
+
+struct nvkm_hwsq {
+	struct nvkm_bus *pbus;
+	u32 addr;
+	u32 data;
+	struct {
+		u8 data[512];
+		u8 size;
+	} c;
+};
+
+static void
+hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[])
+{
+	memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
+	hwsq->c.size += size;
+}
+
+int
+nvkm_hwsq_init(struct nvkm_bus *pbus, struct nvkm_hwsq **phwsq)
+{
+	struct nvkm_hwsq *hwsq;
+
+	hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
+	if (hwsq) {
+		hwsq->pbus = pbus;
+		hwsq->addr = ~0;
+		hwsq->data = ~0;
+		memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
+		hwsq->c.size = 0;
+	}
+
+	return hwsq ? 0 : -ENOMEM;
+}
+
+int
+nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec)
+{
+	struct nvkm_hwsq *hwsq = *phwsq;
+	int ret = 0, i;
+	if (hwsq) {
+		struct nvkm_bus *pbus = hwsq->pbus;
+		hwsq->c.size = (hwsq->c.size + 4) / 4;
+		if (hwsq->c.size <= pbus->hwsq_size) {
+			if (exec)
+				ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data,
+						      hwsq->c.size);
+			if (ret)
+				nv_error(pbus, "hwsq exec failed: %d\n", ret);
+		} else {
+			nv_error(pbus, "hwsq ucode too large\n");
+			ret = -ENOSPC;
+		}
+
+		for (i = 0; ret && i < hwsq->c.size; i++)
+			nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]);
+
+		*phwsq = NULL;
+		kfree(hwsq);
+	}
+	return ret;
+}
+
+void
+nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data)
+{
+	nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data);
+
+	if (hwsq->data != data) {
+		if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
+			hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
+						  data >> 16, data >> 24 });
+		} else {
+			hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
+		}
+	}
+
+	if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
+		hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
+					  addr >> 16, addr >> 24 });
+	} else {
+		hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
+	}
+
+	hwsq->addr = addr;
+	hwsq->data = data;
+}
+
+void
+nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data)
+{
+	nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data);
+	flag += 0x80;
+	if (data >= 0)
+		flag += 0x20;
+	if (data >= 1)
+		flag += 0x20;
+	hwsq_cmd(hwsq, 1, (u8[]){ flag });
+}
+
+void
+nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data)
+{
+	nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data);
+	hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
+}
+
+void
+nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec)
+{
+	u8 shift = 0, usec = nsec / 1000;
+	while (usec & ~3) {
+		usec >>= 2;
+		shift++;
+	}
+
+	nv_debug(hwsq->pbus, "    DELAY = %d ns\n", nsec);
+	hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
new file mode 100644
index 0000000..3394a5e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
@@ -0,0 +1,111 @@
+#ifndef __NVKM_BUS_HWSQ_H__
+#define __NVKM_BUS_HWSQ_H__
+#include <subdev/bus.h>
+
+struct hwsq {
+	struct nvkm_subdev *subdev;
+	struct nvkm_hwsq *hwsq;
+	int sequence;
+};
+
+struct hwsq_reg {
+	int sequence;
+	bool force;
+	u32 addr[2];
+	u32 data;
+};
+
+static inline struct hwsq_reg
+hwsq_reg2(u32 addr1, u32 addr2)
+{
+	return (struct hwsq_reg) {
+		.sequence = 0,
+		.force = 0,
+		.addr = { addr1, addr2 },
+		.data = 0xdeadbeef,
+	};
+}
+
+static inline struct hwsq_reg
+hwsq_reg(u32 addr)
+{
+	return hwsq_reg2(addr, addr);
+}
+
+static inline int
+hwsq_init(struct hwsq *ram, struct nvkm_subdev *subdev)
+{
+	struct nvkm_bus *pbus = nvkm_bus(subdev);
+	int ret;
+
+	ret = nvkm_hwsq_init(pbus, &ram->hwsq);
+	if (ret)
+		return ret;
+
+	ram->sequence++;
+	ram->subdev = subdev;
+	return 0;
+}
+
+static inline int
+hwsq_exec(struct hwsq *ram, bool exec)
+{
+	int ret = 0;
+	if (ram->subdev) {
+		ret = nvkm_hwsq_fini(&ram->hwsq, exec);
+		ram->subdev = NULL;
+	}
+	return ret;
+}
+
+static inline u32
+hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
+{
+	if (reg->sequence != ram->sequence)
+		reg->data = nv_rd32(ram->subdev, reg->addr[0]);
+	return reg->data;
+}
+
+static inline void
+hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
+{
+	reg->sequence = ram->sequence;
+	reg->data = data;
+	if (reg->addr[0] != reg->addr[1])
+		nvkm_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
+	nvkm_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
+}
+
+static inline void
+hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg)
+{
+	reg->force = true;
+}
+
+static inline u32
+hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data)
+{
+	u32 temp = hwsq_rd32(ram, reg);
+	if (temp != ((temp & ~mask) | data) || reg->force)
+		hwsq_wr32(ram, reg, (temp & ~mask) | data);
+	return temp;
+}
+
+static inline void
+hwsq_setf(struct hwsq *ram, u8 flag, int data)
+{
+	nvkm_hwsq_setf(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
+{
+	nvkm_hwsq_wait(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_nsec(struct hwsq *ram, u32 nsec)
+{
+	nvkm_hwsq_nsec(ram->hwsq, nsec);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c
new file mode 100644
index 0000000..19c8e50
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+nv04_bus_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_bus *pbus = nvkm_bus(subdev);
+	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+	if (stat & 0x00000001) {
+		nv_error(pbus, "BUS ERROR\n");
+		stat &= ~0x00000001;
+		nv_wr32(pbus, 0x001100, 0x00000001);
+	}
+
+	if (stat & 0x00000110) {
+		subdev = nvkm_subdev(subdev, NVDEV_SUBDEV_GPIO);
+		if (subdev && subdev->intr)
+			subdev->intr(subdev);
+		stat &= ~0x00000110;
+		nv_wr32(pbus, 0x001100, 0x00000110);
+	}
+
+	if (stat) {
+		nv_error(pbus, "unknown intr 0x%08x\n", stat);
+		nv_mask(pbus, 0x001140, stat, 0x00000000);
+	}
+}
+
+static int
+nv04_bus_init(struct nvkm_object *object)
+{
+	struct nv04_bus_priv *priv = (void *)object;
+
+	nv_wr32(priv, 0x001100, 0xffffffff);
+	nv_wr32(priv, 0x001140, 0x00000111);
+
+	return nvkm_bus_init(&priv->base);
+}
+
+int
+nv04_bus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv04_bus_impl *impl = (void *)oclass;
+	struct nv04_bus_priv *priv;
+	int ret;
+
+	ret = nvkm_bus_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->intr = impl->intr;
+	priv->base.hwsq_exec = impl->hwsq_exec;
+	priv->base.hwsq_size = impl->hwsq_size;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_bus_oclass = &(struct nv04_bus_impl) {
+	.base.handle = NV_SUBDEV(BUS, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_bus_ctor,
+		.dtor = _nvkm_bus_dtor,
+		.init = nv04_bus_init,
+		.fini = _nvkm_bus_fini,
+	},
+	.intr = nv04_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h
new file mode 100644
index 0000000..3ddc8f9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_BUS_NV04_H__
+#define __NVKM_BUS_NV04_H__
+#include <subdev/bus.h>
+
+struct nv04_bus_priv {
+	struct nvkm_bus base;
+};
+
+int  nv04_bus_ctor(struct nvkm_object *, struct nvkm_object *,
+		   struct nvkm_oclass *, void *, u32,
+		   struct nvkm_object **);
+int  nv50_bus_init(struct nvkm_object *);
+void nv50_bus_intr(struct nvkm_subdev *);
+
+struct nv04_bus_impl {
+	struct nvkm_oclass base;
+	void (*intr)(struct nvkm_subdev *);
+	int  (*hwsq_exec)(struct nvkm_bus *, u32 *, u32);
+	u32  hwsq_size;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c
new file mode 100644
index 0000000..c5739bce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+nv31_bus_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_bus *pbus = nvkm_bus(subdev);
+	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+	u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144);
+
+	if (gpio) {
+		subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_GPIO);
+		if (subdev && subdev->intr)
+			subdev->intr(subdev);
+	}
+
+	if (stat & 0x00000008) {  /* NV41- */
+		u32 addr = nv_rd32(pbus, 0x009084);
+		u32 data = nv_rd32(pbus, 0x009088);
+
+		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
+			 (addr & 0x00000002) ? "write" : "read", data,
+			 (addr & 0x00fffffc));
+
+		stat &= ~0x00000008;
+		nv_wr32(pbus, 0x001100, 0x00000008);
+	}
+
+	if (stat & 0x00070000) {
+		subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM);
+		if (subdev && subdev->intr)
+			subdev->intr(subdev);
+		stat &= ~0x00070000;
+		nv_wr32(pbus, 0x001100, 0x00070000);
+	}
+
+	if (stat) {
+		nv_error(pbus, "unknown intr 0x%08x\n", stat);
+		nv_mask(pbus, 0x001140, stat, 0x00000000);
+	}
+}
+
+static int
+nv31_bus_init(struct nvkm_object *object)
+{
+	struct nv04_bus_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_bus_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x001100, 0xffffffff);
+	nv_wr32(priv, 0x001140, 0x00070008);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv31_bus_oclass = &(struct nv04_bus_impl) {
+	.base.handle = NV_SUBDEV(BUS, 0x31),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_bus_ctor,
+		.dtor = _nvkm_bus_dtor,
+		.init = nv31_bus_init,
+		.fini = _nvkm_bus_fini,
+	},
+	.intr = nv31_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c
new file mode 100644
index 0000000..1987863
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ *          Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/timer.h>
+
+static int
+nv50_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size)
+{
+	struct nv50_bus_priv *priv = (void *)pbus;
+	int i;
+
+	nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+	nv_wr32(pbus, 0x001304, 0x00000000);
+	for (i = 0; i < size; i++)
+		nv_wr32(priv, 0x001400 + (i * 4), data[i]);
+	nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+	nv_wr32(pbus, 0x00130c, 0x00000003);
+
+	return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+void
+nv50_bus_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_bus *pbus = nvkm_bus(subdev);
+	u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+	if (stat & 0x00000008) {
+		u32 addr = nv_rd32(pbus, 0x009084);
+		u32 data = nv_rd32(pbus, 0x009088);
+
+		nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
+			 (addr & 0x00000002) ? "write" : "read", data,
+			 (addr & 0x00fffffc));
+
+		stat &= ~0x00000008;
+		nv_wr32(pbus, 0x001100, 0x00000008);
+	}
+
+	if (stat & 0x00010000) {
+		subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM);
+		if (subdev && subdev->intr)
+			subdev->intr(subdev);
+		stat &= ~0x00010000;
+		nv_wr32(pbus, 0x001100, 0x00010000);
+	}
+
+	if (stat) {
+		nv_error(pbus, "unknown intr 0x%08x\n", stat);
+		nv_mask(pbus, 0x001140, stat, 0);
+	}
+}
+
+int
+nv50_bus_init(struct nvkm_object *object)
+{
+	struct nv04_bus_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_bus_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x001100, 0xffffffff);
+	nv_wr32(priv, 0x001140, 0x00010008);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_bus_oclass = &(struct nv04_bus_impl) {
+	.base.handle = NV_SUBDEV(BUS, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_bus_ctor,
+		.dtor = _nvkm_bus_dtor,
+		.init = nv50_bus_init,
+		.fini = _nvkm_bus_fini,
+	},
+	.intr = nv50_bus_intr,
+	.hwsq_exec = nv50_bus_hwsq_exec,
+	.hwsq_size = 64,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild
new file mode 100644
index 0000000..9c2f688
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild
@@ -0,0 +1,12 @@
+nvkm-y += nvkm/subdev/clk/base.o
+nvkm-y += nvkm/subdev/clk/nv04.o
+nvkm-y += nvkm/subdev/clk/nv40.o
+nvkm-y += nvkm/subdev/clk/nv50.o
+nvkm-y += nvkm/subdev/clk/g84.o
+nvkm-y += nvkm/subdev/clk/gt215.o
+nvkm-y += nvkm/subdev/clk/mcp77.o
+nvkm-y += nvkm/subdev/clk/gf100.o
+nvkm-y += nvkm/subdev/clk/gk104.o
+nvkm-y += nvkm/subdev/clk/gk20a.o
+nvkm-y += nvkm/subdev/clk/pllnv04.o
+nvkm-y += nvkm/subdev/clk/pllgt215.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
new file mode 100644
index 0000000..b24a9cc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include <subdev/bios.h>
+#include <subdev/bios/boost.h>
+#include <subdev/bios/cstep.h>
+#include <subdev/bios/perf.h>
+#include <subdev/fb.h>
+#include <subdev/therm.h>
+#include <subdev/volt.h>
+
+#include <core/device.h>
+#include <core/option.h>
+
+/******************************************************************************
+ * misc
+ *****************************************************************************/
+static u32
+nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
+		u8 pstate, u8 domain, u32 input)
+{
+	struct nvkm_bios *bios = nvkm_bios(clk);
+	struct nvbios_boostE boostE;
+	u8  ver, hdr, cnt, len;
+	u16 data;
+
+	data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE);
+	if (data) {
+		struct nvbios_boostS boostS;
+		u8  idx = 0, sver, shdr;
+		u16 subd;
+
+		input = max(boostE.min, input);
+		input = min(boostE.max, input);
+		do {
+			sver = ver;
+			shdr = hdr;
+			subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr,
+					      cnt, len, &boostS);
+			if (subd && boostS.domain == domain) {
+				if (adjust)
+					input = input * boostS.percent / 100;
+				input = max(boostS.min, input);
+				input = min(boostS.max, input);
+				break;
+			}
+		} while (subd);
+	}
+
+	return input;
+}
+
+/******************************************************************************
+ * C-States
+ *****************************************************************************/
+static int
+nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
+{
+	struct nvkm_therm *ptherm = nvkm_therm(clk);
+	struct nvkm_volt *volt = nvkm_volt(clk);
+	struct nvkm_cstate *cstate;
+	int ret;
+
+	if (!list_empty(&pstate->list)) {
+		cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
+	} else {
+		cstate = &pstate->base;
+	}
+
+	if (ptherm) {
+		ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, +1);
+		if (ret && ret != -ENODEV) {
+			nv_error(clk, "failed to raise fan speed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (volt) {
+		ret = volt->set_id(volt, cstate->voltage, +1);
+		if (ret && ret != -ENODEV) {
+			nv_error(clk, "failed to raise voltage: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = clk->calc(clk, cstate);
+	if (ret == 0) {
+		ret = clk->prog(clk);
+		clk->tidy(clk);
+	}
+
+	if (volt) {
+		ret = volt->set_id(volt, cstate->voltage, -1);
+		if (ret && ret != -ENODEV)
+			nv_error(clk, "failed to lower voltage: %d\n", ret);
+	}
+
+	if (ptherm) {
+		ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, -1);
+		if (ret && ret != -ENODEV)
+			nv_error(clk, "failed to lower fan speed: %d\n", ret);
+	}
+
+	return 0;
+}
+
+static void
+nvkm_cstate_del(struct nvkm_cstate *cstate)
+{
+	list_del(&cstate->head);
+	kfree(cstate);
+}
+
+static int
+nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
+{
+	struct nvkm_bios *bios = nvkm_bios(clk);
+	struct nvkm_domain *domain = clk->domains;
+	struct nvkm_cstate *cstate = NULL;
+	struct nvbios_cstepX cstepX;
+	u8  ver, hdr;
+	u16 data;
+
+	data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX);
+	if (!data)
+		return -ENOENT;
+
+	cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
+	if (!cstate)
+		return -ENOMEM;
+
+	*cstate = pstate->base;
+	cstate->voltage = cstepX.voltage;
+
+	while (domain && domain->name != nv_clk_src_max) {
+		if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+			u32 freq = nvkm_clk_adjust(clk, true, pstate->pstate,
+						   domain->bios, cstepX.freq);
+			cstate->domain[domain->name] = freq;
+		}
+		domain++;
+	}
+
+	list_add(&cstate->head, &pstate->list);
+	return 0;
+}
+
+/******************************************************************************
+ * P-States
+ *****************************************************************************/
+static int
+nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
+{
+	struct nvkm_fb *pfb = nvkm_fb(clk);
+	struct nvkm_pstate *pstate;
+	int ret, idx = 0;
+
+	list_for_each_entry(pstate, &clk->states, head) {
+		if (idx++ == pstatei)
+			break;
+	}
+
+	nv_debug(clk, "setting performance state %d\n", pstatei);
+	clk->pstate = pstatei;
+
+	if (pfb->ram->calc) {
+		int khz = pstate->base.domain[nv_clk_src_mem];
+		do {
+			ret = pfb->ram->calc(pfb, khz);
+			if (ret == 0)
+				ret = pfb->ram->prog(pfb);
+		} while (ret > 0);
+		pfb->ram->tidy(pfb);
+	}
+
+	return nvkm_cstate_prog(clk, pstate, 0);
+}
+
+static void
+nvkm_pstate_work(struct work_struct *work)
+{
+	struct nvkm_clk *clk = container_of(work, typeof(*clk), work);
+	int pstate;
+
+	if (!atomic_xchg(&clk->waiting, 0))
+		return;
+	clk->pwrsrc = power_supply_is_system_supplied();
+
+	nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
+		 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
+		 clk->astate, clk->tstate, clk->dstate);
+
+	pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
+	if (clk->state_nr && pstate != -1) {
+		pstate = (pstate < 0) ? clk->astate : pstate;
+		pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
+		pstate = max(pstate, clk->dstate);
+	} else {
+		pstate = clk->pstate = -1;
+	}
+
+	nv_trace(clk, "-> %d\n", pstate);
+	if (pstate != clk->pstate) {
+		int ret = nvkm_pstate_prog(clk, pstate);
+		if (ret) {
+			nv_error(clk, "error setting pstate %d: %d\n",
+				 pstate, ret);
+		}
+	}
+
+	wake_up_all(&clk->wait);
+	nvkm_notify_get(&clk->pwrsrc_ntfy);
+}
+
+static int
+nvkm_pstate_calc(struct nvkm_clk *clk, bool wait)
+{
+	atomic_set(&clk->waiting, 1);
+	schedule_work(&clk->work);
+	if (wait)
+		wait_event(clk->wait, !atomic_read(&clk->waiting));
+	return 0;
+}
+
+static void
+nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate)
+{
+	struct nvkm_domain *clock = clk->domains - 1;
+	struct nvkm_cstate *cstate;
+	char info[3][32] = { "", "", "" };
+	char name[4] = "--";
+	int i = -1;
+
+	if (pstate->pstate != 0xff)
+		snprintf(name, sizeof(name), "%02x", pstate->pstate);
+
+	while ((++clock)->name != nv_clk_src_max) {
+		u32 lo = pstate->base.domain[clock->name];
+		u32 hi = lo;
+		if (hi == 0)
+			continue;
+
+		nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo);
+		list_for_each_entry(cstate, &pstate->list, head) {
+			u32 freq = cstate->domain[clock->name];
+			lo = min(lo, freq);
+			hi = max(hi, freq);
+			nv_debug(clk, "%10d KHz\n", freq);
+		}
+
+		if (clock->mname && ++i < ARRAY_SIZE(info)) {
+			lo /= clock->mdiv;
+			hi /= clock->mdiv;
+			if (lo == hi) {
+				snprintf(info[i], sizeof(info[i]), "%s %d MHz",
+					 clock->mname, lo);
+			} else {
+				snprintf(info[i], sizeof(info[i]),
+					 "%s %d-%d MHz", clock->mname, lo, hi);
+			}
+		}
+	}
+
+	nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]);
+}
+
+static void
+nvkm_pstate_del(struct nvkm_pstate *pstate)
+{
+	struct nvkm_cstate *cstate, *temp;
+
+	list_for_each_entry_safe(cstate, temp, &pstate->list, head) {
+		nvkm_cstate_del(cstate);
+	}
+
+	list_del(&pstate->head);
+	kfree(pstate);
+}
+
+static int
+nvkm_pstate_new(struct nvkm_clk *clk, int idx)
+{
+	struct nvkm_bios *bios = nvkm_bios(clk);
+	struct nvkm_domain *domain = clk->domains - 1;
+	struct nvkm_pstate *pstate;
+	struct nvkm_cstate *cstate;
+	struct nvbios_cstepE cstepE;
+	struct nvbios_perfE perfE;
+	u8  ver, hdr, cnt, len;
+	u16 data;
+
+	data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE);
+	if (!data)
+		return -EINVAL;
+	if (perfE.pstate == 0xff)
+		return 0;
+
+	pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+	cstate = &pstate->base;
+	if (!pstate)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&pstate->list);
+
+	pstate->pstate = perfE.pstate;
+	pstate->fanspeed = perfE.fanspeed;
+	cstate->voltage = perfE.voltage;
+	cstate->domain[nv_clk_src_core] = perfE.core;
+	cstate->domain[nv_clk_src_shader] = perfE.shader;
+	cstate->domain[nv_clk_src_mem] = perfE.memory;
+	cstate->domain[nv_clk_src_vdec] = perfE.vdec;
+	cstate->domain[nv_clk_src_dom6] = perfE.disp;
+
+	while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) {
+		struct nvbios_perfS perfS;
+		u8  sver = ver, shdr = hdr;
+		u32 perfSe = nvbios_perfSp(bios, data, domain->bios,
+					  &sver, &shdr, cnt, len, &perfS);
+		if (perfSe == 0 || sver != 0x40)
+			continue;
+
+		if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+			perfS.v40.freq = nvkm_clk_adjust(clk, false,
+							 pstate->pstate,
+							 domain->bios,
+							 perfS.v40.freq);
+		}
+
+		cstate->domain[domain->name] = perfS.v40.freq;
+	}
+
+	data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE);
+	if (data) {
+		int idx = cstepE.index;
+		do {
+			nvkm_cstate_new(clk, idx, pstate);
+		} while(idx--);
+	}
+
+	nvkm_pstate_info(clk, pstate);
+	list_add_tail(&pstate->head, &clk->states);
+	clk->state_nr++;
+	return 0;
+}
+
+/******************************************************************************
+ * Adjustment triggers
+ *****************************************************************************/
+static int
+nvkm_clk_ustate_update(struct nvkm_clk *clk, int req)
+{
+	struct nvkm_pstate *pstate;
+	int i = 0;
+
+	if (!clk->allow_reclock)
+		return -ENOSYS;
+
+	if (req != -1 && req != -2) {
+		list_for_each_entry(pstate, &clk->states, head) {
+			if (pstate->pstate == req)
+				break;
+			i++;
+		}
+
+		if (pstate->pstate != req)
+			return -EINVAL;
+		req = i;
+	}
+
+	return req + 2;
+}
+
+static int
+nvkm_clk_nstate(struct nvkm_clk *clk, const char *mode, int arglen)
+{
+	int ret = 1;
+
+	if (clk->allow_reclock && !strncasecmpz(mode, "auto", arglen))
+		return -2;
+
+	if (strncasecmpz(mode, "disabled", arglen)) {
+		char save = mode[arglen];
+		long v;
+
+		((char *)mode)[arglen] = '\0';
+		if (!kstrtol(mode, 0, &v)) {
+			ret = nvkm_clk_ustate_update(clk, v);
+			if (ret < 0)
+				ret = 1;
+		}
+		((char *)mode)[arglen] = save;
+	}
+
+	return ret - 2;
+}
+
+int
+nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr)
+{
+	int ret = nvkm_clk_ustate_update(clk, req);
+	if (ret >= 0) {
+		if (ret -= 2, pwr) clk->ustate_ac = ret;
+		else		   clk->ustate_dc = ret;
+		return nvkm_pstate_calc(clk, true);
+	}
+	return ret;
+}
+
+int
+nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait)
+{
+	if (!rel) clk->astate  = req;
+	if ( rel) clk->astate += rel;
+	clk->astate = min(clk->astate, clk->state_nr - 1);
+	clk->astate = max(clk->astate, 0);
+	return nvkm_pstate_calc(clk, wait);
+}
+
+int
+nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel)
+{
+	if (!rel) clk->tstate  = req;
+	if ( rel) clk->tstate += rel;
+	clk->tstate = min(clk->tstate, 0);
+	clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
+	return nvkm_pstate_calc(clk, true);
+}
+
+int
+nvkm_clk_dstate(struct nvkm_clk *clk, int req, int rel)
+{
+	if (!rel) clk->dstate  = req;
+	if ( rel) clk->dstate += rel;
+	clk->dstate = min(clk->dstate, clk->state_nr - 1);
+	clk->dstate = max(clk->dstate, 0);
+	return nvkm_pstate_calc(clk, true);
+}
+
+static int
+nvkm_clk_pwrsrc(struct nvkm_notify *notify)
+{
+	struct nvkm_clk *clk =
+		container_of(notify, typeof(*clk), pwrsrc_ntfy);
+	nvkm_pstate_calc(clk, false);
+	return NVKM_NOTIFY_DROP;
+}
+
+/******************************************************************************
+ * subdev base class implementation
+ *****************************************************************************/
+
+int
+_nvkm_clk_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_clk *clk = (void *)object;
+	nvkm_notify_put(&clk->pwrsrc_ntfy);
+	return nvkm_subdev_fini(&clk->base, suspend);
+}
+
+int
+_nvkm_clk_init(struct nvkm_object *object)
+{
+	struct nvkm_clk *clk = (void *)object;
+	struct nvkm_domain *clock = clk->domains;
+	int ret;
+
+	ret = nvkm_subdev_init(&clk->base);
+	if (ret)
+		return ret;
+
+	memset(&clk->bstate, 0x00, sizeof(clk->bstate));
+	INIT_LIST_HEAD(&clk->bstate.list);
+	clk->bstate.pstate = 0xff;
+
+	while (clock->name != nv_clk_src_max) {
+		ret = clk->read(clk, clock->name);
+		if (ret < 0) {
+			nv_error(clk, "%02x freq unknown\n", clock->name);
+			return ret;
+		}
+		clk->bstate.base.domain[clock->name] = ret;
+		clock++;
+	}
+
+	nvkm_pstate_info(clk, &clk->bstate);
+
+	clk->astate = clk->state_nr - 1;
+	clk->tstate = 0;
+	clk->dstate = 0;
+	clk->pstate = -1;
+	nvkm_pstate_calc(clk, true);
+	return 0;
+}
+
+void
+_nvkm_clk_dtor(struct nvkm_object *object)
+{
+	struct nvkm_clk *clk = (void *)object;
+	struct nvkm_pstate *pstate, *temp;
+
+	nvkm_notify_fini(&clk->pwrsrc_ntfy);
+
+	list_for_each_entry_safe(pstate, temp, &clk->states, head) {
+		nvkm_pstate_del(pstate);
+	}
+
+	nvkm_subdev_destroy(&clk->base);
+}
+
+int
+nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, struct nvkm_domain *clocks,
+		 struct nvkm_pstate *pstates, int nb_pstates,
+		 bool allow_reclock, int length, void **object)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_clk *clk;
+	int ret, idx, arglen;
+	const char *mode;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "CLK",
+				  "clock", length, object);
+	clk = *object;
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&clk->states);
+	clk->domains = clocks;
+	clk->ustate_ac = -1;
+	clk->ustate_dc = -1;
+
+	INIT_WORK(&clk->work, nvkm_pstate_work);
+	init_waitqueue_head(&clk->wait);
+	atomic_set(&clk->waiting, 0);
+
+	/* If no pstates are provided, try and fetch them from the BIOS */
+	if (!pstates) {
+		idx = 0;
+		do {
+			ret = nvkm_pstate_new(clk, idx++);
+		} while (ret == 0);
+	} else {
+		for (idx = 0; idx < nb_pstates; idx++)
+			list_add_tail(&pstates[idx].head, &clk->states);
+		clk->state_nr = nb_pstates;
+	}
+
+	clk->allow_reclock = allow_reclock;
+
+	ret = nvkm_notify_init(NULL, &device->event, nvkm_clk_pwrsrc, true,
+			       NULL, 0, 0, &clk->pwrsrc_ntfy);
+	if (ret)
+		return ret;
+
+	mode = nvkm_stropt(device->cfgopt, "NvClkMode", &arglen);
+	if (mode) {
+		clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen);
+		clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
+	}
+
+	mode = nvkm_stropt(device->cfgopt, "NvClkModeAC", &arglen);
+	if (mode)
+		clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen);
+
+	mode = nvkm_stropt(device->cfgopt, "NvClkModeDC", &arglen);
+	if (mode)
+		clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c
new file mode 100644
index 0000000..4c90b97
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "nv50.h"
+
+static struct nvkm_domain
+g84_domains[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
+	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+	{ nv_clk_src_vdec   , 0xff },
+	{ nv_clk_src_max }
+};
+
+struct nvkm_oclass *
+g84_clk_oclass = &(struct nv50_clk_oclass) {
+	.base.handle = NV_SUBDEV(CLK, 0x84),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+	.domains = g84_domains,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
new file mode 100644
index 0000000..3d7330d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct gf100_clk_info {
+	u32 freq;
+	u32 ssel;
+	u32 mdiv;
+	u32 dsrc;
+	u32 ddiv;
+	u32 coef;
+};
+
+struct gf100_clk_priv {
+	struct nvkm_clk base;
+	struct gf100_clk_info eng[16];
+};
+
+static u32 read_div(struct gf100_clk_priv *, int, u32, u32);
+
+static u32
+read_vco(struct gf100_clk_priv *priv, u32 dsrc)
+{
+	struct nvkm_clk *clk = &priv->base;
+	u32 ssrc = nv_rd32(priv, dsrc);
+	if (!(ssrc & 0x00000100))
+		return clk->read(clk, nv_clk_src_sppll0);
+	return clk->read(clk, nv_clk_src_sppll1);
+}
+
+static u32
+read_pll(struct gf100_clk_priv *priv, u32 pll)
+{
+	struct nvkm_clk *clk = &priv->base;
+	u32 ctrl = nv_rd32(priv, pll + 0x00);
+	u32 coef = nv_rd32(priv, pll + 0x04);
+	u32 P = (coef & 0x003f0000) >> 16;
+	u32 N = (coef & 0x0000ff00) >> 8;
+	u32 M = (coef & 0x000000ff) >> 0;
+	u32 sclk;
+
+	if (!(ctrl & 0x00000001))
+		return 0;
+
+	switch (pll) {
+	case 0x00e800:
+	case 0x00e820:
+		sclk = nv_device(priv)->crystal;
+		P = 1;
+		break;
+	case 0x132000:
+		sclk = clk->read(clk, nv_clk_src_mpllsrc);
+		break;
+	case 0x132020:
+		sclk = clk->read(clk, nv_clk_src_mpllsrcref);
+		break;
+	case 0x137000:
+	case 0x137020:
+	case 0x137040:
+	case 0x1370e0:
+		sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+		break;
+	default:
+		return 0;
+	}
+
+	return sclk * N / M / P;
+}
+
+static u32
+read_div(struct gf100_clk_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+	u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+	u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+	switch (ssrc & 0x00000003) {
+	case 0:
+		if ((ssrc & 0x00030000) != 0x00030000)
+			return nv_device(priv)->crystal;
+		return 108000;
+	case 2:
+		return 100000;
+	case 3:
+		if (sctl & 0x80000000) {
+			u32 sclk = read_vco(priv, dsrc + (doff * 4));
+			u32 sdiv = (sctl & 0x0000003f) + 2;
+			return (sclk * 2) / sdiv;
+		}
+
+		return read_vco(priv, dsrc + (doff * 4));
+	default:
+		return 0;
+	}
+}
+
+static u32
+read_clk(struct gf100_clk_priv *priv, int clk)
+{
+	u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+	u32 ssel = nv_rd32(priv, 0x137100);
+	u32 sclk, sdiv;
+
+	if (ssel & (1 << clk)) {
+		if (clk < 7)
+			sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+		else
+			sclk = read_pll(priv, 0x1370e0);
+		sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+	} else {
+		sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+		sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+	}
+
+	if (sctl & 0x80000000)
+		return (sclk * 2) / sdiv;
+
+	return sclk;
+}
+
+static int
+gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct nvkm_device *device = nv_device(clk);
+	struct gf100_clk_priv *priv = (void *)clk;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return device->crystal;
+	case nv_clk_src_href:
+		return 100000;
+	case nv_clk_src_sppll0:
+		return read_pll(priv, 0x00e800);
+	case nv_clk_src_sppll1:
+		return read_pll(priv, 0x00e820);
+
+	case nv_clk_src_mpllsrcref:
+		return read_div(priv, 0, 0x137320, 0x137330);
+	case nv_clk_src_mpllsrc:
+		return read_pll(priv, 0x132020);
+	case nv_clk_src_mpll:
+		return read_pll(priv, 0x132000);
+	case nv_clk_src_mdiv:
+		return read_div(priv, 0, 0x137300, 0x137310);
+	case nv_clk_src_mem:
+		if (nv_rd32(priv, 0x1373f0) & 0x00000002)
+			return clk->read(clk, nv_clk_src_mpll);
+		return clk->read(clk, nv_clk_src_mdiv);
+
+	case nv_clk_src_gpc:
+		return read_clk(priv, 0x00);
+	case nv_clk_src_rop:
+		return read_clk(priv, 0x01);
+	case nv_clk_src_hubk07:
+		return read_clk(priv, 0x02);
+	case nv_clk_src_hubk06:
+		return read_clk(priv, 0x07);
+	case nv_clk_src_hubk01:
+		return read_clk(priv, 0x08);
+	case nv_clk_src_copy:
+		return read_clk(priv, 0x09);
+	case nv_clk_src_daemon:
+		return read_clk(priv, 0x0c);
+	case nv_clk_src_vdec:
+		return read_clk(priv, 0x0e);
+	default:
+		nv_error(clk, "invalid clock source %d\n", src);
+		return -EINVAL;
+	}
+}
+
+static u32
+calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+	u32 div = min((ref * 2) / freq, (u32)65);
+	if (div < 2)
+		div = 2;
+
+	*ddiv = div - 2;
+	return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+	u32 sclk;
+
+	/* use one of the fixed frequencies if possible */
+	*ddiv = 0x00000000;
+	switch (freq) {
+	case  27000:
+	case 108000:
+		*dsrc = 0x00000000;
+		if (freq == 108000)
+			*dsrc |= 0x00030000;
+		return freq;
+	case 100000:
+		*dsrc = 0x00000002;
+		return freq;
+	default:
+		*dsrc = 0x00000003;
+		break;
+	}
+
+	/* otherwise, calculate the closest divider */
+	sclk = read_vco(priv, 0x137160 + (clk * 4));
+	if (clk < 7)
+		sclk = calc_div(priv, clk, sclk, freq, ddiv);
+	return sclk;
+}
+
+static u32
+calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll limits;
+	int N, M, P, ret;
+
+	ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+	if (ret)
+		return 0;
+
+	limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+	if (!limits.refclk)
+		return 0;
+
+	ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+	if (ret <= 0)
+		return 0;
+
+	*coef = (P << 16) | (N << 8) | M;
+	return ret;
+}
+
+static int
+calc_clk(struct gf100_clk_priv *priv,
+	 struct nvkm_cstate *cstate, int clk, int dom)
+{
+	struct gf100_clk_info *info = &priv->eng[clk];
+	u32 freq = cstate->domain[dom];
+	u32 src0, div0, div1D, div1P = 0;
+	u32 clk0, clk1 = 0;
+
+	/* invalid clock domain */
+	if (!freq)
+		return 0;
+
+	/* first possible path, using only dividers */
+	clk0 = calc_src(priv, clk, freq, &src0, &div0);
+	clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+	/* see if we can get any closer using PLLs */
+	if (clk0 != freq && (0x00004387 & (1 << clk))) {
+		if (clk <= 7)
+			clk1 = calc_pll(priv, clk, freq, &info->coef);
+		else
+			clk1 = cstate->domain[nv_clk_src_hubk06];
+		clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+	}
+
+	/* select the method which gets closest to target freq */
+	if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+		info->dsrc = src0;
+		if (div0) {
+			info->ddiv |= 0x80000000;
+			info->ddiv |= div0 << 8;
+			info->ddiv |= div0;
+		}
+		if (div1D) {
+			info->mdiv |= 0x80000000;
+			info->mdiv |= div1D;
+		}
+		info->ssel = info->coef = 0;
+		info->freq = clk0;
+	} else {
+		if (div1P) {
+			info->mdiv |= 0x80000000;
+			info->mdiv |= div1P << 8;
+		}
+		info->ssel = (1 << clk);
+		info->freq = clk1;
+	}
+
+	return 0;
+}
+
+static int
+gf100_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct gf100_clk_priv *priv = (void *)clk;
+	int ret;
+
+	if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+	    (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+	    (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+	    (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+	    (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+	    (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) ||
+	    (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+	    (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+		return ret;
+
+	return 0;
+}
+
+static void
+gf100_clk_prog_0(struct gf100_clk_priv *priv, int clk)
+{
+	struct gf100_clk_info *info = &priv->eng[clk];
+	if (clk < 7 && !info->ssel) {
+		nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
+		nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+	}
+}
+
+static void
+gf100_clk_prog_1(struct gf100_clk_priv *priv, int clk)
+{
+	nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+	nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+gf100_clk_prog_2(struct gf100_clk_priv *priv, int clk)
+{
+	struct gf100_clk_info *info = &priv->eng[clk];
+	const u32 addr = 0x137000 + (clk * 0x20);
+	if (clk <= 7) {
+		nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+		nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+		if (info->coef) {
+			nv_wr32(priv, addr + 0x04, info->coef);
+			nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+			nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+			nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+		}
+	}
+}
+
+static void
+gf100_clk_prog_3(struct gf100_clk_priv *priv, int clk)
+{
+	struct gf100_clk_info *info = &priv->eng[clk];
+	if (info->ssel) {
+		nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+		nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+	}
+}
+
+static void
+gf100_clk_prog_4(struct gf100_clk_priv *priv, int clk)
+{
+	struct gf100_clk_info *info = &priv->eng[clk];
+	nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
+}
+
+static int
+gf100_clk_prog(struct nvkm_clk *clk)
+{
+	struct gf100_clk_priv *priv = (void *)clk;
+	struct {
+		void (*exec)(struct gf100_clk_priv *, int);
+	} stage[] = {
+		{ gf100_clk_prog_0 }, /* div programming */
+		{ gf100_clk_prog_1 }, /* select div mode */
+		{ gf100_clk_prog_2 }, /* (maybe) program pll */
+		{ gf100_clk_prog_3 }, /* (maybe) select pll mode */
+		{ gf100_clk_prog_4 }, /* final divider */
+	};
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(stage); i++) {
+		for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+			if (!priv->eng[j].freq)
+				continue;
+			stage[i].exec(priv, j);
+		}
+	}
+
+	return 0;
+}
+
+static void
+gf100_clk_tidy(struct nvkm_clk *clk)
+{
+	struct gf100_clk_priv *priv = (void *)clk;
+	memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nvkm_domain
+gf100_domain[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_hubk06 , 0x00 },
+	{ nv_clk_src_hubk01 , 0x01 },
+	{ nv_clk_src_copy   , 0x02 },
+	{ nv_clk_src_gpc    , 0x03, 0, "core", 2000 },
+	{ nv_clk_src_rop    , 0x04 },
+	{ nv_clk_src_mem    , 0x05, 0, "memory", 1000 },
+	{ nv_clk_src_vdec   , 0x06 },
+	{ nv_clk_src_daemon , 0x0a },
+	{ nv_clk_src_hubk07 , 0x0b },
+	{ nv_clk_src_max }
+};
+
+static int
+gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gf100_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, gf100_domain,
+			      NULL, 0, false, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.read = gf100_clk_read;
+	priv->base.calc = gf100_clk_calc;
+	priv->base.prog = gf100_clk_prog;
+	priv->base.tidy = gf100_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
new file mode 100644
index 0000000..e9b2310
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/timer.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+struct gk104_clk_info {
+	u32 freq;
+	u32 ssel;
+	u32 mdiv;
+	u32 dsrc;
+	u32 ddiv;
+	u32 coef;
+};
+
+struct gk104_clk_priv {
+	struct nvkm_clk base;
+	struct gk104_clk_info eng[16];
+};
+
+static u32 read_div(struct gk104_clk_priv *, int, u32, u32);
+static u32 read_pll(struct gk104_clk_priv *, u32);
+
+static u32
+read_vco(struct gk104_clk_priv *priv, u32 dsrc)
+{
+	u32 ssrc = nv_rd32(priv, dsrc);
+	if (!(ssrc & 0x00000100))
+		return read_pll(priv, 0x00e800);
+	return read_pll(priv, 0x00e820);
+}
+
+static u32
+read_pll(struct gk104_clk_priv *priv, u32 pll)
+{
+	u32 ctrl = nv_rd32(priv, pll + 0x00);
+	u32 coef = nv_rd32(priv, pll + 0x04);
+	u32 P = (coef & 0x003f0000) >> 16;
+	u32 N = (coef & 0x0000ff00) >> 8;
+	u32 M = (coef & 0x000000ff) >> 0;
+	u32 sclk;
+	u16 fN = 0xf000;
+
+	if (!(ctrl & 0x00000001))
+		return 0;
+
+	switch (pll) {
+	case 0x00e800:
+	case 0x00e820:
+		sclk = nv_device(priv)->crystal;
+		P = 1;
+		break;
+	case 0x132000:
+		sclk = read_pll(priv, 0x132020);
+		P = (coef & 0x10000000) ? 2 : 1;
+		break;
+	case 0x132020:
+		sclk = read_div(priv, 0, 0x137320, 0x137330);
+		fN   = nv_rd32(priv, pll + 0x10) >> 16;
+		break;
+	case 0x137000:
+	case 0x137020:
+	case 0x137040:
+	case 0x1370e0:
+		sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+		break;
+	default:
+		return 0;
+	}
+
+	if (P == 0)
+		P = 1;
+
+	sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13);
+	return sclk / (M * P);
+}
+
+static u32
+read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+	u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+	u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+	switch (ssrc & 0x00000003) {
+	case 0:
+		if ((ssrc & 0x00030000) != 0x00030000)
+			return nv_device(priv)->crystal;
+		return 108000;
+	case 2:
+		return 100000;
+	case 3:
+		if (sctl & 0x80000000) {
+			u32 sclk = read_vco(priv, dsrc + (doff * 4));
+			u32 sdiv = (sctl & 0x0000003f) + 2;
+			return (sclk * 2) / sdiv;
+		}
+
+		return read_vco(priv, dsrc + (doff * 4));
+	default:
+		return 0;
+	}
+}
+
+static u32
+read_mem(struct gk104_clk_priv *priv)
+{
+	switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
+	case 1: return read_pll(priv, 0x132020);
+	case 2: return read_pll(priv, 0x132000);
+	default:
+		return 0;
+	}
+}
+
+static u32
+read_clk(struct gk104_clk_priv *priv, int clk)
+{
+	u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+	u32 sclk, sdiv;
+
+	if (clk < 7) {
+		u32 ssel = nv_rd32(priv, 0x137100);
+		if (ssel & (1 << clk)) {
+			sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+			sdiv = 1;
+		} else {
+			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+			sdiv = 0;
+		}
+	} else {
+		u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
+		if ((ssrc & 0x00000003) == 0x00000003) {
+			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+			if (ssrc & 0x00000100) {
+				if (ssrc & 0x40000000)
+					sclk = read_pll(priv, 0x1370e0);
+				sdiv = 1;
+			} else {
+				sdiv = 0;
+			}
+		} else {
+			sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+			sdiv = 0;
+		}
+	}
+
+	if (sctl & 0x80000000) {
+		if (sdiv)
+			sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+		else
+			sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+		return (sclk * 2) / sdiv;
+	}
+
+	return sclk;
+}
+
+static int
+gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct nvkm_device *device = nv_device(clk);
+	struct gk104_clk_priv *priv = (void *)clk;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return device->crystal;
+	case nv_clk_src_href:
+		return 100000;
+	case nv_clk_src_mem:
+		return read_mem(priv);
+	case nv_clk_src_gpc:
+		return read_clk(priv, 0x00);
+	case nv_clk_src_rop:
+		return read_clk(priv, 0x01);
+	case nv_clk_src_hubk07:
+		return read_clk(priv, 0x02);
+	case nv_clk_src_hubk06:
+		return read_clk(priv, 0x07);
+	case nv_clk_src_hubk01:
+		return read_clk(priv, 0x08);
+	case nv_clk_src_daemon:
+		return read_clk(priv, 0x0c);
+	case nv_clk_src_vdec:
+		return read_clk(priv, 0x0e);
+	default:
+		nv_error(clk, "invalid clock source %d\n", src);
+		return -EINVAL;
+	}
+}
+
+static u32
+calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+	u32 div = min((ref * 2) / freq, (u32)65);
+	if (div < 2)
+		div = 2;
+
+	*ddiv = div - 2;
+	return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+	u32 sclk;
+
+	/* use one of the fixed frequencies if possible */
+	*ddiv = 0x00000000;
+	switch (freq) {
+	case  27000:
+	case 108000:
+		*dsrc = 0x00000000;
+		if (freq == 108000)
+			*dsrc |= 0x00030000;
+		return freq;
+	case 100000:
+		*dsrc = 0x00000002;
+		return freq;
+	default:
+		*dsrc = 0x00000003;
+		break;
+	}
+
+	/* otherwise, calculate the closest divider */
+	sclk = read_vco(priv, 0x137160 + (clk * 4));
+	if (clk < 7)
+		sclk = calc_div(priv, clk, sclk, freq, ddiv);
+	return sclk;
+}
+
+static u32
+calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll limits;
+	int N, M, P, ret;
+
+	ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+	if (ret)
+		return 0;
+
+	limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+	if (!limits.refclk)
+		return 0;
+
+	ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+	if (ret <= 0)
+		return 0;
+
+	*coef = (P << 16) | (N << 8) | M;
+	return ret;
+}
+
+static int
+calc_clk(struct gk104_clk_priv *priv,
+	 struct nvkm_cstate *cstate, int clk, int dom)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	u32 freq = cstate->domain[dom];
+	u32 src0, div0, div1D, div1P = 0;
+	u32 clk0, clk1 = 0;
+
+	/* invalid clock domain */
+	if (!freq)
+		return 0;
+
+	/* first possible path, using only dividers */
+	clk0 = calc_src(priv, clk, freq, &src0, &div0);
+	clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+	/* see if we can get any closer using PLLs */
+	if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
+		if (clk <= 7)
+			clk1 = calc_pll(priv, clk, freq, &info->coef);
+		else
+			clk1 = cstate->domain[nv_clk_src_hubk06];
+		clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+	}
+
+	/* select the method which gets closest to target freq */
+	if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+		info->dsrc = src0;
+		if (div0) {
+			info->ddiv |= 0x80000000;
+			info->ddiv |= div0;
+		}
+		if (div1D) {
+			info->mdiv |= 0x80000000;
+			info->mdiv |= div1D;
+		}
+		info->ssel = 0;
+		info->freq = clk0;
+	} else {
+		if (div1P) {
+			info->mdiv |= 0x80000000;
+			info->mdiv |= div1P << 8;
+		}
+		info->ssel = (1 << clk);
+		info->dsrc = 0x40000100;
+		info->freq = clk1;
+	}
+
+	return 0;
+}
+
+static int
+gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct gk104_clk_priv *priv = (void *)clk;
+	int ret;
+
+	if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+	    (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+	    (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+	    (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+	    (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+	    (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+	    (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+		return ret;
+
+	return 0;
+}
+
+static void
+gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	if (!info->ssel) {
+		nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv);
+		nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+	}
+}
+
+static void
+gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk)
+{
+	nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+	nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk)
+{
+	nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
+}
+
+static void
+gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	const u32 addr = 0x137000 + (clk * 0x20);
+	nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+	nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+	if (info->coef) {
+		nv_wr32(priv, addr + 0x04, info->coef);
+		nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+		nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+		nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+	}
+}
+
+static void
+gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	if (info->ssel)
+		nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv);
+	else
+		nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv);
+}
+
+static void
+gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	if (info->ssel) {
+		nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+		nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+	}
+}
+
+static void
+gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk)
+{
+	struct gk104_clk_info *info = &priv->eng[clk];
+	if (info->ssel) {
+		nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
+		nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
+	}
+}
+
+static int
+gk104_clk_prog(struct nvkm_clk *clk)
+{
+	struct gk104_clk_priv *priv = (void *)clk;
+	struct {
+		u32 mask;
+		void (*exec)(struct gk104_clk_priv *, int);
+	} stage[] = {
+		{ 0x007f, gk104_clk_prog_0   }, /* div programming */
+		{ 0x007f, gk104_clk_prog_1_0 }, /* select div mode */
+		{ 0xff80, gk104_clk_prog_1_1 },
+		{ 0x00ff, gk104_clk_prog_2   }, /* (maybe) program pll */
+		{ 0xff80, gk104_clk_prog_3   }, /* final divider */
+		{ 0x007f, gk104_clk_prog_4_0 }, /* (maybe) select pll mode */
+		{ 0xff80, gk104_clk_prog_4_1 },
+	};
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(stage); i++) {
+		for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+			if (!(stage[i].mask & (1 << j)))
+				continue;
+			if (!priv->eng[j].freq)
+				continue;
+			stage[i].exec(priv, j);
+		}
+	}
+
+	return 0;
+}
+
+static void
+gk104_clk_tidy(struct nvkm_clk *clk)
+{
+	struct gk104_clk_priv *priv = (void *)clk;
+	memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nvkm_domain
+gk104_domain[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
+	{ nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
+	{ nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
+	{ nv_clk_src_mem    , 0x03, 0, "memory", 500 },
+	{ nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
+	{ nv_clk_src_hubk01 , 0x05 },
+	{ nv_clk_src_vdec   , 0x06 },
+	{ nv_clk_src_daemon , 0x07 },
+	{ nv_clk_src_max }
+};
+
+static int
+gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk104_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, gk104_domain,
+			      NULL, 0, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.read = gk104_clk_read;
+	priv->base.calc = gk104_clk_calc;
+	priv->base.prog = gk104_clk_prog;
+	priv->base.tidy = gk104_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
new file mode 100644
index 0000000..65c5327
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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.
+ *
+ * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c
+ *
+ */
+#include <subdev/clk.h>
+#include <subdev/timer.h>
+
+#include <core/device.h>
+
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
+
+#define MHZ (1000 * 1000)
+
+#define MASK(w)	((1 << w) - 1)
+
+#define SYS_GPCPLL_CFG_BASE			0x00137000
+#define GPC_BCASE_GPCPLL_CFG_BASE		0x00132800
+
+#define GPCPLL_CFG		(SYS_GPCPLL_CFG_BASE + 0)
+#define GPCPLL_CFG_ENABLE	BIT(0)
+#define GPCPLL_CFG_IDDQ		BIT(1)
+#define GPCPLL_CFG_LOCK_DET_OFF	BIT(4)
+#define GPCPLL_CFG_LOCK		BIT(17)
+
+#define GPCPLL_COEFF		(SYS_GPCPLL_CFG_BASE + 4)
+#define GPCPLL_COEFF_M_SHIFT	0
+#define GPCPLL_COEFF_M_WIDTH	8
+#define GPCPLL_COEFF_N_SHIFT	8
+#define GPCPLL_COEFF_N_WIDTH	8
+#define GPCPLL_COEFF_P_SHIFT	16
+#define GPCPLL_COEFF_P_WIDTH	6
+
+#define GPCPLL_CFG2			(SYS_GPCPLL_CFG_BASE + 0xc)
+#define GPCPLL_CFG2_SETUP2_SHIFT	16
+#define GPCPLL_CFG2_PLL_STEPA_SHIFT	24
+
+#define GPCPLL_CFG3			(SYS_GPCPLL_CFG_BASE + 0x18)
+#define GPCPLL_CFG3_PLL_STEPB_SHIFT	16
+
+#define GPCPLL_NDIV_SLOWDOWN			(SYS_GPCPLL_CFG_BASE + 0x1c)
+#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT	0
+#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT	8
+#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT	16
+#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT	22
+#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT	31
+
+#define SEL_VCO				(SYS_GPCPLL_CFG_BASE + 0x100)
+#define SEL_VCO_GPC2CLK_OUT_SHIFT	0
+
+#define GPC2CLK_OUT			(SYS_GPCPLL_CFG_BASE + 0x250)
+#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH	1
+#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT	31
+#define GPC2CLK_OUT_SDIV14_INDIV4_MODE	1
+#define GPC2CLK_OUT_VCODIV_WIDTH	6
+#define GPC2CLK_OUT_VCODIV_SHIFT	8
+#define GPC2CLK_OUT_VCODIV1		0
+#define GPC2CLK_OUT_VCODIV_MASK		(MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \
+					GPC2CLK_OUT_VCODIV_SHIFT)
+#define	GPC2CLK_OUT_BYPDIV_WIDTH	6
+#define GPC2CLK_OUT_BYPDIV_SHIFT	0
+#define GPC2CLK_OUT_BYPDIV31		0x3c
+#define GPC2CLK_OUT_INIT_MASK	((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \
+		GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\
+		| (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\
+		| (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT))
+#define GPC2CLK_OUT_INIT_VAL	((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \
+		GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \
+		| (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \
+		| (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT))
+
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG	(GPC_BCASE_GPCPLL_CFG_BASE + 0xa0)
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT	24
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \
+	    (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT)
+
+static const u8 pl_to_div[] = {
+/* PL:   0, 1, 2, 3, 4, 5, 6,  7,  8,  9, 10, 11, 12, 13, 14 */
+/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32,
+};
+
+/* All frequencies in Mhz */
+struct gk20a_clk_pllg_params {
+	u32 min_vco, max_vco;
+	u32 min_u, max_u;
+	u32 min_m, max_m;
+	u32 min_n, max_n;
+	u32 min_pl, max_pl;
+};
+
+static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
+	.min_vco = 1000, .max_vco = 2064,
+	.min_u = 12, .max_u = 38,
+	.min_m = 1, .max_m = 255,
+	.min_n = 8, .max_n = 255,
+	.min_pl = 1, .max_pl = 32,
+};
+
+struct gk20a_clk_priv {
+	struct nvkm_clk base;
+	const struct gk20a_clk_pllg_params *params;
+	u32 m, n, pl;
+	u32 parent_rate;
+};
+#define to_gk20a_clk(base) container_of(base, struct gk20a_clk_priv, base)
+
+static void
+gk20a_pllg_read_mnp(struct gk20a_clk_priv *priv)
+{
+	u32 val;
+
+	val = nv_rd32(priv, GPCPLL_COEFF);
+	priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+	priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH);
+	priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
+}
+
+static u32
+gk20a_pllg_calc_rate(struct gk20a_clk_priv *priv)
+{
+	u32 rate;
+	u32 divider;
+
+	rate = priv->parent_rate * priv->n;
+	divider = priv->m * pl_to_div[priv->pl];
+	do_div(rate, divider);
+
+	return rate / 2;
+}
+
+static int
+gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate)
+{
+	u32 target_clk_f, ref_clk_f, target_freq;
+	u32 min_vco_f, max_vco_f;
+	u32 low_pl, high_pl, best_pl;
+	u32 target_vco_f, vco_f;
+	u32 best_m, best_n;
+	u32 u_f;
+	u32 m, n, n2;
+	u32 delta, lwv, best_delta = ~0;
+	u32 pl;
+
+	target_clk_f = rate * 2 / MHZ;
+	ref_clk_f = priv->parent_rate / MHZ;
+
+	max_vco_f = priv->params->max_vco;
+	min_vco_f = priv->params->min_vco;
+	best_m = priv->params->max_m;
+	best_n = priv->params->min_n;
+	best_pl = priv->params->min_pl;
+
+	target_vco_f = target_clk_f + target_clk_f / 50;
+	if (max_vco_f < target_vco_f)
+		max_vco_f = target_vco_f;
+
+	/* min_pl <= high_pl <= max_pl */
+	high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f;
+	high_pl = min(high_pl, priv->params->max_pl);
+	high_pl = max(high_pl, priv->params->min_pl);
+
+	/* min_pl <= low_pl <= max_pl */
+	low_pl = min_vco_f / target_vco_f;
+	low_pl = min(low_pl, priv->params->max_pl);
+	low_pl = max(low_pl, priv->params->min_pl);
+
+	/* Find Indices of high_pl and low_pl */
+	for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
+		if (pl_to_div[pl] >= low_pl) {
+			low_pl = pl;
+			break;
+		}
+	}
+	for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
+		if (pl_to_div[pl] >= high_pl) {
+			high_pl = pl;
+			break;
+		}
+	}
+
+	nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl,
+		 pl_to_div[low_pl], high_pl, pl_to_div[high_pl]);
+
+	/* Select lowest possible VCO */
+	for (pl = low_pl; pl <= high_pl; pl++) {
+		target_vco_f = target_clk_f * pl_to_div[pl];
+		for (m = priv->params->min_m; m <= priv->params->max_m; m++) {
+			u_f = ref_clk_f / m;
+
+			if (u_f < priv->params->min_u)
+				break;
+			if (u_f > priv->params->max_u)
+				continue;
+
+			n = (target_vco_f * m) / ref_clk_f;
+			n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;
+
+			if (n > priv->params->max_n)
+				break;
+
+			for (; n <= n2; n++) {
+				if (n < priv->params->min_n)
+					continue;
+				if (n > priv->params->max_n)
+					break;
+
+				vco_f = ref_clk_f * n / m;
+
+				if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
+					lwv = (vco_f + (pl_to_div[pl] / 2))
+						/ pl_to_div[pl];
+					delta = abs(lwv - target_clk_f);
+
+					if (delta < best_delta) {
+						best_delta = delta;
+						best_m = m;
+						best_n = n;
+						best_pl = pl;
+
+						if (best_delta == 0)
+							goto found_match;
+					}
+				}
+			}
+		}
+	}
+
+found_match:
+	WARN_ON(best_delta == ~0);
+
+	if (best_delta != 0)
+		nv_debug(priv, "no best match for target @ %dMHz on gpc_pll",
+			 target_clk_f);
+
+	priv->m = best_m;
+	priv->n = best_n;
+	priv->pl = best_pl;
+
+	target_freq = gk20a_pllg_calc_rate(priv) / MHZ;
+
+	nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n",
+		 target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]);
+	return 0;
+}
+
+static int
+gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n)
+{
+	u32 val;
+	int ramp_timeout;
+
+	/* get old coefficients */
+	val = nv_rd32(priv, GPCPLL_COEFF);
+	/* do nothing if NDIV is the same */
+	if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH)))
+		return 0;
+
+	/* setup */
+	nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT,
+		0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT);
+	nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT,
+		0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT);
+
+	/* pll slowdown mode */
+	nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
+		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT),
+		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT));
+
+	/* new ndiv ready for ramp */
+	val = nv_rd32(priv, GPCPLL_COEFF);
+	val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT);
+	val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT;
+	udelay(1);
+	nv_wr32(priv, GPCPLL_COEFF, val);
+
+	/* dynamic ramp to new ndiv */
+	val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
+	val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT;
+	udelay(1);
+	nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val);
+
+	for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) {
+		udelay(1);
+		val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG);
+		if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK)
+			break;
+	}
+
+	/* exit slowdown mode */
+	nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
+		BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) |
+		BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0);
+	nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
+
+	if (ramp_timeout <= 0) {
+		nv_error(priv, "gpcpll dynamic ramp timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void
+_gk20a_pllg_enable(struct gk20a_clk_priv *priv)
+{
+	nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE);
+	nv_rd32(priv, GPCPLL_CFG);
+}
+
+static void
+_gk20a_pllg_disable(struct gk20a_clk_priv *priv)
+{
+	nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0);
+	nv_rd32(priv, GPCPLL_CFG);
+}
+
+static int
+_gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv, bool allow_slide)
+{
+	u32 val, cfg;
+	u32 m_old, pl_old, n_lo;
+
+	/* get old coefficients */
+	val = nv_rd32(priv, GPCPLL_COEFF);
+	m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+	pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
+
+	/* do NDIV slide if there is no change in M and PL */
+	cfg = nv_rd32(priv, GPCPLL_CFG);
+	if (allow_slide && priv->m == m_old && priv->pl == pl_old &&
+	    (cfg & GPCPLL_CFG_ENABLE)) {
+		return gk20a_pllg_slide(priv, priv->n);
+	}
+
+	/* slide down to NDIV_LO */
+	n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco,
+			    priv->parent_rate / MHZ);
+	if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) {
+		int ret = gk20a_pllg_slide(priv, n_lo);
+
+		if (ret)
+			return ret;
+	}
+
+	/* split FO-to-bypass jump in halfs by setting out divider 1:2 */
+	nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK,
+		0x2 << GPC2CLK_OUT_VCODIV_SHIFT);
+
+	/* put PLL in bypass before programming it */
+	val = nv_rd32(priv, SEL_VCO);
+	val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
+	udelay(2);
+	nv_wr32(priv, SEL_VCO, val);
+
+	/* get out from IDDQ */
+	val = nv_rd32(priv, GPCPLL_CFG);
+	if (val & GPCPLL_CFG_IDDQ) {
+		val &= ~GPCPLL_CFG_IDDQ;
+		nv_wr32(priv, GPCPLL_CFG, val);
+		nv_rd32(priv, GPCPLL_CFG);
+		udelay(2);
+	}
+
+	_gk20a_pllg_disable(priv);
+
+	nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n,
+		 priv->pl);
+
+	n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco,
+			    priv->parent_rate / MHZ);
+	val = priv->m << GPCPLL_COEFF_M_SHIFT;
+	val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT;
+	val |= priv->pl << GPCPLL_COEFF_P_SHIFT;
+	nv_wr32(priv, GPCPLL_COEFF, val);
+
+	_gk20a_pllg_enable(priv);
+
+	val = nv_rd32(priv, GPCPLL_CFG);
+	if (val & GPCPLL_CFG_LOCK_DET_OFF) {
+		val &= ~GPCPLL_CFG_LOCK_DET_OFF;
+		nv_wr32(priv, GPCPLL_CFG, val);
+	}
+
+	if (!nvkm_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK,
+				GPCPLL_CFG_LOCK)) {
+		nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	/* switch to VCO mode */
+	nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
+
+	/* restore out divider 1:1 */
+	val = nv_rd32(priv, GPC2CLK_OUT);
+	val &= ~GPC2CLK_OUT_VCODIV_MASK;
+	udelay(2);
+	nv_wr32(priv, GPC2CLK_OUT, val);
+
+	/* slide up to new NDIV */
+	return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0;
+}
+
+static int
+gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv)
+{
+	int err;
+
+	err = _gk20a_pllg_program_mnp(priv, true);
+	if (err)
+		err = _gk20a_pllg_program_mnp(priv, false);
+
+	return err;
+}
+
+static void
+gk20a_pllg_disable(struct gk20a_clk_priv *priv)
+{
+	u32 val;
+
+	/* slide to VCO min */
+	val = nv_rd32(priv, GPCPLL_CFG);
+	if (val & GPCPLL_CFG_ENABLE) {
+		u32 coeff, m, n_lo;
+
+		coeff = nv_rd32(priv, GPCPLL_COEFF);
+		m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+		n_lo = DIV_ROUND_UP(m * priv->params->min_vco,
+				    priv->parent_rate / MHZ);
+		gk20a_pllg_slide(priv, n_lo);
+	}
+
+	/* put PLL in bypass before disabling it */
+	nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0);
+
+	_gk20a_pllg_disable(priv);
+}
+
+#define GK20A_CLK_GPC_MDIV 1000
+
+static struct nvkm_domain
+gk20a_domains[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV },
+	{ nv_clk_src_max }
+};
+
+static struct nvkm_pstate
+gk20a_pstates[] = {
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 72000,
+			.voltage = 0,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 108000,
+			.voltage = 1,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 180000,
+			.voltage = 2,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 252000,
+			.voltage = 3,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 324000,
+			.voltage = 4,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 396000,
+			.voltage = 5,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 468000,
+			.voltage = 6,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 540000,
+			.voltage = 7,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 612000,
+			.voltage = 8,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 648000,
+			.voltage = 9,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 684000,
+			.voltage = 10,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 708000,
+			.voltage = 11,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 756000,
+			.voltage = 12,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 804000,
+			.voltage = 13,
+		},
+	},
+	{
+		.base = {
+			.domain[nv_clk_src_gpc] = 852000,
+			.voltage = 14,
+		},
+	},
+};
+
+static int
+gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct gk20a_clk_priv *priv = (void *)clk;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return nv_device(clk)->crystal;
+	case nv_clk_src_gpc:
+		gk20a_pllg_read_mnp(priv);
+		return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV;
+	default:
+		nv_error(clk, "invalid clock source %d\n", src);
+		return -EINVAL;
+	}
+}
+
+static int
+gk20a_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct gk20a_clk_priv *priv = (void *)clk;
+
+	return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] *
+					 GK20A_CLK_GPC_MDIV);
+}
+
+static int
+gk20a_clk_prog(struct nvkm_clk *clk)
+{
+	struct gk20a_clk_priv *priv = (void *)clk;
+
+	return gk20a_pllg_program_mnp(priv);
+}
+
+static void
+gk20a_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static int
+gk20a_clk_fini(struct nvkm_object *object, bool suspend)
+{
+	struct gk20a_clk_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_clk_fini(&priv->base, false);
+
+	gk20a_pllg_disable(priv);
+
+	return ret;
+}
+
+static int
+gk20a_clk_init(struct nvkm_object *object)
+{
+	struct gk20a_clk_priv *priv = (void *)object;
+	int ret;
+
+	nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL);
+
+	ret = nvkm_clk_init(&priv->base);
+	if (ret)
+		return ret;
+
+	ret = gk20a_clk_prog(&priv->base);
+	if (ret) {
+		nv_error(priv, "cannot initialize clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int
+gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk20a_clk_priv *priv;
+	struct nouveau_platform_device *plat;
+	int ret;
+	int i;
+
+	/* Finish initializing the pstates */
+	for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) {
+		INIT_LIST_HEAD(&gk20a_pstates[i].list);
+		gk20a_pstates[i].pstate = i + 1;
+	}
+
+	ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains,
+			      gk20a_pstates, ARRAY_SIZE(gk20a_pstates),
+			      true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->params = &gk20a_pllg_params;
+
+	plat = nv_device_to_platform(nv_device(parent));
+	priv->parent_rate = clk_get_rate(plat->gpu->clk);
+	nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ);
+
+	priv->base.read = gk20a_clk_read;
+	priv->base.calc = gk20a_clk_calc;
+	priv->base.prog = gk20a_clk_prog;
+	priv->base.tidy = gk20a_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0xea),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_clk_ctor,
+		.dtor = _nvkm_subdev_dtor,
+		.init = gk20a_clk_init,
+		.fini = gk20a_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
new file mode 100644
index 0000000..822d32a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ *          Roy Spliet
+ */
+#include "gt215.h"
+#include "pll.h"
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct gt215_clk_priv {
+	struct nvkm_clk base;
+	struct gt215_clk_info eng[nv_clk_src_max];
+};
+
+static u32 read_clk(struct gt215_clk_priv *, int, bool);
+static u32 read_pll(struct gt215_clk_priv *, int, u32);
+
+static u32
+read_vco(struct gt215_clk_priv *priv, int clk)
+{
+	u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+
+	switch (sctl & 0x00000030) {
+	case 0x00000000:
+		return nv_device(priv)->crystal;
+	case 0x00000020:
+		return read_pll(priv, 0x41, 0x00e820);
+	case 0x00000030:
+		return read_pll(priv, 0x42, 0x00e8a0);
+	default:
+		return 0;
+	}
+}
+
+static u32
+read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en)
+{
+	u32 sctl, sdiv, sclk;
+
+	/* refclk for the 0xe8xx plls is a fixed frequency */
+	if (clk >= 0x40) {
+		if (nv_device(priv)->chipset == 0xaf) {
+			/* no joke.. seriously.. sigh.. */
+			return nv_rd32(priv, 0x00471c) * 1000;
+		}
+
+		return nv_device(priv)->crystal;
+	}
+
+	sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+	if (!ignore_en && !(sctl & 0x00000100))
+		return 0;
+
+	/* out_alt */
+	if (sctl & 0x00000400)
+		return 108000;
+
+	/* vco_out */
+	switch (sctl & 0x00003000) {
+	case 0x00000000:
+		if (!(sctl & 0x00000200))
+			return nv_device(priv)->crystal;
+		return 0;
+	case 0x00002000:
+		if (sctl & 0x00000040)
+			return 108000;
+		return 100000;
+	case 0x00003000:
+		/* vco_enable */
+		if (!(sctl & 0x00000001))
+			return 0;
+
+		sclk = read_vco(priv, clk);
+		sdiv = ((sctl & 0x003f0000) >> 16) + 2;
+		return (sclk * 2) / sdiv;
+	default:
+		return 0;
+	}
+}
+
+static u32
+read_pll(struct gt215_clk_priv *priv, int clk, u32 pll)
+{
+	u32 ctrl = nv_rd32(priv, pll + 0);
+	u32 sclk = 0, P = 1, N = 1, M = 1;
+
+	if (!(ctrl & 0x00000008)) {
+		if (ctrl & 0x00000001) {
+			u32 coef = nv_rd32(priv, pll + 4);
+			M = (coef & 0x000000ff) >> 0;
+			N = (coef & 0x0000ff00) >> 8;
+			P = (coef & 0x003f0000) >> 16;
+
+			/* no post-divider on these..
+			 * XXX: it looks more like two post-"dividers" that
+			 * cross each other out in the default RPLL config */
+			if ((pll & 0x00ff00) == 0x00e800)
+				P = 1;
+
+			sclk = read_clk(priv, 0x00 + clk, false);
+		}
+	} else {
+		sclk = read_clk(priv, 0x10 + clk, false);
+	}
+
+	if (M * P)
+		return sclk * N / (M * P);
+
+	return 0;
+}
+
+static int
+gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct gt215_clk_priv *priv = (void *)clk;
+	u32 hsrc;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return nv_device(priv)->crystal;
+	case nv_clk_src_core:
+	case nv_clk_src_core_intm:
+		return read_pll(priv, 0x00, 0x4200);
+	case nv_clk_src_shader:
+		return read_pll(priv, 0x01, 0x4220);
+	case nv_clk_src_mem:
+		return read_pll(priv, 0x02, 0x4000);
+	case nv_clk_src_disp:
+		return read_clk(priv, 0x20, false);
+	case nv_clk_src_vdec:
+		return read_clk(priv, 0x21, false);
+	case nv_clk_src_daemon:
+		return read_clk(priv, 0x25, false);
+	case nv_clk_src_host:
+		hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
+		switch (hsrc) {
+		case 0:
+			return read_clk(priv, 0x1d, false);
+		case 2:
+		case 3:
+			return 277000;
+		default:
+			nv_error(clk, "unknown HOST clock source %d\n", hsrc);
+			return -EINVAL;
+		}
+	default:
+		nv_error(clk, "invalid clock source %d\n", src);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int
+gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz,
+	       struct gt215_clk_info *info)
+{
+	struct gt215_clk_priv *priv = (void *)clock;
+	u32 oclk, sclk, sdiv, diff;
+
+	info->clk = 0;
+
+	switch (khz) {
+	case 27000:
+		info->clk = 0x00000100;
+		return khz;
+	case 100000:
+		info->clk = 0x00002100;
+		return khz;
+	case 108000:
+		info->clk = 0x00002140;
+		return khz;
+	default:
+		sclk = read_vco(priv, clk);
+		sdiv = min((sclk * 2) / khz, (u32)65);
+		oclk = (sclk * 2) / sdiv;
+		diff = ((khz + 3000) - oclk);
+
+		/* When imprecise, play it safe and aim for a clock lower than
+		 * desired rather than higher */
+		if (diff < 0) {
+			sdiv++;
+			oclk = (sclk * 2) / sdiv;
+		}
+
+		/* divider can go as low as 2, limited here because NVIDIA
+		 * and the VBIOS on my NVA8 seem to prefer using the PLL
+		 * for 810MHz - is there a good reason?
+		 * XXX: PLLs with refclk 810MHz?  */
+		if (sdiv > 4) {
+			info->clk = (((sdiv - 2) << 16) | 0x00003100);
+			return oclk;
+		}
+
+		break;
+	}
+
+	return -ERANGE;
+}
+
+int
+gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz,
+	       struct gt215_clk_info *info)
+{
+	struct nvkm_bios *bios = nvkm_bios(clock);
+	struct gt215_clk_priv *priv = (void *)clock;
+	struct nvbios_pll limits;
+	int P, N, M, diff;
+	int ret;
+
+	info->pll = 0;
+
+	/* If we can get a within [-2, 3) MHz of a divider, we'll disable the
+	 * PLL and use the divider instead. */
+	ret = gt215_clk_info(clock, clk, khz, info);
+	diff = khz - ret;
+	if (!pll || (diff >= -2000 && diff < 3000)) {
+		goto out;
+	}
+
+	/* Try with PLL */
+	ret = nvbios_pll_parse(bios, pll, &limits);
+	if (ret)
+		return ret;
+
+	ret = gt215_clk_info(clock, clk - 0x10, limits.refclk, info);
+	if (ret != limits.refclk)
+		return -EINVAL;
+
+	ret = gt215_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
+	if (ret >= 0) {
+		info->pll = (P << 16) | (N << 8) | M;
+	}
+
+out:
+	info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
+	return ret ? ret : -ERANGE;
+}
+
+static int
+calc_clk(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate,
+	 int clk, u32 pll, int idx)
+{
+	int ret = gt215_pll_info(&priv->base, clk, pll, cstate->domain[idx],
+				 &priv->eng[idx]);
+	if (ret >= 0)
+		return 0;
+	return ret;
+}
+
+static int
+calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate)
+{
+	int ret = 0;
+	u32 kHz = cstate->domain[nv_clk_src_host];
+	struct gt215_clk_info *info = &priv->eng[nv_clk_src_host];
+
+	if (kHz == 277000) {
+		info->clk = 0;
+		info->host_out = NVA3_HOST_277;
+		return 0;
+	}
+
+	info->host_out = NVA3_HOST_CLK;
+
+	ret = gt215_clk_info(&priv->base, 0x1d, kHz, info);
+	if (ret >= 0)
+		return 0;
+
+	return ret;
+}
+
+int
+gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(clk);
+
+	/* halt and idle execution engines */
+	nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
+	nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
+	/* Wait until the interrupt handler is finished */
+	if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
+		return -EBUSY;
+
+	if (pfifo)
+		pfifo->pause(pfifo, flags);
+
+	if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
+		return -EIO;
+	if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
+		return -EIO;
+
+	return 0;
+}
+
+void
+gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags)
+{
+	struct nvkm_fifo *pfifo = nvkm_fifo(clk);
+
+	if (pfifo && flags)
+		pfifo->start(pfifo, flags);
+
+	nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
+	nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
+}
+
+static void
+disable_clk_src(struct gt215_clk_priv *priv, u32 src)
+{
+	nv_mask(priv, src, 0x00000100, 0x00000000);
+	nv_mask(priv, src, 0x00000001, 0x00000000);
+}
+
+static void
+prog_pll(struct gt215_clk_priv *priv, int clk, u32 pll, int idx)
+{
+	struct gt215_clk_info *info = &priv->eng[idx];
+	const u32 src0 = 0x004120 + (clk * 4);
+	const u32 src1 = 0x004160 + (clk * 4);
+	const u32 ctrl = pll + 0;
+	const u32 coef = pll + 4;
+	u32 bypass;
+
+	if (info->pll) {
+		/* Always start from a non-PLL clock */
+		bypass = nv_rd32(priv, ctrl)  & 0x00000008;
+		if (!bypass) {
+			nv_mask(priv, src1, 0x00000101, 0x00000101);
+			nv_mask(priv, ctrl, 0x00000008, 0x00000008);
+			udelay(20);
+		}
+
+		nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
+		nv_wr32(priv, coef, info->pll);
+		nv_mask(priv, ctrl, 0x00000015, 0x00000015);
+		nv_mask(priv, ctrl, 0x00000010, 0x00000000);
+		if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
+			nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+			nv_mask(priv, src0, 0x00000101, 0x00000000);
+			return;
+		}
+		nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+		nv_mask(priv, ctrl, 0x00000008, 0x00000000);
+		disable_clk_src(priv, src1);
+	} else {
+		nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
+		nv_mask(priv, ctrl, 0x00000018, 0x00000018);
+		udelay(20);
+		nv_mask(priv, ctrl, 0x00000001, 0x00000000);
+		disable_clk_src(priv, src0);
+	}
+}
+
+static void
+prog_clk(struct gt215_clk_priv *priv, int clk, int idx)
+{
+	struct gt215_clk_info *info = &priv->eng[idx];
+	nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
+}
+
+static void
+prog_host(struct gt215_clk_priv *priv)
+{
+	struct gt215_clk_info *info = &priv->eng[nv_clk_src_host];
+	u32 hsrc = (nv_rd32(priv, 0xc040));
+
+	switch (info->host_out) {
+	case NVA3_HOST_277:
+		if ((hsrc & 0x30000000) == 0) {
+			nv_wr32(priv, 0xc040, hsrc | 0x20000000);
+			disable_clk_src(priv, 0x4194);
+		}
+		break;
+	case NVA3_HOST_CLK:
+		prog_clk(priv, 0x1d, nv_clk_src_host);
+		if ((hsrc & 0x30000000) >= 0x20000000) {
+			nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* This seems to be a clock gating factor on idle, always set to 64 */
+	nv_wr32(priv, 0xc044, 0x3e);
+}
+
+static void
+prog_core(struct gt215_clk_priv *priv, int idx)
+{
+	struct gt215_clk_info *info = &priv->eng[idx];
+	u32 fb_delay = nv_rd32(priv, 0x10002c);
+
+	if (fb_delay < info->fb_delay)
+		nv_wr32(priv, 0x10002c, info->fb_delay);
+
+	prog_pll(priv, 0x00, 0x004200, idx);
+
+	if (fb_delay > info->fb_delay)
+		nv_wr32(priv, 0x10002c, info->fb_delay);
+}
+
+static int
+gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct gt215_clk_priv *priv = (void *)clk;
+	struct gt215_clk_info *core = &priv->eng[nv_clk_src_core];
+	int ret;
+
+	if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
+	    (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
+	    (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
+	    (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
+	    (ret = calc_host(priv, cstate)))
+		return ret;
+
+	/* XXX: Should be reading the highest bit in the VBIOS clock to decide
+	 * whether to use a PLL or not... but using a PLL defeats the purpose */
+	if (core->pll) {
+		ret = gt215_clk_info(clk, 0x10,
+				     cstate->domain[nv_clk_src_core_intm],
+				     &priv->eng[nv_clk_src_core_intm]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+gt215_clk_prog(struct nvkm_clk *clk)
+{
+	struct gt215_clk_priv *priv = (void *)clk;
+	struct gt215_clk_info *core = &priv->eng[nv_clk_src_core];
+	int ret = 0;
+	unsigned long flags;
+	unsigned long *f = &flags;
+
+	ret = gt215_clk_pre(clk, f);
+	if (ret)
+		goto out;
+
+	if (core->pll)
+		prog_core(priv, nv_clk_src_core_intm);
+
+	prog_core(priv,  nv_clk_src_core);
+	prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
+	prog_clk(priv, 0x20, nv_clk_src_disp);
+	prog_clk(priv, 0x21, nv_clk_src_vdec);
+	prog_host(priv);
+
+out:
+	if (ret == -EBUSY)
+		f = NULL;
+
+	gt215_clk_post(clk, f);
+	return ret;
+}
+
+static void
+gt215_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static struct nvkm_domain
+gt215_domain[] = {
+	{ nv_clk_src_crystal  , 0xff },
+	{ nv_clk_src_core     , 0x00, 0, "core", 1000 },
+	{ nv_clk_src_shader   , 0x01, 0, "shader", 1000 },
+	{ nv_clk_src_mem      , 0x02, 0, "memory", 1000 },
+	{ nv_clk_src_vdec     , 0x03 },
+	{ nv_clk_src_disp     , 0x04 },
+	{ nv_clk_src_host     , 0x05 },
+	{ nv_clk_src_core_intm, 0x06 },
+	{ nv_clk_src_max }
+};
+
+static int
+gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gt215_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, gt215_domain,
+			      NULL, 0, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.read = gt215_clk_read;
+	priv->base.calc = gt215_clk_calc;
+	priv->base.prog = gt215_clk_prog;
+	priv->base.tidy = gt215_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+gt215_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0xa3),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h
new file mode 100644
index 0000000..b447d9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h
@@ -0,0 +1,18 @@
+#ifndef __NVKM_CLK_NVA3_H__
+#define __NVKM_CLK_NVA3_H__
+#include <subdev/clk.h>
+
+struct gt215_clk_info {
+	u32 clk;
+	u32 pll;
+	enum {
+		NVA3_HOST_277,
+		NVA3_HOST_CLK,
+	} host_out;
+	u32 fb_delay;
+};
+
+int  gt215_pll_info(struct nvkm_clk *, int, u32, u32, struct gt215_clk_info *);
+int  gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags);
+void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c
new file mode 100644
index 0000000..c54417b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gt215.h"
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct mcp77_clk_priv {
+	struct nvkm_clk base;
+	enum nv_clk_src csrc, ssrc, vsrc;
+	u32 cctrl, sctrl;
+	u32 ccoef, scoef;
+	u32 cpost, spost;
+	u32 vdiv;
+};
+
+static u32
+read_div(struct nvkm_clk *clk)
+{
+	return nv_rd32(clk, 0x004600);
+}
+
+static u32
+read_pll(struct nvkm_clk *clk, u32 base)
+{
+	u32 ctrl = nv_rd32(clk, base + 0);
+	u32 coef = nv_rd32(clk, base + 4);
+	u32 ref = clk->read(clk, nv_clk_src_href);
+	u32 post_div = 0;
+	u32 clock = 0;
+	int N1, M1;
+
+	switch (base){
+	case 0x4020:
+		post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16);
+		break;
+	case 0x4028:
+		post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16;
+		break;
+	default:
+		break;
+	}
+
+	N1 = (coef & 0x0000ff00) >> 8;
+	M1 = (coef & 0x000000ff);
+	if ((ctrl & 0x80000000) && M1) {
+		clock = ref * N1 / M1;
+		clock = clock / post_div;
+	}
+
+	return clock;
+}
+
+static int
+mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct mcp77_clk_priv *priv = (void *)clk;
+	u32 mast = nv_rd32(clk, 0x00c054);
+	u32 P = 0;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return nv_device(priv)->crystal;
+	case nv_clk_src_href:
+		return 100000; /* PCIE reference clock */
+	case nv_clk_src_hclkm4:
+		return clk->read(clk, nv_clk_src_href) * 4;
+	case nv_clk_src_hclkm2d3:
+		return clk->read(clk, nv_clk_src_href) * 2 / 3;
+	case nv_clk_src_host:
+		switch (mast & 0x000c0000) {
+		case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3);
+		case 0x00040000: break;
+		case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4);
+		case 0x000c0000: return clk->read(clk, nv_clk_src_cclk);
+		}
+		break;
+	case nv_clk_src_core:
+		P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16;
+
+		switch (mast & 0x00000003) {
+		case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
+		case 0x00000001: return 0;
+		case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P;
+		case 0x00000003: return read_pll(clk, 0x004028) >> P;
+		}
+		break;
+	case nv_clk_src_cclk:
+		if ((mast & 0x03000000) != 0x03000000)
+			return clk->read(clk, nv_clk_src_core);
+
+		if ((mast & 0x00000200) == 0x00000000)
+			return clk->read(clk, nv_clk_src_core);
+
+		switch (mast & 0x00000c00) {
+		case 0x00000000: return clk->read(clk, nv_clk_src_href);
+		case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4);
+		case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3);
+		default: return 0;
+		}
+	case nv_clk_src_shader:
+		P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16;
+		switch (mast & 0x00000030) {
+		case 0x00000000:
+			if (mast & 0x00000040)
+				return clk->read(clk, nv_clk_src_href) >> P;
+			return clk->read(clk, nv_clk_src_crystal) >> P;
+		case 0x00000010: break;
+		case 0x00000020: return read_pll(clk, 0x004028) >> P;
+		case 0x00000030: return read_pll(clk, 0x004020) >> P;
+		}
+		break;
+	case nv_clk_src_mem:
+		return 0;
+		break;
+	case nv_clk_src_vdec:
+		P = (read_div(clk) & 0x00000700) >> 8;
+
+		switch (mast & 0x00400000) {
+		case 0x00400000:
+			return clk->read(clk, nv_clk_src_core) >> P;
+			break;
+		default:
+			return 500000 >> P;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+	return 0;
+}
+
+static u32
+calc_pll(struct mcp77_clk_priv *priv, u32 reg,
+	 u32 clock, int *N, int *M, int *P)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll pll;
+	struct nvkm_clk *clk = &priv->base;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, reg, &pll);
+	if (ret)
+		return 0;
+
+	pll.vco2.max_freq = 0;
+	pll.refclk = clk->read(clk, nv_clk_src_href);
+	if (!pll.refclk)
+		return 0;
+
+	return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P);
+}
+
+static inline u32
+calc_P(u32 src, u32 target, int *div)
+{
+	u32 clk0 = src, clk1 = src;
+	for (*div = 0; *div <= 7; (*div)++) {
+		if (clk0 <= target) {
+			clk1 = clk0 << (*div ? 1 : 0);
+			break;
+		}
+		clk0 >>= 1;
+	}
+
+	if (target - clk0 <= clk1 - target)
+		return clk0;
+	(*div)--;
+	return clk1;
+}
+
+static int
+mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct mcp77_clk_priv *priv = (void *)clk;
+	const int shader = cstate->domain[nv_clk_src_shader];
+	const int core = cstate->domain[nv_clk_src_core];
+	const int vdec = cstate->domain[nv_clk_src_vdec];
+	u32 out = 0, clock = 0;
+	int N, M, P1, P2 = 0;
+	int divs = 0;
+
+	/* cclk: find suitable source, disable PLL if we can */
+	if (core < clk->read(clk, nv_clk_src_hclkm4))
+		out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs);
+
+	/* Calculate clock * 2, so shader clock can use it too */
+	clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1);
+
+	if (abs(core - out) <= abs(core - (clock >> 1))) {
+		priv->csrc = nv_clk_src_hclkm4;
+		priv->cctrl = divs << 16;
+	} else {
+		/* NVCTRL is actually used _after_ NVPOST, and after what we
+		 * call NVPLL. To make matters worse, NVPOST is an integer
+		 * divider instead of a right-shift number. */
+		if(P1 > 2) {
+			P2 = P1 - 2;
+			P1 = 2;
+		}
+
+		priv->csrc = nv_clk_src_core;
+		priv->ccoef = (N << 8) | M;
+
+		priv->cctrl = (P2 + 1) << 16;
+		priv->cpost = (1 << P1) << 16;
+	}
+
+	/* sclk: nvpll + divisor, href or spll */
+	out = 0;
+	if (shader == clk->read(clk, nv_clk_src_href)) {
+		priv->ssrc = nv_clk_src_href;
+	} else {
+		clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
+		if (priv->csrc == nv_clk_src_core)
+			out = calc_P((core << 1), shader, &divs);
+
+		if (abs(shader - out) <=
+		    abs(shader - clock) &&
+		   (divs + P2) <= 7) {
+			priv->ssrc = nv_clk_src_core;
+			priv->sctrl = (divs + P2) << 16;
+		} else {
+			priv->ssrc = nv_clk_src_shader;
+			priv->scoef = (N << 8) | M;
+			priv->sctrl = P1 << 16;
+		}
+	}
+
+	/* vclk */
+	out = calc_P(core, vdec, &divs);
+	clock = calc_P(500000, vdec, &P1);
+	if(abs(vdec - out) <= abs(vdec - clock)) {
+		priv->vsrc = nv_clk_src_cclk;
+		priv->vdiv = divs << 16;
+	} else {
+		priv->vsrc = nv_clk_src_vdec;
+		priv->vdiv = P1 << 16;
+	}
+
+	/* Print strategy! */
+	nv_debug(priv, "nvpll: %08x %08x %08x\n",
+			priv->ccoef, priv->cpost, priv->cctrl);
+	nv_debug(priv, " spll: %08x %08x %08x\n",
+			priv->scoef, priv->spost, priv->sctrl);
+	nv_debug(priv, " vdiv: %08x\n", priv->vdiv);
+	if (priv->csrc == nv_clk_src_hclkm4)
+		nv_debug(priv, "core: hrefm4\n");
+	else
+		nv_debug(priv, "core: nvpll\n");
+
+	if (priv->ssrc == nv_clk_src_hclkm4)
+		nv_debug(priv, "shader: hrefm4\n");
+	else if (priv->ssrc == nv_clk_src_core)
+		nv_debug(priv, "shader: nvpll\n");
+	else
+		nv_debug(priv, "shader: spll\n");
+
+	if (priv->vsrc == nv_clk_src_hclkm4)
+		nv_debug(priv, "vdec: 500MHz\n");
+	else
+		nv_debug(priv, "vdec: core\n");
+
+	return 0;
+}
+
+static int
+mcp77_clk_prog(struct nvkm_clk *clk)
+{
+	struct mcp77_clk_priv *priv = (void *)clk;
+	u32 pllmask = 0, mast;
+	unsigned long flags;
+	unsigned long *f = &flags;
+	int ret = 0;
+
+	ret = gt215_clk_pre(clk, f);
+	if (ret)
+		goto out;
+
+	/* First switch to safe clocks: href */
+	mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
+	mast &= ~0x00400e73;
+	mast |= 0x03000000;
+
+	switch (priv->csrc) {
+	case nv_clk_src_hclkm4:
+		nv_mask(clk, 0x4028, 0x00070000, priv->cctrl);
+		mast |= 0x00000002;
+		break;
+	case nv_clk_src_core:
+		nv_wr32(clk, 0x402c, priv->ccoef);
+		nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl);
+		nv_wr32(clk, 0x4040, priv->cpost);
+		pllmask |= (0x3 << 8);
+		mast |= 0x00000003;
+		break;
+	default:
+		nv_warn(priv,"Reclocking failed: unknown core clock\n");
+		goto resume;
+	}
+
+	switch (priv->ssrc) {
+	case nv_clk_src_href:
+		nv_mask(clk, 0x4020, 0x00070000, 0x00000000);
+		/* mast |= 0x00000000; */
+		break;
+	case nv_clk_src_core:
+		nv_mask(clk, 0x4020, 0x00070000, priv->sctrl);
+		mast |= 0x00000020;
+		break;
+	case nv_clk_src_shader:
+		nv_wr32(clk, 0x4024, priv->scoef);
+		nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl);
+		nv_wr32(clk, 0x4070, priv->spost);
+		pllmask |= (0x3 << 12);
+		mast |= 0x00000030;
+		break;
+	default:
+		nv_warn(priv,"Reclocking failed: unknown sclk clock\n");
+		goto resume;
+	}
+
+	if (!nv_wait(clk, 0x004080, pllmask, pllmask)) {
+		nv_warn(priv,"Reclocking failed: unstable PLLs\n");
+		goto resume;
+	}
+
+	switch (priv->vsrc) {
+	case nv_clk_src_cclk:
+		mast |= 0x00400000;
+	default:
+		nv_wr32(clk, 0x4600, priv->vdiv);
+	}
+
+	nv_wr32(clk, 0xc054, mast);
+
+resume:
+	/* Disable some PLLs and dividers when unused */
+	if (priv->csrc != nv_clk_src_core) {
+		nv_wr32(clk, 0x4040, 0x00000000);
+		nv_mask(clk, 0x4028, 0x80000000, 0x00000000);
+	}
+
+	if (priv->ssrc != nv_clk_src_shader) {
+		nv_wr32(clk, 0x4070, 0x00000000);
+		nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
+	}
+
+out:
+	if (ret == -EBUSY)
+		f = NULL;
+
+	gt215_clk_post(clk, f);
+	return ret;
+}
+
+static void
+mcp77_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static struct nvkm_domain
+mcp77_domains[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
+	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+	{ nv_clk_src_vdec   , 0xff, 0, "vdec", 1000 },
+	{ nv_clk_src_max }
+};
+
+static int
+mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct mcp77_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains,
+			      NULL, 0, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.read = mcp77_clk_read;
+	priv->base.calc = mcp77_clk_calc;
+	priv->base.prog = mcp77_clk_prog;
+	priv->base.tidy = mcp77_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass *
+mcp77_clk_oclass = &(struct nvkm_oclass) {
+	.handle = NV_SUBDEV(CLK, 0xaa),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = mcp77_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c
new file mode 100644
index 0000000..63dbbb5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit/nv04.h>
+
+struct nv04_clk_priv {
+	struct nvkm_clk base;
+};
+
+int
+nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info,
+		  int clk, struct nvkm_pll_vals *pv)
+{
+	int N1, M1, N2, M2, P;
+	int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
+	if (ret) {
+		pv->refclk = info->refclk;
+		pv->N1 = N1;
+		pv->M1 = M1;
+		pv->N2 = N2;
+		pv->M2 = M2;
+		pv->log2P = P;
+	}
+	return ret;
+}
+
+int
+nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv)
+{
+	struct nvkm_devinit *devinit = nvkm_devinit(clk);
+	int cv = nvkm_bios(clk)->version.chip;
+
+	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+	    cv >= 0x40) {
+		if (reg1 > 0x405c)
+			setPLL_double_highregs(devinit, reg1, pv);
+		else
+			setPLL_double_lowregs(devinit, reg1, pv);
+	} else
+		setPLL_single(devinit, reg1, pv);
+
+	return 0;
+}
+
+static struct nvkm_domain
+nv04_domain[] = {
+	{ nv_clk_src_max }
+};
+
+static int
+nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv04_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, nv04_domain,
+			      NULL, 0, false, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.pll_calc = nv04_clk_pll_calc;
+	priv->base.pll_prog = nv04_clk_pll_prog;
+	return 0;
+}
+
+struct nvkm_oclass
+nv04_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c
new file mode 100644
index 0000000..ed83813
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+struct nv40_clk_priv {
+	struct nvkm_clk base;
+	u32 ctrl;
+	u32 npll_ctrl;
+	u32 npll_coef;
+	u32 spll;
+};
+
+static struct nvkm_domain
+nv40_domain[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
+	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+	{ nv_clk_src_max }
+};
+
+static u32
+read_pll_1(struct nv40_clk_priv *priv, u32 reg)
+{
+	u32 ctrl = nv_rd32(priv, reg + 0x00);
+	int P = (ctrl & 0x00070000) >> 16;
+	int N = (ctrl & 0x0000ff00) >> 8;
+	int M = (ctrl & 0x000000ff) >> 0;
+	u32 ref = 27000, clk = 0;
+
+	if (ctrl & 0x80000000)
+		clk = ref * N / M;
+
+	return clk >> P;
+}
+
+static u32
+read_pll_2(struct nv40_clk_priv *priv, u32 reg)
+{
+	u32 ctrl = nv_rd32(priv, reg + 0x00);
+	u32 coef = nv_rd32(priv, reg + 0x04);
+	int N2 = (coef & 0xff000000) >> 24;
+	int M2 = (coef & 0x00ff0000) >> 16;
+	int N1 = (coef & 0x0000ff00) >> 8;
+	int M1 = (coef & 0x000000ff) >> 0;
+	int P = (ctrl & 0x00070000) >> 16;
+	u32 ref = 27000, clk = 0;
+
+	if ((ctrl & 0x80000000) && M1) {
+		clk = ref * N1 / M1;
+		if ((ctrl & 0x40000100) == 0x40000000) {
+			if (M2)
+				clk = clk * N2 / M2;
+			else
+				clk = 0;
+		}
+	}
+
+	return clk >> P;
+}
+
+static u32
+read_clk(struct nv40_clk_priv *priv, u32 src)
+{
+	switch (src) {
+	case 3:
+		return read_pll_2(priv, 0x004000);
+	case 2:
+		return read_pll_1(priv, 0x004008);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+nv40_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct nv40_clk_priv *priv = (void *)clk;
+	u32 mast = nv_rd32(priv, 0x00c040);
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return nv_device(priv)->crystal;
+	case nv_clk_src_href:
+		return 100000; /*XXX: PCIE/AGP differ*/
+	case nv_clk_src_core:
+		return read_clk(priv, (mast & 0x00000003) >> 0);
+	case nv_clk_src_shader:
+		return read_clk(priv, (mast & 0x00000030) >> 4);
+	case nv_clk_src_mem:
+		return read_pll_2(priv, 0x4020);
+	default:
+		break;
+	}
+
+	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+	return -EINVAL;
+}
+
+static int
+nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk,
+		  int *N1, int *M1, int *N2, int *M2, int *log2P)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll pll;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, reg, &pll);
+	if (ret)
+		return ret;
+
+	if (clk < pll.vco1.max_freq)
+		pll.vco2.max_freq = 0;
+
+	ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P);
+	if (ret == 0)
+		return -ERANGE;
+
+	return ret;
+}
+
+static int
+nv40_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct nv40_clk_priv *priv = (void *)clk;
+	int gclk = cstate->domain[nv_clk_src_core];
+	int sclk = cstate->domain[nv_clk_src_shader];
+	int N1, M1, N2, M2, log2P;
+	int ret;
+
+	/* core/geometric clock */
+	ret = nv40_clk_calc_pll(priv, 0x004000, gclk,
+				&N1, &M1, &N2, &M2, &log2P);
+	if (ret < 0)
+		return ret;
+
+	if (N2 == M2) {
+		priv->npll_ctrl = 0x80000100 | (log2P << 16);
+		priv->npll_coef = (N1 << 8) | M1;
+	} else {
+		priv->npll_ctrl = 0xc0000000 | (log2P << 16);
+		priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+	}
+
+	/* use the second pll for shader/rop clock, if it differs from core */
+	if (sclk && sclk != gclk) {
+		ret = nv40_clk_calc_pll(priv, 0x004008, sclk,
+					&N1, &M1, NULL, NULL, &log2P);
+		if (ret < 0)
+			return ret;
+
+		priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
+		priv->ctrl = 0x00000223;
+	} else {
+		priv->spll = 0x00000000;
+		priv->ctrl = 0x00000333;
+	}
+
+	return 0;
+}
+
+static int
+nv40_clk_prog(struct nvkm_clk *clk)
+{
+	struct nv40_clk_priv *priv = (void *)clk;
+	nv_mask(priv, 0x00c040, 0x00000333, 0x00000000);
+	nv_wr32(priv, 0x004004, priv->npll_coef);
+	nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl);
+	nv_mask(priv, 0x004008, 0xc007ffff, priv->spll);
+	mdelay(5);
+	nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl);
+	return 0;
+}
+
+static void
+nv40_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static int
+nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv40_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, nv40_domain,
+			      NULL, 0, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.pll_calc = nv04_clk_pll_calc;
+	priv->base.pll_prog = nv04_clk_pll_prog;
+	priv->base.read = nv40_clk_read;
+	priv->base.calc = nv40_clk_calc;
+	priv->base.prog = nv40_clk_prog;
+	priv->base.tidy = nv40_clk_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+nv40_clk_oclass = {
+	.handle = NV_SUBDEV(CLK, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
new file mode 100644
index 0000000..9b4ffd6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "pll.h"
+#include "seq.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+static u32
+read_div(struct nv50_clk_priv *priv)
+{
+	switch (nv_device(priv)->chipset) {
+	case 0x50: /* it exists, but only has bit 31, not the dividers.. */
+	case 0x84:
+	case 0x86:
+	case 0x98:
+	case 0xa0:
+		return nv_rd32(priv, 0x004700);
+	case 0x92:
+	case 0x94:
+	case 0x96:
+		return nv_rd32(priv, 0x004800);
+	default:
+		return 0x00000000;
+	}
+}
+
+static u32
+read_pll_src(struct nv50_clk_priv *priv, u32 base)
+{
+	struct nvkm_clk *clk = &priv->base;
+	u32 coef, ref = clk->read(clk, nv_clk_src_crystal);
+	u32 rsel = nv_rd32(priv, 0x00e18c);
+	int P, N, M, id;
+
+	switch (nv_device(priv)->chipset) {
+	case 0x50:
+	case 0xa0:
+		switch (base) {
+		case 0x4020:
+		case 0x4028: id = !!(rsel & 0x00000004); break;
+		case 0x4008: id = !!(rsel & 0x00000008); break;
+		case 0x4030: id = 0; break;
+		default:
+			nv_error(priv, "ref: bad pll 0x%06x\n", base);
+			return 0;
+		}
+
+		coef = nv_rd32(priv, 0x00e81c + (id * 0x0c));
+		ref *=  (coef & 0x01000000) ? 2 : 4;
+		P    =  (coef & 0x00070000) >> 16;
+		N    = ((coef & 0x0000ff00) >> 8) + 1;
+		M    = ((coef & 0x000000ff) >> 0) + 1;
+		break;
+	case 0x84:
+	case 0x86:
+	case 0x92:
+		coef = nv_rd32(priv, 0x00e81c);
+		P    = (coef & 0x00070000) >> 16;
+		N    = (coef & 0x0000ff00) >> 8;
+		M    = (coef & 0x000000ff) >> 0;
+		break;
+	case 0x94:
+	case 0x96:
+	case 0x98:
+		rsel = nv_rd32(priv, 0x00c050);
+		switch (base) {
+		case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
+		case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
+		case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
+		case 0x4030: rsel = 3; break;
+		default:
+			nv_error(priv, "ref: bad pll 0x%06x\n", base);
+			return 0;
+		}
+
+		switch (rsel) {
+		case 0: id = 1; break;
+		case 1: return clk->read(clk, nv_clk_src_crystal);
+		case 2: return clk->read(clk, nv_clk_src_href);
+		case 3: id = 0; break;
+		}
+
+		coef =  nv_rd32(priv, 0x00e81c + (id * 0x28));
+		P    = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7;
+		P   += (coef & 0x00070000) >> 16;
+		N    = (coef & 0x0000ff00) >> 8;
+		M    = (coef & 0x000000ff) >> 0;
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	if (M)
+		return (ref * N / M) >> P;
+
+	return 0;
+}
+
+static u32
+read_pll_ref(struct nv50_clk_priv *priv, u32 base)
+{
+	struct nvkm_clk *clk = &priv->base;
+	u32 src, mast = nv_rd32(priv, 0x00c040);
+
+	switch (base) {
+	case 0x004028:
+		src = !!(mast & 0x00200000);
+		break;
+	case 0x004020:
+		src = !!(mast & 0x00400000);
+		break;
+	case 0x004008:
+		src = !!(mast & 0x00010000);
+		break;
+	case 0x004030:
+		src = !!(mast & 0x02000000);
+		break;
+	case 0x00e810:
+		return clk->read(clk, nv_clk_src_crystal);
+	default:
+		nv_error(priv, "bad pll 0x%06x\n", base);
+		return 0;
+	}
+
+	if (src)
+		return clk->read(clk, nv_clk_src_href);
+
+	return read_pll_src(priv, base);
+}
+
+static u32
+read_pll(struct nv50_clk_priv *priv, u32 base)
+{
+	struct nvkm_clk *clk = &priv->base;
+	u32 mast = nv_rd32(priv, 0x00c040);
+	u32 ctrl = nv_rd32(priv, base + 0);
+	u32 coef = nv_rd32(priv, base + 4);
+	u32 ref = read_pll_ref(priv, base);
+	u32 freq = 0;
+	int N1, N2, M1, M2;
+
+	if (base == 0x004028 && (mast & 0x00100000)) {
+		/* wtf, appears to only disable post-divider on gt200 */
+		if (nv_device(priv)->chipset != 0xa0)
+			return clk->read(clk, nv_clk_src_dom6);
+	}
+
+	N2 = (coef & 0xff000000) >> 24;
+	M2 = (coef & 0x00ff0000) >> 16;
+	N1 = (coef & 0x0000ff00) >> 8;
+	M1 = (coef & 0x000000ff);
+	if ((ctrl & 0x80000000) && M1) {
+		freq = ref * N1 / M1;
+		if ((ctrl & 0x40000100) == 0x40000000) {
+			if (M2)
+				freq = freq * N2 / M2;
+			else
+				freq = 0;
+		}
+	}
+
+	return freq;
+}
+
+static int
+nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+	struct nv50_clk_priv *priv = (void *)clk;
+	u32 mast = nv_rd32(priv, 0x00c040);
+	u32 P = 0;
+
+	switch (src) {
+	case nv_clk_src_crystal:
+		return nv_device(priv)->crystal;
+	case nv_clk_src_href:
+		return 100000; /* PCIE reference clock */
+	case nv_clk_src_hclk:
+		return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000);
+	case nv_clk_src_hclkm3:
+		return clk->read(clk, nv_clk_src_hclk) * 3;
+	case nv_clk_src_hclkm3d2:
+		return clk->read(clk, nv_clk_src_hclk) * 3 / 2;
+	case nv_clk_src_host:
+		switch (mast & 0x30000000) {
+		case 0x00000000: return clk->read(clk, nv_clk_src_href);
+		case 0x10000000: break;
+		case 0x20000000: /* !0x50 */
+		case 0x30000000: return clk->read(clk, nv_clk_src_hclk);
+		}
+		break;
+	case nv_clk_src_core:
+		if (!(mast & 0x00100000))
+			P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16;
+		switch (mast & 0x00000003) {
+		case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
+		case 0x00000001: return clk->read(clk, nv_clk_src_dom6);
+		case 0x00000002: return read_pll(priv, 0x004020) >> P;
+		case 0x00000003: return read_pll(priv, 0x004028) >> P;
+		}
+		break;
+	case nv_clk_src_shader:
+		P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16;
+		switch (mast & 0x00000030) {
+		case 0x00000000:
+			if (mast & 0x00000080)
+				return clk->read(clk, nv_clk_src_host) >> P;
+			return clk->read(clk, nv_clk_src_crystal) >> P;
+		case 0x00000010: break;
+		case 0x00000020: return read_pll(priv, 0x004028) >> P;
+		case 0x00000030: return read_pll(priv, 0x004020) >> P;
+		}
+		break;
+	case nv_clk_src_mem:
+		P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16;
+		if (nv_rd32(priv, 0x004008) & 0x00000200) {
+			switch (mast & 0x0000c000) {
+			case 0x00000000:
+				return clk->read(clk, nv_clk_src_crystal) >> P;
+			case 0x00008000:
+			case 0x0000c000:
+				return clk->read(clk, nv_clk_src_href) >> P;
+			}
+		} else {
+			return read_pll(priv, 0x004008) >> P;
+		}
+		break;
+	case nv_clk_src_vdec:
+		P = (read_div(priv) & 0x00000700) >> 8;
+		switch (nv_device(priv)->chipset) {
+		case 0x84:
+		case 0x86:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+		case 0xa0:
+			switch (mast & 0x00000c00) {
+			case 0x00000000:
+				if (nv_device(priv)->chipset == 0xa0) /* wtf?? */
+					return clk->read(clk, nv_clk_src_core) >> P;
+				return clk->read(clk, nv_clk_src_crystal) >> P;
+			case 0x00000400:
+				return 0;
+			case 0x00000800:
+				if (mast & 0x01000000)
+					return read_pll(priv, 0x004028) >> P;
+				return read_pll(priv, 0x004030) >> P;
+			case 0x00000c00:
+				return clk->read(clk, nv_clk_src_core) >> P;
+			}
+			break;
+		case 0x98:
+			switch (mast & 0x00000c00) {
+			case 0x00000000:
+				return clk->read(clk, nv_clk_src_core) >> P;
+			case 0x00000400:
+				return 0;
+			case 0x00000800:
+				return clk->read(clk, nv_clk_src_hclkm3d2) >> P;
+			case 0x00000c00:
+				return clk->read(clk, nv_clk_src_mem) >> P;
+			}
+			break;
+		}
+		break;
+	case nv_clk_src_dom6:
+		switch (nv_device(priv)->chipset) {
+		case 0x50:
+		case 0xa0:
+			return read_pll(priv, 0x00e810) >> 2;
+		case 0x84:
+		case 0x86:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+		case 0x98:
+			P = (read_div(priv) & 0x00000007) >> 0;
+			switch (mast & 0x0c000000) {
+			case 0x00000000: return clk->read(clk, nv_clk_src_href);
+			case 0x04000000: break;
+			case 0x08000000: return clk->read(clk, nv_clk_src_hclk);
+			case 0x0c000000:
+				return clk->read(clk, nv_clk_src_hclkm3) >> P;
+			}
+			break;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+
+	nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+	return -EINVAL;
+}
+
+static u32
+calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll pll;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, reg, &pll);
+	if (ret)
+		return 0;
+
+	pll.vco2.max_freq = 0;
+	pll.refclk = read_pll_ref(priv, reg);
+	if (!pll.refclk)
+		return 0;
+
+	return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P);
+}
+
+static inline u32
+calc_div(u32 src, u32 target, int *div)
+{
+	u32 clk0 = src, clk1 = src;
+	for (*div = 0; *div <= 7; (*div)++) {
+		if (clk0 <= target) {
+			clk1 = clk0 << (*div ? 1 : 0);
+			break;
+		}
+		clk0 >>= 1;
+	}
+
+	if (target - clk0 <= clk1 - target)
+		return clk0;
+	(*div)--;
+	return clk1;
+}
+
+static inline u32
+clk_same(u32 a, u32 b)
+{
+	return ((a / 1000) == (b / 1000));
+}
+
+static int
+nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+	struct nv50_clk_priv *priv = (void *)clk;
+	struct nv50_clk_hwsq *hwsq = &priv->hwsq;
+	const int shader = cstate->domain[nv_clk_src_shader];
+	const int core = cstate->domain[nv_clk_src_core];
+	const int vdec = cstate->domain[nv_clk_src_vdec];
+	const int dom6 = cstate->domain[nv_clk_src_dom6];
+	u32 mastm = 0, mastv = 0;
+	u32 divsm = 0, divsv = 0;
+	int N, M, P1, P2;
+	int freq, out;
+
+	/* prepare a hwsq script from which we'll perform the reclock */
+	out = clk_init(hwsq, nv_subdev(clk));
+	if (out)
+		return out;
+
+	clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */
+	clk_nsec(hwsq, 8000);
+	clk_setf(hwsq, 0x10, 0x00); /* disable fb */
+	clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+	/* vdec: avoid modifying xpll until we know exactly how the other
+	 * clock domains work, i suspect at least some of them can also be
+	 * tied to xpll...
+	 */
+	if (vdec) {
+		/* see how close we can get using nvclk as a source */
+		freq = calc_div(core, vdec, &P1);
+
+		/* see how close we can get using xpll/hclk as a source */
+		if (nv_device(priv)->chipset != 0x98)
+			out = read_pll(priv, 0x004030);
+		else
+			out = clk->read(clk, nv_clk_src_hclkm3d2);
+		out = calc_div(out, vdec, &P2);
+
+		/* select whichever gets us closest */
+		if (abs(vdec - freq) <= abs(vdec - out)) {
+			if (nv_device(priv)->chipset != 0x98)
+				mastv |= 0x00000c00;
+			divsv |= P1 << 8;
+		} else {
+			mastv |= 0x00000800;
+			divsv |= P2 << 8;
+		}
+
+		mastm |= 0x00000c00;
+		divsm |= 0x00000700;
+	}
+
+	/* dom6: nfi what this is, but we're limited to various combinations
+	 * of the host clock frequency
+	 */
+	if (dom6) {
+		if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) {
+			mastv |= 0x00000000;
+		} else
+		if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) {
+			mastv |= 0x08000000;
+		} else {
+			freq = clk->read(clk, nv_clk_src_hclk) * 3;
+			freq = calc_div(freq, dom6, &P1);
+
+			mastv |= 0x0c000000;
+			divsv |= P1;
+		}
+
+		mastm |= 0x0c000000;
+		divsm |= 0x00000007;
+	}
+
+	/* vdec/dom6: switch to "safe" clocks temporarily, update dividers
+	 * and then switch to target clocks
+	 */
+	clk_mask(hwsq, mast, mastm, 0x00000000);
+	clk_mask(hwsq, divs, divsm, divsv);
+	clk_mask(hwsq, mast, mastm, mastv);
+
+	/* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6,
+	 * sclk to hclk) before reprogramming
+	 */
+	if (nv_device(priv)->chipset < 0x92)
+		clk_mask(hwsq, mast, 0x001000b0, 0x00100080);
+	else
+		clk_mask(hwsq, mast, 0x000000b3, 0x00000081);
+
+	/* core: for the moment at least, always use nvpll */
+	freq = calc_pll(priv, 0x4028, core, &N, &M, &P1);
+	if (freq == 0)
+		return -ERANGE;
+
+	clk_mask(hwsq, nvpll[0], 0xc03f0100,
+				 0x80000000 | (P1 << 19) | (P1 << 16));
+	clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M);
+
+	/* shader: tie to nvclk if possible, otherwise use spll.  have to be
+	 * very careful that the shader clock is at least twice the core, or
+	 * some chipsets will be very unhappy.  i expect most or all of these
+	 * cases will be handled by tying to nvclk, but it's possible there's
+	 * corners
+	 */
+	if (P1-- && shader == (core << 1)) {
+		clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16));
+		clk_mask(hwsq, mast, 0x00100033, 0x00000023);
+	} else {
+		freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
+		if (freq == 0)
+			return -ERANGE;
+
+		clk_mask(hwsq, spll[0], 0xc03f0100,
+					0x80000000 | (P1 << 19) | (P1 << 16));
+		clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M);
+		clk_mask(hwsq, mast, 0x00100033, 0x00000033);
+	}
+
+	/* restore normal operation */
+	clk_setf(hwsq, 0x10, 0x01); /* enable fb */
+	clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+	clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */
+	return 0;
+}
+
+static int
+nv50_clk_prog(struct nvkm_clk *clk)
+{
+	struct nv50_clk_priv *priv = (void *)clk;
+	return clk_exec(&priv->hwsq, true);
+}
+
+static void
+nv50_clk_tidy(struct nvkm_clk *clk)
+{
+	struct nv50_clk_priv *priv = (void *)clk;
+	clk_exec(&priv->hwsq, false);
+}
+
+int
+nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_clk_oclass *pclass = (void *)oclass;
+	struct nv50_clk_priv *priv;
+	int ret;
+
+	ret = nvkm_clk_create(parent, engine, oclass, pclass->domains,
+			      NULL, 0, false, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->hwsq.r_fifo = hwsq_reg(0x002504);
+	priv->hwsq.r_spll[0] = hwsq_reg(0x004020);
+	priv->hwsq.r_spll[1] = hwsq_reg(0x004024);
+	priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028);
+	priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c);
+	switch (nv_device(priv)->chipset) {
+	case 0x92:
+	case 0x94:
+	case 0x96:
+		priv->hwsq.r_divs = hwsq_reg(0x004800);
+		break;
+	default:
+		priv->hwsq.r_divs = hwsq_reg(0x004700);
+		break;
+	}
+	priv->hwsq.r_mast = hwsq_reg(0x00c040);
+
+	priv->base.read = nv50_clk_read;
+	priv->base.calc = nv50_clk_calc;
+	priv->base.prog = nv50_clk_prog;
+	priv->base.tidy = nv50_clk_tidy;
+	return 0;
+}
+
+static struct nvkm_domain
+nv50_domains[] = {
+	{ nv_clk_src_crystal, 0xff },
+	{ nv_clk_src_href   , 0xff },
+	{ nv_clk_src_core   , 0xff, 0, "core", 1000 },
+	{ nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+	{ nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
+	{ nv_clk_src_max }
+};
+
+struct nvkm_oclass *
+nv50_clk_oclass = &(struct nv50_clk_oclass) {
+	.base.handle = NV_SUBDEV(CLK, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_clk_ctor,
+		.dtor = _nvkm_clk_dtor,
+		.init = _nvkm_clk_init,
+		.fini = _nvkm_clk_fini,
+	},
+	.domains = nv50_domains,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h
new file mode 100644
index 0000000..0ead76a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_CLK_NV50_H__
+#define __NVKM_CLK_NV50_H__
+#include <subdev/bus/hwsq.h>
+#include <subdev/clk.h>
+
+struct nv50_clk_hwsq {
+	struct hwsq base;
+	struct hwsq_reg r_fifo;
+	struct hwsq_reg r_spll[2];
+	struct hwsq_reg r_nvpll[2];
+	struct hwsq_reg r_divs;
+	struct hwsq_reg r_mast;
+};
+
+struct nv50_clk_priv {
+	struct nvkm_clk base;
+	struct nv50_clk_hwsq hwsq;
+};
+
+int  nv50_clk_ctor(struct nvkm_object *, struct nvkm_object *,
+		     struct nvkm_oclass *, void *, u32,
+		     struct nvkm_object **);
+
+struct nv50_clk_oclass {
+	struct nvkm_oclass base;
+	struct nvkm_domain *domains;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h
new file mode 100644
index 0000000..44020a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h
@@ -0,0 +1,11 @@
+#ifndef __NVKM_PLL_H__
+#define __NVKM_PLL_H__
+#include <core/os.h>
+struct nvkm_subdev;
+struct nvbios_pll;
+
+int nv04_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq,
+		  int *N1, int *M1, int *N2, int *M2, int *P);
+int gt215_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq,
+		  int *N, int *fN, int *M, int *P);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c
new file mode 100644
index 0000000..783a3e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+int
+gt215_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info,
+	       u32 freq, int *pN, int *pfN, int *pM, int *P)
+{
+	u32 best_err = ~0, err;
+	int M, lM, hM, N, fN;
+
+	*P = info->vco1.max_freq / freq;
+	if (*P > info->max_p)
+		*P = info->max_p;
+	if (*P < info->min_p)
+		*P = info->min_p;
+
+	lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq;
+	lM = max(lM, (int)info->vco1.min_m);
+	hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq;
+	hM = min(hM, (int)info->vco1.max_m);
+	lM = min(lM, hM);
+
+	for (M = lM; M <= hM; M++) {
+		u32 tmp = freq * *P * M;
+		N  = tmp / info->refclk;
+		fN = tmp % info->refclk;
+
+		if (!pfN) {
+			if (fN >= info->refclk / 2)
+				N++;
+		} else {
+			if (fN <  info->refclk / 2)
+				N--;
+			fN = tmp - (N * info->refclk);
+		}
+
+		if (N < info->vco1.min_n)
+			continue;
+		if (N > info->vco1.max_n)
+			break;
+
+		err = abs(freq - (info->refclk * N / M / *P));
+		if (err < best_err) {
+			best_err = err;
+			*pN = N;
+			*pM = M;
+		}
+
+		if (pfN) {
+			*pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
+			*pfN = (*pfN - 4096) & 0xffff;
+			return freq;
+		}
+	}
+
+	if (unlikely(best_err == ~0)) {
+		nv_error(subdev, "unable to find matching pll values\n");
+		return -EINVAL;
+	}
+
+	return info->refclk * *pN / *pM / *P;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c
new file mode 100644
index 0000000..f229289
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1993-2003 NVIDIA, Corporation
+ * Copyright 2007-2009 Stuart Bennett
+ *
+ * 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 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 "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+static int
+getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
+	      int *pN, int *pM, int *pP)
+{
+	/* Find M, N and P for a single stage PLL
+	 *
+	 * Note that some bioses (NV3x) have lookup tables of precomputed MNP
+	 * values, but we're too lazy to use those atm
+	 *
+	 * "clk" parameter in kHz
+	 * returns calculated clock
+	 */
+	struct nvkm_bios *bios = nvkm_bios(subdev);
+	int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
+	int minM = info->vco1.min_m, maxM = info->vco1.max_m;
+	int minN = info->vco1.min_n, maxN = info->vco1.max_n;
+	int minU = info->vco1.min_inputfreq;
+	int maxU = info->vco1.max_inputfreq;
+	int minP = info->min_p;
+	int maxP = info->max_p_usable;
+	int crystal = info->refclk;
+	int M, N, thisP, P;
+	int clkP, calcclk;
+	int delta, bestdelta = INT_MAX;
+	int bestclk = 0;
+
+	/* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
+	/* possibly correlated with introduction of 27MHz crystal */
+	if (bios->version.major < 0x60) {
+		int cv = bios->version.chip;
+		if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
+			if (clk > 250000)
+				maxM = 6;
+			if (clk > 340000)
+				maxM = 2;
+		} else if (cv < 0x40) {
+			if (clk > 150000)
+				maxM = 6;
+			if (clk > 200000)
+				maxM = 4;
+			if (clk > 340000)
+				maxM = 2;
+		}
+	}
+
+	P = 1 << maxP;
+	if ((clk * P) < minvco) {
+		minvco = clk * maxP;
+		maxvco = minvco * 2;
+	}
+
+	if (clk + clk/200 > maxvco)	/* +0.5% */
+		maxvco = clk + clk/200;
+
+	/* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
+	for (thisP = minP; thisP <= maxP; thisP++) {
+		P = 1 << thisP;
+		clkP = clk * P;
+
+		if (clkP < minvco)
+			continue;
+		if (clkP > maxvco)
+			return bestclk;
+
+		for (M = minM; M <= maxM; M++) {
+			if (crystal/M < minU)
+				return bestclk;
+			if (crystal/M > maxU)
+				continue;
+
+			/* add crystal/2 to round better */
+			N = (clkP * M + crystal/2) / crystal;
+
+			if (N < minN)
+				continue;
+			if (N > maxN)
+				break;
+
+			/* more rounding additions */
+			calcclk = ((N * crystal + P/2) / P + M/2) / M;
+			delta = abs(calcclk - clk);
+			/* we do an exhaustive search rather than terminating
+			 * on an optimality condition...
+			 */
+			if (delta < bestdelta) {
+				bestdelta = delta;
+				bestclk = calcclk;
+				*pN = N;
+				*pM = M;
+				*pP = thisP;
+				if (delta == 0)	/* except this one */
+					return bestclk;
+			}
+		}
+	}
+
+	return bestclk;
+}
+
+static int
+getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
+	      int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
+{
+	/* Find M, N and P for a two stage PLL
+	 *
+	 * Note that some bioses (NV30+) have lookup tables of precomputed MNP
+	 * values, but we're too lazy to use those atm
+	 *
+	 * "clk" parameter in kHz
+	 * returns calculated clock
+	 */
+	int chip_version = nvkm_bios(subdev)->version.chip;
+	int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
+	int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
+	int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
+	int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
+	int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
+	int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
+	int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
+	int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;
+	int maxlog2P = info->max_p_usable;
+	int crystal = info->refclk;
+	bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
+	int M1, N1, M2, N2, log2P;
+	int clkP, calcclk1, calcclk2, calcclkout;
+	int delta, bestdelta = INT_MAX;
+	int bestclk = 0;
+
+	int vco2 = (maxvco2 - maxvco2/200) / 2;
+	for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
+		;
+	clkP = clk << log2P;
+
+	if (maxvco2 < clk + clk/200)	/* +0.5% */
+		maxvco2 = clk + clk/200;
+
+	for (M1 = minM1; M1 <= maxM1; M1++) {
+		if (crystal/M1 < minU1)
+			return bestclk;
+		if (crystal/M1 > maxU1)
+			continue;
+
+		for (N1 = minN1; N1 <= maxN1; N1++) {
+			calcclk1 = crystal * N1 / M1;
+			if (calcclk1 < minvco1)
+				continue;
+			if (calcclk1 > maxvco1)
+				break;
+
+			for (M2 = minM2; M2 <= maxM2; M2++) {
+				if (calcclk1/M2 < minU2)
+					break;
+				if (calcclk1/M2 > maxU2)
+					continue;
+
+				/* add calcclk1/2 to round better */
+				N2 = (clkP * M2 + calcclk1/2) / calcclk1;
+				if (N2 < minN2)
+					continue;
+				if (N2 > maxN2)
+					break;
+
+				if (!fixedgain2) {
+					if (chip_version < 0x60)
+						if (N2/M2 < 4 || N2/M2 > 10)
+							continue;
+
+					calcclk2 = calcclk1 * N2 / M2;
+					if (calcclk2 < minvco2)
+						break;
+					if (calcclk2 > maxvco2)
+						continue;
+				} else
+					calcclk2 = calcclk1;
+
+				calcclkout = calcclk2 >> log2P;
+				delta = abs(calcclkout - clk);
+				/* we do an exhaustive search rather than terminating
+				 * on an optimality condition...
+				 */
+				if (delta < bestdelta) {
+					bestdelta = delta;
+					bestclk = calcclkout;
+					*pN1 = N1;
+					*pM1 = M1;
+					*pN2 = N2;
+					*pM2 = M2;
+					*pP = log2P;
+					if (delta == 0)	/* except this one */
+						return bestclk;
+				}
+			}
+		}
+	}
+
+	return bestclk;
+}
+
+int
+nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq,
+	      int *N1, int *M1, int *N2, int *M2, int *P)
+{
+	int ret;
+
+	if (!info->vco2.max_freq || !N2) {
+		ret = getMNP_single(subdev, info, freq, N1, M1, P);
+		if (N2) {
+			*N2 = 1;
+			*M2 = 1;
+		}
+	} else {
+		ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
+	}
+
+	if (!ret)
+		nv_error(subdev, "unable to compute acceptable pll values\n");
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h
new file mode 100644
index 0000000..d717e8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h
@@ -0,0 +1,14 @@
+#ifndef __NVKM_CLK_SEQ_H__
+#define __NVKM_CLK_SEQ_H__
+#include <subdev/bus/hwsq.h>
+
+#define clk_init(s,p)       hwsq_init(&(s)->base, (p))
+#define clk_exec(s,e)       hwsq_exec(&(s)->base, (e))
+#define clk_have(s,r)       ((s)->r_##r.addr != 0x000000)
+#define clk_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define clk_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define clk_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define clk_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
+#define clk_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
+#define clk_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
new file mode 100644
index 0000000..793e73d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
@@ -0,0 +1,14 @@
+nvkm-y += nvkm/subdev/devinit/base.o
+nvkm-y += nvkm/subdev/devinit/nv04.o
+nvkm-y += nvkm/subdev/devinit/nv05.o
+nvkm-y += nvkm/subdev/devinit/nv10.o
+nvkm-y += nvkm/subdev/devinit/nv1a.o
+nvkm-y += nvkm/subdev/devinit/nv20.o
+nvkm-y += nvkm/subdev/devinit/nv50.o
+nvkm-y += nvkm/subdev/devinit/g84.o
+nvkm-y += nvkm/subdev/devinit/g98.o
+nvkm-y += nvkm/subdev/devinit/gt215.o
+nvkm-y += nvkm/subdev/devinit/mcp89.o
+nvkm-y += nvkm/subdev/devinit/gf100.o
+nvkm-y += nvkm/subdev/devinit/gm107.o
+nvkm-y += nvkm/subdev/devinit/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
new file mode 100644
index 0000000..b0d7c5f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/vga.h>
+
+int
+_nvkm_devinit_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_devinit *devinit = (void *)object;
+
+	/* force full reinit on resume */
+	if (suspend)
+		devinit->post = true;
+
+	/* unlock the extended vga crtc regs */
+	nv_lockvgac(devinit, false);
+
+	return nvkm_subdev_fini(&devinit->base, suspend);
+}
+
+int
+_nvkm_devinit_init(struct nvkm_object *object)
+{
+	struct nvkm_devinit_impl *impl = (void *)object->oclass;
+	struct nvkm_devinit *devinit = (void *)object;
+	int ret;
+
+	ret = nvkm_subdev_init(&devinit->base);
+	if (ret)
+		return ret;
+
+	ret = impl->post(&devinit->base, devinit->post);
+	if (ret)
+		return ret;
+
+	if (impl->disable)
+		nv_device(devinit)->disable_mask |= impl->disable(devinit);
+	return 0;
+}
+
+void
+_nvkm_devinit_dtor(struct nvkm_object *object)
+{
+	struct nvkm_devinit *devinit = (void *)object;
+
+	/* lock crtc regs */
+	nv_lockvgac(devinit, true);
+
+	nvkm_subdev_destroy(&devinit->base);
+}
+
+int
+nvkm_devinit_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, int size, void **pobject)
+{
+	struct nvkm_devinit_impl *impl = (void *)oclass;
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_devinit *devinit;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "DEVINIT",
+				  "init", size, pobject);
+	devinit = *pobject;
+	if (ret)
+		return ret;
+
+	devinit->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false);
+	devinit->meminit = impl->meminit;
+	devinit->pll_set = impl->pll_set;
+	devinit->mmio    = impl->mmio;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h
new file mode 100644
index 0000000..36684c3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include <core/device.h>
+#include <subdev/fb/regsnv04.h>
+
+#define NV04_PFB_DEBUG_0					0x00100080
+#	define NV04_PFB_DEBUG_0_PAGE_MODE			0x00000001
+#	define NV04_PFB_DEBUG_0_REFRESH_OFF			0x00000010
+#	define NV04_PFB_DEBUG_0_REFRESH_COUNTX64		0x00003f00
+#	define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK		0x00004000
+#	define NV04_PFB_DEBUG_0_SAFE_MODE			0x00008000
+#	define NV04_PFB_DEBUG_0_ALOM_ENABLE			0x00010000
+#	define NV04_PFB_DEBUG_0_CASOE				0x00100000
+#	define NV04_PFB_DEBUG_0_CKE_INVERT			0x10000000
+#	define NV04_PFB_DEBUG_0_REFINC				0x20000000
+#	define NV04_PFB_DEBUG_0_SAVE_POWER_OFF			0x40000000
+#define NV04_PFB_CFG0						0x00100200
+#	define NV04_PFB_CFG0_SCRAMBLE				0x20000000
+#define NV04_PFB_CFG1						0x00100204
+#define NV04_PFB_SCRAMBLE(i)                         (0x00100400 + 4 * (i))
+
+#define NV10_PFB_REFCTRL					0x00100210
+#	define NV10_PFB_REFCTRL_VALID_1				(1 << 31)
+
+static inline struct io_mapping *
+fbmem_init(struct nvkm_device *dev)
+{
+	return io_mapping_create_wc(nv_device_resource_start(dev, 1),
+				    nv_device_resource_len(dev, 1));
+}
+
+static inline void
+fbmem_fini(struct io_mapping *fb)
+{
+	io_mapping_free(fb);
+}
+
+static inline u32
+fbmem_peek(struct io_mapping *fb, u32 off)
+{
+	u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
+	u32 val = ioread32(p + (off & ~PAGE_MASK));
+	io_mapping_unmap_atomic(p);
+	return val;
+}
+
+static inline void
+fbmem_poke(struct io_mapping *fb, u32 off, u32 val)
+{
+	u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
+	iowrite32(val, p + (off & ~PAGE_MASK));
+	wmb();
+	io_mapping_unmap_atomic(p);
+}
+
+static inline bool
+fbmem_readback(struct io_mapping *fb, u32 off, u32 val)
+{
+	fbmem_poke(fb, off, val);
+	return val == fbmem_peek(fb, off);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
new file mode 100644
index 0000000..ca776ce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+g84_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r001540 = nv_rd32(priv, 0x001540);
+	u32 r00154c = nv_rd32(priv, 0x00154c);
+	u64 disable = 0ULL;
+
+	if (!(r001540 & 0x40000000)) {
+		disable |= (1ULL << NVDEV_ENGINE_MPEG);
+		disable |= (1ULL << NVDEV_ENGINE_VP);
+		disable |= (1ULL << NVDEV_ENGINE_BSP);
+		disable |= (1ULL << NVDEV_ENGINE_CIPHER);
+	}
+
+	if (!(r00154c & 0x00000004))
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+	if (!(r00154c & 0x00000020))
+		disable |= (1ULL << NVDEV_ENGINE_BSP);
+	if (!(r00154c & 0x00000040))
+		disable |= (1ULL << NVDEV_ENGINE_CIPHER);
+
+	return disable;
+}
+
+struct nvkm_oclass *
+g84_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x84),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = nv50_devinit_pll_set,
+	.disable = g84_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
new file mode 100644
index 0000000..d29bace
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+g98_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r001540 = nv_rd32(priv, 0x001540);
+	u32 r00154c = nv_rd32(priv, 0x00154c);
+	u64 disable = 0ULL;
+
+	if (!(r001540 & 0x40000000)) {
+		disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+		disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+		disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+	}
+
+	if (!(r00154c & 0x00000004))
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+	if (!(r00154c & 0x00000020))
+		disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+	if (!(r00154c & 0x00000040))
+		disable |= (1ULL << NVDEV_ENGINE_SEC);
+
+	return disable;
+}
+
+struct nvkm_oclass *
+g98_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x98),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = nv50_devinit_pll_set,
+	.disable = g98_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
new file mode 100644
index 0000000..e8778c6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+
+int
+gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll info;
+	int N, fN, M, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret)
+		return ret;
+
+	ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+	if (ret < 0)
+		return ret;
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+	case PLL_VPLL2:
+	case PLL_VPLL3:
+		nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
+		nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
+		nv_wr32(priv, info.reg + 0x10, fN << 16);
+		break;
+	default:
+		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static u64
+gf100_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r022500 = nv_rd32(priv, 0x022500);
+	u64 disable = 0ULL;
+
+	if (r022500 & 0x00000001)
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+	if (r022500 & 0x00000002) {
+		disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+		disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+	}
+
+	if (r022500 & 0x00000004)
+		disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+	if (r022500 & 0x00000008)
+		disable |= (1ULL << NVDEV_ENGINE_MSENC);
+	if (r022500 & 0x00000100)
+		disable |= (1ULL << NVDEV_ENGINE_CE0);
+	if (r022500 & 0x00000200)
+		disable |= (1ULL << NVDEV_ENGINE_CE1);
+
+	return disable;
+}
+
+static int
+gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 size,
+		   struct nvkm_object **pobject)
+{
+	struct nv50_devinit_priv *priv;
+	int ret;
+
+	ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	if (nv_rd32(priv, 0x022500) & 0x00000001)
+		priv->base.post = true;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+gf100_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = gf100_devinit_pll_set,
+	.disable = gf100_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
new file mode 100644
index 0000000..b345a53
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+u64
+gm107_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r021c00 = nv_rd32(priv, 0x021c00);
+	u32 r021c04 = nv_rd32(priv, 0x021c04);
+	u64 disable = 0ULL;
+
+	if (r021c00 & 0x00000001)
+		disable |= (1ULL << NVDEV_ENGINE_CE0);
+	if (r021c00 & 0x00000004)
+		disable |= (1ULL << NVDEV_ENGINE_CE2);
+	if (r021c04 & 0x00000001)
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+	return disable;
+}
+
+struct nvkm_oclass *
+gm107_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x07),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = gf100_devinit_pll_set,
+	.disable = gm107_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
new file mode 100644
index 0000000..535172c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pmu.h>
+
+static void
+pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	int i;
+
+	nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
+	for (i = 0; i < len; i += 4) {
+		if ((i & 0xff) == 0)
+			nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
+		nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
+	}
+
+	while (i & 0xff) {
+		nv_wr32(priv, 0x10a184, 0x00000000);
+		i += 4;
+	}
+}
+
+static void
+pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	int i;
+
+	nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
+	for (i = 0; i < len; i += 4)
+		nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
+}
+
+static u32
+pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
+{
+	nv_wr32(priv, 0x10a1c0, argp);
+	nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
+	return nv_rd32(priv, 0x10a1c4);
+}
+
+static void
+pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
+{
+	nv_wr32(priv, 0x10a104, init_addr);
+	nv_wr32(priv, 0x10a10c, 0x00000000);
+	nv_wr32(priv, 0x10a100, 0x00000002);
+}
+
+static int
+pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
+	 u32 *init_addr_pmu, u32 *args_addr_pmu)
+{
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pmuR pmu;
+
+	if (!nvbios_pmuRm(bios, type, &pmu)) {
+		nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
+		return -EINVAL;
+	}
+
+	if (!post)
+		return 0;
+
+	pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
+	pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
+	pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
+
+	if (init_addr_pmu) {
+		*init_addr_pmu = pmu.init_addr_pmu;
+		*args_addr_pmu = pmu.args_addr_pmu;
+		return 0;
+	}
+
+	return pmu_exec(priv, pmu.init_addr_pmu), 0;
+}
+
+static int
+gm204_devinit_post(struct nvkm_subdev *subdev, bool post)
+{
+	struct nv50_devinit_priv *priv = (void *)nvkm_devinit(subdev);
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct bit_entry bit_I;
+	u32 init, args;
+	int ret;
+
+	if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
+					    bit_I.length < 0x1c) {
+		nv_error(priv, "VBIOS PMU init data not found\n");
+		return -EINVAL;
+	}
+
+	/* reset PMU and load init table parser ucode */
+	if (post) {
+		nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
+		nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
+		nv_rd32(priv, 0x000200);
+		while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
+		}
+	}
+
+	ret = pmu_load(priv, 0x04, post, &init, &args);
+	if (ret)
+		return ret;
+
+	/* upload first chunk of init data */
+	if (post) {
+		u32 pmu = pmu_args(priv, args + 0x08, 0x08);
+		u32 img = nv_ro16(bios, bit_I.offset + 0x14);
+		u32 len = nv_ro16(bios, bit_I.offset + 0x16);
+		pmu_data(priv, pmu, img, len);
+	}
+
+	/* upload second chunk of init data */
+	if (post) {
+		u32 pmu = pmu_args(priv, args + 0x08, 0x10);
+		u32 img = nv_ro16(bios, bit_I.offset + 0x18);
+		u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
+		pmu_data(priv, pmu, img, len);
+	}
+
+	/* execute init tables */
+	if (post) {
+		nv_wr32(priv, 0x10a040, 0x00005000);
+		pmu_exec(priv, init);
+		while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
+		}
+	}
+
+	/* load and execute some other ucode image (bios therm?) */
+	return pmu_load(priv, 0x01, post, NULL, NULL);
+}
+
+struct nvkm_oclass *
+gm204_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x07),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = gf100_devinit_pll_set,
+	.disable = gm107_devinit_disable,
+	.post = gm204_devinit_post,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
new file mode 100644
index 0000000..6a3e8d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+
+int
+gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll info;
+	int N, fN, M, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret)
+		return ret;
+
+	ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+	if (ret < 0)
+		return ret;
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+		nv_wr32(priv, info.reg + 0, 0x50000610);
+		nv_mask(priv, info.reg + 4, 0x003fffff,
+					    (P << 16) | (M << 8) | N);
+		nv_wr32(priv, info.reg + 8, fN);
+		break;
+	default:
+		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static u64
+gt215_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r001540 = nv_rd32(priv, 0x001540);
+	u32 r00154c = nv_rd32(priv, 0x00154c);
+	u64 disable = 0ULL;
+
+	if (!(r001540 & 0x40000000)) {
+		disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+		disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+	}
+
+	if (!(r00154c & 0x00000004))
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+	if (!(r00154c & 0x00000020))
+		disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+	if (!(r00154c & 0x00000200))
+		disable |= (1ULL << NVDEV_ENGINE_CE0);
+
+	return disable;
+}
+
+static u32
+gt215_devinit_mmio_part[] = {
+	0x100720, 0x1008bc, 4,
+	0x100a20, 0x100adc, 4,
+	0x100d80, 0x100ddc, 4,
+	0x110000, 0x110f9c, 4,
+	0x111000, 0x11103c, 8,
+	0x111080, 0x1110fc, 4,
+	0x111120, 0x1111fc, 4,
+	0x111300, 0x1114bc, 4,
+	0,
+};
+
+static u32
+gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 *mmio = gt215_devinit_mmio_part;
+
+	/* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP
+	 * instructions which touch registers that may not even exist on
+	 * some configurations (Quadro 400), which causes the register
+	 * interface to screw up for some amount of time after attempting to
+	 * write to one of these, and results in all sorts of things going
+	 * horribly wrong.
+	 *
+	 * the binary driver avoids touching these registers at all, however,
+	 * the video bios doesn't care and does what the scripts say.  it's
+	 * presumed that the io-port access to priv registers isn't effected
+	 * by the screw-up bug mentioned above.
+	 *
+	 * really, a new opcode should've been invented to handle these
+	 * requirements, but whatever, it's too late for that now.
+	 */
+	while (mmio[0]) {
+		if (addr >= mmio[0] && addr <= mmio[1]) {
+			u32 part = (addr / mmio[2]) & 7;
+			if (!priv->r001540)
+				priv->r001540 = nv_rd32(priv, 0x001540);
+			if (part >= hweight8((priv->r001540 >> 16) & 0xff))
+				return ~0;
+			return addr;
+		}
+		mmio += 3;
+	}
+
+	return addr;
+}
+
+struct nvkm_oclass *
+gt215_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0xa3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = gt215_devinit_pll_set,
+	.disable = gt215_devinit_disable,
+	.mmio    = gt215_devinit_mmio,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
new file mode 100644
index 0000000..55cf48b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+mcp89_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r001540 = nv_rd32(priv, 0x001540);
+	u32 r00154c = nv_rd32(priv, 0x00154c);
+	u64 disable = 0;
+
+	if (!(r001540 & 0x40000000)) {
+		disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+		disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+	}
+
+	if (!(r00154c & 0x00000004))
+		disable |= (1ULL << NVDEV_ENGINE_DISP);
+	if (!(r00154c & 0x00000020))
+		disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+	if (!(r00154c & 0x00000040))
+		disable |= (1ULL << NVDEV_ENGINE_VIC);
+	if (!(r00154c & 0x00000200))
+		disable |= (1ULL << NVDEV_ENGINE_CE0);
+
+	return disable;
+}
+
+struct nvkm_oclass *
+mcp89_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0xaf),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = gt215_devinit_pll_set,
+	.disable = mcp89_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
new file mode 100644
index 0000000..03a0da8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/vga.h>
+
+static void
+nv04_devinit_meminit(struct nvkm_devinit *devinit)
+{
+	struct nv04_devinit_priv *priv = (void *)devinit;
+	u32 patt = 0xdeadbeef;
+	struct io_mapping *fb;
+	int i;
+
+	/* Map the framebuffer aperture */
+	fb = fbmem_init(nv_device(priv));
+	if (!fb) {
+		nv_error(priv, "failed to map fb\n");
+		return;
+	}
+
+	/* Sequencer and refresh off */
+	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
+	nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
+
+	nv_mask(priv, NV04_PFB_BOOT_0, ~0,
+		      NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
+		      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+		      NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
+
+	for (i = 0; i < 4; i++)
+		fbmem_poke(fb, 4 * i, patt);
+
+	fbmem_poke(fb, 0x400000, patt + 1);
+
+	if (fbmem_peek(fb, 0) == patt + 1) {
+		nv_mask(priv, NV04_PFB_BOOT_0,
+			      NV04_PFB_BOOT_0_RAM_TYPE,
+			      NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
+		nv_mask(priv, NV04_PFB_DEBUG_0,
+			      NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+		for (i = 0; i < 4; i++)
+			fbmem_poke(fb, 4 * i, patt);
+
+		if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff))
+			nv_mask(priv, NV04_PFB_BOOT_0,
+				      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+				      NV04_PFB_BOOT_0_RAM_AMOUNT,
+				      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+	} else
+	if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) {
+		nv_mask(priv, NV04_PFB_BOOT_0,
+			      NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+			      NV04_PFB_BOOT_0_RAM_AMOUNT,
+			      NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+	} else
+	if (fbmem_peek(fb, 0) != patt) {
+		if (fbmem_readback(fb, 0x800000, patt))
+			nv_mask(priv, NV04_PFB_BOOT_0,
+				      NV04_PFB_BOOT_0_RAM_AMOUNT,
+				      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+		else
+			nv_mask(priv, NV04_PFB_BOOT_0,
+				      NV04_PFB_BOOT_0_RAM_AMOUNT,
+				      NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
+			      NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
+	} else
+	if (!fbmem_readback(fb, 0x800000, patt)) {
+		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+			      NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+	}
+
+	/* Refresh on, sequencer on */
+	nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
+	fbmem_fini(fb);
+}
+
+static int
+powerctrl_1_shift(int chip_version, int reg)
+{
+	int shift = -4;
+
+	if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
+		return shift;
+
+	switch (reg) {
+	case 0x680520:
+		shift += 4;
+	case 0x680508:
+		shift += 4;
+	case 0x680504:
+		shift += 4;
+	case 0x680500:
+		shift += 4;
+	}
+
+	/*
+	 * the shift for vpll regs is only used for nv3x chips with a single
+	 * stage pll
+	 */
+	if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
+			  chip_version == 0x36 || chip_version >= 0x40))
+		shift = -4;
+
+	return shift;
+}
+
+void
+setPLL_single(struct nvkm_devinit *devinit, u32 reg,
+	      struct nvkm_pll_vals *pv)
+{
+	int chip_version = nvkm_bios(devinit)->version.chip;
+	uint32_t oldpll = nv_rd32(devinit, reg);
+	int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
+	uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+	uint32_t saved_powerctrl_1 = 0;
+	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
+
+	if (oldpll == pll)
+		return;	/* already set */
+
+	if (shift_powerctrl_1 >= 0) {
+		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+		nv_wr32(devinit, 0x001584,
+			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+			1 << shift_powerctrl_1);
+	}
+
+	if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
+		/* upclock -- write new post divider first */
+		nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
+	else
+		/* downclock -- write new NM first */
+		nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
+
+	if ((chip_version < 0x17 || chip_version == 0x1a) &&
+	    chip_version != 0x11)
+		/* wait a bit on older chips */
+		msleep(64);
+	nv_rd32(devinit, reg);
+
+	/* then write the other half as well */
+	nv_wr32(devinit, reg, pll);
+
+	if (shift_powerctrl_1 >= 0)
+		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+}
+
+static uint32_t
+new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
+{
+	bool head_a = (reg1 == 0x680508);
+
+	if (ss)	/* single stage pll mode */
+		ramdac580 |= head_a ? 0x00000100 : 0x10000000;
+	else
+		ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
+
+	return ramdac580;
+}
+
+void
+setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1,
+		       struct nvkm_pll_vals *pv)
+{
+	int chip_version = nvkm_bios(devinit)->version.chip;
+	bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
+	uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
+	uint32_t oldpll1 = nv_rd32(devinit, reg1);
+	uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
+	uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+	uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
+	uint32_t oldramdac580 = 0, ramdac580 = 0;
+	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;	/* nv41+ only */
+	uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
+	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
+
+	/* model specific additions to generic pll1 and pll2 set up above */
+	if (nv3035) {
+		pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
+		       (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
+		pll2 = 0;
+	}
+	if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
+		oldramdac580 = nv_rd32(devinit, 0x680580);
+		ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
+		if (oldramdac580 != ramdac580)
+			oldpll1 = ~0;	/* force mismatch */
+		if (single_stage)
+			/* magic value used by nvidia in single stage mode */
+			pll2 |= 0x011f;
+	}
+	if (chip_version > 0x70)
+		/* magic bits set by the blob (but not the bios) on g71-73 */
+		pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
+
+	if (oldpll1 == pll1 && oldpll2 == pll2)
+		return;	/* already set */
+
+	if (shift_powerctrl_1 >= 0) {
+		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+		nv_wr32(devinit, 0x001584,
+			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+			1 << shift_powerctrl_1);
+	}
+
+	if (chip_version >= 0x40) {
+		int shift_c040 = 14;
+
+		switch (reg1) {
+		case 0x680504:
+			shift_c040 += 2;
+		case 0x680500:
+			shift_c040 += 2;
+		case 0x680520:
+			shift_c040 += 2;
+		case 0x680508:
+			shift_c040 += 2;
+		}
+
+		savedc040 = nv_rd32(devinit, 0xc040);
+		if (shift_c040 != 14)
+			nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
+	}
+
+	if (oldramdac580 != ramdac580)
+		nv_wr32(devinit, 0x680580, ramdac580);
+
+	if (!nv3035)
+		nv_wr32(devinit, reg2, pll2);
+	nv_wr32(devinit, reg1, pll1);
+
+	if (shift_powerctrl_1 >= 0)
+		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+	if (chip_version >= 0x40)
+		nv_wr32(devinit, 0xc040, savedc040);
+}
+
+void
+setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg,
+		      struct nvkm_pll_vals *pv)
+{
+	/* When setting PLLs, there is a merry game of disabling and enabling
+	 * various bits of hardware during the process. This function is a
+	 * synthesis of six nv4x traces, nearly each card doing a subtly
+	 * different thing. With luck all the necessary bits for each card are
+	 * combined herein. Without luck it deviates from each card's formula
+	 * so as to not work on any :)
+	 */
+
+	uint32_t Preg = NMNMreg - 4;
+	bool mpll = Preg == 0x4020;
+	uint32_t oldPval = nv_rd32(devinit, Preg);
+	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
+	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
+			0xc << 28 | pv->log2P << 16;
+	uint32_t saved4600 = 0;
+	/* some cards have different maskc040s */
+	uint32_t maskc040 = ~(3 << 14), savedc040;
+	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
+
+	if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
+		return;
+
+	if (Preg == 0x4000)
+		maskc040 = ~0x333;
+	if (Preg == 0x4058)
+		maskc040 = ~(0xc << 24);
+
+	if (mpll) {
+		struct nvbios_pll info;
+		uint8_t Pval2;
+
+		if (nvbios_pll_parse(nvkm_bios(devinit), Preg, &info))
+			return;
+
+		Pval2 = pv->log2P + info.bias_p;
+		if (Pval2 > info.max_p)
+			Pval2 = info.max_p;
+		Pval |= 1 << 28 | Pval2 << 20;
+
+		saved4600 = nv_rd32(devinit, 0x4600);
+		nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
+	}
+	if (single_stage)
+		Pval |= mpll ? 1 << 12 : 1 << 8;
+
+	nv_wr32(devinit, Preg, oldPval | 1 << 28);
+	nv_wr32(devinit, Preg, Pval & ~(4 << 28));
+	if (mpll) {
+		Pval |= 8 << 20;
+		nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
+		nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
+	}
+
+	savedc040 = nv_rd32(devinit, 0xc040);
+	nv_wr32(devinit, 0xc040, savedc040 & maskc040);
+
+	nv_wr32(devinit, NMNMreg, NMNM);
+	if (NMNMreg == 0x4024)
+		nv_wr32(devinit, 0x403c, NMNM);
+
+	nv_wr32(devinit, Preg, Pval);
+	if (mpll) {
+		Pval &= ~(8 << 20);
+		nv_wr32(devinit, 0x4020, Pval);
+		nv_wr32(devinit, 0x4038, Pval);
+		nv_wr32(devinit, 0x4600, saved4600);
+	}
+
+	nv_wr32(devinit, 0xc040, savedc040);
+
+	if (mpll) {
+		nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
+		nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
+	}
+}
+
+int
+nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+	struct nvkm_bios *bios = nvkm_bios(devinit);
+	struct nvkm_pll_vals pv;
+	struct nvbios_pll info;
+	int cv = bios->version.chip;
+	int N1, M1, N2, M2, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
+	if (ret)
+		return ret;
+
+	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
+			    &N1, &M1, &N2, &M2, &P);
+	if (!ret)
+		return -EINVAL;
+
+	pv.refclk = info.refclk;
+	pv.N1 = N1;
+	pv.M1 = M1;
+	pv.N2 = N2;
+	pv.M2 = M2;
+	pv.log2P = P;
+
+	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+	    cv >= 0x40) {
+		if (type > 0x405c)
+			setPLL_double_highregs(devinit, type, &pv);
+		else
+			setPLL_double_lowregs(devinit, type, &pv);
+	} else
+		setPLL_single(devinit, type, &pv);
+
+	return 0;
+}
+
+int
+nv04_devinit_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv04_devinit_priv *priv = (void *)object;
+	int ret;
+
+	/* make i2c busses accessible */
+	nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
+
+	ret = nvkm_devinit_fini(&priv->base, suspend);
+	if (ret)
+		return ret;
+
+	/* unslave crtcs */
+	if (priv->owner < 0)
+		priv->owner = nv_rdvgaowner(priv);
+	nv_wrvgaowner(priv, 0);
+	return 0;
+}
+
+int
+nv04_devinit_init(struct nvkm_object *object)
+{
+	struct nv04_devinit_priv *priv = (void *)object;
+
+	if (!priv->base.post) {
+		u32 htotal = nv_rdvgac(priv, 0, 0x06);
+		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
+		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
+		htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
+		htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
+		if (!htotal) {
+			nv_info(priv, "adaptor not initialised\n");
+			priv->base.post = true;
+		}
+	}
+
+	return nvkm_devinit_init(&priv->base);
+}
+
+void
+nv04_devinit_dtor(struct nvkm_object *object)
+{
+	struct nv04_devinit_priv *priv = (void *)object;
+
+	/* restore vga owner saved at first init */
+	nv_wrvgaowner(priv, priv->owner);
+
+	nvkm_devinit_destroy(&priv->base);
+}
+
+int
+nv04_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nv04_devinit_priv *priv;
+	int ret;
+
+	ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->owner = -1;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_devinit_ctor,
+		.dtor = nv04_devinit_dtor,
+		.init = nv04_devinit_init,
+		.fini = nv04_devinit_fini,
+	},
+	.meminit = nv04_devinit_meminit,
+	.pll_set = nv04_devinit_pll_set,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
new file mode 100644
index 0000000..14a51a9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
@@ -0,0 +1,22 @@
+#ifndef __NVKM_DEVINIT_NV04_H__
+#define __NVKM_DEVINIT_NV04_H__
+#include "priv.h"
+struct nvkm_pll_vals;
+
+struct nv04_devinit_priv {
+	struct nvkm_devinit base;
+	u8 owner;
+};
+
+int  nv04_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, void *, u32,
+		       struct nvkm_object **);
+void nv04_devinit_dtor(struct nvkm_object *);
+int  nv04_devinit_init(struct nvkm_object *);
+int  nv04_devinit_fini(struct nvkm_object *, bool);
+int  nv04_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+void setPLL_single(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+void setPLL_double_highregs(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+void setPLL_double_lowregs(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c
new file mode 100644
index 0000000..def8649
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/init.h>
+#include <subdev/vga.h>
+
+static void
+nv05_devinit_meminit(struct nvkm_devinit *devinit)
+{
+	static const u8 default_config_tab[][2] = {
+		{ 0x24, 0x00 },
+		{ 0x28, 0x00 },
+		{ 0x24, 0x01 },
+		{ 0x1f, 0x00 },
+		{ 0x0f, 0x00 },
+		{ 0x17, 0x00 },
+		{ 0x06, 0x00 },
+		{ 0x00, 0x00 }
+	};
+	struct nv04_devinit_priv *priv = (void *)devinit;
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct io_mapping *fb;
+	u32 patt = 0xdeadbeef;
+	u16 data;
+	u8 strap, ramcfg[2];
+	int i, v;
+
+	/* Map the framebuffer aperture */
+	fb = fbmem_init(nv_device(priv));
+	if (!fb) {
+		nv_error(priv, "failed to map fb\n");
+		return;
+	}
+
+	strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2;
+	if ((data = bmp_mem_init_table(bios))) {
+		ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0);
+		ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1);
+	} else {
+		ramcfg[0] = default_config_tab[strap][0];
+		ramcfg[1] = default_config_tab[strap][1];
+	}
+
+	/* Sequencer off */
+	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
+
+	if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
+		goto out;
+
+	nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+	/* If present load the hardcoded scrambling table */
+	if (data) {
+		for (i = 0, data += 0x10; i < 8; i++, data += 4) {
+			u32 scramble = nv_ro32(bios, data);
+			nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble);
+		}
+	}
+
+	/* Set memory type/width/length defaults depending on the straps */
+	nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
+
+	if (ramcfg[1] & 0x80)
+		nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
+
+	nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
+	nv_mask(priv, NV04_PFB_CFG1, 0, 1);
+
+	/* Probe memory bus width */
+	for (i = 0; i < 4; i++)
+		fbmem_poke(fb, 4 * i, patt);
+
+	if (fbmem_peek(fb, 0xc) != patt)
+		nv_mask(priv, NV04_PFB_BOOT_0,
+			  NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
+
+	/* Probe memory length */
+	v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
+
+	if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
+	    (!fbmem_readback(fb, 0x1000000, ++patt) ||
+	     !fbmem_readback(fb, 0, ++patt)))
+		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+			  NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
+
+	if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
+	    !fbmem_readback(fb, 0x800000, ++patt))
+		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+			  NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+	if (!fbmem_readback(fb, 0x400000, ++patt))
+		nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+			  NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+out:
+	/* Sequencer on */
+	nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
+	fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv05_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x05),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_devinit_ctor,
+		.dtor = nv04_devinit_dtor,
+		.init = nv04_devinit_init,
+		.fini = nv04_devinit_fini,
+	},
+	.meminit = nv05_devinit_meminit,
+	.pll_set = nv04_devinit_pll_set,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c
new file mode 100644
index 0000000..7aabc1b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static void
+nv10_devinit_meminit(struct nvkm_devinit *devinit)
+{
+	struct nv04_devinit_priv *priv = (void *)devinit;
+	static const int mem_width[] = { 0x10, 0x00, 0x20 };
+	int mem_width_count;
+	uint32_t patt = 0xdeadbeef;
+	struct io_mapping *fb;
+	int i, j, k;
+
+	if (nv_device(priv)->card_type >= NV_11 &&
+	    nv_device(priv)->chipset >= 0x17)
+		mem_width_count = 3;
+	else
+		mem_width_count = 2;
+
+	/* Map the framebuffer aperture */
+	fb = fbmem_init(nv_device(priv));
+	if (!fb) {
+		nv_error(priv, "failed to map fb\n");
+		return;
+	}
+
+	nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+	/* Probe memory bus width */
+	for (i = 0; i < mem_width_count; i++) {
+		nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]);
+
+		for (j = 0; j < 4; j++) {
+			for (k = 0; k < 4; k++)
+				fbmem_poke(fb, 0x1c, 0);
+
+			fbmem_poke(fb, 0x1c, patt);
+			fbmem_poke(fb, 0x3c, 0);
+
+			if (fbmem_peek(fb, 0x1c) == patt)
+				goto mem_width_found;
+		}
+	}
+
+mem_width_found:
+	patt <<= 1;
+
+	/* Probe amount of installed memory */
+	for (i = 0; i < 4; i++) {
+		int off = nv_rd32(priv, 0x10020c) - 0x100000;
+
+		fbmem_poke(fb, off, patt);
+		fbmem_poke(fb, 0, 0);
+
+		fbmem_peek(fb, 0);
+		fbmem_peek(fb, 0);
+		fbmem_peek(fb, 0);
+		fbmem_peek(fb, 0);
+
+		if (fbmem_peek(fb, off) == patt)
+			goto amount_found;
+	}
+
+	/* IC missing - disable the upper half memory space. */
+	nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0);
+
+amount_found:
+	fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv10_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x10),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_devinit_ctor,
+		.dtor = nv04_devinit_dtor,
+		.init = nv04_devinit_init,
+		.fini = nv04_devinit_fini,
+	},
+	.meminit = nv10_devinit_meminit,
+	.pll_set = nv04_devinit_pll_set,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c
new file mode 100644
index 0000000..9f36fff
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+struct nvkm_oclass *
+nv1a_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x1a),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_devinit_ctor,
+		.dtor = nv04_devinit_dtor,
+		.init = nv04_devinit_init,
+		.fini = nv04_devinit_fini,
+	},
+	.pll_set = nv04_devinit_pll_set,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c
new file mode 100644
index 0000000..02fcfd9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static void
+nv20_devinit_meminit(struct nvkm_devinit *devinit)
+{
+	struct nv04_devinit_priv *priv = (void *)devinit;
+	struct nvkm_device *device = nv_device(priv);
+	uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900);
+	uint32_t amount, off;
+	struct io_mapping *fb;
+
+	/* Map the framebuffer aperture */
+	fb = fbmem_init(nv_device(priv));
+	if (!fb) {
+		nv_error(priv, "failed to map fb\n");
+		return;
+	}
+
+	nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+	/* Allow full addressing */
+	nv_mask(priv, NV04_PFB_CFG0, 0, mask);
+
+	amount = nv_rd32(priv, 0x10020c);
+	for (off = amount; off > 0x2000000; off -= 0x2000000)
+		fbmem_poke(fb, off - 4, off);
+
+	amount = nv_rd32(priv, 0x10020c);
+	if (amount != fbmem_peek(fb, amount - 4))
+		/* IC missing - disable the upper half memory space. */
+		nv_mask(priv, NV04_PFB_CFG0, mask, 0);
+
+	fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv20_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x20),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_devinit_ctor,
+		.dtor = nv04_devinit_dtor,
+		.init = nv04_devinit_init,
+		.fini = nv04_devinit_fini,
+	},
+	.meminit = nv20_devinit_meminit,
+	.pll_set = nv04_devinit_pll_set,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
new file mode 100644
index 0000000..26b7cb1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/ibus.h>
+#include <subdev/vga.h>
+
+int
+nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	struct nvkm_bios *bios = nvkm_bios(priv);
+	struct nvbios_pll info;
+	int N1, M1, N2, M2, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret) {
+		nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
+		return ret;
+	}
+
+	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
+	if (!ret) {
+		nv_error(devinit, "failed pll calculation\n");
+		return ret;
+	}
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+		nv_wr32(priv, info.reg + 0, 0x10000611);
+		nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
+		nv_mask(priv, info.reg + 8, 0x7fff00ff, (P  << 28) |
+							(M2 << 16) | N2);
+		break;
+	case PLL_MEMORY:
+		nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
+						        (info.bias_p << 19) |
+							(P << 16));
+		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+		break;
+	default:
+		nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
+		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+		break;
+	}
+
+	return 0;
+}
+
+static u64
+nv50_devinit_disable(struct nvkm_devinit *devinit)
+{
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	u32 r001540 = nv_rd32(priv, 0x001540);
+	u64 disable = 0ULL;
+
+	if (!(r001540 & 0x40000000))
+		disable |= (1ULL << NVDEV_ENGINE_MPEG);
+
+	return disable;
+}
+
+int
+nv50_devinit_init(struct nvkm_object *object)
+{
+	struct nvkm_bios *bios = nvkm_bios(object);
+	struct nvkm_ibus *ibus = nvkm_ibus(object);
+	struct nv50_devinit_priv *priv = (void *)object;
+	struct nvbios_outp info;
+	struct dcb_output outp;
+	u8  ver = 0xff, hdr, cnt, len;
+	int ret, i = 0;
+
+	if (!priv->base.post) {
+		if (!nv_rdvgac(priv, 0, 0x00) &&
+		    !nv_rdvgac(priv, 0, 0x1a)) {
+			nv_info(priv, "adaptor not initialised\n");
+			priv->base.post = true;
+		}
+	}
+
+	/* some boards appear to require certain priv register timeouts
+	 * to be bumped before runing devinit scripts.  not a clue why
+	 * the vbios engineers didn't make the scripts just work...
+	 */
+	if (priv->base.post && ibus)
+		nv_ofuncs(ibus)->init(nv_object(ibus));
+
+	ret = nvkm_devinit_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* if we ran the init tables, we have to execute the first script
+	 * pointer of each dcb entry's display encoder table in order
+	 * to properly initialise each encoder.
+	 */
+	while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
+		if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
+				      &ver, &hdr, &cnt, &len, &info)) {
+			struct nvbios_init init = {
+				.subdev = nv_subdev(priv),
+				.bios = bios,
+				.offset = info.script[0],
+				.outp = &outp,
+				.crtc = -1,
+				.execute = 1,
+			};
+
+			nvbios_exec(&init);
+		}
+		i++;
+	}
+
+	return 0;
+}
+
+int
+nv50_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nv50_devinit_priv *priv;
+	int ret;
+
+	ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_devinit_oclass = &(struct nvkm_devinit_impl) {
+	.base.handle = NV_SUBDEV(DEVINIT, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_devinit_ctor,
+		.dtor = _nvkm_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nvkm_devinit_fini,
+	},
+	.pll_set = nv50_devinit_pll_set,
+	.disable = nv50_devinit_disable,
+	.post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
new file mode 100644
index 0000000..b882b65
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_DEVINIT_NV50_H__
+#define __NVKM_DEVINIT_NV50_H__
+#include "priv.h"
+
+struct nv50_devinit_priv {
+	struct nvkm_devinit base;
+	u32 r001540;
+};
+
+int  nv50_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, void *, u32,
+		       struct nvkm_object **);
+int  nv50_devinit_init(struct nvkm_object *);
+int  nv50_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+int  gt215_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+int  gf100_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+u64  gm107_devinit_disable(struct nvkm_devinit *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
new file mode 100644
index 0000000..bb51a95
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_DEVINIT_PRIV_H__
+#define __NVKM_DEVINIT_PRIV_H__
+#include <subdev/devinit.h>
+
+struct nvkm_devinit_impl {
+	struct nvkm_oclass base;
+	void (*meminit)(struct nvkm_devinit *);
+	int  (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq);
+	u64  (*disable)(struct nvkm_devinit *);
+	u32  (*mmio)(struct nvkm_devinit *, u32);
+	int  (*post)(struct nvkm_subdev *, bool);
+};
+
+#define nvkm_devinit_create(p,e,o,d)                                        \
+	nvkm_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_devinit_destroy(p) ({                                          \
+	struct nvkm_devinit *d = (p);                                       \
+	_nvkm_devinit_dtor(nv_object(d));                                   \
+})
+#define nvkm_devinit_init(p) ({                                             \
+	struct nvkm_devinit *d = (p);                                       \
+	_nvkm_devinit_init(nv_object(d));                                   \
+})
+#define nvkm_devinit_fini(p,s) ({                                           \
+	struct nvkm_devinit *d = (p);                                       \
+	_nvkm_devinit_fini(nv_object(d), (s));                              \
+})
+
+int nvkm_devinit_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, int, void **);
+void _nvkm_devinit_dtor(struct nvkm_object *);
+int _nvkm_devinit_init(struct nvkm_object *);
+int _nvkm_devinit_fini(struct nvkm_object *, bool suspend);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
new file mode 100644
index 0000000..904d601
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
@@ -0,0 +1,45 @@
+nvkm-y += nvkm/subdev/fb/base.o
+nvkm-y += nvkm/subdev/fb/nv04.o
+nvkm-y += nvkm/subdev/fb/nv10.o
+nvkm-y += nvkm/subdev/fb/nv1a.o
+nvkm-y += nvkm/subdev/fb/nv20.o
+nvkm-y += nvkm/subdev/fb/nv25.o
+nvkm-y += nvkm/subdev/fb/nv30.o
+nvkm-y += nvkm/subdev/fb/nv35.o
+nvkm-y += nvkm/subdev/fb/nv36.o
+nvkm-y += nvkm/subdev/fb/nv40.o
+nvkm-y += nvkm/subdev/fb/nv41.o
+nvkm-y += nvkm/subdev/fb/nv44.o
+nvkm-y += nvkm/subdev/fb/nv46.o
+nvkm-y += nvkm/subdev/fb/nv47.o
+nvkm-y += nvkm/subdev/fb/nv49.o
+nvkm-y += nvkm/subdev/fb/nv4e.o
+nvkm-y += nvkm/subdev/fb/nv50.o
+nvkm-y += nvkm/subdev/fb/g84.o
+nvkm-y += nvkm/subdev/fb/gt215.o
+nvkm-y += nvkm/subdev/fb/mcp77.o
+nvkm-y += nvkm/subdev/fb/mcp89.o
+nvkm-y += nvkm/subdev/fb/gf100.o
+nvkm-y += nvkm/subdev/fb/gk104.o
+nvkm-y += nvkm/subdev/fb/gk20a.o
+nvkm-y += nvkm/subdev/fb/gm107.o
+nvkm-y += nvkm/subdev/fb/ramnv04.o
+nvkm-y += nvkm/subdev/fb/ramnv10.o
+nvkm-y += nvkm/subdev/fb/ramnv1a.o
+nvkm-y += nvkm/subdev/fb/ramnv20.o
+nvkm-y += nvkm/subdev/fb/ramnv40.o
+nvkm-y += nvkm/subdev/fb/ramnv41.o
+nvkm-y += nvkm/subdev/fb/ramnv44.o
+nvkm-y += nvkm/subdev/fb/ramnv49.o
+nvkm-y += nvkm/subdev/fb/ramnv4e.o
+nvkm-y += nvkm/subdev/fb/ramnv50.o
+nvkm-y += nvkm/subdev/fb/ramgt215.o
+nvkm-y += nvkm/subdev/fb/rammcp77.o
+nvkm-y += nvkm/subdev/fb/ramgf100.o
+nvkm-y += nvkm/subdev/fb/ramgk104.o
+nvkm-y += nvkm/subdev/fb/ramgk20a.o
+nvkm-y += nvkm/subdev/fb/ramgm107.o
+nvkm-y += nvkm/subdev/fb/sddr2.o
+nvkm-y += nvkm/subdev/fb/sddr3.o
+nvkm-y += nvkm/subdev/fb/gddr3.o
+nvkm-y += nvkm/subdev/fb/gddr5.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
new file mode 100644
index 0000000..16589fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/M0203.h>
+
+int
+nvkm_fb_bios_memtype(struct nvkm_bios *bios)
+{
+	const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
+	struct nvbios_M0203E M0203E;
+	u8 ver, hdr;
+
+	if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
+		switch (M0203E.type) {
+		case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
+		case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
+		case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
+		case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
+		default:
+			nv_warn(bios, "M0203E type %02x\n", M0203E.type);
+			return NV_MEM_TYPE_UNKNOWN;
+		}
+	}
+
+	nv_warn(bios, "M0203E not matched!\n");
+	return NV_MEM_TYPE_UNKNOWN;
+}
+
+int
+_nvkm_fb_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_fb *pfb = (void *)object;
+	int ret;
+
+	ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+	if (ret && suspend)
+		return ret;
+
+	return nvkm_subdev_fini(&pfb->base, suspend);
+}
+
+int
+_nvkm_fb_init(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = (void *)object;
+	int ret, i;
+
+	ret = nvkm_subdev_init(&pfb->base);
+	if (ret)
+		return ret;
+
+	ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+	if (ret)
+		return ret;
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+
+	return 0;
+}
+
+void
+_nvkm_fb_dtor(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = (void *)object;
+	int i;
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
+	nvkm_mm_fini(&pfb->tags);
+	nvkm_mm_fini(&pfb->vram);
+
+	nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram);
+	nvkm_subdev_destroy(&pfb->base);
+}
+
+int
+nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_fb_impl *impl = (void *)oclass;
+	static const char *name[] = {
+		[NV_MEM_TYPE_UNKNOWN] = "unknown",
+		[NV_MEM_TYPE_STOLEN ] = "stolen system memory",
+		[NV_MEM_TYPE_SGRAM  ] = "SGRAM",
+		[NV_MEM_TYPE_SDRAM  ] = "SDRAM",
+		[NV_MEM_TYPE_DDR1   ] = "DDR1",
+		[NV_MEM_TYPE_DDR2   ] = "DDR2",
+		[NV_MEM_TYPE_DDR3   ] = "DDR3",
+		[NV_MEM_TYPE_GDDR2  ] = "GDDR2",
+		[NV_MEM_TYPE_GDDR3  ] = "GDDR3",
+		[NV_MEM_TYPE_GDDR4  ] = "GDDR4",
+		[NV_MEM_TYPE_GDDR5  ] = "GDDR5",
+	};
+	struct nvkm_object *ram;
+	struct nvkm_fb *pfb;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
+				  length, pobject);
+	pfb = *pobject;
+	if (ret)
+		return ret;
+
+	pfb->memtype_valid = impl->memtype;
+
+	ret = nvkm_object_ctor(nv_object(pfb), NULL, impl->ram, NULL, 0, &ram);
+	if (ret) {
+		nv_fatal(pfb, "error detecting memory configuration!!\n");
+		return ret;
+	}
+
+	pfb->ram = (void *)ram;
+
+	if (!nvkm_mm_initialised(&pfb->vram)) {
+		ret = nvkm_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
+		if (ret)
+			return ret;
+	}
+
+	if (!nvkm_mm_initialised(&pfb->tags)) {
+		ret = nvkm_mm_init(&pfb->tags, 0, pfb->ram->tags ?
+				   ++pfb->ram->tags : 0, 1);
+		if (ret)
+			return ret;
+	}
+
+	nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
+	nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
+	nv_info(pfb, "   ZCOMP: %d tags\n", pfb->ram->tags);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c
new file mode 100644
index 0000000..6c968d1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+g84_fb_oclass = &(struct nv50_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x84),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fb_ctor,
+		.dtor = nv50_fb_dtor,
+		.init = nv50_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv50_fb_memtype_valid,
+	.base.ram = &nv50_ram_oclass,
+	.trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
new file mode 100644
index 0000000..15b462a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ * 	    Roy Spliet <rspliet@eclipso.eu>
+ */
+#include "priv.h"
+
+struct ramxlat {
+	int id;
+	u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+	while (xlat->id >= 0) {
+		if (xlat->id == id)
+			return xlat->enc;
+		xlat++;
+	}
+	return -EINVAL;
+}
+
+static const struct ramxlat
+ramgddr3_cl_lo[] = {
+	{ 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
+	/* the below are mentioned in some, but not all, gddr3 docs */
+	{ 12, 4 }, { 13, 5 }, { 14, 6 },
+	/* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
+	/* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
+	 * { 15, 11 }, */
+	{ -1 }
+};
+
+static const struct ramxlat
+ramgddr3_cl_hi[] = {
+	{ 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
+	{ 16, 0 }, { 17, 1 },
+	{ -1 }
+};
+
+static const struct ramxlat
+ramgddr3_wr_lo[] = {
+	{ 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
+	{ 11, 0 },
+	/* the below are mentioned in some, but not all, gddr3 docs */
+	{ 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
+	{ -1 }
+};
+
+int
+nvkm_gddr3_calc(struct nvkm_ram *ram)
+{
+	int CL, WR, CWL, DLL = 0, ODT = 0, hi;
+
+	switch (ram->next->bios.timing_ver) {
+	case 0x10:
+		CWL = ram->next->bios.timing_10_CWL;
+		CL  = ram->next->bios.timing_10_CL;
+		WR  = ram->next->bios.timing_10_WR;
+		DLL = !ram->next->bios.ramcfg_10_DLLoff;
+		ODT = ram->next->bios.timing_10_ODT;
+		break;
+	case 0x20:
+		CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+		CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+		/* XXX: Get these values from the VBIOS instead */
+		DLL = !(ram->mr[1] & 0x1);
+		ODT =  (ram->mr[1] & 0x004) >> 2 |
+		       (ram->mr[1] & 0x040) >> 5 |
+		       (ram->mr[1] & 0x200) >> 7;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	hi = ram->mr[2] & 0x1;
+	CL  = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
+	WR  = ramxlat(ramgddr3_wr_lo, WR);
+	if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
+		return -EINVAL;
+
+	ram->mr[0] &= ~0xf74;
+	ram->mr[0] |= (CWL & 0x07) << 9;
+	ram->mr[0] |= (CL & 0x07) << 4;
+	ram->mr[0] |= (CL & 0x08) >> 1;
+
+	ram->mr[1] &= ~0x3fc;
+	ram->mr[1] |= (ODT & 0x03) << 2;
+	ram->mr[1] |= (ODT & 0x03) << 8;
+	ram->mr[1] |= (WR  & 0x03) << 4;
+	ram->mr[1] |= (WR  & 0x04) << 5;
+	ram->mr[1] |= !DLL << 6;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c
new file mode 100644
index 0000000..f6f9eee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+/* binary driver only executes this path if the condition (a) is true
+ * for any configuration (combination of rammap+ramcfg+timing) that
+ * can be reached on a given card.  for now, we will execute the branch
+ * unconditionally in the hope that a "false everywhere" in the bios
+ * tables doesn't actually mean "don't touch this".
+ */
+#define NOTE00(a) 1
+
+int
+nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts)
+{
+	int pd, lf, xd, vh, vr, vo, l3;
+	int WL, CL, WR, at[2], dt, ds;
+	int rq = ram->freq < 1000000; /* XXX */
+
+	switch (ram->next->bios.ramcfg_ver) {
+	case 0x11:
+		pd =  ram->next->bios.ramcfg_11_01_80;
+		lf =  ram->next->bios.ramcfg_11_01_40;
+		xd = !ram->next->bios.ramcfg_11_01_20;
+		vh =  ram->next->bios.ramcfg_11_02_10;
+		vr =  ram->next->bios.ramcfg_11_02_04;
+		vo =  ram->next->bios.ramcfg_11_06;
+		l3 = !ram->next->bios.ramcfg_11_07_02;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	switch (ram->next->bios.timing_ver) {
+	case 0x20:
+		WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+		CL = (ram->next->bios.timing[1] & 0x0000001f);
+		WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+		at[0] = ram->next->bios.timing_20_2e_c0;
+		at[1] = ram->next->bios.timing_20_2e_30;
+		dt =  ram->next->bios.timing_20_2e_03;
+		ds =  ram->next->bios.timing_20_2f_03;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
+		return -EINVAL;
+	CL -= 5;
+	WR -= 4;
+
+	ram->mr[0] &= ~0xf7f;
+	ram->mr[0] |= (WR & 0x0f) << 8;
+	ram->mr[0] |= (CL & 0x0f) << 3;
+	ram->mr[0] |= (WL & 0x07) << 0;
+
+	ram->mr[1] &= ~0x0bf;
+	ram->mr[1] |= (xd & 0x01) << 7;
+	ram->mr[1] |= (at[0] & 0x03) << 4;
+	ram->mr[1] |= (dt & 0x03) << 2;
+	ram->mr[1] |= (ds & 0x03) << 0;
+
+	/* this seems wrong, alternate field used for the broadcast
+	 * on nuts vs non-nuts configs..  meh, it matches for now.
+	 */
+	ram->mr1_nuts = ram->mr[1];
+	if (nuts) {
+		ram->mr[1] &= ~0x030;
+		ram->mr[1] |= (at[1] & 0x03) << 4;
+	}
+
+	ram->mr[3] &= ~0x020;
+	ram->mr[3] |= (rq & 0x01) << 5;
+
+	ram->mr[5] &= ~0x004;
+	ram->mr[5] |= (l3 << 2);
+
+	if (!vo)
+		vo = (ram->mr[6] & 0xff0) >> 4;
+	if (ram->mr[6] & 0x001)
+		pd = 1; /* binary driver does this.. bug? */
+	ram->mr[6] &= ~0xff1;
+	ram->mr[6] |= (vo & 0xff) << 4;
+	ram->mr[6] |= (pd & 0x01) << 0;
+
+	if (NOTE00(vr)) {
+		ram->mr[7] &= ~0x300;
+		ram->mr[7] |= (vr & 0x03) << 8;
+	}
+	ram->mr[7] &= ~0x088;
+	ram->mr[7] |= (vh & 0x01) << 7;
+	ram->mr[7] |= (lf & 0x01) << 3;
+
+	ram->mr[8] &= ~0x003;
+	ram->mr[8] |= (WR & 0x10) >> 3;
+	ram->mr[8] |= (CL & 0x10) >> 4;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
new file mode 100644
index 0000000..d51aa02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+#include <core/device.h>
+
+extern const u8 gf100_pte_storage_type_map[256];
+
+bool
+gf100_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags)
+{
+	u8 memtype = (tile_flags & 0x0000ff00) >> 8;
+	return likely((gf100_pte_storage_type_map[memtype] != 0xff));
+}
+
+static void
+gf100_fb_intr(struct nvkm_subdev *subdev)
+{
+	struct gf100_fb_priv *priv = (void *)subdev;
+	u32 intr = nv_rd32(priv, 0x000100);
+	if (intr & 0x08000000) {
+		nv_debug(priv, "PFFB intr\n");
+		intr &= ~0x08000000;
+	}
+	if (intr & 0x00002000) {
+		nv_debug(priv, "PBFB intr\n");
+		intr &= ~0x00002000;
+	}
+}
+
+int
+gf100_fb_init(struct nvkm_object *object)
+{
+	struct gf100_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	if (priv->r100c10_page)
+		nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
+
+	nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
+	return 0;
+}
+
+void
+gf100_fb_dtor(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct gf100_fb_priv *priv = (void *)object;
+
+	if (priv->r100c10_page) {
+		dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE,
+			       DMA_BIDIRECTIONAL);
+		__free_page(priv->r100c10_page);
+	}
+
+	nvkm_fb_destroy(&priv->base);
+}
+
+int
+gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct gf100_fb_priv *priv;
+	int ret;
+
+	ret = nvkm_fb_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (priv->r100c10_page) {
+		priv->r100c10 = dma_map_page(nv_device_base(device),
+					     priv->r100c10_page, 0, PAGE_SIZE,
+					     DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(nv_device_base(device), priv->r100c10))
+			return -EFAULT;
+	}
+
+	nv_subdev(priv)->intr = gf100_fb_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+gf100_fb_oclass = &(struct nvkm_fb_impl) {
+	.base.handle = NV_SUBDEV(FB, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fb_ctor,
+		.dtor = gf100_fb_dtor,
+		.init = gf100_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.memtype = gf100_fb_memtype_valid,
+	.ram = &gf100_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
new file mode 100644
index 0000000..0af4da2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_RAM_NVC0_H__
+#define __NVKM_RAM_NVC0_H__
+#include "priv.h"
+#include "nv50.h"
+
+struct gf100_fb_priv {
+	struct nvkm_fb base;
+	struct page *r100c10_page;
+	dma_addr_t r100c10;
+};
+
+int  gf100_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+		  struct nvkm_oclass *, void *, u32,
+		  struct nvkm_object **);
+void gf100_fb_dtor(struct nvkm_object *);
+int  gf100_fb_init(struct nvkm_object *);
+bool gf100_fb_memtype_valid(struct nvkm_fb *, u32);
+
+#define gf100_ram_create(p,e,o,m,d)                                             \
+	gf100_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
+int  gf100_ram_create_(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, u32, int, void **);
+int  gf100_ram_get(struct nvkm_fb *, u64, u32, u32, u32,
+		  struct nvkm_mem **);
+void gf100_ram_put(struct nvkm_fb *, struct nvkm_mem **);
+
+int  gk104_ram_init(struct nvkm_object*);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c
new file mode 100644
index 0000000..1c08317
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct nvkm_oclass *
+gk104_fb_oclass = &(struct nvkm_fb_impl) {
+	.base.handle = NV_SUBDEV(FB, 0xe0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fb_ctor,
+		.dtor = gf100_fb_dtor,
+		.init = gf100_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.memtype = gf100_fb_memtype_valid,
+	.ram = &gk104_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c
new file mode 100644
index 0000000..6762847
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "gf100.h"
+
+struct gk20a_fb_priv {
+	struct nvkm_fb base;
+};
+
+static int
+gk20a_fb_init(struct nvkm_object *object)
+{
+	struct gk20a_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
+	return 0;
+}
+
+static int
+gk20a_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct gk20a_fb_priv *priv;
+	int ret;
+
+	ret = nvkm_fb_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+gk20a_fb_oclass = &(struct nvkm_fb_impl) {
+	.base.handle = NV_SUBDEV(FB, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = gk20a_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.memtype = gf100_fb_memtype_valid,
+	.ram = &gk20a_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
new file mode 100644
index 0000000..843f935
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct nvkm_oclass *
+gm107_fb_oclass = &(struct nvkm_fb_impl) {
+	.base.handle = NV_SUBDEV(FB, 0x07),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fb_ctor,
+		.dtor = gf100_fb_dtor,
+		.init = gf100_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.memtype = gf100_fb_memtype_valid,
+	.ram = &gm107_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c
new file mode 100644
index 0000000..dd9b8a0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+gt215_fb_oclass = &(struct nv50_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0xa3),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fb_ctor,
+		.dtor = nv50_fb_dtor,
+		.init = nv50_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv50_fb_memtype_valid,
+	.base.ram = &gt215_ram_oclass,
+	.trap = 0x000d0fff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c
new file mode 100644
index 0000000..7be4a47
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+mcp77_fb_oclass = &(struct nv50_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0xaa),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fb_ctor,
+		.dtor = nv50_fb_dtor,
+		.init = nv50_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv50_fb_memtype_valid,
+	.base.ram = &mcp77_ram_oclass,
+	.trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c
new file mode 100644
index 0000000..2d00656
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+mcp89_fb_oclass = &(struct nv50_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0xaf),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fb_ctor,
+		.dtor = nv50_fb_dtor,
+		.init = nv50_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv50_fb_memtype_valid,
+	.base.ram = &mcp77_ram_oclass,
+	.trap = 0x089d1fff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c
new file mode 100644
index 0000000..c063dec
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+#include "regsnv04.h"
+
+bool
+nv04_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags)
+{
+	if (!(tile_flags & 0xff00))
+		return true;
+
+	return false;
+}
+
+static int
+nv04_fb_init(struct nvkm_object *object)
+{
+	struct nv04_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
+	 * nvidia reading PFB_CFG_0, then writing back its original value.
+	 * (which was 0x701114 in this case)
+	 */
+	nv_wr32(priv, NV04_PFB_CFG0, 0x1114);
+	return 0;
+}
+
+int
+nv04_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv04_fb_impl *impl = (void *)oclass;
+	struct nv04_fb_priv *priv;
+	int ret;
+
+	ret = nvkm_fb_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.tile.regions = impl->tile.regions;
+	priv->base.tile.init = impl->tile.init;
+	priv->base.tile.comp = impl->tile.comp;
+	priv->base.tile.fini = impl->tile.fini;
+	priv->base.tile.prog = impl->tile.prog;
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x04),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv04_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv04_ram_oclass,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h
new file mode 100644
index 0000000..caa0d03
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_FB_NV04_H__
+#define __NVKM_FB_NV04_H__
+#include "priv.h"
+
+struct nv04_fb_priv {
+	struct nvkm_fb base;
+};
+
+int  nv04_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+		  struct nvkm_oclass *, void *, u32,
+		  struct nvkm_object **);
+
+struct nv04_fb_impl {
+	struct nvkm_fb_impl base;
+	struct {
+		int regions;
+		void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size,
+			     u32 pitch, u32 flags, struct nvkm_fb_tile *);
+		void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags,
+			     struct nvkm_fb_tile *);
+		void (*fini)(struct nvkm_fb *, int i,
+			     struct nvkm_fb_tile *);
+		void (*prog)(struct nvkm_fb *, int i,
+			     struct nvkm_fb_tile *);
+	} tile;
+};
+
+void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nvkm_fb_tile *);
+void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nvkm_fb_tile *);
+void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+int  nv30_fb_init(struct nvkm_object *);
+void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nvkm_fb_tile *);
+
+void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags,
+		       struct nvkm_fb_tile *);
+
+int  nv41_fb_init(struct nvkm_object *);
+void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+int  nv44_fb_init(struct nvkm_object *);
+void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nvkm_fb_tile *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c
new file mode 100644
index 0000000..f3530e4a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+void
+nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+		  u32 flags, struct nvkm_fb_tile *tile)
+{
+	tile->addr  = 0x80000000 | addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+}
+
+void
+nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	tile->addr  = 0;
+	tile->limit = 0;
+	tile->pitch = 0;
+	tile->zcomp = 0;
+}
+
+void
+nv10_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
+	nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
+	nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
+	nv_rd32(pfb, 0x100240 + (i * 0x10));
+}
+
+struct nvkm_oclass *
+nv10_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x10),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = _nvkm_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv10_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv10_fb_tile_init,
+	.tile.fini = nv10_fb_tile_fini,
+	.tile.prog = nv10_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c
new file mode 100644
index 0000000..83bcb73
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv1a_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x1a),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = _nvkm_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv1a_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv10_fb_tile_init,
+	.tile.fini = nv10_fb_tile_fini,
+	.tile.prog = nv10_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c
new file mode 100644
index 0000000..e37084b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+void
+nv20_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+		  u32 flags, struct nvkm_fb_tile *tile)
+{
+	tile->addr  = 0x00000001 | addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+	if (flags & 4) {
+		pfb->tile.comp(pfb, i, size, flags, tile);
+		tile->addr |= 2;
+	}
+}
+
+static void
+nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
+	if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
+		else              tile->zcomp = 0x04000000; /* Z24S8 */
+		tile->zcomp |= tile->tag->offset;
+		tile->zcomp |= 0x80000000; /* enable */
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x08000000;
+#endif
+	}
+}
+
+void
+nv20_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	tile->addr  = 0;
+	tile->limit = 0;
+	tile->pitch = 0;
+	tile->zcomp = 0;
+	nvkm_mm_free(&pfb->tags, &tile->tag);
+}
+
+void
+nv20_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
+	nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
+	nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
+	nv_rd32(pfb, 0x100240 + (i * 0x10));
+	nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
+}
+
+struct nvkm_oclass *
+nv20_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x20),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = _nvkm_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv20_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv20_fb_tile_init,
+	.tile.comp = nv20_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c
new file mode 100644
index 0000000..bc9f54f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv25_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
+	if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
+		else              tile->zcomp = 0x00200000; /* Z24S8 */
+		tile->zcomp |= tile->tag->offset;
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x01000000;
+#endif
+	}
+}
+
+struct nvkm_oclass *
+nv25_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x25),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = _nvkm_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv20_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv20_fb_tile_init,
+	.tile.comp = nv25_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c
new file mode 100644
index 0000000..09ebb94
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+void
+nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+		  u32 flags, struct nvkm_fb_tile *tile)
+{
+	/* for performance, select alternate bank offset for zeta */
+	if (!(flags & 4)) {
+		tile->addr = (0 << 4);
+	} else {
+		if (pfb->tile.comp) /* z compression */
+			pfb->tile.comp(pfb, i, size, flags, tile);
+		tile->addr = (1 << 4);
+	}
+
+	tile->addr |= 0x00000001; /* enable */
+	tile->addr |= addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+}
+
+static void
+nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
+	if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
+		else           tile->zcomp |= 0x02000000; /* Z24S8 */
+		tile->zcomp |= ((tile->tag->offset           ) >> 6);
+		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x10000000;
+#endif
+	}
+}
+
+static int
+calc_bias(struct nv04_fb_priv *priv, int k, int i, int j)
+{
+	struct nvkm_device *device = nv_device(priv);
+	int b = (device->chipset > 0x30 ?
+		 nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
+		 0) & 0xf;
+
+	return 2 * (b & 0x8 ? b - 0x10 : b);
+}
+
+static int
+calc_ref(struct nv04_fb_priv *priv, int l, int k, int i)
+{
+	int j, x = 0;
+
+	for (j = 0; j < 4; j++) {
+		int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j);
+
+		x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
+	}
+
+	return x;
+}
+
+int
+nv30_fb_init(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nv04_fb_priv *priv = (void *)object;
+	int ret, i, j;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* Init the memory timing regs at 0x10037c/0x1003ac */
+	if (device->chipset == 0x30 ||
+	    device->chipset == 0x31 ||
+	    device->chipset == 0x35) {
+		/* Related to ROP count */
+		int n = (device->chipset == 0x31 ? 2 : 4);
+		int l = nv_rd32(priv, 0x1003d0);
+
+		for (i = 0; i < n; i++) {
+			for (j = 0; j < 3; j++)
+				nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j,
+					calc_ref(priv, l, 0, j));
+
+			for (j = 0; j < 2; j++)
+				nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j,
+					calc_ref(priv, l, 1, j));
+		}
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nv30_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x30),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv30_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv20_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv30_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c
new file mode 100644
index 0000000..c01dc18
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv35_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
+	if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
+		else           tile->zcomp |= 0x08000000; /* Z24S8 */
+		tile->zcomp |= ((tile->tag->offset           ) >> 6);
+		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x40000000;
+#endif
+	}
+}
+
+struct nvkm_oclass *
+nv35_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x35),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv30_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv20_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv35_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c
new file mode 100644
index 0000000..cad75a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv36_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
+	if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
+		else           tile->zcomp |= 0x20000000; /* Z24S8 */
+		tile->zcomp |= ((tile->tag->offset           ) >> 6);
+		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x80000000;
+#endif
+	}
+}
+
+struct nvkm_oclass *
+nv36_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x36),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv30_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv20_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv36_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c
new file mode 100644
index 0000000..dbe5c19
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+void
+nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+		  struct nvkm_fb_tile *tile)
+{
+	u32 tiles = DIV_ROUND_UP(size, 0x80);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x100);
+	if ( (flags & 2) &&
+	    !nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+		tile->zcomp  = 0x28000000; /* Z24S8_SPLIT_GRAD */
+		tile->zcomp |= ((tile->tag->offset           ) >> 8);
+		tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
+#ifdef __BIG_ENDIAN
+		tile->zcomp |= 0x40000000;
+#endif
+	}
+}
+
+static int
+nv40_fb_init(struct nvkm_object *object)
+{
+	struct nv04_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv40_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x40),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv40_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv40_ram_oclass,
+	.tile.regions = 8,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv40_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h
new file mode 100644
index 0000000..6021826
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h
@@ -0,0 +1,14 @@
+#ifndef __NVKM_FB_NV40_H__
+#define __NVKM_FB_NV40_H__
+#include "priv.h"
+
+struct nv40_ram {
+	struct nvkm_ram base;
+	u32 ctrl;
+	u32 coef;
+};
+
+int  nv40_ram_calc(struct nvkm_fb *, u32);
+int  nv40_ram_prog(struct nvkm_fb *);
+void nv40_ram_tidy(struct nvkm_fb *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c
new file mode 100644
index 0000000..d9e1a40
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+void
+nv41_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
+	nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
+	nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
+	nv_rd32(pfb, 0x100600 + (i * 0x10));
+	nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp);
+}
+
+int
+nv41_fb_init(struct nvkm_object *object)
+{
+	struct nv04_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x100800, 0x00000001);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv41_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x41),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv41_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv41_ram_oclass,
+	.tile.regions = 12,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv40_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c
new file mode 100644
index 0000000..20b97c8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+		  u32 flags, struct nvkm_fb_tile *tile)
+{
+	tile->addr  = 0x00000001; /* mode = vram */
+	tile->addr |= addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+}
+
+void
+nv44_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+	nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
+	nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
+	nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
+	nv_rd32(pfb, 0x100600 + (i * 0x10));
+}
+
+int
+nv44_fb_init(struct nvkm_object *object)
+{
+	struct nv04_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x100850, 0x80000000);
+	nv_wr32(priv, 0x100800, 0x00000001);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv44_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x44),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv44_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv44_ram_oclass,
+	.tile.regions = 12,
+	.tile.init = nv44_fb_tile_init,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c
new file mode 100644
index 0000000..5bfac38
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+void
+nv46_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+		  u32 flags, struct nvkm_fb_tile *tile)
+{
+	/* for performance, select alternate bank offset for zeta */
+	if (!(flags & 4)) tile->addr = (0 << 3);
+	else              tile->addr = (1 << 3);
+
+	tile->addr |= 0x00000001; /* mode = vram */
+	tile->addr |= addr;
+	tile->limit = max(1u, addr + size) - 1;
+	tile->pitch = pitch;
+}
+
+struct nvkm_oclass *
+nv46_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x46),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv44_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv44_ram_oclass,
+	.tile.regions = 15,
+	.tile.init = nv46_fb_tile_init,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c
new file mode 100644
index 0000000..d3b3988
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv47_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x47),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv41_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv41_ram_oclass,
+	.tile.regions = 15,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv40_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c
new file mode 100644
index 0000000..236e36c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv49_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x49),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv41_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv49_ram_oclass,
+	.tile.regions = 15,
+	.tile.init = nv30_fb_tile_init,
+	.tile.comp = nv40_fb_tile_comp,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c
new file mode 100644
index 0000000..1352b6a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv4e_fb_oclass = &(struct nv04_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x4e),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_fb_ctor,
+		.dtor = _nvkm_fb_dtor,
+		.init = nv44_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv04_fb_memtype_valid,
+	.base.ram = &nv4e_ram_oclass,
+	.tile.regions = 12,
+	.tile.init = nv46_fb_tile_init,
+	.tile.fini = nv20_fb_tile_fini,
+	.tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
new file mode 100644
index 0000000..0480ce5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+int
+nv50_fb_memtype[0x80] = {
+	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+	0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+	1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
+};
+
+bool
+nv50_fb_memtype_valid(struct nvkm_fb *pfb, u32 memtype)
+{
+	return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
+}
+
+static const struct nvkm_enum vm_dispatch_subclients[] = {
+	{ 0x00000000, "GRCTX", NULL },
+	{ 0x00000001, "NOTIFY", NULL },
+	{ 0x00000002, "QUERY", NULL },
+	{ 0x00000003, "COND", NULL },
+	{ 0x00000004, "M2M_IN", NULL },
+	{ 0x00000005, "M2M_OUT", NULL },
+	{ 0x00000006, "M2M_NOTIFY", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_ccache_subclients[] = {
+	{ 0x00000000, "CB", NULL },
+	{ 0x00000001, "TIC", NULL },
+	{ 0x00000002, "TSC", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_prop_subclients[] = {
+	{ 0x00000000, "RT0", NULL },
+	{ 0x00000001, "RT1", NULL },
+	{ 0x00000002, "RT2", NULL },
+	{ 0x00000003, "RT3", NULL },
+	{ 0x00000004, "RT4", NULL },
+	{ 0x00000005, "RT5", NULL },
+	{ 0x00000006, "RT6", NULL },
+	{ 0x00000007, "RT7", NULL },
+	{ 0x00000008, "ZETA", NULL },
+	{ 0x00000009, "LOCAL", NULL },
+	{ 0x0000000a, "GLOBAL", NULL },
+	{ 0x0000000b, "STACK", NULL },
+	{ 0x0000000c, "DST2D", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_pfifo_subclients[] = {
+	{ 0x00000000, "PUSHBUF", NULL },
+	{ 0x00000001, "SEMAPHORE", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_bar_subclients[] = {
+	{ 0x00000000, "FB", NULL },
+	{ 0x00000001, "IN", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_client[] = {
+	{ 0x00000000, "STRMOUT", NULL },
+	{ 0x00000003, "DISPATCH", vm_dispatch_subclients },
+	{ 0x00000004, "PFIFO_WRITE", NULL },
+	{ 0x00000005, "CCACHE", vm_ccache_subclients },
+	{ 0x00000006, "PMSPPP", NULL },
+	{ 0x00000007, "CLIPID", NULL },
+	{ 0x00000008, "PFIFO_READ", NULL },
+	{ 0x00000009, "VFETCH", NULL },
+	{ 0x0000000a, "TEXTURE", NULL },
+	{ 0x0000000b, "PROP", vm_prop_subclients },
+	{ 0x0000000c, "PVP", NULL },
+	{ 0x0000000d, "PBSP", NULL },
+	{ 0x0000000e, "PCRYPT", NULL },
+	{ 0x0000000f, "PCOUNTER", NULL },
+	{ 0x00000011, "PDAEMON", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_engine[] = {
+	{ 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
+	{ 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
+	{ 0x00000004, "PEEPHOLE", NULL },
+	{ 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
+	{ 0x00000006, "BAR", vm_bar_subclients },
+	{ 0x00000008, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP },
+	{ 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
+	{ 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
+	{ 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CIPHER },
+	{ 0x0000000b, "PCOUNTER", NULL },
+	{ 0x0000000c, "SEMAPHORE_BG", NULL },
+	{ 0x0000000d, "PCE0", NULL, NVDEV_ENGINE_CE0 },
+	{ 0x0000000e, "PDAEMON", NULL },
+	{}
+};
+
+static const struct nvkm_enum vm_fault[] = {
+	{ 0x00000000, "PT_NOT_PRESENT", NULL },
+	{ 0x00000001, "PT_TOO_SHORT", NULL },
+	{ 0x00000002, "PAGE_NOT_PRESENT", NULL },
+	{ 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
+	{ 0x00000004, "PAGE_READ_ONLY", NULL },
+	{ 0x00000006, "NULL_DMAOBJ", NULL },
+	{ 0x00000007, "WRONG_MEMTYPE", NULL },
+	{ 0x0000000b, "VRAM_LIMIT", NULL },
+	{ 0x0000000f, "DMAOBJ_LIMIT", NULL },
+	{}
+};
+
+static void
+nv50_fb_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_device *device = nv_device(subdev);
+	struct nvkm_engine *engine;
+	struct nv50_fb_priv *priv = (void *)subdev;
+	const struct nvkm_enum *en, *cl;
+	struct nvkm_object *engctx = NULL;
+	u32 trap[6], idx, chan;
+	u8 st0, st1, st2, st3;
+	int i;
+
+	idx = nv_rd32(priv, 0x100c90);
+	if (!(idx & 0x80000000))
+		return;
+	idx &= 0x00ffffff;
+
+	for (i = 0; i < 6; i++) {
+		nv_wr32(priv, 0x100c90, idx | i << 24);
+		trap[i] = nv_rd32(priv, 0x100c94);
+	}
+	nv_wr32(priv, 0x100c90, idx | 0x80000000);
+
+	/* decode status bits into something more useful */
+	if (device->chipset  < 0xa3 ||
+	    device->chipset == 0xaa || device->chipset == 0xac) {
+		st0 = (trap[0] & 0x0000000f) >> 0;
+		st1 = (trap[0] & 0x000000f0) >> 4;
+		st2 = (trap[0] & 0x00000f00) >> 8;
+		st3 = (trap[0] & 0x0000f000) >> 12;
+	} else {
+		st0 = (trap[0] & 0x000000ff) >> 0;
+		st1 = (trap[0] & 0x0000ff00) >> 8;
+		st2 = (trap[0] & 0x00ff0000) >> 16;
+		st3 = (trap[0] & 0xff000000) >> 24;
+	}
+	chan = (trap[2] << 16) | trap[1];
+
+	en = nvkm_enum_find(vm_engine, st0);
+
+	if (en && en->data2) {
+		const struct nvkm_enum *orig_en = en;
+		while (en->name && en->value == st0 && en->data2) {
+			engine = nvkm_engine(subdev, en->data2);
+			/*XXX: clean this up */
+			if (!engine && en->data2 == NVDEV_ENGINE_BSP)
+				engine = nvkm_engine(subdev, NVDEV_ENGINE_MSVLD);
+			if (!engine && en->data2 == NVDEV_ENGINE_CIPHER)
+				engine = nvkm_engine(subdev, NVDEV_ENGINE_SEC);
+			if (!engine && en->data2 == NVDEV_ENGINE_VP)
+				engine = nvkm_engine(subdev, NVDEV_ENGINE_MSPDEC);
+			if (engine) {
+				engctx = nvkm_engctx_get(engine, chan);
+				if (engctx)
+					break;
+			}
+			en++;
+		}
+		if (!engctx)
+			en = orig_en;
+	}
+
+	nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
+		 (trap[5] & 0x00000100) ? "read" : "write",
+		 trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
+		 nvkm_client_name(engctx));
+
+	nvkm_engctx_put(engctx);
+
+	if (en)
+		pr_cont("%s/", en->name);
+	else
+		pr_cont("%02x/", st0);
+
+	cl = nvkm_enum_find(vm_client, st2);
+	if (cl)
+		pr_cont("%s/", cl->name);
+	else
+		pr_cont("%02x/", st2);
+
+	if      (cl && cl->data) cl = nvkm_enum_find(cl->data, st3);
+	else if (en && en->data) cl = nvkm_enum_find(en->data, st3);
+	else                     cl = NULL;
+	if (cl)
+		pr_cont("%s", cl->name);
+	else
+		pr_cont("%02x", st3);
+
+	pr_cont(" reason: ");
+	en = nvkm_enum_find(vm_fault, st1);
+	if (en)
+		pr_cont("%s\n", en->name);
+	else
+		pr_cont("0x%08x\n", st1);
+}
+
+int
+nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nv50_fb_priv *priv;
+	int ret;
+
+	ret = nvkm_fb_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (priv->r100c08_page) {
+		priv->r100c08 = dma_map_page(nv_device_base(device),
+					     priv->r100c08_page, 0, PAGE_SIZE,
+					     DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(nv_device_base(device), priv->r100c08))
+			return -EFAULT;
+	} else {
+		nv_warn(priv, "failed 0x100c08 page alloc\n");
+	}
+
+	nv_subdev(priv)->intr = nv50_fb_intr;
+	return 0;
+}
+
+void
+nv50_fb_dtor(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nv50_fb_priv *priv = (void *)object;
+
+	if (priv->r100c08_page) {
+		dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE,
+			       DMA_BIDIRECTIONAL);
+		__free_page(priv->r100c08_page);
+	}
+
+	nvkm_fb_destroy(&priv->base);
+}
+
+int
+nv50_fb_init(struct nvkm_object *object)
+{
+	struct nv50_fb_impl *impl = (void *)object->oclass;
+	struct nv50_fb_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_fb_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* Not a clue what this is exactly.  Without pointing it at a
+	 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
+	 * cause IOMMU "read from address 0" errors (rh#561267)
+	 */
+	nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
+
+	/* This is needed to get meaningful information from 100c90
+	 * on traps. No idea what these values mean exactly. */
+	nv_wr32(priv, 0x100c90, impl->trap);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_fb_oclass = &(struct nv50_fb_impl) {
+	.base.base.handle = NV_SUBDEV(FB, 0x50),
+	.base.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fb_ctor,
+		.dtor = nv50_fb_dtor,
+		.init = nv50_fb_init,
+		.fini = _nvkm_fb_fini,
+	},
+	.base.memtype = nv50_fb_memtype_valid,
+	.base.ram = &nv50_ram_oclass,
+	.trap = 0x000707ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
new file mode 100644
index 0000000..f3cde3f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
@@ -0,0 +1,31 @@
+#ifndef __NVKM_FB_NV50_H__
+#define __NVKM_FB_NV50_H__
+#include "priv.h"
+
+struct nv50_fb_priv {
+	struct nvkm_fb base;
+	struct page *r100c08_page;
+	dma_addr_t r100c08;
+};
+
+int  nv50_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+		  struct nvkm_oclass *, void *, u32,
+		  struct nvkm_object **);
+void nv50_fb_dtor(struct nvkm_object *);
+int  nv50_fb_init(struct nvkm_object *);
+
+struct nv50_fb_impl {
+	struct nvkm_fb_impl base;
+	u32 trap;
+};
+
+#define nv50_ram_create(p,e,o,d)                                               \
+	nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
+int  nv50_ram_create_(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, int, void **);
+int  nv50_ram_get(struct nvkm_fb *, u64 size, u32 align, u32 ncmin,
+		  u32 memtype, struct nvkm_mem **);
+void nv50_ram_put(struct nvkm_fb *, struct nvkm_mem **);
+void __nv50_ram_put(struct nvkm_fb *, struct nvkm_mem *);
+extern int nv50_fb_memtype[0x80];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
new file mode 100644
index 0000000..d82da02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
@@ -0,0 +1,74 @@
+#ifndef __NVKM_FB_PRIV_H__
+#define __NVKM_FB_PRIV_H__
+#include <subdev/fb.h>
+struct nvkm_bios;
+
+#define nvkm_ram_create(p,e,o,d)                                            \
+	nvkm_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
+#define nvkm_ram_destroy(p)                                                 \
+	nvkm_object_destroy(&(p)->base)
+#define nvkm_ram_init(p)                                                    \
+	nvkm_object_init(&(p)->base)
+#define nvkm_ram_fini(p,s)                                                  \
+	nvkm_object_fini(&(p)->base, (s))
+
+#define nvkm_ram_create_(p,e,o,s,d)                                         \
+	nvkm_object_create_((p), (e), (o), 0, (s), (void **)d)
+#define _nvkm_ram_dtor nvkm_object_destroy
+#define _nvkm_ram_init nvkm_object_init
+#define _nvkm_ram_fini nvkm_object_fini
+
+extern struct nvkm_oclass nv04_ram_oclass;
+extern struct nvkm_oclass nv10_ram_oclass;
+extern struct nvkm_oclass nv1a_ram_oclass;
+extern struct nvkm_oclass nv20_ram_oclass;
+extern struct nvkm_oclass nv40_ram_oclass;
+extern struct nvkm_oclass nv41_ram_oclass;
+extern struct nvkm_oclass nv44_ram_oclass;
+extern struct nvkm_oclass nv49_ram_oclass;
+extern struct nvkm_oclass nv4e_ram_oclass;
+extern struct nvkm_oclass nv50_ram_oclass;
+extern struct nvkm_oclass gt215_ram_oclass;
+extern struct nvkm_oclass mcp77_ram_oclass;
+extern struct nvkm_oclass gf100_ram_oclass;
+extern struct nvkm_oclass gk104_ram_oclass;
+extern struct nvkm_oclass gk20a_ram_oclass;
+extern struct nvkm_oclass gm107_ram_oclass;
+
+int nvkm_sddr2_calc(struct nvkm_ram *ram);
+int nvkm_sddr3_calc(struct nvkm_ram *ram);
+int nvkm_gddr3_calc(struct nvkm_ram *ram);
+int nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts);
+
+#define nvkm_fb_create(p,e,c,d)                                             \
+	nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
+#define nvkm_fb_destroy(p) ({                                               \
+	struct nvkm_fb *pfb = (p);                                          \
+	_nvkm_fb_dtor(nv_object(pfb));                                      \
+})
+#define nvkm_fb_init(p) ({                                                  \
+	struct nvkm_fb *pfb = (p);                                          \
+	_nvkm_fb_init(nv_object(pfb));                                      \
+})
+#define nvkm_fb_fini(p,s) ({                                                \
+	struct nvkm_fb *pfb = (p);                                          \
+	_nvkm_fb_fini(nv_object(pfb), (s));                                 \
+})
+
+int nvkm_fb_create_(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, int, void **);
+void _nvkm_fb_dtor(struct nvkm_object *);
+int  _nvkm_fb_init(struct nvkm_object *);
+int  _nvkm_fb_fini(struct nvkm_object *, bool);
+
+struct nvkm_fb_impl {
+	struct nvkm_oclass base;
+	struct nvkm_oclass *ram;
+	bool (*memtype)(struct nvkm_fb *, u32);
+};
+
+bool nv04_fb_memtype_valid(struct nvkm_fb *, u32 memtype);
+bool nv50_fb_memtype_valid(struct nvkm_fb *, u32 memtype);
+
+int  nvkm_fb_bios_memtype(struct nvkm_bios *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h
new file mode 100644
index 0000000..f343682
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h
@@ -0,0 +1,180 @@
+#ifndef __NVKM_FBRAM_FUC_H__
+#define __NVKM_FBRAM_FUC_H__
+#include <subdev/pmu.h>
+
+struct ramfuc {
+	struct nvkm_memx *memx;
+	struct nvkm_fb *pfb;
+	int sequence;
+};
+
+struct ramfuc_reg {
+	int sequence;
+	bool force;
+	u32 addr;
+	u32 stride; /* in bytes */
+	u32 mask;
+	u32 data;
+};
+
+static inline struct ramfuc_reg
+ramfuc_stride(u32 addr, u32 stride, u32 mask)
+{
+	return (struct ramfuc_reg) {
+		.sequence = 0,
+		.addr = addr,
+		.stride = stride,
+		.mask = mask,
+		.data = 0xdeadbeef,
+	};
+}
+
+static inline struct ramfuc_reg
+ramfuc_reg2(u32 addr1, u32 addr2)
+{
+	return (struct ramfuc_reg) {
+		.sequence = 0,
+		.addr = addr1,
+		.stride = addr2 - addr1,
+		.mask = 0x3,
+		.data = 0xdeadbeef,
+	};
+}
+
+static noinline struct ramfuc_reg
+ramfuc_reg(u32 addr)
+{
+	return (struct ramfuc_reg) {
+		.sequence = 0,
+		.addr = addr,
+		.stride = 0,
+		.mask = 0x1,
+		.data = 0xdeadbeef,
+	};
+}
+
+static inline int
+ramfuc_init(struct ramfuc *ram, struct nvkm_fb *pfb)
+{
+	struct nvkm_pmu *pmu = nvkm_pmu(pfb);
+	int ret;
+
+	ret = nvkm_memx_init(pmu, &ram->memx);
+	if (ret)
+		return ret;
+
+	ram->sequence++;
+	ram->pfb = pfb;
+	return 0;
+}
+
+static inline int
+ramfuc_exec(struct ramfuc *ram, bool exec)
+{
+	int ret = 0;
+	if (ram->pfb) {
+		ret = nvkm_memx_fini(&ram->memx, exec);
+		ram->pfb = NULL;
+	}
+	return ret;
+}
+
+static inline u32
+ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+	if (reg->sequence != ram->sequence)
+		reg->data = nv_rd32(ram->pfb, reg->addr);
+	return reg->data;
+}
+
+static inline void
+ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
+{
+	unsigned int mask, off = 0;
+
+	reg->sequence = ram->sequence;
+	reg->data = data;
+
+	for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
+		if (mask & 1)
+			nvkm_memx_wr32(ram->memx, reg->addr+off, reg->data);
+		off += reg->stride;
+	}
+}
+
+static inline void
+ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+	reg->force = true;
+}
+
+static inline u32
+ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
+{
+	u32 temp = ramfuc_rd32(ram, reg);
+	if (temp != ((temp & ~mask) | data) || reg->force) {
+		ramfuc_wr32(ram, reg, (temp & ~mask) | data);
+		reg->force = false;
+	}
+	return temp;
+}
+
+static inline void
+ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
+{
+	nvkm_memx_wait(ram->memx, addr, mask, data, nsec);
+}
+
+static inline void
+ramfuc_nsec(struct ramfuc *ram, u32 nsec)
+{
+	nvkm_memx_nsec(ram->memx, nsec);
+}
+
+static inline void
+ramfuc_wait_vblank(struct ramfuc *ram)
+{
+	nvkm_memx_wait_vblank(ram->memx);
+}
+
+static inline void
+ramfuc_train(struct ramfuc *ram)
+{
+	nvkm_memx_train(ram->memx);
+}
+
+static inline int
+ramfuc_train_result(struct nvkm_fb *pfb, u32 *result, u32 rsize)
+{
+	struct nvkm_pmu *pmu = nvkm_pmu(pfb);
+
+	return nvkm_memx_train_result(pmu, result, rsize);
+}
+
+static inline void
+ramfuc_block(struct ramfuc *ram)
+{
+	nvkm_memx_block(ram->memx);
+}
+
+static inline void
+ramfuc_unblock(struct ramfuc *ram)
+{
+	nvkm_memx_unblock(ram->memx);
+}
+
+#define ram_init(s,p)        ramfuc_init(&(s)->base, (p))
+#define ram_exec(s,e)        ramfuc_exec(&(s)->base, (e))
+#define ram_have(s,r)        ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r)        ramfuc_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d)      ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r)        ramfuc_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d)    ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_wait(s,r,m,d,n)  ramfuc_wait(&(s)->base, (r), (m), (d), (n))
+#define ram_nsec(s,n)        ramfuc_nsec(&(s)->base, (n))
+#define ram_wait_vblank(s)   ramfuc_wait_vblank(&(s)->base)
+#define ram_train(s)         ramfuc_train(&(s)->base)
+#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
+#define ram_block(s)         ramfuc_block(&(s)->base)
+#define ram_unblock(s)       ramfuc_unblock(&(s)->base)
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
new file mode 100644
index 0000000..de9f395
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+#include "ramfuc.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk.h>
+#include <subdev/clk/pll.h>
+#include <subdev/ltc.h>
+
+struct gf100_ramfuc {
+	struct ramfuc base;
+
+	struct ramfuc_reg r_0x10fe20;
+	struct ramfuc_reg r_0x10fe24;
+	struct ramfuc_reg r_0x137320;
+	struct ramfuc_reg r_0x137330;
+
+	struct ramfuc_reg r_0x132000;
+	struct ramfuc_reg r_0x132004;
+	struct ramfuc_reg r_0x132100;
+
+	struct ramfuc_reg r_0x137390;
+
+	struct ramfuc_reg r_0x10f290;
+	struct ramfuc_reg r_0x10f294;
+	struct ramfuc_reg r_0x10f298;
+	struct ramfuc_reg r_0x10f29c;
+	struct ramfuc_reg r_0x10f2a0;
+
+	struct ramfuc_reg r_0x10f300;
+	struct ramfuc_reg r_0x10f338;
+	struct ramfuc_reg r_0x10f340;
+	struct ramfuc_reg r_0x10f344;
+	struct ramfuc_reg r_0x10f348;
+
+	struct ramfuc_reg r_0x10f910;
+	struct ramfuc_reg r_0x10f914;
+
+	struct ramfuc_reg r_0x100b0c;
+	struct ramfuc_reg r_0x10f050;
+	struct ramfuc_reg r_0x10f090;
+	struct ramfuc_reg r_0x10f200;
+	struct ramfuc_reg r_0x10f210;
+	struct ramfuc_reg r_0x10f310;
+	struct ramfuc_reg r_0x10f314;
+	struct ramfuc_reg r_0x10f610;
+	struct ramfuc_reg r_0x10f614;
+	struct ramfuc_reg r_0x10f800;
+	struct ramfuc_reg r_0x10f808;
+	struct ramfuc_reg r_0x10f824;
+	struct ramfuc_reg r_0x10f830;
+	struct ramfuc_reg r_0x10f988;
+	struct ramfuc_reg r_0x10f98c;
+	struct ramfuc_reg r_0x10f990;
+	struct ramfuc_reg r_0x10f998;
+	struct ramfuc_reg r_0x10f9b0;
+	struct ramfuc_reg r_0x10f9b4;
+	struct ramfuc_reg r_0x10fb04;
+	struct ramfuc_reg r_0x10fb08;
+	struct ramfuc_reg r_0x137300;
+	struct ramfuc_reg r_0x137310;
+	struct ramfuc_reg r_0x137360;
+	struct ramfuc_reg r_0x1373ec;
+	struct ramfuc_reg r_0x1373f0;
+	struct ramfuc_reg r_0x1373f8;
+
+	struct ramfuc_reg r_0x61c140;
+	struct ramfuc_reg r_0x611200;
+
+	struct ramfuc_reg r_0x13d8f4;
+};
+
+struct gf100_ram {
+	struct nvkm_ram base;
+	struct gf100_ramfuc fuc;
+	struct nvbios_pll refpll;
+	struct nvbios_pll mempll;
+};
+
+static void
+gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic)
+{
+	struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc);
+	struct nvkm_fb *pfb = nvkm_fb(ram);
+	u32 part = nv_rd32(pfb, 0x022438), i;
+	u32 mask = nv_rd32(pfb, 0x022554);
+	u32 addr = 0x110974;
+
+	ram_wr32(fuc, 0x10f910, magic);
+	ram_wr32(fuc, 0x10f914, magic);
+
+	for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
+		if (mask & (1 << i))
+			continue;
+		ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+	}
+}
+
+static int
+gf100_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+	struct nvkm_clk *clk = nvkm_clk(pfb);
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct gf100_ram *ram = (void *)pfb->ram;
+	struct gf100_ramfuc *fuc = &ram->fuc;
+	struct nvbios_ramcfg cfg;
+	u8  ver, cnt, len, strap;
+	struct {
+		u32 data;
+		u8  size;
+	} rammap, ramcfg, timing;
+	int ref, div, out;
+	int from, mode;
+	int N1, M1, P;
+	int ret;
+
+	/* lookup memory config data relevant to the target frequency */
+	rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
+				      &cnt, &ramcfg.size, &cfg);
+	if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
+		nv_error(pfb, "invalid/missing rammap entry\n");
+		return -EINVAL;
+	}
+
+	/* locate specific data set for the attached memory */
+	strap = nvbios_ramcfg_index(nv_subdev(pfb));
+	if (strap >= cnt) {
+		nv_error(pfb, "invalid ramcfg strap\n");
+		return -EINVAL;
+	}
+
+	ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
+	if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
+		nv_error(pfb, "invalid/missing ramcfg entry\n");
+		return -EINVAL;
+	}
+
+	/* lookup memory timings, if bios says they're present */
+	strap = nv_ro08(bios, ramcfg.data + 0x01);
+	if (strap != 0xff) {
+		timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
+					      &cnt, &len);
+		if (!timing.data || ver != 0x10 || timing.size < 0x19) {
+			nv_error(pfb, "invalid/missing timing entry\n");
+			return -EINVAL;
+		}
+	} else {
+		timing.data = 0;
+	}
+
+	ret = ram_init(fuc, pfb);
+	if (ret)
+		return ret;
+
+	/* determine current mclk configuration */
+	from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
+
+	/* determine target mclk configuration */
+	if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
+		ref = clk->read(clk, nv_clk_src_sppll0);
+	else
+		ref = clk->read(clk, nv_clk_src_sppll1);
+	div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
+	out = (ref * 2) / (div + 2);
+	mode = freq != out;
+
+	ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
+
+	if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
+		ram_nuke(fuc, 0x132000);
+		ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
+		ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
+	}
+
+	if (mode == 1) {
+		ram_nuke(fuc, 0x10fe20);
+		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
+		ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
+	}
+
+// 0x00020034 // 0x0000000a
+	ram_wr32(fuc, 0x132100, 0x00000001);
+
+	if (mode == 1 && from == 0) {
+		/* calculate refpll */
+		ret = gt215_pll_calc(nv_subdev(pfb), &ram->refpll,
+				     ram->mempll.refclk, &N1, NULL, &M1, &P);
+		if (ret <= 0) {
+			nv_error(pfb, "unable to calc refpll\n");
+			return ret ? ret : -ERANGE;
+		}
+
+		ram_wr32(fuc, 0x10fe20, 0x20010000);
+		ram_wr32(fuc, 0x137320, 0x00000003);
+		ram_wr32(fuc, 0x137330, 0x81200006);
+		ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
+		ram_wr32(fuc, 0x10fe20, 0x20010001);
+		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+
+		/* calculate mempll */
+		ret = gt215_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
+				     &N1, NULL, &M1, &P);
+		if (ret <= 0) {
+			nv_error(pfb, "unable to calc refpll\n");
+			return ret ? ret : -ERANGE;
+		}
+
+		ram_wr32(fuc, 0x10fe20, 0x20010005);
+		ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
+		ram_wr32(fuc, 0x132000, 0x18010101);
+		ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+	} else
+	if (mode == 0) {
+		ram_wr32(fuc, 0x137300, 0x00000003);
+	}
+
+	if (from == 0) {
+		ram_nuke(fuc, 0x10fb04);
+		ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
+		ram_nuke(fuc, 0x10fb08);
+		ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
+		ram_wr32(fuc, 0x10f988, 0x2004ff00);
+		ram_wr32(fuc, 0x10f98c, 0x003fc040);
+		ram_wr32(fuc, 0x10f990, 0x20012001);
+		ram_wr32(fuc, 0x10f998, 0x00011a00);
+		ram_wr32(fuc, 0x13d8f4, 0x00000000);
+	} else {
+		ram_wr32(fuc, 0x10f988, 0x20010000);
+		ram_wr32(fuc, 0x10f98c, 0x00000000);
+		ram_wr32(fuc, 0x10f990, 0x20012001);
+		ram_wr32(fuc, 0x10f998, 0x00010a00);
+	}
+
+	if (from == 0) {
+// 0x00020039 // 0x000000ba
+	}
+
+// 0x0002003a // 0x00000002
+	ram_wr32(fuc, 0x100b0c, 0x00080012);
+// 0x00030014 // 0x00000000 // 0x02b5f070
+// 0x00030014 // 0x00010000 // 0x02b5f070
+	ram_wr32(fuc, 0x611200, 0x00003300);
+// 0x00020034 // 0x0000000a
+// 0x00030020 // 0x00000001 // 0x00000000
+
+	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+	ram_wr32(fuc, 0x10f210, 0x00000000);
+	ram_nsec(fuc, 1000);
+	if (mode == 0)
+		gf100_ram_train(fuc, 0x000c1001);
+	ram_wr32(fuc, 0x10f310, 0x00000001);
+	ram_nsec(fuc, 1000);
+	ram_wr32(fuc, 0x10f090, 0x00000061);
+	ram_wr32(fuc, 0x10f090, 0xc000007f);
+	ram_nsec(fuc, 1000);
+
+	if (from == 0) {
+		ram_wr32(fuc, 0x10f824, 0x00007fd4);
+	} else {
+		ram_wr32(fuc, 0x1373ec, 0x00020404);
+	}
+
+	if (mode == 0) {
+		ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+		ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
+		ram_wr32(fuc, 0x10f830, 0x41500010);
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+		ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
+		ram_wr32(fuc, 0x10f050, 0xff000090);
+		ram_wr32(fuc, 0x1373ec, 0x00020f0f);
+		ram_wr32(fuc, 0x1373f0, 0x00000003);
+		ram_wr32(fuc, 0x137310, 0x81201616);
+		ram_wr32(fuc, 0x132100, 0x00000001);
+// 0x00020039 // 0x000000ba
+		ram_wr32(fuc, 0x10f830, 0x00300017);
+		ram_wr32(fuc, 0x1373f0, 0x00000001);
+		ram_wr32(fuc, 0x10f824, 0x00007e77);
+		ram_wr32(fuc, 0x132000, 0x18030001);
+		ram_wr32(fuc, 0x10f090, 0x4000007e);
+		ram_nsec(fuc, 2000);
+		ram_wr32(fuc, 0x10f314, 0x00000001);
+		ram_wr32(fuc, 0x10f210, 0x80000000);
+		ram_wr32(fuc, 0x10f338, 0x00300220);
+		ram_wr32(fuc, 0x10f300, 0x0000011d);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f290, 0x02060505);
+		ram_wr32(fuc, 0x10f294, 0x34208288);
+		ram_wr32(fuc, 0x10f298, 0x44050411);
+		ram_wr32(fuc, 0x10f29c, 0x0000114c);
+		ram_wr32(fuc, 0x10f2a0, 0x42e10069);
+		ram_wr32(fuc, 0x10f614, 0x40044f77);
+		ram_wr32(fuc, 0x10f610, 0x40044f77);
+		ram_wr32(fuc, 0x10f344, 0x00600009);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f348, 0x00700008);
+		ram_wr32(fuc, 0x61c140, 0x19240000);
+		ram_wr32(fuc, 0x10f830, 0x00300017);
+		gf100_ram_train(fuc, 0x80021001);
+		gf100_ram_train(fuc, 0x80081001);
+		ram_wr32(fuc, 0x10f340, 0x00500004);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f830, 0x01300017);
+		ram_wr32(fuc, 0x10f830, 0x00300017);
+// 0x00030020 // 0x00000000 // 0x00000000
+// 0x00020034 // 0x0000000b
+		ram_wr32(fuc, 0x100b0c, 0x00080028);
+		ram_wr32(fuc, 0x611200, 0x00003330);
+	} else {
+		ram_wr32(fuc, 0x10f800, 0x00001800);
+		ram_wr32(fuc, 0x13d8f4, 0x00000000);
+		ram_wr32(fuc, 0x1373ec, 0x00020404);
+		ram_wr32(fuc, 0x1373f0, 0x00000003);
+		ram_wr32(fuc, 0x10f830, 0x40700010);
+		ram_wr32(fuc, 0x10f830, 0x40500010);
+		ram_wr32(fuc, 0x13d8f4, 0x00000000);
+		ram_wr32(fuc, 0x1373f8, 0x00000000);
+		ram_wr32(fuc, 0x132100, 0x00000101);
+		ram_wr32(fuc, 0x137310, 0x89201616);
+		ram_wr32(fuc, 0x10f050, 0xff000090);
+		ram_wr32(fuc, 0x1373ec, 0x00030404);
+		ram_wr32(fuc, 0x1373f0, 0x00000002);
+	// 0x00020039 // 0x00000011
+		ram_wr32(fuc, 0x132100, 0x00000001);
+		ram_wr32(fuc, 0x1373f8, 0x00002000);
+		ram_nsec(fuc, 2000);
+		ram_wr32(fuc, 0x10f808, 0x7aaa0050);
+		ram_wr32(fuc, 0x10f830, 0x00500010);
+		ram_wr32(fuc, 0x10f200, 0x00ce1000);
+		ram_wr32(fuc, 0x10f090, 0x4000007e);
+		ram_nsec(fuc, 2000);
+		ram_wr32(fuc, 0x10f314, 0x00000001);
+		ram_wr32(fuc, 0x10f210, 0x80000000);
+		ram_wr32(fuc, 0x10f338, 0x00300200);
+		ram_wr32(fuc, 0x10f300, 0x0000084d);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f290, 0x0b343825);
+		ram_wr32(fuc, 0x10f294, 0x3483028e);
+		ram_wr32(fuc, 0x10f298, 0x440c0600);
+		ram_wr32(fuc, 0x10f29c, 0x0000214c);
+		ram_wr32(fuc, 0x10f2a0, 0x42e20069);
+		ram_wr32(fuc, 0x10f200, 0x00ce0000);
+		ram_wr32(fuc, 0x10f614, 0x60044e77);
+		ram_wr32(fuc, 0x10f610, 0x60044e77);
+		ram_wr32(fuc, 0x10f340, 0x00500000);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f344, 0x00600228);
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f348, 0x00700000);
+		ram_wr32(fuc, 0x13d8f4, 0x00000000);
+		ram_wr32(fuc, 0x61c140, 0x09a40000);
+
+		gf100_ram_train(fuc, 0x800e1008);
+
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f800, 0x00001804);
+	// 0x00030020 // 0x00000000 // 0x00000000
+	// 0x00020034 // 0x0000000b
+		ram_wr32(fuc, 0x13d8f4, 0x00000000);
+		ram_wr32(fuc, 0x100b0c, 0x00080028);
+		ram_wr32(fuc, 0x611200, 0x00003330);
+		ram_nsec(fuc, 100000);
+		ram_wr32(fuc, 0x10f9b0, 0x05313f41);
+		ram_wr32(fuc, 0x10f9b4, 0x00002f50);
+
+		gf100_ram_train(fuc, 0x010c1001);
+	}
+
+	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
+// 0x00020016 // 0x00000000
+
+	if (mode == 0)
+		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+
+	return 0;
+}
+
+static int
+gf100_ram_prog(struct nvkm_fb *pfb)
+{
+	struct nvkm_device *device = nv_device(pfb);
+	struct gf100_ram *ram = (void *)pfb->ram;
+	struct gf100_ramfuc *fuc = &ram->fuc;
+	ram_exec(fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
+	return 0;
+}
+
+static void
+gf100_ram_tidy(struct nvkm_fb *pfb)
+{
+	struct gf100_ram *ram = (void *)pfb->ram;
+	struct gf100_ramfuc *fuc = &ram->fuc;
+	ram_exec(fuc, false);
+}
+
+extern const u8 gf100_pte_storage_type_map[256];
+
+void
+gf100_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+	struct nvkm_ltc *ltc = nvkm_ltc(pfb);
+	struct nvkm_mem *mem = *pmem;
+
+	*pmem = NULL;
+	if (unlikely(mem == NULL))
+		return;
+
+	mutex_lock(&pfb->base.mutex);
+	if (mem->tag)
+		ltc->tags_free(ltc, &mem->tag);
+	__nv50_ram_put(pfb, mem);
+	mutex_unlock(&pfb->base.mutex);
+
+	kfree(mem);
+}
+
+int
+gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+	      u32 memtype, struct nvkm_mem **pmem)
+{
+	struct nvkm_mm *mm = &pfb->vram;
+	struct nvkm_mm_node *r;
+	struct nvkm_mem *mem;
+	int type = (memtype & 0x0ff);
+	int back = (memtype & 0x800);
+	const bool comp = gf100_pte_storage_type_map[type] != type;
+	int ret;
+
+	size  >>= 12;
+	align >>= 12;
+	ncmin >>= 12;
+	if (!ncmin)
+		ncmin = size;
+
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&mem->regions);
+	mem->size = size;
+
+	mutex_lock(&pfb->base.mutex);
+	if (comp) {
+		struct nvkm_ltc *ltc = nvkm_ltc(pfb);
+
+		/* compression only works with lpages */
+		if (align == (1 << (17 - 12))) {
+			int n = size >> 5;
+			ltc->tags_alloc(ltc, n, &mem->tag);
+		}
+
+		if (unlikely(!mem->tag))
+			type = gf100_pte_storage_type_map[type];
+	}
+	mem->memtype = type;
+
+	do {
+		if (back)
+			ret = nvkm_mm_tail(mm, 0, 1, size, ncmin, align, &r);
+		else
+			ret = nvkm_mm_head(mm, 0, 1, size, ncmin, align, &r);
+		if (ret) {
+			mutex_unlock(&pfb->base.mutex);
+			pfb->ram->put(pfb, &mem);
+			return ret;
+		}
+
+		list_add_tail(&r->rl_entry, &mem->regions);
+		size -= r->length;
+	} while (size);
+	mutex_unlock(&pfb->base.mutex);
+
+	r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry);
+	mem->offset = (u64)r->offset << 12;
+	*pmem = mem;
+	return 0;
+}
+
+int
+gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, u32 maskaddr, int size,
+		  void **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nvkm_ram *ram;
+	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+	u32 parts = nv_rd32(pfb, 0x022438);
+	u32 pmask = nv_rd32(pfb, maskaddr);
+	u32 bsize = nv_rd32(pfb, 0x10f20c);
+	u32 offset, length;
+	bool uniform = true;
+	int ret, part;
+
+	ret = nvkm_ram_create_(parent, engine, oclass, size, pobject);
+	ram = *pobject;
+	if (ret)
+		return ret;
+
+	nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
+	nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+	ram->type = nvkm_fb_bios_memtype(bios);
+	ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
+
+	/* read amount of vram attached to each memory controller */
+	for (part = 0; part < parts; part++) {
+		if (!(pmask & (1 << part))) {
+			u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
+			if (psize != bsize) {
+				if (psize < bsize)
+					bsize = psize;
+				uniform = false;
+			}
+
+			nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
+			ram->size += (u64)psize << 20;
+		}
+	}
+
+	/* if all controllers have the same amount attached, there's no holes */
+	if (uniform) {
+		offset = rsvd_head;
+		length = (ram->size >> 12) - rsvd_head - rsvd_tail;
+		ret = nvkm_mm_init(&pfb->vram, offset, length, 1);
+	} else {
+		/* otherwise, address lowest common amount from 0GiB */
+		ret = nvkm_mm_init(&pfb->vram, rsvd_head,
+				   (bsize << 8) * parts - rsvd_head, 1);
+		if (ret)
+			return ret;
+
+		/* and the rest starting from (8GiB + common_size) */
+		offset = (0x0200000000ULL >> 12) + (bsize << 8);
+		length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
+
+		ret = nvkm_mm_init(&pfb->vram, offset, length, 1);
+		if (ret)
+			nvkm_mm_fini(&pfb->vram);
+	}
+
+	if (ret)
+		return ret;
+
+	ram->get = gf100_ram_get;
+	ram->put = gf100_ram_put;
+	return 0;
+}
+
+static int
+gf100_ram_init(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = (void *)object->parent;
+	struct gf100_ram *ram = (void *)object;
+	int ret, i;
+
+	ret = nvkm_ram_init(&ram->base);
+	if (ret)
+		return ret;
+
+	/* prepare for ddr link training, and load training patterns */
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_GDDR5: {
+		static const u8  train0[] = {
+			0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
+			0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+		};
+		static const u32 train1[] = {
+			0x00000000, 0xffffffff,
+			0x55555555, 0xaaaaaaaa,
+			0x33333333, 0xcccccccc,
+			0xf0f0f0f0, 0x0f0f0f0f,
+			0x00ff00ff, 0xff00ff00,
+			0x0000ffff, 0xffff0000,
+		};
+
+		for (i = 0; i < 0x30; i++) {
+			nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
+			nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
+			nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
+			nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
+			nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+			nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+			nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
+			nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
+			nv_wr32(pfb, 0x10f918,              train1[i % 12]);
+			nv_wr32(pfb, 0x10f91c,              train1[i % 12]);
+		}
+	}	break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int
+gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct gf100_ram *ram;
+	int ret;
+
+	ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
+	if (ret) {
+		nv_error(ram, "mclk refpll data not found\n");
+		return ret;
+	}
+
+	ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
+	if (ret) {
+		nv_error(ram, "mclk pll data not found\n");
+		return ret;
+	}
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_GDDR5:
+		ram->base.calc = gf100_ram_calc;
+		ram->base.prog = gf100_ram_prog;
+		ram->base.tidy = gf100_ram_tidy;
+		break;
+	default:
+		nv_warn(ram, "reclocking of this ram type unsupported\n");
+		return 0;
+	}
+
+	ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
+	ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
+	ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+	ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
+
+	ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+	ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+	ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
+
+	ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
+
+	ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+	ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+	ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+	ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+	ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+
+	ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
+	ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
+	ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
+	ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
+	ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
+
+	ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+	ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+	ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
+	ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
+	ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+	ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+	ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+	ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+	ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+	ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+	ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+	ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+	ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+	ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+	ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+	ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
+	ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
+	ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
+	ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
+	ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
+	ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
+	ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
+	ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
+	ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
+	ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
+	ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
+	ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+	ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+	ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
+
+	ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
+	ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+	ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = gf100_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
new file mode 100644
index 0000000..1ef15c3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -0,0 +1,1639 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "ramfuc.h"
+#include "gf100.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/M0205.h>
+#include <subdev/bios/M0209.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk.h>
+#include <subdev/clk/pll.h>
+#include <subdev/gpio.h>
+
+struct gk104_ramfuc {
+	struct ramfuc base;
+
+	struct nvbios_pll refpll;
+	struct nvbios_pll mempll;
+
+	struct ramfuc_reg r_gpioMV;
+	u32 r_funcMV[2];
+	struct ramfuc_reg r_gpio2E;
+	u32 r_func2E[2];
+	struct ramfuc_reg r_gpiotrig;
+
+	struct ramfuc_reg r_0x132020;
+	struct ramfuc_reg r_0x132028;
+	struct ramfuc_reg r_0x132024;
+	struct ramfuc_reg r_0x132030;
+	struct ramfuc_reg r_0x132034;
+	struct ramfuc_reg r_0x132000;
+	struct ramfuc_reg r_0x132004;
+	struct ramfuc_reg r_0x132040;
+
+	struct ramfuc_reg r_0x10f248;
+	struct ramfuc_reg r_0x10f290;
+	struct ramfuc_reg r_0x10f294;
+	struct ramfuc_reg r_0x10f298;
+	struct ramfuc_reg r_0x10f29c;
+	struct ramfuc_reg r_0x10f2a0;
+	struct ramfuc_reg r_0x10f2a4;
+	struct ramfuc_reg r_0x10f2a8;
+	struct ramfuc_reg r_0x10f2ac;
+	struct ramfuc_reg r_0x10f2cc;
+	struct ramfuc_reg r_0x10f2e8;
+	struct ramfuc_reg r_0x10f250;
+	struct ramfuc_reg r_0x10f24c;
+	struct ramfuc_reg r_0x10fec4;
+	struct ramfuc_reg r_0x10fec8;
+	struct ramfuc_reg r_0x10f604;
+	struct ramfuc_reg r_0x10f614;
+	struct ramfuc_reg r_0x10f610;
+	struct ramfuc_reg r_0x100770;
+	struct ramfuc_reg r_0x100778;
+	struct ramfuc_reg r_0x10f224;
+
+	struct ramfuc_reg r_0x10f870;
+	struct ramfuc_reg r_0x10f698;
+	struct ramfuc_reg r_0x10f694;
+	struct ramfuc_reg r_0x10f6b8;
+	struct ramfuc_reg r_0x10f808;
+	struct ramfuc_reg r_0x10f670;
+	struct ramfuc_reg r_0x10f60c;
+	struct ramfuc_reg r_0x10f830;
+	struct ramfuc_reg r_0x1373ec;
+	struct ramfuc_reg r_0x10f800;
+	struct ramfuc_reg r_0x10f82c;
+
+	struct ramfuc_reg r_0x10f978;
+	struct ramfuc_reg r_0x10f910;
+	struct ramfuc_reg r_0x10f914;
+
+	struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
+
+	struct ramfuc_reg r_0x62c000;
+
+	struct ramfuc_reg r_0x10f200;
+
+	struct ramfuc_reg r_0x10f210;
+	struct ramfuc_reg r_0x10f310;
+	struct ramfuc_reg r_0x10f314;
+	struct ramfuc_reg r_0x10f318;
+	struct ramfuc_reg r_0x10f090;
+	struct ramfuc_reg r_0x10f69c;
+	struct ramfuc_reg r_0x10f824;
+	struct ramfuc_reg r_0x1373f0;
+	struct ramfuc_reg r_0x1373f4;
+	struct ramfuc_reg r_0x137320;
+	struct ramfuc_reg r_0x10f65c;
+	struct ramfuc_reg r_0x10f6bc;
+	struct ramfuc_reg r_0x100710;
+	struct ramfuc_reg r_0x100750;
+};
+
+struct gk104_ram {
+	struct nvkm_ram base;
+	struct gk104_ramfuc fuc;
+
+	struct list_head cfg;
+	u32 parts;
+	u32 pmask;
+	u32 pnuts;
+
+	struct nvbios_ramcfg diff;
+	int from;
+	int mode;
+	int N1, fN1, M1, P1;
+	int N2, M2, P2;
+};
+
+/*******************************************************************************
+ * GDDR5
+ ******************************************************************************/
+static void
+gk104_ram_train(struct gk104_ramfuc *fuc, u32 mask, u32 data)
+{
+	struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+	u32 addr = 0x110974, i;
+
+	ram_mask(fuc, 0x10f910, mask, data);
+	ram_mask(fuc, 0x10f914, mask, data);
+
+	for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
+		if (ram->pmask & (1 << i))
+			continue;
+		ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+	}
+}
+
+static void
+r1373f4_init(struct gk104_ramfuc *fuc)
+{
+	struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+	const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2);
+	const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+	const u32 runk0 = ram->fN1 << 16;
+	const u32 runk1 = ram->fN1;
+
+	if (ram->from == 2) {
+		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+	} else {
+		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+	}
+
+	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+	/* (re)program refpll, if required */
+	if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+	    (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+		ram_wr32(fuc, 0x137320, 0x00000000);
+		ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+		ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+		ram_wr32(fuc, 0x132024, rcoef);
+		ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+		ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+		ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+	}
+
+	/* (re)program mempll, if required */
+	if (ram->mode == 2) {
+		ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+		ram_mask(fuc, 0x132000, 0x80000000, 0x80000000);
+		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x132004, 0x103fffff, mcoef);
+		ram_mask(fuc, 0x132000, 0x00000001, 0x00000001);
+		ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+	} else {
+		ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100);
+	}
+
+	ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+}
+
+static void
+r1373f4_fini(struct gk104_ramfuc *fuc)
+{
+	struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+	struct nvkm_ram_data *next = ram->base.next;
+	u8 v0 = next->bios.ramcfg_11_03_c0;
+	u8 v1 = next->bios.ramcfg_11_03_30;
+	u32 tmp;
+
+	tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+	ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
+	ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
+	if (ram->mode == 2) {
+		ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
+		ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
+	} else {
+		ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
+		ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
+	}
+	ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
+}
+
+static void
+gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg,
+	       u32 _mask, u32 _data, u32 _copy)
+{
+	struct gk104_fb_priv *priv = (void *)nvkm_fb(ram);
+	struct ramfuc *fuc = &ram->fuc.base;
+	u32 addr = 0x110000 + (reg->addr & 0xfff);
+	u32 mask = _mask | _copy;
+	u32 data = (_data & _mask) | (reg->data & _copy);
+	u32 i;
+
+	for (i = 0; i < 16; i++, addr += 0x1000) {
+		if (ram->pnuts & (1 << i)) {
+			u32 prev = nv_rd32(priv, addr);
+			u32 next = (prev & ~mask) | data;
+			nvkm_memx_wr32(fuc->memx, addr, next);
+		}
+	}
+}
+#define ram_nuts(s,r,m,d,c)                                                    \
+	gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
+
+static int
+gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct gk104_ramfuc *fuc = &ram->fuc;
+	struct nvkm_ram_data *next = ram->base.next;
+	int vc = !next->bios.ramcfg_11_02_08;
+	int mv = !next->bios.ramcfg_11_02_04;
+	u32 mask, data;
+
+	ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+	ram_block(fuc);
+	ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+	/* MR1: turn termination on early, for some reason.. */
+	if ((ram->base.mr[1] & 0x03c) != 0x030) {
+		ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
+		ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
+	}
+
+	if (vc == 1 && ram_have(fuc, gpio2E)) {
+		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+		if (temp != ram_rd32(fuc, gpio2E)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 20000);
+		}
+	}
+
+	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+
+	gk104_ram_train(fuc, 0x01020000, 0x000c0000);
+
+	ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+	ram_nsec(fuc, 1000);
+	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+	ram_nsec(fuc, 1000);
+
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+	ram_wr32(fuc, 0x10f090, 0x00000061);
+	ram_wr32(fuc, 0x10f090, 0xc000007f);
+	ram_nsec(fuc, 1000);
+
+	ram_wr32(fuc, 0x10f698, 0x00000000);
+	ram_wr32(fuc, 0x10f69c, 0x00000000);
+
+	/*XXX: there does appear to be some kind of condition here, simply
+	 *     modifying these bits in the vbios from the default pl0
+	 *     entries shows no change.  however, the data does appear to
+	 *     be correct and may be required for the transition back
+	 */
+	mask = 0x800f07e0;
+	data = 0x00030000;
+	if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+		data |= 0x00040000;
+
+	if (1) {
+		data |= 0x800807e0;
+		switch (next->bios.ramcfg_11_03_c0) {
+		case 3: data &= ~0x00000040; break;
+		case 2: data &= ~0x00000100; break;
+		case 1: data &= ~0x80000000; break;
+		case 0: data &= ~0x00000400; break;
+		}
+
+		switch (next->bios.ramcfg_11_03_30) {
+		case 3: data &= ~0x00000020; break;
+		case 2: data &= ~0x00000080; break;
+		case 1: data &= ~0x00080000; break;
+		case 0: data &= ~0x00000200; break;
+		}
+	}
+
+	if (next->bios.ramcfg_11_02_80)
+		mask |= 0x03000000;
+	if (next->bios.ramcfg_11_02_40)
+		mask |= 0x00002000;
+	if (next->bios.ramcfg_11_07_10)
+		mask |= 0x00004000;
+	if (next->bios.ramcfg_11_07_08)
+		mask |= 0x00000003;
+	else {
+		mask |= 0x34000000;
+		if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+			mask |= 0x40000000;
+	}
+	ram_mask(fuc, 0x10f824, mask, data);
+
+	ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+	if (ram->from == 2 && ram->mode != 2) {
+		ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+		ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000);
+		ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
+		ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+		r1373f4_init(fuc);
+		ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
+		r1373f4_fini(fuc);
+		ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
+	} else
+	if (ram->from != 2 && ram->mode != 2) {
+		r1373f4_init(fuc);
+		r1373f4_fini(fuc);
+	}
+
+	if (ram_have(fuc, gpioMV)) {
+		u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+		if (temp != ram_rd32(fuc, gpioMV)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 64000);
+		}
+	}
+
+	if (next->bios.ramcfg_11_02_40 ||
+	    next->bios.ramcfg_11_07_10) {
+		ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+		ram_nsec(fuc, 20000);
+	}
+
+	if (ram->from != 2 && ram->mode == 2) {
+		if (0 /*XXX: Titan */)
+			ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000);
+		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+		ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
+		ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
+		r1373f4_init(fuc);
+		r1373f4_fini(fuc);
+		ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
+		ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
+	} else
+	if (ram->from == 2 && ram->mode == 2) {
+		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+		r1373f4_init(fuc);
+		r1373f4_fini(fuc);
+	}
+
+	if (ram->mode != 2) /*XXX*/ {
+		if (next->bios.ramcfg_11_07_40)
+			ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+	}
+
+	ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+	ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+	ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
+
+	if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) {
+		ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04);
+		ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04);
+	} else
+	if (!next->bios.ramcfg_11_07_08) {
+		ram_wr32(fuc, 0x10f698, 0x00000000);
+		ram_wr32(fuc, 0x10f69c, 0x00000000);
+	}
+
+	if (ram->mode != 2) {
+		u32 data = 0x01000100 * next->bios.ramcfg_11_04;
+		ram_nuke(fuc, 0x10f694);
+		ram_mask(fuc, 0x10f694, 0xff00ff00, data);
+	}
+
+	if (ram->mode == 2 && next->bios.ramcfg_11_08_10)
+		data = 0x00000080;
+	else
+		data = 0x00000000;
+	ram_mask(fuc, 0x10f60c, 0x00000080, data);
+
+	mask = 0x00070000;
+	data = 0x00000000;
+	if (!next->bios.ramcfg_11_02_80)
+		data |= 0x03000000;
+	if (!next->bios.ramcfg_11_02_40)
+		data |= 0x00002000;
+	if (!next->bios.ramcfg_11_07_10)
+		data |= 0x00004000;
+	if (!next->bios.ramcfg_11_07_08)
+		data |= 0x00000003;
+	else
+		data |= 0x74000000;
+	ram_mask(fuc, 0x10f824, mask, data);
+
+	if (next->bios.ramcfg_11_01_08)
+		data = 0x00000000;
+	else
+		data = 0x00001000;
+	ram_mask(fuc, 0x10f200, 0x00001000, data);
+
+	if (ram_rd32(fuc, 0x10f670) & 0x80000000) {
+		ram_nsec(fuc, 10000);
+		ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
+	}
+
+	if (next->bios.ramcfg_11_08_01)
+		data = 0x00100000;
+	else
+		data = 0x00000000;
+	ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+	data = 0x00000000;
+	if (next->bios.ramcfg_11_08_08)
+		data |= 0x00002000;
+	if (next->bios.ramcfg_11_08_04)
+		data |= 0x00001000;
+	if (next->bios.ramcfg_11_08_02)
+		data |= 0x00004000;
+	ram_mask(fuc, 0x10f830, 0x00007000, data);
+
+	/* PFB timing */
+	ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+	ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+	ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+	ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+	ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+	ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+	ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+	ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+	ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+	ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+	ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
+
+	data = mask = 0x00000000;
+	if (ram->diff.ramcfg_11_08_20) {
+		if (next->bios.ramcfg_11_08_20)
+			data |= 0x01000000;
+		mask |= 0x01000000;
+	}
+	ram_mask(fuc, 0x10f200, mask, data);
+
+	data = mask = 0x00000000;
+	if (ram->diff.ramcfg_11_02_03) {
+		data |= next->bios.ramcfg_11_02_03 << 8;
+		mask |= 0x00000300;
+	}
+	if (ram->diff.ramcfg_11_01_10) {
+		if (next->bios.ramcfg_11_01_10)
+			data |= 0x70000000;
+		mask |= 0x70000000;
+	}
+	ram_mask(fuc, 0x10f604, mask, data);
+
+	data = mask = 0x00000000;
+	if (ram->diff.timing_20_30_07) {
+		data |= next->bios.timing_20_30_07 << 28;
+		mask |= 0x70000000;
+	}
+	if (ram->diff.ramcfg_11_01_01) {
+		if (next->bios.ramcfg_11_01_01)
+			data |= 0x00000100;
+		mask |= 0x00000100;
+	}
+	ram_mask(fuc, 0x10f614, mask, data);
+
+	data = mask = 0x00000000;
+	if (ram->diff.timing_20_30_07) {
+		data |= next->bios.timing_20_30_07 << 28;
+		mask |= 0x70000000;
+	}
+	if (ram->diff.ramcfg_11_01_02) {
+		if (next->bios.ramcfg_11_01_02)
+			data |= 0x00000100;
+		mask |= 0x00000100;
+	}
+	ram_mask(fuc, 0x10f610, mask, data);
+
+	mask = 0x33f00000;
+	data = 0x00000000;
+	if (!next->bios.ramcfg_11_01_04)
+		data |= 0x20200000;
+	if (!next->bios.ramcfg_11_07_80)
+		data |= 0x12800000;
+	/*XXX: see note above about there probably being some condition
+	 *     for the 10f824 stuff that uses ramcfg 3...
+	 */
+	if (next->bios.ramcfg_11_03_f0) {
+		if (next->bios.rammap_11_08_0c) {
+			if (!next->bios.ramcfg_11_07_80)
+				mask |= 0x00000020;
+			else
+				data |= 0x00000020;
+			mask |= 0x00000004;
+		}
+	} else {
+		mask |= 0x40000020;
+		data |= 0x00000004;
+	}
+
+	ram_mask(fuc, 0x10f808, mask, data);
+
+	ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
+
+	data = mask = 0x00000000;
+	if (ram->diff.ramcfg_11_02_03) {
+		data |= next->bios.ramcfg_11_02_03;
+		mask |= 0x00000003;
+	}
+	if (ram->diff.ramcfg_11_01_10) {
+		if (next->bios.ramcfg_11_01_10)
+			data |= 0x00000004;
+		mask |= 0x00000004;
+	}
+
+	if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) {
+		ram_mask(fuc, 0x100750, 0x00000008, 0x00000008);
+		ram_wr32(fuc, 0x100710, 0x00000000);
+		ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
+	}
+
+	data = next->bios.timing_20_30_07 << 8;
+	if (next->bios.ramcfg_11_01_01)
+		data |= 0x80000000;
+	ram_mask(fuc, 0x100778, 0x00000700, data);
+
+	ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
+	data = (next->bios.timing[10] & 0x7f000000) >> 24;
+	if (data < next->bios.timing_20_2c_1fc0)
+		data = next->bios.timing_20_2c_1fc0;
+	ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+	ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
+
+	ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 |
+					    next->bios.timing_20_31_0780 << 17 |
+					    next->bios.timing_20_31_0078 << 8 |
+					    next->bios.timing_20_31_0007);
+	ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 |
+					    next->bios.timing_20_31_7000);
+
+	ram_wr32(fuc, 0x10f090, 0x4000007e);
+	ram_nsec(fuc, 2000);
+	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+	ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+
+	if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) {
+		u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
+		gk104_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/
+		ram_nsec(fuc, 1000);
+		ram_wr32(fuc, 0x10f294, temp);
+	}
+
+	ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]);
+	ram_wr32(fuc, mr[0], ram->base.mr[0]);
+	ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
+	ram_nsec(fuc, 1000);
+	ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
+	ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */
+	ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
+	ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
+
+	if (vc == 0 && ram_have(fuc, gpio2E)) {
+		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+		if (temp != ram_rd32(fuc, gpio2E)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 20000);
+		}
+	}
+
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+	ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+	ram_nsec(fuc, 1000);
+	ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800);
+
+	data  = ram_rd32(fuc, 0x10f978);
+	data &= ~0x00046144;
+	data |=  0x0000000b;
+	if (!next->bios.ramcfg_11_07_08) {
+		if (!next->bios.ramcfg_11_07_04)
+			data |= 0x0000200c;
+		else
+			data |= 0x00000000;
+	} else {
+		data |= 0x00040044;
+	}
+	ram_wr32(fuc, 0x10f978, data);
+
+	if (ram->mode == 1) {
+		data = ram_rd32(fuc, 0x10f830) | 0x00000001;
+		ram_wr32(fuc, 0x10f830, data);
+	}
+
+	if (!next->bios.ramcfg_11_07_08) {
+		data = 0x88020000;
+		if ( next->bios.ramcfg_11_07_04)
+			data |= 0x10000000;
+		if (!next->bios.rammap_11_08_10)
+			data |= 0x00080000;
+	} else {
+		data = 0xa40e0000;
+	}
+	gk104_ram_train(fuc, 0xbc0f0000, data);
+	if (1) /* XXX: not always? */
+		ram_nsec(fuc, 1000);
+
+	if (ram->mode == 2) { /*XXX*/
+		ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
+	}
+
+	/* LP3 */
+	if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5])
+		ram_nsec(fuc, 1000);
+
+	if (ram->mode != 2) {
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+	}
+
+	if (next->bios.ramcfg_11_07_02)
+		gk104_ram_train(fuc, 0x80020000, 0x01000000);
+
+	ram_unblock(fuc);
+	ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+	if (next->bios.rammap_11_08_01)
+		data = 0x00000800;
+	else
+		data = 0x00000000;
+	ram_mask(fuc, 0x10f200, 0x00000800, data);
+	ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800);
+	return 0;
+}
+
+/*******************************************************************************
+ * DDR3
+ ******************************************************************************/
+
+static int
+gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct gk104_ramfuc *fuc = &ram->fuc;
+	const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+	const u32 runk0 = ram->fN1 << 16;
+	const u32 runk1 = ram->fN1;
+	struct nvkm_ram_data *next = ram->base.next;
+	int vc = !next->bios.ramcfg_11_02_08;
+	int mv = !next->bios.ramcfg_11_02_04;
+	u32 mask, data;
+
+	ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+	ram_block(fuc);
+	ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+	if (vc == 1 && ram_have(fuc, gpio2E)) {
+		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+		if (temp != ram_rd32(fuc, gpio2E)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 20000);
+		}
+	}
+
+	ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+	if (next->bios.ramcfg_11_03_f0)
+		ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
+
+	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+	ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+	ram_nsec(fuc, 1000);
+
+	ram_wr32(fuc, 0x10f090, 0x00000060);
+	ram_wr32(fuc, 0x10f090, 0xc000007e);
+
+	/*XXX: there does appear to be some kind of condition here, simply
+	 *     modifying these bits in the vbios from the default pl0
+	 *     entries shows no change.  however, the data does appear to
+	 *     be correct and may be required for the transition back
+	 */
+	mask = 0x00010000;
+	data = 0x00010000;
+
+	if (1) {
+		mask |= 0x800807e0;
+		data |= 0x800807e0;
+		switch (next->bios.ramcfg_11_03_c0) {
+		case 3: data &= ~0x00000040; break;
+		case 2: data &= ~0x00000100; break;
+		case 1: data &= ~0x80000000; break;
+		case 0: data &= ~0x00000400; break;
+		}
+
+		switch (next->bios.ramcfg_11_03_30) {
+		case 3: data &= ~0x00000020; break;
+		case 2: data &= ~0x00000080; break;
+		case 1: data &= ~0x00080000; break;
+		case 0: data &= ~0x00000200; break;
+		}
+	}
+
+	if (next->bios.ramcfg_11_02_80)
+		mask |= 0x03000000;
+	if (next->bios.ramcfg_11_02_40)
+		mask |= 0x00002000;
+	if (next->bios.ramcfg_11_07_10)
+		mask |= 0x00004000;
+	if (next->bios.ramcfg_11_07_08)
+		mask |= 0x00000003;
+	else
+		mask |= 0x14000000;
+	ram_mask(fuc, 0x10f824, mask, data);
+
+	ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+	ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+	data  = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+	data |= next->bios.ramcfg_11_03_30 << 16;
+	ram_wr32(fuc, 0x1373ec, data);
+	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+	/* (re)program refpll, if required */
+	if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+	    (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+		ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+		ram_wr32(fuc, 0x137320, 0x00000000);
+		ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+		ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+		ram_wr32(fuc, 0x132024, rcoef);
+		ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+		ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+		ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+		ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+	}
+
+	ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010);
+	ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
+	ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+
+	if (ram_have(fuc, gpioMV)) {
+		u32 temp  = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+		if (temp != ram_rd32(fuc, gpioMV)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 64000);
+		}
+	}
+
+	if (next->bios.ramcfg_11_02_40 ||
+	    next->bios.ramcfg_11_07_10) {
+		ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+		ram_nsec(fuc, 20000);
+	}
+
+	if (ram->mode != 2) /*XXX*/ {
+		if (next->bios.ramcfg_11_07_40)
+			ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+	}
+
+	ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+	ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+	ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
+
+	mask = 0x00010000;
+	data = 0x00000000;
+	if (!next->bios.ramcfg_11_02_80)
+		data |= 0x03000000;
+	if (!next->bios.ramcfg_11_02_40)
+		data |= 0x00002000;
+	if (!next->bios.ramcfg_11_07_10)
+		data |= 0x00004000;
+	if (!next->bios.ramcfg_11_07_08)
+		data |= 0x00000003;
+	else
+		data |= 0x14000000;
+	ram_mask(fuc, 0x10f824, mask, data);
+	ram_nsec(fuc, 1000);
+
+	if (next->bios.ramcfg_11_08_01)
+		data = 0x00100000;
+	else
+		data = 0x00000000;
+	ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+	/* PFB timing */
+	ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+	ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+	ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+	ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+	ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+	ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+	ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+	ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+	ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+	ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+	ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
+
+	mask = 0x33f00000;
+	data = 0x00000000;
+	if (!next->bios.ramcfg_11_01_04)
+		data |= 0x20200000;
+	if (!next->bios.ramcfg_11_07_80)
+		data |= 0x12800000;
+	/*XXX: see note above about there probably being some condition
+	 *     for the 10f824 stuff that uses ramcfg 3...
+	 */
+	if (next->bios.ramcfg_11_03_f0) {
+		if (next->bios.rammap_11_08_0c) {
+			if (!next->bios.ramcfg_11_07_80)
+				mask |= 0x00000020;
+			else
+				data |= 0x00000020;
+			mask |= 0x08000004;
+		}
+		data |= 0x04000000;
+	} else {
+		mask |= 0x44000020;
+		data |= 0x08000004;
+	}
+
+	ram_mask(fuc, 0x10f808, mask, data);
+
+	ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
+
+	ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
+
+	data = (next->bios.timing[10] & 0x7f000000) >> 24;
+	if (data < next->bios.timing_20_2c_1fc0)
+		data = next->bios.timing_20_2c_1fc0;
+	ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+
+	ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
+
+	ram_wr32(fuc, 0x10f090, 0x4000007f);
+	ram_nsec(fuc, 1000);
+
+	ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+	ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+	ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+	ram_nsec(fuc, 1000);
+
+	ram_nuke(fuc, mr[0]);
+	ram_mask(fuc, mr[0], 0x100, 0x100);
+	ram_mask(fuc, mr[0], 0x100, 0x000);
+
+	ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
+	ram_wr32(fuc, mr[0], ram->base.mr[0]);
+	ram_nsec(fuc, 1000);
+
+	ram_nuke(fuc, mr[0]);
+	ram_mask(fuc, mr[0], 0x100, 0x100);
+	ram_mask(fuc, mr[0], 0x100, 0x000);
+
+	if (vc == 0 && ram_have(fuc, gpio2E)) {
+		u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+		if (temp != ram_rd32(fuc, gpio2E)) {
+			ram_wr32(fuc, gpiotrig, 1);
+			ram_nsec(fuc, 20000);
+		}
+	}
+
+	if (ram->mode != 2) {
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+		ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+	}
+
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+	ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+	ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+	ram_nsec(fuc, 1000);
+
+	ram_unblock(fuc);
+	ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+	if (next->bios.rammap_11_08_01)
+		data = 0x00000800;
+	else
+		data = 0x00000000;
+	ram_mask(fuc, 0x10f200, 0x00000800, data);
+	return 0;
+}
+
+/*******************************************************************************
+ * main hooks
+ ******************************************************************************/
+
+static int
+gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct nvkm_ram_data *cfg;
+	u32 mhz = khz / 1000;
+
+	list_for_each_entry(cfg, &ram->cfg, head) {
+		if (mhz >= cfg->bios.rammap_min &&
+		    mhz <= cfg->bios.rammap_max) {
+			*data = *cfg;
+			data->freq = khz;
+			return 0;
+		}
+	}
+
+	nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
+	return -EINVAL;
+}
+
+static int
+gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct gk104_ramfuc *fuc = &ram->fuc;
+	int refclk, i;
+	int ret;
+
+	ret = ram_init(fuc, pfb);
+	if (ret)
+		return ret;
+
+	ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
+	ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
+
+	/* XXX: this is *not* what nvidia do.  on fermi nvidia generally
+	 * select, based on some unknown condition, one of the two possible
+	 * reference frequencies listed in the vbios table for mempll and
+	 * program refpll to that frequency.
+	 *
+	 * so far, i've seen very weird values being chosen by nvidia on
+	 * kepler boards, no idea how/why they're chosen.
+	 */
+	refclk = next->freq;
+	if (ram->mode == 2)
+		refclk = fuc->mempll.refclk;
+
+	/* calculate refpll coefficients */
+	ret = gt215_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
+			     &ram->fN1, &ram->M1, &ram->P1);
+	fuc->mempll.refclk = ret;
+	if (ret <= 0) {
+		nv_error(pfb, "unable to calc refpll\n");
+		return -EINVAL;
+	}
+
+	/* calculate mempll coefficients, if we're using it */
+	if (ram->mode == 2) {
+		/* post-divider doesn't work... the reg takes the values but
+		 * appears to completely ignore it.  there *is* a bit at
+		 * bit 28 that appears to divide the clock by 2 if set.
+		 */
+		fuc->mempll.min_p = 1;
+		fuc->mempll.max_p = 2;
+
+		ret = gt215_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
+				     &ram->N2, NULL, &ram->M2, &ram->P2);
+		if (ret <= 0) {
+			nv_error(pfb, "unable to calc mempll\n");
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) {
+		if (ram_have(fuc, mr[i]))
+			ram->base.mr[i] = ram_rd32(fuc, mr[i]);
+	}
+	ram->base.freq = next->freq;
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR3:
+		ret = nvkm_sddr3_calc(&ram->base);
+		if (ret == 0)
+			ret = gk104_ram_calc_sddr3(pfb, next->freq);
+		break;
+	case NV_MEM_TYPE_GDDR5:
+		ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0);
+		if (ret == 0)
+			ret = gk104_ram_calc_gddr5(pfb, next->freq);
+		break;
+	default:
+		ret = -ENOSYS;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+gk104_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+	struct nvkm_clk *clk = nvkm_clk(pfb);
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct nvkm_ram_data *xits = &ram->base.xition;
+	struct nvkm_ram_data *copy;
+	int ret;
+
+	if (ram->base.next == NULL) {
+		ret = gk104_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
+					  &ram->base.former);
+		if (ret)
+			return ret;
+
+		ret = gk104_ram_calc_data(pfb, freq, &ram->base.target);
+		if (ret)
+			return ret;
+
+		if (ram->base.target.freq < ram->base.former.freq) {
+			*xits = ram->base.target;
+			copy = &ram->base.former;
+		} else {
+			*xits = ram->base.former;
+			copy = &ram->base.target;
+		}
+
+		xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04;
+		xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03;
+		xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07;
+
+		ram->base.next = &ram->base.target;
+		if (memcmp(xits, &ram->base.former, sizeof(xits->bios)))
+			ram->base.next = &ram->base.xition;
+	} else {
+		BUG_ON(ram->base.next != &ram->base.xition);
+		ram->base.next = &ram->base.target;
+	}
+
+	return gk104_ram_calc_xits(pfb, ram->base.next);
+}
+
+static void
+gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct nvkm_ram_data *cfg;
+	u32 mhz = freq / 1000;
+	u32 mask, data;
+
+	list_for_each_entry(cfg, &ram->cfg, head) {
+		if (mhz >= cfg->bios.rammap_min &&
+		    mhz <= cfg->bios.rammap_max)
+			break;
+	}
+
+	if (&cfg->head == &ram->cfg)
+		return;
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
+		data |= cfg->bios.rammap_11_0a_03fe << 12;
+		mask |= 0x001ff000;
+	}
+	if (ram->diff.rammap_11_09_01ff) {
+		data |= cfg->bios.rammap_11_09_01ff;
+		mask |= 0x000001ff;
+	}
+	nv_mask(pfb, 0x10f468, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
+		data |= cfg->bios.rammap_11_0a_0400;
+		mask |= 0x00000001;
+	}
+	nv_mask(pfb, 0x10f420, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
+		data |= cfg->bios.rammap_11_0a_0800;
+		mask |= 0x00000001;
+	}
+	nv_mask(pfb, 0x10f430, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
+		data |= cfg->bios.rammap_11_0b_01f0;
+		mask |= 0x0000001f;
+	}
+	nv_mask(pfb, 0x10f400, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
+		data |= cfg->bios.rammap_11_0b_0200 << 9;
+		mask |= 0x00000200;
+	}
+	nv_mask(pfb, 0x10f410, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
+		data |= cfg->bios.rammap_11_0d << 16;
+		mask |= 0x00ff0000;
+	}
+	if (ram->diff.rammap_11_0f) {
+		data |= cfg->bios.rammap_11_0f << 8;
+		mask |= 0x0000ff00;
+	}
+	nv_mask(pfb, 0x10f440, mask, data);
+
+	if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
+		data |= cfg->bios.rammap_11_0e << 8;
+		mask |= 0x0000ff00;
+	}
+	if (ram->diff.rammap_11_0b_0800) {
+		data |= cfg->bios.rammap_11_0b_0800 << 7;
+		mask |= 0x00000080;
+	}
+	if (ram->diff.rammap_11_0b_0400) {
+		data |= cfg->bios.rammap_11_0b_0400 << 5;
+		mask |= 0x00000020;
+	}
+	nv_mask(pfb, 0x10f444, mask, data);
+}
+
+static int
+gk104_ram_prog(struct nvkm_fb *pfb)
+{
+	struct nvkm_device *device = nv_device(pfb);
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct gk104_ramfuc *fuc = &ram->fuc;
+	struct nvkm_ram_data *next = ram->base.next;
+
+	if (!nvkm_boolopt(device->cfgopt, "NvMemExec", true)) {
+		ram_exec(fuc, false);
+		return (ram->base.next == &ram->base.xition);
+	}
+
+	gk104_ram_prog_0(pfb, 1000);
+	ram_exec(fuc, true);
+	gk104_ram_prog_0(pfb, next->freq);
+
+	return (ram->base.next == &ram->base.xition);
+}
+
+static void
+gk104_ram_tidy(struct nvkm_fb *pfb)
+{
+	struct gk104_ram *ram = (void *)pfb->ram;
+	struct gk104_ramfuc *fuc = &ram->fuc;
+	ram->base.next = NULL;
+	ram_exec(fuc, false);
+}
+
+struct gk104_ram_train {
+	u16 mask;
+	struct nvbios_M0209S remap;
+	struct nvbios_M0209S type00;
+	struct nvbios_M0209S type01;
+	struct nvbios_M0209S type04;
+	struct nvbios_M0209S type06;
+	struct nvbios_M0209S type07;
+	struct nvbios_M0209S type08;
+	struct nvbios_M0209S type09;
+};
+
+static int
+gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg,
+		     struct gk104_ram_train *train)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nvbios_M0205E M0205E;
+	struct nvbios_M0205S M0205S;
+	struct nvbios_M0209E M0209E;
+	struct nvbios_M0209S *remap = &train->remap;
+	struct nvbios_M0209S *value;
+	u8  ver, hdr, cnt, len;
+	u32 data;
+
+	/* determine type of data for this index */
+	if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
+		return -ENOENT;
+
+	switch (M0205E.type) {
+	case 0x00: value = &train->type00; break;
+	case 0x01: value = &train->type01; break;
+	case 0x04: value = &train->type04; break;
+	case 0x06: value = &train->type06; break;
+	case 0x07: value = &train->type07; break;
+	case 0x08: value = &train->type08; break;
+	case 0x09: value = &train->type09; break;
+	default:
+		return 0;
+	}
+
+	/* training data index determined by ramcfg strap */
+	if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
+		return -EINVAL;
+	i = M0205S.data;
+
+	/* training data format information */
+	if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
+		return -EINVAL;
+
+	/* ... and the raw data */
+	if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
+		return -EINVAL;
+
+	if (M0209E.v02_07 == 2) {
+		/* of course! why wouldn't we have a pointer to another entry
+		 * in the same table, and use the first one as an array of
+		 * remap indices...
+		 */
+		if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
+					    remap)))
+			return -EINVAL;
+
+		for (i = 0; i < ARRAY_SIZE(value->data); i++)
+			value->data[i] = remap->data[value->data[i]];
+	} else
+	if (M0209E.v02_07 != 1)
+		return -EINVAL;
+
+	train->mask |= 1 << M0205E.type;
+	return 0;
+}
+
+static int
+gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train)
+{
+	int i, j;
+
+	if ((train->mask & 0x03d3) != 0x03d3) {
+		nv_warn(pfb, "missing link training data\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 0x30; i++) {
+		for (j = 0; j < 8; j += 4) {
+			nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
+			nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
+						   train->type08.data[i] << 4 |
+						   train->type06.data[i]);
+			nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
+			nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
+						   train->type09.data[i] << 4 |
+						   train->type07.data[i]);
+			nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
+		}
+	}
+
+	for (j = 0; j < 8; j += 4) {
+		for (i = 0; i < 0x100; i++) {
+			nv_wr32(pfb, 0x10f968 + j, i);
+			nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
+		}
+	}
+
+	return 0;
+}
+
+static int
+gk104_ram_train_init(struct nvkm_fb *pfb)
+{
+	u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+	struct gk104_ram_train *train;
+	int ret = -ENOMEM, i;
+
+	if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
+		for (i = 0; i < 0x100; i++) {
+			ret = gk104_ram_train_type(pfb, i, ramcfg, train);
+			if (ret && ret != -ENOENT)
+				break;
+		}
+	}
+
+	switch (pfb->ram->type) {
+	case NV_MEM_TYPE_GDDR5:
+		ret = gk104_ram_train_init_0(pfb, train);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	kfree(train);
+	return ret;
+}
+
+int
+gk104_ram_init(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = (void *)object->parent;
+	struct gk104_ram *ram   = (void *)object;
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	u8  ver, hdr, cnt, len, snr, ssz;
+	u32 data, save;
+	int ret, i;
+
+	ret = nvkm_ram_init(&ram->base);
+	if (ret)
+		return ret;
+
+	/* run a bunch of tables from rammap table.  there's actually
+	 * individual pointers for each rammap entry too, but, nvidia
+	 * seem to just run the last two entries' scripts early on in
+	 * their init, and never again.. we'll just run 'em all once
+	 * for now.
+	 *
+	 * i strongly suspect that each script is for a separate mode
+	 * (likely selected by 0x10f65c's lower bits?), and the
+	 * binary driver skips the one that's already been setup by
+	 * the init tables.
+	 */
+	data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+	if (!data || hdr < 0x15)
+		return -EINVAL;
+
+	cnt  = nv_ro08(bios, data + 0x14); /* guess at count */
+	data = nv_ro32(bios, data + 0x10); /* guess u32... */
+	save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
+	for (i = 0; i < cnt; i++, data += 4) {
+		if (i != save >> 4) {
+			nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
+			nvbios_exec(&(struct nvbios_init) {
+					.subdev = nv_subdev(pfb),
+					.bios = bios,
+					.offset = nv_ro32(bios, data),
+					.execute = 1,
+				    });
+		}
+	}
+	nv_mask(pfb, 0x10f65c, 0x000000f0, save);
+	nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
+	nv_wr32(pfb, 0x10ecc0, 0xffffffff);
+	nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
+
+	return gk104_ram_train_init(pfb);
+}
+
+static int
+gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i)
+{
+	struct nvkm_fb *pfb = (void *)nv_object(ram)->parent;
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nvkm_ram_data *cfg;
+	struct nvbios_ramcfg *d = &ram->diff;
+	struct nvbios_ramcfg *p, *n;
+	u8  ver, hdr, cnt, len;
+	u32 data;
+	int ret;
+
+	if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
+		return -ENOMEM;
+	p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
+	n = &cfg->bios;
+
+	/* memory config data for a range of target frequencies */
+	data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
+	if (ret = -ENOENT, !data)
+		goto done;
+	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
+		goto done;
+
+	/* ... and a portion specific to the attached memory */
+	data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
+			       &ver, &hdr, &cfg->bios);
+	if (ret = -EINVAL, !data)
+		goto done;
+	if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
+		goto done;
+
+	/* lookup memory timings, if bios says they're present */
+	if (cfg->bios.ramcfg_timing != 0xff) {
+		data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
+				       &ver, &hdr, &cnt, &len,
+				       &cfg->bios);
+		if (ret = -EINVAL, !data)
+			goto done;
+		if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
+			goto done;
+	}
+
+	list_add_tail(&cfg->head, &ram->cfg);
+	if (ret = 0, i == 0)
+		goto done;
+
+	d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
+	d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
+	d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
+	d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
+	d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
+	d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
+	d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
+	d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
+	d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
+	d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
+	d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
+	d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
+	d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
+	d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
+	d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
+	d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
+	d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
+done:
+	if (ret)
+		kfree(cfg);
+	return ret;
+}
+
+static void
+gk104_ram_dtor(struct nvkm_object *object)
+{
+	struct gk104_ram *ram = (void *)object;
+	struct nvkm_ram_data *cfg, *tmp;
+
+	list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
+		kfree(cfg);
+	}
+
+	nvkm_ram_destroy(&ram->base);
+}
+
+static int
+gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nvkm_gpio *gpio = nvkm_gpio(pfb);
+	struct dcb_gpio_func func;
+	struct gk104_ram *ram;
+	int ret, i;
+	u8  ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+	u32 tmp;
+
+	ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&ram->cfg);
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR3:
+	case NV_MEM_TYPE_GDDR5:
+		ram->base.calc = gk104_ram_calc;
+		ram->base.prog = gk104_ram_prog;
+		ram->base.tidy = gk104_ram_tidy;
+		break;
+	default:
+		nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
+		break;
+	}
+
+	/* calculate a mask of differently configured memory partitions,
+	 * because, of course reclocking wasn't complicated enough
+	 * already without having to treat some of them differently to
+	 * the others....
+	 */
+	ram->parts = nv_rd32(pfb, 0x022438);
+	ram->pmask = nv_rd32(pfb, 0x022554);
+	ram->pnuts = 0;
+	for (i = 0, tmp = 0; i < ram->parts; i++) {
+		if (!(ram->pmask & (1 << i))) {
+			u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
+			if (tmp && tmp != cfg1) {
+				ram->pnuts |= (1 << i);
+				continue;
+			}
+			tmp = cfg1;
+		}
+	}
+
+	/* parse bios data for all rammap table entries up-front, and
+	 * build information on whether certain fields differ between
+	 * any of the entries.
+	 *
+	 * the binary driver appears to completely ignore some fields
+	 * when all entries contain the same value.  at first, it was
+	 * hoped that these were mere optimisations and the bios init
+	 * tables had configured as per the values here, but there is
+	 * evidence now to suggest that this isn't the case and we do
+	 * need to treat this condition as a "don't touch" indicator.
+	 */
+	for (i = 0; !ret; i++) {
+		ret = gk104_ram_ctor_data(ram, ramcfg, i);
+		if (ret && ret != -ENOENT) {
+			nv_error(pfb, "failed to parse ramcfg data\n");
+			return ret;
+		}
+	}
+
+	/* parse bios data for both pll's */
+	ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
+	if (ret) {
+		nv_error(pfb, "mclk refpll data not found\n");
+		return ret;
+	}
+
+	ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
+	if (ret) {
+		nv_error(pfb, "mclk pll data not found\n");
+		return ret;
+	}
+
+	/* lookup memory voltage gpios */
+	ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
+	if (ret == 0) {
+		ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
+		ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
+		ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
+	}
+
+	ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+	if (ret == 0) {
+		ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
+		ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
+		ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
+	}
+
+	ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
+
+	ram->fuc.r_0x132020 = ramfuc_reg(0x132020);
+	ram->fuc.r_0x132028 = ramfuc_reg(0x132028);
+	ram->fuc.r_0x132024 = ramfuc_reg(0x132024);
+	ram->fuc.r_0x132030 = ramfuc_reg(0x132030);
+	ram->fuc.r_0x132034 = ramfuc_reg(0x132034);
+	ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+	ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+	ram->fuc.r_0x132040 = ramfuc_reg(0x132040);
+
+	ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248);
+	ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+	ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+	ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+	ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+	ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+	ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4);
+	ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8);
+	ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac);
+	ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc);
+	ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8);
+	ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250);
+	ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c);
+	ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4);
+	ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8);
+	ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604);
+	ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+	ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+	ram->fuc.r_0x100770 = ramfuc_reg(0x100770);
+	ram->fuc.r_0x100778 = ramfuc_reg(0x100778);
+	ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224);
+
+	ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870);
+	ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698);
+	ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694);
+	ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8);
+	ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+	ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670);
+	ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c);
+	ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+	ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+	ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+	ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c);
+
+	ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978);
+	ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+	ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_GDDR5:
+		ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+		ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
+		ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
+		ram->fuc.r_mr[3] = ramfuc_reg(0x10f338);
+		ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c);
+		ram->fuc.r_mr[5] = ramfuc_reg(0x10f340);
+		ram->fuc.r_mr[6] = ramfuc_reg(0x10f344);
+		ram->fuc.r_mr[7] = ramfuc_reg(0x10f348);
+		ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
+		ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
+		break;
+	case NV_MEM_TYPE_DDR3:
+		ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+		ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
+		break;
+	default:
+		break;
+	}
+
+	ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000);
+	ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+	ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+	ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+	ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+	ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318);
+	ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+	ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c);
+	ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+	ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+	ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4);
+	ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+	ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
+	ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
+	ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
+	ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_ram_ctor,
+		.dtor = gk104_ram_dtor,
+		.init = gk104_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c
new file mode 100644
index 0000000..5f30db1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "priv.h"
+
+#include <core/device.h>
+
+struct gk20a_mem {
+	struct nvkm_mem base;
+	void *cpuaddr;
+	dma_addr_t handle;
+};
+#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base)
+
+static void
+gk20a_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+	struct device *dev = nv_device_base(nv_device(pfb));
+	struct gk20a_mem *mem = to_gk20a_mem(*pmem);
+
+	*pmem = NULL;
+	if (unlikely(mem == NULL))
+		return;
+
+	if (likely(mem->cpuaddr))
+		dma_free_coherent(dev, mem->base.size << PAGE_SHIFT,
+				  mem->cpuaddr, mem->handle);
+
+	kfree(mem->base.pages);
+	kfree(mem);
+}
+
+static int
+gk20a_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+	     u32 memtype, struct nvkm_mem **pmem)
+{
+	struct device *dev = nv_device_base(nv_device(pfb));
+	struct gk20a_mem *mem;
+	u32 type = memtype & 0xff;
+	u32 npages, order;
+	int i;
+
+	nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
+		 align, ncmin);
+
+	npages = size >> PAGE_SHIFT;
+	if (npages == 0)
+		npages = 1;
+
+	if (align == 0)
+		align = PAGE_SIZE;
+	align >>= PAGE_SHIFT;
+
+	/* round alignment to the next power of 2, if needed */
+	order = fls(align);
+	if ((align & (align - 1)) == 0)
+		order--;
+	align = BIT(order);
+
+	/* ensure returned address is correctly aligned */
+	npages = max(align, npages);
+
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	mem->base.size = npages;
+	mem->base.memtype = type;
+
+	mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
+	if (!mem->base.pages) {
+		kfree(mem);
+		return -ENOMEM;
+	}
+
+	*pmem = &mem->base;
+
+	mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
+					  &mem->handle, GFP_KERNEL);
+	if (!mem->cpuaddr) {
+		nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
+		gk20a_ram_put(pfb, pmem);
+		return -ENOMEM;
+	}
+
+	align <<= PAGE_SHIFT;
+
+	/* alignment check */
+	if (unlikely(mem->handle & (align - 1)))
+		nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
+			&mem->handle, align);
+
+	nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
+		 npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);
+
+	for (i = 0; i < npages; i++)
+		mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);
+
+	mem->base.offset = (u64)mem->base.pages[0];
+	return 0;
+}
+
+static int
+gk20a_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 datasize,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_ram *ram;
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+	ram->type = NV_MEM_TYPE_STOLEN;
+	ram->size = get_num_physpages() << PAGE_SHIFT;
+
+	ram->get = gk20a_ram_get;
+	ram->put = gk20a_ram_put;
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_ram_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
new file mode 100644
index 0000000..a298b39
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct gm107_ram {
+	struct nvkm_ram base;
+};
+
+static int
+gm107_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gm107_ram *ram;
+	int ret;
+
+	ret = gf100_ram_create(parent, engine, oclass, 0x021c14, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass
+gm107_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm107_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = gk104_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c
new file mode 100644
index 0000000..2417640
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Roy Spliet <rspliet@eclipso.eu>
+ */
+
+#include "ramfuc.h"
+#include "nv50.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/M0205.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk/gt215.h>
+#include <subdev/gpio.h>
+
+/* XXX: Remove when memx gains GPIO support */
+extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
+
+struct gt215_ramfuc {
+	struct ramfuc base;
+	struct ramfuc_reg r_0x001610;
+	struct ramfuc_reg r_0x001700;
+	struct ramfuc_reg r_0x002504;
+	struct ramfuc_reg r_0x004000;
+	struct ramfuc_reg r_0x004004;
+	struct ramfuc_reg r_0x004018;
+	struct ramfuc_reg r_0x004128;
+	struct ramfuc_reg r_0x004168;
+	struct ramfuc_reg r_0x100080;
+	struct ramfuc_reg r_0x100200;
+	struct ramfuc_reg r_0x100210;
+	struct ramfuc_reg r_0x100220[9];
+	struct ramfuc_reg r_0x100264;
+	struct ramfuc_reg r_0x1002d0;
+	struct ramfuc_reg r_0x1002d4;
+	struct ramfuc_reg r_0x1002dc;
+	struct ramfuc_reg r_0x10053c;
+	struct ramfuc_reg r_0x1005a0;
+	struct ramfuc_reg r_0x1005a4;
+	struct ramfuc_reg r_0x100700;
+	struct ramfuc_reg r_0x100714;
+	struct ramfuc_reg r_0x100718;
+	struct ramfuc_reg r_0x10071c;
+	struct ramfuc_reg r_0x100720;
+	struct ramfuc_reg r_0x100760;
+	struct ramfuc_reg r_0x1007a0;
+	struct ramfuc_reg r_0x1007e0;
+	struct ramfuc_reg r_0x100da0;
+	struct ramfuc_reg r_0x10f804;
+	struct ramfuc_reg r_0x1110e0;
+	struct ramfuc_reg r_0x111100;
+	struct ramfuc_reg r_0x111104;
+	struct ramfuc_reg r_0x1111e0;
+	struct ramfuc_reg r_0x111400;
+	struct ramfuc_reg r_0x611200;
+	struct ramfuc_reg r_mr[4];
+	struct ramfuc_reg r_gpioFBVREF;
+};
+
+struct gt215_ltrain {
+	enum {
+		NVA3_TRAIN_UNKNOWN,
+		NVA3_TRAIN_UNSUPPORTED,
+		NVA3_TRAIN_ONCE,
+		NVA3_TRAIN_EXEC,
+		NVA3_TRAIN_DONE
+	} state;
+	u32 r_100720;
+	u32 r_1111e0;
+	u32 r_111400;
+	struct nvkm_mem *mem;
+};
+
+struct gt215_ram {
+	struct nvkm_ram base;
+	struct gt215_ramfuc fuc;
+	struct gt215_ltrain ltrain;
+};
+
+void
+gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train)
+{
+	int i, lo, hi;
+	u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (lo = 0; lo < 0x40; lo++) {
+			if (!(vals[lo] & 0x80000000))
+				continue;
+			if (vals[lo] & (0x101 << i))
+				break;
+		}
+
+		if (lo == 0x40)
+			return;
+
+		for (hi = lo + 1; hi < 0x40; hi++) {
+			if (!(vals[lo] & 0x80000000))
+				continue;
+			if (!(vals[hi] & (0x101 << i))) {
+				hi--;
+				break;
+			}
+		}
+
+		median[i] = ((hi - lo) >> 1) + lo;
+		bins[(median[i] & 0xf0) >> 4]++;
+		median[i] += 0x30;
+	}
+
+	/* Find the best value for 0x1111e0 */
+	for (i = 0; i < 4; i++) {
+		if (bins[i] > qty) {
+			bin = i + 3;
+			qty = bins[i];
+		}
+	}
+
+	train->r_100720 = 0;
+	for (i = 0; i < 8; i++) {
+		median[i] = max(median[i], (u8) (bin << 4));
+		median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
+
+		train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
+	}
+
+	train->r_1111e0 = 0x02000000 | (bin * 0x101);
+	train->r_111400 = 0x0;
+}
+
+/*
+ * Link training for (at least) DDR3
+ */
+int
+gt215_link_train(struct nvkm_fb *pfb)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct nvkm_clk *clk = nvkm_clk(pfb);
+	struct gt215_ltrain *train = &ram->ltrain;
+	struct nvkm_device *device = nv_device(pfb);
+	struct gt215_ramfuc *fuc = &ram->fuc;
+	u32 *result, r1700;
+	int ret, i;
+	struct nvbios_M0205T M0205T = { 0 };
+	u8 ver, hdr, cnt, len, snr, ssz;
+	unsigned int clk_current;
+	unsigned long flags;
+	unsigned long *f = &flags;
+
+	if (nvkm_boolopt(device->cfgopt, "NvMemExec", true) != true)
+		return -ENOSYS;
+
+	/* XXX: Multiple partitions? */
+	result = kmalloc(64 * sizeof(u32), GFP_KERNEL);
+	if (!result)
+		return -ENOMEM;
+
+	train->state = NVA3_TRAIN_EXEC;
+
+	/* Clock speeds for training and back */
+	nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
+	if (M0205T.freq == 0)
+		return -ENOENT;
+
+	clk_current = clk->read(clk, nv_clk_src_mem);
+
+	ret = gt215_clk_pre(clk, f);
+	if (ret)
+		goto out;
+
+	/* First: clock up/down */
+	ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000);
+	if (ret)
+		goto out;
+
+	/* Do this *after* calc, eliminates write in script */
+	nv_wr32(pfb, 0x111400, 0x00000000);
+	/* XXX: Magic writes that improve train reliability? */
+	nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000);
+	nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000);
+	nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000);
+	nv_wr32(pfb, 0x100c04, 0x00000400);
+
+	/* Now the training script */
+	r1700 = ram_rd32(fuc, 0x001700);
+
+	ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+	ram_wr32(fuc, 0x611200, 0x3300);
+	ram_wait_vblank(fuc);
+	ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
+	ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
+	ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
+	ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+	ram_wr32(fuc, 0x001700, 0x00000000);
+
+	ram_train(fuc);
+
+	/* Reset */
+	ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
+	ram_wr32(fuc, 0x10053c, 0x0);
+	ram_wr32(fuc, 0x100720, train->r_100720);
+	ram_wr32(fuc, 0x1111e0, train->r_1111e0);
+	ram_wr32(fuc, 0x111400, train->r_111400);
+	ram_nuke(fuc, 0x100080);
+	ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
+	ram_nsec(fuc, 1000);
+
+	ram_wr32(fuc, 0x001700, r1700);
+	ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
+	ram_wr32(fuc, 0x611200, 0x3330);
+	ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+
+	ram_exec(fuc, true);
+
+	ram->base.calc(pfb, clk_current);
+	ram_exec(fuc, true);
+
+	/* Post-processing, avoids flicker */
+	nv_mask(pfb, 0x616308, 0x10, 0x10);
+	nv_mask(pfb, 0x616b08, 0x10, 0x10);
+
+	gt215_clk_post(clk, f);
+
+	ram_train_result(pfb, result, 64);
+	for (i = 0; i < 64; i++)
+		nv_debug(pfb, "Train: %08x", result[i]);
+	gt215_link_train_calc(result, train);
+
+	nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720,
+			train->r_1111e0, train->r_111400);
+
+	kfree(result);
+
+	train->state = NVA3_TRAIN_DONE;
+
+	return ret;
+
+out:
+	if(ret == -EBUSY)
+		f = NULL;
+
+	train->state = NVA3_TRAIN_UNSUPPORTED;
+
+	gt215_clk_post(clk, f);
+	return ret;
+}
+
+int
+gt215_link_train_init(struct nvkm_fb *pfb)
+{
+	static const u32 pattern[16] = {
+		0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
+		0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
+		0x33333333, 0x55555555, 0x77777777, 0x66666666,
+		0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
+	};
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct gt215_ltrain *train = &ram->ltrain;
+	struct nvkm_mem *mem;
+	struct nvbios_M0205E M0205E;
+	u8 ver, hdr, cnt, len;
+	u32 r001700;
+	int ret, i = 0;
+
+	train->state = NVA3_TRAIN_UNSUPPORTED;
+
+	/* We support type "5"
+	 * XXX: training pattern table appears to be unused for this routine */
+	if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
+		return -ENOENT;
+
+	if (M0205E.type != 5)
+		return 0;
+
+	train->state = NVA3_TRAIN_ONCE;
+
+	ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem);
+	if (ret)
+		return ret;
+
+	mem = ram->ltrain.mem;
+
+	nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16));
+	nv_wr32(pfb, 0x1005a8, 0x0000ffff);
+	nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
+
+	for (i = 0; i < 0x30; i++) {
+		nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
+		nv_wr32(pfb, 0x10f900, pattern[i % 16]);
+	}
+
+	for (i = 0; i < 0x30; i++) {
+		nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
+		nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+	}
+
+	/* And upload the pattern */
+	r001700 = nv_rd32(pfb, 0x1700);
+	nv_wr32(pfb, 0x1700, mem->offset >> 16);
+	for (i = 0; i < 16; i++)
+		nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]);
+	for (i = 0; i < 16; i++)
+		nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]);
+	nv_wr32(pfb, 0x1700, r001700);
+
+	train->r_100720 = nv_rd32(pfb, 0x100720);
+	train->r_1111e0 = nv_rd32(pfb, 0x1111e0);
+	train->r_111400 = nv_rd32(pfb, 0x111400);
+	return 0;
+}
+
+void
+gt215_link_train_fini(struct nvkm_fb *pfb)
+{
+	struct gt215_ram *ram = (void *)pfb->ram;
+
+	if (ram->ltrain.mem)
+		pfb->ram->put(pfb, &ram->ltrain.mem);
+}
+
+/*
+ * RAM reclocking
+ */
+#define T(t) cfg->timing_10_##t
+static int
+gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing)
+{
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct nvbios_ramcfg *cfg = &ram->base.target.bios;
+	int tUNK_base, tUNK_40_0, prevCL;
+	u32 cur2, cur3, cur7, cur8;
+
+	cur2 = nv_rd32(pfb, 0x100228);
+	cur3 = nv_rd32(pfb, 0x10022c);
+	cur7 = nv_rd32(pfb, 0x10023c);
+	cur8 = nv_rd32(pfb, 0x100240);
+
+
+	switch ((!T(CWL)) * ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+		T(CWL) = T(CL) - 1;
+		break;
+	case NV_MEM_TYPE_GDDR3:
+		T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
+		break;
+	}
+
+	prevCL = (cur3 & 0x000000ff) + 1;
+	tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
+
+	timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
+	timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
+		    max_t(u8,T(18), 1) << 16 |
+		    (T(WTR) + 1 + T(CWL)) << 8 |
+		    (5 + T(CL) - T(CWL));
+	timing[2] = (T(CWL) - 1) << 24 |
+		    (T(RRD) << 16) |
+		    (T(RCDWR) << 8) |
+		    T(RCDRD);
+	timing[3] = (cur3 & 0x00ff0000) |
+		    (0x30 + T(CL)) << 24 |
+		    (0xb + T(CL)) << 8 |
+		    (T(CL) - 1);
+	timing[4] = T(20) << 24 |
+		    T(21) << 16 |
+		    T(13) << 8 |
+		    T(13);
+	timing[5] = T(RFC) << 24 |
+		    max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
+		    max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
+		    T(RP);
+	timing[6] = (0x5a + T(CL)) << 16 |
+		    max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
+		    (0x50 + T(CL) - T(CWL));
+	timing[7] = (cur7 & 0xff000000) |
+		    ((tUNK_base + T(CL)) << 16) |
+		    0x202;
+	timing[8] = cur8 & 0xffffff00;
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+	case NV_MEM_TYPE_GDDR3:
+		tUNK_40_0 = prevCL - (cur8 & 0xff);
+		if (tUNK_40_0 > 0)
+			timing[8] |= T(CL);
+		break;
+	default:
+		break;
+	}
+
+	nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n",
+			timing[0], timing[1], timing[2], timing[3]);
+	nv_debug(pfb, "  230: %08x %08x %08x %08x\n",
+			timing[4], timing[5], timing[6], timing[7]);
+	nv_debug(pfb, "  240: %08x\n", timing[8]);
+	return 0;
+}
+#undef T
+
+static void
+nvkm_sddr2_dll_reset(struct gt215_ramfuc *fuc)
+{
+	ram_mask(fuc, mr[0], 0x100, 0x100);
+	ram_nsec(fuc, 1000);
+	ram_mask(fuc, mr[0], 0x100, 0x000);
+	ram_nsec(fuc, 1000);
+}
+
+static void
+nvkm_sddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
+{
+	u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+	if (!(mr1_old & 0x1)) {
+		ram_wr32(fuc, 0x1002d4, 0x00000001);
+		ram_wr32(fuc, mr[1], mr[1]);
+		ram_nsec(fuc, 1000);
+	}
+}
+
+static void
+nvkm_gddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
+{
+	u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+	if (!(mr1_old & 0x40)) {
+		ram_wr32(fuc, mr[1], mr[1]);
+		ram_nsec(fuc, 1000);
+	}
+}
+
+static void
+gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk)
+{
+	ram_wr32(fuc, 0x004004, mclk->pll);
+	ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
+	ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
+	ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
+	ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
+}
+
+static void
+gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.pfb);
+	struct dcb_gpio_func func;
+	u32 reg, sh, gpio_val;
+	int ret;
+
+	if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
+		ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+		if (ret)
+			return;
+
+		nv50_gpio_location(func.line, &reg, &sh);
+		gpio_val = ram_rd32(fuc, gpioFBVREF);
+		if (gpio_val & (8 << sh))
+			val = !val;
+
+		ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
+		ram_nsec(fuc, 20000);
+	}
+}
+
+static int
+gt215_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct gt215_ramfuc *fuc = &ram->fuc;
+	struct gt215_ltrain *train = &ram->ltrain;
+	struct gt215_clk_info mclk;
+	struct nvkm_ram_data *next;
+	u8  ver, hdr, cnt, len, strap;
+	u32 data;
+	u32 r004018, r100760, r100da0, r111100, ctrl;
+	u32 unk714, unk718, unk71c;
+	int ret, i;
+	u32 timing[9];
+	bool pll2pll;
+
+	next = &ram->base.target;
+	next->freq = freq;
+	ram->base.next = next;
+
+	if (ram->ltrain.state == NVA3_TRAIN_ONCE)
+		gt215_link_train(pfb);
+
+	/* lookup memory config data relevant to the target frequency */
+	i = 0;
+	data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
+			       &next->bios);
+	if (!data || ver != 0x10 || hdr < 0x05) {
+		nv_error(pfb, "invalid/missing rammap entry\n");
+		return -EINVAL;
+	}
+
+	/* locate specific data set for the attached memory */
+	strap = nvbios_ramcfg_index(nv_subdev(pfb));
+	if (strap >= cnt) {
+		nv_error(pfb, "invalid ramcfg strap\n");
+		return -EINVAL;
+	}
+
+	data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
+			       &ver, &hdr, &next->bios);
+	if (!data || ver != 0x10 || hdr < 0x09) {
+		nv_error(pfb, "invalid/missing ramcfg entry\n");
+		return -EINVAL;
+	}
+
+	/* lookup memory timings, if bios says they're present */
+	if (next->bios.ramcfg_timing != 0xff) {
+		data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
+				       &ver, &hdr, &cnt, &len,
+				       &next->bios);
+		if (!data || ver != 0x10 || hdr < 0x17) {
+			nv_error(pfb, "invalid/missing timing entry\n");
+			return -EINVAL;
+		}
+	}
+
+	ret = gt215_pll_info(nvkm_clk(pfb), 0x12, 0x4000, freq, &mclk);
+	if (ret < 0) {
+		nv_error(pfb, "failed mclk calculation\n");
+		return ret;
+	}
+
+	gt215_ram_timing_calc(pfb, timing);
+
+	ret = ram_init(fuc, pfb);
+	if (ret)
+		return ret;
+
+	/* Determine ram-specific MR values */
+	ram->base.mr[0] = ram_rd32(fuc, mr[0]);
+	ram->base.mr[1] = ram_rd32(fuc, mr[1]);
+	ram->base.mr[2] = ram_rd32(fuc, mr[2]);
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+		ret = nvkm_sddr2_calc(&ram->base);
+		break;
+	case NV_MEM_TYPE_DDR3:
+		ret = nvkm_sddr3_calc(&ram->base);
+		break;
+	case NV_MEM_TYPE_GDDR3:
+		ret = nvkm_gddr3_calc(&ram->base);
+		break;
+	default:
+		ret = -ENOSYS;
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	/* XXX: where the fuck does 750MHz come from? */
+	if (freq <= 750000) {
+		r004018 = 0x10000000;
+		r100760 = 0x22222222;
+		r100da0 = 0x00000010;
+	} else {
+		r004018 = 0x00000000;
+		r100760 = 0x00000000;
+		r100da0 = 0x00000000;
+	}
+
+	if (!next->bios.ramcfg_10_DLLoff)
+		r004018 |= 0x00004000;
+
+	/* pll2pll requires to switch to a safe clock first */
+	ctrl = ram_rd32(fuc, 0x004000);
+	pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
+
+	/* Pre, NVIDIA does this outside the script */
+	if (next->bios.ramcfg_10_02_10) {
+		ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
+	} else {
+		ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
+		ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
+	}
+	/* Always disable this bit during reclock */
+	ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+
+	/* If switching from non-pll to pll, lock before disabling FB */
+	if (mclk.pll && !pll2pll) {
+		ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
+		gt215_ram_lock_pll(fuc, &mclk);
+	}
+
+	/* Start with disabling some CRTCs and PFIFO? */
+	ram_wait_vblank(fuc);
+	ram_wr32(fuc, 0x611200, 0x3300);
+	ram_mask(fuc, 0x002504, 0x1, 0x1);
+	ram_nsec(fuc, 10000);
+	ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
+	ram_block(fuc);
+	ram_nsec(fuc, 2000);
+
+	if (!next->bios.ramcfg_10_02_10) {
+		if (ram->base.type == NV_MEM_TYPE_GDDR3)
+			ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
+		else
+			ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
+	}
+
+	/* If we're disabling the DLL, do it now */
+	switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
+	case NV_MEM_TYPE_DDR3:
+		nvkm_sddr3_dll_disable(fuc, ram->base.mr);
+		break;
+	case NV_MEM_TYPE_GDDR3:
+		nvkm_gddr3_dll_disable(fuc, ram->base.mr);
+		break;
+	}
+
+	if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
+		gt215_ram_fbvref(fuc, 0);
+
+	/* Brace RAM for impact */
+	ram_wr32(fuc, 0x1002d4, 0x00000001);
+	ram_wr32(fuc, 0x1002d0, 0x00000001);
+	ram_wr32(fuc, 0x1002d0, 0x00000001);
+	ram_wr32(fuc, 0x100210, 0x00000000);
+	ram_wr32(fuc, 0x1002dc, 0x00000001);
+	ram_nsec(fuc, 2000);
+
+	if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000)
+		ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
+
+	/* Fiddle with clocks */
+	/* There's 4 scenario's
+	 * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
+	 * clk->pll: Set up new PLL, switch
+	 * pll->clk: Set up clock, switch
+	 * clk->clk: Overwrite ctrl and other bits, switch */
+
+	/* Switch to regular clock - 324MHz */
+	if (pll2pll) {
+		ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
+		ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
+		ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
+		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+		ram_wr32(fuc, 0x004018, 0x00001000);
+		gt215_ram_lock_pll(fuc, &mclk);
+	}
+
+	if (mclk.pll) {
+		ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
+		ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
+		ram_wr32(fuc, 0x100da0, r100da0);
+	} else {
+		ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
+		ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
+		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+		ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
+		ram_wr32(fuc, 0x100da0, r100da0);
+	}
+	ram_nsec(fuc, 20000);
+
+	if (next->bios.rammap_10_04_08) {
+		ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
+					next->bios.ramcfg_10_05 << 8 |
+					next->bios.ramcfg_10_05);
+		ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
+					next->bios.ramcfg_10_07);
+		ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
+					next->bios.ramcfg_10_03_0f << 16 |
+					next->bios.ramcfg_10_09_0f |
+					0x80000000);
+		ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
+	} else {
+		if (train->state == NVA3_TRAIN_DONE) {
+			ram_wr32(fuc, 0x100080, 0x1020);
+			ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
+			ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
+			ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
+		}
+		ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
+		ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+		ram_mask(fuc, 0x100760, 0x22222222, r100760);
+		ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
+		ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
+	}
+
+	if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) {
+		ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
+	}
+
+	/* Final switch */
+	if (mclk.pll) {
+		ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
+		ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
+	}
+
+	ram_wr32(fuc, 0x1002dc, 0x00000000);
+	ram_wr32(fuc, 0x1002d4, 0x00000001);
+	ram_wr32(fuc, 0x100210, 0x80000000);
+	ram_nsec(fuc, 2000);
+
+	/* Set RAM MR parameters and timings */
+	for (i = 2; i >= 0; i--) {
+		if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
+			ram_wr32(fuc, mr[i], ram->base.mr[i]);
+			ram_nsec(fuc, 1000);
+		}
+	}
+
+	ram_wr32(fuc, 0x100220[3], timing[3]);
+	ram_wr32(fuc, 0x100220[1], timing[1]);
+	ram_wr32(fuc, 0x100220[6], timing[6]);
+	ram_wr32(fuc, 0x100220[7], timing[7]);
+	ram_wr32(fuc, 0x100220[2], timing[2]);
+	ram_wr32(fuc, 0x100220[4], timing[4]);
+	ram_wr32(fuc, 0x100220[5], timing[5]);
+	ram_wr32(fuc, 0x100220[0], timing[0]);
+	ram_wr32(fuc, 0x100220[8], timing[8]);
+
+	/* Misc */
+	ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
+
+	/* XXX: A lot of "chipset"/"ram type" specific stuff...? */
+	unk714  = ram_rd32(fuc, 0x100714) & ~0xf0000130;
+	unk718  = ram_rd32(fuc, 0x100718) & ~0x00000100;
+	unk71c  = ram_rd32(fuc, 0x10071c) & ~0x00000100;
+	r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
+
+	if (next->bios.ramcfg_10_02_04) {
+		switch (ram->base.type) {
+		case NV_MEM_TYPE_DDR3:
+			if (nv_device(pfb)->chipset != 0xa8)
+				r111100 |= 0x00000004;
+			/* no break */
+		case NV_MEM_TYPE_DDR2:
+			r111100 |= 0x08000000;
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch (ram->base.type) {
+		case NV_MEM_TYPE_DDR2:
+			r111100 |= 0x1a800000;
+			unk714  |= 0x00000010;
+			break;
+		case NV_MEM_TYPE_DDR3:
+			if (nv_device(pfb)->chipset == 0xa8) {
+				r111100 |=  0x08000000;
+			} else {
+				r111100 &= ~0x00000004;
+				r111100 |=  0x12800000;
+			}
+			unk714  |= 0x00000010;
+			break;
+		case NV_MEM_TYPE_GDDR3:
+			r111100 |= 0x30000000;
+			unk714  |= 0x00000020;
+			break;
+		default:
+			break;
+		}
+	}
+
+	unk714 |= (next->bios.ramcfg_10_04_01) << 8;
+
+	if (next->bios.ramcfg_10_02_20)
+		unk714 |= 0xf0000000;
+	if (next->bios.ramcfg_10_02_02)
+		unk718 |= 0x00000100;
+	if (next->bios.ramcfg_10_02_01)
+		unk71c |= 0x00000100;
+	if (next->bios.timing_10_24 != 0xff) {
+		unk718 &= ~0xf0000000;
+		unk718 |= next->bios.timing_10_24 << 28;
+	}
+	if (next->bios.ramcfg_10_02_10)
+		r111100 &= ~0x04020000;
+
+	ram_mask(fuc, 0x100714, 0xffffffff, unk714);
+	ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
+	ram_mask(fuc, 0x100718, 0xffffffff, unk718);
+	ram_mask(fuc, 0x111100, 0xffffffff, r111100);
+
+	if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
+		gt215_ram_fbvref(fuc, 1);
+
+	/* Reset DLL */
+	if (!next->bios.ramcfg_10_DLLoff)
+		nvkm_sddr2_dll_reset(fuc);
+
+	if (ram->base.type == NV_MEM_TYPE_GDDR3) {
+		ram_nsec(fuc, 31000);
+	} else {
+		ram_nsec(fuc, 14000);
+	}
+
+	if (ram->base.type == NV_MEM_TYPE_DDR3) {
+		ram_wr32(fuc, 0x100264, 0x1);
+		ram_nsec(fuc, 2000);
+	}
+
+	ram_nuke(fuc, 0x100700);
+	ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
+	ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
+
+	/* Re-enable FB */
+	ram_unblock(fuc);
+	ram_wr32(fuc, 0x611200, 0x3330);
+
+	/* Post fiddlings */
+	if (next->bios.rammap_10_04_02)
+		ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+	if (next->bios.ramcfg_10_02_10) {
+		ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
+		ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
+	} else {
+		ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
+	}
+
+	if (mclk.pll) {
+		ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
+	} else {
+		ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
+		ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
+	}
+
+	return 0;
+}
+
+static int
+gt215_ram_prog(struct nvkm_fb *pfb)
+{
+	struct nvkm_device *device = nv_device(pfb);
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct gt215_ramfuc *fuc = &ram->fuc;
+	bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true);
+
+	if (exec) {
+		nv_mask(pfb, 0x001534, 0x2, 0x2);
+
+		ram_exec(fuc, true);
+
+		/* Post-processing, avoids flicker */
+		nv_mask(pfb, 0x002504, 0x1, 0x0);
+		nv_mask(pfb, 0x001534, 0x2, 0x0);
+
+		nv_mask(pfb, 0x616308, 0x10, 0x10);
+		nv_mask(pfb, 0x616b08, 0x10, 0x10);
+	} else {
+		ram_exec(fuc, false);
+	}
+	return 0;
+}
+
+static void
+gt215_ram_tidy(struct nvkm_fb *pfb)
+{
+	struct gt215_ram *ram = (void *)pfb->ram;
+	struct gt215_ramfuc *fuc = &ram->fuc;
+	ram_exec(fuc, false);
+}
+
+static int
+gt215_ram_init(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = (void *)object->parent;
+	struct gt215_ram   *ram = (void *)object;
+	int ret;
+
+	ret = nvkm_ram_init(&ram->base);
+	if (ret)
+		return ret;
+
+	gt215_link_train_init(pfb);
+	return 0;
+}
+
+static int
+gt215_ram_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_fb *pfb = (void *)object->parent;
+
+	if (!suspend)
+		gt215_link_train_fini(pfb);
+
+	return 0;
+}
+
+static int
+gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 datasize,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_gpio *gpio = nvkm_gpio(pfb);
+	struct dcb_gpio_func func;
+	struct gt215_ram *ram;
+	int ret, i;
+	u32 reg, shift;
+
+	ret = nv50_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+	case NV_MEM_TYPE_DDR3:
+	case NV_MEM_TYPE_GDDR3:
+		ram->base.calc = gt215_ram_calc;
+		ram->base.prog = gt215_ram_prog;
+		ram->base.tidy = gt215_ram_tidy;
+		break;
+	default:
+		nv_warn(ram, "reclocking of this ram type unsupported\n");
+		return 0;
+	}
+
+	ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
+	ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
+	ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
+	ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
+	ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
+	ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
+	ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
+	ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
+	ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
+	ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
+	ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
+	for (i = 0; i < 9; i++)
+		ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
+	ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
+	ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
+	ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
+	ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
+	ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
+	ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
+	ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
+	ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
+	ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
+	ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
+	ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
+	ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
+	ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
+	ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
+	ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
+	ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
+	ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
+	ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
+	ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
+	ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
+	ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
+	ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
+	ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+	if (ram->base.ranks > 1) {
+		ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
+		ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
+		ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
+		ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
+	} else {
+		ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
+		ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
+		ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
+		ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
+	}
+
+	ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+	if (ret == 0) {
+		nv50_gpio_location(func.line, &reg, &shift);
+		ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+gt215_ram_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = gt215_ram_init,
+		.fini = gt215_ram_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c
new file mode 100644
index 0000000..abc18e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct mcp77_ram_priv {
+	struct nvkm_ram base;
+	u64 poller_base;
+};
+
+static int
+mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 datasize,
+	       struct nvkm_object **pobject)
+{
+	u32 rsvd_head = ( 256 * 1024); /* vga memory */
+	u32 rsvd_tail = (1024 * 1024); /* vbios etc */
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct mcp77_ram_priv *priv;
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.type   = NV_MEM_TYPE_STOLEN;
+	priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+	priv->base.size   = (u64)nv_rd32(pfb, 0x100e14) << 12;
+
+	rsvd_tail += 0x1000;
+	priv->poller_base = priv->base.size - rsvd_tail;
+
+	ret = nvkm_mm_init(&pfb->vram, rsvd_head >> 12,
+			   (priv->base.size  - (rsvd_head + rsvd_tail)) >> 12,
+			   1);
+	if (ret)
+		return ret;
+
+	priv->base.get = nv50_ram_get;
+	priv->base.put = nv50_ram_put;
+	return 0;
+}
+
+static int
+mcp77_ram_init(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	struct mcp77_ram_priv *priv = (void *)object;
+	int ret;
+	u64 dniso, hostnb, flush;
+
+	ret = nvkm_ram_init(&priv->base);
+	if (ret)
+		return ret;
+
+	dniso  = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1;
+	hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1;
+	flush  = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1;
+
+	/* Enable NISO poller for various clients and set their associated
+	 * read address, only for MCP77/78 and MCP79/7A. (fd#25701)
+	 */
+	nv_wr32(pfb, 0x100c18, dniso);
+	nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001);
+	nv_wr32(pfb, 0x100c1c, hostnb);
+	nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002);
+	nv_wr32(pfb, 0x100c24, flush);
+	nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000);
+	return 0;
+}
+
+struct nvkm_oclass
+mcp77_ram_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = mcp77_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = mcp77_ram_init,
+		.fini = _nvkm_ram_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c
new file mode 100644
index 0000000..855de16
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "regsnv04.h"
+
+static int
+nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (boot0 & 0x00000100) {
+		ram->size  = ((boot0 >> 12) & 0xf) * 2 + 2;
+		ram->size *= 1024 * 1024;
+	} else {
+		switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+			ram->size = 32 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+			ram->size = 16 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+			ram->size = 8 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+			ram->size = 4 * 1024 * 1024;
+			break;
+		}
+	}
+
+	if ((boot0 & 0x00000038) <= 0x10)
+		ram->type = NV_MEM_TYPE_SGRAM;
+	else
+		ram->type = NV_MEM_TYPE_SDRAM;
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv04_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c
new file mode 100644
index 0000000..3b8a1ed
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	u32 cfg0 = nv_rd32(pfb, 0x100200);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (cfg0 & 0x00000001)
+		ram->type = NV_MEM_TYPE_DDR1;
+	else
+		ram->type = NV_MEM_TYPE_SDRAM;
+
+	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	return 0;
+}
+
+struct nvkm_oclass
+nv10_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv10_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c
new file mode 100644
index 0000000..fbae05d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+static int
+nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	struct pci_dev *bridge;
+	u32 mem, mib;
+	int ret;
+
+	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+	if (!bridge) {
+		nv_fatal(pfb, "no bridge device\n");
+		return -ENODEV;
+	}
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (nv_device(pfb)->chipset == 0x1a) {
+		pci_read_config_dword(bridge, 0x7c, &mem);
+		mib = ((mem >> 6) & 31) + 1;
+	} else {
+		pci_read_config_dword(bridge, 0x84, &mem);
+		mib = ((mem >> 4) & 127) + 1;
+	}
+
+	ram->type = NV_MEM_TYPE_STOLEN;
+	ram->size = mib * 1024 * 1024;
+	return 0;
+}
+
+struct nvkm_oclass
+nv1a_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv1a_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c
new file mode 100644
index 0000000..d9e7187
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	u32 pbus1218 = nv_rd32(pfb, 0x001218);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pbus1218 & 0x00000300) {
+	case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+	case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
+	}
+	ram->size  = (nv_rd32(pfb, 0x10020c) & 0xff000000);
+	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->tags  = nv_rd32(pfb, 0x100320);
+	return 0;
+}
+
+struct nvkm_oclass
+nv20_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv20_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
new file mode 100644
index 0000000..3d31fa4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/timer.h>
+
+int
+nv40_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nv40_ram *ram = (void *)pfb->ram;
+	struct nvbios_pll pll;
+	int N1, M1, N2, M2;
+	int log2P, ret;
+
+	ret = nvbios_pll_parse(bios, 0x04, &pll);
+	if (ret) {
+		nv_error(pfb, "mclk pll data not found\n");
+		return ret;
+	}
+
+	ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq,
+			    &N1, &M1, &N2, &M2, &log2P);
+	if (ret < 0)
+		return ret;
+
+	ram->ctrl  = 0x80000000 | (log2P << 16);
+	ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
+	if (N2 == M2) {
+		ram->ctrl |= 0x00000100;
+		ram->coef  = (N1 << 8) | M1;
+	} else {
+		ram->ctrl |= 0x40000000;
+		ram->coef  = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+	}
+
+	return 0;
+}
+
+int
+nv40_ram_prog(struct nvkm_fb *pfb)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nv40_ram *ram = (void *)pfb->ram;
+	struct bit_entry M;
+	u32 crtc_mask = 0;
+	u8  sr1[2];
+	int i;
+
+	/* determine which CRTCs are active, fetch VGA_SR1 for each */
+	for (i = 0; i < 2; i++) {
+		u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000));
+		u32 cnt = 0;
+		do {
+			if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) {
+				nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+				sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000));
+				if (!(sr1[i] & 0x20))
+					crtc_mask |= (1 << i);
+				break;
+			}
+			udelay(1);
+		} while (cnt++ < 32);
+	}
+
+	/* wait for vblank start on active crtcs, disable memory access */
+	for (i = 0; i < 2; i++) {
+		if (!(crtc_mask & (1 << i)))
+			continue;
+		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
+		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+		nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+		nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
+	}
+
+	/* prepare ram for reclocking */
+	nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */
+	nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+	nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+	nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
+	nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+	/* change the PLL of each memory partition */
+	nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000);
+	switch (nv_device(pfb)->chipset) {
+	case 0x40:
+	case 0x45:
+	case 0x41:
+	case 0x42:
+	case 0x47:
+		nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl);
+		nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl);
+		nv_wr32(pfb, 0x004048, ram->coef);
+		nv_wr32(pfb, 0x004030, ram->coef);
+	case 0x43:
+	case 0x49:
+	case 0x4b:
+		nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl);
+		nv_wr32(pfb, 0x00403c, ram->coef);
+	default:
+		nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl);
+		nv_wr32(pfb, 0x004024, ram->coef);
+		break;
+	}
+	udelay(100);
+	nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000);
+
+	/* re-enable normal operation of memory controller */
+	nv_wr32(pfb, 0x1002dc, 0x00000000);
+	nv_mask(pfb, 0x100210, 0x80000000, 0x80000000);
+	udelay(100);
+
+	/* execute memory reset script from vbios */
+	if (!bit_entry(bios, 'M', &M)) {
+		struct nvbios_init init = {
+			.subdev = nv_subdev(pfb),
+			.bios = bios,
+			.offset = nv_ro16(bios, M.offset + 0x00),
+			.execute = 1,
+		};
+
+		nvbios_exec(&init);
+	}
+
+	/* make sure we're in vblank (hopefully the same one as before), and
+	 * then re-enable crtc memory access
+	 */
+	for (i = 0; i < 2; i++) {
+		if (!(crtc_mask & (1 << i)))
+			continue;
+		nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+		nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+		nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]);
+	}
+
+	return 0;
+}
+
+void
+nv40_ram_tidy(struct nvkm_fb *pfb)
+{
+}
+
+static int
+nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nv40_ram *ram;
+	u32 pbus1218 = nv_rd32(pfb, 0x001218);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pbus1218 & 0x00000300) {
+	case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break;
+	case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break;
+	}
+
+	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->base.tags  =  nv_rd32(pfb, 0x100320);
+	ram->base.calc = nv40_ram_calc;
+	ram->base.prog = nv40_ram_prog;
+	ram->base.tidy = nv40_ram_tidy;
+	return 0;
+}
+
+
+struct nvkm_oclass
+nv40_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c
new file mode 100644
index 0000000..33c612b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nv40_ram *ram;
+	u32 pfb474 = nv_rd32(pfb, 0x100474);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (pfb474 & 0x00000004)
+		ram->base.type = NV_MEM_TYPE_GDDR3;
+	if (pfb474 & 0x00000002)
+		ram->base.type = NV_MEM_TYPE_DDR2;
+	if (pfb474 & 0x00000001)
+		ram->base.type = NV_MEM_TYPE_DDR1;
+
+	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->base.tags  =  nv_rd32(pfb, 0x100320);
+	ram->base.calc = nv40_ram_calc;
+	ram->base.prog = nv40_ram_prog;
+	ram->base.tidy = nv40_ram_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+nv41_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv41_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c
new file mode 100644
index 0000000..f575a72
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nv40_ram *ram;
+	u32 pfb474 = nv_rd32(pfb, 0x100474);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (pfb474 & 0x00000004)
+		ram->base.type = NV_MEM_TYPE_GDDR3;
+	if (pfb474 & 0x00000002)
+		ram->base.type = NV_MEM_TYPE_DDR2;
+	if (pfb474 & 0x00000001)
+		ram->base.type = NV_MEM_TYPE_DDR1;
+
+	ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->base.calc = nv40_ram_calc;
+	ram->base.prog = nv40_ram_prog;
+	ram->base.tidy = nv40_ram_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+nv44_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv44_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c
new file mode 100644
index 0000000..51b44cd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nv40_ram *ram;
+	u32 pfb914 = nv_rd32(pfb, 0x100914);
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pfb914 & 0x00000003) {
+	case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break;
+	case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000003: break;
+	}
+
+	ram->base.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->base.tags  =  nv_rd32(pfb, 0x100320);
+	ram->base.calc = nv40_ram_calc;
+	ram->base.prog = nv40_ram_prog;
+	ram->base.tidy = nv40_ram_tidy;
+	return 0;
+}
+
+struct nvkm_oclass
+nv49_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv49_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c
new file mode 100644
index 0000000..f3ed1c6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	int ret;
+
+	ret = nvkm_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->type = NV_MEM_TYPE_STOLEN;
+	return 0;
+}
+
+struct nvkm_oclass
+nv4e_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv4e_ram_create,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c
new file mode 100644
index 0000000..d2c81dd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "ramseq.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/perf.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk/pll.h>
+
+struct nv50_ramseq {
+	struct hwsq base;
+	struct hwsq_reg r_0x002504;
+	struct hwsq_reg r_0x004008;
+	struct hwsq_reg r_0x00400c;
+	struct hwsq_reg r_0x00c040;
+	struct hwsq_reg r_0x100210;
+	struct hwsq_reg r_0x1002d0;
+	struct hwsq_reg r_0x1002d4;
+	struct hwsq_reg r_0x1002dc;
+	struct hwsq_reg r_0x100da0[8];
+	struct hwsq_reg r_0x100e20;
+	struct hwsq_reg r_0x100e24;
+	struct hwsq_reg r_0x611200;
+	struct hwsq_reg r_timing[9];
+	struct hwsq_reg r_mr[4];
+};
+
+struct nv50_ram {
+	struct nvkm_ram base;
+	struct nv50_ramseq hwsq;
+};
+
+#define QFX5800NVA0 1
+
+static int
+nv50_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+	struct nvkm_bios *bios = nvkm_bios(pfb);
+	struct nv50_ram *ram = (void *)pfb->ram;
+	struct nv50_ramseq *hwsq = &ram->hwsq;
+	struct nvbios_perfE perfE;
+	struct nvbios_pll mpll;
+	struct {
+		u32 data;
+		u8  size;
+	} ramcfg, timing;
+	u8  ver, hdr, cnt, len, strap;
+	int N1, M1, N2, M2, P;
+	int ret, i;
+
+	/* lookup closest matching performance table entry for frequency */
+	i = 0;
+	do {
+		ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
+					    &ramcfg.size, &perfE);
+		if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) ||
+		    (ramcfg.size < 2)) {
+			nv_error(pfb, "invalid/missing perftab entry\n");
+			return -EINVAL;
+		}
+	} while (perfE.memory < freq);
+
+	/* locate specific data set for the attached memory */
+	strap = nvbios_ramcfg_index(nv_subdev(pfb));
+	if (strap >= cnt) {
+		nv_error(pfb, "invalid ramcfg strap\n");
+		return -EINVAL;
+	}
+
+	ramcfg.data += hdr + (strap * ramcfg.size);
+
+	/* lookup memory timings, if bios says they're present */
+	strap = nv_ro08(bios, ramcfg.data + 0x01);
+	if (strap != 0xff) {
+		timing.data = nvbios_timingEe(bios, strap, &ver, &hdr,
+					      &cnt, &len);
+		if (!timing.data || ver != 0x10 || hdr < 0x12) {
+			nv_error(pfb, "invalid/missing timing entry "
+				 "%02x %04x %02x %02x\n",
+				 strap, timing.data, ver, hdr);
+			return -EINVAL;
+		}
+	} else {
+		timing.data = 0;
+	}
+
+	ret = ram_init(hwsq, nv_subdev(pfb));
+	if (ret)
+		return ret;
+
+	ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
+	ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
+	ram_wr32(hwsq, 0x611200, 0x00003300);
+	ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
+	ram_nsec(hwsq, 8000);
+	ram_setf(hwsq, 0x10, 0x00); /* disable fb */
+	ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+	ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
+	ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+	ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+	ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
+	ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+	ret = nvbios_pll_parse(bios, 0x004008, &mpll);
+	mpll.vco2.max_freq = 0;
+	if (ret == 0) {
+		ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq,
+				    &N1, &M1, &N2, &M2, &P);
+		if (ret == 0)
+			ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
+	ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200);
+	ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
+	ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) |
+					     (P << 22) | (P << 16));
+#if QFX5800NVA0
+	for (i = 0; i < 8; i++)
+		ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/
+#endif
+	ram_nsec(hwsq, 96000); /*XXX*/
+	ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
+
+	ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
+	ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
+
+	ram_nsec(hwsq, 12000);
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+		ram_nuke(hwsq, mr[0]); /* force update */
+		ram_mask(hwsq, mr[0], 0x000, 0x000);
+		break;
+	case NV_MEM_TYPE_GDDR3:
+		ram_mask(hwsq, mr[2], 0x000, 0x000);
+		ram_nuke(hwsq, mr[0]); /* force update */
+		ram_mask(hwsq, mr[0], 0x000, 0x000);
+		break;
+	default:
+		break;
+	}
+
+	ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/
+	ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/
+
+	ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+
+#if QFX5800NVA0
+	ram_nuke(hwsq, 0x100e24);
+	ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000);
+	ram_nuke(hwsq, 0x100e20);
+	ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000);
+#endif
+
+	ram_mask(hwsq, mr[0], 0x100, 0x100);
+	ram_mask(hwsq, mr[0], 0x100, 0x000);
+
+	ram_setf(hwsq, 0x10, 0x01); /* enable fb */
+	ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+	ram_wr32(hwsq, 0x611200, 0x00003330);
+	ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
+	return 0;
+}
+
+static int
+nv50_ram_prog(struct nvkm_fb *pfb)
+{
+	struct nvkm_device *device = nv_device(pfb);
+	struct nv50_ram *ram = (void *)pfb->ram;
+	struct nv50_ramseq *hwsq = &ram->hwsq;
+
+	ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
+	return 0;
+}
+
+static void
+nv50_ram_tidy(struct nvkm_fb *pfb)
+{
+	struct nv50_ram *ram = (void *)pfb->ram;
+	struct nv50_ramseq *hwsq = &ram->hwsq;
+	ram_exec(hwsq, false);
+}
+
+void
+__nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem)
+{
+	struct nvkm_mm_node *this;
+
+	while (!list_empty(&mem->regions)) {
+		this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
+
+		list_del(&this->rl_entry);
+		nvkm_mm_free(&pfb->vram, &this);
+	}
+
+	nvkm_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+	struct nvkm_mem *mem = *pmem;
+
+	*pmem = NULL;
+	if (unlikely(mem == NULL))
+		return;
+
+	mutex_lock(&pfb->base.mutex);
+	__nv50_ram_put(pfb, mem);
+	mutex_unlock(&pfb->base.mutex);
+
+	kfree(mem);
+}
+
+int
+nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+	     u32 memtype, struct nvkm_mem **pmem)
+{
+	struct nvkm_mm *heap = &pfb->vram;
+	struct nvkm_mm *tags = &pfb->tags;
+	struct nvkm_mm_node *r;
+	struct nvkm_mem *mem;
+	int comp = (memtype & 0x300) >> 8;
+	int type = (memtype & 0x07f);
+	int back = (memtype & 0x800);
+	int min, max, ret;
+
+	max = (size >> 12);
+	min = ncmin ? (ncmin >> 12) : max;
+	align >>= 12;
+
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	mutex_lock(&pfb->base.mutex);
+	if (comp) {
+		if (align == 16) {
+			int n = (max >> 4) * comp;
+
+			ret = nvkm_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
+			if (ret)
+				mem->tag = NULL;
+		}
+
+		if (unlikely(!mem->tag))
+			comp = 0;
+	}
+
+	INIT_LIST_HEAD(&mem->regions);
+	mem->memtype = (comp << 7) | type;
+	mem->size = max;
+
+	type = nv50_fb_memtype[type];
+	do {
+		if (back)
+			ret = nvkm_mm_tail(heap, 0, type, max, min, align, &r);
+		else
+			ret = nvkm_mm_head(heap, 0, type, max, min, align, &r);
+		if (ret) {
+			mutex_unlock(&pfb->base.mutex);
+			pfb->ram->put(pfb, &mem);
+			return ret;
+		}
+
+		list_add_tail(&r->rl_entry, &mem->regions);
+		max -= r->length;
+	} while (max);
+	mutex_unlock(&pfb->base.mutex);
+
+	r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry);
+	mem->offset = (u64)r->offset << 12;
+	*pmem = mem;
+	return 0;
+}
+
+static u32
+nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram)
+{
+	int colbits, rowbitsa, rowbitsb, banks;
+	u64 rowsize, predicted;
+	u32 r0, r4, rt, rblock_size;
+
+	r0 = nv_rd32(pfb, 0x100200);
+	r4 = nv_rd32(pfb, 0x100204);
+	rt = nv_rd32(pfb, 0x100250);
+	nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n",
+		 r0, r4, rt, nv_rd32(pfb, 0x001540));
+
+	colbits  =  (r4 & 0x0000f000) >> 12;
+	rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+	rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+	banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+	rowsize = ram->parts * banks * (1 << colbits) * 8;
+	predicted = rowsize << rowbitsa;
+	if (r0 & 0x00000004)
+		predicted += rowsize << rowbitsb;
+
+	if (predicted != ram->size) {
+		nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
+			(u32)(ram->size >> 20));
+	}
+
+	rblock_size = rowsize;
+	if (rt & 1)
+		rblock_size *= 3;
+
+	nv_debug(pfb, "rblock %d bytes\n", rblock_size);
+	return rblock_size;
+}
+
+int
+nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ram *ram;
+	int ret;
+
+	ret = nvkm_ram_create_(parent, engine, oclass, length, pobject);
+	ram = *pobject;
+	if (ret)
+		return ret;
+
+	ram->size = nv_rd32(pfb, 0x10020c);
+	ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
+
+	ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
+	ram->parts = hweight8(ram->part_mask);
+
+	switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+	case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+	case 1:
+		if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+			ram->type = NV_MEM_TYPE_DDR3;
+		else
+			ram->type = NV_MEM_TYPE_DDR2;
+		break;
+	case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+	case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
+	default:
+		break;
+	}
+
+	ret = nvkm_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
+			   (rsvd_head + rsvd_tail),
+			   nv50_fb_vram_rblock(pfb, ram) >> 12);
+	if (ret)
+		return ret;
+
+	ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+	ram->tags  =  nv_rd32(pfb, 0x100320);
+	ram->get = nv50_ram_get;
+	ram->put = nv50_ram_put;
+	return 0;
+}
+
+static int
+nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 datasize,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_ram *ram;
+	int ret, i;
+
+	ret = nv50_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (ram->base.type) {
+	case NV_MEM_TYPE_DDR2:
+	case NV_MEM_TYPE_GDDR3:
+		ram->base.calc = nv50_ram_calc;
+		ram->base.prog = nv50_ram_prog;
+		ram->base.tidy = nv50_ram_tidy;
+		break;
+	default:
+		nv_warn(ram, "reclocking of this ram type unsupported\n");
+		return 0;
+	}
+
+	ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
+	ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
+	ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
+	ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
+	ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
+	ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
+	ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
+	ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
+	for (i = 0; i < 8; i++)
+		ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04));
+	ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
+	ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
+	ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
+
+	for (i = 0; i < 9; i++)
+		ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
+
+	if (ram->base.ranks > 1) {
+		ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
+		ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
+		ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
+		ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
+	} else {
+		ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
+		ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
+		ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
+		ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_ram_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_ram_ctor,
+		.dtor = _nvkm_ram_dtor,
+		.init = _nvkm_ram_init,
+		.fini = _nvkm_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h
new file mode 100644
index 0000000..0f1f97c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h
@@ -0,0 +1,15 @@
+#ifndef __NVKM_FBRAM_SEQ_H__
+#define __NVKM_FBRAM_SEQ_H__
+#include <subdev/bus/hwsq.h>
+
+#define ram_init(s,p)       hwsq_init(&(s)->base, (p))
+#define ram_exec(s,e)       hwsq_exec(&(s)->base, (e))
+#define ram_have(s,r)       ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r)       hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d)     hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r)       hwsq_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d)   hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_setf(s,f,d)     hwsq_setf(&(s)->base, (f), (d))
+#define ram_wait(s,f,d)     hwsq_wait(&(s)->base, (f), (d))
+#define ram_nsec(s,n)       hwsq_nsec(&(s)->base, (n))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h
new file mode 100644
index 0000000..1f865f6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h
@@ -0,0 +1,22 @@
+#ifndef __NVKM_FB_REGS_04_H__
+#define __NVKM_FB_REGS_04_H__
+
+#define NV04_PFB_BOOT_0						0x00100000
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT			0x00000003
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB			0x00000000
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB			0x00000001
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB			0x00000002
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB			0x00000003
+#	define NV04_PFB_BOOT_0_RAM_WIDTH_128			0x00000004
+#	define NV04_PFB_BOOT_0_RAM_TYPE				0x00000028
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT		0x00000000
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT		0x00000008
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK	0x00000010
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT		0x00000018
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT		0x00000020
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16		0x00000028
+#	define NV04_PFB_BOOT_0_UMA_ENABLE			0x00000100
+#	define NV04_PFB_BOOT_0_UMA_SIZE				0x0000f000
+#define NV04_PFB_CFG0						0x00100200
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c
new file mode 100644
index 0000000..afab42d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Roy Spliet
+ *
+ * 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.
+ *
+ * Authors: Roy Spliet <rspliet@eclipso.eu>
+ *          Ben Skeggs
+ */
+#include "priv.h"
+
+struct ramxlat {
+	int id;
+	u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+	while (xlat->id >= 0) {
+		if (xlat->id == id)
+			return xlat->enc;
+		xlat++;
+	}
+	return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr2_cl[] = {
+	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
+	/* The following are available in some, but not all DDR2 docs */
+	{ 7, 7 },
+	{ -1 }
+};
+
+static const struct ramxlat
+ramddr2_wr[] = {
+	{ 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
+	/* The following are available in some, but not all DDR2 docs */
+	{ 7, 6 },
+	{ -1 }
+};
+
+int
+nvkm_sddr2_calc(struct nvkm_ram *ram)
+{
+	int CL, WR, DLL = 0, ODT = 0;
+
+	switch (ram->next->bios.timing_ver) {
+	case 0x10:
+		CL  = ram->next->bios.timing_10_CL;
+		WR  = ram->next->bios.timing_10_WR;
+		DLL = !ram->next->bios.ramcfg_10_DLLoff;
+		ODT = ram->next->bios.timing_10_ODT & 3;
+		break;
+	case 0x20:
+		CL  = (ram->next->bios.timing[1] & 0x0000001f);
+		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	CL  = ramxlat(ramddr2_cl, CL);
+	WR  = ramxlat(ramddr2_wr, WR);
+	if (CL < 0 || WR < 0)
+		return -EINVAL;
+
+	ram->mr[0] &= ~0xf70;
+	ram->mr[0] |= (WR & 0x07) << 9;
+	ram->mr[0] |= (CL & 0x07) << 4;
+
+	ram->mr[1] &= ~0x045;
+	ram->mr[1] |= (ODT & 0x1) << 2;
+	ram->mr[1] |= (ODT & 0x2) << 5;
+	ram->mr[1] |= !DLL;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c
new file mode 100644
index 0000000..1084435
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ * 	    Roy Spliet <rspliet@eclipso.eu>
+ */
+#include "priv.h"
+
+struct ramxlat {
+	int id;
+	u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+	while (xlat->id >= 0) {
+		if (xlat->id == id)
+			return xlat->enc;
+		xlat++;
+	}
+	return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr3_cl[] = {
+	{ 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
+	{ 11, 14 },
+	/* the below are mentioned in some, but not all, ddr3 docs */
+	{ 12, 1 }, { 13, 3 }, { 14, 5 },
+	{ -1 }
+};
+
+static const struct ramxlat
+ramddr3_wr[] = {
+	{ 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
+	/* the below are mentioned in some, but not all, ddr3 docs */
+	{ 14, 7 }, { 16, 0 },
+	{ -1 }
+};
+
+static const struct ramxlat
+ramddr3_cwl[] = {
+	{ 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
+	/* the below are mentioned in some, but not all, ddr3 docs */
+	{ 9, 4 },
+	{ -1 }
+};
+
+int
+nvkm_sddr3_calc(struct nvkm_ram *ram)
+{
+	int CWL, CL, WR, DLL = 0, ODT = 0;
+
+	switch (ram->next->bios.timing_ver) {
+	case 0x10:
+		if (ram->next->bios.timing_hdr < 0x17) {
+			/* XXX: NV50: Get CWL from the timing register */
+			return -ENOSYS;
+		}
+		CWL = ram->next->bios.timing_10_CWL;
+		CL  = ram->next->bios.timing_10_CL;
+		WR  = ram->next->bios.timing_10_WR;
+		DLL = !ram->next->bios.ramcfg_10_DLLoff;
+		ODT = ram->next->bios.timing_10_ODT;
+		break;
+	case 0x20:
+		CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+		CL  = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+		WR  = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+		/* XXX: Get these values from the VBIOS instead */
+		DLL = !(ram->mr[1] & 0x1);
+		ODT =   (ram->mr[1] & 0x004) >> 2 |
+			(ram->mr[1] & 0x040) >> 5 |
+		        (ram->mr[1] & 0x200) >> 7;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	CWL = ramxlat(ramddr3_cwl, CWL);
+	CL  = ramxlat(ramddr3_cl, CL);
+	WR  = ramxlat(ramddr3_wr, WR);
+	if (CL < 0 || CWL < 0 || WR < 0)
+		return -EINVAL;
+
+	ram->mr[0] &= ~0xf74;
+	ram->mr[0] |= (WR & 0x07) << 9;
+	ram->mr[0] |= (CL & 0x0e) << 3;
+	ram->mr[0] |= (CL & 0x01) << 2;
+
+	ram->mr[1] &= ~0x245;
+	ram->mr[1] |= (ODT & 0x1) << 2;
+	ram->mr[1] |= (ODT & 0x2) << 5;
+	ram->mr[1] |= (ODT & 0x4) << 7;
+	ram->mr[1] |= !DLL;
+
+	ram->mr[2] &= ~0x038;
+	ram->mr[2] |= (CWL & 0x07) << 3;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild
new file mode 100644
index 0000000..f3d4e6e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/fuse/base.o
+nvkm-y += nvkm/subdev/fuse/nv50.o
+nvkm-y += nvkm/subdev/fuse/gf100.o
+nvkm-y += nvkm/subdev/fuse/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c
new file mode 100644
index 0000000..b7b7193
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/fuse.h>
+
+int
+_nvkm_fuse_init(struct nvkm_object *object)
+{
+	struct nvkm_fuse *fuse = (void *)object;
+	return nvkm_subdev_init(&fuse->base);
+}
+
+void
+_nvkm_fuse_dtor(struct nvkm_object *object)
+{
+	struct nvkm_fuse *fuse = (void *)object;
+	nvkm_subdev_destroy(&fuse->base);
+}
+
+int
+nvkm_fuse_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_fuse *fuse;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE",
+				  "fuse", length, pobject);
+	fuse = *pobject;
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c
new file mode 100644
index 0000000..393ef3a0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct gf100_fuse_priv {
+	struct nvkm_fuse base;
+
+	spinlock_t fuse_enable_lock;
+};
+
+static u32
+gf100_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct gf100_fuse_priv *priv = (void *)object;
+	unsigned long flags;
+	u32 fuse_enable, unk, val;
+
+	/* racy if another part of nvkm start writing to these regs */
+	spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+	fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
+	unk = nv_mask(priv, 0x21000, 0x1, 0x1);
+	val = nv_rd32(priv, 0x21100 + addr);
+	nv_wr32(priv, 0x21000, unk);
+	nv_wr32(priv, 0x22400, fuse_enable);
+	spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+	return val;
+}
+
+
+static int
+gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gf100_fuse_priv *priv;
+	int ret;
+
+	ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&priv->fuse_enable_lock);
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_fuse_oclass = {
+	.handle = NV_SUBDEV(FUSE, 0xC0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_fuse_ctor,
+		.dtor = _nvkm_fuse_dtor,
+		.init = _nvkm_fuse_init,
+		.fini = _nvkm_fuse_fini,
+		.rd32 = gf100_fuse_rd32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c
new file mode 100644
index 0000000..ba19158
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct gm107_fuse_priv {
+	struct nvkm_fuse base;
+};
+
+static u32
+gm107_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct gf100_fuse_priv *priv = (void *)object;
+	return nv_rd32(priv, 0x21100 + addr);
+}
+
+
+static int
+gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gm107_fuse_priv *priv;
+	int ret;
+
+	ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass
+gm107_fuse_oclass = {
+	.handle = NV_SUBDEV(FUSE, 0x117),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm107_fuse_ctor,
+		.dtor = _nvkm_fuse_dtor,
+		.init = _nvkm_fuse_init,
+		.fini = _nvkm_fuse_fini,
+		.rd32 = gm107_fuse_rd32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c
new file mode 100644
index 0000000..0d2afc4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct nv50_fuse_priv {
+	struct nvkm_fuse base;
+
+	spinlock_t fuse_enable_lock;
+};
+
+static u32
+nv50_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nv50_fuse_priv *priv = (void *)object;
+	unsigned long flags;
+	u32 fuse_enable, val;
+
+	/* racy if another part of nvkm start writing to this reg */
+	spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+	fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
+	val = nv_rd32(priv, 0x21000 + addr);
+	nv_wr32(priv, 0x1084, fuse_enable);
+	spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+	return val;
+}
+
+
+static int
+nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv50_fuse_priv *priv;
+	int ret;
+
+	ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&priv->fuse_enable_lock);
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_fuse_oclass = {
+	.handle = NV_SUBDEV(FUSE, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_fuse_ctor,
+		.dtor = _nvkm_fuse_dtor,
+		.init = _nvkm_fuse_init,
+		.fini = _nvkm_fuse_fini,
+		.rd32 = nv50_fuse_rd32,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h
new file mode 100644
index 0000000..7e050f7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_FUSE_PRIV_H__
+#define __NVKM_FUSE_PRIV_H__
+#include <subdev/fuse.h>
+
+int _nvkm_fuse_init(struct nvkm_object *object);
+void _nvkm_fuse_dtor(struct nvkm_object *object);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild
new file mode 100644
index 0000000..ea42a9e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/gpio/base.o
+nvkm-y += nvkm/subdev/gpio/nv10.o
+nvkm-y += nvkm/subdev/gpio/nv50.o
+nvkm-y += nvkm/subdev/gpio/g94.o
+nvkm-y += nvkm/subdev/gpio/gf110.o
+nvkm-y += nvkm/subdev/gpio/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
new file mode 100644
index 0000000..dea5816
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/notify.h>
+
+static int
+nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out)
+{
+	const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+	return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
+}
+
+static int
+nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line)
+{
+	const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+	return impl->sense ? impl->sense(gpio, line) : -ENODEV;
+}
+
+static int
+nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line,
+	       struct dcb_gpio_func *func)
+{
+	struct nvkm_bios *bios = nvkm_bios(gpio);
+	u8  ver, len;
+	u16 data;
+
+	if (line == 0xff && tag == 0xff)
+		return -EINVAL;
+
+	data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
+	if (data)
+		return 0;
+
+	/* Apple iMac G4 NV18 */
+	if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
+		if (tag == DCB_GPIO_TVDAC0) {
+			*func = (struct dcb_gpio_func) {
+				.func = DCB_GPIO_TVDAC0,
+				.line = 4,
+				.log[0] = 0,
+				.log[1] = 1,
+			};
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+static int
+nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state)
+{
+	struct dcb_gpio_func func;
+	int ret;
+
+	ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
+	if (ret == 0) {
+		int dir = !!(func.log[state] & 0x02);
+		int out = !!(func.log[state] & 0x01);
+		ret = nvkm_gpio_drive(gpio, idx, func.line, dir, out);
+	}
+
+	return ret;
+}
+
+static int
+nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line)
+{
+	struct dcb_gpio_func func;
+	int ret;
+
+	ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
+	if (ret == 0) {
+		ret = nvkm_gpio_sense(gpio, idx, func.line);
+		if (ret >= 0)
+			ret = (ret == (func.log[1] & 1));
+	}
+
+	return ret;
+}
+
+static void
+nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
+	const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+	impl->intr_mask(gpio, type, 1 << index, 0);
+}
+
+static void
+nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
+	const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+	impl->intr_mask(gpio, type, 1 << index, 1 << index);
+}
+
+static int
+nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size,
+		    struct nvkm_notify *notify)
+{
+	struct nvkm_gpio_ntfy_req *req = data;
+	if (!WARN_ON(size != sizeof(*req))) {
+		notify->size  = sizeof(struct nvkm_gpio_ntfy_rep);
+		notify->types = req->mask;
+		notify->index = req->line;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void
+nvkm_gpio_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(subdev);
+	const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+	u32 hi, lo, i;
+
+	impl->intr_stat(gpio, &hi, &lo);
+
+	for (i = 0; (hi | lo) && i < impl->lines; i++) {
+		struct nvkm_gpio_ntfy_rep rep = {
+			.mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
+				(NVKM_GPIO_LO * !!(lo & (1 << i))),
+		};
+		nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
+	}
+}
+
+static const struct nvkm_event_func
+nvkm_gpio_intr_func = {
+	.ctor = nvkm_gpio_intr_ctor,
+	.init = nvkm_gpio_intr_init,
+	.fini = nvkm_gpio_intr_fini,
+};
+
+int
+_nvkm_gpio_fini(struct nvkm_object *object, bool suspend)
+{
+	const struct nvkm_gpio_impl *impl = (void *)object->oclass;
+	struct nvkm_gpio *gpio = nvkm_gpio(object);
+	u32 mask = (1 << impl->lines) - 1;
+
+	impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
+	impl->intr_stat(gpio, &mask, &mask);
+
+	return nvkm_subdev_fini(&gpio->base, suspend);
+}
+
+static struct dmi_system_id gpio_reset_ids[] = {
+	{
+		.ident = "Apple Macbook 10,1",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
+		}
+	},
+	{ }
+};
+
+int
+_nvkm_gpio_init(struct nvkm_object *object)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(object);
+	int ret;
+
+	ret = nvkm_subdev_init(&gpio->base);
+	if (ret)
+		return ret;
+
+	if (gpio->reset && dmi_check_system(gpio_reset_ids))
+		gpio->reset(gpio, DCB_GPIO_UNUSED);
+
+	return ret;
+}
+
+void
+_nvkm_gpio_dtor(struct nvkm_object *object)
+{
+	struct nvkm_gpio *gpio = (void *)object;
+	nvkm_event_fini(&gpio->event);
+	nvkm_subdev_destroy(&gpio->base);
+}
+
+int
+nvkm_gpio_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	const struct nvkm_gpio_impl *impl = (void *)oclass;
+	struct nvkm_gpio *gpio;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "GPIO",
+				  "gpio", length, pobject);
+	gpio = *pobject;
+	if (ret)
+		return ret;
+
+	gpio->find = nvkm_gpio_find;
+	gpio->set  = nvkm_gpio_set;
+	gpio->get  = nvkm_gpio_get;
+	gpio->reset = impl->reset;
+
+	ret = nvkm_event_init(&nvkm_gpio_intr_func, 2, impl->lines,
+			      &gpio->event);
+	if (ret)
+		return ret;
+
+	nv_subdev(gpio)->intr = nvkm_gpio_intr;
+	return 0;
+}
+
+int
+_nvkm_gpio_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nvkm_gpio *gpio;
+	int ret;
+
+	ret = nvkm_gpio_create(parent, engine, oclass, &gpio);
+	*pobject = nv_object(gpio);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c
new file mode 100644
index 0000000..12b3e01
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+g94_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+	u32 intr0 = nv_rd32(gpio, 0x00e054);
+	u32 intr1 = nv_rd32(gpio, 0x00e074);
+	u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
+	u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
+	*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
+	*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
+	nv_wr32(gpio, 0x00e054, intr0);
+	nv_wr32(gpio, 0x00e074, intr1);
+}
+
+void
+g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+	u32 inte0 = nv_rd32(gpio, 0x00e050);
+	u32 inte1 = nv_rd32(gpio, 0x00e070);
+	if (type & NVKM_GPIO_LO)
+		inte0 = (inte0 & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
+	mask >>= 16;
+	data >>= 16;
+	if (type & NVKM_GPIO_LO)
+		inte1 = (inte1 & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte1 = (inte1 & ~mask) | data;
+	nv_wr32(gpio, 0x00e050, inte0);
+	nv_wr32(gpio, 0x00e070, inte1);
+}
+
+struct nvkm_oclass *
+g94_gpio_oclass = &(struct nvkm_gpio_impl) {
+	.base.handle = NV_SUBDEV(GPIO, 0x94),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpio_ctor,
+		.dtor = _nvkm_gpio_dtor,
+		.init = _nvkm_gpio_init,
+		.fini = _nvkm_gpio_fini,
+	},
+	.lines = 32,
+	.intr_stat = g94_gpio_intr_stat,
+	.intr_mask = g94_gpio_intr_mask,
+	.drive = nv50_gpio_drive,
+	.sense = nv50_gpio_sense,
+	.reset = nv50_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c
new file mode 100644
index 0000000..2c3bb25
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match)
+{
+	struct nvkm_bios *bios = nvkm_bios(gpio);
+	u8 ver, len;
+	u16 entry;
+	int ent = -1;
+
+	while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
+		u32 data = nv_ro32(bios, entry);
+		u8  line =   (data & 0x0000003f);
+		u8  defs = !!(data & 0x00000080);
+		u8  func =   (data & 0x0000ff00) >> 8;
+		u8  unk0 =   (data & 0x00ff0000) >> 16;
+		u8  unk1 =   (data & 0x1f000000) >> 24;
+
+		if ( func  == DCB_GPIO_UNUSED ||
+		    (match != DCB_GPIO_UNUSED && match != func))
+			continue;
+
+		gpio->set(gpio, 0, func, line, defs);
+
+		nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0);
+		if (unk1--)
+			nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line);
+	}
+}
+
+int
+gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+	u32 data = ((dir ^ 1) << 13) | (out << 12);
+	nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data);
+	nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */
+	return 0;
+}
+
+int
+gf110_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+	return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
+}
+
+struct nvkm_oclass *
+gf110_gpio_oclass = &(struct nvkm_gpio_impl) {
+	.base.handle = NV_SUBDEV(GPIO, 0xd0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpio_ctor,
+		.dtor = _nvkm_gpio_dtor,
+		.init = _nvkm_gpio_init,
+		.fini = _nvkm_gpio_fini,
+	},
+	.lines = 32,
+	.intr_stat = g94_gpio_intr_stat,
+	.intr_mask = g94_gpio_intr_mask,
+	.drive = gf110_gpio_drive,
+	.sense = gf110_gpio_sense,
+	.reset = gf110_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c
new file mode 100644
index 0000000..42fd2fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static void
+gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+	u32 intr0 = nv_rd32(gpio, 0x00dc00);
+	u32 intr1 = nv_rd32(gpio, 0x00dc80);
+	u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0;
+	u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1;
+	*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
+	*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
+	nv_wr32(gpio, 0x00dc00, intr0);
+	nv_wr32(gpio, 0x00dc80, intr1);
+}
+
+void
+gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+	u32 inte0 = nv_rd32(gpio, 0x00dc08);
+	u32 inte1 = nv_rd32(gpio, 0x00dc88);
+	if (type & NVKM_GPIO_LO)
+		inte0 = (inte0 & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
+	mask >>= 16;
+	data >>= 16;
+	if (type & NVKM_GPIO_LO)
+		inte1 = (inte1 & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte1 = (inte1 & ~mask) | data;
+	nv_wr32(gpio, 0x00dc08, inte0);
+	nv_wr32(gpio, 0x00dc88, inte1);
+}
+
+struct nvkm_oclass *
+gk104_gpio_oclass = &(struct nvkm_gpio_impl) {
+	.base.handle = NV_SUBDEV(GPIO, 0xe0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpio_ctor,
+		.dtor = _nvkm_gpio_dtor,
+		.init = _nvkm_gpio_init,
+		.fini = _nvkm_gpio_fini,
+	},
+	.lines = 32,
+	.intr_stat = gk104_gpio_intr_stat,
+	.intr_mask = gk104_gpio_intr_mask,
+	.drive = gf110_gpio_drive,
+	.sense = gf110_gpio_sense,
+	.reset = gf110_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c
new file mode 100644
index 0000000..2b29515
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ */
+#include "priv.h"
+
+static int
+nv10_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+	if (line < 2) {
+		line = line * 16;
+		line = nv_rd32(gpio, 0x600818) >> line;
+		return !!(line & 0x0100);
+	} else
+	if (line < 10) {
+		line = (line - 2) * 4;
+		line = nv_rd32(gpio, 0x60081c) >> line;
+		return !!(line & 0x04);
+	} else
+	if (line < 14) {
+		line = (line - 10) * 4;
+		line = nv_rd32(gpio, 0x600850) >> line;
+		return !!(line & 0x04);
+	}
+
+	return -EINVAL;
+}
+
+static int
+nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+	u32 reg, mask, data;
+
+	if (line < 2) {
+		line = line * 16;
+		reg  = 0x600818;
+		mask = 0x00000011;
+		data = (dir << 4) | out;
+	} else
+	if (line < 10) {
+		line = (line - 2) * 4;
+		reg  = 0x60081c;
+		mask = 0x00000003;
+		data = (dir << 1) | out;
+	} else
+	if (line < 14) {
+		line = (line - 10) * 4;
+		reg  = 0x600850;
+		mask = 0x00000003;
+		data = (dir << 1) | out;
+	} else {
+		return -EINVAL;
+	}
+
+	nv_mask(gpio, reg, mask << line, data << line);
+	return 0;
+}
+
+static void
+nv10_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+	u32 intr = nv_rd32(gpio, 0x001104);
+	u32 stat = nv_rd32(gpio, 0x001144) & intr;
+	*lo = (stat & 0xffff0000) >> 16;
+	*hi = (stat & 0x0000ffff);
+	nv_wr32(gpio, 0x001104, intr);
+}
+
+static void
+nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+	u32 inte = nv_rd32(gpio, 0x001144);
+	if (type & NVKM_GPIO_LO)
+		inte = (inte & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte = (inte & ~mask) | data;
+	nv_wr32(gpio, 0x001144, inte);
+}
+
+struct nvkm_oclass *
+nv10_gpio_oclass = &(struct nvkm_gpio_impl) {
+	.base.handle = NV_SUBDEV(GPIO, 0x10),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpio_ctor,
+		.dtor = _nvkm_gpio_dtor,
+		.init = _nvkm_gpio_init,
+		.fini = _nvkm_gpio_fini,
+	},
+	.lines = 16,
+	.intr_stat = nv10_gpio_intr_stat,
+	.intr_mask = nv10_gpio_intr_mask,
+	.drive = nv10_gpio_drive,
+	.sense = nv10_gpio_sense,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c
new file mode 100644
index 0000000..6a03103
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match)
+{
+	struct nvkm_bios *bios = nvkm_bios(gpio);
+	u8 ver, len;
+	u16 entry;
+	int ent = -1;
+
+	while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
+		static const u32 regs[] = { 0xe100, 0xe28c };
+		u32 data = nv_ro32(bios, entry);
+		u8  line =   (data & 0x0000001f);
+		u8  func =   (data & 0x0000ff00) >> 8;
+		u8  defs = !!(data & 0x01000000);
+		u8  unk0 = !!(data & 0x02000000);
+		u8  unk1 = !!(data & 0x04000000);
+		u32 val = (unk1 << 16) | unk0;
+		u32 reg = regs[line >> 4];
+		u32 lsh = line & 0x0f;
+
+		if ( func  == DCB_GPIO_UNUSED ||
+		    (match != DCB_GPIO_UNUSED && match != func))
+			continue;
+
+		gpio->set(gpio, 0, func, line, defs);
+
+		nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
+	}
+}
+
+int
+nv50_gpio_location(int line, u32 *reg, u32 *shift)
+{
+	const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
+
+	if (line >= 32)
+		return -EINVAL;
+
+	*reg = nv50_gpio_reg[line >> 3];
+	*shift = (line & 7) << 2;
+	return 0;
+}
+
+int
+nv50_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+	u32 reg, shift;
+
+	if (nv50_gpio_location(line, &reg, &shift))
+		return -EINVAL;
+
+	nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
+	return 0;
+}
+
+int
+nv50_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+	u32 reg, shift;
+
+	if (nv50_gpio_location(line, &reg, &shift))
+		return -EINVAL;
+
+	return !!(nv_rd32(gpio, reg) & (4 << shift));
+}
+
+static void
+nv50_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+	u32 intr = nv_rd32(gpio, 0x00e054);
+	u32 stat = nv_rd32(gpio, 0x00e050) & intr;
+	*lo = (stat & 0xffff0000) >> 16;
+	*hi = (stat & 0x0000ffff);
+	nv_wr32(gpio, 0x00e054, intr);
+}
+
+static void
+nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+	u32 inte = nv_rd32(gpio, 0x00e050);
+	if (type & NVKM_GPIO_LO)
+		inte = (inte & ~(mask << 16)) | (data << 16);
+	if (type & NVKM_GPIO_HI)
+		inte = (inte & ~mask) | data;
+	nv_wr32(gpio, 0x00e050, inte);
+}
+
+struct nvkm_oclass *
+nv50_gpio_oclass = &(struct nvkm_gpio_impl) {
+	.base.handle = NV_SUBDEV(GPIO, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_gpio_ctor,
+		.dtor = _nvkm_gpio_dtor,
+		.init = _nvkm_gpio_init,
+		.fini = _nvkm_gpio_fini,
+	},
+	.lines = 16,
+	.intr_stat = nv50_gpio_intr_stat,
+	.intr_mask = nv50_gpio_intr_mask,
+	.drive = nv50_gpio_drive,
+	.sense = nv50_gpio_sense,
+	.reset = nv50_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h
new file mode 100644
index 0000000..382f8d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h
@@ -0,0 +1,64 @@
+#ifndef __NVKM_GPIO_PRIV_H__
+#define __NVKM_GPIO_PRIV_H__
+#include <subdev/gpio.h>
+
+#define nvkm_gpio_create(p,e,o,d)                                           \
+	nvkm_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_gpio_destroy(p) ({                                             \
+	struct nvkm_gpio *gpio = (p);                                       \
+	_nvkm_gpio_dtor(nv_object(gpio));                                   \
+})
+#define nvkm_gpio_init(p) ({                                                \
+	struct nvkm_gpio *gpio = (p);                                       \
+	_nvkm_gpio_init(nv_object(gpio));                                   \
+})
+#define nvkm_gpio_fini(p,s) ({                                              \
+	struct nvkm_gpio *gpio = (p);                                       \
+	_nvkm_gpio_fini(nv_object(gpio), (s));                              \
+})
+
+int  nvkm_gpio_create_(struct nvkm_object *, struct nvkm_object *,
+			  struct nvkm_oclass *, int, void **);
+int  _nvkm_gpio_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+void _nvkm_gpio_dtor(struct nvkm_object *);
+int  _nvkm_gpio_init(struct nvkm_object *);
+int  _nvkm_gpio_fini(struct nvkm_object *, bool);
+
+struct nvkm_gpio_impl {
+	struct nvkm_oclass base;
+	int lines;
+
+	/* read and ack pending interrupts, returning only data
+	 * for lines that have not been masked off, while still
+	 * performing the ack for anything that was pending.
+	 */
+	void (*intr_stat)(struct nvkm_gpio *, u32 *, u32 *);
+
+	/* mask on/off interrupts for hi/lo transitions on a
+	 * given set of gpio lines
+	 */
+	void (*intr_mask)(struct nvkm_gpio *, u32, u32, u32);
+
+	/* configure gpio direction and output value */
+	int  (*drive)(struct nvkm_gpio *, int line, int dir, int out);
+
+	/* sense current state of given gpio line */
+	int  (*sense)(struct nvkm_gpio *, int line);
+
+	/*XXX*/
+	void (*reset)(struct nvkm_gpio *, u8);
+};
+
+void nv50_gpio_reset(struct nvkm_gpio *, u8);
+int  nv50_gpio_drive(struct nvkm_gpio *, int, int, int);
+int  nv50_gpio_sense(struct nvkm_gpio *, int);
+
+void g94_gpio_intr_stat(struct nvkm_gpio *, u32 *, u32 *);
+void g94_gpio_intr_mask(struct nvkm_gpio *, u32, u32, u32);
+
+void gf110_gpio_reset(struct nvkm_gpio *, u8);
+int  gf110_gpio_drive(struct nvkm_gpio *, int, int, int);
+int  gf110_gpio_sense(struct nvkm_gpio *, int);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
new file mode 100644
index 0000000..d683074
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
@@ -0,0 +1,16 @@
+nvkm-y += nvkm/subdev/i2c/base.o
+nvkm-y += nvkm/subdev/i2c/anx9805.o
+nvkm-y += nvkm/subdev/i2c/aux.o
+nvkm-y += nvkm/subdev/i2c/bit.o
+nvkm-y += nvkm/subdev/i2c/pad.o
+nvkm-y += nvkm/subdev/i2c/padnv04.o
+nvkm-y += nvkm/subdev/i2c/padg94.o
+nvkm-y += nvkm/subdev/i2c/padgm204.o
+nvkm-y += nvkm/subdev/i2c/nv04.o
+nvkm-y += nvkm/subdev/i2c/nv4e.o
+nvkm-y += nvkm/subdev/i2c/nv50.o
+nvkm-y += nvkm/subdev/i2c/g94.o
+nvkm-y += nvkm/subdev/i2c/gf110.o
+nvkm-y += nvkm/subdev/i2c/gf117.o
+nvkm-y += nvkm/subdev/i2c/gk104.o
+nvkm-y += nvkm/subdev/i2c/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
new file mode 100644
index 0000000..d17dd1c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "port.h"
+
+struct anx9805_i2c_port {
+	struct nvkm_i2c_port base;
+	u32 addr;
+	u32 ctrl;
+};
+
+static int
+anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh)
+{
+	struct anx9805_i2c_port *chan = (void *)port;
+	struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent;
+	u8 tmp, i;
+
+	DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh);
+
+	nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
+	nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
+	nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
+	nv_wri2cr(mast, chan->addr, 0xa8, 0x01);
+
+	i = 0;
+	while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) {
+		mdelay(5);
+		if (i++ == 100) {
+			nv_error(port, "link training timed out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	if (tmp & 0x70) {
+		nv_error(port, "link training failed: 0x%02x\n", tmp);
+		return -EIO;
+	}
+
+	return 1;
+}
+
+static int
+anx9805_aux(struct nvkm_i2c_port *port, bool retry,
+	    u8 type, u32 addr, u8 *data, u8 size)
+{
+	struct anx9805_i2c_port *chan = (void *)port;
+	struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent;
+	int i, ret = -ETIMEDOUT;
+	u8 buf[16] = {};
+	u8 tmp;
+
+	DBG("%02x %05x %d\n", type, addr, size);
+
+	tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
+	nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
+	nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
+	nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
+
+	nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
+	if (!(type & 1)) {
+		memcpy(buf, data, size);
+		DBG("%16ph", buf);
+		for (i = 0; i < size; i++)
+			nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]);
+	}
+	nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
+	nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >>  0);
+	nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >>  8);
+	nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16);
+	nv_wri2cr(mast, chan->addr, 0xe9, 0x01);
+
+	i = 0;
+	while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) {
+		mdelay(5);
+		if (i++ == 32)
+			goto done;
+	}
+
+	if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) {
+		ret = -EIO;
+		goto done;
+	}
+
+	if (type & 1) {
+		for (i = 0; i < size; i++)
+			buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
+		DBG("%16ph", buf);
+		memcpy(data, buf, size);
+	}
+
+	ret = 0;
+done:
+	nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
+	return ret;
+}
+
+static const struct nvkm_i2c_func
+anx9805_aux_func = {
+	.aux = anx9805_aux,
+	.lnk_ctl = anx9805_train,
+};
+
+static int
+anx9805_aux_chan_ctor(struct nvkm_object *parent,
+		      struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *data, u32 index,
+		      struct nvkm_object **pobject)
+{
+	struct nvkm_i2c_port *mast = (void *)parent;
+	struct anx9805_i2c_port *chan;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_aux_algo, &anx9805_aux_func,
+				   &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	switch ((oclass->handle & 0xff00) >> 8) {
+	case 0x0d:
+		chan->addr = 0x38;
+		chan->ctrl = 0x39;
+		break;
+	case 0x0e:
+		chan->addr = 0x3c;
+		chan->ctrl = 0x3b;
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	if (mast->adapter.algo == &i2c_bit_algo) {
+		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
+		algo->udelay = max(algo->udelay, 40);
+	}
+
+	return 0;
+}
+
+static struct nvkm_ofuncs
+anx9805_aux_ofuncs = {
+	.ctor =  anx9805_aux_chan_ctor,
+	.dtor = _nvkm_i2c_port_dtor,
+	.init = _nvkm_i2c_port_init,
+	.fini = _nvkm_i2c_port_fini,
+};
+
+static int
+anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct anx9805_i2c_port *port = adap->algo_data;
+	struct nvkm_i2c_port *mast = (void *)nv_object(port)->parent;
+	struct i2c_msg *msg = msgs;
+	int ret = -ETIMEDOUT;
+	int i, j, cnt = num;
+	u8 seg = 0x00, off = 0x00, tmp;
+
+	tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10;
+	nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10);
+	nv_wri2cr(mast, port->ctrl, 0x07, tmp);
+	nv_wri2cr(mast, port->addr, 0x43, 0x05);
+	mdelay(5);
+
+	while (cnt--) {
+		if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
+			nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1);
+			nv_wri2cr(mast, port->addr, 0x41, seg);
+			nv_wri2cr(mast, port->addr, 0x42, off);
+			nv_wri2cr(mast, port->addr, 0x44, msg->len);
+			nv_wri2cr(mast, port->addr, 0x45, 0x00);
+			nv_wri2cr(mast, port->addr, 0x43, 0x01);
+			for (i = 0; i < msg->len; i++) {
+				j = 0;
+				while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) {
+					mdelay(5);
+					if (j++ == 32)
+						goto done;
+				}
+				msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47);
+			}
+		} else
+		if (!(msg->flags & I2C_M_RD)) {
+			if (msg->addr == 0x50 && msg->len == 0x01) {
+				off = msg->buf[0];
+			} else
+			if (msg->addr == 0x30 && msg->len == 0x01) {
+				seg = msg->buf[0];
+			} else
+				goto done;
+		} else {
+			goto done;
+		}
+		msg++;
+	}
+
+	ret = num;
+done:
+	nv_wri2cr(mast, port->addr, 0x43, 0x00);
+	return ret;
+}
+
+static u32
+anx9805_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm
+anx9805_i2c_algo = {
+	.master_xfer = anx9805_xfer,
+	.functionality = anx9805_func
+};
+
+static const struct nvkm_i2c_func
+anx9805_i2c_func = {
+};
+
+static int
+anx9805_ddc_port_ctor(struct nvkm_object *parent,
+		      struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, void *data, u32 index,
+		      struct nvkm_object **pobject)
+{
+	struct nvkm_i2c_port *mast = (void *)parent;
+	struct anx9805_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &anx9805_i2c_algo, &anx9805_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	switch ((oclass->handle & 0xff00) >> 8) {
+	case 0x0d:
+		port->addr = 0x3d;
+		port->ctrl = 0x39;
+		break;
+	case 0x0e:
+		port->addr = 0x3f;
+		port->ctrl = 0x3b;
+		break;
+	default:
+		BUG_ON(1);
+	}
+
+	if (mast->adapter.algo == &i2c_bit_algo) {
+		struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
+		algo->udelay = max(algo->udelay, 40);
+	}
+
+	return 0;
+}
+
+static struct nvkm_ofuncs
+anx9805_ddc_ofuncs = {
+	.ctor =  anx9805_ddc_port_ctor,
+	.dtor = _nvkm_i2c_port_dtor,
+	.init = _nvkm_i2c_port_init,
+	.fini = _nvkm_i2c_port_fini,
+};
+
+struct nvkm_oclass
+nvkm_anx9805_sclass[] = {
+	{ .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs },
+	{ .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs },
+	{ .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs },
+	{ .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs },
+	{}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
new file mode 100644
index 0000000..1c18860
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+int
+nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(port);
+	if (port->func->aux) {
+		int ret = i2c->acquire(port, 0);
+		if (ret == 0) {
+			ret = port->func->aux(port, true, 9, addr, data, size);
+			i2c->release(port);
+		}
+		return ret;
+	}
+	return -ENODEV;
+}
+
+int
+nv_wraux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(port);
+	if (port->func->aux) {
+		int ret = i2c->acquire(port, 0);
+		if (ret == 0) {
+			ret = port->func->aux(port, true, 8, addr, data, size);
+			i2c->release(port);
+		}
+		return ret;
+	}
+	return -ENODEV;
+}
+
+static int
+aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct nvkm_i2c_port *port = adap->algo_data;
+	struct nvkm_i2c *i2c = nvkm_i2c(port);
+	struct i2c_msg *msg = msgs;
+	int ret, mcnt = num;
+
+	if (!port->func->aux)
+		return -ENODEV;
+
+	ret = i2c->acquire(port, 0);
+	if (ret)
+		return ret;
+
+	while (mcnt--) {
+		u8 remaining = msg->len;
+		u8 *ptr = msg->buf;
+
+		while (remaining) {
+			u8 cnt = (remaining > 16) ? 16 : remaining;
+			u8 cmd;
+
+			if (msg->flags & I2C_M_RD)
+				cmd = 1;
+			else
+				cmd = 0;
+
+			if (mcnt || remaining > 16)
+				cmd |= 4; /* MOT */
+
+			ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
+			if (ret < 0) {
+				i2c->release(port);
+				return ret;
+			}
+
+			ptr += cnt;
+			remaining -= cnt;
+		}
+
+		msg++;
+	}
+
+	i2c->release(port);
+	return num;
+}
+
+static u32
+aux_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nvkm_i2c_aux_algo = {
+	.master_xfer = aux_xfer,
+	.functionality = aux_func
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
new file mode 100644
index 0000000..9200f12
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "pad.h"
+
+#include <core/device.h>
+#include <core/notify.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+/******************************************************************************
+ * interface to linux i2c bit-banging algorithm
+ *****************************************************************************/
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
+#define CSTMSEL true
+#else
+#define CSTMSEL false
+#endif
+
+static int
+nvkm_i2c_pre_xfer(struct i2c_adapter *adap)
+{
+	struct i2c_algo_bit_data *bit = adap->algo_data;
+	struct nvkm_i2c_port *port = bit->data;
+	return nvkm_i2c(port)->acquire(port, bit->timeout);
+}
+
+static void
+nvkm_i2c_post_xfer(struct i2c_adapter *adap)
+{
+	struct i2c_algo_bit_data *bit = adap->algo_data;
+	struct nvkm_i2c_port *port = bit->data;
+	return nvkm_i2c(port)->release(port);
+}
+
+static void
+nvkm_i2c_setscl(void *data, int state)
+{
+	struct nvkm_i2c_port *port = data;
+	port->func->drive_scl(port, state);
+}
+
+static void
+nvkm_i2c_setsda(void *data, int state)
+{
+	struct nvkm_i2c_port *port = data;
+	port->func->drive_sda(port, state);
+}
+
+static int
+nvkm_i2c_getscl(void *data)
+{
+	struct nvkm_i2c_port *port = data;
+	return port->func->sense_scl(port);
+}
+
+static int
+nvkm_i2c_getsda(void *data)
+{
+	struct nvkm_i2c_port *port = data;
+	return port->func->sense_sda(port);
+}
+
+/******************************************************************************
+ * base i2c "port" class implementation
+ *****************************************************************************/
+
+int
+_nvkm_i2c_port_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_i2c_port *port = (void *)object;
+	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+	nv_ofuncs(pad)->fini(nv_object(pad), suspend);
+	return nvkm_object_fini(&port->base, suspend);
+}
+
+void
+_nvkm_i2c_port_dtor(struct nvkm_object *object)
+{
+	struct nvkm_i2c_port *port = (void *)object;
+	i2c_del_adapter(&port->adapter);
+	nvkm_object_destroy(&port->base);
+}
+
+int
+nvkm_i2c_port_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		      struct nvkm_oclass *oclass, u8 index,
+		      const struct i2c_algorithm *algo,
+		      const struct nvkm_i2c_func *func,
+		      int size, void **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvkm_i2c_port *port;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject);
+	port = *pobject;
+	if (ret)
+		return ret;
+
+	snprintf(port->adapter.name, sizeof(port->adapter.name),
+		 "nvkm-%s-%d", device->name, index);
+	port->adapter.owner = THIS_MODULE;
+	port->adapter.dev.parent = nv_device_base(device);
+	port->index = index;
+	port->aux = -1;
+	port->func = func;
+	mutex_init(&port->mutex);
+
+	if ( algo == &nvkm_i2c_bit_algo &&
+	    !nvkm_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
+		struct i2c_algo_bit_data *bit;
+
+		bit = kzalloc(sizeof(*bit), GFP_KERNEL);
+		if (!bit)
+			return -ENOMEM;
+
+		bit->udelay = 10;
+		bit->timeout = usecs_to_jiffies(2200);
+		bit->data = port;
+		bit->pre_xfer = nvkm_i2c_pre_xfer;
+		bit->post_xfer = nvkm_i2c_post_xfer;
+		bit->setsda = nvkm_i2c_setsda;
+		bit->setscl = nvkm_i2c_setscl;
+		bit->getsda = nvkm_i2c_getsda;
+		bit->getscl = nvkm_i2c_getscl;
+
+		port->adapter.algo_data = bit;
+		ret = i2c_bit_add_bus(&port->adapter);
+	} else {
+		port->adapter.algo_data = port;
+		port->adapter.algo = algo;
+		ret = i2c_add_adapter(&port->adapter);
+	}
+
+	if (ret == 0)
+		list_add_tail(&port->head, &i2c->ports);
+	return ret;
+}
+
+/******************************************************************************
+ * base i2c subdev class implementation
+ *****************************************************************************/
+
+static struct nvkm_i2c_port *
+nvkm_i2c_find(struct nvkm_i2c *i2c, u8 index)
+{
+	struct nvkm_bios *bios = nvkm_bios(i2c);
+	struct nvkm_i2c_port *port;
+
+	if (index == NV_I2C_DEFAULT(0) ||
+	    index == NV_I2C_DEFAULT(1)) {
+		u8  ver, hdr, cnt, len;
+		u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
+		if (i2c && ver >= 0x30) {
+			u8 auxidx = nv_ro08(bios, i2c + 4);
+			if (index == NV_I2C_DEFAULT(0))
+				index = (auxidx & 0x0f) >> 0;
+			else
+				index = (auxidx & 0xf0) >> 4;
+		} else {
+			index = 2;
+		}
+	}
+
+	list_for_each_entry(port, &i2c->ports, head) {
+		if (port->index == index)
+			return port;
+	}
+
+	return NULL;
+}
+
+static struct nvkm_i2c_port *
+nvkm_i2c_find_type(struct nvkm_i2c *i2c, u16 type)
+{
+	struct nvkm_i2c_port *port;
+
+	list_for_each_entry(port, &i2c->ports, head) {
+		if (nv_hclass(port) == type)
+			return port;
+	}
+
+	return NULL;
+}
+
+static void
+nvkm_i2c_release_pad(struct nvkm_i2c_port *port)
+{
+	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+	struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+	if (atomic_dec_and_test(&nv_object(pad)->usecount)) {
+		nv_ofuncs(pad)->fini(nv_object(pad), false);
+		wake_up_all(&i2c->wait);
+	}
+}
+
+static int
+nvkm_i2c_try_acquire_pad(struct nvkm_i2c_port *port)
+{
+	struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+
+	if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) {
+		struct nvkm_object *owner = (void *)pad->port;
+		do {
+			if (owner == (void *)port)
+				return 0;
+			owner = owner->parent;
+		} while(owner);
+		nvkm_i2c_release_pad(port);
+		return -EBUSY;
+	}
+
+	pad->next = port;
+	nv_ofuncs(pad)->init(nv_object(pad));
+	return 0;
+}
+
+static int
+nvkm_i2c_acquire_pad(struct nvkm_i2c_port *port, unsigned long timeout)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+	if (timeout) {
+		if (wait_event_timeout(i2c->wait,
+				       nvkm_i2c_try_acquire_pad(port) == 0,
+				       timeout) == 0)
+			return -EBUSY;
+	} else {
+		wait_event(i2c->wait, nvkm_i2c_try_acquire_pad(port) == 0);
+	}
+
+	return 0;
+}
+
+static void
+nvkm_i2c_release(struct nvkm_i2c_port *port)
+__releases(pad->mutex)
+{
+	nvkm_i2c(port)->release_pad(port);
+	mutex_unlock(&port->mutex);
+}
+
+static int
+nvkm_i2c_acquire(struct nvkm_i2c_port *port, unsigned long timeout)
+__acquires(pad->mutex)
+{
+	int ret;
+	mutex_lock(&port->mutex);
+	if ((ret = nvkm_i2c(port)->acquire_pad(port, timeout)))
+		mutex_unlock(&port->mutex);
+	return ret;
+}
+
+static int
+nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what,
+		  struct nvkm_i2c_board_info *info,
+		  bool (*match)(struct nvkm_i2c_port *,
+				struct i2c_board_info *, void *), void *data)
+{
+	struct nvkm_i2c_port *port = nvkm_i2c_find(i2c, index);
+	int i;
+
+	if (!port) {
+		nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
+		return -ENODEV;
+	}
+
+	nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
+	for (i = 0; info[i].dev.addr; i++) {
+		u8 orig_udelay = 0;
+
+		if ((port->adapter.algo == &i2c_bit_algo) &&
+		    (info[i].udelay != 0)) {
+			struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+			nv_debug(i2c, "using custom udelay %d instead of %d\n",
+			         info[i].udelay, algo->udelay);
+			orig_udelay = algo->udelay;
+			algo->udelay = info[i].udelay;
+		}
+
+		if (nv_probe_i2c(port, info[i].dev.addr) &&
+		    (!match || match(port, &info[i].dev, data))) {
+			nv_info(i2c, "detected %s: %s\n", what,
+				info[i].dev.type);
+			return i;
+		}
+
+		if (orig_udelay) {
+			struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+			algo->udelay = orig_udelay;
+		}
+	}
+
+	nv_debug(i2c, "no devices found.\n");
+	return -ENODEV;
+}
+
+static void
+nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
+	struct nvkm_i2c_port *port = i2c->find(i2c, index);
+	const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
+	if (port && port->aux >= 0)
+		impl->aux_mask(i2c, type, 1 << port->aux, 0);
+}
+
+static void
+nvkm_i2c_intr_init(struct nvkm_event *event, int type, int index)
+{
+	struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
+	struct nvkm_i2c_port *port = i2c->find(i2c, index);
+	const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
+	if (port && port->aux >= 0)
+		impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
+}
+
+static int
+nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size,
+		      struct nvkm_notify *notify)
+{
+	struct nvkm_i2c_ntfy_req *req = data;
+	if (!WARN_ON(size != sizeof(*req))) {
+		notify->size  = sizeof(struct nvkm_i2c_ntfy_rep);
+		notify->types = req->mask;
+		notify->index = req->port;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static void
+nvkm_i2c_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_i2c_impl *impl = (void *)nv_oclass(subdev);
+	struct nvkm_i2c *i2c = nvkm_i2c(subdev);
+	struct nvkm_i2c_port *port;
+	u32 hi, lo, rq, tx, e;
+
+	if (impl->aux_stat) {
+		impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
+		if (hi || lo || rq || tx) {
+			list_for_each_entry(port, &i2c->ports, head) {
+				if (e = 0, port->aux < 0)
+					continue;
+
+				if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
+				if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
+				if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
+				if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
+				if (e) {
+					struct nvkm_i2c_ntfy_rep rep = {
+						.mask = e,
+					};
+					nvkm_event_send(&i2c->event, rep.mask,
+							port->index, &rep,
+							sizeof(rep));
+				}
+			}
+		}
+	}
+}
+
+static const struct nvkm_event_func
+nvkm_i2c_intr_func = {
+	.ctor = nvkm_i2c_intr_ctor,
+	.init = nvkm_i2c_intr_init,
+	.fini = nvkm_i2c_intr_fini,
+};
+
+int
+_nvkm_i2c_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_i2c_impl *impl = (void *)nv_oclass(object);
+	struct nvkm_i2c *i2c = (void *)object;
+	struct nvkm_i2c_port *port;
+	u32 mask;
+	int ret;
+
+	list_for_each_entry(port, &i2c->ports, head) {
+		ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
+		if (ret && suspend)
+			goto fail;
+	}
+
+	if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
+		impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
+		impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
+	}
+
+	return nvkm_subdev_fini(&i2c->base, suspend);
+fail:
+	list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
+		nv_ofuncs(port)->init(nv_object(port));
+	}
+
+	return ret;
+}
+
+int
+_nvkm_i2c_init(struct nvkm_object *object)
+{
+	struct nvkm_i2c *i2c = (void *)object;
+	struct nvkm_i2c_port *port;
+	int ret;
+
+	ret = nvkm_subdev_init(&i2c->base);
+	if (ret == 0) {
+		list_for_each_entry(port, &i2c->ports, head) {
+			ret = nv_ofuncs(port)->init(nv_object(port));
+			if (ret)
+				goto fail;
+		}
+	}
+
+	return ret;
+fail:
+	list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
+		nv_ofuncs(port)->fini(nv_object(port), false);
+	}
+
+	return ret;
+}
+
+void
+_nvkm_i2c_dtor(struct nvkm_object *object)
+{
+	struct nvkm_i2c *i2c = (void *)object;
+	struct nvkm_i2c_port *port, *temp;
+
+	nvkm_event_fini(&i2c->event);
+
+	list_for_each_entry_safe(port, temp, &i2c->ports, head) {
+		nvkm_object_ref(NULL, (struct nvkm_object **)&port);
+	}
+
+	nvkm_subdev_destroy(&i2c->base);
+}
+
+static struct nvkm_oclass *
+nvkm_i2c_extdev_sclass[] = {
+	nvkm_anx9805_sclass,
+};
+
+static void
+nvkm_i2c_create_port(struct nvkm_i2c *i2c, int index, u8 type,
+		     struct dcb_i2c_entry *info)
+{
+	const struct nvkm_i2c_impl *impl = (void *)nv_oclass(i2c);
+	struct nvkm_oclass *oclass;
+	struct nvkm_object *parent;
+	struct nvkm_object *object;
+	int ret, pad;
+
+	if (info->share != DCB_I2C_UNUSED) {
+		pad    = info->share;
+		oclass = impl->pad_s;
+	} else {
+		if (type != DCB_I2C_NVIO_AUX)
+			pad = 0x100 + info->drive;
+		else
+			pad = 0x100 + info->auxch;
+		oclass = impl->pad_x;
+	}
+
+	ret = nvkm_object_ctor(nv_object(i2c), NULL, oclass,
+			       NULL, pad, &parent);
+	if (ret < 0)
+		return;
+
+	oclass = impl->sclass;
+	do {
+		ret = -EINVAL;
+		if (oclass->handle == type) {
+			ret = nvkm_object_ctor(parent, NULL, oclass,
+					       info, index, &object);
+		}
+	} while (ret && (++oclass)->handle);
+
+	nvkm_object_ref(NULL, &parent);
+}
+
+int
+nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_i2c *i2c;
+	struct nvkm_object *object;
+	struct dcb_i2c_entry info;
+	int ret, i, j, index = -1;
+	struct dcb_output outp;
+	u8  ver, hdr;
+	u32 data;
+
+	ret = nvkm_subdev_create(parent, engine, oclass, 0, "I2C", "i2c", &i2c);
+	*pobject = nv_object(i2c);
+	if (ret)
+		return ret;
+
+	nv_subdev(i2c)->intr = nvkm_i2c_intr;
+	i2c->find = nvkm_i2c_find;
+	i2c->find_type = nvkm_i2c_find_type;
+	i2c->acquire_pad = nvkm_i2c_acquire_pad;
+	i2c->release_pad = nvkm_i2c_release_pad;
+	i2c->acquire = nvkm_i2c_acquire;
+	i2c->release = nvkm_i2c_release;
+	i2c->identify = nvkm_i2c_identify;
+	init_waitqueue_head(&i2c->wait);
+	INIT_LIST_HEAD(&i2c->ports);
+
+	while (!dcb_i2c_parse(bios, ++index, &info)) {
+		switch (info.type) {
+		case DCB_I2C_NV04_BIT:
+		case DCB_I2C_NV4E_BIT:
+		case DCB_I2C_NVIO_BIT:
+			nvkm_i2c_create_port(i2c, NV_I2C_PORT(index),
+					     info.type, &info);
+			break;
+		case DCB_I2C_NVIO_AUX:
+			nvkm_i2c_create_port(i2c, NV_I2C_AUX(index),
+					     info.type, &info);
+			break;
+		case DCB_I2C_PMGR:
+			if (info.drive != DCB_I2C_UNUSED) {
+				nvkm_i2c_create_port(i2c, NV_I2C_PORT(index),
+						     DCB_I2C_NVIO_BIT, &info);
+			}
+			if (info.auxch != DCB_I2C_UNUSED) {
+				nvkm_i2c_create_port(i2c, NV_I2C_AUX(index),
+						     DCB_I2C_NVIO_AUX, &info);
+			}
+			break;
+		case DCB_I2C_UNUSED:
+		default:
+			continue;
+		}
+	}
+
+	/* in addition to the busses specified in the i2c table, there
+	 * may be ddc/aux channels hiding behind external tmds/dp/etc
+	 * transmitters.
+	 */
+	index = NV_I2C_EXT(0);
+	i = -1;
+	while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
+		if (!outp.location || !outp.extdev)
+			continue;
+
+		switch (outp.type) {
+		case DCB_OUTPUT_TMDS:
+			info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
+			break;
+		case DCB_OUTPUT_DP:
+			info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
+			break;
+		default:
+			continue;
+		}
+
+		ret = -ENODEV;
+		j = -1;
+		while (ret && ++j < ARRAY_SIZE(nvkm_i2c_extdev_sclass)) {
+			parent = nv_object(i2c->find(i2c, outp.i2c_index));
+			oclass = nvkm_i2c_extdev_sclass[j];
+			do {
+				if (oclass->handle != info.type)
+					continue;
+				ret = nvkm_object_ctor(parent, NULL, oclass,
+						       NULL, index++, &object);
+			} while (ret && (++oclass)->handle);
+		}
+	}
+
+	ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, index, &i2c->event);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int
+_nvkm_i2c_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_i2c *i2c;
+	int ret;
+
+	ret = nvkm_i2c_create(parent, engine, oclass, &i2c);
+	*pobject = nv_object(i2c);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
new file mode 100644
index 0000000..861a453
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
+#define T_TIMEOUT  2200000
+#define T_RISEFALL 1000
+#define T_HOLD     5000
+
+static inline void
+i2c_drive_scl(struct nvkm_i2c_port *port, int state)
+{
+	port->func->drive_scl(port, state);
+}
+
+static inline void
+i2c_drive_sda(struct nvkm_i2c_port *port, int state)
+{
+	port->func->drive_sda(port, state);
+}
+
+static inline int
+i2c_sense_scl(struct nvkm_i2c_port *port)
+{
+	return port->func->sense_scl(port);
+}
+
+static inline int
+i2c_sense_sda(struct nvkm_i2c_port *port)
+{
+	return port->func->sense_sda(port);
+}
+
+static void
+i2c_delay(struct nvkm_i2c_port *port, u32 nsec)
+{
+	udelay((nsec + 500) / 1000);
+}
+
+static bool
+i2c_raise_scl(struct nvkm_i2c_port *port)
+{
+	u32 timeout = T_TIMEOUT / T_RISEFALL;
+
+	i2c_drive_scl(port, 1);
+	do {
+		i2c_delay(port, T_RISEFALL);
+	} while (!i2c_sense_scl(port) && --timeout);
+
+	return timeout != 0;
+}
+
+static int
+i2c_start(struct nvkm_i2c_port *port)
+{
+	int ret = 0;
+
+	if (!i2c_sense_scl(port) ||
+	    !i2c_sense_sda(port)) {
+		i2c_drive_scl(port, 0);
+		i2c_drive_sda(port, 1);
+		if (!i2c_raise_scl(port))
+			ret = -EBUSY;
+	}
+
+	i2c_drive_sda(port, 0);
+	i2c_delay(port, T_HOLD);
+	i2c_drive_scl(port, 0);
+	i2c_delay(port, T_HOLD);
+	return ret;
+}
+
+static void
+i2c_stop(struct nvkm_i2c_port *port)
+{
+	i2c_drive_scl(port, 0);
+	i2c_drive_sda(port, 0);
+	i2c_delay(port, T_RISEFALL);
+
+	i2c_drive_scl(port, 1);
+	i2c_delay(port, T_HOLD);
+	i2c_drive_sda(port, 1);
+	i2c_delay(port, T_HOLD);
+}
+
+static int
+i2c_bitw(struct nvkm_i2c_port *port, int sda)
+{
+	i2c_drive_sda(port, sda);
+	i2c_delay(port, T_RISEFALL);
+
+	if (!i2c_raise_scl(port))
+		return -ETIMEDOUT;
+	i2c_delay(port, T_HOLD);
+
+	i2c_drive_scl(port, 0);
+	i2c_delay(port, T_HOLD);
+	return 0;
+}
+
+static int
+i2c_bitr(struct nvkm_i2c_port *port)
+{
+	int sda;
+
+	i2c_drive_sda(port, 1);
+	i2c_delay(port, T_RISEFALL);
+
+	if (!i2c_raise_scl(port))
+		return -ETIMEDOUT;
+	i2c_delay(port, T_HOLD);
+
+	sda = i2c_sense_sda(port);
+
+	i2c_drive_scl(port, 0);
+	i2c_delay(port, T_HOLD);
+	return sda;
+}
+
+static int
+i2c_get_byte(struct nvkm_i2c_port *port, u8 *byte, bool last)
+{
+	int i, bit;
+
+	*byte = 0;
+	for (i = 7; i >= 0; i--) {
+		bit = i2c_bitr(port);
+		if (bit < 0)
+			return bit;
+		*byte |= bit << i;
+	}
+
+	return i2c_bitw(port, last ? 1 : 0);
+}
+
+static int
+i2c_put_byte(struct nvkm_i2c_port *port, u8 byte)
+{
+	int i, ret;
+	for (i = 7; i >= 0; i--) {
+		ret = i2c_bitw(port, !!(byte & (1 << i)));
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = i2c_bitr(port);
+	if (ret == 1) /* nack */
+		ret = -EIO;
+	return ret;
+}
+
+static int
+i2c_addr(struct nvkm_i2c_port *port, struct i2c_msg *msg)
+{
+	u32 addr = msg->addr << 1;
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+	return i2c_put_byte(port, addr);
+}
+
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct nvkm_i2c_port *port = adap->algo_data;
+	struct i2c_msg *msg = msgs;
+	int ret = 0, mcnt = num;
+
+	ret = nvkm_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
+	if (ret)
+		return ret;
+
+	while (!ret && mcnt--) {
+		u8 remaining = msg->len;
+		u8 *ptr = msg->buf;
+
+		ret = i2c_start(port);
+		if (ret == 0)
+			ret = i2c_addr(port, msg);
+
+		if (msg->flags & I2C_M_RD) {
+			while (!ret && remaining--)
+				ret = i2c_get_byte(port, ptr++, !remaining);
+		} else {
+			while (!ret && remaining--)
+				ret = i2c_put_byte(port, *ptr++);
+		}
+
+		msg++;
+	}
+
+	i2c_stop(port);
+	nvkm_i2c(port)->release(port);
+	return (ret < 0) ? ret : num;
+}
+#else
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	return -ENODEV;
+}
+#endif
+
+static u32
+i2c_bit_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nvkm_i2c_bit_algo = {
+	.master_xfer = i2c_bit_xfer,
+	.functionality = i2c_bit_func
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
new file mode 100644
index 0000000..2a2dd47
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
+{
+	u32 intr = nv_rd32(i2c, 0x00e06c);
+	u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
+	for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
+		if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
+		if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
+		if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
+		if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
+	}
+	nv_wr32(i2c, 0x00e06c, intr);
+}
+
+void
+g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
+{
+	u32 temp = nv_rd32(i2c, 0x00e068), i;
+	for (i = 0; i < 8; i++) {
+		if (mask & (1 << i)) {
+			if (!(data & (1 << i))) {
+				temp &= ~(type << (i * 4));
+				continue;
+			}
+			temp |= type << (i * 4);
+		}
+	}
+	nv_wr32(i2c, 0x00e068, temp);
+}
+
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nvkm_i2c *aux, int ch)
+{
+	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nvkm_i2c *aux, int ch)
+{
+	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+	const u32 urep = unksel ? 0x01000000 : 0x02000000;
+	u32 ctrl, timeout;
+
+	/* wait up to 1ms for any previous transaction to be done... */
+	timeout = 1000;
+	do {
+		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+		udelay(1);
+		if (!timeout--) {
+			AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+			return -EBUSY;
+		}
+	} while (ctrl & 0x03010000);
+
+	/* set some magic, and wait up to 1ms for it to appear */
+	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
+	timeout = 1000;
+	do {
+		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+		udelay(1);
+		if (!timeout--) {
+			AUX_ERR("magic wait 0x%08x\n", ctrl);
+			auxch_fini(aux, ch);
+			return -EBUSY;
+		}
+	} while ((ctrl & 0x03000000) != urep);
+
+	return 0;
+}
+
+int
+g94_aux(struct nvkm_i2c_port *base, bool retry,
+	 u8 type, u32 addr, u8 *data, u8 size)
+{
+	struct nvkm_i2c *aux = nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	u32 ctrl, stat, timeout, retries;
+	u32 xbuf[4] = {};
+	int ch = port->addr;
+	int ret, i;
+
+	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+	ret = auxch_init(aux, ch);
+	if (ret)
+		goto out;
+
+	stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
+	if (!(stat & 0x10000000)) {
+		AUX_DBG("sink not detected\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (!(type & 1)) {
+		memcpy(xbuf, data, size);
+		for (i = 0; i < 16; i += 4) {
+			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+			nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
+		}
+	}
+
+	ctrl  = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+	ctrl &= ~0x0001f0ff;
+	ctrl |= type << 12;
+	ctrl |= size - 1;
+	nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
+
+	/* (maybe) retry transaction a number of times on failure... */
+	for (retries = 0; !ret && retries < 32; retries++) {
+		/* reset, and delay a while if this is a retry */
+		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
+		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
+		if (retries)
+			udelay(400);
+
+		/* transaction request, wait up to 1ms for it to complete */
+		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
+
+		timeout = 1000;
+		do {
+			ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+			udelay(1);
+			if (!timeout--) {
+				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+				ret = -EIO;
+				goto out;
+			}
+		} while (ctrl & 0x00010000);
+		ret = 1;
+
+		/* read status, and check if transaction completed ok */
+		stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
+		if ((stat & 0x000f0000) == 0x00080000 ||
+		    (stat & 0x000f0000) == 0x00020000)
+			ret = retry ? 0 : 1;
+		if ((stat & 0x00000100))
+			ret = -ETIMEDOUT;
+		if ((stat & 0x00000e00))
+			ret = -EIO;
+
+		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+	}
+
+	if (type & 1) {
+		for (i = 0; i < 16; i += 4) {
+			xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
+			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+		}
+		memcpy(data, xbuf, size);
+	}
+
+out:
+	auxch_fini(aux, ch);
+	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
+}
+
+static const struct nvkm_i2c_func
+g94_i2c_func = {
+	.drive_scl = nv50_i2c_drive_scl,
+	.drive_sda = nv50_i2c_drive_sda,
+	.sense_scl = nv50_i2c_sense_scl,
+	.sense_sda = nv50_i2c_sense_sda,
+};
+
+static int
+g94_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 index,
+		  struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv50_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_bit_algo, &g94_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	if (info->drive >= nv50_i2c_addr_nr)
+		return -EINVAL;
+
+	port->state = 7;
+	port->addr = nv50_i2c_addr[info->drive];
+	return 0;
+}
+
+static const struct nvkm_i2c_func
+g94_aux_func = {
+	.aux       = g94_aux,
+};
+
+int
+g94_aux_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 index,
+		  struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv50_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_aux_algo, &g94_aux_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	port->base.aux = info->auxch;
+	port->addr = info->auxch;
+	return 0;
+}
+
+static struct nvkm_oclass
+g94_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = g94_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = nv50_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = g94_aux_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = _nvkm_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+g94_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0x94),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = g94_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+	.pad_s = &g94_i2c_pad_oclass,
+	.aux = 4,
+	.aux_stat = g94_aux_stat,
+	.aux_mask = g94_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
new file mode 100644
index 0000000..4d4ac66
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+static int
+gf110_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00000010);
+}
+
+static int
+gf110_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00000020);
+}
+
+static const struct nvkm_i2c_func
+gf110_i2c_func = {
+	.drive_scl = nv50_i2c_drive_scl,
+	.drive_sda = nv50_i2c_drive_sda,
+	.sense_scl = gf110_i2c_sense_scl,
+	.sense_sda = gf110_i2c_sense_sda,
+};
+
+int
+gf110_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 index,
+		    struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv50_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_bit_algo, &gf110_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	port->state = 0x00000007;
+	port->addr = 0x00d014 + (info->drive * 0x20);
+	return 0;
+}
+
+struct nvkm_oclass
+gf110_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = gf110_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = nv50_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = g94_aux_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = _nvkm_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+gf110_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0xd0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = gf110_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+	.pad_s = &g94_i2c_pad_oclass,
+	.aux = 4,
+	.aux_stat = g94_aux_stat,
+	.aux_mask = g94_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
new file mode 100644
index 0000000..e290b40
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+gf117_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0xd7),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = gf110_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+	.pad_s = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
new file mode 100644
index 0000000..1a46490
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
+{
+	u32 intr = nv_rd32(i2c, 0x00dc60);
+	u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i;
+	for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
+		if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
+		if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
+		if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
+		if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
+	}
+	nv_wr32(i2c, 0x00dc60, intr);
+}
+
+void
+gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
+{
+	u32 temp = nv_rd32(i2c, 0x00dc68), i;
+	for (i = 0; i < 8; i++) {
+		if (mask & (1 << i)) {
+			if (!(data & (1 << i))) {
+				temp &= ~(type << (i * 4));
+				continue;
+			}
+			temp |= type << (i * 4);
+		}
+	}
+	nv_wr32(i2c, 0x00dc68, temp);
+}
+
+struct nvkm_oclass *
+gk104_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0xe0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = gf110_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+	.pad_s = &g94_i2c_pad_oclass,
+	.aux = 4,
+	.aux_stat = gk104_aux_stat,
+	.aux_mask = gk104_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
new file mode 100644
index 0000000..ab64237
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nvkm_i2c *aux, int ch)
+{
+	nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nvkm_i2c *aux, int ch)
+{
+	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+	const u32 urep = unksel ? 0x01000000 : 0x02000000;
+	u32 ctrl, timeout;
+
+	/* wait up to 1ms for any previous transaction to be done... */
+	timeout = 1000;
+	do {
+		ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+		udelay(1);
+		if (!timeout--) {
+			AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+			return -EBUSY;
+		}
+	} while (ctrl & 0x03010000);
+
+	/* set some magic, and wait up to 1ms for it to appear */
+	nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
+	timeout = 1000;
+	do {
+		ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+		udelay(1);
+		if (!timeout--) {
+			AUX_ERR("magic wait 0x%08x\n", ctrl);
+			auxch_fini(aux, ch);
+			return -EBUSY;
+		}
+	} while ((ctrl & 0x03000000) != urep);
+
+	return 0;
+}
+
+int
+gm204_aux(struct nvkm_i2c_port *base, bool retry,
+	 u8 type, u32 addr, u8 *data, u8 size)
+{
+	struct nvkm_i2c *aux = nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	u32 ctrl, stat, timeout, retries;
+	u32 xbuf[4] = {};
+	int ch = port->addr;
+	int ret, i;
+
+	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+	ret = auxch_init(aux, ch);
+	if (ret)
+		goto out;
+
+	stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
+	if (!(stat & 0x10000000)) {
+		AUX_DBG("sink not detected\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (!(type & 1)) {
+		memcpy(xbuf, data, size);
+		for (i = 0; i < 16; i += 4) {
+			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+			nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
+		}
+	}
+
+	ctrl  = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+	ctrl &= ~0x0001f0ff;
+	ctrl |= type << 12;
+	ctrl |= size - 1;
+	nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
+
+	/* (maybe) retry transaction a number of times on failure... */
+	for (retries = 0; !ret && retries < 32; retries++) {
+		/* reset, and delay a while if this is a retry */
+		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
+		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
+		if (retries)
+			udelay(400);
+
+		/* transaction request, wait up to 1ms for it to complete */
+		nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
+
+		timeout = 1000;
+		do {
+			ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+			udelay(1);
+			if (!timeout--) {
+				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+				ret = -EIO;
+				goto out;
+			}
+		} while (ctrl & 0x00010000);
+		ret = 1;
+
+		/* read status, and check if transaction completed ok */
+		stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
+		if ((stat & 0x000f0000) == 0x00080000 ||
+		    (stat & 0x000f0000) == 0x00020000)
+			ret = retry ? 0 : 1;
+		if ((stat & 0x00000100))
+			ret = -ETIMEDOUT;
+		if ((stat & 0x00000e00))
+			ret = -EIO;
+
+		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+	}
+
+	if (type & 1) {
+		for (i = 0; i < 16; i += 4) {
+			xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
+			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+		}
+		memcpy(data, xbuf, size);
+	}
+
+out:
+	auxch_fini(aux, ch);
+	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
+}
+
+static const struct nvkm_i2c_func
+gm204_aux_func = {
+	.aux       = gm204_aux,
+};
+
+int
+gm204_aux_port_ctor(struct nvkm_object *parent,
+		    struct nvkm_object *engine,
+		    struct nvkm_oclass *oclass, void *data, u32 index,
+		    struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv50_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_aux_algo, &gm204_aux_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	port->base.aux = info->auxch;
+	port->addr = info->auxch;
+	return 0;
+}
+
+struct nvkm_oclass
+gm204_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = gf110_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = nv50_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = gm204_aux_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = _nvkm_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+gm204_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0x24),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = gm204_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+	.pad_s = &gm204_i2c_pad_oclass,
+	.aux = 8,
+	.aux_stat = gk104_aux_stat,
+	.aux_mask = gk104_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
new file mode 100644
index 0000000..4cdf1c4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/vga.h>
+
+struct nv04_i2c_priv {
+	struct nvkm_i2c base;
+};
+
+struct nv04_i2c_port {
+	struct nvkm_i2c_port base;
+	u8 drive;
+	u8 sense;
+};
+
+static void
+nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+	struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv04_i2c_port *port = (void *)base;
+	u8 val = nv_rdvgac(priv, 0, port->drive);
+	if (state) val |= 0x20;
+	else	   val &= 0xdf;
+	nv_wrvgac(priv, 0, port->drive, val | 0x01);
+}
+
+static void
+nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+	struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv04_i2c_port *port = (void *)base;
+	u8 val = nv_rdvgac(priv, 0, port->drive);
+	if (state) val |= 0x10;
+	else	   val &= 0xef;
+	nv_wrvgac(priv, 0, port->drive, val | 0x01);
+}
+
+static int
+nv04_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+	struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv04_i2c_port *port = (void *)base;
+	return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
+}
+
+static int
+nv04_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+	struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv04_i2c_port *port = (void *)base;
+	return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
+}
+
+static const struct nvkm_i2c_func
+nv04_i2c_func = {
+	.drive_scl = nv04_i2c_drive_scl,
+	.drive_sda = nv04_i2c_drive_sda,
+	.sense_scl = nv04_i2c_sense_scl,
+	.sense_sda = nv04_i2c_sense_sda,
+};
+
+static int
+nv04_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 index,
+		   struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv04_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_bit_algo, &nv04_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	port->drive = info->drive;
+	port->sense = info->sense;
+	return 0;
+}
+
+static struct nvkm_oclass
+nv04_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = nv04_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = _nvkm_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+nv04_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = nv04_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
new file mode 100644
index 0000000..046fe5e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/vga.h>
+
+struct nv4e_i2c_priv {
+	struct nvkm_i2c base;
+};
+
+struct nv4e_i2c_port {
+	struct nvkm_i2c_port base;
+	u32 addr;
+};
+
+static void
+nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+	struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv4e_i2c_port *port = (void *)base;
+	nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
+}
+
+static void
+nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+	struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv4e_i2c_port *port = (void *)base;
+	nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
+}
+
+static int
+nv4e_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+	struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv4e_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00040000);
+}
+
+static int
+nv4e_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+	struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv4e_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00080000);
+}
+
+static const struct nvkm_i2c_func
+nv4e_i2c_func = {
+	.drive_scl = nv4e_i2c_drive_scl,
+	.drive_sda = nv4e_i2c_drive_sda,
+	.sense_scl = nv4e_i2c_sense_scl,
+	.sense_sda = nv4e_i2c_sense_sda,
+};
+
+static int
+nv4e_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 index,
+		   struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv4e_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_bit_algo, &nv4e_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	port->addr = 0x600800 + info->drive;
+	return 0;
+}
+
+static struct nvkm_oclass
+nv4e_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = nv4e_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = _nvkm_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+nv4e_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0x4e),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = nv4e_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
new file mode 100644
index 0000000..fba5b26
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	if (state) port->state |= 0x01;
+	else	   port->state &= 0xfe;
+	nv_wr32(priv, port->addr, port->state);
+}
+
+void
+nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	if (state) port->state |= 0x02;
+	else	   port->state &= 0xfd;
+	nv_wr32(priv, port->addr, port->state);
+}
+
+int
+nv50_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00000001);
+}
+
+int
+nv50_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+	struct nv50_i2c_port *port = (void *)base;
+	return !!(nv_rd32(priv, port->addr) & 0x00000002);
+}
+
+static const struct nvkm_i2c_func
+nv50_i2c_func = {
+	.drive_scl = nv50_i2c_drive_scl,
+	.drive_sda = nv50_i2c_drive_sda,
+	.sense_scl = nv50_i2c_sense_scl,
+	.sense_sda = nv50_i2c_sense_sda,
+};
+
+const u32 nv50_i2c_addr[] = {
+	0x00e138, 0x00e150, 0x00e168, 0x00e180,
+	0x00e254, 0x00e274, 0x00e764, 0x00e780,
+	0x00e79c, 0x00e7b8
+};
+const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
+
+static int
+nv50_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 index,
+		   struct nvkm_object **pobject)
+{
+	struct dcb_i2c_entry *info = data;
+	struct nv50_i2c_port *port;
+	int ret;
+
+	ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+				   &nvkm_i2c_bit_algo, &nv50_i2c_func, &port);
+	*pobject = nv_object(port);
+	if (ret)
+		return ret;
+
+	if (info->drive >= nv50_i2c_addr_nr)
+		return -EINVAL;
+
+	port->state = 0x00000007;
+	port->addr = nv50_i2c_addr[info->drive];
+	return 0;
+}
+
+int
+nv50_i2c_port_init(struct nvkm_object *object)
+{
+	struct nv50_i2c_priv *priv = (void *)nvkm_i2c(object);
+	struct nv50_i2c_port *port = (void *)object;
+	nv_wr32(priv, port->addr, port->state);
+	return nvkm_i2c_port_init(&port->base);
+}
+
+static struct nvkm_oclass
+nv50_i2c_sclass[] = {
+	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+	  .ofuncs = &(struct nvkm_ofuncs) {
+		  .ctor = nv50_i2c_port_ctor,
+		  .dtor = _nvkm_i2c_port_dtor,
+		  .init = nv50_i2c_port_init,
+		  .fini = _nvkm_i2c_port_fini,
+	  },
+	},
+	{}
+};
+
+struct nvkm_oclass *
+nv50_i2c_oclass = &(struct nvkm_i2c_impl) {
+	.base.handle = NV_SUBDEV(I2C, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_ctor,
+		.dtor = _nvkm_i2c_dtor,
+		.init = _nvkm_i2c_init,
+		.fini = _nvkm_i2c_fini,
+	},
+	.sclass = nv50_i2c_sclass,
+	.pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
new file mode 100644
index 0000000..b3139e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
@@ -0,0 +1,32 @@
+#ifndef __NV50_I2C_H__
+#define __NV50_I2C_H__
+#include "priv.h"
+
+struct nv50_i2c_priv {
+	struct nvkm_i2c base;
+};
+
+struct nv50_i2c_port {
+	struct nvkm_i2c_port base;
+	u32 addr;
+	u32 state;
+};
+
+extern const u32 nv50_i2c_addr[];
+extern const int nv50_i2c_addr_nr;
+int  nv50_i2c_port_init(struct nvkm_object *);
+int  nv50_i2c_sense_scl(struct nvkm_i2c_port *);
+int  nv50_i2c_sense_sda(struct nvkm_i2c_port *);
+void nv50_i2c_drive_scl(struct nvkm_i2c_port *, int state);
+void nv50_i2c_drive_sda(struct nvkm_i2c_port *, int state);
+
+int  g94_aux_port_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+void g94_i2c_acquire(struct nvkm_i2c_port *);
+void g94_i2c_release(struct nvkm_i2c_port *);
+
+int  gf110_i2c_port_ctor(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, void *, u32,
+			struct nvkm_object **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
new file mode 100644
index 0000000..a242eeb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+int
+_nvkm_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_i2c_pad *pad = (void *)object;
+	DBG("-> NULL\n");
+	pad->port = NULL;
+	return nvkm_object_fini(&pad->base, suspend);
+}
+
+int
+_nvkm_i2c_pad_init(struct nvkm_object *object)
+{
+	struct nvkm_i2c_pad *pad = (void *)object;
+	DBG("-> PORT:%02x\n", pad->next->index);
+	pad->port = pad->next;
+	return nvkm_object_init(&pad->base);
+}
+
+int
+nvkm_i2c_pad_create_(struct nvkm_object *parent,
+		     struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, int index,
+		     int size, void **pobject)
+{
+	struct nvkm_i2c *i2c = nvkm_i2c(parent);
+	struct nvkm_i2c_port *port;
+	struct nvkm_i2c_pad *pad;
+	int ret;
+
+	list_for_each_entry(port, &i2c->ports, head) {
+		pad = nvkm_i2c_pad(port);
+		if (pad->index == index) {
+			atomic_inc(&nv_object(pad)->refcount);
+			*pobject = pad;
+			return 1;
+		}
+	}
+
+	ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject);
+	pad = *pobject;
+	if (ret)
+		return ret;
+
+	pad->index = index;
+	return 0;
+}
+
+int
+_nvkm_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 index,
+		   struct nvkm_object **pobject)
+{
+	struct nvkm_i2c_pad *pad;
+	int ret;
+	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+	*pobject = nv_object(pad);
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
new file mode 100644
index 0000000..f3422cc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
@@ -0,0 +1,56 @@
+#ifndef __NVKM_I2C_PAD_H__
+#define __NVKM_I2C_PAD_H__
+#include "priv.h"
+
+struct nvkm_i2c_pad {
+	struct nvkm_object base;
+	int index;
+	struct nvkm_i2c_port *port;
+	struct nvkm_i2c_port *next;
+};
+
+static inline struct nvkm_i2c_pad *
+nvkm_i2c_pad(struct nvkm_i2c_port *port)
+{
+	struct nvkm_object *pad = nv_object(port);
+	while (!nv_iclass(pad->parent, NV_SUBDEV_CLASS))
+		pad = pad->parent;
+	return (void *)pad;
+}
+
+#define nvkm_i2c_pad_create(p,e,o,i,d)                                         \
+	nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
+#define nvkm_i2c_pad_destroy(p) ({                                             \
+	struct nvkm_i2c_pad *_p = (p);                                         \
+	_nvkm_i2c_pad_dtor(nv_object(_p));                                     \
+})
+#define nvkm_i2c_pad_init(p) ({                                                \
+	struct nvkm_i2c_pad *_p = (p);                                         \
+	_nvkm_i2c_pad_init(nv_object(_p));                                     \
+})
+#define nvkm_i2c_pad_fini(p,s) ({                                              \
+	struct nvkm_i2c_pad *_p = (p);                                         \
+	_nvkm_i2c_pad_fini(nv_object(_p), (s));                                \
+})
+
+int nvkm_i2c_pad_create_(struct nvkm_object *, struct nvkm_object *,
+			 struct nvkm_oclass *, int index, int, void **);
+
+int _nvkm_i2c_pad_ctor(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, void *, u32,
+		       struct nvkm_object **);
+#define _nvkm_i2c_pad_dtor nvkm_object_destroy
+int _nvkm_i2c_pad_init(struct nvkm_object *);
+int _nvkm_i2c_pad_fini(struct nvkm_object *, bool);
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+	struct nvkm_i2c_pad *_pad = (void *)pad;                               \
+	nv_##l(_pad, "PAD:%c:%02x: "f,                                         \
+	       _pad->index >= 0x100 ? 'X' : 'S',                               \
+	       _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
new file mode 100644
index 0000000..e9832f7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct g94_i2c_pad {
+	struct nvkm_i2c_pad base;
+	int addr;
+};
+
+static int
+g94_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+	struct g94_i2c_pad *pad = (void *)object;
+	nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001);
+	return nvkm_i2c_pad_fini(&pad->base, suspend);
+}
+
+static int
+g94_i2c_pad_init(struct nvkm_object *object)
+{
+	struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+	struct g94_i2c_pad *pad = (void *)object;
+
+	switch (nv_oclass(pad->base.next)->handle) {
+	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
+		nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002);
+		break;
+	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
+	default:
+		nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001);
+		break;
+	}
+
+	nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000);
+	return nvkm_i2c_pad_init(&pad->base);
+}
+
+static int
+g94_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 index,
+		 struct nvkm_object **pobject)
+{
+	struct g94_i2c_pad *pad;
+	int ret;
+
+	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+	*pobject = nv_object(pad);
+	if (ret)
+		return ret;
+
+	pad->addr = index * 0x50;;
+	return 0;
+}
+
+struct nvkm_oclass
+g94_i2c_pad_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g94_i2c_pad_ctor,
+		.dtor = _nvkm_i2c_pad_dtor,
+		.init = g94_i2c_pad_init,
+		.fini = g94_i2c_pad_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
new file mode 100644
index 0000000..be59040
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct gm204_i2c_pad {
+	struct nvkm_i2c_pad base;
+	int addr;
+};
+
+static int
+gm204_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+	struct gm204_i2c_pad *pad = (void *)object;
+	nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001);
+	return nvkm_i2c_pad_fini(&pad->base, suspend);
+}
+
+static int
+gm204_i2c_pad_init(struct nvkm_object *object)
+{
+	struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+	struct gm204_i2c_pad *pad = (void *)object;
+
+	switch (nv_oclass(pad->base.next)->handle) {
+	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
+		nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002);
+		break;
+	case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
+	default:
+		nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001);
+		break;
+	}
+
+	nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000);
+	return nvkm_i2c_pad_init(&pad->base);
+}
+
+static int
+gm204_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, void *data, u32 index,
+		   struct nvkm_object **pobject)
+{
+	struct gm204_i2c_pad *pad;
+	int ret;
+
+	ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+	*pobject = nv_object(pad);
+	if (ret)
+		return ret;
+
+	pad->addr = index * 0x50;;
+	return 0;
+}
+
+struct nvkm_oclass
+gm204_i2c_pad_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm204_i2c_pad_ctor,
+		.dtor = _nvkm_i2c_pad_dtor,
+		.init = gm204_i2c_pad_init,
+		.fini = gm204_i2c_pad_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
new file mode 100644
index 0000000..22c7daa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct nvkm_oclass
+nv04_i2c_pad_oclass = {
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_i2c_pad_ctor,
+		.dtor = _nvkm_i2c_pad_dtor,
+		.init = _nvkm_i2c_pad_init,
+		.fini = _nvkm_i2c_pad_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
new file mode 100644
index 0000000..586f53d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
@@ -0,0 +1,13 @@
+#ifndef __NVKM_I2C_PORT_H__
+#define __NVKM_I2C_PORT_H__
+#include "priv.h"
+
+#ifndef MSG
+#define MSG(l,f,a...) do {                                                     \
+	struct nvkm_i2c_port *_port = (void *)port;                         \
+	nv_##l(_port, "PORT:%02x: "f, _port->index, ##a);                      \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
new file mode 100644
index 0000000..6586e15
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
@@ -0,0 +1,87 @@
+#ifndef __NVKM_I2C_PRIV_H__
+#define __NVKM_I2C_PRIV_H__
+#include <subdev/i2c.h>
+
+extern struct nvkm_oclass nv04_i2c_pad_oclass;
+extern struct nvkm_oclass g94_i2c_pad_oclass;
+extern struct nvkm_oclass gm204_i2c_pad_oclass;
+
+#define nvkm_i2c_port_create(p,e,o,i,a,f,d)                                 \
+	nvkm_i2c_port_create_((p), (e), (o), (i), (a), (f),                 \
+				 sizeof(**d), (void **)d)
+#define nvkm_i2c_port_destroy(p) ({                                         \
+	struct nvkm_i2c_port *port = (p);                                   \
+	_nvkm_i2c_port_dtor(nv_object(i2c));                                \
+})
+#define nvkm_i2c_port_init(p)                                               \
+	nvkm_object_init(&(p)->base)
+#define nvkm_i2c_port_fini(p,s)                                             \
+	nvkm_object_fini(&(p)->base, (s))
+
+int nvkm_i2c_port_create_(struct nvkm_object *, struct nvkm_object *,
+			     struct nvkm_oclass *, u8,
+			     const struct i2c_algorithm *,
+			     const struct nvkm_i2c_func *,
+			     int, void **);
+void _nvkm_i2c_port_dtor(struct nvkm_object *);
+#define _nvkm_i2c_port_init nvkm_object_init
+int  _nvkm_i2c_port_fini(struct nvkm_object *, bool);
+
+#define nvkm_i2c_create(p,e,o,d)                                            \
+	nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_i2c_destroy(p) ({                                              \
+	struct nvkm_i2c *i2c = (p);                                         \
+	_nvkm_i2c_dtor(nv_object(i2c));                                     \
+})
+#define nvkm_i2c_init(p) ({                                                 \
+	struct nvkm_i2c *i2c = (p);                                         \
+	_nvkm_i2c_init(nv_object(i2c));                                     \
+})
+#define nvkm_i2c_fini(p,s) ({                                               \
+	struct nvkm_i2c *i2c = (p);                                         \
+	_nvkm_i2c_fini(nv_object(i2c), (s));                                \
+})
+
+int nvkm_i2c_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, int, void **);
+int  _nvkm_i2c_ctor(struct nvkm_object *, struct nvkm_object *,
+		       struct nvkm_oclass *, void *, u32,
+		       struct nvkm_object **);
+void _nvkm_i2c_dtor(struct nvkm_object *);
+int  _nvkm_i2c_init(struct nvkm_object *);
+int  _nvkm_i2c_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass nvkm_anx9805_sclass[];
+extern struct nvkm_oclass gf110_i2c_sclass[];
+
+extern const struct i2c_algorithm nvkm_i2c_bit_algo;
+extern const struct i2c_algorithm nvkm_i2c_aux_algo;
+
+struct nvkm_i2c_impl {
+	struct nvkm_oclass base;
+
+	/* supported i2c port classes */
+	struct nvkm_oclass *sclass;
+	struct nvkm_oclass *pad_x;
+	struct nvkm_oclass *pad_s;
+
+	/* number of native dp aux channels present */
+	int aux;
+
+	/* read and ack pending interrupts, returning only data
+	 * for ports that have not been masked off, while still
+	 * performing the ack for anything that was pending.
+	 */
+	void (*aux_stat)(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+
+	/* mask on/off interrupt types for a given set of auxch
+	 */
+	void (*aux_mask)(struct nvkm_i2c *, u32, u32, u32);
+};
+
+void g94_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+void g94_aux_mask(struct nvkm_i2c *, u32, u32, u32);
+
+void gk104_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+void gk104_aux_mask(struct nvkm_i2c *, u32, u32, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
new file mode 100644
index 0000000..a0b12d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/ibus/gf100.o
+nvkm-y += nvkm/subdev/ibus/gk104.o
+nvkm-y += nvkm/subdev/ibus/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
new file mode 100644
index 0000000..8e578f8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/ibus.h>
+
+struct gf100_ibus_priv {
+	struct nvkm_ibus base;
+};
+
+static void
+gf100_ibus_intr_hub(struct gf100_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400));
+	u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400));
+	u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400));
+	nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr_rop(struct gf100_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400));
+	u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400));
+	u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400));
+	nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr_gpc(struct gf100_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400));
+	u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400));
+	u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400));
+	nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr(struct nvkm_subdev *subdev)
+{
+	struct gf100_ibus_priv *priv = (void *)subdev;
+	u32 intr0 = nv_rd32(priv, 0x121c58);
+	u32 intr1 = nv_rd32(priv, 0x121c5c);
+	u32 hubnr = nv_rd32(priv, 0x121c70);
+	u32 ropnr = nv_rd32(priv, 0x121c74);
+	u32 gpcnr = nv_rd32(priv, 0x121c78);
+	u32 i;
+
+	for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
+		u32 stat = 0x00000100 << i;
+		if (intr0 & stat) {
+			gf100_ibus_intr_hub(priv, i);
+			intr0 &= ~stat;
+		}
+	}
+
+	for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
+		u32 stat = 0x00010000 << i;
+		if (intr0 & stat) {
+			gf100_ibus_intr_rop(priv, i);
+			intr0 &= ~stat;
+		}
+	}
+
+	for (i = 0; intr1 && i < gpcnr; i++) {
+		u32 stat = 0x00000001 << i;
+		if (intr1 & stat) {
+			gf100_ibus_intr_gpc(priv, i);
+			intr1 &= ~stat;
+		}
+	}
+}
+
+static int
+gf100_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gf100_ibus_priv *priv;
+	int ret;
+
+	ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->intr = gf100_ibus_intr;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_ibus_oclass = {
+	.handle = NV_SUBDEV(IBUS, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ibus_ctor,
+		.dtor = _nvkm_ibus_dtor,
+		.init = _nvkm_ibus_init,
+		.fini = _nvkm_ibus_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
new file mode 100644
index 0000000..7b6e9a6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/ibus.h>
+
+struct gk104_ibus_priv {
+	struct nvkm_ibus base;
+};
+
+static void
+gk104_ibus_intr_hub(struct gk104_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800));
+	u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800));
+	u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800));
+	nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr_rop(struct gk104_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800));
+	u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800));
+	u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800));
+	nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr_gpc(struct gk104_ibus_priv *priv, int i)
+{
+	u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800));
+	u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800));
+	u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800));
+	nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+	nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr(struct nvkm_subdev *subdev)
+{
+	struct gk104_ibus_priv *priv = (void *)subdev;
+	u32 intr0 = nv_rd32(priv, 0x120058);
+	u32 intr1 = nv_rd32(priv, 0x12005c);
+	u32 hubnr = nv_rd32(priv, 0x120070);
+	u32 ropnr = nv_rd32(priv, 0x120074);
+	u32 gpcnr = nv_rd32(priv, 0x120078);
+	u32 i;
+
+	for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
+		u32 stat = 0x00000100 << i;
+		if (intr0 & stat) {
+			gk104_ibus_intr_hub(priv, i);
+			intr0 &= ~stat;
+		}
+	}
+
+	for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
+		u32 stat = 0x00010000 << i;
+		if (intr0 & stat) {
+			gk104_ibus_intr_rop(priv, i);
+			intr0 &= ~stat;
+		}
+	}
+
+	for (i = 0; intr1 && i < gpcnr; i++) {
+		u32 stat = 0x00000001 << i;
+		if (intr1 & stat) {
+			gk104_ibus_intr_gpc(priv, i);
+			intr1 &= ~stat;
+		}
+	}
+}
+
+static int
+gk104_ibus_init(struct nvkm_object *object)
+{
+	struct gk104_ibus_priv *priv = (void *)object;
+	int ret = nvkm_ibus_init(&priv->base);
+	if (ret == 0) {
+		nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000);
+		nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200);
+		nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800);
+		nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100);
+		nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff);
+		nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200);
+		nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880);
+	}
+	return ret;
+}
+
+static int
+gk104_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gk104_ibus_priv *priv;
+	int ret;
+
+	ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->intr = gk104_ibus_intr;
+	return 0;
+}
+
+struct nvkm_oclass
+gk104_ibus_oclass = {
+	.handle = NV_SUBDEV(IBUS, 0xe0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk104_ibus_ctor,
+		.dtor = _nvkm_ibus_dtor,
+		.init = gk104_ibus_init,
+		.fini = _nvkm_ibus_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
new file mode 100644
index 0000000..c0fdb89
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 <subdev/ibus.h>
+#include <subdev/timer.h>
+
+struct gk20a_ibus_priv {
+	struct nvkm_ibus base;
+};
+
+static void
+gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
+{
+	nv_mask(priv, 0x137250, 0x3f, 0);
+
+	nv_mask(priv, 0x000200, 0x20, 0);
+	usleep_range(20, 30);
+	nv_mask(priv, 0x000200, 0x20, 0x20);
+
+	nv_wr32(priv, 0x12004c, 0x4);
+	nv_wr32(priv, 0x122204, 0x2);
+	nv_rd32(priv, 0x122204);
+}
+
+static void
+gk20a_ibus_intr(struct nvkm_subdev *subdev)
+{
+	struct gk20a_ibus_priv *priv = (void *)subdev;
+	u32 status0 = nv_rd32(priv, 0x120058);
+
+	if (status0 & 0x7) {
+		nv_debug(priv, "resetting priv ring\n");
+		gk20a_ibus_init_priv_ring(priv);
+	}
+
+	/* Acknowledge interrupt */
+	nv_mask(priv, 0x12004c, 0x2, 0x2);
+
+	if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00))
+		nv_warn(priv, "timeout waiting for ringmaster ack\n");
+}
+
+static int
+gk20a_ibus_init(struct nvkm_object *object)
+{
+	struct gk20a_ibus_priv *priv = (void *)object;
+	int ret;
+
+	ret = _nvkm_ibus_init(object);
+	if (ret)
+		return ret;
+
+	gk20a_ibus_init_priv_ring(priv);
+
+	return 0;
+}
+
+static int
+gk20a_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gk20a_ibus_priv *priv;
+	int ret;
+
+	ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->intr = gk20a_ibus_intr;
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_ibus_oclass = {
+	.handle = NV_SUBDEV(IBUS, 0xea),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_ibus_ctor,
+		.dtor = _nvkm_ibus_dtor,
+		.init = gk20a_ibus_init,
+		.fini = _nvkm_ibus_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
new file mode 100644
index 0000000..e6f35ab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/instmem/base.o
+nvkm-y += nvkm/subdev/instmem/nv04.o
+nvkm-y += nvkm/subdev/instmem/nv40.o
+nvkm-y += nvkm/subdev/instmem/nv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
new file mode 100644
index 0000000..d16358c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/engine.h>
+
+/******************************************************************************
+ * instmem object base implementation
+ *****************************************************************************/
+
+void
+_nvkm_instobj_dtor(struct nvkm_object *object)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(object);
+	struct nvkm_instobj *iobj = (void *)object;
+
+	mutex_lock(&nv_subdev(imem)->mutex);
+	list_del(&iobj->head);
+	mutex_unlock(&nv_subdev(imem)->mutex);
+
+	return nvkm_object_destroy(&iobj->base);
+}
+
+int
+nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_instmem *imem = nvkm_instmem(parent);
+	struct nvkm_instobj *iobj;
+	int ret;
+
+	ret = nvkm_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS,
+				  length, pobject);
+	iobj = *pobject;
+	if (ret)
+		return ret;
+
+	mutex_lock(&imem->base.mutex);
+	list_add(&iobj->head, &imem->list);
+	mutex_unlock(&imem->base.mutex);
+	return 0;
+}
+
+/******************************************************************************
+ * instmem subdev base implementation
+ *****************************************************************************/
+
+static int
+nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent,
+		   u32 size, u32 align, struct nvkm_object **pobject)
+{
+	struct nvkm_instmem_impl *impl = (void *)imem->base.object.oclass;
+	struct nvkm_instobj_args args = { .size = size, .align = align };
+	return nvkm_object_ctor(parent, &parent->engine->subdev.object,
+				impl->instobj, &args, sizeof(args), pobject);
+}
+
+int
+_nvkm_instmem_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_instmem *imem = (void *)object;
+	struct nvkm_instobj *iobj;
+	int i, ret = 0;
+
+	if (suspend) {
+		mutex_lock(&imem->base.mutex);
+		list_for_each_entry(iobj, &imem->list, head) {
+			iobj->suspend = vmalloc(iobj->size);
+			if (!iobj->suspend) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			for (i = 0; i < iobj->size; i += 4)
+				iobj->suspend[i / 4] = nv_ro32(iobj, i);
+		}
+		mutex_unlock(&imem->base.mutex);
+		if (ret)
+			return ret;
+	}
+
+	return nvkm_subdev_fini(&imem->base, suspend);
+}
+
+int
+_nvkm_instmem_init(struct nvkm_object *object)
+{
+	struct nvkm_instmem *imem = (void *)object;
+	struct nvkm_instobj *iobj;
+	int ret, i;
+
+	ret = nvkm_subdev_init(&imem->base);
+	if (ret)
+		return ret;
+
+	mutex_lock(&imem->base.mutex);
+	list_for_each_entry(iobj, &imem->list, head) {
+		if (iobj->suspend) {
+			for (i = 0; i < iobj->size; i += 4)
+				nv_wo32(iobj, i, iobj->suspend[i / 4]);
+			vfree(iobj->suspend);
+			iobj->suspend = NULL;
+		}
+	}
+	mutex_unlock(&imem->base.mutex);
+	return 0;
+}
+
+int
+nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		     struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_instmem *imem;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "INSTMEM",
+				  "instmem", length, pobject);
+	imem = *pobject;
+	if (ret)
+		return ret;
+
+	INIT_LIST_HEAD(&imem->list);
+	imem->alloc = nvkm_instmem_alloc;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
new file mode 100644
index 0000000..80614f1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/ramht.h>
+
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
+
+static u32
+nv04_instobj_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+	struct nv04_instobj_priv *node = (void *)object;
+	return nv_ro32(priv, node->mem->offset + addr);
+}
+
+static void
+nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+	struct nv04_instobj_priv *node = (void *)object;
+	nv_wo32(priv, node->mem->offset + addr, data);
+}
+
+static void
+nv04_instobj_dtor(struct nvkm_object *object)
+{
+	struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+	struct nv04_instobj_priv *node = (void *)object;
+	nvkm_mm_free(&priv->heap, &node->mem);
+	nvkm_instobj_destroy(&node->base);
+}
+
+static int
+nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent);
+	struct nv04_instobj_priv *node;
+	struct nvkm_instobj_args *args = data;
+	int ret;
+
+	if (!args->align)
+		args->align = 1;
+
+	ret = nvkm_instobj_create(parent, engine, oclass, &node);
+	*pobject = nv_object(node);
+	if (ret)
+		return ret;
+
+	ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size,
+			   args->align, &node->mem);
+	if (ret)
+		return ret;
+
+	node->base.addr = node->mem->offset;
+	node->base.size = node->mem->length;
+	return 0;
+}
+
+struct nvkm_instobj_impl
+nv04_instobj_oclass = {
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_instobj_ctor,
+		.dtor = nv04_instobj_dtor,
+		.init = _nvkm_instobj_init,
+		.fini = _nvkm_instobj_fini,
+		.rd32 = nv04_instobj_rd32,
+		.wr32 = nv04_instobj_wr32,
+	},
+};
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv04_instmem_rd32(struct nvkm_object *object, u64 addr)
+{
+	return nv_rd32(object, 0x700000 + addr);
+}
+
+static void
+nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	return nv_wr32(object, 0x700000 + addr, data);
+}
+
+void
+nv04_instmem_dtor(struct nvkm_object *object)
+{
+	struct nv04_instmem_priv *priv = (void *)object;
+	nvkm_gpuobj_ref(NULL, &priv->ramfc);
+	nvkm_gpuobj_ref(NULL, &priv->ramro);
+	nvkm_ramht_ref(NULL, &priv->ramht);
+	nvkm_gpuobj_ref(NULL, &priv->vbios);
+	nvkm_mm_fini(&priv->heap);
+	if (priv->iomem)
+		iounmap(priv->iomem);
+	nvkm_instmem_destroy(&priv->base);
+}
+
+static int
+nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nv04_instmem_priv *priv;
+	int ret;
+
+	ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	/* PRAMIN aperture maps over the end of VRAM, reserve it */
+	priv->base.reserved = 512 * 1024;
+
+	ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1);
+	if (ret)
+		return ret;
+
+	/* 0x00000-0x10000: reserve for probable vbios image */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
+			      &priv->vbios);
+	if (ret)
+		return ret;
+
+	/* 0x10000-0x18000: reserve for RAMHT */
+	ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
+	if (ret)
+		return ret;
+
+	/* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00800, 0,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
+	if (ret)
+		return ret;
+
+	/* 0x18800-0x18a00: reserve for RAMRO */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0,
+			      &priv->ramro);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_instmem_oclass = &(struct nvkm_instmem_impl) {
+	.base.handle = NV_SUBDEV(INSTMEM, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_instmem_ctor,
+		.dtor = nv04_instmem_dtor,
+		.init = _nvkm_instmem_init,
+		.fini = _nvkm_instmem_fini,
+		.rd32 = nv04_instmem_rd32,
+		.wr32 = nv04_instmem_wr32,
+	},
+	.instobj = &nv04_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h
new file mode 100644
index 0000000..42b6c92
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h
@@ -0,0 +1,36 @@
+#ifndef __NV04_INSTMEM_H__
+#define __NV04_INSTMEM_H__
+#include "priv.h"
+
+#include <core/mm.h>
+
+extern struct nvkm_instobj_impl nv04_instobj_oclass;
+
+struct nv04_instmem_priv {
+	struct nvkm_instmem base;
+
+	void __iomem *iomem;
+	struct nvkm_mm heap;
+
+	struct nvkm_gpuobj *vbios;
+	struct nvkm_ramht  *ramht;
+	struct nvkm_gpuobj *ramro;
+	struct nvkm_gpuobj *ramfc;
+};
+
+static inline struct nv04_instmem_priv *
+nv04_instmem(void *obj)
+{
+	return (void *)nvkm_instmem(obj);
+}
+
+struct nv04_instobj_priv {
+	struct nvkm_instobj base;
+	struct nvkm_mm_node *mem;
+};
+
+void nv04_instmem_dtor(struct nvkm_object *);
+
+int nv04_instmem_alloc(struct nvkm_instmem *, struct nvkm_object *,
+		       u32 size, u32 align, struct nvkm_object **pobject);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c
new file mode 100644
index 0000000..b42b858
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/ramht.h>
+#include <engine/gr/nv40.h>
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv40_instmem_rd32(struct nvkm_object *object, u64 addr)
+{
+	struct nv04_instmem_priv *priv = (void *)object;
+	return ioread32_native(priv->iomem + addr);
+}
+
+static void
+nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+	struct nv04_instmem_priv *priv = (void *)object;
+	iowrite32_native(data, priv->iomem + addr);
+}
+
+static int
+nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nv04_instmem_priv *priv;
+	int ret, bar, vs;
+
+	ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	/* map bar */
+	if (nv_device_resource_len(device, 2))
+		bar = 2;
+	else
+		bar = 3;
+
+	priv->iomem = ioremap(nv_device_resource_start(device, bar),
+			      nv_device_resource_len(device, bar));
+	if (!priv->iomem) {
+		nv_error(priv, "unable to map PRAMIN BAR\n");
+		return -EFAULT;
+	}
+
+	/* PRAMIN aperture maps over the end of vram, reserve enough space
+	 * to fit graphics contexts for every channel, the magics come
+	 * from engine/gr/nv40.c
+	 */
+	vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8);
+	if      (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs;
+	else if (device->chipset  < 0x43) priv->base.reserved = 0x4f00 * vs;
+	else if (nv44_gr_class(priv))  priv->base.reserved = 0x4980 * vs;
+	else				  priv->base.reserved = 0x4a40 * vs;
+	priv->base.reserved += 16 * 1024;
+	priv->base.reserved *= 32;		/* per-channel */
+	priv->base.reserved += 512 * 1024;	/* pci(e)gart table */
+	priv->base.reserved += 512 * 1024;	/* object storage */
+
+	priv->base.reserved = round_up(priv->base.reserved, 4096);
+
+	ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1);
+	if (ret)
+		return ret;
+
+	/* 0x00000-0x10000: reserve for probable vbios image */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
+			      &priv->vbios);
+	if (ret)
+		return ret;
+
+	/* 0x10000-0x18000: reserve for RAMHT */
+	ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
+	if (ret)
+		return ret;
+
+	/* 0x18000-0x18200: reserve for RAMRO
+	 * 0x18200-0x20000: padding
+	 */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0,
+			      &priv->ramro);
+	if (ret)
+		return ret;
+
+	/* 0x20000-0x21000: reserve for RAMFC
+	 * 0x21000-0x40000: padding and some unknown crap
+	 */
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
+			      NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nv40_instmem_oclass = &(struct nvkm_instmem_impl) {
+	.base.handle = NV_SUBDEV(INSTMEM, 0x40),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_instmem_ctor,
+		.dtor = nv04_instmem_dtor,
+		.init = _nvkm_instmem_init,
+		.fini = _nvkm_instmem_fini,
+		.rd32 = nv40_instmem_rd32,
+		.wr32 = nv40_instmem_wr32,
+	},
+	.instobj = &nv04_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
new file mode 100644
index 0000000..8404143
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/fb.h>
+
+struct nv50_instmem_priv {
+	struct nvkm_instmem base;
+	spinlock_t lock;
+	u64 addr;
+};
+
+struct nv50_instobj_priv {
+	struct nvkm_instobj base;
+	struct nvkm_mem *mem;
+};
+
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
+
+static u32
+nv50_instobj_rd32(struct nvkm_object *object, u64 offset)
+{
+	struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object);
+	struct nv50_instobj_priv *node = (void *)object;
+	unsigned long flags;
+	u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+	u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+	u32 data;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (unlikely(priv->addr != base)) {
+		nv_wr32(priv, 0x001700, base >> 16);
+		priv->addr = base;
+	}
+	data = nv_rd32(priv, 0x700000 + addr);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return data;
+}
+
+static void
+nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data)
+{
+	struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object);
+	struct nv50_instobj_priv *node = (void *)object;
+	unsigned long flags;
+	u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+	u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (unlikely(priv->addr != base)) {
+		nv_wr32(priv, 0x001700, base >> 16);
+		priv->addr = base;
+	}
+	nv_wr32(priv, 0x700000 + addr, data);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nv50_instobj_dtor(struct nvkm_object *object)
+{
+	struct nv50_instobj_priv *node = (void *)object;
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	pfb->ram->put(pfb, &node->mem);
+	nvkm_instobj_destroy(&node->base);
+}
+
+static int
+nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_instobj_args *args = data;
+	struct nv50_instobj_priv *node;
+	int ret;
+
+	args->size  = max((args->size  + 4095) & ~4095, (u32)4096);
+	args->align = max((args->align + 4095) & ~4095, (u32)4096);
+
+	ret = nvkm_instobj_create(parent, engine, oclass, &node);
+	*pobject = nv_object(node);
+	if (ret)
+		return ret;
+
+	ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem);
+	if (ret)
+		return ret;
+
+	node->base.addr = node->mem->offset;
+	node->base.size = node->mem->size << 12;
+	node->mem->page_shift = 12;
+	return 0;
+}
+
+static struct nvkm_instobj_impl
+nv50_instobj_oclass = {
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_instobj_ctor,
+		.dtor = nv50_instobj_dtor,
+		.init = _nvkm_instobj_init,
+		.fini = _nvkm_instobj_fini,
+		.rd32 = nv50_instobj_rd32,
+		.wr32 = nv50_instobj_wr32,
+	},
+};
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static int
+nv50_instmem_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv50_instmem_priv *priv = (void *)object;
+	priv->addr = ~0ULL;
+	return nvkm_instmem_fini(&priv->base, suspend);
+}
+
+static int
+nv50_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, void *data, u32 size,
+		  struct nvkm_object **pobject)
+{
+	struct nv50_instmem_priv *priv;
+	int ret;
+
+	ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+struct nvkm_oclass *
+nv50_instmem_oclass = &(struct nvkm_instmem_impl) {
+	.base.handle = NV_SUBDEV(INSTMEM, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_instmem_ctor,
+		.dtor = _nvkm_instmem_dtor,
+		.init = _nvkm_instmem_init,
+		.fini = nv50_instmem_fini,
+	},
+	.instobj = &nv50_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
new file mode 100644
index 0000000..b10e292
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
@@ -0,0 +1,54 @@
+#ifndef __NVKM_INSTMEM_PRIV_H__
+#define __NVKM_INSTMEM_PRIV_H__
+#include <subdev/instmem.h>
+
+struct nvkm_instobj_impl {
+	struct nvkm_oclass base;
+};
+
+struct nvkm_instobj_args {
+	u32 size;
+	u32 align;
+};
+
+#define nvkm_instobj_create(p,e,o,d)                                        \
+	nvkm_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_instobj_destroy(p) ({                                          \
+	struct nvkm_instobj *iobj = (p);                                    \
+	_nvkm_instobj_dtor(nv_object(iobj));                                \
+})
+#define nvkm_instobj_init(p)                                                \
+	nvkm_object_init(&(p)->base)
+#define nvkm_instobj_fini(p,s)                                              \
+	nvkm_object_fini(&(p)->base, (s))
+
+int  nvkm_instobj_create_(struct nvkm_object *, struct nvkm_object *,
+			     struct nvkm_oclass *, int, void **);
+void _nvkm_instobj_dtor(struct nvkm_object *);
+#define _nvkm_instobj_init nvkm_object_init
+#define _nvkm_instobj_fini nvkm_object_fini
+
+struct nvkm_instmem_impl {
+	struct nvkm_oclass base;
+	struct nvkm_oclass *instobj;
+};
+
+#define nvkm_instmem_create(p,e,o,d)                                        \
+	nvkm_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_instmem_destroy(p)                                             \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_instmem_init(p) ({                                             \
+	struct nvkm_instmem *imem = (p);                                    \
+	_nvkm_instmem_init(nv_object(imem));                                \
+})
+#define nvkm_instmem_fini(p,s) ({                                           \
+	struct nvkm_instmem *imem = (p);                                    \
+	_nvkm_instmem_fini(nv_object(imem), (s));                           \
+})
+
+int nvkm_instmem_create_(struct nvkm_object *, struct nvkm_object *,
+			    struct nvkm_oclass *, int, void **);
+#define _nvkm_instmem_dtor _nvkm_subdev_dtor
+int _nvkm_instmem_init(struct nvkm_object *);
+int _nvkm_instmem_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
new file mode 100644
index 0000000..e5df3d8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/ltc/base.o
+nvkm-y += nvkm/subdev/ltc/gf100.o
+nvkm-y += nvkm/subdev/ltc/gk104.o
+nvkm-y += nvkm/subdev/ltc/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
new file mode 100644
index 0000000..2fb87fb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+static int
+nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode)
+{
+	struct nvkm_ltc_priv *priv = (void *)ltc;
+	int ret;
+
+	ret = nvkm_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
+	if (ret)
+		*pnode = NULL;
+
+	return ret;
+}
+
+static void
+nvkm_ltc_tags_free(struct nvkm_ltc *ltc, struct nvkm_mm_node **pnode)
+{
+	struct nvkm_ltc_priv *priv = (void *)ltc;
+	nvkm_mm_free(&priv->tags, pnode);
+}
+
+static void
+nvkm_ltc_tags_clear(struct nvkm_ltc *ltc, u32 first, u32 count)
+{
+	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+	struct nvkm_ltc_priv *priv = (void *)ltc;
+	const u32 limit = first + count - 1;
+
+	BUG_ON((first > limit) || (limit >= priv->num_tags));
+
+	impl->cbc_clear(priv, first, limit);
+	impl->cbc_wait(priv);
+}
+
+static int
+nvkm_ltc_zbc_color_get(struct nvkm_ltc *ltc, int index, const u32 color[4])
+{
+	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+	struct nvkm_ltc_priv *priv = (void *)ltc;
+	memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index]));
+	impl->zbc_clear_color(priv, index, color);
+	return index;
+}
+
+static int
+nvkm_ltc_zbc_depth_get(struct nvkm_ltc *ltc, int index, const u32 depth)
+{
+	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+	struct nvkm_ltc_priv *priv = (void *)ltc;
+	priv->zbc_depth[index] = depth;
+	impl->zbc_clear_depth(priv, index, depth);
+	return index;
+}
+
+int
+_nvkm_ltc_init(struct nvkm_object *object)
+{
+	const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object);
+	struct nvkm_ltc_priv *priv = (void *)object;
+	int ret, i;
+
+	ret = nvkm_subdev_init(&priv->base.base);
+	if (ret)
+		return ret;
+
+	for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) {
+		impl->zbc_clear_color(priv, i, priv->zbc_color[i]);
+		impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]);
+	}
+
+	return 0;
+}
+
+int
+nvkm_ltc_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	const struct nvkm_ltc_impl *impl = (void *)oclass;
+	struct nvkm_ltc_priv *priv;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PLTCG",
+				  "l2c", length, pobject);
+	priv = *pobject;
+	if (ret)
+		return ret;
+
+	memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color));
+	memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth));
+
+	priv->base.base.intr = impl->intr;
+	priv->base.tags_alloc = nvkm_ltc_tags_alloc;
+	priv->base.tags_free = nvkm_ltc_tags_free;
+	priv->base.tags_clear = nvkm_ltc_tags_clear;
+	priv->base.zbc_min = 1; /* reserve 0 for disabled */
+	priv->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1;
+	priv->base.zbc_color_get = nvkm_ltc_zbc_color_get;
+	priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
new file mode 100644
index 0000000..8e7cc62
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/enum.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+void
+gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
+{
+	nv_wr32(priv, 0x17e8cc, start);
+	nv_wr32(priv, 0x17e8d0, limit);
+	nv_wr32(priv, 0x17e8c8, 0x00000004);
+}
+
+void
+gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
+{
+	int c, s;
+	for (c = 0; c < priv->ltc_nr; c++) {
+		for (s = 0; s < priv->lts_nr; s++)
+			nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0);
+	}
+}
+
+void
+gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
+{
+	nv_mask(priv, 0x17ea44, 0x0000000f, i);
+	nv_wr32(priv, 0x17ea48, color[0]);
+	nv_wr32(priv, 0x17ea4c, color[1]);
+	nv_wr32(priv, 0x17ea50, color[2]);
+	nv_wr32(priv, 0x17ea54, color[3]);
+}
+
+void
+gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
+{
+	nv_mask(priv, 0x17ea44, 0x0000000f, i);
+	nv_wr32(priv, 0x17ea58, depth);
+}
+
+static const struct nvkm_bitfield
+gf100_ltc_lts_intr_name[] = {
+	{ 0x00000001, "IDLE_ERROR_IQ" },
+	{ 0x00000002, "IDLE_ERROR_CBC" },
+	{ 0x00000004, "IDLE_ERROR_TSTG" },
+	{ 0x00000008, "IDLE_ERROR_DSTG" },
+	{ 0x00000010, "EVICTED_CB" },
+	{ 0x00000020, "ILLEGAL_COMPSTAT" },
+	{ 0x00000040, "BLOCKLINEAR_CB" },
+	{ 0x00000100, "ECC_SEC_ERROR" },
+	{ 0x00000200, "ECC_DED_ERROR" },
+	{ 0x00000400, "DEBUG" },
+	{ 0x00000800, "ATOMIC_TO_Z" },
+	{ 0x00001000, "ILLEGAL_ATOMIC" },
+	{ 0x00002000, "BLKACTIVITY_ERR" },
+	{}
+};
+
+static void
+gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
+{
+	u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
+	u32 intr = nv_rd32(priv, base + 0x020);
+	u32 stat = intr & 0x0000ffff;
+
+	if (stat) {
+		nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
+		nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat);
+		pr_cont("\n");
+	}
+
+	nv_wr32(priv, base + 0x020, intr);
+}
+
+void
+gf100_ltc_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_ltc_priv *priv = (void *)subdev;
+	u32 mask;
+
+	mask = nv_rd32(priv, 0x00017c);
+	while (mask) {
+		u32 lts, ltc = __ffs(mask);
+		for (lts = 0; lts < priv->lts_nr; lts++)
+			gf100_ltc_lts_intr(priv, ltc, lts);
+		mask &= ~(1 << ltc);
+	}
+}
+
+static int
+gf100_ltc_init(struct nvkm_object *object)
+{
+	struct nvkm_ltc_priv *priv = (void *)object;
+	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+	int ret;
+
+	ret = nvkm_ltc_init(priv);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
+	nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
+	nv_wr32(priv, 0x17e8d4, priv->tag_base);
+	nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+	return 0;
+}
+
+void
+gf100_ltc_dtor(struct nvkm_object *object)
+{
+	struct nvkm_fb *pfb = nvkm_fb(object);
+	struct nvkm_ltc_priv *priv = (void *)object;
+
+	nvkm_mm_fini(&priv->tags);
+	nvkm_mm_free(&pfb->vram, &priv->tag_ram);
+
+	nvkm_ltc_destroy(priv);
+}
+
+/* TODO: Figure out tag memory details and drop the over-cautious allocation.
+ */
+int
+gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv)
+{
+	u32 tag_size, tag_margin, tag_align;
+	int ret;
+
+	/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
+	priv->num_tags = (pfb->ram->size >> 17) / 4;
+	if (priv->num_tags > (1 << 17))
+		priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
+	priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
+
+	tag_align = priv->ltc_nr * 0x800;
+	tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
+
+	/* 4 part 4 sub: 0x2000 bytes for 56 tags */
+	/* 3 part 4 sub: 0x6000 bytes for 168 tags */
+	/*
+	 * About 147 bytes per tag. Let's be safe and allocate x2, which makes
+	 * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
+	 *
+	 * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
+	 */
+	tag_size  = (priv->num_tags / 64) * 0x6000 + tag_margin;
+	tag_size += tag_align;
+	tag_size  = (tag_size + 0xfff) >> 12; /* round up */
+
+	ret = nvkm_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
+			   &priv->tag_ram);
+	if (ret) {
+		priv->num_tags = 0;
+	} else {
+		u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
+
+		tag_base += tag_align - 1;
+		ret = do_div(tag_base, tag_align);
+
+		priv->tag_base = tag_base;
+	}
+
+	ret = nvkm_mm_init(&priv->tags, 0, priv->num_tags, 1);
+	return ret;
+}
+
+int
+gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ltc_priv *priv;
+	u32 parts, mask;
+	int ret, i;
+
+	ret = nvkm_ltc_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	parts = nv_rd32(priv, 0x022438);
+	mask = nv_rd32(priv, 0x022554);
+	for (i = 0; i < parts; i++) {
+		if (!(mask & (1 << i)))
+			priv->ltc_nr++;
+	}
+	priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28;
+
+	ret = gf100_ltc_init_tag_ram(pfb, priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->intr = gf100_ltc_intr;
+	return 0;
+}
+
+struct nvkm_oclass *
+gf100_ltc_oclass = &(struct nvkm_ltc_impl) {
+	.base.handle = NV_SUBDEV(LTC, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ltc_ctor,
+		.dtor = gf100_ltc_dtor,
+		.init = gf100_ltc_init,
+		.fini = _nvkm_ltc_fini,
+	},
+	.intr = gf100_ltc_intr,
+	.cbc_clear = gf100_ltc_cbc_clear,
+	.cbc_wait = gf100_ltc_cbc_wait,
+	.zbc = 16,
+	.zbc_clear_color = gf100_ltc_zbc_clear_color,
+	.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
new file mode 100644
index 0000000..d53959b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+gk104_ltc_init(struct nvkm_object *object)
+{
+	struct nvkm_ltc_priv *priv = (void *)object;
+	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+	int ret;
+
+	ret = nvkm_ltc_init(priv);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
+	nv_wr32(priv, 0x17e000, priv->ltc_nr);
+	nv_wr32(priv, 0x17e8d4, priv->tag_base);
+	nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+	return 0;
+}
+
+struct nvkm_oclass *
+gk104_ltc_oclass = &(struct nvkm_ltc_impl) {
+	.base.handle = NV_SUBDEV(LTC, 0xe4),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_ltc_ctor,
+		.dtor = gf100_ltc_dtor,
+		.init = gk104_ltc_init,
+		.fini = _nvkm_ltc_fini,
+	},
+	.intr = gf100_ltc_intr,
+	.cbc_clear = gf100_ltc_cbc_clear,
+	.cbc_wait = gf100_ltc_cbc_wait,
+	.zbc = 16,
+	.zbc_clear_color = gf100_ltc_zbc_clear_color,
+	.zbc_clear_depth = gf100_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
new file mode 100644
index 0000000..6b3f6f4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2014 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+static void
+gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
+{
+	nv_wr32(priv, 0x17e270, start);
+	nv_wr32(priv, 0x17e274, limit);
+	nv_wr32(priv, 0x17e26c, 0x00000004);
+}
+
+static void
+gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
+{
+	int c, s;
+	for (c = 0; c < priv->ltc_nr; c++) {
+		for (s = 0; s < priv->lts_nr; s++)
+			nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0);
+	}
+}
+
+static void
+gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
+{
+	nv_mask(priv, 0x17e338, 0x0000000f, i);
+	nv_wr32(priv, 0x17e33c, color[0]);
+	nv_wr32(priv, 0x17e340, color[1]);
+	nv_wr32(priv, 0x17e344, color[2]);
+	nv_wr32(priv, 0x17e348, color[3]);
+}
+
+static void
+gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
+{
+	nv_mask(priv, 0x17e338, 0x0000000f, i);
+	nv_wr32(priv, 0x17e34c, depth);
+}
+
+static void
+gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
+{
+	u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
+	u32 stat = nv_rd32(priv, base + 0x00c);
+
+	if (stat) {
+		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
+		nv_wr32(priv, base + 0x00c, stat);
+	}
+}
+
+static void
+gm107_ltc_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_ltc_priv *priv = (void *)subdev;
+	u32 mask;
+
+	mask = nv_rd32(priv, 0x00017c);
+	while (mask) {
+		u32 lts, ltc = __ffs(mask);
+		for (lts = 0; lts < priv->lts_nr; lts++)
+			gm107_ltc_lts_isr(priv, ltc, lts);
+		mask &= ~(1 << ltc);
+	}
+}
+
+static int
+gm107_ltc_init(struct nvkm_object *object)
+{
+	struct nvkm_ltc_priv *priv = (void *)object;
+	u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+	int ret;
+
+	ret = nvkm_ltc_init(priv);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x17e27c, priv->ltc_nr);
+	nv_wr32(priv, 0x17e278, priv->tag_base);
+	nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+	return 0;
+}
+
+static int
+gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_fb *pfb = nvkm_fb(parent);
+	struct nvkm_ltc_priv *priv;
+	u32 parts, mask;
+	int ret, i;
+
+	ret = nvkm_ltc_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	parts = nv_rd32(priv, 0x022438);
+	mask = nv_rd32(priv, 0x021c14);
+	for (i = 0; i < parts; i++) {
+		if (!(mask & (1 << i)))
+			priv->ltc_nr++;
+	}
+	priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28;
+
+	ret = gf100_ltc_init_tag_ram(pfb, priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+gm107_ltc_oclass = &(struct nvkm_ltc_impl) {
+	.base.handle = NV_SUBDEV(LTC, 0xff),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm107_ltc_ctor,
+		.dtor = gf100_ltc_dtor,
+		.init = gm107_ltc_init,
+		.fini = _nvkm_ltc_fini,
+	},
+	.intr = gm107_ltc_intr,
+	.cbc_clear = gm107_ltc_cbc_clear,
+	.cbc_wait = gm107_ltc_cbc_wait,
+	.zbc = 16,
+	.zbc_clear_color = gm107_ltc_zbc_clear_color,
+	.zbc_clear_depth = gm107_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
new file mode 100644
index 0000000..09537d7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
@@ -0,0 +1,69 @@
+#ifndef __NVKM_LTC_PRIV_H__
+#define __NVKM_LTC_PRIV_H__
+#include <subdev/ltc.h>
+
+#include <core/mm.h>
+struct nvkm_fb;
+
+struct nvkm_ltc_priv {
+	struct nvkm_ltc base;
+	u32 ltc_nr;
+	u32 lts_nr;
+
+	u32 num_tags;
+	u32 tag_base;
+	struct nvkm_mm tags;
+	struct nvkm_mm_node *tag_ram;
+
+	u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4];
+	u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
+};
+
+#define nvkm_ltc_create(p,e,o,d)                                               \
+	nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_ltc_destroy(p) ({                                                 \
+	struct nvkm_ltc_priv *_priv = (p);                                     \
+	_nvkm_ltc_dtor(nv_object(_priv));                                      \
+})
+#define nvkm_ltc_init(p) ({                                                    \
+	struct nvkm_ltc_priv *_priv = (p);                                     \
+	_nvkm_ltc_init(nv_object(_priv));                                      \
+})
+#define nvkm_ltc_fini(p,s) ({                                                  \
+	struct nvkm_ltc_priv *_priv = (p);                                     \
+	_nvkm_ltc_fini(nv_object(_priv), (s));                                 \
+})
+
+int  nvkm_ltc_create_(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, int, void **);
+
+#define _nvkm_ltc_dtor _nvkm_subdev_dtor
+int _nvkm_ltc_init(struct nvkm_object *);
+#define _nvkm_ltc_fini _nvkm_subdev_fini
+
+int  gf100_ltc_ctor(struct nvkm_object *, struct nvkm_object *,
+		    struct nvkm_oclass *, void *, u32,
+		    struct nvkm_object **);
+void gf100_ltc_dtor(struct nvkm_object *);
+int  gf100_ltc_init_tag_ram(struct nvkm_fb *, struct nvkm_ltc_priv *);
+int  gf100_ltc_tags_alloc(struct nvkm_ltc *, u32, struct nvkm_mm_node **);
+void gf100_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **);
+
+struct nvkm_ltc_impl {
+	struct nvkm_oclass base;
+	void (*intr)(struct nvkm_subdev *);
+
+	void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit);
+	void (*cbc_wait)(struct nvkm_ltc_priv *);
+
+	int zbc;
+	void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]);
+	void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32);
+};
+
+void gf100_ltc_intr(struct nvkm_subdev *);
+void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32);
+void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *);
+void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]);
+void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
new file mode 100644
index 0000000..721643f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
@@ -0,0 +1,11 @@
+nvkm-y += nvkm/subdev/mc/base.o
+nvkm-y += nvkm/subdev/mc/nv04.o
+nvkm-y += nvkm/subdev/mc/nv40.o
+nvkm-y += nvkm/subdev/mc/nv44.o
+nvkm-y += nvkm/subdev/mc/nv4c.o
+nvkm-y += nvkm/subdev/mc/nv50.o
+nvkm-y += nvkm/subdev/mc/g94.o
+nvkm-y += nvkm/subdev/mc/g98.o
+nvkm-y += nvkm/subdev/mc/gf100.o
+nvkm-y += nvkm/subdev/mc/gf106.o
+nvkm-y += nvkm/subdev/mc/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
new file mode 100644
index 0000000..5b051a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+
+static inline void
+nvkm_mc_unk260(struct nvkm_mc *pmc, u32 data)
+{
+	const struct nvkm_mc_oclass *impl = (void *)nv_oclass(pmc);
+	if (impl->unk260)
+		impl->unk260(pmc, data);
+}
+
+static inline u32
+nvkm_mc_intr_mask(struct nvkm_mc *pmc)
+{
+	u32 intr = nv_rd32(pmc, 0x000100);
+	if (intr == 0xffffffff) /* likely fallen off the bus */
+		intr = 0x00000000;
+	return intr;
+}
+
+static irqreturn_t
+nvkm_mc_intr(int irq, void *arg)
+{
+	struct nvkm_mc *pmc = arg;
+	const struct nvkm_mc_oclass *oclass = (void *)nv_object(pmc)->oclass;
+	const struct nvkm_mc_intr *map = oclass->intr;
+	struct nvkm_subdev *unit;
+	u32 intr;
+
+	nv_wr32(pmc, 0x000140, 0x00000000);
+	nv_rd32(pmc, 0x000140);
+	intr = nvkm_mc_intr_mask(pmc);
+	if (pmc->use_msi)
+		oclass->msi_rearm(pmc);
+
+	if (intr) {
+		u32 stat = intr = nvkm_mc_intr_mask(pmc);
+		while (map->stat) {
+			if (intr & map->stat) {
+				unit = nvkm_subdev(pmc, map->unit);
+				if (unit && unit->intr)
+					unit->intr(unit);
+				stat &= ~map->stat;
+			}
+			map++;
+		}
+
+		if (stat)
+			nv_error(pmc, "unknown intr 0x%08x\n", stat);
+	}
+
+	nv_wr32(pmc, 0x000140, 0x00000001);
+	return intr ? IRQ_HANDLED : IRQ_NONE;
+}
+
+int
+_nvkm_mc_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_mc *pmc = (void *)object;
+	nv_wr32(pmc, 0x000140, 0x00000000);
+	return nvkm_subdev_fini(&pmc->base, suspend);
+}
+
+int
+_nvkm_mc_init(struct nvkm_object *object)
+{
+	struct nvkm_mc *pmc = (void *)object;
+	int ret = nvkm_subdev_init(&pmc->base);
+	if (ret)
+		return ret;
+	nv_wr32(pmc, 0x000140, 0x00000001);
+	return 0;
+}
+
+void
+_nvkm_mc_dtor(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nvkm_mc *pmc = (void *)object;
+	free_irq(pmc->irq, pmc);
+	if (pmc->use_msi)
+		pci_disable_msi(device->pdev);
+	nvkm_subdev_destroy(&pmc->base);
+}
+
+int
+nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *bclass, int length, void **pobject)
+{
+	const struct nvkm_mc_oclass *oclass = (void *)bclass;
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_mc *pmc;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, bclass, 0, "PMC",
+				  "master", length, pobject);
+	pmc = *pobject;
+	if (ret)
+		return ret;
+
+	pmc->unk260 = nvkm_mc_unk260;
+
+	if (nv_device_is_pci(device)) {
+		switch (device->pdev->device & 0x0ff0) {
+		case 0x00f0:
+		case 0x02e0:
+			/* BR02? NFI how these would be handled yet exactly */
+			break;
+		default:
+			switch (device->chipset) {
+			case 0xaa:
+				/* reported broken, nv also disable it */
+				break;
+			default:
+				pmc->use_msi = true;
+				break;
+			}
+		}
+
+		pmc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI",
+					    pmc->use_msi);
+
+		if (pmc->use_msi && oclass->msi_rearm) {
+			pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+			if (pmc->use_msi) {
+				nv_info(pmc, "MSI interrupts enabled\n");
+				oclass->msi_rearm(pmc);
+			}
+		} else {
+			pmc->use_msi = false;
+		}
+	}
+
+	ret = nv_device_get_irq(device, true);
+	if (ret < 0)
+		return ret;
+	pmc->irq = ret;
+
+	ret = request_irq(pmc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", pmc);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c
new file mode 100644
index 0000000..f042e7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+g94_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x94),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv50_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
new file mode 100644
index 0000000..8ab7f12
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+static const struct nvkm_mc_intr
+g98_mc_intr[] = {
+	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP first, so pageflip timestamps work */
+	{ 0x00000001, NVDEV_ENGINE_MSPPP },
+	{ 0x00000100, NVDEV_ENGINE_FIFO },
+	{ 0x00001000, NVDEV_ENGINE_GR },
+	{ 0x00004000, NVDEV_ENGINE_SEC },	/* NV84:NVA3 */
+	{ 0x00008000, NVDEV_ENGINE_MSVLD },
+	{ 0x00020000, NVDEV_ENGINE_MSPDEC },
+	{ 0x00040000, NVDEV_SUBDEV_PMU },	/* NVA3:NVC0 */
+	{ 0x00080000, NVDEV_SUBDEV_THERM },	/* NVA3:NVC0 */
+	{ 0x00100000, NVDEV_SUBDEV_TIMER },
+	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
+	{ 0x00200000, NVDEV_SUBDEV_I2C }, 	/* PMGR->I2C/AUX */
+	{ 0x00400000, NVDEV_ENGINE_CE0 },	/* NVA3-     */
+	{ 0x10000000, NVDEV_SUBDEV_BUS },
+	{ 0x80000000, NVDEV_ENGINE_SW },
+	{ 0x0042d101, NVDEV_SUBDEV_FB },
+	{},
+};
+
+struct nvkm_oclass *
+g98_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x98),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = g98_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
new file mode 100644
index 0000000..2425984
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+const struct nvkm_mc_intr
+gf100_mc_intr[] = {
+	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP first, so pageflip timestamps work. */
+	{ 0x00000001, NVDEV_ENGINE_MSPPP },
+	{ 0x00000020, NVDEV_ENGINE_CE0 },
+	{ 0x00000040, NVDEV_ENGINE_CE1 },
+	{ 0x00000080, NVDEV_ENGINE_CE2 },
+	{ 0x00000100, NVDEV_ENGINE_FIFO },
+	{ 0x00001000, NVDEV_ENGINE_GR },
+	{ 0x00002000, NVDEV_SUBDEV_FB },
+	{ 0x00008000, NVDEV_ENGINE_MSVLD },
+	{ 0x00040000, NVDEV_SUBDEV_THERM },
+	{ 0x00020000, NVDEV_ENGINE_MSPDEC },
+	{ 0x00100000, NVDEV_SUBDEV_TIMER },
+	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
+	{ 0x00200000, NVDEV_SUBDEV_I2C },	/* PMGR->I2C/AUX */
+	{ 0x01000000, NVDEV_SUBDEV_PMU },
+	{ 0x02000000, NVDEV_SUBDEV_LTC },
+	{ 0x08000000, NVDEV_SUBDEV_FB },
+	{ 0x10000000, NVDEV_SUBDEV_BUS },
+	{ 0x40000000, NVDEV_SUBDEV_IBUS },
+	{ 0x80000000, NVDEV_ENGINE_SW },
+	{},
+};
+
+static void
+gf100_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+	struct nv04_mc_priv *priv = (void *)pmc;
+	nv_wr32(priv, 0x088704, 0x00000000);
+}
+
+void
+gf100_mc_unk260(struct nvkm_mc *pmc, u32 data)
+{
+	nv_wr32(pmc, 0x000260, data);
+}
+
+struct nvkm_oclass *
+gf100_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = gf100_mc_intr,
+	.msi_rearm = gf100_mc_msi_rearm,
+	.unk260 = gf100_mc_unk260,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c
new file mode 100644
index 0000000..8d2a8f4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+gf106_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0xc3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = gf100_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+	.unk260 = gf100_mc_unk260,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
new file mode 100644
index 0000000..43b2774
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+gk20a_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = gf100_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
new file mode 100644
index 0000000..3271382
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+const struct nvkm_mc_intr
+nv04_mc_intr[] = {
+	{ 0x00000001, NVDEV_ENGINE_MPEG },	/* NV17- MPEG/ME */
+	{ 0x00000100, NVDEV_ENGINE_FIFO },
+	{ 0x00001000, NVDEV_ENGINE_GR },
+	{ 0x00010000, NVDEV_ENGINE_DISP },
+	{ 0x00020000, NVDEV_ENGINE_VP },	/* NV40- */
+	{ 0x00100000, NVDEV_SUBDEV_TIMER },
+	{ 0x01000000, NVDEV_ENGINE_DISP },	/* NV04- PCRTC0 */
+	{ 0x02000000, NVDEV_ENGINE_DISP },	/* NV11- PCRTC1 */
+	{ 0x10000000, NVDEV_SUBDEV_BUS },
+	{ 0x80000000, NVDEV_ENGINE_SW },
+	{}
+};
+
+int
+nv04_mc_init(struct nvkm_object *object)
+{
+	struct nv04_mc_priv *priv = (void *)object;
+
+	nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
+	nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
+
+	return nvkm_mc_init(&priv->base);
+}
+
+int
+nv04_mc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	     struct nvkm_oclass *oclass, void *data, u32 size,
+	     struct nvkm_object **pobject)
+{
+	struct nv04_mc_priv *priv;
+	int ret;
+
+	ret = nvkm_mc_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass *
+nv04_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x04),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv04_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv04_mc_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h
new file mode 100644
index 0000000..411de3d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h
@@ -0,0 +1,20 @@
+#ifndef __NVKM_MC_NV04_H__
+#define __NVKM_MC_NV04_H__
+#include "priv.h"
+
+struct nv04_mc_priv {
+	struct nvkm_mc base;
+};
+
+int  nv04_mc_ctor(struct nvkm_object *, struct nvkm_object *,
+		  struct nvkm_oclass *, void *, u32,
+		  struct nvkm_object **);
+
+extern const struct nvkm_mc_intr nv04_mc_intr[];
+int  nv04_mc_init(struct nvkm_object *);
+void nv40_mc_msi_rearm(struct nvkm_mc *);
+int  nv44_mc_init(struct nvkm_object *object);
+int  nv50_mc_init(struct nvkm_object *);
+extern const struct nvkm_mc_intr nv50_mc_intr[];
+extern const struct nvkm_mc_intr gf100_mc_intr[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c
new file mode 100644
index 0000000..b761305
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+void
+nv40_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+	struct nv04_mc_priv *priv = (void *)pmc;
+	nv_wr08(priv, 0x088068, 0xff);
+}
+
+struct nvkm_oclass *
+nv40_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x40),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv04_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv04_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
new file mode 100644
index 0000000..2c7f7c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+int
+nv44_mc_init(struct nvkm_object *object)
+{
+	struct nv04_mc_priv *priv = (void *)object;
+	u32 tmp = nv_rd32(priv, 0x10020c);
+
+	nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
+
+	nv_wr32(priv, 0x001700, tmp);
+	nv_wr32(priv, 0x001704, 0);
+	nv_wr32(priv, 0x001708, 0);
+	nv_wr32(priv, 0x00170c, tmp);
+
+	return nvkm_mc_init(&priv->base);
+}
+
+struct nvkm_oclass *
+nv44_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x44),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv44_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv04_mc_intr,
+	.msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c
new file mode 100644
index 0000000..c0aac7e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 Ilia Mirkin
+ *
+ * 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.
+ *
+ * Authors: Ilia Mirkin
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv4c_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x4c),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv44_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv04_mc_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
new file mode 100644
index 0000000..40e3019
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+const struct nvkm_mc_intr
+nv50_mc_intr[] = {
+	{ 0x04000000, NVDEV_ENGINE_DISP },  /* DISP before FIFO, so pageflip-timestamping works! */
+	{ 0x00000001, NVDEV_ENGINE_MPEG },
+	{ 0x00000100, NVDEV_ENGINE_FIFO },
+	{ 0x00001000, NVDEV_ENGINE_GR },
+	{ 0x00004000, NVDEV_ENGINE_CIPHER },	/* NV84- */
+	{ 0x00008000, NVDEV_ENGINE_BSP },	/* NV84- */
+	{ 0x00020000, NVDEV_ENGINE_VP },	/* NV84- */
+	{ 0x00100000, NVDEV_SUBDEV_TIMER },
+	{ 0x00200000, NVDEV_SUBDEV_GPIO },	/* PMGR->GPIO */
+	{ 0x00200000, NVDEV_SUBDEV_I2C }, 	/* PMGR->I2C/AUX */
+	{ 0x10000000, NVDEV_SUBDEV_BUS },
+	{ 0x80000000, NVDEV_ENGINE_SW },
+	{ 0x0002d101, NVDEV_SUBDEV_FB },
+	{},
+};
+
+static void
+nv50_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+	struct nvkm_device *device = nv_device(pmc);
+	pci_write_config_byte(device->pdev, 0x68, 0xff);
+}
+
+int
+nv50_mc_init(struct nvkm_object *object)
+{
+	struct nv04_mc_priv *priv = (void *)object;
+	nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */
+	return nvkm_mc_init(&priv->base);
+}
+
+struct nvkm_oclass *
+nv50_mc_oclass = &(struct nvkm_mc_oclass) {
+	.base.handle = NV_SUBDEV(MC, 0x50),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mc_ctor,
+		.dtor = _nvkm_mc_dtor,
+		.init = nv50_mc_init,
+		.fini = _nvkm_mc_fini,
+	},
+	.intr = nv50_mc_intr,
+	.msi_rearm = nv50_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
new file mode 100644
index 0000000..d2cad07
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
@@ -0,0 +1,36 @@
+#ifndef __NVKM_MC_PRIV_H__
+#define __NVKM_MC_PRIV_H__
+#include <subdev/mc.h>
+
+#define nvkm_mc_create(p,e,o,d)                                             \
+	nvkm_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_mc_destroy(p) ({                                               \
+	struct nvkm_mc *pmc = (p); _nvkm_mc_dtor(nv_object(pmc));        \
+})
+#define nvkm_mc_init(p) ({                                                  \
+	struct nvkm_mc *pmc = (p); _nvkm_mc_init(nv_object(pmc));        \
+})
+#define nvkm_mc_fini(p,s) ({                                                \
+	struct nvkm_mc *pmc = (p); _nvkm_mc_fini(nv_object(pmc), (s));   \
+})
+
+int  nvkm_mc_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, int, void **);
+void _nvkm_mc_dtor(struct nvkm_object *);
+int  _nvkm_mc_init(struct nvkm_object *);
+int  _nvkm_mc_fini(struct nvkm_object *, bool);
+
+struct nvkm_mc_intr {
+	u32 stat;
+	u32 unit;
+};
+
+struct nvkm_mc_oclass {
+	struct nvkm_oclass base;
+	const struct nvkm_mc_intr *intr;
+	void (*msi_rearm)(struct nvkm_mc *);
+	void (*unk260)(struct nvkm_mc *, u32);
+};
+
+void gf100_mc_unk260(struct nvkm_mc *, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
new file mode 100644
index 0000000..012c9db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/mmu/base.o
+nvkm-y += nvkm/subdev/mmu/nv04.o
+nvkm-y += nvkm/subdev/mmu/nv41.o
+nvkm-y += nvkm/subdev/mmu/nv44.o
+nvkm-y += nvkm/subdev/mmu/nv50.o
+nvkm-y += nvkm/subdev/mmu/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
new file mode 100644
index 0000000..277b6ec
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/fb.h>
+
+#include <core/gpuobj.h>
+
+void
+nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node)
+{
+	struct nvkm_vm *vm = vma->vm;
+	struct nvkm_mmu *mmu = vm->mmu;
+	struct nvkm_mm_node *r;
+	int big = vma->node->type != mmu->spg_shift;
+	u32 offset = vma->node->offset + (delta >> 12);
+	u32 bits = vma->node->type - 12;
+	u32 pde  = (offset >> mmu->pgt_bits) - vm->fpde;
+	u32 pte  = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+	u32 max  = 1 << (mmu->pgt_bits - bits);
+	u32 end, len;
+
+	delta = 0;
+	list_for_each_entry(r, &node->regions, rl_entry) {
+		u64 phys = (u64)r->offset << 12;
+		u32 num  = r->length >> bits;
+
+		while (num) {
+			struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+			end = (pte + num);
+			if (unlikely(end >= max))
+				end = max;
+			len = end - pte;
+
+			mmu->map(vma, pgt, node, pte, len, phys, delta);
+
+			num -= len;
+			pte += len;
+			if (unlikely(end >= max)) {
+				phys += len << (bits + 12);
+				pde++;
+				pte = 0;
+			}
+
+			delta += (u64)len << vma->node->type;
+		}
+	}
+
+	mmu->flush(vm);
+}
+
+static void
+nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length,
+		     struct nvkm_mem *mem)
+{
+	struct nvkm_vm *vm = vma->vm;
+	struct nvkm_mmu *mmu = vm->mmu;
+	int big = vma->node->type != mmu->spg_shift;
+	u32 offset = vma->node->offset + (delta >> 12);
+	u32 bits = vma->node->type - 12;
+	u32 num  = length >> vma->node->type;
+	u32 pde  = (offset >> mmu->pgt_bits) - vm->fpde;
+	u32 pte  = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+	u32 max  = 1 << (mmu->pgt_bits - bits);
+	unsigned m, sglen;
+	u32 end, len;
+	int i;
+	struct scatterlist *sg;
+
+	for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
+		struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+		sglen = sg_dma_len(sg) >> PAGE_SHIFT;
+
+		end = pte + sglen;
+		if (unlikely(end >= max))
+			end = max;
+		len = end - pte;
+
+		for (m = 0; m < len; m++) {
+			dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+			mmu->map_sg(vma, pgt, mem, pte, 1, &addr);
+			num--;
+			pte++;
+
+			if (num == 0)
+				goto finish;
+		}
+		if (unlikely(end >= max)) {
+			pde++;
+			pte = 0;
+		}
+		if (m < sglen) {
+			for (; m < sglen; m++) {
+				dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+				mmu->map_sg(vma, pgt, mem, pte, 1, &addr);
+				num--;
+				pte++;
+				if (num == 0)
+					goto finish;
+			}
+		}
+
+	}
+finish:
+	mmu->flush(vm);
+}
+
+static void
+nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length,
+	       struct nvkm_mem *mem)
+{
+	struct nvkm_vm *vm = vma->vm;
+	struct nvkm_mmu *mmu = vm->mmu;
+	dma_addr_t *list = mem->pages;
+	int big = vma->node->type != mmu->spg_shift;
+	u32 offset = vma->node->offset + (delta >> 12);
+	u32 bits = vma->node->type - 12;
+	u32 num  = length >> vma->node->type;
+	u32 pde  = (offset >> mmu->pgt_bits) - vm->fpde;
+	u32 pte  = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+	u32 max  = 1 << (mmu->pgt_bits - bits);
+	u32 end, len;
+
+	while (num) {
+		struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+		end = (pte + num);
+		if (unlikely(end >= max))
+			end = max;
+		len = end - pte;
+
+		mmu->map_sg(vma, pgt, mem, pte, len, list);
+
+		num  -= len;
+		pte  += len;
+		list += len;
+		if (unlikely(end >= max)) {
+			pde++;
+			pte = 0;
+		}
+	}
+
+	mmu->flush(vm);
+}
+
+void
+nvkm_vm_map(struct nvkm_vma *vma, struct nvkm_mem *node)
+{
+	if (node->sg)
+		nvkm_vm_map_sg_table(vma, 0, node->size << 12, node);
+	else
+	if (node->pages)
+		nvkm_vm_map_sg(vma, 0, node->size << 12, node);
+	else
+		nvkm_vm_map_at(vma, 0, node);
+}
+
+void
+nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length)
+{
+	struct nvkm_vm *vm = vma->vm;
+	struct nvkm_mmu *mmu = vm->mmu;
+	int big = vma->node->type != mmu->spg_shift;
+	u32 offset = vma->node->offset + (delta >> 12);
+	u32 bits = vma->node->type - 12;
+	u32 num  = length >> vma->node->type;
+	u32 pde  = (offset >> mmu->pgt_bits) - vm->fpde;
+	u32 pte  = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+	u32 max  = 1 << (mmu->pgt_bits - bits);
+	u32 end, len;
+
+	while (num) {
+		struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+		end = (pte + num);
+		if (unlikely(end >= max))
+			end = max;
+		len = end - pte;
+
+		mmu->unmap(pgt, pte, len);
+
+		num -= len;
+		pte += len;
+		if (unlikely(end >= max)) {
+			pde++;
+			pte = 0;
+		}
+	}
+
+	mmu->flush(vm);
+}
+
+void
+nvkm_vm_unmap(struct nvkm_vma *vma)
+{
+	nvkm_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
+}
+
+static void
+nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde)
+{
+	struct nvkm_mmu *mmu = vm->mmu;
+	struct nvkm_vm_pgd *vpgd;
+	struct nvkm_vm_pgt *vpgt;
+	struct nvkm_gpuobj *pgt;
+	u32 pde;
+
+	for (pde = fpde; pde <= lpde; pde++) {
+		vpgt = &vm->pgt[pde - vm->fpde];
+		if (--vpgt->refcount[big])
+			continue;
+
+		pgt = vpgt->obj[big];
+		vpgt->obj[big] = NULL;
+
+		list_for_each_entry(vpgd, &vm->pgd_list, head) {
+			mmu->map_pgt(vpgd->obj, pde, vpgt->obj);
+		}
+
+		mutex_unlock(&nv_subdev(mmu)->mutex);
+		nvkm_gpuobj_ref(NULL, &pgt);
+		mutex_lock(&nv_subdev(mmu)->mutex);
+	}
+}
+
+static int
+nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type)
+{
+	struct nvkm_mmu *mmu = vm->mmu;
+	struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+	struct nvkm_vm_pgd *vpgd;
+	struct nvkm_gpuobj *pgt;
+	int big = (type != mmu->spg_shift);
+	u32 pgt_size;
+	int ret;
+
+	pgt_size  = (1 << (mmu->pgt_bits + 12)) >> type;
+	pgt_size *= 8;
+
+	mutex_unlock(&nv_subdev(mmu)->mutex);
+	ret = nvkm_gpuobj_new(nv_object(vm->mmu), NULL, pgt_size, 0x1000,
+			      NVOBJ_FLAG_ZERO_ALLOC, &pgt);
+	mutex_lock(&nv_subdev(mmu)->mutex);
+	if (unlikely(ret))
+		return ret;
+
+	/* someone beat us to filling the PDE while we didn't have the lock */
+	if (unlikely(vpgt->refcount[big]++)) {
+		mutex_unlock(&nv_subdev(mmu)->mutex);
+		nvkm_gpuobj_ref(NULL, &pgt);
+		mutex_lock(&nv_subdev(mmu)->mutex);
+		return 0;
+	}
+
+	vpgt->obj[big] = pgt;
+	list_for_each_entry(vpgd, &vm->pgd_list, head) {
+		mmu->map_pgt(vpgd->obj, pde, vpgt->obj);
+	}
+
+	return 0;
+}
+
+int
+nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access,
+	    struct nvkm_vma *vma)
+{
+	struct nvkm_mmu *mmu = vm->mmu;
+	u32 align = (1 << page_shift) >> 12;
+	u32 msize = size >> 12;
+	u32 fpde, lpde, pde;
+	int ret;
+
+	mutex_lock(&nv_subdev(mmu)->mutex);
+	ret = nvkm_mm_head(&vm->mm, 0, page_shift, msize, msize, align,
+			   &vma->node);
+	if (unlikely(ret != 0)) {
+		mutex_unlock(&nv_subdev(mmu)->mutex);
+		return ret;
+	}
+
+	fpde = (vma->node->offset >> mmu->pgt_bits);
+	lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits;
+
+	for (pde = fpde; pde <= lpde; pde++) {
+		struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+		int big = (vma->node->type != mmu->spg_shift);
+
+		if (likely(vpgt->refcount[big])) {
+			vpgt->refcount[big]++;
+			continue;
+		}
+
+		ret = nvkm_vm_map_pgt(vm, pde, vma->node->type);
+		if (ret) {
+			if (pde != fpde)
+				nvkm_vm_unmap_pgt(vm, big, fpde, pde - 1);
+			nvkm_mm_free(&vm->mm, &vma->node);
+			mutex_unlock(&nv_subdev(mmu)->mutex);
+			return ret;
+		}
+	}
+	mutex_unlock(&nv_subdev(mmu)->mutex);
+
+	vma->vm = NULL;
+	nvkm_vm_ref(vm, &vma->vm, NULL);
+	vma->offset = (u64)vma->node->offset << 12;
+	vma->access = access;
+	return 0;
+}
+
+void
+nvkm_vm_put(struct nvkm_vma *vma)
+{
+	struct nvkm_vm *vm = vma->vm;
+	struct nvkm_mmu *mmu = vm->mmu;
+	u32 fpde, lpde;
+
+	if (unlikely(vma->node == NULL))
+		return;
+	fpde = (vma->node->offset >> mmu->pgt_bits);
+	lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits;
+
+	mutex_lock(&nv_subdev(mmu)->mutex);
+	nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->spg_shift, fpde, lpde);
+	nvkm_mm_free(&vm->mm, &vma->node);
+	mutex_unlock(&nv_subdev(mmu)->mutex);
+
+	nvkm_vm_ref(NULL, &vma->vm, NULL);
+}
+
+int
+nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
+	       u32 block, struct nvkm_vm **pvm)
+{
+	struct nvkm_vm *vm;
+	u64 mm_length = (offset + length) - mm_offset;
+	int ret;
+
+	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+	if (!vm)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&vm->pgd_list);
+	vm->mmu = mmu;
+	kref_init(&vm->refcount);
+	vm->fpde = offset >> (mmu->pgt_bits + 12);
+	vm->lpde = (offset + length - 1) >> (mmu->pgt_bits + 12);
+
+	vm->pgt  = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
+	if (!vm->pgt) {
+		kfree(vm);
+		return -ENOMEM;
+	}
+
+	ret = nvkm_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
+			   block >> 12);
+	if (ret) {
+		vfree(vm->pgt);
+		kfree(vm);
+		return ret;
+	}
+
+	*pvm = vm;
+
+	return 0;
+}
+
+int
+nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset,
+	    struct nvkm_vm **pvm)
+{
+	struct nvkm_mmu *mmu = nvkm_mmu(device);
+	return mmu->create(mmu, offset, length, mm_offset, pvm);
+}
+
+static int
+nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd)
+{
+	struct nvkm_mmu *mmu = vm->mmu;
+	struct nvkm_vm_pgd *vpgd;
+	int i;
+
+	if (!pgd)
+		return 0;
+
+	vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
+	if (!vpgd)
+		return -ENOMEM;
+
+	nvkm_gpuobj_ref(pgd, &vpgd->obj);
+
+	mutex_lock(&nv_subdev(mmu)->mutex);
+	for (i = vm->fpde; i <= vm->lpde; i++)
+		mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
+	list_add(&vpgd->head, &vm->pgd_list);
+	mutex_unlock(&nv_subdev(mmu)->mutex);
+	return 0;
+}
+
+static void
+nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd)
+{
+	struct nvkm_mmu *mmu = vm->mmu;
+	struct nvkm_vm_pgd *vpgd, *tmp;
+	struct nvkm_gpuobj *pgd = NULL;
+
+	if (!mpgd)
+		return;
+
+	mutex_lock(&nv_subdev(mmu)->mutex);
+	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+		if (vpgd->obj == mpgd) {
+			pgd = vpgd->obj;
+			list_del(&vpgd->head);
+			kfree(vpgd);
+			break;
+		}
+	}
+	mutex_unlock(&nv_subdev(mmu)->mutex);
+
+	nvkm_gpuobj_ref(NULL, &pgd);
+}
+
+static void
+nvkm_vm_del(struct kref *kref)
+{
+	struct nvkm_vm *vm = container_of(kref, typeof(*vm), refcount);
+	struct nvkm_vm_pgd *vpgd, *tmp;
+
+	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+		nvkm_vm_unlink(vm, vpgd->obj);
+	}
+
+	nvkm_mm_fini(&vm->mm);
+	vfree(vm->pgt);
+	kfree(vm);
+}
+
+int
+nvkm_vm_ref(struct nvkm_vm *ref, struct nvkm_vm **ptr, struct nvkm_gpuobj *pgd)
+{
+	if (ref) {
+		int ret = nvkm_vm_link(ref, pgd);
+		if (ret)
+			return ret;
+
+		kref_get(&ref->refcount);
+	}
+
+	if (*ptr) {
+		nvkm_vm_unlink(*ptr, pgd);
+		kref_put(&(*ptr)->refcount, nvkm_vm_del);
+	}
+
+	*ptr = ref;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
new file mode 100644
index 0000000..294cda3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/timer.h>
+
+#include <core/gpuobj.h>
+
+struct gf100_mmu_priv {
+	struct nvkm_mmu base;
+};
+
+
+/* Map from compressed to corresponding uncompressed storage type.
+ * The value 0xff represents an invalid storage type.
+ */
+const u8 gf100_pte_storage_type_map[256] =
+{
+	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, /* 0x00 */
+	0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, /* 0x10 */
+	0x11, 0x11, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x27, /* 0x20 */
+	0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
+	0xff, 0xff, 0x26, 0x27, 0x28, 0x29, 0x26, 0x27,
+	0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0x46, 0xff, /* 0x40 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0x46, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, /* 0x50 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
+	0xff, 0xff, 0xff, 0x7b, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x7b, /* 0x80 */
+	0x7b, 0x7b, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xa7, /* 0xa0 */
+	0xa8, 0xa9, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7,
+	0xa8, 0xa9, 0xaa, 0xc3, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
+	0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xc3, 0xc3,
+	0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
+	0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+	0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, /* 0xe0 */
+	0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff,
+	0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0 */
+	0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
+};
+
+
+static void
+gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_gpuobj *pgt[2])
+{
+	u32 pde[2] = { 0, 0 };
+
+	if (pgt[0])
+		pde[1] = 0x00000001 | (pgt[0]->addr >> 8);
+	if (pgt[1])
+		pde[0] = 0x00000001 | (pgt[1]->addr >> 8);
+
+	nv_wo32(pgd, (index * 8) + 0, pde[0]);
+	nv_wo32(pgd, (index * 8) + 4, pde[1]);
+}
+
+static inline u64
+gf100_vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target)
+{
+	phys >>= 8;
+
+	phys |= 0x00000001; /* present */
+	if (vma->access & NV_MEM_ACCESS_SYS)
+		phys |= 0x00000002;
+
+	phys |= ((u64)target  << 32);
+	phys |= ((u64)memtype << 36);
+	return phys;
+}
+
+static void
+gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	     struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
+{
+	u64 next = 1 << (vma->node->type - 8);
+
+	phys  = gf100_vm_addr(vma, phys, mem->memtype, 0);
+	pte <<= 3;
+
+	if (mem->tag) {
+		struct nvkm_ltc *ltc = nvkm_ltc(vma->vm->mmu);
+		u32 tag = mem->tag->offset + (delta >> 17);
+		phys |= (u64)tag << (32 + 12);
+		next |= (u64)1   << (32 + 12);
+		ltc->tags_clear(ltc, tag, cnt);
+	}
+
+	while (cnt--) {
+		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+		phys += next;
+		pte  += 8;
+	}
+}
+
+static void
+gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+		struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
+	/* compressed storage types are invalid for system memory */
+	u32 memtype = gf100_pte_storage_type_map[mem->memtype & 0xff];
+
+	pte <<= 3;
+	while (cnt--) {
+		u64 phys = gf100_vm_addr(vma, *list++, memtype, target);
+		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+		pte += 8;
+	}
+}
+
+static void
+gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+	pte <<= 3;
+	while (cnt--) {
+		nv_wo32(pgt, pte + 0, 0x00000000);
+		nv_wo32(pgt, pte + 4, 0x00000000);
+		pte += 8;
+	}
+}
+
+static void
+gf100_vm_flush(struct nvkm_vm *vm)
+{
+	struct gf100_mmu_priv *priv = (void *)vm->mmu;
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct nvkm_vm_pgd *vpgd;
+	u32 type;
+
+	bar->flush(bar);
+
+	type = 0x00000001; /* PAGE_ALL */
+	if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
+		type |= 0x00000004; /* HUB_ONLY */
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	list_for_each_entry(vpgd, &vm->pgd_list, head) {
+		/* looks like maybe a "free flush slots" counter, the
+		 * faster you write to 0x100cbc to more it decreases
+		 */
+		if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
+			nv_error(priv, "vm timeout 0: 0x%08x %d\n",
+				 nv_rd32(priv, 0x100c80), type);
+		}
+
+		nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
+		nv_wr32(priv, 0x100cbc, 0x80000000 | type);
+
+		/* wait for flush to be queued? */
+		if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
+			nv_error(priv, "vm timeout 1: 0x%08x %d\n",
+				 nv_rd32(priv, 0x100c80), type);
+		}
+	}
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gf100_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
+		struct nvkm_vm **pvm)
+{
+	return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, pvm);
+}
+
+static int
+gf100_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gf100_mmu_priv *priv;
+	int ret;
+
+	ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.limit = 1ULL << 40;
+	priv->base.dma_bits = 40;
+	priv->base.pgt_bits  = 27 - 12;
+	priv->base.spg_shift = 12;
+	priv->base.lpg_shift = 17;
+	priv->base.create = gf100_vm_create;
+	priv->base.map_pgt = gf100_vm_map_pgt;
+	priv->base.map = gf100_vm_map;
+	priv->base.map_sg = gf100_vm_map_sg;
+	priv->base.unmap = gf100_vm_unmap;
+	priv->base.flush = gf100_vm_flush;
+	return 0;
+}
+
+struct nvkm_oclass
+gf100_mmu_oclass = {
+	.handle = NV_SUBDEV(MMU, 0xc0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf100_mmu_ctor,
+		.dtor = _nvkm_mmu_dtor,
+		.init = _nvkm_mmu_init,
+		.fini = _nvkm_mmu_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c
new file mode 100644
index 0000000..fe93ea2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+
+#define NV04_PDMA_SIZE (128 * 1024 * 1024)
+#define NV04_PDMA_PAGE (  4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	       struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+	pte = 0x00008 + (pte * 4);
+	while (cnt) {
+		u32 page = PAGE_SIZE / NV04_PDMA_PAGE;
+		u32 phys = (u32)*list++;
+		while (cnt && page--) {
+			nv_wo32(pgt, pte, phys | 3);
+			phys += NV04_PDMA_PAGE;
+			pte += 4;
+			cnt -= 1;
+		}
+	}
+}
+
+static void
+nv04_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+	pte = 0x00008 + (pte * 4);
+	while (cnt--) {
+		nv_wo32(pgt, pte, 0x00000000);
+		pte += 4;
+	}
+}
+
+static void
+nv04_vm_flush(struct nvkm_vm *vm)
+{
+}
+
+/*******************************************************************************
+ * VM object
+ ******************************************************************************/
+
+int
+nv04_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mmstart,
+	       struct nvkm_vm **pvm)
+{
+	return -EINVAL;
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv04_mmu_priv *priv;
+	struct nvkm_gpuobj *dma;
+	int ret;
+
+	ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART",
+			      "pcigart", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV04_PDMA_SIZE;
+	priv->base.dma_bits = 32;
+	priv->base.pgt_bits = 32 - 12;
+	priv->base.spg_shift = 12;
+	priv->base.lpg_shift = 12;
+	priv->base.map_sg = nv04_vm_map_sg;
+	priv->base.unmap = nv04_vm_unmap;
+	priv->base.flush = nv04_vm_flush;
+
+	ret = nvkm_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096,
+			     &priv->vm);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+			      (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + 8,
+			      16, NVOBJ_FLAG_ZERO_ALLOC,
+			      &priv->vm->pgt[0].obj[0]);
+	dma = priv->vm->pgt[0].obj[0];
+	priv->vm->pgt[0].refcount[0] = 1;
+	if (ret)
+		return ret;
+
+	nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */
+	nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1);
+	return 0;
+}
+
+void
+nv04_mmu_dtor(struct nvkm_object *object)
+{
+	struct nv04_mmu_priv *priv = (void *)object;
+	if (priv->vm) {
+		nvkm_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]);
+		nvkm_vm_ref(NULL, &priv->vm, NULL);
+	}
+	if (priv->nullp) {
+		pci_free_consistent(nv_device(priv)->pdev, 16 * 1024,
+				    priv->nullp, priv->null);
+	}
+	nvkm_mmu_destroy(&priv->base);
+}
+
+struct nvkm_oclass
+nv04_mmu_oclass = {
+	.handle = NV_SUBDEV(MMU, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_mmu_ctor,
+		.dtor = nv04_mmu_dtor,
+		.init = _nvkm_mmu_init,
+		.fini = _nvkm_mmu_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h
new file mode 100644
index 0000000..7bf6f4b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h
@@ -0,0 +1,19 @@
+#ifndef __NV04_MMU_PRIV__
+#define __NV04_MMU_PRIV__
+
+#include <subdev/mmu.h>
+
+struct nv04_mmu_priv {
+	struct nvkm_mmu base;
+	struct nvkm_vm *vm;
+	dma_addr_t null;
+	void *nullp;
+};
+
+static inline struct nv04_mmu_priv *
+nv04_mmu(void *obj)
+{
+	return (void *)nvkm_mmu(obj);
+}
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c
new file mode 100644
index 0000000..61ee3ab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+#include <subdev/timer.h>
+
+#define NV41_GART_SIZE (512 * 1024 * 1024)
+#define NV41_GART_PAGE (  4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	       struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+	pte = pte * 4;
+	while (cnt) {
+		u32 page = PAGE_SIZE / NV41_GART_PAGE;
+		u64 phys = (u64)*list++;
+		while (cnt && page--) {
+			nv_wo32(pgt, pte, (phys >> 7) | 1);
+			phys += NV41_GART_PAGE;
+			pte += 4;
+			cnt -= 1;
+		}
+	}
+}
+
+static void
+nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+	pte = pte * 4;
+	while (cnt--) {
+		nv_wo32(pgt, pte, 0x00000000);
+		pte += 4;
+	}
+}
+
+static void
+nv41_vm_flush(struct nvkm_vm *vm)
+{
+	struct nv04_mmu_priv *priv = (void *)vm->mmu;
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	nv_wr32(priv, 0x100810, 0x00000022);
+	if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) {
+		nv_warn(priv, "flush timeout, 0x%08x\n",
+			nv_rd32(priv, 0x100810));
+	}
+	nv_wr32(priv, 0x100810, 0x00000000);
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nv04_mmu_priv *priv;
+	int ret;
+
+	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
+	    !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) {
+		return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass,
+					data, size, pobject);
+	}
+
+	ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART",
+			      "pciegart", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV41_GART_SIZE;
+	priv->base.dma_bits = 39;
+	priv->base.pgt_bits = 32 - 12;
+	priv->base.spg_shift = 12;
+	priv->base.lpg_shift = 12;
+	priv->base.map_sg = nv41_vm_map_sg;
+	priv->base.unmap = nv41_vm_unmap;
+	priv->base.flush = nv41_vm_flush;
+
+	ret = nvkm_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096,
+			     &priv->vm);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+			      (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16,
+			      NVOBJ_FLAG_ZERO_ALLOC,
+			      &priv->vm->pgt[0].obj[0]);
+	priv->vm->pgt[0].refcount[0] = 1;
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv41_mmu_init(struct nvkm_object *object)
+{
+	struct nv04_mmu_priv *priv = (void *)object;
+	struct nvkm_gpuobj *dma = priv->vm->pgt[0].obj[0];
+	int ret;
+
+	ret = nvkm_mmu_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x100800, dma->addr | 0x00000002);
+	nv_mask(priv, 0x10008c, 0x00000100, 0x00000100);
+	nv_wr32(priv, 0x100820, 0x00000000);
+	return 0;
+}
+
+struct nvkm_oclass
+nv41_mmu_oclass = {
+	.handle = NV_SUBDEV(MMU, 0x41),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv41_mmu_ctor,
+		.dtor = nv04_mmu_dtor,
+		.init = nv41_mmu_init,
+		.fini = _nvkm_mmu_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c
new file mode 100644
index 0000000..b90ded1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+#include <subdev/timer.h>
+
+#define NV44_GART_SIZE (512 * 1024 * 1024)
+#define NV44_GART_PAGE (  4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null,
+	     dma_addr_t *list, u32 pte, u32 cnt)
+{
+	u32 base = (pte << 2) & ~0x0000000f;
+	u32 tmp[4];
+
+	tmp[0] = nv_ro32(pgt, base + 0x0);
+	tmp[1] = nv_ro32(pgt, base + 0x4);
+	tmp[2] = nv_ro32(pgt, base + 0x8);
+	tmp[3] = nv_ro32(pgt, base + 0xc);
+
+	while (cnt--) {
+		u32 addr = list ? (*list++ >> 12) : (null >> 12);
+		switch (pte++ & 0x3) {
+		case 0:
+			tmp[0] &= ~0x07ffffff;
+			tmp[0] |= addr;
+			break;
+		case 1:
+			tmp[0] &= ~0xf8000000;
+			tmp[0] |= addr << 27;
+			tmp[1] &= ~0x003fffff;
+			tmp[1] |= addr >> 5;
+			break;
+		case 2:
+			tmp[1] &= ~0xffc00000;
+			tmp[1] |= addr << 22;
+			tmp[2] &= ~0x0001ffff;
+			tmp[2] |= addr >> 10;
+			break;
+		case 3:
+			tmp[2] &= ~0xfffe0000;
+			tmp[2] |= addr << 17;
+			tmp[3] &= ~0x00000fff;
+			tmp[3] |= addr >> 15;
+			break;
+		}
+	}
+
+	nv_wo32(pgt, base + 0x0, tmp[0]);
+	nv_wo32(pgt, base + 0x4, tmp[1]);
+	nv_wo32(pgt, base + 0x8, tmp[2]);
+	nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000);
+}
+
+static void
+nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	       struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+	struct nv04_mmu_priv *priv = (void *)vma->vm->mmu;
+	u32 tmp[4];
+	int i;
+
+	if (pte & 3) {
+		u32  max = 4 - (pte & 3);
+		u32 part = (cnt > max) ? max : cnt;
+		nv44_vm_fill(pgt, priv->null, list, pte, part);
+		pte  += part;
+		list += part;
+		cnt  -= part;
+	}
+
+	while (cnt >= 4) {
+		for (i = 0; i < 4; i++)
+			tmp[i] = *list++ >> 12;
+		nv_wo32(pgt, pte++ * 4, tmp[0] >>  0 | tmp[1] << 27);
+		nv_wo32(pgt, pte++ * 4, tmp[1] >>  5 | tmp[2] << 22);
+		nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17);
+		nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000);
+		cnt -= 4;
+	}
+
+	if (cnt)
+		nv44_vm_fill(pgt, priv->null, list, pte, cnt);
+}
+
+static void
+nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+	struct nv04_mmu_priv *priv = (void *)nvkm_mmu(pgt);
+
+	if (pte & 3) {
+		u32  max = 4 - (pte & 3);
+		u32 part = (cnt > max) ? max : cnt;
+		nv44_vm_fill(pgt, priv->null, NULL, pte, part);
+		pte  += part;
+		cnt  -= part;
+	}
+
+	while (cnt >= 4) {
+		nv_wo32(pgt, pte++ * 4, 0x00000000);
+		nv_wo32(pgt, pte++ * 4, 0x00000000);
+		nv_wo32(pgt, pte++ * 4, 0x00000000);
+		nv_wo32(pgt, pte++ * 4, 0x00000000);
+		cnt -= 4;
+	}
+
+	if (cnt)
+		nv44_vm_fill(pgt, priv->null, NULL, pte, cnt);
+}
+
+static void
+nv44_vm_flush(struct nvkm_vm *vm)
+{
+	struct nv04_mmu_priv *priv = (void *)vm->mmu;
+	nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE);
+	nv_wr32(priv, 0x100808, 0x00000020);
+	if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001))
+		nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808));
+	nv_wr32(priv, 0x100808, 0x00000000);
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nv04_mmu_priv *priv;
+	int ret;
+
+	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
+	    !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) {
+		return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass,
+					data, size, pobject);
+	}
+
+	ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART",
+			      "pciegart", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.create = nv04_vm_create;
+	priv->base.limit = NV44_GART_SIZE;
+	priv->base.dma_bits = 39;
+	priv->base.pgt_bits = 32 - 12;
+	priv->base.spg_shift = 12;
+	priv->base.lpg_shift = 12;
+	priv->base.map_sg = nv44_vm_map_sg;
+	priv->base.unmap = nv44_vm_unmap;
+	priv->base.flush = nv44_vm_flush;
+
+	priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null);
+	if (!priv->nullp) {
+		nv_error(priv, "unable to allocate dummy pages\n");
+		return -ENOMEM;
+	}
+
+	ret = nvkm_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096,
+			     &priv->vm);
+	if (ret)
+		return ret;
+
+	ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+			      (NV44_GART_SIZE / NV44_GART_PAGE) * 4,
+			      512 * 1024, NVOBJ_FLAG_ZERO_ALLOC,
+			      &priv->vm->pgt[0].obj[0]);
+	priv->vm->pgt[0].refcount[0] = 1;
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+nv44_mmu_init(struct nvkm_object *object)
+{
+	struct nv04_mmu_priv *priv = (void *)object;
+	struct nvkm_gpuobj *gart = priv->vm->pgt[0].obj[0];
+	u32 addr;
+	int ret;
+
+	ret = nvkm_mmu_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* calculate vram address of this PRAMIN block, object must be
+	 * allocated on 512KiB alignment, and not exceed a total size
+	 * of 512KiB for this to work correctly
+	 */
+	addr  = nv_rd32(priv, 0x10020c);
+	addr -= ((gart->addr >> 19) + 1) << 19;
+
+	nv_wr32(priv, 0x100850, 0x80000000);
+	nv_wr32(priv, 0x100818, priv->null);
+	nv_wr32(priv, 0x100804, NV44_GART_SIZE);
+	nv_wr32(priv, 0x100850, 0x00008000);
+	nv_mask(priv, 0x10008c, 0x00000200, 0x00000200);
+	nv_wr32(priv, 0x100820, 0x00000000);
+	nv_wr32(priv, 0x10082c, 0x00000001);
+	nv_wr32(priv, 0x100800, addr | 0x00000010);
+	return 0;
+}
+
+struct nvkm_oclass
+nv44_mmu_oclass = {
+	.handle = NV_SUBDEV(MMU, 0x44),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv44_mmu_ctor,
+		.dtor = nv04_mmu_dtor,
+		.init = nv44_mmu_init,
+		.fini = _nvkm_mmu_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
new file mode 100644
index 0000000..b83550f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2010 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <core/engine.h>
+#include <core/gpuobj.h>
+
+struct nv50_mmu_priv {
+	struct nvkm_mmu base;
+};
+
+static void
+nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2])
+{
+	u64 phys = 0xdeadcafe00000000ULL;
+	u32 coverage = 0;
+
+	if (pgt[0]) {
+		phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */
+		coverage = (pgt[0]->size >> 3) << 12;
+	} else
+	if (pgt[1]) {
+		phys = 0x00000001 | pgt[1]->addr; /* present */
+		coverage = (pgt[1]->size >> 3) << 16;
+	}
+
+	if (phys & 1) {
+		if (coverage <= 32 * 1024 * 1024)
+			phys |= 0x60;
+		else if (coverage <= 64 * 1024 * 1024)
+			phys |= 0x40;
+		else if (coverage <= 128 * 1024 * 1024)
+			phys |= 0x20;
+	}
+
+	nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys));
+	nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys));
+}
+
+static inline u64
+vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target)
+{
+	phys |= 1; /* present */
+	phys |= (u64)memtype << 40;
+	phys |= target << 4;
+	if (vma->access & NV_MEM_ACCESS_SYS)
+		phys |= (1 << 6);
+	if (!(vma->access & NV_MEM_ACCESS_WO))
+		phys |= (1 << 3);
+	return phys;
+}
+
+static void
+nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	    struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
+{
+	u32 comp = (mem->memtype & 0x180) >> 7;
+	u32 block, target;
+	int i;
+
+	/* IGPs don't have real VRAM, re-target to stolen system memory */
+	target = 0;
+	if (nvkm_fb(vma->vm->mmu)->ram->stolen) {
+		phys += nvkm_fb(vma->vm->mmu)->ram->stolen;
+		target = 3;
+	}
+
+	phys  = vm_addr(vma, phys, mem->memtype, target);
+	pte <<= 3;
+	cnt <<= 3;
+
+	while (cnt) {
+		u32 offset_h = upper_32_bits(phys);
+		u32 offset_l = lower_32_bits(phys);
+
+		for (i = 7; i >= 0; i--) {
+			block = 1 << (i + 3);
+			if (cnt >= block && !(pte & (block - 1)))
+				break;
+		}
+		offset_l |= (i << 7);
+
+		phys += block << (vma->node->type - 3);
+		cnt  -= block;
+		if (comp) {
+			u32 tag = mem->tag->offset + ((delta >> 16) * comp);
+			offset_h |= (tag << 17);
+			delta    += block << (vma->node->type - 3);
+		}
+
+		while (block) {
+			nv_wo32(pgt, pte + 0, offset_l);
+			nv_wo32(pgt, pte + 4, offset_h);
+			pte += 8;
+			block -= 8;
+		}
+	}
+}
+
+static void
+nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+	       struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+	u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
+	pte <<= 3;
+	while (cnt--) {
+		u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
+		nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+		nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+		pte += 8;
+	}
+}
+
+static void
+nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+	pte <<= 3;
+	while (cnt--) {
+		nv_wo32(pgt, pte + 0, 0x00000000);
+		nv_wo32(pgt, pte + 4, 0x00000000);
+		pte += 8;
+	}
+}
+
+static void
+nv50_vm_flush(struct nvkm_vm *vm)
+{
+	struct nv50_mmu_priv *priv = (void *)vm->mmu;
+	struct nvkm_bar *bar = nvkm_bar(priv);
+	struct nvkm_engine *engine;
+	int i, vme;
+
+	bar->flush(bar);
+
+	mutex_lock(&nv_subdev(priv)->mutex);
+	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+		if (!atomic_read(&vm->engref[i]))
+			continue;
+
+		/* unfortunate hw bug workaround... */
+		engine = nvkm_engine(priv, i);
+		if (engine && engine->tlb_flush) {
+			engine->tlb_flush(engine);
+			continue;
+		}
+
+		switch (i) {
+		case NVDEV_ENGINE_GR    : vme = 0x00; break;
+		case NVDEV_ENGINE_VP    :
+		case NVDEV_ENGINE_MSPDEC: vme = 0x01; break;
+		case NVDEV_SUBDEV_BAR   : vme = 0x06; break;
+		case NVDEV_ENGINE_MSPPP :
+		case NVDEV_ENGINE_MPEG  : vme = 0x08; break;
+		case NVDEV_ENGINE_BSP   :
+		case NVDEV_ENGINE_MSVLD : vme = 0x09; break;
+		case NVDEV_ENGINE_CIPHER:
+		case NVDEV_ENGINE_SEC   : vme = 0x0a; break;
+		case NVDEV_ENGINE_CE0   : vme = 0x0d; break;
+		default:
+			continue;
+		}
+
+		nv_wr32(priv, 0x100c80, (vme << 16) | 1);
+		if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+			nv_error(priv, "vm flush timeout: engine %d\n", vme);
+	}
+	mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length,
+	       u64 mm_offset, struct nvkm_vm **pvm)
+{
+	u32 block = (1 << (mmu->pgt_bits + 12));
+	if (block > length)
+		block = length;
+
+	return nvkm_vm_create(mmu, offset, length, mm_offset, block, pvm);
+}
+
+static int
+nv50_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_mmu_priv *priv;
+	int ret;
+
+	ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.limit = 1ULL << 40;
+	priv->base.dma_bits = 40;
+	priv->base.pgt_bits  = 29 - 12;
+	priv->base.spg_shift = 12;
+	priv->base.lpg_shift = 16;
+	priv->base.create = nv50_vm_create;
+	priv->base.map_pgt = nv50_vm_map_pgt;
+	priv->base.map = nv50_vm_map;
+	priv->base.map_sg = nv50_vm_map_sg;
+	priv->base.unmap = nv50_vm_unmap;
+	priv->base.flush = nv50_vm_flush;
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_mmu_oclass = {
+	.handle = NV_SUBDEV(MMU, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_mmu_ctor,
+		.dtor = _nvkm_mmu_dtor,
+		.init = _nvkm_mmu_init,
+		.fini = _nvkm_mmu_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild
new file mode 100644
index 0000000..1a479e0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/mxm/base.o
+nvkm-y += nvkm/subdev/mxm/mxms.o
+nvkm-y += nvkm/subdev/mxm/nv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
new file mode 100644
index 0000000..0ca9dca
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/mxm.h>
+#include <subdev/i2c.h>
+
+static bool
+mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr,
+		     u8 offset, u8 size, u8 *data)
+{
+	struct i2c_msg msgs[] = {
+		{ .addr = addr, .flags = 0, .len = 1, .buf = &offset },
+		{ .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
+	};
+
+	return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+}
+
+static bool
+mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version)
+{
+	struct nvkm_bios *bios = nvkm_bios(mxm);
+	struct nvkm_i2c *i2c = nvkm_i2c(mxm);
+	struct nvkm_i2c_port *port = NULL;
+	u8 i2cidx, mxms[6], addr, size;
+
+	i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f;
+	if (i2cidx < 0x0f)
+		port = i2c->find(i2c, i2cidx);
+	if (!port)
+		return false;
+
+	addr = 0x54;
+	if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) {
+		addr = 0x56;
+		if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms))
+			return false;
+	}
+
+	mxm->mxms = mxms;
+	size = mxms_headerlen(mxm) + mxms_structlen(mxm);
+	mxm->mxms = kmalloc(size, GFP_KERNEL);
+
+	if (mxm->mxms &&
+	    mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms))
+		return true;
+
+	kfree(mxm->mxms);
+	mxm->mxms = NULL;
+	return false;
+}
+
+#if defined(CONFIG_ACPI)
+static bool
+mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
+{
+	struct nvkm_device *device = nv_device(mxm);
+	static char muid[] = {
+		0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
+		0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
+	};
+	u32 mxms_args[] = { 0x00000000 };
+	union acpi_object argv4 = {
+		.buffer.type = ACPI_TYPE_BUFFER,
+		.buffer.length = sizeof(mxms_args),
+		.buffer.pointer = (char *)mxms_args,
+	};
+	union acpi_object *obj;
+	acpi_handle handle;
+	int rev;
+
+	handle = ACPI_HANDLE(nv_device_base(device));
+	if (!handle)
+		return false;
+
+	/*
+	 * spec says this can be zero to mean "highest revision", but
+	 * of course there's at least one bios out there which fails
+	 * unless you pass in exactly the version it supports..
+	 */
+	rev = (version & 0xf0) << 4 | (version & 0x0f);
+	obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
+	if (!obj) {
+		nv_debug(mxm, "DSM MXMS failed\n");
+		return false;
+	}
+
+	if (obj->type == ACPI_TYPE_BUFFER) {
+		mxm->mxms = kmemdup(obj->buffer.pointer,
+					 obj->buffer.length, GFP_KERNEL);
+	} else if (obj->type == ACPI_TYPE_INTEGER) {
+		nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value);
+	}
+
+	ACPI_FREE(obj);
+	return mxm->mxms != NULL;
+}
+#endif
+
+#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
+
+#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+static u8
+wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version)
+{
+	u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
+	struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
+	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+	if (ACPI_FAILURE(status)) {
+		nv_debug(mxm, "WMMX MXMI returned %d\n", status);
+		return 0x00;
+	}
+
+	obj = retn.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		version = obj->integer.value;
+		nv_debug(mxm, "WMMX MXMI version %d.%d\n",
+			     (version >> 4), version & 0x0f);
+	} else {
+		version = 0;
+		nv_debug(mxm, "WMMX MXMI returned non-integer\n");
+	}
+
+	kfree(obj);
+	return version;
+}
+
+static bool
+mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version)
+{
+	u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 };
+	struct acpi_buffer args = { sizeof(mxms_args), mxms_args };
+	struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	if (!wmi_has_guid(WMI_WMMX_GUID)) {
+		nv_debug(mxm, "WMMX GUID not found\n");
+		return false;
+	}
+
+	mxms_args[1] = wmi_wmmx_mxmi(mxm, 0x00);
+	if (!mxms_args[1])
+		mxms_args[1] = wmi_wmmx_mxmi(mxm, version);
+	if (!mxms_args[1])
+		return false;
+
+	status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+	if (ACPI_FAILURE(status)) {
+		nv_debug(mxm, "WMMX MXMS returned %d\n", status);
+		return false;
+	}
+
+	obj = retn.pointer;
+	if (obj->type == ACPI_TYPE_BUFFER) {
+		mxm->mxms = kmemdup(obj->buffer.pointer,
+				    obj->buffer.length, GFP_KERNEL);
+	}
+
+	kfree(obj);
+	return mxm->mxms != NULL;
+}
+#endif
+
+static struct mxm_shadow_h {
+	const char *name;
+	bool (*exec)(struct nvkm_mxm *, u8 version);
+} _mxm_shadow[] = {
+	{ "ROM", mxm_shadow_rom },
+#if defined(CONFIG_ACPI)
+	{ "DSM", mxm_shadow_dsm },
+#endif
+#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
+	{ "WMI", mxm_shadow_wmi },
+#endif
+	{}
+};
+
+static int
+mxm_shadow(struct nvkm_mxm *mxm, u8 version)
+{
+	struct mxm_shadow_h *shadow = _mxm_shadow;
+	do {
+		nv_debug(mxm, "checking %s\n", shadow->name);
+		if (shadow->exec(mxm, version)) {
+			if (mxms_valid(mxm))
+				return 0;
+			kfree(mxm->mxms);
+			mxm->mxms = NULL;
+		}
+	} while ((++shadow)->name);
+	return -ENOENT;
+}
+
+int
+nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_device *device = nv_device(parent);
+	struct nvkm_bios *bios = nvkm_bios(device);
+	struct nvkm_mxm *mxm;
+	u8  ver, len;
+	u16 data;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm",
+				  length, pobject);
+	mxm = *pobject;
+	if (ret)
+		return ret;
+
+	data = mxm_table(bios, &ver, &len);
+	if (!data || !(ver = nv_ro08(bios, data))) {
+		nv_debug(mxm, "no VBIOS data, nothing to do\n");
+		return 0;
+	}
+
+	nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f);
+
+	if (mxm_shadow(mxm, ver)) {
+		nv_info(mxm, "failed to locate valid SIS\n");
+#if 0
+		/* we should, perhaps, fall back to some kind of limited
+		 * mode here if the x86 vbios hasn't already done the
+		 * work for us (so we prevent loading with completely
+		 * whacked vbios tables).
+		 */
+		return -EINVAL;
+#else
+		return 0;
+#endif
+	}
+
+	nv_info(mxm, "MXMS Version %d.%d\n",
+		mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff);
+	mxms_foreach(mxm, 0, NULL, NULL);
+
+	if (nvkm_boolopt(device->cfgopt, "NvMXMDCB", true))
+		mxm->action |= MXM_SANITISE_DCB;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
new file mode 100644
index 0000000..a9b1d63
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
+#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
+
+static u8 *
+mxms_data(struct nvkm_mxm *mxm)
+{
+	return mxm->mxms;
+
+}
+
+u16
+mxms_version(struct nvkm_mxm *mxm)
+{
+	u8 *mxms = mxms_data(mxm);
+	u16 version = (mxms[4] << 8) | mxms[5];
+	switch (version ) {
+	case 0x0200:
+	case 0x0201:
+	case 0x0300:
+		return version;
+	default:
+		break;
+	}
+
+	nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]);
+	return 0x0000;
+}
+
+u16
+mxms_headerlen(struct nvkm_mxm *mxm)
+{
+	return 8;
+}
+
+u16
+mxms_structlen(struct nvkm_mxm *mxm)
+{
+	return *(u16 *)&mxms_data(mxm)[6];
+}
+
+bool
+mxms_checksum(struct nvkm_mxm *mxm)
+{
+	u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
+	u8 *mxms = mxms_data(mxm), sum = 0;
+	while (size--)
+		sum += *mxms++;
+	if (sum) {
+		nv_debug(mxm, "checksum invalid\n");
+		return false;
+	}
+	return true;
+}
+
+bool
+mxms_valid(struct nvkm_mxm *mxm)
+{
+	u8 *mxms = mxms_data(mxm);
+	if (*(u32 *)mxms != 0x5f4d584d) {
+		nv_debug(mxm, "signature invalid\n");
+		return false;
+	}
+
+	if (!mxms_version(mxm) || !mxms_checksum(mxm))
+		return false;
+
+	return true;
+}
+
+bool
+mxms_foreach(struct nvkm_mxm *mxm, u8 types,
+	     bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info)
+{
+	u8 *mxms = mxms_data(mxm);
+	u8 *desc = mxms + mxms_headerlen(mxm);
+	u8 *fini = desc + mxms_structlen(mxm) - 1;
+	while (desc < fini) {
+		u8 type = desc[0] & 0x0f;
+		u8 headerlen = 0;
+		u8 recordlen = 0;
+		u8 entries = 0;
+
+		switch (type) {
+		case 0: /* Output Device Structure */
+			if (mxms_version(mxm) >= 0x0300)
+				headerlen = 8;
+			else
+				headerlen = 6;
+			break;
+		case 1: /* System Cooling Capability Structure */
+		case 2: /* Thermal Structure */
+		case 3: /* Input Power Structure */
+			headerlen = 4;
+			break;
+		case 4: /* GPIO Device Structure */
+			headerlen = 4;
+			recordlen = 2;
+			entries   = (ROM32(desc[0]) & 0x01f00000) >> 20;
+			break;
+		case 5: /* Vendor Specific Structure */
+			headerlen = 8;
+			break;
+		case 6: /* Backlight Control Structure */
+			if (mxms_version(mxm) >= 0x0300) {
+				headerlen = 4;
+				recordlen = 8;
+				entries   = (desc[1] & 0xf0) >> 4;
+			} else {
+				headerlen = 8;
+			}
+			break;
+		case 7: /* Fan Control Structure */
+			headerlen = 8;
+			recordlen = 4;
+			entries   = desc[1] & 0x07;
+			break;
+		default:
+			nv_debug(mxm, "unknown descriptor type %d\n", type);
+			return false;
+		}
+
+		if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) {
+			static const char * mxms_desc_name[] = {
+				"ODS", "SCCS", "TS", "IPS",
+				"GSD", "VSS", "BCS", "FCS",
+			};
+			u8 *dump = desc;
+			int i, j;
+
+			nv_debug(mxm, "%4s: ", mxms_desc_name[type]);
+			for (j = headerlen - 1; j >= 0; j--)
+				pr_cont("%02x", dump[j]);
+			pr_cont("\n");
+			dump += headerlen;
+
+			for (i = 0; i < entries; i++, dump += recordlen) {
+				nv_debug(mxm, "      ");
+				for (j = recordlen - 1; j >= 0; j--)
+					pr_cont("%02x", dump[j]);
+				pr_cont("\n");
+			}
+		}
+
+		if (types & (1 << type)) {
+			if (!exec(mxm, desc, info))
+				return false;
+		}
+
+		desc += headerlen + (entries * recordlen);
+	}
+
+	return true;
+}
+
+void
+mxms_output_device(struct nvkm_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
+{
+	u64 data = ROM32(pdata[0]);
+	if (mxms_version(mxm) >= 0x0300)
+		data |= (u64)ROM16(pdata[4]) << 32;
+
+	desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
+	desc->ddc_port  = (data & 0x0000000000000f00ULL) >> 8;
+	desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
+	desc->dig_conn  = (data & 0x0000000000780000ULL) >> 19;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h
new file mode 100644
index 0000000..4ef8040
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h
@@ -0,0 +1,22 @@
+#ifndef __NVMXM_MXMS_H__
+#define __NVMXM_MXMS_H__
+#include <subdev/mxm.h>
+
+struct mxms_odev {
+	u8 outp_type;
+	u8 conn_type;
+	u8 ddc_port;
+	u8 dig_conn;
+};
+
+void mxms_output_device(struct nvkm_mxm *, u8 *, struct mxms_odev *);
+
+u16  mxms_version(struct nvkm_mxm *);
+u16  mxms_headerlen(struct nvkm_mxm *);
+u16  mxms_structlen(struct nvkm_mxm *);
+bool mxms_checksum(struct nvkm_mxm *);
+bool mxms_valid(struct nvkm_mxm *);
+
+bool mxms_foreach(struct nvkm_mxm *, u8,
+		  bool (*)(struct nvkm_mxm *, u8 *, void *), void *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c
new file mode 100644
index 0000000..42cac13
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/mxm.h>
+
+struct nv50_mxm_priv {
+	struct nvkm_mxm base;
+};
+
+struct context {
+	u32 *outp;
+	struct mxms_odev desc;
+};
+
+static bool
+mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+	struct context *ctx = info;
+	struct mxms_odev desc;
+
+	mxms_output_device(mxm, data, &desc);
+	if (desc.outp_type == 2 &&
+	    desc.dig_conn == ctx->desc.dig_conn)
+		return false;
+	return true;
+}
+
+static bool
+mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+	struct nvkm_bios *bios = nvkm_bios(mxm);
+	struct context *ctx = info;
+	u64 desc = *(u64 *)data;
+
+	mxms_output_device(mxm, data, &ctx->desc);
+
+	/* match dcb encoder type to mxm-ods device type */
+	if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
+		return true;
+
+	/* digital output, have some extra stuff to match here, there's a
+	 * table in the vbios that provides a mapping from the mxm digital
+	 * connection enum values to SOR/link
+	 */
+	if ((desc & 0x00000000000000f0) >= 0x20) {
+		/* check against sor index */
+		u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
+		if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
+			return true;
+
+		/* check dcb entry has a compatible link field */
+		link = (link & 0x30) >> 4;
+		if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
+			return true;
+	}
+
+	/* mark this descriptor accounted for by setting invalid device type,
+	 * except of course some manufactures don't follow specs properly and
+	 * we need to avoid killing off the TMDS function on DP connectors
+	 * if MXM-SIS is missing an entry for it.
+	 */
+	data[0] &= ~0xf0;
+	if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
+	    mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
+		data[0] |= 0x20; /* modify descriptor to match TMDS now */
+	} else {
+		data[0] |= 0xf0;
+	}
+
+	return false;
+}
+
+static int
+mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb)
+{
+	struct nvkm_mxm *mxm = data;
+	struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
+	u8 type, i2cidx, link, ver, len;
+	u8 *conn;
+
+	/* look for an output device structure that matches this dcb entry.
+	 * if one isn't found, disable it.
+	 */
+	if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
+		nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n",
+			idx, ctx.outp[0], ctx.outp[1]);
+		ctx.outp[0] |= 0x0000000f;
+		return 0;
+	}
+
+	/* modify the output's ddc/aux port, there's a pointer to a table
+	 * with the mapping from mxm ddc/aux port to dcb i2c_index in the
+	 * vbios mxm table
+	 */
+	i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
+	if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
+		i2cidx = (i2cidx & 0x0f) << 4;
+	else
+		i2cidx = (i2cidx & 0xf0);
+
+	if (i2cidx != 0xf0) {
+		ctx.outp[0] &= ~0x000000f0;
+		ctx.outp[0] |= i2cidx;
+	}
+
+	/* override dcb sorconf.link, based on what mxm data says */
+	switch (ctx.desc.outp_type) {
+	case 0x00: /* Analog CRT */
+	case 0x01: /* Analog TV/HDTV */
+		break;
+	default:
+		link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
+		ctx.outp[1] &= ~0x00000030;
+		ctx.outp[1] |= link;
+		break;
+	}
+
+	/* we may need to fixup various other vbios tables based on what
+	 * the descriptor says the connector type should be.
+	 *
+	 * in a lot of cases, the vbios tables will claim DVI-I is possible,
+	 * and the mxm data says the connector is really HDMI.  another
+	 * common example is DP->eDP.
+	 */
+	conn  = bios->data;
+	conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
+	type  = conn[0];
+	switch (ctx.desc.conn_type) {
+	case 0x01: /* LVDS */
+		ctx.outp[1] |= 0x00000004; /* use_power_scripts */
+		/* XXX: modify default link width in LVDS table */
+		break;
+	case 0x02: /* HDMI */
+		type = DCB_CONNECTOR_HDMI_1;
+		break;
+	case 0x03: /* DVI-D */
+		type = DCB_CONNECTOR_DVI_D;
+		break;
+	case 0x0e: /* eDP, falls through to DPint */
+		ctx.outp[1] |= 0x00010000;
+	case 0x07: /* DP internal, wtf is this?? HP8670w */
+		ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
+		type = DCB_CONNECTOR_eDP;
+		break;
+	default:
+		break;
+	}
+
+	if (mxms_version(mxm) >= 0x0300)
+		conn[0] = type;
+
+	return 0;
+}
+
+static bool
+mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+	u64 desc = *(u64 *)data;
+	if ((desc & 0xf0) != 0xf0)
+	nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
+	return true;
+}
+
+static void
+mxm_dcb_sanitise(struct nvkm_mxm *mxm)
+{
+	struct nvkm_bios *bios = nvkm_bios(mxm);
+	u8  ver, hdr, cnt, len;
+	u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
+	if (dcb == 0x0000 || ver != 0x40) {
+		nv_debug(mxm, "unsupported DCB version\n");
+		return;
+	}
+
+	dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
+	mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
+}
+
+static int
+nv50_mxm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	      struct nvkm_oclass *oclass, void *data, u32 size,
+	      struct nvkm_object **pobject)
+{
+	struct nv50_mxm_priv *priv;
+	int ret;
+
+	ret = nvkm_mxm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	if (priv->base.action & MXM_SANITISE_DCB)
+		mxm_dcb_sanitise(&priv->base);
+	return 0;
+}
+
+struct nvkm_oclass
+nv50_mxm_oclass = {
+	.handle = NV_SUBDEV(MXM, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_mxm_ctor,
+		.dtor = _nvkm_mxm_dtor,
+		.init = _nvkm_mxm_init,
+		.fini = _nvkm_mxm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
new file mode 100644
index 0000000..9a150d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
@@ -0,0 +1,8 @@
+nvkm-y += nvkm/subdev/pmu/base.o
+nvkm-y += nvkm/subdev/pmu/memx.o
+nvkm-y += nvkm/subdev/pmu/gt215.o
+nvkm-y += nvkm/subdev/pmu/gf100.o
+nvkm-y += nvkm/subdev/pmu/gf110.o
+nvkm-y += nvkm/subdev/pmu/gk104.o
+nvkm-y += nvkm/subdev/pmu/gk208.o
+nvkm-y += nvkm/subdev/pmu/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
new file mode 100644
index 0000000..054b2d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/timer.h>
+
+void
+nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
+{
+	const struct nvkm_pmu_impl *impl = (void *)nv_oclass(pmu);
+	if (impl->pgob)
+		impl->pgob(pmu, enable);
+}
+
+static int
+nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2],
+	      u32 process, u32 message, u32 data0, u32 data1)
+{
+	struct nvkm_subdev *subdev = nv_subdev(pmu);
+	u32 addr;
+
+	/* wait for a free slot in the fifo */
+	addr  = nv_rd32(pmu, 0x10a4a0);
+	if (!nv_wait_ne(pmu, 0x10a4b0, 0xffffffff, addr ^ 8))
+		return -EBUSY;
+
+	/* we currently only support a single process at a time waiting
+	 * on a synchronous reply, take the PMU mutex and tell the
+	 * receive handler what we're waiting for
+	 */
+	if (reply) {
+		mutex_lock(&subdev->mutex);
+		pmu->recv.message = message;
+		pmu->recv.process = process;
+	}
+
+	/* acquire data segment access */
+	do {
+		nv_wr32(pmu, 0x10a580, 0x00000001);
+	} while (nv_rd32(pmu, 0x10a580) != 0x00000001);
+
+	/* write the packet */
+	nv_wr32(pmu, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
+				pmu->send.base));
+	nv_wr32(pmu, 0x10a1c4, process);
+	nv_wr32(pmu, 0x10a1c4, message);
+	nv_wr32(pmu, 0x10a1c4, data0);
+	nv_wr32(pmu, 0x10a1c4, data1);
+	nv_wr32(pmu, 0x10a4a0, (addr + 1) & 0x0f);
+
+	/* release data segment access */
+	nv_wr32(pmu, 0x10a580, 0x00000000);
+
+	/* wait for reply, if requested */
+	if (reply) {
+		wait_event(pmu->recv.wait, (pmu->recv.process == 0));
+		reply[0] = pmu->recv.data[0];
+		reply[1] = pmu->recv.data[1];
+		mutex_unlock(&subdev->mutex);
+	}
+
+	return 0;
+}
+
+static void
+nvkm_pmu_recv(struct work_struct *work)
+{
+	struct nvkm_pmu *pmu = container_of(work, struct nvkm_pmu, recv.work);
+	u32 process, message, data0, data1;
+
+	/* nothing to do if GET == PUT */
+	u32 addr =  nv_rd32(pmu, 0x10a4cc);
+	if (addr == nv_rd32(pmu, 0x10a4c8))
+		return;
+
+	/* acquire data segment access */
+	do {
+		nv_wr32(pmu, 0x10a580, 0x00000002);
+	} while (nv_rd32(pmu, 0x10a580) != 0x00000002);
+
+	/* read the packet */
+	nv_wr32(pmu, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
+				pmu->recv.base));
+	process = nv_rd32(pmu, 0x10a1c4);
+	message = nv_rd32(pmu, 0x10a1c4);
+	data0   = nv_rd32(pmu, 0x10a1c4);
+	data1   = nv_rd32(pmu, 0x10a1c4);
+	nv_wr32(pmu, 0x10a4cc, (addr + 1) & 0x0f);
+
+	/* release data segment access */
+	nv_wr32(pmu, 0x10a580, 0x00000000);
+
+	/* wake process if it's waiting on a synchronous reply */
+	if (pmu->recv.process) {
+		if (process == pmu->recv.process &&
+		    message == pmu->recv.message) {
+			pmu->recv.data[0] = data0;
+			pmu->recv.data[1] = data1;
+			pmu->recv.process = 0;
+			wake_up(&pmu->recv.wait);
+			return;
+		}
+	}
+
+	/* right now there's no other expected responses from the engine,
+	 * so assume that any unexpected message is an error.
+	 */
+	nv_warn(pmu, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
+		(char)((process & 0x000000ff) >>  0),
+		(char)((process & 0x0000ff00) >>  8),
+		(char)((process & 0x00ff0000) >> 16),
+		(char)((process & 0xff000000) >> 24),
+		process, message, data0, data1);
+}
+
+static void
+nvkm_pmu_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_pmu *pmu = (void *)subdev;
+	u32 disp = nv_rd32(pmu, 0x10a01c);
+	u32 intr = nv_rd32(pmu, 0x10a008) & disp & ~(disp >> 16);
+
+	if (intr & 0x00000020) {
+		u32 stat = nv_rd32(pmu, 0x10a16c);
+		if (stat & 0x80000000) {
+			nv_error(pmu, "UAS fault at 0x%06x addr 0x%08x\n",
+				 stat & 0x00ffffff, nv_rd32(pmu, 0x10a168));
+			nv_wr32(pmu, 0x10a16c, 0x00000000);
+			intr &= ~0x00000020;
+		}
+	}
+
+	if (intr & 0x00000040) {
+		schedule_work(&pmu->recv.work);
+		nv_wr32(pmu, 0x10a004, 0x00000040);
+		intr &= ~0x00000040;
+	}
+
+	if (intr & 0x00000080) {
+		nv_info(pmu, "wr32 0x%06x 0x%08x\n", nv_rd32(pmu, 0x10a7a0),
+						     nv_rd32(pmu, 0x10a7a4));
+		nv_wr32(pmu, 0x10a004, 0x00000080);
+		intr &= ~0x00000080;
+	}
+
+	if (intr) {
+		nv_error(pmu, "intr 0x%08x\n", intr);
+		nv_wr32(pmu, 0x10a004, intr);
+	}
+}
+
+int
+_nvkm_pmu_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_pmu *pmu = (void *)object;
+
+	nv_wr32(pmu, 0x10a014, 0x00000060);
+	flush_work(&pmu->recv.work);
+
+	return nvkm_subdev_fini(&pmu->base, suspend);
+}
+
+int
+_nvkm_pmu_init(struct nvkm_object *object)
+{
+	const struct nvkm_pmu_impl *impl = (void *)object->oclass;
+	struct nvkm_pmu *pmu = (void *)object;
+	int ret, i;
+
+	ret = nvkm_subdev_init(&pmu->base);
+	if (ret)
+		return ret;
+
+	nv_subdev(pmu)->intr = nvkm_pmu_intr;
+	pmu->message = nvkm_pmu_send;
+	pmu->pgob = nvkm_pmu_pgob;
+
+	/* prevent previous ucode from running, wait for idle, reset */
+	nv_wr32(pmu, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
+	nv_wait(pmu, 0x10a04c, 0xffffffff, 0x00000000);
+	nv_mask(pmu, 0x000200, 0x00002000, 0x00000000);
+	nv_mask(pmu, 0x000200, 0x00002000, 0x00002000);
+	nv_rd32(pmu, 0x000200);
+	nv_wait(pmu, 0x10a10c, 0x00000006, 0x00000000);
+
+	/* upload data segment */
+	nv_wr32(pmu, 0x10a1c0, 0x01000000);
+	for (i = 0; i < impl->data.size / 4; i++)
+		nv_wr32(pmu, 0x10a1c4, impl->data.data[i]);
+
+	/* upload code segment */
+	nv_wr32(pmu, 0x10a180, 0x01000000);
+	for (i = 0; i < impl->code.size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(pmu, 0x10a188, i >> 6);
+		nv_wr32(pmu, 0x10a184, impl->code.data[i]);
+	}
+
+	/* start it running */
+	nv_wr32(pmu, 0x10a10c, 0x00000000);
+	nv_wr32(pmu, 0x10a104, 0x00000000);
+	nv_wr32(pmu, 0x10a100, 0x00000002);
+
+	/* wait for valid host->pmu ring configuration */
+	if (!nv_wait_ne(pmu, 0x10a4d0, 0xffffffff, 0x00000000))
+		return -EBUSY;
+	pmu->send.base = nv_rd32(pmu, 0x10a4d0) & 0x0000ffff;
+	pmu->send.size = nv_rd32(pmu, 0x10a4d0) >> 16;
+
+	/* wait for valid pmu->host ring configuration */
+	if (!nv_wait_ne(pmu, 0x10a4dc, 0xffffffff, 0x00000000))
+		return -EBUSY;
+	pmu->recv.base = nv_rd32(pmu, 0x10a4dc) & 0x0000ffff;
+	pmu->recv.size = nv_rd32(pmu, 0x10a4dc) >> 16;
+
+	nv_wr32(pmu, 0x10a010, 0x000000e0);
+	return 0;
+}
+
+int
+nvkm_pmu_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_pmu *pmu;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PMU",
+				  "pmu", length, pobject);
+	pmu = *pobject;
+	if (ret)
+		return ret;
+
+	INIT_WORK(&pmu->recv.work, nvkm_pmu_recv);
+	init_waitqueue_head(&pmu->recv.wait);
+	return 0;
+}
+
+int
+_nvkm_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nvkm_pmu *pmu;
+	int ret = nvkm_pmu_create(parent, engine, oclass, &pmu);
+	*pobject = nv_object(pmu);
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/arith.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/arith.fuc
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3
new file mode 100644
index 0000000..37e8407
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF100
+#define HW_TICKS_PER_US 203 // should be 202.5
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gf100_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gf100_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
new file mode 100644
index 0000000..302557c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
@@ -0,0 +1,1865 @@
+uint32_t gf100_pmu_data[] = {
+/* 0x0000: proc_kern */
+	0x52544e49,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: proc_list_head */
+	0x54534f48,
+	0x00000512,
+	0x000004af,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x584d454d,
+	0x0000075e,
+	0x00000750,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x46524550,
+	0x00000762,
+	0x00000760,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x5f433249,
+	0x00000b92,
+	0x00000a35,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x54534554,
+	0x00000bbb,
+	0x00000b94,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x454c4449,
+	0x00000bc7,
+	0x00000bc5,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+	0x00000000,
+/* 0x026c: time_next */
+	0x00000000,
+/* 0x0270: fifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x02f0: rfifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0370: memx_func_head */
+	0x00000001,
+	0x00000000,
+	0x00000551,
+/* 0x037c: memx_func_next */
+	0x00000002,
+	0x00000000,
+	0x000005db,
+	0x00000003,
+	0x00000002,
+	0x000006a5,
+	0x00040004,
+	0x00000000,
+	0x000006c1,
+	0x00010005,
+	0x00000000,
+	0x000006de,
+	0x00010006,
+	0x00000000,
+	0x00000663,
+	0x00000007,
+	0x00000000,
+	0x000006e9,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+	0x00000000,
+/* 0x03c8: memx_ts_end */
+	0x00000000,
+/* 0x03cc: memx_data_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+	0x00001000,
+	0x00004000,
+	0x00010000,
+	0x00000100,
+	0x00040000,
+	0x00100000,
+	0x00400000,
+	0x01000000,
+	0x04000000,
+	0x10000000,
+/* 0x0cf4: i2c_sda_map */
+	0x00002000,
+	0x00008000,
+	0x00020000,
+	0x00000200,
+	0x00080000,
+	0x00200000,
+	0x00800000,
+	0x02000000,
+	0x08000000,
+	0x20000000,
+/* 0x0d1c: i2c_ctrl */
+	0x0000e138,
+	0x0000e150,
+	0x0000e168,
+	0x0000e180,
+	0x0000e254,
+	0x0000e274,
+	0x0000e764,
+	0x0000e780,
+	0x0000e79c,
+	0x0000e7b8,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gf100_pmu_code[] = {
+	0x039e0ef5,
+/* 0x0004: rd32 */
+	0x07a007f1,
+	0xd00604b6,
+	0x04bd000e,
+	0xf001d7f0,
+	0x07f101d3,
+	0x04b607ac,
+	0x000dd006,
+/* 0x0022: rd32_wait */
+	0xd7f104bd,
+	0xd4b607ac,
+	0x00ddcf06,
+	0x7000d4f1,
+	0xf1f21bf4,
+	0xb607a4d7,
+	0xddcf06d4,
+/* 0x003f: wr32 */
+	0xf100f800,
+	0xb607a007,
+	0x0ed00604,
+	0xf104bd00,
+	0xb607a407,
+	0x0dd00604,
+	0xf004bd00,
+	0xd5f002d7,
+	0x01d3f0f0,
+	0x07ac07f1,
+	0xd00604b6,
+	0x04bd000d,
+/* 0x006c: wr32_wait */
+	0x07acd7f1,
+	0xcf06d4b6,
+	0xd4f100dd,
+	0x1bf47000,
+/* 0x007f: nsec */
+	0xf900f8f2,
+	0xf080f990,
+	0x84b62c87,
+	0x0088cf06,
+/* 0x008c: nsec_loop */
+	0xb62c97f0,
+	0x99cf0694,
+	0x0298bb00,
+	0xf4069eb8,
+	0x80fcf11e,
+	0x00f890fc,
+/* 0x00a4: wait */
+	0x80f990f9,
+	0xb62c87f0,
+	0x88cf0684,
+/* 0x00b1: wait_loop */
+	0x02eeb900,
+	0xb90421f4,
+	0xadfd02da,
+	0x06acb804,
+	0xf0150bf4,
+	0x94b62c97,
+	0x0099cf06,
+	0xb80298bb,
+	0x1ef4069b,
+/* 0x00d5: wait_done */
+	0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+	0x9800f890,
+	0x96b003e9,
+	0x2a0bf400,
+	0xbb9a0a98,
+	0x1cf4029a,
+	0x01d7f00f,
+	0x02dd21f5,
+	0x0ef494bd,
+/* 0x00f9: intr_watchdog_next_time */
+	0x9b0a9815,
+	0xf400a6b0,
+	0x9ab8090b,
+	0x061cf406,
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
+	0x809b0980,
+	0xe0b603e9,
+	0x68e6b158,
+	0xc61bf402,
+/* 0x011a: intr */
+	0x00f900f8,
+	0x80f904bd,
+	0xa0f990f9,
+	0xc0f9b0f9,
+	0xe0f9d0f9,
+	0xf7f0f0f9,
+	0x0188fe00,
+	0x87f180f9,
+	0x84b605d0,
+	0x0088cf06,
+	0xf10180b6,
+	0xb605d007,
+	0x08d00604,
+	0xf004bd00,
+	0x84b60887,
+	0x0088cf06,
+	0xf40289c4,
+	0x0080230b,
+	0x58e7f09b,
+	0x98db21f4,
+	0x96b09b09,
+	0x110bf400,
+	0xb63407f0,
+	0x09d00604,
+	0x8004bd00,
+/* 0x017e: intr_skip_watchdog */
+	0x89e49a09,
+	0x0bf40800,
+	0x8897f148,
+	0x0694b606,
+	0xc40099cf,
+	0x0bf4029a,
+	0xc0c7f12c,
+	0x06c4b604,
+	0xf900cccf,
+	0x48e7f1c0,
+	0x53e3f14f,
+	0x00d7f054,
+	0x034221f5,
+	0x07f1c0fc,
+	0x04b604c0,
+	0x000cd006,
+/* 0x01be: intr_subintr_skip_fifo */
+	0x07f104bd,
+	0x04b60688,
+	0x0009d006,
+/* 0x01ca: intr_skip_subintr */
+	0x89c404bd,
+	0x070bf420,
+	0xffbfa4f1,
+/* 0x01d4: intr_skip_pause */
+	0xf44089c4,
+	0xa4f1070b,
+/* 0x01de: intr_skip_user0 */
+	0x07f0ffbf,
+	0x0604b604,
+	0xbd0008d0,
+	0xfe80fc04,
+	0xf0fc0088,
+	0xd0fce0fc,
+	0xb0fcc0fc,
+	0x90fca0fc,
+	0x00fc80fc,
+	0xf80032f4,
+/* 0x0205: ticks_from_ns */
+	0xf9c0f901,
+	0xcbd7f1b0,
+	0x00d3f000,
+	0x041321f5,
+	0x03e8ccec,
+	0xf400b4b0,
+	0xeeec120b,
+	0xd7f103e8,
+	0xd3f000cb,
+	0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+	0x02ceb904,
+	0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+	0xc0f900f8,
+	0xd7f1b0f9,
+	0xd3f000cb,
+	0x1321f500,
+	0x02ceb904,
+	0xf400b4b0,
+	0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+	0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+	0xd7f100f8,
+	0xd3f000cb,
+	0xecedff00,
+/* 0x0262: timer */
+	0x90f900f8,
+	0x32f480f9,
+	0x03f89810,
+	0xf40086b0,
+	0x84bd651c,
+	0xb63807f0,
+	0x08d00604,
+	0xf004bd00,
+	0x84b63487,
+	0x0088cf06,
+	0xbb9a0998,
+	0xe9bb0298,
+	0x03fe8000,
+	0xb60887f0,
+	0x88cf0684,
+	0x0284f000,
+	0xf0261bf4,
+	0x84b63487,
+	0x0088cf06,
+	0xf406e0b8,
+	0xe8b8090b,
+	0x111cf406,
+/* 0x02b8: timer_reset */
+	0xb63407f0,
+	0x0ed00604,
+	0x8004bd00,
+/* 0x02c6: timer_enable */
+	0x87f09a0e,
+	0x3807f001,
+	0xd00604b6,
+	0x04bd0008,
+/* 0x02d4: timer_done */
+	0xfc1031f4,
+	0xf890fc80,
+/* 0x02dd: send_proc */
+	0xf980f900,
+	0x05e89890,
+	0xf004e998,
+	0x89b80486,
+	0x2a0bf406,
+	0x940398c4,
+	0x80b60488,
+	0x008ebb18,
+	0x8000fa98,
+	0x8d80008a,
+	0x028c8001,
+	0xb6038b80,
+	0x94f00190,
+	0x04e98007,
+/* 0x0317: send_done */
+	0xfc0231f4,
+	0xf880fc90,
+/* 0x031d: find */
+	0xf080f900,
+	0x31f45887,
+/* 0x0325: find_loop */
+	0x008a9801,
+	0xf406aeb8,
+	0x80b6100b,
+	0x6886b158,
+	0xf01bf402,
+/* 0x033b: find_done */
+	0xb90132f4,
+	0x80fc028e,
+/* 0x0342: send */
+	0x21f500f8,
+	0x01f4031d,
+/* 0x034b: recv */
+	0xf900f897,
+	0x9880f990,
+	0xe99805e8,
+	0x0132f404,
+	0xf40689b8,
+	0x89c43d0b,
+	0x0180b603,
+	0x800784f0,
+	0xea9805e8,
+	0xfef0f902,
+	0xf0f9018f,
+	0x9402efb9,
+	0xe9bb0499,
+	0x18e0b600,
+	0x9803eb98,
+	0xed9802ec,
+	0x00ee9801,
+	0xf0fca5f9,
+	0xf400f8fe,
+	0xf0fc0131,
+/* 0x0398: recv_done */
+	0x90fc80fc,
+/* 0x039e: init */
+	0x17f100f8,
+	0x14b60108,
+	0x0011cf06,
+	0x010911e7,
+	0xfe0814b6,
+	0x17f10014,
+	0x13f000e0,
+	0x1c07f000,
+	0xd00604b6,
+	0x04bd0001,
+	0xf0ff17f0,
+	0x04b61407,
+	0x0001d006,
+	0x17f004bd,
+	0x0015f102,
+	0x1007f008,
+	0xd00604b6,
+	0x04bd0001,
+	0x011a17f1,
+	0xfe0013f0,
+	0x31f40010,
+	0x0117f010,
+	0xb63807f0,
+	0x01d00604,
+	0xf004bd00,
+/* 0x0402: init_proc */
+	0xf19858f7,
+	0x0016b001,
+	0xf9fa0bf4,
+	0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+	0xf9f20ef4,
+	0xf920f910,
+	0x9540f930,
+	0xd29510e1,
+	0xbdc4bd10,
+	0xc0edffb4,
+	0xb9301dff,
+	0x34f10234,
+	0x34b6ffff,
+	0x1045b610,
+	0xbb00c3bb,
+	0xe2ff01b4,
+	0x0234b930,
+	0xffff34f1,
+	0xb61034b6,
+	0xc3bb1045,
+	0x01b4bb00,
+	0xbb3012ff,
+	0x40fc00b3,
+	0x20fc30fc,
+	0x00f810fc,
+/* 0x0464: host_send */
+	0x04b017f1,
+	0xcf0614b6,
+	0x27f10011,
+	0x24b604a0,
+	0x0022cf06,
+	0xf40612b8,
+	0x1ec4320b,
+	0x04ee9407,
+	0x0270e0b7,
+	0x9803eb98,
+	0xed9802ec,
+	0x00ee9801,
+	0x034221f5,
+	0xc40110b6,
+	0x07f10f1e,
+	0x04b604b0,
+	0x000ed006,
+	0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+	0xf100f8ba,
+	0xf14e4917,
+	0xb8525413,
+	0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+	0xcc17f1aa,
+	0x0614b604,
+	0xf10011cf,
+	0xb604c827,
+	0x22cf0624,
+	0x0816f000,
+	0xf40612b8,
+	0x23c4e60b,
+	0x0434b607,
+	0x02f030b7,
+	0x80033b80,
+	0x3d80023c,
+	0x003e8001,
+	0xf00120b6,
+	0x07f10f24,
+	0x04b604c8,
+	0x0002d006,
+	0x27f004bd,
+	0x0007f040,
+	0xd00604b6,
+	0x04bd0002,
+/* 0x0512: host_init */
+	0x17f100f8,
+	0x14b60080,
+	0x7015f110,
+	0xd007f102,
+	0x0604b604,
+	0xbd0001d0,
+	0x8017f104,
+	0x1014b600,
+	0x02f015f1,
+	0x04dc07f1,
+	0xd00604b6,
+	0x04bd0001,
+	0xf10117f0,
+	0xb604c407,
+	0x01d00604,
+	0xf804bd00,
+/* 0x0551: memx_func_enter */
+	0x2067f100,
+	0x5d77f116,
+	0xff73f1f5,
+	0x026eb9ff,
+	0xb90421f4,
+	0x87fd02d8,
+	0xf960f904,
+	0xfcd0fc80,
+	0x3f21f4e0,
+	0xfffe77f1,
+	0xffff73f1,
+	0xf4026eb9,
+	0xd8b90421,
+	0x0487fd02,
+	0x80f960f9,
+	0xe0fcd0fc,
+	0xf13f21f4,
+	0xb926f067,
+	0x21f4026e,
+	0x02d8b904,
+	0xf90487fd,
+	0xfc80f960,
+	0xf4e0fcd0,
+	0x67f03f21,
+	0xe007f104,
+	0x0604b607,
+	0xbd0006d0,
+/* 0x05bd: memx_func_enter_wait */
+	0xc067f104,
+	0x0664b607,
+	0xf00066cf,
+	0x0bf40464,
+	0x2c67f0f3,
+	0xcf0664b6,
+	0x06800066,
+/* 0x05db: memx_func_leave */
+	0xf000f8f1,
+	0x64b62c67,
+	0x0066cf06,
+	0xf0f20680,
+	0x07f10467,
+	0x04b607e4,
+	0x0006d006,
+/* 0x05f6: memx_func_leave_wait */
+	0x67f104bd,
+	0x64b607c0,
+	0x0066cf06,
+	0xf40464f0,
+	0x67f1f31b,
+	0x77f126f0,
+	0x73f00001,
+	0x026eb900,
+	0xb90421f4,
+	0x87fd02d8,
+	0xf960f905,
+	0xfcd0fc80,
+	0x3f21f4e0,
+	0x162067f1,
+	0xf4026eb9,
+	0xd8b90421,
+	0x0587fd02,
+	0x80f960f9,
+	0xe0fcd0fc,
+	0xf13f21f4,
+	0xf00aa277,
+	0x6eb90073,
+	0x0421f402,
+	0xfd02d8b9,
+	0x60f90587,
+	0xd0fc80f9,
+	0x21f4e0fc,
+/* 0x0663: memx_func_wait_vblank */
+	0x9800f83f,
+	0x66b00016,
+	0x130bf400,
+	0xf40166b0,
+	0x0ef4060b,
+/* 0x0675: memx_func_wait_vblank_head1 */
+	0x2077f12e,
+	0x070ef400,
+/* 0x067c: memx_func_wait_vblank_head0 */
+	0x000877f1,
+/* 0x0680: memx_func_wait_vblank_0 */
+	0x07c467f1,
+	0xcf0664b6,
+	0x67fd0066,
+	0xf31bf404,
+/* 0x0690: memx_func_wait_vblank_1 */
+	0x07c467f1,
+	0xcf0664b6,
+	0x67fd0066,
+	0xf30bf404,
+/* 0x06a0: memx_func_wait_vblank_fini */
+	0xf80410b6,
+/* 0x06a5: memx_func_wr32 */
+	0x00169800,
+	0xb6011598,
+	0x60f90810,
+	0xd0fc50f9,
+	0x21f4e0fc,
+	0x0242b63f,
+	0xf8e91bf4,
+/* 0x06c1: memx_func_wait */
+	0x2c87f000,
+	0xcf0684b6,
+	0x1e980088,
+	0x011d9800,
+	0x98021c98,
+	0x10b6031b,
+	0xa421f410,
+/* 0x06de: memx_func_delay */
+	0x1e9800f8,
+	0x0410b600,
+	0xf87f21f4,
+/* 0x06e9: memx_func_train */
+/* 0x06eb: memx_exec */
+	0xf900f800,
+	0xb9d0f9e0,
+	0xb2b902c1,
+/* 0x06f5: memx_exec_next */
+	0x00139802,
+	0xe70410b6,
+	0xe701f034,
+	0xb601e033,
+	0x30f00132,
+	0xde35980c,
+	0x12b855f9,
+	0xe41ef406,
+	0x98f10b98,
+	0xcbbbf20c,
+	0xc4b7f102,
+	0x06b4b607,
+	0xfc00bbcf,
+	0xf5e0fcd0,
+	0xf8034221,
+/* 0x0731: memx_info */
+	0x01c67000,
+/* 0x0737: memx_info_data */
+	0xf10e0bf4,
+	0xf103ccc7,
+	0xf40800b7,
+/* 0x0742: memx_info_train */
+	0xc7f10b0e,
+	0xb7f10bcc,
+/* 0x074a: memx_info_send */
+	0x21f50100,
+	0x00f80342,
+/* 0x0750: memx_recv */
+	0xf401d6b0,
+	0xd6b0980b,
+	0xd80bf400,
+/* 0x075e: memx_init */
+	0x00f800f8,
+/* 0x0760: perf_recv */
+/* 0x0762: perf_init */
+	0x00f800f8,
+/* 0x0764: i2c_drive_scl */
+	0xf40036b0,
+	0x07f1110b,
+	0x04b607e0,
+	0x0001d006,
+	0x00f804bd,
+/* 0x0778: i2c_drive_scl_lo */
+	0x07e407f1,
+	0xd00604b6,
+	0x04bd0001,
+/* 0x0786: i2c_drive_sda */
+	0x36b000f8,
+	0x110bf400,
+	0x07e007f1,
+	0xd00604b6,
+	0x04bd0002,
+/* 0x079a: i2c_drive_sda_lo */
+	0x07f100f8,
+	0x04b607e4,
+	0x0002d006,
+	0x00f804bd,
+/* 0x07a8: i2c_sense_scl */
+	0xf10132f4,
+	0xb607c437,
+	0x33cf0634,
+	0x0431fd00,
+	0xf4060bf4,
+/* 0x07be: i2c_sense_scl_done */
+	0x00f80131,
+/* 0x07c0: i2c_sense_sda */
+	0xf10132f4,
+	0xb607c437,
+	0x33cf0634,
+	0x0432fd00,
+	0xf4060bf4,
+/* 0x07d6: i2c_sense_sda_done */
+	0x00f80131,
+/* 0x07d8: i2c_raise_scl */
+	0x47f140f9,
+	0x37f00898,
+	0x6421f501,
+/* 0x07e5: i2c_raise_scl_wait */
+	0xe8e7f107,
+	0x7f21f403,
+	0x07a821f5,
+	0xb60901f4,
+	0x1bf40142,
+/* 0x07f9: i2c_raise_scl_done */
+	0xf840fcef,
+/* 0x07fd: i2c_start */
+	0xa821f500,
+	0x0d11f407,
+	0x07c021f5,
+	0xf40611f4,
+/* 0x080e: i2c_start_rep */
+	0x37f0300e,
+	0x6421f500,
+	0x0137f007,
+	0x078621f5,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0xd821f550,
+	0x0464b607,
+/* 0x083b: i2c_start_send */
+	0xf01f11f4,
+	0x21f50037,
+	0xe7f10786,
+	0x21f41388,
+	0x0037f07f,
+	0x076421f5,
+	0x1388e7f1,
+/* 0x0857: i2c_start_out */
+	0xf87f21f4,
+/* 0x0859: i2c_stop */
+	0x0037f000,
+	0x076421f5,
+	0xf50037f0,
+	0xf1078621,
+	0xf403e8e7,
+	0x37f07f21,
+	0x6421f501,
+	0x88e7f107,
+	0x7f21f413,
+	0xf50137f0,
+	0xf1078621,
+	0xf41388e7,
+	0x00f87f21,
+/* 0x088c: i2c_bitw */
+	0x078621f5,
+	0x03e8e7f1,
+	0xbb7f21f4,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x07d821f5,
+	0xf40464b6,
+	0xe7f11811,
+	0x21f41388,
+	0x0037f07f,
+	0x076421f5,
+	0x1388e7f1,
+/* 0x08cb: i2c_bitw_out */
+	0xf87f21f4,
+/* 0x08cd: i2c_bitr */
+	0x0137f000,
+	0x078621f5,
+	0x03e8e7f1,
+	0xbb7f21f4,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x07d821f5,
+	0xf40464b6,
+	0x21f51b11,
+	0x37f007c0,
+	0x6421f500,
+	0x88e7f107,
+	0x7f21f413,
+	0xf4013cf0,
+/* 0x0912: i2c_bitr_done */
+	0x00f80131,
+/* 0x0914: i2c_get_byte */
+	0xf00057f0,
+/* 0x091a: i2c_get_byte_next */
+	0x54b60847,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b608cd,
+	0x2b11f404,
+	0xb60553fd,
+	0x1bf40142,
+	0x0137f0d8,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x8c21f550,
+	0x0464b608,
+/* 0x0964: i2c_get_byte_done */
+/* 0x0966: i2c_put_byte */
+	0x47f000f8,
+/* 0x0969: i2c_put_byte_next */
+	0x0142b608,
+	0xbb3854ff,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x088c21f5,
+	0xf40464b6,
+	0x46b03411,
+	0xd81bf400,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0xcd21f550,
+	0x0464b608,
+	0xbb0f11f4,
+	0x36b00076,
+	0x061bf401,
+/* 0x09bf: i2c_put_byte_done */
+	0xf80132f4,
+/* 0x09c1: i2c_addr */
+	0x0076bb00,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b607fd,
+	0x2911f404,
+	0x012ec3e7,
+	0xfd0134b6,
+	0x76bb0553,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb6096621,
+/* 0x0a06: i2c_addr_done */
+	0x00f80464,
+/* 0x0a08: i2c_acquire_addr */
+	0xb6f8cec7,
+	0xe0b702e4,
+	0xee980d1c,
+/* 0x0a17: i2c_acquire */
+	0xf500f800,
+	0xf40a0821,
+	0xd9f00421,
+	0x3f21f403,
+/* 0x0a26: i2c_release */
+	0x21f500f8,
+	0x21f40a08,
+	0x03daf004,
+	0xf83f21f4,
+/* 0x0a35: i2c_recv */
+	0x0132f400,
+	0xb6f8c1c7,
+	0x16b00214,
+	0x3a1ff528,
+	0xf413a001,
+	0x0032980c,
+	0x0ccc13a0,
+	0xf4003198,
+	0xd0f90231,
+	0xd0f9e0f9,
+	0x000067f1,
+	0x100063f1,
+	0xbb016792,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0a1721f5,
+	0xfc0464b6,
+	0x00d6b0d0,
+	0x00b31bf5,
+	0xbb0057f0,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x09c121f5,
+	0xf50464b6,
+	0xc700d011,
+	0x76bbe0c5,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb6096621,
+	0x11f50464,
+	0x57f000ad,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b609c1,
+	0x8a11f504,
+	0x0076bb00,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b60914,
+	0x6a11f404,
+	0xbbe05bcb,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x085921f5,
+	0xb90464b6,
+	0x74bd025b,
+/* 0x0b3b: i2c_recv_not_rd08 */
+	0xb0430ef4,
+	0x1bf401d6,
+	0x0057f03d,
+	0x09c121f5,
+	0xc73311f4,
+	0x21f5e0c5,
+	0x11f40966,
+	0x0057f029,
+	0x09c121f5,
+	0xc71f11f4,
+	0x21f5e0b5,
+	0x11f40966,
+	0x5921f515,
+	0xc774bd08,
+	0x1bf408c5,
+	0x0232f409,
+/* 0x0b7b: i2c_recv_not_wr08 */
+/* 0x0b7b: i2c_recv_done */
+	0xc7030ef4,
+	0x21f5f8ce,
+	0xe0fc0a26,
+	0x12f4d0fc,
+	0x027cb90a,
+	0x034221f5,
+/* 0x0b90: i2c_recv_exit */
+/* 0x0b92: i2c_init */
+	0x00f800f8,
+/* 0x0b94: test_recv */
+	0x05d817f1,
+	0xcf0614b6,
+	0x10b60011,
+	0xd807f101,
+	0x0604b605,
+	0xbd0001d0,
+	0x00e7f104,
+	0x4fe3f1d9,
+	0x6221f513,
+/* 0x0bbb: test_init */
+	0xf100f802,
+	0xf50800e7,
+	0xf8026221,
+/* 0x0bc5: idle_recv */
+/* 0x0bc7: idle */
+	0xf400f800,
+	0x17f10031,
+	0x14b605d4,
+	0x0011cf06,
+	0xf10110b6,
+	0xb605d407,
+	0x01d00604,
+/* 0x0be3: idle_loop */
+	0xf004bd00,
+	0x32f45817,
+/* 0x0be9: idle_proc */
+/* 0x0be9: idle_proc_exec */
+	0xb910f902,
+	0x21f5021e,
+	0x10fc034b,
+	0xf40911f4,
+	0x0ef40231,
+/* 0x0bfd: idle_proc_next */
+	0x5810b6ef,
+	0xf4061fb8,
+	0x02f4e61b,
+	0x0028f4dd,
+	0x00bb0ef4,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4
new file mode 100644
index 0000000..ae9c3f1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF119
+#define HW_TICKS_PER_US 324
+
+//#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gf110_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gf110_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h
new file mode 100644
index 0000000..a0c499e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h
@@ -0,0 +1,1795 @@
+uint32_t gf110_pmu_data[] = {
+/* 0x0000: proc_kern */
+	0x52544e49,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: proc_list_head */
+	0x54534f48,
+	0x0000049d,
+	0x00000446,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x584d454d,
+	0x0000068b,
+	0x0000067d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x46524550,
+	0x0000068f,
+	0x0000068d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x5f433249,
+	0x00000aaa,
+	0x0000094d,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x54534554,
+	0x00000acd,
+	0x00000aac,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x454c4449,
+	0x00000ad9,
+	0x00000ad7,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+	0x00000000,
+/* 0x026c: time_next */
+	0x00000000,
+/* 0x0270: fifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x02f0: rfifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0370: memx_func_head */
+	0x00000001,
+	0x00000000,
+	0x000004d3,
+/* 0x037c: memx_func_next */
+	0x00000002,
+	0x00000000,
+	0x00000554,
+	0x00000003,
+	0x00000002,
+	0x000005d8,
+	0x00040004,
+	0x00000000,
+	0x000005f4,
+	0x00010005,
+	0x00000000,
+	0x0000060e,
+	0x00010006,
+	0x00000000,
+	0x000005d3,
+	0x00000007,
+	0x00000000,
+	0x00000619,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+	0x00000000,
+/* 0x03c8: memx_ts_end */
+	0x00000000,
+/* 0x03cc: memx_data_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+	0x00000400,
+	0x00000800,
+	0x00001000,
+	0x00002000,
+	0x00004000,
+	0x00008000,
+	0x00010000,
+	0x00020000,
+	0x00040000,
+	0x00080000,
+/* 0x0cf4: i2c_sda_map */
+	0x00100000,
+	0x00200000,
+	0x00400000,
+	0x00800000,
+	0x01000000,
+	0x02000000,
+	0x04000000,
+	0x08000000,
+	0x10000000,
+	0x20000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gf110_pmu_code[] = {
+	0x034d0ef5,
+/* 0x0004: rd32 */
+	0x07a007f1,
+	0xbd000ed0,
+	0x01d7f004,
+	0xf101d3f0,
+	0xd007ac07,
+	0x04bd000d,
+/* 0x001c: rd32_wait */
+	0x07acd7f1,
+	0xf100ddcf,
+	0xf47000d4,
+	0xd7f1f51b,
+	0xddcf07a4,
+/* 0x0033: wr32 */
+	0xf100f800,
+	0xd007a007,
+	0x04bd000e,
+	0x07a407f1,
+	0xbd000dd0,
+	0x02d7f004,
+	0xf0f0d5f0,
+	0x07f101d3,
+	0x0dd007ac,
+/* 0x0057: wr32_wait */
+	0xf104bd00,
+	0xcf07acd7,
+	0xd4f100dd,
+	0x1bf47000,
+/* 0x0067: nsec */
+	0xf900f8f5,
+	0xf080f990,
+	0x88cf2c87,
+/* 0x0071: nsec_loop */
+	0x2c97f000,
+	0xbb0099cf,
+	0x9eb80298,
+	0xf41ef406,
+	0x90fc80fc,
+/* 0x0086: wait */
+	0x90f900f8,
+	0x87f080f9,
+	0x0088cf2c,
+/* 0x0090: wait_loop */
+	0xf402eeb9,
+	0xdab90421,
+	0x04adfd02,
+	0xf406acb8,
+	0x97f0120b,
+	0x0099cf2c,
+	0xb80298bb,
+	0x1ef4069b,
+/* 0x00b1: wait_done */
+	0xfc80fce2,
+/* 0x00b7: intr_watchdog */
+	0x9800f890,
+	0x96b003e9,
+	0x2a0bf400,
+	0xbb9a0a98,
+	0x1cf4029a,
+	0x01d7f00f,
+	0x028c21f5,
+	0x0ef494bd,
+/* 0x00d5: intr_watchdog_next_time */
+	0x9b0a9815,
+	0xf400a6b0,
+	0x9ab8090b,
+	0x061cf406,
+/* 0x00e4: intr_watchdog_next_time_set */
+/* 0x00e7: intr_watchdog_next_proc */
+	0x809b0980,
+	0xe0b603e9,
+	0x68e6b158,
+	0xc61bf402,
+/* 0x00f6: intr */
+	0x00f900f8,
+	0x80f904bd,
+	0xa0f990f9,
+	0xc0f9b0f9,
+	0xe0f9d0f9,
+	0xf7f0f0f9,
+	0x0188fe00,
+	0x87f180f9,
+	0x88cf05d0,
+	0x0180b600,
+	0x05d007f1,
+	0xbd0008d0,
+	0x0887f004,
+	0xc40088cf,
+	0x0bf40289,
+	0x9b008020,
+	0xf458e7f0,
+	0x0998b721,
+	0x0096b09b,
+	0xf00e0bf4,
+	0x09d03407,
+	0x8004bd00,
+/* 0x014e: intr_skip_watchdog */
+	0x89e49a09,
+	0x0bf40800,
+	0x8897f13c,
+	0x0099cf06,
+	0xf4029ac4,
+	0xc7f1260b,
+	0xcccf04c0,
+	0xf1c0f900,
+	0xf14f48e7,
+	0xf05453e3,
+	0x21f500d7,
+	0xc0fc02f1,
+	0x04c007f1,
+	0xbd000cd0,
+/* 0x0185: intr_subintr_skip_fifo */
+	0x8807f104,
+	0x0009d006,
+/* 0x018e: intr_skip_subintr */
+	0x89c404bd,
+	0x070bf420,
+	0xffbfa4f1,
+/* 0x0198: intr_skip_pause */
+	0xf44089c4,
+	0xa4f1070b,
+/* 0x01a2: intr_skip_user0 */
+	0x07f0ffbf,
+	0x0008d004,
+	0x80fc04bd,
+	0xfc0088fe,
+	0xfce0fcf0,
+	0xfcc0fcd0,
+	0xfca0fcb0,
+	0xfc80fc90,
+	0x0032f400,
+/* 0x01c6: ticks_from_ns */
+	0xc0f901f8,
+	0xd7f1b0f9,
+	0xd3f00144,
+	0xb321f500,
+	0xe8ccec03,
+	0x00b4b003,
+	0xec120bf4,
+	0xf103e8ee,
+	0xf00144d7,
+	0x21f500d3,
+/* 0x01ee: ticks_from_ns_quit */
+	0xceb903b3,
+	0xfcb0fc02,
+/* 0x01f7: ticks_from_us */
+	0xf900f8c0,
+	0xf1b0f9c0,
+	0xf00144d7,
+	0x21f500d3,
+	0xceb903b3,
+	0x00b4b002,
+	0xbd050bf4,
+/* 0x0211: ticks_from_us_quit */
+	0xfcb0fce4,
+/* 0x0217: ticks_to_us */
+	0xf100f8c0,
+	0xf00144d7,
+	0xedff00d3,
+/* 0x0223: timer */
+	0xf900f8ec,
+	0xf480f990,
+	0xf8981032,
+	0x0086b003,
+	0xbd531cf4,
+	0x3807f084,
+	0xbd0008d0,
+	0x3487f004,
+	0x980088cf,
+	0x98bb9a09,
+	0x00e9bb02,
+	0xf003fe80,
+	0x88cf0887,
+	0x0284f000,
+	0xf0201bf4,
+	0x88cf3487,
+	0x06e0b800,
+	0xb8090bf4,
+	0x1cf406e8,
+/* 0x026d: timer_reset */
+	0x3407f00e,
+	0xbd000ed0,
+	0x9a0e8004,
+/* 0x0278: timer_enable */
+	0xf00187f0,
+	0x08d03807,
+/* 0x0283: timer_done */
+	0xf404bd00,
+	0x80fc1031,
+	0x00f890fc,
+/* 0x028c: send_proc */
+	0x90f980f9,
+	0x9805e898,
+	0x86f004e9,
+	0x0689b804,
+	0xc42a0bf4,
+	0x88940398,
+	0x1880b604,
+	0x98008ebb,
+	0x8a8000fa,
+	0x018d8000,
+	0x80028c80,
+	0x90b6038b,
+	0x0794f001,
+	0xf404e980,
+/* 0x02c6: send_done */
+	0x90fc0231,
+	0x00f880fc,
+/* 0x02cc: find */
+	0x87f080f9,
+	0x0131f458,
+/* 0x02d4: find_loop */
+	0xb8008a98,
+	0x0bf406ae,
+	0x5880b610,
+	0x026886b1,
+	0xf4f01bf4,
+/* 0x02ea: find_done */
+	0x8eb90132,
+	0xf880fc02,
+/* 0x02f1: send */
+	0xcc21f500,
+	0x9701f402,
+/* 0x02fa: recv */
+	0x90f900f8,
+	0xe89880f9,
+	0x04e99805,
+	0xb80132f4,
+	0x0bf40689,
+	0x0389c43d,
+	0xf00180b6,
+	0xe8800784,
+	0x02ea9805,
+	0x8ffef0f9,
+	0xb9f0f901,
+	0x999402ef,
+	0x00e9bb04,
+	0x9818e0b6,
+	0xec9803eb,
+	0x01ed9802,
+	0xf900ee98,
+	0xfef0fca5,
+	0x31f400f8,
+/* 0x0347: recv_done */
+	0xfcf0fc01,
+	0xf890fc80,
+/* 0x034d: init */
+	0x0817f100,
+	0x0011cf01,
+	0x010911e7,
+	0xfe0814b6,
+	0x17f10014,
+	0x13f000e0,
+	0x1c07f000,
+	0xbd0001d0,
+	0xff17f004,
+	0xd01407f0,
+	0x04bd0001,
+	0xf10217f0,
+	0xf0080015,
+	0x01d01007,
+	0xf104bd00,
+	0xf000f617,
+	0x10fe0013,
+	0x1031f400,
+	0xf00117f0,
+	0x01d03807,
+	0xf004bd00,
+/* 0x03a2: init_proc */
+	0xf19858f7,
+	0x0016b001,
+	0xf9fa0bf4,
+	0x58f0b615,
+/* 0x03b3: mulu32_32_64 */
+	0xf9f20ef4,
+	0xf920f910,
+	0x9540f930,
+	0xd29510e1,
+	0xbdc4bd10,
+	0xc0edffb4,
+	0xb9301dff,
+	0x34f10234,
+	0x34b6ffff,
+	0x1045b610,
+	0xbb00c3bb,
+	0xe2ff01b4,
+	0x0234b930,
+	0xffff34f1,
+	0xb61034b6,
+	0xc3bb1045,
+	0x01b4bb00,
+	0xbb3012ff,
+	0x40fc00b3,
+	0x20fc30fc,
+	0x00f810fc,
+/* 0x0404: host_send */
+	0x04b017f1,
+	0xf10011cf,
+	0xcf04a027,
+	0x12b80022,
+	0x2f0bf406,
+	0x94071ec4,
+	0xe0b704ee,
+	0xeb980270,
+	0x02ec9803,
+	0x9801ed98,
+	0x21f500ee,
+	0x10b602f1,
+	0x0f1ec401,
+	0x04b007f1,
+	0xbd000ed0,
+	0xc30ef404,
+/* 0x0444: host_send_done */
+/* 0x0446: host_recv */
+	0x17f100f8,
+	0x13f14e49,
+	0xe1b85254,
+	0xb30bf406,
+/* 0x0454: host_recv_wait */
+	0x04cc17f1,
+	0xf10011cf,
+	0xcf04c827,
+	0x16f00022,
+	0x0612b808,
+	0xc4ec0bf4,
+	0x34b60723,
+	0xf030b704,
+	0x033b8002,
+	0x80023c80,
+	0x3e80013d,
+	0x0120b600,
+	0xf10f24f0,
+	0xd004c807,
+	0x04bd0002,
+	0xf04027f0,
+	0x02d00007,
+	0xf804bd00,
+/* 0x049d: host_init */
+	0x8017f100,
+	0x1014b600,
+	0x027015f1,
+	0x04d007f1,
+	0xbd0001d0,
+	0x8017f104,
+	0x1014b600,
+	0x02f015f1,
+	0x04dc07f1,
+	0xbd0001d0,
+	0x0117f004,
+	0x04c407f1,
+	0xbd0001d0,
+/* 0x04d3: memx_func_enter */
+	0xf100f804,
+	0xf1162067,
+	0xf1f55d77,
+	0xb9ffff73,
+	0x21f4026e,
+	0x02d8b904,
+	0xf90487fd,
+	0xfc80f960,
+	0xf4e0fcd0,
+	0x77f13321,
+	0x73f1fffe,
+	0x6eb9ffff,
+	0x0421f402,
+	0xfd02d8b9,
+	0x60f90487,
+	0xd0fc80f9,
+	0x21f4e0fc,
+	0xf067f133,
+	0x026eb926,
+	0xb90421f4,
+	0x87fd02d8,
+	0xf960f904,
+	0xfcd0fc80,
+	0x3321f4e0,
+	0xf10467f0,
+	0xd007e007,
+	0x04bd0006,
+/* 0x053c: memx_func_enter_wait */
+	0x07c067f1,
+	0xf00066cf,
+	0x0bf40464,
+	0x2c67f0f6,
+	0x800066cf,
+	0x00f8f106,
+/* 0x0554: memx_func_leave */
+	0xcf2c67f0,
+	0x06800066,
+	0x0467f0f2,
+	0x07e407f1,
+	0xbd0006d0,
+/* 0x0569: memx_func_leave_wait */
+	0xc067f104,
+	0x0066cf07,
+	0xf40464f0,
+	0x67f1f61b,
+	0x77f126f0,
+	0x73f00001,
+	0x026eb900,
+	0xb90421f4,
+	0x87fd02d8,
+	0xf960f905,
+	0xfcd0fc80,
+	0x3321f4e0,
+	0x162067f1,
+	0xf4026eb9,
+	0xd8b90421,
+	0x0587fd02,
+	0x80f960f9,
+	0xe0fcd0fc,
+	0xf13321f4,
+	0xf00aa277,
+	0x6eb90073,
+	0x0421f402,
+	0xfd02d8b9,
+	0x60f90587,
+	0xd0fc80f9,
+	0x21f4e0fc,
+/* 0x05d3: memx_func_wait_vblank */
+	0xb600f833,
+	0x00f80410,
+/* 0x05d8: memx_func_wr32 */
+	0x98001698,
+	0x10b60115,
+	0xf960f908,
+	0xfcd0fc50,
+	0x3321f4e0,
+	0xf40242b6,
+	0x00f8e91b,
+/* 0x05f4: memx_func_wait */
+	0xcf2c87f0,
+	0x1e980088,
+	0x011d9800,
+	0x98021c98,
+	0x10b6031b,
+	0x8621f410,
+/* 0x060e: memx_func_delay */
+	0x1e9800f8,
+	0x0410b600,
+	0xf86721f4,
+/* 0x0619: memx_func_train */
+/* 0x061b: memx_exec */
+	0xf900f800,
+	0xb9d0f9e0,
+	0xb2b902c1,
+/* 0x0625: memx_exec_next */
+	0x00139802,
+	0xe70410b6,
+	0xe701f034,
+	0xb601e033,
+	0x30f00132,
+	0xde35980c,
+	0x12b855f9,
+	0xe41ef406,
+	0x98f10b98,
+	0xcbbbf20c,
+	0xc4b7f102,
+	0x00bbcf07,
+	0xe0fcd0fc,
+	0x02f121f5,
+/* 0x065e: memx_info */
+	0xc67000f8,
+	0x0e0bf401,
+/* 0x0664: memx_info_data */
+	0x03ccc7f1,
+	0x0800b7f1,
+/* 0x066f: memx_info_train */
+	0xf10b0ef4,
+	0xf10bccc7,
+/* 0x0677: memx_info_send */
+	0xf50100b7,
+	0xf802f121,
+/* 0x067d: memx_recv */
+	0x01d6b000,
+	0xb09b0bf4,
+	0x0bf400d6,
+/* 0x068b: memx_init */
+	0xf800f8d8,
+/* 0x068d: perf_recv */
+/* 0x068f: perf_init */
+	0xf800f800,
+/* 0x0691: i2c_drive_scl */
+	0x0036b000,
+	0xf10e0bf4,
+	0xd007e007,
+	0x04bd0001,
+/* 0x06a2: i2c_drive_scl_lo */
+	0x07f100f8,
+	0x01d007e4,
+	0xf804bd00,
+/* 0x06ad: i2c_drive_sda */
+	0x0036b000,
+	0xf10e0bf4,
+	0xd007e007,
+	0x04bd0002,
+/* 0x06be: i2c_drive_sda_lo */
+	0x07f100f8,
+	0x02d007e4,
+	0xf804bd00,
+/* 0x06c9: i2c_sense_scl */
+	0x0132f400,
+	0x07c437f1,
+	0xfd0033cf,
+	0x0bf40431,
+	0x0131f406,
+/* 0x06dc: i2c_sense_scl_done */
+/* 0x06de: i2c_sense_sda */
+	0x32f400f8,
+	0xc437f101,
+	0x0033cf07,
+	0xf40432fd,
+	0x31f4060b,
+/* 0x06f1: i2c_sense_sda_done */
+/* 0x06f3: i2c_raise_scl */
+	0xf900f801,
+	0x9847f140,
+	0x0137f008,
+	0x069121f5,
+/* 0x0700: i2c_raise_scl_wait */
+	0x03e8e7f1,
+	0xf56721f4,
+	0xf406c921,
+	0x42b60901,
+	0xef1bf401,
+/* 0x0714: i2c_raise_scl_done */
+	0x00f840fc,
+/* 0x0718: i2c_start */
+	0x06c921f5,
+	0xf50d11f4,
+	0xf406de21,
+	0x0ef40611,
+/* 0x0729: i2c_start_rep */
+	0x0037f030,
+	0x069121f5,
+	0xf50137f0,
+	0xbb06ad21,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x06f321f5,
+	0xf40464b6,
+/* 0x0756: i2c_start_send */
+	0x37f01f11,
+	0xad21f500,
+	0x88e7f106,
+	0x6721f413,
+	0xf50037f0,
+	0xf1069121,
+	0xf41388e7,
+/* 0x0772: i2c_start_out */
+	0x00f86721,
+/* 0x0774: i2c_stop */
+	0xf50037f0,
+	0xf0069121,
+	0x21f50037,
+	0xe7f106ad,
+	0x21f403e8,
+	0x0137f067,
+	0x069121f5,
+	0x1388e7f1,
+	0xf06721f4,
+	0x21f50137,
+	0xe7f106ad,
+	0x21f41388,
+/* 0x07a7: i2c_bitw */
+	0xf500f867,
+	0xf106ad21,
+	0xf403e8e7,
+	0x76bb6721,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb606f321,
+	0x11f40464,
+	0x88e7f118,
+	0x6721f413,
+	0xf50037f0,
+	0xf1069121,
+	0xf41388e7,
+/* 0x07e6: i2c_bitw_out */
+	0x00f86721,
+/* 0x07e8: i2c_bitr */
+	0xf50137f0,
+	0xf106ad21,
+	0xf403e8e7,
+	0x76bb6721,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb606f321,
+	0x11f40464,
+	0xde21f51b,
+	0x0037f006,
+	0x069121f5,
+	0x1388e7f1,
+	0xf06721f4,
+	0x31f4013c,
+/* 0x082d: i2c_bitr_done */
+/* 0x082f: i2c_get_byte */
+	0xf000f801,
+	0x47f00057,
+/* 0x0835: i2c_get_byte_next */
+	0x0154b608,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0xe821f550,
+	0x0464b607,
+	0xfd2b11f4,
+	0x42b60553,
+	0xd81bf401,
+	0xbb0137f0,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x07a721f5,
+/* 0x087f: i2c_get_byte_done */
+	0xf80464b6,
+/* 0x0881: i2c_put_byte */
+	0x0847f000,
+/* 0x0884: i2c_put_byte_next */
+	0xff0142b6,
+	0x76bb3854,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb607a721,
+	0x11f40464,
+	0x0046b034,
+	0xbbd81bf4,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x07e821f5,
+	0xf40464b6,
+	0x76bb0f11,
+	0x0136b000,
+	0xf4061bf4,
+/* 0x08da: i2c_put_byte_done */
+	0x00f80132,
+/* 0x08dc: i2c_addr */
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x1821f550,
+	0x0464b607,
+	0xe72911f4,
+	0xb6012ec3,
+	0x53fd0134,
+	0x0076bb05,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b60881,
+/* 0x0921: i2c_addr_done */
+/* 0x0923: i2c_acquire_addr */
+	0xc700f804,
+	0xe4b6f8ce,
+	0x14e0b705,
+/* 0x092f: i2c_acquire */
+	0xf500f8d0,
+	0xf4092321,
+	0xd9f00421,
+	0x3321f403,
+/* 0x093e: i2c_release */
+	0x21f500f8,
+	0x21f40923,
+	0x03daf004,
+	0xf83321f4,
+/* 0x094d: i2c_recv */
+	0x0132f400,
+	0xb6f8c1c7,
+	0x16b00214,
+	0x3a1ff528,
+	0xf413a001,
+	0x0032980c,
+	0x0ccc13a0,
+	0xf4003198,
+	0xd0f90231,
+	0xd0f9e0f9,
+	0x000067f1,
+	0x100063f1,
+	0xbb016792,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x092f21f5,
+	0xfc0464b6,
+	0x00d6b0d0,
+	0x00b31bf5,
+	0xbb0057f0,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x08dc21f5,
+	0xf50464b6,
+	0xc700d011,
+	0x76bbe0c5,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb6088121,
+	0x11f50464,
+	0x57f000ad,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b608dc,
+	0x8a11f504,
+	0x0076bb00,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b6082f,
+	0x6a11f404,
+	0xbbe05bcb,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x077421f5,
+	0xb90464b6,
+	0x74bd025b,
+/* 0x0a53: i2c_recv_not_rd08 */
+	0xb0430ef4,
+	0x1bf401d6,
+	0x0057f03d,
+	0x08dc21f5,
+	0xc73311f4,
+	0x21f5e0c5,
+	0x11f40881,
+	0x0057f029,
+	0x08dc21f5,
+	0xc71f11f4,
+	0x21f5e0b5,
+	0x11f40881,
+	0x7421f515,
+	0xc774bd07,
+	0x1bf408c5,
+	0x0232f409,
+/* 0x0a93: i2c_recv_not_wr08 */
+/* 0x0a93: i2c_recv_done */
+	0xc7030ef4,
+	0x21f5f8ce,
+	0xe0fc093e,
+	0x12f4d0fc,
+	0x027cb90a,
+	0x02f121f5,
+/* 0x0aa8: i2c_recv_exit */
+/* 0x0aaa: i2c_init */
+	0x00f800f8,
+/* 0x0aac: test_recv */
+	0x05d817f1,
+	0xb60011cf,
+	0x07f10110,
+	0x01d005d8,
+	0xf104bd00,
+	0xf1d900e7,
+	0xf5134fe3,
+	0xf8022321,
+/* 0x0acd: test_init */
+	0x00e7f100,
+	0x2321f508,
+/* 0x0ad7: idle_recv */
+	0xf800f802,
+/* 0x0ad9: idle */
+	0x0031f400,
+	0x05d417f1,
+	0xb60011cf,
+	0x07f10110,
+	0x01d005d4,
+/* 0x0aef: idle_loop */
+	0xf004bd00,
+	0x32f45817,
+/* 0x0af5: idle_proc */
+/* 0x0af5: idle_proc_exec */
+	0xb910f902,
+	0x21f5021e,
+	0x10fc02fa,
+	0xf40911f4,
+	0x0ef40231,
+/* 0x0b09: idle_proc_next */
+	0x5810b6ef,
+	0xf4061fb8,
+	0x02f4e61b,
+	0x0028f4dd,
+	0x00c10ef4,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5
new file mode 100644
index 0000000..093dc81
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GK208
+#define HW_TICKS_PER_US 324
+
+#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gk208_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gk208_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
new file mode 100644
index 0000000..fe4f63d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
@@ -0,0 +1,1731 @@
+uint32_t gk208_pmu_data[] = {
+/* 0x0000: proc_kern */
+	0x52544e49,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: proc_list_head */
+	0x54534f48,
+	0x00000453,
+	0x00000404,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x584d454d,
+	0x0000062d,
+	0x0000061f,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x46524550,
+	0x00000631,
+	0x0000062f,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x5f433249,
+	0x00000a35,
+	0x000008dc,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x54534554,
+	0x00000a56,
+	0x00000a37,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x454c4449,
+	0x00000a61,
+	0x00000a5f,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+	0x00000000,
+/* 0x026c: time_next */
+	0x00000000,
+/* 0x0270: fifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x02f0: rfifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0370: memx_func_head */
+	0x00000001,
+	0x00000000,
+	0x00000483,
+/* 0x037c: memx_func_next */
+	0x00000002,
+	0x00000000,
+	0x00000500,
+	0x00000003,
+	0x00000002,
+	0x00000580,
+	0x00040004,
+	0x00000000,
+	0x0000059d,
+	0x00010005,
+	0x00000000,
+	0x000005b7,
+	0x00010006,
+	0x00000000,
+	0x0000057b,
+	0x00000007,
+	0x00000000,
+	0x000005c3,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+	0x00000000,
+/* 0x03c8: memx_ts_end */
+	0x00000000,
+/* 0x03cc: memx_data_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+	0x00000400,
+	0x00000800,
+	0x00001000,
+	0x00002000,
+	0x00004000,
+	0x00008000,
+	0x00010000,
+	0x00020000,
+	0x00040000,
+	0x00080000,
+/* 0x0cf4: i2c_sda_map */
+	0x00100000,
+	0x00200000,
+	0x00400000,
+	0x00800000,
+	0x01000000,
+	0x02000000,
+	0x04000000,
+	0x08000000,
+	0x10000000,
+	0x20000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gk208_pmu_code[] = {
+	0x031c0ef5,
+/* 0x0004: rd32 */
+	0xf607a040,
+	0x04bd000e,
+	0xd3f0010d,
+	0x07ac4001,
+	0xbd000df6,
+/* 0x0019: rd32_wait */
+	0x07ac4d04,
+	0xf100ddcf,
+	0xf47000d4,
+	0xa44df61b,
+	0x00ddcf07,
+/* 0x002e: wr32 */
+	0xa04000f8,
+	0x000ef607,
+	0xa44004bd,
+	0x000df607,
+	0x020d04bd,
+	0xf0f0d5f0,
+	0xac4001d3,
+	0x000df607,
+/* 0x004e: wr32_wait */
+	0xac4d04bd,
+	0x00ddcf07,
+	0x7000d4f1,
+	0xf8f61bf4,
+/* 0x005d: nsec */
+	0xf990f900,
+	0xcf2c0880,
+/* 0x0066: nsec_loop */
+	0x2c090088,
+	0xbb0099cf,
+	0x9ea60298,
+	0xfcf61ef4,
+	0xf890fc80,
+/* 0x0079: wait */
+	0xf990f900,
+	0xcf2c0880,
+/* 0x0082: wait_loop */
+	0xeeb20088,
+	0x0000047e,
+	0xadfddab2,
+	0xf4aca604,
+	0x2c09100b,
+	0xbb0099cf,
+	0x9ba60298,
+/* 0x009f: wait_done */
+	0xfce61ef4,
+	0xf890fc80,
+/* 0x00a5: intr_watchdog */
+	0x03e99800,
+	0xf40096b0,
+	0x0a98280b,
+	0x029abb9a,
+	0x0d0e1cf4,
+	0x02617e01,
+	0xf494bd00,
+/* 0x00c2: intr_watchdog_next_time */
+	0x0a98140e,
+	0x00a6b09b,
+	0xa6080bf4,
+	0x061cf49a,
+/* 0x00d0: intr_watchdog_next_time_set */
+/* 0x00d3: intr_watchdog_next_proc */
+	0xb59b09b5,
+	0xe0b603e9,
+	0x68e6b158,
+	0xc81bf402,
+/* 0x00e2: intr */
+	0x00f900f8,
+	0x80f904bd,
+	0xa0f990f9,
+	0xc0f9b0f9,
+	0xe0f9d0f9,
+	0x000ff0f9,
+	0xf90188fe,
+	0x04504880,
+	0xb60088cf,
+	0x50400180,
+	0x0008f604,
+	0x080804bd,
+	0xc40088cf,
+	0x0bf40289,
+	0x9b00b51f,
+	0xa57e580e,
+	0x09980000,
+	0x0096b09b,
+	0x000d0bf4,
+	0x0009f634,
+	0x09b504bd,
+/* 0x0135: intr_skip_watchdog */
+	0x0089e49a,
+	0x360bf408,
+	0xcf068849,
+	0x9ac40099,
+	0x220bf402,
+	0xcf04c04c,
+	0xc0f900cc,
+	0xf14f484e,
+	0x0d5453e3,
+	0x02c27e00,
+	0x40c0fc00,
+	0x0cf604c0,
+/* 0x0167: intr_subintr_skip_fifo */
+	0x4004bd00,
+	0x09f60688,
+/* 0x016f: intr_skip_subintr */
+	0xc404bd00,
+	0x0bf42089,
+	0xbfa4f107,
+/* 0x0179: intr_skip_pause */
+	0x4089c4ff,
+	0xf1070bf4,
+/* 0x0183: intr_skip_user0 */
+	0x00ffbfa4,
+	0x0008f604,
+	0x80fc04bd,
+	0xfc0088fe,
+	0xfce0fcf0,
+	0xfcc0fcd0,
+	0xfca0fcb0,
+	0xfc80fc90,
+	0x0032f400,
+/* 0x01a6: ticks_from_ns */
+	0xc0f901f8,
+	0xd7f1b0f9,
+	0xd3f00144,
+	0x7721f500,
+	0xe8ccec03,
+	0x00b4b003,
+	0xec120bf4,
+	0xf103e8ee,
+	0xf00144d7,
+	0x21f500d3,
+/* 0x01ce: ticks_from_ns_quit */
+	0xceb20377,
+	0xc0fcb0fc,
+/* 0x01d6: ticks_from_us */
+	0xc0f900f8,
+	0xd7f1b0f9,
+	0xd3f00144,
+	0x7721f500,
+	0xb0ceb203,
+	0x0bf400b4,
+/* 0x01ef: ticks_from_us_quit */
+	0xfce4bd05,
+	0xf8c0fcb0,
+/* 0x01f5: ticks_to_us */
+	0x44d7f100,
+	0x00d3f001,
+	0xf8ecedff,
+/* 0x0201: timer */
+	0xf990f900,
+	0x1032f480,
+	0xb003f898,
+	0x1cf40086,
+	0x0084bd4a,
+	0x0008f638,
+	0x340804bd,
+	0x980088cf,
+	0x98bb9a09,
+	0x00e9bb02,
+	0x0803feb5,
+	0x0088cf08,
+	0xf40284f0,
+	0x34081c1b,
+	0xa60088cf,
+	0x080bf4e0,
+	0x1cf4e8a6,
+/* 0x0245: timer_reset */
+	0xf634000d,
+	0x04bd000e,
+/* 0x024f: timer_enable */
+	0x089a0eb5,
+	0xf6380001,
+	0x04bd0008,
+/* 0x0258: timer_done */
+	0xfc1031f4,
+	0xf890fc80,
+/* 0x0261: send_proc */
+	0xf980f900,
+	0x05e89890,
+	0xf004e998,
+	0x89a60486,
+	0xc42a0bf4,
+	0x88940398,
+	0x1880b604,
+	0x98008ebb,
+	0x8ab500fa,
+	0x018db500,
+	0xb5028cb5,
+	0x90b6038b,
+	0x0794f001,
+	0xf404e9b5,
+/* 0x029a: send_done */
+	0x90fc0231,
+	0x00f880fc,
+/* 0x02a0: find */
+	0x580880f9,
+/* 0x02a7: find_loop */
+	0x980131f4,
+	0xaea6008a,
+	0xb6100bf4,
+	0x86b15880,
+	0x1bf40268,
+	0x0132f4f1,
+/* 0x02bc: find_done */
+	0x80fc8eb2,
+/* 0x02c2: send */
+	0xa07e00f8,
+	0x01f40002,
+/* 0x02cb: recv */
+	0xf900f89b,
+	0x9880f990,
+	0xe99805e8,
+	0x0132f404,
+	0x0bf489a6,
+	0x0389c43c,
+	0xf00180b6,
+	0xe8b50784,
+	0x02ea9805,
+	0x8ffef0f9,
+	0xb2f0f901,
+	0x049994ef,
+	0xb600e9bb,
+	0xeb9818e0,
+	0x02ec9803,
+	0x9801ed98,
+	0xa5f900ee,
+	0xf8fef0fc,
+	0x0131f400,
+/* 0x0316: recv_done */
+	0x80fcf0fc,
+	0x00f890fc,
+/* 0x031c: init */
+	0xcf010841,
+	0x11e70011,
+	0x14b60109,
+	0x0014fe08,
+	0xf000e041,
+	0x1c000013,
+	0xbd0001f6,
+	0x00ff0104,
+	0x0001f614,
+	0x020104bd,
+	0x080015f1,
+	0x01f61000,
+	0x4104bd00,
+	0x13f000e2,
+	0x0010fe00,
+	0x011031f4,
+	0xf6380001,
+	0x04bd0001,
+/* 0x0366: init_proc */
+	0xf198580f,
+	0x0016b001,
+	0xf9fa0bf4,
+	0x58f0b615,
+/* 0x0377: mulu32_32_64 */
+	0xf9f20ef4,
+	0xf920f910,
+	0x9540f930,
+	0xd29510e1,
+	0xbdc4bd10,
+	0xc0edffb4,
+	0xb2301dff,
+	0xff34f134,
+	0x1034b6ff,
+	0xbb1045b6,
+	0xb4bb00c3,
+	0x30e2ff01,
+	0x34f134b2,
+	0x34b6ffff,
+	0x1045b610,
+	0xbb00c3bb,
+	0x12ff01b4,
+	0x00b3bb30,
+	0x30fc40fc,
+	0x10fc20fc,
+/* 0x03c6: host_send */
+	0xb04100f8,
+	0x0011cf04,
+	0xcf04a042,
+	0x12a60022,
+	0xc42e0bf4,
+	0xee94071e,
+	0x70e0b704,
+	0x03eb9802,
+	0x9802ec98,
+	0xee9801ed,
+	0x02c27e00,
+	0x0110b600,
+	0x400f1ec4,
+	0x0ef604b0,
+	0xf404bd00,
+/* 0x0402: host_send_done */
+	0x00f8c70e,
+/* 0x0404: host_recv */
+	0xf14e4941,
+	0xa6525413,
+	0xb90bf4e1,
+/* 0x0410: host_recv_wait */
+	0xcf04cc41,
+	0xc8420011,
+	0x0022cf04,
+	0xa60816f0,
+	0xef0bf412,
+	0xb60723c4,
+	0x30b70434,
+	0x3bb502f0,
+	0x023cb503,
+	0xb5013db5,
+	0x20b6003e,
+	0x0f24f001,
+	0xf604c840,
+	0x04bd0002,
+	0x00004002,
+	0xbd0002f6,
+/* 0x0453: host_init */
+	0x4100f804,
+	0x14b60080,
+	0x7015f110,
+	0x04d04002,
+	0xbd0001f6,
+	0x00804104,
+	0xf11014b6,
+	0x4002f015,
+	0x01f604dc,
+	0x0104bd00,
+	0x04c44001,
+	0xbd0001f6,
+/* 0x0483: memx_func_enter */
+	0xf100f804,
+	0xf1162067,
+	0xf1f55d77,
+	0xb2ffff73,
+	0x00047e6e,
+	0xfdd8b200,
+	0x60f90487,
+	0xd0fc80f9,
+	0x2e7ee0fc,
+	0x77f10000,
+	0x73f1fffe,
+	0x6eb2ffff,
+	0x0000047e,
+	0x87fdd8b2,
+	0xf960f904,
+	0xfcd0fc80,
+	0x002e7ee0,
+	0xf067f100,
+	0x7e6eb226,
+	0xb2000004,
+	0x0487fdd8,
+	0x80f960f9,
+	0xe0fcd0fc,
+	0x00002e7e,
+	0xe0400406,
+	0x0006f607,
+/* 0x04ea: memx_func_enter_wait */
+	0xc04604bd,
+	0x0066cf07,
+	0xf40464f0,
+	0x2c06f70b,
+	0xb50066cf,
+	0x00f8f106,
+/* 0x0500: memx_func_leave */
+	0x66cf2c06,
+	0xf206b500,
+	0xe4400406,
+	0x0006f607,
+/* 0x0512: memx_func_leave_wait */
+	0xc04604bd,
+	0x0066cf07,
+	0xf40464f0,
+	0x67f1f71b,
+	0x77f126f0,
+	0x73f00001,
+	0x7e6eb200,
+	0xb2000004,
+	0x0587fdd8,
+	0x80f960f9,
+	0xe0fcd0fc,
+	0x00002e7e,
+	0x162067f1,
+	0x047e6eb2,
+	0xd8b20000,
+	0xf90587fd,
+	0xfc80f960,
+	0x7ee0fcd0,
+	0xf100002e,
+	0xf00aa277,
+	0x6eb20073,
+	0x0000047e,
+	0x87fdd8b2,
+	0xf960f905,
+	0xfcd0fc80,
+	0x002e7ee0,
+/* 0x057b: memx_func_wait_vblank */
+	0xb600f800,
+	0x00f80410,
+/* 0x0580: memx_func_wr32 */
+	0x98001698,
+	0x10b60115,
+	0xf960f908,
+	0xfcd0fc50,
+	0x002e7ee0,
+	0x0242b600,
+	0xf8e81bf4,
+/* 0x059d: memx_func_wait */
+	0xcf2c0800,
+	0x1e980088,
+	0x011d9800,
+	0x98021c98,
+	0x10b6031b,
+	0x00797e10,
+/* 0x05b7: memx_func_delay */
+	0x9800f800,
+	0x10b6001e,
+	0x005d7e04,
+/* 0x05c3: memx_func_train */
+	0xf800f800,
+/* 0x05c5: memx_exec */
+	0xf9e0f900,
+	0xb2c1b2d0,
+/* 0x05cd: memx_exec_next */
+	0x001398b2,
+	0xe70410b6,
+	0xe701f034,
+	0xb601e033,
+	0x30f00132,
+	0xde35980c,
+	0x12a655f9,
+	0x98e51ef4,
+	0x0c98f10b,
+	0x02cbbbf2,
+	0xcf07c44b,
+	0xd0fc00bb,
+	0xc27ee0fc,
+	0x00f80002,
+/* 0x0604: memx_info */
+	0xf401c670,
+/* 0x060a: memx_info_data */
+	0xcc4c0c0b,
+	0x08004b03,
+/* 0x0613: memx_info_train */
+	0x4c090ef4,
+	0x004b0bcc,
+/* 0x0619: memx_info_send */
+	0x02c27e01,
+/* 0x061f: memx_recv */
+	0xb000f800,
+	0x0bf401d6,
+	0x00d6b0a3,
+	0xf8dc0bf4,
+/* 0x062d: memx_init */
+/* 0x062f: perf_recv */
+	0xf800f800,
+/* 0x0631: perf_init */
+/* 0x0633: i2c_drive_scl */
+	0xb000f800,
+	0x0bf40036,
+	0x07e0400d,
+	0xbd0001f6,
+/* 0x0643: i2c_drive_scl_lo */
+	0x4000f804,
+	0x01f607e4,
+	0xf804bd00,
+/* 0x064d: i2c_drive_sda */
+	0x0036b000,
+	0x400d0bf4,
+	0x02f607e0,
+	0xf804bd00,
+/* 0x065d: i2c_drive_sda_lo */
+	0x07e44000,
+	0xbd0002f6,
+/* 0x0667: i2c_sense_scl */
+	0xf400f804,
+	0xc4430132,
+	0x0033cf07,
+	0xf40431fd,
+	0x31f4060b,
+/* 0x0679: i2c_sense_scl_done */
+/* 0x067b: i2c_sense_sda */
+	0xf400f801,
+	0xc4430132,
+	0x0033cf07,
+	0xf40432fd,
+	0x31f4060b,
+/* 0x068d: i2c_sense_sda_done */
+/* 0x068f: i2c_raise_scl */
+	0xf900f801,
+	0x08984440,
+	0x337e0103,
+/* 0x069a: i2c_raise_scl_wait */
+	0xe84e0006,
+	0x005d7e03,
+	0x06677e00,
+	0x0901f400,
+	0xf40142b6,
+/* 0x06ae: i2c_raise_scl_done */
+	0x40fcef1b,
+/* 0x06b2: i2c_start */
+	0x677e00f8,
+	0x11f40006,
+	0x067b7e0d,
+	0x0611f400,
+/* 0x06c3: i2c_start_rep */
+	0x032e0ef4,
+	0x06337e00,
+	0x7e010300,
+	0xbb00064d,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x00068f7e,
+	0xf40464b6,
+/* 0x06ee: i2c_start_send */
+	0x00031d11,
+	0x00064d7e,
+	0x7e13884e,
+	0x0300005d,
+	0x06337e00,
+	0x13884e00,
+	0x00005d7e,
+/* 0x0708: i2c_start_out */
+/* 0x070a: i2c_stop */
+	0x000300f8,
+	0x0006337e,
+	0x4d7e0003,
+	0xe84e0006,
+	0x005d7e03,
+	0x7e010300,
+	0x4e000633,
+	0x5d7e1388,
+	0x01030000,
+	0x00064d7e,
+	0x7e13884e,
+	0xf800005d,
+/* 0x0739: i2c_bitw */
+	0x064d7e00,
+	0x03e84e00,
+	0x00005d7e,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x068f7e50,
+	0x0464b600,
+	0x4e1711f4,
+	0x5d7e1388,
+	0x00030000,
+	0x0006337e,
+	0x7e13884e,
+/* 0x0777: i2c_bitw_out */
+	0xf800005d,
+/* 0x0779: i2c_bitr */
+	0x7e010300,
+	0x4e00064d,
+	0x5d7e03e8,
+	0x76bb0000,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0x7e50fc04,
+	0xb600068f,
+	0x11f40464,
+	0x067b7e1a,
+	0x7e000300,
+	0x4e000633,
+	0x5d7e1388,
+	0x3cf00000,
+	0x0131f401,
+/* 0x07bc: i2c_bitr_done */
+/* 0x07be: i2c_get_byte */
+	0x000500f8,
+/* 0x07c2: i2c_get_byte_next */
+	0x54b60804,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x797e50fc,
+	0x64b60007,
+	0x2a11f404,
+	0xb60553fd,
+	0x1bf40142,
+	0xbb0103d8,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0007397e,
+/* 0x080b: i2c_get_byte_done */
+	0xf80464b6,
+/* 0x080d: i2c_put_byte */
+/* 0x080f: i2c_put_byte_next */
+	0xb6080400,
+	0x54ff0142,
+	0x0076bb38,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x397e50fc,
+	0x64b60007,
+	0x3411f404,
+	0xf40046b0,
+	0x76bbd81b,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0x7e50fc04,
+	0xb6000779,
+	0x11f40464,
+	0x0076bb0f,
+	0xf40136b0,
+	0x32f4061b,
+/* 0x0865: i2c_put_byte_done */
+/* 0x0867: i2c_addr */
+	0xbb00f801,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0006b27e,
+	0xf40464b6,
+	0xc3e72911,
+	0x34b6012e,
+	0x0553fd01,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x080d7e50,
+	0x0464b600,
+/* 0x08ac: i2c_addr_done */
+/* 0x08ae: i2c_acquire_addr */
+	0xcec700f8,
+	0x05e4b6f8,
+	0xd014e0b7,
+/* 0x08ba: i2c_acquire */
+	0xae7e00f8,
+	0x047e0008,
+	0xd9f00000,
+	0x002e7e03,
+/* 0x08cb: i2c_release */
+	0x7e00f800,
+	0x7e0008ae,
+	0xf0000004,
+	0x2e7e03da,
+	0x00f80000,
+/* 0x08dc: i2c_recv */
+	0xc70132f4,
+	0x14b6f8c1,
+	0x2816b002,
+	0x01371ff5,
+	0x0cf413b8,
+	0x00329800,
+	0x0ccc13b8,
+	0x00319800,
+	0xf90231f4,
+	0xf9e0f9d0,
+	0x0067f1d0,
+	0x0063f100,
+	0x01679210,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x08ba7e50,
+	0x0464b600,
+	0xd6b0d0fc,
+	0xb01bf500,
+	0xbb000500,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0008677e,
+	0xf50464b6,
+	0xc700cc11,
+	0x76bbe0c5,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0x7e50fc04,
+	0xb600080d,
+	0x11f50464,
+	0x010500a9,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x08677e50,
+	0x0464b600,
+	0x008711f5,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x07be7e50,
+	0x0464b600,
+	0xcb6711f4,
+	0x76bbe05b,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0x7e50fc04,
+	0xb600070a,
+	0x5bb20464,
+	0x0ef474bd,
+/* 0x09e1: i2c_recv_not_rd08 */
+	0x01d6b041,
+	0x053b1bf4,
+	0x08677e00,
+	0x3211f400,
+	0x7ee0c5c7,
+	0xf400080d,
+	0x00052811,
+	0x0008677e,
+	0xc71f11f4,
+	0x0d7ee0b5,
+	0x11f40008,
+	0x070a7e15,
+	0xc774bd00,
+	0x1bf408c5,
+	0x0232f409,
+/* 0x0a1f: i2c_recv_not_wr08 */
+/* 0x0a1f: i2c_recv_done */
+	0xc7030ef4,
+	0xcb7ef8ce,
+	0xe0fc0008,
+	0x12f4d0fc,
+	0x7e7cb209,
+/* 0x0a33: i2c_recv_exit */
+	0xf80002c2,
+/* 0x0a35: i2c_init */
+/* 0x0a37: test_recv */
+	0x4100f800,
+	0x11cf0458,
+	0x0110b600,
+	0xf6045840,
+	0x04bd0001,
+	0xd900e7f1,
+	0x134fe3f1,
+	0x0002017e,
+/* 0x0a56: test_init */
+	0x004e00f8,
+	0x02017e08,
+/* 0x0a5f: idle_recv */
+	0xf800f800,
+/* 0x0a61: idle */
+	0x0031f400,
+	0xcf045441,
+	0x10b60011,
+	0x04544001,
+	0xbd0001f6,
+/* 0x0a75: idle_loop */
+	0xf4580104,
+/* 0x0a7a: idle_proc */
+/* 0x0a7a: idle_proc_exec */
+	0x10f90232,
+	0xcb7e1eb2,
+	0x10fc0002,
+	0xf40911f4,
+	0x0ef40231,
+/* 0x0a8d: idle_proc_next */
+	0x5810b6f0,
+	0x1bf41fa6,
+	0xe002f4e8,
+	0xf40028f4,
+	0x0000c60e,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3
new file mode 100644
index 0000000..393049f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GT215
+#define HW_TICKS_PER_US 203 // should be 202.5
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gt215_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gt215_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
new file mode 100644
index 0000000..2686f8f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
@@ -0,0 +1,1868 @@
+uint32_t gt215_pmu_data[] = {
+/* 0x0000: proc_kern */
+	0x52544e49,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: proc_list_head */
+	0x54534f48,
+	0x00000512,
+	0x000004af,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x584d454d,
+	0x00000842,
+	0x00000834,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x46524550,
+	0x00000846,
+	0x00000844,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x5f433249,
+	0x00000c76,
+	0x00000b19,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x54534554,
+	0x00000c9f,
+	0x00000c78,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x454c4449,
+	0x00000cab,
+	0x00000ca9,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+	0x00000000,
+/* 0x026c: time_next */
+	0x00000000,
+/* 0x0270: fifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x02f0: rfifo_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0370: memx_func_head */
+	0x00000001,
+	0x00000000,
+	0x00000551,
+/* 0x037c: memx_func_next */
+	0x00000002,
+	0x00000000,
+	0x000005a8,
+	0x00000003,
+	0x00000002,
+	0x0000063a,
+	0x00040004,
+	0x00000000,
+	0x00000656,
+	0x00010005,
+	0x00000000,
+	0x00000673,
+	0x00010006,
+	0x00000000,
+	0x000005f8,
+	0x00000007,
+	0x00000000,
+	0x0000067e,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+	0x00000000,
+/* 0x03c8: memx_ts_end */
+	0x00000000,
+/* 0x03cc: memx_data_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+	0x00001000,
+	0x00004000,
+	0x00010000,
+	0x00000100,
+	0x00040000,
+	0x00100000,
+	0x00400000,
+	0x01000000,
+	0x04000000,
+	0x10000000,
+/* 0x0cf4: i2c_sda_map */
+	0x00002000,
+	0x00008000,
+	0x00020000,
+	0x00000200,
+	0x00080000,
+	0x00200000,
+	0x00800000,
+	0x02000000,
+	0x08000000,
+	0x20000000,
+/* 0x0d1c: i2c_ctrl */
+	0x0000e138,
+	0x0000e150,
+	0x0000e168,
+	0x0000e180,
+	0x0000e254,
+	0x0000e274,
+	0x0000e764,
+	0x0000e780,
+	0x0000e79c,
+	0x0000e7b8,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t gt215_pmu_code[] = {
+	0x039e0ef5,
+/* 0x0004: rd32 */
+	0x07a007f1,
+	0xd00604b6,
+	0x04bd000e,
+	0xf001d7f0,
+	0x07f101d3,
+	0x04b607ac,
+	0x000dd006,
+/* 0x0022: rd32_wait */
+	0xd7f104bd,
+	0xd4b607ac,
+	0x00ddcf06,
+	0x7000d4f1,
+	0xf1f21bf4,
+	0xb607a4d7,
+	0xddcf06d4,
+/* 0x003f: wr32 */
+	0xf100f800,
+	0xb607a007,
+	0x0ed00604,
+	0xf104bd00,
+	0xb607a407,
+	0x0dd00604,
+	0xf004bd00,
+	0xd5f002d7,
+	0x01d3f0f0,
+	0x07ac07f1,
+	0xd00604b6,
+	0x04bd000d,
+/* 0x006c: wr32_wait */
+	0x07acd7f1,
+	0xcf06d4b6,
+	0xd4f100dd,
+	0x1bf47000,
+/* 0x007f: nsec */
+	0xf900f8f2,
+	0xf080f990,
+	0x84b62c87,
+	0x0088cf06,
+/* 0x008c: nsec_loop */
+	0xb62c97f0,
+	0x99cf0694,
+	0x0298bb00,
+	0xf4069eb8,
+	0x80fcf11e,
+	0x00f890fc,
+/* 0x00a4: wait */
+	0x80f990f9,
+	0xb62c87f0,
+	0x88cf0684,
+/* 0x00b1: wait_loop */
+	0x02eeb900,
+	0xb90421f4,
+	0xadfd02da,
+	0x06acb804,
+	0xf0150bf4,
+	0x94b62c97,
+	0x0099cf06,
+	0xb80298bb,
+	0x1ef4069b,
+/* 0x00d5: wait_done */
+	0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+	0x9800f890,
+	0x96b003e9,
+	0x2a0bf400,
+	0xbb9a0a98,
+	0x1cf4029a,
+	0x01d7f00f,
+	0x02dd21f5,
+	0x0ef494bd,
+/* 0x00f9: intr_watchdog_next_time */
+	0x9b0a9815,
+	0xf400a6b0,
+	0x9ab8090b,
+	0x061cf406,
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
+	0x809b0980,
+	0xe0b603e9,
+	0x68e6b158,
+	0xc61bf402,
+/* 0x011a: intr */
+	0x00f900f8,
+	0x80f904bd,
+	0xa0f990f9,
+	0xc0f9b0f9,
+	0xe0f9d0f9,
+	0xf7f0f0f9,
+	0x0188fe00,
+	0x87f180f9,
+	0x84b605d0,
+	0x0088cf06,
+	0xf10180b6,
+	0xb605d007,
+	0x08d00604,
+	0xf004bd00,
+	0x84b60887,
+	0x0088cf06,
+	0xf40289c4,
+	0x0080230b,
+	0x58e7f09b,
+	0x98db21f4,
+	0x96b09b09,
+	0x110bf400,
+	0xb63407f0,
+	0x09d00604,
+	0x8004bd00,
+/* 0x017e: intr_skip_watchdog */
+	0x89e49a09,
+	0x0bf40800,
+	0x8897f148,
+	0x0694b606,
+	0xc40099cf,
+	0x0bf4029a,
+	0xc0c7f12c,
+	0x06c4b604,
+	0xf900cccf,
+	0x48e7f1c0,
+	0x53e3f14f,
+	0x00d7f054,
+	0x034221f5,
+	0x07f1c0fc,
+	0x04b604c0,
+	0x000cd006,
+/* 0x01be: intr_subintr_skip_fifo */
+	0x07f104bd,
+	0x04b60688,
+	0x0009d006,
+/* 0x01ca: intr_skip_subintr */
+	0x89c404bd,
+	0x070bf420,
+	0xffbfa4f1,
+/* 0x01d4: intr_skip_pause */
+	0xf44089c4,
+	0xa4f1070b,
+/* 0x01de: intr_skip_user0 */
+	0x07f0ffbf,
+	0x0604b604,
+	0xbd0008d0,
+	0xfe80fc04,
+	0xf0fc0088,
+	0xd0fce0fc,
+	0xb0fcc0fc,
+	0x90fca0fc,
+	0x00fc80fc,
+	0xf80032f4,
+/* 0x0205: ticks_from_ns */
+	0xf9c0f901,
+	0xcbd7f1b0,
+	0x00d3f000,
+	0x041321f5,
+	0x03e8ccec,
+	0xf400b4b0,
+	0xeeec120b,
+	0xd7f103e8,
+	0xd3f000cb,
+	0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+	0x02ceb904,
+	0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+	0xc0f900f8,
+	0xd7f1b0f9,
+	0xd3f000cb,
+	0x1321f500,
+	0x02ceb904,
+	0xf400b4b0,
+	0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+	0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+	0xd7f100f8,
+	0xd3f000cb,
+	0xecedff00,
+/* 0x0262: timer */
+	0x90f900f8,
+	0x32f480f9,
+	0x03f89810,
+	0xf40086b0,
+	0x84bd651c,
+	0xb63807f0,
+	0x08d00604,
+	0xf004bd00,
+	0x84b63487,
+	0x0088cf06,
+	0xbb9a0998,
+	0xe9bb0298,
+	0x03fe8000,
+	0xb60887f0,
+	0x88cf0684,
+	0x0284f000,
+	0xf0261bf4,
+	0x84b63487,
+	0x0088cf06,
+	0xf406e0b8,
+	0xe8b8090b,
+	0x111cf406,
+/* 0x02b8: timer_reset */
+	0xb63407f0,
+	0x0ed00604,
+	0x8004bd00,
+/* 0x02c6: timer_enable */
+	0x87f09a0e,
+	0x3807f001,
+	0xd00604b6,
+	0x04bd0008,
+/* 0x02d4: timer_done */
+	0xfc1031f4,
+	0xf890fc80,
+/* 0x02dd: send_proc */
+	0xf980f900,
+	0x05e89890,
+	0xf004e998,
+	0x89b80486,
+	0x2a0bf406,
+	0x940398c4,
+	0x80b60488,
+	0x008ebb18,
+	0x8000fa98,
+	0x8d80008a,
+	0x028c8001,
+	0xb6038b80,
+	0x94f00190,
+	0x04e98007,
+/* 0x0317: send_done */
+	0xfc0231f4,
+	0xf880fc90,
+/* 0x031d: find */
+	0xf080f900,
+	0x31f45887,
+/* 0x0325: find_loop */
+	0x008a9801,
+	0xf406aeb8,
+	0x80b6100b,
+	0x6886b158,
+	0xf01bf402,
+/* 0x033b: find_done */
+	0xb90132f4,
+	0x80fc028e,
+/* 0x0342: send */
+	0x21f500f8,
+	0x01f4031d,
+/* 0x034b: recv */
+	0xf900f897,
+	0x9880f990,
+	0xe99805e8,
+	0x0132f404,
+	0xf40689b8,
+	0x89c43d0b,
+	0x0180b603,
+	0x800784f0,
+	0xea9805e8,
+	0xfef0f902,
+	0xf0f9018f,
+	0x9402efb9,
+	0xe9bb0499,
+	0x18e0b600,
+	0x9803eb98,
+	0xed9802ec,
+	0x00ee9801,
+	0xf0fca5f9,
+	0xf400f8fe,
+	0xf0fc0131,
+/* 0x0398: recv_done */
+	0x90fc80fc,
+/* 0x039e: init */
+	0x17f100f8,
+	0x14b60108,
+	0x0011cf06,
+	0x010911e7,
+	0xfe0814b6,
+	0x17f10014,
+	0x13f000e0,
+	0x1c07f000,
+	0xd00604b6,
+	0x04bd0001,
+	0xf0ff17f0,
+	0x04b61407,
+	0x0001d006,
+	0x17f004bd,
+	0x0015f102,
+	0x1007f008,
+	0xd00604b6,
+	0x04bd0001,
+	0x011a17f1,
+	0xfe0013f0,
+	0x31f40010,
+	0x0117f010,
+	0xb63807f0,
+	0x01d00604,
+	0xf004bd00,
+/* 0x0402: init_proc */
+	0xf19858f7,
+	0x0016b001,
+	0xf9fa0bf4,
+	0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+	0xf9f20ef4,
+	0xf920f910,
+	0x9540f930,
+	0xd29510e1,
+	0xbdc4bd10,
+	0xc0edffb4,
+	0xb9301dff,
+	0x34f10234,
+	0x34b6ffff,
+	0x1045b610,
+	0xbb00c3bb,
+	0xe2ff01b4,
+	0x0234b930,
+	0xffff34f1,
+	0xb61034b6,
+	0xc3bb1045,
+	0x01b4bb00,
+	0xbb3012ff,
+	0x40fc00b3,
+	0x20fc30fc,
+	0x00f810fc,
+/* 0x0464: host_send */
+	0x04b017f1,
+	0xcf0614b6,
+	0x27f10011,
+	0x24b604a0,
+	0x0022cf06,
+	0xf40612b8,
+	0x1ec4320b,
+	0x04ee9407,
+	0x0270e0b7,
+	0x9803eb98,
+	0xed9802ec,
+	0x00ee9801,
+	0x034221f5,
+	0xc40110b6,
+	0x07f10f1e,
+	0x04b604b0,
+	0x000ed006,
+	0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+	0xf100f8ba,
+	0xf14e4917,
+	0xb8525413,
+	0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+	0xcc17f1aa,
+	0x0614b604,
+	0xf10011cf,
+	0xb604c827,
+	0x22cf0624,
+	0x0816f000,
+	0xf40612b8,
+	0x23c4e60b,
+	0x0434b607,
+	0x02f030b7,
+	0x80033b80,
+	0x3d80023c,
+	0x003e8001,
+	0xf00120b6,
+	0x07f10f24,
+	0x04b604c8,
+	0x0002d006,
+	0x27f004bd,
+	0x0007f040,
+	0xd00604b6,
+	0x04bd0002,
+/* 0x0512: host_init */
+	0x17f100f8,
+	0x14b60080,
+	0x7015f110,
+	0xd007f102,
+	0x0604b604,
+	0xbd0001d0,
+	0x8017f104,
+	0x1014b600,
+	0x02f015f1,
+	0x04dc07f1,
+	0xd00604b6,
+	0x04bd0001,
+	0xf10117f0,
+	0xb604c407,
+	0x01d00604,
+	0xf804bd00,
+/* 0x0551: memx_func_enter */
+	0x1087f100,
+	0x028eb916,
+	0xb90421f4,
+	0x67f102d7,
+	0x63f1fffc,
+	0x76fdffff,
+	0x0267f104,
+	0x0576fd00,
+	0x70f980f9,
+	0xe0fcd0fc,
+	0xf03f21f4,
+	0x07f10467,
+	0x04b607e0,
+	0x0006d006,
+/* 0x058a: memx_func_enter_wait */
+	0x67f104bd,
+	0x64b607c0,
+	0x0066cf06,
+	0xf40464f0,
+	0x67f0f30b,
+	0x0664b62c,
+	0x800066cf,
+	0x00f8f106,
+/* 0x05a8: memx_func_leave */
+	0xb62c67f0,
+	0x66cf0664,
+	0xf2068000,
+	0xf10467f0,
+	0xb607e407,
+	0x06d00604,
+/* 0x05c3: memx_func_leave_wait */
+	0xf104bd00,
+	0xb607c067,
+	0x66cf0664,
+	0x0464f000,
+	0xf1f31bf4,
+	0xb9161087,
+	0x21f4028e,
+	0x02d7b904,
+	0xffcc67f1,
+	0xffff63f1,
+	0xf90476fd,
+	0xfc70f980,
+	0xf4e0fcd0,
+	0x00f83f21,
+/* 0x05f8: memx_func_wait_vblank */
+	0xb0001698,
+	0x0bf40066,
+	0x0166b013,
+	0xf4060bf4,
+/* 0x060a: memx_func_wait_vblank_head1 */
+	0x77f12e0e,
+	0x0ef40020,
+/* 0x0611: memx_func_wait_vblank_head0 */
+	0x0877f107,
+/* 0x0615: memx_func_wait_vblank_0 */
+	0xc467f100,
+	0x0664b607,
+	0xfd0066cf,
+	0x1bf40467,
+/* 0x0625: memx_func_wait_vblank_1 */
+	0xc467f1f3,
+	0x0664b607,
+	0xfd0066cf,
+	0x0bf40467,
+/* 0x0635: memx_func_wait_vblank_fini */
+	0x0410b6f3,
+/* 0x063a: memx_func_wr32 */
+	0x169800f8,
+	0x01159800,
+	0xf90810b6,
+	0xfc50f960,
+	0xf4e0fcd0,
+	0x42b63f21,
+	0xe91bf402,
+/* 0x0656: memx_func_wait */
+	0x87f000f8,
+	0x0684b62c,
+	0x980088cf,
+	0x1d98001e,
+	0x021c9801,
+	0xb6031b98,
+	0x21f41010,
+/* 0x0673: memx_func_delay */
+	0x9800f8a4,
+	0x10b6001e,
+	0x7f21f404,
+/* 0x067e: memx_func_train */
+	0x57f100f8,
+	0x77f10003,
+	0x97f10000,
+	0x93f00000,
+	0x029eb970,
+	0xb90421f4,
+	0xe7f102d8,
+	0x21f42710,
+/* 0x069d: memx_func_train_loop_outer */
+	0x0158e07f,
+	0x0083f101,
+	0xe097f102,
+	0x1193f011,
+	0x80f990f9,
+	0xe0fcd0fc,
+	0xf93f21f4,
+	0x0067f150,
+/* 0x06bd: memx_func_train_loop_inner */
+	0x1187f100,
+	0x9068ff11,
+	0xfd109894,
+	0x97f10589,
+	0x93f00720,
+	0xf990f910,
+	0xfcd0fc80,
+	0x3f21f4e0,
+	0x008097f1,
+	0xb91093f0,
+	0x21f4029e,
+	0x02d8b904,
+	0xf92088c5,
+	0xfc80f990,
+	0xf4e0fcd0,
+	0x97f13f21,
+	0x93f0053c,
+	0x0287f110,
+	0x0083f130,
+	0xf990f980,
+	0xfcd0fc80,
+	0x3f21f4e0,
+	0x0560e7f1,
+	0xf110e3f0,
+	0xf10000d7,
+	0x908000d3,
+	0xb7f100dc,
+	0xb3f08480,
+	0xa421f41e,
+	0x000057f1,
+	0xffff97f1,
+	0x830093f1,
+/* 0x073c: memx_func_train_loop_4x */
+	0x0080a7f1,
+	0xb910a3f0,
+	0x21f402ae,
+	0x02d8b904,
+	0xffdfb7f1,
+	0xffffb3f1,
+	0xf9048bfd,
+	0xfc80f9a0,
+	0xf4e0fcd0,
+	0xa7f13f21,
+	0xa3f0053c,
+	0x0287f110,
+	0x0083f130,
+	0xf9a0f980,
+	0xfcd0fc80,
+	0x3f21f4e0,
+	0x0560e7f1,
+	0xf110e3f0,
+	0xf10000d7,
+	0xb98000d3,
+	0xb7f102dc,
+	0xb3f02710,
+	0xa421f400,
+	0xf402eeb9,
+	0xddb90421,
+	0x949dff02,
+	0x700150b6,
+	0x1ef40456,
+	0xcc7aa092,
+	0x00a9800b,
+	0xb60160b6,
+	0x66700470,
+	0x001ef510,
+	0xb650fcff,
+	0x56700150,
+	0xd41ef507,
+/* 0x07cf: memx_exec */
+	0xf900f8fe,
+	0xb9d0f9e0,
+	0xb2b902c1,
+/* 0x07d9: memx_exec_next */
+	0x00139802,
+	0xe70410b6,
+	0xe701f034,
+	0xb601e033,
+	0x30f00132,
+	0xde35980c,
+	0x12b855f9,
+	0xe41ef406,
+	0x98f10b98,
+	0xcbbbf20c,
+	0xc4b7f102,
+	0x06b4b607,
+	0xfc00bbcf,
+	0xf5e0fcd0,
+	0xf8034221,
+/* 0x0815: memx_info */
+	0x01c67000,
+/* 0x081b: memx_info_data */
+	0xf10e0bf4,
+	0xf103ccc7,
+	0xf40800b7,
+/* 0x0826: memx_info_train */
+	0xc7f10b0e,
+	0xb7f10bcc,
+/* 0x082e: memx_info_send */
+	0x21f50100,
+	0x00f80342,
+/* 0x0834: memx_recv */
+	0xf401d6b0,
+	0xd6b0980b,
+	0xd80bf400,
+/* 0x0842: memx_init */
+	0x00f800f8,
+/* 0x0844: perf_recv */
+/* 0x0846: perf_init */
+	0x00f800f8,
+/* 0x0848: i2c_drive_scl */
+	0xf40036b0,
+	0x07f1110b,
+	0x04b607e0,
+	0x0001d006,
+	0x00f804bd,
+/* 0x085c: i2c_drive_scl_lo */
+	0x07e407f1,
+	0xd00604b6,
+	0x04bd0001,
+/* 0x086a: i2c_drive_sda */
+	0x36b000f8,
+	0x110bf400,
+	0x07e007f1,
+	0xd00604b6,
+	0x04bd0002,
+/* 0x087e: i2c_drive_sda_lo */
+	0x07f100f8,
+	0x04b607e4,
+	0x0002d006,
+	0x00f804bd,
+/* 0x088c: i2c_sense_scl */
+	0xf10132f4,
+	0xb607c437,
+	0x33cf0634,
+	0x0431fd00,
+	0xf4060bf4,
+/* 0x08a2: i2c_sense_scl_done */
+	0x00f80131,
+/* 0x08a4: i2c_sense_sda */
+	0xf10132f4,
+	0xb607c437,
+	0x33cf0634,
+	0x0432fd00,
+	0xf4060bf4,
+/* 0x08ba: i2c_sense_sda_done */
+	0x00f80131,
+/* 0x08bc: i2c_raise_scl */
+	0x47f140f9,
+	0x37f00898,
+	0x4821f501,
+/* 0x08c9: i2c_raise_scl_wait */
+	0xe8e7f108,
+	0x7f21f403,
+	0x088c21f5,
+	0xb60901f4,
+	0x1bf40142,
+/* 0x08dd: i2c_raise_scl_done */
+	0xf840fcef,
+/* 0x08e1: i2c_start */
+	0x8c21f500,
+	0x0d11f408,
+	0x08a421f5,
+	0xf40611f4,
+/* 0x08f2: i2c_start_rep */
+	0x37f0300e,
+	0x4821f500,
+	0x0137f008,
+	0x086a21f5,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0xbc21f550,
+	0x0464b608,
+/* 0x091f: i2c_start_send */
+	0xf01f11f4,
+	0x21f50037,
+	0xe7f1086a,
+	0x21f41388,
+	0x0037f07f,
+	0x084821f5,
+	0x1388e7f1,
+/* 0x093b: i2c_start_out */
+	0xf87f21f4,
+/* 0x093d: i2c_stop */
+	0x0037f000,
+	0x084821f5,
+	0xf50037f0,
+	0xf1086a21,
+	0xf403e8e7,
+	0x37f07f21,
+	0x4821f501,
+	0x88e7f108,
+	0x7f21f413,
+	0xf50137f0,
+	0xf1086a21,
+	0xf41388e7,
+	0x00f87f21,
+/* 0x0970: i2c_bitw */
+	0x086a21f5,
+	0x03e8e7f1,
+	0xbb7f21f4,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x08bc21f5,
+	0xf40464b6,
+	0xe7f11811,
+	0x21f41388,
+	0x0037f07f,
+	0x084821f5,
+	0x1388e7f1,
+/* 0x09af: i2c_bitw_out */
+	0xf87f21f4,
+/* 0x09b1: i2c_bitr */
+	0x0137f000,
+	0x086a21f5,
+	0x03e8e7f1,
+	0xbb7f21f4,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x08bc21f5,
+	0xf40464b6,
+	0x21f51b11,
+	0x37f008a4,
+	0x4821f500,
+	0x88e7f108,
+	0x7f21f413,
+	0xf4013cf0,
+/* 0x09f6: i2c_bitr_done */
+	0x00f80131,
+/* 0x09f8: i2c_get_byte */
+	0xf00057f0,
+/* 0x09fe: i2c_get_byte_next */
+	0x54b60847,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b609b1,
+	0x2b11f404,
+	0xb60553fd,
+	0x1bf40142,
+	0x0137f0d8,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0x7021f550,
+	0x0464b609,
+/* 0x0a48: i2c_get_byte_done */
+/* 0x0a4a: i2c_put_byte */
+	0x47f000f8,
+/* 0x0a4d: i2c_put_byte_next */
+	0x0142b608,
+	0xbb3854ff,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x097021f5,
+	0xf40464b6,
+	0x46b03411,
+	0xd81bf400,
+	0xb60076bb,
+	0x50f90465,
+	0xbb046594,
+	0x50bd0256,
+	0xfc0475fd,
+	0xb121f550,
+	0x0464b609,
+	0xbb0f11f4,
+	0x36b00076,
+	0x061bf401,
+/* 0x0aa3: i2c_put_byte_done */
+	0xf80132f4,
+/* 0x0aa5: i2c_addr */
+	0x0076bb00,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b608e1,
+	0x2911f404,
+	0x012ec3e7,
+	0xfd0134b6,
+	0x76bb0553,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb60a4a21,
+/* 0x0aea: i2c_addr_done */
+	0x00f80464,
+/* 0x0aec: i2c_acquire_addr */
+	0xb6f8cec7,
+	0xe0b702e4,
+	0xee980d1c,
+/* 0x0afb: i2c_acquire */
+	0xf500f800,
+	0xf40aec21,
+	0xd9f00421,
+	0x3f21f403,
+/* 0x0b0a: i2c_release */
+	0x21f500f8,
+	0x21f40aec,
+	0x03daf004,
+	0xf83f21f4,
+/* 0x0b19: i2c_recv */
+	0x0132f400,
+	0xb6f8c1c7,
+	0x16b00214,
+	0x3a1ff528,
+	0xf413a001,
+	0x0032980c,
+	0x0ccc13a0,
+	0xf4003198,
+	0xd0f90231,
+	0xd0f9e0f9,
+	0x000067f1,
+	0x100063f1,
+	0xbb016792,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0afb21f5,
+	0xfc0464b6,
+	0x00d6b0d0,
+	0x00b31bf5,
+	0xbb0057f0,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x0aa521f5,
+	0xf50464b6,
+	0xc700d011,
+	0x76bbe0c5,
+	0x0465b600,
+	0x659450f9,
+	0x0256bb04,
+	0x75fd50bd,
+	0xf550fc04,
+	0xb60a4a21,
+	0x11f50464,
+	0x57f000ad,
+	0x0076bb01,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b60aa5,
+	0x8a11f504,
+	0x0076bb00,
+	0xf90465b6,
+	0x04659450,
+	0xbd0256bb,
+	0x0475fd50,
+	0x21f550fc,
+	0x64b609f8,
+	0x6a11f404,
+	0xbbe05bcb,
+	0x65b60076,
+	0x9450f904,
+	0x56bb0465,
+	0xfd50bd02,
+	0x50fc0475,
+	0x093d21f5,
+	0xb90464b6,
+	0x74bd025b,
+/* 0x0c1f: i2c_recv_not_rd08 */
+	0xb0430ef4,
+	0x1bf401d6,
+	0x0057f03d,
+	0x0aa521f5,
+	0xc73311f4,
+	0x21f5e0c5,
+	0x11f40a4a,
+	0x0057f029,
+	0x0aa521f5,
+	0xc71f11f4,
+	0x21f5e0b5,
+	0x11f40a4a,
+	0x3d21f515,
+	0xc774bd09,
+	0x1bf408c5,
+	0x0232f409,
+/* 0x0c5f: i2c_recv_not_wr08 */
+/* 0x0c5f: i2c_recv_done */
+	0xc7030ef4,
+	0x21f5f8ce,
+	0xe0fc0b0a,
+	0x12f4d0fc,
+	0x027cb90a,
+	0x034221f5,
+/* 0x0c74: i2c_recv_exit */
+/* 0x0c76: i2c_init */
+	0x00f800f8,
+/* 0x0c78: test_recv */
+	0x05d817f1,
+	0xcf0614b6,
+	0x10b60011,
+	0xd807f101,
+	0x0604b605,
+	0xbd0001d0,
+	0x00e7f104,
+	0x4fe3f1d9,
+	0x6221f513,
+/* 0x0c9f: test_init */
+	0xf100f802,
+	0xf50800e7,
+	0xf8026221,
+/* 0x0ca9: idle_recv */
+/* 0x0cab: idle */
+	0xf400f800,
+	0x17f10031,
+	0x14b605d4,
+	0x0011cf06,
+	0xf10110b6,
+	0xb605d407,
+	0x01d00604,
+/* 0x0cc7: idle_loop */
+	0xf004bd00,
+	0x32f45817,
+/* 0x0ccd: idle_proc */
+/* 0x0ccd: idle_proc_exec */
+	0xb910f902,
+	0x21f5021e,
+	0x10fc034b,
+	0xf40911f4,
+	0x0ef40231,
+/* 0x0ce1: idle_proc_next */
+	0x5810b6ef,
+	0xf4061fb8,
+	0x02f4e61b,
+	0x0028f4dd,
+	0x00bb0ef4,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/host.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/host.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/i2c_.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/i2c_.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/idle.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/idle.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/macros.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/macros.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/perf.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/perf.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/test.fuc
similarity index 100%
rename from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc
rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/test.fuc
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c
new file mode 100644
index 0000000..78a4ea0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gf100.fuc3.h"
+
+struct nvkm_oclass *
+gf100_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0xc0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = _nvkm_pmu_init,
+		.fini = _nvkm_pmu_fini,
+	},
+	.code.data = gf100_pmu_code,
+	.code.size = sizeof(gf100_pmu_code),
+	.data.data = gf100_pmu_data,
+	.data.size = sizeof(gf100_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c
new file mode 100644
index 0000000..6b3a238
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gf110.fuc4.h"
+
+struct nvkm_oclass *
+gf110_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0xd0),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = _nvkm_pmu_init,
+		.fini = _nvkm_pmu_fini,
+	},
+	.code.data = gf110_pmu_code,
+	.code.size = sizeof(gf110_pmu_code),
+	.data.data = gf110_pmu_data,
+	.data.size = sizeof(gf110_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
new file mode 100644
index 0000000..28fdb8e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#define gf110_pmu_code gk104_pmu_code
+#define gf110_pmu_data gk104_pmu_data
+#include "priv.h"
+#include "fuc/gf110.fuc4.h"
+
+static void
+gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
+{
+	nv_mask(pmu, 0x000200, 0x00001000, 0x00000000);
+	nv_rd32(pmu, 0x000200);
+	nv_mask(pmu, 0x000200, 0x08000000, 0x08000000);
+	msleep(50);
+
+	nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002);
+	nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+	nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+	nv_mask(pmu, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000);
+	msleep(50);
+
+	nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000);
+	nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+	nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+	nv_mask(pmu, 0x000200, 0x08000000, 0x00000000);
+	nv_mask(pmu, 0x000200, 0x00001000, 0x00001000);
+	nv_rd32(pmu, 0x000200);
+}
+
+struct nvkm_oclass *
+gk104_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0xe4),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = _nvkm_pmu_init,
+		.fini = _nvkm_pmu_fini,
+	},
+	.code.data = gk104_pmu_code,
+	.code.size = sizeof(gk104_pmu_code),
+	.data.data = gk104_pmu_data,
+	.data.size = sizeof(gk104_pmu_data),
+	.pgob = gk104_pmu_pgob,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c
new file mode 100644
index 0000000..6f9c09a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gk208.fuc5.h"
+
+struct nvkm_oclass *
+gk208_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0x00),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = _nvkm_pmu_init,
+		.fini = _nvkm_pmu_fini,
+	},
+	.code.data = gk208_pmu_code,
+	.code.size = sizeof(gk208_pmu_code),
+	.data.data = gk208_pmu_data,
+	.data.size = sizeof(gk208_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
new file mode 100644
index 0000000..a49934b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 "priv.h"
+
+#include <subdev/clk.h>
+#include <subdev/timer.h>
+#include <subdev/volt.h>
+
+#define BUSY_SLOT	0
+#define CLK_SLOT	7
+
+struct gk20a_pmu_dvfs_data {
+	int p_load_target;
+	int p_load_max;
+	int p_smooth;
+	unsigned int avg_load;
+};
+
+struct gk20a_pmu_priv {
+	struct nvkm_pmu base;
+	struct nvkm_alarm alarm;
+	struct gk20a_pmu_dvfs_data *data;
+};
+
+struct gk20a_pmu_dvfs_dev_status {
+	unsigned long total;
+	unsigned long busy;
+	int cur_state;
+};
+
+static int
+gk20a_pmu_dvfs_target(struct gk20a_pmu_priv *priv, int *state)
+{
+	struct nvkm_clk *clk = nvkm_clk(priv);
+
+	return nvkm_clk_astate(clk, *state, 0, false);
+}
+
+static int
+gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu_priv *priv, int *state)
+{
+	struct nvkm_clk *clk = nvkm_clk(priv);
+
+	*state = clk->pstate;
+	return 0;
+}
+
+static int
+gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv,
+				int *state, int load)
+{
+	struct gk20a_pmu_dvfs_data *data = priv->data;
+	struct nvkm_clk *clk = nvkm_clk(priv);
+	int cur_level, level;
+
+	/* For GK20A, the performance level is directly mapped to pstate */
+	level = cur_level = clk->pstate;
+
+	if (load > data->p_load_max) {
+		level = min(clk->state_nr - 1, level + (clk->state_nr / 3));
+	} else {
+		level += ((load - data->p_load_target) * 10 /
+				data->p_load_target) / 2;
+		level = max(0, level);
+		level = min(clk->state_nr - 1, level);
+	}
+
+	nv_trace(priv, "cur level = %d, new level = %d\n", cur_level, level);
+
+	*state = level;
+
+	if (level == cur_level)
+		return 0;
+	else
+		return 1;
+}
+
+static int
+gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu_priv *priv,
+			      struct gk20a_pmu_dvfs_dev_status *status)
+{
+	status->busy = nv_rd32(priv, 0x10a508 + (BUSY_SLOT * 0x10));
+	status->total= nv_rd32(priv, 0x10a508 + (CLK_SLOT * 0x10));
+	return 0;
+}
+
+static void
+gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu_priv *priv)
+{
+	nv_wr32(priv, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000);
+	nv_wr32(priv, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000);
+}
+
+static void
+gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm)
+{
+	struct gk20a_pmu_priv *priv =
+		container_of(alarm, struct gk20a_pmu_priv, alarm);
+	struct gk20a_pmu_dvfs_data *data = priv->data;
+	struct gk20a_pmu_dvfs_dev_status status;
+	struct nvkm_clk *clk = nvkm_clk(priv);
+	struct nvkm_volt *volt = nvkm_volt(priv);
+	u32 utilization = 0;
+	int state, ret;
+
+	/*
+	 * The PMU is initialized before CLK and VOLT, so we have to make sure the
+	 * CLK and VOLT are ready here.
+	 */
+	if (!clk || !volt)
+		goto resched;
+
+	ret = gk20a_pmu_dvfs_get_dev_status(priv, &status);
+	if (ret) {
+		nv_warn(priv, "failed to get device status\n");
+		goto resched;
+	}
+
+	if (status.total)
+		utilization = div_u64((u64)status.busy * 100, status.total);
+
+	data->avg_load = (data->p_smooth * data->avg_load) + utilization;
+	data->avg_load /= data->p_smooth + 1;
+	nv_trace(priv, "utilization = %d %%, avg_load = %d %%\n",
+			utilization, data->avg_load);
+
+	ret = gk20a_pmu_dvfs_get_cur_state(priv, &state);
+	if (ret) {
+		nv_warn(priv, "failed to get current state\n");
+		goto resched;
+	}
+
+	if (gk20a_pmu_dvfs_get_target_state(priv, &state, data->avg_load)) {
+		nv_trace(priv, "set new state to %d\n", state);
+		gk20a_pmu_dvfs_target(priv, &state);
+	}
+
+resched:
+	gk20a_pmu_dvfs_reset_dev_status(priv);
+	nvkm_timer_alarm(priv, 100000000, alarm);
+}
+
+int
+gk20a_pmu_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_pmu *pmu = (void *)object;
+	struct gk20a_pmu_priv *priv = (void *)pmu;
+
+	nvkm_timer_alarm_cancel(priv, &priv->alarm);
+
+	return nvkm_subdev_fini(&pmu->base, suspend);
+}
+
+int
+gk20a_pmu_init(struct nvkm_object *object)
+{
+	struct nvkm_pmu *pmu = (void *)object;
+	struct gk20a_pmu_priv *priv = (void *)pmu;
+	int ret;
+
+	ret = nvkm_subdev_init(&pmu->base);
+	if (ret)
+		return ret;
+
+	pmu->pgob = nvkm_pmu_pgob;
+
+	/* init pwr perf counter */
+	nv_wr32(pmu, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001);
+	nv_wr32(pmu, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002);
+	nv_wr32(pmu, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003);
+
+	nvkm_timer_alarm(pmu, 2000000000, &priv->alarm);
+	return ret;
+}
+
+struct gk20a_pmu_dvfs_data gk20a_dvfs_data= {
+	.p_load_target = 70,
+	.p_load_max = 90,
+	.p_smooth = 1,
+};
+
+static int
+gk20a_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct gk20a_pmu_priv *priv;
+	int ret;
+
+	ret = nvkm_pmu_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->data = &gk20a_dvfs_data;
+
+	nvkm_alarm_init(&priv->alarm, gk20a_pmu_dvfs_work);
+	return 0;
+}
+
+struct nvkm_oclass *
+gk20a_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0xea),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = gk20a_pmu_init,
+		.fini = gk20a_pmu_fini,
+	},
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
new file mode 100644
index 0000000..30aaeb2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gt215.fuc3.h"
+
+static int
+gt215_pmu_init(struct nvkm_object *object)
+{
+	struct nvkm_pmu *pmu = (void *)object;
+	nv_mask(pmu, 0x022210, 0x00000001, 0x00000000);
+	nv_mask(pmu, 0x022210, 0x00000001, 0x00000001);
+	return nvkm_pmu_init(pmu);
+}
+
+struct nvkm_oclass *
+gt215_pmu_oclass = &(struct nvkm_pmu_impl) {
+	.base.handle = NV_SUBDEV(PMU, 0xa3),
+	.base.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = _nvkm_pmu_ctor,
+		.dtor = _nvkm_pmu_dtor,
+		.init = gt215_pmu_init,
+		.fini = _nvkm_pmu_fini,
+	},
+	.code.data = gt215_pmu_code,
+	.code.size = sizeof(gt215_pmu_code),
+	.data.data = gt215_pmu_data,
+	.data.size = sizeof(gt215_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
new file mode 100644
index 0000000..b75c5b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
@@ -0,0 +1,200 @@
+#ifndef __NVKM_PMU_MEMX_H__
+#define __NVKM_PMU_MEMX_H__
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nvkm_memx {
+	struct nvkm_pmu *pmu;
+	u32 base;
+	u32 size;
+	struct {
+		u32 mthd;
+		u32 size;
+		u32 data[64];
+	} c;
+};
+
+static void
+memx_out(struct nvkm_memx *memx)
+{
+	struct nvkm_pmu *pmu = memx->pmu;
+	int i;
+
+	if (memx->c.mthd) {
+		nv_wr32(pmu, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
+		for (i = 0; i < memx->c.size; i++)
+			nv_wr32(pmu, 0x10a1c4, memx->c.data[i]);
+		memx->c.mthd = 0;
+		memx->c.size = 0;
+	}
+}
+
+static void
+memx_cmd(struct nvkm_memx *memx, u32 mthd, u32 size, u32 data[])
+{
+	if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
+	    (memx->c.mthd && memx->c.mthd != mthd))
+		memx_out(memx);
+	memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
+	memx->c.size += size;
+	memx->c.mthd  = mthd;
+}
+
+int
+nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx)
+{
+	struct nvkm_memx *memx;
+	u32 reply[2];
+	int ret;
+
+	ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO,
+			   MEMX_INFO_DATA, 0);
+	if (ret)
+		return ret;
+
+	memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL);
+	if (!memx)
+		return -ENOMEM;
+	memx->pmu = pmu;
+	memx->base = reply[0];
+	memx->size = reply[1];
+
+	/* acquire data segment access */
+	do {
+		nv_wr32(pmu, 0x10a580, 0x00000003);
+	} while (nv_rd32(pmu, 0x10a580) != 0x00000003);
+	nv_wr32(pmu, 0x10a1c0, 0x01000000 | memx->base);
+	return 0;
+}
+
+int
+nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec)
+{
+	struct nvkm_memx *memx = *pmemx;
+	struct nvkm_pmu *pmu = memx->pmu;
+	u32 finish, reply[2];
+
+	/* flush the cache... */
+	memx_out(memx);
+
+	/* release data segment access */
+	finish = nv_rd32(pmu, 0x10a1c0) & 0x00ffffff;
+	nv_wr32(pmu, 0x10a580, 0x00000000);
+
+	/* call MEMX process to execute the script, and wait for reply */
+	if (exec) {
+		pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC,
+			     memx->base, finish);
+	}
+
+	nv_debug(memx->pmu, "Exec took %uns, PMU_IN %08x\n",
+		 reply[0], reply[1]);
+	kfree(memx);
+	return 0;
+}
+
+void
+nvkm_memx_wr32(struct nvkm_memx *memx, u32 addr, u32 data)
+{
+	nv_debug(memx->pmu, "R[%06x] = 0x%08x\n", addr, data);
+	memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data });
+}
+
+void
+nvkm_memx_wait(struct nvkm_memx *memx,
+		  u32 addr, u32 mask, u32 data, u32 nsec)
+{
+	nv_debug(memx->pmu, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
+				addr, mask, data, nsec);
+	memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec });
+	memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec)
+{
+	nv_debug(memx->pmu, "    DELAY = %d ns\n", nsec);
+	memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec });
+	memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_wait_vblank(struct nvkm_memx *memx)
+{
+	struct nvkm_pmu *pmu = memx->pmu;
+	u32 heads, x, y, px = 0;
+	int i, head_sync;
+
+	if (nv_device(pmu)->chipset < 0xd0) {
+		heads = nv_rd32(pmu, 0x610050);
+		for (i = 0; i < 2; i++) {
+			/* Heuristic: sync to head with biggest resolution */
+			if (heads & (2 << (i << 3))) {
+				x = nv_rd32(pmu, 0x610b40 + (0x540 * i));
+				y = (x & 0xffff0000) >> 16;
+				x &= 0x0000ffff;
+				if ((x * y) > px) {
+					px = (x * y);
+					head_sync = i;
+				}
+			}
+		}
+	}
+
+	if (px == 0) {
+		nv_debug(memx->pmu, "WAIT VBLANK !NO ACTIVE HEAD\n");
+		return;
+	}
+
+	nv_debug(memx->pmu, "WAIT VBLANK HEAD%d\n", head_sync);
+	memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync });
+	memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_train(struct nvkm_memx *memx)
+{
+	nv_debug(memx->pmu, "   MEM TRAIN\n");
+	memx_cmd(memx, MEMX_TRAIN, 0, NULL);
+}
+
+int
+nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize)
+{
+	u32 reply[2], base, size, i;
+	int ret;
+
+	ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO,
+			   MEMX_INFO_TRAIN, 0);
+	if (ret)
+		return ret;
+
+	base = reply[0];
+	size = reply[1] >> 2;
+	if (size > rsize)
+		return -ENOMEM;
+
+	/* read the packet */
+	nv_wr32(pmu, 0x10a1c0, 0x02000000 | base);
+
+	for (i = 0; i < size; i++)
+		res[i] = nv_rd32(pmu, 0x10a1c4);
+
+	return 0;
+}
+
+void
+nvkm_memx_block(struct nvkm_memx *memx)
+{
+	nv_debug(memx->pmu, "   HOST BLOCKED\n");
+	memx_cmd(memx, MEMX_ENTER, 0, NULL);
+}
+
+void
+nvkm_memx_unblock(struct nvkm_memx *memx)
+{
+	nv_debug(memx->pmu, "   HOST UNBLOCKED\n");
+	memx_cmd(memx, MEMX_LEAVE, 0, NULL);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
new file mode 100644
index 0000000..9984105
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
@@ -0,0 +1,43 @@
+#ifndef __NVKM_PMU_PRIV_H__
+#define __NVKM_PMU_PRIV_H__
+#include <subdev/pmu.h>
+#include <subdev/pmu/fuc/os.h>
+
+#define nvkm_pmu_create(p, e, o, d)                                         \
+	nvkm_pmu_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_pmu_destroy(p)                                                 \
+	nvkm_subdev_destroy(&(p)->base)
+#define nvkm_pmu_init(p) ({                                                 \
+	struct nvkm_pmu *_pmu = (p);                                       \
+	_nvkm_pmu_init(nv_object(_pmu));                                   \
+})
+#define nvkm_pmu_fini(p,s) ({                                               \
+	struct nvkm_pmu *_pmu = (p);                                       \
+	_nvkm_pmu_fini(nv_object(_pmu), (s));                              \
+})
+
+int nvkm_pmu_create_(struct nvkm_object *, struct nvkm_object *,
+			struct nvkm_oclass *, int, void **);
+
+int _nvkm_pmu_ctor(struct nvkm_object *, struct nvkm_object *,
+		      struct nvkm_oclass *, void *, u32,
+		      struct nvkm_object **);
+#define _nvkm_pmu_dtor _nvkm_subdev_dtor
+int _nvkm_pmu_init(struct nvkm_object *);
+int _nvkm_pmu_fini(struct nvkm_object *, bool);
+void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable);
+
+struct nvkm_pmu_impl {
+	struct nvkm_oclass base;
+	struct {
+		u32 *data;
+		u32  size;
+	} code;
+	struct {
+		u32 *data;
+		u32  size;
+	} data;
+
+	void (*pgob)(struct nvkm_pmu *, bool);
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
new file mode 100644
index 0000000..5837cf1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
@@ -0,0 +1,13 @@
+nvkm-y += nvkm/subdev/therm/base.o
+nvkm-y += nvkm/subdev/therm/fan.o
+nvkm-y += nvkm/subdev/therm/fannil.o
+nvkm-y += nvkm/subdev/therm/fanpwm.o
+nvkm-y += nvkm/subdev/therm/fantog.o
+nvkm-y += nvkm/subdev/therm/ic.o
+nvkm-y += nvkm/subdev/therm/temp.o
+nvkm-y += nvkm/subdev/therm/nv40.o
+nvkm-y += nvkm/subdev/therm/nv50.o
+nvkm-y += nvkm/subdev/therm/g84.o
+nvkm-y += nvkm/subdev/therm/gt215.o
+nvkm-y += nvkm/subdev/therm/gf110.o
+nvkm-y += nvkm/subdev/therm/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
new file mode 100644
index 0000000..ec327cb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+static int
+nvkm_therm_update_trip(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_trip_point *trip = priv->fan->bios.trip,
+				       *cur_trip = NULL,
+				       *last_trip = priv->last_trip;
+	u8  temp = therm->temp_get(therm);
+	u16 duty, i;
+
+	/* look for the trip point corresponding to the current temperature */
+	cur_trip = NULL;
+	for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) {
+		if (temp >= trip[i].temp)
+			cur_trip = &trip[i];
+	}
+
+	/* account for the hysteresis cycle */
+	if (last_trip && temp <= (last_trip->temp) &&
+	    temp > (last_trip->temp - last_trip->hysteresis))
+		cur_trip = last_trip;
+
+	if (cur_trip) {
+		duty = cur_trip->fan_duty;
+		priv->last_trip = cur_trip;
+	} else {
+		duty = 0;
+		priv->last_trip = NULL;
+	}
+
+	return duty;
+}
+
+static int
+nvkm_therm_update_linear(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	u8  linear_min_temp = priv->fan->bios.linear_min_temp;
+	u8  linear_max_temp = priv->fan->bios.linear_max_temp;
+	u8  temp = therm->temp_get(therm);
+	u16 duty;
+
+	/* handle the non-linear part first */
+	if (temp < linear_min_temp)
+		return priv->fan->bios.min_duty;
+	else if (temp > linear_max_temp)
+		return priv->fan->bios.max_duty;
+
+	/* we are in the linear zone */
+	duty  = (temp - linear_min_temp);
+	duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty);
+	duty /= (linear_max_temp - linear_min_temp);
+	duty += priv->fan->bios.min_duty;
+	return duty;
+}
+
+static void
+nvkm_therm_update(struct nvkm_therm *therm, int mode)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(therm);
+	struct nvkm_therm_priv *priv = (void *)therm;
+	unsigned long flags;
+	bool immd = true;
+	bool poll = true;
+	int duty = -1;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (mode < 0)
+		mode = priv->mode;
+	priv->mode = mode;
+
+	switch (mode) {
+	case NVKM_THERM_CTRL_MANUAL:
+		ptimer->alarm_cancel(ptimer, &priv->alarm);
+		duty = nvkm_therm_fan_get(therm);
+		if (duty < 0)
+			duty = 100;
+		poll = false;
+		break;
+	case NVKM_THERM_CTRL_AUTO:
+		switch(priv->fan->bios.fan_mode) {
+		case NVBIOS_THERM_FAN_TRIP:
+			duty = nvkm_therm_update_trip(therm);
+			break;
+		case NVBIOS_THERM_FAN_LINEAR:
+			duty = nvkm_therm_update_linear(therm);
+			break;
+		case NVBIOS_THERM_FAN_OTHER:
+			if (priv->cstate)
+				duty = priv->cstate;
+			poll = false;
+			break;
+		}
+		immd = false;
+		break;
+	case NVKM_THERM_CTRL_NONE:
+	default:
+		ptimer->alarm_cancel(ptimer, &priv->alarm);
+		poll = false;
+	}
+
+	if (list_empty(&priv->alarm.head) && poll)
+		ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (duty >= 0) {
+		nv_debug(therm, "FAN target request: %d%%\n", duty);
+		nvkm_therm_fan_set(therm, immd, duty);
+	}
+}
+
+int
+nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir)
+{
+	struct nvkm_therm_priv *priv = (void *)ptherm;
+	if (!dir || (dir < 0 && fan < priv->cstate) ||
+		    (dir > 0 && fan > priv->cstate)) {
+		nv_debug(ptherm, "default fan speed -> %d%%\n", fan);
+		priv->cstate = fan;
+		nvkm_therm_update(ptherm, -1);
+	}
+	return 0;
+}
+
+static void
+nvkm_therm_alarm(struct nvkm_alarm *alarm)
+{
+	struct nvkm_therm_priv *priv =
+	       container_of(alarm, struct nvkm_therm_priv, alarm);
+	nvkm_therm_update(&priv->base, -1);
+}
+
+int
+nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_device *device = nv_device(therm);
+	static const char *name[] = {
+		"disabled",
+		"manual",
+		"automatic"
+	};
+
+	/* The default PPWR ucode on fermi interferes with fan management */
+	if ((mode >= ARRAY_SIZE(name)) ||
+	    (mode != NVKM_THERM_CTRL_NONE && device->card_type >= NV_C0 &&
+	     !nvkm_subdev(device, NVDEV_SUBDEV_PMU)))
+		return -EINVAL;
+
+	/* do not allow automatic fan management if the thermal sensor is
+	 * not available */
+	if (mode == NVKM_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
+		return -EINVAL;
+
+	if (priv->mode == mode)
+		return 0;
+
+	nv_info(therm, "fan management: %s\n", name[mode]);
+	nvkm_therm_update(therm, mode);
+	return 0;
+}
+
+int
+nvkm_therm_attr_get(struct nvkm_therm *therm,
+		       enum nvkm_therm_attr_type type)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	switch (type) {
+	case NVKM_THERM_ATTR_FAN_MIN_DUTY:
+		return priv->fan->bios.min_duty;
+	case NVKM_THERM_ATTR_FAN_MAX_DUTY:
+		return priv->fan->bios.max_duty;
+	case NVKM_THERM_ATTR_FAN_MODE:
+		return priv->mode;
+	case NVKM_THERM_ATTR_THRS_FAN_BOOST:
+		return priv->bios_sensor.thrs_fan_boost.temp;
+	case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
+		return priv->bios_sensor.thrs_fan_boost.hysteresis;
+	case NVKM_THERM_ATTR_THRS_DOWN_CLK:
+		return priv->bios_sensor.thrs_down_clock.temp;
+	case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
+		return priv->bios_sensor.thrs_down_clock.hysteresis;
+	case NVKM_THERM_ATTR_THRS_CRITICAL:
+		return priv->bios_sensor.thrs_critical.temp;
+	case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
+		return priv->bios_sensor.thrs_critical.hysteresis;
+	case NVKM_THERM_ATTR_THRS_SHUTDOWN:
+		return priv->bios_sensor.thrs_shutdown.temp;
+	case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
+		return priv->bios_sensor.thrs_shutdown.hysteresis;
+	}
+
+	return -EINVAL;
+}
+
+int
+nvkm_therm_attr_set(struct nvkm_therm *therm,
+		    enum nvkm_therm_attr_type type, int value)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	switch (type) {
+	case NVKM_THERM_ATTR_FAN_MIN_DUTY:
+		if (value < 0)
+			value = 0;
+		if (value > priv->fan->bios.max_duty)
+			value = priv->fan->bios.max_duty;
+		priv->fan->bios.min_duty = value;
+		return 0;
+	case NVKM_THERM_ATTR_FAN_MAX_DUTY:
+		if (value < 0)
+			value = 0;
+		if (value < priv->fan->bios.min_duty)
+			value = priv->fan->bios.min_duty;
+		priv->fan->bios.max_duty = value;
+		return 0;
+	case NVKM_THERM_ATTR_FAN_MODE:
+		return nvkm_therm_fan_mode(therm, value);
+	case NVKM_THERM_ATTR_THRS_FAN_BOOST:
+		priv->bios_sensor.thrs_fan_boost.temp = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
+		priv->bios_sensor.thrs_fan_boost.hysteresis = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_DOWN_CLK:
+		priv->bios_sensor.thrs_down_clock.temp = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
+		priv->bios_sensor.thrs_down_clock.hysteresis = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_CRITICAL:
+		priv->bios_sensor.thrs_critical.temp = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
+		priv->bios_sensor.thrs_critical.hysteresis = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_SHUTDOWN:
+		priv->bios_sensor.thrs_shutdown.temp = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
+		priv->bios_sensor.thrs_shutdown.hysteresis = value;
+		priv->sensor.program_alarms(therm);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int
+_nvkm_therm_init(struct nvkm_object *object)
+{
+	struct nvkm_therm *therm = (void *)object;
+	struct nvkm_therm_priv *priv = (void *)therm;
+	int ret;
+
+	ret = nvkm_subdev_init(&therm->base);
+	if (ret)
+		return ret;
+
+	if (priv->suspend >= 0) {
+		/* restore the pwm value only when on manual or auto mode */
+		if (priv->suspend > 0)
+			nvkm_therm_fan_set(therm, true, priv->fan->percent);
+
+		nvkm_therm_fan_mode(therm, priv->suspend);
+	}
+	nvkm_therm_sensor_init(therm);
+	nvkm_therm_fan_init(therm);
+	return 0;
+}
+
+int
+_nvkm_therm_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nvkm_therm *therm = (void *)object;
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	nvkm_therm_fan_fini(therm, suspend);
+	nvkm_therm_sensor_fini(therm, suspend);
+	if (suspend) {
+		priv->suspend = priv->mode;
+		priv->mode = NVKM_THERM_CTRL_NONE;
+	}
+
+	return nvkm_subdev_fini(&therm->base, suspend);
+}
+
+int
+nvkm_therm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		   struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PTHERM",
+				  "therm", length, pobject);
+	priv = *pobject;
+	if (ret)
+		return ret;
+
+	nvkm_alarm_init(&priv->alarm, nvkm_therm_alarm);
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->sensor.alarm_program_lock);
+
+	priv->base.fan_get = nvkm_therm_fan_user_get;
+	priv->base.fan_set = nvkm_therm_fan_user_set;
+	priv->base.fan_sense = nvkm_therm_fan_sense;
+	priv->base.attr_get = nvkm_therm_attr_get;
+	priv->base.attr_set = nvkm_therm_attr_set;
+	priv->mode = priv->suspend = -1; /* undefined */
+	return 0;
+}
+
+int
+nvkm_therm_preinit(struct nvkm_therm *therm)
+{
+	nvkm_therm_sensor_ctor(therm);
+	nvkm_therm_ic_ctor(therm);
+	nvkm_therm_fan_ctor(therm);
+
+	nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
+	nvkm_therm_sensor_preinit(therm);
+	return 0;
+}
+
+void
+_nvkm_therm_dtor(struct nvkm_object *object)
+{
+	struct nvkm_therm_priv *priv = (void *)object;
+	kfree(priv->fan);
+	nvkm_subdev_destroy(&priv->base.base);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
new file mode 100644
index 0000000..434fa74
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/bios/fan.h>
+#include <subdev/gpio.h>
+#include <subdev/timer.h>
+
+static int
+nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target)
+{
+	struct nvkm_therm *therm = fan->parent;
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_timer *ptimer = nvkm_timer(priv);
+	unsigned long flags;
+	int ret = 0;
+	int duty;
+
+	/* update target fan speed, restricting to allowed range */
+	spin_lock_irqsave(&fan->lock, flags);
+	if (target < 0)
+		target = fan->percent;
+	target = max_t(u8, target, fan->bios.min_duty);
+	target = min_t(u8, target, fan->bios.max_duty);
+	if (fan->percent != target) {
+		nv_debug(therm, "FAN target: %d\n", target);
+		fan->percent = target;
+	}
+
+	/* check that we're not already at the target duty cycle */
+	duty = fan->get(therm);
+	if (duty == target) {
+		spin_unlock_irqrestore(&fan->lock, flags);
+		return 0;
+	}
+
+	/* smooth out the fanspeed increase/decrease */
+	if (!immediate && duty >= 0) {
+		/* the constant "3" is a rough approximation taken from
+		 * nvidia's behaviour.
+		 * it is meant to bump the fan speed more incrementally
+		 */
+		if (duty < target)
+			duty = min(duty + 3, target);
+		else if (duty > target)
+			duty = max(duty - 3, target);
+	} else {
+		duty = target;
+	}
+
+	nv_debug(therm, "FAN update: %d\n", duty);
+	ret = fan->set(therm, duty);
+	if (ret) {
+		spin_unlock_irqrestore(&fan->lock, flags);
+		return ret;
+	}
+
+	/* fan speed updated, drop the fan lock before grabbing the
+	 * alarm-scheduling lock and risking a deadlock
+	 */
+	spin_unlock_irqrestore(&fan->lock, flags);
+
+	/* schedule next fan update, if not at target speed already */
+	if (list_empty(&fan->alarm.head) && target != duty) {
+		u16 bump_period = fan->bios.bump_period;
+		u16 slow_down_period = fan->bios.slow_down_period;
+		u64 delay;
+
+		if (duty > target)
+			delay = slow_down_period;
+		else if (duty == target)
+			delay = min(bump_period, slow_down_period) ;
+		else
+			delay = bump_period;
+
+		ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
+	}
+
+	return ret;
+}
+
+static void
+nvkm_fan_alarm(struct nvkm_alarm *alarm)
+{
+	struct nvkm_fan *fan = container_of(alarm, struct nvkm_fan, alarm);
+	nvkm_fan_update(fan, false, -1);
+}
+
+int
+nvkm_therm_fan_get(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	return priv->fan->get(therm);
+}
+
+int
+nvkm_therm_fan_set(struct nvkm_therm *therm, bool immediate, int percent)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	return nvkm_fan_update(priv->fan, immediate, percent);
+}
+
+int
+nvkm_therm_fan_sense(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_timer *ptimer = nvkm_timer(therm);
+	struct nvkm_gpio *gpio = nvkm_gpio(therm);
+	u32 cycles, cur, prev;
+	u64 start, end, tach;
+
+	if (priv->fan->tach.func == DCB_GPIO_UNUSED)
+		return -ENODEV;
+
+	/* Time a complete rotation and extrapolate to RPM:
+	 * When the fan spins, it changes the value of GPIO FAN_SENSE.
+	 * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
+	 */
+	start = ptimer->read(ptimer);
+	prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
+	cycles = 0;
+	do {
+		usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
+
+		cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
+		if (prev != cur) {
+			if (!start)
+				start = ptimer->read(ptimer);
+			cycles++;
+			prev = cur;
+		}
+	} while (cycles < 5 && ptimer->read(ptimer) - start < 250000000);
+	end = ptimer->read(ptimer);
+
+	if (cycles == 5) {
+		tach = (u64)60000000000ULL;
+		do_div(tach, (end - start));
+		return tach;
+	} else
+		return 0;
+}
+
+int
+nvkm_therm_fan_user_get(struct nvkm_therm *therm)
+{
+	return nvkm_therm_fan_get(therm);
+}
+
+int
+nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	if (priv->mode != NVKM_THERM_CTRL_MANUAL)
+		return -EINVAL;
+
+	return nvkm_therm_fan_set(therm, true, percent);
+}
+
+static void
+nvkm_therm_fan_set_defaults(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	priv->fan->bios.pwm_freq = 0;
+	priv->fan->bios.min_duty = 0;
+	priv->fan->bios.max_duty = 100;
+	priv->fan->bios.bump_period = 500;
+	priv->fan->bios.slow_down_period = 2000;
+	priv->fan->bios.linear_min_temp = 40;
+	priv->fan->bios.linear_max_temp = 85;
+}
+
+static void
+nvkm_therm_fan_safety_checks(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	if (priv->fan->bios.min_duty > 100)
+		priv->fan->bios.min_duty = 100;
+	if (priv->fan->bios.max_duty > 100)
+		priv->fan->bios.max_duty = 100;
+
+	if (priv->fan->bios.min_duty > priv->fan->bios.max_duty)
+		priv->fan->bios.min_duty = priv->fan->bios.max_duty;
+}
+
+int
+nvkm_therm_fan_init(struct nvkm_therm *therm)
+{
+	return 0;
+}
+
+int
+nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_timer *ptimer = nvkm_timer(therm);
+
+	if (suspend)
+		ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
+	return 0;
+}
+
+int
+nvkm_therm_fan_ctor(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_gpio *gpio = nvkm_gpio(therm);
+	struct nvkm_bios *bios = nvkm_bios(therm);
+	struct dcb_gpio_func func;
+	int ret;
+
+	/* attempt to locate a drivable fan, and determine control method */
+	ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
+	if (ret == 0) {
+		/* FIXME: is this really the place to perform such checks ? */
+		if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
+			nv_debug(therm, "GPIO_FAN is in input mode\n");
+			ret = -EINVAL;
+		} else {
+			ret = nvkm_fanpwm_create(therm, &func);
+			if (ret != 0)
+				ret = nvkm_fantog_create(therm, &func);
+		}
+	}
+
+	/* no controllable fan found, create a dummy fan module */
+	if (ret != 0) {
+		ret = nvkm_fannil_create(therm);
+		if (ret)
+			return ret;
+	}
+
+	nv_info(therm, "FAN control: %s\n", priv->fan->type);
+
+	/* read the current speed, it is useful when resuming */
+	priv->fan->percent = nvkm_therm_fan_get(therm);
+
+	/* attempt to detect a tachometer connection */
+	ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
+	if (ret)
+		priv->fan->tach.func = DCB_GPIO_UNUSED;
+
+	/* initialise fan bump/slow update handling */
+	priv->fan->parent = therm;
+	nvkm_alarm_init(&priv->fan->alarm, nvkm_fan_alarm);
+	spin_lock_init(&priv->fan->lock);
+
+	/* other random init... */
+	nvkm_therm_fan_set_defaults(therm);
+	nvbios_perf_fan_parse(bios, &priv->fan->perf);
+	if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
+		nv_debug(therm, "parsing the fan table failed\n");
+		if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
+			nv_error(therm, "parsing both fan tables failed\n");
+	}
+	nvkm_therm_fan_safety_checks(therm);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c
new file mode 100644
index 0000000..534e597
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nvkm_fannil_get(struct nvkm_therm *therm)
+{
+	return -ENODEV;
+}
+
+static int
+nvkm_fannil_set(struct nvkm_therm *therm, int percent)
+{
+	return -ENODEV;
+}
+
+int
+nvkm_fannil_create(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fan *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	tpriv->fan = priv;
+	if (!priv)
+		return -ENOMEM;
+
+	priv->type = "none / external";
+	priv->get = nvkm_fannil_get;
+	priv->set = nvkm_fannil_set;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c
new file mode 100644
index 0000000..bde5cea
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/fan.h>
+#include <subdev/gpio.h>
+
+struct nvkm_fanpwm_priv {
+	struct nvkm_fan base;
+	struct dcb_gpio_func func;
+};
+
+static int
+nvkm_fanpwm_get(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan;
+	struct nvkm_gpio *gpio = nvkm_gpio(therm);
+	int card_type = nv_device(therm)->card_type;
+	u32 divs, duty;
+	int ret;
+
+	ret = therm->pwm_get(therm, priv->func.line, &divs, &duty);
+	if (ret == 0 && divs) {
+		divs = max(divs, duty);
+		if (card_type <= NV_40 || (priv->func.log[0] & 1))
+			duty = divs - duty;
+		return (duty * 100) / divs;
+	}
+
+	return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100;
+}
+
+static int
+nvkm_fanpwm_set(struct nvkm_therm *therm, int percent)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan;
+	int card_type = nv_device(therm)->card_type;
+	u32 divs, duty;
+	int ret;
+
+	divs = priv->base.perf.pwm_divisor;
+	if (priv->base.bios.pwm_freq) {
+		divs = 1;
+		if (therm->pwm_clock)
+			divs = therm->pwm_clock(therm, priv->func.line);
+		divs /= priv->base.bios.pwm_freq;
+	}
+
+	duty = ((divs * percent) + 99) / 100;
+	if (card_type <= NV_40 || (priv->func.log[0] & 1))
+		duty = divs - duty;
+
+	ret = therm->pwm_set(therm, priv->func.line, divs, duty);
+	if (ret == 0)
+		ret = therm->pwm_ctrl(therm, priv->func.line, true);
+	return ret;
+}
+
+int
+nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
+{
+	struct nvkm_device *device = nv_device(therm);
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_bios *bios = nvkm_bios(therm);
+	struct nvkm_fanpwm_priv *priv;
+	struct nvbios_therm_fan fan;
+	u32 divs, duty;
+
+	nvbios_fan_parse(bios, &fan);
+
+	if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) ||
+	    !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE ||
+	     therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV)
+		return -ENODEV;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	tpriv->fan = &priv->base;
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base.type = "PWM";
+	priv->base.get = nvkm_fanpwm_get;
+	priv->base.set = nvkm_fanpwm_set;
+	priv->func = *func;
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
new file mode 100644
index 0000000..4ce041e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/gpio.h>
+#include <subdev/timer.h>
+
+struct nvkm_fantog_priv {
+	struct nvkm_fan base;
+	struct nvkm_alarm alarm;
+	spinlock_t lock;
+	u32 period_us;
+	u32 percent;
+	struct dcb_gpio_func func;
+};
+
+static void
+nvkm_fantog_update(struct nvkm_fantog_priv *priv, int percent)
+{
+	struct nvkm_therm_priv *tpriv = (void *)priv->base.parent;
+	struct nvkm_timer *ptimer = nvkm_timer(tpriv);
+	struct nvkm_gpio *gpio = nvkm_gpio(tpriv);
+	unsigned long flags;
+	int duty;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (percent < 0)
+		percent = priv->percent;
+	priv->percent = percent;
+
+	duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff);
+	gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
+
+	if (list_empty(&priv->alarm.head) && percent != (duty * 100)) {
+		u64 next_change = (percent * priv->period_us) / 100;
+		if (!duty)
+			next_change = priv->period_us - next_change;
+		ptimer->alarm(ptimer, next_change * 1000, &priv->alarm);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nvkm_fantog_alarm(struct nvkm_alarm *alarm)
+{
+	struct nvkm_fantog_priv *priv =
+	       container_of(alarm, struct nvkm_fantog_priv, alarm);
+	nvkm_fantog_update(priv, -1);
+}
+
+static int
+nvkm_fantog_get(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fantog_priv *priv = (void *)tpriv->fan;
+	return priv->percent;
+}
+
+static int
+nvkm_fantog_set(struct nvkm_therm *therm, int percent)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fantog_priv *priv = (void *)tpriv->fan;
+	if (therm->pwm_ctrl)
+		therm->pwm_ctrl(therm, priv->func.line, false);
+	nvkm_fantog_update(priv, percent);
+	return 0;
+}
+
+int
+nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
+{
+	struct nvkm_therm_priv *tpriv = (void *)therm;
+	struct nvkm_fantog_priv *priv;
+	int ret;
+
+	if (therm->pwm_ctrl) {
+		ret = therm->pwm_ctrl(therm, func->line, false);
+		if (ret)
+			return ret;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	tpriv->fan = &priv->base;
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base.type = "toggle";
+	priv->base.get = nvkm_fantog_get;
+	priv->base.set = nvkm_fantog_set;
+	nvkm_alarm_init(&priv->alarm, nvkm_fantog_alarm);
+	priv->period_us = 100000; /* 10Hz */
+	priv->percent = 100;
+	priv->func = *func;
+	spin_lock_init(&priv->lock);
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c
new file mode 100644
index 0000000..85b5d0c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/fuse.h>
+
+struct g84_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+int
+g84_temp_get(struct nvkm_therm *therm)
+{
+	struct nvkm_fuse *fuse = nvkm_fuse(therm);
+
+	if (nv_ro32(fuse, 0x1a8) == 1)
+		return nv_rd32(therm, 0x20400);
+	else
+		return -ENODEV;
+}
+
+void
+g84_sensor_setup(struct nvkm_therm *therm)
+{
+	struct nvkm_fuse *fuse = nvkm_fuse(therm);
+
+	/* enable temperature reading for cards with insane defaults */
+	if (nv_ro32(fuse, 0x1a8) == 1) {
+		nv_mask(therm, 0x20008, 0x80008000, 0x80000000);
+		nv_mask(therm, 0x2000c, 0x80000003, 0x00000000);
+		mdelay(20); /* wait for the temperature to stabilize */
+	}
+}
+
+static void
+g84_therm_program_alarms(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+	/* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */
+	nv_wr32(therm, 0x20000, 0x000003ff);
+
+	/* shutdown: The computer should be shutdown when reached */
+	nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis);
+	nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp);
+
+	/* THRS_1 : fan boost*/
+	nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp);
+
+	/* THRS_2 : critical */
+	nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp);
+
+	/* THRS_4 : down clock */
+	nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp);
+	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+
+	nv_debug(therm,
+		 "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
+		 sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
+		 sensor->thrs_down_clock.temp,
+		 sensor->thrs_down_clock.hysteresis,
+		 sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
+		 sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
+
+}
+
+/* must be called with alarm_program_lock taken ! */
+static void
+g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm,
+				   uint32_t thrs_reg, u8 status_bit,
+				   const struct nvbios_therm_threshold *thrs,
+				   enum nvkm_therm_thrs thrs_name)
+{
+	enum nvkm_therm_thrs_direction direction;
+	enum nvkm_therm_thrs_state prev_state, new_state;
+	int temp, cur;
+
+	prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name);
+	temp = nv_rd32(therm, thrs_reg);
+
+	/* program the next threshold */
+	if (temp == thrs->temp) {
+		nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis);
+		new_state = NVKM_THERM_THRS_HIGHER;
+	} else {
+		nv_wr32(therm, thrs_reg, thrs->temp);
+		new_state = NVKM_THERM_THRS_LOWER;
+	}
+
+	/* fix the state (in case someone reprogrammed the alarms) */
+	cur = therm->temp_get(therm);
+	if (new_state == NVKM_THERM_THRS_LOWER && cur > thrs->temp)
+		new_state = NVKM_THERM_THRS_HIGHER;
+	else if (new_state == NVKM_THERM_THRS_HIGHER &&
+		cur < thrs->temp - thrs->hysteresis)
+		new_state = NVKM_THERM_THRS_LOWER;
+	nvkm_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
+
+	/* find the direction */
+	if (prev_state < new_state)
+		direction = NVKM_THERM_THRS_RISING;
+	else if (prev_state > new_state)
+		direction = NVKM_THERM_THRS_FALLING;
+	else
+		return;
+
+	/* advertise a change in direction */
+	nvkm_therm_sensor_event(therm, thrs_name, direction);
+}
+
+static void
+g84_therm_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_therm *therm = nvkm_therm(subdev);
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	unsigned long flags;
+	uint32_t intr;
+
+	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+	intr = nv_rd32(therm, 0x20100) & 0x3ff;
+
+	/* THRS_4: downclock */
+	if (intr & 0x002) {
+		g84_therm_threshold_hyst_emulation(therm, 0x20414, 24,
+						   &sensor->thrs_down_clock,
+						   NVKM_THERM_THRS_DOWNCLOCK);
+		intr &= ~0x002;
+	}
+
+	/* shutdown */
+	if (intr & 0x004) {
+		g84_therm_threshold_hyst_emulation(therm, 0x20480, 20,
+						   &sensor->thrs_shutdown,
+						   NVKM_THERM_THRS_SHUTDOWN);
+		intr &= ~0x004;
+	}
+
+	/* THRS_1 : fan boost */
+	if (intr & 0x008) {
+		g84_therm_threshold_hyst_emulation(therm, 0x204c4, 21,
+						   &sensor->thrs_fan_boost,
+						   NVKM_THERM_THRS_FANBOOST);
+		intr &= ~0x008;
+	}
+
+	/* THRS_2 : critical */
+	if (intr & 0x010) {
+		g84_therm_threshold_hyst_emulation(therm, 0x204c0, 22,
+						   &sensor->thrs_critical,
+						   NVKM_THERM_THRS_CRITICAL);
+		intr &= ~0x010;
+	}
+
+	if (intr)
+		nv_error(therm, "unhandled intr 0x%08x\n", intr);
+
+	/* ACK everything */
+	nv_wr32(therm, 0x20100, 0xffffffff);
+	nv_wr32(therm, 0x1100, 0x10000); /* PBUS */
+
+	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+}
+
+static int
+g84_therm_init(struct nvkm_object *object)
+{
+	struct g84_therm_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_therm_init(&priv->base.base);
+	if (ret)
+		return ret;
+
+	g84_sensor_setup(&priv->base.base);
+	return 0;
+}
+
+static int
+g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct g84_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+	priv->base.base.pwm_get = nv50_fan_pwm_get;
+	priv->base.base.pwm_set = nv50_fan_pwm_set;
+	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+	priv->base.base.temp_get = g84_temp_get;
+	priv->base.sensor.program_alarms = g84_therm_program_alarms;
+	nv_subdev(priv)->intr = g84_therm_intr;
+
+	/* init the thresholds */
+	nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+					      NVKM_THERM_THRS_SHUTDOWN,
+					      NVKM_THERM_THRS_LOWER);
+	nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+					      NVKM_THERM_THRS_FANBOOST,
+					      NVKM_THERM_THRS_LOWER);
+	nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+					      NVKM_THERM_THRS_CRITICAL,
+					      NVKM_THERM_THRS_LOWER);
+	nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+					      NVKM_THERM_THRS_DOWNCLOCK,
+					      NVKM_THERM_THRS_LOWER);
+
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+int
+g84_therm_fini(struct nvkm_object *object, bool suspend)
+{
+	/* Disable PTherm IRQs */
+	nv_wr32(object, 0x20000, 0x00000000);
+
+	/* ACK all PTherm IRQs */
+	nv_wr32(object, 0x20100, 0xffffffff);
+	nv_wr32(object, 0x1100, 0x10000); /* PBUS */
+
+	return _nvkm_therm_fini(object, suspend);
+}
+
+struct nvkm_oclass
+g84_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0x84),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = g84_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = g84_therm_init,
+		.fini = g84_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c
new file mode 100644
index 0000000..46b7e65
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct gf110_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+static int
+pwm_info(struct nvkm_therm *therm, int line)
+{
+	u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
+
+	switch (gpio & 0x000000c0) {
+	case 0x00000000: /* normal mode, possibly pwm forced off by us */
+	case 0x00000040: /* nvio special */
+		switch (gpio & 0x0000001f) {
+		case 0x00: return 2;
+		case 0x19: return 1;
+		case 0x1c: return 0;
+		case 0x1e: return 2;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+
+	nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio);
+	return -ENODEV;
+}
+
+static int
+gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+	u32 data = enable ? 0x00000040 : 0x00000000;
+	int indx = pwm_info(therm, line);
+	if (indx < 0)
+		return indx;
+	else if (indx < 2)
+		nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
+	/* nothing to do for indx == 2, it seems hardwired to PTHERM */
+	return 0;
+}
+
+static int
+gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+	int indx = pwm_info(therm, line);
+	if (indx < 0)
+		return indx;
+	else if (indx < 2) {
+		if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
+			*divs = nv_rd32(therm, 0x00e114 + (indx * 8));
+			*duty = nv_rd32(therm, 0x00e118 + (indx * 8));
+			return 0;
+		}
+	} else if (indx == 2) {
+		*divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
+		*duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int
+gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+	int indx = pwm_info(therm, line);
+	if (indx < 0)
+		return indx;
+	else if (indx < 2) {
+		nv_wr32(therm, 0x00e114 + (indx * 8), divs);
+		nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
+	} else if (indx == 2) {
+		nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
+		nv_wr32(therm, 0x0200dc, duty | 0x40000000);
+	}
+	return 0;
+}
+
+static int
+gf110_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+	int indx = pwm_info(therm, line);
+	if (indx < 0)
+		return 0;
+	else if (indx < 2)
+		return (nv_device(therm)->crystal * 1000) / 20;
+	else
+		return nv_device(therm)->crystal * 1000 / 10;
+}
+
+int
+gf110_therm_init(struct nvkm_object *object)
+{
+	struct gf110_therm_priv *priv = (void *)object;
+	int ret;
+
+	ret = nvkm_therm_init(&priv->base.base);
+	if (ret)
+		return ret;
+
+	/* enable fan tach, count revolutions per-second */
+	nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
+	if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) {
+		nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line);
+		nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
+		nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
+	}
+	nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
+
+	return 0;
+}
+
+static int
+gf110_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gf110_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	g84_sensor_setup(&priv->base.base);
+
+	priv->base.base.pwm_ctrl = gf110_fan_pwm_ctrl;
+	priv->base.base.pwm_get = gf110_fan_pwm_get;
+	priv->base.base.pwm_set = gf110_fan_pwm_set;
+	priv->base.base.pwm_clock = gf110_fan_pwm_clock;
+	priv->base.base.temp_get = g84_temp_get;
+	priv->base.base.fan_sense = gt215_therm_fan_sense;
+	priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gf110_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0xd0),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gf110_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = gf110_therm_init,
+		.fini = g84_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
new file mode 100644
index 0000000..2fd110f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct gm107_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+static int
+gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+	/* nothing to do, it seems hardwired */
+	return 0;
+}
+
+static int
+gm107_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+	*divs = nv_rd32(therm, 0x10eb20) & 0x1fff;
+	*duty = nv_rd32(therm, 0x10eb24) & 0x1fff;
+	return 0;
+}
+
+static int
+gm107_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+	nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */
+	nv_wr32(therm, 0x10eb14, duty | 0x80000000);
+	return 0;
+}
+
+static int
+gm107_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+	return nv_device(therm)->crystal * 1000;
+}
+
+static int
+gm107_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gm107_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl;
+	priv->base.base.pwm_get = gm107_fan_pwm_get;
+	priv->base.base.pwm_set = gm107_fan_pwm_set;
+	priv->base.base.pwm_clock = gm107_fan_pwm_clock;
+	priv->base.base.temp_get = g84_temp_get;
+	priv->base.base.fan_sense = gt215_therm_fan_sense;
+	priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gm107_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0x117),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gm107_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = gf110_therm_init,
+		.fini = g84_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c
new file mode 100644
index 0000000..e99be20
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <subdev/gpio.h>
+
+struct gt215_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+int
+gt215_therm_fan_sense(struct nvkm_therm *therm)
+{
+	u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff;
+	u32 ctrl = nv_rd32(therm, 0x00e720);
+	if (ctrl & 0x00000001)
+		return tach * 60 / 2;
+	return -ENODEV;
+}
+
+static int
+gt215_therm_init(struct nvkm_object *object)
+{
+	struct gt215_therm_priv *priv = (void *)object;
+	struct dcb_gpio_func *tach = &priv->base.fan->tach;
+	int ret;
+
+	ret = nvkm_therm_init(&priv->base.base);
+	if (ret)
+		return ret;
+
+	g84_sensor_setup(&priv->base.base);
+
+	/* enable fan tach, count revolutions per-second */
+	nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
+	if (tach->func != DCB_GPIO_UNUSED) {
+		nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
+		nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16);
+		nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
+	}
+	nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
+
+	return 0;
+}
+
+static int
+gt215_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		 struct nvkm_oclass *oclass, void *data, u32 size,
+		 struct nvkm_object **pobject)
+{
+	struct gt215_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+	priv->base.base.pwm_get = nv50_fan_pwm_get;
+	priv->base.base.pwm_set = nv50_fan_pwm_set;
+	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+	priv->base.base.temp_get = g84_temp_get;
+	priv->base.base.fan_sense = gt215_therm_fan_sense;
+	priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gt215_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0xa3),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gt215_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = gt215_therm_init,
+		.fini = g84_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
new file mode 100644
index 0000000..09fc460
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012 Nouveau community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/bios/extdev.h>
+#include <subdev/i2c.h>
+
+static bool
+probe_monitoring_device(struct nvkm_i2c_port *i2c,
+			struct i2c_board_info *info, void *data)
+{
+	struct nvkm_therm_priv *priv = data;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	struct i2c_client *client;
+
+	request_module("%s%s", I2C_MODULE_PREFIX, info->type);
+
+	client = i2c_new_device(&i2c->adapter, info);
+	if (!client)
+		return false;
+
+	if (!client->dev.driver ||
+	    to_i2c_driver(client->dev.driver)->detect(client, info)) {
+		i2c_unregister_device(client);
+		return false;
+	}
+
+	nv_info(priv,
+		"Found an %s at address 0x%x (controlled by lm_sensors, "
+		"temp offset %+i C)\n",
+		info->type, info->addr, sensor->offset_constant);
+	priv->ic = client;
+	return true;
+}
+
+static struct nvkm_i2c_board_info
+nv_board_infos[] = {
+	{ { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
+	{ { I2C_BOARD_INFO("w83781d", 0x2d) }, 0  },
+	{ { I2C_BOARD_INFO("adt7473", 0x2e) }, 40  },
+	{ { I2C_BOARD_INFO("adt7473", 0x2d) }, 40  },
+	{ { I2C_BOARD_INFO("adt7473", 0x2c) }, 40  },
+	{ { I2C_BOARD_INFO("f75375", 0x2e) }, 0  },
+	{ { I2C_BOARD_INFO("lm99", 0x4c) }, 0  },
+	{ { I2C_BOARD_INFO("lm90", 0x4c) }, 0  },
+	{ { I2C_BOARD_INFO("lm90", 0x4d) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x18) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x19) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x1a) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x29) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x2a) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x2b) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x4c) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x4d) }, 0  },
+	{ { I2C_BOARD_INFO("adm1021", 0x4e) }, 0  },
+	{ { I2C_BOARD_INFO("lm63", 0x18) }, 0  },
+	{ { I2C_BOARD_INFO("lm63", 0x4e) }, 0  },
+	{ }
+};
+
+void
+nvkm_therm_ic_ctor(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_bios *bios = nvkm_bios(therm);
+	struct nvkm_i2c *i2c = nvkm_i2c(therm);
+	struct nvbios_extdev_func extdev_entry;
+
+	if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
+		struct nvkm_i2c_board_info board[] = {
+		  { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
+		  { }
+		};
+
+		i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+			      board, probe_monitoring_device, therm);
+		if (priv->ic)
+			return;
+	}
+
+	if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
+		struct nvkm_i2c_board_info board[] = {
+		  { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
+		  { }
+		};
+
+		i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+			      board, probe_monitoring_device, therm);
+		if (priv->ic)
+			return;
+	}
+
+	/* The vbios doesn't provide the address of an exisiting monitoring
+	   device. Let's try our static list.
+	 */
+	i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+		      nv_board_infos, probe_monitoring_device, therm);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
new file mode 100644
index 0000000..8496fff
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nv40_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
+
+static enum nv40_sensor_style
+nv40_sensor_style(struct nvkm_therm *therm)
+{
+	struct nvkm_device *device = nv_device(therm);
+
+	switch (device->chipset) {
+	case 0x43:
+	case 0x44:
+	case 0x4a:
+	case 0x47:
+		return OLD_STYLE;
+
+	case 0x46:
+	case 0x49:
+	case 0x4b:
+	case 0x4e:
+	case 0x4c:
+	case 0x67:
+	case 0x68:
+	case 0x63:
+		return NEW_STYLE;
+	default:
+		return INVALID_STYLE;
+	}
+}
+
+static int
+nv40_sensor_setup(struct nvkm_therm *therm)
+{
+	enum nv40_sensor_style style = nv40_sensor_style(therm);
+
+	/* enable ADC readout and disable the ALARM threshold */
+	if (style == NEW_STYLE) {
+		nv_mask(therm, 0x15b8, 0x80000000, 0);
+		nv_wr32(therm, 0x15b0, 0x80003fff);
+		mdelay(20); /* wait for the temperature to stabilize */
+		return nv_rd32(therm, 0x15b4) & 0x3fff;
+	} else if (style == OLD_STYLE) {
+		nv_wr32(therm, 0x15b0, 0xff);
+		mdelay(20); /* wait for the temperature to stabilize */
+		return nv_rd32(therm, 0x15b4) & 0xff;
+	} else
+		return -ENODEV;
+}
+
+static int
+nv40_temp_get(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	enum nv40_sensor_style style = nv40_sensor_style(therm);
+	int core_temp;
+
+	if (style == NEW_STYLE) {
+		nv_wr32(therm, 0x15b0, 0x80003fff);
+		core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
+	} else if (style == OLD_STYLE) {
+		nv_wr32(therm, 0x15b0, 0xff);
+		core_temp = nv_rd32(therm, 0x15b4) & 0xff;
+	} else
+		return -ENODEV;
+
+	/* if the slope or the offset is unset, do no use the sensor */
+	if (!sensor->slope_div || !sensor->slope_mult ||
+	    !sensor->offset_num || !sensor->offset_den)
+	    return -ENODEV;
+
+	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
+	core_temp = core_temp + sensor->offset_constant - 8;
+
+	/* reserve negative temperatures for errors */
+	if (core_temp < 0)
+		core_temp = 0;
+
+	return core_temp;
+}
+
+static int
+nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+	u32 mask = enable ? 0x80000000 : 0x0000000;
+	if      (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask);
+	else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask);
+	else {
+		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int
+nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+	if (line == 2) {
+		u32 reg = nv_rd32(therm, 0x0010f0);
+		if (reg & 0x80000000) {
+			*duty = (reg & 0x7fff0000) >> 16;
+			*divs = (reg & 0x00007fff);
+			return 0;
+		}
+	} else
+	if (line == 9) {
+		u32 reg = nv_rd32(therm, 0x0015f4);
+		if (reg & 0x80000000) {
+			*divs = nv_rd32(therm, 0x0015f8);
+			*duty = (reg & 0x7fffffff);
+			return 0;
+		}
+	} else {
+		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+		return -ENODEV;
+	}
+
+	return -EINVAL;
+}
+
+static int
+nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+	if (line == 2) {
+		nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
+	} else
+	if (line == 9) {
+		nv_wr32(therm, 0x0015f8, divs);
+		nv_mask(therm, 0x0015f4, 0x7fffffff, duty);
+	} else {
+		nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+void
+nv40_therm_intr(struct nvkm_subdev *subdev)
+{
+	struct nvkm_therm *therm = nvkm_therm(subdev);
+	uint32_t stat = nv_rd32(therm, 0x1100);
+
+	/* traitement */
+
+	/* ack all IRQs */
+	nv_wr32(therm, 0x1100, 0x70000);
+
+	nv_error(therm, "THERM received an IRQ: stat = %x\n", stat);
+}
+
+static int
+nv40_therm_ctor(struct nvkm_object *parent,
+		struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv40_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl;
+	priv->base.base.pwm_get = nv40_fan_pwm_get;
+	priv->base.base.pwm_set = nv40_fan_pwm_set;
+	priv->base.base.temp_get = nv40_temp_get;
+	priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+	nv_subdev(priv)->intr = nv40_therm_intr;
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+static int
+nv40_therm_init(struct nvkm_object *object)
+{
+	struct nvkm_therm *therm = (void *)object;
+
+	nv40_sensor_setup(therm);
+
+	return _nvkm_therm_init(object);
+}
+
+struct nvkm_oclass
+nv40_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = nv40_therm_init,
+		.fini = _nvkm_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c
new file mode 100644
index 0000000..1ef59e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ * 	    Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nv50_therm_priv {
+	struct nvkm_therm_priv base;
+};
+
+static int
+pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx)
+{
+	if (*line == 0x04) {
+		*ctrl = 0x00e100;
+		*line = 4;
+		*indx = 0;
+	} else
+	if (*line == 0x09) {
+		*ctrl = 0x00e100;
+		*line = 9;
+		*indx = 1;
+	} else
+	if (*line == 0x10) {
+		*ctrl = 0x00e28c;
+		*line = 0;
+		*indx = 0;
+	} else {
+		nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int
+nv50_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+	u32 data = enable ? 0x00000001 : 0x00000000;
+	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+	if (ret == 0)
+		nv_mask(therm, ctrl, 0x00010001 << line, data << line);
+	return ret;
+}
+
+int
+nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+	if (ret)
+		return ret;
+
+	if (nv_rd32(therm, ctrl) & (1 << line)) {
+		*divs = nv_rd32(therm, 0x00e114 + (id * 8));
+		*duty = nv_rd32(therm, 0x00e118 + (id * 8));
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int
+nv50_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+	int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+	if (ret)
+		return ret;
+
+	nv_wr32(therm, 0x00e114 + (id * 8), divs);
+	nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
+	return 0;
+}
+
+int
+nv50_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+	int chipset = nv_device(therm)->chipset;
+	int crystal = nv_device(therm)->crystal;
+	int pwm_clock;
+
+	/* determine the PWM source clock */
+	if (chipset > 0x50 && chipset < 0x94) {
+		u8 pwm_div = nv_rd32(therm, 0x410c);
+		if (nv_rd32(therm, 0xc040) & 0x800000) {
+			/* Use the HOST clock (100 MHz)
+			* Where does this constant(2.4) comes from? */
+			pwm_clock = (100000000 >> pwm_div) * 10 / 24;
+		} else {
+			/* Where does this constant(20) comes from? */
+			pwm_clock = (crystal * 1000) >> pwm_div;
+			pwm_clock /= 20;
+		}
+	} else {
+		pwm_clock = (crystal * 1000) / 20;
+	}
+
+	return pwm_clock;
+}
+
+static void
+nv50_sensor_setup(struct nvkm_therm *therm)
+{
+	nv_mask(therm, 0x20010, 0x40000000, 0x0);
+	mdelay(20); /* wait for the temperature to stabilize */
+}
+
+static int
+nv50_temp_get(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	int core_temp;
+
+	core_temp = nv_rd32(therm, 0x20014) & 0x3fff;
+
+	/* if the slope or the offset is unset, do no use the sensor */
+	if (!sensor->slope_div || !sensor->slope_mult ||
+	    !sensor->offset_num || !sensor->offset_den)
+	    return -ENODEV;
+
+	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
+	core_temp = core_temp + sensor->offset_constant - 8;
+
+	/* reserve negative temperatures for errors */
+	if (core_temp < 0)
+		core_temp = 0;
+
+	return core_temp;
+}
+
+static int
+nv50_therm_ctor(struct nvkm_object *parent,
+		struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv50_therm_priv *priv;
+	int ret;
+
+	ret = nvkm_therm_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+	priv->base.base.pwm_get = nv50_fan_pwm_get;
+	priv->base.base.pwm_set = nv50_fan_pwm_set;
+	priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+	priv->base.base.temp_get = nv50_temp_get;
+	priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+	nv_subdev(priv)->intr = nv40_therm_intr;
+
+	return nvkm_therm_preinit(&priv->base.base);
+}
+
+static int
+nv50_therm_init(struct nvkm_object *object)
+{
+	struct nvkm_therm *therm = (void *)object;
+
+	nv50_sensor_setup(therm);
+
+	return _nvkm_therm_init(object);
+}
+
+struct nvkm_oclass
+nv50_therm_oclass = {
+	.handle = NV_SUBDEV(THERM, 0x50),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv50_therm_ctor,
+		.dtor = _nvkm_therm_dtor,
+		.init = nv50_therm_init,
+		.fini = _nvkm_therm_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
new file mode 100644
index 0000000..916a149
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
@@ -0,0 +1,153 @@
+#ifndef __NVTHERM_PRIV_H__
+#define __NVTHERM_PRIV_H__
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/therm.h>
+#include <subdev/bios.h>
+#include <subdev/bios/extdev.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/perf.h>
+#include <subdev/bios/therm.h>
+#include <subdev/timer.h>
+
+struct nvkm_fan {
+	struct nvkm_therm *parent;
+	const char *type;
+
+	struct nvbios_therm_fan bios;
+	struct nvbios_perf_fan perf;
+
+	struct nvkm_alarm alarm;
+	spinlock_t lock;
+	int percent;
+
+	int (*get)(struct nvkm_therm *);
+	int (*set)(struct nvkm_therm *, int percent);
+
+	struct dcb_gpio_func tach;
+};
+
+enum nvkm_therm_thrs_direction {
+	NVKM_THERM_THRS_FALLING = 0,
+	NVKM_THERM_THRS_RISING = 1
+};
+
+enum nvkm_therm_thrs_state {
+	NVKM_THERM_THRS_LOWER = 0,
+	NVKM_THERM_THRS_HIGHER = 1
+};
+
+enum nvkm_therm_thrs {
+	NVKM_THERM_THRS_FANBOOST = 0,
+	NVKM_THERM_THRS_DOWNCLOCK = 1,
+	NVKM_THERM_THRS_CRITICAL = 2,
+	NVKM_THERM_THRS_SHUTDOWN = 3,
+	NVKM_THERM_THRS_NR
+};
+
+struct nvkm_therm_priv {
+	struct nvkm_therm base;
+
+	/* automatic thermal management */
+	struct nvkm_alarm alarm;
+	spinlock_t lock;
+	struct nvbios_therm_trip_point *last_trip;
+	int mode;
+	int cstate;
+	int suspend;
+
+	/* bios */
+	struct nvbios_therm_sensor bios_sensor;
+
+	/* fan priv */
+	struct nvkm_fan *fan;
+
+	/* alarms priv */
+	struct {
+		spinlock_t alarm_program_lock;
+		struct nvkm_alarm therm_poll_alarm;
+		enum nvkm_therm_thrs_state alarm_state[NVKM_THERM_THRS_NR];
+		void (*program_alarms)(struct nvkm_therm *);
+	} sensor;
+
+	/* what should be done if the card overheats */
+	struct {
+		void (*downclock)(struct nvkm_therm *, bool active);
+		void (*pause)(struct nvkm_therm *, bool active);
+	} emergency;
+
+	/* ic */
+	struct i2c_client *ic;
+};
+
+int nvkm_therm_fan_mode(struct nvkm_therm *, int mode);
+int nvkm_therm_attr_get(struct nvkm_therm *, enum nvkm_therm_attr_type);
+int nvkm_therm_attr_set(struct nvkm_therm *, enum nvkm_therm_attr_type, int);
+
+void nvkm_therm_ic_ctor(struct nvkm_therm *);
+
+int nvkm_therm_sensor_ctor(struct nvkm_therm *);
+
+int nvkm_therm_fan_ctor(struct nvkm_therm *);
+int nvkm_therm_fan_init(struct nvkm_therm *);
+int nvkm_therm_fan_fini(struct nvkm_therm *, bool suspend);
+int nvkm_therm_fan_get(struct nvkm_therm *);
+int nvkm_therm_fan_set(struct nvkm_therm *, bool now, int percent);
+int nvkm_therm_fan_user_get(struct nvkm_therm *);
+int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent);
+
+int nvkm_therm_fan_sense(struct nvkm_therm *);
+
+int nvkm_therm_preinit(struct nvkm_therm *);
+
+int  nvkm_therm_sensor_init(struct nvkm_therm *);
+int  nvkm_therm_sensor_fini(struct nvkm_therm *, bool suspend);
+void nvkm_therm_sensor_preinit(struct nvkm_therm *);
+void nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *,
+					   enum nvkm_therm_thrs,
+					   enum nvkm_therm_thrs_state);
+enum nvkm_therm_thrs_state
+nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *,
+				      enum nvkm_therm_thrs);
+void nvkm_therm_sensor_event(struct nvkm_therm *, enum nvkm_therm_thrs,
+			     enum nvkm_therm_thrs_direction);
+void nvkm_therm_program_alarms_polling(struct nvkm_therm *);
+
+void nv40_therm_intr(struct nvkm_subdev *);
+int  nv50_fan_pwm_ctrl(struct nvkm_therm *, int, bool);
+int  nv50_fan_pwm_get(struct nvkm_therm *, int, u32 *, u32 *);
+int  nv50_fan_pwm_set(struct nvkm_therm *, int, u32, u32);
+int  nv50_fan_pwm_clock(struct nvkm_therm *, int);
+int  g84_temp_get(struct nvkm_therm *);
+void g84_sensor_setup(struct nvkm_therm *);
+int  g84_therm_fini(struct nvkm_object *, bool suspend);
+
+int gt215_therm_fan_sense(struct nvkm_therm *);
+
+int gf110_therm_init(struct nvkm_object *);
+
+int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *);
+int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *);
+int nvkm_fannil_create(struct nvkm_therm *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
new file mode 100644
index 0000000..aa13744
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * 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.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+static void
+nvkm_therm_temp_set_defaults(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+
+	priv->bios_sensor.offset_constant = 0;
+
+	priv->bios_sensor.thrs_fan_boost.temp = 90;
+	priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
+
+	priv->bios_sensor.thrs_down_clock.temp = 95;
+	priv->bios_sensor.thrs_down_clock.hysteresis = 3;
+
+	priv->bios_sensor.thrs_critical.temp = 105;
+	priv->bios_sensor.thrs_critical.hysteresis = 5;
+
+	priv->bios_sensor.thrs_shutdown.temp = 135;
+	priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
+}
+
+
+static void
+nvkm_therm_temp_safety_checks(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *s = &priv->bios_sensor;
+
+	/* enforce a minimum hysteresis on thresholds */
+	s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2);
+	s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2);
+	s->thrs_critical.hysteresis = max_t(u8, s->thrs_critical.hysteresis, 2);
+	s->thrs_shutdown.hysteresis = max_t(u8, s->thrs_shutdown.hysteresis, 2);
+}
+
+/* must be called with alarm_program_lock taken ! */
+void
+nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *therm,
+				      enum nvkm_therm_thrs thrs,
+				      enum nvkm_therm_thrs_state st)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	priv->sensor.alarm_state[thrs] = st;
+}
+
+/* must be called with alarm_program_lock taken ! */
+enum nvkm_therm_thrs_state
+nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *therm,
+				      enum nvkm_therm_thrs thrs)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	return priv->sensor.alarm_state[thrs];
+}
+
+static void
+nv_poweroff_work(struct work_struct *work)
+{
+	orderly_poweroff(true);
+	kfree(work);
+}
+
+void
+nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs,
+			enum nvkm_therm_thrs_direction dir)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	bool active;
+	const char *thresolds[] = {
+		"fanboost", "downclock", "critical", "shutdown"
+	};
+	int temperature = therm->temp_get(therm);
+
+	if (thrs < 0 || thrs > 3)
+		return;
+
+	if (dir == NVKM_THERM_THRS_FALLING)
+		nv_info(therm, "temperature (%i C) went below the '%s' threshold\n",
+			temperature, thresolds[thrs]);
+	else
+		nv_info(therm, "temperature (%i C) hit the '%s' threshold\n",
+			temperature, thresolds[thrs]);
+
+	active = (dir == NVKM_THERM_THRS_RISING);
+	switch (thrs) {
+	case NVKM_THERM_THRS_FANBOOST:
+		if (active) {
+			nvkm_therm_fan_set(therm, true, 100);
+			nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
+		}
+		break;
+	case NVKM_THERM_THRS_DOWNCLOCK:
+		if (priv->emergency.downclock)
+			priv->emergency.downclock(therm, active);
+		break;
+	case NVKM_THERM_THRS_CRITICAL:
+		if (priv->emergency.pause)
+			priv->emergency.pause(therm, active);
+		break;
+	case NVKM_THERM_THRS_SHUTDOWN:
+		if (active) {
+			struct work_struct *work;
+
+			work = kmalloc(sizeof(*work), GFP_ATOMIC);
+			if (work) {
+				INIT_WORK(work, nv_poweroff_work);
+				schedule_work(work);
+			}
+		}
+		break;
+	case NVKM_THERM_THRS_NR:
+		break;
+	}
+
+}
+
+/* must be called with alarm_program_lock taken ! */
+static void
+nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm,
+				  const struct nvbios_therm_threshold *thrs,
+				  enum nvkm_therm_thrs thrs_name)
+{
+	enum nvkm_therm_thrs_direction direction;
+	enum nvkm_therm_thrs_state prev_state, new_state;
+	int temp = therm->temp_get(therm);
+
+	prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name);
+
+	if (temp >= thrs->temp && prev_state == NVKM_THERM_THRS_LOWER) {
+		direction = NVKM_THERM_THRS_RISING;
+		new_state = NVKM_THERM_THRS_HIGHER;
+	} else if (temp <= thrs->temp - thrs->hysteresis &&
+			prev_state == NVKM_THERM_THRS_HIGHER) {
+		direction = NVKM_THERM_THRS_FALLING;
+		new_state = NVKM_THERM_THRS_LOWER;
+	} else
+		return; /* nothing to do */
+
+	nvkm_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
+	nvkm_therm_sensor_event(therm, thrs_name, direction);
+}
+
+static void
+alarm_timer_callback(struct nvkm_alarm *alarm)
+{
+	struct nvkm_therm_priv *priv =
+	container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm);
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+	struct nvkm_timer *ptimer = nvkm_timer(priv);
+	struct nvkm_therm *therm = &priv->base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+	nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
+					  NVKM_THERM_THRS_FANBOOST);
+
+	nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock,
+					  NVKM_THERM_THRS_DOWNCLOCK);
+
+	nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_critical,
+					  NVKM_THERM_THRS_CRITICAL);
+
+	nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown,
+					  NVKM_THERM_THRS_SHUTDOWN);
+
+	spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+
+	/* schedule the next poll in one second */
+	if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head))
+		ptimer->alarm(ptimer, 1000000000ULL, alarm);
+}
+
+void
+nvkm_therm_program_alarms_polling(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+
+	nv_debug(therm,
+		 "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
+		 sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
+		 sensor->thrs_down_clock.temp,
+		 sensor->thrs_down_clock.hysteresis,
+		 sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
+		 sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
+
+	alarm_timer_callback(&priv->sensor.therm_poll_alarm);
+}
+
+int
+nvkm_therm_sensor_init(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	priv->sensor.program_alarms(therm);
+	return 0;
+}
+
+int
+nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_timer *ptimer = nvkm_timer(therm);
+
+	if (suspend)
+		ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
+	return 0;
+}
+
+void
+nvkm_therm_sensor_preinit(struct nvkm_therm *therm)
+{
+	const char *sensor_avail = "yes";
+
+	if (therm->temp_get(therm) < 0)
+		sensor_avail = "no";
+
+	nv_info(therm, "internal sensor: %s\n", sensor_avail);
+}
+
+int
+nvkm_therm_sensor_ctor(struct nvkm_therm *therm)
+{
+	struct nvkm_therm_priv *priv = (void *)therm;
+	struct nvkm_bios *bios = nvkm_bios(therm);
+
+	nvkm_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback);
+
+	nvkm_therm_temp_set_defaults(therm);
+	if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
+				      &priv->bios_sensor))
+		nv_error(therm, "nvbios_therm_sensor_parse failed\n");
+	nvkm_therm_temp_safety_checks(therm);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild
new file mode 100644
index 0000000..d1d38b4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/timer/base.o
+nvkm-y += nvkm/subdev/timer/nv04.o
+nvkm-y += nvkm/subdev/timer/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
new file mode 100644
index 0000000..d894061
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/timer.h>
+
+bool
+nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(obj);
+	u64 time0;
+
+	time0 = ptimer->read(ptimer);
+	do {
+		if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
+			if ((nv_rd32(obj, addr) & mask) == data)
+				return true;
+		} else {
+			if ((nv_ro32(obj, addr) & mask) == data)
+				return true;
+		}
+	} while (ptimer->read(ptimer) - time0 < nsec);
+
+	return false;
+}
+
+bool
+nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(obj);
+	u64 time0;
+
+	time0 = ptimer->read(ptimer);
+	do {
+		if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
+			if ((nv_rd32(obj, addr) & mask) != data)
+				return true;
+		} else {
+			if ((nv_ro32(obj, addr) & mask) != data)
+				return true;
+		}
+	} while (ptimer->read(ptimer) - time0 < nsec);
+
+	return false;
+}
+
+bool
+nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(obj);
+	u64 time0;
+
+	time0 = ptimer->read(ptimer);
+	do {
+		if (func(data) == true)
+			return true;
+	} while (ptimer->read(ptimer) - time0 < nsec);
+
+	return false;
+}
+
+void
+nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(obj);
+	ptimer->alarm(ptimer, nsec, alarm);
+}
+
+void
+nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm)
+{
+	struct nvkm_timer *ptimer = nvkm_timer(obj);
+	ptimer->alarm_cancel(ptimer, alarm);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c
new file mode 100644
index 0000000..80e3806
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+static int
+gk20a_timer_init(struct nvkm_object *object)
+{
+	struct nv04_timer_priv *priv = (void *)object;
+	u32 hi = upper_32_bits(priv->suspend_time);
+	u32 lo = lower_32_bits(priv->suspend_time);
+	int ret;
+
+	ret = nvkm_timer_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_debug(priv, "time low        : 0x%08x\n", lo);
+	nv_debug(priv, "time high       : 0x%08x\n", hi);
+
+	/* restore the time before suspend */
+	nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+	nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_timer_oclass = {
+	.handle = NV_SUBDEV(TIMER, 0xff),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_timer_ctor,
+		.dtor = nv04_timer_dtor,
+		.init = gk20a_timer_init,
+		.fini = nv04_timer_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
new file mode 100644
index 0000000..6b7facb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2012 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+static u64
+nv04_timer_read(struct nvkm_timer *ptimer)
+{
+	struct nv04_timer_priv *priv = (void *)ptimer;
+	u32 hi, lo;
+
+	do {
+		hi = nv_rd32(priv, NV04_PTIMER_TIME_1);
+		lo = nv_rd32(priv, NV04_PTIMER_TIME_0);
+	} while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1));
+
+	return ((u64)hi << 32 | lo);
+}
+
+static void
+nv04_timer_alarm_trigger(struct nvkm_timer *ptimer)
+{
+	struct nv04_timer_priv *priv = (void *)ptimer;
+	struct nvkm_alarm *alarm, *atemp;
+	unsigned long flags;
+	LIST_HEAD(exec);
+
+	/* move any due alarms off the pending list */
+	spin_lock_irqsave(&priv->lock, flags);
+	list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) {
+		if (alarm->timestamp <= ptimer->read(ptimer))
+			list_move_tail(&alarm->head, &exec);
+	}
+
+	/* reschedule interrupt for next alarm time */
+	if (!list_empty(&priv->alarms)) {
+		alarm = list_first_entry(&priv->alarms, typeof(*alarm), head);
+		nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp);
+		nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001);
+	} else {
+		nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* execute any pending alarm handlers */
+	list_for_each_entry_safe(alarm, atemp, &exec, head) {
+		list_del_init(&alarm->head);
+		alarm->func(alarm);
+	}
+}
+
+static void
+nv04_timer_alarm(struct nvkm_timer *ptimer, u64 time, struct nvkm_alarm *alarm)
+{
+	struct nv04_timer_priv *priv = (void *)ptimer;
+	struct nvkm_alarm *list;
+	unsigned long flags;
+
+	alarm->timestamp = ptimer->read(ptimer) + time;
+
+	/* append new alarm to list, in soonest-alarm-first order */
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!time) {
+		if (!list_empty(&alarm->head))
+			list_del(&alarm->head);
+	} else {
+		list_for_each_entry(list, &priv->alarms, head) {
+			if (list->timestamp > alarm->timestamp)
+				break;
+		}
+		list_add_tail(&alarm->head, &list->head);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* process pending alarms */
+	nv04_timer_alarm_trigger(ptimer);
+}
+
+static void
+nv04_timer_alarm_cancel(struct nvkm_timer *ptimer, struct nvkm_alarm *alarm)
+{
+	struct nv04_timer_priv *priv = (void *)ptimer;
+	unsigned long flags;
+	spin_lock_irqsave(&priv->lock, flags);
+	list_del_init(&alarm->head);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nv04_timer_intr(struct nvkm_subdev *subdev)
+{
+	struct nv04_timer_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0);
+
+	if (stat & 0x00000001) {
+		nv04_timer_alarm_trigger(&priv->base);
+		nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001);
+		stat &= ~0x00000001;
+	}
+
+	if (stat) {
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, NV04_PTIMER_INTR_0, stat);
+	}
+}
+
+int
+nv04_timer_fini(struct nvkm_object *object, bool suspend)
+{
+	struct nv04_timer_priv *priv = (void *)object;
+	if (suspend)
+		priv->suspend_time = nv04_timer_read(&priv->base);
+	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+	return nvkm_timer_fini(&priv->base, suspend);
+}
+
+static int
+nv04_timer_init(struct nvkm_object *object)
+{
+	struct nvkm_device *device = nv_device(object);
+	struct nv04_timer_priv *priv = (void *)object;
+	u32 m = 1, f, n, d, lo, hi;
+	int ret;
+
+	ret = nvkm_timer_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* aim for 31.25MHz, which gives us nanosecond timestamps */
+	d = 1000000 / 32;
+
+	/* determine base clock for timer source */
+#if 0 /*XXX*/
+	if (device->chipset < 0x40) {
+		n = nvkm_hw_get_clock(device, PLL_CORE);
+	} else
+#endif
+	if (device->chipset <= 0x40) {
+		/*XXX: figure this out */
+		f = -1;
+		n = 0;
+	} else {
+		f = device->crystal;
+		n = f;
+		while (n < (d * 2)) {
+			n += (n / m);
+			m++;
+		}
+
+		nv_wr32(priv, 0x009220, m - 1);
+	}
+
+	if (!n) {
+		nv_warn(priv, "unknown input clock freq\n");
+		if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) ||
+		    !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) {
+			nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1);
+			nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1);
+		}
+		return 0;
+	}
+
+	/* reduce ratio to acceptable values */
+	while (((n % 5) == 0) && ((d % 5) == 0)) {
+		n /= 5;
+		d /= 5;
+	}
+
+	while (((n % 2) == 0) && ((d % 2) == 0)) {
+		n /= 2;
+		d /= 2;
+	}
+
+	while (n > 0xffff || d > 0xffff) {
+		n >>= 1;
+		d >>= 1;
+	}
+
+	/* restore the time before suspend */
+	lo = priv->suspend_time;
+	hi = (priv->suspend_time >> 32);
+
+	nv_debug(priv, "input frequency : %dHz\n", f);
+	nv_debug(priv, "input multiplier: %d\n", m);
+	nv_debug(priv, "numerator       : 0x%08x\n", n);
+	nv_debug(priv, "denominator     : 0x%08x\n", d);
+	nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
+	nv_debug(priv, "time low        : 0x%08x\n", lo);
+	nv_debug(priv, "time high       : 0x%08x\n", hi);
+
+	nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
+	nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
+	nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
+	nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+	nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+	nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+	return 0;
+}
+
+void
+nv04_timer_dtor(struct nvkm_object *object)
+{
+	struct nv04_timer_priv *priv = (void *)object;
+	return nvkm_timer_destroy(&priv->base);
+}
+
+int
+nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct nv04_timer_priv *priv;
+	int ret;
+
+	ret = nvkm_timer_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.base.intr = nv04_timer_intr;
+	priv->base.read = nv04_timer_read;
+	priv->base.alarm = nv04_timer_alarm;
+	priv->base.alarm_cancel = nv04_timer_alarm_cancel;
+	priv->suspend_time = 0;
+
+	INIT_LIST_HEAD(&priv->alarms);
+	spin_lock_init(&priv->lock);
+	return 0;
+}
+
+struct nvkm_oclass
+nv04_timer_oclass = {
+	.handle = NV_SUBDEV(TIMER, 0x04),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv04_timer_ctor,
+		.dtor = nv04_timer_dtor,
+		.init = nv04_timer_init,
+		.fini = nv04_timer_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h
new file mode 100644
index 0000000..89996a9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h
@@ -0,0 +1,25 @@
+#ifndef __NVKM_TIMER_NV04_H__
+#define __NVKM_TIMER_NV04_H__
+#include "priv.h"
+
+#define NV04_PTIMER_INTR_0      0x009100
+#define NV04_PTIMER_INTR_EN_0   0x009140
+#define NV04_PTIMER_NUMERATOR   0x009200
+#define NV04_PTIMER_DENOMINATOR 0x009210
+#define NV04_PTIMER_TIME_0      0x009400
+#define NV04_PTIMER_TIME_1      0x009410
+#define NV04_PTIMER_ALARM_0     0x009420
+
+struct nv04_timer_priv {
+	struct nvkm_timer base;
+	struct list_head alarms;
+	spinlock_t lock;
+	u64 suspend_time;
+};
+
+int  nv04_timer_ctor(struct nvkm_object *, struct nvkm_object *,
+		     struct nvkm_oclass *, void *, u32,
+		     struct nvkm_object **);
+void nv04_timer_dtor(struct nvkm_object *);
+int  nv04_timer_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h
new file mode 100644
index 0000000..08e29a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h
@@ -0,0 +1,4 @@
+#ifndef __NVKM_TIMER_PRIV_H__
+#define __NVKM_TIMER_PRIV_H__
+#include <subdev/timer.h>
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
new file mode 100644
index 0000000..6b46ff4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/volt/base.o
+nvkm-y += nvkm/subdev/volt/gpio.o
+nvkm-y += nvkm/subdev/volt/nv40.o
+nvkm-y += nvkm/subdev/volt/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
new file mode 100644
index 0000000..39f1580
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+#include <subdev/bios.h>
+#include <subdev/bios/vmap.h>
+#include <subdev/bios/volt.h>
+
+static int
+nvkm_volt_get(struct nvkm_volt *volt)
+{
+	if (volt->vid_get) {
+		int ret = volt->vid_get(volt), i;
+		if (ret >= 0) {
+			for (i = 0; i < volt->vid_nr; i++) {
+				if (volt->vid[i].vid == ret)
+					return volt->vid[i].uv;
+			}
+			ret = -EINVAL;
+		}
+		return ret;
+	}
+	return -ENODEV;
+}
+
+static int
+nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
+{
+	if (volt->vid_set) {
+		int i, ret = -EINVAL;
+		for (i = 0; i < volt->vid_nr; i++) {
+			if (volt->vid[i].uv == uv) {
+				ret = volt->vid_set(volt, volt->vid[i].vid);
+				nv_debug(volt, "set %duv: %d\n", uv, ret);
+				break;
+			}
+		}
+		return ret;
+	}
+	return -ENODEV;
+}
+
+static int
+nvkm_volt_map(struct nvkm_volt *volt, u8 id)
+{
+	struct nvkm_bios *bios = nvkm_bios(volt);
+	struct nvbios_vmap_entry info;
+	u8  ver, len;
+	u16 vmap;
+
+	vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
+	if (vmap) {
+		if (info.link != 0xff) {
+			int ret = nvkm_volt_map(volt, info.link);
+			if (ret < 0)
+				return ret;
+			info.min += ret;
+		}
+		return info.min;
+	}
+
+	return id ? id * 10000 : -ENODEV;
+}
+
+static int
+nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
+{
+	int ret = nvkm_volt_map(volt, id);
+	if (ret >= 0) {
+		int prev = nvkm_volt_get(volt);
+		if (!condition || prev < 0 ||
+		    (condition < 0 && ret < prev) ||
+		    (condition > 0 && ret > prev)) {
+			ret = nvkm_volt_set(volt, ret);
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+static void
+nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
+{
+	struct nvbios_volt_entry ivid;
+	struct nvbios_volt info;
+	u8  ver, hdr, cnt, len;
+	u16 data;
+	int i;
+
+	data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
+	if (data && info.vidmask && info.base && info.step) {
+		for (i = 0; i < info.vidmask + 1; i++) {
+			if (info.base >= info.min &&
+				info.base <= info.max) {
+				volt->vid[volt->vid_nr].uv = info.base;
+				volt->vid[volt->vid_nr].vid = i;
+				volt->vid_nr++;
+			}
+			info.base += info.step;
+		}
+		volt->vid_mask = info.vidmask;
+	} else if (data && info.vidmask) {
+		for (i = 0; i < cnt; i++) {
+			data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
+						       &ivid);
+			if (data) {
+				volt->vid[volt->vid_nr].uv = ivid.voltage;
+				volt->vid[volt->vid_nr].vid = ivid.vid;
+				volt->vid_nr++;
+			}
+		}
+		volt->vid_mask = info.vidmask;
+	}
+}
+
+int
+_nvkm_volt_init(struct nvkm_object *object)
+{
+	struct nvkm_volt *volt = (void *)object;
+	int ret;
+
+	ret = nvkm_subdev_init(&volt->base);
+	if (ret)
+		return ret;
+
+	ret = volt->get(volt);
+	if (ret < 0) {
+		if (ret != -ENODEV)
+			nv_debug(volt, "current voltage unknown\n");
+		return 0;
+	}
+
+	nv_info(volt, "GPU voltage: %duv\n", ret);
+	return 0;
+}
+
+void
+_nvkm_volt_dtor(struct nvkm_object *object)
+{
+	struct nvkm_volt *volt = (void *)object;
+	nvkm_subdev_destroy(&volt->base);
+}
+
+int
+nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+		  struct nvkm_oclass *oclass, int length, void **pobject)
+{
+	struct nvkm_bios *bios = nvkm_bios(parent);
+	struct nvkm_volt *volt;
+	int ret, i;
+
+	ret = nvkm_subdev_create_(parent, engine, oclass, 0, "VOLT",
+				  "voltage", length, pobject);
+	volt = *pobject;
+	if (ret)
+		return ret;
+
+	volt->get = nvkm_volt_get;
+	volt->set = nvkm_volt_set;
+	volt->set_id = nvkm_volt_set_id;
+
+	/* Assuming the non-bios device should build the voltage table later */
+	if (bios)
+		nvkm_volt_parse_bios(bios, volt);
+
+	if (volt->vid_nr) {
+		for (i = 0; i < volt->vid_nr; i++) {
+			nv_debug(volt, "VID %02x: %duv\n",
+				 volt->vid[i].vid, volt->vid[i].uv);
+		}
+
+		/*XXX: this is an assumption.. there probably exists boards
+		 * out there with i2c-connected voltage controllers too..
+		 */
+		ret = nvkm_voltgpio_init(volt);
+		if (ret == 0) {
+			volt->vid_get = nvkm_voltgpio_get;
+			volt->vid_set = nvkm_voltgpio_set;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c
new file mode 100644
index 0000000..871fd51
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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 <subdev/volt.h>
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
+
+struct cvb_coef {
+	int c0;
+	int c1;
+	int c2;
+	int c3;
+	int c4;
+	int c5;
+};
+
+struct gk20a_volt_priv {
+	struct nvkm_volt base;
+	struct regulator *vdd;
+};
+
+const struct cvb_coef gk20a_cvb_coef[] = {
+	/* MHz,        c0,     c1,   c2,    c3,     c4,   c5 */
+	/*  72 */ { 1209886, -36468,  515,   417, -13123,  203},
+	/* 108 */ { 1130804, -27659,  296,   298, -10834,  221},
+	/* 180 */ { 1162871, -27110,  247,   238, -10681,  268},
+	/* 252 */ { 1220458, -28654,  247,   179, -10376,  298},
+	/* 324 */ { 1280953, -30204,  247,   119,  -9766,  304},
+	/* 396 */ { 1344547, -31777,  247,   119,  -8545,  292},
+	/* 468 */ { 1420168, -34227,  269,    60,  -7172,  256},
+	/* 540 */ { 1490757, -35955,  274,    60,  -5188,  197},
+	/* 612 */ { 1599112, -42583,  398,     0,  -1831,  119},
+	/* 648 */ { 1366986, -16459, -274,     0,  -3204,   72},
+	/* 684 */ { 1391884, -17078, -274,   -60,  -1526,   30},
+	/* 708 */ { 1415522, -17497, -274,   -60,   -458,    0},
+	/* 756 */ { 1464061, -18331, -274,  -119,   1831,  -72},
+	/* 804 */ { 1524225, -20064, -254,  -119,   4272, -155},
+	/* 852 */ { 1608418, -21643, -269,     0,    763,  -48},
+};
+
+/**
+ * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
+ */
+static inline int
+gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef)
+{
+	int mv;
+
+	mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
+	mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
+	return mv;
+}
+
+/**
+ * cvb_t_mv =
+ * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
+ * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
+ */
+static inline int
+gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
+			     const struct cvb_coef *coef)
+{
+	int cvb_mv, mv;
+
+	cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
+
+	mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
+		DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
+	mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
+	return mv;
+}
+
+static int
+gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
+{
+	int mv;
+
+	mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
+	mv = DIV_ROUND_UP(mv, 1000);
+
+	return mv * 1000;
+}
+
+static int
+gk20a_volt_vid_get(struct nvkm_volt *volt)
+{
+	struct gk20a_volt_priv *priv = (void *)volt;
+	int i, uv;
+
+	uv = regulator_get_voltage(priv->vdd);
+
+	for (i = 0; i < volt->vid_nr; i++)
+		if (volt->vid[i].uv >= uv)
+			return i;
+
+	return -EINVAL;
+}
+
+static int
+gk20a_volt_vid_set(struct nvkm_volt *volt, u8 vid)
+{
+	struct gk20a_volt_priv *priv = (void *)volt;
+
+	nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv);
+	return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000);
+}
+
+static int
+gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
+{
+	struct gk20a_volt_priv *priv = (void *)volt;
+	int prev_uv = regulator_get_voltage(priv->vdd);
+	int target_uv = volt->vid[id].uv;
+	int ret;
+
+	nv_debug(volt, "prev=%d, target=%d, condition=%d\n",
+			prev_uv, target_uv, condition);
+	if (!condition ||
+		(condition < 0 && target_uv < prev_uv) ||
+		(condition > 0 && target_uv > prev_uv)) {
+		ret = gk20a_volt_vid_set(volt, volt->vid[id].vid);
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int
+gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+		struct nvkm_oclass *oclass, void *data, u32 size,
+		struct nvkm_object **pobject)
+{
+	struct gk20a_volt_priv *priv;
+	struct nvkm_volt *volt;
+	struct nouveau_platform_device *plat;
+	int i, ret, uv;
+
+	ret = nvkm_volt_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	volt = &priv->base;
+
+	plat = nv_device_to_platform(nv_device(parent));
+
+	uv = regulator_get_voltage(plat->gpu->vdd);
+	nv_info(priv, "The default voltage is %duV\n", uv);
+
+	priv->vdd = plat->gpu->vdd;
+	priv->base.vid_get = gk20a_volt_vid_get;
+	priv->base.vid_set = gk20a_volt_vid_set;
+	priv->base.set_id = gk20a_volt_set_id;
+
+	volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
+	nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
+	for (i = 0; i < volt->vid_nr; i++) {
+		volt->vid[i].vid = i;
+		volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
+					plat->gpu_speedo);
+		nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
+					volt->vid[i].uv);
+	}
+
+	return 0;
+}
+
+struct nvkm_oclass
+gk20a_volt_oclass = {
+	.handle = NV_SUBDEV(VOLT, 0xea),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = gk20a_volt_ctor,
+		.dtor = _nvkm_volt_dtor,
+		.init = _nvkm_volt_init,
+		.fini = _nvkm_volt_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c
new file mode 100644
index 0000000..b778deb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/gpio.h>
+
+static const u8 tags[] = {
+	DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
+	DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
+};
+
+int
+nvkm_voltgpio_get(struct nvkm_volt *volt)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(volt);
+	u8 vid = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tags); i++) {
+		if (volt->vid_mask & (1 << i)) {
+			int ret = gpio->get(gpio, 0, tags[i], 0xff);
+			if (ret < 0)
+				return ret;
+			vid |= ret << i;
+		}
+	}
+
+	return vid;
+}
+
+int
+nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(volt);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
+		if (volt->vid_mask & (1 << i)) {
+			int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+nvkm_voltgpio_init(struct nvkm_volt *volt)
+{
+	struct nvkm_gpio *gpio = nvkm_gpio(volt);
+	struct dcb_gpio_func func;
+	int i;
+
+	/* check we have gpio function info for each vid bit.  on some
+	 * boards (ie. nvs295) the vid mask has more bits than there
+	 * are valid gpio functions... from traces, nvidia appear to
+	 * just touch the existing ones, so let's mask off the invalid
+	 * bits and continue with life
+	 */
+	for (i = 0; i < ARRAY_SIZE(tags); i++) {
+		if (volt->vid_mask & (1 << i)) {
+			int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
+			if (ret) {
+				if (ret != -ENOENT)
+					return ret;
+				nv_debug(volt, "VID bit %d has no GPIO\n", i);
+				volt->vid_mask &= ~(1 << i);
+			}
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c
new file mode 100644
index 0000000..0ac5a3f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat 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.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+
+struct nv40_volt_priv {
+	struct nvkm_volt base;
+};
+
+static int
+nv40_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+	       struct nvkm_oclass *oclass, void *data, u32 size,
+	       struct nvkm_object **pobject)
+{
+	struct nv40_volt_priv *priv;
+	int ret;
+
+	ret = nvkm_volt_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct nvkm_oclass
+nv40_volt_oclass = {
+	.handle = NV_SUBDEV(VOLT, 0x40),
+	.ofuncs = &(struct nvkm_ofuncs) {
+		.ctor = nv40_volt_ctor,
+		.dtor = _nvkm_volt_dtor,
+		.init = _nvkm_volt_init,
+		.fini = _nvkm_volt_fini,
+	},
+};
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 8436c68..d292d24 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -334,17 +334,23 @@
 		goto fail;
 	}
 
-	drm_fb_helper_single_add_all_connectors(helper);
+	ret = drm_fb_helper_single_add_all_connectors(helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(dev);
 
-	drm_fb_helper_initial_config(helper, 32);
+	ret = drm_fb_helper_initial_config(helper, 32);
+	if (ret)
+		goto fini;
 
 	priv->fbdev = helper;
 
 	return helper;
 
+fini:
+	drm_fb_helper_fini(helper);
 fail:
 	kfree(fbdev);
 	return NULL;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 024e98e..d845837 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -10,6 +10,7 @@
 config DRM_PANEL_SIMPLE
 	tristate "support for simple panels"
 	depends on OF
+	depends on BACKLIGHT_CLASS_DEVICE
 	help
 	  DRM panel driver for dumb panels that need at most a regulator and
 	  a GPIO to be powered up. Optionally a backlight can be attached so
@@ -31,6 +32,7 @@
 	tristate "Sharp LQ101R1SX01 panel"
 	depends on OF
 	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
 	help
 	  Say Y here if you want to enable support for Sharp LQ101R1SX01
 	  TFT-LCD modules. The panel has a 2560x1600 resolution and uses
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
index 9d81759..3cce3ca 100644
--- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -19,8 +19,6 @@
 
 #include <video/mipi_display.h>
 
-#include <linux/host1x.h>
-
 struct sharp_panel {
 	struct drm_panel base;
 	/* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
@@ -41,6 +39,16 @@
 	return container_of(panel, struct sharp_panel, base);
 }
 
+static void sharp_wait_frames(struct sharp_panel *sharp, unsigned int frames)
+{
+	unsigned int refresh = drm_mode_vrefresh(sharp->mode);
+
+	if (WARN_ON(frames > refresh))
+		return;
+
+	msleep(1000 / (refresh / frames));
+}
+
 static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
 {
 	u8 payload[3] = { offset >> 8, offset & 0xff, value };
@@ -106,6 +114,8 @@
 	if (!sharp->prepared)
 		return 0;
 
+	sharp_wait_frames(sharp, 4);
+
 	err = mipi_dsi_dcs_set_display_off(sharp->link1);
 	if (err < 0)
 		dev_err(panel->dev, "failed to set display off: %d\n", err);
@@ -170,15 +180,13 @@
 	if (err < 0)
 		return err;
 
-	usleep_range(10000, 20000);
-
-	err = mipi_dsi_dcs_soft_reset(sharp->link1);
-	if (err < 0) {
-		dev_err(panel->dev, "soft reset failed: %d\n", err);
-		goto poweroff;
-	}
-
-	msleep(120);
+	/*
+	 * According to the datasheet, the panel needs around 10 ms to fully
+	 * power up. At least another 120 ms is required before exiting sleep
+	 * mode to make sure the panel is ready. Throw in another 20 ms for
+	 * good measure.
+	 */
+	msleep(150);
 
 	err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
 	if (err < 0) {
@@ -238,6 +246,9 @@
 
 	sharp->prepared = true;
 
+	/* wait for 6 frames before continuing */
+	sharp_wait_frames(sharp, 6);
+
 	return 0;
 
 poweroff:
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index e95385b..39806c3 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -61,6 +61,8 @@
 		unsigned int disable;
 		unsigned int unprepare;
 	} delay;
+
+	u32 bus_format;
 };
 
 struct panel_simple {
@@ -111,6 +113,9 @@
 	connector->display_info.bpc = panel->desc->bpc;
 	connector->display_info.width_mm = panel->desc->size.width;
 	connector->display_info.height_mm = panel->desc->size.height;
+	if (panel->desc->bus_format)
+		drm_display_info_set_bus_formats(&connector->display_info,
+						 &panel->desc->bus_format, 1);
 
 	return num;
 }
@@ -443,6 +448,34 @@
 	},
 };
 
+static const struct drm_display_mode avic_tm070ddh03_mode = {
+	.clock = 51200,
+	.hdisplay = 1024,
+	.hsync_start = 1024 + 160,
+	.hsync_end = 1024 + 160 + 4,
+	.htotal = 1024 + 160 + 4 + 156,
+	.vdisplay = 600,
+	.vsync_start = 600 + 17,
+	.vsync_end = 600 + 17 + 1,
+	.vtotal = 600 + 17 + 1 + 17,
+	.vrefresh = 60,
+};
+
+static const struct panel_desc avic_tm070ddh03 = {
+	.modes = &avic_tm070ddh03_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width = 154,
+		.height = 90,
+	},
+	.delay = {
+		.prepare = 20,
+		.enable = 200,
+		.disable = 200,
+	},
+};
+
 static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
 	.clock = 72070,
 	.hdisplay = 1366,
@@ -558,6 +591,30 @@
 		.width = 108,
 		.height = 65,
 	},
+	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
+	.clock = 9000,
+	.hdisplay = 480,
+	.hsync_start = 480 + 5,
+	.hsync_end = 480 + 5 + 1,
+	.htotal = 480 + 5 + 1 + 40,
+	.vdisplay = 272,
+	.vsync_start = 272 + 8,
+	.vsync_end = 272 + 8 + 1,
+	.vtotal = 272 + 8 + 1 + 8,
+	.vrefresh = 60,
+};
+
+static const struct panel_desc giantplus_gpg482739qs5 = {
+	.modes = &giantplus_gpg482739qs5_mode,
+	.num_modes = 1,
+	.bpc = 8,
+	.size = {
+		.width = 95,
+		.height = 54,
+	},
 };
 
 static const struct drm_display_mode hannstar_hsd070pww1_mode = {
@@ -739,6 +796,9 @@
 		.compatible = "auo,b133xtn01",
 		.data = &auo_b133xtn01,
 	}, {
+		.compatible = "avic,tm070ddh03",
+		.data = &avic_tm070ddh03,
+	}, {
 		.compatible = "chunghwa,claa101wa01a",
 		.data = &chunghwa_claa101wa01a
 	}, {
@@ -757,6 +817,9 @@
 		.compatible = "foxlink,fl500wvr00-a0t",
 		.data = &foxlink_fl500wvr00_a0t,
 	}, {
+		.compatible = "giantplus,gpg482739qs5",
+		.data = &giantplus_gpg482739qs5
+	}, {
 		.compatible = "hannstar,hsd070pww1",
 		.data = &hannstar_hsd070pww1,
 	}, {
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 3d7c1d0..f778c0e 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -686,14 +686,24 @@
 	ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
 				 qxl_num_crtc /* num_crtc - QXL supports just 1 */,
 				 QXLFB_CONN_LIMIT);
-	if (ret) {
-		kfree(qfbdev);
-		return ret;
-	}
+	if (ret)
+		goto free;
 
-	drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
-	drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
+	ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
+	if (ret)
+		goto fini;
+
+	ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&qfbdev->helper);
+free:
+	kfree(qfbdev);
+	return ret;
 }
 
 void qxl_fbdev_fini(struct qxl_device *qdev)
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 12bc212..4605633 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the drm device driver.  This driver provides support for the
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
-ccflags-y := -Iinclude/drm
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include
 
 hostprogs-y := mkregtable
 clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h
@@ -80,8 +80,10 @@
 	r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
 	rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
 	trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
-	ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o \
-	radeon_sync.o
+	ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \
+	radeon_sync.o radeon_audio.o
+
+radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
 
 # add async DMA block
 radeon-y += \
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index db42a67..5bf825d 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -623,10 +623,8 @@
 		drm_dp_dpcd_writeb(dp_info->aux,
 				   DP_DOWNSPREAD_CTRL, 0);
 
-	if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) &&
-	    (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) {
+	if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
 		drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
-	}
 
 	/* set the lane count on the sink */
 	tmp = dp_info->dp_lane_count;
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index b8cd797..7c9df1e 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -27,6 +27,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
+#include "radeon_audio.h"
 #include "atom.h"
 #include <linux/backlight.h>
 
@@ -664,6 +665,8 @@
 int
 atombios_get_encoder_mode(struct drm_encoder *encoder)
 {
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct drm_connector *connector;
 	struct radeon_connector *radeon_connector;
@@ -728,6 +731,8 @@
 		dig_connector = radeon_connector->con_priv;
 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+			if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+				return ATOM_ENCODER_MODE_DP_AUDIO;
 			return ATOM_ENCODER_MODE_DP;
 		} else if (radeon_audio != 0) {
 			if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
@@ -742,6 +747,8 @@
 		}
 		break;
 	case DRM_MODE_CONNECTOR_eDP:
+		if (radeon_audio != 0 && ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+			return ATOM_ENCODER_MODE_DP_AUDIO;
 		return ATOM_ENCODER_MODE_DP;
 	case DRM_MODE_CONNECTOR_DVIA:
 	case DRM_MODE_CONNECTOR_VGA:
@@ -1615,6 +1622,7 @@
 	struct radeon_connector *radeon_connector = NULL;
 	struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
 	bool travis_quirk = false;
+	int encoder_mode;
 
 	if (connector) {
 		radeon_connector = to_radeon_connector(connector);
@@ -1710,6 +1718,11 @@
 		}
 		break;
 	}
+
+	encoder_mode = atombios_get_encoder_mode(encoder);
+	if (radeon_audio != 0 &&
+		(encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
+		radeon_audio_dpms(encoder, mode);
 }
 
 static void
@@ -2123,6 +2136,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	int encoder_mode;
 
 	radeon_encoder->pixel_clock = adjusted_mode->clock;
 
@@ -2149,6 +2163,10 @@
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
 		/* handled in dpms */
+		encoder_mode = atombios_get_encoder_mode(encoder);
+		if (radeon_audio != 0 &&
+			(encoder_mode == ATOM_ENCODER_MODE_HDMI || ENCODER_MODE_IS_DP(encoder_mode)))
+			radeon_audio_mode_set(encoder, adjusted_mode);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@@ -2170,13 +2188,6 @@
 	}
 
 	atombios_apply_encoder_quirks(encoder, adjusted_mode);
-
-	if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
-		if (rdev->asic->display.hdmi_enable)
-			radeon_hdmi_enable(rdev, encoder, true);
-		if (rdev->asic->display.hdmi_setmode)
-			radeon_hdmi_setmode(rdev, encoder, adjusted_mode);
-	}
 }
 
 static bool
@@ -2442,10 +2453,6 @@
 
 disable_done:
 	if (radeon_encoder_is_digital(encoder)) {
-		if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
-			if (rdev->asic->display.hdmi_enable)
-				radeon_hdmi_enable(rdev, encoder, false);
-		}
 		dig = radeon_encoder->enc_priv;
 		dig->dig_encoder = -1;
 	}
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 0b2929d..db08f17 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2277,6 +2277,7 @@
 	eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps;
 }
 
+#if 0
 void btc_dpm_reset_asic(struct radeon_device *rdev)
 {
 	rv770_restrict_performance_levels_before_switch(rdev);
@@ -2284,6 +2285,7 @@
 	btc_set_boot_state_timing(rdev);
 	rv770_set_boot_state(rdev);
 }
+#endif
 
 int btc_dpm_pre_set_power_state(struct radeon_device *rdev)
 {
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index f373a81..bcd2f1f 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -187,6 +187,9 @@
 static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
 						      PPSMC_Msg msg, u32 parameter);
 
+static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
+static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev);
+
 static struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
 {
         struct ci_power_info *pi = rdev->pm.dpm.priv;
@@ -1043,22 +1046,24 @@
 			return -EINVAL;
 	}
 
+	pi->fan_is_controlled_by_smc = true;
 	return 0;
 }
 
-#if 0
 static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
 {
 	PPSMC_Result ret;
+	struct ci_power_info *pi = ci_get_pi(rdev);
 
 	ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
-	if (ret == PPSMC_Result_OK)
+	if (ret == PPSMC_Result_OK) {
+		pi->fan_is_controlled_by_smc = false;
 		return 0;
-	else
+	} else
 		return -EINVAL;
 }
 
-static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
 					     u32 *speed)
 {
 	u32 duty, duty100;
@@ -1083,21 +1088,22 @@
 	return 0;
 }
 
-static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
 					     u32 speed)
 {
 	u32 tmp;
 	u32 duty, duty100;
 	u64 tmp64;
+	struct ci_power_info *pi = ci_get_pi(rdev);
 
 	if (rdev->pm.no_fan)
 		return -ENOENT;
 
-	if (speed > 100)
+	if (pi->fan_is_controlled_by_smc)
 		return -EINVAL;
 
-	if (rdev->pm.dpm.fan.ucode_fan_control)
-		ci_fan_ctrl_stop_smc_fan_control(rdev);
+	if (speed > 100)
+		return -EINVAL;
 
 	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
 
@@ -1112,11 +1118,38 @@
 	tmp |= FDO_STATIC_DUTY(duty);
 	WREG32_SMC(CG_FDO_CTRL0, tmp);
 
-	ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
-
 	return 0;
 }
 
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
+{
+	if (mode) {
+		/* stop auto-manage */
+		if (rdev->pm.dpm.fan.ucode_fan_control)
+			ci_fan_ctrl_stop_smc_fan_control(rdev);
+		ci_fan_ctrl_set_static_mode(rdev, mode);
+	} else {
+		/* restart auto-manage */
+		if (rdev->pm.dpm.fan.ucode_fan_control)
+			ci_thermal_start_smc_fan_control(rdev);
+		else
+			ci_fan_ctrl_set_default_mode(rdev);
+	}
+}
+
+u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev)
+{
+	struct ci_power_info *pi = ci_get_pi(rdev);
+	u32 tmp;
+
+	if (pi->fan_is_controlled_by_smc)
+		return 0;
+
+	tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+	return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
 static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
 					 u32 *speed)
 {
@@ -1698,10 +1731,12 @@
 	return 0;
 }
 
+#if 0
 static int ci_set_boot_state(struct radeon_device *rdev)
 {
 	return ci_enable_sclk_mclk_dpm(rdev, false);
 }
+#endif
 
 static u32 ci_get_average_sclk_freq(struct radeon_device *rdev)
 {
@@ -5343,10 +5378,12 @@
 	return 0;
 }
 
+#if 0
 void ci_dpm_reset_asic(struct radeon_device *rdev)
 {
 	ci_set_boot_state(rdev);
 }
+#endif
 
 void ci_dpm_display_configuration_changed(struct radeon_device *rdev)
 {
diff --git a/drivers/gpu/drm/radeon/ci_dpm.h b/drivers/gpu/drm/radeon/ci_dpm.h
index 84e3d3b..723220f 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.h
+++ b/drivers/gpu/drm/radeon/ci_dpm.h
@@ -291,6 +291,7 @@
 	struct ci_ps requested_ps;
 	/* fan control */
 	bool fan_ctrl_is_in_default_mode;
+	bool fan_is_controlled_by_smc;
 	u32 t_min;
 	u32 fan_ctrl_default_mode;
 };
diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c
index e78bcad..35c6f64 100644
--- a/drivers/gpu/drm/radeon/ci_smc.c
+++ b/drivers/gpu/drm/radeon/ci_smc.c
@@ -184,6 +184,7 @@
 	return (PPSMC_Result)tmp;
 }
 
+#if 0
 PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
 {
 	u32 tmp;
@@ -201,6 +202,7 @@
 
 	return PPSMC_Result_OK;
 }
+#endif
 
 int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 {
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 64fdae5..e6a4ba2 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -27,6 +27,7 @@
 #include "drmP.h"
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "cikd.h"
 #include "atom.h"
 #include "cik_blit_shaders.h"
@@ -3904,7 +3905,21 @@
 	struct radeon_ring *ring = &rdev->ring[fence->ring];
 	u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
 
-	/* EVENT_WRITE_EOP - flush caches, send int */
+	/* Workaround for cache flush problems. First send a dummy EOP
+	 * event down the pipe with seq one below.
+	 */
+	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+				 EOP_TC_ACTION_EN |
+				 EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+				 EVENT_INDEX(5)));
+	radeon_ring_write(ring, addr & 0xfffffffc);
+	radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+				DATA_SEL(1) | INT_SEL(0));
+	radeon_ring_write(ring, fence->seq - 1);
+	radeon_ring_write(ring, 0);
+
+	/* Then send the real EOP event down the pipe. */
 	radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
 	radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
 				 EOP_TC_ACTION_EN |
@@ -5707,6 +5722,28 @@
 	WREG32(VM_INVALIDATE_REQUEST, 0x1);
 }
 
+static void cik_pcie_init_compute_vmid(struct radeon_device *rdev)
+{
+	int i;
+	uint32_t sh_mem_bases, sh_mem_config;
+
+	sh_mem_bases = 0x6000 | 0x6000 << 16;
+	sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
+	sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
+
+	mutex_lock(&rdev->srbm_mutex);
+	for (i = 8; i < 16; i++) {
+		cik_srbm_select(rdev, 0, 0, 0, i);
+		/* CP and shaders */
+		WREG32(SH_MEM_CONFIG, sh_mem_config);
+		WREG32(SH_MEM_APE1_BASE, 1);
+		WREG32(SH_MEM_APE1_LIMIT, 0);
+		WREG32(SH_MEM_BASES, sh_mem_bases);
+	}
+	cik_srbm_select(rdev, 0, 0, 0, 0);
+	mutex_unlock(&rdev->srbm_mutex);
+}
+
 /**
  * cik_pcie_gart_enable - gart enable
  *
@@ -5820,6 +5857,8 @@
 	cik_srbm_select(rdev, 0, 0, 0, 0);
 	mutex_unlock(&rdev->srbm_mutex);
 
+	cik_pcie_init_compute_vmid(rdev);
+
 	cik_pcie_gart_tlb_flush(rdev);
 	DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
 		 (unsigned)(rdev->mc.gtt_size >> 20),
@@ -7334,7 +7373,6 @@
 	u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
 	u32 grbm_int_cntl = 0;
 	u32 dma_cntl, dma_cntl1;
-	u32 thermal_int;
 
 	if (!rdev->irq.installed) {
 		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -7364,13 +7402,6 @@
 
 	cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
 
-	if (rdev->flags & RADEON_IS_IGP)
-		thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) &
-			~(THERM_INTH_MASK | THERM_INTL_MASK);
-	else
-		thermal_int = RREG32_SMC(CG_THERMAL_INT) &
-			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
-
 	/* enable CP interrupts on all rings */
 	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
 		DRM_DEBUG("cik_irq_set: sw int gfx\n");
@@ -7474,14 +7505,6 @@
 		hpd6 |= DC_HPDx_INT_EN;
 	}
 
-	if (rdev->irq.dpm_thermal) {
-		DRM_DEBUG("dpm thermal\n");
-		if (rdev->flags & RADEON_IS_IGP)
-			thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK;
-		else
-			thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
-	}
-
 	WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
 
 	WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
@@ -7528,11 +7551,6 @@
 	WREG32(DC_HPD5_INT_CONTROL, hpd5);
 	WREG32(DC_HPD6_INT_CONTROL, hpd6);
 
-	if (rdev->flags & RADEON_IS_IGP)
-		WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int);
-	else
-		WREG32_SMC(CG_THERMAL_INT, thermal_int);
-
 	return 0;
 }
 
@@ -8493,7 +8511,7 @@
 		return r;
 	}
 
-	r = dce6_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r)
 		return r;
 
@@ -8551,7 +8569,7 @@
 {
 	radeon_kfd_suspend(rdev);
 	radeon_pm_suspend(rdev);
-	dce6_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	cik_cp_enable(rdev, false);
 	cik_sdma_enable(rdev, false);
diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
index 79c45e8..f667347 100644
--- a/drivers/gpu/drm/radeon/cik_reg.h
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -147,140 +147,41 @@
 
 #define CIK_LB_DESKTOP_HEIGHT                     0x6b0c
 
+#define KFD_CIK_SDMA_QUEUE_OFFSET		0x200
+
 #define CP_HQD_IQ_RPTR					0xC970u
 #define AQL_ENABLE					(1U << 0)
-
-#define IDLE					(1 << 2)
-
-struct cik_mqd {
-	uint32_t header;
-	uint32_t compute_dispatch_initiator;
-	uint32_t compute_dim_x;
-	uint32_t compute_dim_y;
-	uint32_t compute_dim_z;
-	uint32_t compute_start_x;
-	uint32_t compute_start_y;
-	uint32_t compute_start_z;
-	uint32_t compute_num_thread_x;
-	uint32_t compute_num_thread_y;
-	uint32_t compute_num_thread_z;
-	uint32_t compute_pipelinestat_enable;
-	uint32_t compute_perfcount_enable;
-	uint32_t compute_pgm_lo;
-	uint32_t compute_pgm_hi;
-	uint32_t compute_tba_lo;
-	uint32_t compute_tba_hi;
-	uint32_t compute_tma_lo;
-	uint32_t compute_tma_hi;
-	uint32_t compute_pgm_rsrc1;
-	uint32_t compute_pgm_rsrc2;
-	uint32_t compute_vmid;
-	uint32_t compute_resource_limits;
-	uint32_t compute_static_thread_mgmt_se0;
-	uint32_t compute_static_thread_mgmt_se1;
-	uint32_t compute_tmpring_size;
-	uint32_t compute_static_thread_mgmt_se2;
-	uint32_t compute_static_thread_mgmt_se3;
-	uint32_t compute_restart_x;
-	uint32_t compute_restart_y;
-	uint32_t compute_restart_z;
-	uint32_t compute_thread_trace_enable;
-	uint32_t compute_misc_reserved;
-	uint32_t compute_user_data_0;
-	uint32_t compute_user_data_1;
-	uint32_t compute_user_data_2;
-	uint32_t compute_user_data_3;
-	uint32_t compute_user_data_4;
-	uint32_t compute_user_data_5;
-	uint32_t compute_user_data_6;
-	uint32_t compute_user_data_7;
-	uint32_t compute_user_data_8;
-	uint32_t compute_user_data_9;
-	uint32_t compute_user_data_10;
-	uint32_t compute_user_data_11;
-	uint32_t compute_user_data_12;
-	uint32_t compute_user_data_13;
-	uint32_t compute_user_data_14;
-	uint32_t compute_user_data_15;
-	uint32_t cp_compute_csinvoc_count_lo;
-	uint32_t cp_compute_csinvoc_count_hi;
-	uint32_t cp_mqd_base_addr_lo;
-	uint32_t cp_mqd_base_addr_hi;
-	uint32_t cp_hqd_active;
-	uint32_t cp_hqd_vmid;
-	uint32_t cp_hqd_persistent_state;
-	uint32_t cp_hqd_pipe_priority;
-	uint32_t cp_hqd_queue_priority;
-	uint32_t cp_hqd_quantum;
-	uint32_t cp_hqd_pq_base_lo;
-	uint32_t cp_hqd_pq_base_hi;
-	uint32_t cp_hqd_pq_rptr;
-	uint32_t cp_hqd_pq_rptr_report_addr_lo;
-	uint32_t cp_hqd_pq_rptr_report_addr_hi;
-	uint32_t cp_hqd_pq_wptr_poll_addr_lo;
-	uint32_t cp_hqd_pq_wptr_poll_addr_hi;
-	uint32_t cp_hqd_pq_doorbell_control;
-	uint32_t cp_hqd_pq_wptr;
-	uint32_t cp_hqd_pq_control;
-	uint32_t cp_hqd_ib_base_addr_lo;
-	uint32_t cp_hqd_ib_base_addr_hi;
-	uint32_t cp_hqd_ib_rptr;
-	uint32_t cp_hqd_ib_control;
-	uint32_t cp_hqd_iq_timer;
-	uint32_t cp_hqd_iq_rptr;
-	uint32_t cp_hqd_dequeue_request;
-	uint32_t cp_hqd_dma_offload;
-	uint32_t cp_hqd_sema_cmd;
-	uint32_t cp_hqd_msg_type;
-	uint32_t cp_hqd_atomic0_preop_lo;
-	uint32_t cp_hqd_atomic0_preop_hi;
-	uint32_t cp_hqd_atomic1_preop_lo;
-	uint32_t cp_hqd_atomic1_preop_hi;
-	uint32_t cp_hqd_hq_status0;
-	uint32_t cp_hqd_hq_control0;
-	uint32_t cp_mqd_control;
-	uint32_t cp_mqd_query_time_lo;
-	uint32_t cp_mqd_query_time_hi;
-	uint32_t cp_mqd_connect_start_time_lo;
-	uint32_t cp_mqd_connect_start_time_hi;
-	uint32_t cp_mqd_connect_end_time_lo;
-	uint32_t cp_mqd_connect_end_time_hi;
-	uint32_t cp_mqd_connect_end_wf_count;
-	uint32_t cp_mqd_connect_end_pq_rptr;
-	uint32_t cp_mqd_connect_end_pq_wptr;
-	uint32_t cp_mqd_connect_end_ib_rptr;
-	uint32_t reserved_96;
-	uint32_t reserved_97;
-	uint32_t reserved_98;
-	uint32_t reserved_99;
-	uint32_t iqtimer_pkt_header;
-	uint32_t iqtimer_pkt_dw0;
-	uint32_t iqtimer_pkt_dw1;
-	uint32_t iqtimer_pkt_dw2;
-	uint32_t iqtimer_pkt_dw3;
-	uint32_t iqtimer_pkt_dw4;
-	uint32_t iqtimer_pkt_dw5;
-	uint32_t iqtimer_pkt_dw6;
-	uint32_t reserved_108;
-	uint32_t reserved_109;
-	uint32_t reserved_110;
-	uint32_t reserved_111;
-	uint32_t queue_doorbell_id0;
-	uint32_t queue_doorbell_id1;
-	uint32_t queue_doorbell_id2;
-	uint32_t queue_doorbell_id3;
-	uint32_t queue_doorbell_id4;
-	uint32_t queue_doorbell_id5;
-	uint32_t queue_doorbell_id6;
-	uint32_t queue_doorbell_id7;
-	uint32_t queue_doorbell_id8;
-	uint32_t queue_doorbell_id9;
-	uint32_t queue_doorbell_id10;
-	uint32_t queue_doorbell_id11;
-	uint32_t queue_doorbell_id12;
-	uint32_t queue_doorbell_id13;
-	uint32_t queue_doorbell_id14;
-	uint32_t queue_doorbell_id15;
-};
+#define SDMA0_RLC0_RB_CNTL				0xD400u
+#define	SDMA_RB_VMID(x)					(x << 24)
+#define	SDMA0_RLC0_RB_BASE				0xD404u
+#define	SDMA0_RLC0_RB_BASE_HI				0xD408u
+#define	SDMA0_RLC0_RB_RPTR				0xD40Cu
+#define	SDMA0_RLC0_RB_WPTR				0xD410u
+#define	SDMA0_RLC0_RB_WPTR_POLL_CNTL			0xD414u
+#define	SDMA0_RLC0_RB_WPTR_POLL_ADDR_HI			0xD418u
+#define	SDMA0_RLC0_RB_WPTR_POLL_ADDR_LO			0xD41Cu
+#define	SDMA0_RLC0_RB_RPTR_ADDR_HI			0xD420u
+#define	SDMA0_RLC0_RB_RPTR_ADDR_LO			0xD424u
+#define	SDMA0_RLC0_IB_CNTL				0xD428u
+#define	SDMA0_RLC0_IB_RPTR				0xD42Cu
+#define	SDMA0_RLC0_IB_OFFSET				0xD430u
+#define	SDMA0_RLC0_IB_BASE_LO				0xD434u
+#define	SDMA0_RLC0_IB_BASE_HI				0xD438u
+#define	SDMA0_RLC0_IB_SIZE				0xD43Cu
+#define	SDMA0_RLC0_SKIP_CNTL				0xD440u
+#define	SDMA0_RLC0_CONTEXT_STATUS			0xD444u
+#define	SDMA_RLC_IDLE					(1 << 2)
+#define	SDMA0_RLC0_DOORBELL				0xD448u
+#define	SDMA_OFFSET(x)					(x << 0)
+#define	SDMA_DB_ENABLE					(1 << 28)
+#define	SDMA0_RLC0_VIRTUAL_ADDR				0xD49Cu
+#define	SDMA_ATC					(1 << 0)
+#define	SDMA_VA_PTR32					(1 << 4)
+#define	SDMA_VA_SHARED_BASE(x)				(x << 8)
+#define	SDMA0_RLC0_APE1_CNTL				0xD4A0u
+#define	SDMA0_RLC0_DOORBELL_LOG				0xD4A4u
+#define	SDMA0_RLC0_WATERMARK				0xD4A8u
+#define	SDMA0_CNTL					0xD010
+#define	SDMA1_CNTL					0xD810
 
 #endif
diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c
index 42cd0cf..f86eb54 100644
--- a/drivers/gpu/drm/radeon/cik_sdma.c
+++ b/drivers/gpu/drm/radeon/cik_sdma.c
@@ -283,6 +283,33 @@
 }
 
 /**
+ * cik_sdma_ctx_switch_enable - enable/disable sdma engine preemption
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable/disable preemption.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_ctx_switch_enable(struct radeon_device *rdev, bool enable)
+{
+	uint32_t reg_offset, value;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (i == 0)
+			reg_offset = SDMA0_REGISTER_OFFSET;
+		else
+			reg_offset = SDMA1_REGISTER_OFFSET;
+		value = RREG32(SDMA0_CNTL + reg_offset);
+		if (enable)
+			value |= AUTO_CTXSW_ENABLE;
+		else
+			value &= ~AUTO_CTXSW_ENABLE;
+		WREG32(SDMA0_CNTL + reg_offset, value);
+	}
+}
+
+/**
  * cik_sdma_enable - stop the async dma engines
  *
  * @rdev: radeon_device pointer
@@ -312,6 +339,8 @@
 			me_cntl |= SDMA_HALT;
 		WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
 	}
+
+	cik_sdma_ctx_switch_enable(rdev, enable);
 }
 
 /**
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 9aad032..ca05858 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -2005,11 +2005,13 @@
 	return 0;
 }
 
+#if 0
 void cypress_dpm_reset_asic(struct radeon_device *rdev)
 {
 	rv770_restrict_performance_levels_before_switch(rdev);
 	rv770_set_boot_state(rdev);
 }
+#endif
 
 void cypress_dpm_display_configuration_changed(struct radeon_device *rdev)
 {
diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c
index bafdf92..f042051 100644
--- a/drivers/gpu/drm/radeon/dce3_1_afmt.c
+++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c
@@ -24,37 +24,17 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "r600d.h"
 
-static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
 	u32 tmp;
-	u8 *sadb = NULL;
-	int sad_count;
-
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
-	if (sad_count < 0) {
-		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
-		sad_count = 0;
-	}
 
 	/* program the speaker allocation */
-	tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
 	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
 	/* set HDMI mode */
 	tmp |= HDMI_CONNECTION;
@@ -62,19 +42,32 @@
 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
 	else
 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-	WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
-
-	kfree(sadb);
+	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
-static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
+void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
-	struct cea_sad *sads;
-	int i, sad_count;
+	u32 tmp;
 
+	/* program the speaker allocation */
+	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+	tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+	/* set DP mode */
+	tmp |= DP_CONNECTION;
+	if (sad_count)
+		tmp |= SPEAKER_ALLOCATION(sadb[0]);
+	else
+		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+
+void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
+	struct cea_sad *sads, int sad_count)
+{
+	int i;
+	struct radeon_device *rdev = encoder->dev->dev_private;
 	static const u16 eld_reg_to_type[][2] = {
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -90,25 +83,6 @@
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
 	};
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
-	if (sad_count <= 0) {
-		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
-		return;
-	}
-	BUG_ON(!sads);
-
 	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
 		u32 value = 0;
 		u8 stereo_freqs = 0;
@@ -135,110 +109,124 @@
 
 		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
 
-		WREG32(eld_reg_to_type[i][0], value);
+		WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
 	}
-
-	kfree(sads);
 }
 
-/*
- * update the info frames with the data from the current display mode
- */
-void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+void dce3_2_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock)
+{
+	struct radeon_encoder *radeon_encoder;
+	struct radeon_encoder_atom_dig *dig;
+	unsigned int max_ratio = clock / 24000;
+	u32 dto_phase;
+	u32 wallclock_ratio;
+	u32 dto_cntl;
+
+	if (!crtc)
+		return;
+
+	radeon_encoder = to_radeon_encoder(crtc->encoder);
+	dig = radeon_encoder->enc_priv;
+
+	if (!dig)
+		return;
+
+	if (max_ratio >= 8) {
+		dto_phase = 192 * 1000;
+		wallclock_ratio = 3;
+	} else if (max_ratio >= 4) {
+		dto_phase = 96 * 1000;
+		wallclock_ratio = 2;
+	} else if (max_ratio >= 2) {
+		dto_phase = 48 * 1000;
+		wallclock_ratio = 1;
+	} else {
+		dto_phase = 24 * 1000;
+		wallclock_ratio = 0;
+	}
+
+	/* Express [24MHz / target pixel clock] as an exact rational
+	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+	 */
+	if (dig->dig_encoder == 0) {
+		dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+		dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+		WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+		WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+		WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+		WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+	} else {
+		dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+		dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+		WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
+		WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
+		WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+		WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
+	}
+}
+
+void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
-	struct hdmi_avi_infoframe frame;
-	uint32_t offset;
-	ssize_t err;
-
-	if (!dig || !dig->afmt)
-		return;
-
-	/* Silent, r600_hdmi_enable will raise WARN for us */
-	if (!dig->afmt->enabled)
-		return;
-	offset = dig->afmt->offset;
-
-	/* disable audio prior to setting up hw */
-	dig->afmt->pin = r600_audio_get_pin(rdev);
-	r600_audio_enable(rdev, dig->afmt->pin, 0);
-
-	r600_audio_set_dto(encoder, mode->clock);
-
-	WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
-	       HDMI0_NULL_SEND); /* send null packets when required */
-
-	WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
-
-	if (ASIC_IS_DCE32(rdev)) {
-		WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
-		       HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
-		       HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-		WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
-		       AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
-		       AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
-	} else {
-		WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
-		       HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
-		       HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
-		       HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
-		       HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
-	}
-
-	if (ASIC_IS_DCE32(rdev)) {
-		dce3_2_afmt_write_speaker_allocation(encoder);
-		dce3_2_afmt_write_sad_regs(encoder);
-	}
 
 	WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
-	       HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
-	       HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
+		HDMI0_ACR_SOURCE |		/* select SW CTS value */
+		HDMI0_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
 
-	WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
-	       HDMI0_NULL_SEND | /* send null packets when required */
-	       HDMI0_GC_SEND | /* send general control packets */
-	       HDMI0_GC_CONT); /* send general control packets every frame */
+	WREG32_P(HDMI0_ACR_32_0 + offset,
+		HDMI0_ACR_CTS_32(acr->cts_32khz),
+		~HDMI0_ACR_CTS_32_MASK);
+	WREG32_P(HDMI0_ACR_32_1 + offset,
+		HDMI0_ACR_N_32(acr->n_32khz),
+		~HDMI0_ACR_N_32_MASK);
 
-	/* TODO: HDMI0_AUDIO_INFO_UPDATE */
-	WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
-	       HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
-	       HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
-	       HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-	       HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
+	WREG32_P(HDMI0_ACR_44_0 + offset,
+		HDMI0_ACR_CTS_44(acr->cts_44_1khz),
+		~HDMI0_ACR_CTS_44_MASK);
+	WREG32_P(HDMI0_ACR_44_1 + offset,
+		HDMI0_ACR_N_44(acr->n_44_1khz),
+		~HDMI0_ACR_N_44_MASK);
 
-	WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
-	       HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
-	       HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+	WREG32_P(HDMI0_ACR_48_0 + offset,
+		HDMI0_ACR_CTS_48(acr->cts_48khz),
+		~HDMI0_ACR_CTS_48_MASK);
+	WREG32_P(HDMI0_ACR_48_1 + offset,
+		HDMI0_ACR_N_48(acr->n_48khz),
+		~HDMI0_ACR_N_48_MASK);
+}
 
-	WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
+void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 
-	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
-	if (err < 0) {
-		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
-		return;
-	}
+	WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
+		HDMI0_AUDIO_DELAY_EN(1) |			/* default audio delay */
+		HDMI0_AUDIO_PACKETS_PER_LINE(3));	/* should be suffient for all audio modes and small enough for all hblanks */
 
-	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
-	if (err < 0) {
-		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
-		return;
-	}
+	WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+		AFMT_AUDIO_SAMPLE_SEND |			/* send audio packets */
+		AFMT_60958_CS_UPDATE);				/* allow 60958 channel status fields to be updated */
 
-	r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
-	r600_hdmi_update_ACR(encoder, mode->clock);
+	WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
+		HDMI0_AUDIO_INFO_SEND |				/* enable audio info frames (frames won't be set until audio is enabled) */
+		HDMI0_AUDIO_INFO_CONT);				/* send audio info frames every frame/field */
 
-	/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
-	WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
-	WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
-	WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
-	WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
+	WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
+		HDMI0_AUDIO_INFO_LINE(2));			/* anything other than 0 */
+}
 
-	r600_hdmi_audio_workaround(encoder);
+void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 
-	/* enable audio after to setting up hw */
-	r600_audio_enable(rdev, dig->afmt->pin, 0xf);
+	if (mute)
+		WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
+	else
+		WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
 }
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index f312edf..192c803 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -23,9 +23,10 @@
 #include <linux/hdmi.h>
 #include <drm/drmP.h>
 #include "radeon.h"
+#include "radeon_audio.h"
 #include "sid.h"
 
-static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
+u32 dce6_endpoint_rreg(struct radeon_device *rdev,
 			      u32 block_offset, u32 reg)
 {
 	unsigned long flags;
@@ -39,7 +40,7 @@
 	return r;
 }
 
-static void dce6_endpoint_wreg(struct radeon_device *rdev,
+void dce6_endpoint_wreg(struct radeon_device *rdev,
 			       u32 block_offset, u32 reg, u32 v)
 {
 	unsigned long flags;
@@ -54,10 +55,6 @@
 	spin_unlock_irqrestore(&rdev->end_idx_lock, flags);
 }
 
-#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg))
-#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v))
-
-
 static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
 {
 	int i;
@@ -105,13 +102,11 @@
 }
 
 void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
-				    struct drm_display_mode *mode)
+		struct drm_connector *connector, struct drm_display_mode *mode)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
 	u32 tmp = 0, offset;
 
 	if (!dig || !dig->afmt || !dig->afmt->pin)
@@ -119,18 +114,6 @@
 
 	offset = dig->afmt->pin->offset;
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
 		if (connector->latency_present[1])
 			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -147,40 +130,19 @@
 	WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
 }
 
-void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
 	u32 offset, tmp;
-	u8 *sadb = NULL;
-	int sad_count;
 
 	if (!dig || !dig->afmt || !dig->afmt->pin)
 		return;
 
 	offset = dig->afmt->pin->offset;
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb);
-	if (sad_count < 0) {
-		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
-		sad_count = 0;
-	}
-
 	/* program the speaker allocation */
 	tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
 	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
@@ -191,21 +153,41 @@
 	else
 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
 	WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
-
-	kfree(sadb);
 }
 
-void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
+void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	u32 offset;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
-	struct cea_sad *sads;
-	int i, sad_count;
+	u32 offset, tmp;
 
+	if (!dig || !dig->afmt || !dig->afmt->pin)
+		return;
+
+	offset = dig->afmt->pin->offset;
+
+	/* program the speaker allocation */
+	tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+	tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+	/* set DP mode */
+	tmp |= DP_CONNECTION;
+	if (sad_count)
+		tmp |= SPEAKER_ALLOCATION(sadb[0]);
+	else
+		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+	WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+
+void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
+	struct cea_sad *sads, int sad_count)
+{
+	u32 offset;
+	int i;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	struct radeon_device *rdev = encoder->dev->dev_private;
 	static const u16 eld_reg_to_type[][2] = {
 		{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
 		{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -226,25 +208,6 @@
 
 	offset = dig->afmt->pin->offset;
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
-	if (sad_count <= 0) {
-		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
-		return;
-	}
-	BUG_ON(!sads);
-
 	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
 		u32 value = 0;
 		u8 stereo_freqs = 0;
@@ -273,13 +236,6 @@
 
 		WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
 	}
-
-	kfree(sads);
-}
-
-static int dce6_audio_chipset_supported(struct radeon_device *rdev)
-{
-	return !ASIC_IS_NODCE(rdev);
 }
 
 void dce6_audio_enable(struct radeon_device *rdev,
@@ -293,64 +249,76 @@
 			enable_mask ? AUDIO_ENABLED : 0);
 }
 
-static const u32 pin_offsets[7] =
+void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock)
 {
-	(0x5e00 - 0x5e00),
-	(0x5e18 - 0x5e00),
-	(0x5e30 - 0x5e00),
-	(0x5e48 - 0x5e00),
-	(0x5e60 - 0x5e00),
-	(0x5e78 - 0x5e00),
-	(0x5e90 - 0x5e00),
-};
+    /* Two dtos; generally use dto0 for HDMI */
+	u32 value = 0;
 
-int dce6_audio_init(struct radeon_device *rdev)
-{
-	int i;
+    if (crtc)
+		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
 
-	if (!radeon_audio || !dce6_audio_chipset_supported(rdev))
-		return 0;
+	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
 
-	rdev->audio.enabled = true;
-
-	if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */
-		rdev->audio.num_pins = 7;
-	else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */
-		rdev->audio.num_pins = 3;
-	else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */
-		rdev->audio.num_pins = 7;
-	else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */
-		rdev->audio.num_pins = 6;
-	else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */
-		rdev->audio.num_pins = 2;
-	else /* SI: 6 streams, 6 endpoints */
-		rdev->audio.num_pins = 6;
-
-	for (i = 0; i < rdev->audio.num_pins; i++) {
-		rdev->audio.pin[i].channels = -1;
-		rdev->audio.pin[i].rate = -1;
-		rdev->audio.pin[i].bits_per_sample = -1;
-		rdev->audio.pin[i].status_bits = 0;
-		rdev->audio.pin[i].category_code = 0;
-		rdev->audio.pin[i].connected = false;
-		rdev->audio.pin[i].offset = pin_offsets[i];
-		rdev->audio.pin[i].id = i;
-		/* disable audio.  it will be set up later */
-		dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
-	}
-
-	return 0;
+    /* Express [24MHz / target pixel clock] as an exact rational
+     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+     */
+    WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
+    WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
 }
 
-void dce6_audio_fini(struct radeon_device *rdev)
+void dce6_dp_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock)
 {
-	int i;
+    /* Two dtos; generally use dto1 for DP */
+	u32 value = 0;
+	value |= DCCG_AUDIO_DTO_SEL;
 
-	if (!rdev->audio.enabled)
+    if (crtc)
+		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
+
+	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
+
+    /* Express [24MHz / target pixel clock] as an exact rational
+     * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+     * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+     */
+    WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+    WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+}
+
+void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	uint32_t offset;
+
+	if (!dig || !dig->afmt)
 		return;
 
-	for (i = 0; i < rdev->audio.num_pins; i++)
-		dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
+	offset = dig->afmt->offset;
 
-	rdev->audio.enabled = false;
+	if (enable) {
+        if (dig->afmt->enabled)
+            return;
+
+		WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+		WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+			EVERGREEN_DP_SEC_ASP_ENABLE |		/* Audio packet transmission */
+			EVERGREEN_DP_SEC_ATP_ENABLE |		/* Audio timestamp packet transmission */
+			EVERGREEN_DP_SEC_AIP_ENABLE |		/* Audio infoframe packet transmission */
+			EVERGREEN_DP_SEC_STREAM_ENABLE);	/* Master enable for secondary stream engine */
+		radeon_audio_enable(rdev, dig->afmt->pin, true);
+	} else {
+		if (!dig->afmt->enabled)
+			return;
+
+		WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
+		radeon_audio_enable(rdev, dig->afmt->pin, false);
+	}
+
+	dig->afmt->enabled = enable;
 }
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 85995b4..78600f5 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -26,6 +26,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include <drm/radeon_drm.h>
 #include "evergreend.h"
 #include "atom.h"
@@ -5286,7 +5287,7 @@
 		return r;
 	}
 
-	r = r600_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r) {
 		DRM_ERROR("radeon: audio init failed\n");
 		return r;
@@ -5332,7 +5333,7 @@
 int evergreen_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	uvd_v1_0_fini(rdev);
 	radeon_uvd_suspend(rdev);
 	r700_cp_stop(rdev);
@@ -5482,7 +5483,7 @@
 void evergreen_fini(struct radeon_device *rdev)
 {
 	radeon_pm_fini(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r700_cp_fini(rdev);
 	r600_dma_fini(rdev);
 	r600_irq_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 924b1b7..c9e0fbb 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -83,6 +83,7 @@
 	u32			htile_offset;
 	u32			htile_surface;
 	struct radeon_bo	*htile_bo;
+	unsigned long		indirect_draw_buffer_size;
 };
 
 static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -1896,6 +1897,14 @@
 		}
 		break;
 	}
+	case PACKET3_INDEX_BUFFER_SIZE:
+	{
+		if (pkt->count != 0) {
+			DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
+			return -EINVAL;
+		}
+		break;
+	}
 	case PACKET3_DRAW_INDEX:
 	{
 		uint64_t offset;
@@ -2006,6 +2015,67 @@
 			return r;
 		}
 		break;
+	case PACKET3_SET_BASE:
+	{
+		/*
+		DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet.
+		   2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs.
+		     0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data.
+		   3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved
+		   4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32]
+		*/
+		if (pkt->count != 2) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		/* currently only supporting setting indirect draw buffer base address */
+		if (idx_value != 1) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		r = radeon_cs_packet_next_reloc(p, &reloc, 0);
+		if (r) {
+			DRM_ERROR("bad SET_BASE\n");
+			return -EINVAL;
+		}
+
+		track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);
+
+		ib[idx+1] = reloc->gpu_offset;
+		ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;
+
+		break;
+	}
+	case PACKET3_DRAW_INDIRECT:
+	case PACKET3_DRAW_INDEX_INDIRECT:
+	{
+		u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;
+
+		/*
+		DW 1 HEADER
+		   2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero
+		   3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context
+		*/
+		if (pkt->count != 1) {
+			DRM_ERROR("bad DRAW_INDIRECT\n");
+			return -EINVAL;
+		}
+
+		if (idx_value + size > track->indirect_draw_buffer_size) {
+			dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n",
+				idx_value, size, track->indirect_draw_buffer_size);
+			return -EINVAL;
+		}
+
+		r = evergreen_cs_track_check(p);
+		if (r) {
+			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+			return r;
+		}
+		break;
+	}
 	case PACKET3_DISPATCH_DIRECT:
 		if (pkt->count != 3) {
 			DRM_ERROR("bad DISPATCH_DIRECT\n");
@@ -3243,7 +3313,13 @@
 
 	switch (pkt->opcode) {
 	case PACKET3_NOP:
+		break;
 	case PACKET3_SET_BASE:
+		if (idx_value != 1) {
+			DRM_ERROR("bad SET_BASE");
+			return -EINVAL;
+		}
+		break;
 	case PACKET3_CLEAR_STATE:
 	case PACKET3_INDEX_BUFFER_SIZE:
 	case PACKET3_DISPATCH_DIRECT:
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index 53abd9b..1d9aebc 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -29,17 +29,12 @@
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "evergreend.h"
 #include "atom.h"
 
-extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);
-extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);
-extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
-extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
-					   struct drm_display_mode *mode);
-
 /* enable the audio stream */
-static void dce4_audio_enable(struct radeon_device *rdev,
+void dce4_audio_enable(struct radeon_device *rdev,
 			      struct r600_audio_pin *pin,
 			      u8 enable_mask)
 {
@@ -69,48 +64,42 @@
 	WREG32(AZ_HOT_PLUG_CONTROL, tmp);
 }
 
-/*
- * update the N and CTS parameters for a given pixel clock rate
- */
-static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	uint32_t offset = dig->afmt->offset;
+	int bpc = 8;
 
-	WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz));
-	WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz);
+	if (encoder->crtc) {
+		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+		bpc = radeon_crtc->bpc;
+	}
 
-	WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz));
-	WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz);
+	if (bpc > 8)
+		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
+			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
+	else
+		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
+			HDMI_ACR_SOURCE |		/* select SW CTS value */
+			HDMI_ACR_AUTO_SEND);	/* allow hw to sent ACR packets when required */
 
-	WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz));
-	WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
+	WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz));
+	WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz);
+
+	WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz));
+	WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz);
+
+	WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz));
+	WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz);
 }
 
-static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
-					   struct drm_display_mode *mode)
+void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
+		struct drm_connector *connector, struct drm_display_mode *mode)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
 	u32 tmp = 0;
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
 		if (connector->latency_present[1])
 			tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -124,38 +113,17 @@
 		else
 			tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
 	}
-	WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
+	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
 }
 
-static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
 	u32 tmp;
-	u8 *sadb = NULL;
-	int sad_count;
-
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb);
-	if (sad_count < 0) {
-		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
-		sad_count = 0;
-	}
 
 	/* program the speaker allocation */
-	tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
 	tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
 	/* set HDMI mode */
 	tmp |= HDMI_CONNECTION;
@@ -163,19 +131,32 @@
 		tmp |= SPEAKER_ALLOCATION(sadb[0]);
 	else
 		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-	WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
-
-	kfree(sadb);
+	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
-static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
+void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+	u8 *sadb, int sad_count)
 {
 	struct radeon_device *rdev = encoder->dev->dev_private;
-	struct drm_connector *connector;
-	struct radeon_connector *radeon_connector = NULL;
-	struct cea_sad *sads;
-	int i, sad_count;
+	u32 tmp;
 
+	/* program the speaker allocation */
+	tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+	tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+	/* set DP mode */
+	tmp |= DP_CONNECTION;
+	if (sad_count)
+		tmp |= SPEAKER_ALLOCATION(sadb[0]);
+	else
+		tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+	WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+
+void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
+	struct cea_sad *sads, int sad_count)
+{
+	int i;
+	struct radeon_device *rdev = encoder->dev->dev_private;
 	static const u16 eld_reg_to_type[][2] = {
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -191,25 +172,6 @@
 		{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
 	};
 
-	list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			radeon_connector = to_radeon_connector(connector);
-			break;
-		}
-	}
-
-	if (!radeon_connector) {
-		DRM_ERROR("Couldn't find encoder's connector\n");
-		return;
-	}
-
-	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
-	if (sad_count <= 0) {
-		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
-		return;
-	}
-	BUG_ON(!sads);
-
 	for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
 		u32 value = 0;
 		u8 stereo_freqs = 0;
@@ -236,25 +198,17 @@
 
 		value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
 
-		WREG32(eld_reg_to_type[i][0], value);
+		WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
 	}
-
-	kfree(sads);
 }
 
 /*
- * build a HDMI Video Info Frame
+ * build a AVI Info Frame
  */
-static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
-						void *buffer, size_t size)
+void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
+    unsigned char *buffer, size_t size)
 {
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-	uint8_t *header = buffer;
 
 	WREG32(AFMT_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -263,104 +217,103 @@
 	WREG32(AFMT_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(AFMT_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+		frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
+
+	WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
+		HDMI_AVI_INFO_SEND |	/* enable AVI info frames */
+		HDMI_AVI_INFO_CONT);	/* required for audio info values to be updated */
+
+	WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
+		HDMI_AVI_INFO_LINE(2),	/* anything other than 0 */
+		~HDMI_AVI_INFO_LINE_MASK);
 }
 
-static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock)
 {
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
-	u32 base_rate = 24000;
-	u32 max_ratio = clock / base_rate;
+	unsigned int max_ratio = clock / 24000;
 	u32 dto_phase;
-	u32 dto_modulo = clock;
 	u32 wallclock_ratio;
-	u32 dto_cntl;
+	u32 value;
 
-	if (!dig || !dig->afmt)
-		return;
-
-	if (ASIC_IS_DCE6(rdev)) {
-		dto_phase = 24 * 1000;
+	if (max_ratio >= 8) {
+		dto_phase = 192 * 1000;
+		wallclock_ratio = 3;
+	} else if (max_ratio >= 4) {
+		dto_phase = 96 * 1000;
+		wallclock_ratio = 2;
+	} else if (max_ratio >= 2) {
+		dto_phase = 48 * 1000;
+		wallclock_ratio = 1;
 	} else {
-		if (max_ratio >= 8) {
-			dto_phase = 192 * 1000;
-			wallclock_ratio = 3;
-		} else if (max_ratio >= 4) {
-			dto_phase = 96 * 1000;
-			wallclock_ratio = 2;
-		} else if (max_ratio >= 2) {
-			dto_phase = 48 * 1000;
-			wallclock_ratio = 1;
-		} else {
-			dto_phase = 24 * 1000;
-			wallclock_ratio = 0;
-		}
-		dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
-		dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
-		WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+		dto_phase = 24 * 1000;
+		wallclock_ratio = 0;
 	}
 
-	/* XXX two dtos; generally use dto0 for hdmi */
+	value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+	value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+	value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO;
+	WREG32(DCCG_AUDIO_DTO0_CNTL, value);
+
+	/* Two dtos; generally use dto0 for HDMI */
+	value = 0;
+
+	if (crtc)
+		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
+
+	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
+
 	/* Express [24MHz / target pixel clock] as an exact rational
 	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
 	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
 	 */
-	WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
 	WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
-	WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
+	WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
 }
 
+void dce4_dp_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock)
+{
+	u32 value;
 
-/*
- * update the info frames with the data from the current display mode
- */
-void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+	value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+	value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO;
+	WREG32(DCCG_AUDIO_DTO1_CNTL, value);
+
+	/* Two dtos; generally use dto1 for DP */
+	value = 0;
+	value |= DCCG_AUDIO_DTO_SEL;
+
+	if (crtc)
+		value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
+
+	WREG32(DCCG_AUDIO_DTO_SOURCE, value);
+
+	/* Express [24MHz / target pixel clock] as an exact rational
+	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
+	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+	 */
+	WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+	WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
+}
+
+void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
-	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
-	struct hdmi_avi_infoframe frame;
-	uint32_t offset;
-	ssize_t err;
-	uint32_t val;
-	int bpc = 8;
-
-	if (!dig || !dig->afmt)
-		return;
-
-	/* Silent, r600_hdmi_enable will raise WARN for us */
-	if (!dig->afmt->enabled)
-		return;
-	offset = dig->afmt->offset;
-
-	/* hdmi deep color mode general control packets setup, if bpc > 8 */
-	if (encoder->crtc) {
-		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
-		bpc = radeon_crtc->bpc;
-	}
-
-	/* disable audio prior to setting up hw */
-	if (ASIC_IS_DCE6(rdev)) {
-		dig->afmt->pin = dce6_audio_get_pin(rdev);
-		dce6_audio_enable(rdev, dig->afmt->pin, 0);
-	} else {
-		dig->afmt->pin = r600_audio_get_pin(rdev);
-		dce4_audio_enable(rdev, dig->afmt->pin, 0);
-	}
-
-	evergreen_audio_set_dto(encoder, mode->clock);
 
 	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
-	       HDMI_NULL_SEND); /* send null packets when required */
+		HDMI_NULL_SEND |	/* send null packets when required */
+		HDMI_GC_SEND |		/* send general control packets */
+		HDMI_GC_CONT);		/* send general control packets every frame */
+}
 
-	WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
+void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+	uint32_t val;
 
 	val = RREG32(HDMI_CONTROL + offset);
 	val &= ~HDMI_DEEP_COLOR_ENABLE;
@@ -390,113 +343,59 @@
 	}
 
 	WREG32(HDMI_CONTROL + offset, val);
+}
 
-	WREG32(HDMI_VBI_PACKET_CONTROL + offset,
-	       HDMI_NULL_SEND | /* send null packets when required */
-	       HDMI_GC_SEND | /* send general control packets */
-	       HDMI_GC_CONT); /* send general control packets every frame */
+void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 
 	WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
-	       HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-	       HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+		HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+		HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
 
 	WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
-	       AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+		AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
 
 	WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
-	       HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-	WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
+		HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
 
 	WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
-	       HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
-	       HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-
-	WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
-	       AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
-
-	/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
-
-	if (bpc > 8)
-		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
-		       HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
-	else
-		WREG32(HDMI_ACR_PACKET_CONTROL + offset,
-		       HDMI_ACR_SOURCE | /* select SW CTS value */
-		       HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
-
-	evergreen_hdmi_update_ACR(encoder, mode->clock);
+		HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+		HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
 
 	WREG32(AFMT_60958_0 + offset,
-	       AFMT_60958_CS_CHANNEL_NUMBER_L(1));
+		AFMT_60958_CS_CHANNEL_NUMBER_L(1));
 
 	WREG32(AFMT_60958_1 + offset,
-	       AFMT_60958_CS_CHANNEL_NUMBER_R(2));
+		AFMT_60958_CS_CHANNEL_NUMBER_R(2));
 
 	WREG32(AFMT_60958_2 + offset,
-	       AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
-	       AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
-	       AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
-	       AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
-	       AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
-	       AFMT_60958_CS_CHANNEL_NUMBER_7(8));
-
-	if (ASIC_IS_DCE6(rdev)) {
-		dce6_afmt_write_speaker_allocation(encoder);
-	} else {
-		dce4_afmt_write_speaker_allocation(encoder);
-	}
+		AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
+		AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
+		AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
+		AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
+		AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
+		AFMT_60958_CS_CHANNEL_NUMBER_7(8));
 
 	WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
-	       AFMT_AUDIO_CHANNEL_ENABLE(0xff));
+		AFMT_AUDIO_CHANNEL_ENABLE(0xff));
 
-	/* fglrx sets 0x40 in 0x5f80 here */
+	/* allow 60958 channel status and send audio packets fields to be updated */
+	WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+		AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
+}
 
-	if (ASIC_IS_DCE6(rdev)) {
-		dce6_afmt_select_pin(encoder);
-		dce6_afmt_write_sad_regs(encoder);
-		dce6_afmt_write_latency_fields(encoder, mode);
-	} else {
-		evergreen_hdmi_write_sad_regs(encoder);
-		dce4_afmt_write_latency_fields(encoder, mode);
-	}
 
-	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
-	if (err < 0) {
-		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
-		return;
-	}
+void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 
-	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
-	if (err < 0) {
-		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
-		return;
-	}
-
-	evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
-
-	WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
-		  HDMI_AVI_INFO_SEND | /* enable AVI info frames */
-		  HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
-
-	WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
-		 HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
-		 ~HDMI_AVI_INFO_LINE_MASK);
-
-	WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
-		  AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */
-
-	/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
-	WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
-	WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
-	WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
-	WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
-
-	/* enable audio after to setting up hw */
-	if (ASIC_IS_DCE6(rdev))
-		dce6_audio_enable(rdev, dig->afmt->pin, 1);
+	if (mute)
+		WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE);
 	else
-		dce4_audio_enable(rdev, dig->afmt->pin, 0xf);
+		WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE);
 }
 
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
@@ -516,10 +415,7 @@
 		return;
 
 	if (!enable && dig->afmt->pin) {
-		if (ASIC_IS_DCE6(rdev))
-			dce6_audio_enable(rdev, dig->afmt->pin, 0);
-		else
-			dce4_audio_enable(rdev, dig->afmt->pin, 0);
+		radeon_audio_enable(rdev, dig->afmt->pin, 0);
 		dig->afmt->pin = NULL;
 	}
 
@@ -528,3 +424,57 @@
 	DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
 		  enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
 }
+
+void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	uint32_t offset;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	offset = dig->afmt->offset;
+
+	if (enable) {
+		struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		struct radeon_connector_atom_dig *dig_connector;
+		uint32_t val;
+
+		if (dig->afmt->enabled)
+			return;
+
+		WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+
+		if (radeon_connector->con_priv) {
+			dig_connector = radeon_connector->con_priv;
+			val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
+			val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
+
+			if (dig_connector->dp_clock == 162000)
+				val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3);
+			else
+				val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
+
+			WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
+		}
+
+		WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+			EVERGREEN_DP_SEC_ASP_ENABLE |		/* Audio packet transmission */
+			EVERGREEN_DP_SEC_ATP_ENABLE |		/* Audio timestamp packet transmission */
+			EVERGREEN_DP_SEC_AIP_ENABLE |		/* Audio infoframe packet transmission */
+			EVERGREEN_DP_SEC_STREAM_ENABLE);	/* Master enable for secondary stream engine */
+		radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+	} else {
+		if (!dig->afmt->enabled)
+			return;
+
+		WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
+		radeon_audio_enable(rdev, dig->afmt->pin, 0);
+	}
+
+	dig->afmt->enabled = enable;
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 23bff59..aa939dfe 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -251,4 +251,19 @@
 /* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
 #define EVERGREEN_HDMI_BASE				0x7030
 
+/* Display Port block */
+#define EVERGREEN_DP_SEC_CNTL                           0x7280
+#       define EVERGREEN_DP_SEC_STREAM_ENABLE           (1 << 0)
+#       define EVERGREEN_DP_SEC_ASP_ENABLE              (1 << 4)
+#       define EVERGREEN_DP_SEC_ATP_ENABLE              (1 << 8)
+#       define EVERGREEN_DP_SEC_AIP_ENABLE              (1 << 12)
+#       define EVERGREEN_DP_SEC_GSP_ENABLE              (1 << 20)
+#       define EVERGREEN_DP_SEC_AVI_ENABLE              (1 << 24)
+#       define EVERGREEN_DP_SEC_MPG_ENABLE              (1 << 28)
+#define EVERGREEN_DP_SEC_TIMESTAMP                      0x72a4
+#       define EVERGREEN_DP_SEC_TIMESTAMP_MODE(x)       (((x) & 0x3) << 0)
+#define EVERGREEN_DP_SEC_AUD_N                          0x7294
+#       define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x)      (((x) & 0xf) << 24)
+#       define EVERGREEN_DP_SEC_SS_EN                   (1 << 28)
+
 #endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index b066d67..ee83d2a 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -509,6 +509,7 @@
 #define DCCG_AUDIO_DTO1_MODULE            0x05c4
 #define DCCG_AUDIO_DTO1_LOAD              0x05c8
 #define DCCG_AUDIO_DTO1_CNTL              0x05cc
+#       define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3)
 
 /* DCE 4.0 AFMT */
 #define HDMI_CONTROL                         0x7030
diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c
index e3e9c10..0e236d0 100644
--- a/drivers/gpu/drm/radeon/kv_dpm.c
+++ b/drivers/gpu/drm/radeon/kv_dpm.c
@@ -1169,6 +1169,19 @@
 	}
 }
 
+static void kv_enable_thermal_int(struct radeon_device *rdev, bool enable)
+{
+	u32 thermal_int;
+
+	thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL);
+	if (enable)
+		thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK;
+	else
+		thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK);
+	WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int);
+
+}
+
 int kv_dpm_enable(struct radeon_device *rdev)
 {
 	struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1280,8 +1293,7 @@
 			DRM_ERROR("kv_set_thermal_temperature_range failed\n");
 			return ret;
 		}
-		rdev->irq.dpm_thermal = true;
-		radeon_irq_set(rdev);
+		kv_enable_thermal_int(rdev, true);
 	}
 
 	/* powerdown unused blocks for now */
@@ -1312,6 +1324,7 @@
 	kv_stop_dpm(rdev);
 	kv_enable_ulv(rdev, false);
 	kv_reset_am(rdev);
+	kv_enable_thermal_int(rdev, false);
 
 	kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
 }
@@ -1925,6 +1938,7 @@
 	kv_init_sclk_t(rdev);
 }
 
+#if 0
 void kv_dpm_reset_asic(struct radeon_device *rdev)
 {
 	struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1945,6 +1959,7 @@
 		kv_set_enabled_level(rdev, pi->graphics_boot_level);
 	}
 }
+#endif
 
 //XXX use sumo_dpm_display_configuration_changed
 
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index aea48c8..24242a7 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -27,6 +27,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include <drm/radeon_drm.h>
 #include "nid.h"
 #include "atom.h"
@@ -2097,15 +2098,9 @@
 		return r;
 	}
 
-	if (ASIC_IS_DCE6(rdev)) {
-		r = dce6_audio_init(rdev);
-		if (r)
-			return r;
-	} else {
-		r = r600_audio_init(rdev);
-		if (r)
-			return r;
-	}
+	r = radeon_audio_init(rdev);
+	if (r)
+		return r;
 
 	return 0;
 }
@@ -2140,10 +2135,7 @@
 int cayman_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	if (ASIC_IS_DCE6(rdev))
-		dce6_audio_fini(rdev);
-	else
-		r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	cayman_cp_enable(rdev, false);
 	cayman_dma_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 6d2f16c..7bc9f8d 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -3862,11 +3862,13 @@
 	ni_update_current_ps(rdev, new_ps);
 }
 
+#if 0
 void ni_dpm_reset_asic(struct radeon_device *rdev)
 {
 	ni_restrict_performance_levels_before_switch(rdev);
 	rv770_set_boot_state(rdev);
 }
+#endif
 
 union power_info {
 	struct _ATOM_POWERPLAY_INFO info;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index ef5d606..07a71a2 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -33,6 +33,7 @@
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "radeon_mode.h"
 #include "r600d.h"
 #include "atom.h"
@@ -3054,7 +3055,7 @@
 		return r;
 	}
 
-	r = r600_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r) {
 		DRM_ERROR("radeon: audio init failed\n");
 		return r;
@@ -3105,7 +3106,7 @@
 int r600_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r600_cp_stop(rdev);
 	if (rdev->has_uvd) {
 		uvd_v1_0_fini(rdev);
@@ -3224,7 +3225,7 @@
 void r600_fini(struct radeon_device *rdev)
 {
 	radeon_pm_fini(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r600_cp_fini(rdev);
 	r600_irq_fini(rdev);
 	if (rdev->has_uvd) {
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index b90dc0e..62c91ed 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -29,6 +29,7 @@
 #include <drm/radeon_drm.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "r600d.h"
 #include "atom.h"
 
@@ -55,30 +56,6 @@
 	AUDIO_STATUS_LEVEL        = 0x80
 };
 
-static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
-    /*	     32kHz	  44.1kHz	48kHz    */
-    /* Clock      N     CTS      N     CTS      N     CTS */
-    {  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
-    {  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
-    {  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
-    {  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
-    {  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
-    {  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
-    {  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
-    {  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
-    { 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
-    { 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
-};
-
-
-/*
- * check if the chipset is supported
- */
-static int r600_audio_chipset_supported(struct radeon_device *rdev)
-{
-	return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
-}
-
 static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
 {
 	struct r600_audio_pin status;
@@ -191,155 +168,56 @@
 	WREG32(AZ_HOT_PLUG_CONTROL, tmp);
 }
 
-/*
- * initialize the audio vars
- */
-int r600_audio_init(struct radeon_device *rdev)
-{
-	if (!radeon_audio || !r600_audio_chipset_supported(rdev))
-		return 0;
-
-	rdev->audio.enabled = true;
-
-	rdev->audio.num_pins = 1;
-	rdev->audio.pin[0].channels = -1;
-	rdev->audio.pin[0].rate = -1;
-	rdev->audio.pin[0].bits_per_sample = -1;
-	rdev->audio.pin[0].status_bits = 0;
-	rdev->audio.pin[0].category_code = 0;
-	rdev->audio.pin[0].id = 0;
-	/* disable audio.  it will be set up later */
-	r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
-
-	return 0;
-}
-
-/*
- * release the audio timer
- * TODO: How to do this correctly on SMP systems?
- */
-void r600_audio_fini(struct radeon_device *rdev)
-{
-	if (!rdev->audio.enabled)
-		return;
-
-	r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
-
-	rdev->audio.enabled = false;
-}
-
 struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
 {
 	/* only one pin on 6xx-NI */
 	return &rdev->audio.pin[0];
 }
 
-/*
- * calculate CTS and N values if they are not found in the table
- */
-static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
-{
-	int n, cts;
-	unsigned long div, mul;
-
-	/* Safe, but overly large values */
-	n = 128 * freq;
-	cts = clock * 1000;
-
-	/* Smallest valid fraction */
-	div = gcd(n, cts);
-
-	n /= div;
-	cts /= div;
-
-	/*
-	 * The optimal N is 128*freq/1000. Calculate the closest larger
-	 * value that doesn't truncate any bits.
-	 */
-	mul = ((128*freq/1000) + (n-1))/n;
-
-	n *= mul;
-	cts *= mul;
-
-	/* Check that we are in spec (not always possible) */
-	if (n < (128*freq/1500))
-		printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
-	if (n > (128*freq/300))
-		printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
-
-	*N = n;
-	*CTS = cts;
-
-	DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
-		  *N, *CTS, freq);
-}
-
-struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
-{
-	struct radeon_hdmi_acr res;
-	u8 i;
-
-	/* Precalculated values for common clocks */
-	for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) {
-		if (r600_hdmi_predefined_acr[i].clock == clock)
-			return r600_hdmi_predefined_acr[i];
-	}
-
-	/* And odd clocks get manually calculated */
-	r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
-	r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
-	r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
-
-	return res;
-}
-
-/*
- * update the N and CTS parameters for a given pixel clock rate
- */
-void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	uint32_t offset = dig->afmt->offset;
+
+	/* DCE 3.0 uses register that's normally for CRC_CONTROL */
+	uint32_t acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
+				       HDMI0_ACR_PACKET_CONTROL;
+	WREG32_P(acr_ctl + offset,
+		HDMI0_ACR_SOURCE |		/* select SW CTS value */
+		HDMI0_ACR_AUTO_SEND,	/* allow hw to sent ACR packets when required */
+		~(HDMI0_ACR_SOURCE |
+		HDMI0_ACR_AUTO_SEND));
 
 	WREG32_P(HDMI0_ACR_32_0 + offset,
-		 HDMI0_ACR_CTS_32(acr.cts_32khz),
-		 ~HDMI0_ACR_CTS_32_MASK);
+		HDMI0_ACR_CTS_32(acr->cts_32khz),
+		~HDMI0_ACR_CTS_32_MASK);
 	WREG32_P(HDMI0_ACR_32_1 + offset,
-		 HDMI0_ACR_N_32(acr.n_32khz),
-		 ~HDMI0_ACR_N_32_MASK);
+		HDMI0_ACR_N_32(acr->n_32khz),
+		~HDMI0_ACR_N_32_MASK);
 
 	WREG32_P(HDMI0_ACR_44_0 + offset,
-		 HDMI0_ACR_CTS_44(acr.cts_44_1khz),
-		 ~HDMI0_ACR_CTS_44_MASK);
+		HDMI0_ACR_CTS_44(acr->cts_44_1khz),
+		~HDMI0_ACR_CTS_44_MASK);
 	WREG32_P(HDMI0_ACR_44_1 + offset,
-		 HDMI0_ACR_N_44(acr.n_44_1khz),
-		 ~HDMI0_ACR_N_44_MASK);
+		HDMI0_ACR_N_44(acr->n_44_1khz),
+		~HDMI0_ACR_N_44_MASK);
 
 	WREG32_P(HDMI0_ACR_48_0 + offset,
-		 HDMI0_ACR_CTS_48(acr.cts_48khz),
-		 ~HDMI0_ACR_CTS_48_MASK);
+		HDMI0_ACR_CTS_48(acr->cts_48khz),
+		~HDMI0_ACR_CTS_48_MASK);
 	WREG32_P(HDMI0_ACR_48_1 + offset,
-		 HDMI0_ACR_N_48(acr.n_48khz),
-		 ~HDMI0_ACR_N_48_MASK);
+		HDMI0_ACR_N_48(acr->n_48khz),
+		~HDMI0_ACR_N_48_MASK);
 }
 
 /*
  * build a HDMI Video Info Frame
  */
-void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
-				    size_t size)
+void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
+    unsigned char *buffer, size_t size)
 {
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	uint32_t offset = dig->afmt->offset;
 	uint8_t *frame = buffer + 3;
-	uint8_t *header = buffer;
 
 	WREG32(HDMI0_AVI_INFO0 + offset,
 		frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -348,7 +226,14 @@
 	WREG32(HDMI0_AVI_INFO2 + offset,
 		frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
 	WREG32(HDMI0_AVI_INFO3 + offset,
-		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+		frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
+
+	WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
+		HDMI0_AVI_INFO_SEND |	/* enable AVI info frames */
+		HDMI0_AVI_INFO_CONT);	/* send AVI info frames every frame/field */
+
+	WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
+		HDMI0_AVI_INFO_LINE(2));	/* anything other than 0 */
 }
 
 /*
@@ -425,188 +310,94 @@
 		 value, ~HDMI0_AUDIO_TEST_EN);
 }
 
-void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
+    struct radeon_crtc *crtc, unsigned int clock)
 {
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	u32 base_rate = 24000;
-	u32 max_ratio = clock / base_rate;
-	u32 dto_phase;
-	u32 dto_modulo = clock;
-	u32 wallclock_ratio;
-	u32 dto_cntl;
+	struct radeon_encoder *radeon_encoder;
+	struct radeon_encoder_atom_dig *dig;
 
-	if (!dig || !dig->afmt)
+	if (!crtc)
 		return;
 
-	if (max_ratio >= 8) {
-		dto_phase = 192 * 1000;
-		wallclock_ratio = 3;
-	} else if (max_ratio >= 4) {
-		dto_phase = 96 * 1000;
-		wallclock_ratio = 2;
-	} else if (max_ratio >= 2) {
-		dto_phase = 48 * 1000;
-		wallclock_ratio = 1;
-	} else {
-		dto_phase = 24 * 1000;
-		wallclock_ratio = 0;
-	}
+	radeon_encoder = to_radeon_encoder(crtc->encoder);
+	dig = radeon_encoder->enc_priv;
 
-	/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
-	 * doesn't matter which one you use.  Just use the first one.
-	 */
-	/* XXX two dtos; generally use dto0 for hdmi */
-	/* Express [24MHz / target pixel clock] as an exact rational
-	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
-	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
-	 */
-	if (ASIC_IS_DCE32(rdev)) {
-		if (dig->dig_encoder == 0) {
-			dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
-			dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
-			WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
-			WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
-			WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
-			WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
-		} else {
-			dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
-			dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
-			WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
-			WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
-			WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
-			WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
-		}
+	if (!dig)
+		return;
+
+	if (dig->dig_encoder == 0) {
+		WREG32(DCCG_AUDIO_DTO0_PHASE, 24000 * 100);
+		WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
+		WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
 	} else {
-		/* according to the reg specs, this should DCE3.2 only, but in
-		 * practice it seems to cover DCE2.0/3.0/3.1 as well.
-		 */
-		if (dig->dig_encoder == 0) {
-			WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
-			WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
-			WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
-		} else {
-			WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100);
-			WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
-			WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
-		}
+		WREG32(DCCG_AUDIO_DTO1_PHASE, 24000 * 100);
+		WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
+		WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
 	}
 }
 
-/*
- * update the info frames with the data from the current display mode
- */
-void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
-	struct hdmi_avi_infoframe frame;
-	uint32_t offset;
-	uint32_t acr_ctl;
-	ssize_t err;
-
-	if (!dig || !dig->afmt)
-		return;
-
-	/* Silent, r600_hdmi_enable will raise WARN for us */
-	if (!dig->afmt->enabled)
-		return;
-	offset = dig->afmt->offset;
-
-	/* disable audio prior to setting up hw */
-	dig->afmt->pin = r600_audio_get_pin(rdev);
-	r600_audio_enable(rdev, dig->afmt->pin, 0xf);
-
-	r600_audio_set_dto(encoder, mode->clock);
-
-	WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
-		 HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
-		 HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
-		 HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
-		 HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
-		 ~(HDMI0_AUDIO_SAMPLE_SEND |
-		   HDMI0_AUDIO_DELAY_EN_MASK |
-		   HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
-		   HDMI0_60958_CS_UPDATE));
-
-	/* DCE 3.0 uses register that's normally for CRC_CONTROL */
-	acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
-				       HDMI0_ACR_PACKET_CONTROL;
-	WREG32_P(acr_ctl + offset,
-		 HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
-		 HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
-		 ~(HDMI0_ACR_SOURCE |
-		   HDMI0_ACR_AUTO_SEND));
 
 	WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
-		  HDMI0_NULL_SEND | /* send null packets when required */
-		  HDMI0_GC_SEND | /* send general control packets */
-		  HDMI0_GC_CONT); /* send general control packets every frame */
+		HDMI0_NULL_SEND |	/* send null packets when required */
+		HDMI0_GC_SEND |		/* send general control packets */
+		HDMI0_GC_CONT);		/* send general control packets every frame */
+}
+
+void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+
+	WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
+		HDMI0_AUDIO_SAMPLE_SEND |			/* send audio packets */
+		HDMI0_AUDIO_DELAY_EN(1) |			/* default audio delay */
+		HDMI0_AUDIO_PACKETS_PER_LINE(3) |	/* should be suffient for all audio modes and small enough for all hblanks */
+		HDMI0_60958_CS_UPDATE,				/* allow 60958 channel status fields to be updated */
+		~(HDMI0_AUDIO_SAMPLE_SEND |
+		HDMI0_AUDIO_DELAY_EN_MASK |
+		HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
+		HDMI0_60958_CS_UPDATE));
 
 	WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
-		  HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
-		  HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
-		  HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-		  HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+		HDMI0_AUDIO_INFO_SEND |		/* enable audio info frames (frames won't be set until audio is enabled) */
+		HDMI0_AUDIO_INFO_UPDATE);	/* required for audio info values to be updated */
 
 	WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
-		 HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
-		 HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
-		 ~(HDMI0_AVI_INFO_LINE_MASK |
-		   HDMI0_AUDIO_INFO_LINE_MASK));
-
-	WREG32_AND(HDMI0_GC + offset,
-		   ~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */
-
-	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
-	if (err < 0) {
-		DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
-		return;
-	}
-
-	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
-	if (err < 0) {
-		DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
-		return;
-	}
-
-	r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
-
-	/* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */
+		HDMI0_AUDIO_INFO_LINE(2),	/* anything other than 0 */
+		~HDMI0_AUDIO_INFO_LINE_MASK);
 
 	WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset,
-		   ~(HDMI0_GENERIC0_SEND |
-		     HDMI0_GENERIC0_CONT |
-		     HDMI0_GENERIC0_UPDATE |
-		     HDMI0_GENERIC1_SEND |
-		     HDMI0_GENERIC1_CONT |
-		     HDMI0_GENERIC0_LINE_MASK |
-		     HDMI0_GENERIC1_LINE_MASK));
-
-	r600_hdmi_update_ACR(encoder, mode->clock);
+		~(HDMI0_GENERIC0_SEND |
+		HDMI0_GENERIC0_CONT |
+		HDMI0_GENERIC0_UPDATE |
+		HDMI0_GENERIC1_SEND |
+		HDMI0_GENERIC1_CONT |
+		HDMI0_GENERIC0_LINE_MASK |
+		HDMI0_GENERIC1_LINE_MASK));
 
 	WREG32_P(HDMI0_60958_0 + offset,
-		 HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
-		 ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
-		   HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
+		HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
+		~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
+		HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
 
 	WREG32_P(HDMI0_60958_1 + offset,
-		 HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
-		 ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
+		HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
+		~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
+}
 
-	/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
-	WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
-	WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
-	WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
-	WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
+void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
 
-	/* enable audio after to setting up hw */
-	r600_audio_enable(rdev, dig->afmt->pin, 0xf);
+	if (mute)
+		WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
+	else
+		WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
 }
 
 /**
@@ -692,7 +483,7 @@
 		return;
 
 	if (!enable && dig->afmt->pin) {
-		r600_audio_enable(rdev, dig->afmt->pin, 0);
+		radeon_audio_enable(rdev, dig->afmt->pin, 0);
 		dig->afmt->pin = NULL;
 	}
 
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3f2a8d3..5587603 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1758,6 +1758,9 @@
 	bool enabled;
 	struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS];
 	int num_pins;
+	struct radeon_audio_funcs *hdmi_funcs;
+	struct radeon_audio_funcs *dp_funcs;
+	struct radeon_audio_basic_funcs *funcs;
 };
 
 /*
@@ -1778,8 +1781,16 @@
 /*
  * MMU Notifier
  */
+#if defined(CONFIG_MMU_NOTIFIER)
 int radeon_mn_register(struct radeon_bo *bo, unsigned long addr);
 void radeon_mn_unregister(struct radeon_bo *bo);
+#else
+static inline int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
+{
+	return -ENODEV;
+}
+static inline void radeon_mn_unregister(struct radeon_bo *bo) {}
+#endif
 
 /*
  * Debugfs
@@ -1969,6 +1980,10 @@
 		bool (*vblank_too_short)(struct radeon_device *rdev);
 		void (*powergate_uvd)(struct radeon_device *rdev, bool gate);
 		void (*enable_bapm)(struct radeon_device *rdev, bool enable);
+		void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode);
+		u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
+		int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
+		int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
 	} dpm;
 	/* pageflipping */
 	struct {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index ed0e10e..c0ecd12 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -647,8 +647,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &r600_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r100_copy_blit,
@@ -716,8 +714,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &r600_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r100_copy_blit,
@@ -948,8 +944,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &r600_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1035,8 +1029,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &r600_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1127,8 +1119,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &r600_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1232,8 +1222,6 @@
 		.wait_for_vblank = &avivo_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &r600_hdmi_enable,
-		.hdmi_setmode = &dce3_1_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1351,8 +1339,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1444,8 +1430,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1536,8 +1520,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1683,8 +1665,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1787,8 +1767,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1921,8 +1899,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &r600_copy_cpdma,
@@ -1975,6 +1951,10 @@
 		.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
 		.force_performance_level = &si_dpm_force_performance_level,
 		.vblank_too_short = &ni_dpm_vblank_too_short,
+		.fan_ctrl_set_mode = &si_fan_ctrl_set_mode,
+		.fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
+		.get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
+		.set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
 	},
 	.pflip = {
 		.page_flip = &evergreen_page_flip,
@@ -2085,8 +2065,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &cik_copy_cpdma,
@@ -2141,6 +2119,10 @@
 		.force_performance_level = &ci_dpm_force_performance_level,
 		.vblank_too_short = &ci_dpm_vblank_too_short,
 		.powergate_uvd = &ci_dpm_powergate_uvd,
+		.fan_ctrl_set_mode = &ci_fan_ctrl_set_mode,
+		.fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
+		.get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
+		.set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
 	},
 	.pflip = {
 		.page_flip = &evergreen_page_flip,
@@ -2193,8 +2175,6 @@
 		.wait_for_vblank = &dce4_wait_for_vblank,
 		.set_backlight_level = &atombios_set_backlight_level,
 		.get_backlight_level = &atombios_get_backlight_level,
-		.hdmi_enable = &evergreen_hdmi_enable,
-		.hdmi_setmode = &evergreen_hdmi_setmode,
 	},
 	.copy = {
 		.blit = &cik_copy_cpdma,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8d787d1..72bdd3b 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -394,7 +394,6 @@
 void r600_disable_interrupts(struct radeon_device *rdev);
 void r600_rlc_stop(struct radeon_device *rdev);
 /* r600 audio */
-int r600_audio_init(struct radeon_device *rdev);
 void r600_audio_fini(struct radeon_device *rdev);
 void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
 void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
@@ -403,8 +402,6 @@
 void r600_hdmi_audio_workaround(struct drm_encoder *encoder);
 int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
 void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
-void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
@@ -473,8 +470,6 @@
 u32 rv770_get_xclk(struct radeon_device *rdev);
 int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int rv770_get_temp(struct radeon_device *rdev);
-/* hdmi */
-void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 /* rv7xx pm */
 int rv770_dpm_init(struct radeon_device *rdev);
 int rv770_dpm_enable(struct radeon_device *rdev);
@@ -544,8 +539,6 @@
 					uint64_t src_offset, uint64_t dst_offset,
 					unsigned num_gpu_pages,
 					struct reservation_object *resv);
-void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
 int evergreen_get_temp(struct radeon_device *rdev);
 int sumo_get_temp(struct radeon_device *rdev);
 int tn_get_temp(struct radeon_device *rdev);
@@ -684,7 +677,6 @@
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
-int dce6_audio_init(struct radeon_device *rdev);
 void dce6_audio_fini(struct radeon_device *rdev);
 
 /*
@@ -748,6 +740,12 @@
 						    struct seq_file *m);
 int si_dpm_force_performance_level(struct radeon_device *rdev,
 				   enum radeon_dpm_forced_level level);
+int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+						 u32 *speed);
+int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+						 u32 speed);
+u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
+void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
@@ -865,6 +863,13 @@
 bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
 void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+						 u32 *speed);
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+						 u32 speed);
+u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev);
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+
 int kv_dpm_init(struct radeon_device *rdev);
 int kv_dpm_enable(struct radeon_device *rdev);
 int kv_dpm_late_enable(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index dbc94f3..fc1b3f3 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -3289,6 +3289,7 @@
 
 	args.in.ucVoltageType = VOLTAGE_TYPE_VDDC;
 	args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
+	args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id);
 	args.in.ulSCLKFreq =
 		cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk);
 
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c
new file mode 100644
index 0000000..a3ceef6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_audio.c
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2014 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.
+ *
+ * Authors: Slava Grigorev <slava.grigorev@amd.com>
+ */
+
+#include <linux/gcd.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include "radeon.h"
+#include "atom.h"
+#include "radeon_audio.h"
+
+void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+		u8 enable_mask);
+void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+		u8 enable_mask);
+void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+		u8 enable_mask);
+u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg);
+void dce6_endpoint_wreg(struct radeon_device *rdev,
+		u32 offset, u32 reg, u32 v);
+void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
+		struct cea_sad *sads, int sad_count);
+void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
+		struct cea_sad *sads, int sad_count);
+void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
+		struct cea_sad *sads, int sad_count);
+void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
+		struct drm_connector *connector, struct drm_display_mode *mode);
+void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
+		struct drm_connector *connector, struct drm_display_mode *mode);
+struct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
+struct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
+void dce6_afmt_select_pin(struct drm_encoder *encoder);
+void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void dce3_2_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void dce4_dp_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void dce6_dp_audio_set_dto(struct radeon_device *rdev,
+	struct radeon_crtc *crtc, unsigned int clock);
+void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
+	unsigned char *buffer, size_t size);
+void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
+	unsigned char *buffer, size_t size);
+void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr);
+void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr);
+void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+	const struct radeon_hdmi_acr *acr);
+void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_hdmi_set_color_depth(struct drm_encoder *encoder,
+	u32 offset, int bpc);
+void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode);
+static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode);
+void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
+void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
+void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+
+static const u32 pin_offsets[7] =
+{
+	(0x5e00 - 0x5e00),
+	(0x5e18 - 0x5e00),
+	(0x5e30 - 0x5e00),
+	(0x5e48 - 0x5e00),
+	(0x5e60 - 0x5e00),
+	(0x5e78 - 0x5e00),
+	(0x5e90 - 0x5e00),
+};
+
+static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+	return RREG32(reg);
+}
+
+static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
+		u32 reg, u32 v)
+{
+	WREG32(reg, v);
+}
+
+static struct radeon_audio_basic_funcs r600_funcs = {
+	.endpoint_rreg = radeon_audio_rreg,
+	.endpoint_wreg = radeon_audio_wreg,
+	.enable = r600_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce32_funcs = {
+	.endpoint_rreg = radeon_audio_rreg,
+	.endpoint_wreg = radeon_audio_wreg,
+	.enable = r600_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce4_funcs = {
+	.endpoint_rreg = radeon_audio_rreg,
+	.endpoint_wreg = radeon_audio_wreg,
+	.enable = dce4_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce6_funcs = {
+	.endpoint_rreg = dce6_endpoint_rreg,
+	.endpoint_wreg = dce6_endpoint_wreg,
+	.enable = dce6_audio_enable,
+};
+
+static struct radeon_audio_funcs r600_hdmi_funcs = {
+	.get_pin = r600_audio_get_pin,
+	.set_dto = r600_hdmi_audio_set_dto,
+	.update_acr = r600_hdmi_update_acr,
+	.set_vbi_packet = r600_set_vbi_packet,
+	.set_avi_packet = r600_set_avi_packet,
+	.set_audio_packet = r600_set_audio_packet,
+	.set_mute = r600_set_mute,
+	.mode_set = radeon_audio_hdmi_mode_set,
+	.dpms = r600_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce32_hdmi_funcs = {
+	.get_pin = r600_audio_get_pin,
+	.write_sad_regs = dce3_2_afmt_write_sad_regs,
+	.write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
+	.set_dto = dce3_2_audio_set_dto,
+	.update_acr = dce3_2_hdmi_update_acr,
+	.set_vbi_packet = r600_set_vbi_packet,
+	.set_avi_packet = r600_set_avi_packet,
+	.set_audio_packet = dce3_2_set_audio_packet,
+	.set_mute = dce3_2_set_mute,
+	.mode_set = radeon_audio_hdmi_mode_set,
+	.dpms = r600_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce32_dp_funcs = {
+	.get_pin = r600_audio_get_pin,
+	.write_sad_regs = dce3_2_afmt_write_sad_regs,
+	.write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
+	.set_dto = dce3_2_audio_set_dto,
+	.set_avi_packet = r600_set_avi_packet,
+	.set_audio_packet = dce3_2_set_audio_packet,
+};
+
+static struct radeon_audio_funcs dce4_hdmi_funcs = {
+	.get_pin = r600_audio_get_pin,
+	.write_sad_regs = evergreen_hdmi_write_sad_regs,
+	.write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
+	.write_latency_fields = dce4_afmt_write_latency_fields,
+	.set_dto = dce4_hdmi_audio_set_dto,
+	.update_acr = evergreen_hdmi_update_acr,
+	.set_vbi_packet = dce4_set_vbi_packet,
+	.set_color_depth = dce4_hdmi_set_color_depth,
+	.set_avi_packet = evergreen_set_avi_packet,
+	.set_audio_packet = dce4_set_audio_packet,
+	.set_mute = dce4_set_mute,
+	.mode_set = radeon_audio_hdmi_mode_set,
+	.dpms = evergreen_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce4_dp_funcs = {
+	.get_pin = r600_audio_get_pin,
+	.write_sad_regs = evergreen_hdmi_write_sad_regs,
+	.write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
+	.write_latency_fields = dce4_afmt_write_latency_fields,
+	.set_dto = dce4_dp_audio_set_dto,
+	.set_avi_packet = evergreen_set_avi_packet,
+	.set_audio_packet = dce4_set_audio_packet,
+	.mode_set = radeon_audio_dp_mode_set,
+	.dpms = evergreen_enable_dp_audio_packets,
+};
+
+static struct radeon_audio_funcs dce6_hdmi_funcs = {
+	.select_pin = dce6_afmt_select_pin,
+	.get_pin = dce6_audio_get_pin,
+	.write_sad_regs = dce6_afmt_write_sad_regs,
+	.write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
+	.write_latency_fields = dce6_afmt_write_latency_fields,
+	.set_dto = dce6_hdmi_audio_set_dto,
+	.update_acr = evergreen_hdmi_update_acr,
+	.set_vbi_packet = dce4_set_vbi_packet,
+	.set_color_depth = dce4_hdmi_set_color_depth,
+	.set_avi_packet = evergreen_set_avi_packet,
+	.set_audio_packet = dce4_set_audio_packet,
+	.set_mute = dce4_set_mute,
+	.mode_set = radeon_audio_hdmi_mode_set,
+	.dpms = evergreen_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce6_dp_funcs = {
+	.select_pin = dce6_afmt_select_pin,
+	.get_pin = dce6_audio_get_pin,
+	.write_sad_regs = dce6_afmt_write_sad_regs,
+	.write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
+	.write_latency_fields = dce6_afmt_write_latency_fields,
+	.set_dto = dce6_dp_audio_set_dto,
+	.set_avi_packet = evergreen_set_avi_packet,
+	.set_audio_packet = dce4_set_audio_packet,
+	.mode_set = radeon_audio_dp_mode_set,
+	.dpms = dce6_enable_dp_audio_packets,
+};
+
+static void radeon_audio_interface_init(struct radeon_device *rdev)
+{
+	if (ASIC_IS_DCE6(rdev)) {
+		rdev->audio.funcs = &dce6_funcs;
+		rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
+		rdev->audio.dp_funcs = &dce6_dp_funcs;
+	} else if (ASIC_IS_DCE4(rdev)) {
+		rdev->audio.funcs = &dce4_funcs;
+		rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
+		rdev->audio.dp_funcs = &dce4_dp_funcs;
+	} else if (ASIC_IS_DCE32(rdev)) {
+		rdev->audio.funcs = &dce32_funcs;
+		rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
+		rdev->audio.dp_funcs = &dce32_dp_funcs;
+	} else {
+		rdev->audio.funcs = &r600_funcs;
+		rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
+		rdev->audio.dp_funcs = 0;
+	}
+}
+
+static int radeon_audio_chipset_supported(struct radeon_device *rdev)
+{
+	return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
+}
+
+int radeon_audio_init(struct radeon_device *rdev)
+{
+	int i;
+
+	if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
+		return 0;
+
+	rdev->audio.enabled = true;
+
+	if (ASIC_IS_DCE83(rdev))		/* KB: 2 streams, 3 endpoints */
+		rdev->audio.num_pins = 3;
+	else if (ASIC_IS_DCE81(rdev))	/* KV: 4 streams, 7 endpoints */
+		rdev->audio.num_pins = 7;
+	else if (ASIC_IS_DCE8(rdev))	/* BN/HW: 6 streams, 7 endpoints */
+		rdev->audio.num_pins = 7;
+	else if (ASIC_IS_DCE64(rdev))	/* OL: 2 streams, 2 endpoints */
+		rdev->audio.num_pins = 2;
+	else if (ASIC_IS_DCE61(rdev))	/* TN: 4 streams, 6 endpoints */
+		rdev->audio.num_pins = 6;
+	else if (ASIC_IS_DCE6(rdev))	/* SI: 6 streams, 6 endpoints */
+		rdev->audio.num_pins = 6;
+	else
+		rdev->audio.num_pins = 1;
+
+	for (i = 0; i < rdev->audio.num_pins; i++) {
+		rdev->audio.pin[i].channels = -1;
+		rdev->audio.pin[i].rate = -1;
+		rdev->audio.pin[i].bits_per_sample = -1;
+		rdev->audio.pin[i].status_bits = 0;
+		rdev->audio.pin[i].category_code = 0;
+		rdev->audio.pin[i].connected = false;
+		rdev->audio.pin[i].offset = pin_offsets[i];
+		rdev->audio.pin[i].id = i;
+	}
+
+	radeon_audio_interface_init(rdev);
+
+	/* disable audio.  it will be set up later */
+	for (i = 0; i < rdev->audio.num_pins; i++)
+		radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
+
+	return 0;
+}
+
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+	if (rdev->audio.funcs->endpoint_rreg)
+		return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
+
+	return 0;
+}
+
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
+	u32 reg, u32 v)
+{
+	if (rdev->audio.funcs->endpoint_wreg)
+		rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
+}
+
+static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder;
+	struct drm_connector *connector;
+	struct radeon_connector *radeon_connector = NULL;
+	struct cea_sad *sads;
+	int sad_count;
+
+	list_for_each_entry(connector,
+		&encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			radeon_connector = to_radeon_connector(connector);
+			break;
+		}
+	}
+
+	if (!radeon_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
+	if (sad_count <= 0) {
+		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
+		return;
+	}
+	BUG_ON(!sads);
+
+	radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
+		radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
+
+	kfree(sads);
+}
+
+static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_connector *connector;
+	struct radeon_connector *radeon_connector = NULL;
+	u8 *sadb = NULL;
+	int sad_count;
+
+	list_for_each_entry(connector,
+			    &encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			radeon_connector = to_radeon_connector(connector);
+			break;
+		}
+	}
+
+	if (!radeon_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	sad_count = drm_edid_to_speaker_allocation(
+		radeon_connector_edid(connector), &sadb);
+	if (sad_count < 0) {
+		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
+			  sad_count);
+		sad_count = 0;
+	}
+
+	if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
+		radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
+
+	kfree(sadb);
+}
+
+static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
+	struct drm_display_mode *mode)
+{
+	struct radeon_encoder *radeon_encoder;
+	struct drm_connector *connector;
+	struct radeon_connector *radeon_connector = 0;
+
+	list_for_each_entry(connector,
+		&encoder->dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder) {
+			radeon_connector = to_radeon_connector(connector);
+			break;
+		}
+	}
+
+	if (!radeon_connector) {
+		DRM_ERROR("Couldn't find encoder's connector\n");
+		return;
+	}
+
+	radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
+		radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
+}
+
+struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
+		return radeon_encoder->audio->get_pin(rdev);
+
+	return NULL;
+}
+
+static void radeon_audio_select_pin(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
+		radeon_encoder->audio->select_pin(encoder);
+}
+
+void radeon_audio_enable(struct radeon_device *rdev,
+	struct r600_audio_pin *pin, u8 enable_mask)
+{
+	if (rdev->audio.funcs->enable)
+		rdev->audio.funcs->enable(rdev, pin, enable_mask);
+}
+
+void radeon_audio_detect(struct drm_connector *connector,
+	enum drm_connector_status status)
+{
+	struct radeon_device *rdev;
+	struct radeon_encoder *radeon_encoder;
+	struct radeon_encoder_atom_dig *dig;
+
+	if (!connector || !connector->encoder)
+		return;
+
+	rdev = connector->encoder->dev->dev_private;
+	radeon_encoder = to_radeon_encoder(connector->encoder);
+	dig = radeon_encoder->enc_priv;
+
+	if (status == connector_status_connected) {
+		struct radeon_connector *radeon_connector;
+		int sink_type;
+
+		if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+			radeon_encoder->audio = NULL;
+			return;
+		}
+
+		radeon_connector = to_radeon_connector(connector);
+		sink_type = radeon_dp_getsinktype(radeon_connector);
+
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort &&
+			sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+			radeon_encoder->audio = rdev->audio.dp_funcs;
+		else
+			radeon_encoder->audio = rdev->audio.hdmi_funcs;
+
+		radeon_audio_write_speaker_allocation(connector->encoder);
+		radeon_audio_write_sad_regs(connector->encoder);
+		if (connector->encoder->crtc)
+			radeon_audio_write_latency_fields(connector->encoder,
+				&connector->encoder->crtc->mode);
+		radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+	} else {
+		radeon_audio_enable(rdev, dig->afmt->pin, 0);
+	}
+}
+
+void radeon_audio_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	if (!rdev->audio.enabled)
+		return;
+
+	for (i = 0; i < rdev->audio.num_pins; i++)
+		radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
+
+	rdev->audio.enabled = false;
+}
+
+static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
+		radeon_encoder->audio->set_dto(rdev, crtc, clock);
+}
+
+static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
+	struct drm_display_mode *mode)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+	struct hdmi_avi_infoframe frame;
+	int err;
+
+	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+	if (err < 0) {
+		DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
+		return err;
+	}
+
+	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
+	if (err < 0) {
+		DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
+		return err;
+	}
+
+	if (dig && dig->afmt &&
+		radeon_encoder->audio && radeon_encoder->audio->set_avi_packet)
+		radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
+			buffer, sizeof(buffer));
+
+	return 0;
+}
+
+/*
+ * calculate CTS and N values if they are not found in the table
+ */
+static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
+{
+	int n, cts;
+	unsigned long div, mul;
+
+	/* Safe, but overly large values */
+	n = 128 * freq;
+	cts = clock * 1000;
+
+	/* Smallest valid fraction */
+	div = gcd(n, cts);
+
+	n /= div;
+	cts /= div;
+
+	/*
+	 * The optimal N is 128*freq/1000. Calculate the closest larger
+	 * value that doesn't truncate any bits.
+	 */
+	mul = ((128*freq/1000) + (n-1))/n;
+
+	n *= mul;
+	cts *= mul;
+
+	/* Check that we are in spec (not always possible) */
+	if (n < (128*freq/1500))
+		printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
+	if (n > (128*freq/300))
+		printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
+
+	*N = n;
+	*CTS = cts;
+
+	DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
+		*N, *CTS, freq);
+}
+
+static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
+{
+	static struct radeon_hdmi_acr res;
+	u8 i;
+
+	static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
+		/*       32kHz    44.1kHz   48kHz    */
+		/* Clock      N     CTS      N     CTS      N     CTS */
+		{  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
+		{  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
+		{  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
+		{  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
+		{  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
+		{  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
+		{  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
+		{  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
+		{ 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
+		{ 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
+	};
+
+	/* Precalculated values for common clocks */
+	for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
+		if (hdmi_predefined_acr[i].clock == clock)
+			return &hdmi_predefined_acr[i];
+
+	/* And odd clocks get manually calculated */
+	radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
+	radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
+	radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
+
+	return &res;
+}
+
+/*
+ * update the N and CTS parameters for a given pixel clock rate
+ */
+static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
+{
+	const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
+		radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
+}
+
+static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
+		radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
+}
+
+static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
+{
+	int bpc = 8;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	if (encoder->crtc) {
+		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+		bpc = radeon_crtc->bpc;
+	}
+
+	if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
+		radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
+}
+
+static void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
+		radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
+}
+
+static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
+		radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
+}
+
+/*
+ * update the info frames with the data from the current display mode
+ */
+static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode)
+{
+	struct radeon_device *rdev = encoder->dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	/* disable audio prior to setting up hw */
+	dig->afmt->pin = radeon_audio_get_pin(encoder);
+	radeon_audio_enable(rdev, dig->afmt->pin, 0);
+
+	radeon_audio_set_dto(encoder, mode->clock);
+	radeon_audio_set_vbi_packet(encoder);
+	radeon_hdmi_set_color_depth(encoder);
+	radeon_audio_set_mute(encoder, false);
+	radeon_audio_update_acr(encoder, mode->clock);
+	radeon_audio_set_audio_packet(encoder);
+	radeon_audio_select_pin(encoder);
+
+	if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+		return;
+
+	/* enable audio after to setting up hw */
+	radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+}
+
+static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+	if (!dig || !dig->afmt)
+		return;
+
+	/* disable audio prior to setting up hw */
+	dig->afmt->pin = radeon_audio_get_pin(encoder);
+	radeon_audio_enable(rdev, dig->afmt->pin, 0);
+
+	radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+	radeon_audio_set_audio_packet(encoder);
+	radeon_audio_select_pin(encoder);
+
+	if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+		return;
+
+	/* enable audio after to setting up hw */
+	radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+}
+
+void radeon_audio_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
+		radeon_encoder->audio->mode_set(encoder, mode);
+}
+
+void radeon_audio_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+	if (radeon_encoder->audio && radeon_encoder->audio->dpms)
+		radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h
new file mode 100644
index 0000000..c92d059
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_audio.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 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.
+ *
+ * Authors: Slava Grigorev <slava.grigorev@amd.com>
+ */
+
+#ifndef __RADEON_AUDIO_H__
+#define __RADEON_AUDIO_H__
+
+#include <linux/types.h>
+
+#define RREG32_ENDPOINT(block, reg)		\
+	radeon_audio_endpoint_rreg(rdev, (block), (reg))
+#define WREG32_ENDPOINT(block, reg, v)	\
+	radeon_audio_endpoint_wreg(rdev, (block), (reg), (v))
+
+struct radeon_audio_basic_funcs
+{
+	u32  (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg);
+	void (*endpoint_wreg)(struct radeon_device *rdev,
+		u32 offset, u32 reg, u32 v);
+	void (*enable)(struct radeon_device *rdev,
+		struct r600_audio_pin *pin, u8 enable_mask);
+};
+
+struct radeon_audio_funcs
+{
+	void (*select_pin)(struct drm_encoder *encoder);
+	struct r600_audio_pin* (*get_pin)(struct radeon_device *rdev);
+	void (*write_latency_fields)(struct drm_encoder *encoder,
+		struct drm_connector *connector, struct drm_display_mode *mode);
+	void (*write_sad_regs)(struct drm_encoder *encoder,
+		struct cea_sad *sads, int sad_count);
+	void (*write_speaker_allocation)(struct drm_encoder *encoder,
+		u8 *sadb, int sad_count);
+	void (*set_dto)(struct radeon_device *rdev,
+		struct radeon_crtc *crtc, unsigned int clock);
+	void (*update_acr)(struct drm_encoder *encoder, long offset,
+		const struct radeon_hdmi_acr *acr);
+	void (*set_vbi_packet)(struct drm_encoder *encoder, u32 offset);
+	void (*set_color_depth)(struct drm_encoder *encoder, u32 offset, int bpc);
+	void (*set_avi_packet)(struct radeon_device *rdev, u32 offset,
+		unsigned char *buffer, size_t size);
+	void (*set_audio_packet)(struct drm_encoder *encoder, u32 offset);
+	void (*set_mute)(struct drm_encoder *encoder, u32 offset, bool mute);
+	void (*mode_set)(struct drm_encoder *encoder,
+		struct drm_display_mode *mode);
+	void (*dpms)(struct drm_encoder *encoder, bool mode);
+};
+
+int radeon_audio_init(struct radeon_device *rdev);
+void radeon_audio_detect(struct drm_connector *connector,
+	enum drm_connector_status status);
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
+	u32 offset, u32 reg);
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
+	u32 offset,	u32 reg, u32 v);
+struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder);
+void radeon_audio_enable(struct radeon_device *rdev,
+	struct r600_audio_pin *pin, u8 enable_mask);
+void radeon_audio_fini(struct radeon_device *rdev);
+void radeon_audio_mode_set(struct drm_encoder *encoder,
+	struct drm_display_mode *mode);
+void radeon_audio_dpms(struct drm_encoder *encoder, int mode);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 26baa9c..27def67 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -29,6 +29,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
+#include "radeon_audio.h"
 #include "atom.h"
 
 #include <linux/pm_runtime.h>
@@ -1332,6 +1333,9 @@
 	/* updated in get modes as well since we need to know if it's analog or digital */
 	radeon_connector_update_scratch_regs(connector, ret);
 
+	if (radeon_audio != 0)
+		radeon_audio_detect(connector, ret);
+
 exit:
 	pm_runtime_mark_last_busy(connector->dev->dev);
 	pm_runtime_put_autosuspend(connector->dev->dev);
@@ -1654,6 +1658,10 @@
 	}
 
 	radeon_connector_update_scratch_regs(connector, ret);
+
+	if (radeon_audio != 0)
+		radeon_audio_detect(connector, ret);
+
 out:
 	pm_runtime_mark_last_busy(connector->dev->dev);
 	pm_runtime_put_autosuspend(connector->dev->dev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 4f50fb0..5d684be 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -88,9 +88,10 @@
  *   2.39.0 - Add INFO query for number of active CUs
  *   2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
  *            CS to GPU on >= r600
+ *   2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	40
+#define KMS_DRIVER_MINOR	41
 #define KMS_DRIVER_PATCHLEVEL	0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 29b9220..ea276ff 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -390,18 +390,27 @@
 	ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
 				 rdev->num_crtc,
 				 RADEONFB_CONN_LIMIT);
-	if (ret) {
-		kfree(rfbdev);
-		return ret;
-	}
+	if (ret)
+		goto free;
 
-	drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
+	ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(rdev->ddev);
 
-	drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+	ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&rfbdev->helper);
+free:
+	kfree(rfbdev);
+	return ret;
 }
 
 void radeon_fbdev_fini(struct radeon_device *rdev)
@@ -419,16 +428,6 @@
 	fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
 }
 
-int radeon_fbdev_total_size(struct radeon_device *rdev)
-{
-	struct radeon_bo *robj;
-	int size = 0;
-
-	robj = gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj);
-	size += radeon_bo_size(robj);
-	return size;
-}
-
 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
 {
 	if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj))
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index add6220..9590bcd 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -1048,11 +1048,6 @@
 	return NULL;
 }
 
-struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
-{
-	return NULL;
-}
-
 void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
 			 u8 slave_addr,
 			 u8 addr,
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c
index bef9a09..061eaa9 100644
--- a/drivers/gpu/drm/radeon/radeon_kfd.c
+++ b/drivers/gpu/drm/radeon/radeon_kfd.c
@@ -30,22 +30,22 @@
 #include "radeon_kfd.h"
 #include "radeon_ucode.h"
 #include <linux/firmware.h>
+#include "cik_structs.h"
 
 #define CIK_PIPE_PER_MEC	(4)
 
 struct kgd_mem {
-	struct radeon_sa_bo *sa_bo;
+	struct radeon_bo *bo;
 	uint64_t gpu_addr;
-	void *ptr;
+	void *cpu_ptr;
 };
 
-static int init_sa_manager(struct kgd_dev *kgd, unsigned int size);
-static void fini_sa_manager(struct kgd_dev *kgd);
 
-static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
-		enum kgd_memory_pool pool, struct kgd_mem **mem);
+static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+			void **mem_obj, uint64_t *gpu_addr,
+			void **cpu_ptr);
 
-static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem);
+static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
 
 static uint64_t get_vmem_size(struct kgd_dev *kgd);
 static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
@@ -64,36 +64,37 @@
 static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
 					unsigned int vmid);
 
-static int kgd_init_memory(struct kgd_dev *kgd);
-
 static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
 				uint32_t hpd_size, uint64_t hpd_gpu_addr);
 
 static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
 			uint32_t queue_id, uint32_t __user *wptr);
-
+static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd);
 static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
 				uint32_t pipe_id, uint32_t queue_id);
 
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
 				unsigned int timeout, uint32_t pipe_id,
 				uint32_t queue_id);
+static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
+static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
+				unsigned int timeout);
 
 static const struct kfd2kgd_calls kfd2kgd = {
-	.init_sa_manager = init_sa_manager,
-	.fini_sa_manager = fini_sa_manager,
-	.allocate_mem = allocate_mem,
-	.free_mem = free_mem,
+	.init_gtt_mem_allocation = alloc_gtt_mem,
+	.free_gtt_mem = free_gtt_mem,
 	.get_vmem_size = get_vmem_size,
 	.get_gpu_clock_counter = get_gpu_clock_counter,
 	.get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
 	.program_sh_mem_settings = kgd_program_sh_mem_settings,
 	.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
-	.init_memory = kgd_init_memory,
 	.init_pipeline = kgd_init_pipeline,
 	.hqd_load = kgd_hqd_load,
+	.hqd_sdma_load = kgd_hqd_sdma_load,
 	.hqd_is_occupied = kgd_hqd_is_occupied,
+	.hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
 	.hqd_destroy = kgd_hqd_destroy,
+	.hqd_sdma_destroy = kgd_hqd_sdma_destroy,
 	.get_fw_version = get_fw_version
 };
 
@@ -194,87 +195,78 @@
 	return r;
 }
 
-static u32 pool_to_domain(enum kgd_memory_pool p)
-{
-	switch (p) {
-	case KGD_POOL_FRAMEBUFFER: return RADEON_GEM_DOMAIN_VRAM;
-	default: return RADEON_GEM_DOMAIN_GTT;
-	}
-}
-
-static int init_sa_manager(struct kgd_dev *kgd, unsigned int size)
+static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+			void **mem_obj, uint64_t *gpu_addr,
+			void **cpu_ptr)
 {
 	struct radeon_device *rdev = (struct radeon_device *)kgd;
+	struct kgd_mem **mem = (struct kgd_mem **) mem_obj;
 	int r;
 
 	BUG_ON(kgd == NULL);
-
-	r = radeon_sa_bo_manager_init(rdev, &rdev->kfd_bo,
-				      size,
-				      RADEON_GPU_PAGE_SIZE,
-				      RADEON_GEM_DOMAIN_GTT,
-				      RADEON_GEM_GTT_WC);
-
-	if (r)
-		return r;
-
-	r = radeon_sa_bo_manager_start(rdev, &rdev->kfd_bo);
-	if (r)
-		radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
-
-	return r;
-}
-
-static void fini_sa_manager(struct kgd_dev *kgd)
-{
-	struct radeon_device *rdev = (struct radeon_device *)kgd;
-
-	BUG_ON(kgd == NULL);
-
-	radeon_sa_bo_manager_suspend(rdev, &rdev->kfd_bo);
-	radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
-}
-
-static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
-		enum kgd_memory_pool pool, struct kgd_mem **mem)
-{
-	struct radeon_device *rdev = (struct radeon_device *)kgd;
-	u32 domain;
-	int r;
-
-	BUG_ON(kgd == NULL);
-
-	domain = pool_to_domain(pool);
-	if (domain != RADEON_GEM_DOMAIN_GTT) {
-		dev_err(rdev->dev,
-			"Only allowed to allocate gart memory for kfd\n");
-		return -EINVAL;
-	}
+	BUG_ON(gpu_addr == NULL);
+	BUG_ON(cpu_ptr == NULL);
 
 	*mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
 	if ((*mem) == NULL)
 		return -ENOMEM;
 
-	r = radeon_sa_bo_new(rdev, &rdev->kfd_bo, &(*mem)->sa_bo, size,
-				alignment);
+	r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+				RADEON_GEM_GTT_WC, NULL, NULL, &(*mem)->bo);
 	if (r) {
-		dev_err(rdev->dev, "failed to get memory for kfd (%d)\n", r);
+		dev_err(rdev->dev,
+			"failed to allocate BO for amdkfd (%d)\n", r);
 		return r;
 	}
 
-	(*mem)->ptr = radeon_sa_bo_cpu_addr((*mem)->sa_bo);
-	(*mem)->gpu_addr = radeon_sa_bo_gpu_addr((*mem)->sa_bo);
+	/* map the buffer */
+	r = radeon_bo_reserve((*mem)->bo, true);
+	if (r) {
+		dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r);
+		goto allocate_mem_reserve_bo_failed;
+	}
+
+	r = radeon_bo_pin((*mem)->bo, RADEON_GEM_DOMAIN_GTT,
+				&(*mem)->gpu_addr);
+	if (r) {
+		dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r);
+		goto allocate_mem_pin_bo_failed;
+	}
+	*gpu_addr = (*mem)->gpu_addr;
+
+	r = radeon_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr);
+	if (r) {
+		dev_err(rdev->dev,
+			"(%d) failed to map bo to kernel for amdkfd\n", r);
+		goto allocate_mem_kmap_bo_failed;
+	}
+	*cpu_ptr = (*mem)->cpu_ptr;
+
+	radeon_bo_unreserve((*mem)->bo);
 
 	return 0;
+
+allocate_mem_kmap_bo_failed:
+	radeon_bo_unpin((*mem)->bo);
+allocate_mem_pin_bo_failed:
+	radeon_bo_unreserve((*mem)->bo);
+allocate_mem_reserve_bo_failed:
+	radeon_bo_unref(&(*mem)->bo);
+
+	return r;
 }
 
-static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem)
+static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
 {
-	struct radeon_device *rdev = (struct radeon_device *)kgd;
+	struct kgd_mem *mem = (struct kgd_mem *) mem_obj;
 
-	BUG_ON(kgd == NULL);
+	BUG_ON(mem == NULL);
 
-	radeon_sa_bo_free(rdev, &mem->sa_bo, NULL);
+	radeon_bo_reserve(mem->bo, true);
+	radeon_bo_kunmap(mem->bo);
+	radeon_bo_unpin(mem->bo);
+	radeon_bo_unreserve(mem->bo);
+	radeon_bo_unref(&(mem->bo));
 	kfree(mem);
 }
 
@@ -397,42 +389,6 @@
 	return 0;
 }
 
-static int kgd_init_memory(struct kgd_dev *kgd)
-{
-	/*
-	 * Configure apertures:
-	 * LDS:         0x60000000'00000000 - 0x60000001'00000000 (4GB)
-	 * Scratch:     0x60000001'00000000 - 0x60000002'00000000 (4GB)
-	 * GPUVM:       0x60010000'00000000 - 0x60020000'00000000 (1TB)
-	 */
-	int i;
-	uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000);
-
-	for (i = 8; i < 16; i++) {
-		uint32_t sh_mem_config;
-
-		lock_srbm(kgd, 0, 0, 0, i);
-
-		sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
-		sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
-
-		write_register(kgd, SH_MEM_CONFIG, sh_mem_config);
-
-		write_register(kgd, SH_MEM_BASES, sh_mem_bases);
-
-		/* Scratch aperture is not supported for now. */
-		write_register(kgd, SH_STATIC_MEM_CONFIG, 0);
-
-		/* APE1 disabled for now. */
-		write_register(kgd, SH_MEM_APE1_BASE, 1);
-		write_register(kgd, SH_MEM_APE1_LIMIT, 0);
-
-		unlock_srbm(kgd);
-	}
-
-	return 0;
-}
-
 static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
 				uint32_t hpd_size, uint64_t hpd_gpu_addr)
 {
@@ -451,11 +407,28 @@
 	return 0;
 }
 
+static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m)
+{
+	uint32_t retval;
+
+	retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET +
+			m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET;
+
+	pr_debug("kfd: sdma base address: 0x%x\n", retval);
+
+	return retval;
+}
+
 static inline struct cik_mqd *get_mqd(void *mqd)
 {
 	return (struct cik_mqd *)mqd;
 }
 
+static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
+{
+	return (struct cik_sdma_rlc_registers *)mqd;
+}
+
 static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
 			uint32_t queue_id, uint32_t __user *wptr)
 {
@@ -533,6 +506,45 @@
 	return 0;
 }
 
+static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd)
+{
+	struct cik_sdma_rlc_registers *m;
+	uint32_t sdma_base_addr;
+
+	m = get_sdma_mqd(mqd);
+	sdma_base_addr = get_sdma_base_addr(m);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_VIRTUAL_ADDR,
+			m->sdma_rlc_virtual_addr);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_RB_BASE,
+			m->sdma_rlc_rb_base);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_RB_BASE_HI,
+			m->sdma_rlc_rb_base_hi);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_LO,
+			m->sdma_rlc_rb_rptr_addr_lo);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_HI,
+			m->sdma_rlc_rb_rptr_addr_hi);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_DOORBELL,
+			m->sdma_rlc_doorbell);
+
+	write_register(kgd,
+			sdma_base_addr + SDMA0_RLC0_RB_CNTL,
+			m->sdma_rlc_rb_cntl);
+
+	return 0;
+}
+
 static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
 				uint32_t pipe_id, uint32_t queue_id)
 {
@@ -554,6 +566,24 @@
 	return retval;
 }
 
+static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
+{
+	struct cik_sdma_rlc_registers *m;
+	uint32_t sdma_base_addr;
+	uint32_t sdma_rlc_rb_cntl;
+
+	m = get_sdma_mqd(mqd);
+	sdma_base_addr = get_sdma_base_addr(m);
+
+	sdma_rlc_rb_cntl = read_register(kgd,
+					sdma_base_addr + SDMA0_RLC0_RB_CNTL);
+
+	if (sdma_rlc_rb_cntl & SDMA_RB_ENABLE)
+		return true;
+
+	return false;
+}
+
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
 				unsigned int timeout, uint32_t pipe_id,
 				uint32_t queue_id)
@@ -583,6 +613,39 @@
 	return 0;
 }
 
+static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
+				unsigned int timeout)
+{
+	struct cik_sdma_rlc_registers *m;
+	uint32_t sdma_base_addr;
+	uint32_t temp;
+
+	m = get_sdma_mqd(mqd);
+	sdma_base_addr = get_sdma_base_addr(m);
+
+	temp = read_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL);
+	temp = temp & ~SDMA_RB_ENABLE;
+	write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL, temp);
+
+	while (true) {
+		temp = read_register(kgd, sdma_base_addr +
+						SDMA0_RLC0_CONTEXT_STATUS);
+		if (temp & SDMA_RLC_IDLE)
+			break;
+		if (timeout == 0)
+			return -ETIME;
+		msleep(20);
+		timeout -= 20;
+	}
+
+	write_register(kgd, sdma_base_addr + SDMA0_RLC0_DOORBELL, 0);
+	write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_RPTR, 0);
+	write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_WPTR, 0);
+	write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_BASE, 0);
+
+	return 0;
+}
+
 static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type)
 {
 	struct radeon_device *rdev = (struct radeon_device *) kgd;
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.h b/drivers/gpu/drm/radeon/radeon_kfd.h
index f90e161..1103f90 100644
--- a/drivers/gpu/drm/radeon/radeon_kfd.h
+++ b/drivers/gpu/drm/radeon/radeon_kfd.h
@@ -29,7 +29,7 @@
 #define RADEON_KFD_H_INCLUDED
 
 #include <linux/types.h>
-#include "../amd/include/kgd_kfd_interface.h"
+#include "kgd_kfd_interface.h"
 
 struct radeon_device;
 
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 390db89..920a8be 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -449,6 +449,7 @@
 	int audio_polling_active;
 	bool is_ext_encoder;
 	u16 caps;
+	struct radeon_audio_funcs *audio;
 };
 
 struct radeon_connector_atom_dig {
@@ -745,8 +746,6 @@
 extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
 extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
 
-extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
-
 extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
 					     struct radeon_atom_ss *ss,
 					     int id);
@@ -925,7 +924,6 @@
 int radeon_fbdev_init(struct radeon_device *rdev);
 void radeon_fbdev_fini(struct radeon_device *rdev);
 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
-int radeon_fbdev_total_size(struct radeon_device *rdev);
 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
 
 void radeon_fb_output_poll_changed(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 86fc564..43e0994 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -238,6 +238,18 @@
 	 * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
 	 */
 	bo->flags &= ~RADEON_GEM_GTT_WC;
+#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
+	/* Don't try to enable write-combining when it can't work, or things
+	 * may be slow
+	 * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
+	 */
+
+#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
+	 thanks to write-combining
+
+	DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
+		      "better performance thanks to write-combining\n");
+	bo->flags &= ~RADEON_GEM_GTT_WC;
 #endif
 
 	radeon_ttm_placement_from_domain(bo, domain);
@@ -576,12 +588,6 @@
 	return 0;
 }
 
-int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
-			     struct vm_area_struct *vma)
-{
-	return ttm_fbdev_mmap(vma, &bo->tbo);
-}
-
 int radeon_bo_get_surface_reg(struct radeon_bo *bo)
 {
 	struct radeon_device *rdev = bo->rdev;
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 3b0b377..d8d295e 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -143,8 +143,6 @@
 extern int radeon_bo_list_validate(struct radeon_device *rdev,
 				   struct ww_acquire_ctx *ticket,
 				   struct list_head *head, int ring);
-extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
-				struct vm_area_struct *vma);
 extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
 				u32 tiling_flags, u32 pitch);
 extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index f7da8fe..9f758d3 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -24,6 +24,7 @@
 #include "radeon.h"
 #include "avivod.h"
 #include "atom.h"
+#include "r600_dpm.h"
 #include <linux/power_supply.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
@@ -554,6 +555,100 @@
 	return count;
 }
 
+static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	u32 pwm_mode = 0;
+
+	if (rdev->asic->dpm.fan_ctrl_get_mode)
+		pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
+
+	/* never 0 (full-speed), fuse or smc-controlled always */
+	return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
+}
+
+static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf,
+					    size_t count)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	int value;
+
+	if(!rdev->asic->dpm.fan_ctrl_set_mode)
+		return -EINVAL;
+
+	err = kstrtoint(buf, 10, &value);
+	if (err)
+		return err;
+
+	switch (value) {
+	case 1: /* manual, percent-based */
+		rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
+		break;
+	default: /* disable */
+		rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
+		break;
+	}
+
+	return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return sprintf(buf, "%i\n", 0);
+}
+
+static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	return sprintf(buf, "%i\n", 255);
+}
+
+static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	u32 value;
+
+	err = kstrtou32(buf, 10, &value);
+	if (err)
+		return err;
+
+	value = (value * 100) / 255;
+
+	err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
+	if (err)
+		return err;
+
+	return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct radeon_device *rdev = dev_get_drvdata(dev);
+	int err;
+	u32 speed;
+
+	err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
+	if (err)
+		return err;
+
+	speed = (speed * 255) / 100;
+
+	return sprintf(buf, "%i\n", speed);
+}
+
 static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
 static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
 static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
@@ -601,11 +696,20 @@
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
+
 
 static struct attribute *hwmon_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_temp1_crit.dev_attr.attr,
 	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_min.dev_attr.attr,
+	&sensor_dev_attr_pwm1_max.dev_attr.attr,
 	NULL
 };
 
@@ -614,6 +718,7 @@
 {
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct radeon_device *rdev = dev_get_drvdata(dev);
+	umode_t effective_mode = attr->mode;
 
 	/* Skip limit attributes if DPM is not enabled */
 	if (rdev->pm.pm_method != PM_METHOD_DPM &&
@@ -621,7 +726,35 @@
 	     attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
 		return 0;
 
-	return attr->mode;
+	/* Skip fan attributes if fan is not present */
+	if (rdev->pm.no_fan &&
+	    (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+	     attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+	     attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+		return 0;
+
+	/* mask fan attributes if we have no bindings for this asic to expose */
+	if ((!rdev->asic->dpm.get_fan_speed_percent &&
+	     attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
+	    (!rdev->asic->dpm.fan_ctrl_get_mode &&
+	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
+		effective_mode &= ~S_IRUGO;
+
+	if ((!rdev->asic->dpm.set_fan_speed_percent &&
+	     attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
+	    (!rdev->asic->dpm.fan_ctrl_set_mode &&
+	     attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
+		effective_mode &= ~S_IWUSR;
+
+	/* hide max/min values if we can't both query and manage the fan */
+	if ((!rdev->asic->dpm.set_fan_speed_percent &&
+	     !rdev->asic->dpm.get_fan_speed_percent) &&
+	    (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+	     attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+		return 0;
+
+	return effective_mode;
 }
 
 static const struct attribute_group hwmon_attrgroup = {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 74bce91..d81182a 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -38,6 +38,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "atom.h"
 #include "rs600d.h"
 
@@ -1016,7 +1017,7 @@
 		return r;
 	}
 
-	r = r600_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing audio\n");
 		return r;
@@ -1057,7 +1058,7 @@
 int rs600_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r100_cp_disable(rdev);
 	radeon_wb_disable(rdev);
 	rs600_irq_disable(rdev);
@@ -1068,7 +1069,7 @@
 void rs600_fini(struct radeon_device *rdev)
 {
 	radeon_pm_fini(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r100_cp_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 0a2d36e..516ca27 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -28,6 +28,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include "atom.h"
 #include "rs690d.h"
 
@@ -729,7 +730,7 @@
 		return r;
 	}
 
-	r = r600_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failed initializing audio\n");
 		return r;
@@ -770,7 +771,7 @@
 int rs690_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r100_cp_disable(rdev);
 	radeon_wb_disable(rdev);
 	rs600_irq_disable(rdev);
@@ -781,7 +782,7 @@
 void rs690_fini(struct radeon_device *rdev)
 {
 	radeon_pm_fini(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	r100_cp_fini(rdev);
 	radeon_wb_fini(rdev);
 	radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 372016e..01ee96a 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -30,6 +30,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include <drm/radeon_drm.h>
 #include "rv770d.h"
 #include "atom.h"
@@ -1788,7 +1789,7 @@
 		return r;
 	}
 
-	r = r600_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r) {
 		DRM_ERROR("radeon: audio init failed\n");
 		return r;
@@ -1829,7 +1830,7 @@
 int rv770_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	r600_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	uvd_v1_0_fini(rdev);
 	radeon_uvd_suspend(rdev);
 	r700_cp_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 755a8f9..3067326 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -231,6 +231,7 @@
 		MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
 }
 
+#if 0
 int rv770_read_smc_soft_register(struct radeon_device *rdev,
 				 u16 reg_offset, u32 *value)
 {
@@ -240,6 +241,7 @@
 					 pi->soft_regs_start + reg_offset,
 					 value, pi->sram_end);
 }
+#endif
 
 int rv770_write_smc_soft_register(struct radeon_device *rdev,
 				  u16 reg_offset, u32 value)
@@ -2075,6 +2077,7 @@
 	return 0;
 }
 
+#if 0
 void rv770_dpm_reset_asic(struct radeon_device *rdev)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -2087,6 +2090,7 @@
 	if (pi->dcodt)
 		rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
 }
+#endif
 
 void rv770_dpm_setup_asic(struct radeon_device *rdev)
 {
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index f776634..d12beab 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -278,8 +278,6 @@
 void rv770_get_engine_memory_ss(struct radeon_device *rdev);
 
 /* smc */
-int rv770_read_smc_soft_register(struct radeon_device *rdev,
-				 u16 reg_offset, u32 *value);
 int rv770_write_smc_soft_register(struct radeon_device *rdev,
 				  u16 reg_offset, u32 value);
 
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 5d89b87..73107fe 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -27,6 +27,7 @@
 #include <drm/drmP.h>
 #include "radeon.h"
 #include "radeon_asic.h"
+#include "radeon_audio.h"
 #include <drm/radeon_drm.h>
 #include "sid.h"
 #include "atom.h"
@@ -6869,7 +6870,7 @@
 		return r;
 	}
 
-	r = dce6_audio_init(rdev);
+	r = radeon_audio_init(rdev);
 	if (r)
 		return r;
 
@@ -6908,7 +6909,7 @@
 int si_suspend(struct radeon_device *rdev)
 {
 	radeon_pm_suspend(rdev);
-	dce6_audio_fini(rdev);
+	radeon_audio_fini(rdev);
 	radeon_vm_manager_fini(rdev);
 	si_cp_enable(rdev, false);
 	cayman_dma_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index eff8a64..7be1165 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -1756,6 +1756,9 @@
 				    u32 engine_clock,
 				    SISLANDS_SMC_SCLK_VALUE *sclk);
 
+static void si_thermal_start_smc_fan_control(struct radeon_device *rdev);
+static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev);
+
 static struct si_power_info *si_get_pi(struct radeon_device *rdev)
 {
         struct si_power_info *pi = rdev->pm.dpm.priv;
@@ -3359,11 +3362,13 @@
 	return 0;
 }
 
+#if 0
 static int si_set_boot_state(struct radeon_device *rdev)
 {
 	return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
 		0 : -EINVAL;
 }
+#endif
 
 static int si_set_sw_state(struct radeon_device *rdev)
 {
@@ -5973,6 +5978,10 @@
 	slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
 	slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
 
+	fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
+	fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
+	fan_table.temp_max = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
+
 	fan_table.slope1 = cpu_to_be16(slope1);
 	fan_table.slope2 = cpu_to_be16(slope2);
 
@@ -6012,29 +6021,35 @@
 
 static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
 {
+	struct si_power_info *si_pi = si_get_pi(rdev);
 	PPSMC_Result ret;
 
 	ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl);
-	if (ret == PPSMC_Result_OK)
+	if (ret == PPSMC_Result_OK) {
+		si_pi->fan_is_controlled_by_smc = true;
 		return 0;
-	else
+	} else {
 		return -EINVAL;
+	}
 }
 
 static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
 {
+	struct si_power_info *si_pi = si_get_pi(rdev);
 	PPSMC_Result ret;
 
 	ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl);
-	if (ret == PPSMC_Result_OK)
+
+	if (ret == PPSMC_Result_OK) {
+		si_pi->fan_is_controlled_by_smc = false;
 		return 0;
-	else
+	} else {
 		return -EINVAL;
+	}
 }
 
-#if 0
-static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
-					     u32 *speed)
+int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+				      u32 *speed)
 {
 	u32 duty, duty100;
 	u64 tmp64;
@@ -6058,9 +6073,10 @@
 	return 0;
 }
 
-static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
-					     u32 speed)
+int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+				      u32 speed)
 {
+	struct si_power_info *si_pi = si_get_pi(rdev);
 	u32 tmp;
 	u32 duty, duty100;
 	u64 tmp64;
@@ -6068,11 +6084,11 @@
 	if (rdev->pm.no_fan)
 		return -ENOENT;
 
-	if (speed > 100)
+	if (si_pi->fan_is_controlled_by_smc)
 		return -EINVAL;
 
-	if (rdev->pm.dpm.fan.ucode_fan_control)
-		si_fan_ctrl_stop_smc_fan_control(rdev);
+	if (speed > 100)
+		return -EINVAL;
 
 	duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
 
@@ -6087,11 +6103,38 @@
 	tmp |= FDO_STATIC_DUTY(duty);
 	WREG32(CG_FDO_CTRL0, tmp);
 
-	si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
-
 	return 0;
 }
 
+void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
+{
+	if (mode) {
+		/* stop auto-manage */
+		if (rdev->pm.dpm.fan.ucode_fan_control)
+			si_fan_ctrl_stop_smc_fan_control(rdev);
+		si_fan_ctrl_set_static_mode(rdev, mode);
+	} else {
+		/* restart auto-manage */
+		if (rdev->pm.dpm.fan.ucode_fan_control)
+			si_thermal_start_smc_fan_control(rdev);
+		else
+			si_fan_ctrl_set_default_mode(rdev);
+	}
+}
+
+u32 si_fan_ctrl_get_mode(struct radeon_device *rdev)
+{
+	struct si_power_info *si_pi = si_get_pi(rdev);
+	u32 tmp;
+
+	if (si_pi->fan_is_controlled_by_smc)
+		return 0;
+
+	tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+	return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
 static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
 					 u32 *speed)
 {
@@ -6538,13 +6581,14 @@
 	ni_update_current_ps(rdev, new_ps);
 }
 
-
+#if 0
 void si_dpm_reset_asic(struct radeon_device *rdev)
 {
 	si_restrict_performance_levels_before_switch(rdev);
 	si_disable_ulv(rdev);
 	si_set_boot_state(rdev);
 }
+#endif
 
 void si_dpm_display_configuration_changed(struct radeon_device *rdev)
 {
@@ -6912,7 +6956,6 @@
 			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
 
 	si_pi->fan_ctrl_is_in_default_mode = true;
-	rdev->pm.dpm.fan.ucode_fan_control = false;
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/si_dpm.h b/drivers/gpu/drm/radeon/si_dpm.h
index d16bb1b..1032a68 100644
--- a/drivers/gpu/drm/radeon/si_dpm.h
+++ b/drivers/gpu/drm/radeon/si_dpm.h
@@ -202,6 +202,7 @@
 	bool fan_ctrl_is_in_default_mode;
 	u32 t_min;
 	u32 fan_ctrl_default_mode;
+	bool fan_is_controlled_by_smc;
 };
 
 #define SISLANDS_INITIAL_STATE_ARB_INDEX    0
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 8499924..cbd91d2 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -901,6 +901,16 @@
 /* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
 #define CRTC_STATUS_FRAME_COUNT                         0x6e98
 
+/* Audio clocks */
+#define DCCG_AUDIO_DTO_SOURCE                           0x05ac
+#       define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
+#       define DCCG_AUDIO_DTO_SEL            (1 << 4)   /* 0=dto0 1=dto1 */
+
+#define DCCG_AUDIO_DTO0_PHASE                           0x05b0
+#define DCCG_AUDIO_DTO0_MODULE                          0x05b4
+#define DCCG_AUDIO_DTO1_PHASE                           0x05b8
+#define DCCG_AUDIO_DTO1_MODULE                          0x05bc
+
 #define AFMT_AUDIO_SRC_CONTROL                          0x713c
 #define		AFMT_AUDIO_SRC_SELECT(x)		(((x) & 7) << 0)
 /* AFMT_AUDIO_SRC_SELECT
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 1f8a883..25fd4ce 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1338,6 +1338,7 @@
 	sumo_update_current_ps(rdev, new_ps);
 }
 
+#if 0
 void sumo_dpm_reset_asic(struct radeon_device *rdev)
 {
 	sumo_program_bootup_state(rdev);
@@ -1349,6 +1350,7 @@
 	sumo_set_forced_mode_enabled(rdev);
 	sumo_set_forced_mode_disabled(rdev);
 }
+#endif
 
 void sumo_dpm_setup_asic(struct radeon_device *rdev)
 {
@@ -1537,6 +1539,7 @@
 	return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
 }
 
+#if 0
 u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
 			      struct sumo_vid_mapping_table *vid_mapping_table,
 			      u32 vid_7bit)
@@ -1550,6 +1553,7 @@
 
 	return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit;
 }
+#endif
 
 static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
 					       u32 vid_2bit)
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index db1ea32..07dda29 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -202,9 +202,6 @@
 u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
 			      struct sumo_vid_mapping_table *vid_mapping_table,
 			      u32 vid_2bit);
-u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
-			      struct sumo_vid_mapping_table *vid_mapping_table,
-			      u32 vid_7bit);
 u32 sumo_get_sleep_divider_from_id(u32 id);
 u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
 					 u32 sclk,
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index b4ec5c4..38dacb7 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -1269,6 +1269,7 @@
 	trinity_release_mutex(rdev);
 }
 
+#if 0
 void trinity_dpm_reset_asic(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1284,6 +1285,7 @@
 	}
 	trinity_release_mutex(rdev);
 }
+#endif
 
 static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
 						  u32 vid_2bit)
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 2324a52..11485a4 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -1,6 +1,6 @@
 config DRM_RCAR_DU
 	tristate "DRM Support for R-Car Display Unit"
-	depends on DRM && ARM
+	depends on DRM && ARM && HAVE_DMA_ATTRS
 	depends on ARCH_SHMOBILE || COMPILE_TEST
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 23cc910..25c7a99 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -74,39 +74,77 @@
 	if (ret < 0)
 		return ret;
 
+	ret = clk_prepare_enable(rcrtc->extclock);
+	if (ret < 0)
+		goto error_clock;
+
 	ret = rcar_du_group_get(rcrtc->group);
 	if (ret < 0)
-		clk_disable_unprepare(rcrtc->clock);
+		goto error_group;
 
+	return 0;
+
+error_group:
+	clk_disable_unprepare(rcrtc->extclock);
+error_clock:
+	clk_disable_unprepare(rcrtc->clock);
 	return ret;
 }
 
 static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
 {
 	rcar_du_group_put(rcrtc->group);
+
+	clk_disable_unprepare(rcrtc->extclock);
 	clk_disable_unprepare(rcrtc->clock);
 }
 
 static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 {
 	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+	unsigned long mode_clock = mode->clock * 1000;
 	unsigned long clk;
 	u32 value;
+	u32 escr;
 	u32 div;
 
-	/* Dot clock */
+	/* Compute the clock divisor and select the internal or external dot
+	 * clock based on the requested frequency.
+	 */
 	clk = clk_get_rate(rcrtc->clock);
-	div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
+	div = DIV_ROUND_CLOSEST(clk, mode_clock);
 	div = clamp(div, 1U, 64U) - 1;
+	escr = div | ESCR_DCLKSEL_CLKS;
+
+	if (rcrtc->extclock) {
+		unsigned long extclk;
+		unsigned long extrate;
+		unsigned long rate;
+		u32 extdiv;
+
+		extclk = clk_get_rate(rcrtc->extclock);
+		extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
+		extdiv = clamp(extdiv, 1U, 64U) - 1;
+
+		rate = clk / (div + 1);
+		extrate = extclk / (extdiv + 1);
+
+		if (abs((long)extrate - (long)mode_clock) <
+		    abs((long)rate - (long)mode_clock)) {
+			dev_dbg(rcrtc->group->dev->dev,
+				"crtc%u: using external clock\n", rcrtc->index);
+			escr = extdiv | ESCR_DCLKSEL_DCLKIN;
+		}
+	}
 
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
-			    ESCR_DCLKSEL_CLKS | div);
+			    escr);
 	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
 
 	/* Signal polarities */
 	value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
 	      | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
-	      | DSMR_DIPM_DE;
+	      | DSMR_DIPM_DE | DSMR_CSPM;
 	rcar_du_crtc_write(rcrtc, DSMR, value);
 
 	/* Display timings */
@@ -117,12 +155,15 @@
 					mode->hsync_start - 1);
 	rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
 
-	rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
-	rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
-					mode->vdisplay - 2);
-	rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
-					mode->vsync_start - 1);
-	rcar_du_crtc_write(rcrtc, VCR,  mode->vtotal - 1);
+	rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal -
+					mode->crtc_vsync_end - 2);
+	rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
+					mode->crtc_vsync_end +
+					mode->crtc_vdisplay - 2);
+	rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal -
+					mode->crtc_vsync_end +
+					mode->crtc_vsync_start - 1);
+	rcar_du_crtc_write(rcrtc, VCR,  mode->crtc_vtotal - 1);
 
 	rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
 	rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
@@ -139,9 +180,10 @@
 	 */
 	rcrtc->outputs |= BIT(output);
 
-	/* Store RGB routing to DPAD0 for R8A7790. */
-	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) &&
-	    output == RCAR_DU_OUTPUT_DPAD0)
+	/* Store RGB routing to DPAD0, the hardware will be configured when
+	 * starting the CRTC.
+	 */
+	if (output == RCAR_DU_OUTPUT_DPAD0)
 		rcdu->dpad0_source = rcrtc->index;
 }
 
@@ -217,6 +259,7 @@
 static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 {
 	struct drm_crtc *crtc = &rcrtc->crtc;
+	bool interlaced;
 	unsigned int i;
 
 	if (rcrtc->started)
@@ -252,7 +295,10 @@
 	 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
 	 * actively driven).
 	 */
-	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
+	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+	rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
+			     (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
+			     DSYSR_TVM_MASTER);
 
 	rcar_du_group_start_stop(rcrtc->group, true);
 
@@ -308,6 +354,9 @@
 {
 	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
 	if (rcrtc->dpms == mode)
 		return;
 
@@ -486,7 +535,7 @@
 	status = rcar_du_crtc_read(rcrtc, DSSR);
 	rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-	if (status & DSSR_VBK) {
+	if (status & DSSR_FRM) {
 		drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
 		rcar_du_crtc_finish_page_flip(rcrtc);
 		ret = IRQ_HANDLED;
@@ -542,12 +591,13 @@
 	struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
 	struct drm_crtc *crtc = &rcrtc->crtc;
 	unsigned int irqflags;
-	char clk_name[5];
+	struct clk *clk;
+	char clk_name[9];
 	char *name;
 	int irq;
 	int ret;
 
-	/* Get the CRTC clock. */
+	/* Get the CRTC clock and the optional external clock. */
 	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
 		sprintf(clk_name, "du.%u", index);
 		name = clk_name;
@@ -561,6 +611,15 @@
 		return PTR_ERR(rcrtc->clock);
 	}
 
+	sprintf(clk_name, "dclkin.%u", index);
+	clk = devm_clk_get(rcdu->dev, clk_name);
+	if (!IS_ERR(clk)) {
+		rcrtc->extclock = clk;
+	} else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
+		dev_info(rcdu->dev, "can't get external clock %u\n", index);
+		return -EPROBE_DEFER;
+	}
+
 	rcrtc->group = rgrp;
 	rcrtc->mmio_offset = mmio_offsets[index];
 	rcrtc->index = index;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 984e608..d2f89f7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -26,6 +26,7 @@
 	struct drm_crtc crtc;
 
 	struct clk *clock;
+	struct clk *extclock;
 	unsigned int mmio_offset;
 	unsigned int index;
 	bool started;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 7bfa09c..e0d74f8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -56,7 +56,8 @@
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
-	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
 	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
 	.num_crtcs = 3,
 	.routes = {
@@ -83,7 +84,8 @@
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
-	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
 	.num_crtcs = 2,
 	.routes = {
 		/* R8A7791 has one RGB output, one LVDS output and one
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 0a72466..c5b9ea6 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -27,7 +27,7 @@
 struct rcar_du_lvdsenc;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK	(1 << 0)	/* Per-CRTC IRQ and clock */
-#define RCAR_DU_FEATURE_DEFR8		(1 << 1)	/* Has DEFR8 register */
+#define RCAR_DU_FEATURE_EXT_CTRL_REGS	(1 << 1)	/* Has extended control registers */
 
 #define RCAR_DU_QUIRK_ALIGN_128B	(1 << 0)	/* Align pitches to 128 bytes */
 #define RCAR_DU_QUIRK_LVDS_LANES	(1 << 1)	/* LVDS lanes 1 and 3 inverted */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 34a122a..279167f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -46,6 +46,9 @@
 {
 	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
 
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
 	if (renc->lvds)
 		rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
 }
@@ -190,35 +193,42 @@
 	}
 
 	if (type == RCAR_DU_ENCODER_HDMI) {
-		if (renc->lvds) {
-			dev_err(rcdu->dev,
-				"Chaining LVDS and HDMI encoders not supported\n");
-			return -EINVAL;
-		}
-
 		ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
 		if (ret < 0)
-			return ret;
+			goto done;
 	} else {
 		ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
 				       encoder_type);
 		if (ret < 0)
-			return ret;
+			goto done;
 
 		drm_encoder_helper_add(encoder, &encoder_helper_funcs);
 	}
 
 	switch (encoder_type) {
 	case DRM_MODE_ENCODER_LVDS:
-		return rcar_du_lvds_connector_init(rcdu, renc, con_node);
+		ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
+		break;
 
 	case DRM_MODE_ENCODER_DAC:
-		return rcar_du_vga_connector_init(rcdu, renc);
+		ret = rcar_du_vga_connector_init(rcdu, renc);
+		break;
 
 	case DRM_MODE_ENCODER_TMDS:
-		return rcar_du_hdmi_connector_init(rcdu, renc);
+		ret = rcar_du_hdmi_connector_init(rcdu, renc);
+		break;
 
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		break;
 	}
+
+done:
+	if (ret < 0) {
+		if (encoder->name)
+			encoder->funcs->destroy(encoder);
+		devm_kfree(rcdu->dev, renc);
+	}
+
+	return ret;
 }
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 4e7614b..1bdc0ee 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -48,9 +48,6 @@
 {
 	u32 defr8 = DEFR8_CODE | DEFR8_DEFE8;
 
-	if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8))
-		return;
-
 	/* The DEFR8 register for the first group also controls RGB output
 	 * routing to DPAD0
 	 */
@@ -69,7 +66,20 @@
 	rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE);
 	rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
 
-	rcar_du_group_setup_defr8(rgrp);
+	if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
+		rcar_du_group_setup_defr8(rgrp);
+
+		/* Configure input dot clock routing. We currently hardcode the
+		 * configuration to routing DOTCLKINn to DUn.
+		 */
+		rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
+				    DIDSR_LCDS_DCLKIN(2) |
+				    DIDSR_LCDS_DCLKIN(1) |
+				    DIDSR_LCDS_DCLKIN(0) |
+				    DIDSR_PDCS_CLK(2, 0) |
+				    DIDSR_PDCS_CLK(1, 0) |
+				    DIDSR_PDCS_CLK(0, 0));
+	}
 
 	/* Use DS1PR and DS2PR to configure planes priorities and connects the
 	 * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
@@ -149,6 +159,9 @@
 {
 	int ret;
 
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
+		return 0;
+
 	/* RGB output routing to DPAD0 is configured in the DEFR8 register of
 	 * the first group. As this function can be called with the DU0 and DU1
 	 * CRTCs disabled, we need to enable the first group clock before
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
index 4d7d4dd..ca94b02 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
@@ -95,6 +95,8 @@
 	connector = &rcon->connector;
 	connector->display_info.width_mm = 0;
 	connector->display_info.height_mm = 0;
+	connector->interlace_allowed = true;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
 
 	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
 				 DRM_MODE_CONNECTOR_HDMIA);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index 359bc99..221f0a1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -21,6 +21,7 @@
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_hdmienc.h"
+#include "rcar_du_lvdsenc.h"
 
 struct rcar_du_hdmienc {
 	struct rcar_du_encoder *renc;
@@ -36,12 +37,21 @@
 	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
+	if (mode != DRM_MODE_DPMS_ON)
+		mode = DRM_MODE_DPMS_OFF;
+
 	if (hdmienc->dpms == mode)
 		return;
 
+	if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+		rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
 	if (sfuncs->dpms)
 		sfuncs->dpms(encoder, mode);
 
+	if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+		rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
 	hdmienc->dpms = mode;
 }
 
@@ -49,8 +59,16 @@
 				       const struct drm_display_mode *mode,
 				       struct drm_display_mode *adjusted_mode)
 {
+	struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
 	struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
+	/* The internal LVDS encoder has a clock frequency operating range of
+	 * 30MHz to 150MHz. Clamp the clock accordingly.
+	 */
+	if (hdmienc->renc->lvds)
+		adjusted_mode->clock = clamp(adjusted_mode->clock,
+					     30000, 150000);
+
 	if (sfuncs->mode_fixup == NULL)
 		return true;
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 0c5ee61..cc9136e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -346,8 +346,14 @@
 		/* Process the output pipeline. */
 		ret = rcar_du_encoders_init_one(rcdu, output, &ep);
 		if (ret < 0) {
-			of_node_put(ep_node);
-			return ret;
+			if (ret == -EPROBE_DEFER) {
+				of_node_put(ep_node);
+				return ret;
+			}
+
+			dev_info(rcdu->dev,
+				 "encoder initialization failed, skipping\n");
+			continue;
 		}
 
 		num_encoders += ret;
@@ -413,6 +419,11 @@
 	if (ret < 0)
 		return ret;
 
+	if (ret == 0) {
+		dev_err(rcdu->dev, "error: no encoder could be initialized\n");
+		return -EINVAL;
+	}
+
 	num_encoders = ret;
 
 	/* Set the possible CRTCs and possible clones. There's always at least
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 72a7cb4..50f2f2b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -104,14 +104,22 @@
 {
 	struct rcar_du_group *rgrp = plane->group;
 	unsigned int index = plane->hwindex;
+	bool interlaced;
 	u32 mwr;
 
-	/* Memory pitch (expressed in pixels) */
+	interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
+	/* Memory pitch (expressed in pixels). Must be doubled for interlaced
+	 * operation with 32bpp formats.
+	 */
 	if (plane->format->planes == 2)
 		mwr = plane->pitch;
 	else
 		mwr = plane->pitch * 8 / plane->format->bpp;
 
+	if (interlaced && plane->format->bpp == 32)
+		mwr *= 2;
+
 	rcar_du_plane_write(rgrp, index, PnMWR, mwr);
 
 	/* The Y position is expressed in raster line units and must be doubled
@@ -119,17 +127,23 @@
 	 * doubling the Y position is found in the R8A7779 datasheet, but the
 	 * rule seems to apply there as well.
 	 *
+	 * Despite not being documented, doubling seem not to be needed when
+	 * operating in interlaced mode.
+	 *
 	 * Similarly, for the second plane, NV12 and NV21 formats seem to
-	 * require a halved Y position value.
+	 * require a halved Y position value, in both progressive and interlaced
+	 * modes.
 	 */
 	rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
 	rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
-			    (plane->format->bpp == 32 ? 2 : 1));
+			    (!interlaced && plane->format->bpp == 32 ? 2 : 1));
 	rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
 
 	if (plane->format->planes == 2) {
 		index = (index + 1) % 8;
 
+		rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch);
+
 		rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
 		rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
 				    (plane->format->bpp == 16 ? 2 : 1) / 2);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 73f7347..70fcbc4 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -34,6 +34,7 @@
 #define DSYSR_SCM_INT_NONE	(0 << 4)
 #define DSYSR_SCM_INT_SYNC	(2 << 4)
 #define DSYSR_SCM_INT_VIDEO	(3 << 4)
+#define DSYSR_SCM_MASK		(3 << 4)
 
 #define DSMR			0x00004
 #define DSMR_VSPM		(1 << 28)
@@ -256,8 +257,8 @@
 #define DIDSR_LCDS_LVDS0(n)	(2 << (8 + (n) * 2))
 #define DIDSR_LCDS_LVDS1(n)	(3 << (8 + (n) * 2))
 #define DIDSR_LCDS_MASK(n)	(3 << (8 + (n) * 2))
-#define DIDSR_PCDS_CLK(n, clk)	(clk << ((n) * 2))
-#define DIDSR_PCDS_MASK(n)	(3 << ((n) * 2))
+#define DIDSR_PDCS_CLK(n, clk)	(clk << ((n) * 2))
+#define DIDSR_PDCS_MASK(n)	(3 << ((n) * 2))
 
 /* -----------------------------------------------------------------------------
  * Display Timing Generation Registers
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
index 752747a..9d48799 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -64,6 +64,7 @@
 	connector = &rcon->connector;
 	connector->display_info.width_mm = 0;
 	connector->display_info.height_mm = 0;
+	connector->interlace_allowed = true;
 
 	ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
 				 DRM_MODE_CONNECTOR_VGA);
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index ca9f085..35215f6 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -1,13 +1,13 @@
 config DRM_ROCKCHIP
 	tristate "DRM Support for Rockchip"
 	depends on DRM && ROCKCHIP_IOMMU
+	depends on RESET_CONTROLLER
 	select DRM_KMS_HELPER
 	select DRM_KMS_FB_HELPER
 	select DRM_PANEL
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
-	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	select VIDEOMODE_HELPERS
 	help
 	  Choose this option if you have a Rockchip soc chipset.
@@ -15,3 +15,13 @@
 	  management to userspace. This driver does not provide
 	  2D or 3D acceleration; acceleration is performed by other
 	  IP found on the SoC.
+
+config ROCKCHIP_DW_HDMI
+        tristate "Rockchip specific extensions for Synopsys DW HDMI"
+        depends on DRM_ROCKCHIP
+        select DRM_DW_HDMI
+        help
+	  This selects support for Rockchip SoC specific extensions
+	  for the Synopsys DesignWare HDMI driver. If you want to
+	  enable HDMI on RK3288 based SoC, you should selet this
+	  option.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 2cb0672..f3d8a19 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -5,4 +5,6 @@
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
 		rockchip_drm_gem.o
 
+obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
+
 obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..d236faa
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip 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 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/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_vop.h"
+
+#define GRF_SOC_CON6                    0x025c
+#define HDMI_SEL_VOP_LIT                (1 << 4)
+
+struct rockchip_hdmi {
+	struct device *dev;
+	struct regmap *regmap;
+	struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x)	container_of(x, struct rockchip_hdmi, x)
+
+static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
+	{
+		27000000, {
+			{ 0x00b3, 0x0000},
+			{ 0x2153, 0x0000},
+			{ 0x40f3, 0x0000}
+		},
+	}, {
+		36000000, {
+			{ 0x00b3, 0x0000},
+			{ 0x2153, 0x0000},
+			{ 0x40f3, 0x0000}
+		},
+	}, {
+		40000000, {
+			{ 0x00b3, 0x0000},
+			{ 0x2153, 0x0000},
+			{ 0x40f3, 0x0000}
+		},
+	}, {
+		54000000, {
+			{ 0x0072, 0x0001},
+			{ 0x2142, 0x0001},
+			{ 0x40a2, 0x0001},
+		},
+	}, {
+		65000000, {
+			{ 0x0072, 0x0001},
+			{ 0x2142, 0x0001},
+			{ 0x40a2, 0x0001},
+		},
+	}, {
+		66000000, {
+			{ 0x013e, 0x0003},
+			{ 0x217e, 0x0002},
+			{ 0x4061, 0x0002}
+		},
+	}, {
+		74250000, {
+			{ 0x0072, 0x0001},
+			{ 0x2145, 0x0002},
+			{ 0x4061, 0x0002}
+		},
+	}, {
+		83500000, {
+			{ 0x0072, 0x0001},
+		},
+	}, {
+		108000000, {
+			{ 0x0051, 0x0002},
+			{ 0x2145, 0x0002},
+			{ 0x4061, 0x0002}
+		},
+	}, {
+		106500000, {
+			{ 0x0051, 0x0002},
+			{ 0x2145, 0x0002},
+			{ 0x4061, 0x0002}
+		},
+	}, {
+		146250000, {
+			{ 0x0051, 0x0002},
+			{ 0x2145, 0x0002},
+			{ 0x4061, 0x0002}
+		},
+	}, {
+		148500000, {
+			{ 0x0051, 0x0003},
+			{ 0x214c, 0x0003},
+			{ 0x4064, 0x0003}
+		},
+	}, {
+		~0UL, {
+			{ 0x00a0, 0x000a },
+			{ 0x2001, 0x000f },
+			{ 0x4002, 0x000f },
+		},
+	}
+};
+
+static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
+	/*      pixelclk    bpp8    bpp10   bpp12 */
+	{
+		40000000,  { 0x0018, 0x0018, 0x0018 },
+	}, {
+		65000000,  { 0x0028, 0x0028, 0x0028 },
+	}, {
+		66000000,  { 0x0038, 0x0038, 0x0038 },
+	}, {
+		74250000,  { 0x0028, 0x0038, 0x0038 },
+	}, {
+		83500000,  { 0x0028, 0x0038, 0x0038 },
+	}, {
+		146250000, { 0x0038, 0x0038, 0x0038 },
+	}, {
+		148500000, { 0x0000, 0x0038, 0x0038 },
+	}, {
+		~0UL,      { 0x0000, 0x0000, 0x0000},
+	}
+};
+
+static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
+	/*pixelclk   symbol   term*/
+	{ 74250000,  0x8009, 0x0004 },
+	{ 148500000, 0x8029, 0x0004 },
+	{ 297000000, 0x8039, 0x0005 },
+	{ ~0UL,	     0x0000, 0x0000 }
+};
+
+static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
+{
+	struct device_node *np = hdmi->dev->of_node;
+
+	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+	if (IS_ERR(hdmi->regmap)) {
+		dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
+		return PTR_ERR(hdmi->regmap);
+	}
+
+	return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+			    struct drm_display_mode *mode)
+{
+	const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
+	int pclk = mode->clock * 1000;
+	bool valid = false;
+	int i;
+
+	for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
+		if (pclk == mpll_cfg[i].mpixelclock) {
+			valid = true;
+			break;
+		}
+	}
+
+	return (valid) ? MODE_OK : MODE_BAD;
+}
+
+static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool
+dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
+				    const struct drm_display_mode *mode,
+				    struct drm_display_mode *adj_mode)
+{
+	return true;
+}
+
+static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
+					      struct drm_display_mode *mode,
+					      struct drm_display_mode *adj_mode)
+{
+}
+
+static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
+{
+	struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+	u32 val;
+	int mux;
+
+	mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
+	if (mux)
+		val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
+	else
+		val = HDMI_SEL_VOP_LIT << 16;
+
+	regmap_write(hdmi->regmap, GRF_SOC_CON6, val);
+	dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
+		(mux) ? "LIT" : "BIG");
+}
+
+static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
+{
+	rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
+				      ROCKCHIP_OUT_MODE_AAAA);
+}
+
+static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
+	.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
+	.mode_set   = dw_hdmi_rockchip_encoder_mode_set,
+	.prepare    = dw_hdmi_rockchip_encoder_prepare,
+	.commit     = dw_hdmi_rockchip_encoder_commit,
+	.disable    = dw_hdmi_rockchip_encoder_disable,
+};
+
+static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
+	.mode_valid = dw_hdmi_rockchip_mode_valid,
+	.mpll_cfg   = rockchip_mpll_cfg,
+	.cur_ctr    = rockchip_cur_ctr,
+	.sym_term   = rockchip_sym_term,
+	.dev_type   = RK3288_HDMI,
+};
+
+static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
+	{ .compatible = "rockchip,rk3288-dw-hdmi",
+	  .data = &rockchip_hdmi_drv_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
+
+static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
+				 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct dw_hdmi_plat_data *plat_data;
+	const struct of_device_id *match;
+	struct drm_device *drm = data;
+	struct drm_encoder *encoder;
+	struct rockchip_hdmi *hdmi;
+	struct resource *iores;
+	int irq;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
+	plat_data = match->data;
+	hdmi->dev = &pdev->dev;
+	encoder = &hdmi->encoder;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores)
+		return -ENXIO;
+
+	platform_set_drvdata(pdev, hdmi);
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	ret = rockchip_hdmi_parse_dt(hdmi);
+	if (ret) {
+		dev_err(hdmi->dev, "Unable to parse OF data\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+
+	return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+				    void *data)
+{
+	return dw_hdmi_unbind(dev, master, data);
+}
+
+static const struct component_ops dw_hdmi_rockchip_ops = {
+	.bind	= dw_hdmi_rockchip_bind,
+	.unbind	= dw_hdmi_rockchip_unbind,
+};
+
+static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
+}
+
+static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
+
+	return 0;
+}
+
+static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
+	.probe  = dw_hdmi_rockchip_probe,
+	.remove = dw_hdmi_rockchip_remove,
+	.driver = {
+		.name = "dwhdmi-rockchip",
+		.of_match_table = dw_hdmi_rockchip_dt_ids,
+	},
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index a798c7c..21a481b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -390,6 +390,7 @@
 
 	return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(rockchip_drm_encoder_get_mux_id);
 
 static int compare_of(struct device *dev, void *data)
 {
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index bc98a22..7ca8799e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -34,12 +34,9 @@
 	rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
 					 &rk_obj->dma_addr, GFP_KERNEL,
 					 &rk_obj->dma_attrs);
-	if (IS_ERR(rk_obj->kvaddr)) {
-		int ret = PTR_ERR(rk_obj->kvaddr);
-
-		DRM_ERROR("failed to allocate %#x byte dma buffer, %d",
-			  obj->size, ret);
-		return ret;
+	if (!rk_obj->kvaddr) {
+		DRM_ERROR("failed to allocate %#x byte dma buffer", obj->size);
+		return -ENOMEM;
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index e7ca25b..9a5c571 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -735,6 +735,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(rockchip_drm_crtc_mode_config);
 
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
 {
diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig
index a50fe0e..b9202aa 100644
--- a/drivers/gpu/drm/shmobile/Kconfig
+++ b/drivers/gpu/drm/shmobile/Kconfig
@@ -1,8 +1,10 @@
 config DRM_SHMOBILE
 	tristate "DRM Support for SH Mobile"
-	depends on DRM && ARM
+	depends on DRM && ARM && HAVE_DMA_ATTRS
 	depends on ARCH_SHMOBILE || COMPILE_TEST
+	depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
 	select BACKLIGHT_CLASS_DEVICE
+	select BACKLIGHT_LCD_SUPPORT
 	select DRM_KMS_HELPER
 	select DRM_KMS_FB_HELPER
 	select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig
index d6d6b70..fbccc10 100644
--- a/drivers/gpu/drm/sti/Kconfig
+++ b/drivers/gpu/drm/sti/Kconfig
@@ -1,10 +1,11 @@
 config DRM_STI
 	tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
-	depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
+	depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) && HAVE_DMA_ATTRS
 	select RESET_CONTROLLER
 	select DRM_KMS_HELPER
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
 	select FW_LOADER_USER_HELPER_FALLBACK
 	help
 	  Choose this option to enable DRM on STM stiH41x chipset
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
index 6ba9d27..f0f1e4e 100644
--- a/drivers/gpu/drm/sti/Makefile
+++ b/drivers/gpu/drm/sti/Makefile
@@ -12,6 +12,9 @@
 	sti_hdmi_tx3g0c55phy.o \
 	sti_hdmi_tx3g4c28phy.o \
 
+stidvo-y := sti_dvo.o \
+	sti_awg_utils.o
+
 obj-$(CONFIG_DRM_STI) = \
 	sti_vtg.o \
 	sti_vtac.o \
@@ -20,4 +23,5 @@
 	sti_tvout.o \
 	sticompositor.o \
 	sti_hqvdp.o \
+	stidvo.o \
 	sti_drm_drv.o
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c
new file mode 100644
index 0000000..6029a2e
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_awg_utils.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "sti_awg_utils.h"
+
+#define AWG_OPCODE_OFFSET 10
+
+enum opcode {
+	SET,
+	RPTSET,
+	RPLSET,
+	SKIP,
+	STOP,
+	REPEAT,
+	REPLAY,
+	JUMP,
+	HOLD,
+};
+
+static int awg_generate_instr(enum opcode opcode,
+			      long int arg,
+			      long int mux_sel,
+			      long int data_en,
+			      struct awg_code_generation_params *fwparams)
+{
+	u32 instruction = 0;
+	u32 mux = (mux_sel << 8) & 0x1ff;
+	u32 data_enable = (data_en << 9) & 0x2ff;
+	long int arg_tmp = arg;
+
+	/* skip, repeat and replay arg should not exceed 1023.
+	 * If user wants to exceed this value, the instruction should be
+	 * duplicate and arg should be adjust for each duplicated instruction.
+	 */
+
+	while (arg_tmp > 0) {
+		arg = arg_tmp;
+		if (fwparams->instruction_offset >= AWG_MAX_INST) {
+			DRM_ERROR("too many number of instructions\n");
+			return -EINVAL;
+		}
+
+		switch (opcode) {
+		case SKIP:
+			/* leave 'arg' + 1 pixel elapsing without changing
+			 * output bus */
+			arg--; /* pixel adjustment */
+			arg_tmp--;
+
+			if (arg < 0) {
+				/* SKIP instruction not needed */
+				return 0;
+			}
+
+			if (arg == 0) {
+				/* SKIP 0 not permitted but we want to skip 1
+				 * pixel. So we transform SKIP into SET
+				 * instruction */
+				opcode = SET;
+				break;
+			}
+
+			mux = 0;
+			data_enable = 0;
+			arg = (arg << 22) >> 22;
+			arg &= (0x3ff);
+			break;
+		case REPEAT:
+		case REPLAY:
+			if (arg == 0) {
+				/* REPEAT or REPLAY instruction not needed */
+				return 0;
+			}
+
+			mux = 0;
+			data_enable = 0;
+			arg = (arg << 22) >> 22;
+			arg &= (0x3ff);
+			break;
+		case JUMP:
+			mux = 0;
+			data_enable = 0;
+			arg |= 0x40; /* for jump instruction 7th bit is 1 */
+			arg = (arg << 22) >> 22;
+			arg &= 0x3ff;
+			break;
+		case STOP:
+			arg = 0;
+			break;
+		case SET:
+		case RPTSET:
+		case RPLSET:
+		case HOLD:
+			arg = (arg << 24) >> 24;
+			arg &= (0x0ff);
+			break;
+		default:
+			DRM_ERROR("instruction %d does not exist\n", opcode);
+			return -EINVAL;
+		}
+
+		arg_tmp = arg_tmp - arg;
+
+		arg = ((arg + mux) + data_enable);
+
+		instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
+		fwparams->ram_code[fwparams->instruction_offset] =
+			instruction & (0x3fff);
+		fwparams->instruction_offset++;
+	}
+	return 0;
+}
+
+int sti_awg_generate_code_data_enable_mode(
+		struct awg_code_generation_params *fwparams,
+		struct awg_timing *timing)
+{
+	long int val;
+	long int data_en;
+	int ret = 0;
+
+	if (timing->trailing_lines > 0) {
+		/* skip trailing lines */
+		val = timing->blanking_level;
+		data_en = 0;
+		ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+		val = timing->trailing_lines - 1;
+		data_en = 0;
+		ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+	}
+
+	if (timing->trailing_pixels > 0) {
+		/* skip trailing pixel */
+		val = timing->blanking_level;
+		data_en = 0;
+		ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+		val = timing->trailing_pixels - 1;
+		data_en = 0;
+		ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
+	}
+
+	/* set DE signal high */
+	val = timing->blanking_level;
+	data_en = 1;
+	ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
+			val, 0, data_en, fwparams);
+
+	if (timing->blanking_pixels > 0) {
+		/* skip the number of active pixel */
+		val = timing->active_pixels - 1;
+		data_en = 1;
+		ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
+
+		/* set DE signal low */
+		val = timing->blanking_level;
+		data_en = 0;
+		ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
+	}
+
+	/* replay the sequence as many active lines defined */
+	val = timing->active_lines - 1;
+	data_en = 0;
+	ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+
+	if (timing->blanking_lines > 0) {
+		/* skip blanking lines */
+		val = timing->blanking_level;
+		data_en = 0;
+		ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+		val = timing->blanking_lines - 1;
+		data_en = 0;
+		ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.h b/drivers/gpu/drm/sti/sti_awg_utils.h
new file mode 100644
index 0000000..45d599b
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_awg_utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STI_AWG_UTILS_H_
+#define _STI_AWG_UTILS_H_
+
+#include <drm/drmP.h>
+
+#define AWG_MAX_INST 64
+
+struct awg_code_generation_params {
+	u32 *ram_code;
+	u8 instruction_offset;
+};
+
+struct awg_timing {
+	u32 total_lines;
+	u32 active_lines;
+	u32 blanking_lines;
+	u32 trailing_lines;
+	u32 total_pixels;
+	u32 active_pixels;
+	u32 blanking_pixels;
+	u32 trailing_pixels;
+	u32 blanking_level;
+};
+
+int sti_awg_generate_code_data_enable_mode(
+		struct awg_code_generation_params *fw_gen_params,
+		struct awg_timing *timing);
+#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
index 4c651c2..e6f6ef7 100644
--- a/drivers/gpu/drm/sti/sti_drm_crtc.c
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
@@ -190,11 +190,6 @@
 	return ret;
 }
 
-static void sti_drm_crtc_load_lut(struct drm_crtc *crtc)
-{
-	/* do nothing */
-}
-
 static void sti_drm_crtc_disable(struct drm_crtc *crtc)
 {
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
@@ -249,7 +244,6 @@
 	.mode_fixup = sti_drm_crtc_mode_fixup,
 	.mode_set = sti_drm_crtc_mode_set,
 	.mode_set_base = sti_drm_crtc_mode_set_base,
-	.load_lut = sti_drm_crtc_load_lut,
 	.disable = sti_drm_crtc_disable,
 };
 
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
new file mode 100644
index 0000000..aeb5070
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "sti_awg_utils.h"
+#include "sti_mixer.h"
+
+/* DVO registers */
+#define DVO_AWG_DIGSYNC_CTRL      0x0000
+#define DVO_DOF_CFG               0x0004
+#define DVO_LUT_PROG_LOW          0x0008
+#define DVO_LUT_PROG_MID          0x000C
+#define DVO_LUT_PROG_HIGH         0x0010
+#define DVO_DIGSYNC_INSTR_I       0x0100
+
+#define DVO_AWG_CTRL_EN           BIT(0)
+#define DVO_AWG_FRAME_BASED_SYNC  BIT(2)
+
+#define DVO_DOF_EN_LOWBYTE        BIT(0)
+#define DVO_DOF_EN_MIDBYTE        BIT(1)
+#define DVO_DOF_EN_HIGHBYTE       BIT(2)
+#define DVO_DOF_EN                BIT(6)
+#define DVO_DOF_MOD_COUNT_SHIFT   8
+
+#define DVO_LUT_ZERO              0
+#define DVO_LUT_Y_G               1
+#define DVO_LUT_Y_G_DEL           2
+#define DVO_LUT_CB_B              3
+#define DVO_LUT_CB_B_DEL          4
+#define DVO_LUT_CR_R              5
+#define DVO_LUT_CR_R_DEL          6
+#define DVO_LUT_HOLD              7
+
+struct dvo_config {
+	u32 flags;
+	u32 lowbyte;
+	u32 midbyte;
+	u32 highbyte;
+	int (*awg_fwgen_fct)(
+			struct awg_code_generation_params *fw_gen_params,
+			struct awg_timing *timing);
+};
+
+static struct dvo_config rgb_24bit_de_cfg = {
+	.flags         = (0L << DVO_DOF_MOD_COUNT_SHIFT),
+	.lowbyte       = DVO_LUT_CR_R,
+	.midbyte       = DVO_LUT_Y_G,
+	.highbyte      = DVO_LUT_CB_B,
+	.awg_fwgen_fct = sti_awg_generate_code_data_enable_mode,
+};
+
+/**
+ * STI digital video output structure
+ *
+ * @dev: driver device
+ * @drm_dev: pointer to drm device
+ * @mode: current display mode selected
+ * @regs: dvo registers
+ * @clk_pix: pixel clock for dvo
+ * @clk: clock for dvo
+ * @clk_main_parent: dvo parent clock if main path used
+ * @clk_aux_parent: dvo parent clock if aux path used
+ * @panel_node: panel node reference from device tree
+ * @panel: reference to the panel connected to the dvo
+ * @enabled: true if dvo is enabled else false
+ * @encoder: drm_encoder it is bound
+ */
+struct sti_dvo {
+	struct device dev;
+	struct drm_device *drm_dev;
+	struct drm_display_mode mode;
+	void __iomem *regs;
+	struct clk *clk_pix;
+	struct clk *clk;
+	struct clk *clk_main_parent;
+	struct clk *clk_aux_parent;
+	struct device_node *panel_node;
+	struct drm_panel *panel;
+	struct dvo_config *config;
+	bool enabled;
+	struct drm_encoder *encoder;
+	struct drm_bridge *bridge;
+};
+
+struct sti_dvo_connector {
+	struct drm_connector drm_connector;
+	struct drm_encoder *encoder;
+	struct sti_dvo *dvo;
+};
+
+#define to_sti_dvo_connector(x) \
+	container_of(x, struct sti_dvo_connector, drm_connector)
+
+#define BLANKING_LEVEL 16
+int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
+{
+	struct drm_display_mode *mode = &dvo->mode;
+	struct dvo_config *config = dvo->config;
+	struct awg_code_generation_params fw_gen_params;
+	struct awg_timing timing;
+
+	fw_gen_params.ram_code = ram_code;
+	fw_gen_params.instruction_offset = 0;
+
+	timing.total_lines = mode->vtotal;
+	timing.active_lines = mode->vdisplay;
+	timing.blanking_lines = mode->vsync_start - mode->vdisplay;
+	timing.trailing_lines = mode->vtotal - mode->vsync_start;
+	timing.total_pixels = mode->htotal;
+	timing.active_pixels = mode->hdisplay;
+	timing.blanking_pixels = mode->hsync_start - mode->hdisplay;
+	timing.trailing_pixels = mode->htotal - mode->hsync_start;
+	timing.blanking_level = BLANKING_LEVEL;
+
+	if (config->awg_fwgen_fct(&fw_gen_params, &timing)) {
+		DRM_ERROR("AWG firmware not properly generated\n");
+		return -EINVAL;
+	}
+
+	*ram_size = fw_gen_params.instruction_offset;
+
+	return 0;
+}
+
+/* Configure AWG, writing instructions
+ *
+ * @dvo: pointer to DVO structure
+ * @awg_ram_code: pointer to AWG instructions table
+ * @nb: nb of AWG instructions
+ */
+static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
+{
+	int i;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	for (i = 0; i < nb; i++)
+		writel(awg_ram_code[i],
+		       dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
+	for (i = nb; i < AWG_MAX_INST; i++)
+		writel(0, dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
+
+	writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+}
+
+static void sti_dvo_disable(struct drm_bridge *bridge)
+{
+	struct sti_dvo *dvo = bridge->driver_private;
+
+	if (!dvo->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	if (dvo->config->awg_fwgen_fct)
+		writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+
+	writel(0x00000000, dvo->regs + DVO_DOF_CFG);
+
+	if (dvo->panel)
+		dvo->panel->funcs->disable(dvo->panel);
+
+	/* Disable/unprepare dvo clock */
+	clk_disable_unprepare(dvo->clk_pix);
+	clk_disable_unprepare(dvo->clk);
+
+	dvo->enabled = false;
+}
+
+static void sti_dvo_pre_enable(struct drm_bridge *bridge)
+{
+	struct sti_dvo *dvo = bridge->driver_private;
+	struct dvo_config *config = dvo->config;
+	u32 val;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	if (dvo->enabled)
+		return;
+
+	/* Make sure DVO is disabled */
+	writel(0x00000000, dvo->regs + DVO_DOF_CFG);
+	writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+
+	if (config->awg_fwgen_fct) {
+		u8 nb_instr;
+		u32 awg_ram_code[AWG_MAX_INST];
+		/* Configure AWG */
+		if (!dvo_awg_generate_code(dvo, &nb_instr, awg_ram_code))
+			dvo_awg_configure(dvo, awg_ram_code, nb_instr);
+		else
+			return;
+	}
+
+	/* Prepare/enable clocks */
+	if (clk_prepare_enable(dvo->clk_pix))
+		DRM_ERROR("Failed to prepare/enable dvo_pix clk\n");
+	if (clk_prepare_enable(dvo->clk))
+		DRM_ERROR("Failed to prepare/enable dvo clk\n");
+
+	if (dvo->panel)
+		dvo->panel->funcs->enable(dvo->panel);
+
+	/* Set LUT */
+	writel(config->lowbyte,  dvo->regs + DVO_LUT_PROG_LOW);
+	writel(config->midbyte,  dvo->regs + DVO_LUT_PROG_MID);
+	writel(config->highbyte, dvo->regs + DVO_LUT_PROG_HIGH);
+
+	/* Digital output formatter config */
+	val = (config->flags | DVO_DOF_EN);
+	writel(val, dvo->regs + DVO_DOF_CFG);
+
+	dvo->enabled = true;
+}
+
+static void sti_dvo_set_mode(struct drm_bridge *bridge,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adjusted_mode)
+{
+	struct sti_dvo *dvo = bridge->driver_private;
+	struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc);
+	int rate = mode->clock * 1000;
+	struct clk *clkp;
+	int ret;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
+
+	/* According to the path used (main or aux), the dvo clocks should
+	 * have a different parent clock. */
+	if (mixer->id == STI_MIXER_MAIN)
+		clkp = dvo->clk_main_parent;
+	else
+		clkp = dvo->clk_aux_parent;
+
+	if (clkp) {
+		clk_set_parent(dvo->clk_pix, clkp);
+		clk_set_parent(dvo->clk, clkp);
+	}
+
+	/* DVO clocks = compositor clock */
+	ret = clk_set_rate(dvo->clk_pix, rate);
+	if (ret < 0) {
+		DRM_ERROR("Cannot set rate (%dHz) for dvo_pix clk\n", rate);
+		return;
+	}
+
+	ret = clk_set_rate(dvo->clk, rate);
+	if (ret < 0) {
+		DRM_ERROR("Cannot set rate (%dHz) for dvo clk\n", rate);
+		return;
+	}
+
+	/* For now, we only support 24bit data enable (DE) synchro format */
+	dvo->config = &rgb_24bit_de_cfg;
+}
+
+static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
+{
+	/* do nothing */
+}
+
+static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
+	.pre_enable = sti_dvo_pre_enable,
+	.enable = sti_dvo_bridge_nope,
+	.disable = sti_dvo_disable,
+	.post_disable = sti_dvo_bridge_nope,
+	.mode_set = sti_dvo_set_mode,
+};
+
+static int sti_dvo_connector_get_modes(struct drm_connector *connector)
+{
+	struct sti_dvo_connector *dvo_connector
+		= to_sti_dvo_connector(connector);
+	struct sti_dvo *dvo = dvo_connector->dvo;
+
+	if (dvo->panel)
+		return dvo->panel->funcs->get_modes(dvo->panel);
+
+	return 0;
+}
+
+#define CLK_TOLERANCE_HZ 50
+
+static int sti_dvo_connector_mode_valid(struct drm_connector *connector,
+					struct drm_display_mode *mode)
+{
+	int target = mode->clock * 1000;
+	int target_min = target - CLK_TOLERANCE_HZ;
+	int target_max = target + CLK_TOLERANCE_HZ;
+	int result;
+	struct sti_dvo_connector *dvo_connector
+		= to_sti_dvo_connector(connector);
+	struct sti_dvo *dvo = dvo_connector->dvo;
+
+	result = clk_round_rate(dvo->clk_pix, target);
+
+	DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
+			 target, result);
+
+	if ((result < target_min) || (result > target_max)) {
+		DRM_DEBUG_DRIVER("dvo pixclk=%d not supported\n", target);
+		return MODE_BAD;
+	}
+
+	return MODE_OK;
+}
+
+struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
+{
+	struct sti_dvo_connector *dvo_connector
+		= to_sti_dvo_connector(connector);
+
+	/* Best encoder is the one associated during connector creation */
+	return dvo_connector->encoder;
+}
+
+static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
+	.get_modes = sti_dvo_connector_get_modes,
+	.mode_valid = sti_dvo_connector_mode_valid,
+	.best_encoder = sti_dvo_best_encoder,
+};
+
+static enum drm_connector_status
+sti_dvo_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct sti_dvo_connector *dvo_connector
+		= to_sti_dvo_connector(connector);
+	struct sti_dvo *dvo = dvo_connector->dvo;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	if (!dvo->panel)
+		dvo->panel = of_drm_find_panel(dvo->panel_node);
+
+	if (dvo->panel)
+		if (!drm_panel_attach(dvo->panel, connector))
+			return connector_status_connected;
+
+	return connector_status_disconnected;
+}
+
+static void sti_dvo_connector_destroy(struct drm_connector *connector)
+{
+	struct sti_dvo_connector *dvo_connector
+		= to_sti_dvo_connector(connector);
+
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+	kfree(dvo_connector);
+}
+
+static struct drm_connector_funcs sti_dvo_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = sti_dvo_connector_detect,
+	.destroy = sti_dvo_connector_destroy,
+};
+
+static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+		if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
+			return encoder;
+	}
+
+	return NULL;
+}
+
+static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
+{
+	struct sti_dvo *dvo = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = data;
+	struct drm_encoder *encoder;
+	struct sti_dvo_connector *connector;
+	struct drm_connector *drm_connector;
+	struct drm_bridge *bridge;
+	int err;
+
+	/* Set the drm device handle */
+	dvo->drm_dev = drm_dev;
+
+	encoder = sti_dvo_find_encoder(drm_dev);
+	if (!encoder)
+		return -ENOMEM;
+
+	connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
+	if (!connector)
+		return -ENOMEM;
+
+	connector->dvo = dvo;
+
+	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->driver_private = dvo;
+	bridge->funcs = &sti_dvo_bridge_funcs;
+	bridge->of_node = dvo->dev.of_node;
+	err = drm_bridge_add(bridge);
+	if (err) {
+		DRM_ERROR("Failed to add bridge\n");
+		return err;
+	}
+
+	err = drm_bridge_attach(drm_dev, bridge);
+	if (err) {
+		DRM_ERROR("Failed to attach bridge\n");
+		return err;
+	}
+
+	dvo->bridge = bridge;
+	encoder->bridge = bridge;
+	connector->encoder = encoder;
+	dvo->encoder = encoder;
+
+	drm_connector = (struct drm_connector *)connector;
+
+	drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_init(drm_dev, drm_connector,
+			   &sti_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(drm_connector,
+				 &sti_dvo_connector_helper_funcs);
+
+	err = drm_connector_register(drm_connector);
+	if (err)
+		goto err_connector;
+
+	err = drm_mode_connector_attach_encoder(drm_connector, encoder);
+	if (err) {
+		DRM_ERROR("Failed to attach a connector to a encoder\n");
+		goto err_sysfs;
+	}
+
+	return 0;
+
+err_sysfs:
+	drm_connector_unregister(drm_connector);
+err_connector:
+	drm_bridge_remove(bridge);
+	drm_connector_cleanup(drm_connector);
+	return -EINVAL;
+}
+
+static void sti_dvo_unbind(struct device *dev,
+			   struct device *master, void *data)
+{
+	struct sti_dvo *dvo = dev_get_drvdata(dev);
+
+	drm_bridge_remove(dvo->bridge);
+}
+
+static const struct component_ops sti_dvo_ops = {
+	.bind = sti_dvo_bind,
+	.unbind = sti_dvo_unbind,
+};
+
+static int sti_dvo_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sti_dvo *dvo;
+	struct resource *res;
+	struct device_node *np = dev->of_node;
+
+	DRM_INFO("%s\n", __func__);
+
+	dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL);
+	if (!dvo) {
+		DRM_ERROR("Failed to allocate memory for DVO\n");
+		return -ENOMEM;
+	}
+
+	dvo->dev = pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvo-reg");
+	if (!res) {
+		DRM_ERROR("Invalid dvo resource\n");
+		return -ENOMEM;
+	}
+	dvo->regs = devm_ioremap_nocache(dev, res->start,
+			resource_size(res));
+	if (IS_ERR(dvo->regs))
+		return PTR_ERR(dvo->regs);
+
+	dvo->clk_pix = devm_clk_get(dev, "dvo_pix");
+	if (IS_ERR(dvo->clk_pix)) {
+		DRM_ERROR("Cannot get dvo_pix clock\n");
+		return PTR_ERR(dvo->clk_pix);
+	}
+
+	dvo->clk = devm_clk_get(dev, "dvo");
+	if (IS_ERR(dvo->clk)) {
+		DRM_ERROR("Cannot get dvo clock\n");
+		return PTR_ERR(dvo->clk);
+	}
+
+	dvo->clk_main_parent = devm_clk_get(dev, "main_parent");
+	if (IS_ERR(dvo->clk_main_parent)) {
+		DRM_DEBUG_DRIVER("Cannot get main_parent clock\n");
+		dvo->clk_main_parent = NULL;
+	}
+
+	dvo->clk_aux_parent = devm_clk_get(dev, "aux_parent");
+	if (IS_ERR(dvo->clk_aux_parent)) {
+		DRM_DEBUG_DRIVER("Cannot get aux_parent clock\n");
+		dvo->clk_aux_parent = NULL;
+	}
+
+	dvo->panel_node = of_parse_phandle(np, "sti,panel", 0);
+	if (!dvo->panel_node)
+		DRM_ERROR("No panel associated to the dvo output\n");
+
+	platform_set_drvdata(pdev, dvo);
+
+	return component_add(&pdev->dev, &sti_dvo_ops);
+}
+
+static int sti_dvo_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sti_dvo_ops);
+	return 0;
+}
+
+static struct of_device_id dvo_of_match[] = {
+	{ .compatible = "st,stih407-dvo", },
+	{ /* end node */ }
+};
+MODULE_DEVICE_TABLE(of, dvo_of_match);
+
+struct platform_driver sti_dvo_driver = {
+	.driver = {
+		.name = "sti-dvo",
+		.owner = THIS_MODULE,
+		.of_match_table = dvo_of_match,
+	},
+	.probe = sti_dvo_probe,
+	.remove = sti_dvo_remove,
+};
+
+module_platform_driver(sti_dvo_driver);
+
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index 32448d1..087906f 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -14,15 +14,19 @@
 #include "sti_layer.h"
 #include "sti_vtg.h"
 
+#define ALPHASWITCH     BIT(6)
 #define ENA_COLOR_FILL  BIT(8)
+#define BIGNOTLITTLE    BIT(23)
 #define WAIT_NEXT_VSYNC BIT(31)
 
 /* GDP color formats */
 #define GDP_RGB565      0x00
 #define GDP_RGB888      0x01
 #define GDP_RGB888_32   0x02
+#define GDP_XBGR8888    (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB8565    0x04
 #define GDP_ARGB8888    0x05
+#define GDP_ABGR8888	(GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB1555    0x06
 #define GDP_ARGB4444    0x07
 #define GDP_CLUT8       0x0B
@@ -103,7 +107,9 @@
 
 static const uint32_t gdp_supported_formats[] = {
 	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
 	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
 	DRM_FORMAT_ARGB4444,
 	DRM_FORMAT_ARGB1555,
 	DRM_FORMAT_RGB565,
@@ -129,8 +135,12 @@
 	switch (fourcc) {
 	case DRM_FORMAT_XRGB8888:
 		return GDP_RGB888_32;
+	case DRM_FORMAT_XBGR8888:
+		return GDP_XBGR8888;
 	case DRM_FORMAT_ARGB8888:
 		return GDP_ARGB8888;
+	case DRM_FORMAT_ABGR8888:
+		return GDP_ABGR8888;
 	case DRM_FORMAT_ARGB4444:
 		return GDP_ARGB4444;
 	case DRM_FORMAT_ARGB1555:
@@ -157,6 +167,7 @@
 	case GDP_ARGB8565:
 	case GDP_ARGB8888:
 	case GDP_AYCBR8888:
+	case GDP_ABGR8888:
 		return GAM_GDP_ALPHARANGE_255;
 	}
 	return 0;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 2ae9a9b..a9bbb08 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -508,19 +508,12 @@
 	/* do nothing */
 }
 
-static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
 	.pre_enable = sti_hda_pre_enable,
 	.enable = sti_hda_bridge_nope,
 	.disable = sti_hda_disable,
 	.post_disable = sti_hda_bridge_nope,
 	.mode_set = sti_hda_set_mode,
-	.destroy = sti_hda_brigde_destroy,
 };
 
 static int sti_hda_connector_get_modes(struct drm_connector *connector)
@@ -664,7 +657,8 @@
 		return -ENOMEM;
 
 	bridge->driver_private = hda;
-	drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
+	bridge->funcs = &sti_hda_bridge_funcs;
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -693,7 +687,6 @@
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 	return -EINVAL;
 }
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index d032e02..1485ade 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -42,8 +42,17 @@
 #define HDMI_SW_DI_1_PKT_WORD5          0x0228
 #define HDMI_SW_DI_1_PKT_WORD6          0x022C
 #define HDMI_SW_DI_CFG                  0x0230
+#define HDMI_SW_DI_2_HEAD_WORD          0x0600
+#define HDMI_SW_DI_2_PKT_WORD0          0x0604
+#define HDMI_SW_DI_2_PKT_WORD1          0x0608
+#define HDMI_SW_DI_2_PKT_WORD2          0x060C
+#define HDMI_SW_DI_2_PKT_WORD3          0x0610
+#define HDMI_SW_DI_2_PKT_WORD4          0x0614
+#define HDMI_SW_DI_2_PKT_WORD5          0x0618
+#define HDMI_SW_DI_2_PKT_WORD6          0x061C
 
 #define HDMI_IFRAME_SLOT_AVI            1
+#define HDMI_IFRAME_SLOT_AUDIO          2
 
 #define  XCAT(prefix, x, suffix)        prefix ## x ## suffix
 #define  HDMI_SW_DI_N_HEAD_WORD(x)      XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
@@ -99,6 +108,10 @@
 
 #define HDMI_STA_SW_RST                 BIT(1)
 
+#define HDMI_INFOFRAME_HEADER_TYPE(x)    (((x) & 0xff) <<  0)
+#define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) <<  8)
+#define HDMI_INFOFRAME_HEADER_LEN(x)     (((x) & 0x0f) << 16)
+
 struct sti_hdmi_connector {
 	struct drm_connector drm_connector;
 	struct drm_encoder *encoder;
@@ -228,6 +241,90 @@
 }
 
 /**
+ * Helper to concatenate infoframe in 32 bits word
+ *
+ * @ptr: pointer on the hdmi internal structure
+ * @data: infoframe to write
+ * @size: size to write
+ */
+static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size)
+{
+	unsigned long value = 0;
+	size_t i;
+
+	for (i = size; i > 0; i--)
+		value = (value << 8) | ptr[i - 1];
+
+	return value;
+}
+
+/**
+ * Helper to write info frame
+ *
+ * @hdmi: pointer on the hdmi internal structure
+ * @data: infoframe to write
+ * @size: size to write
+ */
+static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
+{
+	const u8 *ptr = data;
+	u32 val, slot, mode, i;
+	u32 head_offset, pack_offset;
+	size_t size;
+
+	switch (*ptr) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		slot = HDMI_IFRAME_SLOT_AVI;
+		mode = HDMI_IFRAME_FIELD;
+		head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
+		pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
+		size = HDMI_AVI_INFOFRAME_SIZE;
+		break;
+
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		slot = HDMI_IFRAME_SLOT_AUDIO;
+		mode = HDMI_IFRAME_FRAME;
+		head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
+		pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
+		size = HDMI_AUDIO_INFOFRAME_SIZE;
+		break;
+
+	default:
+		DRM_ERROR("unsupported infoframe type: %#x\n", *ptr);
+		return;
+	}
+
+	/* Disable transmission slot for updated infoframe */
+	val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
+	val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
+	hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+
+	val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++);
+	val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++);
+	val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++);
+	writel(val, hdmi->regs + head_offset);
+
+	/*
+	 * Each subpack contains 4 bytes
+	 * The First Bytes of the first subpacket must contain the checksum
+	 * Packet size in increase by one.
+	 */
+	for (i = 0; i < size; i += sizeof(u32)) {
+		size_t num;
+
+		num = min_t(size_t, size - i, sizeof(u32));
+		val = hdmi_infoframe_subpack(ptr, num);
+		ptr += sizeof(u32);
+		writel(val, hdmi->regs + pack_offset + i);
+	}
+
+	/* Enable transmission slot for updated infoframe */
+	val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
+	val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot);
+	hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+}
+
+/**
  * Prepare and configure the AVI infoframe
  *
  * AVI infoframe are transmitted at least once per two video field and
@@ -243,8 +340,6 @@
 	struct drm_display_mode *mode = &hdmi->mode;
 	struct hdmi_avi_infoframe infoframe;
 	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
-	u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE;
-	u32 val;
 	int ret;
 
 	DRM_DEBUG_DRIVER("\n");
@@ -266,47 +361,43 @@
 		return ret;
 	}
 
-	/* Disable transmission slot for AVI infoframe */
-	val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
-	val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI);
-	hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+	hdmi_infoframe_write_infopack(hdmi, buffer);
 
-	/* Infoframe header */
-	val =  buffer[0];
-	val |= buffer[1] << 8;
-	val |= buffer[2] << 16;
-	hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI));
+	return 0;
+}
 
-	/* Infoframe packet bytes */
-	val =  buffer[3];
-	val |= *(frame++) << 8;
-	val |= *(frame++) << 16;
-	val |= *(frame++) << 24;
-	hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI));
+/**
+ * Prepare and configure the AUDIO infoframe
+ *
+ * AUDIO infoframe are transmitted once per frame and
+ * contains information about HDMI transmission mode such as audio codec,
+ * sample size, ...
+ *
+ * @hdmi: pointer on the hdmi internal structure
+ *
+ * Return negative value if error occurs
+ */
+static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
+{
+	struct hdmi_audio_infoframe infofame;
+	u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
+	int ret;
 
-	val =  *(frame++);
-	val |= *(frame++) << 8;
-	val |= *(frame++) << 16;
-	val |= *(frame++) << 24;
-	hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI));
+	ret = hdmi_audio_infoframe_init(&infofame);
+	if (ret < 0) {
+		DRM_ERROR("failed to setup audio infoframe: %d\n", ret);
+		return ret;
+	}
 
-	val =  *(frame++);
-	val |= *(frame++) << 8;
-	val |= *(frame++) << 16;
-	val |= *(frame++) << 24;
-	hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI));
+	infofame.channels = 2;
 
-	val = *(frame++);
-	val |= *(frame) << 8;
-	hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI));
+	ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer));
+	if (ret < 0) {
+		DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
+		return ret;
+	}
 
-	/* Enable transmission slot for AVI infoframe
-	 * According to the hdmi specification, AVI infoframe should be
-	 * transmitted at least once per two video fields
-	 */
-	val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
-	val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI);
-	hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+	hdmi_infoframe_write_infopack(hdmi, buffer);
 
 	return 0;
 }
@@ -427,6 +518,10 @@
 	if (hdmi_avi_infoframe_config(hdmi))
 		DRM_ERROR("Unable to configure AVI infoframe\n");
 
+	/* Program AUDIO infoframe */
+	if (hdmi_audio_infoframe_config(hdmi))
+		DRM_ERROR("Unable to configure AUDIO infoframe\n");
+
 	/* Sw reset */
 	hdmi_swreset(hdmi);
 }
@@ -463,19 +558,12 @@
 	/* do nothing */
 }
 
-static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
-{
-	drm_bridge_cleanup(bridge);
-	kfree(bridge);
-}
-
 static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
 	.pre_enable = sti_hdmi_pre_enable,
 	.enable = sti_hdmi_bridge_nope,
 	.disable = sti_hdmi_disable,
 	.post_disable = sti_hdmi_bridge_nope,
 	.mode_set = sti_hdmi_set_mode,
-	.destroy = sti_hdmi_brigde_destroy,
 };
 
 static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -635,7 +723,8 @@
 		goto err_adapt;
 
 	bridge->driver_private = hdmi;
-	drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
+	bridge->funcs = &sti_hdmi_bridge_funcs;
+	drm_bridge_attach(drm_dev, bridge);
 
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
@@ -667,7 +756,6 @@
 err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
-	drm_bridge_cleanup(bridge);
 	drm_connector_cleanup(drm_connector);
 err_adapt:
 	put_device(&hdmi->ddc_adapt->dev);
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index f3db05d..b0eb62d 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1025,7 +1025,7 @@
 	/* Get clock resources */
 	hqvdp->clk = devm_clk_get(dev, "hqvdp");
 	hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main");
-	if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk)) {
+	if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk_pix_main)) {
 		DRM_ERROR("Cannot get clocks\n");
 		return -ENXIO;
 	}
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index cb924aa..5cc5311 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -48,6 +48,9 @@
 #define TVO_HDMI_CLIP_VALUE_R_CR         0x514
 #define TVO_HDMI_SYNC_SEL                0x518
 #define TVO_HDMI_DFV_OBS                 0x540
+#define TVO_VIP_DVO                      0x600
+#define TVO_DVO_SYNC_SEL                 0x618
+#define TVO_DVO_CONFIG                   0x620
 
 #define TVO_IN_FMT_SIGNED                BIT(0)
 #define TVO_SYNC_EXT                     BIT(4)
@@ -98,6 +101,9 @@
 
 #define TVO_SYNC_HD_DCS_SHIFT            8
 
+#define TVO_SYNC_DVO_PAD_HSYNC_SHIFT     8
+#define TVO_SYNC_DVO_PAD_VSYNC_SHIFT     16
+
 #define ENCODER_CRTC_MASK                (BIT(0) | BIT(1))
 
 /* enum listing the supported output data format */
@@ -113,6 +119,7 @@
 	struct reset_control *reset;
 	struct drm_encoder *hdmi;
 	struct drm_encoder *hda;
+	struct drm_encoder *dvo;
 };
 
 struct sti_tvout_encoder {
@@ -262,6 +269,66 @@
 }
 
 /**
+ * Start VIP block for DVO output
+ *
+ * @tvout: pointer on tvout structure
+ * @main_path: true if main path has to be used in the vip configuration
+ *	  else aux path is used.
+ */
+static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
+{
+	struct device_node *node = tvout->dev->of_node;
+	bool sel_input_logic_inverted = false;
+	u32 tvo_in_vid_format;
+	int val;
+
+	dev_dbg(tvout->dev, "%s\n", __func__);
+
+	if (main_path) {
+		DRM_DEBUG_DRIVER("main vip for DVO\n");
+		/* Select the input sync for dvo = VTG set 4 */
+		val  = TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
+		val |= TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
+		val |= TVO_SYNC_MAIN_VTG_SET_4;
+		tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
+		tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
+	} else {
+		DRM_DEBUG_DRIVER("aux vip for DVO\n");
+		/* Select the input sync for dvo = VTG set 4 */
+		val  = TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
+		val |= TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
+		val |= TVO_SYNC_AUX_VTG_SET_4;
+		tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
+		tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
+	}
+
+	/* Set color channel order */
+	tvout_vip_set_color_order(tvout, TVO_VIP_DVO,
+				  TVO_VIP_REORDER_CR_R_SEL,
+				  TVO_VIP_REORDER_Y_G_SEL,
+				  TVO_VIP_REORDER_CB_B_SEL);
+
+	/* Set clipping mode (Limited range RGB/Y) */
+	tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO,
+				TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y);
+
+	/* Set round mode (rounded to 8-bit per component) */
+	tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
+
+	if (of_device_is_compatible(node, "st,stih407-tvout")) {
+		/* Set input video format */
+		tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format,
+					 TVO_IN_FMT_SIGNED);
+		sel_input_logic_inverted = true;
+	}
+
+	/* Input selection */
+	tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path,
+				sel_input_logic_inverted,
+				STI_TVOUT_VIDEO_OUT_RGB);
+}
+
+/**
  * Start VIP block for HDMI output
  *
  * @tvout: pointer on tvout structure
@@ -402,6 +469,56 @@
 	.destroy = sti_tvout_encoder_destroy,
 };
 
+static void sti_dvo_encoder_commit(struct drm_encoder *encoder)
+{
+	struct sti_tvout *tvout = to_sti_tvout(encoder);
+
+	tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
+}
+
+static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
+{
+	struct sti_tvout *tvout = to_sti_tvout(encoder);
+
+	/* Reset VIP register */
+	tvout_write(tvout, 0x0, TVO_VIP_DVO);
+}
+
+static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
+	.dpms = sti_tvout_encoder_dpms,
+	.mode_fixup = sti_tvout_encoder_mode_fixup,
+	.mode_set = sti_tvout_encoder_mode_set,
+	.prepare = sti_tvout_encoder_prepare,
+	.commit = sti_dvo_encoder_commit,
+	.disable = sti_dvo_encoder_disable,
+};
+
+static struct drm_encoder *
+sti_tvout_create_dvo_encoder(struct drm_device *dev,
+			     struct sti_tvout *tvout)
+{
+	struct sti_tvout_encoder *encoder;
+	struct drm_encoder *drm_encoder;
+
+	encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
+	if (!encoder)
+		return NULL;
+
+	encoder->tvout = tvout;
+
+	drm_encoder = (struct drm_encoder *)encoder;
+
+	drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
+	drm_encoder->possible_clones = 1 << 0;
+
+	drm_encoder_init(dev, drm_encoder,
+			 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS);
+
+	drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs);
+
+	return drm_encoder;
+}
+
 static void sti_hda_encoder_commit(struct drm_encoder *encoder)
 {
 	struct sti_tvout *tvout = to_sti_tvout(encoder);
@@ -508,6 +625,7 @@
 {
 	tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout);
 	tvout->hda = sti_tvout_create_hda_encoder(dev, tvout);
+	tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout);
 }
 
 static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 978993f..3aaa84a 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -18,9 +18,12 @@
 #include "drm.h"
 #include "gem.h"
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 
 struct tegra_dc_soc_info {
+	bool supports_border_color;
 	bool supports_interlacing;
 	bool supports_cursor;
 	bool supports_block_linear;
@@ -38,63 +41,122 @@
 	return container_of(plane, struct tegra_plane, base);
 }
 
-static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
-{
-	u32 value = WIN_A_ACT_REQ << index;
+struct tegra_dc_state {
+	struct drm_crtc_state base;
 
-	tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
+	struct clk *clk;
+	unsigned long pclk;
+	unsigned int div;
+
+	u32 planes;
+};
+
+static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
+{
+	if (state)
+		return container_of(state, struct tegra_dc_state, base);
+
+	return NULL;
 }
 
-static void tegra_dc_cursor_commit(struct tegra_dc *dc)
+struct tegra_plane_state {
+	struct drm_plane_state base;
+
+	struct tegra_bo_tiling tiling;
+	u32 format;
+	u32 swap;
+};
+
+static inline struct tegra_plane_state *
+to_tegra_plane_state(struct drm_plane_state *state)
 {
-	tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
+	if (state)
+		return container_of(state, struct tegra_plane_state, base);
+
+	return NULL;
 }
 
-static void tegra_dc_commit(struct tegra_dc *dc)
+/*
+ * Reads the active copy of a register. This takes the dc->lock spinlock to
+ * prevent races with the VBLANK processing which also needs access to the
+ * active copy of some registers.
+ */
+static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset)
+{
+	unsigned long flags;
+	u32 value;
+
+	spin_lock_irqsave(&dc->lock, flags);
+
+	tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
+	value = tegra_dc_readl(dc, offset);
+	tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
+
+	spin_unlock_irqrestore(&dc->lock, flags);
+	return value;
+}
+
+/*
+ * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the
+ * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy.
+ * Latching happens mmediately if the display controller is in STOP mode or
+ * on the next frame boundary otherwise.
+ *
+ * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The
+ * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits
+ * are written. When the *_ACT_REQ bits are written, the ARM copy is latched
+ * into the ACTIVE copy, either immediately if the display controller is in
+ * STOP mode, or at the next frame boundary otherwise.
+ */
+void tegra_dc_commit(struct tegra_dc *dc)
 {
 	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
 	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 }
 
-static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
+static int tegra_dc_format(u32 fourcc, u32 *format, u32 *swap)
 {
 	/* assume no swapping of fetched data */
 	if (swap)
 		*swap = BYTE_SWAP_NOSWAP;
 
-	switch (format) {
+	switch (fourcc) {
 	case DRM_FORMAT_XBGR8888:
-		return WIN_COLOR_DEPTH_R8G8B8A8;
+		*format = WIN_COLOR_DEPTH_R8G8B8A8;
+		break;
 
 	case DRM_FORMAT_XRGB8888:
-		return WIN_COLOR_DEPTH_B8G8R8A8;
+		*format = WIN_COLOR_DEPTH_B8G8R8A8;
+		break;
 
 	case DRM_FORMAT_RGB565:
-		return WIN_COLOR_DEPTH_B5G6R5;
+		*format = WIN_COLOR_DEPTH_B5G6R5;
+		break;
 
 	case DRM_FORMAT_UYVY:
-		return WIN_COLOR_DEPTH_YCbCr422;
+		*format = WIN_COLOR_DEPTH_YCbCr422;
+		break;
 
 	case DRM_FORMAT_YUYV:
 		if (swap)
 			*swap = BYTE_SWAP_SWAP2;
 
-		return WIN_COLOR_DEPTH_YCbCr422;
+		*format = WIN_COLOR_DEPTH_YCbCr422;
+		break;
 
 	case DRM_FORMAT_YUV420:
-		return WIN_COLOR_DEPTH_YCbCr420P;
+		*format = WIN_COLOR_DEPTH_YCbCr420P;
+		break;
 
 	case DRM_FORMAT_YUV422:
-		return WIN_COLOR_DEPTH_YCbCr422P;
+		*format = WIN_COLOR_DEPTH_YCbCr422P;
+		break;
 
 	default:
-		break;
+		return -EINVAL;
 	}
 
-	WARN(1, "unsupported pixel format %u, using default\n", format);
-	return WIN_COLOR_DEPTH_B8G8R8A8;
+	return 0;
 }
 
 static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
@@ -121,6 +183,9 @@
 		return true;
 	}
 
+	if (planar)
+		*planar = false;
+
 	return false;
 }
 
@@ -164,8 +229,8 @@
 	return dfixed_frac(inf);
 }
 
-static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
-				 const struct tegra_dc_window *window)
+static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
+				  const struct tegra_dc_window *window)
 {
 	unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
 	unsigned long value, flags;
@@ -274,9 +339,11 @@
 			break;
 
 		case TEGRA_BO_TILING_MODE_BLOCK:
-			DRM_ERROR("hardware doesn't support block linear mode\n");
-			spin_unlock_irqrestore(&dc->lock, flags);
-			return -EINVAL;
+			/*
+			 * No need to handle this here because ->atomic_check
+			 * will already have filtered it out.
+			 */
+			break;
 		}
 
 		tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
@@ -332,37 +399,7 @@
 		break;
 	}
 
-	tegra_dc_window_commit(dc, index);
-
 	spin_unlock_irqrestore(&dc->lock, flags);
-
-	return 0;
-}
-
-static int tegra_window_plane_disable(struct drm_plane *plane)
-{
-	struct tegra_dc *dc = to_tegra_dc(plane->crtc);
-	struct tegra_plane *p = to_tegra_plane(plane);
-	unsigned long flags;
-	u32 value;
-
-	if (!plane->crtc)
-		return 0;
-
-	spin_lock_irqsave(&dc->lock, flags);
-
-	value = WINDOW_A_SELECT << p->index;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
-
-	value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-	value &= ~WIN_ENABLE;
-	tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
-	tegra_dc_window_commit(dc, p->index);
-
-	spin_unlock_irqrestore(&dc->lock, flags);
-
-	return 0;
 }
 
 static void tegra_plane_destroy(struct drm_plane *plane)
@@ -379,62 +416,228 @@
 	DRM_FORMAT_RGB565,
 };
 
-static int tegra_primary_plane_update(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 void tegra_primary_plane_destroy(struct drm_plane *plane)
 {
-	struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
-	struct tegra_plane *p = to_tegra_plane(plane);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-	struct tegra_dc_window window;
+	tegra_plane_destroy(plane);
+}
+
+static void tegra_plane_reset(struct drm_plane *plane)
+{
+	struct tegra_plane_state *state;
+
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
+	kfree(plane->state);
+	plane->state = NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state) {
+		plane->state = &state->base;
+		plane->state->plane = plane;
+	}
+}
+
+static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
+	struct tegra_plane_state *copy;
+
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	if (copy->base.fb)
+		drm_framebuffer_reference(copy->base.fb);
+
+	return &copy->base;
+}
+
+static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
+					     struct drm_plane_state *state)
+{
+	if (state->fb)
+		drm_framebuffer_unreference(state->fb);
+
+	kfree(state);
+}
+
+static const struct drm_plane_funcs tegra_primary_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = tegra_primary_plane_destroy,
+	.reset = tegra_plane_reset,
+	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
+};
+
+static int tegra_plane_prepare_fb(struct drm_plane *plane,
+				  struct drm_framebuffer *fb)
+{
+	return 0;
+}
+
+static void tegra_plane_cleanup_fb(struct drm_plane *plane,
+				   struct drm_framebuffer *fb)
+{
+}
+
+static int tegra_plane_state_add(struct tegra_plane *plane,
+				 struct drm_plane_state *state)
+{
+	struct drm_crtc_state *crtc_state;
+	struct tegra_dc_state *tegra;
+
+	/* Propagate errors from allocation or locking failures. */
+	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	tegra = to_dc_state(crtc_state);
+
+	tegra->planes |= WIN_A_ACT_REQ << plane->index;
+
+	return 0;
+}
+
+static int tegra_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
+	struct tegra_bo_tiling *tiling = &plane_state->tiling;
+	struct tegra_plane *tegra = to_tegra_plane(plane);
+	struct tegra_dc *dc = to_tegra_dc(state->crtc);
 	int err;
 
-	memset(&window, 0, sizeof(window));
-	window.src.x = src_x >> 16;
-	window.src.y = src_y >> 16;
-	window.src.w = src_w >> 16;
-	window.src.h = src_h >> 16;
-	window.dst.x = crtc_x;
-	window.dst.y = crtc_y;
-	window.dst.w = crtc_w;
-	window.dst.h = crtc_h;
-	window.format = tegra_dc_format(fb->pixel_format, &window.swap);
-	window.bits_per_pixel = fb->bits_per_pixel;
-	window.bottom_up = tegra_fb_is_bottom_up(fb);
+	/* no need for further checks if the plane is being disabled */
+	if (!state->crtc)
+		return 0;
 
-	err = tegra_fb_get_tiling(fb, &window.tiling);
+	err = tegra_dc_format(state->fb->pixel_format, &plane_state->format,
+			      &plane_state->swap);
 	if (err < 0)
 		return err;
 
-	window.base[0] = bo->paddr + fb->offsets[0];
-	window.stride[0] = fb->pitches[0];
+	err = tegra_fb_get_tiling(state->fb, tiling);
+	if (err < 0)
+		return err;
 
-	err = tegra_dc_setup_window(dc, p->index, &window);
+	if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
+	    !dc->soc->supports_block_linear) {
+		DRM_ERROR("hardware doesn't support block linear mode\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Tegra doesn't support different strides for U and V planes so we
+	 * error out if the user tries to display a framebuffer with such a
+	 * configuration.
+	 */
+	if (drm_format_num_planes(state->fb->pixel_format) > 2) {
+		if (state->fb->pitches[2] != state->fb->pitches[1]) {
+			DRM_ERROR("unsupported UV-plane configuration\n");
+			return -EINVAL;
+		}
+	}
+
+	err = tegra_plane_state_add(tegra, state);
 	if (err < 0)
 		return err;
 
 	return 0;
 }
 
-static void tegra_primary_plane_destroy(struct drm_plane *plane)
+static void tegra_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
 {
-	tegra_window_plane_disable(plane);
-	tegra_plane_destroy(plane);
+	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
+	struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
+	struct drm_framebuffer *fb = plane->state->fb;
+	struct tegra_plane *p = to_tegra_plane(plane);
+	struct tegra_dc_window window;
+	unsigned int i;
+
+	/* rien ne va plus */
+	if (!plane->state->crtc || !plane->state->fb)
+		return;
+
+	memset(&window, 0, sizeof(window));
+	window.src.x = plane->state->src_x >> 16;
+	window.src.y = plane->state->src_y >> 16;
+	window.src.w = plane->state->src_w >> 16;
+	window.src.h = plane->state->src_h >> 16;
+	window.dst.x = plane->state->crtc_x;
+	window.dst.y = plane->state->crtc_y;
+	window.dst.w = plane->state->crtc_w;
+	window.dst.h = plane->state->crtc_h;
+	window.bits_per_pixel = fb->bits_per_pixel;
+	window.bottom_up = tegra_fb_is_bottom_up(fb);
+
+	/* copy from state */
+	window.tiling = state->tiling;
+	window.format = state->format;
+	window.swap = state->swap;
+
+	for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
+		struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
+
+		window.base[i] = bo->paddr + fb->offsets[i];
+		window.stride[i] = fb->pitches[i];
+	}
+
+	tegra_dc_setup_window(dc, p->index, &window);
 }
 
-static const struct drm_plane_funcs tegra_primary_plane_funcs = {
-	.update_plane = tegra_primary_plane_update,
-	.disable_plane = tegra_window_plane_disable,
-	.destroy = tegra_primary_plane_destroy,
+static void tegra_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct tegra_plane *p = to_tegra_plane(plane);
+	struct tegra_dc *dc;
+	unsigned long flags;
+	u32 value;
+
+	/* rien ne va plus */
+	if (!old_state || !old_state->crtc)
+		return;
+
+	dc = to_tegra_dc(old_state->crtc);
+
+	spin_lock_irqsave(&dc->lock, flags);
+
+	value = WINDOW_A_SELECT << p->index;
+	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+	value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+	value &= ~WIN_ENABLE;
+	tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+	spin_unlock_irqrestore(&dc->lock, flags);
+}
+
+static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
+	.prepare_fb = tegra_plane_prepare_fb,
+	.cleanup_fb = tegra_plane_cleanup_fb,
+	.atomic_check = tegra_plane_atomic_check,
+	.atomic_update = tegra_plane_atomic_update,
+	.atomic_disable = tegra_plane_atomic_disable,
 };
 
 static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
 						       struct tegra_dc *dc)
 {
+	/*
+	 * Ideally this would use drm_crtc_mask(), but that would require the
+	 * CRTC to already be in the mode_config's list of CRTCs. However, it
+	 * will only be added to that list in the drm_crtc_init_with_planes()
+	 * (in tegra_dc_init()), which in turn requires registration of these
+	 * planes. So we have ourselves a nice little chicken and egg problem
+	 * here.
+	 *
+	 * We work around this by manually creating the mask from the number
+	 * of CRTCs that have been registered, and should therefore always be
+	 * the same as drm_crtc_index() after registration.
+	 */
+	unsigned long possible_crtcs = 1 << drm->mode_config.num_crtc;
 	struct tegra_plane *plane;
 	unsigned int num_formats;
 	const u32 *formats;
@@ -447,7 +650,7 @@
 	num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
 	formats = tegra_primary_plane_formats;
 
-	err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
+	err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
 				       &tegra_primary_plane_funcs, formats,
 				       num_formats, DRM_PLANE_TYPE_PRIMARY);
 	if (err < 0) {
@@ -455,6 +658,8 @@
 		return ERR_PTR(err);
 	}
 
+	drm_plane_helper_add(&plane->base, &tegra_primary_plane_helper_funcs);
+
 	return &plane->base;
 }
 
@@ -462,27 +667,49 @@
 	DRM_FORMAT_RGBA8888,
 };
 
-static int tegra_cursor_plane_update(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 int tegra_cursor_atomic_check(struct drm_plane *plane,
+				     struct drm_plane_state *state)
 {
-	struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-	u32 value = CURSOR_CLIP_DISPLAY;
+	struct tegra_plane *tegra = to_tegra_plane(plane);
+	int err;
+
+	/* no need for further checks if the plane is being disabled */
+	if (!state->crtc)
+		return 0;
 
 	/* scaling not supported for cursor */
-	if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h))
+	if ((state->src_w >> 16 != state->crtc_w) ||
+	    (state->src_h >> 16 != state->crtc_h))
 		return -EINVAL;
 
 	/* only square cursors supported */
-	if (src_w != src_h)
+	if (state->src_w != state->src_h)
 		return -EINVAL;
 
-	switch (crtc_w) {
+	if (state->crtc_w != 32 && state->crtc_w != 64 &&
+	    state->crtc_w != 128 && state->crtc_w != 256)
+		return -EINVAL;
+
+	err = tegra_plane_state_add(tegra, state);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void tegra_cursor_atomic_update(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0);
+	struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
+	struct drm_plane_state *state = plane->state;
+	u32 value = CURSOR_CLIP_DISPLAY;
+
+	/* rien ne va plus */
+	if (!plane->state->crtc || !plane->state->fb)
+		return;
+
+	switch (state->crtc_w) {
 	case 32:
 		value |= CURSOR_SIZE_32x32;
 		break;
@@ -500,7 +727,9 @@
 		break;
 
 	default:
-		return -EINVAL;
+		WARN(1, "cursor size %ux%u not supported\n", state->crtc_w,
+		     state->crtc_h);
+		return;
 	}
 
 	value |= (bo->paddr >> 10) & 0x3fffff;
@@ -526,38 +755,43 @@
 	tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
 
 	/* position the cursor */
-	value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff);
+	value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
 	tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
 
-	/* apply changes */
-	tegra_dc_cursor_commit(dc);
-	tegra_dc_commit(dc);
-
-	return 0;
 }
 
-static int tegra_cursor_plane_disable(struct drm_plane *plane)
+static void tegra_cursor_atomic_disable(struct drm_plane *plane,
+					struct drm_plane_state *old_state)
 {
-	struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+	struct tegra_dc *dc;
 	u32 value;
 
-	if (!plane->crtc)
-		return 0;
+	/* rien ne va plus */
+	if (!old_state || !old_state->crtc)
+		return;
+
+	dc = to_tegra_dc(old_state->crtc);
 
 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
 	value &= ~CURSOR_ENABLE;
 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-	tegra_dc_cursor_commit(dc);
-	tegra_dc_commit(dc);
-
-	return 0;
 }
 
 static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
-	.update_plane = tegra_cursor_plane_update,
-	.disable_plane = tegra_cursor_plane_disable,
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
 	.destroy = tegra_plane_destroy,
+	.reset = tegra_plane_reset,
+	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
+};
+
+static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
+	.prepare_fb = tegra_plane_prepare_fb,
+	.cleanup_fb = tegra_plane_cleanup_fb,
+	.atomic_check = tegra_cursor_atomic_check,
+	.atomic_update = tegra_cursor_atomic_update,
+	.atomic_disable = tegra_cursor_atomic_disable,
 };
 
 static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
@@ -572,6 +806,13 @@
 	if (!plane)
 		return ERR_PTR(-ENOMEM);
 
+	/*
+	 * We'll treat the cursor as an overlay plane with index 6 here so
+	 * that the update and activation request bits in DC_CMD_STATE_CONTROL
+	 * match up.
+	 */
+	plane->index = 6;
+
 	num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
 	formats = tegra_cursor_plane_formats;
 
@@ -583,71 +824,23 @@
 		return ERR_PTR(err);
 	}
 
+	drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs);
+
 	return &plane->base;
 }
 
-static int tegra_overlay_plane_update(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 tegra_plane *p = to_tegra_plane(plane);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-	struct tegra_dc_window window;
-	unsigned int i;
-	int err;
-
-	memset(&window, 0, sizeof(window));
-	window.src.x = src_x >> 16;
-	window.src.y = src_y >> 16;
-	window.src.w = src_w >> 16;
-	window.src.h = src_h >> 16;
-	window.dst.x = crtc_x;
-	window.dst.y = crtc_y;
-	window.dst.w = crtc_w;
-	window.dst.h = crtc_h;
-	window.format = tegra_dc_format(fb->pixel_format, &window.swap);
-	window.bits_per_pixel = fb->bits_per_pixel;
-	window.bottom_up = tegra_fb_is_bottom_up(fb);
-
-	err = tegra_fb_get_tiling(fb, &window.tiling);
-	if (err < 0)
-		return err;
-
-	for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
-		struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
-
-		window.base[i] = bo->paddr + fb->offsets[i];
-
-		/*
-		 * Tegra doesn't support different strides for U and V planes
-		 * so we display a warning if the user tries to display a
-		 * framebuffer with such a configuration.
-		 */
-		if (i >= 2) {
-			if (fb->pitches[i] != window.stride[1])
-				DRM_ERROR("unsupported UV-plane configuration\n");
-		} else {
-			window.stride[i] = fb->pitches[i];
-		}
-	}
-
-	return tegra_dc_setup_window(dc, p->index, &window);
-}
-
 static void tegra_overlay_plane_destroy(struct drm_plane *plane)
 {
-	tegra_window_plane_disable(plane);
 	tegra_plane_destroy(plane);
 }
 
 static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
-	.update_plane = tegra_overlay_plane_update,
-	.disable_plane = tegra_window_plane_disable,
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
 	.destroy = tegra_overlay_plane_destroy,
+	.reset = tegra_plane_reset,
+	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
 };
 
 static const uint32_t tegra_overlay_plane_formats[] = {
@@ -660,6 +853,14 @@
 	DRM_FORMAT_YUV422,
 };
 
+static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
+	.prepare_fb = tegra_plane_prepare_fb,
+	.cleanup_fb = tegra_plane_cleanup_fb,
+	.atomic_check = tegra_plane_atomic_check,
+	.atomic_update = tegra_plane_atomic_update,
+	.atomic_disable = tegra_plane_atomic_disable,
+};
+
 static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
 						       struct tegra_dc *dc,
 						       unsigned int index)
@@ -686,6 +887,8 @@
 		return ERR_PTR(err);
 	}
 
+	drm_plane_helper_add(&plane->base, &tegra_overlay_plane_helper_funcs);
+
 	return &plane->base;
 }
 
@@ -703,99 +906,6 @@
 	return 0;
 }
 
-static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
-			     struct drm_framebuffer *fb)
-{
-	struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
-	unsigned int h_offset = 0, v_offset = 0;
-	struct tegra_bo_tiling tiling;
-	unsigned long value, flags;
-	unsigned int format, swap;
-	int err;
-
-	err = tegra_fb_get_tiling(fb, &tiling);
-	if (err < 0)
-		return err;
-
-	spin_lock_irqsave(&dc->lock, flags);
-
-	tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
-
-	value = fb->offsets[0] + y * fb->pitches[0] +
-		x * fb->bits_per_pixel / 8;
-
-	tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
-	tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
-
-	format = tegra_dc_format(fb->pixel_format, &swap);
-	tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
-	tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
-
-	if (dc->soc->supports_block_linear) {
-		unsigned long height = tiling.value;
-
-		switch (tiling.mode) {
-		case TEGRA_BO_TILING_MODE_PITCH:
-			value = DC_WINBUF_SURFACE_KIND_PITCH;
-			break;
-
-		case TEGRA_BO_TILING_MODE_TILED:
-			value = DC_WINBUF_SURFACE_KIND_TILED;
-			break;
-
-		case TEGRA_BO_TILING_MODE_BLOCK:
-			value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
-				DC_WINBUF_SURFACE_KIND_BLOCK;
-			break;
-		}
-
-		tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
-	} else {
-		switch (tiling.mode) {
-		case TEGRA_BO_TILING_MODE_PITCH:
-			value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
-				DC_WIN_BUFFER_ADDR_MODE_LINEAR;
-			break;
-
-		case TEGRA_BO_TILING_MODE_TILED:
-			value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
-				DC_WIN_BUFFER_ADDR_MODE_TILE;
-			break;
-
-		case TEGRA_BO_TILING_MODE_BLOCK:
-			DRM_ERROR("hardware doesn't support block linear mode\n");
-			spin_unlock_irqrestore(&dc->lock, flags);
-			return -EINVAL;
-		}
-
-		tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
-	}
-
-	/* make sure bottom-up buffers are properly displayed */
-	if (tegra_fb_is_bottom_up(fb)) {
-		value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-		value |= V_DIRECTION;
-		tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
-		v_offset += fb->height - 1;
-	} else {
-		value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-		value &= ~V_DIRECTION;
-		tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-	}
-
-	tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
-	tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
-
-	value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
-	tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
-
-	spin_unlock_irqrestore(&dc->lock, flags);
-
-	return 0;
-}
-
 void tegra_dc_enable_vblank(struct tegra_dc *dc)
 {
 	unsigned long value, flags;
@@ -838,7 +948,7 @@
 
 	bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 
-	spin_lock_irqsave(&dc->lock, flags);
+	spin_lock(&dc->lock);
 
 	/* check if new start address has been latched */
 	tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -846,7 +956,7 @@
 	base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
 	tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
 
-	spin_unlock_irqrestore(&dc->lock, flags);
+	spin_unlock(&dc->lock);
 
 	if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
 		drm_crtc_send_vblank_event(crtc, dc->event);
@@ -874,64 +984,130 @@
 	spin_unlock_irqrestore(&drm->event_lock, flags);
 }
 
-static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			      struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
-{
-	unsigned int pipe = drm_crtc_index(crtc);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-
-	if (dc->event)
-		return -EBUSY;
-
-	if (event) {
-		event->pipe = pipe;
-		dc->event = event;
-		drm_crtc_vblank_get(crtc);
-	}
-
-	tegra_dc_set_base(dc, 0, 0, fb);
-	crtc->primary->fb = fb;
-
-	return 0;
-}
-
-static void drm_crtc_clear(struct drm_crtc *crtc)
-{
-	memset(crtc, 0, sizeof(*crtc));
-}
-
 static void tegra_dc_destroy(struct drm_crtc *crtc)
 {
 	drm_crtc_cleanup(crtc);
-	drm_crtc_clear(crtc);
+}
+
+static void tegra_crtc_reset(struct drm_crtc *crtc)
+{
+	struct tegra_dc_state *state;
+
+	kfree(crtc->state);
+	crtc->state = NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state)
+		crtc->state = &state->base;
+}
+
+static struct drm_crtc_state *
+tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc_state *copy;
+
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	copy->base.mode_changed = false;
+	copy->base.planes_changed = false;
+	copy->base.event = NULL;
+
+	return &copy->base;
+}
+
+static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+					    struct drm_crtc_state *state)
+{
+	kfree(state);
 }
 
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
-	.page_flip = tegra_dc_page_flip,
-	.set_config = drm_crtc_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
 	.destroy = tegra_dc_destroy,
+	.reset = tegra_crtc_reset,
+	.atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,
+	.atomic_destroy_state = tegra_crtc_atomic_destroy_state,
 };
 
+static void tegra_dc_stop(struct tegra_dc *dc)
+{
+	u32 value;
+
+	/* stop the display controller */
+	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+	value &= ~DISP_CTRL_MODE_MASK;
+	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+	tegra_dc_commit(dc);
+}
+
+static bool tegra_dc_idle(struct tegra_dc *dc)
+{
+	u32 value;
+
+	value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
+
+	return (value & DISP_CTRL_MODE_MASK) == 0;
+}
+
+static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
+{
+	timeout = jiffies + msecs_to_jiffies(timeout);
+
+	while (time_before(jiffies, timeout)) {
+		if (tegra_dc_idle(dc))
+			return 0;
+
+		usleep_range(1000, 2000);
+	}
+
+	dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
+	return -ETIMEDOUT;
+}
+
 static void tegra_crtc_disable(struct drm_crtc *crtc)
 {
 	struct tegra_dc *dc = to_tegra_dc(crtc);
-	struct drm_device *drm = crtc->dev;
-	struct drm_plane *plane;
+	u32 value;
 
-	drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
-		if (plane->crtc == crtc) {
-			tegra_window_plane_disable(plane);
-			plane->crtc = NULL;
+	if (!tegra_dc_idle(dc)) {
+		tegra_dc_stop(dc);
 
-			if (plane->fb) {
-				drm_framebuffer_unreference(plane->fb);
-				plane->fb = NULL;
-			}
-		}
+		/*
+		 * Ignore the return value, there isn't anything useful to do
+		 * in case this fails.
+		 */
+		tegra_dc_wait_idle(dc, 100);
+	}
+
+	/*
+	 * This should really be part of the RGB encoder driver, but clearing
+	 * these bits has the side-effect of stopping the display controller.
+	 * When that happens no VBLANK interrupts will be raised. At the same
+	 * time the encoder is disabled before the display controller, so the
+	 * above code is always going to timeout waiting for the controller
+	 * to go idle.
+	 *
+	 * Given the close coupling between the RGB encoder and the display
+	 * controller doing it here is still kind of okay. None of the other
+	 * encoder drivers require these bits to be cleared.
+	 *
+	 * XXX: Perhaps given that the display controller is switched off at
+	 * this point anyway maybe clearing these bits isn't even useful for
+	 * the RGB encoder?
+	 */
+	if (dc->rgb) {
+		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
 	}
 
 	drm_crtc_vblank_off(crtc);
-	tegra_dc_commit(dc);
 }
 
 static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -971,33 +1147,15 @@
 	return 0;
 }
 
-static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
-				struct drm_display_mode *mode)
+int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
+			 unsigned long pclk, unsigned int div)
 {
-	unsigned long pclk = mode->clock * 1000;
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-	struct tegra_output *output = NULL;
-	struct drm_encoder *encoder;
-	unsigned int div;
 	u32 value;
-	long err;
+	int err;
 
-	list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head)
-		if (encoder->crtc == crtc) {
-			output = encoder_to_output(encoder);
-			break;
-		}
-
-	if (!output)
-		return -ENODEV;
-
-	/*
-	 * This assumes that the parent clock is pll_d_out0 or pll_d2_out
-	 * respectively, each of which divides the base pll_d by 2.
-	 */
-	err = tegra_output_setup_clock(output, dc->clk, pclk, &div);
+	err = clk_set_parent(dc->clk, parent);
 	if (err < 0) {
-		dev_err(dc->dev, "failed to setup clock: %ld\n", err);
+		dev_err(dc->dev, "failed to set parent clock: %d\n", err);
 		return err;
 	}
 
@@ -1009,26 +1167,69 @@
 	return 0;
 }
 
-static int tegra_crtc_mode_set(struct drm_crtc *crtc,
-			       struct drm_display_mode *mode,
-			       struct drm_display_mode *adjusted,
-			       int x, int y, struct drm_framebuffer *old_fb)
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+			       struct drm_crtc_state *crtc_state,
+			       struct clk *clk, unsigned long pclk,
+			       unsigned int div)
 {
-	struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-	struct tegra_dc_window window;
+	struct tegra_dc_state *state = to_dc_state(crtc_state);
+
+	state->clk = clk;
+	state->pclk = pclk;
+	state->div = div;
+
+	return 0;
+}
+
+static void tegra_dc_commit_state(struct tegra_dc *dc,
+				  struct tegra_dc_state *state)
+{
 	u32 value;
 	int err;
 
-	err = tegra_crtc_setup_clk(crtc, mode);
-	if (err) {
-		dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
-		return err;
+	err = clk_set_parent(dc->clk, state->clk);
+	if (err < 0)
+		dev_err(dc->dev, "failed to set parent clock: %d\n", err);
+
+	/*
+	 * Outputs may not want to change the parent clock rate. This is only
+	 * relevant to Tegra20 where only a single display PLL is available.
+	 * Since that PLL would typically be used for HDMI, an internal LVDS
+	 * panel would need to be driven by some other clock such as PLL_P
+	 * which is shared with other peripherals. Changing the clock rate
+	 * should therefore be avoided.
+	 */
+	if (state->pclk > 0) {
+		err = clk_set_rate(state->clk, state->pclk);
+		if (err < 0)
+			dev_err(dc->dev,
+				"failed to set clock rate to %lu Hz\n",
+				state->pclk);
 	}
 
+	DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk),
+		      state->div);
+	DRM_DEBUG_KMS("pclk: %lu\n", state->pclk);
+
+	value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
+	tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
+}
+
+static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+	u32 value;
+
+	tegra_dc_commit_state(dc, state);
+
 	/* program display mode */
 	tegra_dc_set_timings(dc, mode);
 
+	if (dc->soc->supports_border_color)
+		tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
+
 	/* interlacing isn't supported yet, so disable it */
 	if (dc->soc->supports_interlacing) {
 		value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
@@ -1036,35 +1237,17 @@
 		tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
 	}
 
-	/* setup window parameters */
-	memset(&window, 0, sizeof(window));
-	window.src.x = 0;
-	window.src.y = 0;
-	window.src.w = mode->hdisplay;
-	window.src.h = mode->vdisplay;
-	window.dst.x = 0;
-	window.dst.y = 0;
-	window.dst.w = mode->hdisplay;
-	window.dst.h = mode->vdisplay;
-	window.format = tegra_dc_format(crtc->primary->fb->pixel_format,
-					&window.swap);
-	window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
-	window.stride[0] = crtc->primary->fb->pitches[0];
-	window.base[0] = bo->paddr;
+	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+	value &= ~DISP_CTRL_MODE_MASK;
+	value |= DISP_CTRL_MODE_C_DISPLAY;
+	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
 
-	err = tegra_dc_setup_window(dc, 0, &window);
-	if (err < 0)
-		dev_err(dc->dev, "failed to enable root plane\n");
+	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
 
-	return 0;
-}
-
-static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-				    struct drm_framebuffer *old_fb)
-{
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-
-	return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
+	tegra_dc_commit(dc);
 }
 
 static void tegra_crtc_prepare(struct drm_crtc *crtc)
@@ -1075,10 +1258,6 @@
 
 	drm_crtc_vblank_off(crtc);
 
-	/* hardware initialization */
-	reset_control_deassert(dc->rst);
-	usleep_range(10000, 20000);
-
 	if (dc->pipe)
 		syncpt = SYNCPT_VBLANK1;
 	else
@@ -1113,24 +1292,49 @@
 
 static void tegra_crtc_commit(struct drm_crtc *crtc)
 {
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-
 	drm_crtc_vblank_on(crtc);
-	tegra_dc_commit(dc);
 }
 
-static void tegra_crtc_load_lut(struct drm_crtc *crtc)
+static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
 {
+	return 0;
+}
+
+static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
+{
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+
+	if (crtc->state->event) {
+		crtc->state->event->pipe = drm_crtc_index(crtc);
+
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		dc->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
+}
+
+static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
+{
+	struct tegra_dc_state *state = to_dc_state(crtc->state);
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+
+	tegra_dc_writel(dc, state->planes << 8, DC_CMD_STATE_CONTROL);
+	tegra_dc_writel(dc, state->planes, DC_CMD_STATE_CONTROL);
 }
 
 static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
 	.disable = tegra_crtc_disable,
 	.mode_fixup = tegra_crtc_mode_fixup,
-	.mode_set = tegra_crtc_mode_set,
-	.mode_set_base = tegra_crtc_mode_set_base,
+	.mode_set = drm_helper_crtc_mode_set,
+	.mode_set_nofb = tegra_crtc_mode_set_nofb,
+	.mode_set_base = drm_helper_crtc_mode_set_base,
 	.prepare = tegra_crtc_prepare,
 	.commit = tegra_crtc_commit,
-	.load_lut = tegra_crtc_load_lut,
+	.atomic_check = tegra_crtc_atomic_check,
+	.atomic_begin = tegra_crtc_atomic_begin,
+	.atomic_flush = tegra_crtc_atomic_flush,
 };
 
 static irqreturn_t tegra_dc_irq(int irq, void *data)
@@ -1576,6 +1780,7 @@
 };
 
 static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
+	.supports_border_color = true,
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
@@ -1584,6 +1789,7 @@
 };
 
 static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
+	.supports_border_color = true,
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
@@ -1592,6 +1798,7 @@
 };
 
 static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
+	.supports_border_color = true,
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
@@ -1600,6 +1807,7 @@
 };
 
 static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
+	.supports_border_color = false,
 	.supports_interlacing = true,
 	.supports_cursor = true,
 	.supports_block_linear = true,
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index d4f8275..7dd328d 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -10,6 +10,9 @@
 #include <linux/host1x.h>
 #include <linux/iommu.h>
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+
 #include "drm.h"
 #include "gem.h"
 
@@ -24,6 +27,92 @@
 	struct list_head contexts;
 };
 
+static void tegra_atomic_schedule(struct tegra_drm *tegra,
+				  struct drm_atomic_state *state)
+{
+	tegra->commit.state = state;
+	schedule_work(&tegra->commit.work);
+}
+
+static void tegra_atomic_complete(struct tegra_drm *tegra,
+				  struct drm_atomic_state *state)
+{
+	struct drm_device *drm = tegra->drm;
+
+	/*
+	 * Everything below can be run asynchronously without the need to grab
+	 * any modeset locks at all under one condition: It must be guaranteed
+	 * that the asynchronous work has either been cancelled (if the driver
+	 * supports it, which at least requires that the framebuffers get
+	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+	 * before the new state gets committed on the software side with
+	 * drm_atomic_helper_swap_state().
+	 *
+	 * This scheme allows new atomic state updates to be prepared and
+	 * checked in parallel to the asynchronous completion of the previous
+	 * update. Which is important since compositors need to figure out the
+	 * composition of the next frame right after having submitted the
+	 * current layout.
+	 */
+
+	drm_atomic_helper_commit_pre_planes(drm, state);
+	drm_atomic_helper_commit_planes(drm, state);
+	drm_atomic_helper_commit_post_planes(drm, state);
+
+	drm_atomic_helper_wait_for_vblanks(drm, state);
+
+	drm_atomic_helper_cleanup_planes(drm, state);
+	drm_atomic_state_free(state);
+}
+
+static void tegra_atomic_work(struct work_struct *work)
+{
+	struct tegra_drm *tegra = container_of(work, struct tegra_drm,
+					       commit.work);
+
+	tegra_atomic_complete(tegra, tegra->commit.state);
+}
+
+static int tegra_atomic_commit(struct drm_device *drm,
+			       struct drm_atomic_state *state, bool async)
+{
+	struct tegra_drm *tegra = drm->dev_private;
+	int err;
+
+	err = drm_atomic_helper_prepare_planes(drm, state);
+	if (err)
+		return err;
+
+	/* serialize outstanding asynchronous commits */
+	mutex_lock(&tegra->commit.lock);
+	flush_work(&tegra->commit.work);
+
+	/*
+	 * This is the point of no return - everything below never fails except
+	 * when the hw goes bonghits. Which means we can commit the new state on
+	 * the software side now.
+	 */
+
+	drm_atomic_helper_swap_state(drm, state);
+
+	if (async)
+		tegra_atomic_schedule(tegra, state);
+	else
+		tegra_atomic_complete(tegra, state);
+
+	mutex_unlock(&tegra->commit.lock);
+	return 0;
+}
+
+static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
+	.fb_create = tegra_fb_create,
+#ifdef CONFIG_DRM_TEGRA_FBDEV
+	.output_poll_changed = tegra_fb_output_poll_changed,
+#endif
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = tegra_atomic_commit,
+};
+
 static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 {
 	struct host1x_device *device = to_host1x_device(drm->dev);
@@ -36,8 +125,8 @@
 
 	if (iommu_present(&platform_bus_type)) {
 		tegra->domain = iommu_domain_alloc(&platform_bus_type);
-		if (IS_ERR(tegra->domain)) {
-			err = PTR_ERR(tegra->domain);
+		if (!tegra->domain) {
+			err = -ENOMEM;
 			goto free;
 		}
 
@@ -47,11 +136,23 @@
 
 	mutex_init(&tegra->clients_lock);
 	INIT_LIST_HEAD(&tegra->clients);
+
+	mutex_init(&tegra->commit.lock);
+	INIT_WORK(&tegra->commit.work, tegra_atomic_work);
+
 	drm->dev_private = tegra;
 	tegra->drm = drm;
 
 	drm_mode_config_init(drm);
 
+	drm->mode_config.min_width = 0;
+	drm->mode_config.min_height = 0;
+
+	drm->mode_config.max_width = 4096;
+	drm->mode_config.max_height = 4096;
+
+	drm->mode_config.funcs = &tegra_drm_mode_funcs;
+
 	err = tegra_drm_fb_prepare(drm);
 	if (err < 0)
 		goto config;
@@ -62,6 +163,8 @@
 	if (err < 0)
 		goto fbdev;
 
+	drm_mode_config_reset(drm);
+
 	/*
 	 * We don't use the drm_irq_install() helpers provided by the DRM
 	 * core, so we need to set this manually in order to allow the
@@ -106,8 +209,8 @@
 
 	drm_kms_helper_poll_fini(drm);
 	tegra_drm_fb_exit(drm);
-	drm_vblank_cleanup(drm);
 	drm_mode_config_cleanup(drm);
+	drm_vblank_cleanup(drm);
 
 	err = host1x_device_exit(device);
 	if (err < 0)
@@ -190,7 +293,7 @@
 	if (err < 0)
 		return err;
 
-	err = get_user(dest->target.offset, &src->cmdbuf.offset);
+	err = get_user(dest->target.offset, &src->target.offset);
 	if (err < 0)
 		return err;
 
@@ -893,6 +996,30 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int host1x_drm_suspend(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+
+	drm_kms_helper_poll_disable(drm);
+
+	return 0;
+}
+
+static int host1x_drm_resume(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+
+	drm_kms_helper_poll_enable(drm);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops host1x_drm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(host1x_drm_suspend, host1x_drm_resume)
+};
+
 static const struct of_device_id host1x_drm_subdevs[] = {
 	{ .compatible = "nvidia,tegra20-dc", },
 	{ .compatible = "nvidia,tegra20-hdmi", },
@@ -912,7 +1039,10 @@
 };
 
 static struct host1x_driver host1x_drm_driver = {
-	.name = "drm",
+	.driver = {
+		.name = "drm",
+		.pm = &host1x_drm_pm_ops,
+	},
 	.probe = host1x_drm_probe,
 	.remove = host1x_drm_remove,
 	.subdevs = host1x_drm_subdevs,
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 3a3b2e7..8cb2dfe 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -50,6 +50,12 @@
 #endif
 
 	unsigned int pitch_align;
+
+	struct {
+		struct drm_atomic_state *state;
+		struct work_struct work;
+		struct mutex lock;
+	} commit;
 };
 
 struct tegra_drm_client;
@@ -164,45 +170,31 @@
 		unsigned int h;
 	} dst;
 	unsigned int bits_per_pixel;
-	unsigned int format;
-	unsigned int swap;
 	unsigned int stride[2];
 	unsigned long base[3];
 	bool bottom_up;
 
 	struct tegra_bo_tiling tiling;
+	u32 format;
+	u32 swap;
 };
 
 /* from dc.c */
 void tegra_dc_enable_vblank(struct tegra_dc *dc);
 void tegra_dc_disable_vblank(struct tegra_dc *dc);
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
-
-struct tegra_output_ops {
-	int (*enable)(struct tegra_output *output);
-	int (*disable)(struct tegra_output *output);
-	int (*setup_clock)(struct tegra_output *output, struct clk *clk,
-			   unsigned long pclk, unsigned int *div);
-	int (*check_mode)(struct tegra_output *output,
-			  struct drm_display_mode *mode,
-			  enum drm_mode_status *status);
-	enum drm_connector_status (*detect)(struct tegra_output *output);
-};
-
-enum tegra_output_type {
-	TEGRA_OUTPUT_RGB,
-	TEGRA_OUTPUT_HDMI,
-	TEGRA_OUTPUT_DSI,
-	TEGRA_OUTPUT_EDP,
-};
+void tegra_dc_commit(struct tegra_dc *dc);
+int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
+			 unsigned long pclk, unsigned int div);
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+			       struct drm_crtc_state *crtc_state,
+			       struct clk *clk, unsigned long pclk,
+			       unsigned int div);
 
 struct tegra_output {
 	struct device_node *of_node;
 	struct device *dev;
 
-	const struct tegra_output_ops *ops;
-	enum tegra_output_type type;
-
 	struct drm_panel *panel;
 	struct i2c_adapter *ddc;
 	const struct edid *edid;
@@ -223,42 +215,6 @@
 	return container_of(c, struct tegra_output, connector);
 }
 
-static inline int tegra_output_enable(struct tegra_output *output)
-{
-	if (output && output->ops && output->ops->enable)
-		return output->ops->enable(output);
-
-	return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_disable(struct tegra_output *output)
-{
-	if (output && output->ops && output->ops->disable)
-		return output->ops->disable(output);
-
-	return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_setup_clock(struct tegra_output *output,
-					   struct clk *clk, unsigned long pclk,
-					   unsigned int *div)
-{
-	if (output && output->ops && output->ops->setup_clock)
-		return output->ops->setup_clock(output, clk, pclk, div);
-
-	return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_check_mode(struct tegra_output *output,
-					  struct drm_display_mode *mode,
-					  enum drm_mode_status *status)
-{
-	if (output && output->ops && output->ops->check_mode)
-		return output->ops->check_mode(output, mode, status);
-
-	return output ? -ENOSYS : -EINVAL;
-}
-
 /* from rgb.c */
 int tegra_dc_rgb_probe(struct tegra_dc *dc);
 int tegra_dc_rgb_remove(struct tegra_dc *dc);
@@ -267,9 +223,18 @@
 
 /* from output.c */
 int tegra_output_probe(struct tegra_output *output);
-int tegra_output_remove(struct tegra_output *output);
+void tegra_output_remove(struct tegra_output *output);
 int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
-int tegra_output_exit(struct tegra_output *output);
+void tegra_output_exit(struct tegra_output *output);
+
+int tegra_output_connector_get_modes(struct drm_connector *connector);
+struct drm_encoder *
+tegra_output_connector_best_encoder(struct drm_connector *connector);
+enum drm_connector_status
+tegra_output_connector_detect(struct drm_connector *connector, bool force);
+void tegra_output_connector_destroy(struct drm_connector *connector);
+
+void tegra_output_encoder_destroy(struct drm_encoder *encoder);
 
 /* from dpaux.c */
 struct tegra_dpaux;
@@ -291,12 +256,16 @@
 bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
 int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
 			struct tegra_bo_tiling *tiling);
+struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
+					struct drm_file *file,
+					struct drm_mode_fb_cmd2 *cmd);
 int tegra_drm_fb_prepare(struct drm_device *drm);
 void tegra_drm_fb_free(struct drm_device *drm);
 int tegra_drm_fb_init(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
 #ifdef CONFIG_DRM_TEGRA_FBDEV
 void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
+void tegra_fb_output_poll_changed(struct drm_device *drm);
 #endif
 
 extern struct platform_driver tegra_dc_driver;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 33f67fd..ed970f6 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -17,6 +17,7 @@
 
 #include <linux/regulator/consumer.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_panel.h>
 
@@ -27,6 +28,28 @@
 #include "dsi.h"
 #include "mipi-phy.h"
 
+struct tegra_dsi_state {
+	struct drm_connector_state base;
+
+	struct mipi_dphy_timing timing;
+	unsigned long period;
+
+	unsigned int vrefresh;
+	unsigned int lanes;
+	unsigned long pclk;
+	unsigned long bclk;
+
+	enum tegra_dsi_format format;
+	unsigned int mul;
+	unsigned int div;
+};
+
+static inline struct tegra_dsi_state *
+to_dsi_state(struct drm_connector_state *state)
+{
+	return container_of(state, struct tegra_dsi_state, base);
+}
+
 struct tegra_dsi {
 	struct host1x_client client;
 	struct tegra_output output;
@@ -51,7 +74,6 @@
 	struct mipi_dsi_host host;
 
 	struct regulator *vdd;
-	bool enabled;
 
 	unsigned int video_fifo_depth;
 	unsigned int host_fifo_depth;
@@ -77,13 +99,17 @@
 	return container_of(output, struct tegra_dsi, output);
 }
 
-static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
-					    unsigned long reg)
+static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
+{
+	return to_dsi_state(dsi->output.connector.state);
+}
+
+static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned long reg)
 {
 	return readl(dsi->regs + (reg << 2));
 }
 
-static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
+static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
 				    unsigned long reg)
 {
 	writel(value, dsi->regs + (reg << 2));
@@ -95,7 +121,7 @@
 	struct tegra_dsi *dsi = node->info_ent->data;
 
 #define DUMP_REG(name)						\
-	seq_printf(s, "%-32s %#05x %08lx\n", #name, name,	\
+	seq_printf(s, "%-32s %#05x %08x\n", #name, name,	\
 		   tegra_dsi_readl(dsi, name))
 
 	DUMP_REG(DSI_INCR_SYNCPT);
@@ -230,7 +256,7 @@
 	return err;
 }
 
-static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
+static void tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
 {
 	drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
 				 dsi->minor);
@@ -241,8 +267,6 @@
 
 	debugfs_remove(dsi->debugfs);
 	dsi->debugfs = NULL;
-
-	return 0;
 }
 
 #define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
@@ -338,61 +362,36 @@
 	[11] = 0,
 };
 
-static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+static void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
+				     unsigned long period,
+				     const struct mipi_dphy_timing *timing)
 {
-	struct mipi_dphy_timing timing;
-	unsigned long value, period;
-	long rate;
-	int err;
+	u32 value;
 
-	rate = clk_get_rate(dsi->clk);
-	if (rate < 0)
-		return rate;
-
-	period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
-
-	err = mipi_dphy_timing_get_default(&timing, period);
-	if (err < 0)
-		return err;
-
-	err = mipi_dphy_timing_validate(&timing, period);
-	if (err < 0) {
-		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
-		return err;
-	}
-
-	/*
-	 * The D-PHY timing fields below are expressed in byte-clock cycles,
-	 * so multiply the period by 8.
-	 */
-	period *= 8;
-
-	value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
-		DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
-		DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
-		DSI_TIMING_FIELD(timing.hsprepare, period, 1);
+	value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
+		DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
+		DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
+		DSI_TIMING_FIELD(timing->hsprepare, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
 
-	value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
-		DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
-		DSI_TIMING_FIELD(timing.lpx, period, 1);
+	value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
+		DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
+		DSI_TIMING_FIELD(timing->lpx, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
 
-	value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
+	value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
 
-	value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
-		DSI_TIMING_FIELD(timing.tago, period, 1);
+	value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
+		DSI_TIMING_FIELD(timing->tago, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
 
 	if (dsi->slave)
-		return tegra_dsi_set_phy_timing(dsi->slave);
-
-	return 0;
+		tegra_dsi_set_phy_timing(dsi->slave, period, timing);
 }
 
 static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
@@ -484,14 +483,22 @@
 	return dsi->lanes;
 }
 
-static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
-			       const struct drm_display_mode *mode)
+static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+				const struct drm_display_mode *mode)
 {
 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
-	enum tegra_dsi_format format;
+	struct tegra_dsi_state *state;
 	const u32 *pkt_seq;
 	u32 value;
-	int err;
+
+	/* XXX: pass in state into this function? */
+	if (dsi->master)
+		state = tegra_dsi_get_state(dsi->master);
+	else
+		state = tegra_dsi_get_state(dsi);
+
+	mul = state->mul;
+	div = state->div;
 
 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
@@ -504,15 +511,8 @@
 		pkt_seq = pkt_seq_command_mode;
 	}
 
-	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
-	if (err < 0)
-		return err;
-
-	err = tegra_dsi_get_format(dsi->format, &format);
-	if (err < 0)
-		return err;
-
-	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
+	value = DSI_CONTROL_CHANNEL(0) |
+		DSI_CONTROL_FORMAT(state->format) |
 		DSI_CONTROL_LANES(dsi->lanes - 1) |
 		DSI_CONTROL_SOURCE(pipe);
 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
@@ -591,8 +591,8 @@
 
 		/* set SOL delay */
 		if (dsi->master || dsi->slave) {
-			unsigned int lanes = tegra_dsi_get_lanes(dsi);
 			unsigned long delay, bclk, bclk_ganged;
+			unsigned int lanes = state->lanes;
 
 			/* SOL to valid, valid to FIFO and FIFO write delay */
 			delay = 4 + 4 + 2;
@@ -612,9 +612,7 @@
 	}
 
 	if (dsi->slave) {
-		err = tegra_dsi_configure(dsi->slave, pipe, mode);
-		if (err < 0)
-			return err;
+		tegra_dsi_configure(dsi->slave, pipe, mode);
 
 		/*
 		 * TODO: Support modes other than symmetrical left-right
@@ -624,49 +622,6 @@
 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
 					mode->hdisplay / 2);
 	}
-
-	return 0;
-}
-
-static int tegra_output_dsi_enable(struct tegra_output *output)
-{
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	const struct drm_display_mode *mode = &dc->base.mode;
-	struct tegra_dsi *dsi = to_dsi(output);
-	u32 value;
-	int err;
-
-	if (dsi->enabled)
-		return 0;
-
-	err = tegra_dsi_configure(dsi, dc->pipe, mode);
-	if (err < 0)
-		return err;
-
-	/* enable display controller */
-	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-	value |= DSI_ENABLE;
-	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-	value &= ~DISP_CTRL_MODE_MASK;
-	value |= DISP_CTRL_MODE_C_DISPLAY;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
-	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-	/* enable DSI controller */
-	tegra_dsi_enable(dsi);
-
-	dsi->enabled = true;
-
-	return 0;
 }
 
 static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
@@ -705,70 +660,6 @@
 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
 }
 
-static void tegra_dsi_disable(struct tegra_dsi *dsi)
-{
-	u32 value;
-
-	if (dsi->slave) {
-		tegra_dsi_ganged_disable(dsi->slave);
-		tegra_dsi_ganged_disable(dsi);
-	}
-
-	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
-	value &= ~DSI_POWER_CONTROL_ENABLE;
-	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
-
-	if (dsi->slave)
-		tegra_dsi_disable(dsi->slave);
-
-	usleep_range(5000, 10000);
-}
-
-static int tegra_output_dsi_disable(struct tegra_output *output)
-{
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	struct tegra_dsi *dsi = to_dsi(output);
-	unsigned long value;
-	int err;
-
-	if (!dsi->enabled)
-		return 0;
-
-	tegra_dsi_video_disable(dsi);
-
-	/*
-	 * The following accesses registers of the display controller, so make
-	 * sure it's only executed when the output is attached to one.
-	 */
-	if (dc) {
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-		value &= ~DISP_CTRL_MODE_MASK;
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
-		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-		value &= ~DSI_ENABLE;
-		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
-		tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-		tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-	}
-
-	err = tegra_dsi_wait_idle(dsi, 100);
-	if (err < 0)
-		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
-
-	tegra_dsi_disable(dsi);
-
-	dsi->enabled = false;
-
-	return 0;
-}
-
 static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
 				  unsigned int vrefresh)
 {
@@ -792,34 +683,248 @@
 		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
 }
 
-static int tegra_output_dsi_setup_clock(struct tegra_output *output,
-					struct clk *clk, unsigned long pclk,
-					unsigned int *divp)
+static void tegra_dsi_disable(struct tegra_dsi *dsi)
 {
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	struct drm_display_mode *mode = &dc->base.mode;
+	u32 value;
+
+	if (dsi->slave) {
+		tegra_dsi_ganged_disable(dsi->slave);
+		tegra_dsi_ganged_disable(dsi);
+	}
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value &= ~DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	if (dsi->slave)
+		tegra_dsi_disable(dsi->slave);
+
+	usleep_range(5000, 10000);
+}
+
+static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
+{
+	u32 value;
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value &= ~DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	usleep_range(300, 1000);
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value |= DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	usleep_range(300, 1000);
+
+	value = tegra_dsi_readl(dsi, DSI_TRIGGER);
+	if (value)
+		tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
+
+	if (dsi->slave)
+		tegra_dsi_soft_reset(dsi->slave);
+}
+
+static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
+{
+}
+
+static void tegra_dsi_connector_reset(struct drm_connector *connector)
+{
+	struct tegra_dsi_state *state;
+
+	kfree(connector->state);
+	connector->state = NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state)
+		connector->state = &state->base;
+}
+
+static struct drm_connector_state *
+tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
+{
+	struct tegra_dsi_state *state = to_dsi_state(connector->state);
+	struct tegra_dsi_state *copy;
+
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	return &copy->base;
+}
+
+static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
+	.dpms = tegra_dsi_connector_dpms,
+	.reset = tegra_dsi_connector_reset,
+	.detect = tegra_output_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = tegra_output_connector_destroy,
+	.atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_dsi_connector_mode_valid(struct drm_connector *connector,
+			       struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
+	.get_modes = tegra_output_connector_get_modes,
+	.mode_valid = tegra_dsi_connector_mode_valid,
+	.best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
+	.destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_dsi_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_dsi_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
 	struct tegra_dsi *dsi = to_dsi(output);
-	unsigned int mul, div, vrefresh, lanes;
-	unsigned long bclk, plld;
+	struct tegra_dsi_state *state;
+	u32 value;
+
+	state = tegra_dsi_get_state(dsi);
+
+	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
+
+	/*
+	 * The D-PHY timing fields are expressed in byte-clock cycles, so
+	 * multiply the period by 8.
+	 */
+	tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
+
+	if (output->panel)
+		drm_panel_prepare(output->panel);
+
+	tegra_dsi_configure(dsi, dc->pipe, mode);
+
+	/* enable display controller */
+	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+	value |= DSI_ENABLE;
+	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+	tegra_dc_commit(dc);
+
+	/* enable DSI controller */
+	tegra_dsi_enable(dsi);
+
+	if (output->panel)
+		drm_panel_enable(output->panel);
+
+	return;
+}
+
+static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+	struct tegra_dsi *dsi = to_dsi(output);
+	u32 value;
 	int err;
 
-	lanes = tegra_dsi_get_lanes(dsi);
+	if (output->panel)
+		drm_panel_disable(output->panel);
 
-	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+	tegra_dsi_video_disable(dsi);
+
+	/*
+	 * The following accesses registers of the display controller, so make
+	 * sure it's only executed when the output is attached to one.
+	 */
+	if (dc) {
+		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+		value &= ~DSI_ENABLE;
+		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+		tegra_dc_commit(dc);
+	}
+
+	err = tegra_dsi_wait_idle(dsi, 100);
+	if (err < 0)
+		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
+
+	tegra_dsi_soft_reset(dsi);
+
+	if (output->panel)
+		drm_panel_unprepare(output->panel);
+
+	tegra_dsi_disable(dsi);
+
+	return;
+}
+
+static int
+tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dsi_state *state = to_dsi_state(conn_state);
+	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+	struct tegra_dsi *dsi = to_dsi(output);
+	unsigned int scdiv;
+	unsigned long plld;
+	int err;
+
+	state->pclk = crtc_state->mode.clock * 1000;
+
+	err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
 	if (err < 0)
 		return err;
 
-	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes);
-	vrefresh = drm_mode_vrefresh(mode);
-	DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
+	state->lanes = tegra_dsi_get_lanes(dsi);
+
+	err = tegra_dsi_get_format(dsi->format, &state->format);
+	if (err < 0)
+		return err;
+
+	state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
 
 	/* compute byte clock */
-	bclk = (pclk * mul) / (div * lanes);
+	state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
+
+	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
+		      state->lanes);
+	DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
+		      state->vrefresh);
+	DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
 
 	/*
 	 * Compute bit clock and round up to the next MHz.
 	 */
-	plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+	plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+	state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
+
+	err = mipi_dphy_timing_get_default(&state->timing, state->period);
+	if (err < 0)
+		return err;
+
+	err = mipi_dphy_timing_validate(&state->timing, state->period);
+	if (err < 0) {
+		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
+		return err;
+	}
 
 	/*
 	 * We divide the frequency by two here, but we make up for that by
@@ -828,19 +933,6 @@
 	 */
 	plld /= 2;
 
-	err = clk_set_parent(clk, dsi->clk_parent);
-	if (err < 0) {
-		dev_err(dsi->dev, "failed to set parent clock: %d\n", err);
-		return err;
-	}
-
-	err = clk_set_rate(dsi->clk_parent, plld);
-	if (err < 0) {
-		dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
-			plld);
-		return err;
-	}
-
 	/*
 	 * Derive pixel clock from bit clock using the shift clock divider.
 	 * Note that this is only half of what we would expect, but we need
@@ -851,44 +943,30 @@
 	 * not working properly otherwise. Perhaps the PLLs cannot generate
 	 * frequencies sufficiently high.
 	 */
-	*divp = ((8 * mul) / (div * lanes)) - 2;
+	scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
 
-	/*
-	 * XXX: Move the below somewhere else so that we don't need to have
-	 * access to the vrefresh in this function?
-	 */
-	tegra_dsi_set_timeout(dsi, bclk, vrefresh);
-
-	err = tegra_dsi_set_phy_timing(dsi);
-	if (err < 0)
+	err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
+					 plld, scdiv);
+	if (err < 0) {
+		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
 		return err;
+	}
 
-	return 0;
+	return err;
 }
 
-static int tegra_output_dsi_check_mode(struct tegra_output *output,
-				       struct drm_display_mode *mode,
-				       enum drm_mode_status *status)
-{
-	/*
-	 * FIXME: For now, always assume that the mode is okay.
-	 */
-
-	*status = MODE_OK;
-
-	return 0;
-}
-
-static const struct tegra_output_ops dsi_ops = {
-	.enable = tegra_output_dsi_enable,
-	.disable = tegra_output_dsi_disable,
-	.setup_clock = tegra_output_dsi_setup_clock,
-	.check_mode = tegra_output_dsi_check_mode,
+static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
+	.dpms = tegra_dsi_encoder_dpms,
+	.prepare = tegra_dsi_encoder_prepare,
+	.commit = tegra_dsi_encoder_commit,
+	.mode_set = tegra_dsi_encoder_mode_set,
+	.disable = tegra_dsi_encoder_disable,
+	.atomic_check = tegra_dsi_encoder_atomic_check,
 };
 
 static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
 {
-	unsigned long value;
+	u32 value;
 
 	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
@@ -923,17 +1001,44 @@
 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
 	int err;
 
+	reset_control_deassert(dsi->rst);
+
+	err = tegra_dsi_pad_calibrate(dsi);
+	if (err < 0) {
+		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
+		goto reset;
+	}
+
 	/* Gangsters must not register their own outputs. */
 	if (!dsi->master) {
-		dsi->output.type = TEGRA_OUTPUT_DSI;
 		dsi->output.dev = client->dev;
-		dsi->output.ops = &dsi_ops;
+
+		drm_connector_init(drm, &dsi->output.connector,
+				   &tegra_dsi_connector_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+		drm_connector_helper_add(&dsi->output.connector,
+					 &tegra_dsi_connector_helper_funcs);
+		dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+		drm_encoder_init(drm, &dsi->output.encoder,
+				 &tegra_dsi_encoder_funcs,
+				 DRM_MODE_ENCODER_DSI);
+		drm_encoder_helper_add(&dsi->output.encoder,
+				       &tegra_dsi_encoder_helper_funcs);
+
+		drm_mode_connector_attach_encoder(&dsi->output.connector,
+						  &dsi->output.encoder);
+		drm_connector_register(&dsi->output.connector);
 
 		err = tegra_output_init(drm, &dsi->output);
 		if (err < 0) {
-			dev_err(client->dev, "output setup failed: %d\n", err);
-			return err;
+			dev_err(client->dev,
+				"failed to initialize output: %d\n",
+				err);
+			goto reset;
 		}
+
+		dsi->output.encoder.possible_crtcs = 0x3;
 	}
 
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
@@ -943,34 +1048,22 @@
 	}
 
 	return 0;
+
+reset:
+	reset_control_assert(dsi->rst);
+	return err;
 }
 
 static int tegra_dsi_exit(struct host1x_client *client)
 {
 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
-	int err;
 
-	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		err = tegra_dsi_debugfs_exit(dsi);
-		if (err < 0)
-			dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
-	}
+	tegra_output_exit(&dsi->output);
 
-	if (!dsi->master) {
-		err = tegra_output_disable(&dsi->output);
-		if (err < 0) {
-			dev_err(client->dev, "output failed to disable: %d\n",
-				err);
-			return err;
-		}
+	if (IS_ENABLED(CONFIG_DEBUG_FS))
+		tegra_dsi_debugfs_exit(dsi);
 
-		err = tegra_output_exit(&dsi->output);
-		if (err < 0) {
-			dev_err(client->dev, "output cleanup failed: %d\n",
-				err);
-			return err;
-		}
-	}
+	reset_control_assert(dsi->rst);
 
 	return 0;
 }
@@ -1398,13 +1491,6 @@
 	if (IS_ERR(dsi->rst))
 		return PTR_ERR(dsi->rst);
 
-	err = reset_control_deassert(dsi->rst);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n",
-			err);
-		return err;
-	}
-
 	dsi->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dsi->clk)) {
 		dev_err(&pdev->dev, "cannot get DSI clock\n");
@@ -1470,12 +1556,6 @@
 		goto disable_vdd;
 	}
 
-	err = tegra_dsi_pad_calibrate(dsi);
-	if (err < 0) {
-		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
-		goto mipi_free;
-	}
-
 	dsi->host.ops = &tegra_dsi_host_ops;
 	dsi->host.dev = &pdev->dev;
 
@@ -1527,6 +1607,8 @@
 		return err;
 	}
 
+	tegra_output_remove(&dsi->output);
+
 	mipi_dsi_host_unregister(&dsi->host);
 	tegra_mipi_free(dsi->mipi);
 
@@ -1535,12 +1617,6 @@
 	clk_disable_unprepare(dsi->clk);
 	reset_control_assert(dsi->rst);
 
-	err = tegra_output_remove(&dsi->output);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to remove output: %d\n", err);
-		return err;
-	}
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index e9c715d..397fb34 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -129,9 +129,9 @@
 	return fb;
 }
 
-static struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
-					       struct drm_file *file,
-					       struct drm_mode_fb_cmd2 *cmd)
+struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
+					struct drm_file *file,
+					struct drm_mode_fb_cmd2 *cmd)
 {
 	unsigned int hsub, vsub, i;
 	struct tegra_bo *planes[4];
@@ -377,7 +377,7 @@
 		drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev->base);
 }
 
-static void tegra_fb_output_poll_changed(struct drm_device *drm)
+void tegra_fb_output_poll_changed(struct drm_device *drm)
 {
 	struct tegra_drm *tegra = drm->dev_private;
 
@@ -386,28 +386,11 @@
 }
 #endif
 
-static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
-	.fb_create = tegra_fb_create,
-#ifdef CONFIG_DRM_TEGRA_FBDEV
-	.output_poll_changed = tegra_fb_output_poll_changed,
-#endif
-};
-
 int tegra_drm_fb_prepare(struct drm_device *drm)
 {
 #ifdef CONFIG_DRM_TEGRA_FBDEV
 	struct tegra_drm *tegra = drm->dev_private;
-#endif
 
-	drm->mode_config.min_width = 0;
-	drm->mode_config.min_height = 0;
-
-	drm->mode_config.max_width = 4096;
-	drm->mode_config.max_height = 4096;
-
-	drm->mode_config.funcs = &tegra_drm_mode_funcs;
-
-#ifdef CONFIG_DRM_TEGRA_FBDEV
 	tegra->fbdev = tegra_fbdev_create(drm);
 	if (IS_ERR(tegra->fbdev))
 		return PTR_ERR(tegra->fbdev);
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 8777b7f..cfb4819 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -92,36 +92,6 @@
 	.kunmap = tegra_bo_kunmap,
 };
 
-/*
- * A generic iommu_map_sg() function is being reviewed and will hopefully be
- * merged soon. At that point this function can be dropped in favour of the
- * one provided by the IOMMU API.
- */
-static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
-			      struct scatterlist *sg, unsigned int nents,
-			      int prot)
-{
-	struct scatterlist *s;
-	size_t offset = 0;
-	unsigned int i;
-	int err;
-
-	for_each_sg(sg, s, nents, i) {
-		phys_addr_t phys = page_to_phys(sg_page(s));
-		size_t length = s->offset + s->length;
-
-		err = iommu_map(domain, iova + offset, phys, length, prot);
-		if (err < 0) {
-			iommu_unmap(domain, iova, offset);
-			return err;
-		}
-
-		offset += length;
-	}
-
-	return offset;
-}
-
 static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
 {
 	int prot = IOMMU_READ | IOMMU_WRITE;
@@ -144,8 +114,8 @@
 
 	bo->paddr = bo->mm->start;
 
-	err = __iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl,
-			     bo->sgt->nents, prot);
+	err = iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl,
+			   bo->sgt->nents, prot);
 	if (err < 0) {
 		dev_err(tegra->drm->dev, "failed to map buffer: %zd\n", err);
 		goto remove;
@@ -244,10 +214,8 @@
 	for_each_sg(sgt->sgl, s, sgt->nents, i)
 		sg_dma_address(s) = sg_phys(s);
 
-	if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) {
-		sgt = ERR_PTR(-ENOMEM);
+	if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0)
 		goto release_sgt;
-	}
 
 	bo->sgt = sgt;
 
@@ -256,6 +224,7 @@
 release_sgt:
 	sg_free_table(sgt);
 	kfree(sgt);
+	sgt = ERR_PTR(-ENOMEM);
 put_pages:
 	drm_gem_put_pages(&bo->gem, bo->pages, false, false);
 	return PTR_ERR(sgt);
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index ffe2654..7e06657 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -9,10 +9,15 @@
 
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/gpio.h>
 #include <linux/hdmi.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
 #include "hdmi.h"
 #include "drm.h"
 #include "dc.h"
@@ -31,7 +36,7 @@
 	unsigned int num_tmds;
 
 	unsigned long fuse_override_offset;
-	unsigned long fuse_override_value;
+	u32 fuse_override_value;
 
 	bool has_sor_io_peak_current;
 };
@@ -40,7 +45,6 @@
 	struct host1x_client client;
 	struct tegra_output output;
 	struct device *dev;
-	bool enabled;
 
 	struct regulator *hdmi;
 	struct regulator *pll;
@@ -85,16 +89,16 @@
 	HDA,
 };
 
-static inline unsigned long tegra_hdmi_readl(struct tegra_hdmi *hdmi,
-					     unsigned long reg)
+static inline u32 tegra_hdmi_readl(struct tegra_hdmi *hdmi,
+				   unsigned long offset)
 {
-	return readl(hdmi->regs + (reg << 2));
+	return readl(hdmi->regs + (offset << 2));
 }
 
-static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, unsigned long val,
-				     unsigned long reg)
+static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, u32 value,
+				     unsigned long offset)
 {
-	writel(val, hdmi->regs + (reg << 2));
+	writel(value, hdmi->regs + (offset << 2));
 }
 
 struct tegra_hdmi_audio_config {
@@ -455,8 +459,8 @@
 	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
 		unsigned int f = freqs[i];
 		unsigned int eight_half;
-		unsigned long value;
 		unsigned int delta;
+		u32 value;
 
 		if (f > 96000)
 			delta = 2;
@@ -477,7 +481,7 @@
 	struct device_node *node = hdmi->dev->of_node;
 	const struct tegra_hdmi_audio_config *config;
 	unsigned int offset = 0;
-	unsigned long value;
+	u32 value;
 
 	switch (hdmi->audio_source) {
 	case HDA:
@@ -571,9 +575,9 @@
 	return 0;
 }
 
-static inline unsigned long tegra_hdmi_subpack(const u8 *ptr, size_t size)
+static inline u32 tegra_hdmi_subpack(const u8 *ptr, size_t size)
 {
-	unsigned long value = 0;
+	u32 value = 0;
 	size_t i;
 
 	for (i = size; i > 0; i--)
@@ -587,8 +591,8 @@
 {
 	const u8 *ptr = data;
 	unsigned long offset;
-	unsigned long value;
 	size_t i, j;
+	u32 value;
 
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
@@ -707,9 +711,9 @@
 static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi)
 {
 	struct hdmi_vendor_infoframe frame;
-	unsigned long value;
 	u8 buffer[10];
 	ssize_t err;
+	u32 value;
 
 	if (!hdmi->stereo) {
 		value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
@@ -738,7 +742,7 @@
 static void tegra_hdmi_setup_tmds(struct tegra_hdmi *hdmi,
 				  const struct tmds_config *tmds)
 {
-	unsigned long value;
+	u32 value;
 
 	tegra_hdmi_writel(hdmi, tmds->pll0, HDMI_NV_PDISP_SOR_PLL0);
 	tegra_hdmi_writel(hdmi, tmds->pll1, HDMI_NV_PDISP_SOR_PLL1);
@@ -768,21 +772,78 @@
 	return drm_detect_hdmi_monitor(edid);
 }
 
-static int tegra_output_hdmi_enable(struct tegra_output *output)
+static void tegra_hdmi_connector_dpms(struct drm_connector *connector,
+				      int mode)
+{
+}
+
+static const struct drm_connector_funcs tegra_hdmi_connector_funcs = {
+	.dpms = tegra_hdmi_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = tegra_output_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = tegra_output_connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_hdmi_connector_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	struct tegra_output *output = connector_to_output(connector);
+	struct tegra_hdmi *hdmi = to_hdmi(output);
+	unsigned long pclk = mode->clock * 1000;
+	enum drm_mode_status status = MODE_OK;
+	struct clk *parent;
+	long err;
+
+	parent = clk_get_parent(hdmi->clk_parent);
+
+	err = clk_round_rate(parent, pclk * 4);
+	if (err <= 0)
+		status = MODE_NOCLOCK;
+
+	return status;
+}
+
+static const struct drm_connector_helper_funcs
+tegra_hdmi_connector_helper_funcs = {
+	.get_modes = tegra_output_connector_get_modes,
+	.mode_valid = tegra_hdmi_connector_mode_valid,
+	.best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = {
+	.destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_hdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_hdmi_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+					struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted)
 {
 	unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey;
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	struct drm_display_mode *mode = &dc->base.mode;
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+	struct device_node *node = output->dev->of_node;
 	struct tegra_hdmi *hdmi = to_hdmi(output);
-	struct device_node *node = hdmi->dev->of_node;
 	unsigned int pulse_start, div82, pclk;
-	unsigned long value;
 	int retries = 1000;
+	u32 value;
 	int err;
 
-	if (hdmi->enabled)
-		return 0;
-
 	hdmi->dvi = !tegra_output_is_hdmi(output);
 
 	pclk = mode->clock * 1000;
@@ -790,32 +851,6 @@
 	h_back_porch = mode->htotal - mode->hsync_end;
 	h_front_porch = mode->hsync_start - mode->hdisplay;
 
-	err = regulator_enable(hdmi->pll);
-	if (err < 0) {
-		dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err);
-		return err;
-	}
-
-	err = regulator_enable(hdmi->vdd);
-	if (err < 0) {
-		dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
-		return err;
-	}
-
-	err = clk_set_rate(hdmi->clk, pclk);
-	if (err < 0)
-		return err;
-
-	err = clk_prepare_enable(hdmi->clk);
-	if (err < 0) {
-		dev_err(hdmi->dev, "failed to enable clock: %d\n", err);
-		return err;
-	}
-
-	reset_control_assert(hdmi->rst);
-	usleep_range(1000, 2000);
-	reset_control_deassert(hdmi->rst);
-
 	/* power up sequence */
 	value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
 	value &= ~SOR_PLL_PDBG;
@@ -987,123 +1022,57 @@
 	value |= HDMI_ENABLE;
 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-	value &= ~DISP_CTRL_MODE_MASK;
-	value |= DISP_CTRL_MODE_C_DISPLAY;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
-	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+	tegra_dc_commit(dc);
 
 	/* TODO: add HDCP support */
-
-	hdmi->enabled = true;
-
-	return 0;
 }
 
-static int tegra_output_hdmi_disable(struct tegra_output *output)
+static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
 {
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	struct tegra_hdmi *hdmi = to_hdmi(output);
-	unsigned long value;
-
-	if (!hdmi->enabled)
-		return 0;
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+	u32 value;
 
 	/*
 	 * The following accesses registers of the display controller, so make
 	 * sure it's only executed when the output is attached to one.
 	 */
 	if (dc) {
-		/*
-		 * XXX: We can't do this here because it causes HDMI to go
-		 * into an erroneous state with the result that HDMI won't
-		 * properly work once disabled. See also a similar symptom
-		 * for the SOR output.
-		 */
-		/*
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-		*/
-
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-		value &= ~DISP_CTRL_MODE_MASK;
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
 		value &= ~HDMI_ENABLE;
 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-		tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-		tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+		tegra_dc_commit(dc);
 	}
-
-	clk_disable_unprepare(hdmi->clk);
-	reset_control_assert(hdmi->rst);
-	regulator_disable(hdmi->vdd);
-	regulator_disable(hdmi->pll);
-
-	hdmi->enabled = false;
-
-	return 0;
 }
 
-static int tegra_output_hdmi_setup_clock(struct tegra_output *output,
-					 struct clk *clk, unsigned long pclk,
-					 unsigned int *div)
+static int
+tegra_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+				struct drm_crtc_state *crtc_state,
+				struct drm_connector_state *conn_state)
 {
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+	unsigned long pclk = crtc_state->mode.clock * 1000;
 	struct tegra_hdmi *hdmi = to_hdmi(output);
 	int err;
 
-	err = clk_set_parent(clk, hdmi->clk_parent);
+	err = tegra_dc_state_setup_clock(dc, crtc_state, hdmi->clk_parent,
+					 pclk, 0);
 	if (err < 0) {
-		dev_err(output->dev, "failed to set parent: %d\n", err);
+		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
 		return err;
 	}
 
-	err = clk_set_rate(hdmi->clk_parent, pclk);
-	if (err < 0)
-		dev_err(output->dev, "failed to set clock rate to %lu Hz\n",
-			pclk);
-
-	*div = 0;
-
-	return 0;
+	return err;
 }
 
-static int tegra_output_hdmi_check_mode(struct tegra_output *output,
-					struct drm_display_mode *mode,
-					enum drm_mode_status *status)
-{
-	struct tegra_hdmi *hdmi = to_hdmi(output);
-	unsigned long pclk = mode->clock * 1000;
-	struct clk *parent;
-	long err;
-
-	parent = clk_get_parent(hdmi->clk_parent);
-
-	err = clk_round_rate(parent, pclk * 4);
-	if (err <= 0)
-		*status = MODE_NOCLOCK;
-	else
-		*status = MODE_OK;
-
-	return 0;
-}
-
-static const struct tegra_output_ops hdmi_ops = {
-	.enable = tegra_output_hdmi_enable,
-	.disable = tegra_output_hdmi_disable,
-	.setup_clock = tegra_output_hdmi_setup_clock,
-	.check_mode = tegra_output_hdmi_check_mode,
+static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = {
+	.dpms = tegra_hdmi_encoder_dpms,
+	.prepare = tegra_hdmi_encoder_prepare,
+	.commit = tegra_hdmi_encoder_commit,
+	.mode_set = tegra_hdmi_encoder_mode_set,
+	.disable = tegra_hdmi_encoder_disable,
+	.atomic_check = tegra_hdmi_encoder_atomic_check,
 };
 
 static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
@@ -1117,8 +1086,8 @@
 		return err;
 
 #define DUMP_REG(name)						\
-	seq_printf(s, "%-56s %#05x %08lx\n", #name, name,	\
-		tegra_hdmi_readl(hdmi, name))
+	seq_printf(s, "%-56s %#05x %08x\n", #name, name,	\
+		   tegra_hdmi_readl(hdmi, name))
 
 	DUMP_REG(HDMI_CTXSW);
 	DUMP_REG(HDMI_NV_PDISP_SOR_STATE0);
@@ -1330,7 +1299,7 @@
 	return err;
 }
 
-static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
+static void tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
 {
 	drm_debugfs_remove_files(hdmi->debugfs_files, ARRAY_SIZE(debugfs_files),
 				 hdmi->minor);
@@ -1341,8 +1310,6 @@
 
 	debugfs_remove(hdmi->debugfs);
 	hdmi->debugfs = NULL;
-
-	return 0;
 }
 
 static int tegra_hdmi_init(struct host1x_client *client)
@@ -1351,16 +1318,32 @@
 	struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
 	int err;
 
-	hdmi->output.type = TEGRA_OUTPUT_HDMI;
 	hdmi->output.dev = client->dev;
-	hdmi->output.ops = &hdmi_ops;
+
+	drm_connector_init(drm, &hdmi->output.connector,
+			   &tegra_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+	drm_connector_helper_add(&hdmi->output.connector,
+				 &tegra_hdmi_connector_helper_funcs);
+	hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+	drm_encoder_init(drm, &hdmi->output.encoder, &tegra_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+	drm_encoder_helper_add(&hdmi->output.encoder,
+			       &tegra_hdmi_encoder_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&hdmi->output.connector,
+					  &hdmi->output.encoder);
+	drm_connector_register(&hdmi->output.connector);
 
 	err = tegra_output_init(drm, &hdmi->output);
 	if (err < 0) {
-		dev_err(client->dev, "output setup failed: %d\n", err);
+		dev_err(client->dev, "failed to initialize output: %d\n", err);
 		return err;
 	}
 
+	hdmi->output.encoder.possible_crtcs = 0x3;
+
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
 		err = tegra_hdmi_debugfs_init(hdmi, drm->primary);
 		if (err < 0)
@@ -1374,34 +1357,44 @@
 		return err;
 	}
 
+	err = regulator_enable(hdmi->pll);
+	if (err < 0) {
+		dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err);
+		return err;
+	}
+
+	err = regulator_enable(hdmi->vdd);
+	if (err < 0) {
+		dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
+		return err;
+	}
+
+	err = clk_prepare_enable(hdmi->clk);
+	if (err < 0) {
+		dev_err(hdmi->dev, "failed to enable clock: %d\n", err);
+		return err;
+	}
+
+	reset_control_deassert(hdmi->rst);
+
 	return 0;
 }
 
 static int tegra_hdmi_exit(struct host1x_client *client)
 {
 	struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
-	int err;
 
+	tegra_output_exit(&hdmi->output);
+
+	clk_disable_unprepare(hdmi->clk);
+	reset_control_assert(hdmi->rst);
+
+	regulator_disable(hdmi->vdd);
+	regulator_disable(hdmi->pll);
 	regulator_disable(hdmi->hdmi);
 
-	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		err = tegra_hdmi_debugfs_exit(hdmi);
-		if (err < 0)
-			dev_err(client->dev, "debugfs cleanup failed: %d\n",
-				err);
-	}
-
-	err = tegra_output_disable(&hdmi->output);
-	if (err < 0) {
-		dev_err(client->dev, "output failed to disable: %d\n", err);
-		return err;
-	}
-
-	err = tegra_output_exit(&hdmi->output);
-	if (err < 0) {
-		dev_err(client->dev, "output cleanup failed: %d\n", err);
-		return err;
-	}
+	if (IS_ENABLED(CONFIG_DEBUG_FS))
+		tegra_hdmi_debugfs_exit(hdmi);
 
 	return 0;
 }
@@ -1559,11 +1552,7 @@
 		return err;
 	}
 
-	err = tegra_output_remove(&hdmi->output);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed to remove output: %d\n", err);
-		return err;
-	}
+	tegra_output_remove(&hdmi->output);
 
 	clk_disable_unprepare(hdmi->clk_parent);
 	clk_disable_unprepare(hdmi->clk);
diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c
index 486d19d..ba2ae65 100644
--- a/drivers/gpu/drm/tegra/mipi-phy.c
+++ b/drivers/gpu/drm/tegra/mipi-phy.c
@@ -12,9 +12,9 @@
 #include "mipi-phy.h"
 
 /*
- * Default D-PHY timings based on MIPI D-PHY specification. Derived from
- * the valid ranges specified in Section 5.9 of the D-PHY specification
- * with minor adjustments.
+ * Default D-PHY timings based on MIPI D-PHY specification. Derived from the
+ * valid ranges specified in Section 6.9, Table 14, Page 40 of the D-PHY
+ * specification (v1.2) with minor adjustments.
  */
 int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
 				 unsigned long period)
@@ -34,7 +34,20 @@
 	timing->hszero = 145 + 5 * period;
 	timing->hssettle = 85 + 6 * period;
 	timing->hsskip = 40;
-	timing->hstrail = max(8 * period, 60 + 4 * period);
+
+	/*
+	 * The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40)
+	 * contains this formula as:
+	 *
+	 *     T_HS-TRAIL = max(n * 8 * period, 60 + n * 4 * period)
+	 *
+	 * where n = 1 for forward-direction HS mode and n = 4 for reverse-
+	 * direction HS mode. There's only one setting and this function does
+	 * not parameterize on anything other that period, so this code will
+	 * assumes that reverse-direction HS mode is supported and uses n = 4.
+	 */
+	timing->hstrail = max(4 * 8 * period, 60 + 4 * 4 * period);
+
 	timing->init = 100000;
 	timing->lpx = 60;
 	timing->taget = 5 * timing->lpx;
@@ -46,8 +59,8 @@
 }
 
 /*
- * Validate D-PHY timing according to MIPI Alliance Specification for D-PHY,
- * Section 5.9 "Global Operation Timing Parameters".
+ * Validate D-PHY timing according to MIPI D-PHY specification (v1.2, Section
+ * Section 6.9 "Global Operation Timing Parameters").
  */
 int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
 			      unsigned long period)
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 6a5c7b8..37db479 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -9,10 +9,11 @@
 
 #include <linux/of_gpio.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_panel.h>
 #include "drm.h"
 
-static int tegra_connector_get_modes(struct drm_connector *connector)
+int tegra_output_connector_get_modes(struct drm_connector *connector)
 {
 	struct tegra_output *output = connector_to_output(connector);
 	struct edid *edid = NULL;
@@ -43,43 +44,20 @@
 	return err;
 }
 
-static int tegra_connector_mode_valid(struct drm_connector *connector,
-				      struct drm_display_mode *mode)
-{
-	struct tegra_output *output = connector_to_output(connector);
-	enum drm_mode_status status = MODE_OK;
-	int err;
-
-	err = tegra_output_check_mode(output, mode, &status);
-	if (err < 0)
-		return MODE_ERROR;
-
-	return status;
-}
-
-static struct drm_encoder *
-tegra_connector_best_encoder(struct drm_connector *connector)
+struct drm_encoder *
+tegra_output_connector_best_encoder(struct drm_connector *connector)
 {
 	struct tegra_output *output = connector_to_output(connector);
 
 	return &output->encoder;
 }
 
-static const struct drm_connector_helper_funcs connector_helper_funcs = {
-	.get_modes = tegra_connector_get_modes,
-	.mode_valid = tegra_connector_mode_valid,
-	.best_encoder = tegra_connector_best_encoder,
-};
-
-static enum drm_connector_status
-tegra_connector_detect(struct drm_connector *connector, bool force)
+enum drm_connector_status
+tegra_output_connector_detect(struct drm_connector *connector, bool force)
 {
 	struct tegra_output *output = connector_to_output(connector);
 	enum drm_connector_status status = connector_status_unknown;
 
-	if (output->ops->detect)
-		return output->ops->detect(output);
-
 	if (gpio_is_valid(output->hpd_gpio)) {
 		if (gpio_get_value(output->hpd_gpio) == 0)
 			status = connector_status_disconnected;
@@ -90,95 +68,22 @@
 			status = connector_status_disconnected;
 		else
 			status = connector_status_connected;
-
-		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
-			status = connector_status_connected;
 	}
 
 	return status;
 }
 
-static void drm_connector_clear(struct drm_connector *connector)
-{
-	memset(connector, 0, sizeof(*connector));
-}
-
-static void tegra_connector_destroy(struct drm_connector *connector)
+void tegra_output_connector_destroy(struct drm_connector *connector)
 {
 	drm_connector_unregister(connector);
 	drm_connector_cleanup(connector);
-	drm_connector_clear(connector);
 }
 
-static const struct drm_connector_funcs connector_funcs = {
-	.dpms = drm_helper_connector_dpms,
-	.detect = tegra_connector_detect,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = tegra_connector_destroy,
-};
-
-static void drm_encoder_clear(struct drm_encoder *encoder)
-{
-	memset(encoder, 0, sizeof(*encoder));
-}
-
-static void tegra_encoder_destroy(struct drm_encoder *encoder)
+void tegra_output_encoder_destroy(struct drm_encoder *encoder)
 {
 	drm_encoder_cleanup(encoder);
-	drm_encoder_clear(encoder);
 }
 
-static const struct drm_encoder_funcs encoder_funcs = {
-	.destroy = tegra_encoder_destroy,
-};
-
-static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
-	struct tegra_output *output = encoder_to_output(encoder);
-	struct drm_panel *panel = output->panel;
-
-	if (mode != DRM_MODE_DPMS_ON) {
-		drm_panel_disable(panel);
-		tegra_output_disable(output);
-		drm_panel_unprepare(panel);
-	} else {
-		drm_panel_prepare(panel);
-		tegra_output_enable(output);
-		drm_panel_enable(panel);
-	}
-}
-
-static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
-				     const struct drm_display_mode *mode,
-				     struct drm_display_mode *adjusted)
-{
-	return true;
-}
-
-static void tegra_encoder_prepare(struct drm_encoder *encoder)
-{
-	tegra_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void tegra_encoder_commit(struct drm_encoder *encoder)
-{
-	tegra_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-static void tegra_encoder_mode_set(struct drm_encoder *encoder,
-				   struct drm_display_mode *mode,
-				   struct drm_display_mode *adjusted)
-{
-}
-
-static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
-	.dpms = tegra_encoder_dpms,
-	.mode_fixup = tegra_encoder_mode_fixup,
-	.prepare = tegra_encoder_prepare,
-	.commit = tegra_encoder_commit,
-	.mode_set = tegra_encoder_mode_set,
-};
-
 static irqreturn_t hpd_irq(int irq, void *data)
 {
 	struct tegra_output *output = data;
@@ -268,7 +173,7 @@
 	return 0;
 }
 
-int tegra_output_remove(struct tegra_output *output)
+void tegra_output_remove(struct tegra_output *output)
 {
 	if (gpio_is_valid(output->hpd_gpio)) {
 		free_irq(output->hpd_irq, output);
@@ -277,57 +182,18 @@
 
 	if (output->ddc)
 		put_device(&output->ddc->dev);
-
-	return 0;
 }
 
 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
 {
-	int connector, encoder;
+	int err;
 
-	switch (output->type) {
-	case TEGRA_OUTPUT_RGB:
-		connector = DRM_MODE_CONNECTOR_LVDS;
-		encoder = DRM_MODE_ENCODER_LVDS;
-		break;
-
-	case TEGRA_OUTPUT_HDMI:
-		connector = DRM_MODE_CONNECTOR_HDMIA;
-		encoder = DRM_MODE_ENCODER_TMDS;
-		break;
-
-	case TEGRA_OUTPUT_DSI:
-		connector = DRM_MODE_CONNECTOR_DSI;
-		encoder = DRM_MODE_ENCODER_DSI;
-		break;
-
-	case TEGRA_OUTPUT_EDP:
-		connector = DRM_MODE_CONNECTOR_eDP;
-		encoder = DRM_MODE_ENCODER_TMDS;
-		break;
-
-	default:
-		connector = DRM_MODE_CONNECTOR_Unknown;
-		encoder = DRM_MODE_ENCODER_NONE;
-		break;
+	if (output->panel) {
+		err = drm_panel_attach(output->panel, &output->connector);
+		if (err < 0)
+			return err;
 	}
 
-	drm_connector_init(drm, &output->connector, &connector_funcs,
-			   connector);
-	drm_connector_helper_add(&output->connector, &connector_helper_funcs);
-	output->connector.dpms = DRM_MODE_DPMS_OFF;
-
-	if (output->panel)
-		drm_panel_attach(output->panel, &output->connector);
-
-	drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder);
-	drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs);
-
-	drm_mode_connector_attach_encoder(&output->connector, &output->encoder);
-	drm_connector_register(&output->connector);
-
-	output->encoder.possible_crtcs = 0x3;
-
 	/*
 	 * The connector is now registered and ready to receive hotplug events
 	 * so the hotplug interrupt can be enabled.
@@ -338,7 +204,7 @@
 	return 0;
 }
 
-int tegra_output_exit(struct tegra_output *output)
+void tegra_output_exit(struct tegra_output *output)
 {
 	/*
 	 * The connector is going away, so the interrupt must be disabled to
@@ -349,6 +215,4 @@
 
 	if (output->panel)
 		drm_panel_detach(output->panel);
-
-	return 0;
 }
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index d6af9be..7cd833f 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -9,6 +9,9 @@
 
 #include <linux/clk.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_panel.h>
+
 #include "drm.h"
 #include "dc.h"
 
@@ -85,13 +88,65 @@
 		tegra_dc_writel(dc, table[i].value, table[i].offset);
 }
 
-static int tegra_output_rgb_enable(struct tegra_output *output)
+static void tegra_rgb_connector_dpms(struct drm_connector *connector,
+				     int mode)
 {
-	struct tegra_rgb *rgb = to_rgb(output);
-	unsigned long value;
+}
 
-	if (rgb->enabled)
-		return 0;
+static const struct drm_connector_funcs tegra_rgb_connector_funcs = {
+	.dpms = tegra_rgb_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = tegra_output_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = tegra_output_connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_rgb_connector_mode_valid(struct drm_connector *connector,
+			       struct drm_display_mode *mode)
+{
+	/*
+	 * FIXME: For now, always assume that the mode is okay. There are
+	 * unresolved issues with clk_round_rate(), which doesn't always
+	 * reliably report whether a frequency can be set or not.
+	 */
+	return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_rgb_connector_helper_funcs = {
+	.get_modes = tegra_output_connector_get_modes,
+	.mode_valid = tegra_rgb_connector_mode_valid,
+	.best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_rgb_encoder_funcs = {
+	.destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_rgb_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_rgb_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_rgb_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_rgb_encoder_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_rgb *rgb = to_rgb(output);
+	u32 value;
+
+	if (output->panel)
+		drm_panel_prepare(output->panel);
 
 	tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
 
@@ -113,64 +168,39 @@
 	value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
 	tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
 
-	value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
-	value &= ~DISP_CTRL_MODE_MASK;
-	value |= DISP_CTRL_MODE_C_DISPLAY;
-	tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
+	tegra_dc_commit(rgb->dc);
 
-	value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
-	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-	tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-	tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
-	rgb->enabled = true;
-
-	return 0;
+	if (output->panel)
+		drm_panel_enable(output->panel);
 }
 
-static int tegra_output_rgb_disable(struct tegra_output *output)
+static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
 {
+	struct tegra_output *output = encoder_to_output(encoder);
 	struct tegra_rgb *rgb = to_rgb(output);
-	unsigned long value;
 
-	if (!rgb->enabled)
-		return 0;
-
-	value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
-	value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-		   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
-	tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-	value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
-	value &= ~DISP_CTRL_MODE_MASK;
-	tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
-
-	tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+	if (output->panel)
+		drm_panel_disable(output->panel);
 
 	tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
+	tegra_dc_commit(rgb->dc);
 
-	rgb->enabled = false;
-
-	return 0;
+	if (output->panel)
+		drm_panel_unprepare(output->panel);
 }
 
-static int tegra_output_rgb_setup_clock(struct tegra_output *output,
-					struct clk *clk, unsigned long pclk,
-					unsigned int *div)
+static int
+tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
 {
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+	unsigned long pclk = crtc_state->mode.clock * 1000;
 	struct tegra_rgb *rgb = to_rgb(output);
+	unsigned int div;
 	int err;
 
-	err = clk_set_parent(clk, rgb->clk_parent);
-	if (err < 0) {
-		dev_err(output->dev, "failed to set parent: %d\n", err);
-		return err;
-	}
-
 	/*
 	 * We may not want to change the frequency of the parent clock, since
 	 * it may be a parent for other peripherals. This is due to the fact
@@ -187,32 +217,26 @@
 	 * and hope that the desired frequency can be matched (or at least
 	 * matched sufficiently close that the panel will still work).
 	 */
+	div = ((clk_get_rate(rgb->clk) * 2) / pclk) - 2;
+	pclk = 0;
 
-	*div = ((clk_get_rate(clk) * 2) / pclk) - 2;
+	err = tegra_dc_state_setup_clock(dc, crtc_state, rgb->clk_parent,
+					 pclk, div);
+	if (err < 0) {
+		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
+		return err;
+	}
 
-	return 0;
+	return err;
 }
 
-static int tegra_output_rgb_check_mode(struct tegra_output *output,
-				       struct drm_display_mode *mode,
-				       enum drm_mode_status *status)
-{
-	/*
-	 * FIXME: For now, always assume that the mode is okay. There are
-	 * unresolved issues with clk_round_rate(), which doesn't always
-	 * reliably report whether a frequency can be set or not.
-	 */
-
-	*status = MODE_OK;
-
-	return 0;
-}
-
-static const struct tegra_output_ops rgb_ops = {
-	.enable = tegra_output_rgb_enable,
-	.disable = tegra_output_rgb_disable,
-	.setup_clock = tegra_output_rgb_setup_clock,
-	.check_mode = tegra_output_rgb_check_mode,
+static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
+	.dpms = tegra_rgb_encoder_dpms,
+	.prepare = tegra_rgb_encoder_prepare,
+	.commit = tegra_rgb_encoder_commit,
+	.mode_set = tegra_rgb_encoder_mode_set,
+	.disable = tegra_rgb_encoder_disable,
+	.atomic_check = tegra_rgb_encoder_atomic_check,
 };
 
 int tegra_dc_rgb_probe(struct tegra_dc *dc)
@@ -262,64 +286,58 @@
 
 int tegra_dc_rgb_remove(struct tegra_dc *dc)
 {
-	int err;
-
 	if (!dc->rgb)
 		return 0;
 
-	err = tegra_output_remove(dc->rgb);
-	if (err < 0)
-		return err;
+	tegra_output_remove(dc->rgb);
+	dc->rgb = NULL;
 
 	return 0;
 }
 
 int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
 {
-	struct tegra_rgb *rgb = to_rgb(dc->rgb);
+	struct tegra_output *output = dc->rgb;
 	int err;
 
 	if (!dc->rgb)
 		return -ENODEV;
 
-	rgb->output.type = TEGRA_OUTPUT_RGB;
-	rgb->output.ops = &rgb_ops;
+	drm_connector_init(drm, &output->connector, &tegra_rgb_connector_funcs,
+			   DRM_MODE_CONNECTOR_LVDS);
+	drm_connector_helper_add(&output->connector,
+				 &tegra_rgb_connector_helper_funcs);
+	output->connector.dpms = DRM_MODE_DPMS_OFF;
 
-	err = tegra_output_init(dc->base.dev, &rgb->output);
+	drm_encoder_init(drm, &output->encoder, &tegra_rgb_encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS);
+	drm_encoder_helper_add(&output->encoder,
+			       &tegra_rgb_encoder_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&output->connector,
+					  &output->encoder);
+	drm_connector_register(&output->connector);
+
+	err = tegra_output_init(drm, output);
 	if (err < 0) {
-		dev_err(dc->dev, "output setup failed: %d\n", err);
+		dev_err(output->dev, "failed to initialize output: %d\n", err);
 		return err;
 	}
 
 	/*
-	 * By default, outputs can be associated with each display controller.
-	 * RGB outputs are an exception, so we make sure they can be attached
-	 * to only their parent display controller.
+	 * Other outputs can be attached to either display controller. The RGB
+	 * outputs are an exception and work only with their parent display
+	 * controller.
 	 */
-	rgb->output.encoder.possible_crtcs = drm_crtc_mask(&dc->base);
+	output->encoder.possible_crtcs = drm_crtc_mask(&dc->base);
 
 	return 0;
 }
 
 int tegra_dc_rgb_exit(struct tegra_dc *dc)
 {
-	if (dc->rgb) {
-		int err;
-
-		err = tegra_output_disable(dc->rgb);
-		if (err < 0) {
-			dev_err(dc->dev, "output failed to disable: %d\n", err);
-			return err;
-		}
-
-		err = tegra_output_exit(dc->rgb);
-		if (err < 0) {
-			dev_err(dc->dev, "output cleanup failed: %d\n", err);
-			return err;
-		}
-
-		dc->rgb = NULL;
-	}
+	if (dc->rgb)
+		tegra_output_exit(dc->rgb);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 7829e81..2afe478 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -8,13 +8,16 @@
 
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/gpio.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 
 #include <soc/tegra/pmc.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
 
 #include "dc.h"
 #include "drm.h"
@@ -258,18 +261,8 @@
 
 static int tegra_sor_wakeup(struct tegra_sor *sor)
 {
-	struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc);
 	unsigned long value, timeout;
 
-	/* enable display controller outputs */
-	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
-	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
 	timeout = jiffies + msecs_to_jiffies(250);
 
 	/* wait for head to wake up */
@@ -482,10 +475,317 @@
 	return 0;
 }
 
-static int tegra_output_sor_enable(struct tegra_output *output)
+static int tegra_sor_detach(struct tegra_sor *sor)
 {
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-	struct drm_display_mode *mode = &dc->base.mode;
+	unsigned long value, timeout;
+
+	/* switch to safe mode */
+	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+	value &= ~SOR_SUPER_STATE_MODE_NORMAL;
+	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+	tegra_sor_super_update(sor);
+
+	timeout = jiffies + msecs_to_jiffies(250);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_sor_readl(sor, SOR_PWR);
+		if (value & SOR_PWR_MODE_SAFE)
+			break;
+	}
+
+	if ((value & SOR_PWR_MODE_SAFE) == 0)
+		return -ETIMEDOUT;
+
+	/* go to sleep */
+	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+	value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
+	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+	tegra_sor_super_update(sor);
+
+	/* detach */
+	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+	value &= ~SOR_SUPER_STATE_ATTACHED;
+	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+	tegra_sor_super_update(sor);
+
+	timeout = jiffies + msecs_to_jiffies(250);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_sor_readl(sor, SOR_TEST);
+		if ((value & SOR_TEST_ATTACHED) == 0)
+			break;
+
+		usleep_range(25, 100);
+	}
+
+	if ((value & SOR_TEST_ATTACHED) != 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int tegra_sor_power_down(struct tegra_sor *sor)
+{
+	unsigned long value, timeout;
+	int err;
+
+	value = tegra_sor_readl(sor, SOR_PWR);
+	value &= ~SOR_PWR_NORMAL_STATE_PU;
+	value |= SOR_PWR_TRIGGER;
+	tegra_sor_writel(sor, value, SOR_PWR);
+
+	timeout = jiffies + msecs_to_jiffies(250);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_sor_readl(sor, SOR_PWR);
+		if ((value & SOR_PWR_TRIGGER) == 0)
+			return 0;
+
+		usleep_range(25, 100);
+	}
+
+	if ((value & SOR_PWR_TRIGGER) != 0)
+		return -ETIMEDOUT;
+
+	err = clk_set_parent(sor->clk, sor->clk_safe);
+	if (err < 0)
+		dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
+
+	value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+	value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
+		   SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
+	tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+	/* stop lane sequencer */
+	value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP |
+		SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
+	tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
+
+	timeout = jiffies + msecs_to_jiffies(250);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+		if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
+			break;
+
+		usleep_range(25, 100);
+	}
+
+	if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
+		return -ETIMEDOUT;
+
+	value = tegra_sor_readl(sor, SOR_PLL_2);
+	value |= SOR_PLL_2_PORT_POWERDOWN;
+	tegra_sor_writel(sor, value, SOR_PLL_2);
+
+	usleep_range(20, 100);
+
+	value = tegra_sor_readl(sor, SOR_PLL_0);
+	value |= SOR_PLL_0_POWER_OFF;
+	value |= SOR_PLL_0_VCOPD;
+	tegra_sor_writel(sor, value, SOR_PLL_0);
+
+	value = tegra_sor_readl(sor, SOR_PLL_2);
+	value |= SOR_PLL_2_SEQ_PLLCAPPD;
+	value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
+	tegra_sor_writel(sor, value, SOR_PLL_2);
+
+	usleep_range(20, 100);
+
+	return 0;
+}
+
+static int tegra_sor_crc_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+
+	return 0;
+}
+
+static int tegra_sor_crc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
+{
+	u32 value;
+
+	timeout = jiffies + msecs_to_jiffies(timeout);
+
+	while (time_before(jiffies, timeout)) {
+		value = tegra_sor_readl(sor, SOR_CRC_A);
+		if (value & SOR_CRC_A_VALID)
+			return 0;
+
+		usleep_range(100, 200);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
+				  size_t size, loff_t *ppos)
+{
+	struct tegra_sor *sor = file->private_data;
+	ssize_t num, err;
+	char buf[10];
+	u32 value;
+
+	mutex_lock(&sor->lock);
+
+	if (!sor->enabled) {
+		err = -EAGAIN;
+		goto unlock;
+	}
+
+	value = tegra_sor_readl(sor, SOR_STATE_1);
+	value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
+	tegra_sor_writel(sor, value, SOR_STATE_1);
+
+	value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
+	value |= SOR_CRC_CNTRL_ENABLE;
+	tegra_sor_writel(sor, value, SOR_CRC_CNTRL);
+
+	value = tegra_sor_readl(sor, SOR_TEST);
+	value &= ~SOR_TEST_CRC_POST_SERIALIZE;
+	tegra_sor_writel(sor, value, SOR_TEST);
+
+	err = tegra_sor_crc_wait(sor, 100);
+	if (err < 0)
+		goto unlock;
+
+	tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
+	value = tegra_sor_readl(sor, SOR_CRC_B);
+
+	num = scnprintf(buf, sizeof(buf), "%08x\n", value);
+
+	err = simple_read_from_buffer(buffer, size, ppos, buf, num);
+
+unlock:
+	mutex_unlock(&sor->lock);
+	return err;
+}
+
+static const struct file_operations tegra_sor_crc_fops = {
+	.owner = THIS_MODULE,
+	.open = tegra_sor_crc_open,
+	.read = tegra_sor_crc_read,
+	.release = tegra_sor_crc_release,
+};
+
+static int tegra_sor_debugfs_init(struct tegra_sor *sor,
+				  struct drm_minor *minor)
+{
+	struct dentry *entry;
+	int err = 0;
+
+	sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
+	if (!sor->debugfs)
+		return -ENOMEM;
+
+	entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
+				    &tegra_sor_crc_fops);
+	if (!entry) {
+		dev_err(sor->dev,
+			"cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
+			minor->debugfs_root->d_name.name);
+		err = -ENOMEM;
+		goto remove;
+	}
+
+	return err;
+
+remove:
+	debugfs_remove(sor->debugfs);
+	sor->debugfs = NULL;
+	return err;
+}
+
+static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
+{
+	debugfs_remove_recursive(sor->debugfs);
+	sor->debugfs = NULL;
+}
+
+static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
+{
+}
+
+static enum drm_connector_status
+tegra_sor_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct tegra_output *output = connector_to_output(connector);
+	struct tegra_sor *sor = to_sor(output);
+
+	if (sor->dpaux)
+		return tegra_dpaux_detect(sor->dpaux);
+
+	return connector_status_unknown;
+}
+
+static const struct drm_connector_funcs tegra_sor_connector_funcs = {
+	.dpms = tegra_sor_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = tegra_sor_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = tegra_output_connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int tegra_sor_connector_get_modes(struct drm_connector *connector)
+{
+	struct tegra_output *output = connector_to_output(connector);
+	struct tegra_sor *sor = to_sor(output);
+	int err;
+
+	if (sor->dpaux)
+		tegra_dpaux_enable(sor->dpaux);
+
+	err = tegra_output_connector_get_modes(connector);
+
+	if (sor->dpaux)
+		tegra_dpaux_disable(sor->dpaux);
+
+	return err;
+}
+
+static enum drm_mode_status
+tegra_sor_connector_mode_valid(struct drm_connector *connector,
+			       struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = {
+	.get_modes = tegra_sor_connector_get_modes,
+	.mode_valid = tegra_sor_connector_mode_valid,
+	.best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_sor_encoder_funcs = {
+	.destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_sor_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_sor_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_sor_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
 	unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
 	struct tegra_sor *sor = to_sor(output);
 	struct tegra_sor_config config;
@@ -505,6 +805,9 @@
 
 	reset_control_deassert(sor->rst);
 
+	if (output->panel)
+		drm_panel_prepare(output->panel);
+
 	/* FIXME: properly convert to struct drm_dp_aux */
 	aux = (struct drm_dp_aux *)sor->dpaux;
 
@@ -800,18 +1103,6 @@
 		goto unlock;
 	}
 
-	/* start display controller in continuous mode */
-	value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
-	value |= WRITE_MUX;
-	tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
-
-	tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS);
-	tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
-
-	value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
-	value &= ~WRITE_MUX;
-	tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
-
 	/*
 	 * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
 	 * raster, associate with display controller)
@@ -886,11 +1177,13 @@
 		goto unlock;
 	}
 
+	tegra_sor_update(sor);
+
 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
 	value |= SOR_ENABLE;
 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-	tegra_sor_update(sor);
+	tegra_dc_commit(dc);
 
 	err = tegra_sor_attach(sor);
 	if (err < 0) {
@@ -904,145 +1197,31 @@
 		goto unlock;
 	}
 
+	if (output->panel)
+		drm_panel_enable(output->panel);
+
 	sor->enabled = true;
 
 unlock:
 	mutex_unlock(&sor->lock);
-	return err;
 }
 
-static int tegra_sor_detach(struct tegra_sor *sor)
+static void tegra_sor_encoder_disable(struct drm_encoder *encoder)
 {
-	unsigned long value, timeout;
-
-	/* switch to safe mode */
-	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
-	value &= ~SOR_SUPER_STATE_MODE_NORMAL;
-	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
-	tegra_sor_super_update(sor);
-
-	timeout = jiffies + msecs_to_jiffies(250);
-
-	while (time_before(jiffies, timeout)) {
-		value = tegra_sor_readl(sor, SOR_PWR);
-		if (value & SOR_PWR_MODE_SAFE)
-			break;
-	}
-
-	if ((value & SOR_PWR_MODE_SAFE) == 0)
-		return -ETIMEDOUT;
-
-	/* go to sleep */
-	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
-	value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
-	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
-	tegra_sor_super_update(sor);
-
-	/* detach */
-	value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
-	value &= ~SOR_SUPER_STATE_ATTACHED;
-	tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
-	tegra_sor_super_update(sor);
-
-	timeout = jiffies + msecs_to_jiffies(250);
-
-	while (time_before(jiffies, timeout)) {
-		value = tegra_sor_readl(sor, SOR_TEST);
-		if ((value & SOR_TEST_ATTACHED) == 0)
-			break;
-
-		usleep_range(25, 100);
-	}
-
-	if ((value & SOR_TEST_ATTACHED) != 0)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-static int tegra_sor_power_down(struct tegra_sor *sor)
-{
-	unsigned long value, timeout;
-	int err;
-
-	value = tegra_sor_readl(sor, SOR_PWR);
-	value &= ~SOR_PWR_NORMAL_STATE_PU;
-	value |= SOR_PWR_TRIGGER;
-	tegra_sor_writel(sor, value, SOR_PWR);
-
-	timeout = jiffies + msecs_to_jiffies(250);
-
-	while (time_before(jiffies, timeout)) {
-		value = tegra_sor_readl(sor, SOR_PWR);
-		if ((value & SOR_PWR_TRIGGER) == 0)
-			return 0;
-
-		usleep_range(25, 100);
-	}
-
-	if ((value & SOR_PWR_TRIGGER) != 0)
-		return -ETIMEDOUT;
-
-	err = clk_set_parent(sor->clk, sor->clk_safe);
-	if (err < 0)
-		dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
-
-	value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
-	value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
-		   SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
-	tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
-
-	/* stop lane sequencer */
-	value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP |
-		SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
-	tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
-
-	timeout = jiffies + msecs_to_jiffies(250);
-
-	while (time_before(jiffies, timeout)) {
-		value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
-		if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
-			break;
-
-		usleep_range(25, 100);
-	}
-
-	if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
-		return -ETIMEDOUT;
-
-	value = tegra_sor_readl(sor, SOR_PLL_2);
-	value |= SOR_PLL_2_PORT_POWERDOWN;
-	tegra_sor_writel(sor, value, SOR_PLL_2);
-
-	usleep_range(20, 100);
-
-	value = tegra_sor_readl(sor, SOR_PLL_0);
-	value |= SOR_PLL_0_POWER_OFF;
-	value |= SOR_PLL_0_VCOPD;
-	tegra_sor_writel(sor, value, SOR_PLL_0);
-
-	value = tegra_sor_readl(sor, SOR_PLL_2);
-	value |= SOR_PLL_2_SEQ_PLLCAPPD;
-	value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
-	tegra_sor_writel(sor, value, SOR_PLL_2);
-
-	usleep_range(20, 100);
-
-	return 0;
-}
-
-static int tegra_output_sor_disable(struct tegra_output *output)
-{
-	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
 	struct tegra_sor *sor = to_sor(output);
-	unsigned long value;
-	int err = 0;
+	u32 value;
+	int err;
 
 	mutex_lock(&sor->lock);
 
 	if (!sor->enabled)
 		goto unlock;
 
+	if (output->panel)
+		drm_panel_disable(output->panel);
+
 	err = tegra_sor_detach(sor);
 	if (err < 0) {
 		dev_err(sor->dev, "failed to detach SOR: %d\n", err);
@@ -1057,31 +1236,11 @@
 	 * sure it's only executed when the output is attached to one.
 	 */
 	if (dc) {
-		/*
-		 * XXX: We can't do this here because it causes the SOR to go
-		 * into an erroneous state and the output will look scrambled
-		 * the next time it is enabled. Presumably this is because we
-		 * should be doing this only on the next VBLANK. A possible
-		 * solution would be to queue a "power-off" event to trigger
-		 * this code to be run during the next VBLANK.
-		 */
-		/*
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
-		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-		*/
-
-		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-		value &= ~DISP_CTRL_MODE_MASK;
-		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
 		value &= ~SOR_ENABLE;
 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-		tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-		tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+		tegra_dc_commit(dc);
 	}
 
 	err = tegra_sor_power_down(sor);
@@ -1104,187 +1263,48 @@
 		goto unlock;
 	}
 
-	reset_control_assert(sor->rst);
+	if (output->panel)
+		drm_panel_unprepare(output->panel);
+
 	clk_disable_unprepare(sor->clk);
+	reset_control_assert(sor->rst);
 
 	sor->enabled = false;
 
 unlock:
 	mutex_unlock(&sor->lock);
-	return err;
 }
 
-static int tegra_output_sor_setup_clock(struct tegra_output *output,
-					struct clk *clk, unsigned long pclk,
-					unsigned int *div)
+static int
+tegra_sor_encoder_atomic_check(struct drm_encoder *encoder,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
 {
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+	unsigned long pclk = crtc_state->mode.clock * 1000;
 	struct tegra_sor *sor = to_sor(output);
 	int err;
 
-	err = clk_set_parent(clk, sor->clk_parent);
+	err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent,
+					 pclk, 0);
 	if (err < 0) {
-		dev_err(sor->dev, "failed to set parent clock: %d\n", err);
+		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
 		return err;
 	}
 
-	err = clk_set_rate(sor->clk_parent, pclk);
-	if (err < 0) {
-		dev_err(sor->dev, "failed to set clock rate to %lu Hz\n", pclk);
-		return err;
-	}
-
-	*div = 0;
-
 	return 0;
 }
 
-static int tegra_output_sor_check_mode(struct tegra_output *output,
-				       struct drm_display_mode *mode,
-				       enum drm_mode_status *status)
-{
-	/*
-	 * FIXME: For now, always assume that the mode is okay.
-	 */
-
-	*status = MODE_OK;
-
-	return 0;
-}
-
-static enum drm_connector_status
-tegra_output_sor_detect(struct tegra_output *output)
-{
-	struct tegra_sor *sor = to_sor(output);
-
-	if (sor->dpaux)
-		return tegra_dpaux_detect(sor->dpaux);
-
-	return connector_status_unknown;
-}
-
-static const struct tegra_output_ops sor_ops = {
-	.enable = tegra_output_sor_enable,
-	.disable = tegra_output_sor_disable,
-	.setup_clock = tegra_output_sor_setup_clock,
-	.check_mode = tegra_output_sor_check_mode,
-	.detect = tegra_output_sor_detect,
+static const struct drm_encoder_helper_funcs tegra_sor_encoder_helper_funcs = {
+	.dpms = tegra_sor_encoder_dpms,
+	.prepare = tegra_sor_encoder_prepare,
+	.commit = tegra_sor_encoder_commit,
+	.mode_set = tegra_sor_encoder_mode_set,
+	.disable = tegra_sor_encoder_disable,
+	.atomic_check = tegra_sor_encoder_atomic_check,
 };
 
-static int tegra_sor_crc_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-
-	return 0;
-}
-
-static int tegra_sor_crc_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
-{
-	u32 value;
-
-	timeout = jiffies + msecs_to_jiffies(timeout);
-
-	while (time_before(jiffies, timeout)) {
-		value = tegra_sor_readl(sor, SOR_CRC_A);
-		if (value & SOR_CRC_A_VALID)
-			return 0;
-
-		usleep_range(100, 200);
-	}
-
-	return -ETIMEDOUT;
-}
-
-static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
-				  size_t size, loff_t *ppos)
-{
-	struct tegra_sor *sor = file->private_data;
-	ssize_t num, err;
-	char buf[10];
-	u32 value;
-
-	mutex_lock(&sor->lock);
-
-	if (!sor->enabled) {
-		err = -EAGAIN;
-		goto unlock;
-	}
-
-	value = tegra_sor_readl(sor, SOR_STATE_1);
-	value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
-	tegra_sor_writel(sor, value, SOR_STATE_1);
-
-	value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
-	value |= SOR_CRC_CNTRL_ENABLE;
-	tegra_sor_writel(sor, value, SOR_CRC_CNTRL);
-
-	value = tegra_sor_readl(sor, SOR_TEST);
-	value &= ~SOR_TEST_CRC_POST_SERIALIZE;
-	tegra_sor_writel(sor, value, SOR_TEST);
-
-	err = tegra_sor_crc_wait(sor, 100);
-	if (err < 0)
-		goto unlock;
-
-	tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
-	value = tegra_sor_readl(sor, SOR_CRC_B);
-
-	num = scnprintf(buf, sizeof(buf), "%08x\n", value);
-
-	err = simple_read_from_buffer(buffer, size, ppos, buf, num);
-
-unlock:
-	mutex_unlock(&sor->lock);
-	return err;
-}
-
-static const struct file_operations tegra_sor_crc_fops = {
-	.owner = THIS_MODULE,
-	.open = tegra_sor_crc_open,
-	.read = tegra_sor_crc_read,
-	.release = tegra_sor_crc_release,
-};
-
-static int tegra_sor_debugfs_init(struct tegra_sor *sor,
-				  struct drm_minor *minor)
-{
-	struct dentry *entry;
-	int err = 0;
-
-	sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
-	if (!sor->debugfs)
-		return -ENOMEM;
-
-	entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
-				    &tegra_sor_crc_fops);
-	if (!entry) {
-		dev_err(sor->dev,
-			"cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
-			minor->debugfs_root->d_name.name);
-		err = -ENOMEM;
-		goto remove;
-	}
-
-	return err;
-
-remove:
-	debugfs_remove(sor->debugfs);
-	sor->debugfs = NULL;
-	return err;
-}
-
-static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
-{
-	debugfs_remove_recursive(sor->debugfs);
-	sor->debugfs = NULL;
-
-	return 0;
-}
-
 static int tegra_sor_init(struct host1x_client *client)
 {
 	struct drm_device *drm = dev_get_drvdata(client->parent);
@@ -1294,17 +1314,32 @@
 	if (!sor->dpaux)
 		return -ENODEV;
 
-	sor->output.type = TEGRA_OUTPUT_EDP;
-
 	sor->output.dev = sor->dev;
-	sor->output.ops = &sor_ops;
+
+	drm_connector_init(drm, &sor->output.connector,
+			   &tegra_sor_connector_funcs,
+			   DRM_MODE_CONNECTOR_eDP);
+	drm_connector_helper_add(&sor->output.connector,
+				 &tegra_sor_connector_helper_funcs);
+	sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+	drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+	drm_encoder_helper_add(&sor->output.encoder,
+			       &tegra_sor_encoder_helper_funcs);
+
+	drm_mode_connector_attach_encoder(&sor->output.connector,
+					  &sor->output.encoder);
+	drm_connector_register(&sor->output.connector);
 
 	err = tegra_output_init(drm, &sor->output);
 	if (err < 0) {
-		dev_err(sor->dev, "output setup failed: %d\n", err);
+		dev_err(client->dev, "failed to initialize output: %d\n", err);
 		return err;
 	}
 
+	sor->output.encoder.possible_crtcs = 0x3;
+
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
 		err = tegra_sor_debugfs_init(sor, drm->primary);
 		if (err < 0)
@@ -1319,6 +1354,20 @@
 		}
 	}
 
+	err = clk_prepare_enable(sor->clk);
+	if (err < 0) {
+		dev_err(sor->dev, "failed to enable clock: %d\n", err);
+		return err;
+	}
+
+	err = clk_prepare_enable(sor->clk_safe);
+	if (err < 0)
+		return err;
+
+	err = clk_prepare_enable(sor->clk_dp);
+	if (err < 0)
+		return err;
+
 	return 0;
 }
 
@@ -1327,11 +1376,7 @@
 	struct tegra_sor *sor = host1x_client_to_sor(client);
 	int err;
 
-	err = tegra_output_disable(&sor->output);
-	if (err < 0) {
-		dev_err(sor->dev, "output failed to disable: %d\n", err);
-		return err;
-	}
+	tegra_output_exit(&sor->output);
 
 	if (sor->dpaux) {
 		err = tegra_dpaux_detach(sor->dpaux);
@@ -1341,17 +1386,12 @@
 		}
 	}
 
-	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
-		err = tegra_sor_debugfs_exit(sor);
-		if (err < 0)
-			dev_err(sor->dev, "debugfs cleanup failed: %d\n", err);
-	}
+	clk_disable_unprepare(sor->clk_safe);
+	clk_disable_unprepare(sor->clk_dp);
+	clk_disable_unprepare(sor->clk);
 
-	err = tegra_output_exit(&sor->output);
-	if (err < 0) {
-		dev_err(sor->dev, "output cleanup failed: %d\n", err);
-		return err;
-	}
+	if (IS_ENABLED(CONFIG_DEBUG_FS))
+		tegra_sor_debugfs_exit(sor);
 
 	return 0;
 }
@@ -1404,26 +1444,14 @@
 	if (IS_ERR(sor->clk_parent))
 		return PTR_ERR(sor->clk_parent);
 
-	err = clk_prepare_enable(sor->clk_parent);
-	if (err < 0)
-		return err;
-
 	sor->clk_safe = devm_clk_get(&pdev->dev, "safe");
 	if (IS_ERR(sor->clk_safe))
 		return PTR_ERR(sor->clk_safe);
 
-	err = clk_prepare_enable(sor->clk_safe);
-	if (err < 0)
-		return err;
-
 	sor->clk_dp = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(sor->clk_dp))
 		return PTR_ERR(sor->clk_dp);
 
-	err = clk_prepare_enable(sor->clk_dp);
-	if (err < 0)
-		return err;
-
 	INIT_LIST_HEAD(&sor->client.list);
 	sor->client.ops = &sor_client_ops;
 	sor->client.dev = &pdev->dev;
@@ -1454,10 +1482,7 @@
 		return err;
 	}
 
-	clk_disable_unprepare(sor->clk_parent);
-	clk_disable_unprepare(sor->clk_safe);
-	clk_disable_unprepare(sor->clk_dp);
-	clk_disable_unprepare(sor->clk);
+	tegra_output_remove(&sor->output);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index 7c3ef79..8394a0b 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -1,6 +1,6 @@
 config DRM_TILCDC
 	tristate "DRM Support for TI LCDC Display Controller"
-	depends on DRM && OF && ARM
+	depends on DRM && OF && ARM && HAVE_DMA_ATTRS
 	select DRM_KMS_HELPER
 	select DRM_KMS_FB_HELPER
 	select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 8cbcb45..5fc16ce 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -589,19 +589,27 @@
 
 	ret = drm_fb_helper_init(dev, &ufbdev->helper,
 				 1, 1);
-	if (ret) {
-		kfree(ufbdev);
-		return ret;
+	if (ret)
+		goto free;
 
-	}
-
-	drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+	ret = drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+	if (ret)
+		goto fini;
 
 	/* disable all the possible outputs/crtcs before entering KMS mode */
 	drm_helper_disable_unused_functions(dev);
 
-	drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+	ret = drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+	if (ret)
+		goto fini;
+
 	return 0;
+
+fini:
+	drm_fb_helper_fini(&ufbdev->helper);
+free:
+	kfree(ufbdev);
+	return ret;
 }
 
 void udl_fbdev_cleanup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 1701f1d..677190a6 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -340,11 +340,11 @@
 
 	wrptr = udl_dummy_render(wrptr);
 
-	ufb->active_16 = true;
 	if (old_fb) {
 		struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
 		uold_fb->active_16 = false;
 	}
+	ufb->active_16 = true;
 	udl->mode_buf_len = wrptr - buf;
 
 	/* damage all of it */
@@ -373,6 +373,13 @@
 	struct drm_device *dev = crtc->dev;
 	unsigned long flags;
 
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
+	if (old_fb) {
+		struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
+		uold_fb->active_16 = false;
+	}
+	ufb->active_16 = true;
+
 	udl_handle_damage(ufb, 0, 0, fb->width, fb->height);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
index f343db7..917dcb9 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -82,12 +82,14 @@
 		((pixel >> 8) & 0xf800));
 }
 
-static bool pixel_repeats(const void *pixel, const uint32_t repeat, int bpp)
+static inline u16 get_pixel_val16(const uint8_t *pixel, int bpp)
 {
+	u16 pixel_val16 = 0;
 	if (bpp == 2)
-		return *(const uint16_t *)pixel == repeat;
-	else
-		return *(const uint32_t *)pixel == repeat;
+		pixel_val16 = *(const uint16_t *)pixel;
+	else if (bpp == 4)
+		pixel_val16 = pixel32_to_be16(*(const uint32_t *)pixel);
+	return pixel_val16;
 }
 
 /*
@@ -134,6 +136,7 @@
 		uint8_t *cmd_pixels_count_byte = NULL;
 		const u8 *raw_pixel_start = NULL;
 		const u8 *cmd_pixel_start, *cmd_pixel_end = NULL;
+		uint16_t pixel_val16;
 
 		prefetchw((void *) cmd); /* pull in one cache line at least */
 
@@ -154,33 +157,29 @@
 			    (int)(cmd_buffer_end - cmd) / 2))) * bpp;
 
 		prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
+		pixel_val16 = get_pixel_val16(pixel, bpp);
 
 		while (pixel < cmd_pixel_end) {
 			const u8 *const start = pixel;
-			u32 repeating_pixel;
+			const uint16_t repeating_pixel_val16 = pixel_val16;
 
-			if (bpp == 2) {
-				repeating_pixel = *(uint16_t *)pixel;
-				*(uint16_t *)cmd = cpu_to_be16(repeating_pixel);
-			} else {
-				repeating_pixel = *(uint32_t *)pixel;
-				*(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16(repeating_pixel));
-			}
+			*(uint16_t *)cmd = cpu_to_be16(pixel_val16);
 
 			cmd += 2;
 			pixel += bpp;
 
-			if (unlikely((pixel < cmd_pixel_end) &&
-				     (pixel_repeats(pixel, repeating_pixel, bpp)))) {
+			while (pixel < cmd_pixel_end) {
+				pixel_val16 = get_pixel_val16(pixel, bpp);
+				if (pixel_val16 != repeating_pixel_val16)
+					break;
+				pixel += bpp;
+			}
+
+			if (unlikely(pixel > start + bpp)) {
 				/* go back and fill in raw pixel count */
 				*raw_pixels_count_byte = (((start -
 						raw_pixel_start) / bpp) + 1) & 0xFF;
 
-				while ((pixel < cmd_pixel_end) &&
-				       (pixel_repeats(pixel, repeating_pixel, bpp))) {
-					pixel += bpp;
-				}
-
 				/* immediately after raw data is repeat byte */
 				*cmd++ = (((pixel - start) / bpp) - 1) & 0xFF;
 
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index aaf5485..4a99c64 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -72,13 +72,14 @@
 /**
  * host1x_device_parse_dt() - scan device tree and add matching subdevices
  */
-static int host1x_device_parse_dt(struct host1x_device *device)
+static int host1x_device_parse_dt(struct host1x_device *device,
+				  struct host1x_driver *driver)
 {
 	struct device_node *np;
 	int err;
 
 	for_each_child_of_node(device->dev.parent->of_node, np) {
-		if (of_match_node(device->driver->subdevs, np) &&
+		if (of_match_node(driver->subdevs, np) &&
 		    of_device_is_available(np)) {
 			err = host1x_subdev_add(device, np);
 			if (err < 0)
@@ -109,14 +110,12 @@
 	mutex_unlock(&device->clients_lock);
 	mutex_unlock(&device->subdevs_lock);
 
-	/*
-	 * When all subdevices have been registered, the composite device is
-	 * ready to be probed.
-	 */
 	if (list_empty(&device->subdevs)) {
-		err = device->driver->probe(device);
+		err = device_add(&device->dev);
 		if (err < 0)
-			dev_err(&device->dev, "probe failed: %d\n", err);
+			dev_err(&device->dev, "failed to add: %d\n", err);
+		else
+			device->registered = true;
 	}
 }
 
@@ -124,16 +123,16 @@
 				       struct host1x_subdev *subdev)
 {
 	struct host1x_client *client = subdev->client;
-	int err;
 
 	/*
 	 * If all subdevices have been activated, we're about to remove the
 	 * first active subdevice, so unload the driver first.
 	 */
 	if (list_empty(&device->subdevs)) {
-		err = device->driver->remove(device);
-		if (err < 0)
-			dev_err(&device->dev, "remove failed: %d\n", err);
+		if (device->registered) {
+			device->registered = false;
+			device_del(&device->dev);
+		}
 	}
 
 	/*
@@ -260,92 +259,61 @@
 	return -ENODEV;
 }
 
-static struct bus_type host1x_bus_type = {
-	.name = "host1x",
-};
-
-int host1x_bus_init(void)
+static int host1x_device_match(struct device *dev, struct device_driver *drv)
 {
-	return bus_register(&host1x_bus_type);
+	return strcmp(dev_name(dev), drv->name) == 0;
 }
 
-void host1x_bus_exit(void)
+static int host1x_device_probe(struct device *dev)
 {
-	bus_unregister(&host1x_bus_type);
-}
-
-static void host1x_device_release(struct device *dev)
-{
+	struct host1x_driver *driver = to_host1x_driver(dev->driver);
 	struct host1x_device *device = to_host1x_device(dev);
 
-	kfree(device);
-}
-
-static int host1x_device_add(struct host1x *host1x,
-			     struct host1x_driver *driver)
-{
-	struct host1x_client *client, *tmp;
-	struct host1x_subdev *subdev;
-	struct host1x_device *device;
-	int err;
-
-	device = kzalloc(sizeof(*device), GFP_KERNEL);
-	if (!device)
-		return -ENOMEM;
-
-	mutex_init(&device->subdevs_lock);
-	INIT_LIST_HEAD(&device->subdevs);
-	INIT_LIST_HEAD(&device->active);
-	mutex_init(&device->clients_lock);
-	INIT_LIST_HEAD(&device->clients);
-	INIT_LIST_HEAD(&device->list);
-	device->driver = driver;
-
-	device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
-	device->dev.dma_mask = &device->dev.coherent_dma_mask;
-	device->dev.release = host1x_device_release;
-	dev_set_name(&device->dev, "%s", driver->name);
-	device->dev.bus = &host1x_bus_type;
-	device->dev.parent = host1x->dev;
-
-	err = device_register(&device->dev);
-	if (err < 0)
-		return err;
-
-	err = host1x_device_parse_dt(device);
-	if (err < 0) {
-		device_unregister(&device->dev);
-		return err;
-	}
-
-	mutex_lock(&host1x->devices_lock);
-	list_add_tail(&device->list, &host1x->devices);
-	mutex_unlock(&host1x->devices_lock);
-
-	mutex_lock(&clients_lock);
-
-	list_for_each_entry_safe(client, tmp, &clients, list) {
-		list_for_each_entry(subdev, &device->subdevs, list) {
-			if (subdev->np == client->dev->of_node) {
-				host1x_subdev_register(device, subdev, client);
-				break;
-			}
-		}
-	}
-
-	mutex_unlock(&clients_lock);
+	if (driver->probe)
+		return driver->probe(device);
 
 	return 0;
 }
 
-/*
- * Removes a device by first unregistering any subdevices and then removing
- * itself from the list of devices.
- *
- * This function must be called with the host1x->devices_lock held.
- */
-static void host1x_device_del(struct host1x *host1x,
-			      struct host1x_device *device)
+static int host1x_device_remove(struct device *dev)
+{
+	struct host1x_driver *driver = to_host1x_driver(dev->driver);
+	struct host1x_device *device = to_host1x_device(dev);
+
+	if (driver->remove)
+		return driver->remove(device);
+
+	return 0;
+}
+
+static void host1x_device_shutdown(struct device *dev)
+{
+	struct host1x_driver *driver = to_host1x_driver(dev->driver);
+	struct host1x_device *device = to_host1x_device(dev);
+
+	if (driver->shutdown)
+		driver->shutdown(device);
+}
+
+static const struct dev_pm_ops host1x_device_pm_ops = {
+	.suspend = pm_generic_suspend,
+	.resume = pm_generic_resume,
+	.freeze = pm_generic_freeze,
+	.thaw = pm_generic_thaw,
+	.poweroff = pm_generic_poweroff,
+	.restore = pm_generic_restore,
+};
+
+struct bus_type host1x_bus_type = {
+	.name = "host1x",
+	.match = host1x_device_match,
+	.probe = host1x_device_probe,
+	.remove = host1x_device_remove,
+	.shutdown = host1x_device_shutdown,
+	.pm = &host1x_device_pm_ops,
+};
+
+static void __host1x_device_del(struct host1x_device *device)
 {
 	struct host1x_subdev *subdev, *sd;
 	struct host1x_client *client, *cl;
@@ -391,7 +359,84 @@
 
 	/* finally remove the device */
 	list_del_init(&device->list);
-	device_unregister(&device->dev);
+}
+
+static void host1x_device_release(struct device *dev)
+{
+	struct host1x_device *device = to_host1x_device(dev);
+
+	__host1x_device_del(device);
+	kfree(device);
+}
+
+static int host1x_device_add(struct host1x *host1x,
+			     struct host1x_driver *driver)
+{
+	struct host1x_client *client, *tmp;
+	struct host1x_subdev *subdev;
+	struct host1x_device *device;
+	int err;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device_initialize(&device->dev);
+
+	mutex_init(&device->subdevs_lock);
+	INIT_LIST_HEAD(&device->subdevs);
+	INIT_LIST_HEAD(&device->active);
+	mutex_init(&device->clients_lock);
+	INIT_LIST_HEAD(&device->clients);
+	INIT_LIST_HEAD(&device->list);
+	device->driver = driver;
+
+	device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
+	device->dev.dma_mask = &device->dev.coherent_dma_mask;
+	dev_set_name(&device->dev, "%s", driver->driver.name);
+	device->dev.release = host1x_device_release;
+	device->dev.bus = &host1x_bus_type;
+	device->dev.parent = host1x->dev;
+
+	err = host1x_device_parse_dt(device, driver);
+	if (err < 0) {
+		kfree(device);
+		return err;
+	}
+
+	list_add_tail(&device->list, &host1x->devices);
+
+	mutex_lock(&clients_lock);
+
+	list_for_each_entry_safe(client, tmp, &clients, list) {
+		list_for_each_entry(subdev, &device->subdevs, list) {
+			if (subdev->np == client->dev->of_node) {
+				host1x_subdev_register(device, subdev, client);
+				break;
+			}
+		}
+	}
+
+	mutex_unlock(&clients_lock);
+
+	return 0;
+}
+
+/*
+ * Removes a device by first unregistering any subdevices and then removing
+ * itself from the list of devices.
+ *
+ * This function must be called with the host1x->devices_lock held.
+ */
+static void host1x_device_del(struct host1x *host1x,
+			      struct host1x_device *device)
+{
+	if (device->registered) {
+		device->registered = false;
+		device_del(&device->dev);
+	}
+
+	put_device(&device->dev);
 }
 
 static void host1x_attach_driver(struct host1x *host1x,
@@ -409,11 +454,11 @@
 		}
 	}
 
-	mutex_unlock(&host1x->devices_lock);
-
 	err = host1x_device_add(host1x, driver);
 	if (err < 0)
 		dev_err(host1x->dev, "failed to allocate device: %d\n", err);
+
+	mutex_unlock(&host1x->devices_lock);
 }
 
 static void host1x_detach_driver(struct host1x *host1x,
@@ -466,7 +511,8 @@
 	return 0;
 }
 
-int host1x_driver_register(struct host1x_driver *driver)
+int host1x_driver_register_full(struct host1x_driver *driver,
+				struct module *owner)
 {
 	struct host1x *host1x;
 
@@ -483,9 +529,12 @@
 
 	mutex_unlock(&devices_lock);
 
-	return 0;
+	driver->driver.bus = &host1x_bus_type;
+	driver->driver.owner = owner;
+
+	return driver_register(&driver->driver);
 }
-EXPORT_SYMBOL(host1x_driver_register);
+EXPORT_SYMBOL(host1x_driver_register_full);
 
 void host1x_driver_unregister(struct host1x_driver *driver)
 {
diff --git a/drivers/gpu/host1x/bus.h b/drivers/gpu/host1x/bus.h
index 4099e99..88fb1c4 100644
--- a/drivers/gpu/host1x/bus.h
+++ b/drivers/gpu/host1x/bus.h
@@ -18,10 +18,10 @@
 #ifndef HOST1X_BUS_H
 #define HOST1X_BUS_H
 
+struct bus_type;
 struct host1x;
 
-int host1x_bus_init(void);
-void host1x_bus_exit(void);
+extern struct bus_type host1x_bus_type;
 
 int host1x_register(struct host1x *host1x);
 int host1x_unregister(struct host1x *host1x);
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 2529908..53d3d1d 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -216,7 +216,7 @@
 {
 	int err;
 
-	err = host1x_bus_init();
+	err = bus_register(&host1x_bus_type);
 	if (err < 0)
 		return err;
 
@@ -233,7 +233,7 @@
 unregister_host1x:
 	platform_driver_unregister(&tegra_host1x_driver);
 unregister_bus:
-	host1x_bus_exit();
+	bus_unregister(&host1x_bus_type);
 	return err;
 }
 module_init(tegra_host1x_init);
@@ -242,7 +242,7 @@
 {
 	platform_driver_unregister(&tegra_mipi_driver);
 	platform_driver_unregister(&tegra_host1x_driver);
-	host1x_bus_exit();
+	bus_unregister(&host1x_bus_type);
 }
 module_exit(tegra_host1x_exit);
 
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index f707d25..67bab5c 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -742,7 +742,7 @@
 	.tpm_ofs = 0x1f060000,
 	.csi0_ofs = 0x1f030000,
 	.csi1_ofs = 0x1f038000,
-	.ic_ofs = 0x1f020000,
+	.ic_ofs = 0x1e020000,
 	.disp0_ofs = 0x1e040000,
 	.disp1_ofs = 0x1e048000,
 	.dc_tmpl_ofs = 0x1f080000,
@@ -758,7 +758,7 @@
 	.tpm_ofs = 0x07060000,
 	.csi0_ofs = 0x07030000,
 	.csi1_ofs = 0x07038000,
-	.ic_ofs = 0x07020000,
+	.ic_ofs = 0x06020000,
 	.disp0_ofs = 0x06040000,
 	.disp1_ofs = 0x06048000,
 	.dc_tmpl_ofs = 0x07080000,
diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c
index 2326c75..4864f83 100644
--- a/drivers/gpu/ipu-v3/ipu-dc.c
+++ b/drivers/gpu/ipu-v3/ipu-dc.c
@@ -114,6 +114,7 @@
 	struct completion	comp;
 	int			dc_irq;
 	int			dp_irq;
+	int			use_count;
 };
 
 static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
@@ -232,7 +233,16 @@
 
 void ipu_dc_enable(struct ipu_soc *ipu)
 {
-	ipu_module_enable(ipu, IPU_CONF_DC_EN);
+	struct ipu_dc_priv *priv = ipu->dc_priv;
+
+	mutex_lock(&priv->mutex);
+
+	if (!priv->use_count)
+		ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+
+	priv->use_count++;
+
+	mutex_unlock(&priv->mutex);
 }
 EXPORT_SYMBOL_GPL(ipu_dc_enable);
 
@@ -267,7 +277,8 @@
 void ipu_dc_disable_channel(struct ipu_dc *dc)
 {
 	struct ipu_dc_priv *priv = dc->priv;
-	int irq, ret;
+	int irq;
+	unsigned long ret;
 	u32 val;
 
 	/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
@@ -282,7 +293,7 @@
 	enable_irq(irq);
 	ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
 	disable_irq(irq);
-	if (ret <= 0) {
+	if (ret == 0) {
 		dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
 
 		val = readl(dc->base + DC_WR_CH_CONF);
@@ -294,7 +305,18 @@
 
 void ipu_dc_disable(struct ipu_soc *ipu)
 {
-	ipu_module_disable(ipu, IPU_CONF_DC_EN);
+	struct ipu_dc_priv *priv = ipu->dc_priv;
+
+	mutex_lock(&priv->mutex);
+
+	priv->use_count--;
+	if (!priv->use_count)
+		ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
+
+	if (priv->use_count < 0)
+		priv->use_count = 0;
+
+	mutex_unlock(&priv->mutex);
 }
 EXPORT_SYMBOL_GPL(ipu_dc_disable);
 
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index c490ba4..b61d6be 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -207,10 +207,10 @@
 static void ipu_di_sync_config_interlaced(struct ipu_di *di,
 		struct ipu_di_signal_cfg *sig)
 {
-	u32 h_total = sig->width + sig->h_sync_width +
-		sig->h_start_width + sig->h_end_width;
-	u32 v_total = sig->height + sig->v_sync_width +
-		sig->v_start_width + sig->v_end_width;
+	u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+		sig->mode.hback_porch + sig->mode.hfront_porch;
+	u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+		sig->mode.vback_porch + sig->mode.vfront_porch;
 	u32 reg;
 	struct di_sync_config cfg[] = {
 		{
@@ -229,13 +229,13 @@
 		}, {
 			.run_count = v_total / 2 - 1,
 			.run_src = DI_SYNC_HSYNC,
-			.offset_count = sig->v_start_width,
+			.offset_count = sig->mode.vback_porch,
 			.offset_src = DI_SYNC_HSYNC,
 			.repeat_count = 2,
 			.cnt_clr_src = DI_SYNC_VSYNC,
 		}, {
 			.run_src = DI_SYNC_HSYNC,
-			.repeat_count = sig->height / 2,
+			.repeat_count = sig->mode.vactive / 2,
 			.cnt_clr_src = 4,
 		}, {
 			.run_count = v_total - 1,
@@ -249,9 +249,9 @@
 			.cnt_clr_src = DI_SYNC_VSYNC,
 		}, {
 			.run_src = DI_SYNC_CLK,
-			.offset_count = sig->h_start_width,
+			.offset_count = sig->mode.hback_porch,
 			.offset_src = DI_SYNC_CLK,
-			.repeat_count = sig->width,
+			.repeat_count = sig->mode.hactive,
 			.cnt_clr_src = 5,
 		}, {
 			.run_count = v_total - 1,
@@ -277,10 +277,10 @@
 static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
 		struct ipu_di_signal_cfg *sig, int div)
 {
-	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
-		sig->h_end_width;
-	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
-		sig->v_end_width;
+	u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+		sig->mode.hback_porch + sig->mode.hfront_porch;
+	u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+		sig->mode.vback_porch + sig->mode.vfront_porch;
 	struct di_sync_config cfg[] = {
 		{
 			/* 1: INT_HSYNC */
@@ -294,27 +294,29 @@
 			.offset_src = DI_SYNC_CLK,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_CLK,
-			.cnt_down = sig->h_sync_width * 2,
+			.cnt_down = sig->mode.hsync_len * 2,
 		} , {
 			/* PIN3: VSYNC */
 			.run_count = v_total - 1,
 			.run_src = DI_SYNC_INT_HSYNC,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
-			.cnt_down = sig->v_sync_width * 2,
+			.cnt_down = sig->mode.vsync_len * 2,
 		} , {
 			/* 4: Line Active */
 			.run_src = DI_SYNC_HSYNC,
-			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_count = sig->mode.vsync_len +
+					sig->mode.vback_porch,
 			.offset_src = DI_SYNC_HSYNC,
-			.repeat_count = sig->height,
+			.repeat_count = sig->mode.vactive,
 			.cnt_clr_src = DI_SYNC_VSYNC,
 		} , {
 			/* 5: Pixel Active, referenced by DC */
 			.run_src = DI_SYNC_CLK,
-			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_count = sig->mode.hsync_len +
+					sig->mode.hback_porch,
 			.offset_src = DI_SYNC_CLK,
-			.repeat_count = sig->width,
+			.repeat_count = sig->mode.hactive,
 			.cnt_clr_src = 5, /* Line Active */
 		} , {
 			/* unused */
@@ -339,9 +341,10 @@
 		} , {
 			/* 3: Line Active */
 			.run_src = DI_SYNC_INT_HSYNC,
-			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_count = sig->mode.vsync_len +
+					sig->mode.vback_porch,
 			.offset_src = DI_SYNC_INT_HSYNC,
-			.repeat_count = sig->height,
+			.repeat_count = sig->mode.vactive,
 			.cnt_clr_src = 3 /* VSYNC */,
 		} , {
 			/* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -351,13 +354,14 @@
 			.offset_src = DI_SYNC_CLK,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_CLK,
-			.cnt_down = sig->h_sync_width * 2,
+			.cnt_down = sig->mode.hsync_len * 2,
 		} , {
 			/* 5: Pixel Active signal to DC */
 			.run_src = DI_SYNC_CLK,
-			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_count = sig->mode.hsync_len +
+					sig->mode.hback_porch,
 			.offset_src = DI_SYNC_CLK,
-			.repeat_count = sig->width,
+			.repeat_count = sig->mode.hactive,
 			.cnt_clr_src = 4, /* Line Active */
 		} , {
 			/* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -367,7 +371,7 @@
 			.offset_src = DI_SYNC_INT_HSYNC,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
-			.cnt_down = sig->v_sync_width * 2,
+			.cnt_down = sig->mode.vsync_len * 2,
 		} , {
 			/* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
 			.run_count = h_total - 1,
@@ -376,7 +380,7 @@
 			.offset_src = DI_SYNC_CLK,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_CLK,
-			.cnt_down = sig->h_sync_width * 2,
+			.cnt_down = sig->mode.hsync_len * 2,
 		} , {
 			/* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
 			.run_count = v_total - 1,
@@ -385,7 +389,7 @@
 			.offset_src = DI_SYNC_INT_HSYNC,
 			.cnt_polarity_gen_en = 1,
 			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
-			.cnt_down = sig->v_sync_width * 2,
+			.cnt_down = sig->mode.vsync_len * 2,
 		} , {
 			/* unused */
 		},
@@ -433,10 +437,10 @@
 			unsigned long in_rate;
 			unsigned div;
 
-			clk_set_rate(clk, sig->pixelclock);
+			clk_set_rate(clk, sig->mode.pixelclock);
 
 			in_rate = clk_get_rate(clk);
-			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
 			if (div == 0)
 				div = 1;
 
@@ -454,10 +458,10 @@
 		unsigned div, error;
 
 		clkrate = clk_get_rate(di->clk_ipu);
-		div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+		div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
 		rate = clkrate / div;
 
-		error = rate / (sig->pixelclock / 1000);
+		error = rate / (sig->mode.pixelclock / 1000);
 
 		dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
 			rate, div, (signed)(error - 1000) / 10, error % 10);
@@ -473,10 +477,10 @@
 
 			clk = di->clk_di;
 
-			clk_set_rate(clk, sig->pixelclock);
+			clk_set_rate(clk, sig->mode.pixelclock);
 
 			in_rate = clk_get_rate(clk);
-			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
 			if (div == 0)
 				div = 1;
 
@@ -504,35 +508,58 @@
 	ipu_di_write(di, val, DI_GENERAL);
 
 	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
-		sig->pixelclock,
+		sig->mode.pixelclock,
 		clk_get_rate(di->clk_ipu),
 		clk_get_rate(di->clk_di),
 		clk == di->clk_di ? "DI" : "IPU",
 		clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
 }
 
+/*
+ * This function is called to adjust a video mode to IPU restrictions.
+ * It is meant to be called from drm crtc mode_fixup() methods.
+ */
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+{
+	u32 diff;
+
+	if (mode->vfront_porch >= 2)
+		return 0;
+
+	diff = 2 - mode->vfront_porch;
+
+	if (mode->vback_porch >= diff) {
+		mode->vfront_porch = 2;
+		mode->vback_porch -= diff;
+	} else if (mode->vsync_len > diff) {
+		mode->vfront_porch = 2;
+		mode->vsync_len = mode->vsync_len - diff;
+	} else {
+		dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+		return -EINVAL;
+	}
+
+	dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+
 int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 {
 	u32 reg;
 	u32 di_gen, vsync_cnt;
 	u32 div;
-	u32 h_total, v_total;
 
 	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
-		di->id, sig->width, sig->height);
+		di->id, sig->mode.hactive, sig->mode.vactive);
 
-	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+	if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0))
 		return -EINVAL;
 
-	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
-		sig->h_end_width;
-	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
-		sig->v_end_width;
-
 	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
 		clk_get_rate(di->clk_ipu),
 		clk_get_rate(di->clk_di),
-		sig->pixelclock);
+		sig->mode.pixelclock);
 
 	mutex_lock(&di_mutex);
 
@@ -551,7 +578,7 @@
 	di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
 	di_gen |= DI_GEN_DI_VSYNC_EXT;
 
-	if (sig->interlaced) {
+	if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
 		ipu_di_sync_config_interlaced(di, sig);
 
 		/* set y_sel = 1 */
@@ -561,9 +588,9 @@
 
 		vsync_cnt = 7;
 
-		if (sig->Hsync_pol)
+		if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
 			di_gen |= DI_GEN_POLARITY_3;
-		if (sig->Vsync_pol)
+		if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
 			di_gen |= DI_GEN_POLARITY_2;
 	} else {
 		ipu_di_sync_config_noninterlaced(di, sig, div);
@@ -577,7 +604,7 @@
 			if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
 				vsync_cnt = 6;
 
-		if (sig->Hsync_pol) {
+		if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) {
 			if (sig->hsync_pin == 2)
 				di_gen |= DI_GEN_POLARITY_2;
 			else if (sig->hsync_pin == 4)
@@ -585,7 +612,7 @@
 			else if (sig->hsync_pin == 7)
 				di_gen |= DI_GEN_POLARITY_7;
 		}
-		if (sig->Vsync_pol) {
+		if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) {
 			if (sig->vsync_pin == 3)
 				di_gen |= DI_GEN_POLARITY_3;
 			else if (sig->vsync_pin == 6)
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 433f72a..2978f5e 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -73,14 +73,14 @@
 	unsigned long flags;
 	int ret, t, err = 0;
 
-	spin_lock_irqsave(&newchannel->sc_lock, flags);
+	spin_lock_irqsave(&newchannel->lock, flags);
 	if (newchannel->state == CHANNEL_OPEN_STATE) {
 		newchannel->state = CHANNEL_OPENING_STATE;
 	} else {
-		spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+		spin_unlock_irqrestore(&newchannel->lock, flags);
 		return -EINVAL;
 	}
-	spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+	spin_unlock_irqrestore(&newchannel->lock, flags);
 
 	newchannel->onchannel_callback = onchannelcallback;
 	newchannel->channel_callback_context = context;
@@ -366,8 +366,8 @@
 	unsigned long flags;
 	int ret = 0;
 
-	next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
-	atomic_inc(&vmbus_connection.next_gpadl_handle);
+	next_gpadl_handle =
+		(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
 
 	ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
 	if (ret)
@@ -686,6 +686,50 @@
 /*
  * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
  * using a GPADL Direct packet type.
+ * The buffer includes the vmbus descriptor.
+ */
+int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
+			      struct vmbus_packet_mpb_array *desc,
+			      u32 desc_size,
+			      void *buffer, u32 bufferlen, u64 requestid)
+{
+	int ret;
+	u32 packetlen;
+	u32 packetlen_aligned;
+	struct kvec bufferlist[3];
+	u64 aligned_data = 0;
+	bool signal = false;
+
+	packetlen = desc_size + bufferlen;
+	packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+
+	/* Setup the descriptor */
+	desc->type = VM_PKT_DATA_USING_GPA_DIRECT;
+	desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+	desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */
+	desc->length8 = (u16)(packetlen_aligned >> 3);
+	desc->transactionid = requestid;
+	desc->rangecount = 1;
+
+	bufferlist[0].iov_base = desc;
+	bufferlist[0].iov_len = desc_size;
+	bufferlist[1].iov_base = buffer;
+	bufferlist[1].iov_len = bufferlen;
+	bufferlist[2].iov_base = &aligned_data;
+	bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+
+	ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+
+	if (ret == 0 && signal)
+		vmbus_setevent(channel);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
+
+/*
+ * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
+ * using a GPADL Direct packet type.
  */
 int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
 				struct hv_multipage_buffer *multi_pagebuffer,
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 2c59f03..3736f71 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -146,7 +146,7 @@
 		return NULL;
 
 	spin_lock_init(&channel->inbound_lock);
-	spin_lock_init(&channel->sc_lock);
+	spin_lock_init(&channel->lock);
 
 	INIT_LIST_HEAD(&channel->sc_list);
 	INIT_LIST_HEAD(&channel->percpu_list);
@@ -246,9 +246,9 @@
 		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
 	} else {
 		primary_channel = channel->primary_channel;
-		spin_lock_irqsave(&primary_channel->sc_lock, flags);
+		spin_lock_irqsave(&primary_channel->lock, flags);
 		list_del(&channel->sc_list);
-		spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
+		spin_unlock_irqrestore(&primary_channel->lock, flags);
 	}
 	free_channel(channel);
 }
@@ -279,9 +279,6 @@
 	int ret;
 	unsigned long flags;
 
-	/* The next possible work is rescind handling */
-	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
-
 	/* Make sure this is a new offer */
 	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
 
@@ -323,9 +320,9 @@
 			 * Process the sub-channel.
 			 */
 			newchannel->primary_channel = channel;
-			spin_lock_irqsave(&channel->sc_lock, flags);
+			spin_lock_irqsave(&channel->lock, flags);
 			list_add_tail(&newchannel->sc_list, &channel->sc_list);
-			spin_unlock_irqrestore(&channel->sc_lock, flags);
+			spin_unlock_irqrestore(&channel->lock, flags);
 
 			if (newchannel->target_cpu != get_cpu()) {
 				put_cpu();
@@ -341,11 +338,10 @@
 			if (channel->sc_creation_callback != NULL)
 				channel->sc_creation_callback(newchannel);
 
-			return;
+			goto done_init_rescind;
 		}
 
-		free_channel(newchannel);
-		return;
+		goto err_free_chan;
 	}
 
 	/*
@@ -364,6 +360,8 @@
 		&newchannel->offermsg.offer.if_type,
 		&newchannel->offermsg.offer.if_instance,
 		newchannel);
+	if (!newchannel->device_obj)
+		goto err_free_chan;
 
 	/*
 	 * Add the new device to the bus. This will kick off device-driver
@@ -379,9 +377,19 @@
 		list_del(&newchannel->listentry);
 		spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
 		kfree(newchannel->device_obj);
-
-		free_channel(newchannel);
+		goto err_free_chan;
 	}
+done_init_rescind:
+	spin_lock_irqsave(&newchannel->lock, flags);
+	/* The next possible work is rescind handling */
+	INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
+	/* Check if rescind offer was already received */
+	if (newchannel->rescind)
+		queue_work(newchannel->controlwq, &newchannel->work);
+	spin_unlock_irqrestore(&newchannel->lock, flags);
+	return;
+err_free_chan:
+	free_channel(newchannel);
 }
 
 enum {
@@ -516,6 +524,7 @@
 {
 	struct vmbus_channel_rescind_offer *rescind;
 	struct vmbus_channel *channel;
+	unsigned long flags;
 
 	rescind = (struct vmbus_channel_rescind_offer *)hdr;
 	channel = relid2channel(rescind->child_relid);
@@ -524,11 +533,20 @@
 		/* Just return here, no channel found */
 		return;
 
+	spin_lock_irqsave(&channel->lock, flags);
 	channel->rescind = true;
+	/*
+	 * channel->work.func != vmbus_process_rescind_offer means we are still
+	 * processing offer request and the rescind offer processing should be
+	 * postponed. It will be done at the very end of vmbus_process_offer()
+	 * as rescind flag is being checked there.
+	 */
+	if (channel->work.func == vmbus_process_rescind_offer)
+		/* work is initialized for vmbus_process_rescind_offer() from
+		 * vmbus_process_offer() where the channel got created */
+		queue_work(channel->controlwq, &channel->work);
 
-	/* work is initialized for vmbus_process_rescind_offer() from
-	 * vmbus_process_offer() where the channel got created */
-	queue_work(channel->controlwq, &channel->work);
+	spin_unlock_irqrestore(&channel->lock, flags);
 }
 
 /*
@@ -815,7 +833,7 @@
 struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
 {
 	struct list_head *cur, *tmp;
-	int cur_cpu = hv_context.vp_index[smp_processor_id()];
+	int cur_cpu;
 	struct vmbus_channel *cur_channel;
 	struct vmbus_channel *outgoing_channel = primary;
 	int cpu_distance, new_cpu_distance;
@@ -823,6 +841,8 @@
 	if (list_empty(&primary->sc_list))
 		return outgoing_channel;
 
+	cur_cpu = hv_context.vp_index[get_cpu()];
+	put_cpu();
 	list_for_each_safe(cur, tmp, &primary->sc_list) {
 		cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
 		if (cur_channel->state != CHANNEL_OPENED_STATE)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index e206619..a63a795 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -80,8 +80,10 @@
 	msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
 	msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
 	msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
-	if (version == VERSION_WIN8_1)
-		msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
+	if (version == VERSION_WIN8_1) {
+		msg->target_vcpu = hv_context.vp_index[get_cpu()];
+		put_cpu();
+	}
 
 	/*
 	 * Add to list before we send the request since we may
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 3e4235c..50e51a5 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -28,7 +28,9 @@
 #include <linux/hyperv.h>
 #include <linux/version.h>
 #include <linux/interrupt.h>
+#include <linux/clockchips.h>
 #include <asm/hyperv.h>
+#include <asm/mshyperv.h>
 #include "hyperv_vmbus.h"
 
 /* The one and only */
@@ -37,6 +39,10 @@
 	.hypercall_page		= NULL,
 };
 
+#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
+#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
+#define HV_MIN_DELTA_TICKS 1
+
 /*
  * query_hypervisor_info - Get version info of the windows hypervisor
  */
@@ -144,6 +150,8 @@
 	       sizeof(int) * NR_CPUS);
 	memset(hv_context.event_dpc, 0,
 	       sizeof(void *) * NR_CPUS);
+	memset(hv_context.clk_evt, 0,
+	       sizeof(void *) * NR_CPUS);
 
 	max_leaf = query_hypervisor_info();
 
@@ -258,10 +266,63 @@
 	return status;
 }
 
+static int hv_ce_set_next_event(unsigned long delta,
+				struct clock_event_device *evt)
+{
+	cycle_t current_tick;
+
+	WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+	rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+	current_tick += delta;
+	wrmsrl(HV_X64_MSR_STIMER0_COUNT, current_tick);
+	return 0;
+}
+
+static void hv_ce_setmode(enum clock_event_mode mode,
+			  struct clock_event_device *evt)
+{
+	union hv_timer_config timer_cfg;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		/* unsupported */
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+		timer_cfg.enable = 1;
+		timer_cfg.auto_enable = 1;
+		timer_cfg.sintx = VMBUS_MESSAGE_SINT;
+		wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+		break;
+
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0);
+		wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
+{
+	dev->name = "Hyper-V clockevent";
+	dev->features = CLOCK_EVT_FEAT_ONESHOT;
+	dev->cpumask = cpumask_of(cpu);
+	dev->rating = 1000;
+	dev->owner = THIS_MODULE;
+
+	dev->set_mode = hv_ce_setmode;
+	dev->set_next_event = hv_ce_set_next_event;
+}
+
 
 int hv_synic_alloc(void)
 {
 	size_t size = sizeof(struct tasklet_struct);
+	size_t ced_size = sizeof(struct clock_event_device);
 	int cpu;
 
 	for_each_online_cpu(cpu) {
@@ -272,6 +333,13 @@
 		}
 		tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
 
+		hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
+		if (hv_context.clk_evt[cpu] == NULL) {
+			pr_err("Unable to allocate clock event device\n");
+			goto err;
+		}
+		hv_init_clockevent_device(hv_context.clk_evt[cpu], cpu);
+
 		hv_context.synic_message_page[cpu] =
 			(void *)get_zeroed_page(GFP_ATOMIC);
 
@@ -305,6 +373,7 @@
 static void hv_synic_free_cpu(int cpu)
 {
 	kfree(hv_context.event_dpc[cpu]);
+	kfree(hv_context.clk_evt[cpu]);
 	if (hv_context.synic_event_page[cpu])
 		free_page((unsigned long)hv_context.synic_event_page[cpu]);
 	if (hv_context.synic_message_page[cpu])
@@ -388,6 +457,15 @@
 	hv_context.vp_index[cpu] = (u32)vp_index;
 
 	INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
+
+	/*
+	 * Register the per-cpu clockevent source.
+	 */
+	if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE)
+		clockevents_config_and_register(hv_context.clk_evt[cpu],
+						HV_TIMER_FREQUENCY,
+						HV_MIN_DELTA_TICKS,
+						HV_MAX_MAX_DELTA_TICKS);
 	return;
 }
 
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index b958ded..ff16938 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -533,6 +533,9 @@
 	 */
 	struct task_struct *thread;
 
+	struct mutex ha_region_mutex;
+	struct completion waiter_event;
+
 	/*
 	 * A list of hot-add regions.
 	 */
@@ -549,7 +552,59 @@
 static struct hv_dynmem_device dm_device;
 
 static void post_status(struct hv_dynmem_device *dm);
+
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void acquire_region_mutex(bool trylock)
+{
+	if (trylock) {
+		reinit_completion(&dm_device.waiter_event);
+		while (!mutex_trylock(&dm_device.ha_region_mutex))
+			wait_for_completion(&dm_device.waiter_event);
+	} else {
+		mutex_lock(&dm_device.ha_region_mutex);
+	}
+}
+
+static void release_region_mutex(bool trylock)
+{
+	if (trylock) {
+		mutex_unlock(&dm_device.ha_region_mutex);
+	} else {
+		mutex_unlock(&dm_device.ha_region_mutex);
+		complete(&dm_device.waiter_event);
+	}
+}
+
+static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
+			      void *v)
+{
+	switch (val) {
+	case MEM_GOING_ONLINE:
+		acquire_region_mutex(true);
+		break;
+
+	case MEM_ONLINE:
+	case MEM_CANCEL_ONLINE:
+		release_region_mutex(true);
+		if (dm_device.ha_waiting) {
+			dm_device.ha_waiting = false;
+			complete(&dm_device.ol_waitevent);
+		}
+		break;
+
+	case MEM_GOING_OFFLINE:
+	case MEM_OFFLINE:
+	case MEM_CANCEL_OFFLINE:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block hv_memory_nb = {
+	.notifier_call = hv_memory_notifier,
+	.priority = 0
+};
+
 
 static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
 {
@@ -591,6 +646,7 @@
 		init_completion(&dm_device.ol_waitevent);
 		dm_device.ha_waiting = true;
 
+		release_region_mutex(false);
 		nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
 		ret = add_memory(nid, PFN_PHYS((start_pfn)),
 				(HA_CHUNK << PAGE_SHIFT));
@@ -619,6 +675,7 @@
 		 * have not been "onlined" within the allowed time.
 		 */
 		wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
+		acquire_region_mutex(false);
 		post_status(&dm_device);
 	}
 
@@ -632,11 +689,6 @@
 	unsigned long cur_start_pgp;
 	unsigned long cur_end_pgp;
 
-	if (dm_device.ha_waiting) {
-		dm_device.ha_waiting = false;
-		complete(&dm_device.ol_waitevent);
-	}
-
 	list_for_each(cur, &dm_device.ha_region_list) {
 		has = list_entry(cur, struct hv_hotadd_state, list);
 		cur_start_pgp = (unsigned long)
@@ -834,6 +886,7 @@
 	resp.hdr.size = sizeof(struct dm_hot_add_response);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+	acquire_region_mutex(false);
 	pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
 	pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
 
@@ -865,6 +918,7 @@
 	if (do_hot_add)
 		resp.page_count = process_hot_add(pg_start, pfn_cnt,
 						rg_start, rg_sz);
+	release_region_mutex(false);
 #endif
 	/*
 	 * The result field of the response structure has the
@@ -928,9 +982,8 @@
 	 *     128        72    (1/2)
 	 *     512       168    (1/4)
 	 *    2048       360    (1/8)
-	 *    8192       552    (1/32)
-	 *   32768      1320
-	 *  131072      4392
+	 *    8192       768    (1/16)
+	 *   32768      1536	(1/32)
 	 */
 	if (totalram_pages < MB2PAGES(128))
 		min_pages = MB2PAGES(8) + (totalram_pages >> 1);
@@ -938,8 +991,10 @@
 		min_pages = MB2PAGES(40) + (totalram_pages >> 2);
 	else if (totalram_pages < MB2PAGES(2048))
 		min_pages = MB2PAGES(104) + (totalram_pages >> 3);
+	else if (totalram_pages < MB2PAGES(8192))
+		min_pages = MB2PAGES(256) + (totalram_pages >> 4);
 	else
-		min_pages = MB2PAGES(296) + (totalram_pages >> 5);
+		min_pages = MB2PAGES(512) + (totalram_pages >> 5);
 #undef MB2PAGES
 	return min_pages;
 }
@@ -1171,7 +1226,7 @@
 
 	for (i = 0; i < range_count; i++) {
 		free_balloon_pages(dm, &range_array[i]);
-		post_status(&dm_device);
+		complete(&dm_device.config_event);
 	}
 
 	if (req->more_pages == 1)
@@ -1195,19 +1250,16 @@
 static int dm_thread_func(void *dm_dev)
 {
 	struct hv_dynmem_device *dm = dm_dev;
-	int t;
 
 	while (!kthread_should_stop()) {
-		t = wait_for_completion_interruptible_timeout(
+		wait_for_completion_interruptible_timeout(
 						&dm_device.config_event, 1*HZ);
 		/*
 		 * The host expects us to post information on the memory
 		 * pressure every second.
 		 */
-
-		if (t == 0)
-			post_status(dm);
-
+		reinit_completion(&dm_device.config_event);
+		post_status(dm);
 	}
 
 	return 0;
@@ -1387,7 +1439,9 @@
 	dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7;
 	init_completion(&dm_device.host_event);
 	init_completion(&dm_device.config_event);
+	init_completion(&dm_device.waiter_event);
 	INIT_LIST_HEAD(&dm_device.ha_region_list);
+	mutex_init(&dm_device.ha_region_mutex);
 	INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
 	INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
 	dm_device.host_specified_ha_region = false;
@@ -1401,6 +1455,7 @@
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 	set_online_page_callback(&hv_online_page);
+	register_memory_notifier(&hv_memory_nb);
 #endif
 
 	hv_set_drvdata(dev, &dm_device);
@@ -1519,6 +1574,7 @@
 	kfree(send_buffer);
 #ifdef CONFIG_MEMORY_HOTPLUG
 	restore_online_page_callback(&hv_online_page);
+	unregister_memory_notifier(&hv_memory_nb);
 #endif
 	list_for_each_safe(cur, tmp, &dm->ha_region_list) {
 		has = list_entry(cur, struct hv_hotadd_state, list);
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index 23b2ce2..cd453e4 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -86,6 +86,18 @@
 	 * process the pending transaction.
 	 */
 	fcopy_respond_to_host(HV_E_FAIL);
+
+	/* In the case the user-space daemon crashes, hangs or is killed, we
+	 * need to down the semaphore, otherwise, after the daemon starts next
+	 * time, the obsolete data in fcopy_transaction.message or
+	 * fcopy_transaction.fcopy_msg will be used immediately.
+	 *
+	 * NOTE: fcopy_read() happens to get the semaphore (very rare)? We're
+	 * still OK, because we've reported the failure to the host.
+	 */
+	if (down_trylock(&fcopy_transaction.read_sema))
+		;
+
 }
 
 static int fcopy_handle_handshake(u32 version)
@@ -344,6 +356,14 @@
 	return 0;
 }
 
+/* XXX: there are still some tricky corner cases, e.g.,
+ * 1) In a SMP guest, when fcopy_release() runs between
+ * schedule_delayed_work() and fcopy_send_data(), there is
+ * still a chance an obsolete message will be queued.
+ *
+ * 2) When the fcopy daemon is running, if we unload the driver,
+ * we'll notice a kernel oops when we kill the daemon later.
+ */
 static int fcopy_release(struct inode *inode, struct file *f)
 {
 	/*
@@ -351,6 +371,13 @@
 	 */
 	in_hand_shake = true;
 	opened = false;
+
+	if (cancel_delayed_work_sync(&fcopy_work)) {
+		/* We haven't up()-ed the semaphore(very rare)? */
+		if (down_trylock(&fcopy_transaction.read_sema))
+			;
+		fcopy_respond_to_host(HV_E_FAIL);
+	}
 	return 0;
 }
 
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index c386d8d..44b1c94 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -178,6 +178,23 @@
 	};
 };
 
+/*
+ * Timer configuration register.
+ */
+union hv_timer_config {
+	u64 as_uint64;
+	struct {
+		u64 enable:1;
+		u64 periodic:1;
+		u64 lazy:1;
+		u64 auto_enable:1;
+		u64 reserved_z0:12;
+		u64 sintx:4;
+		u64 reserved_z1:44;
+	};
+};
+
+
 /* Define timer message payload structure. */
 struct hv_timer_message_payload {
 	u32 timer_index;
@@ -519,6 +536,10 @@
 	 * buffer to post messages to the host.
 	 */
 	void *post_msg_page[NR_CPUS];
+	/*
+	 * Support PV clockevent device.
+	 */
+	struct clock_event_device *clk_evt[NR_CPUS];
 };
 
 extern struct hv_context hv_context;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index bb3725b..f518b8d7 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -32,6 +32,7 @@
 #include <linux/completion.h>
 #include <linux/hyperv.h>
 #include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
 #include <asm/hyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/mshyperv.h>
@@ -578,6 +579,34 @@
 	kfree(ctx);
 }
 
+static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
+{
+	struct clock_event_device *dev = hv_context.clk_evt[cpu];
+
+	if (dev->event_handler)
+		dev->event_handler(dev);
+
+	msg->header.message_type = HVMSG_NONE;
+
+	/*
+	 * Make sure the write to MessageType (ie set to
+	 * HVMSG_NONE) happens before we read the
+	 * MessagePending and EOMing. Otherwise, the EOMing
+	 * will not deliver any more messages since there is
+	 * no empty slot
+	 */
+	mb();
+
+	if (msg->header.message_flags.msg_pending) {
+		/*
+		 * This will cause message queue rescan to
+		 * possibly deliver another msg from the
+		 * hypervisor
+		 */
+		wrmsrl(HV_X64_MSR_EOM, 0);
+	}
+}
+
 static void vmbus_on_msg_dpc(unsigned long data)
 {
 	int cpu = smp_processor_id();
@@ -667,8 +696,12 @@
 	msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 
 	/* Check if there are actual msgs to be processed */
-	if (msg->header.message_type != HVMSG_NONE)
-		tasklet_schedule(&msg_dpc);
+	if (msg->header.message_type != HVMSG_NONE) {
+		if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
+			hv_process_timer_expiration(msg, cpu);
+		else
+			tasklet_schedule(&msg_dpc);
+	}
 }
 
 /*
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 345395e..4132935 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -27,7 +27,6 @@
 	  usage.  That is, those where the data is pushed to the consumer.
 
 config IIO_KFIFO_BUF
-	select IIO_TRIGGER
 	tristate "Industrial I/O buffering based on kfifo"
 	help
 	  A simple fifo based on kfifo.  Note that this currently provides
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 9b9be87..7c9a9a9 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -43,6 +43,9 @@
 	  Say yes here to build support for the HID SENSOR
 	  accelerometers 3D.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called hid-sensor-accel-3d.
+
 config IIO_ST_ACCEL_3AXIS
 	tristate "STMicroelectronics accelerometers 3-Axis Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
@@ -80,6 +83,9 @@
 	  Say yes here to build support for the Kionix KXSD9 accelerometer.
 	  Currently this only supports the device via an SPI interface.
 
+	  To compile this driver as a module, choose M here: the module
+	  will be called kxsd9.
+
 config MMA8452
 	tristate "Freescale MMA8452Q Accelerometer Driver"
 	depends on I2C
@@ -105,4 +111,29 @@
 	  To compile this driver as a module, choose M here: the module will
 	  be called kxcjk-1013.
 
+config MMA9551_CORE
+	tristate
+
+config MMA9551
+	tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
+	depends on I2C
+	select MMA9551_CORE
+
+	help
+	  Say yes here to build support for the Freescale MMA9551L
+	  Intelligent Motion-Sensing Platform Driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mma9551.
+
+config MMA9553
+	tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver"
+	depends on I2C
+	select MMA9551_CORE
+	help
+	  Say yes here to build support for the Freescale MMA9553L
+	  Intelligent Pedometer Platform Driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mma9553.
 endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index a593996..99d89e4 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -10,6 +10,12 @@
 obj-$(CONFIG_KXSD9)	+= kxsd9.o
 obj-$(CONFIG_MMA8452)	+= mma8452.o
 
+obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
+obj-$(CONFIG_MMA9551)		+= mma9551.o
+obj-$(CONFIG_MMA9553)		+= mma9553.o
+
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
+
 obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
 st_accel-y := st_accel_core.o
 st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index d5d95317..df6a593 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -111,19 +111,12 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
 	switch (mask) {
 	case 0:
-		poll_value = hid_sensor_read_poll_value(
-					&accel_state->common_attributes);
-		if (poll_value < 0)
-			return -EINVAL;
-
 		hid_sensor_power_state(&accel_state->common_attributes, true);
-		msleep_interruptible(poll_value * 2);
 		report_id = accel_state->accel[chan->scan_index].report_id;
 		address = accel_3d_addresses[chan->scan_index];
 		if (report_id >= 0)
@@ -419,6 +412,7 @@
 	.id_table = hid_accel_3d_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_accel_3d_probe,
 	.remove		= hid_accel_3d_remove,
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index da2fe93..567de26 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -108,6 +108,7 @@
 	bool motion_trigger_on;
 	int64_t timestamp;
 	enum kx_chipset chipset;
+	bool is_smo8500_device;
 };
 
 enum kxcjk1013_axis {
@@ -377,6 +378,7 @@
 
 static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
 {
+#ifdef CONFIG_PM
 	int ret;
 
 	if (on)
@@ -388,8 +390,11 @@
 	if (ret < 0) {
 		dev_err(&data->client->dev,
 			"Failed: kxcjk1013_set_power_state for %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&data->client->dev);
 		return ret;
 	}
+#endif
 
 	return 0;
 }
@@ -858,6 +863,8 @@
 
 	ret =  kxcjk1013_setup_any_motion_interrupt(data, state);
 	if (ret < 0) {
+		kxcjk1013_set_power_state(data, false);
+		data->ev_enable_state = 0;
 		mutex_unlock(&data->mutex);
 		return ret;
 	}
@@ -1008,6 +1015,7 @@
 	else
 		ret = kxcjk1013_setup_new_data_interrupt(data, state);
 	if (ret < 0) {
+		kxcjk1013_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
 	}
@@ -1131,12 +1139,16 @@
 }
 
 static const char *kxcjk1013_match_acpi_device(struct device *dev,
-					       enum kx_chipset *chipset)
+					       enum kx_chipset *chipset,
+					       bool *is_smo8500_device)
 {
 	const struct acpi_device_id *id;
+
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id)
 		return NULL;
+	if (strcmp(id->id, "SMO8500") == 0)
+		*is_smo8500_device = true;
 	*chipset = (enum kx_chipset)id->driver_data;
 
 	return dev_name(dev);
@@ -1151,6 +1163,8 @@
 
 	if (!client)
 		return -EINVAL;
+	if (data->is_smo8500_device)
+		return -ENOTSUPP;
 
 	dev = &client->dev;
 
@@ -1200,7 +1214,8 @@
 		name = id->name;
 	} else if (ACPI_HANDLE(&client->dev)) {
 		name = kxcjk1013_match_acpi_device(&client->dev,
-						   &data->chipset);
+						   &data->chipset,
+						   &data->is_smo8500_device);
 	} else
 		return -ENODEV;
 
@@ -1228,21 +1243,25 @@
 						KXCJK1013_IRQ_NAME,
 						indio_dev);
 		if (ret)
-			return ret;
+			goto err_poweroff;
 
 		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
 							   "%s-dev%d",
 							   indio_dev->name,
 							   indio_dev->id);
-		if (!data->dready_trig)
-			return -ENOMEM;
+		if (!data->dready_trig) {
+			ret = -ENOMEM;
+			goto err_poweroff;
+		}
 
 		data->motion_trig = devm_iio_trigger_alloc(&client->dev,
 							  "%s-any-motion-dev%d",
 							  indio_dev->name,
 							  indio_dev->id);
-		if (!data->motion_trig)
-			return -ENOMEM;
+		if (!data->motion_trig) {
+			ret = -ENOMEM;
+			goto err_poweroff;
+		}
 
 		data->dready_trig->dev.parent = &client->dev;
 		data->dready_trig->ops = &kxcjk1013_trigger_ops;
@@ -1251,7 +1270,7 @@
 		iio_trigger_get(indio_dev->trig);
 		ret = iio_trigger_register(data->dready_trig);
 		if (ret)
-			return ret;
+			goto err_poweroff;
 
 		data->motion_trig->dev.parent = &client->dev;
 		data->motion_trig->ops = &kxcjk1013_trigger_ops;
@@ -1300,6 +1319,8 @@
 		iio_trigger_unregister(data->dready_trig);
 	if (data->motion_trig)
 		iio_trigger_unregister(data->motion_trig);
+err_poweroff:
+	kxcjk1013_set_mode(data, STANDBY);
 
 	return ret;
 }
@@ -1349,10 +1370,7 @@
 	int ret = 0;
 
 	mutex_lock(&data->mutex);
-	/* Check, if the suspend occured while active */
-	if (data->dready_trigger_on || data->motion_trigger_on ||
-							data->ev_enable_state)
-		ret = kxcjk1013_set_mode(data, OPERATION);
+	ret = kxcjk1013_set_mode(data, OPERATION);
 	mutex_unlock(&data->mutex);
 
 	return ret;
@@ -1364,8 +1382,14 @@
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 	struct kxcjk1013_data *data = iio_priv(indio_dev);
+	int ret;
 
-	return kxcjk1013_set_mode(data, STANDBY);
+	ret = kxcjk1013_set_mode(data, STANDBY);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+	return 0;
 }
 
 static int kxcjk1013_runtime_resume(struct device *dev)
@@ -1399,6 +1423,7 @@
 	{"KXCJ1013", KXCJK1013},
 	{"KXCJ1008", KXCJ91008},
 	{"KXTJ1009", KXTJ21009},
+	{"SMO8500",  KXCJ91008},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
@@ -1407,6 +1432,7 @@
 	{"kxcjk1013", KXCJK1013},
 	{"kxcj91008", KXCJ91008},
 	{"kxtj21009", KXTJ21009},
+	{"SMO8500",   KXCJ91008},
 	{}
 };
 
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 3c12d49..5b80657 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -111,7 +111,7 @@
 	{6, 250000}, {1, 560000}
 };
 
-/* 
+/*
  * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
  * The userspace interface uses m/s^2 and we declare micro units
  * So scale factor is given by:
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
new file mode 100644
index 0000000..46c3835
--- /dev/null
+++ b/drivers/iio/accel/mma9551.c
@@ -0,0 +1,637 @@
+/*
+ * Freescale MMA9551L Intelligent Motion-Sensing Platform driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+#define MMA9551_DRV_NAME		"mma9551"
+#define MMA9551_IRQ_NAME		"mma9551_event"
+#define MMA9551_GPIO_NAME		"mma9551_int"
+#define MMA9551_GPIO_COUNT		4
+
+/* Tilt application (inclination in IIO terms). */
+#define MMA9551_TILT_XZ_ANG_REG		0x00
+#define MMA9551_TILT_YZ_ANG_REG		0x01
+#define MMA9551_TILT_XY_ANG_REG		0x02
+#define MMA9551_TILT_ANGFLG		BIT(7)
+#define MMA9551_TILT_QUAD_REG		0x03
+#define MMA9551_TILT_XY_QUAD_SHIFT	0
+#define MMA9551_TILT_YZ_QUAD_SHIFT	2
+#define MMA9551_TILT_XZ_QUAD_SHIFT	4
+#define MMA9551_TILT_CFG_REG		0x01
+#define MMA9551_TILT_ANG_THRESH_MASK	GENMASK(3, 0)
+
+#define MMA9551_DEFAULT_SAMPLE_RATE	122	/* Hz */
+
+/* Tilt events are mapped to the first three GPIO pins. */
+enum mma9551_tilt_axis {
+	mma9551_x = 0,
+	mma9551_y,
+	mma9551_z,
+};
+
+struct mma9551_data {
+	struct i2c_client *client;
+	struct mutex mutex;
+	int event_enabled[3];
+	int irqs[MMA9551_GPIO_COUNT];
+};
+
+static int mma9551_read_incli_chan(struct i2c_client *client,
+				   const struct iio_chan_spec *chan,
+				   int *val)
+{
+	u8 quad_shift, angle, quadrant;
+	u16 reg_addr;
+	int ret;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg_addr = MMA9551_TILT_YZ_ANG_REG;
+		quad_shift = MMA9551_TILT_YZ_QUAD_SHIFT;
+		break;
+	case IIO_MOD_Y:
+		reg_addr = MMA9551_TILT_XZ_ANG_REG;
+		quad_shift = MMA9551_TILT_XZ_QUAD_SHIFT;
+		break;
+	case IIO_MOD_Z:
+		reg_addr = MMA9551_TILT_XY_ANG_REG;
+		quad_shift = MMA9551_TILT_XY_QUAD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mma9551_set_power_state(client, true);
+	if (ret < 0)
+		return ret;
+
+	ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
+				       reg_addr, &angle);
+	if (ret < 0)
+		goto out_poweroff;
+
+	ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
+				       MMA9551_TILT_QUAD_REG, &quadrant);
+	if (ret < 0)
+		goto out_poweroff;
+
+	angle &= ~MMA9551_TILT_ANGFLG;
+	quadrant = (quadrant >> quad_shift) & 0x03;
+
+	if (quadrant == 1 || quadrant == 3)
+		*val = 90 * (quadrant + 1) - angle;
+	else
+		*val = angle + 90 * quadrant;
+
+	ret = IIO_VAL_INT;
+
+out_poweroff:
+	mma9551_set_power_state(client, false);
+	return ret;
+}
+
+static int mma9551_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_INCLI:
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_incli_chan(data->client, chan, val);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_accel_chan(data->client,
+						      chan, val, val2);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			return mma9551_read_accel_scale(val, val2);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9551_read_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+
+	switch (chan->type) {
+	case IIO_INCLI:
+		/* IIO counts axes from 1, because IIO_NO_MOD is 0. */
+		return data->event_enabled[chan->channel2 - 1];
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9551_config_incli_event(struct iio_dev *indio_dev,
+				      enum iio_modifier axis,
+				      int state)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+	enum mma9551_tilt_axis mma_axis;
+	int ret;
+
+	/* IIO counts axes from 1, because IIO_NO_MOD is 0. */
+	mma_axis = axis - 1;
+
+	if (data->event_enabled[mma_axis] == state)
+		return 0;
+
+	if (state == 0) {
+		ret = mma9551_gpio_config(data->client,
+					  (enum mma9551_gpio_pin)mma_axis,
+					  MMA9551_APPID_NONE, 0, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = mma9551_set_power_state(data->client, false);
+		if (ret < 0)
+			return ret;
+	} else {
+		int bitnum;
+
+		/* Bit 7 of each angle register holds the angle flag. */
+		switch (axis) {
+		case IIO_MOD_X:
+			bitnum = 7 + 8 * MMA9551_TILT_YZ_ANG_REG;
+			break;
+		case IIO_MOD_Y:
+			bitnum = 7 + 8 * MMA9551_TILT_XZ_ANG_REG;
+			break;
+		case IIO_MOD_Z:
+			bitnum = 7 + 8 * MMA9551_TILT_XY_ANG_REG;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+
+		ret = mma9551_set_power_state(data->client, true);
+		if (ret < 0)
+			return ret;
+
+		ret = mma9551_gpio_config(data->client,
+					  (enum mma9551_gpio_pin)mma_axis,
+					  MMA9551_APPID_TILT, bitnum, 0);
+		if (ret < 0) {
+			mma9551_set_power_state(data->client, false);
+			return ret;
+		}
+	}
+
+	data->event_enabled[mma_axis] = state;
+
+	return ret;
+}
+
+static int mma9551_write_event_config(struct iio_dev *indio_dev,
+				      const struct iio_chan_spec *chan,
+				      enum iio_event_type type,
+				      enum iio_event_direction dir,
+				      int state)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (chan->type) {
+	case IIO_INCLI:
+		mutex_lock(&data->mutex);
+		ret = mma9551_config_incli_event(indio_dev,
+						 chan->channel2, state);
+		mutex_unlock(&data->mutex);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9551_write_event_value(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     enum iio_event_info info,
+				     int val, int val2)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (chan->type) {
+	case IIO_INCLI:
+		if (val2 != 0 || val < 1 || val > 10)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9551_update_config_bits(data->client,
+						 MMA9551_APPID_TILT,
+						 MMA9551_TILT_CFG_REG,
+						 MMA9551_TILT_ANG_THRESH_MASK,
+						 val);
+		mutex_unlock(&data->mutex);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9551_read_event_value(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info,
+				    int *val, int *val2)
+{
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+	u8 tmp;
+
+	switch (chan->type) {
+	case IIO_INCLI:
+		mutex_lock(&data->mutex);
+		ret = mma9551_read_config_byte(data->client,
+					       MMA9551_APPID_TILT,
+					       MMA9551_TILT_CFG_REG, &tmp);
+		mutex_unlock(&data->mutex);
+		if (ret < 0)
+			return ret;
+		*val = tmp & MMA9551_TILT_ANG_THRESH_MASK;
+		*val2 = 0;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_event_spec mma9551_incli_event = {
+	.type = IIO_EV_TYPE_ROC,
+	.dir = IIO_EV_DIR_RISING,
+	.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+};
+
+#define MMA9551_INCLI_CHANNEL(axis) {				\
+	.type = IIO_INCLI,					\
+	.modified = 1,						\
+	.channel2 = axis,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),	\
+	.event_spec = &mma9551_incli_event,			\
+	.num_event_specs = 1,					\
+}
+
+static const struct iio_chan_spec mma9551_channels[] = {
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
+
+	MMA9551_INCLI_CHANNEL(IIO_MOD_X),
+	MMA9551_INCLI_CHANNEL(IIO_MOD_Y),
+	MMA9551_INCLI_CHANNEL(IIO_MOD_Z),
+};
+
+static const struct iio_info mma9551_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = mma9551_read_raw,
+	.read_event_config = mma9551_read_event_config,
+	.write_event_config = mma9551_write_event_config,
+	.read_event_value = mma9551_read_event_value,
+	.write_event_value = mma9551_write_event_value,
+};
+
+static irqreturn_t mma9551_event_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int i, ret, mma_axis = -1;
+	u16 reg;
+	u8 val;
+
+	mutex_lock(&data->mutex);
+
+	for (i = 0; i < 3; i++)
+		if (irq == data->irqs[i]) {
+			mma_axis = i;
+			break;
+		}
+
+	if (mma_axis == -1) {
+		/* IRQ was triggered on 4th line, which we don't use. */
+		dev_warn(&data->client->dev,
+			 "irq triggered on unused line %d\n", data->irqs[3]);
+		goto out;
+	}
+
+	switch (mma_axis) {
+	case mma9551_x:
+		reg = MMA9551_TILT_YZ_ANG_REG;
+		break;
+	case mma9551_y:
+		reg = MMA9551_TILT_XZ_ANG_REG;
+		break;
+	case mma9551_z:
+		reg = MMA9551_TILT_XY_ANG_REG;
+		break;
+	}
+
+	/*
+	 * Read the angle even though we don't use it, otherwise we
+	 * won't get any further interrupts.
+	 */
+	ret = mma9551_read_status_byte(data->client, MMA9551_APPID_TILT,
+				       reg, &val);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error %d reading tilt register in IRQ\n", ret);
+		goto out;
+	}
+
+	iio_push_event(indio_dev,
+		       IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1),
+					  IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING),
+		       iio_get_time_ns());
+
+out:
+	mutex_unlock(&data->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int mma9551_init(struct mma9551_data *data)
+{
+	int ret;
+
+	ret = mma9551_read_version(data->client);
+	if (ret)
+		return ret;
+
+	return mma9551_set_device_state(data->client, true);
+}
+
+static int mma9551_gpio_probe(struct iio_dev *indio_dev)
+{
+	struct gpio_desc *gpio;
+	int i, ret;
+	struct mma9551_data *data = iio_priv(indio_dev);
+	struct device *dev = &data->client->dev;
+
+	for (i = 0; i < MMA9551_GPIO_COUNT; i++) {
+		gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i);
+		if (IS_ERR(gpio)) {
+			dev_err(dev, "acpi gpio get index failed\n");
+			return PTR_ERR(gpio);
+		}
+
+		ret = gpiod_direction_input(gpio);
+		if (ret)
+			return ret;
+
+		data->irqs[i] = gpiod_to_irq(gpio);
+		ret = devm_request_threaded_irq(dev, data->irqs[i],
+				NULL, mma9551_event_handler,
+				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				MMA9551_IRQ_NAME, indio_dev);
+		if (ret < 0) {
+			dev_err(dev, "request irq %d failed\n", data->irqs[i]);
+			return ret;
+		}
+
+		dev_dbg(dev, "gpio resource, no:%d irq:%d\n",
+			desc_to_gpio(gpio), data->irqs[i]);
+	}
+
+	return 0;
+}
+
+static const char *mma9551_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+
+	return dev_name(dev);
+}
+
+static int mma9551_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct mma9551_data *data;
+	struct iio_dev *indio_dev;
+	const char *name = NULL;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	if (id)
+		name = id->name;
+	else if (ACPI_HANDLE(&client->dev))
+		name = mma9551_match_acpi_device(&client->dev);
+
+	ret = mma9551_init(data);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&data->mutex);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = mma9551_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mma9551_channels);
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &mma9551_info;
+
+	ret = mma9551_gpio_probe(indio_dev);
+	if (ret < 0)
+		goto out_poweroff;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to register iio device\n");
+		goto out_poweroff;
+	}
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto out_iio_unregister;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 MMA9551_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	return 0;
+
+out_iio_unregister:
+	iio_device_unregister(indio_dev);
+out_poweroff:
+	mma9551_set_device_state(client, false);
+
+	return ret;
+}
+
+static int mma9551_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct mma9551_data *data = iio_priv(indio_dev);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	iio_device_unregister(indio_dev);
+	mutex_lock(&data->mutex);
+	mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma9551_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int mma9551_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = mma9551_set_device_state(data->client, true);
+	if (ret < 0)
+		return ret;
+
+	mma9551_sleep(MMA9551_DEFAULT_SAMPLE_RATE);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mma9551_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int mma9551_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9551_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, true);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops mma9551_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
+	SET_RUNTIME_PM_OPS(mma9551_runtime_suspend,
+			   mma9551_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id mma9551_acpi_match[] = {
+	{"MMA9551", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
+
+static const struct i2c_device_id mma9551_id[] = {
+	{"mma9551", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, mma9551_id);
+
+static struct i2c_driver mma9551_driver = {
+	.driver = {
+		   .name = MMA9551_DRV_NAME,
+		   .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
+		   .pm = &mma9551_pm_ops,
+		   },
+	.probe = mma9551_probe,
+	.remove = mma9551_remove,
+	.id_table = mma9551_id,
+};
+
+module_i2c_driver(mma9551_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver");
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
new file mode 100644
index 0000000..7f55a6d
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.c
@@ -0,0 +1,798 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+/* Command masks for mailbox write command */
+#define MMA9551_CMD_READ_VERSION_INFO	0x00
+#define MMA9551_CMD_READ_CONFIG		0x10
+#define MMA9551_CMD_WRITE_CONFIG	0x20
+#define MMA9551_CMD_READ_STATUS		0x30
+
+/* Mailbox read command */
+#define MMA9551_RESPONSE_COCO		BIT(7)
+
+/* Error-Status codes returned in mailbox read command */
+#define MMA9551_MCI_ERROR_NONE			0x00
+#define MMA9551_MCI_ERROR_PARAM			0x04
+#define MMA9551_MCI_INVALID_COUNT		0x19
+#define MMA9551_MCI_ERROR_COMMAND		0x1C
+#define MMA9551_MCI_ERROR_INVALID_LENGTH	0x21
+#define MMA9551_MCI_ERROR_FIFO_BUSY		0x22
+#define MMA9551_MCI_ERROR_FIFO_ALLOCATED	0x23
+#define MMA9551_MCI_ERROR_FIFO_OVERSIZE		0x24
+
+/* GPIO Application */
+#define MMA9551_GPIO_POL_MSB		0x08
+#define MMA9551_GPIO_POL_LSB		0x09
+
+/* Sleep/Wake application */
+#define MMA9551_SLEEP_CFG		0x06
+#define MMA9551_SLEEP_CFG_SNCEN		BIT(0)
+#define MMA9551_SLEEP_CFG_FLEEN		BIT(1)
+#define MMA9551_SLEEP_CFG_SCHEN		BIT(2)
+
+/* AFE application */
+#define MMA9551_AFE_X_ACCEL_REG		0x00
+#define MMA9551_AFE_Y_ACCEL_REG		0x02
+#define MMA9551_AFE_Z_ACCEL_REG		0x04
+
+/* Reset/Suspend/Clear application */
+#define MMA9551_RSC_RESET		0x00
+#define MMA9551_RSC_OFFSET(mask)	(3 - (ffs(mask) - 1) / 8)
+#define MMA9551_RSC_VAL(mask)		(mask >> (((ffs(mask) - 1) / 8) * 8))
+
+/*
+ * A response is composed of:
+ * - control registers: MB0-3
+ * - data registers: MB4-31
+ *
+ * A request is composed of:
+ * - mbox to write to (always 0)
+ * - control registers: MB1-4
+ * - data registers: MB5-31
+ */
+#define MMA9551_MAILBOX_CTRL_REGS	4
+#define MMA9551_MAX_MAILBOX_DATA_REGS	28
+#define MMA9551_MAILBOX_REGS		32
+
+#define MMA9551_I2C_READ_RETRIES	5
+#define MMA9551_I2C_READ_DELAY	50	/* us */
+
+struct mma9551_mbox_request {
+	u8 start_mbox;		/* Always 0. */
+	u8 app_id;
+	/*
+	 * See Section 5.3.1 of the MMA955xL Software Reference Manual.
+	 *
+	 * Bit 7: reserved, always 0
+	 * Bits 6-4: command
+	 * Bits 3-0: upper bits of register offset
+	 */
+	u8 cmd_off;
+	u8 lower_off;
+	u8 nbytes;
+	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
+} __packed;
+
+struct mma9551_mbox_response {
+	u8 app_id;
+	/*
+	 * See Section 5.3.3 of the MMA955xL Software Reference Manual.
+	 *
+	 * Bit 7: COCO
+	 * Bits 6-0: Error code.
+	 */
+	u8 coco_err;
+	u8 nbytes;
+	u8 req_bytes;
+	u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+} __packed;
+
+struct mma9551_version_info {
+	__be32 device_id;
+	u8 rom_version[2];
+	u8 fw_version[2];
+	u8 hw_version[2];
+	u8 fw_build[2];
+};
+
+static int mma9551_transfer(struct i2c_client *client,
+			    u8 app_id, u8 command, u16 offset,
+			    u8 *inbytes, int num_inbytes,
+			    u8 *outbytes, int num_outbytes)
+{
+	struct mma9551_mbox_request req;
+	struct mma9551_mbox_response rsp;
+	struct i2c_msg in, out;
+	u8 req_len, err_code;
+	int ret, retries;
+
+	if (offset >= 1 << 12) {
+		dev_err(&client->dev, "register offset too large\n");
+		return -EINVAL;
+	}
+
+	req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
+	req.start_mbox = 0;
+	req.app_id = app_id;
+	req.cmd_off = command | (offset >> 8);
+	req.lower_off = offset;
+
+	if (command == MMA9551_CMD_WRITE_CONFIG)
+		req.nbytes = num_inbytes;
+	else
+		req.nbytes = num_outbytes;
+	if (num_inbytes)
+		memcpy(req.buf, inbytes, num_inbytes);
+
+	out.addr = client->addr;
+	out.flags = 0;
+	out.len = req_len;
+	out.buf = (u8 *)&req;
+
+	ret = i2c_transfer(client->adapter, &out, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c write failed\n");
+		return ret;
+	}
+
+	retries = MMA9551_I2C_READ_RETRIES;
+	do {
+		udelay(MMA9551_I2C_READ_DELAY);
+
+		in.addr = client->addr;
+		in.flags = I2C_M_RD;
+		in.len = sizeof(rsp);
+		in.buf = (u8 *)&rsp;
+
+		ret = i2c_transfer(client->adapter, &in, 1);
+		if (ret < 0) {
+			dev_err(&client->dev, "i2c read failed\n");
+			return ret;
+		}
+
+		if (rsp.coco_err & MMA9551_RESPONSE_COCO)
+			break;
+	} while (--retries > 0);
+
+	if (retries == 0) {
+		dev_err(&client->dev,
+			"timed out while waiting for command response\n");
+		return -ETIMEDOUT;
+	}
+
+	if (rsp.app_id != app_id) {
+		dev_err(&client->dev,
+			"app_id mismatch in response got %02x expected %02x\n",
+			rsp.app_id, app_id);
+		return -EINVAL;
+	}
+
+	err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
+	if (err_code != MMA9551_MCI_ERROR_NONE) {
+		dev_err(&client->dev, "read returned error %x\n", err_code);
+		return -EINVAL;
+	}
+
+	if (rsp.nbytes != rsp.req_bytes) {
+		dev_err(&client->dev,
+			"output length mismatch got %d expected %d\n",
+			rsp.nbytes, rsp.req_bytes);
+		return -EINVAL;
+	}
+
+	if (num_outbytes)
+		memcpy(outbytes, rsp.buf, num_outbytes);
+
+	return 0;
+}
+
+/**
+ * mma9551_read_config_byte() - read 1 configuration byte
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Pointer to store value read
+ *
+ * Read one configuration byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed
+ * by one or more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+				reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_config_byte);
+
+/**
+ * mma9551_write_config_byte() - write 1 configuration byte
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Value to write
+ *
+ * Write one configuration byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+				&val, 1, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_byte);
+
+/**
+ * mma9551_read_status_byte() - read 1 status byte
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Pointer to store value read
+ *
+ * Read one status byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val)
+{
+	return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+				reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_status_byte);
+
+/**
+ * mma9551_read_config_word() - read 1 config word
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Pointer to store value read
+ *
+ * Read one configuration word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+			    u16 reg, u16 *val)
+{
+	int ret;
+	__be16 v;
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+			       reg, NULL, 0, (u8 *)&v, 2);
+	*val = be16_to_cpu(v);
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_config_word);
+
+/**
+ * mma9551_write_config_word() - write 1 config word
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Value to write
+ *
+ * Write one configuration word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 val)
+{
+	__be16 v = cpu_to_be16(val);
+
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+				(u8 *) &v, 2, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_word);
+
+/**
+ * mma9551_read_status_word() - read 1 status word
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @val:	Pointer to store value read
+ *
+ * Read one status word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 *val)
+{
+	int ret;
+	__be16 v;
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+			       reg, NULL, 0, (u8 *)&v, 2);
+	*val = be16_to_cpu(v);
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_status_word);
+
+/**
+ * mma9551_read_config_words() - read multiple config words
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @len:	Length of array to read in bytes
+ * @val:	Array of words to read
+ *
+ * Read multiple configuration registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 len, u16 *buf)
+{
+	int ret, i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+			       reg, NULL, 0, (u8 *) be_buf, len);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < len_words; i++)
+		buf[i] = be16_to_cpu(be_buf[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_config_words);
+
+/**
+ * mma9551_read_status_words() - read multiple status words
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @len:	Length of array to read in bytes
+ * @val:	Array of words to read
+ *
+ * Read multiple status registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 len, u16 *buf)
+{
+	int ret, i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+			       reg, NULL, 0, (u8 *) be_buf, len);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < len_words; i++)
+		buf[i] = be16_to_cpu(be_buf[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_status_words);
+
+/**
+ * mma9551_write_config_words() - write multiple config words
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @len:	Length of array to write in bytes
+ * @val:	Array of words to write
+ *
+ * Write multiple configuration registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 len, u16 *buf)
+{
+	int i;
+	int len_words = len / sizeof(u16);
+	__be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+	for (i = 0; i < len_words; i++)
+		be_buf[i] = cpu_to_be16(buf[i]);
+
+	return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
+				reg, (u8 *) be_buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_words);
+
+/**
+ * mma9551_update_config_bits() - update bits in register
+ * @client:	I2C client
+ * @app_id:	Application ID
+ * @reg:	Application register
+ * @mask:	Mask for the bits to update
+ * @val:	Value of the bits to update
+ *
+ * Update bits in the given register using a bit mask.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 mask, u8 val)
+{
+	int ret;
+	u8 tmp, orig;
+
+	ret = mma9551_read_config_byte(client, app_id, reg, &orig);
+	if (ret < 0)
+		return ret;
+
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+
+	if (tmp == orig)
+		return 0;
+
+	return mma9551_write_config_byte(client, app_id, reg, tmp);
+}
+EXPORT_SYMBOL(mma9551_update_config_bits);
+
+/**
+ * mma9551_gpio_config() - configure gpio
+ * @client:	I2C client
+ * @pin:	GPIO pin to configure
+ * @app_id:	Application ID
+ * @bitnum:	Bit number of status register being assigned to the GPIO pin.
+ * @polarity:	The polarity parameter is described in section 6.2.2, page 66,
+ *		of the Software Reference Manual.  Basically, polarity=0 means
+ *		the interrupt line has the same value as the selected bit,
+ *		while polarity=1 means the line is inverted.
+ *
+ * Assign a bit from an application’s status register to a specific GPIO pin.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+			u8 app_id, u8 bitnum, int polarity)
+{
+	u8 reg, pol_mask, pol_val;
+	int ret;
+
+	if (pin > mma9551_gpio_max) {
+		dev_err(&client->dev, "bad GPIO pin\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
+	 * 0x03, and so on.
+	 */
+	reg = pin * 2;
+
+	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+					reg, app_id);
+	if (ret < 0) {
+		dev_err(&client->dev, "error setting GPIO app_id\n");
+		return ret;
+	}
+
+	ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+					reg + 1, bitnum);
+	if (ret < 0) {
+		dev_err(&client->dev, "error setting GPIO bit number\n");
+		return ret;
+	}
+
+	switch (pin) {
+	case mma9551_gpio6:
+		reg = MMA9551_GPIO_POL_LSB;
+		pol_mask = 1 << 6;
+		break;
+	case mma9551_gpio7:
+		reg = MMA9551_GPIO_POL_LSB;
+		pol_mask = 1 << 7;
+		break;
+	case mma9551_gpio8:
+		reg = MMA9551_GPIO_POL_MSB;
+		pol_mask = 1 << 0;
+		break;
+	case mma9551_gpio9:
+		reg = MMA9551_GPIO_POL_MSB;
+		pol_mask = 1 << 1;
+		break;
+	}
+	pol_val = polarity ? pol_mask : 0;
+
+	ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
+					 pol_mask, pol_val);
+	if (ret < 0)
+		dev_err(&client->dev, "error setting GPIO polarity\n");
+
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_gpio_config);
+
+/**
+ * mma9551_read_version() - read device version information
+ * @client:	I2C client
+ *
+ * Read version information and print device id and firmware version.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_version(struct i2c_client *client)
+{
+	struct mma9551_version_info info;
+	int ret;
+
+	ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
+			       NULL, 0, (u8 *)&info, sizeof(info));
+	if (ret < 0)
+		return ret;
+
+	dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n",
+		 be32_to_cpu(info.device_id), info.fw_version[0],
+		 info.fw_version[1]);
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_read_version);
+
+/**
+ * mma9551_set_device_state() - sets HW power mode
+ * @client:	I2C client
+ * @enable:	Use true to power on device, false to cause the device
+ *		to enter sleep.
+ *
+ * Set power on/off for device using the Sleep/Wake Application.
+ * When enable is true, power on chip and enable doze mode.
+ * When enable is false, enter sleep mode (device remains in the
+ * lowest-power mode).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_set_device_state(struct i2c_client *client, bool enable)
+{
+	return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
+					  MMA9551_SLEEP_CFG,
+					  MMA9551_SLEEP_CFG_SNCEN |
+					  MMA9551_SLEEP_CFG_FLEEN |
+					  MMA9551_SLEEP_CFG_SCHEN,
+					  enable ? MMA9551_SLEEP_CFG_SCHEN |
+					  MMA9551_SLEEP_CFG_FLEEN :
+					  MMA9551_SLEEP_CFG_SNCEN);
+}
+EXPORT_SYMBOL(mma9551_set_device_state);
+
+/**
+ * mma9551_set_power_state() - sets runtime PM state
+ * @client:	I2C client
+ * @on:		Use true to power on device, false to power off
+ *
+ * Resume or suspend the device using Runtime PM.
+ * The device will suspend after the autosuspend delay.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_set_power_state(struct i2c_client *client, bool on)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (on)
+		ret = pm_runtime_get_sync(&client->dev);
+	else {
+		pm_runtime_mark_last_busy(&client->dev);
+		ret = pm_runtime_put_autosuspend(&client->dev);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"failed to change power state to %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&client->dev);
+
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+EXPORT_SYMBOL(mma9551_set_power_state);
+
+/**
+ * mma9551_sleep() - sleep
+ * @freq:	Application frequency
+ *
+ * Firmware applications run at a certain frequency on the
+ * device. Sleep for one application cycle to make sure the
+ * application had time to run once and initialize set values.
+ */
+void mma9551_sleep(int freq)
+{
+	int sleep_val = 1000 / freq;
+
+	if (sleep_val < 20)
+		usleep_range(sleep_val * 1000, 20000);
+	else
+		msleep_interruptible(sleep_val);
+}
+EXPORT_SYMBOL(mma9551_sleep);
+
+/**
+ * mma9551_read_accel_chan() - read accelerometer channel
+ * @client:	I2C client
+ * @chan:	IIO channel
+ * @val:	Pointer to the accelerometer value read
+ * @val2:	Unused
+ *
+ * Read accelerometer value for the specified channel.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: IIO_VAL_INT on success, negative value on failure.
+ */
+int mma9551_read_accel_chan(struct i2c_client *client,
+			    const struct iio_chan_spec *chan,
+			    int *val, int *val2)
+{
+	u16 reg_addr;
+	s16 raw_accel;
+	int ret;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg_addr = MMA9551_AFE_X_ACCEL_REG;
+		break;
+	case IIO_MOD_Y:
+		reg_addr = MMA9551_AFE_Y_ACCEL_REG;
+		break;
+	case IIO_MOD_Z:
+		reg_addr = MMA9551_AFE_Z_ACCEL_REG;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mma9551_set_power_state(client, true);
+	if (ret < 0)
+		return ret;
+
+	ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
+				       reg_addr, &raw_accel);
+	if (ret < 0)
+		goto out_poweroff;
+
+	*val = raw_accel;
+
+	ret = IIO_VAL_INT;
+
+out_poweroff:
+	mma9551_set_power_state(client, false);
+	return ret;
+}
+EXPORT_SYMBOL(mma9551_read_accel_chan);
+
+/**
+ * mma9551_read_accel_scale() - read accelerometer scale
+ * @val:	Pointer to the accelerometer scale (int value)
+ * @val2:	Pointer to the accelerometer scale (micro value)
+ *
+ * Read accelerometer scale.
+ *
+ * Returns: IIO_VAL_INT_PLUS_MICRO.
+ */
+int mma9551_read_accel_scale(int *val, int *val2)
+{
+	*val = 0;
+	*val2 = 2440;
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(mma9551_read_accel_scale);
+
+/**
+ * mma9551_app_reset() - reset application
+ * @client:	I2C client
+ * @app_mask:	Application to reset
+ *
+ * Reset the given application (using the Reset/Suspend/Clear
+ * Control Application)
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
+{
+	return mma9551_write_config_byte(client, MMA9551_APPID_RCS,
+					 MMA9551_RSC_RESET +
+					 MMA9551_RSC_OFFSET(app_mask),
+					 MMA9551_RSC_VAL(app_mask));
+}
+EXPORT_SYMBOL(mma9551_app_reset);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA955xL sensors core");
diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
new file mode 100644
index 0000000..edaa56b
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.h
@@ -0,0 +1,81 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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 _MMA9551_CORE_H_
+#define _MMA9551_CORE_H_
+
+/* Applications IDs */
+#define MMA9551_APPID_VERSION		0x00
+#define MMA9551_APPID_GPIO		0x03
+#define MMA9551_APPID_AFE		0x06
+#define MMA9551_APPID_TILT		0x0B
+#define MMA9551_APPID_SLEEP_WAKE	0x12
+#define MMA9551_APPID_PEDOMETER	        0x15
+#define MMA9551_APPID_RCS		0x17
+#define MMA9551_APPID_NONE		0xff
+
+/* Reset/Suspend/Clear application app masks */
+#define MMA9551_RSC_PED			BIT(21)
+
+#define MMA9551_AUTO_SUSPEND_DELAY_MS	2000
+
+enum mma9551_gpio_pin {
+	mma9551_gpio6 = 0,
+	mma9551_gpio7,
+	mma9551_gpio8,
+	mma9551_gpio9,
+	mma9551_gpio_max = mma9551_gpio9,
+};
+
+#define MMA9551_ACCEL_CHANNEL(axis) {				\
+	.type = IIO_ACCEL,					\
+	.modified = 1,						\
+	.channel2 = axis,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val);
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 val);
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 *val);
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+			    u16 reg, u16 *val);
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 val);
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+			     u16 reg, u16 *val);
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+			     u16 reg, u8 len, u16 *buf);
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+			      u16 reg, u8 len, u16 *buf);
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 len, u16 *buf);
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+			       u16 reg, u8 mask, u8 val);
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+			u8 app_id, u8 bitnum, int polarity);
+int mma9551_read_version(struct i2c_client *client);
+int mma9551_set_device_state(struct i2c_client *client, bool enable);
+int mma9551_set_power_state(struct i2c_client *client, bool on);
+void mma9551_sleep(int freq);
+int mma9551_read_accel_chan(struct i2c_client *client,
+			    const struct iio_chan_spec *chan,
+			    int *val, int *val2);
+int mma9551_read_accel_scale(int *val, int *val2);
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask);
+
+#endif /* _MMA9551_CORE_H_ */
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
new file mode 100644
index 0000000..d23ebf1
--- /dev/null
+++ b/drivers/iio/accel/mma9553.c
@@ -0,0 +1,1334 @@
+/*
+ * Freescale MMA9553L Intelligent Pedometer driver
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+#define MMA9553_DRV_NAME			"mma9553"
+#define MMA9553_IRQ_NAME			"mma9553_event"
+#define MMA9553_GPIO_NAME			"mma9553_int"
+
+/* Pedometer configuration registers (R/W) */
+#define MMA9553_REG_CONF_SLEEPMIN		0x00
+#define MMA9553_REG_CONF_SLEEPMAX		0x02
+#define MMA9553_REG_CONF_SLEEPTHD		0x04
+#define MMA9553_MASK_CONF_WORD			GENMASK(15, 0)
+
+#define MMA9553_REG_CONF_CONF_STEPLEN		0x06
+#define MMA9553_MASK_CONF_CONFIG		BIT(15)
+#define MMA9553_MASK_CONF_ACT_DBCNTM		BIT(14)
+#define MMA9553_MASK_CONF_SLP_DBCNTM		BIT(13)
+#define MMA9553_MASK_CONF_STEPLEN		GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_HEIGHT_WEIGHT		0x08
+#define MMA9553_MASK_CONF_HEIGHT		GENMASK(15, 8)
+#define MMA9553_MASK_CONF_WEIGHT		GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_FILTER			0x0A
+#define MMA9553_MASK_CONF_FILTSTEP		GENMASK(15, 8)
+#define MMA9553_MASK_CONF_MALE			BIT(7)
+#define MMA9553_MASK_CONF_FILTTIME		GENMASK(6, 0)
+
+#define MMA9553_REG_CONF_SPEED_STEP		0x0C
+#define MMA9553_MASK_CONF_SPDPRD		GENMASK(15, 8)
+#define MMA9553_MASK_CONF_STEPCOALESCE		GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_ACTTHD			0x0E
+
+/* Pedometer status registers (R-only) */
+#define MMA9553_REG_STATUS			0x00
+#define MMA9553_MASK_STATUS_MRGFL		BIT(15)
+#define MMA9553_MASK_STATUS_SUSPCHG		BIT(14)
+#define MMA9553_MASK_STATUS_STEPCHG		BIT(13)
+#define MMA9553_MASK_STATUS_ACTCHG		BIT(12)
+#define MMA9553_MASK_STATUS_SUSP		BIT(11)
+#define MMA9553_MASK_STATUS_ACTIVITY		(BIT(10) | BIT(9) | BIT(8))
+#define MMA9553_MASK_STATUS_VERSION		0x00FF
+
+#define MMA9553_REG_STEPCNT			0x02
+#define MMA9553_REG_DISTANCE			0x04
+#define MMA9553_REG_SPEED			0x06
+#define MMA9553_REG_CALORIES			0x08
+#define MMA9553_REG_SLEEPCNT			0x0A
+
+/* Pedometer events are always mapped to this pin. */
+#define MMA9553_DEFAULT_GPIO_PIN	mma9551_gpio6
+#define MMA9553_DEFAULT_GPIO_POLARITY	0
+
+/* Bitnum used for gpio configuration = bit number in high status byte */
+#define STATUS_TO_BITNUM(bit)		(ffs(bit) - 9)
+
+#define MMA9553_DEFAULT_SAMPLE_RATE	30	/* Hz */
+
+/*
+ * The internal activity level must be stable for ACTTHD samples before
+ * ACTIVITY is updated.The ACTIVITY variable contains the current activity
+ * level and is updated every time a step is detected or once a second
+ * if there are no steps.
+ */
+#define MMA9553_ACTIVITY_THD_TO_SEC(thd) ((thd) / MMA9553_DEFAULT_SAMPLE_RATE)
+#define MMA9553_ACTIVITY_SEC_TO_THD(sec) ((sec) * MMA9553_DEFAULT_SAMPLE_RATE)
+
+/*
+ * Autonomously suspend pedometer if acceleration vector magnitude
+ * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
+ */
+#define MMA9553_DEFAULT_SLEEPMIN	3688	/* 0,9 g */
+#define MMA9553_DEFAULT_SLEEPMAX	4508	/* 1,1 g */
+#define MMA9553_DEFAULT_SLEEPTHD	(MMA9553_DEFAULT_SAMPLE_RATE * 30)
+
+#define MMA9553_CONFIG_RETRIES		2
+
+/* Status register - activity field  */
+enum activity_level {
+	ACTIVITY_UNKNOWN,
+	ACTIVITY_REST,
+	ACTIVITY_WALKING,
+	ACTIVITY_JOGGING,
+	ACTIVITY_RUNNING,
+};
+
+static struct mma9553_event_info {
+	enum iio_chan_type type;
+	enum iio_modifier mod;
+	enum iio_event_direction dir;
+} mma9553_events_info[] = {
+	{
+		.type = IIO_STEPS,
+		.mod = IIO_NO_MOD,
+		.dir = IIO_EV_DIR_NONE,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_STILL,
+		.dir = IIO_EV_DIR_RISING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_STILL,
+		.dir = IIO_EV_DIR_FALLING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_WALKING,
+		.dir = IIO_EV_DIR_RISING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_WALKING,
+		.dir = IIO_EV_DIR_FALLING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_JOGGING,
+		.dir = IIO_EV_DIR_RISING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_JOGGING,
+		.dir = IIO_EV_DIR_FALLING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_RUNNING,
+		.dir = IIO_EV_DIR_RISING,
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.mod = IIO_MOD_RUNNING,
+		.dir = IIO_EV_DIR_FALLING,
+	},
+};
+
+#define MMA9553_EVENTS_INFO_SIZE ARRAY_SIZE(mma9553_events_info)
+
+struct mma9553_event {
+	struct mma9553_event_info *info;
+	bool enabled;
+};
+
+struct mma9553_conf_regs {
+	u16 sleepmin;
+	u16 sleepmax;
+	u16 sleepthd;
+	u16 config;
+	u16 height_weight;
+	u16 filter;
+	u16 speed_step;
+	u16 actthd;
+} __packed;
+
+struct mma9553_data {
+	struct i2c_client *client;
+	struct mutex mutex;
+	struct mma9553_conf_regs conf;
+	struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE];
+	int num_events;
+	u8 gpio_bitnum;
+	/*
+	 * This is used for all features that depend on step count:
+	 * step count, distance, speed, calories.
+	 */
+	bool stepcnt_enabled;
+	u16 stepcnt;
+	u8 activity;
+	s64 timestamp;
+};
+
+static u8 mma9553_get_bits(u16 val, u16 mask)
+{
+	return (val & mask) >> (ffs(mask) - 1);
+}
+
+static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask)
+{
+	return (current_val & ~mask) | (val << (ffs(mask) - 1));
+}
+
+static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity)
+{
+	switch (activity) {
+	case ACTIVITY_RUNNING:
+		return IIO_MOD_RUNNING;
+	case ACTIVITY_JOGGING:
+		return IIO_MOD_JOGGING;
+	case ACTIVITY_WALKING:
+		return IIO_MOD_WALKING;
+	case ACTIVITY_REST:
+		return IIO_MOD_STILL;
+	case ACTIVITY_UNKNOWN:
+	default:
+		return IIO_NO_MOD;
+	}
+}
+
+static void mma9553_init_events(struct mma9553_data *data)
+{
+	int i;
+
+	data->num_events = MMA9553_EVENTS_INFO_SIZE;
+	for (i = 0; i < data->num_events; i++) {
+		data->events[i].info = &mma9553_events_info[i];
+		data->events[i].enabled = false;
+	}
+}
+
+static struct mma9553_event *mma9553_get_event(struct mma9553_data *data,
+					       enum iio_chan_type type,
+					       enum iio_modifier mod,
+					       enum iio_event_direction dir)
+{
+	int i;
+
+	for (i = 0; i < data->num_events; i++)
+		if (data->events[i].info->type == type &&
+		    data->events[i].info->mod == mod &&
+		    data->events[i].info->dir == dir)
+			return &data->events[i];
+
+	return NULL;
+}
+
+static bool mma9553_is_any_event_enabled(struct mma9553_data *data,
+					 bool check_type,
+					 enum iio_chan_type type)
+{
+	int i;
+
+	for (i = 0; i < data->num_events; i++)
+		if ((check_type && data->events[i].info->type == type &&
+		     data->events[i].enabled) ||
+		     (!check_type && data->events[i].enabled))
+			return true;
+
+	return false;
+}
+
+static int mma9553_set_config(struct mma9553_data *data, u16 reg,
+			      u16 *p_reg_val, u16 val, u16 mask)
+{
+	int ret, retries;
+	u16 reg_val, config;
+
+	reg_val = *p_reg_val;
+	if (val == mma9553_get_bits(reg_val, mask))
+		return 0;
+
+	reg_val = mma9553_set_bits(reg_val, val, mask);
+	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+					reg, reg_val);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error writing config register 0x%x\n", reg);
+		return ret;
+	}
+
+	*p_reg_val = reg_val;
+
+	/* Reinitializes the pedometer with current configuration values */
+	config = mma9553_set_bits(data->conf.config, 1,
+				  MMA9553_MASK_CONF_CONFIG);
+
+	ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+					MMA9553_REG_CONF_CONF_STEPLEN, config);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error writing config register 0x%x\n",
+			MMA9553_REG_CONF_CONF_STEPLEN);
+		return ret;
+	}
+
+	retries = MMA9553_CONFIG_RETRIES;
+	do {
+		mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+		ret = mma9551_read_config_word(data->client,
+					       MMA9551_APPID_PEDOMETER,
+					       MMA9553_REG_CONF_CONF_STEPLEN,
+					       &config);
+		if (ret < 0)
+			return ret;
+	} while (mma9553_get_bits(config, MMA9553_MASK_CONF_CONFIG) &&
+		 --retries > 0);
+
+	return 0;
+}
+
+static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
+					 u8 *activity, u16 *stepcnt)
+{
+	u32 status_stepcnt;
+	u16 status;
+	int ret;
+
+	ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
+					MMA9553_REG_STATUS, sizeof(u32),
+					(u16 *) &status_stepcnt);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"error reading status and stepcnt\n");
+		return ret;
+	}
+
+	status = status_stepcnt & MMA9553_MASK_CONF_WORD;
+	*activity = mma9553_get_bits(status, MMA9553_MASK_STATUS_ACTIVITY);
+	*stepcnt = status_stepcnt >> 16;
+
+	return 0;
+}
+
+static int mma9553_conf_gpio(struct mma9553_data *data)
+{
+	u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER;
+	int ret;
+	struct mma9553_event *ev_step_detect;
+	bool activity_enabled;
+
+	activity_enabled =
+	    mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
+	ev_step_detect =
+	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+	/*
+	 * If both step detector and activity are enabled, use the MRGFL bit.
+	 * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags.
+	 */
+	if (activity_enabled && ev_step_detect->enabled)
+		bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_MRGFL);
+	else if (ev_step_detect->enabled)
+		bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_STEPCHG);
+	else if (activity_enabled)
+		bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_ACTCHG);
+	else			/* Reset */
+		appid = MMA9551_APPID_NONE;
+
+	if (data->gpio_bitnum == bitnum)
+		return 0;
+
+	/* Save initial values for activity and stepcnt */
+	if (activity_enabled || ev_step_detect->enabled)
+		mma9553_read_activity_stepcnt(data, &data->activity,
+					      &data->stepcnt);
+
+	ret = mma9551_gpio_config(data->client,
+				  MMA9553_DEFAULT_GPIO_PIN,
+				  appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
+	if (ret < 0)
+		return ret;
+	data->gpio_bitnum = bitnum;
+
+	return 0;
+}
+
+static int mma9553_init(struct mma9553_data *data)
+{
+	int ret;
+
+	ret = mma9551_read_version(data->client);
+	if (ret)
+		return ret;
+
+	/*
+	 * Read all the pedometer configuration registers. This is used as
+	 * a device identification command to differentiate the MMA9553L
+	 * from the MMA9550L.
+	 */
+	ret =
+	    mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
+				      MMA9553_REG_CONF_SLEEPMIN,
+				      sizeof(data->conf), (u16 *) &data->conf);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"device is not MMA9553L: failed to read cfg regs\n");
+		return ret;
+	}
+
+
+	/* Reset gpio */
+	data->gpio_bitnum = -1;
+	ret = mma9553_conf_gpio(data);
+	if (ret < 0)
+		return ret;
+
+	ret = mma9551_app_reset(data->client, MMA9551_RSC_PED);
+	if (ret < 0)
+		return ret;
+
+	/* Init config registers */
+	data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
+	data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
+	data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
+	data->conf.config =
+	    mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG);
+	/*
+	 * Clear the activity debounce counter when the activity level changes,
+	 * so that the confidence level applies for any activity level.
+	 */
+	data->conf.config = mma9553_set_bits(data->conf.config, 1,
+					     MMA9553_MASK_CONF_ACT_DBCNTM);
+	ret =
+	    mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
+				       MMA9553_REG_CONF_SLEEPMIN,
+				       sizeof(data->conf), (u16 *) &data->conf);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"failed to write configuration registers\n");
+		return ret;
+	}
+
+	return mma9551_set_device_state(data->client, true);
+}
+
+static int mma9553_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+	u16 tmp;
+	u8 activity;
+	bool powered_on;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_STEPS:
+			/*
+			 * The HW only counts steps and other dependent
+			 * parameters (speed, distance, calories, activity)
+			 * if power is on (from enabling an event or the
+			 * step counter */
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on) {
+				dev_err(&data->client->dev,
+					"No channels enabled\n");
+				return -EINVAL;
+			}
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_REG_STEPCNT,
+						       &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_DISTANCE:
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on) {
+				dev_err(&data->client->dev,
+					"No channels enabled\n");
+				return -EINVAL;
+			}
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_REG_DISTANCE,
+						       &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_ACTIVITY:
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on) {
+				dev_err(&data->client->dev,
+					"No channels enabled\n");
+				return -EINVAL;
+			}
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_REG_STATUS,
+						       &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+
+			activity =
+			    mma9553_get_bits(tmp, MMA9553_MASK_STATUS_ACTIVITY);
+
+			/*
+			 * The device does not support confidence value levels,
+			 * so we will always have 100% for current activity and
+			 * 0% for the others.
+			 */
+			if (chan->channel2 == mma9553_activity_to_mod(activity))
+				*val = 100;
+			else
+				*val = 0;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_VELOCITY:	/* m/h */
+			if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+				return -EINVAL;
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on) {
+				dev_err(&data->client->dev,
+					"No channels enabled\n");
+				return -EINVAL;
+			}
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_REG_SPEED, &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_ENERGY:	/* Cal or kcal */
+			powered_on =
+			    mma9553_is_any_event_enabled(data, false, 0) ||
+			    data->stepcnt_enabled;
+			if (!powered_on) {
+				dev_err(&data->client->dev,
+					"No channels enabled\n");
+				return -EINVAL;
+			}
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_status_word(data->client,
+						       MMA9551_APPID_PEDOMETER,
+						       MMA9553_REG_CALORIES,
+						       &tmp);
+			mutex_unlock(&data->mutex);
+			if (ret < 0)
+				return ret;
+			*val = tmp;
+			return IIO_VAL_INT;
+		case IIO_ACCEL:
+			mutex_lock(&data->mutex);
+			ret = mma9551_read_accel_chan(data->client,
+						      chan, val, val2);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_VELOCITY:	/* m/h to m/s */
+			if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+				return -EINVAL;
+			*val = 0;
+			*val2 = 277;	/* 0.000277 */
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_ENERGY:	/* Cal or kcal to J */
+			*val = 4184;
+			return IIO_VAL_INT;
+		case IIO_ACCEL:
+			return mma9551_read_accel_scale(val, val2);
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_ENABLE:
+		*val = data->stepcnt_enabled;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		tmp = mma9553_get_bits(data->conf.height_weight,
+					MMA9553_MASK_CONF_HEIGHT);
+		*val = tmp / 100;	/* cm to m */
+		*val2 = (tmp % 100) * 10000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_CALIBWEIGHT:
+		*val = mma9553_get_bits(data->conf.height_weight,
+					MMA9553_MASK_CONF_WEIGHT);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_DEBOUNCE_COUNT:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.filter,
+						MMA9553_MASK_CONF_FILTSTEP);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_DEBOUNCE_TIME:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.filter,
+						MMA9553_MASK_CONF_FILTTIME);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_INT_TIME:
+		switch (chan->type) {
+		case IIO_VELOCITY:
+			if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+				return -EINVAL;
+			*val = mma9553_get_bits(data->conf.speed_step,
+						MMA9553_MASK_CONF_SPDPRD);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret, tmp;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_ENABLE:
+		if (data->stepcnt_enabled == !!val)
+			return 0;
+		mutex_lock(&data->mutex);
+		ret = mma9551_set_power_state(data->client, val);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+		data->stepcnt_enabled = val;
+		mutex_unlock(&data->mutex);
+		return 0;
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		/* m to cm */
+		tmp = val * 100 + val2 / 10000;
+		if (tmp < 0 || tmp > 255)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9553_set_config(data,
+					 MMA9553_REG_CONF_HEIGHT_WEIGHT,
+					 &data->conf.height_weight,
+					 tmp, MMA9553_MASK_CONF_HEIGHT);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_CALIBWEIGHT:
+		if (val < 0 || val > 255)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = mma9553_set_config(data,
+					 MMA9553_REG_CONF_HEIGHT_WEIGHT,
+					 &data->conf.height_weight,
+					 val, MMA9553_MASK_CONF_WEIGHT);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_DEBOUNCE_COUNT:
+		switch (chan->type) {
+		case IIO_STEPS:
+			/*
+			 * Set to 0 to disable step filtering. If the value
+			 * specified is greater than 6, then 6 will be used.
+			 */
+			if (val < 0)
+				return -EINVAL;
+			if (val > 6)
+				val = 6;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+						 &data->conf.filter, val,
+						 MMA9553_MASK_CONF_FILTSTEP);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_DEBOUNCE_TIME:
+		switch (chan->type) {
+		case IIO_STEPS:
+			if (val < 0 || val > 127)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+						 &data->conf.filter, val,
+						 MMA9553_MASK_CONF_FILTTIME);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_INT_TIME:
+		switch (chan->type) {
+		case IIO_VELOCITY:
+			if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+				return -EINVAL;
+			/*
+			 * If set to a value greater than 5, then 5 will be
+			 * used. Warning: Do not set SPDPRD to 0 or 1 as
+			 * this may cause undesirable behavior.
+			 */
+			if (val < 2)
+				return -EINVAL;
+			if (val > 5)
+				val = 5;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data,
+						 MMA9553_REG_CONF_SPEED_STEP,
+						 &data->conf.speed_step, val,
+						 MMA9553_MASK_CONF_SPDPRD);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_read_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir)
+{
+
+	struct mma9553_data *data = iio_priv(indio_dev);
+	struct mma9553_event *event;
+
+	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+	if (!event)
+		return -EINVAL;
+
+	return event->enabled;
+}
+
+static int mma9553_write_event_config(struct iio_dev *indio_dev,
+				      const struct iio_chan_spec *chan,
+				      enum iio_event_type type,
+				      enum iio_event_direction dir, int state)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	struct mma9553_event *event;
+	int ret;
+
+	event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+	if (!event)
+		return -EINVAL;
+
+	if (event->enabled == state)
+		return 0;
+
+	mutex_lock(&data->mutex);
+
+	ret = mma9551_set_power_state(data->client, state);
+	if (ret < 0)
+		goto err_out;
+	event->enabled = state;
+
+	ret = mma9553_conf_gpio(data);
+	if (ret < 0)
+		goto err_conf_gpio;
+
+	mutex_unlock(&data->mutex);
+
+	return ret;
+
+err_conf_gpio:
+	if (state) {
+		event->enabled = false;
+		mma9551_set_power_state(data->client, false);
+	}
+err_out:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static int mma9553_read_event_value(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    enum iio_event_info info,
+				    int *val, int *val2)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+
+	*val2 = 0;
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = mma9553_get_bits(data->conf.speed_step,
+						MMA9553_MASK_CONF_STEPCOALESCE);
+			return IIO_VAL_INT;
+		case IIO_ACTIVITY:
+			/*
+			 * The device does not support confidence value levels.
+			 * We set an average of 50%.
+			 */
+			*val = 50;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (chan->type) {
+		case IIO_ACTIVITY:
+			*val = MMA9553_ACTIVITY_THD_TO_SEC(data->conf.actthd);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_write_event_value(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     enum iio_event_info info,
+				     int val, int val2)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		switch (chan->type) {
+		case IIO_STEPS:
+			if (val < 0 || val > 255)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data,
+						MMA9553_REG_CONF_SPEED_STEP,
+						&data->conf.speed_step, val,
+						MMA9553_MASK_CONF_STEPCOALESCE);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	case IIO_EV_INFO_PERIOD:
+		switch (chan->type) {
+		case IIO_ACTIVITY:
+			mutex_lock(&data->mutex);
+			ret = mma9553_set_config(data, MMA9553_REG_CONF_ACTTHD,
+						 &data->conf.actthd,
+						 MMA9553_ACTIVITY_SEC_TO_THD
+						 (val), MMA9553_MASK_CONF_WORD);
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mma9553_get_calibgender_mode(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	u8 gender;
+
+	gender = mma9553_get_bits(data->conf.filter, MMA9553_MASK_CONF_MALE);
+	/*
+	 * HW expects 0 for female and 1 for male,
+	 * while iio index is 0 for male and 1 for female
+	 */
+	return !gender;
+}
+
+static int mma9553_set_calibgender_mode(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan,
+					unsigned int mode)
+{
+	struct mma9553_data *data = iio_priv(indio_dev);
+	u8 gender = !mode;
+	int ret;
+
+	if ((mode != 0) && (mode != 1))
+		return -EINVAL;
+	mutex_lock(&data->mutex);
+	ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+				 &data->conf.filter, gender,
+				 MMA9553_MASK_CONF_MALE);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static const struct iio_event_spec mma9553_step_event = {
+	.type = IIO_EV_TYPE_CHANGE,
+	.dir = IIO_EV_DIR_NONE,
+	.mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE),
+};
+
+static const struct iio_event_spec mma9553_activity_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+				 BIT(IIO_EV_INFO_VALUE) |
+				 BIT(IIO_EV_INFO_PERIOD),
+	 },
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+				 BIT(IIO_EV_INFO_VALUE) |
+				 BIT(IIO_EV_INFO_PERIOD),
+	},
+};
+
+static const char * const calibgender_modes[] = { "male", "female" };
+
+static const struct iio_enum mma9553_calibgender_enum = {
+	.items = calibgender_modes,
+	.num_items = ARRAY_SIZE(calibgender_modes),
+	.get = mma9553_get_calibgender_mode,
+	.set = mma9553_set_calibgender_mode,
+};
+
+static const struct iio_chan_spec_ext_info mma9553_ext_info[] = {
+	IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum),
+	IIO_ENUM_AVAILABLE("calibgender", &mma9553_calibgender_enum),
+	{},
+};
+
+#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) {		\
+	.type = _type,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE)      |	\
+			      BIT(IIO_CHAN_INFO_CALIBHEIGHT) |	\
+			      _mask,				\
+	.ext_info = mma9553_ext_info,				\
+}
+
+#define MMA9553_ACTIVITY_CHANNEL(_chan2) {				\
+	.type = IIO_ACTIVITY,						\
+	.modified = 1,							\
+	.channel2 = _chan2,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT),	\
+	.event_spec = mma9553_activity_events,				\
+	.num_event_specs = ARRAY_SIZE(mma9553_activity_events),		\
+	.ext_info = mma9553_ext_info,					\
+}
+
+static const struct iio_chan_spec mma9553_channels[] = {
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
+	MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
+
+	{
+		.type = IIO_STEPS,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				     BIT(IIO_CHAN_INFO_ENABLE) |
+				     BIT(IIO_CHAN_INFO_DEBOUNCE_COUNT) |
+				     BIT(IIO_CHAN_INFO_DEBOUNCE_TIME),
+		.event_spec = &mma9553_step_event,
+		.num_event_specs = 1,
+	},
+
+	MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
+	{
+		.type = IIO_VELOCITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_INT_TIME) |
+				      BIT(IIO_CHAN_INFO_ENABLE),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT),
+		.ext_info = mma9553_ext_info,
+	},
+	MMA9553_PEDOMETER_CHANNEL(IIO_ENERGY, BIT(IIO_CHAN_INFO_RAW) |
+				  BIT(IIO_CHAN_INFO_SCALE) |
+				  BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
+
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
+	MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
+};
+
+static const struct iio_info mma9553_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = mma9553_read_raw,
+	.write_raw = mma9553_write_raw,
+	.read_event_config = mma9553_read_event_config,
+	.write_event_config = mma9553_write_event_config,
+	.read_event_value = mma9553_read_event_value,
+	.write_event_value = mma9553_write_event_value,
+};
+
+static irqreturn_t mma9553_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct mma9553_data *data = iio_priv(indio_dev);
+
+	data->timestamp = iio_get_time_ns();
+	/*
+	 * Since we only configure the interrupt pin when an
+	 * event is enabled, we are sure we have at least
+	 * one event enabled at this point.
+	 */
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t mma9553_event_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct mma9553_data *data = iio_priv(indio_dev);
+	u16 stepcnt;
+	u8 activity;
+	struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
+	if (ret < 0) {
+		mutex_unlock(&data->mutex);
+		return IRQ_HANDLED;
+	}
+
+	ev_prev_activity =
+	    mma9553_get_event(data, IIO_ACTIVITY,
+			      mma9553_activity_to_mod(data->activity),
+			      IIO_EV_DIR_FALLING);
+	ev_activity =
+	    mma9553_get_event(data, IIO_ACTIVITY,
+			      mma9553_activity_to_mod(activity),
+			      IIO_EV_DIR_RISING);
+	ev_step_detect =
+	    mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+	if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
+		data->stepcnt = stepcnt;
+		iio_push_event(indio_dev,
+			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+			       IIO_EV_DIR_NONE, IIO_EV_TYPE_CHANGE, 0, 0, 0),
+			       data->timestamp);
+	}
+
+	if (activity != data->activity) {
+		data->activity = activity;
+		/* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
+		if (ev_prev_activity && ev_prev_activity->enabled)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+				       ev_prev_activity->info->mod,
+				       IIO_EV_DIR_FALLING,
+				       IIO_EV_TYPE_THRESH, 0, 0, 0),
+				       data->timestamp);
+
+		if (ev_activity && ev_activity->enabled)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+				       ev_activity->info->mod,
+				       IIO_EV_DIR_RISING,
+				       IIO_EV_TYPE_THRESH, 0, 0, 0),
+				       data->timestamp);
+	}
+	mutex_unlock(&data->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int mma9553_gpio_probe(struct i2c_client *client)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static const char *mma9553_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+
+	return dev_name(dev);
+}
+
+static int mma9553_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct mma9553_data *data;
+	struct iio_dev *indio_dev;
+	const char *name = NULL;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	if (id)
+		name = id->name;
+	else if (ACPI_HANDLE(&client->dev))
+		name = mma9553_match_acpi_device(&client->dev);
+	else
+		return -ENOSYS;
+
+	mutex_init(&data->mutex);
+	mma9553_init_events(data);
+
+	ret = mma9553_init(data);
+	if (ret < 0)
+		return ret;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = mma9553_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &mma9553_info;
+
+	if (client->irq < 0)
+		client->irq = mma9553_gpio_probe(client);
+
+	if (client->irq >= 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						mma9553_irq_handler,
+						mma9553_event_handler,
+						IRQF_TRIGGER_RISING,
+						MMA9553_IRQ_NAME, indio_dev);
+		if (ret < 0) {
+			dev_err(&client->dev, "request irq %d failed\n",
+				client->irq);
+			goto out_poweroff;
+		}
+
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to register iio device\n");
+		goto out_poweroff;
+	}
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto out_iio_unregister;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 MMA9551_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+
+	return 0;
+
+out_iio_unregister:
+	iio_device_unregister(indio_dev);
+out_poweroff:
+	mma9551_set_device_state(client, false);
+	return ret;
+}
+
+static int mma9553_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct mma9553_data *data = iio_priv(indio_dev);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	iio_device_unregister(indio_dev);
+	mutex_lock(&data->mutex);
+	mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma9553_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int mma9553_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = mma9551_set_device_state(data->client, true);
+	if (ret < 0)
+		return ret;
+
+	mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mma9553_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, false);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int mma9553_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma9553_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = mma9551_set_device_state(data->client, true);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops mma9553_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
+	SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
+			   mma9553_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id mma9553_acpi_match[] = {
+	{"MMA9553", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
+
+static const struct i2c_device_id mma9553_id[] = {
+	{"mma9553", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma9553_id);
+
+static struct i2c_driver mma9553_driver = {
+	.driver = {
+		   .name = MMA9553_DRV_NAME,
+		   .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
+		   .pm = &mma9553_pm_ops,
+		   },
+	.probe = mma9553_probe,
+	.remove = mma9553_remove,
+	.id_table = mma9553_id,
+};
+
+module_i2c_driver(mma9553_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c
new file mode 100644
index 0000000..4ae05fc
--- /dev/null
+++ b/drivers/iio/accel/ssp_accel_sensor.c
@@ -0,0 +1,169 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "../common/ssp_sensors/ssp_iio_sensor.h"
+
+#define SSP_CHANNEL_COUNT 3
+
+#define SSP_ACCEL_NAME "ssp-accelerometer"
+static const char ssp_accel_device_name[] = SSP_ACCEL_NAME;
+
+enum ssp_accel_3d_channel {
+	SSP_CHANNEL_SCAN_INDEX_X,
+	SSP_CHANNEL_SCAN_INDEX_Y,
+	SSP_CHANNEL_SCAN_INDEX_Z,
+	SSP_CHANNEL_SCAN_INDEX_TIME,
+};
+
+static int ssp_accel_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,  int *val,
+			      int *val2, long mask)
+{
+	u32 t;
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		t = ssp_get_sensor_delay(data, SSP_ACCELEROMETER_SENSOR);
+		ssp_convert_to_freq(t, val, val2);
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ssp_accel_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan, int val,
+			       int val2, long mask)
+{
+	int ret;
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = ssp_convert_to_time(val, val2);
+		ret = ssp_change_delay(data, SSP_ACCELEROMETER_SENSOR, ret);
+		if (ret < 0)
+			dev_err(&indio_dev->dev, "accel sensor enable fail\n");
+
+		return ret;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static struct iio_info ssp_accel_iio_info = {
+	.read_raw = &ssp_accel_read_raw,
+	.write_raw = &ssp_accel_write_raw,
+};
+
+static const unsigned long ssp_accel_scan_mask[] = { 0x7, 0, };
+
+static const struct iio_chan_spec ssp_acc_channels[] = {
+	SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
+	SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
+	SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
+	SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+};
+
+static int ssp_process_accel_data(struct iio_dev *indio_dev, void *buf,
+				  int64_t timestamp)
+{
+	return ssp_common_process_data(indio_dev, buf, SSP_ACCELEROMETER_SIZE,
+				       timestamp);
+}
+
+static const struct iio_buffer_setup_ops ssp_accel_buffer_ops = {
+	.postenable = &ssp_common_buffer_postenable,
+	.postdisable = &ssp_common_buffer_postdisable,
+};
+
+static int ssp_accel_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct ssp_sensor_data *spd;
+	struct iio_buffer *buffer;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	spd = iio_priv(indio_dev);
+
+	spd->process_data = ssp_process_accel_data;
+	spd->type = SSP_ACCELEROMETER_SENSOR;
+
+	indio_dev->name = ssp_accel_device_name;
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->info = &ssp_accel_iio_info;
+	indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+	indio_dev->channels = ssp_acc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ssp_acc_channels);
+	indio_dev->available_scan_masks = ssp_accel_scan_mask;
+
+	buffer = devm_iio_kfifo_allocate(&pdev->dev);
+	if (!buffer)
+		return -ENOMEM;
+
+	iio_device_attach_buffer(indio_dev, buffer);
+
+	indio_dev->setup_ops = &ssp_accel_buffer_ops;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	/* ssp registering should be done after all iio setup */
+	ssp_register_consumer(indio_dev, SSP_ACCELEROMETER_SENSOR);
+
+	return 0;
+}
+
+static int ssp_accel_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver ssp_accel_driver = {
+	.driver = {
+		.name = SSP_ACCEL_NAME,
+	},
+	.probe = ssp_accel_probe,
+	.remove =  ssp_accel_remove,
+};
+
+module_platform_driver(ssp_accel_driver);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 0f79e47..202daf8 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -135,6 +135,17 @@
 	  device. Depending on platform configuration, this general purpose ADC can
 	  be used for sampling sensors such as thermal resistors.
 
+config CC10001_ADC
+	tristate "Cosmic Circuits 10001 ADC driver"
+	depends on HAS_IOMEM || HAVE_CLK || REGULATOR
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Cosmic Circuits 10001 ADC.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called cc10001_adc.
+
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -228,6 +239,20 @@
 	  To compile this driver as a module, choose M here: the module will
 	  be called qcom-spmi-iadc.
 
+config QCOM_SPMI_VADC
+	tristate "Qualcomm SPMI PMIC voltage ADC"
+	depends on SPMI
+	select REGMAP_SPMI
+	help
+	  This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip.
+
+	  The driver supports multiple channels read. The VADC is a 15-bit
+	  sigma-delta ADC. Some of the channels are internally used for
+	  calibration.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called qcom-spmi-vadc.
+
 config ROCKCHIP_SARADC
 	tristate "Rockchip SARADC driver"
 	depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 701fdb7..0315af6 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
+obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
@@ -24,6 +25,7 @@
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
+obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
new file mode 100644
index 0000000..51e2a83
--- /dev/null
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2014-2015 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* Registers */
+#define CC10001_ADC_CONFIG		0x00
+#define CC10001_ADC_START_CONV		BIT(4)
+#define CC10001_ADC_MODE_SINGLE_CONV	BIT(5)
+
+#define CC10001_ADC_DDATA_OUT		0x04
+#define CC10001_ADC_EOC			0x08
+#define CC10001_ADC_EOC_SET		BIT(0)
+
+#define CC10001_ADC_CHSEL_SAMPLED	0x0c
+#define CC10001_ADC_POWER_UP		0x10
+#define CC10001_ADC_POWER_UP_SET	BIT(0)
+#define CC10001_ADC_DEBUG		0x14
+#define CC10001_ADC_DATA_COUNT		0x20
+
+#define CC10001_ADC_DATA_MASK		GENMASK(9, 0)
+#define CC10001_ADC_NUM_CHANNELS	8
+#define CC10001_ADC_CH_MASK		GENMASK(2, 0)
+
+#define CC10001_INVALID_SAMPLED		0xffff
+#define CC10001_MAX_POLL_COUNT		20
+
+/*
+ * As per device specification, wait six clock cycles after power-up to
+ * activate START. Since adding two more clock cycles delay does not
+ * impact the performance too much, we are adding two additional cycles delay
+ * intentionally here.
+ */
+#define	CC10001_WAIT_CYCLES		8
+
+struct cc10001_adc_device {
+	void __iomem *reg_base;
+	struct clk *adc_clk;
+	struct regulator *reg;
+	u16 *buf;
+
+	struct mutex lock;
+	unsigned long channel_map;
+	unsigned int start_delay_ns;
+	unsigned int eoc_delay_ns;
+};
+
+static inline void cc10001_adc_write_reg(struct cc10001_adc_device *adc_dev,
+					 u32 reg, u32 val)
+{
+	writel(val, adc_dev->reg_base + reg);
+}
+
+static inline u32 cc10001_adc_read_reg(struct cc10001_adc_device *adc_dev,
+				       u32 reg)
+{
+	return readl(adc_dev->reg_base + reg);
+}
+
+static void cc10001_adc_start(struct cc10001_adc_device *adc_dev,
+			      unsigned int channel)
+{
+	u32 val;
+
+	/* Channel selection and mode of operation */
+	val = (channel & CC10001_ADC_CH_MASK) | CC10001_ADC_MODE_SINGLE_CONV;
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
+
+	val = cc10001_adc_read_reg(adc_dev, CC10001_ADC_CONFIG);
+	val = val | CC10001_ADC_START_CONV;
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
+}
+
+static u16 cc10001_adc_poll_done(struct iio_dev *indio_dev,
+				 unsigned int channel,
+				 unsigned int delay)
+{
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+	unsigned int poll_count = 0;
+
+	while (!(cc10001_adc_read_reg(adc_dev, CC10001_ADC_EOC) &
+			CC10001_ADC_EOC_SET)) {
+
+		ndelay(delay);
+		if (poll_count++ == CC10001_MAX_POLL_COUNT)
+			return CC10001_INVALID_SAMPLED;
+	}
+
+	poll_count = 0;
+	while ((cc10001_adc_read_reg(adc_dev, CC10001_ADC_CHSEL_SAMPLED) &
+			CC10001_ADC_CH_MASK) != channel) {
+
+		ndelay(delay);
+		if (poll_count++ == CC10001_MAX_POLL_COUNT)
+			return CC10001_INVALID_SAMPLED;
+	}
+
+	/* Read the 10 bit output register */
+	return cc10001_adc_read_reg(adc_dev, CC10001_ADC_DDATA_OUT) &
+			       CC10001_ADC_DATA_MASK;
+}
+
+static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
+{
+	struct cc10001_adc_device *adc_dev;
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev;
+	unsigned int delay_ns;
+	unsigned int channel;
+	bool sample_invalid;
+	u16 *data;
+	int i;
+
+	indio_dev = pf->indio_dev;
+	adc_dev = iio_priv(indio_dev);
+	data = adc_dev->buf;
+
+	mutex_lock(&adc_dev->lock);
+
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
+			      CC10001_ADC_POWER_UP_SET);
+
+	/* Wait for 8 (6+2) clock cycles before activating START */
+	ndelay(adc_dev->start_delay_ns);
+
+	/* Calculate delay step for eoc and sampled data */
+	delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
+
+	i = 0;
+	sample_invalid = false;
+	for_each_set_bit(channel, indio_dev->active_scan_mask,
+				  indio_dev->masklength) {
+
+		cc10001_adc_start(adc_dev, channel);
+
+		data[i] = cc10001_adc_poll_done(indio_dev, channel, delay_ns);
+		if (data[i] == CC10001_INVALID_SAMPLED) {
+			dev_warn(&indio_dev->dev,
+				 "invalid sample on channel %d\n", channel);
+			sample_invalid = true;
+			goto done;
+		}
+		i++;
+	}
+
+done:
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+
+	mutex_unlock(&adc_dev->lock);
+
+	if (!sample_invalid)
+		iio_push_to_buffers_with_timestamp(indio_dev, data,
+						   iio_get_time_ns());
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan)
+{
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+	unsigned int delay_ns;
+	u16 val;
+
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
+			      CC10001_ADC_POWER_UP_SET);
+
+	/* Wait for 8 (6+2) clock cycles before activating START */
+	ndelay(adc_dev->start_delay_ns);
+
+	/* Calculate delay step for eoc and sampled data */
+	delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
+
+	cc10001_adc_start(adc_dev, chan->channel);
+
+	val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
+
+	cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+
+	return val;
+}
+
+static int cc10001_adc_read_raw(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan,
+				 int *val, int *val2, long mask)
+{
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (iio_buffer_enabled(indio_dev))
+			return -EBUSY;
+		mutex_lock(&adc_dev->lock);
+		*val = cc10001_adc_read_raw_voltage(indio_dev, chan);
+		mutex_unlock(&adc_dev->lock);
+
+		if (*val == CC10001_INVALID_SAMPLED)
+			return -EIO;
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = regulator_get_voltage(adc_dev->reg);
+		if (ret)
+			return ret;
+
+		*val = ret / 1000;
+		*val2 = chan->scan_type.realbits;
+		return IIO_VAL_FRACTIONAL_LOG2;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int cc10001_update_scan_mode(struct iio_dev *indio_dev,
+				    const unsigned long *scan_mask)
+{
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+
+	kfree(adc_dev->buf);
+	adc_dev->buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+	if (!adc_dev->buf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static const struct iio_info cc10001_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &cc10001_adc_read_raw,
+	.update_scan_mode = &cc10001_update_scan_mode,
+};
+
+static int cc10001_adc_channel_init(struct iio_dev *indio_dev)
+{
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+	struct iio_chan_spec *chan_array, *timestamp;
+	unsigned int bit, idx = 0;
+
+	indio_dev->num_channels = bitmap_weight(&adc_dev->channel_map,
+						CC10001_ADC_NUM_CHANNELS);
+
+	chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels + 1,
+				  sizeof(struct iio_chan_spec),
+				  GFP_KERNEL);
+	if (!chan_array)
+		return -ENOMEM;
+
+	for_each_set_bit(bit, &adc_dev->channel_map, CC10001_ADC_NUM_CHANNELS) {
+		struct iio_chan_spec *chan = &chan_array[idx];
+
+		chan->type = IIO_VOLTAGE;
+		chan->indexed = 1;
+		chan->channel = bit;
+		chan->scan_index = idx;
+		chan->scan_type.sign = 'u';
+		chan->scan_type.realbits = 10;
+		chan->scan_type.storagebits = 16;
+		chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+		chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+		idx++;
+	}
+
+	timestamp = &chan_array[idx];
+	timestamp->type = IIO_TIMESTAMP;
+	timestamp->channel = -1;
+	timestamp->scan_index = idx;
+	timestamp->scan_type.sign = 's';
+	timestamp->scan_type.realbits = 64;
+	timestamp->scan_type.storagebits = 64;
+
+	indio_dev->channels = chan_array;
+
+	return 0;
+}
+
+static int cc10001_adc_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct cc10001_adc_device *adc_dev;
+	unsigned long adc_clk_rate;
+	struct resource *res;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	adc_dev = iio_priv(indio_dev);
+
+	adc_dev->channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
+	if (!of_property_read_u32(node, "adc-reserved-channels", &ret))
+		adc_dev->channel_map &= ~ret;
+
+	adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
+	if (IS_ERR(adc_dev->reg))
+		return PTR_ERR(adc_dev->reg);
+
+	ret = regulator_enable(adc_dev->reg);
+	if (ret)
+		return ret;
+
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->info = &cc10001_adc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc_dev->reg_base)) {
+		ret = PTR_ERR(adc_dev->reg_base);
+		goto err_disable_reg;
+	}
+
+	adc_dev->adc_clk = devm_clk_get(&pdev->dev, "adc");
+	if (IS_ERR(adc_dev->adc_clk)) {
+		dev_err(&pdev->dev, "failed to get the clock\n");
+		ret = PTR_ERR(adc_dev->adc_clk);
+		goto err_disable_reg;
+	}
+
+	ret = clk_prepare_enable(adc_dev->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable the clock\n");
+		goto err_disable_reg;
+	}
+
+	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+	if (!adc_clk_rate) {
+		ret = -EINVAL;
+		dev_err(&pdev->dev, "null clock rate!\n");
+		goto err_disable_clk;
+	}
+
+	adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
+	adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
+
+	/* Setup the ADC channels available on the device */
+	ret = cc10001_adc_channel_init(indio_dev);
+	if (ret < 0)
+		goto err_disable_clk;
+
+	mutex_init(&adc_dev->lock);
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 &cc10001_adc_trigger_h, NULL);
+	if (ret < 0)
+		goto err_disable_clk;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto err_cleanup_buffer;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	return 0;
+
+err_cleanup_buffer:
+	iio_triggered_buffer_cleanup(indio_dev);
+err_disable_clk:
+	clk_disable_unprepare(adc_dev->adc_clk);
+err_disable_reg:
+	regulator_disable(adc_dev->reg);
+	return ret;
+}
+
+static int cc10001_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	clk_disable_unprepare(adc_dev->adc_clk);
+	regulator_disable(adc_dev->reg);
+
+	return 0;
+}
+
+static const struct of_device_id cc10001_adc_dt_ids[] = {
+	{ .compatible = "cosmic,10001-adc", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cc10001_adc_dt_ids);
+
+static struct platform_driver cc10001_adc_driver = {
+	.driver = {
+		.name   = "cc10001-adc",
+		.of_match_table = cc10001_adc_dt_ids,
+	},
+	.probe	= cc10001_adc_probe,
+	.remove	= cc10001_adc_remove,
+};
+module_platform_driver(cc10001_adc_driver);
+
+MODULE_AUTHOR("Phani Movva <Phani.Movva@imgtec.com>");
+MODULE_DESCRIPTION("Cosmic Circuits ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c
new file mode 100644
index 0000000..3211729
--- /dev/null
+++ b/drivers/iio/adc/qcom-spmi-vadc.c
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+
+/* VADC register and bit definitions */
+#define VADC_REVISION2				0x1
+#define VADC_REVISION2_SUPPORTED_VADC		1
+
+#define VADC_PERPH_TYPE				0x4
+#define VADC_PERPH_TYPE_ADC			8
+
+#define VADC_PERPH_SUBTYPE			0x5
+#define VADC_PERPH_SUBTYPE_VADC			1
+
+#define VADC_STATUS1				0x8
+#define VADC_STATUS1_OP_MODE			4
+#define VADC_STATUS1_REQ_STS			BIT(1)
+#define VADC_STATUS1_EOC			BIT(0)
+#define VADC_STATUS1_REQ_STS_EOC_MASK		0x3
+
+#define VADC_MODE_CTL				0x40
+#define VADC_OP_MODE_SHIFT			3
+#define VADC_OP_MODE_NORMAL			0
+#define VADC_AMUX_TRIM_EN			BIT(1)
+#define VADC_ADC_TRIM_EN			BIT(0)
+
+#define VADC_EN_CTL1				0x46
+#define VADC_EN_CTL1_SET			BIT(7)
+
+#define VADC_ADC_CH_SEL_CTL			0x48
+
+#define VADC_ADC_DIG_PARAM			0x50
+#define VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT	2
+
+#define VADC_HW_SETTLE_DELAY			0x51
+
+#define VADC_CONV_REQ				0x52
+#define VADC_CONV_REQ_SET			BIT(7)
+
+#define VADC_FAST_AVG_CTL			0x5a
+#define VADC_FAST_AVG_EN			0x5b
+#define VADC_FAST_AVG_EN_SET			BIT(7)
+
+#define VADC_ACCESS				0xd0
+#define VADC_ACCESS_DATA			0xa5
+
+#define VADC_PERH_RESET_CTL3			0xda
+#define VADC_FOLLOW_WARM_RB			BIT(2)
+
+#define VADC_DATA				0x60	/* 16 bits */
+
+#define VADC_CONV_TIME_MIN_US			2000
+#define VADC_CONV_TIME_MAX_US			2100
+
+/* Min ADC code represents 0V */
+#define VADC_MIN_ADC_CODE			0x6000
+/* Max ADC code represents full-scale range of 1.8V */
+#define VADC_MAX_ADC_CODE			0xa800
+
+#define VADC_ABSOLUTE_RANGE_UV			625000
+#define VADC_RATIOMETRIC_RANGE_UV		1800000
+
+#define VADC_DEF_PRESCALING			0 /* 1:1 */
+#define VADC_DEF_DECIMATION			0 /* 512 */
+#define VADC_DEF_HW_SETTLE_TIME			0 /* 0 us */
+#define VADC_DEF_AVG_SAMPLES			0 /* 1 sample */
+#define VADC_DEF_CALIB_TYPE			VADC_CALIB_ABSOLUTE
+
+#define VADC_DECIMATION_MIN			512
+#define VADC_DECIMATION_MAX			4096
+
+#define VADC_HW_SETTLE_DELAY_MAX		10000
+#define VADC_AVG_SAMPLES_MAX			512
+
+#define KELVINMIL_CELSIUSMIL			273150
+
+#define VADC_CHAN_MIN			VADC_USBIN
+#define VADC_CHAN_MAX			VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
+
+/*
+ * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
+ * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
+ * calibration.
+ */
+enum vadc_calibration {
+	VADC_CALIB_ABSOLUTE = 0,
+	VADC_CALIB_RATIOMETRIC
+};
+
+/**
+ * struct vadc_linear_graph - Represent ADC characteristics.
+ * @dy: numerator slope to calculate the gain.
+ * @dx: denominator slope to calculate the gain.
+ * @gnd: A/D word of the ground reference used for the channel.
+ *
+ * Each ADC device has different offset and gain parameters which are
+ * computed to calibrate the device.
+ */
+struct vadc_linear_graph {
+	s32 dy;
+	s32 dx;
+	s32 gnd;
+};
+
+/**
+ * struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
+ * @num: the inverse numerator of the gain applied to the input channel.
+ * @den: the inverse denominator of the gain applied to the input channel.
+ */
+struct vadc_prescale_ratio {
+	u32 num;
+	u32 den;
+};
+
+/**
+ * struct vadc_channel_prop - VADC channel property.
+ * @channel: channel number, refer to the channel list.
+ * @calibration: calibration type.
+ * @decimation: sampling rate supported for the channel.
+ * @prescale: channel scaling performed on the input signal.
+ * @hw_settle_time: the time between AMUX being configured and the
+ *	start of conversion.
+ * @avg_samples: ability to provide single result from the ADC
+ *	that is an average of multiple measurements.
+ */
+struct vadc_channel_prop {
+	unsigned int channel;
+	enum vadc_calibration calibration;
+	unsigned int decimation;
+	unsigned int prescale;
+	unsigned int hw_settle_time;
+	unsigned int avg_samples;
+};
+
+/**
+ * struct vadc_priv - VADC private structure.
+ * @regmap: pointer to struct regmap.
+ * @dev: pointer to struct device.
+ * @base: base address for the ADC peripheral.
+ * @nchannels: number of VADC channels.
+ * @chan_props: array of VADC channel properties.
+ * @iio_chans: array of IIO channels specification.
+ * @are_ref_measured: are reference points measured.
+ * @poll_eoc: use polling instead of interrupt.
+ * @complete: VADC result notification after interrupt is received.
+ * @graph: store parameters for calibration.
+ * @lock: ADC lock for access to the peripheral.
+ */
+struct vadc_priv {
+	struct regmap		 *regmap;
+	struct device		 *dev;
+	u16			 base;
+	unsigned int		 nchannels;
+	struct vadc_channel_prop *chan_props;
+	struct iio_chan_spec	 *iio_chans;
+	bool			 are_ref_measured;
+	bool			 poll_eoc;
+	struct completion	 complete;
+	struct vadc_linear_graph graph[2];
+	struct mutex		 lock;
+};
+
+static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
+	{.num =  1, .den =  1},
+	{.num =  1, .den =  3},
+	{.num =  1, .den =  4},
+	{.num =  1, .den =  6},
+	{.num =  1, .den = 20},
+	{.num =  1, .den =  8},
+	{.num = 10, .den = 81},
+	{.num =  1, .den = 10}
+};
+
+static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
+{
+	return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
+}
+
+static int vadc_write(struct vadc_priv *vadc, u16 offset, u8 data)
+{
+	return regmap_write(vadc->regmap, vadc->base + offset, data);
+}
+
+static int vadc_reset(struct vadc_priv *vadc)
+{
+	u8 data;
+	int ret;
+
+	ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
+	if (ret)
+		return ret;
+
+	ret = vadc_read(vadc, VADC_PERH_RESET_CTL3, &data);
+	if (ret)
+		return ret;
+
+	ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
+	if (ret)
+		return ret;
+
+	data |= VADC_FOLLOW_WARM_RB;
+
+	return vadc_write(vadc, VADC_PERH_RESET_CTL3, data);
+}
+
+static int vadc_set_state(struct vadc_priv *vadc, bool state)
+{
+	return vadc_write(vadc, VADC_EN_CTL1, state ? VADC_EN_CTL1_SET : 0);
+}
+
+static void vadc_show_status(struct vadc_priv *vadc)
+{
+	u8 mode, sta1, chan, dig, en, req;
+	int ret;
+
+	ret = vadc_read(vadc, VADC_MODE_CTL, &mode);
+	if (ret)
+		return;
+
+	ret = vadc_read(vadc, VADC_ADC_DIG_PARAM, &dig);
+	if (ret)
+		return;
+
+	ret = vadc_read(vadc, VADC_ADC_CH_SEL_CTL, &chan);
+	if (ret)
+		return;
+
+	ret = vadc_read(vadc, VADC_CONV_REQ, &req);
+	if (ret)
+		return;
+
+	ret = vadc_read(vadc, VADC_STATUS1, &sta1);
+	if (ret)
+		return;
+
+	ret = vadc_read(vadc, VADC_EN_CTL1, &en);
+	if (ret)
+		return;
+
+	dev_err(vadc->dev,
+		"mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
+		mode, en, chan, dig, req, sta1);
+}
+
+static int vadc_configure(struct vadc_priv *vadc,
+			  struct vadc_channel_prop *prop)
+{
+	u8 decimation, mode_ctrl;
+	int ret;
+
+	/* Mode selection */
+	mode_ctrl = (VADC_OP_MODE_NORMAL << VADC_OP_MODE_SHIFT) |
+		     VADC_ADC_TRIM_EN | VADC_AMUX_TRIM_EN;
+	ret = vadc_write(vadc, VADC_MODE_CTL, mode_ctrl);
+	if (ret)
+		return ret;
+
+	/* Channel selection */
+	ret = vadc_write(vadc, VADC_ADC_CH_SEL_CTL, prop->channel);
+	if (ret)
+		return ret;
+
+	/* Digital parameter setup */
+	decimation = prop->decimation << VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+	ret = vadc_write(vadc, VADC_ADC_DIG_PARAM, decimation);
+	if (ret)
+		return ret;
+
+	/* HW settle time delay */
+	ret = vadc_write(vadc, VADC_HW_SETTLE_DELAY, prop->hw_settle_time);
+	if (ret)
+		return ret;
+
+	ret = vadc_write(vadc, VADC_FAST_AVG_CTL, prop->avg_samples);
+	if (ret)
+		return ret;
+
+	if (prop->avg_samples)
+		ret = vadc_write(vadc, VADC_FAST_AVG_EN, VADC_FAST_AVG_EN_SET);
+	else
+		ret = vadc_write(vadc, VADC_FAST_AVG_EN, 0);
+
+	return ret;
+}
+
+static int vadc_poll_wait_eoc(struct vadc_priv *vadc, unsigned int interval_us)
+{
+	unsigned int count, retry;
+	u8 sta1;
+	int ret;
+
+	retry = interval_us / VADC_CONV_TIME_MIN_US;
+
+	for (count = 0; count < retry; count++) {
+		ret = vadc_read(vadc, VADC_STATUS1, &sta1);
+		if (ret)
+			return ret;
+
+		sta1 &= VADC_STATUS1_REQ_STS_EOC_MASK;
+		if (sta1 == VADC_STATUS1_EOC)
+			return 0;
+
+		usleep_range(VADC_CONV_TIME_MIN_US, VADC_CONV_TIME_MAX_US);
+	}
+
+	vadc_show_status(vadc);
+
+	return -ETIMEDOUT;
+}
+
+static int vadc_read_result(struct vadc_priv *vadc, u16 *data)
+{
+	int ret;
+
+	ret = regmap_bulk_read(vadc->regmap, vadc->base + VADC_DATA, data, 2);
+	if (ret)
+		return ret;
+
+	*data = clamp_t(u16, *data, VADC_MIN_ADC_CODE, VADC_MAX_ADC_CODE);
+
+	return 0;
+}
+
+static struct vadc_channel_prop *vadc_get_channel(struct vadc_priv *vadc,
+						  unsigned int num)
+{
+	unsigned int i;
+
+	for (i = 0; i < vadc->nchannels; i++)
+		if (vadc->chan_props[i].channel == num)
+			return &vadc->chan_props[i];
+
+	dev_dbg(vadc->dev, "no such channel %02x\n", num);
+
+	return NULL;
+}
+
+static int vadc_do_conversion(struct vadc_priv *vadc,
+			      struct vadc_channel_prop *prop, u16 *data)
+{
+	unsigned int timeout;
+	int ret;
+
+	mutex_lock(&vadc->lock);
+
+	ret = vadc_configure(vadc, prop);
+	if (ret)
+		goto unlock;
+
+	if (!vadc->poll_eoc)
+		reinit_completion(&vadc->complete);
+
+	ret = vadc_set_state(vadc, true);
+	if (ret)
+		goto unlock;
+
+	ret = vadc_write(vadc, VADC_CONV_REQ, VADC_CONV_REQ_SET);
+	if (ret)
+		goto err_disable;
+
+	timeout = BIT(prop->avg_samples) * VADC_CONV_TIME_MIN_US * 2;
+
+	if (vadc->poll_eoc) {
+		ret = vadc_poll_wait_eoc(vadc, timeout);
+	} else {
+		ret = wait_for_completion_timeout(&vadc->complete, timeout);
+		if (!ret) {
+			ret = -ETIMEDOUT;
+			goto err_disable;
+		}
+
+		/* Double check conversion status */
+		ret = vadc_poll_wait_eoc(vadc, VADC_CONV_TIME_MIN_US);
+		if (ret)
+			goto err_disable;
+	}
+
+	ret = vadc_read_result(vadc, data);
+
+err_disable:
+	vadc_set_state(vadc, false);
+	if (ret)
+		dev_err(vadc->dev, "conversion failed\n");
+unlock:
+	mutex_unlock(&vadc->lock);
+	return ret;
+}
+
+static int vadc_measure_ref_points(struct vadc_priv *vadc)
+{
+	struct vadc_channel_prop *prop;
+	u16 read_1, read_2;
+	int ret;
+
+	vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE_UV;
+	vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV;
+
+	prop = vadc_get_channel(vadc, VADC_REF_1250MV);
+	ret = vadc_do_conversion(vadc, prop, &read_1);
+	if (ret)
+		goto err;
+
+	/* Try with buffered 625mV channel first */
+	prop = vadc_get_channel(vadc, VADC_SPARE1);
+	if (!prop)
+		prop = vadc_get_channel(vadc, VADC_REF_625MV);
+
+	ret = vadc_do_conversion(vadc, prop, &read_2);
+	if (ret)
+		goto err;
+
+	if (read_1 == read_2) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	vadc->graph[VADC_CALIB_ABSOLUTE].dy = read_1 - read_2;
+	vadc->graph[VADC_CALIB_ABSOLUTE].gnd = read_2;
+
+	/* Ratiometric calibration */
+	prop = vadc_get_channel(vadc, VADC_VDD_VADC);
+	ret = vadc_do_conversion(vadc, prop, &read_1);
+	if (ret)
+		goto err;
+
+	prop = vadc_get_channel(vadc, VADC_GND_REF);
+	ret = vadc_do_conversion(vadc, prop, &read_2);
+	if (ret)
+		goto err;
+
+	if (read_1 == read_2) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	vadc->graph[VADC_CALIB_RATIOMETRIC].dy = read_1 - read_2;
+	vadc->graph[VADC_CALIB_RATIOMETRIC].gnd = read_2;
+err:
+	if (ret)
+		dev_err(vadc->dev, "measure reference points failed\n");
+
+	return ret;
+}
+
+static s32 vadc_calibrate(struct vadc_priv *vadc,
+			  const struct vadc_channel_prop *prop, u16 adc_code)
+{
+	const struct vadc_prescale_ratio *prescale;
+	s32 voltage;
+
+	voltage = adc_code - vadc->graph[prop->calibration].gnd;
+	voltage *= vadc->graph[prop->calibration].dx;
+	voltage = voltage / vadc->graph[prop->calibration].dy;
+
+	if (prop->calibration == VADC_CALIB_ABSOLUTE)
+		voltage += vadc->graph[prop->calibration].dx;
+
+	if (voltage < 0)
+		voltage = 0;
+
+	prescale = &vadc_prescale_ratios[prop->prescale];
+
+	voltage = voltage * prescale->den;
+
+	return voltage / prescale->num;
+}
+
+static int vadc_decimation_from_dt(u32 value)
+{
+	if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
+	    value > VADC_DECIMATION_MAX)
+		return -EINVAL;
+
+	return __ffs64(value / VADC_DECIMATION_MIN);
+}
+
+static int vadc_prescaling_from_dt(u32 num, u32 den)
+{
+	unsigned int pre;
+
+	for (pre = 0; pre < ARRAY_SIZE(vadc_prescale_ratios); pre++)
+		if (vadc_prescale_ratios[pre].num == num &&
+		    vadc_prescale_ratios[pre].den == den)
+			break;
+
+	if (pre == ARRAY_SIZE(vadc_prescale_ratios))
+		return -EINVAL;
+
+	return pre;
+}
+
+static int vadc_hw_settle_time_from_dt(u32 value)
+{
+	if ((value <= 1000 && value % 100) || (value > 1000 && value % 2000))
+		return -EINVAL;
+
+	if (value <= 1000)
+		value /= 100;
+	else
+		value = value / 2000 + 10;
+
+	return value;
+}
+
+static int vadc_avg_samples_from_dt(u32 value)
+{
+	if (!is_power_of_2(value) || value > VADC_AVG_SAMPLES_MAX)
+		return -EINVAL;
+
+	return __ffs64(value);
+}
+
+static int vadc_read_raw(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan, int *val, int *val2,
+			 long mask)
+{
+	struct vadc_priv *vadc = iio_priv(indio_dev);
+	struct vadc_channel_prop *prop;
+	u16 adc_code;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		prop = &vadc->chan_props[chan->address];
+		ret = vadc_do_conversion(vadc, prop, &adc_code);
+		if (ret)
+			break;
+
+		*val = vadc_calibrate(vadc, prop, adc_code);
+
+		/* 2mV/K, return milli Celsius */
+		*val /= 2;
+		*val -= KELVINMIL_CELSIUSMIL;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_RAW:
+		prop = &vadc->chan_props[chan->address];
+		ret = vadc_do_conversion(vadc, prop, &adc_code);
+		if (ret)
+			break;
+
+		*val = vadc_calibrate(vadc, prop, adc_code);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int vadc_of_xlate(struct iio_dev *indio_dev,
+			 const struct of_phandle_args *iiospec)
+{
+	struct vadc_priv *vadc = iio_priv(indio_dev);
+	unsigned int i;
+
+	for (i = 0; i < vadc->nchannels; i++)
+		if (vadc->iio_chans[i].channel == iiospec->args[0])
+			return i;
+
+	return -EINVAL;
+}
+
+static const struct iio_info vadc_info = {
+	.read_raw = vadc_read_raw,
+	.of_xlate = vadc_of_xlate,
+	.driver_module = THIS_MODULE,
+};
+
+struct vadc_channels {
+	const char *datasheet_name;
+	unsigned int prescale_index;
+	enum iio_chan_type type;
+	long info_mask;
+};
+
+#define VADC_CHAN(_dname, _type, _mask, _pre)				\
+	[VADC_##_dname] = {						\
+		.datasheet_name = __stringify(_dname),			\
+		.prescale_index = _pre,					\
+		.type = _type,						\
+		.info_mask = _mask					\
+	},								\
+
+#define VADC_CHAN_TEMP(_dname, _pre)					\
+	VADC_CHAN(_dname, IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre)	\
+
+#define VADC_CHAN_VOLT(_dname, _pre)					\
+	VADC_CHAN(_dname, IIO_VOLTAGE,					\
+		  BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),	\
+		  _pre)							\
+
+/*
+ * The array represents all possible ADC channels found in the supported PMICs.
+ * Every index in the array is equal to the channel number per datasheet. The
+ * gaps in the array should be treated as reserved channels.
+ */
+static const struct vadc_channels vadc_chans[] = {
+	VADC_CHAN_VOLT(USBIN, 4)
+	VADC_CHAN_VOLT(DCIN, 4)
+	VADC_CHAN_VOLT(VCHG_SNS, 3)
+	VADC_CHAN_VOLT(SPARE1_03, 1)
+	VADC_CHAN_VOLT(USB_ID_MV, 1)
+	VADC_CHAN_VOLT(VCOIN, 1)
+	VADC_CHAN_VOLT(VBAT_SNS, 1)
+	VADC_CHAN_VOLT(VSYS, 1)
+	VADC_CHAN_TEMP(DIE_TEMP, 0)
+	VADC_CHAN_VOLT(REF_625MV, 0)
+	VADC_CHAN_VOLT(REF_1250MV, 0)
+	VADC_CHAN_VOLT(CHG_TEMP, 0)
+	VADC_CHAN_VOLT(SPARE1, 0)
+	VADC_CHAN_VOLT(SPARE2, 0)
+	VADC_CHAN_VOLT(GND_REF, 0)
+	VADC_CHAN_VOLT(VDD_VADC, 0)
+
+	VADC_CHAN_VOLT(P_MUX1_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX2_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX3_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX4_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX5_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX6_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX7_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX8_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX9_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX10_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX11_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX12_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX13_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX14_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX15_1_1, 0)
+	VADC_CHAN_VOLT(P_MUX16_1_1, 0)
+
+	VADC_CHAN_VOLT(P_MUX1_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX2_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX3_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX4_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX5_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX6_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX7_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX8_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX9_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX10_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX11_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX12_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX13_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX14_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX15_1_3, 1)
+	VADC_CHAN_VOLT(P_MUX16_1_3, 1)
+
+	VADC_CHAN_VOLT(LR_MUX1_BAT_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_XO_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX4_AMUX_THM1, 0)
+	VADC_CHAN_VOLT(LR_MUX5_AMUX_THM2, 0)
+	VADC_CHAN_VOLT(LR_MUX6_AMUX_THM3, 0)
+	VADC_CHAN_VOLT(LR_MUX7_HW_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX8_AMUX_THM4, 0)
+	VADC_CHAN_VOLT(LR_MUX9_AMUX_THM5, 0)
+	VADC_CHAN_VOLT(LR_MUX10_USB_ID, 0)
+	VADC_CHAN_VOLT(AMUX_PU1, 0)
+	VADC_CHAN_VOLT(AMUX_PU2, 0)
+	VADC_CHAN_VOLT(LR_MUX3_BUF_XO_THERM, 0)
+
+	VADC_CHAN_VOLT(LR_MUX1_PU1_BAT_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX2_PU1_BAT_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_PU1_XO_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX4_PU1_AMUX_THM1, 0)
+	VADC_CHAN_VOLT(LR_MUX5_PU1_AMUX_THM2, 0)
+	VADC_CHAN_VOLT(LR_MUX6_PU1_AMUX_THM3, 0)
+	VADC_CHAN_VOLT(LR_MUX7_PU1_AMUX_HW_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX8_PU1_AMUX_THM4, 0)
+	VADC_CHAN_VOLT(LR_MUX9_PU1_AMUX_THM5, 0)
+	VADC_CHAN_VOLT(LR_MUX10_PU1_AMUX_USB_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_XO_THERM, 0)
+
+	VADC_CHAN_VOLT(LR_MUX1_PU2_BAT_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX2_PU2_BAT_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_PU2_XO_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX4_PU2_AMUX_THM1, 0)
+	VADC_CHAN_VOLT(LR_MUX5_PU2_AMUX_THM2, 0)
+	VADC_CHAN_VOLT(LR_MUX6_PU2_AMUX_THM3, 0)
+	VADC_CHAN_VOLT(LR_MUX7_PU2_AMUX_HW_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX8_PU2_AMUX_THM4, 0)
+	VADC_CHAN_VOLT(LR_MUX9_PU2_AMUX_THM5, 0)
+	VADC_CHAN_VOLT(LR_MUX10_PU2_AMUX_USB_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_BUF_PU2_XO_THERM, 0)
+
+	VADC_CHAN_VOLT(LR_MUX1_PU1_PU2_BAT_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX2_PU1_PU2_BAT_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_PU1_PU2_XO_THERM, 0)
+	VADC_CHAN_VOLT(LR_MUX4_PU1_PU2_AMUX_THM1, 0)
+	VADC_CHAN_VOLT(LR_MUX5_PU1_PU2_AMUX_THM2, 0)
+	VADC_CHAN_VOLT(LR_MUX6_PU1_PU2_AMUX_THM3, 0)
+	VADC_CHAN_VOLT(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX8_PU1_PU2_AMUX_THM4, 0)
+	VADC_CHAN_VOLT(LR_MUX9_PU1_PU2_AMUX_THM5, 0)
+	VADC_CHAN_VOLT(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0)
+	VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0)
+};
+
+static int vadc_get_dt_channel_data(struct device *dev,
+				    struct vadc_channel_prop *prop,
+				    struct device_node *node)
+{
+	const char *name = node->name;
+	u32 chan, value, varr[2];
+	int ret;
+
+	ret = of_property_read_u32(node, "reg", &chan);
+	if (ret) {
+		dev_err(dev, "invalid channel number %s\n", name);
+		return ret;
+	}
+
+	if (chan > VADC_CHAN_MAX || chan < VADC_CHAN_MIN) {
+		dev_err(dev, "%s invalid channel number %d\n", name, chan);
+		return -EINVAL;
+	}
+
+	/* the channel has DT description */
+	prop->channel = chan;
+
+	ret = of_property_read_u32(node, "qcom,decimation", &value);
+	if (!ret) {
+		ret = vadc_decimation_from_dt(value);
+		if (ret < 0) {
+			dev_err(dev, "%02x invalid decimation %d\n",
+				chan, value);
+			return ret;
+		}
+		prop->decimation = ret;
+	} else {
+		prop->decimation = VADC_DEF_DECIMATION;
+	}
+
+	ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
+	if (!ret) {
+		ret = vadc_prescaling_from_dt(varr[0], varr[1]);
+		if (ret < 0) {
+			dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
+				chan, varr[0], varr[1]);
+			return ret;
+		}
+		prop->prescale = ret;
+	} else {
+		prop->prescale = vadc_chans[prop->channel].prescale_index;
+	}
+
+	ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
+	if (!ret) {
+		ret = vadc_hw_settle_time_from_dt(value);
+		if (ret < 0) {
+			dev_err(dev, "%02x invalid hw-settle-time %d us\n",
+				chan, value);
+			return ret;
+		}
+		prop->hw_settle_time = ret;
+	} else {
+		prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
+	}
+
+	ret = of_property_read_u32(node, "qcom,avg-samples", &value);
+	if (!ret) {
+		ret = vadc_avg_samples_from_dt(value);
+		if (ret < 0) {
+			dev_err(dev, "%02x invalid avg-samples %d\n",
+				chan, value);
+			return ret;
+		}
+		prop->avg_samples = ret;
+	} else {
+		prop->avg_samples = VADC_DEF_AVG_SAMPLES;
+	}
+
+	if (of_property_read_bool(node, "qcom,ratiometric"))
+		prop->calibration = VADC_CALIB_RATIOMETRIC;
+	else
+		prop->calibration = VADC_CALIB_ABSOLUTE;
+
+	dev_dbg(dev, "%02x name %s\n", chan, name);
+
+	return 0;
+}
+
+static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
+{
+	const struct vadc_channels *vadc_chan;
+	struct iio_chan_spec *iio_chan;
+	struct vadc_channel_prop prop;
+	struct device_node *child;
+	unsigned int index = 0;
+	int ret;
+
+	vadc->nchannels = of_get_available_child_count(node);
+	if (!vadc->nchannels)
+		return -EINVAL;
+
+	vadc->iio_chans = devm_kcalloc(vadc->dev, vadc->nchannels,
+				       sizeof(*vadc->iio_chans), GFP_KERNEL);
+	if (!vadc->iio_chans)
+		return -ENOMEM;
+
+	vadc->chan_props = devm_kcalloc(vadc->dev, vadc->nchannels,
+					sizeof(*vadc->chan_props), GFP_KERNEL);
+	if (!vadc->chan_props)
+		return -ENOMEM;
+
+	iio_chan = vadc->iio_chans;
+
+	for_each_available_child_of_node(node, child) {
+		ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
+		if (ret)
+			return ret;
+
+		vadc->chan_props[index] = prop;
+
+		vadc_chan = &vadc_chans[prop.channel];
+
+		iio_chan->channel = prop.channel;
+		iio_chan->datasheet_name = vadc_chan->datasheet_name;
+		iio_chan->info_mask_separate = vadc_chan->info_mask;
+		iio_chan->type = vadc_chan->type;
+		iio_chan->indexed = 1;
+		iio_chan->address = index++;
+
+		iio_chan++;
+	}
+
+	/* These channels are mandatory, they are used as reference points */
+	if (!vadc_get_channel(vadc, VADC_REF_1250MV)) {
+		dev_err(vadc->dev, "Please define 1.25V channel\n");
+		return -ENODEV;
+	}
+
+	if (!vadc_get_channel(vadc, VADC_REF_625MV)) {
+		dev_err(vadc->dev, "Please define 0.625V channel\n");
+		return -ENODEV;
+	}
+
+	if (!vadc_get_channel(vadc, VADC_VDD_VADC)) {
+		dev_err(vadc->dev, "Please define VDD channel\n");
+		return -ENODEV;
+	}
+
+	if (!vadc_get_channel(vadc, VADC_GND_REF)) {
+		dev_err(vadc->dev, "Please define GND channel\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static irqreturn_t vadc_isr(int irq, void *dev_id)
+{
+	struct vadc_priv *vadc = dev_id;
+
+	complete(&vadc->complete);
+
+	return IRQ_HANDLED;
+}
+
+static int vadc_check_revision(struct vadc_priv *vadc)
+{
+	u8 val;
+	int ret;
+
+	ret = vadc_read(vadc, VADC_PERPH_TYPE, &val);
+	if (ret)
+		return ret;
+
+	if (val < VADC_PERPH_TYPE_ADC) {
+		dev_err(vadc->dev, "%d is not ADC\n", val);
+		return -ENODEV;
+	}
+
+	ret = vadc_read(vadc, VADC_PERPH_SUBTYPE, &val);
+	if (ret)
+		return ret;
+
+	if (val < VADC_PERPH_SUBTYPE_VADC) {
+		dev_err(vadc->dev, "%d is not VADC\n", val);
+		return -ENODEV;
+	}
+
+	ret = vadc_read(vadc, VADC_REVISION2, &val);
+	if (ret)
+		return ret;
+
+	if (val < VADC_REVISION2_SUPPORTED_VADC) {
+		dev_err(vadc->dev, "revision %d not supported\n", val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int vadc_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct iio_dev *indio_dev;
+	struct vadc_priv *vadc;
+	struct regmap *regmap;
+	int ret, irq_eoc;
+	u32 reg;
+
+	regmap = dev_get_regmap(dev->parent, NULL);
+	if (!regmap)
+		return -ENODEV;
+
+	ret = of_property_read_u32(node, "reg", &reg);
+	if (ret < 0)
+		return ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*vadc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	vadc = iio_priv(indio_dev);
+	vadc->regmap = regmap;
+	vadc->dev = dev;
+	vadc->base = reg;
+	vadc->are_ref_measured = false;
+	init_completion(&vadc->complete);
+	mutex_init(&vadc->lock);
+
+	ret = vadc_check_revision(vadc);
+	if (ret)
+		return ret;
+
+	ret = vadc_get_dt_data(vadc, node);
+	if (ret)
+		return ret;
+
+	irq_eoc = platform_get_irq(pdev, 0);
+	if (irq_eoc < 0) {
+		if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
+			return irq_eoc;
+		vadc->poll_eoc = true;
+	} else {
+		ret = devm_request_irq(dev, irq_eoc, vadc_isr, 0,
+				       "spmi-vadc", vadc);
+		if (ret)
+			return ret;
+	}
+
+	ret = vadc_reset(vadc);
+	if (ret) {
+		dev_err(dev, "reset failed\n");
+		return ret;
+	}
+
+	ret = vadc_measure_ref_points(vadc);
+	if (ret)
+		return ret;
+
+	indio_dev->dev.parent = dev;
+	indio_dev->dev.of_node = node;
+	indio_dev->name = pdev->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &vadc_info;
+	indio_dev->channels = vadc->iio_chans;
+	indio_dev->num_channels = vadc->nchannels;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id vadc_match_table[] = {
+	{ .compatible = "qcom,spmi-vadc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, vadc_match_table);
+
+static struct platform_driver vadc_driver = {
+	.driver = {
+		   .name = "qcom-spmi-vadc",
+		   .of_match_table = vadc_match_table,
+	},
+	.probe = vadc_probe,
+};
+module_platform_driver(vadc_driver);
+
+MODULE_ALIAS("platform:qcom-spmi-vadc");
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC voltage ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
+MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index adba232..2e5cc44 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -249,7 +249,7 @@
 	struct iio_buffer *buffer;
 	int ret;
 
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (!buffer)
 		return -ENOMEM;
 
@@ -263,16 +263,8 @@
 	indio_dev->setup_ops = setup_ops;
 	indio_dev->modes |= INDIO_BUFFER_HARDWARE;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_free_irq;
-
 	return 0;
 
-error_free_irq:
-	free_irq(irq, indio_dev);
 error_kfifo_free:
 	iio_kfifo_free(indio_dev->buffer);
 	return ret;
@@ -284,7 +276,6 @@
 
 	free_irq(adc_dev->mfd_tscadc->irq, indio_dev);
 	iio_kfifo_free(indio_dev->buffer);
-	iio_buffer_unregister(indio_dev);
 }
 
 
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index ba6f6a9..c0d364e 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -31,7 +31,7 @@
 };
 
 static int ad8366_write(struct iio_dev *indio_dev,
-			unsigned char ch_a, char unsigned ch_b)
+			unsigned char ch_a, unsigned char ch_b)
 {
 	struct ad8366_state *st = iio_priv(indio_dev);
 	int ret;
@@ -166,7 +166,7 @@
 	if (ret)
 		goto error_disable_reg;
 
-	ad8366_write(indio_dev, 0 , 0);
+	ad8366_write(indio_dev, 0, 0);
 
 	return 0;
 
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 0b6e97d1..790f106 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,4 +3,5 @@
 #
 
 source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/ssp_sensors/Kconfig"
 source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index 3112df0..b1e4d9c 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,4 +8,5 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-y += hid-sensors/
+obj-y += ssp_sensors/
 obj-y += st_sensors/
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 92068cd..2f1d535b 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -22,16 +22,18 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/hid-sensor-hub.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
 #include <linux/iio/sysfs.h>
 #include "hid-sensor-trigger.h"
 
-int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
+static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 {
 	int state_val;
 	int report_val;
+	s32 poll_value = 0;
 
 	if (state) {
 		if (sensor_hub_device_open(st->hsdev))
@@ -47,6 +49,8 @@
 			st->report_state.report_id,
 			st->report_state.index,
 			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
+
+		poll_value = hid_sensor_read_poll_value(st);
 	} else {
 		if (!atomic_dec_and_test(&st->data_ready))
 			return 0;
@@ -78,10 +82,36 @@
 	sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
 					st->power_state.index,
 					&state_val);
+	if (state && poll_value)
+		msleep_interruptible(poll_value * 2);
+
 	return 0;
 }
 EXPORT_SYMBOL(hid_sensor_power_state);
 
+int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (state)
+		ret = pm_runtime_get_sync(&st->pdev->dev);
+	else {
+		pm_runtime_mark_last_busy(&st->pdev->dev);
+		ret = pm_runtime_put_autosuspend(&st->pdev->dev);
+	}
+	if (ret < 0) {
+		if (state)
+			pm_runtime_put_noidle(&st->pdev->dev);
+		return ret;
+	}
+
+ 	return 0;
+#else
+	return _hid_sensor_power_state(st, state);
+#endif
+}
+
 static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
 						bool state)
 {
@@ -125,8 +155,21 @@
 	attrb->trigger = trig;
 	indio_dev->trig = iio_trigger_get(trig);
 
-	return ret;
+	ret = pm_runtime_set_active(&indio_dev->dev);
+	if (ret)
+		goto error_unreg_trigger;
 
+	iio_device_set_drvdata(indio_dev, attrb);
+	pm_suspend_ignore_children(&attrb->pdev->dev, true);
+	pm_runtime_enable(&attrb->pdev->dev);
+	/* Default to 3 seconds, but can be changed from sysfs */
+	pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
+					 3000);
+	pm_runtime_use_autosuspend(&attrb->pdev->dev);
+
+	return ret;
+error_unreg_trigger:
+	iio_trigger_unregister(trig);
 error_free_trig:
 	iio_trigger_free(trig);
 error_ret:
@@ -134,6 +177,34 @@
 }
 EXPORT_SYMBOL(hid_sensor_setup_trigger);
 
+#ifdef CONFIG_PM
+static int hid_sensor_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
+	return _hid_sensor_power_state(attrb, false);
+}
+
+static int hid_sensor_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
+	return _hid_sensor_power_state(attrb, true);
+}
+
+#endif
+
+const struct dev_pm_ops hid_sensor_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
+	SET_RUNTIME_PM_OPS(hid_sensor_suspend,
+			   hid_sensor_resume, NULL)
+};
+EXPORT_SYMBOL(hid_sensor_pm_ops);
+
 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
 MODULE_DESCRIPTION("HID Sensor trigger processing");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index 0f8e78c..9f4713f 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -19,6 +19,11 @@
 #ifndef _HID_SENSOR_TRIGGER_H
 #define _HID_SENSOR_TRIGGER_H
 
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+extern const struct dev_pm_ops hid_sensor_pm_ops;
+
 int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
 				struct hid_sensor_common *attrb);
 void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
diff --git a/drivers/iio/common/ssp_sensors/Kconfig b/drivers/iio/common/ssp_sensors/Kconfig
new file mode 100644
index 0000000..0ea4faf
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Kconfig
@@ -0,0 +1,26 @@
+#
+# SSP sensor drivers and commons configuration
+#
+menu "SSP Sensor Common"
+
+config IIO_SSP_SENSORS_COMMONS
+	tristate "Commons for all SSP Sensor IIO drivers"
+	depends on IIO_SSP_SENSORHUB
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	help
+	  Say yes here to build commons for SSP sensors.
+	  To compile this as a module, choose M here: the module
+	  will be called ssp_iio.
+
+config IIO_SSP_SENSORHUB
+	tristate "Samsung Sensorhub driver"
+	depends on SPI
+	select MFD_CORE
+	help
+	  SSP driver for sensorhub.
+	  If you say yes here you get ssp support for sensorhub.
+	  To compile this driver as a module, choose M here: the
+	  module will be called sensorhub.
+
+endmenu
diff --git a/drivers/iio/common/ssp_sensors/Makefile b/drivers/iio/common/ssp_sensors/Makefile
new file mode 100644
index 0000000..1e0389e
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for SSP sensor drivers and commons.
+#
+
+sensorhub-objs				:= ssp_dev.o ssp_spi.o
+obj-$(CONFIG_IIO_SSP_SENSORHUB)		+= sensorhub.o
+
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) 	+= ssp_iio.o
diff --git a/drivers/iio/common/ssp_sensors/ssp.h b/drivers/iio/common/ssp_sensors/ssp.h
new file mode 100644
index 0000000..b910e91
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp.h
@@ -0,0 +1,257 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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 __SSP_SENSORHUB_H__
+#define __SSP_SENSORHUB_H__
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/spi/spi.h>
+
+#define SSP_DEVICE_ID		0x55
+
+#ifdef SSP_DBG
+#define ssp_dbg(format, ...) pr_info("[SSP] "format, ##__VA_ARGS__)
+#else
+#define ssp_dbg(format, ...)
+#endif
+
+#define SSP_SW_RESET_TIME		3000
+/* Sensor polling in ms */
+#define SSP_DEFAULT_POLLING_DELAY	200
+#define SSP_DEFAULT_RETRIES		3
+#define SSP_DATA_PACKET_SIZE		960
+#define SSP_HEADER_BUFFER_SIZE		4
+
+enum {
+	SSP_KERNEL_BINARY = 0,
+	SSP_KERNEL_CRASHED_BINARY,
+};
+
+enum {
+	SSP_INITIALIZATION_STATE = 0,
+	SSP_NO_SENSOR_STATE,
+	SSP_ADD_SENSOR_STATE,
+	SSP_RUNNING_SENSOR_STATE,
+};
+
+/* Firmware download STATE */
+enum {
+	SSP_FW_DL_STATE_FAIL = -1,
+	SSP_FW_DL_STATE_NONE = 0,
+	SSP_FW_DL_STATE_NEED_TO_SCHEDULE,
+	SSP_FW_DL_STATE_SCHEDULED,
+	SSP_FW_DL_STATE_DOWNLOADING,
+	SSP_FW_DL_STATE_SYNC,
+	SSP_FW_DL_STATE_DONE,
+};
+
+#define SSP_INVALID_REVISION			99999
+#define SSP_INVALID_REVISION2			0xffffff
+
+/* AP -> SSP Instruction */
+#define SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD	0xa1
+#define SSP_MSG2SSP_INST_BYPASS_SENSOR_RM	0xa2
+#define SSP_MSG2SSP_INST_REMOVE_ALL		0xa3
+#define SSP_MSG2SSP_INST_CHANGE_DELAY		0xa4
+#define SSP_MSG2SSP_INST_LIBRARY_ADD		0xb1
+#define SSP_MSG2SSP_INST_LIBRARY_REMOVE		0xb2
+#define SSP_MSG2SSP_INST_LIB_NOTI		0xb4
+#define SSP_MSG2SSP_INST_LIB_DATA		0xc1
+
+#define SSP_MSG2SSP_AP_MCU_SET_GYRO_CAL		0xcd
+#define SSP_MSG2SSP_AP_MCU_SET_ACCEL_CAL	0xce
+#define SSP_MSG2SSP_AP_STATUS_SHUTDOWN		0xd0
+#define SSP_MSG2SSP_AP_STATUS_WAKEUP		0xd1
+#define SSP_MSG2SSP_AP_STATUS_SLEEP		0xd2
+#define SSP_MSG2SSP_AP_STATUS_RESUME		0xd3
+#define SSP_MSG2SSP_AP_STATUS_SUSPEND		0xd4
+#define SSP_MSG2SSP_AP_STATUS_RESET		0xd5
+#define SSP_MSG2SSP_AP_STATUS_POW_CONNECTED	0xd6
+#define SSP_MSG2SSP_AP_STATUS_POW_DISCONNECTED	0xd7
+#define SSP_MSG2SSP_AP_TEMPHUMIDITY_CAL_DONE	0xda
+#define SSP_MSG2SSP_AP_MCU_SET_DUMPMODE		0xdb
+#define SSP_MSG2SSP_AP_MCU_DUMP_CHECK		0xdc
+#define SSP_MSG2SSP_AP_MCU_BATCH_FLUSH		0xdd
+#define SSP_MSG2SSP_AP_MCU_BATCH_COUNT		0xdf
+
+#define SSP_MSG2SSP_AP_WHOAMI				0x0f
+#define SSP_MSG2SSP_AP_FIRMWARE_REV			0xf0
+#define SSP_MSG2SSP_AP_SENSOR_FORMATION			0xf1
+#define SSP_MSG2SSP_AP_SENSOR_PROXTHRESHOLD		0xf2
+#define SSP_MSG2SSP_AP_SENSOR_BARCODE_EMUL		0xf3
+#define SSP_MSG2SSP_AP_SENSOR_SCANNING			0xf4
+#define SSP_MSG2SSP_AP_SET_MAGNETIC_HWOFFSET		0xf5
+#define SSP_MSG2SSP_AP_GET_MAGNETIC_HWOFFSET		0xf6
+#define SSP_MSG2SSP_AP_SENSOR_GESTURE_CURRENT		0xf7
+#define SSP_MSG2SSP_AP_GET_THERM			0xf8
+#define SSP_MSG2SSP_AP_GET_BIG_DATA			0xf9
+#define SSP_MSG2SSP_AP_SET_BIG_DATA			0xfa
+#define SSP_MSG2SSP_AP_START_BIG_DATA			0xfb
+#define SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX	0xfd
+#define SSP_MSG2SSP_AP_SENSOR_TILT			0xea
+#define SSP_MSG2SSP_AP_MCU_SET_TIME			0xfe
+#define SSP_MSG2SSP_AP_MCU_GET_TIME			0xff
+
+#define SSP_MSG2SSP_AP_FUSEROM				0x01
+
+/* voice data */
+#define SSP_TYPE_WAKE_UP_VOICE_SERVICE			0x01
+#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_AM		0x01
+#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_GRAMMER	0x02
+
+/* Factory Test */
+#define SSP_ACCELEROMETER_FACTORY			0x80
+#define SSP_GYROSCOPE_FACTORY				0x81
+#define SSP_GEOMAGNETIC_FACTORY				0x82
+#define SSP_PRESSURE_FACTORY				0x85
+#define SSP_GESTURE_FACTORY				0x86
+#define SSP_TEMPHUMIDITY_CRC_FACTORY			0x88
+#define SSP_GYROSCOPE_TEMP_FACTORY			0x8a
+#define SSP_GYROSCOPE_DPS_FACTORY			0x8b
+#define SSP_MCU_FACTORY					0x8c
+#define SSP_MCU_SLEEP_FACTORY				0x8d
+
+/* SSP -> AP ACK about write CMD */
+#define SSP_MSG_ACK		0x80	/* ACK from SSP to AP */
+#define SSP_MSG_NAK		0x70	/* NAK from SSP to AP */
+
+struct ssp_sensorhub_info {
+	char *fw_name;
+	char *fw_crashed_name;
+	unsigned int fw_rev;
+	const u8 * const mag_table;
+	const unsigned int mag_length;
+};
+
+/* ssp_msg options bit */
+#define SSP_RW		0
+#define SSP_INDEX	3
+
+#define SSP_AP2HUB_READ		0
+#define SSP_AP2HUB_WRITE	1
+#define SSP_HUB2AP_WRITE	2
+#define SSP_AP2HUB_READY	3
+#define SSP_AP2HUB_RETURN	4
+
+/**
+ * struct ssp_data - ssp platformdata structure
+ * @spi:		spi device
+ * @sensorhub_info:	info about sensorhub board specific features
+ * @wdt_timer:		watchdog timer
+ * @work_wdt:		watchdog work
+ * @work_firmware:	firmware upgrade work queue
+ * @work_refresh:	refresh work queue for reset request from MCU
+ * @shut_down:		shut down flag
+ * @mcu_dump_mode:	mcu dump mode for debug
+ * @time_syncing:	time syncing indication flag
+ * @timestamp:		previous time in ns calculated for time syncing
+ * @check_status:	status table for each sensor
+ * @com_fail_cnt:	communication fail count
+ * @reset_cnt:		reset count
+ * @timeout_cnt:	timeout count
+ * @available_sensors:	available sensors seen by sensorhub (bit array)
+ * @cur_firm_rev:	cached current firmware revision
+ * @last_resume_state:	last AP resume/suspend state used to handle the PM
+ *                      state of ssp
+ * @last_ap_state:	(obsolete) sleep notification for MCU
+ * @sensor_enable:	sensor enable mask
+ * @delay_buf:		data acquisition intervals table
+ * @batch_latency_buf:	yet unknown but existing in communication protocol
+ * @batch_opt_buf:	yet unknown but existing in communication protocol
+ * @accel_position:	yet unknown but existing in communication protocol
+ * @mag_position:	yet unknown but existing in communication protocol
+ * @fw_dl_state:	firmware download state
+ * @comm_lock:		lock protecting the handshake
+ * @pending_lock:	lock protecting pending list and completion
+ * @mcu_reset_gpio:	mcu reset line
+ * @ap_mcu_gpio:	ap to mcu gpio line
+ * @mcu_ap_gpio:	mcu to ap gpio line
+ * @pending_list:	pending list for messages queued to be sent/read
+ * @sensor_devs:	registered IIO devices table
+ * @enable_refcount:	enable reference count for wdt (watchdog timer)
+ * @header_buffer:	cache aligned buffer for packet header
+ */
+struct ssp_data {
+	struct spi_device *spi;
+	struct ssp_sensorhub_info *sensorhub_info;
+	struct timer_list wdt_timer;
+	struct work_struct work_wdt;
+	struct delayed_work work_refresh;
+
+	bool shut_down;
+	bool mcu_dump_mode;
+	bool time_syncing;
+	int64_t timestamp;
+
+	int check_status[SSP_SENSOR_MAX];
+
+	unsigned int com_fail_cnt;
+	unsigned int reset_cnt;
+	unsigned int timeout_cnt;
+
+	unsigned int available_sensors;
+	unsigned int cur_firm_rev;
+
+	char last_resume_state;
+	char last_ap_state;
+
+	unsigned int sensor_enable;
+	u32 delay_buf[SSP_SENSOR_MAX];
+	s32 batch_latency_buf[SSP_SENSOR_MAX];
+	s8 batch_opt_buf[SSP_SENSOR_MAX];
+
+	int accel_position;
+	int mag_position;
+	int fw_dl_state;
+
+	struct mutex comm_lock;
+	struct mutex pending_lock;
+
+	int mcu_reset_gpio;
+	int ap_mcu_gpio;
+	int mcu_ap_gpio;
+
+	struct list_head pending_list;
+
+	struct iio_dev *sensor_devs[SSP_SENSOR_MAX];
+	atomic_t enable_refcount;
+
+	__le16 header_buffer[SSP_HEADER_BUFFER_SIZE / sizeof(__le16)]
+		____cacheline_aligned;
+};
+
+void ssp_clean_pending_list(struct ssp_data *data);
+
+int ssp_command(struct ssp_data *data, char command, int arg);
+
+int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
+			 u8 *send_buf, u8 length);
+
+int ssp_irq_msg(struct ssp_data *data);
+
+int ssp_get_chipid(struct ssp_data *data);
+
+int ssp_set_magnetic_matrix(struct ssp_data *data);
+
+unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data);
+
+unsigned int ssp_get_firmware_rev(struct ssp_data *data);
+
+int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay);
+
+#endif /* __SSP_SENSORHUB_H__ */
diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c
new file mode 100644
index 0000000..52d7043
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_dev.c
@@ -0,0 +1,712 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include "ssp.h"
+
+#define SSP_WDT_TIME			10000
+#define SSP_LIMIT_RESET_CNT		20
+#define SSP_LIMIT_TIMEOUT_CNT		3
+
+/* It is possible that it is max clk rate for version 1.0 of bootcode */
+#define SSP_BOOT_SPI_HZ	400000
+
+/*
+ * These fields can look enigmatic but this structure is used mainly to flat
+ * some values and depends on command type.
+ */
+struct ssp_instruction {
+	__le32 a;
+	__le32 b;
+	u8 c;
+} __attribute__((__packed__));
+
+static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,
+	208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,
+	243, 13, 45, 250};
+
+static const struct ssp_sensorhub_info ssp_rinato_info = {
+	.fw_name = "ssp_B2.fw",
+	.fw_crashed_name = "ssp_crashed.fw",
+	.fw_rev = 14052300,
+	.mag_table = ssp_magnitude_table,
+	.mag_length = ARRAY_SIZE(ssp_magnitude_table),
+};
+
+static const struct ssp_sensorhub_info ssp_thermostat_info = {
+	.fw_name = "thermostat_B2.fw",
+	.fw_crashed_name = "ssp_crashed.fw",
+	.fw_rev = 14080600,
+	.mag_table = ssp_magnitude_table,
+	.mag_length = ARRAY_SIZE(ssp_magnitude_table),
+};
+
+static const struct mfd_cell sensorhub_sensor_devs[] = {
+	{
+		.name = "ssp-accelerometer",
+	},
+	{
+		.name = "ssp-gyroscope",
+	},
+};
+
+static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
+{
+	gpio_set_value(data->mcu_reset_gpio, 0);
+	usleep_range(1000, 1200);
+	gpio_set_value(data->mcu_reset_gpio, 1);
+	msleep(50);
+}
+
+static void ssp_sync_available_sensors(struct ssp_data *data)
+{
+	int i, ret;
+
+	for (i = 0; i < SSP_SENSOR_MAX; ++i) {
+		if (data->available_sensors & BIT(i)) {
+			ret = ssp_enable_sensor(data, i, data->delay_buf[i]);
+			if (ret < 0) {
+				dev_err(&data->spi->dev,
+					"Sync sensor nr: %d fail\n", i);
+				continue;
+			}
+		}
+	}
+
+	ret = ssp_command(data, SSP_MSG2SSP_AP_MCU_SET_DUMPMODE,
+			  data->mcu_dump_mode);
+	if (ret < 0)
+		dev_err(&data->spi->dev,
+			"SSP_MSG2SSP_AP_MCU_SET_DUMPMODE failed\n");
+}
+
+static void ssp_enable_mcu(struct ssp_data *data, bool enable)
+{
+	dev_info(&data->spi->dev, "current shutdown = %d, old = %d\n", enable,
+		 data->shut_down);
+
+	if (enable && data->shut_down) {
+		data->shut_down = false;
+		enable_irq(data->spi->irq);
+		enable_irq_wake(data->spi->irq);
+	} else if (!enable && !data->shut_down) {
+		data->shut_down = true;
+		disable_irq(data->spi->irq);
+		disable_irq_wake(data->spi->irq);
+	} else {
+		dev_warn(&data->spi->dev, "current shutdown = %d, old = %d\n",
+			 enable, data->shut_down);
+	}
+}
+
+/*
+ * This function is the first one which communicates with the mcu so it is
+ * possible that the first attempt will fail
+ */
+static int ssp_check_fwbl(struct ssp_data *data)
+{
+	int retries = 0;
+
+	while (retries++ < 5) {
+		data->cur_firm_rev = ssp_get_firmware_rev(data);
+		if (data->cur_firm_rev == SSP_INVALID_REVISION ||
+		    data->cur_firm_rev == SSP_INVALID_REVISION2) {
+			dev_warn(&data->spi->dev,
+				 "Invalid revision, trying %d time\n", retries);
+		} else {
+			break;
+		}
+	}
+
+	if (data->cur_firm_rev == SSP_INVALID_REVISION ||
+	    data->cur_firm_rev == SSP_INVALID_REVISION2) {
+		dev_err(&data->spi->dev, "SSP_INVALID_REVISION\n");
+		return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
+	}
+
+	dev_info(&data->spi->dev,
+		 "MCU Firm Rev : Old = %8u, New = %8u\n",
+		 data->cur_firm_rev,
+		 data->sensorhub_info->fw_rev);
+
+	if (data->cur_firm_rev != data->sensorhub_info->fw_rev)
+		return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
+
+	return SSP_FW_DL_STATE_NONE;
+}
+
+static void ssp_reset_mcu(struct ssp_data *data)
+{
+	ssp_enable_mcu(data, false);
+	ssp_clean_pending_list(data);
+	ssp_toggle_mcu_reset_gpio(data);
+	ssp_enable_mcu(data, true);
+}
+
+static void ssp_wdt_work_func(struct work_struct *work)
+{
+	struct ssp_data *data = container_of(work, struct ssp_data, work_wdt);
+
+	dev_err(&data->spi->dev, "%s - Sensor state: 0x%x, RC: %u, CC: %u\n",
+		__func__, data->available_sensors, data->reset_cnt,
+		data->com_fail_cnt);
+
+	ssp_reset_mcu(data);
+	data->com_fail_cnt = 0;
+	data->timeout_cnt = 0;
+}
+
+static void ssp_wdt_timer_func(unsigned long ptr)
+{
+	struct ssp_data *data = (struct ssp_data *)ptr;
+
+	switch (data->fw_dl_state) {
+	case SSP_FW_DL_STATE_FAIL:
+	case SSP_FW_DL_STATE_DOWNLOADING:
+	case SSP_FW_DL_STATE_SYNC:
+		goto _mod;
+	}
+
+	if (data->timeout_cnt > SSP_LIMIT_TIMEOUT_CNT ||
+	    data->com_fail_cnt > SSP_LIMIT_RESET_CNT)
+		queue_work(system_power_efficient_wq, &data->work_wdt);
+_mod:
+	mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
+}
+
+static void ssp_enable_wdt_timer(struct ssp_data *data)
+{
+	mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
+}
+
+static void ssp_disable_wdt_timer(struct ssp_data *data)
+{
+	del_timer_sync(&data->wdt_timer);
+	cancel_work_sync(&data->work_wdt);
+}
+
+/**
+ * ssp_get_sensor_delay() - gets sensor data acquisition period
+ * @data:	sensorhub structure
+ * @type:	SSP sensor type
+ *
+ * Returns acquisition period in ms
+ */
+u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)
+{
+	return data->delay_buf[type];
+}
+EXPORT_SYMBOL(ssp_get_sensor_delay);
+
+/**
+ * ssp_enable_sensor() - enables data acquisition for sensor
+ * @data:	sensorhub structure
+ * @type:	SSP sensor type
+ * @delay:	delay in ms
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
+		      u32 delay)
+{
+	int ret;
+	struct ssp_instruction to_send;
+
+	to_send.a = cpu_to_le32(delay);
+	to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
+	to_send.c = data->batch_opt_buf[type];
+
+	switch (data->check_status[type]) {
+	case SSP_INITIALIZATION_STATE:
+		/* do calibration step, now just enable */
+	case SSP_ADD_SENSOR_STATE:
+		ret = ssp_send_instruction(data,
+					   SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD,
+					   type,
+					   (u8 *)&to_send, sizeof(to_send));
+		if (ret < 0) {
+			dev_err(&data->spi->dev, "Enabling sensor failed\n");
+			data->check_status[type] = SSP_NO_SENSOR_STATE;
+			goto derror;
+		}
+
+		data->sensor_enable |= BIT(type);
+		data->check_status[type] = SSP_RUNNING_SENSOR_STATE;
+		break;
+	case SSP_RUNNING_SENSOR_STATE:
+		ret = ssp_send_instruction(data,
+					   SSP_MSG2SSP_INST_CHANGE_DELAY, type,
+					   (u8 *)&to_send, sizeof(to_send));
+		if (ret < 0) {
+			dev_err(&data->spi->dev,
+				"Changing sensor delay failed\n");
+			goto derror;
+		}
+		break;
+	default:
+		data->check_status[type] = SSP_ADD_SENSOR_STATE;
+		break;
+	}
+
+	data->delay_buf[type] = delay;
+
+	if (atomic_inc_return(&data->enable_refcount) == 1)
+		ssp_enable_wdt_timer(data);
+
+	return 0;
+
+derror:
+	return ret;
+}
+EXPORT_SYMBOL(ssp_enable_sensor);
+
+/**
+ * ssp_change_delay() - changes data acquisition for sensor
+ * @data:	sensorhub structure
+ * @type:	SSP sensor type
+ * @delay:	delay in ms
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
+		     u32 delay)
+{
+	int ret;
+	struct ssp_instruction to_send;
+
+	to_send.a = cpu_to_le32(delay);
+	to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
+	to_send.c = data->batch_opt_buf[type];
+
+	ret = ssp_send_instruction(data, SSP_MSG2SSP_INST_CHANGE_DELAY, type,
+				   (u8 *)&to_send, sizeof(to_send));
+	if (ret < 0) {
+		dev_err(&data->spi->dev, "Changing sensor delay failed\n");
+		return ret;
+	}
+
+	data->delay_buf[type] = delay;
+
+	return 0;
+}
+EXPORT_SYMBOL(ssp_change_delay);
+
+/**
+ * ssp_disable_sensor() - disables sensor
+ *
+ * @data:	sensorhub structure
+ * @type:	SSP sensor type
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)
+{
+	int ret;
+	__le32 command;
+
+	if (data->sensor_enable & BIT(type)) {
+		command = cpu_to_le32(data->delay_buf[type]);
+
+		ret = ssp_send_instruction(data,
+					   SSP_MSG2SSP_INST_BYPASS_SENSOR_RM,
+					   type, (u8 *)&command,
+					   sizeof(command));
+		if (ret < 0) {
+			dev_err(&data->spi->dev, "Remove sensor fail\n");
+			return ret;
+		}
+
+		data->sensor_enable &= ~BIT(type);
+	}
+
+	data->check_status[type] = SSP_ADD_SENSOR_STATE;
+
+	if (atomic_dec_and_test(&data->enable_refcount))
+		ssp_disable_wdt_timer(data);
+
+	return 0;
+}
+EXPORT_SYMBOL(ssp_disable_sensor);
+
+static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)
+{
+	struct ssp_data *data = dev_id;
+
+	/*
+	 * This wrapper is done to preserve error path for ssp_irq_msg, also
+	 * it is defined in different file.
+	 */
+	ssp_irq_msg(data);
+
+	return IRQ_HANDLED;
+}
+
+static int ssp_initialize_mcu(struct ssp_data *data)
+{
+	int ret;
+
+	ssp_clean_pending_list(data);
+
+	ret = ssp_get_chipid(data);
+	if (ret != SSP_DEVICE_ID) {
+		dev_err(&data->spi->dev, "%s - MCU %s ret = %d\n", __func__,
+			ret < 0 ? "is not working" : "identification failed",
+			ret);
+		return ret < 0 ? ret : -ENODEV;
+	}
+
+	dev_info(&data->spi->dev, "MCU device ID = %d\n", ret);
+
+	/*
+	 * needs clarification, for now do not want to export all transfer
+	 * methods to sensors' drivers
+	 */
+	ret = ssp_set_magnetic_matrix(data);
+	if (ret < 0) {
+		dev_err(&data->spi->dev,
+			"%s - ssp_set_magnetic_matrix failed\n", __func__);
+		return ret;
+	}
+
+	data->available_sensors = ssp_get_sensor_scanning_info(data);
+	if (data->available_sensors == 0) {
+		dev_err(&data->spi->dev,
+			"%s - ssp_get_sensor_scanning_info failed\n", __func__);
+		return -EIO;
+	}
+
+	data->cur_firm_rev = ssp_get_firmware_rev(data);
+	dev_info(&data->spi->dev, "MCU Firm Rev : New = %8u\n",
+		 data->cur_firm_rev);
+
+	return ssp_command(data, SSP_MSG2SSP_AP_MCU_DUMP_CHECK, 0);
+}
+
+/*
+ * sensorhub can request its reinitialization as some brutal and rare error
+ * handling. It can be requested from the MCU.
+ */
+static void ssp_refresh_task(struct work_struct *work)
+{
+	struct ssp_data *data = container_of((struct delayed_work *)work,
+					     struct ssp_data, work_refresh);
+
+	dev_info(&data->spi->dev, "refreshing\n");
+
+	data->reset_cnt++;
+
+	if (ssp_initialize_mcu(data) >= 0) {
+		ssp_sync_available_sensors(data);
+		if (data->last_ap_state != 0)
+			ssp_command(data, data->last_ap_state, 0);
+
+		if (data->last_resume_state != 0)
+			ssp_command(data, data->last_resume_state, 0);
+
+		data->timeout_cnt = 0;
+		data->com_fail_cnt = 0;
+	}
+}
+
+int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
+{
+	cancel_delayed_work_sync(&data->work_refresh);
+
+	return queue_delayed_work(system_power_efficient_wq,
+				  &data->work_refresh,
+				  msecs_to_jiffies(delay));
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id ssp_of_match[] = {
+	{
+		.compatible	= "samsung,sensorhub-rinato",
+		.data		= &ssp_rinato_info,
+	}, {
+		.compatible	= "samsung,sensorhub-thermostat",
+		.data		= &ssp_thermostat_info,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, ssp_of_match);
+
+static struct ssp_data *ssp_parse_dt(struct device *dev)
+{
+	int ret;
+	struct ssp_data *data;
+	struct device_node *node = dev->of_node;
+	const struct of_device_id *match;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
+	if (data->mcu_ap_gpio < 0)
+		goto err_free_pd;
+
+	data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
+	if (data->ap_mcu_gpio < 0)
+		goto err_free_pd;
+
+	data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
+	if (data->mcu_reset_gpio < 0)
+		goto err_free_pd;
+
+	ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
+				    "ap-mcu-gpios");
+	if (ret)
+		goto err_free_pd;
+
+	ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
+				    GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
+	if (ret)
+		goto err_ap_mcu;
+
+	match = of_match_node(ssp_of_match, node);
+	if (!match)
+		goto err_mcu_reset_gpio;
+
+	data->sensorhub_info = (struct ssp_sensorhub_info *)match->data;
+
+	dev_set_drvdata(dev, data);
+
+	return data;
+
+err_mcu_reset_gpio:
+	devm_gpio_free(dev, data->mcu_reset_gpio);
+err_ap_mcu:
+	devm_gpio_free(dev, data->ap_mcu_gpio);
+err_free_pd:
+	devm_kfree(dev, data);
+	return NULL;
+}
+#else
+static struct ssp_data *ssp_parse_dt(struct device *pdev)
+{
+	return NULL;
+}
+#endif
+
+/**
+ * ssp_register_consumer() - registers iio consumer in ssp framework
+ *
+ * @indio_dev:	consumer iio device
+ * @type:	ssp sensor type
+ */
+void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)
+{
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	data->sensor_devs[type] = indio_dev;
+}
+EXPORT_SYMBOL(ssp_register_consumer);
+
+static int ssp_probe(struct spi_device *spi)
+{
+	int ret, i;
+	struct ssp_data *data;
+
+	data = ssp_parse_dt(&spi->dev);
+	if (!data) {
+		dev_err(&spi->dev, "Failed to find platform data\n");
+		return -ENODEV;
+	}
+
+	ret = mfd_add_devices(&spi->dev, -1, sensorhub_sensor_devs,
+			      ARRAY_SIZE(sensorhub_sensor_devs), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(&spi->dev, "mfd add devices fail\n");
+		return ret;
+	}
+
+	spi->mode = SPI_MODE_1;
+	ret = spi_setup(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "Failed to setup spi\n");
+		return ret;
+	}
+
+	data->fw_dl_state = SSP_FW_DL_STATE_NONE;
+	data->spi = spi;
+	spi_set_drvdata(spi, data);
+
+	mutex_init(&data->comm_lock);
+
+	for (i = 0; i < SSP_SENSOR_MAX; ++i) {
+		data->delay_buf[i] = SSP_DEFAULT_POLLING_DELAY;
+		data->batch_latency_buf[i] = 0;
+		data->batch_opt_buf[i] = 0;
+		data->check_status[i] = SSP_INITIALIZATION_STATE;
+	}
+
+	data->delay_buf[SSP_BIO_HRM_LIB] = 100;
+
+	data->time_syncing = true;
+
+	mutex_init(&data->pending_lock);
+	INIT_LIST_HEAD(&data->pending_list);
+
+	atomic_set(&data->enable_refcount, 0);
+
+	INIT_WORK(&data->work_wdt, ssp_wdt_work_func);
+	INIT_DELAYED_WORK(&data->work_refresh, ssp_refresh_task);
+
+	setup_timer(&data->wdt_timer, ssp_wdt_timer_func, (unsigned long)data);
+
+	ret = request_threaded_irq(data->spi->irq, NULL,
+				   ssp_irq_thread_fn,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   "SSP_Int", data);
+	if (ret < 0) {
+		dev_err(&spi->dev, "Irq request fail\n");
+		goto err_setup_irq;
+	}
+
+	/* Let's start with enabled one so irq balance could be ok */
+	data->shut_down = false;
+
+	/* just to avoid unbalanced irq set wake up */
+	enable_irq_wake(data->spi->irq);
+
+	data->fw_dl_state = ssp_check_fwbl(data);
+	if (data->fw_dl_state == SSP_FW_DL_STATE_NONE) {
+		ret = ssp_initialize_mcu(data);
+		if (ret < 0) {
+			dev_err(&spi->dev, "Initialize_mcu failed\n");
+			goto err_read_reg;
+		}
+	} else {
+		dev_err(&spi->dev, "Firmware version not supported\n");
+		ret = -EPERM;
+		goto err_read_reg;
+	}
+
+	return 0;
+
+err_read_reg:
+	free_irq(data->spi->irq, data);
+err_setup_irq:
+	mutex_destroy(&data->pending_lock);
+	mutex_destroy(&data->comm_lock);
+
+	dev_err(&spi->dev, "Probe failed!\n");
+
+	return ret;
+}
+
+static int ssp_remove(struct spi_device *spi)
+{
+	struct ssp_data *data = spi_get_drvdata(spi);
+
+	if (ssp_command(data, SSP_MSG2SSP_AP_STATUS_SHUTDOWN, 0) < 0)
+		dev_err(&data->spi->dev,
+			"SSP_MSG2SSP_AP_STATUS_SHUTDOWN failed\n");
+
+	ssp_enable_mcu(data, false);
+	ssp_disable_wdt_timer(data);
+
+	ssp_clean_pending_list(data);
+
+	free_irq(data->spi->irq, data);
+
+	del_timer_sync(&data->wdt_timer);
+	cancel_work_sync(&data->work_wdt);
+
+	mutex_destroy(&data->comm_lock);
+	mutex_destroy(&data->pending_lock);
+
+	mfd_remove_devices(&spi->dev);
+
+	return 0;
+}
+
+static int ssp_suspend(struct device *dev)
+{
+	int ret;
+	struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
+
+	data->last_resume_state = SSP_MSG2SSP_AP_STATUS_SUSPEND;
+
+	if (atomic_read(&data->enable_refcount) > 0)
+		ssp_disable_wdt_timer(data);
+
+	ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_SUSPEND, 0);
+	if (ret < 0) {
+		dev_err(&data->spi->dev,
+			"%s SSP_MSG2SSP_AP_STATUS_SUSPEND failed\n", __func__);
+
+		ssp_enable_wdt_timer(data);
+		return ret;
+	}
+
+	data->time_syncing = false;
+	disable_irq(data->spi->irq);
+
+	return 0;
+}
+
+static int ssp_resume(struct device *dev)
+{
+	int ret;
+	struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
+
+	enable_irq(data->spi->irq);
+
+	if (atomic_read(&data->enable_refcount) > 0)
+		ssp_enable_wdt_timer(data);
+
+	ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_RESUME, 0);
+	if (ret < 0) {
+		dev_err(&data->spi->dev,
+			"%s SSP_MSG2SSP_AP_STATUS_RESUME failed\n", __func__);
+		ssp_disable_wdt_timer(data);
+		return ret;
+	}
+
+	/* timesyncing is set by MCU */
+	data->last_resume_state = SSP_MSG2SSP_AP_STATUS_RESUME;
+
+	return 0;
+}
+
+static const struct dev_pm_ops ssp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
+};
+
+static struct spi_driver ssp_driver = {
+	.probe = ssp_probe,
+	.remove = ssp_remove,
+	.driver = {
+		.pm = &ssp_pm_ops,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(ssp_of_match),
+		.name = "sensorhub"
+	},
+};
+
+module_spi_driver(ssp_driver);
+
+MODULE_DESCRIPTION("ssp sensorhub driver");
+MODULE_AUTHOR("Samsung Electronics");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c
new file mode 100644
index 0000000..a3ae165
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_iio.c
@@ -0,0 +1,107 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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/iio/common/ssp_sensors.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "ssp_iio_sensor.h"
+
+/**
+ * ssp_common_buffer_postenable() - generic postenable callback for ssp buffer
+ *
+ * @indio_dev:		iio device
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct ssp_sensor_data *spd = iio_priv(indio_dev);
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	/* the allocation is made in post because scan size is known in this
+	 * moment
+	 * */
+	spd->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL | GFP_DMA);
+	if (!spd->buffer)
+		return -ENOMEM;
+
+	return ssp_enable_sensor(data, spd->type,
+				 ssp_get_sensor_delay(data, spd->type));
+}
+EXPORT_SYMBOL(ssp_common_buffer_postenable);
+
+/**
+ * ssp_common_buffer_postdisable() - generic postdisable callback for ssp buffer
+ *
+ * @indio_dev:		iio device
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	int ret;
+	struct ssp_sensor_data *spd = iio_priv(indio_dev);
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	ret = ssp_disable_sensor(data, spd->type);
+	if (ret < 0)
+		return ret;
+
+	kfree(spd->buffer);
+
+	return ret;
+}
+EXPORT_SYMBOL(ssp_common_buffer_postdisable);
+
+/**
+ * ssp_common_process_data() - Common process data callback for ssp sensors
+ *
+ * @indio_dev:		iio device
+ * @buf:		source buffer
+ * @len:		sensor data length
+ * @timestamp:		system timestamp
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
+			    unsigned int len, int64_t timestamp)
+{
+	__le32 time;
+	int64_t calculated_time;
+	struct ssp_sensor_data *spd = iio_priv(indio_dev);
+
+	if (indio_dev->scan_bytes == 0)
+		return 0;
+
+	/*
+	 * it always sends full set of samples, remember about available masks
+	 */
+	memcpy(spd->buffer, buf, len);
+
+	if (indio_dev->scan_timestamp) {
+		memcpy(&time, &((char *)buf)[len], SSP_TIME_SIZE);
+		calculated_time =
+			timestamp + (int64_t)le32_to_cpu(time) * 1000000;
+	}
+
+	return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer,
+						  calculated_time);
+}
+EXPORT_SYMBOL(ssp_common_process_data);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub commons");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
new file mode 100644
index 0000000..541c659
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
@@ -0,0 +1,71 @@
+#ifndef __SSP_IIO_SENSOR_H__
+#define __SSP_IIO_SENSOR_H__
+
+#define SSP_CHANNEL_AG(_type, _mod, _index) \
+{ \
+		.type = _type,\
+		.modified = 1,\
+		.channel2 = _mod,\
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+		.scan_index = _index,\
+		.scan_type = {\
+			.sign = 's',\
+			.realbits = 16,\
+			.storagebits = 16,\
+			.shift = 0,\
+			.endianness = IIO_LE,\
+		},\
+}
+
+/* It is defined here as it is a mixed timestamp */
+#define SSP_CHAN_TIMESTAMP(_si) {					\
+	.type = IIO_TIMESTAMP,						\
+	.channel = -1,							\
+	.scan_index = _si,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 64,						\
+		.storagebits = 64,					\
+		},							\
+}
+
+#define SSP_MS_PER_S			1000
+#define SSP_INVERTED_SCALING_FACTOR	1000000U
+
+#define SSP_FACTOR_WITH_MS \
+	(SSP_INVERTED_SCALING_FACTOR * SSP_MS_PER_S)
+
+int ssp_common_buffer_postenable(struct iio_dev *indio_dev);
+
+int ssp_common_buffer_postdisable(struct iio_dev *indio_dev);
+
+int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
+			    unsigned int len, int64_t timestamp);
+
+/* Converts time in ms to frequency */
+static inline void ssp_convert_to_freq(u32 time, int *integer_part,
+				       int *fractional)
+{
+	if (time == 0) {
+		*fractional = 0;
+		*integer_part = 0;
+		return;
+	}
+
+	*integer_part = SSP_FACTOR_WITH_MS / time;
+	*fractional = *integer_part % SSP_INVERTED_SCALING_FACTOR;
+	*integer_part = *integer_part / SSP_INVERTED_SCALING_FACTOR;
+}
+
+/* Converts frequency to time in ms */
+static inline int ssp_convert_to_time(int integer_part, int fractional)
+{
+	u64 value;
+
+	value = (u64)integer_part * SSP_INVERTED_SCALING_FACTOR + fractional;
+	if (value == 0)
+		return 0;
+
+	return div64_u64((u64)SSP_FACTOR_WITH_MS, value);
+}
+#endif /* __SSP_IIO_SENSOR_H__ */
diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c
new file mode 100644
index 0000000..704284a
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -0,0 +1,608 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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 "ssp.h"
+
+#define SSP_DEV (&data->spi->dev)
+#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW))
+
+/*
+ * SSP -> AP Instruction
+ * They tell what packet type can be expected. In the future there will
+ * be less of them. BYPASS means common sensor packets with accel, gyro,
+ * hrm etc. data. LIBRARY and META are mock-up's for now.
+ */
+#define SSP_MSG2AP_INST_BYPASS_DATA		0x37
+#define SSP_MSG2AP_INST_LIBRARY_DATA		0x01
+#define SSP_MSG2AP_INST_DEBUG_DATA		0x03
+#define SSP_MSG2AP_INST_BIG_DATA		0x04
+#define SSP_MSG2AP_INST_META_DATA		0x05
+#define SSP_MSG2AP_INST_TIME_SYNC		0x06
+#define SSP_MSG2AP_INST_RESET			0x07
+
+#define SSP_UNIMPLEMENTED -1
+
+struct ssp_msg_header {
+	u8 cmd;
+	__le16 length;
+	__le16 options;
+	__le32 data;
+} __attribute__((__packed__));
+
+struct ssp_msg {
+	u16 length;
+	u16 options;
+	struct list_head list;
+	struct completion *done;
+	struct ssp_msg_header *h;
+	char *buffer;
+};
+
+static const int ssp_offset_map[SSP_SENSOR_MAX] = {
+	[SSP_ACCELEROMETER_SENSOR] =		SSP_ACCELEROMETER_SIZE +
+						SSP_TIME_SIZE,
+	[SSP_GYROSCOPE_SENSOR] =		SSP_GYROSCOPE_SIZE +
+						SSP_TIME_SIZE,
+	[SSP_GEOMAGNETIC_UNCALIB_SENSOR] =	SSP_UNIMPLEMENTED,
+	[SSP_GEOMAGNETIC_RAW] =			SSP_UNIMPLEMENTED,
+	[SSP_GEOMAGNETIC_SENSOR] =		SSP_UNIMPLEMENTED,
+	[SSP_PRESSURE_SENSOR] =			SSP_UNIMPLEMENTED,
+	[SSP_GESTURE_SENSOR] =			SSP_UNIMPLEMENTED,
+	[SSP_PROXIMITY_SENSOR] =		SSP_UNIMPLEMENTED,
+	[SSP_TEMPERATURE_HUMIDITY_SENSOR] =	SSP_UNIMPLEMENTED,
+	[SSP_LIGHT_SENSOR] =			SSP_UNIMPLEMENTED,
+	[SSP_PROXIMITY_RAW] =			SSP_UNIMPLEMENTED,
+	[SSP_ORIENTATION_SENSOR] =		SSP_UNIMPLEMENTED,
+	[SSP_STEP_DETECTOR] =			SSP_UNIMPLEMENTED,
+	[SSP_SIG_MOTION_SENSOR] =		SSP_UNIMPLEMENTED,
+	[SSP_GYRO_UNCALIB_SENSOR] =		SSP_UNIMPLEMENTED,
+	[SSP_GAME_ROTATION_VECTOR] =		SSP_UNIMPLEMENTED,
+	[SSP_ROTATION_VECTOR] =			SSP_UNIMPLEMENTED,
+	[SSP_STEP_COUNTER] =			SSP_UNIMPLEMENTED,
+	[SSP_BIO_HRM_RAW] =			SSP_BIO_HRM_RAW_SIZE +
+						SSP_TIME_SIZE,
+	[SSP_BIO_HRM_RAW_FAC] =			SSP_BIO_HRM_RAW_FAC_SIZE +
+						SSP_TIME_SIZE,
+	[SSP_BIO_HRM_LIB] =			SSP_BIO_HRM_LIB_SIZE +
+						SSP_TIME_SIZE,
+};
+
+#define SSP_HEADER_SIZE		(sizeof(struct ssp_msg_header))
+#define SSP_HEADER_SIZE_ALIGNED	(ALIGN(SSP_HEADER_SIZE, 4))
+
+static struct ssp_msg *ssp_create_msg(u8 cmd, u16 len, u16 opt, u32 data)
+{
+	struct ssp_msg_header h;
+	struct ssp_msg *msg;
+
+	msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+	if (!msg)
+		return NULL;
+
+	h.cmd = cmd;
+	h.length = cpu_to_le16(len);
+	h.options = cpu_to_le16(opt);
+	h.data = cpu_to_le32(data);
+
+	msg->buffer = kzalloc(SSP_HEADER_SIZE_ALIGNED + len,
+			      GFP_KERNEL | GFP_DMA);
+	if (!msg->buffer) {
+		kfree(msg);
+		return NULL;
+	}
+
+	msg->length = len;
+	msg->options = opt;
+
+	memcpy(msg->buffer, &h, SSP_HEADER_SIZE);
+
+	return msg;
+}
+
+/*
+ * It is a bit heavy to do it this way but often the function is used to compose
+ * the message from smaller chunks which are placed on the stack.  Often the
+ * chunks are small so memcpy should be optimalized.
+ */
+static inline void ssp_fill_buffer(struct ssp_msg *m, unsigned int offset,
+				   const void *src, unsigned int len)
+{
+	memcpy(&m->buffer[SSP_HEADER_SIZE_ALIGNED + offset], src, len);
+}
+
+static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset,
+				  void *dest, unsigned int len)
+{
+	memcpy(dest, &m->buffer[SSP_HEADER_SIZE_ALIGNED + offset],  len);
+}
+
+#define SSP_GET_BUFFER_AT_INDEX(m, index) \
+	(m->buffer[SSP_HEADER_SIZE_ALIGNED + index])
+#define SSP_SET_BUFFER_AT_INDEX(m, index, val) \
+	(m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val)
+
+static void ssp_clean_msg(struct ssp_msg *m)
+{
+	kfree(m->buffer);
+	kfree(m);
+}
+
+static int ssp_print_mcu_debug(char *data_frame, int *data_index,
+			       int received_len)
+{
+	int length = data_frame[(*data_index)++];
+
+	if (length > received_len - *data_index || length <= 0) {
+		ssp_dbg("[SSP]: MSG From MCU-invalid debug length(%d/%d)\n",
+			length, received_len);
+		return length ? length : -EPROTO;
+	}
+
+	ssp_dbg("[SSP]: MSG From MCU - %s\n", &data_frame[*data_index]);
+
+	*data_index += length;
+
+	return 0;
+}
+
+/*
+ * It was designed that way - additional lines to some kind of handshake,
+ * please do not ask why - only the firmware guy can know it.
+ */
+static int ssp_check_lines(struct ssp_data *data, bool state)
+{
+	int delay_cnt = 0;
+
+	gpio_set_value_cansleep(data->ap_mcu_gpio, state);
+
+	while (gpio_get_value_cansleep(data->mcu_ap_gpio) != state) {
+		usleep_range(3000, 3500);
+
+		if (data->shut_down || delay_cnt++ > 500) {
+			dev_err(SSP_DEV, "%s:timeout, hw ack wait fail %d\n",
+				__func__, state);
+
+			if (!state)
+				gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
+
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int ssp_do_transfer(struct ssp_data *data, struct ssp_msg *msg,
+			   struct completion *done, int timeout)
+{
+	int status;
+	/*
+	 * check if this is a short one way message or the whole transfer has
+	 * second part after an interrupt
+	 */
+	const bool use_no_irq = msg->length == 0;
+
+	if (data->shut_down)
+		return -EPERM;
+
+	msg->done = done;
+
+	mutex_lock(&data->comm_lock);
+
+	status = ssp_check_lines(data, false);
+	if (status < 0)
+		goto _error_locked;
+
+	status = spi_write(data->spi, msg->buffer, SSP_HEADER_SIZE);
+	if (status < 0) {
+		gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
+		dev_err(SSP_DEV, "%s spi_write fail\n", __func__);
+		goto _error_locked;
+	}
+
+	if (!use_no_irq) {
+		mutex_lock(&data->pending_lock);
+		list_add_tail(&msg->list, &data->pending_list);
+		mutex_unlock(&data->pending_lock);
+	}
+
+	status = ssp_check_lines(data, true);
+	if (status < 0) {
+		if (!use_no_irq) {
+			mutex_lock(&data->pending_lock);
+			list_del(&msg->list);
+			mutex_unlock(&data->pending_lock);
+		}
+		goto _error_locked;
+	}
+
+	mutex_unlock(&data->comm_lock);
+
+	if (!use_no_irq && done)
+		if (wait_for_completion_timeout(done,
+						msecs_to_jiffies(timeout)) ==
+		    0) {
+			mutex_lock(&data->pending_lock);
+			list_del(&msg->list);
+			mutex_unlock(&data->pending_lock);
+
+			data->timeout_cnt++;
+			return -ETIMEDOUT;
+		}
+
+	return 0;
+
+_error_locked:
+	mutex_unlock(&data->comm_lock);
+	data->timeout_cnt++;
+	return status;
+}
+
+static inline int ssp_spi_sync_command(struct ssp_data *data,
+				       struct ssp_msg *msg)
+{
+	return ssp_do_transfer(data, msg, NULL, 0);
+}
+
+static int ssp_spi_sync(struct ssp_data *data, struct ssp_msg *msg,
+			int timeout)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+
+	if (WARN_ON(!msg->length))
+		return -EPERM;
+
+	return ssp_do_transfer(data, msg, &done, timeout);
+}
+
+static int ssp_handle_big_data(struct ssp_data *data, char *dataframe, int *idx)
+{
+	/* mock-up, it will be changed with adding another sensor types */
+	*idx += 8;
+	return 0;
+}
+
+static int ssp_parse_dataframe(struct ssp_data *data, char *dataframe, int len)
+{
+	int idx, sd;
+	struct timespec ts;
+	struct ssp_sensor_data *spd;
+	struct iio_dev **indio_devs = data->sensor_devs;
+
+	getnstimeofday(&ts);
+
+	for (idx = 0; idx < len;) {
+		switch (dataframe[idx++]) {
+		case SSP_MSG2AP_INST_BYPASS_DATA:
+			sd = dataframe[idx++];
+			if (sd < 0 || sd >= SSP_SENSOR_MAX) {
+				dev_err(SSP_DEV,
+					"Mcu data frame1 error %d\n", sd);
+				return -EPROTO;
+			}
+
+			if (indio_devs[sd]) {
+				spd = iio_priv(indio_devs[sd]);
+				if (spd->process_data)
+					spd->process_data(indio_devs[sd],
+							  &dataframe[idx],
+							  data->timestamp);
+			} else {
+				dev_err(SSP_DEV, "no client for frame\n");
+			}
+
+			idx += ssp_offset_map[sd];
+			break;
+		case SSP_MSG2AP_INST_DEBUG_DATA:
+			sd = ssp_print_mcu_debug(dataframe, &idx, len);
+			if (sd) {
+				dev_err(SSP_DEV,
+					"Mcu data frame3 error %d\n", sd);
+				return sd;
+			}
+			break;
+		case SSP_MSG2AP_INST_LIBRARY_DATA:
+			idx += len;
+			break;
+		case SSP_MSG2AP_INST_BIG_DATA:
+			ssp_handle_big_data(data, dataframe, &idx);
+			break;
+		case SSP_MSG2AP_INST_TIME_SYNC:
+			data->time_syncing = true;
+			break;
+		case SSP_MSG2AP_INST_RESET:
+			ssp_queue_ssp_refresh_task(data, 0);
+			break;
+		}
+	}
+
+	if (data->time_syncing)
+		data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	return 0;
+}
+
+/* threaded irq */
+int ssp_irq_msg(struct ssp_data *data)
+{
+	bool found = false;
+	char *buffer;
+	u8 msg_type;
+	int ret;
+	u16 length, msg_options;
+	struct ssp_msg *msg, *n;
+
+	ret = spi_read(data->spi, data->header_buffer, SSP_HEADER_BUFFER_SIZE);
+	if (ret < 0) {
+		dev_err(SSP_DEV, "header read fail\n");
+		return ret;
+	}
+
+	length = le16_to_cpu(data->header_buffer[1]);
+	msg_options = le16_to_cpu(data->header_buffer[0]);
+
+	if (length == 0) {
+		dev_err(SSP_DEV, "length received from mcu is 0\n");
+		return -EINVAL;
+	}
+
+	msg_type = SSP_GET_MESSAGE_TYPE(msg_options);
+
+	switch (msg_type) {
+	case SSP_AP2HUB_READ:
+	case SSP_AP2HUB_WRITE:
+		/*
+		 * this is a small list, a few elements - the packets can be
+		 * received with no order
+		 */
+		mutex_lock(&data->pending_lock);
+		list_for_each_entry_safe(msg, n, &data->pending_list, list) {
+			if (msg->options == msg_options) {
+				list_del(&msg->list);
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			/*
+			 * here can be implemented dead messages handling
+			 * but the slave should not send such ones - it is to
+			 * check but let's handle this
+			 */
+			buffer = kmalloc(length, GFP_KERNEL | GFP_DMA);
+			if (!buffer) {
+				ret = -ENOMEM;
+				goto _unlock;
+			}
+
+			/* got dead packet so it is always an error */
+			ret = spi_read(data->spi, buffer, length);
+			if (ret >= 0)
+				ret = -EPROTO;
+
+			kfree(buffer);
+
+			dev_err(SSP_DEV, "No match error %x\n",
+				msg_options);
+
+			goto _unlock;
+		}
+
+		if (msg_type == SSP_AP2HUB_READ)
+			ret = spi_read(data->spi,
+				       &msg->buffer[SSP_HEADER_SIZE_ALIGNED],
+				       msg->length);
+
+		if (msg_type == SSP_AP2HUB_WRITE) {
+			ret = spi_write(data->spi,
+					&msg->buffer[SSP_HEADER_SIZE_ALIGNED],
+					msg->length);
+			if (msg_options & SSP_AP2HUB_RETURN) {
+				msg->options =
+					SSP_AP2HUB_READ | SSP_AP2HUB_RETURN;
+				msg->length = 1;
+
+				list_add_tail(&msg->list, &data->pending_list);
+				goto _unlock;
+			}
+		}
+
+		if (msg->done)
+			if (!completion_done(msg->done))
+				complete(msg->done);
+_unlock:
+		mutex_unlock(&data->pending_lock);
+		break;
+	case SSP_HUB2AP_WRITE:
+		buffer = kzalloc(length, GFP_KERNEL | GFP_DMA);
+		if (!buffer)
+			return -ENOMEM;
+
+		ret = spi_read(data->spi, buffer, length);
+		if (ret < 0) {
+			dev_err(SSP_DEV, "spi read fail\n");
+			kfree(buffer);
+			break;
+		}
+
+		ret = ssp_parse_dataframe(data, buffer, length);
+
+		kfree(buffer);
+		break;
+
+	default:
+		dev_err(SSP_DEV, "unknown msg type\n");
+		return -EPROTO;
+	}
+
+	return ret;
+}
+
+void ssp_clean_pending_list(struct ssp_data *data)
+{
+	struct ssp_msg *msg, *n;
+
+	mutex_lock(&data->pending_lock);
+	list_for_each_entry_safe(msg, n, &data->pending_list, list) {
+		list_del(&msg->list);
+
+		if (msg->done)
+			if (!completion_done(msg->done))
+				complete(msg->done);
+	}
+	mutex_unlock(&data->pending_lock);
+}
+
+int ssp_command(struct ssp_data *data, char command, int arg)
+{
+	int ret;
+	struct ssp_msg *msg;
+
+	msg = ssp_create_msg(command, 0, SSP_AP2HUB_WRITE, arg);
+	if (!msg)
+		return -ENOMEM;
+
+	ssp_dbg("%s - command 0x%x %d\n", __func__, command, arg);
+
+	ret = ssp_spi_sync_command(data, msg);
+	ssp_clean_msg(msg);
+
+	return ret;
+}
+
+int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
+			 u8 *send_buf, u8 length)
+{
+	int ret;
+	struct ssp_msg *msg;
+
+	if (data->fw_dl_state == SSP_FW_DL_STATE_DOWNLOADING) {
+		dev_err(SSP_DEV, "%s - Skip Inst! DL state = %d\n",
+			__func__, data->fw_dl_state);
+		return -EBUSY;
+	} else if (!(data->available_sensors & BIT(sensor_type)) &&
+		   (inst <= SSP_MSG2SSP_INST_CHANGE_DELAY)) {
+		dev_err(SSP_DEV, "%s - Bypass Inst Skip! - %u\n",
+			__func__, sensor_type);
+		return -EIO; /* just fail */
+	}
+
+	msg = ssp_create_msg(inst, length + 2, SSP_AP2HUB_WRITE, 0);
+	if (!msg)
+		return -ENOMEM;
+
+	ssp_fill_buffer(msg, 0, &sensor_type, 1);
+	ssp_fill_buffer(msg, 1, send_buf, length);
+
+	ssp_dbg("%s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n",
+		__func__, inst, sensor_type, send_buf[1]);
+
+	ret = ssp_spi_sync(data, msg, 1000);
+	ssp_clean_msg(msg);
+
+	return ret;
+}
+
+int ssp_get_chipid(struct ssp_data *data)
+{
+	int ret;
+	char buffer;
+	struct ssp_msg *msg;
+
+	msg = ssp_create_msg(SSP_MSG2SSP_AP_WHOAMI, 1, SSP_AP2HUB_READ, 0);
+	if (!msg)
+		return -ENOMEM;
+
+	ret = ssp_spi_sync(data, msg, 1000);
+
+	buffer = SSP_GET_BUFFER_AT_INDEX(msg, 0);
+
+	ssp_clean_msg(msg);
+
+	return ret < 0 ? ret : buffer;
+}
+
+int ssp_set_magnetic_matrix(struct ssp_data *data)
+{
+	int ret;
+	struct ssp_msg *msg;
+
+	msg = ssp_create_msg(SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX,
+			     data->sensorhub_info->mag_length, SSP_AP2HUB_WRITE,
+			     0);
+	if (!msg)
+		return -ENOMEM;
+
+	ssp_fill_buffer(msg, 0, data->sensorhub_info->mag_table,
+			data->sensorhub_info->mag_length);
+
+	ret = ssp_spi_sync(data, msg, 1000);
+	ssp_clean_msg(msg);
+
+	return ret;
+}
+
+unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data)
+{
+	int ret;
+	__le32 result;
+	u32 cpu_result = 0;
+
+	struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_SENSOR_SCANNING, 4,
+					     SSP_AP2HUB_READ, 0);
+	if (!msg)
+		return 0;
+
+	ret = ssp_spi_sync(data, msg, 1000);
+	if (ret < 0) {
+		dev_err(SSP_DEV, "%s - spi read fail %d\n", __func__, ret);
+		goto _exit;
+	}
+
+	ssp_get_buffer(msg, 0, &result, 4);
+	cpu_result = le32_to_cpu(result);
+
+	dev_info(SSP_DEV, "%s state: 0x%08x\n", __func__, cpu_result);
+
+_exit:
+	ssp_clean_msg(msg);
+	return cpu_result;
+}
+
+unsigned int ssp_get_firmware_rev(struct ssp_data *data)
+{
+	int ret;
+	__le32 result;
+
+	struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_FIRMWARE_REV, 4,
+					     SSP_AP2HUB_READ, 0);
+	if (!msg)
+		return SSP_INVALID_REVISION;
+
+	ret = ssp_spi_sync(data, msg, 1000);
+	if (ret < 0) {
+		dev_err(SSP_DEV, "%s - transfer fail %d\n", __func__, ret);
+		ret = SSP_INVALID_REVISION;
+		goto _exit;
+	}
+
+	ssp_get_buffer(msg, 0, &result, 4);
+	ret = le32_to_cpu(result);
+
+_exit:
+	ssp_clean_msg(msg);
+	return ret;
+}
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
index 78a6a1a..5b37737 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -54,7 +54,7 @@
 	if (err)
 		goto acc_spi_read_error;
 
-	memcpy(data, tb->rx_buf, len*sizeof(u8));
+	memcpy(data, tb->rx_buf, len);
 	mutex_unlock(&tb->buf_lock);
 	return len;
 
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 7c5245d..50ed8d1 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -445,7 +445,7 @@
 
 	tmp = 4;
 	do {
-		msleep(16);
+		msleep(20);
 		ret = ad9523_read(indio_dev,
 				  AD9523_EEPROM_DATA_XFER_STATUS);
 		if (ret < 0)
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 63a25d9..10a0dfc 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -387,10 +387,8 @@
 	int ret;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata) {
-		dev_err(dev, "could not allocate memory for platform data\n");
+	if (!pdata)
 		return NULL;
-	}
 
 	strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
 
@@ -613,9 +611,8 @@
 	if (st->clk)
 		clk_disable_unprepare(st->clk);
 
-	if (!IS_ERR(reg)) {
+	if (!IS_ERR(reg))
 		regulator_disable(reg);
-	}
 
 	return 0;
 }
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index 36a3877..f46341b 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -16,6 +16,8 @@
 itg3200-$(CONFIG_IIO_BUFFER) += itg3200_buffer.o
 obj-$(CONFIG_ITG3200)   += itg3200.o
 
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_gyro_sensor.o
+
 obj-$(CONFIG_IIO_ST_GYRO_3AXIS) += st_gyro.o
 st_gyro-y := st_gyro_core.o
 st_gyro-$(CONFIG_IIO_BUFFER) += st_gyro_buffer.o
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index a3ea1e8..a3c3e19 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -111,19 +111,12 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
 	switch (mask) {
 	case 0:
-		poll_value = hid_sensor_read_poll_value(
-					&gyro_state->common_attributes);
-		if (poll_value < 0)
-			return -EINVAL;
-
 		hid_sensor_power_state(&gyro_state->common_attributes, true);
-		msleep_interruptible(poll_value * 2);
 		report_id = gyro_state->gyro[chan->scan_index].report_id;
 		address = gyro_3d_addresses[chan->scan_index];
 		if (report_id >= 0)
@@ -416,6 +409,7 @@
 	.id_table = hid_gyro_3d_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_gyro_3d_probe,
 	.remove		= hid_gyro_3d_remove,
diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c
new file mode 100644
index 0000000..0a8afdd
--- /dev/null
+++ b/drivers/iio/gyro/ssp_gyro_sensor.c
@@ -0,0 +1,168 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "../common/ssp_sensors/ssp_iio_sensor.h"
+
+#define SSP_CHANNEL_COUNT 3
+
+#define SSP_GYROSCOPE_NAME "ssp-gyroscope"
+static const char ssp_gyro_name[] = SSP_GYROSCOPE_NAME;
+
+enum ssp_gyro_3d_channel {
+	SSP_CHANNEL_SCAN_INDEX_X,
+	SSP_CHANNEL_SCAN_INDEX_Y,
+	SSP_CHANNEL_SCAN_INDEX_Z,
+	SSP_CHANNEL_SCAN_INDEX_TIME,
+};
+
+static int ssp_gyro_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int *val,
+			     int *val2, long mask)
+{
+	u32 t;
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		t = ssp_get_sensor_delay(data, SSP_GYROSCOPE_SENSOR);
+		ssp_convert_to_freq(t, val, val2);
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ssp_gyro_write_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan, int val,
+			      int val2, long mask)
+{
+	int ret;
+	struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = ssp_convert_to_time(val, val2);
+		ret = ssp_change_delay(data, SSP_GYROSCOPE_SENSOR, ret);
+		if (ret < 0)
+			dev_err(&indio_dev->dev, "gyro sensor enable fail\n");
+
+		return ret;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static struct iio_info ssp_gyro_iio_info = {
+	.read_raw = &ssp_gyro_read_raw,
+	.write_raw = &ssp_gyro_write_raw,
+};
+
+static const unsigned long ssp_gyro_scan_mask[] = { 0x07, 0, };
+
+static const struct iio_chan_spec ssp_gyro_channels[] = {
+	SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
+	SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
+	SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
+	SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+};
+
+static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf,
+				 int64_t timestamp)
+{
+	return ssp_common_process_data(indio_dev, buf, SSP_GYROSCOPE_SIZE,
+				       timestamp);
+}
+
+static const struct iio_buffer_setup_ops ssp_gyro_buffer_ops = {
+	.postenable = &ssp_common_buffer_postenable,
+	.postdisable = &ssp_common_buffer_postdisable,
+};
+
+static int ssp_gyro_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct ssp_sensor_data *spd;
+	struct iio_buffer *buffer;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	spd = iio_priv(indio_dev);
+
+	spd->process_data = ssp_process_gyro_data;
+	spd->type = SSP_GYROSCOPE_SENSOR;
+
+	indio_dev->name = ssp_gyro_name;
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &ssp_gyro_iio_info;
+	indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+	indio_dev->channels = ssp_gyro_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ssp_gyro_channels);
+	indio_dev->available_scan_masks = ssp_gyro_scan_mask;
+
+	buffer = devm_iio_kfifo_allocate(&pdev->dev);
+	if (!buffer)
+		return -ENOMEM;
+
+	iio_device_attach_buffer(indio_dev, buffer);
+
+	indio_dev->setup_ops = &ssp_gyro_buffer_ops;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	/* ssp registering should be done after all iio setup */
+	ssp_register_consumer(indio_dev, SSP_GYROSCOPE_SENSOR);
+
+	return 0;
+}
+
+static int ssp_gyro_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver ssp_gyro_driver = {
+	.driver = {
+		.name = SSP_GYROSCOPE_NAME,
+	},
+	.probe = ssp_gyro_probe,
+	.remove = ssp_gyro_remove,
+};
+
+module_platform_driver(ssp_gyro_driver);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 5f0ea77..3598835 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -48,6 +48,8 @@
 ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
 				      size_t n, loff_t *f_ps);
 
+int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
+void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
 
 #define iio_buffer_poll_addr (&iio_buffer_poll)
 #define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
@@ -60,6 +62,13 @@
 #define iio_buffer_poll_addr NULL
 #define iio_buffer_read_first_n_outer_addr NULL
 
+static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+{
+	return 0;
+}
+
+static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
+
 static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
 static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}
 
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 2b0e451..5e610f7 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -25,6 +25,17 @@
 	  Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
 	  ADIS16485, ADIS16488 inertial sensors.
 
+config KMX61
+	tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
+	depends on I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say Y here if you want to build a driver for Kionix KMX61 6-axis
+	  accelerometer and magnetometer.
+	  To compile this driver as module, choose M here: the module will
+	  be called kmx61.
+
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
 endmenu
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 114d2c1..e1e6e3d 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -14,3 +14,5 @@
 obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
 
 obj-y += inv_mpu6050/
+
+obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index 2d0608b..48fbc0b 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -7,6 +7,7 @@
 	depends on I2C && SYSFS
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
+	select I2C_MUX
 	help
 	  This driver supports the Invensense MPU6050 devices.
 	  This driver can also support MPU6500 in MPU6050 compatibility mode
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index b75519d..f73e60b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,6 +23,8 @@
 #include <linux/kfifo.h>
 #include <linux/spinlock.h>
 #include <linux/iio/iio.h>
+#include <linux/i2c-mux.h>
+#include <linux/acpi.h>
 #include "inv_mpu_iio.h"
 
 /*
@@ -52,6 +54,7 @@
 	.int_enable             = INV_MPU6050_REG_INT_ENABLE,
 	.pwr_mgmt_1             = INV_MPU6050_REG_PWR_MGMT_1,
 	.pwr_mgmt_2             = INV_MPU6050_REG_PWR_MGMT_2,
+	.int_pin_cfg		= INV_MPU6050_REG_INT_PIN_CFG,
 };
 
 static const struct inv_mpu6050_chip_config chip_config_6050 = {
@@ -77,6 +80,83 @@
 	return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d);
 }
 
+/*
+ * The i2c read/write needs to happen in unlocked mode. As the parent
+ * adapter is common. If we use locked versions, it will fail as
+ * the mux adapter will lock the parent i2c adapter, while calling
+ * select/deselect functions.
+ */
+static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
+					  u8 reg, u8 d)
+{
+	int ret;
+	u8 buf[2];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = st->client->addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	buf[1] = d;
+	ret = __i2c_transfer(st->client->adapter, msg, 1);
+	if (ret != 1)
+		return ret;
+
+	return 0;
+}
+
+static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
+				     u32 chan_id)
+{
+	struct iio_dev *indio_dev = mux_priv;
+	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+	int ret = 0;
+
+	/* Use the same mutex which was used everywhere to protect power-op */
+	mutex_lock(&indio_dev->mlock);
+	if (!st->powerup_count) {
+		ret = inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
+						     0);
+		if (ret)
+			goto write_error;
+
+		msleep(INV_MPU6050_REG_UP_TIME);
+	}
+	if (!ret) {
+		st->powerup_count++;
+		ret = inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
+						     st->client->irq |
+						     INV_MPU6050_BIT_BYPASS_EN);
+	}
+write_error:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
+				       void *mux_priv, u32 chan_id)
+{
+	struct iio_dev *indio_dev = mux_priv;
+	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+	mutex_lock(&indio_dev->mlock);
+	/* It doesn't really mattter, if any of the calls fails */
+	inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
+				       st->client->irq);
+	st->powerup_count--;
+	if (!st->powerup_count)
+		inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
+					       INV_MPU6050_BIT_SLEEP);
+	mutex_unlock(&indio_dev->mlock);
+
+	return 0;
+}
+
 int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
 {
 	u8 d, mgmt_1;
@@ -133,13 +213,22 @@
 
 int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
 {
-	int result;
+	int result = 0;
 
-	if (power_on)
-		result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0);
-	else
-		result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
-						INV_MPU6050_BIT_SLEEP);
+	if (power_on) {
+		/* Already under indio-dev->mlock mutex */
+		if (!st->powerup_count)
+			result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+						       0);
+		if (!result)
+			st->powerup_count++;
+	} else {
+		st->powerup_count--;
+		if (!st->powerup_count)
+			result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+						       INV_MPU6050_BIT_SLEEP);
+	}
+
 	if (result)
 		return result;
 
@@ -673,6 +762,7 @@
 
 	st = iio_priv(indio_dev);
 	st->client = client;
+	st->powerup_count = 0;
 	pdata = dev_get_platdata(&client->dev);
 	if (pdata)
 		st->plat_data = *pdata;
@@ -720,8 +810,21 @@
 		goto out_remove_trigger;
 	}
 
+	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
+					      &client->dev,
+					      indio_dev,
+					      0, 0, 0,
+					      inv_mpu6050_select_bypass,
+					      inv_mpu6050_deselect_bypass);
+	if (!st->mux_adapter) {
+		result = -ENODEV;
+		goto out_unreg_device;
+	}
+
 	return 0;
 
+out_unreg_device:
+	iio_device_unregister(indio_dev);
 out_remove_trigger:
 	inv_mpu6050_remove_trigger(st);
 out_unreg_ring:
@@ -734,6 +837,7 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
+	i2c_del_mux_adapter(st->mux_adapter);
 	iio_device_unregister(indio_dev);
 	inv_mpu6050_remove_trigger(st);
 	iio_triggered_buffer_cleanup(indio_dev);
@@ -772,6 +876,13 @@
 
 MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
 
+static const struct acpi_device_id inv_acpi_match[] = {
+	{"INVN6500", 0},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
+
 static struct i2c_driver inv_mpu_driver = {
 	.probe		=	inv_mpu_probe,
 	.remove		=	inv_mpu_remove,
@@ -780,6 +891,7 @@
 		.owner	=	THIS_MODULE,
 		.name	=	"inv-mpu6050",
 		.pm     =       INV_MPU6050_PMOPS,
+		.acpi_match_table = ACPI_PTR(inv_acpi_match),
 	},
 };
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e779931..aa837de 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -54,6 +54,7 @@
 	u8 int_enable;
 	u8 pwr_mgmt_1;
 	u8 pwr_mgmt_2;
+	u8 int_pin_cfg;
 };
 
 /*device enum */
@@ -119,6 +120,8 @@
 	enum   inv_devices chip_type;
 	spinlock_t time_stamp_lock;
 	struct i2c_client *client;
+	struct i2c_adapter *mux_adapter;
+	unsigned int powerup_count;
 	struct inv_mpu6050_platform_data plat_data;
 	DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
 };
@@ -179,6 +182,9 @@
 /* 6 + 6 round up and plus 8 */
 #define INV_MPU6050_OUTPUT_DATA_SIZE         24
 
+#define INV_MPU6050_REG_INT_PIN_CFG	0x37
+#define INV_MPU6050_BIT_BYPASS_EN	0x2
+
 /* init parameters */
 #define INV_MPU6050_INIT_FIFO_RATE           50
 #define INV_MPU6050_TIME_STAMP_TOR           5
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index 926fcce..844610c 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -116,40 +116,35 @@
 	int ret;
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
-	st->trig = iio_trigger_alloc("%s-dev%d",
-					indio_dev->name,
-					indio_dev->id);
-	if (st->trig == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
-				IRQF_TRIGGER_RISING,
-				"inv_mpu",
-				st->trig);
+	st->trig = devm_iio_trigger_alloc(&indio_dev->dev,
+					  "%s-dev%d",
+					  indio_dev->name,
+					  indio_dev->id);
+	if (!st->trig)
+		return -ENOMEM;
+
+	ret = devm_request_irq(&indio_dev->dev, st->client->irq,
+			       &iio_trigger_generic_data_rdy_poll,
+			       IRQF_TRIGGER_RISING,
+			       "inv_mpu",
+			       st->trig);
 	if (ret)
-		goto error_free_trig;
+		return ret;
+
 	st->trig->dev.parent = &st->client->dev;
 	st->trig->ops = &inv_mpu_trigger_ops;
 	iio_trigger_set_drvdata(st->trig, indio_dev);
+
 	ret = iio_trigger_register(st->trig);
 	if (ret)
-		goto error_free_irq;
+		return ret;
+
 	indio_dev->trig = iio_trigger_get(st->trig);
 
 	return 0;
-
-error_free_irq:
-	free_irq(st->client->irq, st->trig);
-error_free_trig:
-	iio_trigger_free(st->trig);
-error_ret:
-	return ret;
 }
 
 void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st)
 {
 	iio_trigger_unregister(st->trig);
-	free_irq(st->client->irq, st->trig);
-	iio_trigger_free(st->trig);
 }
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
new file mode 100644
index 0000000..5cc3692
--- /dev/null
+++ b/drivers/iio/imu/kmx61.c
@@ -0,0 +1,1595 @@
+/*
+ * KMX61 - Kionix 6-axis Accelerometer/Magnetometer
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F).
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define KMX61_DRV_NAME "kmx61"
+#define KMX61_GPIO_NAME "kmx61_int"
+#define KMX61_IRQ_NAME "kmx61_event"
+
+#define KMX61_REG_WHO_AM_I	0x00
+#define KMX61_REG_INS1		0x01
+#define KMX61_REG_INS2		0x02
+
+/*
+ * three 16-bit accelerometer output registers for X/Y/Z axis
+ * we use only XOUT_L as a base register, all other addresses
+ * can be obtained by applying an offset and are provided here
+ * only for clarity.
+ */
+#define KMX61_ACC_XOUT_L	0x0A
+#define KMX61_ACC_XOUT_H	0x0B
+#define KMX61_ACC_YOUT_L	0x0C
+#define KMX61_ACC_YOUT_H	0x0D
+#define KMX61_ACC_ZOUT_L	0x0E
+#define KMX61_ACC_ZOUT_H	0x0F
+
+/*
+ * one 16-bit temperature output register
+ */
+#define KMX61_TEMP_L		0x10
+#define KMX61_TEMP_H		0x11
+
+/*
+ * three 16-bit magnetometer output registers for X/Y/Z axis
+ */
+#define KMX61_MAG_XOUT_L	0x12
+#define KMX61_MAG_XOUT_H	0x13
+#define KMX61_MAG_YOUT_L	0x14
+#define KMX61_MAG_YOUT_H	0x15
+#define KMX61_MAG_ZOUT_L	0x16
+#define KMX61_MAG_ZOUT_H	0x17
+
+#define KMX61_REG_INL		0x28
+#define KMX61_REG_STBY		0x29
+#define KMX61_REG_CTRL1		0x2A
+#define KMX61_REG_CTRL2		0x2B
+#define KMX61_REG_ODCNTL	0x2C
+#define KMX61_REG_INC1		0x2D
+
+#define KMX61_REG_WUF_THRESH	0x3D
+#define KMX61_REG_WUF_TIMER	0x3E
+
+#define KMX61_ACC_STBY_BIT	BIT(0)
+#define KMX61_MAG_STBY_BIT	BIT(1)
+#define KMX61_ACT_STBY_BIT	BIT(7)
+
+#define KMX61_ALL_STBY		(KMX61_ACC_STBY_BIT | KMX61_MAG_STBY_BIT)
+
+#define KMX61_REG_INS1_BIT_WUFS		BIT(1)
+
+#define KMX61_REG_INS2_BIT_ZP		BIT(0)
+#define KMX61_REG_INS2_BIT_ZN		BIT(1)
+#define KMX61_REG_INS2_BIT_YP		BIT(2)
+#define KMX61_REG_INS2_BIT_YN		BIT(3)
+#define KMX61_REG_INS2_BIT_XP		BIT(4)
+#define KMX61_REG_INS2_BIT_XN		BIT(5)
+
+#define KMX61_REG_CTRL1_GSEL_MASK	0x03
+
+#define KMX61_REG_CTRL1_BIT_RES		BIT(4)
+#define KMX61_REG_CTRL1_BIT_DRDYE	BIT(5)
+#define KMX61_REG_CTRL1_BIT_WUFE	BIT(6)
+#define KMX61_REG_CTRL1_BIT_BTSE	BIT(7)
+
+#define KMX61_REG_INC1_BIT_WUFS		BIT(0)
+#define KMX61_REG_INC1_BIT_DRDYM	BIT(1)
+#define KMX61_REG_INC1_BIT_DRDYA	BIT(2)
+#define KMX61_REG_INC1_BIT_IEN		BIT(5)
+
+#define KMX61_ACC_ODR_SHIFT	0
+#define KMX61_MAG_ODR_SHIFT	4
+#define KMX61_ACC_ODR_MASK	0x0F
+#define KMX61_MAG_ODR_MASK	0xF0
+
+#define KMX61_OWUF_MASK		0x7
+
+#define KMX61_DEFAULT_WAKE_THRESH	1
+#define KMX61_DEFAULT_WAKE_DURATION	1
+
+#define KMX61_SLEEP_DELAY_MS	2000
+
+#define KMX61_CHIP_ID		0x12
+
+/* KMX61 devices */
+#define KMX61_ACC	0x01
+#define KMX61_MAG	0x02
+
+struct kmx61_data {
+	struct i2c_client *client;
+
+	/* serialize access to non-atomic ops, e.g set_mode */
+	struct mutex lock;
+
+	/* standby state */
+	bool acc_stby;
+	bool mag_stby;
+
+	/* power state */
+	bool acc_ps;
+	bool mag_ps;
+
+	/* config bits */
+	u8 range;
+	u8 odr_bits;
+	u8 wake_thresh;
+	u8 wake_duration;
+
+	/* accelerometer specific data */
+	struct iio_dev *acc_indio_dev;
+	struct iio_trigger *acc_dready_trig;
+	struct iio_trigger *motion_trig;
+	bool acc_dready_trig_on;
+	bool motion_trig_on;
+	bool ev_enable_state;
+
+	/* magnetometer specific data */
+	struct iio_dev *mag_indio_dev;
+	struct iio_trigger *mag_dready_trig;
+	bool mag_dready_trig_on;
+};
+
+enum kmx61_range {
+	KMX61_RANGE_2G,
+	KMX61_RANGE_4G,
+	KMX61_RANGE_8G,
+};
+
+enum kmx61_axis {
+	KMX61_AXIS_X,
+	KMX61_AXIS_Y,
+	KMX61_AXIS_Z,
+};
+
+static const u16 kmx61_uscale_table[] = {9582, 19163, 38326};
+
+static const struct {
+	int val;
+	int val2;
+	u8 odr_bits;
+} kmx61_samp_freq_table[] = { {12, 500000, 0x00},
+			{25, 0, 0x01},
+			{50, 0, 0x02},
+			{100, 0, 0x03},
+			{200, 0, 0x04},
+			{400, 0, 0x05},
+			{800, 0, 0x06},
+			{1600, 0, 0x07},
+			{0, 781000, 0x08},
+			{1, 563000, 0x09},
+			{3, 125000, 0x0A},
+			{6, 250000, 0x0B} };
+
+static const struct {
+	int val;
+	int val2;
+	int odr_bits;
+} kmx61_wake_up_odr_table[] = { {0, 781000, 0x00},
+				 {1, 563000, 0x01},
+				 {3, 125000, 0x02},
+				 {6, 250000, 0x03},
+				 {12, 500000, 0x04},
+				 {25, 0, 0x05},
+				 {50, 0, 0x06},
+				 {100, 0, 0x06},
+				 {200, 0, 0x06},
+				 {400, 0, 0x06},
+				 {800, 0, 0x06},
+				 {1600, 0, 0x06} };
+
+static IIO_CONST_ATTR(accel_scale_available, "0.009582 0.019163 0.038326");
+static IIO_CONST_ATTR(magn_scale_available, "0.001465");
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+	"0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800");
+
+static struct attribute *kmx61_acc_attributes[] = {
+	&iio_const_attr_accel_scale_available.dev_attr.attr,
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute *kmx61_mag_attributes[] = {
+	&iio_const_attr_magn_scale_available.dev_attr.attr,
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group kmx61_acc_attribute_group = {
+	.attrs = kmx61_acc_attributes,
+};
+
+static const struct attribute_group kmx61_mag_attribute_group = {
+	.attrs = kmx61_mag_attributes,
+};
+
+static const struct iio_event_spec kmx61_event = {
+	.type = IIO_EV_TYPE_THRESH,
+	.dir = IIO_EV_DIR_EITHER,
+	.mask_separate = BIT(IIO_EV_INFO_VALUE) |
+			 BIT(IIO_EV_INFO_ENABLE) |
+			 BIT(IIO_EV_INFO_PERIOD),
+};
+
+#define KMX61_ACC_CHAN(_axis) { \
+	.type = IIO_ACCEL, \
+	.modified = 1, \
+	.channel2 = IIO_MOD_ ## _axis, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+				BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+	.address = KMX61_ACC, \
+	.scan_index = KMX61_AXIS_ ## _axis, \
+	.scan_type = { \
+		.sign = 's', \
+		.realbits = 12, \
+		.storagebits = 16, \
+		.shift = 4, \
+		.endianness = IIO_LE, \
+	}, \
+	.event_spec = &kmx61_event, \
+	.num_event_specs = 1 \
+}
+
+#define KMX61_MAG_CHAN(_axis) { \
+	.type = IIO_MAGN, \
+	.modified = 1, \
+	.channel2 = IIO_MOD_ ## _axis, \
+	.address = KMX61_MAG, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+				BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+	.scan_index = KMX61_AXIS_ ## _axis, \
+	.scan_type = { \
+		.sign = 's', \
+		.realbits = 14, \
+		.storagebits = 16, \
+		.shift = 2, \
+		.endianness = IIO_LE, \
+	}, \
+}
+
+static const struct iio_chan_spec kmx61_acc_channels[] = {
+	KMX61_ACC_CHAN(X),
+	KMX61_ACC_CHAN(Y),
+	KMX61_ACC_CHAN(Z),
+};
+
+static const struct iio_chan_spec kmx61_mag_channels[] = {
+	KMX61_MAG_CHAN(X),
+	KMX61_MAG_CHAN(Y),
+	KMX61_MAG_CHAN(Z),
+};
+
+static void kmx61_set_data(struct iio_dev *indio_dev, struct kmx61_data *data)
+{
+	struct kmx61_data **priv = iio_priv(indio_dev);
+
+	*priv = data;
+}
+
+static struct kmx61_data *kmx61_get_data(struct iio_dev *indio_dev)
+{
+	return *(struct kmx61_data **)iio_priv(indio_dev);
+}
+
+static int kmx61_convert_freq_to_bit(int val, int val2)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+		if (val == kmx61_samp_freq_table[i].val &&
+		    val2 == kmx61_samp_freq_table[i].val2)
+			return kmx61_samp_freq_table[i].odr_bits;
+	return -EINVAL;
+}
+
+static int kmx61_convert_bit_to_freq(u8 odr_bits, int *val, int *val2)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+		if (odr_bits == kmx61_samp_freq_table[i].odr_bits) {
+			*val = kmx61_samp_freq_table[i].val;
+			*val2 = kmx61_samp_freq_table[i].val2;
+			return 0;
+		}
+	return -EINVAL;
+}
+
+
+static int kmx61_convert_wake_up_odr_to_bit(int val, int val2)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(kmx61_wake_up_odr_table); ++i)
+		if (kmx61_wake_up_odr_table[i].val == val &&
+			kmx61_wake_up_odr_table[i].val2 == val2)
+				return kmx61_wake_up_odr_table[i].odr_bits;
+	return -EINVAL;
+}
+
+/**
+ * kmx61_set_mode() - set KMX61 device operating mode
+ * @data - kmx61 device private data pointer
+ * @mode - bitmask, indicating operating mode for @device
+ * @device - bitmask, indicating device for which @mode needs to be set
+ * @update - update stby bits stored in device's private  @data
+ *
+ * For each sensor (accelerometer/magnetometer) there are two operating modes
+ * STANDBY and OPERATION. Neither accel nor magn can be disabled independently
+ * if they are both enabled. Internal sensors state is saved in acc_stby and
+ * mag_stby members of driver's private @data.
+ */
+static int kmx61_set_mode(struct kmx61_data *data, u8 mode, u8 device,
+			  bool update)
+{
+	int ret;
+	int acc_stby = -1, mag_stby = -1;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_stby\n");
+		return ret;
+	}
+	if (device & KMX61_ACC) {
+		if (mode & KMX61_ACC_STBY_BIT) {
+			ret |= KMX61_ACC_STBY_BIT;
+			acc_stby = 1;
+		} else {
+			ret &= ~KMX61_ACC_STBY_BIT;
+			acc_stby = 0;
+		}
+	}
+
+	if (device & KMX61_MAG) {
+		if (mode & KMX61_MAG_STBY_BIT) {
+			ret |= KMX61_MAG_STBY_BIT;
+			mag_stby = 1;
+		} else {
+			ret &= ~KMX61_MAG_STBY_BIT;
+			mag_stby = 0;
+		}
+	}
+
+	if (mode & KMX61_ACT_STBY_BIT)
+		ret |= KMX61_ACT_STBY_BIT;
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_STBY, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_stby\n");
+		return ret;
+	}
+
+	if (acc_stby != -1 && update)
+		data->acc_stby = acc_stby;
+	if (mag_stby != -1 && update)
+		data->mag_stby = mag_stby;
+
+	return 0;
+}
+
+static int kmx61_get_mode(struct kmx61_data *data, u8 *mode, u8 device)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_stby\n");
+		return ret;
+	}
+	*mode = 0;
+
+	if (device & KMX61_ACC) {
+		if (ret & KMX61_ACC_STBY_BIT)
+			*mode |= KMX61_ACC_STBY_BIT;
+		else
+			*mode &= ~KMX61_ACC_STBY_BIT;
+	}
+
+	if (device & KMX61_MAG) {
+		if (ret & KMX61_MAG_STBY_BIT)
+			*mode |= KMX61_MAG_STBY_BIT;
+		else
+			*mode &= ~KMX61_MAG_STBY_BIT;
+	}
+
+	return 0;
+}
+
+static int kmx61_set_wake_up_odr(struct kmx61_data *data, int val, int val2)
+{
+	int ret, odr_bits;
+
+	odr_bits = kmx61_convert_wake_up_odr_to_bit(val, val2);
+	if (odr_bits < 0)
+		return odr_bits;
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL2,
+					odr_bits);
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
+	return ret;
+}
+
+static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device)
+{
+	int ret;
+	u8 mode;
+	int lodr_bits, odr_bits;
+
+	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+	if (ret < 0)
+		return ret;
+
+	lodr_bits = kmx61_convert_freq_to_bit(val, val2);
+	if (lodr_bits < 0)
+		return lodr_bits;
+
+	/* To change ODR, accel and magn must be in STDBY */
+	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
+			     true);
+	if (ret < 0)
+		return ret;
+
+	odr_bits = 0;
+	if (device & KMX61_ACC)
+		odr_bits |= lodr_bits << KMX61_ACC_ODR_SHIFT;
+	if (device & KMX61_MAG)
+		odr_bits |= lodr_bits << KMX61_MAG_ODR_SHIFT;
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_ODCNTL,
+					odr_bits);
+	if (ret < 0)
+		return ret;
+
+	data->odr_bits = odr_bits;
+
+	if (device & KMX61_ACC) {
+		ret = kmx61_set_wake_up_odr(data, val, val2);
+		if (ret)
+			return ret;
+	}
+
+	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
+			 u8 device)
+{	int i;
+	u8 lodr_bits;
+
+	if (device & KMX61_ACC)
+		lodr_bits = (data->odr_bits >> KMX61_ACC_ODR_SHIFT) &
+			     KMX61_ACC_ODR_MASK;
+	else if (device & KMX61_MAG)
+		lodr_bits = (data->odr_bits >> KMX61_MAG_ODR_SHIFT) &
+			     KMX61_MAG_ODR_MASK;
+	else
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+		if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) {
+			*val = kmx61_samp_freq_table[i].val;
+			*val2 = kmx61_samp_freq_table[i].val2;
+			return 0;
+		}
+	return -EINVAL;
+}
+
+static int kmx61_set_range(struct kmx61_data *data, u8 range)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+		return ret;
+	}
+
+	ret &= ~KMX61_REG_CTRL1_GSEL_MASK;
+	ret |= range & KMX61_REG_CTRL1_GSEL_MASK;
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+		return ret;
+	}
+
+	data->range = range;
+
+	return 0;
+}
+
+static int kmx61_set_scale(struct kmx61_data *data, u16 uscale)
+{
+	int ret, i;
+	u8  mode;
+
+	for (i = 0; i < ARRAY_SIZE(kmx61_uscale_table); i++) {
+		if (kmx61_uscale_table[i] == uscale) {
+			ret = kmx61_get_mode(data, &mode,
+					     KMX61_ACC | KMX61_MAG);
+			if (ret < 0)
+				return ret;
+
+			ret = kmx61_set_mode(data, KMX61_ALL_STBY,
+					     KMX61_ACC | KMX61_MAG, true);
+			if (ret < 0)
+				return ret;
+
+			ret = kmx61_set_range(data, i);
+			if (ret < 0)
+				return ret;
+
+			return  kmx61_set_mode(data, mode,
+					       KMX61_ACC | KMX61_MAG, true);
+		}
+	}
+	return -EINVAL;
+}
+
+static int kmx61_chip_init(struct kmx61_data *data)
+{
+	int ret, val, val2;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_WHO_AM_I);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading who_am_i\n");
+		return ret;
+	}
+
+	if (ret != KMX61_CHIP_ID) {
+		dev_err(&data->client->dev,
+			"Wrong chip id, got %x expected %x\n",
+			 ret, KMX61_CHIP_ID);
+		return -EINVAL;
+	}
+
+	/* set accel 12bit, 4g range */
+	ret = kmx61_set_range(data, KMX61_RANGE_4G);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_ODCNTL);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_odcntl\n");
+		return ret;
+	}
+	data->odr_bits = ret;
+
+	/* set output data rate for wake up (motion detection) function */
+	ret = kmx61_convert_bit_to_freq(data->odr_bits, &val, &val2);
+	if (ret < 0)
+		return ret;
+
+	ret = kmx61_set_wake_up_odr(data, val, val2);
+	if (ret < 0)
+		return ret;
+
+	/* set acc/magn to OPERATION mode */
+	ret = kmx61_set_mode(data, 0, KMX61_ACC | KMX61_MAG, true);
+	if (ret < 0)
+		return ret;
+
+	data->wake_thresh = KMX61_DEFAULT_WAKE_THRESH;
+	data->wake_duration = KMX61_DEFAULT_WAKE_DURATION;
+
+	return 0;
+}
+
+static int kmx61_setup_new_data_interrupt(struct kmx61_data *data,
+					  bool status, u8 device)
+{
+	u8 mode;
+	int ret;
+
+	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+	if (ret < 0)
+		return ret;
+
+	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+		return ret;
+	}
+
+	if (status) {
+		ret |= KMX61_REG_INC1_BIT_IEN;
+		if (device & KMX61_ACC)
+			ret |= KMX61_REG_INC1_BIT_DRDYA;
+		if (device & KMX61_MAG)
+			ret |=  KMX61_REG_INC1_BIT_DRDYM;
+	} else {
+		ret &= ~KMX61_REG_INC1_BIT_IEN;
+		if (device & KMX61_ACC)
+			ret &= ~KMX61_REG_INC1_BIT_DRDYA;
+		if (device & KMX61_MAG)
+			ret &= ~KMX61_REG_INC1_BIT_DRDYM;
+	}
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
+		return ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+		return ret;
+	}
+
+	if (status)
+		ret |= KMX61_REG_CTRL1_BIT_DRDYE;
+	else
+		ret &= ~KMX61_REG_CTRL1_BIT_DRDYE;
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+		return ret;
+	}
+
+	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+static int kmx61_chip_update_thresholds(struct kmx61_data *data)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(data->client,
+					KMX61_REG_WUF_TIMER,
+					data->wake_duration);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Errow writing reg_wuf_timer\n");
+		return ret;
+	}
+
+	ret = i2c_smbus_write_byte_data(data->client,
+					KMX61_REG_WUF_THRESH,
+					data->wake_thresh);
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error writing reg_wuf_thresh\n");
+
+	return ret;
+}
+
+static int kmx61_setup_any_motion_interrupt(struct kmx61_data *data,
+					    bool status)
+{
+	u8 mode;
+	int ret;
+
+	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+	if (ret < 0)
+		return ret;
+
+	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+	if (ret < 0)
+		return ret;
+
+	ret = kmx61_chip_update_thresholds(data);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_inc1\n");
+		return ret;
+	}
+	if (status)
+		ret |= (KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
+	else
+		ret &= ~(KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_inc1\n");
+		return ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+		return ret;
+	}
+
+	if (status)
+		ret |= KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE;
+	else
+		ret &= ~(KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE);
+
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+		return ret;
+	}
+	mode |= KMX61_ACT_STBY_BIT;
+	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+/**
+ * kmx61_set_power_state() - set power state for kmx61 @device
+ * @data - kmx61 device private pointer
+ * @on - power state to be set for @device
+ * @device - bitmask indicating device for which @on state needs to be set
+ *
+ * Notice that when ACC power state needs to be set to ON and MAG is in
+ * OPERATION then we know that kmx61_runtime_resume was already called
+ * so we must set ACC OPERATION mode here. The same happens when MAG power
+ * state needs to be set to ON and ACC is in OPERATION.
+ */
+static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (device & KMX61_ACC) {
+		if (on && !data->acc_ps && !data->mag_stby) {
+			ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
+			if (ret < 0)
+				return ret;
+		}
+		data->acc_ps = on;
+	}
+	if (device & KMX61_MAG) {
+		if (on && !data->mag_ps && !data->acc_stby) {
+			ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
+			if (ret < 0)
+				return ret;
+		}
+		data->mag_ps = on;
+	}
+
+	if (on) {
+		ret = pm_runtime_get_sync(&data->client->dev);
+	} else {
+		pm_runtime_mark_last_busy(&data->client->dev);
+		ret = pm_runtime_put_autosuspend(&data->client->dev);
+	}
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"Failed: kmx61_set_power_state for %d, ret %d\n",
+			on, ret);
+		if (on)
+			pm_runtime_put_noidle(&data->client->dev);
+
+		return ret;
+	}
+#endif
+	return 0;
+}
+
+static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 offset)
+{
+	int ret;
+	u8 reg = base + offset * 2;
+
+	ret = i2c_smbus_read_word_data(data->client, reg);
+	if (ret < 0)
+		dev_err(&data->client->dev, "failed to read reg at %x\n", reg);
+
+	return ret;
+}
+
+static int kmx61_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan, int *val,
+			  int *val2, long mask)
+{
+	int ret;
+	u8 base_reg;
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			base_reg = KMX61_ACC_XOUT_L;
+			break;
+		case IIO_MAGN:
+			base_reg = KMX61_MAG_XOUT_L;
+			break;
+		default:
+			return -EINVAL;
+		}
+		mutex_lock(&data->lock);
+
+		ret = kmx61_set_power_state(data, true, chan->address);
+		if (ret) {
+			mutex_unlock(&data->lock);
+			return ret;
+		}
+
+		ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
+		if (ret < 0) {
+			kmx61_set_power_state(data, false, chan->address);
+			mutex_unlock(&data->lock);
+			return ret;
+		}
+		*val = sign_extend32(ret >> chan->scan_type.shift,
+				     chan->scan_type.realbits - 1);
+		ret = kmx61_set_power_state(data, false, chan->address);
+
+		mutex_unlock(&data->lock);
+		if (ret)
+			return ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			*val = 0;
+			*val2 = kmx61_uscale_table[data->range];
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_MAGN:
+			/* 14 bits res, 1465 microGauss per magn count */
+			*val = 0;
+			*val2 = 1465;
+			return IIO_VAL_INT_PLUS_MICRO;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = kmx61_get_odr(data, val, val2, chan->address);
+		mutex_unlock(&data->lock);
+		if (ret)
+			return -EINVAL;
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+	return -EINVAL;
+}
+
+static int kmx61_write_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan, int val,
+			   int val2, long mask)
+{
+	int ret;
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = kmx61_set_odr(data, val, val2, chan->address);
+		mutex_unlock(&data->lock);
+		return ret;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			if (val != 0)
+				return -EINVAL;
+			mutex_lock(&data->lock);
+			ret = kmx61_set_scale(data, val2);
+			mutex_unlock(&data->lock);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kmx61_read_event(struct iio_dev *indio_dev,
+			    const struct iio_chan_spec *chan,
+			    enum iio_event_type type,
+			    enum iio_event_direction dir,
+			    enum iio_event_info info,
+			    int *val, int *val2)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	*val2 = 0;
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		*val = data->wake_thresh;
+		return IIO_VAL_INT;
+	case IIO_EV_INFO_PERIOD:
+		*val = data->wake_duration;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kmx61_write_event(struct iio_dev *indio_dev,
+			     const struct iio_chan_spec *chan,
+			     enum iio_event_type type,
+			     enum iio_event_direction dir,
+			     enum iio_event_info info,
+			     int val, int val2)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	if (data->ev_enable_state)
+		return -EBUSY;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		data->wake_thresh = val;
+		return IIO_VAL_INT;
+	case IIO_EV_INFO_PERIOD:
+		data->wake_duration = val;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kmx61_read_event_config(struct iio_dev *indio_dev,
+				   const struct iio_chan_spec *chan,
+				   enum iio_event_type type,
+				   enum iio_event_direction dir)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	return data->ev_enable_state;
+}
+
+static int kmx61_write_event_config(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir,
+				    int state)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+	int ret = 0;
+
+	if (state && data->ev_enable_state)
+		return 0;
+
+	mutex_lock(&data->lock);
+
+	if (!state && data->motion_trig_on) {
+		data->ev_enable_state = false;
+		goto err_unlock;
+	}
+
+	ret = kmx61_set_power_state(data, state, KMX61_ACC);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = kmx61_setup_any_motion_interrupt(data, state);
+	if (ret < 0) {
+		kmx61_set_power_state(data, false, KMX61_ACC);
+		goto err_unlock;
+	}
+
+	data->ev_enable_state = state;
+
+err_unlock:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev,
+				      struct iio_trigger *trig)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	if (data->acc_dready_trig != trig && data->motion_trig != trig)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int kmx61_mag_validate_trigger(struct iio_dev *indio_dev,
+				      struct iio_trigger *trig)
+{
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	if (data->mag_dready_trig != trig)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct iio_info kmx61_acc_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= kmx61_read_raw,
+	.write_raw		= kmx61_write_raw,
+	.attrs			= &kmx61_acc_attribute_group,
+	.read_event_value	= kmx61_read_event,
+	.write_event_value	= kmx61_write_event,
+	.read_event_config	= kmx61_read_event_config,
+	.write_event_config	= kmx61_write_event_config,
+	.validate_trigger	= kmx61_acc_validate_trigger,
+};
+
+static const struct iio_info kmx61_mag_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= kmx61_read_raw,
+	.write_raw		= kmx61_write_raw,
+	.attrs			= &kmx61_mag_attribute_group,
+	.validate_trigger	= kmx61_mag_validate_trigger,
+};
+
+
+static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
+					    bool state)
+{
+	int ret = 0;
+	u8 device;
+
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+	mutex_lock(&data->lock);
+
+	if (!state && data->ev_enable_state && data->motion_trig_on) {
+		data->motion_trig_on = false;
+		goto err_unlock;
+	}
+
+	if (data->acc_dready_trig == trig || data->motion_trig == trig)
+		device = KMX61_ACC;
+	else
+		device = KMX61_MAG;
+
+	ret = kmx61_set_power_state(data, state, device);
+	if (ret < 0)
+		goto err_unlock;
+
+	if (data->acc_dready_trig == trig || data->mag_dready_trig == trig)
+		ret = kmx61_setup_new_data_interrupt(data, state, device);
+	else
+		ret = kmx61_setup_any_motion_interrupt(data, state);
+	if (ret < 0) {
+		kmx61_set_power_state(data, false, device);
+		goto err_unlock;
+	}
+
+	if (data->acc_dready_trig == trig)
+		data->acc_dready_trig_on = state;
+	else if (data->mag_dready_trig == trig)
+		data->mag_dready_trig_on = state;
+	else
+		data->motion_trig_on = state;
+err_unlock:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int kmx61_trig_try_reenable(struct iio_trigger *trig)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_inl\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct iio_trigger_ops kmx61_trigger_ops = {
+	.set_trigger_state = kmx61_data_rdy_trigger_set_state,
+	.try_reenable = kmx61_trig_try_reenable,
+	.owner = THIS_MODULE,
+};
+
+static irqreturn_t kmx61_event_handler(int irq, void *private)
+{
+	struct kmx61_data *data = private;
+	struct iio_dev *indio_dev = data->acc_indio_dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS1);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading reg_ins1\n");
+		goto ack_intr;
+	}
+
+	if (ret & KMX61_REG_INS1_BIT_WUFS) {
+		ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS2);
+		if (ret < 0) {
+			dev_err(&data->client->dev, "Error reading reg_ins2\n");
+			goto ack_intr;
+		}
+
+		if (ret & KMX61_REG_INS2_BIT_XN)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_X,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_FALLING),
+				       0);
+
+		if (ret & KMX61_REG_INS2_BIT_XP)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_X,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_RISING),
+				       0);
+
+		if (ret & KMX61_REG_INS2_BIT_YN)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_Y,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_FALLING),
+				       0);
+
+		if (ret & KMX61_REG_INS2_BIT_YP)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_Y,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_RISING),
+				       0);
+
+		if (ret & KMX61_REG_INS2_BIT_ZN)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_Z,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_FALLING),
+				       0);
+
+		if (ret & KMX61_REG_INS2_BIT_ZP)
+			iio_push_event(indio_dev,
+				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
+				       0,
+				       IIO_MOD_Z,
+				       IIO_EV_TYPE_THRESH,
+				       IIO_EV_DIR_RISING),
+				       0);
+	}
+
+ack_intr:
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+
+	ret |= KMX61_REG_CTRL1_BIT_RES;
+	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+
+	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
+	if (ret < 0)
+		dev_err(&data->client->dev, "Error reading reg_inl\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private)
+{
+	struct kmx61_data *data = private;
+
+	if (data->acc_dready_trig_on)
+		iio_trigger_poll(data->acc_dready_trig);
+	if (data->mag_dready_trig_on)
+		iio_trigger_poll(data->mag_dready_trig);
+
+	if (data->motion_trig_on)
+		iio_trigger_poll(data->motion_trig);
+
+	if (data->ev_enable_state)
+		return IRQ_WAKE_THREAD;
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t kmx61_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct kmx61_data *data = kmx61_get_data(indio_dev);
+	int bit, ret, i = 0;
+	u8 base;
+	s16 buffer[8];
+
+	if (indio_dev == data->acc_indio_dev)
+		base = KMX61_ACC_XOUT_L;
+	else
+		base = KMX61_MAG_XOUT_L;
+
+	mutex_lock(&data->lock);
+	for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+			 indio_dev->masklength) {
+		ret = kmx61_read_measurement(data, base, bit);
+		if (ret < 0) {
+			mutex_unlock(&data->lock);
+			goto err;
+		}
+		buffer[i++] = ret;
+	}
+	mutex_unlock(&data->lock);
+
+	iio_push_to_buffers(indio_dev, buffer);
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static const char *kmx61_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+	return dev_name(dev);
+}
+
+static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+	return ret;
+}
+
+static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
+					    const struct iio_info *info,
+					    const struct iio_chan_spec *chan,
+					    int num_channels,
+					    const char *name)
+{
+	struct iio_dev *indio_dev;
+
+	indio_dev = devm_iio_device_alloc(&data->client->dev, sizeof(data));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+
+	kmx61_set_data(indio_dev, data);
+
+	indio_dev->dev.parent = &data->client->dev;
+	indio_dev->channels = chan;
+	indio_dev->num_channels = num_channels;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = info;
+
+	return indio_dev;
+}
+
+static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
+					       struct iio_dev *indio_dev,
+					       const char *tag)
+{
+	struct iio_trigger *trig;
+	int ret;
+
+	trig = devm_iio_trigger_alloc(&data->client->dev,
+				      "%s-%s-dev%d",
+				      indio_dev->name,
+				      tag,
+				      indio_dev->id);
+	if (!trig)
+		return ERR_PTR(-ENOMEM);
+
+	trig->dev.parent = &data->client->dev;
+	trig->ops = &kmx61_trigger_ops;
+	iio_trigger_set_drvdata(trig, indio_dev);
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return trig;
+}
+
+static int kmx61_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	int ret;
+	struct kmx61_data *data;
+	const char *name = NULL;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+
+	mutex_init(&data->lock);
+
+	if (id)
+		name = id->name;
+	else if (ACPI_HANDLE(&client->dev))
+		name = kmx61_match_acpi_device(&client->dev);
+	else
+		return -ENODEV;
+
+	data->acc_indio_dev =
+		kmx61_indiodev_setup(data, &kmx61_acc_info,
+				     kmx61_acc_channels,
+				     ARRAY_SIZE(kmx61_acc_channels),
+				     name);
+	if (IS_ERR(data->acc_indio_dev))
+		return PTR_ERR(data->acc_indio_dev);
+
+	data->mag_indio_dev =
+		kmx61_indiodev_setup(data, &kmx61_mag_info,
+				     kmx61_mag_channels,
+				     ARRAY_SIZE(kmx61_mag_channels),
+				     name);
+	if (IS_ERR(data->mag_indio_dev))
+		return PTR_ERR(data->mag_indio_dev);
+
+	ret = kmx61_chip_init(data);
+	if (ret < 0)
+		return ret;
+
+	if (client->irq < 0)
+		client->irq = kmx61_gpio_probe(client, data);
+
+	if (client->irq >= 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						kmx61_data_rdy_trig_poll,
+						kmx61_event_handler,
+						IRQF_TRIGGER_RISING,
+						KMX61_IRQ_NAME,
+						data);
+		if (ret)
+			goto err_chip_uninit;
+
+		data->acc_dready_trig =
+			kmx61_trigger_setup(data, data->acc_indio_dev,
+					    "dready");
+		if (IS_ERR(data->acc_dready_trig)) {
+			ret = PTR_ERR(data->acc_dready_trig);
+			goto err_chip_uninit;
+		}
+
+		data->mag_dready_trig =
+			kmx61_trigger_setup(data, data->mag_indio_dev,
+					    "dready");
+		if (IS_ERR(data->mag_dready_trig)) {
+			ret = PTR_ERR(data->mag_dready_trig);
+			goto err_trigger_unregister_acc_dready;
+		}
+
+		data->motion_trig =
+			kmx61_trigger_setup(data, data->acc_indio_dev,
+					    "any-motion");
+		if (IS_ERR(data->motion_trig)) {
+			ret = PTR_ERR(data->motion_trig);
+			goto err_trigger_unregister_mag_dready;
+		}
+
+		ret = iio_triggered_buffer_setup(data->acc_indio_dev,
+						 &iio_pollfunc_store_time,
+						 kmx61_trigger_handler,
+						 NULL);
+		if (ret < 0) {
+			dev_err(&data->client->dev,
+				"Failed to setup acc triggered buffer\n");
+			goto err_trigger_unregister_motion;
+		}
+
+		ret = iio_triggered_buffer_setup(data->mag_indio_dev,
+						 &iio_pollfunc_store_time,
+						 kmx61_trigger_handler,
+						 NULL);
+		if (ret < 0) {
+			dev_err(&data->client->dev,
+				"Failed to setup mag triggered buffer\n");
+			goto err_buffer_cleanup_acc;
+		}
+	}
+
+	ret = iio_device_register(data->acc_indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to register acc iio device\n");
+		goto err_buffer_cleanup_mag;
+	}
+
+	ret = iio_device_register(data->mag_indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to register mag iio device\n");
+		goto err_iio_unregister_acc;
+	}
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto err_iio_unregister_mag;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	return 0;
+
+err_iio_unregister_mag:
+	iio_device_unregister(data->mag_indio_dev);
+err_iio_unregister_acc:
+	iio_device_unregister(data->acc_indio_dev);
+err_buffer_cleanup_mag:
+	if (client->irq >= 0)
+		iio_triggered_buffer_cleanup(data->mag_indio_dev);
+err_buffer_cleanup_acc:
+	if (client->irq >= 0)
+		iio_triggered_buffer_cleanup(data->acc_indio_dev);
+err_trigger_unregister_motion:
+	iio_trigger_unregister(data->motion_trig);
+err_trigger_unregister_mag_dready:
+	iio_trigger_unregister(data->mag_dready_trig);
+err_trigger_unregister_acc_dready:
+	iio_trigger_unregister(data->acc_dready_trig);
+err_chip_uninit:
+	kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+	return ret;
+}
+
+static int kmx61_remove(struct i2c_client *client)
+{
+	struct kmx61_data *data = i2c_get_clientdata(client);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	iio_device_unregister(data->acc_indio_dev);
+	iio_device_unregister(data->mag_indio_dev);
+
+	if (client->irq >= 0) {
+		iio_triggered_buffer_cleanup(data->acc_indio_dev);
+		iio_triggered_buffer_cleanup(data->mag_indio_dev);
+		iio_trigger_unregister(data->acc_dready_trig);
+		iio_trigger_unregister(data->mag_dready_trig);
+		iio_trigger_unregister(data->motion_trig);
+	}
+
+	mutex_lock(&data->lock);
+	kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+	mutex_unlock(&data->lock);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int kmx61_suspend(struct device *dev)
+{
+	int ret;
+	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+	mutex_lock(&data->lock);
+	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
+			     false);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int kmx61_resume(struct device *dev)
+{
+	u8 stby = 0;
+	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+	if (data->acc_stby)
+		stby |= KMX61_ACC_STBY_BIT;
+	if (data->mag_stby)
+		stby |= KMX61_MAG_STBY_BIT;
+
+	return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int kmx61_runtime_suspend(struct device *dev)
+{
+	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+	int ret;
+
+	mutex_lock(&data->lock);
+	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int kmx61_runtime_resume(struct device *dev)
+{
+	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+	u8 stby = 0;
+
+	if (!data->acc_ps)
+		stby |= KMX61_ACC_STBY_BIT;
+	if (!data->mag_ps)
+		stby |= KMX61_MAG_STBY_BIT;
+
+	return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
+}
+#endif
+
+static const struct dev_pm_ops kmx61_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume)
+	SET_RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id kmx61_acpi_match[] = {
+	{"KMX61021", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match);
+
+static const struct i2c_device_id kmx61_id[] = {
+	{"kmx611021", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, kmx61_id);
+
+static struct i2c_driver kmx61_driver = {
+	.driver = {
+		.name = KMX61_DRV_NAME,
+		.acpi_match_table = ACPI_PTR(kmx61_acpi_match),
+		.pm = &kmx61_pm_ops,
+	},
+	.probe		= kmx61_probe,
+	.remove		= kmx61_remove,
+	.id_table	= kmx61_id,
+};
+
+module_i2c_driver(kmx61_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("KMX61 accelerometer/magnetometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index f971f79..7133314 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -178,6 +178,80 @@
 	return sprintf(buf, "%d\n", ret);
 }
 
+/* Note NULL used as error indicator as it doesn't make sense. */
+static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
+					  unsigned int masklength,
+					  const unsigned long *mask)
+{
+	if (bitmap_empty(mask, masklength))
+		return NULL;
+	while (*av_masks) {
+		if (bitmap_subset(mask, av_masks, masklength))
+			return av_masks;
+		av_masks += BITS_TO_LONGS(masklength);
+	}
+	return NULL;
+}
+
+static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
+	const unsigned long *mask)
+{
+	if (!indio_dev->setup_ops->validate_scan_mask)
+		return true;
+
+	return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
+}
+
+/**
+ * iio_scan_mask_set() - set particular bit in the scan mask
+ * @indio_dev: the iio device
+ * @buffer: the buffer whose scan mask we are interested in
+ * @bit: the bit to be set.
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
+static int iio_scan_mask_set(struct iio_dev *indio_dev,
+		      struct iio_buffer *buffer, int bit)
+{
+	const unsigned long *mask;
+	unsigned long *trialmask;
+
+	trialmask = kmalloc(sizeof(*trialmask)*
+			    BITS_TO_LONGS(indio_dev->masklength),
+			    GFP_KERNEL);
+
+	if (trialmask == NULL)
+		return -ENOMEM;
+	if (!indio_dev->masklength) {
+		WARN_ON("Trying to set scanmask prior to registering buffer\n");
+		goto err_invalid_mask;
+	}
+	bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
+	set_bit(bit, trialmask);
+
+	if (!iio_validate_scan_mask(indio_dev, trialmask))
+		goto err_invalid_mask;
+
+	if (indio_dev->available_scan_masks) {
+		mask = iio_scan_mask_match(indio_dev->available_scan_masks,
+					   indio_dev->masklength,
+					   trialmask);
+		if (!mask)
+			goto err_invalid_mask;
+	}
+	bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
+
+	kfree(trialmask);
+
+	return 0;
+
+err_invalid_mask:
+	kfree(trialmask);
+	return -EINVAL;
+}
+
 static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
 {
 	clear_bit(bit, buffer->scan_mask);
@@ -309,115 +383,19 @@
 	return ret;
 }
 
-static const char * const iio_scan_elements_group_name = "scan_elements";
-
-int iio_buffer_register(struct iio_dev *indio_dev,
-			const struct iio_chan_spec *channels,
-			int num_channels)
-{
-	struct iio_dev_attr *p;
-	struct attribute **attr;
-	struct iio_buffer *buffer = indio_dev->buffer;
-	int ret, i, attrn, attrcount, attrcount_orig = 0;
-
-	if (buffer->attrs)
-		indio_dev->groups[indio_dev->groupcounter++] = buffer->attrs;
-
-	if (buffer->scan_el_attrs != NULL) {
-		attr = buffer->scan_el_attrs->attrs;
-		while (*attr++ != NULL)
-			attrcount_orig++;
-	}
-	attrcount = attrcount_orig;
-	INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
-	if (channels) {
-		/* new magic */
-		for (i = 0; i < num_channels; i++) {
-			if (channels[i].scan_index < 0)
-				continue;
-
-			/* Establish necessary mask length */
-			if (channels[i].scan_index >
-			    (int)indio_dev->masklength - 1)
-				indio_dev->masklength
-					= channels[i].scan_index + 1;
-
-			ret = iio_buffer_add_channel_sysfs(indio_dev,
-							 &channels[i]);
-			if (ret < 0)
-				goto error_cleanup_dynamic;
-			attrcount += ret;
-			if (channels[i].type == IIO_TIMESTAMP)
-				indio_dev->scan_index_timestamp =
-					channels[i].scan_index;
-		}
-		if (indio_dev->masklength && buffer->scan_mask == NULL) {
-			buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
-						    sizeof(*buffer->scan_mask),
-						    GFP_KERNEL);
-			if (buffer->scan_mask == NULL) {
-				ret = -ENOMEM;
-				goto error_cleanup_dynamic;
-			}
-		}
-	}
-
-	buffer->scan_el_group.name = iio_scan_elements_group_name;
-
-	buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
-					      sizeof(buffer->scan_el_group.attrs[0]),
-					      GFP_KERNEL);
-	if (buffer->scan_el_group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_free_scan_mask;
-	}
-	if (buffer->scan_el_attrs)
-		memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
-		       sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
-	attrn = attrcount_orig;
-
-	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
-		buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
-	indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
-
-	return 0;
-
-error_free_scan_mask:
-	kfree(buffer->scan_mask);
-error_cleanup_dynamic:
-	iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
-
-	return ret;
-}
-EXPORT_SYMBOL(iio_buffer_register);
-
-void iio_buffer_unregister(struct iio_dev *indio_dev)
-{
-	kfree(indio_dev->buffer->scan_mask);
-	kfree(indio_dev->buffer->scan_el_group.attrs);
-	iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
-}
-EXPORT_SYMBOL(iio_buffer_unregister);
-
-ssize_t iio_buffer_read_length(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
+static ssize_t iio_buffer_read_length(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct iio_buffer *buffer = indio_dev->buffer;
 
-	if (buffer->access->get_length)
-		return sprintf(buf, "%d\n",
-			       buffer->access->get_length(buffer));
-
-	return 0;
+	return sprintf(buf, "%d\n", buffer->length);
 }
-EXPORT_SYMBOL(iio_buffer_read_length);
 
-ssize_t iio_buffer_write_length(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len)
+static ssize_t iio_buffer_write_length(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct iio_buffer *buffer = indio_dev->buffer;
@@ -428,47 +406,28 @@
 	if (ret)
 		return ret;
 
-	if (buffer->access->get_length)
-		if (val == buffer->access->get_length(buffer))
-			return len;
+	if (val == buffer->length)
+		return len;
 
 	mutex_lock(&indio_dev->mlock);
 	if (iio_buffer_is_active(indio_dev->buffer)) {
 		ret = -EBUSY;
 	} else {
-		if (buffer->access->set_length)
-			buffer->access->set_length(buffer, val);
+		buffer->access->set_length(buffer, val);
 		ret = 0;
 	}
 	mutex_unlock(&indio_dev->mlock);
 
 	return ret ? ret : len;
 }
-EXPORT_SYMBOL(iio_buffer_write_length);
 
-ssize_t iio_buffer_show_enable(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
+static ssize_t iio_buffer_show_enable(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer));
 }
-EXPORT_SYMBOL(iio_buffer_show_enable);
-
-/* Note NULL used as error indicator as it doesn't make sense. */
-static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
-					  unsigned int masklength,
-					  const unsigned long *mask)
-{
-	if (bitmap_empty(mask, masklength))
-		return NULL;
-	while (*av_masks) {
-		if (bitmap_subset(mask, av_masks, masklength))
-			return av_masks;
-		av_masks += BITS_TO_LONGS(masklength);
-	}
-	return NULL;
-}
 
 static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
 				const unsigned long *mask, bool timestamp)
@@ -680,6 +639,8 @@
 		indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
 	} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
 		indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+	} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
+		indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
 	} else { /* Should never be reached */
 		ret = -EINVAL;
 		goto error_run_postdisable;
@@ -755,10 +716,10 @@
 }
 EXPORT_SYMBOL_GPL(iio_update_buffers);
 
-ssize_t iio_buffer_store_enable(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len)
+static ssize_t iio_buffer_store_enable(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf,
+				       size_t len)
 {
 	int ret;
 	bool requested_state;
@@ -790,7 +751,130 @@
 	mutex_unlock(&indio_dev->mlock);
 	return (ret < 0) ? ret : len;
 }
-EXPORT_SYMBOL(iio_buffer_store_enable);
+
+static const char * const iio_scan_elements_group_name = "scan_elements";
+
+static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
+		   iio_buffer_write_length);
+static struct device_attribute dev_attr_length_ro = __ATTR(length,
+	S_IRUGO, iio_buffer_read_length, NULL);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
+		   iio_buffer_show_enable, iio_buffer_store_enable);
+
+int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+{
+	struct iio_dev_attr *p;
+	struct attribute **attr;
+	struct iio_buffer *buffer = indio_dev->buffer;
+	int ret, i, attrn, attrcount, attrcount_orig = 0;
+	const struct iio_chan_spec *channels;
+
+	if (!buffer)
+		return 0;
+
+	attrcount = 0;
+	if (buffer->attrs) {
+		while (buffer->attrs[attrcount] != NULL)
+			attrcount++;
+	}
+
+	buffer->buffer_group.name = "buffer";
+	buffer->buffer_group.attrs = kcalloc(attrcount + 3,
+			sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
+	if (!buffer->buffer_group.attrs)
+		return -ENOMEM;
+
+	if (buffer->access->set_length)
+		buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
+	else
+		buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
+	buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
+	if (buffer->attrs)
+		memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
+			sizeof(*&buffer->buffer_group.attrs) * attrcount);
+	buffer->buffer_group.attrs[attrcount+2] = NULL;
+
+	indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
+
+	if (buffer->scan_el_attrs != NULL) {
+		attr = buffer->scan_el_attrs->attrs;
+		while (*attr++ != NULL)
+			attrcount_orig++;
+	}
+	attrcount = attrcount_orig;
+	INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
+	channels = indio_dev->channels;
+	if (channels) {
+		/* new magic */
+		for (i = 0; i < indio_dev->num_channels; i++) {
+			if (channels[i].scan_index < 0)
+				continue;
+
+			/* Establish necessary mask length */
+			if (channels[i].scan_index >
+			    (int)indio_dev->masklength - 1)
+				indio_dev->masklength
+					= channels[i].scan_index + 1;
+
+			ret = iio_buffer_add_channel_sysfs(indio_dev,
+							 &channels[i]);
+			if (ret < 0)
+				goto error_cleanup_dynamic;
+			attrcount += ret;
+			if (channels[i].type == IIO_TIMESTAMP)
+				indio_dev->scan_index_timestamp =
+					channels[i].scan_index;
+		}
+		if (indio_dev->masklength && buffer->scan_mask == NULL) {
+			buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
+						    sizeof(*buffer->scan_mask),
+						    GFP_KERNEL);
+			if (buffer->scan_mask == NULL) {
+				ret = -ENOMEM;
+				goto error_cleanup_dynamic;
+			}
+		}
+	}
+
+	buffer->scan_el_group.name = iio_scan_elements_group_name;
+
+	buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
+					      sizeof(buffer->scan_el_group.attrs[0]),
+					      GFP_KERNEL);
+	if (buffer->scan_el_group.attrs == NULL) {
+		ret = -ENOMEM;
+		goto error_free_scan_mask;
+	}
+	if (buffer->scan_el_attrs)
+		memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
+		       sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
+	attrn = attrcount_orig;
+
+	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
+		buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
+	indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
+
+	return 0;
+
+error_free_scan_mask:
+	kfree(buffer->scan_mask);
+error_cleanup_dynamic:
+	iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+	kfree(indio_dev->buffer->buffer_group.attrs);
+
+	return ret;
+}
+
+void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
+{
+	if (!indio_dev->buffer)
+		return;
+
+	kfree(indio_dev->buffer->scan_mask);
+	kfree(indio_dev->buffer->buffer_group.attrs);
+	kfree(indio_dev->buffer->scan_el_group.attrs);
+	iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
+}
 
 /**
  * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected
@@ -808,66 +892,6 @@
 }
 EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
 
-static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
-	const unsigned long *mask)
-{
-	if (!indio_dev->setup_ops->validate_scan_mask)
-		return true;
-
-	return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
-}
-
-/**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @indio_dev: the iio device
- * @buffer: the buffer whose scan mask we are interested in
- * @bit: the bit to be set.
- *
- * Note that at this point we have no way of knowing what other
- * buffers might request, hence this code only verifies that the
- * individual buffers request is plausible.
- */
-int iio_scan_mask_set(struct iio_dev *indio_dev,
-		      struct iio_buffer *buffer, int bit)
-{
-	const unsigned long *mask;
-	unsigned long *trialmask;
-
-	trialmask = kmalloc(sizeof(*trialmask)*
-			    BITS_TO_LONGS(indio_dev->masklength),
-			    GFP_KERNEL);
-
-	if (trialmask == NULL)
-		return -ENOMEM;
-	if (!indio_dev->masklength) {
-		WARN_ON("Trying to set scanmask prior to registering buffer\n");
-		goto err_invalid_mask;
-	}
-	bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
-	set_bit(bit, trialmask);
-
-	if (!iio_validate_scan_mask(indio_dev, trialmask))
-		goto err_invalid_mask;
-
-	if (indio_dev->available_scan_masks) {
-		mask = iio_scan_mask_match(indio_dev->available_scan_masks,
-					   indio_dev->masklength,
-					   trialmask);
-		if (!mask)
-			goto err_invalid_mask;
-	}
-	bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
-
-	kfree(trialmask);
-
-	return 0;
-
-err_invalid_mask:
-	kfree(trialmask);
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(iio_scan_mask_set);
-
 int iio_scan_mask_query(struct iio_dev *indio_dev,
 			struct iio_buffer *buffer, int bit)
 {
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index af3e76d..aaba9d3 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -70,6 +70,11 @@
 	[IIO_CCT] = "cct",
 	[IIO_PRESSURE] = "pressure",
 	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
+	[IIO_ACTIVITY] = "activity",
+	[IIO_STEPS] = "steps",
+	[IIO_ENERGY] = "energy",
+	[IIO_DISTANCE] = "distance",
+	[IIO_VELOCITY] = "velocity",
 };
 
 static const char * const iio_modifier_names[] = {
@@ -91,6 +96,11 @@
 	[IIO_MOD_NORTH_TRUE] = "from_north_true",
 	[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
 	[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
+	[IIO_MOD_RUNNING] = "running",
+	[IIO_MOD_JOGGING] = "jogging",
+	[IIO_MOD_WALKING] = "walking",
+	[IIO_MOD_STILL] = "still",
+	[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
 };
 
 /* relies on pairs of these shared then separate */
@@ -113,6 +123,11 @@
 	[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
 	[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
 	[IIO_CHAN_INFO_INT_TIME] = "integration_time",
+	[IIO_CHAN_INFO_ENABLE] = "en",
+	[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
+	[IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
+	[IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count",
+	[IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
 };
 
 /**
@@ -1035,7 +1050,6 @@
 	if (!ptr)
 		return NULL;
 
-	/* use raw alloc_dr for kmalloc caller tracing */
 	iio_dev = iio_device_alloc(sizeof_priv);
 	if (iio_dev) {
 		*ptr = iio_dev;
@@ -1127,6 +1141,29 @@
 	.compat_ioctl = iio_ioctl,
 };
 
+static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
+{
+	int i, j;
+	const struct iio_chan_spec *channels = indio_dev->channels;
+
+	if (!(indio_dev->modes & INDIO_ALL_BUFFER_MODES))
+		return 0;
+
+	for (i = 0; i < indio_dev->num_channels - 1; i++) {
+		if (channels[i].scan_index < 0)
+			continue;
+		for (j = i + 1; j < indio_dev->num_channels; j++)
+			if (channels[i].scan_index == channels[j].scan_index) {
+				dev_err(&indio_dev->dev,
+					"Duplicate scan index %d\n",
+					channels[i].scan_index);
+				return -EINVAL;
+			}
+	}
+
+	return 0;
+}
+
 static const struct iio_buffer_setup_ops noop_ring_setup_ops;
 
 /**
@@ -1141,6 +1178,10 @@
 	if (!indio_dev->dev.of_node && indio_dev->dev.parent)
 		indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
 
+	ret = iio_check_unique_scan_index(indio_dev);
+	if (ret < 0)
+		return ret;
+
 	/* configure elements for the chrdev */
 	indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
 
@@ -1150,11 +1191,19 @@
 			"Failed to register debugfs interfaces\n");
 		return ret;
 	}
+
+	ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"Failed to create buffer sysfs interfaces\n");
+		goto error_unreg_debugfs;
+	}
+
 	ret = iio_device_register_sysfs(indio_dev);
 	if (ret) {
 		dev_err(indio_dev->dev.parent,
 			"Failed to register sysfs interfaces\n");
-		goto error_unreg_debugfs;
+		goto error_buffer_free_sysfs;
 	}
 	ret = iio_device_register_eventset(indio_dev);
 	if (ret) {
@@ -1187,6 +1236,8 @@
 	iio_device_unregister_eventset(indio_dev);
 error_free_sysfs:
 	iio_device_unregister_sysfs(indio_dev);
+error_buffer_free_sysfs:
+	iio_buffer_free_sysfs_and_mask(indio_dev);
 error_unreg_debugfs:
 	iio_device_unregister_debugfs(indio_dev);
 	return ret;
@@ -1215,6 +1266,8 @@
 	iio_buffer_wakeup_poll(indio_dev);
 
 	mutex_unlock(&indio_dev->info_exist_lock);
+
+	iio_buffer_free_sysfs_and_mask(indio_dev);
 }
 EXPORT_SYMBOL(iio_device_unregister);
 
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 0c1e37e..a4b3970 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -197,6 +197,7 @@
 	[IIO_EV_TYPE_ROC] = "roc",
 	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
 	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+	[IIO_EV_TYPE_CHANGE] = "change",
 };
 
 static const char * const iio_ev_dir_text[] = {
@@ -327,9 +328,15 @@
 	for_each_set_bit(i, mask, sizeof(*mask)*8) {
 		if (i >= ARRAY_SIZE(iio_ev_info_text))
 			return -EINVAL;
-		postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
-				iio_ev_type_text[type], iio_ev_dir_text[dir],
-				iio_ev_info_text[i]);
+		if (dir != IIO_EV_DIR_NONE)
+			postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
+					iio_ev_type_text[type],
+					iio_ev_dir_text[dir],
+					iio_ev_info_text[i]);
+		else
+			postfix = kasprintf(GFP_KERNEL, "%s_%s",
+					iio_ev_type_text[type],
+					iio_ev_info_text[i]);
 		if (postfix == NULL)
 			return -ENOMEM;
 
@@ -404,7 +411,7 @@
 {
 	int j, ret, attrcount = 0;
 
-	/* Dynically created from the channels array */
+	/* Dynamically created from the channels array */
 	for (j = 0; j < indio_dev->num_channels; j++) {
 		ret = iio_device_add_event_sysfs(indio_dev,
 						 &indio_dev->channels[j]);
diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c
index d6f54930..15a5341 100644
--- a/drivers/iio/industrialio-triggered-buffer.c
+++ b/drivers/iio/industrialio-triggered-buffer.c
@@ -32,7 +32,7 @@
  *
  * This function combines some common tasks which will normally be performed
  * when setting up a triggered buffer. It will allocate the buffer and the
- * pollfunc, as well as register the buffer with the IIO core.
+ * pollfunc.
  *
  * Before calling this function the indio_dev structure should already be
  * completely initialized, but not yet registered. In practice this means that
@@ -49,7 +49,7 @@
 	struct iio_buffer *buffer;
 	int ret;
 
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (!buffer) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -78,16 +78,8 @@
 	/* Flag that polled ring buffering is possible */
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 
-	ret = iio_buffer_register(indio_dev,
-				  indio_dev->channels,
-				  indio_dev->num_channels);
-	if (ret)
-		goto error_dealloc_pollfunc;
-
 	return 0;
 
-error_dealloc_pollfunc:
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
 error_kfifo_free:
 	iio_kfifo_free(indio_dev->buffer);
 error_ret:
@@ -101,7 +93,6 @@
  */
 void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
 {
-	iio_buffer_unregister(indio_dev);
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
 	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 90c8cb7..c8bad3c 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -116,8 +116,11 @@
 	if (!iiospec->args_count)
 		return 0;
 
-	if (iiospec->args[0] >= indio_dev->num_channels)
+	if (iiospec->args[0] >= indio_dev->num_channels) {
+		dev_err(&indio_dev->dev, "invalid channel index %u\n",
+			iiospec->args[0]);
 		return -EINVAL;
+	}
 
 	return iiospec->args[0];
 }
@@ -634,3 +637,28 @@
 	return ret;
 }
 EXPORT_SYMBOL_GPL(iio_get_channel_type);
+
+static int iio_channel_write(struct iio_channel *chan, int val, int val2,
+			     enum iio_chan_info_enum info)
+{
+	return chan->indio_dev->info->write_raw(chan->indio_dev,
+						chan->channel, val, val2, info);
+}
+
+int iio_write_channel_raw(struct iio_channel *chan, int val)
+{
+	int ret;
+
+	mutex_lock(&chan->indio_dev->info_exist_lock);
+	if (chan->indio_dev->info == NULL) {
+		ret = -ENODEV;
+		goto err_unlock;
+	}
+
+	ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW);
+err_unlock:
+	mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_raw);
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 7134e8a..b2beea0 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -47,30 +47,6 @@
 	return ret;
 }
 
-static int iio_get_length_kfifo(struct iio_buffer *r)
-{
-	return r->length;
-}
-
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
-static struct attribute *iio_kfifo_attributes[] = {
-	&dev_attr_length.attr,
-	&dev_attr_enable.attr,
-	NULL,
-};
-
-static struct attribute_group iio_kfifo_attribute_group = {
-	.attrs = iio_kfifo_attributes,
-	.name = "buffer",
-};
-
-static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
-{
-	return r->bytes_per_datum;
-}
-
 static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
 {
 	struct iio_kfifo *kf = iio_to_kfifo(r);
@@ -159,26 +135,25 @@
 	.read_first_n = &iio_read_first_n_kfifo,
 	.data_available = iio_kfifo_buf_data_available,
 	.request_update = &iio_request_update_kfifo,
-	.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
 	.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
-	.get_length = &iio_get_length_kfifo,
 	.set_length = &iio_set_length_kfifo,
 	.release = &iio_kfifo_buffer_release,
 };
 
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
+struct iio_buffer *iio_kfifo_allocate(void)
 {
 	struct iio_kfifo *kf;
 
-	kf = kzalloc(sizeof *kf, GFP_KERNEL);
+	kf = kzalloc(sizeof(*kf), GFP_KERNEL);
 	if (!kf)
 		return NULL;
+
 	kf->update_needed = true;
 	iio_buffer_init(&kf->buffer);
-	kf->buffer.attrs = &iio_kfifo_attribute_group;
 	kf->buffer.access = &kfifo_access_funcs;
 	kf->buffer.length = 2;
 	mutex_init(&kf->user_lock);
+
 	return &kf->buffer;
 }
 EXPORT_SYMBOL(iio_kfifo_allocate);
@@ -189,4 +164,58 @@
 }
 EXPORT_SYMBOL(iio_kfifo_free);
 
+static void devm_iio_kfifo_release(struct device *dev, void *res)
+{
+	iio_kfifo_free(*(struct iio_buffer **)res);
+}
+
+static int devm_iio_kfifo_match(struct device *dev, void *res, void *data)
+{
+	struct iio_buffer **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+/**
+ * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
+ * @dev:		Device to allocate kfifo buffer for
+ *
+ * RETURNS:
+ * Pointer to allocated iio_buffer on success, NULL on failure.
+ */
+struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
+{
+	struct iio_buffer **ptr, *r;
+
+	ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	r = iio_kfifo_allocate();
+	if (r) {
+		*ptr = r;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return r;
+}
+EXPORT_SYMBOL(devm_iio_kfifo_allocate);
+
+/**
+ * devm_iio_fifo_free - Resource-managed iio_kfifo_free()
+ * @dev:		Device the buffer belongs to
+ * @r:			The buffer associated with the device
+ */
+void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r)
+{
+	WARN_ON(devres_release(dev, devm_iio_kfifo_release,
+			       devm_iio_kfifo_match, r));
+}
+EXPORT_SYMBOL(devm_iio_kfifo_free);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 5bea821..ae68c64 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -48,6 +48,17 @@
 	 To compile this driver as a module, choose M here:
 	 the module will be called cm32181.
 
+config CM3232
+	depends on I2C
+	tristate "CM3232 ambient light sensor"
+	help
+	 Say Y here if you use cm3232.
+	 This option enables ambient light sensor using
+	 Capella Microsystems cm3232 device driver.
+
+	 To compile this driver as a module, choose M here:
+	 the module will be called cm3232.
+
 config CM36651
 	depends on I2C
 	tristate "CM36651 driver"
@@ -95,6 +106,9 @@
 	  Say yes here to build support for the HID SENSOR
 	  Ambient light sensor.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called hid-sensor-als.
+
 config HID_SENSOR_PROX
 	depends on HID_SENSOR_HUB
 	select IIO_BUFFER
@@ -109,6 +123,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called hid-sensor-prox.
 
+config JSA1212
+	tristate "JSA1212 ALS and proximity sensor driver"
+	depends on I2C
+	help
+	 Say Y here if you want to build a IIO driver for JSA1212
+	 proximity & ALS sensor device.
+
+	 To compile this driver as a module, choose M here:
+	 the module will be called jsa1212.
+
 config SENSORS_LM3533
 	tristate "LM3533 ambient light sensor"
 	depends on MFD_LM3533
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 47877a3..b12a516 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -7,11 +7,13 @@
 obj-$(CONFIG_AL3320A)		+= al3320a.o
 obj-$(CONFIG_APDS9300)		+= apds9300.o
 obj-$(CONFIG_CM32181)		+= cm32181.o
+obj-$(CONFIG_CM3232)		+= cm3232.o
 obj-$(CONFIG_CM36651)		+= cm36651.o
 obj-$(CONFIG_GP2AP020A00F)	+= gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)	+= hid-sensor-als.o
 obj-$(CONFIG_HID_SENSOR_PROX)	+= hid-sensor-prox.o
 obj-$(CONFIG_ISL29125)		+= isl29125.o
+obj-$(CONFIG_JSA1212)		+= jsa1212.o
 obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
 obj-$(CONFIG_LTR501)		+= ltr501.o
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index ad36b29..5d12ae54 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -169,7 +169,7 @@
  * @cm32181:	pointer of struct cm32181.
  *
  * Convert sensor raw data to lux.  It depends on integration
- * time and claibscale variable.
+ * time and calibscale variable.
  *
  * Return: Positive value is lux, otherwise is error code.
  */
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
new file mode 100644
index 0000000..90e3519
--- /dev/null
+++ b/drivers/iio/light/cm3232.c
@@ -0,0 +1,403 @@
+/*
+ * CM3232 Ambient Light Sensor
+ *
+ * Copyright (C) 2014-2015 Capella Microsystems Inc.
+ * Author: Kevin Tsai <ktsai@capellamicro.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.
+ *
+ * IIO driver for CM3232 (7-bit I2C slave address 0x10).
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/init.h>
+
+/* Registers Address */
+#define CM3232_REG_ADDR_CMD		0x00
+#define CM3232_REG_ADDR_ALS		0x50
+#define CM3232_REG_ADDR_ID		0x53
+
+#define CM3232_CMD_ALS_DISABLE		BIT(0)
+
+#define CM3232_CMD_ALS_IT_SHIFT		2
+#define CM3232_CMD_ALS_IT_MASK		(BIT(2) | BIT(3) | BIT(4))
+#define CM3232_CMD_ALS_IT_DEFAULT	(0x01 << CM3232_CMD_ALS_IT_SHIFT)
+
+#define CM3232_CMD_ALS_RESET		BIT(6)
+
+#define CM3232_CMD_DEFAULT		CM3232_CMD_ALS_IT_DEFAULT
+
+#define CM3232_HW_ID			0x32
+#define CM3232_CALIBSCALE_DEFAULT	100000
+#define CM3232_CALIBSCALE_RESOLUTION	100000
+#define CM3232_MLUX_PER_LUX		1000
+
+#define CM3232_MLUX_PER_BIT_DEFAULT	64
+#define CM3232_MLUX_PER_BIT_BASE_IT	100000
+
+static const struct {
+	int val;
+	int val2;
+	u8 it;
+} cm3232_als_it_scales[] = {
+	{0, 100000, 0},	/* 0.100000 */
+	{0, 200000, 1},	/* 0.200000 */
+	{0, 400000, 2},	/* 0.400000 */
+	{0, 800000, 3},	/* 0.800000 */
+	{1, 600000, 4},	/* 1.600000 */
+	{3, 200000, 5},	/* 3.200000 */
+};
+
+struct cm3232_als_info {
+	u8 regs_cmd_default;
+	u8 hw_id;
+	int calibscale;
+	int mlux_per_bit;
+	int mlux_per_bit_base_it;
+};
+
+static struct cm3232_als_info cm3232_als_info_default = {
+	.regs_cmd_default = CM3232_CMD_DEFAULT,
+	.hw_id = CM3232_HW_ID,
+	.calibscale = CM3232_CALIBSCALE_DEFAULT,
+	.mlux_per_bit = CM3232_MLUX_PER_BIT_DEFAULT,
+	.mlux_per_bit_base_it = CM3232_MLUX_PER_BIT_BASE_IT,
+};
+
+struct cm3232_chip {
+	struct i2c_client *client;
+	struct cm3232_als_info *als_info;
+	u8 regs_cmd;
+	u16 regs_als;
+};
+
+/**
+ * cm3232_reg_init() - Initialize CM3232
+ * @chip:	pointer of struct cm3232_chip.
+ *
+ * Check and initialize CM3232 ambient light sensor.
+ *
+ * Return: 0 for success; otherwise for error code.
+ */
+static int cm3232_reg_init(struct cm3232_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	s32 ret;
+
+	chip->als_info = &cm3232_als_info_default;
+
+	/* Identify device */
+	ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "Error reading addr_id\n");
+		return ret;
+	}
+
+	if ((ret & 0xFF) != chip->als_info->hw_id)
+		return -ENODEV;
+
+	/* Disable and reset device */
+	chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
+	ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+					chip->regs_cmd);
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "Error writing reg_cmd\n");
+		return ret;
+	}
+
+	/* Register default value */
+	chip->regs_cmd = chip->als_info->regs_cmd_default;
+
+	/* Configure register */
+	ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+					chip->regs_cmd);
+	if (ret < 0)
+		dev_err(&chip->client->dev, "Error writing reg_cmd\n");
+
+	return 0;
+}
+
+/**
+ *  cm3232_read_als_it() - Get sensor integration time
+ *  @chip:	pointer of struct cm3232_chip
+ *  @val:	pointer of int to load the integration (sec).
+ *  @val2:	pointer of int to load the integration time (microsecond).
+ *
+ *  Report the current integration time.
+ *
+ *  Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
+ */
+static int cm3232_read_als_it(struct cm3232_chip *chip, int *val, int *val2)
+{
+	u16 als_it;
+	int i;
+
+	als_it = chip->regs_cmd;
+	als_it &= CM3232_CMD_ALS_IT_MASK;
+	als_it >>= CM3232_CMD_ALS_IT_SHIFT;
+	for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
+		if (als_it == cm3232_als_it_scales[i].it) {
+			*val = cm3232_als_it_scales[i].val;
+			*val2 = cm3232_als_it_scales[i].val2;
+			return IIO_VAL_INT_PLUS_MICRO;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * cm3232_write_als_it() - Write sensor integration time
+ * @chip:	pointer of struct cm3232_chip.
+ * @val:	integration time in second.
+ * @val2:	integration time in microsecond.
+ *
+ * Convert integration time to sensor value.
+ *
+ * Return: i2c_smbus_write_byte_data command return value.
+ */
+static int cm3232_write_als_it(struct cm3232_chip *chip, int val, int val2)
+{
+	struct i2c_client *client = chip->client;
+	u16 als_it, cmd;
+	int i;
+	s32 ret;
+
+	for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
+		if (val == cm3232_als_it_scales[i].val &&
+			val2 == cm3232_als_it_scales[i].val2) {
+
+			als_it = cm3232_als_it_scales[i].it;
+			als_it <<= CM3232_CMD_ALS_IT_SHIFT;
+
+			cmd = chip->regs_cmd & ~CM3232_CMD_ALS_IT_MASK;
+			cmd |= als_it;
+			ret = i2c_smbus_write_byte_data(client,
+							CM3232_REG_ADDR_CMD,
+							cmd);
+			if (ret < 0)
+				return ret;
+			chip->regs_cmd = cmd;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+/**
+ * cm3232_get_lux() - report current lux value
+ * @chip:	pointer of struct cm3232_chip.
+ *
+ * Convert sensor data to lux.  It depends on integration
+ * time and calibscale variable.
+ *
+ * Return: Zero or positive value is lux, otherwise error code.
+ */
+static int cm3232_get_lux(struct cm3232_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	struct cm3232_als_info *als_info = chip->als_info;
+	int ret;
+	int val, val2;
+	int als_it;
+	u64 lux;
+
+	/* Calculate mlux per bit based on als_it */
+	ret = cm3232_read_als_it(chip, &val, &val2);
+	if (ret < 0)
+		return -EINVAL;
+	als_it = val * 1000000 + val2;
+	lux = (__force u64)als_info->mlux_per_bit;
+	lux *= als_info->mlux_per_bit_base_it;
+	lux = div_u64(lux, als_it);
+
+	ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ALS);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading reg_addr_als\n");
+		return ret;
+	}
+
+	chip->regs_als = (u16)ret;
+	lux *= chip->regs_als;
+	lux *= als_info->calibscale;
+	lux = div_u64(lux, CM3232_CALIBSCALE_RESOLUTION);
+	lux = div_u64(lux, CM3232_MLUX_PER_LUX);
+
+	if (lux > 0xFFFF)
+		lux = 0xFFFF;
+
+	return (int)lux;
+}
+
+static int cm3232_read_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val, int *val2, long mask)
+{
+	struct cm3232_chip *chip = iio_priv(indio_dev);
+	struct cm3232_als_info *als_info = chip->als_info;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = cm3232_get_lux(chip);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		*val = als_info->calibscale;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_INT_TIME:
+		return cm3232_read_als_it(chip, val, val2);
+	}
+
+	return -EINVAL;
+}
+
+static int cm3232_write_raw(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int val, int val2, long mask)
+{
+	struct cm3232_chip *chip = iio_priv(indio_dev);
+	struct cm3232_als_info *als_info = chip->als_info;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_CALIBSCALE:
+		als_info->calibscale = val;
+		return 0;
+	case IIO_CHAN_INFO_INT_TIME:
+		return cm3232_write_als_it(chip, val, val2);
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * cm3232_get_it_available() - Get available ALS IT value
+ * @dev:	pointer of struct device.
+ * @attr:	pointer of struct device_attribute.
+ * @buf:	pointer of return string buffer.
+ *
+ * Display the available integration time in second.
+ *
+ * Return: string length.
+ */
+static ssize_t cm3232_get_it_available(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int i, len;
+
+	for (i = 0, len = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
+			cm3232_als_it_scales[i].val,
+			cm3232_als_it_scales[i].val2);
+	return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
+}
+
+static const struct iio_chan_spec cm3232_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_PROCESSED) |
+			BIT(IIO_CHAN_INFO_CALIBSCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME),
+	}
+};
+
+static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
+			S_IRUGO, cm3232_get_it_available, NULL, 0);
+
+static struct attribute *cm3232_attributes[] = {
+	&iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group cm3232_attribute_group = {
+	.attrs = cm3232_attributes
+};
+
+static const struct iio_info cm3232_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= &cm3232_read_raw,
+	.write_raw		= &cm3232_write_raw,
+	.attrs			= &cm3232_attribute_group,
+};
+
+static int cm3232_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct cm3232_chip *chip;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	chip = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	chip->client = client;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = cm3232_channels;
+	indio_dev->num_channels = ARRAY_SIZE(cm3232_channels);
+	indio_dev->info = &cm3232_info;
+	indio_dev->name = id->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = cm3232_reg_init(chip);
+	if (ret) {
+		dev_err(&client->dev,
+			"%s: register init failed\n",
+			__func__);
+		return ret;
+	}
+
+	return iio_device_register(indio_dev);
+}
+
+static int cm3232_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+		CM3232_CMD_ALS_DISABLE);
+
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id cm3232_id[] = {
+	{"cm3232", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, cm3232_id);
+
+static const struct of_device_id cm3232_of_match[] = {
+	{.compatible = "capella,cm3232"},
+	{}
+};
+
+static struct i2c_driver cm3232_driver = {
+	.driver = {
+		.name	= "cm3232",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(cm3232_of_match),
+	},
+	.id_table	= cm3232_id,
+	.probe		= cm3232_probe,
+	.remove		= cm3232_remove,
+};
+
+module_i2c_driver(cm3232_driver);
+
+MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
+MODULE_DESCRIPTION("CM3232 ambient light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index a5283d7..948acfc 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -80,7 +80,6 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
@@ -97,15 +96,8 @@
 			break;
 		}
 		if (report_id >= 0) {
-			poll_value = hid_sensor_read_poll_value(
-						&als_state->common_attributes);
-			if (poll_value < 0)
-				return -EINVAL;
-
 			hid_sensor_power_state(&als_state->common_attributes,
 						true);
-			msleep_interruptible(poll_value * 2);
-
 			*val = sensor_hub_input_attr_get_raw_value(
 					als_state->common_attributes.hsdev,
 					HID_USAGE_SENSOR_ALS, address,
@@ -381,6 +373,7 @@
 	.id_table = hid_als_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_als_probe,
 	.remove		= hid_als_remove,
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index f5a5146..3ecf79e 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -75,7 +75,6 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
@@ -92,16 +91,8 @@
 			break;
 		}
 		if (report_id >= 0) {
-			poll_value = hid_sensor_read_poll_value(
-					&prox_state->common_attributes);
-			if (poll_value < 0)
-				return -EINVAL;
-
 			hid_sensor_power_state(&prox_state->common_attributes,
 						true);
-
-			msleep_interruptible(poll_value * 2);
-
 			*val = sensor_hub_input_attr_get_raw_value(
 				prox_state->common_attributes.hsdev,
 				HID_USAGE_SENSOR_PROX, address,
@@ -373,6 +364,7 @@
 	.id_table = hid_prox_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_prox_probe,
 	.remove		= hid_prox_remove,
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
new file mode 100644
index 0000000..29de7e7
--- /dev/null
+++ b/drivers/iio/light/jsa1212.c
@@ -0,0 +1,471 @@
+/*
+ * JSA1212 Ambient Light & Proximity Sensor Driver
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * 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.
+ *
+ * JSA1212 I2C slave address: 0x44(ADDR tied to GND), 0x45(ADDR tied to VDD)
+ *
+ * TODO: Interrupt support, thresholds, range support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* JSA1212 reg address */
+#define JSA1212_CONF_REG		0x01
+#define JSA1212_INT_REG			0x02
+#define JSA1212_PXS_LT_REG		0x03
+#define JSA1212_PXS_HT_REG		0x04
+#define JSA1212_ALS_TH1_REG		0x05
+#define JSA1212_ALS_TH2_REG		0x06
+#define JSA1212_ALS_TH3_REG		0x07
+#define JSA1212_PXS_DATA_REG		0x08
+#define JSA1212_ALS_DT1_REG		0x09
+#define JSA1212_ALS_DT2_REG		0x0A
+#define JSA1212_ALS_RNG_REG		0x0B
+#define JSA1212_MAX_REG			0x0C
+
+/* JSA1212 reg masks */
+#define JSA1212_CONF_MASK		0xFF
+#define JSA1212_INT_MASK		0xFF
+#define JSA1212_PXS_LT_MASK		0xFF
+#define JSA1212_PXS_HT_MASK		0xFF
+#define JSA1212_ALS_TH1_MASK		0xFF
+#define JSA1212_ALS_TH2_LT_MASK		0x0F
+#define JSA1212_ALS_TH2_HT_MASK		0xF0
+#define JSA1212_ALS_TH3_MASK		0xFF
+#define JSA1212_PXS_DATA_MASK		0xFF
+#define JSA1212_ALS_DATA_MASK		0x0FFF
+#define JSA1212_ALS_DT1_MASK		0xFF
+#define JSA1212_ALS_DT2_MASK		0x0F
+#define JSA1212_ALS_RNG_MASK		0x07
+
+/* JSA1212 CONF REG bits */
+#define JSA1212_CONF_PXS_MASK		0x80
+#define JSA1212_CONF_PXS_ENABLE		0x80
+#define JSA1212_CONF_PXS_DISABLE	0x00
+#define JSA1212_CONF_ALS_MASK		0x04
+#define JSA1212_CONF_ALS_ENABLE		0x04
+#define JSA1212_CONF_ALS_DISABLE	0x00
+#define JSA1212_CONF_IRDR_MASK		0x08
+/* Proxmity sensing IRDR current sink settings */
+#define JSA1212_CONF_IRDR_200MA		0x08
+#define JSA1212_CONF_IRDR_100MA		0x00
+#define JSA1212_CONF_PXS_SLP_MASK	0x70
+#define JSA1212_CONF_PXS_SLP_0MS	0x70
+#define JSA1212_CONF_PXS_SLP_12MS	0x60
+#define JSA1212_CONF_PXS_SLP_50MS	0x50
+#define JSA1212_CONF_PXS_SLP_75MS	0x40
+#define JSA1212_CONF_PXS_SLP_100MS	0x30
+#define JSA1212_CONF_PXS_SLP_200MS	0x20
+#define JSA1212_CONF_PXS_SLP_400MS	0x10
+#define JSA1212_CONF_PXS_SLP_800MS	0x00
+
+/* JSA1212 INT REG bits */
+#define JSA1212_INT_CTRL_MASK		0x01
+#define JSA1212_INT_CTRL_EITHER		0x00
+#define JSA1212_INT_CTRL_BOTH		0x01
+#define JSA1212_INT_ALS_PRST_MASK	0x06
+#define JSA1212_INT_ALS_PRST_1CONV	0x00
+#define JSA1212_INT_ALS_PRST_4CONV	0x02
+#define JSA1212_INT_ALS_PRST_8CONV	0x04
+#define JSA1212_INT_ALS_PRST_16CONV	0x06
+#define JSA1212_INT_ALS_FLAG_MASK	0x08
+#define JSA1212_INT_ALS_FLAG_CLR	0x00
+#define JSA1212_INT_PXS_PRST_MASK	0x60
+#define JSA1212_INT_PXS_PRST_1CONV	0x00
+#define JSA1212_INT_PXS_PRST_4CONV	0x20
+#define JSA1212_INT_PXS_PRST_8CONV	0x40
+#define JSA1212_INT_PXS_PRST_16CONV	0x60
+#define JSA1212_INT_PXS_FLAG_MASK	0x80
+#define JSA1212_INT_PXS_FLAG_CLR	0x00
+
+/* JSA1212 ALS RNG REG bits */
+#define JSA1212_ALS_RNG_0_2048		0x00
+#define JSA1212_ALS_RNG_0_1024		0x01
+#define JSA1212_ALS_RNG_0_512		0x02
+#define JSA1212_ALS_RNG_0_256		0x03
+#define JSA1212_ALS_RNG_0_128		0x04
+
+/* JSA1212 INT threshold range */
+#define JSA1212_ALS_TH_MIN	0x0000
+#define JSA1212_ALS_TH_MAX	0x0FFF
+#define JSA1212_PXS_TH_MIN	0x00
+#define JSA1212_PXS_TH_MAX	0xFF
+
+#define JSA1212_ALS_DELAY_MS	200
+#define JSA1212_PXS_DELAY_MS	100
+
+#define JSA1212_DRIVER_NAME	"jsa1212"
+#define JSA1212_REGMAP_NAME	"jsa1212_regmap"
+
+enum jsa1212_op_mode {
+	JSA1212_OPMODE_ALS_EN,
+	JSA1212_OPMODE_PXS_EN,
+};
+
+struct jsa1212_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	u8 als_rng_idx;
+	bool als_en; /* ALS enable status */
+	bool pxs_en; /* proximity enable status */
+	struct regmap *regmap;
+};
+
+/* ALS range idx to val mapping */
+static const int jsa1212_als_range_val[] = {2048, 1024, 512, 256, 128,
+						128, 128, 128};
+
+/* Enables or disables ALS function based on status */
+static int jsa1212_als_enable(struct jsa1212_data *data, u8 status)
+{
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+				JSA1212_CONF_ALS_MASK,
+				status);
+	if (ret < 0)
+		return ret;
+
+	data->als_en = !!status;
+
+	return 0;
+}
+
+/* Enables or disables PXS function based on status */
+static int jsa1212_pxs_enable(struct jsa1212_data *data, u8 status)
+{
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+				JSA1212_CONF_PXS_MASK,
+				status);
+	if (ret < 0)
+		return ret;
+
+	data->pxs_en = !!status;
+
+	return 0;
+}
+
+static int jsa1212_read_als_data(struct jsa1212_data *data,
+				unsigned int *val)
+{
+	int ret;
+	__le16 als_data;
+
+	ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Delay for data output */
+	msleep(JSA1212_ALS_DELAY_MS);
+
+	/* Read 12 bit data */
+	ret = regmap_bulk_read(data->regmap, JSA1212_ALS_DT1_REG, &als_data, 2);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "als data read err\n");
+		goto als_data_read_err;
+	}
+
+	*val = le16_to_cpu(als_data);
+
+als_data_read_err:
+	return jsa1212_als_enable(data, JSA1212_CONF_ALS_DISABLE);
+}
+
+static int jsa1212_read_pxs_data(struct jsa1212_data *data,
+				unsigned int *val)
+{
+	int ret;
+	unsigned int pxs_data;
+
+	ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Delay for data output */
+	msleep(JSA1212_PXS_DELAY_MS);
+
+	/* Read out all data */
+	ret = regmap_read(data->regmap, JSA1212_PXS_DATA_REG, &pxs_data);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "pxs data read err\n");
+		goto pxs_data_read_err;
+	}
+
+	*val = pxs_data & JSA1212_PXS_DATA_MASK;
+
+pxs_data_read_err:
+	return jsa1212_pxs_enable(data, JSA1212_CONF_PXS_DISABLE);
+}
+
+static int jsa1212_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	int ret;
+	struct jsa1212_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+		switch (chan->type) {
+		case IIO_LIGHT:
+			ret = jsa1212_read_als_data(data, val);
+			break;
+		case IIO_PROXIMITY:
+			ret = jsa1212_read_pxs_data(data, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		mutex_unlock(&data->lock);
+		return ret < 0 ? ret : IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			*val = jsa1212_als_range_val[data->als_rng_idx];
+			*val2 = BIT(12); /* Max 12 bit value */
+			return IIO_VAL_FRACTIONAL;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_chan_spec jsa1212_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+	},
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+	}
+};
+
+static const struct iio_info jsa1212_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= &jsa1212_read_raw,
+};
+
+static int jsa1212_chip_init(struct jsa1212_data *data)
+{
+	int ret;
+
+	ret = regmap_write(data->regmap, JSA1212_CONF_REG,
+				(JSA1212_CONF_PXS_SLP_50MS |
+				JSA1212_CONF_IRDR_200MA));
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, JSA1212_INT_REG,
+				JSA1212_INT_ALS_PRST_4CONV);
+	if (ret < 0)
+		return ret;
+
+	data->als_rng_idx = JSA1212_ALS_RNG_0_2048;
+
+	return 0;
+}
+
+static bool jsa1212_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case JSA1212_PXS_DATA_REG:
+	case JSA1212_ALS_DT1_REG:
+	case JSA1212_ALS_DT2_REG:
+	case JSA1212_INT_REG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static struct regmap_config jsa1212_regmap_config = {
+	.name =  JSA1212_REGMAP_NAME,
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = JSA1212_MAX_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = jsa1212_is_volatile_reg,
+};
+
+static int jsa1212_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct jsa1212_data *data;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	regmap = devm_regmap_init_i2c(client, &jsa1212_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "Regmap initialization failed.\n");
+		return PTR_ERR(regmap);
+	}
+
+	data = iio_priv(indio_dev);
+
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+	data->regmap = regmap;
+
+	mutex_init(&data->lock);
+
+	ret = jsa1212_chip_init(data);
+	if (ret < 0)
+		return ret;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = jsa1212_channels;
+	indio_dev->num_channels = ARRAY_SIZE(jsa1212_channels);
+	indio_dev->name = JSA1212_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	indio_dev->info = &jsa1212_info;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		dev_err(&client->dev, "%s: register device failed\n", __func__);
+
+	return ret;
+}
+
+ /* power off the device */
+static int jsa1212_power_off(struct jsa1212_data *data)
+{
+	int ret;
+
+	mutex_lock(&data->lock);
+
+	ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+				JSA1212_CONF_ALS_MASK |
+				JSA1212_CONF_PXS_MASK,
+				JSA1212_CONF_ALS_DISABLE |
+				JSA1212_CONF_PXS_DISABLE);
+
+	if (ret < 0)
+		dev_err(&data->client->dev, "power off cmd failed\n");
+
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int jsa1212_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct jsa1212_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	return jsa1212_power_off(data);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int jsa1212_suspend(struct device *dev)
+{
+	struct jsa1212_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return jsa1212_power_off(data);
+}
+
+static int jsa1212_resume(struct device *dev)
+{
+	int ret = 0;
+	struct jsa1212_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	mutex_lock(&data->lock);
+
+	if (data->als_en) {
+		ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
+		if (ret < 0) {
+			dev_err(dev, "als resume failed\n");
+			goto unlock_and_ret;
+		}
+	}
+
+	if (data->pxs_en) {
+		ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
+		if (ret < 0)
+			dev_err(dev, "pxs resume failed\n");
+	}
+
+unlock_and_ret:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, jsa1212_resume);
+
+#define JSA1212_PM_OPS (&jsa1212_pm_ops)
+#else
+#define JSA1212_PM_OPS NULL
+#endif
+
+static const struct acpi_device_id jsa1212_acpi_match[] = {
+	{"JSA1212", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
+
+static const struct i2c_device_id jsa1212_id[] = {
+	{ JSA1212_DRIVER_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, jsa1212_id);
+
+static struct i2c_driver jsa1212_driver = {
+	.driver = {
+		.name	= JSA1212_DRIVER_NAME,
+		.pm	= JSA1212_PM_OPS,
+		.owner	= THIS_MODULE,
+		.acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
+	},
+	.probe		= jsa1212_probe,
+	.remove		= jsa1212_remove,
+	.id_table	= jsa1212_id,
+};
+module_i2c_driver(jsa1212_driver);
+
+MODULE_AUTHOR("Sathya Kuppuswamy <sathyanarayanan.kuppuswamy@linux.intel.com>");
+MODULE_DESCRIPTION("JSA1212 proximity/ambient light sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index ae3c71b..076bc46 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -657,7 +657,7 @@
 #define ILLUMINANCE_ATTR_RO(_name) \
 	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
 #define ILLUMINANCE_ATTR_RW(_name) \
-	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR , \
+	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR, \
 						show_##_name, store_##_name)
 /*
  * ALS Zone threshold-event enable
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index a9e449b..71c2bde 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -149,8 +149,8 @@
 		*val = ret;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-	i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
-	*val = tcs3414_scales[i][0];
+		i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
+		*val = tcs3414_scales[i][0];
 		*val2 = tcs3414_scales[i][1];
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_INT_TIME:
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e..4c7a4c5 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,26 +6,21 @@
 menu "Magnetometer sensors"
 
 config AK8975
-	tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB
 	help
-	  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-	  Magnetometer. This driver can also support AK8963, if i2c
-	  device name is identified as ak8963.
+	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
+	  AK09911 or AK09912 3-Axis Magnetometer.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called ak8975.
 
 config AK09911
 	tristate "Asahi Kasei AK09911 3-axis Compass"
-	depends on I2C
+	select AK8975
 	help
-	  Say yes here to build support for Asahi Kasei AK09911 3-Axis
-	  Magnetometer.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called ak09911.
+	  Deprecated: AK09911 is now supported by AK8975 driver.
 
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e..0f5d3c9 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
 #
 
 # When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911)	+= ak09911.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942..0000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * Copyright (c) 2014, Intel Corporation.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1		0x00
-#define AK09911_REG_WIA2		0x01
-#define AK09911_WIA1_VALUE		0x48
-#define AK09911_WIA2_VALUE		0x05
-
-#define AK09911_REG_ST1			0x10
-#define AK09911_REG_HXL			0x11
-#define AK09911_REG_HXH			0x12
-#define AK09911_REG_HYL			0x13
-#define AK09911_REG_HYH			0x14
-#define AK09911_REG_HZL			0x15
-#define AK09911_REG_HZH			0x16
-
-#define AK09911_REG_ASAX		0x60
-#define AK09911_REG_ASAY		0x61
-#define AK09911_REG_ASAZ		0x62
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_MODE_SNG_MEASURE	0x01
-#define AK09911_MODE_SELF_TEST		0x10
-#define AK09911_MODE_FUSE_ACCESS	0x1F
-#define AK09911_MODE_POWERDOWN		0x00
-#define AK09911_RESET_DATA		0x01
-
-#define AK09911_REG_CNTL1		0x30
-#define AK09911_REG_CNTL2		0x31
-#define AK09911_REG_CNTL3		0x32
-
-#define AK09911_RAW_TO_GAUSS(asa)	((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS	500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS	10
-
-struct ak09911_data {
-	struct i2c_client	*client;
-	struct mutex		lock;
-	u8			asa[3];
-	long			raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
-	AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
-	int ret;
-
-	switch (mode) {
-	case AK09911_MODE_SNG_MEASURE:
-	case AK09911_MODE_SELF_TEST:
-	case AK09911_MODE_FUSE_ACCESS:
-	case AK09911_MODE_POWERDOWN:
-		ret = i2c_smbus_write_byte_data(client,
-						AK09911_REG_CNTL2, mode);
-		if (ret < 0) {
-			dev_err(&client->dev, "set_mode error\n");
-			return ret;
-		}
-		/* After mode change wait atleast 100us */
-		usleep_range(100, 500);
-		break;
-	default:
-		dev_err(&client->dev,
-			"%s: Unknown mode(%d).", __func__, mode);
-		return -EINVAL;
-	}
-
-	return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak09911_data *data = iio_priv(indio_dev);
-	int ret;
-
-	ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
-	if (ret < 0)
-		return ret;
-
-	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
-					    3, data->asa);
-	if (ret < 0) {
-		dev_err(&client->dev, "Not able to read asa data\n");
-		return ret;
-	}
-
-	ret = ak09911_set_mode(client,  AK09911_MODE_POWERDOWN);
-	if (ret < 0)
-		return ret;
-
-	data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
-	data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
-	data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
-	return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
-	u8 wia_val[2];
-	int ret;
-
-	ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
-					    2, wia_val);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-
-	dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
-	if (wia_val[0] != AK09911_WIA1_VALUE ||
-		wia_val[1] != AK09911_WIA2_VALUE) {
-		dev_err(&client->dev, "Device ak09911 not found\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
-	struct i2c_client *client = data->client;
-	u8 read_status;
-	u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
-	int ret;
-
-	/* Wait for the conversion to complete. */
-	while (timeout_ms) {
-		msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
-		ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
-		if (ret < 0) {
-			dev_err(&client->dev, "Error in reading ST1\n");
-			return ret;
-		}
-		read_status = ret & 0x01;
-		if (read_status)
-			break;
-		timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
-	}
-	if (!timeout_ms) {
-		dev_err(&client->dev, "Conversion timeout happened\n");
-		return -EIO;
-	}
-
-	return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
-	ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
-	if (ret < 0)
-		goto fn_exit;
-
-	ret = wait_conversion_complete_polled(data);
-	if (ret < 0)
-		goto fn_exit;
-
-	/* Read data */
-	ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
-		goto fn_exit;
-	}
-
-	mutex_unlock(&data->lock);
-
-	/* Clamp to valid range. */
-	*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
-	return IIO_VAL_INT;
-
-fn_exit:
-	mutex_unlock(&data->lock);
-
-	return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
-			    struct iio_chan_spec const *chan,
-			    int *val, int *val2,
-			    long mask)
-{
-	struct ak09911_data *data = iio_priv(indio_dev);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return ak09911_read_axis(indio_dev, chan->address, val);
-	case IIO_CHAN_INFO_SCALE:
-		*val = 0;
-		*val2 = data->raw_to_gauss[chan->address];
-		return IIO_VAL_INT_PLUS_MICRO;
-	}
-
-	return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index)					\
-	{								\
-		.type = IIO_MAGN,					\
-		.modified = 1,						\
-		.channel2 = IIO_MOD_##axis,				\
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			     BIT(IIO_CHAN_INFO_SCALE),			\
-		.address = index,					\
-	}
-
-static const struct iio_chan_spec ak09911_channels[] = {
-	AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
-	.read_raw = &ak09911_read_raw,
-	.driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
-	{"AK009911", 0},
-	{ },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	struct iio_dev *indio_dev;
-	struct ak09911_data *data;
-	const char *name;
-	int ret;
-
-	ret = ak09911_verify_chip_id(client);
-	if (ret) {
-		dev_err(&client->dev, "AK00911 not detected\n");
-		return -ENODEV;
-	}
-
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
-	if (indio_dev == NULL)
-		return -ENOMEM;
-
-	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-
-	data->client = client;
-	mutex_init(&data->lock);
-
-	ret = ak09911_get_asa(client);
-	if (ret)
-		return ret;
-
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = dev_name(&client->dev);
-	else
-		return -ENODEV;
-
-	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
-	indio_dev->dev.parent = &client->dev;
-	indio_dev->channels = ak09911_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
-	indio_dev->info = &ak09911_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->name = name;
-
-	return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
-	{"ak09911", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
-	.driver = {
-		.name	= "ak09911",
-		.acpi_match_table = ACPI_PTR(ak_acpi_match),
-	},
-	.probe		= ak09911_probe,
-	.id_table	= ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef07..b13936d 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -64,10 +64,10 @@
 #define AK8975_REG_CNTL			0x0A
 #define AK8975_REG_CNTL_MODE_SHIFT	0
 #define AK8975_REG_CNTL_MODE_MASK	(0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN	0
-#define AK8975_REG_CNTL_MODE_ONCE	1
-#define AK8975_REG_CNTL_MODE_SELF_TEST	8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM	0xF
+#define AK8975_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK8975_REG_CNTL_MODE_ONCE	0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST	0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM	0x0F
 
 #define AK8975_REG_RSVC			0x0B
 #define AK8975_REG_ASTC			0x0C
@@ -81,18 +81,278 @@
 #define AK8975_MAX_REGS			AK8975_REG_ASAZ
 
 /*
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1		0x00
+#define AK09912_REG_WIA2		0x01
+#define AK09912_DEVICE_ID		0x04
+#define AK09911_DEVICE_ID		0x05
+
+#define AK09911_REG_INFO1		0x02
+#define AK09911_REG_INFO2		0x03
+
+#define AK09912_REG_ST1			0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT	0
+#define AK09912_REG_ST1_DRDY_MASK	(1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL			0x11
+#define AK09912_REG_HXH			0x12
+#define AK09912_REG_HYL			0x13
+#define AK09912_REG_HYH			0x14
+#define AK09912_REG_HZL			0x15
+#define AK09912_REG_HZH			0x16
+#define AK09912_REG_TMPS		0x17
+
+#define AK09912_REG_ST2			0x18
+#define AK09912_REG_ST2_HOFL_SHIFT	3
+#define AK09912_REG_ST2_HOFL_MASK	(1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1		0x30
+
+#define AK09912_REG_CNTL2		0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN	0x00
+#define AK09912_REG_CNTL_MODE_ONCE	0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST	0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM	0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT	0
+#define AK09912_REG_CNTL2_MODE_MASK	(0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3		0x32
+
+#define AK09912_REG_TS1			0x33
+#define AK09912_REG_TS2			0x34
+#define AK09912_REG_TS3			0x35
+#define AK09912_REG_I2CDIS		0x36
+#define AK09912_REG_TS4			0x37
+
+#define AK09912_REG_ASAX		0x60
+#define AK09912_REG_ASAY		0x61
+#define AK09912_REG_ASAZ		0x62
+
+#define AK09912_MAX_REGS		AK09912_REG_ASAZ
+
+/*
  * Miscellaneous values.
  */
 #define AK8975_MAX_CONVERSION_TIMEOUT	500
 #define AK8975_CONVERSION_DONE_POLL_TIME 10
 #define AK8975_DATA_READY_TIMEOUT	((100*HZ)/1000)
-#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
-#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
+
+/*
+ * Precalculate scale factor (in Gauss units) for each axis and
+ * store in the device data.
+ *
+ * This scale factor is axis-dependent, and is derived from 3 calibration
+ * factors ASA(x), ASA(y), and ASA(z).
+ *
+ * These ASA values are read from the sensor device at start of day, and
+ * cached in the device context struct.
+ *
+ * Adjusting the flux value with the sensitivity adjustment value should be
+ * done via the following formula:
+ *
+ * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
+ * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
+ * is the resultant adjusted value.
+ *
+ * We reduce the formula to:
+ *
+ * Hadj = H * (ASA + 128) / 256
+ *
+ * H is in the range of -4096 to 4095.  The magnetometer has a range of
+ * +-1229uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 1229/4096, or roughly, 3/10.
+ *
+ * Since 1uT = 0.01 gauss, our final scale factor becomes:
+ *
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
+ *
+ * Since ASA doesn't change, we cache the resultant scale factor into the
+ * device context in ak8975_setup().
+ *
+ * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
+ * multiply the stored scale value by 1e6.
+ */
+static long ak8975_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 3000) / 256;
+}
+
+/*
+ * For AK8963 and AK09911, same calculation, but the device is less sensitive:
+ *
+ * H is in the range of +-8190.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
+ */
+
+static long ak8963_09911_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 6000) / 256;
+}
+
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752.  The magnetometer has a range of
+ * +-4912uT.  To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+static long ak09912_raw_to_gauss(u16 data)
+{
+	return (((long)data + 128) * 1500) / 256;
+}
 
 /* Compatible Asahi Kasei Compass parts */
 enum asahi_compass_chipset {
 	AK8975,
 	AK8963,
+	AK09911,
+	AK09912,
+	AK_MAX_TYPE
+};
+
+enum ak_ctrl_reg_addr {
+	ST1,
+	ST2,
+	CNTL,
+	ASA_BASE,
+	MAX_REGS,
+	REGS_END,
+};
+
+enum ak_ctrl_reg_mask {
+	ST1_DRDY,
+	ST2_HOFL,
+	ST2_DERR,
+	CNTL_MODE,
+	MASK_END,
+};
+
+enum ak_ctrl_mode {
+	POWER_DOWN,
+	MODE_ONCE,
+	SELF_TEST,
+	FUSE_ROM,
+	MODE_END,
+};
+
+struct ak_def {
+	enum asahi_compass_chipset type;
+	long (*raw_to_gauss)(u16 data);
+	u16 range;
+	u8 ctrl_regs[REGS_END];
+	u8 ctrl_masks[MASK_END];
+	u8 ctrl_modes[MODE_END];
+	u8 data_regs[3];
+};
+
+static struct ak_def ak_def_array[AK_MAX_TYPE] = {
+	{
+		.type = AK8975,
+		.raw_to_gauss = ak8975_raw_to_gauss,
+		.range = 4096,
+		.ctrl_regs = {
+			AK8975_REG_ST1,
+			AK8975_REG_ST2,
+			AK8975_REG_CNTL,
+			AK8975_REG_ASAX,
+			AK8975_MAX_REGS},
+		.ctrl_masks = {
+			AK8975_REG_ST1_DRDY_MASK,
+			AK8975_REG_ST2_HOFL_MASK,
+			AK8975_REG_ST2_DERR_MASK,
+			AK8975_REG_CNTL_MODE_MASK},
+		.ctrl_modes = {
+			AK8975_REG_CNTL_MODE_POWER_DOWN,
+			AK8975_REG_CNTL_MODE_ONCE,
+			AK8975_REG_CNTL_MODE_SELF_TEST,
+			AK8975_REG_CNTL_MODE_FUSE_ROM},
+		.data_regs = {
+			AK8975_REG_HXL,
+			AK8975_REG_HYL,
+			AK8975_REG_HZL},
+	},
+	{
+		.type = AK8963,
+		.raw_to_gauss = ak8963_09911_raw_to_gauss,
+		.range = 8190,
+		.ctrl_regs = {
+			AK8975_REG_ST1,
+			AK8975_REG_ST2,
+			AK8975_REG_CNTL,
+			AK8975_REG_ASAX,
+			AK8975_MAX_REGS},
+		.ctrl_masks = {
+			AK8975_REG_ST1_DRDY_MASK,
+			AK8975_REG_ST2_HOFL_MASK,
+			0,
+			AK8975_REG_CNTL_MODE_MASK},
+		.ctrl_modes = {
+			AK8975_REG_CNTL_MODE_POWER_DOWN,
+			AK8975_REG_CNTL_MODE_ONCE,
+			AK8975_REG_CNTL_MODE_SELF_TEST,
+			AK8975_REG_CNTL_MODE_FUSE_ROM},
+		.data_regs = {
+			AK8975_REG_HXL,
+			AK8975_REG_HYL,
+			AK8975_REG_HZL},
+	},
+	{
+		.type = AK09911,
+		.raw_to_gauss = ak8963_09911_raw_to_gauss,
+		.range = 8192,
+		.ctrl_regs = {
+			AK09912_REG_ST1,
+			AK09912_REG_ST2,
+			AK09912_REG_CNTL2,
+			AK09912_REG_ASAX,
+			AK09912_MAX_REGS},
+		.ctrl_masks = {
+			AK09912_REG_ST1_DRDY_MASK,
+			AK09912_REG_ST2_HOFL_MASK,
+			0,
+			AK09912_REG_CNTL2_MODE_MASK},
+		.ctrl_modes = {
+			AK09912_REG_CNTL_MODE_POWER_DOWN,
+			AK09912_REG_CNTL_MODE_ONCE,
+			AK09912_REG_CNTL_MODE_SELF_TEST,
+			AK09912_REG_CNTL_MODE_FUSE_ROM},
+		.data_regs = {
+			AK09912_REG_HXL,
+			AK09912_REG_HYL,
+			AK09912_REG_HZL},
+	},
+	{
+		.type = AK09912,
+		.raw_to_gauss = ak09912_raw_to_gauss,
+		.range = 32752,
+		.ctrl_regs = {
+			AK09912_REG_ST1,
+			AK09912_REG_ST2,
+			AK09912_REG_CNTL2,
+			AK09912_REG_ASAX,
+			AK09912_MAX_REGS},
+		.ctrl_masks = {
+			AK09912_REG_ST1_DRDY_MASK,
+			AK09912_REG_ST2_HOFL_MASK,
+			0,
+			AK09912_REG_CNTL2_MODE_MASK},
+		.ctrl_modes = {
+			AK09912_REG_CNTL_MODE_POWER_DOWN,
+			AK09912_REG_CNTL_MODE_ONCE,
+			AK09912_REG_CNTL_MODE_SELF_TEST,
+			AK09912_REG_CNTL_MODE_FUSE_ROM},
+		.data_regs = {
+			AK09912_REG_HXL,
+			AK09912_REG_HYL,
+			AK09912_REG_HZL},
+	}
 };
 
 /*
@@ -100,40 +360,82 @@
  */
 struct ak8975_data {
 	struct i2c_client	*client;
+	struct ak_def		*def;
 	struct attribute_group	attrs;
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
-	u8			reg_cache[AK8975_MAX_REGS];
 	int			eoc_gpio;
 	int			eoc_irq;
 	wait_queue_head_t	data_ready_queue;
 	unsigned long		flags;
-	enum asahi_compass_chipset chipset;
-};
-
-static const int ak8975_index_to_reg[] = {
-	AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
+	u8			cntl_cache;
 };
 
 /*
- * Helper function to write to the I2C device's registers.
+ * Return 0 if the i2c device is the one we expect.
+ * return a negative error number otherwise
  */
-static int ak8975_write_data(struct i2c_client *client,
-			     u8 reg, u8 val, u8 mask, u8 shift)
+static int ak8975_who_i_am(struct i2c_client *client,
+			   enum asahi_compass_chipset type)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-	struct ak8975_data *data = iio_priv(indio_dev);
+	u8 wia_val[2];
+	int ret;
+
+	/*
+	 * Signature for each device:
+	 * Device   |  WIA1      |  WIA2
+	 * AK09912  |  DEVICE_ID |  AK09912_DEVICE_ID
+	 * AK09911  |  DEVICE_ID |  AK09911_DEVICE_ID
+	 * AK8975   |  DEVICE_ID |  NA
+	 * AK8963   |  DEVICE_ID |  NA
+	 */
+	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+					    2, wia_val);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return ret;
+	}
+
+	if (wia_val[0] != AK8975_DEVICE_ID)
+		return -ENODEV;
+
+	switch (type) {
+	case AK8975:
+	case AK8963:
+		return 0;
+	case AK09911:
+		if (wia_val[1] == AK09911_DEVICE_ID)
+			return 0;
+		break;
+	case AK09912:
+		if (wia_val[1] == AK09912_DEVICE_ID)
+			return 0;
+		break;
+	default:
+		dev_err(&client->dev, "Type %d unknown\n", type);
+	}
+	return -ENODEV;
+}
+
+/*
+ * Helper function to write to CNTL register.
+ */
+static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
+{
 	u8 regval;
 	int ret;
 
-	regval = (data->reg_cache[reg] & ~mask) | (val << shift);
-	ret = i2c_smbus_write_byte_data(client, reg, regval);
+	regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
+		 data->def->ctrl_modes[mode];
+	ret = i2c_smbus_write_byte_data(data->client,
+					data->def->ctrl_regs[CNTL], regval);
 	if (ret < 0) {
-		dev_err(&client->dev, "Write to device fails status %x\n", ret);
 		return ret;
 	}
-	data->reg_cache[reg] = regval;
+	data->cntl_cache = regval;
+	/* After mode change wait atleast 100us */
+	usleep_range(100, 500);
 
 	return 0;
 }
@@ -166,8 +468,8 @@
 		irq = gpio_to_irq(data->eoc_gpio);
 
 	rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
-			 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-			 dev_name(&client->dev), data);
+			      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			      dev_name(&client->dev), data);
 	if (rc < 0) {
 		dev_err(&client->dev,
 			"irq %d request failed, (gpio %d): %d\n",
@@ -191,34 +493,18 @@
 {
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	struct ak8975_data *data = iio_priv(indio_dev);
-	u8 device_id;
 	int ret;
 
-	/* Confirm that the device we're talking to is really an AK8975. */
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
-	if (ret < 0) {
-		dev_err(&client->dev, "Error reading WIA\n");
-		return ret;
-	}
-	device_id = ret;
-	if (device_id != AK8975_DEVICE_ID) {
-		dev_err(&client->dev, "Device ak8975 not found\n");
-		return -ENODEV;
-	}
-
 	/* Write the fused rom access mode. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_FUSE_ROM,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, FUSE_ROM);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting fuse access mode\n");
 		return ret;
 	}
 
 	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
+	ret = i2c_smbus_read_i2c_block_data(client,
+					    data->def->ctrl_regs[ASA_BASE],
 					    3, data->asa);
 	if (ret < 0) {
 		dev_err(&client->dev, "Not able to read asa data\n");
@@ -226,13 +512,13 @@
 	}
 
 	/* After reading fuse ROM data set power-down mode */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_POWER_DOWN,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, POWER_DOWN);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
 
-	if (data->eoc_gpio > 0 || client->irq) {
+	if (data->eoc_gpio > 0 || client->irq > 0) {
 		ret = ak8975_setup_irq(data);
 		if (ret < 0) {
 			dev_err(&client->dev,
@@ -241,61 +527,9 @@
 		}
 	}
 
-	if (ret < 0) {
-		dev_err(&client->dev, "Error in setting power-down mode\n");
-		return ret;
-	}
-
-/*
- * Precalculate scale factor (in Gauss units) for each axis and
- * store in the device data.
- *
- * This scale factor is axis-dependent, and is derived from 3 calibration
- * factors ASA(x), ASA(y), and ASA(z).
- *
- * These ASA values are read from the sensor device at start of day, and
- * cached in the device context struct.
- *
- * Adjusting the flux value with the sensitivity adjustment value should be
- * done via the following formula:
- *
- * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
- *
- * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
- * is the resultant adjusted value.
- *
- * We reduce the formula to:
- *
- * Hadj = H * (ASA + 128) / 256
- *
- * H is in the range of -4096 to 4095.  The magnetometer has a range of
- * +-1229uT.  To go from the raw value to uT is:
- *
- * HuT = H * 1229/4096, or roughly, 3/10.
- *
- * Since 1uT = 0.01 gauss, our final scale factor becomes:
- *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
- * Hadj = H * ((ASA + 128) * 0.003) / 256
- *
- * Since ASA doesn't change, we cache the resultant scale factor into the
- * device context in ak8975_setup().
- */
-	if (data->chipset == AK8963) {
-		/*
-		 * H range is +-8190 and magnetometer range is +-4912.
-		 * So HuT using the above explanation for 8975,
-		 * 4912/8190 = ~ 6/10.
-		 * So the Hadj should use 6/10 instead of 3/10.
-		 */
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
-	} else {
-		data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
-		data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
-		data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
-	}
+	data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
+	data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
+	data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
 
 	return 0;
 }
@@ -318,7 +552,7 @@
 		return -EINVAL;
 	}
 
-	ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
 	if (ret < 0)
 		dev_err(&client->dev, "Error in reading ST1\n");
 
@@ -335,7 +569,8 @@
 	/* Wait for the conversion to complete. */
 	while (timeout_ms) {
 		msleep(AK8975_CONVERSION_DONE_POLL_TIME);
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+		ret = i2c_smbus_read_byte_data(client,
+					       data->def->ctrl_regs[ST1]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST1\n");
 			return ret;
@@ -378,11 +613,7 @@
 	mutex_lock(&data->lock);
 
 	/* Set up the device for taking a sample. */
-	ret = ak8975_write_data(client,
-				AK8975_REG_CNTL,
-				AK8975_REG_CNTL_MODE_ONCE,
-				AK8975_REG_CNTL_MODE_MASK,
-				AK8975_REG_CNTL_MODE_SHIFT);
+	ret = ak8975_set_mode(data, MODE_ONCE);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting operating mode\n");
 		goto exit;
@@ -399,14 +630,15 @@
 		goto exit;
 
 	/* This will be executed only for non-interrupt based waiting case */
-	if (ret & AK8975_REG_ST1_DRDY_MASK) {
-		ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
+	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
+		ret = i2c_smbus_read_byte_data(client,
+					       data->def->ctrl_regs[ST2]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST2\n");
 			goto exit;
 		}
-		if (ret & (AK8975_REG_ST2_DERR_MASK |
-			   AK8975_REG_ST2_HOFL_MASK)) {
+		if (ret & (data->def->ctrl_masks[ST2_DERR] |
+			   data->def->ctrl_masks[ST2_HOFL])) {
 			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
 			ret = -EINVAL;
 			goto exit;
@@ -415,7 +647,7 @@
 
 	/* Read the flux value from the appropriate register
 	   (the register is specified in the iio device attributes). */
-	ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
+	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
 	if (ret < 0) {
 		dev_err(&client->dev, "Read axis data fails\n");
 		goto exit;
@@ -424,7 +656,7 @@
 	mutex_unlock(&data->lock);
 
 	/* Clamp to valid range. */
-	*val = clamp_t(s16, ret, -4096, 4095);
+	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
 	return IIO_VAL_INT;
 
 exit:
@@ -473,6 +705,8 @@
 	{"AK8975", AK8975},
 	{"AK8963", AK8963},
 	{"INVN6500", AK8963},
+	{"AK09911", AK09911},
+	{"AK09912", AK09912},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
@@ -498,6 +732,7 @@
 	int eoc_gpio;
 	int err;
 	const char *name = NULL;
+	enum asahi_compass_chipset chipset;
 
 	/* Grab and set up the supplied GPIO. */
 	if (client->dev.platform_data)
@@ -537,42 +772,50 @@
 
 	/* id will be NULL when enumerated via ACPI */
 	if (id) {
-		data->chipset =
-			(enum asahi_compass_chipset)(id->driver_data);
+		chipset = (enum asahi_compass_chipset)(id->driver_data);
 		name = id->name;
 	} else if (ACPI_HANDLE(&client->dev))
-		name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+		name = ak8975_match_acpi_device(&client->dev, &chipset);
 	else
 		return -ENOSYS;
 
+	if (chipset >= AK_MAX_TYPE) {
+		dev_err(&client->dev, "AKM device type unsupported: %d\n",
+			chipset);
+		return -ENODEV;
+	}
+
+	data->def = &ak_def_array[chipset];
+	err = ak8975_who_i_am(client, data->def->type);
+	if (err < 0) {
+		dev_err(&client->dev, "Unexpected device\n");
+		return err;
+	}
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
 	/* Perform some basic start-of-day setup of the device. */
 	err = ak8975_setup(client);
 	if (err < 0) {
-		dev_err(&client->dev, "AK8975 initialization fails\n");
+		dev_err(&client->dev, "%s initialization fails\n", name);
 		return err;
 	}
 
-	data->client = client;
 	mutex_init(&data->lock);
-	data->eoc_gpio = eoc_gpio;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->channels = ak8975_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
 	indio_dev->info = &ak8975_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
-	err = devm_iio_device_register(&client->dev, indio_dev);
-	if (err < 0)
-		return err;
-
-	return 0;
+	return devm_iio_device_register(&client->dev, indio_dev);
 }
 
 static const struct i2c_device_id ak8975_id[] = {
 	{"ak8975", AK8975},
 	{"ak8963", AK8963},
+	{"AK8963", AK8963},
+	{"ak09911", AK09911},
+	{"ak09912", AK09912},
 	{}
 };
 
@@ -581,14 +824,20 @@
 static const struct of_device_id ak8975_of_match[] = {
 	{ .compatible = "asahi-kasei,ak8975", },
 	{ .compatible = "ak8975", },
-	{ }
+	{ .compatible = "asahi-kasei,ak8963", },
+	{ .compatible = "ak8963", },
+	{ .compatible = "asahi-kasei,ak09911", },
+	{ .compatible = "ak09911", },
+	{ .compatible = "asahi-kasei,ak09912", },
+	{ .compatible = "ak09912", },
+	{}
 };
 MODULE_DEVICE_TABLE(of, ak8975_of_match);
 
 static struct i2c_driver ak8975_driver = {
 	.driver = {
 		.name	= "ak8975",
-		.of_match_table = ak8975_of_match,
+		.of_match_table = of_match_ptr(ak8975_of_match),
 		.acpi_match_table = ACPI_PTR(ak_acpi_match),
 	},
 	.probe		= ak8975_probe,
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 6294575..d22993b 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -157,20 +157,12 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
 	switch (mask) {
 	case 0:
-		poll_value = hid_sensor_read_poll_value(
-					&magn_state->common_attributes);
-		if (poll_value < 0)
-				return -EINVAL;
-
 		hid_sensor_power_state(&magn_state->common_attributes, true);
-		msleep_interruptible(poll_value * 2);
-
 		report_id =
 			magn_state->magn[chan->address].report_id;
 		address = magn_3d_addresses[chan->address];
@@ -530,6 +522,7 @@
 	.id_table = hid_magn_3d_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_magn_3d_probe,
 	.remove		= hid_magn_3d_remove,
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 1ff181b..7385446 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -111,20 +111,12 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		poll_value = hid_sensor_read_poll_value(
-					&incl_state->common_attributes);
-		if (poll_value < 0)
-			return -EINVAL;
-
 		hid_sensor_power_state(&incl_state->common_attributes, true);
-		msleep_interruptible(poll_value * 2);
-
 		report_id =
 			incl_state->incl[chan->scan_index].report_id;
 		address = incl_3d_addresses[chan->scan_index];
@@ -437,6 +429,7 @@
 	.id_table = hid_incl_3d_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_incl_3d_probe,
 	.remove		= hid_incl_3d_remove,
diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c
index 75038da..7c623e2 100644
--- a/drivers/iio/pressure/bmp280.c
+++ b/drivers/iio/pressure/bmp280.c
@@ -80,16 +80,12 @@
 	s32 t_fine;
 };
 
-/* Compensation parameters. */
-struct bmp280_comp_temp {
-	u16 dig_t1;
-	s16 dig_t2, dig_t3;
-};
-
-struct bmp280_comp_press {
-	u16 dig_p1;
-	s16 dig_p2, dig_p3, dig_p4, dig_p5, dig_p6, dig_p7, dig_p8, dig_p9;
-};
+/*
+ * These enums are used for indexing into the array of compensation
+ * parameters.
+ */
+enum { T1, T2, T3 };
+enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 };
 
 static const struct iio_chan_spec bmp280_channels[] = {
 	{
@@ -141,10 +137,18 @@
 	.volatile_reg = bmp280_is_volatile_reg,
 };
 
-static int bmp280_read_compensation_temp(struct bmp280_data *data,
-					 struct bmp280_comp_temp *comp)
+/*
+ * Returns temperature in DegC, resolution is 0.01 DegC.  Output value of
+ * "5123" equals 51.23 DegC.  t_fine carries fine temperature as global
+ * value.
+ *
+ * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ */
+static s32 bmp280_compensate_temp(struct bmp280_data *data,
+				  s32 adc_temp)
 {
 	int ret;
+	s32 var1, var2;
 	__le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
 
 	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
@@ -155,63 +159,21 @@
 		return ret;
 	}
 
-	comp->dig_t1 = (u16) le16_to_cpu(buf[0]);
-	comp->dig_t2 = (s16) le16_to_cpu(buf[1]);
-	comp->dig_t3 = (s16) le16_to_cpu(buf[2]);
+	/*
+	 * The double casts are necessary because le16_to_cpu returns an
+	 * unsigned 16-bit value.  Casting that value directly to a
+	 * signed 32-bit will not do proper sign extension.
+	 *
+	 * Conversely, T1 and P1 are unsigned values, so they can be
+	 * cast straight to the larger type.
+	 */
+	var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) *
+		((s32)(s16)le16_to_cpu(buf[T2]))) >> 11;
+	var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) *
+		  ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) *
+		((s32)(s16)le16_to_cpu(buf[T3]))) >> 14;
 
-	return 0;
-}
-
-static int bmp280_read_compensation_press(struct bmp280_data *data,
-					  struct bmp280_comp_press *comp)
-{
-	int ret;
-	__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
-
-	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
-			       buf, BMP280_COMP_PRESS_REG_COUNT);
-	if (ret < 0) {
-		dev_err(&data->client->dev,
-			"failed to read pressure calibration parameters\n");
-		return ret;
-	}
-
-	comp->dig_p1 = (u16) le16_to_cpu(buf[0]);
-	comp->dig_p2 = (s16) le16_to_cpu(buf[1]);
-	comp->dig_p3 = (s16) le16_to_cpu(buf[2]);
-	comp->dig_p4 = (s16) le16_to_cpu(buf[3]);
-	comp->dig_p5 = (s16) le16_to_cpu(buf[4]);
-	comp->dig_p6 = (s16) le16_to_cpu(buf[5]);
-	comp->dig_p7 = (s16) le16_to_cpu(buf[6]);
-	comp->dig_p8 = (s16) le16_to_cpu(buf[7]);
-	comp->dig_p9 = (s16) le16_to_cpu(buf[8]);
-
-	return 0;
-}
-
-/*
- * Returns temperature in DegC, resolution is 0.01 DegC.  Output value of
- * "5123" equals 51.23 DegC.  t_fine carries fine temperature as global
- * value.
- *
- * Taken from datasheet, Section 3.11.3, "Compensation formula".
- */
-static s32 bmp280_compensate_temp(struct bmp280_data *data,
-				  struct bmp280_comp_temp *comp,
-				  s32 adc_temp)
-{
-	s32 var1, var2, t;
-
-	var1 = (((adc_temp >> 3) - ((s32) comp->dig_t1 << 1)) *
-		((s32) comp->dig_t2)) >> 11;
-	var2 = (((((adc_temp >> 4) - ((s32) comp->dig_t1)) *
-		  ((adc_temp >> 4) - ((s32) comp->dig_t1))) >> 12) *
-		((s32) comp->dig_t3)) >> 14;
-
-	data->t_fine = var1 + var2;
-	t = (data->t_fine * 5 + 128) >> 8;
-
-	return t;
+	return (data->t_fine * 5 + 128) >> 8;
 }
 
 /*
@@ -222,29 +184,38 @@
  * Taken from datasheet, Section 3.11.3, "Compensation formula".
  */
 static u32 bmp280_compensate_press(struct bmp280_data *data,
-				   struct bmp280_comp_press *comp,
 				   s32 adc_press)
 {
+	int ret;
 	s64 var1, var2, p;
+	__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
 
-	var1 = ((s64) data->t_fine) - 128000;
-	var2 = var1 * var1 * (s64) comp->dig_p6;
-	var2 = var2 + ((var1 * (s64) comp->dig_p5) << 17);
-	var2 = var2 + (((s64) comp->dig_p4) << 35);
-	var1 = ((var1 * var1 * (s64) comp->dig_p3) >> 8) +
-		((var1 * (s64) comp->dig_p2) << 12);
-	var1 = (((((s64) 1) << 47) + var1)) * ((s64) comp->dig_p1) >> 33;
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
+			       buf, BMP280_COMP_PRESS_REG_COUNT);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"failed to read pressure calibration parameters\n");
+		return ret;
+	}
+
+	var1 = ((s64)data->t_fine) - 128000;
+	var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]);
+	var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17;
+	var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35;
+	var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) +
+		((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12);
+	var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33;
 
 	if (var1 == 0)
 		return 0;
 
-	p = ((((s64) 1048576 - adc_press) << 31) - var2) * 3125;
+	p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;
 	p = div64_s64(p, var1);
-	var1 = (((s64) comp->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
-	var2 = (((s64) comp->dig_p8) * p) >> 19;
-	p = ((p + var1 + var2) >> 8) + (((s64) comp->dig_p7) << 4);
+	var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25;
+	var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19;
+	p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4);
 
-	return (u32) p;
+	return (u32)p;
 }
 
 static int bmp280_read_temp(struct bmp280_data *data,
@@ -253,11 +224,6 @@
 	int ret;
 	__be32 tmp = 0;
 	s32 adc_temp, comp_temp;
-	struct bmp280_comp_temp comp;
-
-	ret = bmp280_read_compensation_temp(data, &comp);
-	if (ret < 0)
-		return ret;
 
 	ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
 			       (u8 *) &tmp, 3);
@@ -267,7 +233,7 @@
 	}
 
 	adc_temp = be32_to_cpu(tmp) >> 12;
-	comp_temp = bmp280_compensate_temp(data, &comp, adc_temp);
+	comp_temp = bmp280_compensate_temp(data, adc_temp);
 
 	/*
 	 * val might be NULL if we're called by the read_press routine,
@@ -288,11 +254,6 @@
 	__be32 tmp = 0;
 	s32 adc_press;
 	u32 comp_press;
-	struct bmp280_comp_press comp;
-
-	ret = bmp280_read_compensation_press(data, &comp);
-	if (ret < 0)
-		return ret;
 
 	/* Read and compensate temperature so we get a reading of t_fine. */
 	ret = bmp280_read_temp(data, NULL);
@@ -307,7 +268,7 @@
 	}
 
 	adc_press = be32_to_cpu(tmp) >> 12;
-	comp_press = bmp280_compensate_press(data, &comp, adc_press);
+	comp_press = bmp280_compensate_press(data, adc_press);
 
 	*val = comp_press;
 	*val2 = 256000;
@@ -366,7 +327,7 @@
 				 BMP280_MODE_NORMAL);
 	if (ret < 0) {
 		dev_err(&data->client->dev,
-			"failed to write config register\n");
+			"failed to write ctrl_meas register\n");
 		return ret;
 	}
 
@@ -394,7 +355,6 @@
 	if (!indio_dev)
 		return -ENOMEM;
 
-	i2c_set_clientdata(client, indio_dev);
 	data = iio_priv(indio_dev);
 	mutex_init(&data->lock);
 	data->client = client;
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 7649286..1af3149 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -79,7 +79,6 @@
 	int report_id = -1;
 	u32 address;
 	int ret_type;
-	s32 poll_value;
 
 	*val = 0;
 	*val2 = 0;
@@ -96,15 +95,8 @@
 			break;
 		}
 		if (report_id >= 0) {
-			poll_value = hid_sensor_read_poll_value(
-					&press_state->common_attributes);
-			if (poll_value < 0)
-				return -EINVAL;
 			hid_sensor_power_state(&press_state->common_attributes,
 						true);
-
-			msleep_interruptible(poll_value * 2);
-
 			*val = sensor_hub_input_attr_get_raw_value(
 				press_state->common_attributes.hsdev,
 				HID_USAGE_SENSOR_PRESSURE, address,
@@ -382,6 +374,7 @@
 	.id_table = hid_press_ids,
 	.driver = {
 		.name	= KBUILD_MODNAME,
+		.pm	= &hid_sensor_pm_ops,
 	},
 	.probe		= hid_press_probe,
 	.remove		= hid_press_remove,
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 0c8cdf5..41a8d8f 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -17,3 +17,20 @@
 	  module will be called as3935
 
 endmenu
+
+menu "Proximity sensors"
+
+config SX9500
+	tristate "SX9500 Semtech proximity sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say Y here to build a driver for Semtech's SX9500 capacitive
+	  proximity/button sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sx9500.
+
+endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 743adee..9818dc5 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -4,3 +4,4 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AS3935)		+= as3935.o
+obj-$(CONFIG_SX9500)		+= sx9500.o
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index 466aa43..bc0d68e 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -273,9 +273,9 @@
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int as3935_suspend(struct spi_device *spi, pm_message_t msg)
+static int as3935_suspend(struct device *dev)
 {
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct as3935_state *st = iio_priv(indio_dev);
 	int val, ret;
 
@@ -293,9 +293,9 @@
 	return ret;
 }
 
-static int as3935_resume(struct spi_device *spi)
+static int as3935_resume(struct device *dev)
 {
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct as3935_state *st = iio_priv(indio_dev);
 	int val, ret;
 
@@ -311,9 +311,12 @@
 
 	return ret;
 }
+
+static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
+#define AS3935_PM_OPS (&as3935_pm_ops)
+
 #else
-#define as3935_suspend	NULL
-#define as3935_resume	NULL
+#define AS3935_PM_OPS NULL
 #endif
 
 static int as3935_probe(struct spi_device *spi)
@@ -441,12 +444,11 @@
 	.driver = {
 		.name	= "as3935",
 		.owner	= THIS_MODULE,
+		.pm	= AS3935_PM_OPS,
 	},
 	.probe		= as3935_probe,
 	.remove		= as3935_remove,
 	.id_table	= as3935_id,
-	.suspend	= as3935_suspend,
-	.resume		= as3935_resume,
 };
 module_spi_driver(as3935_driver);
 
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
new file mode 100644
index 0000000..74dff4e
--- /dev/null
+++ b/drivers/iio/proximity/sx9500.c
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Driver for Semtech's SX9500 capacitive proximity/button solution.
+ * Datasheet available at
+ * <http://www.semtech.com/images/datasheet/sx9500.pdf>.
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define SX9500_DRIVER_NAME		"sx9500"
+#define SX9500_IRQ_NAME			"sx9500_event"
+#define SX9500_GPIO_NAME		"sx9500_gpio"
+
+/* Register definitions. */
+#define SX9500_REG_IRQ_SRC		0x00
+#define SX9500_REG_STAT			0x01
+#define SX9500_REG_IRQ_MSK		0x03
+
+#define SX9500_REG_PROX_CTRL0		0x06
+#define SX9500_REG_PROX_CTRL1		0x07
+#define SX9500_REG_PROX_CTRL2		0x08
+#define SX9500_REG_PROX_CTRL3		0x09
+#define SX9500_REG_PROX_CTRL4		0x0a
+#define SX9500_REG_PROX_CTRL5		0x0b
+#define SX9500_REG_PROX_CTRL6		0x0c
+#define SX9500_REG_PROX_CTRL7		0x0d
+#define SX9500_REG_PROX_CTRL8		0x0e
+
+#define SX9500_REG_SENSOR_SEL		0x20
+#define SX9500_REG_USE_MSB		0x21
+#define SX9500_REG_USE_LSB		0x22
+#define SX9500_REG_AVG_MSB		0x23
+#define SX9500_REG_AVG_LSB		0x24
+#define SX9500_REG_DIFF_MSB		0x25
+#define SX9500_REG_DIFF_LSB		0x26
+#define SX9500_REG_OFFSET_MSB		0x27
+#define SX9500_REG_OFFSET_LSB		0x28
+
+#define SX9500_REG_RESET		0x7f
+
+/* Write this to REG_RESET to do a soft reset. */
+#define SX9500_SOFT_RESET		0xde
+
+#define SX9500_SCAN_PERIOD_MASK		GENMASK(6, 4)
+#define SX9500_SCAN_PERIOD_SHIFT	4
+
+/*
+ * These serve for identifying IRQ source in the IRQ_SRC register, and
+ * also for masking the IRQs in the IRQ_MSK register.
+ */
+#define SX9500_CLOSE_IRQ		BIT(6)
+#define SX9500_FAR_IRQ			BIT(5)
+#define SX9500_CONVDONE_IRQ		BIT(3)
+
+#define SX9500_PROXSTAT_SHIFT		4
+
+#define SX9500_NUM_CHANNELS		4
+
+struct sx9500_data {
+	struct mutex mutex;
+	struct i2c_client *client;
+	struct iio_trigger *trig;
+	struct regmap *regmap;
+	/*
+	 * Last reading of the proximity status for each channel.  We
+	 * only send an event to user space when this changes.
+	 */
+	bool prox_stat[SX9500_NUM_CHANNELS];
+	bool event_enabled[SX9500_NUM_CHANNELS];
+	bool trigger_enabled;
+	u16 *buffer;
+};
+
+static const struct iio_event_spec sx9500_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+#define SX9500_CHANNEL(idx)					\
+	{							\
+		.type = IIO_PROXIMITY,				\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+		.indexed = 1,					\
+		.channel = idx,					\
+		.event_spec = sx9500_events,			\
+		.num_event_specs = ARRAY_SIZE(sx9500_events),	\
+		.scan_index = idx,				\
+		.scan_type = {					\
+			.sign = 'u',				\
+			.realbits = 16,				\
+			.storagebits = 16,			\
+			.shift = 0,				\
+		},						\
+	}
+
+static const struct iio_chan_spec sx9500_channels[] = {
+	SX9500_CHANNEL(0),
+	SX9500_CHANNEL(1),
+	SX9500_CHANNEL(2),
+	SX9500_CHANNEL(3),
+	IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct {
+	int val;
+	int val2;
+} sx9500_samp_freq_table[] = {
+	{33, 333333},
+	{16, 666666},
+	{11, 111111},
+	{8, 333333},
+	{6, 666666},
+	{5, 0},
+	{3, 333333},
+	{2, 500000},
+};
+
+static const struct regmap_range sx9500_writable_reg_ranges[] = {
+	regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK),
+	regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8),
+	regmap_reg_range(SX9500_REG_SENSOR_SEL, SX9500_REG_SENSOR_SEL),
+	regmap_reg_range(SX9500_REG_OFFSET_MSB, SX9500_REG_OFFSET_LSB),
+	regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
+};
+
+static const struct regmap_access_table sx9500_writeable_regs = {
+	.yes_ranges = sx9500_writable_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(sx9500_writable_reg_ranges),
+};
+
+/*
+ * All allocated registers are readable, so we just list unallocated
+ * ones.
+ */
+static const struct regmap_range sx9500_non_readable_reg_ranges[] = {
+	regmap_reg_range(SX9500_REG_STAT + 1, SX9500_REG_STAT + 1),
+	regmap_reg_range(SX9500_REG_IRQ_MSK + 1, SX9500_REG_PROX_CTRL0 - 1),
+	regmap_reg_range(SX9500_REG_PROX_CTRL8 + 1, SX9500_REG_SENSOR_SEL - 1),
+	regmap_reg_range(SX9500_REG_OFFSET_LSB + 1, SX9500_REG_RESET - 1),
+};
+
+static const struct regmap_access_table sx9500_readable_regs = {
+	.no_ranges = sx9500_non_readable_reg_ranges,
+	.n_no_ranges = ARRAY_SIZE(sx9500_non_readable_reg_ranges),
+};
+
+static const struct regmap_range sx9500_volatile_reg_ranges[] = {
+	regmap_reg_range(SX9500_REG_IRQ_SRC, SX9500_REG_STAT),
+	regmap_reg_range(SX9500_REG_USE_MSB, SX9500_REG_OFFSET_LSB),
+	regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
+};
+
+static const struct regmap_access_table sx9500_volatile_regs = {
+	.yes_ranges = sx9500_volatile_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(sx9500_volatile_reg_ranges),
+};
+
+static const struct regmap_config sx9500_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = SX9500_REG_RESET,
+	.cache_type = REGCACHE_RBTREE,
+
+	.wr_table = &sx9500_writeable_regs,
+	.rd_table = &sx9500_readable_regs,
+	.volatile_table = &sx9500_volatile_regs,
+};
+
+static int sx9500_read_proximity(struct sx9500_data *data,
+				 const struct iio_chan_spec *chan,
+				 int *val)
+{
+	int ret;
+	__be16 regval;
+
+	ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, &regval, 2);
+	if (ret < 0)
+		return ret;
+
+	*val = 32767 - (s16)be16_to_cpu(regval);
+
+	return IIO_VAL_INT;
+}
+
+static int sx9500_read_samp_freq(struct sx9500_data *data,
+				 int *val, int *val2)
+{
+	int ret;
+	unsigned int regval;
+
+	mutex_lock(&data->mutex);
+	ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &regval);
+	mutex_unlock(&data->mutex);
+
+	if (ret < 0)
+		return ret;
+
+	regval = (regval & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT;
+	*val = sx9500_samp_freq_table[regval].val;
+	*val2 = sx9500_samp_freq_table[regval].val2;
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int sx9500_read_raw(struct iio_dev *indio_dev,
+			   const struct iio_chan_spec *chan,
+			   int *val, int *val2, long mask)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (chan->type) {
+	case IIO_PROXIMITY:
+		switch (mask) {
+		case IIO_CHAN_INFO_RAW:
+			if (iio_buffer_enabled(indio_dev))
+				return -EBUSY;
+			mutex_lock(&data->mutex);
+			ret = sx9500_read_proximity(data, chan, val);
+			mutex_unlock(&data->mutex);
+			return ret;
+		case IIO_CHAN_INFO_SAMP_FREQ:
+			return sx9500_read_samp_freq(data, val, val2);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sx9500_set_samp_freq(struct sx9500_data *data,
+				int val, int val2)
+{
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(sx9500_samp_freq_table); i++)
+		if (val == sx9500_samp_freq_table[i].val &&
+		    val2 == sx9500_samp_freq_table[i].val2)
+			break;
+
+	if (i == ARRAY_SIZE(sx9500_samp_freq_table))
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+
+	ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
+				 SX9500_SCAN_PERIOD_MASK,
+				 i << SX9500_SCAN_PERIOD_SHIFT);
+
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int sx9500_write_raw(struct iio_dev *indio_dev,
+			    const struct iio_chan_spec *chan,
+			    int val, int val2, long mask)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+
+	switch (chan->type) {
+	case IIO_PROXIMITY:
+		switch (mask) {
+		case IIO_CHAN_INFO_SAMP_FREQ:
+			return sx9500_set_samp_freq(data, val, val2);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static irqreturn_t sx9500_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct sx9500_data *data = iio_priv(indio_dev);
+
+	if (data->trigger_enabled)
+		iio_trigger_poll(data->trig);
+
+	/*
+	 * Even if no event is enabled, we need to wake the thread to
+	 * clear the interrupt state by reading SX9500_REG_IRQ_SRC.  It
+	 * is not possible to do that here because regmap_read takes a
+	 * mutex.
+	 */
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int ret;
+	unsigned int val, chan;
+
+	mutex_lock(&data->mutex);
+
+	ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c transfer error in irq\n");
+		goto out;
+	}
+
+	if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)))
+		goto out;
+
+	ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "i2c transfer error in irq\n");
+		goto out;
+	}
+
+	val >>= SX9500_PROXSTAT_SHIFT;
+	for (chan = 0; chan < SX9500_NUM_CHANNELS; chan++) {
+		int dir;
+		u64 ev;
+		bool new_prox = val & BIT(chan);
+
+		if (!data->event_enabled[chan])
+			continue;
+		if (new_prox == data->prox_stat[chan])
+			/* No change on this channel. */
+			continue;
+
+		dir = new_prox ? IIO_EV_DIR_FALLING :
+			IIO_EV_DIR_RISING;
+		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+					  chan,
+					  IIO_EV_TYPE_THRESH,
+					  dir);
+		iio_push_event(indio_dev, ev, iio_get_time_ns());
+		data->prox_stat[chan] = new_prox;
+	}
+
+out:
+	mutex_unlock(&data->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int sx9500_read_event_config(struct iio_dev *indio_dev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+	    dir != IIO_EV_DIR_EITHER)
+		return -EINVAL;
+
+	return data->event_enabled[chan->channel];
+}
+
+static int sx9500_write_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir,
+				     int state)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int ret, i;
+	bool any_active = false;
+	unsigned int irqmask;
+
+	if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+	    dir != IIO_EV_DIR_EITHER)
+		return -EINVAL;
+
+	mutex_lock(&data->mutex);
+
+	data->event_enabled[chan->channel] = state;
+
+	for (i = 0; i < SX9500_NUM_CHANNELS; i++)
+		if (data->event_enabled[i]) {
+			any_active = true;
+			break;
+		}
+
+	irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ;
+	if (any_active)
+		ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+					 irqmask, irqmask);
+	else
+		ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+					 irqmask, 0);
+
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int sx9500_update_scan_mode(struct iio_dev *indio_dev,
+				   const unsigned long *scan_mask)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+
+	mutex_lock(&data->mutex);
+	kfree(data->buffer);
+	data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
+	mutex_unlock(&data->mutex);
+
+	if (data->buffer == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+	"2.500000 3.333333 5 6.666666 8.333333 11.111111 16.666666 33.333333");
+
+static struct attribute *sx9500_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group sx9500_attribute_group = {
+	.attrs = sx9500_attributes,
+};
+
+static const struct iio_info sx9500_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &sx9500_attribute_group,
+	.read_raw = &sx9500_read_raw,
+	.write_raw = &sx9500_write_raw,
+	.read_event_config = &sx9500_read_event_config,
+	.write_event_config = &sx9500_write_event_config,
+	.update_scan_mode = &sx9500_update_scan_mode,
+};
+
+static int sx9500_set_trigger_state(struct iio_trigger *trig,
+				    bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+
+	ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+				 SX9500_CONVDONE_IRQ,
+				 state ? SX9500_CONVDONE_IRQ : 0);
+	if (ret == 0)
+		data->trigger_enabled = state;
+
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static const struct iio_trigger_ops sx9500_trigger_ops = {
+	.set_trigger_state = sx9500_set_trigger_state,
+	.owner = THIS_MODULE,
+};
+
+static irqreturn_t sx9500_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int val, bit, ret, i = 0;
+
+	mutex_lock(&data->mutex);
+
+	for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+			 indio_dev->masklength) {
+		ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
+					    &val);
+		if (ret < 0)
+			goto out;
+
+		data->buffer[i++] = val;
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   iio_get_time_ns());
+
+out:
+	mutex_unlock(&data->mutex);
+
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+struct sx9500_reg_default {
+	u8 reg;
+	u8 def;
+};
+
+static const struct sx9500_reg_default sx9500_default_regs[] = {
+	{
+		.reg = SX9500_REG_PROX_CTRL1,
+		/* Shield enabled, small range. */
+		.def = 0x43,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL2,
+		/* x8 gain, 167kHz frequency, finest resolution. */
+		.def = 0x77,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL3,
+		/* Doze enabled, 2x scan period doze, no raw filter. */
+		.def = 0x40,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL4,
+		/* Average threshold. */
+		.def = 0x30,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL5,
+		/*
+		 * Debouncer off, lowest average negative filter,
+		 * highest average postive filter.
+		 */
+		.def = 0x0f,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL6,
+		/* Proximity detection threshold: 280 */
+		.def = 0x0e,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL7,
+		/*
+		 * No automatic compensation, compensate each pin
+		 * independently, proximity hysteresis: 32, close
+		 * debouncer off, far debouncer off.
+		 */
+		.def = 0x00,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL8,
+		/* No stuck timeout, no periodic compensation. */
+		.def = 0x00,
+	},
+	{
+		.reg = SX9500_REG_PROX_CTRL0,
+		/* Scan period: 30ms, all sensors enabled. */
+		.def = 0x0f,
+	},
+};
+
+static int sx9500_init_device(struct iio_dev *indio_dev)
+{
+	struct sx9500_data *data = iio_priv(indio_dev);
+	int ret, i;
+	unsigned int val;
+
+	ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, SX9500_REG_RESET,
+			   SX9500_SOFT_RESET);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(sx9500_default_regs); i++) {
+		ret = regmap_write(data->regmap,
+				   sx9500_default_regs[i].reg,
+				   sx9500_default_regs[i].def);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sx9500_gpio_probe(struct i2c_client *client,
+			     struct sx9500_data *data)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static int sx9500_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct sx9500_data *data;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	mutex_init(&data->mutex);
+	data->trigger_enabled = false;
+
+	data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+
+	sx9500_init_device(indio_dev);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = SX9500_DRIVER_NAME;
+	indio_dev->channels = sx9500_channels;
+	indio_dev->num_channels = ARRAY_SIZE(sx9500_channels);
+	indio_dev->info = &sx9500_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	i2c_set_clientdata(client, indio_dev);
+
+	if (client->irq <= 0)
+		client->irq = sx9500_gpio_probe(client, data);
+
+	if (client->irq > 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+				sx9500_irq_handler, sx9500_irq_thread_handler,
+				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				SX9500_IRQ_NAME, indio_dev);
+		if (ret < 0)
+			return ret;
+
+		data->trig = devm_iio_trigger_alloc(&client->dev,
+				"%s-dev%d", indio_dev->name, indio_dev->id);
+		if (!data->trig)
+			return -ENOMEM;
+
+		data->trig->dev.parent = &client->dev;
+		data->trig->ops = &sx9500_trigger_ops;
+		iio_trigger_set_drvdata(data->trig, indio_dev);
+
+		ret = iio_trigger_register(data->trig);
+		if (ret)
+			return ret;
+	}
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 sx9500_trigger_handler, NULL);
+	if (ret < 0)
+		goto out_trigger_unregister;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto out_buffer_cleanup;
+
+	return 0;
+
+out_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+out_trigger_unregister:
+	if (client->irq > 0)
+		iio_trigger_unregister(data->trig);
+
+	return ret;
+}
+
+static int sx9500_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct sx9500_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	if (client->irq > 0)
+		iio_trigger_unregister(data->trig);
+	kfree(data->buffer);
+
+	return 0;
+}
+
+static const struct acpi_device_id sx9500_acpi_match[] = {
+	{"SSX9500", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
+
+static const struct i2c_device_id sx9500_id[] = {
+	{"sx9500", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, sx9500_id);
+
+static struct i2c_driver sx9500_driver = {
+	.driver = {
+		.name	= SX9500_DRIVER_NAME,
+		.acpi_match_table = ACPI_PTR(sx9500_acpi_match),
+	},
+	.probe		= sx9500_probe,
+	.remove		= sx9500_remove,
+	.id_table	= sx9500_id,
+};
+module_i2c_driver(sx9500_driver);
+
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_DESCRIPTION("Driver for Semtech SX9500 proximity sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index 254c7e9..3dfab2b 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -135,6 +135,7 @@
 	struct iio_sysfs_trig *t;
 	int ret;
 	bool foundit = false;
+
 	mutex_lock(&iio_sysfs_trig_list_mut);
 	list_for_each_entry(t, &iio_sysfs_trig_list, l)
 		if (id == t->id) {
@@ -185,6 +186,7 @@
 {
 	bool foundit = false;
 	struct iio_sysfs_trig *t;
+
 	mutex_lock(&iio_sysfs_trig_list_mut);
 	list_for_each_entry(t, &iio_sysfs_trig_list, l)
 		if (id == t->id) {
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index e27a258..387c51f 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1399,8 +1399,8 @@
 
 static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
 {
-	size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
-			atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
+	size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+			       ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
 
 	buf[len++] = '\n';
 	buf[len] = '\0';
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 883d6ae..ddf4045 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -190,7 +190,7 @@
 		__set_bit(bdata->button->code, bits);
 	}
 
-	ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
+	ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
 	buf[ret++] = '\n';
 	buf[ret] = '\0';
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 9516a32..42965d2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -42,3 +42,4 @@
 obj-$(CONFIG_KEYSTONE_IRQ)		+= irq-keystone.o
 obj-$(CONFIG_MIPS_GIC)			+= irq-mips-gic.o
 obj-$(CONFIG_ARCH_MEDIATEK)		+= irq-mtk-sysirq.o
+obj-$(CONFIG_ARCH_DIGICOLOR)		+= irq-digicolor.o
diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c
new file mode 100644
index 0000000..930a2a2
--- /dev/null
+++ b/drivers/irqchip/irq-digicolor.c
@@ -0,0 +1,120 @@
+/*
+ * Conexant Digicolor SoCs IRQ chip driver
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * 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/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define UC_IRQ_CONTROL		0x04
+
+#define IC_FLAG_CLEAR_LO	0x00
+#define IC_FLAG_CLEAR_XLO	0x04
+#define IC_INT0ENABLE_LO	0x10
+#define IC_INT0ENABLE_XLO	0x14
+#define IC_INT0STATUS_LO	0x18
+#define IC_INT0STATUS_XLO	0x1c
+
+static struct irq_domain *digicolor_irq_domain;
+
+static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)
+{
+	struct irq_domain_chip_generic *dgc = digicolor_irq_domain->gc;
+	struct irq_chip_generic *gc = dgc->gc[0];
+	u32 status, hwirq;
+
+	do {
+		status = irq_reg_readl(gc, IC_INT0STATUS_LO);
+		if (status) {
+			hwirq = ffs(status) - 1;
+		} else {
+			status = irq_reg_readl(gc, IC_INT0STATUS_XLO);
+			if (status)
+				hwirq = ffs(status) - 1 + 32;
+			else
+				return;
+		}
+
+		handle_domain_irq(digicolor_irq_domain, hwirq, regs);
+	} while (1);
+}
+
+static void digicolor_set_gc(void __iomem *reg_base, unsigned irq_base,
+			     unsigned en_reg, unsigned ack_reg)
+{
+	struct irq_chip_generic *gc;
+
+	gc = irq_get_domain_generic_chip(digicolor_irq_domain, irq_base);
+	gc->reg_base = reg_base;
+	gc->chip_types[0].regs.ack = ack_reg;
+	gc->chip_types[0].regs.mask = en_reg;
+	gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+	gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+	gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+}
+
+static int __init digicolor_of_init(struct device_node *node,
+				struct device_node *parent)
+{
+	static void __iomem *reg_base;
+	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+	struct regmap *ucregs;
+	int ret;
+
+	reg_base = of_iomap(node, 0);
+	if (!reg_base) {
+		pr_err("%s: unable to map IC registers\n", node->full_name);
+		return -ENXIO;
+	}
+
+	/* disable all interrupts */
+	writel(0, reg_base + IC_INT0ENABLE_LO);
+	writel(0, reg_base + IC_INT0ENABLE_XLO);
+
+	ucregs = syscon_regmap_lookup_by_phandle(node, "syscon");
+	if (IS_ERR(ucregs)) {
+		pr_err("%s: unable to map UC registers\n", node->full_name);
+		return PTR_ERR(ucregs);
+	}
+	/* channel 1, regular IRQs */
+	regmap_write(ucregs, UC_IRQ_CONTROL, 1);
+
+	digicolor_irq_domain =
+		irq_domain_add_linear(node, 64, &irq_generic_chip_ops, NULL);
+	if (!digicolor_irq_domain) {
+		pr_err("%s: unable to create IRQ domain\n", node->full_name);
+		return -ENOMEM;
+	}
+
+	ret = irq_alloc_domain_generic_chips(digicolor_irq_domain, 32, 1,
+					     "digicolor_irq", handle_level_irq,
+					     clr, 0, 0);
+	if (ret) {
+		pr_err("%s: unable to allocate IRQ gc\n", node->full_name);
+		return ret;
+	}
+
+	digicolor_set_gc(reg_base, 0, IC_INT0ENABLE_LO, IC_FLAG_CLEAR_LO);
+	digicolor_set_gc(reg_base, 32, IC_INT0ENABLE_XLO, IC_FLAG_CLEAR_XLO);
+
+	set_handle_irq(digicolor_handle_irq);
+
+	return 0;
+}
+IRQCHIP_DECLARE(conexant_digicolor_ic, "cnxt,cx92755-ic", digicolor_of_init);
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 61541ff..ad96ebb 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,7 +21,7 @@
 
 #include "irq-gic-common.h"
 
-void gic_configure_irq(unsigned int irq, unsigned int type,
+int gic_configure_irq(unsigned int irq, unsigned int type,
 		       void __iomem *base, void (*sync_access)(void))
 {
 	u32 enablemask = 1 << (irq % 32);
@@ -29,16 +29,17 @@
 	u32 confmask = 0x2 << ((irq % 16) * 2);
 	u32 confoff = (irq / 16) * 4;
 	bool enabled = false;
-	u32 val;
+	u32 val, oldval;
+	int ret = 0;
 
 	/*
 	 * Read current configuration register, and insert the config
 	 * for "irq", depending on "type".
 	 */
-	val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-	if (type == IRQ_TYPE_LEVEL_HIGH)
+	val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+	if (type & IRQ_TYPE_LEVEL_MASK)
 		val &= ~confmask;
-	else if (type == IRQ_TYPE_EDGE_RISING)
+	else if (type & IRQ_TYPE_EDGE_BOTH)
 		val |= confmask;
 
 	/*
@@ -54,15 +55,20 @@
 
 	/*
 	 * Write back the new configuration, and possibly re-enable
-	 * the interrupt.
+	 * the interrupt. If we tried to write a new configuration and failed,
+	 * return an error.
 	 */
 	writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+	if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
+		ret = -EINVAL;
 
 	if (enabled)
 		writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
 
 	if (sync_access)
 		sync_access();
+
+	return ret;
 }
 
 void __init gic_dist_config(void __iomem *base, int gic_irqs,
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index b41f024..35a9884 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -20,7 +20,7 @@
 #include <linux/of.h>
 #include <linux/irqdomain.h>
 
-void gic_configure_irq(unsigned int irq, unsigned int type,
+int gic_configure_irq(unsigned int irq, unsigned int type,
                        void __iomem *base, void (*sync_access)(void));
 void gic_dist_config(void __iomem *base, int gic_irqs,
 		     void (*sync_access)(void));
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 2ab290b..1c6dea2 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -238,7 +238,9 @@
 	if (irq < 16)
 		return -EINVAL;
 
-	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+	/* SPIs have restrictions on the supported types */
+	if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+			 type != IRQ_TYPE_EDGE_RISING)
 		return -EINVAL;
 
 	if (gic_irq_in_rdist(d)) {
@@ -249,9 +251,7 @@
 		rwp_wait = gic_dist_wait_for_rwp;
 	}
 
-	gic_configure_irq(irq, type, base, rwp_wait);
-
-	return 0;
+	return gic_configure_irq(irq, type, base, rwp_wait);
 }
 
 static u64 gic_mpidr_to_affinity(u64 mpidr)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d617ee5..4634cf7 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -188,12 +188,15 @@
 {
 	void __iomem *base = gic_dist_base(d);
 	unsigned int gicirq = gic_irq(d);
+	int ret;
 
 	/* Interrupt configuration for SGIs can't be changed */
 	if (gicirq < 16)
 		return -EINVAL;
 
-	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+	/* SPIs have restrictions on the supported types */
+	if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+			    type != IRQ_TYPE_EDGE_RISING)
 		return -EINVAL;
 
 	raw_spin_lock(&irq_controller_lock);
@@ -201,11 +204,11 @@
 	if (gic_arch_extn.irq_set_type)
 		gic_arch_extn.irq_set_type(d, type);
 
-	gic_configure_irq(gicirq, type, base, NULL);
+	ret = gic_configure_irq(gicirq, type, base, NULL);
 
 	raw_spin_unlock(&irq_controller_lock);
 
-	return 0;
+	return ret;
 }
 
 static int gic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 6bc2deb..7d6ffb5 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -120,21 +120,24 @@
 {
 	void __iomem *base = hip04_dist_base(d);
 	unsigned int irq = hip04_irq(d);
+	int ret;
 
 	/* Interrupt configuration for SGIs can't be changed */
 	if (irq < 16)
 		return -EINVAL;
 
-	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+	/* SPIs have restrictions on the supported types */
+	if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+			 type != IRQ_TYPE_EDGE_RISING)
 		return -EINVAL;
 
 	raw_spin_lock(&irq_controller_lock);
 
-	gic_configure_irq(irq, type, base, NULL);
+	ret = gic_configure_irq(irq, type, base, NULL);
 
 	raw_spin_unlock(&irq_controller_lock);
 
-	return 0;
+	return ret;
 }
 
 #ifdef CONFIG_SMP
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 56b96c6..1daa7ca 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -235,9 +235,9 @@
 				  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
 }
 
-static unsigned int gic_get_int(void)
+static void gic_handle_shared_int(void)
 {
-	unsigned int i;
+	unsigned int i, intr, virq;
 	unsigned long *pcpu_mask;
 	unsigned long pending_reg, intrmask_reg;
 	DECLARE_BITMAP(pending, GIC_MAX_INTRS);
@@ -259,7 +259,16 @@
 	bitmap_and(pending, pending, intrmask, gic_shared_intrs);
 	bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
 
-	return find_first_bit(pending, gic_shared_intrs);
+	intr = find_first_bit(pending, gic_shared_intrs);
+	while (intr != gic_shared_intrs) {
+		virq = irq_linear_revmap(gic_irq_domain,
+					 GIC_SHARED_TO_HWIRQ(intr));
+		do_IRQ(virq);
+
+		/* go to next pending bit */
+		bitmap_clear(pending, intr, 1);
+		intr = find_first_bit(pending, gic_shared_intrs);
+	}
 }
 
 static void gic_mask_irq(struct irq_data *d)
@@ -386,16 +395,26 @@
 #endif
 };
 
-static unsigned int gic_get_local_int(void)
+static void gic_handle_local_int(void)
 {
 	unsigned long pending, masked;
+	unsigned int intr, virq;
 
 	pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
 	masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
 
 	bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
 
-	return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+	intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+	while (intr != GIC_NUM_LOCAL_INTRS) {
+		virq = irq_linear_revmap(gic_irq_domain,
+					 GIC_LOCAL_TO_HWIRQ(intr));
+		do_IRQ(virq);
+
+		/* go to next pending bit */
+		bitmap_clear(&pending, intr, 1);
+		intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+	}
 }
 
 static void gic_mask_local_irq(struct irq_data *d)
@@ -454,19 +473,8 @@
 
 static void __gic_irq_dispatch(void)
 {
-	unsigned int intr, virq;
-
-	while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
-		virq = irq_linear_revmap(gic_irq_domain,
-					 GIC_LOCAL_TO_HWIRQ(intr));
-		do_IRQ(virq);
-	}
-
-	while ((intr = gic_get_int()) != gic_shared_intrs) {
-		virq = irq_linear_revmap(gic_irq_domain,
-					 GIC_SHARED_TO_HWIRQ(intr));
-		do_IRQ(virq);
-	}
+	gic_handle_local_int();
+	gic_handle_shared_int();
 }
 
 static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c
index 0b0d2c0..eaf0a71 100644
--- a/drivers/irqchip/irq-mtk-sysirq.c
+++ b/drivers/irqchip/irq-mtk-sysirq.c
@@ -23,8 +23,6 @@
 
 #include "irqchip.h"
 
-#define MT6577_SYS_INTPOL_NUM	(224)
-
 struct mtk_sysirq_chip_data {
 	spinlock_t lock;
 	void __iomem *intpol_base;
@@ -124,7 +122,8 @@
 {
 	struct irq_domain *domain, *domain_parent;
 	struct mtk_sysirq_chip_data *chip_data;
-	int ret = 0;
+	int ret, size, intpol_num;
+	struct resource res;
 
 	domain_parent = irq_find_host(parent);
 	if (!domain_parent) {
@@ -132,19 +131,24 @@
 		return -EINVAL;
 	}
 
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret)
+		return ret;
+
 	chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL);
 	if (!chip_data)
 		return -ENOMEM;
 
-	chip_data->intpol_base = of_io_request_and_map(node, 0, "intpol");
-	if (IS_ERR(chip_data->intpol_base)) {
+	size = resource_size(&res);
+	intpol_num = size * 8;
+	chip_data->intpol_base = ioremap(res.start, size);
+	if (!chip_data->intpol_base) {
 		pr_err("mtk_sysirq: unable to map sysirq register\n");
 		ret = PTR_ERR(chip_data->intpol_base);
 		goto out_free;
 	}
 
-	domain = irq_domain_add_hierarchy(domain_parent, 0,
-					  MT6577_SYS_INTPOL_NUM, node,
+	domain = irq_domain_add_hierarchy(domain_parent, 0, intpol_num, node,
 					  &sysirq_domain_ops, chip_data);
 	if (!domain) {
 		ret = -ENOMEM;
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c
index c03f140..a569c6d 100644
--- a/drivers/irqchip/irq-omap-intc.c
+++ b/drivers/irqchip/irq-omap-intc.c
@@ -364,14 +364,6 @@
 		omap_ack_irq(NULL);
 }
 
-void __init omap2_init_irq(void)
-{
-	omap_nr_irqs = 96;
-	omap_nr_pending = 3;
-	omap_init_irq(OMAP24XX_IC_BASE, NULL);
-	set_handle_irq(omap_intc_handle_irq);
-}
-
 void __init omap3_init_irq(void)
 {
 	omap_nr_irqs = 96;
@@ -380,14 +372,6 @@
 	set_handle_irq(omap_intc_handle_irq);
 }
 
-void __init ti81xx_init_irq(void)
-{
-	omap_nr_irqs = 96;
-	omap_nr_pending = 4;
-	omap_init_irq(OMAP34XX_IC_BASE, NULL);
-	set_handle_irq(omap_intc_handle_irq);
-}
-
 static int __init intc_of_init(struct device_node *node,
 			     struct device_node *parent)
 {
@@ -399,7 +383,9 @@
 	if (WARN_ON(!node))
 		return -ENODEV;
 
-	if (of_device_is_compatible(node, "ti,am33xx-intc")) {
+	if (of_device_is_compatible(node, "ti,dm814-intc") ||
+	    of_device_is_compatible(node, "ti,dm816-intc") ||
+	    of_device_is_compatible(node, "ti,am33xx-intc")) {
 		omap_nr_irqs = 128;
 		omap_nr_pending = 4;
 	}
@@ -415,4 +401,6 @@
 
 IRQCHIP_DECLARE(omap2_intc, "ti,omap2-intc", intc_of_init);
 IRQCHIP_DECLARE(omap3_intc, "ti,omap3-intc", intc_of_init);
+IRQCHIP_DECLARE(dm814x_intc, "ti,dm814-intc", intc_of_init);
+IRQCHIP_DECLARE(dm816x_intc, "ti,dm816-intc", intc_of_init);
 IRQCHIP_DECLARE(am33xx_intc, "ti,am33xx-intc", intc_of_init);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 078cac5..9a0767b 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_data/irq-renesas-intc-irqpin.h>
 #include <linux/pm_runtime.h>
 
@@ -40,7 +41,9 @@
 #define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
 #define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
 #define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
-#define INTC_IRQPIN_REG_NR 5
+#define INTC_IRQPIN_REG_NR_MANDATORY 5
+#define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */
+#define INTC_IRQPIN_REG_NR 6
 
 /* INTC external IRQ PIN hardware register access:
  *
@@ -82,6 +85,10 @@
 	u8 shared_irq_mask;
 };
 
+struct intc_irqpin_irlm_config {
+	unsigned int irlm_bit;
+};
+
 static unsigned long intc_irqpin_read32(void __iomem *iomem)
 {
 	return ioread32(iomem);
@@ -345,10 +352,23 @@
 	.xlate  = irq_domain_xlate_twocell,
 };
 
+static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a7779 = {
+	.irlm_bit = 23, /* ICR0.IRLM0 */
+};
+
+static const struct of_device_id intc_irqpin_dt_ids[] = {
+	{ .compatible = "renesas,intc-irqpin", },
+	{ .compatible = "renesas,intc-irqpin-r8a7779",
+	  .data = &intc_irqpin_irlm_r8a7779 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
+
 static int intc_irqpin_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct renesas_intc_irqpin_config *pdata = dev->platform_data;
+	const struct of_device_id *of_id;
 	struct intc_irqpin_priv *p;
 	struct intc_irqpin_iomem *i;
 	struct resource *io[INTC_IRQPIN_REG_NR];
@@ -391,10 +411,11 @@
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 
-	/* get hold of manadatory IOMEM */
+	/* get hold of register banks */
+	memset(io, 0, sizeof(io));
 	for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
 		io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
-		if (!io[k]) {
+		if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) {
 			dev_err(dev, "not enough IOMEM resources\n");
 			ret = -EINVAL;
 			goto err0;
@@ -422,6 +443,10 @@
 	for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
 		i = &p->iomem[k];
 
+		/* handle optional registers */
+		if (!io[k])
+			continue;
+
 		switch (resource_size(io[k])) {
 		case 1:
 			i->width = 8;
@@ -448,6 +473,19 @@
 		}
 	}
 
+	/* configure "individual IRQ mode" where needed */
+	of_id = of_match_device(intc_irqpin_dt_ids, dev);
+	if (of_id && of_id->data) {
+		const struct intc_irqpin_irlm_config *irlm_config = of_id->data;
+
+		if (io[INTC_IRQPIN_REG_IRLM])
+			intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
+						      irlm_config->irlm_bit,
+						      1, 1);
+		else
+			dev_warn(dev, "unable to select IRLM mode\n");
+	}
+
 	/* mask all interrupts using priority */
 	for (k = 0; k < p->number_of_irqs; k++)
 		intc_irqpin_mask_unmask_prio(p, k, 1);
@@ -550,12 +588,6 @@
 	return 0;
 }
 
-static const struct of_device_id intc_irqpin_dt_ids[] = {
-	{ .compatible = "renesas,intc-irqpin", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
-
 static struct platform_driver intc_irqpin_device_driver = {
 	.probe		= intc_irqpin_probe,
 	.remove		= intc_irqpin_remove,
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 922a1ac..6adfd7b 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -47,6 +47,7 @@
 #include <asm/lguest.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/tlbflush.h>
 #include "../lg.h"
 
 static int cpu_had_pge;
@@ -452,9 +453,9 @@
 static void adjust_pge(void *on)
 {
 	if (on)
-		write_cr4(read_cr4() | X86_CR4_PGE);
+		cr4_set_bits(X86_CR4_PGE);
 	else
-		write_cr4(read_cr4() & ~X86_CR4_PGE);
+		cr4_clear_bits(X86_CR4_PGE);
 }
 
 /*H:020
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
index 5e1bd5d..0af7361 100644
--- a/drivers/mcb/mcb-pci.c
+++ b/drivers/mcb/mcb-pci.c
@@ -51,7 +51,7 @@
 	priv->mapbase = pci_resource_start(pdev, 0);
 	if (!priv->mapbase) {
 		dev_err(&pdev->dev, "No PCI resource\n");
-		goto err_start;
+		goto out_disable;
 	}
 
 	res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE,
@@ -59,14 +59,14 @@
 	if (IS_ERR(res)) {
 		dev_err(&pdev->dev, "Failed to request PCI memory\n");
 		ret = PTR_ERR(res);
-		goto err_start;
+		goto out_disable;
 	}
 
 	priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE);
 	if (!priv->base) {
 		dev_err(&pdev->dev, "Cannot ioremap\n");
 		ret = -ENOMEM;
-		goto err_ioremap;
+		goto out_release;
 	}
 
 	flags = pci_resource_flags(pdev, 0);
@@ -74,7 +74,7 @@
 		ret = -ENOTSUPP;
 		dev_err(&pdev->dev,
 			"IO mapped PCI devices are not supported\n");
-		goto err_ioremap;
+		goto out_release;
 	}
 
 	pci_set_drvdata(pdev, priv);
@@ -82,14 +82,14 @@
 	priv->bus = mcb_alloc_bus(&pdev->dev);
 	if (IS_ERR(priv->bus)) {
 		ret = PTR_ERR(priv->bus);
-		goto err_drvdata;
+		goto out_iounmap;
 	}
 
 	priv->bus->get_irq = mcb_pci_get_irq;
 
 	ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base);
 	if (ret < 0)
-		goto err_drvdata;
+		goto out_iounmap;
 	num_cells = ret;
 
 	dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
@@ -98,11 +98,11 @@
 
 	return 0;
 
-err_drvdata:
+out_iounmap:
 	iounmap(priv->base);
-err_ioremap:
+out_release:
 	pci_release_region(pdev, 0);
-err_start:
+out_disable:
 	pci_disable_device(pdev);
 	return ret;
 }
diff --git a/drivers/message/Makefile b/drivers/message/Makefile
index 97ef5a0..755676d 100644
--- a/drivers/message/Makefile
+++ b/drivers/message/Makefile
@@ -2,5 +2,4 @@
 # Makefile for MPT based block devices
 #
 
-obj-$(CONFIG_I2O)	+= i2o/
 obj-$(CONFIG_FUSION)	+= fusion/
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
deleted file mode 100644
index 5afa0e3..0000000
--- a/drivers/message/i2o/Kconfig
+++ /dev/null
@@ -1,121 +0,0 @@
-
-menuconfig I2O
-	tristate "I2O device support"
-	depends on PCI
-	---help---
-	  The Intelligent Input/Output (I2O) architecture allows hardware
-	  drivers to be split into two parts: an operating system specific
-	  module called the OSM and an hardware specific module called the
-	  HDM. The OSM can talk to a whole range of HDM's, and ideally the
-	  HDM's are not OS dependent. This allows for the same HDM driver to
-	  be used under different operating systems if the relevant OSM is in
-	  place. In order for this to work, you need to have an I2O interface
-	  adapter card in your computer. This card contains a special I/O
-	  processor (IOP), thus allowing high speeds since the CPU does not
-	  have to deal with I/O.
-
-	  If you say Y here, you will get a choice of interface adapter
-	  drivers and OSM's with the following questions.
-
-	  To compile this support as a module, choose M here: the
-	  modules will be called i2o_core.
-
-	  If unsure, say N.
-
-if I2O
-
-config I2O_LCT_NOTIFY_ON_CHANGES
-	bool "Enable LCT notification"
-	default y
-	---help---
-	  Only say N here if you have a I2O controller from SUN. The SUN
-	  firmware doesn't support LCT notification on changes. If this option
-	  is enabled on such a controller the driver will hang up in a endless
-	  loop. On all other controllers say Y.
-
-	  If unsure, say Y.
-
-config I2O_EXT_ADAPTEC
-	bool "Enable Adaptec extensions"
-	default y
-	---help---
-	  Say Y for support of raidutils for Adaptec I2O controllers. You also
-	  have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
-	  and to "SCSI generic support" under "SCSI device configuration".
-
-config I2O_EXT_ADAPTEC_DMA64
-	bool "Enable 64-bit DMA"
-	depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
-	default y
-	---help---
-	  Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
-	  controllers.
-	  Note: You need at least firmware version 3709.
-
-config I2O_CONFIG
-	tristate "I2O Configuration support"
-	depends on VIRT_TO_BUS
-	---help---
-	  Say Y for support of the configuration interface for the I2O adapters.
-	  If you have a RAID controller from Adaptec and you want to use the
-	  raidutils to manage your RAID array, you have to say Y here.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called i2o_config.
-
-	  Note: If you want to use the new API you have to download the
-	  i2o_config patch from http://i2o.shadowconnect.com/
-
-config I2O_CONFIG_OLD_IOCTL
-	bool "Enable ioctls (OBSOLETE)"
-	depends on I2O_CONFIG
-	default y
-	---help---
-	  Enables old ioctls.
-
-config I2O_BUS
-	tristate "I2O Bus Adapter OSM"
-	---help---
-	  Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
-	  provides access to the busses on the I2O controller. The main purpose
-	  is to rescan the bus to find new devices.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called i2o_bus.
-
-config I2O_BLOCK
-	tristate "I2O Block OSM"
-	depends on BLOCK
-	---help---
-	  Include support for the I2O Block OSM. The Block OSM presents disk
-	  and other structured block devices to the operating system. If you
-	  are using an RAID controller, you could access the array only by
-	  the Block OSM driver. But it is possible to access the single disks
-	  by the SCSI OSM driver, for example to monitor the disks.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called i2o_block.
-
-config I2O_SCSI
-	tristate "I2O SCSI OSM"
-	depends on SCSI
-	---help---
-	  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
-	  I2O controller. You can use both the SCSI and Block OSM together if
-	  you wish. To access a RAID array, you must use the Block OSM driver.
-	  But you could use the SCSI OSM driver to monitor the single disks.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called i2o_scsi.
-
-config I2O_PROC
-	tristate "I2O /proc support"
-	---help---
-	  If you say Y here and to "/proc file system support", you will be
-	  able to read I2O related information from the virtual directory
-	  /proc/i2o.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called i2o_proc.
-
-endif # I2O
diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
deleted file mode 100644
index c463dc2..0000000
--- a/drivers/message/i2o/bus-osm.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- *	Bus Adapter OSM
- *
- *	Copyright (C) 2005	Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- *	Fixes/additions:
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>
- *			initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-
-#define OSM_NAME	"bus-osm"
-#define OSM_VERSION	"1.317"
-#define OSM_DESCRIPTION	"I2O Bus Adapter OSM"
-
-static struct i2o_driver i2o_bus_driver;
-
-/* Bus OSM class handling definition */
-static struct i2o_class_id i2o_bus_class_id[] = {
-	{I2O_CLASS_BUS_ADAPTER},
-	{I2O_CLASS_END}
-};
-
-/**
- *	i2o_bus_scan - Scan the bus for new devices
- *	@dev: I2O device of the bus, which should be scanned
- *
- *	Scans the bus dev for new / removed devices. After the scan a new LCT
- *	will be fetched automatically.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_bus_scan(struct i2o_device *dev)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return -ETIMEDOUT;
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.
-			tid);
-
-	return i2o_msg_post_wait(dev->iop, msg, 60);
-};
-
-/**
- *	i2o_bus_store_scan - Scan the I2O Bus Adapter
- *	@d: device which should be scanned
- *	@attr: device_attribute
- *	@buf: output buffer
- *	@count: buffer size
- *
- *	Returns count.
- */
-static ssize_t i2o_bus_store_scan(struct device *d,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(d);
-	int rc;
-
-	if ((rc = i2o_bus_scan(i2o_dev)))
-		osm_warn("bus scan failed %d\n", rc);
-
-	return count;
-}
-
-/* Bus Adapter OSM device attributes */
-static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
-
-/**
- *	i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
- *	@dev: device to verify if it is a I2O Bus Adapter device
- *
- *	Because we want all Bus Adapters always return 0.
- *	Except when we fail.  Then we are sad.
- *
- *	Returns 0, except when we fail to excel.
- */
-static int i2o_bus_probe(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
-	int rc;
-
-	rc = device_create_file(dev, &dev_attr_scan);
-	if (rc)
-		goto err_out;
-
-	osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
-
-	return 0;
-
-err_out:
-	put_device(dev);
-	return rc;
-};
-
-/**
- *	i2o_bus_remove - remove the I2O Bus Adapter device from the system again
- *	@dev: I2O Bus Adapter device which should be removed
- *
- *	Always returns 0.
- */
-static int i2o_bus_remove(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-
-	device_remove_file(dev, &dev_attr_scan);
-
-	put_device(dev);
-
-	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
-
-	return 0;
-};
-
-/* Bus Adapter OSM driver struct */
-static struct i2o_driver i2o_bus_driver = {
-	.name = OSM_NAME,
-	.classes = i2o_bus_class_id,
-	.driver = {
-		   .probe = i2o_bus_probe,
-		   .remove = i2o_bus_remove,
-		   },
-};
-
-/**
- *	i2o_bus_init - Bus Adapter OSM initialization function
- *
- *	Only register the Bus Adapter OSM in the I2O core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_bus_init(void)
-{
-	int rc;
-
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	/* Register Bus Adapter OSM into I2O core */
-	rc = i2o_driver_register(&i2o_bus_driver);
-	if (rc) {
-		osm_err("Could not register Bus Adapter OSM\n");
-		return rc;
-	}
-
-	return 0;
-};
-
-/**
- *	i2o_bus_exit - Bus Adapter OSM exit function
- *
- *	Unregisters Bus Adapter OSM from I2O core.
- */
-static void __exit i2o_bus_exit(void)
-{
-	i2o_driver_unregister(&i2o_bus_driver);
-};
-
-MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_bus_init);
-module_exit(i2o_bus_exit);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
deleted file mode 100644
index 3bba7aa..0000000
--- a/drivers/message/i2o/config-osm.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *	Configuration OSM
- *
- *	Copyright (C) 2005	Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- *	Fixes/additions:
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>
- *			initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/dcache.h>
-#include <linux/namei.h>
-#include <linux/fs.h>
-
-#include <asm/uaccess.h>
-
-#define OSM_NAME	"config-osm"
-#define OSM_VERSION	"1.323"
-#define OSM_DESCRIPTION	"I2O Configuration OSM"
-
-/* access mode user rw */
-#define S_IWRSR (S_IRUSR | S_IWUSR)
-
-static struct i2o_driver i2o_config_driver;
-
-/* Config OSM driver struct */
-static struct i2o_driver i2o_config_driver = {
-	.name = OSM_NAME,
-};
-
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
-#include "i2o_config.c"
-#endif
-
-/**
- *	i2o_config_init - Configuration OSM initialization function
- *
- *	Registers Configuration OSM in the I2O core and if old ioctl's are
- *	compiled in initialize them.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_config_init(void)
-{
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	if (i2o_driver_register(&i2o_config_driver)) {
-		osm_err("handler register failed.\n");
-		return -EBUSY;
-	}
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
-	if (i2o_config_old_init()) {
-		osm_err("old config handler initialization failed\n");
-		i2o_driver_unregister(&i2o_config_driver);
-		return -EBUSY;
-	}
-#endif
-
-	return 0;
-}
-
-/**
- *	i2o_config_exit - Configuration OSM exit function
- *
- *	If old ioctl's are compiled in exit remove them and unregisters
- *	Configuration OSM from I2O core.
- */
-static void i2o_config_exit(void)
-{
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
-	i2o_config_old_exit();
-#endif
-
-	i2o_driver_unregister(&i2o_config_driver);
-}
-
-MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_config_init);
-module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
deleted file mode 100644
index ce62d8b..0000000
--- a/drivers/message/i2o/debug.c
+++ /dev/null
@@ -1,472 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-
-static void i2o_report_util_cmd(u8 cmd);
-static void i2o_report_exec_cmd(u8 cmd);
-static void i2o_report_fail_status(u8 req_status, u32 * msg);
-static void i2o_report_common_status(u8 req_status);
-static void i2o_report_common_dsc(u16 detailed_status);
-
-/*
- * Used for error reporting/debugging purposes.
- * Report Cmd name, Request status, Detailed Status.
- */
-void i2o_report_status(const char *severity, const char *str,
-		       struct i2o_message *m)
-{
-	u32 *msg = (u32 *) m;
-	u8 cmd = (msg[1] >> 24) & 0xFF;
-	u8 req_status = (msg[4] >> 24) & 0xFF;
-	u16 detailed_status = msg[4] & 0xFFFF;
-
-	if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
-		return;		// No status in this reply
-
-	printk("%s%s: ", severity, str);
-
-	if (cmd < 0x1F)		// Utility cmd
-		i2o_report_util_cmd(cmd);
-
-	else if (cmd >= 0xA0 && cmd <= 0xEF)	// Executive cmd
-		i2o_report_exec_cmd(cmd);
-	else
-		printk("Cmd = %0#2x, ", cmd);	// Other cmds
-
-	if (msg[0] & MSG_FAIL) {
-		i2o_report_fail_status(req_status, msg);
-		return;
-	}
-
-	i2o_report_common_status(req_status);
-
-	if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
-		i2o_report_common_dsc(detailed_status);
-	else
-		printk(" / DetailedStatus = %0#4x.\n",
-		       detailed_status);
-}
-
-/* Used to dump a message to syslog during debugging */
-void i2o_dump_message(struct i2o_message *m)
-{
-#ifdef DEBUG
-	u32 *msg = (u32 *) m;
-	int i;
-	printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
-	       msg[0] >> 16 & 0xffff, msg);
-	for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
-		printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
-#endif
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following fail status are common to all classes.
- * The preserved message must be handled in the reply handler.
- */
-static void i2o_report_fail_status(u8 req_status, u32 * msg)
-{
-	static char *FAIL_STATUS[] = {
-		"0x80",		/* not used */
-		"SERVICE_SUSPENDED",	/* 0x81 */
-		"SERVICE_TERMINATED",	/* 0x82 */
-		"CONGESTION",
-		"FAILURE",
-		"STATE_ERROR",
-		"TIME_OUT",
-		"ROUTING_FAILURE",
-		"INVALID_VERSION",
-		"INVALID_OFFSET",
-		"INVALID_MSG_FLAGS",
-		"FRAME_TOO_SMALL",
-		"FRAME_TOO_LARGE",
-		"INVALID_TARGET_ID",
-		"INVALID_INITIATOR_ID",
-		"INVALID_INITIATOR_CONTEX",	/* 0x8F */
-		"UNKNOWN_FAILURE"	/* 0xFF */
-	};
-
-	if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
-		printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
-		       req_status);
-	else
-		printk("TRANSPORT_%s.\n",
-		       FAIL_STATUS[req_status & 0x0F]);
-
-	/* Dump some details */
-
-	printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
-	       (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
-	printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
-	       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
-	printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
-	       msg[5] >> 16, msg[5] & 0xFFF);
-
-	printk(KERN_ERR "  Severity:  0x%02X\n", (msg[4] >> 16) & 0xFF);
-	if (msg[4] & (1 << 16))
-		printk(KERN_DEBUG "(FormatError), "
-		       "this msg can never be delivered/processed.\n");
-	if (msg[4] & (1 << 17))
-		printk(KERN_DEBUG "(PathError), "
-		       "this msg can no longer be delivered/processed.\n");
-	if (msg[4] & (1 << 18))
-		printk(KERN_DEBUG "(PathState), "
-		       "the system state does not allow delivery.\n");
-	if (msg[4] & (1 << 19))
-		printk(KERN_DEBUG
-		       "(Congestion), resources temporarily not available;"
-		       "do not retry immediately.\n");
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following reply status are common to all classes.
- */
-static void i2o_report_common_status(u8 req_status)
-{
-	static char *REPLY_STATUS[] = {
-		"SUCCESS",
-		"ABORT_DIRTY",
-		"ABORT_NO_DATA_TRANSFER",
-		"ABORT_PARTIAL_TRANSFER",
-		"ERROR_DIRTY",
-		"ERROR_NO_DATA_TRANSFER",
-		"ERROR_PARTIAL_TRANSFER",
-		"PROCESS_ABORT_DIRTY",
-		"PROCESS_ABORT_NO_DATA_TRANSFER",
-		"PROCESS_ABORT_PARTIAL_TRANSFER",
-		"TRANSACTION_ERROR",
-		"PROGRESS_REPORT"
-	};
-
-	if (req_status >= ARRAY_SIZE(REPLY_STATUS))
-		printk("RequestStatus = %0#2x", req_status);
-	else
-		printk("%s", REPLY_STATUS[req_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following detailed status are valid  for executive class,
- * utility class, DDM class and for transaction error replies.
- */
-static void i2o_report_common_dsc(u16 detailed_status)
-{
-	static char *COMMON_DSC[] = {
-		"SUCCESS",
-		"0x01",		// not used
-		"BAD_KEY",
-		"TCL_ERROR",
-		"REPLY_BUFFER_FULL",
-		"NO_SUCH_PAGE",
-		"INSUFFICIENT_RESOURCE_SOFT",
-		"INSUFFICIENT_RESOURCE_HARD",
-		"0x08",		// not used
-		"CHAIN_BUFFER_TOO_LARGE",
-		"UNSUPPORTED_FUNCTION",
-		"DEVICE_LOCKED",
-		"DEVICE_RESET",
-		"INAPPROPRIATE_FUNCTION",
-		"INVALID_INITIATOR_ADDRESS",
-		"INVALID_MESSAGE_FLAGS",
-		"INVALID_OFFSET",
-		"INVALID_PARAMETER",
-		"INVALID_REQUEST",
-		"INVALID_TARGET_ADDRESS",
-		"MESSAGE_TOO_LARGE",
-		"MESSAGE_TOO_SMALL",
-		"MISSING_PARAMETER",
-		"TIMEOUT",
-		"UNKNOWN_ERROR",
-		"UNKNOWN_FUNCTION",
-		"UNSUPPORTED_VERSION",
-		"DEVICE_BUSY",
-		"DEVICE_NOT_AVAILABLE"
-	};
-
-	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
-		printk(" / DetailedStatus = %0#4x.\n",
-		       detailed_status);
-	else
-		printk(" / %s.\n", COMMON_DSC[detailed_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_util_cmd(u8 cmd)
-{
-	switch (cmd) {
-	case I2O_CMD_UTIL_NOP:
-		printk("UTIL_NOP, ");
-		break;
-	case I2O_CMD_UTIL_ABORT:
-		printk("UTIL_ABORT, ");
-		break;
-	case I2O_CMD_UTIL_CLAIM:
-		printk("UTIL_CLAIM, ");
-		break;
-	case I2O_CMD_UTIL_RELEASE:
-		printk("UTIL_CLAIM_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_CONFIG_DIALOG:
-		printk("UTIL_CONFIG_DIALOG, ");
-		break;
-	case I2O_CMD_UTIL_DEVICE_RESERVE:
-		printk("UTIL_DEVICE_RESERVE, ");
-		break;
-	case I2O_CMD_UTIL_DEVICE_RELEASE:
-		printk("UTIL_DEVICE_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_EVT_ACK:
-		printk("UTIL_EVENT_ACKNOWLEDGE, ");
-		break;
-	case I2O_CMD_UTIL_EVT_REGISTER:
-		printk("UTIL_EVENT_REGISTER, ");
-		break;
-	case I2O_CMD_UTIL_LOCK:
-		printk("UTIL_LOCK, ");
-		break;
-	case I2O_CMD_UTIL_LOCK_RELEASE:
-		printk("UTIL_LOCK_RELEASE, ");
-		break;
-	case I2O_CMD_UTIL_PARAMS_GET:
-		printk("UTIL_PARAMS_GET, ");
-		break;
-	case I2O_CMD_UTIL_PARAMS_SET:
-		printk("UTIL_PARAMS_SET, ");
-		break;
-	case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
-		printk("UTIL_REPLY_FAULT_NOTIFY, ");
-		break;
-	default:
-		printk("Cmd = %0#2x, ", cmd);
-	}
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_exec_cmd(u8 cmd)
-{
-	switch (cmd) {
-	case I2O_CMD_ADAPTER_ASSIGN:
-		printk("EXEC_ADAPTER_ASSIGN, ");
-		break;
-	case I2O_CMD_ADAPTER_READ:
-		printk("EXEC_ADAPTER_READ, ");
-		break;
-	case I2O_CMD_ADAPTER_RELEASE:
-		printk("EXEC_ADAPTER_RELEASE, ");
-		break;
-	case I2O_CMD_BIOS_INFO_SET:
-		printk("EXEC_BIOS_INFO_SET, ");
-		break;
-	case I2O_CMD_BOOT_DEVICE_SET:
-		printk("EXEC_BOOT_DEVICE_SET, ");
-		break;
-	case I2O_CMD_CONFIG_VALIDATE:
-		printk("EXEC_CONFIG_VALIDATE, ");
-		break;
-	case I2O_CMD_CONN_SETUP:
-		printk("EXEC_CONN_SETUP, ");
-		break;
-	case I2O_CMD_DDM_DESTROY:
-		printk("EXEC_DDM_DESTROY, ");
-		break;
-	case I2O_CMD_DDM_ENABLE:
-		printk("EXEC_DDM_ENABLE, ");
-		break;
-	case I2O_CMD_DDM_QUIESCE:
-		printk("EXEC_DDM_QUIESCE, ");
-		break;
-	case I2O_CMD_DDM_RESET:
-		printk("EXEC_DDM_RESET, ");
-		break;
-	case I2O_CMD_DDM_SUSPEND:
-		printk("EXEC_DDM_SUSPEND, ");
-		break;
-	case I2O_CMD_DEVICE_ASSIGN:
-		printk("EXEC_DEVICE_ASSIGN, ");
-		break;
-	case I2O_CMD_DEVICE_RELEASE:
-		printk("EXEC_DEVICE_RELEASE, ");
-		break;
-	case I2O_CMD_HRT_GET:
-		printk("EXEC_HRT_GET, ");
-		break;
-	case I2O_CMD_ADAPTER_CLEAR:
-		printk("EXEC_IOP_CLEAR, ");
-		break;
-	case I2O_CMD_ADAPTER_CONNECT:
-		printk("EXEC_IOP_CONNECT, ");
-		break;
-	case I2O_CMD_ADAPTER_RESET:
-		printk("EXEC_IOP_RESET, ");
-		break;
-	case I2O_CMD_LCT_NOTIFY:
-		printk("EXEC_LCT_NOTIFY, ");
-		break;
-	case I2O_CMD_OUTBOUND_INIT:
-		printk("EXEC_OUTBOUND_INIT, ");
-		break;
-	case I2O_CMD_PATH_ENABLE:
-		printk("EXEC_PATH_ENABLE, ");
-		break;
-	case I2O_CMD_PATH_QUIESCE:
-		printk("EXEC_PATH_QUIESCE, ");
-		break;
-	case I2O_CMD_PATH_RESET:
-		printk("EXEC_PATH_RESET, ");
-		break;
-	case I2O_CMD_STATIC_MF_CREATE:
-		printk("EXEC_STATIC_MF_CREATE, ");
-		break;
-	case I2O_CMD_STATIC_MF_RELEASE:
-		printk("EXEC_STATIC_MF_RELEASE, ");
-		break;
-	case I2O_CMD_STATUS_GET:
-		printk("EXEC_STATUS_GET, ");
-		break;
-	case I2O_CMD_SW_DOWNLOAD:
-		printk("EXEC_SW_DOWNLOAD, ");
-		break;
-	case I2O_CMD_SW_UPLOAD:
-		printk("EXEC_SW_UPLOAD, ");
-		break;
-	case I2O_CMD_SW_REMOVE:
-		printk("EXEC_SW_REMOVE, ");
-		break;
-	case I2O_CMD_SYS_ENABLE:
-		printk("EXEC_SYS_ENABLE, ");
-		break;
-	case I2O_CMD_SYS_MODIFY:
-		printk("EXEC_SYS_MODIFY, ");
-		break;
-	case I2O_CMD_SYS_QUIESCE:
-		printk("EXEC_SYS_QUIESCE, ");
-		break;
-	case I2O_CMD_SYS_TAB_SET:
-		printk("EXEC_SYS_TAB_SET, ");
-		break;
-	default:
-		printk("Cmd = %#02x, ", cmd);
-	}
-}
-
-void i2o_debug_state(struct i2o_controller *c)
-{
-	printk(KERN_INFO "%s: State = ", c->name);
-	switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
-	case 0x01:
-		printk("INIT\n");
-		break;
-	case 0x02:
-		printk("RESET\n");
-		break;
-	case 0x04:
-		printk("HOLD\n");
-		break;
-	case 0x05:
-		printk("READY\n");
-		break;
-	case 0x08:
-		printk("OPERATIONAL\n");
-		break;
-	case 0x10:
-		printk("FAILED\n");
-		break;
-	case 0x11:
-		printk("FAULTED\n");
-		break;
-	default:
-		printk("%x (unknown !!)\n",
-		       ((i2o_status_block *) c->status_block.virt)->iop_state);
-	}
-};
-
-void i2o_dump_hrt(struct i2o_controller *c)
-{
-	u32 *rows = (u32 *) c->hrt.virt;
-	u8 *p = (u8 *) c->hrt.virt;
-	u8 *d;
-	int count;
-	int length;
-	int i;
-	int state;
-
-	if (p[3] != 0) {
-		printk(KERN_ERR
-		       "%s: HRT table for controller is too new a version.\n",
-		       c->name);
-		return;
-	}
-
-	count = p[0] | (p[1] << 8);
-	length = p[2];
-
-	printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
-	       c->name, count, length << 2);
-
-	rows += 2;
-
-	for (i = 0; i < count; i++) {
-		printk(KERN_INFO "Adapter %08X: ", rows[0]);
-		p = (u8 *) (rows + 1);
-		d = (u8 *) (rows + 2);
-		state = p[1] << 8 | p[0];
-
-		printk("TID %04X:[", state & 0xFFF);
-		state >>= 12;
-		if (state & (1 << 0))
-			printk("H");	/* Hidden */
-		if (state & (1 << 2)) {
-			printk("P");	/* Present */
-			if (state & (1 << 1))
-				printk("C");	/* Controlled */
-		}
-		if (state > 9)
-			printk("*");	/* Hard */
-
-		printk("]:");
-
-		switch (p[3] & 0xFFFF) {
-		case 0:
-			/* Adapter private bus - easy */
-			printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
-			       d[1] << 8 | d[0], *(u32 *) (d + 4));
-			break;
-		case 1:
-			/* ISA bus */
-			printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
-			       d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
-			break;
-
-		case 2:	/* EISA bus */
-			printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
-			       p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
-			break;
-
-		case 3:	/* MCA bus */
-			printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
-			       d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
-			break;
-
-		case 4:	/* PCI bus */
-			printk("PCI %d: Bus %d Device %d Function %d", p[2],
-			       d[2], d[1], d[0]);
-			break;
-
-		case 0x80:	/* Other */
-		default:
-			printk("Unsupported bus type.");
-			break;
-		}
-		printk("\n");
-		rows += length;
-	}
-}
-
-EXPORT_SYMBOL(i2o_dump_message);
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
deleted file mode 100644
index 98348f4..0000000
--- a/drivers/message/i2o/device.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- *	Functions to handle I2O devices
- *
- *	Copyright (C) 2004	Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- *	Fixes/additions:
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>
- *			initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-/**
- *	i2o_device_issue_claim - claim or release a device
- *	@dev: I2O device to claim or release
- *	@cmd: claim or release command
- *	@type: type of claim
- *
- *	Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
- *	is set by cmd. dev is the I2O device which should be claim or
- *	released and the type is the claim type (see the I2O spec).
- *
- *	Returs 0 on success or negative error code on failure.
- */
-static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
-					 u32 type)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid);
-	msg->body[0] = cpu_to_le32(type);
-
-	return i2o_msg_post_wait(dev->iop, msg, 60);
-}
-
-/**
- *	i2o_device_claim - claim a device for use by an OSM
- *	@dev: I2O device to claim
- *
- *	Do the leg work to assign a device to a given OSM. If the claim succeeds,
- *	the owner is the primary. If the attempt fails a negative errno code
- *	is returned. On success zero is returned.
- */
-int i2o_device_claim(struct i2o_device *dev)
-{
-	int rc = 0;
-
-	mutex_lock(&dev->lock);
-
-	rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
-	if (!rc)
-		pr_debug("i2o: claim of device %d succeeded\n",
-			 dev->lct_data.tid);
-	else
-		pr_debug("i2o: claim of device %d failed %d\n",
-			 dev->lct_data.tid, rc);
-
-	mutex_unlock(&dev->lock);
-
-	return rc;
-}
-
-/**
- *	i2o_device_claim_release - release a device that the OSM is using
- *	@dev: device to release
- *
- *	Drop a claim by an OSM on a given I2O device.
- *
- *	AC - some devices seem to want to refuse an unclaim until they have
- *	finished internal processing. It makes sense since you don't want a
- *	new device to go reconfiguring the entire system until you are done.
- *	Thus we are prepared to wait briefly.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_device_claim_release(struct i2o_device *dev)
-{
-	int tries;
-	int rc = 0;
-
-	mutex_lock(&dev->lock);
-
-	/*
-	 *      If the controller takes a nonblocking approach to
-	 *      releases we have to sleep/poll for a few times.
-	 */
-	for (tries = 0; tries < 10; tries++) {
-		rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
-					    I2O_CLAIM_PRIMARY);
-		if (!rc)
-			break;
-
-		ssleep(1);
-	}
-
-	if (!rc)
-		pr_debug("i2o: claim release of device %d succeeded\n",
-			 dev->lct_data.tid);
-	else
-		pr_debug("i2o: claim release of device %d failed %d\n",
-			 dev->lct_data.tid, rc);
-
-	mutex_unlock(&dev->lock);
-
-	return rc;
-}
-
-/**
- *	i2o_device_release - release the memory for a I2O device
- *	@dev: I2O device which should be released
- *
- *	Release the allocated memory. This function is called if refcount of
- *	device reaches 0 automatically.
- */
-static void i2o_device_release(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-
-	pr_debug("i2o: device %s released\n", dev_name(dev));
-
-	kfree(i2o_dev);
-}
-
-/**
- *	class_id_show - Displays class id of I2O device
- *	@dev: device of which the class id should be displayed
- *	@attr: pointer to device attribute
- *	@buf: buffer into which the class id should be printed
- *
- *	Returns the number of bytes which are printed into the buffer.
- */
-static ssize_t class_id_show(struct device *dev, struct device_attribute *attr,
-			     char *buf)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-
-	sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id);
-	return strlen(buf) + 1;
-}
-static DEVICE_ATTR_RO(class_id);
-
-/**
- *	tid_show - Displays TID of I2O device
- *	@dev: device of which the TID should be displayed
- *	@attr: pointer to device attribute
- *	@buf: buffer into which the TID should be printed
- *
- *	Returns the number of bytes which are printed into the buffer.
- */
-static ssize_t tid_show(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-
-	sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid);
-	return strlen(buf) + 1;
-}
-static DEVICE_ATTR_RO(tid);
-
-/* I2O device attributes */
-static struct attribute *i2o_device_attrs[] = {
-	&dev_attr_class_id.attr,
-	&dev_attr_tid.attr,
-	NULL,
-};
-
-static const struct attribute_group i2o_device_group = {
-	.attrs = i2o_device_attrs,
-};
-
-const struct attribute_group *i2o_device_groups[] = {
-	&i2o_device_group,
-	NULL,
-};
-
-/**
- *	i2o_device_alloc - Allocate a I2O device and initialize it
- *
- *	Allocate the memory for a I2O device and initialize locks and lists
- *
- *	Returns the allocated I2O device or a negative error code if the device
- *	could not be allocated.
- */
-static struct i2o_device *i2o_device_alloc(void)
-{
-	struct i2o_device *dev;
-
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	INIT_LIST_HEAD(&dev->list);
-	mutex_init(&dev->lock);
-
-	dev->device.bus = &i2o_bus_type;
-	dev->device.release = &i2o_device_release;
-
-	return dev;
-}
-
-/**
- *	i2o_device_add - allocate a new I2O device and add it to the IOP
- *	@c: I2O controller that the device is on
- *	@entry: LCT entry of the I2O device
- *
- *	Allocate a new I2O device and initialize it with the LCT entry. The
- *	device is appended to the device list of the controller.
- *
- *	Returns zero on success, or a -ve errno.
- */
-static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
-{
-	struct i2o_device *i2o_dev, *tmp;
-	int rc;
-
-	i2o_dev = i2o_device_alloc();
-	if (IS_ERR(i2o_dev)) {
-		printk(KERN_ERR "i2o: unable to allocate i2o device\n");
-		return PTR_ERR(i2o_dev);
-	}
-
-	i2o_dev->lct_data = *entry;
-
-	dev_set_name(&i2o_dev->device, "%d:%03x", c->unit,
-		     i2o_dev->lct_data.tid);
-
-	i2o_dev->iop = c;
-	i2o_dev->device.parent = &c->device;
-
-	rc = device_register(&i2o_dev->device);
-	if (rc)
-		goto err;
-
-	list_add_tail(&i2o_dev->list, &c->devices);
-
-	/* create user entries for this device */
-	tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
-	if (tmp && (tmp != i2o_dev)) {
-		rc = sysfs_create_link(&i2o_dev->device.kobj,
-				       &tmp->device.kobj, "user");
-		if (rc)
-			goto unreg_dev;
-	}
-
-	/* create user entries referring to this device */
-	list_for_each_entry(tmp, &c->devices, list)
-	    if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
-		&& (tmp != i2o_dev)) {
-		rc = sysfs_create_link(&tmp->device.kobj,
-				       &i2o_dev->device.kobj, "user");
-		if (rc)
-			goto rmlink1;
-	}
-
-	/* create parent entries for this device */
-	tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
-	if (tmp && (tmp != i2o_dev)) {
-		rc = sysfs_create_link(&i2o_dev->device.kobj,
-				       &tmp->device.kobj, "parent");
-		if (rc)
-			goto rmlink1;
-	}
-
-	/* create parent entries referring to this device */
-	list_for_each_entry(tmp, &c->devices, list)
-	    if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
-		&& (tmp != i2o_dev)) {
-		rc = sysfs_create_link(&tmp->device.kobj,
-				       &i2o_dev->device.kobj, "parent");
-		if (rc)
-			goto rmlink2;
-	}
-
-	i2o_driver_notify_device_add_all(i2o_dev);
-
-	pr_debug("i2o: device %s added\n", dev_name(&i2o_dev->device));
-
-	return 0;
-
-rmlink2:
-	/* If link creating failed halfway, we loop whole list to cleanup.
-	 * And we don't care wrong removing of link, because sysfs_remove_link
-	 * will take care of it.
-	 */
-	list_for_each_entry(tmp, &c->devices, list) {
-		if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
-			sysfs_remove_link(&tmp->device.kobj, "parent");
-	}
-	sysfs_remove_link(&i2o_dev->device.kobj, "parent");
-rmlink1:
-	list_for_each_entry(tmp, &c->devices, list)
-		if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
-			sysfs_remove_link(&tmp->device.kobj, "user");
-	sysfs_remove_link(&i2o_dev->device.kobj, "user");
-unreg_dev:
-	list_del(&i2o_dev->list);
-	device_unregister(&i2o_dev->device);
-err:
-	kfree(i2o_dev);
-	return rc;
-}
-
-/**
- *	i2o_device_remove - remove an I2O device from the I2O core
- *	@i2o_dev: I2O device which should be released
- *
- *	Is used on I2O controller removal or LCT modification, when the device
- *	is removed from the system. Note that the device could still hang
- *	around until the refcount reaches 0.
- */
-void i2o_device_remove(struct i2o_device *i2o_dev)
-{
-	struct i2o_device *tmp;
-	struct i2o_controller *c = i2o_dev->iop;
-
-	i2o_driver_notify_device_remove_all(i2o_dev);
-
-	sysfs_remove_link(&i2o_dev->device.kobj, "parent");
-	sysfs_remove_link(&i2o_dev->device.kobj, "user");
-
-	list_for_each_entry(tmp, &c->devices, list) {
-		if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
-			sysfs_remove_link(&tmp->device.kobj, "parent");
-		if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
-			sysfs_remove_link(&tmp->device.kobj, "user");
-	}
-	list_del(&i2o_dev->list);
-
-	device_unregister(&i2o_dev->device);
-}
-
-/**
- *	i2o_device_parse_lct - Parse a previously fetched LCT and create devices
- *	@c: I2O controller from which the LCT should be parsed.
- *
- *	The Logical Configuration Table tells us what we can talk to on the
- *	board. For every entry we create an I2O device, which is registered in
- *	the I2O core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_device_parse_lct(struct i2o_controller *c)
-{
-	struct i2o_device *dev, *tmp;
-	i2o_lct *lct;
-	u32 *dlct = c->dlct.virt;
-	int max = 0, i = 0;
-	u16 table_size;
-	u32 buf;
-
-	mutex_lock(&c->lct_lock);
-
-	kfree(c->lct);
-
-	buf = le32_to_cpu(*dlct++);
-	table_size = buf & 0xffff;
-
-	lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL);
-	if (!lct) {
-		mutex_unlock(&c->lct_lock);
-		return -ENOMEM;
-	}
-
-	lct->lct_ver = buf >> 28;
-	lct->boot_tid = buf >> 16 & 0xfff;
-	lct->table_size = table_size;
-	lct->change_ind = le32_to_cpu(*dlct++);
-	lct->iop_flags = le32_to_cpu(*dlct++);
-
-	table_size -= 3;
-
-	pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max,
-		 lct->table_size);
-
-	while (table_size > 0) {
-		i2o_lct_entry *entry = &lct->lct_entry[max];
-		int found = 0;
-
-		buf = le32_to_cpu(*dlct++);
-		entry->entry_size = buf & 0xffff;
-		entry->tid = buf >> 16 & 0xfff;
-
-		entry->change_ind = le32_to_cpu(*dlct++);
-		entry->device_flags = le32_to_cpu(*dlct++);
-
-		buf = le32_to_cpu(*dlct++);
-		entry->class_id = buf & 0xfff;
-		entry->version = buf >> 12 & 0xf;
-		entry->vendor_id = buf >> 16;
-
-		entry->sub_class = le32_to_cpu(*dlct++);
-
-		buf = le32_to_cpu(*dlct++);
-		entry->user_tid = buf & 0xfff;
-		entry->parent_tid = buf >> 12 & 0xfff;
-		entry->bios_info = buf >> 24;
-
-		memcpy(&entry->identity_tag, dlct, 8);
-		dlct += 2;
-
-		entry->event_capabilities = le32_to_cpu(*dlct++);
-
-		/* add new devices, which are new in the LCT */
-		list_for_each_entry_safe(dev, tmp, &c->devices, list) {
-			if (entry->tid == dev->lct_data.tid) {
-				found = 1;
-				break;
-			}
-		}
-
-		if (!found)
-			i2o_device_add(c, entry);
-
-		table_size -= 9;
-		max++;
-	}
-
-	/* remove devices, which are not in the LCT anymore */
-	list_for_each_entry_safe(dev, tmp, &c->devices, list) {
-		int found = 0;
-
-		for (i = 0; i < max; i++) {
-			if (lct->lct_entry[i].tid == dev->lct_data.tid) {
-				found = 1;
-				break;
-			}
-		}
-
-		if (!found)
-			i2o_device_remove(dev);
-	}
-
-	mutex_unlock(&c->lct_lock);
-
-	return 0;
-}
-
-/*
- *	Run time support routines
- */
-
-/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
- *
- *	This function can be used for all UtilParamsGet/Set operations.
- *	The OperationList is given in oplist-buffer,
- *	and results are returned in reslist-buffer.
- *	Note that the minimum sized reslist is 8 bytes and contains
- *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
- */
-int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
-		   int oplen, void *reslist, int reslen)
-{
-	struct i2o_message *msg;
-	int i = 0;
-	int rc;
-	struct i2o_dma res;
-	struct i2o_controller *c = i2o_dev->iop;
-	struct device *dev = &c->pdev->dev;
-
-	res.virt = NULL;
-
-	if (i2o_dma_alloc(dev, &res, reslen))
-		return -ENOMEM;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg)) {
-		i2o_dma_free(dev, &res);
-		return PTR_ERR(msg);
-	}
-
-	i = 0;
-	msg->u.head[1] =
-	    cpu_to_le32(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid);
-	msg->body[i++] = cpu_to_le32(0x00000000);
-	msg->body[i++] = cpu_to_le32(0x4C000000 | oplen);	/* OperationList */
-	memcpy(&msg->body[i], oplist, oplen);
-	i += (oplen / 4 + (oplen % 4 ? 1 : 0));
-	msg->body[i++] = cpu_to_le32(0xD0000000 | res.len);	/* ResultList */
-	msg->body[i++] = cpu_to_le32(res.phys);
-
-	msg->u.head[0] =
-	    cpu_to_le32(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
-			SGL_OFFSET_5);
-
-	rc = i2o_msg_post_wait_mem(c, msg, 10, &res);
-
-	/* This only looks like a memory leak - don't "fix" it. */
-	if (rc == -ETIMEDOUT)
-		return rc;
-
-	memcpy(reslist, res.virt, res.len);
-	i2o_dma_free(dev, &res);
-
-	return rc;
-}
-
-/*
- *	 Query one field group value or a whole scalar group.
- */
-int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
-		       void *buf, int buflen)
-{
-	u32 opblk[] = { cpu_to_le32(0x00000001),
-		cpu_to_le32((u16) group << 16 | I2O_PARAMS_FIELD_GET),
-		cpu_to_le32((s16) field << 16 | 0x00000001)
-	};
-	u8 *resblk;		/* 8 bytes for header */
-	int rc;
-
-	resblk = kmalloc(buflen + 8, GFP_KERNEL);
-	if (!resblk)
-		return -ENOMEM;
-
-	rc = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
-			    sizeof(opblk), resblk, buflen + 8);
-
-	memcpy(buf, resblk + 8, buflen);	/* cut off header */
-
-	kfree(resblk);
-
-	return rc;
-}
-
-/*
- *	if oper == I2O_PARAMS_TABLE_GET, get from all rows
- *		if fieldcount == -1 return all fields
- *			ibuf and ibuflen are unused (use NULL, 0)
- *		else return specific fields
- *			ibuf contains fieldindexes
- *
- *	if oper == I2O_PARAMS_LIST_GET, get from specific rows
- *		if fieldcount == -1 return all fields
- *			ibuf contains rowcount, keyvalues
- *		else return specific fields
- *			fieldcount is # of fieldindexes
- *			ibuf contains fieldindexes, rowcount, keyvalues
- *
- *	You could also use directly function i2o_issue_params().
- */
-int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
-		       int fieldcount, void *ibuf, int ibuflen, void *resblk,
-		       int reslen)
-{
-	u16 *opblk;
-	int size;
-
-	size = 10 + ibuflen;
-	if (size % 4)
-		size += 4 - size % 4;
-
-	opblk = kmalloc(size, GFP_KERNEL);
-	if (opblk == NULL) {
-		printk(KERN_ERR "i2o: no memory for query buffer.\n");
-		return -ENOMEM;
-	}
-
-	opblk[0] = 1;		/* operation count */
-	opblk[1] = 0;		/* pad */
-	opblk[2] = oper;
-	opblk[3] = group;
-	opblk[4] = fieldcount;
-	memcpy(opblk + 5, ibuf, ibuflen);	/* other params */
-
-	size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
-			      size, resblk, reslen);
-
-	kfree(opblk);
-	if (size > reslen)
-		return reslen;
-
-	return size;
-}
-
-EXPORT_SYMBOL(i2o_device_claim);
-EXPORT_SYMBOL(i2o_device_claim_release);
-EXPORT_SYMBOL(i2o_parm_field_get);
-EXPORT_SYMBOL(i2o_parm_table_get);
-EXPORT_SYMBOL(i2o_parm_issue);
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
deleted file mode 100644
index 1b18a0d..0000000
--- a/drivers/message/i2o/driver.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- *	Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
- *
- *	Copyright (C) 2004	Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- *	Fixes/additions:
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>
- *			initial version.
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/rwsem.h>
-#include <linux/i2o.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-#define OSM_NAME	"i2o"
-
-/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
-static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
-module_param_named(max_drivers, i2o_max_drivers, uint, 0);
-MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
-
-/* I2O drivers lock and array */
-static spinlock_t i2o_drivers_lock;
-static struct i2o_driver **i2o_drivers;
-
-/**
- *	i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM)
- *	@dev: device which should be verified
- *	@drv: the driver to match against
- *
- *	Used by the bus to check if the driver wants to handle the device.
- *
- *	Returns 1 if the class ids of the driver match the class id of the
- *	device, otherwise 0.
- */
-static int i2o_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	struct i2o_driver *i2o_drv = to_i2o_driver(drv);
-	struct i2o_class_id *ids = i2o_drv->classes;
-
-	if (ids)
-		while (ids->class_id != I2O_CLASS_END) {
-			if (ids->class_id == i2o_dev->lct_data.class_id)
-				return 1;
-			ids++;
-		}
-	return 0;
-};
-
-/* I2O bus type */
-struct bus_type i2o_bus_type = {
-	.name = "i2o",
-	.match = i2o_bus_match,
-	.dev_groups = i2o_device_groups,
-};
-
-/**
- *	i2o_driver_register - Register a I2O driver (OSM) in the I2O core
- *	@drv: I2O driver which should be registered
- *
- *	Registers the OSM drv in the I2O core and creates an event queues if
- *	necessary.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_driver_register(struct i2o_driver *drv)
-{
-	struct i2o_controller *c;
-	int i;
-	int rc = 0;
-	unsigned long flags;
-
-	osm_debug("Register driver %s\n", drv->name);
-
-	if (drv->event) {
-		drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
-						   drv->name);
-		if (!drv->event_queue) {
-			osm_err("Could not initialize event queue for driver "
-				"%s\n", drv->name);
-			return -EFAULT;
-		}
-		osm_debug("Event queue initialized for driver %s\n", drv->name);
-	} else
-		drv->event_queue = NULL;
-
-	drv->driver.name = drv->name;
-	drv->driver.bus = &i2o_bus_type;
-
-	spin_lock_irqsave(&i2o_drivers_lock, flags);
-
-	for (i = 0; i2o_drivers[i]; i++)
-		if (i >= i2o_max_drivers) {
-			osm_err("too many drivers registered, increase "
-				"max_drivers\n");
-			spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-			rc = -EFAULT;
-			goto out;
-		}
-
-	drv->context = i;
-	i2o_drivers[i] = drv;
-
-	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
-	osm_debug("driver %s gets context id %d\n", drv->name, drv->context);
-
-	list_for_each_entry(c, &i2o_controllers, list) {
-		struct i2o_device *i2o_dev;
-
-		i2o_driver_notify_controller_add(drv, c);
-		list_for_each_entry(i2o_dev, &c->devices, list)
-		    i2o_driver_notify_device_add(drv, i2o_dev);
-	}
-
-	rc = driver_register(&drv->driver);
-	if (rc)
-		goto out;
-
-	return 0;
-out:
-	if (drv->event_queue) {
-		destroy_workqueue(drv->event_queue);
-		drv->event_queue = NULL;
-	}
-
-	return rc;
-};
-
-/**
- *	i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
- *	@drv: I2O driver which should be unregistered
- *
- *	Unregisters the OSM drv from the I2O core and cleanup event queues if
- *	necessary.
- */
-void i2o_driver_unregister(struct i2o_driver *drv)
-{
-	struct i2o_controller *c;
-	unsigned long flags;
-
-	osm_debug("unregister driver %s\n", drv->name);
-
-	driver_unregister(&drv->driver);
-
-	list_for_each_entry(c, &i2o_controllers, list) {
-		struct i2o_device *i2o_dev;
-
-		list_for_each_entry(i2o_dev, &c->devices, list)
-		    i2o_driver_notify_device_remove(drv, i2o_dev);
-
-		i2o_driver_notify_controller_remove(drv, c);
-	}
-
-	spin_lock_irqsave(&i2o_drivers_lock, flags);
-	i2o_drivers[drv->context] = NULL;
-	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
-	if (drv->event_queue) {
-		destroy_workqueue(drv->event_queue);
-		drv->event_queue = NULL;
-		osm_debug("event queue removed for %s\n", drv->name);
-	}
-};
-
-/**
- *	i2o_driver_dispatch - dispatch an I2O reply message
- *	@c: I2O controller of the message
- *	@m: I2O message number
- *
- *	The reply is delivered to the driver from which the original message
- *	was. This function is only called from interrupt context.
- *
- *	Returns 0 on success and the message should not be flushed. Returns > 0
- *	on success and if the message should be flushed afterwords. Returns
- *	negative error code on failure (the message will be flushed too).
- */
-int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
-{
-	struct i2o_driver *drv;
-	struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
-	u32 context = le32_to_cpu(msg->u.s.icntxt);
-	unsigned long flags;
-
-	if (unlikely(context >= i2o_max_drivers)) {
-		osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
-			 context);
-		return -EIO;
-	}
-
-	spin_lock_irqsave(&i2o_drivers_lock, flags);
-	drv = i2o_drivers[context];
-	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
-	if (unlikely(!drv)) {
-		osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
-			 context);
-		return -EIO;
-	}
-
-	if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
-		struct i2o_device *dev, *tmp;
-		struct i2o_event *evt;
-		u16 size;
-		u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
-
-		osm_debug("event received from device %d\n", tid);
-
-		if (!drv->event)
-			return -EIO;
-
-		/* cut of header from message size (in 32-bit words) */
-		size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
-
-		evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
-		if (!evt)
-			return -ENOMEM;
-
-		evt->size = size;
-		evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
-		evt->event_indicator = le32_to_cpu(msg->body[0]);
-		memcpy(&evt->data, &msg->body[1], size * 4);
-
-		list_for_each_entry_safe(dev, tmp, &c->devices, list)
-		    if (dev->lct_data.tid == tid) {
-			evt->i2o_dev = dev;
-			break;
-		}
-
-		INIT_WORK(&evt->work, drv->event);
-		queue_work(drv->event_queue, &evt->work);
-		return 1;
-	}
-
-	if (unlikely(!drv->reply)) {
-		osm_debug("%s: Reply to driver %s, but no reply function"
-			  " defined!\n", c->name, drv->name);
-		return -EIO;
-	}
-
-	return drv->reply(c, m, msg);
-}
-
-/**
- *	i2o_driver_notify_controller_add_all - Send notify of added controller
- *	@c: newly added controller
- *
- *	Send notifications to all registered drivers that a new controller was
- *	added.
- */
-void i2o_driver_notify_controller_add_all(struct i2o_controller *c)
-{
-	int i;
-	struct i2o_driver *drv;
-
-	for (i = 0; i < i2o_max_drivers; i++) {
-		drv = i2o_drivers[i];
-
-		if (drv)
-			i2o_driver_notify_controller_add(drv, c);
-	}
-}
-
-/**
- *	i2o_driver_notify_controller_remove_all - Send notify of removed controller
- *	@c: controller that is being removed
- *
- *	Send notifications to all registered drivers that a controller was
- *	removed.
- */
-void i2o_driver_notify_controller_remove_all(struct i2o_controller *c)
-{
-	int i;
-	struct i2o_driver *drv;
-
-	for (i = 0; i < i2o_max_drivers; i++) {
-		drv = i2o_drivers[i];
-
-		if (drv)
-			i2o_driver_notify_controller_remove(drv, c);
-	}
-}
-
-/**
- *	i2o_driver_notify_device_add_all - Send notify of added device
- *	@i2o_dev: newly added I2O device
- *
- *	Send notifications to all registered drivers that a device was added.
- */
-void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev)
-{
-	int i;
-	struct i2o_driver *drv;
-
-	for (i = 0; i < i2o_max_drivers; i++) {
-		drv = i2o_drivers[i];
-
-		if (drv)
-			i2o_driver_notify_device_add(drv, i2o_dev);
-	}
-}
-
-/**
- *	i2o_driver_notify_device_remove_all - Send notify of removed device
- *	@i2o_dev: device that is being removed
- *
- *	Send notifications to all registered drivers that a device was removed.
- */
-void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev)
-{
-	int i;
-	struct i2o_driver *drv;
-
-	for (i = 0; i < i2o_max_drivers; i++) {
-		drv = i2o_drivers[i];
-
-		if (drv)
-			i2o_driver_notify_device_remove(drv, i2o_dev);
-	}
-}
-
-/**
- *	i2o_driver_init - initialize I2O drivers (OSMs)
- *
- *	Registers the I2O bus and allocate memory for the array of OSMs.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int __init i2o_driver_init(void)
-{
-	int rc = 0;
-
-	spin_lock_init(&i2o_drivers_lock);
-
-	if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) {
-		osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n",
-			 i2o_max_drivers);
-		i2o_max_drivers = I2O_MAX_DRIVERS;
-	}
-	osm_info("max drivers = %d\n", i2o_max_drivers);
-
-	i2o_drivers =
-	    kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL);
-	if (!i2o_drivers)
-		return -ENOMEM;
-
-	rc = bus_register(&i2o_bus_type);
-
-	if (rc < 0)
-		kfree(i2o_drivers);
-
-	return rc;
-};
-
-/**
- *	i2o_driver_exit - clean up I2O drivers (OSMs)
- *
- *	Unregisters the I2O bus and frees driver array.
- */
-void i2o_driver_exit(void)
-{
-	bus_unregister(&i2o_bus_type);
-	kfree(i2o_drivers);
-};
-
-EXPORT_SYMBOL(i2o_driver_register);
-EXPORT_SYMBOL(i2o_driver_unregister);
-EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
-EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
-EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
-EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
deleted file mode 100644
index a3970e5..0000000
--- a/drivers/message/i2o/exec-osm.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- *	Executive OSM
- *
- * 	Copyright (C) 1999-2002	Red Hat Software
- *
- *	Written by Alan Cox, Building Number Three Ltd
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the
- *	Free Software Foundation; either version 2 of the License, or (at your
- *	option) any later version.
- *
- *	A lot of the I2O message side code from this is taken from the Red
- *	Creek RCPCI45 adapter driver by Red Creek Communications
- *
- *	Fixes/additions:
- *		Philipp Rumpf
- *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *		Deepak Saxena <deepak@plexity.net>
- *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
- *			Ported to Linux 2.5.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Minor fixes for 2.6.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Support for sysfs included.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>	/* wait_event_interruptible_timeout() needs this */
-#include <asm/param.h>		/* HZ */
-#include "core.h"
-
-#define OSM_NAME "exec-osm"
-
-struct i2o_driver i2o_exec_driver;
-
-/* global wait list for POST WAIT */
-static LIST_HEAD(i2o_exec_wait_list);
-
-/* Wait struct needed for POST WAIT */
-struct i2o_exec_wait {
-	wait_queue_head_t *wq;	/* Pointer to Wait queue */
-	struct i2o_dma dma;	/* DMA buffers to free on failure */
-	u32 tcntxt;		/* transaction context from reply */
-	int complete;		/* 1 if reply received otherwise 0 */
-	u32 m;			/* message id */
-	struct i2o_message *msg;	/* pointer to the reply message */
-	struct list_head list;	/* node in global wait list */
-	spinlock_t lock;	/* lock before modifying */
-};
-
-/* Work struct needed to handle LCT NOTIFY replies */
-struct i2o_exec_lct_notify_work {
-	struct work_struct work;	/* work struct */
-	struct i2o_controller *c;	/* controller on which the LCT NOTIFY
-					   was received */
-};
-
-/* Exec OSM class handling definition */
-static struct i2o_class_id i2o_exec_class_id[] = {
-	{I2O_CLASS_EXECUTIVE},
-	{I2O_CLASS_END}
-};
-
-/**
- *	i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
- *
- *	Allocate the i2o_exec_wait struct and initialize the wait.
- *
- *	Returns i2o_exec_wait pointer on success or negative error code on
- *	failure.
- */
-static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
-{
-	struct i2o_exec_wait *wait;
-
-	wait = kzalloc(sizeof(*wait), GFP_KERNEL);
-	if (!wait)
-		return NULL;
-
-	INIT_LIST_HEAD(&wait->list);
-	spin_lock_init(&wait->lock);
-
-	return wait;
-};
-
-/**
- *	i2o_exec_wait_free - Free an i2o_exec_wait struct
- *	@wait: I2O wait data which should be cleaned up
- */
-static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
-{
-	kfree(wait);
-};
-
-/**
- * 	i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
- *	@c: controller
- *	@msg: message to post
- *	@timeout: time in seconds to wait
- *	@dma: i2o_dma struct of the DMA buffer to free on failure
- *
- * 	This API allows an OSM to post a message and then be told whether or
- *	not the system received a successful reply. If the message times out
- *	then the value '-ETIMEDOUT' is returned. This is a special case. In
- *	this situation the message may (should) complete at an indefinite time
- *	in the future. When it completes it will use the memory buffer
- *	attached to the request. If -ETIMEDOUT is returned then the memory
- *	buffer must not be freed. Instead the event completion will free them
- *	for you. In all other cases the buffer are your problem.
- *
- *	Returns 0 on success, negative error code on timeout or positive error
- *	code from reply.
- */
-int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
-			  unsigned long timeout, struct i2o_dma *dma)
-{
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
-	struct i2o_exec_wait *wait;
-	static u32 tcntxt = 0x80000000;
-	unsigned long flags;
-	int rc = 0;
-
-	wait = i2o_exec_wait_alloc();
-	if (!wait) {
-		i2o_msg_nop(c, msg);
-		return -ENOMEM;
-	}
-
-	if (tcntxt == 0xffffffff)
-		tcntxt = 0x80000000;
-
-	if (dma)
-		wait->dma = *dma;
-
-	/*
-	 * Fill in the message initiator context and transaction context.
-	 * We will only use transaction contexts >= 0x80000000 for POST WAIT,
-	 * so we could find a POST WAIT reply easier in the reply handler.
-	 */
-	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
-	wait->tcntxt = tcntxt++;
-	msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
-
-	wait->wq = &wq;
-	/*
-	 * we add elements to the head, because if a entry in the list will
-	 * never be removed, we have to iterate over it every time
-	 */
-	list_add(&wait->list, &i2o_exec_wait_list);
-
-	/*
-	 * Post the message to the controller. At some point later it will
-	 * return. If we time out before it returns then complete will be zero.
-	 */
-	i2o_msg_post(c, msg);
-
-	wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
-
-	spin_lock_irqsave(&wait->lock, flags);
-
-	wait->wq = NULL;
-
-	if (wait->complete)
-		rc = le32_to_cpu(wait->msg->body[0]) >> 24;
-	else {
-		/*
-		 * We cannot remove it now. This is important. When it does
-		 * terminate (which it must do if the controller has not
-		 * died...) then it will otherwise scribble on stuff.
-		 *
-		 * FIXME: try abort message
-		 */
-		if (dma)
-			dma->virt = NULL;
-
-		rc = -ETIMEDOUT;
-	}
-
-	spin_unlock_irqrestore(&wait->lock, flags);
-
-	if (rc != -ETIMEDOUT) {
-		i2o_flush_reply(c, wait->m);
-		i2o_exec_wait_free(wait);
-	}
-
-	return rc;
-};
-
-/**
- *	i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
- *	@c: I2O controller which answers
- *	@m: message id
- *	@msg: pointer to the I2O reply message
- *	@context: transaction context of request
- *
- *	This function is called in interrupt context only. If the reply reached
- *	before the timeout, the i2o_exec_wait struct is filled with the message
- *	and the task will be waked up. The task is now responsible for returning
- *	the message m back to the controller! If the message reaches us after
- *	the timeout clean up the i2o_exec_wait struct (including allocated
- *	DMA buffer).
- *
- *	Return 0 on success and if the message m should not be given back to the
- *	I2O controller, or >0 on success and if the message should be given back
- *	afterwords. Returns negative error code on failure. In this case the
- *	message must also be given back to the controller.
- */
-static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
-				      struct i2o_message *msg, u32 context)
-{
-	struct i2o_exec_wait *wait, *tmp;
-	unsigned long flags;
-	int rc = 1;
-
-	/*
-	 * We need to search through the i2o_exec_wait_list to see if the given
-	 * message is still outstanding. If not, it means that the IOP took
-	 * longer to respond to the message than we had allowed and timer has
-	 * already expired. Not much we can do about that except log it for
-	 * debug purposes, increase timeout, and recompile.
-	 */
-	list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
-		if (wait->tcntxt == context) {
-			spin_lock_irqsave(&wait->lock, flags);
-
-			list_del(&wait->list);
-
-			wait->m = m;
-			wait->msg = msg;
-			wait->complete = 1;
-
-			if (wait->wq)
-				rc = 0;
-			else
-				rc = -1;
-
-			spin_unlock_irqrestore(&wait->lock, flags);
-
-			if (rc) {
-				struct device *dev;
-
-				dev = &c->pdev->dev;
-
-				pr_debug("%s: timedout reply received!\n",
-					 c->name);
-				i2o_dma_free(dev, &wait->dma);
-				i2o_exec_wait_free(wait);
-			} else
-				wake_up_interruptible(wait->wq);
-
-			return rc;
-		}
-	}
-
-	osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
-		 context);
-
-	return -1;
-};
-
-/**
- *	i2o_exec_show_vendor_id - Displays Vendor ID of controller
- *	@d: device of which the Vendor ID should be displayed
- *	@attr: device_attribute to display
- *	@buf: buffer into which the Vendor ID should be printed
- *
- *	Returns number of bytes printed into buffer.
- */
-static ssize_t i2o_exec_show_vendor_id(struct device *d,
-				       struct device_attribute *attr, char *buf)
-{
-	struct i2o_device *dev = to_i2o_device(d);
-	u16 id;
-
-	if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
-		sprintf(buf, "0x%04x", le16_to_cpu(id));
-		return strlen(buf) + 1;
-	}
-
-	return 0;
-};
-
-/**
- *	i2o_exec_show_product_id - Displays Product ID of controller
- *	@d: device of which the Product ID should be displayed
- *	@attr: device_attribute to display
- *	@buf: buffer into which the Product ID should be printed
- *
- *	Returns number of bytes printed into buffer.
- */
-static ssize_t i2o_exec_show_product_id(struct device *d,
-					struct device_attribute *attr,
-					char *buf)
-{
-	struct i2o_device *dev = to_i2o_device(d);
-	u16 id;
-
-	if (!i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
-		sprintf(buf, "0x%04x", le16_to_cpu(id));
-		return strlen(buf) + 1;
-	}
-
-	return 0;
-};
-
-/* Exec-OSM device attributes */
-static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
-static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
-
-/**
- *	i2o_exec_probe - Called if a new I2O device (executive class) appears
- *	@dev: I2O device which should be probed
- *
- *	Registers event notification for every event from Executive device. The
- *	return is always 0, because we want all devices of class Executive.
- *
- *	Returns 0 on success.
- */
-static int i2o_exec_probe(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	int rc;
-
-	rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
-	if (rc) goto err_out;
-
-	rc = device_create_file(dev, &dev_attr_vendor_id);
-	if (rc) goto err_evtreg;
-	rc = device_create_file(dev, &dev_attr_product_id);
-	if (rc) goto err_vid;
-
-	i2o_dev->iop->exec = i2o_dev;
-
-	return 0;
-
-err_vid:
-	device_remove_file(dev, &dev_attr_vendor_id);
-err_evtreg:
-	i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
-err_out:
-	return rc;
-};
-
-/**
- *	i2o_exec_remove - Called on I2O device removal
- *	@dev: I2O device which was removed
- *
- *	Unregisters event notification from Executive I2O device.
- *
- *	Returns 0 on success.
- */
-static int i2o_exec_remove(struct device *dev)
-{
-	device_remove_file(dev, &dev_attr_product_id);
-	device_remove_file(dev, &dev_attr_vendor_id);
-
-	i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
-
-	return 0;
-};
-
-#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
-/**
- *	i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
- *	@c: I2O controller to which the request should be send
- *	@change_ind: change indicator
- *
- *	This function sends a LCT NOTIFY request to the I2O controller with
- *	the change indicator change_ind. If the change_ind == 0 the controller
- *	replies immediately after the request. If change_ind > 0 the reply is
- *	send after change indicator of the LCT is > change_ind.
- */
-static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
-{
-	i2o_status_block *sb = c->status_block.virt;
-	struct device *dev;
-	struct i2o_message *msg;
-
-	mutex_lock(&c->lct_lock);
-
-	dev = &c->pdev->dev;
-
-	if (i2o_dma_realloc(dev, &c->dlct,
-					le32_to_cpu(sb->expected_lct_size))) {
-		mutex_unlock(&c->lct_lock);
-		return -ENOMEM;
-	}
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg)) {
-		mutex_unlock(&c->lct_lock);
-		return PTR_ERR(msg);
-	}
-
-	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
-	msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
-				     ADAPTER_TID);
-	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
-	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
-	msg->body[0] = cpu_to_le32(0xffffffff);
-	msg->body[1] = cpu_to_le32(change_ind);
-	msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
-	msg->body[3] = cpu_to_le32(c->dlct.phys);
-
-	i2o_msg_post(c, msg);
-
-	mutex_unlock(&c->lct_lock);
-
-	return 0;
-}
-#endif
-
-/**
- *	i2o_exec_lct_modified - Called on LCT NOTIFY reply
- *	@_work: work struct for a specific controller
- *
- *	This function handles asynchronus LCT NOTIFY replies. It parses the
- *	new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
- *	again, otherwise send LCT NOTIFY to get informed on next LCT change.
- */
-static void i2o_exec_lct_modified(struct work_struct *_work)
-{
-	struct i2o_exec_lct_notify_work *work =
-		container_of(_work, struct i2o_exec_lct_notify_work, work);
-	u32 change_ind = 0;
-	struct i2o_controller *c = work->c;
-
-	kfree(work);
-
-	if (i2o_device_parse_lct(c) != -EAGAIN)
-		change_ind = c->lct->change_ind + 1;
-
-#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
-	i2o_exec_lct_notify(c, change_ind);
-#endif
-};
-
-/**
- *	i2o_exec_reply -  I2O Executive reply handler
- *	@c: I2O controller from which the reply comes
- *	@m: message id
- *	@msg: pointer to the I2O reply message
- *
- *	This function is always called from interrupt context. If a POST WAIT
- *	reply was received, pass it to the complete function. If a LCT NOTIFY
- *	reply was received, a new event is created to handle the update.
- *
- *	Returns 0 on success and if the reply should not be flushed or > 0
- *	on success and if the reply should be flushed. Returns negative error
- *	code on failure and if the reply should be flushed.
- */
-static int i2o_exec_reply(struct i2o_controller *c, u32 m,
-			  struct i2o_message *msg)
-{
-	u32 context;
-
-	if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
-		struct i2o_message __iomem *pmsg;
-		u32 pm;
-
-		/*
-		 * If Fail bit is set we must take the transaction context of
-		 * the preserved message to find the right request again.
-		 */
-
-		pm = le32_to_cpu(msg->body[3]);
-		pmsg = i2o_msg_in_to_virt(c, pm);
-		context = readl(&pmsg->u.s.tcntxt);
-
-		i2o_report_status(KERN_INFO, "i2o_core", msg);
-
-		/* Release the preserved msg */
-		i2o_msg_nop_mfa(c, pm);
-	} else
-		context = le32_to_cpu(msg->u.s.tcntxt);
-
-	if (context & 0x80000000)
-		return i2o_msg_post_wait_complete(c, m, msg, context);
-
-	if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
-		struct i2o_exec_lct_notify_work *work;
-
-		pr_debug("%s: LCT notify received\n", c->name);
-
-		work = kmalloc(sizeof(*work), GFP_ATOMIC);
-		if (!work)
-			return -ENOMEM;
-
-		work->c = c;
-
-		INIT_WORK(&work->work, i2o_exec_lct_modified);
-		queue_work(i2o_exec_driver.event_queue, &work->work);
-		return 1;
-	}
-
-	/*
-	 * If this happens, we want to dump the message to the syslog so
-	 * it can be sent back to the card manufacturer by the end user
-	 * to aid in debugging.
-	 *
-	 */
-	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
-	       "Message dumped to syslog\n", c->name);
-	i2o_dump_message(msg);
-
-	return -EFAULT;
-}
-
-/**
- *	i2o_exec_event - Event handling function
- *	@work: Work item in occurring event
- *
- *	Handles events send by the Executive device. At the moment does not do
- *	anything useful.
- */
-static void i2o_exec_event(struct work_struct *work)
-{
-	struct i2o_event *evt = container_of(work, struct i2o_event, work);
-
-	if (likely(evt->i2o_dev))
-		osm_debug("Event received from device: %d\n",
-			  evt->i2o_dev->lct_data.tid);
-	kfree(evt);
-};
-
-/**
- *	i2o_exec_lct_get - Get the IOP's Logical Configuration Table
- *	@c: I2O controller from which the LCT should be fetched
- *
- *	Send a LCT NOTIFY request to the controller, and wait
- *	I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
- *	to large, retry it.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_exec_lct_get(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	int i = 0;
-	int rc = -EAGAIN;
-
-	for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
-		msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		msg->u.head[0] =
-		    cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
-		msg->u.head[1] =
-		    cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
-				ADAPTER_TID);
-		msg->body[0] = cpu_to_le32(0xffffffff);
-		msg->body[1] = cpu_to_le32(0x00000000);
-		msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
-		msg->body[3] = cpu_to_le32(c->dlct.phys);
-
-		rc = i2o_msg_post_wait(c, msg, I2O_TIMEOUT_LCT_GET);
-		if (rc < 0)
-			break;
-
-		rc = i2o_device_parse_lct(c);
-		if (rc != -EAGAIN)
-			break;
-	}
-
-	return rc;
-}
-
-/* Exec OSM driver struct */
-struct i2o_driver i2o_exec_driver = {
-	.name = OSM_NAME,
-	.reply = i2o_exec_reply,
-	.event = i2o_exec_event,
-	.classes = i2o_exec_class_id,
-	.driver = {
-		   .probe = i2o_exec_probe,
-		   .remove = i2o_exec_remove,
-		   },
-};
-
-/**
- *	i2o_exec_init - Registers the Exec OSM
- *
- *	Registers the Exec OSM in the I2O core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int __init i2o_exec_init(void)
-{
-	return i2o_driver_register(&i2o_exec_driver);
-};
-
-/**
- *	i2o_exec_exit - Removes the Exec OSM
- *
- *	Unregisters the Exec OSM from the I2O core.
- */
-void i2o_exec_exit(void)
-{
-	i2o_driver_unregister(&i2o_exec_driver);
-};
-
-EXPORT_SYMBOL(i2o_msg_post_wait_mem);
-EXPORT_SYMBOL(i2o_exec_lct_get);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
deleted file mode 100644
index 6fc3866..0000000
--- a/drivers/message/i2o/i2o_block.c
+++ /dev/null
@@ -1,1228 +0,0 @@
-/*
- *	Block OSM
- *
- * 	Copyright (C) 1999-2002	Red Hat Software
- *
- *	Written by Alan Cox, Building Number Three Ltd
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the
- *	Free Software Foundation; either version 2 of the License, or (at your
- *	option) any later version.
- *
- *	This program is distributed in the hope that it will be useful, but
- *	WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *	General Public License for more details.
- *
- *	For the purpose of avoiding doubt the preferred form of the work
- *	for making modifications shall be a standards compliant form such
- *	gzipped tar and not one requiring a proprietary or patent encumbered
- *	tool to unpack.
- *
- *	Fixes/additions:
- *		Steve Ralston:
- *			Multiple device handling error fixes,
- *			Added a queue depth.
- *		Alan Cox:
- *			FC920 has an rmw bug. Dont or in the end marker.
- *			Removed queue walk, fixed for 64bitness.
- *			Rewrote much of the code over time
- *			Added indirect block lists
- *			Handle 64K limits on many controllers
- *			Don't use indirects on the Promise (breaks)
- *			Heavily chop down the queue depths
- *		Deepak Saxena:
- *			Independent queues per IOP
- *			Support for dynamic device creation/deletion
- *			Code cleanup
- *	    		Support for larger I/Os through merge* functions
- *			(taken from DAC960 driver)
- *		Boji T Kannanthanam:
- *			Set the I2O Block devices to be detected in increasing
- *			order of TIDs during boot.
- *			Search and set the I2O block device that we boot off
- *			from as the first device to be claimed (as /dev/i2o/hda)
- *			Properly attach/detach I2O gendisk structure from the
- *			system gendisk list. The I2O block devices now appear in
- *			/proc/partitions.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Minor bugfixes for 2.6.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2o.h>
-#include <linux/mutex.h>
-
-#include <linux/mempool.h>
-
-#include <linux/genhd.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <scsi/scsi.h>
-
-#include "i2o_block.h"
-
-#define OSM_NAME	"block-osm"
-#define OSM_VERSION	"1.325"
-#define OSM_DESCRIPTION	"I2O Block Device OSM"
-
-static DEFINE_MUTEX(i2o_block_mutex);
-static struct i2o_driver i2o_block_driver;
-
-/* global Block OSM request mempool */
-static struct i2o_block_mempool i2o_blk_req_pool;
-
-/* Block OSM class handling definition */
-static struct i2o_class_id i2o_block_class_id[] = {
-	{I2O_CLASS_RANDOM_BLOCK_STORAGE},
-	{I2O_CLASS_END}
-};
-
-/**
- *	i2o_block_device_free - free the memory of the I2O Block device
- *	@dev: I2O Block device, which should be cleaned up
- *
- *	Frees the request queue, gendisk and the i2o_block_device structure.
- */
-static void i2o_block_device_free(struct i2o_block_device *dev)
-{
-	blk_cleanup_queue(dev->gd->queue);
-
-	put_disk(dev->gd);
-
-	kfree(dev);
-};
-
-/**
- *	i2o_block_remove - remove the I2O Block device from the system again
- *	@dev: I2O Block device which should be removed
- *
- *	Remove gendisk from system and free all allocated memory.
- *
- *	Always returns 0.
- */
-static int i2o_block_remove(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev);
-
-	osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
-		 i2o_blk_dev->gd->disk_name);
-
-	i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
-
-	del_gendisk(i2o_blk_dev->gd);
-
-	dev_set_drvdata(dev, NULL);
-
-	i2o_device_claim_release(i2o_dev);
-
-	i2o_block_device_free(i2o_blk_dev);
-
-	return 0;
-};
-
-/**
- *	i2o_block_device flush - Flush all dirty data of I2O device dev
- *	@dev: I2O device which should be flushed
- *
- *	Flushes all dirty data on device dev.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_flush(struct i2o_device *dev)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->
-			lct_data.tid);
-	msg->body[0] = cpu_to_le32(60 << 16);
-	osm_debug("Flushing...\n");
-
-	return i2o_msg_post_wait(dev->iop, msg, 60);
-};
-
-/**
- *	i2o_block_device_mount - Mount (load) the media of device dev
- *	@dev: I2O device which should receive the mount request
- *	@media_id: Media Identifier
- *
- *	Load a media into drive. Identifier should be set to -1, because the
- *	spec does not support any other value.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->
-			lct_data.tid);
-	msg->body[0] = cpu_to_le32(-1);
-	msg->body[1] = cpu_to_le32(0x00000000);
-	osm_debug("Mounting...\n");
-
-	return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- *	i2o_block_device_lock - Locks the media of device dev
- *	@dev: I2O device which should receive the lock request
- *	@media_id: Media Identifier
- *
- *	Lock media of device dev to prevent removal. The media identifier
- *	should be set to -1, because the spec does not support any other value.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->
-			lct_data.tid);
-	msg->body[0] = cpu_to_le32(-1);
-	osm_debug("Locking...\n");
-
-	return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- *	i2o_block_device_unlock - Unlocks the media of device dev
- *	@dev: I2O device which should receive the unlocked request
- *	@media_id: Media Identifier
- *
- *	Unlocks the media in device dev. The media identifier should be set to
- *	-1, because the spec does not support any other value.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id)
-{
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->
-			lct_data.tid);
-	msg->body[0] = cpu_to_le32(media_id);
-	osm_debug("Unlocking...\n");
-
-	return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- *	i2o_block_device_power - Power management for device dev
- *	@dev: I2O device which should receive the power management request
- *	@op: Operation to send
- *
- *	Send a power management request to the device dev.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_power(struct i2o_block_device *dev, u8 op)
-{
-	struct i2o_device *i2o_dev = dev->i2o_dev;
-	struct i2o_controller *c = i2o_dev->iop;
-	struct i2o_message *msg;
-	int rc;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->
-			lct_data.tid);
-	msg->body[0] = cpu_to_le32(op << 24);
-	osm_debug("Power...\n");
-
-	rc = i2o_msg_post_wait(c, msg, 60);
-	if (!rc)
-		dev->power = op;
-
-	return rc;
-};
-
-/**
- *	i2o_block_request_alloc - Allocate an I2O block request struct
- *
- *	Allocates an I2O block request struct and initialize the list.
- *
- *	Returns a i2o_block_request pointer on success or negative error code
- *	on failure.
- */
-static inline struct i2o_block_request *i2o_block_request_alloc(void)
-{
-	struct i2o_block_request *ireq;
-
-	ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC);
-	if (!ireq)
-		return ERR_PTR(-ENOMEM);
-
-	INIT_LIST_HEAD(&ireq->queue);
-	sg_init_table(ireq->sg_table, I2O_MAX_PHYS_SEGMENTS);
-
-	return ireq;
-};
-
-/**
- *	i2o_block_request_free - Frees a I2O block request
- *	@ireq: I2O block request which should be freed
- *
- *	Frees the allocated memory (give it back to the request mempool).
- */
-static inline void i2o_block_request_free(struct i2o_block_request *ireq)
-{
-	mempool_free(ireq, i2o_blk_req_pool.pool);
-};
-
-/**
- *	i2o_block_sglist_alloc - Allocate the SG list and map it
- *	@c: I2O controller to which the request belongs
- *	@ireq: I2O block request
- *	@mptr: message body pointer
- *
- *	Builds the SG list and map it to be accessible by the controller.
- *
- *	Returns 0 on failure or 1 on success.
- */
-static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
-					 struct i2o_block_request *ireq,
-					 u32 ** mptr)
-{
-	int nents;
-	enum dma_data_direction direction;
-
-	ireq->dev = &c->pdev->dev;
-	nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table);
-
-	if (rq_data_dir(ireq->req) == READ)
-		direction = PCI_DMA_FROMDEVICE;
-	else
-		direction = PCI_DMA_TODEVICE;
-
-	ireq->sg_nents = nents;
-
-	return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
-};
-
-/**
- *	i2o_block_sglist_free - Frees the SG list
- *	@ireq: I2O block request from which the SG should be freed
- *
- *	Frees the SG list from the I2O block request.
- */
-static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
-{
-	enum dma_data_direction direction;
-
-	if (rq_data_dir(ireq->req) == READ)
-		direction = PCI_DMA_FROMDEVICE;
-	else
-		direction = PCI_DMA_TODEVICE;
-
-	dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
-};
-
-/**
- *	i2o_block_prep_req_fn - Allocates I2O block device specific struct
- *	@q: request queue for the request
- *	@req: the request to prepare
- *
- *	Allocate the necessary i2o_block_request struct and connect it to
- *	the request. This is needed that we not lose the SG list later on.
- *
- *	Returns BLKPREP_OK on success or BLKPREP_DEFER on failure.
- */
-static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
-{
-	struct i2o_block_device *i2o_blk_dev = q->queuedata;
-	struct i2o_block_request *ireq;
-
-	if (unlikely(!i2o_blk_dev)) {
-		osm_err("block device already removed\n");
-		return BLKPREP_KILL;
-	}
-
-	/* connect the i2o_block_request to the request */
-	if (!req->special) {
-		ireq = i2o_block_request_alloc();
-		if (IS_ERR(ireq)) {
-			osm_debug("unable to allocate i2o_block_request!\n");
-			return BLKPREP_DEFER;
-		}
-
-		ireq->i2o_blk_dev = i2o_blk_dev;
-		req->special = ireq;
-		ireq->req = req;
-	}
-	/* do not come back here */
-	req->cmd_flags |= REQ_DONTPREP;
-
-	return BLKPREP_OK;
-};
-
-/**
- *	i2o_block_delayed_request_fn - delayed request queue function
- *	@work: the delayed request with the queue to start
- *
- *	If the request queue is stopped for a disk, and there is no open
- *	request, a new event is created, which calls this function to start
- *	the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never
- *	be started again.
- */
-static void i2o_block_delayed_request_fn(struct work_struct *work)
-{
-	struct i2o_block_delayed_request *dreq =
-		container_of(work, struct i2o_block_delayed_request,
-			     work.work);
-	struct request_queue *q = dreq->queue;
-	unsigned long flags;
-
-	spin_lock_irqsave(q->queue_lock, flags);
-	blk_start_queue(q);
-	spin_unlock_irqrestore(q->queue_lock, flags);
-	kfree(dreq);
-};
-
-/**
- *	i2o_block_end_request - Post-processing of completed commands
- *	@req: request which should be completed
- *	@error: 0 for success, < 0 for error
- *	@nr_bytes: number of bytes to complete
- *
- *	Mark the request as complete. The lock must not be held when entering.
- *
- */
-static void i2o_block_end_request(struct request *req, int error,
-				  int nr_bytes)
-{
-	struct i2o_block_request *ireq = req->special;
-	struct i2o_block_device *dev = ireq->i2o_blk_dev;
-	struct request_queue *q = req->q;
-	unsigned long flags;
-
-	if (blk_end_request(req, error, nr_bytes))
-		if (error)
-			blk_end_request_all(req, -EIO);
-
-	spin_lock_irqsave(q->queue_lock, flags);
-
-	if (likely(dev)) {
-		dev->open_queue_depth--;
-		list_del(&ireq->queue);
-	}
-
-	blk_start_queue(q);
-
-	spin_unlock_irqrestore(q->queue_lock, flags);
-
-	i2o_block_sglist_free(ireq);
-	i2o_block_request_free(ireq);
-};
-
-/**
- *	i2o_block_reply - Block OSM reply handler.
- *	@c: I2O controller from which the message arrives
- *	@m: message id of reply
- *	@msg: the actual I2O message reply
- *
- *	This function gets all the message replies.
- *
- */
-static int i2o_block_reply(struct i2o_controller *c, u32 m,
-			   struct i2o_message *msg)
-{
-	struct request *req;
-	int error = 0;
-
-	req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
-	if (unlikely(!req)) {
-		osm_err("NULL reply received!\n");
-		return -1;
-	}
-
-	/*
-	 *      Lets see what is cooking. We stuffed the
-	 *      request in the context.
-	 */
-
-	if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
-		u32 status = le32_to_cpu(msg->body[0]);
-		/*
-		 *      Device not ready means two things. One is that the
-		 *      the thing went offline (but not a removal media)
-		 *
-		 *      The second is that you have a SuperTrak 100 and the
-		 *      firmware got constipated. Unlike standard i2o card
-		 *      setups the supertrak returns an error rather than
-		 *      blocking for the timeout in these cases.
-		 *
-		 *      Don't stick a supertrak100 into cache aggressive modes
-		 */
-
-		osm_err("TID %03x error status: 0x%02x, detailed status: "
-			"0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
-			status >> 24, status & 0xffff);
-
-		req->errors++;
-
-		error = -EIO;
-	}
-
-	i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
-
-	return 1;
-};
-
-static void i2o_block_event(struct work_struct *work)
-{
-	struct i2o_event *evt = container_of(work, struct i2o_event, work);
-	osm_debug("event received\n");
-	kfree(evt);
-};
-
-/*
- *	SCSI-CAM for ioctl geometry mapping
- *	Duplicated with SCSI - this should be moved into somewhere common
- *	perhaps genhd ?
- *
- * LBA -> CHS mapping table taken from:
- *
- * "Incorporating the I2O Architecture into BIOS for Intel Architecture
- *  Platforms"
- *
- * This is an I2O document that is only available to I2O members,
- * not developers.
- *
- * From my understanding, this is how all the I2O cards do this
- *
- * Disk Size      | Sectors | Heads | Cylinders
- * ---------------+---------+-------+-------------------
- * 1 < X <= 528M  | 63      | 16    | X/(63 * 16 * 512)
- * 528M < X <= 1G | 63      | 32    | X/(63 * 32 * 512)
- * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
- * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
- *
- */
-#define	BLOCK_SIZE_528M		1081344
-#define	BLOCK_SIZE_1G		2097152
-#define	BLOCK_SIZE_21G		4403200
-#define	BLOCK_SIZE_42G		8806400
-#define	BLOCK_SIZE_84G		17612800
-
-static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls,
-				unsigned char *hds, unsigned char *secs)
-{
-	unsigned long heads, sectors, cylinders;
-
-	sectors = 63L;		/* Maximize sectors per track */
-	if (capacity <= BLOCK_SIZE_528M)
-		heads = 16;
-	else if (capacity <= BLOCK_SIZE_1G)
-		heads = 32;
-	else if (capacity <= BLOCK_SIZE_21G)
-		heads = 64;
-	else if (capacity <= BLOCK_SIZE_42G)
-		heads = 128;
-	else
-		heads = 255;
-
-	cylinders = (unsigned long)capacity / (heads * sectors);
-
-	*cyls = (unsigned short)cylinders;	/* Stuff return values */
-	*secs = (unsigned char)sectors;
-	*hds = (unsigned char)heads;
-}
-
-/**
- *	i2o_block_open - Open the block device
- *	@bdev: block device being opened
- *	@mode: file open mode
- *
- *	Power up the device, mount and lock the media. This function is called,
- *	if the block device is opened for access.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_open(struct block_device *bdev, fmode_t mode)
-{
-	struct i2o_block_device *dev = bdev->bd_disk->private_data;
-
-	if (!dev->i2o_dev)
-		return -ENODEV;
-
-	mutex_lock(&i2o_block_mutex);
-	if (dev->power > 0x1f)
-		i2o_block_device_power(dev, 0x02);
-
-	i2o_block_device_mount(dev->i2o_dev, -1);
-
-	i2o_block_device_lock(dev->i2o_dev, -1);
-
-	osm_debug("Ready.\n");
-	mutex_unlock(&i2o_block_mutex);
-
-	return 0;
-};
-
-/**
- *	i2o_block_release - Release the I2O block device
- *	@disk: gendisk device being released
- *	@mode: file open mode
- *
- *	Unlock and unmount the media, and power down the device. Gets called if
- *	the block device is closed.
- */
-static void i2o_block_release(struct gendisk *disk, fmode_t mode)
-{
-	struct i2o_block_device *dev = disk->private_data;
-	u8 operation;
-
-	/*
-	 * This is to deal with the case of an application
-	 * opening a device and then the device disappears while
-	 * it's in use, and then the application tries to release
-	 * it.  ex: Unmounting a deleted RAID volume at reboot.
-	 * If we send messages, it will just cause FAILs since
-	 * the TID no longer exists.
-	 */
-	if (!dev->i2o_dev)
-		return;
-
-	mutex_lock(&i2o_block_mutex);
-	i2o_block_device_flush(dev->i2o_dev);
-
-	i2o_block_device_unlock(dev->i2o_dev, -1);
-
-	if (dev->flags & (1 << 3 | 1 << 4))	/* Removable */
-		operation = 0x21;
-	else
-		operation = 0x24;
-
-	i2o_block_device_power(dev, operation);
-	mutex_unlock(&i2o_block_mutex);
-}
-
-static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-	i2o_block_biosparam(get_capacity(bdev->bd_disk),
-			    &geo->cylinders, &geo->heads, &geo->sectors);
-	return 0;
-}
-
-/**
- *	i2o_block_ioctl - Issue device specific ioctl calls.
- *	@bdev: block device being opened
- *	@mode: file open mode
- *	@cmd: ioctl command
- *	@arg: arg
- *
- *	Handles ioctl request for the block device.
- *
- *	Return 0 on success or negative error on failure.
- */
-static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
-			   unsigned int cmd, unsigned long arg)
-{
-	struct gendisk *disk = bdev->bd_disk;
-	struct i2o_block_device *dev = disk->private_data;
-	int ret = -ENOTTY;
-
-	/* Anyone capable of this syscall can do *real bad* things */
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-
-	mutex_lock(&i2o_block_mutex);
-	switch (cmd) {
-	case BLKI2OGRSTRAT:
-		ret = put_user(dev->rcache, (int __user *)arg);
-		break;
-	case BLKI2OGWSTRAT:
-		ret = put_user(dev->wcache, (int __user *)arg);
-		break;
-	case BLKI2OSRSTRAT:
-		ret = -EINVAL;
-		if (arg < 0 || arg > CACHE_SMARTFETCH)
-			break;
-		dev->rcache = arg;
-		ret = 0;
-		break;
-	case BLKI2OSWSTRAT:
-		ret = -EINVAL;
-		if (arg != 0
-		    && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK))
-			break;
-		dev->wcache = arg;
-		ret = 0;
-		break;
-	}
-	mutex_unlock(&i2o_block_mutex);
-
-	return ret;
-};
-
-/**
- *	i2o_block_check_events - Have we seen a media change?
- *	@disk: gendisk which should be verified
- *	@clearing: events being cleared
- *
- *	Verifies if the media has changed.
- *
- *	Returns 1 if the media was changed or 0 otherwise.
- */
-static unsigned int i2o_block_check_events(struct gendisk *disk,
-					   unsigned int clearing)
-{
-	struct i2o_block_device *p = disk->private_data;
-
-	if (p->media_change_flag) {
-		p->media_change_flag = 0;
-		return DISK_EVENT_MEDIA_CHANGE;
-	}
-	return 0;
-}
-
-/**
- *	i2o_block_transfer - Transfer a request to/from the I2O controller
- *	@req: the request which should be transferred
- *
- *	This function converts the request into a I2O message. The necessary
- *	DMA buffers are allocated and after everything is setup post the message
- *	to the I2O controller. No cleanup is done by this function. It is done
- *	on the interrupt side when the reply arrives.
- *
- *	Return 0 on success or negative error code on failure.
- */
-static int i2o_block_transfer(struct request *req)
-{
-	struct i2o_block_device *dev = req->rq_disk->private_data;
-	struct i2o_controller *c;
-	u32 tid;
-	struct i2o_message *msg;
-	u32 *mptr;
-	struct i2o_block_request *ireq = req->special;
-	u32 tcntxt;
-	u32 sgl_offset = SGL_OFFSET_8;
-	u32 ctl_flags = 0x00000000;
-	int rc;
-	u32 cmd;
-
-	if (unlikely(!dev->i2o_dev)) {
-		osm_err("transfer to removed drive\n");
-		rc = -ENODEV;
-		goto exit;
-	}
-
-	tid = dev->i2o_dev->lct_data.tid;
-	c = dev->i2o_dev->iop;
-
-	msg = i2o_msg_get(c);
-	if (IS_ERR(msg)) {
-		rc = PTR_ERR(msg);
-		goto exit;
-	}
-
-	tcntxt = i2o_cntxt_list_add(c, req);
-	if (!tcntxt) {
-		rc = -ENOMEM;
-		goto nop_msg;
-	}
-
-	msg->u.s.icntxt = cpu_to_le32(i2o_block_driver.context);
-	msg->u.s.tcntxt = cpu_to_le32(tcntxt);
-
-	mptr = &msg->body[0];
-
-	if (rq_data_dir(req) == READ) {
-		cmd = I2O_CMD_BLOCK_READ << 24;
-
-		switch (dev->rcache) {
-		case CACHE_PREFETCH:
-			ctl_flags = 0x201F0008;
-			break;
-
-		case CACHE_SMARTFETCH:
-			if (blk_rq_sectors(req) > 16)
-				ctl_flags = 0x201F0008;
-			else
-				ctl_flags = 0x001F0000;
-			break;
-
-		default:
-			break;
-		}
-	} else {
-		cmd = I2O_CMD_BLOCK_WRITE << 24;
-
-		switch (dev->wcache) {
-		case CACHE_WRITETHROUGH:
-			ctl_flags = 0x001F0008;
-			break;
-		case CACHE_WRITEBACK:
-			ctl_flags = 0x001F0010;
-			break;
-		case CACHE_SMARTBACK:
-			if (blk_rq_sectors(req) > 16)
-				ctl_flags = 0x001F0004;
-			else
-				ctl_flags = 0x001F0010;
-			break;
-		case CACHE_SMARTTHROUGH:
-			if (blk_rq_sectors(req) > 16)
-				ctl_flags = 0x001F0004;
-			else
-				ctl_flags = 0x001F0010;
-		default:
-			break;
-		}
-	}
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
-	if (c->adaptec) {
-		u8 cmd[10];
-		u32 scsi_flags;
-		u16 hwsec;
-
-		hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT;
-		memset(cmd, 0, 10);
-
-		sgl_offset = SGL_OFFSET_12;
-
-		msg->u.head[1] =
-		    cpu_to_le32(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid);
-
-		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
-		*mptr++ = cpu_to_le32(tid);
-
-		/*
-		 * ENABLE_DISCONNECT
-		 * SIMPLE_TAG
-		 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
-		 */
-		if (rq_data_dir(req) == READ) {
-			cmd[0] = READ_10;
-			scsi_flags = 0x60a0000a;
-		} else {
-			cmd[0] = WRITE_10;
-			scsi_flags = 0xa0a0000a;
-		}
-
-		*mptr++ = cpu_to_le32(scsi_flags);
-
-		*((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec);
-		*((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec);
-
-		memcpy(mptr, cmd, 10);
-		mptr += 4;
-		*mptr++ = cpu_to_le32(blk_rq_bytes(req));
-	} else
-#endif
-	{
-		msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
-		*mptr++ = cpu_to_le32(ctl_flags);
-		*mptr++ = cpu_to_le32(blk_rq_bytes(req));
-		*mptr++ =
-		    cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT));
-		*mptr++ =
-		    cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT));
-	}
-
-	if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
-		rc = -ENOMEM;
-		goto context_remove;
-	}
-
-	msg->u.head[0] =
-	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
-
-	list_add_tail(&ireq->queue, &dev->open_queue);
-	dev->open_queue_depth++;
-
-	i2o_msg_post(c, msg);
-
-	return 0;
-
-      context_remove:
-	i2o_cntxt_list_remove(c, req);
-
-      nop_msg:
-	i2o_msg_nop(c, msg);
-
-      exit:
-	return rc;
-};
-
-/**
- *	i2o_block_request_fn - request queue handling function
- *	@q: request queue from which the request could be fetched
- *
- *	Takes the next request from the queue, transfers it and if no error
- *	occurs dequeue it from the queue. On arrival of the reply the message
- *	will be processed further. If an error occurs requeue the request.
- */
-static void i2o_block_request_fn(struct request_queue *q)
-{
-	struct request *req;
-
-	while ((req = blk_peek_request(q)) != NULL) {
-		if (req->cmd_type == REQ_TYPE_FS) {
-			struct i2o_block_delayed_request *dreq;
-			struct i2o_block_request *ireq = req->special;
-			unsigned int queue_depth;
-
-			queue_depth = ireq->i2o_blk_dev->open_queue_depth;
-
-			if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
-				if (!i2o_block_transfer(req)) {
-					blk_start_request(req);
-					continue;
-				} else
-					osm_info("transfer error\n");
-			}
-
-			if (queue_depth)
-				break;
-
-			/* stop the queue and retry later */
-			dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC);
-			if (!dreq)
-				continue;
-
-			dreq->queue = q;
-			INIT_DELAYED_WORK(&dreq->work,
-					  i2o_block_delayed_request_fn);
-
-			if (!queue_delayed_work(i2o_block_driver.event_queue,
-						&dreq->work,
-						I2O_BLOCK_RETRY_TIME))
-				kfree(dreq);
-			else {
-				blk_stop_queue(q);
-				break;
-			}
-		} else {
-			blk_start_request(req);
-			__blk_end_request_all(req, -EIO);
-		}
-	}
-};
-
-/* I2O Block device operations definition */
-static const struct block_device_operations i2o_block_fops = {
-	.owner = THIS_MODULE,
-	.open = i2o_block_open,
-	.release = i2o_block_release,
-	.ioctl = i2o_block_ioctl,
-	.compat_ioctl = i2o_block_ioctl,
-	.getgeo = i2o_block_getgeo,
-	.check_events = i2o_block_check_events,
-};
-
-/**
- *	i2o_block_device_alloc - Allocate memory for a I2O Block device
- *
- *	Allocate memory for the i2o_block_device struct, gendisk and request
- *	queue and initialize them as far as no additional information is needed.
- *
- *	Returns a pointer to the allocated I2O Block device on success or a
- *	negative error code on failure.
- */
-static struct i2o_block_device *i2o_block_device_alloc(void)
-{
-	struct i2o_block_device *dev;
-	struct gendisk *gd;
-	struct request_queue *queue;
-	int rc;
-
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		osm_err("Insufficient memory to allocate I2O Block disk.\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-	INIT_LIST_HEAD(&dev->open_queue);
-	spin_lock_init(&dev->lock);
-	dev->rcache = CACHE_PREFETCH;
-	dev->wcache = CACHE_WRITEBACK;
-
-	/* allocate a gendisk with 16 partitions */
-	gd = alloc_disk(16);
-	if (!gd) {
-		osm_err("Insufficient memory to allocate gendisk.\n");
-		rc = -ENOMEM;
-		goto cleanup_dev;
-	}
-
-	/* initialize the request queue */
-	queue = blk_init_queue(i2o_block_request_fn, &dev->lock);
-	if (!queue) {
-		osm_err("Insufficient memory to allocate request queue.\n");
-		rc = -ENOMEM;
-		goto cleanup_queue;
-	}
-
-	blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
-
-	gd->major = I2O_MAJOR;
-	gd->queue = queue;
-	gd->fops = &i2o_block_fops;
-	gd->private_data = dev;
-
-	dev->gd = gd;
-
-	return dev;
-
-      cleanup_queue:
-	put_disk(gd);
-
-      cleanup_dev:
-	kfree(dev);
-
-      exit:
-	return ERR_PTR(rc);
-};
-
-/**
- *	i2o_block_probe - verify if dev is a I2O Block device and install it
- *	@dev: device to verify if it is a I2O Block device
- *
- *	We only verify if the user_tid of the device is 0xfff and then install
- *	the device. Otherwise it is used by some other device (e. g. RAID).
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_probe(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	struct i2o_controller *c = i2o_dev->iop;
-	struct i2o_block_device *i2o_blk_dev;
-	struct gendisk *gd;
-	struct request_queue *queue;
-	static int unit = 0;
-	int rc;
-	u64 size;
-	u32 blocksize;
-	u16 body_size = 4;
-	u16 power;
-	unsigned short max_sectors;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
-	if (c->adaptec)
-		body_size = 8;
-#endif
-
-	if (c->limit_sectors)
-		max_sectors = I2O_MAX_SECTORS_LIMITED;
-	else
-		max_sectors = I2O_MAX_SECTORS;
-
-	/* skip devices which are used by IOP */
-	if (i2o_dev->lct_data.user_tid != 0xfff) {
-		osm_debug("skipping used device %03x\n", i2o_dev->lct_data.tid);
-		return -ENODEV;
-	}
-
-	if (i2o_device_claim(i2o_dev)) {
-		osm_warn("Unable to claim device. Installation aborted\n");
-		rc = -EFAULT;
-		goto exit;
-	}
-
-	i2o_blk_dev = i2o_block_device_alloc();
-	if (IS_ERR(i2o_blk_dev)) {
-		osm_err("could not alloc a new I2O block device");
-		rc = PTR_ERR(i2o_blk_dev);
-		goto claim_release;
-	}
-
-	i2o_blk_dev->i2o_dev = i2o_dev;
-	dev_set_drvdata(dev, i2o_blk_dev);
-
-	/* setup gendisk */
-	gd = i2o_blk_dev->gd;
-	gd->first_minor = unit << 4;
-	sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
-	gd->driverfs_dev = &i2o_dev->device;
-
-	/* setup request queue */
-	queue = gd->queue;
-	queue->queuedata = i2o_blk_dev;
-
-	blk_queue_max_hw_sectors(queue, max_sectors);
-	blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
-
-	osm_debug("max sectors = %d\n", queue->max_sectors);
-	osm_debug("phys segments = %d\n", queue->max_phys_segments);
-	osm_debug("max hw segments = %d\n", queue->max_hw_segments);
-
-	/*
-	 *      Ask for the current media data. If that isn't supported
-	 *      then we ask for the device capacity data
-	 */
-	if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
-	    !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
-		blk_queue_logical_block_size(queue, le32_to_cpu(blocksize));
-	} else
-		osm_warn("unable to get blocksize of %s\n", gd->disk_name);
-
-	if (!i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
-	    !i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
-		set_capacity(gd, le64_to_cpu(size) >> KERNEL_SECTOR_SHIFT);
-	} else
-		osm_warn("could not get size of %s\n", gd->disk_name);
-
-	if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
-		i2o_blk_dev->power = power;
-
-	i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff);
-
-	add_disk(gd);
-
-	unit++;
-
-	osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
-		 i2o_blk_dev->gd->disk_name);
-
-	return 0;
-
-      claim_release:
-	i2o_device_claim_release(i2o_dev);
-
-      exit:
-	return rc;
-};
-
-/* Block OSM driver struct */
-static struct i2o_driver i2o_block_driver = {
-	.name = OSM_NAME,
-	.event = i2o_block_event,
-	.reply = i2o_block_reply,
-	.classes = i2o_block_class_id,
-	.driver = {
-		   .probe = i2o_block_probe,
-		   .remove = i2o_block_remove,
-		   },
-};
-
-/**
- *	i2o_block_init - Block OSM initialization function
- *
- *	Allocate the slab and mempool for request structs, registers i2o_block
- *	block device and finally register the Block OSM in the I2O core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_block_init(void)
-{
-	int rc;
-	int size;
-
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	/* Allocate request mempool and slab */
-	size = sizeof(struct i2o_block_request);
-	i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
-						  SLAB_HWCACHE_ALIGN, NULL);
-	if (!i2o_blk_req_pool.slab) {
-		osm_err("can't init request slab\n");
-		rc = -ENOMEM;
-		goto exit;
-	}
-
-	i2o_blk_req_pool.pool =
-		mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
-					 i2o_blk_req_pool.slab);
-	if (!i2o_blk_req_pool.pool) {
-		osm_err("can't init request mempool\n");
-		rc = -ENOMEM;
-		goto free_slab;
-	}
-
-	/* Register the block device interfaces */
-	rc = register_blkdev(I2O_MAJOR, "i2o_block");
-	if (rc) {
-		osm_err("unable to register block device\n");
-		goto free_mempool;
-	}
-#ifdef MODULE
-	osm_info("registered device at major %d\n", I2O_MAJOR);
-#endif
-
-	/* Register Block OSM into I2O core */
-	rc = i2o_driver_register(&i2o_block_driver);
-	if (rc) {
-		osm_err("Could not register Block driver\n");
-		goto unregister_blkdev;
-	}
-
-	return 0;
-
-      unregister_blkdev:
-	unregister_blkdev(I2O_MAJOR, "i2o_block");
-
-      free_mempool:
-	mempool_destroy(i2o_blk_req_pool.pool);
-
-      free_slab:
-	kmem_cache_destroy(i2o_blk_req_pool.slab);
-
-      exit:
-	return rc;
-};
-
-/**
- *	i2o_block_exit - Block OSM exit function
- *
- *	Unregisters Block OSM from I2O core, unregisters i2o_block block device
- *	and frees the mempool and slab.
- */
-static void __exit i2o_block_exit(void)
-{
-	/* Unregister I2O Block OSM from I2O core */
-	i2o_driver_unregister(&i2o_block_driver);
-
-	/* Unregister block device */
-	unregister_blkdev(I2O_MAJOR, "i2o_block");
-
-	/* Free request mempool and slab */
-	mempool_destroy(i2o_blk_req_pool.pool);
-	kmem_cache_destroy(i2o_blk_req_pool.slab);
-};
-
-MODULE_AUTHOR("Red Hat");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_block_init);
-module_exit(i2o_block_exit);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
deleted file mode 100644
index b7d87cd..0000000
--- a/drivers/message/i2o/i2o_proc.c
+++ /dev/null
@@ -1,2045 +0,0 @@
-/*
- *	procfs handler for Linux I2O subsystem
- *
- *	(c) Copyright 1999	Deepak Saxena
- *
- *	Originally written by Deepak Saxena(deepak@plexity.net)
- *
- *	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 is an initial test release. The code is based on the design of the
- *	ide procfs system (drivers/block/ide-proc.c). Some code taken from
- *	i2o-core module by Alan Cox.
- *
- *	DISCLAIMER: This code is still under development/test and may cause
- *	your system to behave unpredictably.  Use at your own discretion.
- *
- *
- *	Fixes/additions:
- *		Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
- *		Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
- *		University of Helsinki, Department of Computer Science
- *			LAN entries
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>
- *			Changes for new I2O API
- */
-
-#define OSM_NAME	"proc-osm"
-#define OSM_VERSION	"1.316"
-#define OSM_DESCRIPTION	"I2O ProcFS OSM"
-
-#define I2O_MAX_MODULES 4
-// FIXME!
-#define FMT_U64_HEX "0x%08x%08x"
-#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-
-/* Structure used to define /proc entries */
-typedef struct _i2o_proc_entry_t {
-	char *name;		/* entry name */
-	umode_t mode;		/* mode */
-	const struct file_operations *fops;	/* open function */
-} i2o_proc_entry;
-
-/* global I2O /proc/i2o entry */
-static struct proc_dir_entry *i2o_proc_dir_root;
-
-/* proc OSM driver struct */
-static struct i2o_driver i2o_proc_driver = {
-	.name = OSM_NAME,
-};
-
-static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
-{
-	int i;
-
-	/* 19990419 -sralston
-	 *      The I2O v1.5 (and v2.0 so far) "official specification"
-	 *      got serial numbers WRONG!
-	 *      Apparently, and despite what Section 3.4.4 says and
-	 *      Figure 3-35 shows (pg 3-39 in the pdf doc),
-	 *      the convention / consensus seems to be:
-	 *        + First byte is SNFormat
-	 *        + Second byte is SNLen (but only if SNFormat==7 (?))
-	 *        + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
-	 */
-	switch (serialno[0]) {
-	case I2O_SNFORMAT_BINARY:	/* Binary */
-		seq_printf(seq, "0x");
-		for (i = 0; i < serialno[1]; i++) {
-			seq_printf(seq, "%02X", serialno[2 + i]);
-		}
-		break;
-
-	case I2O_SNFORMAT_ASCII:	/* ASCII */
-		if (serialno[1] < ' ') {	/* printable or SNLen? */
-			/* sanity */
-			max_len =
-			    (max_len < serialno[1]) ? max_len : serialno[1];
-			serialno[1 + max_len] = '\0';
-
-			/* just print it */
-			seq_printf(seq, "%s", &serialno[2]);
-		} else {
-			/* print chars for specified length */
-			for (i = 0; i < serialno[1]; i++) {
-				seq_printf(seq, "%c", serialno[2 + i]);
-			}
-		}
-		break;
-
-	case I2O_SNFORMAT_UNICODE:	/* UNICODE */
-		seq_printf(seq, "UNICODE Format.  Can't Display\n");
-		break;
-
-	case I2O_SNFORMAT_LAN48_MAC:	/* LAN-48 MAC Address */
-		seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
-		break;
-
-	case I2O_SNFORMAT_WAN:	/* WAN MAC Address */
-		/* FIXME: Figure out what a WAN access address looks like?? */
-		seq_printf(seq, "WAN Access Address");
-		break;
-
-/* plus new in v2.0 */
-	case I2O_SNFORMAT_LAN64_MAC:	/* LAN-64 MAC Address */
-		/* FIXME: Figure out what a LAN-64 address really looks like?? */
-		seq_printf(seq,
-			   "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
-			   serialno[8], serialno[9], &serialno[2]);
-		break;
-
-	case I2O_SNFORMAT_DDM:	/* I2O DDM */
-		seq_printf(seq,
-			   "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
-			   *(u16 *) & serialno[2],
-			   *(u16 *) & serialno[4], *(u16 *) & serialno[6]);
-		break;
-
-	case I2O_SNFORMAT_IEEE_REG64:	/* IEEE Registered (64-bit) */
-	case I2O_SNFORMAT_IEEE_REG128:	/* IEEE Registered (128-bit) */
-		/* FIXME: Figure if this is even close?? */
-		seq_printf(seq,
-			   "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
-			   *(u32 *) & serialno[2],
-			   *(u32 *) & serialno[6],
-			   *(u32 *) & serialno[10], *(u32 *) & serialno[14]);
-		break;
-
-	case I2O_SNFORMAT_UNKNOWN:	/* Unknown 0    */
-	case I2O_SNFORMAT_UNKNOWN2:	/* Unknown 0xff */
-	default:
-		seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]);
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *	i2o_get_class_name - 	do i2o class name lookup
- *	@class: class number
- *
- *	Return a descriptive string for an i2o class.
- */
-static const char *i2o_get_class_name(int class)
-{
-	int idx = 16;
-	static char *i2o_class_name[] = {
-		"Executive",
-		"Device Driver Module",
-		"Block Device",
-		"Tape Device",
-		"LAN Interface",
-		"WAN Interface",
-		"Fibre Channel Port",
-		"Fibre Channel Device",
-		"SCSI Device",
-		"ATE Port",
-		"ATE Device",
-		"Floppy Controller",
-		"Floppy Device",
-		"Secondary Bus Port",
-		"Peer Transport Agent",
-		"Peer Transport",
-		"Unknown"
-	};
-
-	switch (class & 0xfff) {
-	case I2O_CLASS_EXECUTIVE:
-		idx = 0;
-		break;
-	case I2O_CLASS_DDM:
-		idx = 1;
-		break;
-	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-		idx = 2;
-		break;
-	case I2O_CLASS_SEQUENTIAL_STORAGE:
-		idx = 3;
-		break;
-	case I2O_CLASS_LAN:
-		idx = 4;
-		break;
-	case I2O_CLASS_WAN:
-		idx = 5;
-		break;
-	case I2O_CLASS_FIBRE_CHANNEL_PORT:
-		idx = 6;
-		break;
-	case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
-		idx = 7;
-		break;
-	case I2O_CLASS_SCSI_PERIPHERAL:
-		idx = 8;
-		break;
-	case I2O_CLASS_ATE_PORT:
-		idx = 9;
-		break;
-	case I2O_CLASS_ATE_PERIPHERAL:
-		idx = 10;
-		break;
-	case I2O_CLASS_FLOPPY_CONTROLLER:
-		idx = 11;
-		break;
-	case I2O_CLASS_FLOPPY_DEVICE:
-		idx = 12;
-		break;
-	case I2O_CLASS_BUS_ADAPTER:
-		idx = 13;
-		break;
-	case I2O_CLASS_PEER_TRANSPORT_AGENT:
-		idx = 14;
-		break;
-	case I2O_CLASS_PEER_TRANSPORT:
-		idx = 15;
-		break;
-	}
-
-	return i2o_class_name[idx];
-}
-
-#define SCSI_TABLE_SIZE	13
-static char *scsi_devices[] = {
-	"Direct-Access Read/Write",
-	"Sequential-Access Storage",
-	"Printer",
-	"Processor",
-	"WORM Device",
-	"CD-ROM Device",
-	"Scanner Device",
-	"Optical Memory Device",
-	"Medium Changer Device",
-	"Communications Device",
-	"Graphics Art Pre-Press Device",
-	"Graphics Art Pre-Press Device",
-	"Array Controller Device"
-};
-
-static char *chtostr(char *tmp, u8 *chars, int n)
-{
-	tmp[0] = 0;
-	return strncat(tmp, (char *)chars, n);
-}
-
-static int i2o_report_query_status(struct seq_file *seq, int block_status,
-				   char *group)
-{
-	switch (block_status) {
-	case -ETIMEDOUT:
-		return seq_printf(seq, "Timeout reading group %s.\n", group);
-	case -ENOMEM:
-		return seq_printf(seq, "No free memory to read the table.\n");
-	case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
-		return seq_printf(seq, "Group %s not supported.\n", group);
-	default:
-		return seq_printf(seq,
-				  "Error reading group %s. BlockStatus 0x%02X\n",
-				  group, -block_status);
-	}
-}
-
-static char *bus_strings[] = {
-	"Local Bus",
-	"ISA",
-	"EISA",
-	"PCI",
-	"PCMCIA",
-	"NUBUS",
-	"CARDBUS"
-};
-
-static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt;
-	u32 bus;
-	int i;
-
-	if (hrt->hrt_version) {
-		seq_printf(seq,
-			   "HRT table for controller is too new a version.\n");
-		return 0;
-	}
-
-	seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
-		   hrt->num_entries, hrt->entry_len << 2);
-
-	for (i = 0; i < hrt->num_entries; i++) {
-		seq_printf(seq, "Entry %d:\n", i);
-		seq_printf(seq, "   Adapter ID: %0#10x\n",
-			   hrt->hrt_entry[i].adapter_id);
-		seq_printf(seq, "   Controlling tid: %0#6x\n",
-			   hrt->hrt_entry[i].parent_tid);
-
-		if (hrt->hrt_entry[i].bus_type != 0x80) {
-			bus = hrt->hrt_entry[i].bus_type;
-			seq_printf(seq, "   %s Information\n",
-				   bus_strings[bus]);
-
-			switch (bus) {
-			case I2O_BUS_LOCAL:
-				seq_printf(seq, "     IOBase: %0#6x,",
-					   hrt->hrt_entry[i].bus.local_bus.
-					   LbBaseIOPort);
-				seq_printf(seq, " MemoryBase: %0#10x\n",
-					   hrt->hrt_entry[i].bus.local_bus.
-					   LbBaseMemoryAddress);
-				break;
-
-			case I2O_BUS_ISA:
-				seq_printf(seq, "     IOBase: %0#6x,",
-					   hrt->hrt_entry[i].bus.isa_bus.
-					   IsaBaseIOPort);
-				seq_printf(seq, " MemoryBase: %0#10x,",
-					   hrt->hrt_entry[i].bus.isa_bus.
-					   IsaBaseMemoryAddress);
-				seq_printf(seq, " CSN: %0#4x,",
-					   hrt->hrt_entry[i].bus.isa_bus.CSN);
-				break;
-
-			case I2O_BUS_EISA:
-				seq_printf(seq, "     IOBase: %0#6x,",
-					   hrt->hrt_entry[i].bus.eisa_bus.
-					   EisaBaseIOPort);
-				seq_printf(seq, " MemoryBase: %0#10x,",
-					   hrt->hrt_entry[i].bus.eisa_bus.
-					   EisaBaseMemoryAddress);
-				seq_printf(seq, " Slot: %0#4x,",
-					   hrt->hrt_entry[i].bus.eisa_bus.
-					   EisaSlotNumber);
-				break;
-
-			case I2O_BUS_PCI:
-				seq_printf(seq, "     Bus: %0#4x",
-					   hrt->hrt_entry[i].bus.pci_bus.
-					   PciBusNumber);
-				seq_printf(seq, " Dev: %0#4x",
-					   hrt->hrt_entry[i].bus.pci_bus.
-					   PciDeviceNumber);
-				seq_printf(seq, " Func: %0#4x",
-					   hrt->hrt_entry[i].bus.pci_bus.
-					   PciFunctionNumber);
-				seq_printf(seq, " Vendor: %0#6x",
-					   hrt->hrt_entry[i].bus.pci_bus.
-					   PciVendorID);
-				seq_printf(seq, " Device: %0#6x\n",
-					   hrt->hrt_entry[i].bus.pci_bus.
-					   PciDeviceID);
-				break;
-
-			default:
-				seq_printf(seq, "      Unsupported Bus Type\n");
-			}
-		} else
-			seq_printf(seq, "   Unknown Bus Type\n");
-	}
-
-	return 0;
-}
-
-static int i2o_seq_show_lct(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	i2o_lct *lct = (i2o_lct *) c->lct;
-	int entries;
-	int i;
-
-#define BUS_TABLE_SIZE 3
-	static char *bus_ports[] = {
-		"Generic Bus",
-		"SCSI Bus",
-		"Fibre Channel Bus"
-	};
-
-	entries = (lct->table_size - 3) / 9;
-
-	seq_printf(seq, "LCT contains %d %s\n", entries,
-		   entries == 1 ? "entry" : "entries");
-	if (lct->boot_tid)
-		seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid);
-
-	seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
-
-	for (i = 0; i < entries; i++) {
-		seq_printf(seq, "Entry %d\n", i);
-		seq_printf(seq, "  Class, SubClass  : %s",
-			   i2o_get_class_name(lct->lct_entry[i].class_id));
-
-		/*
-		 *      Classes which we'll print subclass info for
-		 */
-		switch (lct->lct_entry[i].class_id & 0xFFF) {
-		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-			switch (lct->lct_entry[i].sub_class) {
-			case 0x00:
-				seq_printf(seq, ", Direct-Access Read/Write");
-				break;
-
-			case 0x04:
-				seq_printf(seq, ", WORM Drive");
-				break;
-
-			case 0x05:
-				seq_printf(seq, ", CD-ROM Drive");
-				break;
-
-			case 0x07:
-				seq_printf(seq, ", Optical Memory Device");
-				break;
-
-			default:
-				seq_printf(seq, ", Unknown (0x%02x)",
-					   lct->lct_entry[i].sub_class);
-				break;
-			}
-			break;
-
-		case I2O_CLASS_LAN:
-			switch (lct->lct_entry[i].sub_class & 0xFF) {
-			case 0x30:
-				seq_printf(seq, ", Ethernet");
-				break;
-
-			case 0x40:
-				seq_printf(seq, ", 100base VG");
-				break;
-
-			case 0x50:
-				seq_printf(seq, ", IEEE 802.5/Token-Ring");
-				break;
-
-			case 0x60:
-				seq_printf(seq, ", ANSI X3T9.5 FDDI");
-				break;
-
-			case 0x70:
-				seq_printf(seq, ", Fibre Channel");
-				break;
-
-			default:
-				seq_printf(seq, ", Unknown Sub-Class (0x%02x)",
-					   lct->lct_entry[i].sub_class & 0xFF);
-				break;
-			}
-			break;
-
-		case I2O_CLASS_SCSI_PERIPHERAL:
-			if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
-				seq_printf(seq, ", %s",
-					   scsi_devices[lct->lct_entry[i].
-							sub_class]);
-			else
-				seq_printf(seq, ", Unknown Device Type");
-			break;
-
-		case I2O_CLASS_BUS_ADAPTER:
-			if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
-				seq_printf(seq, ", %s",
-					   bus_ports[lct->lct_entry[i].
-						     sub_class]);
-			else
-				seq_printf(seq, ", Unknown Bus Type");
-			break;
-		}
-		seq_printf(seq, "\n");
-
-		seq_printf(seq, "  Local TID        : 0x%03x\n",
-			   lct->lct_entry[i].tid);
-		seq_printf(seq, "  User TID         : 0x%03x\n",
-			   lct->lct_entry[i].user_tid);
-		seq_printf(seq, "  Parent TID       : 0x%03x\n",
-			   lct->lct_entry[i].parent_tid);
-		seq_printf(seq, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
-			   lct->lct_entry[i].identity_tag[0],
-			   lct->lct_entry[i].identity_tag[1],
-			   lct->lct_entry[i].identity_tag[2],
-			   lct->lct_entry[i].identity_tag[3],
-			   lct->lct_entry[i].identity_tag[4],
-			   lct->lct_entry[i].identity_tag[5],
-			   lct->lct_entry[i].identity_tag[6],
-			   lct->lct_entry[i].identity_tag[7]);
-		seq_printf(seq, "  Change Indicator : %0#10x\n",
-			   lct->lct_entry[i].change_ind);
-		seq_printf(seq, "  Event Capab Mask : %0#10x\n",
-			   lct->lct_entry[i].device_flags);
-	}
-
-	return 0;
-}
-
-static int i2o_seq_show_status(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	char prodstr[25];
-	int version;
-	i2o_status_block *sb = c->status_block.virt;
-
-	i2o_status_get(c);	// reread the status block
-
-	seq_printf(seq, "Organization ID        : %0#6x\n", sb->org_id);
-
-	version = sb->i2o_version;
-
-/* FIXME for Spec 2.0
-	if (version == 0x02) {
-		seq_printf(seq, "Lowest I2O version supported: ");
-		switch(workspace[2]) {
-			case 0x00:
-				seq_printf(seq, "1.0\n");
-				break;
-			case 0x01:
-				seq_printf(seq, "1.5\n");
-				break;
-			case 0x02:
-				seq_printf(seq, "2.0\n");
-				break;
-		}
-
-		seq_printf(seq, "Highest I2O version supported: ");
-		switch(workspace[3]) {
-			case 0x00:
-				seq_printf(seq, "1.0\n");
-				break;
-			case 0x01:
-				seq_printf(seq, "1.5\n");
-				break;
-			case 0x02:
-				seq_printf(seq, "2.0\n");
-				break;
-		}
-	}
-*/
-	seq_printf(seq, "IOP ID                 : %0#5x\n", sb->iop_id);
-	seq_printf(seq, "Host Unit ID           : %0#6x\n", sb->host_unit_id);
-	seq_printf(seq, "Segment Number         : %0#5x\n", sb->segment_number);
-
-	seq_printf(seq, "I2O version            : ");
-	switch (version) {
-	case 0x00:
-		seq_printf(seq, "1.0\n");
-		break;
-	case 0x01:
-		seq_printf(seq, "1.5\n");
-		break;
-	case 0x02:
-		seq_printf(seq, "2.0\n");
-		break;
-	default:
-		seq_printf(seq, "Unknown version\n");
-	}
-
-	seq_printf(seq, "IOP State              : ");
-	switch (sb->iop_state) {
-	case 0x01:
-		seq_printf(seq, "INIT\n");
-		break;
-
-	case 0x02:
-		seq_printf(seq, "RESET\n");
-		break;
-
-	case 0x04:
-		seq_printf(seq, "HOLD\n");
-		break;
-
-	case 0x05:
-		seq_printf(seq, "READY\n");
-		break;
-
-	case 0x08:
-		seq_printf(seq, "OPERATIONAL\n");
-		break;
-
-	case 0x10:
-		seq_printf(seq, "FAILED\n");
-		break;
-
-	case 0x11:
-		seq_printf(seq, "FAULTED\n");
-		break;
-
-	default:
-		seq_printf(seq, "Unknown\n");
-		break;
-	}
-
-	seq_printf(seq, "Messenger Type         : ");
-	switch (sb->msg_type) {
-	case 0x00:
-		seq_printf(seq, "Memory mapped\n");
-		break;
-	case 0x01:
-		seq_printf(seq, "Memory mapped only\n");
-		break;
-	case 0x02:
-		seq_printf(seq, "Remote only\n");
-		break;
-	case 0x03:
-		seq_printf(seq, "Memory mapped and remote\n");
-		break;
-	default:
-		seq_printf(seq, "Unknown\n");
-	}
-
-	seq_printf(seq, "Inbound Frame Size     : %d bytes\n",
-		   sb->inbound_frame_size << 2);
-	seq_printf(seq, "Max Inbound Frames     : %d\n",
-		   sb->max_inbound_frames);
-	seq_printf(seq, "Current Inbound Frames : %d\n",
-		   sb->cur_inbound_frames);
-	seq_printf(seq, "Max Outbound Frames    : %d\n",
-		   sb->max_outbound_frames);
-
-	/* Spec doesn't say if NULL terminated or not... */
-	memcpy(prodstr, sb->product_id, 24);
-	prodstr[24] = '\0';
-	seq_printf(seq, "Product ID             : %s\n", prodstr);
-	seq_printf(seq, "Expected LCT Size      : %d bytes\n",
-		   sb->expected_lct_size);
-
-	seq_printf(seq, "IOP Capabilities\n");
-	seq_printf(seq, "    Context Field Size Support : ");
-	switch (sb->iop_capabilities & 0x0000003) {
-	case 0:
-		seq_printf(seq, "Supports only 32-bit context fields\n");
-		break;
-	case 1:
-		seq_printf(seq, "Supports only 64-bit context fields\n");
-		break;
-	case 2:
-		seq_printf(seq, "Supports 32-bit and 64-bit context fields, "
-			   "but not concurrently\n");
-		break;
-	case 3:
-		seq_printf(seq, "Supports 32-bit and 64-bit context fields "
-			   "concurrently\n");
-		break;
-	default:
-		seq_printf(seq, "0x%08x\n", sb->iop_capabilities);
-	}
-	seq_printf(seq, "    Current Context Field Size : ");
-	switch (sb->iop_capabilities & 0x0000000C) {
-	case 0:
-		seq_printf(seq, "not configured\n");
-		break;
-	case 4:
-		seq_printf(seq, "Supports only 32-bit context fields\n");
-		break;
-	case 8:
-		seq_printf(seq, "Supports only 64-bit context fields\n");
-		break;
-	case 12:
-		seq_printf(seq, "Supports both 32-bit or 64-bit context fields "
-			   "concurrently\n");
-		break;
-	default:
-		seq_printf(seq, "\n");
-	}
-	seq_printf(seq, "    Inbound Peer Support       : %s\n",
-		   (sb->
-		    iop_capabilities & 0x00000010) ? "Supported" :
-		   "Not supported");
-	seq_printf(seq, "    Outbound Peer Support      : %s\n",
-		   (sb->
-		    iop_capabilities & 0x00000020) ? "Supported" :
-		   "Not supported");
-	seq_printf(seq, "    Peer to Peer Support       : %s\n",
-		   (sb->
-		    iop_capabilities & 0x00000040) ? "Supported" :
-		   "Not supported");
-
-	seq_printf(seq, "Desired private memory size   : %d kB\n",
-		   sb->desired_mem_size >> 10);
-	seq_printf(seq, "Allocated private memory size : %d kB\n",
-		   sb->current_mem_size >> 10);
-	seq_printf(seq, "Private memory base address   : %0#10x\n",
-		   sb->current_mem_base);
-	seq_printf(seq, "Desired private I/O size      : %d kB\n",
-		   sb->desired_io_size >> 10);
-	seq_printf(seq, "Allocated private I/O size    : %d kB\n",
-		   sb->current_io_size >> 10);
-	seq_printf(seq, "Private I/O base address      : %0#10x\n",
-		   sb->current_io_base);
-
-	return 0;
-}
-
-static int i2o_seq_show_hw(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	static u32 work32[5];
-	static u8 *work8 = (u8 *) work32;
-	static u16 *work16 = (u16 *) work32;
-	int token;
-	u32 hwcap;
-
-	static char *cpu_table[] = {
-		"Intel 80960 series",
-		"AMD2900 series",
-		"Motorola 68000 series",
-		"ARM series",
-		"MIPS series",
-		"Sparc series",
-		"PowerPC series",
-		"Intel x86 series"
-	};
-
-	token =
-	    i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0x0000 IOP Hardware");
-		return 0;
-	}
-
-	seq_printf(seq, "I2O Vendor ID    : %0#6x\n", work16[0]);
-	seq_printf(seq, "Product ID       : %0#6x\n", work16[1]);
-	seq_printf(seq, "CPU              : ");
-	if (work8[16] > 8)
-		seq_printf(seq, "Unknown\n");
-	else
-		seq_printf(seq, "%s\n", cpu_table[work8[16]]);
-	/* Anyone using ProcessorVersion? */
-
-	seq_printf(seq, "RAM              : %dkB\n", work32[1] >> 10);
-	seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10);
-
-	hwcap = work32[3];
-	seq_printf(seq, "Capabilities : 0x%08x\n", hwcap);
-	seq_printf(seq, "   [%s] Self booting\n",
-		   (hwcap & 0x00000001) ? "+" : "-");
-	seq_printf(seq, "   [%s] Upgradable IRTOS\n",
-		   (hwcap & 0x00000002) ? "+" : "-");
-	seq_printf(seq, "   [%s] Supports downloading DDMs\n",
-		   (hwcap & 0x00000004) ? "+" : "-");
-	seq_printf(seq, "   [%s] Supports installing DDMs\n",
-		   (hwcap & 0x00000008) ? "+" : "-");
-	seq_printf(seq, "   [%s] Battery-backed RAM\n",
-		   (hwcap & 0x00000010) ? "+" : "-");
-
-	return 0;
-}
-
-/* Executive group 0003h - Executing DDM List (table) */
-static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	int token;
-	int i;
-
-	typedef struct _i2o_exec_execute_ddm_table {
-		u16 ddm_tid;
-		u8 module_type;
-		u8 reserved;
-		u16 i2o_vendor_id;
-		u16 module_id;
-		u8 module_name_version[28];
-		u32 data_size;
-		u32 code_size;
-	} i2o_exec_execute_ddm_table;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES];
-	} *result;
-
-	i2o_exec_execute_ddm_table ddm_table;
-	char tmp[28 + 1];
-
-	result = kmalloc(sizeof(*result), GFP_KERNEL);
-	if (!result)
-		return -ENOMEM;
-
-	token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1,
-				   NULL, 0, result, sizeof(*result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0x0003 Executing DDM List");
-		goto out;
-	}
-
-	seq_printf(seq,
-		   "Tid   Module_type     Vendor Mod_id  Module_name             Vrs  Data_size Code_size\n");
-	ddm_table = result->ddm_table[0];
-
-	for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) {
-		seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
-
-		switch (ddm_table.module_type) {
-		case 0x01:
-			seq_printf(seq, "Downloaded DDM  ");
-			break;
-		case 0x22:
-			seq_printf(seq, "Embedded DDM    ");
-			break;
-		default:
-			seq_printf(seq, "                ");
-		}
-
-		seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id);
-		seq_printf(seq, "%-#8x", ddm_table.module_id);
-		seq_printf(seq, "%-29s",
-			   chtostr(tmp, ddm_table.module_name_version, 28));
-		seq_printf(seq, "%9d  ", ddm_table.data_size);
-		seq_printf(seq, "%8d", ddm_table.code_size);
-
-		seq_printf(seq, "\n");
-	}
-      out:
-	kfree(result);
-	return 0;
-}
-
-/* Executive group 0004h - Driver Store (scalar) */
-static int i2o_seq_show_driver_store(struct seq_file *seq, void *v)
-{
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	u32 work32[8];
-	int token;
-
-	token =
-	    i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32));
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0x0004 Driver Store");
-		return 0;
-	}
-
-	seq_printf(seq, "Module limit  : %d\n"
-		   "Module count  : %d\n"
-		   "Current space : %d kB\n"
-		   "Free space    : %d kB\n",
-		   work32[0], work32[1], work32[2] >> 10, work32[3] >> 10);
-
-	return 0;
-}
-
-/* Executive group 0005h - Driver Store Table (table) */
-static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
-{
-	typedef struct _i2o_driver_store {
-		u16 stored_ddm_index;
-		u8 module_type;
-		u8 reserved;
-		u16 i2o_vendor_id;
-		u16 module_id;
-		u8 module_name_version[28];
-		u8 date[8];
-		u32 module_size;
-		u32 mpb_size;
-		u32 module_flags;
-	} i2o_driver_store_table;
-
-	struct i2o_controller *c = (struct i2o_controller *)seq->private;
-	int token;
-	int i;
-
-	typedef struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_driver_store_table dst[I2O_MAX_MODULES];
-	} i2o_driver_result_table;
-
-	i2o_driver_result_table *result;
-	i2o_driver_store_table *dst;
-	char tmp[28 + 1];
-
-	result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
-	if (result == NULL)
-		return -ENOMEM;
-
-	token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1,
-				   NULL, 0, result, sizeof(*result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0x0005 DRIVER STORE TABLE");
-		kfree(result);
-		return 0;
-	}
-
-	seq_printf(seq,
-		   "#  Module_type     Vendor Mod_id  Module_name             Vrs"
-		   "Date     Mod_size Par_size Flags\n");
-	for (i = 0, dst = &result->dst[0]; i < result->row_count;
-	     dst = &result->dst[++i]) {
-		seq_printf(seq, "%-3d", dst->stored_ddm_index);
-		switch (dst->module_type) {
-		case 0x01:
-			seq_printf(seq, "Downloaded DDM  ");
-			break;
-		case 0x22:
-			seq_printf(seq, "Embedded DDM    ");
-			break;
-		default:
-			seq_printf(seq, "                ");
-		}
-
-		seq_printf(seq, "%-#7x", dst->i2o_vendor_id);
-		seq_printf(seq, "%-#8x", dst->module_id);
-		seq_printf(seq, "%-29s",
-			   chtostr(tmp, dst->module_name_version, 28));
-		seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8));
-		seq_printf(seq, "%8d ", dst->module_size);
-		seq_printf(seq, "%8d ", dst->mpb_size);
-		seq_printf(seq, "0x%04x", dst->module_flags);
-		seq_printf(seq, "\n");
-	}
-
-	kfree(result);
-	return 0;
-}
-
-/* Generic group F000h - Params Descriptor (table) */
-static int i2o_seq_show_groups(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-	u8 properties;
-
-	typedef struct _i2o_group_info {
-		u16 group_number;
-		u16 field_count;
-		u16 row_count;
-		u8 properties;
-		u8 reserved;
-	} i2o_group_info;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_group_info group[256];
-	} *result;
-
-	result = kmalloc(sizeof(*result), GFP_KERNEL);
-	if (!result)
-		return -ENOMEM;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
-				   result, sizeof(*result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF000 Params Descriptor");
-		goto out;
-	}
-
-	seq_printf(seq,
-		   "#  Group   FieldCount RowCount Type   Add Del Clear\n");
-
-	for (i = 0; i < result->row_count; i++) {
-		seq_printf(seq, "%-3d", i);
-		seq_printf(seq, "0x%04X ", result->group[i].group_number);
-		seq_printf(seq, "%10d ", result->group[i].field_count);
-		seq_printf(seq, "%8d ", result->group[i].row_count);
-
-		properties = result->group[i].properties;
-		if (properties & 0x1)
-			seq_printf(seq, "Table  ");
-		else
-			seq_printf(seq, "Scalar ");
-		if (properties & 0x2)
-			seq_printf(seq, " + ");
-		else
-			seq_printf(seq, " - ");
-		if (properties & 0x4)
-			seq_printf(seq, "  + ");
-		else
-			seq_printf(seq, "  - ");
-		if (properties & 0x8)
-			seq_printf(seq, "  + ");
-		else
-			seq_printf(seq, "  - ");
-
-		seq_printf(seq, "\n");
-	}
-
-	if (result->more_flag)
-		seq_printf(seq, "There is more...\n");
-      out:
-	kfree(result);
-	return 0;
-}
-
-/* Generic group F001h - Physical Device Table (table) */
-static int i2o_seq_show_phys_device(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u32 adapter_id[64];
-	} result;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0,
-				   &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0xF001 Physical Device Table");
-		return 0;
-	}
-
-	if (result.row_count)
-		seq_printf(seq, "#  AdapterId\n");
-
-	for (i = 0; i < result.row_count; i++) {
-		seq_printf(seq, "%-2d", i);
-		seq_printf(seq, "%#7x\n", result.adapter_id[i]);
-	}
-
-	if (result.more_flag)
-		seq_printf(seq, "There is more...\n");
-
-	return 0;
-}
-
-/* Generic group F002h - Claimed Table (table) */
-static int i2o_seq_show_claimed(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u16 claimed_tid[64];
-	} result;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0,
-				   &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF002 Claimed Table");
-		return 0;
-	}
-
-	if (result.row_count)
-		seq_printf(seq, "#  ClaimedTid\n");
-
-	for (i = 0; i < result.row_count; i++) {
-		seq_printf(seq, "%-2d", i);
-		seq_printf(seq, "%#7x\n", result.claimed_tid[i]);
-	}
-
-	if (result.more_flag)
-		seq_printf(seq, "There is more...\n");
-
-	return 0;
-}
-
-/* Generic group F003h - User Table (table) */
-static int i2o_seq_show_users(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-
-	typedef struct _i2o_user_table {
-		u16 instance;
-		u16 user_tid;
-		u8 claim_type;
-		u8 reserved1;
-		u16 reserved2;
-	} i2o_user_table;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_user_table user[64];
-	} *result;
-
-	result = kmalloc(sizeof(*result), GFP_KERNEL);
-	if (!result)
-		return -ENOMEM;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0,
-				   result, sizeof(*result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF003 User Table");
-		goto out;
-	}
-
-	seq_printf(seq, "#  Instance UserTid ClaimType\n");
-
-	for (i = 0; i < result->row_count; i++) {
-		seq_printf(seq, "%-3d", i);
-		seq_printf(seq, "%#8x ", result->user[i].instance);
-		seq_printf(seq, "%#7x ", result->user[i].user_tid);
-		seq_printf(seq, "%#9x\n", result->user[i].claim_type);
-	}
-
-	if (result->more_flag)
-		seq_printf(seq, "There is more...\n");
-      out:
-	kfree(result);
-	return 0;
-}
-
-/* Generic group F005h - Private message extensions (table) (optional) */
-static int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-
-	typedef struct _i2o_private {
-		u16 ext_instance;
-		u16 organization_id;
-		u16 x_function_code;
-	} i2o_private;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		i2o_private extension[64];
-	} result;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
-				   &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0xF005 Private Message Extensions (optional)");
-		return 0;
-	}
-
-	seq_printf(seq, "Instance#  OrgId  FunctionCode\n");
-
-	for (i = 0; i < result.row_count; i++) {
-		seq_printf(seq, "%0#9x ", result.extension[i].ext_instance);
-		seq_printf(seq, "%0#6x ", result.extension[i].organization_id);
-		seq_printf(seq, "%0#6x", result.extension[i].x_function_code);
-
-		seq_printf(seq, "\n");
-	}
-
-	if (result.more_flag)
-		seq_printf(seq, "There is more...\n");
-
-	return 0;
-}
-
-/* Generic group F006h - Authorized User Table (table) */
-static int i2o_seq_show_authorized_users(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-	int i;
-
-	struct {
-		u16 result_count;
-		u16 pad;
-		u16 block_size;
-		u8 block_status;
-		u8 error_info_size;
-		u16 row_count;
-		u16 more_flag;
-		u32 alternate_tid[64];
-	} result;
-
-	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0,
-				   &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0xF006 Autohorized User Table");
-		return 0;
-	}
-
-	if (result.row_count)
-		seq_printf(seq, "#  AlternateTid\n");
-
-	for (i = 0; i < result.row_count; i++) {
-		seq_printf(seq, "%-2d", i);
-		seq_printf(seq, "%#7x ", result.alternate_tid[i]);
-	}
-
-	if (result.more_flag)
-		seq_printf(seq, "There is more...\n");
-
-	return 0;
-}
-
-/* Generic group F100h - Device Identity (scalar) */
-static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	static u32 work32[128];	// allow for "stuff" + up to 256 byte (max) serial number
-	// == (allow) 512d bytes (max)
-	static u16 *work16 = (u16 *) work32;
-	int token;
-	char tmp[16 + 1];
-
-	token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF100 Device Identity");
-		return 0;
-	}
-
-	seq_printf(seq, "Device Class  : %s\n", i2o_get_class_name(work16[0]));
-	seq_printf(seq, "Owner TID     : %0#5x\n", work16[2]);
-	seq_printf(seq, "Parent TID    : %0#5x\n", work16[3]);
-	seq_printf(seq, "Vendor info   : %s\n",
-		   chtostr(tmp, (u8 *) (work32 + 2), 16));
-	seq_printf(seq, "Product info  : %s\n",
-		   chtostr(tmp, (u8 *) (work32 + 6), 16));
-	seq_printf(seq, "Description   : %s\n",
-		   chtostr(tmp, (u8 *) (work32 + 10), 16));
-	seq_printf(seq, "Product rev.  : %s\n",
-		   chtostr(tmp, (u8 *) (work32 + 14), 8));
-
-	seq_printf(seq, "Serial number : ");
-	print_serial_number(seq, (u8 *) (work32 + 16),
-			    /* allow for SNLen plus
-			     * possible trailing '\0'
-			     */
-			    sizeof(work32) - (16 * sizeof(u32)) - 2);
-	seq_printf(seq, "\n");
-
-	return 0;
-}
-
-static int i2o_seq_show_dev_name(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-
-	seq_printf(seq, "%s\n", dev_name(&d->device));
-
-	return 0;
-}
-
-/* Generic group F101h - DDM Identity (scalar) */
-static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-
-	struct {
-		u16 ddm_tid;
-		u8 module_name[24];
-		u8 module_rev[8];
-		u8 sn_format;
-		u8 serial_number[12];
-		u8 pad[256];	// allow up to 256 byte (max) serial number
-	} result;
-
-	char tmp[24 + 1];
-
-	token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF101 DDM Identity");
-		return 0;
-	}
-
-	seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid);
-	seq_printf(seq, "Module name         : %s\n",
-		   chtostr(tmp, result.module_name, 24));
-	seq_printf(seq, "Module revision     : %s\n",
-		   chtostr(tmp, result.module_rev, 8));
-
-	seq_printf(seq, "Serial number       : ");
-	print_serial_number(seq, result.serial_number, sizeof(result) - 36);
-	/* allow for SNLen plus possible trailing '\0' */
-
-	seq_printf(seq, "\n");
-
-	return 0;
-}
-
-/* Generic group F102h - User Information (scalar) */
-static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-
-	struct {
-		u8 device_name[64];
-		u8 service_name[64];
-		u8 physical_location[64];
-		u8 instance_number[4];
-	} result;
-
-	char tmp[64 + 1];
-
-	token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token, "0xF102 User Information");
-		return 0;
-	}
-
-	seq_printf(seq, "Device name     : %s\n",
-		   chtostr(tmp, result.device_name, 64));
-	seq_printf(seq, "Service name    : %s\n",
-		   chtostr(tmp, result.service_name, 64));
-	seq_printf(seq, "Physical name   : %s\n",
-		   chtostr(tmp, result.physical_location, 64));
-	seq_printf(seq, "Instance number : %s\n",
-		   chtostr(tmp, result.instance_number, 4));
-
-	return 0;
-}
-
-/* Generic group F103h - SGL Operating Limits (scalar) */
-static int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	static u32 work32[12];
-	static u16 *work16 = (u16 *) work32;
-	static u8 *work8 = (u8 *) work32;
-	int token;
-
-	token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0xF103 SGL Operating Limits");
-		return 0;
-	}
-
-	seq_printf(seq, "SGL chain size        : %d\n", work32[0]);
-	seq_printf(seq, "Max SGL chain size    : %d\n", work32[1]);
-	seq_printf(seq, "SGL chain size target : %d\n", work32[2]);
-	seq_printf(seq, "SGL frag count        : %d\n", work16[6]);
-	seq_printf(seq, "Max SGL frag count    : %d\n", work16[7]);
-	seq_printf(seq, "SGL frag count target : %d\n", work16[8]);
-
-/* FIXME
-	if (d->i2oversion == 0x02)
-	{
-*/
-	seq_printf(seq, "SGL data alignment    : %d\n", work16[8]);
-	seq_printf(seq, "SGL addr limit        : %d\n", work8[20]);
-	seq_printf(seq, "SGL addr sizes supported : ");
-	if (work8[21] & 0x01)
-		seq_printf(seq, "32 bit ");
-	if (work8[21] & 0x02)
-		seq_printf(seq, "64 bit ");
-	if (work8[21] & 0x04)
-		seq_printf(seq, "96 bit ");
-	if (work8[21] & 0x08)
-		seq_printf(seq, "128 bit ");
-	seq_printf(seq, "\n");
-/*
-	}
-*/
-
-	return 0;
-}
-
-/* Generic group F200h - Sensors (scalar) */
-static int i2o_seq_show_sensors(struct seq_file *seq, void *v)
-{
-	struct i2o_device *d = (struct i2o_device *)seq->private;
-	int token;
-
-	struct {
-		u16 sensor_instance;
-		u8 component;
-		u16 component_instance;
-		u8 sensor_class;
-		u8 sensor_type;
-		u8 scaling_exponent;
-		u32 actual_reading;
-		u32 minimum_reading;
-		u32 low2lowcat_treshold;
-		u32 lowcat2low_treshold;
-		u32 lowwarn2low_treshold;
-		u32 low2lowwarn_treshold;
-		u32 norm2lowwarn_treshold;
-		u32 lowwarn2norm_treshold;
-		u32 nominal_reading;
-		u32 hiwarn2norm_treshold;
-		u32 norm2hiwarn_treshold;
-		u32 high2hiwarn_treshold;
-		u32 hiwarn2high_treshold;
-		u32 hicat2high_treshold;
-		u32 hi2hicat_treshold;
-		u32 maximum_reading;
-		u8 sensor_state;
-		u16 event_enable;
-	} result;
-
-	token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result));
-
-	if (token < 0) {
-		i2o_report_query_status(seq, token,
-					"0xF200 Sensors (optional)");
-		return 0;
-	}
-
-	seq_printf(seq, "Sensor instance       : %d\n", result.sensor_instance);
-
-	seq_printf(seq, "Component             : %d = ", result.component);
-	switch (result.component) {
-	case 0:
-		seq_printf(seq, "Other");
-		break;
-	case 1:
-		seq_printf(seq, "Planar logic Board");
-		break;
-	case 2:
-		seq_printf(seq, "CPU");
-		break;
-	case 3:
-		seq_printf(seq, "Chassis");
-		break;
-	case 4:
-		seq_printf(seq, "Power Supply");
-		break;
-	case 5:
-		seq_printf(seq, "Storage");
-		break;
-	case 6:
-		seq_printf(seq, "External");
-		break;
-	}
-	seq_printf(seq, "\n");
-
-	seq_printf(seq, "Component instance    : %d\n",
-		   result.component_instance);
-	seq_printf(seq, "Sensor class          : %s\n",
-		   result.sensor_class ? "Analog" : "Digital");
-
-	seq_printf(seq, "Sensor type           : %d = ", result.sensor_type);
-	switch (result.sensor_type) {
-	case 0:
-		seq_printf(seq, "Other\n");
-		break;
-	case 1:
-		seq_printf(seq, "Thermal\n");
-		break;
-	case 2:
-		seq_printf(seq, "DC voltage (DC volts)\n");
-		break;
-	case 3:
-		seq_printf(seq, "AC voltage (AC volts)\n");
-		break;
-	case 4:
-		seq_printf(seq, "DC current (DC amps)\n");
-		break;
-	case 5:
-		seq_printf(seq, "AC current (AC volts)\n");
-		break;
-	case 6:
-		seq_printf(seq, "Door open\n");
-		break;
-	case 7:
-		seq_printf(seq, "Fan operational\n");
-		break;
-	}
-
-	seq_printf(seq, "Scaling exponent      : %d\n",
-		   result.scaling_exponent);
-	seq_printf(seq, "Actual reading        : %d\n", result.actual_reading);
-	seq_printf(seq, "Minimum reading       : %d\n", result.minimum_reading);
-	seq_printf(seq, "Low2LowCat treshold   : %d\n",
-		   result.low2lowcat_treshold);
-	seq_printf(seq, "LowCat2Low treshold   : %d\n",
-		   result.lowcat2low_treshold);
-	seq_printf(seq, "LowWarn2Low treshold  : %d\n",
-		   result.lowwarn2low_treshold);
-	seq_printf(seq, "Low2LowWarn treshold  : %d\n",
-		   result.low2lowwarn_treshold);
-	seq_printf(seq, "Norm2LowWarn treshold : %d\n",
-		   result.norm2lowwarn_treshold);
-	seq_printf(seq, "LowWarn2Norm treshold : %d\n",
-		   result.lowwarn2norm_treshold);
-	seq_printf(seq, "Nominal reading       : %d\n", result.nominal_reading);
-	seq_printf(seq, "HiWarn2Norm treshold  : %d\n",
-		   result.hiwarn2norm_treshold);
-	seq_printf(seq, "Norm2HiWarn treshold  : %d\n",
-		   result.norm2hiwarn_treshold);
-	seq_printf(seq, "High2HiWarn treshold  : %d\n",
-		   result.high2hiwarn_treshold);
-	seq_printf(seq, "HiWarn2High treshold  : %d\n",
-		   result.hiwarn2high_treshold);
-	seq_printf(seq, "HiCat2High treshold   : %d\n",
-		   result.hicat2high_treshold);
-	seq_printf(seq, "High2HiCat treshold   : %d\n",
-		   result.hi2hicat_treshold);
-	seq_printf(seq, "Maximum reading       : %d\n", result.maximum_reading);
-
-	seq_printf(seq, "Sensor state          : %d = ", result.sensor_state);
-	switch (result.sensor_state) {
-	case 0:
-		seq_printf(seq, "Normal\n");
-		break;
-	case 1:
-		seq_printf(seq, "Abnormal\n");
-		break;
-	case 2:
-		seq_printf(seq, "Unknown\n");
-		break;
-	case 3:
-		seq_printf(seq, "Low Catastrophic (LoCat)\n");
-		break;
-	case 4:
-		seq_printf(seq, "Low (Low)\n");
-		break;
-	case 5:
-		seq_printf(seq, "Low Warning (LoWarn)\n");
-		break;
-	case 6:
-		seq_printf(seq, "High Warning (HiWarn)\n");
-		break;
-	case 7:
-		seq_printf(seq, "High (High)\n");
-		break;
-	case 8:
-		seq_printf(seq, "High Catastrophic (HiCat)\n");
-		break;
-	}
-
-	seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable);
-	seq_printf(seq, "    [%s] Operational state change. \n",
-		   (result.event_enable & 0x01) ? "+" : "-");
-	seq_printf(seq, "    [%s] Low catastrophic. \n",
-		   (result.event_enable & 0x02) ? "+" : "-");
-	seq_printf(seq, "    [%s] Low reading. \n",
-		   (result.event_enable & 0x04) ? "+" : "-");
-	seq_printf(seq, "    [%s] Low warning. \n",
-		   (result.event_enable & 0x08) ? "+" : "-");
-	seq_printf(seq,
-		   "    [%s] Change back to normal from out of range state. \n",
-		   (result.event_enable & 0x10) ? "+" : "-");
-	seq_printf(seq, "    [%s] High warning. \n",
-		   (result.event_enable & 0x20) ? "+" : "-");
-	seq_printf(seq, "    [%s] High reading. \n",
-		   (result.event_enable & 0x40) ? "+" : "-");
-	seq_printf(seq, "    [%s] High catastrophic. \n",
-		   (result.event_enable & 0x80) ? "+" : "-");
-
-	return 0;
-}
-
-static int i2o_seq_open_hrt(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_hrt, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_lct(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_lct, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_status(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_status, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_hw(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_hw, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_ddm_table, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_driver_store(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_driver_store, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_drivers_stored, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_groups(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_groups, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_phys_device(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_phys_device, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_claimed(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_claimed, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_users(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_users, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_priv_msgs, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_authorized_users,
-			   PDE_DATA(inode));
-};
-
-static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_dev_identity, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_ddm_identity, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_uinfo(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_uinfo, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_sgl_limits, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_sensors(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_sensors, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_dev_name(struct inode *inode, struct file *file)
-{
-	return single_open(file, i2o_seq_show_dev_name, PDE_DATA(inode));
-};
-
-static const struct file_operations i2o_seq_fops_lct = {
-	.open = i2o_seq_open_lct,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_hrt = {
-	.open = i2o_seq_open_hrt,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_status = {
-	.open = i2o_seq_open_status,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_hw = {
-	.open = i2o_seq_open_hw,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_ddm_table = {
-	.open = i2o_seq_open_ddm_table,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_driver_store = {
-	.open = i2o_seq_open_driver_store,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_drivers_stored = {
-	.open = i2o_seq_open_drivers_stored,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_groups = {
-	.open = i2o_seq_open_groups,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_phys_device = {
-	.open = i2o_seq_open_phys_device,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_claimed = {
-	.open = i2o_seq_open_claimed,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_users = {
-	.open = i2o_seq_open_users,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_priv_msgs = {
-	.open = i2o_seq_open_priv_msgs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_authorized_users = {
-	.open = i2o_seq_open_authorized_users,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_dev_name = {
-	.open = i2o_seq_open_dev_name,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_dev_identity = {
-	.open = i2o_seq_open_dev_identity,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_ddm_identity = {
-	.open = i2o_seq_open_ddm_identity,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_uinfo = {
-	.open = i2o_seq_open_uinfo,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_sgl_limits = {
-	.open = i2o_seq_open_sgl_limits,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_sensors = {
-	.open = i2o_seq_open_sensors,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-/*
- * IOP specific entries...write field just in case someone
- * ever wants one.
- */
-static i2o_proc_entry i2o_proc_generic_iop_entries[] = {
-	{"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt},
-	{"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct},
-	{"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status},
-	{"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw},
-	{"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table},
-	{"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store},
-	{"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored},
-	{NULL, 0, NULL}
-};
-
-/*
- * Device specific entries
- */
-static i2o_proc_entry generic_dev_entries[] = {
-	{"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups},
-	{"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device},
-	{"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed},
-	{"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users},
-	{"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs},
-	{"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users},
-	{"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity},
-	{"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity},
-	{"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo},
-	{"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits},
-	{"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors},
-	{NULL, 0, NULL}
-};
-
-/*
- *  Storage unit specific entries (SCSI Periph, BS) with device names
- */
-static i2o_proc_entry rbs_dev_entries[] = {
-	{"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name},
-	{NULL, 0, NULL}
-};
-
-/**
- *	i2o_proc_create_entries - Creates proc dir entries
- *	@dir: proc dir entry under which the entries should be placed
- *	@i2o_pe: pointer to the entries which should be added
- *	@data: pointer to I2O controller or device
- *
- *	Create proc dir entries for a I2O controller or I2O device.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_proc_create_entries(struct proc_dir_entry *dir,
-				   i2o_proc_entry * i2o_pe, void *data)
-{
-	struct proc_dir_entry *tmp;
-
-	while (i2o_pe->name) {
-		tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
-				       i2o_pe->fops, data);
-		if (!tmp)
-			return -1;
-
-		i2o_pe++;
-	}
-
-	return 0;
-}
-
-/**
- *	i2o_proc_device_add - Add an I2O device to the proc dir
- *	@dir: proc dir entry to which the device should be added
- *	@dev: I2O device which should be added
- *
- *	Add an I2O device to the proc dir entry dir and create the entries for
- *	the device depending on the class of the I2O device.
- */
-static void i2o_proc_device_add(struct proc_dir_entry *dir,
-				struct i2o_device *dev)
-{
-	char buff[10];
-	struct proc_dir_entry *devdir;
-	i2o_proc_entry *i2o_pe = NULL;
-
-	sprintf(buff, "%03x", dev->lct_data.tid);
-
-	osm_debug("adding device /proc/i2o/%s/%s\n", dev->iop->name, buff);
-
-	devdir = proc_mkdir_data(buff, 0, dir, dev);
-	if (!devdir) {
-		osm_warn("Could not allocate procdir!\n");
-		return;
-	}
-
-	i2o_proc_create_entries(devdir, generic_dev_entries, dev);
-
-	/* Inform core that we want updates about this device's status */
-	switch (dev->lct_data.class_id) {
-	case I2O_CLASS_SCSI_PERIPHERAL:
-	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-		i2o_pe = rbs_dev_entries;
-		break;
-	default:
-		break;
-	}
-	if (i2o_pe)
-		i2o_proc_create_entries(devdir, i2o_pe, dev);
-}
-
-/**
- *	i2o_proc_iop_add - Add an I2O controller to the i2o proc tree
- *	@dir: parent proc dir entry
- *	@c: I2O controller which should be added
- *
- *	Add the entries to the parent proc dir entry. Also each device is added
- *	to the controllers proc dir entry.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_proc_iop_add(struct proc_dir_entry *dir,
-			    struct i2o_controller *c)
-{
-	struct proc_dir_entry *iopdir;
-	struct i2o_device *dev;
-
-	osm_debug("adding IOP /proc/i2o/%s\n", c->name);
-
-	iopdir = proc_mkdir_data(c->name, 0, dir, c);
-	if (!iopdir)
-		return -1;
-
-	i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c);
-
-	list_for_each_entry(dev, &c->devices, list)
-	    i2o_proc_device_add(iopdir, dev);
-
-	return 0;
-}
-
-/**
- *	i2o_proc_fs_create - Create the i2o proc fs.
- *
- *	Iterate over each I2O controller and create the entries for it.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_proc_fs_create(void)
-{
-	struct i2o_controller *c;
-
-	i2o_proc_dir_root = proc_mkdir("i2o", NULL);
-	if (!i2o_proc_dir_root)
-		return -1;
-
-	list_for_each_entry(c, &i2o_controllers, list)
-	    i2o_proc_iop_add(i2o_proc_dir_root, c);
-
-	return 0;
-};
-
-/**
- *	i2o_proc_fs_destroy - Cleanup the all i2o proc entries
- *
- *	Iterate over each I2O controller and remove the entries for it.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __exit i2o_proc_fs_destroy(void)
-{
-	remove_proc_subtree("i2o", NULL);
-
-	return 0;
-};
-
-/**
- *	i2o_proc_init - Init function for procfs
- *
- *	Registers Proc OSM and creates procfs entries.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_proc_init(void)
-{
-	int rc;
-
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	rc = i2o_driver_register(&i2o_proc_driver);
-	if (rc)
-		return rc;
-
-	rc = i2o_proc_fs_create();
-	if (rc) {
-		i2o_driver_unregister(&i2o_proc_driver);
-		return rc;
-	}
-
-	return 0;
-};
-
-/**
- *	i2o_proc_exit - Exit function for procfs
- *
- *	Unregisters Proc OSM and removes procfs entries.
- */
-static void __exit i2o_proc_exit(void)
-{
-	i2o_driver_unregister(&i2o_proc_driver);
-	i2o_proc_fs_destroy();
-};
-
-MODULE_AUTHOR("Deepak Saxena");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_proc_init);
-module_exit(i2o_proc_exit);
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
deleted file mode 100644
index 8152e9fa..0000000
--- a/drivers/message/i2o/i2o_scsi.c
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- * 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- *  Complications for I2O scsi
- *
- *	o	Each (bus,lun) is a logical device in I2O. We keep a map
- *		table. We spoof failed selection for unmapped units
- *	o	Request sense buffers can come back for free.
- *	o	Scatter gather is a bit dynamic. We have to investigate at
- *		setup time.
- *	o	Some of our resources are dynamically shared. The i2o core
- *		needs a message reservation protocol to avoid swap v net
- *		deadlocking. We need to back off queue requests.
- *
- *	In general the firmware wants to help. Where its help isn't performance
- *	useful we just ignore the aid. Its not worth the code in truth.
- *
- * Fixes/additions:
- *	Steve Ralston:
- *		Scatter gather now works
- *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *		Minor fixes for 2.6.
- *
- * To Do:
- *	64bit cleanups
- *	Fix the resource management problems.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/prefetch.h>
-#include <linux/pci.h>
-#include <linux/blkdev.h>
-#include <linux/i2o.h>
-#include <linux/scatterlist.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/sg.h>
-
-#define OSM_NAME	"scsi-osm"
-#define OSM_VERSION	"1.316"
-#define OSM_DESCRIPTION	"I2O SCSI Peripheral OSM"
-
-static struct i2o_driver i2o_scsi_driver;
-
-static unsigned int i2o_scsi_max_id = 16;
-static unsigned int i2o_scsi_max_lun = 255;
-
-struct i2o_scsi_host {
-	struct Scsi_Host *scsi_host;	/* pointer to the SCSI host */
-	struct i2o_controller *iop;	/* pointer to the I2O controller */
-	u64 lun;	/* lun's used for block devices */
-	struct i2o_device *channel[0];	/* channel->i2o_dev mapping table */
-};
-
-static struct scsi_host_template i2o_scsi_host_template;
-
-#define I2O_SCSI_CAN_QUEUE	4
-
-/* SCSI OSM class handling definition */
-static struct i2o_class_id i2o_scsi_class_id[] = {
-	{I2O_CLASS_SCSI_PERIPHERAL},
-	{I2O_CLASS_END}
-};
-
-static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
-{
-	struct i2o_scsi_host *i2o_shost;
-	struct i2o_device *i2o_dev;
-	struct Scsi_Host *scsi_host;
-	int max_channel = 0;
-	u8 type;
-	int i;
-	size_t size;
-	u16 body_size = 6;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
-	if (c->adaptec)
-		body_size = 8;
-#endif
-
-	list_for_each_entry(i2o_dev, &c->devices, list)
-	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
-		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
-		    && (type == 0x01))	/* SCSI bus */
-			max_channel++;
-	}
-
-	if (!max_channel) {
-		osm_warn("no channels found on %s\n", c->name);
-		return ERR_PTR(-EFAULT);
-	}
-
-	size = max_channel * sizeof(struct i2o_device *)
-	    + sizeof(struct i2o_scsi_host);
-
-	scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
-	if (!scsi_host) {
-		osm_warn("Could not allocate SCSI host\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	scsi_host->max_channel = max_channel - 1;
-	scsi_host->max_id = i2o_scsi_max_id;
-	scsi_host->max_lun = i2o_scsi_max_lun;
-	scsi_host->this_id = c->unit;
-	scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
-
-	i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
-	i2o_shost->scsi_host = scsi_host;
-	i2o_shost->iop = c;
-	i2o_shost->lun = 1;
-
-	i = 0;
-	list_for_each_entry(i2o_dev, &c->devices, list)
-	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
-		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
-		    && (type == 0x01))	/* only SCSI bus */
-			i2o_shost->channel[i++] = i2o_dev;
-
-		if (i >= max_channel)
-			break;
-	}
-
-	return i2o_shost;
-};
-
-/**
- *	i2o_scsi_get_host - Get an I2O SCSI host
- *	@c: I2O controller to for which to get the SCSI host
- *
- *	If the I2O controller already exists as SCSI host, the SCSI host
- *	is returned, otherwise the I2O controller is added to the SCSI
- *	core.
- *
- *	Returns pointer to the I2O SCSI host on success or NULL on failure.
- */
-static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
-{
-	return c->driver_data[i2o_scsi_driver.context];
-};
-
-/**
- *	i2o_scsi_remove - Remove I2O device from SCSI core
- *	@dev: device which should be removed
- *
- *	Removes the I2O device from the SCSI core again.
- *
- *	Returns 0 on success.
- */
-static int i2o_scsi_remove(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	struct i2o_controller *c = i2o_dev->iop;
-	struct i2o_scsi_host *i2o_shost;
-	struct scsi_device *scsi_dev;
-
-	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
-
-	i2o_shost = i2o_scsi_get_host(c);
-
-	shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
-	    if (scsi_dev->hostdata == i2o_dev) {
-		sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
-		scsi_remove_device(scsi_dev);
-		scsi_device_put(scsi_dev);
-		break;
-	}
-
-	return 0;
-};
-
-/**
- *	i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
- *	@dev: device to verify if it is a I2O SCSI device
- *
- *	Retrieve channel, id and lun for I2O device. If everything goes well
- *	register the I2O device as SCSI device on the I2O SCSI controller.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_scsi_probe(struct device *dev)
-{
-	struct i2o_device *i2o_dev = to_i2o_device(dev);
-	struct i2o_controller *c = i2o_dev->iop;
-	struct i2o_scsi_host *i2o_shost;
-	struct Scsi_Host *scsi_host;
-	struct i2o_device *parent;
-	struct scsi_device *scsi_dev;
-	u32 id = -1;
-	u64 lun = -1;
-	int channel = -1;
-	int i, rc;
-
-	i2o_shost = i2o_scsi_get_host(c);
-	if (!i2o_shost)
-		return -EFAULT;
-
-	scsi_host = i2o_shost->scsi_host;
-
-	switch (i2o_dev->lct_data.class_id) {
-	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-	case I2O_CLASS_EXECUTIVE:
-#ifdef CONFIG_I2O_EXT_ADAPTEC
-		if (c->adaptec) {
-			u8 type;
-			struct i2o_device *d = i2o_shost->channel[0];
-
-			if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
-			    && (type == 0x01))	/* SCSI bus */
-				if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
-					channel = 0;
-					if (i2o_dev->lct_data.class_id ==
-					    I2O_CLASS_RANDOM_BLOCK_STORAGE)
-						lun =
-						    cpu_to_le64(i2o_shost->
-								lun++);
-					else
-						lun = 0;
-				}
-		}
-#endif
-		break;
-
-	case I2O_CLASS_SCSI_PERIPHERAL:
-		if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
-			return -EFAULT;
-
-		if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
-			return -EFAULT;
-
-		parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
-		if (!parent) {
-			osm_warn("can not find parent of device %03x\n",
-				 i2o_dev->lct_data.tid);
-			return -EFAULT;
-		}
-
-		for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
-			if (i2o_shost->channel[i] == parent)
-				channel = i;
-		break;
-
-	default:
-		return -EFAULT;
-	}
-
-	if (channel == -1) {
-		osm_warn("can not find channel of device %03x\n",
-			 i2o_dev->lct_data.tid);
-		return -EFAULT;
-	}
-
-	if (le32_to_cpu(id) >= scsi_host->max_id) {
-		osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
-			 le32_to_cpu(id), scsi_host->max_id);
-		return -EFAULT;
-	}
-
-	if (le64_to_cpu(lun) >= scsi_host->max_lun) {
-		osm_warn("SCSI device lun (%llu) >= max_lun of I2O host (%llu)",
-			 le64_to_cpu(lun), scsi_host->max_lun);
-		return -EFAULT;
-	}
-
-	scsi_dev =
-	    __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
-			      le64_to_cpu(lun), i2o_dev);
-
-	if (IS_ERR(scsi_dev)) {
-		osm_warn("can not add SCSI device %03x\n",
-			 i2o_dev->lct_data.tid);
-		return PTR_ERR(scsi_dev);
-	}
-
-	rc = sysfs_create_link(&i2o_dev->device.kobj,
-			       &scsi_dev->sdev_gendev.kobj, "scsi");
-	if (rc)
-		goto err;
-
-	osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %llu\n",
-		 i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
-		 le64_to_cpu(lun));
-
-	return 0;
-
-err:
-	scsi_remove_device(scsi_dev);
-	return rc;
-};
-
-static const char *i2o_scsi_info(struct Scsi_Host *SChost)
-{
-	struct i2o_scsi_host *hostdata;
-	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
-	return hostdata->iop->name;
-}
-
-/**
- *	i2o_scsi_reply - SCSI OSM message reply handler
- *	@c: controller issuing the reply
- *	@m: message id for flushing
- *	@msg: the message from the controller
- *
- *	Process reply messages (interrupts in normal scsi controller think).
- *	We can get a variety of messages to process. The normal path is
- *	scsi command completions. We must also deal with IOP failures,
- *	the reply to a bus reset and the reply to a LUN query.
- *
- *	Returns 0 on success and if the reply should not be flushed or > 0
- *	on success and if the reply should be flushed. Returns negative error
- *	code on failure and if the reply should be flushed.
- */
-static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
-			  struct i2o_message *msg)
-{
-	struct scsi_cmnd *cmd;
-	u32 error;
-	struct device *dev;
-
-	cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
-	if (unlikely(!cmd)) {
-		osm_err("NULL reply received!\n");
-		return -1;
-	}
-
-	/*
-	 *      Low byte is device status, next is adapter status,
-	 *      (then one byte reserved), then request status.
-	 */
-	error = le32_to_cpu(msg->body[0]);
-
-	osm_debug("Completed %0x%p\n", cmd);
-
-	cmd->result = error & 0xff;
-	/*
-	 * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
-	 * the SCSI layer handle the error
-	 */
-	if (cmd->result)
-		memcpy(cmd->sense_buffer, &msg->body[3],
-		       min(SCSI_SENSE_BUFFERSIZE, 40));
-
-	/* only output error code if AdapterStatus is not HBA_SUCCESS */
-	if ((error >> 8) & 0xff)
-		osm_err("SCSI error %08x\n", error);
-
-	dev = &c->pdev->dev;
-
-	scsi_dma_unmap(cmd);
-
-	cmd->scsi_done(cmd);
-
-	return 1;
-};
-
-/**
- *	i2o_scsi_notify_device_add - Retrieve notifications of added devices
- *	@i2o_dev: the I2O device which was added
- *
- *	If a I2O device is added we catch the notification, because I2O classes
- *	other than SCSI peripheral will not be received through
- *	i2o_scsi_probe().
- */
-static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
-{
-	switch (i2o_dev->lct_data.class_id) {
-	case I2O_CLASS_EXECUTIVE:
-	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-		i2o_scsi_probe(&i2o_dev->device);
-		break;
-
-	default:
-		break;
-	}
-};
-
-/**
- *	i2o_scsi_notify_device_remove - Retrieve notifications of removed devices
- *	@i2o_dev: the I2O device which was removed
- *
- *	If a I2O device is removed, we catch the notification to remove the
- *	corresponding SCSI device.
- */
-static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
-{
-	switch (i2o_dev->lct_data.class_id) {
-	case I2O_CLASS_EXECUTIVE:
-	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-		i2o_scsi_remove(&i2o_dev->device);
-		break;
-
-	default:
-		break;
-	}
-};
-
-/**
- *	i2o_scsi_notify_controller_add - Retrieve notifications of added controllers
- *	@c: the controller which was added
- *
- *	If a I2O controller is added, we catch the notification to add a
- *	corresponding Scsi_Host.
- */
-static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
-{
-	struct i2o_scsi_host *i2o_shost;
-	int rc;
-
-	i2o_shost = i2o_scsi_host_alloc(c);
-	if (IS_ERR(i2o_shost)) {
-		osm_err("Could not initialize SCSI host\n");
-		return;
-	}
-
-	rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
-	if (rc) {
-		osm_err("Could not add SCSI host\n");
-		scsi_host_put(i2o_shost->scsi_host);
-		return;
-	}
-
-	c->driver_data[i2o_scsi_driver.context] = i2o_shost;
-
-	osm_debug("new I2O SCSI host added\n");
-};
-
-/**
- *	i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers
- *	@c: the controller which was removed
- *
- *	If a I2O controller is removed, we catch the notification to remove the
- *	corresponding Scsi_Host.
- */
-static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
-{
-	struct i2o_scsi_host *i2o_shost;
-	i2o_shost = i2o_scsi_get_host(c);
-	if (!i2o_shost)
-		return;
-
-	c->driver_data[i2o_scsi_driver.context] = NULL;
-
-	scsi_remove_host(i2o_shost->scsi_host);
-	scsi_host_put(i2o_shost->scsi_host);
-	osm_debug("I2O SCSI host removed\n");
-};
-
-/* SCSI OSM driver struct */
-static struct i2o_driver i2o_scsi_driver = {
-	.name = OSM_NAME,
-	.reply = i2o_scsi_reply,
-	.classes = i2o_scsi_class_id,
-	.notify_device_add = i2o_scsi_notify_device_add,
-	.notify_device_remove = i2o_scsi_notify_device_remove,
-	.notify_controller_add = i2o_scsi_notify_controller_add,
-	.notify_controller_remove = i2o_scsi_notify_controller_remove,
-	.driver = {
-		   .probe = i2o_scsi_probe,
-		   .remove = i2o_scsi_remove,
-		   },
-};
-
-/**
- *	i2o_scsi_queuecommand - queue a SCSI command
- *	@SCpnt: scsi command pointer
- *	@done: callback for completion
- *
- *	Issue a scsi command asynchronously. Return 0 on success or 1 if
- *	we hit an error (normally message queue congestion). The only
- *	minor complication here is that I2O deals with the device addressing
- *	so we have to map the bus/dev/lun back to an I2O handle as well
- *	as faking absent devices ourself.
- *
- *	Locks: takes the controller lock on error path only
- */
-
-static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
-				 void (*done) (struct scsi_cmnd *))
-{
-	struct i2o_controller *c;
-	struct i2o_device *i2o_dev;
-	int tid;
-	struct i2o_message *msg;
-	/*
-	 * ENABLE_DISCONNECT
-	 * SIMPLE_TAG
-	 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
-	 */
-	u32 scsi_flags = 0x20a00000;
-	u32 sgl_offset;
-	u32 *mptr;
-	u32 cmd = I2O_CMD_SCSI_EXEC << 24;
-	int rc = 0;
-
-	/*
-	 *      Do the incoming paperwork
-	 */
-	i2o_dev = SCpnt->device->hostdata;
-
-	SCpnt->scsi_done = done;
-
-	if (unlikely(!i2o_dev)) {
-		osm_warn("no I2O device in request\n");
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		goto exit;
-	}
-	c = i2o_dev->iop;
-	tid = i2o_dev->lct_data.tid;
-
-	osm_debug("qcmd: Tid = %03x\n", tid);
-	osm_debug("Real scsi messages.\n");
-
-	/*
-	 *      Put together a scsi execscb message
-	 */
-	switch (SCpnt->sc_data_direction) {
-	case PCI_DMA_NONE:
-		/* DATA NO XFER */
-		sgl_offset = SGL_OFFSET_0;
-		break;
-
-	case PCI_DMA_TODEVICE:
-		/* DATA OUT (iop-->dev) */
-		scsi_flags |= 0x80000000;
-		sgl_offset = SGL_OFFSET_10;
-		break;
-
-	case PCI_DMA_FROMDEVICE:
-		/* DATA IN  (iop<--dev) */
-		scsi_flags |= 0x40000000;
-		sgl_offset = SGL_OFFSET_10;
-		break;
-
-	default:
-		/* Unknown - kill the command */
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done(SCpnt);
-		goto exit;
-	}
-
-	/*
-	 *      Obtain an I2O message. If there are none free then
-	 *      throw it back to the scsi layer
-	 */
-
-	msg = i2o_msg_get(c);
-	if (IS_ERR(msg)) {
-		rc = SCSI_MLQUEUE_HOST_BUSY;
-		goto exit;
-	}
-
-	mptr = &msg->body[0];
-
-#if 0 /* this code can't work */
-#ifdef CONFIG_I2O_EXT_ADAPTEC
-	if (c->adaptec) {
-		u32 adpt_flags = 0;
-
-		if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
-			i2o_sg_io_hdr_t __user *usr_ptr =
-			    ((Sg_request *) (SCpnt->sc_request->
-					     upper_private_data))->header.
-			    usr_ptr;
-
-			if (usr_ptr)
-				get_user(adpt_flags, &usr_ptr->flags);
-		}
-
-		switch (i2o_dev->lct_data.class_id) {
-		case I2O_CLASS_EXECUTIVE:
-		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
-			/* interpret flag has to be set for executive */
-			adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
-			break;
-
-		default:
-			break;
-		}
-
-		/*
-		 * for Adaptec controllers we use the PRIVATE command, because
-		 * the normal SCSI EXEC doesn't support all SCSI commands on
-		 * all controllers (for example READ CAPACITY).
-		 */
-		if (sgl_offset == SGL_OFFSET_10)
-			sgl_offset = SGL_OFFSET_12;
-		cmd = I2O_CMD_PRIVATE << 24;
-		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
-		*mptr++ = cpu_to_le32(adpt_flags | tid);
-	}
-#endif
-#endif
-
-	msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
-	msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
-
-	/* We want the SCSI control block back */
-	msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
-
-	/* LSI_920_PCI_QUIRK
-	 *
-	 *      Intermittant observations of msg frame word data corruption
-	 *      observed on msg[4] after:
-	 *        WRITE, READ-MODIFY-WRITE
-	 *      operations.  19990606 -sralston
-	 *
-	 *      (Hence we build this word via tag. Its good practice anyway
-	 *       we don't want fetches over PCI needlessly)
-	 */
-
-	/* Attach tags to the devices */
-	/* FIXME: implement
-	   if(SCpnt->device->tagged_supported) {
-	   if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
-	   scsi_flags |= 0x01000000;
-	   else if(SCpnt->tag == ORDERED_QUEUE_TAG)
-	   scsi_flags |= 0x01800000;
-	   }
-	 */
-
-	*mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
-
-	/* Write SCSI command into the message - always 16 byte block */
-	memcpy(mptr, SCpnt->cmnd, 16);
-	mptr += 4;
-
-	if (sgl_offset != SGL_OFFSET_0) {
-		/* write size of data addressed by SGL */
-		*mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
-
-		/* Now fill in the SGList and command */
-
-		if (scsi_sg_count(SCpnt)) {
-			if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
-					    scsi_sg_count(SCpnt),
-					    SCpnt->sc_data_direction, &mptr))
-				goto nomem;
-		}
-	}
-
-	/* Stick the headers on */
-	msg->u.head[0] =
-	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
-
-	/* Queue the message */
-	i2o_msg_post(c, msg);
-
-	osm_debug("Issued %0x%p\n", SCpnt);
-
-	return 0;
-
-      nomem:
-	rc = -ENOMEM;
-	i2o_msg_nop(c, msg);
-
-      exit:
-	return rc;
-}
-
-static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
-
-/**
- *	i2o_scsi_abort - abort a running command
- *	@SCpnt: command to abort
- *
- *	Ask the I2O controller to abort a command. This is an asynchrnous
- *	process and our callback handler will see the command complete with an
- *	aborted message if it succeeds.
- *
- *	Returns 0 if the command is successfully aborted or negative error code
- *	on failure.
- */
-static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
-{
-	struct i2o_device *i2o_dev;
-	struct i2o_controller *c;
-	struct i2o_message *msg;
-	int tid;
-	int status = FAILED;
-
-	osm_warn("Aborting command block.\n");
-
-	i2o_dev = SCpnt->device->hostdata;
-	c = i2o_dev->iop;
-	tid = i2o_dev->lct_data.tid;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return SCSI_MLQUEUE_HOST_BUSY;
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
-	msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
-
-	if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
-		status = SUCCESS;
-
-	return status;
-}
-
-/**
- *	i2o_scsi_bios_param	-	Invent disk geometry
- *	@sdev: scsi device
- *	@dev: block layer device
- *	@capacity: size in sectors
- *	@ip: geometry array
- *
- *	This is anyone's guess quite frankly. We use the same rules everyone
- *	else appears to and hope. It seems to work.
- */
-
-static int i2o_scsi_bios_param(struct scsi_device *sdev,
-			       struct block_device *dev, sector_t capacity,
-			       int *ip)
-{
-	int size;
-
-	size = capacity;
-	ip[0] = 64;		/* heads                        */
-	ip[1] = 32;		/* sectors                      */
-	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
-		ip[0] = 255;	/* heads                        */
-		ip[1] = 63;	/* sectors                      */
-		ip[2] = size / (255 * 63);	/* cylinders                    */
-	}
-	return 0;
-}
-
-static struct scsi_host_template i2o_scsi_host_template = {
-	.proc_name = OSM_NAME,
-	.name = OSM_DESCRIPTION,
-	.info = i2o_scsi_info,
-	.queuecommand = i2o_scsi_queuecommand,
-	.eh_abort_handler = i2o_scsi_abort,
-	.bios_param = i2o_scsi_bios_param,
-	.can_queue = I2O_SCSI_CAN_QUEUE,
-	.sg_tablesize = 8,
-	.cmd_per_lun = 6,
-	.use_clustering = ENABLE_CLUSTERING,
-};
-
-/**
- *	i2o_scsi_init - SCSI OSM initialization function
- *
- *	Register SCSI OSM into I2O core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_scsi_init(void)
-{
-	int rc;
-
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	/* Register SCSI OSM into I2O core */
-	rc = i2o_driver_register(&i2o_scsi_driver);
-	if (rc) {
-		osm_err("Could not register SCSI driver\n");
-		return rc;
-	}
-
-	return 0;
-};
-
-/**
- *	i2o_scsi_exit - SCSI OSM exit function
- *
- *	Unregisters SCSI OSM from I2O core.
- */
-static void __exit i2o_scsi_exit(void)
-{
-	/* Unregister I2O SCSI OSM from I2O core */
-	i2o_driver_unregister(&i2o_scsi_driver);
-};
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_scsi_init);
-module_exit(i2o_scsi_exit);
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
deleted file mode 100644
index 92752fb..0000000
--- a/drivers/message/i2o/iop.c
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- *	Functions to handle I2O controllers and I2O message handling
- *
- *	Copyright (C) 1999-2002	Red Hat Software
- *
- *	Written by Alan Cox, Building Number Three Ltd
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the
- *	Free Software Foundation; either version 2 of the License, or (at your
- *	option) any later version.
- *
- *	A lot of the I2O message side code from this is taken from the
- *	Red Creek RCPCI45 adapter driver by Red Creek Communications
- *
- *	Fixes/additions:
- *		Philipp Rumpf
- *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *		Deepak Saxena <deepak@plexity.net>
- *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
- *			Ported to Linux 2.5.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Minor fixes for 2.6.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include "core.h"
-
-#define OSM_NAME	"i2o"
-#define OSM_VERSION	"1.325"
-#define OSM_DESCRIPTION	"I2O subsystem"
-
-/* global I2O controller list */
-LIST_HEAD(i2o_controllers);
-
-/*
- * global I2O System Table. Contains information about all the IOPs in the
- * system. Used to inform IOPs about each others existence.
- */
-static struct i2o_dma i2o_systab;
-
-static int i2o_hrt_get(struct i2o_controller *c);
-
-/**
- *	i2o_msg_get_wait - obtain an I2O message from the IOP
- *	@c: I2O controller
- *	@wait: how long to wait until timeout
- *
- *	This function waits up to wait seconds for a message slot to be
- *	available.
- *
- *	On a success the message is returned and the pointer to the message is
- *	set in msg. The returned message is the physical page frame offset
- *	address from the read port (see the i2o spec). If no message is
- *	available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
- */
-struct i2o_message *i2o_msg_get_wait(struct i2o_controller *c, int wait)
-{
-	unsigned long timeout = jiffies + wait * HZ;
-	struct i2o_message *msg;
-
-	while (IS_ERR(msg = i2o_msg_get(c))) {
-		if (time_after(jiffies, timeout)) {
-			osm_debug("%s: Timeout waiting for message frame.\n",
-				  c->name);
-			return ERR_PTR(-ETIMEDOUT);
-		}
-		schedule_timeout_uninterruptible(1);
-	}
-
-	return msg;
-};
-
-#if BITS_PER_LONG == 64
-/**
- *      i2o_cntxt_list_add - Append a pointer to context list and return a id
- *	@c: controller to which the context list belong
- *	@ptr: pointer to add to the context list
- *
- *	Because the context field in I2O is only 32-bit large, on 64-bit the
- *	pointer is to large to fit in the context field. The i2o_cntxt_list
- *	functions therefore map pointers to context fields.
- *
- *	Returns context id > 0 on success or 0 on failure.
- */
-u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
-{
-	struct i2o_context_list_element *entry;
-	unsigned long flags;
-
-	if (!ptr)
-		osm_err("%s: couldn't add NULL pointer to context list!\n",
-			c->name);
-
-	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
-	if (!entry) {
-		osm_err("%s: Could not allocate memory for context list element"
-			"\n", c->name);
-		return 0;
-	}
-
-	entry->ptr = ptr;
-	entry->timestamp = jiffies;
-	INIT_LIST_HEAD(&entry->list);
-
-	spin_lock_irqsave(&c->context_list_lock, flags);
-
-	if (unlikely(atomic_inc_and_test(&c->context_list_counter)))
-		atomic_inc(&c->context_list_counter);
-
-	entry->context = atomic_read(&c->context_list_counter);
-
-	list_add(&entry->list, &c->context_list);
-
-	spin_unlock_irqrestore(&c->context_list_lock, flags);
-
-	osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
-
-	return entry->context;
-};
-
-/**
- *      i2o_cntxt_list_remove - Remove a pointer from the context list
- *	@c: controller to which the context list belong
- *	@ptr: pointer which should be removed from the context list
- *
- *	Removes a previously added pointer from the context list and returns
- *	the matching context id.
- *
- *	Returns context id on success or 0 on failure.
- */
-u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
-{
-	struct i2o_context_list_element *entry;
-	u32 context = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->context_list_lock, flags);
-	list_for_each_entry(entry, &c->context_list, list)
-	    if (entry->ptr == ptr) {
-		list_del(&entry->list);
-		context = entry->context;
-		kfree(entry);
-		break;
-	}
-	spin_unlock_irqrestore(&c->context_list_lock, flags);
-
-	if (!context)
-		osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
-			 ptr);
-
-	osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
-		  context, ptr);
-
-	return context;
-};
-
-/**
- *      i2o_cntxt_list_get - Get a pointer from the context list and remove it
- *	@c: controller to which the context list belong
- *	@context: context id to which the pointer belong
- *
- *	Returns pointer to the matching context id on success or NULL on
- *	failure.
- */
-void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
-{
-	struct i2o_context_list_element *entry;
-	unsigned long flags;
-	void *ptr = NULL;
-
-	spin_lock_irqsave(&c->context_list_lock, flags);
-	list_for_each_entry(entry, &c->context_list, list)
-	    if (entry->context == context) {
-		list_del(&entry->list);
-		ptr = entry->ptr;
-		kfree(entry);
-		break;
-	}
-	spin_unlock_irqrestore(&c->context_list_lock, flags);
-
-	if (!ptr)
-		osm_warn("%s: context id %d not found\n", c->name, context);
-
-	osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
-		  ptr);
-
-	return ptr;
-};
-
-/**
- *      i2o_cntxt_list_get_ptr - Get a context id from the context list
- *	@c: controller to which the context list belong
- *	@ptr: pointer to which the context id should be fetched
- *
- *	Returns context id which matches to the pointer on success or 0 on
- *	failure.
- */
-u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
-{
-	struct i2o_context_list_element *entry;
-	u32 context = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->context_list_lock, flags);
-	list_for_each_entry(entry, &c->context_list, list)
-	    if (entry->ptr == ptr) {
-		context = entry->context;
-		break;
-	}
-	spin_unlock_irqrestore(&c->context_list_lock, flags);
-
-	if (!context)
-		osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
-			 ptr);
-
-	osm_debug("%s: get context id from context list %p -> %d\n", c->name,
-		  ptr, context);
-
-	return context;
-};
-#endif
-
-/**
- *	i2o_iop_find - Find an I2O controller by id
- *	@unit: unit number of the I2O controller to search for
- *
- *	Lookup the I2O controller on the controller list.
- *
- *	Returns pointer to the I2O controller on success or NULL if not found.
- */
-struct i2o_controller *i2o_find_iop(int unit)
-{
-	struct i2o_controller *c;
-
-	list_for_each_entry(c, &i2o_controllers, list) {
-		if (c->unit == unit)
-			return c;
-	}
-
-	return NULL;
-};
-
-/**
- *	i2o_iop_find_device - Find a I2O device on an I2O controller
- *	@c: I2O controller where the I2O device hangs on
- *	@tid: TID of the I2O device to search for
- *
- *	Searches the devices of the I2O controller for a device with TID tid and
- *	returns it.
- *
- *	Returns a pointer to the I2O device if found, otherwise NULL.
- */
-struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
-{
-	struct i2o_device *dev;
-
-	list_for_each_entry(dev, &c->devices, list)
-	    if (dev->lct_data.tid == tid)
-		return dev;
-
-	return NULL;
-};
-
-/**
- *	i2o_quiesce_controller - quiesce controller
- *	@c: controller
- *
- *	Quiesce an IOP. Causes IOP to make external operation quiescent
- *	(i2o 'READY' state). Internal operation of the IOP continues normally.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_quiesce(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	i2o_status_block *sb = c->status_block.virt;
-	int rc;
-
-	i2o_status_get(c);
-
-	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
-	if ((sb->iop_state != ADAPTER_STATE_READY) &&
-	    (sb->iop_state != ADAPTER_STATE_OPERATIONAL))
-		return 0;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-
-	/* Long timeout needed for quiesce if lots of devices */
-	if ((rc = i2o_msg_post_wait(c, msg, 240)))
-		osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
-	else
-		osm_debug("%s: Quiesced.\n", c->name);
-
-	i2o_status_get(c);	// Entered READY state
-
-	return rc;
-};
-
-/**
- *	i2o_iop_enable - move controller from ready to OPERATIONAL
- *	@c: I2O controller
- *
- *	Enable IOP. This allows the IOP to resume external operations and
- *	reverses the effect of a quiesce. Returns zero or an error code if
- *	an error occurs.
- */
-static int i2o_iop_enable(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	i2o_status_block *sb = c->status_block.virt;
-	int rc;
-
-	i2o_status_get(c);
-
-	/* Enable only allowed on READY state */
-	if (sb->iop_state != ADAPTER_STATE_READY)
-		return -EINVAL;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-
-	/* How long of a timeout do we need? */
-	if ((rc = i2o_msg_post_wait(c, msg, 240)))
-		osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
-	else
-		osm_debug("%s: Enabled.\n", c->name);
-
-	i2o_status_get(c);	// entered OPERATIONAL state
-
-	return rc;
-};
-
-/**
- *	i2o_iop_quiesce_all - Quiesce all I2O controllers on the system
- *
- *	Quiesce all I2O controllers which are connected to the system.
- */
-static inline void i2o_iop_quiesce_all(void)
-{
-	struct i2o_controller *c, *tmp;
-
-	list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
-		if (!c->no_quiesce)
-			i2o_iop_quiesce(c);
-	}
-};
-
-/**
- *	i2o_iop_enable_all - Enables all controllers on the system
- *
- *	Enables all I2O controllers which are connected to the system.
- */
-static inline void i2o_iop_enable_all(void)
-{
-	struct i2o_controller *c, *tmp;
-
-	list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
-	    i2o_iop_enable(c);
-};
-
-/**
- *	i2o_clear_controller - Bring I2O controller into HOLD state
- *	@c: controller
- *
- *	Clear an IOP to HOLD state, ie. terminate external operations, clear all
- *	input queues and prepare for a system restart. IOP's internal operation
- *	continues normally and the outbound queue is alive. The IOP is not
- *	expected to rebuild its LCT.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_clear(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	int rc;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	/* Quiesce all IOPs first */
-	i2o_iop_quiesce_all();
-
-	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-
-	if ((rc = i2o_msg_post_wait(c, msg, 30)))
-		osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
-	else
-		osm_debug("%s: Cleared.\n", c->name);
-
-	/* Enable all IOPs */
-	i2o_iop_enable_all();
-
-	return rc;
-}
-
-/**
- *	i2o_iop_init_outbound_queue - setup the outbound message queue
- *	@c: I2O controller
- *
- *	Clear and (re)initialize IOP's outbound queue and post the message
- *	frames to the IOP.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
-{
-	u32 m;
-	volatile u8 *status = c->status.virt;
-	struct i2o_message *msg;
-	ulong timeout;
-	int i;
-
-	osm_debug("%s: Initializing Outbound Queue...\n", c->name);
-
-	memset(c->status.virt, 0, 4);
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
-	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
-	msg->body[0] = cpu_to_le32(PAGE_SIZE);
-	/* Outbound msg frame size in words and Initcode */
-	msg->body[1] = cpu_to_le32(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80);
-	msg->body[2] = cpu_to_le32(0xd0000004);
-	msg->body[3] = cpu_to_le32(i2o_dma_low(c->status.phys));
-	msg->body[4] = cpu_to_le32(i2o_dma_high(c->status.phys));
-
-	i2o_msg_post(c, msg);
-
-	timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
-	while (*status <= I2O_CMD_IN_PROGRESS) {
-		if (time_after(jiffies, timeout)) {
-			osm_warn("%s: Timeout Initializing\n", c->name);
-			return -ETIMEDOUT;
-		}
-		schedule_timeout_uninterruptible(1);
-	}
-
-	m = c->out_queue.phys;
-
-	/* Post frames */
-	for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
-		i2o_flush_reply(c, m);
-		udelay(1);	/* Promise */
-		m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
-	}
-
-	return 0;
-}
-
-/**
- *	i2o_iop_reset - reset an I2O controller
- *	@c: controller to reset
- *
- *	Reset the IOP into INIT state and wait until IOP gets into RESET state.
- *	Terminate all external operations, clear IOP's inbound and outbound
- *	queues, terminate all DDMs, and reload the IOP's operating environment
- *	and all local DDMs. The IOP rebuilds its LCT.
- */
-static int i2o_iop_reset(struct i2o_controller *c)
-{
-	volatile u8 *status = c->status.virt;
-	struct i2o_message *msg;
-	unsigned long timeout;
-	i2o_status_block *sb = c->status_block.virt;
-	int rc = 0;
-
-	osm_debug("%s: Resetting controller\n", c->name);
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	memset(c->status_block.virt, 0, 8);
-
-	/* Quiesce all IOPs first */
-	i2o_iop_quiesce_all();
-
-	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
-	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
-	msg->body[0] = cpu_to_le32(0x00000000);
-	msg->body[1] = cpu_to_le32(0x00000000);
-	msg->body[2] = cpu_to_le32(i2o_dma_low(c->status.phys));
-	msg->body[3] = cpu_to_le32(i2o_dma_high(c->status.phys));
-
-	i2o_msg_post(c, msg);
-
-	/* Wait for a reply */
-	timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
-	while (!*status) {
-		if (time_after(jiffies, timeout))
-			break;
-
-		schedule_timeout_uninterruptible(1);
-	}
-
-	switch (*status) {
-	case I2O_CMD_REJECTED:
-		osm_warn("%s: IOP reset rejected\n", c->name);
-		rc = -EPERM;
-		break;
-
-	case I2O_CMD_IN_PROGRESS:
-		/*
-		 * Once the reset is sent, the IOP goes into the INIT state
-		 * which is indeterminate. We need to wait until the IOP has
-		 * rebooted before we can let the system talk to it. We read
-		 * the inbound Free_List until a message is available. If we
-		 * can't read one in the given amount of time, we assume the
-		 * IOP could not reboot properly.
-		 */
-		osm_debug("%s: Reset in progress, waiting for reboot...\n",
-			  c->name);
-
-		while (IS_ERR(msg = i2o_msg_get_wait(c, I2O_TIMEOUT_RESET))) {
-			if (time_after(jiffies, timeout)) {
-				osm_err("%s: IOP reset timeout.\n", c->name);
-				rc = PTR_ERR(msg);
-				goto exit;
-			}
-			schedule_timeout_uninterruptible(1);
-		}
-		i2o_msg_nop(c, msg);
-
-		/* from here all quiesce commands are safe */
-		c->no_quiesce = 0;
-
-		/* verify if controller is in state RESET */
-		i2o_status_get(c);
-
-		if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
-			osm_warn("%s: reset completed, but adapter not in RESET"
-				 " state.\n", c->name);
-		else
-			osm_debug("%s: reset completed.\n", c->name);
-
-		break;
-
-	default:
-		osm_err("%s: IOP reset timeout.\n", c->name);
-		rc = -ETIMEDOUT;
-		break;
-	}
-
-      exit:
-	/* Enable all IOPs */
-	i2o_iop_enable_all();
-
-	return rc;
-};
-
-/**
- *	i2o_iop_activate - Bring controller up to HOLD
- *	@c: controller
- *
- *	This function brings an I2O controller into HOLD state. The adapter
- *	is reset if necessary and then the queues and resource table are read.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_activate(struct i2o_controller *c)
-{
-	i2o_status_block *sb = c->status_block.virt;
-	int rc;
-	int state;
-
-	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
-	/* In READY state, Get status */
-
-	rc = i2o_status_get(c);
-	if (rc) {
-		osm_info("%s: Unable to obtain status, attempting a reset.\n",
-			 c->name);
-		rc = i2o_iop_reset(c);
-		if (rc)
-			return rc;
-	}
-
-	if (sb->i2o_version > I2OVER15) {
-		osm_err("%s: Not running version 1.5 of the I2O Specification."
-			"\n", c->name);
-		return -ENODEV;
-	}
-
-	switch (sb->iop_state) {
-	case ADAPTER_STATE_FAULTED:
-		osm_err("%s: hardware fault\n", c->name);
-		return -EFAULT;
-
-	case ADAPTER_STATE_READY:
-	case ADAPTER_STATE_OPERATIONAL:
-	case ADAPTER_STATE_HOLD:
-	case ADAPTER_STATE_FAILED:
-		osm_debug("%s: already running, trying to reset...\n", c->name);
-		rc = i2o_iop_reset(c);
-		if (rc)
-			return rc;
-	}
-
-	/* preserve state */
-	state = sb->iop_state;
-
-	rc = i2o_iop_init_outbound_queue(c);
-	if (rc)
-		return rc;
-
-	/* if adapter was not in RESET state clear now */
-	if (state != ADAPTER_STATE_RESET)
-		i2o_iop_clear(c);
-
-	i2o_status_get(c);
-
-	if (sb->iop_state != ADAPTER_STATE_HOLD) {
-		osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
-		return -EIO;
-	}
-
-	return i2o_hrt_get(c);
-};
-
-static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
-{
-	i2o_status_block *sb = c->status_block.virt;
-	struct resource *res = &c->mem_resource;
-	resource_size_t size, align;
-	int err;
-
-	res->name = c->pdev->bus->name;
-	res->flags = flags;
-	res->start = 0;
-	res->end = 0;
-	osm_info("%s: requires private memory resources.\n", c->name);
-
-	if (flags & IORESOURCE_MEM) {
-		size = sb->desired_mem_size;
-		align = 1 << 20;	/* unspecified, use 1Mb and play safe */
-	} else {
-		size = sb->desired_io_size;
-		align = 1 << 12;	/* unspecified, use 4Kb and play safe */
-	}
-
-	err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
-				     NULL, NULL);
-	if (err < 0)
-		return;
-
-	if (flags & IORESOURCE_MEM) {
-		c->mem_alloc = 1;
-		sb->current_mem_size = resource_size(res);
-		sb->current_mem_base = res->start;
-	} else if (flags & IORESOURCE_IO) {
-		c->io_alloc = 1;
-		sb->current_io_size = resource_size(res);
-		sb->current_io_base = res->start;
-	}
-	osm_info("%s: allocated PCI space %pR\n", c->name, res);
-}
-
-/**
- *	i2o_iop_systab_set - Set the I2O System Table of the specified IOP
- *	@c: I2O controller to which the system table should be send
- *
- *	Before the systab could be set i2o_systab_build() must be called.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_systab_set(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	i2o_status_block *sb = c->status_block.virt;
-	struct device *dev = &c->pdev->dev;
-	int rc;
-
-	if (sb->current_mem_size < sb->desired_mem_size)
-		i2o_res_alloc(c, IORESOURCE_MEM);
-
-	if (sb->current_io_size < sb->desired_io_size)
-		i2o_res_alloc(c, IORESOURCE_IO);
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len,
-					 PCI_DMA_TODEVICE);
-	if (!i2o_systab.phys) {
-		i2o_msg_nop(c, msg);
-		return -ENOMEM;
-	}
-
-	msg->u.head[0] = cpu_to_le32(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-
-	/*
-	 * Provide three SGL-elements:
-	 * System table (SysTab), Private memory space declaration and
-	 * Private i/o space declaration
-	 */
-
-	msg->body[0] = cpu_to_le32(c->unit + 2);
-	msg->body[1] = cpu_to_le32(0x00000000);
-	msg->body[2] = cpu_to_le32(0x54000000 | i2o_systab.len);
-	msg->body[3] = cpu_to_le32(i2o_systab.phys);
-	msg->body[4] = cpu_to_le32(0x54000000 | sb->current_mem_size);
-	msg->body[5] = cpu_to_le32(sb->current_mem_base);
-	msg->body[6] = cpu_to_le32(0xd4000000 | sb->current_io_size);
-	msg->body[6] = cpu_to_le32(sb->current_io_base);
-
-	rc = i2o_msg_post_wait(c, msg, 120);
-
-	dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len,
-			 PCI_DMA_TODEVICE);
-
-	if (rc < 0)
-		osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
-			-rc);
-	else
-		osm_debug("%s: SysTab set.\n", c->name);
-
-	return rc;
-}
-
-/**
- *	i2o_iop_online - Bring a controller online into OPERATIONAL state.
- *	@c: I2O controller
- *
- *	Send the system table and enable the I2O controller.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_online(struct i2o_controller *c)
-{
-	int rc;
-
-	rc = i2o_iop_systab_set(c);
-	if (rc)
-		return rc;
-
-	/* In READY state */
-	osm_debug("%s: Attempting to enable...\n", c->name);
-	rc = i2o_iop_enable(c);
-	if (rc)
-		return rc;
-
-	return 0;
-};
-
-/**
- *	i2o_iop_remove - Remove the I2O controller from the I2O core
- *	@c: I2O controller
- *
- *	Remove the I2O controller from the I2O core. If devices are attached to
- *	the controller remove these also and finally reset the controller.
- */
-void i2o_iop_remove(struct i2o_controller *c)
-{
-	struct i2o_device *dev, *tmp;
-
-	osm_debug("%s: deleting controller\n", c->name);
-
-	i2o_driver_notify_controller_remove_all(c);
-
-	list_del(&c->list);
-
-	list_for_each_entry_safe(dev, tmp, &c->devices, list)
-	    i2o_device_remove(dev);
-
-	device_del(&c->device);
-
-	/* Ask the IOP to switch to RESET state */
-	i2o_iop_reset(c);
-}
-
-/**
- *	i2o_systab_build - Build system table
- *
- *	The system table contains information about all the IOPs in the system
- *	(duh) and is used by the Executives on the IOPs to establish peer2peer
- *	connections. We're not supporting peer2peer at the moment, but this
- *	will be needed down the road for things like lan2lan forwarding.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_systab_build(void)
-{
-	struct i2o_controller *c, *tmp;
-	int num_controllers = 0;
-	u32 change_ind = 0;
-	int count = 0;
-	struct i2o_sys_tbl *systab = i2o_systab.virt;
-
-	list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
-	    num_controllers++;
-
-	if (systab) {
-		change_ind = systab->change_ind;
-		kfree(i2o_systab.virt);
-	}
-
-	/* Header + IOPs */
-	i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers *
-	    sizeof(struct i2o_sys_tbl_entry);
-
-	systab = i2o_systab.virt = kzalloc(i2o_systab.len, GFP_KERNEL);
-	if (!systab) {
-		osm_err("unable to allocate memory for System Table\n");
-		return -ENOMEM;
-	}
-
-	systab->version = I2OVERSION;
-	systab->change_ind = change_ind + 1;
-
-	list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
-		i2o_status_block *sb;
-
-		if (count >= num_controllers) {
-			osm_err("controller added while building system table"
-				"\n");
-			break;
-		}
-
-		sb = c->status_block.virt;
-
-		/*
-		 * Get updated IOP state so we have the latest information
-		 *
-		 * We should delete the controller at this point if it
-		 * doesn't respond since if it's not on the system table
-		 * it is techninically not part of the I2O subsystem...
-		 */
-		if (unlikely(i2o_status_get(c))) {
-			osm_err("%s: Deleting b/c could not get status while "
-				"attempting to build system table\n", c->name);
-			i2o_iop_remove(c);
-			continue;	// try the next one
-		}
-
-		systab->iops[count].org_id = sb->org_id;
-		systab->iops[count].iop_id = c->unit + 2;
-		systab->iops[count].seg_num = 0;
-		systab->iops[count].i2o_version = sb->i2o_version;
-		systab->iops[count].iop_state = sb->iop_state;
-		systab->iops[count].msg_type = sb->msg_type;
-		systab->iops[count].frame_size = sb->inbound_frame_size;
-		systab->iops[count].last_changed = change_ind;
-		systab->iops[count].iop_capabilities = sb->iop_capabilities;
-		systab->iops[count].inbound_low =
-		    i2o_dma_low(c->base.phys + I2O_IN_PORT);
-		systab->iops[count].inbound_high =
-		    i2o_dma_high(c->base.phys + I2O_IN_PORT);
-
-		count++;
-	}
-
-	systab->num_entries = count;
-
-	return 0;
-};
-
-/**
- *	i2o_parse_hrt - Parse the hardware resource table.
- *	@c: I2O controller
- *
- *	We don't do anything with it except dumping it (in debug mode).
- *
- *	Returns 0.
- */
-static int i2o_parse_hrt(struct i2o_controller *c)
-{
-	i2o_dump_hrt(c);
-	return 0;
-};
-
-/**
- *	i2o_status_get - Get the status block from the I2O controller
- *	@c: I2O controller
- *
- *	Issue a status query on the controller. This updates the attached
- *	status block. The status block could then be accessed through
- *	c->status_block.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_status_get(struct i2o_controller *c)
-{
-	struct i2o_message *msg;
-	volatile u8 *status_block;
-	unsigned long timeout;
-
-	status_block = (u8 *) c->status_block.virt;
-	memset(c->status_block.virt, 0, sizeof(i2o_status_block));
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 |
-			ADAPTER_TID);
-	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
-	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
-	msg->body[0] = cpu_to_le32(0x00000000);
-	msg->body[1] = cpu_to_le32(0x00000000);
-	msg->body[2] = cpu_to_le32(i2o_dma_low(c->status_block.phys));
-	msg->body[3] = cpu_to_le32(i2o_dma_high(c->status_block.phys));
-	msg->body[4] = cpu_to_le32(sizeof(i2o_status_block));	/* always 88 bytes */
-
-	i2o_msg_post(c, msg);
-
-	/* Wait for a reply */
-	timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ;
-	while (status_block[87] != 0xFF) {
-		if (time_after(jiffies, timeout)) {
-			osm_err("%s: Get status timeout.\n", c->name);
-			return -ETIMEDOUT;
-		}
-
-		schedule_timeout_uninterruptible(1);
-	}
-
-#ifdef DEBUG
-	i2o_debug_state(c);
-#endif
-
-	return 0;
-}
-
-/*
- *	i2o_hrt_get - Get the Hardware Resource Table from the I2O controller
- *	@c: I2O controller from which the HRT should be fetched
- *
- *	The HRT contains information about possible hidden devices but is
- *	mostly useless to us.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_hrt_get(struct i2o_controller *c)
-{
-	int rc;
-	int i;
-	i2o_hrt *hrt = c->hrt.virt;
-	u32 size = sizeof(i2o_hrt);
-	struct device *dev = &c->pdev->dev;
-
-	for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
-		struct i2o_message *msg;
-
-		msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-		if (IS_ERR(msg))
-			return PTR_ERR(msg);
-
-		msg->u.head[0] = cpu_to_le32(SIX_WORD_MSG_SIZE | SGL_OFFSET_4);
-		msg->u.head[1] =
-		    cpu_to_le32(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 |
-				ADAPTER_TID);
-		msg->body[0] = cpu_to_le32(0xd0000000 | c->hrt.len);
-		msg->body[1] = cpu_to_le32(c->hrt.phys);
-
-		rc = i2o_msg_post_wait_mem(c, msg, 20, &c->hrt);
-
-		if (rc < 0) {
-			osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
-				-rc);
-			return rc;
-		}
-
-		size = hrt->num_entries * hrt->entry_len << 2;
-		if (size > c->hrt.len) {
-			if (i2o_dma_realloc(dev, &c->hrt, size))
-				return -ENOMEM;
-			else
-				hrt = c->hrt.virt;
-		} else
-			return i2o_parse_hrt(c);
-	}
-
-	osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
-		I2O_HRT_GET_TRIES);
-
-	return -EBUSY;
-}
-
-/**
- *	i2o_iop_release - release the memory for a I2O controller
- *	@dev: I2O controller which should be released
- *
- *	Release the allocated memory. This function is called if refcount of
- *	device reaches 0 automatically.
- */
-static void i2o_iop_release(struct device *dev)
-{
-	struct i2o_controller *c = to_i2o_controller(dev);
-
-	i2o_iop_free(c);
-};
-
-/**
- *	i2o_iop_alloc - Allocate and initialize a i2o_controller struct
- *
- *	Allocate the necessary memory for a i2o_controller struct and
- *	initialize the lists and message mempool.
- *
- *	Returns a pointer to the I2O controller or a negative error code on
- *	failure.
- */
-struct i2o_controller *i2o_iop_alloc(void)
-{
-	static int unit = 0;	/* 0 and 1 are NULL IOP and Local Host */
-	struct i2o_controller *c;
-	char poolname[32];
-
-	c = kzalloc(sizeof(*c), GFP_KERNEL);
-	if (!c) {
-		osm_err("i2o: Insufficient memory to allocate a I2O controller."
-			"\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	c->unit = unit++;
-	sprintf(c->name, "iop%d", c->unit);
-
-	snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name);
-	if (i2o_pool_alloc
-	    (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32),
-	     I2O_MSG_INPOOL_MIN)) {
-		kfree(c);
-		return ERR_PTR(-ENOMEM);
-	};
-
-	INIT_LIST_HEAD(&c->devices);
-	spin_lock_init(&c->lock);
-	mutex_init(&c->lct_lock);
-
-	device_initialize(&c->device);
-
-	c->device.release = &i2o_iop_release;
-
-	dev_set_name(&c->device, "iop%d", c->unit);
-
-#if BITS_PER_LONG == 64
-	spin_lock_init(&c->context_list_lock);
-	atomic_set(&c->context_list_counter, 0);
-	INIT_LIST_HEAD(&c->context_list);
-#endif
-
-	return c;
-};
-
-/**
- *	i2o_iop_add - Initialize the I2O controller and add him to the I2O core
- *	@c: controller
- *
- *	Initialize the I2O controller and if no error occurs add him to the I2O
- *	core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_iop_add(struct i2o_controller *c)
-{
-	int rc;
-
-	if ((rc = device_add(&c->device))) {
-		osm_err("%s: could not add controller\n", c->name);
-		goto iop_reset;
-	}
-
-	osm_info("%s: Activating I2O controller...\n", c->name);
-	osm_info("%s: This may take a few minutes if there are many devices\n",
-		 c->name);
-
-	if ((rc = i2o_iop_activate(c))) {
-		osm_err("%s: could not activate controller\n", c->name);
-		goto device_del;
-	}
-
-	osm_debug("%s: building sys table...\n", c->name);
-
-	if ((rc = i2o_systab_build()))
-		goto device_del;
-
-	osm_debug("%s: online controller...\n", c->name);
-
-	if ((rc = i2o_iop_online(c)))
-		goto device_del;
-
-	osm_debug("%s: getting LCT...\n", c->name);
-
-	if ((rc = i2o_exec_lct_get(c)))
-		goto device_del;
-
-	list_add(&c->list, &i2o_controllers);
-
-	i2o_driver_notify_controller_add_all(c);
-
-	osm_info("%s: Controller added\n", c->name);
-
-	return 0;
-
-      device_del:
-	device_del(&c->device);
-
-      iop_reset:
-	i2o_iop_reset(c);
-
-	return rc;
-};
-
-/**
- *	i2o_event_register - Turn on/off event notification for a I2O device
- *	@dev: I2O device which should receive the event registration request
- *	@drv: driver which want to get notified
- *	@tcntxt: transaction context to use with this notifier
- *	@evt_mask: mask of events
- *
- *	Create and posts an event registration message to the task. No reply
- *	is waited for, or expected. If you do not want further notifications,
- *	call the i2o_event_register again with a evt_mask of 0.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv,
-		       int tcntxt, u32 evt_mask)
-{
-	struct i2o_controller *c = dev->iop;
-	struct i2o_message *msg;
-
-	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-	if (IS_ERR(msg))
-		return PTR_ERR(msg);
-
-	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
-	msg->u.head[1] =
-	    cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->
-			lct_data.tid);
-	msg->u.s.icntxt = cpu_to_le32(drv->context);
-	msg->u.s.tcntxt = cpu_to_le32(tcntxt);
-	msg->body[0] = cpu_to_le32(evt_mask);
-
-	i2o_msg_post(c, msg);
-
-	return 0;
-};
-
-/**
- *	i2o_iop_init - I2O main initialization function
- *
- *	Initialize the I2O drivers (OSM) functions, register the Executive OSM,
- *	initialize the I2O PCI part and finally initialize I2O device stuff.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_iop_init(void)
-{
-	int rc = 0;
-
-	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
-	if ((rc = i2o_driver_init()))
-		goto exit;
-
-	if ((rc = i2o_exec_init()))
-		goto driver_exit;
-
-	if ((rc = i2o_pci_init()))
-		goto exec_exit;
-
-	return 0;
-
-      exec_exit:
-	i2o_exec_exit();
-
-      driver_exit:
-	i2o_driver_exit();
-
-      exit:
-	return rc;
-}
-
-/**
- *	i2o_iop_exit - I2O main exit function
- *
- *	Removes I2O controllers from PCI subsystem and shut down OSMs.
- */
-static void __exit i2o_iop_exit(void)
-{
-	i2o_pci_exit();
-	i2o_exec_exit();
-	i2o_driver_exit();
-};
-
-module_init(i2o_iop_init);
-module_exit(i2o_iop_exit);
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-#if BITS_PER_LONG == 64
-EXPORT_SYMBOL(i2o_cntxt_list_add);
-EXPORT_SYMBOL(i2o_cntxt_list_get);
-EXPORT_SYMBOL(i2o_cntxt_list_remove);
-EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
-#endif
-EXPORT_SYMBOL(i2o_msg_get_wait);
-EXPORT_SYMBOL(i2o_find_iop);
-EXPORT_SYMBOL(i2o_iop_find_device);
-EXPORT_SYMBOL(i2o_event_register);
-EXPORT_SYMBOL(i2o_status_get);
-EXPORT_SYMBOL(i2o_controllers);
diff --git a/drivers/message/i2o/memory.c b/drivers/message/i2o/memory.c
deleted file mode 100644
index 292b41e..0000000
--- a/drivers/message/i2o/memory.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- *	Functions to handle I2O memory
- *
- *	Pulled from the inlines in i2o headers and uninlined
- *
- *
- *	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/i2o.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-/* Protects our 32/64bit mask switching */
-static DEFINE_MUTEX(mem_lock);
-
-/**
- *	i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
- *	@c: I2O controller for which the calculation should be done
- *	@body_size: maximum body size used for message in 32-bit words.
- *
- *	Return the maximum number of SG elements in a SG list.
- */
-u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
-{
-	i2o_status_block *sb = c->status_block.virt;
-	u16 sg_count =
-	    (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
-	    body_size;
-
-	if (c->pae_support) {
-		/*
-		 * for 64-bit a SG attribute element must be added and each
-		 * SG element needs 12 bytes instead of 8.
-		 */
-		sg_count -= 2;
-		sg_count /= 3;
-	} else
-		sg_count /= 2;
-
-	if (c->short_req && (sg_count > 8))
-		sg_count = 8;
-
-	return sg_count;
-}
-EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
-
-
-/**
- *	i2o_dma_map_single - Map pointer to controller and fill in I2O message.
- *	@c: I2O controller
- *	@ptr: pointer to the data which should be mapped
- *	@size: size of data in bytes
- *	@direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- *	@sg_ptr: pointer to the SG list inside the I2O message
- *
- *	This function does all necessary DMA handling and also writes the I2O
- *	SGL elements into the I2O message. For details on DMA handling see also
- *	dma_map_single(). The pointer sg_ptr will only be set to the end of the
- *	SG list if the allocation was successful.
- *
- *	Returns DMA address which must be checked for failures using
- *	dma_mapping_error().
- */
-dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
-					    size_t size,
-					    enum dma_data_direction direction,
-					    u32 ** sg_ptr)
-{
-	u32 sg_flags;
-	u32 *mptr = *sg_ptr;
-	dma_addr_t dma_addr;
-
-	switch (direction) {
-	case DMA_TO_DEVICE:
-		sg_flags = 0xd4000000;
-		break;
-	case DMA_FROM_DEVICE:
-		sg_flags = 0xd0000000;
-		break;
-	default:
-		return 0;
-	}
-
-	dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
-	if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-		if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
-			*mptr++ = cpu_to_le32(0x7C020002);
-			*mptr++ = cpu_to_le32(PAGE_SIZE);
-		}
-#endif
-
-		*mptr++ = cpu_to_le32(sg_flags | size);
-		*mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-		if ((sizeof(dma_addr_t) > 4) && c->pae_support)
-			*mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
-#endif
-		*sg_ptr = mptr;
-	}
-	return dma_addr;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_map_single);
-
-/**
- *	i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
- *	@c: I2O controller
- *	@sg: SG list to be mapped
- *	@sg_count: number of elements in the SG list
- *	@direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- *	@sg_ptr: pointer to the SG list inside the I2O message
- *
- *	This function does all necessary DMA handling and also writes the I2O
- *	SGL elements into the I2O message. For details on DMA handling see also
- *	dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
- *	list if the allocation was successful.
- *
- *	Returns 0 on failure or 1 on success.
- */
-int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
-	    int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
-{
-	u32 sg_flags;
-	u32 *mptr = *sg_ptr;
-
-	switch (direction) {
-	case DMA_TO_DEVICE:
-		sg_flags = 0x14000000;
-		break;
-	case DMA_FROM_DEVICE:
-		sg_flags = 0x10000000;
-		break;
-	default:
-		return 0;
-	}
-
-	sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
-	if (!sg_count)
-		return 0;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-	if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
-		*mptr++ = cpu_to_le32(0x7C020002);
-		*mptr++ = cpu_to_le32(PAGE_SIZE);
-	}
-#endif
-
-	while (sg_count-- > 0) {
-		if (!sg_count)
-			sg_flags |= 0xC0000000;
-		*mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
-		*mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-		if ((sizeof(dma_addr_t) > 4) && c->pae_support)
-			*mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
-#endif
-		sg = sg_next(sg);
-	}
-	*sg_ptr = mptr;
-
-	return 1;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
-
-/**
- *	i2o_dma_alloc - Allocate DMA memory
- *	@dev: struct device pointer to the PCI device of the I2O controller
- *	@addr: i2o_dma struct which should get the DMA buffer
- *	@len: length of the new DMA memory
- *
- *	Allocate a coherent DMA memory and write the pointers into addr.
- *
- *	Returns 0 on success or -ENOMEM on failure.
- */
-int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
-{
-	struct pci_dev *pdev = to_pci_dev(dev);
-	int dma_64 = 0;
-
-	mutex_lock(&mem_lock);
-	if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_BIT_MASK(64))) {
-		dma_64 = 1;
-		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-			mutex_unlock(&mem_lock);
-			return -ENOMEM;
-		}
-	}
-
-	addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
-
-	if ((sizeof(dma_addr_t) > 4) && dma_64)
-		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
-			printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
-	mutex_unlock(&mem_lock);
-
-	if (!addr->virt)
-		return -ENOMEM;
-
-	memset(addr->virt, 0, len);
-	addr->len = len;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_alloc);
-
-
-/**
- *	i2o_dma_free - Free DMA memory
- *	@dev: struct device pointer to the PCI device of the I2O controller
- *	@addr: i2o_dma struct which contains the DMA buffer
- *
- *	Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
-	if (addr->virt) {
-		if (addr->phys)
-			dma_free_coherent(dev, addr->len, addr->virt,
-					  addr->phys);
-		else
-			kfree(addr->virt);
-		addr->virt = NULL;
-	}
-}
-EXPORT_SYMBOL_GPL(i2o_dma_free);
-
-
-/**
- *	i2o_dma_realloc - Realloc DMA memory
- *	@dev: struct device pointer to the PCI device of the I2O controller
- *	@addr: pointer to a i2o_dma struct DMA buffer
- *	@len: new length of memory
- *
- *	If there was something allocated in the addr, free it first. If len > 0
- *	than try to allocate it and write the addresses back to the addr
- *	structure. If len == 0 set the virtual address to NULL.
- *
- *	Returns the 0 on success or negative error code on failure.
- */
-int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
-{
-	i2o_dma_free(dev, addr);
-
-	if (len)
-		return i2o_dma_alloc(dev, addr, len);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_realloc);
-
-/*
- *	i2o_pool_alloc - Allocate an slab cache and mempool
- *	@mempool: pointer to struct i2o_pool to write data into.
- *	@name: name which is used to identify cache
- *	@size: size of each object
- *	@min_nr: minimum number of objects
- *
- *	First allocates a slab cache with name and size. Then allocates a
- *	mempool which uses the slab cache for allocation and freeing.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
-				 size_t size, int min_nr)
-{
-	pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-	if (!pool->name)
-		goto exit;
-	strcpy(pool->name, name);
-
-	pool->slab =
-	    kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
-	if (!pool->slab)
-		goto free_name;
-
-	pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
-	if (!pool->mempool)
-		goto free_slab;
-
-	return 0;
-
-free_slab:
-	kmem_cache_destroy(pool->slab);
-
-free_name:
-	kfree(pool->name);
-
-exit:
-	return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(i2o_pool_alloc);
-
-/*
- *	i2o_pool_free - Free slab cache and mempool again
- *	@mempool: pointer to struct i2o_pool which should be freed
- *
- *	Note that you have to return all objects to the mempool again before
- *	calling i2o_pool_free().
- */
-void i2o_pool_free(struct i2o_pool *pool)
-{
-	mempool_destroy(pool->mempool);
-	kmem_cache_destroy(pool->slab);
-	kfree(pool->name);
-};
-EXPORT_SYMBOL_GPL(i2o_pool_free);
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
deleted file mode 100644
index 0f9f3e1..0000000
--- a/drivers/message/i2o/pci.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- *	PCI handling of I2O controller
- *
- * 	Copyright (C) 1999-2002	Red Hat Software
- *
- *	Written by Alan Cox, Building Number Three Ltd
- *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License as published by the
- *	Free Software Foundation; either version 2 of the License, or (at your
- *	option) any later version.
- *
- *	A lot of the I2O message side code from this is taken from the Red
- *	Creek RCPCI45 adapter driver by Red Creek Communications
- *
- *	Fixes/additions:
- *		Philipp Rumpf
- *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *		Deepak Saxena <deepak@plexity.net>
- *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
- *			Ported to Linux 2.5.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Minor fixes for 2.6.
- *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
- *			Support for sysfs included.
- */
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/i2o.h>
-#include <linux/module.h>
-#include "core.h"
-
-#define OSM_DESCRIPTION	"I2O-subsystem"
-
-/* PCI device id table for all I2O controllers */
-static struct pci_device_id i2o_pci_ids[] = {
-	{PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
-	{PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
-	{.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
-	 .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
-	{0}
-};
-
-/**
- *	i2o_pci_free - Frees the DMA memory for the I2O controller
- *	@c: I2O controller to free
- *
- *	Remove all allocated DMA memory and unmap memory IO regions. If MTRR
- *	is enabled, also remove it again.
- */
-static void i2o_pci_free(struct i2o_controller *c)
-{
-	struct device *dev;
-
-	dev = &c->pdev->dev;
-
-	i2o_dma_free(dev, &c->out_queue);
-	i2o_dma_free(dev, &c->status_block);
-	kfree(c->lct);
-	i2o_dma_free(dev, &c->dlct);
-	i2o_dma_free(dev, &c->hrt);
-	i2o_dma_free(dev, &c->status);
-
-	if (c->raptor && c->in_queue.virt)
-		iounmap(c->in_queue.virt);
-
-	if (c->base.virt)
-		iounmap(c->base.virt);
-
-	pci_release_regions(c->pdev);
-}
-
-/**
- *	i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
- *	@c: I2O controller
- *
- *	Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
- *	IO mappings are also done here. If MTRR is enabled, also do add memory
- *	regions here.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_alloc(struct i2o_controller *c)
-{
-	struct pci_dev *pdev = c->pdev;
-	struct device *dev = &pdev->dev;
-	int i;
-
-	if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
-		printk(KERN_ERR "%s: device already claimed\n", c->name);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < 6; i++) {
-		/* Skip I/O spaces */
-		if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
-			if (!c->base.phys) {
-				c->base.phys = pci_resource_start(pdev, i);
-				c->base.len = pci_resource_len(pdev, i);
-
-				/*
-				 * If we know what card it is, set the size
-				 * correctly. Code is taken from dpt_i2o.c
-				 */
-				if (pdev->device == 0xa501) {
-					if (pdev->subsystem_device >= 0xc032 &&
-					    pdev->subsystem_device <= 0xc03b) {
-						if (c->base.len > 0x400000)
-							c->base.len = 0x400000;
-					} else {
-						if (c->base.len > 0x100000)
-							c->base.len = 0x100000;
-					}
-				}
-				if (!c->raptor)
-					break;
-			} else {
-				c->in_queue.phys = pci_resource_start(pdev, i);
-				c->in_queue.len = pci_resource_len(pdev, i);
-				break;
-			}
-		}
-	}
-
-	if (i == 6) {
-		printk(KERN_ERR "%s: I2O controller has no memory regions"
-		       " defined.\n", c->name);
-		i2o_pci_free(c);
-		return -EINVAL;
-	}
-
-	/* Map the I2O controller */
-	if (c->raptor) {
-		printk(KERN_INFO "%s: PCI I2O controller\n", c->name);
-		printk(KERN_INFO "     BAR0 at 0x%08lX size=%ld\n",
-		       (unsigned long)c->base.phys, (unsigned long)c->base.len);
-		printk(KERN_INFO "     BAR1 at 0x%08lX size=%ld\n",
-		       (unsigned long)c->in_queue.phys,
-		       (unsigned long)c->in_queue.len);
-	} else
-		printk(KERN_INFO "%s: PCI I2O controller at %08lX size=%ld\n",
-		       c->name, (unsigned long)c->base.phys,
-		       (unsigned long)c->base.len);
-
-	c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
-	if (!c->base.virt) {
-		printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	if (c->raptor) {
-		c->in_queue.virt =
-		    ioremap_nocache(c->in_queue.phys, c->in_queue.len);
-		if (!c->in_queue.virt) {
-			printk(KERN_ERR "%s: Unable to map controller.\n",
-			       c->name);
-			i2o_pci_free(c);
-			return -ENOMEM;
-		}
-	} else
-		c->in_queue = c->base;
-
-	c->irq_status = c->base.virt + I2O_IRQ_STATUS;
-	c->irq_mask = c->base.virt + I2O_IRQ_MASK;
-	c->in_port = c->base.virt + I2O_IN_PORT;
-	c->out_port = c->base.virt + I2O_OUT_PORT;
-
-	/* Motorola/Freescale chip does not follow spec */
-	if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
-		/* Check if CPU is enabled */
-		if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
-			printk(KERN_INFO "%s: MPC82XX needs CPU running to "
-			       "service I2O.\n", c->name);
-			i2o_pci_free(c);
-			return -ENODEV;
-		} else {
-			c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
-			c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
-			c->in_port += I2O_MOTOROLA_PORT_OFFSET;
-			c->out_port += I2O_MOTOROLA_PORT_OFFSET;
-			printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
-			       c->name);
-		}
-	}
-
-	if (i2o_dma_alloc(dev, &c->status, 8)) {
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	if (i2o_dma_alloc(dev, &c->out_queue,
-		I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
-				sizeof(u32))) {
-		i2o_pci_free(c);
-		return -ENOMEM;
-	}
-
-	pci_set_drvdata(pdev, c);
-
-	return 0;
-}
-
-/**
- *	i2o_pci_interrupt - Interrupt handler for I2O controller
- *	@irq: interrupt line
- *	@dev_id: pointer to the I2O controller
- *
- *	Handle an interrupt from a PCI based I2O controller. This turns out
- *	to be rather simple. We keep the controller pointer in the cookie.
- */
-static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
-{
-	struct i2o_controller *c = dev_id;
-	u32 m;
-	irqreturn_t rc = IRQ_NONE;
-
-	while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
-		m = readl(c->out_port);
-		if (m == I2O_QUEUE_EMPTY) {
-			/*
-			 * Old 960 steppings had a bug in the I2O unit that
-			 * caused the queue to appear empty when it wasn't.
-			 */
-			m = readl(c->out_port);
-			if (unlikely(m == I2O_QUEUE_EMPTY))
-				break;
-		}
-
-		/* dispatch it */
-		if (i2o_driver_dispatch(c, m))
-			/* flush it if result != 0 */
-			i2o_flush_reply(c, m);
-
-		rc = IRQ_HANDLED;
-	}
-
-	return rc;
-}
-
-/**
- *	i2o_pci_irq_enable - Allocate interrupt for I2O controller
- *	@c: i2o_controller that the request is for
- *
- *	Allocate an interrupt for the I2O controller, and activate interrupts
- *	on the I2O controller.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_irq_enable(struct i2o_controller *c)
-{
-	struct pci_dev *pdev = c->pdev;
-	int rc;
-
-	writel(0xffffffff, c->irq_mask);
-
-	if (pdev->irq) {
-		rc = request_irq(pdev->irq, i2o_pci_interrupt, IRQF_SHARED,
-				 c->name, c);
-		if (rc < 0) {
-			printk(KERN_ERR "%s: unable to allocate interrupt %d."
-			       "\n", c->name, pdev->irq);
-			return rc;
-		}
-	}
-
-	writel(0x00000000, c->irq_mask);
-
-	printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
-
-	return 0;
-}
-
-/**
- *	i2o_pci_irq_disable - Free interrupt for I2O controller
- *	@c: I2O controller
- *
- *	Disable interrupts in I2O controller and then free interrupt.
- */
-static void i2o_pci_irq_disable(struct i2o_controller *c)
-{
-	writel(0xffffffff, c->irq_mask);
-
-	if (c->pdev->irq > 0)
-		free_irq(c->pdev->irq, c);
-}
-
-/**
- *	i2o_pci_probe - Probe the PCI device for an I2O controller
- *	@pdev: PCI device to test
- *	@id: id which matched with the PCI device id table
- *
- *	Probe the PCI device for any device which is a memory of the
- *	Intelligent, I2O class or an Adaptec Zero Channel Controller. We
- *	attempt to set up each such device and register it with the core.
- *
- *	Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct i2o_controller *c;
-	int rc;
-	struct pci_dev *i960 = NULL;
-
-	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
-
-	if ((pdev->class & 0xff) > 1) {
-		printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
-		       "(skipping).\n", pci_name(pdev));
-		return -ENODEV;
-	}
-
-	if ((rc = pci_enable_device(pdev))) {
-		printk(KERN_WARNING "i2o: couldn't enable device %s\n",
-		       pci_name(pdev));
-		return rc;
-	}
-
-	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-		printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
-		       pci_name(pdev));
-		rc = -ENODEV;
-		goto disable;
-	}
-
-	pci_set_master(pdev);
-
-	c = i2o_iop_alloc();
-	if (IS_ERR(c)) {
-		printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
-		       pci_name(pdev));
-		rc = PTR_ERR(c);
-		goto disable;
-	} else
-		printk(KERN_INFO "%s: controller found (%s)\n", c->name,
-		       pci_name(pdev));
-
-	c->pdev = pdev;
-	c->device.parent = &pdev->dev;
-
-	/* Cards that fall apart if you hit them with large I/O loads... */
-	if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
-		c->short_req = 1;
-		printk(KERN_INFO "%s: Symbios FC920 workarounds activated.\n",
-		       c->name);
-	}
-
-	if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
-		/*
-		 * Expose the ship behind i960 for initialization, or it will
-		 * failed
-		 */
-		i960 = pci_get_slot(c->pdev->bus,
-				  PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
-
-		if (i960) {
-			pci_write_config_word(i960, 0x42, 0);
-			pci_dev_put(i960);
-		}
-
-		c->promise = 1;
-		c->limit_sectors = 1;
-	}
-
-	if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
-		c->adaptec = 1;
-
-	/* Cards that go bananas if you quiesce them before you reset them. */
-	if (pdev->vendor == PCI_VENDOR_ID_DPT) {
-		c->no_quiesce = 1;
-		if (pdev->device == 0xa511)
-			c->raptor = 1;
-
-		if (pdev->subsystem_device == 0xc05a) {
-			c->limit_sectors = 1;
-			printk(KERN_INFO
-			       "%s: limit sectors per request to %d\n", c->name,
-			       I2O_MAX_SECTORS_LIMITED);
-		}
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
-		if (sizeof(dma_addr_t) > 4) {
-			if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
-				printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
-				       c->name);
-			else {
-				c->pae_support = 1;
-				printk(KERN_INFO "%s: using 64-bit DMA\n",
-				       c->name);
-			}
-		}
-#endif
-	}
-
-	if ((rc = i2o_pci_alloc(c))) {
-		printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
-		       "failed\n", c->name);
-		goto free_controller;
-	}
-
-	if (i2o_pci_irq_enable(c)) {
-		printk(KERN_ERR "%s: unable to enable interrupts for I2O "
-		       "controller\n", c->name);
-		goto free_pci;
-	}
-
-	if ((rc = i2o_iop_add(c)))
-		goto uninstall;
-
-	if (i960)
-		pci_write_config_word(i960, 0x42, 0x03ff);
-
-	return 0;
-
-      uninstall:
-	i2o_pci_irq_disable(c);
-
-      free_pci:
-	i2o_pci_free(c);
-
-      free_controller:
-	i2o_iop_free(c);
-
-      disable:
-	pci_disable_device(pdev);
-
-	return rc;
-}
-
-/**
- *	i2o_pci_remove - Removes a I2O controller from the system
- *	@pdev: I2O controller which should be removed
- *
- *	Reset the I2O controller, disable interrupts and remove all allocated
- *	resources.
- */
-static void i2o_pci_remove(struct pci_dev *pdev)
-{
-	struct i2o_controller *c;
-	c = pci_get_drvdata(pdev);
-
-	i2o_iop_remove(c);
-	i2o_pci_irq_disable(c);
-	i2o_pci_free(c);
-
-	pci_disable_device(pdev);
-
-	printk(KERN_INFO "%s: Controller removed.\n", c->name);
-
-	put_device(&c->device);
-};
-
-/* PCI driver for I2O controller */
-static struct pci_driver i2o_pci_driver = {
-	.name = "PCI_I2O",
-	.id_table = i2o_pci_ids,
-	.probe = i2o_pci_probe,
-	.remove = i2o_pci_remove,
-};
-
-/**
- *	i2o_pci_init - registers I2O PCI driver in PCI subsystem
- *
- *	Returns > 0 on success or negative error code on failure.
- */
-int __init i2o_pci_init(void)
-{
-	return pci_register_driver(&i2o_pci_driver);
-};
-
-/**
- *	i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
- */
-void __exit i2o_pci_exit(void)
-{
-	pci_unregister_driver(&i2o_pci_driver);
-};
-
-MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
index 9da04ed..f4c82ea 100644
--- a/drivers/misc/ad525x_dpot-spi.c
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -15,18 +15,21 @@
 static int write8(void *client, u8 val)
 {
 	u8 data = val;
+
 	return spi_write(client, &data, 1);
 }
 
 static int write16(void *client, u8 reg, u8 val)
 {
 	u8 data[2] = {reg, val};
+
 	return spi_write(client, data, 2);
 }
 
 static int write24(void *client, u8 reg, u16 val)
 {
 	u8 data[3] = {reg, val >> 8, val};
+
 	return spi_write(client, data, 3);
 }
 
@@ -34,6 +37,7 @@
 {
 	int ret;
 	u8 data;
+
 	ret = spi_read(client, &data, 1);
 	if (ret < 0)
 		return ret;
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index a43053d..15e88078 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -176,6 +176,7 @@
 {
 	int value;
 	unsigned ctrl = 0;
+
 	switch (dpot->uid) {
 	case DPOT_UID(AD5246_ID):
 	case DPOT_UID(AD5247_ID):
@@ -333,7 +334,6 @@
 	case DPOT_UID(AD5246_ID):
 	case DPOT_UID(AD5247_ID):
 		return dpot_write_d8(dpot, value);
-		break;
 
 	case DPOT_UID(AD5245_ID):
 	case DPOT_UID(AD5241_ID):
@@ -345,7 +345,6 @@
 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
 			0 : DPOT_AD5282_RDAC_AB;
 		return dpot_write_r8d8(dpot, ctrl, value);
-		break;
 	case DPOT_UID(AD5171_ID):
 	case DPOT_UID(AD5273_ID):
 		if (reg & DPOT_ADDR_OTP) {
@@ -355,7 +354,6 @@
 			ctrl = DPOT_AD5273_FUSE;
 		}
 		return dpot_write_r8d8(dpot, ctrl, value);
-		break;
 	case DPOT_UID(AD5172_ID):
 	case DPOT_UID(AD5173_ID):
 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
@@ -367,7 +365,6 @@
 			ctrl |= DPOT_AD5170_2_3_FUSE;
 		}
 		return dpot_write_r8d8(dpot, ctrl, value);
-		break;
 	case DPOT_UID(AD5170_ID):
 		if (reg & DPOT_ADDR_OTP) {
 			tmp = dpot_read_r8d16(dpot, tmp);
@@ -376,7 +373,6 @@
 			ctrl = DPOT_AD5170_2_3_FUSE;
 		}
 		return dpot_write_r8d8(dpot, ctrl, value);
-		break;
 	case DPOT_UID(AD5272_ID):
 	case DPOT_UID(AD5274_ID):
 		dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
@@ -391,7 +387,6 @@
 
 		return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
 				       (value >> 8), value & 0xFF);
-		break;
 	default:
 		if (reg & DPOT_ADDR_CMD)
 			return dpot_write_d8(dpot, reg);
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index c64d7ca..e735344 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -34,7 +34,6 @@
 #include <linux/semaphore.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 
diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c
index 2c33fbc..6ab31ef 100644
--- a/drivers/misc/genwqe/card_sysfs.c
+++ b/drivers/misc/genwqe/card_sysfs.c
@@ -24,7 +24,6 @@
  * debugging, please also see the debugfs interfaces of this driver.
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/module.h>
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 3336ddc..8758d03 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -144,9 +144,9 @@
 {
 	union ioc4_int_out int_out;
 	union ioc4_gpcr gpcr;
-	unsigned int state, last_state = 1;
+	unsigned int state, last_state;
 	uint64_t start, end, period;
-	unsigned int count = 0;
+	unsigned int count;
 
 	/* Enable output */
 	gpcr.raw = 0;
@@ -167,19 +167,20 @@
 	mmiowb();
 
 	/* Check square wave period averaged over some number of cycles */
-	do {
-		int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
-		state = int_out.fields.int_out;
-		if (!last_state && state) {
-			count++;
-			if (count == IOC4_CALIBRATE_END) {
-				end = ktime_get_ns();
-				break;
-			} else if (count == IOC4_CALIBRATE_DISCARD)
-				start = ktime_get_ns();
-		}
-		last_state = state;
-	} while (1);
+	start = ktime_get_ns();
+	state = 1; /* make sure the first read isn't a rising edge */
+	for (count = 0; count <= IOC4_CALIBRATE_END; count++) {
+		do { /* wait for a rising edge */
+			last_state = state;
+			int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
+			state = int_out.fields.int_out;
+		} while (last_state || !state);
+
+		/* discard the first few cycles */
+		if (count == IOC4_CALIBRATE_DISCARD)
+			start = ktime_get_ns();
+	}
+	end = ktime_get_ns();
 
 	/* Calculation rearranged to preserve intermediate precision.
 	 * Logically:
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 79f53941..c4cb9a9 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -97,23 +97,25 @@
 	/* allocate storage for ME message buffer */
 	msg_buf = kcalloc(dev->iamthif_mtu,
 			sizeof(unsigned char), GFP_KERNEL);
-	if (!msg_buf)
-		return -ENOMEM;
+	if (!msg_buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	dev->iamthif_msg_buf = msg_buf;
 
 	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
-
 	if (ret < 0) {
-		dev_err(dev->dev,
-			"amthif: failed link client %d\n", ret);
-		return ret;
+		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
+		goto out;
 	}
 
 	ret = mei_cl_connect(cl, NULL);
 
 	dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
+out:
+	mei_me_cl_put(me_cl);
 	return ret;
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index b3a72bc..be767f4 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -224,46 +224,53 @@
 }
 EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
 
-static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking)
 {
 	struct mei_device *dev;
-	struct mei_me_client *me_cl;
-	struct mei_cl_cb *cb;
-	int rets;
+	struct mei_me_client *me_cl = NULL;
+	struct mei_cl_cb *cb = NULL;
+	ssize_t rets;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
 
 	dev = cl->dev;
 
-	if (cl->state != MEI_FILE_CONNECTED)
-		return -ENODEV;
+	mutex_lock(&dev->device_lock);
+	if (cl->state != MEI_FILE_CONNECTED) {
+		rets = -ENODEV;
+		goto out;
+	}
 
 	/* Check if we have an ME client device */
 	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
-	if (!me_cl)
-		return -ENOTTY;
+	if (!me_cl) {
+		rets = -ENOTTY;
+		goto out;
+	}
 
-	if (length > me_cl->props.max_msg_length)
-		return -EFBIG;
+	if (length > me_cl->props.max_msg_length) {
+		rets = -EFBIG;
+		goto out;
+	}
 
 	cb = mei_io_cb_init(cl, NULL);
-	if (!cb)
-		return -ENOMEM;
+	if (!cb) {
+		rets = -ENOMEM;
+		goto out;
+	}
 
 	rets = mei_io_cb_alloc_req_buf(cb, length);
-	if (rets < 0) {
-		mei_io_cb_free(cb);
-		return rets;
-	}
+	if (rets < 0)
+		goto out;
 
 	memcpy(cb->request_buffer.data, buf, length);
 
-	mutex_lock(&dev->device_lock);
-
 	rets = mei_cl_write(cl, cb, blocking);
 
+out:
+	mei_me_cl_put(me_cl);
 	mutex_unlock(&dev->device_lock);
 	if (rets < 0)
 		mei_io_cb_free(cb);
@@ -271,12 +278,12 @@
 	return rets;
 }
 
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 {
 	struct mei_device *dev;
 	struct mei_cl_cb *cb;
 	size_t r_length;
-	int err;
+	ssize_t rets;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
@@ -286,11 +293,9 @@
 	mutex_lock(&dev->device_lock);
 
 	if (!cl->read_cb) {
-		err = mei_cl_read_start(cl, length);
-		if (err < 0) {
-			mutex_unlock(&dev->device_lock);
-			return err;
-		}
+		rets = mei_cl_read_start(cl, length);
+		if (rets < 0)
+			goto out;
 	}
 
 	if (cl->reading_state != MEI_READ_COMPLETE &&
@@ -313,13 +318,13 @@
 	cb = cl->read_cb;
 
 	if (cl->reading_state != MEI_READ_COMPLETE) {
-		r_length = 0;
+		rets = 0;
 		goto out;
 	}
 
 	r_length = min_t(size_t, length, cb->buf_idx);
-
 	memcpy(buf, cb->response_buffer.data, r_length);
+	rets = r_length;
 
 	mei_io_cb_free(cb);
 	cl->reading_state = MEI_IDLE;
@@ -328,20 +333,20 @@
 out:
 	mutex_unlock(&dev->device_lock);
 
-	return r_length;
+	return rets;
 }
 
-inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
 {
 	return ___mei_cl_send(cl, buf, length, 0);
 }
 
-inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
 {
 	return ___mei_cl_send(cl, buf, length, 1);
 }
 
-int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
 {
 	struct mei_cl *cl = device->cl;
 
@@ -355,7 +360,7 @@
 }
 EXPORT_SYMBOL_GPL(mei_cl_send);
 
-int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
 {
 	struct mei_cl *cl =  device->cl;
 
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1382d55..dfbddfe 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -27,7 +27,63 @@
 #include "client.h"
 
 /**
+ * mei_me_cl_init - initialize me client
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl)
+{
+	INIT_LIST_HEAD(&me_cl->list);
+	kref_init(&me_cl->refcnt);
+}
+
+/**
+ * mei_me_cl_get - increases me client refcount
+ *
+ * @me_cl: me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: me client or NULL
+ */
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
+{
+	if (me_cl)
+		kref_get(&me_cl->refcnt);
+
+	return me_cl;
+}
+
+/**
+ * mei_me_cl_release - unlink and free me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @ref: me_client refcount
+ */
+static void mei_me_cl_release(struct kref *ref)
+{
+	struct mei_me_client *me_cl =
+		container_of(ref, struct mei_me_client, refcnt);
+	list_del(&me_cl->list);
+	kfree(me_cl);
+}
+/**
+ * mei_me_cl_put - decrease me client refcount and free client if necessary
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_put(struct mei_me_client *me_cl)
+{
+	if (me_cl)
+		kref_put(&me_cl->refcnt, mei_me_cl_release);
+}
+
+/**
  * mei_me_cl_by_uuid - locate me client by uuid
+ *	increases ref count
  *
  * @dev: mei device
  * @uuid: me client uuid
@@ -43,13 +99,14 @@
 
 	list_for_each_entry(me_cl, &dev->me_clients, list)
 		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
-			return me_cl;
+			return mei_me_cl_get(me_cl);
 
 	return NULL;
 }
 
 /**
  * mei_me_cl_by_id - locate me client by client id
+ *	increases ref count
  *
  * @dev: the device structure
  * @client_id: me client id
@@ -65,12 +122,14 @@
 
 	list_for_each_entry(me_cl, &dev->me_clients, list)
 		if (me_cl->client_id == client_id)
-			return me_cl;
+			return mei_me_cl_get(me_cl);
+
 	return NULL;
 }
 
 /**
  * mei_me_cl_by_uuid_id - locate me client by client id and uuid
+ *	increases ref count
  *
  * @dev: the device structure
  * @uuid: me client uuid
@@ -88,31 +147,67 @@
 	list_for_each_entry(me_cl, &dev->me_clients, list)
 		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
 		    me_cl->client_id == client_id)
-			return me_cl;
+			return mei_me_cl_get(me_cl);
+
 	return NULL;
 }
 
 /**
- * mei_me_cl_remove - remove me client matching uuid and client_id
+ * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
  *
  * @dev: the device structure
  * @uuid: me client uuid
- * @client_id: me client address
+ *
+ * Locking: called under "dev->device_lock" lock
  */
-void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
 {
 	struct mei_me_client *me_cl, *next;
 
+	dev_dbg(dev->dev, "remove %pUl\n", uuid);
+	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
+			mei_me_cl_put(me_cl);
+}
+
+/**
+ * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
+ *
+ * @dev: the device structure
+ * @uuid: me client uuid
+ * @id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
+{
+	struct mei_me_client *me_cl, *next;
+	const uuid_le *pn;
+
+	dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
 	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
-		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
-		    me_cl->client_id == client_id) {
-			list_del(&me_cl->list);
-			kfree(me_cl);
-			break;
-		}
+		pn =  &me_cl->props.protocol_name;
+		if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
+			mei_me_cl_put(me_cl);
 	}
 }
 
+/**
+ * mei_me_cl_rm_all - remove all me clients
+ *
+ * @dev: the device structure
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_all(struct mei_device *dev)
+{
+	struct mei_me_client *me_cl, *next;
+
+	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+			mei_me_cl_put(me_cl);
+}
+
+
 
 /**
  * mei_cl_cmp_id - tells if the clients are the same
@@ -695,6 +790,7 @@
 {
 	struct mei_device *dev;
 	struct mei_me_client *me_cl;
+	int rets = 0;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -EINVAL;
@@ -704,18 +800,19 @@
 	if (cl->mei_flow_ctrl_creds > 0)
 		return 1;
 
-	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
 	if (!me_cl) {
 		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
 		return -ENOENT;
 	}
 
-	if (me_cl->mei_flow_ctrl_creds) {
+	if (me_cl->mei_flow_ctrl_creds > 0) {
+		rets = 1;
 		if (WARN_ON(me_cl->props.single_recv_buf == 0))
-			return -EINVAL;
-		return 1;
+			rets = -EINVAL;
 	}
-	return 0;
+	mei_me_cl_put(me_cl);
+	return rets;
 }
 
 /**
@@ -732,28 +829,36 @@
 {
 	struct mei_device *dev;
 	struct mei_me_client *me_cl;
+	int rets;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -EINVAL;
 
 	dev = cl->dev;
 
-	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
 	if (!me_cl) {
 		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
 		return -ENOENT;
 	}
 
 	if (me_cl->props.single_recv_buf) {
-		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-			return -EINVAL;
+		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
+			rets = -EINVAL;
+			goto out;
+		}
 		me_cl->mei_flow_ctrl_creds--;
 	} else {
-		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-			return -EINVAL;
+		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
+			rets = -EINVAL;
+			goto out;
+		}
 		cl->mei_flow_ctrl_creds--;
 	}
-	return 0;
+	rets = 0;
+out:
+	mei_me_cl_put(me_cl);
+	return rets;
 }
 
 /**
@@ -788,6 +893,9 @@
 		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
 		return  -ENOTTY;
 	}
+	/* always allocate at least client max message */
+	length = max_t(size_t, length, me_cl->props.max_msg_length);
+	mei_me_cl_put(me_cl);
 
 	rets = pm_runtime_get(dev->dev);
 	if (rets < 0 && rets != -EINPROGRESS) {
@@ -802,8 +910,6 @@
 		goto out;
 	}
 
-	/* always allocate at least client max message */
-	length = max_t(size_t, length, me_cl->props.max_msg_length);
 	rets = mei_io_cb_alloc_resp_buf(cb, length);
 	if (rets)
 		goto out;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index d9d0c15..cfcde8e 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -24,15 +24,22 @@
 
 #include "mei_dev.h"
 
-struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
-					const uuid_le *cuuid);
-struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
+/*
+ * reference counting base function
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl);
+void mei_me_cl_put(struct mei_me_client *me_cl);
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl);
 
+struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
+					const uuid_le *uuid);
+struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
 struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
 					   const uuid_le *uuid, u8 client_id);
-
-void mei_me_cl_remove(struct mei_device *dev,
-		      const uuid_le *uuid, u8 client_id);
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid);
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev,
+			     const uuid_le *uuid, u8 id);
+void mei_me_cl_rm_all(struct mei_device *dev);
 
 /*
  * MEI IO Functions
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index b60b426..b125380 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -21,20 +21,22 @@
 #include <linux/mei.h>
 
 #include "mei_dev.h"
+#include "client.h"
 #include "hw.h"
 
 static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
 					size_t cnt, loff_t *ppos)
 {
 	struct mei_device *dev = fp->private_data;
-	struct mei_me_client *me_cl;
+	struct mei_me_client *me_cl, *n;
 	size_t bufsz = 1;
 	char *buf;
 	int i = 0;
 	int pos = 0;
 	int ret;
 
-#define HDR "  |id|fix|         UUID                       |con|msg len|sb|\n"
+#define HDR \
+"  |id|fix|         UUID                       |con|msg len|sb|refc|\n"
 
 	mutex_lock(&dev->device_lock);
 
@@ -54,16 +56,22 @@
 	if (dev->dev_state != MEI_DEV_ENABLED)
 		goto out;
 
-	list_for_each_entry(me_cl, &dev->me_clients, list) {
+	list_for_each_entry_safe(me_cl, n, &dev->me_clients, list) {
 
-		pos += scnprintf(buf + pos, bufsz - pos,
-			"%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n",
-			i++, me_cl->client_id,
-			me_cl->props.fixed_address,
-			&me_cl->props.protocol_name,
-			me_cl->props.max_number_of_connections,
-			me_cl->props.max_msg_length,
-			me_cl->props.single_recv_buf);
+		me_cl = mei_me_cl_get(me_cl);
+		if (me_cl) {
+			pos += scnprintf(buf + pos, bufsz - pos,
+				"%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
+				i++, me_cl->client_id,
+				me_cl->props.fixed_address,
+				&me_cl->props.protocol_name,
+				me_cl->props.max_number_of_connections,
+				me_cl->props.max_msg_length,
+				me_cl->props.single_recv_buf,
+				atomic_read(&me_cl->refcnt.refcount));
+		}
+
+		mei_me_cl_put(me_cl);
 	}
 out:
 	mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 239d7f5..c8412d4 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -105,21 +105,6 @@
 }
 
 /**
- * mei_me_cl_remove_all - remove all me clients
- *
- * @dev: the device structure
- */
-static void mei_me_cl_remove_all(struct mei_device *dev)
-{
-	struct mei_me_client *me_cl, *next;
-
-	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
-			list_del(&me_cl->list);
-			kfree(me_cl);
-	}
-}
-
-/**
  * mei_hbm_reset - reset hbm counters and book keeping data structurs
  *
  * @dev: the device structure
@@ -128,7 +113,7 @@
 {
 	dev->me_client_index = 0;
 
-	mei_me_cl_remove_all(dev);
+	mei_me_cl_rm_all(dev);
 
 	mei_hbm_idle(dev);
 }
@@ -339,11 +324,16 @@
 			     struct hbm_props_response *res)
 {
 	struct mei_me_client *me_cl;
+	const uuid_le *uuid = &res->client_properties.protocol_name;
+
+	mei_me_cl_rm_by_uuid(dev, uuid);
 
 	me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
 	if (!me_cl)
 		return -ENOMEM;
 
+	mei_me_cl_init(me_cl);
+
 	me_cl->props = res->client_properties;
 	me_cl->client_id = res->me_addr;
 	me_cl->mei_flow_ctrl_creds = 0;
@@ -484,6 +474,7 @@
 				  struct hbm_flow_control *flow)
 {
 	struct mei_me_client *me_cl;
+	int rets;
 
 	me_cl = mei_me_cl_by_id(dev, flow->me_addr);
 	if (!me_cl) {
@@ -492,14 +483,19 @@
 		return -ENOENT;
 	}
 
-	if (WARN_ON(me_cl->props.single_recv_buf == 0))
-		return -EINVAL;
+	if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
+		rets = -EINVAL;
+		goto out;
+	}
 
 	me_cl->mei_flow_ctrl_creds++;
 	dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
 	    flow->me_addr, me_cl->mei_flow_ctrl_creds);
 
-	return 0;
+	rets = 0;
+out:
+	mei_me_cl_put(me_cl);
+	return rets;
 }
 
 /**
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 06ff0a2..f8fd503 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -242,7 +242,7 @@
 	if ((hcsr & H_RST) == H_RST) {
 		dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr);
 		hcsr &= ~H_RST;
-		mei_me_reg_write(hw, H_CSR, hcsr);
+		mei_hcsr_set(hw, hcsr);
 		hcsr = mei_hcsr_read(hw);
 	}
 
@@ -335,6 +335,7 @@
 		return -ETIME;
 	}
 
+	mei_me_hw_reset_release(dev);
 	dev->recvd_hw_ready = false;
 	return 0;
 }
@@ -731,9 +732,7 @@
 	/*  check if we need to start the dev */
 	if (!mei_host_is_ready(dev)) {
 		if (mei_hw_is_ready(dev)) {
-			mei_me_hw_reset_release(dev);
 			dev_dbg(dev->dev, "we need to start the dev.\n");
-
 			dev->recvd_hw_ready = true;
 			wake_up(&dev->wait_hw_ready);
 		} else {
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index ae56ba6..3c019c0 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -303,7 +303,7 @@
 			 size_t length, loff_t *offset)
 {
 	struct mei_cl *cl = file->private_data;
-	struct mei_me_client *me_cl;
+	struct mei_me_client *me_cl = NULL;
 	struct mei_cl_cb *write_cb = NULL;
 	struct mei_device *dev;
 	unsigned long timeout = 0;
@@ -399,12 +399,14 @@
 				"amthif write failed with status = %d\n", rets);
 			goto out;
 		}
+		mei_me_cl_put(me_cl);
 		mutex_unlock(&dev->device_lock);
 		return length;
 	}
 
 	rets = mei_cl_write(cl, write_cb, false);
 out:
+	mei_me_cl_put(me_cl);
 	mutex_unlock(&dev->device_lock);
 	if (rets < 0)
 		mei_io_cb_free(write_cb);
@@ -433,24 +435,19 @@
 	cl = file->private_data;
 	dev = cl->dev;
 
-	if (dev->dev_state != MEI_DEV_ENABLED) {
-		rets = -ENODEV;
-		goto end;
-	}
+	if (dev->dev_state != MEI_DEV_ENABLED)
+		return -ENODEV;
 
 	if (cl->state != MEI_FILE_INITIALIZING &&
-	    cl->state != MEI_FILE_DISCONNECTED) {
-		rets = -EBUSY;
-		goto end;
-	}
+	    cl->state != MEI_FILE_DISCONNECTED)
+		return  -EBUSY;
 
 	/* find ME client we're trying to connect to */
 	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
 	if (!me_cl || me_cl->props.fixed_address) {
 		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
 				&data->in_client_uuid);
-		rets = -ENOTTY;
-		goto end;
+		return  -ENOTTY;
 	}
 
 	cl->me_client_id = me_cl->client_id;
@@ -487,17 +484,16 @@
 		goto end;
 	}
 
-
 	/* prepare the output buffer */
 	client = &data->out_client_properties;
 	client->max_msg_length = me_cl->props.max_msg_length;
 	client->protocol_version = me_cl->props.protocol_version;
 	dev_dbg(dev->dev, "Can connect?\n");
 
-
 	rets = mei_cl_connect(cl, file);
 
 end:
+	mei_me_cl_put(me_cl);
 	return rets;
 }
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 3dad74a..6c6ce93 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -172,12 +172,14 @@
  * struct mei_me_client - representation of me (fw) client
  *
  * @list: link in me client list
+ * @refcnt: struct reference count
  * @props: client properties
  * @client_id: me client id
  * @mei_flow_ctrl_creds: flow control credits
  */
 struct mei_me_client {
 	struct list_head list;
+	struct kref refcnt;
 	struct mei_client_properties props;
 	u8 client_id;
 	u8 mei_flow_ctrl_creds;
@@ -345,9 +347,9 @@
 					struct mei_cl_ops *ops);
 void mei_cl_remove_device(struct mei_cl_device *device);
 
-int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 void mei_cl_bus_rx_event(struct mei_cl *cl);
 void mei_cl_bus_remove_devices(struct mei_device *dev);
 int mei_cl_bus_init(void);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 60ca924..bb61a11 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -521,6 +521,7 @@
 
 	cl_info->me_client_id = me_cl->client_id;
 	cl_info->cl_uuid = me_cl->props.protocol_name;
+	mei_me_cl_put(me_cl);
 
 	ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
 	if (ret)
@@ -539,6 +540,7 @@
 
 	cl->me_client_id = me_cl->client_id;
 	cl->cl_uuid = me_cl->props.protocol_name;
+	mei_me_cl_put(me_cl);
 
 	ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
 	if (ret)
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index b1d892c..475f1de 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -76,6 +76,7 @@
 
 	cl->me_client_id = me_cl->client_id;
 	cl->cl_uuid = me_cl->props.protocol_name;
+	mei_me_cl_put(me_cl);
 
 	ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
 
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 54be83d..c8c6a36 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -343,12 +343,26 @@
 			/* Unknow packet? */
 		default:
 			type = *ptr;
-			if (st_gdata->list[type] == NULL) {
-				pr_err("chip/interface misbehavior dropping"
-					" frame starting with 0x%02x", type);
-				goto done;
 
+			/* Default case means non-HCILL packets,
+			 * possibilities are packets for:
+			 * (a) valid protocol -  Supported Protocols within
+			 *     the ST_MAX_CHANNELS.
+			 * (b) registered protocol - Checked by
+			 *     "st_gdata->list[type] == NULL)" are supported
+			 *     protocols only.
+			 *  Rules out any invalid protocol and
+			 *  unregistered protocols with channel ID < 16.
+			 */
+
+			if ((type >= ST_MAX_CHANNELS) ||
+					(st_gdata->list[type] == NULL)) {
+				pr_err("chip/interface misbehavior: "
+						"dropping frame starting "
+						"with 0x%02x\n", type);
+				goto done;
 			}
+
 			st_gdata->rx_skb = alloc_skb(
 					st_gdata->list[type]->max_frame_size,
 					GFP_ATOMIC);
@@ -893,5 +907,3 @@
 		kfree(st_gdata);
 	}
 }
-
-
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index e4b7ee4f..18e7a03 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -36,7 +36,8 @@
 #include <linux/skbuff.h>
 #include <linux/ti_wilink_st.h>
 #include <linux/module.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #define MAX_ST_DEVICES	3	/* Imagine 1 on each UART for now */
 static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
@@ -44,6 +45,9 @@
 /**********************************************************************/
 /* internal functions */
 
+struct ti_st_plat_data	*dt_pdata;
+static struct ti_st_plat_data *get_platform_data(struct device *dev);
+
 /**
  * st_get_plat_device -
  *	function which returns the reference to the platform device
@@ -215,6 +219,7 @@
 {
 	unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
 	const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
+	long timeout;
 
 	pr_debug("%s", __func__);
 
@@ -224,10 +229,11 @@
 		return -EIO;
 	}
 
-	if (!wait_for_completion_interruptible_timeout(
-		&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
-		pr_err(" waiting for ver info- timed out ");
-		return -ETIMEDOUT;
+	timeout = wait_for_completion_interruptible_timeout(
+		&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME));
+	if (timeout <= 0) {
+		pr_err(" waiting for ver info- timed out or received signal");
+		return timeout ? -ERESTARTSYS : -ETIMEDOUT;
 	}
 	reinit_completion(&kim_gdata->kim_rcvd);
 	/* the positions 12 & 13 in the response buffer provide with the
@@ -391,13 +397,14 @@
 			break;
 		case ACTION_WAIT_EVENT:  /* wait */
 			pr_debug("W");
-			if (!wait_for_completion_interruptible_timeout(
+			err = wait_for_completion_interruptible_timeout(
 					&kim_gdata->kim_rcvd,
-					msecs_to_jiffies(CMD_RESP_TIME))) {
-				pr_err("response timeout during fw download ");
+					msecs_to_jiffies(CMD_RESP_TIME));
+			if (err <= 0) {
+				pr_err("response timeout/signaled during fw download ");
 				/* timed out */
 				release_firmware(kim_gdata->fw_entry);
-				return -ETIMEDOUT;
+				return err ? -ERESTARTSYS : -ETIMEDOUT;
 			}
 			reinit_completion(&kim_gdata->kim_rcvd);
 			break;
@@ -462,7 +469,12 @@
 	struct kim_data_s	*kim_gdata = (struct kim_data_s *)kim_data;
 
 	pr_info(" %s", __func__);
-	pdata = kim_gdata->kim_pdev->dev.platform_data;
+	if (kim_gdata->kim_pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = kim_gdata->kim_pdev->dev.platform_data;
+	}
 
 	do {
 		/* platform specific enabling code here */
@@ -522,12 +534,18 @@
 {
 	long err = 0;
 	struct kim_data_s	*kim_gdata = (struct kim_data_s *)kim_data;
-	struct ti_st_plat_data	*pdata =
-		kim_gdata->kim_pdev->dev.platform_data;
+	struct ti_st_plat_data	*pdata;
 	struct tty_struct	*tty = kim_gdata->core_data->tty;
 
 	reinit_completion(&kim_gdata->ldisc_installed);
 
+	if (kim_gdata->kim_pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else
+		pdata = kim_gdata->kim_pdev->dev.platform_data;
+
+
 	if (tty) {	/* can be called before ldisc is installed */
 		/* Flush any pending characters in the driver and discipline. */
 		tty_ldisc_flush(tty);
@@ -620,7 +638,7 @@
 		struct device_attribute *attr, char *buf)
 {
 	struct kim_data_s *kim_data = dev_get_drvdata(dev);
-	return sprintf(buf, "%ld\n", kim_data->baud_rate);
+	return sprintf(buf, "%d\n", kim_data->baud_rate);
 }
 
 static ssize_t show_flow_cntrl(struct device *dev,
@@ -676,12 +694,16 @@
 	struct kim_data_s	*kim_gdata;
 	/* get kim_gdata reference from platform device */
 	pdev = st_get_plat_device(id);
-	if (!pdev) {
-		*core_data = NULL;
-		return;
-	}
+	if (!pdev)
+		goto err;
 	kim_gdata = platform_get_drvdata(pdev);
+	if (!kim_gdata)
+		goto err;
+
 	*core_data = kim_gdata->core_data;
+	return;
+err:
+	*core_data = NULL;
 }
 
 static int kim_version_open(struct inode *i, struct file *f)
@@ -715,13 +737,53 @@
  * board-*.c file
  */
 
+static const struct of_device_id kim_of_match[] = {
+{
+	.compatible = "kim",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, kim_of_match);
+
+static struct ti_st_plat_data *get_platform_data(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	const u32 *dt_property;
+	int len;
+
+	dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL);
+
+	if (!dt_pdata)
+		pr_err("Can't allocate device_tree platform data\n");
+
+	dt_property = of_get_property(np, "dev_name", &len);
+	if (dt_property)
+		memcpy(&dt_pdata->dev_name, dt_property, len);
+	of_property_read_u32(np, "nshutdown_gpio",
+			     &dt_pdata->nshutdown_gpio);
+	of_property_read_u32(np, "flow_cntrl", &dt_pdata->flow_cntrl);
+	of_property_read_u32(np, "baud_rate", &dt_pdata->baud_rate);
+
+	return dt_pdata;
+}
+
 static struct dentry *kim_debugfs_dir;
 static int kim_probe(struct platform_device *pdev)
 {
 	struct kim_data_s	*kim_gdata;
-	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
+	struct ti_st_plat_data	*pdata;
 	int err;
 
+	if (pdev->dev.of_node)
+		pdata = get_platform_data(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "Platform Data is missing\n");
+		return -ENXIO;
+	}
+
 	if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) {
 		/* multiple devices could exist */
 		st_kim_devices[pdev->id] = pdev;
@@ -750,14 +812,14 @@
 	kim_gdata->nshutdown = pdata->nshutdown_gpio;
 	err = gpio_request(kim_gdata->nshutdown, "kim");
 	if (unlikely(err)) {
-		pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
+		pr_err(" gpio %d request failed ", kim_gdata->nshutdown);
 		return err;
 	}
 
 	/* Configure nShutdown GPIO as output=0 */
 	err = gpio_direction_output(kim_gdata->nshutdown, 0);
 	if (unlikely(err)) {
-		pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
+		pr_err(" unable to configure gpio %d", kim_gdata->nshutdown);
 		return err;
 	}
 	/* get reference of pdev for request_firmware
@@ -781,8 +843,7 @@
 	kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
 	if (!kim_debugfs_dir) {
 		pr_err(" debugfs entries creation failed ");
-		err = -EIO;
-		goto err_debugfs_dir;
+		return 0;
 	}
 
 	debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
@@ -791,9 +852,6 @@
 				kim_gdata, &list_debugfs_fops);
 	return 0;
 
-err_debugfs_dir:
-	sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
-
 err_sysfs_group:
 	st_core_exit(kim_gdata->core_data);
 
@@ -806,9 +864,16 @@
 static int kim_remove(struct platform_device *pdev)
 {
 	/* free the GPIOs requested */
-	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
+	struct ti_st_plat_data	*pdata;
 	struct kim_data_s	*kim_gdata;
 
+	if (pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = pdev->dev.platform_data;
+	}
+
 	kim_gdata = platform_get_drvdata(pdev);
 
 	/* Free the Bluetooth/FM/GPIO
@@ -826,27 +891,44 @@
 
 	kfree(kim_gdata);
 	kim_gdata = NULL;
+	kfree(dt_pdata);
+	dt_pdata = NULL;
+
 	return 0;
 }
 
 static int kim_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
+	struct ti_st_plat_data	*pdata;
+
+	if (pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = pdev->dev.platform_data;
+	}
 
 	if (pdata->suspend)
 		return pdata->suspend(pdev, state);
 
-	return -EOPNOTSUPP;
+	return 0;
 }
 
 static int kim_resume(struct platform_device *pdev)
 {
-	struct ti_st_plat_data	*pdata = pdev->dev.platform_data;
+	struct ti_st_plat_data	*pdata;
+
+	if (pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = pdev->dev.platform_data;
+	}
 
 	if (pdata->resume)
 		return pdata->resume(pdev);
 
-	return -EOPNOTSUPP;
+	return 0;
 }
 
 /**********************************************************************/
@@ -858,6 +940,8 @@
 	.resume = kim_resume,
 	.driver = {
 		.name = "kim",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(kim_of_match),
 	},
 };
 
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
index 93b4d67..518e1b7 100644
--- a/drivers/misc/ti-st/st_ll.c
+++ b/drivers/misc/ti-st/st_ll.c
@@ -26,6 +26,7 @@
 #include <linux/ti_wilink_st.h>
 
 /**********************************************************************/
+
 /* internal functions */
 static void send_ll_cmd(struct st_data_s *st_data,
 	unsigned char cmd)
@@ -53,7 +54,13 @@
 
 	/* communicate to platform about chip asleep */
 	kim_data = st_data->kim_data;
-	pdata = kim_data->kim_pdev->dev.platform_data;
+	if (kim_data->kim_pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = kim_data->kim_pdev->dev.platform_data;
+	}
+
 	if (pdata->chip_asleep)
 		pdata->chip_asleep(NULL);
 }
@@ -86,7 +93,13 @@
 
 	/* communicate to platform about chip wakeup */
 	kim_data = st_data->kim_data;
-	pdata = kim_data->kim_pdev->dev.platform_data;
+	if (kim_data->kim_pdev->dev.of_node) {
+		pr_debug("use device tree data");
+		pdata = dt_pdata;
+	} else {
+		pdata = kim_data->kim_pdev->dev.platform_data;
+	}
+
 	if (pdata->chip_awake)
 		pdata->chip_awake(NULL);
 }
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index 3dee7ae..032d35c 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.0.0-k");
+MODULE_VERSION("1.1.1.0-k");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
index 1723a6e..66fc992 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -218,13 +218,12 @@
 }
 
 /*
- * Sets up a given context for notify to work.  Calls drv_map_bool_ptr()
- * which maps the notify boolean in user VA in kernel space.
+ * Sets up a given context for notify to work. Maps the notify
+ * boolean in user VA into kernel space.
  */
 static int vmci_host_setup_notify(struct vmci_ctx *context,
 				  unsigned long uva)
 {
-	struct page *page;
 	int retval;
 
 	if (context->notify_page) {
@@ -243,14 +242,16 @@
 	/*
 	 * Lock physical page backing a given user VA.
 	 */
-	retval = get_user_pages_fast(PAGE_ALIGN(uva), 1, 1, &page);
-	if (retval != 1)
+	retval = get_user_pages_fast(uva, 1, 1, &context->notify_page);
+	if (retval != 1) {
+		context->notify_page = NULL;
 		return VMCI_ERROR_GENERIC;
+	}
 
 	/*
 	 * Map the locked page and set up notify pointer.
 	 */
-	context->notify = kmap(page) + (uva & (PAGE_SIZE - 1));
+	context->notify = kmap(context->notify_page) + (uva & (PAGE_SIZE - 1));
 	vmci_ctx_check_signal_notify(context);
 
 	return VMCI_SUCCESS;
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 6b6bce2..db2c05b 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -42,11 +42,12 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/mtd/ubi.h>
 #include <linux/workqueue.h>
 #include <linux/blkdev.h>
+#include <linux/blk-mq.h>
 #include <linux/hdreg.h>
+#include <linux/scatterlist.h>
 #include <asm/div64.h>
 
 #include "ubi-media.h"
@@ -67,6 +68,11 @@
 	char name[UBIBLOCK_PARAM_LEN+1];
 };
 
+struct ubiblock_pdu {
+	struct work_struct work;
+	struct ubi_sgl usgl;
+};
+
 /* Numbers of elements set in the @ubiblock_param array */
 static int ubiblock_devs __initdata;
 
@@ -84,11 +90,10 @@
 	struct request_queue *rq;
 
 	struct workqueue_struct *wq;
-	struct work_struct work;
 
 	struct mutex dev_mutex;
-	spinlock_t queue_lock;
 	struct list_head list;
+	struct blk_mq_tag_set tag_set;
 };
 
 /* Linked list of all ubiblock instances */
@@ -181,31 +186,20 @@
 	return NULL;
 }
 
-static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
-				int leb, int offset, int len)
+static int ubiblock_read(struct ubiblock_pdu *pdu)
 {
-	int ret;
+	int ret, leb, offset, bytes_left, to_read;
+	u64 pos;
+	struct request *req = blk_mq_rq_from_pdu(pdu);
+	struct ubiblock *dev = req->q->queuedata;
 
-	ret = ubi_read(dev->desc, leb, buffer, offset, len);
-	if (ret) {
-		dev_err(disk_to_dev(dev->gd), "%d while reading from LEB %d (offset %d, length %d)",
-			ret, leb, offset, len);
-		return ret;
-	}
-	return 0;
-}
-
-static int ubiblock_read(struct ubiblock *dev, char *buffer,
-			 sector_t sec, int len)
-{
-	int ret, leb, offset;
-	int bytes_left = len;
-	int to_read = len;
-	u64 pos = sec << 9;
+	to_read = blk_rq_bytes(req);
+	pos = blk_rq_pos(req) << 9;
 
 	/* Get LEB:offset address to read from */
 	offset = do_div(pos, dev->leb_size);
 	leb = pos;
+	bytes_left = to_read;
 
 	while (bytes_left) {
 		/*
@@ -215,11 +209,10 @@
 		if (offset + to_read > dev->leb_size)
 			to_read = dev->leb_size - offset;
 
-		ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read);
-		if (ret)
+		ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
+		if (ret < 0)
 			return ret;
 
-		buffer += to_read;
 		bytes_left -= to_read;
 		to_read = bytes_left;
 		leb += 1;
@@ -228,79 +221,6 @@
 	return 0;
 }
 
-static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
-{
-	int len, ret;
-	sector_t sec;
-
-	if (req->cmd_type != REQ_TYPE_FS)
-		return -EIO;
-
-	if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
-	    get_capacity(req->rq_disk))
-		return -EIO;
-
-	if (rq_data_dir(req) != READ)
-		return -ENOSYS; /* Write not implemented */
-
-	sec = blk_rq_pos(req);
-	len = blk_rq_cur_bytes(req);
-
-	/*
-	 * Let's prevent the device from being removed while we're doing I/O
-	 * work. Notice that this means we serialize all the I/O operations,
-	 * but it's probably of no impact given the NAND core serializes
-	 * flash access anyway.
-	 */
-	mutex_lock(&dev->dev_mutex);
-	ret = ubiblock_read(dev, bio_data(req->bio), sec, len);
-	mutex_unlock(&dev->dev_mutex);
-
-	return ret;
-}
-
-static void ubiblock_do_work(struct work_struct *work)
-{
-	struct ubiblock *dev =
-		container_of(work, struct ubiblock, work);
-	struct request_queue *rq = dev->rq;
-	struct request *req;
-	int res;
-
-	spin_lock_irq(rq->queue_lock);
-
-	req = blk_fetch_request(rq);
-	while (req) {
-
-		spin_unlock_irq(rq->queue_lock);
-		res = do_ubiblock_request(dev, req);
-		spin_lock_irq(rq->queue_lock);
-
-		/*
-		 * If we're done with this request,
-		 * we need to fetch a new one
-		 */
-		if (!__blk_end_request_cur(req, res))
-			req = blk_fetch_request(rq);
-	}
-
-	spin_unlock_irq(rq->queue_lock);
-}
-
-static void ubiblock_request(struct request_queue *rq)
-{
-	struct ubiblock *dev;
-	struct request *req;
-
-	dev = rq->queuedata;
-
-	if (!dev)
-		while ((req = blk_fetch_request(rq)) != NULL)
-			__blk_end_request_all(req, -ENODEV);
-	else
-		queue_work(dev->wq, &dev->work);
-}
-
 static int ubiblock_open(struct block_device *bdev, fmode_t mode)
 {
 	struct ubiblock *dev = bdev->bd_disk->private_data;
@@ -374,6 +294,63 @@
 	.getgeo	= ubiblock_getgeo,
 };
 
+static void ubiblock_do_work(struct work_struct *work)
+{
+	int ret;
+	struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work);
+	struct request *req = blk_mq_rq_from_pdu(pdu);
+
+	blk_mq_start_request(req);
+
+	/*
+	 * It is safe to ignore the return value of blk_rq_map_sg() because
+	 * the number of sg entries is limited to UBI_MAX_SG_COUNT
+	 * and ubi_read_sg() will check that limit.
+	 */
+	blk_rq_map_sg(req->q, req, pdu->usgl.sg);
+
+	ret = ubiblock_read(pdu);
+	blk_mq_end_request(req, ret);
+}
+
+static int ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
+			     const struct blk_mq_queue_data *bd)
+{
+	struct request *req = bd->rq;
+	struct ubiblock *dev = hctx->queue->queuedata;
+	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
+
+	if (req->cmd_type != REQ_TYPE_FS)
+		return BLK_MQ_RQ_QUEUE_ERROR;
+
+	if (rq_data_dir(req) != READ)
+		return BLK_MQ_RQ_QUEUE_ERROR; /* Write not implemented */
+
+	ubi_sgl_init(&pdu->usgl);
+	queue_work(dev->wq, &pdu->work);
+
+	return BLK_MQ_RQ_QUEUE_OK;
+}
+
+static int ubiblock_init_request(void *data, struct request *req,
+				 unsigned int hctx_idx,
+				 unsigned int request_idx,
+				 unsigned int numa_node)
+{
+	struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
+
+	sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
+	INIT_WORK(&pdu->work, ubiblock_do_work);
+
+	return 0;
+}
+
+static struct blk_mq_ops ubiblock_mq_ops = {
+	.queue_rq       = ubiblock_queue_rq,
+	.init_request	= ubiblock_init_request,
+	.map_queue      = blk_mq_map_queue,
+};
+
 int ubiblock_create(struct ubi_volume_info *vi)
 {
 	struct ubiblock *dev;
@@ -417,14 +394,28 @@
 	set_capacity(gd, disk_capacity);
 	dev->gd = gd;
 
-	spin_lock_init(&dev->queue_lock);
-	dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock);
-	if (!dev->rq) {
-		dev_err(disk_to_dev(gd), "blk_init_queue failed");
-		ret = -ENODEV;
+	dev->tag_set.ops = &ubiblock_mq_ops;
+	dev->tag_set.queue_depth = 64;
+	dev->tag_set.numa_node = NUMA_NO_NODE;
+	dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+	dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
+	dev->tag_set.driver_data = dev;
+	dev->tag_set.nr_hw_queues = 1;
+
+	ret = blk_mq_alloc_tag_set(&dev->tag_set);
+	if (ret) {
+		dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
 		goto out_put_disk;
 	}
 
+	dev->rq = blk_mq_init_queue(&dev->tag_set);
+	if (IS_ERR(dev->rq)) {
+		dev_err(disk_to_dev(gd), "blk_mq_init_queue failed");
+		ret = PTR_ERR(dev->rq);
+		goto out_free_tags;
+	}
+	blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
+
 	dev->rq->queuedata = dev;
 	dev->gd->queue = dev->rq;
 
@@ -437,7 +428,6 @@
 		ret = -ENOMEM;
 		goto out_free_queue;
 	}
-	INIT_WORK(&dev->work, ubiblock_do_work);
 
 	mutex_lock(&devices_mutex);
 	list_add_tail(&dev->list, &ubiblock_devices);
@@ -451,6 +441,8 @@
 
 out_free_queue:
 	blk_cleanup_queue(dev->rq);
+out_free_tags:
+	blk_mq_free_tag_set(&dev->tag_set);
 out_put_disk:
 	put_disk(dev->gd);
 out_free_dev:
@@ -461,8 +453,13 @@
 
 static void ubiblock_cleanup(struct ubiblock *dev)
 {
+	/* Stop new requests to arrive */
 	del_gendisk(dev->gd);
+	/* Flush pending work */
+	destroy_workqueue(dev->wq);
+	/* Finally destroy the blk queue */
 	blk_cleanup_queue(dev->rq);
+	blk_mq_free_tag_set(&dev->tag_set);
 	dev_info(disk_to_dev(dev->gd), "released");
 	put_disk(dev->gd);
 }
@@ -490,9 +487,6 @@
 	list_del(&dev->list);
 	mutex_unlock(&devices_mutex);
 
-	/* Flush pending work and stop this workqueue */
-	destroy_workqueue(dev->wq);
-
 	ubiblock_cleanup(dev);
 	mutex_unlock(&dev->dev_mutex);
 	kfree(dev);
@@ -583,22 +577,28 @@
 		return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
 }
 
-static int __init ubiblock_create_from_param(void)
+static void __init ubiblock_create_from_param(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	struct ubiblock_param *p;
 	struct ubi_volume_desc *desc;
 	struct ubi_volume_info vi;
 
+	/*
+	 * If there is an error creating one of the ubiblocks, continue on to
+	 * create the following ubiblocks. This helps in a circumstance where
+	 * the kernel command-line specifies multiple block devices and some
+	 * may be broken, but we still want the working ones to come up.
+	 */
 	for (i = 0; i < ubiblock_devs; i++) {
 		p = &ubiblock_param[i];
 
 		desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
 		if (IS_ERR(desc)) {
-			pr_err("UBI: block: can't open volume, err=%ld\n",
-			       PTR_ERR(desc));
-			ret = PTR_ERR(desc);
-			break;
+			pr_err(
+			       "UBI: block: can't open volume on ubi%d_%d, err=%ld",
+			       p->ubi_num, p->vol_id, PTR_ERR(desc));
+			continue;
 		}
 
 		ubi_get_volume_info(desc, &vi);
@@ -606,12 +606,12 @@
 
 		ret = ubiblock_create(&vi);
 		if (ret) {
-			pr_err("UBI: block: can't add '%s' volume, err=%d\n",
-			       vi.name, ret);
-			break;
+			pr_err(
+			       "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d",
+			       vi.name, p->ubi_num, p->vol_id, ret);
+			continue;
 		}
 	}
-	return ret;
 }
 
 static void ubiblock_remove_all(void)
@@ -620,8 +620,6 @@
 	struct ubiblock *dev;
 
 	list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
-		/* Flush pending work and stop workqueue */
-		destroy_workqueue(dev->wq);
 		/* The module is being forcefully removed */
 		WARN_ON(dev->desc);
 		/* Remove from device list */
@@ -639,10 +637,12 @@
 	if (ubiblock_major < 0)
 		return ubiblock_major;
 
-	/* Attach block devices from 'block=' module param */
-	ret = ubiblock_create_from_param();
-	if (ret)
-		goto err_remove;
+	/*
+	 * Attach block devices from 'block=' module param.
+	 * Even if one block device in the param list fails to come up,
+	 * still allow the module to load and leave any others up.
+	 */
+	ubiblock_create_from_param();
 
 	/*
 	 * Block devices are only created upon user requests, so we ignore
@@ -655,7 +655,6 @@
 
 err_unreg:
 	unregister_blkdev(ubiblock_major, "ubiblock");
-err_remove:
 	ubiblock_remove_all();
 	return ret;
 }
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 3405be4..ba01a8d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -923,7 +923,7 @@
 
 		/* Make sure ubi_num is not busy */
 		if (ubi_devices[ubi_num]) {
-			ubi_err(ubi, "ubi%d already exists", ubi_num);
+			ubi_err(ubi, "already exists");
 			return -EEXIST;
 		}
 	}
@@ -973,7 +973,7 @@
 	mutex_init(&ubi->fm_mutex);
 	init_rwsem(&ubi->fm_sem);
 
-	ubi_msg(ubi, "attaching mtd%d to ubi%d", mtd->index, ubi_num);
+	ubi_msg(ubi, "attaching mtd%d", mtd->index);
 
 	err = io_init(ubi, max_beb_per1024);
 	if (err)
@@ -1428,7 +1428,7 @@
 	}
 
 	if (len == 0) {
-		pr_err("UBI warning: empty 'mtd=' parameter - ignored\n");
+		pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n");
 		return 0;
 	}
 
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 3410ea81..d647e50 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -48,26 +48,25 @@
 
 /**
  * get_exclusive - get exclusive access to an UBI volume.
- * @ubi: UBI device description object
  * @desc: volume descriptor
  *
  * This function changes UBI volume open mode to "exclusive". Returns previous
  * mode value (positive integer) in case of success and a negative error code
  * in case of failure.
  */
-static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc)
+static int get_exclusive(struct ubi_volume_desc *desc)
 {
 	int users, err;
 	struct ubi_volume *vol = desc->vol;
 
 	spin_lock(&vol->ubi->volumes_lock);
-	users = vol->readers + vol->writers + vol->exclusive;
+	users = vol->readers + vol->writers + vol->exclusive + vol->metaonly;
 	ubi_assert(users > 0);
 	if (users > 1) {
-		ubi_err(ubi, "%d users for volume %d", users, vol->vol_id);
+		ubi_err(vol->ubi, "%d users for volume %d", users, vol->vol_id);
 		err = -EBUSY;
 	} else {
-		vol->readers = vol->writers = 0;
+		vol->readers = vol->writers = vol->metaonly = 0;
 		vol->exclusive = 1;
 		err = desc->mode;
 		desc->mode = UBI_EXCLUSIVE;
@@ -87,13 +86,15 @@
 	struct ubi_volume *vol = desc->vol;
 
 	spin_lock(&vol->ubi->volumes_lock);
-	ubi_assert(vol->readers == 0 && vol->writers == 0);
+	ubi_assert(vol->readers == 0 && vol->writers == 0 && vol->metaonly == 0);
 	ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
 	vol->exclusive = 0;
 	if (mode == UBI_READONLY)
 		vol->readers = 1;
 	else if (mode == UBI_READWRITE)
 		vol->writers = 1;
+	else if (mode == UBI_METAONLY)
+		vol->metaonly = 1;
 	else
 		vol->exclusive = 1;
 	spin_unlock(&vol->ubi->volumes_lock);
@@ -421,7 +422,7 @@
 			break;
 		}
 
-		err = get_exclusive(ubi, desc);
+		err = get_exclusive(desc);
 		if (err < 0)
 			break;
 
@@ -457,7 +458,7 @@
 		    req.bytes < 0 || req.lnum >= vol->usable_leb_size)
 			break;
 
-		err = get_exclusive(ubi, desc);
+		err = get_exclusive(desc);
 		if (err < 0)
 			break;
 
@@ -734,7 +735,7 @@
 			goto out_free;
 		}
 
-		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE);
+		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY);
 		if (IS_ERR(re->desc)) {
 			err = PTR_ERR(re->desc);
 			ubi_err(ubi, "cannot open volume %d, error %d",
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index a40020c..da4c792 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -426,6 +426,7 @@
 						 pnum, vol_id, lnum);
 					err = -EBADMSG;
 				} else
+					err = -EINVAL;
 					ubi_ro_mode(ubi);
 			}
 			goto out_free;
@@ -480,6 +481,61 @@
 }
 
 /**
+ * ubi_eba_read_leb_sg - read data into a scatter gather list.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @sgl: UBI scatter gather list to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * This function works exactly like ubi_eba_read_leb(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+			struct ubi_sgl *sgl, int lnum, int offset, int len,
+			int check)
+{
+	int to_read;
+	int ret;
+	struct scatterlist *sg;
+
+	for (;;) {
+		ubi_assert(sgl->list_pos < UBI_MAX_SG_COUNT);
+		sg = &sgl->sg[sgl->list_pos];
+		if (len < sg->length - sgl->page_pos)
+			to_read = len;
+		else
+			to_read = sg->length - sgl->page_pos;
+
+		ret = ubi_eba_read_leb(ubi, vol, lnum,
+				       sg_virt(sg) + sgl->page_pos, offset,
+				       to_read, check);
+		if (ret < 0)
+			return ret;
+
+		offset += to_read;
+		len -= to_read;
+		if (!len) {
+			sgl->page_pos += to_read;
+			if (sgl->page_pos == sg->length) {
+				sgl->list_pos++;
+				sgl->page_pos = 0;
+			}
+
+			break;
+		}
+
+		sgl->list_pos++;
+		sgl->page_pos = 0;
+	}
+
+	return ret;
+}
+
+/**
  * recover_peb - recover from write failure.
  * @ubi: UBI device description object
  * @pnum: the physical eraseblock to recover
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index b56672b..db3defd 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1196,6 +1196,19 @@
 		fm_pos += sizeof(*fec);
 		ubi_assert(fm_pos <= ubi->fm_size);
 	}
+
+	for (i = 0; i < UBI_PROT_QUEUE_LEN; i++) {
+		list_for_each_entry(wl_e, &ubi->pq[i], u.list) {
+			fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
+
+			fec->pnum = cpu_to_be32(wl_e->pnum);
+			fec->ec = cpu_to_be32(wl_e->ec);
+
+			used_peb_count++;
+			fm_pos += sizeof(*fec);
+			ubi_assert(fm_pos <= ubi->fm_size);
+		}
+	}
 	fmh->used_peb_count = cpu_to_be32(used_peb_count);
 
 	for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 396aaa5..ed0bcb3 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1419,8 +1419,7 @@
 
 fail:
 	ubi_err(ubi, "self-check failed for PEB %d", pnum);
-	ubi_msg(ubi, "hex dump of the %d-%d region",
-		 offset, offset + len);
+	ubi_msg(ubi, "hex dump of the %d-%d region", offset, offset + len);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
 	err = -EINVAL;
 error:
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index f3bab66..478e00c 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -137,7 +137,7 @@
 		return ERR_PTR(-EINVAL);
 
 	if (mode != UBI_READONLY && mode != UBI_READWRITE &&
-	    mode != UBI_EXCLUSIVE)
+	    mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)
 		return ERR_PTR(-EINVAL);
 
 	/*
@@ -182,10 +182,17 @@
 		break;
 
 	case UBI_EXCLUSIVE:
-		if (vol->exclusive || vol->writers || vol->readers)
+		if (vol->exclusive || vol->writers || vol->readers ||
+		    vol->metaonly)
 			goto out_unlock;
 		vol->exclusive = 1;
 		break;
+
+	case UBI_METAONLY:
+		if (vol->metaonly || vol->exclusive)
+			goto out_unlock;
+		vol->metaonly = 1;
+		break;
 	}
 	get_device(&vol->dev);
 	vol->ref_count += 1;
@@ -343,6 +350,10 @@
 		break;
 	case UBI_EXCLUSIVE:
 		vol->exclusive = 0;
+		break;
+	case UBI_METAONLY:
+		vol->metaonly = 0;
+		break;
 	}
 	vol->ref_count -= 1;
 	spin_unlock(&ubi->volumes_lock);
@@ -355,6 +366,43 @@
 EXPORT_SYMBOL_GPL(ubi_close_volume);
 
 /**
+ * leb_read_sanity_check - does sanity checks on read requests.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ *
+ * This function is used by ubi_leb_read() and ubi_leb_read_sg()
+ * to perform sanity checks.
+ */
+static int leb_read_sanity_check(struct ubi_volume_desc *desc, int lnum,
+				 int offset, int len)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int vol_id = vol->vol_id;
+
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
+	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||
+	    offset + len > vol->usable_leb_size)
+		return -EINVAL;
+
+	if (vol->vol_type == UBI_STATIC_VOLUME) {
+		if (vol->used_ebs == 0)
+			/* Empty static UBI volume */
+			return 0;
+		if (lnum == vol->used_ebs - 1 &&
+		    offset + len > vol->last_eb_bytes)
+			return -EINVAL;
+	}
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	return 0;
+}
+
+/**
  * ubi_leb_read - read data.
  * @desc: volume descriptor
  * @lnum: logical eraseblock number to read from
@@ -390,22 +438,10 @@
 
 	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
 
-	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
-	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||
-	    offset + len > vol->usable_leb_size)
-		return -EINVAL;
+	err = leb_read_sanity_check(desc, lnum, offset, len);
+	if (err < 0)
+		return err;
 
-	if (vol->vol_type == UBI_STATIC_VOLUME) {
-		if (vol->used_ebs == 0)
-			/* Empty static UBI volume */
-			return 0;
-		if (lnum == vol->used_ebs - 1 &&
-		    offset + len > vol->last_eb_bytes)
-			return -EINVAL;
-	}
-
-	if (vol->upd_marker)
-		return -EBADF;
 	if (len == 0)
 		return 0;
 
@@ -419,6 +455,46 @@
 }
 EXPORT_SYMBOL_GPL(ubi_leb_read);
 
+
+/**
+ * ubi_leb_read_sg - read data into a scatter gather list.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @buf: buffer where to store the read data
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ * @check: whether UBI has to check the read data's CRC or not.
+ *
+ * This function works exactly like ubi_leb_read_sg(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
+		    int offset, int len, int check)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int err, vol_id = vol->vol_id;
+
+	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+	err = leb_read_sanity_check(desc, lnum, offset, len);
+	if (err < 0)
+		return err;
+
+	if (len == 0)
+		return 0;
+
+	err = ubi_eba_read_leb_sg(ubi, vol, sgl, lnum, offset, len, check);
+	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
+		ubi_warn(ubi, "mark volume %d as corrupted", vol_id);
+		vol->corrupted = 1;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_leb_read_sg);
+
 /**
  * ubi_leb_write - write data.
  * @desc: volume descriptor
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index dbda77e..2a45ac2 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -74,6 +74,8 @@
 	for (i = 0; i < vol->used_ebs; i++) {
 		int size;
 
+		cond_resched();
+
 		if (i == vol->used_ebs - 1)
 			size = vol->last_eb_bytes;
 		else
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index f80ffab..c5be82d 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -50,13 +50,13 @@
 #define UBI_NAME_STR "ubi"
 
 /* Normal UBI messages */
-#define ubi_msg(ubi, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", \
-					 ubi->ubi_num, __func__, ##__VA_ARGS__)
+#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
+					 ubi->ubi_num, ##__VA_ARGS__)
 /* UBI warning messages */
-#define ubi_warn(ubi, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \
+#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
 					ubi->ubi_num, __func__, ##__VA_ARGS__)
 /* UBI error messages */
-#define ubi_err(ubi, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \
+#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
 				      ubi->ubi_num, __func__, ##__VA_ARGS__)
 
 /* Background thread name pattern */
@@ -261,6 +261,7 @@
  * @readers: number of users holding this volume in read-only mode
  * @writers: number of users holding this volume in read-write mode
  * @exclusive: whether somebody holds this volume in exclusive mode
+ * @metaonly: whether somebody is altering only meta data of this volume
  *
  * @reserved_pebs: how many physical eraseblocks are reserved for this volume
  * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
@@ -309,6 +310,7 @@
 	int readers;
 	int writers;
 	int exclusive;
+	int metaonly;
 
 	int reserved_pebs;
 	int vol_type;
@@ -339,7 +341,8 @@
 /**
  * struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
  * @vol: reference to the corresponding volume description object
- * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
+ * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, %UBI_EXCLUSIVE
+ * or %UBI_METAONLY)
  */
 struct ubi_volume_desc {
 	struct ubi_volume *vol;
@@ -390,7 +393,8 @@
  * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
  *                @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
  *                @vol->readers, @vol->writers, @vol->exclusive,
- *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ *                @vol->metaonly, @vol->ref_count, @vol->mapping and
+ *                @vol->eba_tbl.
  * @ref_count: count of references on the UBI device
  * @image_seq: image sequence number recorded on EC headers
  *
@@ -791,6 +795,9 @@
 		      int lnum);
 int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 		     void *buf, int offset, int len, int check);
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+			struct ubi_sgl *sgl, int lnum, int offset, int len,
+			int check);
 int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 		      const void *buf, int offset, int len);
 int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index f8fc308..68c9c5ea 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -655,14 +655,13 @@
 
 /**
  * check_av - check volume attaching information.
- * @ubi: UBI device description object
  * @vol: UBI volume description object
  * @av: volume attaching information
  *
  * This function returns zero if the volume attaching information is consistent
  * to the data read from the volume tabla, and %-EINVAL if not.
  */
-static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol,
+static int check_av(const struct ubi_volume *vol,
 		    const struct ubi_ainf_volume *av)
 {
 	int err;
@@ -690,7 +689,7 @@
 	return 0;
 
 bad:
-	ubi_err(ubi, "bad attaching information, error %d", err);
+	ubi_err(vol->ubi, "bad attaching information, error %d", err);
 	ubi_dump_av(av);
 	ubi_dump_vol_info(vol);
 	return -EINVAL;
@@ -753,7 +752,7 @@
 			ubi_msg(ubi, "finish volume %d removal", av->vol_id);
 			ubi_remove_av(ai, av);
 		} else if (av) {
-			err = check_av(ubi, vol, av);
+			err = check_av(vol, av);
 			if (err)
 				return err;
 		}
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 834f6fe..8f7bde6 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -470,11 +470,8 @@
 {
 	struct ubi_wl_entry *e = NULL;
 
-	if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) {
-		ubi_warn(ubi, "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d",
-			 anchor, ubi->free_count, ubi->beb_rsvd_pebs);
+	if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
 		goto out;
-	}
 
 	if (anchor)
 		e = find_anchor_wl_entry(&ubi->free);
@@ -1806,11 +1803,8 @@
 	for (;;) {
 		int err;
 
-		if (kthread_should_stop()) {
-			ubi_msg(ubi, "background thread \"%s\" should stop, PID %d",
-				ubi->bgt_name, task_pid_nr(current));
+		if (kthread_should_stop())
 			break;
-		}
 
 		if (try_to_freeze())
 			continue;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 932b93a..0a81685 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -26,7 +26,6 @@
 #include <net/vxlan.h>
 
 MODULE_VERSION(DRV_VER);
-MODULE_DEVICE_TABLE(pci, be_dev_ids);
 MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
 MODULE_AUTHOR("Emulex Corporation");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 049747f..bea8cd2 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -292,7 +292,6 @@
  */
 static bool network_cpus_init(void)
 {
-	char buf[1024];
 	int rc;
 
 	if (network_cpus_string == NULL)
@@ -314,8 +313,8 @@
 		return false;
 	}
 
-	cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
-	pr_info("Linux network CPUs: %s\n", buf);
+	pr_info("Linux network CPUs: %*pbl\n",
+		cpumask_pr_args(&network_cpus_map));
 	return true;
 }
 
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index fb12d31..3d8f60d 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -2410,9 +2410,8 @@
 		if (cpumask_empty(&network_cpus_map)) {
 			pr_warn("Ignoring network_cpus='%s'\n", str);
 		} else {
-			char buf[1024];
-			cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
-			pr_info("Linux network CPUs: %s\n", buf);
+			pr_info("Linux network CPUs: %*pbl\n",
+				cpumask_pr_args(&network_cpus_map));
 			network_cpus_used = true;
 		}
 	}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index 8cef1ed..dc79afd 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -291,26 +291,15 @@
 {
 	struct ath9k_htc_priv *priv = file->private_data;
 	char buf[512];
-	unsigned int len = 0;
+	unsigned int len;
 
 	spin_lock_bh(&priv->tx.tx_lock);
-
-	len += scnprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
-
-	len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
-			       priv->tx.tx_slot, MAX_TX_BUF_NUM);
-
-	len += scnprintf(buf + len, sizeof(buf) - len, "\n");
-
-	len += scnprintf(buf + len, sizeof(buf) - len,
-			 "Used slots     : %d\n",
-			 bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
-
+	len = scnprintf(buf, sizeof(buf),
+			"TX slot bitmap : %*pb\n"
+			"Used slots     : %d\n",
+			MAX_TX_BUF_NUM, priv->tx.tx_slot,
+			bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
 	spin_unlock_bh(&priv->tx.tx_lock);
-
-	if (len > sizeof(buf))
-		len = sizeof(buf);
-
 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 1c0af9c..6808db4 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -214,14 +214,10 @@
 static char *carl9170_debugfs_mem_usage_read(struct ar9170 *ar, char *buf,
 					     size_t bufsize, ssize_t *len)
 {
-	ADD(buf, *len, bufsize, "jar: [");
-
 	spin_lock_bh(&ar->mem_lock);
 
-	*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
-				  ar->mem_bitmap, ar->fw.mem_blocks);
-
-	ADD(buf, *len, bufsize, "]\n");
+	ADD(buf, *len, bufsize, "jar: [%*pb]\n",
+	    ar->fw.mem_blocks, ar->mem_bitmap);
 
 	ADD(buf, *len, bufsize, "cookies: used:%3d / total:%3d, allocs:%d\n",
 	    bitmap_weight(ar->mem_bitmap, ar->fw.mem_blocks),
@@ -316,17 +312,13 @@
 		    cnt, iter->tid, iter->bsn, iter->snx, iter->hsn,
 		    iter->max, iter->state, iter->counter);
 
-		ADD(buf, *len, bufsize, "\tWindow:  [");
-
-		*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
-			iter->bitmap, CARL9170_BAW_BITS);
+		ADD(buf, *len, bufsize, "\tWindow:  [%*pb,W]\n",
+		    CARL9170_BAW_BITS, iter->bitmap);
 
 #define BM_STR_OFF(offset)					\
 	((CARL9170_BAW_BITS - (offset) - 1) / 4 +		\
 	 (CARL9170_BAW_BITS - (offset) - 1) / 32 + 1)
 
-		ADD(buf, *len, bufsize, ",W]\n");
-
 		offset = BM_STR_OFF(0);
 		ADD(buf, *len, bufsize, "\tBase Seq: %*s\n", offset, "T");
 
@@ -448,12 +440,8 @@
 	ADD(buf, *len, bufsize, "registered VIFs:%d \\ %d\n",
 	    ar->vifs, ar->fw.vif_num);
 
-	ADD(buf, *len, bufsize, "VIF bitmap: [");
-
-	*len += bitmap_scnprintf(&buf[*len], bufsize - *len,
-				 &ar->vif_bitmap, ar->fw.vif_num);
-
-	ADD(buf, *len, bufsize, "]\n");
+	ADD(buf, *len, bufsize, "VIF bitmap: [%*pb]\n",
+	    ar->fw.vif_num, &ar->vif_bitmap);
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(iter, &ar->vif_list, list) {
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b0d50d7..b189733 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -526,6 +526,7 @@
 		amba_device_unregister(to_amba_device(dev));
 #endif
 
+	of_dma_deconfigure(dev);
 	of_node_clear_flag(dev->of_node, OF_POPULATED);
 	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
 	return 0;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 910e90b..3bb4925 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -69,7 +69,8 @@
 	tristate "CardBus yenta-compatible bridge support"
 	depends on PCI
 	select CARDBUS if !EXPERT
-	select PCCARD_NONSTATIC if PCMCIA != n
+	select PCCARD_NONSTATIC if PCMCIA != n && ISA
+	select PCCARD_PCI if PCMCIA !=n && !ISA
 	---help---
 	  This option enables support for CardBus host bridges.  Virtually
 	  all modern PCMCIA bridges are CardBus compatible.  A "bridge" is
@@ -109,7 +110,8 @@
 config PD6729
 	tristate "Cirrus PD6729 compatible bridge support"
 	depends on PCMCIA && PCI
-	select PCCARD_NONSTATIC
+	select PCCARD_NONSTATIC if PCMCIA != n && ISA
+	select PCCARD_PCI if PCMCIA !=n && !ISA
 	help
 	  This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
 	  device, found in some older laptops and PCMCIA card readers.
@@ -117,7 +119,8 @@
 config I82092
 	tristate "i82092 compatible bridge support"
 	depends on PCMCIA && PCI
-	select PCCARD_NONSTATIC
+	select PCCARD_NONSTATIC if PCMCIA != n && ISA
+	select PCCARD_PCI if PCMCIA !=n && !ISA
 	help
 	  This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
 	  found in some older laptops and more commonly in evaluation boards for the
@@ -276,6 +279,7 @@
 config AT91_CF
 	tristate "AT91 CompactFlash Controller"
 	depends on PCMCIA && ARCH_AT91
+	depends on !ARCH_MULTIPLATFORM
 	help
 	  Say Y here to support the CompactFlash controller on AT91 chips.
 	  Or choose M to compile the driver as a module named "at91_cf".
@@ -287,6 +291,9 @@
 	  Say Y here to support the CompactFlash controller on the
 	  PA Semi Electra eval board.
 
+config PCCARD_PCI
+	bool
+
 config PCCARD_NONSTATIC
 	bool
 
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 27e94b3..f1a7ca0 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -12,6 +12,7 @@
 pcmcia_rsrc-y					+= rsrc_mgr.o
 pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC)		+= rsrc_nonstatic.o
 pcmcia_rsrc-$(CONFIG_PCCARD_IODYN)		+= rsrc_iodyn.o
+pcmcia_rsrc-$(CONFIG_PCCARD_PCI)		+= rsrc_pci.o
 obj-$(CONFIG_PCCARD)				+= pcmcia_rsrc.o
 
 
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 884a984..64d0515 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -168,9 +168,12 @@
 	} else {
 		u_int inc = 1, card_offset, flags;
 
-		if (addr > CISTPL_MAX_CIS_SIZE)
+		if (addr > CISTPL_MAX_CIS_SIZE) {
 			dev_dbg(&s->dev,
 				"attempt to read CIS mem at addr %#x", addr);
+			memset(ptr, 0xff, len);
+			return -1;
+		}
 
 		flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 		if (attr) {
@@ -1383,7 +1386,7 @@
 	if (!s)
 		return -EINVAL;
 
-	if (s->functions) {
+	if (s->functions || !(s->state & SOCKET_PRESENT)) {
 		WARN_ON(1);
 		return -EINVAL;
 	}
@@ -1448,10 +1451,26 @@
 done:
 	/* invalidate CIS cache on failure */
 	if (!dev_ok || !ident_ok || !count) {
-		mutex_lock(&s->ops_mutex);
-		destroy_cis_cache(s);
-		mutex_unlock(&s->ops_mutex);
-		ret = -EIO;
+#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
+		/* Set up as an anonymous card. If we don't have anonymous
+		   memory support then just error the card as there is no
+		   point trying to second guess.
+
+		   Note: some cards have just a device entry, it may be
+		   worth extending support to cover these in future */
+		if (!dev_ok || !ident_ok) {
+			dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
+			pcmcia_replace_cis(s, "\xFF", 1);
+			count = 1;
+			ret = 0;
+		} else
+#endif
+		{
+			mutex_lock(&s->ops_mutex);
+			destroy_cis_cache(s);
+			mutex_unlock(&s->ops_mutex);
+			ret = -EIO;
+		}
 	}
 
 	if (info)
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 7f1953f..e86cd6b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -80,9 +80,9 @@
  * Stuff internal to module "pcmcia_rsrc":
  */
 extern int static_init(struct pcmcia_socket *s);
-extern struct resource *pcmcia_make_resource(unsigned long start,
-					unsigned long end,
-					int flags, const char *name);
+extern struct resource *pcmcia_make_resource(resource_size_t start,
+					resource_size_t end,
+					unsigned long flags, const char *name);
 
 /*
  * Stuff internal to module "pcmcia_core":
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 757119b..d3baf0b 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -667,6 +667,9 @@
 {
 	int has_pfc;
 
+	if (!(s->state & SOCKET_PRESENT))
+		return;
+
 	if (s->functions == 0) {
 		pcmcia_card_add(s);
 		return;
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index aa628ed..df2cb70 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -30,8 +30,9 @@
 	return 0;
 }
 
-struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
-				int flags, const char *name)
+struct resource *pcmcia_make_resource(resource_size_t start,
+					resource_size_t end,
+					unsigned long flags, const char *name)
 {
 	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
 
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
new file mode 100644
index 0000000..1f67b3b
--- /dev/null
+++ b/drivers/pcmcia/rsrc_pci.c
@@ -0,0 +1,173 @@
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+
+struct pcmcia_align_data {
+	unsigned long	mask;
+	unsigned long	offset;
+};
+
+static resource_size_t pcmcia_align(void *align_data,
+				const struct resource *res,
+				resource_size_t size, resource_size_t align)
+{
+	struct pcmcia_align_data *data = align_data;
+	resource_size_t start;
+
+	start = (res->start & ~data->mask) + data->offset;
+	if (start < res->start)
+		start += data->mask + 1;
+	return start;
+}
+
+static struct resource *find_io_region(struct pcmcia_socket *s,
+					unsigned long base, int num,
+					unsigned long align)
+{
+	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
+						dev_name(&s->dev));
+	struct pcmcia_align_data data;
+	int ret;
+
+	data.mask = align - 1;
+	data.offset = base & data.mask;
+
+	ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
+					     base, 0, pcmcia_align, &data);
+	if (ret != 0) {
+		kfree(res);
+		res = NULL;
+	}
+	return res;
+}
+
+static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
+			unsigned int *base, unsigned int num,
+			unsigned int align, struct resource **parent)
+{
+	int i, ret = 0;
+
+	/* Check for an already-allocated window that must conflict with
+	 * what was asked for.  It is a hack because it does not catch all
+	 * potential conflicts, just the most obvious ones.
+	 */
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		if (!s->io[i].res)
+			continue;
+
+		if (!*base)
+			continue;
+
+		if ((s->io[i].res->start & (align-1)) == *base)
+			return -EBUSY;
+	}
+
+	for (i = 0; i < MAX_IO_WIN; i++) {
+		struct resource *res = s->io[i].res;
+		unsigned int try;
+
+		if (res && (res->flags & IORESOURCE_BITS) !=
+			(attr & IORESOURCE_BITS))
+			continue;
+
+		if (!res) {
+			if (align == 0)
+				align = 0x10000;
+
+			res = s->io[i].res = find_io_region(s, *base, num,
+								align);
+			if (!res)
+				return -EINVAL;
+
+			*base = res->start;
+			s->io[i].res->flags =
+				((res->flags & ~IORESOURCE_BITS) |
+					(attr & IORESOURCE_BITS));
+			s->io[i].InUse = num;
+			*parent = res;
+			return 0;
+		}
+
+		/* Try to extend top of window */
+		try = res->end + 1;
+		if ((*base == 0) || (*base == try)) {
+			ret = adjust_resource(s->io[i].res, res->start,
+					      resource_size(res) + num);
+			if (ret)
+				continue;
+			*base = try;
+			s->io[i].InUse += num;
+			*parent = res;
+			return 0;
+		}
+
+		/* Try to extend bottom of window */
+		try = res->start - num;
+		if ((*base == 0) || (*base == try)) {
+			ret = adjust_resource(s->io[i].res,
+					      res->start - num,
+					      resource_size(res) + num);
+			if (ret)
+				continue;
+			*base = try;
+			s->io[i].InUse += num;
+			*parent = res;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static struct resource *res_pci_find_mem(u_long base, u_long num,
+		u_long align, int low, struct pcmcia_socket *s)
+{
+	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
+						dev_name(&s->dev));
+	struct pcmcia_align_data data;
+	unsigned long min;
+	int ret;
+
+	if (align < 0x20000)
+		align = 0x20000;
+	data.mask = align - 1;
+	data.offset = base & data.mask;
+
+	min = 0;
+	if (!low)
+		min = 0x100000UL;
+
+	ret = pci_bus_alloc_resource(s->cb_dev->bus,
+			res, num, 1, min, 0,
+			pcmcia_align, &data);
+
+	if (ret != 0) {
+		kfree(res);
+		res = NULL;
+	}
+	return res;
+}
+
+
+static int res_pci_init(struct pcmcia_socket *s)
+{
+	if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
+		dev_err(&s->dev, "not supported by res_pci\n");
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+struct pccard_resource_ops pccard_nonstatic_ops = {
+	.validate_mem = NULL,
+	.find_io = res_pci_find_io,
+	.find_mem = res_pci_find_mem,
+	.init = res_pci_init,
+	.exit = NULL,
+};
+EXPORT_SYMBOL(pccard_nonstatic_ops);
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 26a7623..2962de2 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -239,6 +239,13 @@
 	depends on OF
 	select GENERIC_PHY
 
+config PHY_ROCKCHIP_USB
+	tristate "Rockchip USB2 PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	help
+	  Enable this to support the Rockchip USB 2.0 PHY.
+
 config PHY_ST_SPEAR1310_MIPHY
 	tristate "ST SPEAR1310-MIPHY driver"
 	select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index cfbb720..f080e1b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -28,6 +28,7 @@
 phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
+obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c
index ac7d99d..7c99ca2 100644
--- a/drivers/phy/phy-armada375-usb2.c
+++ b/drivers/phy/phy-armada375-usb2.c
@@ -118,8 +118,8 @@
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
-	if (!usb_cluster_base)
-		return -ENOMEM;
+	if (IS_ERR(usb_cluster_base))
+		return PTR_ERR(usb_cluster_base);
 
 	phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
 	if (IS_ERR(phy)) {
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index 943e0f8..f017b2f 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -12,19 +12,18 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/mfd/syscon/exynos4-pmu.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
 
-/* MIPI_PHYn_CONTROL register offset: n = 0..1 */
+/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
 #define EXYNOS_MIPI_PHY_CONTROL(n)	((n) * 4)
-#define EXYNOS_MIPI_PHY_ENABLE		(1 << 0)
-#define EXYNOS_MIPI_PHY_SRESETN		(1 << 1)
-#define EXYNOS_MIPI_PHY_MRESETN		(1 << 2)
-#define EXYNOS_MIPI_PHY_RESET_MASK	(3 << 1)
 
 enum exynos_mipi_phy_id {
 	EXYNOS_MIPI_PHY_ID_CSIS0,
@@ -38,43 +37,62 @@
 	((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
 
 struct exynos_mipi_video_phy {
-	spinlock_t slock;
 	struct video_phy_desc {
 		struct phy *phy;
 		unsigned int index;
 	} phys[EXYNOS_MIPI_PHYS_NUM];
+	spinlock_t slock;
 	void __iomem *regs;
+	struct mutex mutex;
+	struct regmap *regmap;
 };
 
 static int __set_phy_state(struct exynos_mipi_video_phy *state,
 			enum exynos_mipi_phy_id id, unsigned int on)
 {
+	const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
 	void __iomem *addr;
-	u32 reg, reset;
-
-	addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
+	u32 val, reset;
 
 	if (is_mipi_dsim_phy_id(id))
-		reset = EXYNOS_MIPI_PHY_MRESETN;
+		reset = EXYNOS4_MIPI_PHY_MRESETN;
 	else
-		reset = EXYNOS_MIPI_PHY_SRESETN;
+		reset = EXYNOS4_MIPI_PHY_SRESETN;
 
-	spin_lock(&state->slock);
-	reg = readl(addr);
-	if (on)
-		reg |= reset;
-	else
-		reg &= ~reset;
-	writel(reg, addr);
+	if (state->regmap) {
+		mutex_lock(&state->mutex);
+		regmap_read(state->regmap, offset, &val);
+		if (on)
+			val |= reset;
+		else
+			val &= ~reset;
+		regmap_write(state->regmap, offset, val);
+		if (on)
+			val |= EXYNOS4_MIPI_PHY_ENABLE;
+		else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
+			val &= ~EXYNOS4_MIPI_PHY_ENABLE;
+		regmap_write(state->regmap, offset, val);
+		mutex_unlock(&state->mutex);
+	} else {
+		addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
 
-	/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set. */
-	if (on)
-		reg |= EXYNOS_MIPI_PHY_ENABLE;
-	else if (!(reg & EXYNOS_MIPI_PHY_RESET_MASK))
-		reg &= ~EXYNOS_MIPI_PHY_ENABLE;
+		spin_lock(&state->slock);
+		val = readl(addr);
+		if (on)
+			val |= reset;
+		else
+			val &= ~reset;
+		writel(val, addr);
+		/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */
+		if (on)
+			val |= EXYNOS4_MIPI_PHY_ENABLE;
+		else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
+			val &= ~EXYNOS4_MIPI_PHY_ENABLE;
 
-	writel(reg, addr);
-	spin_unlock(&state->slock);
+		writel(val, addr);
+		spin_unlock(&state->slock);
+	}
+
 	return 0;
 }
 
@@ -118,7 +136,6 @@
 {
 	struct exynos_mipi_video_phy *state;
 	struct device *dev = &pdev->dev;
-	struct resource *res;
 	struct phy_provider *phy_provider;
 	unsigned int i;
 
@@ -126,14 +143,22 @@
 	if (!state)
 		return -ENOMEM;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+	if (IS_ERR(state->regmap)) {
+		struct resource *res;
 
-	state->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(state->regs))
-		return PTR_ERR(state->regs);
+		dev_info(dev, "regmap lookup failed: %ld\n",
+			 PTR_ERR(state->regmap));
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		state->regs = devm_ioremap_resource(dev, res);
+		if (IS_ERR(state->regs))
+			return PTR_ERR(state->regs);
+	}
 
 	dev_set_drvdata(dev, state);
 	spin_lock_init(&state->slock);
+	mutex_init(&state->mutex);
 
 	for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
 		struct phy *phy = devm_phy_create(dev, NULL,
diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c
index 27fa62c..9b2848e 100644
--- a/drivers/phy/phy-miphy28lp.c
+++ b/drivers/phy/phy-miphy28lp.c
@@ -194,6 +194,14 @@
 #define MIPHY_SATA_BANK_NB	3
 #define MIPHY_PCIE_BANK_NB	2
 
+enum {
+	SYSCFG_CTRL,
+	SYSCFG_STATUS,
+	SYSCFG_PCI,
+	SYSCFG_SATA,
+	SYSCFG_REG_MAX,
+};
+
 struct miphy28lp_phy {
 	struct phy *phy;
 	struct miphy28lp_dev *phydev;
@@ -211,10 +219,7 @@
 	u32 sata_gen;
 
 	/* Sysconfig registers offsets needed to configure the device */
-	u32 syscfg_miphy_ctrl;
-	u32 syscfg_miphy_status;
-	u32 syscfg_pci;
-	u32 syscfg_sata;
+	u32 syscfg_reg[SYSCFG_REG_MAX];
 	u8 type;
 };
 
@@ -834,12 +839,12 @@
 	if (!miphy_phy->osc_rdy)
 		return 0;
 
-	if (!miphy_phy->syscfg_miphy_status)
+	if (!miphy_phy->syscfg_reg[SYSCFG_STATUS])
 		return -EINVAL;
 
 	do {
-		regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status,
-			    &val);
+		regmap_read(miphy_dev->regmap,
+				miphy_phy->syscfg_reg[SYSCFG_STATUS], &val);
 
 		if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
 			cpu_relax();
@@ -888,7 +893,7 @@
 	int err;
 	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 
-	if (!miphy_phy->syscfg_miphy_ctrl)
+	if (!miphy_phy->syscfg_reg[SYSCFG_CTRL])
 		return -EINVAL;
 
 	err = reset_control_assert(miphy_phy->miphy_rst);
@@ -900,7 +905,8 @@
 	if (miphy_phy->osc_force_ext)
 		miphy_val |= MIPHY_OSC_FORCE_EXT;
 
-	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl,
+	regmap_update_bits(miphy_dev->regmap,
+			   miphy_phy->syscfg_reg[SYSCFG_CTRL],
 			   MIPHY_CTRL_MASK, miphy_val);
 
 	err = reset_control_deassert(miphy_phy->miphy_rst);
@@ -917,8 +923,9 @@
 	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 	int err, sata_conf = SATA_CTRL_SELECT_SATA;
 
-	if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
-		|| (!miphy_phy->base))
+	if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
+			(!miphy_phy->syscfg_reg[SYSCFG_PCI]) ||
+			(!miphy_phy->base))
 		return -EINVAL;
 
 	dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
@@ -926,10 +933,11 @@
 	/* Configure the glue-logic */
 	sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
 
-	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+	regmap_update_bits(miphy_dev->regmap,
+			   miphy_phy->syscfg_reg[SYSCFG_SATA],
 			   SATA_CTRL_MASK, sata_conf);
 
-	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
 			   PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 
 	/* MiPHY path and clocking init */
@@ -951,17 +959,19 @@
 	struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
 	int err;
 
-	if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
+	if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
+			(!miphy_phy->syscfg_reg[SYSCFG_PCI])
 		|| (!miphy_phy->base) || (!miphy_phy->pipebase))
 		return -EINVAL;
 
 	dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
 
 	/* Configure the glue-logic */
-	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+	regmap_update_bits(miphy_dev->regmap,
+			   miphy_phy->syscfg_reg[SYSCFG_SATA],
 			   SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
 
-	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+	regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
 			   PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
 
 	/* MiPHY path and clocking init */
@@ -1156,7 +1166,8 @@
 static int miphy28lp_of_probe(struct device_node *np,
 			      struct miphy28lp_phy *miphy_phy)
 {
-	struct resource res;
+	int i;
+	u32 ctrlreg;
 
 	miphy_phy->osc_force_ext =
 		of_property_read_bool(np, "st,osc-force-ext");
@@ -1175,18 +1186,10 @@
 	if (!miphy_phy->sata_gen)
 		miphy_phy->sata_gen = SATA_GEN1;
 
-	if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res))
-		miphy_phy->syscfg_miphy_ctrl = res.start;
-
-	if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res))
-		miphy_phy->syscfg_miphy_status = res.start;
-
-	if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res))
-		miphy_phy->syscfg_pci = res.start;
-
-	if (!miphy28lp_get_resource_byname(np, "sata-glue", &res))
-		miphy_phy->syscfg_sata = res.start;
-
+	for (i = 0; i < SYSCFG_REG_MAX; i++) {
+		if (!of_property_read_u32_index(np, "st,syscfg", i, &ctrlreg))
+			miphy_phy->syscfg_reg[i] = ctrlreg;
+	}
 
 	return 0;
 }
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
new file mode 100644
index 0000000..22011c3
--- /dev/null
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -0,0 +1,158 @@
+/*
+ * Rockchip usb PHY driver
+ *
+ * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
+ * Copyright (C) 2014 ROCKCHIP, 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.
+ *
+ * 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/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+/*
+ * The higher 16-bit of this register is used for write protection
+ * only if BIT(13 + 16) set to 1 the BIT(13) can be written.
+ */
+#define SIDDQ_WRITE_ENA	BIT(29)
+#define SIDDQ_ON		BIT(13)
+#define SIDDQ_OFF		(0 << 13)
+
+struct rockchip_usb_phy {
+	unsigned int	reg_offset;
+	struct regmap	*reg_base;
+	struct clk	*clk;
+	struct phy	*phy;
+};
+
+static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
+					   bool siddq)
+{
+	return regmap_write(phy->reg_base, phy->reg_offset,
+			    SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
+}
+
+static int rockchip_usb_phy_power_off(struct phy *_phy)
+{
+	struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+	int ret = 0;
+
+	/* Power down usb phy analog blocks by set siddq 1 */
+	ret = rockchip_usb_phy_power(phy, 1);
+	if (ret)
+		return ret;
+
+	clk_disable_unprepare(phy->clk);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rockchip_usb_phy_power_on(struct phy *_phy)
+{
+	struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+	int ret = 0;
+
+	ret = clk_prepare_enable(phy->clk);
+	if (ret)
+		return ret;
+
+	/* Power up usb phy analog blocks by set siddq 0 */
+	ret = rockchip_usb_phy_power(phy, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct phy_ops ops = {
+	.power_on	= rockchip_usb_phy_power_on,
+	.power_off	= rockchip_usb_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static int rockchip_usb_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_usb_phy *rk_phy;
+	struct phy_provider *phy_provider;
+	struct device_node *child;
+	struct regmap *grf;
+	unsigned int reg_offset;
+
+	grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+	if (IS_ERR(grf)) {
+		dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+		return PTR_ERR(grf);
+	}
+
+	for_each_available_child_of_node(dev->of_node, child) {
+		rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
+		if (!rk_phy)
+			return -ENOMEM;
+
+		if (of_property_read_u32(child, "reg", &reg_offset)) {
+			dev_err(dev, "missing reg property in node %s\n",
+				child->name);
+			return -EINVAL;
+		}
+
+		rk_phy->reg_offset = reg_offset;
+		rk_phy->reg_base = grf;
+
+		rk_phy->clk = of_clk_get_by_name(child, "phyclk");
+		if (IS_ERR(rk_phy->clk))
+			rk_phy->clk = NULL;
+
+		rk_phy->phy = devm_phy_create(dev, child, &ops);
+		if (IS_ERR(rk_phy->phy)) {
+			dev_err(dev, "failed to create PHY\n");
+			return PTR_ERR(rk_phy->phy);
+		}
+		phy_set_drvdata(rk_phy->phy, rk_phy);
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
+	{ .compatible = "rockchip,rk3288-usb-phy" },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
+
+static struct platform_driver rockchip_usb_driver = {
+	.probe		= rockchip_usb_phy_probe,
+	.driver		= {
+		.name	= "rockchip-usb-phy",
+		.owner	= THIS_MODULE,
+		.of_match_table = rockchip_usb_phy_dt_ids,
+	},
+};
+
+module_platform_driver(rockchip_usb_driver);
+
+MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 465de2c..95c88f9 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
+#include <linux/spinlock.h>
 
 #define	PLL_STATUS		0x00000004
 #define	PLL_GO			0x00000008
@@ -82,6 +83,10 @@
 	struct clk		*refclk;
 	struct clk		*div_clk;
 	struct pipe3_dpll_map	*dpll_map;
+	bool			enabled;
+	spinlock_t		lock;	/* serialize clock enable/disable */
+	/* the below flag is needed specifically for SATA */
+	bool			refclk_enabled;
 };
 
 static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -307,6 +312,7 @@
 		return -ENOMEM;
 
 	phy->dev		= &pdev->dev;
+	spin_lock_init(&phy->lock);
 
 	if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
 		match = of_match_device(of_match_ptr(ti_pipe3_id_table),
@@ -333,21 +339,24 @@
 		}
 	}
 
+	phy->refclk = devm_clk_get(phy->dev, "refclk");
+	if (IS_ERR(phy->refclk)) {
+		dev_err(&pdev->dev, "unable to get refclk\n");
+		/* older DTBs have missing refclk in SATA PHY
+		 * so don't bail out in case of SATA PHY.
+		 */
+		if (!of_device_is_compatible(node, "ti,phy-pipe3-sata"))
+			return PTR_ERR(phy->refclk);
+	}
+
 	if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
 		phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
 		if (IS_ERR(phy->wkupclk)) {
 			dev_err(&pdev->dev, "unable to get wkupclk\n");
 			return PTR_ERR(phy->wkupclk);
 		}
-
-		phy->refclk = devm_clk_get(phy->dev, "refclk");
-		if (IS_ERR(phy->refclk)) {
-			dev_err(&pdev->dev, "unable to get refclk\n");
-			return PTR_ERR(phy->refclk);
-		}
 	} else {
 		phy->wkupclk = ERR_PTR(-ENODEV);
-		phy->refclk = ERR_PTR(-ENODEV);
 	}
 
 	if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -426,33 +435,42 @@
 }
 
 #ifdef CONFIG_PM
-
-static int ti_pipe3_runtime_suspend(struct device *dev)
+static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
 {
-	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+	if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
+		int ret;
 
-	if (!IS_ERR(phy->wkupclk))
-		clk_disable_unprepare(phy->wkupclk);
-	if (!IS_ERR(phy->refclk))
-		clk_disable_unprepare(phy->refclk);
-	if (!IS_ERR(phy->div_clk))
-		clk_disable_unprepare(phy->div_clk);
+		ret = clk_prepare_enable(phy->refclk);
+		if (ret) {
+			dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
+			return ret;
+		}
+		phy->refclk_enabled = true;
+	}
 
 	return 0;
 }
 
-static int ti_pipe3_runtime_resume(struct device *dev)
+static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
 {
-	u32 ret = 0;
-	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+	if (!IS_ERR(phy->refclk))
+		clk_disable_unprepare(phy->refclk);
 
-	if (!IS_ERR(phy->refclk)) {
-		ret = clk_prepare_enable(phy->refclk);
-		if (ret) {
-			dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
-			goto err1;
-		}
-	}
+	phy->refclk_enabled = false;
+}
+
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&phy->lock, flags);
+	if (phy->enabled)
+		goto err1;
+
+	ret = ti_pipe3_enable_refclk(phy);
+	if (ret)
+		goto err1;
 
 	if (!IS_ERR(phy->wkupclk)) {
 		ret = clk_prepare_enable(phy->wkupclk);
@@ -469,6 +487,9 @@
 			goto err3;
 		}
 	}
+
+	phy->enabled = true;
+	spin_unlock_irqrestore(&phy->lock, flags);
 	return 0;
 
 err3:
@@ -479,20 +500,80 @@
 	if (!IS_ERR(phy->refclk))
 		clk_disable_unprepare(phy->refclk);
 
+	ti_pipe3_disable_refclk(phy);
 err1:
+	spin_unlock_irqrestore(&phy->lock, flags);
 	return ret;
 }
 
+static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&phy->lock, flags);
+	if (!phy->enabled) {
+		spin_unlock_irqrestore(&phy->lock, flags);
+		return;
+	}
+
+	if (!IS_ERR(phy->wkupclk))
+		clk_disable_unprepare(phy->wkupclk);
+	/* Don't disable refclk for SATA PHY due to Errata i783 */
+	if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+		ti_pipe3_disable_refclk(phy);
+	if (!IS_ERR(phy->div_clk))
+		clk_disable_unprepare(phy->div_clk);
+	phy->enabled = false;
+	spin_unlock_irqrestore(&phy->lock, flags);
+}
+
+static int ti_pipe3_runtime_suspend(struct device *dev)
+{
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+
+	ti_pipe3_disable_clocks(phy);
+	return 0;
+}
+
+static int ti_pipe3_runtime_resume(struct device *dev)
+{
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+	int ret = 0;
+
+	ret = ti_pipe3_enable_clocks(phy);
+	return ret;
+}
+
+static int ti_pipe3_suspend(struct device *dev)
+{
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+
+	ti_pipe3_disable_clocks(phy);
+	return 0;
+}
+
+static int ti_pipe3_resume(struct device *dev)
+{
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
+	int ret;
+
+	ret = ti_pipe3_enable_clocks(phy);
+	if (ret)
+		return ret;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	return 0;
+}
+#endif
+
 static const struct dev_pm_ops ti_pipe3_pm_ops = {
 	SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
 			   ti_pipe3_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
 };
 
-#define DEV_PM_OPS     (&ti_pipe3_pm_ops)
-#else
-#define DEV_PM_OPS     NULL
-#endif
-
 #ifdef CONFIG_OF
 static const struct of_device_id ti_pipe3_id_table[] = {
 	{
@@ -520,7 +601,7 @@
 	.remove		= ti_pipe3_remove,
 	.driver		= {
 		.name	= "ti-pipe3",
-		.pm	= DEV_PM_OPS,
+		.pm	= &ti_pipe3_pm_ops,
 		.of_match_table = of_match_ptr(ti_pipe3_id_table),
 	},
 };
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index f748cc8..4e57d33 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -182,7 +182,7 @@
 			return error;
 	}
 
-	if (pnp_dev->protocol->suspend)
+	if (pnp_can_suspend(pnp_dev))
 		pnp_dev->protocol->suspend(pnp_dev, state);
 	return 0;
 }
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 074569e..facd43b 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -181,7 +181,8 @@
 			break;
 		default:
 			pnpbios_print_status("pnp_dock_thread", status);
-			continue;
+			printk(KERN_WARNING "PnPBIOS: disabling dock monitoring.\n");
+			complete_and_exit(&unload_sem, 0);
 		}
 		if (d != docked) {
 			if (pnp_dock_event(d, &now) == 0) {
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f15cddf..cedb41c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -153,6 +153,17 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-88pm80x.
 
+config RTC_DRV_ABB5ZES3
+       depends on I2C
+       select REGMAP_I2C
+       tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
+       help
+	  If you say yes here you get support for the Abracon
+	  AB-RTCMC-32.768kHz-B5ZE-S3 I2C RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ab-b5ze-s3.
+
 config RTC_DRV_AS3722
 	tristate "ams AS3722 RTC driver"
 	depends on MFD_AS3722
@@ -790,6 +801,96 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1553.
 
+config RTC_DRV_DS1685_FAMILY
+	tristate "Dallas/Maxim DS1685 Family"
+	help
+	  If you say yes here you get support for the Dallas/Maxim DS1685
+	  family of real time chips.  This family includes the DS1685/DS1687,
+	  DS1689/DS1693, DS17285/DS17287, DS17485/DS17487, and
+	  DS17885/DS17887 chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1685.
+
+choice
+	prompt "Subtype"
+	depends on RTC_DRV_DS1685_FAMILY
+	default RTC_DRV_DS1685
+
+config RTC_DRV_DS1685
+	bool "DS1685/DS1687"
+	help
+	  This enables support for the Dallas/Maxim DS1685/DS1687 real time
+	  clock chip.
+
+	  This chip is commonly found in SGI O2 (IP32) and SGI Octane (IP30)
+	  systems, as well as EPPC-405-UC modules by electronic system design
+	  GmbH.
+
+config RTC_DRV_DS1689
+	bool "DS1689/DS1693"
+	help
+	  This enables support for the Dallas/Maxim DS1689/DS1693 real time
+	  clock chip.
+
+	  This is an older RTC chip, supplanted by the DS1685/DS1687 above,
+	  which supports a few minor features such as Vcc, Vbat, and Power
+	  Cycle counters, plus a customer-specific, 8-byte ROM/Serial number.
+
+	  It also works for the even older DS1688/DS1691 RTC chips, which are
+	  virtually the same and carry the same model number.  Both chips
+	  have 114 bytes of user NVRAM.
+
+config RTC_DRV_DS17285
+	bool "DS17285/DS17287"
+	help
+	  This enables support for the Dallas/Maxim DS17285/DS17287 real time
+	  clock chip.
+
+	  This chip features 2kb of extended NV-SRAM.  It may possibly be
+	  found in some SGI O2 systems (rare).
+
+config RTC_DRV_DS17485
+	bool "DS17485/DS17487"
+	help
+	  This enables support for the Dallas/Maxim DS17485/DS17487 real time
+	  clock chip.
+
+	  This chip features 4kb of extended NV-SRAM.
+
+config RTC_DRV_DS17885
+	bool "DS17885/DS17887"
+	help
+	  This enables support for the Dallas/Maxim DS17885/DS17887 real time
+	  clock chip.
+
+	  This chip features 8kb of extended NV-SRAM.
+
+endchoice
+
+config RTC_DS1685_PROC_REGS
+	bool "Display register values in /proc"
+	depends on RTC_DRV_DS1685_FAMILY && PROC_FS
+	help
+	  Enable this to display a readout of all of the RTC registers in
+	  /proc/drivers/rtc.  Keep in mind that this can potentially lead
+	  to lost interrupts, as reading Control Register C will clear
+	  all pending IRQ flags.
+
+	  Unless you are debugging this driver, choose N.
+
+config RTC_DS1685_SYSFS_REGS
+	bool "SysFS access to RTC register bits"
+	depends on RTC_DRV_DS1685_FAMILY && SYSFS
+	help
+	  Enable this to provide access to the RTC control register bits
+	  in /sys.  Some of the bits are read-write, others are read-only.
+
+	  Keep in mind that reading Control C's bits automatically clears
+	  all pending IRQ flags - this can cause lost interrupts.
+
+	  If you know that you need access to these bits, choose Y, Else N.
+
 config RTC_DRV_DS1742
 	tristate "Maxim/Dallas DS1742/1743"
 	depends on HAS_IOMEM
@@ -1141,34 +1242,6 @@
 	  probably want to use the real RTC block instead of the "RTT as an
 	  RTC" driver.
 
-config RTC_DRV_AT91SAM9_RTT
-	int
-	range 0 1
-	default 0
-	depends on RTC_DRV_AT91SAM9
-	help
-	  This option is only relevant for legacy board support and
-	  won't be used when booting a DT board.
-
-	  More than one RTT module is available. You can choose which
-	  one will be used as an RTC. The default of zero is normally
-	  OK to use, though some systems use that for non-RTC purposes.
-
-config RTC_DRV_AT91SAM9_GPBR
-	int
-	range 0 3
-	default 0
-	prompt "Backup Register Number"
-	depends on RTC_DRV_AT91SAM9
-	help
-	  This option is only relevant for legacy board support and
-	  won't be used when booting a DT board.
-
-	  The RTC driver needs to use one of the General Purpose Backup
-	  Registers (GPBRs) as well as the RTT. You can choose which one
-	  will be used. The default of zero is normally OK to use, but
-	  on some systems other software needs to use that register.
-
 config RTC_DRV_AU1XXX
 	tristate "Au1xxx Counter0 RTC support"
 	depends on MIPS_ALCHEMY
@@ -1269,6 +1342,16 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-mv.
 
+config RTC_DRV_ARMADA38X
+	tristate "Armada 38x Marvell SoC RTC"
+	depends on ARCH_MVEBU
+	help
+	  If you say yes here you will get support for the in-chip RTC
+	  that can be found in the Armada 38x Marvell's SoC device
+
+	  This driver can also be built as a module. If so, the module
+	  will be called armada38x-rtc.
+
 config RTC_DRV_PS3
 	tristate "PS3 RTC"
 	depends on PPC_PS3
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index c8ef3e1..69c8706 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -24,6 +24,8 @@
 obj-$(CONFIG_RTC_DRV_88PM80X)	+= rtc-88pm80x.o
 obj-$(CONFIG_RTC_DRV_AB3100)	+= rtc-ab3100.o
 obj-$(CONFIG_RTC_DRV_AB8500)	+= rtc-ab8500.o
+obj-$(CONFIG_RTC_DRV_ABB5ZES3)	+= rtc-ab-b5ze-s3.o
+obj-$(CONFIG_RTC_DRV_ARMADA38X)	+= rtc-armada38x.o
 obj-$(CONFIG_RTC_DRV_AS3722)	+= rtc-as3722.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
@@ -52,6 +54,7 @@
 obj-$(CONFIG_RTC_DRV_DS1511)	+= rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1685_FAMILY)	+= rtc-ds1685.o
 obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_DS2404)    += rtc-ds2404.o
 obj-$(CONFIG_RTC_DRV_DS3232)	+= rtc-ds3232.o
diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c
new file mode 100644
index 0000000..cfc2ef9
--- /dev/null
+++ b/drivers/rtc/rtc-ab-b5ze-s3.c
@@ -0,0 +1,1035 @@
+/*
+ * rtc-ab-b5ze-s3 - Driver for Abracon AB-RTCMC-32.768Khz-B5ZE-S3
+ *                  I2C RTC / Alarm chip
+ *
+ * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * Detailed datasheet of the chip is available here:
+ *
+ *  http://www.abracon.com/realtimeclock/AB-RTCMC-32.768kHz-B5ZE-S3-Application-Manual.pdf
+ *
+ * This work is based on ISL12057 driver (drivers/rtc/rtc-isl12057.c).
+ *
+ * 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/module.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/interrupt.h>
+
+#define DRV_NAME "rtc-ab-b5ze-s3"
+
+/* Control section */
+#define ABB5ZES3_REG_CTRL1	   0x00	   /* Control 1 register */
+#define ABB5ZES3_REG_CTRL1_CIE	   BIT(0)  /* Pulse interrupt enable */
+#define ABB5ZES3_REG_CTRL1_AIE	   BIT(1)  /* Alarm interrupt enable */
+#define ABB5ZES3_REG_CTRL1_SIE	   BIT(2)  /* Second interrupt enable */
+#define ABB5ZES3_REG_CTRL1_PM	   BIT(3)  /* 24h/12h mode */
+#define ABB5ZES3_REG_CTRL1_SR	   BIT(4)  /* Software reset */
+#define ABB5ZES3_REG_CTRL1_STOP	   BIT(5)  /* RTC circuit enable */
+#define ABB5ZES3_REG_CTRL1_CAP	   BIT(7)
+
+#define ABB5ZES3_REG_CTRL2	   0x01	   /* Control 2 register */
+#define ABB5ZES3_REG_CTRL2_CTBIE   BIT(0)  /* Countdown timer B int. enable */
+#define ABB5ZES3_REG_CTRL2_CTAIE   BIT(1)  /* Countdown timer A int. enable */
+#define ABB5ZES3_REG_CTRL2_WTAIE   BIT(2)  /* Watchdog timer A int. enable */
+#define ABB5ZES3_REG_CTRL2_AF	   BIT(3)  /* Alarm interrupt status */
+#define ABB5ZES3_REG_CTRL2_SF	   BIT(4)  /* Second interrupt status */
+#define ABB5ZES3_REG_CTRL2_CTBF	   BIT(5)  /* Countdown timer B int. status */
+#define ABB5ZES3_REG_CTRL2_CTAF	   BIT(6)  /* Countdown timer A int. status */
+#define ABB5ZES3_REG_CTRL2_WTAF	   BIT(7)  /* Watchdog timer A int. status */
+
+#define ABB5ZES3_REG_CTRL3	   0x02	   /* Control 3 register */
+#define ABB5ZES3_REG_CTRL3_PM2	   BIT(7)  /* Power Management bit 2 */
+#define ABB5ZES3_REG_CTRL3_PM1	   BIT(6)  /* Power Management bit 1 */
+#define ABB5ZES3_REG_CTRL3_PM0	   BIT(5)  /* Power Management bit 0 */
+#define ABB5ZES3_REG_CTRL3_BSF	   BIT(3)  /* Battery switchover int. status */
+#define ABB5ZES3_REG_CTRL3_BLF	   BIT(2)  /* Battery low int. status */
+#define ABB5ZES3_REG_CTRL3_BSIE	   BIT(1)  /* Battery switchover int. enable */
+#define ABB5ZES3_REG_CTRL3_BLIE	   BIT(0)  /* Battery low int. enable */
+
+#define ABB5ZES3_CTRL_SEC_LEN	   3
+
+/* RTC section */
+#define ABB5ZES3_REG_RTC_SC	   0x03	   /* RTC Seconds register */
+#define ABB5ZES3_REG_RTC_SC_OSC	   BIT(7)  /* Clock integrity status */
+#define ABB5ZES3_REG_RTC_MN	   0x04	   /* RTC Minutes register */
+#define ABB5ZES3_REG_RTC_HR	   0x05	   /* RTC Hours register */
+#define ABB5ZES3_REG_RTC_HR_PM	   BIT(5)  /* RTC Hours PM bit */
+#define ABB5ZES3_REG_RTC_DT	   0x06	   /* RTC Date register */
+#define ABB5ZES3_REG_RTC_DW	   0x07	   /* RTC Day of the week register */
+#define ABB5ZES3_REG_RTC_MO	   0x08	   /* RTC Month register */
+#define ABB5ZES3_REG_RTC_YR	   0x09	   /* RTC Year register */
+
+#define ABB5ZES3_RTC_SEC_LEN	   7
+
+/* Alarm section (enable bits are all active low) */
+#define ABB5ZES3_REG_ALRM_MN	   0x0A	   /* Alarm - minute register */
+#define ABB5ZES3_REG_ALRM_MN_AE	   BIT(7)  /* Minute enable */
+#define ABB5ZES3_REG_ALRM_HR	   0x0B	   /* Alarm - hours register */
+#define ABB5ZES3_REG_ALRM_HR_AE	   BIT(7)  /* Hour enable */
+#define ABB5ZES3_REG_ALRM_DT	   0x0C	   /* Alarm - date register */
+#define ABB5ZES3_REG_ALRM_DT_AE	   BIT(7)  /* Date (day of the month) enable */
+#define ABB5ZES3_REG_ALRM_DW	   0x0D	   /* Alarm - day of the week reg. */
+#define ABB5ZES3_REG_ALRM_DW_AE	   BIT(7)  /* Day of the week enable */
+
+#define ABB5ZES3_ALRM_SEC_LEN	   4
+
+/* Frequency offset section */
+#define ABB5ZES3_REG_FREQ_OF	   0x0E	   /* Frequency offset register */
+#define ABB5ZES3_REG_FREQ_OF_MODE  0x0E	   /* Offset mode: 2 hours / minute */
+
+/* CLOCKOUT section */
+#define ABB5ZES3_REG_TIM_CLK	   0x0F	   /* Timer & Clockout register */
+#define ABB5ZES3_REG_TIM_CLK_TAM   BIT(7)  /* Permanent/pulsed timer A/int. 2 */
+#define ABB5ZES3_REG_TIM_CLK_TBM   BIT(6)  /* Permanent/pulsed timer B */
+#define ABB5ZES3_REG_TIM_CLK_COF2  BIT(5)  /* Clkout Freq bit 2 */
+#define ABB5ZES3_REG_TIM_CLK_COF1  BIT(4)  /* Clkout Freq bit 1 */
+#define ABB5ZES3_REG_TIM_CLK_COF0  BIT(3)  /* Clkout Freq bit 0 */
+#define ABB5ZES3_REG_TIM_CLK_TAC1  BIT(2)  /* Timer A: - 01 : countdown */
+#define ABB5ZES3_REG_TIM_CLK_TAC0  BIT(1)  /*	       - 10 : timer	*/
+#define ABB5ZES3_REG_TIM_CLK_TBC   BIT(0)  /* Timer B enable */
+
+/* Timer A Section */
+#define ABB5ZES3_REG_TIMA_CLK	   0x10	   /* Timer A clock register */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ2 BIT(2)  /* Freq bit 2 */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ1 BIT(1)  /* Freq bit 1 */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ0 BIT(0)  /* Freq bit 0 */
+#define ABB5ZES3_REG_TIMA	   0x11	   /* Timer A register */
+
+#define ABB5ZES3_TIMA_SEC_LEN	   2
+
+/* Timer B Section */
+#define ABB5ZES3_REG_TIMB_CLK	   0x12	   /* Timer B clock register */
+#define ABB5ZES3_REG_TIMB_CLK_TBW2 BIT(6)
+#define ABB5ZES3_REG_TIMB_CLK_TBW1 BIT(5)
+#define ABB5ZES3_REG_TIMB_CLK_TBW0 BIT(4)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ2 BIT(2)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ1 BIT(1)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ0 BIT(0)
+#define ABB5ZES3_REG_TIMB	   0x13	   /* Timer B register */
+#define ABB5ZES3_TIMB_SEC_LEN	   2
+
+#define ABB5ZES3_MEM_MAP_LEN	   0x14
+
+struct abb5zes3_rtc_data {
+	struct rtc_device *rtc;
+	struct regmap *regmap;
+	struct mutex lock;
+
+	int irq;
+
+	bool battery_low;
+	bool timer_alarm; /* current alarm is via timer A */
+};
+
+/*
+ * Try and match register bits w/ fixed null values to see whether we
+ * are dealing with an ABB5ZES3. Note: this function is called early
+ * during init and hence does need mutex protection.
+ */
+static int abb5zes3_i2c_validate_chip(struct regmap *regmap)
+{
+	u8 regs[ABB5ZES3_MEM_MAP_LEN];
+	static const u8 mask[ABB5ZES3_MEM_MAP_LEN] = { 0x00, 0x00, 0x10, 0x00,
+						       0x80, 0xc0, 0xc0, 0xf8,
+						       0xe0, 0x00, 0x00, 0x40,
+						       0x40, 0x78, 0x00, 0x00,
+						       0xf8, 0x00, 0x88, 0x00 };
+	int ret, i;
+
+	ret = regmap_bulk_read(regmap, 0, regs, ABB5ZES3_MEM_MAP_LEN);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ABB5ZES3_MEM_MAP_LEN; ++i) {
+		if (regs[i] & mask[i]) /* check if bits are cleared */
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Clear alarm status bit. */
+static int _abb5zes3_rtc_clear_alarm(struct device *dev)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL2,
+				 ABB5ZES3_REG_CTRL2_AF, 0);
+	if (ret)
+		dev_err(dev, "%s: clearing alarm failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+/* Enable or disable alarm (i.e. alarm interrupt generation) */
+static int _abb5zes3_rtc_update_alarm(struct device *dev, bool enable)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL1,
+				 ABB5ZES3_REG_CTRL1_AIE,
+				 enable ? ABB5ZES3_REG_CTRL1_AIE : 0);
+	if (ret)
+		dev_err(dev, "%s: writing alarm INT failed (%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+/* Enable or disable timer (watchdog timer A interrupt generation) */
+static int _abb5zes3_rtc_update_timer(struct device *dev, bool enable)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL2,
+				 ABB5ZES3_REG_CTRL2_WTAIE,
+				 enable ? ABB5ZES3_REG_CTRL2_WTAIE : 0);
+	if (ret)
+		dev_err(dev, "%s: writing timer INT failed (%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+/*
+ * Note: we only read, so regmap inner lock protection is sufficient, i.e.
+ * we do not need driver's main lock protection.
+ */
+static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
+	int ret;
+
+	/*
+	 * As we need to read CTRL1 register anyway to access 24/12h
+	 * mode bit, we do a single bulk read of both control and RTC
+	 * sections (they are consecutive). This also ease indexing
+	 * of register values after bulk read.
+	 */
+	ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_CTRL1, regs,
+			       sizeof(regs));
+	if (ret) {
+		dev_err(dev, "%s: reading RTC time failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* If clock integrity is not guaranteed, do not return a time value */
+	if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC) {
+		ret = -ENODATA;
+		goto err;
+	}
+
+	tm->tm_sec = bcd2bin(regs[ABB5ZES3_REG_RTC_SC] & 0x7F);
+	tm->tm_min = bcd2bin(regs[ABB5ZES3_REG_RTC_MN]);
+
+	if (regs[ABB5ZES3_REG_CTRL1] & ABB5ZES3_REG_CTRL1_PM) { /* 12hr mode */
+		tm->tm_hour = bcd2bin(regs[ABB5ZES3_REG_RTC_HR] & 0x1f);
+		if (regs[ABB5ZES3_REG_RTC_HR] & ABB5ZES3_REG_RTC_HR_PM) /* PM */
+			tm->tm_hour += 12;
+	} else {						/* 24hr mode */
+		tm->tm_hour = bcd2bin(regs[ABB5ZES3_REG_RTC_HR]);
+	}
+
+	tm->tm_mday = bcd2bin(regs[ABB5ZES3_REG_RTC_DT]);
+	tm->tm_wday = bcd2bin(regs[ABB5ZES3_REG_RTC_DW]);
+	tm->tm_mon  = bcd2bin(regs[ABB5ZES3_REG_RTC_MO]) - 1; /* starts at 1 */
+	tm->tm_year = bcd2bin(regs[ABB5ZES3_REG_RTC_YR]) + 100;
+
+	ret = rtc_valid_tm(tm);
+
+err:
+	return ret;
+}
+
+static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
+	int ret;
+
+	/*
+	 * Year register is 8-bit wide and bcd-coded, i.e records values
+	 * between 0 and 99. tm_year is an offset from 1900 and we are
+	 * interested in the 2000-2099 range, so any value less than 100
+	 * is invalid.
+	 */
+	if (tm->tm_year < 100)
+		return -EINVAL;
+
+	regs[ABB5ZES3_REG_RTC_SC] = bin2bcd(tm->tm_sec); /* MSB=0 clears OSC */
+	regs[ABB5ZES3_REG_RTC_MN] = bin2bcd(tm->tm_min);
+	regs[ABB5ZES3_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
+	regs[ABB5ZES3_REG_RTC_DT] = bin2bcd(tm->tm_mday);
+	regs[ABB5ZES3_REG_RTC_DW] = bin2bcd(tm->tm_wday);
+	regs[ABB5ZES3_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
+	regs[ABB5ZES3_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
+
+	mutex_lock(&data->lock);
+	ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_RTC_SC,
+				regs + ABB5ZES3_REG_RTC_SC,
+				ABB5ZES3_RTC_SEC_LEN);
+	mutex_unlock(&data->lock);
+
+
+	return ret;
+}
+
+/*
+ * Set provided TAQ and Timer A registers (TIMA_CLK and TIMA) based on
+ * given number of seconds.
+ */
+static inline void sec_to_timer_a(u8 secs, u8 *taq, u8 *timer_a)
+{
+	*taq = ABB5ZES3_REG_TIMA_CLK_TAQ1; /* 1Hz */
+	*timer_a = secs;
+}
+
+/*
+ * Return current number of seconds in Timer A. As we only use
+ * timer A with a 1Hz freq, this is what we expect to have.
+ */
+static inline int sec_from_timer_a(u8 *secs, u8 taq, u8 timer_a)
+{
+	if (taq != ABB5ZES3_REG_TIMA_CLK_TAQ1) /* 1Hz */
+		return -EINVAL;
+
+	*secs = timer_a;
+
+	return 0;
+}
+
+/*
+ * Read alarm currently configured via a watchdog timer using timer A. This
+ * is done by reading current RTC time and adding remaining timer time.
+ */
+static int _abb5zes3_rtc_read_timer(struct device *dev,
+				    struct rtc_wkalrm *alarm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+	u8 regs[ABB5ZES3_TIMA_SEC_LEN + 1];
+	unsigned long rtc_secs;
+	unsigned int reg;
+	u8 timer_secs;
+	int ret;
+
+	/*
+	 * Instead of doing two separate calls, because they are consecutive,
+	 * we grab both clockout register and Timer A section. The latter is
+	 * used to decide if timer A is enabled (as a watchdog timer).
+	 */
+	ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_TIM_CLK, regs,
+			       ABB5ZES3_TIMA_SEC_LEN + 1);
+	if (ret) {
+		dev_err(dev, "%s: reading Timer A section failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* get current time ... */
+	ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err;
+
+	/* ... convert to seconds ... */
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err;
+
+	/* ... add remaining timer A time ... */
+	ret = sec_from_timer_a(&timer_secs, regs[1], regs[2]);
+	if (ret)
+		goto err;
+
+	/* ... and convert back. */
+	rtc_time_to_tm(rtc_secs + timer_secs, alarm_tm);
+
+	ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL2, &reg);
+	if (ret) {
+		dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL2_WTAIE);
+
+err:
+	return ret;
+}
+
+/* Read alarm currently configured via a RTC alarm registers. */
+static int _abb5zes3_rtc_read_alarm(struct device *dev,
+				    struct rtc_wkalrm *alarm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+	unsigned long rtc_secs, alarm_secs;
+	u8 regs[ABB5ZES3_ALRM_SEC_LEN];
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_ALRM_MN, regs,
+			       ABB5ZES3_ALRM_SEC_LEN);
+	if (ret) {
+		dev_err(dev, "%s: reading alarm section failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	alarm_tm->tm_sec  = 0;
+	alarm_tm->tm_min  = bcd2bin(regs[0] & 0x7f);
+	alarm_tm->tm_hour = bcd2bin(regs[1] & 0x3f);
+	alarm_tm->tm_mday = bcd2bin(regs[2] & 0x3f);
+	alarm_tm->tm_wday = -1;
+
+	/*
+	 * The alarm section does not store year/month. We use the ones in rtc
+	 * section as a basis and increment month and then year if needed to get
+	 * alarm after current time.
+	 */
+	ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err;
+
+	alarm_tm->tm_year = rtc_tm.tm_year;
+	alarm_tm->tm_mon = rtc_tm.tm_mon;
+
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err;
+
+	ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+	if (ret)
+		goto err;
+
+	if (alarm_secs < rtc_secs) {
+		if (alarm_tm->tm_mon == 11) {
+			alarm_tm->tm_mon = 0;
+			alarm_tm->tm_year += 1;
+		} else {
+			alarm_tm->tm_mon += 1;
+		}
+	}
+
+	ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL1, &reg);
+	if (ret) {
+		dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL1_AIE);
+
+err:
+	return ret;
+}
+
+/*
+ * As the Alarm mechanism supported by the chip is only accurate to the
+ * minute, we use the watchdog timer mechanism provided by timer A
+ * (up to 256 seconds w/ a second accuracy) for low alarm values (below
+ * 4 minutes). Otherwise, we use the common alarm mechanism provided
+ * by the chip. In order for that to work, we keep track of currently
+ * configured timer type via 'timer_alarm' flag in our private data
+ * structure.
+ */
+static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&data->lock);
+	if (data->timer_alarm)
+		ret = _abb5zes3_rtc_read_timer(dev, alarm);
+	else
+		ret = _abb5zes3_rtc_read_alarm(dev, alarm);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+/*
+ * Set alarm using chip alarm mechanism. It is only accurate to the
+ * minute (not the second). The function expects alarm interrupt to
+ * be disabled.
+ */
+static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time *alarm_tm = &alarm->time;
+	unsigned long rtc_secs, alarm_secs;
+	u8 regs[ABB5ZES3_ALRM_SEC_LEN];
+	struct rtc_time rtc_tm;
+	int ret, enable = 1;
+
+	ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err;
+
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err;
+
+	ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+	if (ret)
+		goto err;
+
+	/* If alarm time is before current time, disable the alarm */
+	if (!alarm->enabled || alarm_secs <= rtc_secs) {
+		enable = 0;
+	} else {
+		/*
+		 * Chip only support alarms up to one month in the future. Let's
+		 * return an error if we get something after that limit.
+		 * Comparison is done by incrementing rtc_tm month field by one
+		 * and checking alarm value is still below.
+		 */
+		if (rtc_tm.tm_mon == 11) { /* handle year wrapping */
+			rtc_tm.tm_mon = 0;
+			rtc_tm.tm_year += 1;
+		} else {
+			rtc_tm.tm_mon += 1;
+		}
+
+		ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+		if (ret)
+			goto err;
+
+		if (alarm_secs > rtc_secs) {
+			dev_err(dev, "%s: alarm maximum is one month in the "
+				"future (%d)\n", __func__, ret);
+			ret = -EINVAL;
+			goto err;
+		}
+	}
+
+	/*
+	 * Program all alarm registers but DW one. For each register, setting
+	 * MSB to 0 enables associated alarm.
+	 */
+	regs[0] = bin2bcd(alarm_tm->tm_min) & 0x7f;
+	regs[1] = bin2bcd(alarm_tm->tm_hour) & 0x3f;
+	regs[2] = bin2bcd(alarm_tm->tm_mday) & 0x3f;
+	regs[3] = ABB5ZES3_REG_ALRM_DW_AE; /* do not match day of the week */
+
+	ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_ALRM_MN, regs,
+				ABB5ZES3_ALRM_SEC_LEN);
+	if (ret < 0) {
+		dev_err(dev, "%s: writing ALARM section failed (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* Record currently configured alarm is not a timer */
+	data->timer_alarm = 0;
+
+	/* Enable or disable alarm interrupt generation */
+	ret = _abb5zes3_rtc_update_alarm(dev, enable);
+
+err:
+	return ret;
+}
+
+/*
+ * Set alarm using timer watchdog (via timer A) mechanism. The function expects
+ * timer A interrupt to be disabled.
+ */
+static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm,
+				   u8 secs)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	u8 regs[ABB5ZES3_TIMA_SEC_LEN];
+	u8 mask = ABB5ZES3_REG_TIM_CLK_TAC0 | ABB5ZES3_REG_TIM_CLK_TAC1;
+	int ret = 0;
+
+	/* Program given number of seconds to Timer A registers */
+	sec_to_timer_a(secs, &regs[0], &regs[1]);
+	ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_TIMA_CLK, regs,
+				ABB5ZES3_TIMA_SEC_LEN);
+	if (ret < 0) {
+		dev_err(dev, "%s: writing timer section failed\n", __func__);
+		goto err;
+	}
+
+	/* Configure Timer A as a watchdog timer */
+	ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_TIM_CLK,
+				 mask, ABB5ZES3_REG_TIM_CLK_TAC1);
+	if (ret)
+		dev_err(dev, "%s: failed to update timer\n", __func__);
+
+	/* Record currently configured alarm is a timer */
+	data->timer_alarm = 1;
+
+	/* Enable or disable timer interrupt generation */
+	ret = _abb5zes3_rtc_update_timer(dev, alarm->enabled);
+
+err:
+	return ret;
+}
+
+/*
+ * The chip has an alarm which is only accurate to the minute. In order to
+ * handle alarms below that limit, we use the watchdog timer function of
+ * timer A. More precisely, the timer method is used for alarms below 240
+ * seconds.
+ */
+static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time *alarm_tm = &alarm->time;
+	unsigned long rtc_secs, alarm_secs;
+	struct rtc_time rtc_tm;
+	int ret;
+
+	mutex_lock(&data->lock);
+	ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err;
+
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err;
+
+	ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+	if (ret)
+		goto err;
+
+	/* Let's first disable both the alarm and the timer interrupts */
+	ret = _abb5zes3_rtc_update_alarm(dev, false);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to disable alarm (%d)\n", __func__,
+			ret);
+		goto err;
+	}
+	ret = _abb5zes3_rtc_update_timer(dev, false);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to disable timer (%d)\n", __func__,
+			ret);
+		goto err;
+	}
+
+	data->timer_alarm = 0;
+
+	/*
+	 * Let's now configure the alarm; if we are expected to ring in
+	 * more than 240s, then we setup an alarm. Otherwise, a timer.
+	 */
+	if ((alarm_secs > rtc_secs) && ((alarm_secs - rtc_secs) <= 240))
+		ret = _abb5zes3_rtc_set_timer(dev, alarm,
+					      alarm_secs - rtc_secs);
+	else
+		ret = _abb5zes3_rtc_set_alarm(dev, alarm);
+
+ err:
+	mutex_unlock(&data->lock);
+
+	if (ret)
+		dev_err(dev, "%s: unable to configure alarm (%d)\n", __func__,
+			ret);
+
+	return ret;
+ }
+
+/* Enable or disable battery low irq generation */
+static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap,
+						       bool enable)
+{
+	return regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3,
+				  ABB5ZES3_REG_CTRL3_BLIE,
+				  enable ? ABB5ZES3_REG_CTRL3_BLIE : 0);
+}
+
+/*
+ * Check current RTC status and enable/disable what needs to be. Return 0 if
+ * everything went ok and a negative value upon error. Note: this function
+ * is called early during init and hence does need mutex protection.
+ */
+static int abb5zes3_rtc_check_setup(struct device *dev)
+{
+	struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+	struct regmap *regmap = data->regmap;
+	unsigned int reg;
+	int ret;
+	u8 mask;
+
+	/*
+	 * By default, the devices generates a 32.768KHz signal on IRQ#1 pin. It
+	 * is disabled here to prevent polluting the interrupt line and
+	 * uselessly triggering the IRQ handler we install for alarm and battery
+	 * low events. Note: this is done before clearing int. status below
+	 * in this function.
+	 * We also disable all timers and set timer interrupt to permanent (not
+	 * pulsed).
+	 */
+	mask = (ABB5ZES3_REG_TIM_CLK_TBC | ABB5ZES3_REG_TIM_CLK_TAC0 |
+		ABB5ZES3_REG_TIM_CLK_TAC1 | ABB5ZES3_REG_TIM_CLK_COF0 |
+		ABB5ZES3_REG_TIM_CLK_COF1 | ABB5ZES3_REG_TIM_CLK_COF2 |
+		ABB5ZES3_REG_TIM_CLK_TBM | ABB5ZES3_REG_TIM_CLK_TAM);
+	ret = regmap_update_bits(regmap, ABB5ZES3_REG_TIM_CLK, mask,
+		ABB5ZES3_REG_TIM_CLK_COF0 | ABB5ZES3_REG_TIM_CLK_COF1 |
+		ABB5ZES3_REG_TIM_CLK_COF2);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to initialize clkout register (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Each component of the alarm (MN, HR, DT, DW) can be enabled/disabled
+	 * individually by clearing/setting MSB of each associated register. So,
+	 * we set all alarm enable bits to disable current alarm setting.
+	 */
+	mask = (ABB5ZES3_REG_ALRM_MN_AE | ABB5ZES3_REG_ALRM_HR_AE |
+		ABB5ZES3_REG_ALRM_DT_AE | ABB5ZES3_REG_ALRM_DW_AE);
+	ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL2, mask, mask);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to disable alarm setting (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* Set Control 1 register (RTC enabled, 24hr mode, all int. disabled) */
+	mask = (ABB5ZES3_REG_CTRL1_CIE | ABB5ZES3_REG_CTRL1_AIE |
+		ABB5ZES3_REG_CTRL1_SIE | ABB5ZES3_REG_CTRL1_PM |
+		ABB5ZES3_REG_CTRL1_CAP | ABB5ZES3_REG_CTRL1_STOP);
+	ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL1, mask, 0);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to initialize CTRL1 register (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Set Control 2 register (timer int. disabled, alarm status cleared).
+	 * WTAF is read-only and cleared automatically by reading the register.
+	 */
+	mask = (ABB5ZES3_REG_CTRL2_CTBIE | ABB5ZES3_REG_CTRL2_CTAIE |
+		ABB5ZES3_REG_CTRL2_WTAIE | ABB5ZES3_REG_CTRL2_AF |
+		ABB5ZES3_REG_CTRL2_SF | ABB5ZES3_REG_CTRL2_CTBF |
+		ABB5ZES3_REG_CTRL2_CTAF);
+	ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL2, mask, 0);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to initialize CTRL2 register (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/*
+	 * Enable battery low detection function and battery switchover function
+	 * (standard mode). Disable associated interrupts. Clear battery
+	 * switchover flag but not battery low flag. The latter is checked
+	 * later below.
+	 */
+	mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 |
+		ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE |
+		ABB5ZES3_REG_CTRL3_BSIE| ABB5ZES3_REG_CTRL3_BSF);
+	ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3, mask, 0);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to initialize CTRL3 register (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* Check oscillator integrity flag */
+	ret = regmap_read(regmap, ABB5ZES3_REG_RTC_SC, &reg);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to read osc. integrity flag (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	if (reg & ABB5ZES3_REG_RTC_SC_OSC) {
+		dev_err(dev, "clock integrity not guaranteed. Osc. has stopped "
+			"or has been interrupted.\n");
+		dev_err(dev, "change battery (if not already done) and  "
+			"then set time to reset osc. failure flag.\n");
+	}
+
+	/*
+	 * Check battery low flag at startup: this allows reporting battery
+	 * is low at startup when IRQ line is not connected. Note: we record
+	 * current status to avoid reenabling this interrupt later in probe
+	 * function if battery is low.
+	 */
+	ret = regmap_read(regmap, ABB5ZES3_REG_CTRL3, &reg);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to read battery low flag (%d)\n",
+			__func__, ret);
+		return ret;
+	}
+
+	data->battery_low = reg & ABB5ZES3_REG_CTRL3_BLF;
+	if (data->battery_low) {
+		dev_err(dev, "RTC battery is low; please, consider "
+			"changing it!\n");
+
+		ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, false);
+		if (ret)
+			dev_err(dev, "%s: disabling battery low interrupt "
+				"generation failed (%d)\n", __func__, ret);
+	}
+
+	return ret;
+}
+
+static int abb5zes3_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enable)
+{
+	struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (rtc_data->irq) {
+		mutex_lock(&rtc_data->lock);
+		if (rtc_data->timer_alarm)
+			ret = _abb5zes3_rtc_update_timer(dev, enable);
+		else
+			ret = _abb5zes3_rtc_update_alarm(dev, enable);
+		mutex_unlock(&rtc_data->lock);
+	}
+
+	return ret;
+}
+
+static irqreturn_t _abb5zes3_rtc_interrupt(int irq, void *data)
+{
+	struct i2c_client *client = data;
+	struct device *dev = &client->dev;
+	struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+	struct rtc_device *rtc = rtc_data->rtc;
+	u8 regs[ABB5ZES3_CTRL_SEC_LEN];
+	int ret, handled = IRQ_NONE;
+
+	ret = regmap_bulk_read(rtc_data->regmap, 0, regs,
+			       ABB5ZES3_CTRL_SEC_LEN);
+	if (ret) {
+		dev_err(dev, "%s: unable to read control section (%d)!\n",
+			__func__, ret);
+		return handled;
+	}
+
+	/*
+	 * Check battery low detection flag and disable battery low interrupt
+	 * generation if flag is set (interrupt can only be cleared when
+	 * battery is replaced).
+	 */
+	if (regs[ABB5ZES3_REG_CTRL3] & ABB5ZES3_REG_CTRL3_BLF) {
+		dev_err(dev, "RTC battery is low; please change it!\n");
+
+		_abb5zes3_rtc_battery_low_irq_enable(rtc_data->regmap, false);
+
+		handled = IRQ_HANDLED;
+	}
+
+	/* Check alarm flag */
+	if (regs[ABB5ZES3_REG_CTRL2] & ABB5ZES3_REG_CTRL2_AF) {
+		dev_dbg(dev, "RTC alarm!\n");
+
+		rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+		/* Acknowledge and disable the alarm */
+		_abb5zes3_rtc_clear_alarm(dev);
+		_abb5zes3_rtc_update_alarm(dev, 0);
+
+		handled = IRQ_HANDLED;
+	}
+
+	/* Check watchdog Timer A flag */
+	if (regs[ABB5ZES3_REG_CTRL2] & ABB5ZES3_REG_CTRL2_WTAF) {
+		dev_dbg(dev, "RTC timer!\n");
+
+		rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+		/*
+		 * Acknowledge and disable the alarm. Note: WTAF
+		 * flag had been cleared when reading CTRL2
+		 */
+		_abb5zes3_rtc_update_timer(dev, 0);
+
+		rtc_data->timer_alarm = 0;
+
+		handled = IRQ_HANDLED;
+	}
+
+	return handled;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+	.read_time = _abb5zes3_rtc_read_time,
+	.set_time = abb5zes3_rtc_set_time,
+	.read_alarm = abb5zes3_rtc_read_alarm,
+	.set_alarm = abb5zes3_rtc_set_alarm,
+	.alarm_irq_enable = abb5zes3_rtc_alarm_irq_enable,
+};
+
+static struct regmap_config abb5zes3_rtc_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int abb5zes3_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct abb5zes3_rtc_data *data = NULL;
+	struct device *dev = &client->dev;
+	struct regmap *regmap;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_I2C_BLOCK)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	regmap = devm_regmap_init_i2c(client, &abb5zes3_rtc_regmap_config);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(dev, "%s: regmap allocation failed: %d\n",
+			__func__, ret);
+		goto err;
+	}
+
+	ret = abb5zes3_i2c_validate_chip(regmap);
+	if (ret)
+		goto err;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	mutex_init(&data->lock);
+	data->regmap = regmap;
+	dev_set_drvdata(dev, data);
+
+	ret = abb5zes3_rtc_check_setup(dev);
+	if (ret)
+		goto err;
+
+	if (client->irq > 0) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						_abb5zes3_rtc_interrupt,
+						IRQF_SHARED|IRQF_ONESHOT,
+						DRV_NAME, client);
+		if (!ret) {
+			device_init_wakeup(dev, true);
+			data->irq = client->irq;
+			dev_dbg(dev, "%s: irq %d used by RTC\n", __func__,
+				client->irq);
+		} else {
+			dev_err(dev, "%s: irq %d unavailable (%d)\n",
+				__func__, client->irq, ret);
+			goto err;
+		}
+	}
+
+	data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops,
+					     THIS_MODULE);
+	ret = PTR_ERR_OR_ZERO(data->rtc);
+	if (ret) {
+		dev_err(dev, "%s: unable to register RTC device (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* Enable battery low detection interrupt if battery not already low */
+	if (!data->battery_low && data->irq) {
+		ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, true);
+		if (ret) {
+			dev_err(dev, "%s: enabling battery low interrupt "
+				"generation failed (%d)\n", __func__, ret);
+			goto err;
+		}
+	}
+
+err:
+	if (ret && data && data->irq)
+		device_init_wakeup(dev, false);
+	return ret;
+}
+
+static int abb5zes3_remove(struct i2c_client *client)
+{
+	struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(&client->dev);
+
+	if (rtc_data->irq > 0)
+		device_init_wakeup(&client->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int abb5zes3_rtc_suspend(struct device *dev)
+{
+	struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		return enable_irq_wake(rtc_data->irq);
+
+	return 0;
+}
+
+static int abb5zes3_rtc_resume(struct device *dev)
+{
+	struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev))
+		return disable_irq_wake(rtc_data->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(abb5zes3_rtc_pm_ops, abb5zes3_rtc_suspend,
+			 abb5zes3_rtc_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id abb5zes3_dt_match[] = {
+	{ .compatible = "abracon,abb5zes3" },
+	{ },
+};
+#endif
+
+static const struct i2c_device_id abb5zes3_id[] = {
+	{ "abb5zes3", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, abb5zes3_id);
+
+static struct i2c_driver abb5zes3_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &abb5zes3_rtc_pm_ops,
+		.of_match_table = of_match_ptr(abb5zes3_dt_match),
+	},
+	.probe	  = abb5zes3_probe,
+	.remove	  = abb5zes3_remove,
+	.id_table = abb5zes3_id,
+};
+module_i2c_driver(abb5zes3_driver);
+
+MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
+MODULE_DESCRIPTION("Abracon AB-RTCMC-32.768kHz-B5ZE-S3 RTC/Alarm driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
new file mode 100644
index 0000000..43e04af
--- /dev/null
+++ b/drivers/rtc/rtc-armada38x.c
@@ -0,0 +1,320 @@
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2015 Marvell
+ *
+ * Gregory Clement <gregory.clement@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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define RTC_STATUS	    0x0
+#define RTC_STATUS_ALARM1	    BIT(0)
+#define RTC_STATUS_ALARM2	    BIT(1)
+#define RTC_IRQ1_CONF	    0x4
+#define RTC_IRQ1_AL_EN		    BIT(0)
+#define RTC_IRQ1_FREQ_EN	    BIT(1)
+#define RTC_IRQ1_FREQ_1HZ	    BIT(2)
+#define RTC_TIME	    0xC
+#define RTC_ALARM1	    0x10
+
+#define SOC_RTC_INTERRUPT   0x8
+#define SOC_RTC_ALARM1		BIT(0)
+#define SOC_RTC_ALARM2		BIT(1)
+#define SOC_RTC_ALARM1_MASK	BIT(2)
+#define SOC_RTC_ALARM2_MASK	BIT(3)
+
+struct armada38x_rtc {
+	struct rtc_device   *rtc_dev;
+	void __iomem	    *regs;
+	void __iomem	    *regs_soc;
+	spinlock_t	    lock;
+	int		    irq;
+};
+
+/*
+ * According to the datasheet, the OS should wait 5us after every
+ * register write to the RTC hard macro so that the required update
+ * can occur without holding off the system bus
+ */
+static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
+{
+	writel(val, rtc->regs + offset);
+	udelay(5);
+}
+
+static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long time, time_check, flags;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	time = readl(rtc->regs + RTC_TIME);
+	/*
+	 * WA for failing time set attempts. As stated in HW ERRATA if
+	 * more than one second between two time reads is detected
+	 * then read once again.
+	 */
+	time_check = readl(rtc->regs + RTC_TIME);
+	if ((time_check - time) > 1)
+		time_check = readl(rtc->regs + RTC_TIME);
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	rtc_time_to_tm(time_check, tm);
+
+	return 0;
+}
+
+static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+	int ret = 0;
+	unsigned long time, flags;
+
+	ret = rtc_tm_to_time(tm, &time);
+
+	if (ret)
+		goto out;
+	/*
+	 * Setting the RTC time not always succeeds. According to the
+	 * errata we need to first write on the status register and
+	 * then wait for 100ms before writing to the time register to be
+	 * sure that the data will be taken into account.
+	 */
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	rtc_delayed_write(0, rtc, RTC_STATUS);
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	msleep(100);
+
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	rtc_delayed_write(time, rtc, RTC_TIME);
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+out:
+	return ret;
+}
+
+static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long time, flags;
+	u32 val;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	time = readl(rtc->regs + RTC_ALARM1);
+	val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	alrm->enabled = val ? 1 : 0;
+	rtc_time_to_tm(time,  &alrm->time);
+
+	return 0;
+}
+
+static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long time, flags;
+	int ret = 0;
+	u32 val;
+
+	ret = rtc_tm_to_time(&alrm->time, &time);
+
+	if (ret)
+		goto out;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	rtc_delayed_write(time, rtc, RTC_ALARM1);
+
+	if (alrm->enabled) {
+			rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
+			val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+			writel(val | SOC_RTC_ALARM1_MASK,
+			       rtc->regs_soc + SOC_RTC_INTERRUPT);
+	}
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+out:
+	return ret;
+}
+
+static int armada38x_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enabled)
+{
+	struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	if (enabled)
+		rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
+	else
+		rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	return 0;
+}
+
+static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
+{
+	struct armada38x_rtc *rtc = data;
+	u32 val;
+	int event = RTC_IRQF | RTC_AF;
+
+	dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
+
+	spin_lock(&rtc->lock);
+
+	val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+
+	writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
+	val = readl(rtc->regs + RTC_IRQ1_CONF);
+	/* disable all the interrupts for alarm 1 */
+	rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+	/* Ack the event */
+	rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS);
+
+	spin_unlock(&rtc->lock);
+
+	if (val & RTC_IRQ1_FREQ_EN) {
+		if (val & RTC_IRQ1_FREQ_1HZ)
+			event |= RTC_UF;
+		else
+			event |= RTC_PF;
+	}
+
+	rtc_update_irq(rtc->rtc_dev, 1, event);
+
+	return IRQ_HANDLED;
+}
+
+static struct rtc_class_ops armada38x_rtc_ops = {
+	.read_time = armada38x_rtc_read_time,
+	.set_time = armada38x_rtc_set_time,
+	.read_alarm = armada38x_rtc_read_alarm,
+	.set_alarm = armada38x_rtc_set_alarm,
+	.alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
+};
+
+static __init int armada38x_rtc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct armada38x_rtc *rtc;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
+			    GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	spin_lock_init(&rtc->lock);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
+	rtc->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rtc->regs))
+		return PTR_ERR(rtc->regs);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
+	rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rtc->regs_soc))
+		return PTR_ERR(rtc->regs_soc);
+
+	rtc->irq = platform_get_irq(pdev, 0);
+
+	if (rtc->irq < 0) {
+		dev_err(&pdev->dev, "no irq\n");
+		return rtc->irq;
+	}
+	if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
+				0, pdev->name, rtc) < 0) {
+		dev_warn(&pdev->dev, "Interrupt not available.\n");
+		rtc->irq = -1;
+		/*
+		 * If there is no interrupt available then we can't
+		 * use the alarm
+		 */
+		armada38x_rtc_ops.set_alarm = NULL;
+		armada38x_rtc_ops.alarm_irq_enable = NULL;
+	}
+	platform_set_drvdata(pdev, rtc);
+	if (rtc->irq != -1)
+		device_init_wakeup(&pdev->dev, 1);
+
+	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+					&armada38x_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc_dev)) {
+		ret = PTR_ERR(rtc->rtc_dev);
+		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int armada38x_rtc_suspend(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+
+		return enable_irq_wake(rtc->irq);
+	}
+
+	return 0;
+}
+
+static int armada38x_rtc_resume(struct device *dev)
+{
+	if (device_may_wakeup(dev)) {
+		struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+
+		return disable_irq_wake(rtc->irq);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
+			 armada38x_rtc_suspend, armada38x_rtc_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id armada38x_rtc_of_match_table[] = {
+	{ .compatible = "marvell,armada-380-rtc", },
+	{}
+};
+#endif
+
+static struct platform_driver armada38x_rtc_driver = {
+	.driver		= {
+		.name	= "armada38x-rtc",
+		.pm	= &armada38x_rtc_pm_ops,
+		.of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
+	},
+};
+
+module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe);
+
+MODULE_DESCRIPTION("Marvell Armada 38x RTC driver");
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 6b9aaf1..2183fd2 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -313,7 +313,7 @@
 	.alarm_irq_enable = at91_rtc_alarm_irq_enable,
 };
 
-static struct regmap_config gpbr_regmap_config = {
+static const struct regmap_config gpbr_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = 4,
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
new file mode 100644
index 0000000..8c3bfcb
--- /dev/null
+++ b/drivers/rtc/rtc-ds1685.c
@@ -0,0 +1,2252 @@
+/*
+ * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time
+ * chips.
+ *
+ * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
+ *
+ * References:
+ *    DS1685/DS1687 3V/5V Real-Time Clocks, 19-5215, Rev 4/10.
+ *    DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10.
+ *    DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105.
+ *    Application Note 90, Using the Multiplex Bus RTC Extended Features.
+ *
+ * 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/bcd.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+
+#include <linux/rtc/ds1685.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#define DRV_VERSION	"0.42.0"
+
+
+/* ----------------------------------------------------------------------- */
+/* Standard read/write functions if platform does not provide overrides */
+
+/**
+ * ds1685_read - read a value from an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to read.
+ */
+static u8
+ds1685_read(struct ds1685_priv *rtc, int reg)
+{
+	return readb((u8 __iomem *)rtc->regs +
+		     (reg * rtc->regstep));
+}
+
+/**
+ * ds1685_write - write a value to an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to write.
+ * @value: value to write to the register.
+ */
+static void
+ds1685_write(struct ds1685_priv *rtc, int reg, u8 value)
+{
+	writeb(value, ((u8 __iomem *)rtc->regs +
+		       (reg * rtc->regstep)));
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Inlined functions */
+
+/**
+ * ds1685_rtc_bcd2bin - bcd2bin wrapper in case platform doesn't support BCD.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @val: u8 time value to consider converting.
+ * @bcd_mask: u8 mask value if BCD mode is used.
+ * @bin_mask: u8 mask value if BIN mode is used.
+ *
+ * Returns the value, converted to BIN if originally in BCD and bcd_mode TRUE.
+ */
+static inline u8
+ds1685_rtc_bcd2bin(struct ds1685_priv *rtc, u8 val, u8 bcd_mask, u8 bin_mask)
+{
+	if (rtc->bcd_mode)
+		return (bcd2bin(val) & bcd_mask);
+
+	return (val & bin_mask);
+}
+
+/**
+ * ds1685_rtc_bin2bcd - bin2bcd wrapper in case platform doesn't support BCD.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @val: u8 time value to consider converting.
+ * @bin_mask: u8 mask value if BIN mode is used.
+ * @bcd_mask: u8 mask value if BCD mode is used.
+ *
+ * Returns the value, converted to BCD if originally in BIN and bcd_mode TRUE.
+ */
+static inline u8
+ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask)
+{
+	if (rtc->bcd_mode)
+		return (bin2bcd(val) & bcd_mask);
+
+	return (val & bin_mask);
+}
+
+/**
+ * ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0.
+ * @rtc: pointer to the ds1685 rtc structure.
+ */
+static inline void
+ds1685_rtc_switch_to_bank0(struct ds1685_priv *rtc)
+{
+	rtc->write(rtc, RTC_CTRL_A,
+		   (rtc->read(rtc, RTC_CTRL_A) & ~(RTC_CTRL_A_DV0)));
+}
+
+/**
+ * ds1685_rtc_switch_to_bank1 - switch the rtc to bank 1.
+ * @rtc: pointer to the ds1685 rtc structure.
+ */
+static inline void
+ds1685_rtc_switch_to_bank1(struct ds1685_priv *rtc)
+{
+	rtc->write(rtc, RTC_CTRL_A,
+		   (rtc->read(rtc, RTC_CTRL_A) | RTC_CTRL_A_DV0));
+}
+
+/**
+ * ds1685_rtc_begin_data_access - prepare the rtc for data access.
+ * @rtc: pointer to the ds1685 rtc structure.
+ *
+ * This takes several steps to prepare the rtc for access to get/set time
+ * and alarm values from the rtc registers:
+ *  - Sets the SET bit in Control Register B.
+ *  - Reads Ext Control Register 4A and checks the INCR bit.
+ *  - If INCR is active, a short delay is added before Ext Control Register 4A
+ *    is read again in a loop until INCR is inactive.
+ *  - Switches the rtc to bank 1.  This allows access to all relevant
+ *    data for normal rtc operation, as bank 0 contains only the nvram.
+ */
+static inline void
+ds1685_rtc_begin_data_access(struct ds1685_priv *rtc)
+{
+	/* Set the SET bit in Ctrl B */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET));
+
+	/* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */
+	while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR)
+		cpu_relax();
+
+	/* Switch to Bank 1 */
+	ds1685_rtc_switch_to_bank1(rtc);
+}
+
+/**
+ * ds1685_rtc_end_data_access - end data access on the rtc.
+ * @rtc: pointer to the ds1685 rtc structure.
+ *
+ * This ends what was started by ds1685_rtc_begin_data_access:
+ *  - Switches the rtc back to bank 0.
+ *  - Clears the SET bit in Control Register B.
+ */
+static inline void
+ds1685_rtc_end_data_access(struct ds1685_priv *rtc)
+{
+	/* Switch back to Bank 0 */
+	ds1685_rtc_switch_to_bank1(rtc);
+
+	/* Clear the SET bit in Ctrl B */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET)));
+}
+
+/**
+ * ds1685_rtc_begin_ctrl_access - prepare the rtc for ctrl access.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @flags: irq flags variable for spin_lock_irqsave.
+ *
+ * This takes several steps to prepare the rtc for access to read just the
+ * control registers:
+ *  - Sets a spinlock on the rtc IRQ.
+ *  - Switches the rtc to bank 1.  This allows access to the two extended
+ *    control registers.
+ *
+ * Only use this where you are certain another lock will not be held.
+ */
+static inline void
+ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+{
+	spin_lock_irqsave(&rtc->lock, flags);
+	ds1685_rtc_switch_to_bank1(rtc);
+}
+
+/**
+ * ds1685_rtc_end_ctrl_access - end ctrl access on the rtc.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @flags: irq flags variable for spin_unlock_irqrestore.
+ *
+ * This ends what was started by ds1685_rtc_begin_ctrl_access:
+ *  - Switches the rtc back to bank 0.
+ *  - Unsets the spinlock on the rtc IRQ.
+ */
+static inline void
+ds1685_rtc_end_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+{
+	ds1685_rtc_switch_to_bank0(rtc);
+	spin_unlock_irqrestore(&rtc->lock, flags);
+}
+
+/**
+ * ds1685_rtc_get_ssn - retrieve the silicon serial number.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @ssn: u8 array to hold the bits of the silicon serial number.
+ *
+ * This number starts at 0x40, and is 8-bytes long, ending at 0x47. The
+ * first byte is the model number, the next six bytes are the serial number
+ * digits, and the final byte is a CRC check byte.  Together, they form the
+ * silicon serial number.
+ *
+ * These values are stored in bank1, so ds1685_rtc_switch_to_bank1 must be
+ * called first before calling this function, else data will be read out of
+ * the bank0 NVRAM.  Be sure to call ds1685_rtc_switch_to_bank0 when done.
+ */
+static inline void
+ds1685_rtc_get_ssn(struct ds1685_priv *rtc, u8 *ssn)
+{
+	ssn[0] = rtc->read(rtc, RTC_BANK1_SSN_MODEL);
+	ssn[1] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_1);
+	ssn[2] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_2);
+	ssn[3] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_3);
+	ssn[4] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_4);
+	ssn[5] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_5);
+	ssn[6] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_6);
+	ssn[7] = rtc->read(rtc, RTC_BANK1_SSN_CRC);
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Read/Set Time & Alarm functions */
+
+/**
+ * ds1685_rtc_read_time - reads the time registers.
+ * @dev: pointer to device structure.
+ * @tm: pointer to rtc_time structure.
+ */
+static int
+ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrlb, century;
+	u8 seconds, minutes, hours, wday, mday, month, years;
+
+	/* Fetch the time info from the RTC registers. */
+	ds1685_rtc_begin_data_access(rtc);
+	seconds = rtc->read(rtc, RTC_SECS);
+	minutes = rtc->read(rtc, RTC_MINS);
+	hours   = rtc->read(rtc, RTC_HRS);
+	wday    = rtc->read(rtc, RTC_WDAY);
+	mday    = rtc->read(rtc, RTC_MDAY);
+	month   = rtc->read(rtc, RTC_MONTH);
+	years   = rtc->read(rtc, RTC_YEAR);
+	century = rtc->read(rtc, RTC_CENTURY);
+	ctrlb   = rtc->read(rtc, RTC_CTRL_B);
+	ds1685_rtc_end_data_access(rtc);
+
+	/* bcd2bin if needed, perform fixups, and store to rtc_time. */
+	years        = ds1685_rtc_bcd2bin(rtc, years, RTC_YEAR_BCD_MASK,
+					  RTC_YEAR_BIN_MASK);
+	century      = ds1685_rtc_bcd2bin(rtc, century, RTC_CENTURY_MASK,
+					  RTC_CENTURY_MASK);
+	tm->tm_sec   = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK,
+					  RTC_SECS_BIN_MASK);
+	tm->tm_min   = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK,
+					  RTC_MINS_BIN_MASK);
+	tm->tm_hour  = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK,
+					  RTC_HRS_24_BIN_MASK);
+	tm->tm_wday  = (ds1685_rtc_bcd2bin(rtc, wday, RTC_WDAY_MASK,
+					   RTC_WDAY_MASK) - 1);
+	tm->tm_mday  = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
+					  RTC_MDAY_BIN_MASK);
+	tm->tm_mon   = (ds1685_rtc_bcd2bin(rtc, month, RTC_MONTH_BCD_MASK,
+					   RTC_MONTH_BIN_MASK) - 1);
+	tm->tm_year  = ((years + (century * 100)) - 1900);
+	tm->tm_yday  = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+	tm->tm_isdst = 0; /* RTC has hardcoded timezone, so don't use. */
+
+	return rtc_valid_tm(tm);
+}
+
+/**
+ * ds1685_rtc_set_time - sets the time registers.
+ * @dev: pointer to device structure.
+ * @tm: pointer to rtc_time structure.
+ */
+static int
+ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrlb, seconds, minutes, hours, wday, mday, month, years, century;
+
+	/* Fetch the time info from rtc_time. */
+	seconds = ds1685_rtc_bin2bcd(rtc, tm->tm_sec, RTC_SECS_BIN_MASK,
+				     RTC_SECS_BCD_MASK);
+	minutes = ds1685_rtc_bin2bcd(rtc, tm->tm_min, RTC_MINS_BIN_MASK,
+				     RTC_MINS_BCD_MASK);
+	hours   = ds1685_rtc_bin2bcd(rtc, tm->tm_hour, RTC_HRS_24_BIN_MASK,
+				     RTC_HRS_24_BCD_MASK);
+	wday    = ds1685_rtc_bin2bcd(rtc, (tm->tm_wday + 1), RTC_WDAY_MASK,
+				     RTC_WDAY_MASK);
+	mday    = ds1685_rtc_bin2bcd(rtc, tm->tm_mday, RTC_MDAY_BIN_MASK,
+				     RTC_MDAY_BCD_MASK);
+	month   = ds1685_rtc_bin2bcd(rtc, (tm->tm_mon + 1), RTC_MONTH_BIN_MASK,
+				     RTC_MONTH_BCD_MASK);
+	years   = ds1685_rtc_bin2bcd(rtc, (tm->tm_year % 100),
+				     RTC_YEAR_BIN_MASK, RTC_YEAR_BCD_MASK);
+	century = ds1685_rtc_bin2bcd(rtc, ((tm->tm_year + 1900) / 100),
+				     RTC_CENTURY_MASK, RTC_CENTURY_MASK);
+
+	/*
+	 * Perform Sanity Checks:
+	 *   - Months: !> 12, Month Day != 0.
+	 *   - Month Day !> Max days in current month.
+	 *   - Hours !>= 24, Mins !>= 60, Secs !>= 60, & Weekday !> 7.
+	 */
+	if ((tm->tm_mon > 11) || (mday == 0))
+		return -EDOM;
+
+	if (tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year))
+		return -EDOM;
+
+	if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) ||
+	    (tm->tm_sec >= 60)  || (wday > 7))
+		return -EDOM;
+
+	/*
+	 * Set the data mode to use and store the time values in the
+	 * RTC registers.
+	 */
+	ds1685_rtc_begin_data_access(rtc);
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	if (rtc->bcd_mode)
+		ctrlb &= ~(RTC_CTRL_B_DM);
+	else
+		ctrlb |= RTC_CTRL_B_DM;
+	rtc->write(rtc, RTC_CTRL_B, ctrlb);
+	rtc->write(rtc, RTC_SECS, seconds);
+	rtc->write(rtc, RTC_MINS, minutes);
+	rtc->write(rtc, RTC_HRS, hours);
+	rtc->write(rtc, RTC_WDAY, wday);
+	rtc->write(rtc, RTC_MDAY, mday);
+	rtc->write(rtc, RTC_MONTH, month);
+	rtc->write(rtc, RTC_YEAR, years);
+	rtc->write(rtc, RTC_CENTURY, century);
+	ds1685_rtc_end_data_access(rtc);
+
+	return 0;
+}
+
+/**
+ * ds1685_rtc_read_alarm - reads the alarm registers.
+ * @dev: pointer to device structure.
+ * @alrm: pointer to rtc_wkalrm structure.
+ *
+ * There are three primary alarm registers: seconds, minutes, and hours.
+ * A fourth alarm register for the month date is also available in bank1 for
+ * kickstart/wakeup features.  The DS1685/DS1687 manual states that a
+ * "don't care" value ranging from 0xc0 to 0xff may be written into one or
+ * more of the three alarm bytes to act as a wildcard value.  The fourth
+ * byte doesn't support a "don't care" value.
+ */
+static int
+ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
+
+	/* Fetch the alarm info from the RTC alarm registers. */
+	ds1685_rtc_begin_data_access(rtc);
+	seconds	= rtc->read(rtc, RTC_SECS_ALARM);
+	minutes	= rtc->read(rtc, RTC_MINS_ALARM);
+	hours	= rtc->read(rtc, RTC_HRS_ALARM);
+	mday	= rtc->read(rtc, RTC_MDAY_ALARM);
+	ctrlb	= rtc->read(rtc, RTC_CTRL_B);
+	ctrlc	= rtc->read(rtc, RTC_CTRL_C);
+	ds1685_rtc_end_data_access(rtc);
+
+	/* Check month date. */
+	if (!(mday >= 1) && (mday <= 31))
+		return -EDOM;
+
+	/*
+	 * Check the three alarm bytes.
+	 *
+	 * The Linux RTC system doesn't support the "don't care" capability
+	 * of this RTC chip.  We check for it anyways in case support is
+	 * added in the future.
+	 */
+	if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+		alrm->time.tm_sec = -1;
+	else
+		alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
+						       RTC_SECS_BCD_MASK,
+						       RTC_SECS_BIN_MASK);
+
+	if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+		alrm->time.tm_min = -1;
+	else
+		alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
+						       RTC_MINS_BCD_MASK,
+						       RTC_MINS_BIN_MASK);
+
+	if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+		alrm->time.tm_hour = -1;
+	else
+		alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
+							RTC_HRS_24_BCD_MASK,
+							RTC_HRS_24_BIN_MASK);
+
+	/* Write the data to rtc_wkalrm. */
+	alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
+						RTC_MDAY_BIN_MASK);
+	alrm->time.tm_mon = -1;
+	alrm->time.tm_year = -1;
+	alrm->time.tm_wday = -1;
+	alrm->time.tm_yday = -1;
+	alrm->time.tm_isdst = -1;
+	alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE);
+	alrm->pending = !!(ctrlc & RTC_CTRL_C_AF);
+
+	return 0;
+}
+
+/**
+ * ds1685_rtc_set_alarm - sets the alarm in registers.
+ * @dev: pointer to device structure.
+ * @alrm: pointer to rtc_wkalrm structure.
+ */
+static int
+ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrlb, seconds, minutes, hours, mday;
+
+	/* Fetch the alarm info and convert to BCD. */
+	seconds	= ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec,
+				     RTC_SECS_BIN_MASK,
+				     RTC_SECS_BCD_MASK);
+	minutes	= ds1685_rtc_bin2bcd(rtc, alrm->time.tm_min,
+				     RTC_MINS_BIN_MASK,
+				     RTC_MINS_BCD_MASK);
+	hours	= ds1685_rtc_bin2bcd(rtc, alrm->time.tm_hour,
+				     RTC_HRS_24_BIN_MASK,
+				     RTC_HRS_24_BCD_MASK);
+	mday	= ds1685_rtc_bin2bcd(rtc, alrm->time.tm_mday,
+				     RTC_MDAY_BIN_MASK,
+				     RTC_MDAY_BCD_MASK);
+
+	/* Check the month date for validity. */
+	if (!(mday >= 1) && (mday <= 31))
+		return -EDOM;
+
+	/*
+	 * Check the three alarm bytes.
+	 *
+	 * The Linux RTC system doesn't support the "don't care" capability
+	 * of this RTC chip because rtc_valid_tm tries to validate every
+	 * field, and we only support four fields.  We put the support
+	 * here anyways for the future.
+	 */
+	if (unlikely((seconds >= 0xc0) && (seconds <= 0xff)))
+		seconds = 0xff;
+
+	if (unlikely((minutes >= 0xc0) && (minutes <= 0xff)))
+		minutes = 0xff;
+
+	if (unlikely((hours >= 0xc0) && (hours <= 0xff)))
+		hours = 0xff;
+
+	alrm->time.tm_mon	= -1;
+	alrm->time.tm_year	= -1;
+	alrm->time.tm_wday	= -1;
+	alrm->time.tm_yday	= -1;
+	alrm->time.tm_isdst	= -1;
+
+	/* Disable the alarm interrupt first. */
+	ds1685_rtc_begin_data_access(rtc);
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	rtc->write(rtc, RTC_CTRL_B, (ctrlb & ~(RTC_CTRL_B_AIE)));
+
+	/* Read ctrlc to clear RTC_CTRL_C_AF. */
+	rtc->read(rtc, RTC_CTRL_C);
+
+	/*
+	 * Set the data mode to use and store the time values in the
+	 * RTC registers.
+	 */
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	if (rtc->bcd_mode)
+		ctrlb &= ~(RTC_CTRL_B_DM);
+	else
+		ctrlb |= RTC_CTRL_B_DM;
+	rtc->write(rtc, RTC_CTRL_B, ctrlb);
+	rtc->write(rtc, RTC_SECS_ALARM, seconds);
+	rtc->write(rtc, RTC_MINS_ALARM, minutes);
+	rtc->write(rtc, RTC_HRS_ALARM, hours);
+	rtc->write(rtc, RTC_MDAY_ALARM, mday);
+
+	/* Re-enable the alarm if needed. */
+	if (alrm->enabled) {
+		ctrlb = rtc->read(rtc, RTC_CTRL_B);
+		ctrlb |= RTC_CTRL_B_AIE;
+		rtc->write(rtc, RTC_CTRL_B, ctrlb);
+	}
+
+	/* Done! */
+	ds1685_rtc_end_data_access(rtc);
+
+	return 0;
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* /dev/rtcX Interface functions */
+
+#ifdef CONFIG_RTC_INTF_DEV
+/**
+ * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off.
+ * @dev: pointer to device structure.
+ * @enabled: flag indicating whether to enable or disable.
+ */
+static int
+ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+	struct ds1685_priv *rtc = dev_get_drvdata(dev);
+	unsigned long flags = 0;
+
+	/* Enable/disable the Alarm IRQ-Enable flag. */
+	spin_lock_irqsave(&rtc->lock, flags);
+
+	/* Flip the requisite interrupt-enable bit. */
+	if (enabled)
+		rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) |
+					     RTC_CTRL_B_AIE));
+	else
+		rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) &
+					     ~(RTC_CTRL_B_AIE)));
+
+	/* Read Control C to clear all the flag bits. */
+	rtc->read(rtc, RTC_CTRL_C);
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	return 0;
+}
+#endif
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* IRQ handler & workqueue. */
+
+/**
+ * ds1685_rtc_irq_handler - IRQ handler.
+ * @irq: IRQ number.
+ * @dev_id: platform device pointer.
+ */
+static irqreturn_t
+ds1685_rtc_irq_handler(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrlb, ctrlc;
+	unsigned long events = 0;
+	u8 num_irqs = 0;
+
+	/* Abort early if the device isn't ready yet (i.e., DEBUG_SHIRQ). */
+	if (unlikely(!rtc))
+		return IRQ_HANDLED;
+
+	/* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */
+	spin_lock(&rtc->lock);
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	ctrlc = rtc->read(rtc, RTC_CTRL_C);
+
+	/* Is the IRQF bit set? */
+	if (likely(ctrlc & RTC_CTRL_C_IRQF)) {
+		/*
+		 * We need to determine if it was one of the standard
+		 * events: PF, AF, or UF.  If so, we handle them and
+		 * update the RTC core.
+		 */
+		if (likely(ctrlc & RTC_CTRL_B_PAU_MASK)) {
+			events = RTC_IRQF;
+
+			/* Check for a periodic interrupt. */
+			if ((ctrlb & RTC_CTRL_B_PIE) &&
+			    (ctrlc & RTC_CTRL_C_PF)) {
+				events |= RTC_PF;
+				num_irqs++;
+			}
+
+			/* Check for an alarm interrupt. */
+			if ((ctrlb & RTC_CTRL_B_AIE) &&
+			    (ctrlc & RTC_CTRL_C_AF)) {
+				events |= RTC_AF;
+				num_irqs++;
+			}
+
+			/* Check for an update interrupt. */
+			if ((ctrlb & RTC_CTRL_B_UIE) &&
+			    (ctrlc & RTC_CTRL_C_UF)) {
+				events |= RTC_UF;
+				num_irqs++;
+			}
+
+			rtc_update_irq(rtc->dev, num_irqs, events);
+		} else {
+			/*
+			 * One of the "extended" interrupts was received that
+			 * is not recognized by the RTC core.  These need to
+			 * be handled in task context as they can call other
+			 * functions and the time spent in irq context needs
+			 * to be minimized.  Schedule them into a workqueue
+			 * and inform the RTC core that the IRQs were handled.
+			 */
+			spin_unlock(&rtc->lock);
+			schedule_work(&rtc->work);
+			rtc_update_irq(rtc->dev, 0, 0);
+			return IRQ_HANDLED;
+		}
+	}
+	spin_unlock(&rtc->lock);
+
+	return events ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * ds1685_rtc_work_queue - work queue handler.
+ * @work: work_struct containing data to work on in task context.
+ */
+static void
+ds1685_rtc_work_queue(struct work_struct *work)
+{
+	struct ds1685_priv *rtc = container_of(work,
+					       struct ds1685_priv, work);
+	struct platform_device *pdev = to_platform_device(&rtc->dev->dev);
+	struct mutex *rtc_mutex = &rtc->dev->ops_lock;
+	u8 ctrl4a, ctrl4b;
+
+	mutex_lock(rtc_mutex);
+
+	ds1685_rtc_switch_to_bank1(rtc);
+	ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+	ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+
+	/*
+	 * Check for a kickstart interrupt. With Vcc applied, this
+	 * typically means that the power button was pressed, so we
+	 * begin the shutdown sequence.
+	 */
+	if ((ctrl4b & RTC_CTRL_4B_KSE) && (ctrl4a & RTC_CTRL_4A_KF)) {
+		/* Briefly disable kickstarts to debounce button presses. */
+		rtc->write(rtc, RTC_EXT_CTRL_4B,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4B) &
+			    ~(RTC_CTRL_4B_KSE)));
+
+		/* Clear the kickstart flag. */
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (ctrl4a & ~(RTC_CTRL_4A_KF)));
+
+
+		/*
+		 * Sleep 500ms before re-enabling kickstarts.  This allows
+		 * adequate time to avoid reading signal jitter as additional
+		 * button presses.
+		 */
+		msleep(500);
+		rtc->write(rtc, RTC_EXT_CTRL_4B,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4B) |
+			    RTC_CTRL_4B_KSE));
+
+		/* Call the platform pre-poweroff function. Else, shutdown. */
+		if (rtc->prepare_poweroff != NULL)
+			rtc->prepare_poweroff();
+		else
+			ds1685_rtc_poweroff(pdev);
+	}
+
+	/*
+	 * Check for a wake-up interrupt.  With Vcc applied, this is
+	 * essentially a second alarm interrupt, except it takes into
+	 * account the 'date' register in bank1 in addition to the
+	 * standard three alarm registers.
+	 */
+	if ((ctrl4b & RTC_CTRL_4B_WIE) && (ctrl4a & RTC_CTRL_4A_WF)) {
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (ctrl4a & ~(RTC_CTRL_4A_WF)));
+
+		/* Call the platform wake_alarm function if defined. */
+		if (rtc->wake_alarm != NULL)
+			rtc->wake_alarm();
+		else
+			dev_warn(&pdev->dev,
+				 "Wake Alarm IRQ just occurred!\n");
+	}
+
+	/*
+	 * Check for a ram-clear interrupt.  This happens if RIE=1 and RF=0
+	 * when RCE=1 in 4B.  This clears all NVRAM bytes in bank0 by setting
+	 * each byte to a logic 1.  This has no effect on any extended
+	 * NV-SRAM that might be present, nor on the time/calendar/alarm
+	 * registers.  After a ram-clear is completed, there is a minimum
+	 * recovery time of ~150ms in which all reads/writes are locked out.
+	 * NOTE: A ram-clear can still occur if RCE=1 and RIE=0.  We cannot
+	 * catch this scenario.
+	 */
+	if ((ctrl4b & RTC_CTRL_4B_RIE) && (ctrl4a & RTC_CTRL_4A_RF)) {
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (ctrl4a & ~(RTC_CTRL_4A_RF)));
+		msleep(150);
+
+		/* Call the platform post_ram_clear function if defined. */
+		if (rtc->post_ram_clear != NULL)
+			rtc->post_ram_clear();
+		else
+			dev_warn(&pdev->dev,
+				 "RAM-Clear IRQ just occurred!\n");
+	}
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	mutex_unlock(rtc_mutex);
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* ProcFS interface */
+
+#ifdef CONFIG_PROC_FS
+#define NUM_REGS	6	/* Num of control registers. */
+#define NUM_BITS	8	/* Num bits per register. */
+#define NUM_SPACES	4	/* Num spaces between each bit. */
+
+/*
+ * Periodic Interrupt Rates.
+ */
+static const char *ds1685_rtc_pirq_rate[16] = {
+	"none", "3.90625ms", "7.8125ms", "0.122070ms", "0.244141ms",
+	"0.488281ms", "0.9765625ms", "1.953125ms", "3.90625ms", "7.8125ms",
+	"15.625ms", "31.25ms", "62.5ms", "125ms", "250ms", "500ms"
+};
+
+/*
+ * Square-Wave Output Frequencies.
+ */
+static const char *ds1685_rtc_sqw_freq[16] = {
+	"none", "256Hz", "128Hz", "8192Hz", "4096Hz", "2048Hz", "1024Hz",
+	"512Hz", "256Hz", "128Hz", "64Hz", "32Hz", "16Hz", "8Hz", "4Hz", "2Hz"
+};
+
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+/**
+ * ds1685_rtc_print_regs - helper function to print register values.
+ * @hex: hex byte to convert into binary bits.
+ * @dest: destination char array.
+ *
+ * This is basically a hex->binary function, just with extra spacing between
+ * the digits.  It only works on 1-byte values (8 bits).
+ */
+static char*
+ds1685_rtc_print_regs(u8 hex, char *dest)
+{
+	u32 i, j;
+	char *tmp = dest;
+
+	for (i = 0; i < NUM_BITS; i++) {
+		*tmp++ = ((hex & 0x80) != 0 ? '1' : '0');
+		for (j = 0; j < NUM_SPACES; j++)
+			*tmp++ = ' ';
+		hex <<= 1;
+	}
+	*tmp++ = '\0';
+
+	return dest;
+}
+#endif
+
+/**
+ * ds1685_rtc_proc - procfs access function.
+ * @dev: pointer to device structure.
+ * @seq: pointer to seq_file structure.
+ */
+static int
+ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8];
+	char *model = '\0';
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+	char bits[NUM_REGS][(NUM_BITS * NUM_SPACES) + NUM_BITS + 1];
+#endif
+
+	/* Read all the relevant data from the control registers. */
+	ds1685_rtc_switch_to_bank1(rtc);
+	ds1685_rtc_get_ssn(rtc, ssn);
+	ctrla = rtc->read(rtc, RTC_CTRL_A);
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	ctrlc = rtc->read(rtc, RTC_CTRL_C);
+	ctrld = rtc->read(rtc, RTC_CTRL_D);
+	ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+	ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	/* Determine the RTC model. */
+	switch (ssn[0]) {
+	case RTC_MODEL_DS1685:
+		model = "DS1685/DS1687\0";
+		break;
+	case RTC_MODEL_DS1689:
+		model = "DS1689/DS1693\0";
+		break;
+	case RTC_MODEL_DS17285:
+		model = "DS17285/DS17287\0";
+		break;
+	case RTC_MODEL_DS17485:
+		model = "DS17485/DS17487\0";
+		break;
+	case RTC_MODEL_DS17885:
+		model = "DS17885/DS17887\0";
+		break;
+	default:
+		model = "Unknown\0";
+		break;
+	}
+
+	/* Print out the information. */
+	seq_printf(seq,
+	   "Model\t\t: %s\n"
+	   "Oscillator\t: %s\n"
+	   "12/24hr\t\t: %s\n"
+	   "DST\t\t: %s\n"
+	   "Data mode\t: %s\n"
+	   "Battery\t\t: %s\n"
+	   "Aux batt\t: %s\n"
+	   "Update IRQ\t: %s\n"
+	   "Periodic IRQ\t: %s\n"
+	   "Periodic Rate\t: %s\n"
+	   "SQW Freq\t: %s\n"
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+	   "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
+	   "Register Status\t:\n"
+	   "   Ctrl A\t: UIP  DV2  DV1  DV0  RS3  RS2  RS1  RS0\n"
+	   "\t\t:  %s\n"
+	   "   Ctrl B\t: SET  PIE  AIE  UIE  SQWE  DM  2412 DSE\n"
+	   "\t\t:  %s\n"
+	   "   Ctrl C\t: IRQF  PF   AF   UF  ---  ---  ---  ---\n"
+	   "\t\t:  %s\n"
+	   "   Ctrl D\t: VRT  ---  ---  ---  ---  ---  ---  ---\n"
+	   "\t\t:  %s\n"
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+	   "   Ctrl 4A\t: VRT2 INCR BME  ---  PAB   RF   WF   KF\n"
+#else
+	   "   Ctrl 4A\t: VRT2 INCR ---  ---  PAB   RF   WF   KF\n"
+#endif
+	   "\t\t:  %s\n"
+	   "   Ctrl 4B\t: ABE  E32k  CS  RCE  PRS  RIE  WIE  KSE\n"
+	   "\t\t:  %s\n",
+#else
+	   "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+#endif
+	   model,
+	   ((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
+	   ((ctrlb & RTC_CTRL_B_2412) ? "24-hour" : "12-hour"),
+	   ((ctrlb & RTC_CTRL_B_DSE) ? "enabled" : "disabled"),
+	   ((ctrlb & RTC_CTRL_B_DM) ? "binary" : "BCD"),
+	   ((ctrld & RTC_CTRL_D_VRT) ? "ok" : "exhausted or n/a"),
+	   ((ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "exhausted or n/a"),
+	   ((ctrlb & RTC_CTRL_B_UIE) ? "yes" : "no"),
+	   ((ctrlb & RTC_CTRL_B_PIE) ? "yes" : "no"),
+	   (!(ctrl4b & RTC_CTRL_4B_E32K) ?
+	    ds1685_rtc_pirq_rate[(ctrla & RTC_CTRL_A_RS_MASK)] : "none"),
+	   (!((ctrl4b & RTC_CTRL_4B_E32K)) ?
+	    ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+	   ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7],
+	   ds1685_rtc_print_regs(ctrla, bits[0]),
+	   ds1685_rtc_print_regs(ctrlb, bits[1]),
+	   ds1685_rtc_print_regs(ctrlc, bits[2]),
+	   ds1685_rtc_print_regs(ctrld, bits[3]),
+	   ds1685_rtc_print_regs(ctrl4a, bits[4]),
+	   ds1685_rtc_print_regs(ctrl4b, bits[5]));
+#else
+	   ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7]);
+#endif
+	return 0;
+}
+#else
+#define ds1685_rtc_proc NULL
+#endif /* CONFIG_PROC_FS */
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* RTC Class operations */
+
+static const struct rtc_class_ops
+ds1685_rtc_ops = {
+	.proc = ds1685_rtc_proc,
+	.read_time = ds1685_rtc_read_time,
+	.set_time = ds1685_rtc_set_time,
+	.read_alarm = ds1685_rtc_read_alarm,
+	.set_alarm = ds1685_rtc_set_alarm,
+	.alarm_irq_enable = ds1685_rtc_alarm_irq_enable,
+};
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* SysFS interface */
+
+#ifdef CONFIG_SYSFS
+/**
+ * ds1685_rtc_sysfs_nvram_read - reads rtc nvram via sysfs.
+ * @file: pointer to file structure.
+ * @kobj: pointer to kobject structure.
+ * @bin_attr: pointer to bin_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @pos: current file position pointer.
+ * @size: size of the data to read.
+ */
+static ssize_t
+ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	ssize_t count;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	/* Read NVRAM in time and bank0 registers. */
+	for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0;
+	     count++, size--) {
+		if (count < NVRAM_SZ_TIME)
+			*buf++ = rtc->read(rtc, (NVRAM_TIME_BASE + pos++));
+		else
+			*buf++ = rtc->read(rtc, (NVRAM_BANK0_BASE + pos++));
+	}
+
+#ifndef CONFIG_RTC_DRV_DS1689
+	if (size > 0) {
+		ds1685_rtc_switch_to_bank1(rtc);
+
+#ifndef CONFIG_RTC_DRV_DS1685
+		/* Enable burst-mode on DS17x85/DS17x87 */
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4A) |
+			    RTC_CTRL_4A_BME));
+
+		/* We need one write to RTC_BANK1_RAM_ADDR_LSB to start
+		 * reading with burst-mode */
+		rtc->write(rtc, RTC_BANK1_RAM_ADDR_LSB,
+			   (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+
+		/* Read NVRAM in bank1 registers. */
+		for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ;
+		     count++, size--) {
+#ifdef CONFIG_RTC_DRV_DS1685
+			/* DS1685/DS1687 has to write to RTC_BANK1_RAM_ADDR
+			 * before each read. */
+			rtc->write(rtc, RTC_BANK1_RAM_ADDR,
+				   (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+			*buf++ = rtc->read(rtc, RTC_BANK1_RAM_DATA_PORT);
+			pos++;
+		}
+
+#ifndef CONFIG_RTC_DRV_DS1685
+		/* Disable burst-mode on DS17x85/DS17x87 */
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+			    ~(RTC_CTRL_4A_BME)));
+#endif
+		ds1685_rtc_switch_to_bank0(rtc);
+	}
+#endif /* !CONFIG_RTC_DRV_DS1689 */
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	/*
+	 * XXX: Bug? this appears to cause the function to get executed
+	 * several times in succession.  But it's the only way to actually get
+	 * data written out to a file.
+	 */
+	return count;
+}
+
+/**
+ * ds1685_rtc_sysfs_nvram_write - writes rtc nvram via sysfs.
+ * @file: pointer to file structure.
+ * @kobj: pointer to kobject structure.
+ * @bin_attr: pointer to bin_attribute structure.
+ * @buf: pointer to char array to hold the input.
+ * @pos: current file position pointer.
+ * @size: size of the data to write.
+ */
+static ssize_t
+ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	ssize_t count;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&rtc->lock, flags);
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	/* Write NVRAM in time and bank0 registers. */
+	for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0;
+	     count++, size--)
+		if (count < NVRAM_SZ_TIME)
+			rtc->write(rtc, (NVRAM_TIME_BASE + pos++),
+				   *buf++);
+		else
+			rtc->write(rtc, (NVRAM_BANK0_BASE), *buf++);
+
+#ifndef CONFIG_RTC_DRV_DS1689
+	if (size > 0) {
+		ds1685_rtc_switch_to_bank1(rtc);
+
+#ifndef CONFIG_RTC_DRV_DS1685
+		/* Enable burst-mode on DS17x85/DS17x87 */
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4A) |
+			    RTC_CTRL_4A_BME));
+
+		/* We need one write to RTC_BANK1_RAM_ADDR_LSB to start
+		 * writing with burst-mode */
+		rtc->write(rtc, RTC_BANK1_RAM_ADDR_LSB,
+			   (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+
+		/* Write NVRAM in bank1 registers. */
+		for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ;
+		     count++, size--) {
+#ifdef CONFIG_RTC_DRV_DS1685
+			/* DS1685/DS1687 has to write to RTC_BANK1_RAM_ADDR
+			 * before each read. */
+			rtc->write(rtc, RTC_BANK1_RAM_ADDR,
+				   (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+			rtc->write(rtc, RTC_BANK1_RAM_DATA_PORT, *buf++);
+			pos++;
+		}
+
+#ifndef CONFIG_RTC_DRV_DS1685
+		/* Disable burst-mode on DS17x85/DS17x87 */
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+			    ~(RTC_CTRL_4A_BME)));
+#endif
+		ds1685_rtc_switch_to_bank0(rtc);
+	}
+#endif /* !CONFIG_RTC_DRV_DS1689 */
+	spin_unlock_irqrestore(&rtc->lock, flags);
+
+	return count;
+}
+
+/**
+ * struct ds1685_rtc_sysfs_nvram_attr - sysfs attributes for rtc nvram.
+ * @attr: nvram attributes.
+ * @read: nvram read function.
+ * @write: nvram write function.
+ * @size: nvram total size (bank0 + extended).
+ */
+static struct bin_attribute
+ds1685_rtc_sysfs_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUGO | S_IWUSR,
+	},
+	.read = ds1685_rtc_sysfs_nvram_read,
+	.write = ds1685_rtc_sysfs_nvram_write,
+	.size = NVRAM_TOTAL_SZ
+};
+
+/**
+ * ds1685_rtc_sysfs_battery_show - sysfs file for main battery status.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_battery_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrld;
+
+	ctrld = rtc->read(rtc, RTC_CTRL_D);
+
+	return snprintf(buf, 13, "%s\n",
+			(ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
+}
+static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL);
+
+/**
+ * ds1685_rtc_sysfs_auxbatt_show - sysfs file for aux battery status.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ctrl4a;
+
+	ds1685_rtc_switch_to_bank1(rtc);
+	ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	return snprintf(buf, 13, "%s\n",
+			(ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
+}
+static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL);
+
+/**
+ * ds1685_rtc_sysfs_serial_show - sysfs file for silicon serial number.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_serial_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+	u8 ssn[8];
+
+	ds1685_rtc_switch_to_bank1(rtc);
+	ds1685_rtc_get_ssn(rtc, ssn);
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	return snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+			ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5],
+			ssn[6], ssn[7]);
+
+	return 0;
+}
+static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
+
+/**
+ * struct ds1685_rtc_sysfs_misc_attrs - list for misc RTC features.
+ */
+static struct attribute*
+ds1685_rtc_sysfs_misc_attrs[] = {
+	&dev_attr_battery.attr,
+	&dev_attr_auxbatt.attr,
+	&dev_attr_serial.attr,
+	NULL,
+};
+
+/**
+ * struct ds1685_rtc_sysfs_misc_grp - attr group for misc RTC features.
+ */
+static const struct attribute_group
+ds1685_rtc_sysfs_misc_grp = {
+	.name = "misc",
+	.attrs = ds1685_rtc_sysfs_misc_attrs,
+};
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+/**
+ * struct ds1685_rtc_ctrl_regs.
+ * @name: char pointer for the bit name.
+ * @reg: control register the bit is in.
+ * @bit: the bit's offset in the register.
+ */
+struct ds1685_rtc_ctrl_regs {
+	const char *name;
+	const u8 reg;
+	const u8 bit;
+};
+
+/*
+ * Ctrl register bit lookup table.
+ */
+static const struct ds1685_rtc_ctrl_regs
+ds1685_ctrl_regs_table[] = {
+	{ "uip",  RTC_CTRL_A,      RTC_CTRL_A_UIP   },
+	{ "dv2",  RTC_CTRL_A,      RTC_CTRL_A_DV2   },
+	{ "dv1",  RTC_CTRL_A,      RTC_CTRL_A_DV1   },
+	{ "dv0",  RTC_CTRL_A,      RTC_CTRL_A_DV0   },
+	{ "rs3",  RTC_CTRL_A,      RTC_CTRL_A_RS3   },
+	{ "rs2",  RTC_CTRL_A,      RTC_CTRL_A_RS2   },
+	{ "rs1",  RTC_CTRL_A,      RTC_CTRL_A_RS1   },
+	{ "rs0",  RTC_CTRL_A,      RTC_CTRL_A_RS0   },
+	{ "set",  RTC_CTRL_B,      RTC_CTRL_B_SET   },
+	{ "pie",  RTC_CTRL_B,      RTC_CTRL_B_PIE   },
+	{ "aie",  RTC_CTRL_B,      RTC_CTRL_B_AIE   },
+	{ "uie",  RTC_CTRL_B,      RTC_CTRL_B_UIE   },
+	{ "sqwe", RTC_CTRL_B,      RTC_CTRL_B_SQWE  },
+	{ "dm",   RTC_CTRL_B,      RTC_CTRL_B_DM    },
+	{ "2412", RTC_CTRL_B,      RTC_CTRL_B_2412  },
+	{ "dse",  RTC_CTRL_B,      RTC_CTRL_B_DSE   },
+	{ "irqf", RTC_CTRL_C,      RTC_CTRL_C_IRQF  },
+	{ "pf",   RTC_CTRL_C,      RTC_CTRL_C_PF    },
+	{ "af",   RTC_CTRL_C,      RTC_CTRL_C_AF    },
+	{ "uf",   RTC_CTRL_C,      RTC_CTRL_C_UF    },
+	{ "vrt",  RTC_CTRL_D,      RTC_CTRL_D_VRT   },
+	{ "vrt2", RTC_EXT_CTRL_4A, RTC_CTRL_4A_VRT2 },
+	{ "incr", RTC_EXT_CTRL_4A, RTC_CTRL_4A_INCR },
+	{ "pab",  RTC_EXT_CTRL_4A, RTC_CTRL_4A_PAB  },
+	{ "rf",   RTC_EXT_CTRL_4A, RTC_CTRL_4A_RF   },
+	{ "wf",   RTC_EXT_CTRL_4A, RTC_CTRL_4A_WF   },
+	{ "kf",   RTC_EXT_CTRL_4A, RTC_CTRL_4A_KF   },
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+	{ "bme",  RTC_EXT_CTRL_4A, RTC_CTRL_4A_BME  },
+#endif
+	{ "abe",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_ABE  },
+	{ "e32k", RTC_EXT_CTRL_4B, RTC_CTRL_4B_E32K },
+	{ "cs",   RTC_EXT_CTRL_4B, RTC_CTRL_4B_CS   },
+	{ "rce",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_RCE  },
+	{ "prs",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_PRS  },
+	{ "rie",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_RIE  },
+	{ "wie",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_WIE  },
+	{ "kse",  RTC_EXT_CTRL_4B, RTC_CTRL_4B_KSE  },
+	{ NULL,   0,               0                },
+};
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_lookup - ctrl register bit lookup function.
+ * @name: ctrl register bit to look up in ds1685_ctrl_regs_table.
+ */
+static const struct ds1685_rtc_ctrl_regs*
+ds1685_rtc_sysfs_ctrl_regs_lookup(const char *name)
+{
+	const struct ds1685_rtc_ctrl_regs *p = ds1685_ctrl_regs_table;
+
+	for (; p->name != NULL; ++p)
+		if (strcmp(p->name, name) == 0)
+			return p;
+
+	return NULL;
+}
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_show - reads a ctrl register bit via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	u8 tmp;
+	struct ds1685_priv *rtc = dev_get_drvdata(dev);
+	const struct ds1685_rtc_ctrl_regs *reg_info =
+		ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
+
+	/* Make sure we actually matched something. */
+	if (!reg_info)
+		return -EINVAL;
+
+	/* No spinlock during a read -- mutex is already held. */
+	ds1685_rtc_switch_to_bank1(rtc);
+	tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit;
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	return snprintf(buf, 2, "%d\n", (tmp ? 1 : 0));
+}
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_store - writes a ctrl register bit via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @count: number of bytes written.
+ */
+static ssize_t
+ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct ds1685_priv *rtc = dev_get_drvdata(dev);
+	u8 reg = 0, bit = 0, tmp;
+	unsigned long flags = 0;
+	long int val = 0;
+	const struct ds1685_rtc_ctrl_regs *reg_info =
+		ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
+
+	/* We only accept numbers. */
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	/* bits are binary, 0 or 1 only. */
+	if ((val != 0) && (val != 1))
+		return -ERANGE;
+
+	/* Make sure we actually matched something. */
+	if (!reg_info)
+		return -EINVAL;
+
+	reg = reg_info->reg;
+	bit = reg_info->bit;
+
+	/* Safe to spinlock during a write. */
+	ds1685_rtc_begin_ctrl_access(rtc, flags);
+	tmp = rtc->read(rtc, reg);
+	rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
+	ds1685_rtc_end_ctrl_access(rtc, flags);
+
+	return count;
+}
+
+/**
+ * DS1685_RTC_SYSFS_CTRL_REG_RO - device_attribute for read-only register bit.
+ * @bit: bit to read.
+ */
+#define DS1685_RTC_SYSFS_CTRL_REG_RO(bit)				\
+	static DEVICE_ATTR(bit, S_IRUGO,				\
+	ds1685_rtc_sysfs_ctrl_regs_show, NULL)
+
+/**
+ * DS1685_RTC_SYSFS_CTRL_REG_RW - device_attribute for read-write register bit.
+ * @bit: bit to read or write.
+ */
+#define DS1685_RTC_SYSFS_CTRL_REG_RW(bit)				\
+	static DEVICE_ATTR(bit, S_IRUGO | S_IWUSR,			\
+	ds1685_rtc_sysfs_ctrl_regs_show,				\
+	ds1685_rtc_sysfs_ctrl_regs_store)
+
+/*
+ * Control Register A bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(uip);
+DS1685_RTC_SYSFS_CTRL_REG_RW(dv2);
+DS1685_RTC_SYSFS_CTRL_REG_RW(dv1);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dv0);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs3);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs2);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs1);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs0);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrla_attrs[] = {
+	&dev_attr_uip.attr,
+	&dev_attr_dv2.attr,
+	&dev_attr_dv1.attr,
+	&dev_attr_dv0.attr,
+	&dev_attr_rs3.attr,
+	&dev_attr_rs2.attr,
+	&dev_attr_rs1.attr,
+	&dev_attr_rs0.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrla_grp = {
+	.name = "ctrla",
+	.attrs = ds1685_rtc_sysfs_ctrla_attrs,
+};
+
+
+/*
+ * Control Register B bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(set);
+DS1685_RTC_SYSFS_CTRL_REG_RW(pie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(aie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(uie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(sqwe);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dm);
+DS1685_RTC_SYSFS_CTRL_REG_RO(2412);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dse);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrlb_attrs[] = {
+	&dev_attr_set.attr,
+	&dev_attr_pie.attr,
+	&dev_attr_aie.attr,
+	&dev_attr_uie.attr,
+	&dev_attr_sqwe.attr,
+	&dev_attr_dm.attr,
+	&dev_attr_2412.attr,
+	&dev_attr_dse.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrlb_grp = {
+	.name = "ctrlb",
+	.attrs = ds1685_rtc_sysfs_ctrlb_attrs,
+};
+
+/*
+ * Control Register C bits.
+ *
+ * Reading Control C clears these bits!  Reading them individually can
+ * possibly cause an interrupt to be missed.  Use the /proc interface
+ * to see all the bits in this register simultaneously.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(irqf);
+DS1685_RTC_SYSFS_CTRL_REG_RO(pf);
+DS1685_RTC_SYSFS_CTRL_REG_RO(af);
+DS1685_RTC_SYSFS_CTRL_REG_RO(uf);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrlc_attrs[] = {
+	&dev_attr_irqf.attr,
+	&dev_attr_pf.attr,
+	&dev_attr_af.attr,
+	&dev_attr_uf.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrlc_grp = {
+	.name = "ctrlc",
+	.attrs = ds1685_rtc_sysfs_ctrlc_attrs,
+};
+
+/*
+ * Control Register D bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(vrt);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrld_attrs[] = {
+	&dev_attr_vrt.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrld_grp = {
+	.name = "ctrld",
+	.attrs = ds1685_rtc_sysfs_ctrld_attrs,
+};
+
+/*
+ * Control Register 4A bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(vrt2);
+DS1685_RTC_SYSFS_CTRL_REG_RO(incr);
+DS1685_RTC_SYSFS_CTRL_REG_RW(pab);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rf);
+DS1685_RTC_SYSFS_CTRL_REG_RW(wf);
+DS1685_RTC_SYSFS_CTRL_REG_RW(kf);
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+DS1685_RTC_SYSFS_CTRL_REG_RO(bme);
+#endif
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrl4a_attrs[] = {
+	&dev_attr_vrt2.attr,
+	&dev_attr_incr.attr,
+	&dev_attr_pab.attr,
+	&dev_attr_rf.attr,
+	&dev_attr_wf.attr,
+	&dev_attr_kf.attr,
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+	&dev_attr_bme.attr,
+#endif
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrl4a_grp = {
+	.name = "ctrl4a",
+	.attrs = ds1685_rtc_sysfs_ctrl4a_attrs,
+};
+
+/*
+ * Control Register 4B bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RW(abe);
+DS1685_RTC_SYSFS_CTRL_REG_RW(e32k);
+DS1685_RTC_SYSFS_CTRL_REG_RO(cs);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rce);
+DS1685_RTC_SYSFS_CTRL_REG_RW(prs);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(wie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(kse);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrl4b_attrs[] = {
+	&dev_attr_abe.attr,
+	&dev_attr_e32k.attr,
+	&dev_attr_cs.attr,
+	&dev_attr_rce.attr,
+	&dev_attr_prs.attr,
+	&dev_attr_rie.attr,
+	&dev_attr_wie.attr,
+	&dev_attr_kse.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrl4b_grp = {
+	.name = "ctrl4b",
+	.attrs = ds1685_rtc_sysfs_ctrl4b_attrs,
+};
+
+
+/**
+ * struct ds1685_rtc_ctrl_regs.
+ * @name: char pointer for the bit name.
+ * @reg: control register the bit is in.
+ * @bit: the bit's offset in the register.
+ */
+struct ds1685_rtc_time_regs {
+	const char *name;
+	const u8 reg;
+	const u8 mask;
+	const u8 min;
+	const u8 max;
+};
+
+/*
+ * Time/Date register lookup tables.
+ */
+static const struct ds1685_rtc_time_regs
+ds1685_time_regs_bcd_table[] = {
+	{ "seconds",       RTC_SECS,       RTC_SECS_BCD_MASK,   0, 59 },
+	{ "minutes",       RTC_MINS,       RTC_MINS_BCD_MASK,   0, 59 },
+	{ "hours",         RTC_HRS,        RTC_HRS_24_BCD_MASK, 0, 23 },
+	{ "wday",          RTC_WDAY,       RTC_WDAY_MASK,       1,  7 },
+	{ "mday",          RTC_MDAY,       RTC_MDAY_BCD_MASK,   1, 31 },
+	{ "month",         RTC_MONTH,      RTC_MONTH_BCD_MASK,  1, 12 },
+	{ "year",          RTC_YEAR,       RTC_YEAR_BCD_MASK,   0, 99 },
+	{ "century",       RTC_CENTURY,    RTC_CENTURY_MASK,    0, 99 },
+	{ "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BCD_MASK,   0, 59 },
+	{ "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BCD_MASK,   0, 59 },
+	{ "alarm_hours",   RTC_HRS_ALARM,  RTC_HRS_24_BCD_MASK, 0, 23 },
+	{ "alarm_mday",    RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 1, 31 },
+	{ NULL,            0,              0,                   0,  0 },
+};
+
+static const struct ds1685_rtc_time_regs
+ds1685_time_regs_bin_table[] = {
+	{ "seconds",       RTC_SECS,       RTC_SECS_BIN_MASK,   0x00, 0x3b },
+	{ "minutes",       RTC_MINS,       RTC_MINS_BIN_MASK,   0x00, 0x3b },
+	{ "hours",         RTC_HRS,        RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
+	{ "wday",          RTC_WDAY,       RTC_WDAY_MASK,       0x01, 0x07 },
+	{ "mday",          RTC_MDAY,       RTC_MDAY_BIN_MASK,   0x01, 0x1f },
+	{ "month",         RTC_MONTH,      RTC_MONTH_BIN_MASK,  0x01, 0x0c },
+	{ "year",          RTC_YEAR,       RTC_YEAR_BIN_MASK,   0x00, 0x63 },
+	{ "century",       RTC_CENTURY,    RTC_CENTURY_MASK,    0x00, 0x63 },
+	{ "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BIN_MASK,   0x00, 0x3b },
+	{ "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BIN_MASK,   0x00, 0x3b },
+	{ "alarm_hours",   RTC_HRS_ALARM,  RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
+	{ "alarm_mday",    RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 0x01, 0x1f },
+	{ NULL,            0,              0,                   0x00, 0x00 },
+};
+
+/**
+ * ds1685_rtc_sysfs_time_regs_bcd_lookup - time/date reg bit lookup function.
+ * @name: register bit to look up in ds1685_time_regs_bcd_table.
+ */
+static const struct ds1685_rtc_time_regs*
+ds1685_rtc_sysfs_time_regs_lookup(const char *name, bool bcd_mode)
+{
+	const struct ds1685_rtc_time_regs *p;
+
+	if (bcd_mode)
+		p = ds1685_time_regs_bcd_table;
+	else
+		p = ds1685_time_regs_bin_table;
+
+	for (; p->name != NULL; ++p)
+		if (strcmp(p->name, name) == 0)
+			return p;
+
+	return NULL;
+}
+
+/**
+ * ds1685_rtc_sysfs_time_regs_show - reads a time/date register via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_time_regs_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	u8 tmp;
+	struct ds1685_priv *rtc = dev_get_drvdata(dev);
+	const struct ds1685_rtc_time_regs *bcd_reg_info =
+		ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
+	const struct ds1685_rtc_time_regs *bin_reg_info =
+		ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
+
+	/* Make sure we actually matched something. */
+	if (!bcd_reg_info && !bin_reg_info)
+		return -EINVAL;
+
+	/* bcd_reg_info->reg == bin_reg_info->reg. */
+	ds1685_rtc_begin_data_access(rtc);
+	tmp = rtc->read(rtc, bcd_reg_info->reg);
+	ds1685_rtc_end_data_access(rtc);
+
+	tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask,
+				 bin_reg_info->mask);
+
+	return snprintf(buf, 4, "%d\n", tmp);
+}
+
+/**
+ * ds1685_rtc_sysfs_time_regs_store - writes a time/date register via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @count: number of bytes written.
+ */
+static ssize_t
+ds1685_rtc_sysfs_time_regs_store(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	long int val = 0;
+	struct ds1685_priv *rtc = dev_get_drvdata(dev);
+	const struct ds1685_rtc_time_regs *bcd_reg_info =
+		ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
+	const struct ds1685_rtc_time_regs *bin_reg_info =
+		ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
+
+	/* We only accept numbers. */
+	if (kstrtol(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	/* Make sure we actually matched something. */
+	if (!bcd_reg_info && !bin_reg_info)
+		return -EINVAL;
+
+	/* Check for a valid range. */
+	if (rtc->bcd_mode) {
+		if ((val < bcd_reg_info->min) || (val > bcd_reg_info->max))
+			return -ERANGE;
+	} else {
+		if ((val < bin_reg_info->min) || (val > bin_reg_info->max))
+			return -ERANGE;
+	}
+
+	val = ds1685_rtc_bin2bcd(rtc, val, bin_reg_info->mask,
+				 bcd_reg_info->mask);
+
+	/* bcd_reg_info->reg == bin_reg_info->reg. */
+	ds1685_rtc_begin_data_access(rtc);
+	rtc->write(rtc, bcd_reg_info->reg, val);
+	ds1685_rtc_end_data_access(rtc);
+
+	return count;
+}
+
+/**
+ * DS1685_RTC_SYSFS_REG_RW - device_attribute for a read-write time register.
+ * @reg: time/date register to read or write.
+ */
+#define DS1685_RTC_SYSFS_TIME_REG_RW(reg)				\
+	static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,			\
+	ds1685_rtc_sysfs_time_regs_show,				\
+	ds1685_rtc_sysfs_time_regs_store)
+
+/*
+ * Time/Date Register bits.
+ */
+DS1685_RTC_SYSFS_TIME_REG_RW(seconds);
+DS1685_RTC_SYSFS_TIME_REG_RW(minutes);
+DS1685_RTC_SYSFS_TIME_REG_RW(hours);
+DS1685_RTC_SYSFS_TIME_REG_RW(wday);
+DS1685_RTC_SYSFS_TIME_REG_RW(mday);
+DS1685_RTC_SYSFS_TIME_REG_RW(month);
+DS1685_RTC_SYSFS_TIME_REG_RW(year);
+DS1685_RTC_SYSFS_TIME_REG_RW(century);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_seconds);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_minutes);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_hours);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_mday);
+
+static struct attribute*
+ds1685_rtc_sysfs_time_attrs[] = {
+	&dev_attr_seconds.attr,
+	&dev_attr_minutes.attr,
+	&dev_attr_hours.attr,
+	&dev_attr_wday.attr,
+	&dev_attr_mday.attr,
+	&dev_attr_month.attr,
+	&dev_attr_year.attr,
+	&dev_attr_century.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_time_grp = {
+	.name = "datetime",
+	.attrs = ds1685_rtc_sysfs_time_attrs,
+};
+
+static struct attribute*
+ds1685_rtc_sysfs_alarm_attrs[] = {
+	&dev_attr_alarm_seconds.attr,
+	&dev_attr_alarm_minutes.attr,
+	&dev_attr_alarm_hours.attr,
+	&dev_attr_alarm_mday.attr,
+	NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_alarm_grp = {
+	.name = "alarm",
+	.attrs = ds1685_rtc_sysfs_alarm_attrs,
+};
+#endif /* CONFIG_RTC_DS1685_SYSFS_REGS */
+
+
+/**
+ * ds1685_rtc_sysfs_register - register sysfs files.
+ * @dev: pointer to device structure.
+ */
+static int
+ds1685_rtc_sysfs_register(struct device *dev)
+{
+	int ret = 0;
+
+	sysfs_bin_attr_init(&ds1685_rtc_sysfs_nvram_attr);
+	ret = sysfs_create_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
+	if (ret)
+		return ret;
+
+	ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
+	if (ret)
+		return ret;
+#endif
+	return 0;
+}
+
+/**
+ * ds1685_rtc_sysfs_unregister - unregister sysfs files.
+ * @dev: pointer to device structure.
+ */
+static int
+ds1685_rtc_sysfs_unregister(struct device *dev)
+{
+	sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
+	sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
+#endif
+
+	return 0;
+}
+#endif /* CONFIG_SYSFS */
+
+
+
+/* ----------------------------------------------------------------------- */
+/* Driver Probe/Removal */
+
+/**
+ * ds1685_rtc_probe - initializes rtc driver.
+ * @pdev: pointer to platform_device structure.
+ */
+static int
+ds1685_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc_dev;
+	struct resource *res;
+	struct ds1685_priv *rtc;
+	struct ds1685_rtc_platform_data *pdata;
+	u8 ctrla, ctrlb, hours;
+	unsigned char am_pm;
+	int ret = 0;
+
+	/* Get the platform data. */
+	pdata = (struct ds1685_rtc_platform_data *) pdev->dev.platform_data;
+	if (!pdata)
+		return -ENODEV;
+
+	/* Allocate memory for the rtc device. */
+	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	/*
+	 * Allocate/setup any IORESOURCE_MEM resources, if required.  Not all
+	 * platforms put the RTC in an easy-access place.  Like the SGI Octane,
+	 * which attaches the RTC to a "ByteBus", hooked to a SuperIO chip
+	 * that sits behind the IOC3 PCI metadevice.
+	 */
+	if (pdata->alloc_io_resources) {
+		/* Get the platform resources. */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -ENXIO;
+		rtc->size = resource_size(res);
+
+		/* Request a memory region. */
+		/* XXX: mmio-only for now. */
+		if (!devm_request_mem_region(&pdev->dev, res->start, rtc->size,
+					     pdev->name))
+			return -EBUSY;
+
+		/*
+		 * Set the base address for the rtc, and ioremap its
+		 * registers.
+		 */
+		rtc->baseaddr = res->start;
+		rtc->regs = devm_ioremap(&pdev->dev, res->start, rtc->size);
+		if (!rtc->regs)
+			return -ENOMEM;
+	}
+	rtc->alloc_io_resources = pdata->alloc_io_resources;
+
+	/* Get the register step size. */
+	if (pdata->regstep > 0)
+		rtc->regstep = pdata->regstep;
+	else
+		rtc->regstep = 1;
+
+	/* Platform read function, else default if mmio setup */
+	if (pdata->plat_read)
+		rtc->read = pdata->plat_read;
+	else
+		if (pdata->alloc_io_resources)
+			rtc->read = ds1685_read;
+		else
+			return -ENXIO;
+
+	/* Platform write function, else default if mmio setup */
+	if (pdata->plat_write)
+		rtc->write = pdata->plat_write;
+	else
+		if (pdata->alloc_io_resources)
+			rtc->write = ds1685_write;
+		else
+			return -ENXIO;
+
+	/* Platform pre-shutdown function, if defined. */
+	if (pdata->plat_prepare_poweroff)
+		rtc->prepare_poweroff = pdata->plat_prepare_poweroff;
+
+	/* Platform wake_alarm function, if defined. */
+	if (pdata->plat_wake_alarm)
+		rtc->wake_alarm = pdata->plat_wake_alarm;
+
+	/* Platform post_ram_clear function, if defined. */
+	if (pdata->plat_post_ram_clear)
+		rtc->post_ram_clear = pdata->plat_post_ram_clear;
+
+	/* Init the spinlock, workqueue, & set the driver data. */
+	spin_lock_init(&rtc->lock);
+	INIT_WORK(&rtc->work, ds1685_rtc_work_queue);
+	platform_set_drvdata(pdev, rtc);
+
+	/* Turn the oscillator on if is not already on (DV1 = 1). */
+	ctrla = rtc->read(rtc, RTC_CTRL_A);
+	if (!(ctrla & RTC_CTRL_A_DV1))
+		ctrla |= RTC_CTRL_A_DV1;
+
+	/* Enable the countdown chain (DV2 = 0) */
+	ctrla &= ~(RTC_CTRL_A_DV2);
+
+	/* Clear RS3-RS0 in Control A. */
+	ctrla &= ~(RTC_CTRL_A_RS_MASK);
+
+	/*
+	 * All done with Control A.  Switch to Bank 1 for the remainder of
+	 * the RTC setup so we have access to the extended functions.
+	 */
+	ctrla |= RTC_CTRL_A_DV0;
+	rtc->write(rtc, RTC_CTRL_A, ctrla);
+
+	/* Default to 32768kHz output. */
+	rtc->write(rtc, RTC_EXT_CTRL_4B,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4B) | RTC_CTRL_4B_E32K));
+
+	/* Set the SET bit in Control B so we can do some housekeeping. */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET));
+
+	/* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */
+	while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR)
+		cpu_relax();
+
+	/*
+	 * If the platform supports BCD mode, then set DM=0 in Control B.
+	 * Otherwise, set DM=1 for BIN mode.
+	 */
+	ctrlb = rtc->read(rtc, RTC_CTRL_B);
+	if (pdata->bcd_mode)
+		ctrlb &= ~(RTC_CTRL_B_DM);
+	else
+		ctrlb |= RTC_CTRL_B_DM;
+	rtc->bcd_mode = pdata->bcd_mode;
+
+	/*
+	 * Disable Daylight Savings Time (DSE = 0).
+	 * The RTC has hardcoded timezone information that is rendered
+	 * obselete.  We'll let the OS deal with DST settings instead.
+	 */
+	if (ctrlb & RTC_CTRL_B_DSE)
+		ctrlb &= ~(RTC_CTRL_B_DSE);
+
+	/* Force 24-hour mode (2412 = 1). */
+	if (!(ctrlb & RTC_CTRL_B_2412)) {
+		/* Reinitialize the time hours. */
+		hours = rtc->read(rtc, RTC_HRS);
+		am_pm = hours & RTC_HRS_AMPM_MASK;
+		hours = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_12_BCD_MASK,
+					   RTC_HRS_12_BIN_MASK);
+		hours = ((hours == 12) ? 0 : ((am_pm) ? hours + 12 : hours));
+
+		/* Enable 24-hour mode. */
+		ctrlb |= RTC_CTRL_B_2412;
+
+		/* Write back to Control B, including DM & DSE bits. */
+		rtc->write(rtc, RTC_CTRL_B, ctrlb);
+
+		/* Write the time hours back. */
+		rtc->write(rtc, RTC_HRS,
+			   ds1685_rtc_bin2bcd(rtc, hours,
+					      RTC_HRS_24_BIN_MASK,
+					      RTC_HRS_24_BCD_MASK));
+
+		/* Reinitialize the alarm hours. */
+		hours = rtc->read(rtc, RTC_HRS_ALARM);
+		am_pm = hours & RTC_HRS_AMPM_MASK;
+		hours = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_12_BCD_MASK,
+					   RTC_HRS_12_BIN_MASK);
+		hours = ((hours == 12) ? 0 : ((am_pm) ? hours + 12 : hours));
+
+		/* Write the alarm hours back. */
+		rtc->write(rtc, RTC_HRS_ALARM,
+			   ds1685_rtc_bin2bcd(rtc, hours,
+					      RTC_HRS_24_BIN_MASK,
+					      RTC_HRS_24_BCD_MASK));
+	} else {
+		/* 24-hour mode is already set, so write Control B back. */
+		rtc->write(rtc, RTC_CTRL_B, ctrlb);
+	}
+
+	/* Unset the SET bit in Control B so the RTC can update. */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET)));
+
+	/* Check the main battery. */
+	if (!(rtc->read(rtc, RTC_CTRL_D) & RTC_CTRL_D_VRT))
+		dev_warn(&pdev->dev,
+			 "Main battery is exhausted! RTC may be invalid!\n");
+
+	/* Check the auxillary battery.  It is optional. */
+	if (!(rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_VRT2))
+		dev_warn(&pdev->dev,
+			 "Aux battery is exhausted or not available.\n");
+
+	/* Read Ctrl B and clear PIE/AIE/UIE. */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_PAU_MASK)));
+
+	/* Reading Ctrl C auto-clears PF/AF/UF. */
+	rtc->read(rtc, RTC_CTRL_C);
+
+	/* Read Ctrl 4B and clear RIE/WIE/KSE. */
+	rtc->write(rtc, RTC_EXT_CTRL_4B,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4B) & ~(RTC_CTRL_4B_RWK_MASK)));
+
+	/* Clear RF/WF/KF in Ctrl 4A. */
+	rtc->write(rtc, RTC_EXT_CTRL_4A,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4A) & ~(RTC_CTRL_4A_RWK_MASK)));
+
+	/*
+	 * Re-enable KSE to handle power button events.  We do not enable
+	 * WIE or RIE by default.
+	 */
+	rtc->write(rtc, RTC_EXT_CTRL_4B,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4B) | RTC_CTRL_4B_KSE));
+
+	/*
+	 * Fetch the IRQ and setup the interrupt handler.
+	 *
+	 * Not all platforms have the IRQF pin tied to something.  If not, the
+	 * RTC will still set the *IE / *F flags and raise IRQF in ctrlc, but
+	 * there won't be an automatic way of notifying the kernel about it,
+	 * unless ctrlc is explicitly polled.
+	 */
+	if (!pdata->no_irq) {
+		ret = platform_get_irq(pdev, 0);
+		if (ret > 0) {
+			rtc->irq_num = ret;
+
+			/* Request an IRQ. */
+			ret = devm_request_irq(&pdev->dev, rtc->irq_num,
+					       ds1685_rtc_irq_handler,
+					       IRQF_SHARED, pdev->name, pdev);
+
+			/* Check to see if something came back. */
+			if (unlikely(ret)) {
+				dev_warn(&pdev->dev,
+					 "RTC interrupt not available\n");
+				rtc->irq_num = 0;
+			}
+		} else
+			return ret;
+	}
+	rtc->no_irq = pdata->no_irq;
+
+	/* Setup complete. */
+	ds1685_rtc_switch_to_bank0(rtc);
+
+	/* Register the device as an RTC. */
+	rtc_dev = rtc_device_register(pdev->name, &pdev->dev,
+				      &ds1685_rtc_ops, THIS_MODULE);
+
+	/* Success? */
+	if (IS_ERR(rtc_dev))
+		return PTR_ERR(rtc_dev);
+
+	/* Maximum periodic rate is 8192Hz (0.122070ms). */
+	rtc_dev->max_user_freq = RTC_MAX_USER_FREQ;
+
+	/* See if the platform doesn't support UIE. */
+	if (pdata->uie_unsupported)
+		rtc_dev->uie_unsupported = 1;
+	rtc->uie_unsupported = pdata->uie_unsupported;
+
+	rtc->dev = rtc_dev;
+
+#ifdef CONFIG_SYSFS
+	ret = ds1685_rtc_sysfs_register(&pdev->dev);
+	if (ret)
+		rtc_device_unregister(rtc->dev);
+#endif
+
+	/* Done! */
+	return ret;
+}
+
+/**
+ * ds1685_rtc_remove - removes rtc driver.
+ * @pdev: pointer to platform_device structure.
+ */
+static int
+ds1685_rtc_remove(struct platform_device *pdev)
+{
+	struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_SYSFS
+	ds1685_rtc_sysfs_unregister(&pdev->dev);
+#endif
+
+	rtc_device_unregister(rtc->dev);
+
+	/* Read Ctrl B and clear PIE/AIE/UIE. */
+	rtc->write(rtc, RTC_CTRL_B,
+		   (rtc->read(rtc, RTC_CTRL_B) &
+		    ~(RTC_CTRL_B_PAU_MASK)));
+
+	/* Reading Ctrl C auto-clears PF/AF/UF. */
+	rtc->read(rtc, RTC_CTRL_C);
+
+	/* Read Ctrl 4B and clear RIE/WIE/KSE. */
+	rtc->write(rtc, RTC_EXT_CTRL_4B,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4B) &
+		    ~(RTC_CTRL_4B_RWK_MASK)));
+
+	/* Manually clear RF/WF/KF in Ctrl 4A. */
+	rtc->write(rtc, RTC_EXT_CTRL_4A,
+		   (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+		    ~(RTC_CTRL_4A_RWK_MASK)));
+
+	cancel_work_sync(&rtc->work);
+
+	return 0;
+}
+
+/**
+ * ds1685_rtc_driver - rtc driver properties.
+ */
+static struct platform_driver ds1685_rtc_driver = {
+	.driver		= {
+		.name	= "rtc-ds1685",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ds1685_rtc_probe,
+	.remove		= ds1685_rtc_remove,
+};
+
+/**
+ * ds1685_rtc_init - rtc module init.
+ */
+static int __init
+ds1685_rtc_init(void)
+{
+	return platform_driver_register(&ds1685_rtc_driver);
+}
+
+/**
+ * ds1685_rtc_exit - rtc module exit.
+ */
+static void __exit
+ds1685_rtc_exit(void)
+{
+	platform_driver_unregister(&ds1685_rtc_driver);
+}
+
+module_init(ds1685_rtc_init);
+module_exit(ds1685_rtc_exit);
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Poweroff function */
+
+/**
+ * ds1685_rtc_poweroff - uses the RTC chip to power the system off.
+ * @pdev: pointer to platform_device structure.
+ */
+extern void __noreturn
+ds1685_rtc_poweroff(struct platform_device *pdev)
+{
+	u8 ctrla, ctrl4a, ctrl4b;
+	struct ds1685_priv *rtc;
+
+	/* Check for valid RTC data, else, spin forever. */
+	if (unlikely(!pdev)) {
+		pr_emerg("rtc-ds1685: platform device data not available, spinning forever ...\n");
+		unreachable();
+	} else {
+		/* Get the rtc data. */
+		rtc = platform_get_drvdata(pdev);
+
+		/*
+		 * Disable our IRQ.  We're powering down, so we're not
+		 * going to worry about cleaning up.  Most of that should
+		 * have been taken care of by the shutdown scripts and this
+		 * is the final function call.
+		 */
+		if (!rtc->no_irq)
+			disable_irq_nosync(rtc->irq_num);
+
+		/* Oscillator must be on and the countdown chain enabled. */
+		ctrla = rtc->read(rtc, RTC_CTRL_A);
+		ctrla |= RTC_CTRL_A_DV1;
+		ctrla &= ~(RTC_CTRL_A_DV2);
+		rtc->write(rtc, RTC_CTRL_A, ctrla);
+
+		/*
+		 * Read Control 4A and check the status of the auxillary
+		 * battery.  This must be present and working (VRT2 = 1)
+		 * for wakeup and kickstart functionality to be useful.
+		 */
+		ds1685_rtc_switch_to_bank1(rtc);
+		ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+		if (ctrl4a & RTC_CTRL_4A_VRT2) {
+			/* Clear all of the interrupt flags on Control 4A. */
+			ctrl4a &= ~(RTC_CTRL_4A_RWK_MASK);
+			rtc->write(rtc, RTC_EXT_CTRL_4A, ctrl4a);
+
+			/*
+			 * The auxillary battery is present and working.
+			 * Enable extended functions (ABE=1), enable
+			 * wake-up (WIE=1), and enable kickstart (KSE=1)
+			 * in Control 4B.
+			 */
+			ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+			ctrl4b |= (RTC_CTRL_4B_ABE | RTC_CTRL_4B_WIE |
+				   RTC_CTRL_4B_KSE);
+			rtc->write(rtc, RTC_EXT_CTRL_4B, ctrl4b);
+		}
+
+		/* Set PAB to 1 in Control 4A to power the system down. */
+		dev_warn(&pdev->dev, "Powerdown.\n");
+		msleep(20);
+		rtc->write(rtc, RTC_EXT_CTRL_4A,
+			   (ctrl4a | RTC_CTRL_4A_PAB));
+
+		/* Spin ... we do not switch back to bank0. */
+		unreachable();
+	}
+}
+EXPORT_SYMBOL(ds1685_rtc_poweroff);
+/* ----------------------------------------------------------------------- */
+
+
+MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>");
+MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>");
+MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-ds1685");
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 42f5570..c666eab 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -50,22 +50,58 @@
 #define DCAMR_UNSET  0xFFFFFFFF  /* doomsday - 1 sec */
 
 #define DCR       0x10           /* Control Reg */
+#define DCR_TDCHL (1 << 30)      /* Tamper-detect configuration hard lock */
+#define DCR_TDCSL (1 << 29)      /* Tamper-detect configuration soft lock */
+#define DCR_KSSL  (1 << 27)      /* Key-select soft lock */
+#define DCR_MCHL  (1 << 20)      /* Monotonic-counter hard lock */
+#define DCR_MCSL  (1 << 19)      /* Monotonic-counter soft lock */
+#define DCR_TCHL  (1 << 18)      /* Timer-counter hard lock */
+#define DCR_TCSL  (1 << 17)      /* Timer-counter soft lock */
+#define DCR_FSHL  (1 << 16)      /* Failure state hard lock */
 #define DCR_TCE   (1 << 3)       /* Time Counter Enable */
+#define DCR_MCE   (1 << 2)       /* Monotonic Counter Enable */
 
 #define DSR       0x14           /* Status Reg */
-#define DSR_WBF   (1 << 10)      /* Write Busy Flag */
-#define DSR_WNF   (1 << 9)       /* Write Next Flag */
-#define DSR_WCF   (1 << 8)       /* Write Complete Flag */
+#define DSR_WTD   (1 << 23)      /* Wire-mesh tamper detected */
+#define DSR_ETBD  (1 << 22)      /* External tamper B detected */
+#define DSR_ETAD  (1 << 21)      /* External tamper A detected */
+#define DSR_EBD   (1 << 20)      /* External boot detected */
+#define DSR_SAD   (1 << 19)      /* SCC alarm detected */
+#define DSR_TTD   (1 << 18)      /* Temperatur tamper detected */
+#define DSR_CTD   (1 << 17)      /* Clock tamper detected */
+#define DSR_VTD   (1 << 16)      /* Voltage tamper detected */
+#define DSR_WBF   (1 << 10)      /* Write Busy Flag (synchronous) */
+#define DSR_WNF   (1 << 9)       /* Write Next Flag (synchronous) */
+#define DSR_WCF   (1 << 8)       /* Write Complete Flag (synchronous)*/
 #define DSR_WEF   (1 << 7)       /* Write Error Flag */
 #define DSR_CAF   (1 << 4)       /* Clock Alarm Flag */
+#define DSR_MCO   (1 << 3)       /* monotonic counter overflow */
+#define DSR_TCO   (1 << 2)       /* time counter overflow */
 #define DSR_NVF   (1 << 1)       /* Non-Valid Flag */
 #define DSR_SVF   (1 << 0)       /* Security Violation Flag */
 
-#define DIER      0x18           /* Interrupt Enable Reg */
+#define DIER      0x18           /* Interrupt Enable Reg (synchronous) */
 #define DIER_WNIE (1 << 9)       /* Write Next Interrupt Enable */
 #define DIER_WCIE (1 << 8)       /* Write Complete Interrupt Enable */
 #define DIER_WEIE (1 << 7)       /* Write Error Interrupt Enable */
 #define DIER_CAIE (1 << 4)       /* Clock Alarm Interrupt Enable */
+#define DIER_SVIE (1 << 0)       /* Security-violation Interrupt Enable */
+
+#define DMCR      0x1c           /* DryIce Monotonic Counter Reg */
+
+#define DTCR      0x28           /* DryIce Tamper Configuration Reg */
+#define DTCR_MOE  (1 << 9)       /* monotonic overflow enabled */
+#define DTCR_TOE  (1 << 8)       /* time overflow enabled */
+#define DTCR_WTE  (1 << 7)       /* wire-mesh tamper enabled */
+#define DTCR_ETBE (1 << 6)       /* external B tamper enabled */
+#define DTCR_ETAE (1 << 5)       /* external A tamper enabled */
+#define DTCR_EBE  (1 << 4)       /* external boot tamper enabled */
+#define DTCR_SAIE (1 << 3)       /* SCC enabled */
+#define DTCR_TTE  (1 << 2)       /* temperature tamper enabled */
+#define DTCR_CTE  (1 << 1)       /* clock tamper enabled */
+#define DTCR_VTE  (1 << 0)       /* voltage tamper enabled */
+
+#define DGPR      0x3c           /* DryIce General Purpose Reg */
 
 /**
  * struct imxdi_dev - private imxdi rtc data
@@ -313,7 +349,7 @@
 	dier = __raw_readl(imxdi->ioaddr + DIER);
 
 	/* handle write complete and write error cases */
-	if ((dier & DIER_WCIE)) {
+	if (dier & DIER_WCIE) {
 		/*If the write wait queue is empty then there is no pending
 		  operations. It means the interrupt is for DryIce -Security.
 		  IRQ must be returned as none.*/
@@ -322,7 +358,7 @@
 
 		/* DSR_WCF clears itself on DSR read */
 		dsr = __raw_readl(imxdi->ioaddr + DSR);
-		if ((dsr & (DSR_WCF | DSR_WEF))) {
+		if (dsr & (DSR_WCF | DSR_WEF)) {
 			/* mask the interrupt */
 			di_int_disable(imxdi, DIER_WCIE);
 
@@ -335,7 +371,7 @@
 	}
 
 	/* handle the alarm case */
-	if ((dier & DIER_CAIE)) {
+	if (dier & DIER_CAIE) {
 		/* DSR_WCF clears itself on DSR read */
 		dsr = __raw_readl(imxdi->ioaddr + DSR);
 		if (dsr & DSR_CAF) {
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index ee3ba7e..f9b0827 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -275,7 +275,8 @@
 
 #ifdef CONFIG_OF
 static const struct of_device_id isl12022_dt_match[] = {
-	{ .compatible = "isl,isl12022" },
+	{ .compatible = "isl,isl12022" }, /* for backward compat., don't use */
+	{ .compatible = "isil,isl12022" },
 	{ },
 };
 #endif
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
index 6e1fcfb..da818d3 100644
--- a/drivers/rtc/rtc-isl12057.c
+++ b/drivers/rtc/rtc-isl12057.c
@@ -79,8 +79,10 @@
 #define ISL12057_MEM_MAP_LEN	0x10
 
 struct isl12057_rtc_data {
+	struct rtc_device *rtc;
 	struct regmap *regmap;
 	struct mutex lock;
+	int irq;
 };
 
 static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
@@ -160,14 +162,47 @@
 	return 0;
 }
 
-static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int _isl12057_rtc_clear_alarm(struct device *dev)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, ISL12057_REG_SR,
+				 ISL12057_REG_SR_A1F, 0);
+	if (ret)
+		dev_err(dev, "%s: clearing alarm failed (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static int _isl12057_rtc_update_alarm(struct device *dev, int enable)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, ISL12057_REG_INT,
+				 ISL12057_REG_INT_A1IE,
+				 enable ? ISL12057_REG_INT_A1IE : 0);
+	if (ret)
+		dev_err(dev, "%s: changing alarm interrupt flag failed (%d)\n",
+			__func__, ret);
+
+	return ret;
+}
+
+/*
+ * Note: as we only read from device and do not perform any update, there is
+ * no need for an equivalent function which would try and get driver's main
+ * lock. Here, it is safe for everyone if we just use regmap internal lock
+ * on the device when reading.
+ */
+static int _isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
 	u8 regs[ISL12057_RTC_SEC_LEN];
 	unsigned int sr;
 	int ret;
 
-	mutex_lock(&data->lock);
 	ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr);
 	if (ret) {
 		dev_err(dev, "%s: unable to read oscillator status flag (%d)\n",
@@ -187,8 +222,6 @@
 			__func__, ret);
 
 out:
-	mutex_unlock(&data->lock);
-
 	if (ret)
 		return ret;
 
@@ -197,6 +230,168 @@
 	return rtc_valid_tm(tm);
 }
 
+static int isl12057_rtc_update_alarm(struct device *dev, int enable)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	mutex_lock(&data->lock);
+	ret = _isl12057_rtc_update_alarm(dev, enable);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+	unsigned long rtc_secs, alarm_secs;
+	u8 regs[ISL12057_A1_SEC_LEN];
+	unsigned int ir;
+	int ret;
+
+	mutex_lock(&data->lock);
+	ret = regmap_bulk_read(data->regmap, ISL12057_REG_A1_SC, regs,
+			       ISL12057_A1_SEC_LEN);
+	if (ret) {
+		dev_err(dev, "%s: reading alarm section failed (%d)\n",
+			__func__, ret);
+		goto err_unlock;
+	}
+
+	alarm_tm->tm_sec  = bcd2bin(regs[0] & 0x7f);
+	alarm_tm->tm_min  = bcd2bin(regs[1] & 0x7f);
+	alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f);
+	alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f);
+	alarm_tm->tm_wday = -1;
+
+	/*
+	 * The alarm section does not store year/month. We use the ones in rtc
+	 * section as a basis and increment month and then year if needed to get
+	 * alarm after current time.
+	 */
+	ret = _isl12057_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err_unlock;
+
+	alarm_tm->tm_year = rtc_tm.tm_year;
+	alarm_tm->tm_mon = rtc_tm.tm_mon;
+
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err_unlock;
+
+	ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+	if (ret)
+		goto err_unlock;
+
+	if (alarm_secs < rtc_secs) {
+		if (alarm_tm->tm_mon == 11) {
+			alarm_tm->tm_mon = 0;
+			alarm_tm->tm_year += 1;
+		} else {
+			alarm_tm->tm_mon += 1;
+		}
+	}
+
+	ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir);
+	if (ret) {
+		dev_err(dev, "%s: reading alarm interrupt flag failed (%d)\n",
+			__func__, ret);
+		goto err_unlock;
+	}
+
+	alarm->enabled = !!(ir & ISL12057_REG_INT_A1IE);
+
+err_unlock:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int isl12057_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+	struct rtc_time *alarm_tm = &alarm->time;
+	unsigned long rtc_secs, alarm_secs;
+	u8 regs[ISL12057_A1_SEC_LEN];
+	struct rtc_time rtc_tm;
+	int ret, enable = 1;
+
+	mutex_lock(&data->lock);
+	ret = _isl12057_rtc_read_time(dev, &rtc_tm);
+	if (ret)
+		goto err_unlock;
+
+	ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+	if (ret)
+		goto err_unlock;
+
+	ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+	if (ret)
+		goto err_unlock;
+
+	/* If alarm time is before current time, disable the alarm */
+	if (!alarm->enabled || alarm_secs <= rtc_secs) {
+		enable = 0;
+	} else {
+		/*
+		 * Chip only support alarms up to one month in the future. Let's
+		 * return an error if we get something after that limit.
+		 * Comparison is done by incrementing rtc_tm month field by one
+		 * and checking alarm value is still below.
+		 */
+		if (rtc_tm.tm_mon == 11) { /* handle year wrapping */
+			rtc_tm.tm_mon = 0;
+			rtc_tm.tm_year += 1;
+		} else {
+			rtc_tm.tm_mon += 1;
+		}
+
+		ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+		if (ret)
+			goto err_unlock;
+
+		if (alarm_secs > rtc_secs) {
+			dev_err(dev, "%s: max for alarm is one month (%d)\n",
+				__func__, ret);
+			ret = -EINVAL;
+			goto err_unlock;
+		}
+	}
+
+	/* Disable the alarm before modifying it */
+	ret = _isl12057_rtc_update_alarm(dev, 0);
+	if (ret < 0) {
+		dev_err(dev, "%s: unable to disable the alarm (%d)\n",
+			__func__, ret);
+		goto err_unlock;
+	}
+
+	/* Program alarm registers */
+	regs[0] = bin2bcd(alarm_tm->tm_sec) & 0x7f;
+	regs[1] = bin2bcd(alarm_tm->tm_min) & 0x7f;
+	regs[2] = bin2bcd(alarm_tm->tm_hour) & 0x3f;
+	regs[3] = bin2bcd(alarm_tm->tm_mday) & 0x3f;
+
+	ret = regmap_bulk_write(data->regmap, ISL12057_REG_A1_SC, regs,
+				ISL12057_A1_SEC_LEN);
+	if (ret < 0) {
+		dev_err(dev, "%s: writing alarm section failed (%d)\n",
+			__func__, ret);
+		goto err_unlock;
+	}
+
+	/* Enable or disable alarm */
+	ret = _isl12057_rtc_update_alarm(dev, enable);
+
+err_unlock:
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
 static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
@@ -262,12 +457,85 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+/*
+ * One would expect the device to be marked as a wakeup source only
+ * when an IRQ pin of the RTC is routed to an interrupt line of the
+ * CPU. In practice, such an IRQ pin can be connected to a PMIC and
+ * this allows the device to be powered up when RTC alarm rings. This
+ * is for instance the case on ReadyNAS 102, 104 and 2120. On those
+ * devices with no IRQ driectly connected to the SoC, the RTC chip
+ * can be forced as a wakeup source by stating that explicitly in
+ * the device's .dts file using the "isil,irq2-can-wakeup-machine"
+ * boolean property. This will guarantee 'wakealarm' sysfs entry is
+ * available on the device.
+ *
+ * The function below returns 1, i.e. the capability of the chip to
+ * wakeup the device, based on IRQ availability or if the boolean
+ * property has been set in the .dts file. Otherwise, it returns 0.
+ */
+
+static bool isl12057_can_wakeup_machine(struct device *dev)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+
+	return (data->irq || of_property_read_bool(dev->of_node,
+					      "isil,irq2-can-wakeup-machine"));
+}
+#else
+static bool isl12057_can_wakeup_machine(struct device *dev)
+{
+	struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+
+	return !!data->irq;
+}
+#endif
+
+static int isl12057_rtc_alarm_irq_enable(struct device *dev,
+					 unsigned int enable)
+{
+	struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+	int ret = -ENOTTY;
+
+	if (rtc_data->irq)
+		ret = isl12057_rtc_update_alarm(dev, enable);
+
+	return ret;
+}
+
+static irqreturn_t isl12057_rtc_interrupt(int irq, void *data)
+{
+	struct i2c_client *client = data;
+	struct isl12057_rtc_data *rtc_data = dev_get_drvdata(&client->dev);
+	struct rtc_device *rtc = rtc_data->rtc;
+	int ret, handled = IRQ_NONE;
+	unsigned int sr;
+
+	ret = regmap_read(rtc_data->regmap, ISL12057_REG_SR, &sr);
+	if (!ret && (sr & ISL12057_REG_SR_A1F)) {
+		dev_dbg(&client->dev, "RTC alarm!\n");
+
+		rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+		/* Acknowledge and disable the alarm */
+		_isl12057_rtc_clear_alarm(&client->dev);
+		_isl12057_rtc_update_alarm(&client->dev, 0);
+
+		handled = IRQ_HANDLED;
+	}
+
+	return handled;
+}
+
 static const struct rtc_class_ops rtc_ops = {
-	.read_time = isl12057_rtc_read_time,
+	.read_time = _isl12057_rtc_read_time,
 	.set_time = isl12057_rtc_set_time,
+	.read_alarm = isl12057_rtc_read_alarm,
+	.set_alarm = isl12057_rtc_set_alarm,
+	.alarm_irq_enable = isl12057_rtc_alarm_irq_enable,
 };
 
-static struct regmap_config isl12057_rtc_regmap_config = {
+static const struct regmap_config isl12057_rtc_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 };
@@ -277,7 +545,6 @@
 {
 	struct device *dev = &client->dev;
 	struct isl12057_rtc_data *data;
-	struct rtc_device *rtc;
 	struct regmap *regmap;
 	int ret;
 
@@ -310,13 +577,75 @@
 	data->regmap = regmap;
 	dev_set_drvdata(dev, data);
 
-	rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE);
-	return PTR_ERR_OR_ZERO(rtc);
+	if (client->irq > 0) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						isl12057_rtc_interrupt,
+						IRQF_SHARED|IRQF_ONESHOT,
+						DRV_NAME, client);
+		if (!ret)
+			data->irq = client->irq;
+		else
+			dev_err(dev, "%s: irq %d unavailable (%d)\n", __func__,
+				client->irq, ret);
+	}
+
+	if (isl12057_can_wakeup_machine(dev))
+		device_init_wakeup(dev, true);
+
+	data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops,
+					     THIS_MODULE);
+	ret = PTR_ERR_OR_ZERO(data->rtc);
+	if (ret) {
+		dev_err(dev, "%s: unable to register RTC device (%d)\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* We cannot support UIE mode if we do not have an IRQ line */
+	if (!data->irq)
+		data->rtc->uie_unsupported = 1;
+
+err:
+	return ret;
 }
 
+static int isl12057_remove(struct i2c_client *client)
+{
+	if (isl12057_can_wakeup_machine(&client->dev))
+		device_init_wakeup(&client->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int isl12057_rtc_suspend(struct device *dev)
+{
+	struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+	if (rtc_data->irq && device_may_wakeup(dev))
+		return enable_irq_wake(rtc_data->irq);
+
+	return 0;
+}
+
+static int isl12057_rtc_resume(struct device *dev)
+{
+	struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+	if (rtc_data->irq && device_may_wakeup(dev))
+		return disable_irq_wake(rtc_data->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(isl12057_rtc_pm_ops, isl12057_rtc_suspend,
+			 isl12057_rtc_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id isl12057_dt_match[] = {
-	{ .compatible = "isl,isl12057" },
+	{ .compatible = "isl,isl12057" }, /* for backward compat., don't use */
+	{ .compatible = "isil,isl12057" },
 	{ },
 };
 #endif
@@ -331,9 +660,11 @@
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
+		.pm = &isl12057_rtc_pm_ops,
 		.of_match_table = of_match_ptr(isl12057_dt_match),
 	},
 	.probe	  = isl12057_probe,
+	.remove	  = isl12057_remove,
 	.id_table = isl12057_id,
 };
 module_i2c_driver(isl12057_driver);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index d1953bb..8a7556c 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -38,6 +38,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/rtc.h>
@@ -340,10 +341,19 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pcf2123_dt_ids[] = {
+	{ .compatible = "nxp,rtc-pcf2123", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pcf2123_dt_ids);
+#endif
+
 static struct spi_driver pcf2123_driver = {
 	.driver	= {
 			.name	= "rtc-pcf2123",
 			.owner	= THIS_MODULE,
+			.of_match_table = of_match_ptr(pcf2123_dt_ids),
 	},
 	.probe	= pcf2123_probe,
 	.remove	= pcf2123_remove,
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
index df42257..91ca0bc 100644
--- a/drivers/rtc/rtc-rk808.c
+++ b/drivers/rtc/rtc-rk808.c
@@ -67,15 +67,21 @@
 	/* Force an update of the shadowed registers right now */
 	ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
 				 BIT_RTC_CTRL_REG_RTC_GET_TIME,
-				 0);
+				 BIT_RTC_CTRL_REG_RTC_GET_TIME);
 	if (ret) {
 		dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
 		return ret;
 	}
 
+	/*
+	 * After we set the GET_TIME bit, the rtc time can't be read
+	 * immediately. So we should wait up to 31.25 us, about one cycle of
+	 * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
+	 * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
+	 */
 	ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
 				 BIT_RTC_CTRL_REG_RTC_GET_TIME,
-				 BIT_RTC_CTRL_REG_RTC_GET_TIME);
+				 0);
 	if (ret) {
 		dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
 		return ret;
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index f319340..96241b2 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -48,7 +48,6 @@
 static unsigned int be_max_phys_size = 64;
 static unsigned int enable_msix = 1;
 
-MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
 MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
 MODULE_VERSION(BUILD_STR);
 MODULE_AUTHOR("Emulex Corporation");
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 1132321..1f8e2dc 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -4658,10 +4658,10 @@
 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
 				 sdebug_store_sectors);
 
-	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
-
+	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+			  (int)map_size, map_storep);
 	buf[count++] = '\n';
-	buf[count++] = 0;
+	buf[count] = '\0';
 
 	return count;
 }
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 011a336..c0d660f 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -81,6 +81,7 @@
 	{ .compatible = "nvidia,tegra30-car", },
 	{ .compatible = "nvidia,tegra114-car", },
 	{ .compatible = "nvidia,tegra124-car", },
+	{ .compatible = "nvidia,tegra132-car", },
 	{},
 };
 
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index 8646fa9..4d2f71b 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -56,7 +56,7 @@
 
 static void __iomem *fuse_base;
 static struct clk *fuse_clk;
-static struct tegra_fuse_info *fuse_info;
+static const struct tegra_fuse_info *fuse_info;
 
 u32 tegra30_fuse_readl(const unsigned int offset)
 {
@@ -78,18 +78,18 @@
 	return val;
 }
 
-static struct tegra_fuse_info tegra30_info = {
+static const struct tegra_fuse_info tegra30_info = {
 	.size			= 0x2a4,
 	.spare_bit		= 0x144,
 	.speedo_idx		= SPEEDO_TEGRA30,
 };
 
-static struct tegra_fuse_info tegra114_info = {
+static const struct tegra_fuse_info tegra114_info = {
 	.size			= 0x2a0,
 	.speedo_idx		= SPEEDO_TEGRA114,
 };
 
-static struct tegra_fuse_info tegra124_info = {
+static const struct tegra_fuse_info tegra124_info = {
 	.size			= 0x300,
 	.speedo_idx		= SPEEDO_TEGRA124,
 };
@@ -182,6 +182,7 @@
 		fuse_info = &tegra114_info;
 		break;
 	case TEGRA124:
+	case TEGRA132:
 		fuse_info = &tegra124_info;
 		break;
 	default:
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a2c0ceb..c956395 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -70,6 +70,10 @@
 
 #define PMC_SCRATCH41			0x140
 
+#define PMC_SENSOR_CTRL			0x1b0
+#define PMC_SENSOR_CTRL_SCRATCH_WRITE	(1 << 2)
+#define PMC_SENSOR_CTRL_ENABLE_RST	(1 << 1)
+
 #define IO_DPD_REQ			0x1b8
 #define  IO_DPD_REQ_CODE_IDLE		(0 << 30)
 #define  IO_DPD_REQ_CODE_OFF		(1 << 30)
@@ -81,6 +85,18 @@
 #define IO_DPD2_STATUS			0x1c4
 #define SEL_DPD_TIM			0x1c8
 
+#define PMC_SCRATCH54			0x258
+#define PMC_SCRATCH54_DATA_SHIFT	8
+#define PMC_SCRATCH54_ADDR_SHIFT	0
+
+#define PMC_SCRATCH55			0x25c
+#define PMC_SCRATCH55_RESET_TEGRA	(1 << 31)
+#define PMC_SCRATCH55_CNTRL_ID_SHIFT	27
+#define PMC_SCRATCH55_PINMUX_SHIFT	24
+#define PMC_SCRATCH55_16BITOP		(1 << 15)
+#define PMC_SCRATCH55_CHECKSUM_SHIFT	16
+#define PMC_SCRATCH55_I2CSLV1_SHIFT	0
+
 #define GPU_RG_CNTRL			0x2d4
 
 struct tegra_pmc_soc {
@@ -88,6 +104,9 @@
 	const char *const *powergates;
 	unsigned int num_cpu_powergates;
 	const u8 *cpu_powergates;
+
+	bool has_tsense_reset;
+	bool has_gpu_clamps;
 };
 
 /**
@@ -110,6 +129,7 @@
  * @powergates_lock: mutex for power gate register access
  */
 struct tegra_pmc {
+	struct device *dev;
 	void __iomem *base;
 	struct clk *clk;
 
@@ -225,11 +245,11 @@
 		return -EINVAL;
 
 	/*
-	 * The Tegra124 GPU has a separate register (with different semantics)
-	 * to remove clamps.
+	 * On Tegra124 and later, the clamps for the GPU are controlled by a
+	 * separate register (with different semantics).
 	 */
-	if (tegra_get_chip_id() == TEGRA124) {
-		if (id == TEGRA_POWERGATE_3D) {
+	if (id == TEGRA_POWERGATE_3D) {
+		if (pmc->soc->has_gpu_clamps) {
 			tegra_pmc_writel(0, GPU_RG_CNTRL);
 			return 0;
 		}
@@ -703,6 +723,83 @@
 	tegra_pmc_writel(value, PMC_CNTRL);
 }
 
+void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
+{
+	static const char disabled[] = "emergency thermal reset disabled";
+	u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
+	struct device *dev = pmc->dev;
+	struct device_node *np;
+	u32 value, checksum;
+
+	if (!pmc->soc->has_tsense_reset)
+		goto out;
+
+	np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
+	if (!np) {
+		dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) {
+		dev_err(dev, "I2C controller ID missing, %s.\n", disabled);
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) {
+		dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled);
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "nvidia,reg-addr", &reg_addr)) {
+		dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled);
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "nvidia,reg-data", &reg_data)) {
+		dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled);
+		goto out;
+	}
+
+	if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux))
+		pinmux = 0;
+
+	value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+	value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
+	tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+	value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
+		(reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
+	tegra_pmc_writel(value, PMC_SCRATCH54);
+
+	value = PMC_SCRATCH55_RESET_TEGRA;
+	value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
+	value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
+	value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT;
+
+	/*
+	 * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will
+	 * contain the checksum and are currently zero, so they are not added.
+	 */
+	checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff)
+		+ ((value >> 24) & 0xff);
+	checksum &= 0xff;
+	checksum = 0x100 - checksum;
+
+	value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT;
+
+	tegra_pmc_writel(value, PMC_SCRATCH55);
+
+	value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+	value |= PMC_SENSOR_CTRL_ENABLE_RST;
+	tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+	dev_info(pmc->dev, "emergency thermal reset enabled\n");
+
+out:
+	of_node_put(np);
+	return;
+}
+
 static int tegra_pmc_probe(struct platform_device *pdev)
 {
 	void __iomem *base = pmc->base;
@@ -728,8 +825,12 @@
 		return err;
 	}
 
+	pmc->dev = &pdev->dev;
+
 	tegra_pmc_init(pmc);
 
+	tegra_pmc_init_tsense_reset(pmc);
+
 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
 		err = tegra_powergate_debugfs_init();
 		if (err < 0)
@@ -739,7 +840,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
 static int tegra_pmc_suspend(struct device *dev)
 {
 	tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
@@ -753,10 +854,11 @@
 
 	return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
 
+#endif
+
 static const char * const tegra20_powergates[] = {
 	[TEGRA_POWERGATE_CPU] = "cpu",
 	[TEGRA_POWERGATE_3D] = "3d",
@@ -772,6 +874,8 @@
 	.powergates = tegra20_powergates,
 	.num_cpu_powergates = 0,
 	.cpu_powergates = NULL,
+	.has_tsense_reset = false,
+	.has_gpu_clamps = false,
 };
 
 static const char * const tegra30_powergates[] = {
@@ -803,6 +907,8 @@
 	.powergates = tegra30_powergates,
 	.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
 	.cpu_powergates = tegra30_cpu_powergates,
+	.has_tsense_reset = true,
+	.has_gpu_clamps = false,
 };
 
 static const char * const tegra114_powergates[] = {
@@ -838,6 +944,8 @@
 	.powergates = tegra114_powergates,
 	.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
 	.cpu_powergates = tegra114_cpu_powergates,
+	.has_tsense_reset = true,
+	.has_gpu_clamps = false,
 };
 
 static const char * const tegra124_powergates[] = {
@@ -879,6 +987,8 @@
 	.powergates = tegra124_powergates,
 	.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
 	.cpu_powergates = tegra124_cpu_powergates,
+	.has_tsense_reset = true,
+	.has_gpu_clamps = true,
 };
 
 static const struct of_device_id tegra_pmc_match[] = {
@@ -894,7 +1004,9 @@
 		.name = "tegra-pmc",
 		.suppress_bind_attrs = true,
 		.of_match_table = tegra_pmc_match,
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
 		.pm = &tegra_pmc_pm_ops,
+#endif
 	},
 	.probe = tegra_pmc_probe,
 };
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 6bed611..135bdad 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -1,5 +1,6 @@
 #
 # TI Keystone SOC drivers
 #
-obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS)	+= knav_qmss_queue.o knav_qmss_acc.o
+obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS)	+= knav_qmss.o
+knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
 obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)	+= knav_dma.o
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index 6fbfde6e..ef6f69d 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -209,7 +209,7 @@
 	return IRQ_HANDLED;
 }
 
-int knav_range_setup_acc_irq(struct knav_range_info *range,
+static int knav_range_setup_acc_irq(struct knav_range_info *range,
 				int queue, bool enabled)
 {
 	struct knav_device *kdev = range->kdev;
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 8e6a95d..6d8646d 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -626,6 +626,7 @@
 	atomic_inc(&qh->stats.pushes);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(knav_queue_push);
 
 /**
  * knav_queue_pop()	- pop data (or descriptor) from the head of a queue
@@ -663,6 +664,7 @@
 	atomic_inc(&qh->stats.pops);
 	return dma;
 }
+EXPORT_SYMBOL_GPL(knav_queue_pop);
 
 /* carve out descriptors and push into queue */
 static void kdesc_fill_pool(struct knav_pool *pool)
@@ -717,12 +719,14 @@
 	struct knav_pool *pool = ph;
 	return pool->region->dma_start + (virt - pool->region->virt_start);
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_virt_to_dma);
 
 void *knav_pool_desc_dma_to_virt(void *ph, dma_addr_t dma)
 {
 	struct knav_pool *pool = ph;
 	return pool->region->virt_start + (dma - pool->region->dma_start);
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_dma_to_virt);
 
 /**
  * knav_pool_create()	- Create a pool of descriptors
@@ -878,6 +882,7 @@
 	data = knav_pool_desc_dma_to_virt(pool, dma);
 	return data;
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_get);
 
 /**
  * knav_pool_desc_put()	- return a descriptor to the pool
@@ -890,6 +895,7 @@
 	dma = knav_pool_desc_virt_to_dma(pool, desc);
 	knav_queue_push(pool->queue, dma, pool->region->desc_size, 0);
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_put);
 
 /**
  * knav_pool_desc_map()	- Map descriptor for DMA transfer
@@ -916,6 +922,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_map);
 
 /**
  * knav_pool_desc_unmap()	- Unmap descriptor after DMA transfer
@@ -938,6 +945,7 @@
 	prefetch(desc);
 	return desc;
 }
+EXPORT_SYMBOL_GPL(knav_pool_desc_unmap);
 
 /**
  * knav_pool_count()	- Get the number of descriptors in pool.
@@ -949,6 +957,7 @@
 	struct knav_pool *pool = ph;
 	return knav_queue_get_count(pool->queue);
 }
+EXPORT_SYMBOL_GPL(knav_pool_count);
 
 static void knav_queue_setup_region(struct knav_device *kdev,
 					struct knav_region *region)
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 9049dd9..45baa83 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -56,6 +56,8 @@
 
 source "drivers/staging/iio/Kconfig"
 
+source "drivers/staging/sm7xxfb/Kconfig"
+
 source "drivers/staging/xgifb/Kconfig"
 
 source "drivers/staging/emxx_udc/Kconfig"
@@ -64,8 +66,6 @@
 
 source "drivers/staging/speakup/Kconfig"
 
-source "drivers/staging/cptm1217/Kconfig"
-
 source "drivers/staging/ste_rmi4/Kconfig"
 
 source "drivers/staging/nvec/Kconfig"
@@ -104,4 +104,8 @@
 
 source "drivers/staging/clocking-wizard/Kconfig"
 
+source "drivers/staging/fbtft/Kconfig"
+
+source "drivers/staging/i2o/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index fe26ff1..2916079 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -22,11 +22,11 @@
 obj-$(CONFIG_VT6656)		+= vt6656/
 obj-$(CONFIG_VME_BUS)		+= vme/
 obj-$(CONFIG_IIO)		+= iio/
+obj-$(CONFIG_FB_SM7XX)		+= sm7xxfb/
 obj-$(CONFIG_FB_XGI)		+= xgifb/
 obj-$(CONFIG_USB_EMXX)		+= emxx_udc/
 obj-$(CONFIG_FT1000)		+= ft1000/
 obj-$(CONFIG_SPEAKUP)		+= speakup/
-obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)	+= cptm1217/
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)	+= ste_rmi4/
 obj-$(CONFIG_MFD_NVEC)		+= nvec/
 obj-$(CONFIG_ANDROID)		+= android/
@@ -44,3 +44,5 @@
 obj-$(CONFIG_CRYPTO_SKEIN)	+= skein/
 obj-$(CONFIG_UNISYSSPAR)	+= unisys/
 obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD)	+= clocking-wizard/
+obj-$(CONFIG_FB_TFT)		+= fbtft/
+obj-$(CONFIG_I2O)		+= i2o/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 7e012f3..8feb904 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -14,23 +14,6 @@
 	  It is, in theory, a good memory allocator for low-memory devices,
 	  because it can discard shared memory units when under memory pressure.
 
-config ANDROID_LOGGER
-	tristate "Android log driver"
-	default n
-	---help---
-	  This adds support for system-wide logging using four log buffers.
-
-	  These are:
-
-	      1: main
-	      2: events
-	      3: radio
-	      4: system
-
-	  Log reading and writing is performed via normal Linux reads and
-	  optimized writes. This optimization avoids logging having too
-	  much overhead in the system.
-
 config ANDROID_TIMED_OUTPUT
 	bool "Timed output class driver"
 	default y
@@ -45,15 +28,6 @@
 	---help---
 	  Registers processes to be killed when memory is low
 
-config ANDROID_INTF_ALARM_DEV
-	tristate "Android alarm driver"
-	depends on RTC_CLASS
-	default n
-	---help---
-	  Provides non-wakeup and rtc backed wakeup alarms based on rtc or
-	  elapsed realtime, and a non-wakeup alarm on the monotonic clock.
-	  Also exports the alarm interface to user-space.
-
 config SYNC
 	bool "Synchronization framework"
 	default n
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 479b2b8..c7b6c99 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -3,10 +3,8 @@
 obj-y					+= ion/
 
 obj-$(CONFIG_ASHMEM)			+= ashmem.o
-obj-$(CONFIG_ANDROID_LOGGER)		+= logger.o
 obj-$(CONFIG_ANDROID_TIMED_OUTPUT)	+= timed_output.o
 obj-$(CONFIG_ANDROID_TIMED_GPIO)	+= timed_gpio.o
 obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
-obj-$(CONFIG_ANDROID_INTF_ALARM_DEV)	+= alarm-dev.o
 obj-$(CONFIG_SYNC)			+= sync.o sync_debug.o
 obj-$(CONFIG_SW_SYNC)			+= sw_sync.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
deleted file mode 100644
index ff4b3e8..0000000
--- a/drivers/staging/android/alarm-dev.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/* drivers/rtc/alarm-dev.c
- *
- * Copyright (C) 2007-2009 Google, Inc.
- *
- * 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/time.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
-#include <linux/alarmtimer.h>
-#include "android_alarm.h"
-
-#define ANDROID_ALARM_PRINT_INFO (1U << 0)
-#define ANDROID_ALARM_PRINT_IO (1U << 1)
-#define ANDROID_ALARM_PRINT_INT (1U << 2)
-
-static int debug_mask = ANDROID_ALARM_PRINT_INFO;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define alarm_dbg(debug_level_mask, fmt, ...)				\
-do {									\
-	if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask)	\
-		pr_info(fmt, ##__VA_ARGS__);				\
-} while (0)
-
-#define ANDROID_ALARM_WAKEUP_MASK ( \
-	ANDROID_ALARM_RTC_WAKEUP_MASK | \
-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-
-static int alarm_opened;
-static DEFINE_SPINLOCK(alarm_slock);
-static struct wakeup_source alarm_wake_lock;
-static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
-static uint32_t alarm_pending;
-static uint32_t alarm_enabled;
-static uint32_t wait_pending;
-
-struct devalarm {
-	union {
-		struct hrtimer hrt;
-		struct alarm alrm;
-	} u;
-	enum android_alarm_type type;
-};
-
-static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
-
-/**
- * is_wakeup() - Checks to see if this alarm can wake the device
- * @type:	 The type of alarm being checked
- *
- * Return: 1 if this is a wakeup alarm, otherwise 0
- */
-static int is_wakeup(enum android_alarm_type type)
-{
-	return type == ANDROID_ALARM_RTC_WAKEUP ||
-		type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP;
-}
-
-static void devalarm_start(struct devalarm *alrm, ktime_t exp)
-{
-	if (is_wakeup(alrm->type))
-		alarm_start(&alrm->u.alrm, exp);
-	else
-		hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
-}
-
-static int devalarm_try_to_cancel(struct devalarm *alrm)
-{
-	if (is_wakeup(alrm->type))
-		return alarm_try_to_cancel(&alrm->u.alrm);
-	return hrtimer_try_to_cancel(&alrm->u.hrt);
-}
-
-static void devalarm_cancel(struct devalarm *alrm)
-{
-	if (is_wakeup(alrm->type))
-		alarm_cancel(&alrm->u.alrm);
-	else
-		hrtimer_cancel(&alrm->u.hrt);
-}
-
-static void alarm_clear(enum android_alarm_type alarm_type)
-{
-	uint32_t alarm_type_mask = 1U << alarm_type;
-	unsigned long flags;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	alarm_dbg(IO, "alarm %d clear\n", alarm_type);
-	devalarm_try_to_cancel(&alarms[alarm_type]);
-	if (alarm_pending) {
-		alarm_pending &= ~alarm_type_mask;
-		if (!alarm_pending && !wait_pending)
-			__pm_relax(&alarm_wake_lock);
-	}
-	alarm_enabled &= ~alarm_type_mask;
-	spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static void alarm_set(enum android_alarm_type alarm_type,
-							struct timespec *ts)
-{
-	uint32_t alarm_type_mask = 1U << alarm_type;
-	unsigned long flags;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
-			alarm_type, ts->tv_sec, ts->tv_nsec);
-	alarm_enabled |= alarm_type_mask;
-	devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
-	spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static int alarm_wait(void)
-{
-	unsigned long flags;
-	int rv = 0;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	alarm_dbg(IO, "alarm wait\n");
-	if (!alarm_pending && wait_pending) {
-		__pm_relax(&alarm_wake_lock);
-		wait_pending = 0;
-	}
-	spin_unlock_irqrestore(&alarm_slock, flags);
-
-	rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
-	if (rv)
-		return rv;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	rv = alarm_pending;
-	wait_pending = 1;
-	alarm_pending = 0;
-	spin_unlock_irqrestore(&alarm_slock, flags);
-
-	return rv;
-}
-
-static int alarm_set_rtc(struct timespec *ts)
-{
-	struct rtc_time new_rtc_tm;
-	struct rtc_device *rtc_dev;
-	unsigned long flags;
-	int rv = 0;
-
-	rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
-	rtc_dev = alarmtimer_get_rtcdev();
-	rv = do_settimeofday(ts);
-	if (rv < 0)
-		return rv;
-	if (rtc_dev)
-		rv = rtc_set_time(rtc_dev, &new_rtc_tm);
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
-	wake_up(&alarm_wait_queue);
-	spin_unlock_irqrestore(&alarm_slock, flags);
-
-	return rv;
-}
-
-static int alarm_get_time(enum android_alarm_type alarm_type,
-							struct timespec *ts)
-{
-	int rv = 0;
-
-	switch (alarm_type) {
-	case ANDROID_ALARM_RTC_WAKEUP:
-	case ANDROID_ALARM_RTC:
-		getnstimeofday(ts);
-		break;
-	case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
-	case ANDROID_ALARM_ELAPSED_REALTIME:
-		get_monotonic_boottime(ts);
-		break;
-	case ANDROID_ALARM_SYSTEMTIME:
-		ktime_get_ts(ts);
-		break;
-	default:
-		rv = -EINVAL;
-	}
-	return rv;
-}
-
-static long alarm_do_ioctl(struct file *file, unsigned int cmd,
-							struct timespec *ts)
-{
-	int rv = 0;
-	unsigned long flags;
-	enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
-
-	if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
-		return -EINVAL;
-
-	if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
-		if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-			return -EPERM;
-		if (file->private_data == NULL &&
-		    cmd != ANDROID_ALARM_SET_RTC) {
-			spin_lock_irqsave(&alarm_slock, flags);
-			if (alarm_opened) {
-				spin_unlock_irqrestore(&alarm_slock, flags);
-				return -EBUSY;
-			}
-			alarm_opened = 1;
-			file->private_data = (void *)1;
-			spin_unlock_irqrestore(&alarm_slock, flags);
-		}
-	}
-
-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
-	case ANDROID_ALARM_CLEAR(0):
-		alarm_clear(alarm_type);
-		break;
-	case ANDROID_ALARM_SET(0):
-		alarm_set(alarm_type, ts);
-		break;
-	case ANDROID_ALARM_SET_AND_WAIT(0):
-		alarm_set(alarm_type, ts);
-		/* fall though */
-	case ANDROID_ALARM_WAIT:
-		rv = alarm_wait();
-		break;
-	case ANDROID_ALARM_SET_RTC:
-		rv = alarm_set_rtc(ts);
-		break;
-	case ANDROID_ALARM_GET_TIME(0):
-		rv = alarm_get_time(alarm_type, ts);
-		break;
-
-	default:
-		rv = -EINVAL;
-	}
-	return rv;
-}
-
-static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-
-	struct timespec ts;
-	int rv;
-
-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
-	case ANDROID_ALARM_SET_AND_WAIT(0):
-	case ANDROID_ALARM_SET(0):
-	case ANDROID_ALARM_SET_RTC:
-		if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
-			return -EFAULT;
-		break;
-	}
-
-	rv = alarm_do_ioctl(file, cmd, &ts);
-	if (rv)
-		return rv;
-
-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
-	case ANDROID_ALARM_GET_TIME(0):
-		if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
-			return -EFAULT;
-		break;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
-							unsigned long arg)
-{
-
-	struct timespec ts;
-	int rv;
-
-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
-	case ANDROID_ALARM_SET_AND_WAIT_COMPAT(0):
-	case ANDROID_ALARM_SET_COMPAT(0):
-	case ANDROID_ALARM_SET_RTC_COMPAT:
-		if (compat_get_timespec(&ts, (void __user *)arg))
-			return -EFAULT;
-		/* fall through */
-	case ANDROID_ALARM_GET_TIME_COMPAT(0):
-		cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
-		break;
-	}
-
-	rv = alarm_do_ioctl(file, cmd, &ts);
-	if (rv)
-		return rv;
-
-	switch (ANDROID_ALARM_BASE_CMD(cmd)) {
-	case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
-		if (compat_put_timespec(&ts, (void __user *)arg))
-			return -EFAULT;
-		break;
-	}
-
-	return 0;
-}
-#endif
-
-static int alarm_open(struct inode *inode, struct file *file)
-{
-	file->private_data = NULL;
-	return 0;
-}
-
-static int alarm_release(struct inode *inode, struct file *file)
-{
-	int i;
-	unsigned long flags;
-
-	spin_lock_irqsave(&alarm_slock, flags);
-	if (file->private_data) {
-		for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
-			uint32_t alarm_type_mask = 1U << i;
-
-			if (alarm_enabled & alarm_type_mask) {
-				alarm_dbg(INFO,
-					  "%s: clear alarm, pending %d\n",
-					  __func__,
-					  !!(alarm_pending & alarm_type_mask));
-				alarm_enabled &= ~alarm_type_mask;
-			}
-			spin_unlock_irqrestore(&alarm_slock, flags);
-			devalarm_cancel(&alarms[i]);
-			spin_lock_irqsave(&alarm_slock, flags);
-		}
-		if (alarm_pending | wait_pending) {
-			if (alarm_pending)
-				alarm_dbg(INFO, "%s: clear pending alarms %x\n",
-					  __func__, alarm_pending);
-			__pm_relax(&alarm_wake_lock);
-			wait_pending = 0;
-			alarm_pending = 0;
-		}
-		alarm_opened = 0;
-	}
-	spin_unlock_irqrestore(&alarm_slock, flags);
-	return 0;
-}
-
-static void devalarm_triggered(struct devalarm *alarm)
-{
-	unsigned long flags;
-	uint32_t alarm_type_mask = 1U << alarm->type;
-
-	alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
-	spin_lock_irqsave(&alarm_slock, flags);
-	if (alarm_enabled & alarm_type_mask) {
-		__pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
-		alarm_enabled &= ~alarm_type_mask;
-		alarm_pending |= alarm_type_mask;
-		wake_up(&alarm_wait_queue);
-	}
-	spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
-{
-	struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
-
-	devalarm_triggered(devalrm);
-	return HRTIMER_NORESTART;
-}
-
-static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
-							ktime_t now)
-{
-	struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
-
-	devalarm_triggered(devalrm);
-	return ALARMTIMER_NORESTART;
-}
-
-
-static const struct file_operations alarm_fops = {
-	.owner = THIS_MODULE,
-	.unlocked_ioctl = alarm_ioctl,
-	.open = alarm_open,
-	.release = alarm_release,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = alarm_compat_ioctl,
-#endif
-};
-
-static struct miscdevice alarm_device = {
-	.minor = MISC_DYNAMIC_MINOR,
-	.name = "alarm",
-	.fops = &alarm_fops,
-};
-
-static int __init alarm_dev_init(void)
-{
-	int err;
-	int i;
-
-	err = misc_register(&alarm_device);
-	if (err)
-		return err;
-
-	alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
-			ALARM_REALTIME, devalarm_alarmhandler);
-	hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
-			CLOCK_REALTIME, HRTIMER_MODE_ABS);
-	alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
-			ALARM_BOOTTIME, devalarm_alarmhandler);
-	hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
-			CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
-	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
-			CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-
-	for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
-		alarms[i].type = i;
-		if (!is_wakeup(i))
-			alarms[i].u.hrt.function = devalarm_hrthandler;
-	}
-
-	wakeup_source_init(&alarm_wake_lock, "alarm");
-	return 0;
-}
-
-static void  __exit alarm_dev_exit(void)
-{
-	misc_deregister(&alarm_device);
-	wakeup_source_trash(&alarm_wake_lock);
-}
-
-module_init(alarm_dev_init);
-module_exit(alarm_dev_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
deleted file mode 100644
index 495b20c..0000000
--- a/drivers/staging/android/android_alarm.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* include/linux/android_alarm.h
- *
- * Copyright (C) 2006-2007 Google, Inc.
- *
- * 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.
- *
- */
-
-#ifndef _LINUX_ANDROID_ALARM_H
-#define _LINUX_ANDROID_ALARM_H
-
-#include <linux/compat.h>
-#include <linux/ioctl.h>
-
-#include "uapi/android_alarm.h"
-
-#ifdef CONFIG_COMPAT
-#define ANDROID_ALARM_SET_COMPAT(type)		ALARM_IOW(2, type, \
-							struct compat_timespec)
-#define ANDROID_ALARM_SET_AND_WAIT_COMPAT(type)	ALARM_IOW(3, type, \
-							struct compat_timespec)
-#define ANDROID_ALARM_GET_TIME_COMPAT(type)	ALARM_IOW(4, type, \
-							struct compat_timespec)
-#define ANDROID_ALARM_SET_RTC_COMPAT		_IOW('a', 5, \
-							struct compat_timespec)
-#define ANDROID_ALARM_IOCTL_NR(cmd)		(_IOC_NR(cmd) & ((1<<4)-1))
-#define ANDROID_ALARM_COMPAT_TO_NORM(cmd)  \
-				ALARM_IOW(ANDROID_ALARM_IOCTL_NR(cmd), \
-					ANDROID_ALARM_IOCTL_TO_TYPE(cmd), \
-					struct timespec)
-
-#endif
-
-#endif
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 8c78527..d140b733 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -447,8 +447,8 @@
 		loff_t end = (range->pgend + 1) * PAGE_SIZE;
 
 		vfs_fallocate(range->asma->file,
-				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
-				start, end - start);
+			      FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+			      start, end - start);
 		range->purged = ASHMEM_WAS_PURGED;
 		lru_del(range);
 
@@ -549,7 +549,6 @@
 
 	mutex_lock(&ashmem_mutex);
 	if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {
-
 		/*
 		 * Copying only `len', instead of ASHMEM_NAME_LEN, bytes
 		 * prevents us from revealing one user's stack to another.
@@ -751,10 +750,10 @@
 
 	switch (cmd) {
 	case ASHMEM_SET_NAME:
-		ret = set_name(asma, (void __user *) arg);
+		ret = set_name(asma, (void __user *)arg);
 		break;
 	case ASHMEM_GET_NAME:
-		ret = get_name(asma, (void __user *) arg);
+		ret = get_name(asma, (void __user *)arg);
 		break;
 	case ASHMEM_SET_SIZE:
 		ret = -EINVAL;
@@ -775,7 +774,7 @@
 	case ASHMEM_PIN:
 	case ASHMEM_UNPIN:
 	case ASHMEM_GET_PIN_STATUS:
-		ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);
+		ret = ashmem_pin_unpin(asma, cmd, (void __user *)arg);
 		break;
 	case ASHMEM_PURGE_ALL_CACHES:
 		ret = -EPERM;
@@ -798,7 +797,6 @@
 static long compat_ashmem_ioctl(struct file *file, unsigned int cmd,
 				unsigned long arg)
 {
-
 	switch (cmd) {
 	case COMPAT_ASHMEM_SET_SIZE:
 		cmd = ASHMEM_SET_SIZE;
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 296d347..b8f1c49 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1508,6 +1508,9 @@
 		pr_err("%s: can not add heap with invalid ops struct.\n",
 		       __func__);
 
+	spin_lock_init(&heap->free_lock);
+	heap->free_list_size = 0;
+
 	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
 		ion_heap_init_deferred_free(heap);
 
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index f8cabcb..f4211f1 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -39,24 +39,6 @@
 	struct sg_table *table;
 };
 
-/*
- * Create scatter-list for the already allocated DMA buffer.
- * This function could be replaced by dma_common_get_sgtable
- * as soon as it will avalaible.
- */
-static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
-			       void *cpu_addr, dma_addr_t handle, size_t size)
-{
-	struct page *page = virt_to_page(cpu_addr);
-	int ret;
-
-	ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
-	if (unlikely(ret))
-		return ret;
-
-	sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
-	return 0;
-}
 
 /* ION CMA heap operations functions */
 static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -91,7 +73,7 @@
 	if (!info->table)
 		goto free_mem;
 
-	if (ion_cma_get_sgtable
+	if (dma_common_get_sgtable
 	    (dev, info->table, info->cpu_addr, info->handle, len))
 		goto free_table;
 	/* keep this for memory release */
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 4605e04..fd13d05 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -253,8 +253,6 @@
 	struct sched_param param = { .sched_priority = 0 };
 
 	INIT_LIST_HEAD(&heap->free_list);
-	heap->free_list_size = 0;
-	spin_lock_init(&heap->free_lock);
 	init_waitqueue_head(&heap->waitqueue);
 	heap->task = kthread_run(ion_heap_deferred_free, heap,
 				 "%s", heap->name);
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
deleted file mode 100644
index a673ffa..0000000
--- a/drivers/staging/android/logger.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * drivers/misc/logger.c
- *
- * A Logging Subsystem
- *
- * Copyright (C) 2007-2008 Google, Inc.
- *
- * Robert Love <rlove@google.com>
- *
- * 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.
- */
-
-#define pr_fmt(fmt) "logger: " fmt
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/vmalloc.h>
-#include <linux/aio.h>
-#include "logger.h"
-
-#include <asm/ioctls.h>
-
-/**
- * struct logger_log - represents a specific log, such as 'main' or 'radio'
- * @buffer:	The actual ring buffer
- * @misc:	The "misc" device representing the log
- * @wq:		The wait queue for @readers
- * @readers:	This log's readers
- * @mutex:	The mutex that protects the @buffer
- * @w_off:	The current write head offset
- * @head:	The head, or location that readers start reading at.
- * @size:	The size of the log
- * @logs:	The list of log channels
- *
- * This structure lives from module insertion until module removal, so it does
- * not need additional reference counting. The structure is protected by the
- * mutex 'mutex'.
- */
-struct logger_log {
-	unsigned char		*buffer;
-	struct miscdevice	misc;
-	wait_queue_head_t	wq;
-	struct list_head	readers;
-	struct mutex		mutex;
-	size_t			w_off;
-	size_t			head;
-	size_t			size;
-	struct list_head	logs;
-};
-
-static LIST_HEAD(log_list);
-
-
-/**
- * struct logger_reader - a logging device open for reading
- * @log:	The associated log
- * @list:	The associated entry in @logger_log's list
- * @r_off:	The current read head offset.
- * @r_all:	Reader can read all entries
- * @r_ver:	Reader ABI version
- *
- * This object lives from open to release, so we don't need additional
- * reference counting. The structure is protected by log->mutex.
- */
-struct logger_reader {
-	struct logger_log	*log;
-	struct list_head	list;
-	size_t			r_off;
-	bool			r_all;
-	int			r_ver;
-};
-
-/* logger_offset - returns index 'n' into the log via (optimized) modulus */
-static size_t logger_offset(struct logger_log *log, size_t n)
-{
-	return n & (log->size - 1);
-}
-
-
-/*
- * file_get_log - Given a file structure, return the associated log
- *
- * This isn't aesthetic. We have several goals:
- *
- *	1) Need to quickly obtain the associated log during an I/O operation
- *	2) Readers need to maintain state (logger_reader)
- *	3) Writers need to be very fast (open() should be a near no-op)
- *
- * In the reader case, we can trivially go file->logger_reader->logger_log.
- * For a writer, we don't want to maintain a logger_reader, so we just go
- * file->logger_log. Thus what file->private_data points at depends on whether
- * or not the file was opened for reading. This function hides that dirtiness.
- */
-static inline struct logger_log *file_get_log(struct file *file)
-{
-	if (file->f_mode & FMODE_READ) {
-		struct logger_reader *reader = file->private_data;
-
-		return reader->log;
-	}
-	return file->private_data;
-}
-
-/*
- * get_entry_header - returns a pointer to the logger_entry header within
- * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
- * be provided. Typically the return value will be a pointer within
- * 'logger->buf'.  However, a pointer to 'scratch' may be returned if
- * the log entry spans the end and beginning of the circular buffer.
- */
-static struct logger_entry *get_entry_header(struct logger_log *log,
-		size_t off, struct logger_entry *scratch)
-{
-	size_t len = min(sizeof(struct logger_entry), log->size - off);
-
-	if (len != sizeof(struct logger_entry)) {
-		memcpy(((void *) scratch), log->buffer + off, len);
-		memcpy(((void *) scratch) + len, log->buffer,
-			sizeof(struct logger_entry) - len);
-		return scratch;
-	}
-
-	return (struct logger_entry *) (log->buffer + off);
-}
-
-/*
- * get_entry_msg_len - Grabs the length of the message of the entry
- * starting from from 'off'.
- *
- * An entry length is 2 bytes (16 bits) in host endian order.
- * In the log, the length does not include the size of the log entry structure.
- * This function returns the size including the log entry structure.
- *
- * Caller needs to hold log->mutex.
- */
-static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
-{
-	struct logger_entry scratch;
-	struct logger_entry *entry;
-
-	entry = get_entry_header(log, off, &scratch);
-	return entry->len;
-}
-
-static size_t get_user_hdr_len(int ver)
-{
-	if (ver < 2)
-		return sizeof(struct user_logger_entry_compat);
-	return sizeof(struct logger_entry);
-}
-
-static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
-					 char __user *buf)
-{
-	void *hdr;
-	size_t hdr_len;
-	struct user_logger_entry_compat v1;
-
-	if (ver < 2) {
-		v1.len      = entry->len;
-		v1.__pad    = 0;
-		v1.pid      = entry->pid;
-		v1.tid      = entry->tid;
-		v1.sec      = entry->sec;
-		v1.nsec     = entry->nsec;
-		hdr         = &v1;
-		hdr_len     = sizeof(struct user_logger_entry_compat);
-	} else {
-		hdr         = entry;
-		hdr_len     = sizeof(struct logger_entry);
-	}
-
-	return copy_to_user(buf, hdr, hdr_len);
-}
-
-/*
- * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
- * user-space buffer 'buf'. Returns 'count' on success.
- *
- * Caller must hold log->mutex.
- */
-static ssize_t do_read_log_to_user(struct logger_log *log,
-				   struct logger_reader *reader,
-				   char __user *buf,
-				   size_t count)
-{
-	struct logger_entry scratch;
-	struct logger_entry *entry;
-	size_t len;
-	size_t msg_start;
-
-	/*
-	 * First, copy the header to userspace, using the version of
-	 * the header requested
-	 */
-	entry = get_entry_header(log, reader->r_off, &scratch);
-	if (copy_header_to_user(reader->r_ver, entry, buf))
-		return -EFAULT;
-
-	count -= get_user_hdr_len(reader->r_ver);
-	buf += get_user_hdr_len(reader->r_ver);
-	msg_start = logger_offset(log,
-		reader->r_off + sizeof(struct logger_entry));
-
-	/*
-	 * We read from the msg in two disjoint operations. First, we read from
-	 * the current msg head offset up to 'count' bytes or to the end of
-	 * the log, whichever comes first.
-	 */
-	len = min(count, log->size - msg_start);
-	if (copy_to_user(buf, log->buffer + msg_start, len))
-		return -EFAULT;
-
-	/*
-	 * Second, we read any remaining bytes, starting back at the head of
-	 * the log.
-	 */
-	if (count != len)
-		if (copy_to_user(buf + len, log->buffer, count - len))
-			return -EFAULT;
-
-	reader->r_off = logger_offset(log, reader->r_off +
-		sizeof(struct logger_entry) + count);
-
-	return count + get_user_hdr_len(reader->r_ver);
-}
-
-/*
- * get_next_entry_by_uid - Starting at 'off', returns an offset into
- * 'log->buffer' which contains the first entry readable by 'euid'
- */
-static size_t get_next_entry_by_uid(struct logger_log *log,
-		size_t off, kuid_t euid)
-{
-	while (off != log->w_off) {
-		struct logger_entry *entry;
-		struct logger_entry scratch;
-		size_t next_len;
-
-		entry = get_entry_header(log, off, &scratch);
-
-		if (uid_eq(entry->euid, euid))
-			return off;
-
-		next_len = sizeof(struct logger_entry) + entry->len;
-		off = logger_offset(log, off + next_len);
-	}
-
-	return off;
-}
-
-/*
- * logger_read - our log's read() method
- *
- * Behavior:
- *
- *	- O_NONBLOCK works
- *	- If there are no log entries to read, blocks until log is written to
- *	- Atomically reads exactly one log entry
- *
- * Will set errno to EINVAL if read
- * buffer is insufficient to hold next entry.
- */
-static ssize_t logger_read(struct file *file, char __user *buf,
-			   size_t count, loff_t *pos)
-{
-	struct logger_reader *reader = file->private_data;
-	struct logger_log *log = reader->log;
-	ssize_t ret;
-	DEFINE_WAIT(wait);
-
-start:
-	while (1) {
-		mutex_lock(&log->mutex);
-
-		prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
-
-		ret = (log->w_off == reader->r_off);
-		mutex_unlock(&log->mutex);
-		if (!ret)
-			break;
-
-		if (file->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			break;
-		}
-
-		if (signal_pending(current)) {
-			ret = -EINTR;
-			break;
-		}
-
-		schedule();
-	}
-
-	finish_wait(&log->wq, &wait);
-	if (ret)
-		return ret;
-
-	mutex_lock(&log->mutex);
-
-	if (!reader->r_all)
-		reader->r_off = get_next_entry_by_uid(log,
-			reader->r_off, current_euid());
-
-	/* is there still something to read or did we race? */
-	if (unlikely(log->w_off == reader->r_off)) {
-		mutex_unlock(&log->mutex);
-		goto start;
-	}
-
-	/* get the size of the next entry */
-	ret = get_user_hdr_len(reader->r_ver) +
-		get_entry_msg_len(log, reader->r_off);
-	if (count < ret) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	/* get exactly one entry from the log */
-	ret = do_read_log_to_user(log, reader, buf, ret);
-
-out:
-	mutex_unlock(&log->mutex);
-
-	return ret;
-}
-
-/*
- * get_next_entry - return the offset of the first valid entry at least 'len'
- * bytes after 'off'.
- *
- * Caller must hold log->mutex.
- */
-static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
-{
-	size_t count = 0;
-
-	do {
-		size_t nr = sizeof(struct logger_entry) +
-			get_entry_msg_len(log, off);
-		off = logger_offset(log, off + nr);
-		count += nr;
-	} while (count < len);
-
-	return off;
-}
-
-/*
- * is_between - is a < c < b, accounting for wrapping of a, b, and c
- *    positions in the buffer
- *
- * That is, if a<b, check for c between a and b
- * and if a>b, check for c outside (not between) a and b
- *
- * |------- a xxxxxxxx b --------|
- *               c^
- *
- * |xxxxx b --------- a xxxxxxxxx|
- *    c^
- *  or                    c^
- */
-static inline int is_between(size_t a, size_t b, size_t c)
-{
-	if (a < b) {
-		/* is c between a and b? */
-		if (a < c && c <= b)
-			return 1;
-	} else {
-		/* is c outside of b through a? */
-		if (c <= b || a < c)
-			return 1;
-	}
-
-	return 0;
-}
-
-/*
- * fix_up_readers - walk the list of all readers and "fix up" any who were
- * lapped by the writer; also do the same for the default "start head".
- * We do this by "pulling forward" the readers and start head to the first
- * entry after the new write head.
- *
- * The caller needs to hold log->mutex.
- */
-static void fix_up_readers(struct logger_log *log, size_t len)
-{
-	size_t old = log->w_off;
-	size_t new = logger_offset(log, old + len);
-	struct logger_reader *reader;
-
-	if (is_between(old, new, log->head))
-		log->head = get_next_entry(log, log->head, len);
-
-	list_for_each_entry(reader, &log->readers, list)
-		if (is_between(old, new, reader->r_off))
-			reader->r_off = get_next_entry(log, reader->r_off, len);
-}
-
-/*
- * logger_write_iter - our write method, implementing support for write(),
- * writev(), and aio_write(). Writes are our fast path, and we try to optimize
- * them above all else.
- */
-static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
-{
-	struct logger_log *log = file_get_log(iocb->ki_filp);
-	struct logger_entry header;
-	struct timespec now;
-	size_t len, count, w_off;
-
-	count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
-
-	now = current_kernel_time();
-
-	header.pid = current->tgid;
-	header.tid = current->pid;
-	header.sec = now.tv_sec;
-	header.nsec = now.tv_nsec;
-	header.euid = current_euid();
-	header.len = count;
-	header.hdr_size = sizeof(struct logger_entry);
-
-	/* null writes succeed, return zero */
-	if (unlikely(!header.len))
-		return 0;
-
-	mutex_lock(&log->mutex);
-
-	/*
-	 * Fix up any readers, pulling them forward to the first readable
-	 * entry after (what will be) the new write offset. We do this now
-	 * because if we partially fail, we can end up with clobbered log
-	 * entries that encroach on readable buffer.
-	 */
-	fix_up_readers(log, sizeof(struct logger_entry) + header.len);
-
-	len = min(sizeof(header), log->size - log->w_off);
-	memcpy(log->buffer + log->w_off, &header, len);
-	memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
-
-	/* Work with a copy until we are ready to commit the whole entry */
-	w_off =  logger_offset(log, log->w_off + sizeof(struct logger_entry));
-
-	len = min(count, log->size - w_off);
-
-	if (copy_from_iter(log->buffer + w_off, len, from) != len) {
-		/*
-		 * Note that by not updating log->w_off, this abandons the
-		 * portion of the new entry that *was* successfully
-		 * copied, just above.  This is intentional to avoid
-		 * message corruption from missing fragments.
-		 */
-		mutex_unlock(&log->mutex);
-		return -EFAULT;
-	}
-
-	if (copy_from_iter(log->buffer, count - len, from) != count - len) {
-		mutex_unlock(&log->mutex);
-		return -EFAULT;
-	}
-
-	log->w_off = logger_offset(log, w_off + count);
-	mutex_unlock(&log->mutex);
-
-	/* wake up any blocked readers */
-	wake_up_interruptible(&log->wq);
-
-	return len;
-}
-
-static struct logger_log *get_log_from_minor(int minor)
-{
-	struct logger_log *log;
-
-	list_for_each_entry(log, &log_list, logs)
-		if (log->misc.minor == minor)
-			return log;
-	return NULL;
-}
-
-/*
- * logger_open - the log's open() file operation
- *
- * Note how near a no-op this is in the write-only case. Keep it that way!
- */
-static int logger_open(struct inode *inode, struct file *file)
-{
-	struct logger_log *log;
-	int ret;
-
-	ret = nonseekable_open(inode, file);
-	if (ret)
-		return ret;
-
-	log = get_log_from_minor(MINOR(inode->i_rdev));
-	if (!log)
-		return -ENODEV;
-
-	if (file->f_mode & FMODE_READ) {
-		struct logger_reader *reader;
-
-		reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
-		if (!reader)
-			return -ENOMEM;
-
-		reader->log = log;
-		reader->r_ver = 1;
-		reader->r_all = in_egroup_p(inode->i_gid) ||
-			capable(CAP_SYSLOG);
-
-		INIT_LIST_HEAD(&reader->list);
-
-		mutex_lock(&log->mutex);
-		reader->r_off = log->head;
-		list_add_tail(&reader->list, &log->readers);
-		mutex_unlock(&log->mutex);
-
-		file->private_data = reader;
-	} else
-		file->private_data = log;
-
-	return 0;
-}
-
-/*
- * logger_release - the log's release file operation
- *
- * Note this is a total no-op in the write-only case. Keep it that way!
- */
-static int logger_release(struct inode *ignored, struct file *file)
-{
-	if (file->f_mode & FMODE_READ) {
-		struct logger_reader *reader = file->private_data;
-		struct logger_log *log = reader->log;
-
-		mutex_lock(&log->mutex);
-		list_del(&reader->list);
-		mutex_unlock(&log->mutex);
-
-		kfree(reader);
-	}
-
-	return 0;
-}
-
-/*
- * logger_poll - the log's poll file operation, for poll/select/epoll
- *
- * Note we always return POLLOUT, because you can always write() to the log.
- * Note also that, strictly speaking, a return value of POLLIN does not
- * guarantee that the log is readable without blocking, as there is a small
- * chance that the writer can lap the reader in the interim between poll()
- * returning and the read() request.
- */
-static unsigned int logger_poll(struct file *file, poll_table *wait)
-{
-	struct logger_reader *reader;
-	struct logger_log *log;
-	unsigned int ret = POLLOUT | POLLWRNORM;
-
-	if (!(file->f_mode & FMODE_READ))
-		return ret;
-
-	reader = file->private_data;
-	log = reader->log;
-
-	poll_wait(file, &log->wq, wait);
-
-	mutex_lock(&log->mutex);
-	if (!reader->r_all)
-		reader->r_off = get_next_entry_by_uid(log,
-			reader->r_off, current_euid());
-
-	if (log->w_off != reader->r_off)
-		ret |= POLLIN | POLLRDNORM;
-	mutex_unlock(&log->mutex);
-
-	return ret;
-}
-
-static long logger_set_version(struct logger_reader *reader, void __user *arg)
-{
-	int version;
-
-	if (copy_from_user(&version, arg, sizeof(int)))
-		return -EFAULT;
-
-	if ((version < 1) || (version > 2))
-		return -EINVAL;
-
-	reader->r_ver = version;
-	return 0;
-}
-
-static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct logger_log *log = file_get_log(file);
-	struct logger_reader *reader;
-	long ret = -EINVAL;
-	void __user *argp = (void __user *) arg;
-
-	mutex_lock(&log->mutex);
-
-	switch (cmd) {
-	case LOGGER_GET_LOG_BUF_SIZE:
-		ret = log->size;
-		break;
-	case LOGGER_GET_LOG_LEN:
-		if (!(file->f_mode & FMODE_READ)) {
-			ret = -EBADF;
-			break;
-		}
-		reader = file->private_data;
-		if (log->w_off >= reader->r_off)
-			ret = log->w_off - reader->r_off;
-		else
-			ret = (log->size - reader->r_off) + log->w_off;
-		break;
-	case LOGGER_GET_NEXT_ENTRY_LEN:
-		if (!(file->f_mode & FMODE_READ)) {
-			ret = -EBADF;
-			break;
-		}
-		reader = file->private_data;
-
-		if (!reader->r_all)
-			reader->r_off = get_next_entry_by_uid(log,
-				reader->r_off, current_euid());
-
-		if (log->w_off != reader->r_off)
-			ret = get_user_hdr_len(reader->r_ver) +
-				get_entry_msg_len(log, reader->r_off);
-		else
-			ret = 0;
-		break;
-	case LOGGER_FLUSH_LOG:
-		if (!(file->f_mode & FMODE_WRITE)) {
-			ret = -EBADF;
-			break;
-		}
-		if (!(in_egroup_p(file_inode(file)->i_gid) ||
-				capable(CAP_SYSLOG))) {
-			ret = -EPERM;
-			break;
-		}
-		list_for_each_entry(reader, &log->readers, list)
-			reader->r_off = log->w_off;
-		log->head = log->w_off;
-		ret = 0;
-		break;
-	case LOGGER_GET_VERSION:
-		if (!(file->f_mode & FMODE_READ)) {
-			ret = -EBADF;
-			break;
-		}
-		reader = file->private_data;
-		ret = reader->r_ver;
-		break;
-	case LOGGER_SET_VERSION:
-		if (!(file->f_mode & FMODE_READ)) {
-			ret = -EBADF;
-			break;
-		}
-		reader = file->private_data;
-		ret = logger_set_version(reader, argp);
-		break;
-	}
-
-	mutex_unlock(&log->mutex);
-
-	return ret;
-}
-
-static const struct file_operations logger_fops = {
-	.owner = THIS_MODULE,
-	.read = logger_read,
-	.write_iter = logger_write_iter,
-	.poll = logger_poll,
-	.unlocked_ioctl = logger_ioctl,
-	.compat_ioctl = logger_ioctl,
-	.open = logger_open,
-	.release = logger_release,
-};
-
-/*
- * Log size must must be a power of two, and greater than
- * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
- */
-static int __init create_log(char *log_name, int size)
-{
-	int ret = 0;
-	struct logger_log *log;
-	unsigned char *buffer;
-
-	buffer = vmalloc(size);
-	if (buffer == NULL)
-		return -ENOMEM;
-
-	log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
-	if (log == NULL) {
-		ret = -ENOMEM;
-		goto out_free_buffer;
-	}
-	log->buffer = buffer;
-
-	log->misc.minor = MISC_DYNAMIC_MINOR;
-	log->misc.name = kstrdup(log_name, GFP_KERNEL);
-	if (log->misc.name == NULL) {
-		ret = -ENOMEM;
-		goto out_free_log;
-	}
-
-	log->misc.fops = &logger_fops;
-	log->misc.parent = NULL;
-
-	init_waitqueue_head(&log->wq);
-	INIT_LIST_HEAD(&log->readers);
-	mutex_init(&log->mutex);
-	log->w_off = 0;
-	log->head = 0;
-	log->size = size;
-
-	INIT_LIST_HEAD(&log->logs);
-	list_add_tail(&log->logs, &log_list);
-
-	/* finally, initialize the misc device for this log */
-	ret = misc_register(&log->misc);
-	if (unlikely(ret)) {
-		pr_err("failed to register misc device for log '%s'!\n",
-				log->misc.name);
-		goto out_free_misc_name;
-	}
-
-	pr_info("created %luK log '%s'\n",
-		(unsigned long) log->size >> 10, log->misc.name);
-
-	return 0;
-
-out_free_misc_name:
-	kfree(log->misc.name);
-
-out_free_log:
-	kfree(log);
-
-out_free_buffer:
-	vfree(buffer);
-	return ret;
-}
-
-static int __init logger_init(void)
-{
-	int ret;
-
-	ret = create_log(LOGGER_LOG_MAIN, 256*1024);
-	if (unlikely(ret))
-		goto out;
-
-	ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
-	if (unlikely(ret))
-		goto out;
-
-	ret = create_log(LOGGER_LOG_RADIO, 256*1024);
-	if (unlikely(ret))
-		goto out;
-
-	ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
-	if (unlikely(ret))
-		goto out;
-
-out:
-	return ret;
-}
-
-static void __exit logger_exit(void)
-{
-	struct logger_log *current_log, *next_log;
-
-	list_for_each_entry_safe(current_log, next_log, &log_list, logs) {
-		/* we have to delete all the entry inside log_list */
-		misc_deregister(&current_log->misc);
-		vfree(current_log->buffer);
-		kfree(current_log->misc.name);
-		list_del(&current_log->logs);
-		kfree(current_log);
-	}
-}
-
-
-device_initcall(logger_init);
-module_exit(logger_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Robert Love, <rlove@google.com>");
-MODULE_DESCRIPTION("Android Logger");
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
deleted file mode 100644
index 70af7d8..0000000
--- a/drivers/staging/android/logger.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* include/linux/logger.h
- *
- * Copyright (C) 2007-2008 Google, Inc.
- * Author: Robert Love <rlove@android.com>
- *
- * 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.
- *
- */
-
-#ifndef _LINUX_LOGGER_H
-#define _LINUX_LOGGER_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-/**
- * struct user_logger_entry_compat - defines a single entry that is given to a logger
- * @len:	The length of the payload
- * @__pad:	Two bytes of padding that appear to be required
- * @pid:	The generating process' process ID
- * @tid:	The generating process' thread ID
- * @sec:	The number of seconds that have elapsed since the Epoch
- * @nsec:	The number of nanoseconds that have elapsed since @sec
- * @msg:	The message that is to be logged
- *
- * The userspace structure for version 1 of the logger_entry ABI.
- * This structure is returned to userspace unless the caller requests
- * an upgrade to a newer ABI version.
- */
-struct user_logger_entry_compat {
-	__u16		len;
-	__u16		__pad;
-	__s32		pid;
-	__s32		tid;
-	__s32		sec;
-	__s32		nsec;
-	char		msg[0];
-};
-
-/**
- * struct logger_entry - defines a single entry that is given to a logger
- * @len:	The length of the payload
- * @hdr_size:	sizeof(struct logger_entry_v2)
- * @pid:	The generating process' process ID
- * @tid:	The generating process' thread ID
- * @sec:	The number of seconds that have elapsed since the Epoch
- * @nsec:	The number of nanoseconds that have elapsed since @sec
- * @euid:	Effective UID of logger
- * @msg:	The message that is to be logged
- *
- * The structure for version 2 of the logger_entry ABI.
- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version >= 2
- */
-struct logger_entry {
-	__u16		len;
-	__u16		hdr_size;
-	__s32		pid;
-	__s32		tid;
-	__s32		sec;
-	__s32		nsec;
-	kuid_t		euid;
-	char		msg[0];
-};
-
-#define LOGGER_LOG_RADIO	"log_radio"	/* radio-related messages */
-#define LOGGER_LOG_EVENTS	"log_events"	/* system/hardware events */
-#define LOGGER_LOG_SYSTEM	"log_system"	/* system/framework messages */
-#define LOGGER_LOG_MAIN		"log_main"	/* everything else */
-
-#define LOGGER_ENTRY_MAX_PAYLOAD	4076
-
-#define __LOGGERIO	0xAE
-
-#define LOGGER_GET_LOG_BUF_SIZE		_IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN		_IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN	_IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG		_IO(__LOGGERIO, 4) /* flush log */
-#define LOGGER_GET_VERSION		_IO(__LOGGERIO, 5) /* abi version */
-#define LOGGER_SET_VERSION		_IO(__LOGGERIO, 6) /* abi version */
-
-#endif /* _LINUX_LOGGER_H */
diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c
index 1532a86..91ed2c4c 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -96,7 +96,8 @@
 		   sync_status_str(status));
 
 	if (status <= 0) {
-		struct timespec64 ts64 = ktime_to_timespec64(pt->base.timestamp);
+		struct timespec64 ts64 =
+			ktime_to_timespec64(pt->base.timestamp);
 
 		seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
 	}
diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h
deleted file mode 100644
index aa013f6..0000000
--- a/drivers/staging/android/uapi/android_alarm.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* drivers/staging/android/uapi/android_alarm.h
- *
- * Copyright (C) 2006-2007 Google, Inc.
- *
- * 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.
- *
- */
-
-#ifndef _UAPI_LINUX_ANDROID_ALARM_H
-#define _UAPI_LINUX_ANDROID_ALARM_H
-
-#include <linux/ioctl.h>
-#include <linux/time.h>
-
-enum android_alarm_type {
-	/* return code bit numbers or set alarm arg */
-	ANDROID_ALARM_RTC_WAKEUP,
-	ANDROID_ALARM_RTC,
-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
-	ANDROID_ALARM_ELAPSED_REALTIME,
-	ANDROID_ALARM_SYSTEMTIME,
-
-	ANDROID_ALARM_TYPE_COUNT,
-
-	/* return code bit numbers */
-	/* ANDROID_ALARM_TIME_CHANGE = 16 */
-};
-
-enum android_alarm_return_flags {
-	ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
-	ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
-	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
-				1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
-	ANDROID_ALARM_ELAPSED_REALTIME_MASK =
-				1U << ANDROID_ALARM_ELAPSED_REALTIME,
-	ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
-	ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
-};
-
-/* Disable alarm */
-#define ANDROID_ALARM_CLEAR(type)           _IO('a', 0 | ((type) << 4))
-
-/* Ack last alarm and wait for next */
-#define ANDROID_ALARM_WAIT                  _IO('a', 1)
-
-#define ALARM_IOW(c, type, size)            _IOW('a', (c) | ((type) << 4), size)
-/* Set alarm */
-#define ANDROID_ALARM_SET(type)             ALARM_IOW(2, type, struct timespec)
-#define ANDROID_ALARM_SET_AND_WAIT(type)    ALARM_IOW(3, type, struct timespec)
-#define ANDROID_ALARM_GET_TIME(type)        ALARM_IOW(4, type, struct timespec)
-#define ANDROID_ALARM_SET_RTC               _IOW('a', 5, struct timespec)
-#define ANDROID_ALARM_BASE_CMD(cmd)         (cmd & ~(_IOC(0, 0, 0xf0, 0)))
-#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd)    (_IOC_NR(cmd) >> 4)
-
-#endif
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
index 6050fbd..d5a6abc 100644
--- a/drivers/staging/board/board.c
+++ b/drivers/staging/board/board.c
@@ -11,8 +11,7 @@
 	struct resource res;
 
 	while (dn) {
-		if (of_can_translate_address(dn)
-		    && !of_address_to_resource(dn, 0, &res)) {
+		if (!of_address_to_resource(dn, 0, &res)) {
 			if (res.start == base_address) {
 				of_node_put(dn);
 				return true;
diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
index 471d0877..5455bf3 100644
--- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
+++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
@@ -91,8 +91,10 @@
 
 	if (ndata->clk == clk_wzrd->clk_in1)
 		max = clk_wzrd_max_freq[clk_wzrd->speed_grade - 1];
-	if (ndata->clk == clk_wzrd->axi_clk)
+	else if (ndata->clk == clk_wzrd->axi_clk)
 		max = WZRD_ACLK_MAX_FREQ;
+	else
+		return NOTIFY_DONE;	/* should never happen */
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
@@ -239,6 +241,7 @@
 	/* register div per output */
 	for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) {
 		const char *clkout_name;
+
 		if (of_property_read_string_index(np, "clock-output-names", i,
 						  &clkout_name)) {
 			dev_err(&pdev->dev,
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index a8201fe..593fcb1 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -168,7 +168,7 @@
 
 config COMEDI_PCL812
 	tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
 	  ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -179,7 +179,7 @@
 
 config COMEDI_PCL816
 	tristate "Advantech PCL-814 and PCL-816 ISA card support"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for Advantech PCL-814 and PCL-816 ISA cards
 
@@ -188,7 +188,7 @@
 
 config COMEDI_PCL818
 	tristate "Advantech PCL-718 and PCL-818 ISA card support"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for Advantech PCL-818 ISA cards
 	  PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -281,7 +281,7 @@
 
 config COMEDI_DAS16
 	tristate "DAS-16 compatible ISA and PC/104 card support"
-	depends on ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	select COMEDI_8255
 	---help---
 	  Enable support for Keithley Metrabyte/ComputerBoards DAS16
@@ -309,7 +309,7 @@
 
 config COMEDI_DAS1800
 	tristate "DAS1800 and compatible ISA card support"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for DAS1800 and compatible ISA cards
 	  Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -372,7 +372,7 @@
 
 config COMEDI_DT282X
 	tristate "Data Translation DT2821 series and DT-EZ ISA card support"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for Data Translation DT2821 series including DT-EZ
 	  DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI,
@@ -462,7 +462,7 @@
 
 config COMEDI_NI_AT_A2150
 	tristate "NI AT-A2150 ISA card support"
-	depends on VIRT_TO_BUS && ISA_DMA_API
+	select COMEDI_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for National Instruments AT-A2150 cards
 
@@ -502,7 +502,7 @@
 config COMEDI_NI_LABPC_ISA
 	tristate "NI Lab-PC and compatibles ISA support"
 	select COMEDI_NI_LABPC
-	select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS
+	select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API
 	---help---
 	  Enable support for National Instruments Lab-PC and compatibles
 	  Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
@@ -724,7 +724,6 @@
 config COMEDI_ADL_PCI9118
 	tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
 	depends on HAS_DMA
-	depends on VIRT_TO_BUS
 	---help---
 	  Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
 
@@ -1263,12 +1262,16 @@
 	tristate
 	select COMEDI_8255
 
+config COMEDI_ISADMA
+	tristate
+
 config COMEDI_NI_LABPC
 	tristate
 	select COMEDI_8255
 
 config COMEDI_NI_LABPC_ISADMA
 	tristate
+	select COMEDI_ISADMA
 
 config COMEDI_NI_TIO
 	tristate
diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c
index 5a4c74f..2584824 100644
--- a/drivers/staging/comedi/comedi_compat32.c
+++ b/drivers/staging/comedi/comedi_compat32.c
@@ -1,23 +1,23 @@
 /*
-    comedi/comedi_compat32.c
-    32-bit ioctl compatibility for 64-bit comedi kernel module.
-
-    Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
-    Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1997-2007 David A. Schleef <ds@schleef.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.
-*/
+ * comedi/comedi_compat32.c
+ * 32-bit ioctl compatibility for 64-bit comedi kernel module.
+ *
+ * Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
+ * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2007 David A. Schleef <ds@schleef.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/uaccess.h>
 #include <linux/compat.h>
@@ -27,11 +27,15 @@
 
 #define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
 #define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
-/* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
- * It's too late to change it now, but it only affects the command number. */
+/*
+ * N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
+ * It's too late to change it now, but it only affects the command number.
+ */
 #define COMEDI32_CMD _IOR(CIO, 9, struct comedi32_cmd_struct)
-/* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
- * It's too late to change it now, but it only affects the command number. */
+/*
+ * N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
+ * It's too late to change it now, but it only affects the command number.
+ */
 #define COMEDI32_CMDTEST _IOR(CIO, 10, struct comedi32_cmd_struct)
 #define COMEDI32_INSNLIST _IOR(CIO, 11, struct comedi32_insnlist_struct)
 #define COMEDI32_INSN _IOR(CIO, 12, struct comedi32_insn_struct)
@@ -39,7 +43,7 @@
 struct comedi32_chaninfo_struct {
 	unsigned int subdev;
 	compat_uptr_t maxdata_list;	/* 32-bit 'unsigned int *' */
-	compat_uptr_t flaglist;	/* 32-bit 'unsigned int *' */
+	compat_uptr_t flaglist;		/* 32-bit 'unsigned int *' */
 	compat_uptr_t rangelist;	/* 32-bit 'unsigned int *' */
 	unsigned int unused[4];
 };
@@ -62,16 +66,16 @@
 	unsigned int scan_end_arg;
 	unsigned int stop_src;
 	unsigned int stop_arg;
-	compat_uptr_t chanlist;	/* 32-bit 'unsigned int *' */
+	compat_uptr_t chanlist;		/* 32-bit 'unsigned int *' */
 	unsigned int chanlist_len;
-	compat_uptr_t data;	/* 32-bit 'short *' */
+	compat_uptr_t data;		/* 32-bit 'short *' */
 	unsigned int data_len;
 };
 
 struct comedi32_insn_struct {
 	unsigned int insn;
 	unsigned int n;
-	compat_uptr_t data;	/* 32-bit 'unsigned int *' */
+	compat_uptr_t data;		/* 32-bit 'unsigned int *' */
 	unsigned int subdev;
 	unsigned int chanspec;
 	unsigned int unused[3];
@@ -79,7 +83,7 @@
 
 struct comedi32_insnlist_struct {
 	unsigned int n_insns;
-	compat_uptr_t insns;	/* 32-bit 'struct comedi_insn *' */
+	compat_uptr_t insns;		/* 32-bit 'struct comedi_insn *' */
 };
 
 /* Handle translated ioctl. */
@@ -215,10 +219,12 @@
 	int err;
 	unsigned int temp;
 
-	/* Copy back most of cmd structure. */
-	/* Assume the pointer values are already valid. */
-	/* (Could use ptr_to_compat() to set them, but that wasn't implemented
-	 * until kernel version 2.6.11.) */
+	/*
+	 * Copy back most of cmd structure.
+	 *
+	 * Assume the pointer values are already valid.
+	 * (Could use ptr_to_compat() to set them.)
+	 */
 	if (!access_ok(VERIFY_READ, cmd, sizeof(*cmd)) ||
 	    !access_ok(VERIFY_WRITE, cmd32, sizeof(*cmd32)))
 		return -EFAULT;
@@ -262,7 +268,7 @@
 {
 	struct comedi_cmd __user *cmd;
 	struct comedi32_cmd_struct __user *cmd32;
-	int rc;
+	int rc, err;
 
 	cmd32 = compat_ptr(arg);
 	cmd = compat_alloc_user_space(sizeof(*cmd));
@@ -271,7 +277,15 @@
 	if (rc)
 		return rc;
 
-	return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
+	rc = translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
+	if (rc == -EAGAIN) {
+		/* Special case: copy cmd back to user. */
+		err = put_compat_cmd(cmd32, cmd);
+		if (err)
+			rc = err;
+	}
+
+	return rc;
 }
 
 /* Handle 32-bit COMEDI_CMDTEST ioctl. */
@@ -395,10 +409,12 @@
 	return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn);
 }
 
-/* Process untranslated ioctl. */
-/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
-static inline int raw_ioctl(struct file *file, unsigned int cmd,
-			    unsigned long arg)
+/*
+ * compat_ioctl file operation.
+ *
+ * Returns -ENOIOCTLCMD for unrecognised ioctl codes.
+ */
+long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int rc;
 
@@ -445,10 +461,3 @@
 	}
 	return rc;
 }
-
-/* compat_ioctl file operation. */
-/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
-long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	return raw_ioctl(file, cmd, arg);
-}
diff --git a/drivers/staging/comedi/comedi_compat32.h b/drivers/staging/comedi/comedi_compat32.h
index 2d0a6fc..5ce77f3 100644
--- a/drivers/staging/comedi/comedi_compat32.h
+++ b/drivers/staging/comedi/comedi_compat32.h
@@ -1,23 +1,23 @@
 /*
-    comedi/comedi_compat32.h
-    32-bit ioctl compatibility for 64-bit comedi kernel module.
-
-    Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
-    Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1997-2007 David A. Schleef <ds@schleef.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.
-*/
+ * comedi/comedi_compat32.h
+ * 32-bit ioctl compatibility for 64-bit comedi kernel module.
+ *
+ * Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
+ * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2007 David A. Schleef <ds@schleef.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.
+ */
 
 #ifndef _COMEDI_COMPAT32_H
 #define _COMEDI_COMPAT32_H
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f143cb6..727640e 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1,20 +1,20 @@
 /*
-    comedi/comedi_fops.c
-    comedi kernel module
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1997-2000 David A. Schleef <ds@schleef.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.
-*/
+ * comedi/comedi_fops.c
+ * comedi kernel module
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.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.
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -113,6 +113,18 @@
 	kfree(dev);
 }
 
+/**
+ * comedi_dev_put - release a use of a comedi device structure
+ * @dev: comedi_device struct
+ *
+ * Must be called when a user of a comedi device is finished with it.
+ * When the last user of the comedi device calls this function, the
+ * comedi device is destroyed.
+ *
+ * Return 1 if the comedi device is destroyed by this call or dev is
+ * NULL, otherwise return 0.  Callers must not assume the comedi
+ * device is still valid if this function returns 0.
+ */
 int comedi_dev_put(struct comedi_device *dev)
 {
 	if (dev)
@@ -220,6 +232,18 @@
 	return dev;
 }
 
+/**
+ * comedi_dev_get_from_minor - get comedi device by minor device number
+ * @minor: minor device number
+ *
+ * Finds the comedi device associated by the minor device number, if any,
+ * and increments its reference count.  The comedi device is prevented from
+ * being freed until a matching call is made to comedi_dev_put().
+ *
+ * Return a pointer to the comedi device if it exists, with its usage
+ * reference incremented.  Return NULL if no comedi device exists with the
+ * specified minor device number.
+ */
 struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
 {
 	if (minor < COMEDI_NUM_BOARD_MINORS)
@@ -323,8 +347,7 @@
 		return -EBUSY;
 	}
 
-	/* make sure buffer is an integral number of pages
-	 * (we round up) */
+	/* make sure buffer is an integral number of pages (we round up) */
 	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
 
 	retval = comedi_buf_alloc(dev, s, new_size);
@@ -600,11 +623,18 @@
 	return runflags;
 }
 
+/**
+ * comedi_is_subdevice_running - check if async command running on subdevice
+ * @s: comedi_subdevice struct
+ *
+ * Return true if an asynchronous comedi command is active on the comedi
+ * subdevice, else return false.
+ */
 bool comedi_is_subdevice_running(struct comedi_subdevice *s)
 {
 	unsigned runflags = comedi_get_subdevice_runflags(s);
 
-	return (runflags & SRF_RUNNING) ? true : false;
+	return (runflags & COMEDI_SRF_RUNNING) ? true : false;
 }
 EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
 
@@ -612,14 +642,14 @@
 {
 	unsigned runflags = comedi_get_subdevice_runflags(s);
 
-	return (runflags & SRF_ERROR) ? true : false;
+	return (runflags & COMEDI_SRF_ERROR) ? true : false;
 }
 
 static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
 {
 	unsigned runflags = comedi_get_subdevice_runflags(s);
 
-	return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
+	return (runflags & COMEDI_SRF_BUSY_MASK) ? false : true;
 }
 
 /**
@@ -634,20 +664,20 @@
 {
 	s->private = kzalloc(size, GFP_KERNEL);
 	if (s->private)
-		s->runflags |= SRF_FREE_SPRIV;
+		s->runflags |= COMEDI_SRF_FREE_SPRIV;
 	return s->private;
 }
 EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
 
 /*
-   This function restores a subdevice to an idle state.
+ * This function restores a subdevice to an idle state.
  */
 static void do_become_nonbusy(struct comedi_device *dev,
 			      struct comedi_subdevice *s)
 {
 	struct comedi_async *async = s->async;
 
-	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
+	comedi_set_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
 	if (async) {
 		comedi_buf_reset(s);
 		async->inttrig = NULL;
@@ -709,18 +739,18 @@
 }
 
 /*
-	COMEDI_DEVCONFIG
-	device config ioctl
-
-	arg:
-		pointer to devconfig structure
-
-	reads:
-		devconfig structure at arg
-
-	writes:
-		none
-*/
+ * COMEDI_DEVCONFIG ioctl
+ * attaches (and configures) or detaches a legacy device
+ *
+ * arg:
+ *	pointer to comedi_devconfig structure (NULL if detaching)
+ *
+ * reads:
+ *	comedi_devconfig structure (if attaching)
+ *
+ * writes:
+ *	nothing
+ */
 static int do_devconfig_ioctl(struct comedi_device *dev,
 			      struct comedi_devconfig __user *arg)
 {
@@ -761,19 +791,18 @@
 }
 
 /*
-	COMEDI_BUFCONFIG
-	buffer configuration ioctl
-
-	arg:
-		pointer to bufconfig structure
-
-	reads:
-		bufconfig at arg
-
-	writes:
-		modified bufconfig at arg
-
-*/
+ * COMEDI_BUFCONFIG ioctl
+ * buffer configuration
+ *
+ * arg:
+ *	pointer to comedi_bufconfig structure
+ *
+ * reads:
+ *	comedi_bufconfig structure
+ *
+ * writes:
+ *	modified comedi_bufconfig structure
+ */
 static int do_bufconfig_ioctl(struct comedi_device *dev,
 			      struct comedi_bufconfig __user *arg)
 {
@@ -823,19 +852,18 @@
 }
 
 /*
-	COMEDI_DEVINFO
-	device info ioctl
-
-	arg:
-		pointer to devinfo structure
-
-	reads:
-		none
-
-	writes:
-		devinfo structure
-
-*/
+ * COMEDI_DEVINFO ioctl
+ * device info
+ *
+ * arg:
+ *	pointer to comedi_devinfo structure
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	comedi_devinfo structure
+ */
 static int do_devinfo_ioctl(struct comedi_device *dev,
 			    struct comedi_devinfo __user *arg,
 			    struct file *file)
@@ -870,19 +898,18 @@
 }
 
 /*
-	COMEDI_SUBDINFO
-	subdevice info ioctl
-
-	arg:
-		pointer to array of subdevice info structures
-
-	reads:
-		none
-
-	writes:
-		array of subdevice info structures at arg
-
-*/
+ * COMEDI_SUBDINFO ioctl
+ * subdevices info
+ *
+ * arg:
+ *	pointer to array of comedi_subdinfo structures
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	array of comedi_subdinfo structures
+ */
 static int do_subdinfo_ioctl(struct comedi_device *dev,
 			     struct comedi_subdinfo __user *arg, void *file)
 {
@@ -944,19 +971,19 @@
 }
 
 /*
-	COMEDI_CHANINFO
-	subdevice info ioctl
-
-	arg:
-		pointer to chaninfo structure
-
-	reads:
-		chaninfo structure at arg
-
-	writes:
-		arrays at elements of chaninfo structure
-
-*/
+ * COMEDI_CHANINFO ioctl
+ * subdevice channel info
+ *
+ * arg:
+ *	pointer to comedi_chaninfo structure
+ *
+ * reads:
+ *	comedi_chaninfo structure
+ *
+ * writes:
+ *	array of maxdata values to chaninfo->maxdata_list if requested
+ *	array of range table lengths to chaninfo->range_table_list if requested
+ */
 static int do_chaninfo_ioctl(struct comedi_device *dev,
 			     struct comedi_chaninfo __user *arg)
 {
@@ -1004,20 +1031,19 @@
 	return 0;
 }
 
- /*
-    COMEDI_BUFINFO
-    buffer information ioctl
-
-    arg:
-    pointer to bufinfo structure
-
-    reads:
-    bufinfo at arg
-
-    writes:
-    modified bufinfo at arg
-
-  */
+/*
+ * COMEDI_BUFINFO ioctl
+ * buffer information
+ *
+ * arg:
+ *	pointer to comedi_bufinfo structure
+ *
+ * reads:
+ *	comedi_bufinfo structure
+ *
+ * writes:
+ *	modified comedi_bufinfo structure
+ */
 static int do_bufinfo_ioctl(struct comedi_device *dev,
 			    struct comedi_bufinfo __user *arg, void *file)
 {
@@ -1135,8 +1161,10 @@
 		if (insn->n == 6)
 			return 0;
 		break;
-		/* by default we allow the insn since we don't have checks for
-		 * all possible cases yet */
+		/*
+		 * by default we allow the insn since we don't have checks for
+		 * all possible cases yet
+		 */
 	default:
 		pr_warn("No check for data length of config insn id %i is implemented\n",
 			data[0]);
@@ -1287,9 +1315,11 @@
 			if (insn->n != 2) {
 				ret = -EINVAL;
 			} else {
-				/* Most drivers ignore the base channel in
+				/*
+				 * Most drivers ignore the base channel in
 				 * insn->chanspec.  Fix this here if
-				 * the subdevice has <= 32 channels.  */
+				 * the subdevice has <= 32 channels.
+				 */
 				unsigned int orig_mask = data[0];
 				unsigned int shift = 0;
 
@@ -1326,19 +1356,19 @@
 }
 
 /*
- *	COMEDI_INSNLIST
- *	synchronous instructions
+ * COMEDI_INSNLIST ioctl
+ * synchronous instruction list
  *
- *	arg:
- *		pointer to sync cmd structure
+ * arg:
+ *	pointer to comedi_insnlist structure
  *
- *	reads:
- *		sync cmd struct at arg
- *		instruction list
- *		data (for writes)
+ * reads:
+ *	comedi_insnlist structure
+ *	array of comedi_insn structures from insnlist->insns pointer
+ *	data (for writes) from insns[].data pointers
  *
- *	writes:
- *		data (for reads)
+ * writes:
+ *	data (for reads) to insns[].data pointers
  */
 /* arbitrary limits */
 #define MAX_SAMPLES 256
@@ -1415,18 +1445,18 @@
 }
 
 /*
- *	COMEDI_INSN
- *	synchronous instructions
+ * COMEDI_INSN ioctl
+ * synchronous instruction
  *
- *	arg:
- *		pointer to insn
+ * arg:
+ *	pointer to comedi_insn structure
  *
- *	reads:
- *		struct comedi_insn struct at arg
- *		data (for writes)
+ * reads:
+ *	comedi_insn structure
+ *	data (for writes) from insn->data pointer
  *
- *	writes:
- *		data (for reads)
+ * writes:
+ *	data (for reads) to insn->data pointer
  */
 static int do_insn_ioctl(struct comedi_device *dev,
 			 struct comedi_insn __user *arg, void *file)
@@ -1558,6 +1588,20 @@
 	return 0;
 }
 
+/*
+ * COMEDI_CMD ioctl
+ * asynchronous acquisition command set-up
+ *
+ * arg:
+ *	pointer to comedi_cmd structure
+ *
+ * reads:
+ *	comedi_cmd structure
+ *	channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ *	possibly modified comedi_cmd structure (when -EAGAIN returned)
+ */
 static int do_cmd_ioctl(struct comedi_device *dev,
 			struct comedi_cmd __user *arg, void *file)
 {
@@ -1634,10 +1678,13 @@
 	if (async->cmd.flags & CMDF_WAKE_EOS)
 		async->cb_mask |= COMEDI_CB_EOS;
 
-	comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
+	comedi_set_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
+				      COMEDI_SRF_RUNNING);
 
-	/* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
-	 * comedi_read() or comedi_write() */
+	/*
+	 * Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
+	 * race with comedi_read() or comedi_write().
+	 */
 	s->busy = file;
 	ret = s->do_cmd(dev, s);
 	if (ret == 0)
@@ -1650,20 +1697,19 @@
 }
 
 /*
-	COMEDI_CMDTEST
-	command testing ioctl
-
-	arg:
-		pointer to cmd structure
-
-	reads:
-		cmd structure at arg
-		channel/range list
-
-	writes:
-		modified cmd structure at arg
-
-*/
+ * COMEDI_CMDTEST ioctl
+ * asynchronous aquisition command testing
+ *
+ * arg:
+ *	pointer to comedi_cmd structure
+ *
+ * reads:
+ *	comedi_cmd structure
+ *	channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ *	possibly modified comedi_cmd structure
+ */
 static int do_cmdtest_ioctl(struct comedi_device *dev,
 			    struct comedi_cmd __user *arg, void *file)
 {
@@ -1706,20 +1752,18 @@
 }
 
 /*
-	COMEDI_LOCK
-	lock subdevice
-
-	arg:
-		subdevice number
-
-	reads:
-		none
-
-	writes:
-		none
-
-*/
-
+ * COMEDI_LOCK ioctl
+ * lock subdevice
+ *
+ * arg:
+ *	subdevice number
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	nothing
+ */
 static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
 			 void *file)
 {
@@ -1742,21 +1786,18 @@
 }
 
 /*
-	COMEDI_UNLOCK
-	unlock subdevice
-
-	arg:
-		subdevice number
-
-	reads:
-		none
-
-	writes:
-		none
-
-	This function isn't protected by the semaphore, since
-	we already own the lock.
-*/
+ * COMEDI_UNLOCK ioctl
+ * unlock subdevice
+ *
+ * arg:
+ *	subdevice number
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	nothing
+ */
 static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
 			   void *file)
 {
@@ -1779,19 +1820,18 @@
 }
 
 /*
-	COMEDI_CANCEL
-	cancel acquisition ioctl
-
-	arg:
-		subdevice number
-
-	reads:
-		nothing
-
-	writes:
-		nothing
-
-*/
+ * COMEDI_CANCEL ioctl
+ * cancel asynchronous acquisition
+ *
+ * arg:
+ *	subdevice number
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	nothing
+ */
 static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
 			   void *file)
 {
@@ -1813,19 +1853,18 @@
 }
 
 /*
-	COMEDI_POLL ioctl
-	instructs driver to synchronize buffers
-
-	arg:
-		subdevice number
-
-	reads:
-		nothing
-
-	writes:
-		nothing
-
-*/
+ * COMEDI_POLL ioctl
+ * instructs driver to synchronize buffers
+ *
+ * arg:
+ *	subdevice number
+ *
+ * reads:
+ *	nothing
+ *
+ * writes:
+ *	nothing
+ */
 static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
 			 void *file)
 {
@@ -1941,8 +1980,10 @@
 
 	mutex_lock(&dev->mutex);
 
-	/* Device config is special, because it must work on
-	 * an unconfigured device. */
+	/*
+	 * Device config is special, because it must work on
+	 * an unconfigured device.
+	 */
 	if (cmd == COMEDI_DEVCONFIG) {
 		if (minor >= COMEDI_NUM_BOARD_MINORS) {
 			/* Device config not appropriate on non-board minors. */
@@ -1954,8 +1995,10 @@
 		if (rc == 0) {
 			if (arg == 0 &&
 			    dev->minor >= comedi_num_legacy_minors) {
-				/* Successfully unconfigured a dynamically
-				 * allocated device.  Try and remove it. */
+				/*
+				 * Successfully unconfigured a dynamically
+				 * allocated device.  Try and remove it.
+				 */
 				if (comedi_clear_board_dev(dev)) {
 					mutex_unlock(&dev->mutex);
 					comedi_free_board_dev(dev);
@@ -2581,6 +2624,17 @@
 	.llseek = noop_llseek,
 };
 
+/**
+ * comedi_event - handle events for asynchronous comedi command
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct associated with dev
+ * Context: interrupt (usually), s->spin_lock spin-lock not held
+ *
+ * If an asynchronous comedi command is active on the subdevice, process
+ * any COMEDI_CB_... event flags that have been set, usually by an
+ * interrupt handler.  These may change the run state of the asynchronous
+ * command, wake a task, and/or send a SIGIO signal.
+ */
 void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct comedi_async *async = s->async;
@@ -2591,18 +2645,21 @@
 		return;
 
 	if (s->async->events & COMEDI_CB_CANCEL_MASK)
-		runflags_mask |= SRF_RUNNING;
+		runflags_mask |= COMEDI_SRF_RUNNING;
 
 	/*
 	 * Remember if an error event has occurred, so an error
 	 * can be returned the next time the user does a read().
 	 */
 	if (s->async->events & COMEDI_CB_ERROR_MASK) {
-		runflags_mask |= SRF_ERROR;
-		runflags |= SRF_ERROR;
+		runflags_mask |= COMEDI_SRF_ERROR;
+		runflags |= COMEDI_SRF_ERROR;
 	}
 	if (runflags_mask) {
-		/*sets SRF_ERROR and SRF_RUNNING together atomically */
+		/*
+		 * Sets COMEDI_SRF_ERROR and COMEDI_SRF_RUNNING together
+		 * atomically.
+		 */
 		comedi_set_subdevice_runflags(s, runflags_mask, runflags);
 	}
 
diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c
index 0529bae..7e78439 100644
--- a/drivers/staging/comedi/comedi_pcmcia.c
+++ b/drivers/staging/comedi/comedi_pcmcia.c
@@ -19,10 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include "comedidev.h"
+#include "comedi_pcmcia.h"
 
 /**
  * comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer.
diff --git a/drivers/staging/comedi/comedi_pcmcia.h b/drivers/staging/comedi/comedi_pcmcia.h
new file mode 100644
index 0000000..5d3db2b
--- /dev/null
+++ b/drivers/staging/comedi/comedi_pcmcia.h
@@ -0,0 +1,55 @@
+/*
+ * comedi_pcmcia.h
+ * header file for Comedi PCMCIA drivers
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.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.
+ */
+
+#ifndef _COMEDI_PCMCIA_H
+#define _COMEDI_PCMCIA_H
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "comedidev.h"
+
+struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *);
+
+int comedi_pcmcia_enable(struct comedi_device *,
+			 int (*conf_check)(struct pcmcia_device *, void *));
+void comedi_pcmcia_disable(struct comedi_device *);
+
+int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *);
+void comedi_pcmcia_auto_unconfig(struct pcmcia_device *);
+
+int comedi_pcmcia_driver_register(struct comedi_driver *,
+				  struct pcmcia_driver *);
+void comedi_pcmcia_driver_unregister(struct comedi_driver *,
+				     struct pcmcia_driver *);
+
+/**
+ * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver
+ * @__comedi_driver: comedi_driver struct
+ * @__pcmcia_driver: pcmcia_driver struct
+ *
+ * Helper macro for comedi PCMCIA drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \
+	module_driver(__comedi_driver, comedi_pcmcia_driver_register, \
+			comedi_pcmcia_driver_unregister, &(__pcmcia_driver))
+
+#endif /* _COMEDI_PCMCIA_H */
diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c
index 0b862a6..68b75e8 100644
--- a/drivers/staging/comedi/comedi_usb.c
+++ b/drivers/staging/comedi/comedi_usb.c
@@ -17,9 +17,8 @@
  */
 
 #include <linux/module.h>
-#include <linux/usb.h>
 
-#include "comedidev.h"
+#include "comedi_usb.h"
 
 /**
  * comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer.
diff --git a/drivers/staging/comedi/comedi_usb.h b/drivers/staging/comedi/comedi_usb.h
new file mode 100644
index 0000000..721128b
--- /dev/null
+++ b/drivers/staging/comedi/comedi_usb.h
@@ -0,0 +1,50 @@
+/*
+ * comedi_usb.h
+ * header file for USB Comedi drivers
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.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.
+ */
+
+#ifndef _COMEDI_USB_H
+#define _COMEDI_USB_H
+
+#include <linux/usb.h>
+
+#include "comedidev.h"
+
+struct usb_interface *comedi_to_usb_interface(struct comedi_device *);
+struct usb_device *comedi_to_usb_dev(struct comedi_device *);
+
+int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *,
+			   unsigned long context);
+void comedi_usb_auto_unconfig(struct usb_interface *);
+
+int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
+void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+
+/**
+ * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
+ * @__comedi_driver: comedi_driver struct
+ * @__usb_driver: usb_driver struct
+ *
+ * Helper macro for comedi USB drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
+	module_driver(__comedi_driver, comedi_usb_driver_register, \
+			comedi_usb_driver_unregister, &(__usb_driver))
+
+#endif /* _COMEDI_USB_H */
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 77be191..e138eb0 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -299,34 +299,25 @@
 
 void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s);
 
-/* we can expand the number of bits used to encode devices/subdevices into
- the minor number soon, after more distros support > 8 bit minor numbers
- (like after Debian Etch gets released) */
-enum comedi_minor_bits {
-	COMEDI_DEVICE_MINOR_MASK = 0xf,
-	COMEDI_SUBDEVICE_MINOR_MASK = 0xf0
-};
-
-static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4;
-static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
-
 struct comedi_device *comedi_dev_get_from_minor(unsigned minor);
 int comedi_dev_put(struct comedi_device *dev);
 
-void init_polling(void);
-void cleanup_polling(void);
-void start_polling(struct comedi_device *);
-void stop_polling(struct comedi_device *);
+/**
+ * comedi_subdevice "runflags"
+ * @COMEDI_SRF_RT:		DEPRECATED: command is running real-time
+ * @COMEDI_SRF_ERROR:		indicates an COMEDI_CB_ERROR event has occurred
+ *				since the last command was started
+ * @COMEDI_SRF_RUNNING:		command is running
+ * @COMEDI_SRF_FREE_SPRIV:	free s->private on detach
+ *
+ * @COMEDI_SRF_BUSY_MASK:	runflags that indicate the subdevice is "busy"
+ */
+#define COMEDI_SRF_RT		BIT(1)
+#define COMEDI_SRF_ERROR	BIT(2)
+#define COMEDI_SRF_RUNNING	BIT(27)
+#define COMEDI_SRF_FREE_SPRIV	BIT(31)
 
-/* subdevice runflags */
-enum subdevice_runflags {
-	SRF_RT = 0x00000002,
-	/* indicates an COMEDI_CB_ERROR event has occurred since the last
-	 * command was started */
-	SRF_ERROR = 0x00000004,
-	SRF_RUNNING = 0x08000000,
-	SRF_FREE_SPRIV = 0x80000000,	/* free s->private on detach */
-};
+#define COMEDI_SRF_BUSY_MASK	(COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
 
 bool comedi_is_subdevice_running(struct comedi_subdevice *s);
 
@@ -605,66 +596,4 @@
 	module_driver(__comedi_driver, comedi_pci_driver_register, \
 			comedi_pci_driver_unregister, &(__pci_driver))
 
-/* comedi_pcmcia.c - comedi PCMCIA driver specific functions */
-
-struct pcmcia_driver;
-struct pcmcia_device;
-
-struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *);
-
-int comedi_pcmcia_enable(struct comedi_device *,
-			 int (*conf_check)(struct pcmcia_device *, void *));
-void comedi_pcmcia_disable(struct comedi_device *);
-
-int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *);
-void comedi_pcmcia_auto_unconfig(struct pcmcia_device *);
-
-int comedi_pcmcia_driver_register(struct comedi_driver *,
-				  struct pcmcia_driver *);
-void comedi_pcmcia_driver_unregister(struct comedi_driver *,
-				     struct pcmcia_driver *);
-
-/**
- * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver
- * @__comedi_driver: comedi_driver struct
- * @__pcmcia_driver: pcmcia_driver struct
- *
- * Helper macro for comedi PCMCIA drivers which do not do anything special
- * in module init/exit. This eliminates a lot of boilerplate. Each
- * module may only use this macro once, and calling it replaces
- * module_init() and module_exit()
- */
-#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \
-	module_driver(__comedi_driver, comedi_pcmcia_driver_register, \
-			comedi_pcmcia_driver_unregister, &(__pcmcia_driver))
-
-/* comedi_usb.c - comedi USB driver specific functions */
-
-struct usb_driver;
-struct usb_interface;
-
-struct usb_interface *comedi_to_usb_interface(struct comedi_device *);
-struct usb_device *comedi_to_usb_dev(struct comedi_device *);
-
-int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *,
-			   unsigned long context);
-void comedi_usb_auto_unconfig(struct usb_interface *);
-
-int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
-void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
-
-/**
- * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
- * @__comedi_driver: comedi_driver struct
- * @__usb_driver: usb_driver struct
- *
- * Helper macro for comedi USB drivers which do not do anything special
- * in module init/exit. This eliminates a lot of boilerplate. Each
- * module may only use this macro once, and calling it replaces
- * module_init() and module_exit()
- */
-#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
-	module_driver(__comedi_driver, comedi_usb_driver_register, \
-			comedi_usb_driver_unregister, &(__usb_driver))
-
 #endif /* _COMEDIDEV_H */
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 61802d7..f32e714 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -125,7 +125,7 @@
 	if (dev->subdevices) {
 		for (i = 0; i < dev->n_subdevices; i++) {
 			s = &dev->subdevices[i];
-			if (s->runflags & SRF_FREE_SPRIV)
+			if (s->runflags & COMEDI_SRF_FREE_SPRIV)
 				kfree(s->private);
 			comedi_free_subdevice_minor(s);
 			if (s->async) {
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h
index 9f4c141..51b9c8d 100644
--- a/drivers/staging/comedi/drivers/8253.h
+++ b/drivers/staging/comedi/drivers/8253.h
@@ -1,20 +1,20 @@
 /*
-    comedi/drivers/8253.h
-    Header file for 8253
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.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.
-*/
+ * comedi/drivers/8253.h
+ * Header file for 8253
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.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.
+ */
 
 #ifndef _8253_H
 #define _8253_H
@@ -44,9 +44,11 @@
 	unsigned int start;
 	unsigned int ns_low, ns_high;
 	static const unsigned int max_count = 0x10000;
-	/* exit early if everything is already correct (this can save time
+	/*
+	 * exit early if everything is already correct (this can save time
 	 * since this function may be called repeatedly during command tests
-	 * and execution) */
+	 * and execution)
+	 */
 	div1 = *d1 ? *d1 : max_count;
 	div2 = *d2 ? *d2 : max_count;
 	divider = div1 * div2;
@@ -114,13 +116,14 @@
 	}
 
 	*nanosec = div1 * div2 * i8253_osc_base;
-	/*  masking is done since counter maps zero to 0x10000 */
+	/* masking is done since counter maps zero to 0x10000 */
 	*d1 = div1 & 0xffff;
 	*d2 = div2 & 0xffff;
 }
 
 #ifndef CMDTEST
-/* i8254_load programs 8254 counter chip.  It should also work for the 8253.
+/*
+ * i8254_load programs 8254 counter chip.  It should also work for the 8253.
  * base_address is the lowest io address
  * for the chip (the address of counter 0).
  * counter_number is the counter you want to load (0,1 or 2)
@@ -158,12 +161,12 @@
 		return -1;
 
 	byte = counter_number << 6;
-	byte |= 0x30;		/*  load low then high byte */
-	byte |= (mode << 1);	/*  set counter mode */
+	byte |= 0x30;		/* load low then high byte */
+	byte |= (mode << 1);	/* set counter mode */
 	outb(byte, base_address + (i8254_control_reg << regshift));
-	byte = count & 0xff;	/*  lsb of counter value */
+	byte = count & 0xff;	/* lsb of counter value */
 	outb(byte, base_address + (counter_number << regshift));
-	byte = (count >> 8) & 0xff;	/*  msb of counter value */
+	byte = (count >> 8) & 0xff;	/* msb of counter value */
 	outb(byte, base_address + (counter_number << regshift));
 
 	return 0;
@@ -187,18 +190,18 @@
 		return -1;
 
 	byte = counter_number << 6;
-	byte |= 0x30;		/*  load low then high byte */
-	byte |= (mode << 1);	/*  set counter mode */
+	byte |= 0x30;		/* load low then high byte */
+	byte |= (mode << 1);	/* set counter mode */
 	writeb(byte, base_address + (i8254_control_reg << regshift));
-	byte = count & 0xff;	/*  lsb of counter value */
+	byte = count & 0xff;	/* lsb of counter value */
 	writeb(byte, base_address + (counter_number << regshift));
-	byte = (count >> 8) & 0xff;	/*  msb of counter value */
+	byte = (count >> 8) & 0xff;	/* msb of counter value */
 	writeb(byte, base_address + (counter_number << regshift));
 
 	return 0;
 }
 
-/* Returns 16 bit counter value, should work for 8253 also.*/
+/* Returns 16 bit counter value, should work for 8253 also. */
 static inline int i8254_read(unsigned long base_address, unsigned int regshift,
 			     unsigned int counter_number)
 {
@@ -208,13 +211,13 @@
 	if (counter_number > 2)
 		return -1;
 
-	/*  latch counter */
+	/* latch counter */
 	byte = counter_number << 6;
 	outb(byte, base_address + (i8254_control_reg << regshift));
 
-	/*  read lsb */
+	/* read lsb */
 	ret = inb(base_address + (counter_number << regshift));
-	/*  read msb */
+	/* read msb */
 	ret += inb(base_address + (counter_number << regshift)) << 8;
 
 	return ret;
@@ -230,13 +233,13 @@
 	if (counter_number > 2)
 		return -1;
 
-	/*  latch counter */
+	/* latch counter */
 	byte = counter_number << 6;
 	writeb(byte, base_address + (i8254_control_reg << regshift));
 
-	/*  read lsb */
+	/* read lsb */
 	ret = readb(base_address + (counter_number << regshift));
-	/*  read msb */
+	/* read msb */
 	ret += readb(base_address + (counter_number << regshift)) << 8;
 
 	return ret;
@@ -252,9 +255,9 @@
 	if (counter_number > 2)
 		return;
 
-	byte = count & 0xff;	/*  lsb of counter value */
+	byte = count & 0xff;	/* lsb of counter value */
 	outb(byte, base_address + (counter_number << regshift));
-	byte = (count >> 8) & 0xff;	/*  msb of counter value */
+	byte = (count >> 8) & 0xff;	/* msb of counter value */
 	outb(byte, base_address + (counter_number << regshift));
 }
 
@@ -268,13 +271,14 @@
 	if (counter_number > 2)
 		return;
 
-	byte = count & 0xff;	/*  lsb of counter value */
+	byte = count & 0xff;	/* lsb of counter value */
 	writeb(byte, base_address + (counter_number << regshift));
-	byte = (count >> 8) & 0xff;	/*  msb of counter value */
+	byte = (count >> 8) & 0xff;	/* msb of counter value */
 	writeb(byte, base_address + (counter_number << regshift));
 }
 
-/* Set counter mode, should work for 8253 also.
+/*
+ * Set counter mode, should work for 8253 also.
  * Note: the 'mode' value is different to that for i8254_load() and comes
  * from the INSN_CONFIG_8254_SET_MODE command:
  *   I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
@@ -293,8 +297,8 @@
 		return -1;
 
 	byte = counter_number << 6;
-	byte |= 0x30;		/*  load low then high byte */
-	byte |= mode;		/*  set counter mode and BCD|binary */
+	byte |= 0x30;		/* load low then high byte */
+	byte |= mode;		/* set counter mode and BCD|binary */
 	outb(byte, base_address + (i8254_control_reg << regshift));
 
 	return 0;
@@ -313,8 +317,8 @@
 		return -1;
 
 	byte = counter_number << 6;
-	byte |= 0x30;		/*  load low then high byte */
-	byte |= mode;		/*  set counter mode and BCD|binary */
+	byte |= 0x30;		/* load low then high byte */
+	byte |= mode;		/* set counter mode and BCD|binary */
 	writeb(byte, base_address + (i8254_control_reg << regshift));
 
 	return 0;
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 34d4d8b..c2f15de 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -1,76 +1,51 @@
 /*
-    comedi/drivers/8255.c
-    Driver for 8255
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1998 David A. Schleef <ds@schleef.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.
-*/
-/*
-Driver: 8255
-Description: generic 8255 support
-Devices: [standard] 8255 (8255)
-Author: ds
-Status: works
-Updated: Fri,  7 Jun 2002 12:56:45 -0700
-
-The classic in digital I/O.  The 8255 appears in Comedi as a single
-digital I/O subdevice with 24 channels.  The channel 0 corresponds
-to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
-7.  Direction configuration is done in blocks, with channels 0-7,
-8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
-supported is mode 0.
-
-You should enable compilation this driver if you plan to use a board
-that has an 8255 chip.  For multifunction boards, the main driver will
-configure the 8255 subdevice automatically.
-
-This driver also works independently with ISA and PCI cards that
-directly map the 8255 registers to I/O ports, including cards with
-multiple 8255 chips.  To configure the driver for such a card, the
-option list should be a list of the I/O port bases for each of the
-8255 chips.  For example,
-
-  comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
-
-Note that most PCI 8255 boards do NOT work with this driver, and
-need a separate driver as a wrapper.  For those that do work, the
-I/O port base address can be found in the output of 'lspci -v'.
-
-*/
+ * comedi/drivers/8255.c
+ * Driver for 8255
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.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.
+ */
 
 /*
-   This file contains an exported subdevice for driving an 8255.
-
-   To use this subdevice as part of another driver, you need to
-   set up the subdevice in the attach function of the driver by
-   calling:
-
-     subdev_8255_init(device, subdevice, io_function, iobase)
-
-   device and subdevice are pointers to the device and subdevice
-   structures.  io_function will be called to provide the
-   low-level input/output to the device, i.e., actual register
-   access.  io_function will be called with the value of iobase
-   as the last parameter.  If the 8255 device is mapped as 4
-   consecutive I/O ports, you can use NULL for io_function
-   and the I/O port base for iobase, and an internal function will
-   handle the register access.
-
-   In addition, if the main driver handles interrupts, you can
-   enable commands on the subdevice by calling subdev_8255_init_irq()
-   instead.  Then, when you get an interrupt that is likely to be
-   from the 8255, you should call subdev_8255_interrupt(), which
-   will copy the latched value to a Comedi buffer.
+ * Driver: 8255
+ * Description: generic 8255 support
+ * Devices: [standard] 8255 (8255)
+ * Author: ds
+ * Status: works
+ * Updated: Fri,  7 Jun 2002 12:56:45 -0700
+ *
+ * The classic in digital I/O.  The 8255 appears in Comedi as a single
+ * digital I/O subdevice with 24 channels.  The channel 0 corresponds
+ * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
+ * 7.  Direction configuration is done in blocks, with channels 0-7,
+ * 8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
+ * supported is mode 0.
+ *
+ * You should enable compilation this driver if you plan to use a board
+ * that has an 8255 chip.  For multifunction boards, the main driver will
+ * configure the 8255 subdevice automatically.
+ *
+ * This driver also works independently with ISA and PCI cards that
+ * directly map the 8255 registers to I/O ports, including cards with
+ * multiple 8255 chips.  To configure the driver for such a card, the
+ * option list should be a list of the I/O port bases for each of the
+ * 8255 chips.  For example,
+ *
+ *   comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
+ *
+ * Note that most PCI 8255 boards do NOT work with this driver, and
+ * need a separate driver as a wrapper.  For those that do work, the
+ * I/O port base address can be found in the output of 'lspci -v'.
  */
 
 #include <linux/module.h>
@@ -218,6 +193,33 @@
 	return 0;
 }
 
+/**
+ * subdev_8255_init - initialize DIO subdevice for driving I/O mapped 8255
+ * @dev: comedi device owning subdevice
+ * @s: comedi subdevice to initialize
+ * @io: (optional) register I/O call-back function
+ * @regbase: offset of 8255 registers from dev->iobase, or call-back context
+ *
+ * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
+ *
+ * If the optional I/O call-back function is provided, its prototype is of
+ * the following form:
+ *
+ *   int my_8255_callback(struct comedi_device *dev,
+ *                        struct comedi_subdevice *s, int dir, int port,
+ *                        int data, unsigned long regbase);
+ *
+ * where 'dev', 's', and 'regbase' match the values passed to this function,
+ * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
+ * is the direction (0 for read, 1 for write) and 'data' is the value to be
+ * written.  It should return 0 if writing or the value read if reading.
+ *
+ * If the optional I/O call-back function is not provided, an internal
+ * call-back function is used which uses consecutive I/O port addresses
+ * starting at dev->iobase + regbase.
+ *
+ * Return: -ENOMEM if failed to allocate memory, zero on success.
+ */
 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
 		     int (*io)(struct comedi_device *,
 			       int, int, int, unsigned long),
@@ -227,6 +229,33 @@
 }
 EXPORT_SYMBOL_GPL(subdev_8255_init);
 
+/**
+ * subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255
+ * @dev: comedi device owning subdevice
+ * @s: comedi subdevice to initialize
+ * @io: (optional) register I/O call-back function
+ * @regbase: offset of 8255 registers from dev->mmio, or call-back context
+ *
+ * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
+ *
+ * If the optional I/O call-back function is provided, its prototype is of
+ * the following form:
+ *
+ *   int my_8255_callback(struct comedi_device *dev,
+ *                        struct comedi_subdevice *s, int dir, int port,
+ *                        int data, unsigned long regbase);
+ *
+ * where 'dev', 's', and 'regbase' match the values passed to this function,
+ * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
+ * is the direction (0 for read, 1 for write) and 'data' is the value to be
+ * written.  It should return 0 if writing or the value read if reading.
+ *
+ * If the optional I/O call-back function is not provided, an internal
+ * call-back function is used which uses consecutive MMIO virtual addresses
+ * starting at dev->mmio + regbase.
+ *
+ * Return: -ENOMEM if failed to allocate memory, zero on success.
+ */
 int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
 			int (*io)(struct comedi_device *,
 				  int, int, int, unsigned long),
@@ -235,10 +264,9 @@
 	return __subdev_8255_init(dev, s, io, regbase, true);
 }
 EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
+
 /*
-
-   Start of the 8255 standalone device
-
+ * Start of the 8255 standalone device
  */
 
 static int dev_8255_attach(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index 5985c8e..934b940 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -1,20 +1,20 @@
 /*
-    module/8255.h
-    Header file for 8255
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1998 David A. Schleef <ds@schleef.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.
-*/
+ * module/8255.h
+ * Header file for 8255
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.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.
+ */
 
 #ifndef _8255_H
 #define _8255_H
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 8b95898..9847642 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -22,33 +22,44 @@
  */
 
 /*
-Driver: 8255_pci
-Description: Generic PCI based 8255 Digital I/O boards
-Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels
-	 (ADLink) PCI-7248 [adl_pci-7248] - 48 channels
-	 (ADLink) PCI-7296 [adl_pci-7296] - 96 channels
-	 (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels
-	 (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels
-	 (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels
-	 (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels
-	 (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels
-	 (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels
-	 (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels
-	 (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels
-	 (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels
-	 (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels
-	 (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels
-Author: H Hartley Sweeten <hsweeten@visionengravers.com>
-Updated: Wed, 12 Sep 2012 11:52:01 -0700
-Status: untested
-
-Some of these boards also have an 8254 programmable timer/counter
-chip. This chip is not currently supported by this driver.
-
-Interrupt support for these boards is also not currently supported.
-
-Configuration Options: not applicable, uses PCI auto config
-*/
+ * Driver: 8255_pci
+ * Description: Generic PCI based 8255 Digital I/O boards
+ * Devices: [ADLink] PCI-7224 (adl_pci-7224), PCI-7248 (adl_pci-7248),
+ *   PCI-7296 (adl_pci-7296),
+ *   [Measurement Computing] PCI-DIO24 (cb_pci-dio24),
+ *   PCI-DIO24H (cb_pci-dio24h), PCI-DIO48H (cb_pci-dio48h),
+ *   PCI-DIO96H (cb_pci-dio96h),
+ *   [National Instruments] PCI-DIO-96 (ni_pci-dio-96),
+ *   PCI-DIO-96B (ni_pci-dio-96b), PXI-6508 (ni_pxi-6508),
+ *   PCI-6503 (ni_pci-6503), PCI-6503B (ni_pci-6503b),
+ *   PCI-6503X (ni_pci-6503x), PXI-6503 (ni_pxi-6503)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Wed, 12 Sep 2012 11:52:01 -0700
+ * Status: untested
+ *
+ * These boards have one or more 8255 digital I/O chips, each of which
+ * is supported as a separate 24-channel DIO subdevice.
+ *
+ * Boards with 24 DIO channels (1 DIO subdevice):
+ *
+ *   PCI-7224, PCI-DIO24, PCI-DIO24H, PCI-6503, PCI-6503B, PCI-6503X,
+ *   PXI-6503
+ *
+ * Boards with 48 DIO channels (2 DIO subdevices):
+ *
+ *   PCI-7248, PCI-DIO48H
+ *
+ * Boards with 96 DIO channels (4 DIO subdevices):
+ *
+ *   PCI-7296, PCI-DIO96H, PCI-DIO-96, PCI-DIO-96B, PXI-6508
+ *
+ * Some of these boards also have an 8254 programmable timer/counter
+ * chip.  This chip is not currently supported by this driver.
+ *
+ * Interrupt support for these boards is also not currently supported.
+ *
+ * Configuration Options: not applicable, uses PCI auto config.
+ */
 
 #include <linux/module.h>
 #include <linux/pci.h>
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 84fdf20..7d1fbd5 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -3,6 +3,7 @@
 ccflags-$(CONFIG_COMEDI_DEBUG)		:= -DDEBUG
 
 # Comedi "helper" modules
+obj-$(CONFIG_COMEDI_ISADMA)		+= comedi_isadma.o
 
 # Comedi misc drivers
 obj-$(CONFIG_COMEDI_BOND)		+= comedi_bond.o
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
deleted file mode 100644
index bfa9228..0000000
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ /dev/null
@@ -1,2365 +0,0 @@
-/*
- * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
- *
- *	ADDI-DATA GmbH
- *	Dieselstrasse 3
- *	D-77833 Ottersweier
- *	Tel: +19(0)7223/9493-0
- *	Fax: +49(0)7223/9493-92
- *	http://www.addi-data.com
- *	info@addi-data.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.
- *
- */
-
-/* Card Specific information */
-#define APCI1500_ADDRESS_RANGE		4
-
-/* DIGITAL INPUT-OUTPUT DEFINE */
-
-#define APCI1500_DIGITAL_OP		2
-#define APCI1500_DIGITAL_IP		0
-#define APCI1500_AND			2
-#define APCI1500_OR			4
-#define APCI1500_OR_PRIORITY		6
-#define APCI1500_CLK_SELECT		0
-#define COUNTER1			0
-#define COUNTER2			1
-#define COUNTER3			2
-#define APCI1500_COUNTER		0x20
-#define APCI1500_TIMER			0
-#define APCI1500_WATCHDOG		0
-#define APCI1500_SINGLE			0
-#define APCI1500_CONTINUOUS		0x80
-#define APCI1500_DISABLE		0
-#define APCI1500_ENABLE			1
-#define APCI1500_SOFTWARE_TRIGGER	0x4
-#define APCI1500_HARDWARE_TRIGGER	0x10
-#define APCI1500_SOFTWARE_GATE		0
-#define APCI1500_HARDWARE_GATE		0x8
-#define START				0
-#define STOP				1
-#define TRIGGER				2
-
-/*
- * Zillog I/O enumeration
- */
-enum {
-	APCI1500_Z8536_PORT_C,
-	APCI1500_Z8536_PORT_B,
-	APCI1500_Z8536_PORT_A,
-	APCI1500_Z8536_CONTROL_REGISTER
-};
-
-/*
- * Z8536 CIO Internal Address
- */
-enum {
-	APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-	APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-	APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
-	APCI1500_RW_PORT_B_INTERRUPT_CONTROL,
-	APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR,
-	APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_C_DATA_DIRECTION,
-	APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
-
-	APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-	APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-	APCI1500_RW_CPT_TMR1_CMD_STATUS,
-	APCI1500_RW_CPT_TMR2_CMD_STATUS,
-	APCI1500_RW_CPT_TMR3_CMD_STATUS,
-	APCI1500_RW_PORT_A_DATA,
-	APCI1500_RW_PORT_B_DATA,
-	APCI1500_RW_PORT_C_DATA,
-
-	APCI1500_R_CPT_TMR1_VALUE_HIGH,
-	APCI1500_R_CPT_TMR1_VALUE_LOW,
-	APCI1500_R_CPT_TMR2_VALUE_HIGH,
-	APCI1500_R_CPT_TMR2_VALUE_LOW,
-	APCI1500_R_CPT_TMR3_VALUE_HIGH,
-	APCI1500_R_CPT_TMR3_VALUE_LOW,
-	APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
-	APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
-	APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
-	APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
-	APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
-	APCI1500_R_CURRENT_VECTOR,
-
-	APCI1500_RW_PORT_A_SPECIFICATION,
-	APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
-	APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_A_DATA_DIRECTION,
-	APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL,
-	APCI1500_RW_PORT_A_PATTERN_POLARITY,
-	APCI1500_RW_PORT_A_PATTERN_TRANSITION,
-	APCI1500_RW_PORT_A_PATTERN_MASK,
-
-	APCI1500_RW_PORT_B_SPECIFICATION,
-	APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
-	APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
-	APCI1500_RW_PORT_B_DATA_DIRECTION,
-	APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL,
-	APCI1500_RW_PORT_B_PATTERN_POLARITY,
-	APCI1500_RW_PORT_B_PATTERN_TRANSITION,
-	APCI1500_RW_PORT_B_PATTERN_MASK
-};
-
-static int i_TimerCounter1Init;
-static int i_TimerCounter2Init;
-static int i_WatchdogCounter3Init;
-static int i_Event1Status, i_Event2Status;
-static int i_TimerCounterWatchdogInterrupt;
-static int i_Logic, i_CounterLogic;
-static int i_InterruptMask;
-static int i_InputChannel;
-static int i_TimerCounter1Enabled, i_TimerCounter2Enabled,
-	   i_WatchdogCounter3Enabled;
-
-/*
- * An event can be generated for each port. The first event is related to the
- * first 8 channels (port 1) and the second to the following 6 channels (port 2)
- * An interrupt is generated when one or both events have occurred.
- *
- * data[0] Number of the input port on which the event will take place (1 or 2)
- * data[1] The event logic for port 1 has three possibilities:
- *	APCI1500_AND		This logic links the inputs with an AND logic.
- *	APCI1500_OR		This logic links the inputs with a OR logic.
- *	APCI1500_OR_PRIORITY	This logic links the inputs with a priority OR
- *				logic. Input 1 has the highest priority level
- *				and input 8 the	smallest.
- *	For the second port the user has 1 possibility:
- *	APCI1500_OR	This logic links the inputs with a polarity OR logic
- * data[2] These 8-character word for port1 and 6-character word for port 2
- *	   give the mask of the event. Each place gives the state of the input
- *	   channels and can have one of these six characters
- *	0 This input must be on 0
- *	1 This input must be on 1
- *	2 This input reacts to a falling edge
- *	3 This input reacts to a rising edge
- *	4 This input reacts to both edges
- *	5 This input is not used for event
- */
-static int apci1500_di_config(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn,
-			      unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
-	int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0;
-	int i_PatternTransitionCount = 0, i_RegValue;
-	int i;
-
-	/* Selects the master interrupt control register */
-	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Disables  the main interrupt on the board */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	if (data[0] == 1) {
-		i_MaxChannel = 8;
-	} else {
-		if (data[0] == 2) {
-			i_MaxChannel = 6;
-		} else {
-			dev_warn(dev->class_dev,
-				"The specified port event does not exist\n");
-			return -EINVAL;
-		}
-	}
-	switch (data[1]) {
-	case 0:
-		data[1] = APCI1500_AND;
-		break;
-	case 1:
-		data[1] = APCI1500_OR;
-		break;
-	case 2:
-		data[1] = APCI1500_OR_PRIORITY;
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The specified interrupt logic does not exist\n");
-		return -EINVAL;
-	}
-
-	i_Logic = data[1];
-	for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) {
-		i_EventMask = data[2 + i];
-		switch (i_EventMask) {
-		case 0:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			break;
-		case 1:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternPolarity =
-				i_PatternPolarity | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 2:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 3:
-			i_PatternMask =
-				i_PatternMask | (1 << (i_MaxChannel - i_Count));
-			i_PatternPolarity =
-				i_PatternPolarity | (1 << (i_MaxChannel -
-					i_Count));
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 4:
-			i_PatternTransition =
-				i_PatternTransition | (1 << (i_MaxChannel -
-					i_Count));
-			break;
-		case 5:
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The option indicated in the event mask does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	if (data[0] == 1) {
-		/* Test the interrupt logic */
-
-		if (data[1] == APCI1500_AND ||
-			data[1] == APCI1500_OR ||
-			data[1] == APCI1500_OR_PRIORITY) {
-			/* Tests if a transition was declared */
-			/* for a OR PRIORITY logic            */
-
-			if (data[1] == APCI1500_OR_PRIORITY
-				&& i_PatternTransition != 0) {
-				dev_warn(dev->class_dev,
-					"Transition error on an OR PRIORITY logic\n");
-				return -EINVAL;
-			}
-
-			/* Tests if more than one transition */
-			/* was declared for an AND logic     */
-
-			if (data[1] == APCI1500_AND) {
-				for (i_Count = 0; i_Count < 8; i_Count++) {
-					i_PatternTransitionCount =
-						i_PatternTransitionCount +
-						((i_PatternTransition >>
-							i_Count) & 0x1);
-
-				}
-
-				if (i_PatternTransitionCount > 1) {
-					dev_warn(dev->class_dev,
-						"Transition error on an AND logic\n");
-					return -EINVAL;
-				}
-			}
-
-			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Disable Port A */
-			outb(0xF0,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the polarity register of port 1    */
-			outb(APCI1500_RW_PORT_A_PATTERN_POLARITY,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternPolarity,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the pattern mask register of      */
-			/* port 1                                    */
-			outb(APCI1500_RW_PORT_A_PATTERN_MASK,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternMask,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the pattern transition register  */
-			/* of port 1                                */
-			outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternTransition,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the mode specification mask    */
-			/* register of port 1                     */
-			outb(APCI1500_RW_PORT_A_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_RegValue =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the mode specification mask    */
-			/* register of port 1                     */
-			outb(APCI1500_RW_PORT_A_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Port A new mode    */
-
-			i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			i_Event1Status = 1;
-
-			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-
-			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Enable Port A */
-			outb(0xF4,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-		} else {
-			dev_warn(dev->class_dev,
-				"The choice for interrupt logic does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Test if event setting for port 2 */
-
-	if (data[0] == 2) {
-		/* Test the event logic */
-
-		if (data[1] == APCI1500_OR) {
-			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Disable Port B */
-			outb(0x74,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the mode specification mask  */
-			/* register of port B                   */
-			outb(APCI1500_RW_PORT_B_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_RegValue =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the mode specification mask    */
-			/* register of port B                     */
-			outb(APCI1500_RW_PORT_B_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_RegValue = i_RegValue & 0xF9;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects error channels 1 and 2 */
-
-			i_PatternMask = (i_PatternMask | 0xC0);
-			i_PatternPolarity = (i_PatternPolarity | 0xC0);
-			i_PatternTransition = (i_PatternTransition | 0xC0);
-
-			/* Selects the polarity register of port 2    */
-			outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternPolarity,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the pattern transition register    */
-			/* of port 2                                  */
-			outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternTransition,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the pattern Mask register    */
-			/* of port 2                                  */
-
-			outb(APCI1500_RW_PORT_B_PATTERN_MASK,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_PatternMask,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the mode specification mask    */
-			/* register of port 2                     */
-			outb(APCI1500_RW_PORT_B_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_RegValue =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Selects the mode specification mask    */
-			/* register of port 2                     */
-			outb(APCI1500_RW_PORT_B_SPECIFICATION,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_RegValue = (i_RegValue & 0xF9) | 4;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			i_Event2Status = 1;
-			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-
-			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Enable Port B */
-
-			outb(0xF4,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-		} else {
-			dev_warn(dev->class_dev,
-				"The choice for interrupt logic does not exist\n");
-			return -EINVAL;
-		}
-	}
-
-	return insn->n;
-}
-
-/*
- * Allows or disallows a port event
- *
- * data[0] 0 = Start input event, 1 = Stop input event
- * data[1] Number of port (1 or 2)
- */
-static int apci1500_di_write(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn,
-			     unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
-		0, i_RegValue;
-
-	switch (data[0]) {
-	case START:
-		/* Tests the port number */
-
-		if (data[1] == 1 || data[1] == 2) {
-			/* Test if port 1 selected */
-
-			if (data[1] == 1) {
-				/* Test if event initialised */
-				if (i_Event1Status == 1) {
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Disable Port A */
-					outb(0xF0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the command and status register of      */
-					/* port 1                                          */
-					outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Allows the pattern interrupt      */
-					outb(0xC0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Enable Port A */
-					outb(0xF4,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					i_Event1InterruptStatus = 1;
-					outb(APCI1500_RW_PORT_A_SPECIFICATION,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					i_RegValue =
-						inb(devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-
-					/* Selects the master interrupt control register */
-					outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Authorizes the main interrupt on the board */
-					outb(0xD0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 1 not initialised\n");
-					return -EINVAL;
-				}
-			}
-			if (data[1] == 2) {
-
-				if (i_Event2Status == 1) {
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Disable Port B */
-					outb(0x74,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the command and status register of      */
-					/* port 2                                          */
-					outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Allows the pattern interrupt      */
-					outb(0xC0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Enable Port B */
-					outb(0xF4,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-
-					/* Selects the master interrupt control register */
-					outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Authorizes the main interrupt on the board */
-					outb(0xD0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					i_Event2InterruptStatus = 1;
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 2 not initialised\n");
-					return -EINVAL;
-				}
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"The port parameter is in error\n");
-			return -EINVAL;
-		}
-
-		break;
-
-	case STOP:
-		/* Tests the port number */
-
-		if (data[1] == 1 || data[1] == 2) {
-			/* Test if port 1 selected */
-
-			if (data[1] == 1) {
-				/* Test if event initialised */
-				if (i_Event1Status == 1) {
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Disable Port A */
-					outb(0xF0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the command and status register of      */
-					/* port 1                                          */
-					outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Inhibits the pattern interrupt      */
-					outb(0xE0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Enable Port A */
-					outb(0xF4,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					i_Event1InterruptStatus = 0;
-				} else {
-					dev_warn(dev->class_dev,
-						"Event 1 not initialised\n");
-					return -EINVAL;
-				}
-			}
-			if (data[1] == 2) {
-				/* Test if event initialised */
-				if (i_Event2Status == 1) {
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Disable Port B */
-					outb(0x74,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the command and status register of      */
-					/* port 2                                         */
-					outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Inhibits the pattern interrupt      */
-					outb(0xE0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-					/* Enable Port B */
-					outb(0xF4,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					i_Event2InterruptStatus = 0;
-				} else {
-
-					dev_warn(dev->class_dev,
-						"Event 2 not initialised\n");
-					return -EINVAL;
-				}
-			}
-
-		} else {
-			dev_warn(dev->class_dev,
-				"The port parameter is in error\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The option of START/STOP logic does not exist\n");
-		return -EINVAL;
-	}
-
-	return insn->n;
-}
-
-/*
- * Return the status of the digital input
- */
-static int apci1500_di_read(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn,
-			    unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_DummyRead = 0;
-
-	/* Software reset */
-	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the master configuration control register */
-	outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the mode specification register of port A */
-	outb(APCI1500_RW_PORT_A_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data path polarity register of port A */
-	outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* High level of port A means 1 */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data direction register of port A */
-	outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/*  Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of port A:  */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the handshake specification register of port A */
-	outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the register */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the mode specification register of port B */
-	outb(APCI1500_RW_PORT_B_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data path polarity register of port B */
-	outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* A high level of port B means 1 */
-	outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data direction register of port B */
-	outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of port B:         */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the handshake specification register of port B */
-	outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the register */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data path polarity register of port C */
-	outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* High level of port C means 1 */
-	outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data direction register of port C */
-	outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs except channel 1 */
-	outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the special IO register of port C */
-	outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes it */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of timer 1         */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates Timer 2 interrupt management:               */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 3 */
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of Timer 3 */
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates interrupt management of timer 3:            */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the master interrupt control register */
-	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes all interrupts */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	return insn->n;
-}
-
-static int apci1500_di_insn_bits(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn,
-				 unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-
-	data[1] = inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP);
-
-	return insn->n;
-}
-
-/*
- * Configures the digital output memory and the digital output error interrupt
- *
- * data[1] 1 = Enable the voltage error interrupt
- *	   2 = Disable the voltage error interrupt
- */
-static int apci1500_do_config(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn,
-			      unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-
-	devpriv->b_OutputMemoryStatus = data[0];
-	return insn->n;
-}
-
-/*
- * Writes port value to the selected port
- */
-static int apci1500_do_write(struct comedi_device *dev,
-			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn,
-			     unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	static unsigned int ui_Temp;
-	unsigned int ui_Temp1;
-	unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec);	/*  get the channel */
-
-	if (!devpriv->b_OutputMemoryStatus)
-		ui_Temp = 0;
-
-	if (data[3] == 0) {
-		if (data[1] == 0) {
-			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
-			outw(data[0],
-				devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
-		} else {
-			if (data[1] == 1) {
-				switch (ui_NoOfChannel) {
-
-				case 2:
-					data[0] =
-						(data[0] << (2 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 4:
-					data[0] =
-						(data[0] << (4 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 8:
-					data[0] =
-						(data[0] << (8 *
-							data[2])) | ui_Temp;
-					break;
-
-				case 15:
-					data[0] = data[0] | ui_Temp;
-					break;
-
-				default:
-					dev_err(dev->class_dev,
-						"chan spec wrong\n");
-					return -EINVAL;	/*  "sorry channel spec wrong " */
-
-				}
-
-				outw(data[0],
-					devpriv->i_IobaseAddon +
-					APCI1500_DIGITAL_OP);
-			} else {
-				dev_warn(dev->class_dev,
-					"Specified channel not supported\n");
-				return -EINVAL;
-			}
-		}
-	} else {
-		if (data[3] == 1) {
-			if (data[1] == 0) {
-				data[0] = ~data[0] & 0x1;
-				ui_Temp1 = 1;
-				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
-				ui_Temp = ui_Temp | ui_Temp1;
-				data[0] =
-					(data[0] << ui_NoOfChannel) ^
-					0xffffffff;
-				data[0] = data[0] & ui_Temp;
-				outw(data[0],
-					devpriv->i_IobaseAddon +
-					APCI1500_DIGITAL_OP);
-			} else {
-				if (data[1] == 1) {
-					switch (ui_NoOfChannel) {
-
-					case 2:
-						data[0] = ~data[0] & 0x3;
-						ui_Temp1 = 3;
-						ui_Temp1 =
-							ui_Temp1 << 2 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (2 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 4:
-						data[0] = ~data[0] & 0xf;
-						ui_Temp1 = 15;
-						ui_Temp1 =
-							ui_Temp1 << 4 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (4 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 8:
-						data[0] = ~data[0] & 0xff;
-						ui_Temp1 = 255;
-						ui_Temp1 =
-							ui_Temp1 << 8 * data[2];
-						ui_Temp = ui_Temp | ui_Temp1;
-						data[0] =
-							((data[0] << (8 *
-									data
-									[2])) ^
-							0xffffffff) & ui_Temp;
-						break;
-
-					case 15:
-						break;
-
-					default:
-						dev_err(dev->class_dev,
-							"chan spec wrong\n");
-						return -EINVAL;	/*  "sorry channel spec wrong " */
-
-					}
-
-					outw(data[0],
-						devpriv->i_IobaseAddon +
-						APCI1500_DIGITAL_OP);
-				} else {
-					dev_warn(dev->class_dev,
-						"Specified channel not supported\n");
-					return -EINVAL;
-				}
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Specified functionality does not exist\n");
-			return -EINVAL;
-		}
-	}
-	ui_Temp = data[0];
-	return insn->n;
-}
-
-/*
- * Configures The Watchdog
- *
- * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ
- * data[1] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- * data[3] This parameter has two meanings. If the counter/timer is used as
- *	a counter the limit value of the counter is given. If the counter/timer
- *	is used as a timer, the divider factor for the output is given.
- * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE
- * data[5] 0 = Software Trigger, 1 = Hardware Trigger
- * data[6] 0 = Software gate, 1 = Hardware gate
- * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable
- */
-static int apci1500_timer_config(struct comedi_device *dev,
-				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn,
-				 unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_TimerCounterMode, i_MasterConfiguration;
-
-	devpriv->tsk_Current = current;
-
-	/* Selection of the input clock */
-	if (data[0] == 0 || data[0] == 1 || data[0] == 2) {
-		outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT);
-	} else {
-		if (data[0] != 3) {
-			dev_warn(dev->class_dev,
-				"The option for input clock selection does not exist\n");
-			return -EINVAL;
-		}
-	}
-	/* Select the counter/timer */
-	switch (data[1]) {
-	case COUNTER1:
-		/* selecting counter or timer */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_TIMER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a timer nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		i_TimerCounterMode = data[2] | data[4] | 7;
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE
-				|| data[7] == APCI1500_DISABLE) {
-
-				/* Selects the mode register of timer/counter 1 */
-				outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Writes the new mode */
-				outb(i_TimerCounterMode,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of timer/counter 1 */
-
-				outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the low value  */
-
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of timer/counter 1 */
-
-				outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the high value  */
-
-				data[3] = data[3] >> 8;
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the master configuration register */
-
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Reads the register */
-
-				i_MasterConfiguration =
-					inb(devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Enables timer/counter 1 and triggers timer/counter 1 */
-
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x40;
-
-				/* Selects the master configuration register */
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the new configuration */
-				outb(i_MasterConfiguration,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Selects the commands register of     */
-				/* timer/counter 1                      */
-
-				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Disable timer/counter 1 */
-
-				outb(0x0,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Selects the commands register of     */
-				/* timer/counter 1                      */
-				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Trigger timer/counter 1 */
-				outb(0x2,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_TimerCounter1Init = 1;
-		break;
-
-	case COUNTER2:		/* selecting counter or timer */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_TIMER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a timer nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware trigger */
-		switch (data[5]) {
-		case 0:
-			data[5] = APCI1500_SOFTWARE_TRIGGER;
-			break;
-		case 1:
-			data[5] = APCI1500_HARDWARE_TRIGGER;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware trigger does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware gate */
-		switch (data[6]) {
-		case 0:
-			data[6] = APCI1500_SOFTWARE_GATE;
-			break;
-		case 1:
-			data[6] = APCI1500_HARDWARE_GATE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware gate does not exist\n");
-			return -EINVAL;
-		}
-
-		i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
-
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE
-				|| data[7] == APCI1500_DISABLE) {
-
-				/* Selects the mode register of timer/counter 2 */
-				outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Writes the new mode */
-				outb(i_TimerCounterMode,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of timer/counter 2 */
-
-				outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the low value  */
-
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of timer/counter 2 */
-
-				outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the high value  */
-
-				data[3] = data[3] >> 8;
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the master configuration register */
-
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Reads the register */
-
-				i_MasterConfiguration =
-					inb(devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Enables timer/counter 2 and triggers timer/counter 2 */
-
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x20;
-
-				/* Selects the master configuration register */
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the new configuration */
-				outb(i_MasterConfiguration,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Selects the commands register of     */
-				/* timer/counter 2                      */
-
-				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Disable timer/counter 2 */
-
-				outb(0x0,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Selects the commands register of     */
-				/* timer/counter 2                      */
-				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Trigger timer/counter 1 */
-				outb(0x2,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_TimerCounter2Init = 1;
-		break;
-
-	case COUNTER3:		/* selecting counter or watchdog */
-		switch (data[2]) {
-		case 0:
-			data[2] = APCI1500_COUNTER;
-			break;
-		case 1:
-			data[2] = APCI1500_WATCHDOG;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice is not a watchdog nor a counter\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  single or continuous mode */
-		switch (data[4]) {
-		case 0:
-			data[4] = APCI1500_CONTINUOUS;
-			break;
-		case 1:
-			data[4] = APCI1500_SINGLE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This option for single/continuous mode does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Selecting  software or hardware gate */
-		switch (data[6]) {
-		case 0:
-			data[6] = APCI1500_SOFTWARE_GATE;
-			break;
-		case 1:
-			data[6] = APCI1500_HARDWARE_GATE;
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"This choice for software or hardware gate does not exist\n");
-			return -EINVAL;
-		}
-
-		/* Test if used for watchdog */
-
-		if (data[2] == APCI1500_WATCHDOG) {
-			/* - Enables the output line */
-			/* - Enables retrigger       */
-			/* - Pulses output           */
-			i_TimerCounterMode = data[2] | data[4] | 0x54;
-		} else {
-			i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
-		}
-		/* Test the reload value */
-
-		if ((data[3] >= 0) && (data[3] <= 65535)) {
-			if (data[7] == APCI1500_ENABLE
-				|| data[7] == APCI1500_DISABLE) {
-
-				/* Selects the mode register of watchdog/counter 3 */
-				outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				/* Writes the new mode */
-				outb(i_TimerCounterMode,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of watchdog/counter 3 */
-
-				outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the low value  */
-
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the constant register of watchdog/counter 3 */
-
-				outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the high value  */
-
-				data[3] = data[3] >> 8;
-				outb(data[3],
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the master configuration register */
-
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Reads the register */
-
-				i_MasterConfiguration =
-					inb(devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
-
-				i_MasterConfiguration =
-					i_MasterConfiguration | 0x10;
-
-				/* Selects the master configuration register */
-				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Writes the new configuration */
-				outb(i_MasterConfiguration,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Test if COUNTER */
-				if (data[2] == APCI1500_COUNTER) {
-
-					/* Selects the command register of   */
-					/* watchdog/counter 3                */
-					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Disable the  watchdog/counter 3 and starts it */
-					outb(0x0,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-
-					/* Selects the command register of   */
-					/* watchdog/counter 3                */
-
-					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					/* Trigger the  watchdog/counter 3 and starts it */
-					outb(0x2,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-
-				}
-
-			} else {
-
-				dev_warn(dev->class_dev,
-					"Error in selection of interrupt enable or disable\n");
-				return -EINVAL;
-			}
-		} else {
-			dev_warn(dev->class_dev,
-				"Error in selection of reload value\n");
-			return -EINVAL;
-		}
-		i_TimerCounterWatchdogInterrupt = data[7];
-		i_WatchdogCounter3Init = 1;
-		break;
-
-	default:
-		dev_warn(dev->class_dev,
-			"The specified counter/timer option does not exist\n");
-		return -EINVAL;
-	}
-	i_CounterLogic = data[2];
-	return insn->n;
-}
-
-/*
- * Start / Stop or trigger the timer counter or Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- * data[1] 0 = Start, 1 = Stop, 2 = Trigger
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- */
-static int apci1500_timer_write(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn,
-				unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_CommandAndStatusValue;
-
-	switch (data[0]) {
-	case COUNTER1:
-		switch (data[1]) {
-		case START:
-			if (i_TimerCounter1Init == 1) {
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts timer/counter 1 */
-				i_TimerCounter1Enabled = 1;
-				/* Selects the commands and status register */
-				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				outb(i_CommandAndStatusValue,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer1 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-
-			/* Stop timer/counter 1 */
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(0x00,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_TimerCounter1Enabled = 0;
-			break;
-
-		case TRIGGER:
-			if (i_TimerCounter1Init == 1) {
-				if (i_TimerCounter1Enabled == 1) {
-					/* Set Trigger and gate */
-
-					i_CommandAndStatusValue = 0x6;
-				} else {
-					/* Set Trigger */
-
-					i_CommandAndStatusValue = 0x2;
-				}
-
-				/* Selects the commands and status register */
-				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				outb(i_CommandAndStatusValue,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer1 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-
-	case COUNTER2:
-		switch (data[1]) {
-		case START:
-			if (i_TimerCounter2Init == 1) {
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts timer/counter 2 */
-				i_TimerCounter2Enabled = 1;
-				/* Selects the commands and status register */
-				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				outb(i_CommandAndStatusValue,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer2 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-
-			/* Stop timer/counter 2 */
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(0x00,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_TimerCounter2Enabled = 0;
-			break;
-		case TRIGGER:
-			if (i_TimerCounter2Init == 1) {
-				if (i_TimerCounter2Enabled == 1) {
-					/* Set Trigger and gate */
-
-					i_CommandAndStatusValue = 0x6;
-				} else {
-					/* Set Trigger */
-
-					i_CommandAndStatusValue = 0x2;
-				}
-
-				/* Selects the commands and status register */
-				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				outb(i_CommandAndStatusValue,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-			} else {
-				dev_warn(dev->class_dev,
-					"Counter/Timer2 not configured\n");
-				return -EINVAL;
-			}
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER3:
-		switch (data[1]) {
-		case START:
-			if (i_WatchdogCounter3Init == 1) {
-
-				if (i_TimerCounterWatchdogInterrupt == 1)
-					i_CommandAndStatusValue = 0xC4;	/* Enable the interrupt */
-				else
-					i_CommandAndStatusValue = 0xE4;	/* disable the interrupt */
-
-				/* Starts Watchdog/counter 3 */
-				i_WatchdogCounter3Enabled = 1;
-				/* Selects the commands and status register */
-				outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				outb(i_CommandAndStatusValue,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-			} else {
-				dev_warn(dev->class_dev,
-					"Watchdog/Counter3 not configured\n");
-				return -EINVAL;
-			}
-			break;
-
-		case STOP:
-
-			/* Stop Watchdog/counter 3 */
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(0x00,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_WatchdogCounter3Enabled = 0;
-			break;
-
-		case TRIGGER:
-			switch (data[2]) {
-			case 0:	/* triggering counter 3 */
-				if (i_WatchdogCounter3Init == 1) {
-					if (i_WatchdogCounter3Enabled == 1) {
-						/* Set Trigger and gate */
-
-						i_CommandAndStatusValue = 0x6;
-					} else {
-						/* Set Trigger */
-
-						i_CommandAndStatusValue = 0x2;
-					}
-
-					/* Selects the commands and status register */
-					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					outb(i_CommandAndStatusValue,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-				} else {
-					dev_warn(dev->class_dev,
-						"Counter3 not configured\n");
-					return -EINVAL;
-				}
-				break;
-			case 1:
-				/* triggering Watchdog 3 */
-				if (i_WatchdogCounter3Init == 1) {
-
-					/* Selects the commands and status register */
-					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-					outb(0x6,
-						devpriv->iobase +
-						APCI1500_Z8536_CONTROL_REGISTER);
-				} else {
-					dev_warn(dev->class_dev,
-						"Watchdog 3 not configured\n");
-					return -EINVAL;
-				}
-				break;
-			default:
-				dev_warn(dev->class_dev,
-					"Wrong choice of watchdog/counter3\n");
-				return -EINVAL;
-			}
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				"The specified option for start/stop/trigger does not exist\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The specified choice for counter/watchdog/timer does not exist\n");
-		return -EINVAL;
-	}
-	return insn->n;
-}
-
-/*
- * Read The Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 =  Counter2/Timer2, 2 = Counter3/Watchdog
- */
-static int apci1500_timer_bits(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn,
-			       unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_CommandAndStatusValue;
-
-	switch (data[0]) {
-	case COUNTER1:
-		/* Read counter/timer1 */
-		if (i_TimerCounter1Init == 1) {
-			if (i_TimerCounter1Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_CommandAndStatusValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the counter register (high) */
-			outb(APCI1500_R_CPT_TMR1_VALUE_HIGH,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			outb(APCI1500_R_CPT_TMR1_VALUE_LOW,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				data[0] | inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-		} else {
-			dev_warn(dev->class_dev,
-				"Timer/Counter1 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER2:
-		/* Read counter/timer2 */
-		if (i_TimerCounter2Init == 1) {
-			if (i_TimerCounter2Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_CommandAndStatusValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the counter register (high) */
-			outb(APCI1500_R_CPT_TMR2_VALUE_HIGH,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			outb(APCI1500_R_CPT_TMR2_VALUE_LOW,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				data[0] | inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-		} else {
-			dev_warn(dev->class_dev,
-				"Timer/Counter2 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	case COUNTER3:
-		/* Read counter/watchdog2 */
-		if (i_WatchdogCounter3Init == 1) {
-			if (i_WatchdogCounter3Enabled == 1) {
-				/* Set RCC and gate */
-
-				i_CommandAndStatusValue = 0xC;
-			} else {
-				/* Set RCC */
-
-				i_CommandAndStatusValue = 0x8;
-			}
-
-			/* Selects the commands and status register */
-			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			outb(i_CommandAndStatusValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-
-			/* Selects the counter register (high) */
-			outb(APCI1500_R_CPT_TMR3_VALUE_HIGH,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] = data[0] << 8;
-			data[0] = data[0] & 0xff00;
-			outb(APCI1500_R_CPT_TMR3_VALUE_LOW,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			data[0] =
-				data[0] | inb(devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-		} else {
-			dev_warn(dev->class_dev,
-				"WatchdogCounter3 not configured\n");
-			return -EINVAL;
-		}
-		break;
-	default:
-		dev_warn(dev->class_dev,
-			"The choice of timer/counter/watchdog does not exist\n");
-		return -EINVAL;
-	}
-
-	return insn->n;
-}
-
-/*
- * Read the interrupt mask
- *
- * data[0] The interrupt mask value
- * data[1] Channel Number
- */
-static int apci1500_timer_read(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn,
-			       unsigned int *data)
-{
-	data[0] = i_InterruptMask;
-	data[1] = i_InputChannel;
-	i_InterruptMask = 0;
-	return insn->n;
-}
-
-/*
- * Configures the interrupt registers
- */
-static int apci1500_do_bits(struct comedi_device *dev,
-			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn,
-			    unsigned int *data)
-{
-	struct apci1500_private *devpriv = dev->private;
-	unsigned int ui_Status;
-	int i_RegValue;
-	int i_Constant;
-
-	devpriv->tsk_Current = current;
-	outl(0x0, devpriv->i_IobaseAmcc + 0x38);
-	if (data[0] == 1) {
-		i_Constant = 0xC0;
-	} else {
-		if (data[0] == 0) {
-			i_Constant = 0x00;
-		} else {
-			dev_warn(dev->class_dev,
-				"The parameter passed to driver is in error for enabling the voltage interrupt\n");
-			return -EINVAL;
-		}
-	}
-
-	/* Selects the mode specification register of port B */
-	outb(APCI1500_RW_PORT_B_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_PORT_B_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Writes the new configuration (APCI1500_OR) */
-	i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
-
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Authorises the interrupt on the board */
-	outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the pattern polarity register of port B */
-	outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the pattern transition register of port B */
-	outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the pattern mask register of port B */
-	outb(APCI1500_RW_PORT_B_PATTERN_MASK,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the interrupt of port A */
-
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port  B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the interrupt of port B */
-
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the interrupt of timer 1 */
-
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the interrupt of timer 2 */
-
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the command and status register of timer 3 */
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the interrupt of timer 3 */
-
-	i_RegValue = (i_RegValue & 0x0F) | 0x20;
-	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the master interrupt control register */
-	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Authorizes the main interrupt on the board */
-	outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Enables the PCI interrupt */
-	outl(0x3000, devpriv->i_IobaseAmcc + 0x38);
-	ui_Status = inl(devpriv->i_IobaseAmcc + 0x10);
-	ui_Status = inl(devpriv->i_IobaseAmcc + 0x38);
-	outl(0x23000, devpriv->i_IobaseAmcc + 0x38);
-
-	return insn->n;
-}
-
-static irqreturn_t apci1500_interrupt(int irq, void *d)
-{
-
-	struct comedi_device *dev = d;
-	struct apci1500_private *devpriv = dev->private;
-	unsigned int ui_InterruptStatus = 0;
-	int i_RegValue = 0;
-
-	/* Clear the interrupt mask */
-	i_InterruptMask = 0;
-
-	/* Read the board interrupt status */
-	ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38);
-
-	/* Test if board generated a interrupt */
-	if ((ui_InterruptStatus & 0x800000) == 0x800000) {
-		/* Disable all Interrupt */
-		/* Selects the master interrupt control register */
-		/* Disables  the main interrupt on the board */
-		/* Selects the command and status register of port A */
-		outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		i_RegValue =
-			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		if ((i_RegValue & 0x60) == 0x60) {
-			/* Selects the command and status register of port A */
-			outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Deletes the interrupt of port A */
-			i_RegValue = (i_RegValue & 0x0F) | 0x20;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_InterruptMask = i_InterruptMask | 1;
-			if (i_Logic == APCI1500_OR_PRIORITY) {
-				outb(APCI1500_RW_PORT_A_SPECIFICATION,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				i_RegValue =
-					inb(devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				/* Selects the interrupt vector register of port A */
-				outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
-					devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-				i_RegValue =
-					inb(devpriv->iobase +
-					APCI1500_Z8536_CONTROL_REGISTER);
-
-				i_InputChannel = 1 + (i_RegValue >> 1);
-
-			} else {
-				i_InputChannel = 0;
-			}
-		}
-
-		/* Selects the command and status register of port B */
-		outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		i_RegValue =
-			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		if ((i_RegValue & 0x60) == 0x60) {
-			/* Selects the command and status register of port B */
-			outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Deletes the interrupt of port B */
-			i_RegValue = (i_RegValue & 0x0F) | 0x20;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Reads port B */
-			i_RegValue =
-				inb((unsigned int) devpriv->iobase +
-				APCI1500_Z8536_PORT_B);
-
-			i_RegValue = i_RegValue & 0xC0;
-			/* Tests if this is an external error */
-
-			if (i_RegValue) {
-				/* Disable the interrupt */
-				/* Selects the command and status register of port B */
-				outl(0x0, devpriv->i_IobaseAmcc + 0x38);
-
-				if (i_RegValue & 0x80) {
-					i_InterruptMask =
-						i_InterruptMask | 0x40;
-				}
-
-				if (i_RegValue & 0x40) {
-					i_InterruptMask =
-						i_InterruptMask | 0x80;
-				}
-			} else {
-				i_InterruptMask = i_InterruptMask | 2;
-			}
-		}
-
-		/* Selects the command and status register of timer 1 */
-		outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		i_RegValue =
-			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		if ((i_RegValue & 0x60) == 0x60) {
-			/* Selects the command and status register of timer 1 */
-			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Deletes the interrupt of timer 1 */
-			i_RegValue = (i_RegValue & 0x0F) | 0x20;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_InterruptMask = i_InterruptMask | 4;
-		}
-		/* Selects the command and status register of timer 2 */
-		outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		i_RegValue =
-			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		if ((i_RegValue & 0x60) == 0x60) {
-			/* Selects the command and status register of timer 2 */
-			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Deletes the interrupt of timer 2 */
-			i_RegValue = (i_RegValue & 0x0F) | 0x20;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			i_InterruptMask = i_InterruptMask | 8;
-		}
-
-		/* Selects the command and status register of timer 3 */
-		outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		i_RegValue =
-			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		if ((i_RegValue & 0x60) == 0x60) {
-			/* Selects the command and status register of timer 3 */
-			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			/* Deletes the interrupt of timer 3 */
-			i_RegValue = (i_RegValue & 0x0F) | 0x20;
-			outb(i_RegValue,
-				devpriv->iobase +
-				APCI1500_Z8536_CONTROL_REGISTER);
-			if (i_CounterLogic == APCI1500_COUNTER)
-				i_InterruptMask = i_InterruptMask | 0x10;
-			else
-				i_InterruptMask = i_InterruptMask | 0x20;
-		}
-
-		send_sig(SIGIO, devpriv->tsk_Current, 0);	/*  send signal to the sample */
-		/* Enable all Interrupts */
-
-		/* Selects the master interrupt control register */
-		outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-		/* Authorizes the main interrupt on the board */
-		outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	} else {
-		dev_warn(dev->class_dev,
-			"Interrupt from unknown source\n");
-
-	}
-
-	return IRQ_HANDLED;
-}
-
-static int apci1500_reset(struct comedi_device *dev)
-{
-	struct apci1500_private *devpriv = dev->private;
-	int i_DummyRead = 0;
-
-	i_TimerCounter1Init = 0;
-	i_TimerCounter2Init = 0;
-	i_WatchdogCounter3Init = 0;
-	i_Event1Status = 0;
-	i_Event2Status = 0;
-	i_TimerCounterWatchdogInterrupt = 0;
-	i_Logic = 0;
-	i_CounterLogic = 0;
-	i_InterruptMask = 0;
-	i_InputChannel = 0;
-	i_TimerCounter1Enabled = 0;
-	i_TimerCounter2Enabled = 0;
-	i_WatchdogCounter3Enabled = 0;
-
-	/* Software reset */
-	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the master configuration control register */
-	outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the mode specification register of port A */
-	outb(APCI1500_RW_PORT_A_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data path polarity register of port A */
-	outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* High level of port A means 1 */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data direction register of port A */
-	outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/*  Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of port A:  */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the handshake specification register of port A */
-	outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the register */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the mode specification register of port B */
-	outb(APCI1500_RW_PORT_B_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data path polarity register of port B */
-	outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* A high level of port B means 1 */
-	outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data direction register of port B */
-	outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs */
-	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of port B:         */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the handshake specification register of port B */
-	outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes the register */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
-	/* Selects the data path polarity register of port C */
-	outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* High level of port C means 1 */
-	outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the data direction register of port C */
-	outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* All bits used as inputs except channel 1 */
-	outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the special IO register of port C */
-	outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes it */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates the interrupt management of timer 1         */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates Timer 2 interrupt management:               */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 3 */
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes IP and IUS */
-	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of Timer 3 */
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates interrupt management of timer 3:            */
-	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the master interrupt control register */
-	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deletes all interrupts */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* reset all the digital outputs */
-	outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
-	/* Disable the board interrupt */
-	/* Selects the master interrupt control register */
-	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port A */
-	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of port B */
-	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 1 */
-	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 2 */
-	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Selects the command and status register of timer 3*/
-	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
-		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	/* Deactivates all interrupts */
-	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-	return 0;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index 339519a..1f2f781 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -93,7 +93,6 @@
 {
 	struct apci3501_private *devpriv = dev->private;
 	unsigned int ul_Command1 = 0;
-	int i_Temp;
 
 	if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
 
@@ -135,7 +134,7 @@
 		}
 	}
 
-	i_Temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1;
+	inl(dev->iobase + APCI3501_TIMER_STATUS_REG);
 	return insn->n;
 }
 
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index bf14165..4911b62 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -22,6 +22,54 @@
  * more details.
  */
 
+/*
+ * Driver: addi_apci_1032
+ * Description: ADDI-DATA APCI-1032 Digital Input Board
+ * Author: ADDI-DATA GmbH <info@addi-data.com>,
+ *   H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Status: untested
+ * Devices: [ADDI-DATA] APCI-1032 (addi_apci_1032)
+ *
+ * Configuration options:
+ *   None; devices are configured automatically.
+ *
+ * This driver models the APCI-1032 as a 32-channel, digital input subdevice
+ * plus an additional digital input subdevice to handle change-of-state (COS)
+ * interrupts (if an interrupt handler can be set up successfully).
+ *
+ * The COS subdevice supports comedi asynchronous read commands.
+ *
+ * Change-Of-State (COS) interrupt configuration:
+ *
+ * Channels 0 to 15 are interruptible. These channels can be configured
+ * to generate interrupts based on AND/OR logic for the desired channels.
+ *
+ *   OR logic:
+ *   - reacts to rising or falling edges
+ *   - interrupt is generated when any enabled channel meets the desired
+ *     interrupt condition
+ *
+ *   AND logic:
+ *   - reacts to changes in level of the selected inputs
+ *   - interrupt is generated when all enabled channels meet the desired
+ *     interrupt condition
+ *   - after an interrupt, a change in level must occur on the selected
+ *     inputs to release the IRQ logic
+ *
+ * The COS subdevice must be configured before setting up a comedi
+ * asynchronous command:
+ *
+ *   data[0] : INSN_CONFIG_DIGITAL_TRIG
+ *   data[1] : trigger number (= 0)
+ *   data[2] : configuration operation:
+ *             - COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
+ *             - COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts
+ *             - COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts
+ *   data[3] : left-shift for data[4] and data[5]
+ *   data[4] : rising-edge/high level channels
+ *   data[5] : falling-edge/low level channels
+ */
+
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -62,36 +110,6 @@
 	return 0;
 }
 
-/*
- * Change-Of-State (COS) interrupt configuration
- *
- * Channels 0 to 15 are interruptible. These channels can be configured
- * to generate interrupts based on AND/OR logic for the desired channels.
- *
- *	OR logic
- *		- reacts to rising or falling edges
- *		- interrupt is generated when any enabled channel
- *		  meet the desired interrupt condition
- *
- *	AND logic
- *		- reacts to changes in level of the selected inputs
- *		- interrupt is generated when all enabled channels
- *		  meet the desired interrupt condition
- *		- after an interrupt, a change in level must occur on
- *		  the selected inputs to release the IRQ logic
- *
- * The COS interrupt must be configured before it can be enabled.
- *
- *	data[0] : INSN_CONFIG_DIGITAL_TRIG
- *	data[1] : trigger number (= 0)
- *	data[2] : configuration operation:
- *	          COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
- *	          COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts
- *	          COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts
- *	data[3] : left-shift for data[4] and data[5]
- *	data[4] : rising-edge/high level channels
- *	data[5] : falling-edge/low level channels
- */
 static int apci1032_cos_insn_config(struct comedi_device *dev,
 				    struct comedi_subdevice *s,
 				    struct comedi_insn *insn,
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 30b132c..f15aa1f 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,22 +1,755 @@
+/*
+ * addi_apci_1500.c
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data.com
+ *	info@addi-data.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/module.h>
 #include <linux/pci.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 
 #include "../comedidev.h"
 #include "comedi_fc.h"
 #include "amcc_s5933.h"
+#include "z8536.h"
+
+/*
+ * PCI Bar 0 Register map (devpriv->amcc)
+ * see amcc_s5933.h for register and bit defines
+ */
+
+/*
+ * PCI Bar 1 Register map (dev->iobase)
+ * see z8536.h for Z8536 internal registers and bit defines
+ */
+#define APCI1500_Z8536_PORTC_REG	0x00
+#define APCI1500_Z8536_PORTB_REG	0x01
+#define APCI1500_Z8536_PORTA_REG	0x02
+#define APCI1500_Z8536_CTRL_REG		0x03
+
+/*
+ * PCI Bar 2 Register map (devpriv->addon)
+ */
+#define APCI1500_CLK_SEL_REG		0x00
+#define APCI1500_DI_REG			0x00
+#define APCI1500_DO_REG			0x02
 
 struct apci1500_private {
-	int iobase;
-	int i_IobaseAmcc;
-	int i_IobaseAddon;
-	int i_IobaseReserved;
-	unsigned char b_OutputMemoryStatus;
-	struct task_struct *tsk_Current;
+	unsigned long amcc;
+	unsigned long addon;
+
+	unsigned int clk_src;
+
+	/* Digital trigger configuration [0]=AND [1]=OR */
+	unsigned int pm[2];	/* Pattern Mask */
+	unsigned int pt[2];	/* Pattern Transition */
+	unsigned int pp[2];	/* Pattern Polarity */
 };
 
-#include "addi-data/hwdrv_apci1500.c"
+static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	return val;
+}
+
+static void z8536_write(struct comedi_device *dev,
+			unsigned int val, unsigned int reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+	outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static void z8536_reset(struct comedi_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 * Even if the state of the Z8536 is not known, the following
+	 * sequence will reset it and put it in State 0.
+	 */
+	spin_lock_irqsave(&dev->spinlock, flags);
+	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	/* Disable all Ports and Counter/Timers */
+	z8536_write(dev, 0x00, Z8536_CFG_CTRL_REG);
+
+	/*
+	 * Port A is connected to Ditial Input channels 0-7.
+	 * Configure the port to allow interrupt detection.
+	 */
+	z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+			 Z8536_PAB_MODE_SB |
+			 Z8536_PAB_MODE_PMS_DISABLE,
+		    Z8536_PA_MODE_REG);
+	z8536_write(dev, 0xff, Z8536_PB_DPP_REG);
+	z8536_write(dev, 0xff, Z8536_PA_DD_REG);
+
+	/*
+	 * Port B is connected to Ditial Input channels 8-13.
+	 * Configure the port to allow interrupt detection.
+	 *
+	 * NOTE: Bits 7 and 6 of Port B are connected to internal
+	 * diagnostic signals and bit 7 is inverted.
+	 */
+	z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+			 Z8536_PAB_MODE_SB |
+			 Z8536_PAB_MODE_PMS_DISABLE,
+		    Z8536_PB_MODE_REG);
+	z8536_write(dev, 0x7f, Z8536_PB_DPP_REG);
+	z8536_write(dev, 0xff, Z8536_PB_DD_REG);
+
+	/*
+	 * Not sure what Port C is connected to...
+	 */
+	z8536_write(dev, 0x09, Z8536_PC_DPP_REG);
+	z8536_write(dev, 0x0e, Z8536_PC_DD_REG);
+
+	/*
+	 * Clear and disable all interrupt sources.
+	 *
+	 * Just in case, the reset of the Z8536 should have already
+	 * done this.
+	 */
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PA_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PB_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(0));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(0));
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(1));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(1));
+
+	z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(2));
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(2));
+
+	/* Disable all interrupts */
+	z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+}
+
+static void apci1500_port_enable(struct comedi_device *dev, bool enable)
+{
+	unsigned int cfg;
+
+	cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+	if (enable)
+		cfg |= (Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+	else
+		cfg &= ~(Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+	z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static void apci1500_timer_enable(struct comedi_device *dev,
+				  unsigned int chan, bool enable)
+{
+	unsigned int bit;
+	unsigned int cfg;
+
+	if (chan == 0)
+		bit = Z8536_CFG_CTRL_CT1E;
+	else if (chan == 1)
+		bit = Z8536_CFG_CTRL_CT2E;
+	else
+		bit = Z8536_CFG_CTRL_PCE_CT3E;
+
+	cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+	if (enable) {
+		cfg |= bit;
+	} else {
+		cfg &= ~bit;
+		z8536_write(dev, 0x00, Z8536_CT_CMDSTAT_REG(chan));
+	}
+	z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static bool apci1500_ack_irq(struct comedi_device *dev,
+			     unsigned int reg)
+{
+	unsigned int val;
+
+	val = z8536_read(dev, reg);
+	if ((val & Z8536_STAT_IE_IP) == Z8536_STAT_IE_IP) {
+		val &= 0x0f;			/* preserve any write bits */
+		val |= Z8536_CMD_CLR_IP_IUS;
+		z8536_write(dev, val, reg);
+
+		return true;
+	}
+	return false;
+}
+
+static irqreturn_t apci1500_interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	struct apci1500_private *devpriv = dev->private;
+	struct comedi_subdevice *s = dev->read_subdev;
+	unsigned int status = 0;
+	unsigned int val;
+
+	val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+	if (!(val & INTCSR_INTR_ASSERTED))
+		return IRQ_NONE;
+
+	if (apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG))
+		status |= 0x01;	/* port a event (inputs 0-7) */
+
+	if (apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG)) {
+		/* Tests if this is an external error */
+		val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
+		val &= 0xc0;
+		if (val) {
+			if (val & 0x80)	/* voltage error */
+				status |= 0x40;
+			if (val & 0x40)	/* short circuit error */
+				status |= 0x80;
+		} else {
+			status |= 0x02;	/* port b event (inputs 8-13) */
+		}
+	}
+
+	/*
+	 * NOTE: The 'status' returned by the sample matches the
+	 * interrupt mask information from the APCI-1500 Users Manual.
+	 *
+	 *    Mask     Meaning
+	 * ----------  ------------------------------------------
+	 * 0x00000001  Event 1 has occured
+	 * 0x00000010  Event 2 has occured
+	 * 0x00000100  Counter/timer 1 has run down (not implemented)
+	 * 0x00001000  Counter/timer 2 has run down (not implemented)
+	 * 0x00010000  Counter 3 has run down (not implemented)
+	 * 0x00100000  Watchdog has run down (not implemented)
+	 * 0x01000000  Voltage error
+	 * 0x10000000  Short-circuit error
+	 */
+	comedi_buf_write_samples(s, &status, 1);
+	comedi_handle_events(dev, s);
+
+	return IRQ_HANDLED;
+}
+
+static int apci1500_di_cancel(struct comedi_device *dev,
+			      struct comedi_subdevice *s)
+{
+	/* Disables the main interrupt on the board */
+	z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+
+	/* Disable Ports A & B */
+	apci1500_port_enable(dev, false);
+
+	/* Ack any pending interrupts */
+	apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG);
+	apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG);
+
+	/* Disable pattern interrupts */
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+	z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+	/* Enable Ports A & B */
+	apci1500_port_enable(dev, true);
+
+	return 0;
+}
+
+static int apci1500_di_inttrig_start(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     unsigned int trig_num)
+{
+	struct apci1500_private *devpriv = dev->private;
+	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned int pa_mode = Z8536_PAB_MODE_PMS_DISABLE;
+	unsigned int pb_mode = Z8536_PAB_MODE_PMS_DISABLE;
+	unsigned int pa_trig = trig_num & 0x01;
+	unsigned int pb_trig = (trig_num >> 1) & 0x01;
+	bool valid_trig = false;
+	unsigned int val;
+
+	if (trig_num != cmd->start_arg)
+		return -EINVAL;
+
+	/* Disable Ports A & B */
+	apci1500_port_enable(dev, false);
+
+	/* Set Port A for selected trigger pattern */
+	z8536_write(dev, devpriv->pm[pa_trig] & 0xff, Z8536_PA_PM_REG);
+	z8536_write(dev, devpriv->pt[pa_trig] & 0xff, Z8536_PA_PT_REG);
+	z8536_write(dev, devpriv->pp[pa_trig] & 0xff, Z8536_PA_PP_REG);
+
+	/* Set Port B for selected trigger pattern */
+	z8536_write(dev, (devpriv->pm[pb_trig] >> 8) & 0xff, Z8536_PB_PM_REG);
+	z8536_write(dev, (devpriv->pt[pb_trig] >> 8) & 0xff, Z8536_PB_PT_REG);
+	z8536_write(dev, (devpriv->pp[pb_trig] >> 8) & 0xff, Z8536_PB_PP_REG);
+
+	/* Set Port A trigger mode (if enabled) and enable interrupt */
+	if (devpriv->pm[pa_trig] & 0xff) {
+		pa_mode = pa_trig ? Z8536_PAB_MODE_PMS_AND
+				  : Z8536_PAB_MODE_PMS_OR;
+
+		val = z8536_read(dev, Z8536_PA_MODE_REG);
+		val &= ~Z8536_PAB_MODE_PMS_MASK;
+		val |= (pa_mode | Z8536_PAB_MODE_IMO);
+		z8536_write(dev, val, Z8536_PA_MODE_REG);
+
+		z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PA_CMDSTAT_REG);
+
+		valid_trig = true;
+
+		dev_dbg(dev->class_dev,
+			"Port A configured for %s mode pattern detection\n",
+			pa_trig ? "AND" : "OR");
+	}
+
+	/* Set Port B trigger mode (if enabled) and enable interrupt */
+	if (devpriv->pm[pb_trig] & 0xff00) {
+		pb_mode = pb_trig ? Z8536_PAB_MODE_PMS_AND
+				  : Z8536_PAB_MODE_PMS_OR;
+
+		val = z8536_read(dev, Z8536_PB_MODE_REG);
+		val &= ~Z8536_PAB_MODE_PMS_MASK;
+		val |= (pb_mode | Z8536_PAB_MODE_IMO);
+		z8536_write(dev, val, Z8536_PB_MODE_REG);
+
+		z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PB_CMDSTAT_REG);
+
+		valid_trig = true;
+
+		dev_dbg(dev->class_dev,
+			"Port B configured for %s mode pattern detection\n",
+			pb_trig ? "AND" : "OR");
+	}
+
+	/* Enable Ports A & B */
+	apci1500_port_enable(dev, true);
+
+	if (!valid_trig) {
+		dev_dbg(dev->class_dev,
+			"digital trigger %d is not configured\n", trig_num);
+		return -EINVAL;
+	}
+
+	/* Authorizes the main interrupt on the board */
+	z8536_write(dev, Z8536_INT_CTRL_MIE | Z8536_INT_CTRL_DLC,
+		    Z8536_INT_CTRL_REG);
+
+	return 0;
+}
+
+static int apci1500_di_cmd(struct comedi_device *dev,
+			   struct comedi_subdevice *s)
+{
+	s->async->inttrig = apci1500_di_inttrig_start;
+
+	return 0;
+}
+
+static int apci1500_di_cmdtest(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_cmd *cmd)
+{
+	int err = 0;
+
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+	if (err)
+		return 1;
+
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
+
+	/* Step 3: check if arguments are trivially valid */
+
+	/*
+	 * Internal start source triggers:
+	 *
+	 *   0	AND mode for Port A (digital inputs 0-7)
+	 *	AND mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   1	OR mode for Port A (digital inputs 0-7)
+	 *	AND mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   2	AND mode for Port A (digital inputs 0-7)
+	 *	OR mode for Port B (digital inputs 8-13 and internal signals)
+	 *
+	 *   3	OR mode for Port A (digital inputs 0-7)
+	 *	OR mode for Port B (digital inputs 8-13 and internal signals)
+	 */
+	err |= cfc_check_trigger_arg_max(&cmd->start_arg, 3);
+
+	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+	if (err)
+		return 3;
+
+	/* Step 4: fix up any arguments */
+
+	/* Step 5: check channel list if it exists */
+
+	return 0;
+}
+
+/*
+ * The pattern-recognition logic must be configured before the digital
+ * input async command is started.
+ *
+ * Digital input channels 0 to 13 can generate interrupts. Channels 14
+ * and 15 are connected to internal board status/diagnostic signals.
+ *
+ * Channel 14 - Voltage error (the external supply is < 5V)
+ * Channel 15 - Short-circuit/overtemperature error
+ *
+ *	data[0] : INSN_CONFIG_DIGITAL_TRIG
+ *	data[1] : trigger number
+ *		  0 = AND mode
+ *		  1 = OR mode
+ *	data[2] : configuration operation:
+ *	          COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
+ *	          COMEDI_DIGITAL_TRIG_ENABLE_EDGES = edge interrupts
+ *	          COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = level interrupts
+ *	data[3] : left-shift for data[4] and data[5]
+ *	data[4] : rising-edge/high level channels
+ *	data[5] : falling-edge/low level channels
+ */
+static int apci1500_di_cfg_trig(struct comedi_device *dev,
+				struct comedi_subdevice *s,
+				struct comedi_insn *insn,
+				unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+	unsigned int trig = data[1];
+	unsigned int shift = data[3];
+	unsigned int hi_mask = data[4] << shift;
+	unsigned int lo_mask = data[5] << shift;
+	unsigned int chan_mask = hi_mask | lo_mask;
+	unsigned int old_mask = (1 << shift) - 1;
+	unsigned int pm = devpriv->pm[trig] & old_mask;
+	unsigned int pt = devpriv->pt[trig] & old_mask;
+	unsigned int pp = devpriv->pp[trig] & old_mask;
+
+	if (trig > 1) {
+		dev_dbg(dev->class_dev,
+			"invalid digital trigger number (0=AND, 1=OR)\n");
+		return -EINVAL;
+	}
+
+	if (chan_mask > 0xffff) {
+		dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
+		return -EINVAL;
+	}
+
+	switch (data[2]) {
+	case COMEDI_DIGITAL_TRIG_DISABLE:
+		/* clear trigger configuration */
+		pm = 0;
+		pt = 0;
+		pp = 0;
+		break;
+	case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
+		pm |= chan_mask;	/* enable channels */
+		pt |= chan_mask;	/* enable edge detection */
+		pp |= hi_mask;		/* rising-edge channels */
+		pp &= ~lo_mask;		/* falling-edge channels */
+		break;
+	case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
+		pm |= chan_mask;	/* enable channels */
+		pt &= ~chan_mask;	/* enable level detection */
+		pp |= hi_mask;		/* high level channels */
+		pp &= ~lo_mask;		/* low level channels */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * The AND mode trigger can only have one channel (max) enabled
+	 * for edge detection.
+	 */
+	if (trig == 0) {
+		int ret = 0;
+		unsigned int src;
+
+		src = pt & 0xff;
+		if (src)
+			ret |= cfc_check_trigger_is_unique(src);
+
+		src = (pt >> 8) & 0xff;
+		if (src)
+			ret |= cfc_check_trigger_is_unique(src);
+
+		if (ret) {
+			dev_dbg(dev->class_dev,
+				"invalid AND trigger configuration\n");
+			return ret;
+		}
+	}
+
+	/* save the trigger configuration */
+	devpriv->pm[trig] = pm;
+	devpriv->pt[trig] = pt;
+	devpriv->pp[trig] = pp;
+
+	return insn->n;
+}
+
+static int apci1500_di_insn_config(struct comedi_device *dev,
+				   struct comedi_subdevice *s,
+				   struct comedi_insn *insn,
+				   unsigned int *data)
+{
+	switch (data[0]) {
+	case INSN_CONFIG_DIGITAL_TRIG:
+		return apci1500_di_cfg_trig(dev, s, insn, data);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int apci1500_di_insn_bits(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+
+	data[1] = inw(devpriv->addon + APCI1500_DI_REG);
+
+	return insn->n;
+}
+
+static int apci1500_do_insn_bits(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+
+	if (comedi_dio_update_state(s, data))
+		outw(s->state, devpriv->addon + APCI1500_DO_REG);
+
+	data[1] = s->state;
+
+	return insn->n;
+}
+
+static int apci1500_timer_insn_config(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      struct comedi_insn *insn,
+				      unsigned int *data)
+{
+	struct apci1500_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int val;
+
+	switch (data[0]) {
+	case INSN_CONFIG_ARM:
+		val = data[1] & s->maxdata;
+		z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan));
+		z8536_write(dev, (val >> 8) & 0xff,
+			    Z8536_CT_RELOAD_MSB_REG(chan));
+
+		apci1500_timer_enable(dev, chan, true);
+		z8536_write(dev, Z8536_CT_CMDSTAT_GCB,
+			    Z8536_CT_CMDSTAT_REG(chan));
+		break;
+	case INSN_CONFIG_DISARM:
+		apci1500_timer_enable(dev, chan, false);
+		break;
+
+	case INSN_CONFIG_GET_COUNTER_STATUS:
+		data[1] = 0;
+		val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+		if (val & Z8536_CT_STAT_CIP)
+			data[1] |= COMEDI_COUNTER_COUNTING;
+		if (val & Z8536_CT_CMDSTAT_GCB)
+			data[1] |= COMEDI_COUNTER_ARMED;
+		if (val & Z8536_STAT_IP) {
+			data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
+			apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan));
+		}
+		data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
+			  COMEDI_COUNTER_TERMINAL_COUNT;
+		break;
+
+	case INSN_CONFIG_SET_COUNTER_MODE:
+		/* Simulate the 8254 timer modes */
+		switch (data[1]) {
+		case I8254_MODE0:
+			/* Interrupt on Terminal Count */
+			val = Z8536_CT_MODE_ECE |
+			      Z8536_CT_MODE_DCS_ONESHOT;
+			break;
+		case I8254_MODE1:
+			/* Hardware Retriggerable One-Shot */
+			val = Z8536_CT_MODE_ETE |
+			      Z8536_CT_MODE_DCS_ONESHOT;
+			break;
+		case I8254_MODE2:
+			/* Rate Generator */
+			val = Z8536_CT_MODE_CSC |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		case I8254_MODE3:
+			/* Square Wave Mode */
+			val = Z8536_CT_MODE_CSC |
+			      Z8536_CT_MODE_DCS_SQRWAVE;
+			break;
+		case I8254_MODE4:
+			/* Software Triggered Strobe */
+			val = Z8536_CT_MODE_REB |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		case I8254_MODE5:
+			/* Hardware Triggered Strobe (watchdog) */
+			val = Z8536_CT_MODE_EOE |
+			      Z8536_CT_MODE_ETE |
+			      Z8536_CT_MODE_REB |
+			      Z8536_CT_MODE_DCS_PULSE;
+			break;
+		default:
+			return -EINVAL;
+		}
+		apci1500_timer_enable(dev, chan, false);
+		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+		break;
+
+	case INSN_CONFIG_SET_CLOCK_SRC:
+		if (data[1] > 2)
+			return -EINVAL;
+		devpriv->clk_src = data[1];
+		if (devpriv->clk_src == 2)
+			devpriv->clk_src = 3;
+		outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG);
+		break;
+	case INSN_CONFIG_GET_CLOCK_SRC:
+		switch (devpriv->clk_src) {
+		case 0:
+			data[1] = 0;		/* 111.86 kHz / 2 */
+			data[2] = 17879;	/* 17879 ns (approx) */
+			break;
+		case 1:
+			data[1] = 1;		/* 3.49 kHz / 2 */
+			data[2] = 573066;	/* 573066 ns (approx) */
+			break;
+		case 3:
+			data[1] = 2;		/* 1.747 kHz / 2 */
+			data[2] = 1164822;	/* 1164822 ns (approx) */
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case INSN_CONFIG_SET_GATE_SRC:
+		if (chan == 0)
+			return -EINVAL;
+
+		val = z8536_read(dev, Z8536_CT_MODE_REG(chan));
+		val &= Z8536_CT_MODE_EGE;
+		if (data[1] == 1)
+			val |= Z8536_CT_MODE_EGE;
+		else if (data[1] > 1)
+			return -EINVAL;
+		z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+		break;
+	case INSN_CONFIG_GET_GATE_SRC:
+		if (chan == 0)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return insn->n;
+}
+
+static int apci1500_timer_insn_write(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     struct comedi_insn *insn,
+				     unsigned int *data)
+{
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int cmd;
+
+	cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+	cmd &= Z8536_CT_CMDSTAT_GCB;	/* preserve gate */
+	cmd |= Z8536_CT_CMD_TCB;	/* set trigger */
+
+	/* software trigger a timer, it only makes sense to do one write */
+	if (insn->n)
+		z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+	return insn->n;
+}
+
+static int apci1500_timer_insn_read(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int cmd;
+	unsigned int val;
+	int i;
+
+	cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+	cmd &= Z8536_CT_CMDSTAT_GCB;	/* preserve gate */
+	cmd |= Z8536_CT_CMD_RCC;	/* set RCC */
+
+	for (i = 0; i < insn->n; i++) {
+		z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+		val = z8536_read(dev, Z8536_CT_VAL_MSB_REG(chan)) << 8;
+		val |= z8536_read(dev, Z8536_CT_VAL_LSB_REG(chan));
+
+		data[i] = val;
+	}
+
+	return insn->n;
+}
 
 static int apci1500_auto_attach(struct comedi_device *dev,
 				unsigned long context)
@@ -35,10 +768,10 @@
 		return ret;
 
 	dev->iobase = pci_resource_start(pcidev, 1);
-	devpriv->iobase = dev->iobase;
-	devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
-	devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2);
-	devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
+	devpriv->amcc = pci_resource_start(pcidev, 0);
+	devpriv->addon = pci_resource_start(pcidev, 2);
+
+	z8536_reset(dev);
 
 	if (pcidev->irq > 0) {
 		ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED,
@@ -51,51 +784,66 @@
 	if (ret)
 		return ret;
 
-	/*  Allocate and Initialise DI Subdevice Structures */
+	/* Digital Input subdevice */
 	s = &dev->subdevices[0];
-	s->type = COMEDI_SUBD_DI;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_config = apci1500_di_config;
-	s->insn_read = apci1500_di_read;
-	s->insn_write = apci1500_di_write;
-	s->insn_bits = apci1500_di_insn_bits;
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= apci1500_di_insn_bits;
+	if (dev->irq) {
+		dev->read_subdev = s;
+		s->subdev_flags |= SDF_CMD_READ;
+		s->len_chanlist	= 1;
+		s->insn_config	= apci1500_di_insn_config;
+		s->do_cmdtest	= apci1500_di_cmdtest;
+		s->do_cmd	= apci1500_di_cmd;
+		s->cancel	= apci1500_di_cancel;
+	}
 
-	/*  Allocate and Initialise DO Subdevice Structures */
+	/* Digital Output subdevice */
 	s = &dev->subdevices[1];
-	s->type = COMEDI_SUBD_DO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_config = apci1500_do_config;
-	s->insn_write = apci1500_do_write;
-	s->insn_bits = apci1500_do_bits;
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= apci1500_do_insn_bits;
 
-	/*  Allocate and Initialise Timer Subdevice Structures */
+	/* reset all the digital outputs */
+	outw(0x0, devpriv->addon + APCI1500_DO_REG);
+
+	/* Counter/Timer(Watchdog) subdevice */
 	s = &dev->subdevices[2];
-	s->type = COMEDI_SUBD_TIMER;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 1;
-	s->maxdata = 0;
-	s->len_chanlist = 1;
-	s->range_table = &range_digital;
-	s->insn_write = apci1500_timer_write;
-	s->insn_read = apci1500_timer_read;
-	s->insn_config = apci1500_timer_config;
-	s->insn_bits = apci1500_timer_bits;
+	s->type		= COMEDI_SUBD_TIMER;
+	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
+	s->n_chan	= 3;
+	s->maxdata	= 0xffff;
+	s->range_table	= &range_unknown;
+	s->insn_config	= apci1500_timer_insn_config;
+	s->insn_write	= apci1500_timer_insn_write;
+	s->insn_read	= apci1500_timer_insn_read;
 
-	apci1500_reset(dev);
+	/* Enable the PCI interrupt */
+	if (dev->irq) {
+		outl(0x2000 | INTCSR_INBOX_FULL_INT,
+		     devpriv->amcc + AMCC_OP_REG_INTCSR);
+		inl(devpriv->amcc + AMCC_OP_REG_IMB1);
+		inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+		outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT,
+		     devpriv->amcc + AMCC_OP_REG_INTCSR);
+	}
 
 	return 0;
 }
 
 static void apci1500_detach(struct comedi_device *dev)
 {
-	if (dev->iobase)
-		apci1500_reset(dev);
+	struct apci1500_private *devpriv = dev->private;
+
+	if (devpriv->amcc)
+		outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
 	comedi_pci_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index a726efc..5961f19 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -267,7 +267,6 @@
 	struct apci3501_private *devpriv = dev->private;
 	unsigned int ui_Timer_AOWatchdog;
 	unsigned long ul_Command1;
-	int i_temp;
 
 	/*  Disable Interrupt */
 	ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
@@ -285,7 +284,7 @@
 	ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
 	ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1);
 	outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG);
-	i_temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1;
+	inl(dev->iobase + APCI3501_TIMER_STATUS_REG);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 528f15c..a3ea4b7 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -19,8 +19,7 @@
 /*
  * Driver: adl_pci6208
  * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
- * Devices: (ADLink) PCI-6208 [adl_pci6208]
- *	    (ADLink) PCI-6216 [adl_pci6216]
+ * Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216 (adl_pci6216)
  * Author: nsyeow <nsyeow@pd.jaring.my>
  * Updated: Fri, 30 Jan 2004 14:44:27 +0800
  * Status: untested
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index fb8e5f5..618e641 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -22,27 +22,35 @@
  */
 
 /*
-Driver: adl_pci7x3x
-Description: 32/64-Channel Isolated Digital I/O Boards
-Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output
-	 (ADLink) PCI-7233 [adl_pci7233] - 32 input
-	 (ADLink) PCI-7234 [adl_pci7234] - 32 output
-	 (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output
-	 (ADLink) PCI-7433 [adl_pci7433] - 64 input
-	 (ADLink) PCI-7434 [adl_pci7434] - 64 output
-Author: H Hartley Sweeten <hsweeten@visionengravers.com>
-Updated: Thu, 02 Aug 2012 14:27:46 -0700
-Status: untested
-
-The PCI-7230, PCI-7432 and PCI-7433 boards also support external
-interrupt signals on digital input channels 0 and 1. The PCI-7233
-has dual-interrupt sources for change-of-state (COS) on any 16
-digital input channels of LSB and for COS on any 16 digital input
-lines of MSB. Interrupts are not currently supported by this
-driver.
-
-Configuration Options: not applicable, uses comedi PCI auto config
-*/
+ * Driver: adl_pci7x3x
+ * Description: 32/64-Channel Isolated Digital I/O Boards
+ * Devices: [ADLink] PCI-7230 (adl_pci7230), PCI-7233 (adl_pci7233),
+ *   PCI-7234 (adl_pci7234), PCI-7432 (adl_pci7432), PCI-7433 (adl_pci7433),
+ *   PCI-7434 (adl_pci7434)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Thu, 02 Aug 2012 14:27:46 -0700
+ * Status: untested
+ *
+ * One or two subdevices are setup by this driver depending on
+ * the number of digital inputs and/or outputs provided by the
+ * board. Each subdevice has a maximum of 32 channels.
+ *
+ *	PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
+ *	PCI-7233 - 1 subdevice: 0 - 32 input
+ *	PCI-7234 - 1 subdevice: 0 - 32 output
+ *	PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
+ *	PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
+ *	PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
+ *
+ * The PCI-7230, PCI-7432 and PCI-7433 boards also support external
+ * interrupt signals on digital input channels 0 and 1. The PCI-7233
+ * has dual-interrupt sources for change-of-state (COS) on any 16
+ * digital input channels of LSB and for COS on any 16 digital input
+ * lines of MSB. Interrupts are not currently supported by this
+ * driver.
+ *
+ * Configuration Options: not applicable, uses comedi PCI auto config
+ */
 
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -155,18 +163,6 @@
 		return ret;
 	dev->iobase = pci_resource_start(pcidev, 2);
 
-	/*
-	 * One or two subdevices are setup by this driver depending on
-	 * the number of digital inputs and/or outputs provided by the
-	 * board. Each subdevice has a maximum of 32 channels.
-	 *
-	 *	PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
-	 *	PCI-7233 - 1 subdevice: 0 - 32 input
-	 *	PCI-7234 - 1 subdevice: 0 - 32 output
-	 *	PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
-	 *	PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
-	 *	PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
-	 */
 	ret = comedi_alloc_subdevices(dev, board->nsubdevs);
 	if (ret)
 		return ret;
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 72bccb4..cc6c53b 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -18,7 +18,7 @@
 /*
  * Driver: adl_pci8164
  * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
- * Devices: (ADLink) PCI-8164 [adl_pci8164]
+ * Devices: [ADLink] PCI-8164 (adl_pci8164)
  * Author: Michel Lachaine <mike@mikelachaine.ca>
  * Status: experimental
  * Updated: Mon, 14 Apr 2008 15:10:32 +0100
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 47f6c0e..f68dc99 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -539,7 +539,7 @@
 			spin_unlock_irqrestore(&dev->spinlock, irq_flags);
 			dev_dbg(dev->class_dev, "fifo overflow\n");
 			outb(0, dev->iobase + PCI9111_INT_CLR_REG);
-			async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+			async->events |= COMEDI_CB_ERROR;
 			comedi_handle_events(dev, s);
 
 			return IRQ_HANDLED;
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 2660358..f61e392 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -749,13 +749,13 @@
 
 	if (intcsr & MASTER_ABORT_INT) {
 		dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
-		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		s->async->events |= COMEDI_CB_ERROR;
 		goto interrupt_exit;
 	}
 
 	if (intcsr & TARGET_ABORT_INT) {
 		dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
-		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		s->async->events |= COMEDI_CB_ERROR;
 		goto interrupt_exit;
 	}
 
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index d02df7d..9800c01 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -51,11 +51,6 @@
 #include "8253.h"
 #include "amcc_s5933.h"
 
-/* hardware types of the cards */
-#define TYPE_PCI171X	0
-#define TYPE_PCI1713	2
-#define TYPE_PCI1720	3
-
 #define PCI171x_AD_DATA	 0	/* R:   A/D data */
 #define PCI171x_SOFTTRG	 0	/* W:   soft trigger for A/D */
 #define PCI171x_RANGE	 2	/* W:   A/D gain/range register */
@@ -164,7 +159,7 @@
 
 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
 
-static const struct comedi_lrange range_pci1720 = {
+static const struct comedi_lrange pci1720_ao_range = {
 	4, {
 		UNI_RANGE(5),
 		UNI_RANGE(10),
@@ -173,7 +168,7 @@
 	}
 };
 
-static const struct comedi_lrange range_pci171x_da = {
+static const struct comedi_lrange pci171x_ao_range = {
 	2, {
 		UNI_RANGE(5),
 		UNI_RANGE(10)
@@ -191,112 +186,81 @@
 
 struct boardtype {
 	const char *name;	/*  board name */
-	char have_irq;		/*  1=card support IRQ */
-	char cardtype;		/*  0=1710& co. 2=1713, ... */
 	int n_aichan;		/*  num of A/D chans */
-	int n_aichand;		/*  num of A/D chans in diff mode */
-	int n_aochan;		/*  num of D/A chans */
-	int n_dichan;		/*  num of DI chans */
-	int n_dochan;		/*  num of DO chans */
-	int n_counter;		/*  num of counters */
-	int ai_maxdata;		/*  resolution of A/D */
-	int ao_maxdata;		/*  resolution of D/A */
 	const struct comedi_lrange *rangelist_ai;	/*  rangelist for A/D */
 	const char *rangecode_ai;	/*  range codes for programming */
-	const struct comedi_lrange *rangelist_ao;	/*  rangelist for D/A */
-	unsigned int ai_ns_min;	/*  max sample speed of card v ns */
-	unsigned int fifo_half_size;	/*  size of FIFO/2 */
+	unsigned int is_pci1713:1;
+	unsigned int is_pci1720:1;
+	unsigned int has_irq:1;
+	unsigned int has_large_fifo:1;	/* 4K or 1K FIFO */
+	unsigned int has_diff_ai:1;
+	unsigned int has_ao:1;
+	unsigned int has_di_do:1;
+	unsigned int has_counter:1;
 };
 
 static const struct boardtype boardtypes[] = {
 	[BOARD_PCI1710] = {
 		.name		= "pci1710",
-		.have_irq	= 1,
-		.cardtype	= TYPE_PCI171X,
 		.n_aichan	= 16,
-		.n_aichand	= 8,
-		.n_aochan	= 2,
-		.n_dichan	= 16,
-		.n_dochan	= 16,
-		.n_counter	= 1,
-		.ai_maxdata	= 0x0fff,
-		.ao_maxdata	= 0x0fff,
 		.rangelist_ai	= &range_pci1710_3,
 		.rangecode_ai	= range_codes_pci1710_3,
-		.rangelist_ao	= &range_pci171x_da,
-		.ai_ns_min	= 10000,
-		.fifo_half_size	= 2048,
+		.has_irq	= 1,
+		.has_large_fifo	= 1,
+		.has_diff_ai	= 1,
+		.has_ao		= 1,
+		.has_di_do	= 1,
+		.has_counter	= 1,
 	},
 	[BOARD_PCI1710HG] = {
 		.name		= "pci1710hg",
-		.have_irq	= 1,
-		.cardtype	= TYPE_PCI171X,
 		.n_aichan	= 16,
-		.n_aichand	= 8,
-		.n_aochan	= 2,
-		.n_dichan	= 16,
-		.n_dochan	= 16,
-		.n_counter	= 1,
-		.ai_maxdata	= 0x0fff,
-		.ao_maxdata	= 0x0fff,
 		.rangelist_ai	= &range_pci1710hg,
 		.rangecode_ai	= range_codes_pci1710hg,
-		.rangelist_ao	= &range_pci171x_da,
-		.ai_ns_min	= 10000,
-		.fifo_half_size	= 2048,
+		.has_irq	= 1,
+		.has_large_fifo	= 1,
+		.has_diff_ai	= 1,
+		.has_ao		= 1,
+		.has_di_do	= 1,
+		.has_counter	= 1,
 	},
 	[BOARD_PCI1711] = {
 		.name		= "pci1711",
-		.have_irq	= 1,
-		.cardtype	= TYPE_PCI171X,
 		.n_aichan	= 16,
-		.n_aochan	= 2,
-		.n_dichan	= 16,
-		.n_dochan	= 16,
-		.n_counter	= 1,
-		.ai_maxdata	= 0x0fff,
-		.ao_maxdata	= 0x0fff,
 		.rangelist_ai	= &range_pci17x1,
 		.rangecode_ai	= range_codes_pci17x1,
-		.rangelist_ao	= &range_pci171x_da,
-		.ai_ns_min	= 10000,
-		.fifo_half_size	= 512,
+		.has_irq	= 1,
+		.has_ao		= 1,
+		.has_di_do	= 1,
+		.has_counter	= 1,
 	},
 	[BOARD_PCI1713] = {
 		.name		= "pci1713",
-		.have_irq	= 1,
-		.cardtype	= TYPE_PCI1713,
 		.n_aichan	= 32,
-		.n_aichand	= 16,
-		.ai_maxdata	= 0x0fff,
 		.rangelist_ai	= &range_pci1710_3,
 		.rangecode_ai	= range_codes_pci1710_3,
-		.ai_ns_min	= 10000,
-		.fifo_half_size	= 2048,
+		.is_pci1713	= 1,
+		.has_irq	= 1,
+		.has_large_fifo	= 1,
+		.has_diff_ai	= 1,
 	},
 	[BOARD_PCI1720] = {
 		.name		= "pci1720",
-		.cardtype	= TYPE_PCI1720,
-		.n_aochan	= 4,
-		.ao_maxdata	= 0x0fff,
-		.rangelist_ao	= &range_pci1720,
+		.is_pci1720	= 1,
+		.has_ao		= 1,
 	},
 	[BOARD_PCI1731] = {
 		.name		= "pci1731",
-		.have_irq	= 1,
-		.cardtype	= TYPE_PCI171X,
 		.n_aichan	= 16,
-		.n_dichan	= 16,
-		.n_dochan	= 16,
-		.ai_maxdata	= 0x0fff,
 		.rangelist_ai	= &range_pci17x1,
 		.rangecode_ai	= range_codes_pci17x1,
-		.ai_ns_min	= 10000,
-		.fifo_half_size	= 512,
+		.has_irq	= 1,
+		.has_di_do	= 1,
 	},
 };
 
 struct pci1710_private {
+	unsigned int max_samples;
 	unsigned int CntrlReg;	/*  Control register */
 	unsigned char ai_et;
 	unsigned int ai_et_CntrlReg;
@@ -308,39 +272,10 @@
 	unsigned int act_chanlist[32];	/*  list of scanned channel */
 	unsigned char saved_seglen;	/* len of the non-repeating chanlist */
 	unsigned char da_ranges;	/*  copy of D/A outpit range register */
-	unsigned short ao_data[4];	/*  data output buffer */
 	unsigned int cnt0_write_wait;	/* after a write, wait for update of the
 					 * internal state */
 };
 
-/*  used for gain list programming */
-static const unsigned int muxonechan[] = {
-	0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
-	0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
-	0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
-	0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
-};
-
-static int pci171x_ai_dropout(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      unsigned int chan,
-			      unsigned int val)
-{
-	const struct boardtype *board = dev->board_ptr;
-	struct pci1710_private *devpriv = dev->private;
-
-	if (board->cardtype != TYPE_PCI1713) {
-		if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
-			dev_err(dev->class_dev,
-				"A/D data droput: received from channel %d, expected %d\n",
-				(val >> 12) & 0xf,
-				(devpriv->act_chanlist[chan] >> 12) & 0xf);
-			return -ENODATA;
-		}
-	}
-	return 0;
-}
-
 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
 				     struct comedi_subdevice *s,
 				     struct comedi_cmd *cmd)
@@ -407,33 +342,39 @@
 	return 0;
 }
 
-static void setup_channel_list(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       unsigned int *chanlist, unsigned int n_chan,
-			       unsigned int seglen)
+static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      unsigned int *chanlist,
+				      unsigned int n_chan,
+				      unsigned int seglen)
 {
-	const struct boardtype *this_board = dev->board_ptr;
+	const struct boardtype *board = dev->board_ptr;
 	struct pci1710_private *devpriv = dev->private;
-	unsigned int i, range, chanprog;
+	unsigned int first_chan = CR_CHAN(chanlist[0]);
+	unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
+	unsigned int i;
 
 	for (i = 0; i < seglen; i++) {	/*  store range list to card */
-		chanprog = muxonechan[CR_CHAN(chanlist[i])];
-		outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
-		range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
-		if (CR_AREF(chanlist[i]) == AREF_DIFF)
-			range |= 0x0020;
-		outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
-		devpriv->act_chanlist[i] =
-			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
-	}
-	for ( ; i < n_chan; i++) { /* store remainder of channel list */
-		devpriv->act_chanlist[i] =
-			(CR_CHAN(chanlist[i]) << 12) & 0xf000;
-	}
+		unsigned int chan = CR_CHAN(chanlist[i]);
+		unsigned int range = CR_RANGE(chanlist[i]);
+		unsigned int aref = CR_AREF(chanlist[i]);
+		unsigned int rangeval;
 
-	devpriv->ai_et_MuxVal =
-		CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
+		rangeval = board->rangecode_ai[range];
+		if (aref == AREF_DIFF)
+			rangeval |= 0x0020;
+
+		/* select channel and set range */
+		outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
+		outw(rangeval, dev->iobase + PCI171x_RANGE);
+
+		devpriv->act_chanlist[i] = chan;
+	}
+	for ( ; i < n_chan; i++)	/* store remainder of channel list */
+		devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
+
 	/* select channel interval to scan */
+	devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
 	outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
 }
 
@@ -450,9 +391,39 @@
 	return -EBUSY;
 }
 
-static int pci171x_insn_read_ai(struct comedi_device *dev,
+static int pci171x_ai_read_sample(struct comedi_device *dev,
+				  struct comedi_subdevice *s,
+				  unsigned int cur_chan,
+				  unsigned int *val)
+{
+	const struct boardtype *board = dev->board_ptr;
+	struct pci1710_private *devpriv = dev->private;
+	unsigned int sample;
+	unsigned int chan;
+
+	sample = inw(dev->iobase + PCI171x_AD_DATA);
+	if (!board->is_pci1713) {
+		/*
+		 * The upper 4 bits of the 16-bit sample are the channel number
+		 * that the sample was acquired from. Verify that this channel
+		 * number matches the expected channel number.
+		 */
+		chan = sample >> 12;
+		if (chan != devpriv->act_chanlist[cur_chan]) {
+			dev_err(dev->class_dev,
+				"A/D data droput: received from channel %d, expected %d\n",
+				chan, devpriv->act_chanlist[cur_chan]);
+			return -ENODATA;
+		}
+	}
+	*val = sample & s->maxdata;
+	return 0;
+}
+
+static int pci171x_ai_insn_read(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	struct pci1710_private *devpriv = dev->private;
 	unsigned int chan = CR_CHAN(insn->chanspec);
@@ -465,7 +436,7 @@
 	outb(0, dev->iobase + PCI171x_CLRFIFO);
 	outb(0, dev->iobase + PCI171x_CLRINT);
 
-	setup_channel_list(dev, s, &insn->chanspec, 1, 1);
+	pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
 
 	for (i = 0; i < insn->n; i++) {
 		unsigned int val;
@@ -476,12 +447,11 @@
 		if (ret)
 			break;
 
-		val = inw(dev->iobase + PCI171x_AD_DATA);
-		ret = pci171x_ai_dropout(dev, s, chan, val);
+		ret = pci171x_ai_read_sample(dev, s, chan, &val);
 		if (ret)
 			break;
 
-		data[i] = val & s->maxdata;
+		data[i] = val;
 	}
 
 	outb(0, dev->iobase + PCI171x_CLRFIFO);
@@ -490,73 +460,43 @@
 	return ret ? ret : insn->n;
 }
 
-/*
-==============================================================================
-*/
-static int pci171x_insn_write_ao(struct comedi_device *dev,
+static int pci171x_ao_insn_write(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
 	struct pci1710_private *devpriv = dev->private;
-	unsigned int val;
-	int n, chan, range, ofs;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
+	unsigned int val = s->readback[chan];
+	int i;
 
-	chan = CR_CHAN(insn->chanspec);
-	range = CR_RANGE(insn->chanspec);
-	if (chan) {
-		devpriv->da_ranges &= 0xfb;
-		devpriv->da_ranges |= (range << 2);
-		outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
-		ofs = PCI171x_DA2;
-	} else {
-		devpriv->da_ranges &= 0xfe;
-		devpriv->da_ranges |= range;
-		outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
-		ofs = PCI171x_DA1;
-	}
-	val = devpriv->ao_data[chan];
+	devpriv->da_ranges &= ~(1 << (chan << 1));
+	devpriv->da_ranges |= (range << (chan << 1));
+	outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
 
-	for (n = 0; n < insn->n; n++) {
-		val = data[n];
-		outw(val, dev->iobase + ofs);
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
+		outw(val, dev->iobase + reg);
 	}
 
-	devpriv->ao_data[chan] = val;
+	s->readback[chan] = val;
 
-	return n;
-
+	return insn->n;
 }
 
-/*
-==============================================================================
-*/
-static int pci171x_insn_read_ao(struct comedi_device *dev,
+static int pci171x_di_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
-{
-	struct pci1710_private *devpriv = dev->private;
-	int n, chan;
-
-	chan = CR_CHAN(insn->chanspec);
-	for (n = 0; n < insn->n; n++)
-		data[n] = devpriv->ao_data[chan];
-
-	return n;
-}
-
-/*
-==============================================================================
-*/
-static int pci171x_insn_bits_di(struct comedi_device *dev,
-				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	data[1] = inw(dev->iobase + PCI171x_DI);
 
 	return insn->n;
 }
 
-static int pci171x_insn_bits_do(struct comedi_device *dev,
+static int pci171x_do_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn,
 				unsigned int *data)
@@ -584,10 +524,7 @@
 	}
 }
 
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_read(struct comedi_device *dev,
+static int pci171x_counter_insn_read(struct comedi_device *dev,
 				     struct comedi_subdevice *s,
 				     struct comedi_insn *insn,
 				     unsigned int *data)
@@ -608,10 +545,7 @@
 	return insn->n;
 }
 
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_write(struct comedi_device *dev,
+static int pci171x_counter_insn_write(struct comedi_device *dev,
 				      struct comedi_subdevice *s,
 				      struct comedi_insn *insn,
 				      unsigned int *data)
@@ -638,10 +572,7 @@
 	return insn->n;
 }
 
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_config(struct comedi_device *dev,
+static int pci171x_counter_insn_config(struct comedi_device *dev,
 				       struct comedi_subdevice *s,
 				       struct comedi_insn *insn,
 				       unsigned int *data)
@@ -677,57 +608,48 @@
 	return 1;
 }
 
-/*
-==============================================================================
-*/
-static int pci1720_insn_write_ao(struct comedi_device *dev,
+static int pci1720_ao_insn_write(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
 	struct pci1710_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
 	unsigned int val;
-	int n, rangereg, chan;
+	int i;
 
-	chan = CR_CHAN(insn->chanspec);
-	rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
-	rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
-	if (rangereg != devpriv->da_ranges) {
-		outb(rangereg, dev->iobase + PCI1720_RANGE);
-		devpriv->da_ranges = rangereg;
+	val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
+	val |= (range << (chan << 1));
+	if (val != devpriv->da_ranges) {
+		outb(val, dev->iobase + PCI1720_RANGE);
+		devpriv->da_ranges = val;
 	}
-	val = devpriv->ao_data[chan];
 
-	for (n = 0; n < insn->n; n++) {
-		val = data[n];
+	val = s->readback[chan];
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
 		outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
-		outb(0, dev->iobase + PCI1720_SYNCOUT);	/*  update outputs */
+		outb(0, dev->iobase + PCI1720_SYNCOUT);	/* update outputs */
 	}
 
-	devpriv->ao_data[chan] = val;
+	s->readback[chan] = val;
 
-	return n;
+	return insn->n;
 }
 
-/*
-==============================================================================
-*/
 static int pci171x_ai_cancel(struct comedi_device *dev,
 			     struct comedi_subdevice *s)
 {
-	const struct boardtype *this_board = dev->board_ptr;
 	struct pci1710_private *devpriv = dev->private;
 
-	switch (this_board->cardtype) {
-	default:
-		devpriv->CntrlReg &= Control_CNT0;
-		devpriv->CntrlReg |= Control_SW;
-		/* reset any operations */
-		outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
-		pci171x_start_pacer(dev, false);
-		outb(0, dev->iobase + PCI171x_CLRFIFO);
-		outb(0, dev->iobase + PCI171x_CLRINT);
-		break;
-	}
+	devpriv->CntrlReg &= Control_CNT0;
+	devpriv->CntrlReg |= Control_SW;
+	/* reset any operations */
+	outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
+	pci171x_start_pacer(dev, false);
+	outb(0, dev->iobase + PCI171x_CLRFIFO);
+	outb(0, dev->iobase + PCI171x_CLRINT);
 
 	return 0;
 }
@@ -743,29 +665,25 @@
 	status = inw(dev->iobase + PCI171x_STATUS);
 	if (status & Status_FE) {
 		dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-		comedi_handle_events(dev, s);
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 	if (status & Status_FF) {
 		dev_dbg(dev->class_dev,
 			"A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-		comedi_handle_events(dev, s);
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
 
 	for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
-		val = inw(dev->iobase + PCI171x_AD_DATA);
-		ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
+		ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
 		if (ret) {
-			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+			s->async->events |= COMEDI_CB_ERROR;
 			break;
 		}
 
-		val &= s->maxdata;
 		comedi_buf_write_samples(s, &val, 1);
 
 		if (cmd->stop_src == TRIG_COUNT &&
@@ -776,85 +694,53 @@
 	}
 
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
-
-	comedi_handle_events(dev, s);
-}
-
-/*
-==============================================================================
-*/
-static int move_block_from_fifo(struct comedi_device *dev,
-				struct comedi_subdevice *s, int n, int turn)
-{
-	unsigned int val;
-	int ret;
-	int i;
-
-	for (i = 0; i < n; i++) {
-		val = inw(dev->iobase + PCI171x_AD_DATA);
-
-		ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
-		if (ret) {
-			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-			return ret;
-		}
-
-		val &= s->maxdata;
-		comedi_buf_write_samples(s, &val, 1);
-	}
-	return 0;
 }
 
 static void pci1710_handle_fifo(struct comedi_device *dev,
 				struct comedi_subdevice *s)
 {
-	const struct boardtype *this_board = dev->board_ptr;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int nsamples;
-	unsigned int m;
+	struct pci1710_private *devpriv = dev->private;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+	unsigned int status;
+	int i;
 
-	m = inw(dev->iobase + PCI171x_STATUS);
-	if (!(m & Status_FH)) {
-		dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-		comedi_handle_events(dev, s);
+	status = inw(dev->iobase + PCI171x_STATUS);
+	if (!(status & Status_FH)) {
+		dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
+		async->events |= COMEDI_CB_ERROR;
 		return;
 	}
-	if (m & Status_FF) {
+	if (status & Status_FF) {
 		dev_dbg(dev->class_dev,
-			"A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-		comedi_handle_events(dev, s);
+			"A/D FIFO Full status (Fatal Error!)\n");
+		async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
-	nsamples = this_board->fifo_half_size;
-	if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
-		m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
-		if (move_block_from_fifo(dev, s, m, 0))
-			return;
-		nsamples -= m;
+	for (i = 0; i < devpriv->max_samples; i++) {
+		unsigned int val;
+		int ret;
+
+		ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
+		if (ret) {
+			s->async->events |= COMEDI_CB_ERROR;
+			break;
+		}
+
+		if (!comedi_buf_write_samples(s, &val, 1))
+			break;
+
+		if (cmd->stop_src == TRIG_COUNT &&
+		    async->scans_done >= cmd->stop_arg) {
+			async->events |= COMEDI_CB_EOA;
+			break;
+		}
 	}
 
-	if (nsamples) {
-		if (move_block_from_fifo(dev, s, nsamples, 1))
-			return;
-	}
-
-	if (cmd->stop_src == TRIG_COUNT &&
-	    s->async->scans_done >= cmd->stop_arg) {
-		s->async->events |= COMEDI_CB_EOA;
-		comedi_handle_events(dev, s);
-		return;
-	}
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear our INT request */
-
-	comedi_handle_events(dev, s);
 }
 
-/*
-==============================================================================
-*/
 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
 {
 	struct comedi_device *dev = d;
@@ -891,6 +777,8 @@
 	else
 		pci1710_handle_fifo(dev, s);
 
+	comedi_handle_events(dev, s);
+
 	return IRQ_HANDLED;
 }
 
@@ -901,8 +789,8 @@
 
 	pci171x_start_pacer(dev, false);
 
-	setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
-			   devpriv->saved_seglen);
+	pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
+				  devpriv->saved_seglen);
 
 	outb(0, dev->iobase + PCI171x_CLRFIFO);
 	outb(0, dev->iobase + PCI171x_CLRINT);
@@ -937,14 +825,10 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci171x_ai_cmdtest(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
 			      struct comedi_cmd *cmd)
 {
-	const struct boardtype *this_board = dev->board_ptr;
 	struct pci1710_private *devpriv = dev->private;
 	int err = 0;
 	unsigned int arg;
@@ -977,8 +861,7 @@
 	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 
 	if (cmd->convert_src == TRIG_TIMER)
-		err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
-						 this_board->ai_ns_min);
+		err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
 	else	/* TRIG_FOLLOW */
 		err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
 
@@ -1016,12 +899,9 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci171x_reset(struct comedi_device *dev)
 {
-	const struct boardtype *this_board = dev->board_ptr;
+	const struct boardtype *board = dev->board_ptr;
 	struct pci1710_private *devpriv = dev->private;
 
 	outw(0x30, dev->iobase + PCI171x_CNTCTRL);
@@ -1033,15 +913,11 @@
 	outb(0, dev->iobase + PCI171x_CLRINT);	/*  clear INT request */
 	pci171x_start_pacer(dev, false);
 	devpriv->da_ranges = 0;
-	if (this_board->n_aochan) {
+	if (board->has_ao) {
 		/* set DACs to 0..5V */
 		outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
 		outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
-		devpriv->ao_data[0] = 0x0000;
-		if (this_board->n_aochan > 1) {
-			outw(0, dev->iobase + PCI171x_DA2);
-			devpriv->ao_data[1] = 0x0000;
-		}
+		outw(0, dev->iobase + PCI171x_DA2);
 	}
 	outw(0, dev->iobase + PCI171x_DO);	/*  digital outputs to 0 */
 	outb(0, dev->iobase + PCI171x_CLRFIFO);	/*  clear FIFO */
@@ -1050,9 +926,6 @@
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci1720_reset(struct comedi_device *dev)
 {
 	struct pci1710_private *devpriv = dev->private;
@@ -1066,43 +939,35 @@
 	outw(0x0800, dev->iobase + PCI1720_DA2);
 	outw(0x0800, dev->iobase + PCI1720_DA3);
 	outb(0, dev->iobase + PCI1720_SYNCOUT);	/*  update outputs */
-	devpriv->ao_data[0] = 0x0800;
-	devpriv->ao_data[1] = 0x0800;
-	devpriv->ao_data[2] = 0x0800;
-	devpriv->ao_data[3] = 0x0800;
+
 	return 0;
 }
 
-/*
-==============================================================================
-*/
 static int pci1710_reset(struct comedi_device *dev)
 {
-	const struct boardtype *this_board = dev->board_ptr;
+	const struct boardtype *board = dev->board_ptr;
 
-	switch (this_board->cardtype) {
-	case TYPE_PCI1720:
+	if (board->is_pci1720)
 		return pci1720_reset(dev);
-	default:
-		return pci171x_reset(dev);
-	}
+
+	return pci171x_reset(dev);
 }
 
 static int pci1710_auto_attach(struct comedi_device *dev,
 			       unsigned long context)
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-	const struct boardtype *this_board = NULL;
+	const struct boardtype *board = NULL;
 	struct pci1710_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret, subdev, n_subdevices;
 
 	if (context < ARRAY_SIZE(boardtypes))
-		this_board = &boardtypes[context];
-	if (!this_board)
+		board = &boardtypes[context];
+	if (!board)
 		return -ENODEV;
-	dev->board_ptr = this_board;
-	dev->board_name = this_board->name;
+	dev->board_ptr = board;
+	dev->board_name = board->name;
 
 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
@@ -1114,15 +979,13 @@
 	dev->iobase = pci_resource_start(pcidev, 2);
 
 	n_subdevices = 0;
-	if (this_board->n_aichan)
+	if (board->n_aichan)
 		n_subdevices++;
-	if (this_board->n_aochan)
+	if (board->has_ao)
 		n_subdevices++;
-	if (this_board->n_dichan)
-		n_subdevices++;
-	if (this_board->n_dochan)
-		n_subdevices++;
-	if (this_board->n_counter)
+	if (board->has_di_do)
+		n_subdevices += 2;
+	if (board->has_counter)
 		n_subdevices++;
 
 	ret = comedi_alloc_subdevices(dev, n_subdevices);
@@ -1131,7 +994,7 @@
 
 	pci1710_reset(dev);
 
-	if (this_board->have_irq && pcidev->irq) {
+	if (board->has_irq && pcidev->irq) {
 		ret = request_irq(pcidev->irq, interrupt_service_pci1710,
 				  IRQF_SHARED, dev->board_name, dev);
 		if (ret == 0)
@@ -1140,84 +1003,92 @@
 
 	subdev = 0;
 
-	if (this_board->n_aichan) {
+	if (board->n_aichan) {
 		s = &dev->subdevices[subdev];
-		s->type = COMEDI_SUBD_AI;
-		s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
-		if (this_board->n_aichand)
-			s->subdev_flags |= SDF_DIFF;
-		s->n_chan = this_board->n_aichan;
-		s->maxdata = this_board->ai_maxdata;
-		s->range_table = this_board->rangelist_ai;
-		s->insn_read = pci171x_insn_read_ai;
+		s->type		= COMEDI_SUBD_AI;
+		s->subdev_flags	= SDF_READABLE | SDF_COMMON | SDF_GROUND;
+		if (board->has_diff_ai)
+			s->subdev_flags	|= SDF_DIFF;
+		s->n_chan	= board->n_aichan;
+		s->maxdata	= 0x0fff;
+		s->range_table	= board->rangelist_ai;
+		s->insn_read	= pci171x_ai_insn_read;
 		if (dev->irq) {
 			dev->read_subdev = s;
-			s->subdev_flags |= SDF_CMD_READ;
-			s->len_chanlist = s->n_chan;
-			s->do_cmdtest = pci171x_ai_cmdtest;
-			s->do_cmd = pci171x_ai_cmd;
-			s->cancel = pci171x_ai_cancel;
+			s->subdev_flags	|= SDF_CMD_READ;
+			s->len_chanlist	= s->n_chan;
+			s->do_cmdtest	= pci171x_ai_cmdtest;
+			s->do_cmd	= pci171x_ai_cmd;
+			s->cancel	= pci171x_ai_cancel;
 		}
 		subdev++;
 	}
 
-	if (this_board->n_aochan) {
+	if (board->has_ao) {
 		s = &dev->subdevices[subdev];
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-		s->n_chan = this_board->n_aochan;
-		s->maxdata = this_board->ao_maxdata;
-		s->len_chanlist = this_board->n_aochan;
-		s->range_table = this_board->rangelist_ao;
-		switch (this_board->cardtype) {
-		case TYPE_PCI1720:
-			s->insn_write = pci1720_insn_write_ao;
-			break;
-		default:
-			s->insn_write = pci171x_insn_write_ao;
-			break;
+		s->type		= COMEDI_SUBD_AO;
+		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+		s->maxdata	= 0x0fff;
+		if (board->is_pci1720) {
+			s->n_chan	= 4;
+			s->range_table	= &pci1720_ao_range;
+			s->insn_write	= pci1720_ao_insn_write;
+		} else {
+			s->n_chan	= 2;
+			s->range_table	= &pci171x_ao_range;
+			s->insn_write	= pci171x_ao_insn_write;
 		}
-		s->insn_read = pci171x_insn_read_ao;
+
+		ret = comedi_alloc_subdev_readback(s);
+		if (ret)
+			return ret;
+
+		/* initialize the readback values to match the board reset */
+		if (board->is_pci1720) {
+			int i;
+
+			for (i = 0; i < s->n_chan; i++)
+				s->readback[i] = 0x0800;
+		}
+
 		subdev++;
 	}
 
-	if (this_board->n_dichan) {
+	if (board->has_di_do) {
 		s = &dev->subdevices[subdev];
-		s->type = COMEDI_SUBD_DI;
-		s->subdev_flags = SDF_READABLE;
-		s->n_chan = this_board->n_dichan;
-		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dichan;
-		s->range_table = &range_digital;
-		s->insn_bits = pci171x_insn_bits_di;
+		s->type		= COMEDI_SUBD_DI;
+		s->subdev_flags	= SDF_READABLE;
+		s->n_chan	= 16;
+		s->maxdata	= 1;
+		s->range_table	= &range_digital;
+		s->insn_bits	= pci171x_di_insn_bits;
+		subdev++;
+
+		s = &dev->subdevices[subdev];
+		s->type		= COMEDI_SUBD_DO;
+		s->subdev_flags	= SDF_WRITABLE;
+		s->n_chan	= 16;
+		s->maxdata	= 1;
+		s->range_table	= &range_digital;
+		s->insn_bits	= pci171x_do_insn_bits;
 		subdev++;
 	}
 
-	if (this_board->n_dochan) {
+	if (board->has_counter) {
 		s = &dev->subdevices[subdev];
-		s->type = COMEDI_SUBD_DO;
-		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = this_board->n_dochan;
-		s->maxdata = 1;
-		s->len_chanlist = this_board->n_dochan;
-		s->range_table = &range_digital;
-		s->insn_bits = pci171x_insn_bits_do;
+		s->type		= COMEDI_SUBD_COUNTER;
+		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+		s->n_chan	= 1;
+		s->maxdata	= 0xffff;
+		s->range_table	= &range_unknown;
+		s->insn_read	= pci171x_counter_insn_read;
+		s->insn_write	= pci171x_counter_insn_write;
+		s->insn_config	= pci171x_counter_insn_config;
 		subdev++;
 	}
 
-	if (this_board->n_counter) {
-		s = &dev->subdevices[subdev];
-		s->type = COMEDI_SUBD_COUNTER;
-		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-		s->n_chan = this_board->n_counter;
-		s->len_chanlist = this_board->n_counter;
-		s->maxdata = 0xffff;
-		s->range_table = &range_unknown;
-		s->insn_read = pci171x_insn_counter_read;
-		s->insn_write = pci171x_insn_counter_write;
-		s->insn_config = pci171x_insn_counter_config;
-		subdev++;
-	}
+	/* max_samples is half the FIFO size (2 bytes/sample) */
+	devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
 
 	return 0;
 }
@@ -1312,5 +1183,5 @@
 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 65f854e..f1945be 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -20,7 +20,7 @@
  * Driver: adv_pci1723
  * Description: Advantech PCI-1723
  * Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk>
- * Devices: (Advantech) PCI-1723 [adv_pci1723]
+ * Devices: [Advantech] PCI-1723 (adv_pci1723)
  * Updated: Mon, 14 Apr 2008 15:12:56 +0100
  * Status: works
  *
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index a8d2840..a3573ea 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -22,7 +22,7 @@
 /*
  * Driver: adv_pci1724
  * Description: Advantech PCI-1724U
- * Devices: (Advantech) PCI-1724U [adv_pci1724]
+ * Devices: [Advantech] PCI-1724U (adv_pci1724)
  * Author: Frank Mori Hess <fmh6jj@gmail.com>
  * Updated: 2013-02-09
  * Status: works
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 7b5ed43..1c7b325 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -1,48 +1,155 @@
 /*
-
-    comedi/drivers/aio_iiro_16.c
-
-    Driver for Access I/O Products PC-104 AIO-IIRO-16 Digital I/O board
-    Copyright (C) 2006 C&C Technologies, 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.
-*/
+ * aio_iiro_16.c
+ * Comedi driver for Access I/O Products 104-IIRO-16 board
+ * Copyright (C) 2006 C&C Technologies, 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.
+ */
 
 /*
-
-Driver: aio_iiro_16
-Description: Access I/O Products PC-104 IIRO16 Relay And Isolated Input Board
-Author: Zachary Ware <zach.ware@cctechnol.com>
-Devices:
- [Access I/O] PC-104 AIO12-8
-Status: experimental
-
-Configuration Options:
-  [0] - I/O port base address
-
-*/
+ * Driver: aio_iiro_16
+ * Description: Access I/O Products PC/104 Isolated Input/Relay Output Board
+ * Author: Zachary Ware <zach.ware@cctechnol.com>
+ * Devices: [Access I/O] 104-IIRO-16 (aio_iiro_16)
+ * Status: experimental
+ *
+ * Configuration Options:
+ *   [0] - I/O port base address
+ *   [1] - IRQ (optional)
+ *
+ * The board supports interrupts on change of state of the digital inputs.
+ * The sample data returned by the async command indicates which inputs
+ * changed state and the current state of the inputs:
+ *
+ *	Bit 23 - IRQ Enable (1) / Disable (0)
+ *	Bit 17 - Input 8-15 Changed State (1 = Changed, 0 = No Change)
+ *	Bit 16 - Input 0-7 Changed State (1 = Changed, 0 = No Change)
+ *	Bit 15 - Digital input 15
+ *	...
+ *	Bit 0  - Digital input 0
+ */
 
 #include <linux/module.h>
+#include <linux/interrupt.h>
+
 #include "../comedidev.h"
 
-#define AIO_IIRO_16_RELAY_0_7	0x00
-#define AIO_IIRO_16_INPUT_0_7	0x01
-#define AIO_IIRO_16_IRQ		0x02
-#define AIO_IIRO_16_RELAY_8_15	0x04
-#define AIO_IIRO_16_INPUT_8_15	0x05
+#include "comedi_fc.h"
 
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data)
+#define AIO_IIRO_16_RELAY_0_7		0x00
+#define AIO_IIRO_16_INPUT_0_7		0x01
+#define AIO_IIRO_16_IRQ			0x02
+#define AIO_IIRO_16_RELAY_8_15		0x04
+#define AIO_IIRO_16_INPUT_8_15		0x05
+#define AIO_IIRO_16_STATUS		0x07
+#define AIO_IIRO_16_STATUS_IRQE		BIT(7)
+#define AIO_IIRO_16_STATUS_INPUT_8_15	BIT(1)
+#define AIO_IIRO_16_STATUS_INPUT_0_7	BIT(0)
+
+static unsigned int aio_iiro_16_read_inputs(struct comedi_device *dev)
+{
+	unsigned int val;
+
+	val = inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
+	val |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+
+	return val;
+}
+
+static irqreturn_t aio_iiro_16_cos(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	struct comedi_subdevice *s = dev->read_subdev;
+	unsigned int status;
+	unsigned int val;
+
+	status = inb(dev->iobase + AIO_IIRO_16_STATUS);
+	if (!(status & AIO_IIRO_16_STATUS_IRQE))
+		return IRQ_NONE;
+
+	val = aio_iiro_16_read_inputs(dev);
+	val |= (status << 16);
+
+	comedi_buf_write_samples(s, &val, 1);
+	comedi_handle_events(dev, s);
+
+	return IRQ_HANDLED;
+}
+
+static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
+{
+	if (enable)
+		inb(dev->iobase + AIO_IIRO_16_IRQ);
+	else
+		outb(0, dev->iobase + AIO_IIRO_16_IRQ);
+}
+
+static int aio_iiro_16_cos_cancel(struct comedi_device *dev,
+				  struct comedi_subdevice *s)
+{
+	aio_iiro_enable_irq(dev, false);
+
+	return 0;
+}
+
+static int aio_iiro_16_cos_cmd(struct comedi_device *dev,
+			       struct comedi_subdevice *s)
+{
+	aio_iiro_enable_irq(dev, true);
+
+	return 0;
+}
+
+static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev,
+				   struct comedi_subdevice *s,
+				   struct comedi_cmd *cmd)
+{
+	int err = 0;
+
+	/* Step 1 : check if triggers are trivially valid */
+
+	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+	if (err)
+		return 1;
+
+	/* Step 2a : make sure trigger sources are unique */
+	/* Step 2b : and mutually compatible */
+
+	/* Step 3: check if arguments are trivially valid */
+
+	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+	if (err)
+		return 3;
+
+	/* Step 4: fix up any arguments */
+
+	/* Step 5: check channel list if it exists */
+
+	return 0;
+}
+
+static int aio_iiro_16_do_insn_bits(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
 {
 	if (comedi_dio_update_state(s, data)) {
 		outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
@@ -55,14 +162,12 @@
 	return insn->n;
 }
 
-static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
-					  struct comedi_subdevice *s,
-					  struct comedi_insn *insn,
-					  unsigned int *data)
+static int aio_iiro_16_di_insn_bits(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
 {
-	data[1] = 0;
-	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
-	data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+	data[1] = aio_iiro_16_read_inputs(dev);
 
 	return insn->n;
 }
@@ -77,25 +182,52 @@
 	if (ret)
 		return ret;
 
+	aio_iiro_enable_irq(dev, false);
+
+	/*
+	 * Digital input change of state interrupts are optionally supported
+	 * using IRQ 2-7, 10-12, 14, or 15.
+	 */
+	if ((1 << it->options[1]) & 0xdcfc) {
+		ret = request_irq(it->options[1], aio_iiro_16_cos, 0,
+				  dev->board_name, dev);
+		if (ret == 0)
+			dev->irq = it->options[1];
+	}
+
 	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
 		return ret;
 
+	/* Digital Output subdevice */
 	s = &dev->subdevices[0];
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = aio_iiro_16_dio_insn_bits_write;
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= aio_iiro_16_do_insn_bits;
 
+	/* get the initial state of the relays */
+	s->state = inb(dev->iobase + AIO_IIRO_16_RELAY_0_7) |
+		   (inb(dev->iobase + AIO_IIRO_16_RELAY_8_15) << 8);
+
+	/* Digital Input subdevice */
 	s = &dev->subdevices[1];
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = 16;
-	s->maxdata = 1;
-	s->range_table = &range_digital;
-	s->insn_bits = aio_iiro_16_dio_insn_bits_read;
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 16;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= aio_iiro_16_di_insn_bits;
+	if (dev->irq) {
+		dev->read_subdev = s;
+		s->subdev_flags	|= SDF_CMD_READ | SDF_LSAMPL;
+		s->len_chanlist	= 1;
+		s->do_cmdtest	= aio_iiro_16_cos_cmdtest;
+		s->do_cmd	= aio_iiro_16_cos_cmd;
+		s->cancel	= aio_iiro_16_cos_cancel;
+	}
 
 	return 0;
 }
@@ -109,5 +241,5 @@
 module_comedi_driver(aio_iiro_16_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Access I/O Products 104-IIRO-16 board");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index e7cb703..1a109e3 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -22,7 +22,7 @@
  * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
  * Author: Dan Block
  * Status: unknown
- * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio]
+ * Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
  * Updated: Sun Nov 20 20:18:34 EST 2005
  *
  * Configuration Options:
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 0a48d2a..1079b6c 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -38,10 +38,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
 
 #include "comedi_fc.h"
 #include "8253.h"
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 669b170..dd0c65a 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -1355,7 +1355,7 @@
 		outw(devpriv->adc_fifo_bits | LADFUL,
 		     devpriv->control_status + INT_ADCFIFO);
 		spin_unlock_irqrestore(&dev->spinlock, flags);
-		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		async->events |= COMEDI_CB_ERROR;
 	}
 
 	comedi_handle_events(dev, s);
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index eddb7ac..5b43e4e 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -439,6 +439,29 @@
 	}
 };
 
+static const uint8_t ai_range_code_64xx[8] = {
+	0x0, 0x1, 0x2, 0x3,	/* bipolar 10, 5, 2,5, 1.25 */
+	0x8, 0x9, 0xa, 0xb	/* unipolar 10, 5, 2.5, 1.25 */
+};
+
+/* analog input ranges for 64-Mx boards */
+static const struct comedi_lrange ai_ranges_64_mx = {
+	7, {
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
+		BIP_RANGE(0.625),
+		UNI_RANGE(5),
+		UNI_RANGE(2.5),
+		UNI_RANGE(1.25)
+	}
+};
+
+static const uint8_t ai_range_code_64_mx[7] = {
+	0x0, 0x1, 0x2, 0x3,	/* bipolar 5, 2.5, 1.25, 0.625 */
+	0x9, 0xa, 0xb		/* unipolar 5, 2.5, 1.25 */
+};
+
 /* analog input ranges for 60xx boards */
 static const struct comedi_lrange ai_ranges_60xx = {
 	4, {
@@ -449,6 +472,10 @@
 	}
 };
 
+static const uint8_t ai_range_code_60xx[4] = {
+	0x0, 0x1, 0x4, 0x7	/* bipolar 10, 5, 0.5, 0.05 */
+};
+
 /* analog input ranges for 6030, etc boards */
 static const struct comedi_lrange ai_ranges_6030 = {
 	14, {
@@ -469,6 +496,11 @@
 	}
 };
 
+static const uint8_t ai_range_code_6030[14] = {
+	0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */
+	0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf  /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */
+};
+
 /* analog input ranges for 6052, etc boards */
 static const struct comedi_lrange ai_ranges_6052 = {
 	15, {
@@ -490,6 +522,11 @@
 	}
 };
 
+static const uint8_t ai_range_code_6052[15] = {
+	0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,	/* bipolar 10 ... 0.05 */
+	0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf	/* unipolar 10 ... 0.1 */
+};
+
 /* analog input ranges for 4020 board */
 static const struct comedi_lrange ai_ranges_4020 = {
 	2, {
@@ -593,6 +630,7 @@
 	int ai_bits;		/*  analog input resolution */
 	int ai_speed;		/*  fastest conversion period in ns */
 	const struct comedi_lrange *ai_range_table;
+	const uint8_t *ai_range_code;
 	int ao_nchan;		/*  number of analog out channels */
 	int ao_bits;		/*  analog output resolution */
 	int ao_scan_speed;	/*  analog output scan speed */
@@ -651,6 +689,7 @@
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
 		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_code	= ai_range_code_64xx,
 		.ao_range_table	= &ao_ranges_64xx,
 		.ao_range_code	= ao_range_code_64xx,
 		.ai_fifo	= &ai_fifo_64xx,
@@ -666,6 +705,7 @@
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
 		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_code	= ai_range_code_64xx,
 		.ao_range_table	= &ao_ranges_64xx,
 		.ao_range_code	= ao_range_code_64xx,
 		.ai_fifo	= &ai_fifo_64xx,
@@ -680,7 +720,8 @@
 		.ao_bits	= 16,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ao_range_table	= &ao_ranges_64xx,
 		.ao_range_code	= ao_range_code_64xx,
 		.ai_fifo	= &ai_fifo_64xx,
@@ -695,7 +736,8 @@
 		.ao_bits	= 16,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ao_range_table	= &ao_ranges_64xx,
 		.ao_range_code	= ao_range_code_64xx,
 		.ai_fifo	= &ai_fifo_64xx,
@@ -710,7 +752,8 @@
 		.ao_bits	= 16,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ao_range_table	= &ao_ranges_64xx,
 		.ao_range_code	= ao_range_code_64xx,
 		.ai_fifo	= &ai_fifo_64xx,
@@ -725,6 +768,7 @@
 		.ao_bits	= 16,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -740,6 +784,7 @@
 		.ao_scan_speed	= 100000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -754,6 +799,7 @@
 		.ao_scan_speed	= 100000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -769,6 +815,7 @@
 		.ao_scan_speed	= 100000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -784,6 +831,7 @@
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6030,
+		.ai_range_code	= ai_range_code_6030,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -799,6 +847,7 @@
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6030,
+		.ai_range_code	= ai_range_code_6030,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -812,6 +861,7 @@
 		.ao_nchan	= 0,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6030,
+		.ai_range_code	= ai_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
 		.has_8255	= 0,
 	},
@@ -823,6 +873,7 @@
 		.ao_nchan	= 0,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6030,
+		.ai_range_code	= ai_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
 		.has_8255	= 0,
 	},
@@ -835,6 +886,7 @@
 		.ao_scan_speed	= 0,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
 		.has_8255	= 0,
 	},
@@ -848,6 +900,7 @@
 		.ao_scan_speed	= 100000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -863,6 +916,7 @@
 		.ao_scan_speed	= 100000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_60xx,
+		.ai_range_code	= ai_range_code_60xx,
 		.ao_range_table	= &range_bipolar10,
 		.ao_range_code	= ao_range_code_60xx,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -878,6 +932,7 @@
 		.ao_scan_speed	= 1000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6052,
+		.ai_range_code	= ai_range_code_6052,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -893,6 +948,7 @@
 		.ao_scan_speed	= 3333,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6052,
+		.ai_range_code	= ai_range_code_6052,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -908,6 +964,7 @@
 		.ao_scan_speed	= 1000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6052,
+		.ai_range_code	= ai_range_code_6052,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -923,6 +980,7 @@
 		.ao_scan_speed	= 1000,
 		.layout		= LAYOUT_60XX,
 		.ai_range_table	= &ai_ranges_6052,
+		.ai_range_code	= ai_range_code_6052,
 		.ao_range_table	= &ao_ranges_6030,
 		.ao_range_code	= ao_range_code_6030,
 		.ai_fifo	= &ai_fifo_60xx,
@@ -957,6 +1015,7 @@
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
 		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_code	= ai_range_code_64xx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -968,7 +1027,8 @@
 		.ao_nchan	= 0,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -980,7 +1040,8 @@
 		.ao_nchan	= 0,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -992,7 +1053,8 @@
 		.ao_nchan	= 0,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -1004,7 +1066,8 @@
 		.ao_nchan	= 2,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -1016,7 +1079,8 @@
 		.ao_nchan	= 2,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -1028,7 +1092,8 @@
 		.ao_nchan	= 2,
 		.ao_scan_speed	= 10000,
 		.layout		= LAYOUT_64XX,
-		.ai_range_table	= &ai_ranges_64xx,
+		.ai_range_table	= &ai_ranges_64_mx,
+		.ai_range_code	= ai_range_code_64_mx,
 		.ai_fifo	= ai_fifo_64xx,
 		.has_8255	= 1,
 	},
@@ -1115,45 +1180,8 @@
 				       unsigned int range_index)
 {
 	const struct pcidas64_board *thisboard = dev->board_ptr;
-	const struct comedi_krange *range =
-		&thisboard->ai_range_table->range[range_index];
-	unsigned int bits = 0;
 
-	switch (range->max) {
-	case 10000000:
-		bits = 0x000;
-		break;
-	case 5000000:
-		bits = 0x100;
-		break;
-	case 2000000:
-	case 2500000:
-		bits = 0x200;
-		break;
-	case 1000000:
-	case 1250000:
-		bits = 0x300;
-		break;
-	case 500000:
-		bits = 0x400;
-		break;
-	case 200000:
-	case 250000:
-		bits = 0x500;
-		break;
-	case 100000:
-		bits = 0x600;
-		break;
-	case 50000:
-		bits = 0x700;
-		break;
-	default:
-		dev_err(dev->class_dev, "bug! in %s\n", __func__);
-		break;
-	}
-	if (range->min == 0)
-		bits += 0x900;
-	return bits;
+	return thisboard->ai_range_code[range_index] << 8;
 }
 
 static unsigned int hw_revision(const struct comedi_device *dev,
@@ -2776,7 +2804,7 @@
 	/*  check for fifo overrun */
 	if (status & ADC_OVERRUN_BIT) {
 		dev_err(dev->class_dev, "fifo overrun\n");
-		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		async->events |= COMEDI_CB_ERROR;
 	}
 	/*  spin lock makes sure no one else changes plx dma control reg */
 	spin_lock_irqsave(&dev->spinlock, flags);
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 01875d7..2b2cfcd 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -22,12 +22,10 @@
 /*
  * Driver: cb_pcidda
  * Description: MeasurementComputing PCI-DDA series
- * Devices: (Measurement Computing) PCI-DDA08/12 [pci-dda08/12]
- *	    (Measurement Computing) PCI-DDA04/12 [pci-dda04/12]
- *	    (Measurement Computing) PCI-DDA02/12 [pci-dda02/12]
- *	    (Measurement Computing) PCI-DDA08/16 [pci-dda08/16]
- *	    (Measurement Computing) PCI-DDA04/16 [pci-dda04/16]
- *	    (Measurement Computing) PCI-DDA02/16 [pci-dda02/16]
+ * Devices: [Measurement Computing] PCI-DDA08/12 (pci-dda08/12),
+ *   PCI-DDA04/12 (pci-dda04/12), PCI-DDA02/12 (pci-dda02/12),
+ *   PCI-DDA08/16 (pci-dda08/16), PCI-DDA04/16 (pci-dda04/16),
+ *   PCI-DDA02/16 (pci-dda02/16)
  * Author: Ivan Martinez <ivanmr@altavista.com>
  *	   Frank Mori Hess <fmhess@users.sourceforge.net>
  * Status: works
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 85b2f4a..221d381 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -261,6 +261,7 @@
 			{
 				/* Append dev:subdev to devpriv->name */
 				char buf[20];
+
 				snprintf(buf, sizeof(buf), "%u:%u ",
 					 bdev->minor, bdev->subdev);
 				strlcat(devpriv->name, buf,
diff --git a/drivers/staging/comedi/drivers/comedi_isadma.c b/drivers/staging/comedi/drivers/comedi_isadma.c
new file mode 100644
index 0000000..dbdea71
--- /dev/null
+++ b/drivers/staging/comedi/drivers/comedi_isadma.c
@@ -0,0 +1,262 @@
+/*
+ * COMEDI ISA DMA support functions
+ * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.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/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
+
+/**
+ * comedi_isadma_program - program and enable an ISA DMA transfer
+ * @desc:	the ISA DMA cookie to program and enable
+ */
+void comedi_isadma_program(struct comedi_isadma_desc *desc)
+{
+	unsigned long flags;
+
+	flags = claim_dma_lock();
+	clear_dma_ff(desc->chan);
+	set_dma_mode(desc->chan, desc->mode);
+	set_dma_addr(desc->chan, desc->hw_addr);
+	set_dma_count(desc->chan, desc->size);
+	enable_dma(desc->chan);
+	release_dma_lock(flags);
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_program);
+
+/**
+ * comedi_isadma_disable - disable the ISA DMA channel
+ * @dma_chan:	the DMA channel to disable
+ *
+ * Returns the residue (remaining bytes) left in the DMA transfer.
+ */
+unsigned int comedi_isadma_disable(unsigned int dma_chan)
+{
+	unsigned long flags;
+	unsigned int residue;
+
+	flags = claim_dma_lock();
+	disable_dma(dma_chan);
+	residue = get_dma_residue(dma_chan);
+	release_dma_lock(flags);
+
+	return residue;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_disable);
+
+/**
+ * comedi_isadma_disable_on_sample - disable the ISA DMA channel
+ * @dma_chan:	the DMA channel to disable
+ * @size:	the sample size (in bytes)
+ *
+ * Returns the residue (remaining bytes) left in the DMA transfer.
+ */
+unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
+					     unsigned int size)
+{
+	int stalled = 0;
+	unsigned long flags;
+	unsigned int residue;
+	unsigned int new_residue;
+
+	residue = comedi_isadma_disable(dma_chan);
+	while (residue % size) {
+		/* residue is a partial sample, enable DMA to allow more data */
+		flags = claim_dma_lock();
+		enable_dma(dma_chan);
+		release_dma_lock(flags);
+
+		udelay(2);
+		new_residue = comedi_isadma_disable(dma_chan);
+
+		/* is DMA stalled? */
+		if (new_residue == residue) {
+			stalled++;
+			if (stalled > 10)
+				break;
+		}
+		residue = new_residue;
+		stalled = 0;
+	}
+	return residue;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_disable_on_sample);
+
+/**
+ * comedi_isadma_poll - poll the current DMA transfer
+ * @dma:	the ISA DMA to poll
+ *
+ * Returns the position (in bytes) of the current DMA transfer.
+ */
+unsigned int comedi_isadma_poll(struct comedi_isadma *dma)
+{
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned long flags;
+	unsigned int result;
+	unsigned int result1;
+
+	flags = claim_dma_lock();
+	clear_dma_ff(desc->chan);
+	if (!isa_dma_bridge_buggy)
+		disable_dma(desc->chan);
+	result = get_dma_residue(desc->chan);
+	/*
+	 * Read the counter again and choose higher value in order to
+	 * avoid reading during counter lower byte roll over if the
+	 * isa_dma_bridge_buggy is set.
+	 */
+	result1 = get_dma_residue(desc->chan);
+	if (!isa_dma_bridge_buggy)
+		enable_dma(desc->chan);
+	release_dma_lock(flags);
+
+	if (result < result1)
+		result = result1;
+	if (result >= desc->size || result == 0)
+		return 0;
+	else
+		return desc->size - result;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_poll);
+
+/**
+ * comedi_isadma_set_mode - set the ISA DMA transfer direction
+ * @desc:	the ISA DMA cookie to set
+ * @dma_dir:	the DMA direction
+ */
+void comedi_isadma_set_mode(struct comedi_isadma_desc *desc, char dma_dir)
+{
+	desc->mode = (dma_dir == COMEDI_ISADMA_READ) ? DMA_MODE_READ
+						     : DMA_MODE_WRITE;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_set_mode);
+
+/**
+ * comedi_isadma_alloc - allocate and initialize the ISA DMA
+ * @dev:	comedi_device struct
+ * @n_desc:	the number of cookies to allocate
+ * @dma_chan:	DMA channel for the first cookie
+ * @dma_chan2:	DMA channel for the second cookie
+ * @maxsize:	the size of the buffer to allocate for each cookie
+ * @dma_dir:	the DMA direction
+ *
+ * Returns the allocated and initialized ISA DMA or NULL if anything fails.
+ */
+struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev,
+					  int n_desc, unsigned int dma_chan1,
+					  unsigned int dma_chan2,
+					  unsigned int maxsize, char dma_dir)
+{
+	struct comedi_isadma *dma = NULL;
+	struct comedi_isadma_desc *desc;
+	unsigned int dma_chans[2];
+	int i;
+
+	if (n_desc < 1 || n_desc > 2)
+		goto no_dma;
+
+	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		goto no_dma;
+
+	desc = kcalloc(n_desc, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		goto no_dma;
+	dma->desc = desc;
+	dma->n_desc = n_desc;
+
+	dma_chans[0] = dma_chan1;
+	if (dma_chan2 == 0 || dma_chan2 == dma_chan1)
+		dma_chans[1] = dma_chan1;
+	else
+		dma_chans[1] = dma_chan2;
+
+	if (request_dma(dma_chans[0], dev->board_name))
+		goto no_dma;
+	dma->chan = dma_chans[0];
+	if (dma_chans[1] != dma_chans[0]) {
+		if (request_dma(dma_chans[1], dev->board_name))
+			goto no_dma;
+	}
+	dma->chan2 = dma_chans[1];
+
+	for (i = 0; i < n_desc; i++) {
+		desc = &dma->desc[i];
+		desc->chan = dma_chans[i];
+		desc->maxsize = maxsize;
+		desc->virt_addr = dma_alloc_coherent(NULL, desc->maxsize,
+						     &desc->hw_addr,
+						     GFP_KERNEL);
+		if (!desc->virt_addr)
+			goto no_dma;
+		comedi_isadma_set_mode(desc, dma_dir);
+	}
+
+	return dma;
+
+no_dma:
+	comedi_isadma_free(dma);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_alloc);
+
+/**
+ * comedi_isadma_free - free the ISA DMA
+ * @dma:	the ISA DMA to free
+ */
+void comedi_isadma_free(struct comedi_isadma *dma)
+{
+	struct comedi_isadma_desc *desc;
+	int i;
+
+	if (!dma)
+		return;
+
+	if (dma->desc) {
+		for (i = 0; i < dma->n_desc; i++) {
+			desc = &dma->desc[i];
+			if (desc->virt_addr)
+				dma_free_coherent(NULL, desc->maxsize,
+						desc->virt_addr, desc->hw_addr);
+		}
+		kfree(dma->desc);
+	}
+	if (dma->chan2 && dma->chan2 != dma->chan)
+		free_dma(dma->chan2);
+	if (dma->chan)
+		free_dma(dma->chan);
+	kfree(dma);
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_free);
+
+static int __init comedi_isadma_init(void)
+{
+	return 0;
+}
+module_init(comedi_isadma_init);
+
+static void __exit comedi_isadma_exit(void)
+{
+}
+module_exit(comedi_isadma_exit);
+
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi ISA DMA support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_isadma.h b/drivers/staging/comedi/drivers/comedi_isadma.h
new file mode 100644
index 0000000..c7c524f
--- /dev/null
+++ b/drivers/staging/comedi/drivers/comedi_isadma.h
@@ -0,0 +1,116 @@
+/*
+ * COMEDI ISA DMA support functions
+ * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.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.
+ */
+
+#ifndef _COMEDI_ISADMA_H
+#define _COMEDI_ISADMA_H
+
+/*
+ * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_
+ * defines are not available.
+ */
+#define COMEDI_ISADMA_READ	0
+#define COMEDI_ISADMA_WRITE	1
+
+/**
+ * struct comedi_isadma_desc - cookie for ISA DMA
+ * @virt_addr:	virtual address of buffer
+ * @hw_addr:	hardware (bus) address of buffer
+ * @chan:	DMA channel
+ * @maxsize:	allocated size of buffer (in bytes)
+ * @size:	transfer size (in bytes)
+ * @mode:	DMA_MODE_READ or DMA_MODE_WRITE
+ */
+struct comedi_isadma_desc {
+	void *virt_addr;
+	dma_addr_t hw_addr;
+	unsigned int chan;
+	unsigned int maxsize;
+	unsigned int size;
+	char mode;
+};
+
+/**
+ * struct comedi_isadma - ISA DMA data
+ * @desc:	cookie for each DMA buffer
+ * @n_desc:	the number of cookies
+ * @cur_dma:	the current cookie in use
+ * @chan:	the first DMA channel requested
+ * @chan2:	the second DMA channel requested
+ */
+struct comedi_isadma {
+	struct comedi_isadma_desc *desc;
+	int n_desc;
+	int cur_dma;
+	unsigned int chan;
+	unsigned int chan2;
+};
+
+#if IS_ENABLED(CONFIG_ISA_DMA_API)
+
+void comedi_isadma_program(struct comedi_isadma_desc *);
+unsigned int comedi_isadma_disable(unsigned int dma_chan);
+unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
+					     unsigned int size);
+unsigned int comedi_isadma_poll(struct comedi_isadma *);
+void comedi_isadma_set_mode(struct comedi_isadma_desc *, char dma_dir);
+
+struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *,
+					  int n_desc, unsigned int dma_chan1,
+					  unsigned int dma_chan2,
+					  unsigned int maxsize, char dma_dir);
+void comedi_isadma_free(struct comedi_isadma *);
+
+#else	/* !IS_ENABLED(CONFIG_ISA_DMA_API) */
+
+static inline void comedi_isadma_program(struct comedi_isadma_desc *desc)
+{
+}
+
+static inline unsigned int comedi_isadma_disable(unsigned int dma_chan)
+{
+	return 0;
+}
+
+static inline unsigned int
+comedi_isadma_disable_on_sample(unsigned int dma_chan, unsigned int size)
+{
+	return 0;
+}
+
+static inline unsigned int comedi_isadma_poll(struct comedi_isadma *dma)
+{
+	return 0;
+}
+
+static inline void comedi_isadma_set_mode(struct comedi_isadma_desc *desc,
+					  char dma_dir)
+{
+}
+
+static inline struct comedi_isadma *
+comedi_isadma_alloc(struct comedi_device *dev, int n_desc,
+		    unsigned int dma_chan1, unsigned int dma_chan2,
+		    unsigned int maxsize, char dma_dir)
+{
+	return NULL;
+}
+
+static inline void comedi_isadma_free(struct comedi_isadma *dma)
+{
+}
+
+#endif	/* !IS_ENABLED(CONFIG_ISA_DMA_API) */
+
+#endif	/* #ifndef _COMEDI_ISADMA_H */
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 3bac903..ceef693 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -24,7 +24,7 @@
  * Description: Standard PC parallel port
  * Author: ds
  * Status: works in immediate mode
- * Devices: (standard) parallel port [comedi_parport]
+ * Devices: [standard] parallel port (comedi_parport)
  * Updated: Tue, 30 Apr 2002 21:11:45 -0700
  *
  * A cheap and easy way to get a few more digital I/O lines. Steal
diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c
index beb36c8..a6798ad 100644
--- a/drivers/staging/comedi/drivers/dac02.c
+++ b/drivers/staging/comedi/drivers/dac02.c
@@ -24,7 +24,7 @@
 /*
  * Driver: dac02
  * Description: Comedi driver for DAC02 compatible boards
- * Devices: (Keithley Metrabyte) DAC-02 [dac02]
+ * Devices: [Keithley Metrabyte] DAC-02 (dac02)
  * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
  * Updated: Tue, 11 Mar 2014 11:27:19 -0700
  * Status: unknown
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 20a9f0e..c78c0df 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -1,6 +1,6 @@
 /*
  *  comedi/drivers/das08.c
- *  comedi driver for common DAS08 support (used by ISA/PCI/PCMCIA drivers)
+ *  comedi module for common DAS08 support (used by ISA/PCI/PCMCIA drivers)
  *
  *  COMEDI - Linux Control and Measurement Device Interface
  *  Copyright (C) 2000 David A. Schleef <ds@schleef.org>
@@ -18,21 +18,6 @@
  *  GNU General Public License for more details.
  */
 
-/*
- * Driver: das08
- * Description: DAS-08 compatible boards
- * Devices: various, see das08_isa, das08_cs, and das08_pci drivers
- * Author: Warren Jasper, ds, Frank Hess
- * Updated: Fri, 31 Aug 2012 19:19:06 +0100
- * Status: works
- *
- * This driver is used by the das08_isa, das08_cs, and das08_pci
- * drivers to provide the common support for the DAS-08 hardware.
- *
- * The driver doesn't support asynchronous commands, since the
- * cheap das08 hardware doesn't really support them.
- */
-
 #include <linux/module.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index f3ccc2c..93fab68 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -41,10 +41,7 @@
 
 #include <linux/module.h>
 
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
 
 #include "das08.h"
 
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index e4ba268..2d9a31d 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -21,18 +21,12 @@
 /*
  * Driver: das08_isa
  * Description: DAS-08 ISA/PC-104 compatible boards
- * Devices: (Keithley Metrabyte) DAS08 [isa-das08],
- *	    (ComputerBoards) DAS08 [isa-das08]
- *	    (ComputerBoards) DAS08-PGM [das08-pgm]
- *	    (ComputerBoards) DAS08-PGH [das08-pgh]
- *	    (ComputerBoards) DAS08-PGL [das08-pgl]
- *	    (ComputerBoards) DAS08-AOH [das08-aoh]
- *	    (ComputerBoards) DAS08-AOL [das08-aol]
- *	    (ComputerBoards) DAS08-AOM [das08-aom]
- *	    (ComputerBoards) DAS08/JR-AO [das08/jr-ao]
- *	    (ComputerBoards) DAS08/JR-16-AO [das08jr-16-ao]
- *	    (ComputerBoards) PC104-DAS08 [pc104-das08]
- *	    (ComputerBoards) DAS08/JR/16 [das08jr/16]
+ * Devices: [Keithley Metrabyte] DAS08 (isa-das08),
+ *   [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
+ *   DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
+ *   DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
+ *   DAS08/JR-16-AO (das08jr-16-ao), PC104-DAS08 (pc104-das08),
+ *   DAS08/JR/16 (das08jr/16)
  * Author: Warren Jasper, ds, Frank Hess
  * Updated: Fri, 31 Aug 2012 19:19:06 +0100
  * Status: works
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 0987ce55..b2ea10b 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -21,7 +21,7 @@
 /*
  * Driver: das08_pci
  * Description: DAS-08 PCI compatible boards
- * Devices: (ComputerBoards) PCI-DAS08 [pci-das08]
+ * Devices: [ComputerBoards] PCI-DAS08 (pci-das08)
  * Author: Warren Jasper, ds, Frank Hess
  * Updated: Fri, 31 Aug 2012 19:19:06 +0100
  * Status: works
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 2436057..2c20311 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -22,28 +22,17 @@
  * Driver: das16
  * Description: DAS16 compatible boards
  * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
- * Devices: (Keithley Metrabyte) DAS-16 [das-16]
- *	    (Keithley Metrabyte) DAS-16G [das-16g]
- *	    (Keithley Metrabyte) DAS-16F [das-16f]
- *	    (Keithley Metrabyte) DAS-1201 [das-1201]
- *	    (Keithley Metrabyte) DAS-1202 [das-1202]
- *	    (Keithley Metrabyte) DAS-1401 [das-1401]
- *	    (Keithley Metrabyte) DAS-1402 [das-1402]
- *	    (Keithley Metrabyte) DAS-1601 [das-1601]
- *	    (Keithley Metrabyte) DAS-1602 [das-1602]
- *	    (ComputerBoards) PC104-DAS16/JR [pc104-das16jr]
- *	    (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16]
- *	    (ComputerBoards) CIO-DAS16 [cio-das16]
- *	    (ComputerBoards) CIO-DAS16F [cio-das16/f]
- *	    (ComputerBoards) CIO-DAS16/JR [cio-das16/jr]
- *	    (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16]
- *	    (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12]
- *	    (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12]
- *	    (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16]
- *	    (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12]
- *	    (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12]
- *	    (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16]
- *	    (ComputerBoards) CIO-DAS16/330 [cio-das16/330]
+ * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
+ *   DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
+ *   DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
+ *   DAS-1602 (das-1602),
+ *   [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
+ *   PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16),
+ *   CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr),
+ *   CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12),
+ *   CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
+ *   CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
+ *   CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
  * Status: works
  * Updated: 2003-10-12
  *
@@ -82,17 +71,14 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
 #include <linux/interrupt.h>
 
-#include <asm/dma.h>
-
 #include "../comedidev.h"
 
+#include "comedi_isadma.h"
+#include "comedi_fc.h"
 #include "8253.h"
 #include "8255.h"
-#include "comedi_fc.h"
 
 #define DAS16_DMA_SIZE 0xff00	/*  size in bytes of allocated dma buffer */
 
@@ -451,86 +437,37 @@
 }
 
 struct das16_private_struct {
+	struct comedi_isadma	*dma;
 	unsigned int		clockbase;
 	unsigned int		ctrl_reg;
-	unsigned long		adc_byte_count;
 	unsigned int		divisor1;
 	unsigned int		divisor2;
-	unsigned int		dma_chan;
-	uint16_t		*dma_buffer[2];
-	dma_addr_t		dma_buffer_addr[2];
-	unsigned int		current_buffer;
-	unsigned int		dma_transfer_size;
-	struct comedi_lrange	*user_ai_range_table;
-	struct comedi_lrange	*user_ao_range_table;
 	struct timer_list	timer;
-	short			timer_running;
 	unsigned long		extra_iobase;
 	unsigned int		can_burst:1;
+	unsigned int		timer_running:1;
 };
 
-static void das16_ai_enable(struct comedi_device *dev,
-			    unsigned int mode, unsigned int src)
+static void das16_ai_setup_dma(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       unsigned int unread_samples)
 {
 	struct das16_private_struct *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+	unsigned int nsamples;
 
-	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
-			       DAS16_CTRL_DMAE |
-			       DAS16_CTRL_PACING_MASK);
-	devpriv->ctrl_reg |= mode;
-
-	if (src == TRIG_EXT)
-		devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
-	else
-		devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
-	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
-}
-
-static void das16_ai_disable(struct comedi_device *dev)
-{
-	struct das16_private_struct *devpriv = dev->private;
-
-	/* disable interrupts, dma and pacer clocked conversions */
-	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
-			       DAS16_CTRL_DMAE |
-			       DAS16_CTRL_PACING_MASK);
-	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
-}
-
-/* the pc104-das16jr (at least) has problems if the dma
-	transfer is interrupted in the middle of transferring
-	a 16 bit sample, so this function takes care to get
-	an even transfer count after disabling dma
-	channel.
-*/
-static int disable_dma_on_even(struct comedi_device *dev)
-{
-	struct das16_private_struct *devpriv = dev->private;
-	static const int disable_limit = 100;
-	static const int enable_timeout = 100;
-	int residue;
-	int new_residue;
-	int i;
-	int j;
-
-	disable_dma(devpriv->dma_chan);
-	residue = get_dma_residue(devpriv->dma_chan);
-	for (i = 0; i < disable_limit && (residue % 2); ++i) {
-		enable_dma(devpriv->dma_chan);
-		for (j = 0; j < enable_timeout; ++j) {
-			udelay(2);
-			new_residue = get_dma_residue(devpriv->dma_chan);
-			if (new_residue != residue)
-				break;
-		}
-		disable_dma(devpriv->dma_chan);
-		residue = get_dma_residue(devpriv->dma_chan);
+	/*
+	 * Determine dma size based on the buffer size plus the number of
+	 * unread samples and the number of samples remaining in the command.
+	 */
+	nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+	if (nsamples > unread_samples) {
+		nsamples -= unread_samples;
+		desc->size = comedi_samples_to_bytes(s, nsamples);
+		comedi_isadma_program(desc);
 	}
-	if (i == disable_limit) {
-		dev_err(dev->class_dev,
-			"failed to get an even dma transfer, could be trouble\n");
-	}
-	return residue;
 }
 
 static void das16_interrupt(struct comedi_device *dev)
@@ -539,11 +476,12 @@
 	struct comedi_subdevice *s = dev->read_subdev;
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 	unsigned long spin_flags;
-	unsigned long dma_flags;
+	unsigned int residue;
+	unsigned int nbytes;
 	unsigned int nsamples;
-	int num_bytes, residue;
-	int buffer_index;
 
 	spin_lock_irqsave(&dev->spinlock, spin_flags);
 	if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
@@ -551,42 +489,36 @@
 		return;
 	}
 
-	dma_flags = claim_dma_lock();
-	clear_dma_ff(devpriv->dma_chan);
-	residue = disable_dma_on_even(dev);
+	/*
+	 * The pc104-das16jr (at least) has problems if the dma
+	 * transfer is interrupted in the middle of transferring
+	 * a 16 bit sample.
+	 */
+	residue = comedi_isadma_disable_on_sample(desc->chan,
+						  comedi_bytes_per_sample(s));
 
-	/*  figure out how many points to read */
-	if (residue > devpriv->dma_transfer_size) {
+	/* figure out how many samples to read */
+	if (residue > desc->size) {
 		dev_err(dev->class_dev, "residue > transfer size!\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
-		num_bytes = 0;
-	} else
-		num_bytes = devpriv->dma_transfer_size - residue;
-
-	if (cmd->stop_src == TRIG_COUNT &&
-					num_bytes >= devpriv->adc_byte_count) {
-		num_bytes = devpriv->adc_byte_count;
-		async->events |= COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
+		nbytes = 0;
+	} else {
+		nbytes = desc->size - residue;
 	}
+	nsamples = comedi_bytes_to_samples(s, nbytes);
 
-	buffer_index = devpriv->current_buffer;
-	devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
-	devpriv->adc_byte_count -= num_bytes;
-
-	/*  re-enable  dma */
-	if ((async->events & COMEDI_CB_EOA) == 0) {
-		set_dma_addr(devpriv->dma_chan,
-			     devpriv->dma_buffer_addr[devpriv->current_buffer]);
-		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
-		enable_dma(devpriv->dma_chan);
+	/* restart DMA if more samples are needed */
+	if (nsamples) {
+		dma->cur_dma = 1 - dma->cur_dma;
+		das16_ai_setup_dma(dev, s, nsamples);
 	}
-	release_dma_lock(dma_flags);
 
 	spin_unlock_irqrestore(&dev->spinlock, spin_flags);
 
-	nsamples = comedi_bytes_to_samples(s, num_bytes);
-	comedi_buf_write_samples(s, devpriv->dma_buffer[buffer_index],
-				 nsamples);
+	comedi_buf_write_samples(s, desc->virt_addr, nsamples);
+
+	if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
+		async->events |= COMEDI_CB_EOA;
 
 	comedi_handle_events(dev, s);
 }
@@ -605,6 +537,29 @@
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 }
 
+static void das16_ai_set_mux_range(struct comedi_device *dev,
+				   unsigned int first_chan,
+				   unsigned int last_chan,
+				   unsigned int range)
+{
+	const struct das16_board *board = dev->board_ptr;
+
+	/* set multiplexer */
+	outb(first_chan | (last_chan << 4), dev->iobase + DAS16_MUX_REG);
+
+	/* some boards do not have programmable gain */
+	if (board->ai_pg == das16_pg_none)
+		return;
+
+	/*
+	 * Set gain (this is also burst rate register but according to
+	 * computer boards manual, burst rate does nothing, even on
+	 * keithley cards).
+	 */
+	outb((das16_gainlists[board->ai_pg])[range],
+	     dev->iobase + DAS16_GAIN_REG);
+}
+
 static int das16_ai_check_chanlist(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
 				   struct comedi_cmd *cmd)
@@ -755,13 +710,15 @@
 
 static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	const struct das16_board *board = dev->board_ptr;
 	struct das16_private_struct *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
+	unsigned int first_chan = CR_CHAN(cmd->chanlist[0]);
+	unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
+	unsigned int range = CR_RANGE(cmd->chanlist[0]);
 	unsigned int byte;
 	unsigned long flags;
-	int range;
 
 	if (cmd->flags & CMDF_PRIORITY) {
 		dev_err(dev->class_dev,
@@ -769,24 +726,11 @@
 		return -1;
 	}
 
-	devpriv->adc_byte_count = cmd->stop_arg * comedi_bytes_per_scan(s);
-
 	if (devpriv->can_burst)
 		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
 
-	/*  set scan limits */
-	byte = CR_CHAN(cmd->chanlist[0]);
-	byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
-	outb(byte, dev->iobase + DAS16_MUX_REG);
-
-	/* set gain (this is also burst rate register but according to
-	 * computer boards manual, burst rate does nothing, even on
-	 * keithley cards) */
-	if (board->ai_pg != das16_pg_none) {
-		range = CR_RANGE(cmd->chanlist[0]);
-		outb((das16_gainlists[board->ai_pg])[range],
-		     dev->iobase + DAS16_GAIN_REG);
-	}
+	/* set mux and range for chanlist scan */
+	das16_ai_set_mux_range(dev, first_chan, last_chan, range);
 
 	/* set counter mode and counts */
 	cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags);
@@ -805,19 +749,9 @@
 	}
 	outb(byte, dev->iobase + DAS16_PACER_REG);
 
-	/*  set up dma transfer */
-	flags = claim_dma_lock();
-	disable_dma(devpriv->dma_chan);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma_chan);
-	devpriv->current_buffer = 0;
-	set_dma_addr(devpriv->dma_chan,
-		     devpriv->dma_buffer_addr[devpriv->current_buffer]);
-	devpriv->dma_transfer_size = DAS16_DMA_SIZE;
-	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
-	enable_dma(devpriv->dma_chan);
-	release_dma_lock(flags);
+	/* set up dma transfer */
+	dma->cur_dma = 0;
+	das16_ai_setup_dma(dev, s, 0);
 
 	/*  set up timer */
 	spin_lock_irqsave(&dev->spinlock, flags);
@@ -825,7 +759,14 @@
 	devpriv->timer.expires = jiffies + timer_period();
 	add_timer(&devpriv->timer);
 
-	das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src);
+	/* enable DMA interrupt with external or internal pacing */
+	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_PACING_MASK);
+	devpriv->ctrl_reg |= DAS16_CTRL_DMAE;
+	if (cmd->convert_src == TRIG_EXT)
+		devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
+	else
+		devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
+	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 
 	if (devpriv->can_burst)
 		outb(0, dev->iobase + DAS1600_CONV_REG);
@@ -837,12 +778,17 @@
 static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct das16_private_struct *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 
-	das16_ai_disable(dev);
-	disable_dma(devpriv->dma_chan);
+	/* disable interrupts, dma and pacer clocked conversions */
+	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_DMAE |
+			       DAS16_CTRL_PACING_MASK);
+	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+
+	comedi_isadma_disable(dma->chan);
 
 	/*  disable SW timer */
 	if (devpriv->timer_running) {
@@ -893,23 +839,14 @@
 			      struct comedi_insn *insn,
 			      unsigned int *data)
 {
-	const struct das16_board *board = dev->board_ptr;
 	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned int range = CR_RANGE(insn->chanspec);
 	unsigned int val;
 	int ret;
 	int i;
 
-	das16_ai_disable(dev);
-
-	/* set multiplexer */
-	outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG);
-
-	/* set gain */
-	if (board->ai_pg != das16_pg_none) {
-		outb((das16_gainlists[board->ai_pg])[range],
-		     dev->iobase + DAS16_GAIN_REG);
-	}
+	/* set mux and range for single channel */
+	das16_ai_set_mux_range(dev, chan, chan, range);
 
 	for (i = 0; i < insn->n; i++) {
 		/* trigger conversion */
@@ -1001,14 +938,107 @@
 	outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg);
 }
 
+static void das16_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+	struct das16_private_struct *devpriv = dev->private;
+
+	/* only DMA channels 3 and 1 are valid */
+	if (!(dma_chan == 1 || dma_chan == 3))
+		return;
+
+	/* DMA uses two buffers */
+	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+					   DAS16_DMA_SIZE, COMEDI_ISADMA_READ);
+	if (devpriv->dma) {
+		init_timer(&devpriv->timer);
+		devpriv->timer.function = das16_timer_interrupt;
+		devpriv->timer.data = (unsigned long)dev;
+	}
+}
+
+static void das16_free_dma(struct comedi_device *dev)
+{
+	struct das16_private_struct *devpriv = dev->private;
+
+	if (devpriv) {
+		if (devpriv->timer.data)
+			del_timer_sync(&devpriv->timer);
+		comedi_isadma_free(devpriv->dma);
+	}
+}
+
+static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev,
+						  struct comedi_subdevice *s,
+						  struct comedi_devconfig *it,
+						  unsigned int pg_type,
+						  unsigned int status)
+{
+	unsigned int min = it->options[4];
+	unsigned int max = it->options[5];
+
+	/* get any user-defined input range */
+	if (pg_type == das16_pg_none && (min || max)) {
+		struct comedi_lrange *lrange;
+		struct comedi_krange *krange;
+
+		/* allocate single-range range table */
+		lrange = comedi_alloc_spriv(s,
+					    sizeof(*lrange) + sizeof(*krange));
+		if (!lrange)
+			return &range_unknown;
+
+		/* initialize ai range */
+		lrange->length = 1;
+		krange = lrange->range;
+		krange->min = min;
+		krange->max = max;
+		krange->flags = UNIT_volt;
+
+		return lrange;
+	}
+
+	/* use software programmable range */
+	if (status & DAS16_STATUS_UNIPOLAR)
+		return das16_ai_uni_lranges[pg_type];
+	return das16_ai_bip_lranges[pg_type];
+}
+
+static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev,
+						  struct comedi_subdevice *s,
+						  struct comedi_devconfig *it)
+{
+	unsigned int min = it->options[6];
+	unsigned int max = it->options[7];
+
+	/* get any user-defined output range */
+	if (min || max) {
+		struct comedi_lrange *lrange;
+		struct comedi_krange *krange;
+
+		/* allocate single-range range table */
+		lrange = comedi_alloc_spriv(s,
+					    sizeof(*lrange) + sizeof(*krange));
+		if (!lrange)
+			return &range_unknown;
+
+		/* initialize ao range */
+		lrange->length = 1;
+		krange = lrange->range;
+		krange->min = min;
+		krange->max = max;
+		krange->flags = UNIT_volt;
+
+		return lrange;
+	}
+
+	return &range_unknown;
+}
+
 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct das16_board *board = dev->board_ptr;
 	struct das16_private_struct *devpriv;
 	struct comedi_subdevice *s;
-	struct comedi_lrange *lrange;
-	struct comedi_krange *krange;
-	unsigned int dma_chan = it->options[2];
 	unsigned int status;
 	int ret;
 
@@ -1063,72 +1093,7 @@
 			devpriv->clockbase = I8254_OSC_BASE_1MHZ;
 	}
 
-	/* initialize dma */
-	if (dma_chan == 1 || dma_chan == 3) {
-		unsigned long flags;
-		int i;
-
-		if (request_dma(dma_chan, dev->board_name)) {
-			dev_err(dev->class_dev,
-				"failed to request dma channel %i\n",
-				dma_chan);
-			return -EINVAL;
-		}
-		devpriv->dma_chan = dma_chan;
-
-		/* allocate dma buffers */
-		for (i = 0; i < 2; i++) {
-			void *p;
-
-			p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
-						 &devpriv->dma_buffer_addr[i]);
-			if (!p)
-				return -ENOMEM;
-			devpriv->dma_buffer[i] = p;
-		}
-
-		flags = claim_dma_lock();
-		disable_dma(devpriv->dma_chan);
-		set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
-		release_dma_lock(flags);
-
-		init_timer(&devpriv->timer);
-		devpriv->timer.function = das16_timer_interrupt;
-		devpriv->timer.data = (unsigned long)dev;
-	}
-
-	/* get any user-defined input range */
-	if (board->ai_pg == das16_pg_none &&
-	    (it->options[4] || it->options[5])) {
-		/* allocate single-range range table */
-		lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
-		if (!lrange)
-			return -ENOMEM;
-
-		/* initialize ai range */
-		devpriv->user_ai_range_table = lrange;
-		lrange->length = 1;
-		krange = devpriv->user_ai_range_table->range;
-		krange->min = it->options[4];
-		krange->max = it->options[5];
-		krange->flags = UNIT_volt;
-	}
-
-	/* get any user-defined output range */
-	if (it->options[6] || it->options[7]) {
-		/* allocate single-range range table */
-		lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
-		if (!lrange)
-			return -ENOMEM;
-
-		/* initialize ao range */
-		devpriv->user_ao_range_table = lrange;
-		lrange->length = 1;
-		krange = devpriv->user_ao_range_table->range;
-		krange->min = it->options[6];
-		krange->max = it->options[7];
-		krange->flags = UNIT_volt;
-	}
+	das16_alloc_dma(dev, it->options[2]);
 
 	ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
 	if (ret)
@@ -1149,15 +1114,9 @@
 	}
 	s->len_chanlist	= s->n_chan;
 	s->maxdata	= board->ai_maxdata;
-	if (devpriv->user_ai_range_table) { /*  user defined ai range */
-		s->range_table	= devpriv->user_ai_range_table;
-	} else if (status & DAS16_STATUS_UNIPOLAR) {
-		s->range_table	= das16_ai_uni_lranges[board->ai_pg];
-	} else {
-		s->range_table	= das16_ai_bip_lranges[board->ai_pg];
-	}
+	s->range_table	= das16_ai_range(dev, s, it, board->ai_pg, status);
 	s->insn_read	= das16_ai_insn_read;
-	if (devpriv->dma_chan) {
+	if (devpriv->dma) {
 		dev->read_subdev = s;
 		s->subdev_flags	|= SDF_CMD_READ;
 		s->do_cmdtest	= das16_cmd_test;
@@ -1173,7 +1132,7 @@
 		s->subdev_flags	= SDF_WRITABLE;
 		s->n_chan	= 2;
 		s->maxdata	= 0x0fff;
-		s->range_table	= devpriv->user_ao_range_table;
+		s->range_table	= das16_ao_range(dev, s, it);
 		s->insn_write	= das16_ao_insn_write;
 
 		ret = comedi_alloc_subdev_readback(s);
@@ -1230,25 +1189,11 @@
 {
 	const struct das16_board *board = dev->board_ptr;
 	struct das16_private_struct *devpriv = dev->private;
-	int i;
 
 	if (devpriv) {
-		if (devpriv->timer.data)
-			del_timer_sync(&devpriv->timer);
 		if (dev->iobase)
 			das16_reset(dev);
-
-		for (i = 0; i < 2; i++) {
-			if (devpriv->dma_buffer[i])
-				pci_free_consistent(NULL, DAS16_DMA_SIZE,
-						    devpriv->dma_buffer[i],
-						    devpriv->
-						    dma_buffer_addr[i]);
-		}
-		if (devpriv->dma_chan)
-			free_dma(devpriv->dma_chan);
-		kfree(devpriv->user_ai_range_table);
-		kfree(devpriv->user_ao_range_table);
+		das16_free_dma(dev);
 
 		if (devpriv->extra_iobase)
 			release_region(devpriv->extra_iobase,
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 80f41b7..3666a68 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -455,7 +455,7 @@
 	/* this probably won't catch overruns since the card doesn't generate
 	 * overrun interrupts, but we might as well try */
 	if (status & OVRUN) {
-		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		async->events |= COMEDI_CB_ERROR;
 		dev_err(dev->class_dev, "fifo overflow\n");
 	}
 
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index be825d2..0790a28 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -98,12 +98,12 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+
 #include "../comedidev.h"
 
-#include <asm/dma.h>
-
-#include "8253.h"
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
+#include "8253.h"
 
 /* misc. defines */
 #define DAS1800_SIZE           16	/* uses 16 io addresses */
@@ -421,19 +421,14 @@
 };
 
 struct das1800_private {
+	struct comedi_isadma *dma;
 	unsigned int divisor1;	/* value to load into board's counter 1 for timed conversions */
 	unsigned int divisor2;	/* value to load into board's counter 2 for timed conversions */
 	int irq_dma_bits;	/* bits for control register b */
 	/* dma bits for control register b, stored so that dma can be
 	 * turned on and off */
 	int dma_bits;
-	unsigned int dma0;	/* dma channels used */
-	unsigned int dma1;
-	unsigned int dma_current;	/* dma channel currently in use */
-	uint16_t *ai_buf0;	/* pointers to dma buffers */
-	uint16_t *ai_buf1;
-	uint16_t *dma_current_buf;	/* pointer to dma buffer currently being used */
-	unsigned int dma_transfer_size;	/* size of transfer currently used, in bytes */
+	uint16_t *fifo_buf;	/* bounce buffer for analog input FIFO */
 	unsigned long iobase2;	/* secondary io address used for analog out on 'ao' boards */
 	unsigned short ao_update_bits;	/* remembers the last write to the
 					 * 'update' dac */
@@ -480,9 +475,9 @@
 	struct das1800_private *devpriv = dev->private;
 	unsigned int nsamples = comedi_nsamples_left(s, FIFO_SIZE / 2);
 
-	insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, nsamples);
-	munge_data(dev, devpriv->ai_buf0, nsamples);
-	comedi_buf_write_samples(s, devpriv->ai_buf0, nsamples);
+	insw(dev->iobase + DAS1800_FIFO, devpriv->fifo_buf, nsamples);
+	munge_data(dev, devpriv->fifo_buf, nsamples);
+	comedi_buf_write_samples(s, devpriv->fifo_buf, nsamples);
 }
 
 static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
@@ -508,29 +503,21 @@
 	}
 }
 
-/* Utility function used by das1800_flush_dma() and das1800_handle_dma().
- * Assumes dma lock is held */
+/* Utility function used by das1800_flush_dma() and das1800_handle_dma() */
 static void das1800_flush_dma_channel(struct comedi_device *dev,
 				      struct comedi_subdevice *s,
-				      unsigned int channel, uint16_t *buffer)
+				      struct comedi_isadma_desc *desc)
 {
-	struct das1800_private *devpriv = dev->private;
-	unsigned int nbytes;
+	unsigned int residue = comedi_isadma_disable(desc->chan);
+	unsigned int nbytes = desc->size - residue;
 	unsigned int nsamples;
 
-	disable_dma(channel);
-
-	/* clear flip-flop to make sure 2-byte registers
-	 * get set correctly */
-	clear_dma_ff(channel);
-
 	/*  figure out how many points to read */
-	nbytes = devpriv->dma_transfer_size - get_dma_residue(channel);
 	nsamples = comedi_bytes_to_samples(s, nbytes);
 	nsamples = comedi_nsamples_left(s, nsamples);
 
-	munge_data(dev, buffer, nsamples);
-	comedi_buf_write_samples(s, buffer, nsamples);
+	munge_data(dev, desc->virt_addr, nsamples);
+	comedi_buf_write_samples(s, desc->virt_addr, nsamples);
 }
 
 /* flushes remaining data from board when external trigger has stopped acquisition
@@ -539,28 +526,19 @@
 			      struct comedi_subdevice *s)
 {
 	struct das1800_private *devpriv = dev->private;
-	unsigned long flags;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	flags = claim_dma_lock();
-	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-				  devpriv->dma_current_buf);
+	das1800_flush_dma_channel(dev, s, desc);
 
 	if (dual_dma) {
 		/*  switch to other channel and flush it */
-		if (devpriv->dma_current == devpriv->dma0) {
-			devpriv->dma_current = devpriv->dma1;
-			devpriv->dma_current_buf = devpriv->ai_buf1;
-		} else {
-			devpriv->dma_current = devpriv->dma0;
-			devpriv->dma_current_buf = devpriv->ai_buf0;
-		}
-		das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-					  devpriv->dma_current_buf);
+		dma->cur_dma = 1 - dma->cur_dma;
+		desc = &dma->desc[dma->cur_dma];
+		das1800_flush_dma_channel(dev, s, desc);
 	}
 
-	release_dma_lock(flags);
-
 	/*  get any remaining samples in fifo */
 	das1800_handle_fifo_not_empty(dev, s);
 }
@@ -569,47 +547,41 @@
 			       struct comedi_subdevice *s, unsigned int status)
 {
 	struct das1800_private *devpriv = dev->private;
-	unsigned long flags;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
 
-	flags = claim_dma_lock();
-	das1800_flush_dma_channel(dev, s, devpriv->dma_current,
-				  devpriv->dma_current_buf);
-	/*  re-enable  dma channel */
-	set_dma_addr(devpriv->dma_current,
-		     virt_to_bus(devpriv->dma_current_buf));
-	set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);
-	enable_dma(devpriv->dma_current);
-	release_dma_lock(flags);
+	das1800_flush_dma_channel(dev, s, desc);
+
+	/* re-enable dma channel */
+	comedi_isadma_program(desc);
 
 	if (status & DMATC) {
 		/*  clear DMATC interrupt bit */
 		outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);
 		/*  switch dma channels for next time, if appropriate */
-		if (dual_dma) {
-			/*  read data from the other channel next time */
-			if (devpriv->dma_current == devpriv->dma0) {
-				devpriv->dma_current = devpriv->dma1;
-				devpriv->dma_current_buf = devpriv->ai_buf1;
-			} else {
-				devpriv->dma_current = devpriv->dma0;
-				devpriv->dma_current_buf = devpriv->ai_buf0;
-			}
-		}
+		if (dual_dma)
+			dma->cur_dma = 1 - dma->cur_dma;
 	}
 }
 
 static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct das1800_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc;
+	int i;
 
 	outb(0x0, dev->iobase + DAS1800_STATUS);	/* disable conversions */
 	outb(0x0, dev->iobase + DAS1800_CONTROL_B);	/* disable interrupts and dma */
 	outb(0x0, dev->iobase + DAS1800_CONTROL_A);	/* disable and clear fifo and stop triggering */
-	if (devpriv->dma0)
-		disable_dma(devpriv->dma0);
-	if (devpriv->dma1)
-		disable_dma(devpriv->dma1);
+
+	for (i = 0; i < 2; i++) {
+		desc = &dma->desc[i];
+		if (desc->chan)
+			comedi_isadma_disable(desc->chan);
+	}
+
 	return 0;
 }
 
@@ -639,7 +611,7 @@
 		/*  clear OVF interrupt bit */
 		outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);
 		dev_err(dev->class_dev, "FIFO overflow\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 		return;
 	}
@@ -963,79 +935,64 @@
 	}
 }
 
-/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
-static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd)
+static unsigned int das1800_ai_transfer_size(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     unsigned int maxbytes,
+					     unsigned int ns)
 {
-	unsigned int size = DMA_BUF_SIZE;
-	static const int sample_size = 2;	/*  size in bytes of one sample from board */
-	unsigned int fill_time = 300000000;	/*  target time in nanoseconds for filling dma buffer */
-	unsigned int max_size;	/*  maximum size we will allow for a transfer */
+	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned int max_samples = comedi_bytes_to_samples(s, maxbytes);
+	unsigned int samples;
 
-	/*  make dma buffer fill in 0.3 seconds for timed modes */
+	samples = max_samples;
+
+	/* for timed modes, make dma buffer fill in 'ns' time */
 	switch (cmd->scan_begin_src) {
-	case TRIG_FOLLOW:	/*  not in burst mode */
+	case TRIG_FOLLOW:	/* not in burst mode */
 		if (cmd->convert_src == TRIG_TIMER)
-			size = (fill_time / cmd->convert_arg) * sample_size;
+			samples = ns / cmd->convert_arg;
 		break;
 	case TRIG_TIMER:
-		size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) *
-		    sample_size;
-		break;
-	default:
-		size = DMA_BUF_SIZE;
+		samples = ns / (cmd->scan_begin_arg * cmd->chanlist_len);
 		break;
 	}
 
-	/*  set a minimum and maximum size allowed */
-	max_size = DMA_BUF_SIZE;
-	/*  if we are taking limited number of conversions, limit transfer size to that */
-	if (cmd->stop_src == TRIG_COUNT &&
-	    cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)
-		max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;
+	/* limit samples to what is remaining in the command */
+	samples = comedi_nsamples_left(s, samples);
 
-	if (size > max_size)
-		size = max_size;
-	if (size < sample_size)
-		size = sample_size;
+	if (samples > max_samples)
+		samples = max_samples;
+	if (samples < 1)
+		samples = 1;
 
-	return size;
+	return comedi_samples_to_bytes(s, samples);
 }
 
-/* sets up dma */
-static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
+static void das1800_ai_setup_dma(struct comedi_device *dev,
+				 struct comedi_subdevice *s)
 {
 	struct das1800_private *devpriv = dev->private;
-	unsigned long lock_flags;
-	const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[0];
+	unsigned int bytes;
 
 	if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0)
 		return;
 
-	/* determine a reasonable dma transfer size */
-	devpriv->dma_transfer_size = suggest_transfer_size(cmd);
-	lock_flags = claim_dma_lock();
-	disable_dma(devpriv->dma0);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma0);
-	set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0));
-	/*  set appropriate size of transfer */
-	set_dma_count(devpriv->dma0, devpriv->dma_transfer_size);
-	devpriv->dma_current = devpriv->dma0;
-	devpriv->dma_current_buf = devpriv->ai_buf0;
-	enable_dma(devpriv->dma0);
-	/*  set up dual dma if appropriate */
-	if (dual_dma) {
-		disable_dma(devpriv->dma1);
-		/* clear flip-flop to make sure 2-byte registers for
-		 * count and address get set correctly */
-		clear_dma_ff(devpriv->dma1);
-		set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1));
-		/*  set appropriate size of transfer */
-		set_dma_count(devpriv->dma1, devpriv->dma_transfer_size);
-		enable_dma(devpriv->dma1);
+	dma->cur_dma = 0;
+
+	/* determine a dma transfer size to fill buffer in 0.3 sec */
+	bytes = das1800_ai_transfer_size(dev, s, desc->maxsize, 300000000);
+
+	desc->size = bytes;
+	comedi_isadma_program(desc);
+
+	/* set up dual dma if appropriate */
+	if (devpriv->irq_dma_bits & DMA_DUAL) {
+		desc = &dma->desc[1];
+		desc->size = bytes;
+		comedi_isadma_program(desc);
 	}
-	release_dma_lock(lock_flags);
 }
 
 /* programs channel/gain list into card */
@@ -1097,7 +1054,7 @@
 	/* setup card and start */
 	program_chanlist(dev, cmd);
 	das1800_setup_counters(dev, cmd);
-	setup_dma(dev, cmd);
+	das1800_ai_setup_dma(dev, s);
 	outb(control_c, dev->iobase + DAS1800_CONTROL_C);
 	/*  set conversion rate and length for burst mode */
 	if (control_c & BMDE) {
@@ -1234,79 +1191,57 @@
 	return insn->n;
 }
 
-static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
-			    unsigned int dma1)
+static void das1800_init_dma(struct comedi_device *dev,
+			     struct comedi_devconfig *it)
 {
 	struct das1800_private *devpriv = dev->private;
-	unsigned long flags;
+	unsigned int *dma_chan;
 
-	/*  need an irq to do dma */
-	if (dev->irq && dma0) {
-		/* encode dma0 and dma1 into 2 digit hexadecimal for switch */
-		switch ((dma0 & 0x7) | (dma1 << 4)) {
-		case 0x5:	/*  dma0 == 5 */
-			devpriv->dma_bits |= DMA_CH5;
-			break;
-		case 0x6:	/*  dma0 == 6 */
-			devpriv->dma_bits |= DMA_CH6;
-			break;
-		case 0x7:	/*  dma0 == 7 */
-			devpriv->dma_bits |= DMA_CH7;
-			break;
-		case 0x65:	/*  dma0 == 5, dma1 == 6 */
-			devpriv->dma_bits |= DMA_CH5_CH6;
-			break;
-		case 0x76:	/*  dma0 == 6, dma1 == 7 */
-			devpriv->dma_bits |= DMA_CH6_CH7;
-			break;
-		case 0x57:	/*  dma0 == 7, dma1 == 5 */
-			devpriv->dma_bits |= DMA_CH7_CH5;
-			break;
-		default:
-			dev_err(dev->class_dev,
-				"only supports dma channels 5 through 7\n");
-			dev_err(dev->class_dev,
-				"Dual dma only allows the following combinations:\n");
-			dev_err(dev->class_dev,
-				"dma 5,6 / 6,7 / or 7,5\n");
-			return -EINVAL;
-		}
-		if (request_dma(dma0, dev->driver->driver_name)) {
-			dev_err(dev->class_dev,
-				"failed to allocate dma channel %i\n", dma0);
-			return -EINVAL;
-		}
-		devpriv->dma0 = dma0;
-		devpriv->dma_current = dma0;
-		if (dma1) {
-			if (request_dma(dma1, dev->driver->driver_name)) {
-				dev_err(dev->class_dev,
-					"failed to allocate dma channel %i\n",
-					dma1);
-				return -EINVAL;
-			}
-			devpriv->dma1 = dma1;
-		}
-		devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
-		if (devpriv->ai_buf0 == NULL)
-			return -ENOMEM;
-		devpriv->dma_current_buf = devpriv->ai_buf0;
-		if (dma1) {
-			devpriv->ai_buf1 =
-			    kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
-			if (devpriv->ai_buf1 == NULL)
-				return -ENOMEM;
-		}
-		flags = claim_dma_lock();
-		disable_dma(devpriv->dma0);
-		set_dma_mode(devpriv->dma0, DMA_MODE_READ);
-		if (dma1) {
-			disable_dma(devpriv->dma1);
-			set_dma_mode(devpriv->dma1, DMA_MODE_READ);
-		}
-		release_dma_lock(flags);
+	/*
+	 * it->options[2] is DMA channel 0
+	 * it->options[3] is DMA channel 1
+	 *
+	 * Encode the DMA channels into 2 digit hexadecimal for switch.
+	 */
+	dma_chan = &it->options[2];
+
+	switch ((dma_chan[0] & 0x7) | (dma_chan[1] << 4)) {
+	case 0x5:	/*  dma0 == 5 */
+		devpriv->dma_bits = DMA_CH5;
+		break;
+	case 0x6:	/*  dma0 == 6 */
+		devpriv->dma_bits = DMA_CH6;
+		break;
+	case 0x7:	/*  dma0 == 7 */
+		devpriv->dma_bits = DMA_CH7;
+		break;
+	case 0x65:	/*  dma0 == 5, dma1 == 6 */
+		devpriv->dma_bits = DMA_CH5_CH6;
+		break;
+	case 0x76:	/*  dma0 == 6, dma1 == 7 */
+		devpriv->dma_bits = DMA_CH6_CH7;
+		break;
+	case 0x57:	/*  dma0 == 7, dma1 == 5 */
+		devpriv->dma_bits = DMA_CH7_CH5;
+		break;
+	default:
+		return;
 	}
-	return 0;
+
+	/* DMA can use 1 or 2 buffers, each with a separate channel */
+	devpriv->dma = comedi_isadma_alloc(dev, dma_chan[1] ? 2 : 1,
+					   dma_chan[0], dma_chan[1],
+					   DMA_BUF_SIZE, COMEDI_ISADMA_READ);
+	if (!devpriv->dma)
+		devpriv->dma_bits = 0;
+}
+
+static void das1800_free_dma(struct comedi_device *dev)
+{
+	struct das1800_private *devpriv = dev->private;
+
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
 }
 
 static int das1800_probe(struct comedi_device *dev)
@@ -1374,8 +1309,6 @@
 	struct das1800_private *devpriv;
 	struct comedi_subdevice *s;
 	unsigned int irq = it->options[1];
-	unsigned int dma0 = it->options[2];
-	unsigned int dma1 = it->options[3];
 	int board;
 	int ret;
 
@@ -1437,16 +1370,13 @@
 		}
 	}
 
-	ret = das1800_init_dma(dev, dma0, dma1);
-	if (ret < 0)
-		return ret;
+	/* an irq and one dma channel is required to use dma */
+	if (dev->irq & it->options[2])
+		das1800_init_dma(dev, it);
 
-	if (devpriv->ai_buf0 == NULL) {
-		devpriv->ai_buf0 =
-		    kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL);
-		if (devpriv->ai_buf0 == NULL)
-			return -ENOMEM;
-	}
+	devpriv->fifo_buf = kmalloc_array(FIFO_SIZE, sizeof(uint16_t), GFP_KERNEL);
+	if (!devpriv->fifo_buf)
+		return -ENOMEM;
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
@@ -1523,13 +1453,9 @@
 {
 	struct das1800_private *devpriv = dev->private;
 
+	das1800_free_dma(dev);
 	if (devpriv) {
-		if (devpriv->dma0)
-			free_dma(devpriv->dma0);
-		if (devpriv->dma1)
-			free_dma(devpriv->dma1);
-		kfree(devpriv->ai_buf0);
-		kfree(devpriv->ai_buf1);
+		kfree(devpriv->fifo_buf);
 		if (devpriv->iobase2)
 			release_region(devpriv->iobase2, DAS1800_SIZE);
 	}
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 780f4f6..b8755b5 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -20,8 +20,8 @@
 /*
  * Driver: das6402
  * Description: Keithley Metrabyte DAS6402 (& compatibles)
- * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12)
- *	    (Keithley Metrabyte) DAS6402-16 (das6402-16)
+ * Devices: [Keithley Metrabyte] DAS6402-12 (das6402-12),
+ *   DAS6402-16 (das6402-16)
  * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
  * Updated: Fri, 14 Mar 2014 10:18:43 -0700
  * Status: unknown
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index e5bdc24..ff7f4be 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -511,7 +511,7 @@
 
 	if (fifo_overflow) {
 		spin_unlock_irqrestore(&dev->spinlock, irq_flags);
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 		return IRQ_HANDLED;
 	}
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 6df298a..1af0066 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -19,7 +19,7 @@
 /*
  * Driver: dmm32at
  * Description: Diamond Systems Diamond-MM-32-AT
- * Devices: (Diamond Systems) Diamond-MM-32-AT [dmm32at]
+ * Devices: [Diamond Systems] Diamond-MM-32-AT (dmm32at)
  * Author: Perry J. Piplani <perry.j.piplani@nasa.gov>
  * Updated: Fri Jun  4 09:13:24 CDT 2004
  * Status: experimental
@@ -365,7 +365,7 @@
 	/* enable the ai conversion interrupt and the clock to start scans */
 	outb(DMM32AT_INTCLK_ADINT |
 	     DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL,
-             dev->iobase + DMM32AT_INTCLK_REG);
+	     dev->iobase + DMM32AT_INTCLK_REG);
 }
 
 static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 2be98bb..db21d21 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -20,22 +20,12 @@
  * Driver: dt282x
  * Description: Data Translation DT2821 series (including DT-EZ)
  * Author: ds
- * Devices: (Data Translation) DT2821 [dt2821]
- *	    (Data Translation) DT2821-F-16SE [dt2821-f]
- *	    (Data Translation) DT2821-F-8DI [dt2821-f]
- *	    (Data Translation) DT2821-G-16SE [dt2821-g]
- *	    (Data Translation) DT2821-G-8DI [dt2821-g]
- *	    (Data Translation) DT2823 [dt2823]
- *	    (Data Translation) DT2824-PGH [dt2824-pgh]
- *	    (Data Translation) DT2824-PGL [dt2824-pgl]
- *	    (Data Translation) DT2825 [dt2825]
- *	    (Data Translation) DT2827 [dt2827]
- *	    (Data Translation) DT2828 [dt2828]
- *	    (Data Translation) DT2928 [dt2829]
- *	    (Data Translation) DT21-EZ [dt21-ez]
- *	    (Data Translation) DT23-EZ [dt23-ez]
- *	    (Data Translation) DT24-EZ [dt24-ez]
- *	    (Data Translation) DT24-EZ-PGL [dt24-ez-pgl]
+ * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
+ *   DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
+ *   DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
+ *   DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
+ *   DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
+ *   DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
  * Status: complete
  * Updated: Wed, 22 Aug 2001 17:11:34 -0700
  *
@@ -66,15 +56,14 @@
  */
 
 #include <linux/module.h>
-#include "../comedidev.h"
-
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
-#include <asm/dma.h>
+#include "../comedidev.h"
 
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
 
 /*
@@ -311,55 +300,36 @@
 };
 
 struct dt282x_private {
+	struct comedi_isadma *dma;
 	unsigned int ad_2scomp:1;
-
 	unsigned int divisor;
-
 	int dacsr;	/* software copies of registers */
 	int adcsr;
 	int supcsr;
-
 	int ntrig;
 	int nread;
-
-	struct {
-		int chan;
-		unsigned short *buf;	/* DMA buffer */
-		int size;	/* size of current transfer */
-	} dma[2];
-	int dma_maxsize;	/* max size of DMA transfer (in bytes) */
-	int current_dma_index;
 	int dma_dir;
 };
 
 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int dma_chan;
-	unsigned long dma_ptr;
-	unsigned long flags;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma_index];
 
 	if (!devpriv->ntrig)
 		return 0;
 
 	if (n == 0)
-		n = devpriv->dma_maxsize;
+		n = desc->maxsize;
 	if (n > devpriv->ntrig * 2)
 		n = devpriv->ntrig * 2;
 	devpriv->ntrig -= n / 2;
 
-	devpriv->dma[dma_index].size = n;
-	dma_chan = devpriv->dma[dma_index].chan;
-	dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
+	desc->size = n;
+	comedi_isadma_set_mode(desc, devpriv->dma_dir);
 
-	set_dma_mode(dma_chan, DMA_MODE_READ);
-	flags = claim_dma_lock();
-	clear_dma_ff(dma_chan);
-	set_dma_addr(dma_chan, dma_ptr);
-	set_dma_count(dma_chan, n);
-	release_dma_lock(flags);
-
-	enable_dma(dma_chan);
+	comedi_isadma_program(desc);
 
 	return n;
 }
@@ -367,22 +337,13 @@
 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int dma_chan;
-	unsigned long dma_ptr;
-	unsigned long flags;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma_index];
 
-	devpriv->dma[dma_index].size = n;
-	dma_chan = devpriv->dma[dma_index].chan;
-	dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
+	desc->size = n;
+	comedi_isadma_set_mode(desc, devpriv->dma_dir);
 
-	set_dma_mode(dma_chan, DMA_MODE_WRITE);
-	flags = claim_dma_lock();
-	clear_dma_ff(dma_chan);
-	set_dma_addr(dma_chan, dma_ptr);
-	set_dma_count(dma_chan, n);
-	release_dma_lock(flags);
-
-	enable_dma(dma_chan);
+	comedi_isadma_program(desc);
 
 	return n;
 }
@@ -390,9 +351,14 @@
 static void dt282x_disable_dma(struct comedi_device *dev)
 {
 	struct dt282x_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc;
+	int i;
 
-	disable_dma(devpriv->dma[0].chan);
-	disable_dma(devpriv->dma[1].chan);
+	for (i = 0; i < 2; i++) {
+		desc = &dma->desc[i];
+		comedi_isadma_disable(desc->chan);
+	}
 }
 
 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
@@ -454,11 +420,12 @@
 					int cur_dma)
 {
 	struct dt282x_private *devpriv = dev->private;
-	void *ptr = devpriv->dma[cur_dma].buf;
-	unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize);
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
+	unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
 	unsigned int nbytes;
 
-	nbytes = comedi_buf_read_samples(s, ptr, nsamples);
+	nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
 	if (nbytes)
 		dt282x_prep_ao_dma(dev, cur_dma, nbytes);
 	else
@@ -471,39 +438,37 @@
 				    struct comedi_subdevice *s)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int cur_dma = devpriv->current_dma_index;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 
 	outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
 	     dev->iobase + DT2821_SUPCSR_REG);
 
-	disable_dma(devpriv->dma[cur_dma].chan);
+	comedi_isadma_disable(desc->chan);
 
-	devpriv->current_dma_index = 1 - cur_dma;
-
-	if (!dt282x_ao_setup_dma(dev, s, cur_dma))
+	if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
 		s->async->events |= COMEDI_CB_OVERFLOW;
+
+	dma->cur_dma = 1 - dma->cur_dma;
 }
 
 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
 				    struct comedi_subdevice *s)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int cur_dma = devpriv->current_dma_index;
-	void *ptr = devpriv->dma[cur_dma].buf;
-	int size = devpriv->dma[cur_dma].size;
-	unsigned int nsamples = comedi_bytes_to_samples(s, size);
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
 	int ret;
 
 	outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
 	     dev->iobase + DT2821_SUPCSR_REG);
 
-	disable_dma(devpriv->dma[cur_dma].chan);
+	comedi_isadma_disable(desc->chan);
 
-	devpriv->current_dma_index = 1 - cur_dma;
-
-	dt282x_munge(dev, s, ptr, size);
-	ret = comedi_buf_write_samples(s, ptr, nsamples);
-	if (ret != size)
+	dt282x_munge(dev, s, desc->virt_addr, desc->size);
+	ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
+	if (ret != desc->size)
 		return;
 
 	devpriv->nread -= nsamples;
@@ -524,7 +489,9 @@
 	}
 #endif
 	/* restart the channel */
-	dt282x_prep_ai_dma(dev, cur_dma, 0);
+	dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
+
+	dma->cur_dma = 1 - dma->cur_dma;
 }
 
 static irqreturn_t dt282x_interrupt(int irq, void *d)
@@ -545,7 +512,7 @@
 	dacsr = inw(dev->iobase + DT2821_DACSR_REG);
 	supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
 	if (supcsr & DT2821_SUPCSR_DMAD) {
-		if (devpriv->dma_dir == DMA_MODE_READ)
+		if (devpriv->dma_dir == COMEDI_ISADMA_READ)
 			dt282x_ai_dma_interrupt(dev, s);
 		else
 			dt282x_ao_dma_interrupt(dev, s_ao);
@@ -718,14 +685,7 @@
 
 	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 
-	if (cmd->scan_begin_src == TRIG_FOLLOW) {
-		/* internal trigger */
-		err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-	} else {
-		/* external trigger */
-		/* should be level/edge, hi/lo specification here */
-		err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-	}
+	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 
 	err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
 
@@ -757,6 +717,7 @@
 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct dt282x_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	int ret;
 
@@ -778,8 +739,8 @@
 	devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
 	devpriv->nread = devpriv->ntrig;
 
-	devpriv->dma_dir = DMA_MODE_READ;
-	devpriv->current_dma_index = 0;
+	devpriv->dma_dir = COMEDI_ISADMA_READ;
+	dma->cur_dma = 0;
 	dt282x_prep_ai_dma(dev, 0, 0);
 	if (devpriv->ntrig) {
 		dt282x_prep_ai_dma(dev, 1, 0);
@@ -942,6 +903,7 @@
 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct dt282x_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
 	dt282x_disable_dma(dev);
@@ -958,8 +920,8 @@
 	devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
 	devpriv->nread = devpriv->ntrig;
 
-	devpriv->dma_dir = DMA_MODE_WRITE;
-	devpriv->current_dma_index = 0;
+	devpriv->dma_dir = COMEDI_ISADMA_WRITE;
+	dma->cur_dma = 0;
 
 	outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
 
@@ -1063,46 +1025,42 @@
 	return ai_range_table[x];
 }
 
-static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
+static void dt282x_alloc_dma(struct comedi_device *dev,
+			     struct comedi_devconfig *it)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int ret;
+	unsigned int irq_num = it->options[1];
+	unsigned int dma_chan[2];
 
-	ret = request_dma(dma1, "dt282x A");
-	if (ret)
-		return -EBUSY;
-	devpriv->dma[0].chan = dma1;
+	if (it->options[2] < it->options[3]) {
+		dma_chan[0] = it->options[2];
+		dma_chan[1] = it->options[3];
+	} else {
+		dma_chan[0] = it->options[3];
+		dma_chan[1] = it->options[2];
+	}
 
-	ret = request_dma(dma2, "dt282x B");
-	if (ret)
-		return -EBUSY;
-	devpriv->dma[1].chan = dma2;
+	if (!irq_num || dma_chan[0] == dma_chan[1] ||
+	    dma_chan[0] < 5 || dma_chan[0] > 7 ||
+	    dma_chan[1] < 5 || dma_chan[1] > 7)
+		return;
 
-	devpriv->dma_maxsize = PAGE_SIZE;
-	devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-	devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
-	if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
-		return -ENOMEM;
+	if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
+		return;
 
-	return 0;
+	/* DMA uses two 4K buffers with separate DMA channels */
+	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
+					   PAGE_SIZE, 0);
+	if (!devpriv->dma)
+		free_irq(irq_num, dev);
 }
 
 static void dt282x_free_dma(struct comedi_device *dev)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int i;
 
-	if (!devpriv)
-		return;
-
-	for (i = 0; i < 2; i++) {
-		if (devpriv->dma[i].chan)
-			free_dma(devpriv->dma[i].chan);
-		if (devpriv->dma[i].buf)
-			free_page((unsigned long)devpriv->dma[i].buf);
-		devpriv->dma[i].chan = 0;
-		devpriv->dma[i].buf = NULL;
-	}
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
 }
 
 static int dt282x_initialize(struct comedi_device *dev)
@@ -1160,36 +1118,7 @@
 		return -ENOMEM;
 
 	/* an IRQ and 2 DMA channels are required for async command support */
-	if (it->options[1] && it->options[2] && it->options[3]) {
-		unsigned int irq = it->options[1];
-		unsigned int dma1 = it->options[2];
-		unsigned int dma2 = it->options[3];
-
-		if (dma2 < dma1) {
-			unsigned int swap;
-
-			swap = dma1;
-			dma1 = dma2;
-			dma2 = swap;
-		}
-
-		if (dma1 != dma2 &&
-		    dma1 >= 5 && dma1 <= 7 &&
-		    dma2 >= 5 && dma2 <= 7) {
-			ret = request_irq(irq, dt282x_interrupt, 0,
-					  dev->board_name, dev);
-			if (ret == 0) {
-				dev->irq = irq;
-
-				ret = dt282x_grab_dma(dev, dma1, dma2);
-				if (ret < 0) {
-					dt282x_free_dma(dev);
-					free_irq(dev->irq, dev);
-					dev->irq = 0;
-				}
-			}
-		}
-	}
+	dt282x_alloc_dma(dev, it);
 
 	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 1d9a7a6..0aa5198 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -355,7 +355,7 @@
 		dt3k_ai_empty_fifo(dev, s);
 
 	if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
-		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		s->async->events |= COMEDI_CB_ERROR;
 
 	debug_n_ints++;
 	if (debug_n_ints >= 10)
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 06c601d..e11c216 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -42,9 +42,8 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/uaccess.h>
-#include <linux/usb.h>
 
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 #define DT9812_DIAGS_BOARD_INFO_ADDR	0xFBFF
 #define DT9812_MAX_WRITE_CMD_PIPE_SIZE	32
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index 1b6324c..6c1e442 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -14,24 +14,23 @@
  */
 
 /*
- Driver: dyna_pci10xx
- Devices: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/
- Author: Prashant Shah <pshah.mumbai@gmail.com>
- Developed at Automation Labs, Chemical Dept., IIT Bombay, India.
- Prof. Kannan Moudgalya <kannan@iitb.ac.in>
- http://www.iitb.ac.in
- Status: Stable
- Version: 1.0
- Device Supported :
- - Dynalog PCI 1050
-
- Notes :
- - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and
- they are using the PLX Technlogies Vendor ID since that is the PCI Chip used
- in the card.
- - Dynalog India Pvt. Ltd. has provided the internal register specification for
- their cards in their manuals.
-*/
+ * Driver: dyna_pci10xx
+ * Description: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/
+ * Devices: [Dynalog] PCI-1050 (dyna_pci1050)
+ * Author: Prashant Shah <pshah.mumbai@gmail.com>
+ * Status: Stable
+ *
+ * Developed at Automation Labs, Chemical Dept., IIT Bombay, India.
+ * Prof. Kannan Moudgalya <kannan@iitb.ac.in>
+ * http://www.iitb.ac.in
+ *
+ * Notes :
+ * - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and
+ *   they are using the PLX Technlogies Vendor ID since that is the PCI Chip
+ *   used in the card.
+ * - Dynalog India Pvt. Ltd. has provided the internal register specification
+ *   for their cards in their manuals.
+ */
 
 #include <linux/module.h>
 #include <linux/delay.h>
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 0979f53..deada97 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -261,12 +261,12 @@
 
 	if (hpdi_board_status & RX_OVERRUN_BIT) {
 		dev_err(dev->class_dev, "rx fifo overrun\n");
-		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		async->events |= COMEDI_CB_ERROR;
 	}
 
 	if (hpdi_board_status & RX_UNDERRUN_BIT) {
 		dev_err(dev->class_dev, "rx fifo underrun\n");
-		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		async->events |= COMEDI_CB_ERROR;
 	}
 
 	if (devpriv->dio_count == 0)
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 1085d66..0768bc42 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -9,7 +9,7 @@
 /*
  * Driver: ii_pci20kc
  * Description: Intelligent Instruments PCI-20001C carrier board
- * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc]
+ * Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
  * Author: Markus Kempf <kempf@matsci.uni-sb.de>
  * Status: works
  *
diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h
index 20478ae..356811d 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.h
+++ b/drivers/staging/comedi/drivers/jr3_pci.h
@@ -261,8 +261,9 @@
 	} link[8];
 };
 
-/*  JR3 force/torque sensor data definition. For more information see sensor and */
-/*  hardware manuals. */
+/*  JR3 force/torque sensor data definition. For more information see sensor
+ *  and hardware manuals.
+ */
 
 struct jr3_channel {
 	/*  Raw_channels is the area used to store the raw data coming from */
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 77e94a3..3c19e0f 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -19,7 +19,7 @@
 /*
  * Driver: ke_counter
  * Description: Driver for Kolter Electronic Counter Card
- * Devices: (Kolter Electronic) PCI Counter Card [ke_counter]
+ * Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
  * Author: Michael Hillmann
  * Updated: Mon, 14 Apr 2008 15:42:42 +0100
  * Status: tested
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 915685c..d120aa2 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -1068,7 +1068,7 @@
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
 			outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
-			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+			s->async->events |= COMEDI_CB_ERROR;
 
 			dev_err(dev->class_dev, "FIFO overflow\n");
 		} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
@@ -1089,7 +1089,7 @@
 				 ME4000_AI_CTRL_BIT_SC_IRQ);
 			outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
 
-			s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+			s->async->events |= COMEDI_CB_ERROR;
 
 			dev_err(dev->class_dev, "Undefined FIFO state\n");
 		}
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index b5278c1..92e2352 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -19,8 +19,7 @@
 /*
  * Driver: me_daq
  * Description: Meilhaus PCI data acquisition cards
- * Devices: (Meilhaus) ME-2600i [me-2600i]
- *          (Meilhaus) ME-2000i [me-2000i]
+ * Devices: [Meilhaus] ME-2600i (me-2600i), ME-2000i (me-2000i)
  * Author: Michael Hillmann <hillmann@syscongroup.de>
  * Status: experimental
  *
@@ -175,7 +174,7 @@
 
 static inline void sleep(unsigned sec)
 {
-	current->state = TASK_INTERRUPTIBLE;
+	__set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(sec * HZ);
 }
 
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
index af21bc1..db972bc 100644
--- a/drivers/staging/comedi/drivers/mf6x4.c
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -18,7 +18,7 @@
 /*
  * Driver: mf6x4
  * Description: Humusoft MF634 and MF624 Data acquisition card driver
- * Devices: Humusoft MF634, Humusoft MF624
+ * Devices: [Humusoft] MF634 (mf634), MF624 (mf624)
  * Author: Rostislav Lisovy <lisovy@gmail.com>
  * Status: works
  * Updated:
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index ffc9e61..1e537a5 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -494,9 +494,7 @@
 unsigned mite_dma_tcr(struct mite_channel *mite_chan)
 {
 	struct mite_struct *mite = mite_chan->mite;
-	int lkar;
 
-	lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
 	return readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel));
 }
 EXPORT_SYMBOL_GPL(mite_dma_tcr);
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index f99847f..530f716 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -19,8 +19,7 @@
 /*
  * Driver: ni_6527
  * Description: National Instruments 6527
- * Devices: (National Instruments) PCI-6527 [pci-6527]
- *          (National Instruments) PXI-6527 [pxi-6527]
+ * Devices: [National Instruments] PCI-6527 (pci-6527), PXI-6527 (pxi-6527)
  * Author: David A. Schleef <ds@schleef.org>
  * Updated: Sat, 25 Jan 2003 13:24:40 -0800
  * Status: works
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index bcb326e..67cb758 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -25,28 +25,14 @@
  * Author: Jon Grierson <jd@renko.co.uk>,
  *	   Frank Mori Hess <fmhess@users.sourceforge.net>
  * Status: testing
- * Devices: (National Instruments) PCI-6509 [ni_65xx]
- *	    (National Instruments) PXI-6509 [ni_65xx]
- *	    (National Instruments) PCI-6510 [ni_65xx]
- *	    (National Instruments) PCI-6511 [ni_65xx]
- *	    (National Instruments) PXI-6511 [ni_65xx]
- *	    (National Instruments) PCI-6512 [ni_65xx]
- *	    (National Instruments) PXI-6512 [ni_65xx]
- *	    (National Instruments) PCI-6513 [ni_65xx]
- *	    (National Instruments) PXI-6513 [ni_65xx]
- *	    (National Instruments) PCI-6514 [ni_65xx]
- *	    (National Instruments) PXI-6514 [ni_65xx]
- *	    (National Instruments) PCI-6515 [ni_65xx]
- *	    (National Instruments) PXI-6515 [ni_65xx]
- *	    (National Instruments) PCI-6516 [ni_65xx]
- *	    (National Instruments) PCI-6517 [ni_65xx]
- *	    (National Instruments) PCI-6518 [ni_65xx]
- *	    (National Instruments) PCI-6519 [ni_65xx]
- *	    (National Instruments) PCI-6520 [ni_65xx]
- *	    (National Instruments) PCI-6521 [ni_65xx]
- *	    (National Instruments) PXI-6521 [ni_65xx]
- *	    (National Instruments) PCI-6528 [ni_65xx]
- *	    (National Instruments) PXI-6528 [ni_65xx]
+ * Devices: [National Instruments] PCI-6509 (pci-6509), PXI-6509 (pxi-6509),
+ *   PCI-6510 (pci-6510), PCI-6511 (pci-6511), PXI-6511 (pxi-6511),
+ *   PCI-6512 (pci-6512), PXI-6512 (pxi-6512), PCI-6513 (pci-6513),
+ *   PXI-6513 (pxi-6513), PCI-6514 (pci-6514), PXI-6514 (pxi-6514),
+ *   PCI-6515 (pxi-6515), PXI-6515 (pxi-6515), PCI-6516 (pci-6516),
+ *   PCI-6517 (pci-6517), PCI-6518 (pci-6518), PCI-6519 (pci-6519),
+ *   PCI-6520 (pci-6520), PCI-6521 (pci-6521), PXI-6521 (pxi-6521),
+ *   PCI-6528 (pci-6528), PXI-6528 (pxi-6528)
  * Updated: Mon, 21 Jul 2014 12:49:58 +0000
  *
  * Configuration Options: not applicable, uses PCI auto config
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 69e543a..a1ce0b0 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -62,14 +62,13 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
-#include "../comedidev.h"
-
 #include <linux/io.h>
 
-#include <asm/dma.h>
+#include "../comedidev.h"
 
-#include "8253.h"
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
+#include "8253.h"
 
 #define A2150_DMA_BUFFER_SIZE	0xff00	/*  size in bytes of dma buffer */
 
@@ -146,11 +145,8 @@
 };
 
 struct a2150_private {
-
-	volatile unsigned int count;	/* number of data points left to be taken */
-	unsigned int dma;	/*  dma channel */
-	uint16_t *dma_buffer;	/*  dma buffer */
-	unsigned int dma_transfer_size;	/*  size in bytes of dma transfers */
+	struct comedi_isadma *dma;
+	unsigned int count;	/* number of data points left to be taken */
 	int irq_dma_bits;	/*  irq/dma register bits */
 	int config_bits;	/*  config register bits */
 };
@@ -158,68 +154,54 @@
 /* interrupt service routine */
 static irqreturn_t a2150_interrupt(int irq, void *d)
 {
-	int i;
-	int status;
-	unsigned long flags;
 	struct comedi_device *dev = d;
 	struct a2150_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[0];
 	struct comedi_subdevice *s = dev->read_subdev;
-	struct comedi_async *async;
-	struct comedi_cmd *cmd;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+	unsigned short *buf = desc->virt_addr;
 	unsigned int max_points, num_points, residue, leftover;
 	unsigned short dpnt;
+	int status;
+	int i;
 
-	if (!dev->attached) {
-		dev_err(dev->class_dev, "premature interrupt\n");
+	if (!dev->attached)
 		return IRQ_HANDLED;
-	}
-	/*  initialize async here to make sure s is not NULL */
-	async = s->async;
-	cmd = &async->cmd;
 
 	status = inw(dev->iobase + STATUS_REG);
-
-	if ((status & INTR_BIT) == 0) {
-		dev_err(dev->class_dev, "spurious interrupt\n");
+	if ((status & INTR_BIT) == 0)
 		return IRQ_NONE;
-	}
 
 	if (status & OVFL_BIT) {
-		dev_err(dev->class_dev, "fifo overflow\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 	}
 
 	if ((status & DMA_TC_BIT) == 0) {
-		dev_err(dev->class_dev,
-			"caught non-dma interrupt?  Aborting.\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 		return IRQ_HANDLED;
 	}
 
-	flags = claim_dma_lock();
-	disable_dma(devpriv->dma);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma);
-
-	/*  figure out how many points to read */
-	max_points = comedi_bytes_to_samples(s, devpriv->dma_transfer_size);
-	/* residue is the number of points left to be done on the dma
+	/*
+	 * residue is the number of bytes left to be done on the dma
 	 * transfer.  It should always be zero at this point unless
 	 * the stop_src is set to external triggering.
 	 */
-	residue = comedi_bytes_to_samples(s, get_dma_residue(devpriv->dma));
-	num_points = max_points - residue;
+	residue = comedi_isadma_disable(desc->chan);
+
+	/*  figure out how many points to read */
+	max_points = comedi_bytes_to_samples(s, desc->size);
+	num_points = max_points - comedi_bytes_to_samples(s, residue);
 	if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT)
 		num_points = devpriv->count;
 
 	/*  figure out how many points will be stored next time */
 	leftover = 0;
 	if (cmd->stop_src == TRIG_NONE) {
-		leftover = comedi_bytes_to_samples(s,
-						   devpriv->dma_transfer_size);
+		leftover = comedi_bytes_to_samples(s, desc->size);
 	} else if (devpriv->count > max_points) {
 		leftover = devpriv->count - max_points;
 		if (leftover > max_points)
@@ -234,7 +216,7 @@
 
 	for (i = 0; i < num_points; i++) {
 		/* write data point to comedi buffer */
-		dpnt = devpriv->dma_buffer[i];
+		dpnt = buf[i];
 		/*  convert from 2's complement to unsigned coding */
 		dpnt ^= 0x8000;
 		comedi_buf_write_samples(s, &dpnt, 1);
@@ -245,14 +227,11 @@
 			}
 		}
 	}
-	/*  re-enable  dma */
+	/* re-enable dma */
 	if (leftover) {
-		set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
-		set_dma_count(devpriv->dma,
-			      comedi_samples_to_bytes(s, leftover));
-		enable_dma(devpriv->dma);
+		desc->size = comedi_samples_to_bytes(s, leftover);
+		comedi_isadma_program(desc);
 	}
-	release_dma_lock(flags);
 
 	comedi_handle_events(dev, s);
 
@@ -265,13 +244,15 @@
 static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct a2150_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[0];
 
 	/*  disable dma on card */
 	devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT;
 	outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
 
 	/*  disable computer's dma */
-	disable_dma(devpriv->dma);
+	comedi_isadma_disable(desc->chan);
 
 	/*  clear fifo and reset triggering circuitry */
 	outw(0, dev->iobase + FIFO_RESET_REG);
@@ -503,10 +484,11 @@
 static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct a2150_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[0];
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
 	unsigned long timer_base = dev->iobase + I8253_BASE_REG;
-	unsigned long lock_flags;
 	unsigned int old_config_bits = devpriv->config_bits;
 	unsigned int trigger_bits;
 
@@ -542,27 +524,19 @@
 	/*  initialize number of samples remaining */
 	devpriv->count = cmd->stop_arg * cmd->chanlist_len;
 
-	/*  enable computer's dma */
-	lock_flags = claim_dma_lock();
-	disable_dma(devpriv->dma);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma);
-	set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
+	comedi_isadma_disable(desc->chan);
+
 	/*  set size of transfer to fill in 1/3 second */
 #define ONE_THIRD_SECOND 333333333
-	devpriv->dma_transfer_size =
-	    sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len *
-	    ONE_THIRD_SECOND / cmd->scan_begin_arg;
-	if (devpriv->dma_transfer_size > A2150_DMA_BUFFER_SIZE)
-		devpriv->dma_transfer_size = A2150_DMA_BUFFER_SIZE;
-	if (devpriv->dma_transfer_size < sizeof(devpriv->dma_buffer[0]))
-		devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]);
-	devpriv->dma_transfer_size -=
-	    devpriv->dma_transfer_size % sizeof(devpriv->dma_buffer[0]);
-	set_dma_count(devpriv->dma, devpriv->dma_transfer_size);
-	enable_dma(devpriv->dma);
-	release_dma_lock(lock_flags);
+	desc->size = comedi_bytes_per_sample(s) * cmd->chanlist_len *
+		    ONE_THIRD_SECOND / cmd->scan_begin_arg;
+	if (desc->size > desc->maxsize)
+		desc->size = desc->maxsize;
+	if (desc->size < comedi_bytes_per_sample(s))
+		desc->size = comedi_bytes_per_sample(s);
+	desc->size -= desc->size % comedi_bytes_per_sample(s);
+
+	comedi_isadma_program(desc);
 
 	/* clear dma interrupt before enabling it, to try and get rid of that
 	 * one spurious interrupt that has been happening */
@@ -677,6 +651,45 @@
 	return n;
 }
 
+static void a2150_alloc_irq_and_dma(struct comedi_device *dev,
+				    struct comedi_devconfig *it)
+{
+	struct a2150_private *devpriv = dev->private;
+	unsigned int irq_num = it->options[1];
+	unsigned int dma_chan = it->options[2];
+
+	/*
+	 * Only IRQs 15, 14, 12-9, and 7-3 are valid.
+	 * Only DMA channels 7-5 and 3-0 are valid.
+	 */
+	if (irq_num > 15 || dma_chan > 7 ||
+	    !((1 << irq_num) & 0xdef8) || !((1 << dma_chan) & 0xef))
+		return;
+
+	if (request_irq(irq_num, a2150_interrupt, 0, dev->board_name, dev))
+		return;
+
+	/* DMA uses 1 buffer */
+	devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan,
+					   A2150_DMA_BUFFER_SIZE,
+					   COMEDI_ISADMA_READ);
+	if (!devpriv->dma) {
+		free_irq(irq_num, dev);
+	} else {
+		dev->irq = irq_num;
+		devpriv->irq_dma_bits = IRQ_LVL_BITS(irq_num) |
+					DMA_CHAN_BITS(dma_chan);
+	}
+}
+
+static void a2150_free_dma(struct comedi_device *dev)
+{
+	struct a2150_private *devpriv = dev->private;
+
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
+}
+
 /* probes board type, returns offset */
 static int a2150_probe(struct comedi_device *dev)
 {
@@ -690,8 +703,6 @@
 	const struct a2150_board *thisboard;
 	struct a2150_private *devpriv;
 	struct comedi_subdevice *s;
-	unsigned int irq = it->options[1];
-	unsigned int dma = it->options[2];
 	static const int timeout = 2000;
 	int i;
 	int ret;
@@ -712,31 +723,8 @@
 	thisboard = dev->board_ptr;
 	dev->board_name = thisboard->name;
 
-	if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) ||
-	    irq == 14 || irq == 15) {
-		ret = request_irq(irq, a2150_interrupt, 0,
-				  dev->board_name, dev);
-		if (ret == 0) {
-			devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
-			dev->irq = irq;
-		}
-	}
-
-	if (dev->irq && dma <= 7 && dma != 4) {
-		ret = request_dma(dma, dev->board_name);
-		if (ret == 0) {
-			devpriv->dma = dma;
-			devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE,
-						      GFP_KERNEL | GFP_DMA);
-			if (!devpriv->dma_buffer)
-				return -ENOMEM;
-
-			disable_dma(dma);
-			set_dma_mode(dma, DMA_MODE_READ);
-
-			devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
-		}
-	}
+	/* an IRQ and DMA are required to support async commands */
+	a2150_alloc_irq_and_dma(dev, it);
 
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
@@ -750,7 +738,7 @@
 	s->maxdata = 0xffff;
 	s->range_table = &range_a2150;
 	s->insn_read = a2150_ai_rinsn;
-	if (dev->irq && devpriv->dma) {
+	if (dev->irq) {
 		dev->read_subdev = s;
 		s->subdev_flags |= SDF_CMD_READ;
 		s->len_chanlist = s->n_chan;
@@ -791,15 +779,9 @@
 
 static void a2150_detach(struct comedi_device *dev)
 {
-	struct a2150_private *devpriv = dev->private;
-
 	if (dev->iobase)
 		outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
-	if (devpriv) {
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		kfree(devpriv->dma_buffer);
-	}
+	a2150_free_dma(dev);
 	comedi_legacy_detach(dev);
 };
 
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 05370a4..9eeaf3c 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -19,8 +19,7 @@
 /*
  * Driver: ni_at_ao
  * Description: National Instruments AT-AO-6/10
- * Devices: (National Instruments) AT-AO-6 [at-ao-6]
- *          (National Instruments) AT-AO-10 [at-ao-10]
+ * Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10)
  * Status: should work
  * Author: David A. Schleef <ds@schleef.org>
  * Updated: Sun Dec 26 12:26:28 EST 2004
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 0c5ff28..301f154 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -300,7 +300,6 @@
 			   struct comedi_devconfig *it)
 {
 	const struct ni_board_struct *boardtype;
-	struct ni_private *devpriv;
 	struct pnp_dev *isapnp_dev;
 	int ret;
 	unsigned long iobase;
@@ -310,7 +309,6 @@
 	ret = ni_alloc_private(dev);
 	if (ret)
 		return ret;
-	devpriv = dev->private;
 
 	iobase = it->options[0];
 	irq = it->options[1];
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 5e472cb..8f6396e 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -51,10 +51,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
 
 /* daqcard700 registers */
 #define DIO_W		0x04	/* WO 8bit */
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 8cfabdb..a208cb3 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -32,11 +32,7 @@
 */
 
 #include <linux/module.h>
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
 
 #include "8255.h"
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 1fbfdb4..a916047 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -17,9 +17,8 @@
 /*
  * Driver: ni_labpc
  * Description: National Instruments Lab-PC (& compatibles)
- * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200]
- *	    (National Instruments) Lab-PC-1200AI [lab-pc-1200ai]
- *	    (National Instruments) Lab-PC+ [lab-pc+]
+ * Devices: [National Instruments] Lab-PC-1200 (lab-pc-1200),
+ *   Lab-PC-1200AI (lab-pc-1200ai), Lab-PC+ (lab-pc+)
  * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
  * Status: works
  *
@@ -85,15 +84,10 @@
 
 static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
-	struct labpc_private *devpriv;
 	unsigned int irq = it->options[1];
 	unsigned int dma_chan = it->options[2];
 	int ret;
 
-	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
-	if (!devpriv)
-		return -ENOMEM;
-
 	ret = comedi_request_region(dev, it->options[0], 0x20);
 	if (ret)
 		return ret;
@@ -110,11 +104,7 @@
 
 static void labpc_detach(struct comedi_device *dev)
 {
-	struct labpc_private *devpriv = dev->private;
-
-	if (devpriv)
-		labpc_free_dma_chan(dev);
-
+	labpc_free_dma_chan(dev);
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index ac2c01f..be89ae4 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -35,6 +35,8 @@
 };
 
 struct labpc_private {
+	struct comedi_isadma *dma;
+
 	/*  number of data points left to be taken */
 	unsigned long long count;
 	/*  software copys of bits written to command registers */
@@ -61,11 +63,7 @@
 	 * conversions
 	 */
 	unsigned int divisor_b1;
-	unsigned int dma_chan;	/*  dma channel to use */
-	u16 *dma_buffer;	/*  buffer ai will dma into */
-	phys_addr_t dma_addr;
-	/* transfer size in bytes for current transfer */
-	unsigned int dma_transfer_size;
+
 	/* we are using dma/fifo-half-full/etc. */
 	enum transfer_type current_transfer;
 	/*
diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c
index d89d585..b88ee26 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_common.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_common.c
@@ -368,10 +368,6 @@
 			     enum scan_mode mode)
 {
 	struct labpc_private *devpriv = dev->private;
-	/* max value for 16 bit counter in mode 2 */
-	const int max_counter_value = 0x10000;
-	/* min value for 16 bit counter in mode 2 */
-	const int min_counter_value = 2;
 	unsigned int base_period;
 	unsigned int scan_period;
 	unsigned int convert_period;
@@ -388,11 +384,10 @@
 		 * clock speed on convert and scan counters)
 		 */
 		devpriv->divisor_b0 = (scan_period - 1) /
-		    (I8254_OSC_BASE_2MHZ * max_counter_value) + 1;
-		if (devpriv->divisor_b0 < min_counter_value)
-			devpriv->divisor_b0 = min_counter_value;
-		if (devpriv->divisor_b0 > max_counter_value)
-			devpriv->divisor_b0 = max_counter_value;
+		    (I8254_OSC_BASE_2MHZ * 0x10000) + 1;
+
+		cfc_check_trigger_arg_min(&devpriv->divisor_b0, 2);
+		cfc_check_trigger_arg_max(&devpriv->divisor_b0, 0x10000);
 
 		base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0;
 
@@ -400,16 +395,16 @@
 		switch (cmd->flags & CMDF_ROUND_MASK) {
 		default:
 		case CMDF_ROUND_NEAREST:
-			devpriv->divisor_a0 =
-			    (convert_period + (base_period / 2)) / base_period;
-			devpriv->divisor_b1 =
-			    (scan_period + (base_period / 2)) / base_period;
+			devpriv->divisor_a0 = DIV_ROUND_CLOSEST(convert_period,
+								base_period);
+			devpriv->divisor_b1 = DIV_ROUND_CLOSEST(scan_period,
+								base_period);
 			break;
 		case CMDF_ROUND_UP:
-			devpriv->divisor_a0 =
-			    (convert_period + (base_period - 1)) / base_period;
-			devpriv->divisor_b1 =
-			    (scan_period + (base_period - 1)) / base_period;
+			devpriv->divisor_a0 = DIV_ROUND_UP(convert_period,
+							   base_period);
+			devpriv->divisor_b1 = DIV_ROUND_UP(scan_period,
+							   base_period);
 			break;
 		case CMDF_ROUND_DOWN:
 			devpriv->divisor_a0 = convert_period / base_period;
@@ -417,14 +412,10 @@
 			break;
 		}
 		/*  make sure a0 and b1 values are acceptable */
-		if (devpriv->divisor_a0 < min_counter_value)
-			devpriv->divisor_a0 = min_counter_value;
-		if (devpriv->divisor_a0 > max_counter_value)
-			devpriv->divisor_a0 = max_counter_value;
-		if (devpriv->divisor_b1 < min_counter_value)
-			devpriv->divisor_b1 = min_counter_value;
-		if (devpriv->divisor_b1 > max_counter_value)
-			devpriv->divisor_b1 = max_counter_value;
+		cfc_check_trigger_arg_min(&devpriv->divisor_a0, 2);
+		cfc_check_trigger_arg_max(&devpriv->divisor_a0, 0x10000);
+		cfc_check_trigger_arg_min(&devpriv->divisor_b1, 2);
+		cfc_check_trigger_arg_max(&devpriv->divisor_b1, 0x10000);
 		/*  write corrected timings to command */
 		labpc_set_ai_convert_period(cmd, mode,
 					    base_period * devpriv->divisor_a0);
@@ -687,7 +678,7 @@
 	}
 
 	/* figure out what method we will use to transfer data */
-	if (labpc_have_dma_chan(dev) &&
+	if (devpriv->dma &&
 	    /* dma unsafe at RT priority,
 	     * and too much setup time for CMDF_WAKE_EOS */
 	    (cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) == 0)
@@ -823,7 +814,7 @@
 	}
 	if (i == timeout) {
 		dev_err(dev->class_dev, "ai timeout, fifo never empties\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		return -1;
 	}
 
@@ -875,7 +866,7 @@
 	if (devpriv->stat1 & STAT1_OVERRUN) {
 		/* clear error interrupt */
 		devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 		dev_err(dev->class_dev, "overrun\n");
 		return IRQ_HANDLED;
@@ -895,7 +886,7 @@
 	if (devpriv->stat1 & STAT1_OVERFLOW) {
 		/*  clear error interrupt */
 		devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		async->events |= COMEDI_CB_ERROR;
 		comedi_handle_events(dev, s);
 		dev_err(dev->class_dev, "overflow\n");
 		return IRQ_HANDLED;
@@ -1215,11 +1206,15 @@
 			unsigned int irq, unsigned long isr_flags)
 {
 	const struct labpc_boardinfo *board = dev->board_ptr;
-	struct labpc_private *devpriv = dev->private;
+	struct labpc_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret;
 	int i;
 
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+	if (!devpriv)
+		return -ENOMEM;
+
 	if (dev->mmio) {
 		devpriv->read_byte = labpc_readb;
 		devpriv->write_byte = labpc_writeb;
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 0a8b322..746c4cd9 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -54,19 +54,11 @@
 */
 
 #include <linux/module.h>
-#include "../comedidev.h"
 
-#include <linux/delay.h>
+#include "../comedi_pcmcia.h"
 
-#include "8253.h"
-#include "8255.h"
-#include "comedi_fc.h"
 #include "ni_labpc.h"
 
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
 static const struct labpc_boardinfo labpc_cs_boards[] = {
 	{
 		.name			= "daqcard-1200",
@@ -80,7 +72,6 @@
 			     unsigned long context)
 {
 	struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
-	struct labpc_private *devpriv;
 	int ret;
 
 	/* The ni_labpc driver needs the board_ptr */
@@ -96,10 +87,6 @@
 	if (!link->irq)
 		return -EINVAL;
 
-	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
-	if (!devpriv)
-		return -ENOMEM;
-
 	return labpc_common_attach(dev, link->irq, IRQF_SHARED);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
index 6d38605..6b4ccd8 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -19,23 +19,25 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+
 #include "../comedidev.h"
 
-#include <asm/dma.h>
-
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
 #include "ni_labpc.h"
 #include "ni_labpc_regs.h"
 #include "ni_labpc_isadma.h"
 
 /* size in bytes of dma buffer */
-static const int dma_buffer_size = 0xff00;
-/* 2 bytes per sample */
-static const int sample_size = 2;
+#define LABPC_ISADMA_BUFFER_SIZE	0xff00
 
 /* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
+static unsigned int labpc_suggest_transfer_size(struct comedi_device *dev,
+						struct comedi_subdevice *s,
+						unsigned int maxbytes)
 {
+	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned int sample_size = comedi_bytes_per_sample(s);
 	unsigned int size;
 	unsigned int freq;
 
@@ -49,8 +51,8 @@
 	size = (freq / 3) * sample_size;
 
 	/* set a minimum and maximum size allowed */
-	if (size > dma_buffer_size)
-		size = dma_buffer_size - dma_buffer_size % sample_size;
+	if (size > maxbytes)
+		size = maxbytes;
 	else if (size < sample_size)
 		size = sample_size;
 
@@ -60,23 +62,18 @@
 void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct labpc_private *devpriv = dev->private;
+	struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
 	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned long irq_flags;
+	unsigned int sample_size = comedi_bytes_per_sample(s);
 
-	irq_flags = claim_dma_lock();
-	disable_dma(devpriv->dma_chan);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma_chan);
-	set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
 	/* set appropriate size of transfer */
-	devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
+	desc->size = labpc_suggest_transfer_size(dev, s, desc->maxsize);
 	if (cmd->stop_src == TRIG_COUNT &&
-	    devpriv->count * sample_size < devpriv->dma_transfer_size)
-		devpriv->dma_transfer_size = devpriv->count * sample_size;
-	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
-	enable_dma(devpriv->dma_chan);
-	release_dma_lock(irq_flags);
+	    devpriv->count * sample_size < desc->size)
+		desc->size = devpriv->count * sample_size;
+
+	comedi_isadma_program(desc);
+
 	/* set CMD3 bits for caller to enable DMA and interrupt */
 	devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
 }
@@ -85,61 +82,55 @@
 void labpc_drain_dma(struct comedi_device *dev)
 {
 	struct labpc_private *devpriv = dev->private;
+	struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
 	struct comedi_subdevice *s = dev->read_subdev;
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
-	int status;
-	unsigned long flags;
-	unsigned int max_points, num_points, residue, leftover;
+	unsigned int max_samples = comedi_bytes_to_samples(s, desc->size);
+	unsigned int residue;
+	unsigned int nsamples;
+	unsigned int leftover;
 
-	status = devpriv->stat1;
-
-	flags = claim_dma_lock();
-	disable_dma(devpriv->dma_chan);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma_chan);
-
-	/* figure out how many points to read */
-	max_points = devpriv->dma_transfer_size / sample_size;
-	/* residue is the number of points left to be done on the dma
+	/*
+	 * residue is the number of bytes left to be done on the dma
 	 * transfer.  It should always be zero at this point unless
 	 * the stop_src is set to external triggering.
 	 */
-	residue = get_dma_residue(devpriv->dma_chan) / sample_size;
-	num_points = max_points - residue;
-	if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points)
-		num_points = devpriv->count;
+	residue = comedi_isadma_disable(desc->chan);
 
-	/* figure out how many points will be stored next time */
-	leftover = 0;
-	if (cmd->stop_src != TRIG_COUNT) {
-		leftover = devpriv->dma_transfer_size / sample_size;
-	} else if (devpriv->count > num_points) {
-		leftover = devpriv->count - num_points;
-		if (leftover > max_points)
-			leftover = max_points;
+	/*
+	 * Figure out how many samples to read for this transfer and
+	 * how many will be stored for next time.
+	 */
+	nsamples = max_samples - comedi_bytes_to_samples(s, residue);
+	if (cmd->stop_src == TRIG_COUNT) {
+		if (devpriv->count <= nsamples) {
+			nsamples = devpriv->count;
+			leftover = 0;
+		} else {
+			leftover = devpriv->count - nsamples;
+			if (leftover > max_samples)
+				leftover = max_samples;
+		}
+		devpriv->count -= nsamples;
+	} else {
+		leftover = max_samples;
 	}
+	desc->size = comedi_samples_to_bytes(s, leftover);
 
-	comedi_buf_write_samples(s, devpriv->dma_buffer, num_points);
-
-	if (cmd->stop_src == TRIG_COUNT)
-		devpriv->count -= num_points;
-
-	/* set address and count for next transfer */
-	set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
-	set_dma_count(devpriv->dma_chan, leftover * sample_size);
-	release_dma_lock(flags);
+	comedi_buf_write_samples(s, desc->virt_addr, nsamples);
 }
 EXPORT_SYMBOL_GPL(labpc_drain_dma);
 
 static void handle_isa_dma(struct comedi_device *dev)
 {
 	struct labpc_private *devpriv = dev->private;
+	struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
 
 	labpc_drain_dma(dev);
 
-	enable_dma(devpriv->dma_chan);
+	if (desc->size)
+		comedi_isadma_program(desc);
 
 	/* clear dma tc interrupt */
 	devpriv->write_byte(dev, 0x1, DMATC_CLEAR_REG);
@@ -160,36 +151,18 @@
 }
 EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
 
-int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
+void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
 {
 	struct labpc_private *devpriv = dev->private;
-	void *dma_buffer;
-	unsigned long dma_flags;
-	int ret;
 
+	/* only DMA channels 3 and 1 are valid */
 	if (dma_chan != 1 && dma_chan != 3)
-		return -EINVAL;
+		return;
 
-	dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
-	if (!dma_buffer)
-		return -ENOMEM;
-
-	ret = request_dma(dma_chan, dev->board_name);
-	if (ret) {
-		kfree(dma_buffer);
-		return ret;
-	}
-
-	devpriv->dma_buffer = dma_buffer;
-	devpriv->dma_chan = dma_chan;
-	devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer);
-
-	dma_flags = claim_dma_lock();
-	disable_dma(devpriv->dma_chan);
-	set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
-	release_dma_lock(dma_flags);
-
-	return 0;
+	/* DMA uses 1 buffer */
+	devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan,
+					   LABPC_ISADMA_BUFFER_SIZE,
+					   COMEDI_ISADMA_READ);
 }
 EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
 
@@ -197,12 +170,8 @@
 {
 	struct labpc_private *devpriv = dev->private;
 
-	kfree(devpriv->dma_buffer);
-	devpriv->dma_buffer = NULL;
-	if (devpriv->dma_chan) {
-		free_dma(devpriv->dma_chan);
-		devpriv->dma_chan = 0;
-	}
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
 }
 EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
index 771af4b..b8a1b0e 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.h
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
@@ -5,18 +5,9 @@
 #ifndef _NI_LABPC_ISADMA_H
 #define _NI_LABPC_ISADMA_H
 
-#define NI_LABPC_HAVE_ISA_DMA	IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
 
-#if NI_LABPC_HAVE_ISA_DMA
-
-static inline bool labpc_have_dma_chan(struct comedi_device *dev)
-{
-	struct labpc_private *devpriv = dev->private;
-
-	return (bool)devpriv->dma_chan;
-}
-
-int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
+void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
 void labpc_free_dma_chan(struct comedi_device *dev);
 void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s);
 void labpc_drain_dma(struct comedi_device *dev);
@@ -24,15 +15,9 @@
 
 #else
 
-static inline bool labpc_have_dma_chan(struct comedi_device *dev)
+static inline void labpc_init_dma_chan(struct comedi_device *dev,
+				       unsigned int dma_chan)
 {
-	return false;
-}
-
-static inline int labpc_init_dma_chan(struct comedi_device *dev,
-				      unsigned int dma_chan)
-{
-	return -ENOTSUPP;
 }
 
 static inline void labpc_free_dma_chan(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 3fc4204..0407ff6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -17,7 +17,7 @@
 /*
  * Driver: ni_labpc_pci
  * Description: National Instruments Lab-PC PCI-1200
- * Devices: (National Instruments) PCI-1200 [ni_pci-1200]
+ * Devices: [National Instruments] PCI-1200 (ni_pci-1200)
  * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
  * Status: works
  *
@@ -79,7 +79,6 @@
 {
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 	const struct labpc_boardinfo *board = NULL;
-	struct labpc_private *devpriv;
 	int ret;
 
 	if (context < ARRAY_SIZE(labpc_pci_boards))
@@ -101,10 +100,6 @@
 	if (!dev->mmio)
 		return -ENOMEM;
 
-	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
-	if (!devpriv)
-		return -ENOMEM;
-
 	return labpc_common_attach(dev, pcidev->irq, IRQF_SHARED);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 11e7017..b6ddc01 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1478,7 +1478,7 @@
 		dev_err(dev->class_dev,
 			"unknown mite interrupt (ai_mite_status=%08x)\n",
 			ai_mite_status);
-		s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		s->async->events |= COMEDI_CB_ERROR;
 		/* disable_irq(dev->irq); */
 	}
 #endif
@@ -1491,8 +1491,7 @@
 			/* we probably aren't even running a command now,
 			 * so it's a good idea to be careful. */
 			if (comedi_is_subdevice_running(s)) {
-				s->async->events |=
-				    COMEDI_CB_ERROR | COMEDI_CB_EOA;
+				s->async->events |= COMEDI_CB_ERROR;
 				comedi_handle_events(dev, s);
 			}
 			return;
@@ -1579,7 +1578,7 @@
 		dev_err(dev->class_dev,
 			"unknown mite interrupt (ao_mite_status=%08x)\n",
 			ao_mite_status);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		s->async->events |= COMEDI_CB_ERROR;
 	}
 #endif
 
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 9b201e4..e3d821b 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -37,16 +37,12 @@
 */
 
 #include <linux/module.h>
-#include "../comedidev.h"
-
 #include <linux/delay.h>
 
+#include "../comedi_pcmcia.h"
 #include "ni_stc.h"
 #include "8255.h"
 
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
 /*
  *  AT specific setup
  */
@@ -163,7 +159,6 @@
 {
 	struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
 	static const struct ni_board_struct *board;
-	struct ni_private *devpriv;
 	int ret;
 
 	board = ni_getboardtype(dev, link);
@@ -188,8 +183,6 @@
 	if (ret)
 		return ret;
 
-	devpriv = dev->private;
-
 	return ni_E_init(dev, 0, 1);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index db7e8aa..db399fe 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -418,7 +418,7 @@
 				 CHSR_DRQ1 | CHSR_MRDY)) {
 			dev_dbg(dev->class_dev,
 				"unknown mite interrupt, disabling IRQ\n");
-			async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+			async->events |= COMEDI_CB_ERROR;
 			disable_irq(dev->irq);
 		}
 	}
@@ -460,7 +460,7 @@
 			break;
 		} else if (flags & Waited) {
 			writeb(ClearWaited, dev->mmio + Group_1_First_Clear);
-			async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+			async->events |= COMEDI_CB_ERROR;
 			break;
 		} else if (flags & PrimaryTC) {
 			writeb(ClearPrimaryTC,
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index 0525292..c20c51b 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -16,29 +16,28 @@
 */
 
 /*
-Driver: ni_tio
-Description: National Instruments general purpose counters
-Devices:
-Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
-	Herman.Bruyninckx@mech.kuleuven.ac.be,
-	Wim.Meeussen@mech.kuleuven.ac.be,
-	Klaas.Gadeyne@mech.kuleuven.ac.be,
-	Frank Mori Hess <fmhess@users.sourceforge.net>
-Updated: Thu Nov 16 09:50:32 EST 2006
-Status: works
+ * Module: ni_tio
+ * Description: National Instruments general purpose counters
+ * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
+ *         Herman.Bruyninckx@mech.kuleuven.ac.be,
+ *         Wim.Meeussen@mech.kuleuven.ac.be,
+ *         Klaas.Gadeyne@mech.kuleuven.ac.be,
+ *         Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Updated: Thu Nov 16 09:50:32 EST 2006
+ * Status: works
+ *
+ * This module is not used directly by end-users.  Rather, it
+ * is used by other drivers (for example ni_660x and ni_pcimio)
+ * to provide support for NI's general purpose counters.  It was
+ * originally based on the counter code from ni_660x.c and
+ * ni_mio_common.c.
+ *
+ * References:
+ * DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
+ * DAQ 6601/6602 User Manual (NI 322137B-01)
+ * 340934b.pdf  DAQ-STC reference manual
+ */
 
-This module is not used directly by end-users.  Rather, it
-is used by other drivers (for example ni_660x and ni_pcimio)
-to provide support for NI's general purpose counters.  It was
-originally based on the counter code from ni_660x.c and
-ni_mio_common.c.
-
-References:
-DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
-DAQ 6601/6602 User Manual (NI 322137B-01)
-340934b.pdf  DAQ-STC reference manual
-
-*/
 /*
 TODO:
 	Support use of both banks X and Y
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 6037bec..d36c3ab 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -16,29 +16,28 @@
 */
 
 /*
-Driver: ni_tiocmd
-Description: National Instruments general purpose counters command support
-Devices:
-Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
-	Herman.Bruyninckx@mech.kuleuven.ac.be,
-	Wim.Meeussen@mech.kuleuven.ac.be,
-	Klaas.Gadeyne@mech.kuleuven.ac.be,
-	Frank Mori Hess <fmhess@users.sourceforge.net>
-Updated: Fri, 11 Apr 2008 12:32:35 +0100
-Status: works
+ * Module: ni_tiocmd
+ * Description: National Instruments general purpose counters command support
+ * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
+ *         Herman.Bruyninckx@mech.kuleuven.ac.be,
+ *         Wim.Meeussen@mech.kuleuven.ac.be,
+ *         Klaas.Gadeyne@mech.kuleuven.ac.be,
+ *         Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Updated: Fri, 11 Apr 2008 12:32:35 +0100
+ * Status: works
+ *
+ * This module is not used directly by end-users.  Rather, it
+ * is used by other drivers (for example ni_660x and ni_pcimio)
+ * to provide command support for NI's general purpose counters.
+ * It was originally split out of ni_tio.c to stop the 'ni_tio'
+ * module depending on the 'mite' module.
+ *
+ * References:
+ * DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
+ * DAQ 6601/6602 User Manual (NI 322137B-01)
+ * 340934b.pdf  DAQ-STC reference manual
+ */
 
-This module is not used directly by end-users.  Rather, it
-is used by other drivers (for example ni_660x and ni_pcimio)
-to provide command support for NI's general purpose counters.
-It was originally split out of ni_tio.c to stop the 'ni_tio'
-module depending on the 'mite' module.
-
-References:
-DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
-DAQ 6601/6602 User Manual (NI 322137B-01)
-340934b.pdf  DAQ-STC reference manual
-
-*/
 /*
 TODO:
 	Support use of both banks X and Y
diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c
index 3b5a1b9..5f649f8 100644
--- a/drivers/staging/comedi/drivers/ni_usb6501.c
+++ b/drivers/staging/comedi/drivers/ni_usb6501.c
@@ -96,9 +96,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/usb.h>
 
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 #define	NI6501_TIMEOUT	1000
 
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 938aebc..cb7e4c3 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -22,10 +22,8 @@
 /*
  * Driver: pcl711
  * Description: Advantech PCL-711 and 711b, ADLink ACL-8112
- * Devices: (Advantech) PCL-711 [pcl711]
- *	    (Advantech) PCL-711B [pcl711b]
- *	    (AdLink) ACL-8112HG [acl8112hg]
- *	    (AdLink) ACL-8112DG [acl8112dg]
+ * Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b),
+ *   [ADLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg)
  * Author: David A. Schleef <ds@schleef.org>
  *	   Janne Jalkanen <jalkanen@cs.hut.fi>
  *	   Eric Bunn <ebu@cs.hut.fi>
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index fcc4408..74b07e1 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -8,14 +8,10 @@
 /*
  * Driver: pcl724
  * Description: Comedi driver for 8255 based ISA DIO boards
- * Devices: (Advantech) PCL-724 [pcl724]
- *	    (Advantech) PCL-722 [pcl722]
- *	    (Advantech) PCL-731 [pcl731]
- *	    (ADLink) ACL-7122 [acl7122]
- *	    (ADLink) ACL-7124 [acl7124]
- *	    (ADLink) PET-48DIO [pet48dio]
- *	    (WinSystems) PCM-IO48 [pcmio48]
- *	    (Diamond Systems) ONYX-MM-DIO [onyx-mm-dio]
+ * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731),
+ *  [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio),
+ *  [WinSystems] PCM-IO48 (pcmio48),
+ *  [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio)
  * Author: Michal Dobes <dobes@tesnet.cz>
  * Status: untested
  *
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 86f713f..4079815 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -21,11 +21,8 @@
  * Description: Advantech PCL-726 & compatibles
  * Author: David A. Schleef <ds@schleef.org>
  * Status: untested
- * Devices: (Advantech) PCL-726 [pcl726]
- *	    (Advantech) PCL-727 [pcl727]
- *	    (Advantech) PCL-728 [pcl728]
- *	    (ADLink) ACL-6126 [acl6126]
- *	    (ADLink) ACL-6128 [acl6128]
+ * Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728),
+ *   [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128)
  *
  * Configuration Options:
  *   [0]  - IO Base
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index a6c5770..ce958ee 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -7,19 +7,12 @@
 /*
  * Driver: pcl730
  * Description: Advantech PCL-730 (& compatibles)
- * Devices: (Advantech) PCL-730 [pcl730]
- *	    (ICP) ISO-730 [iso730]
- *	    (Adlink) ACL-7130 [acl7130]
- *	    (Advantech) PCM-3730 [pcm3730]
- *	    (Advantech) PCL-725 [pcl725]
- *	    (ICP) P8R8-DIO [p16r16dio]
- *	    (Adlink) ACL-7225b [acl7225b]
- *	    (ICP) P16R16-DIO [p16r16dio]
- *	    (Advantech) PCL-733 [pcl733]
- *	    (Advantech) PCL-734 [pcl734]
- *	    (Diamond Systems) OPMM-1616-XT [opmm-1616-xt]
- *	    (Diamond Systems) PEARL-MM-P [prearl-mm-p]
- *	    (Diamond Systems) IR104-PBF [ir104-pbf]
+ * Devices: [Advantech] PCL-730 (pcl730), PCM-3730 (pcm3730), PCL-725 (pcl725),
+ *   PCL-733 (pcl733), PCL-734 (pcl734),
+ *   [ADLink] ACL-7130 (acl7130), ACL-7225b (acl7225b),
+ *   [ICP] ISO-730 (iso730), P8R8-DIO (p8r8dio), P16R16-DIO (p16r16dio),
+ *   [Diamond Systems] OPMM-1616-XT (opmm-1616-xt), PEARL-MM-P (pearl-mm-p),
+ *   IR104-PBF (ir104-pbf),
  * Author: José Luis Sánchez (jsanchezv@teleline.es)
  * Status: untested
  *
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index ac243ca..3ffb1ea 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -111,12 +111,12 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/gfp.h>
-#include "../comedidev.h"
-
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <asm/dma.h>
 
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
 #include "8253.h"
 
@@ -507,19 +507,11 @@
 };
 
 struct pcl812_private {
-	unsigned char dma;	/*  >0 use dma ( usedDMA channel) */
+	struct comedi_isadma *dma;
 	unsigned char range_correction;	/*  =1 we must add 1 to range number */
 	unsigned int last_ai_chanspec;
 	unsigned char mode_reg_int;	/*  there is stored INT number for some card */
 	unsigned int ai_poll_ptr;	/*  how many sampes transfer poll */
-	unsigned int dmapages;
-	unsigned int hwdmasize;
-	unsigned long dmabuf[2];	/*  PTR to DMA buf */
-	unsigned int hwdmaptr[2];	/*  HW PTR to DMA buf */
-	unsigned int dmabytestomove[2];	/*  how many bytes DMA transfer */
-	int next_dma_buf;	/*  which buffer is next to use */
-	unsigned int dma_runs_to_end;	/*  how many times we must switch DMA buffers */
-	unsigned int last_dma_run;	/*  how many bytes to transfer on last DMA buffer */
 	unsigned int max_812_ai_mode0_rangewait;	/*  setling time for gain */
 	unsigned int divisor1;
 	unsigned int divisor2;
@@ -546,90 +538,32 @@
 }
 
 static void pcl812_ai_setup_dma(struct comedi_device *dev,
-				struct comedi_subdevice *s)
+				struct comedi_subdevice *s,
+				unsigned int unread_samples)
 {
 	struct pcl812_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int dma_flags;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
 	unsigned int bytes;
+	unsigned int max_samples;
+	unsigned int nsamples;
 
-	/*  we use EOS, so adapt DMA buffer to one scan */
-	if (devpriv->ai_eos) {
-		devpriv->dmabytestomove[0] = comedi_bytes_per_scan(s);
-		devpriv->dmabytestomove[1] = comedi_bytes_per_scan(s);
-		devpriv->dma_runs_to_end = 1;
-	} else {
-		devpriv->dmabytestomove[0] = devpriv->hwdmasize;
-		devpriv->dmabytestomove[1] = devpriv->hwdmasize;
-		if (s->async->prealloc_bufsz < devpriv->hwdmasize) {
-			devpriv->dmabytestomove[0] =
-				s->async->prealloc_bufsz;
-			devpriv->dmabytestomove[1] =
-				s->async->prealloc_bufsz;
-		}
-		if (cmd->stop_src == TRIG_NONE) {
-			devpriv->dma_runs_to_end = 1;
-		} else {
-			/*  how many samples we must transfer? */
-			bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
+	comedi_isadma_disable(dma->chan);
 
-			/*  how many DMA pages we must fill */
-			devpriv->dma_runs_to_end =
-				bytes / devpriv->dmabytestomove[0];
+	/* if using EOS, adapt DMA buffer to one scan */
+	bytes = devpriv->ai_eos ? comedi_bytes_per_scan(s) : desc->maxsize;
+	max_samples = comedi_bytes_to_samples(s, bytes);
 
-			/* on last dma transfer must be moved */
-			devpriv->last_dma_run =
-				bytes % devpriv->dmabytestomove[0];
-			if (devpriv->dma_runs_to_end == 0)
-				devpriv->dmabytestomove[0] =
-					devpriv->last_dma_run;
-			devpriv->dma_runs_to_end--;
-		}
+	/*
+	 * Determine dma size based on the buffer size plus the number of
+	 * unread samples and the number of samples remaining in the command.
+	 */
+	nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+	if (nsamples > unread_samples) {
+		nsamples -= unread_samples;
+		desc->size = comedi_samples_to_bytes(s, nsamples);
+		comedi_isadma_program(desc);
 	}
-	if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) {
-		devpriv->dmabytestomove[0] = devpriv->hwdmasize;
-		devpriv->ai_eos = 0;
-	}
-	if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
-		devpriv->dmabytestomove[1] = devpriv->hwdmasize;
-		devpriv->ai_eos = 0;
-	}
-	devpriv->next_dma_buf = 0;
-	set_dma_mode(devpriv->dma, DMA_MODE_READ);
-	dma_flags = claim_dma_lock();
-	clear_dma_ff(devpriv->dma);
-	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
-	set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
-	release_dma_lock(dma_flags);
-	enable_dma(devpriv->dma);
-}
-
-static void pcl812_ai_setup_next_dma(struct comedi_device *dev,
-				     struct comedi_subdevice *s)
-{
-	struct pcl812_private *devpriv = dev->private;
-	unsigned long dma_flags;
-
-	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
-	disable_dma(devpriv->dma);
-	set_dma_mode(devpriv->dma, DMA_MODE_READ);
-	dma_flags = claim_dma_lock();
-	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
-	if (devpriv->ai_eos) {
-		set_dma_count(devpriv->dma,
-			      devpriv->dmabytestomove[devpriv->next_dma_buf]);
-	} else {
-		if (devpriv->dma_runs_to_end) {
-			set_dma_count(devpriv->dma,
-				      devpriv->dmabytestomove[devpriv->
-							      next_dma_buf]);
-		} else {
-			set_dma_count(devpriv->dma, devpriv->last_dma_run);
-		}
-		devpriv->dma_runs_to_end--;
-	}
-	release_dma_lock(dma_flags);
-	enable_dma(devpriv->dma);
 }
 
 static void pcl812_ai_set_chan_range(struct comedi_device *dev,
@@ -786,6 +720,7 @@
 static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct pcl812_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int ctrl = 0;
 	unsigned int i;
@@ -794,7 +729,7 @@
 
 	pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1);
 
-	if (devpriv->dma) {	/*  check if we can use DMA transfer */
+	if (dma) {	/*  check if we can use DMA transfer */
 		devpriv->ai_dma = 1;
 		for (i = 1; i < cmd->chanlist_len; i++)
 			if (cmd->chanlist[0] != cmd->chanlist[i]) {
@@ -817,8 +752,11 @@
 			devpriv->ai_dma = 0;
 	}
 
-	if (devpriv->ai_dma)
-		pcl812_ai_setup_dma(dev, s);
+	if (devpriv->ai_dma) {
+		/* setup and enable dma for the first buffer */
+		dma->cur_dma = 0;
+		pcl812_ai_setup_dma(dev, s, 0);
+	}
 
 	switch (cmd->convert_src) {
 	case TRIG_TIMER:
@@ -859,7 +797,7 @@
 
 	if (pcl812_ai_eoc(dev, s, NULL, 0)) {
 		dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n");
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
@@ -895,19 +833,21 @@
 			      struct comedi_subdevice *s)
 {
 	struct pcl812_private *devpriv = dev->private;
-	int len, bufptr;
-	unsigned short *ptr;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int nsamples;
+	int bufptr;
 
-	ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
-	len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
-	    devpriv->ai_poll_ptr;
-
-	pcl812_ai_setup_next_dma(dev, s);
-
+	nsamples = comedi_bytes_to_samples(s, desc->size) -
+		   devpriv->ai_poll_ptr;
 	bufptr = devpriv->ai_poll_ptr;
 	devpriv->ai_poll_ptr = 0;
 
-	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
+	/* restart dma with the next buffer */
+	dma->cur_dma = 1 - dma->cur_dma;
+	pcl812_ai_setup_dma(dev, s, nsamples);
+
+	transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples);
 }
 
 static irqreturn_t pcl812_interrupt(int irq, void *d)
@@ -935,45 +875,37 @@
 static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct pcl812_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc;
 	unsigned long flags;
-	unsigned int top1, top2, i;
+	unsigned int poll;
+	int ret;
 
+	/* poll is valid only for DMA transfer */
 	if (!devpriv->ai_dma)
-		return 0;	/*  poll is valid only for DMA transfer */
+		return 0;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 
-	for (i = 0; i < 10; i++) {
-		/*  where is now DMA */
-		top1 = get_dma_residue(devpriv->ai_dma);
-		top2 = get_dma_residue(devpriv->ai_dma);
-		if (top1 == top2)
-			break;
-	}
+	poll = comedi_isadma_poll(dma);
+	poll = comedi_bytes_to_samples(s, poll);
+	if (poll > devpriv->ai_poll_ptr) {
+		desc = &dma->desc[dma->cur_dma];
+		transfer_from_dma_buf(dev, s, desc->virt_addr,
+				      devpriv->ai_poll_ptr,
+				      poll - devpriv->ai_poll_ptr);
+		/* new buffer position */
+		devpriv->ai_poll_ptr = poll;
 
-	if (top1 != top2) {
-		spin_unlock_irqrestore(&dev->spinlock, flags);
-		return 0;
+		ret = comedi_buf_n_bytes_ready(s);
+	} else {
+		/* no new samples */
+		ret = 0;
 	}
-	/*  where is now DMA in buffer */
-	top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
-	top1 >>= 1;		/*  sample position */
-	top2 = top1 - devpriv->ai_poll_ptr;
-	if (top2 < 1) {		/*  no new samples */
-		spin_unlock_irqrestore(&dev->spinlock, flags);
-		return 0;
-	}
-
-	transfer_from_dma_buf(dev, s,
-			      (void *)devpriv->dmabuf[1 -
-						      devpriv->next_dma_buf],
-			      devpriv->ai_poll_ptr, top2);
-
-	devpriv->ai_poll_ptr = top1;	/*  new buffer position */
 
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 
-	return comedi_buf_n_bytes_ready(s);
+	return ret;
 }
 
 static int pcl812_ai_cancel(struct comedi_device *dev,
@@ -982,7 +914,7 @@
 	struct pcl812_private *devpriv = dev->private;
 
 	if (devpriv->ai_dma)
-		disable_dma(devpriv->dma);
+		comedi_isadma_disable(devpriv->dma->chan);
 
 	outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
 	     dev->iobase + PCL812_CTRL_REG);
@@ -1192,6 +1124,27 @@
 	}
 }
 
+static void pcl812_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+	struct pcl812_private *devpriv = dev->private;
+
+	/* only DMA channels 3 and 1 are valid */
+	if (!(dma_chan == 3 || dma_chan == 1))
+		return;
+
+	/* DMA uses two 8K buffers */
+	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+					   PAGE_SIZE * 2, COMEDI_ISADMA_READ);
+}
+
+static void pcl812_free_dma(struct comedi_device *dev)
+{
+	struct pcl812_private *devpriv = dev->private;
+
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
+}
+
 static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct pcl812_board *board = dev->board_ptr;
@@ -1200,7 +1153,6 @@
 	int n_subdevices;
 	int subdev;
 	int ret;
-	int i;
 
 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
@@ -1218,31 +1170,8 @@
 	}
 
 	/* we need an IRQ to do DMA on channel 3 or 1 */
-	if (dev->irq && board->has_dma &&
-	    (it->options[2] == 3 || it->options[2] == 1)) {
-		ret = request_dma(it->options[2], dev->board_name);
-		if (ret) {
-			dev_err(dev->class_dev,
-				"unable to request DMA channel %d\n",
-				it->options[2]);
-			return -EBUSY;
-		}
-		devpriv->dma = it->options[2];
-
-		devpriv->dmapages = 1;	/* we want 8KB */
-		devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
-		for (i = 0; i < 2; i++) {
-			unsigned long dmabuf;
-
-			dmabuf =  __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
-			if (!dmabuf)
-				return -ENOMEM;
-
-			devpriv->dmabuf[i] = dmabuf;
-			devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
-		}
-	}
+	if (dev->irq && board->has_dma)
+		 pcl812_alloc_dma(dev, it->options[2]);
 
 	/* differential analog inputs? */
 	switch (board->board_type) {
@@ -1384,16 +1313,7 @@
 
 static void pcl812_detach(struct comedi_device *dev)
 {
-	struct pcl812_private *devpriv = dev->private;
-
-	if (devpriv) {
-		if (devpriv->dmabuf[0])
-			free_pages(devpriv->dmabuf[0], devpriv->dmapages);
-		if (devpriv->dmabuf[1])
-			free_pages(devpriv->dmabuf[1], devpriv->dmapages);
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-	}
+	pcl812_free_dma(dev);
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 73deb4b..da35edf 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -33,14 +33,14 @@
 */
 
 #include <linux/module.h>
-#include "../comedidev.h"
-
 #include <linux/gfp.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
 
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
 #include "8253.h"
 
@@ -114,14 +114,7 @@
 };
 
 struct pcl816_private {
-	unsigned int dma;	/*  used DMA, 0=don't use DMA */
-	unsigned int dmapages;
-	unsigned int hwdmasize;
-	unsigned long dmabuf[2];	/*  pointers to begin of DMA buffers */
-	unsigned int hwdmaptr[2];	/*  hardware address of DMA buffers */
-	int next_dma_buf;	/*  which DMA buffer will be used next round */
-	long dma_runs_to_end;	/*  how many we must permorm DMA transfer to end of record */
-	unsigned long last_dma_run;	/*  how many bytes we must transfer on last DMA page */
+	struct comedi_isadma *dma;
 	unsigned int ai_poll_ptr;	/*  how many sampes transfer poll */
 	unsigned int divisor1;
 	unsigned int divisor2;
@@ -149,63 +142,27 @@
 }
 
 static void pcl816_ai_setup_dma(struct comedi_device *dev,
-				struct comedi_subdevice *s)
+				struct comedi_subdevice *s,
+				unsigned int unread_samples)
 {
 	struct pcl816_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int dma_flags;
-	unsigned int bytes;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+	unsigned int nsamples;
 
-	bytes = devpriv->hwdmasize;
-	if (cmd->stop_src == TRIG_COUNT) {
-		/*  how many */
-		bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
+	comedi_isadma_disable(dma->chan);
 
-		/*  how many DMA pages we must fill */
-		devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
-
-		/* on last dma transfer must be moved */
-		devpriv->last_dma_run = bytes % devpriv->hwdmasize;
-		devpriv->dma_runs_to_end--;
-		if (devpriv->dma_runs_to_end >= 0)
-			bytes = devpriv->hwdmasize;
-	} else
-		devpriv->dma_runs_to_end = -1;
-
-	devpriv->next_dma_buf = 0;
-	set_dma_mode(devpriv->dma, DMA_MODE_READ);
-	dma_flags = claim_dma_lock();
-	clear_dma_ff(devpriv->dma);
-	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
-	set_dma_count(devpriv->dma, bytes);
-	release_dma_lock(dma_flags);
-	enable_dma(devpriv->dma);
-}
-
-static void pcl816_ai_setup_next_dma(struct comedi_device *dev,
-				     struct comedi_subdevice *s)
-{
-	struct pcl816_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned long dma_flags;
-
-	disable_dma(devpriv->dma);
-	if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
-		/* switch dma bufs */
-		devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
-		set_dma_mode(devpriv->dma, DMA_MODE_READ);
-		dma_flags = claim_dma_lock();
-		set_dma_addr(devpriv->dma,
-			     devpriv->hwdmaptr[devpriv->next_dma_buf]);
-		if (devpriv->dma_runs_to_end)
-			set_dma_count(devpriv->dma, devpriv->hwdmasize);
-		else
-			set_dma_count(devpriv->dma, devpriv->last_dma_run);
-		release_dma_lock(dma_flags);
-		enable_dma(devpriv->dma);
+	/*
+	 * Determine dma size based on the buffer maxsize plus the number of
+	 * unread samples and the number of samples remaining in the command.
+	 */
+	nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+	if (nsamples > unread_samples) {
+		nsamples -= unread_samples;
+		desc->size = comedi_samples_to_bytes(s, nsamples);
+		comedi_isadma_program(desc);
 	}
-
-	devpriv->dma_runs_to_end--;
 }
 
 static void pcl816_ai_set_chan_range(struct comedi_device *dev,
@@ -318,9 +275,10 @@
 	struct comedi_device *dev = d;
 	struct comedi_subdevice *s = dev->read_subdev;
 	struct pcl816_private *devpriv = dev->private;
-	unsigned short *ptr;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int nsamples;
 	unsigned int bufptr;
-	unsigned int len;
 
 	if (!dev->attached || !devpriv->ai_cmd_running) {
 		pcl816_ai_clear_eoc(dev);
@@ -333,15 +291,16 @@
 		return IRQ_HANDLED;
 	}
 
-	ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
-
-	pcl816_ai_setup_next_dma(dev, s);
-
-	len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr;
+	nsamples = comedi_bytes_to_samples(s, desc->size) -
+		   devpriv->ai_poll_ptr;
 	bufptr = devpriv->ai_poll_ptr;
 	devpriv->ai_poll_ptr = 0;
 
-	transfer_from_dma_buf(dev, s, ptr, bufptr, len);
+	/* restart dma with the next buffer */
+	dma->cur_dma = 1 - dma->cur_dma;
+	pcl816_ai_setup_dma(dev, s, nsamples);
+
+	transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples);
 
 	pcl816_ai_clear_eoc(dev);
 
@@ -483,6 +442,7 @@
 static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct pcl816_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int ctrl;
 	unsigned int seglen;
@@ -502,7 +462,9 @@
 	devpriv->ai_poll_ptr = 0;
 	devpriv->ai_cmd_canceled = 0;
 
-	pcl816_ai_setup_dma(dev, s);
+	/* setup and enable dma for the first buffer */
+	dma->cur_dma = 0;
+	pcl816_ai_setup_dma(dev, s, 0);
 
 	pcl816_start_pacer(dev, true);
 
@@ -513,7 +475,8 @@
 		ctrl |= PCL816_CTRL_EXT_TRIG;
 
 	outb(ctrl, dev->iobase + PCL816_CTRL_REG);
-	outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG);
+	outb((dma->chan << 4) | dev->irq,
+	     dev->iobase + PCL816_STATUS_REG);
 
 	return 0;
 }
@@ -521,42 +484,34 @@
 static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct pcl816_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc;
 	unsigned long flags;
-	unsigned int top1, top2, i;
+	unsigned int poll;
+	int ret;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
 
-	for (i = 0; i < 20; i++) {
-		top1 = get_dma_residue(devpriv->dma);	/*  where is now DMA */
-		top2 = get_dma_residue(devpriv->dma);
-		if (top1 == top2)
-			break;
-	}
-	if (top1 != top2) {
-		spin_unlock_irqrestore(&dev->spinlock, flags);
-		return 0;
-	}
+	poll = comedi_isadma_poll(dma);
+	poll = comedi_bytes_to_samples(s, poll);
+	if (poll > devpriv->ai_poll_ptr) {
+		desc = &dma->desc[dma->cur_dma];
+		transfer_from_dma_buf(dev, s, desc->virt_addr,
+				      devpriv->ai_poll_ptr,
+				      poll - devpriv->ai_poll_ptr);
+		/* new buffer position */
+		devpriv->ai_poll_ptr = poll;
 
-	/*  where is now DMA in buffer */
-	top1 = devpriv->hwdmasize - top1;
-	top1 >>= 1;		/*  sample position */
-	top2 = top1 - devpriv->ai_poll_ptr;
-	if (top2 < 1) {		/*  no new samples */
-		spin_unlock_irqrestore(&dev->spinlock, flags);
-		return 0;
+		comedi_handle_events(dev, s);
+
+		ret = comedi_buf_n_bytes_ready(s);
+	} else {
+		/* no new samples */
+		ret = 0;
 	}
-
-	transfer_from_dma_buf(dev, s,
-			      (unsigned short *)devpriv->dmabuf[devpriv->
-								next_dma_buf],
-			      devpriv->ai_poll_ptr, top2);
-
-	devpriv->ai_poll_ptr = top1;	/*  new buffer position */
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 
-	comedi_handle_events(dev, s);
-
-	return comedi_buf_n_bytes_ready(s);
+	return ret;
 }
 
 static int pcl816_ai_cancel(struct comedi_device *dev,
@@ -657,13 +612,44 @@
 	outb(0, dev->iobase + PCL816_DO_DI_MSB_REG);
 }
 
+static void pcl816_alloc_irq_and_dma(struct comedi_device *dev,
+				     struct comedi_devconfig *it)
+{
+	struct pcl816_private *devpriv = dev->private;
+	unsigned int irq_num = it->options[1];
+	unsigned int dma_chan = it->options[2];
+
+	/* only IRQs 2-7 and DMA channels 3 and 1 are valid */
+	if (!(irq_num >= 2 && irq_num <= 7) ||
+	    !(dma_chan == 3 || dma_chan == 1))
+		return;
+
+	if (request_irq(irq_num, pcl816_interrupt, 0, dev->board_name, dev))
+		return;
+
+	/* DMA uses two 16K buffers */
+	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+					   PAGE_SIZE * 4, COMEDI_ISADMA_READ);
+	if (!devpriv->dma)
+		free_irq(irq_num, dev);
+	else
+		dev->irq = irq_num;
+}
+
+static void pcl816_free_dma(struct comedi_device *dev)
+{
+	struct pcl816_private *devpriv = dev->private;
+
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
+}
+
 static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct pcl816_board *board = dev->board_ptr;
 	struct pcl816_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret;
-	int i;
 
 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
@@ -673,39 +659,8 @@
 	if (ret)
 		return ret;
 
-	/* we can use IRQ 2-7 for async command support */
-	if (it->options[1] >= 2 && it->options[1] <= 7) {
-		ret = request_irq(it->options[1], pcl816_interrupt, 0,
-				  dev->board_name, dev);
-		if (ret == 0)
-			dev->irq = it->options[1];
-	}
-
-	/* we need an IRQ to do DMA on channel 3 or 1 */
-	if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) {
-		ret = request_dma(it->options[2], dev->board_name);
-		if (ret) {
-			dev_err(dev->class_dev,
-				"unable to request DMA channel %d\n",
-				it->options[2]);
-			return -EBUSY;
-		}
-		devpriv->dma = it->options[2];
-
-		devpriv->dmapages = 2;	/* we need 16KB */
-		devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
-		for (i = 0; i < 2; i++) {
-			unsigned long dmabuf;
-
-			dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
-			if (!dmabuf)
-				return -ENOMEM;
-
-			devpriv->dmabuf[i] = dmabuf;
-			devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
-		}
-	}
+	/* an IRQ and DMA are required to support async commands */
+	pcl816_alloc_irq_and_dma(dev, it);
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
@@ -718,7 +673,7 @@
 	s->maxdata	= board->ai_maxdata;
 	s->range_table	= &range_pcl816;
 	s->insn_read	= pcl816_ai_insn_read;
-	if (devpriv->dma) {
+	if (dev->irq) {
 		dev->read_subdev = s;
 		s->subdev_flags	|= SDF_CMD_READ;
 		s->len_chanlist	= board->ai_chanlist;
@@ -764,18 +719,11 @@
 
 static void pcl816_detach(struct comedi_device *dev)
 {
-	struct pcl816_private *devpriv = dev->private;
-
 	if (dev->private) {
 		pcl816_ai_cancel(dev, dev->read_subdev);
 		pcl816_reset(dev);
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		if (devpriv->dmabuf[0])
-			free_pages(devpriv->dmabuf[0], devpriv->dmapages);
-		if (devpriv->dmabuf[1])
-			free_pages(devpriv->dmabuf[1], devpriv->dmapages);
 	}
+	pcl816_free_dma(dev);
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 8edea35..7e4cdea 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -1,112 +1,105 @@
 /*
-   comedi/drivers/pcl818.c
-
-   Author:  Michal Dobes <dobes@tesnet.cz>
-
-   hardware driver for Advantech cards:
-    card:   PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
-    driver: pcl818l,  pcl818h,  pcl818hd,  pcl818hg,  pcl818,  pcl718
-*/
-/*
-Driver: pcl818
-Description: Advantech PCL-818 cards, PCL-718
-Author: Michal Dobes <dobes@tesnet.cz>
-Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
-  PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
-  PCL-718 (pcl718)
-Status: works
-
-All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
-Differences are only at maximal sample speed, range list and FIFO
-support.
-The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
-only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
-PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
-but this code is untested.
-A word or two about DMA. Driver support DMA operations at two ways:
-1) DMA uses two buffers and after one is filled then is generated
-   INT and DMA restart with second buffer. With this mode I'm unable run
-   more that 80Ksamples/secs without data dropouts on K6/233.
-2) DMA uses one buffer and run in autoinit mode and the data are
-   from DMA buffer moved on the fly with 2kHz interrupts from RTC.
-   This mode is used if the interrupt 8 is available for allocation.
-   If not, then first DMA mode is used. With this I can run at
-   full speed one card (100ksamples/secs) or two cards with
-   60ksamples/secs each (more is problem on account of ISA limitations).
-   To use this mode you must have compiled  kernel with disabled
-   "Enhanced Real Time Clock Support".
-   Maybe you can have problems if you use xntpd or similar.
-   If you've data dropouts with DMA mode 2 then:
-    a) disable IDE DMA
-    b) switch text mode console to fb.
-
-   Options for PCL-818L:
-    [0] - IO Base
-    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
-    [2] - DMA	(0=disable, 1, 3)
-    [3] - 0, 10=10MHz clock for 8254
-              1= 1MHz clock for 8254
-    [4] - 0,  5=A/D input  -5V.. +5V
-          1, 10=A/D input -10V..+10V
-    [5] - 0,  5=D/A output 0-5V  (internal reference -5V)
-          1, 10=D/A output 0-10V (internal reference -10V)
-	  2    =D/A output unknown (external reference)
-
-   Options for PCL-818, PCL-818H:
-    [0] - IO Base
-    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
-    [2] - DMA	(0=disable, 1, 3)
-    [3] - 0, 10=10MHz clock for 8254
-              1= 1MHz clock for 8254
-    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
-          1, 10=D/A output 0-10V (internal reference -10V)
-	  2    =D/A output unknown (external reference)
-
-   Options for PCL-818HD, PCL-818HG:
-    [0] - IO Base
-    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
-    [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,
-                      1=use DMA ch 1, 3=use DMA ch 3)
-    [3] - 0, 10=10MHz clock for 8254
-              1= 1MHz clock for 8254
-    [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
-          1, 10=D/A output 0-10V (internal reference -10V)
-   	  2    =D/A output unknown (external reference)
-
-   Options for PCL-718:
-    [0] - IO Base
-    [1] - IRQ	(0=disable, 2, 3, 4, 5, 6, 7)
-    [2] - DMA	(0=disable, 1, 3)
-    [3] - 0, 10=10MHz clock for 8254
-              1= 1MHz clock for 8254
-    [4] -     0=A/D Range is +/-10V
-	      1=             +/-5V
-	      2=             +/-2.5V
-	      3=             +/-1V
-	      4=             +/-0.5V
-	      5=  	     user defined bipolar
-	      6=	     0-10V
-	      7=	     0-5V
- 	      8=	     0-2V
-	      9=	     0-1V
-	     10=	     user defined unipolar
-    [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)
-          1, 10=D/A outputs 0-10V (internal reference -10V)
-	      2=D/A outputs unknown (external reference)
-    [6] - 0, 60=max  60kHz A/D sampling
-          1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
-
-*/
+ * comedi/drivers/pcl818.c
+ *
+ * Driver: pcl818
+ * Description: Advantech PCL-818 cards, PCL-718
+ * Author: Michal Dobes <dobes@tesnet.cz>
+ * Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
+ *   PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
+ *   PCL-718 (pcl718)
+ * Status: works
+ *
+ * All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
+ * Differences are only at maximal sample speed, range list and FIFO
+ * support.
+ * The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
+ * only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
+ * PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
+ * but this code is untested.
+ * A word or two about DMA. Driver support DMA operations at two ways:
+ * 1) DMA uses two buffers and after one is filled then is generated
+ *    INT and DMA restart with second buffer. With this mode I'm unable run
+ *    more that 80Ksamples/secs without data dropouts on K6/233.
+ * 2) DMA uses one buffer and run in autoinit mode and the data are
+ *    from DMA buffer moved on the fly with 2kHz interrupts from RTC.
+ *    This mode is used if the interrupt 8 is available for allocation.
+ *    If not, then first DMA mode is used. With this I can run at
+ *    full speed one card (100ksamples/secs) or two cards with
+ *    60ksamples/secs each (more is problem on account of ISA limitations).
+ *    To use this mode you must have compiled  kernel with disabled
+ *    "Enhanced Real Time Clock Support".
+ *    Maybe you can have problems if you use xntpd or similar.
+ *    If you've data dropouts with DMA mode 2 then:
+ *     a) disable IDE DMA
+ *     b) switch text mode console to fb.
+ *
+ *  Options for PCL-818L:
+ *  [0] - IO Base
+ *  [1] - IRQ        (0=disable, 2, 3, 4, 5, 6, 7)
+ *  [2] - DMA        (0=disable, 1, 3)
+ *  [3] - 0, 10=10MHz clock for 8254
+ *            1= 1MHz clock for 8254
+ *  [4] - 0,  5=A/D input  -5V.. +5V
+ *        1, 10=A/D input -10V..+10V
+ *  [5] - 0,  5=D/A output 0-5V  (internal reference -5V)
+ *        1, 10=D/A output 0-10V (internal reference -10V)
+ *        2    =D/A output unknown (external reference)
+ *
+ *  Options for PCL-818, PCL-818H:
+ *  [0] - IO Base
+ *  [1] - IRQ        (0=disable, 2, 3, 4, 5, 6, 7)
+ *  [2] - DMA        (0=disable, 1, 3)
+ *  [3] - 0, 10=10MHz clock for 8254
+ *            1= 1MHz clock for 8254
+ *  [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
+ *        1, 10=D/A output 0-10V (internal reference -10V)
+ *        2    =D/A output unknown (external reference)
+ *
+ *  Options for PCL-818HD, PCL-818HG:
+ *  [0] - IO Base
+ *  [1] - IRQ        (0=disable, 2, 3, 4, 5, 6, 7)
+ *  [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,
+ *                    1=use DMA ch 1, 3=use DMA ch 3)
+ *  [3] - 0, 10=10MHz clock for 8254
+ *            1= 1MHz clock for 8254
+ *  [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
+ *        1, 10=D/A output 0-10V (internal reference -10V)
+ *        2    =D/A output unknown (external reference)
+ *
+ *  Options for PCL-718:
+ *  [0] - IO Base
+ *  [1] - IRQ        (0=disable, 2, 3, 4, 5, 6, 7)
+ *  [2] - DMA        (0=disable, 1, 3)
+ *  [3] - 0, 10=10MHz clock for 8254
+ *            1= 1MHz clock for 8254
+ *  [4] -     0=A/D Range is +/-10V
+ *            1=             +/-5V
+ *            2=             +/-2.5V
+ *            3=             +/-1V
+ *            4=             +/-0.5V
+ *            5=             user defined bipolar
+ *            6=             0-10V
+ *            7=             0-5V
+ *            8=             0-2V
+ *            9=             0-1V
+ *           10=             user defined unipolar
+ *  [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)
+ *        1, 10=D/A outputs 0-10V (internal reference -10V)
+ *            2=D/A outputs unknown (external reference)
+ *  [6] - 0, 60=max  60kHz A/D sampling
+ *        1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
+ *
+ */
 
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
 
 #include "../comedidev.h"
 
+#include "comedi_isadma.h"
 #include "comedi_fc.h"
 #include "8253.h"
 
@@ -303,20 +296,14 @@
 };
 
 struct pcl818_private {
-	unsigned int dma;	/*  used DMA, 0=don't use DMA */
-	unsigned int dmapages;
-	unsigned int hwdmasize;
-	unsigned long dmabuf[2];	/*  pointers to begin of DMA buffers */
-	unsigned int hwdmaptr[2];	/*  hardware address of DMA buffers */
-	int next_dma_buf;	/*  which DMA buffer will be used next round */
-	long dma_runs_to_end;	/*  how many we must permorm DMA transfer to end of record */
-	unsigned long last_dma_run;	/*  how many bytes we must transfer on last DMA page */
-	unsigned int ns_min;	/*  manimal allowed delay between samples (in us) for actual card */
+	struct comedi_isadma *dma;
+	/*  manimal allowed delay between samples (in us) for actual card */
+	unsigned int ns_min;
 	int i8253_osc_base;	/*  1/frequency of on board oscilator in ns */
-	unsigned int act_chanlist[16];	/*  MUX setting for actual AI operations */
+	/*  MUX setting for actual AI operations */
+	unsigned int act_chanlist[16];
 	unsigned int act_chanlist_len;	/*  how long is actual MUX list */
 	unsigned int act_chanlist_pos;	/*  actual position in MUX list */
-	unsigned int ai_data_len;	/*  len of data buffer */
 	unsigned int divisor1;
 	unsigned int divisor2;
 	unsigned int usefifo:1;
@@ -340,58 +327,27 @@
 }
 
 static void pcl818_ai_setup_dma(struct comedi_device *dev,
-				struct comedi_subdevice *s)
+				struct comedi_subdevice *s,
+				unsigned int unread_samples)
 {
 	struct pcl818_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int flags;
-	unsigned int bytes;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+	unsigned int nsamples;
 
-	disable_dma(devpriv->dma);	/*  disable dma */
-	bytes = devpriv->hwdmasize;
-	if (cmd->stop_src == TRIG_COUNT) {
-		bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
-		devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
-		devpriv->last_dma_run = bytes % devpriv->hwdmasize;
-		devpriv->dma_runs_to_end--;
-		if (devpriv->dma_runs_to_end >= 0)
-			bytes = devpriv->hwdmasize;
+	comedi_isadma_disable(dma->chan);
+
+	/*
+	 * Determine dma size based on the buffer maxsize plus the number of
+	 * unread samples and the number of samples remaining in the command.
+	 */
+	nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+	if (nsamples > unread_samples) {
+		nsamples -= unread_samples;
+		desc->size = comedi_samples_to_bytes(s, nsamples);
+		comedi_isadma_program(desc);
 	}
-
-	devpriv->next_dma_buf = 0;
-	set_dma_mode(devpriv->dma, DMA_MODE_READ);
-	flags = claim_dma_lock();
-	clear_dma_ff(devpriv->dma);
-	set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
-	set_dma_count(devpriv->dma, bytes);
-	release_dma_lock(flags);
-	enable_dma(devpriv->dma);
-}
-
-static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
-				     struct comedi_subdevice *s)
-{
-	struct pcl818_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned long flags;
-
-	disable_dma(devpriv->dma);
-	devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
-	if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
-		/* switch dma bufs */
-		set_dma_mode(devpriv->dma, DMA_MODE_READ);
-		flags = claim_dma_lock();
-		set_dma_addr(devpriv->dma,
-			     devpriv->hwdmaptr[devpriv->next_dma_buf]);
-		if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
-			set_dma_count(devpriv->dma, devpriv->hwdmasize);
-		else
-			set_dma_count(devpriv->dma, devpriv->last_dma_run);
-		release_dma_lock(flags);
-		enable_dma(devpriv->dma);
-	}
-
-	devpriv->dma_runs_to_end--;
 }
 
 static void pcl818_ai_set_chan_range(struct comedi_device *dev,
@@ -493,11 +449,12 @@
 	return -EBUSY;
 }
 
-static bool pcl818_ai_dropout(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      unsigned int chan)
+static bool pcl818_ai_write_sample(struct comedi_device *dev,
+				   struct comedi_subdevice *s,
+				   unsigned int chan, unsigned int val)
 {
 	struct pcl818_private *devpriv = dev->private;
+	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int expected_chan;
 
 	expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
@@ -507,17 +464,11 @@
 			(devpriv->dma) ? "DMA" :
 			(devpriv->usefifo) ? "FIFO" : "IRQ",
 			chan, expected_chan);
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
-		return true;
+		s->async->events |= COMEDI_CB_ERROR;
+		return false;
 	}
-	return false;
-}
 
-static bool pcl818_ai_next_chan(struct comedi_device *dev,
-				struct comedi_subdevice *s)
-{
-	struct pcl818_private *devpriv = dev->private;
-	struct comedi_cmd *cmd = &s->async->cmd;
+	comedi_buf_write_samples(s, &val, 1);
 
 	devpriv->act_chanlist_pos++;
 	if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
@@ -540,47 +491,35 @@
 
 	if (pcl818_ai_eoc(dev, s, NULL, 0)) {
 		dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n");
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
 	val = pcl818_ai_get_sample(dev, s, &chan);
-
-	if (pcl818_ai_dropout(dev, s, chan))
-		return;
-
-	comedi_buf_write_samples(s, &val, 1);
-
-	pcl818_ai_next_chan(dev, s);
+	pcl818_ai_write_sample(dev, s, chan, val);
 }
 
 static void pcl818_handle_dma(struct comedi_device *dev,
 			      struct comedi_subdevice *s)
 {
 	struct pcl818_private *devpriv = dev->private;
-	unsigned short *ptr;
+	struct comedi_isadma *dma = devpriv->dma;
+	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+	unsigned short *ptr = desc->virt_addr;
+	unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
 	unsigned int chan;
 	unsigned int val;
-	int i, len, bufptr;
+	int i;
 
-	pcl818_ai_setup_next_dma(dev, s);
+	/* restart dma with the next buffer */
+	dma->cur_dma = 1 - dma->cur_dma;
+	pcl818_ai_setup_dma(dev, s, nsamples);
 
-	ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
-
-	len = devpriv->hwdmasize >> 1;
-	bufptr = 0;
-
-	for (i = 0; i < len; i++) {
-		val = ptr[bufptr++];
+	for (i = 0; i < nsamples; i++) {
+		val = ptr[i];
 		chan = val & 0xf;
 		val = (val >> 4) & s->maxdata;
-
-		if (pcl818_ai_dropout(dev, s, chan))
-			break;
-
-		comedi_buf_write_samples(s, &val, 1);
-
-		if (!pcl818_ai_next_chan(dev, s))
+		if (!pcl818_ai_write_sample(dev, s, chan, val))
 			break;
 	}
 }
@@ -597,14 +536,14 @@
 
 	if (status & 4) {
 		dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n");
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
 	if (status & 1) {
 		dev_err(dev->class_dev,
 			"A/D mode1/3 FIFO interrupt without data!\n");
-		s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+		s->async->events |= COMEDI_CB_ERROR;
 		return;
 	}
 
@@ -615,13 +554,7 @@
 
 	for (i = 0; i < len; i++) {
 		val = pcl818_ai_get_fifo_sample(dev, s, &chan);
-
-		if (pcl818_ai_dropout(dev, s, chan))
-			break;
-
-		comedi_buf_write_samples(s, &val, 1);
-
-		if (!pcl818_ai_next_chan(dev, s))
+		if (!pcl818_ai_write_sample(dev, s, chan, val))
 			break;
 	}
 }
@@ -687,7 +620,8 @@
 				break;
 			nowmustbechan =
 			    (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
-			if (nowmustbechan != CR_CHAN(chanlist[i])) {	/*  channel list isn't continuous :-( */
+			if (nowmustbechan != CR_CHAN(chanlist[i])) {
+				/*  channel list isn't continuous :-( */
 				dev_dbg(dev->class_dev,
 					"channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
 					i, CR_CHAN(chanlist[i]), nowmustbechan,
@@ -804,6 +738,7 @@
 			 struct comedi_subdevice *s)
 {
 	struct pcl818_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 	unsigned int ctrl = 0;
 	unsigned int seglen;
@@ -818,11 +753,9 @@
 		return -EINVAL;
 	pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
 
-	devpriv->ai_data_len = s->async->prealloc_bufsz;
 	devpriv->ai_cmd_running = 1;
 	devpriv->ai_cmd_canceled = 0;
 	devpriv->act_chanlist_pos = 0;
-	devpriv->dma_runs_to_end = 0;
 
 	if (cmd->convert_src == TRIG_TIMER)
 		ctrl |= PCL818_CTRL_PACER_TRIG;
@@ -831,8 +764,10 @@
 
 	outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
 
-	if (devpriv->dma) {
-		pcl818_ai_setup_dma(dev, s);
+	if (dma) {
+		/* setup and enable dma for the first buffer */
+		dma->cur_dma = 0;
+		pcl818_ai_setup_dma(dev, s, 0);
 
 		ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
 			PCL818_CTRL_DMAE;
@@ -854,12 +789,13 @@
 			    struct comedi_subdevice *s)
 {
 	struct pcl818_private *devpriv = dev->private;
+	struct comedi_isadma *dma = devpriv->dma;
 	struct comedi_cmd *cmd = &s->async->cmd;
 
 	if (!devpriv->ai_cmd_running)
 		return 0;
 
-	if (devpriv->dma) {
+	if (dma) {
 		if (cmd->stop_src == TRIG_NONE ||
 		    (cmd->stop_src == TRIG_COUNT &&
 		     s->async->scans_done < cmd->stop_arg)) {
@@ -872,7 +808,7 @@
 				return 0;
 			}
 		}
-		disable_dma(devpriv->dma);
+		comedi_isadma_disable(dma->chan);
 	}
 
 	outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
@@ -1054,13 +990,33 @@
 	}
 }
 
+static void pcl818_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+	struct pcl818_private *devpriv = dev->private;
+
+	/* only DMA channels 3 and 1 are valid */
+	if (!(dma_chan == 3 || dma_chan == 1))
+		return;
+
+	/* DMA uses two 16K buffers */
+	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+					   PAGE_SIZE * 4, COMEDI_ISADMA_READ);
+}
+
+static void pcl818_free_dma(struct comedi_device *dev)
+{
+	struct pcl818_private *devpriv = dev->private;
+
+	if (devpriv)
+		comedi_isadma_free(devpriv->dma);
+}
+
 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct pcl818_board *board = dev->board_ptr;
 	struct pcl818_private *devpriv;
 	struct comedi_subdevice *s;
 	int ret;
-	int i;
 
 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
@@ -1084,31 +1040,8 @@
 		devpriv->usefifo = 1;
 
 	/* we need an IRQ to do DMA on channel 3 or 1 */
-	if (dev->irq && board->has_dma &&
-	    (it->options[2] == 3 || it->options[2] == 1)) {
-		ret = request_dma(it->options[2], dev->board_name);
-		if (ret) {
-			dev_err(dev->class_dev,
-				"unable to request DMA channel %d\n",
-				it->options[2]);
-			return -EBUSY;
-		}
-		devpriv->dma = it->options[2];
-
-		devpriv->dmapages = 2;	/* we need 16KB */
-		devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
-		for (i = 0; i < 2; i++) {
-			unsigned long dmabuf;
-
-			dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
-			if (!dmabuf)
-				return -ENOMEM;
-
-			devpriv->dmabuf[i] = dmabuf;
-			devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
-		}
-	}
+	if (dev->irq && board->has_dma)
+		pcl818_alloc_dma(dev, it->options[2]);
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
@@ -1194,8 +1127,10 @@
 	devpriv->ns_min = board->ns_min;
 
 	if (!board->is_818) {
-		if ((it->options[6] == 1) || (it->options[6] == 100))
-			devpriv->ns_min = 10000;	/* extended PCL718 to 100kHz DAC */
+		if ((it->options[6] == 1) || (it->options[6] == 100)) {
+			/* extended PCL718 to 100kHz DAC */
+			devpriv->ns_min = 10000;
+		}
 	}
 
 	pcl818_reset(dev);
@@ -1210,13 +1145,8 @@
 	if (devpriv) {
 		pcl818_ai_cancel(dev, dev->read_subdev);
 		pcl818_reset(dev);
-		if (devpriv->dma)
-			free_dma(devpriv->dma);
-		if (devpriv->dmabuf[0])
-			free_pages(devpriv->dmabuf[0], devpriv->dmapages);
-		if (devpriv->dmabuf[1])
-			free_pages(devpriv->dmabuf[1], devpriv->dmapages);
 	}
+	pcl818_free_dma(dev);
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index e3ac8ac..12f94fe 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -19,8 +19,7 @@
 /*
  * Driver: pcmad
  * Description: Winsystems PCM-A/D12, PCM-A/D16
- * Devices: (Winsystems) PCM-A/D12 [pcmad12]
- *	    (Winsystems) PCM-A/D16 [pcmad16]
+ * Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
  * Author: ds
  * Status: untested
  *
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 59108c0..d86c5e2 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -19,7 +19,7 @@
 /*
  * Driver: pcmda12
  * Description: A driver for the Winsystems PCM-D/A-12
- * Devices: (Winsystems) PCM-D/A-12 [pcmda12]
+ * Devices: [Winsystems] PCM-D/A-12 (pcmda12)
  * Author: Calin Culianu <calin@ajvar.org>
  * Updated: Fri, 13 Jan 2006 12:01:01 -0500
  * Status: works
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index f0059e9..2c0e7ec 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -19,7 +19,7 @@
 /*
  * Driver: pcmmio
  * Description: A driver for the PCM-MIO multifunction board
- * Devices: (Winsystems) PCM-MIO [pcmmio]
+ * Devices: [Winsystems] PCM-MIO (pcmmio)
  * Author: Calin Culianu <calin@ajvar.org>
  * Updated: Wed, May 16 2007 16:21:10 -0500
  * Status: works
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 0f5483b..a1641d9 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -19,8 +19,7 @@
 /*
  * Driver: pcmuio
  * Description: Winsystems PC-104 based 48/96-channel DIO boards.
- * Devices: (Winsystems) PCM-UIO48A [pcmuio48]
- *	    (Winsystems) PCM-UIO96A [pcmuio96]
+ * Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
  * Author: Calin Culianu <calin@ajvar.org>
  * Updated: Fri, 13 Jan 2006 12:01:01 -0500
  * Status: works
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 9609811..8387fd0 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -48,15 +48,10 @@
 */
 
 #include <linux/module.h>
-#include "../comedidev.h"
 #include <linux/semaphore.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
 #include <linux/completion.h>
 
+#include "../comedi_pcmcia.h"
 #include "comedi_fc.h"
 
 struct daqp_private {
@@ -210,8 +205,7 @@
 			unsigned short data;
 
 			if (status & DAQP_STATUS_DATA_LOST) {
-				s->async->events |=
-				    COMEDI_CB_EOA | COMEDI_CB_OVERFLOW;
+				s->async->events |= COMEDI_CB_OVERFLOW;
 				dev_warn(dev->class_dev, "data lost\n");
 				break;
 			}
@@ -239,7 +233,7 @@
 		if (loop_limit <= 0) {
 			dev_warn(dev->class_dev,
 				 "loop_limit reached in daqp_interrupt()\n");
-			s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+			s->async->events |= COMEDI_CB_ERROR;
 		}
 
 		comedi_handle_events(dev, s);
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 581aa58..c94ad12 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -19,10 +19,8 @@
 /*
  * Driver: rtd520
  * Description: Real Time Devices PCI4520/DM7520
- * Devices: (Real Time Devices) DM7520HR-1 [DM7520]
- *	    (Real Time Devices) DM7520HR-8 [DM7520]
- *	    (Real Time Devices) PCI4520 [PCI4520]
- *	    (Real Time Devices) PCI4520-8 [PCI4520]
+ * Devices: [Real Time Devices] DM7520HR-1 (DM7520), DM7520HR-8,
+ *   PCI4520 (PCI4520), PCI4520-8
  * Author: Dan Christian
  * Status: Works. Only tested on DM7520-8. Not SMP safe.
  *
@@ -1014,10 +1012,8 @@
 	readw(dev->mmio + LAS0_CLEAR);
 
 	/* TODO: allow multiple interrupt sources */
-	if (devpriv->xfer_count > 0)	/* transfer every N samples */
-		writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
-	else				/* 1/2 FIFO transfers */
-		writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
+	/* transfer every N samples */
+	writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
 
 	/* BUG: start_src is ASSUMED to be TRIG_NOW */
 	/* BUG? it seems like things are running before the "start" */
@@ -1031,8 +1027,6 @@
 static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 	struct rtd_private *devpriv = dev->private;
-	u32 overrun;
-	u16 status;
 
 	/* pacer stop source: SOFTWARE */
 	writel(0, dev->mmio + LAS0_PACER_STOP);
@@ -1040,8 +1034,6 @@
 	writel(0, dev->mmio + LAS0_ADC_CONVERSION);
 	writew(0, dev->mmio + LAS0_IT);
 	devpriv->ai_count = 0;	/* stop and don't transfer any more */
-	status = readw(dev->mmio + LAS0_IT);
-	overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff;
 	writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
 	return 0;
 }
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 67b4b37..340ac77 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -19,8 +19,7 @@
 /*
  * Driver: rti800
  * Description: Analog Devices RTI-800/815
- * Devices: (Analog Devices) RTI-800 [rti800]
- *	    (Analog Devices) RTI-815 [rti815]
+ * Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
  * Author: David A. Schleef <ds@schleef.org>
  * Status: unknown
  * Updated: Fri, 05 Sep 2008 14:50:44 +0100
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 96c3974..6db58fc 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -20,7 +20,7 @@
  * Driver: rti802
  * Description: Analog Devices RTI-802
  * Author: Anders Blomdell <anders.blomdell@control.lth.se>
- * Devices: (Analog Devices) RTI-802 [rti802]
+ * Devices: [Analog Devices] RTI-802 (rti802)
  * Status: works
  *
  * Configuration Options:
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 14932c5..fc497dd 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -118,7 +118,7 @@
 static void s626_mc_disable(struct comedi_device *dev,
 			    unsigned int cmd, unsigned int reg)
 {
-	writel(cmd << 16 , dev->mmio + reg);
+	writel(cmd << 16, dev->mmio + reg);
 	mmiowb();
 }
 
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 4737dbf..1cd7403 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -16,10 +16,11 @@
 /*
  * Driver: usbdux
  * Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbdux]
+ * Devices: [ITL] USB-DUX (usbdux)
  * Author: Bernd Porr <mail@berndporr.me.uk>
  * Updated: 10 Oct 2014
  * Status: Stable
+ *
  * Connection scheme for the counter at the digital port:
  * 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1.
  * The sampling rate of the counter is approximately 500Hz.
@@ -79,11 +80,10 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/usb.h>
 #include <linux/fcntl.h>
 #include <linux/compiler.h>
 
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 #include "comedi_fc.h"
 
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index ddc4cb9..7ce27c1 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -15,7 +15,7 @@
 /*
  * Driver: usbduxfast
  * Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbduxfast]
+ * Devices: [ITL] USB-DUX-FAST (usbduxfast)
  * Author: Bernd Porr <mail@berndporr.me.uk>
  * Updated: 10 Oct 2014
  * Status: stable
@@ -46,11 +46,10 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/usb.h>
 #include <linux/fcntl.h>
 #include <linux/compiler.h>
 #include "comedi_fc.h"
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 /*
  * timeout for the USB-transfer
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index dc19435..394969b 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -16,7 +16,7 @@
 /*
  * Driver: usbduxsigma
  * Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbduxsigma]
+ * Devices: [ITL] USB-DUX-SIGMA (usbduxsigma)
  * Author: Bernd Porr <mail@berndporr.me.uk>
  * Updated: 10 Oct 2014
  * Status: stable
@@ -45,13 +45,12 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/usb.h>
 #include <linux/fcntl.h>
 #include <linux/compiler.h>
 #include <asm/unaligned.h>
 
 #include "comedi_fc.h"
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 /* timeout for the USB-transfer in ms*/
 #define BULK_TIMEOUT 1000
@@ -215,7 +214,6 @@
 	struct usbduxsigma_private *devpriv = dev->private;
 	struct comedi_async *async = s->async;
 	struct comedi_cmd *cmd = &async->cmd;
-	unsigned int dio_state;
 	uint32_t val;
 	int ret;
 	int i;
@@ -224,9 +222,6 @@
 	if (devpriv->ai_counter == 0) {
 		devpriv->ai_counter = devpriv->ai_timer;
 
-		/* get the state of the dio pins to allow external trigger */
-		dio_state = be32_to_cpu(devpriv->in_buf[0]);
-
 		/* get the data from the USB bus and hand it over to comedi */
 		for (i = 0; i < cmd->chanlist_len; i++) {
 			/* transfer data, note first byte is the DIO state */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index a19a56e..e371183 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -18,21 +18,22 @@
     GNU General Public License for more details.
 */
 /*
-Driver: vmk80xx
-Description: Velleman USB Board Low-Level Driver
-Devices: K8055/K8061 aka VM110/VM140
-Author: Manuel Gebele <forensixs@gmx.de>
-Updated: Sun, 10 May 2009 11:14:59 +0200
-Status: works
-
-Supports:
- - analog input
- - analog output
- - digital input
- - digital output
- - counter
- - pwm
-*/
+ * Driver: vmk80xx
+ * Description: Velleman USB Board Low-Level Driver
+ * Devices: [Velleman] K8055 (K8055/VM110), K8061 (K8061/VM140),
+ *   VM110 (K8055/VM110), VM140 (K8061/VM140)
+ * Author: Manuel Gebele <forensixs@gmx.de>
+ * Updated: Sun, 10 May 2009 11:14:59 +0200
+ * Status: works
+ *
+ * Supports:
+ *  - analog input
+ *  - analog output
+ *  - digital input
+ *  - digital output
+ *  - counter
+ *  - pwm
+ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -41,10 +42,9 @@
 #include <linux/input.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
-#include <linux/usb.h>
 #include <linux/uaccess.h>
 
-#include "../comedidev.h"
+#include "../comedi_usb.h"
 
 enum {
 	DEVICE_VMK8055,
@@ -550,41 +550,35 @@
 				   unsigned int *data)
 {
 	struct vmk80xx_private *devpriv = dev->private;
-	unsigned int insn_cmd;
-	int chan;
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	int cmd;
 	int reg;
-	int n;
-
-	insn_cmd = data[0];
-	if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
-		return -EINVAL;
+	int ret;
 
 	down(&devpriv->limit_sem);
-
-	chan = CR_CHAN(insn->chanspec);
-
-	if (devpriv->model == VMK8055_MODEL) {
-		if (!chan) {
-			cmd = VMK8055_CMD_RST_CNT1;
-			reg = VMK8055_CNT1_REG;
+	switch (data[0]) {
+	case INSN_CONFIG_RESET:
+		if (devpriv->model == VMK8055_MODEL) {
+			if (!chan) {
+				cmd = VMK8055_CMD_RST_CNT1;
+				reg = VMK8055_CNT1_REG;
+			} else {
+				cmd = VMK8055_CMD_RST_CNT2;
+				reg = VMK8055_CNT2_REG;
+			}
+			devpriv->usb_tx_buf[reg] = 0x00;
 		} else {
-			cmd = VMK8055_CMD_RST_CNT2;
-			reg = VMK8055_CNT2_REG;
+			cmd = VMK8061_CMD_RST_CNT;
 		}
-
-		devpriv->usb_tx_buf[reg] = 0x00;
-	} else {
-		cmd = VMK8061_CMD_RST_CNT;
+		ret = vmk80xx_write_packet(dev, cmd);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
 	}
-
-	for (n = 0; n < insn->n; n++)
-		if (vmk80xx_write_packet(dev, cmd))
-			break;
-
 	up(&devpriv->limit_sem);
 
-	return n;
+	return ret ? ret : insn->n;
 }
 
 static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/z8536.h b/drivers/staging/comedi/drivers/z8536.h
new file mode 100644
index 0000000..7be5310
--- /dev/null
+++ b/drivers/staging/comedi/drivers/z8536.h
@@ -0,0 +1,202 @@
+/*
+ * Z8536 CIO Internal registers
+ */
+
+#ifndef _Z8536_H
+#define _Z8536_H
+
+/* Master Interrupt Control register */
+#define Z8536_INT_CTRL_REG		0x00
+#define Z8536_INT_CTRL_MIE		BIT(7)	/* Master Interrupt Enable */
+#define Z8536_INT_CTRL_DLC		BIT(6)	/* Disable Lower Chain */
+#define Z8536_INT_CTRL_NV		BIT(5)	/* No Vector */
+#define Z8536_INT_CTRL_PA_VIS		BIT(4)	/* Port A Vect Inc Status */
+#define Z8536_INT_CTRL_PB_VIS		BIT(3)	/* Port B Vect Inc Status */
+#define Z8536_INT_CTRL_VT_VIS		BIT(2)	/* C/T Vect Inc Status */
+#define Z8536_INT_CTRL_RJA		BIT(1)	/* Right Justified Addresses */
+#define Z8536_INT_CTRL_RESET		BIT(0)	/* Reset */
+
+/* Master Configuration Control register */
+#define Z8536_CFG_CTRL_REG		0x01
+#define Z8536_CFG_CTRL_PBE		BIT(7)	/* Port B Enable */
+#define Z8536_CFG_CTRL_CT1E		BIT(6)	/* C/T 1 Enable */
+#define Z8536_CFG_CTRL_CT2E		BIT(5)	/* C/T 2 Enable */
+#define Z8536_CFG_CTRL_PCE_CT3E		BIT(4)	/* Port C & C/T 3 Enable */
+#define Z8536_CFG_CTRL_PLC		BIT(3)	/* Port A/B Link Control */
+#define Z8536_CFG_CTRL_PAE		BIT(2)	/* Port A Enable */
+#define Z8536_CFG_CTRL_LC_INDEP		(0 << 0)/* C/Ts Independent */
+#define Z8536_CFG_CTRL_LC_GATE		(1 << 0)/* C/T 1 Out Gates C/T 2 */
+#define Z8536_CFG_CTRL_LC_TRIG		(2 << 0)/* C/T 1 Out Triggers C/T 2 */
+#define Z8536_CFG_CTRL_LC_CLK		(3 << 0)/* C/T 1 Out Clocks C/T 2 */
+#define Z8536_CFG_CTRL_LC_MASK		(3 << 0)/* C/T Link Control mask */
+
+/* Interrupt Vector registers */
+#define Z8536_PA_INT_VECT_REG		0x02
+#define Z8536_PB_INT_VECT_REG		0x03
+#define Z8536_CT_INT_VECT_REG		0x04
+#define Z8536_CURR_INT_VECT_REG		0x1f
+
+/* Port A/B & Counter/Timer 1/2/3 Command and Status registers */
+#define Z8536_PA_CMDSTAT_REG		0x08
+#define Z8536_PB_CMDSTAT_REG		0x09
+#define Z8536_CT1_CMDSTAT_REG		0x0a
+#define Z8536_CT2_CMDSTAT_REG		0x0b
+#define Z8536_CT3_CMDSTAT_REG		0x0c
+#define Z8536_CT_CMDSTAT_REG(x)		(0x0a + (x))
+#define Z8536_CMD_NULL			(0 << 5)/* Null Code */
+#define Z8536_CMD_CLR_IP_IUS		(1 << 5)/* Clear IP & IUS */
+#define Z8536_CMD_SET_IUS		(2 << 5)/* Set IUS */
+#define Z8536_CMD_CLR_IUS		(3 << 5)/* Clear IUS */
+#define Z8536_CMD_SET_IP		(4 << 5)/* Set IP */
+#define Z8536_CMD_CLR_IP		(5 << 5)/* Clear IP */
+#define Z8536_CMD_SET_IE		(6 << 5)/* Set IE */
+#define Z8536_CMD_CLR_IE		(7 << 5)/* Clear IE */
+#define Z8536_CMD_MASK			(7 << 5)
+
+#define Z8536_STAT_IUS			BIT(7)	/* Interrupt Under Service */
+#define Z8536_STAT_IE			BIT(6)	/* Interrupt Enable */
+#define Z8536_STAT_IP			BIT(5)	/* Interrupt Pending */
+#define Z8536_STAT_ERR			BIT(4)	/* Interrupt Error */
+#define Z8536_STAT_IE_IP		(Z8536_STAT_IE | Z8536_STAT_IP)
+
+#define Z8536_PAB_STAT_ORE		BIT(3)	/* Output Register Empty */
+#define Z8536_PAB_STAT_IRF		BIT(2)	/* Input Register Full */
+#define Z8536_PAB_STAT_PMF		BIT(1)	/* Pattern Match Flag */
+#define Z8536_PAB_CMDSTAT_IOE		BIT(0)	/* Interrupt On Error */
+
+#define Z8536_CT_CMD_RCC		BIT(3)	/* Read Counter Control */
+#define Z8536_CT_CMDSTAT_GCB		BIT(2)	/* Gate Command Bit */
+#define Z8536_CT_CMD_TCB		BIT(1)	/* Trigger Command Bit */
+#define Z8536_CT_STAT_CIP		BIT(0)	/* Count In Progress */
+
+/* Port Data registers */
+#define Z8536_PA_DATA_REG		0x0d
+#define Z8536_PB_DATA_REG		0x0e
+#define Z8536_PC_DATA_REG		0x0f
+
+/* Counter/Timer 1/2/3 Current Count registers */
+#define Z8536_CT1_VAL_MSB_REG		0x10
+#define Z8536_CT1_VAL_LSB_REG		0x11
+#define Z8536_CT2_VAL_MSB_REG		0x12
+#define Z8536_CT2_VAL_LSB_REG		0x13
+#define Z8536_CT3_VAL_MSB_REG		0x14
+#define Z8536_CT3_VAL_LSB_REG		0x15
+#define Z8536_CT_VAL_MSB_REG(x)		(0x10 + ((x) * 2))
+#define Z8536_CT_VAL_LSB_REG(x)		(0x11 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Time Constant registers */
+#define Z8536_CT1_RELOAD_MSB_REG	0x16
+#define Z8536_CT1_RELOAD_LSB_REG	0x17
+#define Z8536_CT2_RELOAD_MSB_REG	0x18
+#define Z8536_CT2_RELOAD_LSB_REG	0x19
+#define Z8536_CT3_RELOAD_MSB_REG	0x1a
+#define Z8536_CT3_RELOAD_LSB_REG	0x1b
+#define Z8536_CT_RELOAD_MSB_REG(x)	(0x16 + ((x) * 2))
+#define Z8536_CT_RELOAD_LSB_REG(x)	(0x17 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Mode Specification registers */
+#define Z8536_CT1_MODE_REG		0x1c
+#define Z8536_CT2_MODE_REG		0x1d
+#define Z8536_CT3_MODE_REG		0x1e
+#define Z8536_CT_MODE_REG(x)		(0x1c + (x))
+#define Z8536_CT_MODE_CSC		BIT(7)	/* Continuous/Single Cycle */
+#define Z8536_CT_MODE_EOE		BIT(6)	/* External Output Enable */
+#define Z8536_CT_MODE_ECE		BIT(5)	/* External Count Enable */
+#define Z8536_CT_MODE_ETE		BIT(4)	/* External Trigger Enable */
+#define Z8536_CT_MODE_EGE		BIT(3)	/* External Gate Enable */
+#define Z8536_CT_MODE_REB		BIT(2)	/* Retrigger Enable Bit */
+#define Z8536_CT_MODE_DCS_PULSE		(0 << 0)/* Duty Cycle - Pulse */
+#define Z8536_CT_MODE_DCS_ONESHOT	(1 << 0)/* Duty Cycle - One-Shot */
+#define Z8536_CT_MODE_DCS_SQRWAVE	(2 << 0)/* Duty Cycle - Square Wave */
+#define Z8536_CT_MODE_DCS_DO_NOT_USE	(3 << 0)/* Duty Cycle - Do Not Use */
+#define Z8536_CT_MODE_DCS_MASK		(3 << 0)/* Duty Cycle mask */
+
+/* Port A/B Mode Specification registers */
+#define Z8536_PA_MODE_REG		0x20
+#define Z8536_PB_MODE_REG		0x28
+#define Z8536_PAB_MODE_PTS_BIT		(0 << 6)/* Bit Port */
+#define Z8536_PAB_MODE_PTS_INPUT	(1 << 6)/* Input Port */
+#define Z8536_PAB_MODE_PTS_OUTPUT	(2 << 6)/* Output Port */
+#define Z8536_PAB_MODE_PTS_BIDIR	(3 << 6)/* Bidirectional Port */
+#define Z8536_PAB_MODE_PTS_MASK		(3 << 6)/* Port Type Select mask */
+#define Z8536_PAB_MODE_ITB		BIT(5)	/* Interrupt on Two Bytes */
+#define Z8536_PAB_MODE_SB		BIT(4)	/* Single Buffered mode */
+#define Z8536_PAB_MODE_IMO		BIT(3)	/* Interrupt on Match Only */
+#define Z8536_PAB_MODE_PMS_DISABLE	(0 << 1)/* Disable Pattern Match */
+#define Z8536_PAB_MODE_PMS_AND		(1 << 1)/* "AND" mode */
+#define Z8536_PAB_MODE_PMS_OR		(2 << 1)/* "OR" mode */
+#define Z8536_PAB_MODE_PMS_OR_PEV	(3 << 1)/* "OR-Priority" mode */
+#define Z8536_PAB_MODE_PMS_MASK		(3 << 1)/* Pattern Mode mask */
+#define Z8536_PAB_MODE_LPM		BIT(0)	/* Latch on Pattern Match */
+#define Z8536_PAB_MODE_DTE		BIT(0)	/* Deskew Timer Enabled */
+
+/* Port A/B Handshake Specification registers */
+#define Z8536_PA_HANDSHAKE_REG		0x21
+#define Z8536_PB_HANDSHAKE_REG		0x29
+#define Z8536_PAB_HANDSHAKE_HST_INTER	(0 << 6)/* Interlocked Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_STROBED	(1 << 6)/* Strobed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_PULSED	(2 << 6)/* Pulsed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_3WIRE	(3 << 6)/* Three-Wire Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_MASK	(3 << 6)/* Handshake Type mask */
+#define Z8536_PAB_HANDSHAKE_RWS_DISABLE	(0 << 3)/* Req/Wait Disabled */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTWAIT	(1 << 3)/* Output Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_INWAIT	(3 << 3)/* Input Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_SPREQ	(4 << 3)/* Special Request */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTREQ	(5 << 4)/* Output Request */
+#define Z8536_PAB_HANDSHAKE_RWS_INREQ	(7 << 3)/* Input Request */
+#define Z8536_PAB_HANDSHAKE_RWS_MASK	(7 << 3)/* Req/Wait mask */
+#define Z8536_PAB_HANDSHAKE_DESKEW(x)	((x) << 0)/* Deskew Time */
+#define Z8536_PAB_HANDSHAKE_DESKEW_MASK	(3 << 0)/* Deskew Time mask */
+
+/*
+ * Port A/B/C Data Path Polarity registers
+ *
+ *	0 = Non-Inverting
+ *	1 = Inverting
+ */
+#define Z8536_PA_DPP_REG		0x22
+#define Z8536_PB_DPP_REG		0x2a
+#define Z8536_PC_DPP_REG		0x05
+
+/*
+ * Port A/B/C Data Direction registers
+ *
+ *	0 = Output bit
+ *	1 = Input bit
+ */
+#define Z8536_PA_DD_REG			0x23
+#define Z8536_PB_DD_REG			0x2b
+#define Z8536_PC_DD_REG			0x06
+
+/*
+ * Port A/B/C Special I/O Control registers
+ *
+ *	0 = Normal Input or Output
+ *	1 = Output with open drain or Input with 1's catcher
+ */
+#define Z8536_PA_SIO_REG		0x24
+#define Z8536_PB_SIO_REG		0x2c
+#define Z8536_PC_SIO_REG		0x07
+
+/*
+ * Port A/B Pattern Polarity/Transition/Mask registers
+ *
+ *	PM PT PP  Pattern Specification
+ *	-- -- --  -------------------------------------
+ *	 0  0  x  Bit masked off
+ *	 0  1  x  Any transition
+ *	 1  0  0  Zero (low-level)
+ *	 1  0  1  One (high-level)
+ *	 1  1  0  One-to-zero transition (falling-edge)
+ *	 1  1  1  Zero-to-one transition (rising-edge)
+ */
+#define Z8536_PA_PP_REG			0x25
+#define Z8536_PB_PP_REG			0x2d
+
+#define Z8536_PA_PT_REG			0x26
+#define Z8536_PB_PT_REG			0x2e
+
+#define Z8536_PA_PM_REG			0x27
+#define Z8536_PB_PM_REG			0x2f
+
+#endif	/* _Z8536_H */
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 8777f95..973f544 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -95,7 +95,7 @@
 
 	if (s->type == COMEDI_SUBD_UNUSED) {
 		dev_err(dev->class_dev,
-			"%d not useable subdevice\n", insn->subdev);
+			"%d not usable subdevice\n", insn->subdev);
 		ret = -EIO;
 		goto error;
 	}
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 9a1dc56..6a393b2 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -1,20 +1,20 @@
 /*
-    module/range.c
-    comedi routines for voltage ranges
-
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 1997-8 David A. Schleef <ds@schleef.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.
-*/
+ * comedi/range.c
+ * comedi routines for voltage ranges
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-8 David A. Schleef <ds@schleef.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/uaccess.h>
 #include "comedidev.h"
@@ -42,18 +42,18 @@
 EXPORT_SYMBOL_GPL(range_unknown);
 
 /*
-	COMEDI_RANGEINFO
-	range information ioctl
-
-	arg:
-		pointer to rangeinfo structure
-
-	reads:
-		range info structure
-
-	writes:
-		n struct comedi_krange structures to rangeinfo->range_ptr
-*/
+ * COMEDI_RANGEINFO ioctl
+ * range information
+ *
+ * arg:
+ *	pointer to comedi_rangeinfo structure
+ *
+ * reads:
+ *	comedi_rangeinfo structure
+ *
+ * writes:
+ *	array of comedi_krange structures to rangeinfo->range_ptr pointer
+ */
 int do_rangeinfo_ioctl(struct comedi_device *dev,
 		       struct comedi_rangeinfo __user *arg)
 {
diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig
deleted file mode 100644
index 43b1cc0..0000000
--- a/drivers/staging/cptm1217/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config TOUCHSCREEN_CLEARPAD_TM1217
-	tristate "Synaptics Clearpad TM1217"
-	depends on I2C
-	depends on GPIOLIB
-	depends on INPUT
-	help
-	  Say Y here if you have a Synaptics Clearpad TM1217 Controller
-
-	  If unsure, say N.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called clearpad_tm1217.
diff --git a/drivers/staging/cptm1217/Makefile b/drivers/staging/cptm1217/Makefile
deleted file mode 100644
index 8961faf..0000000
--- a/drivers/staging/cptm1217/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)	+= clearpad_tm1217.o
-
diff --git a/drivers/staging/cptm1217/TODO b/drivers/staging/cptm1217/TODO
deleted file mode 100644
index 3039224..0000000
--- a/drivers/staging/cptm1217/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-- Wait for the official upstream general clearpad drivers as promised over
-  the past few months
-- Merge any device support needed from this driver into it
-- Delete this driver
-
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
deleted file mode 100644
index 7f265ce..0000000
--- a/drivers/staging/cptm1217/clearpad_tm1217.c
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad
- * TM1217 controller
- *
- * Copyright (C) 2008 Intel Corp
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; ifnot, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/timer.h>
-#include <linux/gpio.h>
-#include <linux/hrtimer.h>
-#include <linux/kthread.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include "cp_tm1217.h"
-
-#define CPTM1217_DEVICE_NAME		"cptm1217"
-#define CPTM1217_DRIVER_NAME		CPTM1217_DEVICE_NAME
-
-#define MAX_TOUCH_SUPPORTED		2
-#define TOUCH_SUPPORTED			1
-#define SAMPLING_FREQ			80	/* Frequency in HZ */
-#define DELAY_BTWIN_SAMPLE		(1000 / SAMPLING_FREQ)
-#define WAIT_FOR_RESPONSE		5	/* 5msec just works */
-#define MAX_RETRIES			5	/* As above */
-#define INCREMENTAL_DELAY		5	/* As above */
-
-/* Regster Definitions */
-#define TMA1217_DEV_STATUS		0x13	/* Device Status */
-#define TMA1217_INT_STATUS		0x14	/* Interrupt Status */
-
-/* Controller can detect up to 2 possible finger touches.
- * Each finger touch provides  12 bit X Y co-ordinates, the values are split
- * across 2 registers, and an 8 bit  Z value */
-#define TMA1217_FINGER_STATE		0x18 /* Finger State */
-#define TMA1217_FINGER1_X_HIGHER8	0x19 /* Higher 8 bit of X coordinate */
-#define TMA1217_FINGER1_Y_HIGHER8	0x1A /* Higher 8 bit of Y coordinate */
-#define TMA1217_FINGER1_XY_LOWER4	0x1B /* Lower 4 bits of X and Y */
-#define TMA1217_FINGER1_Z_VALUE		0x1D /* 8 bit Z value for finger 1 */
-#define TMA1217_FINGER2_X_HIGHER8	0x1E /* Higher 8 bit of X coordinate */
-#define TMA1217_FINGER2_Y_HIGHER8	0x1F /* Higher 8 bit of Y coordinate */
-#define TMA1217_FINGER2_XY_LOWER4	0x20 /* Lower 4 bits of X and Y */
-#define TMA1217_FINGER2_Z_VALUE		0x22 /* 8 bit Z value for finger 2 */
-#define TMA1217_DEVICE_CTRL		0x23 /* Device Control */
-#define TMA1217_INTERRUPT_ENABLE	0x24 /* Interrupt Enable */
-#define TMA1217_REPORT_MODE		0x2B /* Reporting Mode */
-#define TMA1217_MAX_X_LOWER8		0x31 /* Bit 0-7 for Max X */
-#define TMA1217_MAX_X_HIGHER4		0x32 /* Bit 8-11 for Max X */
-#define TMA1217_MAX_Y_LOWER8		0x33 /* Bit 0-7 for Max Y */
-#define TMA1217_MAX_Y_HIGHER4		0x34 /* Bit 8-11 for Max Y */
-#define TMA1217_DEVICE_CMD_RESET	0x67 /* Device CMD reg for reset */
-#define TMA1217_DEVICE_CMD_REZERO	0x69 /* Device CMD reg for rezero */
-
-#define TMA1217_MANUFACTURER_ID		0x73 /* Manufacturer Id */
-#define TMA1217_PRODUCT_FAMILY		0x75 /* Product Family */
-#define TMA1217_FIRMWARE_REVISION	0x76 /* Firmware Revision */
-#define TMA1217_SERIAL_NO_HIGH		0x7C /* Bit 8-15 of device serial no. */
-#define TMA1217_SERIAL_NO_LOW		0x7D /* Bit 0-7 of device serial no. */
-#define TMA1217_PRODUCT_ID_START	0x7E /* Start address for 10 byte ID */
-#define TMA1217_DEVICE_CAPABILITY	0x8B /* Reporting capability */
-
-
-/*
- * The touch position structure.
- */
-struct touch_state {
-	int	x;
-	int	y;
-	bool button;
-};
-
-/* Device Specific info given by the controller */
-struct cp_dev_info {
-	u16	maxX;
-	u16	maxY;
-};
-
-/* Vendor related info given by the controller */
-struct cp_vendor_info {
-	u8	vendor_id;
-	u8	product_family;
-	u8	firmware_rev;
-	u16	serial_no;
-};
-
-/*
- * Private structure to store the device details
- */
-struct cp_tm1217_device {
-	struct i2c_client	*client;
-	struct device		*dev;
-	struct cp_vendor_info	vinfo;
-	struct cp_dev_info	dinfo;
-	struct input_dev_info {
-		char			phys[32];
-		char			name[128];
-		struct input_dev	*input;
-		struct touch_state	touch;
-	} cp_input_info[MAX_TOUCH_SUPPORTED];
-
-	int	thread_running;
-	struct mutex	thread_mutex;
-
-	int gpio;
-};
-
-
-/* The following functions are used to read/write registers on the device
- * as per the RMI prorocol. Technically, a page select should be written
- * before doing read/write but since the register offsets are below 0xFF
- * we can use the default value of page which is 0x00
- */
-static int cp_tm1217_read(struct cp_tm1217_device *ts,
-				u8 *req, int size)
-{
-	int i, retval;
-
-	/* Send the address */
-	retval = i2c_master_send(ts->client, &req[0], 1);
-	if (retval != 1) {
-		dev_err(ts->dev, "cp_tm1217: I2C send failed\n");
-		return retval;
-	}
-	msleep(WAIT_FOR_RESPONSE);
-	for (i = 0; i < MAX_RETRIES; i++) {
-		retval = i2c_master_recv(ts->client, &req[1], size);
-		if (retval == size)
-			break;
-
-		msleep(INCREMENTAL_DELAY);
-		dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i);
-	}
-	if (retval != size)
-		dev_err(ts->dev, "cp_tm1217: Read from device failed\n");
-
-	return retval;
-}
-
-static int cp_tm1217_write(struct cp_tm1217_device *ts,
-				u8 *req, int size)
-{
-	int retval;
-
-	/* Send the address and the data to be written */
-	retval = i2c_master_send(ts->client, &req[0], size + 1);
-	if (retval != size + 1) {
-		dev_err(ts->dev, "cp_tm1217: I2C write  failed: %d\n", retval);
-		return retval;
-	}
-	/* Wait for the write to complete. TBD why this is required */
-	msleep(WAIT_FOR_RESPONSE);
-
-	return size;
-}
-
-static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts)
-{
-	u8 req[2];
-	int retval;
-
-	req[0] = TMA1217_INTERRUPT_ENABLE;
-	req[1] = 0x0;
-	retval = cp_tm1217_write(ts, req, 1);
-	if (retval != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts)
-{
-	u8 req[2];
-	int retval;
-
-	req[0] = TMA1217_INTERRUPT_ENABLE;
-	req[1] = 0xa;
-	retval = cp_tm1217_write(ts, req, 1);
-	if (retval != 1)
-		return -EIO;
-
-	return 0;
-}
-
-static void process_touch(struct cp_tm1217_device *ts, int index)
-{
-	int retval;
-	struct input_dev_info *input_info =
-		(struct input_dev_info *)&ts->cp_input_info[index];
-	u8 xy_data[6];
-
-	if (index == 0)
-		xy_data[0] = TMA1217_FINGER1_X_HIGHER8;
-	else
-		xy_data[0] = TMA1217_FINGER2_X_HIGHER8;
-
-	retval = cp_tm1217_read(ts, xy_data, 5);
-	if (retval < 5) {
-		dev_err(ts->dev, "cp_tm1217: XY read from device failed\n");
-		return;
-	}
-
-	/* Note: Currently not using the Z values but may be requried in
-	   the future. */
-	input_info->touch.x = (xy_data[1] << 4)
-					| (xy_data[3] & 0x0F);
-	input_info->touch.y = (xy_data[2] << 4)
-					| ((xy_data[3] & 0xF0) >> 4);
-	input_report_abs(input_info->input, ABS_X, input_info->touch.x);
-	input_report_abs(input_info->input, ABS_Y, input_info->touch.y);
-	input_sync(input_info->input);
-}
-
-static void cp_tm1217_get_data(struct cp_tm1217_device *ts)
-{
-	u8 req[2];
-	int retval, i, finger_touched = 0;
-
-	do {
-		req[0] = TMA1217_FINGER_STATE;
-		retval = cp_tm1217_read(ts, req, 1);
-		if (retval != 1) {
-			dev_err(ts->dev,
-				"cp_tm1217: Read from device failed\n");
-			continue;
-		}
-		finger_touched = 0;
-		/* Start sampling until the pressure is below
-		  threshold */
-		for (i = 0; i < TOUCH_SUPPORTED; i++) {
-			if (req[1] & 0x3) {
-				finger_touched++;
-				if (ts->cp_input_info[i].touch.button == 0) {
-					/* send the button touch event */
-					input_report_key(
-						ts->cp_input_info[i].input,
-						BTN_TOUCH, 1);
-					ts->cp_input_info[i].touch.button = 1;
-				}
-				process_touch(ts, i);
-			} else {
-				if (ts->cp_input_info[i].touch.button == 1) {
-					/* send the button release event */
-					input_report_key(
-						ts->cp_input_info[i].input,
-						BTN_TOUCH, 0);
-					input_sync(ts->cp_input_info[i].input);
-					ts->cp_input_info[i].touch.button = 0;
-				}
-			}
-			req[1] = req[1] >> 2;
-		}
-		msleep(DELAY_BTWIN_SAMPLE);
-	} while (finger_touched > 0);
-}
-
-static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle)
-{
-	struct cp_tm1217_device *ts = handle;
-	u8 req[2];
-	int retval;
-
-	/* Chedk if another thread is already running */
-	mutex_lock(&ts->thread_mutex);
-	if (ts->thread_running == 1) {
-		mutex_unlock(&ts->thread_mutex);
-		return IRQ_HANDLED;
-	}
-
-	ts->thread_running = 1;
-	mutex_unlock(&ts->thread_mutex);
-
-	/* Mask the interrupts */
-	retval = cp_tm1217_mask_interrupt(ts);
-
-	/* Read the Interrupt Status register to find the cause of the
-	   Interrupt */
-	req[0] = TMA1217_INT_STATUS;
-	retval = cp_tm1217_read(ts, req, 1);
-	if (retval != 1)
-		goto exit_thread;
-
-	if (!(req[1] & 0x8))
-		goto exit_thread;
-
-	cp_tm1217_get_data(ts);
-
-exit_thread:
-	/* Unmask the interrupts before going to sleep */
-	retval = cp_tm1217_unmask_interrupt(ts);
-
-	mutex_lock(&ts->thread_mutex);
-	ts->thread_running = 0;
-	mutex_unlock(&ts->thread_mutex);
-
-	return IRQ_HANDLED;
-}
-
-static int cp_tm1217_init_data(struct cp_tm1217_device *ts)
-{
-	int retval;
-	u8	req[2];
-
-	/* Read the vendor id/ fw revision etc. Ignoring return check as this
-	   is non critical info  */
-	req[0] = TMA1217_MANUFACTURER_ID;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->vinfo.vendor_id = req[1];
-
-	req[0] = TMA1217_PRODUCT_FAMILY;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->vinfo.product_family = req[1];
-
-	req[0] = TMA1217_FIRMWARE_REVISION;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->vinfo.firmware_rev = req[1];
-
-	req[0] = TMA1217_SERIAL_NO_HIGH;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->vinfo.serial_no = (req[1] << 8);
-
-	req[0] = TMA1217_SERIAL_NO_LOW;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->vinfo.serial_no = ts->vinfo.serial_no | req[1];
-
-	req[0] = TMA1217_MAX_X_HIGHER4;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->dinfo.maxX = (req[1] & 0xF) << 8;
-
-	req[0] = TMA1217_MAX_X_LOWER8;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->dinfo.maxX = ts->dinfo.maxX | req[1];
-
-	req[0] = TMA1217_MAX_Y_HIGHER4;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->dinfo.maxY = (req[1] & 0xF) << 8;
-
-	req[0] = TMA1217_MAX_Y_LOWER8;
-	retval = cp_tm1217_read(ts, req, 1);
-	ts->dinfo.maxY = ts->dinfo.maxY | req[1];
-
-	return 0;
-
-}
-
-/*
- *	Set up a GPIO for use as the interrupt. We can't simply do this at
- *	boot time because the GPIO drivers themselves may not be around at
- *	boot/firmware set up time to do the work. Instead defer it to driver
- *	detection.
- */
-
-static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
-{
-	int retval;
-
-	/* Hook up the irq handler */
-	retval = gpio_request(ts->gpio, "cp_tm1217_touch");
-	if (retval < 0) {
-		dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
-								retval);
-		return retval;
-	}
-
-	retval = gpio_direction_input(ts->gpio);
-	if (retval < 0) {
-		dev_err(ts->dev,
-		"cp_tm1217: GPIO direction configuration failed, error %d\n",
-								retval);
-		gpio_free(ts->gpio);
-		return retval;
-	}
-
-	retval = gpio_to_irq(ts->gpio);
-	if (retval < 0) {
-		dev_err(ts->dev,
-			"cp_tm1217: GPIO to IRQ failed, error %d\n", retval);
-		gpio_free(ts->gpio);
-	}
-	dev_dbg(ts->dev,
-		"cp_tm1217: Got IRQ number is %d for GPIO %d\n",
-		retval, ts->gpio);
-	return retval;
-}
-
-static int cp_tm1217_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
-{
-	struct cp_tm1217_device *ts;
-	struct input_dev *input_dev;
-	struct input_dev_info	*input_info;
-	struct cp_tm1217_platform_data *pdata;
-	u8 req[2];
-	int i, retval;
-
-	/* No pdata is fine - we then use "normal" IRQ mode */
-
-	pdata = client->dev.platform_data;
-
-	ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL);
-	if (!ts)
-		return -ENOMEM;
-
-	ts->client = client;
-	ts->dev = &client->dev;
-	i2c_set_clientdata(client, ts);
-
-	ts->thread_running = 0;
-	mutex_init(&ts->thread_mutex);
-
-	/* Reset the Controller */
-	req[0] = TMA1217_DEVICE_CMD_RESET;
-	req[1] = 0x1;
-	retval = cp_tm1217_write(ts, req, 1);
-	if (retval != 1) {
-		dev_err(ts->dev, "cp_tm1217: Controller reset failed\n");
-		kfree(ts);
-		return -EIO;
-	}
-
-	/* Clear up the interrupt status from reset. */
-	req[0] = TMA1217_INT_STATUS;
-	retval = cp_tm1217_read(ts, req, 1);
-
-	/* Mask all the interrupts */
-	retval = cp_tm1217_mask_interrupt(ts);
-
-	/* Read the controller information */
-	cp_tm1217_init_data(ts);
-
-	/* The following code will register multiple event devices when
-	   multi-pointer is enabled, the code has not been tested
-	   with MPX */
-	for (i = 0; i < TOUCH_SUPPORTED; i++) {
-		input_dev = input_allocate_device();
-		if (input_dev == NULL) {
-			retval = -ENOMEM;
-			goto fail;
-		}
-		input_info = &ts->cp_input_info[i];
-		snprintf(input_info->name, sizeof(input_info->name),
-			"cp_tm1217_touchscreen_%d", i);
-		input_dev->name = input_info->name;
-		snprintf(input_info->phys, sizeof(input_info->phys),
-			"%s/input%d", dev_name(&client->dev), i);
-
-		input_dev->phys = input_info->phys;
-		input_dev->id.bustype = BUS_I2C;
-
-		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-		input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
-		input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0);
-		input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0);
-
-		retval = input_register_device(input_dev);
-		if (retval) {
-			dev_err(ts->dev,
-				"Input dev registration failed for %s\n",
-					input_dev->name);
-			input_free_device(input_dev);
-			goto fail;
-		}
-		input_info->input = input_dev;
-	}
-
-	/* Setup the reporting mode to send an interrupt only when
-	   finger arrives or departs. */
-	req[0] = TMA1217_REPORT_MODE;
-	req[1] = 0x02;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	/* Setup the device to no sleep mode for now and make it configured */
-	req[0] = TMA1217_DEVICE_CTRL;
-	req[1] = 0x84;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	/* Check for the status of the device */
-	req[0] = TMA1217_DEV_STATUS;
-	retval = cp_tm1217_read(ts, req, 1);
-	if (req[1] != 0) {
-		dev_err(ts->dev,
-			"cp_tm1217: Device Status 0x%x != 0: config failed\n",
-			req[1]);
-
-		retval = -EIO;
-		goto fail;
-	}
-
-	if (pdata && pdata->gpio) {
-		ts->gpio = pdata->gpio;
-		retval = cp_tm1217_setup_gpio_irq(ts);
-	} else
-		retval = client->irq;
-
-	if (retval < 0) {
-		dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
-								retval);
-		goto fail;
-	}
-
-	client->irq = retval;
-
-
-	retval = request_threaded_irq(client->irq,
-		NULL, cp_tm1217_sample_thread,
-		IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts);
-	if (retval < 0) {
-		dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval);
-		goto fail_gpio;
-	}
-
-	/* Unmask the interrupts */
-	retval = cp_tm1217_unmask_interrupt(ts);
-	if (retval == 0)
-		return 0;
-
-	free_irq(client->irq, ts);
-fail_gpio:
-	if (ts->gpio)
-		gpio_free(ts->gpio);
-fail:
-	/* Clean up before returning failure */
-	for (i = 0; i < TOUCH_SUPPORTED; i++) {
-		if (ts->cp_input_info[i].input)
-			input_unregister_device(ts->cp_input_info[i].input);
-	}
-	kfree(ts);
-	return retval;
-
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-/*
- * cp_tm1217 suspend
- *
- */
-static int cp_tm1217_suspend(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
-	u8 req[2];
-	int retval;
-
-	/* Put the controller to sleep */
-	req[0] = TMA1217_DEVICE_CTRL;
-	retval = cp_tm1217_read(ts, req, 1);
-	req[1] = (req[1] & 0xF8) | 0x1;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	if (device_may_wakeup(&client->dev))
-		enable_irq_wake(client->irq);
-
-	return 0;
-}
-
-/*
- * cp_tm1217_resume
- *
- */
-static int cp_tm1217_resume(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
-	u8 req[2];
-	int retval;
-
-	/* Take the controller out of sleep */
-	req[0] = TMA1217_DEVICE_CTRL;
-	retval = cp_tm1217_read(ts, req, 1);
-	req[1] = (req[1] & 0xF8) | 0x4;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	/* Restore the register settings sinc the power to the
-	   could have been cut off */
-
-	/* Setup the reporting mode to send an interrupt only when
-	   finger arrives or departs. */
-	req[0] = TMA1217_REPORT_MODE;
-	req[1] = 0x02;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	/* Setup the device to no sleep mode for now and make it configured */
-	req[0] = TMA1217_DEVICE_CTRL;
-	req[1] = 0x84;
-	retval = cp_tm1217_write(ts, req, 1);
-
-	/* Setup the interrupt mask */
-	retval = cp_tm1217_unmask_interrupt(ts);
-
-	if (device_may_wakeup(&client->dev))
-		disable_irq_wake(client->irq);
-
-	return 0;
-}
-
-#endif
-
-static SIMPLE_DEV_PM_OPS(cp_tm1217_pm_ops, cp_tm1217_suspend,
-	cp_tm1217_resume);
-
-/*
- * cp_tm1217_remove
- *
- */
-static int cp_tm1217_remove(struct i2c_client *client)
-{
-	struct cp_tm1217_device *ts = i2c_get_clientdata(client);
-	int i;
-
-	free_irq(client->irq, ts);
-	if (ts->gpio)
-		gpio_free(ts->gpio);
-	for (i = 0; i < TOUCH_SUPPORTED; i++)
-		input_unregister_device(ts->cp_input_info[i].input);
-	kfree(ts);
-	return 0;
-}
-
-static struct i2c_device_id cp_tm1217_idtable[] = {
-	{ CPTM1217_DEVICE_NAME, 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable);
-
-static struct i2c_driver cp_tm1217_driver = {
-	.driver = {
-		.owner	= THIS_MODULE,
-		.name	= CPTM1217_DRIVER_NAME,
-		.pm	= &cp_tm1217_pm_ops,
-	},
-	.id_table	= cp_tm1217_idtable,
-	.probe		= cp_tm1217_probe,
-	.remove		= cp_tm1217_remove,
-};
-
-module_i2c_driver(cp_tm1217_driver);
-
-MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
-MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/cptm1217/cp_tm1217.h b/drivers/staging/cptm1217/cp_tm1217.h
deleted file mode 100644
index 30bad35..0000000
--- a/drivers/staging/cptm1217/cp_tm1217.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __LINUX_I2C_CP_TM1217_H
-#define __LINUX_I2C_CP_TM1217_H
-
-struct cp_tm1217_platform_data {
-	int gpio;		/* If not set uses the IRQ resource 0 */
-};
-
-#endif
diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c
index bdb5317..7184747 100644
--- a/drivers/staging/dgap/dgap.c
+++ b/drivers/staging/dgap/dgap.c
@@ -978,8 +978,8 @@
 				brd->u.board.conc1++;
 
 			conc_type = dgap_gettok(in);
-			if (conc_type == 0 || conc_type != CX ||
-			    conc_type != EPC) {
+			if (conc_type == 0 || (conc_type != CX &&
+			    conc_type != EPC)) {
 				pr_err("failed to set a type of concentratros");
 				return -1;
 			}
@@ -1019,8 +1019,8 @@
 				brd->u.board.module1++;
 
 			module_type = dgap_gettok(in);
-			if (module_type == 0 || module_type != PORTS ||
-			    module_type != MODEM) {
+			if (module_type == 0 || (module_type != PORTS &&
+			    module_type != MODEM)) {
 				pr_err("failed to set a type of module");
 				return -1;
 			}
@@ -1400,27 +1400,27 @@
 		return -ENOMEM;
 
 	if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000,
-					"dgap")) {
-		release_mem_region(brd->membase, 0x200000);
-		return -ENOMEM;
-	}
+					"dgap"))
+		goto err_req_mem;
 
 	brd->re_map_membase = ioremap(brd->membase, 0x200000);
-	if (!brd->re_map_membase) {
-		release_mem_region(brd->membase, 0x200000);
-		release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
-		return -ENOMEM;
-	}
+	if (!brd->re_map_membase)
+		goto err_remap_mem;
 
 	brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
-	if (!brd->re_map_port) {
-		release_mem_region(brd->membase, 0x200000);
-		release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
-		iounmap(brd->re_map_membase);
-		return -ENOMEM;
-	}
+	if (!brd->re_map_port)
+		goto err_remap_port;
 
 	return 0;
+
+err_remap_port:
+	iounmap(brd->re_map_membase);
+err_remap_mem:
+	release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+err_req_mem:
+	release_mem_region(brd->membase, 0x200000);
+
+	return -ENOMEM;
 }
 
 static void dgap_unmap(struct board_t *brd)
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index ba98ff3..f177d3a 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -97,12 +97,12 @@
 static struct timer_list dgnc_poll_timer;
 
 
-static struct pci_device_id dgnc_pci_tbl[] = {
-	{	DIGI_VID, PCI_DEVICE_CLASSIC_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	0 },
-	{	DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	1 },
-	{	DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	2 },
-	{	DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	3 },
-	{0,}						/* 0 terminated list. */
+static const struct pci_device_id dgnc_pci_tbl[] = {
+	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID),     .driver_data = 0},
+	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1},
+	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID),     .driver_data = 2},
+	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3},
+	{0,}
 };
 MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
 
@@ -238,6 +238,7 @@
 {
 	int rc = 0;
 	unsigned long flags;
+	struct device *dev;
 
 	/* make sure that the globals are init'd before we do anything else */
 	dgnc_init_globals();
@@ -257,9 +258,20 @@
 	dgnc_Major = rc;
 
 	dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
-	device_create(dgnc_class, NULL,
-		MKDEV(dgnc_Major, 0),
-		NULL, "dgnc_mgmt");
+	if (IS_ERR(dgnc_class)) {
+		rc = PTR_ERR(dgnc_class);
+		pr_err(DRVSTR ": Can't create dgnc_mgmt class (%d)\n", rc);
+		goto failed_class;
+	}
+
+	dev = device_create(dgnc_class, NULL,
+			MKDEV(dgnc_Major, 0),
+			NULL, "dgnc_mgmt");
+	if (IS_ERR(dev)) {
+		rc = PTR_ERR(dev);
+		pr_err(DRVSTR ": Can't create device (%d)\n", rc);
+		goto failed_device;
+	}
 
 	/*
 	 * Init any global tty stuff.
@@ -268,7 +280,7 @@
 
 	if (rc < 0) {
 		pr_err(DRVSTR ": tty preinit - not enough memory (%d)\n", rc);
-		return rc;
+		goto failed_tty;
 	}
 
 	/* Start the poller */
@@ -282,6 +294,14 @@
 
 	add_timer(&dgnc_poll_timer);
 
+	return 0;
+
+failed_tty:
+	device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
+failed_device:
+	class_destroy(dgnc_class);
+failed_class:
+	unregister_chrdev(dgnc_Major, "dgnc");
 	return rc;
 }
 
diff --git a/drivers/staging/dgnc/dgnc_utils.c b/drivers/staging/dgnc/dgnc_utils.c
index 61efc13..80b5133 100644
--- a/drivers/staging/dgnc/dgnc_utils.c
+++ b/drivers/staging/dgnc/dgnc_utils.c
@@ -12,7 +12,7 @@
  */
 int dgnc_ms_sleep(ulong ms)
 {
-	current->state = TASK_INTERRUPTIBLE;
+	__set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout((ms * HZ) / 1000);
 	return signal_pending(current);
 }
diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h
index 3181a35..d6e0b9f 100644
--- a/drivers/staging/dgnc/digi.h
+++ b/drivers/staging/dgnc/digi.h
@@ -38,8 +38,8 @@
 
 #if !defined(TIOCMODG)
 
-#define	TIOCMODG	('d'<<8) | 250		/* get modem ctrl state	*/
-#define	TIOCMODS	('d'<<8) | 251		/* set modem ctrl state	*/
+#define	TIOCMODG	(('d'<<8) | 250)	/* get modem ctrl state	*/
+#define	TIOCMODS	(('d'<<8) | 251)	/* set modem ctrl state	*/
 
 #ifndef TIOCM_LE
 #define		TIOCM_LE	0x01		/* line enable		*/
@@ -58,44 +58,44 @@
 #endif
 
 #if !defined(TIOCMSET)
-#define	TIOCMSET	('d'<<8) | 252		/* set modem ctrl state	*/
-#define	TIOCMGET	('d'<<8) | 253		/* set modem ctrl state	*/
+#define	TIOCMSET	(('d'<<8) | 252)	/* set modem ctrl state	*/
+#define	TIOCMGET	(('d'<<8) | 253)	/* set modem ctrl state	*/
 #endif
 
 #if !defined(TIOCMBIC)
-#define	TIOCMBIC	('d'<<8) | 254		/* set modem ctrl state */
-#define	TIOCMBIS	('d'<<8) | 255		/* set modem ctrl state */
+#define	TIOCMBIC	(('d'<<8) | 254)	/* set modem ctrl state */
+#define	TIOCMBIS	(('d'<<8) | 255)	/* set modem ctrl state */
 #endif
 
 
 #if !defined(TIOCSDTR)
-#define	TIOCSDTR	('e'<<8) | 0		/* set DTR		*/
-#define	TIOCCDTR	('e'<<8) | 1		/* clear DTR		*/
+#define	TIOCSDTR	(('e'<<8) | 0)		/* set DTR		*/
+#define	TIOCCDTR	(('e'<<8) | 1)		/* clear DTR		*/
 #endif
 
 /************************************************************************
  * Ioctl command arguments for DIGI parameters.
  ************************************************************************/
-#define DIGI_GETA	('e'<<8) | 94		/* Read params		*/
+#define DIGI_GETA	(('e'<<8) | 94)		/* Read params		*/
 
-#define DIGI_SETA	('e'<<8) | 95		/* Set params		*/
-#define DIGI_SETAW	('e'<<8) | 96		/* Drain & set params	*/
-#define DIGI_SETAF	('e'<<8) | 97		/* Drain, flush & set params */
+#define DIGI_SETA	(('e'<<8) | 95)		/* Set params		*/
+#define DIGI_SETAW	(('e'<<8) | 96)		/* Drain & set params	*/
+#define DIGI_SETAF	(('e'<<8) | 97)		/* Drain, flush & set params */
 
-#define DIGI_KME	('e'<<8) | 98		/* Read/Write Host	*/
+#define DIGI_KME	(('e'<<8) | 98)		/* Read/Write Host	*/
 						/* Adapter Memory	*/
 
-#define	DIGI_GETFLOW	('e'<<8) | 99		/* Get startc/stopc flow */
+#define	DIGI_GETFLOW	(('e'<<8) | 99)		/* Get startc/stopc flow */
 						/* control characters	 */
-#define	DIGI_SETFLOW	('e'<<8) | 100		/* Set startc/stopc flow */
+#define	DIGI_SETFLOW	(('e'<<8) | 100)	/* Set startc/stopc flow */
 						/* control characters	 */
-#define	DIGI_GETAFLOW	('e'<<8) | 101		/* Get Aux. startc/stopc */
+#define	DIGI_GETAFLOW	(('e'<<8) | 101)	/* Get Aux. startc/stopc */
 						/* flow control chars	 */
-#define	DIGI_SETAFLOW	('e'<<8) | 102		/* Set Aux. startc/stopc */
+#define	DIGI_SETAFLOW	(('e'<<8) | 102)	/* Set Aux. startc/stopc */
 						/* flow control chars	 */
 
-#define DIGI_GEDELAY	('d'<<8) | 246		/* Get edelay */
-#define DIGI_SEDELAY	('d'<<8) | 247		/* Set edelay */
+#define DIGI_GEDELAY	(('d'<<8) | 246)	/* Get edelay */
+#define DIGI_SEDELAY	(('d'<<8) | 247)	/* Set edelay */
 
 struct	digiflow_t {
 	unsigned char	startc;				/* flow cntl start char	*/
@@ -104,8 +104,8 @@
 
 
 #ifdef	FLOW_2200
-#define	F2200_GETA	('e'<<8) | 104		/* Get 2x36 flow cntl flags */
-#define	F2200_SETAW	('e'<<8) | 105		/* Set 2x36 flow cntl flags */
+#define	F2200_GETA	(('e'<<8) | 104)	/* Get 2x36 flow cntl flags */
+#define	F2200_SETAW	(('e'<<8) | 105)	/* Set 2x36 flow cntl flags */
 #define		F2200_MASK	0x03		/* 2200 flow cntl bit mask  */
 #define		FCNTL_2200	0x01		/* 2x36 terminal flow cntl  */
 #define		PCNTL_2200	0x02		/* 2x36 printer flow cntl   */
@@ -241,7 +241,7 @@
 	char		dinfo_version[16];	/* driver version       */
 };
 
-#define	DIGI_GETDD	('d'<<8) | 248		/* get driver info      */
+#define	DIGI_GETDD	(('d'<<8) | 248)	/* get driver info      */
 
 /************************************************************************
  * Structure used with ioctl commands for per-board information
@@ -261,7 +261,7 @@
 	char		info_reserved[7];	/* for future expansion    */
 };
 
-#define	DIGI_GETBD	('d'<<8) | 249		/* get board info          */
+#define	DIGI_GETBD	(('d'<<8) | 249)	/* get board info          */
 
 struct digi_stat {
 	unsigned int	info_chan;		/* Channel number (0 based)  */
@@ -276,7 +276,7 @@
 	unsigned int	info_reserved[8];	/* for future expansion    */
 };
 
-#define	DIGI_GETSTAT	('d'<<8) | 244		/* get board info          */
+#define	DIGI_GETSTAT	(('d'<<8) | 244)	/* get board info          */
 /************************************************************************
  *
  * Structure used with ioctl commands for per-channel information
@@ -339,7 +339,7 @@
 #define INFO_CH_WLOW	0x0020
 #define INFO_XXBUF_BUSY 0x0040
 
-#define	DIGI_GETCH	('d'<<8) | 245		/* get board info          */
+#define	DIGI_GETCH	(('d'<<8) | 245)	/* get board info          */
 
 /* Board type definitions */
 
@@ -384,15 +384,15 @@
 #define BD_TRIBOOT	0x8
 #define	BD_BADKME	0x80
 
-#define DIGI_SPOLL            ('d'<<8) | 254  /* change poller rate   */
+#define DIGI_SPOLL            (('d'<<8) | 254)  /* change poller rate   */
 
 #define DIGI_SETCUSTOMBAUD	_IOW('e', 106, int)	/* Set integer baud rate */
 #define DIGI_GETCUSTOMBAUD	_IOR('e', 107, int)	/* Get integer baud rate */
 
-#define DIGI_REALPORT_GETBUFFERS ('e'<<8) | 108
-#define DIGI_REALPORT_SENDIMMEDIATE ('e'<<8) | 109
-#define DIGI_REALPORT_GETCOUNTERS ('e'<<8) | 110
-#define DIGI_REALPORT_GETEVENTS ('e'<<8) | 111
+#define DIGI_REALPORT_GETBUFFERS (('e'<<8) | 108)
+#define DIGI_REALPORT_SENDIMMEDIATE (('e'<<8) | 109)
+#define DIGI_REALPORT_GETCOUNTERS (('e'<<8) | 110)
+#define DIGI_REALPORT_GETEVENTS (('e'<<8) | 111)
 
 #define EV_OPU		0x0001		/* !<Output paused by client */
 #define EV_OPS		0x0002		/* !<Output paused by reqular sw flowctrl */
diff --git a/drivers/staging/dgnc/dpacompat.h b/drivers/staging/dgnc/dpacompat.h
index b2d2dc0..33cb394 100644
--- a/drivers/staging/dgnc/dpacompat.h
+++ b/drivers/staging/dgnc/dpacompat.h
@@ -51,7 +51,7 @@
 
 #define RW_READ		1
 #define RW_WRITE        2
-#define DIGI_KME        ('e'<<8) | 98           /* Read/Write Host */
+#define DIGI_KME        (('e'<<8) | 98)         /* Read/Write Host */
 
 #define SUBTYPE         0007
 #define T_PCXI          0000
@@ -106,10 +106,10 @@
 
 /* Ioctls needed for dpa operation */
 
-#define DIGI_GETDD      ('d'<<8) | 248          /* get driver info      */
-#define DIGI_GETBD      ('d'<<8) | 249          /* get board info       */
-#define DIGI_GET_NI_INFO ('d'<<8) | 250		/* nonintelligent state snfo */
+#define DIGI_GETDD      (('d'<<8) | 248)       /* get driver info      */
+#define DIGI_GETBD      (('d'<<8) | 249)       /* get board info       */
+#define DIGI_GET_NI_INFO (('d'<<8) | 250)	/* nonintelligent state snfo */
 
 /* Other special ioctls */
-#define DIGI_TIMERIRQ ('d'<<8) | 251		/* Enable/disable RS_TIMER use */
-#define DIGI_LOOPBACK ('d'<<8) | 252		/* Enable/disable UART internal loopback */
+#define DIGI_TIMERIRQ (('d'<<8) | 251)		/* Enable/disable RS_TIMER use */
+#define DIGI_LOOPBACK (('d'<<8) | 252)		/* Enable/disable UART internal loopback */
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index eb178fc..4be646c 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -1608,7 +1608,7 @@
 	switch (recipient) {
 	case USB_RECIP_DEVICE:
 		if (udc->ctrl.wIndex == 0x0000) {
-			if (udc->self_powered)
+			if (udc->gadget.is_selfpowered)
 				status_data |= (1 << USB_DEVICE_SELF_POWERED);
 
 			if (udc->remote_wakeup)
@@ -3117,7 +3117,7 @@
 static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
 					int is_selfpowered)
 {
-	struct nbu2ss_udc	*udc;
+	struct nbu2ss_udc       *udc;
 	unsigned long		flags;
 
 /*	INFO("=== %s()\n", __func__); */
@@ -3130,7 +3130,7 @@
 	udc = container_of(pgadget, struct nbu2ss_udc, gadget);
 
 	spin_lock_irqsave(&udc->lock, flags);
-	udc->self_powered = (is_selfpowered != 0);
+	pgadget->is_selfpowered = (is_selfpowered != 0);
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	return 0;
@@ -3249,42 +3249,6 @@
 };
 
 /*-------------------------------------------------------------------------*/
-static void __init nbu2ss_drv_set_ep_info(
-	struct nbu2ss_udc	*udc,
-	struct nbu2ss_ep	*ep,
-	const char *name)
-{
-	ep->udc = udc;
-	ep->desc = NULL;
-
-	ep->ep.driver_data = NULL;
-	ep->ep.name = name;
-	ep->ep.ops = &nbu2ss_ep_ops;
-
-	if (isdigit(name[2])) {
-
-		long	num;
-		int	res;
-		char	tempbuf[2];
-
-		tempbuf[0] = name[2];
-		tempbuf[1] = '\0';
-		res = kstrtol(tempbuf, 16, &num);
-
-		if (num == 0)
-			ep->ep.maxpacket = EP0_PACKETSIZE;
-		else
-			ep->ep.maxpacket = EP_PACKETSIZE;
-
-	} else {
-		ep->ep.maxpacket = EP_PACKETSIZE;
-	}
-
-	list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-	INIT_LIST_HEAD(&ep->queue);
-}
-
-/*-------------------------------------------------------------------------*/
 static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
 {
 	int	i;
@@ -3292,9 +3256,21 @@
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
 	udc->gadget.ep0 = &udc->ep[0].ep;
 
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct nbu2ss_ep *ep = &udc->ep[i];
 
-	for (i = 0; i < NUM_ENDPOINTS; i++)
-		nbu2ss_drv_set_ep_info(udc, &udc->ep[i], gp_ep_name[i]);
+		ep->udc = udc;
+		ep->desc = NULL;
+
+		ep->ep.driver_data = NULL;
+		ep->ep.name = gp_ep_name[i];
+		ep->ep.ops = &nbu2ss_ep_ops;
+
+		ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
+
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		INIT_LIST_HEAD(&ep->queue);
+	}
 
 	list_del_init(&udc->ep[0].ep.ep_list);
 }
@@ -3308,7 +3284,7 @@
 	spin_lock_init(&udc->lock);
 	udc->dev = &pdev->dev;
 
-	udc->self_powered = 1;
+	udc->gadget.is_selfpowered = 1;
 	udc->devstate = USB_STATE_NOTATTACHED;
 	udc->pdev = pdev;
 	udc->mA = 0;
diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h
index ee1b80d..202e2dc 100644
--- a/drivers/staging/emxx_udc/emxx_udc.h
+++ b/drivers/staging/emxx_udc/emxx_udc.h
@@ -624,7 +624,6 @@
 	unsigned		linux_suspended:1;
 	unsigned		linux_resume:1;
 	unsigned		usb_suspended:1;
-	unsigned		self_powered:1;
 	unsigned		remote_wakeup:1;
 	unsigned		udc_enabled:1;
 
diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
new file mode 100644
index 0000000..995a910
--- /dev/null
+++ b/drivers/staging/fbtft/Kconfig
@@ -0,0 +1,169 @@
+menuconfig FB_TFT
+	tristate "Support for small TFT LCD display modules"
+	depends on FB && SPI && GPIOLIB
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	select FB_DEFERRED_IO
+	select FB_BACKLIGHT
+
+config FB_TFT_AGM1264K_FL
+	tristate "FB driver for the AGM1264K-FL LCD display"
+	depends on FB_TFT
+	help
+	  Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips)
+
+config FB_TFT_BD663474
+	tristate "FB driver for the BD663474 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for BD663474
+
+config FB_TFT_HX8340BN
+	tristate "FB driver for the HX8340BN LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for HX8340BN
+
+config FB_TFT_HX8347D
+	tristate "FB driver for the HX8347D LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for HX8347D
+
+config FB_TFT_HX8353D
+	tristate "FB driver for the HX8353D LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for HX8353D
+
+config FB_TFT_ILI9320
+	tristate "FB driver for the ILI9320 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9320
+
+config FB_TFT_ILI9325
+	tristate "FB driver for the ILI9325 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9325
+
+config FB_TFT_ILI9340
+	tristate "FB driver for the ILI9340 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9340
+
+config FB_TFT_ILI9341
+	tristate "FB driver for the ILI9341 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9341
+
+config FB_TFT_ILI9481
+	tristate "FB driver for the ILI9481 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9481
+
+config FB_TFT_ILI9486
+	tristate "FB driver for the ILI9486 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ILI9486
+
+config FB_TFT_PCD8544
+	tristate "FB driver for the PCD8544 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for PCD8544
+
+config FB_TFT_RA8875
+        tristate "FB driver for the RA8875 LCD Controller"
+        depends on FB_TFT
+	help
+	  Generic Framebuffer support for RA8875
+
+config FB_TFT_S6D02A1
+	tristate "FB driver for the S6D02A1 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for S6D02A1
+
+config FB_TFT_S6D1121
+	tristate "FB driver for the S6D1211 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for S6D1121
+
+config FB_TFT_SSD1289
+	tristate "FB driver for the SSD1289 LCD Controller"
+	depends on FB_TFT
+	help
+	  Framebuffer support for SSD1289
+
+config FB_TFT_SSD1306
+	tristate "FB driver for the SSD1306 OLED Controller"
+	depends on FB_TFT
+	help
+	  Framebuffer support for SSD1306
+
+config FB_TFT_SSD1331
+	tristate "FB driver for the SSD1331 LCD Controller"
+	depends on FB_TFT
+	help
+	  Framebuffer support for SSD1331
+
+config FB_TFT_SSD1351
+	tristate "FB driver for the SSD1351 LCD Controller"
+	depends on FB_TFT
+	help
+	  Framebuffer support for SSD1351
+
+config FB_TFT_ST7735R
+	tristate "FB driver for the ST7735R LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for ST7735R
+
+config FB_TFT_TINYLCD
+	tristate "FB driver for tinylcd.com display"
+	depends on FB_TFT
+	help
+	  Custom Framebuffer support for tinylcd.com display
+
+config FB_TFT_TLS8204
+	tristate "FB driver for the TLS8204 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for TLS8204
+
+config FB_TFT_UC1701
+	tristate "FB driver for the UC1701 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for UC1701
+
+config FB_TFT_UPD161704
+	tristate "FB driver for the uPD161704 LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for uPD161704
+
+config FB_TFT_WATTEROTT
+	tristate "FB driver for the WATTEROTT LCD Controller"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for WATTEROTT
+
+config FB_FLEX
+	tristate "Generic FB driver for TFT LCD displays"
+	depends on FB_TFT
+	help
+	  Generic Framebuffer support for TFT LCD displays.
+
+config FB_TFT_FBTFT_DEVICE
+	tristate "Module to for adding FBTFT devices"
+	depends on FB_TFT
diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile
new file mode 100644
index 0000000..e773f0f
--- /dev/null
+++ b/drivers/staging/fbtft/Makefile
@@ -0,0 +1,34 @@
+# Core module
+obj-$(CONFIG_FB_TFT)             += fbtft.o
+fbtft-y                          += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o
+
+# drivers
+obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o
+obj-$(CONFIG_FB_TFT_BD663474)    += fb_bd663474.o
+obj-$(CONFIG_FB_TFT_HX8340BN)    += fb_hx8340bn.o
+obj-$(CONFIG_FB_TFT_HX8347D)     += fb_hx8347d.o
+obj-$(CONFIG_FB_TFT_HX8353D)     += fb_hx8353d.o
+obj-$(CONFIG_FB_TFT_ILI9320)     += fb_ili9320.o
+obj-$(CONFIG_FB_TFT_ILI9325)     += fb_ili9325.o
+obj-$(CONFIG_FB_TFT_ILI9340)     += fb_ili9340.o
+obj-$(CONFIG_FB_TFT_ILI9341)     += fb_ili9341.o
+obj-$(CONFIG_FB_TFT_ILI9481)     += fb_ili9481.o
+obj-$(CONFIG_FB_TFT_ILI9486)     += fb_ili9486.o
+obj-$(CONFIG_FB_TFT_PCD8544)     += fb_pcd8544.o
+obj-$(CONFIG_FB_TFT_RA8875)      += fb_ra8875.o
+obj-$(CONFIG_FB_TFT_S6D02A1)     += fb_s6d02a1.o
+obj-$(CONFIG_FB_TFT_S6D1121)     += fb_s6d1121.o
+obj-$(CONFIG_FB_TFT_SSD1289)     += fb_ssd1289.o
+obj-$(CONFIG_FB_TFT_SSD1306)     += fb_ssd1306.o
+obj-$(CONFIG_FB_TFT_SSD1331)     += fb_ssd1331.o
+obj-$(CONFIG_FB_TFT_SSD1351)     += fb_ssd1351.o
+obj-$(CONFIG_FB_TFT_ST7735R)     += fb_st7735r.o
+obj-$(CONFIG_FB_TFT_TINYLCD)     += fb_tinylcd.o
+obj-$(CONFIG_FB_TFT_TLS8204)     += fb_tls8204.o
+obj-$(CONFIG_FB_TFT_UC1701)      += fb_uc1701.o
+obj-$(CONFIG_FB_TFT_UPD161704)   += fb_upd161704.o
+obj-$(CONFIG_FB_TFT_WATTEROTT)   += fb_watterott.o
+obj-$(CONFIG_FB_FLEX)            += flexfb.o
+
+# Device modules
+obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o
diff --git a/drivers/staging/fbtft/README b/drivers/staging/fbtft/README
new file mode 100644
index 0000000..bc89b58
--- /dev/null
+++ b/drivers/staging/fbtft/README
@@ -0,0 +1,32 @@
+  FBTFT
+=========
+
+Linux Framebuffer drivers for small TFT LCD display modules.
+The module 'fbtft' makes writing drivers for some of these displays very easy.
+
+Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution.
+
+INSTALLATION
+  Download kernel sources
+
+  From Linux 3.15  
+    cd drivers/video/fbdev/fbtft
+    git clone https://github.com/notro/fbtft.git
+    
+    Add to drivers/video/fbdev/Kconfig:   source "drivers/video/fbdev/fbtft/Kconfig"
+    Add to drivers/video/fbdev/Makefile:  obj-y += fbtft/
+  
+  Before Linux 3.15  
+    cd drivers/video
+    git clone https://github.com/notro/fbtft.git
+    
+    Add to drivers/video/Kconfig:   source "drivers/video/fbtft/Kconfig"
+    Add to drivers/video/Makefile:  obj-y += fbtft/
+  
+  Enable driver(s) in menuconfig and build the kernel
+
+
+See wiki for more information: https://github.com/notro/fbtft/wiki
+
+
+Source: https://github.com/notro/fbtft/
diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c
new file mode 100644
index 0000000..9cc7d25
--- /dev/null
+++ b/drivers/staging/fbtft/fb_agm1264k-fl.c
@@ -0,0 +1,462 @@
+/*
+ * FB driver for Two KS0108 LCD controllers in AGM1264K-FL display
+ *
+ * Copyright (C) 2014 ololoshka2871
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "fbtft.h"
+
+/* Uncomment text line to use negative image on display */
+/*#define NEGATIVE*/
+
+#define WHITE		0xff
+#define BLACK		0
+
+#define DRVNAME		"fb_agm1264k-fl"
+#define WIDTH		64
+#define HEIGHT		64
+#define TOTALWIDTH	(WIDTH * 2)	 /* because 2 x ks0108 in one display */
+#define FPS			20
+
+#define EPIN		gpio.wr
+#define RS			gpio.dc
+#define RW			gpio.aux[2]
+#define CS0			gpio.aux[0]
+#define CS1			gpio.aux[1]
+
+
+/* diffusing error (“Floyd-Steinberg”) */
+#define DIFFUSING_MATRIX_WIDTH	2
+#define DIFFUSING_MATRIX_HEIGHT	2
+
+static const signed char
+diffusing_matrix[DIFFUSING_MATRIX_WIDTH][DIFFUSING_MATRIX_HEIGHT] = {
+	{-1, 3},
+	{3, 2},
+};
+
+static const unsigned char gamma_correction_table[] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6,
+6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13,
+13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21,
+22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32,
+33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45,
+46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 81,
+82, 83, 84, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 102,
+103, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119, 120, 121,
+123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 141, 143,
+145, 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166,
+168, 170, 172, 173, 175, 177, 179, 181, 182, 184, 186, 188, 190, 192,
+194, 196, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219,
+221, 223, 225, 227, 229, 231, 234, 236, 238, 240, 242, 244, 246, 248,
+251, 253, 255
+};
+
+static int init_display(struct fbtft_par *par)
+{
+	u8 i;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	for (i = 0; i < 2; ++i) {
+		write_reg(par, i, 0x3f); /* display on */
+		write_reg(par, i, 0x40); /* set x to 0 */
+		write_reg(par, i, 0xb0); /* set page to 0 */
+		write_reg(par, i, 0xc0); /* set start line to 0 */
+	}
+
+	return 0;
+}
+
+static void reset(struct fbtft_par *par)
+{
+	if (par->gpio.reset == -1)
+		return;
+
+	fbtft_dev_dbg(DEBUG_RESET, par, par->info->device, "%s()\n", __func__);
+
+	gpio_set_value(par->gpio.reset, 0);
+	udelay(20);
+	gpio_set_value(par->gpio.reset, 1);
+	mdelay(120);
+}
+
+/* Check if all necessary GPIOS defined */
+static int verify_gpios(struct fbtft_par *par)
+{
+	int i;
+
+	fbtft_dev_dbg(DEBUG_VERIFY_GPIOS, par, par->info->device,
+		"%s()\n", __func__);
+
+	if (par->EPIN < 0) {
+		dev_err(par->info->device,
+			"Missing info about 'wr' (aka E) gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < 8; ++i) {
+		if (par->gpio.db[i] < 0) {
+			dev_err(par->info->device,
+				"Missing info about 'db[%i]' gpio. Aborting.\n",
+				i);
+			return -EINVAL;
+		}
+	}
+	if (par->CS0 < 0) {
+		dev_err(par->info->device,
+			"Missing info about 'cs0' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	if (par->CS1 < 0) {
+		dev_err(par->info->device,
+			"Missing info about 'cs1' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	if (par->RW < 0) {
+		dev_err(par->info->device,
+			"Missing info about 'rw' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned long
+request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio)
+{
+	fbtft_dev_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, par->info->device,
+		"%s('%s')\n", __func__, gpio->name);
+
+	if (strcasecmp(gpio->name, "wr") == 0) {
+		/* left ks0108 E pin */
+		par->EPIN = gpio->gpio;
+		return GPIOF_OUT_INIT_LOW;
+	} else if (strcasecmp(gpio->name, "cs0") == 0) {
+		/* left ks0108 controller pin */
+		par->CS0 = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	} else if (strcasecmp(gpio->name, "cs1") == 0) {
+		/* right ks0108 controller pin */
+		par->CS1 = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	}
+
+	/* if write (rw = 0) e(1->0) perform write */
+	/* if read (rw = 1) e(0->1) set data on D0-7*/
+	else if (strcasecmp(gpio->name, "rw") == 0) {
+		par->RW = gpio->gpio;
+		return GPIOF_OUT_INIT_LOW;
+	}
+
+	return FBTFT_GPIO_NO_MATCH;
+}
+
+/* This function oses to enter commands
+ * first byte - destination controller 0 or 1
+ * folowing - commands
+ */
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+	va_list args;
+	int i, ret;
+	u8 *buf = (u8 *)par->buf;
+
+	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+		va_start(args, len);
+		for (i = 0; i < len; i++)
+			buf[i] = (u8)va_arg(args, unsigned int);
+
+		va_end(args);
+		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+			par->info->device, u8, buf, len, "%s: ", __func__);
+	}
+
+	va_start(args, len);
+
+	*buf = (u8)va_arg(args, unsigned int);
+
+	if (*buf > 1) {
+		va_end(args);
+		dev_err(par->info->device, "%s: Incorrect chip sellect request (%d)\n",
+			__func__, *buf);
+		return;
+	}
+
+	/* select chip */
+	if (*buf) {
+		/* cs1 */
+		gpio_set_value(par->CS0, 1);
+		gpio_set_value(par->CS1, 0);
+	} else {
+		/* cs0 */
+		gpio_set_value(par->CS0, 0);
+		gpio_set_value(par->CS1, 1);
+	}
+
+	gpio_set_value(par->RS, 0); /* RS->0 (command mode) */
+	len--;
+
+	if (len) {
+		i = len;
+		while (i--)
+			*buf++ = (u8)va_arg(args, unsigned int);
+		ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8)));
+		if (ret < 0) {
+			va_end(args);
+			dev_err(par->info->device, "%s: write() failed and returned %d\n",
+				__func__, ret);
+			return;
+		}
+	}
+
+	va_end(args);
+}
+
+static struct
+{
+	int xs, ys_page, xe, ye_page;
+} addr_win;
+
+/* save display writing zone */
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	addr_win.xs = xs;
+	addr_win.ys_page = ys / 8;
+	addr_win.xe = xe;
+	addr_win.ye_page = ye / 8;
+
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys_page=%d, xe=%d, ye_page=%d)\n", __func__,
+		addr_win.xs, addr_win.ys_page, addr_win.xe, addr_win.ye_page);
+}
+
+static void
+construct_line_bitmap(struct fbtft_par *par, u8 *dest, signed short *src,
+						int xs, int xe, int y)
+{
+	int x, i;
+
+	for (x = xs; x < xe; ++x) {
+		u8 res = 0;
+
+		for (i = 0; i < 8; i++)
+			if (src[(y * 8 + i) * par->info->var.xres + x])
+				res |= 1 << i;
+#ifdef NEGATIVE
+		*dest++ = res;
+#else
+		*dest++ = ~res;
+#endif
+	}
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16 = (u16 *)par->info->screen_base;
+	u8 *buf = par->txbuf.buf;
+	int x, y;
+	int ret = 0;
+
+	/* buffer to convert RGB565 -> grayscale16 -> Ditherd image 1bpp */
+	signed short *convert_buf = kmalloc(par->info->var.xres *
+		par->info->var.yres * sizeof(signed short), GFP_NOIO);
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	/* converting to grayscale16 */
+	for (x = 0; x < par->info->var.xres; ++x)
+		for (y = 0; y < par->info->var.yres; ++y) {
+			u16 pixel = vmem16[y *  par->info->var.xres + x];
+			u16 b = pixel & 0x1f;
+			u16 g = (pixel & (0x3f << 5)) >> 5;
+			u16 r = (pixel & (0x1f << (5 + 6))) >> (5 + 6);
+
+			pixel = (299 * r + 587 * g + 114 * b) / 200;
+			if (pixel > 255)
+				pixel = 255;
+
+			/* gamma-correction by table */
+			convert_buf[y *  par->info->var.xres + x] =
+				(signed short)gamma_correction_table[pixel];
+		}
+
+	/* Image Dithering */
+	for (x = 0; x < par->info->var.xres; ++x)
+		for (y = 0; y < par->info->var.yres; ++y) {
+			signed short pixel =
+				convert_buf[y *  par->info->var.xres + x];
+			signed short error_b = pixel - BLACK;
+			signed short error_w = pixel - WHITE;
+			signed short error;
+			u16 i, j;
+
+			/* what color close? */
+			if (abs(error_b) >= abs(error_w)) {
+				/* white */
+				error = error_w;
+				pixel = 0xff;
+			} else {
+				/* black */
+				error = error_b;
+				pixel = 0;
+			}
+
+			error /= 8;
+
+			/* diffusion matrix row */
+			for (i = 0; i < DIFFUSING_MATRIX_WIDTH; ++i)
+				/* diffusion matrix column */
+				for (j = 0; j < DIFFUSING_MATRIX_HEIGHT; ++j) {
+					signed short *write_pos;
+					signed char coeff;
+
+					/* skip pixels out of zone */
+					if (x + i < 0 ||
+						x + i >= par->info->var.xres
+						|| y + j >= par->info->var.yres)
+						continue;
+					write_pos = &convert_buf[
+						(y + j) * par->info->var.xres +
+						x + i];
+					coeff = diffusing_matrix[i][j];
+					if (coeff == -1)
+						/* pixel itself */
+						*write_pos = pixel;
+					else {
+						signed short p = *write_pos +
+							error * coeff;
+
+						if (p > WHITE)
+							p = WHITE;
+						if (p < BLACK)
+							p = BLACK;
+						*write_pos = p;
+					}
+				}
+		}
+
+	 /* 1 string = 2 pages */
+	 for (y = addr_win.ys_page; y <= addr_win.ye_page; ++y) {
+		/* left half of display */
+		if (addr_win.xs < par->info->var.xres / 2) {
+			construct_line_bitmap(par, buf, convert_buf,
+				addr_win.xs, par->info->var.xres / 2, y);
+
+			len = par->info->var.xres / 2 - addr_win.xs;
+
+			/* select left side (sc0)
+			 * set addr
+			 */
+			write_reg(par, 0x00, (1 << 6) | (u8)addr_win.xs);
+			write_reg(par, 0x00, (0x17 << 3) | (u8)y);
+
+			/* write bitmap */
+			gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+			ret = par->fbtftops.write(par, buf, len);
+			if (ret < 0)
+				dev_err(par->info->device,
+					"%s: write failed and returned: %d\n",
+					__func__, ret);
+		}
+		/* right half of display */
+		if (addr_win.xe >= par->info->var.xres / 2) {
+			construct_line_bitmap(par, buf,
+				convert_buf, par->info->var.xres / 2,
+				addr_win.xe + 1, y);
+
+			len = addr_win.xe + 1 - par->info->var.xres / 2;
+
+			/* select right side (sc1)
+			 * set addr
+			 */
+			write_reg(par, 0x01, (1 << 6));
+			write_reg(par, 0x01, (0x17 << 3) | (u8)y);
+
+			/* write bitmap */
+			gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+			par->fbtftops.write(par, buf, len);
+			if (ret < 0)
+				dev_err(par->info->device,
+					"%s: write failed and returned: %d\n",
+					__func__, ret);
+		}
+	}
+	kfree(convert_buf);
+
+	gpio_set_value(par->CS0, 1);
+	gpio_set_value(par->CS1, 1);
+
+	return ret;
+}
+
+static int write(struct fbtft_par *par, void *buf, size_t len)
+{
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	gpio_set_value(par->RW, 0); /* set write mode */
+
+
+	while (len--) {
+		u8 i, data;
+
+		data = *(u8 *) buf++;
+
+		/* set data bus */
+		for (i = 0; i < 8; ++i)
+			gpio_set_value(par->gpio.db[i], data & (1 << i));
+		/* set E */
+		gpio_set_value(par->EPIN, 1);
+		udelay(5);
+		/* unset E - write */
+		gpio_set_value(par->EPIN, 0);
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = TOTALWIDTH,
+	.height = HEIGHT,
+	.fps = FPS,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.verify_gpios = verify_gpios,
+		.request_gpios_match = request_gpios_match,
+		.reset = reset,
+		.write = write,
+		.write_register = write_reg8_bus8,
+		.write_vmem = write_vmem,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "displaytronic,fb_agm1264k-fl", &display);
+
+MODULE_ALIAS("platform:" DRVNAME);
+
+MODULE_DESCRIPTION("Two KS0108 LCD controllers in AGM1264K-FL display");
+MODULE_AUTHOR("ololoshka2871");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c
new file mode 100644
index 0000000..7e00c60
--- /dev/null
+++ b/drivers/staging/fbtft/fb_bd663474.c
@@ -0,0 +1,193 @@
+/*
+ * FB driver for the uPD161704 LCD Controller
+ *
+ * Copyright (C) 2014 Seong-Woo Kim
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_bd663474"
+#define WIDTH		240
+#define HEIGHT		320
+#define BPP		16
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	par->fbtftops.reset(par);
+
+	/* Initialization sequence from Lib_UTFT */
+
+	/* oscillator start */
+	write_reg(par, 0x000,0x0001);	/*oscillator 0: stop, 1: operation */
+	mdelay(10);
+
+	/* Power settings */
+	write_reg(par, 0x100, 0x0000 ); /* power supply setup */
+	write_reg(par, 0x101, 0x0000 );
+	write_reg(par, 0x102, 0x3110 );
+	write_reg(par, 0x103, 0xe200 );
+	write_reg(par, 0x110, 0x009d );
+	write_reg(par, 0x111, 0x0022 );
+	write_reg(par, 0x100, 0x0120 );
+	mdelay( 20 );
+
+	write_reg(par, 0x100, 0x3120 );
+	mdelay( 80 );
+	/* Display control */
+	write_reg(par, 0x001, 0x0100 );
+	write_reg(par, 0x002, 0x0000 );
+	write_reg(par, 0x003, 0x1230 );
+	write_reg(par, 0x006, 0x0000 );
+	write_reg(par, 0x007, 0x0101 );
+	write_reg(par, 0x008, 0x0808 );
+	write_reg(par, 0x009, 0x0000 );
+	write_reg(par, 0x00b, 0x0000 );
+	write_reg(par, 0x00c, 0x0000 );
+	write_reg(par, 0x00d, 0x0018 );
+	/* LTPS control settings */
+	write_reg(par, 0x012, 0x0000 );
+	write_reg(par, 0x013, 0x0000 );
+	write_reg(par, 0x018, 0x0000 );
+	write_reg(par, 0x019, 0x0000 );
+
+	write_reg(par, 0x203, 0x0000 );
+	write_reg(par, 0x204, 0x0000 );
+
+	write_reg(par, 0x210, 0x0000 );
+	write_reg(par, 0x211, 0x00ef );
+	write_reg(par, 0x212, 0x0000 );
+	write_reg(par, 0x213, 0x013f );
+	write_reg(par, 0x214, 0x0000 );
+	write_reg(par, 0x215, 0x0000 );
+	write_reg(par, 0x216, 0x0000 );
+	write_reg(par, 0x217, 0x0000 );
+
+	/* Gray scale settings */
+	write_reg(par, 0x300, 0x5343);
+	write_reg(par, 0x301, 0x1021);
+	write_reg(par, 0x302, 0x0003);
+	write_reg(par, 0x303, 0x0011);
+	write_reg(par, 0x304, 0x050a);
+	write_reg(par, 0x305, 0x4342);
+	write_reg(par, 0x306, 0x1100);
+	write_reg(par, 0x307, 0x0003);
+	write_reg(par, 0x308, 0x1201);
+	write_reg(par, 0x309, 0x050a);
+
+	/* RAM access settings */
+	write_reg(par, 0x400, 0x4027 );
+	write_reg(par, 0x401, 0x0000 );
+	write_reg(par, 0x402, 0x0000 );  /* First screen drive position (1) */
+	write_reg(par, 0x403, 0x013f );  /* First screen drive position (2) */
+	write_reg(par, 0x404, 0x0000 );
+
+	write_reg(par, 0x200, 0x0000 );
+	write_reg(par, 0x201, 0x0000 );
+	write_reg(par, 0x100, 0x7120 );
+	write_reg(par, 0x007, 0x0103 );
+	mdelay( 10 );
+	write_reg(par, 0x007, 0x0113 );
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	switch (par->info->var.rotate) {
+	/* R200h = Horizontal GRAM Start Address */
+	/* R201h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0200, xs);
+		write_reg(par, 0x0201, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0200, WIDTH - 1 - xs);
+		write_reg(par, 0x0201, HEIGHT - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0200, WIDTH - 1 - ys);
+		write_reg(par, 0x0201, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0200, ys);
+		write_reg(par, 0x0201, HEIGHT - 1 - xs);
+		break;
+	}
+	write_reg(par, 0x202); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	/* AM: GRAM update direction */
+	case 0:
+		write_reg(par, 0x003, 0x1230);
+		break;
+	case 180:
+		write_reg(par, 0x003, 0x1200);
+		break;
+	case 270:
+		write_reg(par, 0x003, 0x1228);
+		break;
+	case 90:
+		write_reg(par, 0x003, 0x1218);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.bpp = BPP,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:bd663474");
+MODULE_ALIAS("platform:bd663474");
+
+MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller");
+MODULE_AUTHOR("Seong-Woo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8340bn.c b/drivers/staging/fbtft/fb_hx8340bn.c
new file mode 100644
index 0000000..3939502
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8340bn.c
@@ -0,0 +1,229 @@
+/*
+ * FB driver for the HX8340BN LCD Controller
+ *
+ * This display uses 9-bit SPI: Data/Command bit + 8 data bits
+ * For platforms that doesn't support 9-bit, the driver is capable
+ * of emulating this using 8-bit transfer.
+ * This is done by transfering eight 9-bit words in 9 bytes.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_hx8340bn"
+#define WIDTH		176
+#define HEIGHT		220
+#define TXBUFLEN	(4 * PAGE_SIZE)
+#define DEFAULT_GAMMA	"1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \
+			"3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
+
+
+static bool emulate;
+module_param(emulate, bool, 0);
+MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* BTL221722-276L startup sequence, from datasheet */
+
+	/* SETEXTCOM: Set extended command set (C1h)
+	   This command is used to set extended command set access enable.
+	   Enable: After command (C1h), must write: ffh,83h,40h */
+	write_reg(par, 0xC1, 0xFF, 0x83, 0x40);
+
+	/* Sleep out
+	   This command turns off sleep mode.
+	   In this mode the DC/DC converter is enabled, Internal oscillator
+	   is started, and panel scanning is started. */
+	write_reg(par, 0x11);
+	mdelay(150);
+
+	/* Undoc'd register? */
+	write_reg(par, 0xCA, 0x70, 0x00, 0xD9);
+
+	/* SETOSC: Set Internal Oscillator (B0h)
+	   This command is used to set internal oscillator related settings */
+	/*	OSC_EN: Enable internal oscillator */
+	/*	Internal oscillator frequency: 125% x 2.52MHz */
+	write_reg(par, 0xB0, 0x01, 0x11);
+
+	/* Drive ability setting */
+	write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06);
+	mdelay(20);
+
+	/* SETPWCTR5: Set Power Control 5(B5h)
+	   This command is used to set VCOM Low and VCOM High Voltage */
+	/* VCOMH 0110101 :  3.925 */
+	/* VCOML 0100000 : -1.700 */
+	/* 45h=69  VCOMH: "VMH" + 5d   VCOML: "VMH" + 5d */
+	write_reg(par, 0xB5, 0x35, 0x20, 0x45);
+
+	/* SETPWCTR4: Set Power Control 4(B4h)
+		VRH[4:0]:	Specify the VREG1 voltage adjusting.
+				VREG1 voltage is for gamma voltage setting.
+		BT[2:0]:	Switch the output factor of step-up circuit 2
+				for VGH and VGL voltage generation. */
+	write_reg(par, 0xB4, 0x33, 0x25, 0x4C);
+	mdelay(10);
+
+	/* Interface Pixel Format (3Ah)
+	   This command is used to define the format of RGB picture data,
+	   which is to be transfer via the system and RGB interface. */
+	/* RGB interface: 16 Bit/Pixel	*/
+	write_reg(par, 0x3A, 0x05);
+
+	/* Display on (29h)
+	   This command is used to recover from DISPLAY OFF mode.
+	   Output from the Frame Memory is enabled. */
+	write_reg(par, 0x29);
+	mdelay(10);
+
+	return 0;
+}
+
+void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe);
+	write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye);
+	write_reg(par, FBTFT_RAMWR);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* MADCTL - Memory data access control */
+	/* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, (par->bgr << 3));
+		break;
+	case 270:
+		write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma Curve selection, GC (only GC0 can be customized):
+    0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0
+  Gamma string format:
+    OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1
+    ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX  GC
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111,
+		0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b11, 0b11,
+		0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111,
+		0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b0, 0b0 };
+	int i, j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < par->gamma.num_curves; i++)
+		for (j = 0; j < par->gamma.num_values; j++)
+			CURVE(i, j) &= mask[i * par->gamma.num_values + j];
+
+	write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */
+
+	if (CURVE(1, 14))
+		return 0; /* only GC0 can be customized */
+
+	write_reg(par, 0xC2,
+		(CURVE(0, 8) << 4) | CURVE(0, 7),
+		(CURVE(0, 10) << 4) | CURVE(0, 9),
+		(CURVE(0, 12) << 4) | CURVE(0, 11),
+		CURVE(0, 2),
+		(CURVE(0, 4) << 4) | CURVE(0, 3),
+		CURVE(0, 5),
+		CURVE(0, 6),
+		(CURVE(0, 1) << 4) | CURVE(0, 0),
+		(CURVE(0, 14) << 2) | CURVE(0, 13));
+
+	write_reg(par, 0xC3,
+		(CURVE(1, 8) << 4) | CURVE(1, 7),
+		(CURVE(1, 10) << 4) | CURVE(1, 9),
+		(CURVE(1, 12) << 4) | CURVE(1, 11),
+		CURVE(1, 2),
+		(CURVE(1, 4) << 4) | CURVE(1, 3),
+		CURVE(1, 5),
+		CURVE(1, 6),
+		(CURVE(1, 1) << 4) | CURVE(1, 0));
+
+	mdelay(10);
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.txbuflen = TXBUFLEN,
+	.gamma_num = 2,
+	.gamma_len = 15,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8340bn");
+MODULE_ALIAS("platform:hx8340bn");
+
+MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8347d.c b/drivers/staging/fbtft/fb_hx8347d.c
new file mode 100644
index 0000000..8139a8f
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8347d.c
@@ -0,0 +1,181 @@
+/*
+ * FB driver for the HX8347D LCD Controller
+ *
+ * Copyright (C) 2013 Christian Vogelgsang
+ *
+ * Based on driver code found here: https://github.com/watterott/r61505u-Adapter
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_hx8347d"
+#define WIDTH		320
+#define HEIGHT		240
+#define DEFAULT_GAMMA	"0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" \
+			"0 0 0 0 0 0 0 0 0 0 0 0 0 0"
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* driving ability */
+	write_reg(par, 0xEA, 0x00);
+	write_reg(par, 0xEB, 0x20);
+	write_reg(par, 0xEC, 0x0C);
+	write_reg(par, 0xED, 0xC4);
+	write_reg(par, 0xE8, 0x40);
+	write_reg(par, 0xE9, 0x38);
+	write_reg(par, 0xF1, 0x01);
+	write_reg(par, 0xF2, 0x10);
+	write_reg(par, 0x27, 0xA3);
+
+	/* power voltage */
+	write_reg(par, 0x1B, 0x1B);
+	write_reg(par, 0x1A, 0x01);
+	write_reg(par, 0x24, 0x2F);
+	write_reg(par, 0x25, 0x57);
+
+	/* VCOM offset */
+	write_reg(par, 0x23, 0x8D); /* for flicker adjust */
+
+	/* power on */
+	write_reg(par, 0x18, 0x36);
+	write_reg(par, 0x19, 0x01); /* start osc */
+	write_reg(par, 0x01, 0x00); /* wakeup */
+	write_reg(par, 0x1F, 0x88);
+	mdelay(5);
+	write_reg(par, 0x1F, 0x80);
+	mdelay(5);
+	write_reg(par, 0x1F, 0x90);
+	mdelay(5);
+	write_reg(par, 0x1F, 0xD0);
+	mdelay(5);
+
+	/* color selection */
+	write_reg(par, 0x17, 0x05); /* 65k */
+
+	/*panel characteristic */
+	write_reg(par, 0x36, 0x00);
+
+	/*display on */
+	write_reg(par, 0x28, 0x38);
+	mdelay(40);
+	write_reg(par, 0x28, 0x3C);
+
+	/* orientation */
+	write_reg(par, 0x16, 0x60 | (par->bgr << 3));
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	write_reg(par, 0x02, (xs >> 8) & 0xFF);
+	write_reg(par, 0x03, xs & 0xFF);
+	write_reg(par, 0x04, (xe >> 8) & 0xFF);
+	write_reg(par, 0x05, xe & 0xFF);
+	write_reg(par, 0x06, (ys >> 8) & 0xFF);
+	write_reg(par, 0x07, ys & 0xFF);
+	write_reg(par, 0x08, (ye >> 8) & 0xFF);
+	write_reg(par, 0x09, ye & 0xFF);
+	write_reg(par, 0x22);
+}
+
+/*
+  Gamma string format:
+    VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM
+    VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+		0b1111111, 0b1111111,
+		0b11111, 0b11111, 0b11111, 0b11111, 0b11111,
+		0b1111};
+	int i, j;
+	int acc = 0;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < par->gamma.num_curves; i++)
+		for (j = 0; j < par->gamma.num_values; j++) {
+			acc += CURVE(i, j);
+			CURVE(i, j) &= mask[j];
+		}
+
+	if (acc == 0) /* skip if all values are zero */
+		return 0;
+
+	for (i = 0; i < par->gamma.num_curves; i++) {
+		write_reg(par, 0x40 + (i * 0x10), CURVE(i, 0));
+		write_reg(par, 0x41 + (i * 0x10), CURVE(i, 1));
+		write_reg(par, 0x42 + (i * 0x10), CURVE(i, 2));
+		write_reg(par, 0x43 + (i * 0x10), CURVE(i, 3));
+		write_reg(par, 0x44 + (i * 0x10), CURVE(i, 4));
+		write_reg(par, 0x45 + (i * 0x10), CURVE(i, 5));
+		write_reg(par, 0x46 + (i * 0x10), CURVE(i, 6));
+		write_reg(par, 0x47 + (i * 0x10), CURVE(i, 7));
+		write_reg(par, 0x48 + (i * 0x10), CURVE(i, 8));
+		write_reg(par, 0x49 + (i * 0x10), CURVE(i, 9));
+		write_reg(par, 0x4A + (i * 0x10), CURVE(i, 10));
+		write_reg(par, 0x4B + (i * 0x10), CURVE(i, 11));
+		write_reg(par, 0x4C + (i * 0x10), CURVE(i, 12));
+	}
+	write_reg(par, 0x5D, (CURVE(1, 0) << 4) | CURVE(0, 0));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = 2,
+	.gamma_len = 14,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8347d", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8347d");
+MODULE_ALIAS("platform:hx8347d");
+
+MODULE_DESCRIPTION("FB driver for the HX8347D LCD Controller");
+MODULE_AUTHOR("Christian Vogelgsang");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8353d.c b/drivers/staging/fbtft/fb_hx8353d.c
new file mode 100644
index 0000000..c9512dc
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8353d.c
@@ -0,0 +1,166 @@
+/*
+ * FB driver for the HX8353D LCD Controller
+ *
+ * Copyright (c) 2014 Petr Olivka
+ * Copyright (c) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_hx8353d"
+#define DEFAULT_GAMMA "50 77 40 08 BF 00 03 0F 00 01 73 00 72 03 B0 0F 08 00 0F"
+
+static int init_display(struct fbtft_par *par)
+{
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+	mdelay(150);
+
+	/* SETEXTC */
+	write_reg(par, 0xB9, 0xFF, 0x83, 0x53);
+
+	/* RADJ */
+	write_reg(par, 0xB0, 0x3C, 0x01);
+
+	/* VCOM */
+	write_reg(par, 0xB6, 0x94, 0x6C, 0x50);
+
+	/* PWR */
+	write_reg(par, 0xB1, 0x00, 0x01, 0x1B, 0x03, 0x01, 0x08, 0x77, 0x89);
+
+	/* COLMOD */
+	write_reg(par, 0x3A, 0x05);
+
+	/* MEM ACCESS */
+	write_reg(par, 0x36, 0xC0);
+
+	/* SLPOUT - Sleep out & booster on */
+	write_reg(par, 0x11);
+	mdelay(150);
+
+	/* DISPON - Display On */
+	write_reg(par, 0x29);
+
+	/* RGBSET */
+	write_reg(par, 0x2D,
+		 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+		32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+		 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+		32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62);
+
+	return 0;
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* column address */
+	write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
+
+	/* row adress */
+	write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
+
+	/* memory write */
+	write_reg(par, 0x2c);
+}
+
+#define my (1 << 7)
+#define mx (1 << 6)
+#define mv (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* madctl - memory data access control
+	     rgb/bgr:
+	     1. mode selection pin srgb
+		rgb h/w pin for color filter setting: 0=rgb, 1=bgr
+	     2. madctl rgb bit
+		rgb-bgr order color filter panel: 0=rgb, 1=bgr */
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, mx | my | (par->bgr << 3));
+		break;
+	case 270:
+		write_reg(par, 0x36, my | mv | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, mx | mv | (par->bgr << 3));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  gamma string format:
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	write_reg(par, 0xE0,
+		curves[0], curves[1], curves[2], curves[3],
+		curves[4], curves[5], curves[6], curves[7],
+		curves[8], curves[9], curves[10], curves[11],
+		curves[12], curves[13], curves[14], curves[15],
+		curves[16], curves[17], curves[18]);
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = 128,
+	.height = 160,
+	.gamma_num = 1,
+	.gamma_len = 19,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8353d", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8353d");
+MODULE_ALIAS("platform:hx8353d");
+
+MODULE_DESCRIPTION("FB driver for the HX8353D LCD Controller");
+MODULE_AUTHOR("Petr Olivka");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c
new file mode 100644
index 0000000..b26d893
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9320.c
@@ -0,0 +1,234 @@
+/*
+ * FB driver for the ILI9320 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ili9320"
+#define WIDTH		240
+#define HEIGHT		320
+#define DEFAULT_GAMMA	"07 07 6 0 0 0 5 5 4 0\n" \
+			"07 08 4 7 5 1 2 0 7 7"
+
+
+static unsigned read_devicecode(struct fbtft_par *par)
+{
+	int ret;
+	u8 rxbuf[8] = {0, };
+
+	write_reg(par, 0x0000);
+	ret = par->fbtftops.read(par, rxbuf, 4);
+	return (rxbuf[2] << 8) | rxbuf[3];
+}
+
+static int init_display(struct fbtft_par *par)
+{
+	unsigned devcode;
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	devcode = read_devicecode(par);
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Device code: 0x%04X\n",
+		devcode);
+	if ((devcode != 0x0000) && (devcode != 0x9320))
+		dev_warn(par->info->device,
+			"Unrecognized Device code: 0x%04X (expected 0x9320)\n",
+			devcode);
+
+	/* Initialization sequence from ILI9320 Application Notes */
+
+	/* *********** Start Initial Sequence ********* */
+	write_reg(par, 0x00E5, 0x8000); /* Set the Vcore voltage and this setting is must. */
+	write_reg(par, 0x0000, 0x0001); /* Start internal OSC. */
+	write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */
+	write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */
+	write_reg(par, 0x0004, 0x0000); /* Resize register */
+	write_reg(par, 0x0008, 0x0202); /* set the back and front porch */
+	write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */
+	write_reg(par, 0x000A, 0x0000); /* FMARK function */
+	write_reg(par, 0x000C, 0x0000); /* RGB interface setting */
+	write_reg(par, 0x000D, 0x0000); /* Frame marker Position */
+	write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */
+
+	/* ***********Power On sequence *************** */
+	write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+	write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
+	write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */
+	write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
+	mdelay(200); /* Dis-charge capacitor power voltage */
+	write_reg(par, 0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+	write_reg(par, 0x0011, 0x0031); /* R11h=0x0031 at VCI=3.3V DC1[2:0], DC0[2:0], VC[2:0] */
+	mdelay(50);
+	write_reg(par, 0x0012, 0x0138); /* R12h=0x0138 at VCI=3.3V VREG1OUT voltage */
+	mdelay(50);
+	write_reg(par, 0x0013, 0x1800); /* R13h=0x1800 at VCI=3.3V VDV[4:0] for VCOM amplitude */
+	write_reg(par, 0x0029, 0x0008); /* R29h=0x0008 at VCI=3.3V VCM[4:0] for VCOMH */
+	mdelay(50);
+	write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */
+	write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */
+
+	/* ------------------ Set GRAM area --------------- */
+	write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */
+	write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */
+	write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */
+	write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */
+	write_reg(par, 0x0060, 0x2700); /* Gate Scan Line */
+	write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */
+	write_reg(par, 0x006A, 0x0000); /* set scrolling line */
+
+	/* -------------- Partial Display Control --------- */
+	write_reg(par, 0x0080, 0x0000);
+	write_reg(par, 0x0081, 0x0000);
+	write_reg(par, 0x0082, 0x0000);
+	write_reg(par, 0x0083, 0x0000);
+	write_reg(par, 0x0084, 0x0000);
+	write_reg(par, 0x0085, 0x0000);
+
+	/* -------------- Panel Control ------------------- */
+	write_reg(par, 0x0090, 0x0010);
+	write_reg(par, 0x0092, 0x0000);
+	write_reg(par, 0x0093, 0x0003);
+	write_reg(par, 0x0095, 0x0110);
+	write_reg(par, 0x0097, 0x0000);
+	write_reg(par, 0x0098, 0x0000);
+	write_reg(par, 0x0007, 0x0173); /* 262K color and display ON */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	switch (par->info->var.rotate) {
+	/* R20h = Horizontal GRAM Start Address */
+	/* R21h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0020, xs);
+		write_reg(par, 0x0021, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0020, WIDTH - 1 - xs);
+		write_reg(par, 0x0021, HEIGHT - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0020, WIDTH - 1 - ys);
+		write_reg(par, 0x0021, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0020, ys);
+		write_reg(par, 0x0021, HEIGHT - 1 - xs);
+		break;
+	}
+	write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x3, (par->bgr << 12) | 0x30);
+		break;
+	case 270:
+		write_reg(par, 0x3, (par->bgr << 12) | 0x28);
+		break;
+	case 180:
+		write_reg(par, 0x3, (par->bgr << 12) | 0x00);
+		break;
+	case 90:
+		write_reg(par, 0x3, (par->bgr << 12) | 0x18);
+		break;
+	}
+	return 0;
+}
+
+/*
+  Gamma string format:
+    VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5
+    VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111,
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111 };
+	int i, j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < 2; i++)
+		for (j = 0; j < 10; j++)
+			CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+	write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+	write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+	write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+	write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2));
+	write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0));
+
+	write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4));
+	write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6));
+	write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8));
+	write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2));
+	write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = 2,
+	.gamma_len = 10,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9320", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9320");
+MODULE_ALIAS("platform:ili9320");
+
+MODULE_DESCRIPTION("FB driver for the ILI9320 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c
new file mode 100644
index 0000000..5f88145
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9325.c
@@ -0,0 +1,291 @@
+/*
+ * FB driver for the ILI9325 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * Based on ili9325.c by Jeroen Domburg
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ili9325"
+#define WIDTH		240
+#define HEIGHT		320
+#define BPP		16
+#define FPS		20
+#define DEFAULT_GAMMA	"0F 00 7 2 0 0 6 5 4 1\n" \
+			"04 16 2 7 6 3 2 1 7 7"
+
+
+static unsigned bt = 6; /* VGL=Vci*4 , VGH=Vci*4 */
+module_param(bt, uint, 0);
+MODULE_PARM_DESC(bt, "Sets the factor used in the step-up circuits");
+
+static unsigned vc = 0b011; /* Vci1=Vci*0.80 */
+module_param(vc, uint, 0);
+MODULE_PARM_DESC(vc,
+"Sets the ratio factor of Vci to generate the reference voltages Vci1");
+
+static unsigned vrh = 0b1101; /* VREG1OUT=Vci*1.85 */
+module_param(vrh, uint, 0);
+MODULE_PARM_DESC(vrh,
+"Set the amplifying rate (1.6 ~ 1.9) of Vci applied to output the VREG1OUT");
+
+static unsigned vdv = 0b10010; /* VCOMH amplitude=VREG1OUT*0.98 */
+module_param(vdv, uint, 0);
+MODULE_PARM_DESC(vdv,
+"Select the factor of VREG1OUT to set the amplitude of Vcom");
+
+static unsigned vcm = 0b001010; /* VCOMH=VREG1OUT*0.735 */
+module_param(vcm, uint, 0);
+MODULE_PARM_DESC(vcm, "Set the internal VcomH voltage");
+
+
+/*
+Verify that this configuration is within the Voltage limits
+
+Display module configuration: Vcc = IOVcc = Vci = 3.3V
+
+ Voltages
+----------
+Vci                                =   3.3
+Vci1           =  Vci * 0.80       =   2.64
+DDVDH          =  Vci1 * 2         =   5.28
+VCL            = -Vci1             =  -2.64
+VREG1OUT       =  Vci * 1.85       =   4.88
+VCOMH          =  VREG1OUT * 0.735 =   3.59
+VCOM amplitude =  VREG1OUT * 0.98  =   4.79
+VGH            =  Vci * 4          =  13.2
+VGL            = -Vci * 4          = -13.2
+
+ Limits
+--------
+Power supplies
+1.65 < IOVcc < 3.30   =>  1.65 < 3.3 < 3.30
+2.40 < Vcc   < 3.30   =>  2.40 < 3.3 < 3.30
+2.50 < Vci   < 3.30   =>  2.50 < 3.3 < 3.30
+
+Source/VCOM power supply voltage
+ 4.50 < DDVDH < 6.0   =>  4.50 <  5.28 <  6.0
+-3.0  < VCL   < -2.0  =>  -3.0 < -2.64 < -2.0
+VCI - VCL < 6.0       =>  5.94 < 6.0
+
+Gate driver output voltage
+ 10  < VGH   < 20     =>   10 <  13.2  < 20
+-15  < VGL   < -5     =>  -15 < -13.2  < -5
+VGH - VGL < 32        =>   26.4 < 32
+
+VCOM driver output voltage
+VCOMH - VCOML < 6.0   =>  4.79 < 6.0
+*/
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	bt &= 0b111;
+	vc &= 0b111;
+	vrh &= 0b1111;
+	vdv &= 0b11111;
+	vcm &= 0b111111;
+
+	/* Initialization sequence from ILI9325 Application Notes */
+
+	/* ----------- Start Initial Sequence ----------- */
+	write_reg(par, 0x00E3, 0x3008); /* Set internal timing */
+	write_reg(par, 0x00E7, 0x0012); /* Set internal timing */
+	write_reg(par, 0x00EF, 0x1231); /* Set internal timing */
+	write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */
+	write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */
+	write_reg(par, 0x0004, 0x0000); /* Resize register */
+	write_reg(par, 0x0008, 0x0207); /* set the back porch and front porch */
+	write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */
+	write_reg(par, 0x000A, 0x0000); /* FMARK function */
+	write_reg(par, 0x000C, 0x0000); /* RGB interface setting */
+	write_reg(par, 0x000D, 0x0000); /* Frame marker Position */
+	write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */
+
+	/* ----------- Power On sequence ----------- */
+	write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+	write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
+	write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */
+	write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
+	mdelay(200); /* Dis-charge capacitor power voltage */
+	write_reg(par, 0x0010, /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+		(1 << 12) | (bt << 8) | (1 << 7) | (0b001 << 4));
+	write_reg(par, 0x0011, 0x220 | vc); /* DC1[2:0], DC0[2:0], VC[2:0] */
+	mdelay(50); /* Delay 50ms */
+	write_reg(par, 0x0012, vrh); /* Internal reference voltage= Vci; */
+	mdelay(50); /* Delay 50ms */
+	write_reg(par, 0x0013, vdv << 8); /* Set VDV[4:0] for VCOM amplitude */
+	write_reg(par, 0x0029, vcm); /* Set VCM[5:0] for VCOMH */
+	write_reg(par, 0x002B, 0x000C); /* Set Frame Rate */
+	mdelay(50); /* Delay 50ms */
+	write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */
+	write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */
+
+	/*------------------ Set GRAM area --------------- */
+	write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */
+	write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */
+	write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */
+	write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */
+	write_reg(par, 0x0060, 0xA700); /* Gate Scan Line */
+	write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */
+	write_reg(par, 0x006A, 0x0000); /* set scrolling line */
+
+	/*-------------- Partial Display Control --------- */
+	write_reg(par, 0x0080, 0x0000);
+	write_reg(par, 0x0081, 0x0000);
+	write_reg(par, 0x0082, 0x0000);
+	write_reg(par, 0x0083, 0x0000);
+	write_reg(par, 0x0084, 0x0000);
+	write_reg(par, 0x0085, 0x0000);
+
+	/*-------------- Panel Control ------------------- */
+	write_reg(par, 0x0090, 0x0010);
+	write_reg(par, 0x0092, 0x0600);
+	write_reg(par, 0x0007, 0x0133); /* 262K color and display ON */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	switch (par->info->var.rotate) {
+	/* R20h = Horizontal GRAM Start Address */
+	/* R21h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0020, xs);
+		write_reg(par, 0x0021, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0020, WIDTH - 1 - xs);
+		write_reg(par, 0x0021, HEIGHT - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0020, WIDTH - 1 - ys);
+		write_reg(par, 0x0021, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0020, ys);
+		write_reg(par, 0x0021, HEIGHT - 1 - xs);
+		break;
+	}
+	write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	/* AM: GRAM update direction */
+	case 0:
+		write_reg(par, 0x03, 0x0030 | (par->bgr << 12));
+		break;
+	case 180:
+		write_reg(par, 0x03, 0x0000 | (par->bgr << 12));
+		break;
+	case 270:
+		write_reg(par, 0x03, 0x0028 | (par->bgr << 12));
+		break;
+	case 90:
+		write_reg(par, 0x03, 0x0018 | (par->bgr << 12));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma string format:
+    VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5
+    VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111,
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111 };
+	int i, j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < 2; i++)
+		for (j = 0; j < 10; j++)
+			CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+	write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+	write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+	write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+	write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2));
+	write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0));
+
+	write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4));
+	write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6));
+	write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8));
+	write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2));
+	write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.bpp = BPP,
+	.fps = FPS,
+	.gamma_num = 2,
+	.gamma_len = 10,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9325", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9325");
+MODULE_ALIAS("platform:ili9325");
+
+MODULE_DESCRIPTION("FB driver for the ILI9325 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c
new file mode 100644
index 0000000..985687d
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9340.c
@@ -0,0 +1,163 @@
+/*
+ * FB driver for the ILI9340 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ili9340"
+#define WIDTH		240
+#define HEIGHT		320
+
+
+/* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	write_reg(par, 0xEF, 0x03, 0x80, 0x02);
+	write_reg(par, 0xCF, 0x00 , 0XC1 , 0X30);
+	write_reg(par, 0xED, 0x64 , 0x03 , 0X12 , 0X81);
+	write_reg(par, 0xE8, 0x85 , 0x00 , 0x78);
+	write_reg(par, 0xCB, 0x39 , 0x2C , 0x00 , 0x34 , 0x02);
+	write_reg(par, 0xF7, 0x20);
+	write_reg(par, 0xEA, 0x00 , 0x00);
+
+	/* Power Control 1 */
+	write_reg(par, 0xC0, 0x23);
+
+	/* Power Control 2 */
+	write_reg(par, 0xC1, 0x10);
+
+	/* VCOM Control 1 */
+	write_reg(par, 0xC5, 0x3e, 0x28);
+
+	/* VCOM Control 2 */
+	write_reg(par, 0xC7, 0x86);
+
+	/* COLMOD: Pixel Format Set */
+	/* 16 bits/pixel */
+	write_reg(par, 0x3A, 0x55);
+
+	/* Frame Rate Control */
+	/* Division ratio = fosc, Frame Rate = 79Hz */
+	write_reg(par, 0xB1, 0x00, 0x18);
+
+	/* Display Function Control */
+	write_reg(par, 0xB6, 0x08, 0x82, 0x27);
+
+	/* Gamma Function Disable */
+	write_reg(par, 0xF2, 0x00);
+
+	/* Gamma curve selected  */
+	write_reg(par, 0x26, 0x01);
+
+	/* Positive Gamma Correction */
+	write_reg(par, 0xE0,
+		0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1,
+		0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00);
+
+	/* Negative Gamma Correction */
+	write_reg(par, 0xE1,
+		0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1,
+		0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F);
+
+	/* Sleep OUT */
+	write_reg(par, 0x11);
+
+	mdelay(120);
+
+	/* Display ON */
+	write_reg(par, 0x29);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address */
+	write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	/* Row adress */
+	write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+#define ILI9340_MADCTL_MV  0x20
+#define ILI9340_MADCTL_MX  0x40
+#define ILI9340_MADCTL_MY  0x80
+static int set_var(struct fbtft_par *par)
+{
+	u8 val;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 270:
+		val = ILI9340_MADCTL_MV;
+		break;
+	case 180:
+		val = ILI9340_MADCTL_MY;
+		break;
+	case 90:
+		val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX;
+		break;
+	default:
+		val = ILI9340_MADCTL_MX;
+		break;
+	}
+	/* Memory Access Control  */
+	write_reg(par, 0x36, val | (par->bgr << 3));
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9340");
+MODULE_ALIAS("platform:ili9340");
+
+MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9341.c b/drivers/staging/fbtft/fb_ili9341.c
new file mode 100644
index 0000000..225b2d8
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9341.c
@@ -0,0 +1,179 @@
+/*
+ * FB driver for the ILI9341 LCD display controller
+ *
+ * This display uses 9-bit SPI: Data/Command bit + 8 data bits
+ * For platforms that doesn't support 9-bit, the driver is capable
+ * of emulating this using 8-bit transfer.
+ * This is done by transfering eight 9-bit words in 9 bytes.
+ *
+ * Copyright (C) 2013 Christian Vogelgsang
+ * Based on adafruit22fb.c by Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ili9341"
+#define WIDTH		240
+#define HEIGHT		320
+#define TXBUFLEN	(4 * PAGE_SIZE)
+#define DEFAULT_GAMMA	"1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \
+			"00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F"
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* startup sequence for MI0283QT-9A */
+	write_reg(par, 0x01); /* software reset */
+	mdelay(5);
+	write_reg(par, 0x28); /* display off */
+	/* --------------------------------------------------------- */
+	write_reg(par, 0xCF, 0x00, 0x83, 0x30);
+	write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81);
+	write_reg(par, 0xE8, 0x85, 0x01, 0x79);
+	write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02);
+	write_reg(par, 0xF7, 0x20);
+	write_reg(par, 0xEA, 0x00, 0x00);
+	/* ------------power control-------------------------------- */
+	write_reg(par, 0xC0, 0x26);
+	write_reg(par, 0xC1, 0x11);
+	/* ------------VCOM --------- */
+	write_reg(par, 0xC5, 0x35, 0x3E);
+	write_reg(par, 0xC7, 0xBE);
+	/* ------------memory access control------------------------ */
+	write_reg(par, 0x3A, 0x55); /* 16bit pixel */
+	/* ------------frame rate----------------------------------- */
+	write_reg(par, 0xB1, 0x00, 0x1B);
+	/* ------------Gamma---------------------------------------- */
+	/* write_reg(par, 0xF2, 0x08); */ /* Gamma Function Disable */
+	write_reg(par, 0x26, 0x01);
+	/* ------------display-------------------------------------- */
+	write_reg(par, 0xB7, 0x07); /* entry mode set */
+	write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00);
+	write_reg(par, 0x11); /* sleep out */
+	mdelay(100);
+	write_reg(par, 0x29); /* display on */
+	mdelay(20);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address set */
+	write_reg(par, 0x2A,
+		(xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
+
+	/* Row adress set */
+	write_reg(par, 0x2B,
+		(ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+#define MEM_Y   (7) /* MY row address order */
+#define MEM_X   (6) /* MX column address order */
+#define MEM_V   (5) /* MV row / column exchange */
+#define MEM_L   (4) /* ML vertical refresh order */
+#define MEM_H   (2) /* MH horizontal refresh order */
+#define MEM_BGR (3) /* RGB-BGR Order */
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, (1 << MEM_X) | (par->bgr << MEM_BGR));
+		break;
+	case 270:
+		write_reg(par, 0x36,
+			(1<<MEM_V) | (1 << MEM_L) | (par->bgr << MEM_BGR));
+		break;
+	case 180:
+		write_reg(par, 0x36, (1 << MEM_Y) | (par->bgr << MEM_BGR));
+		break;
+	case 90:
+		write_reg(par, 0x36, (1 << MEM_Y) | (1 << MEM_X) |
+				     (1 << MEM_V) | (par->bgr << MEM_BGR));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma string format:
+    Positive: Par1 Par2 [...] Par15
+    Negative: Par1 Par2 [...] Par15
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	int i;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	for (i = 0; i < par->gamma.num_curves; i++)
+		write_reg(par, 0xE0 + i,
+			CURVE(i, 0), CURVE(i, 1), CURVE(i, 2),
+			CURVE(i, 3), CURVE(i, 4), CURVE(i, 5),
+			CURVE(i, 6), CURVE(i, 7), CURVE(i, 8),
+			CURVE(i, 9), CURVE(i, 10), CURVE(i, 11),
+			CURVE(i, 12), CURVE(i, 13), CURVE(i, 14));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.txbuflen = TXBUFLEN,
+	.gamma_num = 2,
+	.gamma_len = 15,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9341");
+MODULE_ALIAS("platform:ili9341");
+
+MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller");
+MODULE_AUTHOR("Christian Vogelgsang");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9481.c b/drivers/staging/fbtft/fb_ili9481.c
new file mode 100644
index 0000000..725157a
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9481.c
@@ -0,0 +1,117 @@
+/*
+ * FB driver for the ILI9481 LCD Controller
+ *
+ * Copyright (c) 2014 Petr Olivka
+ * Copyright (c) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME	"fb_ili9481"
+#define WIDTH		320
+#define HEIGHT		480
+
+static int default_init_sequence[] = {
+
+	/* SLP_OUT - Sleep out */
+	-1, 0x11,
+	-2, 50,
+	/* Power setting */
+	-1, 0xD0, 0x07, 0x42, 0x18,
+	/* VCOM */
+	-1, 0xD1, 0x00, 0x07, 0x10,
+	/* Power setting for norm. mode */
+	-1, 0xD2, 0x01, 0x02,
+	/* Panel driving setting */
+	-1, 0xC0, 0x10, 0x3B, 0x00, 0x02, 0x11,
+	/* Frame rate & inv. */
+	-1, 0xC5, 0x03,
+	/* Pixel format */
+	-1, 0x3A, 0x55,
+	/* Gamma */
+	-1, 0xC8, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16,
+		  0x37, 0x75, 0x77, 0x54, 0x0C, 0x00,
+	/* DISP_ON */
+	-1, 0x29,
+	-3
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* column address */
+	write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
+
+	/* row adress */
+	write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
+
+	/* memory write */
+	write_reg(par, 0x2c);
+}
+
+#define HFLIP 0x01
+#define VFLIP 0x02
+#define ROWxCOL 0x20
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 270:
+		write_reg(par, 0x36, ROWxCOL | HFLIP | VFLIP | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, VFLIP | (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, ROWxCOL | (par->bgr << 3));
+		break;
+	default:
+		write_reg(par, 0x36, HFLIP | (par->bgr << 3));
+		break;
+	}
+
+	return 0;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.init_sequence = default_init_sequence,
+	.fbtftops = {
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9481", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9481");
+MODULE_ALIAS("platform:ili9481");
+
+MODULE_DESCRIPTION("FB driver for the ILI9481 LCD Controller");
+MODULE_AUTHOR("Petr Olivka");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9486.c b/drivers/staging/fbtft/fb_ili9486.c
new file mode 100644
index 0000000..95b8999
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9486.c
@@ -0,0 +1,121 @@
+/*
+ * FB driver for the ILI9486 LCD Controller
+ *
+ * Copyright (C) 2014 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ili9486"
+#define WIDTH		320
+#define HEIGHT		480
+
+
+/* this init sequence matches PiScreen */
+static int default_init_sequence[] = {
+	/* Interface Mode Control */
+	-1, 0xb0, 0x0,
+	/* Sleep OUT */
+	-1, 0x11,
+	-2, 250,
+	/* Interface Pixel Format */
+	-1, 0x3A, 0x55,
+	/* Power Control 3 */
+	-1, 0xC2, 0x44,
+	/* VCOM Control 1 */
+	-1, 0xC5, 0x00, 0x00, 0x00, 0x00,
+	/* PGAMCTRL(Positive Gamma Control) */
+	-1, 0xE0, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98,
+	          0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00,
+	/* NGAMCTRL(Negative Gamma Control) */
+	-1, 0xE1, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+	          0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00,
+	/* Digital Gamma Control 1 */
+	-1, 0xE2, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+	          0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00,
+	/* Sleep OUT */
+	-1, 0x11,
+	/* Display ON */
+	-1, 0x29,
+	/* end marker */
+	-3
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address */
+	write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	/* Row adress */
+	write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, 0x80 | (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, 0x20 | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, 0x40 | (par->bgr << 3));
+		break;
+	case 270:
+		write_reg(par, 0x36, 0xE0 | (par->bgr << 3));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.init_sequence = default_init_sequence,
+	.fbtftops = {
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9486", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9486");
+MODULE_ALIAS("platform:ili9486");
+
+MODULE_DESCRIPTION("FB driver for the ILI9486 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c
new file mode 100644
index 0000000..8b9ebfb
--- /dev/null
+++ b/drivers/staging/fbtft/fb_pcd8544.c
@@ -0,0 +1,177 @@
+/*
+ * FB driver for the PCD8544 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME	       "fb_pcd8544"
+#define WIDTH          84
+#define HEIGHT         48
+#define TXBUFLEN       (84*6)
+#define DEFAULT_GAMMA  "40" /* gamma is used to control contrast in this driver */
+
+static unsigned tc;
+module_param(tc, uint, 0);
+MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)");
+
+static unsigned bs = 4;
+module_param(bs, uint, 0);
+MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* Function set */
+	write_reg(par, 0x21); /* 5:1  1
+	                         2:0  PD - Powerdown control: chip is active
+							 1:0  V  - Entry mode: horizontal addressing
+							 0:1  H  - Extended instruction set control: extended
+						  */
+
+	/* H=1 Temperature control */
+	write_reg(par, 0x04 | (tc & 0x3)); /*
+	                         2:1  1
+	                         1:x  TC1 - Temperature Coefficient: 0x10
+							 0:x  TC0
+						  */
+
+	/* H=1 Bias system */
+	write_reg(par, 0x10 | (bs & 0x7)); /*
+	                         4:1  1
+	                         3:0  0
+							 2:x  BS2 - Bias System
+							 1:x  BS1
+							 0:x  BS0
+	                      */
+
+	/* Function set */
+	write_reg(par, 0x22); /* 5:1  1
+	                         2:0  PD - Powerdown control: chip is active
+							 1:1  V  - Entry mode: vertical addressing
+							 0:0  H  - Extended instruction set control: basic
+						  */
+
+	/* H=0 Display control */
+	write_reg(par, 0x08 | 4); /*
+	                         3:1  1
+	                         2:1  D  - DE: 10=normal mode
+							 1:0  0
+							 0:0  E
+						  */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* H=0 Set X address of RAM */
+	write_reg(par, 0x80); /* 7:1  1
+	                         6-0: X[6:0] - 0x00
+	                      */
+
+	/* H=0 Set Y address of RAM */
+	write_reg(par, 0x40); /* 7:0  0
+	                         6:1  1
+	                         2-0: Y[2:0] - 0x0
+	                      */
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16 = (u16 *)par->info->screen_base;
+	u8 *buf = par->txbuf.buf;
+	int x, y, i;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	for (x = 0; x < 84; x++) {
+		for (y = 0; y < 6; y++) {
+			*buf = 0x00;
+			for (i = 0; i < 8; i++) {
+				*buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i;
+			}
+			buf++;
+		}
+	}
+
+	/* Write data */
+	gpio_set_value(par->gpio.dc, 1);
+	ret = par->fbtftops.write(par, par->txbuf.buf, 6*84);
+	if (ret < 0)
+		dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret);
+
+	return ret;
+}
+
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	curves[0] &= 0x7F;
+
+	write_reg(par, 0x23); /* turn on extended instruction set */
+	write_reg(par, 0x80 | curves[0]);
+	write_reg(par, 0x22); /* turn off extended instruction set */
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.txbuflen = TXBUFLEN,
+	.gamma_num = 1,
+	.gamma_len = 1,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.write_vmem = write_vmem,
+		.set_gamma = set_gamma,
+	},
+	.backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:pdc8544");
+
+MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
new file mode 100644
index 0000000..c323c06
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -0,0 +1,331 @@
+/******************************************************************************
+
+  ProjectName: FBTFT driver                       ***** *****
+	       for the RA8875 LCD Controller     *     *      ************
+						*   **   **   *           *
+  Copyright © by Pf@nne & NOTRO                *   *   *   *   *   ****	   *
+						*   *       *   *   *   *   *
+  Last modification by:                        *   *       *   *   ****    *
+  - Pf@nne (pf@nne-mail.de)                     *   *     *****           *
+						 *   *        *   *******
+						  *****      *   *
+  Date    : 10.06.2014                                      *   *
+  Version : V1.13                                          *****
+  Revison : 5
+
+*******************************************************************************
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+#include "fbtft.h"
+
+#define DRVNAME "fb_ra8875"
+
+static int write_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+	struct spi_transfer t = {
+		.tx_buf = buf,
+		.len = len,
+		.speed_hz = 1000000,
+	};
+	struct spi_message m;
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	if (!par->spi) {
+		dev_err(par->info->device,
+			"%s: par->spi is unexpectedly NULL\n", __func__);
+		return -1;
+	}
+
+	spi_message_init(&m);
+	if (par->txbuf.dma && buf == par->txbuf.buf) {
+		t.tx_dma = par->txbuf.dma;
+		m.is_dma_mapped = 1;
+	}
+	spi_message_add_tail(&t, &m);
+	return spi_sync(par->spi, &m);
+}
+
+static int init_display(struct fbtft_par *par)
+{
+	gpio_set_value(par->gpio.dc, 1);
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+		"%s()\n", __func__);
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+		"display size %dx%d\n", par->info->var.xres, par->info->var.yres);
+
+	par->fbtftops.reset(par);
+
+	if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) {
+		/* PLL clock frequency */
+		write_reg(par, 0x88 , 0x0A);
+		write_reg(par, 0x89 , 0x02);
+		mdelay(10);
+		/* color deep / MCU Interface */
+		write_reg(par, 0x10 , 0x0C);
+		/* pixel clock period  */
+		write_reg(par, 0x04 , 0x03);
+		mdelay(1);
+		/* horizontal settings */
+		write_reg(par, 0x14 , 0x27);
+		write_reg(par, 0x15 , 0x00);
+		write_reg(par, 0x16 , 0x05);
+		write_reg(par, 0x17 , 0x04);
+		write_reg(par, 0x18 , 0x03);
+		/* vertical settings */
+		write_reg(par, 0x19 , 0xEF);
+		write_reg(par, 0x1A , 0x00);
+		write_reg(par, 0x1B , 0x05);
+		write_reg(par, 0x1C , 0x00);
+		write_reg(par, 0x1D , 0x0E);
+		write_reg(par, 0x1E , 0x00);
+		write_reg(par, 0x1F , 0x02);
+	} else if ((par->info->var.xres == 480) && (par->info->var.yres == 272)) {
+		/* PLL clock frequency  */
+		write_reg(par, 0x88 , 0x0A);
+		write_reg(par, 0x89 , 0x02);
+		mdelay(10);
+		/* color deep / MCU Interface */
+		write_reg(par, 0x10 , 0x0C);
+		/* pixel clock period  */
+		write_reg(par, 0x04 , 0x82);
+		mdelay(1);
+		/* horizontal settings */
+		write_reg(par, 0x14 , 0x3B);
+		write_reg(par, 0x15 , 0x00);
+		write_reg(par, 0x16 , 0x01);
+		write_reg(par, 0x17 , 0x00);
+		write_reg(par, 0x18 , 0x05);
+		/* vertical settings */
+		write_reg(par, 0x19 , 0x0F);
+		write_reg(par, 0x1A , 0x01);
+		write_reg(par, 0x1B , 0x02);
+		write_reg(par, 0x1C , 0x00);
+		write_reg(par, 0x1D , 0x07);
+		write_reg(par, 0x1E , 0x00);
+		write_reg(par, 0x1F , 0x09);
+	} else if ((par->info->var.xres == 640) && (par->info->var.yres == 480)) {
+		/* PLL clock frequency */
+		write_reg(par, 0x88 , 0x0B);
+		write_reg(par, 0x89 , 0x02);
+		mdelay(10);
+		/* color deep / MCU Interface */
+		write_reg(par, 0x10 , 0x0C);
+		/* pixel clock period */
+		write_reg(par, 0x04 , 0x01);
+		mdelay(1);
+		/* horizontal settings */
+		write_reg(par, 0x14 , 0x4F);
+		write_reg(par, 0x15 , 0x05);
+		write_reg(par, 0x16 , 0x0F);
+		write_reg(par, 0x17 , 0x01);
+		write_reg(par, 0x18 , 0x00);
+		/* vertical settings */
+		write_reg(par, 0x19 , 0xDF);
+		write_reg(par, 0x1A , 0x01);
+		write_reg(par, 0x1B , 0x0A);
+		write_reg(par, 0x1C , 0x00);
+		write_reg(par, 0x1D , 0x0E);
+		write_reg(par, 0x1E , 0x00);
+		write_reg(par, 0x1F , 0x01);
+	} else if ((par->info->var.xres == 800) && (par->info->var.yres == 480)) {
+		/* PLL clock frequency */
+		write_reg(par, 0x88 , 0x0B);
+		write_reg(par, 0x89 , 0x02);
+		mdelay(10);
+		/* color deep / MCU Interface */
+		write_reg(par, 0x10 , 0x0C);
+		/* pixel clock period */
+		write_reg(par, 0x04 , 0x81);
+		mdelay(1);
+		/* horizontal settings */
+		write_reg(par, 0x14 , 0x63);
+		write_reg(par, 0x15 , 0x03);
+		write_reg(par, 0x16 , 0x03);
+		write_reg(par, 0x17 , 0x02);
+		write_reg(par, 0x18 , 0x00);
+		/* vertical settings */
+		write_reg(par, 0x19 , 0xDF);
+		write_reg(par, 0x1A , 0x01);
+		write_reg(par, 0x1B , 0x14);
+		write_reg(par, 0x1C , 0x00);
+		write_reg(par, 0x1D , 0x06);
+		write_reg(par, 0x1E , 0x00);
+		write_reg(par, 0x1F , 0x01);
+	} else {
+		dev_err(par->info->device, "display size is not supported!!");
+		return -1;
+	}
+
+	/* PWM clock */
+	write_reg(par, 0x8a , 0x81);
+	write_reg(par, 0x8b , 0xFF);
+	mdelay(10);
+
+	/* Display ON */
+	write_reg(par, 0x01 , 0x80);
+	mdelay(10);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Set_Active_Window */
+	write_reg(par, 0x30 , xs & 0x00FF);
+	write_reg(par, 0x31 , (xs & 0xFF00) >> 8);
+	write_reg(par, 0x32 , ys & 0x00FF);
+	write_reg(par, 0x33 , (ys & 0xFF00) >> 8);
+	write_reg(par, 0x34 , (xs+xe) & 0x00FF);
+	write_reg(par, 0x35 , ((xs+xe) & 0xFF00) >> 8);
+	write_reg(par, 0x36 , (ys+ye) & 0x00FF);
+	write_reg(par, 0x37 , ((ys+ye) & 0xFF00) >> 8);
+
+	/* Set_Memory_Write_Cursor */
+	write_reg(par, 0x46,  xs & 0xff);
+	write_reg(par, 0x47, (xs >> 8) & 0x03);
+	write_reg(par, 0x48,  ys & 0xff);
+	write_reg(par, 0x49, (ys >> 8) & 0x01);
+
+	write_reg(par, 0x02);
+}
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+	va_list args;
+	int i, ret;
+	u8 *buf = (u8 *)par->buf;
+
+	/* slow down spi-speed for writing registers */
+	par->fbtftops.write = write_spi;
+
+	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+		va_start(args, len);
+		for (i = 0; i < len; i++)
+			buf[i] = (u8)va_arg(args, unsigned int);
+		va_end(args);
+		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
+			u8, buf, len, "%s: ", __func__);
+	}
+
+	va_start(args, len);
+	*buf++ = 0x80;
+	*buf = (u8)va_arg(args, unsigned int);
+	ret = par->fbtftops.write(par, par->buf, 2);
+	if (ret < 0) {
+		va_end(args);
+		dev_err(par->info->device, "%s: write() failed and returned %dn",
+			__func__, ret);
+		return;
+	}
+	len--;
+
+	udelay(100);
+
+	if (len) {
+		buf = (u8 *)par->buf;
+		*buf++ = 0x00;
+		i = len;
+		while (i--)
+			*buf++ = (u8)va_arg(args, unsigned int);
+
+		ret = par->fbtftops.write(par, par->buf, len + 1);
+		if (ret < 0) {
+			va_end(args);
+			dev_err(par->info->device, "%s: write() failed and returned %dn",
+				__func__, ret);
+			return;
+		}
+	}
+	va_end(args);
+
+	/* restore user spi-speed */
+	par->fbtftops.write = fbtft_write_spi;
+	udelay(100);
+}
+
+static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16;
+	u16 *txbuf16 = (u16 *)par->txbuf.buf;
+	size_t remain;
+	size_t to_copy;
+	size_t tx_array_size;
+	int i;
+	int ret = 0;
+	size_t startbyte_size = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+		__func__, offset, len);
+
+	remain = len / 2;
+	vmem16 = (u16 *)(par->info->screen_base + offset);
+	tx_array_size = par->txbuf.len / 2;
+		txbuf16 = (u16 *)(par->txbuf.buf + 1);
+		tx_array_size -= 2;
+		*(u8 *)(par->txbuf.buf) = 0x00;
+		startbyte_size = 1;
+
+	while (remain) {
+		to_copy = remain > tx_array_size ? tx_array_size : remain;
+		dev_dbg(par->info->device, "    to_copy=%zu, remain=%zu\n",
+			to_copy, remain - to_copy);
+
+		for (i = 0; i < to_copy; i++)
+			txbuf16[i] = cpu_to_be16(vmem16[i]);
+
+		vmem16 = vmem16 + to_copy;
+		ret = par->fbtftops.write(par, par->txbuf.buf,
+			startbyte_size + to_copy * 2);
+		if (ret < 0)
+			return ret;
+		remain -= to_copy;
+	}
+
+	return ret;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.write_register = write_reg8_bus8,
+		.write_vmem = write_vmem16_bus8,
+		.write = write_spi,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ra8875");
+MODULE_ALIAS("platform:ra8875");
+
+MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller");
+MODULE_AUTHOR("Pf@nne");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_s6d02a1.c b/drivers/staging/fbtft/fb_s6d02a1.c
new file mode 100644
index 0000000..e412a42
--- /dev/null
+++ b/drivers/staging/fbtft/fb_s6d02a1.c
@@ -0,0 +1,168 @@
+/*
+ * FB driver for the S6D02A1 LCD Controller
+ *
+ * Based on fb_st7735r.c by Noralf Tronnes
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_s6d02a1"
+
+static int default_init_sequence[] = {
+
+	-1, 0xf0, 0x5a, 0x5a,
+
+	-1, 0xfc, 0x5a, 0x5a,
+
+	-1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01,
+
+	-1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02,
+
+	/* power setting sequence */
+	-1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f,
+
+	-1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+
+	-1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06,
+
+	-1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00,
+
+	-1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08,
+
+	-1, 0xf8, 0x11,
+
+	-1, 0xf7, 0xc8, 0x20, 0x00, 0x00,
+
+	-1, 0xf3, 0x00, 0x00,
+
+	-1, 0x11,
+	-2, 50,
+
+	-1, 0xf3, 0x00, 0x01,
+	-2, 50,
+	-1, 0xf3, 0x00, 0x03,
+	-2, 50,
+	-1, 0xf3, 0x00, 0x07,
+	-2, 50,
+	-1, 0xf3, 0x00, 0x0f,
+	-2, 50,
+
+	-1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+	-2, 50,
+
+	-1, 0xf3, 0x00, 0x1f,
+	-2, 50,
+	-1, 0xf3, 0x00, 0x7f,
+	-2, 50,
+
+	-1, 0xf3, 0x00, 0xff,
+	-2, 50,
+
+	-1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16,
+
+	-1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+
+	/* initializing sequence */
+
+	-1, 0x36, 0x08,
+
+	-1, 0x35, 0x00,
+
+	-1, 0x3a, 0x05,
+
+	/* gamma setting sequence */
+	-1, 0x26, 0x01,	/* preset gamma curves, possible values 0x01, 0x02, 0x04, 0x08 */
+
+	-2, 150,
+	-1, 0x29,
+	-1, 0x2c,
+	/* end marker */
+	-3
+
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address */
+	write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	/* Row adress */
+	write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* MADCTL - Memory data access control
+	     RGB/BGR:
+		1. Mode selection pin SRGB
+			RGB H/W pin for color filter setting: 0=RGB, 1=BGR
+		2. MADCTL RGB bit
+			RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+		break;
+	case 270:
+		write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+		break;
+	}
+
+	return 0;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = 128,
+	.height = 160,
+	.init_sequence = default_init_sequence,
+	.fbtftops = {
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:s6d02a1");
+MODULE_ALIAS("platform:s6d02a1");
+
+MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller");
+MODULE_AUTHOR("WOLFGANG BUENING");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c
new file mode 100644
index 0000000..1ef8c1a
--- /dev/null
+++ b/drivers/staging/fbtft/fb_s6d1121.c
@@ -0,0 +1,208 @@
+/*
+ * FB driver for the S6D1121 LCD Controller
+ *
+ * Copyright (C) 2013 Roman Rolinsky
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_s6d1121"
+#define WIDTH		240
+#define HEIGHT		320
+#define BPP		16
+#define FPS		20
+#define DEFAULT_GAMMA	"26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \
+			"1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D"
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	/* Initialization sequence from Lib_UTFT */
+
+	write_reg(par, 0x0011, 0x2004);
+	write_reg(par, 0x0013, 0xCC00);
+	write_reg(par, 0x0015, 0x2600);
+	write_reg(par, 0x0014, 0x252A);
+	write_reg(par, 0x0012, 0x0033);
+	write_reg(par, 0x0013, 0xCC04);
+	write_reg(par, 0x0013, 0xCC06);
+	write_reg(par, 0x0013, 0xCC4F);
+	write_reg(par, 0x0013, 0x674F);
+	write_reg(par, 0x0011, 0x2003);
+	write_reg(par, 0x0016, 0x0007);
+	write_reg(par, 0x0002, 0x0013);
+	write_reg(par, 0x0003, 0x0003);
+	write_reg(par, 0x0001, 0x0127);
+	write_reg(par, 0x0008, 0x0303);
+	write_reg(par, 0x000A, 0x000B);
+	write_reg(par, 0x000B, 0x0003);
+	write_reg(par, 0x000C, 0x0000);
+	write_reg(par, 0x0041, 0x0000);
+	write_reg(par, 0x0050, 0x0000);
+	write_reg(par, 0x0060, 0x0005);
+	write_reg(par, 0x0070, 0x000B);
+	write_reg(par, 0x0071, 0x0000);
+	write_reg(par, 0x0078, 0x0000);
+	write_reg(par, 0x007A, 0x0000);
+	write_reg(par, 0x0079, 0x0007);
+	write_reg(par, 0x0007, 0x0051);
+	write_reg(par, 0x0007, 0x0053);
+	write_reg(par, 0x0079, 0x0000);
+
+	write_reg(par, 0x0022); /* Write Data to GRAM */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	switch (par->info->var.rotate) {
+	/* R20h = Horizontal GRAM Start Address */
+	/* R21h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0020, xs);
+		write_reg(par, 0x0021, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0020, WIDTH - 1 - xs);
+		write_reg(par, 0x0021, HEIGHT - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0020, WIDTH - 1 - ys);
+		write_reg(par, 0x0021, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0020, ys);
+		write_reg(par, 0x0021, HEIGHT - 1 - xs);
+		break;
+	}
+	write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	/* AM: GRAM update direction */
+	case 0:
+		write_reg(par, 0x03, 0x0003 | (par->bgr << 12));
+		break;
+	case 180:
+		write_reg(par, 0x03, 0x0000 | (par->bgr << 12));
+		break;
+	case 270:
+		write_reg(par, 0x03, 0x000A | (par->bgr << 12));
+		break;
+	case 90:
+		write_reg(par, 0x03, 0x0009 | (par->bgr << 12));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma string format:
+    PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1
+    PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 
+		0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+		0b11111, 0b11111,
+		0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+		0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+		0b11111, 0b11111 };
+	int i, j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < 2; i++)
+		for (j = 0; j < 14; j++)
+			CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+	write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0));
+	write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2));
+	write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3));
+	write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6));
+	write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8));
+	write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10));
+
+	write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0));
+	write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2));
+	write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4));
+	write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6));
+	write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8));
+	write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10));
+
+	write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12));
+	write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.bpp = BPP,
+	.fps = FPS,
+	.gamma_num = 2,
+	.gamma_len = 14,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:s6d1121");
+MODULE_ALIAS("platform:s6d1121");
+
+MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller");
+MODULE_AUTHOR("Roman Rolinsky");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c
new file mode 100644
index 0000000..ef46fbc
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1289.c
@@ -0,0 +1,206 @@
+/*
+ * FB driver for the SSD1289 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * Init sequence taken from ITDB02_Graph16.cpp - (C)2010-2011 Henning Karlsen
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ssd1289"
+#define WIDTH		240
+#define HEIGHT		320
+#define DEFAULT_GAMMA	"02 03 2 5 7 7 4 2 4 2\n" \
+			"02 03 2 5 7 5 4 2 4 2"
+
+static unsigned reg11 = 0x6040;
+module_param(reg11, uint, 0);
+MODULE_PARM_DESC(reg11, "Register 11h value");
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	write_reg(par, 0x00, 0x0001);
+	write_reg(par, 0x03, 0xA8A4);
+	write_reg(par, 0x0C, 0x0000);
+	write_reg(par, 0x0D, 0x080C);
+	write_reg(par, 0x0E, 0x2B00);
+	write_reg(par, 0x1E, 0x00B7);
+	write_reg(par, 0x01,
+		(1 << 13) | (par->bgr << 11) | (1 << 9) | (HEIGHT - 1));
+	write_reg(par, 0x02, 0x0600);
+	write_reg(par, 0x10, 0x0000);
+	write_reg(par, 0x05, 0x0000);
+	write_reg(par, 0x06, 0x0000);
+	write_reg(par, 0x16, 0xEF1C);
+	write_reg(par, 0x17, 0x0003);
+	write_reg(par, 0x07, 0x0233);
+	write_reg(par, 0x0B, 0x0000);
+	write_reg(par, 0x0F, 0x0000);
+	write_reg(par, 0x41, 0x0000);
+	write_reg(par, 0x42, 0x0000);
+	write_reg(par, 0x48, 0x0000);
+	write_reg(par, 0x49, 0x013F);
+	write_reg(par, 0x4A, 0x0000);
+	write_reg(par, 0x4B, 0x0000);
+	write_reg(par, 0x44, 0xEF00);
+	write_reg(par, 0x45, 0x0000);
+	write_reg(par, 0x46, 0x013F);
+	write_reg(par, 0x23, 0x0000);
+	write_reg(par, 0x24, 0x0000);
+	write_reg(par, 0x25, 0x8000);
+	write_reg(par, 0x4f, 0x0000);
+	write_reg(par, 0x4e, 0x0000);
+	write_reg(par, 0x22);
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	switch (par->info->var.rotate) {
+	/* R4Eh - Set GDDRAM X address counter */
+	/* R4Fh - Set GDDRAM Y address counter */
+	case 0:
+		write_reg(par, 0x4e, xs);
+		write_reg(par, 0x4f, ys);
+		break;
+	case 180:
+		write_reg(par, 0x4e, par->info->var.xres - 1 - xs);
+		write_reg(par, 0x4f, par->info->var.yres - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x4e, par->info->var.yres - 1 - ys);
+		write_reg(par, 0x4f, xs);
+		break;
+	case 90:
+		write_reg(par, 0x4e, ys);
+		write_reg(par, 0x4f, par->info->var.xres - 1 - xs);
+		break;
+	}
+
+	/* R22h - RAM data write */
+	write_reg(par, 0x22);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	if (par->fbtftops.init_display != init_display) {
+		/* don't risk messing up register 11h */
+		fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+			"%s: skipping since custom init_display() is used\n",
+			__func__);
+		return 0;
+	}
+
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x11, reg11 | 0b110000);
+		break;
+	case 270:
+		write_reg(par, 0x11, reg11 | 0b101000);
+		break;
+	case 180:
+		write_reg(par, 0x11, reg11 | 0b000000);
+		break;
+	case 90:
+		write_reg(par, 0x11, reg11 | 0b011000);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma string format:
+    VRP0 VRP1 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 PKP5
+    VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long mask[] = {
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111,
+		0b11111, 0b11111, 0b111, 0b111, 0b111,
+		0b111, 0b111, 0b111, 0b111, 0b111 };
+	int i, j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < 2; i++)
+		for (j = 0; j < 10; j++)
+			CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+	write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+	write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+	write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+	write_reg(par, 0x0033, CURVE(0, 3) << 8 | CURVE(0, 2));
+	write_reg(par, 0x0034, CURVE(1, 5) << 8 | CURVE(1, 4));
+	write_reg(par, 0x0035, CURVE(1, 7) << 8 | CURVE(1, 6));
+	write_reg(par, 0x0036, CURVE(1, 9) << 8 | CURVE(1, 8));
+	write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2));
+	write_reg(par, 0x003A, CURVE(0, 1) << 8 | CURVE(0, 0));
+	write_reg(par, 0x003B, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = 2,
+	.gamma_len = 10,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1289", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1289");
+MODULE_ALIAS("platform:ssd1289");
+
+MODULE_DESCRIPTION("FB driver for the SSD1289 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1306.c b/drivers/staging/fbtft/fb_ssd1306.c
new file mode 100644
index 0000000..5ea195b
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1306.c
@@ -0,0 +1,229 @@
+/*
+ * FB driver for the SSD1306 OLED Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ssd1306"
+#define WIDTH		128
+#define HEIGHT		64
+
+
+/*
+  write_reg() caveat:
+
+     This doesn't work because D/C has to be LOW for both values:
+       write_reg(par, val1, val2);
+
+     Do it like this:
+       write_reg(par, val1);
+       write_reg(par, val2);
+*/
+
+/* Init sequence taken from the Adafruit SSD1306 Arduino library */
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	if (par->gamma.curves[0] == 0) {
+		mutex_lock(&par->gamma.lock);
+		if (par->info->var.yres == 64)
+			par->gamma.curves[0] = 0xCF;
+		else
+			par->gamma.curves[0] = 0x8F;
+		mutex_unlock(&par->gamma.lock);
+	}
+
+	/* Set Display OFF */
+	write_reg(par, 0xAE);
+
+	/* Set Display Clock Divide Ratio/ Oscillator Frequency */
+	write_reg(par, 0xD5);
+	write_reg(par, 0x80);
+
+	/* Set Multiplex Ratio */
+	write_reg(par, 0xA8);
+	if (par->info->var.yres == 64)
+		write_reg(par, 0x3F);
+	else
+		write_reg(par, 0x1F);
+
+	/* Set Display Offset */
+	write_reg(par, 0xD3);
+	write_reg(par, 0x0);
+
+	/* Set Display Start Line */
+	write_reg(par, 0x40 | 0x0);
+
+	/* Charge Pump Setting */
+	write_reg(par, 0x8D);
+	/* A[2] = 1b, Enable charge pump during display on */
+	write_reg(par, 0x14);
+
+	/* Set Memory Addressing Mode */
+	write_reg(par, 0x20);
+	/* Vertical addressing mode  */
+	write_reg(par, 0x01);
+
+	/*Set Segment Re-map */
+	/* column address 127 is mapped to SEG0 */
+	write_reg(par, 0xA0 | 0x1);
+
+	/* Set COM Output Scan Direction */
+	/* remapped mode. Scan from COM[N-1] to COM0 */
+	write_reg(par, 0xC8);
+
+	/* Set COM Pins Hardware Configuration */
+	write_reg(par, 0xDA);
+	if (par->info->var.yres == 64)
+		/* A[4]=1b, Alternative COM pin configuration */
+		write_reg(par, 0x12);
+	else
+		/* A[4]=0b, Sequential COM pin configuration */
+		write_reg(par, 0x02);
+
+	/* Set Pre-charge Period */
+	write_reg(par, 0xD9);
+	write_reg(par, 0xF1);
+
+	/* Set VCOMH Deselect Level */
+	write_reg(par, 0xDB);
+	/* according to the datasheet, this value is out of bounds */
+	write_reg(par, 0x40);
+
+	/* Entire Display ON */
+	/* Resume to RAM content display. Output follows RAM content */
+	write_reg(par, 0xA4);
+
+	/* Set Normal Display
+	   0 in RAM: OFF in display panel
+	   1 in RAM: ON in display panel */
+	write_reg(par, 0xA6);
+
+	/* Set Display ON */
+	write_reg(par, 0xAF);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Set Lower Column Start Address for Page Addressing Mode */
+	write_reg(par, 0x00 | 0x0);
+	/* Set Higher Column Start Address for Page Addressing Mode */
+	write_reg(par, 0x10 | 0x0);
+	/* Set Display Start Line */
+	write_reg(par, 0x40 | 0x0);
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+	fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+		__func__, on ? "true" : "false");
+
+	if (on)
+		write_reg(par, 0xAE);
+	else
+		write_reg(par, 0xAF);
+	return 0;
+}
+
+/* Gamma is used to control Contrast */
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	curves[0] &= 0xFF;
+
+	/* Set Contrast Control for BANK0 */
+	write_reg(par, 0x81);
+	write_reg(par, curves[0]);
+
+	return 0;
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16 = (u16 *)par->info->screen_base;
+	u8 *buf = par->txbuf.buf;
+	int x, y, i;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	for (x = 0; x < par->info->var.xres; x++) {
+		for (y = 0; y < par->info->var.yres/8; y++) {
+			*buf = 0x00;
+			for (i = 0; i < 8; i++)
+				*buf |= (vmem16[(y*8+i)*par->info->var.xres+x] ? 1 : 0) << i;
+			buf++;
+		}
+	}
+
+	/* Write data */
+	gpio_set_value(par->gpio.dc, 1);
+	ret = par->fbtftops.write(par, par->txbuf.buf,
+				par->info->var.xres*par->info->var.yres/8);
+	if (ret < 0)
+		dev_err(par->info->device,
+			"%s: write failed and returned: %d\n", __func__, ret);
+
+	return ret;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = 1,
+	.gamma_len = 1,
+	.gamma = "00",
+	.fbtftops = {
+		.write_vmem = write_vmem,
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.blank = blank,
+		.set_gamma = set_gamma,
+	},
+};
+
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1306", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1306");
+MODULE_ALIAS("platform:ssd1306");
+
+MODULE_DESCRIPTION("SSD1306 OLED Driver");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c
new file mode 100644
index 0000000..da7464f
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1331.c
@@ -0,0 +1,205 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ssd1331"
+#define WIDTH		96
+#define HEIGHT		64
+#define GAMMA_NUM	1
+#define GAMMA_LEN	63
+#define DEFAULT_GAMMA	"0 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2" \
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	write_reg(par, 0xae); /* Display Off */
+	write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */
+	write_reg(par, 0x72); // RGB colour
+	write_reg(par, 0xa1, 0x00); /* Set Display Start Line */
+	write_reg(par, 0xa2, 0x00); /* Set Display Offset */
+	write_reg(par, 0xa4); /* NORMALDISPLAY */
+	write_reg(par, 0xa8, 0x3f); // Set multiplex
+	write_reg(par, 0xad, 0x8e); // Set master
+	// write_reg(par, 0xb0, 0x0b); // Set power mode
+	write_reg(par, 0xb1, 0x31); // Precharge
+	write_reg(par, 0xb3, 0xf0); // Clock div
+	write_reg(par, 0x8a, 0x64); // Precharge A
+	write_reg(par, 0x8b, 0x78); // Precharge B
+	write_reg(par, 0x8c, 0x64); // Precharge C
+	write_reg(par, 0xbb, 0x3a); // Precharge level
+	write_reg(par, 0xbe, 0x3e); // vcomh
+	write_reg(par, 0x87, 0x06); // Master current
+	write_reg(par, 0x81, 0x91); // Contrast A
+	write_reg(par, 0x82, 0x50); // Contrast B
+	write_reg(par, 0x83, 0x7d); // Contrast C
+	write_reg(par, 0xaf); /* Set Sleep Mode Display On */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	write_reg(par, 0x15, xs, xe);
+	write_reg(par, 0x75, ys, ye);
+}
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+	va_list args;
+	int i, ret;
+	u8 *buf = (u8 *)par->buf;
+
+	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+		va_start(args, len);
+		for (i = 0; i < len; i++) {
+			buf[i] = (u8)va_arg(args, unsigned int);
+		}
+		va_end(args);
+		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__);
+	}
+
+	va_start(args, len);
+
+	*buf = (u8)va_arg(args, unsigned int);
+	if (par->gpio.dc != -1)
+		gpio_set_value(par->gpio.dc, 0);
+	ret = par->fbtftops.write(par, par->buf, sizeof(u8));
+	if (ret < 0) {
+		va_end(args);
+		dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret);
+		return;
+	}
+	len--;
+
+	if (len) {
+		i = len;
+		while (i--) {
+			*buf++ = (u8)va_arg(args, unsigned int);
+		}
+		ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8)));
+		if (ret < 0) {
+			va_end(args);
+			dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret);
+			return;
+		}
+	}
+	if (par->gpio.dc != -1)
+		gpio_set_value(par->gpio.dc, 1);
+	va_end(args);
+}
+
+/*
+	Grayscale Lookup Table
+	GS1 - GS63
+	The driver Gamma curve contains the relative values between the entries
+	in the Lookup table.
+
+	From datasheet:
+	8.8 Gray Scale Decoder
+
+		there are total 180 Gamma Settings (Setting 0 to Setting 180)
+		available for the Gray Scale table.
+
+		The gray scale is defined in incremental way, with reference
+		to the length of previous table entry:
+			Setting of GS1 has to be >= 0
+			Setting of GS2 has to be > Setting of GS1 +1
+			Setting of GS3 has to be > Setting of GS2 +1
+			:
+			Setting of GS63 has to be > Setting of GS62 +1
+
+
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
+	int i, acc = 0;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	for (i = 0; i < 63; i++) {
+		if (i > 0 && curves[i] < 2) {
+			dev_err(par->info->device,
+				"Illegal value in Grayscale Lookup Table at index %d. " \
+				"Must be greater than 1\n", i);
+			return -EINVAL;
+		}
+		acc += curves[i];
+		tmp[i] = acc;
+		if (acc > 180) {
+			dev_err(par->info->device,
+				"Illegal value(s) in Grayscale Lookup Table. " \
+				"At index=%d, the accumulated value has exceeded 180\n", i);
+			return -EINVAL;
+		}
+	}
+
+	write_reg(par, 0xB8,
+	tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7],
+	tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15],
+	tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23],
+	tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31],
+	tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39],
+	tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47],
+	tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
+	tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]);
+
+	return 0;
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+	fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+		__func__, on ? "true" : "false");
+	if (on)
+		write_reg(par, 0xAE);
+	else
+		write_reg(par, 0xAF);
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = GAMMA_NUM,
+	.gamma_len = GAMMA_LEN,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.write_register = write_reg8_bus8,
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_gamma = set_gamma,
+		.blank = blank,
+	},
+};
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1331");
+MODULE_ALIAS("platform:ssd1331");
+
+MODULE_DESCRIPTION("SSD1331 OLED Driver");
+MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c
new file mode 100644
index 0000000..062d986
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1351.c
@@ -0,0 +1,258 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_ssd1351"
+#define WIDTH		128
+#define HEIGHT		128
+#define GAMMA_NUM	1
+#define GAMMA_LEN	63
+#define DEFAULT_GAMMA	"0 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2 2 " \
+			"2 2 2 2 2 2 2" \
+
+static void register_onboard_backlight(struct fbtft_par *par);
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	if (par->pdata
+		&& par->pdata->display.backlight == FBTFT_ONBOARD_BACKLIGHT) {
+		/* module uses onboard GPIO for panel power */
+		par->fbtftops.register_backlight = register_onboard_backlight;
+	}
+
+	par->fbtftops.reset(par);
+
+	write_reg(par, 0xfd, 0x12); /* Command Lock */
+	write_reg(par, 0xfd, 0xb1); /* Command Lock */
+	write_reg(par, 0xae); /* Display Off */
+	write_reg(par, 0xb3, 0xf1); /* Front Clock Div */
+	write_reg(par, 0xca, 0x7f); /* Set Mux Ratio */
+	write_reg(par, 0x15, 0x00, 0x7f); /* Set Column Address */
+	write_reg(par, 0x75, 0x00, 0x7f); /* Set Row Address */
+	write_reg(par, 0xa1, 0x00); /* Set Display Start Line */
+	write_reg(par, 0xa2, 0x00); /* Set Display Offset */
+	write_reg(par, 0xb5, 0x00); /* Set GPIO */
+	write_reg(par, 0xab, 0x01); /* Set Function Selection */
+	write_reg(par, 0xb1, 0x32); /* Set Phase Length */
+	write_reg(par, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */
+	write_reg(par, 0xbb, 0x17); /* Set Precharge Voltage */
+	write_reg(par, 0xbe, 0x05); /* Set VComH Voltage */
+	write_reg(par, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */
+	write_reg(par, 0xc7, 0x0f); /* Set Master Contrast */
+	write_reg(par, 0xb6, 0x01); /* Set Second Precharge Period */
+	write_reg(par, 0xa6); /* Set Display Mode Reset */
+	write_reg(par, 0xaf); /* Set Sleep Mode Display On */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	write_reg(par, 0x15, xs, xe);
+	write_reg(par, 0x75, ys, ye);
+	write_reg(par, 0x5c);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	unsigned remap;
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	if (par->fbtftops.init_display != init_display) {
+		/* don't risk messing up register A0h */
+		fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+			"%s: skipping since custom init_display() is used\n",
+			__func__);
+		return 0;
+	}
+
+	remap = 0x60 | (par->bgr << 2); /* Set Colour Depth */
+
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0xA0, remap | 0b00 | 1<<4);
+		break;
+	case 270:
+		write_reg(par, 0xA0, remap | 0b11 | 1<<4);
+		break;
+	case 180:
+		write_reg(par, 0xA0, remap | 0b10);
+		break;
+	case 90:
+		write_reg(par, 0xA0, remap | 0b01);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+	Grayscale Lookup Table
+	GS1 - GS63
+	The driver Gamma curve contains the relative values between the entries
+	in the Lookup table.
+
+	From datasheet:
+	8.8 Gray Scale Decoder
+
+		there are total 180 Gamma Settings (Setting 0 to Setting 180)
+		available for the Gray Scale table.
+
+		The gray scale is defined in incremental way, with reference
+		to the length of previous table entry:
+			Setting of GS1 has to be >= 0
+			Setting of GS2 has to be > Setting of GS1 +1
+			Setting of GS3 has to be > Setting of GS2 +1
+			:
+			Setting of GS63 has to be > Setting of GS62 +1
+
+
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
+	int i, acc = 0;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	for (i = 0; i < 63; i++) {
+		if (i > 0 && curves[i] < 2) {
+			dev_err(par->info->device,
+				"Illegal value in Grayscale Lookup Table at index %d. " \
+				"Must be greater than 1\n", i);
+			return -EINVAL;
+		}
+		acc += curves[i];
+		tmp[i] = acc;
+		if (acc > 180) {
+			dev_err(par->info->device,
+				"Illegal value(s) in Grayscale Lookup Table. " \
+				"At index=%d, the accumulated value has exceeded 180\n", i);
+			return -EINVAL;
+		}
+	}
+
+	write_reg(par, 0xB8,
+	tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7],
+	tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15],
+	tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23],
+	tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31],
+	tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39],
+	tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47],
+	tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
+	tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]);
+
+	return 0;
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+	fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+		__func__, on ? "true" : "false");
+	if (on)
+		write_reg(par, 0xAE);
+	else
+		write_reg(par, 0xAF);
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.gamma_num = GAMMA_NUM,
+	.gamma_len = GAMMA_LEN,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+		.blank = blank,
+	},
+};
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int update_onboard_backlight(struct backlight_device *bd)
+{
+	struct fbtft_par *par = bl_get_data(bd);
+	bool on;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+		"%s: power=%d, fb_blank=%d\n",
+		__func__, bd->props.power, bd->props.fb_blank);
+
+	on = (bd->props.power == FB_BLANK_UNBLANK)
+		&& (bd->props.fb_blank == FB_BLANK_UNBLANK);
+	/* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */
+	write_reg(par, 0xB5, on ? 0x03 : 0x02);
+
+	return 0;
+}
+
+static void register_onboard_backlight(struct fbtft_par *par)
+{
+	struct backlight_device *bd;
+	struct backlight_properties bl_props = { 0, };
+	struct backlight_ops *bl_ops;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+	bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+				GFP_KERNEL);
+	if (!bl_ops) {
+		dev_err(par->info->device,
+			"%s: could not allocate memory for backlight operations.\n",
+			__func__);
+		return;
+	}
+
+	bl_ops->update_status = update_onboard_backlight;
+	bl_props.type = BACKLIGHT_RAW;
+	bl_props.power = FB_BLANK_POWERDOWN;
+
+	bd = backlight_device_register(dev_driver_string(par->info->device),
+				par->info->device, par, bl_ops, &bl_props);
+	if (IS_ERR(bd)) {
+		dev_err(par->info->device,
+			"cannot register backlight device (%ld)\n",
+			PTR_ERR(bd));
+		return;
+	}
+	par->info->bl_dev = bd;
+
+	if (!par->fbtftops.unregister_backlight)
+		par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+static void register_onboard_backlight(struct fbtft_par *par) { };
+#endif
+
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1351");
+MODULE_ALIAS("platform:ssd1351");
+
+MODULE_DESCRIPTION("SSD1351 OLED Driver");
+MODULE_AUTHOR("James Davies");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_st7735r.c b/drivers/staging/fbtft/fb_st7735r.c
new file mode 100644
index 0000000..b63aa38
--- /dev/null
+++ b/drivers/staging/fbtft/fb_st7735r.c
@@ -0,0 +1,195 @@
+/*
+ * FB driver for the ST7735R LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_st7735r"
+#define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \
+                      "0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10"
+
+
+static int default_init_sequence[] = {
+	/* SWRESET - Software reset */
+	-1, 0x01,                                
+	-2, 150,                               /* delay */
+
+	/* SLPOUT - Sleep out & booster on */
+	-1, 0x11,                          
+	-2, 500,                               /* delay */
+
+	/* FRMCTR1 - frame rate control: normal mode
+	     frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */
+	-1, 0xB1, 0x01, 0x2C, 0x2D, 
+
+	/* FRMCTR2 - frame rate control: idle mode
+	     frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */
+	-1, 0xB2, 0x01, 0x2C, 0x2D, 
+
+	/* FRMCTR3 - frame rate control - partial mode
+	     dot inversion mode, line inversion mode */
+	-1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D,
+
+	/* INVCTR - display inversion control
+	     no inversion */
+	-1, 0xB4, 0x07,
+
+	/* PWCTR1 - Power Control
+	     -4.6V, AUTO mode */
+	-1, 0xC0, 0xA2, 0x02, 0x84,
+
+	/* PWCTR2 - Power Control
+	     VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */
+	-1, 0xC1, 0xC5,
+
+	/* PWCTR3 - Power Control
+	     Opamp current small, Boost frequency */
+	-1, 0xC2, 0x0A, 0x00,
+
+	/* PWCTR4 - Power Control
+	     BCLK/2, Opamp current small & Medium low */
+	-1, 0xC3,0x8A,0x2A,
+
+	/* PWCTR5 - Power Control */
+	-1, 0xC4, 0x8A, 0xEE,
+
+	/* VMCTR1 - Power Control */
+	-1, 0xC5, 0x0E,
+
+	/* INVOFF - Display inversion off */
+	-1, 0x20,
+
+	/* COLMOD - Interface pixel format */
+	-1, 0x3A, 0x05,
+
+	/* DISPON - Display On */
+	-1, 0x29,
+	-2, 100,                               /* delay */
+
+	/* NORON - Partial off (Normal) */
+	-1, 0x13,
+	-2, 10,                               /* delay */
+
+	/* end marker */
+	-3                                  
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address */
+	write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	/* Row adress */
+	write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* MADCTL - Memory data access control
+	     RGB/BGR:
+	     1. Mode selection pin SRGB
+	        RGB H/W pin for color filter setting: 0=RGB, 1=BGR
+	     2. MADCTL RGB bit
+	        RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */
+	switch (par->info->var.rotate) {
+	case 0:
+		write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+		break;
+	case 270:
+		write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+		break;
+	case 180:
+		write_reg(par, 0x36, (par->bgr << 3));
+		break;
+	case 90:
+		write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+		break;
+	}
+
+	return 0;
+}
+
+/*
+  Gamma string format:
+    VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P
+    VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N
+*/
+#define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	int i,j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	for (i = 0; i < par->gamma.num_curves; i++)
+		for (j = 0; j < par->gamma.num_values; j++)
+			CURVE(i,j) &= 0b111111;
+
+	for (i = 0; i < par->gamma.num_curves; i++)
+		write_reg(par, 0xE0 + i,
+			CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), CURVE(i, 3),
+			CURVE(i, 4), CURVE(i, 5), CURVE(i, 6), CURVE(i, 7),
+			CURVE(i, 8), CURVE(i, 9), CURVE(i, 10), CURVE(i, 11),
+			CURVE(i, 12), CURVE(i, 13), CURVE(i, 14), CURVE(i,15));
+
+	return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = 128,
+	.height = 160,
+	.init_sequence = default_init_sequence,
+	.gamma_num = 2,
+	.gamma_len = 16,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.set_gamma = set_gamma,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:st7735r");
+MODULE_ALIAS("platform:st7735r");
+
+MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_tinylcd.c b/drivers/staging/fbtft/fb_tinylcd.c
new file mode 100644
index 0000000..ca98bfb
--- /dev/null
+++ b/drivers/staging/fbtft/fb_tinylcd.c
@@ -0,0 +1,124 @@
+/*
+ * Custom FB driver for tinylcd.com display
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_tinylcd"
+#define WIDTH		320
+#define HEIGHT		480
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	write_reg(par, 0xB0, 0x80);
+	write_reg(par, 0xC0, 0x0A, 0x0A);
+	write_reg(par, 0xC1, 0x45, 0x07);
+	write_reg(par, 0xC2, 0x33);
+	write_reg(par, 0xC5, 0x00, 0x42, 0x80);
+	write_reg(par, 0xB1, 0xD0, 0x11);
+	write_reg(par, 0xB4, 0x02);
+	write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+	write_reg(par, 0xB7, 0x07);
+	write_reg(par, 0x36, 0x58);
+	write_reg(par, 0xF0, 0x36, 0xA5, 0xD3);
+	write_reg(par, 0xE5, 0x80);
+	write_reg(par, 0xE5, 0x01);
+	write_reg(par, 0xB3, 0x00);
+	write_reg(par, 0xE5, 0x00);
+	write_reg(par, 0xF0, 0x36, 0xA5, 0x53);
+	write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00,
+	                     0x00, 0x35, 0x33, 0x00, 0x00, 0x00);
+	write_reg(par, 0x3A, 0x55);
+	write_reg(par, 0x11);
+	udelay(250);
+	write_reg(par, 0x29);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address */
+	write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+	/* Row adress */
+	write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	case 270:
+		write_reg(par, 0xB6, 0x00, 0x02, 0x3B);
+		write_reg(par, 0x36, 0x28);
+		break;
+	case 180:
+		write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+		write_reg(par, 0x36, 0x58);
+		break;
+	case 90:
+		write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+		write_reg(par, 0x36, 0x38);
+		break;
+	default:
+		write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+		write_reg(par, 0x36, 0x08);
+		break;
+	}
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "neosec,tinylcd", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:tinylcd");
+
+MODULE_DESCRIPTION("Custom FB driver for tinylcd.com display");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_tls8204.c b/drivers/staging/fbtft/fb_tls8204.c
new file mode 100644
index 0000000..8738c7a
--- /dev/null
+++ b/drivers/staging/fbtft/fb_tls8204.c
@@ -0,0 +1,176 @@
+/*
+ * FB driver for the TLS8204 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ * Copyright (C) 2014 Michael Hope (adapted for the TLS8204)
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_tls8204"
+#define WIDTH		84
+#define HEIGHT		48
+#define TXBUFLEN	WIDTH
+#define DEFAULT_GAMMA	"40" /* gamma is used to control contrast in this driver */
+
+static unsigned bs = 4;
+module_param(bs, uint, 0);
+MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* Enter extended command mode */
+	write_reg(par, 0x21); /* 5:1  1
+				 2:0  PD - Powerdown control: chip is active
+				 1:0  V  - Entry mode: horizontal addressing
+				 0:1  H  - Extended instruction set control: extended
+			      */
+
+	/* H=1 Bias system */
+	write_reg(par, 0x10 | (bs & 0x7)); /*
+				 4:1  1
+				 3:0  0
+				 2:x  BS2 - Bias System
+				 1:x  BS1
+				 0:x  BS0
+			      */
+
+	/* Set the address of the first display line. */
+	write_reg(par, 0x04 | (64 >> 6));
+	write_reg(par, 0x40 | (64 & 0x3F));
+
+	/* Enter H=0 standard command mode */
+	write_reg(par, 0x20);
+
+	/* H=0 Display control */
+	write_reg(par, 0x08 | 4); /*
+				 3:1  1
+				 2:1  D  - DE: 10=normal mode
+				 1:0  0
+				 0:0  E
+			      */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* H=0 Set X address of RAM */
+	write_reg(par, 0x80); /* 7:1  1
+				 6-0: X[6:0] - 0x00
+			      */
+
+	/* H=0 Set Y address of RAM */
+	write_reg(par, 0x40); /* 7:0  0
+				 6:1  1
+				 2-0: Y[2:0] - 0x0
+			      */
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16 = (u16 *)par->info->screen_base;
+	int x, y, i;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	for (y = 0; y < HEIGHT/8; y++) {
+		u8 *buf = par->txbuf.buf;
+		/* The display is 102x68 but the LCD is 84x48.  Set
+		   the write pointer at the start of each row. */
+		gpio_set_value(par->gpio.dc, 0);
+		write_reg(par, 0x80 | 0);
+		write_reg(par, 0x40 | y);
+
+		for (x = 0; x < WIDTH; x++) {
+			u8 ch = 0;
+			for (i = 0; i < 8*WIDTH; i += WIDTH) {
+				ch >>= 1;
+				if (vmem16[(y*8*WIDTH)+i+x])
+					ch |= 0x80;
+			}
+			*buf++ = ch;
+		}
+		/* Write the row */
+		gpio_set_value(par->gpio.dc, 1);
+		ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
+		if (ret < 0) {
+			dev_err(par->info->device,
+				"%s: write failed and returned: %d\n", __func__, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* apply mask */
+	curves[0] &= 0x7F;
+
+	write_reg(par, 0x21); /* turn on extended instruction set */
+	write_reg(par, 0x80 | curves[0]);
+	write_reg(par, 0x20); /* turn off extended instruction set */
+
+	return 0;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.txbuflen = TXBUFLEN,
+	.gamma_num = 1,
+	.gamma_len = 1,
+	.gamma = DEFAULT_GAMMA,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.write_vmem = write_vmem,
+		.set_gamma = set_gamma,
+	},
+	.backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:tls8204");
+
+MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller");
+MODULE_AUTHOR("Michael Hope");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_uc1701.c b/drivers/staging/fbtft/fb_uc1701.c
new file mode 100644
index 0000000..d70ac52
--- /dev/null
+++ b/drivers/staging/fbtft/fb_uc1701.c
@@ -0,0 +1,210 @@
+/*
+ * FB driver for the UC1701 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2014 Juergen Holzmann
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME	"fb_uc1701"
+#define WIDTH	  102
+#define HEIGHT	 64
+#define PAGES	  (HEIGHT/8)
+
+/* 1: Display on/off */
+#define LCD_DISPLAY_ENABLE    0xAE
+/* 2: display start line set */
+#define LCD_START_LINE	0x40
+/* 3: Page address set (lower 4 bits select one of the pages) */
+#define LCD_PAGE_ADDRESS      0xB0
+/* 4: column address */
+#define LCD_COL_ADDRESS       0x10
+/* 8: select orientation */
+#define LCD_BOTTOMVIEW	0xA0
+/* 9: inverted display */
+#define LCD_DISPLAY_INVERT    0xA6
+/* 10: show memory content or switch all pixels on */
+#define LCD_ALL_PIXEL	 0xA4
+/* 11: lcd bias set */
+#define LCD_BIAS	      0xA2
+/* 14: Reset Controller */
+#define LCD_RESET_CMD	 0xE2
+/* 15: output mode select (turns display upside-down) */
+#define LCD_SCAN_DIR	  0xC0
+/* 16: power control set */
+#define LCD_POWER_CONTROL     0x28
+/* 17: voltage regulator resistor ratio set */
+#define LCD_VOLTAGE	   0x20
+/* 18: Volume mode set */
+#define LCD_VOLUME_MODE       0x81
+/* 22: NOP command */
+#define LCD_NO_OP	     0xE3
+/* 25: advanced program control */
+#define LCD_ADV_PROG_CTRL     0xFA
+/* 25: advanced program control2 */
+#define LCD_ADV_PROG_CTRL2    0x10
+#define LCD_TEMPCOMP_HIGH     0x80
+/* column offset for normal orientation */
+#define SHIFT_ADDR_NORMAL     0
+/* column offset for bottom view orientation */
+#define SHIFT_ADDR_TOPVIEW    30
+
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	/* softreset of LCD */
+	write_reg(par, LCD_RESET_CMD);
+	mdelay(10);
+
+	/* set startpoint */
+	/* LCD_START_LINE | (pos & 0x3F) */
+	write_reg(par, LCD_START_LINE);
+
+	/* select orientation BOTTOMVIEW */
+	write_reg(par, LCD_BOTTOMVIEW | 1);
+	/* output mode select (turns display upside-down) */
+	write_reg(par, LCD_SCAN_DIR | 0x00);
+
+	/* Normal Pixel mode */
+	write_reg(par, LCD_ALL_PIXEL | 0);
+
+	/* positive display */
+	write_reg(par, LCD_DISPLAY_INVERT | 0);
+
+	/* bias 1/9 */
+	write_reg(par, LCD_BIAS | 0);
+
+	/* power control mode: all features on */
+	/* LCD_POWER_CONTROL | (val&0x07) */
+	write_reg(par, LCD_POWER_CONTROL | 0x07);
+
+	/* set voltage regulator R/R */
+	/* LCD_VOLTAGE | (val&0x07) */
+	write_reg(par, LCD_VOLTAGE | 0x07);
+
+	/* volume mode set */
+	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+	write_reg(par, LCD_VOLUME_MODE);
+	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+	write_reg(par, 0x09);
+	/* ???? */
+	/* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+	write_reg(par, LCD_NO_OP);
+
+	/* advanced program control */
+	write_reg(par, LCD_ADV_PROG_CTRL);
+	write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH);
+
+	/* enable display */
+	write_reg(par, LCD_DISPLAY_ENABLE | 1);
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* goto address */
+	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+	 LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+	write_reg(par, LCD_PAGE_ADDRESS);
+	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+	  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+	write_reg(par, 0x00);
+	/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+	 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+	  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+	write_reg(par, LCD_COL_ADDRESS);
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16 = (u16 *)par->info->screen_base;
+	u8 *buf = par->txbuf.buf;
+	int x, y, i;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	for (y = 0; y < PAGES; y++) {
+		buf = par->txbuf.buf;
+		for (x = 0; x < WIDTH; x++) {
+			*buf = 0x00;
+			for (i = 0; i < 8; i++)
+				*buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i;
+			buf++;
+		}
+		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+		write_reg(par, LCD_PAGE_ADDRESS|(u8)y);
+		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+		write_reg(par, 0x00);
+		/* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+		 (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+		  LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+		write_reg(par, LCD_COL_ADDRESS);
+		gpio_set_value(par->gpio.dc, 1);
+		ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
+		gpio_set_value(par->gpio.dc, 0);
+	}
+
+	if (ret < 0)
+		dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret);
+
+	return ret;
+}
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.write_vmem = write_vmem,
+	},
+	.backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:uc1701");
+
+MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller");
+MODULE_AUTHOR("Juergen Holzmann");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c
new file mode 100644
index 0000000..fff57b3
--- /dev/null
+++ b/drivers/staging/fbtft/fb_upd161704.c
@@ -0,0 +1,206 @@
+/*
+ * FB driver for the uPD161704 LCD Controller
+ *
+ * Copyright (C) 2014 Seong-Woo Kim
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME		"fb_upd161704"
+#define WIDTH		240
+#define HEIGHT		320
+#define BPP		16
+
+static int init_display(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	par->fbtftops.reset(par);
+
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	/* Initialization sequence from Lib_UTFT */
+
+	/* register reset */
+	write_reg(par, 0x0003,0x0001);	/* Soft reset */
+
+	/* oscillator start */
+	write_reg(par, 0x003A,0x0001);	/*Oscillator 0: stop, 1: operation */
+	udelay(100);
+
+	/* y-setting */
+	write_reg(par, 0x0024,0x007B);	/* amplitude setting */
+	udelay(10);
+	write_reg(par, 0x0025,0x003B);	/* amplitude setting */
+	write_reg(par, 0x0026,0x0034);	/* amplitude setting */
+	udelay(10);
+	write_reg(par, 0x0027,0x0004);	/* amplitude setting */
+	write_reg(par, 0x0052,0x0025);	/* circuit setting 1 */
+	udelay(10);
+	write_reg(par, 0x0053,0x0033);	/* circuit setting 2 */
+	write_reg(par, 0x0061,0x001C);	/* adjustment V10 positive polarity */
+	udelay(10);
+	write_reg(par, 0x0062,0x002C);	/* adjustment V9 negative polarity */
+	write_reg(par, 0x0063,0x0022);	/* adjustment V34 positive polarity */
+	udelay(10);
+	write_reg(par, 0x0064,0x0027);	/* adjustment V31 negative polarity */
+	udelay(10);
+	write_reg(par, 0x0065,0x0014);	/* adjustment V61 negative polarity */
+	udelay(10);
+	write_reg(par, 0x0066,0x0010);	/* adjustment V61 negative polarity */
+	
+	/* Basical clock for 1 line (BASECOUNT[7:0]) number specified */
+	write_reg(par, 0x002E,0x002D);
+	
+	/* Power supply setting */
+	write_reg(par, 0x0019,0x0000);	/* DC/DC output setting */
+	udelay(200);
+	write_reg(par, 0x001A,0x1000);	/* DC/DC frequency setting */
+	write_reg(par, 0x001B,0x0023);	/* DC/DC rising setting */
+	write_reg(par, 0x001C,0x0C01);	/* Regulator voltage setting */
+	write_reg(par, 0x001D,0x0000);	/* Regulator current setting */
+	write_reg(par, 0x001E,0x0009);	/* VCOM output setting */
+	write_reg(par, 0x001F,0x0035);	/* VCOM amplitude setting */
+	write_reg(par, 0x0020,0x0015);	/* VCOMM cencter setting */
+	write_reg(par, 0x0018,0x1E7B);	/* DC/DC operation setting */
+
+	/* windows setting */
+	write_reg(par, 0x0008,0x0000);	/* Minimum X address */
+	write_reg(par, 0x0009,0x00EF);	/* Maximum X address */
+	write_reg(par, 0x000a,0x0000);	/* Minimum Y address */
+	write_reg(par, 0x000b,0x013F);	/* Maximum Y address */
+
+	/* LCD display area setting */
+	write_reg(par, 0x0029,0x0000);	/* [LCDSIZE]  X MIN. size set */
+	write_reg(par, 0x002A,0x0000);	/* [LCDSIZE]  Y MIN. size set */
+	write_reg(par, 0x002B,0x00EF);	/* [LCDSIZE]  X MAX. size set */
+	write_reg(par, 0x002C,0x013F);	/* [LCDSIZE]  Y MAX. size set */
+
+	/* Gate scan setting */
+	write_reg(par, 0x0032,0x0002);
+	
+	/* n line inversion line number */
+	write_reg(par, 0x0033,0x0000);
+
+	/* Line inversion/frame inversion/interlace setting */
+	write_reg(par, 0x0037,0x0000);
+	
+	/* Gate scan operation setting register */
+	write_reg(par, 0x003B,0x0001);
+	
+	/* Color mode */
+	/*GS = 0: 260-k color (64 gray scale), GS = 1: 8 color (2 gray scale) */
+	write_reg(par, 0x0004,0x0000);
+
+	/* RAM control register */
+	write_reg(par, 0x0005,0x0000);	/*Window access 00:Normal, 10:Window */
+
+	/* Display setting register 2 */
+	write_reg(par, 0x0001,0x0000);
+
+	/* display setting */
+	write_reg(par, 0x0000,0x0000);	/* display on */
+
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	switch (par->info->var.rotate) {
+	/* R20h = Horizontal GRAM Start Address */
+	/* R21h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0006, xs);
+		write_reg(par, 0x0007, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0006, WIDTH - 1 - xs);
+		write_reg(par, 0x0007, HEIGHT - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0006, WIDTH - 1 - ys);
+		write_reg(par, 0x0007, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0006, ys);
+		write_reg(par, 0x0007, HEIGHT - 1 - xs);
+		break;
+	}
+
+	write_reg(par, 0x0e); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	switch (par->info->var.rotate) {
+	/* AM: GRAM update direction */
+	case 0:
+		write_reg(par, 0x01, 0x0000);
+		write_reg(par, 0x05, 0x0000);
+		break;
+	case 180:
+		write_reg(par, 0x01, 0x00C0);
+		write_reg(par, 0x05, 0x0000);
+		break;
+	case 270:
+		write_reg(par, 0x01, 0x0080);
+		write_reg(par, 0x05, 0x0001);
+		break;
+	case 90:
+		write_reg(par, 0x01, 0x0040);
+		write_reg(par, 0x05, 0x0001);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fbtft_display display = {
+	.regwidth = 16,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.fbtftops = {
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "nec,upd161704", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:upd161704");
+MODULE_ALIAS("platform:upd161704");
+
+MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller");
+MODULE_AUTHOR("Seong-Woo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c
new file mode 100644
index 0000000..975b579
--- /dev/null
+++ b/drivers/staging/fbtft/fb_watterott.c
@@ -0,0 +1,324 @@
+/*
+ * FB driver for the Watterott LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME			"fb_watterott"
+#define WIDTH			320
+#define HEIGHT			240
+#define FPS			5
+#define TXBUFLEN		1024
+#define DEFAULT_BRIGHTNESS	50
+
+#define CMD_VERSION		0x01
+#define CMD_LCD_LED		0x10
+#define CMD_LCD_RESET		0x11
+#define CMD_LCD_ORIENTATION	0x20
+#define CMD_LCD_DRAWIMAGE	0x27
+#define COLOR_RGB323		8
+#define COLOR_RGB332		9
+#define COLOR_RGB233		10
+#define COLOR_RGB565		16
+
+
+static short mode = 565;
+module_param(mode, short, 0);
+MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)");
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+	va_list args;
+	int i, ret;
+	u8 *buf = par->buf;
+
+	va_start(args, len);
+	for (i = 0; i < len; i++)
+		*buf++ = (u8)va_arg(args, unsigned int);
+	va_end(args);
+
+	fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+		par->info->device, u8, par->buf, len, "%s: ", __func__);
+
+	ret = par->fbtftops.write(par, par->buf, len);
+	if (ret < 0) {
+		dev_err(par->info->device,
+			"%s: write() failed and returned %d\n", __func__, ret);
+		return;
+	}
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+	unsigned start_line, end_line;
+	u16 *vmem16 = (u16 *)(par->info->screen_base + offset);
+	u16 *pos = par->txbuf.buf + 1;
+	u16 *buf16 = par->txbuf.buf + 10;
+	int i, j;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	start_line = offset / par->info->fix.line_length;
+	end_line = start_line + (len / par->info->fix.line_length) - 1;
+
+	/* Set command header. pos: x, y, w, h */
+	((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE;
+	pos[0] = 0;
+	pos[2] = cpu_to_be16(par->info->var.xres);
+	pos[3] = cpu_to_be16(1);
+	((u8 *)par->txbuf.buf)[9] = COLOR_RGB565;
+
+	for (i = start_line; i <= end_line; i++) {
+		pos[1] = cpu_to_be16(i);
+		for (j = 0; j < par->info->var.xres; j++)
+			buf16[j] = cpu_to_be16(*vmem16++);
+		ret = par->fbtftops.write(par,
+			par->txbuf.buf, 10 + par->info->fix.line_length);
+		if (ret < 0)
+			return ret;
+		udelay(300);
+	}
+
+	return 0;
+}
+
+#define RGB565toRGB323(c) (((c&0xE000)>>8) | ((c&0600)>>6) | ((c&0x001C)>>2))
+#define RGB565toRGB332(c) (((c&0xE000)>>8) | ((c&0700)>>6) | ((c&0x0018)>>3))
+#define RGB565toRGB233(c) (((c&0xC000)>>8) | ((c&0700)>>5) | ((c&0x001C)>>2))
+
+static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len)
+{
+	unsigned start_line, end_line;
+	u16 *vmem16 = (u16 *)(par->info->screen_base + offset);
+	u16 *pos = par->txbuf.buf + 1;
+	u8 *buf8 = par->txbuf.buf + 10;
+	int i, j;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+	start_line = offset / par->info->fix.line_length;
+	end_line = start_line + (len / par->info->fix.line_length) - 1;
+
+	/* Set command header. pos: x, y, w, h */
+	((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE;
+	pos[0] = 0;
+	pos[2] = cpu_to_be16(par->info->var.xres);
+	pos[3] = cpu_to_be16(1);
+	((u8 *)par->txbuf.buf)[9] = COLOR_RGB332;
+
+	for (i = start_line; i <= end_line; i++) {
+		pos[1] = cpu_to_be16(i);
+		for (j = 0; j < par->info->var.xres; j++) {
+			buf8[j] = RGB565toRGB332(*vmem16);
+			vmem16++;
+		}
+		ret = par->fbtftops.write(par,
+			par->txbuf.buf, 10 + par->info->var.xres);
+		if (ret < 0)
+			return ret;
+		udelay(700);
+	}
+
+	return 0;
+}
+
+static unsigned firmware_version(struct fbtft_par *par)
+{
+	u8 rxbuf[4] = {0, };
+
+	write_reg(par, CMD_VERSION);
+	par->fbtftops.read(par, rxbuf, 4);
+	if (rxbuf[1] != '.')
+		return 0;
+
+	return (rxbuf[0] - '0') << 8 | (rxbuf[2] - '0') << 4 | (rxbuf[3] - '0');
+}
+
+static int init_display(struct fbtft_par *par)
+{
+	int ret;
+	unsigned version;
+	u8 save_mode;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* enable SPI interface by having CS and MOSI low during reset */
+	save_mode = par->spi->mode;
+	par->spi->mode |= SPI_CS_HIGH;
+	ret = par->spi->master->setup(par->spi); /* set CS inactive low */
+	if (ret) {
+		dev_err(par->info->device, "Could not set SPI_CS_HIGH\n");
+		return ret;
+	}
+	write_reg(par, 0x00); /* make sure mode is set */
+
+	mdelay(50);
+	par->fbtftops.reset(par);
+	mdelay(1000);
+	par->spi->mode = save_mode;
+	ret = par->spi->master->setup(par->spi);
+	if (ret) {
+		dev_err(par->info->device, "Could not restore SPI mode\n");
+		return ret;
+	}
+	write_reg(par, 0x00);
+
+	version = firmware_version(par);
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Firmware version: %x.%02x\n",
+						version >> 8, version & 0xFF);
+
+	if (mode == 332)
+		par->fbtftops.write_vmem = write_vmem_8bit;
+	return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	/* not used on this controller */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+	u8 rotate;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* this controller rotates clock wise */
+	switch (par->info->var.rotate) {
+	case 90:
+		rotate = 27;
+		break;
+	case 180:
+		rotate = 18;
+		break;
+	case 270:
+		rotate = 9;
+		break;
+	default:
+		rotate = 0;
+	}
+	write_reg(par, CMD_LCD_ORIENTATION, rotate);
+
+	return 0;
+}
+
+static int verify_gpios(struct fbtft_par *par)
+{
+	if (par->gpio.reset < 0) {
+		dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int backlight_chip_update_status(struct backlight_device *bd)
+{
+	struct fbtft_par *par = bl_get_data(bd);
+	int brightness = bd->props.brightness;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+		"%s: brightness=%d, power=%d, fb_blank=%d\n",
+		__func__, bd->props.brightness, bd->props.power,
+		bd->props.fb_blank);
+
+	if (bd->props.power != FB_BLANK_UNBLANK)
+		brightness = 0;
+
+	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+		brightness = 0;
+
+	write_reg(par, CMD_LCD_LED, brightness);
+
+	return 0;
+}
+
+static void register_chip_backlight(struct fbtft_par *par)
+{
+	struct backlight_device *bd;
+	struct backlight_properties bl_props = { 0, };
+	struct backlight_ops *bl_ops;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+	bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+				GFP_KERNEL);
+	if (!bl_ops) {
+		dev_err(par->info->device,
+			"%s: could not allocate memory for backlight operations.\n",
+			__func__);
+		return;
+	}
+
+	bl_ops->update_status = backlight_chip_update_status;
+	bl_props.type = BACKLIGHT_RAW;
+	bl_props.power = FB_BLANK_POWERDOWN;
+	bl_props.max_brightness = 100;
+	bl_props.brightness = DEFAULT_BRIGHTNESS;
+
+	bd = backlight_device_register(dev_driver_string(par->info->device),
+				par->info->device, par, bl_ops, &bl_props);
+	if (IS_ERR(bd)) {
+		dev_err(par->info->device,
+			"cannot register backlight device (%ld)\n",
+			PTR_ERR(bd));
+		return;
+	}
+	par->info->bl_dev = bd;
+
+	if (!par->fbtftops.unregister_backlight)
+		par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+#define register_chip_backlight NULL
+#endif
+
+
+static struct fbtft_display display = {
+	.regwidth = 8,
+	.buswidth = 8,
+	.width = WIDTH,
+	.height = HEIGHT,
+	.fps = FPS,
+	.txbuflen = TXBUFLEN,
+	.fbtftops = {
+		.write_register = write_reg8_bus8,
+		.write_vmem = write_vmem,
+		.init_display = init_display,
+		.set_addr_win = set_addr_win,
+		.set_var = set_var,
+		.verify_gpios = verify_gpios,
+		.register_backlight = register_chip_backlight,
+	},
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "watterott,openlcd", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+
+MODULE_DESCRIPTION("FB driver for the Watterott LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
new file mode 100644
index 0000000..b3cddb0
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -0,0 +1,256 @@
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include "fbtft.h"
+
+
+
+
+/*****************************************************************************
+ *
+ *   void (*write_reg)(struct fbtft_par *par, int len, ...);
+ *
+ *****************************************************************************/
+
+#define define_fbtft_write_reg(func, type, modifier)                          \
+void func(struct fbtft_par *par, int len, ...)                                \
+{                                                                             \
+	va_list args;                                                         \
+	int i, ret;                                                           \
+	int offset = 0;                                                       \
+	type *buf = (type *)par->buf;                                         \
+									      \
+	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {                    \
+		va_start(args, len);                                          \
+		for (i = 0; i < len; i++) {                                   \
+			buf[i] = (type)va_arg(args, unsigned int);            \
+		}                                                             \
+		va_end(args);                                                 \
+		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__);   \
+	}                                                                     \
+									      \
+	va_start(args, len);                                                  \
+									      \
+	if (par->startbyte) {                                                 \
+		*(u8 *)par->buf = par->startbyte;                             \
+		buf = (type *)(par->buf + 1);                                 \
+		offset = 1;                                                   \
+	}                                                                     \
+									      \
+	*buf = modifier((type)va_arg(args, unsigned int));                    \
+	if (par->gpio.dc != -1)                                               \
+		gpio_set_value(par->gpio.dc, 0);                              \
+	ret = par->fbtftops.write(par, par->buf, sizeof(type)+offset);        \
+	if (ret < 0) {                                                        \
+		va_end(args);                                                 \
+		dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \
+		return;                                                       \
+	}                                                                     \
+	len--;                                                                \
+									      \
+	if (par->startbyte)                                                   \
+		*(u8 *)par->buf = par->startbyte | 0x2;                       \
+									      \
+	if (len) {                                                            \
+		i = len;                                                      \
+		while (i--) {                                                 \
+			*buf++ = modifier((type)va_arg(args, unsigned int));  \
+		}                                                             \
+		if (par->gpio.dc != -1)                                       \
+			gpio_set_value(par->gpio.dc, 1);                      \
+		ret = par->fbtftops.write(par, par->buf, len * (sizeof(type)+offset)); \
+		if (ret < 0) {                                                \
+			va_end(args);                                         \
+			dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \
+			return;                                               \
+		}                                                             \
+	}                                                                     \
+	va_end(args);                                                         \
+}                                                                             \
+EXPORT_SYMBOL(func);
+
+define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, )
+define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16)
+define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, )
+
+void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
+{
+	va_list args;
+	int i, ret;
+	int pad = 0;
+	u16 *buf = (u16 *)par->buf;
+
+	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+		va_start(args, len);
+		for (i = 0; i < len; i++)
+			*(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int);
+		va_end(args);
+		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+			par->info->device, u8, buf, len, "%s: ", __func__);
+	}
+	if (len <= 0)
+		return;
+
+	if (par->spi && (par->spi->bits_per_word == 8)) {
+		/* we're emulating 9-bit, pad start of buffer with no-ops
+		   (assuming here that zero is a no-op) */
+		pad = (len % 4) ? 4 - (len % 4) : 0;
+		for (i = 0; i < pad; i++)
+			*buf++ = 0x000;
+	}
+
+	va_start(args, len);
+	*buf++ = (u8)va_arg(args, unsigned int);
+	i = len - 1;
+	while (i--) {
+		*buf = (u8)va_arg(args, unsigned int);
+		*buf++ |= 0x100; /* dc=1 */
+	}
+	va_end(args);
+	ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16));
+	if (ret < 0) {
+		dev_err(par->info->device,
+			"%s: write() failed and returned %d\n", __func__, ret);
+		return;
+	}
+}
+EXPORT_SYMBOL(fbtft_write_reg8_bus9);
+
+
+
+
+/*****************************************************************************
+ *
+ *   int (*write_vmem)(struct fbtft_par *par);
+ *
+ *****************************************************************************/
+
+/* 16 bit pixel over 8-bit databus */
+int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16;
+	u16 *txbuf16 = (u16 *)par->txbuf.buf;
+	size_t remain;
+	size_t to_copy;
+	size_t tx_array_size;
+	int i;
+	int ret = 0;
+	size_t startbyte_size = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+		__func__, offset, len);
+
+	remain = len / 2;
+	vmem16 = (u16 *)(par->info->screen_base + offset);
+
+	if (par->gpio.dc != -1)
+		gpio_set_value(par->gpio.dc, 1);
+
+	/* non buffered write */
+	if (!par->txbuf.buf)
+		return par->fbtftops.write(par, vmem16, len);
+
+	/* buffered write */
+	tx_array_size = par->txbuf.len / 2;
+
+	if (par->startbyte) {
+		txbuf16 = (u16 *)(par->txbuf.buf + 1);
+		tx_array_size -= 2;
+		*(u8 *)(par->txbuf.buf) = par->startbyte | 0x2;
+		startbyte_size = 1;
+	}
+
+	while (remain) {
+		to_copy = remain > tx_array_size ? tx_array_size : remain;
+		dev_dbg(par->info->device, "    to_copy=%zu, remain=%zu\n",
+						to_copy, remain - to_copy);
+
+		for (i = 0; i < to_copy; i++)
+			txbuf16[i] = cpu_to_be16(vmem16[i]);
+
+		vmem16 = vmem16 + to_copy;
+		ret = par->fbtftops.write(par, par->txbuf.buf,
+						startbyte_size + to_copy * 2);
+		if (ret < 0)
+			return ret;
+		remain -= to_copy;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus8);
+
+/* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */
+int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u8 *vmem8;
+	u16 *txbuf16 = par->txbuf.buf;
+	size_t remain;
+	size_t to_copy;
+	size_t tx_array_size;
+	int i;
+	int ret = 0;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+		__func__, offset, len);
+
+	if (!par->txbuf.buf) {
+		dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__);
+		return -1;
+	}
+
+	remain = len;
+	vmem8 = par->info->screen_base + offset;
+
+	tx_array_size = par->txbuf.len / 2;
+
+	while (remain) {
+		to_copy = remain > tx_array_size ? tx_array_size : remain;
+		dev_dbg(par->info->device, "    to_copy=%zu, remain=%zu\n",
+						to_copy, remain - to_copy);
+
+#ifdef __LITTLE_ENDIAN
+		for (i = 0; i < to_copy; i += 2) {
+			txbuf16[i]   = 0x0100 | vmem8[i+1];
+			txbuf16[i+1] = 0x0100 | vmem8[i];
+		}
+#else
+		for (i = 0; i < to_copy; i++)
+			txbuf16[i]   = 0x0100 | vmem8[i];
+#endif
+		vmem8 = vmem8 + to_copy;
+		ret = par->fbtftops.write(par, par->txbuf.buf, to_copy*2);
+		if (ret < 0)
+			return ret;
+		remain -= to_copy;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus9);
+
+int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+	dev_err(par->info->device, "%s: function not implemented\n", __func__);
+	return -1;
+}
+EXPORT_SYMBOL(fbtft_write_vmem8_bus8);
+
+/* 16 bit pixel over 16-bit databus */
+int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len)
+{
+	u16 *vmem16;
+
+	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+		__func__, offset, len);
+
+	vmem16 = (u16 *)(par->info->screen_base + offset);
+
+	if (par->gpio.dc != -1)
+		gpio_set_value(par->gpio.dc, 1);
+
+	/* no need for buffered write with 16-bit bus */
+	return par->fbtftops.write(par, vmem16, len);
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus16);
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
new file mode 100644
index 0000000..37dcf7e
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -0,0 +1,1521 @@
+/*
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This driver is inspired by:
+ *   st7735fb.c, Copyright (C) 2011, Matt Porter
+ *   broadsheetfb.c, Copyright (C) 2008, Jaya Kumar
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include "fbtft.h"
+
+extern void fbtft_sysfs_init(struct fbtft_par *par);
+extern void fbtft_sysfs_exit(struct fbtft_par *par);
+extern void fbtft_expand_debug_value(unsigned long *debug);
+extern int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+						const char *str, int size);
+
+static unsigned long debug;
+module_param(debug, ulong , 0);
+MODULE_PARM_DESC(debug, "override device debug level");
+
+static bool dma = true;
+module_param(dma, bool, 0);
+MODULE_PARM_DESC(dma, "Use DMA buffer");
+
+
+void fbtft_dbg_hex(const struct device *dev, int groupsize,
+			void *buf, size_t len, const char *fmt, ...)
+{
+	va_list args;
+	static char textbuf[512];
+	char *text = textbuf;
+	size_t text_len;
+
+	va_start(args, fmt);
+	text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
+	va_end(args);
+
+	hex_dump_to_buffer(buf, len, 32, groupsize, text + text_len,
+				512 - text_len, false);
+
+	if (len > 32)
+		dev_info(dev, "%s ...\n", text);
+	else
+		dev_info(dev, "%s\n", text);
+}
+EXPORT_SYMBOL(fbtft_dbg_hex);
+
+static unsigned long fbtft_request_gpios_match(struct fbtft_par *par,
+					const struct fbtft_gpio *gpio)
+{
+	int ret;
+	long val;
+
+	fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n",
+		__func__, gpio->name);
+
+	if (strcasecmp(gpio->name, "reset") == 0) {
+		par->gpio.reset = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	} else if (strcasecmp(gpio->name, "dc") == 0) {
+		par->gpio.dc = gpio->gpio;
+		return GPIOF_OUT_INIT_LOW;
+	} else if (strcasecmp(gpio->name, "cs") == 0) {
+		par->gpio.cs = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	} else if (strcasecmp(gpio->name, "wr") == 0) {
+		par->gpio.wr = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	} else if (strcasecmp(gpio->name, "rd") == 0) {
+		par->gpio.rd = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	} else if (strcasecmp(gpio->name, "latch") == 0) {
+		par->gpio.latch = gpio->gpio;
+		return GPIOF_OUT_INIT_LOW;
+	} else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') {
+		ret = kstrtol(&gpio->name[2], 10, &val);
+		if (ret == 0 && val < 16) {
+			par->gpio.db[val] = gpio->gpio;
+			return GPIOF_OUT_INIT_LOW;
+		}
+	} else if (strcasecmp(gpio->name, "led") == 0) {
+		par->gpio.led[0] = gpio->gpio;
+		return GPIOF_OUT_INIT_LOW;
+	} else if (strcasecmp(gpio->name, "led_") == 0) {
+		par->gpio.led[0] = gpio->gpio;
+		return GPIOF_OUT_INIT_HIGH;
+	}
+
+	return FBTFT_GPIO_NO_MATCH;
+}
+
+static int fbtft_request_gpios(struct fbtft_par *par)
+{
+	struct fbtft_platform_data *pdata = par->pdata;
+	const struct fbtft_gpio *gpio;
+	unsigned long flags;
+	int ret;
+
+	if (pdata && pdata->gpios) {
+		gpio = pdata->gpios;
+		while (gpio->name[0]) {
+			flags = FBTFT_GPIO_NO_MATCH;
+			/* if driver provides match function, try it first,
+			   if no match use our own */
+			if (par->fbtftops.request_gpios_match)
+				flags = par->fbtftops.request_gpios_match(par, gpio);
+			if (flags == FBTFT_GPIO_NO_MATCH)
+				flags = fbtft_request_gpios_match(par, gpio);
+			if (flags != FBTFT_GPIO_NO_MATCH) {
+				ret = devm_gpio_request_one(par->info->device,
+						gpio->gpio, flags,
+						par->info->device->driver->name);
+				if (ret < 0) {
+					dev_err(par->info->device,
+						"%s: gpio_request_one('%s'=%d) failed with %d\n",
+						__func__, gpio->name,
+						gpio->gpio, ret);
+					return ret;
+				}
+				fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par,
+					"%s: '%s' = GPIO%d\n",
+					__func__, gpio->name, gpio->gpio);
+			}
+			gpio++;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int fbtft_request_one_gpio(struct fbtft_par *par,
+				  const char *name, int index, int *gpiop)
+{
+	struct device *dev = par->info->device;
+	struct device_node *node = dev->of_node;
+	int gpio, flags, ret = 0;
+	enum of_gpio_flags of_flags;
+
+	if (of_find_property(node, name, NULL)) {
+		gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
+		if (gpio == -ENOENT)
+			return 0;
+		if (gpio == -EPROBE_DEFER)
+			return gpio;
+		if (gpio < 0) {
+			dev_err(dev,
+				"failed to get '%s' from DT\n", name);
+			return gpio;
+		}
+
+		/* active low translates to initially low */
+		flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
+							GPIOF_OUT_INIT_HIGH;
+		ret = devm_gpio_request_one(dev, gpio, flags,
+						dev->driver->name);
+		if (ret) {
+			dev_err(dev,
+				"gpio_request_one('%s'=%d) failed with %d\n",
+				name, gpio, ret);
+			return ret;
+		}
+		if (gpiop)
+			*gpiop = gpio;
+		fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
+							__func__, name, gpio);
+	}
+
+	return ret;
+}
+
+static int fbtft_request_gpios_dt(struct fbtft_par *par)
+{
+	int i;
+	int ret;
+
+	if (!par->info->device->of_node)
+		return -EINVAL;
+
+	ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
+	if (ret)
+		return ret;
+	ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
+	if (ret)
+		return ret;
+	ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
+	if (ret)
+		return ret;
+	ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
+	if (ret)
+		return ret;
+	ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
+	if (ret)
+		return ret;
+	ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
+	if (ret)
+		return ret;
+	for (i = 0; i < 16; i++) {
+		ret = fbtft_request_one_gpio(par, "db-gpios", i,
+						&par->gpio.db[i]);
+		if (ret)
+			return ret;
+		ret = fbtft_request_one_gpio(par, "led-gpios", i,
+						&par->gpio.led[i]);
+		if (ret)
+			return ret;
+		ret = fbtft_request_one_gpio(par, "aux-gpios", i,
+						&par->gpio.aux[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int fbtft_backlight_update_status(struct backlight_device *bd)
+{
+	struct fbtft_par *par = bl_get_data(bd);
+	bool polarity = !!(bd->props.state & BL_CORE_DRIVER1);
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+		"%s: polarity=%d, power=%d, fb_blank=%d\n",
+		__func__, polarity, bd->props.power, bd->props.fb_blank);
+
+	if ((bd->props.power == FB_BLANK_UNBLANK) && (bd->props.fb_blank == FB_BLANK_UNBLANK))
+		gpio_set_value(par->gpio.led[0], polarity);
+	else
+		gpio_set_value(par->gpio.led[0], !polarity);
+
+	return 0;
+}
+
+static int fbtft_backlight_get_brightness(struct backlight_device *bd)
+{
+	return bd->props.brightness;
+}
+
+void fbtft_unregister_backlight(struct fbtft_par *par)
+{
+	const struct backlight_ops *bl_ops;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+	if (par->info->bl_dev) {
+		par->info->bl_dev->props.power = FB_BLANK_POWERDOWN;
+		backlight_update_status(par->info->bl_dev);
+		bl_ops = par->info->bl_dev->ops;
+		backlight_device_unregister(par->info->bl_dev);
+		par->info->bl_dev = NULL;
+	}
+}
+
+void fbtft_register_backlight(struct fbtft_par *par)
+{
+	struct backlight_device *bd;
+	struct backlight_properties bl_props = { 0, };
+	struct backlight_ops *bl_ops;
+
+	fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+	if (par->gpio.led[0] == -1) {
+		fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+			"%s(): led pin not set, exiting.\n", __func__);
+		return;
+	}
+
+	bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+				GFP_KERNEL);
+	if (!bl_ops) {
+		dev_err(par->info->device,
+			"%s: could not allocate memeory for backlight operations.\n",
+			__func__);
+		return;
+	}
+
+	bl_ops->get_brightness = fbtft_backlight_get_brightness;
+	bl_ops->update_status = fbtft_backlight_update_status;
+	bl_props.type = BACKLIGHT_RAW;
+	/* Assume backlight is off, get polarity from current state of pin */
+	bl_props.power = FB_BLANK_POWERDOWN;
+	if (!gpio_get_value(par->gpio.led[0]))
+		bl_props.state |= BL_CORE_DRIVER1;
+
+	bd = backlight_device_register(dev_driver_string(par->info->device),
+				par->info->device, par, bl_ops, &bl_props);
+	if (IS_ERR(bd)) {
+		dev_err(par->info->device,
+			"cannot register backlight device (%ld)\n",
+			PTR_ERR(bd));
+		return;
+	}
+	par->info->bl_dev = bd;
+
+	if (!par->fbtftops.unregister_backlight)
+		par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+void fbtft_register_backlight(struct fbtft_par *par) { };
+void fbtft_unregister_backlight(struct fbtft_par *par) { };
+#endif
+EXPORT_SYMBOL(fbtft_register_backlight);
+EXPORT_SYMBOL(fbtft_unregister_backlight);
+
+static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
+			       int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	/* Column address set */
+	write_reg(par, 0x2A,
+		(xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
+
+	/* Row adress set */
+	write_reg(par, 0x2B,
+		(ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
+
+	/* Memory write */
+	write_reg(par, 0x2C);
+}
+
+
+static void fbtft_reset(struct fbtft_par *par)
+{
+	if (par->gpio.reset == -1)
+		return;
+	fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
+	gpio_set_value(par->gpio.reset, 0);
+	udelay(20);
+	gpio_set_value(par->gpio.reset, 1);
+	mdelay(120);
+}
+
+
+static void fbtft_update_display(struct fbtft_par *par, unsigned start_line,
+				 unsigned end_line)
+{
+	size_t offset, len;
+	struct timespec ts_start, ts_end, ts_fps, ts_duration;
+	long fps_ms, fps_us, duration_ms, duration_us;
+	long fps, throughput;
+	bool timeit = false;
+	int ret = 0;
+
+	if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) {
+		if ((par->debug & DEBUG_TIME_EACH_UPDATE) || \
+				((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) {
+			getnstimeofday(&ts_start);
+			timeit = true;
+		}
+	}
+
+	/* Sanity checks */
+	if (start_line > end_line) {
+		dev_warn(par->info->device,
+			"%s: start_line=%u is larger than end_line=%u. Shouldn't happen, will do full display update\n",
+			__func__, start_line, end_line);
+		start_line = 0;
+		end_line = par->info->var.yres - 1;
+	}
+	if (start_line > par->info->var.yres - 1 || end_line > par->info->var.yres - 1) {
+		dev_warn(par->info->device,
+			"%s: start_line=%u or end_line=%u is larger than max=%d. Shouldn't happen, will do full display update\n",
+			__func__, start_line, end_line, par->info->var.yres - 1);
+		start_line = 0;
+		end_line = par->info->var.yres - 1;
+	}
+
+	fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
+		__func__, start_line, end_line);
+
+	if (par->fbtftops.set_addr_win)
+		par->fbtftops.set_addr_win(par, 0, start_line,
+				par->info->var.xres-1, end_line);
+
+	offset = start_line * par->info->fix.line_length;
+	len = (end_line - start_line + 1) * par->info->fix.line_length;
+	ret = par->fbtftops.write_vmem(par, offset, len);
+	if (ret < 0)
+		dev_err(par->info->device,
+			"%s: write_vmem failed to update display buffer\n",
+			__func__);
+
+	if (unlikely(timeit)) {
+		getnstimeofday(&ts_end);
+		if (par->update_time.tv_nsec == 0 && par->update_time.tv_sec == 0) {
+			par->update_time.tv_sec = ts_start.tv_sec;
+			par->update_time.tv_nsec = ts_start.tv_nsec;
+		}
+		ts_fps = timespec_sub(ts_start, par->update_time);
+		par->update_time.tv_sec = ts_start.tv_sec;
+		par->update_time.tv_nsec = ts_start.tv_nsec;
+		fps_ms = (ts_fps.tv_sec * 1000) + ((ts_fps.tv_nsec / 1000000) % 1000);
+		fps_us = (ts_fps.tv_nsec / 1000) % 1000;
+		fps = fps_ms * 1000 + fps_us;
+		fps = fps ? 1000000 / fps : 0;
+
+		ts_duration = timespec_sub(ts_end, ts_start);
+		duration_ms = (ts_duration.tv_sec * 1000) + ((ts_duration.tv_nsec / 1000000) % 1000);
+		duration_us = (ts_duration.tv_nsec / 1000) % 1000;
+		throughput = duration_ms * 1000 + duration_us;
+		throughput = throughput ? (len * 1000) / throughput : 0;
+		throughput = throughput * 1000 / 1024;
+
+		dev_info(par->info->device,
+			"Display update: %ld kB/s (%ld.%.3ld ms), fps=%ld (%ld.%.3ld ms)\n",
+			throughput, duration_ms, duration_us,
+			fps, fps_ms, fps_us);
+		par->first_update_done = true;
+	}
+}
+
+
+static void fbtft_mkdirty(struct fb_info *info, int y, int height)
+{
+	struct fbtft_par *par = info->par;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	/* special case, needed ? */
+	if (y == -1) {
+		y = 0;
+		height = info->var.yres - 1;
+	}
+
+	/* Mark display lines/area as dirty */
+	spin_lock(&par->dirty_lock);
+	if (y < par->dirty_lines_start)
+		par->dirty_lines_start = y;
+	if (y + height - 1 > par->dirty_lines_end)
+		par->dirty_lines_end = y + height - 1;
+	spin_unlock(&par->dirty_lock);
+
+	/* Schedule deferred_io to update display (no-op if already on queue)*/
+	schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+}
+
+static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+	struct fbtft_par *par = info->par;
+	unsigned dirty_lines_start, dirty_lines_end;
+	struct page *page;
+	unsigned long index;
+	unsigned y_low = 0, y_high = 0;
+	int count = 0;
+
+	spin_lock(&par->dirty_lock);
+	dirty_lines_start = par->dirty_lines_start;
+	dirty_lines_end = par->dirty_lines_end;
+	/* set display line markers as clean */
+	par->dirty_lines_start = par->info->var.yres - 1;
+	par->dirty_lines_end = 0;
+	spin_unlock(&par->dirty_lock);
+
+	/* Mark display lines as dirty */
+	list_for_each_entry(page, pagelist, lru) {
+		count++;
+		index = page->index << PAGE_SHIFT;
+		y_low = index / info->fix.line_length;
+		y_high = (index + PAGE_SIZE - 1) / info->fix.line_length;
+		fbtft_dev_dbg(DEBUG_DEFERRED_IO, par, info->device,
+			"page->index=%lu y_low=%d y_high=%d\n",
+			page->index, y_low, y_high);
+		if (y_high > info->var.yres - 1)
+			y_high = info->var.yres - 1;
+		if (y_low < dirty_lines_start)
+			dirty_lines_start = y_low;
+		if (y_high > dirty_lines_end)
+			dirty_lines_end = y_high;
+	}
+
+	par->fbtftops.update_display(info->par,
+					dirty_lines_start, dirty_lines_end);
+}
+
+
+static void fbtft_fb_fillrect(struct fb_info *info,
+			      const struct fb_fillrect *rect)
+{
+	struct fbtft_par *par = info->par;
+
+	fbtft_dev_dbg(DEBUG_FB_FILLRECT, par, info->dev,
+		"%s: dx=%d, dy=%d, width=%d, height=%d\n",
+		__func__, rect->dx, rect->dy, rect->width, rect->height);
+	sys_fillrect(info, rect);
+
+	par->fbtftops.mkdirty(info, rect->dy, rect->height);
+}
+
+static void fbtft_fb_copyarea(struct fb_info *info,
+			      const struct fb_copyarea *area)
+{
+	struct fbtft_par *par = info->par;
+
+	fbtft_dev_dbg(DEBUG_FB_COPYAREA, par, info->dev,
+		"%s: dx=%d, dy=%d, width=%d, height=%d\n",
+		__func__,  area->dx, area->dy, area->width, area->height);
+	sys_copyarea(info, area);
+
+	par->fbtftops.mkdirty(info, area->dy, area->height);
+}
+
+static void fbtft_fb_imageblit(struct fb_info *info,
+			       const struct fb_image *image)
+{
+	struct fbtft_par *par = info->par;
+
+	fbtft_dev_dbg(DEBUG_FB_IMAGEBLIT, par, info->dev,
+		"%s: dx=%d, dy=%d, width=%d, height=%d\n",
+		__func__,  image->dx, image->dy, image->width, image->height);
+	sys_imageblit(info, image);
+
+	par->fbtftops.mkdirty(info, image->dy, image->height);
+}
+
+static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf,
+			      size_t count, loff_t *ppos)
+{
+	struct fbtft_par *par = info->par;
+	ssize_t res;
+
+	fbtft_dev_dbg(DEBUG_FB_WRITE, par, info->dev,
+		"%s: count=%zd, ppos=%llu\n", __func__,  count, *ppos);
+	res = fb_sys_write(info, buf, count, ppos);
+
+	/* TODO: only mark changed area
+	   update all for now */
+	par->fbtftops.mkdirty(info, -1, 0);
+
+	return res;
+}
+
+/* from pxafb.c */
+static unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int fbtft_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *info)
+{
+	struct fbtft_par *par = info->par;
+	unsigned val;
+	int ret = 1;
+
+	fbtft_dev_dbg(DEBUG_FB_SETCOLREG, par, info->dev,
+		"%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
+		__func__, regno, red, green, blue, transp);
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno < 16) {
+			u32 *pal = info->pseudo_palette;
+
+			val  = chan_to_field(red,   &info->var.red);
+			val |= chan_to_field(green, &info->var.green);
+			val |= chan_to_field(blue,  &info->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	}
+	return ret;
+}
+
+static int fbtft_fb_blank(int blank, struct fb_info *info)
+{
+	struct fbtft_par *par = info->par;
+	int ret = -EINVAL;
+
+	fbtft_dev_dbg(DEBUG_FB_BLANK, par, info->dev, "%s(blank=%d)\n",
+		__func__, blank);
+
+	if (!par->fbtftops.blank)
+		return ret;
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		ret = par->fbtftops.blank(par, true);
+		break;
+	case FB_BLANK_UNBLANK:
+		ret = par->fbtftops.blank(par, false);
+		break;
+	}
+	return ret;
+}
+
+static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src)
+{
+	if (src->write)
+		dst->write = src->write;
+	if (src->read)
+		dst->read = src->read;
+	if (src->write_vmem)
+		dst->write_vmem = src->write_vmem;
+	if (src->write_register)
+		dst->write_register = src->write_register;
+	if (src->set_addr_win)
+		dst->set_addr_win = src->set_addr_win;
+	if (src->reset)
+		dst->reset = src->reset;
+	if (src->mkdirty)
+		dst->mkdirty = src->mkdirty;
+	if (src->update_display)
+		dst->update_display = src->update_display;
+	if (src->init_display)
+		dst->init_display = src->init_display;
+	if (src->blank)
+		dst->blank = src->blank;
+	if (src->request_gpios_match)
+		dst->request_gpios_match = src->request_gpios_match;
+	if (src->request_gpios)
+		dst->request_gpios = src->request_gpios;
+	if (src->verify_gpios)
+		dst->verify_gpios = src->verify_gpios;
+	if (src->register_backlight)
+		dst->register_backlight = src->register_backlight;
+	if (src->unregister_backlight)
+		dst->unregister_backlight = src->unregister_backlight;
+	if (src->set_var)
+		dst->set_var = src->set_var;
+	if (src->set_gamma)
+		dst->set_gamma = src->set_gamma;
+}
+
+/**
+ * fbtft_framebuffer_alloc - creates a new frame buffer info structure
+ *
+ * @display: pointer to structure describing the display
+ * @dev: pointer to the device for this fb, this can be NULL
+ *
+ * Creates a new frame buffer info structure.
+ *
+ * Also creates and populates the following structures:
+ *   info->fbops
+ *   info->fbdefio
+ *   info->pseudo_palette
+ *   par->fbtftops
+ *   par->txbuf
+ *
+ * Returns the new structure, or NULL if an error occurred.
+ *
+ */
+struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
+					struct device *dev)
+{
+	struct fb_info *info;
+	struct fbtft_par *par;
+	struct fb_ops *fbops = NULL;
+	struct fb_deferred_io *fbdefio = NULL;
+	struct fbtft_platform_data *pdata = dev->platform_data;
+	u8 *vmem = NULL;
+	void *txbuf = NULL;
+	void *buf = NULL;
+	unsigned width;
+	unsigned height;
+	int txbuflen = display->txbuflen;
+	unsigned bpp = display->bpp;
+	unsigned fps = display->fps;
+	int vmem_size, i;
+	int *init_sequence = display->init_sequence;
+	char *gamma = display->gamma;
+	unsigned long *gamma_curves = NULL;
+
+	/* sanity check */
+	if (display->gamma_num * display->gamma_len > FBTFT_GAMMA_MAX_VALUES_TOTAL) {
+		dev_err(dev,
+			"%s: FBTFT_GAMMA_MAX_VALUES_TOTAL=%d is exceeded\n",
+			__func__, FBTFT_GAMMA_MAX_VALUES_TOTAL);
+		return NULL;
+	}
+
+	/* defaults */
+	if (!fps)
+		fps = 20;
+	if (!bpp)
+		bpp = 16;
+
+	if (!pdata) {
+		dev_err(dev, "platform data is missing\n");
+		return NULL;
+	}
+
+	/* override driver values? */
+	if (pdata->fps)
+		fps = pdata->fps;
+	if (pdata->txbuflen)
+		txbuflen = pdata->txbuflen;
+	if (pdata->display.init_sequence)
+		init_sequence = pdata->display.init_sequence;
+	if (pdata->gamma)
+		gamma = pdata->gamma;
+	if (pdata->display.debug)
+		display->debug = pdata->display.debug;
+	if (pdata->display.backlight)
+		display->backlight = pdata->display.backlight;
+	if (pdata->display.width)
+		display->width = pdata->display.width;
+	if (pdata->display.height)
+		display->height = pdata->display.height;
+	if (pdata->display.buswidth)
+		display->buswidth = pdata->display.buswidth;
+	if (pdata->display.regwidth)
+		display->regwidth = pdata->display.regwidth;
+
+	display->debug |= debug;
+	fbtft_expand_debug_value(&display->debug);
+
+	switch (pdata->rotate) {
+	case 90:
+	case 270:
+		width =  display->height;
+		height = display->width;
+		break;
+	default:
+		width =  display->width;
+		height = display->height;
+	}
+
+	vmem_size = display->width * display->height * bpp / 8;
+	vmem = vzalloc(vmem_size);
+	if (!vmem)
+		goto alloc_fail;
+
+	fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL);
+	if (!fbops)
+		goto alloc_fail;
+
+	fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL);
+	if (!fbdefio)
+		goto alloc_fail;
+
+	buf = devm_kzalloc(dev, 128, GFP_KERNEL);
+	if (!buf)
+		goto alloc_fail;
+
+	if (display->gamma_num && display->gamma_len) {
+		gamma_curves = devm_kzalloc(dev, display->gamma_num * display->gamma_len * sizeof(gamma_curves[0]),
+						GFP_KERNEL);
+		if (!gamma_curves)
+			goto alloc_fail;
+	}
+
+	info = framebuffer_alloc(sizeof(struct fbtft_par), dev);
+	if (!info)
+		goto alloc_fail;
+
+	info->screen_base = (u8 __force __iomem *)vmem;
+	info->fbops = fbops;
+	info->fbdefio = fbdefio;
+
+	fbops->owner        =      dev->driver->owner;
+	fbops->fb_read      =      fb_sys_read;
+	fbops->fb_write     =      fbtft_fb_write;
+	fbops->fb_fillrect  =      fbtft_fb_fillrect;
+	fbops->fb_copyarea  =      fbtft_fb_copyarea;
+	fbops->fb_imageblit =      fbtft_fb_imageblit;
+	fbops->fb_setcolreg =      fbtft_fb_setcolreg;
+	fbops->fb_blank     =      fbtft_fb_blank;
+
+	fbdefio->delay =           HZ/fps;
+	fbdefio->deferred_io =     fbtft_deferred_io;
+	fb_deferred_io_init(info);
+
+	strncpy(info->fix.id, dev->driver->name, 16);
+	info->fix.type =           FB_TYPE_PACKED_PIXELS;
+	info->fix.visual =         FB_VISUAL_TRUECOLOR;
+	info->fix.xpanstep =	   0;
+	info->fix.ypanstep =	   0;
+	info->fix.ywrapstep =	   0;
+	info->fix.line_length =    width*bpp/8;
+	info->fix.accel =          FB_ACCEL_NONE;
+	info->fix.smem_len =       vmem_size;
+
+	info->var.rotate =         pdata->rotate;
+	info->var.xres =           width;
+	info->var.yres =           height;
+	info->var.xres_virtual =   info->var.xres;
+	info->var.yres_virtual =   info->var.yres;
+	info->var.bits_per_pixel = bpp;
+	info->var.nonstd =         1;
+
+	/* RGB565 */
+	info->var.red.offset =     11;
+	info->var.red.length =     5;
+	info->var.green.offset =   5;
+	info->var.green.length =   6;
+	info->var.blue.offset =    0;
+	info->var.blue.length =    5;
+	info->var.transp.offset =  0;
+	info->var.transp.length =  0;
+
+	info->flags =              FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
+
+	par = info->par;
+	par->info = info;
+	par->pdata = dev->platform_data;
+	par->debug = display->debug;
+	par->buf = buf;
+	spin_lock_init(&par->dirty_lock);
+	par->bgr = pdata->bgr;
+	par->startbyte = pdata->startbyte;
+	par->init_sequence = init_sequence;
+	par->gamma.curves = gamma_curves;
+	par->gamma.num_curves = display->gamma_num;
+	par->gamma.num_values = display->gamma_len;
+	mutex_init(&par->gamma.lock);
+	info->pseudo_palette = par->pseudo_palette;
+
+	if (par->gamma.curves && gamma) {
+		if (fbtft_gamma_parse_str(par,
+			par->gamma.curves, gamma, strlen(gamma)))
+			goto alloc_fail;
+	}
+
+	/* Transmit buffer */
+	if (txbuflen == -1)
+		txbuflen = vmem_size + 2; /* add in case startbyte is used */
+
+#ifdef __LITTLE_ENDIAN
+	if ((!txbuflen) && (bpp > 8))
+		txbuflen = PAGE_SIZE; /* need buffer for byteswapping */
+#endif
+
+	if (txbuflen > 0) {
+		if (dma) {
+			dev->coherent_dma_mask = ~0;
+			txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA);
+		} else {
+			txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL);
+		}
+		if (!txbuf)
+			goto alloc_fail;
+		par->txbuf.buf = txbuf;
+		par->txbuf.len = txbuflen;
+	}
+
+	/* Initialize gpios to disabled */
+	par->gpio.reset = -1;
+	par->gpio.dc = -1;
+	par->gpio.rd = -1;
+	par->gpio.wr = -1;
+	par->gpio.cs = -1;
+	par->gpio.latch = -1;
+	for (i = 0; i < 16; i++) {
+		par->gpio.db[i] = -1;
+		par->gpio.led[i] = -1;
+		par->gpio.aux[i] = -1;
+	}
+
+	/* default fbtft operations */
+	par->fbtftops.write = fbtft_write_spi;
+	par->fbtftops.read = fbtft_read_spi;
+	par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+	par->fbtftops.write_register = fbtft_write_reg8_bus8;
+	par->fbtftops.set_addr_win = fbtft_set_addr_win;
+	par->fbtftops.reset = fbtft_reset;
+	par->fbtftops.mkdirty = fbtft_mkdirty;
+	par->fbtftops.update_display = fbtft_update_display;
+	par->fbtftops.request_gpios = fbtft_request_gpios;
+	if (display->backlight)
+		par->fbtftops.register_backlight = fbtft_register_backlight;
+
+	/* use driver provided functions */
+	fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops);
+
+	return info;
+
+alloc_fail:
+	vfree(vmem);
+
+	return NULL;
+}
+EXPORT_SYMBOL(fbtft_framebuffer_alloc);
+
+/**
+ * fbtft_framebuffer_release - frees up all memory used by the framebuffer
+ *
+ * @info: frame buffer info structure
+ *
+ */
+void fbtft_framebuffer_release(struct fb_info *info)
+{
+	fb_deferred_io_cleanup(info);
+	vfree(info->screen_base);
+	framebuffer_release(info);
+}
+EXPORT_SYMBOL(fbtft_framebuffer_release);
+
+/**
+ *	fbtft_register_framebuffer - registers a tft frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *  Sets SPI driverdata if needed
+ *  Requests needed gpios.
+ *  Initializes display
+ *  Updates display.
+ *	Registers a frame buffer device @fb_info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+int fbtft_register_framebuffer(struct fb_info *fb_info)
+{
+	int ret;
+	char text1[50] = "";
+	char text2[50] = "";
+	struct fbtft_par *par = fb_info->par;
+	struct spi_device *spi = par->spi;
+
+	/* sanity checks */
+	if (!par->fbtftops.init_display) {
+		dev_err(fb_info->device, "missing fbtftops.init_display()\n");
+		return -EINVAL;
+	}
+
+	if (spi)
+		spi_set_drvdata(spi, fb_info);
+	if (par->pdev)
+		platform_set_drvdata(par->pdev, fb_info);
+
+	ret = par->fbtftops.request_gpios(par);
+	if (ret < 0)
+		goto reg_fail;
+
+	if (par->fbtftops.verify_gpios) {
+		ret = par->fbtftops.verify_gpios(par);
+		if (ret < 0)
+			goto reg_fail;
+	}
+
+	ret = par->fbtftops.init_display(par);
+	if (ret < 0)
+		goto reg_fail;
+	if (par->fbtftops.set_var) {
+		ret = par->fbtftops.set_var(par);
+		if (ret < 0)
+			goto reg_fail;
+	}
+
+	/* update the entire display */
+	par->fbtftops.update_display(par, 0, par->info->var.yres - 1);
+
+	if (par->fbtftops.set_gamma && par->gamma.curves) {
+		ret = par->fbtftops.set_gamma(par, par->gamma.curves);
+		if (ret)
+			goto reg_fail;
+	}
+
+	if (par->fbtftops.register_backlight)
+		par->fbtftops.register_backlight(par);
+
+	ret = register_framebuffer(fb_info);
+	if (ret < 0)
+		goto reg_fail;
+
+	fbtft_sysfs_init(par);
+
+	if (par->txbuf.buf)
+		sprintf(text1, ", %d KiB %sbuffer memory",
+			par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : "");
+	if (spi)
+		sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num,
+				spi->chip_select, spi->max_speed_hz/1000000);
+	dev_info(fb_info->dev,
+		"%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
+		fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
+		fb_info->fix.smem_len >> 10, text1,
+		HZ/fb_info->fbdefio->delay, text2);
+
+#ifdef CONFIG_FB_BACKLIGHT
+	/* Turn on backlight if available */
+	if (fb_info->bl_dev) {
+		fb_info->bl_dev->props.power = FB_BLANK_UNBLANK;
+		fb_info->bl_dev->ops->update_status(fb_info->bl_dev);
+	}
+#endif
+
+	return 0;
+
+reg_fail:
+	if (par->fbtftops.unregister_backlight)
+		par->fbtftops.unregister_backlight(par);
+	if (spi)
+		spi_set_drvdata(spi, NULL);
+	if (par->pdev)
+		platform_set_drvdata(par->pdev, NULL);
+
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_register_framebuffer);
+
+/**
+ *	fbtft_unregister_framebuffer - releases a tft frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *  Frees SPI driverdata if needed
+ *  Frees gpios.
+ *	Unregisters frame buffer device.
+ *
+ */
+int fbtft_unregister_framebuffer(struct fb_info *fb_info)
+{
+	struct fbtft_par *par = fb_info->par;
+	struct spi_device *spi = par->spi;
+	int ret;
+
+	if (spi)
+		spi_set_drvdata(spi, NULL);
+	if (par->pdev)
+		platform_set_drvdata(par->pdev, NULL);
+	if (par->fbtftops.unregister_backlight)
+		par->fbtftops.unregister_backlight(par);
+	fbtft_sysfs_exit(par);
+	ret = unregister_framebuffer(fb_info);
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_unregister_framebuffer);
+
+#ifdef CONFIG_OF
+/**
+ * fbtft_init_display_dt() - Device Tree init_display() function
+ * @par: Driver data
+ *
+ * Return: 0 if successful, negative if error
+ */
+static int fbtft_init_display_dt(struct fbtft_par *par)
+{
+	struct device_node *node = par->info->device->of_node;
+	struct property *prop;
+	const __be32 *p;
+	u32 val;
+	int buf[64], i, j;
+	char msg[128];
+	char str[16];
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	if (!node)
+		return -EINVAL;
+
+	prop = of_find_property(node, "init", NULL);
+	p = of_prop_next_u32(prop, NULL, &val);
+	if (!p)
+		return -EINVAL;
+	while (p) {
+		if (val & FBTFT_OF_INIT_CMD) {
+			val &= 0xFFFF;
+			i = 0;
+			while (p && !(val & 0xFFFF0000)) {
+				if (i > 63) {
+					dev_err(par->info->device,
+					"%s: Maximum register values exceeded\n",
+					__func__);
+					return -EINVAL;
+				}
+				buf[i++] = val;
+				p = of_prop_next_u32(prop, p, &val);
+			}
+			/* make debug message */
+			msg[0] = '\0';
+			for (j = 0; j < i; j++) {
+				snprintf(str, 128, " %02X", buf[j]);
+				strcat(msg, str);
+			}
+			fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+				"init: write_register:%s\n", msg);
+
+			par->fbtftops.write_register(par, i,
+				buf[0], buf[1], buf[2], buf[3],
+				buf[4], buf[5], buf[6], buf[7],
+				buf[8], buf[9], buf[10], buf[11],
+				buf[12], buf[13], buf[14], buf[15],
+				buf[16], buf[17], buf[18], buf[19],
+				buf[20], buf[21], buf[22], buf[23],
+				buf[24], buf[25], buf[26], buf[27],
+				buf[28], buf[29], buf[30], buf[31],
+				buf[32], buf[33], buf[34], buf[35],
+				buf[36], buf[37], buf[38], buf[39],
+				buf[40], buf[41], buf[42], buf[43],
+				buf[44], buf[45], buf[46], buf[47],
+				buf[48], buf[49], buf[50], buf[51],
+				buf[52], buf[53], buf[54], buf[55],
+				buf[56], buf[57], buf[58], buf[59],
+				buf[60], buf[61], buf[62], buf[63]);
+		} else if (val & FBTFT_OF_INIT_DELAY) {
+			fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+				"init: msleep(%u)\n", val & 0xFFFF);
+			msleep(val & 0xFFFF);
+			p = of_prop_next_u32(prop, p, &val);
+		} else {
+			dev_err(par->info->device, "illegal init value 0x%X\n",
+									val);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+#endif
+
+/**
+ * fbtft_init_display() - Generic init_display() function
+ * @par: Driver data
+ *
+ * Uses par->init_sequence to do the initialization
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_init_display(struct fbtft_par *par)
+{
+	int buf[64];
+	char msg[128];
+	char str[16];
+	int i = 0;
+	int j;
+
+	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+	/* sanity check */
+	if (!par->init_sequence) {
+		dev_err(par->info->device,
+			"error: init_sequence is not set\n");
+		return -EINVAL;
+	}
+
+	/* make sure stop marker exists */
+	for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++)
+		if (par->init_sequence[i] == -3)
+			break;
+	if (i == FBTFT_MAX_INIT_SEQUENCE) {
+		dev_err(par->info->device,
+			"missing stop marker at end of init sequence\n");
+		return -EINVAL;
+	}
+
+	par->fbtftops.reset(par);
+	if (par->gpio.cs != -1)
+		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
+
+	i = 0;
+	while (i < FBTFT_MAX_INIT_SEQUENCE) {
+		if (par->init_sequence[i] == -3) {
+			/* done */
+			return 0;
+		}
+		if (par->init_sequence[i] >= 0) {
+			dev_err(par->info->device,
+				"missing delimiter at position %d\n", i);
+			return -EINVAL;
+		}
+		if (par->init_sequence[i+1] < 0) {
+			dev_err(par->info->device,
+				"missing value after delimiter %d at position %d\n",
+				par->init_sequence[i], i);
+			return -EINVAL;
+		}
+		switch (par->init_sequence[i]) {
+		case -1:
+			i++;
+			/* make debug message */
+			strcpy(msg, "");
+			j = i + 1;
+			while (par->init_sequence[j] >= 0) {
+				sprintf(str, "0x%02X ", par->init_sequence[j]);
+				strcat(msg, str);
+				j++;
+			}
+			fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+				"init: write(0x%02X) %s\n",
+				par->init_sequence[i], msg);
+
+			/* Write */
+			j = 0;
+			while (par->init_sequence[i] >= 0) {
+				if (j > 63) {
+					dev_err(par->info->device,
+					"%s: Maximum register values exceeded\n",
+					__func__);
+					return -EINVAL;
+				}
+				buf[j++] = par->init_sequence[i++];
+			}
+			par->fbtftops.write_register(par, j,
+				buf[0], buf[1], buf[2], buf[3],
+				buf[4], buf[5], buf[6], buf[7],
+				buf[8], buf[9], buf[10], buf[11],
+				buf[12], buf[13], buf[14], buf[15],
+				buf[16], buf[17], buf[18], buf[19],
+				buf[20], buf[21], buf[22], buf[23],
+				buf[24], buf[25], buf[26], buf[27],
+				buf[28], buf[29], buf[30], buf[31],
+				buf[32], buf[33], buf[34], buf[35],
+				buf[36], buf[37], buf[38], buf[39],
+				buf[40], buf[41], buf[42], buf[43],
+				buf[44], buf[45], buf[46], buf[47],
+				buf[48], buf[49], buf[50], buf[51],
+				buf[52], buf[53], buf[54], buf[55],
+				buf[56], buf[57], buf[58], buf[59],
+				buf[60], buf[61], buf[62], buf[63]);
+			break;
+		case -2:
+			i++;
+			fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+				"init: mdelay(%d)\n", par->init_sequence[i]);
+			mdelay(par->init_sequence[i++]);
+			break;
+		default:
+			dev_err(par->info->device,
+				"unknown delimiter %d at position %d\n",
+				par->init_sequence[i], i);
+			return -EINVAL;
+		}
+	}
+
+	dev_err(par->info->device,
+		"%s: something is wrong. Shouldn't get here.\n", __func__);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(fbtft_init_display);
+
+/**
+ * fbtft_verify_gpios() - Generic verify_gpios() function
+ * @par: Driver data
+ *
+ * Uses @spi, @pdev and @buswidth to determine which GPIOs is needed
+ *
+ * Return: 0 if successful, negative if error
+ */
+static int fbtft_verify_gpios(struct fbtft_par *par)
+{
+	struct fbtft_platform_data *pdata;
+	int i;
+
+	fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+	pdata = par->info->device->platform_data;
+	if (pdata->display.buswidth != 9 && par->startbyte == 0 && \
+							par->gpio.dc < 0) {
+		dev_err(par->info->device,
+			"Missing info about 'dc' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+
+	if (!par->pdev)
+		return 0;
+
+	if (par->gpio.wr < 0) {
+		dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < pdata->display.buswidth; i++) {
+		if (par->gpio.db[i] < 0) {
+			dev_err(par->info->device,
+				"Missing 'db%02d' gpio. Aborting.\n", i);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+/* returns 0 if the property is not present */
+static u32 fbtft_of_value(struct device_node *node, const char *propname)
+{
+	int ret;
+	u32 val = 0;
+
+	ret = of_property_read_u32(node, propname, &val);
+	if (ret == 0)
+		pr_info("%s: %s = %u\n", __func__, propname, val);
+
+	return val;
+}
+
+static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
+{
+	struct device_node *node = dev->of_node;
+	struct fbtft_platform_data *pdata;
+
+	if (!node) {
+		dev_err(dev, "Missing platform data or DT\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->display.width = fbtft_of_value(node, "width");
+	pdata->display.height = fbtft_of_value(node, "height");
+	pdata->display.regwidth = fbtft_of_value(node, "regwidth");
+	pdata->display.buswidth = fbtft_of_value(node, "buswidth");
+	pdata->display.backlight = fbtft_of_value(node, "backlight");
+	pdata->display.bpp = fbtft_of_value(node, "bpp");
+	pdata->display.debug = fbtft_of_value(node, "debug");
+	pdata->rotate = fbtft_of_value(node, "rotate");
+	pdata->bgr = of_property_read_bool(node, "bgr");
+	pdata->fps = fbtft_of_value(node, "fps");
+	pdata->txbuflen = fbtft_of_value(node, "txbuflen");
+	pdata->startbyte = fbtft_of_value(node, "startbyte");
+	of_property_read_string(node, "gamma", (const char **)&pdata->gamma);
+
+	if (of_find_property(node, "led-gpios", NULL))
+		pdata->display.backlight = 1;
+	if (of_find_property(node, "init", NULL))
+		pdata->display.fbtftops.init_display = fbtft_init_display_dt;
+	pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt;
+
+	return pdata;
+}
+#else
+static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
+{
+	dev_err(dev, "Missing platform data\n");
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
+/**
+ * fbtft_probe_common() - Generic device probe() helper function
+ * @display: Display properties
+ * @sdev: SPI device
+ * @pdev: Platform device
+ *
+ * Allocates, initializes and registers a framebuffer
+ *
+ * Either @sdev or @pdev should be NULL
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_probe_common(struct fbtft_display *display,
+			struct spi_device *sdev, struct platform_device *pdev)
+{
+	struct device *dev;
+	struct fb_info *info;
+	struct fbtft_par *par;
+	struct fbtft_platform_data *pdata;
+	int ret;
+
+	if (sdev)
+		dev = &sdev->dev;
+	else
+		dev = &pdev->dev;
+
+	if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS))
+		dev_info(dev, "%s()\n", __func__);
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		pdata = fbtft_probe_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		dev->platform_data = pdata;
+	}
+
+	info = fbtft_framebuffer_alloc(display, dev);
+	if (!info)
+		return -ENOMEM;
+
+	par = info->par;
+	par->spi = sdev;
+	par->pdev = pdev;
+
+	if (display->buswidth == 0) {
+		dev_err(dev, "buswidth is not set\n");
+		return -EINVAL;
+	}
+
+	/* write register functions */
+	if (display->regwidth == 8 && display->buswidth == 8) {
+		par->fbtftops.write_register = fbtft_write_reg8_bus8;
+	} else
+	if (display->regwidth == 8 && display->buswidth == 9 && par->spi) {
+		par->fbtftops.write_register = fbtft_write_reg8_bus9;
+	} else if (display->regwidth == 16 && display->buswidth == 8) {
+		par->fbtftops.write_register = fbtft_write_reg16_bus8;
+	} else if (display->regwidth == 16 && display->buswidth == 16) {
+		par->fbtftops.write_register = fbtft_write_reg16_bus16;
+	} else {
+		dev_warn(dev,
+			"no default functions for regwidth=%d and buswidth=%d\n",
+			display->regwidth, display->buswidth);
+	}
+
+	/* write_vmem() functions */
+	if (display->buswidth == 8)
+		par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+	else if (display->buswidth == 9)
+		par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
+	else if (display->buswidth == 16)
+		par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;
+
+	/* GPIO write() functions */
+	if (par->pdev) {
+		if (display->buswidth == 8)
+			par->fbtftops.write = fbtft_write_gpio8_wr;
+		else if (display->buswidth == 16)
+			par->fbtftops.write = fbtft_write_gpio16_wr;
+	}
+
+	/* 9-bit SPI setup */
+	if (par->spi && display->buswidth == 9) {
+		par->spi->bits_per_word = 9;
+		ret = par->spi->master->setup(par->spi);
+		if (ret) {
+			dev_warn(&par->spi->dev,
+				"9-bit SPI not available, emulating using 8-bit.\n");
+			par->spi->bits_per_word = 8;
+			ret = par->spi->master->setup(par->spi);
+			if (ret)
+				goto out_release;
+			/* allocate buffer with room for dc bits */
+			par->extra = devm_kzalloc(par->info->device,
+				par->txbuf.len + (par->txbuf.len / 8) + 8,
+				GFP_KERNEL);
+			if (!par->extra) {
+				ret = -ENOMEM;
+				goto out_release;
+			}
+			par->fbtftops.write = fbtft_write_spi_emulate_9;
+		}
+	}
+
+	if (!par->fbtftops.verify_gpios)
+		par->fbtftops.verify_gpios = fbtft_verify_gpios;
+
+	/* make sure we still use the driver provided functions */
+	fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops);
+
+	/* use init_sequence if provided */
+	if (par->init_sequence)
+		par->fbtftops.init_display = fbtft_init_display;
+
+	/* use platform_data provided functions above all */
+	fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops);
+
+	ret = fbtft_register_framebuffer(info);
+	if (ret < 0)
+		goto out_release;
+
+	return 0;
+
+out_release:
+	fbtft_framebuffer_release(info);
+
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_probe_common);
+
+/**
+ * fbtft_remove_common() - Generic device remove() helper function
+ * @dev: Device
+ * @info: Framebuffer
+ *
+ * Unregisters and releases the framebuffer
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_remove_common(struct device *dev, struct fb_info *info)
+{
+	struct fbtft_par *par;
+
+	if (!info)
+		return -EINVAL;
+	par = info->par;
+	if (par)
+		fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par,
+			"%s()\n", __func__);
+	fbtft_unregister_framebuffer(info);
+	fbtft_framebuffer_release(info);
+
+	return 0;
+}
+EXPORT_SYMBOL(fbtft_remove_common);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
new file mode 100644
index 0000000..32155a7
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -0,0 +1,239 @@
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include "fbtft.h"
+
+int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+	struct spi_transfer t = {
+		.tx_buf = buf,
+		.len = len,
+	};
+	struct spi_message m;
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	if (!par->spi) {
+		dev_err(par->info->device,
+			"%s: par->spi is unexpectedly NULL\n", __func__);
+		return -1;
+	}
+
+	spi_message_init(&m);
+	if (par->txbuf.dma && buf == par->txbuf.buf) {
+		t.tx_dma = par->txbuf.dma;
+		m.is_dma_mapped = 1;
+	}
+	spi_message_add_tail(&t, &m);
+	return spi_sync(par->spi, &m);
+}
+EXPORT_SYMBOL(fbtft_write_spi);
+
+/**
+ * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit
+ * @par: Driver data
+ * @buf: Buffer to write
+ * @len: Length of buffer (must be divisible by 8)
+ *
+ * When 9-bit SPI is not available, this function can be used to emulate that.
+ * par->extra must hold a transformation buffer used for transfer.
+ */
+int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)
+{
+	u16 *src = buf;
+	u8 *dst = par->extra;
+	size_t size = len / 2;
+	size_t added = 0;
+	int bits, i, j;
+	u64 val, dc, tmp;
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	if (!par->extra) {
+		dev_err(par->info->device, "%s: error: par->extra is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+	if ((len % 8) != 0) {
+		dev_err(par->info->device,
+			"%s: error: len=%d must be divisible by 8\n",
+			__func__, len);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i += 8) {
+		tmp = 0;
+		bits = 63;
+		for (j = 0; j < 7; j++) {
+			dc = (*src & 0x0100) ? 1 : 0;
+			val = *src & 0x00FF;
+			tmp |= dc << bits;
+			bits -= 8;
+			tmp |= val << bits--;
+			src++;
+		}
+		tmp |= ((*src & 0x0100) ? 1 : 0);
+		*(u64 *)dst = cpu_to_be64(tmp);
+		dst += 8;
+		*dst++ = (u8)(*src++ & 0x00FF);
+		added++;
+	}
+
+	return spi_write(par->spi, par->extra, size + added);
+}
+EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
+
+int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+	int ret;
+	u8 txbuf[32] = { 0, };
+	struct spi_transfer	t = {
+			.speed_hz = 2000000,
+			.rx_buf		= buf,
+			.len		= len,
+		};
+	struct spi_message	m;
+
+	if (!par->spi) {
+		dev_err(par->info->device,
+			"%s: par->spi is unexpectedly NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	if (par->startbyte) {
+		if (len > 32) {
+			dev_err(par->info->device,
+				"%s: len=%d can't be larger than 32 when using 'startbyte'\n",
+				__func__, len);
+			return -EINVAL;
+		}
+		txbuf[0] = par->startbyte | 0x3;
+		t.tx_buf = txbuf;
+		fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,
+			txbuf, len, "%s(len=%d) txbuf => ", __func__, len);
+	}
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+	ret = spi_sync(par->spi, &m);
+	fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
+		"%s(len=%d) buf <= ", __func__, len);
+
+	return ret;
+}
+EXPORT_SYMBOL(fbtft_read_spi);
+
+/*
+ * Optimized use of gpiolib is twice as fast as no optimization
+ * only one driver can use the optimized version at a time
+ */
+int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
+{
+	u8 data;
+	int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+	static u8 prev_data;
+#endif
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	while (len--) {
+		data = *(u8 *) buf;
+
+		/* Start writing by pulling down /WR */
+		gpio_set_value(par->gpio.wr, 0);
+
+		/* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		if (data == prev_data) {
+			gpio_set_value(par->gpio.wr, 0); /* used as delay */
+		} else {
+			for (i = 0; i < 8; i++) {
+				if ((data & 1) != (prev_data & 1))
+					gpio_set_value(par->gpio.db[i],
+								(data & 1));
+				data >>= 1;
+				prev_data >>= 1;
+			}
+		}
+#else
+		for (i = 0; i < 8; i++) {
+			gpio_set_value(par->gpio.db[i], (data & 1));
+			data >>= 1;
+		}
+#endif
+
+		/* Pullup /WR */
+		gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		prev_data = *(u8 *) buf;
+#endif
+		buf++;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(fbtft_write_gpio8_wr);
+
+int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
+{
+	u16 data;
+	int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+	static u16 prev_data;
+#endif
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	while (len) {
+		data = *(u16 *) buf;
+
+		/* Start writing by pulling down /WR */
+		gpio_set_value(par->gpio.wr, 0);
+
+		/* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		if (data == prev_data) {
+			gpio_set_value(par->gpio.wr, 0); /* used as delay */
+		} else {
+			for (i = 0; i < 16; i++) {
+				if ((data & 1) != (prev_data & 1))
+					gpio_set_value(par->gpio.db[i],
+								(data & 1));
+				data >>= 1;
+				prev_data >>= 1;
+			}
+		}
+#else
+		for (i = 0; i < 16; i++) {
+			gpio_set_value(par->gpio.db[i], (data & 1));
+			data >>= 1;
+		}
+#endif
+
+		/* Pullup /WR */
+		gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		prev_data = *(u16 *) buf;
+#endif
+		buf += 2;
+		len -= 2;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(fbtft_write_gpio16_wr);
+
+int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
+{
+	dev_err(par->info->device, "%s: function not implemented\n", __func__);
+	return -1;
+}
+EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
new file mode 100644
index 0000000..45f8de3
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-sysfs.c
@@ -0,0 +1,222 @@
+#include "fbtft.h"
+
+
+static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base)
+{
+	char *p_val;
+	int ret;
+
+	if (!str_p || !(*str_p))
+		return -EINVAL;
+
+	p_val = strsep(str_p, sep);
+
+	if (!p_val)
+		return -EINVAL;
+
+	ret = kstrtoul(p_val, base, val);
+	if (ret)
+		return -EINVAL;
+
+	return 0;
+}
+
+int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+						const char *str, int size)
+{
+	char *str_p, *curve_p = NULL;
+	char *tmp;
+	unsigned long val = 0;
+	int ret = 0;
+	int curve_counter, value_counter;
+
+	fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__);
+
+	if (!str || !curves)
+		return -EINVAL;
+
+	fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str);
+
+	tmp = kmalloc(size+1, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+	memcpy(tmp, str, size+1);
+
+	/* replace optional separators */
+	str_p = tmp;
+	while (*str_p) {
+		if (*str_p == ',')
+			*str_p = ' ';
+		if (*str_p == ';')
+			*str_p = '\n';
+		str_p++;
+	}
+
+	str_p = strim(tmp);
+
+	curve_counter = 0;
+	while (str_p) {
+		if (curve_counter == par->gamma.num_curves) {
+			dev_err(par->info->device, "Gamma: Too many curves\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		curve_p = strsep(&str_p, "\n");
+		value_counter = 0;
+		while (curve_p) {
+			if (value_counter == par->gamma.num_values) {
+				dev_err(par->info->device,
+					"Gamma: Too many values\n");
+				ret = -EINVAL;
+				goto out;
+			}
+			ret = get_next_ulong(&curve_p, &val, " ", 16);
+			if (ret)
+				goto out;
+			curves[curve_counter * par->gamma.num_values + value_counter] = val;
+			value_counter++;
+		}
+		if (value_counter != par->gamma.num_values) {
+			dev_err(par->info->device, "Gamma: Too few values\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		curve_counter++;
+	}
+	if (curve_counter != par->gamma.num_curves) {
+		dev_err(par->info->device, "Gamma: Too few curves\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	kfree(tmp);
+	return ret;
+}
+
+static ssize_t
+sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf)
+{
+	ssize_t len = 0;
+	unsigned int i, j;
+
+	mutex_lock(&par->gamma.lock);
+	for (i = 0; i < par->gamma.num_curves; i++) {
+		for (j = 0; j < par->gamma.num_values; j++)
+			len += scnprintf(&buf[len], PAGE_SIZE,
+				"%04lx ", curves[i*par->gamma.num_values + j]);
+		buf[len-1] = '\n';
+	}
+	mutex_unlock(&par->gamma.lock);
+
+	return len;
+}
+
+static ssize_t store_gamma_curve(struct device *device,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct fb_info *fb_info = dev_get_drvdata(device);
+	struct fbtft_par *par = fb_info->par;
+	unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL];
+	int ret;
+
+	ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count);
+	if (ret)
+		return ret;
+
+	ret = par->fbtftops.set_gamma(par, tmp_curves);
+	if (ret)
+		return ret;
+
+	mutex_lock(&par->gamma.lock);
+	memcpy(par->gamma.curves, tmp_curves,
+		par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0]));
+	mutex_unlock(&par->gamma.lock);
+
+	return count;
+}
+
+static ssize_t show_gamma_curve(struct device *device,
+				struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fb_info = dev_get_drvdata(device);
+	struct fbtft_par *par = fb_info->par;
+
+	return sprintf_gamma(par, par->gamma.curves, buf);
+}
+
+static struct device_attribute gamma_device_attrs[] = {
+	__ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve),
+};
+
+
+void fbtft_expand_debug_value(unsigned long *debug)
+{
+	switch (*debug & 0b111) {
+	case 1:
+		*debug |= DEBUG_LEVEL_1;
+		break;
+	case 2:
+		*debug |= DEBUG_LEVEL_2;
+		break;
+	case 3:
+		*debug |= DEBUG_LEVEL_3;
+		break;
+	case 4:
+		*debug |= DEBUG_LEVEL_4;
+		break;
+	case 5:
+		*debug |= DEBUG_LEVEL_5;
+		break;
+	case 6:
+		*debug |= DEBUG_LEVEL_6;
+		break;
+	case 7:
+		*debug = 0xFFFFFFFF;
+		break;
+	}
+}
+
+static ssize_t store_debug(struct device *device,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct fb_info *fb_info = dev_get_drvdata(device);
+	struct fbtft_par *par = fb_info->par;
+	int ret;
+
+	ret = kstrtoul(buf, 10, &par->debug);
+	if (ret)
+		return ret;
+	fbtft_expand_debug_value(&par->debug);
+
+	return count;
+}
+
+static ssize_t show_debug(struct device *device,
+				struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fb_info = dev_get_drvdata(device);
+	struct fbtft_par *par = fb_info->par;
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug);
+}
+
+static struct device_attribute debug_device_attr = \
+	__ATTR(debug, 0660, show_debug, store_debug);
+
+
+void fbtft_sysfs_init(struct fbtft_par *par)
+{
+	device_create_file(par->info->dev, &debug_device_attr);
+	if (par->gamma.curves && par->fbtftops.set_gamma)
+		device_create_file(par->info->dev, &gamma_device_attrs[0]);
+}
+
+void fbtft_sysfs_exit(struct fbtft_par *par)
+{
+	device_remove_file(par->info->dev, &debug_device_attr);
+	if (par->gamma.curves && par->fbtftops.set_gamma)
+		device_remove_file(par->info->dev, &gamma_device_attrs[0]);
+}
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
new file mode 100644
index 0000000..0dbf3f9
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft.h
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_FBTFT_H
+#define __LINUX_FBTFT_H
+
+#include <linux/fb.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+
+
+#define FBTFT_NOP		0x00
+#define FBTFT_SWRESET	0x01
+#define FBTFT_RDDID		0x04
+#define FBTFT_RDDST		0x09
+#define FBTFT_CASET		0x2A
+#define FBTFT_RASET		0x2B
+#define FBTFT_RAMWR		0x2C
+
+#define FBTFT_ONBOARD_BACKLIGHT 2
+
+#define FBTFT_GPIO_NO_MATCH		0xFFFF
+#define FBTFT_GPIO_NAME_SIZE	32
+#define FBTFT_MAX_INIT_SEQUENCE      512
+#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128
+
+#define FBTFT_OF_INIT_CMD	BIT(24)
+#define FBTFT_OF_INIT_DELAY	BIT(25)
+
+/**
+ * struct fbtft_gpio - Structure that holds one pinname to gpio mapping
+ * @name: pinname (reset, dc, etc.)
+ * @gpio: GPIO number
+ *
+ */
+struct fbtft_gpio {
+	char name[FBTFT_GPIO_NAME_SIZE];
+	unsigned gpio;
+};
+
+struct fbtft_par;
+
+/**
+ * struct fbtft_ops - FBTFT operations structure
+ * @write: Writes to interface bus
+ * @read: Reads from interface bus
+ * @write_vmem: Writes video memory to display
+ * @write_reg: Writes to controller register
+ * @set_addr_win: Set the GRAM update window
+ * @reset: Reset the LCD controller
+ * @mkdirty: Marks display lines for update
+ * @update_display: Updates the display
+ * @init_display: Initializes the display
+ * @blank: Blank the display (optional)
+ * @request_gpios_match: Do pinname to gpio matching
+ * @request_gpios: Request gpios from the kernel
+ * @free_gpios: Free previously requested gpios
+ * @verify_gpios: Verify that necessary gpios is present (optional)
+ * @register_backlight: Used to register backlight device (optional)
+ * @unregister_backlight: Unregister backlight device (optional)
+ * @set_var: Configure LCD with values from variables like @rotate and @bgr
+ *           (optional)
+ * @set_gamma: Set Gamma curve (optional)
+ *
+ * Most of these operations have default functions assigned to them in
+ *     fbtft_framebuffer_alloc()
+ */
+struct fbtft_ops {
+	int (*write)(struct fbtft_par *par, void *buf, size_t len);
+	int (*read)(struct fbtft_par *par, void *buf, size_t len);
+	int (*write_vmem)(struct fbtft_par *par, size_t offset, size_t len);
+	void (*write_register)(struct fbtft_par *par, int len, ...);
+
+	void (*set_addr_win)(struct fbtft_par *par,
+		int xs, int ys, int xe, int ye);
+	void (*reset)(struct fbtft_par *par);
+	void (*mkdirty)(struct fb_info *info, int from, int to);
+	void (*update_display)(struct fbtft_par *par,
+				unsigned start_line, unsigned end_line);
+	int (*init_display)(struct fbtft_par *par);
+	int (*blank)(struct fbtft_par *par, bool on);
+
+	unsigned long (*request_gpios_match)(struct fbtft_par *par,
+		const struct fbtft_gpio *gpio);
+	int (*request_gpios)(struct fbtft_par *par);
+	int (*verify_gpios)(struct fbtft_par *par);
+
+	void (*register_backlight)(struct fbtft_par *par);
+	void (*unregister_backlight)(struct fbtft_par *par);
+
+	int (*set_var)(struct fbtft_par *par);
+	int (*set_gamma)(struct fbtft_par *par, unsigned long *curves);
+};
+
+/**
+ * struct fbtft_display - Describes the display properties
+ * @width: Width of display in pixels
+ * @height: Height of display in pixels
+ * @regwidth: LCD Controller Register width in bits
+ * @buswidth: Display interface bus width in bits
+ * @backlight: Backlight type.
+ * @fbtftops: FBTFT operations provided by driver or device (platform_data)
+ * @bpp: Bits per pixel
+ * @fps: Frames per second
+ * @txbuflen: Size of transmit buffer
+ * @init_sequence: Pointer to LCD initialization array
+ * @gamma: String representation of Gamma curve(s)
+ * @gamma_num: Number of Gamma curves
+ * @gamma_len: Number of values per Gamma curve
+ * @debug: Initial debug value
+ *
+ * This structure is not stored by FBTFT except for init_sequence.
+ */
+struct fbtft_display {
+	unsigned width;
+	unsigned height;
+	unsigned regwidth;
+	unsigned buswidth;
+	unsigned backlight;
+	struct fbtft_ops fbtftops;
+	unsigned bpp;
+	unsigned fps;
+	int txbuflen;
+	int *init_sequence;
+	char *gamma;
+	int gamma_num;
+	int gamma_len;
+	unsigned long debug;
+};
+
+/**
+ * struct fbtft_platform_data - Passes display specific data to the driver
+ * @display: Display properties
+ * @gpios: Pointer to an array of piname to gpio mappings
+ * @rotate: Display rotation angle
+ * @bgr: LCD Controller BGR bit
+ * @fps: Frames per second (this will go away, use @fps in @fbtft_display)
+ * @txbuflen: Size of transmit buffer
+ * @startbyte: When set, enables use of Startbyte in transfers
+ * @gamma: String representation of Gamma curve(s)
+ * @extra: A way to pass extra info
+ */
+struct fbtft_platform_data {
+	struct fbtft_display display;
+	const struct fbtft_gpio *gpios;
+	unsigned rotate;
+	bool bgr;
+	unsigned fps;
+	int txbuflen;
+	u8 startbyte;
+	char *gamma;
+	void *extra;
+};
+
+/**
+ * struct fbtft_par - Main FBTFT data structure
+ *
+ * This structure holds all relevant data to operate the display
+ *
+ * See sourcefile for documentation since nested structs is not
+ * supported by kernel-doc.
+ *
+ */
+/* @spi: Set if it is a SPI device
+ * @pdev: Set if it is a platform device
+ * @info: Pointer to framebuffer fb_info structure
+ * @pdata: Pointer to platform data
+ * @ssbuf: Not used
+ * @pseudo_palette: Used by fb_set_colreg()
+ * @txbuf.buf: Transmit buffer
+ * @txbuf.len: Transmit buffer length
+ * @buf: Small buffer used when writing init data over SPI
+ * @startbyte: Used by some controllers when in SPI mode.
+ *             Format: 6 bit Device id + RS bit + RW bit
+ * @fbtftops: FBTFT operations provided by driver or device (platform_data)
+ * @dirty_lock: Protects dirty_lines_start and dirty_lines_end
+ * @dirty_lines_start: Where to begin updating display
+ * @dirty_lines_end: Where to end updating display
+ * @gpio.reset: GPIO used to reset display
+ * @gpio.dc: Data/Command signal, also known as RS
+ * @gpio.rd: Read latching signal
+ * @gpio.wr: Write latching signal
+ * @gpio.latch: Bus latch signal, eg. 16->8 bit bus latch
+ * @gpio.cs: LCD Chip Select with parallel interface bus
+ * @gpio.db[16]: Parallel databus
+ * @gpio.led[16]: Led control signals
+ * @gpio.aux[16]: Auxillary signals, not used by core
+ * @init_sequence: Pointer to LCD initialization array
+ * @gamma.lock: Mutex for Gamma curve locking
+ * @gamma.curves: Pointer to Gamma curve array
+ * @gamma.num_values: Number of values per Gamma curve
+ * @gamma.num_curves: Number of Gamma curves
+ * @debug: Pointer to debug value
+ * @current_debug:
+ * @first_update_done: Used to only time the first display update
+ * @update_time: Used to calculate 'fps' in debug output
+ * @bgr: BGR mode/\n
+ * @extra: Extra info needed by driver
+ */
+struct fbtft_par {
+	struct spi_device *spi;
+	struct platform_device *pdev;
+	struct fb_info *info;
+	struct fbtft_platform_data *pdata;
+	u16 *ssbuf;
+	u32 pseudo_palette[16];
+	struct {
+		void *buf;
+		dma_addr_t dma;
+		size_t len;
+	} txbuf;
+	u8 *buf;
+	u8 startbyte;
+	struct fbtft_ops fbtftops;
+	spinlock_t dirty_lock;
+	unsigned dirty_lines_start;
+	unsigned dirty_lines_end;
+	struct {
+		int reset;
+		int dc;
+		int rd;
+		int wr;
+		int latch;
+		int cs;
+		int db[16];
+		int led[16];
+		int aux[16];
+	} gpio;
+	int *init_sequence;
+	struct {
+		struct mutex lock;
+		unsigned long *curves;
+		int num_values;
+		int num_curves;
+	} gamma;
+	unsigned long debug;
+	bool first_update_done;
+	struct timespec update_time;
+	bool bgr;
+	void *extra;
+};
+
+#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+
+#define write_reg(par, ...)                                              \
+do {                                                                     \
+	par->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__); \
+} while (0)
+
+/* fbtft-core.c */
+extern void fbtft_dbg_hex(const struct device *dev,
+	int groupsize, void *buf, size_t len, const char *fmt, ...);
+extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
+	struct device *dev);
+extern void fbtft_framebuffer_release(struct fb_info *info);
+extern int fbtft_register_framebuffer(struct fb_info *fb_info);
+extern int fbtft_unregister_framebuffer(struct fb_info *fb_info);
+extern void fbtft_register_backlight(struct fbtft_par *par);
+extern void fbtft_unregister_backlight(struct fbtft_par *par);
+extern int fbtft_init_display(struct fbtft_par *par);
+extern int fbtft_probe_common(struct fbtft_display *display,
+	struct spi_device *sdev, struct platform_device *pdev);
+extern int fbtft_remove_common(struct device *dev, struct fb_info *info);
+
+/* fbtft-io.c */
+extern int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_spi_emulate_9(struct fbtft_par *par,
+	void *buf, size_t len);
+extern int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio16_wr_latched(struct fbtft_par *par,
+	void *buf, size_t len);
+
+/* fbtft-bus.c */
+extern int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len);
+extern void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...);
+
+
+#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display)                \
+									   \
+static int fbtft_driver_probe_spi(struct spi_device *spi)                  \
+{                                                                          \
+	return fbtft_probe_common(_display, spi, NULL);                    \
+}                                                                          \
+									   \
+static int fbtft_driver_remove_spi(struct spi_device *spi)                 \
+{                                                                          \
+	struct fb_info *info = spi_get_drvdata(spi);                       \
+									   \
+	return fbtft_remove_common(&spi->dev, info);                       \
+}                                                                          \
+									   \
+static int fbtft_driver_probe_pdev(struct platform_device *pdev)           \
+{                                                                          \
+	return fbtft_probe_common(_display, NULL, pdev);                   \
+}                                                                          \
+									   \
+static int fbtft_driver_remove_pdev(struct platform_device *pdev)          \
+{                                                                          \
+	struct fb_info *info = platform_get_drvdata(pdev);                 \
+									   \
+	return fbtft_remove_common(&pdev->dev, info);                      \
+}                                                                          \
+									   \
+static const struct of_device_id dt_ids[] = {                              \
+        { .compatible = _compatible },                                     \
+        {},                                                                \
+};                                                                         \
+									   \
+MODULE_DEVICE_TABLE(of, dt_ids);                                           \
+									   \
+									   \
+static struct spi_driver fbtft_driver_spi_driver = {                       \
+	.driver = {                                                        \
+		.name   = _name,                                           \
+		.owner  = THIS_MODULE,                                     \
+                .of_match_table = of_match_ptr(dt_ids),                    \
+	},                                                                 \
+	.probe  = fbtft_driver_probe_spi,                                  \
+	.remove = fbtft_driver_remove_spi,                                 \
+};                                                                         \
+									   \
+static struct platform_driver fbtft_driver_platform_driver = {             \
+	.driver = {                                                        \
+		.name   = _name,                                           \
+		.owner  = THIS_MODULE,                                     \
+                .of_match_table = of_match_ptr(dt_ids),                    \
+	},                                                                 \
+	.probe  = fbtft_driver_probe_pdev,                                 \
+	.remove = fbtft_driver_remove_pdev,                                \
+};                                                                         \
+									   \
+static int __init fbtft_driver_module_init(void)                           \
+{                                                                          \
+	int ret;                                                           \
+									   \
+	ret = spi_register_driver(&fbtft_driver_spi_driver);               \
+	if (ret < 0)                                                       \
+		return ret;                                                \
+	return platform_driver_register(&fbtft_driver_platform_driver);    \
+}                                                                          \
+									   \
+static void __exit fbtft_driver_module_exit(void)                          \
+{                                                                          \
+	spi_unregister_driver(&fbtft_driver_spi_driver);                   \
+	platform_driver_unregister(&fbtft_driver_platform_driver);         \
+}                                                                          \
+									   \
+module_init(fbtft_driver_module_init);                                     \
+module_exit(fbtft_driver_module_exit);
+
+
+/* Debug macros */
+
+/* shorthand debug levels */
+#define DEBUG_LEVEL_1	DEBUG_REQUEST_GPIOS
+#define DEBUG_LEVEL_2	(DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE)
+#define DEBUG_LEVEL_3	(DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS)
+#define DEBUG_LEVEL_4	(DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK)
+#define DEBUG_LEVEL_5	(DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY)
+#define DEBUG_LEVEL_6	(DEBUG_LEVEL_4 | DEBUG_LEVEL_5)
+#define DEBUG_LEVEL_7	0xFFFFFFFF
+
+#define DEBUG_DRIVER_INIT_FUNCTIONS (1<<3)
+#define DEBUG_TIME_FIRST_UPDATE     (1<<4)
+#define DEBUG_TIME_EACH_UPDATE      (1<<5)
+#define DEBUG_DEFERRED_IO           (1<<6)
+#define DEBUG_FBTFT_INIT_FUNCTIONS  (1<<7)
+
+/* fbops */
+#define DEBUG_FB_READ               (1<<8)
+#define DEBUG_FB_WRITE              (1<<9)
+#define DEBUG_FB_FILLRECT           (1<<10)
+#define DEBUG_FB_COPYAREA           (1<<11)
+#define DEBUG_FB_IMAGEBLIT          (1<<12)
+#define DEBUG_FB_SETCOLREG          (1<<13)
+#define DEBUG_FB_BLANK              (1<<14)
+
+#define DEBUG_SYSFS                 (1<<16)
+
+/* fbtftops */
+#define DEBUG_BACKLIGHT             (1<<17)
+#define DEBUG_READ                  (1<<18)
+#define DEBUG_WRITE                 (1<<19)
+#define DEBUG_WRITE_VMEM            (1<<20)
+#define DEBUG_WRITE_REGISTER        (1<<21)
+#define DEBUG_SET_ADDR_WIN          (1<<22)
+#define DEBUG_RESET                 (1<<23)
+#define DEBUG_MKDIRTY               (1<<24)
+#define DEBUG_UPDATE_DISPLAY        (1<<25)
+#define DEBUG_INIT_DISPLAY          (1<<26)
+#define DEBUG_BLANK                 (1<<27)
+#define DEBUG_REQUEST_GPIOS         (1<<28)
+#define DEBUG_FREE_GPIOS            (1<<29)
+#define DEBUG_REQUEST_GPIOS_MATCH   (1<<30)
+#define DEBUG_VERIFY_GPIOS          (1<<31)
+
+
+#define fbtft_init_dbg(dev, format, arg...)                  \
+do {                                                         \
+	if (unlikely((dev)->platform_data &&                 \
+	    (((struct fbtft_platform_data *)(dev)->platform_data)->display.debug & DEBUG_DRIVER_INIT_FUNCTIONS))) \
+		dev_info(dev, format, ##arg);                \
+} while (0)
+
+#define fbtft_par_dbg(level, par, format, arg...)            \
+do {                                                         \
+	if (unlikely(par->debug & level))                    \
+		dev_info(par->info->device, format, ##arg);  \
+} while (0)
+
+#define fbtft_dev_dbg(level, par, dev, format, arg...)       \
+do {                                                         \
+	if (unlikely(par->debug & level))                    \
+		dev_info(dev, format, ##arg);                \
+} while (0)
+
+#define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \
+do {                                                                       \
+	if (unlikely(par->debug & level))                                  \
+		fbtft_dbg_hex(dev, sizeof(type), buf, num * sizeof(type), format, ##arg); \
+} while (0)
+
+#endif /* __LINUX_FBTFT_H */
diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c
new file mode 100644
index 0000000..b9f4c30
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft_device.c
@@ -0,0 +1,1444 @@
+/*
+ *
+ * Copyright (C) 2013, Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fbtft_device"
+
+#define MAX_GPIOS 32
+
+struct spi_device *spi_device;
+struct platform_device *p_device;
+
+static char *name;
+module_param(name, charp, 0);
+MODULE_PARM_DESC(name, "Devicename (required). " \
+"name=list => list all supported devices.");
+
+static unsigned rotate;
+module_param(rotate, uint, 0);
+MODULE_PARM_DESC(rotate,
+"Angle to rotate display counter clockwise: 0, 90, 180, 270");
+
+static unsigned busnum;
+module_param(busnum, uint, 0);
+MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
+
+static unsigned cs;
+module_param(cs, uint, 0);
+MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
+
+static unsigned speed;
+module_param(speed, uint, 0);
+MODULE_PARM_DESC(speed, "SPI speed (override device default)");
+
+static int mode = -1;
+module_param(mode, int, 0);
+MODULE_PARM_DESC(mode, "SPI mode (override device default)");
+
+static char *gpios;
+module_param(gpios, charp, 0);
+MODULE_PARM_DESC(gpios,
+"List of gpios. Comma separated with the form: reset:23,dc:24 " \
+"(when overriding the default, all gpios must be specified)");
+
+static unsigned fps;
+module_param(fps, uint, 0);
+MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
+
+static char *gamma;
+module_param(gamma, charp, 0);
+MODULE_PARM_DESC(gamma,
+"String representation of Gamma Curve(s). Driver specific.");
+
+static int txbuflen;
+module_param(txbuflen, int, 0);
+MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
+
+static int bgr = -1;
+module_param(bgr, int, 0);
+MODULE_PARM_DESC(bgr,
+"BGR bit (supported by some drivers).");
+
+static unsigned startbyte;
+module_param(startbyte, uint, 0);
+MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
+
+static bool custom;
+module_param(custom, bool, 0);
+MODULE_PARM_DESC(custom, "Add a custom display device. " \
+"Use speed= argument to make it a SPI device, else platform_device");
+
+static unsigned width;
+module_param(width, uint, 0);
+MODULE_PARM_DESC(width, "Display width, used with the custom argument");
+
+static unsigned height;
+module_param(height, uint, 0);
+MODULE_PARM_DESC(height, "Display height, used with the custom argument");
+
+static unsigned buswidth = 8;
+module_param(buswidth, uint, 0);
+MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
+
+static int init[FBTFT_MAX_INIT_SEQUENCE];
+static int init_num;
+module_param_array(init, int, &init_num, 0);
+MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
+
+static unsigned long debug;
+module_param(debug, ulong , 0);
+MODULE_PARM_DESC(debug,
+"level: 0-7 (the remaining 29 bits is for advanced usage)");
+
+static unsigned verbose = 3;
+module_param(verbose, uint, 0);
+MODULE_PARM_DESC(verbose,
+"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)");
+
+
+struct fbtft_device_display {
+	char *name;
+	struct spi_board_info *spi;
+	struct platform_device *pdev;
+};
+
+static void fbtft_device_pdev_release(struct device *dev);
+
+static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
+static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
+	int xs, int ys, int xe, int ye);
+
+#define ADAFRUIT18_GAMMA \
+		"02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
+		"03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
+
+static int hy28b_init_sequence[] = {
+	-1,0x00e7,0x0010,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,
+	-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0207,-1,0x0009,0x0000,
+	-1,0x000a,0x0000,-1,0x000c,0x0001,-1,0x000d,0x0000,-1,0x000f,0x0000,
+	-1,0x0010,0x0000,-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,
+	-2,50,-1,0x0010,0x1590,-1,0x0011,0x0227,-2,50,-1,0x0012,0x009c,-2,50,
+	-1,0x0013,0x1900,-1,0x0029,0x0023,-1,0x002b,0x000e,-2,50,
+	-1,0x0020,0x0000,-1,0x0021,0x0000,-2,50,-1,0x0050,0x0000,
+	-1,0x0051,0x00ef,-1,0x0052,0x0000,-1,0x0053,0x013f,-1,0x0060,0xa700,
+	-1,0x0061,0x0001,-1,0x006a,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,
+	-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,
+	-1,0x0090,0x0010,-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,
+	-1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0133,-1,0x0020,0x0000,
+	-1,0x0021,0x0000,-2,100,-3 };
+
+#define HY28B_GAMMA \
+	"04 1F 4 7 7 0 7 7 6 0\n" \
+	"0F 00 1 7 4 0 0 0 6 7"
+
+static int pitft_init_sequence[] = {
+	-1,0x01,-2,5,-1,0x28,-1,0xEF,0x03,0x80,0x02,-1,0xCF,0x00,0xC1,0x30,
+	-1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x00,0x78,
+	-1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,
+	-1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,-1,0x3A,0x55,
+	-1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,-1,0xF2,0x00,-1,0x26,0x01,
+	-1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,
+	0x0E,0x09,0x00,-1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,
+	0x08,0x0F,0x0C,0x31,0x36,0x0F,-1,0x11,-2,100,-1,0x29,-2,20,-3 };
+
+static int waveshare32b_init_sequence[] = {
+	-1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xCF,0x00,0xC1,0x30,
+	-1,0xE8,0x85,0x00,0x78,-1,0xEA,0x00,0x00,-1,0xED,0x64,0x03,0x12,0x81,
+	-1,0xF7,0x20,-1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,
+	-1,0x36,0x28,-1,0x3A,0x55,-1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,
+	-1,0xF2,0x00,-1,0x26,0x01,
+	-1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,0x0E,0x09,0x00,
+	-1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,0x31,0x36,0x0F,
+	-1,0x11,-2,120,-1,0x29,-1,0x2c,-3 };
+
+/* Supported displays in alphabetical order */
+static struct fbtft_device_display displays[] = {
+	{
+		.name = "adafruit18",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_st7735r",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+				.gamma = ADAFRUIT18_GAMMA,
+			}
+		}
+	}, {
+		.name = "adafruit18_green",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_st7735r",
+			.max_speed_hz = 4000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.fbtftops.set_addr_win = \
+					    adafruit18_green_tab_set_addr_win,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+				.gamma = ADAFRUIT18_GAMMA,
+			}
+		}
+	}, {
+		.name = "adafruit22",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_hx8340bn",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 9,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "led", 23 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "adafruit22a",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9340",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "adafruit28",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9341",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "adafruit13m",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ssd1306",
+			.max_speed_hz = 16000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "agm1264k-fl",
+		.pdev = &(struct platform_device) {
+			.name = "fb_agm1264k-fl",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = FBTFT_ONBOARD_BACKLIGHT,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+			}
+		}
+	}, {
+		.name = "dogs102",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_uc1701",
+			.max_speed_hz = 8000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 13 },
+					{ "dc", 6 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "er_tftm050_2",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ra8875",
+			.max_speed_hz = 5000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.width = 480,
+					.height = 272,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "er_tftm070_5",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ra8875",
+			.max_speed_hz = 5000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.width = 800,
+					.height = 480,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "flexfb",
+		.spi = &(struct spi_board_info) {
+			.modalias = "flexfb",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "flexpfb",
+		.pdev = &(struct platform_device) {
+			.name = "flexpfb",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 17 },
+					{ "dc", 1 },
+					{ "wr", 0 },
+					{ "cs", 21 },
+					{ "db00", 9 },
+					{ "db01", 11 },
+					{ "db02", 18 },
+					{ "db03", 23 },
+					{ "db04", 24 },
+					{ "db05", 25 },
+					{ "db06", 8 },
+					{ "db07", 7 },
+					{ "led", 4 },
+					{},
+				},
+			},
+			}
+		}
+	}, {
+		.name = "freetronicsoled128",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ssd1351",
+			.max_speed_hz = 20000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = FBTFT_ONBOARD_BACKLIGHT,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 24 },
+					{ "dc", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "hx8353d",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_hx8353d",
+			.max_speed_hz = 16000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 23 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "hy28a",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9320",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.startbyte = 0b01110000,
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "hy28b",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9325",
+			.max_speed_hz = 48000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.init_sequence = hy28b_init_sequence,
+				},
+				.startbyte = 0b01110000,
+				.bgr = true,
+				.fps= 50,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "led", 18 },
+					{},
+				},
+				.gamma = HY28B_GAMMA,
+			}
+		}
+	}, {
+		.name = "ili9481",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9481",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.regwidth = 16,
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 22 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "itdb24",
+		.pdev = &(struct platform_device) {
+			.name = "fb_s6d1121",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = false,
+				.gpios = (const struct fbtft_gpio []) {
+					/* Wiring for LCD adapter kit */
+					{ "reset", 7 },
+					{ "dc", 0 }, 	/* rev 2: 2 */
+					{ "wr", 1 }, 	/* rev 2: 3 */
+					{ "cs", 8 },
+					{ "db00", 17 },
+					{ "db01", 18 },
+					{ "db02", 21 }, /* rev 2: 27 */
+					{ "db03", 22 },
+					{ "db04", 23 },
+					{ "db05", 24 },
+					{ "db06", 25 },
+					{ "db07", 4 },
+					{}
+				},
+			},
+			}
+		}
+	}, {
+		.name = "itdb28",
+		.pdev = &(struct platform_device) {
+			.name = "fb_ili9325",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+			}
+		}
+	}, {
+		.name = "itdb28_spi",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9325",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "mi0283qt-2",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_hx8347d",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.startbyte = 0b01110000,
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "mi0283qt-9a",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9341",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 9,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "mi0283qt-v2",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_watterott",
+			.max_speed_hz = 4000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "nokia3310",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_pcd8544",
+			.max_speed_hz = 400000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 23 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "nokia3310a",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_tls8204",
+			.max_speed_hz = 1000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 23 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "piscreen",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9486",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.regwidth = 16,
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 22 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "pitft",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9340",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.chip_select = 0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.init_sequence = pitft_init_sequence,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "dc", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "pioled",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ssd1351",
+			.max_speed_hz = 20000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 24 },
+					{ "dc", 25 },
+					{},
+				},
+				.gamma =	"0 2 2 2 2 2 2 2 " \
+						"2 2 2 2 2 2 2 2 " \
+						"2 2 2 2 2 2 2 2 " \
+						"2 2 2 2 2 2 2 3 " \
+						"3 3 3 3 3 3 3 3 " \
+						"3 3 3 3 3 3 3 3 " \
+						"3 3 3 4 4 4 4 4 " \
+						"4 4 4 4 4 4 4"
+			}
+		}
+	}, {
+		.name = "rpi-display",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9341",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 23 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "s6d02a1",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_s6d02a1",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 23 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "sainsmart18",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_st7735r",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "sainsmart32",
+		.pdev = &(struct platform_device) {
+			.name = "fb_ssd1289",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 16,
+					.txbuflen = -2, /* disable buffer */
+					.backlight = 1,
+					.fbtftops.write = write_gpio16_wr_slow,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+		},
+		}
+	}, {
+		.name = "sainsmart32_fast",
+		.pdev = &(struct platform_device) {
+			.name = "fb_ssd1289",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 16,
+					.txbuflen = -2, /* disable buffer */
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+		},
+		}
+	}, {
+		.name = "sainsmart32_latched",
+		.pdev = &(struct platform_device) {
+			.name = "fb_ssd1289",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 16,
+					.txbuflen = -2, /* disable buffer */
+					.backlight = 1,
+					.fbtftops.write = \
+						fbtft_write_gpio16_wr_latched,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+		},
+		}
+	}, {
+		.name = "sainsmart32_spi",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ssd1289",
+			.max_speed_hz = 16000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "spidev",
+		.spi = &(struct spi_board_info) {
+			.modalias = "spidev",
+			.max_speed_hz = 500000,
+			.bus_num = 0,
+			.chip_select = 0,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "ssd1331",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ssd1331",
+			.max_speed_hz = 20000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 24 },
+					{ "dc", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "tinylcd35",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_tinylcd",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "tm022hdh26",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9341",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 25 },
+					{ "dc", 24 },
+					{ "led", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "tontec35_9481", /* boards before 02 July 2014 */
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9481",
+			.max_speed_hz = 128000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 15 },
+					{ "dc", 25 },
+					{ "led_", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "tontec35_9486", /* boards after 02 July 2014 */
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9486",
+			.max_speed_hz = 128000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 15 },
+					{ "dc", 25 },
+					{ "led_", 18 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "upd161704",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_upd161704",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 24 },
+					{ "dc", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "waveshare32b",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_ili9340",
+			.max_speed_hz = 48000000,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+					.backlight = 1,
+					.init_sequence = waveshare32b_init_sequence,
+				},
+				.bgr = true,
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 27 },
+					{ "dc", 22 },
+					{},
+				},
+			}
+		}
+	}, {
+		.name = "waveshare22",
+		.spi = &(struct spi_board_info) {
+			.modalias = "fb_bd663474",
+			.max_speed_hz = 32000000,
+			.mode = SPI_MODE_3,
+			.platform_data = &(struct fbtft_platform_data) {
+				.display = {
+					.buswidth = 8,
+				},
+				.gpios = (const struct fbtft_gpio []) {
+					{ "reset", 24 },
+					{ "dc", 25 },
+					{},
+				},
+			}
+		}
+	}, {
+		/* This should be the last item.
+		   Used with the custom argument */
+		.name = "",
+		.spi = &(struct spi_board_info) {
+			.modalias = "",
+			.max_speed_hz = 0,
+			.mode = SPI_MODE_0,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			}
+		},
+		.pdev = &(struct platform_device) {
+			.name = "",
+			.id = 0,
+			.dev = {
+			.release = fbtft_device_pdev_release,
+			.platform_data = &(struct fbtft_platform_data) {
+				.gpios = (const struct fbtft_gpio []) {
+					{},
+				},
+			},
+		},
+		},
+	}
+};
+
+static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
+{
+	u16 data;
+	int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+	static u16 prev_data;
+#endif
+
+	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+		"%s(len=%d): ", __func__, len);
+
+	while (len) {
+		data = *(u16 *) buf;
+
+		/* Start writing by pulling down /WR */
+		gpio_set_value(par->gpio.wr, 0);
+
+		/* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		if (data == prev_data) {
+			gpio_set_value(par->gpio.wr, 0); /* used as delay */
+		} else {
+			for (i = 0; i < 16; i++) {
+				if ((data & 1) != (prev_data & 1))
+					gpio_set_value(par->gpio.db[i],
+								(data & 1));
+				data >>= 1;
+				prev_data >>= 1;
+			}
+		}
+#else
+		for (i = 0; i < 16; i++) {
+			gpio_set_value(par->gpio.db[i], (data & 1));
+			data >>= 1;
+		}
+#endif
+
+		/* Pullup /WR */
+		gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+		prev_data = *(u16 *) buf;
+#endif
+		buf += 2;
+		len -= 2;
+	}
+
+	return 0;
+}
+
+static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
+						int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
+	write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
+	write_reg(par, 0x2C);
+}
+
+/* used if gpios parameter is present */
+static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS+1] = { };
+
+static void fbtft_device_pdev_release(struct device *dev)
+{
+/* Needed to silence this message:
+Device 'xxx' does not have a release() function, it is broken and must be fixed
+*/
+}
+
+static int spi_device_found(struct device *dev, void *data)
+{
+	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+
+	pr_info(DRVNAME":      %s %s %dkHz %d bits mode=0x%02X\n",
+		spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
+		spi->bits_per_word, spi->mode);
+
+	return 0;
+}
+
+static void pr_spi_devices(void)
+{
+	pr_info(DRVNAME":  SPI devices registered:\n");
+	bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
+}
+
+static int p_device_found(struct device *dev, void *data)
+{
+	struct platform_device
+	*pdev = container_of(dev, struct platform_device, dev);
+
+	if (strstr(pdev->name, "fb"))
+		pr_info(DRVNAME":      %s id=%d pdata? %s\n",
+				pdev->name, pdev->id,
+				pdev->dev.platform_data ? "yes" : "no");
+
+	return 0;
+}
+
+static void pr_p_devices(void)
+{
+	pr_info(DRVNAME":  'fb' Platform devices registered:\n");
+	bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
+}
+
+#ifdef MODULE
+static void fbtft_device_spi_delete(struct spi_master *master, unsigned cs)
+{
+	struct device *dev;
+	char str[32];
+
+	snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
+
+	dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
+	if (dev) {
+		if (verbose)
+			pr_info(DRVNAME": Deleting %s\n", str);
+		device_del(dev);
+	}
+}
+
+static int fbtft_device_spi_device_register(struct spi_board_info *spi)
+{
+	struct spi_master *master;
+
+	master = spi_busnum_to_master(spi->bus_num);
+	if (!master) {
+		pr_err(DRVNAME ":  spi_busnum_to_master(%d) returned NULL\n",
+								spi->bus_num);
+		return -EINVAL;
+	}
+	/* make sure it's available */
+	fbtft_device_spi_delete(master, spi->chip_select);
+	spi_device = spi_new_device(master, spi);
+	put_device(&master->dev);
+	if (!spi_device) {
+		pr_err(DRVNAME ":    spi_new_device() returned NULL\n");
+		return -EPERM;
+	}
+	return 0;
+}
+#else
+static int fbtft_device_spi_device_register(struct spi_board_info *spi)
+{
+	return spi_register_board_info(spi, 1);
+}
+#endif
+
+static int __init fbtft_device_init(void)
+{
+	struct spi_board_info *spi = NULL;
+	struct fbtft_platform_data *pdata;
+	const struct fbtft_gpio *gpio = NULL;
+	char *p_gpio, *p_name, *p_num;
+	bool found = false;
+	int i = 0;
+	long val;
+	int ret = 0;
+
+	pr_debug("\n\n"DRVNAME": init\n");
+
+	if (name == NULL) {
+#ifdef MODULE
+		pr_err(DRVNAME":  missing module parameter: 'name'\n");
+		return -EINVAL;
+#else
+		return 0;
+#endif
+	}
+
+	if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
+		pr_err(DRVNAME \
+			":  init parameter: exceeded max array size: %d\n",
+			FBTFT_MAX_INIT_SEQUENCE);
+		return -EINVAL;
+	}
+
+	/* parse module parameter: gpios */
+	while ((p_gpio = strsep(&gpios, ","))) {
+		if (strchr(p_gpio, ':') == NULL) {
+			pr_err(DRVNAME \
+				":  error: missing ':' in gpios parameter: %s\n",
+				p_gpio);
+			return -EINVAL;
+		}
+		p_num = p_gpio;
+		p_name = strsep(&p_num, ":");
+		if (p_name == NULL || p_num == NULL) {
+			pr_err(DRVNAME \
+				":  something bad happened parsing gpios parameter: %s\n",
+				p_gpio);
+			return -EINVAL;
+		}
+		ret = kstrtol(p_num, 10, &val);
+		if (ret) {
+			pr_err(DRVNAME \
+				":  could not parse number in gpios parameter: %s:%s\n",
+				p_name, p_num);
+			return -EINVAL;
+		}
+		strcpy(fbtft_device_param_gpios[i].name, p_name);
+		fbtft_device_param_gpios[i++].gpio = (int) val;
+		if (i == MAX_GPIOS) {
+			pr_err(DRVNAME \
+				":  gpios parameter: exceeded max array size: %d\n",
+				MAX_GPIOS);
+			return -EINVAL;
+		}
+	}
+	if (fbtft_device_param_gpios[0].name[0])
+		gpio = fbtft_device_param_gpios;
+
+	if (verbose > 2)
+		pr_spi_devices(); /* print list of registered SPI devices */
+
+	if (verbose > 2)
+		pr_p_devices(); /* print list of 'fb' platform devices */
+
+	pr_debug(DRVNAME":  name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
+
+	if (rotate > 0 && rotate < 4) {
+		rotate = (4 - rotate) * 90;
+		pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
+			rotate);
+	}
+	if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
+		pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
+			rotate);
+		rotate = 0;
+	}
+
+	/* name=list lists all supported displays */
+	if (strncmp(name, "list", 32) == 0) {
+		pr_info(DRVNAME":  Supported displays:\n");
+
+		for (i = 0; i < ARRAY_SIZE(displays); i++)
+			pr_info(DRVNAME":      %s\n", displays[i].name);
+		return -ECANCELED;
+	}
+
+	if (custom) {
+		i = ARRAY_SIZE(displays) - 1;
+		displays[i].name = name;
+		if (speed == 0) {
+			displays[i].pdev->name = name;
+			displays[i].spi = NULL;
+		} else {
+			strncpy(displays[i].spi->modalias, name, SPI_NAME_SIZE);
+			displays[i].pdev = NULL;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(displays); i++) {
+		if (strncmp(name, displays[i].name, 32) == 0) {
+			if (displays[i].spi) {
+				spi = displays[i].spi;
+				spi->chip_select = cs;
+				spi->bus_num = busnum;
+				if (speed)
+					spi->max_speed_hz = speed;
+				if (mode != -1)
+					spi->mode = mode;
+				pdata = (void *)spi->platform_data;
+			} else if (displays[i].pdev) {
+				p_device = displays[i].pdev;
+				pdata = p_device->dev.platform_data;
+			} else {
+				pr_err(DRVNAME": broken displays array\n");
+				return -EINVAL;
+			}
+
+			pdata->rotate = rotate;
+			if (bgr == 0)
+				pdata->bgr = false;
+			else if (bgr == 1)
+				pdata->bgr = true;
+			if (startbyte)
+				pdata->startbyte = startbyte;
+			if (gamma)
+				pdata->gamma = gamma;
+			pdata->display.debug = debug;
+			if (fps)
+				pdata->fps = fps;
+			if (txbuflen)
+				pdata->txbuflen = txbuflen;
+			if (init_num)
+				pdata->display.init_sequence = init;
+			if (gpio)
+				pdata->gpios = gpio;
+			if (custom) {
+				pdata->display.width = width;
+				pdata->display.height = height;
+				pdata->display.buswidth = buswidth;
+				pdata->display.backlight = 1;
+			}
+
+			if (displays[i].spi) {
+				ret = fbtft_device_spi_device_register(spi);
+				if (ret) {
+					pr_err(DRVNAME \
+						": failed to register SPI device\n");
+					return ret;
+				}
+				found = true;
+				break;
+			} else {
+				ret = platform_device_register(p_device);
+				if (ret < 0) {
+					pr_err(DRVNAME \
+						":    platform_device_register() returned %d\n",
+						ret);
+					return ret;
+				}
+				found = true;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		pr_err(DRVNAME":  display not supported: '%s'\n", name);
+		return -EINVAL;
+	}
+
+	if (verbose && pdata && pdata->gpios) {
+		gpio = pdata->gpios;
+		pr_info(DRVNAME":  GPIOS used by '%s':\n", name);
+		found = false;
+		while (verbose && gpio->name[0]) {
+			pr_info(DRVNAME":    '%s' = GPIO%d\n",
+				gpio->name, gpio->gpio);
+			gpio++;
+			found = true;
+		}
+		if (!found)
+			pr_info(DRVNAME":    (none)\n");
+	}
+
+	if (spi_device && (verbose > 1))
+		pr_spi_devices();
+	if (p_device && (verbose > 1))
+		pr_p_devices();
+
+	return 0;
+}
+
+static void __exit fbtft_device_exit(void)
+{
+	pr_debug(DRVNAME" - exit\n");
+
+	if (spi_device) {
+		device_del(&spi_device->dev);
+		kfree(spi_device);
+	}
+
+	if (p_device)
+		platform_device_unregister(p_device);
+
+}
+
+arch_initcall(fbtft_device_init);
+module_exit(fbtft_device_exit);
+
+MODULE_DESCRIPTION("Add a FBTFT device.");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c
new file mode 100644
index 0000000..90832c3
--- /dev/null
+++ b/drivers/staging/fbtft/flexfb.c
@@ -0,0 +1,592 @@
+/*
+ * Generic FB driver for TFT LCD displays
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME	    "flexfb"
+
+
+static char *chip;
+module_param(chip, charp, 0);
+MODULE_PARM_DESC(chip, "LCD controller");
+
+static unsigned int width;
+module_param(width, uint, 0);
+MODULE_PARM_DESC(width, "Display width");
+
+static unsigned int height;
+module_param(height, uint, 0);
+MODULE_PARM_DESC(height, "Display height");
+
+static int init[512];
+static int init_num;
+module_param_array(init, int, &init_num, 0);
+MODULE_PARM_DESC(init, "Init sequence");
+
+static unsigned int setaddrwin;
+module_param(setaddrwin, uint, 0);
+MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use");
+
+static unsigned int buswidth = 8;
+module_param(buswidth, uint, 0);
+MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)");
+
+static unsigned int regwidth = 8;
+module_param(regwidth, uint, 0);
+MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)");
+
+static bool nobacklight;
+module_param(nobacklight, bool, 0);
+MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality.");
+
+static bool latched;
+module_param(latched, bool, 0);
+MODULE_PARM_DESC(latched, "Use with latched 16-bit databus");
+
+
+static int *initp;
+static int initp_num;
+
+/* default init sequences */
+static int st7735r_init[] = { \
+-1,0x01,-2,150,-1,0x11,-2,500,-1,0xB1,0x01,0x2C,0x2D,-1,0xB2,0x01,0x2C,0x2D,-1,0xB3,0x01,0x2C,0x2D,0x01,0x2C,0x2D, \
+-1,0xB4,0x07,-1,0xC0,0xA2,0x02,0x84,-1,0xC1,0xC5,-1,0xC2,0x0A,0x00,-1,0xC3,0x8A,0x2A,-1,0xC4,0x8A,0xEE,-1,0xC5,0x0E, \
+-1,0x20,-1,0x36,0xC0,-1,0x3A,0x05,-1,0xE0,0x0f,0x1a,0x0f,0x18,0x2f,0x28,0x20,0x22,0x1f,0x1b,0x23,0x37,0x00,0x07,0x02,0x10, \
+-1,0xE1,0x0f,0x1b,0x0f,0x17,0x33,0x2c,0x29,0x2e,0x30,0x30,0x39,0x3f,0x00,0x07,0x03,0x10,-1,0x29,-2,100,-1,0x13,-2,10,-3 };
+
+static int ssd1289_init[] = { \
+-1,0x00,0x0001,-1,0x03,0xA8A4,-1,0x0C,0x0000,-1,0x0D,0x080C,-1,0x0E,0x2B00,-1,0x1E,0x00B7,-1,0x01,0x2B3F,-1,0x02,0x0600, \
+-1,0x10,0x0000,-1,0x11,0x6070,-1,0x05,0x0000,-1,0x06,0x0000,-1,0x16,0xEF1C,-1,0x17,0x0003,-1,0x07,0x0233,-1,0x0B,0x0000, \
+-1,0x0F,0x0000,-1,0x41,0x0000,-1,0x42,0x0000,-1,0x48,0x0000,-1,0x49,0x013F,-1,0x4A,0x0000,-1,0x4B,0x0000,-1,0x44,0xEF00, \
+-1,0x45,0x0000,-1,0x46,0x013F,-1,0x30,0x0707,-1,0x31,0x0204,-1,0x32,0x0204,-1,0x33,0x0502,-1,0x34,0x0507,-1,0x35,0x0204, \
+-1,0x36,0x0204,-1,0x37,0x0502,-1,0x3A,0x0302,-1,0x3B,0x0302,-1,0x23,0x0000,-1,0x24,0x0000,-1,0x25,0x8000,-1,0x4f,0x0000, \
+-1,0x4e,0x0000,-1,0x22,-3 };
+
+static int hx8340bn_init[] = { \
+-1,0xC1,0xFF,0x83,0x40,-1,0x11,-2,150,-1,0xCA,0x70,0x00,0xD9,-1,0xB0,0x01,0x11, \
+-1,0xC9,0x90,0x49,0x10,0x28,0x28,0x10,0x00,0x06,-2,20,-1,0xC2,0x60,0x71,0x01,0x0E,0x05,0x02,0x09,0x31,0x0A, \
+-1,0xC3,0x67,0x30,0x61,0x17,0x48,0x07,0x05,0x33,-2,10,-1,0xB5,0x35,0x20,0x45,-1,0xB4,0x33,0x25,0x4C,-2,10, \
+-1,0x3A,0x05,-1,0x29,-2,10,-3 };
+
+static int ili9225_init[] = { \
+-1,0x0001,0x011C,-1,0x0002,0x0100,-1,0x0003,0x1030,-1,0x0008,0x0808,-1,0x000C,0x0000,-1,0x000F,0x0A01,-1,0x0020,0x0000, \
+-1,0x0021,0x0000,-2,50,-1,0x0010,0x0A00,-1,0x0011,0x1038,-2,50,-1,0x0012,0x1121,-1,0x0013,0x004E,-1,0x0014,0x676F, \
+-1,0x0030,0x0000,-1,0x0031,0x00DB,-1,0x0032,0x0000,-1,0x0033,0x0000,-1,0x0034,0x00DB,-1,0x0035,0x0000,-1,0x0036,0x00AF, \
+-1,0x0037,0x0000,-1,0x0038,0x00DB,-1,0x0039,0x0000,-1,0x0050,0x0000,-1,0x0051,0x060A,-1,0x0052,0x0D0A,-1,0x0053,0x0303, \
+-1,0x0054,0x0A0D,-1,0x0055,0x0A06,-1,0x0056,0x0000,-1,0x0057,0x0303,-1,0x0058,0x0000,-1,0x0059,0x0000,-2,50, \
+-1,0x0007,0x1017,-2,50,-3 };
+
+static int ili9320_init[] = { \
+-1,0x00E5,0x8000,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0202, \
+-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000,-1,0x0011,0x0007, \
+-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x17B0,-1,0x0011,0x0031,-2,50,-1,0x0012,0x0138,-2,50,-1,0x0013,0x1800, \
+-1,0x0029,0x0008,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000,-1,0x0031,0x0505,-1,0x0032,0x0004, \
+-1,0x0035,0x0006,-1,0x0036,0x0707,-1,0x0037,0x0105,-1,0x0038,0x0002,-1,0x0039,0x0707,-1,0x003C,0x0704,-1,0x003D,0x0807, \
+-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0x2700,-1,0x0061,0x0001,-1,0x006A,0x0000, \
+-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,-1,0x0090,0x0010, \
+-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,-1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0173,-3 };
+
+static int ili9325_init[] = { \
+-1,0x00E3,0x3008,-1,0x00E7,0x0012,-1,0x00EF,0x1231,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000, \
+-1,0x0008,0x0207,-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000, \
+-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x1690,-1,0x0011,0x0223,-2,50,-1,0x0012,0x000D,-2,50, \
+-1,0x0013,0x1200,-1,0x0029,0x000A,-1,0x002B,0x000C,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000, \
+-1,0x0031,0x0506,-1,0x0032,0x0104,-1,0x0035,0x0207,-1,0x0036,0x000F,-1,0x0037,0x0306,-1,0x0038,0x0102,-1,0x0039,0x0707, \
+-1,0x003C,0x0702,-1,0x003D,0x1604,-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0xA700, \
+-1,0x0061,0x0001,-1,0x006A,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000, \
+-1,0x0085,0x0000,-1,0x0090,0x0010,-1,0x0092,0x0600,-1,0x0007,0x0133,-3 };
+
+static int ili9341_init[] = { \
+-1,0x28,-2,20,-1,0xCF,0x00,0x83,0x30,-1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x01,0x79, \
+-1,0xCB,0x39,0x2c,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,-1,0xC0,0x26,-1,0xC1,0x11, \
+-1,0xC5,0x35,0x3E,-1,0xC7,0xBE,-1,0xB1,0x00,0x1B,-1,0xB6,0x0a,0x82,0x27,0x00,-1,0xB7,0x07, \
+-1,0x3A,0x55,-1,0x36,0x48,-1,0x11,-2,120,-1,0x29,-2,20,-3 };
+
+static int ssd1351_init[] = { -1,0xfd,0x12,-1,0xfd,0xb1,-1,0xae,-1,0xb3,0xf1,-1,0xca,0x7f,-1,0xa0,0x74, \
+                              -1,0x15,0x00,0x7f,-1,0x75,0x00,0x7f,-1,0xa1,0x00,-1,0xa2,0x00,-1,0xb5,0x00, \
+                              -1,0xab,0x01,-1,0xb1,0x32,-1,0xb4,0xa0,0xb5,0x55,-1,0xbb,0x17,-1,0xbe,0x05, \
+                              -1,0xc1,0xc8,0x80,0xc8,-1,0xc7,0x0f,-1,0xb6,0x01,-1,0xa6,-1,0xaf,-3 };
+
+
+/* ili9320, ili9325 */
+static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+	switch (par->info->var.rotate) {
+	/* R20h = Horizontal GRAM Start Address */
+	/* R21h = Vertical GRAM Start Address */
+	case 0:
+		write_reg(par, 0x0020, xs);
+		write_reg(par, 0x0021, ys);
+		break;
+	case 180:
+		write_reg(par, 0x0020, width - 1 - xs);
+		write_reg(par, 0x0021, height - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x0020, width - 1 - ys);
+		write_reg(par, 0x0021, xs);
+		break;
+	case 90:
+		write_reg(par, 0x0020, ys);
+		write_reg(par, 0x0021, height - 1 - xs);
+		break;
+	}
+	write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+/* ssd1289 */
+static void flexfb_set_addr_win_2(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	switch (par->info->var.rotate) {
+	/* R4Eh - Set GDDRAM X address counter */
+	/* R4Fh - Set GDDRAM Y address counter */
+	case 0:
+		write_reg(par, 0x4e, xs);
+		write_reg(par, 0x4f, ys);
+		break;
+	case 180:
+		write_reg(par, 0x4e, par->info->var.xres - 1 - xs);
+		write_reg(par, 0x4f, par->info->var.yres - 1 - ys);
+		break;
+	case 270:
+		write_reg(par, 0x4e, par->info->var.yres - 1 - ys);
+		write_reg(par, 0x4f, xs);
+		break;
+	case 90:
+		write_reg(par, 0x4e, ys);
+		write_reg(par, 0x4f, par->info->var.xres - 1 - xs);
+		break;
+	}
+
+	/* R22h - RAM data write */
+	write_reg(par, 0x22, 0);
+}
+
+/* ssd1351 */
+static void set_addr_win_3(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+	write_reg(par, 0x15, xs, xe);
+	write_reg(par, 0x75, ys, ye);
+	write_reg(par, 0x5C);
+}
+
+static int flexfb_verify_gpios_dc(struct fbtft_par *par)
+{
+	fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+	if (par->gpio.dc < 0) {
+		dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int flexfb_verify_gpios_db(struct fbtft_par *par)
+{
+	int i;
+	int num_db = buswidth;
+
+	fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+	if (par->gpio.dc < 0) {
+		dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	if (par->gpio.wr < 0) {
+		dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	if (latched && (par->gpio.latch < 0)) {
+		dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n");
+		return -EINVAL;
+	}
+	if (latched)
+		num_db=buswidth/2;
+	for (i=0;i < num_db;i++) {
+		if (par->gpio.db[i] < 0) {
+			dev_err(par->info->device, "Missing info about 'db%02d' gpio. Aborting.\n", i);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static struct fbtft_display flex_display = { };
+
+static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev)
+{
+	struct device *dev;
+	struct fb_info *info;
+	struct fbtft_par *par;
+	int ret;
+
+	initp = init;
+	initp_num = init_num;
+
+	if (sdev)
+		dev = &sdev->dev;
+	else
+		dev = &pdev->dev;
+
+	fbtft_init_dbg(dev, "%s(%s)\n", __func__, sdev ? "'SPI device'" : "'Platform device'");
+
+	if (chip) {
+
+		if (!strcmp(chip, "st7735r")) {
+			if (!width)
+				width = 128;
+			if (!height)
+				height = 160;
+			if (init_num == 0) {
+				initp = st7735r_init;
+				initp_num = ARRAY_SIZE(st7735r_init);
+			}
+
+
+		} else if (!strcmp(chip, "hx8340bn")) {
+			if (!width)
+				width = 176;
+			if (!height)
+				height = 220;
+			setaddrwin = 0;
+			if (init_num == 0) {
+				initp = hx8340bn_init;
+				initp_num = ARRAY_SIZE(hx8340bn_init);
+			}
+
+
+		} else if (!strcmp(chip, "ili9225")) {
+			if (!width)
+				width = 176;
+			if (!height)
+				height = 220;
+			setaddrwin = 0;
+			regwidth = 16;
+			if (init_num == 0) {
+				initp = ili9225_init;
+				initp_num = ARRAY_SIZE(ili9225_init);
+			}
+
+
+
+		} else if (!strcmp(chip, "ili9320")) {
+			if (!width)
+				width = 240;
+			if (!height)
+				height = 320;
+			setaddrwin = 1;
+			regwidth = 16;
+			if (init_num == 0) {
+				initp = ili9320_init;
+				initp_num = ARRAY_SIZE(ili9320_init);
+			}
+
+
+		} else if (!strcmp(chip, "ili9325")) {
+			if (!width)
+				width = 240;
+			if (!height)
+				height = 320;
+			setaddrwin = 1;
+			regwidth = 16;
+			if (init_num == 0) {
+				initp = ili9325_init;
+				initp_num = ARRAY_SIZE(ili9325_init);
+			}
+
+		} else if (!strcmp(chip, "ili9341")) {
+			if (!width)
+				width = 240;
+			if (!height)
+				height = 320;
+			setaddrwin = 0;
+			regwidth = 8;
+			if (init_num == 0) {
+				initp = ili9341_init;
+				initp_num = ARRAY_SIZE(ili9341_init);
+			}
+
+
+		} else if (!strcmp(chip, "ssd1289")) {
+			if (!width)
+				width = 240;
+			if (!height)
+				height = 320;
+			setaddrwin = 2;
+			regwidth = 16;
+			if (init_num == 0) {
+				initp = ssd1289_init;
+				initp_num = ARRAY_SIZE(ssd1289_init);
+			}
+
+
+
+		} else if (!strcmp(chip, "ssd1351")) {
+			if (!width)
+				width = 128;
+			if (!height)
+				height = 128;
+			setaddrwin = 3;
+			if (init_num == 0) {
+				initp = ssd1351_init;
+				initp_num = ARRAY_SIZE(ssd1351_init);
+			}
+		} else {
+			dev_err(dev, "chip=%s is not supported\n", chip);
+			return -EINVAL;
+		}
+	}
+
+	if (width == 0 || height == 0) {
+		dev_err(dev, "argument(s) missing: width and height has to be set.\n");
+		return -EINVAL;
+	}
+	flex_display.width = width;
+	flex_display.height = height;
+	fbtft_init_dbg(dev, "Display resolution: %dx%d\n", width, height);
+	fbtft_init_dbg(dev, "chip = %s\n", chip ? chip : "not set");
+	fbtft_init_dbg(dev, "setaddrwin = %d\n", setaddrwin);
+	fbtft_init_dbg(dev, "regwidth = %d\n", regwidth);
+	fbtft_init_dbg(dev, "buswidth = %d\n", buswidth);
+
+	info = fbtft_framebuffer_alloc(&flex_display, dev);
+	if (!info)
+		return -ENOMEM;
+
+	par = info->par;
+	if (sdev)
+		par->spi = sdev;
+	else
+		par->pdev = pdev;
+	if (!par->init_sequence)
+		par->init_sequence = initp;
+	par->fbtftops.init_display = fbtft_init_display;
+
+	/* registerwrite functions */
+	switch (regwidth) {
+	case 8:
+		par->fbtftops.write_register = fbtft_write_reg8_bus8;
+		break;
+	case 16:
+		par->fbtftops.write_register = fbtft_write_reg16_bus8;
+		break;
+	default:
+		dev_err(dev, "argument 'regwidth': %d is not supported.\n", regwidth);
+		return -EINVAL;
+	}
+
+	/* bus functions */
+	if (sdev) {
+		par->fbtftops.write = fbtft_write_spi;
+		switch (buswidth) {
+		case 8:
+			par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+			if (!par->startbyte)
+				par->fbtftops.verify_gpios = flexfb_verify_gpios_dc;
+			break;
+		case 9:
+			if (regwidth == 16) {
+				dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", regwidth, buswidth);
+				return -EINVAL;
+			}
+			par->fbtftops.write_register = fbtft_write_reg8_bus9;
+			par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
+			sdev->bits_per_word=9;
+			ret = sdev->master->setup(sdev);
+			if (ret) {
+				dev_warn(dev,
+					"9-bit SPI not available, emulating using 8-bit.\n");
+				sdev->bits_per_word = 8;
+				ret = sdev->master->setup(sdev);
+				if (ret)
+					goto out_release;
+				/* allocate buffer with room for dc bits */
+				par->extra = devm_kzalloc(par->info->device,
+						par->txbuf.len + (par->txbuf.len / 8) + 8,
+						GFP_KERNEL);
+				if (!par->extra) {
+					ret = -ENOMEM;
+					goto out_release;
+				}
+				par->fbtftops.write = fbtft_write_spi_emulate_9;
+			}
+			break;
+		default:
+			dev_err(dev, "argument 'buswidth': %d is not supported with SPI.\n", buswidth);
+			return -EINVAL;
+		}
+	} else {
+		par->fbtftops.verify_gpios = flexfb_verify_gpios_db;
+		switch (buswidth) {
+		case 8:
+			par->fbtftops.write = fbtft_write_gpio8_wr;
+			par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+			break;
+		case 16:
+			par->fbtftops.write_register = fbtft_write_reg16_bus16;
+			if (latched)
+				par->fbtftops.write = fbtft_write_gpio16_wr_latched;
+			else
+				par->fbtftops.write = fbtft_write_gpio16_wr;
+			par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;
+			break;
+		default:
+			dev_err(dev, "argument 'buswidth': %d is not supported with parallel.\n", buswidth);
+			return -EINVAL;
+		}
+	}
+
+	/* set_addr_win function */
+	switch (setaddrwin) {
+	case 0:
+		/* use default */
+		break;
+	case 1:
+		par->fbtftops.set_addr_win = flexfb_set_addr_win_1;
+		break;
+	case 2:
+		par->fbtftops.set_addr_win = flexfb_set_addr_win_2;
+		break;
+	case 3:
+		par->fbtftops.set_addr_win = set_addr_win_3;
+		break;
+	default:
+		dev_err(dev, "argument 'setaddrwin': unknown value %d.\n", setaddrwin);
+		return -EINVAL;
+	}
+
+	if (!nobacklight)
+		par->fbtftops.register_backlight = fbtft_register_backlight;
+
+	ret = fbtft_register_framebuffer(info);
+	if (ret < 0)
+		goto out_release;
+
+	return 0;
+
+out_release:
+	fbtft_framebuffer_release(info);
+
+	return ret;
+}
+
+static int flexfb_remove_common(struct device *dev, struct fb_info *info)
+{
+	struct fbtft_par *par;
+
+	if (!info)
+		return -EINVAL;
+	par = info->par;
+	if (par)
+		fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par,
+			"%s()\n", __func__);
+	fbtft_unregister_framebuffer(info);
+	fbtft_framebuffer_release(info);
+
+	return 0;
+}
+
+static int flexfb_probe_spi(struct spi_device *spi)
+{
+	return flexfb_probe_common(spi, NULL);
+}
+
+static int flexfb_remove_spi(struct spi_device *spi)
+{
+	struct fb_info *info = spi_get_drvdata(spi);
+
+	return flexfb_remove_common(&spi->dev, info);
+}
+
+static int flexfb_probe_pdev(struct platform_device *pdev)
+{
+	return flexfb_probe_common(NULL, pdev);
+}
+
+static int flexfb_remove_pdev(struct platform_device *pdev)
+{
+	struct fb_info *info = platform_get_drvdata(pdev);
+
+	return flexfb_remove_common(&pdev->dev, info);
+}
+
+static struct spi_driver flexfb_spi_driver = {
+	.driver = {
+		.name   = DRVNAME,
+		.owner  = THIS_MODULE,
+	},
+	.probe  = flexfb_probe_spi,
+	.remove = flexfb_remove_spi,
+};
+
+static const struct platform_device_id flexfb_platform_ids[] = {
+	{ "flexpfb", 0 },
+	{ },
+};
+
+static struct platform_driver flexfb_platform_driver = {
+	.driver = {
+		.name   = DRVNAME,
+	},
+	.id_table = flexfb_platform_ids,
+	.probe  = flexfb_probe_pdev,
+	.remove = flexfb_remove_pdev,
+};
+
+static int __init flexfb_init(void)
+{
+	int ret, ret2;
+
+	ret = spi_register_driver(&flexfb_spi_driver);
+	ret2 = platform_driver_register(&flexfb_platform_driver);
+	if (ret < 0)
+		return ret;
+	return ret2;
+}
+
+static void __exit flexfb_exit(void)
+{
+	spi_unregister_driver(&flexfb_spi_driver);
+	platform_driver_unregister(&flexfb_platform_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+module_init(flexfb_init);
+module_exit(flexfb_exit);
+
+MODULE_DESCRIPTION("Generic FB driver for TFT LCD displays");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index d5475b7..017c3b9 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -172,11 +172,11 @@
 	spin_lock_irqsave(&info->dpram_lock, flags);
 	ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, offset);
 	/* check if we want to read upper or lower 32-bit word */
-	if (Index) {
+	if (Index)
 		data = ft1000_read_reg(dev, FT1000_REG_MAG_DPDATAL);
-	} else {
+	else
 		data = ft1000_read_reg(dev, FT1000_REG_MAG_DPDATAH);
-	}
+
 	spin_unlock_irqrestore(&info->dpram_lock, flags);
 
 	return data;
@@ -204,11 +204,11 @@
 	/* Provide mutual exclusive access while reading ASIC registers. */
 	spin_lock_irqsave(&info->dpram_lock, flags);
 	ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, offset);
-	if (Index) {
+	if (Index)
 		ft1000_write_reg(dev, FT1000_REG_MAG_DPDATAL, value);
-	} else {
+	else
 		ft1000_write_reg(dev, FT1000_REG_MAG_DPDATAH, value);
-	}
+
 	spin_unlock_irqrestore(&info->dpram_lock, flags);
 }
 
@@ -440,9 +440,8 @@
 			tempword =
 				ft1000_read_dpram_mag_16(dev, FT1000_MAG_DPRAM_FEFE,
 							 FT1000_MAG_DPRAM_FEFE_INDX);
-			if (tempword == 0xfefe) {
+			if (tempword == 0xfefe)
 				break;
-			}
 			mdelay(20);
 		}
 
@@ -570,12 +569,12 @@
 		pr_debug("hi_ho value = 0x%x\n", tempword);
 		/* Let's perform another check if ho is not detected */
 		if (tempword != ho) {
-			if (info->AsicID == ELECTRABUZZ_ID) {
+			if (info->AsicID == ELECTRABUZZ_ID)
 				tempword = ft1000_read_dpram(dev, FT1000_HI_HO);
-			}
-			else {
-				tempword = ntohs(ft1000_read_dpram_mag_16(dev, FT1000_MAG_HI_HO, FT1000_MAG_HI_HO_INDX));
-			}
+			else
+				tempword = ntohs(ft1000_read_dpram_mag_16(dev,
+							FT1000_MAG_HI_HO,
+							FT1000_MAG_HI_HO_INDX));
 		}
 		if (tempword != ho) {
 			pr_info("heartbeat failed - no ho detected\n");
@@ -621,9 +620,9 @@
 
 		tempword = ft1000_read_reg(dev, FT1000_REG_DOORBELL);
 		/* Let's check doorbell again if fail */
-		if (tempword & FT1000_DB_HB) {
+		if (tempword & FT1000_DB_HB)
 			tempword = ft1000_read_reg(dev, FT1000_REG_DOORBELL);
-		}
+
 		if (tempword & FT1000_DB_HB) {
 			pr_info("heartbeat doorbell not clear by firmware\n");
 			if (info->AsicID == ELECTRABUZZ_ID) {
@@ -686,19 +685,15 @@
 		}
 		/* Let's write hi again if fail */
 		if (tempword != hi) {
-			if (info->AsicID == ELECTRABUZZ_ID) {
+			if (info->AsicID == ELECTRABUZZ_ID)
 				ft1000_write_dpram(dev, FT1000_HI_HO, hi);
-			}
-			else {
+			else
 				ft1000_write_dpram_mag_16(dev, FT1000_MAG_HI_HO, hi_mag, FT1000_MAG_HI_HO_INDX);
-			}
 
-			if (info->AsicID == ELECTRABUZZ_ID) {
+			if (info->AsicID == ELECTRABUZZ_ID)
 				tempword = ft1000_read_dpram(dev, FT1000_HI_HO);
-			}
-			else {
+			else
 				tempword = ntohs(ft1000_read_dpram_mag_16(dev, FT1000_MAG_HI_HO, FT1000_MAG_HI_HO_INDX));
-			}
 
 		}
 
@@ -770,9 +765,8 @@
 
 	size += sizeof(struct pseudo_hdr);
 	/* check for odd byte and increment to 16-bit word align value */
-	if ((size & 0x0001)) {
+	if ((size & 0x0001))
 		size++;
-	}
 	pr_debug("total length = %d\n", size);
 	pr_debug("length = %d\n", ntohs(*ptempbuffer));
 	/*
@@ -915,9 +909,8 @@
 		 * Calculate pseudo header checksum
 		 */
 		tempword = *ppseudohdr++;
-		for (i = 1; i < 7; i++) {
+		for (i = 1; i < 7; i++)
 			tempword ^= *ppseudohdr++;
-		}
 		if ((tempword != *ppseudohdr)) {
 			pr_debug("Pseudo header checksum mismatch\n");
 			/* Drop this message */
@@ -957,12 +950,11 @@
 		u16 wrd;
 	} convert;
 
-	if (info->AsicID == ELECTRABUZZ_ID) {
+	if (info->AsicID == ELECTRABUZZ_ID)
 		tempword = FT1000_DPRAM_RX_BASE+2;
-	}
-	else {
+	else
 		tempword = FT1000_DPRAM_MAG_RX_BASE;
-	}
+
 	if (ft1000_receive_cmd(dev, &cmdbuffer[0], MAX_CMD_SQSIZE, &tempword)) {
 
 		/* Get the message type which is total_len + PSEUDO header + msgtype + message body */
@@ -982,9 +974,8 @@
 				while (tempword & FT1000_DB_DPRAM_TX) {
 					mdelay(5);
 					i++;
-					if (i == 10) {
+					if (i == 10)
 						break;
-					}
 				}
 				ptr =
 					list_entry(info->prov_list.next,
@@ -1039,8 +1030,7 @@
 						info->ConTm = 0;
 					}
 				}
-			}
-			else {
+			} else {
 				pr_debug("Media is down\n");
 				if (info->mediastate == 1) {
 					info->mediastate = 0;
@@ -1105,9 +1095,8 @@
 				mdelay(10);
 				tempword =
 					ft1000_read_reg(dev, FT1000_REG_DOORBELL);
-				if (tempword & FT1000_DB_DPRAM_TX) {
+				if (tempword & FT1000_DB_DPRAM_TX)
 					mdelay(10);
-				}
 			}
 
 			if ((tempword & FT1000_DB_DPRAM_TX) == 0) {
@@ -1134,9 +1123,9 @@
 				ppseudo_hdr->portsrc = 0;
 				/* Calculate new checksum */
 				ppseudo_hdr->checksum = *pmsg++;
-				for (i = 1; i < 7; i++) {
+				for (i = 1; i < 7; i++)
 					ppseudo_hdr->checksum ^= *pmsg++;
-				}
+
 				info->DSPInfoBlk[8] = 0x7200;
 				info->DSPInfoBlk[9] =
 					htons(info->DSPInfoBlklen);
@@ -1156,9 +1145,8 @@
 				mdelay(10);
 				tempword =
 					ft1000_read_reg(dev, FT1000_REG_DOORBELL);
-				if (tempword & FT1000_DB_DPRAM_TX) {
+				if (tempword & FT1000_DB_DPRAM_TX)
 					mdelay(10);
-				}
 			}
 
 			if ((tempword & FT1000_DB_DPRAM_TX) == 0) {
@@ -1184,9 +1172,9 @@
 				ppseudo_hdr->portsrc = 0;
 				/* Calculate new checksum */
 				ppseudo_hdr->checksum = *pmsg++;
-				for (i = 1; i < 7; i++) {
+				for (i = 1; i < 7; i++)
 					ppseudo_hdr->checksum ^= *pmsg++;
-				}
+
 				pmsg = (u16 *)&tempbuffer[16];
 				*pmsg++ = htons(RSP_DRV_ERR_RPT_MSG);
 				*pmsg++ = htons(0x000e);
@@ -1508,9 +1496,8 @@
 			tempword = inw(dev->base_addr + FT1000_REG_MAG_DFSR);
 			pr_debug("FT1000_REG_MAG_DFSR = 0x%x\n", tempword);
 		}
-		if (DrvErrNum) {
+		if (DrvErrNum)
 			pcmcia->PktIntfErr++;
-		}
 	}
 }
 
@@ -1567,9 +1554,9 @@
 	if (skb == NULL) {
 		pr_debug("No Network buffers available\n");
 		/* Read High word to complete 32 bit access */
-		if (info->AsicID == MAGNEMITE_ID) {
+		if (info->AsicID == MAGNEMITE_ID)
 			tempword = ft1000_read_reg(dev, FT1000_REG_MAG_DFRH);
-		}
+
 		ft1000_flush_fifo(dev, 0);
 		info->stats.rx_errors++;
 		return FAILURE;
@@ -1673,9 +1660,8 @@
 	}
 
 	pr_debug("Data passed to Protocol layer:\n");
-	for (i = 0; i < len + 12; i++) {
+	for (i = 0; i < len + 12; i++)
 		pr_debug("Protocol Data: 0x%x\n", *ptemp++);
-	}
 
 	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
@@ -1729,21 +1715,16 @@
 	/* Check if there is room on the FIFO */
 	if (len > ft1000_read_fifo_len(dev)) {
 		udelay(10);
-		if (len > ft1000_read_fifo_len(dev)) {
+		if (len > ft1000_read_fifo_len(dev))
 			udelay(20);
-		}
-		if (len > ft1000_read_fifo_len(dev)) {
+		if (len > ft1000_read_fifo_len(dev))
 			udelay(20);
-		}
-		if (len > ft1000_read_fifo_len(dev)) {
+		if (len > ft1000_read_fifo_len(dev))
 			udelay(20);
-		}
-		if (len > ft1000_read_fifo_len(dev)) {
+		if (len > ft1000_read_fifo_len(dev))
 			udelay(20);
-		}
-		if (len > ft1000_read_fifo_len(dev)) {
+		if (len > ft1000_read_fifo_len(dev))
 			udelay(20);
-		}
 		if (len > ft1000_read_fifo_len(dev)) {
 			pr_debug("Transmit FIFO is full - pkt drop\n");
 			info->stats.tx_errors++;
@@ -1751,11 +1732,11 @@
 		}
 	}
 	/* Create pseudo header and send pseudo/ip to hardware */
-	if (info->AsicID == ELECTRABUZZ_ID) {
+	if (info->AsicID == ELECTRABUZZ_ID)
 		pseudo.blk.length = len;
-	} else {
+	else
 		pseudo.blk.length = ntohs(len);
-	}
+
 	pseudo.blk.source = DSPID;	/* Need to swap to get in correct order */
 	pseudo.blk.destination = HOSTID;
 	pseudo.blk.portdest = NETWORKID;	/* Need to swap to get in correct order */
@@ -1768,9 +1749,8 @@
 	pseudo.blk.qos_class = 0;
 	/* Calculate pseudo header checksum */
 	pseudo.blk.checksum = pseudo.buff[0];
-	for (i = 1; i < 7; i++) {
+	for (i = 1; i < 7; i++)
 		pseudo.blk.checksum ^= pseudo.buff[i];
-	}
 
 	/* Production Mode */
 	if (info->AsicID == ELECTRABUZZ_ID) {
@@ -1835,9 +1815,8 @@
 
 		plong = (u32 *)packet;
 		/* Write PPP type + IP Packet into Downlink FIFO */
-		for (i = 0; i < (len >> 2); i++) {
+		for (i = 0; i < (len >> 2); i++)
 			outl(*plong++, dev->base_addr + FT1000_REG_MAG_UFDR);
-		}
 
 		/* Check for odd alignment */
 		if (len & 0x0003) {
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index d12cfc9..f0ac438 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -332,15 +332,15 @@
 
 	pr_debug("enter card_send_command... size=%d\n", size);
 
+	ret = ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
+	if (ret)
+		return ret;
+
 	commandbuf = kmalloc(size + 2, GFP_KERNEL);
 	if (!commandbuf)
 		return -ENOMEM;
 	memcpy((void *)commandbuf + 2, (void *)ptempbuffer, size);
 
-	ret = ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
-	if (ret)
-		return ret;
-
 	if (temp & 0x0100)
 		usleep_range(900, 1100);
 
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 73eede1..7c4a77b 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -281,7 +281,8 @@
 		icmp6_out.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
 		icmp6_out.icmp6_code = 0;
 		icmp6_out.icmp6_cksum = 0;
-		icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */
+		/* R=0, S=1, O=1 */
+		icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000);
 
 		ns = (struct neighbour_solicitation *)
 			(skb_in->data + mac_header_len +
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
index b5b063a..d1ab996 100644
--- a/drivers/staging/gdm724x/gdm_mux.c
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -220,7 +220,7 @@
 static void do_rx(struct work_struct *work)
 {
 	struct mux_dev *mux_dev =
-		container_of(work, struct mux_dev , work_rx.work);
+		container_of(work, struct mux_dev, work_rx.work);
 	struct mux_rx *r;
 	struct rx_cxt *rx = (struct rx_cxt *)&mux_dev->rx;
 	unsigned long flags;
diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c
index b260e45..819db53 100644
--- a/drivers/staging/gs_fpgaboot/io.c
+++ b/drivers/staging/gs_fpgaboot/io.c
@@ -79,15 +79,6 @@
 /*
  * generic bit swap for xilinx SYSTEMMAP FPGA programming
  */
-static inline unsigned char bitswap(unsigned char s)
-{
-	unsigned char d;
-
-	d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) |
-		((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<5) | ((s&0x01)<<7));
-	return d;
-}
-
 void xl_program_b(int32_t i)
 {
 }
diff --git a/drivers/staging/i2o/Kconfig b/drivers/staging/i2o/Kconfig
new file mode 100644
index 0000000..286c53f
--- /dev/null
+++ b/drivers/staging/i2o/Kconfig
@@ -0,0 +1,120 @@
+menuconfig I2O
+	tristate "I2O device support"
+	depends on PCI
+	---help---
+	  The Intelligent Input/Output (I2O) architecture allows hardware
+	  drivers to be split into two parts: an operating system specific
+	  module called the OSM and an hardware specific module called the
+	  HDM. The OSM can talk to a whole range of HDM's, and ideally the
+	  HDM's are not OS dependent. This allows for the same HDM driver to
+	  be used under different operating systems if the relevant OSM is in
+	  place. In order for this to work, you need to have an I2O interface
+	  adapter card in your computer. This card contains a special I/O
+	  processor (IOP), thus allowing high speeds since the CPU does not
+	  have to deal with I/O.
+
+	  If you say Y here, you will get a choice of interface adapter
+	  drivers and OSM's with the following questions.
+
+	  To compile this support as a module, choose M here: the
+	  modules will be called i2o_core.
+
+	  If unsure, say N.
+
+if I2O
+
+config I2O_LCT_NOTIFY_ON_CHANGES
+	bool "Enable LCT notification"
+	default y
+	---help---
+	  Only say N here if you have a I2O controller from SUN. The SUN
+	  firmware doesn't support LCT notification on changes. If this option
+	  is enabled on such a controller the driver will hang up in a endless
+	  loop. On all other controllers say Y.
+
+	  If unsure, say Y.
+
+config I2O_EXT_ADAPTEC
+	bool "Enable Adaptec extensions"
+	default y
+	---help---
+	  Say Y for support of raidutils for Adaptec I2O controllers. You also
+	  have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
+	  and to "SCSI generic support" under "SCSI device configuration".
+
+config I2O_EXT_ADAPTEC_DMA64
+	bool "Enable 64-bit DMA"
+	depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
+	default y
+	---help---
+	  Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
+	  controllers.
+	  Note: You need at least firmware version 3709.
+
+config I2O_CONFIG
+	tristate "I2O Configuration support"
+	depends on VIRT_TO_BUS
+	---help---
+	  Say Y for support of the configuration interface for the I2O adapters.
+	  If you have a RAID controller from Adaptec and you want to use the
+	  raidutils to manage your RAID array, you have to say Y here.
+
+	  To compile this support as a module, choose M here: the
+	  module will be called i2o_config.
+
+	  Note: If you want to use the new API you have to download the
+	  i2o_config patch from http://i2o.shadowconnect.com/
+
+config I2O_CONFIG_OLD_IOCTL
+	bool "Enable ioctls (OBSOLETE)"
+	depends on I2O_CONFIG
+	default y
+	---help---
+	  Enables old ioctls.
+
+config I2O_BUS
+	tristate "I2O Bus Adapter OSM"
+	---help---
+	  Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
+	  provides access to the busses on the I2O controller. The main purpose
+	  is to rescan the bus to find new devices.
+
+	  To compile this support as a module, choose M here: the
+	  module will be called i2o_bus.
+
+config I2O_BLOCK
+	tristate "I2O Block OSM"
+	depends on BLOCK
+	---help---
+	  Include support for the I2O Block OSM. The Block OSM presents disk
+	  and other structured block devices to the operating system. If you
+	  are using an RAID controller, you could access the array only by
+	  the Block OSM driver. But it is possible to access the single disks
+	  by the SCSI OSM driver, for example to monitor the disks.
+
+	  To compile this support as a module, choose M here: the
+	  module will be called i2o_block.
+
+config I2O_SCSI
+	tristate "I2O SCSI OSM"
+	depends on SCSI
+	---help---
+	  Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
+	  I2O controller. You can use both the SCSI and Block OSM together if
+	  you wish. To access a RAID array, you must use the Block OSM driver.
+	  But you could use the SCSI OSM driver to monitor the single disks.
+
+	  To compile this support as a module, choose M here: the
+	  module will be called i2o_scsi.
+
+config I2O_PROC
+	tristate "I2O /proc support"
+	---help---
+	  If you say Y here and to "/proc file system support", you will be
+	  able to read I2O related information from the virtual directory
+	  /proc/i2o.
+
+	  To compile this support as a module, choose M here: the
+	  module will be called i2o_proc.
+
+endif # I2O
diff --git a/drivers/message/i2o/Makefile b/drivers/staging/i2o/Makefile
similarity index 100%
rename from drivers/message/i2o/Makefile
rename to drivers/staging/i2o/Makefile
diff --git a/drivers/message/i2o/README b/drivers/staging/i2o/README
similarity index 100%
rename from drivers/message/i2o/README
rename to drivers/staging/i2o/README
diff --git a/drivers/message/i2o/README.ioctl b/drivers/staging/i2o/README.ioctl
similarity index 100%
rename from drivers/message/i2o/README.ioctl
rename to drivers/staging/i2o/README.ioctl
diff --git a/drivers/staging/i2o/bus-osm.c b/drivers/staging/i2o/bus-osm.c
new file mode 100644
index 0000000..7aa0339
--- /dev/null
+++ b/drivers/staging/i2o/bus-osm.c
@@ -0,0 +1,176 @@
+/*
+ *	Bus Adapter OSM
+ *
+ *	Copyright (C) 2005	Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *	Fixes/additions:
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *			initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+
+#define OSM_NAME	"bus-osm"
+#define OSM_VERSION	"1.317"
+#define OSM_DESCRIPTION	"I2O Bus Adapter OSM"
+
+static struct i2o_driver i2o_bus_driver;
+
+/* Bus OSM class handling definition */
+static struct i2o_class_id i2o_bus_class_id[] = {
+	{I2O_CLASS_BUS_ADAPTER},
+	{I2O_CLASS_END}
+};
+
+/**
+ *	i2o_bus_scan - Scan the bus for new devices
+ *	@dev: I2O device of the bus, which should be scanned
+ *
+ *	Scans the bus dev for new / removed devices. After the scan a new LCT
+ *	will be fetched automatically.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_bus_scan(struct i2o_device *dev)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return -ETIMEDOUT;
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.
+			tid);
+
+	return i2o_msg_post_wait(dev->iop, msg, 60);
+};
+
+/**
+ *	i2o_bus_store_scan - Scan the I2O Bus Adapter
+ *	@d: device which should be scanned
+ *	@attr: device_attribute
+ *	@buf: output buffer
+ *	@count: buffer size
+ *
+ *	Returns count.
+ */
+static ssize_t i2o_bus_store_scan(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(d);
+	int rc;
+
+	if ((rc = i2o_bus_scan(i2o_dev)))
+		osm_warn("bus scan failed %d\n", rc);
+
+	return count;
+}
+
+/* Bus Adapter OSM device attributes */
+static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
+
+/**
+ *	i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
+ *	@dev: device to verify if it is a I2O Bus Adapter device
+ *
+ *	Because we want all Bus Adapters always return 0.
+ *	Except when we fail.  Then we are sad.
+ *
+ *	Returns 0, except when we fail to excel.
+ */
+static int i2o_bus_probe(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
+	int rc;
+
+	rc = device_create_file(dev, &dev_attr_scan);
+	if (rc)
+		goto err_out;
+
+	osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+	return 0;
+
+err_out:
+	put_device(dev);
+	return rc;
+};
+
+/**
+ *	i2o_bus_remove - remove the I2O Bus Adapter device from the system again
+ *	@dev: I2O Bus Adapter device which should be removed
+ *
+ *	Always returns 0.
+ */
+static int i2o_bus_remove(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+	device_remove_file(dev, &dev_attr_scan);
+
+	put_device(dev);
+
+	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+	return 0;
+};
+
+/* Bus Adapter OSM driver struct */
+static struct i2o_driver i2o_bus_driver = {
+	.name = OSM_NAME,
+	.classes = i2o_bus_class_id,
+	.driver = {
+		   .probe = i2o_bus_probe,
+		   .remove = i2o_bus_remove,
+		   },
+};
+
+/**
+ *	i2o_bus_init - Bus Adapter OSM initialization function
+ *
+ *	Only register the Bus Adapter OSM in the I2O core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_bus_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	/* Register Bus Adapter OSM into I2O core */
+	rc = i2o_driver_register(&i2o_bus_driver);
+	if (rc) {
+		osm_err("Could not register Bus Adapter OSM\n");
+		return rc;
+	}
+
+	return 0;
+};
+
+/**
+ *	i2o_bus_exit - Bus Adapter OSM exit function
+ *
+ *	Unregisters Bus Adapter OSM from I2O core.
+ */
+static void __exit i2o_bus_exit(void)
+{
+	i2o_driver_unregister(&i2o_bus_driver);
+};
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_bus_init);
+module_exit(i2o_bus_exit);
diff --git a/drivers/staging/i2o/config-osm.c b/drivers/staging/i2o/config-osm.c
new file mode 100644
index 0000000..519f52f
--- /dev/null
+++ b/drivers/staging/i2o/config-osm.c
@@ -0,0 +1,90 @@
+/*
+ *	Configuration OSM
+ *
+ *	Copyright (C) 2005	Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *	Fixes/additions:
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *			initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+
+#define OSM_NAME	"config-osm"
+#define OSM_VERSION	"1.323"
+#define OSM_DESCRIPTION	"I2O Configuration OSM"
+
+/* access mode user rw */
+#define S_IWRSR (S_IRUSR | S_IWUSR)
+
+static struct i2o_driver i2o_config_driver;
+
+/* Config OSM driver struct */
+static struct i2o_driver i2o_config_driver = {
+	.name = OSM_NAME,
+};
+
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+#include "i2o_config.c"
+#endif
+
+/**
+ *	i2o_config_init - Configuration OSM initialization function
+ *
+ *	Registers Configuration OSM in the I2O core and if old ioctl's are
+ *	compiled in initialize them.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_config_init(void)
+{
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	if (i2o_driver_register(&i2o_config_driver)) {
+		osm_err("handler register failed.\n");
+		return -EBUSY;
+	}
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+	if (i2o_config_old_init()) {
+		osm_err("old config handler initialization failed\n");
+		i2o_driver_unregister(&i2o_config_driver);
+		return -EBUSY;
+	}
+#endif
+
+	return 0;
+}
+
+/**
+ *	i2o_config_exit - Configuration OSM exit function
+ *
+ *	If old ioctl's are compiled in exit remove them and unregisters
+ *	Configuration OSM from I2O core.
+ */
+static void i2o_config_exit(void)
+{
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+	i2o_config_old_exit();
+#endif
+
+	i2o_driver_unregister(&i2o_config_driver);
+}
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_config_init);
+module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/core.h b/drivers/staging/i2o/core.h
similarity index 100%
rename from drivers/message/i2o/core.h
rename to drivers/staging/i2o/core.h
diff --git a/drivers/staging/i2o/debug.c b/drivers/staging/i2o/debug.c
new file mode 100644
index 0000000..7a16114
--- /dev/null
+++ b/drivers/staging/i2o/debug.c
@@ -0,0 +1,472 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "i2o.h"
+
+static void i2o_report_util_cmd(u8 cmd);
+static void i2o_report_exec_cmd(u8 cmd);
+static void i2o_report_fail_status(u8 req_status, u32 * msg);
+static void i2o_report_common_status(u8 req_status);
+static void i2o_report_common_dsc(u16 detailed_status);
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Report Cmd name, Request status, Detailed Status.
+ */
+void i2o_report_status(const char *severity, const char *str,
+		       struct i2o_message *m)
+{
+	u32 *msg = (u32 *) m;
+	u8 cmd = (msg[1] >> 24) & 0xFF;
+	u8 req_status = (msg[4] >> 24) & 0xFF;
+	u16 detailed_status = msg[4] & 0xFFFF;
+
+	if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
+		return;		// No status in this reply
+
+	printk("%s%s: ", severity, str);
+
+	if (cmd < 0x1F)		// Utility cmd
+		i2o_report_util_cmd(cmd);
+
+	else if (cmd >= 0xA0 && cmd <= 0xEF)	// Executive cmd
+		i2o_report_exec_cmd(cmd);
+	else
+		printk("Cmd = %0#2x, ", cmd);	// Other cmds
+
+	if (msg[0] & MSG_FAIL) {
+		i2o_report_fail_status(req_status, msg);
+		return;
+	}
+
+	i2o_report_common_status(req_status);
+
+	if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
+		i2o_report_common_dsc(detailed_status);
+	else
+		printk(" / DetailedStatus = %0#4x.\n",
+		       detailed_status);
+}
+
+/* Used to dump a message to syslog during debugging */
+void i2o_dump_message(struct i2o_message *m)
+{
+#ifdef DEBUG
+	u32 *msg = (u32 *) m;
+	int i;
+	printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
+	       msg[0] >> 16 & 0xffff, msg);
+	for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
+		printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
+#endif
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following fail status are common to all classes.
+ * The preserved message must be handled in the reply handler.
+ */
+static void i2o_report_fail_status(u8 req_status, u32 * msg)
+{
+	static char *FAIL_STATUS[] = {
+		"0x80",		/* not used */
+		"SERVICE_SUSPENDED",	/* 0x81 */
+		"SERVICE_TERMINATED",	/* 0x82 */
+		"CONGESTION",
+		"FAILURE",
+		"STATE_ERROR",
+		"TIME_OUT",
+		"ROUTING_FAILURE",
+		"INVALID_VERSION",
+		"INVALID_OFFSET",
+		"INVALID_MSG_FLAGS",
+		"FRAME_TOO_SMALL",
+		"FRAME_TOO_LARGE",
+		"INVALID_TARGET_ID",
+		"INVALID_INITIATOR_ID",
+		"INVALID_INITIATOR_CONTEX",	/* 0x8F */
+		"UNKNOWN_FAILURE"	/* 0xFF */
+	};
+
+	if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
+		printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
+		       req_status);
+	else
+		printk("TRANSPORT_%s.\n",
+		       FAIL_STATUS[req_status & 0x0F]);
+
+	/* Dump some details */
+
+	printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
+	       (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+	printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
+	       (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+	printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
+	       msg[5] >> 16, msg[5] & 0xFFF);
+
+	printk(KERN_ERR "  Severity:  0x%02X\n", (msg[4] >> 16) & 0xFF);
+	if (msg[4] & (1 << 16))
+		printk(KERN_DEBUG "(FormatError), "
+		       "this msg can never be delivered/processed.\n");
+	if (msg[4] & (1 << 17))
+		printk(KERN_DEBUG "(PathError), "
+		       "this msg can no longer be delivered/processed.\n");
+	if (msg[4] & (1 << 18))
+		printk(KERN_DEBUG "(PathState), "
+		       "the system state does not allow delivery.\n");
+	if (msg[4] & (1 << 19))
+		printk(KERN_DEBUG
+		       "(Congestion), resources temporarily not available;"
+		       "do not retry immediately.\n");
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following reply status are common to all classes.
+ */
+static void i2o_report_common_status(u8 req_status)
+{
+	static char *REPLY_STATUS[] = {
+		"SUCCESS",
+		"ABORT_DIRTY",
+		"ABORT_NO_DATA_TRANSFER",
+		"ABORT_PARTIAL_TRANSFER",
+		"ERROR_DIRTY",
+		"ERROR_NO_DATA_TRANSFER",
+		"ERROR_PARTIAL_TRANSFER",
+		"PROCESS_ABORT_DIRTY",
+		"PROCESS_ABORT_NO_DATA_TRANSFER",
+		"PROCESS_ABORT_PARTIAL_TRANSFER",
+		"TRANSACTION_ERROR",
+		"PROGRESS_REPORT"
+	};
+
+	if (req_status >= ARRAY_SIZE(REPLY_STATUS))
+		printk("RequestStatus = %0#2x", req_status);
+	else
+		printk("%s", REPLY_STATUS[req_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following detailed status are valid  for executive class,
+ * utility class, DDM class and for transaction error replies.
+ */
+static void i2o_report_common_dsc(u16 detailed_status)
+{
+	static char *COMMON_DSC[] = {
+		"SUCCESS",
+		"0x01",		// not used
+		"BAD_KEY",
+		"TCL_ERROR",
+		"REPLY_BUFFER_FULL",
+		"NO_SUCH_PAGE",
+		"INSUFFICIENT_RESOURCE_SOFT",
+		"INSUFFICIENT_RESOURCE_HARD",
+		"0x08",		// not used
+		"CHAIN_BUFFER_TOO_LARGE",
+		"UNSUPPORTED_FUNCTION",
+		"DEVICE_LOCKED",
+		"DEVICE_RESET",
+		"INAPPROPRIATE_FUNCTION",
+		"INVALID_INITIATOR_ADDRESS",
+		"INVALID_MESSAGE_FLAGS",
+		"INVALID_OFFSET",
+		"INVALID_PARAMETER",
+		"INVALID_REQUEST",
+		"INVALID_TARGET_ADDRESS",
+		"MESSAGE_TOO_LARGE",
+		"MESSAGE_TOO_SMALL",
+		"MISSING_PARAMETER",
+		"TIMEOUT",
+		"UNKNOWN_ERROR",
+		"UNKNOWN_FUNCTION",
+		"UNSUPPORTED_VERSION",
+		"DEVICE_BUSY",
+		"DEVICE_NOT_AVAILABLE"
+	};
+
+	if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
+		printk(" / DetailedStatus = %0#4x.\n",
+		       detailed_status);
+	else
+		printk(" / %s.\n", COMMON_DSC[detailed_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_util_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_UTIL_NOP:
+		printk("UTIL_NOP, ");
+		break;
+	case I2O_CMD_UTIL_ABORT:
+		printk("UTIL_ABORT, ");
+		break;
+	case I2O_CMD_UTIL_CLAIM:
+		printk("UTIL_CLAIM, ");
+		break;
+	case I2O_CMD_UTIL_RELEASE:
+		printk("UTIL_CLAIM_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_CONFIG_DIALOG:
+		printk("UTIL_CONFIG_DIALOG, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RESERVE:
+		printk("UTIL_DEVICE_RESERVE, ");
+		break;
+	case I2O_CMD_UTIL_DEVICE_RELEASE:
+		printk("UTIL_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_ACK:
+		printk("UTIL_EVENT_ACKNOWLEDGE, ");
+		break;
+	case I2O_CMD_UTIL_EVT_REGISTER:
+		printk("UTIL_EVENT_REGISTER, ");
+		break;
+	case I2O_CMD_UTIL_LOCK:
+		printk("UTIL_LOCK, ");
+		break;
+	case I2O_CMD_UTIL_LOCK_RELEASE:
+		printk("UTIL_LOCK_RELEASE, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_GET:
+		printk("UTIL_PARAMS_GET, ");
+		break;
+	case I2O_CMD_UTIL_PARAMS_SET:
+		printk("UTIL_PARAMS_SET, ");
+		break;
+	case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
+		printk("UTIL_REPLY_FAULT_NOTIFY, ");
+		break;
+	default:
+		printk("Cmd = %0#2x, ", cmd);
+	}
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_exec_cmd(u8 cmd)
+{
+	switch (cmd) {
+	case I2O_CMD_ADAPTER_ASSIGN:
+		printk("EXEC_ADAPTER_ASSIGN, ");
+		break;
+	case I2O_CMD_ADAPTER_READ:
+		printk("EXEC_ADAPTER_READ, ");
+		break;
+	case I2O_CMD_ADAPTER_RELEASE:
+		printk("EXEC_ADAPTER_RELEASE, ");
+		break;
+	case I2O_CMD_BIOS_INFO_SET:
+		printk("EXEC_BIOS_INFO_SET, ");
+		break;
+	case I2O_CMD_BOOT_DEVICE_SET:
+		printk("EXEC_BOOT_DEVICE_SET, ");
+		break;
+	case I2O_CMD_CONFIG_VALIDATE:
+		printk("EXEC_CONFIG_VALIDATE, ");
+		break;
+	case I2O_CMD_CONN_SETUP:
+		printk("EXEC_CONN_SETUP, ");
+		break;
+	case I2O_CMD_DDM_DESTROY:
+		printk("EXEC_DDM_DESTROY, ");
+		break;
+	case I2O_CMD_DDM_ENABLE:
+		printk("EXEC_DDM_ENABLE, ");
+		break;
+	case I2O_CMD_DDM_QUIESCE:
+		printk("EXEC_DDM_QUIESCE, ");
+		break;
+	case I2O_CMD_DDM_RESET:
+		printk("EXEC_DDM_RESET, ");
+		break;
+	case I2O_CMD_DDM_SUSPEND:
+		printk("EXEC_DDM_SUSPEND, ");
+		break;
+	case I2O_CMD_DEVICE_ASSIGN:
+		printk("EXEC_DEVICE_ASSIGN, ");
+		break;
+	case I2O_CMD_DEVICE_RELEASE:
+		printk("EXEC_DEVICE_RELEASE, ");
+		break;
+	case I2O_CMD_HRT_GET:
+		printk("EXEC_HRT_GET, ");
+		break;
+	case I2O_CMD_ADAPTER_CLEAR:
+		printk("EXEC_IOP_CLEAR, ");
+		break;
+	case I2O_CMD_ADAPTER_CONNECT:
+		printk("EXEC_IOP_CONNECT, ");
+		break;
+	case I2O_CMD_ADAPTER_RESET:
+		printk("EXEC_IOP_RESET, ");
+		break;
+	case I2O_CMD_LCT_NOTIFY:
+		printk("EXEC_LCT_NOTIFY, ");
+		break;
+	case I2O_CMD_OUTBOUND_INIT:
+		printk("EXEC_OUTBOUND_INIT, ");
+		break;
+	case I2O_CMD_PATH_ENABLE:
+		printk("EXEC_PATH_ENABLE, ");
+		break;
+	case I2O_CMD_PATH_QUIESCE:
+		printk("EXEC_PATH_QUIESCE, ");
+		break;
+	case I2O_CMD_PATH_RESET:
+		printk("EXEC_PATH_RESET, ");
+		break;
+	case I2O_CMD_STATIC_MF_CREATE:
+		printk("EXEC_STATIC_MF_CREATE, ");
+		break;
+	case I2O_CMD_STATIC_MF_RELEASE:
+		printk("EXEC_STATIC_MF_RELEASE, ");
+		break;
+	case I2O_CMD_STATUS_GET:
+		printk("EXEC_STATUS_GET, ");
+		break;
+	case I2O_CMD_SW_DOWNLOAD:
+		printk("EXEC_SW_DOWNLOAD, ");
+		break;
+	case I2O_CMD_SW_UPLOAD:
+		printk("EXEC_SW_UPLOAD, ");
+		break;
+	case I2O_CMD_SW_REMOVE:
+		printk("EXEC_SW_REMOVE, ");
+		break;
+	case I2O_CMD_SYS_ENABLE:
+		printk("EXEC_SYS_ENABLE, ");
+		break;
+	case I2O_CMD_SYS_MODIFY:
+		printk("EXEC_SYS_MODIFY, ");
+		break;
+	case I2O_CMD_SYS_QUIESCE:
+		printk("EXEC_SYS_QUIESCE, ");
+		break;
+	case I2O_CMD_SYS_TAB_SET:
+		printk("EXEC_SYS_TAB_SET, ");
+		break;
+	default:
+		printk("Cmd = %#02x, ", cmd);
+	}
+}
+
+void i2o_debug_state(struct i2o_controller *c)
+{
+	printk(KERN_INFO "%s: State = ", c->name);
+	switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
+	case 0x01:
+		printk("INIT\n");
+		break;
+	case 0x02:
+		printk("RESET\n");
+		break;
+	case 0x04:
+		printk("HOLD\n");
+		break;
+	case 0x05:
+		printk("READY\n");
+		break;
+	case 0x08:
+		printk("OPERATIONAL\n");
+		break;
+	case 0x10:
+		printk("FAILED\n");
+		break;
+	case 0x11:
+		printk("FAULTED\n");
+		break;
+	default:
+		printk("%x (unknown !!)\n",
+		       ((i2o_status_block *) c->status_block.virt)->iop_state);
+	}
+};
+
+void i2o_dump_hrt(struct i2o_controller *c)
+{
+	u32 *rows = (u32 *) c->hrt.virt;
+	u8 *p = (u8 *) c->hrt.virt;
+	u8 *d;
+	int count;
+	int length;
+	int i;
+	int state;
+
+	if (p[3] != 0) {
+		printk(KERN_ERR
+		       "%s: HRT table for controller is too new a version.\n",
+		       c->name);
+		return;
+	}
+
+	count = p[0] | (p[1] << 8);
+	length = p[2];
+
+	printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+	       c->name, count, length << 2);
+
+	rows += 2;
+
+	for (i = 0; i < count; i++) {
+		printk(KERN_INFO "Adapter %08X: ", rows[0]);
+		p = (u8 *) (rows + 1);
+		d = (u8 *) (rows + 2);
+		state = p[1] << 8 | p[0];
+
+		printk("TID %04X:[", state & 0xFFF);
+		state >>= 12;
+		if (state & (1 << 0))
+			printk("H");	/* Hidden */
+		if (state & (1 << 2)) {
+			printk("P");	/* Present */
+			if (state & (1 << 1))
+				printk("C");	/* Controlled */
+		}
+		if (state > 9)
+			printk("*");	/* Hard */
+
+		printk("]:");
+
+		switch (p[3] & 0xFFFF) {
+		case 0:
+			/* Adapter private bus - easy */
+			printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
+			       d[1] << 8 | d[0], *(u32 *) (d + 4));
+			break;
+		case 1:
+			/* ISA bus */
+			printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
+			       d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
+			break;
+
+		case 2:	/* EISA bus */
+			printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+			       p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+			break;
+
+		case 3:	/* MCA bus */
+			printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
+			       d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+			break;
+
+		case 4:	/* PCI bus */
+			printk("PCI %d: Bus %d Device %d Function %d", p[2],
+			       d[2], d[1], d[0]);
+			break;
+
+		case 0x80:	/* Other */
+		default:
+			printk("Unsupported bus type.");
+			break;
+		}
+		printk("\n");
+		rows += length;
+	}
+}
+
+EXPORT_SYMBOL(i2o_dump_message);
diff --git a/drivers/staging/i2o/device.c b/drivers/staging/i2o/device.c
new file mode 100644
index 0000000..2af2255
--- /dev/null
+++ b/drivers/staging/i2o/device.c
@@ -0,0 +1,594 @@
+/*
+ *	Functions to handle I2O devices
+ *
+ *	Copyright (C) 2004	Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *	Fixes/additions:
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *			initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/**
+ *	i2o_device_issue_claim - claim or release a device
+ *	@dev: I2O device to claim or release
+ *	@cmd: claim or release command
+ *	@type: type of claim
+ *
+ *	Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
+ *	is set by cmd. dev is the I2O device which should be claim or
+ *	released and the type is the claim type (see the I2O spec).
+ *
+ *	Returs 0 on success or negative error code on failure.
+ */
+static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
+					 u32 type)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid);
+	msg->body[0] = cpu_to_le32(type);
+
+	return i2o_msg_post_wait(dev->iop, msg, 60);
+}
+
+/**
+ *	i2o_device_claim - claim a device for use by an OSM
+ *	@dev: I2O device to claim
+ *
+ *	Do the leg work to assign a device to a given OSM. If the claim succeeds,
+ *	the owner is the primary. If the attempt fails a negative errno code
+ *	is returned. On success zero is returned.
+ */
+int i2o_device_claim(struct i2o_device *dev)
+{
+	int rc = 0;
+
+	mutex_lock(&dev->lock);
+
+	rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
+	if (!rc)
+		pr_debug("i2o: claim of device %d succeeded\n",
+			 dev->lct_data.tid);
+	else
+		pr_debug("i2o: claim of device %d failed %d\n",
+			 dev->lct_data.tid, rc);
+
+	mutex_unlock(&dev->lock);
+
+	return rc;
+}
+
+/**
+ *	i2o_device_claim_release - release a device that the OSM is using
+ *	@dev: device to release
+ *
+ *	Drop a claim by an OSM on a given I2O device.
+ *
+ *	AC - some devices seem to want to refuse an unclaim until they have
+ *	finished internal processing. It makes sense since you don't want a
+ *	new device to go reconfiguring the entire system until you are done.
+ *	Thus we are prepared to wait briefly.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_claim_release(struct i2o_device *dev)
+{
+	int tries;
+	int rc = 0;
+
+	mutex_lock(&dev->lock);
+
+	/*
+	 *      If the controller takes a nonblocking approach to
+	 *      releases we have to sleep/poll for a few times.
+	 */
+	for (tries = 0; tries < 10; tries++) {
+		rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
+					    I2O_CLAIM_PRIMARY);
+		if (!rc)
+			break;
+
+		ssleep(1);
+	}
+
+	if (!rc)
+		pr_debug("i2o: claim release of device %d succeeded\n",
+			 dev->lct_data.tid);
+	else
+		pr_debug("i2o: claim release of device %d failed %d\n",
+			 dev->lct_data.tid, rc);
+
+	mutex_unlock(&dev->lock);
+
+	return rc;
+}
+
+/**
+ *	i2o_device_release - release the memory for a I2O device
+ *	@dev: I2O device which should be released
+ *
+ *	Release the allocated memory. This function is called if refcount of
+ *	device reaches 0 automatically.
+ */
+static void i2o_device_release(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+	pr_debug("i2o: device %s released\n", dev_name(dev));
+
+	kfree(i2o_dev);
+}
+
+/**
+ *	class_id_show - Displays class id of I2O device
+ *	@dev: device of which the class id should be displayed
+ *	@attr: pointer to device attribute
+ *	@buf: buffer into which the class id should be printed
+ *
+ *	Returns the number of bytes which are printed into the buffer.
+ */
+static ssize_t class_id_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+	sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id);
+	return strlen(buf) + 1;
+}
+static DEVICE_ATTR_RO(class_id);
+
+/**
+ *	tid_show - Displays TID of I2O device
+ *	@dev: device of which the TID should be displayed
+ *	@attr: pointer to device attribute
+ *	@buf: buffer into which the TID should be printed
+ *
+ *	Returns the number of bytes which are printed into the buffer.
+ */
+static ssize_t tid_show(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+	sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid);
+	return strlen(buf) + 1;
+}
+static DEVICE_ATTR_RO(tid);
+
+/* I2O device attributes */
+static struct attribute *i2o_device_attrs[] = {
+	&dev_attr_class_id.attr,
+	&dev_attr_tid.attr,
+	NULL,
+};
+
+static const struct attribute_group i2o_device_group = {
+	.attrs = i2o_device_attrs,
+};
+
+const struct attribute_group *i2o_device_groups[] = {
+	&i2o_device_group,
+	NULL,
+};
+
+/**
+ *	i2o_device_alloc - Allocate a I2O device and initialize it
+ *
+ *	Allocate the memory for a I2O device and initialize locks and lists
+ *
+ *	Returns the allocated I2O device or a negative error code if the device
+ *	could not be allocated.
+ */
+static struct i2o_device *i2o_device_alloc(void)
+{
+	struct i2o_device *dev;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&dev->list);
+	mutex_init(&dev->lock);
+
+	dev->device.bus = &i2o_bus_type;
+	dev->device.release = &i2o_device_release;
+
+	return dev;
+}
+
+/**
+ *	i2o_device_add - allocate a new I2O device and add it to the IOP
+ *	@c: I2O controller that the device is on
+ *	@entry: LCT entry of the I2O device
+ *
+ *	Allocate a new I2O device and initialize it with the LCT entry. The
+ *	device is appended to the device list of the controller.
+ *
+ *	Returns zero on success, or a -ve errno.
+ */
+static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
+{
+	struct i2o_device *i2o_dev, *tmp;
+	int rc;
+
+	i2o_dev = i2o_device_alloc();
+	if (IS_ERR(i2o_dev)) {
+		printk(KERN_ERR "i2o: unable to allocate i2o device\n");
+		return PTR_ERR(i2o_dev);
+	}
+
+	i2o_dev->lct_data = *entry;
+
+	dev_set_name(&i2o_dev->device, "%d:%03x", c->unit,
+		     i2o_dev->lct_data.tid);
+
+	i2o_dev->iop = c;
+	i2o_dev->device.parent = &c->device;
+
+	rc = device_register(&i2o_dev->device);
+	if (rc)
+		goto err;
+
+	list_add_tail(&i2o_dev->list, &c->devices);
+
+	/* create user entries for this device */
+	tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
+	if (tmp && (tmp != i2o_dev)) {
+		rc = sysfs_create_link(&i2o_dev->device.kobj,
+				       &tmp->device.kobj, "user");
+		if (rc)
+			goto unreg_dev;
+	}
+
+	/* create user entries referring to this device */
+	list_for_each_entry(tmp, &c->devices, list)
+	    if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+		&& (tmp != i2o_dev)) {
+		rc = sysfs_create_link(&tmp->device.kobj,
+				       &i2o_dev->device.kobj, "user");
+		if (rc)
+			goto rmlink1;
+	}
+
+	/* create parent entries for this device */
+	tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
+	if (tmp && (tmp != i2o_dev)) {
+		rc = sysfs_create_link(&i2o_dev->device.kobj,
+				       &tmp->device.kobj, "parent");
+		if (rc)
+			goto rmlink1;
+	}
+
+	/* create parent entries referring to this device */
+	list_for_each_entry(tmp, &c->devices, list)
+	    if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+		&& (tmp != i2o_dev)) {
+		rc = sysfs_create_link(&tmp->device.kobj,
+				       &i2o_dev->device.kobj, "parent");
+		if (rc)
+			goto rmlink2;
+	}
+
+	i2o_driver_notify_device_add_all(i2o_dev);
+
+	pr_debug("i2o: device %s added\n", dev_name(&i2o_dev->device));
+
+	return 0;
+
+rmlink2:
+	/* If link creating failed halfway, we loop whole list to cleanup.
+	 * And we don't care wrong removing of link, because sysfs_remove_link
+	 * will take care of it.
+	 */
+	list_for_each_entry(tmp, &c->devices, list) {
+		if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+			sysfs_remove_link(&tmp->device.kobj, "parent");
+	}
+	sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+rmlink1:
+	list_for_each_entry(tmp, &c->devices, list)
+		if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+			sysfs_remove_link(&tmp->device.kobj, "user");
+	sysfs_remove_link(&i2o_dev->device.kobj, "user");
+unreg_dev:
+	list_del(&i2o_dev->list);
+	device_unregister(&i2o_dev->device);
+err:
+	kfree(i2o_dev);
+	return rc;
+}
+
+/**
+ *	i2o_device_remove - remove an I2O device from the I2O core
+ *	@i2o_dev: I2O device which should be released
+ *
+ *	Is used on I2O controller removal or LCT modification, when the device
+ *	is removed from the system. Note that the device could still hang
+ *	around until the refcount reaches 0.
+ */
+void i2o_device_remove(struct i2o_device *i2o_dev)
+{
+	struct i2o_device *tmp;
+	struct i2o_controller *c = i2o_dev->iop;
+
+	i2o_driver_notify_device_remove_all(i2o_dev);
+
+	sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+	sysfs_remove_link(&i2o_dev->device.kobj, "user");
+
+	list_for_each_entry(tmp, &c->devices, list) {
+		if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+			sysfs_remove_link(&tmp->device.kobj, "parent");
+		if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+			sysfs_remove_link(&tmp->device.kobj, "user");
+	}
+	list_del(&i2o_dev->list);
+
+	device_unregister(&i2o_dev->device);
+}
+
+/**
+ *	i2o_device_parse_lct - Parse a previously fetched LCT and create devices
+ *	@c: I2O controller from which the LCT should be parsed.
+ *
+ *	The Logical Configuration Table tells us what we can talk to on the
+ *	board. For every entry we create an I2O device, which is registered in
+ *	the I2O core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_parse_lct(struct i2o_controller *c)
+{
+	struct i2o_device *dev, *tmp;
+	i2o_lct *lct;
+	u32 *dlct = c->dlct.virt;
+	int max = 0, i = 0;
+	u16 table_size;
+	u32 buf;
+
+	mutex_lock(&c->lct_lock);
+
+	kfree(c->lct);
+
+	buf = le32_to_cpu(*dlct++);
+	table_size = buf & 0xffff;
+
+	lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL);
+	if (!lct) {
+		mutex_unlock(&c->lct_lock);
+		return -ENOMEM;
+	}
+
+	lct->lct_ver = buf >> 28;
+	lct->boot_tid = buf >> 16 & 0xfff;
+	lct->table_size = table_size;
+	lct->change_ind = le32_to_cpu(*dlct++);
+	lct->iop_flags = le32_to_cpu(*dlct++);
+
+	table_size -= 3;
+
+	pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max,
+		 lct->table_size);
+
+	while (table_size > 0) {
+		i2o_lct_entry *entry = &lct->lct_entry[max];
+		int found = 0;
+
+		buf = le32_to_cpu(*dlct++);
+		entry->entry_size = buf & 0xffff;
+		entry->tid = buf >> 16 & 0xfff;
+
+		entry->change_ind = le32_to_cpu(*dlct++);
+		entry->device_flags = le32_to_cpu(*dlct++);
+
+		buf = le32_to_cpu(*dlct++);
+		entry->class_id = buf & 0xfff;
+		entry->version = buf >> 12 & 0xf;
+		entry->vendor_id = buf >> 16;
+
+		entry->sub_class = le32_to_cpu(*dlct++);
+
+		buf = le32_to_cpu(*dlct++);
+		entry->user_tid = buf & 0xfff;
+		entry->parent_tid = buf >> 12 & 0xfff;
+		entry->bios_info = buf >> 24;
+
+		memcpy(&entry->identity_tag, dlct, 8);
+		dlct += 2;
+
+		entry->event_capabilities = le32_to_cpu(*dlct++);
+
+		/* add new devices, which are new in the LCT */
+		list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+			if (entry->tid == dev->lct_data.tid) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			i2o_device_add(c, entry);
+
+		table_size -= 9;
+		max++;
+	}
+
+	/* remove devices, which are not in the LCT anymore */
+	list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+		int found = 0;
+
+		for (i = 0; i < max; i++) {
+			if (lct->lct_entry[i].tid == dev->lct_data.tid) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			i2o_device_remove(dev);
+	}
+
+	mutex_unlock(&c->lct_lock);
+
+	return 0;
+}
+
+/*
+ *	Run time support routines
+ */
+
+/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *	This function can be used for all UtilParamsGet/Set operations.
+ *	The OperationList is given in oplist-buffer,
+ *	and results are returned in reslist-buffer.
+ *	Note that the minimum sized reslist is 8 bytes and contains
+ *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
+		   int oplen, void *reslist, int reslen)
+{
+	struct i2o_message *msg;
+	int i = 0;
+	int rc;
+	struct i2o_dma res;
+	struct i2o_controller *c = i2o_dev->iop;
+	struct device *dev = &c->pdev->dev;
+
+	res.virt = NULL;
+
+	if (i2o_dma_alloc(dev, &res, reslen))
+		return -ENOMEM;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg)) {
+		i2o_dma_free(dev, &res);
+		return PTR_ERR(msg);
+	}
+
+	i = 0;
+	msg->u.head[1] =
+	    cpu_to_le32(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid);
+	msg->body[i++] = cpu_to_le32(0x00000000);
+	msg->body[i++] = cpu_to_le32(0x4C000000 | oplen);	/* OperationList */
+	memcpy(&msg->body[i], oplist, oplen);
+	i += (oplen / 4 + (oplen % 4 ? 1 : 0));
+	msg->body[i++] = cpu_to_le32(0xD0000000 | res.len);	/* ResultList */
+	msg->body[i++] = cpu_to_le32(res.phys);
+
+	msg->u.head[0] =
+	    cpu_to_le32(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
+			SGL_OFFSET_5);
+
+	rc = i2o_msg_post_wait_mem(c, msg, 10, &res);
+
+	/* This only looks like a memory leak - don't "fix" it. */
+	if (rc == -ETIMEDOUT)
+		return rc;
+
+	memcpy(reslist, res.virt, res.len);
+	i2o_dma_free(dev, &res);
+
+	return rc;
+}
+
+/*
+ *	 Query one field group value or a whole scalar group.
+ */
+int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
+		       void *buf, int buflen)
+{
+	u32 opblk[] = { cpu_to_le32(0x00000001),
+		cpu_to_le32((u16) group << 16 | I2O_PARAMS_FIELD_GET),
+		cpu_to_le32((s16) field << 16 | 0x00000001)
+	};
+	u8 *resblk;		/* 8 bytes for header */
+	int rc;
+
+	resblk = kmalloc(buflen + 8, GFP_KERNEL);
+	if (!resblk)
+		return -ENOMEM;
+
+	rc = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+			    sizeof(opblk), resblk, buflen + 8);
+
+	memcpy(buf, resblk + 8, buflen);	/* cut off header */
+
+	kfree(resblk);
+
+	return rc;
+}
+
+/*
+ *	if oper == I2O_PARAMS_TABLE_GET, get from all rows
+ *		if fieldcount == -1 return all fields
+ *			ibuf and ibuflen are unused (use NULL, 0)
+ *		else return specific fields
+ *			ibuf contains fieldindexes
+ *
+ *	if oper == I2O_PARAMS_LIST_GET, get from specific rows
+ *		if fieldcount == -1 return all fields
+ *			ibuf contains rowcount, keyvalues
+ *		else return specific fields
+ *			fieldcount is # of fieldindexes
+ *			ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *	You could also use directly function i2o_issue_params().
+ */
+int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
+		       int fieldcount, void *ibuf, int ibuflen, void *resblk,
+		       int reslen)
+{
+	u16 *opblk;
+	int size;
+
+	size = 10 + ibuflen;
+	if (size % 4)
+		size += 4 - size % 4;
+
+	opblk = kmalloc(size, GFP_KERNEL);
+	if (opblk == NULL) {
+		printk(KERN_ERR "i2o: no memory for query buffer.\n");
+		return -ENOMEM;
+	}
+
+	opblk[0] = 1;		/* operation count */
+	opblk[1] = 0;		/* pad */
+	opblk[2] = oper;
+	opblk[3] = group;
+	opblk[4] = fieldcount;
+	memcpy(opblk + 5, ibuf, ibuflen);	/* other params */
+
+	size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+			      size, resblk, reslen);
+
+	kfree(opblk);
+	if (size > reslen)
+		return reslen;
+
+	return size;
+}
+
+EXPORT_SYMBOL(i2o_device_claim);
+EXPORT_SYMBOL(i2o_device_claim_release);
+EXPORT_SYMBOL(i2o_parm_field_get);
+EXPORT_SYMBOL(i2o_parm_table_get);
+EXPORT_SYMBOL(i2o_parm_issue);
diff --git a/drivers/staging/i2o/driver.c b/drivers/staging/i2o/driver.c
new file mode 100644
index 0000000..111c3ed
--- /dev/null
+++ b/drivers/staging/i2o/driver.c
@@ -0,0 +1,382 @@
+/*
+ *	Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
+ *
+ *	Copyright (C) 2004	Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ *	Fixes/additions:
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *			initial version.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include "i2o.h"
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+#define OSM_NAME	"i2o"
+
+/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
+static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
+module_param_named(max_drivers, i2o_max_drivers, uint, 0);
+MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
+
+/* I2O drivers lock and array */
+static spinlock_t i2o_drivers_lock;
+static struct i2o_driver **i2o_drivers;
+
+/**
+ *	i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM)
+ *	@dev: device which should be verified
+ *	@drv: the driver to match against
+ *
+ *	Used by the bus to check if the driver wants to handle the device.
+ *
+ *	Returns 1 if the class ids of the driver match the class id of the
+ *	device, otherwise 0.
+ */
+static int i2o_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	struct i2o_driver *i2o_drv = to_i2o_driver(drv);
+	struct i2o_class_id *ids = i2o_drv->classes;
+
+	if (ids)
+		while (ids->class_id != I2O_CLASS_END) {
+			if (ids->class_id == i2o_dev->lct_data.class_id)
+				return 1;
+			ids++;
+		}
+	return 0;
+};
+
+/* I2O bus type */
+struct bus_type i2o_bus_type = {
+	.name = "i2o",
+	.match = i2o_bus_match,
+	.dev_groups = i2o_device_groups,
+};
+
+/**
+ *	i2o_driver_register - Register a I2O driver (OSM) in the I2O core
+ *	@drv: I2O driver which should be registered
+ *
+ *	Registers the OSM drv in the I2O core and creates an event queues if
+ *	necessary.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_driver_register(struct i2o_driver *drv)
+{
+	struct i2o_controller *c;
+	int i;
+	int rc = 0;
+	unsigned long flags;
+
+	osm_debug("Register driver %s\n", drv->name);
+
+	if (drv->event) {
+		drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
+						   drv->name);
+		if (!drv->event_queue) {
+			osm_err("Could not initialize event queue for driver "
+				"%s\n", drv->name);
+			return -EFAULT;
+		}
+		osm_debug("Event queue initialized for driver %s\n", drv->name);
+	} else
+		drv->event_queue = NULL;
+
+	drv->driver.name = drv->name;
+	drv->driver.bus = &i2o_bus_type;
+
+	spin_lock_irqsave(&i2o_drivers_lock, flags);
+
+	for (i = 0; i2o_drivers[i]; i++)
+		if (i >= i2o_max_drivers) {
+			osm_err("too many drivers registered, increase "
+				"max_drivers\n");
+			spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+			rc = -EFAULT;
+			goto out;
+		}
+
+	drv->context = i;
+	i2o_drivers[i] = drv;
+
+	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+	osm_debug("driver %s gets context id %d\n", drv->name, drv->context);
+
+	list_for_each_entry(c, &i2o_controllers, list) {
+		struct i2o_device *i2o_dev;
+
+		i2o_driver_notify_controller_add(drv, c);
+		list_for_each_entry(i2o_dev, &c->devices, list)
+		    i2o_driver_notify_device_add(drv, i2o_dev);
+	}
+
+	rc = driver_register(&drv->driver);
+	if (rc)
+		goto out;
+
+	return 0;
+out:
+	if (drv->event_queue) {
+		destroy_workqueue(drv->event_queue);
+		drv->event_queue = NULL;
+	}
+
+	return rc;
+};
+
+/**
+ *	i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
+ *	@drv: I2O driver which should be unregistered
+ *
+ *	Unregisters the OSM drv from the I2O core and cleanup event queues if
+ *	necessary.
+ */
+void i2o_driver_unregister(struct i2o_driver *drv)
+{
+	struct i2o_controller *c;
+	unsigned long flags;
+
+	osm_debug("unregister driver %s\n", drv->name);
+
+	driver_unregister(&drv->driver);
+
+	list_for_each_entry(c, &i2o_controllers, list) {
+		struct i2o_device *i2o_dev;
+
+		list_for_each_entry(i2o_dev, &c->devices, list)
+		    i2o_driver_notify_device_remove(drv, i2o_dev);
+
+		i2o_driver_notify_controller_remove(drv, c);
+	}
+
+	spin_lock_irqsave(&i2o_drivers_lock, flags);
+	i2o_drivers[drv->context] = NULL;
+	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+	if (drv->event_queue) {
+		destroy_workqueue(drv->event_queue);
+		drv->event_queue = NULL;
+		osm_debug("event queue removed for %s\n", drv->name);
+	}
+};
+
+/**
+ *	i2o_driver_dispatch - dispatch an I2O reply message
+ *	@c: I2O controller of the message
+ *	@m: I2O message number
+ *
+ *	The reply is delivered to the driver from which the original message
+ *	was. This function is only called from interrupt context.
+ *
+ *	Returns 0 on success and the message should not be flushed. Returns > 0
+ *	on success and if the message should be flushed afterwords. Returns
+ *	negative error code on failure (the message will be flushed too).
+ */
+int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
+{
+	struct i2o_driver *drv;
+	struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
+	u32 context = le32_to_cpu(msg->u.s.icntxt);
+	unsigned long flags;
+
+	if (unlikely(context >= i2o_max_drivers)) {
+		osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+			 context);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&i2o_drivers_lock, flags);
+	drv = i2o_drivers[context];
+	spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+	if (unlikely(!drv)) {
+		osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+			 context);
+		return -EIO;
+	}
+
+	if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
+		struct i2o_device *dev, *tmp;
+		struct i2o_event *evt;
+		u16 size;
+		u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
+
+		osm_debug("event received from device %d\n", tid);
+
+		if (!drv->event)
+			return -EIO;
+
+		/* cut of header from message size (in 32-bit words) */
+		size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
+
+		evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
+		if (!evt)
+			return -ENOMEM;
+
+		evt->size = size;
+		evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
+		evt->event_indicator = le32_to_cpu(msg->body[0]);
+		memcpy(&evt->data, &msg->body[1], size * 4);
+
+		list_for_each_entry_safe(dev, tmp, &c->devices, list)
+		    if (dev->lct_data.tid == tid) {
+			evt->i2o_dev = dev;
+			break;
+		}
+
+		INIT_WORK(&evt->work, drv->event);
+		queue_work(drv->event_queue, &evt->work);
+		return 1;
+	}
+
+	if (unlikely(!drv->reply)) {
+		osm_debug("%s: Reply to driver %s, but no reply function"
+			  " defined!\n", c->name, drv->name);
+		return -EIO;
+	}
+
+	return drv->reply(c, m, msg);
+}
+
+/**
+ *	i2o_driver_notify_controller_add_all - Send notify of added controller
+ *	@c: newly added controller
+ *
+ *	Send notifications to all registered drivers that a new controller was
+ *	added.
+ */
+void i2o_driver_notify_controller_add_all(struct i2o_controller *c)
+{
+	int i;
+	struct i2o_driver *drv;
+
+	for (i = 0; i < i2o_max_drivers; i++) {
+		drv = i2o_drivers[i];
+
+		if (drv)
+			i2o_driver_notify_controller_add(drv, c);
+	}
+}
+
+/**
+ *	i2o_driver_notify_controller_remove_all - Send notify of removed controller
+ *	@c: controller that is being removed
+ *
+ *	Send notifications to all registered drivers that a controller was
+ *	removed.
+ */
+void i2o_driver_notify_controller_remove_all(struct i2o_controller *c)
+{
+	int i;
+	struct i2o_driver *drv;
+
+	for (i = 0; i < i2o_max_drivers; i++) {
+		drv = i2o_drivers[i];
+
+		if (drv)
+			i2o_driver_notify_controller_remove(drv, c);
+	}
+}
+
+/**
+ *	i2o_driver_notify_device_add_all - Send notify of added device
+ *	@i2o_dev: newly added I2O device
+ *
+ *	Send notifications to all registered drivers that a device was added.
+ */
+void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev)
+{
+	int i;
+	struct i2o_driver *drv;
+
+	for (i = 0; i < i2o_max_drivers; i++) {
+		drv = i2o_drivers[i];
+
+		if (drv)
+			i2o_driver_notify_device_add(drv, i2o_dev);
+	}
+}
+
+/**
+ *	i2o_driver_notify_device_remove_all - Send notify of removed device
+ *	@i2o_dev: device that is being removed
+ *
+ *	Send notifications to all registered drivers that a device was removed.
+ */
+void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev)
+{
+	int i;
+	struct i2o_driver *drv;
+
+	for (i = 0; i < i2o_max_drivers; i++) {
+		drv = i2o_drivers[i];
+
+		if (drv)
+			i2o_driver_notify_device_remove(drv, i2o_dev);
+	}
+}
+
+/**
+ *	i2o_driver_init - initialize I2O drivers (OSMs)
+ *
+ *	Registers the I2O bus and allocate memory for the array of OSMs.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_driver_init(void)
+{
+	int rc = 0;
+
+	spin_lock_init(&i2o_drivers_lock);
+
+	if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) {
+		osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n",
+			 i2o_max_drivers);
+		i2o_max_drivers = I2O_MAX_DRIVERS;
+	}
+	osm_info("max drivers = %d\n", i2o_max_drivers);
+
+	i2o_drivers =
+	    kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL);
+	if (!i2o_drivers)
+		return -ENOMEM;
+
+	rc = bus_register(&i2o_bus_type);
+
+	if (rc < 0)
+		kfree(i2o_drivers);
+
+	return rc;
+};
+
+/**
+ *	i2o_driver_exit - clean up I2O drivers (OSMs)
+ *
+ *	Unregisters the I2O bus and frees driver array.
+ */
+void i2o_driver_exit(void)
+{
+	bus_unregister(&i2o_bus_type);
+	kfree(i2o_drivers);
+};
+
+EXPORT_SYMBOL(i2o_driver_register);
+EXPORT_SYMBOL(i2o_driver_unregister);
+EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);
diff --git a/drivers/staging/i2o/exec-osm.c b/drivers/staging/i2o/exec-osm.c
new file mode 100644
index 0000000..16d857d
--- /dev/null
+++ b/drivers/staging/i2o/exec-osm.c
@@ -0,0 +1,612 @@
+/*
+ *	Executive OSM
+ *
+ * 	Copyright (C) 1999-2002	Red Hat Software
+ *
+ *	Written by Alan Cox, Building Number Three Ltd
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation; either version 2 of the License, or (at your
+ *	option) any later version.
+ *
+ *	A lot of the I2O message side code from this is taken from the Red
+ *	Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *	Fixes/additions:
+ *		Philipp Rumpf
+ *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *		Deepak Saxena <deepak@plexity.net>
+ *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ *			Ported to Linux 2.5.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Minor fixes for 2.6.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Support for sysfs included.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>	/* wait_event_interruptible_timeout() needs this */
+#include <asm/param.h>		/* HZ */
+#include "core.h"
+
+#define OSM_NAME "exec-osm"
+
+struct i2o_driver i2o_exec_driver;
+
+/* global wait list for POST WAIT */
+static LIST_HEAD(i2o_exec_wait_list);
+
+/* Wait struct needed for POST WAIT */
+struct i2o_exec_wait {
+	wait_queue_head_t *wq;	/* Pointer to Wait queue */
+	struct i2o_dma dma;	/* DMA buffers to free on failure */
+	u32 tcntxt;		/* transaction context from reply */
+	int complete;		/* 1 if reply received otherwise 0 */
+	u32 m;			/* message id */
+	struct i2o_message *msg;	/* pointer to the reply message */
+	struct list_head list;	/* node in global wait list */
+	spinlock_t lock;	/* lock before modifying */
+};
+
+/* Work struct needed to handle LCT NOTIFY replies */
+struct i2o_exec_lct_notify_work {
+	struct work_struct work;	/* work struct */
+	struct i2o_controller *c;	/* controller on which the LCT NOTIFY
+					   was received */
+};
+
+/* Exec OSM class handling definition */
+static struct i2o_class_id i2o_exec_class_id[] = {
+	{I2O_CLASS_EXECUTIVE},
+	{I2O_CLASS_END}
+};
+
+/**
+ *	i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
+ *
+ *	Allocate the i2o_exec_wait struct and initialize the wait.
+ *
+ *	Returns i2o_exec_wait pointer on success or negative error code on
+ *	failure.
+ */
+static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
+{
+	struct i2o_exec_wait *wait;
+
+	wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+	if (!wait)
+		return NULL;
+
+	INIT_LIST_HEAD(&wait->list);
+	spin_lock_init(&wait->lock);
+
+	return wait;
+};
+
+/**
+ *	i2o_exec_wait_free - Free an i2o_exec_wait struct
+ *	@wait: I2O wait data which should be cleaned up
+ */
+static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
+{
+	kfree(wait);
+};
+
+/**
+ * 	i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
+ *	@c: controller
+ *	@msg: message to post
+ *	@timeout: time in seconds to wait
+ *	@dma: i2o_dma struct of the DMA buffer to free on failure
+ *
+ * 	This API allows an OSM to post a message and then be told whether or
+ *	not the system received a successful reply. If the message times out
+ *	then the value '-ETIMEDOUT' is returned. This is a special case. In
+ *	this situation the message may (should) complete at an indefinite time
+ *	in the future. When it completes it will use the memory buffer
+ *	attached to the request. If -ETIMEDOUT is returned then the memory
+ *	buffer must not be freed. Instead the event completion will free them
+ *	for you. In all other cases the buffer are your problem.
+ *
+ *	Returns 0 on success, negative error code on timeout or positive error
+ *	code from reply.
+ */
+int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
+			  unsigned long timeout, struct i2o_dma *dma)
+{
+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+	struct i2o_exec_wait *wait;
+	static u32 tcntxt = 0x80000000;
+	unsigned long flags;
+	int rc = 0;
+
+	wait = i2o_exec_wait_alloc();
+	if (!wait) {
+		i2o_msg_nop(c, msg);
+		return -ENOMEM;
+	}
+
+	if (tcntxt == 0xffffffff)
+		tcntxt = 0x80000000;
+
+	if (dma)
+		wait->dma = *dma;
+
+	/*
+	 * Fill in the message initiator context and transaction context.
+	 * We will only use transaction contexts >= 0x80000000 for POST WAIT,
+	 * so we could find a POST WAIT reply easier in the reply handler.
+	 */
+	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+	wait->tcntxt = tcntxt++;
+	msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
+
+	wait->wq = &wq;
+	/*
+	 * we add elements to the head, because if a entry in the list will
+	 * never be removed, we have to iterate over it every time
+	 */
+	list_add(&wait->list, &i2o_exec_wait_list);
+
+	/*
+	 * Post the message to the controller. At some point later it will
+	 * return. If we time out before it returns then complete will be zero.
+	 */
+	i2o_msg_post(c, msg);
+
+	wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
+
+	spin_lock_irqsave(&wait->lock, flags);
+
+	wait->wq = NULL;
+
+	if (wait->complete)
+		rc = le32_to_cpu(wait->msg->body[0]) >> 24;
+	else {
+		/*
+		 * We cannot remove it now. This is important. When it does
+		 * terminate (which it must do if the controller has not
+		 * died...) then it will otherwise scribble on stuff.
+		 *
+		 * FIXME: try abort message
+		 */
+		if (dma)
+			dma->virt = NULL;
+
+		rc = -ETIMEDOUT;
+	}
+
+	spin_unlock_irqrestore(&wait->lock, flags);
+
+	if (rc != -ETIMEDOUT) {
+		i2o_flush_reply(c, wait->m);
+		i2o_exec_wait_free(wait);
+	}
+
+	return rc;
+};
+
+/**
+ *	i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
+ *	@c: I2O controller which answers
+ *	@m: message id
+ *	@msg: pointer to the I2O reply message
+ *	@context: transaction context of request
+ *
+ *	This function is called in interrupt context only. If the reply reached
+ *	before the timeout, the i2o_exec_wait struct is filled with the message
+ *	and the task will be waked up. The task is now responsible for returning
+ *	the message m back to the controller! If the message reaches us after
+ *	the timeout clean up the i2o_exec_wait struct (including allocated
+ *	DMA buffer).
+ *
+ *	Return 0 on success and if the message m should not be given back to the
+ *	I2O controller, or >0 on success and if the message should be given back
+ *	afterwords. Returns negative error code on failure. In this case the
+ *	message must also be given back to the controller.
+ */
+static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
+				      struct i2o_message *msg, u32 context)
+{
+	struct i2o_exec_wait *wait, *tmp;
+	unsigned long flags;
+	int rc = 1;
+
+	/*
+	 * We need to search through the i2o_exec_wait_list to see if the given
+	 * message is still outstanding. If not, it means that the IOP took
+	 * longer to respond to the message than we had allowed and timer has
+	 * already expired. Not much we can do about that except log it for
+	 * debug purposes, increase timeout, and recompile.
+	 */
+	list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
+		if (wait->tcntxt == context) {
+			spin_lock_irqsave(&wait->lock, flags);
+
+			list_del(&wait->list);
+
+			wait->m = m;
+			wait->msg = msg;
+			wait->complete = 1;
+
+			if (wait->wq)
+				rc = 0;
+			else
+				rc = -1;
+
+			spin_unlock_irqrestore(&wait->lock, flags);
+
+			if (rc) {
+				struct device *dev;
+
+				dev = &c->pdev->dev;
+
+				pr_debug("%s: timedout reply received!\n",
+					 c->name);
+				i2o_dma_free(dev, &wait->dma);
+				i2o_exec_wait_free(wait);
+			} else
+				wake_up_interruptible(wait->wq);
+
+			return rc;
+		}
+	}
+
+	osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
+		 context);
+
+	return -1;
+};
+
+/**
+ *	i2o_exec_show_vendor_id - Displays Vendor ID of controller
+ *	@d: device of which the Vendor ID should be displayed
+ *	@attr: device_attribute to display
+ *	@buf: buffer into which the Vendor ID should be printed
+ *
+ *	Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_vendor_id(struct device *d,
+				       struct device_attribute *attr, char *buf)
+{
+	struct i2o_device *dev = to_i2o_device(d);
+	u16 id;
+
+	if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
+		sprintf(buf, "0x%04x", le16_to_cpu(id));
+		return strlen(buf) + 1;
+	}
+
+	return 0;
+};
+
+/**
+ *	i2o_exec_show_product_id - Displays Product ID of controller
+ *	@d: device of which the Product ID should be displayed
+ *	@attr: device_attribute to display
+ *	@buf: buffer into which the Product ID should be printed
+ *
+ *	Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_product_id(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct i2o_device *dev = to_i2o_device(d);
+	u16 id;
+
+	if (!i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
+		sprintf(buf, "0x%04x", le16_to_cpu(id));
+		return strlen(buf) + 1;
+	}
+
+	return 0;
+};
+
+/* Exec-OSM device attributes */
+static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
+
+/**
+ *	i2o_exec_probe - Called if a new I2O device (executive class) appears
+ *	@dev: I2O device which should be probed
+ *
+ *	Registers event notification for every event from Executive device. The
+ *	return is always 0, because we want all devices of class Executive.
+ *
+ *	Returns 0 on success.
+ */
+static int i2o_exec_probe(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	int rc;
+
+	rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+	if (rc) goto err_out;
+
+	rc = device_create_file(dev, &dev_attr_vendor_id);
+	if (rc) goto err_evtreg;
+	rc = device_create_file(dev, &dev_attr_product_id);
+	if (rc) goto err_vid;
+
+	i2o_dev->iop->exec = i2o_dev;
+
+	return 0;
+
+err_vid:
+	device_remove_file(dev, &dev_attr_vendor_id);
+err_evtreg:
+	i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+err_out:
+	return rc;
+};
+
+/**
+ *	i2o_exec_remove - Called on I2O device removal
+ *	@dev: I2O device which was removed
+ *
+ *	Unregisters event notification from Executive I2O device.
+ *
+ *	Returns 0 on success.
+ */
+static int i2o_exec_remove(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_product_id);
+	device_remove_file(dev, &dev_attr_vendor_id);
+
+	i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+
+	return 0;
+};
+
+#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
+/**
+ *	i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
+ *	@c: I2O controller to which the request should be send
+ *	@change_ind: change indicator
+ *
+ *	This function sends a LCT NOTIFY request to the I2O controller with
+ *	the change indicator change_ind. If the change_ind == 0 the controller
+ *	replies immediately after the request. If change_ind > 0 the reply is
+ *	send after change indicator of the LCT is > change_ind.
+ */
+static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
+{
+	i2o_status_block *sb = c->status_block.virt;
+	struct device *dev;
+	struct i2o_message *msg;
+
+	mutex_lock(&c->lct_lock);
+
+	dev = &c->pdev->dev;
+
+	if (i2o_dma_realloc(dev, &c->dlct,
+					le32_to_cpu(sb->expected_lct_size))) {
+		mutex_unlock(&c->lct_lock);
+		return -ENOMEM;
+	}
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg)) {
+		mutex_unlock(&c->lct_lock);
+		return PTR_ERR(msg);
+	}
+
+	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+	msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
+				     ADAPTER_TID);
+	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+	msg->body[0] = cpu_to_le32(0xffffffff);
+	msg->body[1] = cpu_to_le32(change_ind);
+	msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
+	msg->body[3] = cpu_to_le32(c->dlct.phys);
+
+	i2o_msg_post(c, msg);
+
+	mutex_unlock(&c->lct_lock);
+
+	return 0;
+}
+#endif
+
+/**
+ *	i2o_exec_lct_modified - Called on LCT NOTIFY reply
+ *	@_work: work struct for a specific controller
+ *
+ *	This function handles asynchronus LCT NOTIFY replies. It parses the
+ *	new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
+ *	again, otherwise send LCT NOTIFY to get informed on next LCT change.
+ */
+static void i2o_exec_lct_modified(struct work_struct *_work)
+{
+	struct i2o_exec_lct_notify_work *work =
+		container_of(_work, struct i2o_exec_lct_notify_work, work);
+	u32 change_ind = 0;
+	struct i2o_controller *c = work->c;
+
+	kfree(work);
+
+	if (i2o_device_parse_lct(c) != -EAGAIN)
+		change_ind = c->lct->change_ind + 1;
+
+#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
+	i2o_exec_lct_notify(c, change_ind);
+#endif
+};
+
+/**
+ *	i2o_exec_reply -  I2O Executive reply handler
+ *	@c: I2O controller from which the reply comes
+ *	@m: message id
+ *	@msg: pointer to the I2O reply message
+ *
+ *	This function is always called from interrupt context. If a POST WAIT
+ *	reply was received, pass it to the complete function. If a LCT NOTIFY
+ *	reply was received, a new event is created to handle the update.
+ *
+ *	Returns 0 on success and if the reply should not be flushed or > 0
+ *	on success and if the reply should be flushed. Returns negative error
+ *	code on failure and if the reply should be flushed.
+ */
+static int i2o_exec_reply(struct i2o_controller *c, u32 m,
+			  struct i2o_message *msg)
+{
+	u32 context;
+
+	if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
+		struct i2o_message __iomem *pmsg;
+		u32 pm;
+
+		/*
+		 * If Fail bit is set we must take the transaction context of
+		 * the preserved message to find the right request again.
+		 */
+
+		pm = le32_to_cpu(msg->body[3]);
+		pmsg = i2o_msg_in_to_virt(c, pm);
+		context = readl(&pmsg->u.s.tcntxt);
+
+		i2o_report_status(KERN_INFO, "i2o_core", msg);
+
+		/* Release the preserved msg */
+		i2o_msg_nop_mfa(c, pm);
+	} else
+		context = le32_to_cpu(msg->u.s.tcntxt);
+
+	if (context & 0x80000000)
+		return i2o_msg_post_wait_complete(c, m, msg, context);
+
+	if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
+		struct i2o_exec_lct_notify_work *work;
+
+		pr_debug("%s: LCT notify received\n", c->name);
+
+		work = kmalloc(sizeof(*work), GFP_ATOMIC);
+		if (!work)
+			return -ENOMEM;
+
+		work->c = c;
+
+		INIT_WORK(&work->work, i2o_exec_lct_modified);
+		queue_work(i2o_exec_driver.event_queue, &work->work);
+		return 1;
+	}
+
+	/*
+	 * If this happens, we want to dump the message to the syslog so
+	 * it can be sent back to the card manufacturer by the end user
+	 * to aid in debugging.
+	 *
+	 */
+	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+	       "Message dumped to syslog\n", c->name);
+	i2o_dump_message(msg);
+
+	return -EFAULT;
+}
+
+/**
+ *	i2o_exec_event - Event handling function
+ *	@work: Work item in occurring event
+ *
+ *	Handles events send by the Executive device. At the moment does not do
+ *	anything useful.
+ */
+static void i2o_exec_event(struct work_struct *work)
+{
+	struct i2o_event *evt = container_of(work, struct i2o_event, work);
+
+	if (likely(evt->i2o_dev))
+		osm_debug("Event received from device: %d\n",
+			  evt->i2o_dev->lct_data.tid);
+	kfree(evt);
+};
+
+/**
+ *	i2o_exec_lct_get - Get the IOP's Logical Configuration Table
+ *	@c: I2O controller from which the LCT should be fetched
+ *
+ *	Send a LCT NOTIFY request to the controller, and wait
+ *	I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
+ *	to large, retry it.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_exec_lct_get(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	int i = 0;
+	int rc = -EAGAIN;
+
+	for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
+		msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+		if (IS_ERR(msg))
+			return PTR_ERR(msg);
+
+		msg->u.head[0] =
+		    cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+		msg->u.head[1] =
+		    cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
+				ADAPTER_TID);
+		msg->body[0] = cpu_to_le32(0xffffffff);
+		msg->body[1] = cpu_to_le32(0x00000000);
+		msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
+		msg->body[3] = cpu_to_le32(c->dlct.phys);
+
+		rc = i2o_msg_post_wait(c, msg, I2O_TIMEOUT_LCT_GET);
+		if (rc < 0)
+			break;
+
+		rc = i2o_device_parse_lct(c);
+		if (rc != -EAGAIN)
+			break;
+	}
+
+	return rc;
+}
+
+/* Exec OSM driver struct */
+struct i2o_driver i2o_exec_driver = {
+	.name = OSM_NAME,
+	.reply = i2o_exec_reply,
+	.event = i2o_exec_event,
+	.classes = i2o_exec_class_id,
+	.driver = {
+		   .probe = i2o_exec_probe,
+		   .remove = i2o_exec_remove,
+		   },
+};
+
+/**
+ *	i2o_exec_init - Registers the Exec OSM
+ *
+ *	Registers the Exec OSM in the I2O core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_exec_init(void)
+{
+	return i2o_driver_register(&i2o_exec_driver);
+};
+
+/**
+ *	i2o_exec_exit - Removes the Exec OSM
+ *
+ *	Unregisters the Exec OSM from the I2O core.
+ */
+void i2o_exec_exit(void)
+{
+	i2o_driver_unregister(&i2o_exec_driver);
+};
+
+EXPORT_SYMBOL(i2o_msg_post_wait_mem);
+EXPORT_SYMBOL(i2o_exec_lct_get);
diff --git a/include/linux/i2o.h b/drivers/staging/i2o/i2o.h
similarity index 100%
rename from include/linux/i2o.h
rename to drivers/staging/i2o/i2o.h
diff --git a/drivers/staging/i2o/i2o_block.c b/drivers/staging/i2o/i2o_block.c
new file mode 100644
index 0000000..0a13c64
--- /dev/null
+++ b/drivers/staging/i2o/i2o_block.c
@@ -0,0 +1,1228 @@
+/*
+ *	Block OSM
+ *
+ * 	Copyright (C) 1999-2002	Red Hat Software
+ *
+ *	Written by Alan Cox, Building Number Three Ltd
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation; either version 2 of the License, or (at your
+ *	option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful, but
+ *	WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *	General Public License for more details.
+ *
+ *	For the purpose of avoiding doubt the preferred form of the work
+ *	for making modifications shall be a standards compliant form such
+ *	gzipped tar and not one requiring a proprietary or patent encumbered
+ *	tool to unpack.
+ *
+ *	Fixes/additions:
+ *		Steve Ralston:
+ *			Multiple device handling error fixes,
+ *			Added a queue depth.
+ *		Alan Cox:
+ *			FC920 has an rmw bug. Dont or in the end marker.
+ *			Removed queue walk, fixed for 64bitness.
+ *			Rewrote much of the code over time
+ *			Added indirect block lists
+ *			Handle 64K limits on many controllers
+ *			Don't use indirects on the Promise (breaks)
+ *			Heavily chop down the queue depths
+ *		Deepak Saxena:
+ *			Independent queues per IOP
+ *			Support for dynamic device creation/deletion
+ *			Code cleanup
+ *	    		Support for larger I/Os through merge* functions
+ *			(taken from DAC960 driver)
+ *		Boji T Kannanthanam:
+ *			Set the I2O Block devices to be detected in increasing
+ *			order of TIDs during boot.
+ *			Search and set the I2O block device that we boot off
+ *			from as the first device to be claimed (as /dev/i2o/hda)
+ *			Properly attach/detach I2O gendisk structure from the
+ *			system gendisk list. The I2O block devices now appear in
+ *			/proc/partitions.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Minor bugfixes for 2.6.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "i2o.h"
+#include <linux/mutex.h>
+
+#include <linux/mempool.h>
+
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <scsi/scsi.h>
+
+#include "i2o_block.h"
+
+#define OSM_NAME	"block-osm"
+#define OSM_VERSION	"1.325"
+#define OSM_DESCRIPTION	"I2O Block Device OSM"
+
+static DEFINE_MUTEX(i2o_block_mutex);
+static struct i2o_driver i2o_block_driver;
+
+/* global Block OSM request mempool */
+static struct i2o_block_mempool i2o_blk_req_pool;
+
+/* Block OSM class handling definition */
+static struct i2o_class_id i2o_block_class_id[] = {
+	{I2O_CLASS_RANDOM_BLOCK_STORAGE},
+	{I2O_CLASS_END}
+};
+
+/**
+ *	i2o_block_device_free - free the memory of the I2O Block device
+ *	@dev: I2O Block device, which should be cleaned up
+ *
+ *	Frees the request queue, gendisk and the i2o_block_device structure.
+ */
+static void i2o_block_device_free(struct i2o_block_device *dev)
+{
+	blk_cleanup_queue(dev->gd->queue);
+
+	put_disk(dev->gd);
+
+	kfree(dev);
+};
+
+/**
+ *	i2o_block_remove - remove the I2O Block device from the system again
+ *	@dev: I2O Block device which should be removed
+ *
+ *	Remove gendisk from system and free all allocated memory.
+ *
+ *	Always returns 0.
+ */
+static int i2o_block_remove(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev);
+
+	osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+		 i2o_blk_dev->gd->disk_name);
+
+	i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
+
+	del_gendisk(i2o_blk_dev->gd);
+
+	dev_set_drvdata(dev, NULL);
+
+	i2o_device_claim_release(i2o_dev);
+
+	i2o_block_device_free(i2o_blk_dev);
+
+	return 0;
+};
+
+/**
+ *	i2o_block_device flush - Flush all dirty data of I2O device dev
+ *	@dev: I2O device which should be flushed
+ *
+ *	Flushes all dirty data on device dev.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_flush(struct i2o_device *dev)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->
+			lct_data.tid);
+	msg->body[0] = cpu_to_le32(60 << 16);
+	osm_debug("Flushing...\n");
+
+	return i2o_msg_post_wait(dev->iop, msg, 60);
+};
+
+/**
+ *	i2o_block_device_mount - Mount (load) the media of device dev
+ *	@dev: I2O device which should receive the mount request
+ *	@media_id: Media Identifier
+ *
+ *	Load a media into drive. Identifier should be set to -1, because the
+ *	spec does not support any other value.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->
+			lct_data.tid);
+	msg->body[0] = cpu_to_le32(-1);
+	msg->body[1] = cpu_to_le32(0x00000000);
+	osm_debug("Mounting...\n");
+
+	return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ *	i2o_block_device_lock - Locks the media of device dev
+ *	@dev: I2O device which should receive the lock request
+ *	@media_id: Media Identifier
+ *
+ *	Lock media of device dev to prevent removal. The media identifier
+ *	should be set to -1, because the spec does not support any other value.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->
+			lct_data.tid);
+	msg->body[0] = cpu_to_le32(-1);
+	osm_debug("Locking...\n");
+
+	return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ *	i2o_block_device_unlock - Unlocks the media of device dev
+ *	@dev: I2O device which should receive the unlocked request
+ *	@media_id: Media Identifier
+ *
+ *	Unlocks the media in device dev. The media identifier should be set to
+ *	-1, because the spec does not support any other value.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id)
+{
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->
+			lct_data.tid);
+	msg->body[0] = cpu_to_le32(media_id);
+	osm_debug("Unlocking...\n");
+
+	return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ *	i2o_block_device_power - Power management for device dev
+ *	@dev: I2O device which should receive the power management request
+ *	@op: Operation to send
+ *
+ *	Send a power management request to the device dev.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_power(struct i2o_block_device *dev, u8 op)
+{
+	struct i2o_device *i2o_dev = dev->i2o_dev;
+	struct i2o_controller *c = i2o_dev->iop;
+	struct i2o_message *msg;
+	int rc;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->
+			lct_data.tid);
+	msg->body[0] = cpu_to_le32(op << 24);
+	osm_debug("Power...\n");
+
+	rc = i2o_msg_post_wait(c, msg, 60);
+	if (!rc)
+		dev->power = op;
+
+	return rc;
+};
+
+/**
+ *	i2o_block_request_alloc - Allocate an I2O block request struct
+ *
+ *	Allocates an I2O block request struct and initialize the list.
+ *
+ *	Returns a i2o_block_request pointer on success or negative error code
+ *	on failure.
+ */
+static inline struct i2o_block_request *i2o_block_request_alloc(void)
+{
+	struct i2o_block_request *ireq;
+
+	ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC);
+	if (!ireq)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&ireq->queue);
+	sg_init_table(ireq->sg_table, I2O_MAX_PHYS_SEGMENTS);
+
+	return ireq;
+};
+
+/**
+ *	i2o_block_request_free - Frees a I2O block request
+ *	@ireq: I2O block request which should be freed
+ *
+ *	Frees the allocated memory (give it back to the request mempool).
+ */
+static inline void i2o_block_request_free(struct i2o_block_request *ireq)
+{
+	mempool_free(ireq, i2o_blk_req_pool.pool);
+};
+
+/**
+ *	i2o_block_sglist_alloc - Allocate the SG list and map it
+ *	@c: I2O controller to which the request belongs
+ *	@ireq: I2O block request
+ *	@mptr: message body pointer
+ *
+ *	Builds the SG list and map it to be accessible by the controller.
+ *
+ *	Returns 0 on failure or 1 on success.
+ */
+static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
+					 struct i2o_block_request *ireq,
+					 u32 ** mptr)
+{
+	int nents;
+	enum dma_data_direction direction;
+
+	ireq->dev = &c->pdev->dev;
+	nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table);
+
+	if (rq_data_dir(ireq->req) == READ)
+		direction = PCI_DMA_FROMDEVICE;
+	else
+		direction = PCI_DMA_TODEVICE;
+
+	ireq->sg_nents = nents;
+
+	return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
+};
+
+/**
+ *	i2o_block_sglist_free - Frees the SG list
+ *	@ireq: I2O block request from which the SG should be freed
+ *
+ *	Frees the SG list from the I2O block request.
+ */
+static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
+{
+	enum dma_data_direction direction;
+
+	if (rq_data_dir(ireq->req) == READ)
+		direction = PCI_DMA_FROMDEVICE;
+	else
+		direction = PCI_DMA_TODEVICE;
+
+	dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
+};
+
+/**
+ *	i2o_block_prep_req_fn - Allocates I2O block device specific struct
+ *	@q: request queue for the request
+ *	@req: the request to prepare
+ *
+ *	Allocate the necessary i2o_block_request struct and connect it to
+ *	the request. This is needed that we not lose the SG list later on.
+ *
+ *	Returns BLKPREP_OK on success or BLKPREP_DEFER on failure.
+ */
+static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
+{
+	struct i2o_block_device *i2o_blk_dev = q->queuedata;
+	struct i2o_block_request *ireq;
+
+	if (unlikely(!i2o_blk_dev)) {
+		osm_err("block device already removed\n");
+		return BLKPREP_KILL;
+	}
+
+	/* connect the i2o_block_request to the request */
+	if (!req->special) {
+		ireq = i2o_block_request_alloc();
+		if (IS_ERR(ireq)) {
+			osm_debug("unable to allocate i2o_block_request!\n");
+			return BLKPREP_DEFER;
+		}
+
+		ireq->i2o_blk_dev = i2o_blk_dev;
+		req->special = ireq;
+		ireq->req = req;
+	}
+	/* do not come back here */
+	req->cmd_flags |= REQ_DONTPREP;
+
+	return BLKPREP_OK;
+};
+
+/**
+ *	i2o_block_delayed_request_fn - delayed request queue function
+ *	@work: the delayed request with the queue to start
+ *
+ *	If the request queue is stopped for a disk, and there is no open
+ *	request, a new event is created, which calls this function to start
+ *	the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never
+ *	be started again.
+ */
+static void i2o_block_delayed_request_fn(struct work_struct *work)
+{
+	struct i2o_block_delayed_request *dreq =
+		container_of(work, struct i2o_block_delayed_request,
+			     work.work);
+	struct request_queue *q = dreq->queue;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	blk_start_queue(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+	kfree(dreq);
+};
+
+/**
+ *	i2o_block_end_request - Post-processing of completed commands
+ *	@req: request which should be completed
+ *	@error: 0 for success, < 0 for error
+ *	@nr_bytes: number of bytes to complete
+ *
+ *	Mark the request as complete. The lock must not be held when entering.
+ *
+ */
+static void i2o_block_end_request(struct request *req, int error,
+				  int nr_bytes)
+{
+	struct i2o_block_request *ireq = req->special;
+	struct i2o_block_device *dev = ireq->i2o_blk_dev;
+	struct request_queue *q = req->q;
+	unsigned long flags;
+
+	if (blk_end_request(req, error, nr_bytes))
+		if (error)
+			blk_end_request_all(req, -EIO);
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	if (likely(dev)) {
+		dev->open_queue_depth--;
+		list_del(&ireq->queue);
+	}
+
+	blk_start_queue(q);
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	i2o_block_sglist_free(ireq);
+	i2o_block_request_free(ireq);
+};
+
+/**
+ *	i2o_block_reply - Block OSM reply handler.
+ *	@c: I2O controller from which the message arrives
+ *	@m: message id of reply
+ *	@msg: the actual I2O message reply
+ *
+ *	This function gets all the message replies.
+ *
+ */
+static int i2o_block_reply(struct i2o_controller *c, u32 m,
+			   struct i2o_message *msg)
+{
+	struct request *req;
+	int error = 0;
+
+	req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+	if (unlikely(!req)) {
+		osm_err("NULL reply received!\n");
+		return -1;
+	}
+
+	/*
+	 *      Lets see what is cooking. We stuffed the
+	 *      request in the context.
+	 */
+
+	if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
+		u32 status = le32_to_cpu(msg->body[0]);
+		/*
+		 *      Device not ready means two things. One is that the
+		 *      the thing went offline (but not a removal media)
+		 *
+		 *      The second is that you have a SuperTrak 100 and the
+		 *      firmware got constipated. Unlike standard i2o card
+		 *      setups the supertrak returns an error rather than
+		 *      blocking for the timeout in these cases.
+		 *
+		 *      Don't stick a supertrak100 into cache aggressive modes
+		 */
+
+		osm_err("TID %03x error status: 0x%02x, detailed status: "
+			"0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
+			status >> 24, status & 0xffff);
+
+		req->errors++;
+
+		error = -EIO;
+	}
+
+	i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
+
+	return 1;
+};
+
+static void i2o_block_event(struct work_struct *work)
+{
+	struct i2o_event *evt = container_of(work, struct i2o_event, work);
+	osm_debug("event received\n");
+	kfree(evt);
+};
+
+/*
+ *	SCSI-CAM for ioctl geometry mapping
+ *	Duplicated with SCSI - this should be moved into somewhere common
+ *	perhaps genhd ?
+ *
+ * LBA -> CHS mapping table taken from:
+ *
+ * "Incorporating the I2O Architecture into BIOS for Intel Architecture
+ *  Platforms"
+ *
+ * This is an I2O document that is only available to I2O members,
+ * not developers.
+ *
+ * From my understanding, this is how all the I2O cards do this
+ *
+ * Disk Size      | Sectors | Heads | Cylinders
+ * ---------------+---------+-------+-------------------
+ * 1 < X <= 528M  | 63      | 16    | X/(63 * 16 * 512)
+ * 528M < X <= 1G | 63      | 32    | X/(63 * 32 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ * 1 < X <528M    | 63      | 16    | X/(63 * 16 * 512)
+ *
+ */
+#define	BLOCK_SIZE_528M		1081344
+#define	BLOCK_SIZE_1G		2097152
+#define	BLOCK_SIZE_21G		4403200
+#define	BLOCK_SIZE_42G		8806400
+#define	BLOCK_SIZE_84G		17612800
+
+static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls,
+				unsigned char *hds, unsigned char *secs)
+{
+	unsigned long heads, sectors, cylinders;
+
+	sectors = 63L;		/* Maximize sectors per track */
+	if (capacity <= BLOCK_SIZE_528M)
+		heads = 16;
+	else if (capacity <= BLOCK_SIZE_1G)
+		heads = 32;
+	else if (capacity <= BLOCK_SIZE_21G)
+		heads = 64;
+	else if (capacity <= BLOCK_SIZE_42G)
+		heads = 128;
+	else
+		heads = 255;
+
+	cylinders = (unsigned long)capacity / (heads * sectors);
+
+	*cyls = (unsigned short)cylinders;	/* Stuff return values */
+	*secs = (unsigned char)sectors;
+	*hds = (unsigned char)heads;
+}
+
+/**
+ *	i2o_block_open - Open the block device
+ *	@bdev: block device being opened
+ *	@mode: file open mode
+ *
+ *	Power up the device, mount and lock the media. This function is called,
+ *	if the block device is opened for access.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_open(struct block_device *bdev, fmode_t mode)
+{
+	struct i2o_block_device *dev = bdev->bd_disk->private_data;
+
+	if (!dev->i2o_dev)
+		return -ENODEV;
+
+	mutex_lock(&i2o_block_mutex);
+	if (dev->power > 0x1f)
+		i2o_block_device_power(dev, 0x02);
+
+	i2o_block_device_mount(dev->i2o_dev, -1);
+
+	i2o_block_device_lock(dev->i2o_dev, -1);
+
+	osm_debug("Ready.\n");
+	mutex_unlock(&i2o_block_mutex);
+
+	return 0;
+};
+
+/**
+ *	i2o_block_release - Release the I2O block device
+ *	@disk: gendisk device being released
+ *	@mode: file open mode
+ *
+ *	Unlock and unmount the media, and power down the device. Gets called if
+ *	the block device is closed.
+ */
+static void i2o_block_release(struct gendisk *disk, fmode_t mode)
+{
+	struct i2o_block_device *dev = disk->private_data;
+	u8 operation;
+
+	/*
+	 * This is to deal with the case of an application
+	 * opening a device and then the device disappears while
+	 * it's in use, and then the application tries to release
+	 * it.  ex: Unmounting a deleted RAID volume at reboot.
+	 * If we send messages, it will just cause FAILs since
+	 * the TID no longer exists.
+	 */
+	if (!dev->i2o_dev)
+		return;
+
+	mutex_lock(&i2o_block_mutex);
+	i2o_block_device_flush(dev->i2o_dev);
+
+	i2o_block_device_unlock(dev->i2o_dev, -1);
+
+	if (dev->flags & (1 << 3 | 1 << 4))	/* Removable */
+		operation = 0x21;
+	else
+		operation = 0x24;
+
+	i2o_block_device_power(dev, operation);
+	mutex_unlock(&i2o_block_mutex);
+}
+
+static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	i2o_block_biosparam(get_capacity(bdev->bd_disk),
+			    &geo->cylinders, &geo->heads, &geo->sectors);
+	return 0;
+}
+
+/**
+ *	i2o_block_ioctl - Issue device specific ioctl calls.
+ *	@bdev: block device being opened
+ *	@mode: file open mode
+ *	@cmd: ioctl command
+ *	@arg: arg
+ *
+ *	Handles ioctl request for the block device.
+ *
+ *	Return 0 on success or negative error on failure.
+ */
+static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	struct i2o_block_device *dev = disk->private_data;
+	int ret = -ENOTTY;
+
+	/* Anyone capable of this syscall can do *real bad* things */
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&i2o_block_mutex);
+	switch (cmd) {
+	case BLKI2OGRSTRAT:
+		ret = put_user(dev->rcache, (int __user *)arg);
+		break;
+	case BLKI2OGWSTRAT:
+		ret = put_user(dev->wcache, (int __user *)arg);
+		break;
+	case BLKI2OSRSTRAT:
+		ret = -EINVAL;
+		if (arg < 0 || arg > CACHE_SMARTFETCH)
+			break;
+		dev->rcache = arg;
+		ret = 0;
+		break;
+	case BLKI2OSWSTRAT:
+		ret = -EINVAL;
+		if (arg != 0
+		    && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK))
+			break;
+		dev->wcache = arg;
+		ret = 0;
+		break;
+	}
+	mutex_unlock(&i2o_block_mutex);
+
+	return ret;
+};
+
+/**
+ *	i2o_block_check_events - Have we seen a media change?
+ *	@disk: gendisk which should be verified
+ *	@clearing: events being cleared
+ *
+ *	Verifies if the media has changed.
+ *
+ *	Returns 1 if the media was changed or 0 otherwise.
+ */
+static unsigned int i2o_block_check_events(struct gendisk *disk,
+					   unsigned int clearing)
+{
+	struct i2o_block_device *p = disk->private_data;
+
+	if (p->media_change_flag) {
+		p->media_change_flag = 0;
+		return DISK_EVENT_MEDIA_CHANGE;
+	}
+	return 0;
+}
+
+/**
+ *	i2o_block_transfer - Transfer a request to/from the I2O controller
+ *	@req: the request which should be transferred
+ *
+ *	This function converts the request into a I2O message. The necessary
+ *	DMA buffers are allocated and after everything is setup post the message
+ *	to the I2O controller. No cleanup is done by this function. It is done
+ *	on the interrupt side when the reply arrives.
+ *
+ *	Return 0 on success or negative error code on failure.
+ */
+static int i2o_block_transfer(struct request *req)
+{
+	struct i2o_block_device *dev = req->rq_disk->private_data;
+	struct i2o_controller *c;
+	u32 tid;
+	struct i2o_message *msg;
+	u32 *mptr;
+	struct i2o_block_request *ireq = req->special;
+	u32 tcntxt;
+	u32 sgl_offset = SGL_OFFSET_8;
+	u32 ctl_flags = 0x00000000;
+	int rc;
+	u32 cmd;
+
+	if (unlikely(!dev->i2o_dev)) {
+		osm_err("transfer to removed drive\n");
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	tid = dev->i2o_dev->lct_data.tid;
+	c = dev->i2o_dev->iop;
+
+	msg = i2o_msg_get(c);
+	if (IS_ERR(msg)) {
+		rc = PTR_ERR(msg);
+		goto exit;
+	}
+
+	tcntxt = i2o_cntxt_list_add(c, req);
+	if (!tcntxt) {
+		rc = -ENOMEM;
+		goto nop_msg;
+	}
+
+	msg->u.s.icntxt = cpu_to_le32(i2o_block_driver.context);
+	msg->u.s.tcntxt = cpu_to_le32(tcntxt);
+
+	mptr = &msg->body[0];
+
+	if (rq_data_dir(req) == READ) {
+		cmd = I2O_CMD_BLOCK_READ << 24;
+
+		switch (dev->rcache) {
+		case CACHE_PREFETCH:
+			ctl_flags = 0x201F0008;
+			break;
+
+		case CACHE_SMARTFETCH:
+			if (blk_rq_sectors(req) > 16)
+				ctl_flags = 0x201F0008;
+			else
+				ctl_flags = 0x001F0000;
+			break;
+
+		default:
+			break;
+		}
+	} else {
+		cmd = I2O_CMD_BLOCK_WRITE << 24;
+
+		switch (dev->wcache) {
+		case CACHE_WRITETHROUGH:
+			ctl_flags = 0x001F0008;
+			break;
+		case CACHE_WRITEBACK:
+			ctl_flags = 0x001F0010;
+			break;
+		case CACHE_SMARTBACK:
+			if (blk_rq_sectors(req) > 16)
+				ctl_flags = 0x001F0004;
+			else
+				ctl_flags = 0x001F0010;
+			break;
+		case CACHE_SMARTTHROUGH:
+			if (blk_rq_sectors(req) > 16)
+				ctl_flags = 0x001F0004;
+			else
+				ctl_flags = 0x001F0010;
+		default:
+			break;
+		}
+	}
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+	if (c->adaptec) {
+		u8 cmd[10];
+		u32 scsi_flags;
+		u16 hwsec;
+
+		hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT;
+		memset(cmd, 0, 10);
+
+		sgl_offset = SGL_OFFSET_12;
+
+		msg->u.head[1] =
+		    cpu_to_le32(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid);
+
+		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
+		*mptr++ = cpu_to_le32(tid);
+
+		/*
+		 * ENABLE_DISCONNECT
+		 * SIMPLE_TAG
+		 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+		 */
+		if (rq_data_dir(req) == READ) {
+			cmd[0] = READ_10;
+			scsi_flags = 0x60a0000a;
+		} else {
+			cmd[0] = WRITE_10;
+			scsi_flags = 0xa0a0000a;
+		}
+
+		*mptr++ = cpu_to_le32(scsi_flags);
+
+		*((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec);
+		*((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec);
+
+		memcpy(mptr, cmd, 10);
+		mptr += 4;
+		*mptr++ = cpu_to_le32(blk_rq_bytes(req));
+	} else
+#endif
+	{
+		msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
+		*mptr++ = cpu_to_le32(ctl_flags);
+		*mptr++ = cpu_to_le32(blk_rq_bytes(req));
+		*mptr++ =
+		    cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT));
+		*mptr++ =
+		    cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT));
+	}
+
+	if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
+		rc = -ENOMEM;
+		goto context_remove;
+	}
+
+	msg->u.head[0] =
+	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
+
+	list_add_tail(&ireq->queue, &dev->open_queue);
+	dev->open_queue_depth++;
+
+	i2o_msg_post(c, msg);
+
+	return 0;
+
+      context_remove:
+	i2o_cntxt_list_remove(c, req);
+
+      nop_msg:
+	i2o_msg_nop(c, msg);
+
+      exit:
+	return rc;
+};
+
+/**
+ *	i2o_block_request_fn - request queue handling function
+ *	@q: request queue from which the request could be fetched
+ *
+ *	Takes the next request from the queue, transfers it and if no error
+ *	occurs dequeue it from the queue. On arrival of the reply the message
+ *	will be processed further. If an error occurs requeue the request.
+ */
+static void i2o_block_request_fn(struct request_queue *q)
+{
+	struct request *req;
+
+	while ((req = blk_peek_request(q)) != NULL) {
+		if (req->cmd_type == REQ_TYPE_FS) {
+			struct i2o_block_delayed_request *dreq;
+			struct i2o_block_request *ireq = req->special;
+			unsigned int queue_depth;
+
+			queue_depth = ireq->i2o_blk_dev->open_queue_depth;
+
+			if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
+				if (!i2o_block_transfer(req)) {
+					blk_start_request(req);
+					continue;
+				} else
+					osm_info("transfer error\n");
+			}
+
+			if (queue_depth)
+				break;
+
+			/* stop the queue and retry later */
+			dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC);
+			if (!dreq)
+				continue;
+
+			dreq->queue = q;
+			INIT_DELAYED_WORK(&dreq->work,
+					  i2o_block_delayed_request_fn);
+
+			if (!queue_delayed_work(i2o_block_driver.event_queue,
+						&dreq->work,
+						I2O_BLOCK_RETRY_TIME))
+				kfree(dreq);
+			else {
+				blk_stop_queue(q);
+				break;
+			}
+		} else {
+			blk_start_request(req);
+			__blk_end_request_all(req, -EIO);
+		}
+	}
+};
+
+/* I2O Block device operations definition */
+static const struct block_device_operations i2o_block_fops = {
+	.owner = THIS_MODULE,
+	.open = i2o_block_open,
+	.release = i2o_block_release,
+	.ioctl = i2o_block_ioctl,
+	.compat_ioctl = i2o_block_ioctl,
+	.getgeo = i2o_block_getgeo,
+	.check_events = i2o_block_check_events,
+};
+
+/**
+ *	i2o_block_device_alloc - Allocate memory for a I2O Block device
+ *
+ *	Allocate memory for the i2o_block_device struct, gendisk and request
+ *	queue and initialize them as far as no additional information is needed.
+ *
+ *	Returns a pointer to the allocated I2O Block device on success or a
+ *	negative error code on failure.
+ */
+static struct i2o_block_device *i2o_block_device_alloc(void)
+{
+	struct i2o_block_device *dev;
+	struct gendisk *gd;
+	struct request_queue *queue;
+	int rc;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		osm_err("Insufficient memory to allocate I2O Block disk.\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	INIT_LIST_HEAD(&dev->open_queue);
+	spin_lock_init(&dev->lock);
+	dev->rcache = CACHE_PREFETCH;
+	dev->wcache = CACHE_WRITEBACK;
+
+	/* allocate a gendisk with 16 partitions */
+	gd = alloc_disk(16);
+	if (!gd) {
+		osm_err("Insufficient memory to allocate gendisk.\n");
+		rc = -ENOMEM;
+		goto cleanup_dev;
+	}
+
+	/* initialize the request queue */
+	queue = blk_init_queue(i2o_block_request_fn, &dev->lock);
+	if (!queue) {
+		osm_err("Insufficient memory to allocate request queue.\n");
+		rc = -ENOMEM;
+		goto cleanup_queue;
+	}
+
+	blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
+
+	gd->major = I2O_MAJOR;
+	gd->queue = queue;
+	gd->fops = &i2o_block_fops;
+	gd->private_data = dev;
+
+	dev->gd = gd;
+
+	return dev;
+
+      cleanup_queue:
+	put_disk(gd);
+
+      cleanup_dev:
+	kfree(dev);
+
+      exit:
+	return ERR_PTR(rc);
+};
+
+/**
+ *	i2o_block_probe - verify if dev is a I2O Block device and install it
+ *	@dev: device to verify if it is a I2O Block device
+ *
+ *	We only verify if the user_tid of the device is 0xfff and then install
+ *	the device. Otherwise it is used by some other device (e. g. RAID).
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_probe(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	struct i2o_controller *c = i2o_dev->iop;
+	struct i2o_block_device *i2o_blk_dev;
+	struct gendisk *gd;
+	struct request_queue *queue;
+	static int unit = 0;
+	int rc;
+	u64 size;
+	u32 blocksize;
+	u16 body_size = 4;
+	u16 power;
+	unsigned short max_sectors;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+	if (c->adaptec)
+		body_size = 8;
+#endif
+
+	if (c->limit_sectors)
+		max_sectors = I2O_MAX_SECTORS_LIMITED;
+	else
+		max_sectors = I2O_MAX_SECTORS;
+
+	/* skip devices which are used by IOP */
+	if (i2o_dev->lct_data.user_tid != 0xfff) {
+		osm_debug("skipping used device %03x\n", i2o_dev->lct_data.tid);
+		return -ENODEV;
+	}
+
+	if (i2o_device_claim(i2o_dev)) {
+		osm_warn("Unable to claim device. Installation aborted\n");
+		rc = -EFAULT;
+		goto exit;
+	}
+
+	i2o_blk_dev = i2o_block_device_alloc();
+	if (IS_ERR(i2o_blk_dev)) {
+		osm_err("could not alloc a new I2O block device");
+		rc = PTR_ERR(i2o_blk_dev);
+		goto claim_release;
+	}
+
+	i2o_blk_dev->i2o_dev = i2o_dev;
+	dev_set_drvdata(dev, i2o_blk_dev);
+
+	/* setup gendisk */
+	gd = i2o_blk_dev->gd;
+	gd->first_minor = unit << 4;
+	sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
+	gd->driverfs_dev = &i2o_dev->device;
+
+	/* setup request queue */
+	queue = gd->queue;
+	queue->queuedata = i2o_blk_dev;
+
+	blk_queue_max_hw_sectors(queue, max_sectors);
+	blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
+
+	osm_debug("max sectors = %d\n", queue->max_sectors);
+	osm_debug("phys segments = %d\n", queue->max_phys_segments);
+	osm_debug("max hw segments = %d\n", queue->max_hw_segments);
+
+	/*
+	 *      Ask for the current media data. If that isn't supported
+	 *      then we ask for the device capacity data
+	 */
+	if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
+	    !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
+		blk_queue_logical_block_size(queue, le32_to_cpu(blocksize));
+	} else
+		osm_warn("unable to get blocksize of %s\n", gd->disk_name);
+
+	if (!i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
+	    !i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
+		set_capacity(gd, le64_to_cpu(size) >> KERNEL_SECTOR_SHIFT);
+	} else
+		osm_warn("could not get size of %s\n", gd->disk_name);
+
+	if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
+		i2o_blk_dev->power = power;
+
+	i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff);
+
+	add_disk(gd);
+
+	unit++;
+
+	osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+		 i2o_blk_dev->gd->disk_name);
+
+	return 0;
+
+      claim_release:
+	i2o_device_claim_release(i2o_dev);
+
+      exit:
+	return rc;
+};
+
+/* Block OSM driver struct */
+static struct i2o_driver i2o_block_driver = {
+	.name = OSM_NAME,
+	.event = i2o_block_event,
+	.reply = i2o_block_reply,
+	.classes = i2o_block_class_id,
+	.driver = {
+		   .probe = i2o_block_probe,
+		   .remove = i2o_block_remove,
+		   },
+};
+
+/**
+ *	i2o_block_init - Block OSM initialization function
+ *
+ *	Allocate the slab and mempool for request structs, registers i2o_block
+ *	block device and finally register the Block OSM in the I2O core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_block_init(void)
+{
+	int rc;
+	int size;
+
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	/* Allocate request mempool and slab */
+	size = sizeof(struct i2o_block_request);
+	i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
+						  SLAB_HWCACHE_ALIGN, NULL);
+	if (!i2o_blk_req_pool.slab) {
+		osm_err("can't init request slab\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	i2o_blk_req_pool.pool =
+		mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
+					 i2o_blk_req_pool.slab);
+	if (!i2o_blk_req_pool.pool) {
+		osm_err("can't init request mempool\n");
+		rc = -ENOMEM;
+		goto free_slab;
+	}
+
+	/* Register the block device interfaces */
+	rc = register_blkdev(I2O_MAJOR, "i2o_block");
+	if (rc) {
+		osm_err("unable to register block device\n");
+		goto free_mempool;
+	}
+#ifdef MODULE
+	osm_info("registered device at major %d\n", I2O_MAJOR);
+#endif
+
+	/* Register Block OSM into I2O core */
+	rc = i2o_driver_register(&i2o_block_driver);
+	if (rc) {
+		osm_err("Could not register Block driver\n");
+		goto unregister_blkdev;
+	}
+
+	return 0;
+
+      unregister_blkdev:
+	unregister_blkdev(I2O_MAJOR, "i2o_block");
+
+      free_mempool:
+	mempool_destroy(i2o_blk_req_pool.pool);
+
+      free_slab:
+	kmem_cache_destroy(i2o_blk_req_pool.slab);
+
+      exit:
+	return rc;
+};
+
+/**
+ *	i2o_block_exit - Block OSM exit function
+ *
+ *	Unregisters Block OSM from I2O core, unregisters i2o_block block device
+ *	and frees the mempool and slab.
+ */
+static void __exit i2o_block_exit(void)
+{
+	/* Unregister I2O Block OSM from I2O core */
+	i2o_driver_unregister(&i2o_block_driver);
+
+	/* Unregister block device */
+	unregister_blkdev(I2O_MAJOR, "i2o_block");
+
+	/* Free request mempool and slab */
+	mempool_destroy(i2o_blk_req_pool.pool);
+	kmem_cache_destroy(i2o_blk_req_pool.slab);
+};
+
+MODULE_AUTHOR("Red Hat");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_block_init);
+module_exit(i2o_block_exit);
diff --git a/drivers/message/i2o/i2o_block.h b/drivers/staging/i2o/i2o_block.h
similarity index 100%
rename from drivers/message/i2o/i2o_block.h
rename to drivers/staging/i2o/i2o_block.h
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/staging/i2o/i2o_config.c
similarity index 100%
rename from drivers/message/i2o/i2o_config.c
rename to drivers/staging/i2o/i2o_config.c
diff --git a/drivers/staging/i2o/i2o_proc.c b/drivers/staging/i2o/i2o_proc.c
new file mode 100644
index 0000000..ad84f33
--- /dev/null
+++ b/drivers/staging/i2o/i2o_proc.c
@@ -0,0 +1,2045 @@
+/*
+ *	procfs handler for Linux I2O subsystem
+ *
+ *	(c) Copyright 1999	Deepak Saxena
+ *
+ *	Originally written by Deepak Saxena(deepak@plexity.net)
+ *
+ *	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 is an initial test release. The code is based on the design of the
+ *	ide procfs system (drivers/block/ide-proc.c). Some code taken from
+ *	i2o-core module by Alan Cox.
+ *
+ *	DISCLAIMER: This code is still under development/test and may cause
+ *	your system to behave unpredictably.  Use at your own discretion.
+ *
+ *
+ *	Fixes/additions:
+ *		Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ *		Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
+ *		University of Helsinki, Department of Computer Science
+ *			LAN entries
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>
+ *			Changes for new I2O API
+ */
+
+#define OSM_NAME	"proc-osm"
+#define OSM_VERSION	"1.316"
+#define OSM_DESCRIPTION	"I2O ProcFS OSM"
+
+#define I2O_MAX_MODULES 4
+// FIXME!
+#define FMT_U64_HEX "0x%08x%08x"
+#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "i2o.h"
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+/* Structure used to define /proc entries */
+typedef struct _i2o_proc_entry_t {
+	char *name;		/* entry name */
+	umode_t mode;		/* mode */
+	const struct file_operations *fops;	/* open function */
+} i2o_proc_entry;
+
+/* global I2O /proc/i2o entry */
+static struct proc_dir_entry *i2o_proc_dir_root;
+
+/* proc OSM driver struct */
+static struct i2o_driver i2o_proc_driver = {
+	.name = OSM_NAME,
+};
+
+static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
+{
+	int i;
+
+	/* 19990419 -sralston
+	 *      The I2O v1.5 (and v2.0 so far) "official specification"
+	 *      got serial numbers WRONG!
+	 *      Apparently, and despite what Section 3.4.4 says and
+	 *      Figure 3-35 shows (pg 3-39 in the pdf doc),
+	 *      the convention / consensus seems to be:
+	 *        + First byte is SNFormat
+	 *        + Second byte is SNLen (but only if SNFormat==7 (?))
+	 *        + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
+	 */
+	switch (serialno[0]) {
+	case I2O_SNFORMAT_BINARY:	/* Binary */
+		seq_printf(seq, "0x");
+		for (i = 0; i < serialno[1]; i++) {
+			seq_printf(seq, "%02X", serialno[2 + i]);
+		}
+		break;
+
+	case I2O_SNFORMAT_ASCII:	/* ASCII */
+		if (serialno[1] < ' ') {	/* printable or SNLen? */
+			/* sanity */
+			max_len =
+			    (max_len < serialno[1]) ? max_len : serialno[1];
+			serialno[1 + max_len] = '\0';
+
+			/* just print it */
+			seq_printf(seq, "%s", &serialno[2]);
+		} else {
+			/* print chars for specified length */
+			for (i = 0; i < serialno[1]; i++) {
+				seq_printf(seq, "%c", serialno[2 + i]);
+			}
+		}
+		break;
+
+	case I2O_SNFORMAT_UNICODE:	/* UNICODE */
+		seq_printf(seq, "UNICODE Format.  Can't Display\n");
+		break;
+
+	case I2O_SNFORMAT_LAN48_MAC:	/* LAN-48 MAC Address */
+		seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
+		break;
+
+	case I2O_SNFORMAT_WAN:	/* WAN MAC Address */
+		/* FIXME: Figure out what a WAN access address looks like?? */
+		seq_printf(seq, "WAN Access Address");
+		break;
+
+/* plus new in v2.0 */
+	case I2O_SNFORMAT_LAN64_MAC:	/* LAN-64 MAC Address */
+		/* FIXME: Figure out what a LAN-64 address really looks like?? */
+		seq_printf(seq,
+			   "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
+			   serialno[8], serialno[9], &serialno[2]);
+		break;
+
+	case I2O_SNFORMAT_DDM:	/* I2O DDM */
+		seq_printf(seq,
+			   "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
+			   *(u16 *) & serialno[2],
+			   *(u16 *) & serialno[4], *(u16 *) & serialno[6]);
+		break;
+
+	case I2O_SNFORMAT_IEEE_REG64:	/* IEEE Registered (64-bit) */
+	case I2O_SNFORMAT_IEEE_REG128:	/* IEEE Registered (128-bit) */
+		/* FIXME: Figure if this is even close?? */
+		seq_printf(seq,
+			   "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
+			   *(u32 *) & serialno[2],
+			   *(u32 *) & serialno[6],
+			   *(u32 *) & serialno[10], *(u32 *) & serialno[14]);
+		break;
+
+	case I2O_SNFORMAT_UNKNOWN:	/* Unknown 0    */
+	case I2O_SNFORMAT_UNKNOWN2:	/* Unknown 0xff */
+	default:
+		seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *	i2o_get_class_name - 	do i2o class name lookup
+ *	@class: class number
+ *
+ *	Return a descriptive string for an i2o class.
+ */
+static const char *i2o_get_class_name(int class)
+{
+	int idx = 16;
+	static char *i2o_class_name[] = {
+		"Executive",
+		"Device Driver Module",
+		"Block Device",
+		"Tape Device",
+		"LAN Interface",
+		"WAN Interface",
+		"Fibre Channel Port",
+		"Fibre Channel Device",
+		"SCSI Device",
+		"ATE Port",
+		"ATE Device",
+		"Floppy Controller",
+		"Floppy Device",
+		"Secondary Bus Port",
+		"Peer Transport Agent",
+		"Peer Transport",
+		"Unknown"
+	};
+
+	switch (class & 0xfff) {
+	case I2O_CLASS_EXECUTIVE:
+		idx = 0;
+		break;
+	case I2O_CLASS_DDM:
+		idx = 1;
+		break;
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+		idx = 2;
+		break;
+	case I2O_CLASS_SEQUENTIAL_STORAGE:
+		idx = 3;
+		break;
+	case I2O_CLASS_LAN:
+		idx = 4;
+		break;
+	case I2O_CLASS_WAN:
+		idx = 5;
+		break;
+	case I2O_CLASS_FIBRE_CHANNEL_PORT:
+		idx = 6;
+		break;
+	case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
+		idx = 7;
+		break;
+	case I2O_CLASS_SCSI_PERIPHERAL:
+		idx = 8;
+		break;
+	case I2O_CLASS_ATE_PORT:
+		idx = 9;
+		break;
+	case I2O_CLASS_ATE_PERIPHERAL:
+		idx = 10;
+		break;
+	case I2O_CLASS_FLOPPY_CONTROLLER:
+		idx = 11;
+		break;
+	case I2O_CLASS_FLOPPY_DEVICE:
+		idx = 12;
+		break;
+	case I2O_CLASS_BUS_ADAPTER:
+		idx = 13;
+		break;
+	case I2O_CLASS_PEER_TRANSPORT_AGENT:
+		idx = 14;
+		break;
+	case I2O_CLASS_PEER_TRANSPORT:
+		idx = 15;
+		break;
+	}
+
+	return i2o_class_name[idx];
+}
+
+#define SCSI_TABLE_SIZE	13
+static char *scsi_devices[] = {
+	"Direct-Access Read/Write",
+	"Sequential-Access Storage",
+	"Printer",
+	"Processor",
+	"WORM Device",
+	"CD-ROM Device",
+	"Scanner Device",
+	"Optical Memory Device",
+	"Medium Changer Device",
+	"Communications Device",
+	"Graphics Art Pre-Press Device",
+	"Graphics Art Pre-Press Device",
+	"Array Controller Device"
+};
+
+static char *chtostr(char *tmp, u8 *chars, int n)
+{
+	tmp[0] = 0;
+	return strncat(tmp, (char *)chars, n);
+}
+
+static int i2o_report_query_status(struct seq_file *seq, int block_status,
+				   char *group)
+{
+	switch (block_status) {
+	case -ETIMEDOUT:
+		return seq_printf(seq, "Timeout reading group %s.\n", group);
+	case -ENOMEM:
+		return seq_printf(seq, "No free memory to read the table.\n");
+	case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
+		return seq_printf(seq, "Group %s not supported.\n", group);
+	default:
+		return seq_printf(seq,
+				  "Error reading group %s. BlockStatus 0x%02X\n",
+				  group, -block_status);
+	}
+}
+
+static char *bus_strings[] = {
+	"Local Bus",
+	"ISA",
+	"EISA",
+	"PCI",
+	"PCMCIA",
+	"NUBUS",
+	"CARDBUS"
+};
+
+static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt;
+	u32 bus;
+	int i;
+
+	if (hrt->hrt_version) {
+		seq_printf(seq,
+			   "HRT table for controller is too new a version.\n");
+		return 0;
+	}
+
+	seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
+		   hrt->num_entries, hrt->entry_len << 2);
+
+	for (i = 0; i < hrt->num_entries; i++) {
+		seq_printf(seq, "Entry %d:\n", i);
+		seq_printf(seq, "   Adapter ID: %0#10x\n",
+			   hrt->hrt_entry[i].adapter_id);
+		seq_printf(seq, "   Controlling tid: %0#6x\n",
+			   hrt->hrt_entry[i].parent_tid);
+
+		if (hrt->hrt_entry[i].bus_type != 0x80) {
+			bus = hrt->hrt_entry[i].bus_type;
+			seq_printf(seq, "   %s Information\n",
+				   bus_strings[bus]);
+
+			switch (bus) {
+			case I2O_BUS_LOCAL:
+				seq_printf(seq, "     IOBase: %0#6x,",
+					   hrt->hrt_entry[i].bus.local_bus.
+					   LbBaseIOPort);
+				seq_printf(seq, " MemoryBase: %0#10x\n",
+					   hrt->hrt_entry[i].bus.local_bus.
+					   LbBaseMemoryAddress);
+				break;
+
+			case I2O_BUS_ISA:
+				seq_printf(seq, "     IOBase: %0#6x,",
+					   hrt->hrt_entry[i].bus.isa_bus.
+					   IsaBaseIOPort);
+				seq_printf(seq, " MemoryBase: %0#10x,",
+					   hrt->hrt_entry[i].bus.isa_bus.
+					   IsaBaseMemoryAddress);
+				seq_printf(seq, " CSN: %0#4x,",
+					   hrt->hrt_entry[i].bus.isa_bus.CSN);
+				break;
+
+			case I2O_BUS_EISA:
+				seq_printf(seq, "     IOBase: %0#6x,",
+					   hrt->hrt_entry[i].bus.eisa_bus.
+					   EisaBaseIOPort);
+				seq_printf(seq, " MemoryBase: %0#10x,",
+					   hrt->hrt_entry[i].bus.eisa_bus.
+					   EisaBaseMemoryAddress);
+				seq_printf(seq, " Slot: %0#4x,",
+					   hrt->hrt_entry[i].bus.eisa_bus.
+					   EisaSlotNumber);
+				break;
+
+			case I2O_BUS_PCI:
+				seq_printf(seq, "     Bus: %0#4x",
+					   hrt->hrt_entry[i].bus.pci_bus.
+					   PciBusNumber);
+				seq_printf(seq, " Dev: %0#4x",
+					   hrt->hrt_entry[i].bus.pci_bus.
+					   PciDeviceNumber);
+				seq_printf(seq, " Func: %0#4x",
+					   hrt->hrt_entry[i].bus.pci_bus.
+					   PciFunctionNumber);
+				seq_printf(seq, " Vendor: %0#6x",
+					   hrt->hrt_entry[i].bus.pci_bus.
+					   PciVendorID);
+				seq_printf(seq, " Device: %0#6x\n",
+					   hrt->hrt_entry[i].bus.pci_bus.
+					   PciDeviceID);
+				break;
+
+			default:
+				seq_printf(seq, "      Unsupported Bus Type\n");
+			}
+		} else
+			seq_printf(seq, "   Unknown Bus Type\n");
+	}
+
+	return 0;
+}
+
+static int i2o_seq_show_lct(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	i2o_lct *lct = (i2o_lct *) c->lct;
+	int entries;
+	int i;
+
+#define BUS_TABLE_SIZE 3
+	static char *bus_ports[] = {
+		"Generic Bus",
+		"SCSI Bus",
+		"Fibre Channel Bus"
+	};
+
+	entries = (lct->table_size - 3) / 9;
+
+	seq_printf(seq, "LCT contains %d %s\n", entries,
+		   entries == 1 ? "entry" : "entries");
+	if (lct->boot_tid)
+		seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid);
+
+	seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
+
+	for (i = 0; i < entries; i++) {
+		seq_printf(seq, "Entry %d\n", i);
+		seq_printf(seq, "  Class, SubClass  : %s",
+			   i2o_get_class_name(lct->lct_entry[i].class_id));
+
+		/*
+		 *      Classes which we'll print subclass info for
+		 */
+		switch (lct->lct_entry[i].class_id & 0xFFF) {
+		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+			switch (lct->lct_entry[i].sub_class) {
+			case 0x00:
+				seq_printf(seq, ", Direct-Access Read/Write");
+				break;
+
+			case 0x04:
+				seq_printf(seq, ", WORM Drive");
+				break;
+
+			case 0x05:
+				seq_printf(seq, ", CD-ROM Drive");
+				break;
+
+			case 0x07:
+				seq_printf(seq, ", Optical Memory Device");
+				break;
+
+			default:
+				seq_printf(seq, ", Unknown (0x%02x)",
+					   lct->lct_entry[i].sub_class);
+				break;
+			}
+			break;
+
+		case I2O_CLASS_LAN:
+			switch (lct->lct_entry[i].sub_class & 0xFF) {
+			case 0x30:
+				seq_printf(seq, ", Ethernet");
+				break;
+
+			case 0x40:
+				seq_printf(seq, ", 100base VG");
+				break;
+
+			case 0x50:
+				seq_printf(seq, ", IEEE 802.5/Token-Ring");
+				break;
+
+			case 0x60:
+				seq_printf(seq, ", ANSI X3T9.5 FDDI");
+				break;
+
+			case 0x70:
+				seq_printf(seq, ", Fibre Channel");
+				break;
+
+			default:
+				seq_printf(seq, ", Unknown Sub-Class (0x%02x)",
+					   lct->lct_entry[i].sub_class & 0xFF);
+				break;
+			}
+			break;
+
+		case I2O_CLASS_SCSI_PERIPHERAL:
+			if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
+				seq_printf(seq, ", %s",
+					   scsi_devices[lct->lct_entry[i].
+							sub_class]);
+			else
+				seq_printf(seq, ", Unknown Device Type");
+			break;
+
+		case I2O_CLASS_BUS_ADAPTER:
+			if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
+				seq_printf(seq, ", %s",
+					   bus_ports[lct->lct_entry[i].
+						     sub_class]);
+			else
+				seq_printf(seq, ", Unknown Bus Type");
+			break;
+		}
+		seq_printf(seq, "\n");
+
+		seq_printf(seq, "  Local TID        : 0x%03x\n",
+			   lct->lct_entry[i].tid);
+		seq_printf(seq, "  User TID         : 0x%03x\n",
+			   lct->lct_entry[i].user_tid);
+		seq_printf(seq, "  Parent TID       : 0x%03x\n",
+			   lct->lct_entry[i].parent_tid);
+		seq_printf(seq, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
+			   lct->lct_entry[i].identity_tag[0],
+			   lct->lct_entry[i].identity_tag[1],
+			   lct->lct_entry[i].identity_tag[2],
+			   lct->lct_entry[i].identity_tag[3],
+			   lct->lct_entry[i].identity_tag[4],
+			   lct->lct_entry[i].identity_tag[5],
+			   lct->lct_entry[i].identity_tag[6],
+			   lct->lct_entry[i].identity_tag[7]);
+		seq_printf(seq, "  Change Indicator : %0#10x\n",
+			   lct->lct_entry[i].change_ind);
+		seq_printf(seq, "  Event Capab Mask : %0#10x\n",
+			   lct->lct_entry[i].device_flags);
+	}
+
+	return 0;
+}
+
+static int i2o_seq_show_status(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	char prodstr[25];
+	int version;
+	i2o_status_block *sb = c->status_block.virt;
+
+	i2o_status_get(c);	// reread the status block
+
+	seq_printf(seq, "Organization ID        : %0#6x\n", sb->org_id);
+
+	version = sb->i2o_version;
+
+/* FIXME for Spec 2.0
+	if (version == 0x02) {
+		seq_printf(seq, "Lowest I2O version supported: ");
+		switch(workspace[2]) {
+			case 0x00:
+				seq_printf(seq, "1.0\n");
+				break;
+			case 0x01:
+				seq_printf(seq, "1.5\n");
+				break;
+			case 0x02:
+				seq_printf(seq, "2.0\n");
+				break;
+		}
+
+		seq_printf(seq, "Highest I2O version supported: ");
+		switch(workspace[3]) {
+			case 0x00:
+				seq_printf(seq, "1.0\n");
+				break;
+			case 0x01:
+				seq_printf(seq, "1.5\n");
+				break;
+			case 0x02:
+				seq_printf(seq, "2.0\n");
+				break;
+		}
+	}
+*/
+	seq_printf(seq, "IOP ID                 : %0#5x\n", sb->iop_id);
+	seq_printf(seq, "Host Unit ID           : %0#6x\n", sb->host_unit_id);
+	seq_printf(seq, "Segment Number         : %0#5x\n", sb->segment_number);
+
+	seq_printf(seq, "I2O version            : ");
+	switch (version) {
+	case 0x00:
+		seq_printf(seq, "1.0\n");
+		break;
+	case 0x01:
+		seq_printf(seq, "1.5\n");
+		break;
+	case 0x02:
+		seq_printf(seq, "2.0\n");
+		break;
+	default:
+		seq_printf(seq, "Unknown version\n");
+	}
+
+	seq_printf(seq, "IOP State              : ");
+	switch (sb->iop_state) {
+	case 0x01:
+		seq_printf(seq, "INIT\n");
+		break;
+
+	case 0x02:
+		seq_printf(seq, "RESET\n");
+		break;
+
+	case 0x04:
+		seq_printf(seq, "HOLD\n");
+		break;
+
+	case 0x05:
+		seq_printf(seq, "READY\n");
+		break;
+
+	case 0x08:
+		seq_printf(seq, "OPERATIONAL\n");
+		break;
+
+	case 0x10:
+		seq_printf(seq, "FAILED\n");
+		break;
+
+	case 0x11:
+		seq_printf(seq, "FAULTED\n");
+		break;
+
+	default:
+		seq_printf(seq, "Unknown\n");
+		break;
+	}
+
+	seq_printf(seq, "Messenger Type         : ");
+	switch (sb->msg_type) {
+	case 0x00:
+		seq_printf(seq, "Memory mapped\n");
+		break;
+	case 0x01:
+		seq_printf(seq, "Memory mapped only\n");
+		break;
+	case 0x02:
+		seq_printf(seq, "Remote only\n");
+		break;
+	case 0x03:
+		seq_printf(seq, "Memory mapped and remote\n");
+		break;
+	default:
+		seq_printf(seq, "Unknown\n");
+	}
+
+	seq_printf(seq, "Inbound Frame Size     : %d bytes\n",
+		   sb->inbound_frame_size << 2);
+	seq_printf(seq, "Max Inbound Frames     : %d\n",
+		   sb->max_inbound_frames);
+	seq_printf(seq, "Current Inbound Frames : %d\n",
+		   sb->cur_inbound_frames);
+	seq_printf(seq, "Max Outbound Frames    : %d\n",
+		   sb->max_outbound_frames);
+
+	/* Spec doesn't say if NULL terminated or not... */
+	memcpy(prodstr, sb->product_id, 24);
+	prodstr[24] = '\0';
+	seq_printf(seq, "Product ID             : %s\n", prodstr);
+	seq_printf(seq, "Expected LCT Size      : %d bytes\n",
+		   sb->expected_lct_size);
+
+	seq_printf(seq, "IOP Capabilities\n");
+	seq_printf(seq, "    Context Field Size Support : ");
+	switch (sb->iop_capabilities & 0x0000003) {
+	case 0:
+		seq_printf(seq, "Supports only 32-bit context fields\n");
+		break;
+	case 1:
+		seq_printf(seq, "Supports only 64-bit context fields\n");
+		break;
+	case 2:
+		seq_printf(seq, "Supports 32-bit and 64-bit context fields, "
+			   "but not concurrently\n");
+		break;
+	case 3:
+		seq_printf(seq, "Supports 32-bit and 64-bit context fields "
+			   "concurrently\n");
+		break;
+	default:
+		seq_printf(seq, "0x%08x\n", sb->iop_capabilities);
+	}
+	seq_printf(seq, "    Current Context Field Size : ");
+	switch (sb->iop_capabilities & 0x0000000C) {
+	case 0:
+		seq_printf(seq, "not configured\n");
+		break;
+	case 4:
+		seq_printf(seq, "Supports only 32-bit context fields\n");
+		break;
+	case 8:
+		seq_printf(seq, "Supports only 64-bit context fields\n");
+		break;
+	case 12:
+		seq_printf(seq, "Supports both 32-bit or 64-bit context fields "
+			   "concurrently\n");
+		break;
+	default:
+		seq_printf(seq, "\n");
+	}
+	seq_printf(seq, "    Inbound Peer Support       : %s\n",
+		   (sb->
+		    iop_capabilities & 0x00000010) ? "Supported" :
+		   "Not supported");
+	seq_printf(seq, "    Outbound Peer Support      : %s\n",
+		   (sb->
+		    iop_capabilities & 0x00000020) ? "Supported" :
+		   "Not supported");
+	seq_printf(seq, "    Peer to Peer Support       : %s\n",
+		   (sb->
+		    iop_capabilities & 0x00000040) ? "Supported" :
+		   "Not supported");
+
+	seq_printf(seq, "Desired private memory size   : %d kB\n",
+		   sb->desired_mem_size >> 10);
+	seq_printf(seq, "Allocated private memory size : %d kB\n",
+		   sb->current_mem_size >> 10);
+	seq_printf(seq, "Private memory base address   : %0#10x\n",
+		   sb->current_mem_base);
+	seq_printf(seq, "Desired private I/O size      : %d kB\n",
+		   sb->desired_io_size >> 10);
+	seq_printf(seq, "Allocated private I/O size    : %d kB\n",
+		   sb->current_io_size >> 10);
+	seq_printf(seq, "Private I/O base address      : %0#10x\n",
+		   sb->current_io_base);
+
+	return 0;
+}
+
+static int i2o_seq_show_hw(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	static u32 work32[5];
+	static u8 *work8 = (u8 *) work32;
+	static u16 *work16 = (u16 *) work32;
+	int token;
+	u32 hwcap;
+
+	static char *cpu_table[] = {
+		"Intel 80960 series",
+		"AMD2900 series",
+		"Motorola 68000 series",
+		"ARM series",
+		"MIPS series",
+		"Sparc series",
+		"PowerPC series",
+		"Intel x86 series"
+	};
+
+	token =
+	    i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0x0000 IOP Hardware");
+		return 0;
+	}
+
+	seq_printf(seq, "I2O Vendor ID    : %0#6x\n", work16[0]);
+	seq_printf(seq, "Product ID       : %0#6x\n", work16[1]);
+	seq_printf(seq, "CPU              : ");
+	if (work8[16] > 8)
+		seq_printf(seq, "Unknown\n");
+	else
+		seq_printf(seq, "%s\n", cpu_table[work8[16]]);
+	/* Anyone using ProcessorVersion? */
+
+	seq_printf(seq, "RAM              : %dkB\n", work32[1] >> 10);
+	seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10);
+
+	hwcap = work32[3];
+	seq_printf(seq, "Capabilities : 0x%08x\n", hwcap);
+	seq_printf(seq, "   [%s] Self booting\n",
+		   (hwcap & 0x00000001) ? "+" : "-");
+	seq_printf(seq, "   [%s] Upgradable IRTOS\n",
+		   (hwcap & 0x00000002) ? "+" : "-");
+	seq_printf(seq, "   [%s] Supports downloading DDMs\n",
+		   (hwcap & 0x00000004) ? "+" : "-");
+	seq_printf(seq, "   [%s] Supports installing DDMs\n",
+		   (hwcap & 0x00000008) ? "+" : "-");
+	seq_printf(seq, "   [%s] Battery-backed RAM\n",
+		   (hwcap & 0x00000010) ? "+" : "-");
+
+	return 0;
+}
+
+/* Executive group 0003h - Executing DDM List (table) */
+static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	int token;
+	int i;
+
+	typedef struct _i2o_exec_execute_ddm_table {
+		u16 ddm_tid;
+		u8 module_type;
+		u8 reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8 module_name_version[28];
+		u32 data_size;
+		u32 code_size;
+	} i2o_exec_execute_ddm_table;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES];
+	} *result;
+
+	i2o_exec_execute_ddm_table ddm_table;
+	char tmp[28 + 1];
+
+	result = kmalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return -ENOMEM;
+
+	token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1,
+				   NULL, 0, result, sizeof(*result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0x0003 Executing DDM List");
+		goto out;
+	}
+
+	seq_printf(seq,
+		   "Tid   Module_type     Vendor Mod_id  Module_name             Vrs  Data_size Code_size\n");
+	ddm_table = result->ddm_table[0];
+
+	for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) {
+		seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
+
+		switch (ddm_table.module_type) {
+		case 0x01:
+			seq_printf(seq, "Downloaded DDM  ");
+			break;
+		case 0x22:
+			seq_printf(seq, "Embedded DDM    ");
+			break;
+		default:
+			seq_printf(seq, "                ");
+		}
+
+		seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id);
+		seq_printf(seq, "%-#8x", ddm_table.module_id);
+		seq_printf(seq, "%-29s",
+			   chtostr(tmp, ddm_table.module_name_version, 28));
+		seq_printf(seq, "%9d  ", ddm_table.data_size);
+		seq_printf(seq, "%8d", ddm_table.code_size);
+
+		seq_printf(seq, "\n");
+	}
+      out:
+	kfree(result);
+	return 0;
+}
+
+/* Executive group 0004h - Driver Store (scalar) */
+static int i2o_seq_show_driver_store(struct seq_file *seq, void *v)
+{
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	u32 work32[8];
+	int token;
+
+	token =
+	    i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32));
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0x0004 Driver Store");
+		return 0;
+	}
+
+	seq_printf(seq, "Module limit  : %d\n"
+		   "Module count  : %d\n"
+		   "Current space : %d kB\n"
+		   "Free space    : %d kB\n",
+		   work32[0], work32[1], work32[2] >> 10, work32[3] >> 10);
+
+	return 0;
+}
+
+/* Executive group 0005h - Driver Store Table (table) */
+static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
+{
+	typedef struct _i2o_driver_store {
+		u16 stored_ddm_index;
+		u8 module_type;
+		u8 reserved;
+		u16 i2o_vendor_id;
+		u16 module_id;
+		u8 module_name_version[28];
+		u8 date[8];
+		u32 module_size;
+		u32 mpb_size;
+		u32 module_flags;
+	} i2o_driver_store_table;
+
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
+	int token;
+	int i;
+
+	typedef struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_driver_store_table dst[I2O_MAX_MODULES];
+	} i2o_driver_result_table;
+
+	i2o_driver_result_table *result;
+	i2o_driver_store_table *dst;
+	char tmp[28 + 1];
+
+	result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
+	if (result == NULL)
+		return -ENOMEM;
+
+	token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1,
+				   NULL, 0, result, sizeof(*result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0x0005 DRIVER STORE TABLE");
+		kfree(result);
+		return 0;
+	}
+
+	seq_printf(seq,
+		   "#  Module_type     Vendor Mod_id  Module_name             Vrs"
+		   "Date     Mod_size Par_size Flags\n");
+	for (i = 0, dst = &result->dst[0]; i < result->row_count;
+	     dst = &result->dst[++i]) {
+		seq_printf(seq, "%-3d", dst->stored_ddm_index);
+		switch (dst->module_type) {
+		case 0x01:
+			seq_printf(seq, "Downloaded DDM  ");
+			break;
+		case 0x22:
+			seq_printf(seq, "Embedded DDM    ");
+			break;
+		default:
+			seq_printf(seq, "                ");
+		}
+
+		seq_printf(seq, "%-#7x", dst->i2o_vendor_id);
+		seq_printf(seq, "%-#8x", dst->module_id);
+		seq_printf(seq, "%-29s",
+			   chtostr(tmp, dst->module_name_version, 28));
+		seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8));
+		seq_printf(seq, "%8d ", dst->module_size);
+		seq_printf(seq, "%8d ", dst->mpb_size);
+		seq_printf(seq, "0x%04x", dst->module_flags);
+		seq_printf(seq, "\n");
+	}
+
+	kfree(result);
+	return 0;
+}
+
+/* Generic group F000h - Params Descriptor (table) */
+static int i2o_seq_show_groups(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+	u8 properties;
+
+	typedef struct _i2o_group_info {
+		u16 group_number;
+		u16 field_count;
+		u16 row_count;
+		u8 properties;
+		u8 reserved;
+	} i2o_group_info;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_group_info group[256];
+	} *result;
+
+	result = kmalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return -ENOMEM;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
+				   result, sizeof(*result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF000 Params Descriptor");
+		goto out;
+	}
+
+	seq_printf(seq,
+		   "#  Group   FieldCount RowCount Type   Add Del Clear\n");
+
+	for (i = 0; i < result->row_count; i++) {
+		seq_printf(seq, "%-3d", i);
+		seq_printf(seq, "0x%04X ", result->group[i].group_number);
+		seq_printf(seq, "%10d ", result->group[i].field_count);
+		seq_printf(seq, "%8d ", result->group[i].row_count);
+
+		properties = result->group[i].properties;
+		if (properties & 0x1)
+			seq_printf(seq, "Table  ");
+		else
+			seq_printf(seq, "Scalar ");
+		if (properties & 0x2)
+			seq_printf(seq, " + ");
+		else
+			seq_printf(seq, " - ");
+		if (properties & 0x4)
+			seq_printf(seq, "  + ");
+		else
+			seq_printf(seq, "  - ");
+		if (properties & 0x8)
+			seq_printf(seq, "  + ");
+		else
+			seq_printf(seq, "  - ");
+
+		seq_printf(seq, "\n");
+	}
+
+	if (result->more_flag)
+		seq_printf(seq, "There is more...\n");
+      out:
+	kfree(result);
+	return 0;
+}
+
+/* Generic group F001h - Physical Device Table (table) */
+static int i2o_seq_show_phys_device(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u32 adapter_id[64];
+	} result;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0,
+				   &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0xF001 Physical Device Table");
+		return 0;
+	}
+
+	if (result.row_count)
+		seq_printf(seq, "#  AdapterId\n");
+
+	for (i = 0; i < result.row_count; i++) {
+		seq_printf(seq, "%-2d", i);
+		seq_printf(seq, "%#7x\n", result.adapter_id[i]);
+	}
+
+	if (result.more_flag)
+		seq_printf(seq, "There is more...\n");
+
+	return 0;
+}
+
+/* Generic group F002h - Claimed Table (table) */
+static int i2o_seq_show_claimed(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u16 claimed_tid[64];
+	} result;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0,
+				   &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF002 Claimed Table");
+		return 0;
+	}
+
+	if (result.row_count)
+		seq_printf(seq, "#  ClaimedTid\n");
+
+	for (i = 0; i < result.row_count; i++) {
+		seq_printf(seq, "%-2d", i);
+		seq_printf(seq, "%#7x\n", result.claimed_tid[i]);
+	}
+
+	if (result.more_flag)
+		seq_printf(seq, "There is more...\n");
+
+	return 0;
+}
+
+/* Generic group F003h - User Table (table) */
+static int i2o_seq_show_users(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+
+	typedef struct _i2o_user_table {
+		u16 instance;
+		u16 user_tid;
+		u8 claim_type;
+		u8 reserved1;
+		u16 reserved2;
+	} i2o_user_table;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_user_table user[64];
+	} *result;
+
+	result = kmalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return -ENOMEM;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0,
+				   result, sizeof(*result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF003 User Table");
+		goto out;
+	}
+
+	seq_printf(seq, "#  Instance UserTid ClaimType\n");
+
+	for (i = 0; i < result->row_count; i++) {
+		seq_printf(seq, "%-3d", i);
+		seq_printf(seq, "%#8x ", result->user[i].instance);
+		seq_printf(seq, "%#7x ", result->user[i].user_tid);
+		seq_printf(seq, "%#9x\n", result->user[i].claim_type);
+	}
+
+	if (result->more_flag)
+		seq_printf(seq, "There is more...\n");
+      out:
+	kfree(result);
+	return 0;
+}
+
+/* Generic group F005h - Private message extensions (table) (optional) */
+static int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+
+	typedef struct _i2o_private {
+		u16 ext_instance;
+		u16 organization_id;
+		u16 x_function_code;
+	} i2o_private;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		i2o_private extension[64];
+	} result;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
+				   &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0xF005 Private Message Extensions (optional)");
+		return 0;
+	}
+
+	seq_printf(seq, "Instance#  OrgId  FunctionCode\n");
+
+	for (i = 0; i < result.row_count; i++) {
+		seq_printf(seq, "%0#9x ", result.extension[i].ext_instance);
+		seq_printf(seq, "%0#6x ", result.extension[i].organization_id);
+		seq_printf(seq, "%0#6x", result.extension[i].x_function_code);
+
+		seq_printf(seq, "\n");
+	}
+
+	if (result.more_flag)
+		seq_printf(seq, "There is more...\n");
+
+	return 0;
+}
+
+/* Generic group F006h - Authorized User Table (table) */
+static int i2o_seq_show_authorized_users(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+	int i;
+
+	struct {
+		u16 result_count;
+		u16 pad;
+		u16 block_size;
+		u8 block_status;
+		u8 error_info_size;
+		u16 row_count;
+		u16 more_flag;
+		u32 alternate_tid[64];
+	} result;
+
+	token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0,
+				   &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0xF006 Autohorized User Table");
+		return 0;
+	}
+
+	if (result.row_count)
+		seq_printf(seq, "#  AlternateTid\n");
+
+	for (i = 0; i < result.row_count; i++) {
+		seq_printf(seq, "%-2d", i);
+		seq_printf(seq, "%#7x ", result.alternate_tid[i]);
+	}
+
+	if (result.more_flag)
+		seq_printf(seq, "There is more...\n");
+
+	return 0;
+}
+
+/* Generic group F100h - Device Identity (scalar) */
+static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	static u32 work32[128];	// allow for "stuff" + up to 256 byte (max) serial number
+	// == (allow) 512d bytes (max)
+	static u16 *work16 = (u16 *) work32;
+	int token;
+	char tmp[16 + 1];
+
+	token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF100 Device Identity");
+		return 0;
+	}
+
+	seq_printf(seq, "Device Class  : %s\n", i2o_get_class_name(work16[0]));
+	seq_printf(seq, "Owner TID     : %0#5x\n", work16[2]);
+	seq_printf(seq, "Parent TID    : %0#5x\n", work16[3]);
+	seq_printf(seq, "Vendor info   : %s\n",
+		   chtostr(tmp, (u8 *) (work32 + 2), 16));
+	seq_printf(seq, "Product info  : %s\n",
+		   chtostr(tmp, (u8 *) (work32 + 6), 16));
+	seq_printf(seq, "Description   : %s\n",
+		   chtostr(tmp, (u8 *) (work32 + 10), 16));
+	seq_printf(seq, "Product rev.  : %s\n",
+		   chtostr(tmp, (u8 *) (work32 + 14), 8));
+
+	seq_printf(seq, "Serial number : ");
+	print_serial_number(seq, (u8 *) (work32 + 16),
+			    /* allow for SNLen plus
+			     * possible trailing '\0'
+			     */
+			    sizeof(work32) - (16 * sizeof(u32)) - 2);
+	seq_printf(seq, "\n");
+
+	return 0;
+}
+
+static int i2o_seq_show_dev_name(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+
+	seq_printf(seq, "%s\n", dev_name(&d->device));
+
+	return 0;
+}
+
+/* Generic group F101h - DDM Identity (scalar) */
+static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+
+	struct {
+		u16 ddm_tid;
+		u8 module_name[24];
+		u8 module_rev[8];
+		u8 sn_format;
+		u8 serial_number[12];
+		u8 pad[256];	// allow up to 256 byte (max) serial number
+	} result;
+
+	char tmp[24 + 1];
+
+	token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF101 DDM Identity");
+		return 0;
+	}
+
+	seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid);
+	seq_printf(seq, "Module name         : %s\n",
+		   chtostr(tmp, result.module_name, 24));
+	seq_printf(seq, "Module revision     : %s\n",
+		   chtostr(tmp, result.module_rev, 8));
+
+	seq_printf(seq, "Serial number       : ");
+	print_serial_number(seq, result.serial_number, sizeof(result) - 36);
+	/* allow for SNLen plus possible trailing '\0' */
+
+	seq_printf(seq, "\n");
+
+	return 0;
+}
+
+/* Generic group F102h - User Information (scalar) */
+static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+
+	struct {
+		u8 device_name[64];
+		u8 service_name[64];
+		u8 physical_location[64];
+		u8 instance_number[4];
+	} result;
+
+	char tmp[64 + 1];
+
+	token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token, "0xF102 User Information");
+		return 0;
+	}
+
+	seq_printf(seq, "Device name     : %s\n",
+		   chtostr(tmp, result.device_name, 64));
+	seq_printf(seq, "Service name    : %s\n",
+		   chtostr(tmp, result.service_name, 64));
+	seq_printf(seq, "Physical name   : %s\n",
+		   chtostr(tmp, result.physical_location, 64));
+	seq_printf(seq, "Instance number : %s\n",
+		   chtostr(tmp, result.instance_number, 4));
+
+	return 0;
+}
+
+/* Generic group F103h - SGL Operating Limits (scalar) */
+static int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	static u32 work32[12];
+	static u16 *work16 = (u16 *) work32;
+	static u8 *work8 = (u8 *) work32;
+	int token;
+
+	token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0xF103 SGL Operating Limits");
+		return 0;
+	}
+
+	seq_printf(seq, "SGL chain size        : %d\n", work32[0]);
+	seq_printf(seq, "Max SGL chain size    : %d\n", work32[1]);
+	seq_printf(seq, "SGL chain size target : %d\n", work32[2]);
+	seq_printf(seq, "SGL frag count        : %d\n", work16[6]);
+	seq_printf(seq, "Max SGL frag count    : %d\n", work16[7]);
+	seq_printf(seq, "SGL frag count target : %d\n", work16[8]);
+
+/* FIXME
+	if (d->i2oversion == 0x02)
+	{
+*/
+	seq_printf(seq, "SGL data alignment    : %d\n", work16[8]);
+	seq_printf(seq, "SGL addr limit        : %d\n", work8[20]);
+	seq_printf(seq, "SGL addr sizes supported : ");
+	if (work8[21] & 0x01)
+		seq_printf(seq, "32 bit ");
+	if (work8[21] & 0x02)
+		seq_printf(seq, "64 bit ");
+	if (work8[21] & 0x04)
+		seq_printf(seq, "96 bit ");
+	if (work8[21] & 0x08)
+		seq_printf(seq, "128 bit ");
+	seq_printf(seq, "\n");
+/*
+	}
+*/
+
+	return 0;
+}
+
+/* Generic group F200h - Sensors (scalar) */
+static int i2o_seq_show_sensors(struct seq_file *seq, void *v)
+{
+	struct i2o_device *d = (struct i2o_device *)seq->private;
+	int token;
+
+	struct {
+		u16 sensor_instance;
+		u8 component;
+		u16 component_instance;
+		u8 sensor_class;
+		u8 sensor_type;
+		u8 scaling_exponent;
+		u32 actual_reading;
+		u32 minimum_reading;
+		u32 low2lowcat_treshold;
+		u32 lowcat2low_treshold;
+		u32 lowwarn2low_treshold;
+		u32 low2lowwarn_treshold;
+		u32 norm2lowwarn_treshold;
+		u32 lowwarn2norm_treshold;
+		u32 nominal_reading;
+		u32 hiwarn2norm_treshold;
+		u32 norm2hiwarn_treshold;
+		u32 high2hiwarn_treshold;
+		u32 hiwarn2high_treshold;
+		u32 hicat2high_treshold;
+		u32 hi2hicat_treshold;
+		u32 maximum_reading;
+		u8 sensor_state;
+		u16 event_enable;
+	} result;
+
+	token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result));
+
+	if (token < 0) {
+		i2o_report_query_status(seq, token,
+					"0xF200 Sensors (optional)");
+		return 0;
+	}
+
+	seq_printf(seq, "Sensor instance       : %d\n", result.sensor_instance);
+
+	seq_printf(seq, "Component             : %d = ", result.component);
+	switch (result.component) {
+	case 0:
+		seq_printf(seq, "Other");
+		break;
+	case 1:
+		seq_printf(seq, "Planar logic Board");
+		break;
+	case 2:
+		seq_printf(seq, "CPU");
+		break;
+	case 3:
+		seq_printf(seq, "Chassis");
+		break;
+	case 4:
+		seq_printf(seq, "Power Supply");
+		break;
+	case 5:
+		seq_printf(seq, "Storage");
+		break;
+	case 6:
+		seq_printf(seq, "External");
+		break;
+	}
+	seq_printf(seq, "\n");
+
+	seq_printf(seq, "Component instance    : %d\n",
+		   result.component_instance);
+	seq_printf(seq, "Sensor class          : %s\n",
+		   result.sensor_class ? "Analog" : "Digital");
+
+	seq_printf(seq, "Sensor type           : %d = ", result.sensor_type);
+	switch (result.sensor_type) {
+	case 0:
+		seq_printf(seq, "Other\n");
+		break;
+	case 1:
+		seq_printf(seq, "Thermal\n");
+		break;
+	case 2:
+		seq_printf(seq, "DC voltage (DC volts)\n");
+		break;
+	case 3:
+		seq_printf(seq, "AC voltage (AC volts)\n");
+		break;
+	case 4:
+		seq_printf(seq, "DC current (DC amps)\n");
+		break;
+	case 5:
+		seq_printf(seq, "AC current (AC volts)\n");
+		break;
+	case 6:
+		seq_printf(seq, "Door open\n");
+		break;
+	case 7:
+		seq_printf(seq, "Fan operational\n");
+		break;
+	}
+
+	seq_printf(seq, "Scaling exponent      : %d\n",
+		   result.scaling_exponent);
+	seq_printf(seq, "Actual reading        : %d\n", result.actual_reading);
+	seq_printf(seq, "Minimum reading       : %d\n", result.minimum_reading);
+	seq_printf(seq, "Low2LowCat treshold   : %d\n",
+		   result.low2lowcat_treshold);
+	seq_printf(seq, "LowCat2Low treshold   : %d\n",
+		   result.lowcat2low_treshold);
+	seq_printf(seq, "LowWarn2Low treshold  : %d\n",
+		   result.lowwarn2low_treshold);
+	seq_printf(seq, "Low2LowWarn treshold  : %d\n",
+		   result.low2lowwarn_treshold);
+	seq_printf(seq, "Norm2LowWarn treshold : %d\n",
+		   result.norm2lowwarn_treshold);
+	seq_printf(seq, "LowWarn2Norm treshold : %d\n",
+		   result.lowwarn2norm_treshold);
+	seq_printf(seq, "Nominal reading       : %d\n", result.nominal_reading);
+	seq_printf(seq, "HiWarn2Norm treshold  : %d\n",
+		   result.hiwarn2norm_treshold);
+	seq_printf(seq, "Norm2HiWarn treshold  : %d\n",
+		   result.norm2hiwarn_treshold);
+	seq_printf(seq, "High2HiWarn treshold  : %d\n",
+		   result.high2hiwarn_treshold);
+	seq_printf(seq, "HiWarn2High treshold  : %d\n",
+		   result.hiwarn2high_treshold);
+	seq_printf(seq, "HiCat2High treshold   : %d\n",
+		   result.hicat2high_treshold);
+	seq_printf(seq, "High2HiCat treshold   : %d\n",
+		   result.hi2hicat_treshold);
+	seq_printf(seq, "Maximum reading       : %d\n", result.maximum_reading);
+
+	seq_printf(seq, "Sensor state          : %d = ", result.sensor_state);
+	switch (result.sensor_state) {
+	case 0:
+		seq_printf(seq, "Normal\n");
+		break;
+	case 1:
+		seq_printf(seq, "Abnormal\n");
+		break;
+	case 2:
+		seq_printf(seq, "Unknown\n");
+		break;
+	case 3:
+		seq_printf(seq, "Low Catastrophic (LoCat)\n");
+		break;
+	case 4:
+		seq_printf(seq, "Low (Low)\n");
+		break;
+	case 5:
+		seq_printf(seq, "Low Warning (LoWarn)\n");
+		break;
+	case 6:
+		seq_printf(seq, "High Warning (HiWarn)\n");
+		break;
+	case 7:
+		seq_printf(seq, "High (High)\n");
+		break;
+	case 8:
+		seq_printf(seq, "High Catastrophic (HiCat)\n");
+		break;
+	}
+
+	seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable);
+	seq_printf(seq, "    [%s] Operational state change. \n",
+		   (result.event_enable & 0x01) ? "+" : "-");
+	seq_printf(seq, "    [%s] Low catastrophic. \n",
+		   (result.event_enable & 0x02) ? "+" : "-");
+	seq_printf(seq, "    [%s] Low reading. \n",
+		   (result.event_enable & 0x04) ? "+" : "-");
+	seq_printf(seq, "    [%s] Low warning. \n",
+		   (result.event_enable & 0x08) ? "+" : "-");
+	seq_printf(seq,
+		   "    [%s] Change back to normal from out of range state. \n",
+		   (result.event_enable & 0x10) ? "+" : "-");
+	seq_printf(seq, "    [%s] High warning. \n",
+		   (result.event_enable & 0x20) ? "+" : "-");
+	seq_printf(seq, "    [%s] High reading. \n",
+		   (result.event_enable & 0x40) ? "+" : "-");
+	seq_printf(seq, "    [%s] High catastrophic. \n",
+		   (result.event_enable & 0x80) ? "+" : "-");
+
+	return 0;
+}
+
+static int i2o_seq_open_hrt(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_hrt, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_lct(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_lct, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_status(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_status, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_hw(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_hw, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_ddm_table, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_driver_store(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_driver_store, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_drivers_stored, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_groups(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_groups, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_phys_device(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_phys_device, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_claimed(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_claimed, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_users(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_users, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_priv_msgs, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_authorized_users,
+			   PDE_DATA(inode));
+};
+
+static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_dev_identity, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_ddm_identity, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_uinfo(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_uinfo, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_sgl_limits, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_sensors(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_sensors, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_dev_name(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_dev_name, PDE_DATA(inode));
+};
+
+static const struct file_operations i2o_seq_fops_lct = {
+	.open = i2o_seq_open_lct,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_hrt = {
+	.open = i2o_seq_open_hrt,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_status = {
+	.open = i2o_seq_open_status,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_hw = {
+	.open = i2o_seq_open_hw,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_ddm_table = {
+	.open = i2o_seq_open_ddm_table,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_driver_store = {
+	.open = i2o_seq_open_driver_store,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_drivers_stored = {
+	.open = i2o_seq_open_drivers_stored,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_groups = {
+	.open = i2o_seq_open_groups,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_phys_device = {
+	.open = i2o_seq_open_phys_device,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_claimed = {
+	.open = i2o_seq_open_claimed,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_users = {
+	.open = i2o_seq_open_users,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_priv_msgs = {
+	.open = i2o_seq_open_priv_msgs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_authorized_users = {
+	.open = i2o_seq_open_authorized_users,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_dev_name = {
+	.open = i2o_seq_open_dev_name,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_dev_identity = {
+	.open = i2o_seq_open_dev_identity,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_ddm_identity = {
+	.open = i2o_seq_open_ddm_identity,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_uinfo = {
+	.open = i2o_seq_open_uinfo,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_sgl_limits = {
+	.open = i2o_seq_open_sgl_limits,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_sensors = {
+	.open = i2o_seq_open_sensors,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/*
+ * IOP specific entries...write field just in case someone
+ * ever wants one.
+ */
+static i2o_proc_entry i2o_proc_generic_iop_entries[] = {
+	{"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt},
+	{"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct},
+	{"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status},
+	{"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw},
+	{"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table},
+	{"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store},
+	{"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored},
+	{NULL, 0, NULL}
+};
+
+/*
+ * Device specific entries
+ */
+static i2o_proc_entry generic_dev_entries[] = {
+	{"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups},
+	{"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device},
+	{"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed},
+	{"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users},
+	{"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs},
+	{"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users},
+	{"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity},
+	{"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity},
+	{"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo},
+	{"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits},
+	{"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors},
+	{NULL, 0, NULL}
+};
+
+/*
+ *  Storage unit specific entries (SCSI Periph, BS) with device names
+ */
+static i2o_proc_entry rbs_dev_entries[] = {
+	{"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name},
+	{NULL, 0, NULL}
+};
+
+/**
+ *	i2o_proc_create_entries - Creates proc dir entries
+ *	@dir: proc dir entry under which the entries should be placed
+ *	@i2o_pe: pointer to the entries which should be added
+ *	@data: pointer to I2O controller or device
+ *
+ *	Create proc dir entries for a I2O controller or I2O device.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_proc_create_entries(struct proc_dir_entry *dir,
+				   i2o_proc_entry * i2o_pe, void *data)
+{
+	struct proc_dir_entry *tmp;
+
+	while (i2o_pe->name) {
+		tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
+				       i2o_pe->fops, data);
+		if (!tmp)
+			return -1;
+
+		i2o_pe++;
+	}
+
+	return 0;
+}
+
+/**
+ *	i2o_proc_device_add - Add an I2O device to the proc dir
+ *	@dir: proc dir entry to which the device should be added
+ *	@dev: I2O device which should be added
+ *
+ *	Add an I2O device to the proc dir entry dir and create the entries for
+ *	the device depending on the class of the I2O device.
+ */
+static void i2o_proc_device_add(struct proc_dir_entry *dir,
+				struct i2o_device *dev)
+{
+	char buff[10];
+	struct proc_dir_entry *devdir;
+	i2o_proc_entry *i2o_pe = NULL;
+
+	sprintf(buff, "%03x", dev->lct_data.tid);
+
+	osm_debug("adding device /proc/i2o/%s/%s\n", dev->iop->name, buff);
+
+	devdir = proc_mkdir_data(buff, 0, dir, dev);
+	if (!devdir) {
+		osm_warn("Could not allocate procdir!\n");
+		return;
+	}
+
+	i2o_proc_create_entries(devdir, generic_dev_entries, dev);
+
+	/* Inform core that we want updates about this device's status */
+	switch (dev->lct_data.class_id) {
+	case I2O_CLASS_SCSI_PERIPHERAL:
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+		i2o_pe = rbs_dev_entries;
+		break;
+	default:
+		break;
+	}
+	if (i2o_pe)
+		i2o_proc_create_entries(devdir, i2o_pe, dev);
+}
+
+/**
+ *	i2o_proc_iop_add - Add an I2O controller to the i2o proc tree
+ *	@dir: parent proc dir entry
+ *	@c: I2O controller which should be added
+ *
+ *	Add the entries to the parent proc dir entry. Also each device is added
+ *	to the controllers proc dir entry.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_proc_iop_add(struct proc_dir_entry *dir,
+			    struct i2o_controller *c)
+{
+	struct proc_dir_entry *iopdir;
+	struct i2o_device *dev;
+
+	osm_debug("adding IOP /proc/i2o/%s\n", c->name);
+
+	iopdir = proc_mkdir_data(c->name, 0, dir, c);
+	if (!iopdir)
+		return -1;
+
+	i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c);
+
+	list_for_each_entry(dev, &c->devices, list)
+	    i2o_proc_device_add(iopdir, dev);
+
+	return 0;
+}
+
+/**
+ *	i2o_proc_fs_create - Create the i2o proc fs.
+ *
+ *	Iterate over each I2O controller and create the entries for it.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_proc_fs_create(void)
+{
+	struct i2o_controller *c;
+
+	i2o_proc_dir_root = proc_mkdir("i2o", NULL);
+	if (!i2o_proc_dir_root)
+		return -1;
+
+	list_for_each_entry(c, &i2o_controllers, list)
+	    i2o_proc_iop_add(i2o_proc_dir_root, c);
+
+	return 0;
+};
+
+/**
+ *	i2o_proc_fs_destroy - Cleanup the all i2o proc entries
+ *
+ *	Iterate over each I2O controller and remove the entries for it.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __exit i2o_proc_fs_destroy(void)
+{
+	remove_proc_subtree("i2o", NULL);
+
+	return 0;
+};
+
+/**
+ *	i2o_proc_init - Init function for procfs
+ *
+ *	Registers Proc OSM and creates procfs entries.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_proc_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	rc = i2o_driver_register(&i2o_proc_driver);
+	if (rc)
+		return rc;
+
+	rc = i2o_proc_fs_create();
+	if (rc) {
+		i2o_driver_unregister(&i2o_proc_driver);
+		return rc;
+	}
+
+	return 0;
+};
+
+/**
+ *	i2o_proc_exit - Exit function for procfs
+ *
+ *	Unregisters Proc OSM and removes procfs entries.
+ */
+static void __exit i2o_proc_exit(void)
+{
+	i2o_driver_unregister(&i2o_proc_driver);
+	i2o_proc_fs_destroy();
+};
+
+MODULE_AUTHOR("Deepak Saxena");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_proc_init);
+module_exit(i2o_proc_exit);
diff --git a/drivers/staging/i2o/i2o_scsi.c b/drivers/staging/i2o/i2o_scsi.c
new file mode 100644
index 0000000..1b11dcb
--- /dev/null
+++ b/drivers/staging/i2o/i2o_scsi.c
@@ -0,0 +1,814 @@
+/*
+ * 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ *  Complications for I2O scsi
+ *
+ *	o	Each (bus,lun) is a logical device in I2O. We keep a map
+ *		table. We spoof failed selection for unmapped units
+ *	o	Request sense buffers can come back for free.
+ *	o	Scatter gather is a bit dynamic. We have to investigate at
+ *		setup time.
+ *	o	Some of our resources are dynamically shared. The i2o core
+ *		needs a message reservation protocol to avoid swap v net
+ *		deadlocking. We need to back off queue requests.
+ *
+ *	In general the firmware wants to help. Where its help isn't performance
+ *	useful we just ignore the aid. Its not worth the code in truth.
+ *
+ * Fixes/additions:
+ *	Steve Ralston:
+ *		Scatter gather now works
+ *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *		Minor fixes for 2.6.
+ *
+ * To Do:
+ *	64bit cleanups
+ *	Fix the resource management problems.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/prefetch.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include "i2o.h"
+#include <linux/scatterlist.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <linux/atomic.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/sg.h>
+
+#define OSM_NAME	"scsi-osm"
+#define OSM_VERSION	"1.316"
+#define OSM_DESCRIPTION	"I2O SCSI Peripheral OSM"
+
+static struct i2o_driver i2o_scsi_driver;
+
+static unsigned int i2o_scsi_max_id = 16;
+static unsigned int i2o_scsi_max_lun = 255;
+
+struct i2o_scsi_host {
+	struct Scsi_Host *scsi_host;	/* pointer to the SCSI host */
+	struct i2o_controller *iop;	/* pointer to the I2O controller */
+	u64 lun;	/* lun's used for block devices */
+	struct i2o_device *channel[0];	/* channel->i2o_dev mapping table */
+};
+
+static struct scsi_host_template i2o_scsi_host_template;
+
+#define I2O_SCSI_CAN_QUEUE	4
+
+/* SCSI OSM class handling definition */
+static struct i2o_class_id i2o_scsi_class_id[] = {
+	{I2O_CLASS_SCSI_PERIPHERAL},
+	{I2O_CLASS_END}
+};
+
+static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
+{
+	struct i2o_scsi_host *i2o_shost;
+	struct i2o_device *i2o_dev;
+	struct Scsi_Host *scsi_host;
+	int max_channel = 0;
+	u8 type;
+	int i;
+	size_t size;
+	u16 body_size = 6;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+	if (c->adaptec)
+		body_size = 8;
+#endif
+
+	list_for_each_entry(i2o_dev, &c->devices, list)
+	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+		    && (type == 0x01))	/* SCSI bus */
+			max_channel++;
+	}
+
+	if (!max_channel) {
+		osm_warn("no channels found on %s\n", c->name);
+		return ERR_PTR(-EFAULT);
+	}
+
+	size = max_channel * sizeof(struct i2o_device *)
+	    + sizeof(struct i2o_scsi_host);
+
+	scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
+	if (!scsi_host) {
+		osm_warn("Could not allocate SCSI host\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	scsi_host->max_channel = max_channel - 1;
+	scsi_host->max_id = i2o_scsi_max_id;
+	scsi_host->max_lun = i2o_scsi_max_lun;
+	scsi_host->this_id = c->unit;
+	scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
+
+	i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
+	i2o_shost->scsi_host = scsi_host;
+	i2o_shost->iop = c;
+	i2o_shost->lun = 1;
+
+	i = 0;
+	list_for_each_entry(i2o_dev, &c->devices, list)
+	    if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+		if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+		    && (type == 0x01))	/* only SCSI bus */
+			i2o_shost->channel[i++] = i2o_dev;
+
+		if (i >= max_channel)
+			break;
+	}
+
+	return i2o_shost;
+};
+
+/**
+ *	i2o_scsi_get_host - Get an I2O SCSI host
+ *	@c: I2O controller to for which to get the SCSI host
+ *
+ *	If the I2O controller already exists as SCSI host, the SCSI host
+ *	is returned, otherwise the I2O controller is added to the SCSI
+ *	core.
+ *
+ *	Returns pointer to the I2O SCSI host on success or NULL on failure.
+ */
+static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
+{
+	return c->driver_data[i2o_scsi_driver.context];
+};
+
+/**
+ *	i2o_scsi_remove - Remove I2O device from SCSI core
+ *	@dev: device which should be removed
+ *
+ *	Removes the I2O device from the SCSI core again.
+ *
+ *	Returns 0 on success.
+ */
+static int i2o_scsi_remove(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	struct i2o_controller *c = i2o_dev->iop;
+	struct i2o_scsi_host *i2o_shost;
+	struct scsi_device *scsi_dev;
+
+	osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+	i2o_shost = i2o_scsi_get_host(c);
+
+	shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
+	    if (scsi_dev->hostdata == i2o_dev) {
+		sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
+		scsi_remove_device(scsi_dev);
+		scsi_device_put(scsi_dev);
+		break;
+	}
+
+	return 0;
+};
+
+/**
+ *	i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
+ *	@dev: device to verify if it is a I2O SCSI device
+ *
+ *	Retrieve channel, id and lun for I2O device. If everything goes well
+ *	register the I2O device as SCSI device on the I2O SCSI controller.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_scsi_probe(struct device *dev)
+{
+	struct i2o_device *i2o_dev = to_i2o_device(dev);
+	struct i2o_controller *c = i2o_dev->iop;
+	struct i2o_scsi_host *i2o_shost;
+	struct Scsi_Host *scsi_host;
+	struct i2o_device *parent;
+	struct scsi_device *scsi_dev;
+	u32 id = -1;
+	u64 lun = -1;
+	int channel = -1;
+	int i, rc;
+
+	i2o_shost = i2o_scsi_get_host(c);
+	if (!i2o_shost)
+		return -EFAULT;
+
+	scsi_host = i2o_shost->scsi_host;
+
+	switch (i2o_dev->lct_data.class_id) {
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+	case I2O_CLASS_EXECUTIVE:
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+		if (c->adaptec) {
+			u8 type;
+			struct i2o_device *d = i2o_shost->channel[0];
+
+			if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
+			    && (type == 0x01))	/* SCSI bus */
+				if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
+					channel = 0;
+					if (i2o_dev->lct_data.class_id ==
+					    I2O_CLASS_RANDOM_BLOCK_STORAGE)
+						lun =
+						    cpu_to_le64(i2o_shost->
+								lun++);
+					else
+						lun = 0;
+				}
+		}
+#endif
+		break;
+
+	case I2O_CLASS_SCSI_PERIPHERAL:
+		if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
+			return -EFAULT;
+
+		if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
+			return -EFAULT;
+
+		parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
+		if (!parent) {
+			osm_warn("can not find parent of device %03x\n",
+				 i2o_dev->lct_data.tid);
+			return -EFAULT;
+		}
+
+		for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
+			if (i2o_shost->channel[i] == parent)
+				channel = i;
+		break;
+
+	default:
+		return -EFAULT;
+	}
+
+	if (channel == -1) {
+		osm_warn("can not find channel of device %03x\n",
+			 i2o_dev->lct_data.tid);
+		return -EFAULT;
+	}
+
+	if (le32_to_cpu(id) >= scsi_host->max_id) {
+		osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
+			 le32_to_cpu(id), scsi_host->max_id);
+		return -EFAULT;
+	}
+
+	if (le64_to_cpu(lun) >= scsi_host->max_lun) {
+		osm_warn("SCSI device lun (%llu) >= max_lun of I2O host (%llu)",
+			 le64_to_cpu(lun), scsi_host->max_lun);
+		return -EFAULT;
+	}
+
+	scsi_dev =
+	    __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
+			      le64_to_cpu(lun), i2o_dev);
+
+	if (IS_ERR(scsi_dev)) {
+		osm_warn("can not add SCSI device %03x\n",
+			 i2o_dev->lct_data.tid);
+		return PTR_ERR(scsi_dev);
+	}
+
+	rc = sysfs_create_link(&i2o_dev->device.kobj,
+			       &scsi_dev->sdev_gendev.kobj, "scsi");
+	if (rc)
+		goto err;
+
+	osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %llu\n",
+		 i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
+		 le64_to_cpu(lun));
+
+	return 0;
+
+err:
+	scsi_remove_device(scsi_dev);
+	return rc;
+};
+
+static const char *i2o_scsi_info(struct Scsi_Host *SChost)
+{
+	struct i2o_scsi_host *hostdata;
+	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
+	return hostdata->iop->name;
+}
+
+/**
+ *	i2o_scsi_reply - SCSI OSM message reply handler
+ *	@c: controller issuing the reply
+ *	@m: message id for flushing
+ *	@msg: the message from the controller
+ *
+ *	Process reply messages (interrupts in normal scsi controller think).
+ *	We can get a variety of messages to process. The normal path is
+ *	scsi command completions. We must also deal with IOP failures,
+ *	the reply to a bus reset and the reply to a LUN query.
+ *
+ *	Returns 0 on success and if the reply should not be flushed or > 0
+ *	on success and if the reply should be flushed. Returns negative error
+ *	code on failure and if the reply should be flushed.
+ */
+static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
+			  struct i2o_message *msg)
+{
+	struct scsi_cmnd *cmd;
+	u32 error;
+	struct device *dev;
+
+	cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+	if (unlikely(!cmd)) {
+		osm_err("NULL reply received!\n");
+		return -1;
+	}
+
+	/*
+	 *      Low byte is device status, next is adapter status,
+	 *      (then one byte reserved), then request status.
+	 */
+	error = le32_to_cpu(msg->body[0]);
+
+	osm_debug("Completed %0x%p\n", cmd);
+
+	cmd->result = error & 0xff;
+	/*
+	 * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+	 * the SCSI layer handle the error
+	 */
+	if (cmd->result)
+		memcpy(cmd->sense_buffer, &msg->body[3],
+		       min(SCSI_SENSE_BUFFERSIZE, 40));
+
+	/* only output error code if AdapterStatus is not HBA_SUCCESS */
+	if ((error >> 8) & 0xff)
+		osm_err("SCSI error %08x\n", error);
+
+	dev = &c->pdev->dev;
+
+	scsi_dma_unmap(cmd);
+
+	cmd->scsi_done(cmd);
+
+	return 1;
+};
+
+/**
+ *	i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ *	@i2o_dev: the I2O device which was added
+ *
+ *	If a I2O device is added we catch the notification, because I2O classes
+ *	other than SCSI peripheral will not be received through
+ *	i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+	switch (i2o_dev->lct_data.class_id) {
+	case I2O_CLASS_EXECUTIVE:
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+		i2o_scsi_probe(&i2o_dev->device);
+		break;
+
+	default:
+		break;
+	}
+};
+
+/**
+ *	i2o_scsi_notify_device_remove - Retrieve notifications of removed devices
+ *	@i2o_dev: the I2O device which was removed
+ *
+ *	If a I2O device is removed, we catch the notification to remove the
+ *	corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+	switch (i2o_dev->lct_data.class_id) {
+	case I2O_CLASS_EXECUTIVE:
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+		i2o_scsi_remove(&i2o_dev->device);
+		break;
+
+	default:
+		break;
+	}
+};
+
+/**
+ *	i2o_scsi_notify_controller_add - Retrieve notifications of added controllers
+ *	@c: the controller which was added
+ *
+ *	If a I2O controller is added, we catch the notification to add a
+ *	corresponding Scsi_Host.
+ */
+static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
+{
+	struct i2o_scsi_host *i2o_shost;
+	int rc;
+
+	i2o_shost = i2o_scsi_host_alloc(c);
+	if (IS_ERR(i2o_shost)) {
+		osm_err("Could not initialize SCSI host\n");
+		return;
+	}
+
+	rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
+	if (rc) {
+		osm_err("Could not add SCSI host\n");
+		scsi_host_put(i2o_shost->scsi_host);
+		return;
+	}
+
+	c->driver_data[i2o_scsi_driver.context] = i2o_shost;
+
+	osm_debug("new I2O SCSI host added\n");
+};
+
+/**
+ *	i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers
+ *	@c: the controller which was removed
+ *
+ *	If a I2O controller is removed, we catch the notification to remove the
+ *	corresponding Scsi_Host.
+ */
+static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
+{
+	struct i2o_scsi_host *i2o_shost;
+	i2o_shost = i2o_scsi_get_host(c);
+	if (!i2o_shost)
+		return;
+
+	c->driver_data[i2o_scsi_driver.context] = NULL;
+
+	scsi_remove_host(i2o_shost->scsi_host);
+	scsi_host_put(i2o_shost->scsi_host);
+	osm_debug("I2O SCSI host removed\n");
+};
+
+/* SCSI OSM driver struct */
+static struct i2o_driver i2o_scsi_driver = {
+	.name = OSM_NAME,
+	.reply = i2o_scsi_reply,
+	.classes = i2o_scsi_class_id,
+	.notify_device_add = i2o_scsi_notify_device_add,
+	.notify_device_remove = i2o_scsi_notify_device_remove,
+	.notify_controller_add = i2o_scsi_notify_controller_add,
+	.notify_controller_remove = i2o_scsi_notify_controller_remove,
+	.driver = {
+		   .probe = i2o_scsi_probe,
+		   .remove = i2o_scsi_remove,
+		   },
+};
+
+/**
+ *	i2o_scsi_queuecommand - queue a SCSI command
+ *	@SCpnt: scsi command pointer
+ *	@done: callback for completion
+ *
+ *	Issue a scsi command asynchronously. Return 0 on success or 1 if
+ *	we hit an error (normally message queue congestion). The only
+ *	minor complication here is that I2O deals with the device addressing
+ *	so we have to map the bus/dev/lun back to an I2O handle as well
+ *	as faking absent devices ourself.
+ *
+ *	Locks: takes the controller lock on error path only
+ */
+
+static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
+				 void (*done) (struct scsi_cmnd *))
+{
+	struct i2o_controller *c;
+	struct i2o_device *i2o_dev;
+	int tid;
+	struct i2o_message *msg;
+	/*
+	 * ENABLE_DISCONNECT
+	 * SIMPLE_TAG
+	 * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+	 */
+	u32 scsi_flags = 0x20a00000;
+	u32 sgl_offset;
+	u32 *mptr;
+	u32 cmd = I2O_CMD_SCSI_EXEC << 24;
+	int rc = 0;
+
+	/*
+	 *      Do the incoming paperwork
+	 */
+	i2o_dev = SCpnt->device->hostdata;
+
+	SCpnt->scsi_done = done;
+
+	if (unlikely(!i2o_dev)) {
+		osm_warn("no I2O device in request\n");
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		goto exit;
+	}
+	c = i2o_dev->iop;
+	tid = i2o_dev->lct_data.tid;
+
+	osm_debug("qcmd: Tid = %03x\n", tid);
+	osm_debug("Real scsi messages.\n");
+
+	/*
+	 *      Put together a scsi execscb message
+	 */
+	switch (SCpnt->sc_data_direction) {
+	case PCI_DMA_NONE:
+		/* DATA NO XFER */
+		sgl_offset = SGL_OFFSET_0;
+		break;
+
+	case PCI_DMA_TODEVICE:
+		/* DATA OUT (iop-->dev) */
+		scsi_flags |= 0x80000000;
+		sgl_offset = SGL_OFFSET_10;
+		break;
+
+	case PCI_DMA_FROMDEVICE:
+		/* DATA IN  (iop<--dev) */
+		scsi_flags |= 0x40000000;
+		sgl_offset = SGL_OFFSET_10;
+		break;
+
+	default:
+		/* Unknown - kill the command */
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		goto exit;
+	}
+
+	/*
+	 *      Obtain an I2O message. If there are none free then
+	 *      throw it back to the scsi layer
+	 */
+
+	msg = i2o_msg_get(c);
+	if (IS_ERR(msg)) {
+		rc = SCSI_MLQUEUE_HOST_BUSY;
+		goto exit;
+	}
+
+	mptr = &msg->body[0];
+
+#if 0 /* this code can't work */
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+	if (c->adaptec) {
+		u32 adpt_flags = 0;
+
+		if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
+			i2o_sg_io_hdr_t __user *usr_ptr =
+			    ((Sg_request *) (SCpnt->sc_request->
+					     upper_private_data))->header.
+			    usr_ptr;
+
+			if (usr_ptr)
+				get_user(adpt_flags, &usr_ptr->flags);
+		}
+
+		switch (i2o_dev->lct_data.class_id) {
+		case I2O_CLASS_EXECUTIVE:
+		case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+			/* interpret flag has to be set for executive */
+			adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
+			break;
+
+		default:
+			break;
+		}
+
+		/*
+		 * for Adaptec controllers we use the PRIVATE command, because
+		 * the normal SCSI EXEC doesn't support all SCSI commands on
+		 * all controllers (for example READ CAPACITY).
+		 */
+		if (sgl_offset == SGL_OFFSET_10)
+			sgl_offset = SGL_OFFSET_12;
+		cmd = I2O_CMD_PRIVATE << 24;
+		*mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
+		*mptr++ = cpu_to_le32(adpt_flags | tid);
+	}
+#endif
+#endif
+
+	msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
+	msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
+
+	/* We want the SCSI control block back */
+	msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
+
+	/* LSI_920_PCI_QUIRK
+	 *
+	 *      Intermittant observations of msg frame word data corruption
+	 *      observed on msg[4] after:
+	 *        WRITE, READ-MODIFY-WRITE
+	 *      operations.  19990606 -sralston
+	 *
+	 *      (Hence we build this word via tag. Its good practice anyway
+	 *       we don't want fetches over PCI needlessly)
+	 */
+
+	/* Attach tags to the devices */
+	/* FIXME: implement
+	   if(SCpnt->device->tagged_supported) {
+	   if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+	   scsi_flags |= 0x01000000;
+	   else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+	   scsi_flags |= 0x01800000;
+	   }
+	 */
+
+	*mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
+
+	/* Write SCSI command into the message - always 16 byte block */
+	memcpy(mptr, SCpnt->cmnd, 16);
+	mptr += 4;
+
+	if (sgl_offset != SGL_OFFSET_0) {
+		/* write size of data addressed by SGL */
+		*mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
+
+		/* Now fill in the SGList and command */
+
+		if (scsi_sg_count(SCpnt)) {
+			if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
+					    scsi_sg_count(SCpnt),
+					    SCpnt->sc_data_direction, &mptr))
+				goto nomem;
+		}
+	}
+
+	/* Stick the headers on */
+	msg->u.head[0] =
+	    cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
+
+	/* Queue the message */
+	i2o_msg_post(c, msg);
+
+	osm_debug("Issued %0x%p\n", SCpnt);
+
+	return 0;
+
+      nomem:
+	rc = -ENOMEM;
+	i2o_msg_nop(c, msg);
+
+      exit:
+	return rc;
+}
+
+static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
+
+/**
+ *	i2o_scsi_abort - abort a running command
+ *	@SCpnt: command to abort
+ *
+ *	Ask the I2O controller to abort a command. This is an asynchrnous
+ *	process and our callback handler will see the command complete with an
+ *	aborted message if it succeeds.
+ *
+ *	Returns 0 if the command is successfully aborted or negative error code
+ *	on failure.
+ */
+static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
+{
+	struct i2o_device *i2o_dev;
+	struct i2o_controller *c;
+	struct i2o_message *msg;
+	int tid;
+	int status = FAILED;
+
+	osm_warn("Aborting command block.\n");
+
+	i2o_dev = SCpnt->device->hostdata;
+	c = i2o_dev->iop;
+	tid = i2o_dev->lct_data.tid;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
+	msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
+
+	if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
+		status = SUCCESS;
+
+	return status;
+}
+
+/**
+ *	i2o_scsi_bios_param	-	Invent disk geometry
+ *	@sdev: scsi device
+ *	@dev: block layer device
+ *	@capacity: size in sectors
+ *	@ip: geometry array
+ *
+ *	This is anyone's guess quite frankly. We use the same rules everyone
+ *	else appears to and hope. It seems to work.
+ */
+
+static int i2o_scsi_bios_param(struct scsi_device *sdev,
+			       struct block_device *dev, sector_t capacity,
+			       int *ip)
+{
+	int size;
+
+	size = capacity;
+	ip[0] = 64;		/* heads                        */
+	ip[1] = 32;		/* sectors                      */
+	if ((ip[2] = size >> 11) > 1024) {	/* cylinders, test for big disk */
+		ip[0] = 255;	/* heads                        */
+		ip[1] = 63;	/* sectors                      */
+		ip[2] = size / (255 * 63);	/* cylinders                    */
+	}
+	return 0;
+}
+
+static struct scsi_host_template i2o_scsi_host_template = {
+	.proc_name = OSM_NAME,
+	.name = OSM_DESCRIPTION,
+	.info = i2o_scsi_info,
+	.queuecommand = i2o_scsi_queuecommand,
+	.eh_abort_handler = i2o_scsi_abort,
+	.bios_param = i2o_scsi_bios_param,
+	.can_queue = I2O_SCSI_CAN_QUEUE,
+	.sg_tablesize = 8,
+	.cmd_per_lun = 6,
+	.use_clustering = ENABLE_CLUSTERING,
+};
+
+/**
+ *	i2o_scsi_init - SCSI OSM initialization function
+ *
+ *	Register SCSI OSM into I2O core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_scsi_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	/* Register SCSI OSM into I2O core */
+	rc = i2o_driver_register(&i2o_scsi_driver);
+	if (rc) {
+		osm_err("Could not register SCSI driver\n");
+		return rc;
+	}
+
+	return 0;
+};
+
+/**
+ *	i2o_scsi_exit - SCSI OSM exit function
+ *
+ *	Unregisters SCSI OSM from I2O core.
+ */
+static void __exit i2o_scsi_exit(void)
+{
+	/* Unregister I2O SCSI OSM from I2O core */
+	i2o_driver_unregister(&i2o_scsi_driver);
+};
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_scsi_init);
+module_exit(i2o_scsi_exit);
diff --git a/drivers/staging/i2o/iop.c b/drivers/staging/i2o/iop.c
new file mode 100644
index 0000000..52334fc
--- /dev/null
+++ b/drivers/staging/i2o/iop.c
@@ -0,0 +1,1247 @@
+/*
+ *	Functions to handle I2O controllers and I2O message handling
+ *
+ *	Copyright (C) 1999-2002	Red Hat Software
+ *
+ *	Written by Alan Cox, Building Number Three Ltd
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation; either version 2 of the License, or (at your
+ *	option) any later version.
+ *
+ *	A lot of the I2O message side code from this is taken from the
+ *	Red Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *	Fixes/additions:
+ *		Philipp Rumpf
+ *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *		Deepak Saxena <deepak@plexity.net>
+ *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ *			Ported to Linux 2.5.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Minor fixes for 2.6.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include "core.h"
+
+#define OSM_NAME	"i2o"
+#define OSM_VERSION	"1.325"
+#define OSM_DESCRIPTION	"I2O subsystem"
+
+/* global I2O controller list */
+LIST_HEAD(i2o_controllers);
+
+/*
+ * global I2O System Table. Contains information about all the IOPs in the
+ * system. Used to inform IOPs about each others existence.
+ */
+static struct i2o_dma i2o_systab;
+
+static int i2o_hrt_get(struct i2o_controller *c);
+
+/**
+ *	i2o_msg_get_wait - obtain an I2O message from the IOP
+ *	@c: I2O controller
+ *	@wait: how long to wait until timeout
+ *
+ *	This function waits up to wait seconds for a message slot to be
+ *	available.
+ *
+ *	On a success the message is returned and the pointer to the message is
+ *	set in msg. The returned message is the physical page frame offset
+ *	address from the read port (see the i2o spec). If no message is
+ *	available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
+ */
+struct i2o_message *i2o_msg_get_wait(struct i2o_controller *c, int wait)
+{
+	unsigned long timeout = jiffies + wait * HZ;
+	struct i2o_message *msg;
+
+	while (IS_ERR(msg = i2o_msg_get(c))) {
+		if (time_after(jiffies, timeout)) {
+			osm_debug("%s: Timeout waiting for message frame.\n",
+				  c->name);
+			return ERR_PTR(-ETIMEDOUT);
+		}
+		schedule_timeout_uninterruptible(1);
+	}
+
+	return msg;
+};
+
+#if BITS_PER_LONG == 64
+/**
+ *      i2o_cntxt_list_add - Append a pointer to context list and return a id
+ *	@c: controller to which the context list belong
+ *	@ptr: pointer to add to the context list
+ *
+ *	Because the context field in I2O is only 32-bit large, on 64-bit the
+ *	pointer is to large to fit in the context field. The i2o_cntxt_list
+ *	functions therefore map pointers to context fields.
+ *
+ *	Returns context id > 0 on success or 0 on failure.
+ */
+u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
+{
+	struct i2o_context_list_element *entry;
+	unsigned long flags;
+
+	if (!ptr)
+		osm_err("%s: couldn't add NULL pointer to context list!\n",
+			c->name);
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (!entry) {
+		osm_err("%s: Could not allocate memory for context list element"
+			"\n", c->name);
+		return 0;
+	}
+
+	entry->ptr = ptr;
+	entry->timestamp = jiffies;
+	INIT_LIST_HEAD(&entry->list);
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+
+	if (unlikely(atomic_inc_and_test(&c->context_list_counter)))
+		atomic_inc(&c->context_list_counter);
+
+	entry->context = atomic_read(&c->context_list_counter);
+
+	list_add(&entry->list, &c->context_list);
+
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+	osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
+
+	return entry->context;
+};
+
+/**
+ *      i2o_cntxt_list_remove - Remove a pointer from the context list
+ *	@c: controller to which the context list belong
+ *	@ptr: pointer which should be removed from the context list
+ *
+ *	Removes a previously added pointer from the context list and returns
+ *	the matching context id.
+ *
+ *	Returns context id on success or 0 on failure.
+ */
+u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
+{
+	struct i2o_context_list_element *entry;
+	u32 context = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	list_for_each_entry(entry, &c->context_list, list)
+	    if (entry->ptr == ptr) {
+		list_del(&entry->list);
+		context = entry->context;
+		kfree(entry);
+		break;
+	}
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+	if (!context)
+		osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
+			 ptr);
+
+	osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
+		  context, ptr);
+
+	return context;
+};
+
+/**
+ *      i2o_cntxt_list_get - Get a pointer from the context list and remove it
+ *	@c: controller to which the context list belong
+ *	@context: context id to which the pointer belong
+ *
+ *	Returns pointer to the matching context id on success or NULL on
+ *	failure.
+ */
+void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
+{
+	struct i2o_context_list_element *entry;
+	unsigned long flags;
+	void *ptr = NULL;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	list_for_each_entry(entry, &c->context_list, list)
+	    if (entry->context == context) {
+		list_del(&entry->list);
+		ptr = entry->ptr;
+		kfree(entry);
+		break;
+	}
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+	if (!ptr)
+		osm_warn("%s: context id %d not found\n", c->name, context);
+
+	osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
+		  ptr);
+
+	return ptr;
+};
+
+/**
+ *      i2o_cntxt_list_get_ptr - Get a context id from the context list
+ *	@c: controller to which the context list belong
+ *	@ptr: pointer to which the context id should be fetched
+ *
+ *	Returns context id which matches to the pointer on success or 0 on
+ *	failure.
+ */
+u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
+{
+	struct i2o_context_list_element *entry;
+	u32 context = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&c->context_list_lock, flags);
+	list_for_each_entry(entry, &c->context_list, list)
+	    if (entry->ptr == ptr) {
+		context = entry->context;
+		break;
+	}
+	spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+	if (!context)
+		osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
+			 ptr);
+
+	osm_debug("%s: get context id from context list %p -> %d\n", c->name,
+		  ptr, context);
+
+	return context;
+};
+#endif
+
+/**
+ *	i2o_iop_find - Find an I2O controller by id
+ *	@unit: unit number of the I2O controller to search for
+ *
+ *	Lookup the I2O controller on the controller list.
+ *
+ *	Returns pointer to the I2O controller on success or NULL if not found.
+ */
+struct i2o_controller *i2o_find_iop(int unit)
+{
+	struct i2o_controller *c;
+
+	list_for_each_entry(c, &i2o_controllers, list) {
+		if (c->unit == unit)
+			return c;
+	}
+
+	return NULL;
+};
+
+/**
+ *	i2o_iop_find_device - Find a I2O device on an I2O controller
+ *	@c: I2O controller where the I2O device hangs on
+ *	@tid: TID of the I2O device to search for
+ *
+ *	Searches the devices of the I2O controller for a device with TID tid and
+ *	returns it.
+ *
+ *	Returns a pointer to the I2O device if found, otherwise NULL.
+ */
+struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
+{
+	struct i2o_device *dev;
+
+	list_for_each_entry(dev, &c->devices, list)
+	    if (dev->lct_data.tid == tid)
+		return dev;
+
+	return NULL;
+};
+
+/**
+ *	i2o_quiesce_controller - quiesce controller
+ *	@c: controller
+ *
+ *	Quiesce an IOP. Causes IOP to make external operation quiescent
+ *	(i2o 'READY' state). Internal operation of the IOP continues normally.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_quiesce(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	i2o_status_block *sb = c->status_block.virt;
+	int rc;
+
+	i2o_status_get(c);
+
+	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+	if ((sb->iop_state != ADAPTER_STATE_READY) &&
+	    (sb->iop_state != ADAPTER_STATE_OPERATIONAL))
+		return 0;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+
+	/* Long timeout needed for quiesce if lots of devices */
+	if ((rc = i2o_msg_post_wait(c, msg, 240)))
+		osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
+	else
+		osm_debug("%s: Quiesced.\n", c->name);
+
+	i2o_status_get(c);	// Entered READY state
+
+	return rc;
+};
+
+/**
+ *	i2o_iop_enable - move controller from ready to OPERATIONAL
+ *	@c: I2O controller
+ *
+ *	Enable IOP. This allows the IOP to resume external operations and
+ *	reverses the effect of a quiesce. Returns zero or an error code if
+ *	an error occurs.
+ */
+static int i2o_iop_enable(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	i2o_status_block *sb = c->status_block.virt;
+	int rc;
+
+	i2o_status_get(c);
+
+	/* Enable only allowed on READY state */
+	if (sb->iop_state != ADAPTER_STATE_READY)
+		return -EINVAL;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+
+	/* How long of a timeout do we need? */
+	if ((rc = i2o_msg_post_wait(c, msg, 240)))
+		osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
+	else
+		osm_debug("%s: Enabled.\n", c->name);
+
+	i2o_status_get(c);	// entered OPERATIONAL state
+
+	return rc;
+};
+
+/**
+ *	i2o_iop_quiesce_all - Quiesce all I2O controllers on the system
+ *
+ *	Quiesce all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_quiesce_all(void)
+{
+	struct i2o_controller *c, *tmp;
+
+	list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+		if (!c->no_quiesce)
+			i2o_iop_quiesce(c);
+	}
+};
+
+/**
+ *	i2o_iop_enable_all - Enables all controllers on the system
+ *
+ *	Enables all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_enable_all(void)
+{
+	struct i2o_controller *c, *tmp;
+
+	list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+	    i2o_iop_enable(c);
+};
+
+/**
+ *	i2o_clear_controller - Bring I2O controller into HOLD state
+ *	@c: controller
+ *
+ *	Clear an IOP to HOLD state, ie. terminate external operations, clear all
+ *	input queues and prepare for a system restart. IOP's internal operation
+ *	continues normally and the outbound queue is alive. The IOP is not
+ *	expected to rebuild its LCT.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_clear(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	int rc;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	/* Quiesce all IOPs first */
+	i2o_iop_quiesce_all();
+
+	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+
+	if ((rc = i2o_msg_post_wait(c, msg, 30)))
+		osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
+	else
+		osm_debug("%s: Cleared.\n", c->name);
+
+	/* Enable all IOPs */
+	i2o_iop_enable_all();
+
+	return rc;
+}
+
+/**
+ *	i2o_iop_init_outbound_queue - setup the outbound message queue
+ *	@c: I2O controller
+ *
+ *	Clear and (re)initialize IOP's outbound queue and post the message
+ *	frames to the IOP.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+{
+	u32 m;
+	volatile u8 *status = c->status.virt;
+	struct i2o_message *msg;
+	ulong timeout;
+	int i;
+
+	osm_debug("%s: Initializing Outbound Queue...\n", c->name);
+
+	memset(c->status.virt, 0, 4);
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+	msg->body[0] = cpu_to_le32(PAGE_SIZE);
+	/* Outbound msg frame size in words and Initcode */
+	msg->body[1] = cpu_to_le32(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80);
+	msg->body[2] = cpu_to_le32(0xd0000004);
+	msg->body[3] = cpu_to_le32(i2o_dma_low(c->status.phys));
+	msg->body[4] = cpu_to_le32(i2o_dma_high(c->status.phys));
+
+	i2o_msg_post(c, msg);
+
+	timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
+	while (*status <= I2O_CMD_IN_PROGRESS) {
+		if (time_after(jiffies, timeout)) {
+			osm_warn("%s: Timeout Initializing\n", c->name);
+			return -ETIMEDOUT;
+		}
+		schedule_timeout_uninterruptible(1);
+	}
+
+	m = c->out_queue.phys;
+
+	/* Post frames */
+	for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
+		i2o_flush_reply(c, m);
+		udelay(1);	/* Promise */
+		m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
+	}
+
+	return 0;
+}
+
+/**
+ *	i2o_iop_reset - reset an I2O controller
+ *	@c: controller to reset
+ *
+ *	Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ *	Terminate all external operations, clear IOP's inbound and outbound
+ *	queues, terminate all DDMs, and reload the IOP's operating environment
+ *	and all local DDMs. The IOP rebuilds its LCT.
+ */
+static int i2o_iop_reset(struct i2o_controller *c)
+{
+	volatile u8 *status = c->status.virt;
+	struct i2o_message *msg;
+	unsigned long timeout;
+	i2o_status_block *sb = c->status_block.virt;
+	int rc = 0;
+
+	osm_debug("%s: Resetting controller\n", c->name);
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	memset(c->status_block.virt, 0, 8);
+
+	/* Quiesce all IOPs first */
+	i2o_iop_quiesce_all();
+
+	msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+	msg->body[0] = cpu_to_le32(0x00000000);
+	msg->body[1] = cpu_to_le32(0x00000000);
+	msg->body[2] = cpu_to_le32(i2o_dma_low(c->status.phys));
+	msg->body[3] = cpu_to_le32(i2o_dma_high(c->status.phys));
+
+	i2o_msg_post(c, msg);
+
+	/* Wait for a reply */
+	timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
+	while (!*status) {
+		if (time_after(jiffies, timeout))
+			break;
+
+		schedule_timeout_uninterruptible(1);
+	}
+
+	switch (*status) {
+	case I2O_CMD_REJECTED:
+		osm_warn("%s: IOP reset rejected\n", c->name);
+		rc = -EPERM;
+		break;
+
+	case I2O_CMD_IN_PROGRESS:
+		/*
+		 * Once the reset is sent, the IOP goes into the INIT state
+		 * which is indeterminate. We need to wait until the IOP has
+		 * rebooted before we can let the system talk to it. We read
+		 * the inbound Free_List until a message is available. If we
+		 * can't read one in the given amount of time, we assume the
+		 * IOP could not reboot properly.
+		 */
+		osm_debug("%s: Reset in progress, waiting for reboot...\n",
+			  c->name);
+
+		while (IS_ERR(msg = i2o_msg_get_wait(c, I2O_TIMEOUT_RESET))) {
+			if (time_after(jiffies, timeout)) {
+				osm_err("%s: IOP reset timeout.\n", c->name);
+				rc = PTR_ERR(msg);
+				goto exit;
+			}
+			schedule_timeout_uninterruptible(1);
+		}
+		i2o_msg_nop(c, msg);
+
+		/* from here all quiesce commands are safe */
+		c->no_quiesce = 0;
+
+		/* verify if controller is in state RESET */
+		i2o_status_get(c);
+
+		if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
+			osm_warn("%s: reset completed, but adapter not in RESET"
+				 " state.\n", c->name);
+		else
+			osm_debug("%s: reset completed.\n", c->name);
+
+		break;
+
+	default:
+		osm_err("%s: IOP reset timeout.\n", c->name);
+		rc = -ETIMEDOUT;
+		break;
+	}
+
+      exit:
+	/* Enable all IOPs */
+	i2o_iop_enable_all();
+
+	return rc;
+};
+
+/**
+ *	i2o_iop_activate - Bring controller up to HOLD
+ *	@c: controller
+ *
+ *	This function brings an I2O controller into HOLD state. The adapter
+ *	is reset if necessary and then the queues and resource table are read.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_activate(struct i2o_controller *c)
+{
+	i2o_status_block *sb = c->status_block.virt;
+	int rc;
+	int state;
+
+	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
+	/* In READY state, Get status */
+
+	rc = i2o_status_get(c);
+	if (rc) {
+		osm_info("%s: Unable to obtain status, attempting a reset.\n",
+			 c->name);
+		rc = i2o_iop_reset(c);
+		if (rc)
+			return rc;
+	}
+
+	if (sb->i2o_version > I2OVER15) {
+		osm_err("%s: Not running version 1.5 of the I2O Specification."
+			"\n", c->name);
+		return -ENODEV;
+	}
+
+	switch (sb->iop_state) {
+	case ADAPTER_STATE_FAULTED:
+		osm_err("%s: hardware fault\n", c->name);
+		return -EFAULT;
+
+	case ADAPTER_STATE_READY:
+	case ADAPTER_STATE_OPERATIONAL:
+	case ADAPTER_STATE_HOLD:
+	case ADAPTER_STATE_FAILED:
+		osm_debug("%s: already running, trying to reset...\n", c->name);
+		rc = i2o_iop_reset(c);
+		if (rc)
+			return rc;
+	}
+
+	/* preserve state */
+	state = sb->iop_state;
+
+	rc = i2o_iop_init_outbound_queue(c);
+	if (rc)
+		return rc;
+
+	/* if adapter was not in RESET state clear now */
+	if (state != ADAPTER_STATE_RESET)
+		i2o_iop_clear(c);
+
+	i2o_status_get(c);
+
+	if (sb->iop_state != ADAPTER_STATE_HOLD) {
+		osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
+		return -EIO;
+	}
+
+	return i2o_hrt_get(c);
+};
+
+static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
+{
+	i2o_status_block *sb = c->status_block.virt;
+	struct resource *res = &c->mem_resource;
+	resource_size_t size, align;
+	int err;
+
+	res->name = c->pdev->bus->name;
+	res->flags = flags;
+	res->start = 0;
+	res->end = 0;
+	osm_info("%s: requires private memory resources.\n", c->name);
+
+	if (flags & IORESOURCE_MEM) {
+		size = sb->desired_mem_size;
+		align = 1 << 20;	/* unspecified, use 1Mb and play safe */
+	} else {
+		size = sb->desired_io_size;
+		align = 1 << 12;	/* unspecified, use 4Kb and play safe */
+	}
+
+	err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
+				     NULL, NULL);
+	if (err < 0)
+		return;
+
+	if (flags & IORESOURCE_MEM) {
+		c->mem_alloc = 1;
+		sb->current_mem_size = resource_size(res);
+		sb->current_mem_base = res->start;
+	} else if (flags & IORESOURCE_IO) {
+		c->io_alloc = 1;
+		sb->current_io_size = resource_size(res);
+		sb->current_io_base = res->start;
+	}
+	osm_info("%s: allocated PCI space %pR\n", c->name, res);
+}
+
+/**
+ *	i2o_iop_systab_set - Set the I2O System Table of the specified IOP
+ *	@c: I2O controller to which the system table should be send
+ *
+ *	Before the systab could be set i2o_systab_build() must be called.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_systab_set(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	i2o_status_block *sb = c->status_block.virt;
+	struct device *dev = &c->pdev->dev;
+	int rc;
+
+	if (sb->current_mem_size < sb->desired_mem_size)
+		i2o_res_alloc(c, IORESOURCE_MEM);
+
+	if (sb->current_io_size < sb->desired_io_size)
+		i2o_res_alloc(c, IORESOURCE_IO);
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len,
+					 PCI_DMA_TODEVICE);
+	if (!i2o_systab.phys) {
+		i2o_msg_nop(c, msg);
+		return -ENOMEM;
+	}
+
+	msg->u.head[0] = cpu_to_le32(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+
+	/*
+	 * Provide three SGL-elements:
+	 * System table (SysTab), Private memory space declaration and
+	 * Private i/o space declaration
+	 */
+
+	msg->body[0] = cpu_to_le32(c->unit + 2);
+	msg->body[1] = cpu_to_le32(0x00000000);
+	msg->body[2] = cpu_to_le32(0x54000000 | i2o_systab.len);
+	msg->body[3] = cpu_to_le32(i2o_systab.phys);
+	msg->body[4] = cpu_to_le32(0x54000000 | sb->current_mem_size);
+	msg->body[5] = cpu_to_le32(sb->current_mem_base);
+	msg->body[6] = cpu_to_le32(0xd4000000 | sb->current_io_size);
+	msg->body[6] = cpu_to_le32(sb->current_io_base);
+
+	rc = i2o_msg_post_wait(c, msg, 120);
+
+	dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len,
+			 PCI_DMA_TODEVICE);
+
+	if (rc < 0)
+		osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
+			-rc);
+	else
+		osm_debug("%s: SysTab set.\n", c->name);
+
+	return rc;
+}
+
+/**
+ *	i2o_iop_online - Bring a controller online into OPERATIONAL state.
+ *	@c: I2O controller
+ *
+ *	Send the system table and enable the I2O controller.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_online(struct i2o_controller *c)
+{
+	int rc;
+
+	rc = i2o_iop_systab_set(c);
+	if (rc)
+		return rc;
+
+	/* In READY state */
+	osm_debug("%s: Attempting to enable...\n", c->name);
+	rc = i2o_iop_enable(c);
+	if (rc)
+		return rc;
+
+	return 0;
+};
+
+/**
+ *	i2o_iop_remove - Remove the I2O controller from the I2O core
+ *	@c: I2O controller
+ *
+ *	Remove the I2O controller from the I2O core. If devices are attached to
+ *	the controller remove these also and finally reset the controller.
+ */
+void i2o_iop_remove(struct i2o_controller *c)
+{
+	struct i2o_device *dev, *tmp;
+
+	osm_debug("%s: deleting controller\n", c->name);
+
+	i2o_driver_notify_controller_remove_all(c);
+
+	list_del(&c->list);
+
+	list_for_each_entry_safe(dev, tmp, &c->devices, list)
+	    i2o_device_remove(dev);
+
+	device_del(&c->device);
+
+	/* Ask the IOP to switch to RESET state */
+	i2o_iop_reset(c);
+}
+
+/**
+ *	i2o_systab_build - Build system table
+ *
+ *	The system table contains information about all the IOPs in the system
+ *	(duh) and is used by the Executives on the IOPs to establish peer2peer
+ *	connections. We're not supporting peer2peer at the moment, but this
+ *	will be needed down the road for things like lan2lan forwarding.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_systab_build(void)
+{
+	struct i2o_controller *c, *tmp;
+	int num_controllers = 0;
+	u32 change_ind = 0;
+	int count = 0;
+	struct i2o_sys_tbl *systab = i2o_systab.virt;
+
+	list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+	    num_controllers++;
+
+	if (systab) {
+		change_ind = systab->change_ind;
+		kfree(i2o_systab.virt);
+	}
+
+	/* Header + IOPs */
+	i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers *
+	    sizeof(struct i2o_sys_tbl_entry);
+
+	systab = i2o_systab.virt = kzalloc(i2o_systab.len, GFP_KERNEL);
+	if (!systab) {
+		osm_err("unable to allocate memory for System Table\n");
+		return -ENOMEM;
+	}
+
+	systab->version = I2OVERSION;
+	systab->change_ind = change_ind + 1;
+
+	list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+		i2o_status_block *sb;
+
+		if (count >= num_controllers) {
+			osm_err("controller added while building system table"
+				"\n");
+			break;
+		}
+
+		sb = c->status_block.virt;
+
+		/*
+		 * Get updated IOP state so we have the latest information
+		 *
+		 * We should delete the controller at this point if it
+		 * doesn't respond since if it's not on the system table
+		 * it is techninically not part of the I2O subsystem...
+		 */
+		if (unlikely(i2o_status_get(c))) {
+			osm_err("%s: Deleting b/c could not get status while "
+				"attempting to build system table\n", c->name);
+			i2o_iop_remove(c);
+			continue;	// try the next one
+		}
+
+		systab->iops[count].org_id = sb->org_id;
+		systab->iops[count].iop_id = c->unit + 2;
+		systab->iops[count].seg_num = 0;
+		systab->iops[count].i2o_version = sb->i2o_version;
+		systab->iops[count].iop_state = sb->iop_state;
+		systab->iops[count].msg_type = sb->msg_type;
+		systab->iops[count].frame_size = sb->inbound_frame_size;
+		systab->iops[count].last_changed = change_ind;
+		systab->iops[count].iop_capabilities = sb->iop_capabilities;
+		systab->iops[count].inbound_low =
+		    i2o_dma_low(c->base.phys + I2O_IN_PORT);
+		systab->iops[count].inbound_high =
+		    i2o_dma_high(c->base.phys + I2O_IN_PORT);
+
+		count++;
+	}
+
+	systab->num_entries = count;
+
+	return 0;
+};
+
+/**
+ *	i2o_parse_hrt - Parse the hardware resource table.
+ *	@c: I2O controller
+ *
+ *	We don't do anything with it except dumping it (in debug mode).
+ *
+ *	Returns 0.
+ */
+static int i2o_parse_hrt(struct i2o_controller *c)
+{
+	i2o_dump_hrt(c);
+	return 0;
+};
+
+/**
+ *	i2o_status_get - Get the status block from the I2O controller
+ *	@c: I2O controller
+ *
+ *	Issue a status query on the controller. This updates the attached
+ *	status block. The status block could then be accessed through
+ *	c->status_block.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_status_get(struct i2o_controller *c)
+{
+	struct i2o_message *msg;
+	volatile u8 *status_block;
+	unsigned long timeout;
+
+	status_block = (u8 *) c->status_block.virt;
+	memset(c->status_block.virt, 0, sizeof(i2o_status_block));
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 |
+			ADAPTER_TID);
+	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+	msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+	msg->body[0] = cpu_to_le32(0x00000000);
+	msg->body[1] = cpu_to_le32(0x00000000);
+	msg->body[2] = cpu_to_le32(i2o_dma_low(c->status_block.phys));
+	msg->body[3] = cpu_to_le32(i2o_dma_high(c->status_block.phys));
+	msg->body[4] = cpu_to_le32(sizeof(i2o_status_block));	/* always 88 bytes */
+
+	i2o_msg_post(c, msg);
+
+	/* Wait for a reply */
+	timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ;
+	while (status_block[87] != 0xFF) {
+		if (time_after(jiffies, timeout)) {
+			osm_err("%s: Get status timeout.\n", c->name);
+			return -ETIMEDOUT;
+		}
+
+		schedule_timeout_uninterruptible(1);
+	}
+
+#ifdef DEBUG
+	i2o_debug_state(c);
+#endif
+
+	return 0;
+}
+
+/*
+ *	i2o_hrt_get - Get the Hardware Resource Table from the I2O controller
+ *	@c: I2O controller from which the HRT should be fetched
+ *
+ *	The HRT contains information about possible hidden devices but is
+ *	mostly useless to us.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_hrt_get(struct i2o_controller *c)
+{
+	int rc;
+	int i;
+	i2o_hrt *hrt = c->hrt.virt;
+	u32 size = sizeof(i2o_hrt);
+	struct device *dev = &c->pdev->dev;
+
+	for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
+		struct i2o_message *msg;
+
+		msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+		if (IS_ERR(msg))
+			return PTR_ERR(msg);
+
+		msg->u.head[0] = cpu_to_le32(SIX_WORD_MSG_SIZE | SGL_OFFSET_4);
+		msg->u.head[1] =
+		    cpu_to_le32(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 |
+				ADAPTER_TID);
+		msg->body[0] = cpu_to_le32(0xd0000000 | c->hrt.len);
+		msg->body[1] = cpu_to_le32(c->hrt.phys);
+
+		rc = i2o_msg_post_wait_mem(c, msg, 20, &c->hrt);
+
+		if (rc < 0) {
+			osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
+				-rc);
+			return rc;
+		}
+
+		size = hrt->num_entries * hrt->entry_len << 2;
+		if (size > c->hrt.len) {
+			if (i2o_dma_realloc(dev, &c->hrt, size))
+				return -ENOMEM;
+			else
+				hrt = c->hrt.virt;
+		} else
+			return i2o_parse_hrt(c);
+	}
+
+	osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
+		I2O_HRT_GET_TRIES);
+
+	return -EBUSY;
+}
+
+/**
+ *	i2o_iop_release - release the memory for a I2O controller
+ *	@dev: I2O controller which should be released
+ *
+ *	Release the allocated memory. This function is called if refcount of
+ *	device reaches 0 automatically.
+ */
+static void i2o_iop_release(struct device *dev)
+{
+	struct i2o_controller *c = to_i2o_controller(dev);
+
+	i2o_iop_free(c);
+};
+
+/**
+ *	i2o_iop_alloc - Allocate and initialize a i2o_controller struct
+ *
+ *	Allocate the necessary memory for a i2o_controller struct and
+ *	initialize the lists and message mempool.
+ *
+ *	Returns a pointer to the I2O controller or a negative error code on
+ *	failure.
+ */
+struct i2o_controller *i2o_iop_alloc(void)
+{
+	static int unit = 0;	/* 0 and 1 are NULL IOP and Local Host */
+	struct i2o_controller *c;
+	char poolname[32];
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c) {
+		osm_err("i2o: Insufficient memory to allocate a I2O controller."
+			"\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	c->unit = unit++;
+	sprintf(c->name, "iop%d", c->unit);
+
+	snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name);
+	if (i2o_pool_alloc
+	    (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32),
+	     I2O_MSG_INPOOL_MIN)) {
+		kfree(c);
+		return ERR_PTR(-ENOMEM);
+	};
+
+	INIT_LIST_HEAD(&c->devices);
+	spin_lock_init(&c->lock);
+	mutex_init(&c->lct_lock);
+
+	device_initialize(&c->device);
+
+	c->device.release = &i2o_iop_release;
+
+	dev_set_name(&c->device, "iop%d", c->unit);
+
+#if BITS_PER_LONG == 64
+	spin_lock_init(&c->context_list_lock);
+	atomic_set(&c->context_list_counter, 0);
+	INIT_LIST_HEAD(&c->context_list);
+#endif
+
+	return c;
+};
+
+/**
+ *	i2o_iop_add - Initialize the I2O controller and add him to the I2O core
+ *	@c: controller
+ *
+ *	Initialize the I2O controller and if no error occurs add him to the I2O
+ *	core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_iop_add(struct i2o_controller *c)
+{
+	int rc;
+
+	if ((rc = device_add(&c->device))) {
+		osm_err("%s: could not add controller\n", c->name);
+		goto iop_reset;
+	}
+
+	osm_info("%s: Activating I2O controller...\n", c->name);
+	osm_info("%s: This may take a few minutes if there are many devices\n",
+		 c->name);
+
+	if ((rc = i2o_iop_activate(c))) {
+		osm_err("%s: could not activate controller\n", c->name);
+		goto device_del;
+	}
+
+	osm_debug("%s: building sys table...\n", c->name);
+
+	if ((rc = i2o_systab_build()))
+		goto device_del;
+
+	osm_debug("%s: online controller...\n", c->name);
+
+	if ((rc = i2o_iop_online(c)))
+		goto device_del;
+
+	osm_debug("%s: getting LCT...\n", c->name);
+
+	if ((rc = i2o_exec_lct_get(c)))
+		goto device_del;
+
+	list_add(&c->list, &i2o_controllers);
+
+	i2o_driver_notify_controller_add_all(c);
+
+	osm_info("%s: Controller added\n", c->name);
+
+	return 0;
+
+      device_del:
+	device_del(&c->device);
+
+      iop_reset:
+	i2o_iop_reset(c);
+
+	return rc;
+};
+
+/**
+ *	i2o_event_register - Turn on/off event notification for a I2O device
+ *	@dev: I2O device which should receive the event registration request
+ *	@drv: driver which want to get notified
+ *	@tcntxt: transaction context to use with this notifier
+ *	@evt_mask: mask of events
+ *
+ *	Create and posts an event registration message to the task. No reply
+ *	is waited for, or expected. If you do not want further notifications,
+ *	call the i2o_event_register again with a evt_mask of 0.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv,
+		       int tcntxt, u32 evt_mask)
+{
+	struct i2o_controller *c = dev->iop;
+	struct i2o_message *msg;
+
+	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+	msg->u.head[1] =
+	    cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->
+			lct_data.tid);
+	msg->u.s.icntxt = cpu_to_le32(drv->context);
+	msg->u.s.tcntxt = cpu_to_le32(tcntxt);
+	msg->body[0] = cpu_to_le32(evt_mask);
+
+	i2o_msg_post(c, msg);
+
+	return 0;
+};
+
+/**
+ *	i2o_iop_init - I2O main initialization function
+ *
+ *	Initialize the I2O drivers (OSM) functions, register the Executive OSM,
+ *	initialize the I2O PCI part and finally initialize I2O device stuff.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_iop_init(void)
+{
+	int rc = 0;
+
+	printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+	if ((rc = i2o_driver_init()))
+		goto exit;
+
+	if ((rc = i2o_exec_init()))
+		goto driver_exit;
+
+	if ((rc = i2o_pci_init()))
+		goto exec_exit;
+
+	return 0;
+
+      exec_exit:
+	i2o_exec_exit();
+
+      driver_exit:
+	i2o_driver_exit();
+
+      exit:
+	return rc;
+}
+
+/**
+ *	i2o_iop_exit - I2O main exit function
+ *
+ *	Removes I2O controllers from PCI subsystem and shut down OSMs.
+ */
+static void __exit i2o_iop_exit(void)
+{
+	i2o_pci_exit();
+	i2o_exec_exit();
+	i2o_driver_exit();
+};
+
+module_init(i2o_iop_init);
+module_exit(i2o_iop_exit);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+#if BITS_PER_LONG == 64
+EXPORT_SYMBOL(i2o_cntxt_list_add);
+EXPORT_SYMBOL(i2o_cntxt_list_get);
+EXPORT_SYMBOL(i2o_cntxt_list_remove);
+EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
+#endif
+EXPORT_SYMBOL(i2o_msg_get_wait);
+EXPORT_SYMBOL(i2o_find_iop);
+EXPORT_SYMBOL(i2o_iop_find_device);
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_status_get);
+EXPORT_SYMBOL(i2o_controllers);
diff --git a/drivers/staging/i2o/memory.c b/drivers/staging/i2o/memory.c
new file mode 100644
index 0000000..8f9509d
--- /dev/null
+++ b/drivers/staging/i2o/memory.c
@@ -0,0 +1,313 @@
+/*
+ *	Functions to handle I2O memory
+ *
+ *	Pulled from the inlines in i2o headers and uninlined
+ *
+ *
+ *	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 "i2o.h"
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/* Protects our 32/64bit mask switching */
+static DEFINE_MUTEX(mem_lock);
+
+/**
+ *	i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ *	@c: I2O controller for which the calculation should be done
+ *	@body_size: maximum body size used for message in 32-bit words.
+ *
+ *	Return the maximum number of SG elements in a SG list.
+ */
+u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+	i2o_status_block *sb = c->status_block.virt;
+	u16 sg_count =
+	    (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+	    body_size;
+
+	if (c->pae_support) {
+		/*
+		 * for 64-bit a SG attribute element must be added and each
+		 * SG element needs 12 bytes instead of 8.
+		 */
+		sg_count -= 2;
+		sg_count /= 3;
+	} else
+		sg_count /= 2;
+
+	if (c->short_req && (sg_count > 8))
+		sg_count = 8;
+
+	return sg_count;
+}
+EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
+
+
+/**
+ *	i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ *	@c: I2O controller
+ *	@ptr: pointer to the data which should be mapped
+ *	@size: size of data in bytes
+ *	@direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *	@sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *	This function does all necessary DMA handling and also writes the I2O
+ *	SGL elements into the I2O message. For details on DMA handling see also
+ *	dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ *	SG list if the allocation was successful.
+ *
+ *	Returns DMA address which must be checked for failures using
+ *	dma_mapping_error().
+ */
+dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+					    size_t size,
+					    enum dma_data_direction direction,
+					    u32 ** sg_ptr)
+{
+	u32 sg_flags;
+	u32 *mptr = *sg_ptr;
+	dma_addr_t dma_addr;
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		sg_flags = 0xd4000000;
+		break;
+	case DMA_FROM_DEVICE:
+		sg_flags = 0xd0000000;
+		break;
+	default:
+		return 0;
+	}
+
+	dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+	if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+		if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+			*mptr++ = cpu_to_le32(0x7C020002);
+			*mptr++ = cpu_to_le32(PAGE_SIZE);
+		}
+#endif
+
+		*mptr++ = cpu_to_le32(sg_flags | size);
+		*mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+		if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+			*mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
+#endif
+		*sg_ptr = mptr;
+	}
+	return dma_addr;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_single);
+
+/**
+ *	i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ *	@c: I2O controller
+ *	@sg: SG list to be mapped
+ *	@sg_count: number of elements in the SG list
+ *	@direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ *	@sg_ptr: pointer to the SG list inside the I2O message
+ *
+ *	This function does all necessary DMA handling and also writes the I2O
+ *	SGL elements into the I2O message. For details on DMA handling see also
+ *	dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ *	list if the allocation was successful.
+ *
+ *	Returns 0 on failure or 1 on success.
+ */
+int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
+	    int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
+{
+	u32 sg_flags;
+	u32 *mptr = *sg_ptr;
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		sg_flags = 0x14000000;
+		break;
+	case DMA_FROM_DEVICE:
+		sg_flags = 0x10000000;
+		break;
+	default:
+		return 0;
+	}
+
+	sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+	if (!sg_count)
+		return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+	if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+		*mptr++ = cpu_to_le32(0x7C020002);
+		*mptr++ = cpu_to_le32(PAGE_SIZE);
+	}
+#endif
+
+	while (sg_count-- > 0) {
+		if (!sg_count)
+			sg_flags |= 0xC0000000;
+		*mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
+		*mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+		if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+			*mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
+#endif
+		sg = sg_next(sg);
+	}
+	*sg_ptr = mptr;
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
+
+/**
+ *	i2o_dma_alloc - Allocate DMA memory
+ *	@dev: struct device pointer to the PCI device of the I2O controller
+ *	@addr: i2o_dma struct which should get the DMA buffer
+ *	@len: length of the new DMA memory
+ *
+ *	Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ *	Returns 0 on success or -ENOMEM on failure.
+ */
+int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int dma_64 = 0;
+
+	mutex_lock(&mem_lock);
+	if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_BIT_MASK(64))) {
+		dma_64 = 1;
+		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+			mutex_unlock(&mem_lock);
+			return -ENOMEM;
+		}
+	}
+
+	addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
+
+	if ((sizeof(dma_addr_t) > 4) && dma_64)
+		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+			printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+	mutex_unlock(&mem_lock);
+
+	if (!addr->virt)
+		return -ENOMEM;
+
+	memset(addr->virt, 0, len);
+	addr->len = len;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_alloc);
+
+
+/**
+ *	i2o_dma_free - Free DMA memory
+ *	@dev: struct device pointer to the PCI device of the I2O controller
+ *	@addr: i2o_dma struct which contains the DMA buffer
+ *
+ *	Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+	if (addr->virt) {
+		if (addr->phys)
+			dma_free_coherent(dev, addr->len, addr->virt,
+					  addr->phys);
+		else
+			kfree(addr->virt);
+		addr->virt = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(i2o_dma_free);
+
+
+/**
+ *	i2o_dma_realloc - Realloc DMA memory
+ *	@dev: struct device pointer to the PCI device of the I2O controller
+ *	@addr: pointer to a i2o_dma struct DMA buffer
+ *	@len: new length of memory
+ *
+ *	If there was something allocated in the addr, free it first. If len > 0
+ *	than try to allocate it and write the addresses back to the addr
+ *	structure. If len == 0 set the virtual address to NULL.
+ *
+ *	Returns the 0 on success or negative error code on failure.
+ */
+int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+	i2o_dma_free(dev, addr);
+
+	if (len)
+		return i2o_dma_alloc(dev, addr, len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_realloc);
+
+/*
+ *	i2o_pool_alloc - Allocate an slab cache and mempool
+ *	@mempool: pointer to struct i2o_pool to write data into.
+ *	@name: name which is used to identify cache
+ *	@size: size of each object
+ *	@min_nr: minimum number of objects
+ *
+ *	First allocates a slab cache with name and size. Then allocates a
+ *	mempool which uses the slab cache for allocation and freeing.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+				 size_t size, int min_nr)
+{
+	pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	if (!pool->name)
+		goto exit;
+	strcpy(pool->name, name);
+
+	pool->slab =
+	    kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
+	if (!pool->slab)
+		goto free_name;
+
+	pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
+	if (!pool->mempool)
+		goto free_slab;
+
+	return 0;
+
+free_slab:
+	kmem_cache_destroy(pool->slab);
+
+free_name:
+	kfree(pool->name);
+
+exit:
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(i2o_pool_alloc);
+
+/*
+ *	i2o_pool_free - Free slab cache and mempool again
+ *	@mempool: pointer to struct i2o_pool which should be freed
+ *
+ *	Note that you have to return all objects to the mempool again before
+ *	calling i2o_pool_free().
+ */
+void i2o_pool_free(struct i2o_pool *pool)
+{
+	mempool_destroy(pool->mempool);
+	kmem_cache_destroy(pool->slab);
+	kfree(pool->name);
+};
+EXPORT_SYMBOL_GPL(i2o_pool_free);
diff --git a/drivers/staging/i2o/pci.c b/drivers/staging/i2o/pci.c
new file mode 100644
index 0000000..b3b8a61
--- /dev/null
+++ b/drivers/staging/i2o/pci.c
@@ -0,0 +1,497 @@
+/*
+ *	PCI handling of I2O controller
+ *
+ * 	Copyright (C) 1999-2002	Red Hat Software
+ *
+ *	Written by Alan Cox, Building Number Three Ltd
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation; either version 2 of the License, or (at your
+ *	option) any later version.
+ *
+ *	A lot of the I2O message side code from this is taken from the Red
+ *	Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *	Fixes/additions:
+ *		Philipp Rumpf
+ *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *		Deepak Saxena <deepak@plexity.net>
+ *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ *			Ported to Linux 2.5.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Minor fixes for 2.6.
+ *		Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *			Support for sysfs included.
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include "i2o.h"
+#include <linux/module.h>
+#include "core.h"
+
+#define OSM_DESCRIPTION	"I2O-subsystem"
+
+/* PCI device id table for all I2O controllers */
+static struct pci_device_id i2o_pci_ids[] = {
+	{PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
+	{PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
+	{.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
+	 .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
+	{0}
+};
+
+/**
+ *	i2o_pci_free - Frees the DMA memory for the I2O controller
+ *	@c: I2O controller to free
+ *
+ *	Remove all allocated DMA memory and unmap memory IO regions. If MTRR
+ *	is enabled, also remove it again.
+ */
+static void i2o_pci_free(struct i2o_controller *c)
+{
+	struct device *dev;
+
+	dev = &c->pdev->dev;
+
+	i2o_dma_free(dev, &c->out_queue);
+	i2o_dma_free(dev, &c->status_block);
+	kfree(c->lct);
+	i2o_dma_free(dev, &c->dlct);
+	i2o_dma_free(dev, &c->hrt);
+	i2o_dma_free(dev, &c->status);
+
+	if (c->raptor && c->in_queue.virt)
+		iounmap(c->in_queue.virt);
+
+	if (c->base.virt)
+		iounmap(c->base.virt);
+
+	pci_release_regions(c->pdev);
+}
+
+/**
+ *	i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
+ *	@c: I2O controller
+ *
+ *	Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
+ *	IO mappings are also done here. If MTRR is enabled, also do add memory
+ *	regions here.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_alloc(struct i2o_controller *c)
+{
+	struct pci_dev *pdev = c->pdev;
+	struct device *dev = &pdev->dev;
+	int i;
+
+	if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+		printk(KERN_ERR "%s: device already claimed\n", c->name);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < 6; i++) {
+		/* Skip I/O spaces */
+		if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+			if (!c->base.phys) {
+				c->base.phys = pci_resource_start(pdev, i);
+				c->base.len = pci_resource_len(pdev, i);
+
+				/*
+				 * If we know what card it is, set the size
+				 * correctly. Code is taken from dpt_i2o.c
+				 */
+				if (pdev->device == 0xa501) {
+					if (pdev->subsystem_device >= 0xc032 &&
+					    pdev->subsystem_device <= 0xc03b) {
+						if (c->base.len > 0x400000)
+							c->base.len = 0x400000;
+					} else {
+						if (c->base.len > 0x100000)
+							c->base.len = 0x100000;
+					}
+				}
+				if (!c->raptor)
+					break;
+			} else {
+				c->in_queue.phys = pci_resource_start(pdev, i);
+				c->in_queue.len = pci_resource_len(pdev, i);
+				break;
+			}
+		}
+	}
+
+	if (i == 6) {
+		printk(KERN_ERR "%s: I2O controller has no memory regions"
+		       " defined.\n", c->name);
+		i2o_pci_free(c);
+		return -EINVAL;
+	}
+
+	/* Map the I2O controller */
+	if (c->raptor) {
+		printk(KERN_INFO "%s: PCI I2O controller\n", c->name);
+		printk(KERN_INFO "     BAR0 at 0x%08lX size=%ld\n",
+		       (unsigned long)c->base.phys, (unsigned long)c->base.len);
+		printk(KERN_INFO "     BAR1 at 0x%08lX size=%ld\n",
+		       (unsigned long)c->in_queue.phys,
+		       (unsigned long)c->in_queue.len);
+	} else
+		printk(KERN_INFO "%s: PCI I2O controller at %08lX size=%ld\n",
+		       c->name, (unsigned long)c->base.phys,
+		       (unsigned long)c->base.len);
+
+	c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
+	if (!c->base.virt) {
+		printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	if (c->raptor) {
+		c->in_queue.virt =
+		    ioremap_nocache(c->in_queue.phys, c->in_queue.len);
+		if (!c->in_queue.virt) {
+			printk(KERN_ERR "%s: Unable to map controller.\n",
+			       c->name);
+			i2o_pci_free(c);
+			return -ENOMEM;
+		}
+	} else
+		c->in_queue = c->base;
+
+	c->irq_status = c->base.virt + I2O_IRQ_STATUS;
+	c->irq_mask = c->base.virt + I2O_IRQ_MASK;
+	c->in_port = c->base.virt + I2O_IN_PORT;
+	c->out_port = c->base.virt + I2O_OUT_PORT;
+
+	/* Motorola/Freescale chip does not follow spec */
+	if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
+		/* Check if CPU is enabled */
+		if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
+			printk(KERN_INFO "%s: MPC82XX needs CPU running to "
+			       "service I2O.\n", c->name);
+			i2o_pci_free(c);
+			return -ENODEV;
+		} else {
+			c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
+			c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
+			c->in_port += I2O_MOTOROLA_PORT_OFFSET;
+			c->out_port += I2O_MOTOROLA_PORT_OFFSET;
+			printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
+			       c->name);
+		}
+	}
+
+	if (i2o_dma_alloc(dev, &c->status, 8)) {
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	if (i2o_dma_alloc(dev, &c->out_queue,
+		I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+				sizeof(u32))) {
+		i2o_pci_free(c);
+		return -ENOMEM;
+	}
+
+	pci_set_drvdata(pdev, c);
+
+	return 0;
+}
+
+/**
+ *	i2o_pci_interrupt - Interrupt handler for I2O controller
+ *	@irq: interrupt line
+ *	@dev_id: pointer to the I2O controller
+ *
+ *	Handle an interrupt from a PCI based I2O controller. This turns out
+ *	to be rather simple. We keep the controller pointer in the cookie.
+ */
+static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
+{
+	struct i2o_controller *c = dev_id;
+	u32 m;
+	irqreturn_t rc = IRQ_NONE;
+
+	while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
+		m = readl(c->out_port);
+		if (m == I2O_QUEUE_EMPTY) {
+			/*
+			 * Old 960 steppings had a bug in the I2O unit that
+			 * caused the queue to appear empty when it wasn't.
+			 */
+			m = readl(c->out_port);
+			if (unlikely(m == I2O_QUEUE_EMPTY))
+				break;
+		}
+
+		/* dispatch it */
+		if (i2o_driver_dispatch(c, m))
+			/* flush it if result != 0 */
+			i2o_flush_reply(c, m);
+
+		rc = IRQ_HANDLED;
+	}
+
+	return rc;
+}
+
+/**
+ *	i2o_pci_irq_enable - Allocate interrupt for I2O controller
+ *	@c: i2o_controller that the request is for
+ *
+ *	Allocate an interrupt for the I2O controller, and activate interrupts
+ *	on the I2O controller.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_irq_enable(struct i2o_controller *c)
+{
+	struct pci_dev *pdev = c->pdev;
+	int rc;
+
+	writel(0xffffffff, c->irq_mask);
+
+	if (pdev->irq) {
+		rc = request_irq(pdev->irq, i2o_pci_interrupt, IRQF_SHARED,
+				 c->name, c);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: unable to allocate interrupt %d."
+			       "\n", c->name, pdev->irq);
+			return rc;
+		}
+	}
+
+	writel(0x00000000, c->irq_mask);
+
+	printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
+
+	return 0;
+}
+
+/**
+ *	i2o_pci_irq_disable - Free interrupt for I2O controller
+ *	@c: I2O controller
+ *
+ *	Disable interrupts in I2O controller and then free interrupt.
+ */
+static void i2o_pci_irq_disable(struct i2o_controller *c)
+{
+	writel(0xffffffff, c->irq_mask);
+
+	if (c->pdev->irq > 0)
+		free_irq(c->pdev->irq, c);
+}
+
+/**
+ *	i2o_pci_probe - Probe the PCI device for an I2O controller
+ *	@pdev: PCI device to test
+ *	@id: id which matched with the PCI device id table
+ *
+ *	Probe the PCI device for any device which is a memory of the
+ *	Intelligent, I2O class or an Adaptec Zero Channel Controller. We
+ *	attempt to set up each such device and register it with the core.
+ *
+ *	Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct i2o_controller *c;
+	int rc;
+	struct pci_dev *i960 = NULL;
+
+	printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
+
+	if ((pdev->class & 0xff) > 1) {
+		printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
+		       "(skipping).\n", pci_name(pdev));
+		return -ENODEV;
+	}
+
+	if ((rc = pci_enable_device(pdev))) {
+		printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+		       pci_name(pdev));
+		return rc;
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+		printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
+		       pci_name(pdev));
+		rc = -ENODEV;
+		goto disable;
+	}
+
+	pci_set_master(pdev);
+
+	c = i2o_iop_alloc();
+	if (IS_ERR(c)) {
+		printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
+		       pci_name(pdev));
+		rc = PTR_ERR(c);
+		goto disable;
+	} else
+		printk(KERN_INFO "%s: controller found (%s)\n", c->name,
+		       pci_name(pdev));
+
+	c->pdev = pdev;
+	c->device.parent = &pdev->dev;
+
+	/* Cards that fall apart if you hit them with large I/O loads... */
+	if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
+		c->short_req = 1;
+		printk(KERN_INFO "%s: Symbios FC920 workarounds activated.\n",
+		       c->name);
+	}
+
+	if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
+		/*
+		 * Expose the ship behind i960 for initialization, or it will
+		 * failed
+		 */
+		i960 = pci_get_slot(c->pdev->bus,
+				  PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+
+		if (i960) {
+			pci_write_config_word(i960, 0x42, 0);
+			pci_dev_put(i960);
+		}
+
+		c->promise = 1;
+		c->limit_sectors = 1;
+	}
+
+	if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
+		c->adaptec = 1;
+
+	/* Cards that go bananas if you quiesce them before you reset them. */
+	if (pdev->vendor == PCI_VENDOR_ID_DPT) {
+		c->no_quiesce = 1;
+		if (pdev->device == 0xa511)
+			c->raptor = 1;
+
+		if (pdev->subsystem_device == 0xc05a) {
+			c->limit_sectors = 1;
+			printk(KERN_INFO
+			       "%s: limit sectors per request to %d\n", c->name,
+			       I2O_MAX_SECTORS_LIMITED);
+		}
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+		if (sizeof(dma_addr_t) > 4) {
+			if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+				printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
+				       c->name);
+			else {
+				c->pae_support = 1;
+				printk(KERN_INFO "%s: using 64-bit DMA\n",
+				       c->name);
+			}
+		}
+#endif
+	}
+
+	if ((rc = i2o_pci_alloc(c))) {
+		printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
+		       "failed\n", c->name);
+		goto free_controller;
+	}
+
+	if (i2o_pci_irq_enable(c)) {
+		printk(KERN_ERR "%s: unable to enable interrupts for I2O "
+		       "controller\n", c->name);
+		goto free_pci;
+	}
+
+	if ((rc = i2o_iop_add(c)))
+		goto uninstall;
+
+	if (i960)
+		pci_write_config_word(i960, 0x42, 0x03ff);
+
+	return 0;
+
+      uninstall:
+	i2o_pci_irq_disable(c);
+
+      free_pci:
+	i2o_pci_free(c);
+
+      free_controller:
+	i2o_iop_free(c);
+
+      disable:
+	pci_disable_device(pdev);
+
+	return rc;
+}
+
+/**
+ *	i2o_pci_remove - Removes a I2O controller from the system
+ *	@pdev: I2O controller which should be removed
+ *
+ *	Reset the I2O controller, disable interrupts and remove all allocated
+ *	resources.
+ */
+static void i2o_pci_remove(struct pci_dev *pdev)
+{
+	struct i2o_controller *c;
+	c = pci_get_drvdata(pdev);
+
+	i2o_iop_remove(c);
+	i2o_pci_irq_disable(c);
+	i2o_pci_free(c);
+
+	pci_disable_device(pdev);
+
+	printk(KERN_INFO "%s: Controller removed.\n", c->name);
+
+	put_device(&c->device);
+};
+
+/* PCI driver for I2O controller */
+static struct pci_driver i2o_pci_driver = {
+	.name = "PCI_I2O",
+	.id_table = i2o_pci_ids,
+	.probe = i2o_pci_probe,
+	.remove = i2o_pci_remove,
+};
+
+/**
+ *	i2o_pci_init - registers I2O PCI driver in PCI subsystem
+ *
+ *	Returns > 0 on success or negative error code on failure.
+ */
+int __init i2o_pci_init(void)
+{
+	return pci_register_driver(&i2o_pci_driver);
+};
+
+/**
+ *	i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
+ */
+void __exit i2o_pci_exit(void)
+{
+	pci_unregister_driver(&i2o_pci_driver);
+};
+
+MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 940ed23..72c96aa 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -49,6 +49,8 @@
 	[IIO_CCT] = "cct",
 	[IIO_PRESSURE] = "pressure",
 	[IIO_HUMIDITYRELATIVE] = "humidityrelative",
+	[IIO_ACTIVITY] = "activity",
+	[IIO_STEPS] = "steps",
 };
 
 static const char * const iio_ev_type_text[] = {
@@ -57,6 +59,7 @@
 	[IIO_EV_TYPE_ROC] = "roc",
 	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
 	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+	[IIO_EV_TYPE_CHANGE] = "change",
 };
 
 static const char * const iio_ev_dir_text[] = {
@@ -92,6 +95,10 @@
 	[IIO_MOD_NORTH_TRUE] = "from_north_true",
 	[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
 	[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
+	[IIO_MOD_RUNNING] = "running",
+	[IIO_MOD_JOGGING] = "jogging",
+	[IIO_MOD_WALKING] = "walking",
+	[IIO_MOD_STILL] = "still",
 };
 
 static bool event_is_known(struct iio_event_data *event)
@@ -121,6 +128,8 @@
 	case IIO_CCT:
 	case IIO_PRESSURE:
 	case IIO_HUMIDITYRELATIVE:
+	case IIO_ACTIVITY:
+	case IIO_STEPS:
 		break;
 	default:
 		return false;
@@ -154,6 +163,10 @@
 	case IIO_MOD_NORTH_TRUE:
 	case IIO_MOD_NORTH_MAGN_TILT_COMP:
 	case IIO_MOD_NORTH_TRUE_TILT_COMP:
+	case IIO_MOD_RUNNING:
+	case IIO_MOD_JOGGING:
+	case IIO_MOD_WALKING:
+	case IIO_MOD_STILL:
 		break;
 	default:
 		return false;
@@ -165,6 +178,7 @@
 	case IIO_EV_TYPE_ROC:
 	case IIO_EV_TYPE_THRESH_ADAPTIVE:
 	case IIO_EV_TYPE_MAG_ADAPTIVE:
+	case IIO_EV_TYPE_CHANGE:
 		break;
 	default:
 		return false;
@@ -174,6 +188,7 @@
 	case IIO_EV_DIR_EITHER:
 	case IIO_EV_DIR_RISING:
 	case IIO_EV_DIR_FALLING:
+	case IIO_EV_DIR_NONE:
 		break;
 	default:
 		return false;
@@ -214,9 +229,11 @@
 	else if (chan >= 0)
 		printf("channel: %d, ", chan);
 
-	printf("evtype: %s, direction: %s\n",
-		iio_ev_type_text[ev_type],
-		iio_ev_dir_text[dir]);
+	printf("evtype: %s", iio_ev_type_text[ev_type]);
+
+	if (dir != IIO_EV_DIR_NONE)
+		printf(", direction: %s", iio_ev_dir_text[dir]);
+	printf("\n");
 }
 
 int main(int argc, char **argv)
diff --git a/drivers/staging/iio/Documentation/ring.txt b/drivers/staging/iio/Documentation/ring.txt
index e1da433..18718fc 100644
--- a/drivers/staging/iio/Documentation/ring.txt
+++ b/drivers/staging/iio/Documentation/ring.txt
@@ -39,9 +39,9 @@
   If parameters have changed that require reinitialization or configuration of
   the buffer this will trigger it.
 
-get_bytes_per_datum, set_bytes_per_datum
-  Get/set the number of bytes for a complete scan. (All samples + timestamp)
+set_bytes_per_datum
+  Set the number of bytes for a complete scan. (All samples + timestamp)
 
-get_length / set_length
-  Get/set the number of complete scans that may be held by the buffer.
+set_length
+  Set the number of complete scans that may be held by the buffer.
 
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index f5e145c..b78c9c5 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -716,14 +716,6 @@
 	if (ret)
 		return ret;
 
-	ret = iio_buffer_register(indio_dev,
-				  lis3l02dq_channels,
-				  ARRAY_SIZE(lis3l02dq_channels));
-	if (ret) {
-		dev_err(&spi->dev, "failed to initialize the buffer\n");
-		goto error_unreg_buffer_funcs;
-	}
-
 	if (spi->irq) {
 		ret = request_threaded_irq(st->us->irq,
 					   &lis3l02dq_th,
@@ -732,7 +724,7 @@
 					   "lis3l02dq",
 					   indio_dev);
 		if (ret)
-			goto error_uninitialize_buffer;
+			goto error_unreg_buffer_funcs;
 
 		ret = lis3l02dq_probe_trigger(indio_dev);
 		if (ret)
@@ -756,8 +748,6 @@
 error_free_interrupt:
 	if (spi->irq)
 		free_irq(st->us->irq, indio_dev);
-error_uninitialize_buffer:
-	iio_buffer_unregister(indio_dev);
 error_unreg_buffer_funcs:
 	lis3l02dq_unconfigure_buffer(indio_dev);
 	return ret;
@@ -804,7 +794,6 @@
 		free_irq(st->us->irq, indio_dev);
 
 	lis3l02dq_remove_trigger(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	lis3l02dq_unconfigure_buffer(indio_dev);
 
 	return 0;
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 9efc77b..1fd9009 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -393,7 +393,7 @@
 	int ret;
 	struct iio_buffer *buffer;
 
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (!buffer)
 		return -ENOMEM;
 
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index e4e5639..31fb218 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -223,33 +223,6 @@
 	return ret;
 }
 
-#ifdef SCA3000_DEBUG
-/**
- * sca3000_check_status() check the status register
- *
- * Only used for debugging purposes
- **/
-static int sca3000_check_status(struct device *dev)
-{
-	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct sca3000_state *st = iio_priv(indio_dev);
-
-	mutex_lock(&st->lock);
-	ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1);
-	if (ret < 0)
-		goto error_ret;
-	if (st->rx[0] & SCA3000_EEPROM_CS_ERROR)
-		dev_err(dev, "eeprom error\n");
-	if (st->rx[0] & SCA3000_SPI_FRAME_ERROR)
-		dev_err(dev, "Previous SPI Frame was corrupt\n");
-
-error_ret:
-	mutex_unlock(&st->lock);
-	return ret;
-}
-#endif /* SCA3000_DEBUG */
-
 /**
  * sca3000_show_rev() - sysfs interface to read the chip revision number
  **/
@@ -459,6 +432,8 @@
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
 			BIT(IIO_CHAN_INFO_OFFSET),
+		/* No buffer support */
+		.scan_index = -1,
 	},
 };
 
@@ -1154,17 +1129,6 @@
 	if (ret < 0)
 		return ret;
 
-	ret = iio_buffer_register(indio_dev,
-				  sca3000_channels,
-				  ARRAY_SIZE(sca3000_channels));
-	if (ret < 0)
-		goto error_unregister_dev;
-	if (indio_dev->buffer) {
-		iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer, 2);
-	}
-
 	if (spi->irq) {
 		ret = request_threaded_irq(spi->irq,
 					   NULL,
@@ -1173,7 +1137,7 @@
 					   "sca3000",
 					   indio_dev);
 		if (ret)
-			goto error_unregister_ring;
+			goto error_unregister_dev;
 	}
 	sca3000_register_ring_funcs(indio_dev);
 	ret = sca3000_clean_setup(st);
@@ -1184,8 +1148,6 @@
 error_free_irq:
 	if (spi->irq)
 		free_irq(spi->irq, indio_dev);
-error_unregister_ring:
-	iio_buffer_unregister(indio_dev);
 error_unregister_dev:
 	iio_device_unregister(indio_dev);
 	return ret;
@@ -1219,7 +1181,6 @@
 	if (spi->irq)
 		free_irq(spi->irq, indio_dev);
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	sca3000_unconfigure_ring(indio_dev);
 
 	return 0;
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 1578276..f76a268 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -129,26 +129,11 @@
 	return ret ? ret : num_read;
 }
 
-/* This is only valid with all 3 elements enabled */
-static int sca3000_ring_get_length(struct iio_buffer *r)
-{
-	return 64;
-}
-
-/* only valid if resolution is kept at 11bits */
-static int sca3000_ring_get_bytes_per_datum(struct iio_buffer *r)
-{
-	return 6;
-}
-
 static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
 {
 	return r->stufftoread;
 }
 
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
 /**
  * sca3000_query_ring_int() is the hardware ring status interrupt enabled
  **/
@@ -238,20 +223,13 @@
  * only apply to the ring buffer.  At all times full rate and accuracy
  * is available via direct reading from registers.
  */
-static struct attribute *sca3000_ring_attributes[] = {
-	&dev_attr_length.attr,
-	&dev_attr_enable.attr,
+static const struct attribute *sca3000_ring_attributes[] = {
 	&iio_dev_attr_50_percent.dev_attr.attr,
 	&iio_dev_attr_75_percent.dev_attr.attr,
 	&iio_dev_attr_in_accel_scale.dev_attr.attr,
 	NULL,
 };
 
-static struct attribute_group sca3000_ring_attr = {
-	.attrs = sca3000_ring_attributes,
-	.name = "buffer",
-};
-
 static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
 {
 	struct iio_buffer *buf;
@@ -264,7 +242,8 @@
 	ring->private = indio_dev;
 	buf = &ring->buf;
 	buf->stufftoread = 0;
-	buf->attrs = &sca3000_ring_attr;
+	buf->length = 64;
+	buf->attrs = sca3000_ring_attributes;
 	iio_buffer_init(buf);
 
 	return buf;
@@ -277,8 +256,6 @@
 
 static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = {
 	.read_first_n = &sca3000_read_first_n_hw_rb,
-	.get_length = &sca3000_ring_get_length,
-	.get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum,
 	.data_available = sca3000_ring_buf_data_available,
 	.release = sca3000_ring_release,
 };
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index f6526aa..6f8ce6c 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -612,7 +612,7 @@
 	const struct ad7192_platform_data *pdata = spi->dev.platform_data;
 	struct ad7192_state *st;
 	struct iio_dev *indio_dev;
-	int ret , voltage_uv = 0;
+	int ret, voltage_uv = 0;
 
 	if (!pdata) {
 		dev_err(&spi->dev, "no platform data?\n");
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index f053535..d9d6fad 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -436,7 +436,14 @@
 	 */
 	mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch));
 
-	/* prepare the delay/loop unit according to the oversampling count */
+	/*
+	 * prepare the delay/loop unit according to the oversampling count
+	 *
+	 * from the datasheet:
+	 * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
+	 * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
+	 * the LRADC will not trigger the delay group."
+	 */
 	mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch) |
 		LRADC_DELAY_TRIGGER_DELAYS(0) |
 		LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) |
@@ -1495,20 +1502,38 @@
 		return -EINVAL;
 	}
 
-	lradc->over_sample_cnt = 4;
-	ret = of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt);
-	if (ret == 0)
+	if (of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt)) {
+		lradc->over_sample_cnt = 4;
+	} else {
+		if (adapt < 1 || adapt > 32) {
+			dev_err(lradc->dev, "Invalid sample count (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
 		lradc->over_sample_cnt = adapt;
+	}
 
-	lradc->over_sample_delay = 2;
-	ret = of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt);
-	if (ret == 0)
+	if (of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt)) {
+		lradc->over_sample_delay = 2;
+	} else {
+		if (adapt < 2 || adapt > LRADC_DELAY_DELAY_MASK + 1) {
+			dev_err(lradc->dev, "Invalid sample delay (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
 		lradc->over_sample_delay = adapt;
+	}
 
-	lradc->settling_delay = 10;
-	ret = of_property_read_u32(lradc_node, "fsl,settling", &adapt);
-	if (ret == 0)
+	if (of_property_read_u32(lradc_node, "fsl,settling", &adapt)) {
+		lradc->settling_delay = 10;
+	} else {
+		if (adapt < 1 || adapt > LRADC_DELAY_DELAY_MASK) {
+			dev_err(lradc->dev, "Invalid settling delay (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
 		lradc->settling_delay = adapt;
+	}
 
 	return 0;
 }
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index 5a804f1..59ad5a3 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -33,6 +33,7 @@
  * @base: base of irq range
  * @enabled: mask of which irqs are enabled
  * @inuse: mask of which irqs are connected
+ * @regs: irq regs we are faking
  * @lock: protect the evgen state
  */
 struct iio_dummy_eventgen {
@@ -40,6 +41,7 @@
 	int base;
 	bool enabled[IIO_EVENTGEN_NO];
 	bool inuse[IIO_EVENTGEN_NO];
+	struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
 	struct mutex lock;
 };
 
@@ -136,6 +138,12 @@
 }
 EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
 
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
+{
+	return &iio_evgen->regs[irq - iio_evgen->base];
+}
+EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
+
 static void iio_dummy_evgen_free(void)
 {
 	irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
@@ -153,6 +161,15 @@
 			      size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+	unsigned long event;
+	int ret;
+
+	ret = kstrtoul(buf, 10, &event);
+	if (ret)
+		return ret;
+
+	iio_evgen->regs[this_attr->address].reg_id   = this_attr->address;
+	iio_evgen->regs[this_attr->address].reg_data = event;
 
 	if (iio_evgen->enabled[this_attr->address])
 		handle_nested_irq(iio_evgen->base + this_attr->address);
diff --git a/drivers/staging/iio/iio_dummy_evgen.h b/drivers/staging/iio/iio_dummy_evgen.h
index 3a18081..2ac293a 100644
--- a/drivers/staging/iio/iio_dummy_evgen.h
+++ b/drivers/staging/iio/iio_dummy_evgen.h
@@ -1,6 +1,12 @@
 #ifndef _IIO_DUMMY_EVGEN_H_
 #define _IIO_DUMMY_EVGEN_H_
 
+struct iio_dummy_regs {
+	u32 reg_id;
+	u32 reg_data;
+};
+
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
 int iio_dummy_evgen_get_irq(void);
 int iio_dummy_evgen_release_irq(int irq);
 
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index bf78e6f..e452021 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -69,6 +69,34 @@
 	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
 };
 
+/*
+ * simple step detect event - triggered when a step is detected
+ */
+static const struct iio_event_spec step_detect_event = {
+	.type = IIO_EV_TYPE_CHANGE,
+	.dir = IIO_EV_DIR_NONE,
+	.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported running confidence
+ * value rises above a threshold value
+ */
+static const struct iio_event_spec iio_running_event = {
+	.type = IIO_EV_TYPE_THRESH,
+	.dir = IIO_EV_DIR_RISING,
+	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported walking confidence
+ * value falls under a threshold value
+ */
+static const struct iio_event_spec iio_walking_event = {
+	.type = IIO_EV_TYPE_THRESH,
+	.dir = IIO_EV_DIR_FALLING,
+	.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
 #endif
 
 /*
@@ -211,10 +239,44 @@
 	{
 		.type = IIO_VOLTAGE,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.scan_index = -1, /* No buffer support */
 		.output = 1,
 		.indexed = 1,
 		.channel = 0,
 	},
+	{
+		.type = IIO_STEPS,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
+			BIT(IIO_CHAN_INFO_CALIBHEIGHT),
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+		.event_spec = &step_detect_event,
+		.num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_RUNNING,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+		.event_spec = &iio_running_event,
+		.num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+	},
+	{
+		.type = IIO_ACTIVITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_WALKING,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+		.event_spec = &iio_walking_event,
+		.num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+	},
 };
 
 /**
@@ -263,24 +325,55 @@
 			break;
 		}
 		break;
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = st->steps;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_ACTIVITY:
+			switch (chan->channel2) {
+			case IIO_MOD_RUNNING:
+				*val = st->activity_running;
+				ret = IIO_VAL_INT;
+				break;
+			case IIO_MOD_WALKING:
+				*val = st->activity_walking;
+				ret = IIO_VAL_INT;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+		break;
 	case IIO_CHAN_INFO_OFFSET:
 		/* only single ended adc -> 7 */
 		*val = 7;
 		ret = IIO_VAL_INT;
 		break;
 	case IIO_CHAN_INFO_SCALE:
-		switch (chan->differential) {
-		case 0:
-			/* only single ended adc -> 0.001333 */
-			*val = 0;
-			*val2 = 1333;
-			ret = IIO_VAL_INT_PLUS_MICRO;
+		switch (chan->type) {
+		case IIO_VOLTAGE:
+			switch (chan->differential) {
+			case 0:
+				/* only single ended adc -> 0.001333 */
+				*val = 0;
+				*val2 = 1333;
+				ret = IIO_VAL_INT_PLUS_MICRO;
+				break;
+			case 1:
+				/* all differential adc channels ->
+				 * 0.000001344 */
+				*val = 0;
+				*val2 = 1344;
+				ret = IIO_VAL_INT_PLUS_NANO;
+			}
 			break;
-		case 1:
-			/* all differential adc channels -> 0.000001344 */
-			*val = 0;
-			*val2 = 1344;
-			ret = IIO_VAL_INT_PLUS_NANO;
+		default:
+			break;
 		}
 		break;
 	case IIO_CHAN_INFO_CALIBBIAS:
@@ -298,6 +391,27 @@
 		*val2 = 33;
 		ret = IIO_VAL_INT_PLUS_NANO;
 		break;
+	case IIO_CHAN_INFO_ENABLE:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = st->steps_enabled;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		switch (chan->type) {
+		case IIO_STEPS:
+			*val = st->height;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			break;
+		}
+		break;
+
 	default:
 		break;
 	}
@@ -330,14 +444,45 @@
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (chan->output == 0)
-			return -EINVAL;
+		switch (chan->type) {
+		case IIO_VOLTAGE:
+			if (chan->output == 0)
+				return -EINVAL;
 
-		/* Locking not required as writing single value */
-		mutex_lock(&st->lock);
-		st->dac_val = val;
-		mutex_unlock(&st->lock);
-		return 0;
+			/* Locking not required as writing single value */
+			mutex_lock(&st->lock);
+			st->dac_val = val;
+			mutex_unlock(&st->lock);
+			return 0;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_STEPS:
+			mutex_lock(&st->lock);
+			st->steps = val;
+			mutex_unlock(&st->lock);
+			return 0;
+		case IIO_ACTIVITY:
+			if (val < 0)
+				val = 0;
+			if (val > 100)
+				val = 100;
+			switch (chan->channel2) {
+			case IIO_MOD_RUNNING:
+				st->activity_running = val;
+				return 0;
+			case IIO_MOD_WALKING:
+				st->activity_walking = val;
+				return 0;
+			default:
+				return -EINVAL;
+			}
+			break;
+		default:
+			return -EINVAL;
+		}
 	case IIO_CHAN_INFO_CALIBSCALE:
 		mutex_lock(&st->lock);
 		/* Compare against table - hard matching here */
@@ -356,6 +501,24 @@
 		st->accel_calibbias = val;
 		mutex_unlock(&st->lock);
 		return 0;
+	case IIO_CHAN_INFO_ENABLE:
+		switch (chan->type) {
+		case IIO_STEPS:
+			mutex_lock(&st->lock);
+			st->steps_enabled = val;
+			mutex_unlock(&st->lock);
+			return 0;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_CALIBHEIGHT:
+		switch (chan->type) {
+		case IIO_STEPS:
+			st->height = val;
+			return 0;
+		default:
+			return -EINVAL;
+		}
 
 	default:
 		return -EINVAL;
@@ -395,6 +558,9 @@
 	st->accel_val = 34;
 	st->accel_calibbias = -7;
 	st->accel_calibscale = &dummy_scales[0];
+	st->steps = 47;
+	st->activity_running = 98;
+	st->activity_walking = 4;
 
 	return 0;
 }
@@ -475,13 +641,7 @@
 	if (ret < 0)
 		goto error_free_device;
 
-	/*
-	 * Configure buffered capture support and register the channels with the
-	 * buffer, but avoid the output channel being registered by reducing the
-	 * number of channels by 1.
-	 */
-	ret = iio_simple_dummy_configure_buffer(indio_dev,
-						iio_dummy_channels, 5);
+	ret = iio_simple_dummy_configure_buffer(indio_dev);
 	if (ret < 0)
 		goto error_unregister_events;
 
diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h
index 3027aed..34989bf 100644
--- a/drivers/staging/iio/iio_simple_dummy.h
+++ b/drivers/staging/iio/iio_simple_dummy.h
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 
 struct iio_dummy_accel_calibscale;
+struct iio_dummy_regs;
 
 /**
  * struct iio_dummy_state - device instance specific state.
@@ -33,8 +34,14 @@
 	int differential_adc_val[2];
 	int accel_val;
 	int accel_calibbias;
+	int activity_running;
+	int activity_walking;
 	const struct iio_dummy_accel_calibscale *accel_calibscale;
 	struct mutex lock;
+	struct iio_dummy_regs *regs;
+	int steps_enabled;
+	int steps;
+	int height;
 #ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
 	int event_irq;
 	int event_val;
@@ -107,12 +114,10 @@
 };
 
 #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *channels, unsigned int num_channels);
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
 #else
-static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *channels, unsigned int num_channels)
+static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
 {
 	return 0;
 };
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index fd74f91..360a4c9 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -115,14 +115,13 @@
 	.predisable = &iio_triggered_buffer_predisable,
 };
 
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
-	const struct iio_chan_spec *channels, unsigned int num_channels)
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
 {
 	int ret;
 	struct iio_buffer *buffer;
 
 	/* Allocate a buffer to use - here a kfifo */
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (buffer == NULL) {
 		ret = -ENOMEM;
 		goto error_ret;
@@ -173,14 +172,8 @@
 	 */
 	indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
 
-	ret = iio_buffer_register(indio_dev, channels, num_channels);
-	if (ret)
-		goto error_dealloc_pollfunc;
-
 	return 0;
 
-error_dealloc_pollfunc:
-	iio_dealloc_pollfunc(indio_dev->pollfunc);
 error_free_buffer:
 	iio_kfifo_free(indio_dev->buffer);
 error_ret:
@@ -194,7 +187,6 @@
  */
 void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
 {
-	iio_buffer_unregister(indio_dev);
 	iio_dealloc_pollfunc(indio_dev->pollfunc);
 	iio_kfifo_free(indio_dev->buffer);
 }
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index 64b45b0..a5cd3bb 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -72,6 +72,22 @@
 				st->event_en = state;
 			else
 				return -EINVAL;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_ACTIVITY:
+		switch (type) {
+		case IIO_EV_TYPE_THRESH:
+			st->event_en = state;
+			break;
+		default:
+			return -EINVAL;
+		}
+	case IIO_STEPS:
+		switch (type) {
+		case IIO_EV_TYPE_CHANGE:
+			st->event_en = state;
 			break;
 		default:
 			return -EINVAL;
@@ -148,12 +164,50 @@
 static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
+	struct iio_dummy_state *st = iio_priv(indio_dev);
 
-	iio_push_event(indio_dev,
-		       IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
-				      IIO_EV_DIR_RISING,
-				      IIO_EV_TYPE_THRESH, 0, 0, 0),
-		       iio_get_time_ns());
+	dev_dbg(&indio_dev->dev, "id %x event %x\n",
+		st->regs->reg_id, st->regs->reg_data);
+
+	switch (st->regs->reg_data) {
+	case 0:
+		iio_push_event(indio_dev,
+			       IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
+					      IIO_EV_DIR_RISING,
+					      IIO_EV_TYPE_THRESH, 0, 0, 0),
+			       iio_get_time_ns());
+		break;
+	case 1:
+		if (st->activity_running > st->event_val)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+						      IIO_MOD_RUNNING,
+						      IIO_EV_DIR_RISING,
+						      IIO_EV_TYPE_THRESH,
+						      0, 0, 0),
+				       iio_get_time_ns());
+		break;
+	case 2:
+		if (st->activity_walking < st->event_val)
+			iio_push_event(indio_dev,
+				       IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+						      IIO_MOD_WALKING,
+						      IIO_EV_DIR_FALLING,
+						      IIO_EV_TYPE_THRESH,
+						      0, 0, 0),
+				       iio_get_time_ns());
+		break;
+	case 3:
+		iio_push_event(indio_dev,
+			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+					      IIO_EV_DIR_NONE,
+					      IIO_EV_TYPE_CHANGE, 0, 0, 0),
+			       iio_get_time_ns());
+		break;
+	default:
+		break;
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -179,6 +233,8 @@
 		ret = st->event_irq;
 		goto error_ret;
 	}
+	st->regs = iio_dummy_evgen_get_regs(st->event_irq);
+
 	ret = request_threaded_irq(st->event_irq,
 				   NULL,
 				   &iio_simple_dummy_event_handler,
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index b6bd609..7919439 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -89,7 +89,6 @@
 struct ad5933_state {
 	struct i2c_client		*client;
 	struct regulator		*reg;
-	struct ad5933_platform_data	*pdata;
 	struct delayed_work		work;
 	unsigned long			mclk_hz;
 	unsigned char			ctrl_hb;
@@ -113,7 +112,8 @@
 		.type = IIO_TEMP,
 		.indexed = 1,
 		.channel = 0,
-		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
 		.address = AD5933_REG_TEMP_DATA,
 		.scan_index = -1,
 		.scan_type = {
@@ -360,11 +360,11 @@
 	mutex_lock(&indio_dev->mlock);
 	switch ((u32) this_attr->address) {
 	case AD5933_OUT_RANGE:
-		len = sprintf(buf, "%d\n",
+		len = sprintf(buf, "%u\n",
 			      st->range_avail[(st->ctrl_hb >> 1) & 0x3]);
 		break;
 	case AD5933_OUT_RANGE_AVAIL:
-		len = sprintf(buf, "%d %d %d %d\n", st->range_avail[0],
+		len = sprintf(buf, "%u %u %u %u\n", st->range_avail[0],
 			      st->range_avail[3], st->range_avail[2],
 			      st->range_avail[1]);
 		break;
@@ -520,12 +520,11 @@
 {
 	struct ad5933_state *st = iio_priv(indio_dev);
 	__be16 dat;
-	int ret = -EINVAL;
+	int ret;
 
-	mutex_lock(&indio_dev->mlock);
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-	case IIO_CHAN_INFO_PROCESSED:
+		mutex_lock(&indio_dev->mlock);
 		if (iio_buffer_enabled(indio_dev)) {
 			ret = -EBUSY;
 			goto out;
@@ -543,16 +542,16 @@
 		if (ret < 0)
 			goto out;
 		mutex_unlock(&indio_dev->mlock);
-		ret = be16_to_cpu(dat);
-		/* Temp in Milli degrees Celsius */
-		if (ret < 8192)
-			*val = ret * 1000 / 32;
-		else
-			*val = (ret - 16384) * 1000 / 32;
+		*val = sign_extend32(be16_to_cpu(dat), 13);
 
 		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 1000;
+		*val2 = 5;
+		return IIO_VAL_FRACTIONAL_LOG2;
 	}
 
+	return -EINVAL;
 out:
 	mutex_unlock(&indio_dev->mlock);
 	return ret;
@@ -626,7 +625,7 @@
 {
 	struct iio_buffer *buffer;
 
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (!buffer)
 		return -ENOMEM;
 
@@ -712,9 +711,7 @@
 	st->client = client;
 
 	if (!pdata)
-		st->pdata = &ad5933_default_pdata;
-	else
-		st->pdata = pdata;
+		pdata = &ad5933_default_pdata;
 
 	st->reg = devm_regulator_get(&client->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
@@ -727,10 +724,10 @@
 	if (voltage_uv)
 		st->vref_mv = voltage_uv / 1000;
 	else
-		st->vref_mv = st->pdata->vref_mv;
+		st->vref_mv = pdata->vref_mv;
 
-	if (st->pdata->ext_clk_Hz) {
-		st->mclk_hz = st->pdata->ext_clk_Hz;
+	if (pdata->ext_clk_Hz) {
+		st->mclk_hz = pdata->ext_clk_Hz;
 		st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK;
 	} else {
 		st->mclk_hz = AD5933_INT_OSC_FREQ_Hz;
@@ -752,27 +749,16 @@
 	if (ret)
 		goto error_disable_reg;
 
-	ret = iio_buffer_register(indio_dev, ad5933_channels,
-		ARRAY_SIZE(ad5933_channels));
+	ret = ad5933_setup(st);
 	if (ret)
 		goto error_unreg_ring;
 
-	/* enable both REAL and IMAG channels by default */
-	iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
-	iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
-
-	ret = ad5933_setup(st);
-	if (ret)
-		goto error_uninitialize_ring;
-
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_uninitialize_ring;
+		goto error_unreg_ring;
 
 	return 0;
 
-error_uninitialize_ring:
-	iio_buffer_unregister(indio_dev);
 error_unreg_ring:
 	iio_kfifo_free(indio_dev->buffer);
 error_disable_reg:
@@ -788,7 +774,6 @@
 	struct ad5933_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	iio_buffer_unregister(indio_dev);
 	iio_kfifo_free(indio_dev->buffer);
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index e969107..6440e3b 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -537,8 +537,8 @@
 MODULE_DEVICE_TABLE(i2c, isl29028_id);
 
 static const struct of_device_id isl29028_of_match[] = {
-	{ .compatible = "isl,isl29028", },
-	{ .compatible = "isil,isl29028", },/* deprecated, don't use */
+	{ .compatible = "isl,isl29028", }, /* for backward compat., don't use */
+	{ .compatible = "isil,isl29028", },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, isl29028_of_match);
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index cc4ddcc..8afae8e 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -692,7 +692,7 @@
 	int offset = 0;
 
 	for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) {
-		offset += sprintf(buf + offset, "%d,%d,%d,",
+		offset += sprintf(buf + offset, "%u,%u,%u,",
 				  taos_device_lux[i].ratio,
 				  taos_device_lux[i].ch0,
 				  taos_device_lux[i].ch1);
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index 423f96b..4a5dc26 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -1147,7 +1147,7 @@
 	int offset = 0;
 
 	while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
-		offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
+		offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
 			chip->tsl2x7x_device_lux[i].ratio,
 			chip->tsl2x7x_device_lux[i].ch0,
 			chip->tsl2x7x_device_lux[i].ch1);
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
index e8c98cf..f6739e2 100644
--- a/drivers/staging/iio/meter/ade7758.h
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -145,7 +145,6 @@
 int ade7758_configure_ring(struct iio_dev *indio_dev);
 void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
 
-void ade7758_uninitialize_ring(struct iio_dev *indio_dev);
 int ade7758_set_irq(struct device *dev, bool enable);
 
 int ade7758_spi_write_reg_8(struct device *dev,
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index fb373b8..70e96b2 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -850,23 +850,15 @@
 	if (ret)
 		goto error_free_tx;
 
-	ret = iio_buffer_register(indio_dev,
-				  &ade7758_channels[0],
-				  ARRAY_SIZE(ade7758_channels));
-	if (ret) {
-		dev_err(&spi->dev, "failed to initialize the ring\n");
-		goto error_unreg_ring_funcs;
-	}
-
 	/* Get the device into a sane initial state */
 	ret = ade7758_initial_setup(indio_dev);
 	if (ret)
-		goto error_uninitialize_ring;
+		goto error_unreg_ring_funcs;
 
 	if (spi->irq) {
 		ret = ade7758_probe_trigger(indio_dev);
 		if (ret)
-			goto error_uninitialize_ring;
+			goto error_unreg_ring_funcs;
 	}
 
 	ret = iio_device_register(indio_dev);
@@ -878,8 +870,6 @@
 error_remove_trigger:
 	if (spi->irq)
 		ade7758_remove_trigger(indio_dev);
-error_uninitialize_ring:
-	ade7758_uninitialize_ring(indio_dev);
 error_unreg_ring_funcs:
 	ade7758_unconfigure_ring(indio_dev);
 error_free_tx:
@@ -897,7 +887,6 @@
 	iio_device_unregister(indio_dev);
 	ade7758_stop_device(&indio_dev->dev);
 	ade7758_remove_trigger(indio_dev);
-	ade7758_uninitialize_ring(indio_dev);
 	ade7758_unconfigure_ring(indio_dev);
 	kfree(st->tx);
 	kfree(st->rx);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 6e90064..3792b57 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -118,7 +118,7 @@
 	struct iio_buffer *buffer;
 	int ret = 0;
 
-	buffer = iio_kfifo_allocate(indio_dev);
+	buffer = iio_kfifo_allocate();
 	if (!buffer) {
 		ret = -ENOMEM;
 		return ret;
@@ -180,8 +180,3 @@
 	iio_kfifo_free(indio_dev->buffer);
 	return ret;
 }
-
-void ade7758_uninitialize_ring(struct iio_dev *indio_dev)
-{
-	iio_buffer_unregister(indio_dev);
-}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 7d21743..b0c7dbc 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -116,7 +116,7 @@
 
 	mutex_lock(&st->buf_lock);
 	st->tx[0] = ADE7759_READ_REG(reg_address);
-	memset(&st->tx[1], 0 , 5);
+	memset(&st->tx[1], 0, 5);
 
 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
 	if (ret) {
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index a6b2f90..4410d7f 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -85,6 +85,9 @@
 
 #include <linux/list.h>
 
+int libcfs_arch_init(void);
+void libcfs_arch_cleanup(void);
+
 /* libcfs tcpip */
 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask);
 int libcfs_ipif_enumerate(char ***names);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index 375586b..808e494 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -454,25 +454,23 @@
 	       hs->hs_extra_bytes;
 }
 
-#define CFS_HOP(hs, op)	   (hs)->hs_ops->hs_ ## op
-
 static inline unsigned
 cfs_hash_id(struct cfs_hash *hs, const void *key, unsigned mask)
 {
-	return CFS_HOP(hs, hash)(hs, key, mask);
+	return hs->hs_ops->hs_hash(hs, key, mask);
 }
 
 static inline void *
 cfs_hash_key(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	return CFS_HOP(hs, key)(hnode);
+	return hs->hs_ops->hs_key(hnode);
 }
 
 static inline void
 cfs_hash_keycpy(struct cfs_hash *hs, struct hlist_node *hnode, void *key)
 {
-	if (CFS_HOP(hs, keycpy) != NULL)
-		CFS_HOP(hs, keycpy)(hnode, key);
+        if (hs->hs_ops->hs_keycpy)
+		hs->hs_ops->hs_keycpy(hnode, key);
 }
 
 /**
@@ -481,42 +479,38 @@
 static inline int
 cfs_hash_keycmp(struct cfs_hash *hs, const void *key, struct hlist_node *hnode)
 {
-	return CFS_HOP(hs, keycmp)(key, hnode);
+	return hs->hs_ops->hs_keycmp(key, hnode);
 }
 
 static inline void *
 cfs_hash_object(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	return CFS_HOP(hs, object)(hnode);
+	return hs->hs_ops->hs_object(hnode);
 }
 
 static inline void
 cfs_hash_get(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	return CFS_HOP(hs, get)(hs, hnode);
+	return hs->hs_ops->hs_get(hs, hnode);
 }
 
 static inline void
 cfs_hash_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	LASSERT(CFS_HOP(hs, put_locked) != NULL);
-
-	return CFS_HOP(hs, put_locked)(hs, hnode);
+	return hs->hs_ops->hs_put_locked(hs, hnode);
 }
 
 static inline void
 cfs_hash_put(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	LASSERT(CFS_HOP(hs, put) != NULL);
-
-	return CFS_HOP(hs, put)(hs, hnode);
+	return hs->hs_ops->hs_put(hs, hnode);
 }
 
 static inline void
 cfs_hash_exit(struct cfs_hash *hs, struct hlist_node *hnode)
 {
-	if (CFS_HOP(hs, exit))
-		CFS_HOP(hs, exit)(hs, hnode);
+	if (hs->hs_ops->hs_exit)
+		hs->hs_ops->hs_exit(hs, hnode);
 }
 
 static inline void cfs_hash_lock(struct cfs_hash *hs, int excl)
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
index 2817112..3d86fb5 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
@@ -458,14 +458,6 @@
 	struct page   *ldu_memhog_root_page;
 };
 
-/* what used to be in portals_lib.h */
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
 #define MKSTR(ptr) ((ptr)) ? (ptr) : ""
 
 static inline int cfs_size_round4(int val)
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
index 7e89b3b..0038d29 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
@@ -636,6 +636,7 @@
 }
 
 extern lnd_t the_lolnd;
+extern int avoid_asym_router_failure;
 
 int lnet_cpt_of_nid_locked(lnet_nid_t nid);
 int lnet_cpt_of_nid(lnet_nid_t nid);
@@ -752,9 +753,9 @@
 void lnet_counters_get(lnet_counters_t *counters);
 void lnet_counters_reset(void);
 
-unsigned int lnet_iov_nob(unsigned int niov, struct iovec *iov);
-int lnet_extract_iov(int dst_niov, struct iovec *dst,
-		     int src_niov, struct iovec *src,
+unsigned int lnet_iov_nob(unsigned int niov, struct kvec *iov);
+int lnet_extract_iov(int dst_niov, struct kvec *dst,
+		     int src_niov, struct kvec *src,
 		      unsigned int offset, unsigned int len);
 
 unsigned int lnet_kiov_nob(unsigned int niov, lnet_kiov_t *iov);
@@ -762,17 +763,17 @@
 		      int src_niov, lnet_kiov_t *src,
 		      unsigned int offset, unsigned int len);
 
-void lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov,
+void lnet_copy_iov2iov(unsigned int ndiov, struct kvec *diov,
 		       unsigned int doffset,
-			unsigned int nsiov, struct iovec *siov,
+			unsigned int nsiov, struct kvec *siov,
 			unsigned int soffset, unsigned int nob);
-void lnet_copy_kiov2iov(unsigned int niov, struct iovec *iov,
+void lnet_copy_kiov2iov(unsigned int niov, struct kvec *iov,
 			unsigned int iovoffset,
 			 unsigned int nkiov, lnet_kiov_t *kiov,
 			 unsigned int kiovoffset, unsigned int nob);
 void lnet_copy_iov2kiov(unsigned int nkiov, lnet_kiov_t *kiov,
 			unsigned int kiovoffset,
-			 unsigned int niov, struct iovec *iov,
+			 unsigned int niov, struct kvec *iov,
 			 unsigned int iovoffset, unsigned int nob);
 void lnet_copy_kiov2kiov(unsigned int ndkiov, lnet_kiov_t *dkiov,
 			 unsigned int doffset,
@@ -781,10 +782,10 @@
 
 static inline void
 lnet_copy_iov2flat(int dlen, void *dest, unsigned int doffset,
-		   unsigned int nsiov, struct iovec *siov, unsigned int soffset,
+		   unsigned int nsiov, struct kvec *siov, unsigned int soffset,
 		   unsigned int nob)
 {
-	struct iovec diov = {/*.iov_base = */ dest, /*.iov_len = */ dlen};
+	struct kvec diov = {/*.iov_base = */ dest, /*.iov_len = */ dlen};
 
 	lnet_copy_iov2iov(1, &diov, doffset,
 			  nsiov, siov, soffset, nob);
@@ -795,17 +796,17 @@
 		    unsigned int nsiov, lnet_kiov_t *skiov,
 		    unsigned int soffset, unsigned int nob)
 {
-	struct iovec diov = {/* .iov_base = */ dest, /* .iov_len = */ dlen};
+	struct kvec diov = {/* .iov_base = */ dest, /* .iov_len = */ dlen};
 
 	lnet_copy_kiov2iov(1, &diov, doffset,
 			   nsiov, skiov, soffset, nob);
 }
 
 static inline void
-lnet_copy_flat2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
+lnet_copy_flat2iov(unsigned int ndiov, struct kvec *diov, unsigned int doffset,
 		   int slen, void *src, unsigned int soffset, unsigned int nob)
 {
-	struct iovec siov = {/*.iov_base = */ src, /*.iov_len = */slen};
+	struct kvec siov = {/*.iov_base = */ src, /*.iov_len = */slen};
 
 	lnet_copy_iov2iov(ndiov, diov, doffset,
 			  1, &siov, soffset, nob);
@@ -816,7 +817,7 @@
 		    unsigned int doffset, int slen, void *src,
 		    unsigned int soffset, unsigned int nob)
 {
-	struct iovec siov = {/* .iov_base = */ src, /* .iov_len = */ slen};
+	struct kvec siov = {/* .iov_base = */ src, /* .iov_len = */ slen};
 
 	lnet_copy_iov2kiov(ndiov, dkiov, doffset,
 			   1, &siov, soffset, nob);
@@ -851,6 +852,7 @@
 
 int lnet_router_checker_start(void);
 void lnet_router_checker_stop(void);
+void lnet_router_ni_update_locked(lnet_peer_t *gw, __u32 net);
 void lnet_swap_pinginfo(lnet_ping_info_t *info);
 
 int lnet_ping_target_init(void);
@@ -870,4 +872,12 @@
 int lnet_peer_tables_create(void);
 void lnet_debug_peer(lnet_nid_t nid);
 
+static inline void lnet_peer_set_alive(lnet_peer_t *lp)
+{
+	lp->lp_last_alive = lp->lp_last_query = get_seconds();
+	if (!lp->lp_alive)
+		lnet_notify_locked(lp, 0, 1, lp->lp_last_alive);
+}
+
+
 #endif
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index f16213f..50537668 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -217,7 +217,7 @@
 	unsigned int	  msg_wanted;
 	unsigned int	  msg_offset;
 	unsigned int	  msg_niov;
-	struct iovec	 *msg_iov;
+	struct kvec	 *msg_iov;
 	lnet_kiov_t	  *msg_kiov;
 
 	lnet_event_t	  msg_ev;
@@ -271,7 +271,7 @@
 	lnet_eq_t	    *md_eq;
 	unsigned int	  md_niov;		/* # frags */
 	union {
-		struct iovec  iov[LNET_MAX_IOV];
+		struct kvec   iov[LNET_MAX_IOV];
 		lnet_kiov_t   kiov[LNET_MAX_IOV];
 	} md_iov;
 } lnet_libmd_t;
@@ -346,7 +346,7 @@
 	 * credit if the LND does flow control. */
 	int (*lnd_recv)(struct lnet_ni *ni, void *private, lnet_msg_t *msg,
 			int delayed, unsigned int niov,
-			struct iovec *iov, lnet_kiov_t *kiov,
+			struct kvec *iov, lnet_kiov_t *kiov,
 			unsigned int offset, unsigned int mlen, unsigned int rlen);
 
 	/* lnet_parse() has had to delay processing of this message
@@ -622,7 +622,7 @@
 	/* Match table for each CPT */
 	struct lnet_match_table	**ptl_mtables;
 	/* spread rotor of incoming "PUT" */
-	int			ptl_rotor;
+	unsigned int		ptl_rotor;
 	/* # active entries for this portal */
 	int		     ptl_mt_nmaps;
 	/* array of active entries' cpu-partition-id */
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 62b575d..6510169 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -1538,7 +1538,7 @@
 	fmr->fmr_pfmr = NULL;
 
 	spin_lock(&fps->fps_lock);
-	fpo->fpo_map_count --;  /* decref the pool */
+	fpo->fpo_map_count--;  /* decref the pool */
 
 	list_for_each_entry_safe(fpo, tmp, &fps->fps_pool_list, fpo_list) {
 		/* the first pool is persistent */
@@ -1547,7 +1547,7 @@
 
 		if (kiblnd_fmr_pool_is_idle(fpo, now)) {
 			list_move(&fpo->fpo_list, &zombies);
-			fps->fps_version ++;
+			fps->fps_version++;
 		}
 	}
 	spin_unlock(&fps->fps_lock);
@@ -1752,7 +1752,7 @@
 
 	LASSERT (pool->po_allocated > 0);
 	list_add(node, &pool->po_free_list);
-	pool->po_allocated --;
+	pool->po_allocated--;
 
 	list_for_each_entry_safe(pool, tmp, &ps->ps_pool_list, po_list) {
 		/* the first pool is persistent */
@@ -1781,7 +1781,7 @@
 		if (list_empty(&pool->po_free_list))
 			continue;
 
-		pool->po_allocated ++;
+		pool->po_allocated++;
 		pool->po_deadline = cfs_time_shift(IBLND_POOL_DEADLINE);
 		node = pool->po_free_list.next;
 		list_del(node);
@@ -1864,7 +1864,7 @@
 		return -EAGAIN;
 	}
 
-	for (i = 0; i < rd->rd_nfrags; i ++) {
+	for (i = 0; i < rd->rd_nfrags; i++) {
 		pmr->pmr_ipb[i].addr = rd->rd_frags[i].rf_addr;
 		pmr->pmr_ipb[i].size = rd->rd_frags[i].rf_nob;
 	}
@@ -2117,7 +2117,7 @@
 					     tps_poolset);
 	kib_tx_t	 *tx  = list_entry(node, kib_tx_t, tx_list);
 
-	tx->tx_cookie = tps->tps_next_tx_cookie ++;
+	tx->tx_cookie = tps->tps_next_tx_cookie++;
 }
 
 static void
@@ -2326,7 +2326,7 @@
 	}
 
 	for (hdev->ibh_mr_shift = 0;
-	     hdev->ibh_mr_shift < 64; hdev->ibh_mr_shift ++) {
+	     hdev->ibh_mr_shift < 64; hdev->ibh_mr_shift++) {
 		if (hdev->ibh_mr_size == (1ULL << hdev->ibh_mr_shift) ||
 		    hdev->ibh_mr_size == (1ULL << hdev->ibh_mr_shift) - 1)
 			return 0;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index b02b4ec..ab128de 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -1026,5 +1026,5 @@
 
 int  kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg);
 int  kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
-		 unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+		 unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
 		 unsigned int offset, unsigned int mlen, unsigned int rlen);
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index b48d7ed..48d885d 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -697,7 +697,7 @@
 
 static int
 kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd,
-		    unsigned int niov, struct iovec *iov, int offset, int nob)
+		    unsigned int niov, struct kvec *iov, int offset, int nob)
 {
 	kib_net_t	  *net = ni->ni_data;
 	struct page	*page;
@@ -1125,8 +1125,9 @@
 			break;
 		}
 
-		wrknob = MIN(MIN(kiblnd_rd_frag_size(srcrd, srcidx),
-				 kiblnd_rd_frag_size(dstrd, dstidx)), resid);
+		wrknob = min(min(kiblnd_rd_frag_size(srcrd, srcidx),
+				 kiblnd_rd_frag_size(dstrd, dstidx)),
+			     (__u32) resid);
 
 		sge = &tx->tx_sge[tx->tx_nwrq];
 		sge->addr   = kiblnd_rd_frag_addr(srcrd, srcidx);
@@ -1461,7 +1462,7 @@
 	int	       target_is_router = lntmsg->msg_target_is_router;
 	int	       routing = lntmsg->msg_routing;
 	unsigned int      payload_niov = lntmsg->msg_niov;
-	struct iovec     *payload_iov = lntmsg->msg_iov;
+	struct kvec      *payload_iov = lntmsg->msg_iov;
 	lnet_kiov_t      *payload_kiov = lntmsg->msg_kiov;
 	unsigned int      payload_offset = lntmsg->msg_offset;
 	unsigned int      payload_nob = lntmsg->msg_len;
@@ -1628,7 +1629,7 @@
 {
 	lnet_process_id_t target = lntmsg->msg_target;
 	unsigned int      niov = lntmsg->msg_niov;
-	struct iovec     *iov = lntmsg->msg_iov;
+	struct kvec      *iov = lntmsg->msg_iov;
 	lnet_kiov_t      *kiov = lntmsg->msg_kiov;
 	unsigned int      offset = lntmsg->msg_offset;
 	unsigned int      nob = lntmsg->msg_len;
@@ -1687,7 +1688,7 @@
 
 int
 kiblnd_recv (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
-	     unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+	     unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
 	     unsigned int offset, unsigned int mlen, unsigned int rlen)
 {
 	kib_rx_t    *rx = private;
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index 9188b34..5956dba 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -773,7 +773,7 @@
 	/* Only match interfaces for additional connections
 	 * if I have > 1 interface */
 	n_ips = (net->ksnn_ninterfaces < 2) ? 0 :
-		MIN(n_peerips, net->ksnn_ninterfaces);
+		min(n_peerips, net->ksnn_ninterfaces);
 
 	for (i = 0; peer->ksnp_n_passive_ips < n_ips; i++) {
 		/*	      ^ yes really... */
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
index a29d4da..03488d2 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
@@ -69,7 +69,7 @@
 	int			kss_nconns;
 	struct ksock_sched_info	*kss_info;	/* owner of it */
 	struct page		*kss_rx_scratch_pgs[LNET_MAX_IOV];
-	struct iovec		kss_scratch_iov[LNET_MAX_IOV];
+	struct kvec		kss_scratch_iov[LNET_MAX_IOV];
 } ksock_sched_t;
 
 struct ksock_sched_info {
@@ -213,7 +213,7 @@
 	int	    tx_nob;	 /* # packet bytes */
 	int	    tx_resid;       /* residual bytes */
 	int	    tx_niov;	/* # packet iovec frags */
-	struct iovec  *tx_iov;	 /* packet iovec frags */
+	struct kvec  *tx_iov;	 /* packet iovec frags */
 	int	    tx_nkiov;       /* # packet page frags */
 	unsigned short tx_zc_aborted;  /* aborted ZC request */
 	unsigned short tx_zc_capable:1; /* payload is large enough for ZC */
@@ -227,11 +227,11 @@
 	int	    tx_desc_size;   /* size of this descriptor */
 	union {
 		struct {
-			struct iovec iov;       /* virt hdr */
+			struct kvec iov;       /* virt hdr */
 			lnet_kiov_t  kiov[0];   /* paged payload */
 		}		  paged;
 		struct {
-			struct iovec iov[1];    /* virt hdr + payload */
+			struct kvec iov[1];    /* virt hdr + payload */
 		}		  virt;
 	}		       tx_frags;
 } ksock_tx_t;
@@ -243,7 +243,7 @@
 /* space for the rx frag descriptors; we either read a single contiguous
  * header, or up to LNET_MAX_IOV frags of payload of either type. */
 typedef union {
-	struct iovec     iov[LNET_MAX_IOV];
+	struct kvec      iov[LNET_MAX_IOV];
 	lnet_kiov_t      kiov[LNET_MAX_IOV];
 } ksock_rxiovspace_t;
 
@@ -284,7 +284,7 @@
 	int		   ksnc_rx_nob_left; /* # bytes to next hdr/body */
 	int		   ksnc_rx_nob_wanted; /* bytes actually wanted */
 	int		   ksnc_rx_niov;     /* # iovec frags */
-	struct iovec	 *ksnc_rx_iov;      /* the iovec frags */
+	struct kvec 	 *ksnc_rx_iov;      /* the iovec frags */
 	int		   ksnc_rx_nkiov;    /* # page frags */
 	lnet_kiov_t	  *ksnc_rx_kiov;     /* the page frags */
 	ksock_rxiovspace_t    ksnc_rx_iov_space;/* space for frag descriptors */
@@ -517,7 +517,7 @@
 int ksocknal_send (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg);
 int ksocknal_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg,
 		  int delayed, unsigned int niov,
-		  struct iovec *iov, lnet_kiov_t *kiov,
+		  struct kvec *iov, lnet_kiov_t *kiov,
 		  unsigned int offset, unsigned int mlen, unsigned int rlen);
 int ksocknal_accept(lnet_ni_t *ni, struct socket *sock);
 
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index e6c1d36..92760fe 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -110,7 +110,7 @@
 static int
 ksocknal_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
 {
-	struct iovec  *iov = tx->tx_iov;
+	struct kvec  *iov = tx->tx_iov;
 	int    nob;
 	int    rc;
 
@@ -251,7 +251,7 @@
 static int
 ksocknal_recv_iov (ksock_conn_t *conn)
 {
-	struct iovec *iov = conn->ksnc_rx_iov;
+	struct kvec *iov = conn->ksnc_rx_iov;
 	int     nob;
 	int     rc;
 
@@ -926,7 +926,7 @@
 	int	       type = lntmsg->msg_type;
 	lnet_process_id_t target = lntmsg->msg_target;
 	unsigned int      payload_niov = lntmsg->msg_niov;
-	struct iovec     *payload_iov = lntmsg->msg_iov;
+	struct kvec      *payload_iov = lntmsg->msg_iov;
 	lnet_kiov_t      *payload_kiov = lntmsg->msg_kiov;
 	unsigned int      payload_offset = lntmsg->msg_offset;
 	unsigned int      payload_nob = lntmsg->msg_len;
@@ -1047,8 +1047,8 @@
 		case  KSOCK_PROTO_V2:
 		case  KSOCK_PROTO_V3:
 			conn->ksnc_rx_state = SOCKNAL_RX_KSM_HEADER;
-			conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
-			conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg;
+			conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+			conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg;
 
 			conn->ksnc_rx_nob_wanted = offsetof(ksock_msg_t, ksm_u);
 			conn->ksnc_rx_nob_left = offsetof(ksock_msg_t, ksm_u);
@@ -1061,8 +1061,8 @@
 			conn->ksnc_rx_nob_wanted = sizeof(lnet_hdr_t);
 			conn->ksnc_rx_nob_left = sizeof(lnet_hdr_t);
 
-			conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
-			conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg.ksm_u.lnetmsg;
+			conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+			conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg.ksm_u.lnetmsg;
 			conn->ksnc_rx_iov[0].iov_len  = sizeof (lnet_hdr_t);
 			break;
 
@@ -1082,12 +1082,12 @@
 
 	conn->ksnc_rx_state = SOCKNAL_RX_SLOP;
 	conn->ksnc_rx_nob_left = nob_to_skip;
-	conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
+	conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
 	skipped = 0;
 	niov = 0;
 
 	do {
-		nob = MIN (nob_to_skip, sizeof (ksocknal_slop_buffer));
+		nob = min_t(int, nob_to_skip, sizeof(ksocknal_slop_buffer));
 
 		conn->ksnc_rx_iov[niov].iov_base = ksocknal_slop_buffer;
 		conn->ksnc_rx_iov[niov].iov_len  = nob;
@@ -1212,8 +1212,8 @@
 		conn->ksnc_rx_nob_wanted = sizeof(ksock_lnet_msg_t);
 		conn->ksnc_rx_nob_left = sizeof(ksock_lnet_msg_t);
 
-		conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
-		conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg.ksm_u.lnetmsg;
+		conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+		conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg.ksm_u.lnetmsg;
 		conn->ksnc_rx_iov[0].iov_len  = sizeof(ksock_lnet_msg_t);
 
 		conn->ksnc_rx_niov = 1;
@@ -1311,7 +1311,7 @@
 
 int
 ksocknal_recv (lnet_ni_t *ni, void *private, lnet_msg_t *msg, int delayed,
-	       unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+	       unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
 	       unsigned int offset, unsigned int mlen, unsigned int rlen)
 {
 	ksock_conn_t  *conn = (ksock_conn_t *)private;
@@ -1950,10 +1950,10 @@
 	/* This is a retry rather than a new connection */
 	route->ksnr_retry_interval *= 2;
 	route->ksnr_retry_interval =
-		MAX(route->ksnr_retry_interval,
+		max(route->ksnr_retry_interval,
 		    cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms)/1000);
 	route->ksnr_retry_interval =
-		MIN(route->ksnr_retry_interval,
+		min(route->ksnr_retry_interval,
 		    cfs_time_seconds(*ksocknal_tunables.ksnd_max_reconnectms)/1000);
 
 	LASSERT (route->ksnr_retry_interval != 0);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
index 245c9d7..66cc509 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
@@ -92,11 +92,11 @@
 
 	{
 #if SOCKNAL_SINGLE_FRAG_TX
-		struct iovec    scratch;
-		struct iovec   *scratchiov = &scratch;
+		struct kvec    scratch;
+		struct kvec   *scratchiov = &scratch;
 		unsigned int    niov = 1;
 #else
-		struct iovec   *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+		struct kvec   *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
 		unsigned int    niov = tx->tx_niov;
 #endif
 		struct msghdr msg = {.msg_flags = MSG_DONTWAIT};
@@ -111,7 +111,7 @@
 		    nob < tx->tx_resid)
 			msg.msg_flags |= MSG_MORE;
 
-		rc = kernel_sendmsg(sock, &msg, (struct kvec *)scratchiov, niov, nob);
+		rc = kernel_sendmsg(sock, &msg, scratchiov, niov, nob);
 	}
 	return rc;
 }
@@ -153,14 +153,14 @@
 		}
 	} else {
 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK
-		struct iovec  scratch;
-		struct iovec *scratchiov = &scratch;
+		struct kvec  scratch;
+		struct kvec *scratchiov = &scratch;
 		unsigned int  niov = 1;
 #else
 #ifdef CONFIG_HIGHMEM
 #warning "XXX risk of kmap deadlock on multiple frags..."
 #endif
-		struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+		struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
 		unsigned int  niov = tx->tx_nkiov;
 #endif
 		struct msghdr msg = {.msg_flags = MSG_DONTWAIT};
@@ -203,14 +203,14 @@
 ksocknal_lib_recv_iov (ksock_conn_t *conn)
 {
 #if SOCKNAL_SINGLE_FRAG_RX
-	struct iovec  scratch;
-	struct iovec *scratchiov = &scratch;
+	struct kvec  scratch;
+	struct kvec *scratchiov = &scratch;
 	unsigned int  niov = 1;
 #else
-	struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+	struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
 	unsigned int  niov = conn->ksnc_rx_niov;
 #endif
-	struct iovec *iov = conn->ksnc_rx_iov;
+	struct kvec *iov = conn->ksnc_rx_iov;
 	struct msghdr msg = {
 		.msg_flags      = 0
 	};
@@ -232,7 +232,7 @@
 	LASSERT (nob <= conn->ksnc_rx_nob_wanted);
 
 	rc = kernel_recvmsg(conn->ksnc_sock, &msg,
-		(struct kvec *)scratchiov, niov, nob, MSG_DONTWAIT);
+		scratchiov, niov, nob, MSG_DONTWAIT);
 
 	saved_csum = 0;
 	if (conn->ksnc_proto == &ksocknal_protocol_v2x) {
@@ -269,7 +269,7 @@
 
 static void *
 ksocknal_lib_kiov_vmap(lnet_kiov_t *kiov, int niov,
-		       struct iovec *iov, struct page **pages)
+		       struct kvec *iov, struct page **pages)
 {
 	void	     *addr;
 	int	       nob;
@@ -307,15 +307,15 @@
 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
 {
 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK
-	struct iovec   scratch;
-	struct iovec  *scratchiov = &scratch;
+	struct kvec   scratch;
+	struct kvec  *scratchiov = &scratch;
 	struct page  **pages      = NULL;
 	unsigned int   niov       = 1;
 #else
 #ifdef CONFIG_HIGHMEM
 #warning "XXX risk of kmap deadlock on multiple frags..."
 #endif
-	struct iovec  *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+	struct kvec  *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
 	struct page  **pages      = conn->ksnc_scheduler->kss_rx_scratch_pgs;
 	unsigned int   niov       = conn->ksnc_rx_nkiov;
 #endif
@@ -390,13 +390,13 @@
 	__u32	csum;
 	void	*base;
 
-	LASSERT(tx->tx_iov[0].iov_base == (void *)&tx->tx_msg);
+	LASSERT(tx->tx_iov[0].iov_base == &tx->tx_msg);
 	LASSERT(tx->tx_conn != NULL);
 	LASSERT(tx->tx_conn->ksnc_proto == &ksocknal_protocol_v2x);
 
 	tx->tx_msg.ksm_csum = 0;
 
-	csum = ksocknal_csum(~0, (void *)tx->tx_iov[0].iov_base,
+	csum = ksocknal_csum(~0, tx->tx_iov[0].iov_base,
 			     tx->tx_iov[0].iov_len);
 
 	if (tx->tx_kiov != NULL) {
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
index ea9d80f..b2f88eb 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
@@ -717,7 +717,7 @@
 	LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP);
 	LASSERT(tx->tx_lnetmsg != NULL);
 
-	tx->tx_iov[0].iov_base = (void *)&tx->tx_lnetmsg->msg_hdr;
+	tx->tx_iov[0].iov_base = &tx->tx_lnetmsg->msg_hdr;
 	tx->tx_iov[0].iov_len  = sizeof(lnet_hdr_t);
 
 	tx->tx_resid = tx->tx_nob = tx->tx_lnetmsg->msg_len + sizeof(lnet_hdr_t);
@@ -726,7 +726,7 @@
 static void
 ksocknal_pack_msg_v2(ksock_tx_t *tx)
 {
-	tx->tx_iov[0].iov_base = (void *)&tx->tx_msg;
+	tx->tx_iov[0].iov_base = &tx->tx_msg;
 
 	if (tx->tx_lnetmsg != NULL) {
 		LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP);
diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c
index c8c1ed8..0f53c76 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-move.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-move.c
@@ -158,7 +158,7 @@
 }
 
 unsigned int
-lnet_iov_nob(unsigned int niov, struct iovec *iov)
+lnet_iov_nob(unsigned int niov, struct kvec *iov)
 {
 	unsigned int nob = 0;
 
@@ -170,8 +170,8 @@
 EXPORT_SYMBOL(lnet_iov_nob);
 
 void
-lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
-		   unsigned int nsiov, struct iovec *siov, unsigned int soffset,
+lnet_copy_iov2iov(unsigned int ndiov, struct kvec *diov, unsigned int doffset,
+		   unsigned int nsiov, struct kvec *siov, unsigned int soffset,
 		   unsigned int nob)
 {
 	/* NB diov, siov are READ-ONLY */
@@ -201,9 +201,9 @@
 	do {
 		LASSERT(ndiov > 0);
 		LASSERT(nsiov > 0);
-		this_nob = MIN(diov->iov_len - doffset,
+		this_nob = min(diov->iov_len - doffset,
 			       siov->iov_len - soffset);
-		this_nob = MIN(this_nob, nob);
+		this_nob = min(this_nob, nob);
 
 		memcpy((char *)diov->iov_base + doffset,
 			(char *)siov->iov_base + soffset, this_nob);
@@ -229,8 +229,8 @@
 EXPORT_SYMBOL(lnet_copy_iov2iov);
 
 int
-lnet_extract_iov(int dst_niov, struct iovec *dst,
-		  int src_niov, struct iovec *src,
+lnet_extract_iov(int dst_niov, struct kvec *dst,
+		  int src_niov, struct kvec *src,
 		  unsigned int offset, unsigned int len)
 {
 	/* Initialise 'dst' to the subset of 'src' starting at 'offset',
@@ -322,9 +322,9 @@
 	do {
 		LASSERT(ndiov > 0);
 		LASSERT(nsiov > 0);
-		this_nob = MIN(diov->kiov_len - doffset,
+		this_nob = min(diov->kiov_len - doffset,
 			       siov->kiov_len - soffset);
-		this_nob = MIN(this_nob, nob);
+		this_nob = min(this_nob, nob);
 
 		if (daddr == NULL)
 			daddr = ((char *)kmap(diov->kiov_page)) +
@@ -371,7 +371,7 @@
 EXPORT_SYMBOL(lnet_copy_kiov2kiov);
 
 void
-lnet_copy_kiov2iov(unsigned int niov, struct iovec *iov, unsigned int iovoffset,
+lnet_copy_kiov2iov(unsigned int niov, struct kvec *iov, unsigned int iovoffset,
 		   unsigned int nkiov, lnet_kiov_t *kiov,
 		   unsigned int kiovoffset, unsigned int nob)
 {
@@ -403,9 +403,9 @@
 	do {
 		LASSERT(niov > 0);
 		LASSERT(nkiov > 0);
-		this_nob = MIN(iov->iov_len - iovoffset,
-			       kiov->kiov_len - kiovoffset);
-		this_nob = MIN(this_nob, nob);
+		this_nob = min(iov->iov_len - iovoffset,
+			       (__kernel_size_t) kiov->kiov_len - kiovoffset);
+		this_nob = min(this_nob, nob);
 
 		if (addr == NULL)
 			addr = ((char *)kmap(kiov->kiov_page)) +
@@ -443,7 +443,7 @@
 void
 lnet_copy_iov2kiov(unsigned int nkiov, lnet_kiov_t *kiov,
 		   unsigned int kiovoffset, unsigned int niov,
-		   struct iovec *iov, unsigned int iovoffset,
+		   struct kvec *iov, unsigned int iovoffset,
 		   unsigned int nob)
 {
 	/* NB kiov, iov are READ-ONLY */
@@ -474,9 +474,9 @@
 	do {
 		LASSERT(nkiov > 0);
 		LASSERT(niov > 0);
-		this_nob = MIN(kiov->kiov_len - kiovoffset,
+		this_nob = min((__kernel_size_t) kiov->kiov_len - kiovoffset,
 			       iov->iov_len - iovoffset);
-		this_nob = MIN(this_nob, nob);
+		this_nob = min(this_nob, nob);
 
 		if (addr == NULL)
 			addr = ((char *)kmap(kiov->kiov_page)) +
@@ -566,7 +566,7 @@
 	     unsigned int offset, unsigned int mlen, unsigned int rlen)
 {
 	unsigned int  niov = 0;
-	struct iovec *iov = NULL;
+	struct kvec *iov = NULL;
 	lnet_kiov_t  *kiov = NULL;
 	int	   rc;
 
@@ -1530,7 +1530,7 @@
 	LASSERT(md->md_offset == 0);
 
 	rlength = hdr->payload_length;
-	mlength = MIN(rlength, (int)md->md_length);
+	mlength = min_t(int, rlength, md->md_length);
 
 	if (mlength < rlength &&
 	    (md->md_options & LNET_MD_TRUNCATE) == 0) {
@@ -1877,6 +1877,19 @@
 		goto drop;
 	}
 
+	if (lnet_isrouter(msg->msg_rxpeer)) {
+		lnet_peer_set_alive(msg->msg_rxpeer);
+		if (avoid_asym_router_failure &&
+		    LNET_NIDNET(src_nid) != LNET_NIDNET(from_nid)) {
+			/* received a remote message from router, update
+			 * remote NI status on this router.
+			 * NB: multi-hop routed message will be ignored.
+			 */
+			lnet_router_ni_update_locked(msg->msg_rxpeer,
+						     LNET_NIDNET(src_nid));
+		}
+	}
+
 	lnet_msg_commit(msg, cpt);
 
 	if (!for_me) {
diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
index 19ed696..3ba0da9 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
@@ -262,10 +262,10 @@
 {
 	struct lnet_match_table	*mtable;
 	struct lnet_portal	*ptl;
-	int			nmaps;
-	int			rotor;
-	int			routed;
-	int			cpt;
+	unsigned int		nmaps;
+	unsigned int		rotor;
+	unsigned int		cpt;
+	bool			routed;
 
 	/* NB: called w/o lock */
 	LASSERT(info->mi_portal < the_lnet.ln_nportals);
diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c
index 17e1643..f708c2e 100644
--- a/drivers/staging/lustre/lnet/lnet/lo.c
+++ b/drivers/staging/lustre/lnet/lnet/lo.c
@@ -47,7 +47,7 @@
 static int
 lolnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg,
 	    int delayed, unsigned int niov,
-	    struct iovec *iov, lnet_kiov_t *kiov,
+	    struct kvec *iov, lnet_kiov_t *kiov,
 	    unsigned int offset, unsigned int mlen, unsigned int rlen)
 {
 	lnet_msg_t *sendmsg = private;
diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c
index 3c23677..72b7fbc 100644
--- a/drivers/staging/lustre/lnet/lnet/module.c
+++ b/drivers/staging/lustre/lnet/lnet/module.c
@@ -108,7 +108,7 @@
 	}
 }
 
-DECLARE_IOCTL_HANDLER(lnet_ioctl_handler, lnet_ioctl);
+static DECLARE_IOCTL_HANDLER(lnet_ioctl_handler, lnet_ioctl);
 
 static int __init
 init_lnet(void)
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index c667b5b..52ec0ab 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -46,7 +46,7 @@
 static int large_router_buffers;
 module_param(large_router_buffers, int, 0444);
 MODULE_PARM_DESC(large_router_buffers, "# of large messages to buffer in the router");
-static int peer_buffer_credits = 0;
+static int peer_buffer_credits;
 module_param(peer_buffer_credits, int, 0444);
 MODULE_PARM_DESC(peer_buffer_credits, "# router buffer credits per peer");
 
@@ -80,11 +80,11 @@
 
 #endif
 
-static int check_routers_before_use = 0;
+static int check_routers_before_use;
 module_param(check_routers_before_use, int, 0444);
 MODULE_PARM_DESC(check_routers_before_use, "Assume routers are down and ping them before use");
 
-static int avoid_asym_router_failure = 1;
+int avoid_asym_router_failure = 1;
 module_param(avoid_asym_router_failure, int, 0644);
 MODULE_PARM_DESC(avoid_asym_router_failure, "Avoid asymmetrical router failures (0 to disable)");
 
@@ -245,7 +245,7 @@
 
 static void lnet_shuffle_seed(void)
 {
-	static int seeded = 0;
+	static int seeded;
 	int lnd_type, seed[2];
 	struct timeval tv;
 	lnet_ni_t *ni;
@@ -783,6 +783,21 @@
 	}
 }
 
+void
+lnet_router_ni_update_locked(lnet_peer_t *gw, __u32 net)
+{
+	lnet_route_t *rte;
+
+	if ((gw->lp_ping_feats & LNET_PING_FEAT_NI_STATUS) != 0) {
+		list_for_each_entry(rte, &gw->lp_routes, lr_gwlist) {
+			if (rte->lr_net == net) {
+				rte->lr_downis = 0;
+				break;
+			}
+		}
+	}
+}
+
 static void
 lnet_update_ni_status_locked(void)
 {
@@ -793,7 +808,7 @@
 	LASSERT(the_lnet.ln_routing);
 
 	timeout = router_ping_timeout +
-		  MAX(live_router_check_interval, dead_router_check_interval);
+		  max(live_router_check_interval, dead_router_check_interval);
 
 	now = get_seconds();
 	list_for_each_entry(ni, &the_lnet.ln_nis, ni_list) {
@@ -1578,8 +1593,8 @@
 void
 lnet_router_checker (void)
 {
-	static time_t last = 0;
-	static int    running = 0;
+	static time_t last;
+	static int    running;
 
 	time_t	    now = get_seconds();
 	int	       interval = now - last;
@@ -1593,7 +1608,7 @@
 		return;
 
 	if (last != 0 &&
-	    interval > MAX(live_router_check_interval,
+	    interval > max(live_router_check_interval,
 			   dead_router_check_interval))
 		CNETERR("Checker(%d/%d) not called for %d seconds\n",
 			live_router_check_interval, dead_router_check_interval,
@@ -1664,13 +1679,16 @@
 	char *s;
 
 	s = getenv("LNET_ROUTER_PING_TIMEOUT");
-	if (s != NULL) router_ping_timeout = atoi(s);
+	if (s != NULL)
+		router_ping_timeout = atoi(s);
 
 	s = getenv("LNET_LIVE_ROUTER_CHECK_INTERVAL");
-	if (s != NULL) live_router_check_interval = atoi(s);
+	if (s != NULL)
+		live_router_check_interval = atoi(s);
 
 	s = getenv("LNET_DEAD_ROUTER_CHECK_INTERVAL");
-	if (s != NULL) dead_router_check_interval = atoi(s);
+	if (s != NULL)
+		dead_router_check_interval = atoi(s);
 
 	/* This replaces old lnd_notify mechanism */
 	check_routers_before_use = 1;
diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c
index 46cde70..c055afc 100644
--- a/drivers/staging/lustre/lnet/lnet/router_proc.c
+++ b/drivers/staging/lustre/lnet/lnet/router_proc.c
@@ -49,7 +49,7 @@
  */
 #define LNET_PROC_CPT_BITS	(LNET_CPT_BITS + 1)
 /* change version, 16 bits or 8 bits */
-#define LNET_PROC_VER_BITS	MAX(((MIN(LNET_LOFFT_BITS, 64)) / 4), 8)
+#define LNET_PROC_VER_BITS	max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
 
 #define LNET_PROC_HASH_BITS	LNET_PEER_HASH_BITS
 /*
diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c
index 5bc6153..fbff84c 100644
--- a/drivers/staging/lustre/lnet/selftest/conctl.c
+++ b/drivers/staging/lustre/lnet/selftest/conctl.c
@@ -721,7 +721,7 @@
 	return rc;
 }
 
-int lst_test_add_ioctl(lstio_test_args_t *args)
+static int lst_test_add_ioctl(lstio_test_args_t *args)
 {
 	char		*batch_name;
 	char		*src_name = NULL;
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 9999b0d..77f02b7 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -703,7 +703,7 @@
 	return 0;
 }
 
-lnet_process_id_packed_t *
+static lnet_process_id_packed_t *
 lstcon_next_id(int idx, int nkiov, lnet_kiov_t *kiov)
 {
 	lnet_process_id_packed_t *pid;
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h
index fc1cb56..2353889 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.h
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.h
@@ -54,7 +54,7 @@
 #define LST_TRANS_TIMEOUT       30
 #define LST_TRANS_MIN_TIMEOUT   3
 
-#define LST_VALIDATE_TIMEOUT(t) MIN(MAX(t, LST_TRANS_MIN_TIMEOUT), LST_TRANS_TIMEOUT)
+#define LST_VALIDATE_TIMEOUT(t) min(max(t, LST_TRANS_MIN_TIMEOUT), LST_TRANS_TIMEOUT)
 
 #define LST_PING_INTERVAL       8
 
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index 49cb654..1e0afc2 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -46,17 +46,17 @@
 #include "console.h"
 #include "conrpc.h"
 
-#define LST_NODE_STATE_COUNTER(nd, p)		   \
-do {						    \
-	if ((nd)->nd_state == LST_NODE_ACTIVE)	  \
-		(p)->nle_nactive ++;		    \
+#define LST_NODE_STATE_COUNTER(nd, p)			\
+do {							\
+	if ((nd)->nd_state == LST_NODE_ACTIVE)		\
+		(p)->nle_nactive++;			\
 	else if ((nd)->nd_state == LST_NODE_BUSY)       \
-		(p)->nle_nbusy ++;		      \
+		(p)->nle_nbusy++;			\
 	else if ((nd)->nd_state == LST_NODE_DOWN)       \
-		(p)->nle_ndown ++;		      \
-	else					    \
-		(p)->nle_nunknown ++;		   \
-	(p)->nle_nnode ++;			      \
+		(p)->nle_ndown++;			\
+	else						\
+		(p)->nle_nunknown++;			\
+	(p)->nle_nnode++;				\
 } while (0)
 
 lstcon_session_t	console_session;
@@ -223,7 +223,7 @@
 static void
 lstcon_group_addref(lstcon_group_t *grp)
 {
-	grp->grp_ref ++;
+	grp->grp_ref++;
 }
 
 static void lstcon_group_ndlink_release(lstcon_group_t *, lstcon_ndlink_t *);
@@ -298,7 +298,7 @@
 		return 0;
 
 	list_add_tail(&(*ndlpp)->ndl_link, &grp->grp_ndl_list);
-	grp->grp_nnode ++;
+	grp->grp_nnode++;
 
 	return 0;
 }
@@ -324,7 +324,7 @@
 
 	list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]);
 	list_add_tail(&ndl->ndl_link, &new->grp_ndl_list);
-	new->grp_nnode ++;
+	new->grp_nnode++;
 
 	return;
 }
@@ -767,7 +767,7 @@
 				     &nd->nd_state, sizeof(nd->nd_state)))
 			return -EFAULT;
 
-		count ++;
+		count++;
 	}
 
 	if (index <= *index_p)
@@ -1343,7 +1343,7 @@
 	/* add to test list anyway, so user can check what's going on */
 	list_add_tail(&test->tes_link, &batch->bat_test_list);
 
-	batch->bat_ntest ++;
+	batch->bat_ntest++;
 	test->tes_hdr.tsb_index = batch->bat_ntest;
 
 	/*  hold groups so nobody can change them */
@@ -1986,7 +1986,7 @@
 
 extern int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_data *data);
 
-DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
+static DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
 
 /* initialize console */
 int
diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c
index cc9d182..5709148 100644
--- a/drivers/staging/lustre/lnet/selftest/framework.c
+++ b/drivers/staging/lustre/lnet/selftest/framework.c
@@ -103,7 +103,7 @@
 #define sfw_test_active(t)      (atomic_read(&(t)->tsi_nactive) != 0)
 #define sfw_batch_active(b)     (atomic_read(&(b)->bat_nactive) != 0)
 
-struct smoketest_framework {
+static struct smoketest_framework {
 	struct list_head	 fw_zombie_rpcs;     /* RPCs to be recycled */
 	struct list_head	 fw_zombie_sessions; /* stopping sessions */
 	struct list_head	 fw_tests;	   /* registered test cases */
@@ -194,9 +194,9 @@
 	return EBUSY; /* racing with sfw_session_expired() */
 }
 
-/* called with sfw_data.fw_lock held */
 static void
 sfw_deactivate_session (void)
+	__must_hold(&sfw_data.fw_lock)
 {
 	sfw_session_t *sn = sfw_data.fw_session;
 	int	    nactive = 0;
diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c
index c6ef5b0..faf4098 100644
--- a/drivers/staging/lustre/lnet/selftest/module.c
+++ b/drivers/staging/lustre/lnet/selftest/module.c
@@ -61,31 +61,31 @@
 	int	i;
 
 	switch (lst_init_step) {
-		case LST_INIT_CONSOLE:
-			lstcon_console_fini();
-		case LST_INIT_FW:
-			sfw_shutdown();
-		case LST_INIT_RPC:
-			srpc_shutdown();
-		case LST_INIT_WI_TEST:
-			for (i = 0;
-			     i < cfs_cpt_number(lnet_cpt_table()); i++) {
-				if (lst_sched_test[i] == NULL)
-					continue;
-				cfs_wi_sched_destroy(lst_sched_test[i]);
-			}
-			LIBCFS_FREE(lst_sched_test,
-				    sizeof(lst_sched_test[0]) *
-				    cfs_cpt_number(lnet_cpt_table()));
-			lst_sched_test = NULL;
+	case LST_INIT_CONSOLE:
+		lstcon_console_fini();
+	case LST_INIT_FW:
+		sfw_shutdown();
+	case LST_INIT_RPC:
+		srpc_shutdown();
+	case LST_INIT_WI_TEST:
+		for (i = 0;
+		     i < cfs_cpt_number(lnet_cpt_table()); i++) {
+			if (lst_sched_test[i] == NULL)
+				continue;
+			cfs_wi_sched_destroy(lst_sched_test[i]);
+		}
+		LIBCFS_FREE(lst_sched_test,
+			    sizeof(lst_sched_test[0]) *
+			    cfs_cpt_number(lnet_cpt_table()));
+		lst_sched_test = NULL;
 
-		case LST_INIT_WI_SERIAL:
-			cfs_wi_sched_destroy(lst_sched_serial);
-			lst_sched_serial = NULL;
-		case LST_INIT_NONE:
-			break;
-		default:
-			LBUG();
+	case LST_INIT_WI_SERIAL:
+		cfs_wi_sched_destroy(lst_sched_serial);
+		lst_sched_serial = NULL;
+	case LST_INIT_NONE:
+		break;
+	default:
+		LBUG();
 	}
 	return;
 }
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index f753add..1f7d9a6 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -54,7 +54,7 @@
 	SRPC_STATE_STOPPING,
 } srpc_state_t;
 
-struct smoketest_rpc {
+static struct smoketest_rpc {
 	spinlock_t	 rpc_glock;	/* global lock */
 	srpc_service_t	*rpc_services[SRPC_SERVICE_MAX_ID + 1];
 	lnet_handle_eq_t rpc_lnet_eq;	/* _the_ LNet event queue */
@@ -468,6 +468,7 @@
 
 static int
 srpc_service_post_buffer(struct srpc_service_cd *scd, struct srpc_buffer *buf)
+	__must_hold(&scd->scd_lock)
 {
 	struct srpc_service	*sv = scd->scd_svc;
 	struct srpc_msg		*msg = &buf->buf_msg;
@@ -559,7 +560,7 @@
 		LASSERT(scd->scd_buf_posting > 0);
 		scd->scd_buf_posting--;
 		scd->scd_buf_total++;
-		scd->scd_buf_low = MAX(2, scd->scd_buf_total / 4);
+		scd->scd_buf_low = max(2, scd->scd_buf_total / 4);
 	}
 
 	if (rc != 0) {
@@ -697,6 +698,7 @@
 /* called with sv->sv_lock held */
 static void
 srpc_service_recycle_buffer(struct srpc_service_cd *scd, srpc_buffer_t *buf)
+	__must_hold(&scd->scd_lock)
 {
 	if (!scd->scd_svc->sv_shuttingdown && scd->scd_buf_adjust >= 0) {
 		if (srpc_service_post_buffer(scd, buf) != 0) {
@@ -1486,7 +1488,7 @@
 		if (scd->scd_buf_err == 0 && /* adding buffer is enabled */
 		    scd->scd_buf_adjust == 0 &&
 		    scd->scd_buf_nposted < scd->scd_buf_low) {
-			scd->scd_buf_adjust = MAX(scd->scd_buf_total / 2,
+			scd->scd_buf_adjust = max(scd->scd_buf_total / 2,
 						  SFW_TEST_WI_MIN);
 			swi_schedule_workitem(&scd->scd_buf_wi);
 		}
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index 9b5c5df..d487018 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -609,4 +609,16 @@
 	}
 }
 
+extern sfw_test_client_ops_t brw_test_client;
+void brw_init_test_client(void);
+
+extern srpc_service_t brw_test_service;
+void brw_init_test_service(void);
+
+extern sfw_test_client_ops_t ping_test_client;
+void ping_init_test_client(void);
+
+extern srpc_service_t ping_test_service;
+void ping_init_test_service(void);
+
 #endif /* __SELFTEST_SELFTEST_H__ */
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index f8352c2..441f947 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -57,7 +57,7 @@
 #define STTIMER_SLOT(t)	       (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
 						    (STTIMER_NSLOTS - 1))])
 
-struct st_timer_data {
+static struct st_timer_data {
 	spinlock_t	 stt_lock;
 	/* start time of the slot processed previously */
 	unsigned long       stt_prev_slot;
diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h
index eb607c5..b5e8da8 100644
--- a/drivers/staging/lustre/lustre/fid/fid_internal.h
+++ b/drivers/staging/lustre/lustre/fid/fid_internal.h
@@ -47,7 +47,7 @@
 int seq_client_alloc_super(struct lu_client_seq *seq,
 			   const struct lu_env *env);
 
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
 extern struct lprocfs_vars seq_client_proc_list[];
 #endif
 
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index 64b1d80..063441a 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -402,7 +402,7 @@
 
 static void seq_client_proc_fini(struct lu_client_seq *seq)
 {
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
 	if (seq->lcs_proc_dir) {
 		if (!IS_ERR(seq->lcs_proc_dir))
 			lprocfs_remove(&seq->lcs_proc_dir);
@@ -413,7 +413,7 @@
 
 static int seq_client_proc_init(struct lu_client_seq *seq)
 {
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
 	int rc;
 
 	seq->lcs_proc_dir = lprocfs_register(seq->lcs_name,
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 5d95d0b..0d0a737 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -257,9 +257,9 @@
  * entry accordingly.
  */
 
-void fld_cache_punch_hole(struct fld_cache *cache,
-			  struct fld_cache_entry *f_curr,
-			  struct fld_cache_entry *f_new)
+static void fld_cache_punch_hole(struct fld_cache *cache,
+				 struct fld_cache_entry *f_curr,
+				 struct fld_cache_entry *f_new)
 {
 	const struct lu_seq_range *range = &f_new->fce_range;
 	const u64 new_start  = range->lsr_start;
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index 8806b60..6125bbe 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -111,7 +111,7 @@
 
 	/**
 	 * Cache name used for debug and messages. */
-	char		     fci_name[80];
+	char		     fci_name[LUSTRE_MDT_MAXNAMELEN];
 	unsigned int		 fci_no_shrink:1;
 };
 
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index 0d361ff..b8d17e1 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -131,11 +131,20 @@
 	else
 		hash = 0;
 
+again:
 	list_for_each_entry(target, &fld->lcf_targets, ft_chain) {
 		if (target->ft_idx == hash)
 			return target;
 	}
 
+	if (hash != 0) {
+		/* It is possible the remote target(MDT) are not connected to
+		 * with client yet, so we will refer this to MDT0, which should
+		 * be connected during mount */
+		hash = 0;
+		goto again;
+	}
+
 	CERROR("%s: Can't find target by hash %d (seq %#llx). Targets (%d):\n",
 		fld->lcf_name, hash, seq, fld->lcf_count);
 
@@ -269,7 +278,7 @@
 }
 EXPORT_SYMBOL(fld_client_del_target);
 
-struct proc_dir_entry *fld_type_proc_dir = NULL;
+static struct proc_dir_entry *fld_type_proc_dir;
 
 #if defined (CONFIG_PROC_FS)
 static int fld_client_proc_init(struct lu_client_fld *fld)
diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c
index 95e7de1..8c5a657 100644
--- a/drivers/staging/lustre/lustre/fld/lproc_fld.c
+++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c
@@ -87,13 +87,21 @@
 }
 
 static ssize_t
-fld_proc_hash_seq_write(struct file *file, const char *buffer,
-			size_t count, loff_t *off)
+fld_proc_hash_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct lu_client_fld *fld;
 	struct lu_fld_hash *hash = NULL;
+	char fh_name[8];
 	int i;
 
+	if (count > sizeof(fh_name))
+		return -ENAMETOOLONG;
+
+	if (copy_from_user(fh_name, buffer, count) != 0)
+		return -EFAULT;
+
 	fld = ((struct seq_file *)file->private_data)->private;
 	LASSERT(fld != NULL);
 
@@ -101,7 +109,7 @@
 		if (count != strlen(fld_hash[i].fh_name))
 			continue;
 
-		if (!strncmp(fld_hash[i].fh_name, buffer, count)) {
+		if (!strncmp(fld_hash[i].fh_name, fh_name, count)) {
 			hash = &fld_hash[i];
 			break;
 		}
@@ -146,7 +154,7 @@
 	return 0;
 }
 
-struct file_operations fld_proc_cache_flush_fops = {
+static struct file_operations fld_proc_cache_flush_fops = {
 	.owner		= THIS_MODULE,
 	.open		= fld_proc_cache_flush_open,
 	.write		= fld_proc_cache_flush_write,
diff --git a/drivers/staging/lustre/lustre/include/lclient.h b/drivers/staging/lustre/lustre/include/lclient.h
index b3b841f..c5c3a8d 100644
--- a/drivers/staging/lustre/lustre/include/lclient.h
+++ b/drivers/staging/lustre/lustre/include/lclient.h
@@ -135,6 +135,7 @@
 static inline struct cl_attr *ccc_env_thread_attr(const struct lu_env *env)
 {
 	struct cl_attr *attr = &ccc_env_info(env)->cti_attr;
+
 	memset(attr, 0, sizeof(*attr));
 	return attr;
 }
@@ -142,6 +143,7 @@
 static inline struct cl_io *ccc_env_thread_io(const struct lu_env *env)
 {
 	struct cl_io *io = &ccc_env_info(env)->cti_io;
+
 	memset(io, 0, sizeof(*io));
 	return io;
 }
@@ -323,6 +325,7 @@
 int ccc_lock_enqueue(const struct lu_env *env,
 		     const struct cl_lock_slice *slice,
 		     struct cl_io *io, __u32 enqflags);
+int ccc_lock_use(const struct lu_env *env, const struct cl_lock_slice *slice);
 int ccc_lock_unuse(const struct lu_env *env, const struct cl_lock_slice *slice);
 int ccc_lock_wait(const struct lu_env *env, const struct cl_lock_slice *slice);
 int ccc_lock_fits_into(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index cfe503b..8a25cf6 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -627,16 +627,16 @@
 extern int lprocfs_at_hist_helper(struct seq_file *m,
 				  struct adaptive_timeout *at);
 extern int lprocfs_rd_timeouts(struct seq_file *m, void *data);
-extern int lprocfs_wr_timeouts(struct file *file, const char *buffer,
+extern int lprocfs_wr_timeouts(struct file *file, const char __user *buffer,
 			       unsigned long count, void *data);
-extern int lprocfs_wr_evict_client(struct file *file, const char *buffer,
+extern int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
 			    size_t count, loff_t *off);
-extern int lprocfs_wr_ping(struct file *file, const char *buffer,
+extern int lprocfs_wr_ping(struct file *file, const char __user *buffer,
 			   size_t count, loff_t *off);
-extern int lprocfs_wr_import(struct file *file, const char *buffer,
+extern int lprocfs_wr_import(struct file *file, const char __user *buffer,
 		      size_t count, loff_t *off);
 extern int lprocfs_rd_pinger_recov(struct seq_file *m, void *n);
-extern int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
+extern int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer,
 				   size_t count, loff_t *off);
 
 /* Statfs helpers */
@@ -650,8 +650,8 @@
 extern int lprocfs_write_helper(const char __user *buffer, unsigned long count,
 				int *val);
 extern int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult);
-extern int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
-				    __u64 *val);
+extern int lprocfs_write_u64_helper(const char __user *buffer,
+				unsigned long count, __u64 *val);
 extern int lprocfs_write_frac_u64_helper(const char *buffer,
 					 unsigned long count,
 					 __u64 *val, int mult);
@@ -716,7 +716,8 @@
 		return lprocfs_rd_##type(m, m->private);		\
 	}								\
 	static ssize_t name##_##type##_seq_write(struct file *file,	\
-			const char *buffer, size_t count, loff_t *off)	\
+			const char __user *buffer, size_t count,	\
+						loff_t *off)		\
 	{								\
 		struct seq_file *seq = file->private_data;		\
 		return lprocfs_wr_##type(file, buffer,			\
@@ -726,7 +727,8 @@
 
 #define LPROC_SEQ_FOPS_WR_ONLY(name, type)				\
 	static ssize_t name##_##type##_write(struct file *file,		\
-			const char *buffer, size_t count, loff_t *off)	\
+			const char __user *buffer, size_t count,	\
+						loff_t *off)		\
 	{								\
 		return lprocfs_wr_##type(file, buffer, count, off);	\
 	}								\
@@ -939,20 +941,24 @@
 static inline int lprocfs_rd_timeouts(struct seq_file *m, void *data)
 { return 0; }
 static inline int lprocfs_wr_timeouts(struct file *file,
-				      const char *buffer,
-				      unsigned long count, void *data)
+				const char __user *buffer,
+				unsigned long count, void *data)
 { return 0; }
-static inline int lprocfs_wr_evict_client(struct file *file, const char *buffer,
-				    size_t count, loff_t *off)
+static inline int lprocfs_wr_evict_client(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 { return 0; }
-static inline int lprocfs_wr_ping(struct file *file, const char *buffer,
-			   size_t count, loff_t *off)
+static inline int lprocfs_wr_ping(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 { return 0; }
-static inline int lprocfs_wr_import(struct file *file, const char *buffer,
-			      size_t count, loff_t *off)
+static inline int lprocfs_wr_import(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 { return 0; }
-static inline int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
-					size_t count, loff_t *off)
+static inline int lprocfs_wr_pinger_recov(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 { return 0; }
 
 /* Statfs helpers */
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 7b7457c..305ecbe 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -105,6 +105,11 @@
  * FOO_BULK_PORTAL    is for incoming bulk on the FOO
  */
 
+/* Lustre service names are following the format
+ * service name + MDT + seq name
+ */
+#define LUSTRE_MDT_MAXNAMELEN	80
+
 #define CONNMGR_REQUEST_PORTAL	  1
 #define CONNMGR_REPLY_PORTAL	    2
 //#define OSC_REQUEST_PORTAL	    3
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 2d6fbb4..0a0929f 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -358,7 +358,7 @@
 	 * Service uuid, passed from MDT + seq name to form unique seq name to
 	 * use it with procfs.
 	 */
-	char		    lcs_name[80];
+	char		    lcs_name[LUSTRE_MDT_MAXNAMELEN];
 
 	/*
 	 * Sequence width, that is how many objects may be allocated in one
@@ -408,7 +408,7 @@
 	 * Service uuid, passed from MDT + seq name to form unique seq name to
 	 * use it with procfs.
 	 */
-	char		    lss_name[80];
+	char		    lss_name[LUSTRE_MDT_MAXNAMELEN];
 
 	/*
 	 * Allocation chunks for super and meta sequences. Default values are
diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h
index 64c5048..5ee4b1e 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fld.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fld.h
@@ -93,7 +93,7 @@
 
 	/**
 	 * Fld service name in form "fld-srv-lustre-MDTXXX" */
-	char		     lsf_name[80];
+	char		     lsf_name[LUSTRE_MDT_MAXNAMELEN];
 
 };
 
@@ -124,7 +124,7 @@
 
 	/**
 	 * Client fld proc entry name. */
-	char		     lcf_name[80];
+	char		     lcf_name[LUSTRE_MDT_MAXNAMELEN];
 
 	int		      lcf_flags;
 };
diff --git a/drivers/staging/lustre/lustre/include/lustre_update.h b/drivers/staging/lustre/lustre/include/lustre_update.h
deleted file mode 100644
index 84defce..0000000
--- a/drivers/staging/lustre/lustre/include/lustre_update.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * 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,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.htm
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2013, Intel Corporation.
- */
-/*
- * lustre/include/lustre_update.h
- *
- * Author: Di Wang <di.wang@intel.com>
- */
-
-#ifndef _LUSTRE_UPDATE_H
-#define _LUSTRE_UPDATE_H
-
-#define UPDATE_BUFFER_SIZE	8192
-struct update_request {
-	struct dt_device	*ur_dt;
-	struct list_head		ur_list;    /* attached itself to thandle */
-	int			ur_flags;
-	int			ur_rc;	    /* request result */
-	int			ur_batchid; /* Current batch(trans) id */
-	struct update_buf	*ur_buf;   /* Holding the update req */
-};
-
-static inline unsigned long update_size(struct update *update)
-{
-	unsigned long size;
-	int	   i;
-
-	size = cfs_size_round(offsetof(struct update, u_bufs[0]));
-	for (i = 0; i < UPDATE_BUF_COUNT; i++)
-		size += cfs_size_round(update->u_lens[i]);
-
-	return size;
-}
-
-static inline void *update_param_buf(struct update *update, int index,
-				     int *size)
-{
-	int	i;
-	void	*ptr;
-
-	if (index >= UPDATE_BUF_COUNT)
-		return NULL;
-
-	ptr = (char *)update + cfs_size_round(offsetof(struct update,
-						       u_bufs[0]));
-	for (i = 0; i < index; i++) {
-		LASSERT(update->u_lens[i] > 0);
-		ptr += cfs_size_round(update->u_lens[i]);
-	}
-
-	if (size != NULL)
-		*size = update->u_lens[index];
-
-	return ptr;
-}
-
-static inline unsigned long update_buf_size(struct update_buf *buf)
-{
-	unsigned long size;
-	int	   i = 0;
-
-	size = cfs_size_round(offsetof(struct update_buf, ub_bufs[0]));
-	for (i = 0; i < buf->ub_count; i++) {
-		struct update *update;
-
-		update = (struct update *)((char *)buf + size);
-		size += update_size(update);
-	}
-	LASSERT(size <= UPDATE_BUFFER_SIZE);
-	return size;
-}
-
-static inline void *update_buf_get(struct update_buf *buf, int index, int *size)
-{
-	int	count = buf->ub_count;
-	void	*ptr;
-	int	i = 0;
-
-	if (index >= count)
-		return NULL;
-
-	ptr = (char *)buf + cfs_size_round(offsetof(struct update_buf,
-						    ub_bufs[0]));
-	for (i = 0; i < index; i++)
-		ptr += update_size((struct update *)ptr);
-
-	if (size != NULL)
-		*size = update_size((struct update *)ptr);
-
-	return ptr;
-}
-
-static inline void update_init_reply_buf(struct update_reply *reply, int count)
-{
-	reply->ur_version = UPDATE_REPLY_V1;
-	reply->ur_count = count;
-}
-
-static inline void *update_get_buf_internal(struct update_reply *reply,
-					    int index, int *size)
-{
-	char *ptr;
-	int count = reply->ur_count;
-	int i;
-
-	if (index >= count)
-		return NULL;
-
-	ptr = (char *)reply + cfs_size_round(offsetof(struct update_reply,
-					     ur_lens[count]));
-	for (i = 0; i < index; i++) {
-		LASSERT(reply->ur_lens[i] > 0);
-		ptr += cfs_size_round(reply->ur_lens[i]);
-	}
-
-	if (size != NULL)
-		*size = reply->ur_lens[index];
-
-	return ptr;
-}
-
-static inline void update_insert_reply(struct update_reply *reply, void *data,
-				       int data_len, int index, int rc)
-{
-	char *ptr;
-
-	ptr = update_get_buf_internal(reply, index, NULL);
-	LASSERT(ptr != NULL);
-
-	*(int *)ptr = cpu_to_le32(rc);
-	ptr += sizeof(int);
-	if (data_len > 0) {
-		LASSERT(data != NULL);
-		memcpy(ptr, data, data_len);
-	}
-	reply->ur_lens[index] = data_len + sizeof(int);
-}
-
-static inline int update_get_reply_buf(struct update_reply *reply, void **buf,
-				       int index)
-{
-	char *ptr;
-	int  size = 0;
-	int  result;
-
-	ptr = update_get_buf_internal(reply, index, &size);
-	result = *(int *)ptr;
-
-	if (result < 0)
-		return result;
-
-	LASSERT((ptr != NULL && size >= sizeof(int)));
-	*buf = ptr + sizeof(int);
-	return size - sizeof(int);
-}
-
-static inline int update_get_reply_result(struct update_reply *reply,
-					  void **buf, int index)
-{
-	void *ptr;
-	int  size;
-
-	ptr = update_get_buf_internal(reply, index, &size);
-	LASSERT(ptr != NULL && size > sizeof(int));
-	return *(int *)ptr;
-}
-
-#endif
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 24d26ab..23095bb 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -586,6 +586,12 @@
 	return 0;
 }
 
+int ccc_lock_use(const struct lu_env *env, const struct cl_lock_slice *slice)
+{
+	CLOBINVRNT(env, slice->cls_obj, ccc_object_invariant(slice->cls_obj));
+	return 0;
+}
+
 int ccc_lock_unuse(const struct lu_env *env, const struct cl_lock_slice *slice)
 {
 	CLOBINVRNT(env, slice->cls_obj, ccc_object_invariant(slice->cls_obj));
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
index 6c6c57c..20e64cd 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
@@ -249,8 +249,9 @@
 	struct __##var##__dummy_read {; } /* semicolon catcher */
 
 #define LDLM_POOL_PROC_WRITER(var, type)				    \
-	static int lprocfs_wr_##var(struct file *file, const char *buffer,  \
-			     unsigned long count, void *data)		    \
+	static int lprocfs_wr_##var(struct file *file,			    \
+				const char __user *buffer,		    \
+				unsigned long count, void *data)	    \
 	{								    \
 		struct ldlm_pool *pl = data;				    \
 		type tmp;						    \
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index 4c838f6..d20d277 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -470,6 +470,7 @@
 static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
 {
 	time_t recalc_interval_sec;
+	int ret;
 
 	recalc_interval_sec = get_seconds() - pl->pl_recalc_time;
 	if (recalc_interval_sec < pl->pl_recalc_period)
@@ -490,16 +491,15 @@
 	 */
 	ldlm_cli_pool_pop_slv(pl);
 
-	pl->pl_recalc_time = get_seconds();
-	lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
-			    recalc_interval_sec);
 	spin_unlock(&pl->pl_lock);
 
 	/*
 	 * Do not cancel locks in case lru resize is disabled for this ns.
 	 */
-	if (!ns_connect_lru_resize(ldlm_pl2ns(pl)))
-		return 0;
+	if (!ns_connect_lru_resize(ldlm_pl2ns(pl))) {
+		ret = 0;
+		goto out;
+	}
 
 	/*
 	 * In the time of canceling locks on client we do not need to maintain
@@ -507,7 +507,19 @@
 	 * It may be called when SLV has changed much, this is why we do not
 	 * take into account pl->pl_recalc_time here.
 	 */
-	return ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
+	ret = ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
+
+out:
+	spin_lock(&pl->pl_lock);
+	/*
+	 * Time of LRU resizing might be longer than period,
+	 * so update after LRU resizing rather than before it.
+	 */
+	pl->pl_recalc_time = get_seconds();
+	lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
+			    recalc_interval_sec);
+	spin_unlock(&pl->pl_lock);
+	return ret;
 }
 
 /**
@@ -591,6 +603,14 @@
 	}
 	recalc_interval_sec = pl->pl_recalc_time - get_seconds() +
 			      pl->pl_recalc_period;
+	if (recalc_interval_sec <= 0) {
+		/* Prevent too frequent recalculation. */
+		CDEBUG(D_DLMTRACE, "Negative interval(%ld), "
+		       "too short period(%ld)",
+		       recalc_interval_sec,
+		       pl->pl_recalc_period);
+		recalc_interval_sec = 1;
+	}
 
 	return recalc_interval_sec;
 }
@@ -697,8 +717,8 @@
 LDLM_POOL_PROC_READER_SEQ_SHOW(recalc_period, int);
 LDLM_POOL_PROC_WRITER(recalc_period, int);
 static ssize_t lprocfs_recalc_period_seq_write(struct file *file,
-					       const char *buf, size_t len,
-					       loff_t *off)
+					       const char __user *buf,
+					       size_t len, loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
 
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 1f150e4..c6f62a9 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -72,7 +72,7 @@
 unsigned int ldlm_dump_granted_max = 256;
 
 #if defined(CONFIG_PROC_FS)
-static ssize_t lprocfs_wr_dump_ns(struct file *file, const char *buffer,
+static ssize_t lprocfs_wr_dump_ns(struct file *file, const char __user *buffer,
 				  size_t count, loff_t *off)
 {
 	ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
@@ -287,8 +287,9 @@
 	return lprocfs_rd_uint(m, &supp);
 }
 
-static ssize_t lprocfs_elc_seq_write(struct file *file, const char *buffer,
-				 size_t count, loff_t *off)
+static ssize_t lprocfs_elc_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct ldlm_namespace *ns = ((struct seq_file *)file->private_data)->private;
 	unsigned int supp = -1;
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index a7a7ac6..76c62e8 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -57,7 +57,7 @@
 MODULE_PARM_DESC(libcfs_debug, "Lustre kernel debug mask");
 EXPORT_SYMBOL(libcfs_debug);
 
-unsigned int libcfs_debug_mb = 0;
+static unsigned int libcfs_debug_mb;
 module_param(libcfs_debug_mb, uint, 0644);
 MODULE_PARM_DESC(libcfs_debug_mb, "Total debug buffer size.");
 EXPORT_SYMBOL(libcfs_debug_mb);
@@ -93,7 +93,7 @@
 unsigned int libcfs_stack = 3 * THREAD_SIZE / 4;
 EXPORT_SYMBOL(libcfs_stack);
 
-unsigned int portal_enter_debugger;
+static unsigned int portal_enter_debugger;
 EXPORT_SYMBOL(portal_enter_debugger);
 
 unsigned int libcfs_catastrophe;
@@ -115,7 +115,7 @@
 char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT;
 
 /* We need to pass a pointer here, but elsewhere this must be a const */
-char *libcfs_debug_file_path;
+static char *libcfs_debug_file_path;
 module_param(libcfs_debug_file_path, charp, 0644);
 MODULE_PARM_DESC(libcfs_debug_file_path,
 		 "Path for dumping debug logs, set 'NONE' to prevent log dumping");
@@ -124,7 +124,7 @@
 
 /* libcfs_debug_token2mask() expects the returned
  * string in lower-case */
-const char *
+static const char *
 libcfs_debug_subsys2str(int subsys)
 {
 	switch (1 << subsys) {
@@ -185,7 +185,7 @@
 
 /* libcfs_debug_token2mask() expects the returned
  * string in lower-case */
-const char *
+static const char *
 libcfs_debug_dbg2str(int debug)
 {
 	switch (1 << debug) {
@@ -350,7 +350,7 @@
 	current->journal_info = journal_info;
 }
 
-int libcfs_debug_dumplog_thread(void *arg)
+static int libcfs_debug_dumplog_thread(void *arg)
 {
 	libcfs_debug_dumplog_internal(arg);
 	wake_up(&debug_ctlwq);
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 2d1e672..ec3a2a8 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -126,18 +126,21 @@
 
 static inline void
 cfs_hash_spin_lock(union cfs_hash_lock *lock, int exclusive)
+	__acquires(&lock->spin)
 {
 	spin_lock(&lock->spin);
 }
 
 static inline void
 cfs_hash_spin_unlock(union cfs_hash_lock *lock, int exclusive)
+	__releases(&lock->spin)
 {
 	spin_unlock(&lock->spin);
 }
 
 static inline void
 cfs_hash_rw_lock(union cfs_hash_lock *lock, int exclusive)
+	__acquires(&lock->rw)
 {
 	if (!exclusive)
 		read_lock(&lock->rw);
@@ -147,6 +150,7 @@
 
 static inline void
 cfs_hash_rw_unlock(union cfs_hash_lock *lock, int exclusive)
+	__releases(&lock->rw)
 {
 	if (!exclusive)
 		read_unlock(&lock->rw);
@@ -1580,7 +1584,7 @@
 
 	stop_on_change = cfs_hash_with_rehash_key(hs) ||
 			 !cfs_hash_with_no_itemref(hs) ||
-			 CFS_HOP(hs, put_locked) == NULL;
+			 hs->hs_ops->hs_put_locked == NULL;
 	cfs_hash_lock(hs, 0);
 	LASSERT(!cfs_hash_is_rehashing(hs));
 
@@ -1635,9 +1639,9 @@
 	    !cfs_hash_with_no_itemref(hs))
 		return -EOPNOTSUPP;
 
-	if (CFS_HOP(hs, get) == NULL ||
-	    (CFS_HOP(hs, put) == NULL &&
-	     CFS_HOP(hs, put_locked) == NULL))
+	if (hs->hs_ops->hs_get == NULL ||
+	    (hs->hs_ops->hs_put == NULL &&
+	     hs->hs_ops->hs_put_locked == NULL))
 		return -EOPNOTSUPP;
 
 	cfs_hash_for_each_enter(hs);
@@ -1667,9 +1671,9 @@
 	if (cfs_hash_with_no_lock(hs))
 		return -EOPNOTSUPP;
 
-	if (CFS_HOP(hs, get) == NULL ||
-	    (CFS_HOP(hs, put) == NULL &&
-	     CFS_HOP(hs, put_locked) == NULL))
+	if (hs->hs_ops->hs_get == NULL ||
+	    (hs->hs_ops->hs_put == NULL &&
+	     hs->hs_ops->hs_put_locked == NULL))
 		return -EOPNOTSUPP;
 
 	cfs_hash_for_each_enter(hs);
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index e2aa637..d9b7c6b 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -228,12 +228,12 @@
 	if (kkuc_groups[group].next == NULL)
 		return 0;
 
-	down_read(&kg_sem);
+	down_write(&kg_sem);
 	list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
 		if (reg->kr_fp != NULL)
 			rc = cb_func(reg->kr_data, cb_arg);
 	}
-	up_read(&kg_sem);
+	up_write(&kg_sem);
 
 	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index fb88733..76d4392 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -47,7 +47,7 @@
 		 int *oldmask, int minmask, int allmask)
 {
 	const char *debugstr;
-	char op = 0;
+	char op = '\0';
 	int newmask = minmask, i, len, found = 0;
 
 	/* <str> must be a list of tokens separated by whitespace
@@ -55,10 +55,10 @@
 	 * appears first in <str>, '*oldmask' is used as the starting point
 	 * (relative), otherwise minmask is used (absolute).  An operator
 	 * applies to all following tokens up to the next operator. */
-	while (*str != 0) {
+	while (*str != '\0') {
 		while (isspace(*str))
 			str++;
-		if (*str == 0)
+		if (*str == '\0')
 			break;
 		if (*str == '+' || *str == '-') {
 			op = *str++;
@@ -67,13 +67,15 @@
 				newmask = *oldmask;
 			while (isspace(*str))
 				str++;
-			if (*str == 0)	  /* trailing op */
+			if (*str == '\0')  /* trailing op */
 				return -EINVAL;
 		}
 
 		/* find token length */
-		for (len = 0; str[len] != 0 && !isspace(str[len]) &&
-		      str[len] != '+' && str[len] != '-'; len++);
+		len = 0;
+		while (str[len] != '\0' && !isspace(str[len]) &&
+		       str[len] != '+' && str[len] != '-')
+			len++;
 
 		/* match token */
 		found = 0;
@@ -132,7 +134,7 @@
 		++end;
 	}
 
-	*end= '\0';
+	*end = '\0';
 out:
 	return str;
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index d71ad5e..277f6b8 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -82,17 +82,12 @@
 	return cap_raised(current_cap(), cap);
 }
 
-void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
+static void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
 {
 	/* XXX lost high byte */
 	*cap = kcap.cap[0];
 }
 
-void cfs_kernel_cap_unpack(kernel_cap_t *kcap, cfs_cap_t cap)
-{
-	kcap->cap[0] = cap;
-}
-
 cfs_cap_t cfs_curproc_cap_pack(void)
 {
 	cfs_cap_t cap;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
index 83d3f08..c539e37 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
@@ -232,8 +232,9 @@
 				 __proc_debug_mb);
 }
 
-int proc_console_max_delay_cs(struct ctl_table *table, int write,
-			      void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_max_delay_cs(struct ctl_table *table, int write,
+				     void __user *buffer, size_t *lenp,
+				     loff_t *ppos)
 {
 	int rc, max_delay_cs;
 	struct ctl_table dummy = *table;
@@ -264,8 +265,9 @@
 	return rc;
 }
 
-int proc_console_min_delay_cs(struct ctl_table *table, int write,
-			      void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_min_delay_cs(struct ctl_table *table, int write,
+				     void __user *buffer, size_t *lenp,
+				     loff_t *ppos)
 {
 	int rc, min_delay_cs;
 	struct ctl_table dummy = *table;
@@ -296,8 +298,8 @@
 	return rc;
 }
 
-int proc_console_backoff(struct ctl_table *table, int write,
-			 void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_backoff(struct ctl_table *table, int write,
+				void __user *buffer, size_t *lenp, loff_t *ppos)
 {
 	int rc, backoff;
 	struct ctl_table dummy = *table;
@@ -324,16 +326,18 @@
 	return rc;
 }
 
-int libcfs_force_lbug(struct ctl_table *table, int write, void __user *buffer,
-		      size_t *lenp, loff_t *ppos)
+static int libcfs_force_lbug(struct ctl_table *table, int write,
+			     void __user *buffer,
+			     size_t *lenp, loff_t *ppos)
 {
 	if (write)
 		LBUG();
 	return 0;
 }
 
-int proc_fail_loc(struct ctl_table *table, int write, void __user *buffer,
-		  size_t *lenp, loff_t *ppos)
+static int proc_fail_loc(struct ctl_table *table, int write,
+			 void __user *buffer,
+			 size_t *lenp, loff_t *ppos)
 {
 	int rc;
 	long old_fail_loc = cfs_fail_loc;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
index b91a1f9..cd2fc01 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
@@ -43,7 +43,7 @@
 /* For sys_open & sys_close */
 #include <linux/syscalls.h>
 
-int
+static int
 libcfs_sock_ioctl(int cmd, unsigned long arg)
 {
 	mm_segment_t	oldmm = get_fs();
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
index 976c61e..c8e2930 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
@@ -151,6 +151,7 @@
  * for details.
  */
 int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
+	__acquires(&tcd->tc_lock)
 {
 	__LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
 	if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
@@ -165,6 +166,7 @@
 }
 
 void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
+	__releases(&tcd->tcd_lock)
 {
 	__LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
 	if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
@@ -269,5 +271,5 @@
 {
 	int  total_mb = (totalram_pages >> (20 - PAGE_SHIFT));
 
-	return MAX(512, (total_mb * 80)/100);
+	return max(512, (total_mb * 80)/100);
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index 2c4fc74..7dc77dd 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -42,8 +42,7 @@
 #include "../../include/linux/lnet/lnet.h"
 #include "tracefile.h"
 
-void
-kportal_memhog_free (struct libcfs_device_userstate *ldu)
+static void kportal_memhog_free (struct libcfs_device_userstate *ldu)
 {
 	struct page **level0p = &ldu->ldu_memhog_root_page;
 	struct page **level1p;
@@ -86,8 +85,7 @@
 	LASSERT (ldu->ldu_memhog_pages == 0);
 }
 
-int
-kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
+static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
 		     gfp_t flags)
 {
 	struct page **level0p;
@@ -334,8 +332,6 @@
 extern struct cfs_wi_sched *cfs_sched_rehash;
 
 extern void libcfs_init_nidstrings(void);
-extern int libcfs_arch_init(void);
-extern void libcfs_arch_cleanup(void);
 
 static int init_libcfs_module(void)
 {
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
index 47c239f..087449f 100644
--- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c
+++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
@@ -81,14 +81,105 @@
 	return str;
 }
 
-static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
-static void libcfs_ip_addr2str(__u32 addr, char *str);
-static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
-static void libcfs_decnum_addr2str(__u32 addr, char *str);
-static void libcfs_hexnum_addr2str(__u32 addr, char *str);
-static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
-static int  libcfs_num_parse(char *str, int len, struct list_head *list);
-static int  libcfs_num_match(__u32 addr, struct list_head *list);
+static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
+{
+	*addr = 0;
+	return 1;
+}
+
+static void libcfs_ip_addr2str(__u32 addr, char *str)
+{
+	snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
+		 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+		 (addr >> 8) & 0xff, addr & 0xff);
+}
+
+static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
+{
+	unsigned int	a;
+	unsigned int	b;
+	unsigned int	c;
+	unsigned int	d;
+	int		n = nob; /* XscanfX */
+
+	/* numeric IP? */
+	if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
+	    n == nob &&
+	    (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
+	    (c & ~0xff) == 0 && (d & ~0xff) == 0) {
+		*addr = ((a<<24)|(b<<16)|(c<<8)|d);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void libcfs_decnum_addr2str(__u32 addr, char *str)
+{
+	snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
+}
+
+static void libcfs_hexnum_addr2str(__u32 addr, char *str)
+{
+	snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
+}
+
+static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
+{
+	int     n;
+
+	n = nob;
+	if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
+		return 1;
+
+	n = nob;
+	if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
+		return 1;
+
+	n = nob;
+	if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * Nf_parse_addrlist method for networks using numeric addresses.
+ *
+ * Examples of such networks are gm and elan.
+ *
+ * \retval 0 if \a str parsed to numeric address
+ * \retval errno otherwise
+ */
+static int
+libcfs_num_parse(char *str, int len, struct list_head *list)
+{
+	struct cfs_expr_list *el;
+	int	rc;
+
+	rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
+	if (rc == 0)
+		list_add_tail(&el->el_link, list);
+
+	return rc;
+}
+
+/*
+ * Nf_match_addr method for networks using numeric addresses
+ *
+ * \retval 1 on match
+ * \retval 0 otherwise
+ */
+static int
+libcfs_num_match(__u32 addr, struct list_head *numaddr)
+{
+	struct cfs_expr_list *el;
+
+	LASSERT(!list_empty(numaddr));
+	el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
+
+	return cfs_expr_list_match(addr, el);
+}
 
 struct netstrfns {
 	int	  nf_type;
@@ -197,24 +288,7 @@
 	{/* .nf_type      */  -1},
 };
 
-const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
-
-int
-libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
-{
-	*addr = 0;
-	return 1;
-}
-
-void
-libcfs_ip_addr2str(__u32 addr, char *str)
-{
-#if 0   /* never lookup */
-#endif
-	snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
-		 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-		 (addr >> 8) & 0xff, addr & 0xff);
-}
+static const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
 
 /* CAVEAT EMPTOR XscanfX
  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
@@ -223,60 +297,7 @@
  * fine, if it doesn't, then the scan ended at the end of the string, which is
  * fine too :) */
 
-int
-libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
-{
-	unsigned int	a;
-	unsigned int	b;
-	unsigned int	c;
-	unsigned int	d;
-	int		n = nob; /* XscanfX */
-
-	/* numeric IP? */
-	if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
-	    n == nob &&
-	    (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
-	    (c & ~0xff) == 0 && (d & ~0xff) == 0) {
-		*addr = ((a<<24)|(b<<16)|(c<<8)|d);
-		return 1;
-	}
-
-	return 0;
-}
-
-void
-libcfs_decnum_addr2str(__u32 addr, char *str)
-{
-	snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
-}
-
-void
-libcfs_hexnum_addr2str(__u32 addr, char *str)
-{
-	snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
-}
-
-int
-libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
-{
-	int     n;
-
-	n = nob;
-	if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
-		return 1;
-
-	n = nob;
-	if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
-		return 1;
-
-	n = nob;
-	if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
-		return 1;
-
-	return 0;
-}
-
-struct netstrfns *
+static struct netstrfns *
 libcfs_lnd2netstrfns(int lnd)
 {
 	int    i;
@@ -289,7 +310,7 @@
 	return NULL;
 }
 
-struct netstrfns *
+static struct netstrfns *
 libcfs_namenum2netstrfns(const char *name)
 {
 	struct netstrfns *nf;
@@ -304,7 +325,7 @@
 	return NULL;
 }
 
-struct netstrfns *
+static struct netstrfns *
 libcfs_name2netstrfns(const char *name)
 {
 	int    i;
@@ -343,7 +364,7 @@
 		return nf->nf_name;
 
 	str = libcfs_next_nidstring();
-	snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
+	snprintf(str, LNET_NIDSTR_SIZE, "?%d?", lnd);
 	return str;
 }
 EXPORT_SYMBOL(libcfs_lnd2str);
@@ -369,11 +390,11 @@
 	char	     *str = libcfs_next_nidstring();
 
 	if (nf == NULL)
-		snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
+		snprintf(str, LNET_NIDSTR_SIZE, "<%d:%d>", lnd, num);
 	else if (num == 0)
 		snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
 	else
-		snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
+		snprintf(str, LNET_NIDSTR_SIZE, "%s%d", nf->nf_name, num);
 
 	return str;
 }
@@ -397,7 +418,7 @@
 	str = libcfs_next_nidstring();
 
 	if (nf == NULL)
-		snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
+		snprintf(str, LNET_NIDSTR_SIZE, "%x@<%d:%d>", addr, lnd, nnum);
 	else {
 		nf->nf_addr2str(addr, str);
 		nob = strlen(str);
@@ -405,7 +426,7 @@
 			snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
 				 nf->nf_name);
 		else
-			snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
+			snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%d",
 				 nf->nf_name, nnum);
 	}
 
@@ -586,27 +607,6 @@
 };
 
 /**
- * Nf_parse_addrlist method for networks using numeric addresses.
- *
- * Examples of such networks are gm and elan.
- *
- * \retval 0 if \a str parsed to numeric address
- * \retval errno otherwise
- */
-static int
-libcfs_num_parse(char *str, int len, struct list_head *list)
-{
-	struct cfs_expr_list *el;
-	int	rc;
-
-	rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
-	if (rc == 0)
-		list_add_tail(&el->el_link, list);
-
-	return rc;
-}
-
-/**
  * Parses \<addrrange\> token on the syntax.
  *
  * Allocates struct addrrange and links to \a nidrange via
@@ -812,23 +812,6 @@
 }
 EXPORT_SYMBOL(cfs_parse_nidlist);
 
-/*
- * Nf_match_addr method for networks using numeric addresses
- *
- * \retval 1 on match
- * \retval 0 otherwise
- */
-static int
-libcfs_num_match(__u32 addr, struct list_head *numaddr)
-{
-	struct cfs_expr_list *el;
-
-	LASSERT(!list_empty(numaddr));
-	el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
-
-	return cfs_expr_list_match(addr, el);
-}
-
 /**
  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
  *
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 5917c31..eb65b50 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -55,7 +55,7 @@
 struct mutex cfs_trace_thread_mutex;
 static int thread_running = 0;
 
-atomic_t cfs_tage_allocated = ATOMIC_INIT(0);
+static atomic_t cfs_tage_allocated = ATOMIC_INIT(0);
 
 static void put_pages_on_tcd_daemon_list(struct page_collection *pc,
 					 struct cfs_trace_cpu_data *tcd);
@@ -1037,6 +1037,7 @@
 				       tage->used, rc);
 				put_pages_back(&pc);
 				__LASSERT(list_empty(&pc.pc_pages));
+				break;
 			}
 		}
 		MMSPACE_CLOSE;
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 1ac7a70..a182019 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -183,7 +183,10 @@
 	op_data->op_offset = hash;
 	rc = md_readpage(exp, op_data, page_pool, &request);
 	ll_finish_md_op_data(op_data);
-	if (rc == 0) {
+	if (rc < 0) {
+		/* page0 is special, which was added into page cache early */
+		delete_from_page_cache(page0);
+	} else if (rc == 0) {
 		body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
 		/* Checked by mdc_readpage() */
 		LASSERT(body != NULL);
@@ -278,7 +281,7 @@
 	spin_lock_irq(&mapping->tree_lock);
 	found = radix_tree_gang_lookup(&mapping->page_tree,
 				       (void **)&page, offset, 1);
-	if (found > 0) {
+	if (found > 0 && !radix_tree_exceptional_entry(page)) {
 		struct lu_dirpage *dp;
 
 		page_cache_get(page);
@@ -652,8 +655,8 @@
 	return rc;
 }
 
-int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
-			char *filename)
+static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
+			       char *filename)
 {
 	struct ptlrpc_request *request = NULL;
 	struct md_op_data *op_data;
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 35a2df0..7c7ef7e 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -1553,6 +1553,11 @@
 	struct ccc_grouplock    grouplock;
 	int		     rc;
 
+	if (arg == 0) {
+		CWARN("group id for group lock must not be 0\n");
+		return -EINVAL;
+	}
+
 	if (ll_file_nolock(file))
 		return -EOPNOTSUPP;
 
@@ -1587,7 +1592,8 @@
 	return 0;
 }
 
-int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
+static int ll_put_grouplock(struct inode *inode, struct file *file,
+			    unsigned long arg)
 {
 	struct ll_inode_info   *lli = ll_i2info(inode);
 	struct ll_file_data    *fd = LUSTRE_FPRIVATE(file);
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index e6a909e..aaa13bd 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -399,9 +399,6 @@
 		return -ERANGE;
 	}
 
-	if (sbi->ll_dt_exp == NULL)
-		return -ENODEV;
-
 	spin_lock(&sbi->ll_lock);
 	diff = pages_number - cache->ccc_lru_max;
 	spin_unlock(&sbi->ll_lock);
@@ -437,6 +434,11 @@
 		if (diff <= 0)
 			break;
 
+		if (sbi->ll_dt_exp == NULL) { /* being initialized */
+			rc = -ENODEV;
+			break;
+		}
+
 		/* difficult - have to ask OSCs to drop LRU slots. */
 		tmp = diff << 1;
 		rc = obd_set_info_async(NULL, sbi->ll_dt_exp,
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 6aff155..7c1e02a 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -72,21 +72,6 @@
 	call_rcu(&inode->i_rcu, ll_inode_destroy_callback);
 }
 
-static int ll_init_inodecache(void)
-{
-	ll_inode_cachep = kmem_cache_create("lustre_inode_cache",
-					       sizeof(struct ll_inode_info),
-					       0, SLAB_HWCACHE_ALIGN, NULL);
-	if (ll_inode_cachep == NULL)
-		return -ENOMEM;
-	return 0;
-}
-
-static void ll_destroy_inodecache(void)
-{
-	kmem_cache_destroy(ll_inode_cachep);
-}
-
 /* exported operations */
 struct super_operations lustre_super_operations = {
 	.alloc_inode   = ll_alloc_inode,
@@ -104,9 +89,10 @@
 
 static int __init init_lustre_lite(void)
 {
-	int i, rc, seed[2];
-	struct timeval tv;
+	struct proc_dir_entry *entry;
 	lnet_process_id_t lnet_id;
+	struct timeval tv;
+	int i, rc, seed[2];
 
 	CLASSERT(sizeof(LUSTRE_VOLATILE_HDR) == LUSTRE_VOLATILE_HDR_LEN + 1);
 
@@ -116,59 +102,52 @@
 	CDEBUG(D_INFO, "Lustre client module (%p).\n",
 	       &lustre_super_operations);
 
-	rc = ll_init_inodecache();
-	if (rc)
-		return -ENOMEM;
+	rc = -ENOMEM;
+	ll_inode_cachep = kmem_cache_create("lustre_inode_cache",
+					    sizeof(struct ll_inode_info),
+					    0, SLAB_HWCACHE_ALIGN, NULL);
+	if (ll_inode_cachep == NULL)
+		goto out_cache;
+
 	ll_file_data_slab = kmem_cache_create("ll_file_data",
 						 sizeof(struct ll_file_data), 0,
 						 SLAB_HWCACHE_ALIGN, NULL);
-	if (ll_file_data_slab == NULL) {
-		ll_destroy_inodecache();
-		return -ENOMEM;
-	}
+	if (ll_file_data_slab == NULL)
+		goto out_cache;
 
 	ll_remote_perm_cachep = kmem_cache_create("ll_remote_perm_cache",
 						  sizeof(struct ll_remote_perm),
 						      0, 0, NULL);
-	if (ll_remote_perm_cachep == NULL) {
-		kmem_cache_destroy(ll_file_data_slab);
-		ll_file_data_slab = NULL;
-		ll_destroy_inodecache();
-		return -ENOMEM;
-	}
+	if (ll_remote_perm_cachep == NULL)
+		goto out_cache;
 
 	ll_rmtperm_hash_cachep = kmem_cache_create("ll_rmtperm_hash_cache",
 						   REMOTE_PERM_HASHSIZE *
 						   sizeof(struct list_head),
 						   0, 0, NULL);
-	if (ll_rmtperm_hash_cachep == NULL) {
-		kmem_cache_destroy(ll_remote_perm_cachep);
-		ll_remote_perm_cachep = NULL;
-		kmem_cache_destroy(ll_file_data_slab);
-		ll_file_data_slab = NULL;
-		ll_destroy_inodecache();
-		return -ENOMEM;
+	if (ll_rmtperm_hash_cachep == NULL)
+		goto out_cache;
+
+	entry = lprocfs_register("llite", proc_lustre_root, NULL, NULL);
+	if (IS_ERR(entry)) {
+		rc = PTR_ERR(entry);
+		CERROR("cannot register '/proc/fs/lustre/llite': rc = %d\n",
+		       rc);
+		goto out_cache;
 	}
 
-	proc_lustre_fs_root = proc_lustre_root ?
-			      lprocfs_register("llite", proc_lustre_root, NULL, NULL) : NULL;
-
-	lustre_register_client_fill_super(ll_fill_super);
-	lustre_register_kill_super_cb(ll_kill_super);
-
-	lustre_register_client_process_config(ll_process_config);
+	proc_lustre_fs_root = entry;
 
 	cfs_get_random_bytes(seed, sizeof(seed));
 
-	/* Nodes with small feet have little entropy
-	 * the NID for this node gives the most entropy in the low bits */
-	for (i = 0; ; i++) {
-		if (LNetGetId(i, &lnet_id) == -ENOENT) {
+	/* Nodes with small feet have little entropy. The NID for this
+	 * node gives the most entropy in the low bits */
+	for (i = 0;; i++) {
+		if (LNetGetId(i, &lnet_id) == -ENOENT)
 			break;
-		}
-		if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND) {
+
+		if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND)
 			seed[0] ^= LNET_NIDADDR(lnet_id.nid);
-		}
 	}
 
 	do_gettimeofday(&tv);
@@ -177,20 +156,54 @@
 	init_timer(&ll_capa_timer);
 	ll_capa_timer.function = ll_capa_timer_callback;
 	rc = ll_capa_thread_start();
-	/*
-	 * XXX normal cleanup is needed here.
-	 */
-	if (rc == 0)
-		rc = vvp_global_init();
+	if (rc != 0)
+		goto out_proc;
 
-	if (rc == 0)
-		rc = ll_xattr_init();
+	rc = vvp_global_init();
+	if (rc != 0)
+		goto out_capa;
+
+	rc = ll_xattr_init();
+	if (rc != 0)
+		goto out_vvp;
+
+	lustre_register_client_fill_super(ll_fill_super);
+	lustre_register_kill_super_cb(ll_kill_super);
+	lustre_register_client_process_config(ll_process_config);
+
+	return 0;
+
+out_vvp:
+	vvp_global_fini();
+out_capa:
+	del_timer(&ll_capa_timer);
+	ll_capa_thread_stop();
+out_proc:
+	lprocfs_remove(&proc_lustre_fs_root);
+out_cache:
+	if (ll_inode_cachep != NULL)
+		kmem_cache_destroy(ll_inode_cachep);
+
+	if (ll_file_data_slab != NULL)
+		kmem_cache_destroy(ll_file_data_slab);
+
+	if (ll_remote_perm_cachep != NULL)
+		kmem_cache_destroy(ll_remote_perm_cachep);
+
+	if (ll_rmtperm_hash_cachep != NULL)
+		kmem_cache_destroy(ll_rmtperm_hash_cachep);
 
 	return rc;
 }
 
 static void __exit exit_lustre_lite(void)
 {
+	lustre_register_client_fill_super(NULL);
+	lustre_register_kill_super_cb(NULL);
+	lustre_register_client_process_config(NULL);
+
+	lprocfs_remove(&proc_lustre_fs_root);
+
 	ll_xattr_fini();
 	vvp_global_fini();
 	del_timer(&ll_capa_timer);
@@ -199,22 +212,12 @@
 		 "client remaining capa count %d\n",
 		 capa_count[CAPA_SITE_CLIENT]);
 
-	lustre_register_client_fill_super(NULL);
-	lustre_register_kill_super_cb(NULL);
-
-	lustre_register_client_process_config(NULL);
-
-	ll_destroy_inodecache();
-
+	kmem_cache_destroy(ll_inode_cachep);
 	kmem_cache_destroy(ll_rmtperm_hash_cachep);
-	ll_rmtperm_hash_cachep = NULL;
 
 	kmem_cache_destroy(ll_remote_perm_cachep);
-	ll_remote_perm_cachep = NULL;
 
 	kmem_cache_destroy(ll_file_data_slab);
-	if (proc_lustre_fs_root && !IS_ERR(proc_lustre_fs_root))
-		lprocfs_remove(&proc_lustre_fs_root);
 }
 
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index 65d610a..91bba79 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -307,18 +307,13 @@
 static int vvp_io_read_lock(const struct lu_env *env,
 			    const struct cl_io_slice *ios)
 {
-	struct cl_io	 *io  = ios->cis_io;
-	struct ll_inode_info *lli = ll_i2info(ccc_object_inode(io->ci_obj));
+	struct cl_io	 *io = ios->cis_io;
+	struct cl_io_rw_common *rd = &io->u.ci_rd.rd;
 	int result;
 
-	/* XXX: Layer violation, we shouldn't see lsm at llite level. */
-	if (lli->lli_has_smd) /* lsm-less file doesn't need to lock */
-		result = vvp_io_rw_lock(env, io, CLM_READ,
-					io->u.ci_rd.rd.crw_pos,
-					io->u.ci_rd.rd.crw_pos +
-					io->u.ci_rd.rd.crw_count - 1);
-	else
-		result = 0;
+	result = vvp_io_rw_lock(env, io, CLM_READ, rd->crw_pos,
+				rd->crw_pos + rd->crw_count - 1);
+
 	return result;
 }
 
diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c
index 372633e..f354e82 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_lock.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c
@@ -71,6 +71,7 @@
 	.clo_fini      = ccc_lock_fini,
 	.clo_enqueue   = ccc_lock_enqueue,
 	.clo_wait      = ccc_lock_wait,
+	.clo_use       = ccc_lock_use,
 	.clo_unuse     = ccc_lock_unuse,
 	.clo_fits_into = ccc_lock_fits_into,
 	.clo_state     = ccc_lock_state,
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 9f38374..b779f47 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -128,7 +128,7 @@
 	return rc;
 }
 
-struct obd_uuid *lmv_get_uuid(struct obd_export *exp)
+static struct obd_uuid *lmv_get_uuid(struct obd_export *exp)
 {
 	struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
 
@@ -335,7 +335,7 @@
 
 #define MAX_STRING_SIZE 128
 
-int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
+static int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
 {
 	struct proc_dir_entry   *lmv_proc_dir;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -1663,10 +1663,10 @@
 	return tgt;
 }
 
-int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
-	       const void *data, int datalen, int mode, __u32 uid,
-	       __u32 gid, cfs_cap_t cap_effective, __u64 rdev,
-	       struct ptlrpc_request **request)
+static int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
+		      const void *data, int datalen, int mode, __u32 uid,
+		      __u32 gid, cfs_cap_t cap_effective, __u64 rdev,
+		      struct ptlrpc_request **request)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2387,9 +2387,9 @@
 	return -EINVAL;
 }
 
-int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
-		       u32 keylen, void *key, u32 vallen,
-		       void *val, struct ptlrpc_request_set *set)
+static int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
+			      u32 keylen, void *key, u32 vallen,
+			      void *val, struct ptlrpc_request_set *set)
 {
 	struct lmv_tgt_desc    *tgt;
 	struct obd_device      *obd;
@@ -2425,8 +2425,8 @@
 	return -EINVAL;
 }
 
-int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
-	       struct lov_stripe_md *lsm)
+static int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
+		      struct lov_stripe_md *lsm)
 {
 	struct obd_device	 *obd = class_exp2obd(exp);
 	struct lmv_obd	    *lmv = &obd->u.lmv;
@@ -2473,8 +2473,8 @@
 	return mea_size;
 }
 
-int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
-		 struct lov_mds_md *lmm, int lmm_size)
+static int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
+			struct lov_mds_md *lmm, int lmm_size)
 {
 	struct obd_device	  *obd = class_exp2obd(exp);
 	struct lmv_stripe_md      **tmea = (struct lmv_stripe_md **)lsmp;
@@ -2551,8 +2551,8 @@
 	return rc;
 }
 
-int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
-		      __u64 *bits)
+static int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
+			     __u64 *bits)
 {
 	struct lmv_obd	  *lmv = &exp->exp_obd->u.lmv;
 	int		      rc;
@@ -2561,10 +2561,10 @@
 	return rc;
 }
 
-ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
-			   const struct lu_fid *fid, ldlm_type_t type,
-			   ldlm_policy_data_t *policy, ldlm_mode_t mode,
-			   struct lustre_handle *lockh)
+static ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
+				  const struct lu_fid *fid, ldlm_type_t type,
+				  ldlm_policy_data_t *policy, ldlm_mode_t mode,
+				  struct lustre_handle *lockh)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2594,16 +2594,18 @@
 	return 0;
 }
 
-int lmv_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
-		      struct obd_export *dt_exp, struct obd_export *md_exp,
-		      struct lustre_md *md)
+static int lmv_get_lustre_md(struct obd_export *exp,
+			     struct ptlrpc_request *req,
+			     struct obd_export *dt_exp,
+			     struct obd_export *md_exp,
+			     struct lustre_md *md)
 {
 	struct lmv_obd	  *lmv = &exp->exp_obd->u.lmv;
 
 	return md_get_lustre_md(lmv->tgts[0]->ltd_exp, req, dt_exp, md_exp, md);
 }
 
-int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
+static int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2613,9 +2615,9 @@
 	return md_free_lustre_md(lmv->tgts[0]->ltd_exp, md);
 }
 
-int lmv_set_open_replay_data(struct obd_export *exp,
-			     struct obd_client_handle *och,
-			     struct lookup_intent *it)
+static int lmv_set_open_replay_data(struct obd_export *exp,
+				    struct obd_client_handle *och,
+				    struct lookup_intent *it)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2628,8 +2630,8 @@
 	return md_set_open_replay_data(tgt->ltd_exp, och, it);
 }
 
-int lmv_clear_open_replay_data(struct obd_export *exp,
-			       struct obd_client_handle *och)
+static int lmv_clear_open_replay_data(struct obd_export *exp,
+				      struct obd_client_handle *och)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2684,17 +2686,18 @@
 	return rc;
 }
 
-int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
-		    const struct req_msg_field *field, struct obd_capa **oc)
+static int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
+			   const struct req_msg_field *field,
+			   struct obd_capa **oc)
 {
 	struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
 
 	return md_unpack_capa(lmv->tgts[0]->ltd_exp, req, field, oc);
 }
 
-int lmv_intent_getattr_async(struct obd_export *exp,
-			     struct md_enqueue_info *minfo,
-			     struct ldlm_enqueue_info *einfo)
+static int lmv_intent_getattr_async(struct obd_export *exp,
+				    struct md_enqueue_info *minfo,
+				    struct ldlm_enqueue_info *einfo)
 {
 	struct md_op_data       *op_data = &minfo->mi_data;
 	struct obd_device       *obd = exp->exp_obd;
@@ -2714,8 +2717,8 @@
 	return rc;
 }
 
-int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
-			struct lu_fid *fid, __u64 *bits)
+static int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
+			       struct lu_fid *fid, __u64 *bits)
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
@@ -2739,8 +2742,8 @@
  * process with other slave MDTs. The only exception is Q_GETOQUOTA for which
  * we directly fetch data from the slave MDTs.
  */
-int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
-		 struct obd_quotactl *oqctl)
+static int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
+			struct obd_quotactl *oqctl)
 {
 	struct obd_device   *obd = class_exp2obd(exp);
 	struct lmv_obd      *lmv = &obd->u.lmv;
@@ -2786,8 +2789,8 @@
 	return rc;
 }
 
-int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
-		   struct obd_quotactl *oqctl)
+static int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
+			  struct obd_quotactl *oqctl)
 {
 	struct obd_device   *obd = class_exp2obd(exp);
 	struct lmv_obd      *lmv = &obd->u.lmv;
@@ -2810,7 +2813,7 @@
 	return rc;
 }
 
-struct obd_ops lmv_obd_ops = {
+static struct obd_ops lmv_obd_ops = {
 	.o_owner		= THIS_MODULE,
 	.o_setup		= lmv_setup,
 	.o_cleanup	      = lmv_cleanup,
@@ -2830,7 +2833,7 @@
 	.o_quotactl	     = lmv_quotactl
 };
 
-struct md_ops lmv_md_ops = {
+static struct md_ops lmv_md_ops = {
 	.m_getstatus	    = lmv_getstatus,
 	.m_null_inode		= lmv_null_inode,
 	.m_find_cbdata	  = lmv_find_cbdata,
@@ -2864,7 +2867,7 @@
 	.m_revalidate_lock      = lmv_revalidate_lock
 };
 
-int __init lmv_init(void)
+static int __init lmv_init(void)
 {
 	struct lprocfs_static_vars lvars;
 	int			rc;
diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
index 1170020..5be4176 100644
--- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
+++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
@@ -175,7 +175,7 @@
 			  tgt->ltd_uuid.uuid, tgt->ltd_active ? "" : "IN");
 }
 
-struct seq_operations lmv_tgt_sops = {
+static struct seq_operations lmv_tgt_sops = {
 	.start		 = lmv_tgt_seq_start,
 	.stop		  = lmv_tgt_seq_stop,
 	.next		  = lmv_tgt_seq_next,
@@ -199,7 +199,7 @@
 
 LPROC_SEQ_FOPS_RO_TYPE(lmv, uuid);
 
-struct lprocfs_vars lprocfs_lmv_obd_vars[] = {
+static struct lprocfs_vars lprocfs_lmv_obd_vars[] = {
 	{ "numobd",	  &lmv_numobd_fops,	  NULL, 0 },
 	{ "placement",	  &lmv_placement_fops,    NULL, 0 },
 	{ "activeobd",	  &lmv_activeobd_fops,    NULL, 0 },
diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c
index c993f25..c99f2f4 100644
--- a/drivers/staging/lustre/lustre/lov/lproc_lov.c
+++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c
@@ -51,8 +51,9 @@
 	return seq_printf(m, "%llu\n", desc->ld_default_stripe_size);
 }
 
-static ssize_t lov_stripesize_seq_write(struct file *file, const char *buffer,
-				    size_t count, loff_t *off)
+static ssize_t lov_stripesize_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct lov_desc *desc;
@@ -81,8 +82,9 @@
 	return seq_printf(m, "%llu\n", desc->ld_default_stripe_offset);
 }
 
-static ssize_t lov_stripeoffset_seq_write(struct file *file, const char *buffer,
-				      size_t count, loff_t *off)
+static ssize_t lov_stripeoffset_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct lov_desc *desc;
@@ -110,8 +112,9 @@
 	return seq_printf(m, "%u\n", desc->ld_pattern);
 }
 
-static ssize_t lov_stripetype_seq_write(struct file *file, const char *buffer,
-				    size_t count, loff_t *off)
+static ssize_t lov_stripetype_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct lov_desc *desc;
@@ -140,8 +143,9 @@
 			(__s16)(desc->ld_default_stripe_count + 1) - 1);
 }
 
-static ssize_t lov_stripecount_seq_write(struct file *file, const char *buffer,
-				     size_t count, loff_t *off)
+static ssize_t lov_stripecount_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct lov_desc *desc;
diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
index 16341c8..c791941 100644
--- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
+++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
@@ -52,7 +52,7 @@
 }
 
 static ssize_t mdc_max_rpcs_in_flight_seq_write(struct file *file,
-						const char *buffer,
+						const char __user *buffer,
 						size_t count,
 						loff_t *off)
 {
@@ -82,8 +82,9 @@
 }
 
 /* temporary for testing */
-static ssize_t mdc_kuc_write(struct file *file, const char *buffer,
-			     size_t count, loff_t *off)
+static ssize_t mdc_kuc_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *obd =
 			((struct seq_file *)file->private_data)->private;
@@ -105,6 +106,8 @@
 		/* for mockup below */ 2 * cfs_size_round(sizeof(*hai));
 
 	OBD_ALLOC(lh, len);
+	if (!lh)
+		return -ENOMEM;
 
 	lh->kuc_magic = KUC_MAGIC;
 	lh->kuc_transport = KUC_TRANSPORT_HSM;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index 4e59995..d3234cb 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -222,10 +222,9 @@
 	rec->cr_fsuid    = from_kuid(&init_user_ns, current_fsuid());
 	rec->cr_fsgid    = from_kgid(&init_user_ns, current_fsgid());
 	rec->cr_cap      = cfs_curproc_cap_pack();
-	if (op_data != NULL) {
-		rec->cr_fid1 = op_data->op_fid1;
-		rec->cr_fid2 = op_data->op_fid2;
-	}
+	rec->cr_fid1 = op_data->op_fid1;
+	rec->cr_fid2 = op_data->op_fid2;
+
 	rec->cr_mode     = mode;
 	cr_flags = mds_pack_open_flags(flags, mode);
 	rec->cr_rdev     = rdev;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 8c9b4f5..d1c224e 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -828,6 +828,7 @@
 			 einfo->ei_type);
 		policy = (ldlm_policy_data_t *)lmm;
 		res_id.name[3] = LDLM_FLOCK;
+		req = NULL;
 	} else if (it->it_op & IT_OPEN) {
 		req = mdc_intent_open_pack(exp, it, op_data, lmm, lmmsize,
 					   einfo->ei_cbdata);
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 3b0f245..ef27447 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -855,8 +855,8 @@
 	}
 }
 
-int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
-	      struct md_open_data *mod, struct ptlrpc_request **request)
+static int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
+		     struct md_open_data *mod, struct ptlrpc_request **request)
 {
 	struct obd_device     *obd = class_exp2obd(exp);
 	struct ptlrpc_request *req;
@@ -974,8 +974,8 @@
 	return rc < 0 ? rc : saved_rc;
 }
 
-int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
-		     struct md_open_data *mod)
+static int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
+			    struct md_open_data *mod)
 {
 	struct obd_device     *obd = class_exp2obd(exp);
 	struct ptlrpc_request *req;
@@ -1044,8 +1044,8 @@
 }
 
 
-int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
-		 struct page **pages, struct ptlrpc_request **request)
+static int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
+			struct page **pages, struct ptlrpc_request **request)
 {
 	struct ptlrpc_request   *req;
 	struct ptlrpc_bulk_desc *desc;
@@ -1908,8 +1908,8 @@
 
 		/* copy UUID */
 		if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(obd),
-				     min((int) data->ioc_plen2,
-					 (int) sizeof(struct obd_uuid)))) {
+				 min_t(size_t, data->ioc_plen2,
+					       sizeof(struct obd_uuid)))) {
 			rc = -EFAULT;
 			goto out;
 		}
@@ -1921,8 +1921,8 @@
 			goto out;
 
 		if (copy_to_user(data->ioc_pbuf1, &stat_buf,
-				     min((int) data->ioc_plen1,
-					 (int) sizeof(stat_buf)))) {
+				 min_t(size_t, data->ioc_plen1,
+					       sizeof(stat_buf)))) {
 			rc = -EFAULT;
 			goto out;
 		}
@@ -1974,9 +1974,9 @@
 	return rc;
 }
 
-int mdc_get_info_rpc(struct obd_export *exp,
-		     u32 keylen, void *key,
-		     int vallen, void *val)
+static int mdc_get_info_rpc(struct obd_export *exp,
+			    u32 keylen, void *key,
+			    int vallen, void *val)
 {
 	struct obd_import      *imp = class_exp2cliimp(exp);
 	struct ptlrpc_request  *req;
@@ -2148,11 +2148,11 @@
 					 (void *)imp);
 }
 
-int mdc_set_info_async(const struct lu_env *env,
-		       struct obd_export *exp,
-		       u32 keylen, void *key,
-		       u32 vallen, void *val,
-		       struct ptlrpc_request_set *set)
+static int mdc_set_info_async(const struct lu_env *env,
+			      struct obd_export *exp,
+			      u32 keylen, void *key,
+			      u32 vallen, void *val,
+			      struct ptlrpc_request_set *set)
 {
 	struct obd_import	*imp = class_exp2cliimp(exp);
 	int			 rc;
@@ -2199,9 +2199,9 @@
 	return -EINVAL;
 }
 
-int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
-		 __u32 keylen, void *key, __u32 *vallen, void *val,
-		 struct lov_stripe_md *lsm)
+static int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
+			__u32 keylen, void *key, __u32 *vallen, void *val,
+			struct lov_stripe_md *lsm)
 {
 	int rc = -EINVAL;
 
@@ -2263,8 +2263,8 @@
 	return rc;
 }
 
-int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
-	     struct obd_capa *oc, struct ptlrpc_request **request)
+static int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
+		    struct obd_capa *oc, struct ptlrpc_request **request)
 {
 	struct ptlrpc_request *req;
 	int		    rc;
@@ -2356,7 +2356,7 @@
 	return seq_client_alloc_fid(NULL, seq, fid);
 }
 
-struct obd_uuid *mdc_get_uuid(struct obd_export *exp)
+static struct obd_uuid *mdc_get_uuid(struct obd_export *exp)
 {
 	struct client_obd *cli = &exp->exp_obd->u.cli;
 
@@ -2390,7 +2390,7 @@
 	return 0;
 }
 
-struct ldlm_valblock_ops inode_lvbo = {
+static struct ldlm_valblock_ops inode_lvbo = {
 	.lvbo_free = mdc_resource_inode_free,
 };
 
@@ -2550,9 +2550,9 @@
 
 
 /* get remote permission for current user on fid */
-int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
-			struct obd_capa *oc, __u32 suppgid,
-			struct ptlrpc_request **request)
+static int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
+			       struct obd_capa *oc, __u32 suppgid,
+			       struct ptlrpc_request **request)
 {
 	struct ptlrpc_request  *req;
 	int		    rc;
@@ -2647,7 +2647,7 @@
 	return 0;
 }
 
-struct obd_ops mdc_obd_ops = {
+static struct obd_ops mdc_obd_ops = {
 	.o_owner	    = THIS_MODULE,
 	.o_setup	    = mdc_setup,
 	.o_precleanup       = mdc_precleanup,
@@ -2670,7 +2670,7 @@
 	.o_quotacheck       = mdc_quotacheck
 };
 
-struct md_ops mdc_md_ops = {
+static struct md_ops mdc_md_ops = {
 	.m_getstatus	= mdc_getstatus,
 	.m_null_inode	    = mdc_null_inode,
 	.m_find_cbdata      = mdc_find_cbdata,
@@ -2705,7 +2705,7 @@
 	.m_revalidate_lock      = mdc_revalidate_lock
 };
 
-int __init mdc_init(void)
+static int __init mdc_init(void)
 {
 	int rc;
 	struct lprocfs_static_vars lvars = { NULL };
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index ce96bd2..f13d1fb 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -193,6 +193,7 @@
  * cl_object_attr_get(), cl_object_attr_set().
  */
 void cl_object_attr_lock(struct cl_object *o)
+	__acquires(cl_object_attr_guard(o))
 {
 	spin_lock(cl_object_attr_guard(o));
 }
@@ -202,6 +203,7 @@
  * Releases data-attributes lock, acquired by cl_object_attr_lock().
  */
 void cl_object_attr_unlock(struct cl_object *o)
+	__releases(cl_object_attr_guard(o))
 {
 	spin_unlock(cl_object_attr_guard(o));
 }
@@ -662,7 +664,8 @@
 	return cl_env_hash != NULL ? 0 :-ENOMEM;
 }
 
-static void cl_env_store_fini(void) {
+static void cl_env_store_fini(void)
+{
 	cfs_hash_putref(cl_env_hash);
 }
 
diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index 89a3fb2..29456e1 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -61,7 +61,7 @@
 EXPORT_SYMBOL(obd_alloc);
 __u64 obd_pages;
 EXPORT_SYMBOL(obd_pages);
-DEFINE_SPINLOCK(obd_updatemax_lock);
+static DEFINE_SPINLOCK(obd_updatemax_lock);
 
 /* The following are visible and mutable through /proc/sys/lustre/. */
 unsigned int obd_alloc_fail_rate = 0;
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index 736ca410..8250821 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -1151,22 +1151,24 @@
 			exp->exp_obd->obd_stale_clients++;
 	}
 	spin_unlock(&obd->obd_recovery_task_lock);
+
+	spin_lock(&exp->exp_lock);
 	/** Cleanup req replay fields */
 	if (exp->exp_req_replay_needed) {
-		spin_lock(&exp->exp_lock);
 		exp->exp_req_replay_needed = 0;
-		spin_unlock(&exp->exp_lock);
+
 		LASSERT(atomic_read(&obd->obd_req_replay_clients));
 		atomic_dec(&obd->obd_req_replay_clients);
 	}
+
 	/** Cleanup lock replay data */
 	if (exp->exp_lock_replay_needed) {
-		spin_lock(&exp->exp_lock);
 		exp->exp_lock_replay_needed = 0;
-		spin_unlock(&exp->exp_lock);
+
 		LASSERT(atomic_read(&obd->obd_lock_replay_clients));
 		atomic_dec(&obd->obd_lock_replay_clients);
 	}
+	spin_unlock(&exp->exp_lock);
 }
 
 /* This function removes 1-3 references from the export:
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index 66ceab2..b94aeac 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -83,9 +83,8 @@
 	int err;
 	int offset = 0;
 
-	err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
-	if (err)
-		return err;
+	if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
+		return -EFAULT;
 
 	if (hdr.ioc_version != OBD_IOCTL_VERSION) {
 		CERROR("Version mismatch kernel (%x) vs application (%x)\n",
@@ -117,18 +116,19 @@
 	*len = hdr.ioc_len;
 	data = (struct obd_ioctl_data *)*buf;
 
-	err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
-	if (err) {
-		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		return err;
+	if (copy_from_user(*buf, (void *)arg, hdr.ioc_len)) {
+		err = -EFAULT;
+		goto free_buf;
 	}
-	if (hdr.ioc_len != data->ioc_len)
-		return -EINVAL;
+	if (hdr.ioc_len != data->ioc_len) {
+		err = -EINVAL;
+		goto free_buf;
+	}
 
 	if (obd_ioctl_is_invalid(data)) {
 		CERROR("ioctl not correctly formatted\n");
-		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		return -EINVAL;
+		err = -EINVAL;
+		goto free_buf;
 	}
 
 	if (data->ioc_inllen1) {
@@ -151,6 +151,10 @@
 	}
 
 	return 0;
+
+free_buf:
+	OBD_FREE_LARGE(*buf, hdr.ioc_len);
+	return err;
 }
 EXPORT_SYMBOL(obd_ioctl_getdata);
 
@@ -272,8 +276,9 @@
 	return seq_printf(m, "%s\n", obd_jobid_var);
 }
 
-static ssize_t obd_proc_jobid_var_seq_write(struct file *file, const char *buffer,
-					size_t count, loff_t *off)
+static ssize_t obd_proc_jobid_var_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN)
 		return -EINVAL;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
index d3ec90e..a2d5aa1 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
@@ -168,7 +168,8 @@
 	}
 	case CHANGELOG_REC:
 	{
-		struct llog_changelog_rec *cr = (struct llog_changelog_rec *)rec;
+		struct llog_changelog_rec *cr =
+			(struct llog_changelog_rec *)rec;
 
 		__swab16s(&cr->cr.cr_namelen);
 		__swab16s(&cr->cr.cr_flags);
@@ -188,6 +189,8 @@
 		} else {
 			tail = &cr->cr_tail;
 		}
+		tail = (struct llog_rec_tail *)((char *)tail +
+						cr->cr.cr_namelen);
 		break;
 	}
 	case CHANGELOG_USER_REC:
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index 3b7dfc3..ddab94d 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -45,6 +45,7 @@
 #include "../include/lprocfs_status.h"
 #include "../include/lustre/lustre_idl.h"
 #include <linux/seq_file.h>
+#include <linux/ctype.h>
 
 static const char * const obd_connect_names[] = {
 	"read_only",
@@ -1849,7 +1850,7 @@
 }
 EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
 
-int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
+int lprocfs_write_u64_helper(const char __user *buffer, unsigned long count,
 			     __u64 *val)
 {
 	return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
@@ -1862,6 +1863,7 @@
 	char kernbuf[22], *end, *pbuf;
 	__u64 whole, frac = 0, units;
 	unsigned frac_d = 1;
+	int sign = 1;
 
 	if (count > (sizeof(kernbuf) - 1))
 		return -EINVAL;
@@ -1872,7 +1874,7 @@
 	kernbuf[count] = '\0';
 	pbuf = kernbuf;
 	if (*pbuf == '-') {
-		mult = -mult;
+		sign = -1;
 		pbuf++;
 	}
 
@@ -1880,7 +1882,7 @@
 	if (pbuf == end)
 		return -EINVAL;
 
-	if (end != NULL && *end == '.') {
+	if (*end == '.') {
 		int i;
 		pbuf = end + 1;
 
@@ -1895,25 +1897,25 @@
 	}
 
 	units = 1;
-	switch (*end) {
-	case 'p': case 'P':
+	switch (tolower(*end)) {
+	case 'p':
 		units <<= 10;
-	case 't': case 'T':
+	case 't':
 		units <<= 10;
-	case 'g': case 'G':
+	case 'g':
 		units <<= 10;
-	case 'm': case 'M':
+	case 'm':
 		units <<= 10;
-	case 'k': case 'K':
+	case 'k':
 		units <<= 10;
 	}
 	/* Specified units override the multiplier */
-	if (units)
-		mult = mult < 0 ? -units : units;
+	if (units > 1)
+		mult = units;
 
 	frac *= mult;
 	do_div(frac, frac_d);
-	*val = whole * mult + frac;
+	*val = sign * (whole * mult + frac);
 	return 0;
 }
 EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 4f39cde..3c0c910 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -376,6 +376,11 @@
 
 	/* Random uuid for MGC allows easier reconnects */
 	OBD_ALLOC_PTR(uuid);
+	if (!uuid) {
+		rc = -ENOMEM;
+		goto out_free;
+	}
+
 	ll_generate_random_uuid(uuidc);
 	class_uuid_unparse(uuidc, uuid);
 
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index 9f719bc..1795d3a 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -53,8 +53,9 @@
 	return rc;
 }
 
-static ssize_t osc_active_seq_write(struct file *file, const char *buffer,
-				    size_t count, loff_t *off)
+static ssize_t osc_active_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	int val, rc;
@@ -88,7 +89,8 @@
 }
 
 static ssize_t osc_max_rpcs_in_flight_seq_write(struct file *file,
-			const char *buffer, size_t count, loff_t *off)
+			const char __user *buffer,
+			size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct client_obd *cli = &dev->u.cli;
@@ -130,8 +132,9 @@
 	return lprocfs_seq_read_frac_helper(m, val, mult);
 }
 
-static ssize_t osc_max_dirty_mb_seq_write(struct file *file, const char *buffer,
-				      size_t count, loff_t *off)
+static ssize_t osc_max_dirty_mb_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct client_obd *cli = &dev->u.cli;
@@ -233,8 +236,9 @@
 	return rc;
 }
 
-static ssize_t osc_cur_grant_bytes_seq_write(struct file *file, const char *buffer,
-				  size_t count, loff_t *off)
+static ssize_t osc_cur_grant_bytes_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	struct client_obd *cli = &obd->u.cli;
@@ -290,7 +294,8 @@
 }
 
 static ssize_t osc_grant_shrink_interval_seq_write(struct file *file,
-				const char *buffer, size_t count, loff_t *off)
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	int val, rc;
@@ -322,8 +327,9 @@
 			obd->u.cli.cl_checksum ? 1 : 0);
 }
 
-static ssize_t osc_checksum_seq_write(struct file *file, const char *buffer,
-			   size_t count, loff_t *off)
+static ssize_t osc_checksum_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	int val, rc;
@@ -358,11 +364,12 @@
 		else
 			seq_printf(m, "%s ", cksum_name[i]);
 	}
-	seq_printf(m, "\n");
+	seq_putc(m, '\n');
 	return 0;
 }
 
-static ssize_t osc_checksum_type_seq_write(struct file *file, const char *buffer,
+static ssize_t osc_checksum_type_seq_write(struct file *file,
+				const char __user *buffer,
 				size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -401,8 +408,9 @@
 	return seq_printf(m, "%u\n", atomic_read(&obd->u.cli.cl_resends));
 }
 
-static ssize_t osc_resend_count_seq_write(struct file *file, const char *buffer,
-			       size_t count, loff_t *off)
+static ssize_t osc_resend_count_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	int val, rc;
@@ -428,8 +436,9 @@
 	return seq_printf(m, "%u\n", od->od_contention_time);
 }
 
-static ssize_t osc_contention_seconds_seq_write(struct file *file, const char *buffer,
-				     size_t count, loff_t *off)
+static ssize_t osc_contention_seconds_seq_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	struct osc_device *od  = obd2osc_dev(obd);
@@ -447,8 +456,9 @@
 	return seq_printf(m, "%u\n", od->od_lockless_truncate);
 }
 
-static ssize_t osc_lockless_truncate_seq_write(struct file *file, const char *buffer,
-				    size_t count, loff_t *off)
+static ssize_t osc_lockless_truncate_seq_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	struct osc_device *od  = obd2osc_dev(obd);
@@ -472,7 +482,8 @@
 }
 
 static ssize_t osc_obd_max_pages_per_rpc_seq_write(struct file *file,
-				const char *buffer, size_t count, loff_t *off)
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
 	struct client_obd *cli = &dev->u.cli;
@@ -590,9 +601,9 @@
 	seq_printf(seq, "pending read pages:   %d\n",
 		   atomic_read(&cli->cl_pending_r_pages));
 
-	seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
-	seq_printf(seq, "pages per rpc	 rpcs   %% cum %% |");
-	seq_printf(seq, "       rpcs   %% cum %%\n");
+	seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+	seq_puts(seq, "pages per rpc	 rpcs   % cum % |");
+	seq_puts(seq, "       rpcs   % cum %\n");
 
 	read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
 	write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
@@ -613,9 +624,9 @@
 			break;
 	}
 
-	seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
-	seq_printf(seq, "rpcs in flight	rpcs   %% cum %% |");
-	seq_printf(seq, "       rpcs   %% cum %%\n");
+	seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+	seq_puts(seq, "rpcs in flight	rpcs   % cum % |");
+	seq_puts(seq, "       rpcs   % cum %\n");
 
 	read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
 	write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
@@ -636,9 +647,9 @@
 			break;
 	}
 
-	seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
-	seq_printf(seq, "offset		rpcs   %% cum %% |");
-	seq_printf(seq, "       rpcs   %% cum %%\n");
+	seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+	seq_puts(seq, "offset		rpcs   % cum % |");
+	seq_puts(seq, "       rpcs   % cum %\n");
 
 	read_tot = lprocfs_oh_sum(&cli->cl_read_offset_hist);
 	write_tot = lprocfs_oh_sum(&cli->cl_write_offset_hist);
@@ -664,8 +675,9 @@
 }
 #undef pct
 
-static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
-				       size_t len, loff_t *off)
+static ssize_t osc_rpc_stats_seq_write(struct file *file,
+				const char __user *buf,
+				size_t len, loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
 	struct obd_device *dev = seq->private;
@@ -702,8 +714,9 @@
 	return 0;
 }
 
-static ssize_t osc_stats_seq_write(struct file *file, const char *buf,
-				   size_t len, loff_t *off)
+static ssize_t osc_stats_seq_write(struct file *file,
+				const char __user *buf,
+				size_t len, loff_t *off)
 {
 	struct seq_file *seq = file->private_data;
 	struct obd_device *dev = seq->private;
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 370e6d4..7022ed4 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -1820,6 +1820,9 @@
 				    int *pc, unsigned int *max_pages)
 {
 	struct osc_extent *tmp;
+	struct osc_async_page *oap = list_first_entry(&ext->oe_pages,
+						      struct osc_async_page,
+						      oap_pending_item);
 
 	EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE),
 		ext);
@@ -1829,6 +1832,10 @@
 		return 0;
 
 	list_for_each_entry(tmp, rpclist, oe_link) {
+		struct osc_async_page *oap2;
+
+		oap2 = list_first_entry(&tmp->oe_pages, struct osc_async_page,
+					oap_pending_item);
 		EASSERT(tmp->oe_owner == current, tmp);
 #if 0
 		if (overlapped(tmp, ext)) {
@@ -1836,6 +1843,11 @@
 			EASSERT(0, ext);
 		}
 #endif
+		if (oap2cl_page(oap)->cp_type != oap2cl_page(oap2)->cp_type) {
+			CDEBUG(D_CACHE, "Do not permit different type of IO"
+					" for a same RPC\n");
+			return 0;
+		}
 
 		if (tmp->oe_srvlock != ext->oe_srvlock ||
 		    !tmp->oe_grants != !ext->oe_grants)
diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h
index d788dac..af96c7b 100644
--- a/drivers/staging/lustre/lustre/osc/osc_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_internal.h
@@ -160,11 +160,6 @@
 	return cli->cl_r_in_flight + cli->cl_w_in_flight;
 }
 
-#ifndef min_t
-#define min_t(type, x, y) \
-	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-#endif
-
 struct osc_device {
 	struct cl_device    od_cl;
 	struct obd_export  *od_exp;
diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c
index a7f08bc..4456557 100644
--- a/drivers/staging/lustre/lustre/osc/osc_lock.c
+++ b/drivers/staging/lustre/lustre/osc/osc_lock.c
@@ -100,14 +100,14 @@
 	/*
 	 * If all the following "ergo"s are true, return 1, otherwise 0
 	 */
-	if (! ergo(olock != NULL, handle_used))
+	if (!ergo(olock != NULL, handle_used))
 		return 0;
 
-	if (! ergo(olock != NULL,
+	if (!ergo(olock != NULL,
 		   olock->l_handle.h_cookie == ols->ols_handle.cookie))
 		return 0;
 
-	if (! ergo(handle_used,
+	if (!ergo(handle_used,
 		   ergo(lock != NULL && olock != NULL, lock == olock) &&
 		   ergo(lock == NULL, olock == NULL)))
 		return 0;
@@ -115,18 +115,18 @@
 	 * Check that ->ols_handle and ->ols_lock are consistent, but
 	 * take into account that they are set at the different time.
 	 */
-	if (! ergo(ols->ols_state == OLS_CANCELLED,
+	if (!ergo(ols->ols_state == OLS_CANCELLED,
 		   olock == NULL && !handle_used))
 		return 0;
 	/*
 	 * DLM lock is destroyed only after we have seen cancellation
 	 * ast.
 	 */
-	if (! ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
+	if (!ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
 		   ((olock->l_flags & LDLM_FL_DESTROYED) == 0)))
 		return 0;
 
-	if (! ergo(ols->ols_state == OLS_GRANTED,
+	if (!ergo(ols->ols_state == OLS_GRANTED,
 		   olock != NULL &&
 		   olock->l_req_mode == olock->l_granted_mode &&
 		   ols->ols_hold))
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index b9450b9..0adfa70 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -3332,7 +3332,7 @@
 extern spinlock_t osc_ast_guard;
 extern struct lock_class_key osc_ast_guard_class;
 
-int __init osc_init(void)
+static int __init osc_init(void)
 {
 	struct lprocfs_static_vars lvars = { NULL };
 	int rc;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index dc9e406..4882dd0 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -1247,7 +1247,9 @@
 		time_t	now = get_seconds();
 
 		DEBUG_REQ(D_RPCTRACE, req, "Resending request on EINPROGRESS");
+		spin_lock(&req->rq_lock);
 		req->rq_resend = 1;
+		spin_unlock(&req->rq_lock);
 		req->rq_nr_resend++;
 
 		/* allocate new xid to avoid reply reconstruction */
@@ -1497,11 +1499,13 @@
 int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
 {
 	struct list_head *tmp, *next;
+	struct list_head comp_reqs;
 	int force_timer_recalc = 0;
 
 	if (atomic_read(&set->set_remaining) == 0)
 		return 1;
 
+	INIT_LIST_HEAD(&comp_reqs);
 	list_for_each_safe(tmp, next, &set->set_requests) {
 		struct ptlrpc_request *req =
 			list_entry(tmp, struct ptlrpc_request,
@@ -1576,8 +1580,10 @@
 			ptlrpc_rqphase_move(req, req->rq_next_phase);
 		}
 
-		if (req->rq_phase == RQ_PHASE_COMPLETE)
+		if (req->rq_phase == RQ_PHASE_COMPLETE) {
+			list_move_tail(&req->rq_set_chain, &comp_reqs);
 			continue;
+		}
 
 		if (req->rq_phase == RQ_PHASE_INTERPRET)
 			goto interpret;
@@ -1860,9 +1866,15 @@
 			if (req->rq_status != 0)
 				set->set_rc = req->rq_status;
 			ptlrpc_req_finished(req);
+		} else {
+			list_move_tail(&req->rq_set_chain, &comp_reqs);
 		}
 	}
 
+	/* move completed request at the head of list so it's easier for
+	 * caller to find them */
+	list_splice(&comp_reqs, &set->set_requests);
+
 	/* If we hit an error, we want to recover promptly. */
 	return atomic_read(&set->set_remaining) == 0 || force_timer_recalc;
 }
diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c
index dc5ceb5..bbef666b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/layout.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c
@@ -65,7 +65,6 @@
 #endif
 /* struct ptlrpc_request, lustre_msg* */
 #include "../include/lustre_req_layout.h"
-#include "../include/lustre_update.h"
 #include "../include/lustre_acl.h"
 #include "../include/lustre_debug.h"
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index 4011e00..0e2071b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -45,7 +45,7 @@
 #include "ptlrpc_internal.h"
 
 
-struct ll_rpc_opcode {
+static struct ll_rpc_opcode {
 	__u32       opcode;
 	const char *opname;
 } ll_rpc_opcode_table[LUSTRE_MAX_OPCODES] = {
@@ -136,7 +136,7 @@
 	{ UPDATE_OBJ,	    "update_obj" },
 };
 
-struct ll_eopcode {
+static struct ll_eopcode {
 	__u32       opcode;
 	const char *opname;
 } ll_eopcode_table[EXTRA_LAST_OPC] = {
@@ -175,15 +175,17 @@
 	return ll_rpc_opcode_table[offset].opname;
 }
 
-const char *ll_eopcode2str(__u32 opcode)
+static const char *ll_eopcode2str(__u32 opcode)
 {
 	LASSERT(ll_eopcode_table[opcode].opcode == opcode);
 	return ll_eopcode_table[opcode].opname;
 }
+
 #if defined (CONFIG_PROC_FS)
-void ptlrpc_lprocfs_register(struct proc_dir_entry *root, char *dir,
-			     char *name, struct proc_dir_entry **procroot_ret,
-			     struct lprocfs_stats **stats_ret)
+static void ptlrpc_lprocfs_register(struct proc_dir_entry *root, char *dir,
+				    char *name,
+				    struct proc_dir_entry **procroot_ret,
+				    struct lprocfs_stats **stats_ret)
 {
 	struct proc_dir_entry *svc_procroot;
 	struct lprocfs_stats *svc_stats;
@@ -284,8 +286,9 @@
 }
 
 static ssize_t
-ptlrpc_lprocfs_req_history_max_seq_write(struct file *file, const char *buffer,
-					 size_t count, loff_t *off)
+ptlrpc_lprocfs_req_history_max_seq_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *off)
 {
 	struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
 	int			    bufpages;
@@ -329,8 +332,9 @@
 }
 
 static ssize_t
-ptlrpc_lprocfs_threads_min_seq_write(struct file *file, const char *buffer,
-				     size_t count, loff_t *off)
+ptlrpc_lprocfs_threads_min_seq_write(struct file *file,
+					const char __user *buffer,
+					size_t count, loff_t *off)
 {
 	struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
 	int	val;
@@ -381,8 +385,9 @@
 }
 
 static ssize_t
-ptlrpc_lprocfs_threads_max_seq_write(struct file *file, const char *buffer,
-				     size_t count, loff_t *off)
+ptlrpc_lprocfs_threads_max_seq_write(struct file *file,
+				const char __user *buffer,
+				size_t count, loff_t *off)
 {
 	struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
 	int	val;
@@ -723,7 +728,7 @@
 	struct ptlrpc_request	*srhi_req;
 };
 
-int
+static int
 ptlrpc_lprocfs_svc_req_history_seek(struct ptlrpc_service_part *svcpt,
 				    struct ptlrpc_srh_iterator *srhi,
 				    __u64 seq)
@@ -1025,7 +1030,7 @@
 }
 
 static ssize_t ptlrpc_lprocfs_hp_ratio_seq_write(struct file *file,
-					     const char *buffer,
+					     const char __user *buffer,
 					     size_t count,
 					     loff_t *off)
 {
@@ -1175,7 +1180,7 @@
 
 #define BUFLEN (UUID_MAX + 5)
 
-int lprocfs_wr_evict_client(struct file *file, const char *buffer,
+int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
 			    size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1223,7 +1228,7 @@
 
 #undef BUFLEN
 
-int lprocfs_wr_ping(struct file *file, const char *buffer,
+int lprocfs_wr_ping(struct file *file, const char __user *buffer,
 		    size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1251,7 +1256,7 @@
  * The connection UUID is a node's primary NID. For example,
  * "echo connection=192.168.0.1@tcp0::instance > .../import".
  */
-int lprocfs_wr_import(struct file *file, const char *buffer,
+int lprocfs_wr_import(struct file *file, const char __user *buffer,
 		      size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1329,7 +1334,7 @@
 }
 EXPORT_SYMBOL(lprocfs_rd_pinger_recov);
 
-int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
+int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer,
 		      size_t count, loff_t *off)
 {
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index cbcc541..4621b71 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -306,21 +306,16 @@
 	if (atomic_read(&set->set_remaining))
 		rc |= ptlrpc_check_set(env, set);
 
-	if (!list_empty(&set->set_requests)) {
-		/*
-		 * XXX: our set never completes, so we prune the completed
-		 * reqs after each iteration. boy could this be smarter.
-		 */
-		list_for_each_safe(pos, tmp, &set->set_requests) {
-			req = list_entry(pos, struct ptlrpc_request,
-					     rq_set_chain);
-			if (req->rq_phase != RQ_PHASE_COMPLETE)
-				continue;
+	/* NB: ptlrpc_check_set has already moved completed request at the
+	 * head of seq::set_requests */
+	list_for_each_safe(pos, tmp, &set->set_requests) {
+		req = list_entry(pos, struct ptlrpc_request, rq_set_chain);
+		if (req->rq_phase != RQ_PHASE_COMPLETE)
+			break;
 
-			list_del_init(&req->rq_set_chain);
-			req->rq_set = NULL;
-			ptlrpc_req_finished(req);
-		}
+		list_del_init(&req->rq_set_chain);
+		req->rq_set = NULL;
+		ptlrpc_req_finished(req);
 	}
 
 	if (rc == 0) {
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index c500aff..81de68e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -47,6 +47,8 @@
 #include "../include/lustre_net.h"
 #include "../include/lustre_sec.h"
 
+#include "ptlrpc_internal.h"
+
 #define SEC_GC_INTERVAL (30 * 60)
 
 
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 704fa20..a425f71 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -901,7 +901,7 @@
 	struct device *dev = ipipe->subdev.v4l2_dev->dev;
 
 	if (!gbce_param) {
-		memset(gbce, 0 , sizeof(struct vpfe_ipipe_gbce));
+		memset(gbce, 0, sizeof(struct vpfe_ipipe_gbce));
 	} else {
 		memcpy(gbce, gbce_param, sizeof(struct vpfe_ipipe_gbce));
 		if (ipipe_validate_gbce_params(gbce) < 0) {
@@ -1086,7 +1086,7 @@
 	struct vpfe_ipipe_car *car = &ipipe->config.car;
 
 	if (!car_param) {
-		memset(car , 0, sizeof(struct vpfe_ipipe_car));
+		memset(car, 0, sizeof(struct vpfe_ipipe_car));
 	} else {
 		memcpy(car, car_param, sizeof(struct vpfe_ipipe_car));
 		if (ipipe_validate_car_params(car) < 0) {
diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig
index 4031748..f3f9cb3 100644
--- a/drivers/staging/mt29f_spinand/Kconfig
+++ b/drivers/staging/mt29f_spinand/Kconfig
@@ -12,5 +12,5 @@
 	bool "Use SPINAND internal ECC"
 	depends on MTD_SPINAND_MT29F
 	help
-	  Internel ECC.
+	  Internal ECC.
 	  Enables Hardware ECC support for Micron SPI NAND.
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 3628bcb..3b191fc 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -626,7 +626,8 @@
 static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 		uint8_t *buf, int oob_required, int page)
 {
-	u8 retval, status;
+	int retval;
+	u8 status;
 	uint8_t *p = buf;
 	int eccsize = chip->ecc.size;
 	int eccsteps = chip->ecc.steps;
@@ -640,6 +641,13 @@
 
 	while (1) {
 		retval = spinand_read_status(info->spi, &status);
+		if (retval < 0) {
+			dev_err(&mtd->dev,
+					"error %d reading status register\n",
+					retval);
+			return retval;
+		}
+
 		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
 			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
 				pr_info("spinand: ECC error\n");
@@ -685,6 +693,13 @@
 
 	while (time_before(jiffies, timeo)) {
 		retval = spinand_read_status(info->spi, &status);
+		if (retval < 0) {
+			dev_err(&mtd->dev,
+					"error %d reading status register\n",
+					retval);
+			return retval;
+		}
+
 		if ((status & STATUS_OIP_MASK) == STATUS_READY)
 			return 0;
 
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
index 5ecb3e6..e8aae09 100644
--- a/drivers/staging/netlogic/xlr_net.c
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -788,7 +788,7 @@
 			xlr_nae_wreg(priv->base_addr, R_MAC_CONFIG_2, 0x7117);
 			priv->phy_speed = speed;
 		}
-		/* Set SGMII speed in Interface controll reg */
+		/* Set SGMII speed in Interface control reg */
 		if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
 			if (speed == SPEED_10)
 				xlr_nae_wreg(priv->base_addr,
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 120b70d..5868ebb 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -256,7 +256,7 @@
  * and return immediately.
  *
  * Returns: 0 on success, a negative error code on failure. If a failure
- * occured, the nvec driver may print an error.
+ * occurred, the nvec driver may print an error.
  */
 int nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
 			short size)
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 6b8b108..1daeb31 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -2687,7 +2687,7 @@
 
 	/*
 	 * Read the channel config info so we can figure out how much data
-	 * transfered
+	 * transferred
 	 */
 	usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb,
 			CVMX_USBCX_HCCHARX(channel, usb->index));
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index fcbe836..22667db 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -109,6 +109,7 @@
 		int interface = cvmx_helper_get_interface_num(work->ipprt);
 		int index = cvmx_helper_get_interface_index_num(work->ipprt);
 		union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
+
 		gmxx_rxx_frm_ctl.u64 =
 		    cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
 		if (gmxx_rxx_frm_ctl.s.pre_chk == 0) {
@@ -214,6 +215,7 @@
 		did_work_request = 0;
 		if (work == NULL) {
 			union cvmx_pow_wq_int wq_int;
+
 			wq_int.u64 = 0;
 			wq_int.s.iq_dis = 1 << pow_receive_group;
 			wq_int.s.wq_int = 1 << pow_receive_group;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index ee32149..460e854 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -798,7 +798,7 @@
 	cvm_oct_rx_initialize();
 
 	/*
-	 * 150 uS: about 10 1500-byte packtes at 1GE.
+	 * 150 uS: about 10 1500-byte packets at 1GE.
 	 */
 	cvm_oct_tx_poll_interval = 150 * (octeon_get_clock_rate() / 1000000);
 
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 6a9a881..bc7e664 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -780,7 +780,7 @@
 };
 MODULE_DEVICE_TABLE(i2c, dcon_idtable);
 
-struct i2c_driver dcon_driver = {
+static struct i2c_driver dcon_driver = {
 	.driver = {
 		.name	= "olpc_dcon",
 		.pm = &dcon_pm_ops,
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index 77e8eb5..0c5a10c 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -52,7 +52,7 @@
 	 * Determine the current state by reading the GPIO bit; earlier
 	 * stages of the boot process have established the state.
 	 *
-	 * Note that we read GPIO_OUPUT_VAL rather than GPIO_READ_BACK here;
+	 * Note that we read GPIO_OUTPUT_VAL rather than GPIO_READ_BACK here;
 	 * this is because OFW will disable input for the pin and set a value..
 	 * READ_BACK will only contain a valid value if input is enabled and
 	 * then a value is set.  So, future readings of the pin can use
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 98325b7..6ed35b6 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -130,6 +130,30 @@
 #define LCD_FLAG_N		0x0040	/* 2-rows mode */
 #define LCD_FLAG_L		0x0080	/* backlight enabled */
 
+/* LCD commands */
+#define LCD_CMD_DISPLAY_CLEAR	0x01	/* Clear entire display */
+
+#define LCD_CMD_ENTRY_MODE	0x04	/* Set entry mode */
+#define LCD_CMD_CURSOR_INC	0x02	/* Increment cursor */
+
+#define LCD_CMD_DISPLAY_CTRL	0x08	/* Display control */
+#define LCD_CMD_DISPLAY_ON	0x04	/* Set display on */
+#define LCD_CMD_CURSOR_ON	0x02	/* Set cursor on */
+#define LCD_CMD_BLINK_ON	0x01	/* Set blink on */
+
+#define LCD_CMD_SHIFT		0x10	/* Shift cursor/display */
+#define LCD_CMD_DISPLAY_SHIFT	0x08	/* Shift display instead of cursor */
+#define LCD_CMD_SHIFT_RIGHT	0x04	/* Shift display/cursor to the right */
+
+#define LCD_CMD_FUNCTION_SET	0x20	/* Set function */
+#define LCD_CMD_DATA_LEN_8BITS	0x10	/* Set data length to 8 bits */
+#define LCD_CMD_TWO_LINES	0x08	/* Set to two display lines */
+#define LCD_CMD_FONT_5X10_DOTS	0x04	/* Set char font to 5x10 dots */
+
+#define LCD_CMD_SET_CGRAM_ADDR	0x40	/* Set char generator RAM address */
+
+#define LCD_CMD_SET_DDRAM_ADDR	0x80	/* Set display data RAM address */
+
 #define LCD_ESCAPE_LEN		24	/* max chars for LCD escape command */
 #define LCD_ESCAPE_CHAR	27	/* use char 27 for escape command */
 
@@ -228,9 +252,6 @@
 	bool initialized;
 	bool must_clear;
 
-	/* TODO: use bool here? */
-	char left_shift;
-
 	int height;
 	int width;
 	int bwidth;
@@ -759,7 +780,7 @@
 	if (in_interrupt()) {
 		mdelay(ms);
 	} else {
-		current->state = TASK_INTERRUPTIBLE;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout((ms * HZ + 999) / 1000);
 	}
 }
@@ -886,7 +907,7 @@
 
 static void lcd_gotoxy(void)
 {
-	lcd_write_cmd(0x80	/* set DDRAM address */
+	lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR
 		      | (lcd.addr.y ? lcd.hwidth : 0)
 		      /* we force the cursor to stay at the end of the
 			 line if it wants to go farther */
@@ -994,7 +1015,7 @@
 /* clears the display and resets X/Y */
 static void lcd_clear_display(void)
 {
-	lcd_write_cmd(0x01);	/* clear display */
+	lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR);
 	lcd.addr.x = 0;
 	lcd.addr.y = 0;
 	/* we must wait a few milliseconds (15) */
@@ -1008,26 +1029,29 @@
 
 	long_sleep(20);		/* wait 20 ms after power-up for the paranoid */
 
-	lcd_write_cmd(0x30);	/* 8bits, 1 line, small fonts */
+	/* 8bits, 1 line, small fonts; let's do it 3 times */
+	lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
 	long_sleep(10);
-	lcd_write_cmd(0x30);	/* 8bits, 1 line, small fonts */
+	lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
 	long_sleep(10);
-	lcd_write_cmd(0x30);	/* 8bits, 1 line, small fonts */
+	lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
 	long_sleep(10);
 
-	lcd_write_cmd(0x30	/* set font height and lines number */
-		      | ((lcd.flags & LCD_FLAG_F) ? 4 : 0)
-		      | ((lcd.flags & LCD_FLAG_N) ? 8 : 0)
+	/* set font height and lines number */
+	lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS
+		      | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0)
+		      | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)
 	    );
 	long_sleep(10);
 
-	lcd_write_cmd(0x08);	/* display off, cursor off, blink off */
+	/* display off, cursor off, blink off */
+	lcd_write_cmd(LCD_CMD_DISPLAY_CTRL);
 	long_sleep(10);
 
-	lcd_write_cmd(0x08	/* set display mode */
-		      | ((lcd.flags & LCD_FLAG_D) ? 4 : 0)
-		      | ((lcd.flags & LCD_FLAG_C) ? 2 : 0)
-		      | ((lcd.flags & LCD_FLAG_B) ? 1 : 0)
+	lcd_write_cmd(LCD_CMD_DISPLAY_CTRL	/* set display mode */
+		      | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0)
+		      | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0)
+		      | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)
 	    );
 
 	lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0);
@@ -1035,7 +1059,7 @@
 	long_sleep(10);
 
 	/* entry mode set : increment, cursor shifting */
-	lcd_write_cmd(0x06);
+	lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
 
 	lcd_clear_display();
 }
@@ -1119,7 +1143,7 @@
 		if (lcd.addr.x > 0) {
 			/* back one char if not at end of line */
 			if (lcd.addr.x < lcd.bwidth)
-				lcd_write_cmd(0x10);
+				lcd_write_cmd(LCD_CMD_SHIFT);
 			lcd.addr.x--;
 		}
 		processed = 1;
@@ -1127,21 +1151,20 @@
 	case 'r':	/* shift cursor right */
 		if (lcd.addr.x < lcd.width) {
 			/* allow the cursor to pass the end of the line */
-			if (lcd.addr.x <
-			    (lcd.bwidth - 1))
-				lcd_write_cmd(0x14);
+			if (lcd.addr.x < (lcd.bwidth - 1))
+				lcd_write_cmd(LCD_CMD_SHIFT |
+						LCD_CMD_SHIFT_RIGHT);
 			lcd.addr.x++;
 		}
 		processed = 1;
 		break;
 	case 'L':	/* shift display left */
-		lcd.left_shift++;
-		lcd_write_cmd(0x18);
+		lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
 		processed = 1;
 		break;
 	case 'R':	/* shift display right */
-		lcd.left_shift--;
-		lcd_write_cmd(0x1C);
+		lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
+				LCD_CMD_SHIFT_RIGHT);
 		processed = 1;
 		break;
 	case 'k': {	/* kill end of line */
@@ -1157,7 +1180,6 @@
 	}
 	case 'I':	/* reinitialize display */
 		lcd_init_display();
-		lcd.left_shift = 0;
 		processed = 1;
 		break;
 	case 'G': {
@@ -1211,7 +1233,7 @@
 			esc++;
 		}
 
-		lcd_write_cmd(0x40 | (cgaddr * 8));
+		lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
 		for (addr = 0; addr < cgoffset; addr++)
 			lcd_write_data(cgbytes[addr]);
 
@@ -1244,21 +1266,29 @@
 		break;
 	}
 
+	/* TODO: This indent party here got ugly, clean it! */
 	/* Check whether one flag was changed */
 	if (oldflags != lcd.flags) {
 		/* check whether one of B,C,D flags were changed */
 		if ((oldflags ^ lcd.flags) &
 		    (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
 			/* set display mode */
-			lcd_write_cmd(0x08
-				      | ((lcd.flags & LCD_FLAG_D) ? 4 : 0)
-				      | ((lcd.flags & LCD_FLAG_C) ? 2 : 0)
-				      | ((lcd.flags & LCD_FLAG_B) ? 1 : 0));
+			lcd_write_cmd(LCD_CMD_DISPLAY_CTRL
+				      | ((lcd.flags & LCD_FLAG_D)
+						      ? LCD_CMD_DISPLAY_ON : 0)
+				      | ((lcd.flags & LCD_FLAG_C)
+						      ? LCD_CMD_CURSOR_ON : 0)
+				      | ((lcd.flags & LCD_FLAG_B)
+						      ? LCD_CMD_BLINK_ON : 0));
 		/* check whether one of F,N flags was changed */
 		else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N))
-			lcd_write_cmd(0x30
-				      | ((lcd.flags & LCD_FLAG_F) ? 4 : 0)
-				      | ((lcd.flags & LCD_FLAG_N) ? 8 : 0));
+			lcd_write_cmd(LCD_CMD_FUNCTION_SET
+				      | LCD_CMD_DATA_LEN_8BITS
+				      | ((lcd.flags & LCD_FLAG_F)
+						      ? LCD_CMD_TWO_LINES : 0)
+				      | ((lcd.flags & LCD_FLAG_N)
+						      ? LCD_CMD_FONT_5X10_DOTS
+								      : 0));
 		/* check whether L flag was changed */
 		else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) {
 			if (lcd.flags & (LCD_FLAG_L))
@@ -1297,13 +1327,13 @@
 				   end of the line */
 				if (lcd.addr.x < lcd.bwidth)
 					/* back one char */
-					lcd_write_cmd(0x10);
+					lcd_write_cmd(LCD_CMD_SHIFT);
 				lcd.addr.x--;
 			}
 			/* replace with a space */
 			lcd_write_data(' ');
 			/* back one char again */
-			lcd_write_cmd(0x10);
+			lcd_write_cmd(LCD_CMD_SHIFT);
 			break;
 		case '\014':
 			/* quickly clear the display */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index d61842e..da19145 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -509,7 +509,7 @@
 		tx_ra_bitmap |= ((raid<<28)&0xf0000000);
 
 		DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
-			__func__ , psta->mac_id, raid , tx_ra_bitmap, arg);
+			__func__, psta->mac_id, raid, tx_ra_bitmap, arg);
 
 		/* bitmap[0:27] = tx_rate_bitmap */
 		/* bitmap[28:31]= Rate Adaptive id */
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index e4b7ee4c..cd12dd7 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -484,17 +484,8 @@
 		/* fall through */
 	case WIFI_ASSOCREQ:
 	case WIFI_REASSOCREQ:
-		_mgt_dispatcher(padapter, ptable, precv_frame);
-		break;
 	case WIFI_PROBEREQ:
-		if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
-			_mgt_dispatcher(padapter, ptable, precv_frame);
-		else
-			_mgt_dispatcher(padapter, ptable, precv_frame);
-		break;
 	case WIFI_BEACON:
-		_mgt_dispatcher(padapter, ptable, precv_frame);
-		break;
 	case WIFI_ACTION:
 		_mgt_dispatcher(padapter, ptable, precv_frame);
 		break;
@@ -577,13 +568,14 @@
 	uint len = precv_frame->len;
 	struct wlan_bssid_ex *pbss;
 	int ret = _SUCCESS;
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
 
 	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
 		report_survey_event(padapter, precv_frame);
 		return _SUCCESS;
 	}
 
-	if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+	if (!memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) {
 		if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
 			/* we should update current network before auth, or some IE is wrong */
 			pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex));
@@ -1445,10 +1437,10 @@
 	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	u8 *pframe = precv_frame->rx_data;
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
 
 	/* check A3 */
-	if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
-		   ETH_ALEN))
+	if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN))
 		return _SUCCESS;
 
 	reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
@@ -1499,10 +1491,10 @@
 	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	u8 *pframe = precv_frame->rx_data;
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
 
 	/* check A3 */
-	if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
-		   ETH_ALEN))
+	if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN))
 		return _SUCCESS;
 
 	reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
@@ -2018,7 +2010,7 @@
 
 	memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
 	/* pmlmeext->mgnt_seq++; */
@@ -2422,6 +2414,7 @@
 	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
 	if (pmgntframe == NULL)
@@ -2487,9 +2480,9 @@
 	} else {
 		__le32 le_tmp32;
 		__le16 le_tmp16;
-		memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+		memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
 		memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
-		memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 		/*  setting auth algo number */
 		val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/*  0:OPEN System, 1:Shared key */
@@ -2582,7 +2575,7 @@
 
 	memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN);
 	memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy((void *)GetAddr3Ptr(pwlanhdr), pnetwork->MacAddress, ETH_ALEN);
 
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
@@ -2687,6 +2680,7 @@
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	int	bssrate_len = 0, sta_bssrate_len = 0;
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
 	if (pmgntframe == NULL)
@@ -2702,9 +2696,9 @@
 
 	fctrl = &(pwlanhdr->frame_ctl);
 	*(fctrl) = 0;
-	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -2879,6 +2873,7 @@
 	struct xmit_priv	*pxmitpriv;
 	struct mlme_ext_priv	*pmlmeext;
 	struct mlme_ext_info	*pmlmeinfo;
+	struct wlan_bssid_ex    *pnetwork;
 
 	if (!padapter)
 		goto exit;
@@ -2886,6 +2881,7 @@
 	pxmitpriv = &(padapter->xmitpriv);
 	pmlmeext = &(padapter->mlmeextpriv);
 	pmlmeinfo = &(pmlmeext->mlmext_info);
+	pnetwork = &(pmlmeinfo->network);
 
 	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
 	if (pmgntframe == NULL)
@@ -2914,7 +2910,7 @@
 
 	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -2946,10 +2942,11 @@
 	u32 start = jiffies;
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	/* da == NULL, assume it's null data for sta to ap*/
 	if (da == NULL)
-		da = get_my_bssid(&(pmlmeinfo->network));
+		da = pnetwork->MacAddress;
 
 	do {
 		ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false);
@@ -2995,6 +2992,7 @@
 	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	DBG_88E("%s\n", __func__);
 
@@ -3038,7 +3036,7 @@
 
 	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -3069,10 +3067,11 @@
 	u32 start = jiffies;
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	/* da == NULL, assume it's null data for sta to ap*/
 	if (da == NULL)
-		da = get_my_bssid(&(pmlmeinfo->network));
+		da = pnetwork->MacAddress;
 
 	do {
 		ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false);
@@ -3115,6 +3114,7 @@
 	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
 	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 	int ret = _FAIL;
 	__le16 le_tmp;
 
@@ -3137,7 +3137,7 @@
 
 	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -3288,6 +3288,7 @@
 	struct sta_info *psta;
 	struct sta_priv *pstapriv = &padapter->stapriv;
 	struct registry_priv *pregpriv = &padapter->registrypriv;
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
 
@@ -3310,7 +3311,7 @@
 	/* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
 	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -3420,6 +3421,8 @@
 	struct __queue *queue	= &(pmlmepriv->scanned_queue);
 	u8 InfoContent[16] = {0};
 	u8 ICS[8][15];
+	struct wlan_bssid_ex  *cur_network   = &(pmlmeinfo->network);
+
 	if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0))
 		return;
 
@@ -3449,9 +3452,9 @@
 	fctrl = &(pwlanhdr->frame_ctl);
 	*(fctrl) = 0;
 
-	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr1, cur_network->MacAddress, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
 	pmlmeext->mgnt_seq++;
@@ -4042,9 +4045,10 @@
 {
 	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex    *pnetwork = &(pmlmeinfo->network);
 
 	/* check A3 */
-	if (memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))
+	if (memcmp(MacAddr, pnetwork->MacAddress, ETH_ALEN))
 		return _SUCCESS;
 
 	DBG_88E("%s\n", __func__);
@@ -4924,11 +4928,6 @@
 	}
 }
 
-u8 NULL_hdl(struct adapter *padapter, u8 *pbuf)
-{
-	return H2C_SUCCESS;
-}
-
 u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
 {
 	u8 type;
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 324c1a7..a3ffc69 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -405,11 +405,6 @@
 		return 0;
 }
 
-__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
-{
-	return pnetwork->MacAddress;
-}
-
 u16 get_beacon_interval(struct wlan_bssid_ex *bss)
 {
 	__le16 val;
@@ -936,6 +931,8 @@
 	}
 
 	bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
+	if (!bssid)
+		return _FAIL;
 
 	subtype = GetFrameSubType(pframe) >> 4;
 
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 9873998..06477e8 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -534,13 +534,8 @@
 	pDM_DigTable->RssiHighThresh	= DM_DIG_THRESH_HIGH;
 	pDM_DigTable->FALowThresh	= DM_false_ALARM_THRESH_LOW;
 	pDM_DigTable->FAHighThresh	= DM_false_ALARM_THRESH_HIGH;
-	if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
-		pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
-		pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
-	} else {
-		pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
-		pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
-	}
+	pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+	pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
 	pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT;
 	pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX;
 	pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN;
@@ -1138,16 +1133,9 @@
 {
 	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
 	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
-	struct mlme_priv	*pmlmepriv = &pAdapter->mlmepriv;
 
-	/* 1 1.Determine the minimum RSSI */
-	if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) &&
-	    (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0))
-		pdmpriv->MinUndecoratedPWDBForDM = 0;
-	if (check_fwstate(pmlmepriv, _FW_LINKED) == true)	/*  Default port */
-		pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
-	else /*  associated entry pwdb */
-		pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+	/* 1 1.Unconditionally set RSSI */
+	pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
 }
 
 void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
index 7f30dea..86347f2 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -127,22 +127,6 @@
 	return ret;
 }
 
-u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param)
-{
-	u8 res = _SUCCESS;
-	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
-
-	if (haldata->fw_ractrl) {
-		;
-	} else {
-		DBG_88E("==>%s fw dont support RA\n", __func__);
-		res = _FAIL;
-	}
-
-
-	return res;
-}
-
 u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask)
 {
 	u8 buf[3];
@@ -276,7 +260,7 @@
 
 	memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
 	memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
-	memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
 
 	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
 	SetFrameSubType(pframe, WIFI_BEACON);
@@ -350,6 +334,7 @@
 	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
 	__le16 *fctrl;
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
 
 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
 
@@ -363,7 +348,7 @@
 	SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
 
 	/*  BSSID. */
-	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
 
 	/*  TA. */
 	memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
@@ -386,6 +371,7 @@
 	struct wlan_network		*cur_network = &pmlmepriv->cur_network;
 	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
 	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
 
 	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
 
@@ -397,21 +383,21 @@
 	switch (cur_network->network.InfrastructureMode) {
 	case Ndis802_11Infrastructure:
 		SetToDs(fctrl);
-		memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
 		memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
 		memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
 		break;
 	case Ndis802_11APMode:
 		SetFrDs(fctrl);
 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
-		memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		memcpy(pwlanhdr->addr2, pnetwork->MacAddress, ETH_ALEN);
 		memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN);
 		break;
 	case Ndis802_11IBSS:
 	default:
 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
 		memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
-		memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
 		break;
 	}
 
@@ -498,6 +484,7 @@
 	u16 BufIndex;
 	u32 TotalPacketLen;
 	struct rsvdpage_loc RsvdPageLoc;
+	struct wlan_bssid_ex *pnetwork;
 
 	DBG_88E("%s\n", __func__);
 	ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
@@ -510,6 +497,7 @@
 	pxmitpriv = &adapt->xmitpriv;
 	pmlmeext = &adapt->mlmeextpriv;
 	pmlmeinfo = &pmlmeext->mlmext_info;
+	pnetwork = &(pmlmeinfo->network);
 
 	TxDescLen = TXDESC_SIZE;
 	PageNum = 0;
@@ -541,7 +529,7 @@
 
 	/* 3 (3) null data * 1 page */
 	RsvdPageLoc.LocNullData = PageNum;
-	ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false);
+	ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, pnetwork->MacAddress, false, 0, 0, false);
 	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
 
 	PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
@@ -551,7 +539,7 @@
 
 	/* 3 (4) probe response * 1page */
 	RsvdPageLoc.LocProbeRsp = PageNum;
-	ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false);
+	ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, pnetwork->MacAddress, false);
 	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
 
 	PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
@@ -562,7 +550,7 @@
 	/* 3 (5) Qos null data */
 	RsvdPageLoc.LocQosNull = PageNum;
 	ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
-				  &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false);
+				  &QosNullLength, pnetwork->MacAddress, true, 0, 0, false);
 	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
 
 	PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 7d460ea..3222d8d 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -242,20 +242,6 @@
 	pHalFunc->hal_notch_filter = &hal_notch_filter_8188e;
 }
 
-u8 GetEEPROMSize8188E(struct adapter *padapter)
-{
-	u8 size = 0;
-	u32	cr;
-
-	cr = usb_read16(padapter, REG_9346CR);
-	/*  6: EEPROM used is 93C46, 4: boot from E-Fuse. */
-	size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
-
-	MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
-
-	return size;
-}
-
 /*  */
 /*  */
 /*  LLT R/W/Init function */
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index 82f58f8..3a27477 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -87,7 +87,7 @@
 
 static inline void _set_timer(struct timer_list *ptimer, u32 delay_time)
 {
-	mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
+	mod_timer(ptimer , (jiffies+msecs_to_jiffies(delay_time)));
 }
 
 #define RTW_TIMER_HDL_ARGS void *FunctionContext
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
index 0e78e2a..42b1f22 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
@@ -107,7 +107,6 @@
 /*  host message to firmware cmd */
 void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode);
 void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus);
-u8 rtl8188e_set_rssi_cmd(struct adapter *padapter, u8 *param);
 u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask);
 void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg,
 			   u8 rssi_level);
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
index 42ab1d2..b8c42ee 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -391,7 +391,6 @@
 s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
 
 /*  EFuse */
-u8 GetEEPROMSize8188E(struct adapter *padapter);
 void Hal_InitPGData88E(struct adapter *padapter);
 void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo);
 void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *hwinfo,
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index 8d72ccf..4f05aee 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -496,7 +496,6 @@
 		    struct adapter *adapter, bool update_ie);
 
 int get_bsstype(unsigned short capability);
-u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork);
 u16 get_beacon_interval(struct wlan_bssid_ex *bss);
 
 int is_client_associated_to_ap(struct adapter *padapter);
@@ -516,7 +515,7 @@
 void VCS_update(struct adapter *padapter, struct sta_info *psta);
 
 void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len,
-		        struct sta_info *psta);
+			struct sta_info *psta);
 int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len);
 void update_IOT_info(struct adapter *padapter);
 void update_capinfo(struct adapter *adapter, u16 updatecap);
@@ -679,7 +678,6 @@
 u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
 u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
 u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
-u8 NULL_hdl(struct adapter *padapter, u8 *pbuf);
 u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf);
 u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf);
 u8 createbss_hdl(struct adapter *padapter, u8 *pbuf);
diff --git a/drivers/staging/rtl8188eu/include/usb_ops_linux.h b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
index 01b3810..4fdc536 100644
--- a/drivers/staging/rtl8188eu/include/usb_ops_linux.h
+++ b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
@@ -79,7 +79,6 @@
 int usb_write8(struct adapter *adapter, u32 addr, u8 val);
 int usb_write16(struct adapter *adapter, u32 addr, u16 val);
 int usb_write32(struct adapter *adapter, u32 addr, u32 val);
-int usb_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata);
 
 u32 usb_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
 void usb_write_port_cancel(struct adapter *adapter);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index d2efa9d..80e7ef9 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -615,33 +615,6 @@
 	return ret;
 }
 
-int usb_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata)
-{
-	u8 request;
-	u8 requesttype;
-	u16 wvalue;
-	u16 index;
-	u16 len;
-	u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
-	int ret;
-
-
-	request = 0x05;
-	requesttype = 0x00;/* write_out */
-	index = 0;/* n/a */
-
-	wvalue = (u16)(addr&0x0000ffff);
-	len = length;
-	 memcpy(buf, pdata, len);
-
-	ret = usbctrl_vendorreq(adapter, request, wvalue, index, buf, len, requesttype);
-
-
-	return RTW_STATUS_CODE(ret);
-}
-
-
-
 static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
 {
 	struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
index 6c64e08..89ea70b 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
@@ -167,35 +167,6 @@
 	RT_TRACE(COMP_SEC, "=========>after set key, usconfig:%x\n", usConfig);
 }
 
-void CAM_read_entry(struct net_device *dev, u32 iIndex)
-{
-	u32 target_command = 0;
-	u32 target_content = 0;
-	u8 entry_i = 0;
-	u32 ulStatus;
-	s32 i = 100;
-
-	for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
-		target_command = entry_i+CAM_CONTENT_COUNT*iIndex;
-		target_command = target_command | BIT31;
-
-		while ((i--) >= 0) {
-			ulStatus = read_nic_dword(dev, RWCAM);
-			if (ulStatus & BIT31)
-				continue;
-			else
-				break;
-		}
-		write_nic_dword(dev, RWCAM, target_command);
-		RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A0: %x\n",
-			 target_command);
-		target_content = read_nic_dword(dev, RCAMO);
-		RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A8: %x\n",
-			 target_content);
-	}
-	printk(KERN_INFO "\n");
-}
-
 void CamRestoreAllEntry(struct net_device *dev)
 {
 	u8 EntryId = 0;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
index 7d075d3..3c4c0e6 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
@@ -41,6 +41,4 @@
 
 void CamRestoreAllEntry(struct net_device *dev);
 
-void CAM_read_entry(struct net_device *dev, u32 iIndex);
-
 #endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 885315c..b8891c6 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -1661,8 +1661,8 @@
 		dm_digtable.rssi_low_thresh = dm_value;
 	} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
 		dm_digtable.rssi_high_power_highthresh = dm_value;
-	} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
-		dm_digtable.rssi_high_power_highthresh = dm_value;
+	} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_LOW) {
+		dm_digtable.rssi_high_power_lowthresh = dm_value;
 	} else if (dm_type == DIG_TYPE_ENABLE) {
 		dm_digtable.dig_state		= DM_STA_DIG_MAX;
 		dm_digtable.dig_enable_flag	= true;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
index 8e1a5d5..0b4f764 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
@@ -22,12 +22,6 @@
 #include "r8190P_rtl8256.h"
 #include "rtl_pm.h"
 
-int rtl8192E_save_state(struct pci_dev *dev, pm_message_t state)
-{
-	printk(KERN_NOTICE "r8192E save state call (state %u).\n", state.event);
-	return -EAGAIN;
-}
-
 
 int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state)
 {
@@ -124,11 +118,3 @@
 	return 0;
 }
 
-
-int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable)
-{
-	printk(KERN_NOTICE "r8192E enable wake call (state %u, enable %d).\n",
-	       state.event, enable);
-	return -EAGAIN;
-}
-
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
index e5299fc..7bfe448 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
@@ -23,9 +23,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-int rtl8192E_save_state(struct pci_dev *dev, pm_message_t state);
 int rtl8192E_suspend(struct pci_dev *dev, pm_message_t state);
 int rtl8192E_resume(struct pci_dev *dev);
-int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable);
 
 #endif
diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c
index c7f4508..1ea426b 100644
--- a/drivers/staging/rtl8192e/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c
@@ -34,13 +34,13 @@
 	 468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182,
 	 182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156,
 	 181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273,
-	 312, 351, 312, 351, 390, 390, 429} ,
+	 312, 351, 312, 351, 390, 390, 429},
 	{14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289,
 	 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520,
 	 578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231,
 	 173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260,
 	 231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390,
-	 433, 433, 477} } ,
+	 433, 433, 477} },
 	{{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486,
 	 540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648,
 	 864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324,
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index 91e98e8..0cf3809 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -202,9 +202,7 @@
 EXPORT_SYMBOL(free_rtllib);
 
 u32 rtllib_debug_level;
-static int debug = \
-			    RTLLIB_DL_ERR
-			    ;
+static int debug = RTLLIB_DL_ERR;
 static struct proc_dir_entry *rtllib_proc;
 
 static int show_debug_level(struct seq_file *m, void *v)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index cf11b04..1664040 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -70,8 +70,7 @@
 		if (entry->skb != NULL &&
 		    time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
 			RTLLIB_DEBUG_FRAG(
-				"expiring fragment cache entry "
-				"seq=%u last_frag=%u\n",
+				"expiring fragment cache entry seq=%u last_frag=%u\n",
 				entry->seq, entry->last_frag);
 			dev_kfree_skb_any(entry->skb);
 			entry->skb = NULL;
@@ -188,8 +187,7 @@
 
 	if (entry == NULL) {
 		RTLLIB_DEBUG_FRAG(
-			"could not invalidate fragment cache "
-			"entry (seq=%u)\n", seq);
+			"could not invalidate fragment cache entry (seq=%u)\n", seq);
 		return -1;
 	}
 
@@ -305,11 +303,9 @@
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
 		RTLLIB_DEBUG_DROP(
-			"decryption failed (SA= %pM"
-			") res=%d\n", hdr->addr2, res);
+			"decryption failed (SA= %pM) res=%d\n", hdr->addr2, res);
 		if (res == -2)
-			RTLLIB_DEBUG_DROP("Decryption failed ICV "
-					     "mismatch (key %d)\n",
+			RTLLIB_DEBUG_DROP("Decryption failed ICV mismatch (key %d)\n",
 					     skb->data[hdrlen + 3] >> 6);
 		ieee->ieee_stats.rx_discards_undecryptable++;
 		return -1;
@@ -345,8 +341,7 @@
 	res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
-		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
-		       " (SA= %pM keyidx=%d)\n",
+		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed (SA= %pM keyidx=%d)\n",
 		       ieee->dev->name, hdr->addr2, keyidx);
 		return -1;
 	}
@@ -559,8 +554,7 @@
 	bool bMatchWinStart = false, bPktInBuf = false;
 	unsigned long flags;
 
-	RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Seq is %d, pTS->RxIndicateSeq"
-		     " is %d, WinSize is %d\n", __func__, SeqNum,
+	RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Seq is %d, pTS->RxIndicateSeq is %d, WinSize is %d\n", __func__, SeqNum,
 		     pTS->RxIndicateSeq, WinSize);
 
 	spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
@@ -600,8 +594,7 @@
 			pTS->RxIndicateSeq = SeqNum + 1 - WinSize;
 		else
 			pTS->RxIndicateSeq = 4095 - (WinSize - (SeqNum + 1)) + 1;
-		RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Window Shift! IndicateSeq: %d,"
-			     " NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum);
+		RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum);
 	}
 
 	/*
@@ -617,8 +610,7 @@
 	 */
 	if (bMatchWinStart) {
 		/* Current packet is going to be indicated.*/
-		RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packets indication!! "
-				"IndicateSeq: %d, NewSeq: %d\n",
+		RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n",
 				pTS->RxIndicateSeq, SeqNum);
 		ieee->prxbIndicateArray[0] = prxb;
 		index = 1;
@@ -636,9 +628,7 @@
 
 			if (!AddReorderEntry(pTS, pReorderEntry)) {
 				RTLLIB_DEBUG(RTLLIB_DL_REORDER,
-					     "%s(): Duplicate packet is "
-					     "dropped!! IndicateSeq: %d, "
-					     "NewSeq: %d\n",
+					     "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n",
 					    __func__, pTS->RxIndicateSeq,
 					    SeqNum);
 				list_add_tail(&pReorderEntry->List,
@@ -652,8 +642,7 @@
 				}
 			} else {
 				RTLLIB_DEBUG(RTLLIB_DL_REORDER,
-					 "Pkt insert into struct buffer!! "
-					 "IndicateSeq: %d, NewSeq: %d\n",
+					 "Pkt insert into struct buffer!! IndicateSeq: %d, NewSeq: %d\n",
 					 pTS->RxIndicateSeq, SeqNum);
 			}
 		} else {
@@ -663,9 +652,7 @@
 			 * indicate all the packets in struct buffer and get
 			 * reorder entries.
 			 */
-			RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():"
-				     " There is no reorder entry!! Packet is "
-				     "dropped!!\n");
+			RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n");
 			{
 				int i;
 
@@ -687,8 +674,7 @@
 				SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) {
 			/* This protect struct buffer from overflow. */
 			if (index >= REORDER_WIN_SIZE) {
-				RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicate"
-					     "Packet(): Buffer overflow!!\n");
+				RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!!\n");
 				bPktInBuf = true;
 				break;
 			}
@@ -699,8 +685,7 @@
 				pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096;
 
 			ieee->prxbIndicateArray[index] = pReorderEntry->prxb;
-			RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum"
-				     " %d!\n", __func__, pReorderEntry->SeqNum);
+			RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum %d!\n", __func__, pReorderEntry->SeqNum);
 			index++;
 
 			list_add_tail(&pReorderEntry->List,
@@ -719,8 +704,7 @@
 		pTS->RxTimeoutIndicateSeq = 0xffff;
 
 		if (index > REORDER_WIN_SIZE) {
-			RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():"
-				     " Rx Reorder struct buffer full!!\n");
+			RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder struct buffer full!!\n");
 			spin_unlock_irqrestore(&(ieee->reorder_spinlock),
 					       flags);
 			return;
@@ -809,14 +793,11 @@
 					   (nSubframe_Length << 8);
 
 			if (skb->len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
-				printk(KERN_INFO "%s: A-MSDU parse error!! "
-				       "pRfd->nTotalSubframe : %d\n",\
+				printk(KERN_INFO "%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",\
 				       __func__, rxb->nr_subframes);
-				printk(KERN_INFO "%s: A-MSDU parse error!! "
-				       "Subframe Length: %d\n", __func__,
+				printk(KERN_INFO "%s: A-MSDU parse error!! Subframe Length: %d\n", __func__,
 				       nSubframe_Length);
-				printk(KERN_INFO "nRemain_Length is %d and "
-				       "nSubframe_Length is : %d\n", skb->len,
+				printk(KERN_INFO "nRemain_Length is %d and nSubframe_Length is : %d\n", skb->len,
 				       nSubframe_Length);
 				printk(KERN_INFO "The Packet SeqNum is %d\n", SeqNum);
 				return 0;
@@ -844,8 +825,7 @@
 			sub_skb->dev = ieee->dev;
 			rxb->subframes[rxb->nr_subframes++] = sub_skb;
 			if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) {
-				RTLLIB_DEBUG_RX("ParseSubframe(): Too many "
-						"Subframes! Packets dropped!\n");
+				RTLLIB_DEBUG_RX("ParseSubframe(): Too many Subframes! Packets dropped!\n");
 				break;
 			}
 			skb_pull(skb, nSubframe_Length);
@@ -922,8 +902,7 @@
 			pRxTS->RxLastFragNum = frag;
 			pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc);
 		} else {
-			RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR!!%s(): No TS!! Skip"
-				     " the check!!\n", __func__);
+			RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR!!%s(): No TS!! Skip the check!!\n", __func__);
 			return -1;
 		}
 	}
@@ -996,9 +975,7 @@
 		    stype != RTLLIB_STYPE_QOS_DATA) {
 			if (stype != RTLLIB_STYPE_NULLFUNC)
 				RTLLIB_DEBUG_DROP(
-					"RX: dropped data frame "
-					"with no data (type=0x%02x, "
-					"subtype=0x%02x)\n",
+					"RX: dropped data frame with no data (type=0x%02x, subtype=0x%02x)\n",
 					type, stype);
 			return -1;
 		}
@@ -1041,8 +1018,7 @@
 			 * frames from other than current BSS, so just drop the
 			 * frames silently instead of filling system log with
 			 * these reports. */
-			RTLLIB_DEBUG_DROP("Decryption failed (not set)"
-					     " (SA= %pM)\n",
+			RTLLIB_DEBUG_DROP("Decryption failed (not set) (SA= %pM)\n",
 					     hdr->addr2);
 			ieee->ieee_stats.rx_discards_undecryptable++;
 			return -1;
@@ -1086,8 +1062,7 @@
 
 		if (!frag_skb) {
 			RTLLIB_DEBUG(RTLLIB_DL_RX | RTLLIB_DL_FRAG,
-					"Rx cannot get skb from fragment "
-					"cache (morefrag=%d seq=%u frag=%u)\n",
+					"Rx cannot get skb from fragment cache (morefrag=%d seq=%u frag=%u)\n",
 					(fc & RTLLIB_FCTL_MOREFRAGS) != 0,
 					WLAN_GET_SEQ_SEQ(sc), frag);
 			return -1;
@@ -1097,8 +1072,7 @@
 			flen -= hdrlen;
 
 		if (frag_skb->tail + flen > frag_skb->end) {
-			printk(KERN_WARNING "%s: host decrypted and "
-			       "reassembled frame did not fit skb\n",
+			printk(KERN_WARNING "%s: host decrypted and reassembled frame did not fit skb\n",
 			       __func__);
 			rtllib_frag_cache_invalidate(ieee, hdr);
 			return -1;
@@ -1152,8 +1126,7 @@
 						eap_get_type(eap->type));
 		} else {
 			RTLLIB_DEBUG_DROP(
-				"encryption configured, but RX "
-				"frame not encrypted (SA= %pM)\n",
+				"encryption configured, but RX frame not encrypted (SA= %pM)\n",
 				hdr->addr2);
 			return -1;
 		}
@@ -1170,9 +1143,7 @@
 	if (crypt && !(fc & RTLLIB_FCTL_WEP) && !ieee->open_wep &&
 	    !rtllib_is_eapol_frame(ieee, skb, hdrlen)) {
 		RTLLIB_DEBUG_DROP(
-			"dropped unencrypted RX data "
-			"frame from %pM"
-			" (drop_unencrypted=1)\n",
+			"dropped unencrypted RX data frame from %pM (drop_unencrypted=1)\n",
 			hdr->addr2);
 		return -1;
 	}
@@ -1762,9 +1733,7 @@
 
 	while (length >= sizeof(*info_element)) {
 		if (sizeof(*info_element) + info_element->len > length) {
-			RTLLIB_DEBUG_MGMT("Info elem: parse failed: "
-					     "info_element->len + 2 > left : "
-					     "info_element->len+2=%zd left=%d, id=%d.\n",
+			RTLLIB_DEBUG_MGMT("Info elem: parse failed: info_element->len + 2 > left : info_element->len+2=%zd left=%d, id=%d.\n",
 					     info_element->len +
 					     sizeof(*info_element),
 					     length, info_element->id);
@@ -2207,34 +2176,6 @@
 	return 0;
 }
 
-static inline u8 rtllib_SignalStrengthTranslate(u8  CurrSS)
-{
-	u8 RetSS;
-
-	if (CurrSS >= 71 && CurrSS <= 100)
-		RetSS = 90 + ((CurrSS - 70) / 3);
-	else if (CurrSS >= 41 && CurrSS <= 70)
-		RetSS = 78 + ((CurrSS - 40) / 3);
-	else if (CurrSS >= 31 && CurrSS <= 40)
-		RetSS = 66 + (CurrSS - 30);
-	else if (CurrSS >= 21 && CurrSS <= 30)
-		RetSS = 54 + (CurrSS - 20);
-	else if (CurrSS >= 5 && CurrSS <= 20)
-		RetSS = 42 + (((CurrSS - 5) * 2) / 3);
-	else if (CurrSS == 4)
-		RetSS = 36;
-	else if (CurrSS == 3)
-		RetSS = 27;
-	else if (CurrSS == 2)
-		RetSS = 18;
-	else if (CurrSS == 1)
-		RetSS = 9;
-	else
-		RetSS = CurrSS;
-
-	return RetSS;
-}
-
 static long rtllib_translate_todbm(u8 signal_strength_index)
 {
 	long	signal_power;
@@ -2321,8 +2262,7 @@
 	}
 
 	if (network->mode == 0) {
-		RTLLIB_DEBUG_SCAN("Filtered out '%s (%pM)' "
-				     "network.\n",
+		RTLLIB_DEBUG_SCAN("Filtered out '%s (%pM)' network.\n",
 				     escape_essid(network->ssid,
 						  network->ssid_len),
 				     network->bssid);
@@ -2363,13 +2303,6 @@
 		(dst->capability & WLAN_CAPABILITY_ESS)));
 }
 
-static inline void update_ibss_network(struct rtllib_network *dst,
-				  struct rtllib_network *src)
-{
-	memcpy(&dst->stats, &src->stats, sizeof(struct rtllib_rx_stats));
-	dst->last_scanned = jiffies;
-}
-
 
 static inline void update_network(struct rtllib_network *dst,
 				  struct rtllib_network *src)
@@ -2568,8 +2501,7 @@
 	if (WLAN_FC_GET_STYPE(le16_to_cpu(beacon->header.frame_ctl)) ==
 	    RTLLIB_STYPE_PROBE_RESP) {
 		if (IsPassiveChannel(ieee, network->channel)) {
-			printk(KERN_INFO "GetScanInfo(): For Global Domain, "
-			       "filter probe response at channel(%d).\n",
+			printk(KERN_INFO "GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n",
 			       network->channel);
 			goto free_network;
 		}
@@ -2618,8 +2550,7 @@
 			/* If there are no more slots, expire the oldest */
 			list_del(&oldest->list);
 			target = oldest;
-			RTLLIB_DEBUG_SCAN("Expired '%s' ( %pM) from "
-					     "network list.\n",
+			RTLLIB_DEBUG_SCAN("Expired '%s' ( %pM) from network list.\n",
 					     escape_essid(target->ssid,
 							  target->ssid_len),
 					     target->bssid);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index cd196ce..1b4623c 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -4,6 +4,8 @@
  * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue.
  * WB 2008-05-27
  * *****************************************************************************************************************************/
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
 #include "ieee80211.h"
 #include "rtl819x_BA.h"
 
@@ -110,13 +112,12 @@
 	struct sk_buff *skb = NULL;
 	 struct ieee80211_hdr_3addr *BAReq = NULL;
 	u8 *tag = NULL;
-	__le16 tmp = 0;
 	u16 len = ieee->tx_headroom + 9;
 	//category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) +  BA Timeout Value(2) +  BA Start SeqCtrl(2)(or StatusCode(2))
 	IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __func__, type, Dst, ieee->dev);
-	if (pBA == NULL||ieee == NULL)
+	if (pBA == NULL)
 	{
-		IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
+		IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA is NULL\n");
 		return NULL;
 	}
 	skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME
@@ -149,17 +150,17 @@
 	{
 		// Status Code
 		printk("=====>to send ADDBARSP\n");
-		tmp = cpu_to_le16(StatusCode);
-		memcpy(tag, (u8 *)&tmp, 2);
+
+		put_unaligned_le16(StatusCode, tag);
 		tag += 2;
 	}
 	// BA Parameter Set
-	tmp = cpu_to_le16(pBA->BaParamSet.shortData);
-	memcpy(tag, (u8 *)&tmp, 2);
+
+	put_unaligned_le16(pBA->BaParamSet.shortData, tag);
 	tag += 2;
 	// BA Timeout Value
-	tmp = cpu_to_le16(pBA->BaTimeoutValue);
-	memcpy(tag, (u8 *)&tmp, 2);
+
+	put_unaligned_le16(pBA->BaTimeoutValue, tag);
 	tag += 2;
 
 	if (ACT_ADDBAREQ == type)
@@ -196,7 +197,6 @@
 	struct sk_buff *skb = NULL;
 	 struct ieee80211_hdr_3addr *Delba = NULL;
 	u8 *tag = NULL;
-	__le16 tmp = 0;
 	//len = head len + DELBA Parameter Set(2) + Reason Code(2)
 	u16 len = 6 + ieee->tx_headroom;
 
@@ -230,12 +230,12 @@
 	*tag ++= ACT_DELBA;
 
 	// DELBA Parameter Set
-	tmp = cpu_to_le16(DelbaParamSet.shortData);
-	memcpy(tag, (u8 *)&tmp, 2);
+
+	put_unaligned_le16(DelbaParamSet.shortData, tag);
 	tag += 2;
 	// Reason Code
-	tmp = cpu_to_le16(ReasonCode);
-	memcpy(tag, (u8 *)&tmp, 2);
+
+	put_unaligned_le16(ReasonCode, tag);
 	tag += 2;
 
 	IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index c451410..acaa723 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -241,7 +241,7 @@
 {
 	//DIRECTION_VALUE	dir;
 	u8	dir;
-	bool				search_dir[4] = {0, 0, 0, 0};
+	bool				search_dir[4] = {0};
 	struct list_head		*psearch_list; //FIXME
 	PTS_COMMON_INFO	pRet = NULL;
 	if(ieee->iw_mode == IW_MODE_MASTER) //ap mode
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c
index 45514aa..1868352 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.c
@@ -23,7 +23,7 @@
  * Return:      NONE
  * Note:	8226 support both 20M  and 40 MHz
  *---------------------------------------------------------------------------*/
-void PHY_SetRF8256Bandwidth(struct net_device *dev , HT_CHANNEL_WIDTH Bandwidth)
+void PHY_SetRF8256Bandwidth(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth)
 {
 	u8	eRFPath;
 	struct r8192_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 936565d..ee6b936 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -21,14 +21,13 @@
 #include "r8190_rtl8256.h"
 #include "r819xU_cmdpkt.h"
 /*---------------------------Define Local Constant---------------------------*/
-//
-// Indicate different AP vendor for IOT issue.
-//
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
-		{ 0x5e4322,	0x5e4322,	0x5e4322,	0x604322,	0xa44f,		0x5ea44f};
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
-		{ 0x5e4322,	0xa44f,		0x5e4322,	0x604322,	0x5ea44f,	0x5ea44f};
-
+/* Indicate different AP vendor for IOT issue. */
+static u32 edca_setting_DL[HT_IOT_PEER_MAX] = {
+	0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0x00a44f, 0x5ea44f
+};
+static u32 edca_setting_UL[HT_IOT_PEER_MAX] = {
+	0x5e4322, 0x00a44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f
+};
 
 #define RTK_UL_EDCA 0xa44f
 #define RTK_DL_EDCA 0x5e4322
@@ -36,11 +35,11 @@
 
 
 /*------------------------Define global variable-----------------------------*/
-// Debug variable ?
+/* Debug variable ? */
 dig_t	dm_digtable;
-// Store current software write register content for MAC PHY.
-u8		dm_shadow[16][256] = {{0}};
-// For Dynamic Rx Path Selection by Signal Strength
+/* Store current software write register content for MAC PHY. */
+u8		dm_shadow[16][256] = { {0} };
+/* For Dynamic Rx Path Selection by Signal Strength */
 DRxPathSel	DM_RxPathSelTable;
 /*------------------------Define global variable-----------------------------*/
 
@@ -56,24 +55,21 @@
 
 
 /*---------------------Define local function prototype-----------------------*/
-// DM --> Rate Adaptive
+/* DM --> Rate Adaptive */
 static	void	dm_check_rate_adaptive(struct net_device *dev);
 
-// DM --> Bandwidth switch
+/* DM --> Bandwidth switch */
 static	void	dm_init_bandwidth_autoswitch(struct net_device *dev);
 static	void	dm_bandwidth_autoswitch(struct net_device *dev);
 
-// DM --> TX power control
-//static	void	dm_initialize_txpower_tracking(struct net_device *dev);
+/* DM --> TX power control */
+/*static	void	dm_initialize_txpower_tracking(struct net_device *dev);*/
 
 static	void	dm_check_txpower_tracking(struct net_device *dev);
 
+/*static	void	dm_txpower_reset_recovery(struct net_device *dev);*/
 
-
-//static	void	dm_txpower_reset_recovery(struct net_device *dev);
-
-
-// DM --> Dynamic Init Gain by RSSI
+/* DM --> Dynamic Init Gain by RSSI */
 static	void	dm_dig_init(struct net_device *dev);
 static	void	dm_ctrl_initgain_byrssi(struct net_device *dev);
 static	void	dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev);
@@ -84,61 +80,58 @@
 static	void	dm_cs_ratio(struct net_device *dev);
 
 static	void dm_init_ctstoself(struct net_device *dev);
-// DM --> EDCA turbo mode control
+/* DM --> EDCA turbo mode control */
 static	void	dm_check_edca_turbo(struct net_device *dev);
 
-//static	void	dm_gpio_change_rf(struct net_device *dev);
-// DM --> Check PBC
+/*static	void	dm_gpio_change_rf(struct net_device *dev);*/
+/* DM --> Check PBC */
 static	void dm_check_pbc_gpio(struct net_device *dev);
 
-
-// DM --> Check current RX RF path state
+/* DM --> Check current RX RF path state */
 static	void	dm_check_rx_path_selection(struct net_device *dev);
 static	void dm_init_rxpath_selection(struct net_device *dev);
 static	void dm_rxpath_sel_byrssi(struct net_device *dev);
 
-
-// DM --> Fsync for broadcom ap
+/* DM --> Fsync for broadcom ap */
 static void dm_init_fsync(struct net_device *dev);
 static void dm_deInit_fsync(struct net_device *dev);
 
-//Added by vivi, 20080522
+/* Added by vivi, 20080522 */
 static	void	dm_check_txrateandretrycount(struct net_device *dev);
 
 /*---------------------Define local function prototype-----------------------*/
 
-/*---------------------Define of Tx Power Control For Near/Far Range --------*/   //Add by Jacken 2008/02/18
+/*---------------------Define of Tx Power Control For Near/Far Range --------*/   /*Add by Jacken 2008/02/18 */
 static	void	dm_init_dynamic_txpower(struct net_device *dev);
 static	void	dm_dynamic_txpower(struct net_device *dev);
 
-
-// DM --> For rate adaptive and DIG, we must send RSSI to firmware
+/* DM --> For rate adaptive and DIG, we must send RSSI to firmware */
 static	void dm_send_rssi_tofw(struct net_device *dev);
 static	void	dm_ctstoself(struct net_device *dev);
 /*---------------------------Define function prototype------------------------*/
-//================================================================================
-//	HW Dynamic mechanism interface.
-//================================================================================
-
-//
-//	Description:
-//		Prepare SW resource for HW dynamic mechanism.
-//
-//	Assumption:
-//		This function is only invoked at driver intialization once.
-//
-//
+/*
+ * ================================================================================
+ *	HW Dynamic mechanism interface.
+ * ================================================================================
+ *
+ *
+ *	Description:
+ *		Prepare SW resource for HW dynamic mechanism.
+ *
+ *	Assumption:
+ *		This function is only invoked at driver intialization once.
+ */
 void init_hal_dm(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism.
+	/* Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism. */
 	priv->undecorated_smoothed_pwdb = -1;
 
-	//Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
+	/* Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. */
 	dm_init_dynamic_txpower(dev);
 	init_rate_adaptive(dev);
-	//dm_initialize_txpower_tracking(dev);
+	/*dm_initialize_txpower_tracking(dev);*/
 	dm_dig_init(dev);
 	dm_init_edca_turbo(dev);
 	dm_init_bandwidth_autoswitch(dev);
@@ -146,18 +139,16 @@
 	dm_init_rxpath_selection(dev);
 	dm_init_ctstoself(dev);
 
-}	// InitHalDm
+}	/* InitHalDm */
 
 void deinit_hal_dm(struct net_device *dev)
 {
-
 	dm_deInit_fsync(dev);
-
 }
 
-
 #ifdef USB_RX_AGGREGATION_SUPPORT
-void dm_CheckRxAggregation(struct net_device *dev) {
+void dm_CheckRxAggregation(struct net_device *dev)
+{
 	struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev);
 	PRT_HIGH_THROUGHPUT	pHTInfo = priv->ieee80211->pHTInfo;
 	static unsigned long	lastTxOkCnt;
@@ -186,14 +177,15 @@
 	if ((curTxOkCnt + curRxOkCnt) < 15000000)
 		return;
 
-	if(curTxOkCnt > 4*curRxOkCnt) {
+	if (curTxOkCnt > 4*curRxOkCnt) {
 		if (priv->bCurrentRxAggrEnable) {
 			write_nic_dword(dev, 0x1a8, 0);
 			priv->bCurrentRxAggrEnable = false;
 		}
-	}else{
+	} else {
 		if (!priv->bCurrentRxAggrEnable && !pHTInfo->bCurrentRT2RTAggregation) {
 			u32 ulValue;
+
 			ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) |
 				(pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout);
 			/*
@@ -208,16 +200,14 @@
 
 	lastTxOkCnt = priv->stats.txbytesunicast;
 	lastRxOkCnt = priv->stats.rxbytesunicast;
-}	// dm_CheckEdcaTurbo
+}	/* dm_CheckEdcaTurbo */
 #endif
 
-
-
 void hal_dm_watchdog(struct net_device *dev)
 {
-	//struct r8192_priv *priv = ieee80211_priv(dev);
+	/*struct r8192_priv *priv = ieee80211_priv(dev);*/
 
-	//static u8	previous_bssid[6] ={0};
+	/*static u8	previous_bssid[6] ={0};*/
 
 	/*Add by amy 2008/05/15 ,porting from windows code.*/
 	dm_check_rate_adaptive(dev);
@@ -230,25 +220,23 @@
 	dm_check_rx_path_selection(dev);
 	dm_check_fsync(dev);
 
-	// Add by amy 2008-05-15 porting from windows code.
+	/* Add by amy 2008-05-15 porting from windows code. */
 	dm_check_pbc_gpio(dev);
 	dm_send_rssi_tofw(dev);
 	dm_ctstoself(dev);
 #ifdef USB_RX_AGGREGATION_SUPPORT
 	dm_CheckRxAggregation(dev);
 #endif
-}	//HalDmWatchDog
-
+}	/* HalDmWatchDog */
 
 /*
-  * Decide Rate Adaptive Set according to distance (signal strength)
-  *	01/11/2008	MHC		Modify input arguments and RATR table level.
-  *	01/16/2008	MHC		RF_Type is assigned in ReadAdapterInfo(). We must call
-  *						the function after making sure RF_Type.
-  */
+ * Decide Rate Adaptive Set according to distance (signal strength)
+ *	01/11/2008	MHC		Modify input arguments and RATR table level.
+ *	01/16/2008	MHC		RF_Type is assigned in ReadAdapterInfo(). We must call
+ *						the function after making sure RF_Type.
+ */
 void init_rate_adaptive(struct net_device *dev)
 {
-
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	prate_adaptive	pra = (prate_adaptive)&priv->rate_adaptive;
 
@@ -261,36 +249,33 @@
 	pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M;
 	pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M;
 
-	if(priv->CustomerID == RT_CID_819x_Netcore)
+	if (priv->CustomerID == RT_CID_819x_Netcore)
 		pra->ping_rssi_enable = 1;
 	else
 		pra->ping_rssi_enable = 0;
 	pra->ping_rssi_thresh_for_ra = 15;
 
-
-	if (priv->rf_type == RF_2T4R)
-	{
-		// 07/10/08 MH Modify for RA smooth scheme.
-		/* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.*/
+	if (priv->rf_type == RF_2T4R) {
+		/*
+		 * 07/10/08 MH Modify for RA smooth scheme.
+		 * 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.
+		 */
 		pra->upper_rssi_threshold_ratr		=	0x8f0f0000;
 		pra->middle_rssi_threshold_ratr		=	0x8f0ff000;
 		pra->low_rssi_threshold_ratr		=	0x8f0ff001;
 		pra->low_rssi_threshold_ratr_40M	=	0x8f0ff005;
 		pra->low_rssi_threshold_ratr_20M	=	0x8f0ff001;
-		pra->ping_rssi_ratr	=	0x0000000d;//cosa add for test
-	}
-	else if (priv->rf_type == RF_1T2R)
-	{
+		pra->ping_rssi_ratr	=	0x0000000d;/* cosa add for test */
+	} else if (priv->rf_type == RF_1T2R) {
 		pra->upper_rssi_threshold_ratr		=	0x000f0000;
 		pra->middle_rssi_threshold_ratr		=	0x000ff000;
 		pra->low_rssi_threshold_ratr		=	0x000ff001;
 		pra->low_rssi_threshold_ratr_40M	=	0x000ff005;
 		pra->low_rssi_threshold_ratr_20M	=	0x000ff001;
-		pra->ping_rssi_ratr	=	0x0000000d;//cosa add for test
+		pra->ping_rssi_ratr	=	0x0000000d;/* cosa add for test */
 	}
 
-}	// InitRateAdaptive
-
+}	/* InitRateAdaptive */
 
 /*-----------------------------------------------------------------------------
  * Function:	dm_check_rate_adaptive()
@@ -318,149 +303,122 @@
 	bool						bshort_gi_enabled = false;
 	static u8					ping_rssi_state;
 
-
-	if(!priv->up)
-	{
+	if (!priv->up) {
 		RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n");
 		return;
 	}
 
-	if(pra->rate_adaptive_disabled)//this variable is set by ioctl.
+	if (pra->rate_adaptive_disabled) /* this variable is set by ioctl. */
 		return;
 
-	// TODO: Only 11n mode is implemented currently,
-	if(!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
-		 priv->ieee80211->mode == WIRELESS_MODE_N_5G))
-		 return;
+	/* TODO: Only 11n mode is implemented currently, */
+	if (!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
+	      priv->ieee80211->mode == WIRELESS_MODE_N_5G))
+		return;
 
-	if(priv->ieee80211->state == IEEE80211_LINKED)
-	{
-	//	RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");
+	if (priv->ieee80211->state == IEEE80211_LINKED) {
+		/*RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");*/
 
-		//
-		// Check whether Short GI is enabled
-		//
+		/* Check whether Short GI is enabled */
 		bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) ||
 			(!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz);
 
-
 		pra->upper_rssi_threshold_ratr =
-				(pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+				(pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
 
 		pra->middle_rssi_threshold_ratr =
-				(pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+				(pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
 
-		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-		{
+		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
 			pra->low_rssi_threshold_ratr =
-				(pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
-		}
-		else
-		{
+				(pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
+		} else {
 			pra->low_rssi_threshold_ratr =
-			(pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+			(pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
 		}
-		//cosa add for test
+		/* cosa add for test */
 		pra->ping_rssi_ratr =
-				(pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+				(pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
 
 		/* 2007/10/08 MH We support RA smooth scheme now. When it is the first
 		   time to link with AP. We will not change upper/lower threshold. If
 		   STA stay in high or low level, we must change two different threshold
 		   to prevent jumping frequently. */
-		if (pra->ratr_state == DM_RATR_STA_HIGH)
-		{
+		if (pra->ratr_state == DM_RATR_STA_HIGH) {
 			HighRSSIThreshForRA	= pra->high2low_rssi_thresh_for_ra;
-			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
 					(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
-		}
-		else if (pra->ratr_state == DM_RATR_STA_LOW)
-		{
+		} else if (pra->ratr_state == DM_RATR_STA_LOW) {
 			HighRSSIThreshForRA	= pra->high_rssi_thresh_for_ra;
-			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
 					(pra->low2high_rssi_thresh_for_ra40M):(pra->low2high_rssi_thresh_for_ra20M);
-		}
-		else
-		{
+		} else {
 			HighRSSIThreshForRA	= pra->high_rssi_thresh_for_ra;
-			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+			LowRSSIThreshForRA	= (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
 					(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
 		}
 
-		//DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA);
-		if(priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA)
-		{
-			//DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB);
+		/*DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA);*/
+		if (priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) {
+			/*DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB);*/
 			pra->ratr_state = DM_RATR_STA_HIGH;
 			targetRATR = pra->upper_rssi_threshold_ratr;
-		}else if(priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA)
-		{
-			//DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB);
+		} else if (priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) {
+			/*DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB);*/
 			pra->ratr_state = DM_RATR_STA_MIDDLE;
 			targetRATR = pra->middle_rssi_threshold_ratr;
-		}else
-		{
-			//DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB);
+		} else {
+			/*DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB);*/
 			pra->ratr_state = DM_RATR_STA_LOW;
 			targetRATR = pra->low_rssi_threshold_ratr;
 		}
 
-			//cosa add for test
-		if(pra->ping_rssi_enable)
-		{
-			//pHalData->UndecoratedSmoothedPWDB = 19;
-			if(priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5))
-			{
-				if((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) ||
-					ping_rssi_state)
-				{
-					//DbgPrint("TestRSSI = %d, set RATR to 0x%x \n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR);
+		/* cosa add for test */
+		if (pra->ping_rssi_enable) {
+			/*pHalData->UndecoratedSmoothedPWDB = 19;*/
+			if (priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) {
+				if ((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) ||
+					ping_rssi_state) {
+					/*DbgPrint("TestRSSI = %d, set RATR to 0x%x\n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR);*/
 					pra->ratr_state = DM_RATR_STA_LOW;
 					targetRATR = pra->ping_rssi_ratr;
 					ping_rssi_state = 1;
 				}
-				//else
-				//	DbgPrint("TestRSSI is between the range. \n");
-			}
-			else
-			{
-				//DbgPrint("TestRSSI Recover to 0x%x \n", targetRATR);
+				/*else
+					DbgPrint("TestRSSI is between the range.\n");*/
+			} else {
+				/*DbgPrint("TestRSSI Recover to 0x%x\n", targetRATR);*/
 				ping_rssi_state = 0;
 			}
 		}
 
-		// 2008.04.01
-		// For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
-		if(priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
-			targetRATR &=  0xf00fffff;
+		/*
+		 * 2008.04.01
+		 * For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
+		 */
+		if (priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
+			targetRATR &= 0xf00fffff;
 
-		//
-		// Check whether updating of RATR0 is required
-		//
+		/* Check whether updating of RATR0 is required */
 		read_nic_dword(dev, RATR0, &currentRATR);
-		if(targetRATR !=  currentRATR)
-		{
+		if (targetRATR !=  currentRATR) {
 			u32 ratr_value;
+
 			ratr_value = targetRATR;
-			RT_TRACE(COMP_RATE,"currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR);
-			if(priv->rf_type == RF_1T2R)
-			{
+			RT_TRACE(COMP_RATE, "currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR);
+			if (priv->rf_type == RF_1T2R)
 				ratr_value &= ~(RATE_ALL_OFDM_2SS);
-			}
 			write_nic_dword(dev, RATR0, ratr_value);
 			write_nic_byte(dev, UFWP, 1);
 
 			pra->last_ratr = targetRATR;
 		}
 
-	}
-	else
-	{
+	} else {
 		pra->ratr_state = DM_RATR_STA_MAX;
 	}
 
-}	// dm_CheckRateAdaptive
-
+}	/* dm_CheckRateAdaptive */
 
 static void dm_init_bandwidth_autoswitch(struct net_device *dev)
 {
@@ -471,78 +429,74 @@
 	priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
 	priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable = false;
 
-}	// dm_init_bandwidth_autoswitch
-
+}	/* dm_init_bandwidth_autoswitch */
 
 static void dm_bandwidth_autoswitch(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||!priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable){
+	if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 || !priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable)
 		return;
-	}else{
-		if(priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false){//If send packets in 40 Mhz in 20/40
-			if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
-				priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true;
-		}else{//in force send packets in 20 Mhz in 20/40
-			if(priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
-				priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
-
-		}
+	if (priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false) { /* If send packets in 40 Mhz in 20/40 */
+		if (priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
+			priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true;
+	} else { /* in force send packets in 20 Mhz in 20/40 */
+		if (priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
+			priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
 	}
-}	// dm_BandwidthAutoSwitch
+}	/* dm_BandwidthAutoSwitch */
 
-//OFDM default at 0db, index=6.
+/* OFDM default at 0db, index=6. */
 static u32 OFDMSwingTable[OFDM_Table_Length] = {
-	0x7f8001fe,	// 0, +6db
-	0x71c001c7,	// 1, +5db
-	0x65400195,	// 2, +4db
-	0x5a400169,	// 3, +3db
-	0x50800142,	// 4, +2db
-	0x47c0011f,	// 5, +1db
-	0x40000100,	// 6, +0db ===> default, upper for higher temperature, lower for low temperature
-	0x390000e4,	// 7, -1db
-	0x32c000cb,	// 8, -2db
-	0x2d4000b5,	// 9, -3db
-	0x288000a2,	// 10, -4db
-	0x24000090,	// 11, -5db
-	0x20000080,	// 12, -6db
-	0x1c800072,	// 13, -7db
-	0x19800066,	// 14, -8db
-	0x26c0005b,	// 15, -9db
-	0x24400051,	// 16, -10db
-	0x12000048,	// 17, -11db
-	0x10000040	// 18, -12db
+	0x7f8001fe,	/* 0, +6db */
+	0x71c001c7,	/* 1, +5db */
+	0x65400195,	/* 2, +4db */
+	0x5a400169,	/* 3, +3db */
+	0x50800142,	/* 4, +2db */
+	0x47c0011f,	/* 5, +1db */
+	0x40000100,	/* 6, +0db ===> default, upper for higher temperature, lower for low temperature */
+	0x390000e4,	/* 7, -1db */
+	0x32c000cb,	/* 8, -2db */
+	0x2d4000b5,	/* 9, -3db */
+	0x288000a2,	/* 10, -4db */
+	0x24000090,	/* 11, -5db */
+	0x20000080,	/* 12, -6db */
+	0x1c800072,	/* 13, -7db */
+	0x19800066,	/* 14, -8db */
+	0x26c0005b,	/* 15, -9db */
+	0x24400051,	/* 16, -10db */
+	0x12000048,	/* 17, -11db */
+	0x10000040	/* 18, -12db */
 };
 
 static u8	CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
-	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},	// 0, +0db ===> CCK40M default
-	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},	// 1, -1db
-	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},	// 2, -2db
-	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},	// 3, -3db
-	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},	// 4, -4db
-	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},	// 5, -5db
-	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},	// 6, -6db ===> CCK20M default
-	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},	// 7, -7db
-	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},	// 8, -8db
-	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},	// 9, -9db
-	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},	// 10, -10db
-	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}	// 11, -11db
+	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},	/* 0, +0db ===> CCK40M default */
+	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},	/* 1, -1db */
+	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},	/* 2, -2db */
+	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},	/* 3, -3db */
+	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},	/* 4, -4db */
+	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},	/* 5, -5db */
+	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},	/* 6, -6db ===> CCK20M default */
+	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},	/* 7, -7db */
+	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},	/* 8, -8db */
+	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},	/* 9, -9db */
+	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},	/* 10, -10db */
+	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}	/* 11, -11db */
 };
 
 static u8	CCKSwingTable_Ch14[CCK_Table_length][8] = {
-	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},	// 0, +0db  ===> CCK40M default
-	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},	// 1, -1db
-	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},	// 2, -2db
-	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},	// 3, -3db
-	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},	// 4, -4db
-	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},	// 5, -5db
-	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},	// 6, -6db  ===> CCK20M default
-	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},	// 7, -7db
-	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},	// 8, -8db
-	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},	// 9, -9db
-	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},	// 10, -10db
-	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}	// 11, -11db
+	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},	/* 0, +0db  ===> CCK40M default */
+	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},	/* 1, -1db */
+	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},	/* 2, -2db */
+	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},	/* 3, -3db */
+	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},	/* 4, -4db */
+	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},	/* 5, -5db */
+	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},	/* 6, -6db  ===> CCK20M default */
+	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},	/* 7, -7db */
+	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},	/* 8, -8db */
+	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},	/* 9, -9db */
+	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},	/* 10, -10db */
+	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}	/* 11, -11db */
 };
 
 static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
@@ -551,14 +505,14 @@
 	bool						bHighpowerstate, viviflag = FALSE;
 	DCMD_TXCMD_T			tx_cmd;
 	u8						powerlevelOFDM24G;
-	int						i =0, j = 0, k = 0;
-	u8						RF_Type, tmp_report[5]={0, 0, 0, 0, 0};
+	int						i = 0, j = 0, k = 0;
+	u8						RF_Type, tmp_report[5] = {0, 0, 0, 0, 0};
 	u32						Value;
 	u8						Pwr_Flag;
-	u16						Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver=0;
-	//RT_STATUS				rtStatus = RT_STATUS_SUCCESS;
+	u16						Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver = 0;
+	/*RT_STATUS				rtStatus = RT_STATUS_SUCCESS;*/
 	bool rtStatus = true;
-	u32						delta=0;
+	u32						delta = 0;
 
 	write_nic_byte(dev, 0x1ba, 0);
 
@@ -571,109 +525,87 @@
 
 	RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", powerlevelOFDM24G);
 
-	for(j = 0; j<=30; j++)
-{	//fill tx_cmd
+	for (j = 0; j <= 30; j++) { /* fill tx_cmd */
+		tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING;
+		tx_cmd.Length = 4;
+		tx_cmd.Value = Value;
+		rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12);
+		if (rtStatus == RT_STATUS_FAILURE)
+			RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n");
+		mdelay(1);
+		/*DbgPrint("hi, vivi, strange\n");*/
+		for (i = 0; i <= 30; i++) {
+			read_nic_byte(dev, 0x1ba, &Pwr_Flag);
 
-	tx_cmd.Op		= TXCMD_SET_TX_PWR_TRACKING;
-	tx_cmd.Length	= 4;
-	tx_cmd.Value		= Value;
-	rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12);
-	if (rtStatus == RT_STATUS_FAILURE)
-	{
-		RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n");
-	}
-	mdelay(1);
-	//DbgPrint("hi, vivi, strange\n");
-	for(i = 0;i <= 30; i++)
-	{
-		read_nic_byte(dev, 0x1ba, &Pwr_Flag);
-
-		if (Pwr_Flag == 0)
-		{
-			mdelay(1);
-			continue;
-		}
-		read_nic_word(dev, 0x13c, &Avg_TSSI_Meas);
-		if(Avg_TSSI_Meas == 0)
-		{
-			write_nic_byte(dev, 0x1ba, 0);
-			break;
-		}
-
-		for(k = 0;k < 5; k++)
-		{
-			if(k !=4)
-				read_nic_byte(dev, 0x134+k, &tmp_report[k]);
-			else
-				read_nic_byte(dev, 0x13e, &tmp_report[k]);
-			RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]);
-		}
-
-		//check if the report value is right
-		for(k = 0;k < 5; k++)
-		{
-			if(tmp_report[k] <= 20)
-			{
-				viviflag =TRUE;
+			if (Pwr_Flag == 0) {
+				mdelay(1);
+				continue;
+			}
+			read_nic_word(dev, 0x13c, &Avg_TSSI_Meas);
+			if (Avg_TSSI_Meas == 0) {
+				write_nic_byte(dev, 0x1ba, 0);
 				break;
 			}
-		}
-		if(viviflag ==TRUE)
-		{
-			write_nic_byte(dev, 0x1ba, 0);
-			viviflag = FALSE;
-			RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
-			for(k = 0;k < 5; k++)
-				tmp_report[k] = 0;
-			break;
-		}
 
-		for(k = 0;k < 5; k++)
-		{
-			Avg_TSSI_Meas_from_driver += tmp_report[k];
-		}
+			for (k = 0; k < 5; k++) {
+				if (k != 4)
+					read_nic_byte(dev, 0x134+k, &tmp_report[k]);
+				else
+					read_nic_byte(dev, 0x13e, &tmp_report[k]);
+				RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]);
+			}
 
-		Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5;
-		RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver);
-		TSSI_13dBm = priv->TSSI_13dBm;
-		RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm);
+			/* check if the report value is right */
+			for (k = 0; k < 5; k++) {
+				if (tmp_report[k] <= 20) {
+					viviflag = TRUE;
+					break;
+				}
+			}
+			if (viviflag == TRUE) {
+				write_nic_byte(dev, 0x1ba, 0);
+				viviflag = FALSE;
+				RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
+				for (k = 0; k < 5; k++)
+					tmp_report[k] = 0;
+				break;
+			}
 
-		//if(abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)
-		// For MacOS-compatible
-		if(Avg_TSSI_Meas_from_driver > TSSI_13dBm)
-			delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
-		else
-			delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
+			for (k = 0; k < 5; k++)
+				Avg_TSSI_Meas_from_driver += tmp_report[k];
 
-		if(delta <= E_FOR_TX_POWER_TRACK)
-		{
-			priv->ieee80211->bdynamic_txpower_enable = TRUE;
-			write_nic_byte(dev, 0x1ba, 0);
-			RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n");
-			RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
-			RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
-			RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
-			RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
-			return;
-		}
-		else
-		{
-			if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK)
-			{
-				if (priv->rfa_txpowertrackingindex > 0)
-				{
+			Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5;
+			RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver);
+			TSSI_13dBm = priv->TSSI_13dBm;
+			RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm);
+
+			/*if (abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)*/
+			/* For MacOS-compatible */
+			if (Avg_TSSI_Meas_from_driver > TSSI_13dBm)
+				delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
+			else
+				delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
+
+			if (delta <= E_FOR_TX_POWER_TRACK) {
+				priv->ieee80211->bdynamic_txpower_enable = TRUE;
+				write_nic_byte(dev, 0x1ba, 0);
+				RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n");
+				RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
+				RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
+				RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
+				RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
+				return;
+			}
+			if (Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) {
+				if (priv->rfa_txpowertrackingindex > 0) {
 					priv->rfa_txpowertrackingindex--;
-					if(priv->rfa_txpowertrackingindex_real > 4)
-					{
+					if (priv->rfa_txpowertrackingindex_real > 4) {
 						priv->rfa_txpowertrackingindex_real--;
 						rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
 					}
 				}
-			}
-			else
-			{
-				if (priv->rfa_txpowertrackingindex < 36)
-				{
+			} else {
+				if (priv->rfa_txpowertrackingindex < 36) {
 					priv->rfa_txpowertrackingindex++;
 					priv->rfa_txpowertrackingindex_real++;
 					rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
@@ -683,52 +615,44 @@
 			priv->cck_present_attentuation_difference
 				= priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default;
 
-			if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+			if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
 				priv->cck_present_attentuation
-				= priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference;
+					= priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference;
 			else
 				priv->cck_present_attentuation
-				= priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference;
+					= priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference;
 
-			if(priv->cck_present_attentuation > -1&&priv->cck_present_attentuation <23)
-			{
-				if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
-				{
+			if (priv->cck_present_attentuation > -1 && priv->cck_present_attentuation < 23) {
+				if (priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) {
 					priv->bcck_in_ch14 = TRUE;
-					dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
-				}
-				else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
-				{
+					dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
+				} else if (priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) {
 					priv->bcck_in_ch14 = FALSE;
-					dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
-				}
-				else
-					dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
+					dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
+				} else
+					dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
 			}
-		RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
-		RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
-		RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
-		RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
+			RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
+			RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
+			RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
+			RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
 
-		if (priv->cck_present_attentuation_difference <= -12||priv->cck_present_attentuation_difference >= 24)
-		{
-			priv->ieee80211->bdynamic_txpower_enable = TRUE;
+			if (priv->cck_present_attentuation_difference <= -12 || priv->cck_present_attentuation_difference >= 24) {
+				priv->ieee80211->bdynamic_txpower_enable = TRUE;
+				write_nic_byte(dev, 0x1ba, 0);
+				RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n");
+				return;
+			}
+
 			write_nic_byte(dev, 0x1ba, 0);
-			RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n");
-			return;
+			Avg_TSSI_Meas_from_driver = 0;
+			for (k = 0; k < 5; k++)
+				tmp_report[k] = 0;
+			break;
 		}
-
-
 	}
-		write_nic_byte(dev, 0x1ba, 0);
-		Avg_TSSI_Meas_from_driver = 0;
-		for(k = 0;k < 5; k++)
-			tmp_report[k] = 0;
-		break;
-	}
-}
-		priv->ieee80211->bdynamic_txpower_enable = TRUE;
-		write_nic_byte(dev, 0x1ba, 0);
+	priv->ieee80211->bdynamic_txpower_enable = TRUE;
+	write_nic_byte(dev, 0x1ba, 0);
 }
 
 static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
@@ -737,107 +661,96 @@
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	u32 tmpRegA, TempCCk;
 	u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval;
-	int i =0, CCKSwingNeedUpdate=0;
+	int i = 0, CCKSwingNeedUpdate = 0;
 
-	if(!priv->btxpower_trackingInit)
-	{
-		//Query OFDM default setting
-		tmpRegA= rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord);
-		for(i=0; i<OFDM_Table_Length; i++)	//find the index
-		{
-			if(tmpRegA == OFDMSwingTable[i])
-			{
-				priv->OFDM_index= (u8)i;
+	if (!priv->btxpower_trackingInit) {
+		/* Query OFDM default setting */
+		tmpRegA = rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord);
+		for (i = 0; i < OFDM_Table_Length; i++) { /* find the index */
+			if (tmpRegA == OFDMSwingTable[i]) {
+				priv->OFDM_index = (u8)i;
 				RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index=0x%x\n",
 					rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index);
 			}
 		}
 
-		//Query CCK default setting From 0xa22
+		/* Query CCK default setting From 0xa22 */
 		TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2);
-		for(i=0 ; i<CCK_Table_length ; i++)
-		{
-			if(TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0])
-			{
-				priv->CCK_index =(u8) i;
+		for (i = 0; i < CCK_Table_length; i++) {
+			if (TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0]) {
+				priv->CCK_index = (u8) i;
 				RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, CCK_index=0x%x\n",
 					rCCK0_TxFilter1, TempCCk, priv->CCK_index);
 				break;
 			}
 		}
 		priv->btxpower_trackingInit = TRUE;
-		//pHalData->TXPowercount = 0;
+		/*pHalData->TXPowercount = 0;*/
 		return;
 	}
 
-	//==========================
-	// this is only for test, should be masked
-	//==========================
+	/*
+	 * ==========================
+	 * this is only for test, should be masked
+	 * ==========================
+	 */
 
-	// read and filter out unreasonable value
-	tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078);	// 0x12: RF Reg[10:7]
-	RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA);
-	if(tmpRegA < 3 || tmpRegA > 13)
+	/* read and filter out unreasonable value */
+	tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078);	/* 0x12: RF Reg[10:7] */
+	RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d\n", tmpRegA);
+	if (tmpRegA < 3 || tmpRegA > 13)
 		return;
-	if(tmpRegA >= 12)	// if over 12, TP will be bad when high temperature
+	if (tmpRegA >= 12)	/* if over 12, TP will be bad when high temperature */
 		tmpRegA = 12;
-	RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA);
-	priv->ThermalMeter[0] = ThermalMeterVal;	//We use fixed value by Bryant's suggestion
-	priv->ThermalMeter[1] = ThermalMeterVal;	//We use fixed value by Bryant's suggestion
+	RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d\n", tmpRegA);
+	priv->ThermalMeter[0] = ThermalMeterVal;	/* We use fixed value by Bryant's suggestion */
+	priv->ThermalMeter[1] = ThermalMeterVal;	/* We use fixed value by Bryant's suggestion */
 
-	//Get current RF-A temperature index
-	if(priv->ThermalMeter[0] >= (u8)tmpRegA)	//lower temperature
-	{
+	/* Get current RF-A temperature index */
+	if (priv->ThermalMeter[0] >= (u8)tmpRegA) {	/* lower temperature */
 		tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
 		tmpCCK40Mindex = tmpCCK20Mindex - 6;
-		if(tmpOFDMindex >= OFDM_Table_Length)
+		if (tmpOFDMindex >= OFDM_Table_Length)
 			tmpOFDMindex = OFDM_Table_Length-1;
-		if(tmpCCK20Mindex >= CCK_Table_length)
+		if (tmpCCK20Mindex >= CCK_Table_length)
 			tmpCCK20Mindex = CCK_Table_length-1;
-		if(tmpCCK40Mindex >= CCK_Table_length)
+		if (tmpCCK40Mindex >= CCK_Table_length)
 			tmpCCK40Mindex = CCK_Table_length-1;
-	}
-	else
-	{
+	} else {
 		tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
-		if(tmpval >= 6)								// higher temperature
-			tmpOFDMindex = tmpCCK20Mindex = 0;		// max to +6dB
+
+		if (tmpval >= 6) /* higher temperature */
+			tmpOFDMindex = tmpCCK20Mindex = 0; /* max to +6dB */
 		else
 			tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
 		tmpCCK40Mindex = 0;
 	}
-	//DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d",
-		//((u1Byte)tmpRegA - pHalData->ThermalMeter[0]),
-		//tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex);
-	if(priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)	//40M
+	/*DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d",
+		((u1Byte)tmpRegA - pHalData->ThermalMeter[0]),
+		tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex);*/
+	if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)	/* 40M */
 		tmpCCKindex = tmpCCK40Mindex;
 	else
 		tmpCCKindex = tmpCCK20Mindex;
 
-	if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
-	{
+	if (priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) {
 		priv->bcck_in_ch14 = TRUE;
 		CCKSwingNeedUpdate = 1;
-	}
-	else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
-	{
+	} else if (priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) {
 		priv->bcck_in_ch14 = FALSE;
 		CCKSwingNeedUpdate = 1;
 	}
 
-	if(priv->CCK_index != tmpCCKindex)
-	{
+	if (priv->CCK_index != tmpCCKindex) {
 		priv->CCK_index = tmpCCKindex;
 		CCKSwingNeedUpdate = 1;
 	}
 
-	if(CCKSwingNeedUpdate)
-	{
-		//DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index);
+	if (CCKSwingNeedUpdate) {
+		/*DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index);*/
 		dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
 	}
-	if(priv->OFDM_index != tmpOFDMindex)
-	{
+	if (priv->OFDM_index != tmpOFDMindex) {
 		priv->OFDM_index = tmpOFDMindex;
 		rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[priv->OFDM_index]);
 		RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n",
@@ -848,100 +761,100 @@
 
 void dm_txpower_trackingcallback(struct work_struct *work)
 {
-	struct delayed_work *dwork = container_of(work,struct delayed_work,work);
-       struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq);
-       struct net_device *dev = priv->ieee80211->dev;
+	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+	struct r8192_priv *priv = container_of(dwork, struct r8192_priv, txpower_tracking_wq);
+	struct net_device *dev = priv->ieee80211->dev;
 
-	if(priv->bDcut == TRUE)
+	if (priv->bDcut == TRUE)
 		dm_TXPowerTrackingCallback_TSSI(dev);
 	else
 		dm_TXPowerTrackingCallback_ThermalMeter(dev);
 }
 
-
 static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
 {
-
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	//Initial the Tx BB index and mapping value
+	/* Initial the Tx BB index and mapping value */
 	priv->txbbgain_table[0].txbb_iq_amplifygain =			12;
-	priv->txbbgain_table[0].txbbgain_value=0x7f8001fe;
+	priv->txbbgain_table[0].txbbgain_value = 0x7f8001fe;
 	priv->txbbgain_table[1].txbb_iq_amplifygain =			11;
-	priv->txbbgain_table[1].txbbgain_value=0x788001e2;
+	priv->txbbgain_table[1].txbbgain_value = 0x788001e2;
 	priv->txbbgain_table[2].txbb_iq_amplifygain =			10;
-	priv->txbbgain_table[2].txbbgain_value=0x71c001c7;
+	priv->txbbgain_table[2].txbbgain_value = 0x71c001c7;
 	priv->txbbgain_table[3].txbb_iq_amplifygain =			9;
-	priv->txbbgain_table[3].txbbgain_value=0x6b8001ae;
+	priv->txbbgain_table[3].txbbgain_value = 0x6b8001ae;
 	priv->txbbgain_table[4].txbb_iq_amplifygain =		       8;
-	priv->txbbgain_table[4].txbbgain_value=0x65400195;
+	priv->txbbgain_table[4].txbbgain_value = 0x65400195;
 	priv->txbbgain_table[5].txbb_iq_amplifygain =		       7;
-	priv->txbbgain_table[5].txbbgain_value=0x5fc0017f;
+	priv->txbbgain_table[5].txbbgain_value = 0x5fc0017f;
 	priv->txbbgain_table[6].txbb_iq_amplifygain =		       6;
-	priv->txbbgain_table[6].txbbgain_value=0x5a400169;
+	priv->txbbgain_table[6].txbbgain_value = 0x5a400169;
 	priv->txbbgain_table[7].txbb_iq_amplifygain =		       5;
-	priv->txbbgain_table[7].txbbgain_value=0x55400155;
+	priv->txbbgain_table[7].txbbgain_value = 0x55400155;
 	priv->txbbgain_table[8].txbb_iq_amplifygain =		       4;
-	priv->txbbgain_table[8].txbbgain_value=0x50800142;
+	priv->txbbgain_table[8].txbbgain_value = 0x50800142;
 	priv->txbbgain_table[9].txbb_iq_amplifygain =		       3;
-	priv->txbbgain_table[9].txbbgain_value=0x4c000130;
+	priv->txbbgain_table[9].txbbgain_value = 0x4c000130;
 	priv->txbbgain_table[10].txbb_iq_amplifygain =		       2;
-	priv->txbbgain_table[10].txbbgain_value=0x47c0011f;
+	priv->txbbgain_table[10].txbbgain_value = 0x47c0011f;
 	priv->txbbgain_table[11].txbb_iq_amplifygain =		       1;
-	priv->txbbgain_table[11].txbbgain_value=0x43c0010f;
+	priv->txbbgain_table[11].txbbgain_value = 0x43c0010f;
 	priv->txbbgain_table[12].txbb_iq_amplifygain =		       0;
-	priv->txbbgain_table[12].txbbgain_value=0x40000100;
+	priv->txbbgain_table[12].txbbgain_value = 0x40000100;
 	priv->txbbgain_table[13].txbb_iq_amplifygain =		       -1;
-	priv->txbbgain_table[13].txbbgain_value=0x3c8000f2;
+	priv->txbbgain_table[13].txbbgain_value = 0x3c8000f2;
 	priv->txbbgain_table[14].txbb_iq_amplifygain =		     -2;
-	priv->txbbgain_table[14].txbbgain_value=0x390000e4;
+	priv->txbbgain_table[14].txbbgain_value = 0x390000e4;
 	priv->txbbgain_table[15].txbb_iq_amplifygain =		     -3;
-	priv->txbbgain_table[15].txbbgain_value=0x35c000d7;
+	priv->txbbgain_table[15].txbbgain_value = 0x35c000d7;
 	priv->txbbgain_table[16].txbb_iq_amplifygain =		     -4;
-	priv->txbbgain_table[16].txbbgain_value=0x32c000cb;
+	priv->txbbgain_table[16].txbbgain_value = 0x32c000cb;
 	priv->txbbgain_table[17].txbb_iq_amplifygain =		     -5;
-	priv->txbbgain_table[17].txbbgain_value=0x300000c0;
+	priv->txbbgain_table[17].txbbgain_value = 0x300000c0;
 	priv->txbbgain_table[18].txbb_iq_amplifygain =			    -6;
-	priv->txbbgain_table[18].txbbgain_value=0x2d4000b5;
+	priv->txbbgain_table[18].txbbgain_value = 0x2d4000b5;
 	priv->txbbgain_table[19].txbb_iq_amplifygain =		     -7;
-	priv->txbbgain_table[19].txbbgain_value=0x2ac000ab;
+	priv->txbbgain_table[19].txbbgain_value = 0x2ac000ab;
 	priv->txbbgain_table[20].txbb_iq_amplifygain =		     -8;
-	priv->txbbgain_table[20].txbbgain_value=0x288000a2;
+	priv->txbbgain_table[20].txbbgain_value = 0x288000a2;
 	priv->txbbgain_table[21].txbb_iq_amplifygain =		     -9;
-	priv->txbbgain_table[21].txbbgain_value=0x26000098;
+	priv->txbbgain_table[21].txbbgain_value = 0x26000098;
 	priv->txbbgain_table[22].txbb_iq_amplifygain =		     -10;
-	priv->txbbgain_table[22].txbbgain_value=0x24000090;
+	priv->txbbgain_table[22].txbbgain_value = 0x24000090;
 	priv->txbbgain_table[23].txbb_iq_amplifygain =		     -11;
-	priv->txbbgain_table[23].txbbgain_value=0x22000088;
+	priv->txbbgain_table[23].txbbgain_value = 0x22000088;
 	priv->txbbgain_table[24].txbb_iq_amplifygain =		     -12;
-	priv->txbbgain_table[24].txbbgain_value=0x20000080;
+	priv->txbbgain_table[24].txbbgain_value = 0x20000080;
 	priv->txbbgain_table[25].txbb_iq_amplifygain =		     -13;
-	priv->txbbgain_table[25].txbbgain_value=0x1a00006c;
+	priv->txbbgain_table[25].txbbgain_value = 0x1a00006c;
 	priv->txbbgain_table[26].txbb_iq_amplifygain =		     -14;
-	priv->txbbgain_table[26].txbbgain_value=0x1c800072;
+	priv->txbbgain_table[26].txbbgain_value = 0x1c800072;
 	priv->txbbgain_table[27].txbb_iq_amplifygain =		     -15;
-	priv->txbbgain_table[27].txbbgain_value=0x18000060;
+	priv->txbbgain_table[27].txbbgain_value = 0x18000060;
 	priv->txbbgain_table[28].txbb_iq_amplifygain =		     -16;
-	priv->txbbgain_table[28].txbbgain_value=0x19800066;
+	priv->txbbgain_table[28].txbbgain_value = 0x19800066;
 	priv->txbbgain_table[29].txbb_iq_amplifygain =		     -17;
-	priv->txbbgain_table[29].txbbgain_value=0x15800056;
+	priv->txbbgain_table[29].txbbgain_value = 0x15800056;
 	priv->txbbgain_table[30].txbb_iq_amplifygain =		     -18;
-	priv->txbbgain_table[30].txbbgain_value=0x26c0005b;
+	priv->txbbgain_table[30].txbbgain_value = 0x26c0005b;
 	priv->txbbgain_table[31].txbb_iq_amplifygain =		     -19;
-	priv->txbbgain_table[31].txbbgain_value=0x14400051;
+	priv->txbbgain_table[31].txbbgain_value = 0x14400051;
 	priv->txbbgain_table[32].txbb_iq_amplifygain =		     -20;
-	priv->txbbgain_table[32].txbbgain_value=0x24400051;
+	priv->txbbgain_table[32].txbbgain_value = 0x24400051;
 	priv->txbbgain_table[33].txbb_iq_amplifygain =		     -21;
-	priv->txbbgain_table[33].txbbgain_value=0x1300004c;
+	priv->txbbgain_table[33].txbbgain_value = 0x1300004c;
 	priv->txbbgain_table[34].txbb_iq_amplifygain =		     -22;
-	priv->txbbgain_table[34].txbbgain_value=0x12000048;
+	priv->txbbgain_table[34].txbbgain_value = 0x12000048;
 	priv->txbbgain_table[35].txbb_iq_amplifygain =		     -23;
-	priv->txbbgain_table[35].txbbgain_value=0x11000044;
+	priv->txbbgain_table[35].txbbgain_value = 0x11000044;
 	priv->txbbgain_table[36].txbb_iq_amplifygain =		     -24;
-	priv->txbbgain_table[36].txbbgain_value=0x10000040;
+	priv->txbbgain_table[36].txbbgain_value = 0x10000040;
 
-	//ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
-	//This Table is for CH1~CH13
+	/*
+	 * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+	 * This Table is for CH1~CH13
+	 */
 	priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36;
 	priv->cck_txbbgain_table[0].ccktxbb_valuearray[1] = 0x35;
 	priv->cck_txbbgain_table[0].ccktxbb_valuearray[2] = 0x2e;
@@ -1149,8 +1062,10 @@
 	priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03;
 	priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01;
 
-	//ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
-	//This Table is for CH14
+	/*
+	 * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+	 * This Table is for CH14
+	 */
 	priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36;
 	priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[1] = 0x35;
 	priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[2] = 0x2e;
@@ -1368,10 +1283,12 @@
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
-	// can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
-	// 3-wire by driver causes RF to go into a wrong state.
-	if(priv->ieee80211->FwRWRF)
+	/*
+	 * Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
+	 * can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
+	 * 3-wire by driver causes RF to go into a wrong state.
+	 */
+	if (priv->ieee80211->FwRWRF)
 		priv->btxpower_tracking = TRUE;
 	else
 		priv->btxpower_tracking = FALSE;
@@ -1379,57 +1296,46 @@
 	priv->btxpower_trackingInit = FALSE;
 }
 
-
 void dm_initialize_txpower_tracking(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	if(priv->bDcut == TRUE)
+
+	if (priv->bDcut == TRUE)
 		dm_InitializeTXPowerTracking_TSSI(dev);
 	else
 		dm_InitializeTXPowerTracking_ThermalMeter(dev);
-}// dm_InitializeTXPowerTracking
-
+} /* dm_InitializeTXPowerTracking */
 
 static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	static u32 tx_power_track_counter;
 
-	if(!priv->btxpower_tracking)
+	if (!priv->btxpower_tracking)
 		return;
-	else
-	{
-		if((tx_power_track_counter % 30 == 0)&&(tx_power_track_counter != 0))
-		{
-				queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
-		}
-		tx_power_track_counter++;
-	}
-
+	if ((tx_power_track_counter % 30 == 0) && (tx_power_track_counter != 0))
+		queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
+	tx_power_track_counter++;
 }
 
-
 static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	static u8	TM_Trigger;
-	//DbgPrint("dm_CheckTXPowerTracking() \n");
-	if(!priv->btxpower_tracking)
+	/*DbgPrint("dm_CheckTXPowerTracking()\n");*/
+	if (!priv->btxpower_tracking)
 		return;
-	else
-	{
-		if(priv->txpower_count  <= 2)
-		{
-			priv->txpower_count++;
-			return;
-		}
+	if (priv->txpower_count  <= 2) {
+		priv->txpower_count++;
+		return;
 	}
 
-	if(!TM_Trigger)
-	{
-		//Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
-		//actually write reg0x02 bit1=0, then bit1=1.
-		//DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
+	if (!TM_Trigger) {
+		/*
+		 * Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
+		 * actually write reg0x02 bit1=0, then bit1=1.
+		 * DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
+		 */
 		rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
 		rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
 		rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
@@ -1437,93 +1343,84 @@
 		TM_Trigger = 1;
 		return;
 	}
-	else
-	{
-		//DbgPrint("Schedule TxPowerTrackingWorkItem\n");
-			queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
-		TM_Trigger = 0;
-	}
+	/*DbgPrint("Schedule TxPowerTrackingWorkItem\n");*/
+		queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
+	TM_Trigger = 0;
 }
 
-
 static void dm_check_txpower_tracking(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	//static u32 tx_power_track_counter = 0;
+	/*static u32 tx_power_track_counter = 0;*/
 
-#ifdef  RTL8190P
+#ifdef RTL8190P
 	dm_CheckTXPowerTracking_TSSI(dev);
 #else
-	if(priv->bDcut == TRUE)
+	if (priv->bDcut == TRUE)
 		dm_CheckTXPowerTracking_TSSI(dev);
 	else
 		dm_CheckTXPowerTracking_ThermalMeter(dev);
 #endif
 
-}	// dm_CheckTXPowerTracking
-
+}	/* dm_CheckTXPowerTracking */
 
 static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool  bInCH14)
 {
 	u32 TempVal;
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	//Write 0xa22 0xa23
+
+	/* Write 0xa22 0xa23 */
 	TempVal = 0;
-	if(!bInCH14){
-		//Write 0xa22 0xa23
+	if (!bInCH14) {
+		/* Write 0xa22 0xa23 */
 		TempVal =	priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] +
-					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ;
+					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
-		//Write 0xa24 ~ 0xa27
+		/* Write 0xa24 ~ 0xa27 */
 		TempVal =	priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] +
 					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) +
 					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16)+
 					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24);
 		rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
-		//Write 0xa28  0xa29
+		/* Write 0xa28  0xa29 */
 		TempVal =	priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] +
-					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ;
+					(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
-	}
-	else
-	{
+	} else {
 		TempVal =	priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] +
-					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ;
+					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
-		//Write 0xa24 ~ 0xa27
+		/* Write 0xa24 ~ 0xa27 */
 		TempVal =	priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] +
 					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) +
 					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16)+
 					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24);
 		rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
-		//Write 0xa28  0xa29
+		/* Write 0xa28  0xa29 */
 		TempVal =	priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] +
-					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ;
+					(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
 	}
-
-
 }
 
-static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev,	bool  bInCH14)
+static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool  bInCH14)
 {
 	u32 TempVal;
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
 	TempVal = 0;
-	if(!bInCH14)
-	{
-		//Write 0xa22 0xa23
+	if (!bInCH14) {
+		/* Write 0xa22 0xa23 */
 		TempVal =	CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] +
-					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8) ;
+					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8);
 		rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
 			rCCK0_TxFilter1, TempVal);
-		//Write 0xa24 ~ 0xa27
+		/* Write 0xa24 ~ 0xa27 */
 		TempVal =	CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] +
 					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) +
 					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16)+
@@ -1531,25 +1428,23 @@
 		rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
 			rCCK0_TxFilter2, TempVal);
-		//Write 0xa28  0xa29
+		/* Write 0xa28  0xa29 */
 		TempVal =	CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] +
-					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8) ;
+					(CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
 			rCCK0_DebugPort, TempVal);
-	}
-	else
-	{
-//		priv->CCKTxPowerAdjustCntNotCh14++;	//cosa add for debug.
-		//Write 0xa22 0xa23
+	} else {
+		/*priv->CCKTxPowerAdjustCntNotCh14++;	cosa add for debug.*/
+		/* Write 0xa22 0xa23 */
 		TempVal =	CCKSwingTable_Ch14[priv->CCK_index][0] +
-					(CCKSwingTable_Ch14[priv->CCK_index][1]<<8) ;
+					(CCKSwingTable_Ch14[priv->CCK_index][1]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
 			rCCK0_TxFilter1, TempVal);
-		//Write 0xa24 ~ 0xa27
+		/* Write 0xa24 ~ 0xa27 */
 		TempVal =	CCKSwingTable_Ch14[priv->CCK_index][2] +
 					(CCKSwingTable_Ch14[priv->CCK_index][3]<<8) +
 					(CCKSwingTable_Ch14[priv->CCK_index][4]<<16)+
@@ -1557,9 +1452,9 @@
 		rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
 			rCCK0_TxFilter2, TempVal);
-		//Write 0xa28  0xa29
+		/* Write 0xa28  0xa29 */
 		TempVal =	CCKSwingTable_Ch14[priv->CCK_index][6] +
-					(CCKSwingTable_Ch14[priv->CCK_index][7]<<8) ;
+					(CCKSwingTable_Ch14[priv->CCK_index][7]<<8);
 
 		rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
 		RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
@@ -1567,20 +1462,17 @@
 	}
 }
 
-
-
 void dm_cck_txpower_adjust(struct net_device *dev, bool binch14)
-{	// dm_CCKTxPowerAdjust
-
+{	/*  dm_CCKTxPowerAdjust */
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	if(priv->bDcut == TRUE)
+
+	if (priv->bDcut == TRUE)
 		dm_CCKTxPowerAdjust_TSSI(dev, binch14);
 	else
 		dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14);
 }
 
-
-#ifndef  RTL8192U
+#ifndef RTL8192U
 static void dm_txpower_reset_recovery(
 	struct net_device *dev
 )
@@ -1589,75 +1481,71 @@
 
 	RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n");
 	rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n",priv->rfa_txpowertrackingindex);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n",priv->cck_present_attentuation);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n", priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n", priv->rfa_txpowertrackingindex);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n", priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n", priv->cck_present_attentuation);
 	dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
 
 	rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n",priv->rfc_txpowertrackingindex);
-	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n", priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n", priv->rfc_txpowertrackingindex);
+	RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n", priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain);
 
-}	// dm_TXPowerResetRecovery
+}	/* dm_TXPowerResetRecovery */
 
 void dm_restore_dynamic_mechanism_state(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	u32	reg_ratr = priv->rate_adaptive.last_ratr;
 
-	if(!priv->up)
-	{
+	if (!priv->up) {
 		RT_TRACE(COMP_RATE, "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n");
 		return;
 	}
 
-	//
-	// Restore previous state for rate adaptive
-	//
-	if(priv->rate_adaptive.rate_adaptive_disabled)
+	/* Restore previous state for rate adaptive */
+	if (priv->rate_adaptive.rate_adaptive_disabled)
 		return;
-	// TODO: Only 11n mode is implemented currently,
-	if(!(priv->ieee80211->mode==WIRELESS_MODE_N_24G ||
-		 priv->ieee80211->mode==WIRELESS_MODE_N_5G))
-		 return;
+	/* TODO: Only 11n mode is implemented currently, */
+	if (!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
+		priv->ieee80211->mode == WIRELESS_MODE_N_5G))
+		return;
+
 	{
 			/* 2007/11/15 MH Copy from 8190PCI. */
 			u32 ratr_value;
+
 			ratr_value = reg_ratr;
-			if(priv->rf_type == RF_1T2R)	// 1T2R, Spatial Stream 2 should be disabled
-			{
+			if (priv->rf_type == RF_1T2R) {	/* 1T2R, Spatial Stream 2 should be disabled */
 				ratr_value &= ~(RATE_ALL_OFDM_2SS);
-				//DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value);
+				/*DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value);*/
 			}
-			//DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value);
-			//cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]);
+			/*DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value);*/
+			/*cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]);*/
 			write_nic_dword(dev, RATR0, ratr_value);
 			write_nic_byte(dev, UFWP, 1);
 	}
-	//Restore TX Power Tracking Index
+	/* Restore TX Power Tracking Index */
 	if (priv->btxpower_trackingInit && priv->btxpower_tracking)
 		dm_txpower_reset_recovery(dev);
 
-	//
-	//Restore BB Initial Gain
-	//
+	/* Restore BB Initial Gain */
 	dm_bb_initialgain_restore(dev);
 
-}	// DM_RestoreDynamicMechanismState
+}	/* DM_RestoreDynamicMechanismState */
 
 static void dm_bb_initialgain_restore(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	u32 bit_mask = 0x7f; //Bit0~ Bit6
+	u32 bit_mask = 0x7f; /* Bit0~ Bit6 */
 
-	if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+	if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
 		return;
 
-	//Disable Initial Gain
-	//PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);
-	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	// Only clear byte 1 and rewrite.
+	/* Disable Initial Gain */
+	/*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/
+	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	/* Only clear byte 1 and rewrite. */
 	rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1);
 	rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1);
 	rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, (u32)priv->initgain_backup.xcagccore1);
@@ -1665,41 +1553,39 @@
 	bit_mask  = bMaskByte2;
 	rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, (u32)priv->initgain_backup.cca);
 
-	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
-	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
-	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
-	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
-	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca);
-	//Enable Initial Gain
-	//PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100);
-	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	// Only clear byte 1 and rewrite.
+	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n", priv->initgain_backup.xaagccore1);
+	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n", priv->initgain_backup.xbagccore1);
+	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n", priv->initgain_backup.xcagccore1);
+	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n", priv->initgain_backup.xdagccore1);
+	RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca);
+	/* Enable Initial Gain */
+	/*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100);*/
+	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	/* Only clear byte 1 and rewrite. */
 
-}	// dm_BBInitialGainRestore
-
+}	/* dm_BBInitialGainRestore */
 
 void dm_backup_dynamic_mechanism_state(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// Fsync to avoid reset
+	/* Fsync to avoid reset */
 	priv->bswitch_fsync  = false;
 	priv->bfsync_processing = false;
-	//Backup BB InitialGain
+	/* Backup BB InitialGain */
 	dm_bb_initialgain_backup(dev);
 
-}	// DM_BackupDynamicMechanismState
-
+}	/* DM_BackupDynamicMechanismState */
 
 static void dm_bb_initialgain_backup(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	u32 bit_mask = bMaskByte0; //Bit0~ Bit6
+	u32 bit_mask = bMaskByte0; /* Bit0~ Bit6 */
 
-	if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+	if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
 		return;
 
-	//PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);
-	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	// Only clear byte 1 and rewrite.
+	/*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/
+	rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	/* Only clear byte 1 and rewrite. */
 	priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask);
 	priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask);
 	priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask);
@@ -1707,13 +1593,13 @@
 	bit_mask  = bMaskByte2;
 	priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask);
 
-	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
-	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
-	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
-	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
-	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca);
+	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n", priv->initgain_backup.xaagccore1);
+	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n", priv->initgain_backup.xbagccore1);
+	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n", priv->initgain_backup.xcagccore1);
+	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n", priv->initgain_backup.xdagccore1);
+	RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n", priv->initgain_backup.cca);
 
-}   // dm_BBInitialGainBakcup
+}   /* dm_BBInitialGainBakcup */
 
 #endif
 /*-----------------------------------------------------------------------------
@@ -1736,67 +1622,44 @@
 void dm_change_dynamic_initgain_thresh(struct net_device *dev, u32 dm_type,
 				       u32 dm_value)
 {
-	if (dm_type == DIG_TYPE_THRESH_HIGH)
-	{
+	if (dm_type == DIG_TYPE_THRESH_HIGH) {
 		dm_digtable.rssi_high_thresh = dm_value;
-	}
-	else if (dm_type == DIG_TYPE_THRESH_LOW)
-	{
+	} else if (dm_type == DIG_TYPE_THRESH_LOW) {
 		dm_digtable.rssi_low_thresh = dm_value;
-	}
-	else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH)
-	{
+	} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
 		dm_digtable.rssi_high_power_highthresh = dm_value;
-	}
-	else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH)
-	{
+	} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
 		dm_digtable.rssi_high_power_highthresh = dm_value;
-	}
-	else if (dm_type == DIG_TYPE_ENABLE)
-	{
+	} else if (dm_type == DIG_TYPE_ENABLE) {
 		dm_digtable.dig_state		= DM_STA_DIG_MAX;
 		dm_digtable.dig_enable_flag	= true;
-	}
-	else if (dm_type == DIG_TYPE_DISABLE)
-	{
+	} else if (dm_type == DIG_TYPE_DISABLE) {
 		dm_digtable.dig_state		= DM_STA_DIG_MAX;
 		dm_digtable.dig_enable_flag	= false;
-	}
-	else if (dm_type == DIG_TYPE_DBG_MODE)
-	{
-		if(dm_value >= DM_DBG_MAX)
+	} else if (dm_type == DIG_TYPE_DBG_MODE) {
+		if (dm_value >= DM_DBG_MAX)
 			dm_value = DM_DBG_OFF;
 		dm_digtable.dbg_mode		= (u8)dm_value;
-	}
-	else if (dm_type == DIG_TYPE_RSSI)
-	{
-		if(dm_value > 100)
+	} else if (dm_type == DIG_TYPE_RSSI) {
+		if (dm_value > 100)
 			dm_value = 30;
 		dm_digtable.rssi_val			= (long)dm_value;
-	}
-	else if (dm_type == DIG_TYPE_ALGORITHM)
-	{
+	} else if (dm_type == DIG_TYPE_ALGORITHM) {
 		if (dm_value >= DIG_ALGO_MAX)
 			dm_value = DIG_ALGO_BY_FALSE_ALARM;
-		if(dm_digtable.dig_algorithm != (u8)dm_value)
+		if (dm_digtable.dig_algorithm != (u8)dm_value)
 			dm_digtable.dig_algorithm_switch = 1;
 		dm_digtable.dig_algorithm	= (u8)dm_value;
-	}
-	else if (dm_type == DIG_TYPE_BACKOFF)
-	{
-		if(dm_value > 30)
+	} else if (dm_type == DIG_TYPE_BACKOFF) {
+		if (dm_value > 30)
 			dm_value = 30;
 		dm_digtable.backoff_val		= (u8)dm_value;
-	}
-	else if(dm_type == DIG_TYPE_RX_GAIN_MIN)
-	{
-		if(dm_value == 0)
+	} else if (dm_type == DIG_TYPE_RX_GAIN_MIN) {
+		if (dm_value == 0)
 			dm_value = 0x1;
 		dm_digtable.rx_gain_range_min = (u8)dm_value;
-	}
-	else if(dm_type == DIG_TYPE_RX_GAIN_MAX)
-	{
-		if(dm_value > 0x50)
+	} else if (dm_type == DIG_TYPE_RX_GAIN_MAX) {
+		if (dm_value > 0x50)
 			dm_value = 0x50;
 		dm_digtable.rx_gain_range_max = (u8)dm_value;
 	}
@@ -1824,7 +1687,7 @@
 	/* 2007/10/05 MH Disable DIG scheme now. Not tested. */
 	dm_digtable.dig_enable_flag	= true;
 	dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI;
-	dm_digtable.dbg_mode = DM_DBG_OFF;	//off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
+	dm_digtable.dbg_mode = DM_DBG_OFF;	/* off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig */
 	dm_digtable.dig_algorithm_switch = 0;
 
 	/* 2007/10/04 MH Define init gain threshold. */
@@ -1838,17 +1701,16 @@
 	dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
 	dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
 
-	dm_digtable.rssi_val = 50;	//for new dig debug rssi value
+	dm_digtable.rssi_val = 50;	/* for new dig debug rssi value */
 	dm_digtable.backoff_val = DM_DIG_BACKOFF;
 	dm_digtable.rx_gain_range_max = DM_DIG_MAX;
-	if(priv->CustomerID == RT_CID_819x_Netcore)
+	if (priv->CustomerID == RT_CID_819x_Netcore)
 		dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore;
 	else
 		dm_digtable.rx_gain_range_min = DM_DIG_MIN;
 
 }	/* dm_dig_init */
 
-
 /*-----------------------------------------------------------------------------
  * Function:	dm_ctrl_initgain_byrssi()
  *
@@ -1868,20 +1730,18 @@
  *---------------------------------------------------------------------------*/
 static void dm_ctrl_initgain_byrssi(struct net_device *dev)
 {
-
 	if (dm_digtable.dig_enable_flag == false)
 		return;
 
-	if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
+	if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
 		dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev);
-	else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+	else if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
 		dm_ctrl_initgain_byrssi_by_driverrssi(dev);
-//		;
+	/* ; */
 	else
 		return;
 }
 
-
 static void dm_ctrl_initgain_byrssi_by_driverrssi(
 	struct net_device *dev)
 {
@@ -1892,32 +1752,33 @@
 	if (dm_digtable.dig_enable_flag == false)
 		return;
 
-	//DbgPrint("Dig by Sw Rssi \n");
-	if(dm_digtable.dig_algorithm_switch)	// if switched algorithm, we have to disable FW Dig.
+	/*DbgPrint("Dig by Sw Rssi\n");*/
+	if (dm_digtable.dig_algorithm_switch)	/* if switched algorithm, we have to disable FW Dig. */
 		fw_dig = 0;
-	if(fw_dig <= 3)	// execute several times to make sure the FW Dig is disabled
-	{// FW DIG Off
-		for(i=0; i<3; i++)
-			rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	// Only clear byte 1 and rewrite.
+
+	if (fw_dig <= 3) { /* execute several times to make sure the FW Dig is disabled */
+		/* FW DIG Off */
+		for (i = 0; i < 3; i++)
+			rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	/* Only clear byte 1 and rewrite. */
 		fw_dig++;
-		dm_digtable.dig_state = DM_STA_DIG_OFF;	//fw dig off.
+		dm_digtable.dig_state = DM_STA_DIG_OFF;	/* fw dig off. */
 	}
 
-	if(priv->ieee80211->state == IEEE80211_LINKED)
+	if (priv->ieee80211->state == IEEE80211_LINKED)
 		dm_digtable.cur_connect_state = DIG_CONNECT;
 	else
 		dm_digtable.cur_connect_state = DIG_DISCONNECT;
 
-	//DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d \n",
-		//DM_DigTable.PreConnectState, DM_DigTable.CurConnectState);
+	/*DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d\n",
+		DM_DigTable.PreConnectState, DM_DigTable.CurConnectState);*/
 
-	if(dm_digtable.dbg_mode == DM_DBG_OFF)
+	if (dm_digtable.dbg_mode == DM_DBG_OFF)
 		dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb;
-	//DbgPrint("DM_DigTable.Rssi_val = %d \n", DM_DigTable.Rssi_val);
+	/*DbgPrint("DM_DigTable.Rssi_val = %d\n", DM_DigTable.Rssi_val);*/
 	dm_initial_gain(dev);
 	dm_pd_th(dev);
 	dm_cs_ratio(dev);
-	if(dm_digtable.dig_algorithm_switch)
+	if (dm_digtable.dig_algorithm_switch)
 		dm_digtable.dig_algorithm_switch = 0;
 	dm_digtable.pre_connect_state = dm_digtable.cur_connect_state;
 
@@ -1933,152 +1794,138 @@
 	if (dm_digtable.dig_enable_flag == false)
 		return;
 
-	if(dm_digtable.dig_algorithm_switch)
-	{
+	if (dm_digtable.dig_algorithm_switch) {
 		dm_digtable.dig_state = DM_STA_DIG_MAX;
-		// Fw DIG On.
-		for(i=0; i<3; i++)
-			rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	// Only clear byte 1 and rewrite.
+		/* Fw DIG On. */
+		for (i = 0; i < 3; i++)
+			rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	/* Only clear byte 1 and rewrite.*/
 		dm_digtable.dig_algorithm_switch = 0;
 	}
 
 	if (priv->ieee80211->state != IEEE80211_LINKED)
 		return;
 
-	// For smooth, we can not change DIG state.
+	/* For smooth, we can not change DIG state. */
 	if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) &&
 		(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh))
-	{
 		return;
-	}
-	//DbgPrint("Dig by Fw False Alarm\n");
-	//if (DM_DigTable.Dig_State == DM_STA_DIG_OFF)
+
+	/*DbgPrint("Dig by Fw False Alarm\n");*/
+	/*if (DM_DigTable.Dig_State == DM_STA_DIG_OFF)*/
 	/*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d",
 	pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
 	DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
 	/* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
 		  and then execute the step below. */
-	if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
-	{
+	if (priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh) {
 		/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
 		   will be reset to init value. We must prevent the condition. */
 		if (dm_digtable.dig_state == DM_STA_DIG_OFF &&
-			(priv->reset_count == reset_cnt))
-		{
+		    (priv->reset_count == reset_cnt)) {
 			return;
 		}
-		else
-		{
-			reset_cnt = priv->reset_count;
-		}
+		reset_cnt = priv->reset_count;
 
-		// If DIG is off, DIG high power state must reset.
+		/* If DIG is off, DIG high power state must reset. */
 		dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
 		dm_digtable.dig_state = DM_STA_DIG_OFF;
 
-		// 1.1 DIG Off.
-		rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	// Only clear byte 1 and rewrite.
+		/*  1.1 DIG Off. */
+		rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8);	/*  Only clear byte 1 and rewrite. */
 
-		// 1.2 Set initial gain.
+		/*  1.2 Set initial gain. */
 		write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17);
 		write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17);
 		write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17);
 		write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17);
 
-		// 1.3 Lower PD_TH for OFDM.
-		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-		{
-			/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
-			// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+		/*  1.3 Lower PD_TH for OFDM. */
+		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+			/*
+			 * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+			 * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+			 */
 			write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
 			/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 				write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40);
+			else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+			else
+				PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40);
 			*/
-			//else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
-
-
-			//else
-				//PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40);
-		}
-		else
+		} else
 			write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
 
-		// 1.4 Lower CS ratio for CCK.
+		/* 1.4 Lower CS ratio for CCK. */
 		write_nic_byte(dev, 0xa0a, 0x08);
 
-		// 1.5 Higher EDCCA.
-		//PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);
+		/* 1.5 Higher EDCCA. */
+		/*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);*/
 		return;
 
 	}
 
 	/* 2. When RSSI increase, We have to judge if it is larger than a threshold
 		  and then execute the step below.  */
-	if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh))
-	{
+	if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
 		u8 reset_flag = 0;
 
 		if (dm_digtable.dig_state == DM_STA_DIG_ON &&
-			(priv->reset_count == reset_cnt))
-		{
+			(priv->reset_count == reset_cnt)) {
 			dm_ctrl_initgain_byrssi_highpwr(dev);
 			return;
 		}
-		else
-		{
-			if (priv->reset_count != reset_cnt)
-				reset_flag = 1;
+		if (priv->reset_count != reset_cnt)
+			reset_flag = 1;
 
-			reset_cnt = priv->reset_count;
-		}
+		reset_cnt = priv->reset_count;
 
 		dm_digtable.dig_state = DM_STA_DIG_ON;
-		//DbgPrint("DIG ON\n\r");
+		/*DbgPrint("DIG ON\n\r");*/
 
-		// 2.1 Set initial gain.
-		// 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
-		if (reset_flag == 1)
-		{
+		/*
+		 * 2.1 Set initial gain.
+		 * 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
+		 */
+		if (reset_flag == 1) {
 			write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c);
 			write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c);
 			write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c);
 			write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c);
-		}
-		else
-		{
+		} else {
 			write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20);
 			write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20);
 			write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20);
 			write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20);
 		}
 
-		// 2.2 Higher PD_TH for OFDM.
-		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-		{
-			/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
-			// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+		/* 2.2 Higher PD_TH for OFDM. */
+		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+			/*
+			 * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+			 * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+			 */
 			write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
 			/*
 			else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 				write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
+			else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+			else
+				PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42);
 			*/
-			//else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
-
-			//else
-				//PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42);
-		}
-		else
+		} else
 			write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
 
-		// 2.3 Higher CS ratio for CCK.
+		/* 2.3 Higher CS ratio for CCK. */
 		write_nic_byte(dev, 0xa0a, 0xcd);
 
-		// 2.4 Lower EDCCA.
-		/* 2008/01/11 MH 90/92 series are the same. */
-		//PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);
+		/*
+		 * 2.4 Lower EDCCA.
+		 * 2008/01/11 MH 90/92 series are the same.
+		 */
+		/*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);*/
 
-		// 2.5 DIG On.
-		rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	// Only clear byte 1 and rewrite.
+		/* 2.5 DIG On. */
+		rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1);	/*  Only clear byte 1 and rewrite. */
 
 	}
 
@@ -2086,7 +1933,6 @@
 
 }	/* dm_CtrlInitGainByRssi */
 
-
 /*-----------------------------------------------------------------------------
  * Function:	dm_ctrl_initgain_byrssi_highpwr()
  *
@@ -2109,58 +1955,49 @@
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	static u32 reset_cnt_highpwr;
 
-	// For smooth, we can not change high power DIG state in the range.
+	/*  For smooth, we can not change high power DIG state in the range. */
 	if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) &&
 		(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh))
-	{
 		return;
-	}
 
-	/* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
-		  it is larger than a threshold and then execute the step below.  */
-	// 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
-	if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
-	{
+	/*
+	 * 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
+	 *    it is larger than a threshold and then execute the step below.
+	 *
+	 * 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
+	 */
+	if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) {
 		if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON &&
 			(priv->reset_count == reset_cnt_highpwr))
 			return;
-		else
-			dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
+		dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
 
-		// 3.1 Higher PD_TH for OFDM for high power state.
-		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-		{
+		/* 3.1 Higher PD_TH for OFDM for high power state. */
+		if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
 			write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10);
 
 			/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 				write_nic_byte(dev, rOFDM0_RxDetector1, 0x41);
 			*/
 
-		}
-		else
+		} else
 			write_nic_byte(dev, rOFDM0_RxDetector1, 0x43);
-	}
-	else
-	{
-		if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF&&
+	} else {
+		if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF &&
 			(priv->reset_count == reset_cnt_highpwr))
 			return;
-		else
-			dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF;
+		dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF;
 
 		if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh &&
-			 priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh)
-		{
-			// 3.2 Recover PD_TH for OFDM for normal power region.
-			if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-			{
+			 priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
+			/*  3.2 Recover PD_TH for OFDM for normal power region. */
+			if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
 				write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
 				/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 					write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
 				*/
 
-			}
-			else
+			} else
 				write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
 		}
 	}
@@ -2169,51 +2006,42 @@
 
 }	/* dm_CtrlInitGainByRssiHighPwr */
 
-
 static void dm_initial_gain(
 	struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	u8					initial_gain=0;
+	u8					initial_gain = 0;
 	static u8				initialized, force_write;
 	static u32			reset_cnt;
 	u8				tmp;
 
-	if(dm_digtable.dig_algorithm_switch)
-	{
+	if (dm_digtable.dig_algorithm_switch) {
 		initialized = 0;
 		reset_cnt = 0;
 	}
 
-	if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
-	{
-		if(dm_digtable.cur_connect_state == DIG_CONNECT)
-		{
-			if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max)
+	if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+		if (dm_digtable.cur_connect_state == DIG_CONNECT) {
+			if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max)
 				dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max;
-			else if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
+			else if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
 				dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min;
 			else
 				dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val;
-		}
-		else		//current state is disconnected
-		{
-			if(dm_digtable.cur_ig_value == 0)
+		} else {	/* current state is disconnected */
+			if (dm_digtable.cur_ig_value == 0)
 				dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
 			else
 				dm_digtable.cur_ig_value = dm_digtable.pre_ig_value;
 		}
-	}
-	else	// disconnected -> connected or connected -> disconnected
-	{
+	} else { /*  disconnected -> connected or connected -> disconnected */
 		dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
 		dm_digtable.pre_ig_value = 0;
 	}
-	//DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue);
+	/*DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue);*/
 
-	// if silent reset happened, we should rewrite the values back
-	if(priv->reset_count != reset_cnt)
-	{
+	/* if silent reset happened, we should rewrite the values back */
+	if (priv->reset_count != reset_cnt) {
 		force_write = 1;
 		reset_cnt = priv->reset_count;
 	}
@@ -2223,12 +2051,11 @@
 		force_write = 1;
 
 	{
-		if((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
-			|| !initialized || force_write)
-		{
+		if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
+			|| !initialized || force_write) {
 			initial_gain = (u8)dm_digtable.cur_ig_value;
-			//DbgPrint("Write initial gain = 0x%x\n", initial_gain);
-			// Set initial gain.
+			/*DbgPrint("Write initial gain = 0x%x\n", initial_gain);*/
+			/*  Set initial gain. */
 			write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain);
 			write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain);
 			write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain);
@@ -2247,93 +2074,77 @@
 	static u8				initialized, force_write;
 	static u32			reset_cnt;
 
-	if(dm_digtable.dig_algorithm_switch)
-	{
+	if (dm_digtable.dig_algorithm_switch) {
 		initialized = 0;
 		reset_cnt = 0;
 	}
 
-	if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
-	{
-		if(dm_digtable.cur_connect_state == DIG_CONNECT)
-		{
+	if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+		if (dm_digtable.cur_connect_state == DIG_CONNECT) {
 			if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh)
 				dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER;
-			else if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
+			else if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)
 				dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
 			else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) &&
 					(dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh))
 				dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER;
 			else
 				dm_digtable.curpd_thstate = dm_digtable.prepd_thstate;
-		}
-		else
-		{
+		} else {
 			dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
 		}
-	}
-	else	// disconnected -> connected or connected -> disconnected
-	{
+	} else { /* disconnected -> connected or connected -> disconnected */
 		dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
 	}
 
-	// if silent reset happened, we should rewrite the values back
-	if(priv->reset_count != reset_cnt)
-	{
+	/*  if silent reset happened, we should rewrite the values back */
+	if (priv->reset_count != reset_cnt) {
 		force_write = 1;
 		reset_cnt = priv->reset_count;
 	}
 
 	{
-		if((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
-			(initialized<=3) || force_write)
-		{
-			//DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState);
-			if(dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER)
-			{
-				// Lower PD_TH for OFDM.
-				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-				{
-					/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
-					// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+		if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
+		    (initialized <= 3) || force_write) {
+			/*DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState);*/
+			if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
+				/*  Lower PD_TH for OFDM. */
+				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+					/*
+					 * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+					 * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+					 */
 					write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
 					/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 						write_nic_byte(dev, rOFDM0_RxDetector1, 0x40);
 					*/
-				}
-				else
+				} else
 					write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
-			}
-			else if(dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER)
-			{
-				// Higher PD_TH for OFDM.
-				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-				{
-					/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
-					// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+			} else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) {
+				/* Higher PD_TH for OFDM. */
+				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+					/*
+					 * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+					 * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+					 */
 					write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
 					/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 						write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
 					*/
-				}
-				else
+				} else
 					write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
-			}
-			else if(dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER)
-			{
-				// Higher PD_TH for OFDM for high power state.
-				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
-				{
+			} else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) {
+				/* Higher PD_TH for OFDM for high power state. */
+				if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
 					write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10);
 					/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
 						write_nic_byte(dev, rOFDM0_RxDetector1, 0x41);
 					*/
-				}
-				else
+				} else
 					write_nic_byte(dev, rOFDM0_RxDetector1, 0x43);
 			}
 			dm_digtable.prepd_thstate = dm_digtable.curpd_thstate;
-			if(initialized <= 3)
+			if (initialized <= 3)
 				initialized++;
 			force_write = 0;
 		}
@@ -2347,54 +2158,40 @@
 	static u8				initialized, force_write;
 	static u32			reset_cnt;
 
-	if(dm_digtable.dig_algorithm_switch)
-	{
+	if (dm_digtable.dig_algorithm_switch) {
 		initialized = 0;
 		reset_cnt = 0;
 	}
 
-	if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
-	{
-		if(dm_digtable.cur_connect_state == DIG_CONNECT)
-		{
-			if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
+	if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+		if (dm_digtable.cur_connect_state == DIG_CONNECT) {
+			if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)
 				dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
-			else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh))
+			else if (dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh)
 				dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER;
 			else
 				dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state;
-		}
-		else
-		{
+		} else {
 			dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
 		}
-	}
-	else	// disconnected -> connected or connected -> disconnected
-	{
+	} else	/* disconnected -> connected or connected -> disconnected */
 		dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
-	}
 
-	// if silent reset happened, we should rewrite the values back
-	if(priv->reset_count != reset_cnt)
-	{
+	/* if silent reset happened, we should rewrite the values back */
+	if (priv->reset_count != reset_cnt) {
 		force_write = 1;
 		reset_cnt = priv->reset_count;
 	}
 
-
 	{
-		if((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
-			!initialized || force_write)
-		{
-			//DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState);
-			if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER)
-			{
-				// Lower CS ratio for CCK.
+		if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
+			!initialized || force_write) {
+			/*DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState);*/
+			if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) {
+				/*  Lower CS ratio for CCK. */
 				write_nic_byte(dev, 0xa0a, 0x08);
-			}
-			else if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER)
-			{
-				// Higher CS ratio for CCK.
+			} else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) {
+				/*  Higher CS ratio for CCK. */
 				write_nic_byte(dev, 0xa0a, 0xcd);
 			}
 			dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state;
@@ -2411,53 +2208,46 @@
 	priv->bcurrent_turbo_EDCA = false;
 	priv->ieee80211->bis_any_nonbepkts = false;
 	priv->bis_cur_rdlstate = false;
-}	// dm_init_edca_turbo
+}	/* dm_init_edca_turbo */
 
 static void dm_check_edca_turbo(
 	struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	PRT_HIGH_THROUGHPUT	pHTInfo = priv->ieee80211->pHTInfo;
-	//PSTA_QOS			pStaQos = pMgntInfo->pStaQos;
+	/*PSTA_QOS			pStaQos = pMgntInfo->pStaQos;*/
 
-	// Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.
+	/* Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. */
 	static unsigned long			lastTxOkCnt;
 	static unsigned long			lastRxOkCnt;
 	unsigned long				curTxOkCnt = 0;
 	unsigned long				curRxOkCnt = 0;
 
-	//
-	// Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
-	// should follow the settings from QAP. By Bruce, 2007-12-07.
-	//
-	if(priv->ieee80211->state != IEEE80211_LINKED)
+	/*
+	 * Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
+	 * should follow the settings from QAP. By Bruce, 2007-12-07.
+	 */
+	if (priv->ieee80211->state != IEEE80211_LINKED)
 		goto dm_CheckEdcaTurbo_EXIT;
-	// We do not turn on EDCA turbo mode for some AP that has IOT issue
-	if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
+	/* We do not turn on EDCA turbo mode for some AP that has IOT issue */
+	if (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
 		goto dm_CheckEdcaTurbo_EXIT;
 
-//	printk("========>%s():bis_any_nonbepkts is %d\n",__func__,priv->bis_any_nonbepkts);
-	// Check the status for current condition.
-	if(!priv->ieee80211->bis_any_nonbepkts)
-	{
+	/*printk("========>%s():bis_any_nonbepkts is %d\n", __func__, priv->bis_any_nonbepkts);*/
+	/* Check the status for current condition. */
+	if (!priv->ieee80211->bis_any_nonbepkts) {
 		curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
 		curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
-		// For RT-AP, we needs to turn it on when Rx>Tx
-		if(curRxOkCnt > 4*curTxOkCnt)
-		{
-			//printk("%s():curRxOkCnt > 4*curTxOkCnt\n");
-			if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
-			{
+		/* For RT-AP, we needs to turn it on when Rx>Tx */
+		if (curRxOkCnt > 4*curTxOkCnt) {
+			/*printk("%s():curRxOkCnt > 4*curTxOkCnt\n");*/
+			if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) {
 				write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]);
 				priv->bis_cur_rdlstate = true;
 			}
-		}
-		else
-		{
-
-			//printk("%s():curRxOkCnt < 4*curTxOkCnt\n");
-			if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
-			{
+		} else {
+			/*printk("%s():curRxOkCnt < 4*curTxOkCnt\n");*/
+			if (priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) {
 				write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]);
 				priv->bis_cur_rdlstate = false;
 			}
@@ -2465,50 +2255,47 @@
 		}
 
 		priv->bcurrent_turbo_EDCA = true;
-	}
-	else
-	{
-		//
-		// Turn Off EDCA turbo here.
-		// Restore original EDCA according to the declaration of AP.
-		//
-		 if(priv->bcurrent_turbo_EDCA)
-		{
-
+	} else {
+		/*
+		 * Turn Off EDCA turbo here.
+		 * Restore original EDCA according to the declaration of AP.
+		 */
+		if (priv->bcurrent_turbo_EDCA) {
 			{
 				u8		u1bAIFS;
 				u32		u4bAcParam;
 				struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters;
 				u8 mode = priv->ieee80211->mode;
 
-			// For Each time updating EDCA parameter, reset EDCA turbo mode status.
+				/*  For Each time updating EDCA parameter, reset EDCA turbo mode status. */
 				dm_init_edca_turbo(dev);
-				u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime;
-				u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0]))<< AC_PARAM_TXOP_LIMIT_OFFSET)|
-					(((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)|
-					(((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)|
+				u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ? 9 : 20) + aSifsTime;
+				u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0])) << AC_PARAM_TXOP_LIMIT_OFFSET)|
+					(((u32)(qos_parameters->cw_max[0])) << AC_PARAM_ECW_MAX_OFFSET)|
+					(((u32)(qos_parameters->cw_min[0])) << AC_PARAM_ECW_MIN_OFFSET)|
 					((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
-			//write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);
+				/*write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);*/
 				write_nic_dword(dev, EDCAPARA_BE,  u4bAcParam);
 
-			// Check ACM bit.
-			// If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
+				/*
+				 * Check ACM bit.
+				 * If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
+				 */
 				{
-			// TODO:  Modified this part and try to set acm control in only 1 IO processing!!
+					/*  TODO:  Modified this part and try to set acm control in only 1 IO processing!! */
 
 					PACI_AIFSN	pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]);
 					u8		AcmCtrl;
+
 					read_nic_byte(dev, AcmHwCtrl, &AcmCtrl);
-					if(pAciAifsn->f.ACM)
-					{ // ACM bit is 1.
+
+					if (pAciAifsn->f.ACM) { /*  ACM bit is 1. */
 						AcmCtrl |= AcmHw_BeqEn;
-					}
-					else
-					{ // ACM bit is 0.
+					} else {	/* ACM bit is 0. */
 						AcmCtrl &= (~AcmHw_BeqEn);
 					}
 
-					RT_TRACE(COMP_QOS,"SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl) ;
+					RT_TRACE(COMP_QOS, "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
 					write_nic_byte(dev, AcmHwCtrl, AcmCtrl);
 				}
 			}
@@ -2516,13 +2303,12 @@
 		}
 	}
 
-
 dm_CheckEdcaTurbo_EXIT:
-	// Set variables for next time.
+	/* Set variables for next time. */
 	priv->ieee80211->bis_any_nonbepkts = false;
 	lastTxOkCnt = priv->stats.txbytesunicast;
 	lastRxOkCnt = priv->stats.rxbytesunicast;
-}	// dm_CheckEdcaTurbo
+}	/* dm_CheckEdcaTurbo */
 
 static void dm_init_ctstoself(struct net_device *dev)
 {
@@ -2541,8 +2327,7 @@
 	unsigned long						curTxOkCnt = 0;
 	unsigned long						curRxOkCnt = 0;
 
-	if(priv->ieee80211->bCTSToSelfEnable != TRUE)
-	{
+	if (priv->ieee80211->bCTSToSelfEnable != TRUE) {
 		pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
 		return;
 	}
@@ -2552,17 +2337,13 @@
 	3. <50 disable, >55 enable
 	*/
 
-	if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM)
-	{
+	if (pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) {
 		curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
 		curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
-		if(curRxOkCnt > 4*curTxOkCnt)	//downlink, disable CTS to self
-		{
+		if (curRxOkCnt > 4*curTxOkCnt) { /* downlink, disable CTS to self */
 			pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
-			//DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n");
-		}
-		else	//uplink
-		{
+			/*DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n");*/
+		} else { /* uplink */
 			pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF;
 		}
 
@@ -2592,15 +2373,15 @@
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	u8 tmp1byte;
 
-
 	read_nic_byte(dev, GPI, &tmp1byte);
-	if(tmp1byte == 0xff)
+	if (tmp1byte == 0xff)
 		return;
 
-	if (tmp1byte&BIT6 || tmp1byte&BIT0)
-	{
-		// Here we only set bPbcPressed to TRUE
-		// After trigger PBC, the variable will be set to FALSE
+	if (tmp1byte&BIT6 || tmp1byte&BIT0) {
+		/*
+		 * Here we only set bPbcPressed to TRUE
+		 * After trigger PBC, the variable will be set to FALSE
+		 */
 		RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n");
 		priv->bpbc_pressed = true;
 	}
@@ -2625,26 +2406,24 @@
  *---------------------------------------------------------------------------*/
 void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
 {
-	struct delayed_work *dwork = container_of(work,struct delayed_work,work);
-       struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq);
-       struct net_device *dev =priv->ieee80211->dev;
-	//bool bactually_set = false;
+	struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+	struct r8192_priv *priv = container_of(dwork, struct r8192_priv, rfpath_check_wq);
+	struct net_device *dev = priv->ieee80211->dev;
+	/*bool bactually_set = false;*/
 	u8 rfpath = 0, i;
 
-
 	/* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will
 	   always be the same. We only read 0xc04 now. */
 	read_nic_byte(dev, 0xc04, &rfpath);
 
-	// Check Bit 0-3, it means if RF A-D is enabled.
-	for (i = 0; i < RF90_PATH_MAX; i++)
-	{
+	/* Check Bit 0-3, it means if RF A-D is enabled. */
+	for (i = 0; i < RF90_PATH_MAX; i++) {
 		if (rfpath & (0x01<<i))
 			priv->brfpath_rxenable[i] = 1;
 		else
 			priv->brfpath_rxenable[i] = 0;
 	}
-	if(!DM_RxPathSelTable.Enable)
+	if (!DM_RxPathSelTable.Enable)
 		return;
 
 	dm_rxpath_sel_byrssi(dev);
@@ -2654,17 +2433,17 @@
 {
 	u8 i;
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	DM_RxPathSelTable.Enable = 1;	//default enabled
+
+	DM_RxPathSelTable.Enable = 1;	/* default enabled */
 	DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low;
 	DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH;
-	if(priv->CustomerID == RT_CID_819x_Netcore)
+	if (priv->CustomerID == RT_CID_819x_Netcore)
 		DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;
 	else
 		DM_RxPathSelTable.cck_method = CCK_Rx_Version_1;
 	DM_RxPathSelTable.DbgMode = DM_DBG_OFF;
 	DM_RxPathSelTable.disabledRF = 0;
-	for(i=0; i<4; i++)
-	{
+	for (i = 0; i < 4; i++) {
 		DM_RxPathSelTable.rf_rssi[i] = 50;
 		DM_RxPathSelTable.cck_pwdb_sta[i] = -64;
 		DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
@@ -2674,22 +2453,21 @@
 static void dm_rxpath_sel_byrssi(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	u8				i, max_rssi_index=0, min_rssi_index=0, sec_rssi_index=0, rf_num=0;
-	u8				tmp_max_rssi=0, tmp_min_rssi=0, tmp_sec_rssi=0;
-	u8				cck_default_Rx=0x2;	//RF-C
-	u8				cck_optional_Rx=0x3;//RF-D
-	long				tmp_cck_max_pwdb=0, tmp_cck_min_pwdb=0, tmp_cck_sec_pwdb=0;
-	u8				cck_rx_ver2_max_index=0, cck_rx_ver2_min_index=0, cck_rx_ver2_sec_index=0;
+	u8				i, max_rssi_index = 0, min_rssi_index = 0, sec_rssi_index = 0, rf_num = 0;
+	u8				tmp_max_rssi = 0, tmp_min_rssi = 0, tmp_sec_rssi = 0;
+	u8				cck_default_Rx = 0x2;  /* RF-C */
+	u8				cck_optional_Rx = 0x3; /* RF-D */
+	long				tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0;
+	u8				cck_rx_ver2_max_index = 0, cck_rx_ver2_min_index = 0, cck_rx_ver2_sec_index = 0;
 	u8				cur_rf_rssi;
 	long				cur_cck_pwdb;
 	static u8			disabled_rf_cnt, cck_Rx_Path_initialized;
 	u8				update_cck_rx_path;
 
-	if(priv->rf_type != RF_2T4R)
+	if (priv->rf_type != RF_2T4R)
 		return;
 
-	if(!cck_Rx_Path_initialized)
-	{
+	if (!cck_Rx_Path_initialized) {
 		read_nic_byte(dev, 0xa07, &DM_RxPathSelTable.cck_Rx_path);
 		DM_RxPathSelTable.cck_Rx_path &= 0xf;
 		cck_Rx_Path_initialized = 1;
@@ -2698,90 +2476,63 @@
 	read_nic_byte(dev, 0xc04, &DM_RxPathSelTable.disabledRF);
 	DM_RxPathSelTable.disabledRF = ~DM_RxPathSelTable.disabledRF & 0xf;
 
-	if(priv->ieee80211->mode == WIRELESS_MODE_B)
-	{
-		DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;	//pure B mode, fixed cck version2
-		//DbgPrint("Pure B mode, use cck rx version2 \n");
+	if (priv->ieee80211->mode == WIRELESS_MODE_B) {
+		DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;	/* pure B mode, fixed cck version2 */
+		/*DbgPrint("Pure B mode, use cck rx version2\n");*/
 	}
 
-	//decide max/sec/min rssi index
-	for (i=0; i<RF90_PATH_MAX; i++)
-	{
-		if(!DM_RxPathSelTable.DbgMode)
+	/* decide max/sec/min rssi index */
+	for (i = 0; i < RF90_PATH_MAX; i++) {
+		if (!DM_RxPathSelTable.DbgMode)
 			DM_RxPathSelTable.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
 
-		if(priv->brfpath_rxenable[i])
-		{
+		if (priv->brfpath_rxenable[i]) {
 			rf_num++;
 			cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i];
 
-			if(rf_num == 1)	// find first enabled rf path and the rssi values
-			{	//initialize, set all rssi index to the same one
+			if (rf_num == 1) { /* find first enabled rf path and the rssi values */
+				/* initialize, set all rssi index to the same one */
 				max_rssi_index = min_rssi_index = sec_rssi_index = i;
 				tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi;
-			}
-			else if(rf_num == 2)
-			{	// we pick up the max index first, and let sec and min to be the same one
-				if(cur_rf_rssi >= tmp_max_rssi)
-				{
+			} else if (rf_num == 2) { /* we pick up the max index first, and let sec and min to be the same one */
+				if (cur_rf_rssi >= tmp_max_rssi) {
 					tmp_max_rssi = cur_rf_rssi;
 					max_rssi_index = i;
-				}
-				else
-				{
+				} else {
 					tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi;
 					sec_rssi_index = min_rssi_index = i;
 				}
-			}
-			else
-			{
-				if(cur_rf_rssi > tmp_max_rssi)
-				{
+			} else {
+				if (cur_rf_rssi > tmp_max_rssi) {
 					tmp_sec_rssi = tmp_max_rssi;
 					sec_rssi_index = max_rssi_index;
 					tmp_max_rssi = cur_rf_rssi;
 					max_rssi_index = i;
-				}
-				else if(cur_rf_rssi == tmp_max_rssi)
-				{	// let sec and min point to the different index
+				} else if (cur_rf_rssi == tmp_max_rssi) {	/* let sec and min point to the different index */
 					tmp_sec_rssi = cur_rf_rssi;
 					sec_rssi_index = i;
-				}
-				else if((cur_rf_rssi < tmp_max_rssi) &&(cur_rf_rssi > tmp_sec_rssi))
-				{
+				} else if ((cur_rf_rssi < tmp_max_rssi) && (cur_rf_rssi > tmp_sec_rssi)) {
 					tmp_sec_rssi = cur_rf_rssi;
 					sec_rssi_index = i;
-				}
-				else if(cur_rf_rssi == tmp_sec_rssi)
-				{
-					if(tmp_sec_rssi == tmp_min_rssi)
-					{	// let sec and min point to the different index
+				} else if (cur_rf_rssi == tmp_sec_rssi) {
+					if (tmp_sec_rssi == tmp_min_rssi) {
+						/* let sec and min point to the different index */
 						tmp_sec_rssi = cur_rf_rssi;
 						sec_rssi_index = i;
+					} else {
+						/* This case we don't need to set any index */
 					}
-					else
-					{
-						// This case we don't need to set any index
-					}
-				}
-				else if((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi))
-				{
-					// This case we don't need to set any index
-				}
-				else if(cur_rf_rssi == tmp_min_rssi)
-				{
-					if(tmp_sec_rssi == tmp_min_rssi)
-					{	// let sec and min point to the different index
+				} else if ((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi)) {
+					/* This case we don't need to set any index */
+				} else if (cur_rf_rssi == tmp_min_rssi) {
+					if (tmp_sec_rssi == tmp_min_rssi) {
+						/* let sec and min point to the different index */
 						tmp_min_rssi = cur_rf_rssi;
 						min_rssi_index = i;
+					} else {
+						/* This case we don't need to set any index */
 					}
-					else
-					{
-						// This case we don't need to set any index
-					}
-				}
-				else if(cur_rf_rssi < tmp_min_rssi)
-				{
+				} else if (cur_rf_rssi < tmp_min_rssi) {
 					tmp_min_rssi = cur_rf_rssi;
 					min_rssi_index = i;
 				}
@@ -2790,83 +2541,51 @@
 	}
 
 	rf_num = 0;
-	// decide max/sec/min cck pwdb index
-	if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
-	{
-		for (i=0; i<RF90_PATH_MAX; i++)
-		{
-			if(priv->brfpath_rxenable[i])
-			{
+	/* decide max/sec/min cck pwdb index */
+	if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
+		for (i = 0; i < RF90_PATH_MAX; i++) {
+			if (priv->brfpath_rxenable[i]) {
 				rf_num++;
 				cur_cck_pwdb =  DM_RxPathSelTable.cck_pwdb_sta[i];
 
-				if(rf_num == 1)	// find first enabled rf path and the rssi values
-				{	//initialize, set all rssi index to the same one
+				if (rf_num == 1) {	/* find first enabled rf path and the rssi values */
+					/* initialize, set all rssi index to the same one */
 					cck_rx_ver2_max_index = cck_rx_ver2_min_index = cck_rx_ver2_sec_index = i;
 					tmp_cck_max_pwdb = tmp_cck_min_pwdb = tmp_cck_sec_pwdb = cur_cck_pwdb;
-				}
-				else if(rf_num == 2)
-				{	// we pick up the max index first, and let sec and min to be the same one
-					if(cur_cck_pwdb >= tmp_cck_max_pwdb)
-					{
+				} else if (rf_num == 2) {	/* we pick up the max index first, and let sec and min to be the same one */
+					if (cur_cck_pwdb >= tmp_cck_max_pwdb) {
 						tmp_cck_max_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_max_index = i;
-					}
-					else
-					{
+					} else {
 						tmp_cck_sec_pwdb = tmp_cck_min_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_sec_index = cck_rx_ver2_min_index = i;
 					}
-				}
-				else
-				{
-					if(cur_cck_pwdb > tmp_cck_max_pwdb)
-					{
+				} else {
+					if (cur_cck_pwdb > tmp_cck_max_pwdb) {
 						tmp_cck_sec_pwdb = tmp_cck_max_pwdb;
 						cck_rx_ver2_sec_index = cck_rx_ver2_max_index;
 						tmp_cck_max_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_max_index = i;
-					}
-					else if(cur_cck_pwdb == tmp_cck_max_pwdb)
-					{	// let sec and min point to the different index
+					} else if (cur_cck_pwdb == tmp_cck_max_pwdb) {
+						/* let sec and min point to the different index */
 						tmp_cck_sec_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_sec_index = i;
-					}
-					else if((cur_cck_pwdb < tmp_cck_max_pwdb) &&(cur_cck_pwdb > tmp_cck_sec_pwdb))
-					{
+					} else if ((cur_cck_pwdb < tmp_cck_max_pwdb) && (cur_cck_pwdb > tmp_cck_sec_pwdb)) {
 						tmp_cck_sec_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_sec_index = i;
-					}
-					else if(cur_cck_pwdb == tmp_cck_sec_pwdb)
-					{
-						if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
-						{	// let sec and min point to the different index
-							tmp_cck_sec_pwdb = cur_cck_pwdb;
-							cck_rx_ver2_sec_index = i;
-						}
-						else
-						{
-							// This case we don't need to set any index
-						}
-					}
-					else if((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb))
-					{
-						// This case we don't need to set any index
-					}
-					else if(cur_cck_pwdb == tmp_cck_min_pwdb)
-					{
-						if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
-						{	// let sec and min point to the different index
-							tmp_cck_min_pwdb = cur_cck_pwdb;
-							cck_rx_ver2_min_index = i;
-						}
-						else
-						{
-							// This case we don't need to set any index
-						}
-					}
-					else if(cur_cck_pwdb < tmp_cck_min_pwdb)
-					{
+					} else if (cur_cck_pwdb == tmp_cck_sec_pwdb && tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
+						/* let sec and min point to the different index */
+						tmp_cck_sec_pwdb = cur_cck_pwdb;
+						cck_rx_ver2_sec_index = i;
+						/* otherwise we don't need to set any index */
+					} else if ((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb)) {
+						/*  This case we don't need to set any index */
+					} else if (cur_cck_pwdb == tmp_cck_min_pwdb && tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
+						/*  let sec and min point to the different index */
+						tmp_cck_min_pwdb = cur_cck_pwdb;
+						cck_rx_ver2_min_index = i;
+						/* otherwise we don't need to set any index */
+					} else if (cur_cck_pwdb < tmp_cck_min_pwdb) {
 						tmp_cck_min_pwdb = cur_cck_pwdb;
 						cck_rx_ver2_min_index = i;
 					}
@@ -2876,56 +2595,48 @@
 		}
 	}
 
-
-	// Set CCK Rx path
-	// reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
+	/*
+	 * Set CCK Rx path
+	 * reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
+	 */
 	update_cck_rx_path = 0;
-	if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
-	{
+	if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
 		cck_default_Rx = cck_rx_ver2_max_index;
 		cck_optional_Rx = cck_rx_ver2_sec_index;
-		if(tmp_cck_max_pwdb != -64)
+		if (tmp_cck_max_pwdb != -64)
 			update_cck_rx_path = 1;
 	}
 
-	if(tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2)
-	{
-		if((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH)
-		{
-			//record the enabled rssi threshold
+	if (tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) {
+		if ((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH) {
+			/* record the enabled rssi threshold */
 			DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5;
-			//disable the BB Rx path, OFDM
-			rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<min_rssi_index, 0x0);	// 0xc04[3:0]
-			rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<min_rssi_index, 0x0);	// 0xd04[3:0]
+			/* disable the BB Rx path, OFDM */
+			rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<min_rssi_index, 0x0);	/* 0xc04[3:0] */
+			rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<min_rssi_index, 0x0);	/* 0xd04[3:0] */
 			disabled_rf_cnt++;
 		}
-		if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_1)
-		{
+		if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_1) {
 			cck_default_Rx = max_rssi_index;
 			cck_optional_Rx = sec_rssi_index;
-			if(tmp_max_rssi)
+			if (tmp_max_rssi)
 				update_cck_rx_path = 1;
 		}
 	}
 
-	if(update_cck_rx_path)
-	{
+	if (update_cck_rx_path) {
 		DM_RxPathSelTable.cck_Rx_path = (cck_default_Rx<<2)|(cck_optional_Rx);
 		rtl8192_setBBreg(dev, rCCK0_AFESetting, 0x0f000000, DM_RxPathSelTable.cck_Rx_path);
 	}
 
-	if(DM_RxPathSelTable.disabledRF)
-	{
-		for(i=0; i<4; i++)
-		{
-			if((DM_RxPathSelTable.disabledRF>>i) & 0x1)	//disabled rf
-			{
-				if(tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i])
-				{
-					//enable the BB Rx path
-					//DbgPrint("RF-%d is enabled. \n", 0x1<<i);
-					rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<i, 0x1);	// 0xc04[3:0]
-					rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<i, 0x1);	// 0xd04[3:0]
+	if (DM_RxPathSelTable.disabledRF) {
+		for (i = 0; i < 4; i++) {
+			if ((DM_RxPathSelTable.disabledRF>>i) & 0x1) {	/* disabled rf */
+				if (tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) {
+					/* enable the BB Rx path */
+					/*DbgPrint("RF-%d is enabled.\n", 0x1<<i);*/
+					rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<i, 0x1);	/* 0xc04[3:0] */
+					rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<i, 0x1);	/* 0xd04[3:0] */
 					DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
 					disabled_rf_cnt--;
 				}
@@ -2950,14 +2661,14 @@
  *	05/28/2008	amy		Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void	dm_check_rx_path_selection(struct net_device *dev)
+static void dm_check_rx_path_selection(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	queue_delayed_work(priv->priv_wq,&priv->rfpath_check_wq,0);
+
+	queue_delayed_work(priv->priv_wq, &priv->rfpath_check_wq, 0);
 }	/* dm_CheckRxRFPath */
 
-
-static void dm_init_fsync (struct net_device *dev)
+static void dm_init_fsync(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
@@ -2966,20 +2677,20 @@
 	priv->ieee80211->fsync_rssi_threshold = 30;
 	priv->ieee80211->bfsync_enable = false;
 	priv->ieee80211->fsync_multiple_timeinterval = 3;
-	priv->ieee80211->fsync_firstdiff_ratethreshold= 100;
-	priv->ieee80211->fsync_seconddiff_ratethreshold= 200;
+	priv->ieee80211->fsync_firstdiff_ratethreshold = 100;
+	priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
 	priv->ieee80211->fsync_state = Default_Fsync;
-	priv->framesyncMonitor = 1;	// current default 0xc38 monitor on
+	priv->framesyncMonitor = 1;	/* current default 0xc38 monitor on */
 
 	init_timer(&priv->fsync_timer);
 	priv->fsync_timer.data = (unsigned long)dev;
 	priv->fsync_timer.function = dm_fsync_timer_callback;
 }
 
-
 static void dm_deInit_fsync(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
+
 	del_timer_sync(&priv->fsync_timer);
 }
 
@@ -2987,102 +2698,84 @@
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct r8192_priv *priv = ieee80211_priv((struct net_device *)data);
-	u32 rate_index, rate_count = 0, rate_count_diff=0;
+	u32 rate_index, rate_count = 0, rate_count_diff = 0;
 	bool		bSwitchFromCountDiff = false;
 	bool		bDoubleTimeInterval = false;
 
-	if(priv->ieee80211->state == IEEE80211_LINKED &&
+	if (priv->ieee80211->state == IEEE80211_LINKED &&
 		priv->ieee80211->bfsync_enable &&
-		(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
-	{
-		 // Count rate 54, MCS [7], [12, 13, 14, 15]
+		(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) {
+		/* Count rate 54, MCS [7], [12, 13, 14, 15] */
 		u32 rate_bitmap;
-		for(rate_index = 0; rate_index <= 27; rate_index++)
-		{
+
+		for (rate_index = 0; rate_index <= 27; rate_index++) {
 			rate_bitmap  = 1 << rate_index;
-			if(priv->ieee80211->fsync_rate_bitmap &  rate_bitmap)
-				rate_count+= priv->stats.received_rate_histogram[1][rate_index];
+			if (priv->ieee80211->fsync_rate_bitmap &  rate_bitmap)
+				rate_count += priv->stats.received_rate_histogram[1][rate_index];
 		}
 
-		if(rate_count < priv->rate_record)
+		if (rate_count < priv->rate_record)
 			rate_count_diff = 0xffffffff - rate_count + priv->rate_record;
 		else
 			rate_count_diff = rate_count - priv->rate_record;
-		if(rate_count_diff < priv->rateCountDiffRecord)
-		{
-
+		if (rate_count_diff < priv->rateCountDiffRecord) {
 			u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
-			// Continue count
-			if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
+			/* Continue count */
+			if (DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
 				priv->ContinueDiffCount++;
 			else
 				priv->ContinueDiffCount = 0;
 
-			// Continue count over
-			if(priv->ContinueDiffCount >=2)
-			{
+			/* Continue count over */
+			if (priv->ContinueDiffCount >= 2) {
 				bSwitchFromCountDiff = true;
 				priv->ContinueDiffCount = 0;
 			}
-		}
-		else
-		{
-			// Stop the continued count
+		} else {
+			/* Stop the continued count */
 			priv->ContinueDiffCount = 0;
 		}
 
-		//If Count diff <= FsyncRateCountThreshold
-		if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
-		{
+		/* If Count diff <= FsyncRateCountThreshold */
+		if (rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold) {
 			bSwitchFromCountDiff = true;
 			priv->ContinueDiffCount = 0;
 		}
 		priv->rate_record = rate_count;
 		priv->rateCountDiffRecord = rate_count_diff;
-		RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
-		// if we never receive those mcs rate and rssi > 30 % then switch fsyn
-		if(priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff)
-		{
+		RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff, priv->bswitch_fsync);
+		/* if we never receive those mcs rate and rssi > 30 % then switch fsyn */
+		if (priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff) {
 			bDoubleTimeInterval = true;
 			priv->bswitch_fsync = !priv->bswitch_fsync;
-			if(priv->bswitch_fsync)
-			{
+			if (priv->bswitch_fsync) {
 				write_nic_byte(dev, 0xC36, 0x1c);
 				write_nic_byte(dev, 0xC3e, 0x90);
-			}
-			else
-			{
+			} else {
 				write_nic_byte(dev, 0xC36, 0x5c);
 				write_nic_byte(dev, 0xC3e, 0x96);
 			}
-		}
-		else if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold)
-		{
-			if(priv->bswitch_fsync)
-			{
+		} else if (priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold) {
+			if (priv->bswitch_fsync) {
 				priv->bswitch_fsync  = false;
 				write_nic_byte(dev, 0xC36, 0x5c);
 				write_nic_byte(dev, 0xC3e, 0x96);
 			}
 		}
-		if(bDoubleTimeInterval){
-			if(timer_pending(&priv->fsync_timer))
+		if (bDoubleTimeInterval) {
+			if (timer_pending(&priv->fsync_timer))
 				del_timer_sync(&priv->fsync_timer);
 			priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval);
 			add_timer(&priv->fsync_timer);
-		}
-		else{
-			if(timer_pending(&priv->fsync_timer))
+		} else {
+			if (timer_pending(&priv->fsync_timer))
 				del_timer_sync(&priv->fsync_timer);
 			priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
 			add_timer(&priv->fsync_timer);
 		}
-	}
-	else
-	{
-		// Let Register return to default value;
-		if(priv->bswitch_fsync)
-		{
+	} else {
+		/* Let Register return to default value; */
+		if (priv->bswitch_fsync) {
 			priv->bswitch_fsync  = false;
 			write_nic_byte(dev, 0xC36, 0x5c);
 			write_nic_byte(dev, 0xC3e, 0x96);
@@ -3091,7 +2784,7 @@
 		write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
 	}
 	RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
-	RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
+	RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff, priv->bswitch_fsync);
 }
 
 static void dm_StartHWFsync(struct net_device *dev)
@@ -3108,9 +2801,8 @@
 	RT_TRACE(COMP_HALDM, "%s\n", __func__);
 	del_timer_sync(&(priv->fsync_timer));
 
-	// Let Register return to default value;
-	if(priv->bswitch_fsync)
-	{
+	/* Let Register return to default value; */
+	if (priv->bswitch_fsync) {
 		priv->bswitch_fsync  = false;
 
 		write_nic_byte(dev, 0xC36, 0x5c);
@@ -3130,30 +2822,26 @@
 	u32			rateBitmap;
 
 	RT_TRACE(COMP_HALDM, "%s\n", __func__);
-	// Initial rate record to zero, start to record.
+	/* Initial rate record to zero, start to record. */
 	priv->rate_record = 0;
-	// Initialize continue diff count to zero, start to record.
+	/* Initialize continue diff count to zero, start to record. */
 	priv->ContinueDiffCount = 0;
 	priv->rateCountDiffRecord = 0;
 	priv->bswitch_fsync  = false;
 
-	if(priv->ieee80211->mode == WIRELESS_MODE_N_24G)
-	{
-		priv->ieee80211->fsync_firstdiff_ratethreshold= 600;
+	if (priv->ieee80211->mode == WIRELESS_MODE_N_24G) {
+		priv->ieee80211->fsync_firstdiff_ratethreshold = 600;
 		priv->ieee80211->fsync_seconddiff_ratethreshold = 0xffff;
-	}
-	else
-	{
-		priv->ieee80211->fsync_firstdiff_ratethreshold= 200;
+	} else {
+		priv->ieee80211->fsync_firstdiff_ratethreshold = 200;
 		priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
 	}
-	for(rateIndex = 0; rateIndex <= 27; rateIndex++)
-	{
-		rateBitmap  = 1 << rateIndex;
-		if(priv->ieee80211->fsync_rate_bitmap &  rateBitmap)
+	for (rateIndex = 0; rateIndex <= 27; rateIndex++) {
+		rateBitmap = 1 << rateIndex;
+		if (priv->ieee80211->fsync_rate_bitmap &  rateBitmap)
 			priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex];
 	}
-	if(timer_pending(&priv->fsync_timer))
+	if (timer_pending(&priv->fsync_timer))
 		del_timer_sync(&priv->fsync_timer);
 	priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
 	add_timer(&priv->fsync_timer);
@@ -3173,139 +2861,112 @@
 void dm_check_fsync(struct net_device *dev)
 {
 #define	RegC38_Default				0
-#define	RegC38_NonFsync_Other_AP	1
-#define	RegC38_Fsync_AP_BCM		2
+#define	RegC38_NonFsync_Other_AP		1
+#define	RegC38_Fsync_AP_BCM			2
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	//u32			framesyncC34;
-	static u8		reg_c38_State=RegC38_Default;
+	/*u32			framesyncC34;*/
+	static u8		reg_c38_State = RegC38_Default;
 	static u32	reset_cnt;
 
 	RT_TRACE(COMP_HALDM, "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", priv->ieee80211->fsync_rssi_threshold, priv->ieee80211->fsync_time_interval, priv->ieee80211->fsync_multiple_timeinterval);
 	RT_TRACE(COMP_HALDM, "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", priv->ieee80211->fsync_rate_bitmap, priv->ieee80211->fsync_firstdiff_ratethreshold, priv->ieee80211->fsync_seconddiff_ratethreshold);
 
-	if(priv->ieee80211->state == IEEE80211_LINKED &&
-		(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
-	{
-		if(priv->ieee80211->bfsync_enable == 0)
-		{
-			switch (priv->ieee80211->fsync_state)
-			{
-				case Default_Fsync:
-					dm_StartHWFsync(dev);
-					priv->ieee80211->fsync_state = HW_Fsync;
-					break;
-				case SW_Fsync:
-					dm_EndSWFsync(dev);
-					dm_StartHWFsync(dev);
-					priv->ieee80211->fsync_state = HW_Fsync;
-					break;
-				case HW_Fsync:
-				default:
-					break;
+	if (priv->ieee80211->state == IEEE80211_LINKED &&
+		(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) {
+		if (priv->ieee80211->bfsync_enable == 0) {
+			switch (priv->ieee80211->fsync_state) {
+			case Default_Fsync:
+				dm_StartHWFsync(dev);
+				priv->ieee80211->fsync_state = HW_Fsync;
+				break;
+			case SW_Fsync:
+				dm_EndSWFsync(dev);
+				dm_StartHWFsync(dev);
+				priv->ieee80211->fsync_state = HW_Fsync;
+				break;
+			case HW_Fsync:
+			default:
+				break;
+			}
+		} else {
+			switch (priv->ieee80211->fsync_state) {
+			case Default_Fsync:
+				dm_StartSWFsync(dev);
+				priv->ieee80211->fsync_state = SW_Fsync;
+				break;
+			case HW_Fsync:
+				dm_EndHWFsync(dev);
+				dm_StartSWFsync(dev);
+				priv->ieee80211->fsync_state = SW_Fsync;
+				break;
+			case SW_Fsync:
+			default:
+				break;
 			}
 		}
-		else
-		{
-			switch (priv->ieee80211->fsync_state)
-			{
-				case Default_Fsync:
-					dm_StartSWFsync(dev);
-					priv->ieee80211->fsync_state = SW_Fsync;
-					break;
-				case HW_Fsync:
-					dm_EndHWFsync(dev);
-					dm_StartSWFsync(dev);
-					priv->ieee80211->fsync_state = SW_Fsync;
-					break;
-				case SW_Fsync:
-				default:
-					break;
-
-			}
-		}
-		if(priv->framesyncMonitor)
-		{
-			if(reg_c38_State != RegC38_Fsync_AP_BCM)
-			{	//For broadcom AP we write different default value
+		if (priv->framesyncMonitor) {
+			if (reg_c38_State != RegC38_Fsync_AP_BCM) {
+				/* For broadcom AP we write different default value */
 				write_nic_byte(dev, rOFDM0_RxDetector3, 0x95);
 
 				reg_c38_State = RegC38_Fsync_AP_BCM;
 			}
 		}
-	}
-	else
-	{
-		switch (priv->ieee80211->fsync_state)
-		{
-			case HW_Fsync:
-				dm_EndHWFsync(dev);
-				priv->ieee80211->fsync_state = Default_Fsync;
-				break;
-			case SW_Fsync:
-				dm_EndSWFsync(dev);
-				priv->ieee80211->fsync_state = Default_Fsync;
-				break;
-			case Default_Fsync:
-			default:
-				break;
+	} else {
+		switch (priv->ieee80211->fsync_state) {
+		case HW_Fsync:
+			dm_EndHWFsync(dev);
+			priv->ieee80211->fsync_state = Default_Fsync;
+			break;
+		case SW_Fsync:
+			dm_EndSWFsync(dev);
+			priv->ieee80211->fsync_state = Default_Fsync;
+			break;
+		case Default_Fsync:
+		default:
+			break;
 		}
 
-		if(priv->framesyncMonitor)
-		{
-			if(priv->ieee80211->state == IEEE80211_LINKED)
-			{
-				if(priv->undecorated_smoothed_pwdb <= RegC38_TH)
-				{
-					if(reg_c38_State != RegC38_NonFsync_Other_AP)
-					{
+		if (priv->framesyncMonitor) {
+			if (priv->ieee80211->state == IEEE80211_LINKED) {
+				if (priv->undecorated_smoothed_pwdb <= RegC38_TH) {
+					if (reg_c38_State != RegC38_NonFsync_Other_AP) {
 						write_nic_byte(dev, rOFDM0_RxDetector3, 0x90);
 
 						reg_c38_State = RegC38_NonFsync_Other_AP;
 					}
-				}
-				else if(priv->undecorated_smoothed_pwdb >= (RegC38_TH+5))
-				{
-					if(reg_c38_State)
-					{
+				} else if (priv->undecorated_smoothed_pwdb >= (RegC38_TH+5)) {
+					if (reg_c38_State) {
 						write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
 						reg_c38_State = RegC38_Default;
-						//DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x \n", pHalData->framesync);
+						/*DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x\n", pHalData->framesync);*/
 					}
 				}
-			}
-			else
-			{
-				if(reg_c38_State)
-				{
+			} else {
+				if (reg_c38_State) {
 					write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
 					reg_c38_State = RegC38_Default;
-					//DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x \n", pHalData->framesync);
+					/*DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x\n", pHalData->framesync);*/
 				}
 			}
 		}
 	}
-	if(priv->framesyncMonitor)
-	{
-		if(priv->reset_count != reset_cnt)
-		{	//After silent reset, the reg_c38_State will be returned to default value
+	if (priv->framesyncMonitor) {
+		if (priv->reset_count != reset_cnt) { /* After silent reset, the reg_c38_State will be returned to default value */
 			write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
 			reg_c38_State = RegC38_Default;
 			reset_cnt = priv->reset_count;
-			//DbgPrint("reg_c38_State = 0 for silent reset. \n");
+			/*DbgPrint("reg_c38_State = 0 for silent reset.\n");*/
 		}
-	}
-	else
-	{
-		if(reg_c38_State)
-		{
+	} else {
+		if (reg_c38_State) {
 			write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
 			reg_c38_State = RegC38_Default;
-			//DbgPrint("framesync no monitor, write 0xc38 = 0x%x \n", pHalData->framesync);
+			/*DbgPrint("framesync no monitor, write 0xc38 = 0x%x\n", pHalData->framesync);*/
 		}
 	}
 }
 
-
 /*-----------------------------------------------------------------------------
  * Function:	dm_shadow_init()
  *
@@ -3328,10 +2989,9 @@
 	u16	offset;
 
 	for (page = 0; page < 5; page++)
-		for (offset = 0; offset < 256; offset++)
-		{
+		for (offset = 0; offset < 256; offset++) {
 			read_nic_byte(dev, offset+page*256, &dm_shadow[page][offset]);
-			//DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]);
+			/*DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]);*/
 		}
 
 	for (page = 8; page < 11; page++)
@@ -3366,8 +3026,8 @@
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	//Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
-	priv->ieee80211->bdynamic_txpower_enable = true;    //Default to enable Tx Power Control
+	/* Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. */
+	priv->ieee80211->bdynamic_txpower_enable = true;    /* Default to enable Tx Power Control */
 	priv->bLastDTPFlag_High = false;
 	priv->bLastDTPFlag_Low = false;
 	priv->bDynamicTxHighPower = false;
@@ -3377,91 +3037,77 @@
 static void dm_dynamic_txpower(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	unsigned int txhipower_threshhold=0;
-	unsigned int txlowpower_threshold=0;
-	if(priv->ieee80211->bdynamic_txpower_enable != true)
-	{
+	unsigned int txhipower_threshhold = 0;
+	unsigned int txlowpower_threshold = 0;
+
+	if (priv->ieee80211->bdynamic_txpower_enable != true) {
 		priv->bDynamicTxHighPower = false;
 		priv->bDynamicTxLowPower = false;
 		return;
 	}
-	//printk("priv->ieee80211->current_network.unknown_cap_exist is %d ,priv->ieee80211->current_network.broadcom_cap_exist is %d\n",priv->ieee80211->current_network.unknown_cap_exist,priv->ieee80211->current_network.broadcom_cap_exist);
-	if((priv->ieee80211->current_network.atheros_cap_exist) && (priv->ieee80211->mode == IEEE_G)){
+	/*printk("priv->ieee80211->current_network.unknown_cap_exist is %d , priv->ieee80211->current_network.broadcom_cap_exist is %d\n", priv->ieee80211->current_network.unknown_cap_exist, priv->ieee80211->current_network.broadcom_cap_exist);*/
+	if ((priv->ieee80211->current_network.atheros_cap_exist) && (priv->ieee80211->mode == IEEE_G)) {
 		txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH;
 		txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW;
-	}
-	else
-	{
+	} else {
 		txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH;
 		txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW;
 	}
 
-//	printk("=======>%s(): txhipower_threshhold is %d,txlowpower_threshold is %d\n",__func__,txhipower_threshhold,txlowpower_threshold);
-	RT_TRACE(COMP_TXAGC,"priv->undecorated_smoothed_pwdb = %ld \n" , priv->undecorated_smoothed_pwdb);
+	/*printk("=======>%s(): txhipower_threshhold is %d, txlowpower_threshold is %d\n", __func__, txhipower_threshhold, txlowpower_threshold);*/
+	RT_TRACE(COMP_TXAGC, "priv->undecorated_smoothed_pwdb = %ld\n", priv->undecorated_smoothed_pwdb);
 
-	if(priv->ieee80211->state == IEEE80211_LINKED)
-	{
-		if(priv->undecorated_smoothed_pwdb >= txhipower_threshhold)
-		{
+	if (priv->ieee80211->state == IEEE80211_LINKED) {
+		if (priv->undecorated_smoothed_pwdb >= txhipower_threshhold) {
 			priv->bDynamicTxHighPower = true;
 			priv->bDynamicTxLowPower = false;
-		}
-		else
-		{
-			// high power state check
-			if(priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true)
-			{
+		} else {
+			/* high power state check */
+			if (priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true)
 				priv->bDynamicTxHighPower = false;
-			}
-			// low power state check
-			if(priv->undecorated_smoothed_pwdb < 35)
-			{
+
+			/* low power state check */
+			if (priv->undecorated_smoothed_pwdb < 35)
 				priv->bDynamicTxLowPower = true;
-			}
-			else if(priv->undecorated_smoothed_pwdb >= 40)
-			{
+			else if (priv->undecorated_smoothed_pwdb >= 40)
 				priv->bDynamicTxLowPower = false;
-			}
 		}
-	}
-	else
-	{
-		//pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;
+	} else {
+		/*pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;*/
 		priv->bDynamicTxHighPower = false;
 		priv->bDynamicTxLowPower = false;
 	}
 
-	if((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) ||
-		(priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low))
-	{
-		RT_TRACE(COMP_TXAGC,"SetTxPowerLevel8190()  channel = %d \n" , priv->ieee80211->current_network.channel);
+	if ((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) ||
+		(priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low)) {
+		RT_TRACE(COMP_TXAGC, "SetTxPowerLevel8190()  channel = %d\n", priv->ieee80211->current_network.channel);
 
 #if  defined(RTL8190P) || defined(RTL8192E)
-		SetTxPowerLevel8190(Adapter,pHalData->CurrentChannel);
+		SetTxPowerLevel8190(Adapter, pHalData->CurrentChannel);
 #endif
 
-		rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel);
-		//pHalData->bStartTxCtrlByTPCNFR = FALSE;    //Clear th flag of Set TX Power from Sitesurvey
+		rtl8192_phy_setTxPower(dev, priv->ieee80211->current_network.channel);
+		/*pHalData->bStartTxCtrlByTPCNFR = FALSE;    Clear th flag of Set TX Power from Sitesurvey*/
 	}
 	priv->bLastDTPFlag_High = priv->bDynamicTxHighPower;
 	priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower;
 
 }	/* dm_dynamic_txpower */
 
-//added by vivi, for read tx rate and retrycount
+/* added by vivi, for read tx rate and retrycount */
 static void dm_check_txrateandretrycount(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = priv->ieee80211;
-	//for 11n tx rate
-//	priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg);
+	/* for 11n tx rate */
+	/*priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg);*/
 	read_nic_byte(dev, Current_Tx_Rate_Reg, &ieee->softmac_stats.CurrentShowTxate);
-	//printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate);
-	//for initial tx rate
-//	priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg);
+	/*printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate);*/
+	/* for initial tx rate */
+	/*priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg);*/
 	read_nic_byte(dev, Initial_Tx_Rate_Reg, &ieee->softmac_stats.last_packet_rate);
-	//for tx tx retry count
-//	priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg);
+	/* for tx tx retry count */
+	/*priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg);*/
 	read_nic_dword(dev, Tx_Retry_Count_Reg, &ieee->softmac_stats.txretrycount);
 }
 
@@ -3469,11 +3115,12 @@
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
-	// If we test chariot, we should stop the TX command ?
-	// Because 92E will always silent reset when we send tx command. We use register
-	// 0x1e0(byte) to notify driver.
+	/*
+	 * If we test chariot, we should stop the TX command ?
+	 * Because 92E will always silent reset when we send tx command. We use register
+	 * 0x1e0(byte) to notify driver.
+	 */
 	write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
-	return;
 }
 
 /*---------------------------Define function prototype------------------------*/
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index 3d0a98b..e62543d 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -129,8 +129,8 @@
 	struct _adapter *padapter;
 	u32 nr_endpoint;
 	u8   ishighspeed;
-	uint(*inirp_init)(struct _adapter *adapter);
-	uint(*inirp_deinit)(struct _adapter *adapter);
+	uint (*inirp_init)(struct _adapter *adapter);
+	uint (*inirp_deinit)(struct _adapter *adapter);
 	struct usb_device *pusbdev;
 };
 
@@ -166,7 +166,7 @@
 	 pid_t evtThread;
 	struct task_struct *xmitThread;
 	pid_t recvThread;
-	uint(*dvobj_init)(struct _adapter *adapter);
+	uint (*dvobj_init)(struct _adapter *adapter);
 	void (*dvobj_deinit)(struct _adapter *adapter);
 	struct net_device *pnetdev;
 	int bup;
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 5153ad9..36348d9 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -71,7 +71,7 @@
 
 static inline void _set_timer(struct timer_list *ptimer, u32 delay_time)
 {
-	mod_timer(ptimer, (jiffies+(delay_time*HZ/1000)));
+	mod_timer(ptimer, (jiffies+msecs_to_jiffies(delay_time)));
 }
 
 static inline void _cancel_timer(struct timer_list *ptimer, u8 *bcancelled)
@@ -101,12 +101,9 @@
 {
 	u32 delta;
 
-	delta = (ms * HZ) / 1000;/*(ms)*/
-	if (delta == 0)
-		delta = 1;/* 1 ms */
+	delta = msecs_to_jiffies(ms);/*(ms)*/
 	set_current_state(TASK_INTERRUPTIBLE);
-	if (schedule_timeout(delta) != 0)
-		return;
+	schedule_timeout(delta);
 }
 
 static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer)
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 0631f36..409c8c8 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -137,20 +137,6 @@
 	 precvpriv->rx_drop++;
 }
 
-void r8712_os_read_port(struct _adapter *padapter, struct recv_buf *precvbuf)
-{
-	struct recv_priv *precvpriv = &padapter->recvpriv;
-
-	precvbuf->ref_cnt--;
-	/*free skb in recv_buf*/
-	dev_kfree_skb_any(precvbuf->pskb);
-	precvbuf->pskb = NULL;
-	precvbuf->reuse = false;
-	if (!precvbuf->irp_pending)
-		r8712_read_port(padapter, precvpriv->ff_hwaddr, 0,
-			 (unsigned char *)precvbuf);
-}
-
 static void _r8712_reordering_ctrl_timeout_handler (void *FunctionContext)
 {
 	struct recv_reorder_ctrl *preorder_ctrl =
diff --git a/drivers/staging/rtl8712/recv_osdep.h b/drivers/staging/rtl8712/recv_osdep.h
index f4384ef..1f4986e 100644
--- a/drivers/staging/rtl8712/recv_osdep.h
+++ b/drivers/staging/rtl8712/recv_osdep.h
@@ -46,7 +46,6 @@
 				    struct recv_buf *precvbuf);
 int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
 				   struct recv_buf *precvbuf);
-void r8712_os_read_port(struct _adapter *padapter, struct recv_buf *precvbuf);
 void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl);
 
 #endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 039ab3e..67e9e91 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -109,16 +109,16 @@
 	GEN_CMD_CODE(_DisconnectCtrlEx), /*61*/
 
 	/* To do, modify these h2c cmd, add or delete */
-	GEN_CMD_CODE(_GetH2cLbk) ,
+	GEN_CMD_CODE(_GetH2cLbk),
 
 	/* WPS extra IE */
-	GEN_CMD_CODE(_SetProbeReqExtraIE) ,
-	GEN_CMD_CODE(_SetAssocReqExtraIE) ,
-	GEN_CMD_CODE(_SetProbeRspExtraIE) ,
-	GEN_CMD_CODE(_SetAssocRspExtraIE) ,
+	GEN_CMD_CODE(_SetProbeReqExtraIE),
+	GEN_CMD_CODE(_SetAssocReqExtraIE),
+	GEN_CMD_CODE(_SetProbeRspExtraIE),
+	GEN_CMD_CODE(_SetAssocRspExtraIE),
 
 	/* the following is driver will do */
-	GEN_CMD_CODE(_GetCurDataRate) ,
+	GEN_CMD_CODE(_GetCurDataRate),
 
 	GEN_CMD_CODE(_GetTxRetrycnt),  /* to record times that Tx retry to
 					* transmit packet after association
diff --git a/drivers/staging/rtl8712/rtl8712_event.h b/drivers/staging/rtl8712/rtl8712_event.h
index 3d7f79e..29a4c23 100644
--- a/drivers/staging/rtl8712/rtl8712_event.h
+++ b/drivers/staging/rtl8712/rtl8712_event.h
@@ -27,7 +27,7 @@
 #define _RTL8712_EVENT_H_
 
 void r8712_event_handle(struct _adapter *padapter, uint *peventbuf);
-void r8712_got_addbareq_event_callback(struct _adapter *adapter , u8 *pbuf);
+void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf);
 
 enum rtl8712_c2h_event {
 	GEN_EVT_CODE(_Read_MACREG) = 0,		/*0*/
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index 73b7d86..9bb364f 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -196,7 +196,7 @@
 	if (p && ht_ielen > 0) {
 		ht_cap = true;
 		pht_capie = (struct ieee80211_ht_cap *)(p + 2);
-		memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+		memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
 	}
 	/* Add the protocol name */
 	iwe.cmd = SIOCGIWNAME;
@@ -1436,7 +1436,7 @@
 		if (p && ht_ielen > 0) {
 			ht_cap = true;
 			pht_capie = (struct ieee80211_ht_cap *)(p + 2);
-			memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+			memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
 			bw_40MHz = (pht_capie->cap_info &
 				    IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
 			short_GI = (pht_capie->cap_info &
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index b7462e8..977a833 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -93,7 +93,7 @@
 		return NULL;
 	spin_lock_irqsave(&free_queue->lock, irqL);
 	plist = free_queue->queue.next;
-	pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+	pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
 	list_del_init(&pnetwork->list);
 	pnetwork->last_scanned = jiffies;
 	pmlmepriv->num_of_scanned++;
@@ -499,7 +499,7 @@
 }
 
 /* TODO: Perry : For Power Management */
-void r8712_atimdone_event_callback(struct _adapter *adapter , u8 *pbuf)
+void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf)
 {
 }
 
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
index a16f15e..0b54612 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
@@ -575,26 +575,6 @@
 	return RNDIS_STATUS_SUCCESS;
 }
 
-uint oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-	struct ndis_802_11_ssid *pssid;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	*poid_par_priv->bytes_needed = (u32)sizeof(struct ndis_802_11_ssid);
-	*poid_par_priv->bytes_rw = 0;
-	if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	pssid = (struct ndis_802_11_ssid *)poid_par_priv->information_buf;
-	if (mp_start_joinbss(Adapter, pssid) == _FAIL)
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	*poid_par_priv->bytes_rw = sizeof(struct ndis_802_11_ssid);
-	return status;
-}
-
 uint oid_rt_pro_read_register_hdl(struct oid_par_priv
 					 *poid_par_priv)
 {
@@ -696,172 +676,6 @@
 	return status;
 }
 
-uint oid_rt_pro_burst_read_register_hdl(struct oid_par_priv
-					       *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct burst_rw_reg *pBstRwReg;
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	pBstRwReg = (struct burst_rw_reg *)poid_par_priv->information_buf;
-	r8712_read_mem(Adapter, pBstRwReg->offset, (u32)pBstRwReg->len,
-		 pBstRwReg->Data);
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_burst_write_register_hdl(struct oid_par_priv
-						*poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct burst_rw_reg *pBstRwReg;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	pBstRwReg = (struct burst_rw_reg *)poid_par_priv->information_buf;
-	r8712_write_mem(Adapter, pBstRwReg->offset, (u32)pBstRwReg->len,
-		  pBstRwReg->Data);
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv)
-{
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct eeprom_rw_param *pEEPROM;
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	pEEPROM = (struct eeprom_rw_param *)poid_par_priv->information_buf;
-	pEEPROM->value = r8712_eeprom_read16(Adapter,
-					     (u16)(pEEPROM->offset >> 1));
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct eeprom_rw_param *pEEPROM;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	pEEPROM = (struct eeprom_rw_param *)poid_par_priv->information_buf;
-	r8712_eeprom_write16(Adapter, (u16)(pEEPROM->offset >> 1),
-			     pEEPROM->value);
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct mp_wiparam *pwi_param;
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < sizeof(struct mp_wiparam))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	if (Adapter->mppriv.workparam.bcompleted == false)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	pwi_param = (struct mp_wiparam *)poid_par_priv->information_buf;
-	memcpy(pwi_param, &Adapter->mppriv.workparam,
-		sizeof(struct mp_wiparam));
-	Adapter->mppriv.act_in_progress = false;
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < sizeof(uint) * 2)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	if (*(uint *)poid_par_priv->information_buf == 1)
-		Adapter->mppriv.rx_pktloss = 0;
-	*((uint *)poid_par_priv->information_buf+1) =
-					 Adapter->mppriv.rx_pktloss;
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
-{
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
-{
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (r8712_setrfintfs_cmd(Adapter, *(unsigned char *)
-	    poid_par_priv->information_buf) == _FAIL)
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	return status;
-}
-
-uint oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	memcpy(poid_par_priv->information_buf,
-		(unsigned char *)&Adapter->mppriv.rxstat,
-		sizeof(struct recv_stat));
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv
-					     *poid_par_priv)
-{
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv
-					    *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (r8712_setdatarate_cmd(Adapter,
-	    poid_par_priv->information_buf) != _SUCCESS)
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	return status;
-}
-
 uint oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
 {
 	struct _adapter *Adapter = (struct _adapter *)
@@ -890,251 +704,6 @@
 	return RNDIS_STATUS_SUCCESS;
 }
 
-uint oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv
-					      *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < sizeof(u8))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	if (!r8712_setptm_cmd(Adapter, *((u8 *)poid_par_priv->information_buf)))
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	return status;
-}
-
-uint oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
-	uint status = RNDIS_STATUS_SUCCESS;
-	u32 ratevalue;
-	u8 datarates[NumRates];
-	int i;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	ratevalue = *((u32 *)poid_par_priv->information_buf);
-	for (i = 0; i < NumRates; i++) {
-		if (ratevalue == mpdatarate[i])
-			datarates[i] = mpdatarate[i];
-		else
-			datarates[i] = 0xff;
-	}
-	if (r8712_setbasicrate_cmd(Adapter, datarates) != _SUCCESS)
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	return status;
-}
-
-uint oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < 8)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	*poid_par_priv->bytes_rw = 8;
-	memcpy(poid_par_priv->information_buf,
-		&(Adapter->pwrctrlpriv.pwr_mode), 8);
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint pwr_mode, smart_ps;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	*poid_par_priv->bytes_rw = 0;
-	*poid_par_priv->bytes_needed = 8;
-	if (poid_par_priv->information_buf_len < 8)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	pwr_mode = *(uint *)(poid_par_priv->information_buf);
-	smart_ps = *(uint *)((addr_t)poid_par_priv->information_buf + 4);
-	if (pwr_mode != Adapter->pwrctrlpriv.pwr_mode || smart_ps !=
-			Adapter->pwrctrlpriv.smart_ps)
-		r8712_set_ps_mode(Adapter, pwr_mode, smart_ps);
-	*poid_par_priv->bytes_rw = 8;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv
-					      *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-	struct setratable_parm *prate_table;
-	u8 res;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	*poid_par_priv->bytes_needed  = sizeof(struct setratable_parm);
-	if (poid_par_priv->information_buf_len <
-	    sizeof(struct setratable_parm))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	prate_table = (struct setratable_parm *)poid_par_priv->information_buf;
-	res = r8712_setrttbl_cmd(Adapter, prate_table);
-	if (res == _FAIL)
-		status = RNDIS_STATUS_FAILURE;
-	return status;
-}
-
-uint oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv
-					      *poid_par_priv)
-{
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv
-					   *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	struct security_priv *psecuritypriv = &Adapter->securitypriv;
-	enum ENCRY_CTRL_STATE encry_mode = 0;
-
-	*poid_par_priv->bytes_needed = sizeof(u8);
-	if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
-		return RNDIS_STATUS_INVALID_LENGTH;
-
-	if (poid_par_priv->type_of_oid == SET_OID) {
-		encry_mode = *((u8 *)poid_par_priv->information_buf);
-		switch (encry_mode) {
-		case HW_CONTROL:
-			psecuritypriv->sw_decrypt = false;
-			psecuritypriv->sw_encrypt = false;
-			break;
-		case SW_CONTROL:
-			psecuritypriv->sw_decrypt = true;
-			psecuritypriv->sw_encrypt = true;
-			break;
-		case HW_ENCRY_SW_DECRY:
-			psecuritypriv->sw_decrypt = true;
-			psecuritypriv->sw_encrypt = false;
-			break;
-		case SW_ENCRY_HW_DECRY:
-			psecuritypriv->sw_decrypt = false;
-			psecuritypriv->sw_encrypt = true;
-			break;
-		}
-	} else {
-		if ((psecuritypriv->sw_encrypt == false) &&
-		    (psecuritypriv->sw_decrypt == false))
-			encry_mode = HW_CONTROL;
-		else if ((psecuritypriv->sw_encrypt == false) &&
-			 (psecuritypriv->sw_decrypt == true))
-			encry_mode = HW_ENCRY_SW_DECRY;
-		else if ((psecuritypriv->sw_encrypt == true) &&
-			 (psecuritypriv->sw_decrypt == false))
-			encry_mode = SW_ENCRY_HW_DECRY;
-		else if ((psecuritypriv->sw_encrypt == true) &&
-			 (psecuritypriv->sw_decrypt == true))
-			encry_mode = SW_CONTROL;
-		*(u8 *)poid_par_priv->information_buf =  encry_mode;
-		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	}
-	return RNDIS_STATUS_SUCCESS;
-}
-/*----------------------------------------------------------------------*/
-uint oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	uint status = RNDIS_STATUS_SUCCESS;
-
-	struct sta_info	*psta = NULL;
-	u8	*macaddr;
-
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-
-	*poid_par_priv->bytes_needed = ETH_ALEN;
-	if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	macaddr = (u8 *) poid_par_priv->information_buf;
-	psta = r8712_get_stainfo(&Adapter->stapriv, macaddr);
-	if (psta == NULL) { /* the sta in sta_info_queue => do nothing*/
-		psta = r8712_alloc_stainfo(&Adapter->stapriv, macaddr);
-		if (psta == NULL)
-			status = RNDIS_STATUS_FAILURE;
-	}
-	return status;
-}
-/*-------------------------------------------------------------------------*/
-uint oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	unsigned long			irqL;
-
-	struct sta_info		*psta = NULL;
-	u8			*macaddr;
-
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-
-	*poid_par_priv->bytes_needed = ETH_ALEN;
-	if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
-		return RNDIS_STATUS_INVALID_LENGTH;
-
-	macaddr = (u8 *)poid_par_priv->information_buf;
-
-	psta = r8712_get_stainfo(&Adapter->stapriv, macaddr);
-	if (psta != NULL) {
-		spin_lock_irqsave(&(Adapter->stapriv.sta_hash_lock), irqL);
-		r8712_free_stainfo(Adapter, psta);
-		spin_unlock_irqrestore(&(Adapter->stapriv.sta_hash_lock), irqL);
-	}
-
-	return RNDIS_STATUS_SUCCESS;
-}
-/*--------------------------------------------------------------------------*/
-static u32 mp_query_drv_var(struct _adapter *padapter, u8 offset, u32 var)
-{
-	return var;
-}
-
-uint oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-
-	struct DR_VARIABLE_STRUCT *pdrv_var;
-
-	if (poid_par_priv->type_of_oid != QUERY_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	*poid_par_priv->bytes_needed = sizeof(struct DR_VARIABLE_STRUCT);
-	if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
-		return RNDIS_STATUS_INVALID_LENGTH;
-	pdrv_var = (struct DR_VARIABLE_STRUCT *)poid_par_priv->information_buf;
-	pdrv_var->variable = mp_query_drv_var(Adapter, pdrv_var->offset,
-					      pdrv_var->variable);
-	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
-	return RNDIS_STATUS_SUCCESS;
-}
-
-/*--------------------------------------------------------------------------*/
-uint oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
-{
-	return RNDIS_STATUS_SUCCESS;
-}
-/*------------------------------------------------------------------------*/
 uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv)
 {
 	struct _adapter *Adapter = (struct _adapter *)
@@ -1192,38 +761,6 @@
 	return status;
 }
 /*----------------------------------------------------------------------*/
-uint oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-	struct PGPKT_STRUCT	*ppgpkt;
-
-	*poid_par_priv->bytes_rw = 0;
-	if (poid_par_priv->information_buf_len < sizeof(struct PGPKT_STRUCT))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	ppgpkt = (struct PGPKT_STRUCT *)poid_par_priv->information_buf;
-	if (poid_par_priv->type_of_oid == QUERY_OID) {
-		if (r8712_efuse_pg_packet_read(Adapter, ppgpkt->offset,
-		    ppgpkt->data) == true)
-			*poid_par_priv->bytes_rw =
-				 poid_par_priv->information_buf_len;
-		else
-			status = RNDIS_STATUS_FAILURE;
-	} else {
-		if (r8712_efuse_reg_init(Adapter) == true) {
-			if (r8712_efuse_pg_packet_write(Adapter, ppgpkt->offset,
-			    ppgpkt->word_en, ppgpkt->data) == true)
-				*poid_par_priv->bytes_rw =
-					 poid_par_priv->information_buf_len;
-			else
-				status = RNDIS_STATUS_FAILURE;
-			r8712_efuse_reg_uninit(Adapter);
-		} else
-			status = RNDIS_STATUS_FAILURE;
-	}
-	return status;
-}
 
 uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv
 					      *poid_par_priv)
@@ -1319,24 +856,6 @@
 	return RNDIS_STATUS_SUCCESS;
 }
 
-uint oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	u32		crystal_cap = 0;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < sizeof(u32))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	crystal_cap = *((u32 *)poid_par_priv->information_buf);/*4*/
-	if (crystal_cap > 0xf)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	Adapter->mppriv.curr_crystalcap = crystal_cap;
-	r8712_SetCrystalCap(Adapter);
-	return RNDIS_STATUS_SUCCESS;
-}
-
 uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv
 					   *poid_par_priv)
 {
@@ -1378,50 +897,6 @@
 	return RNDIS_STATUS_SUCCESS;
 }
 
-uint oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv
-					     *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	u32 txagc;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-	if (poid_par_priv->information_buf_len < sizeof(u32))
-		return RNDIS_STATUS_INVALID_LENGTH;
-	txagc = *(u32 *)poid_par_priv->information_buf;
-	r8712_SetTxAGCOffset(Adapter, txagc);
-	return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv
-					     *poid_par_priv)
-{
-	struct _adapter *Adapter = (struct _adapter *)
-				   (poid_par_priv->adapter_context);
-	uint status = RNDIS_STATUS_SUCCESS;
-	struct mlme_priv	*pmlmepriv = &Adapter->mlmepriv;
-	struct mp_priv		*pmppriv = &Adapter->mppriv;
-	u32			type;
-
-	if (poid_par_priv->type_of_oid != SET_OID)
-		return RNDIS_STATUS_NOT_ACCEPTED;
-
-	if (poid_par_priv->information_buf_len < sizeof(u32))
-		return RNDIS_STATUS_INVALID_LENGTH;
-
-	type = *(u32 *)poid_par_priv->information_buf;
-
-	if (_LOOPBOOK_MODE_ == type) {
-		pmppriv->mode = type;
-		set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); /*append txdesc*/
-	} else if (_2MAC_MODE_ == type) {
-		pmppriv->mode = type;
-		_clr_fwstate_(pmlmepriv, WIFI_MP_LPBK_STATE);
-	} else
-		status = RNDIS_STATUS_NOT_ACCEPTED;
-	return status;
-}
 /*--------------------------------------------------------------------------*/
 /*Linux*/
 unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv)
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
index 850143d..8e7c7f8 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
@@ -86,41 +86,8 @@
 int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid);
 
 /* oid_rtl_seg_87_11_00 */
-uint oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_burst_read_register_hdl(struct oid_par_priv*
-					       poid_par_priv);
-uint oid_rt_pro_burst_write_register_hdl(struct oid_par_priv*
-						poid_par_priv);
-uint oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
-uint  oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_20 */
-uint oid_rt_pro_cfg_debug_message_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_data_rate_ex_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_basic_rate_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_power_tracking_hdl(
-				struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_50 */
-uint oid_rt_pro_qry_pwrstate_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_pwrstate_hdl(
-				struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_F0 */
-uint oid_rt_pro_h2c_set_rate_table_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_h2c_get_rate_table_hdl(
-				struct oid_par_priv *poid_par_priv);
 /* oid_rtl_seg_81_80_00 */
 uint oid_rt_pro_set_data_rate_hdl(
 				struct oid_par_priv *poid_par_priv);
@@ -159,28 +126,15 @@
 uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
 /* oid_rtl_seg_81_85 */
 uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_12_00 */
-uint oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_query_dr_variable_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_get_efuse_current_size_hdl(
 				struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
 uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_tx_agc_offset_hdl(
-				struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_pkt_test_mode_hdl(
-				struct oid_par_priv *poid_par_priv);
 uint oid_rt_get_thermal_meter_hdl(
 				struct oid_par_priv *poid_par_priv);
 uint oid_rt_reset_phy_rx_packet_count_hdl(
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index 0526ba0..dbfb555 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -33,17 +33,17 @@
 #define CMD_ALIVE	BIT(2)
 
 enum Power_Mgnt {
-	PS_MODE_ACTIVE	= 0	,
-	PS_MODE_MIN			,
-	PS_MODE_MAX			,
-	PS_MODE_DTIM			,
-	PS_MODE_VOIP			,
-	PS_MODE_UAPSD_WMM	,
-	PS_MODE_UAPSD			,
-	PS_MODE_IBSS			,
-	PS_MODE_WWLAN		,
-	PM_Radio_Off			,
-	PM_Card_Disable		,
+	PS_MODE_ACTIVE	= 0,
+	PS_MODE_MIN,
+	PS_MODE_MAX,
+	PS_MODE_DTIM,
+	PS_MODE_VOIP,
+	PS_MODE_UAPSD_WMM,
+	PS_MODE_UAPSD,
+	PS_MODE_IBSS,
+	PS_MODE_WWLAN,
+	PM_Radio_Off,
+	PM_Card_Disable,
 	PS_MODE_NUM
 };
 
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index 4c9b98e..1752121 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -83,9 +83,8 @@
 	spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL);
 	phead = &pstapriv->free_sta_queue.queue;
 	plist = phead->next;
-	while ((end_of_queue_search(phead, plist)) == false) {
+	while ((end_of_queue_search(phead, plist)) == false)
 		plist = plist->next;
-	}
 
 	spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
 }
@@ -228,7 +227,7 @@
 					      struct sta_info, hash_list);
 			plist = plist->next;
 			if (pbcmc_stainfo != psta)
-				r8712_free_stainfo(padapter , psta);
+				r8712_free_stainfo(padapter, psta);
 		}
 	}
 	spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index 62a377e..a28af03 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -471,7 +471,7 @@
 	return _SUCCESS;
 }
 
-static sint make_wlanhdr(struct _adapter *padapter , u8 *hdr,
+static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
 			 struct pkt_attrib *pattrib)
 {
 	u16 *qc;
diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h
index c4e0ef2..742dfa0 100644
--- a/drivers/staging/rtl8712/sta_info.h
+++ b/drivers/staging/rtl8712/sta_info.h
@@ -135,7 +135,7 @@
 u32 _r8712_free_sta_priv(struct sta_priv *pstapriv);
 struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv,
 				     u8 *hwaddr);
-void r8712_free_stainfo(struct _adapter *padapter , struct sta_info *psta);
+void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta);
 void r8712_free_all_stainfo(struct _adapter *padapter);
 struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr);
 void r8712_init_bcmc_stainfo(struct _adapter *padapter);
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 7d0d171..f8b5b33 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -366,7 +366,6 @@
 	struct net_device *pnetdev;
 	struct usb_device *udev;
 
-	printk(KERN_INFO "r8712u: Staging version\n");
 	/* In this probe function, O.S. will provide the usb interface pointer
 	 * to driver. We have to increase the reference count of the usb device
 	 * structure by using the usb_get_dev function.
@@ -463,7 +462,7 @@
 				/* Use the mac address stored in the Efuse
 				 * offset = 0x12 for usb in efuse
 				 */
-				memcpy(mac, &pdata[0x12], ETH_ALEN);
+				ether_addr_copy(mac, &pdata[0x12]);
 			}
 			eeprom_CustomerID = pdata[0x52];
 			switch (eeprom_CustomerID) {
@@ -580,7 +579,7 @@
 		} else
 			dev_info(&udev->dev,
 				"r8712u: MAC Address from efuse = %pM\n", mac);
-		memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
+		ether_addr_copy(pnetdev->dev_addr, mac);
 	}
 	/* step 6. Load the firmware asynchronously */
 	if (rtl871x_load_fw(padapter))
diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c
index e394d12..c6327c0 100644
--- a/drivers/staging/rtl8723au/core/rtw_ap.c
+++ b/drivers/staging/rtl8723au/core/rtw_ap.c
@@ -456,8 +456,8 @@
 		       sizeof(struct stainfo_stats));
 
 		/* prepare for add_RATid23a */
-		supportRateNum = rtw_get_rateset_len23a((u8*)&pcur_network->SupportedRates);
-		network_type = rtw_check_network_type23a((u8*)&pcur_network->SupportedRates, supportRateNum, 1);
+		supportRateNum = rtw_get_rateset_len23a((u8 *)&pcur_network->SupportedRates);
+		network_type = rtw_check_network_type23a((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
 
 		memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
 		psta->bssratelen = supportRateNum;
@@ -897,7 +897,7 @@
 	pairwise_cipher = 0;
 	psecuritypriv->wpa_group_cipher = 0;
 	psecuritypriv->wpa_pairwise_cipher = 0;
-	for (p = ie; ;p += (ie_len + 2)) {
+	for (p = ie; ; p += (ie_len + 2)) {
 		p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
 				  pbss_network->IELength - (ie_len + 2));
 		if ((p) && (!memcmp(p+2, RTW_WPA_OUI23A_TYPE, 4))) {
@@ -924,7 +924,7 @@
 	ie_len = 0;
 	pmlmepriv->qos_option = 0;
 	if (pregistrypriv->wmm_enable) {
-		for (p = ie; ;p += (ie_len + 2)) {
+		for (p = ie; ; p += (ie_len + 2)) {
 			p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
 					  (pbss_network->IELength -
 					   (ie_len + 2)));
@@ -1204,7 +1204,7 @@
 {
 }
 
-static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8*oui)
+static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8 *oui)
 {
 	DBG_8723A("%s\n", __func__);
 
diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c
index 60e0ded..2447a56 100644
--- a/drivers/staging/rtl8723au/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723au/core/rtw_cmd.c
@@ -245,11 +245,6 @@
 	return res;
 }
 
-void rtw_cmd_clr_isr23a(struct	cmd_priv *pcmdpriv)
-{
-	pcmdpriv->cmd_done_cnt++;
-}
-
 void rtw_free_cmd_obj23a(struct cmd_obj *pcmd)
 {
 
@@ -852,62 +847,6 @@
 	return res;
 }
 
-/*
- * This is only ever called from on_action_spct23a_ch_switch () which isn't
- * called from anywhere itself
- */
-int rtw_set_ch_cmd23a(struct rtw_adapter *padapter, u8 ch, u8 bw, u8 ch_offset,
-		      u8 enqueue)
-{
-	struct cmd_obj *pcmdobj;
-	struct set_ch_parm *set_ch_parm;
-	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
-	int res = _SUCCESS;
-
-	DBG_8723A("%s(%s): ch:%u, bw:%u, ch_offset:%u\n", __func__,
-		  padapter->pnetdev->name, ch, bw, ch_offset);
-
-	/* check input parameter */
-
-	/* prepare cmd parameter */
-	set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_KERNEL);
-	if (!set_ch_parm) {
-		res = _FAIL;
-		goto exit;
-	}
-	set_ch_parm->ch = ch;
-	set_ch_parm->bw = bw;
-	set_ch_parm->ch_offset = ch_offset;
-
-	if (enqueue) {
-		/* need enqueue, prepare cmd_obj and enqueue */
-		pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
-		if (!pcmdobj) {
-			kfree(set_ch_parm);
-			res = _FAIL;
-			goto exit;
-		}
-
-		init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm,
-					   GEN_CMD_CODE(_SetChannel));
-		res = rtw_enqueue_cmd23a(pcmdpriv, pcmdobj);
-	} else {
-		/* no need to enqueue, do the cmd hdl directly and
-		   free cmd parameter */
-		if (H2C_SUCCESS != set_ch_hdl23a(padapter, (u8 *)set_ch_parm))
-			res = _FAIL;
-
-		kfree(set_ch_parm);
-	}
-
-	/* do something based on res... */
-exit:
-
-	DBG_8723A("%s(%s): res:%u\n", __func__, padapter->pnetdev->name, res);
-
-	return res;
-}
-
 static void traffic_status_watchdog(struct rtw_adapter *padapter)
 {
 	u8 bEnterPS;
diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c
index 81960e7..a6deddc 100644
--- a/drivers/staging/rtl8723au/core/rtw_efuse.c
+++ b/drivers/staging/rtl8723au/core/rtw_efuse.c
@@ -327,15 +327,9 @@
  *---------------------------------------------------------------------------*/
 
 void
-EFUSE_Write1Byte(
-	struct rtw_adapter *	Adapter,
-	u16		Address,
-	u8		Value);
+EFUSE_Write1Byte(struct rtw_adapter *Adapter, u16 Address, u8 Value);
 void
-EFUSE_Write1Byte(
-	struct rtw_adapter *	Adapter,
-	u16		Address,
-	u8		Value)
+EFUSE_Write1Byte(struct rtw_adapter *Adapter, u16 Address, u8 Value)
 {
 	u8	Bytetemp = {0x00};
 	u8	temp = {0x00};
@@ -635,10 +629,7 @@
  *
  *---------------------------------------------------------------------------*/
 static void
-efuse_ShadowRead1Byte(
-	struct rtw_adapter *	pAdapter,
-	u16		Offset,
-	u8		*Value)
+efuse_ShadowRead1Byte(struct rtw_adapter *pAdapter, u16 Offset, u8 *Value)
 {
 	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
 
@@ -647,10 +638,7 @@
 
 /* Read Two Bytes */
 static void
-efuse_ShadowRead2Byte(
-	struct rtw_adapter *	pAdapter,
-	u16		Offset,
-	u16		*Value)
+efuse_ShadowRead2Byte(struct rtw_adapter *pAdapter, u16 Offset, u16 *Value)
 {
 	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
 
@@ -660,10 +648,7 @@
 
 /* Read Four Bytes */
 static void
-efuse_ShadowRead4Byte(
-	struct rtw_adapter *	pAdapter,
-	u16		Offset,
-	u32		*Value)
+efuse_ShadowRead4Byte(struct rtw_adapter *pAdapter, u16 Offset, u32 *Value)
 {
 	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
 
@@ -722,11 +707,8 @@
  *
  *---------------------------------------------------------------------------*/
 void
-EFUSE_ShadowRead23a(
-	struct rtw_adapter *	pAdapter,
-	u8		Type,
-	u16		Offset,
-	u32		*Value)
+EFUSE_ShadowRead23a(struct rtw_adapter *pAdapter,
+		    u8 Type, u16 Offset, u32 *Value)
 {
 	if (Type == 1)
 		efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c
index 7a5e6bf..1c82dff 100644
--- a/drivers/staging/rtl8723au/core/rtw_xmit.c
+++ b/drivers/staging/rtl8723au/core/rtw_xmit.c
@@ -2372,12 +2372,3 @@
 	return rtw_sctx_wait23a(pack_tx_ops);
 }
 
-void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status)
-{
-	struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
-
-	if (pxmitpriv->ack_tx)
-		rtw23a_sctx_done_err(&pack_tx_ops, status);
-	else
-		DBG_8723A("%s ack_tx not set\n", __func__);
-}
diff --git a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
index 1da4eec..33777d2 100644
--- a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
+++ b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
@@ -47,11 +47,11 @@
 		       u8 FabVersion, u8 InterfaceType,
 		       struct wlan_pwr_cfg PwrSeqCmd[])
 {
-	struct wlan_pwr_cfg PwrCfgCmd = { 0 };
-	u8 bPollingBit = false;
+	struct wlan_pwr_cfg PwrCfgCmd;
+	u8 bPollingBit;
 	u32 AryIdx = 0;
-	u8 value = 0;
-	u32 offset = 0;
+	u8 value;
+	u32 offset;
 	u32 pollingCount = 0;	/*  polling autoload done. */
 	u32 maxPollingCnt = 5000;
 
diff --git a/drivers/staging/rtl8723au/hal/odm.c b/drivers/staging/rtl8723au/hal/odm.c
index 1c0f106d..5269b46 100644
--- a/drivers/staging/rtl8723au/hal/odm.c
+++ b/drivers/staging/rtl8723au/hal/odm.c
@@ -187,24 +187,13 @@
 
 void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm);
 
-void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm);
 /* END---------BB POWER SAVE----------------------- */
 
-void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm);
-
 void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm);
 
-void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm);
-
 void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm);
 
-void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm);
-
-void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm);
-
 void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm);
-void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm);
-
 void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm);
 void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm);
 
@@ -212,16 +201,12 @@
 
 void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm);
 
-void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm);
-
 void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm);
 
 void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm);
 
 void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm);
 
-void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm);
-
 void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm);
 
 static void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm);
@@ -946,47 +931,13 @@
 	return;
 }
 
-void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm)
-{
-	struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
-
-	if (pDM_Odm->RSSI_Min != 0xFF) {
-		if (pDM_PSTable->PreCCAState == CCA_2R) {
-			if (pDM_Odm->RSSI_Min >= 35)
-				pDM_PSTable->CurCCAState = CCA_1R;
-			else
-				pDM_PSTable->CurCCAState = CCA_2R;
-		} else {
-			if (pDM_Odm->RSSI_Min <= 30)
-				pDM_PSTable->CurCCAState = CCA_2R;
-			else
-				pDM_PSTable->CurCCAState = CCA_1R;
-		}
-	} else {
-		pDM_PSTable->CurCCAState = CCA_MAX;
-	}
-
-	if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) {
-		if (pDM_PSTable->CurCCAState == CCA_1R) {
-			if (pDM_Odm->RFType == ODM_2T2R)
-				ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13);
-			else
-				ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23);
-		} else {
-			ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33);
-			/* PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x63); */
-		}
-		pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState;
-	}
-}
-
 void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal)
 {
 	struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
-	u8 Rssi_Up_bound = 30 ;
+	u8 Rssi_Up_bound = 30;
 	u8 Rssi_Low_bound = 25;
 	if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */
-		Rssi_Up_bound = 50 ;
+		Rssi_Up_bound = 50;
 		Rssi_Low_bound = 45;
 	}
 	if (pDM_PSTable->initialize == 0) {
@@ -1177,10 +1128,6 @@
 	odm_RefreshRateAdaptiveMask23aCE23a(pDM_Odm);
 }
 
-void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm)
-{
-}
-
 void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm)
 {
 	u8 i;
@@ -1216,10 +1163,6 @@
 
 }
 
-void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm)
-{
-}
-
 /*  Return Value: bool */
 /*  - true: RATRState is changed. */
 bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate,
@@ -1284,14 +1227,6 @@
 	pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal;
 }
 
-/* 3 ============================================================ */
-/* 3 RSSI Monitor */
-/* 3 ============================================================ */
-
-void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm)
-{
-}
-
 void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm)
 {
 	/*  For AP/ADSL use struct rtl8723a_priv * */
@@ -1306,10 +1241,6 @@
 	odm_RSSIMonitorCheck23aCE(pDM_Odm);
 }	/*  odm_RSSIMonitorCheck23a */
 
-void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm)
-{
-}
-
 static void
 FindMinimumRSSI(
 	struct rtw_adapter *pAdapter
@@ -1378,10 +1309,6 @@
 	ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM);
 }
 
-void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm)
-{
-}
-
 /* endif */
 /* 3 ============================================================ */
 /* 3 Tx Power Tracking */
@@ -1422,19 +1349,12 @@
 {
 }
 
-void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm)
-{
-}
-
-void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm)
-{
-}
-
 /* EDCA Turbo */
 static void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm)
 {
 
 	struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
 	pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
 	pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
 	Adapter->recvpriv.bIsAnyNonBEPkts = false;
@@ -1591,6 +1511,7 @@
 void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm)
 {
 	struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
 	pDM_SWAT_Table->ANTA_ON = true;
 	pDM_SWAT_Table->ANTB_ON = true;
 }
diff --git a/drivers/staging/rtl8723au/hal/odm_HWConfig.c b/drivers/staging/rtl8723au/hal/odm_HWConfig.c
index fb3cc87..33aafa0 100644
--- a/drivers/staging/rtl8723au/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723au/hal/odm_HWConfig.c
@@ -113,7 +113,7 @@
 
 		cck_highpwr = pDM_Odm->bCckHighPower;
 
-		cck_agc_rpt =  pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+		cck_agc_rpt =  pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a;
 
 		/* The RSSI formula should be modified according to the gain table */
 		if (!cck_highpwr) {
@@ -138,16 +138,16 @@
 			report = (cck_agc_rpt & 0x60)>>5;
 			switch (report) {
 			case 0x3:
-				rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ;
+				rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1);
 				break;
 			case 0x2:
 				rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1);
 				break;
 			case 0x1:
-				rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ;
+				rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1);
 				break;
 			case 0x0:
-				rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ;
+				rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1);
 				break;
 			}
 		}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
index 86a8397..73cfddd 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
@@ -7255,63 +7255,19 @@
 		RTPRINT(FBT, BT_TRACE, ("[BTCoex], first run TdmaDurationAdjust()!!\n"));
 		if (bScoHid) {
 			if (bTxPause) {
-				if (maxInterval == 1) {
-					btdm_2AntPsTdma(padapter, true, 15);
-					pBtdm8723->psTdmaDuAdjType = 15;
-				} else if (maxInterval == 2) {
-					btdm_2AntPsTdma(padapter, true, 15);
-					pBtdm8723->psTdmaDuAdjType = 15;
-				} else if (maxInterval == 3) {
-					btdm_2AntPsTdma(padapter, true, 15);
-					pBtdm8723->psTdmaDuAdjType = 15;
-				} else {
-					btdm_2AntPsTdma(padapter, true, 15);
-					pBtdm8723->psTdmaDuAdjType = 15;
-				}
+				btdm_2AntPsTdma(padapter, true, 15);
+				pBtdm8723->psTdmaDuAdjType = 15;
 			} else {
-				if (maxInterval == 1) {
-					btdm_2AntPsTdma(padapter, true, 11);
-					pBtdm8723->psTdmaDuAdjType = 11;
-				} else if (maxInterval == 2) {
-					btdm_2AntPsTdma(padapter, true, 11);
-					pBtdm8723->psTdmaDuAdjType = 11;
-				} else if (maxInterval == 3) {
-					btdm_2AntPsTdma(padapter, true, 11);
-					pBtdm8723->psTdmaDuAdjType = 11;
-				} else {
-					btdm_2AntPsTdma(padapter, true, 11);
-					pBtdm8723->psTdmaDuAdjType = 11;
-				}
+				btdm_2AntPsTdma(padapter, true, 11);
+				pBtdm8723->psTdmaDuAdjType = 11;
 			}
 		} else {
 			if (bTxPause) {
-				if (maxInterval == 1) {
-					btdm_2AntPsTdma(padapter, true, 7);
-					pBtdm8723->psTdmaDuAdjType = 7;
-				} else if (maxInterval == 2) {
-					btdm_2AntPsTdma(padapter, true, 7);
-					pBtdm8723->psTdmaDuAdjType = 7;
-				} else if (maxInterval == 3) {
-					btdm_2AntPsTdma(padapter, true, 7);
-					pBtdm8723->psTdmaDuAdjType = 7;
-				} else {
-					btdm_2AntPsTdma(padapter, true, 7);
-					pBtdm8723->psTdmaDuAdjType = 7;
-				}
+				btdm_2AntPsTdma(padapter, true, 7);
+				pBtdm8723->psTdmaDuAdjType = 7;
 			} else {
-				if (maxInterval == 1) {
-					btdm_2AntPsTdma(padapter, true, 3);
-					pBtdm8723->psTdmaDuAdjType = 3;
-				} else if (maxInterval == 2) {
-					btdm_2AntPsTdma(padapter, true, 3);
-					pBtdm8723->psTdmaDuAdjType = 3;
-				} else if (maxInterval == 3) {
-					btdm_2AntPsTdma(padapter, true, 3);
-					pBtdm8723->psTdmaDuAdjType = 3;
-				} else {
-					btdm_2AntPsTdma(padapter, true, 3);
-					pBtdm8723->psTdmaDuAdjType = 3;
-				}
+				btdm_2AntPsTdma(padapter, true, 3);
+				pBtdm8723->psTdmaDuAdjType = 3;
 			}
 		}
 		up = 0;
@@ -9145,7 +9101,7 @@
 	u32	counters = 0;
 
 	counters = pHalData->bt_coexist.halCoex8723.lowPriorityTx+
-		pHalData->bt_coexist.halCoex8723.lowPriorityRx ;
+		pHalData->bt_coexist.halCoex8723.lowPriorityRx;
 	return counters;
 }
 
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
index 88e91cd..19dc5e3 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
@@ -698,7 +698,7 @@
  * 11/10/2008	tynli	Modify to mew files.
  *---------------------------------------------------------------------------*/
 static	int
-phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter, u8 ConfigType)
+phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter)
 {
 	int i;
 	u32 *Rtl819XPHY_REGArray_Table_PG;
@@ -707,17 +707,15 @@
 	PHY_REGArrayPGLen = Rtl8723_PHY_REG_Array_PGLength;
 	Rtl819XPHY_REGArray_Table_PG = (u32 *)Rtl8723_PHY_REG_Array_PG;
 
-	if (ConfigType == BaseBand_Config_PHY_REG) {
-		for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) {
-			storePwrIndexDiffRateOffset(Adapter,
-				Rtl819XPHY_REGArray_Table_PG[i],
-				Rtl819XPHY_REGArray_Table_PG[i+1],
-				Rtl819XPHY_REGArray_Table_PG[i+2]);
-		}
+	for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) {
+		storePwrIndexDiffRateOffset(Adapter,
+					    Rtl819XPHY_REGArray_Table_PG[i],
+					    Rtl819XPHY_REGArray_Table_PG[i+1],
+					    Rtl819XPHY_REGArray_Table_PG[i+2]);
 	}
 
 	return _SUCCESS;
-}	/* phy_ConfigBBWithPgHeaderFile */
+}
 
 static void
 phy_BB8192C_Config_1T(struct rtw_adapter *Adapter)
@@ -768,8 +766,7 @@
 	if (pEEPROM->bautoload_fail_flag == false) {
 		pHalData->pwrGroupCnt = 0;
 
-		rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter,
-							BaseBand_Config_PHY_REG);
+		rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter);
 	}
 
 	if (rtStatus != _SUCCESS)
@@ -923,9 +920,6 @@
 	u8 regBwOpMode;
 	u8 regRRSR_RSC;
 
-	if (pHalData->rf_chip == RF_PSEUDO_11N)
-		return;
-
 	/*  There is no 40MHz mode in RF_8225. */
 	if (pHalData->rf_chip == RF_8225)
 		return;
@@ -1021,10 +1015,6 @@
 		/*  PHY_SetRF8258Bandwidth(); */
 		break;
 
-	case RF_PSEUDO_11N:
-		/*  Do Nothing */
-		break;
-
 	case RF_6052:
 		rtl8723a_phy_rf6052set_bw(Adapter, pHalData->CurrentChannelBW);
 		break;
@@ -1074,7 +1064,7 @@
 
 static void _PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
 {
-	u8 eRFPath;
+	enum RF_RADIO_PATH eRFPath;
 	u32 param1, param2;
 	struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
 
@@ -1088,7 +1078,7 @@
 	for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
 		pHalData->RfRegChnlVal[eRFPath] =
 			(pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2;
-		PHY_SetRFReg(Adapter, (enum RF_RADIO_PATH)eRFPath, param1,
+		PHY_SetRFReg(Adapter, eRFPath, param1,
 			     bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
 	}
 
@@ -1101,11 +1091,6 @@
 	u8 tmpchannel = pHalData->CurrentChannel;
 	bool  result = true;
 
-	if (pHalData->rf_chip == RF_PSEUDO_11N) {
-		/* return immediately if it is peudo-phy */
-		return;
-	}
-
 	if (channel == 0)
 		channel = 1;
 
diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
index 6070510..1759487 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
@@ -79,7 +79,7 @@
 	}
 }
 
-static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw)
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
 {
 	/* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
 
@@ -114,7 +114,7 @@
 	}
 }
 
-static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw)
+static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
 {
 	if (pattrib->ht_en) {
 		*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
diff --git a/drivers/staging/rtl8723au/hal/usb_halinit.c b/drivers/staging/rtl8723au/hal/usb_halinit.c
index febe5ce..adbf1c2 100644
--- a/drivers/staging/rtl8723au/hal/usb_halinit.c
+++ b/drivers/staging/rtl8723au/hal/usb_halinit.c
@@ -625,10 +625,10 @@
 	}
 
 	/* reducing 80M spur */
-	PHY_SetBBReg(Adapter, RF_T_METER, bMaskDWord, 0x0381808d);
-	PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
-	PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff82);
-	PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
+	PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, bMaskDWord, 0x0381808d);
+	PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff83);
+	PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff82);
+	PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff83);
 
 	/* RFSW Control */
 	PHY_SetBBReg(Adapter, rFPGA0_TxInfo, bMaskDWord, 0x00000003);	/* 0x804[14]= 0 */
@@ -640,8 +640,10 @@
 	/*  */
 	/*  Joseph Note: Keep RfRegChnlVal for later use. */
 	/*  */
-	pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)0, RF_CHNLBW, bRFRegOffsetMask);
-	pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)1, RF_CHNLBW, bRFRegOffsetMask);
+	pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, RF_PATH_A,
+						   RF_CHNLBW, bRFRegOffsetMask);
+	pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, RF_PATH_B,
+						   RF_CHNLBW, bRFRegOffsetMask);
 
 	if (!mac_on) {
 		_InitQueueReservedPage(Adapter);
diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
index 688f204..2247d98 100644
--- a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
+++ b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
@@ -17,46 +17,9 @@
 #define __INC_HAL8723PHYCFG_H__
 
 /*--------------------------Define Parameters-------------------------------*/
-#define LOOP_LIMIT				5
-#define MAX_STALL_TIME		50		/* us */
-#define AntennaDiversityValue	0x80
-#define MAX_TXPWR_IDX_NMODE_92S	63
-#define Reset_Cnt_Limit		3
-
-
 #define MAX_AGGR_NUM	0x0909
 
-/*--------------------------Define Parameters-------------------------------*/
-
-
 /*------------------------------Define structure----------------------------*/
-enum swchnlcmdid {
-	CmdID_End,
-	CmdID_SetTxPowerLevel,
-	CmdID_BBRegWrite10,
-	CmdID_WritePortUlong,
-	CmdID_WritePortUshort,
-	CmdID_WritePortUchar,
-	CmdID_RF_WriteReg,
-};
-
-
-/* 1. Switch channel related */
-struct swchnlcmd {
-	enum swchnlcmdid	CmdID;
-	u32			Para1;
-	u32			Para2;
-	u32			msDelay;
-};
-
-enum HW90_BLOCK {
-	HW90_BLOCK_MAC = 0,
-	HW90_BLOCK_PHY0 = 1,
-	HW90_BLOCK_PHY1 = 2,
-	HW90_BLOCK_RF = 3,
-	HW90_BLOCK_MAXIMUM = 4, /*  Never use this */
-};
-
 enum RF_RADIO_PATH {
 	RF_PATH_A = 0,			/* Radio Path A */
 	RF_PATH_B = 1,			/* Radio Path B */
@@ -64,7 +27,6 @@
 };
 
 #define CHANNEL_MAX_NUMBER		14	/*  14 is the max channel number */
-#define CHANNEL_GROUP_MAX		3	/*  ch1~3, ch4~9, ch10~14 total three groups */
 
 enum WIRELESS_MODE {
 	WIRELESS_MODE_UNKNOWN	= 0x00,
@@ -77,22 +39,6 @@
 	WIRELESS_MODE_AC	= BIT(6)
 };
 
-enum baseband_config_type {
-	BaseBand_Config_PHY_REG = 0,			/* Radio Path A */
-	BaseBand_Config_AGC_TAB = 1,			/* Radio Path B */
-};
-
-enum ra_offset_area {
-	RA_OFFSET_LEGACY_OFDM1,
-	RA_OFFSET_LEGACY_OFDM2,
-	RA_OFFSET_HT_OFDM1,
-	RA_OFFSET_HT_OFDM2,
-	RA_OFFSET_HT_OFDM3,
-	RA_OFFSET_HT_OFDM4,
-	RA_OFFSET_HT_CCK,
-};
-
-
 /* BB/RF related */
 enum rf_type_8190p {
 	RF_TYPE_MIN,		/*  0 */
@@ -100,7 +46,6 @@
 	RF_8256 = 2,		/*  2 11b/g/n */
 	RF_8258 = 3,		/*  3 11a/b/g/n RF */
 	RF_6052 = 4,		/*  4 11b/g/n RF */
-	RF_PSEUDO_11N = 5,	/*  5, It is a temporality RF. */
 };
 
 struct bb_reg_define {
diff --git a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
index 4a1f58f..3771d6b 100644
--- a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
+++ b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
@@ -39,10 +39,10 @@
  * { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },  comments here
  */
 #define RTL8723A_TRANS_CARDEMU_TO_ACT														\
-	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \
-	{0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/	\
-	{0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/   \
-	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/   \
+	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \
+	{0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/	\
+	{0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/   \
+	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/   \
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},/* disable SW LPS 0x04[10]= 0*/	\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},/* wait till 0x04[17] = 1    power ready*/	\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},/* release WLON reset  0x04[16]= 1*/ \
@@ -57,48 +57,28 @@
 	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, /*0x04[9] = 1 turn off MAC by HW state machine*/	\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/	\
-	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/   \
-	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/   \
+	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/   \
+	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/   \
 
 
 #define RTL8723A_TRANS_CARDEMU_TO_SUS													\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), (BIT(4)|BIT(3))}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/	\
-	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
-	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/   \
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*Set SDIO suspend local register*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/
 
 #define RTL8723A_TRANS_SUS_TO_CARDEMU													\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, /*clear suspend enable and power down enable*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
-	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/   \
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
 
 #define RTL8723A_TRANS_CARDEMU_TO_CARDDIS													\
-	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/	\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/	\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)}, /*0x04[10] = 1, enable SW LPS*/	\
-	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/   \
-	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*Set SDIO suspend local register*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/	\
+	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/
 
 #define RTL8723A_TRANS_CARDDIS_TO_CARDEMU													\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, /*clear suspend enable and power down enable*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
 	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/   \
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\
-	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/   \
-	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/
-
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
 
 #define RTL8723A_TRANS_CARDEMU_TO_PDN												\
-	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
-	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/   \
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/   \
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
 
@@ -106,7 +86,6 @@
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
 
 #define RTL8723A_TRANS_ACT_TO_LPS														\
-	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/	\
 	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/	\
 	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
 	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
@@ -117,13 +96,10 @@
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},/*Whole BB is reset*/	\
 	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/	\
 	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},/*check if removed later*/	\
-	{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/	\
 	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},/*Respond TxOK to scheduler*/
 
 #define RTL8723A_TRANS_LPS_TO_ACT															\
-	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
 	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
-	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
 	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*.	0x08[4] = 0		 switch TSF to 40M*/\
 	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, /*Polling 0x109[7]= 0  TSF in 40M*/\
diff --git a/drivers/staging/rtl8723au/include/osdep_intf.h b/drivers/staging/rtl8723au/include/osdep_intf.h
index 33afa62..a157eb2 100644
--- a/drivers/staging/rtl8723au/include/osdep_intf.h
+++ b/drivers/staging/rtl8723au/include/osdep_intf.h
@@ -19,9 +19,6 @@
 #include <osdep_service.h>
 #include <drv_types.h>
 
-int rtw_hw_suspend23a(struct rtw_adapter *padapter);
-int rtw_hw_resume23a(struct rtw_adapter *padapter);
-
 int rtw_init_drv_sw23a(struct rtw_adapter *padapter);
 int rtw_free_drv_sw23a(struct rtw_adapter *padapter);
 int rtw_reset_drv_sw23a(struct rtw_adapter *padapter);
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
index 0506965..7add5df 100644
--- a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
+++ b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
@@ -31,8 +31,8 @@
 
 void BT_SignalCompensation(struct rtw_adapter *padapter,
 			   u8 *rssi_wifi, u8 *rssi_bt);
-void BT_HaltProcess(struct rtw_adapter * padapter);
-void BT_LpsLeave(struct rtw_adapter * padapter);
+void BT_HaltProcess(struct rtw_adapter *padapter);
+void BT_LpsLeave(struct rtw_adapter *padapter);
 
 
 #define	BT_HsConnectionEstablished(Adapter)		false
@@ -1092,17 +1092,20 @@
 	BTHCI_StateMachine(_Adapter, _StateToEnter, _StateCmd, _EntryNum);\
 }
 
-void BTHCI_EventParse(struct rtw_adapter * padapter, void *pEvntData, u32 dataLen);
+void BTHCI_EventParse(struct rtw_adapter *padapter, void *pEvntData,
+		      u32 dataLen);
 #define BT_EventParse BTHCI_EventParse
-u8 BTHCI_HsConnectionEstablished(struct rtw_adapter * padapter);
-void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter * padapter);
-void BTHCI_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
-void BTHCI_StateMachine(struct rtw_adapter * padapter, u8 StateToEnter, enum hci_state_with_cmd StateCmd, u8 EntryNum);
-void BTHCI_DisconnectPeer(struct rtw_adapter * padapter, u8 EntryNum);
-void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter * padapter);
-void BTHCI_EventAMPStatusChange(struct rtw_adapter * padapter, u8 AMP_Status);
-void BTHCI_DisconnectAll(struct rtw_adapter * padapter);
-enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter * padapter, struct packet_irp_hcicmd_data *pHciCmd);
+u8 BTHCI_HsConnectionEstablished(struct rtw_adapter *padapter);
+void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter *padapter);
+void BTHCI_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType);
+void BTHCI_StateMachine(struct rtw_adapter *padapter, u8 StateToEnter,
+			enum hci_state_with_cmd StateCmd, u8 EntryNum);
+void BTHCI_DisconnectPeer(struct rtw_adapter *padapter, u8 EntryNum);
+void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter *padapter);
+void BTHCI_EventAMPStatusChange(struct rtw_adapter *padapter, u8 AMP_Status);
+void BTHCI_DisconnectAll(struct rtw_adapter *padapter);
+enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter *padapter,
+				   struct packet_irp_hcicmd_data *pHciCmd);
 
 /*  ===== End of sync from SD7 driver COMMON/bt_hci.h ===== */
 
@@ -1157,9 +1160,10 @@
 	u8		bRAChanged;
 };
 
-void BTDM_1AntSignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
-void BTDM_1AntForDhcp(struct rtw_adapter * padapter);
-void BTDM_1AntBtCoexist8723A(struct rtw_adapter * padapter);
+void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter,
+				 u8 *rssi_wifi, u8 *rssi_bt);
+void BTDM_1AntForDhcp(struct rtw_adapter *padapter);
+void BTDM_1AntBtCoexist8723A(struct rtw_adapter *padapter);
 
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */
 
@@ -1241,7 +1245,7 @@
 	u8	btStatus;
 };
 
-void BTDM_2AntBtCoexist8723A(struct rtw_adapter * padapter);
+void BTDM_2AntBtCoexist8723A(struct rtw_adapter *padapter);
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */
 
 /*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
@@ -1310,15 +1314,17 @@
 	struct btdm_8723a_1ant			btdm1Ant;
 };
 
-void BTDM_SetFwChnlInfo(struct rtw_adapter * padapter, enum rt_media_status mstatus);
-u8 BTDM_IsWifiConnectionExist(struct rtw_adapter * padapter);
-void BTDM_SetFw3a(struct rtw_adapter * padapter, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5);
-void BTDM_QueryBtInformation(struct rtw_adapter * padapter);
-void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter * padapter, u8 type);
-void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter * padapter, u8 raType);
-void BTDM_SetFwDecBtPwr(struct rtw_adapter * padapter, u8 bDecBtPwr);
-u8 BTDM_BtProfileSupport(struct rtw_adapter * padapter);
-void BTDM_LpsLeave(struct rtw_adapter * padapter);
+void BTDM_SetFwChnlInfo(struct rtw_adapter *padapter,
+			enum rt_media_status mstatus);
+u8 BTDM_IsWifiConnectionExist(struct rtw_adapter *padapter);
+void BTDM_SetFw3a(struct rtw_adapter *padapter, u8 byte1, u8 byte2, u8 byte3,
+		  u8 byte4, u8 byte5);
+void BTDM_QueryBtInformation(struct rtw_adapter *padapter);
+void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter *padapter, u8 type);
+void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter *padapter, u8 raType);
+void BTDM_SetFwDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr);
+u8 BTDM_BtProfileSupport(struct rtw_adapter *padapter);
+void BTDM_LpsLeave(struct rtw_adapter *padapter);
 
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
 
@@ -1340,8 +1346,9 @@
 #define BTDM_ANT_BT						2
 
 
-void BTDM_SingleAnt(struct rtw_adapter * padapter, u8 bSingleAntOn, u8 bInterruptOn, u8 bMultiNAVOn);
-void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter * padapter);
+void BTDM_SingleAnt(struct rtw_adapter *padapter, u8 bSingleAntOn,
+		    u8 bInterruptOn, u8 bMultiNAVOn);
+void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter *padapter);
 
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */
 
@@ -1361,7 +1368,8 @@
 #define	BT_DACSWING_M7				2
 #define	BT_DACSWING_M10				3
 
-void BTDM_DiminishWiFi(struct rtw_adapter * Adapter, u8 bDACOn, u8 bInterruptOn, u8 DACSwingLevel, u8 bNAVOn);
+void BTDM_DiminishWiFi(struct rtw_adapter *Adapter, u8 bDACOn, u8 bInterruptOn,
+		       u8 DACSwingLevel, u8 bNAVOn);
 
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */
 
@@ -1534,58 +1542,63 @@
 	u8			fw3aVal[5];
 };
 
-void BTDM_CheckAntSelMode(struct rtw_adapter * padapter);
-void BTDM_FwC2hBtRssi(struct rtw_adapter * padapter, u8 *tmpBuf);
+void BTDM_CheckAntSelMode(struct rtw_adapter *padapter);
+void BTDM_FwC2hBtRssi(struct rtw_adapter *padapter, u8 *tmpBuf);
 #define BT_FwC2hBtRssi BTDM_FwC2hBtRssi
-void BTDM_DisplayBtCoexInfo(struct rtw_adapter * padapter);
+void BTDM_DisplayBtCoexInfo(struct rtw_adapter *padapter);
 #define BT_DisplayBtCoexInfo BTDM_DisplayBtCoexInfo
-void BTDM_RejectAPAggregatedPacket(struct rtw_adapter * padapter, u8 bReject);
-u8 BTDM_IsHT40(struct rtw_adapter * padapter);
-u8 BTDM_Legacy(struct rtw_adapter * padapter);
-void BTDM_CheckWiFiState(struct rtw_adapter * padapter);
-s32 BTDM_GetRxSS(struct rtw_adapter * padapter);
-u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-u8 BTDM_CheckCoexRSSIState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-void BTDM_Balance(struct rtw_adapter * padapter, u8 bBalanceOn, u8 ms0, u8 ms1);
-void BTDM_AGCTable(struct rtw_adapter * padapter, u8 type);
-void BTDM_BBBackOffLevel(struct rtw_adapter * padapter, u8 type);
-void BTDM_FWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_SWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_HWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_CoexAllOff(struct rtw_adapter * padapter);
-void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter * padapter);
-void BTDM_SignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
-void BTDM_UpdateCoexState(struct rtw_adapter * padapter);
-u8 BTDM_IsSameCoexistState(struct rtw_adapter * padapter);
-void BTDM_PWDBMonitor(struct rtw_adapter * padapter);
-u8 BTDM_IsBTBusy(struct rtw_adapter * padapter);
+void BTDM_RejectAPAggregatedPacket(struct rtw_adapter *padapter, u8 bReject);
+u8 BTDM_IsHT40(struct rtw_adapter *padapter);
+u8 BTDM_Legacy(struct rtw_adapter *padapter);
+void BTDM_CheckWiFiState(struct rtw_adapter *padapter);
+s32 BTDM_GetRxSS(struct rtw_adapter *padapter);
+u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter *padapter, u8 levelNum,
+			      u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter *padapter, u8 levelNum,
+			    u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState(struct rtw_adapter *padapter, u8 levelNum,
+			   u8 RssiThresh, u8 RssiThresh1);
+void BTDM_Balance(struct rtw_adapter *padapter, u8 bBalanceOn, u8 ms0, u8 ms1);
+void BTDM_AGCTable(struct rtw_adapter *padapter, u8 type);
+void BTDM_BBBackOffLevel(struct rtw_adapter *padapter, u8 type);
+void BTDM_FWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_SWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_HWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_CoexAllOff(struct rtw_adapter *padapter);
+void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter *padapter);
+void BTDM_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi,
+			     u8 *rssi_bt);
+void BTDM_UpdateCoexState(struct rtw_adapter *padapter);
+u8 BTDM_IsSameCoexistState(struct rtw_adapter *padapter);
+void BTDM_PWDBMonitor(struct rtw_adapter *padapter);
+u8 BTDM_IsBTBusy(struct rtw_adapter *padapter);
 #define BT_IsBtBusy BTDM_IsBTBusy
-u8 BTDM_IsWifiBusy(struct rtw_adapter * padapter);
-u8 BTDM_IsCoexistStateChanged(struct rtw_adapter * padapter);
-u8 BTDM_IsWifiUplink(struct rtw_adapter * padapter);
-u8 BTDM_IsWifiDownlink(struct rtw_adapter * padapter);
-u8 BTDM_IsBTHSMode(struct rtw_adapter * padapter);
-u8 BTDM_IsBTUplink(struct rtw_adapter * padapter);
-u8 BTDM_IsBTDownlink(struct rtw_adapter * padapter);
-void BTDM_AdjustForBtOperation(struct rtw_adapter * padapter);
-void BTDM_ForHalt(struct rtw_adapter * padapter);
-void BTDM_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
-void BTDM_WifiAssociateNotify(struct rtw_adapter * padapter, u8 action);
-void BTDM_MediaStatusNotify(struct rtw_adapter * padapter, enum rt_media_status mstatus);
-void BTDM_ForDhcp(struct rtw_adapter * padapter);
-void BTDM_ResetActionProfileState(struct rtw_adapter * padapter);
-void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter * padapter, u8 antNum);
+u8 BTDM_IsWifiBusy(struct rtw_adapter *padapter);
+u8 BTDM_IsCoexistStateChanged(struct rtw_adapter *padapter);
+u8 BTDM_IsWifiUplink(struct rtw_adapter *padapter);
+u8 BTDM_IsWifiDownlink(struct rtw_adapter *padapter);
+u8 BTDM_IsBTHSMode(struct rtw_adapter *padapter);
+u8 BTDM_IsBTUplink(struct rtw_adapter *padapter);
+u8 BTDM_IsBTDownlink(struct rtw_adapter *padapter);
+void BTDM_AdjustForBtOperation(struct rtw_adapter *padapter);
+void BTDM_ForHalt(struct rtw_adapter *padapter);
+void BTDM_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType);
+void BTDM_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action);
+void BTDM_MediaStatusNotify(struct rtw_adapter *padapter,
+			    enum rt_media_status mstatus);
+void BTDM_ForDhcp(struct rtw_adapter *padapter);
+void BTDM_ResetActionProfileState(struct rtw_adapter *padapter);
+void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum);
 #define BT_SetBtCoexCurrAntNum BTDM_SetBtCoexCurrAntNum
-u8 BTDM_IsActionSCO(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHID(struct rtw_adapter * padapter);
-u8 BTDM_IsActionA2DP(struct rtw_adapter * padapter);
-u8 BTDM_IsActionPAN(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHIDA2DP(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHIDPAN(struct rtw_adapter * padapter);
-u8 BTDM_IsActionPANA2DP(struct rtw_adapter * padapter);
-u32 BTDM_BtTxRxCounterH(struct rtw_adapter * padapter);
-u32 BTDM_BtTxRxCounterL(struct rtw_adapter * padapter);
+u8 BTDM_IsActionSCO(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHID(struct rtw_adapter *padapter);
+u8 BTDM_IsActionA2DP(struct rtw_adapter *padapter);
+u8 BTDM_IsActionPAN(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHIDA2DP(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHIDPAN(struct rtw_adapter *padapter);
+u8 BTDM_IsActionPANA2DP(struct rtw_adapter *padapter);
+u32 BTDM_BtTxRxCounterH(struct rtw_adapter *padapter);
+u32 BTDM_BtTxRxCounterL(struct rtw_adapter *padapter);
 
 /*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */
 
@@ -1593,14 +1606,14 @@
 
 #define RTS_CTS_NO_LEN_LIMIT	0
 
-u8 HALBT_GetPGAntNum(struct rtw_adapter * padapter);
+u8 HALBT_GetPGAntNum(struct rtw_adapter *padapter);
 #define BT_GetPGAntNum HALBT_GetPGAntNum
-void HALBT_SetKey(struct rtw_adapter * padapter, u8 EntryNum);
-void HALBT_RemoveKey(struct rtw_adapter * padapter, u8 EntryNum);
-u8 HALBT_IsBTExist(struct rtw_adapter * padapter);
+void HALBT_SetKey(struct rtw_adapter *padapter, u8 EntryNum);
+void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum);
+u8 HALBT_IsBTExist(struct rtw_adapter *padapter);
 #define BT_IsBtExist HALBT_IsBTExist
-u8 HALBT_BTChipType(struct rtw_adapter * padapter);
-void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter * padapter);
+u8 HALBT_BTChipType(struct rtw_adapter *padapter);
+void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter *padapter);
 
 /*  ===== End of sync from SD7 driver HAL/HalBT.c ===== */
 
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_recv.h b/drivers/staging/rtl8723au/include/rtl8723a_recv.h
index 0177bbc..875d37b 100644
--- a/drivers/staging/rtl8723au/include/rtl8723a_recv.h
+++ b/drivers/staging/rtl8723au/include/rtl8723a_recv.h
@@ -56,8 +56,8 @@
 	unsigned int  MSG_EX;
 };
 
-int rtl8723au_init_recv_priv(struct rtw_adapter * padapter);
-void rtl8723au_free_recv_priv(struct rtw_adapter * padapter);
+int rtl8723au_init_recv_priv(struct rtw_adapter *padapter);
+void rtl8723au_free_recv_priv(struct rtw_adapter *padapter);
 void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe);
 void update_recvframe_attrib(struct recv_frame *precvframe, struct recv_stat *prxstat);
 void update_recvframe_phyinfo(struct recv_frame *precvframe, struct phy_stat *pphy_info);
diff --git a/drivers/staging/rtl8723au/include/rtw_cmd.h b/drivers/staging/rtl8723au/include/rtw_cmd.h
index 7104410..775dcdc 100644
--- a/drivers/staging/rtl8723au/include/rtw_cmd.h
+++ b/drivers/staging/rtl8723au/include/rtw_cmd.h
@@ -99,7 +99,6 @@
 
 u32 rtw_init_evt_priv23a (struct evt_priv *pevtpriv);
 void rtw_free_evt_priv23a (struct evt_priv *pevtpriv);
-void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv);
 void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
 
 enum rtw_drvextra_cmd_id
@@ -689,10 +688,10 @@
 int rtw_setopmode_cmd23a(struct rtw_adapter *padapter, enum nl80211_iftype ifmode);
 int rtw_setdatarate_cmd(struct rtw_adapter  *padapter, u8 *rateset);
 int rtw_setbasicrate_cmd(struct rtw_adapter  *padapter, u8 *rateset);
-int rtw_setbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 val);
-int rtw_setrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u32 val);
-int rtw_getbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
-int rtw_getrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
+int rtw_setbbreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 val);
+int rtw_setrfreg_cmd(struct rtw_adapter *padapter, u8 offset, u32 val);
+int rtw_getbbreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 *pval);
+int rtw_getrfreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 *pval);
 int rtw_setrfintfs_cmd(struct rtw_adapter  *padapter, u8 mode);
 int rtw_setrttbl_cmd(struct rtw_adapter  *padapter, struct setratable_parm *prate_table);
 int rtw_getrttbl_cmd(struct rtw_adapter  *padapter, struct getratable_rsp *pval);
@@ -713,7 +712,6 @@
 int rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter);
 #endif
 
-int rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue);
 int rtw_set_chplan_cmd(struct rtw_adapter*padapter, u8 chplan, u8 enqueue);
 int rtw_led_blink_cmd(struct rtw_adapter*padapter, struct led_8723a *pLed);
 int rtw_set_csa_cmd(struct rtw_adapter*padapter, u8 new_ch_no);
diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
index 51dba1f..ffb37b2 100644
--- a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
@@ -509,7 +509,7 @@
 			  struct ieee80211_mgmt *mgmt, u32 packet_len);
 void update_IOT_info23a(struct rtw_adapter *padapter);
 void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap);
-void update_wireless_mode23a(struct rtw_adapter * padapter);
+void update_wireless_mode23a(struct rtw_adapter *padapter);
 void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 modulation);
 void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id);
 int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie,
diff --git a/drivers/staging/rtl8723au/include/wifi.h b/drivers/staging/rtl8723au/include/wifi.h
index fd3da3b..25d573c 100644
--- a/drivers/staging/rtl8723au/include/wifi.h
+++ b/drivers/staging/rtl8723au/include/wifi.h
@@ -26,9 +26,9 @@
 ------------------------------------------------------------------------------*/
 
 struct AC_param {
-	unsigned char		ACI_AIFSN;
-	unsigned char		CW;
-	unsigned short	TXOP_limit;
+	u8			ACI_AIFSN;
+	u8			CW;
+	__le16			TXOP_limit;
 }  __packed;
 
 struct WMM_para_element {
@@ -38,10 +38,10 @@
 }  __packed;
 
 struct ADDBA_request {
-	unsigned char		dialog_token;
-	unsigned short	BA_para_set;
-	unsigned short	BA_timeout_value;
-	unsigned short	BA_starting_seqctrl;
+	u8		dialog_token;
+	__le16		BA_para_set;
+	__le16		BA_timeout_value;
+	__le16		BA_starting_seqctrl;
 }  __packed;
 
 
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index c5800ae..537bd82 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -1468,9 +1468,8 @@
 		return 0;
 	}
 
-	if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) {
+	if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
 		psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
-	}
 
 /*
 	if (wpa_version & NL80211_WPA_VERSION_2)
diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c
index 9966d16..1b23eb1 100644
--- a/drivers/staging/rtl8723au/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c
@@ -91,7 +91,7 @@
 /*  0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */
 static int rtw_bt_sco = 3;
 /*  0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
-static int rtw_bt_ampdu = 1 ;
+static int rtw_bt_ampdu = 1;
 #endif
 
 /*  0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c
index 373a617..05755b8 100644
--- a/drivers/staging/rtl8723au/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c
@@ -80,11 +80,9 @@
 	struct usb_config_descriptor *pconf_desc;
 	struct usb_host_interface *phost_iface;
 	struct usb_interface_descriptor *piface_desc;
-	struct usb_host_endpoint *phost_endp;
 	struct usb_endpoint_descriptor *pendp_desc;
-	struct usb_device		 *pusbd;
-	int	i;
-	int	status = _FAIL;
+	struct usb_device *pusbd;
+	int i, status = _FAIL;
 
 	pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL);
 	if (!pdvobjpriv)
@@ -114,42 +112,38 @@
 	pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
 
 	for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
-		phost_endp = phost_iface->endpoint + i;
-		if (phost_endp) {
-			pendp_desc = &phost_endp->desc;
+		pendp_desc = &phost_iface->endpoint[i].desc;
 
-			DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i);
-			DBG_8723A("bLength =%x\n", pendp_desc->bLength);
-			DBG_8723A("bDescriptorType =%x\n",
-				  pendp_desc->bDescriptorType);
-			DBG_8723A("bEndpointAddress =%x\n",
-				  pendp_desc->bEndpointAddress);
-			DBG_8723A("wMaxPacketSize =%d\n",
-				  le16_to_cpu(pendp_desc->wMaxPacketSize));
-			DBG_8723A("bInterval =%x\n", pendp_desc->bInterval);
+		DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i);
+		DBG_8723A("bLength =%x\n", pendp_desc->bLength);
+		DBG_8723A("bDescriptorType =%x\n", pendp_desc->bDescriptorType);
+		DBG_8723A("bEndpointAddress =%x\n",
+			  pendp_desc->bEndpointAddress);
+		DBG_8723A("wMaxPacketSize =%d\n",
+			  le16_to_cpu(pendp_desc->wMaxPacketSize));
+		DBG_8723A("bInterval =%x\n", pendp_desc->bInterval);
 
-			if (usb_endpoint_is_bulk_in(pendp_desc)) {
-				DBG_8723A("usb_endpoint_is_bulk_in = %x\n",
-					  usb_endpoint_num(pendp_desc));
-				pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
-					usb_endpoint_num(pendp_desc);
-				pdvobjpriv->RtNumInPipes++;
-			} else if (usb_endpoint_is_int_in(pendp_desc)) {
-				DBG_8723A("usb_endpoint_is_int_in = %x, Interval = %x\n",
-					  usb_endpoint_num(pendp_desc),
-					  pendp_desc->bInterval);
-				pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
-					usb_endpoint_num(pendp_desc);
-				pdvobjpriv->RtNumInPipes++;
-			} else if (usb_endpoint_is_bulk_out(pendp_desc)) {
-				DBG_8723A("usb_endpoint_is_bulk_out = %x\n",
-					  usb_endpoint_num(pendp_desc));
-				pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] =
-					usb_endpoint_num(pendp_desc);
-				pdvobjpriv->RtNumOutPipes++;
-			}
-			pdvobjpriv->ep_num[i] = usb_endpoint_num(pendp_desc);
+		if (usb_endpoint_is_bulk_in(pendp_desc)) {
+			DBG_8723A("usb_endpoint_is_bulk_in = %x\n",
+				  usb_endpoint_num(pendp_desc));
+			pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+				usb_endpoint_num(pendp_desc);
+			pdvobjpriv->RtNumInPipes++;
+		} else if (usb_endpoint_is_int_in(pendp_desc)) {
+			DBG_8723A("usb_endpoint_is_int_in = %x, Interval = "
+				  "%x\n", usb_endpoint_num(pendp_desc),
+				  pendp_desc->bInterval);
+			pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+				usb_endpoint_num(pendp_desc);
+			pdvobjpriv->RtNumInPipes++;
+		} else if (usb_endpoint_is_bulk_out(pendp_desc)) {
+			DBG_8723A("usb_endpoint_is_bulk_out = %x\n",
+				  usb_endpoint_num(pendp_desc));
+			pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] =
+				usb_endpoint_num(pendp_desc);
+			pdvobjpriv->RtNumOutPipes++;
 		}
+		pdvobjpriv->ep_num[i] = usb_endpoint_num(pendp_desc);
 	}
 	DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n",
 		  pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes,
@@ -273,104 +267,6 @@
 	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n"));
 }
 
-int rtw_hw_suspend23a(struct rtw_adapter *padapter)
-{
-	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
-	struct net_device *pnetdev = padapter->pnetdev;
-	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-
-	if ((!padapter->bup) || (padapter->bDriverStopped) ||
-	    (padapter->bSurpriseRemoved)) {
-		DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n",
-			  padapter->bup, padapter->bDriverStopped,
-			  padapter->bSurpriseRemoved);
-		goto error_exit;
-	}
-
-	if (padapter) { /* system suspend */
-		LeaveAllPowerSaveMode23a(padapter);
-
-		DBG_8723A("==> rtw_hw_suspend23a\n");
-		down(&pwrpriv->lock);
-		pwrpriv->bips_processing = true;
-		/* padapter->net_closed = true; */
-		/* s1. */
-		if (pnetdev) {
-			netif_carrier_off(pnetdev);
-			netif_tx_stop_all_queues(pnetdev);
-		}
-
-		/* s2. */
-		rtw_disassoc_cmd23a(padapter, 500, false);
-
-		/* s2-2.  indicate disconnect to os */
-		/* rtw_indicate_disconnect23a(padapter); */
-		if (check_fwstate(pmlmepriv, _FW_LINKED)) {
-			_clr_fwstate_(pmlmepriv, _FW_LINKED);
-
-			rtw_os_indicate_disconnect23a(padapter);
-
-			/* donnot enqueue cmd */
-			rtw_lps_ctrl_wk_cmd23a(padapter,
-					       LPS_CTRL_DISCONNECT, 0);
-		}
-		/* s2-3. */
-		rtw_free_assoc_resources23a(padapter, 1);
-
-		/* s2-4. */
-		rtw_free_network_queue23a(padapter);
-		rtw_ips_dev_unload23a(padapter);
-		pwrpriv->rf_pwrstate = rf_off;
-		pwrpriv->bips_processing = false;
-		up(&pwrpriv->lock);
-	} else {
-		goto error_exit;
-	}
-	return 0;
-error_exit:
-	DBG_8723A("%s, failed\n", __func__);
-	return -1;
-}
-
-int rtw_hw_resume23a(struct rtw_adapter *padapter)
-{
-	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
-	struct net_device *pnetdev = padapter->pnetdev;
-
-	if (padapter) { /* system resume */
-		DBG_8723A("==> rtw_hw_resume23a\n");
-		down(&pwrpriv->lock);
-		pwrpriv->bips_processing = true;
-		rtw_reset_drv_sw23a(padapter);
-
-		if (pm_netdev_open23a(pnetdev, false)) {
-			up(&pwrpriv->lock);
-			goto error_exit;
-		}
-
-		netif_device_attach(pnetdev);
-		netif_carrier_on(pnetdev);
-
-		if (!rtw_netif_queue_stopped(pnetdev))
-			netif_tx_start_all_queues(pnetdev);
-		else
-			netif_tx_wake_all_queues(pnetdev);
-
-		pwrpriv->bkeepfwalive = false;
-
-		pwrpriv->rf_pwrstate = rf_on;
-		pwrpriv->bips_processing = false;
-
-		up(&pwrpriv->lock);
-	} else {
-		goto error_exit;
-	}
-	return 0;
-error_exit:
-	DBG_8723A("%s, Open net dev failed\n", __func__);
-	return -1;
-}
-
 static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
 {
 	struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index b4612fb..a47a191 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -781,7 +781,7 @@
 	buf[4] = 0;
 	buf[5] = 0;
 
-	retval = ms_write_bytes(chip, PRO_WRITE_REG , 6, NO_WAIT_INT, buf, 6);
+	retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
 
@@ -1291,7 +1291,7 @@
 	for (i = 6; i < MS_EXTRA_SIZE + 6; i++)
 		data[i] = buf[i - 6];
 
-	retval = ms_write_bytes(chip, WRITE_REG , (6+MS_EXTRA_SIZE),
+	retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
 				NO_WAIT_INT, data, 16);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
@@ -1342,7 +1342,7 @@
 	data[4] = 0x20;
 	data[5] = page_num;
 
-	retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6);
+	retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
 	if (retval != STATUS_SUCCESS)
 		TRACE_RET(chip, STATUS_FAIL);
 
@@ -1619,7 +1619,7 @@
 		data[4] = 0x20;
 		data[5] = i;
 
-		retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT,
+		retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
 					data, 6);
 		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
@@ -1695,7 +1695,7 @@
 		}
 
 		retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
-				MS_EXTRA_SIZE, SystemParm, (6+MS_EXTRA_SIZE));
+				MS_EXTRA_SIZE, SystemParm, (6 + MS_EXTRA_SIZE));
 
 		ms_set_err_code(chip, MS_NO_ERROR);
 
@@ -1988,7 +1988,7 @@
 		RTSX_WRITE_REG(chip, PPBUF_BASE2, 0xFF, 0x88);
 		RTSX_WRITE_REG(chip, PPBUF_BASE2 + 1, 0xFF, 0);
 
-		retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG , 1,
+		retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1,
 					NO_WAIT_INT);
 		if (retval != STATUS_SUCCESS)
 			TRACE_RET(chip, STATUS_FAIL);
diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c
index 756a968..dab1995 100644
--- a/drivers/staging/rts5208/rtsx_transport.c
+++ b/drivers/staging/rts5208/rtsx_transport.c
@@ -271,7 +271,7 @@
 
 	/* Wait for TRANS_OK_INT */
 	timeleft = wait_for_completion_interruptible_timeout(
-		&trans_done, timeout * HZ / 1000);
+		&trans_done, msecs_to_jiffies(timeout));
 	if (timeleft <= 0) {
 		dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
 			chip->int_reg);
@@ -431,7 +431,7 @@
 	spin_unlock_irq(&rtsx->reg_lock);
 
 	timeleft = wait_for_completion_interruptible_timeout(
-		&trans_done, timeout * HZ / 1000);
+		&trans_done, msecs_to_jiffies(timeout));
 	if (timeleft <= 0) {
 		dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
 			__func__, __LINE__);
@@ -455,7 +455,7 @@
 		init_completion(&trans_done);
 		spin_unlock_irq(&rtsx->reg_lock);
 		timeleft = wait_for_completion_interruptible_timeout(
-			&trans_done, timeout * HZ / 1000);
+			&trans_done, msecs_to_jiffies(timeout));
 		if (timeleft <= 0) {
 			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
 				__func__, __LINE__);
@@ -575,7 +575,7 @@
 		spin_unlock_irq(&rtsx->reg_lock);
 
 		timeleft = wait_for_completion_interruptible_timeout(
-			&trans_done, timeout * HZ / 1000);
+			&trans_done, msecs_to_jiffies(timeout));
 		if (timeleft <= 0) {
 			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
 				__func__, __LINE__);
@@ -602,7 +602,7 @@
 		init_completion(&trans_done);
 		spin_unlock_irq(&rtsx->reg_lock);
 		timeleft = wait_for_completion_interruptible_timeout(
-			&trans_done, timeout * HZ / 1000);
+			&trans_done, msecs_to_jiffies(timeout));
 		if (timeleft <= 0) {
 			dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
 				__func__, __LINE__);
@@ -688,7 +688,7 @@
 
 	/* Wait for TRANS_OK_INT */
 	timeleft = wait_for_completion_interruptible_timeout(
-		&trans_done, timeout * HZ / 1000);
+		&trans_done, msecs_to_jiffies(timeout));
 	if (timeleft <= 0) {
 		dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
 			__func__, __LINE__);
diff --git a/drivers/staging/skein/skein_block.c b/drivers/staging/skein/skein_block.c
index 66261ab..9bd69ce 100644
--- a/drivers/staging/skein/skein_block.c
+++ b/drivers/staging/skein/skein_block.c
@@ -82,10 +82,7 @@
 } while (0)
 #else
 /* looping version */
-#define R256(p0, p1, p2, p3, ROT, r_num) \
-do { \
-	ROUND256(p0, p1, p2, p3, ROT, r_num); \
-} while (0)
+#define R256(p0, p1, p2, p3, ROT, r_num) ROUND256(p0, p1, p2, p3, ROT, r_num)
 
 #define I256(R) \
 do { \
@@ -174,9 +171,7 @@
 
 #else /* looping version */
 #define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num)                 \
-do {                                                                     \
-	ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num);            \
-} while (0)
+	ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num)             \
 
 #define I512(R)                                                           \
 do {                                                                      \
@@ -263,10 +258,8 @@
 #if SKEIN_UNROLL_1024 == 0
 #define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \
 	      ROT, rn)                                                        \
-do {                                                                          \
 	ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \
-		  pF, ROT, rn);                                               \
-} while (0)
+		  pF, ROT, rn)                                                \
 
 #define I1024(R)                                                          \
 do {                                                                      \
@@ -291,10 +284,8 @@
 #else /* looping version */
 #define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \
 	      ROT, rn)                                                        \
-do {                                                                          \
 	ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \
-		  pF, ROT, rn);                                               \
-} while (0)
+		  pF, ROT, rn)                                                \
 
 #define I1024(R)                                                           \
 do {                                                                       \
diff --git a/drivers/staging/skein/skein_generic.c b/drivers/staging/skein/skein_generic.c
index 85bd7d0..899078f 100644
--- a/drivers/staging/skein/skein_generic.c
+++ b/drivers/staging/skein/skein_generic.c
@@ -191,7 +191,6 @@
 
 	return 0;
 
-		
 unreg512:
 	crypto_unregister_shash(&alg512);
 unreg256:
diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig
new file mode 100644
index 0000000..e2922ae
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Kconfig
@@ -0,0 +1,13 @@
+config FB_SM7XX
+	tristate "Silicon Motion SM7XX framebuffer support"
+	depends on FB && PCI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  Frame buffer driver for the Silicon Motion SM710, SM712, SM721
+	  and SM722 chips.
+
+	  This driver is also available as a module. The module will be
+	  called sm7xxfb. If you want to compile it as a module, say M
+	  here and read <file:Documentation/kbuild/modules.txt>.
diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile
new file mode 100644
index 0000000..48f471c
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o
diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO
new file mode 100644
index 0000000..7cb0b24
--- /dev/null
+++ b/drivers/staging/sm7xxfb/TODO
@@ -0,0 +1,12 @@
+TODO:
+- Dual head support
+- 2D acceleration support
+- use kernel coding style
+- refine the code and remove unused code
+- move it to drivers/video/fbdev/sm7xxfb.c
+
+Please send any patches to
+	Greg Kroah-Hartman <greg@kroah.com>
+	Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+	Teddy Wang <teddy.wang@siliconmotion.com>
+	Sudip Mukherjee <sudip@vectorindia.org>
diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h
new file mode 100644
index 0000000..7cc1896
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xx.h
@@ -0,0 +1,779 @@
+/*
+ * Silicon Motion SM712 frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors:	Ge Wang, gewang@siliconmotion.com
+ *		Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#define NR_PALETTE        256
+
+#define FB_ACCEL_SMI_LYNX 88
+
+#define SCREEN_X_RES      1024
+#define SCREEN_Y_RES      600
+#define SCREEN_BPP        16
+
+/*Assume SM712 graphics chip has 4MB VRAM */
+#define SM712_VIDEOMEMORYSIZE	  0x00400000
+/*Assume SM722 graphics chip has 8MB VRAM */
+#define SM722_VIDEOMEMORYSIZE	  0x00800000
+
+#define dac_reg	(0x3c8)
+#define dac_val	(0x3c9)
+
+extern void __iomem *smtc_regbaseaddress;
+#define smtc_mmiowb(dat, reg)	writeb(dat, smtc_regbaseaddress + reg)
+#define smtc_mmioww(dat, reg)	writew(dat, smtc_regbaseaddress + reg)
+#define smtc_mmiowl(dat, reg)	writel(dat, smtc_regbaseaddress + reg)
+
+#define smtc_mmiorb(reg)	readb(smtc_regbaseaddress + reg)
+#define smtc_mmiorw(reg)	readw(smtc_regbaseaddress + reg)
+#define smtc_mmiorl(reg)	readl(smtc_regbaseaddress + reg)
+
+#define SIZE_SR00_SR04      (0x04 - 0x00 + 1)
+#define SIZE_SR10_SR24      (0x24 - 0x10 + 1)
+#define SIZE_SR30_SR75      (0x75 - 0x30 + 1)
+#define SIZE_SR80_SR93      (0x93 - 0x80 + 1)
+#define SIZE_SRA0_SRAF      (0xAF - 0xA0 + 1)
+#define SIZE_GR00_GR08      (0x08 - 0x00 + 1)
+#define SIZE_AR00_AR14      (0x14 - 0x00 + 1)
+#define SIZE_CR00_CR18      (0x18 - 0x00 + 1)
+#define SIZE_CR30_CR4D      (0x4D - 0x30 + 1)
+#define SIZE_CR90_CRA7      (0xA7 - 0x90 + 1)
+#define SIZE_VPR		(0x6C + 1)
+#define SIZE_DPR		(0x44 + 1)
+
+static inline void smtc_crtcw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3d4);
+	smtc_mmiowb(val, 0x3d5);
+}
+
+static inline unsigned int smtc_crtcr(int reg)
+{
+	smtc_mmiowb(reg, 0x3d4);
+	return smtc_mmiorb(0x3d5);
+}
+
+static inline void smtc_grphw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3ce);
+	smtc_mmiowb(val, 0x3cf);
+}
+
+static inline unsigned int smtc_grphr(int reg)
+{
+	smtc_mmiowb(reg, 0x3ce);
+	return smtc_mmiorb(0x3cf);
+}
+
+static inline void smtc_attrw(int reg, int val)
+{
+	smtc_mmiorb(0x3da);
+	smtc_mmiowb(reg, 0x3c0);
+	smtc_mmiorb(0x3c1);
+	smtc_mmiowb(val, 0x3c0);
+}
+
+static inline void smtc_seqw(int reg, int val)
+{
+	smtc_mmiowb(reg, 0x3c4);
+	smtc_mmiowb(val, 0x3c5);
+}
+
+static inline unsigned int smtc_seqr(int reg)
+{
+	smtc_mmiowb(reg, 0x3c4);
+	return smtc_mmiorb(0x3c5);
+}
+
+/* The next structure holds all information relevant for a specific video mode.
+ */
+
+struct ModeInit {
+	int mmsizex;
+	int mmsizey;
+	int bpp;
+	int hz;
+	unsigned char init_misc;
+	unsigned char init_sr00_sr04[SIZE_SR00_SR04];
+	unsigned char init_sr10_sr24[SIZE_SR10_SR24];
+	unsigned char init_sr30_sr75[SIZE_SR30_SR75];
+	unsigned char init_sr80_sr93[SIZE_SR80_SR93];
+	unsigned char init_sra0_sraf[SIZE_SRA0_SRAF];
+	unsigned char init_gr00_gr08[SIZE_GR00_GR08];
+	unsigned char init_ar00_ar14[SIZE_AR00_AR14];
+	unsigned char init_cr00_cr18[SIZE_CR00_CR18];
+	unsigned char init_cr30_cr4d[SIZE_CR30_CR4D];
+	unsigned char init_cr90_cra7[SIZE_CR90_CRA7];
+};
+
+/**********************************************************************
+			 SM712 Mode table.
+ **********************************************************************/
+struct ModeInit vgamode[] = {
+	{
+	 /*  mode#0: 640 x 480  16Bpp  60Hz */
+	 640, 480, 16, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+	{
+	 /*  mode#1: 640 x 480  24Bpp  60Hz */
+	 640, 480, 24, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+	{
+	 /*  mode#0: 640 x 480  32Bpp  60Hz */
+	 640, 480, 32, 60,
+	 /*  Init_MISC */
+	 0xE3,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+	  0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+	  0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+	  0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+	  0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+	  0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+	  0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+	  0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+	  0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+	  },
+	 },
+
+	{			/*  mode#2: 800 x 600  16Bpp  60Hz */
+	 800, 600, 16, 60,
+	 /*  Init_MISC */
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	{			/*  mode#3: 800 x 600  24Bpp  60Hz */
+	 800, 600, 24, 60,
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
+	  0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
+	  0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	{			/*  mode#7: 800 x 600  32Bpp  60Hz */
+	 800, 600, 32, 60,
+	 /*  Init_MISC */
+	 0x2B,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+	  0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+	  0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+	  0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+	  0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+	  0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+	  0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+	  0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+	  0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+	  0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+	  0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+	  },
+	 },
+	/* We use 1024x768 table to light 1024x600 panel for lemote */
+	{			/*  mode#4: 1024 x 600  16Bpp  60Hz  */
+	 1024, 600, 16, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x00, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
+	  0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x00, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
+	  0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
+	  0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
+	  0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
+	  0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#5: 1024 x 768  24Bpp  60Hz */
+	 1024, 768, 24, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x30, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#4: 1024 x 768  32Bpp  60Hz */
+	 1024, 768, 32, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+	  0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+	{			/*  mode#6: 320 x 240  16Bpp  60Hz */
+	 320, 240, 16, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+
+	{			/*  mode#8: 320 x 240  32Bpp  60Hz */
+	 320, 240, 32, 60,
+	 /*  Init_MISC */
+	 0xEB,
+	 {			/*  Init_SR0_SR4 */
+	  0x03, 0x01, 0x0F, 0x03, 0x0E,
+	  },
+	 {			/*  Init_SR10_SR24 */
+	  0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+	  0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xC4, 0x32, 0x02, 0x01, 0x01,
+	  },
+	 {			/*  Init_SR30_SR75 */
+	  0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+	  0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+	  0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+	  0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+	  0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+	  0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+	  0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+	  0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+	  0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+	  },
+	 {			/*  Init_SR80_SR93 */
+	  0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+	  0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+	  0x00, 0x00, 0x00, 0x00,
+	  },
+	 {			/*  Init_SRA0_SRAF */
+	  0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+	  0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+	  },
+	 {			/*  Init_GR00_GR08 */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+	  0xFF,
+	  },
+	 {			/*  Init_AR00_AR14 */
+	  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	  0x41, 0x00, 0x0F, 0x00, 0x00,
+	  },
+	 {			/*  Init_CR00_CR18 */
+	  0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+	  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+	  0xFF,
+	  },
+	 {			/*  Init_CR30_CR4D */
+	  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+	  0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+	  0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+	  0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+	  },
+	 {			/*  Init_CR90_CRA7 */
+	  0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+	  0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+	  0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+	  },
+	 },
+};
+
+#define numvgamodes		ARRAY_SIZE(vgamode)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
new file mode 100644
index 0000000..ebd9536
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -0,0 +1,1024 @@
+/*
+ * Silicon Motion SM7XX frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors:  Ge Wang, gewang@siliconmotion.com
+ *	     Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author:   Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * Copyright (C) 2011 Igalia, S.L.
+ * Author:   Javier M. Mellid <jmunhoz@igalia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
+ */
+
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include "sm7xx.h"
+
+/*
+* Private structure
+*/
+struct smtcfb_info {
+	struct pci_dev *pdev;
+	struct fb_info fb;
+	u16 chip_id;
+	u8  chip_rev_id;
+
+	void __iomem *lfb;	/* linear frame buffer */
+	void __iomem *dp_regs;	/* drawing processor control regs */
+	void __iomem *vp_regs;	/* video processor control regs */
+	void __iomem *cp_regs;	/* capture processor control regs */
+	void __iomem *mmio;	/* memory map IO port */
+
+	u_int width;
+	u_int height;
+	u_int hz;
+
+	u32 colreg[17];
+};
+
+void __iomem *smtc_regbaseaddress;	/* Memory Map IO starting address */
+
+static struct fb_var_screeninfo smtcfb_var = {
+	.xres           = 1024,
+	.yres           = 600,
+	.xres_virtual   = 1024,
+	.yres_virtual   = 600,
+	.bits_per_pixel = 16,
+	.red            = {16, 8, 0},
+	.green          = {8, 8, 0},
+	.blue           = {0, 8, 0},
+	.activate       = FB_ACTIVATE_NOW,
+	.height         = -1,
+	.width          = -1,
+	.vmode          = FB_VMODE_NONINTERLACED,
+	.nonstd         = 0,
+	.accel_flags    = FB_ACCELF_TEXT,
+};
+
+static struct fb_fix_screeninfo smtcfb_fix = {
+	.id             = "smXXXfb",
+	.type           = FB_TYPE_PACKED_PIXELS,
+	.visual         = FB_VISUAL_TRUECOLOR,
+	.line_length    = 800 * 3,
+	.accel          = FB_ACCEL_SMI_LYNX,
+	.type_aux       = 0,
+	.xpanstep       = 0,
+	.ypanstep       = 0,
+	.ywrapstep      = 0,
+};
+
+struct vesa_mode {
+	char index[6];
+	u16  lfb_width;
+	u16  lfb_height;
+	u16  lfb_depth;
+};
+
+static struct vesa_mode vesa_mode_table[] = {
+	{"0x301", 640,  480,  8},
+	{"0x303", 800,  600,  8},
+	{"0x305", 1024, 768,  8},
+	{"0x307", 1280, 1024, 8},
+
+	{"0x311", 640,  480,  16},
+	{"0x314", 800,  600,  16},
+	{"0x317", 1024, 768,  16},
+	{"0x31A", 1280, 1024, 16},
+
+	{"0x312", 640,  480,  24},
+	{"0x315", 800,  600,  24},
+	{"0x318", 1024, 768,  24},
+	{"0x31B", 1280, 1024, 24},
+};
+
+static struct screen_info smtc_scr_info;
+
+/* process command line options, get vga parameter */
+static int __init sm7xx_vga_setup(char *options)
+{
+	int i;
+
+	if (!options || !*options)
+		return -EINVAL;
+
+	smtc_scr_info.lfb_width = 0;
+	smtc_scr_info.lfb_height = 0;
+	smtc_scr_info.lfb_depth = 0;
+
+	pr_debug("sm7xx_vga_setup = %s\n", options);
+
+	for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
+		if (strstr(options, vesa_mode_table[i].index)) {
+			smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
+			smtc_scr_info.lfb_height =
+						vesa_mode_table[i].lfb_height;
+			smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+__setup("vga=", sm7xx_vga_setup);
+
+static void sm712_setpalette(int regno, unsigned red, unsigned green,
+			     unsigned blue, struct fb_info *info)
+{
+	/* set bit 5:4 = 01 (write LCD RAM only) */
+	smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
+
+	smtc_mmiowb(regno, dac_reg);
+	smtc_mmiowb(red >> 10, dac_val);
+	smtc_mmiowb(green >> 10, dac_val);
+	smtc_mmiowb(blue >> 10, dac_val);
+}
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+ */
+
+static inline unsigned int chan_to_field(unsigned int chan,
+					 struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int smtc_blank(int blank_mode, struct fb_info *info)
+{
+	/* clear DPMS setting */
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		/* Screen On: HSync: On, VSync : On */
+		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
+		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+		break;
+	case FB_BLANK_NORMAL:
+		/* Screen Off: HSync: On, VSync : On   Soft blank */
+		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		/* Screen On: HSync: On, VSync : Off */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		/* Screen On: HSync: Off, VSync : On */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	case FB_BLANK_POWERDOWN:
+		/* Screen On: HSync: Off, VSync : Off */
+		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+		smtc_seqw(0x6a, 0x0c);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
+		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned trans, struct fb_info *info)
+{
+	struct smtcfb_info *sfb;
+	u32 val;
+
+	sfb = info->par;
+
+	if (regno > 255)
+		return 1;
+
+	switch (sfb->fb.fix.visual) {
+	case FB_VISUAL_DIRECTCOLOR:
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
+		 */
+		if (regno < 16) {
+			if (sfb->fb.var.bits_per_pixel == 16) {
+				u32 *pal = sfb->fb.pseudo_palette;
+
+				val = chan_to_field(red, &sfb->fb.var.red);
+				val |= chan_to_field(green, &sfb->fb.var.green);
+				val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+				pal[regno] =
+				    ((red & 0xf800) >> 8) |
+				    ((green & 0xe000) >> 13) |
+				    ((green & 0x1c00) << 3) |
+				    ((blue & 0xf800) >> 3);
+#else
+				pal[regno] = val;
+#endif
+			} else {
+				u32 *pal = sfb->fb.pseudo_palette;
+
+				val = chan_to_field(red, &sfb->fb.var.red);
+				val |= chan_to_field(green, &sfb->fb.var.green);
+				val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+				val =
+				    (val & 0xff00ff00 >> 8) |
+				    (val & 0x00ff00ff << 8);
+#endif
+				pal[regno] = val;
+			}
+		}
+		break;
+
+	case FB_VISUAL_PSEUDOCOLOR:
+		/* color depth 8 bit */
+		sm712_setpalette(regno, red, green, blue, info);
+		break;
+
+	default:
+		return 1;	/* unknown type */
+	}
+
+	return 0;
+}
+
+#ifdef __BIG_ENDIAN
+static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
+				count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+
+	u32 *buffer, *dst;
+	u32 __iomem *src;
+	int c, i, cnt = 0, err = 0;
+	unsigned long total_size;
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p >= total_size)
+		return 0;
+
+	if (count >= total_size)
+		count = total_size;
+
+	if (count + p > total_size)
+		count = total_size - p;
+
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	src = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		dst = buffer;
+		for (i = c >> 2; i--;) {
+			*dst = fb_readl(src++);
+			*dst =
+			    (*dst & 0xff00ff00 >> 8) |
+			    (*dst & 0x00ff00ff << 8);
+			dst++;
+		}
+		if (c & 3) {
+			u8 *dst8 = (u8 *)dst;
+			u8 __iomem *src8 = (u8 __iomem *)src;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					*dst8++ = fb_readb(++src8);
+				} else {
+					*dst8++ = fb_readb(--src8);
+					src8 += 2;
+				}
+			}
+			src = (u32 __iomem *)src8;
+		}
+
+		if (copy_to_user(buf, buffer, c)) {
+			err = -EFAULT;
+			break;
+		}
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+
+	kfree(buffer);
+
+	return (err) ? err : cnt;
+}
+
+static ssize_t
+smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
+	     loff_t *ppos)
+{
+	unsigned long p = *ppos;
+
+	u32 *buffer, *src;
+	u32 __iomem *dst;
+	int c, i, cnt = 0, err = 0;
+	unsigned long total_size;
+
+	if (!info || !info->screen_base)
+		return -ENODEV;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EFBIG;
+
+	if (count > total_size) {
+		err = -EFBIG;
+		count = total_size;
+	}
+
+	if (count + p > total_size) {
+		if (!err)
+			err = -ENOSPC;
+
+		count = total_size - p;
+	}
+
+	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	dst = (u32 __iomem *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	while (count) {
+		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+		src = buffer;
+
+		if (copy_from_user(src, buf, c)) {
+			err = -EFAULT;
+			break;
+		}
+
+		for (i = c >> 2; i--;) {
+			fb_writel((*src & 0xff00ff00 >> 8) |
+				  (*src & 0x00ff00ff << 8), dst++);
+			src++;
+		}
+		if (c & 3) {
+			u8 *src8 = (u8 *)src;
+			u8 __iomem *dst8 = (u8 __iomem *)dst;
+
+			for (i = c & 3; i--;) {
+				if (i & 1) {
+					fb_writeb(*src8++, ++dst8);
+				} else {
+					fb_writeb(*src8++, --dst8);
+					dst8 += 2;
+				}
+			}
+			dst = (u32 __iomem *)dst8;
+		}
+
+		*ppos += c;
+		buf += c;
+		cnt += c;
+		count -= c;
+	}
+
+	kfree(buffer);
+
+	return (cnt) ? cnt : err;
+}
+#endif	/* ! __BIG_ENDIAN */
+
+static void sm7xx_set_timing(struct smtcfb_info *sfb)
+{
+	int i = 0, j = 0;
+	u32 m_nscreenstride;
+
+	dev_dbg(&sfb->pdev->dev,
+		"sfb->width=%d sfb->height=%d sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+		sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
+
+	for (j = 0; j < numvgamodes; j++) {
+		if (vgamode[j].mmsizex == sfb->width &&
+		    vgamode[j].mmsizey == sfb->height &&
+		    vgamode[j].bpp == sfb->fb.var.bits_per_pixel &&
+		    vgamode[j].hz == sfb->hz) {
+			dev_dbg(&sfb->pdev->dev,
+				"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
+				vgamode[j].mmsizex, vgamode[j].mmsizey,
+				vgamode[j].bpp, vgamode[j].hz);
+
+			dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
+
+			smtc_mmiowb(0x0, 0x3c6);
+
+			smtc_seqw(0, 0x1);
+
+			smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
+
+			/* init SEQ register SR00 - SR04 */
+			for (i = 0; i < SIZE_SR00_SR04; i++)
+				smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
+
+			/* init SEQ register SR10 - SR24 */
+			for (i = 0; i < SIZE_SR10_SR24; i++)
+				smtc_seqw(i + 0x10,
+					  vgamode[j].init_sr10_sr24[i]);
+
+			/* init SEQ register SR30 - SR75 */
+			for (i = 0; i < SIZE_SR30_SR75; i++)
+				if ((i + 0x30) != 0x62 &&
+				    (i + 0x30) != 0x6a &&
+				    (i + 0x30) != 0x6b)
+					smtc_seqw(i + 0x30,
+						  vgamode[j].init_sr30_sr75[i]);
+
+			/* init SEQ register SR80 - SR93 */
+			for (i = 0; i < SIZE_SR80_SR93; i++)
+				smtc_seqw(i + 0x80,
+					  vgamode[j].init_sr80_sr93[i]);
+
+			/* init SEQ register SRA0 - SRAF */
+			for (i = 0; i < SIZE_SRA0_SRAF; i++)
+				smtc_seqw(i + 0xa0,
+					  vgamode[j].init_sra0_sraf[i]);
+
+			/* init Graphic register GR00 - GR08 */
+			for (i = 0; i < SIZE_GR00_GR08; i++)
+				smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
+
+			/* init Attribute register AR00 - AR14 */
+			for (i = 0; i < SIZE_AR00_AR14; i++)
+				smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
+
+			/* init CRTC register CR00 - CR18 */
+			for (i = 0; i < SIZE_CR00_CR18; i++)
+				smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
+
+			/* init CRTC register CR30 - CR4D */
+			for (i = 0; i < SIZE_CR30_CR4D; i++)
+				smtc_crtcw(i + 0x30,
+					   vgamode[j].init_cr30_cr4d[i]);
+
+			/* init CRTC register CR90 - CRA7 */
+			for (i = 0; i < SIZE_CR90_CRA7; i++)
+				smtc_crtcw(i + 0x90,
+					   vgamode[j].init_cr90_cra7[i]);
+		}
+	}
+	smtc_mmiowb(0x67, 0x3c2);
+
+	/* set VPR registers */
+	writel(0x0, sfb->vp_regs + 0x0C);
+	writel(0x0, sfb->vp_regs + 0x40);
+
+	/* set data width */
+	m_nscreenstride =
+		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
+	switch (sfb->fb.var.bits_per_pixel) {
+	case 8:
+		writel(0x0, sfb->vp_regs + 0x0);
+		break;
+	case 16:
+		writel(0x00020000, sfb->vp_regs + 0x0);
+		break;
+	case 24:
+		writel(0x00040000, sfb->vp_regs + 0x0);
+		break;
+	case 32:
+		writel(0x00030000, sfb->vp_regs + 0x0);
+		break;
+	}
+	writel((u32) (((m_nscreenstride + 2) << 16) | m_nscreenstride),
+	       sfb->vp_regs + 0x10);
+}
+
+static void smtc_set_timing(struct smtcfb_info *sfb)
+{
+	switch (sfb->chip_id) {
+	case 0x710:
+	case 0x712:
+	case 0x720:
+		sm7xx_set_timing(sfb);
+		break;
+	}
+}
+
+static void smtcfb_setmode(struct smtcfb_info *sfb)
+{
+	switch (sfb->fb.var.bits_per_pixel) {
+	case 32:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 4;
+		sfb->fb.var.red.length   = 8;
+		sfb->fb.var.green.length = 8;
+		sfb->fb.var.blue.length  = 8;
+		sfb->fb.var.red.offset   = 16;
+		sfb->fb.var.green.offset = 8;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 24:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 3;
+		sfb->fb.var.red.length   = 8;
+		sfb->fb.var.green.length = 8;
+		sfb->fb.var.blue.length  = 8;
+		sfb->fb.var.red.offset   = 16;
+		sfb->fb.var.green.offset = 8;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 8:
+		sfb->fb.fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres;
+		sfb->fb.var.red.length   = 3;
+		sfb->fb.var.green.length = 3;
+		sfb->fb.var.blue.length  = 2;
+		sfb->fb.var.red.offset   = 5;
+		sfb->fb.var.green.offset = 2;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	case 16:
+	default:
+		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
+		sfb->fb.fix.line_length  = sfb->fb.var.xres * 2;
+		sfb->fb.var.red.length   = 5;
+		sfb->fb.var.green.length = 6;
+		sfb->fb.var.blue.length  = 5;
+		sfb->fb.var.red.offset   = 11;
+		sfb->fb.var.green.offset = 5;
+		sfb->fb.var.blue.offset  = 0;
+		break;
+	}
+
+	sfb->width  = sfb->fb.var.xres;
+	sfb->height = sfb->fb.var.yres;
+	sfb->hz = 60;
+	smtc_set_timing(sfb);
+}
+
+static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* sanity checks */
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	/* set valid default bpp */
+	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
+	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
+		var->bits_per_pixel = 16;
+
+	return 0;
+}
+
+static int smtc_set_par(struct fb_info *info)
+{
+	smtcfb_setmode(info->par);
+
+	return 0;
+}
+
+static struct fb_ops smtcfb_ops = {
+	.owner        = THIS_MODULE,
+	.fb_check_var = smtc_check_var,
+	.fb_set_par   = smtc_set_par,
+	.fb_setcolreg = smtc_setcolreg,
+	.fb_blank     = smtc_blank,
+	.fb_fillrect  = cfb_fillrect,
+	.fb_imageblit = cfb_imageblit,
+	.fb_copyarea  = cfb_copyarea,
+#ifdef __BIG_ENDIAN
+	.fb_read      = smtcfb_read,
+	.fb_write     = smtcfb_write,
+#endif
+};
+
+/*
+ * alloc struct smtcfb_info and assign default values
+ */
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
+{
+	struct smtcfb_info *sfb;
+
+	sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
+
+	if (!sfb)
+		return NULL;
+
+	sfb->pdev = pdev;
+
+	sfb->fb.flags          = FBINFO_FLAG_DEFAULT;
+	sfb->fb.fbops          = &smtcfb_ops;
+	sfb->fb.fix            = smtcfb_fix;
+	sfb->fb.var            = smtcfb_var;
+	sfb->fb.pseudo_palette = sfb->colreg;
+	sfb->fb.par            = sfb;
+
+	return sfb;
+}
+
+/*
+ * free struct smtcfb_info
+ */
+static void smtc_free_fb_info(struct smtcfb_info *sfb)
+{
+	kfree(sfb);
+}
+
+/*
+ * Unmap in the memory mapped IO registers
+ */
+
+static void smtc_unmap_mmio(struct smtcfb_info *sfb)
+{
+	if (sfb && smtc_regbaseaddress)
+		smtc_regbaseaddress = NULL;
+}
+
+/*
+ * Map in the screen memory
+ */
+
+static int smtc_map_smem(struct smtcfb_info *sfb,
+			 struct pci_dev *pdev, u_long smem_len)
+{
+	sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
+
+#ifdef __BIG_ENDIAN
+	if (sfb->fb.var.bits_per_pixel == 32)
+		sfb->fb.fix.smem_start += 0x800000;
+#endif
+
+	sfb->fb.fix.smem_len = smem_len;
+
+	sfb->fb.screen_base = sfb->lfb;
+
+	if (!sfb->fb.screen_base) {
+		dev_err(&pdev->dev,
+			"%s: unable to map screen memory\n", sfb->fb.fix.id);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ * Unmap in the screen memory
+ *
+ */
+static void smtc_unmap_smem(struct smtcfb_info *sfb)
+{
+	if (sfb && sfb->fb.screen_base) {
+		iounmap(sfb->fb.screen_base);
+		sfb->fb.screen_base = NULL;
+	}
+}
+
+/*
+ * We need to wake up the device and make sure its in linear memory mode.
+ */
+static inline void sm7xx_init_hw(void)
+{
+	outb_p(0x18, 0x3c4);
+	outb_p(0x11, 0x3c5);
+}
+
+static int smtcfb_pci_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *ent)
+{
+	struct smtcfb_info *sfb;
+	u_long smem_size = 0x00800000;	/* default 8MB */
+	int err;
+	unsigned long mmio_base;
+
+	dev_info(&pdev->dev, "Silicon Motion display driver.");
+
+	err = pci_enable_device(pdev);	/* enable SMTC chip */
+	if (err)
+		return err;
+
+	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
+
+	sfb = smtc_alloc_fb_info(pdev);
+
+	if (!sfb) {
+		err = -ENOMEM;
+		goto failed_free;
+	}
+
+	sfb->chip_id = ent->device;
+
+	pci_set_drvdata(pdev, sfb);
+
+	sm7xx_init_hw();
+
+	/* get mode parameter from smtc_scr_info */
+	if (smtc_scr_info.lfb_width != 0) {
+		sfb->fb.var.xres = smtc_scr_info.lfb_width;
+		sfb->fb.var.yres = smtc_scr_info.lfb_height;
+		sfb->fb.var.bits_per_pixel = smtc_scr_info.lfb_depth;
+	} else {
+		/* default resolution 1024x600 16bit mode */
+		sfb->fb.var.xres = SCREEN_X_RES;
+		sfb->fb.var.yres = SCREEN_Y_RES;
+		sfb->fb.var.bits_per_pixel = SCREEN_BPP;
+	}
+
+#ifdef __BIG_ENDIAN
+	if (sfb->fb.var.bits_per_pixel == 24)
+		sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
+#endif
+	/* Map address and memory detection */
+	mmio_base = pci_resource_start(pdev, 0);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
+
+	switch (sfb->chip_id) {
+	case 0x710:
+	case 0x712:
+		sfb->fb.fix.mmio_start = mmio_base + 0x00400000;
+		sfb->fb.fix.mmio_len = 0x00400000;
+		smem_size = SM712_VIDEOMEMORYSIZE;
+#ifdef __BIG_ENDIAN
+		sfb->lfb = ioremap(mmio_base, 0x00c00000);
+#else
+		sfb->lfb = ioremap(mmio_base, 0x00800000);
+#endif
+		sfb->mmio = (smtc_regbaseaddress =
+		    sfb->lfb + 0x00700000);
+		sfb->dp_regs = sfb->lfb + 0x00408000;
+		sfb->vp_regs = sfb->lfb + 0x0040c000;
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32) {
+			sfb->lfb += 0x800000;
+			dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
+		}
+#endif
+		if (!smtc_regbaseaddress) {
+			dev_err(&pdev->dev,
+				"%s: unable to map memory mapped IO!",
+				sfb->fb.fix.id);
+			err = -ENOMEM;
+			goto failed_fb;
+		}
+
+		/* set MCLK = 14.31818 * (0x16 / 0x2) */
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x62, 0x3e);
+		/* enable PCI burst */
+		smtc_seqw(0x17, 0x20);
+		/* enable word swap */
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32)
+			smtc_seqw(0x17, 0x30);
+#endif
+		break;
+	case 0x720:
+		sfb->fb.fix.mmio_start = mmio_base;
+		sfb->fb.fix.mmio_len = 0x00200000;
+		smem_size = SM722_VIDEOMEMORYSIZE;
+		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
+		sfb->lfb = sfb->dp_regs + 0x00200000;
+		sfb->mmio = (smtc_regbaseaddress =
+		    sfb->dp_regs + 0x000c0000);
+		sfb->vp_regs = sfb->dp_regs + 0x800;
+
+		smtc_seqw(0x62, 0xff);
+		smtc_seqw(0x6a, 0x0d);
+		smtc_seqw(0x6b, 0x02);
+		break;
+	default:
+		dev_err(&pdev->dev,
+			"No valid Silicon Motion display chip was detected!");
+
+		goto failed_fb;
+	}
+
+	/* can support 32 bpp */
+	if (15 == sfb->fb.var.bits_per_pixel)
+		sfb->fb.var.bits_per_pixel = 16;
+
+	sfb->fb.var.xres_virtual = sfb->fb.var.xres;
+	sfb->fb.var.yres_virtual = sfb->fb.var.yres;
+	err = smtc_map_smem(sfb, pdev, smem_size);
+	if (err)
+		goto failed;
+
+	smtcfb_setmode(sfb);
+
+	err = register_framebuffer(&sfb->fb);
+	if (err < 0)
+		goto failed;
+
+	dev_info(&pdev->dev,
+		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+		 sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres,
+		 sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
+
+	return 0;
+
+failed:
+	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
+
+	smtc_unmap_smem(sfb);
+	smtc_unmap_mmio(sfb);
+failed_fb:
+	smtc_free_fb_info(sfb);
+
+failed_free:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+/*
+ * 0x710 (LynxEM)
+ * 0x712 (LynxEM+)
+ * 0x720 (Lynx3DM, Lynx3DM+)
+ */
+static const struct pci_device_id smtcfb_pci_table[] = {
+	{ PCI_DEVICE(0x126f, 0x710), },
+	{ PCI_DEVICE(0x126f, 0x712), },
+	{ PCI_DEVICE(0x126f, 0x720), },
+	{0,}
+};
+
+static void smtcfb_pci_remove(struct pci_dev *pdev)
+{
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+	smtc_unmap_smem(sfb);
+	smtc_unmap_mmio(sfb);
+	unregister_framebuffer(&sfb->fb);
+	smtc_free_fb_info(sfb);
+}
+
+#ifdef CONFIG_PM
+static int smtcfb_pci_suspend(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+
+	/* set the hw in sleep mode use external clock and self memory refresh
+	 * so that we can turn off internal PLLs later on
+	 */
+	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
+	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
+
+	console_lock();
+	fb_set_suspend(&sfb->fb, 1);
+	console_unlock();
+
+	/* additionally turn off all function blocks including internal PLLs */
+	smtc_seqw(0x21, 0xff);
+
+	return 0;
+}
+
+static int smtcfb_pci_resume(struct device *device)
+{
+	struct pci_dev *pdev = to_pci_dev(device);
+	struct smtcfb_info *sfb;
+
+	sfb = pci_get_drvdata(pdev);
+
+	/* reinit hardware */
+	sm7xx_init_hw();
+	switch (sfb->chip_id) {
+	case 0x710:
+	case 0x712:
+		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
+		smtc_seqw(0x6a, 0x16);
+		smtc_seqw(0x6b, 0x02);
+		smtc_seqw(0x62, 0x3e);
+		/* enable PCI burst */
+		smtc_seqw(0x17, 0x20);
+#ifdef __BIG_ENDIAN
+		if (sfb->fb.var.bits_per_pixel == 32)
+			smtc_seqw(0x17, 0x30);
+#endif
+		break;
+	case 0x720:
+		smtc_seqw(0x62, 0xff);
+		smtc_seqw(0x6a, 0x0d);
+		smtc_seqw(0x6b, 0x02);
+		break;
+	}
+
+	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
+	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
+
+	smtcfb_setmode(sfb);
+
+	console_lock();
+	fb_set_suspend(&sfb->fb, 0);
+	console_unlock();
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
+#define SM7XX_PM_OPS (&sm7xx_pm_ops)
+
+#else  /* !CONFIG_PM */
+
+#define SM7XX_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
+
+static struct pci_driver smtcfb_driver = {
+	.name = "smtcfb",
+	.id_table = smtcfb_pci_table,
+	.probe = smtcfb_pci_probe,
+	.remove = smtcfb_pci_remove,
+	.driver.pm  = SM7XX_PM_OPS,
+};
+
+module_pci_driver(smtcfb_driver);
+
+MODULE_AUTHOR("Siliconmotion ");
+MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/speakup/i18n.h b/drivers/staging/speakup/i18n.h
index 16a0871..326d086 100644
--- a/drivers/staging/speakup/i18n.h
+++ b/drivers/staging/speakup/i18n.h
@@ -3,7 +3,7 @@
 /* Internationalization declarations */
 
 enum msg_index_t {
-	MSG_FIRST_INDEX ,
+	MSG_FIRST_INDEX,
 	MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX,
 	MSG_BLANK = MSG_ANNOUNCEMENTS_START,
 	MSG_IAM_ALIVE,
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
index b12c76d..3708bc1 100644
--- a/drivers/staging/speakup/kobjects.c
+++ b/drivers/staging/speakup/kobjects.c
@@ -566,7 +566,7 @@
 				if (ch >= ' ' && ch < '~')
 					*cp1++ = ch;
 				else
-					cp1 += sprintf(cp1, "\\""x%02x", ch);
+					cp1 += sprintf(cp1, "\\x%02x", ch);
 			}
 			*cp1++ = '"';
 			*cp1++ = '\n';
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
index 507fc9a..a031570 100644
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -157,7 +157,7 @@
 		pasted += count;
 	}
 	remove_wait_queue(&vc->paste_wait, &wait);
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 
 	tty_buffer_unlock_exclusive(&vc->port);
 	tty_ldisc_deref(ld);
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
index f3aa423..01eddab 100644
--- a/drivers/staging/speakup/synth.c
+++ b/drivers/staging/speakup/synth.c
@@ -30,9 +30,9 @@
 	 * must be taken at each kernel->speakup transition and released at
 	 * each corresponding speakup->kernel transition.
 	 *
-	 * The progression thread only interferes with the speakup machinery through
-	 * the synth buffer, so only needs to take the lock while tinkering with
-	 * the buffer.
+	 * The progression thread only interferes with the speakup machinery
+	 * through the synth buffer, so only needs to take the lock
+	 * while tinkering with the buffer.
 	 *
 	 * We use spin_lock/trylock_irqsave and spin_unlock_irqrestore with this
 	 * spinlock because speakup needs to disable the keyboard IRQ.
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
index ac080c9..19fcb34 100644
--- a/drivers/staging/unisys/Kconfig
+++ b/drivers/staging/unisys/Kconfig
@@ -12,7 +12,6 @@
 source "drivers/staging/unisys/visorutil/Kconfig"
 source "drivers/staging/unisys/visorchannel/Kconfig"
 source "drivers/staging/unisys/visorchipset/Kconfig"
-source "drivers/staging/unisys/channels/Kconfig"
 source "drivers/staging/unisys/uislib/Kconfig"
 source "drivers/staging/unisys/virtpci/Kconfig"
 source "drivers/staging/unisys/virthba/Kconfig"
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
index b988d69..68b9925 100644
--- a/drivers/staging/unisys/Makefile
+++ b/drivers/staging/unisys/Makefile
@@ -4,7 +4,6 @@
 obj-$(CONFIG_UNISYS_VISORUTIL)		+= visorutil/
 obj-$(CONFIG_UNISYS_VISORCHANNEL)	+= visorchannel/
 obj-$(CONFIG_UNISYS_VISORCHIPSET)	+= visorchipset/
-obj-$(CONFIG_UNISYS_CHANNELSTUB)	+= channels/
 obj-$(CONFIG_UNISYS_UISLIB)		+= uislib/
 obj-$(CONFIG_UNISYS_VIRTPCI)		+= virtpci/
 obj-$(CONFIG_UNISYS_VIRTHBA)		+= virthba/
diff --git a/drivers/staging/unisys/channels/Kconfig b/drivers/staging/unisys/channels/Kconfig
deleted file mode 100644
index 179c6ce..0000000
--- a/drivers/staging/unisys/channels/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Unisys channels configuration
-#
-
-config UNISYS_CHANNELSTUB
-	tristate "Unisys channelstub driver"
-	depends on UNISYSSPAR && UNISYS_VISORUTIL
-	---help---
-	If you say Y here, you will enable the Unisys channels driver.
-
diff --git a/drivers/staging/unisys/channels/Makefile b/drivers/staging/unisys/channels/Makefile
deleted file mode 100644
index adc1842..0000000
--- a/drivers/staging/unisys/channels/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for Unisys channelstub
-#
-
-obj-$(CONFIG_UNISYS_CHANNELSTUB)	+= visorchannelstub.o
-
-visorchannelstub-y := channel.o chanstub.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c
deleted file mode 100644
index 74cc4d6..0000000
--- a/drivers/staging/unisys/channels/channel.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * 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 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- */
-
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/init.h>		/* for module_init and module_exit */
-#include <linux/slab.h>		/* for memcpy */
-#include <linux/types.h>
-
-/* Implementation of exported functions for Supervisor channels */
-#include "channel.h"
-
-/*
- * Routine Description:
- * Tries to insert the prebuilt signal pointed to by pSignal into the nth
- * Queue of the Channel pointed to by pChannel
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to the signal
- *
- * Assumptions:
- * - pChannel, Queue and pSignal are valid.
- * - If insertion fails due to a full queue, the caller will determine the
- * retry policy (e.g. wait & try again, report an error, etc.).
- *
- * Return value:
- * 1 if the insertion succeeds, 0 if the queue was full.
- */
-unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
-				 void *sig)
-{
-	void __iomem *psignal;
-	unsigned int head, tail, nof;
-
-	struct signal_queue_header __iomem *pqhdr =
-	    (struct signal_queue_header __iomem *)
-		((char __iomem *)ch + readq(&ch->ch_space_offset))
-		+ queue;
-
-	/* capture current head and tail */
-	head = readl(&pqhdr->head);
-	tail = readl(&pqhdr->tail);
-
-	/* queue is full if (head + 1) % n equals tail */
-	if (((head + 1) % readl(&pqhdr->max_slots)) == tail) {
-		nof = readq(&pqhdr->num_overflows) + 1;
-		writeq(nof, &pqhdr->num_overflows);
-		return 0;
-	}
-
-	/* increment the head index */
-	head = (head + 1) % readl(&pqhdr->max_slots);
-
-	/* copy signal to the head location from the area pointed to
-	 * by pSignal
-	 */
-	psignal = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
-		(head * readl(&pqhdr->signal_size));
-	memcpy_toio(psignal, sig, readl(&pqhdr->signal_size));
-
-	mb(); /* channel synch */
-	writel(head, &pqhdr->head);
-
-	writeq(readq(&pqhdr->num_sent) + 1, &pqhdr->num_sent);
-	return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_insert);
-
-/*
- * Routine Description:
- * Removes one signal from Channel pChannel's nth Queue at the
- * time of the call and copies it into the memory pointed to by
- * pSignal.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold queue's SignalSize
- *
- * Return value:
- * 1 if the removal succeeds, 0 if the queue was empty.
- */
-unsigned char
-spar_signal_remove(struct channel_header __iomem *ch, u32 queue, void *sig)
-{
-	void __iomem *psource;
-	unsigned int head, tail;
-	struct signal_queue_header __iomem *pqhdr =
-	    (struct signal_queue_header __iomem *)((char __iomem *)ch +
-				    readq(&ch->ch_space_offset)) + queue;
-
-	/* capture current head and tail */
-	head = readl(&pqhdr->head);
-	tail = readl(&pqhdr->tail);
-
-	/* queue is empty if the head index equals the tail index */
-	if (head == tail) {
-		writeq(readq(&pqhdr->num_empty) + 1, &pqhdr->num_empty);
-		return 0;
-	}
-
-	/* advance past the 'empty' front slot */
-	tail = (tail + 1) % readl(&pqhdr->max_slots);
-
-	/* copy signal from tail location to the area pointed to by pSignal */
-	psource = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
-		(tail * readl(&pqhdr->signal_size));
-	memcpy_fromio(sig, psource, readl(&pqhdr->signal_size));
-
-	mb(); /* channel synch */
-	writel(tail, &pqhdr->tail);
-
-	writeq(readq(&pqhdr->num_received) + 1,
-	       &pqhdr->num_received);
-	return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_remove);
-
-/*
- * Routine Description:
- * Removes all signals present in Channel pChannel's nth Queue at the
- * time of the call and copies them into the memory pointed to by
- * pSignal.  Returns the # of signals copied as the value of the routine.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold Queue's MaxSignals
- * # of signals, each of which is Queue's SignalSize.
- *
- * Return value:
- * # of signals copied.
- */
-unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
-				    void *sig)
-{
-	void *psource;
-	unsigned int head, tail, count = 0;
-	struct signal_queue_header *pqhdr =
-	    (struct signal_queue_header *)((char *)ch +
-				    ch->ch_space_offset) + queue;
-
-	/* capture current head and tail */
-	head = pqhdr->head;
-	tail = pqhdr->tail;
-
-	/* queue is empty if the head index equals the tail index */
-	if (head == tail)
-		return 0;
-
-	while (head != tail) {
-		/* advance past the 'empty' front slot */
-		tail = (tail + 1) % pqhdr->max_slots;
-
-		/* copy signal from tail location to the area pointed
-		 * to by pSignal
-		 */
-		psource =
-		    (char *)pqhdr + pqhdr->sig_base_offset +
-		    (tail * pqhdr->signal_size);
-		memcpy((char *)sig + (pqhdr->signal_size * count),
-		       psource, pqhdr->signal_size);
-
-		mb(); /* channel synch */
-		pqhdr->tail = tail;
-
-		count++;
-		pqhdr->num_received++;
-	}
-
-	return count;
-}
-
-/*
- * Routine Description:
- * Determine whether a signal queue is empty.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- *
- * Return value:
- * 1 if the signal queue is empty, 0 otherwise.
- */
-unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
-				     u32 queue)
-{
-	struct signal_queue_header __iomem *pqhdr =
-	    (struct signal_queue_header __iomem *)((char __iomem *)ch +
-				    readq(&ch->ch_space_offset)) + queue;
-	return readl(&pqhdr->head) == readl(&pqhdr->tail);
-}
-EXPORT_SYMBOL_GPL(spar_signalqueue_empty);
-
diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c
deleted file mode 100644
index b6fd126..0000000
--- a/drivers/staging/unisys/channels/chanstub.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * 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 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- */
-
-#define EXPORT_SYMTAB
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/init.h>		/* for module_init and module_exit */
-#include <linux/slab.h>		/* for memcpy */
-#include <linux/types.h>
-
-#include "channel.h"
-#include "chanstub.h"
-#include "timskmod.h"
-#include "version.h"
-
-static __init int
-channel_mod_init(void)
-{
-	if (!unisys_spar_platform)
-		return -ENODEV;
-	return 0;
-}
-
-static __exit void
-channel_mod_exit(void)
-{
-}
-
-unsigned char
-SignalInsert_withLock(struct channel_header __iomem *pChannel, u32 Queue,
-		      void *pSignal, spinlock_t *lock)
-{
-	unsigned char result;
-	unsigned long flags;
-
-	spin_lock_irqsave(lock, flags);
-	result = spar_signal_insert(pChannel, Queue, pSignal);
-	spin_unlock_irqrestore(lock, flags);
-	return result;
-}
-
-unsigned char
-SignalRemove_withLock(struct channel_header __iomem *pChannel, u32 Queue,
-		      void *pSignal, spinlock_t *lock)
-{
-	unsigned char result;
-
-	spin_lock(lock);
-	result = spar_signal_remove(pChannel, Queue, pSignal);
-	spin_unlock(lock);
-	return result;
-}
-
-module_init(channel_mod_init);
-module_exit(channel_mod_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bryan Glaudel");
-MODULE_ALIAS("uischan");
-	/* this is extracted during depmod and kept in modules.dep */
diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h
deleted file mode 100644
index 1531759..0000000
--- a/drivers/staging/unisys/channels/chanstub.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * 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 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- */
-
-#ifndef __CHANSTUB_H__
-#define __CHANSTUB_H__
-unsigned char SignalInsert_withLock(struct channel_header __iomem *pChannel,
-				    u32 Queue, void *pSignal, spinlock_t *lock);
-unsigned char SignalRemove_withLock(struct channel_header __iomem *pChannel,
-				    u32 Queue, void *pSignal, spinlock_t *lock);
-
-#endif
diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h
index f25208f..83d1da7 100644
--- a/drivers/staging/unisys/common-spar/include/version.h
+++ b/drivers/staging/unisys/common-spar/include/version.h
@@ -30,7 +30,6 @@
 #define SPARVER4 "0"
 
 #define  VERSION        SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
-#define  VERSIONDATE    __DATE__
 
 /* Here are various version forms needed in Windows environments.
  */
diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h
index cff7983..4019a0d 100644
--- a/drivers/staging/unisys/include/timskmod.h
+++ b/drivers/staging/unisys/include/timskmod.h
@@ -133,7 +133,7 @@
  *  x - the number of seconds to sleep.
  */
 #define SLEEP(x)					     \
-	do { current->state = TASK_INTERRUPTIBLE;	     \
+	do { __set_current_state(TASK_INTERRUPTIBLE);        \
 		schedule_timeout((x)*HZ);		     \
 	} while (0)
 
@@ -141,7 +141,7 @@
  *  x - the number of jiffies to sleep.
  */
 #define SLEEPJIFFIES(x)						    \
-	do { current->state = TASK_INTERRUPTIBLE;		    \
+	do { __set_current_state(TASK_INTERRUPTIBLE);		    \
 		schedule_timeout(x);				    \
 	} while (0)
 
diff --git a/drivers/staging/unisys/uislib/Kconfig b/drivers/staging/unisys/uislib/Kconfig
index 6b134e2..a712eb8 100644
--- a/drivers/staging/unisys/uislib/Kconfig
+++ b/drivers/staging/unisys/uislib/Kconfig
@@ -4,7 +4,7 @@
 
 config UNISYS_UISLIB
 	tristate "Unisys uislib driver"
-	depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && HAS_IOMEM
+	depends on UNISYSSPAR && UNISYS_VISORCHIPSET && HAS_IOMEM
 	---help---
 	If you say Y here, you will enable the Unisys uislib driver.
 
diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c
index 7c87452..a9eedde 100644
--- a/drivers/staging/unisys/uislib/uislib.c
+++ b/drivers/staging/unisys/uislib/uislib.c
@@ -41,7 +41,6 @@
 
 #include "sparstop.h"
 #include "visorchipset.h"
-#include "chanstub.h"
 #include "version.h"
 #include "guestlinuxdebug.h"
 
@@ -59,8 +58,8 @@
 /* global function pointers that act as callback functions into virtpcimod */
 int (*virt_control_chan_func)(struct guest_msgs *);
 
-static int ProcReadBufferValid;
-static char *ProcReadBuffer;	/* Note this MUST be global,
+static int debug_buf_valid;
+static char *debug_buf;	/* Note this MUST be global,
 					 * because the contents must */
 static unsigned int chipset_inited;
 
@@ -71,24 +70,24 @@
 		UIS_THREAD_WAIT;	\
 	} while (1)
 
-static struct bus_info *BusListHead;
-static rwlock_t BusListLock;
-static int BusListCount;	/* number of buses in the list */
-static int MaxBusCount;		/* maximum number of buses expected */
-static u64 PhysicalDataChan;
-static int PlatformNumber;
+static struct bus_info *bus_list;
+static rwlock_t bus_list_lock;
+static int bus_list_count;	/* number of buses in the list */
+static int max_bus_count;		/* maximum number of buses expected */
+static u64 phys_data_chan;
+static int platform_no;
 
-static struct uisthread_info Incoming_ThreadInfo;
-static BOOL Incoming_Thread_Started = FALSE;
-static LIST_HEAD(List_Polling_Device_Channels);
+static struct uisthread_info incoming_ti;
+static BOOL incoming_started = FALSE;
+static LIST_HEAD(poll_dev_chan);
 static unsigned long long tot_moved_to_tail_cnt;
 static unsigned long long tot_wait_cnt;
 static unsigned long long tot_wakeup_cnt;
 static unsigned long long tot_schedule_cnt;
 static int en_smart_wakeup = 1;
-static DEFINE_SEMAPHORE(Lock_Polling_Device_Channels);	/* unlocked */
-static DECLARE_WAIT_QUEUE_HEAD(Wakeup_Polling_Device_Channels);
-static int Go_Polling_Device_Channels;
+static DEFINE_SEMAPHORE(poll_dev_lock);	/* unlocked */
+static DECLARE_WAIT_QUEUE_HEAD(poll_dev_wake_q);
+static int poll_dev_start;
 
 #define CALLHOME_PROC_ENTRY_FN "callhome"
 #define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled"
@@ -115,7 +114,7 @@
 /*****************************************************/
 
 static ssize_t info_debugfs_read(struct file *file, char __user *buf,
-			      size_t len, loff_t *offset);
+				 size_t len, loff_t *offset);
 static const struct file_operations debugfs_info_fops = {
 	.read = info_debugfs_read,
 };
@@ -129,58 +128,52 @@
 	msg->hdr.flags.server = svr;
 }
 
-static __iomem void *
-init_vbus_channel(u64 channelAddr, u32 channelBytes)
+static __iomem void *init_vbus_channel(u64 ch_addr, u32 ch_bytes)
 {
-	void __iomem *rc = NULL;
-	void __iomem *pChan = uislib_ioremap_cache(channelAddr, channelBytes);
+	void __iomem *ch = uislib_ioremap_cache(ch_addr, ch_bytes);
 
-	if (!pChan) {
+	if (!ch) {
 		LOGERR("CONTROLVM_BUS_CREATE error: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
-		     (unsigned long long) channelAddr,
-		     (unsigned long long) channelBytes);
-		rc = NULL;
-		goto Away;
+		       (unsigned long long)ch_addr,
+		       (unsigned long long)ch_bytes);
+		return NULL;
 	}
-	if (!SPAR_VBUS_CHANNEL_OK_CLIENT(pChan)) {
+	if (!SPAR_VBUS_CHANNEL_OK_CLIENT(ch)) {
 		ERRDRV("%s channel cannot be used", __func__);
-		uislib_iounmap(pChan);
-		rc = NULL;
-		goto Away;
+		uislib_iounmap(ch);
+		return NULL;
 	}
-	rc = pChan;
-Away:
-	return rc;
+	return ch;
 }
 
 static int
 create_bus(struct controlvm_message *msg, char *buf)
 {
-	u32 busNo, deviceCount;
+	u32 bus_no, dev_count;
 	struct bus_info *tmp, *bus;
 	size_t size;
 
-	if (MaxBusCount == BusListCount) {
+	if (max_bus_count == bus_list_count) {
 		LOGERR("CONTROLVM_BUS_CREATE Failed: max buses:%d already created\n",
-		     MaxBusCount);
-		POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, MaxBusCount,
+		       max_bus_count);
+		POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, max_bus_count,
 				 POSTCODE_SEVERITY_ERR);
 		return CONTROLVM_RESP_ERROR_MAX_BUSES;
 	}
 
-	busNo = msg->cmd.create_bus.bus_no;
-	deviceCount = msg->cmd.create_bus.dev_count;
+	bus_no = msg->cmd.create_bus.bus_no;
+	dev_count = msg->cmd.create_bus.dev_count;
 
-	POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, busNo, deviceCount,
+	POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, bus_no, dev_count,
 			 POSTCODE_SEVERITY_INFO);
 
 	size =
 	    sizeof(struct bus_info) +
-	    (deviceCount * sizeof(struct device_info *));
+	    (dev_count * sizeof(struct device_info *));
 	bus = kzalloc(size, GFP_ATOMIC);
 	if (!bus) {
 		LOGERR("CONTROLVM_BUS_CREATE Failed: kmalloc for bus failed.\n");
-		POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+		POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
 				 POSTCODE_SEVERITY_ERR);
 		return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
 	}
@@ -191,27 +184,29 @@
 	if (msg->hdr.flags.test_message) {
 		/* This implies we're the IOVM so set guest handle to 0... */
 		bus->guest_handle = 0;
-		bus->bus_no = busNo;
+		bus->bus_no = bus_no;
 		bus->local_vnic = 1;
-	} else
-		bus->bus_no = bus->guest_handle = busNo;
-	sprintf(bus->name, "%d", (int) bus->bus_no);
-	bus->device_count = deviceCount;
+	} else {
+		bus->bus_no = bus_no;
+		bus->guest_handle = bus_no;
+	}
+	sprintf(bus->name, "%d", (int)bus->bus_no);
+	bus->device_count = dev_count;
 	bus->device =
-	    (struct device_info **) ((char *) bus + sizeof(struct bus_info));
+	    (struct device_info **)((char *)bus + sizeof(struct bus_info));
 	bus->bus_inst_uuid = msg->cmd.create_bus.bus_inst_uuid;
 	bus->bus_channel_bytes = 0;
 	bus->bus_channel = NULL;
 
 	/* add bus to our bus list - but check for duplicates first */
-	read_lock(&BusListLock);
-	for (tmp = BusListHead; tmp; tmp = tmp->next) {
+	read_lock(&bus_list_lock);
+	for (tmp = bus_list; tmp; tmp = tmp->next) {
 		if (tmp->bus_no == bus->bus_no)
 			break;
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 	if (tmp) {
-		/* found a bus already in the list with same busNo -
+		/* found a bus already in the list with same bus_no -
 		 * reject add
 		 */
 		LOGERR("CONTROLVM_BUS_CREATE Failed: bus %d already exists.\n",
@@ -221,8 +216,8 @@
 		kfree(bus);
 		return CONTROLVM_RESP_ERROR_ALREADY_DONE;
 	}
-	if ((msg->cmd.create_bus.channel_addr != 0)
-	    && (msg->cmd.create_bus.channel_bytes != 0)) {
+	if ((msg->cmd.create_bus.channel_addr != 0) &&
+	    (msg->cmd.create_bus.channel_bytes != 0)) {
 		bus->bus_channel_bytes = msg->cmd.create_bus.channel_bytes;
 		bus->bus_channel =
 		    init_vbus_channel(msg->cmd.create_bus.channel_addr,
@@ -233,9 +228,9 @@
 		struct guest_msgs cmd;
 
 		cmd.msgtype = GUEST_ADD_VBUS;
-		cmd.add_vbus.bus_no = busNo;
+		cmd.add_vbus.bus_no = bus_no;
 		cmd.add_vbus.chanptr = bus->bus_channel;
-		cmd.add_vbus.dev_count = deviceCount;
+		cmd.add_vbus.dev_count = dev_count;
 		cmd.add_vbus.bus_uuid = msg->cmd.create_bus.bus_data_type_uuid;
 		cmd.add_vbus.instance_uuid = msg->cmd.create_bus.bus_inst_uuid;
 		if (!virt_control_chan_func) {
@@ -256,15 +251,15 @@
 	}
 
 	/* add bus at the head of our list */
-	write_lock(&BusListLock);
-	if (!BusListHead)
-		BusListHead = bus;
-	else {
-		bus->next = BusListHead;
-		BusListHead = bus;
+	write_lock(&bus_list_lock);
+	if (!bus_list) {
+		bus_list = bus;
+	} else {
+		bus->next = bus_list;
+		bus_list = bus;
 	}
-	BusListCount++;
-	write_unlock(&BusListLock);
+	bus_list_count++;
+	write_unlock(&bus_list_lock);
 
 	POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->bus_no,
 			 POSTCODE_SEVERITY_INFO);
@@ -277,15 +272,15 @@
 	int i;
 	struct bus_info *bus, *prev = NULL;
 	struct guest_msgs cmd;
-	u32 busNo;
+	u32 bus_no;
 
-	busNo = msg->cmd.destroy_bus.bus_no;
+	bus_no = msg->cmd.destroy_bus.bus_no;
 
-	read_lock(&BusListLock);
+	read_lock(&bus_list_lock);
 
-	bus = BusListHead;
+	bus = bus_list;
 	while (bus) {
-		if (bus->bus_no == busNo)
+		if (bus->bus_no == bus_no)
 			break;
 		prev = bus;
 		bus = bus->next;
@@ -293,8 +288,8 @@
 
 	if (!bus) {
 		LOGERR("CONTROLVM_BUS_DESTROY Failed: failed to find bus %d.\n",
-		       busNo);
-		read_unlock(&BusListLock);
+		       bus_no);
+		read_unlock(&bus_list_lock);
 		return CONTROLVM_RESP_ERROR_ALREADY_DONE;
 	}
 
@@ -302,12 +297,12 @@
 	for (i = 0; i < bus->device_count; i++) {
 		if (bus->device[i] != NULL) {
 			LOGERR("CONTROLVM_BUS_DESTROY Failed: device %i attached to bus %d.",
-			     i, busNo);
-			read_unlock(&BusListLock);
+			       i, bus_no);
+			read_unlock(&bus_list_lock);
 			return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED;
 		}
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 
 	if (msg->hdr.flags.server)
 		goto remove;
@@ -315,7 +310,7 @@
 	/* client messages require us to call the virtpci callback associated
 	   with this bus. */
 	cmd.msgtype = GUEST_DEL_VBUS;
-	cmd.del_vbus.bus_no = busNo;
+	cmd.del_vbus.bus_no = bus_no;
 	if (!virt_control_chan_func) {
 		LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci callback not registered.");
 		return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
@@ -327,13 +322,13 @@
 
 	/* finally, remove the bus from the list */
 remove:
-	write_lock(&BusListLock);
+	write_lock(&bus_list_lock);
 	if (prev)	/* not at head */
 		prev->next = bus->next;
 	else
-		BusListHead = bus->next;
-	BusListCount--;
-	write_unlock(&BusListLock);
+		bus_list = bus->next;
+	bus_list_count--;
+	write_unlock(&bus_list_lock);
 
 	if (bus->bus_channel) {
 		uislib_iounmap(bus->bus_channel);
@@ -344,26 +339,26 @@
 	return CONTROLVM_RESP_SUCCESS;
 }
 
-static int
-create_device(struct controlvm_message *msg, char *buf)
+static int create_device(struct controlvm_message *msg, char *buf)
 {
 	struct device_info *dev;
 	struct bus_info *bus;
-	u32 busNo, devNo;
+	struct guest_msgs cmd;
+	u32 bus_no, dev_no;
 	int result = CONTROLVM_RESP_SUCCESS;
-	u64 minSize = MIN_IO_CHANNEL_SIZE;
-	struct req_handler_info *pReqHandler;
+	u64 min_size = MIN_IO_CHANNEL_SIZE;
+	struct req_handler_info *req_handler;
 
-	busNo = msg->cmd.create_device.bus_no;
-	devNo = msg->cmd.create_device.dev_no;
+	bus_no = msg->cmd.create_device.bus_no;
+	dev_no = msg->cmd.create_device.dev_no;
 
-	POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+	POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
 			 POSTCODE_SEVERITY_INFO);
 
-	dev = kzalloc(sizeof(struct device_info), GFP_ATOMIC);
+	dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
 	if (!dev) {
 		LOGERR("CONTROLVM_DEVICE_CREATE Failed: kmalloc for dev failed.\n");
-		POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+		POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
 				 POSTCODE_SEVERITY_ERR);
 		return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
 	}
@@ -371,169 +366,157 @@
 	dev->channel_uuid = msg->cmd.create_device.data_type_uuid;
 	dev->intr = msg->cmd.create_device.intr;
 	dev->channel_addr = msg->cmd.create_device.channel_addr;
-	dev->bus_no = busNo;
-	dev->dev_no = devNo;
+	dev->bus_no = bus_no;
+	dev->dev_no = dev_no;
 	sema_init(&dev->interrupt_callback_lock, 1);	/* unlocked */
-	sprintf(dev->devid, "vbus%u:dev%u", (unsigned) busNo, (unsigned) devNo);
+	sprintf(dev->devid, "vbus%u:dev%u", (unsigned)bus_no, (unsigned)dev_no);
 	/* map the channel memory for the device. */
-	if (msg->hdr.flags.test_message)
+	if (msg->hdr.flags.test_message) {
 		dev->chanptr = (void __iomem *)__va(dev->channel_addr);
-	else {
-		pReqHandler = req_handler_find(dev->channel_uuid);
-		if (pReqHandler)
+	} else {
+		req_handler = req_handler_find(dev->channel_uuid);
+		if (req_handler)
 			/* generic service handler registered for this
 			 * channel
 			 */
-			minSize = pReqHandler->min_channel_bytes;
-		if (minSize > msg->cmd.create_device.channel_bytes) {
+			min_size = req_handler->min_channel_bytes;
+		if (min_size > msg->cmd.create_device.channel_bytes) {
 			LOGERR("CONTROLVM_DEVICE_CREATE Failed: channel size is too small, channel size:0x%lx, required size:0x%lx",
-			     (ulong) msg->cmd.create_device.channel_bytes,
-			     (ulong) minSize);
-			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
-					 POSTCODE_SEVERITY_ERR);
+			       (ulong)msg->cmd.create_device.channel_bytes,
+			       (ulong)min_size);
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
 			result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL;
-			goto Away;
+			goto cleanup;
 		}
 		dev->chanptr =
 		    uislib_ioremap_cache(dev->channel_addr,
 					 msg->cmd.create_device.channel_bytes);
 		if (!dev->chanptr) {
 			LOGERR("CONTROLVM_DEVICE_CREATE Failed: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
-			     dev->channel_addr,
-			     msg->cmd.create_device.channel_bytes);
+			       dev->channel_addr,
+			       msg->cmd.create_device.channel_bytes);
 			result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
-			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
-					 POSTCODE_SEVERITY_ERR);
-			goto Away;
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
+			goto cleanup;
 		}
 	}
 	dev->instance_uuid = msg->cmd.create_device.dev_inst_uuid;
 	dev->channel_bytes = msg->cmd.create_device.channel_bytes;
 
-	read_lock(&BusListLock);
-	for (bus = BusListHead; bus; bus = bus->next) {
-		if (bus->bus_no == busNo) {
-			/* make sure the device number is valid */
-			if (devNo >= bus->device_count) {
-				LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
-				     devNo, bus->device_count);
-				result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
-				POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
-						 devNo, busNo,
-						 POSTCODE_SEVERITY_ERR);
-				read_unlock(&BusListLock);
-				goto Away;
-			}
-			/* make sure this device is not already set */
-			if (bus->device[devNo]) {
-				LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
-				     devNo);
-				POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
-						 devNo, busNo,
-						 POSTCODE_SEVERITY_ERR);
-				result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
-				read_unlock(&BusListLock);
-				goto Away;
-			}
-			read_unlock(&BusListLock);
-			/* the msg is bound for virtpci; send
-			 * guest_msgs struct to callback
-			 */
-			if (!msg->hdr.flags.server) {
-				struct guest_msgs cmd;
-
-				if (!uuid_le_cmp(dev->channel_uuid,
-				     spar_vhba_channel_protocol_uuid)) {
-					wait_for_valid_guid(&((
-						struct channel_header
-							__iomem *) (dev->
-								  chanptr))->
-							    chtype);
-					if (!SPAR_VHBA_CHANNEL_OK_CLIENT
-					    (dev->chanptr)) {
-						LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
-						     devNo);
-						POSTCODE_LINUX_4
-						    (DEVICE_CREATE_FAILURE_PC,
-						     devNo, busNo,
-						     POSTCODE_SEVERITY_ERR);
-						result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
-						goto Away;
-					}
-					cmd.msgtype = GUEST_ADD_VHBA;
-					cmd.add_vhba.chanptr = dev->chanptr;
-					cmd.add_vhba.bus_no = busNo;
-					cmd.add_vhba.device_no = devNo;
-					cmd.add_vhba.instance_uuid =
-					    dev->instance_uuid;
-					cmd.add_vhba.intr = dev->intr;
-				} else
-				    if (!uuid_le_cmp(dev->channel_uuid,
-					 spar_vnic_channel_protocol_uuid)) {
-					wait_for_valid_guid(&((
-						struct channel_header
-							__iomem *) (dev->
-								  chanptr))->
-							    chtype);
-					if (!SPAR_VNIC_CHANNEL_OK_CLIENT
-					    (dev->chanptr)) {
-						LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
-						     devNo);
-						POSTCODE_LINUX_4
-						    (DEVICE_CREATE_FAILURE_PC,
-						     devNo, busNo,
-						     POSTCODE_SEVERITY_ERR);
-						result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
-						goto Away;
-					}
-					cmd.msgtype = GUEST_ADD_VNIC;
-					cmd.add_vnic.chanptr = dev->chanptr;
-					cmd.add_vnic.bus_no = busNo;
-					cmd.add_vnic.device_no = devNo;
-					cmd.add_vnic.instance_uuid =
-					    dev->instance_uuid;
-					cmd.add_vhba.intr = dev->intr;
-				} else {
-					LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
-					POSTCODE_LINUX_4
-					    (DEVICE_CREATE_FAILURE_PC, devNo,
-					     busNo, POSTCODE_SEVERITY_ERR);
-					result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
-					goto Away;
-				}
-
-				if (!virt_control_chan_func) {
-					LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
-					POSTCODE_LINUX_4
-					    (DEVICE_CREATE_FAILURE_PC, devNo,
-					     busNo, POSTCODE_SEVERITY_ERR);
-					result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
-					goto Away;
-				}
-
-				if (!virt_control_chan_func(&cmd)) {
-					LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
-					POSTCODE_LINUX_4
-					    (DEVICE_CREATE_FAILURE_PC, devNo,
-					     busNo, POSTCODE_SEVERITY_ERR);
-					result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
-					goto Away;
-				}
-			}
-			bus->device[devNo] = dev;
-			POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, devNo, busNo,
-					 POSTCODE_SEVERITY_INFO);
+	read_lock(&bus_list_lock);
+	for (bus = bus_list; bus; bus = bus->next) {
+		if (bus->bus_no != bus_no)
+			continue;
+		/* make sure the device number is valid */
+		if (dev_no >= bus->device_count) {
+			LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
+			       dev_no, bus->device_count);
+			result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
+			read_unlock(&bus_list_lock);
+			goto cleanup;
+		}
+		/* make sure this device is not already set */
+		if (bus->device[dev_no]) {
+			LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
+			       dev_no);
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+					 dev_no, bus_no,
+					 POSTCODE_SEVERITY_ERR);
+			result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
+			read_unlock(&bus_list_lock);
+			goto cleanup;
+		}
+		read_unlock(&bus_list_lock);
+		/* the msg is bound for virtpci; send
+		 * guest_msgs struct to callback
+		 */
+		if (msg->hdr.flags.server) {
+			bus->device[dev_no] = dev;
+			POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_INFO);
 			return CONTROLVM_RESP_SUCCESS;
 		}
-	}
-	read_unlock(&BusListLock);
+		if (uuid_le_cmp(dev->channel_uuid,
+				spar_vhba_channel_protocol_uuid) == 0) {
+			wait_for_valid_guid(&((struct channel_header __iomem *)
+					    (dev->chanptr))->chtype);
+			if (!SPAR_VHBA_CHANNEL_OK_CLIENT(dev->chanptr)) {
+				LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
+				       dev_no);
+				POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+						 dev_no, bus_no,
+						 POSTCODE_SEVERITY_ERR);
+				result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+				goto cleanup;
+			}
+			cmd.msgtype = GUEST_ADD_VHBA;
+			cmd.add_vhba.chanptr = dev->chanptr;
+			cmd.add_vhba.bus_no = bus_no;
+			cmd.add_vhba.device_no = dev_no;
+			cmd.add_vhba.instance_uuid = dev->instance_uuid;
+			cmd.add_vhba.intr = dev->intr;
+		} else if (uuid_le_cmp(dev->channel_uuid,
+				       spar_vnic_channel_protocol_uuid) == 0) {
+			wait_for_valid_guid(&((struct channel_header __iomem *)
+					    (dev->chanptr))->chtype);
+			if (!SPAR_VNIC_CHANNEL_OK_CLIENT(dev->chanptr)) {
+				LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
+				       dev_no);
+				POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+						 dev_no, bus_no,
+						 POSTCODE_SEVERITY_ERR);
+				result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+				goto cleanup;
+			}
+			cmd.msgtype = GUEST_ADD_VNIC;
+			cmd.add_vnic.chanptr = dev->chanptr;
+			cmd.add_vnic.bus_no = bus_no;
+			cmd.add_vnic.device_no = dev_no;
+			cmd.add_vnic.instance_uuid = dev->instance_uuid;
+			cmd.add_vhba.intr = dev->intr;
+		} else {
+			LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
+			result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+			goto cleanup;
+		}
 
-	LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.", busNo);
-	POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+		if (!virt_control_chan_func) {
+			LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
+			result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+			goto cleanup;
+		}
+
+		if (!virt_control_chan_func(&cmd)) {
+			LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
+			POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+					 bus_no, POSTCODE_SEVERITY_ERR);
+			result =
+			     CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+			goto cleanup;
+		}
+
+		bus->device[dev_no] = dev;
+		POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
+				 bus_no, POSTCODE_SEVERITY_INFO);
+		return CONTROLVM_RESP_SUCCESS;
+	}
+	read_unlock(&bus_list_lock);
+
+	LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.",
+	       bus_no);
+	POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
 			 POSTCODE_SEVERITY_ERR);
 	result = CONTROLVM_RESP_ERROR_BUS_INVALID;
 
-Away:
+cleanup:
 	if (!msg->hdr.flags.test_message) {
 		uislib_iounmap(dev->chanptr);
 		dev->chanptr = NULL;
@@ -543,32 +526,31 @@
 	return result;
 }
 
-static int
-pause_device(struct controlvm_message *msg)
+static int pause_device(struct controlvm_message *msg)
 {
-	u32 busNo, devNo;
+	u32 bus_no, dev_no;
 	struct bus_info *bus;
 	struct device_info *dev;
 	struct guest_msgs cmd;
 	int retval = CONTROLVM_RESP_SUCCESS;
 
-	busNo = msg->cmd.device_change_state.bus_no;
-	devNo = msg->cmd.device_change_state.dev_no;
+	bus_no = msg->cmd.device_change_state.bus_no;
+	dev_no = msg->cmd.device_change_state.dev_no;
 
-	read_lock(&BusListLock);
-	for (bus = BusListHead; bus; bus = bus->next) {
-		if (bus->bus_no == busNo) {
+	read_lock(&bus_list_lock);
+	for (bus = bus_list; bus; bus = bus->next) {
+		if (bus->bus_no == bus_no) {
 			/* make sure the device number is valid */
-			if (devNo >= bus->device_count) {
+			if (dev_no >= bus->device_count) {
 				LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device(%d) >= deviceCount(%d).",
-				     devNo, bus->device_count);
+				       dev_no, bus->device_count);
 				retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
 			} else {
 				/* make sure this device exists */
-				dev = bus->device[devNo];
+				dev = bus->device[dev_no];
 				if (!dev) {
 					LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device %d does not exist.",
-					     devNo);
+					       dev_no);
 					retval =
 					  CONTROLVM_RESP_ERROR_ALREADY_DONE;
 				}
@@ -578,20 +560,20 @@
 	}
 	if (!bus) {
 		LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: bus %d does not exist",
-		     busNo);
+		       bus_no);
 		retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 	if (retval == CONTROLVM_RESP_SUCCESS) {
 		/* the msg is bound for virtpci; send
 		 * guest_msgs struct to callback
 		 */
-		if (!uuid_le_cmp(dev->channel_uuid,
-				spar_vhba_channel_protocol_uuid)) {
+		if (uuid_le_cmp(dev->channel_uuid,
+				spar_vhba_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_PAUSE_VHBA;
 			cmd.pause_vhba.chanptr = dev->chanptr;
-		} else if (!uuid_le_cmp(dev->channel_uuid,
-					spar_vnic_channel_protocol_uuid)) {
+		} else if (uuid_le_cmp(dev->channel_uuid,
+				       spar_vnic_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_PAUSE_VNIC;
 			cmd.pause_vnic.chanptr = dev->chanptr;
 		} else {
@@ -611,32 +593,31 @@
 	return retval;
 }
 
-static int
-resume_device(struct controlvm_message *msg)
+static int resume_device(struct controlvm_message *msg)
 {
-	u32 busNo, devNo;
+	u32 bus_no, dev_no;
 	struct bus_info *bus;
 	struct device_info *dev;
 	struct guest_msgs cmd;
 	int retval = CONTROLVM_RESP_SUCCESS;
 
-	busNo = msg->cmd.device_change_state.bus_no;
-	devNo = msg->cmd.device_change_state.dev_no;
+	bus_no = msg->cmd.device_change_state.bus_no;
+	dev_no = msg->cmd.device_change_state.dev_no;
 
-	read_lock(&BusListLock);
-	for (bus = BusListHead; bus; bus = bus->next) {
-		if (bus->bus_no == busNo) {
+	read_lock(&bus_list_lock);
+	for (bus = bus_list; bus; bus = bus->next) {
+		if (bus->bus_no == bus_no) {
 			/* make sure the device number is valid */
-			if (devNo >= bus->device_count) {
+			if (dev_no >= bus->device_count) {
 				LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device(%d) >= deviceCount(%d).",
-				     devNo, bus->device_count);
+				       dev_no, bus->device_count);
 				retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
 			} else {
 				/* make sure this device exists */
-				dev = bus->device[devNo];
+				dev = bus->device[dev_no];
 				if (!dev) {
 					LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device %d does not exist.",
-					     devNo);
+					       dev_no);
 					retval =
 					  CONTROLVM_RESP_ERROR_ALREADY_DONE;
 				}
@@ -647,20 +628,20 @@
 
 	if (!bus) {
 		LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: bus %d does not exist",
-		     busNo);
+		       bus_no);
 		retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 	/* the msg is bound for virtpci; send
 	 * guest_msgs struct to callback
 	 */
 	if (retval == CONTROLVM_RESP_SUCCESS) {
-		if (!uuid_le_cmp(dev->channel_uuid,
-				 spar_vhba_channel_protocol_uuid)) {
+		if (uuid_le_cmp(dev->channel_uuid,
+				spar_vhba_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_RESUME_VHBA;
 			cmd.resume_vhba.chanptr = dev->chanptr;
-		} else if (!uuid_le_cmp(dev->channel_uuid,
-					spar_vnic_channel_protocol_uuid)) {
+		} else if (uuid_le_cmp(dev->channel_uuid,
+				       spar_vnic_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_RESUME_VNIC;
 			cmd.resume_vnic.chanptr = dev->chanptr;
 		} else {
@@ -680,33 +661,33 @@
 	return retval;
 }
 
-static int
-destroy_device(struct controlvm_message *msg, char *buf)
+static int destroy_device(struct controlvm_message *msg, char *buf)
 {
-	u32 busNo, devNo;
+	u32 bus_no, dev_no;
 	struct bus_info *bus;
 	struct device_info *dev;
 	struct guest_msgs cmd;
 	int retval = CONTROLVM_RESP_SUCCESS;
 
-	busNo = msg->cmd.destroy_device.bus_no;
-	devNo = msg->cmd.destroy_device.bus_no;
+	bus_no = msg->cmd.destroy_device.bus_no;
+	dev_no = msg->cmd.destroy_device.bus_no;
 
-	read_lock(&BusListLock);
-	LOGINF("destroy_device called for busNo=%u, devNo=%u", busNo, devNo);
-	for (bus = BusListHead; bus; bus = bus->next) {
-		if (bus->bus_no == busNo) {
+	read_lock(&bus_list_lock);
+	LOGINF("destroy_device called for bus_no=%u, dev_no=%u", bus_no,
+	       dev_no);
+	for (bus = bus_list; bus; bus = bus->next) {
+		if (bus->bus_no == bus_no) {
 			/* make sure the device number is valid */
-			if (devNo >= bus->device_count) {
-				LOGERR("CONTROLVM_DEVICE_DESTORY Failed: device(%d) >= deviceCount(%d).",
-				       devNo, bus->device_count);
+			if (dev_no >= bus->device_count) {
+				LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device(%d) >= device_count(%d).",
+				       dev_no, bus->device_count);
 				retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
 			} else {
 				/* make sure this device exists */
-				dev = bus->device[devNo];
+				dev = bus->device[dev_no];
 				if (!dev) {
 					LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device %d does not exist.",
-					       devNo);
+					       dev_no);
 					retval =
 					     CONTROLVM_RESP_ERROR_ALREADY_DONE;
 				}
@@ -717,20 +698,20 @@
 
 	if (!bus) {
 		LOGERR("CONTROLVM_DEVICE_DESTROY Failed: bus %d does not exist",
-		       busNo);
+		       bus_no);
 		retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 	if (retval == CONTROLVM_RESP_SUCCESS) {
 		/* the msg is bound for virtpci; send
 		 * guest_msgs struct to callback
 		 */
-		if (!uuid_le_cmp(dev->channel_uuid,
-				 spar_vhba_channel_protocol_uuid)) {
+		if (uuid_le_cmp(dev->channel_uuid,
+				spar_vhba_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_DEL_VHBA;
 			cmd.del_vhba.chanptr = dev->chanptr;
-		} else if (!uuid_le_cmp(dev->channel_uuid,
-					spar_vnic_channel_protocol_uuid)) {
+		} else if (uuid_le_cmp(dev->channel_uuid,
+				       spar_vnic_channel_protocol_uuid) == 0) {
 			cmd.msgtype = GUEST_DEL_VNIC;
 			cmd.del_vnic.chanptr = dev->chanptr;
 		} else {
@@ -739,7 +720,7 @@
 			    CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
 		}
 		if (!virt_control_chan_func) {
-			LOGERR("CONTROLVM_DEVICE_DESTORY Failed: virtpci callback not registered.");
+			LOGERR("CONTROLVM_DEVICE_DESTROY Failed: virtpci callback not registered.");
 			return
 			    CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
 		}
@@ -755,7 +736,7 @@
  */
 		if (dev->polling) {
 			LOGINF("calling uislib_disable_channel_interrupts");
-			uislib_disable_channel_interrupts(busNo, devNo);
+			uislib_disable_channel_interrupts(bus_no, dev_no);
 		}
 		/* unmap the channel memory for the device. */
 		if (!msg->hdr.flags.test_message) {
@@ -763,7 +744,7 @@
 			uislib_iounmap(dev->chanptr);
 		}
 		kfree(dev);
-		bus->device[devNo] = NULL;
+		bus->device[dev_no] = NULL;
 	}
 	return retval;
 }
@@ -773,9 +754,9 @@
 {
 	POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
 
-	MaxBusCount = msg->cmd.init_chipset.bus_count;
-	PlatformNumber = msg->cmd.init_chipset.platform_number;
-	PhysicalDataChan = 0;
+	max_bus_count = msg->cmd.init_chipset.bus_count;
+	platform_no = msg->cmd.init_chipset.platform_number;
+	phys_data_chan = 0;
 
 	/* We need to make sure we have our functions registered
 	* before processing messages.  If we are a test vehicle the
@@ -793,31 +774,29 @@
 	return CONTROLVM_RESP_SUCCESS;
 }
 
-static int
-delete_bus_glue(u32 busNo)
+static int delete_bus_glue(u32 bus_no)
 {
 	struct controlvm_message msg;
 
 	init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
-	msg.cmd.destroy_bus.bus_no = busNo;
+	msg.cmd.destroy_bus.bus_no = bus_no;
 	if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
-		LOGERR("destroy_bus failed. busNo=0x%x\n", busNo);
+		LOGERR("destroy_bus failed. bus_no=0x%x\n", bus_no);
 		return 0;
 	}
 	return 1;
 }
 
-static int
-delete_device_glue(u32 busNo, u32 devNo)
+static int delete_device_glue(u32 bus_no, u32 dev_no)
 {
 	struct controlvm_message msg;
 
 	init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
-	msg.cmd.destroy_device.bus_no = busNo;
-	msg.cmd.destroy_device.dev_no = devNo;
+	msg.cmd.destroy_device.bus_no = bus_no;
+	msg.cmd.destroy_device.dev_no = dev_no;
 	if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
-		LOGERR("destroy_device failed. busNo=0x%x devNo=0x%x\n", busNo,
-		       devNo);
+		LOGERR("destroy_device failed. bus_no=0x%x dev_no=0x%x\n",
+		       bus_no, dev_no);
 		return 0;
 	}
 	return 1;
@@ -874,7 +853,6 @@
 }
 EXPORT_SYMBOL_GPL(uislib_client_inject_add_bus);
 
-
 int
 uislib_client_inject_del_bus(u32 bus_no)
 {
@@ -919,7 +897,6 @@
 		return rc;
 	}
 	return 0;
-
 }
 EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vhba);
 
@@ -956,7 +933,7 @@
 	msg.cmd.create_device.channel_addr = phys_chan_addr;
 	if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
 		LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
-		     chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+		       chan_bytes, (unsigned int)MIN_IO_CHANNEL_SIZE);
 		POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes,
 				 MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
 		return 0;
@@ -1015,7 +992,7 @@
 	msg.cmd.create_device.channel_addr = phys_chan_addr;
 	if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
 		LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
-		     chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+		       chan_bytes, (unsigned int)MIN_IO_CHANNEL_SIZE);
 		POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes,
 				 MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
 		return 0;
@@ -1072,7 +1049,6 @@
 		return -1;
 	}
 	return 0;
-
 }
 EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vnic);
 
@@ -1129,14 +1105,12 @@
 	if (PLINE("\nBuses:\n") < 0)
 		goto err_done;
 
-	read_lock(&BusListLock);
-	for (bus = BusListHead; bus; bus = bus->next) {
-
+	read_lock(&bus_list_lock);
+	for (bus = bus_list; bus; bus = bus->next) {
 		if (PLINE("    bus=0x%p, busNo=%d, deviceCount=%d\n",
 			  bus, bus->bus_no, bus->device_count) < 0)
 			goto err_done_unlock;
 
-
 		if (PLINE("        Devices:\n") < 0)
 			goto err_done_unlock;
 
@@ -1156,7 +1130,7 @@
 			}
 		}
 	}
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 
 	if (PLINE("UisUtils_Registered_Services: %d\n",
 		  atomic_read(&uisutils_registered_services)) < 0)
@@ -1175,70 +1149,68 @@
 	return tot;
 
 err_done_unlock:
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 err_done:
 	return -1;
 }
 
-static ssize_t
-info_debugfs_read(struct file *file, char __user *buf,
-		size_t len, loff_t *offset)
+static ssize_t info_debugfs_read(struct file *file, char __user *buf,
+				 size_t len, loff_t *offset)
 {
 	char *temp;
-	int totalBytes = 0;
+	int total_bytes = 0;
 	int remaining_bytes = PROC_READ_BUFFER_SIZE;
 
 /* *start = buf; */
-	if (ProcReadBuffer == NULL) {
-		DBGINF("ProcReadBuffer == NULL; allocating buffer.\n.");
-		ProcReadBuffer = vmalloc(PROC_READ_BUFFER_SIZE);
+	if (debug_buf == NULL) {
+		DBGINF("debug_buf == NULL; allocating buffer.\n.");
+		debug_buf = vmalloc(PROC_READ_BUFFER_SIZE);
 
-		if (ProcReadBuffer == NULL) {
+		if (debug_buf == NULL) {
 			LOGERR("failed to allocate buffer to provide proc data.\n");
 			return -ENOMEM;
 		}
 	}
 
-	temp = ProcReadBuffer;
+	temp = debug_buf;
 
-	if ((*offset == 0) || (!ProcReadBufferValid)) {
+	if ((*offset == 0) || (!debug_buf_valid)) {
 		DBGINF("calling info_debugfs_read_helper.\n");
 		/* if the read fails, then -1 will be returned */
-		totalBytes = info_debugfs_read_helper(&temp, &remaining_bytes);
-		ProcReadBufferValid = 1;
-	} else
-		totalBytes = strlen(ProcReadBuffer);
+		total_bytes = info_debugfs_read_helper(&temp, &remaining_bytes);
+		debug_buf_valid = 1;
+	} else {
+		total_bytes = strlen(debug_buf);
+	}
 
 	return simple_read_from_buffer(buf, len, offset,
-				       ProcReadBuffer, totalBytes);
+				       debug_buf, total_bytes);
 }
 
-static struct device_info *
-find_dev(u32 busNo, u32 devNo)
+static struct device_info *find_dev(u32 bus_no, u32 dev_no)
 {
 	struct bus_info *bus;
 	struct device_info *dev = NULL;
 
-	read_lock(&BusListLock);
-	for (bus = BusListHead; bus; bus = bus->next) {
-		if (bus->bus_no == busNo) {
+	read_lock(&bus_list_lock);
+	for (bus = bus_list; bus; bus = bus->next) {
+		if (bus->bus_no == bus_no) {
 			/* make sure the device number is valid */
-			if (devNo >= bus->device_count) {
-				LOGERR("%s bad busNo, devNo=%d,%d",
+			if (dev_no >= bus->device_count) {
+				LOGERR("%s bad bus_no, dev_no=%d,%d",
 				       __func__,
-				       (int) (busNo), (int) (devNo));
-				goto Away;
+				       (int)bus_no, (int)dev_no);
+				break;
 			}
-			dev = bus->device[devNo];
+			dev = bus->device[dev_no];
 			if (!dev)
-				LOGERR("%s bad busNo, devNo=%d,%d",
+				LOGERR("%s bad bus_no, dev_no=%d,%d",
 				       __func__,
-				       (int) (busNo), (int) (devNo));
-			goto Away;
+				       (int)bus_no, (int)dev_no);
+			break;
 		}
 	}
-Away:
-	read_unlock(&BusListLock);
+	read_unlock(&bus_list_lock);
 	return dev;
 }
 
@@ -1262,8 +1234,7 @@
  *    less-busy ones.
  *
  */
-static int
-Process_Incoming(void *v)
+static int process_incoming(void *v)
 {
 	unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles;
 	struct list_head *new_tail = NULL;
@@ -1272,7 +1243,7 @@
 	UIS_DAEMONIZE("dev_incoming");
 	for (i = 0; i < 16; i++) {
 		old_cycles = get_cycles();
-		wait_event_timeout(Wakeup_Polling_Device_Channels,
+		wait_event_timeout(poll_dev_wake_q,
 				   0, POLLJIFFIES_NORMAL);
 		cur_cycles = get_cycles();
 		if (wait_cycles == 0) {
@@ -1285,15 +1256,15 @@
 	LOGINF("wait_cycles=%llu", wait_cycles);
 	cycles_before_wait = wait_cycles;
 	idle_cycles = 0;
-	Go_Polling_Device_Channels = 0;
+	poll_dev_start = 0;
 	while (1) {
 		struct list_head *lelt, *tmp;
 		struct device_info *dev = NULL;
 
 		/* poll each channel for input */
-		down(&Lock_Polling_Device_Channels);
+		down(&poll_dev_lock);
 		new_tail = NULL;
-		list_for_each_safe(lelt, tmp, &List_Polling_Device_Channels) {
+		list_for_each_safe(lelt, tmp, &poll_dev_chan) {
 			int rc = 0;
 
 			dev = list_entry(lelt, struct device_info,
@@ -1315,22 +1286,22 @@
 					if (!
 					    (list_is_last
 					     (lelt,
-					      &List_Polling_Device_Channels))) {
+					      &poll_dev_chan))) {
 						new_tail = lelt;
 						dev->moved_to_tail_cnt++;
-					} else
+					} else {
 						dev->last_on_list_cnt++;
+					}
 				}
-
 			}
-			if (Incoming_ThreadInfo.should_stop)
+			if (incoming_ti.should_stop)
 				break;
 		}
 		if (new_tail != NULL) {
 			tot_moved_to_tail_cnt++;
-			list_move_tail(new_tail, &List_Polling_Device_Channels);
+			list_move_tail(new_tail, &poll_dev_chan);
 		}
-		up(&Lock_Polling_Device_Channels);
+		up(&poll_dev_lock);
 		cur_cycles = get_cycles();
 		delta_cycles = cur_cycles - old_cycles;
 		old_cycles = cur_cycles;
@@ -1340,24 +1311,24 @@
 		* - there is no input waiting on any of the channels
 		* - we have received a signal to stop this thread
 		*/
-		if (Incoming_ThreadInfo.should_stop)
+		if (incoming_ti.should_stop)
 			break;
 		if (en_smart_wakeup == 0xFF) {
 			LOGINF("en_smart_wakeup set to 0xff, to force exiting process_incoming");
 			break;
 		}
 		/* wait for POLLJIFFIES_NORMAL jiffies, or until
-		* someone wakes up Wakeup_Polling_Device_Channels,
+		* someone wakes up poll_dev_wake_q,
 		* whichever comes first only do a wait when we have
 		* been idle for cycles_before_wait cycles.
 		*/
 		if (idle_cycles > cycles_before_wait) {
-			Go_Polling_Device_Channels = 0;
+			poll_dev_start = 0;
 			tot_wait_cnt++;
-			wait_event_timeout(Wakeup_Polling_Device_Channels,
-					   Go_Polling_Device_Channels,
+			wait_event_timeout(poll_dev_wake_q,
+					   poll_dev_start,
 					   POLLJIFFIES_NORMAL);
-			Go_Polling_Device_Channels = 1;
+			poll_dev_start = 1;
 		} else {
 			tot_schedule_cnt++;
 			schedule();
@@ -1365,25 +1336,25 @@
 		}
 	}
 	DBGINF("exiting.\n");
-	complete_and_exit(&Incoming_ThreadInfo.has_stopped, 0);
+	complete_and_exit(&incoming_ti.has_stopped, 0);
 }
 
 static BOOL
-Initialize_incoming_thread(void)
+initialize_incoming_thread(void)
 {
-	if (Incoming_Thread_Started)
+	if (incoming_started)
 		return TRUE;
-	if (!uisthread_start(&Incoming_ThreadInfo,
-			     &Process_Incoming, NULL, "dev_incoming")) {
-		LOGERR("uisthread_start Initialize_incoming_thread ****FAILED");
+	if (!uisthread_start(&incoming_ti,
+			     &process_incoming, NULL, "dev_incoming")) {
+		LOGERR("uisthread_start initialize_incoming_thread ****FAILED");
 		return FALSE;
 	}
-	Incoming_Thread_Started = TRUE;
+	incoming_started = TRUE;
 	return TRUE;
 }
 
 /*  Add a new device/channel to the list being processed by
- *  Process_Incoming().
+ *  process_incoming().
  *  <interrupt> - indicates the function to call periodically.
  *  <interrupt_context> - indicates the data to pass to the <interrupt>
  *                        function.
@@ -1397,23 +1368,23 @@
 
 	dev = find_dev(bus_no, dev_no);
 	if (!dev) {
-		LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (bus_no),
-		       (int) (dev_no));
+		LOGERR("%s busNo=%d, devNo=%d", __func__, (int)(bus_no),
+		       (int)(dev_no));
 		return;
 	}
-	down(&Lock_Polling_Device_Channels);
-	Initialize_incoming_thread();
+	down(&poll_dev_lock);
+	initialize_incoming_thread();
 	dev->interrupt = interrupt;
 	dev->interrupt_context = interrupt_context;
 	dev->polling = TRUE;
-	list_add_tail(&(dev->list_polling_device_channels),
-		      &List_Polling_Device_Channels);
-	up(&Lock_Polling_Device_Channels);
+	list_add_tail(&dev->list_polling_device_channels,
+		      &poll_dev_chan);
+	up(&poll_dev_lock);
 }
 EXPORT_SYMBOL_GPL(uislib_enable_channel_interrupts);
 
 /*  Remove a device/channel from the list being processed by
- *  Process_Incoming().
+ *  process_incoming().
  */
 void
 uislib_disable_channel_interrupts(u32 bus_no, u32 dev_no)
@@ -1422,31 +1393,31 @@
 
 	dev = find_dev(bus_no, dev_no);
 	if (!dev) {
-		LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (bus_no),
-		       (int) (dev_no));
+		LOGERR("%s busNo=%d, devNo=%d", __func__, (int)(bus_no),
+		       (int)(dev_no));
 		return;
 	}
-	down(&Lock_Polling_Device_Channels);
+	down(&poll_dev_lock);
 	list_del(&dev->list_polling_device_channels);
 	dev->polling = FALSE;
 	dev->interrupt = NULL;
-	up(&Lock_Polling_Device_Channels);
+	up(&poll_dev_lock);
 }
 EXPORT_SYMBOL_GPL(uislib_disable_channel_interrupts);
 
 static void
 do_wakeup_polling_device_channels(struct work_struct *dummy)
 {
-	if (!Go_Polling_Device_Channels) {
-		Go_Polling_Device_Channels = 1;
-		wake_up(&Wakeup_Polling_Device_Channels);
+	if (!poll_dev_start) {
+		poll_dev_start = 1;
+		wake_up(&poll_dev_wake_q);
 	}
 }
 
-static DECLARE_WORK(Work_wakeup_polling_device_channels,
+static DECLARE_WORK(work_wakeup_polling_device_channels,
 		    do_wakeup_polling_device_channels);
 
-/*  Call this function when you want to send a hint to Process_Incoming() that
+/*  Call this function when you want to send a hint to process_incoming() that
  *  your device might have more requests.
  */
 void
@@ -1454,14 +1425,14 @@
 {
 	if (en_smart_wakeup == 0)
 		return;
-	if (Go_Polling_Device_Channels)
+	if (poll_dev_start)
 		return;
 	/* The point of using schedule_work() instead of just doing
 	 * the work inline is to force a slight delay before waking up
-	 * the Process_Incoming() thread.
+	 * the process_incoming() thread.
 	 */
 	tot_wakeup_cnt++;
-	schedule_work(&Work_wakeup_polling_device_channels);
+	schedule_work(&work_wakeup_polling_device_channels);
 }
 EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt);
 
@@ -1472,35 +1443,35 @@
 static int __init
 uislib_mod_init(void)
 {
-
 	if (!unisys_spar_platform)
 		return -ENODEV;
 
 	LOGINF("MONITORAPIS");
 
 	LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
-	       (ulong) sizeof(struct uiscmdrsp));
+	       (ulong)sizeof(struct uiscmdrsp));
 	LOGINF("sizeof(struct phys_info):%lu\n",
-	       (ulong) sizeof(struct phys_info));
+	       (ulong)sizeof(struct phys_info));
 	LOGINF("sizeof(uiscmdrsp_scsi):%lu\n",
-	       (ulong) sizeof(struct uiscmdrsp_scsi));
+	       (ulong)sizeof(struct uiscmdrsp_scsi));
 	LOGINF("sizeof(uiscmdrsp_net):%lu\n",
-	       (ulong) sizeof(struct uiscmdrsp_net));
+	       (ulong)sizeof(struct uiscmdrsp_net));
 	LOGINF("sizeof(CONTROLVM_MESSAGE):%lu bytes\n",
-	       (ulong) sizeof(struct controlvm_message));
+	       (ulong)sizeof(struct controlvm_message));
 	LOGINF("sizeof(struct spar_controlvm_channel_protocol):%lu bytes\n",
-	       (ulong) sizeof(struct spar_controlvm_channel_protocol));
+	       (ulong)sizeof(struct spar_controlvm_channel_protocol));
 	LOGINF("sizeof(CHANNEL_HEADER):%lu bytes\n",
-	       (ulong) sizeof(struct channel_header));
+	       (ulong)sizeof(struct channel_header));
 	LOGINF("sizeof(struct spar_io_channel_protocol):%lu bytes\n",
-	       (ulong) sizeof(struct spar_io_channel_protocol));
+	       (ulong)sizeof(struct spar_io_channel_protocol));
 	LOGINF("SIZEOF_CMDRSP:%lu bytes\n", SIZEOF_CMDRSP);
 	LOGINF("SIZEOF_PROTOCOL:%lu bytes\n", SIZEOF_PROTOCOL);
 
 	/* initialize global pointers to NULL */
-	BusListHead = NULL;
-	BusListCount = MaxBusCount = 0;
-	rwlock_init(&BusListLock);
+	bus_list = NULL;
+	bus_list_count = 0;
+	max_bus_count = 0;
+	rwlock_init(&bus_list_lock);
 	virt_control_chan_func = NULL;
 
 	/* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and
@@ -1515,7 +1486,7 @@
 
 		platformnumber_debugfs_read = debugfs_create_u32(
 			PLATFORMNUMBER_DEBUGFS_ENTRY_FN, 0444, dir_debugfs,
-			&PlatformNumber);
+			&platform_no);
 
 		cycles_before_wait_debugfs_read = debugfs_create_u64(
 			CYCLES_BEFORE_WAIT_DEBUGFS_ENTRY_FN, 0666, dir_debugfs,
@@ -1533,9 +1504,9 @@
 static void __exit
 uislib_mod_exit(void)
 {
-	if (ProcReadBuffer) {
-		vfree(ProcReadBuffer);
-		ProcReadBuffer = NULL;
+	if (debug_buf) {
+		vfree(debug_buf);
+		debug_buf = NULL;
 	}
 
 	debugfs_remove(info_debugfs_entry);
diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c
index f9f8442..71bb7b6 100644
--- a/drivers/staging/unisys/uislib/uisqueue.c
+++ b/drivers/staging/unisys/uislib/uisqueue.c
@@ -21,8 +21,6 @@
 
 #include "uisutils.h"
 
-#include "chanstub.h"
-
 /* this is shorter than using __FILE__ (full path name) in
  * debug/info/error messages */
 #define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
@@ -33,9 +31,202 @@
 /*****************************************************/
 /* Exported functions                                */
 /*****************************************************/
+
+/*
+ * Routine Description:
+ * Tries to insert the prebuilt signal pointed to by pSignal into the nth
+ * Queue of the Channel pointed to by pChannel
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to the signal
+ *
+ * Assumptions:
+ * - pChannel, Queue and pSignal are valid.
+ * - If insertion fails due to a full queue, the caller will determine the
+ * retry policy (e.g. wait & try again, report an error, etc.).
+ *
+ * Return value:
+ * 1 if the insertion succeeds, 0 if the queue was full.
+ */
+unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
+				 void *sig)
+{
+	void __iomem *psignal;
+	unsigned int head, tail, nof;
+
+	struct signal_queue_header __iomem *pqhdr =
+	    (struct signal_queue_header __iomem *)
+		((char __iomem *)ch + readq(&ch->ch_space_offset))
+		+ queue;
+
+	/* capture current head and tail */
+	head = readl(&pqhdr->head);
+	tail = readl(&pqhdr->tail);
+
+	/* queue is full if (head + 1) % n equals tail */
+	if (((head + 1) % readl(&pqhdr->max_slots)) == tail) {
+		nof = readq(&pqhdr->num_overflows) + 1;
+		writeq(nof, &pqhdr->num_overflows);
+		return 0;
+	}
+
+	/* increment the head index */
+	head = (head + 1) % readl(&pqhdr->max_slots);
+
+	/* copy signal to the head location from the area pointed to
+	 * by pSignal
+	 */
+	psignal = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
+		(head * readl(&pqhdr->signal_size));
+	memcpy_toio(psignal, sig, readl(&pqhdr->signal_size));
+
+	mb(); /* channel synch */
+	writel(head, &pqhdr->head);
+
+	writeq(readq(&pqhdr->num_sent) + 1, &pqhdr->num_sent);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(spar_signal_insert);
+
+/*
+ * Routine Description:
+ * Removes one signal from Channel pChannel's nth Queue at the
+ * time of the call and copies it into the memory pointed to by
+ * pSignal.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold queue's SignalSize
+ *
+ * Return value:
+ * 1 if the removal succeeds, 0 if the queue was empty.
+ */
+unsigned char
+spar_signal_remove(struct channel_header __iomem *ch, u32 queue, void *sig)
+{
+	void __iomem *psource;
+	unsigned int head, tail;
+	struct signal_queue_header __iomem *pqhdr =
+	    (struct signal_queue_header __iomem *)((char __iomem *)ch +
+				    readq(&ch->ch_space_offset)) + queue;
+
+	/* capture current head and tail */
+	head = readl(&pqhdr->head);
+	tail = readl(&pqhdr->tail);
+
+	/* queue is empty if the head index equals the tail index */
+	if (head == tail) {
+		writeq(readq(&pqhdr->num_empty) + 1, &pqhdr->num_empty);
+		return 0;
+	}
+
+	/* advance past the 'empty' front slot */
+	tail = (tail + 1) % readl(&pqhdr->max_slots);
+
+	/* copy signal from tail location to the area pointed to by pSignal */
+	psource = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
+		(tail * readl(&pqhdr->signal_size));
+	memcpy_fromio(sig, psource, readl(&pqhdr->signal_size));
+
+	mb(); /* channel synch */
+	writel(tail, &pqhdr->tail);
+
+	writeq(readq(&pqhdr->num_received) + 1,
+	       &pqhdr->num_received);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(spar_signal_remove);
+
+/*
+ * Routine Description:
+ * Removes all signals present in Channel pChannel's nth Queue at the
+ * time of the call and copies them into the memory pointed to by
+ * pSignal.  Returns the # of signals copied as the value of the routine.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold Queue's MaxSignals
+ * # of signals, each of which is Queue's SignalSize.
+ *
+ * Return value:
+ * # of signals copied.
+ */
+unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
+				    void *sig)
+{
+	void *psource;
+	unsigned int head, tail, count = 0;
+	struct signal_queue_header *pqhdr =
+	    (struct signal_queue_header *)((char *)ch +
+				    ch->ch_space_offset) + queue;
+
+	/* capture current head and tail */
+	head = pqhdr->head;
+	tail = pqhdr->tail;
+
+	/* queue is empty if the head index equals the tail index */
+	if (head == tail)
+		return 0;
+
+	while (head != tail) {
+		/* advance past the 'empty' front slot */
+		tail = (tail + 1) % pqhdr->max_slots;
+
+		/* copy signal from tail location to the area pointed
+		 * to by pSignal
+		 */
+		psource =
+		    (char *)pqhdr + pqhdr->sig_base_offset +
+		    (tail * pqhdr->signal_size);
+		memcpy((char *)sig + (pqhdr->signal_size * count),
+		       psource, pqhdr->signal_size);
+
+		mb(); /* channel synch */
+		pqhdr->tail = tail;
+
+		count++;
+		pqhdr->num_received++;
+	}
+
+	return count;
+}
+
+/*
+ * Routine Description:
+ * Determine whether a signal queue is empty.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ *
+ * Return value:
+ * 1 if the signal queue is empty, 0 otherwise.
+ */
+unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
+				     u32 queue)
+{
+	struct signal_queue_header __iomem *pqhdr =
+	    (struct signal_queue_header __iomem *)((char __iomem *)ch +
+				    readq(&ch->ch_space_offset)) + queue;
+	return readl(&pqhdr->head) == readl(&pqhdr->tail);
+}
+EXPORT_SYMBOL_GPL(spar_signalqueue_empty);
+
 unsigned long long
 uisqueue_interlocked_or(unsigned long long __iomem *tgt,
-		       unsigned long long set)
+			unsigned long long set)
 {
 	unsigned long long i;
 	unsigned long long j;
@@ -53,7 +244,7 @@
 
 unsigned long long
 uisqueue_interlocked_and(unsigned long long __iomem *tgt,
-			unsigned long long set)
+			 unsigned long long set)
 {
 	unsigned long long i;
 	unsigned long long j;
@@ -72,22 +263,21 @@
 static u8
 do_locked_client_insert(struct uisqueue_info *queueinfo,
 			unsigned int whichqueue,
-			void *pSignal,
+			void *signal,
 			spinlock_t *lock,
-			unsigned char issueInterruptIfEmpty,
-			u64 interruptHandle, u8 *channelId)
+			u8 *channel_id)
 {
 	unsigned long flags;
 	u8 rc = 0;
 
 	spin_lock_irqsave(lock, flags);
-	if (!spar_channel_client_acquire_os(queueinfo->chan, channelId))
+	if (!spar_channel_client_acquire_os(queueinfo->chan, channel_id))
 		goto unlock;
-	if (spar_signal_insert(queueinfo->chan, whichqueue, pSignal)) {
+	if (spar_signal_insert(queueinfo->chan, whichqueue, signal)) {
 		queueinfo->packets_sent++;
 		rc = 1;
 	}
-	spar_channel_client_release_os(queueinfo->chan, channelId);
+	spar_channel_client_release_os(queueinfo->chan, channel_id);
 unlock:
 	spin_unlock_irqrestore((spinlock_t *)lock, flags);
 	return rc;
@@ -103,9 +293,8 @@
 				     char oktowait, u8 *channel_id)
 {
 	while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
-					(spinlock_t *) insertlock,
-					issue_irq_if_empty,
-					irq_handle, channel_id)) {
+					(spinlock_t *)insertlock,
+					channel_id)) {
 		if (oktowait != OK_TO_WAIT) {
 			LOGERR("****FAILED visor_signal_insert failed; cannot wait; insert aborted\n");
 			return 0;	/* failed to queue */
diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c
index c0fc812..25adf1a 100644
--- a/drivers/staging/unisys/uislib/uisthread.c
+++ b/drivers/staging/unisys/uislib/uisthread.c
@@ -53,7 +53,6 @@
 	wake_up_process(thrinfo->task);
 	LOGINF("started thread pid:%d\n", thrinfo->id);
 	return 1;
-
 }
 EXPORT_SYMBOL_GPL(uisthread_start);
 
diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c
index 4a5b867..31318d2 100644
--- a/drivers/staging/unisys/uislib/uisutils.c
+++ b/drivers/staging/unisys/uislib/uisutils.c
@@ -42,14 +42,13 @@
 					 * uisctrl_register_req_handler() or
 					 * uisctrl_register_req_handler_ex() */
 
-
 /*****************************************************/
 /* Utility functions                                 */
 /*****************************************************/
 
 int
 uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
-		      char *format, ...)
+			 char *format, ...)
 {
 	va_list args;
 	int len;
@@ -57,6 +56,7 @@
 	DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
 	va_start(args, format);
 	len = vsnprintf(*buffer, *buffer_remaining, format, args);
+	va_end(args);
 	if (len >= *buffer_remaining) {
 		*buffer += *buffer_remaining;
 		*total += *buffer_remaining;
@@ -96,7 +96,7 @@
 	}
 	if (chipset_driver_info)
 		bus_device_info_init(chipset_driver_info, "chipset", "uislib",
-				   VERSION, NULL);
+				     VERSION, NULL);
 
 	return 1;
 }
@@ -113,66 +113,57 @@
 						u32 client_str_len, u64 bytes),
 			struct ultra_vbus_deviceinfo *chipset_driver_info)
 {
-	struct req_handler_info *pReqHandlerInfo;
-	int rc = 0;		/* assume failure */
+	struct req_handler_info *req_handler;
 
 	LOGINF("type=%pUL, controlfunc=0x%p.\n",
 	       &switch_uuid, controlfunc);
 	if (!controlfunc) {
 		LOGERR("%pUL: controlfunc must be supplied\n", &switch_uuid);
-		goto Away;
+		return 0;
 	}
 	if (!server_channel_ok) {
 		LOGERR("%pUL: Server_Channel_Ok must be supplied\n",
 				&switch_uuid);
-		goto Away;
+		return 0;
 	}
 	if (!server_channel_init) {
 		LOGERR("%pUL: Server_Channel_Init must be supplied\n",
 				&switch_uuid);
-		goto Away;
+		return 0;
 	}
-	pReqHandlerInfo = req_handler_add(switch_uuid,
-					switch_type_name,
-					controlfunc,
-					min_channel_bytes,
-					server_channel_ok, server_channel_init);
-	if (!pReqHandlerInfo) {
+	req_handler = req_handler_add(switch_uuid,
+				      switch_type_name,
+				      controlfunc,
+				      min_channel_bytes,
+				      server_channel_ok, server_channel_init);
+	if (!req_handler) {
 		LOGERR("failed to add %pUL to server list\n", &switch_uuid);
-		goto Away;
+		return 0;
 	}
 
 	atomic_inc(&uisutils_registered_services);
-	rc = 1;			/* success */
-Away:
-	if (rc) {
-		if (chipset_driver_info)
-			bus_device_info_init(chipset_driver_info, "chipset",
-					   "uislib", VERSION, NULL);
-	} else
-		LOGERR("failed to register type %pUL.\n", &switch_uuid);
+	if (chipset_driver_info) {
+		bus_device_info_init(chipset_driver_info, "chipset",
+				     "uislib", VERSION, NULL);
+		return 1;
+	}
 
-	return rc;
+	LOGERR("failed to register type %pUL.\n", &switch_uuid);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
 
 int
 uisctrl_unregister_req_handler_ex(uuid_le switch_uuid)
 {
-	int rc = 0;		/* assume failure */
-
 	LOGINF("type=%pUL.\n", &switch_uuid);
 	if (req_handler_del(switch_uuid) < 0) {
 		LOGERR("failed to remove %pUL from server list\n",
-				&switch_uuid);
-		goto Away;
+		       &switch_uuid);
+		return 0;
 	}
 	atomic_dec(&uisutils_registered_services);
-	rc = 1;			/* success */
-Away:
-	if (!rc)
-		LOGERR("failed to unregister type %pUL.\n", &switch_uuid);
-	return rc;
+	return 1;
 }
 EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
 
@@ -214,10 +205,10 @@
 		frags[count].pi_pfn =
 		    page_to_pfn(virt_to_page(skb->data + offset));
 		frags[count].pi_off =
-		    (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
+		    (unsigned long)(skb->data + offset) & PI_PAGE_MASK;
 		size =
 		    min(firstfraglen,
-			(unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
+			(unsigned int)(PI_PAGE_SIZE - frags[count].pi_off));
 		/* can take smallest of firstfraglen(what's left) OR
 		* bytes left in the page
 		*/
@@ -231,7 +222,7 @@
 
 	if ((count + numfrags) > frags_max) {
 		LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
-		     calling_ctx, frags_max, count + numfrags);
+		       calling_ctx, frags_max, count + numfrags);
 		return -1;	/* failure */
 	}
 
@@ -255,7 +246,6 @@
 
 		for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
 		     skbinlist = skbinlist->next) {
-
 			c = uisutil_copy_fragsinfo_from_skb("recursive",
 				skbinlist,
 				skbinlist->len - skbinlist->data_len,
@@ -272,17 +262,18 @@
 }
 EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
 
-static LIST_HEAD(ReqHandlerInfo_list);	/* list of struct req_handler_info */
-static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
+static LIST_HEAD(req_handler_info_list); /* list of struct req_handler_info */
+static DEFINE_SPINLOCK(req_handler_info_list_lock);
 
 struct req_handler_info *
 req_handler_add(uuid_le switch_uuid,
 	      const char *switch_type_name,
 	      int (*controlfunc)(struct io_msgs *),
 	      unsigned long min_channel_bytes,
-	      int (*Server_Channel_Ok)(unsigned long channelBytes),
-	      int (*Server_Channel_Init)
-	       (void *x, unsigned char *clientStr, u32 clientStrLen, u64 bytes))
+	      int (*server_channel_ok)(unsigned long channel_bytes),
+	      int (*server_channel_init)
+	       (void *x, unsigned char *clientstr, u32 clientstr_len,
+		u64 bytes))
 {
 	struct req_handler_info *rc = NULL;
 
@@ -292,14 +283,14 @@
 	rc->switch_uuid = switch_uuid;
 	rc->controlfunc = controlfunc;
 	rc->min_channel_bytes = min_channel_bytes;
-	rc->server_channel_ok = Server_Channel_Ok;
-	rc->server_channel_init = Server_Channel_Init;
+	rc->server_channel_ok = server_channel_ok;
+	rc->server_channel_init = server_channel_init;
 	if (switch_type_name)
 		strncpy(rc->switch_type_name, switch_type_name,
 			sizeof(rc->switch_type_name) - 1);
-	spin_lock(&ReqHandlerInfo_list_lock);
-	list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
-	spin_unlock(&ReqHandlerInfo_list_lock);
+	spin_lock(&req_handler_info_list_lock);
+	list_add_tail(&rc->list_link, &req_handler_info_list);
+	spin_unlock(&req_handler_info_list_lock);
 
 	return rc;
 }
@@ -310,15 +301,15 @@
 	struct list_head *lelt, *tmp;
 	struct req_handler_info *entry = NULL;
 
-	spin_lock(&ReqHandlerInfo_list_lock);
-	list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+	spin_lock(&req_handler_info_list_lock);
+	list_for_each_safe(lelt, tmp, &req_handler_info_list) {
 		entry = list_entry(lelt, struct req_handler_info, list_link);
 		if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
-			spin_unlock(&ReqHandlerInfo_list_lock);
+			spin_unlock(&req_handler_info_list_lock);
 			return entry;
 		}
 	}
-	spin_unlock(&ReqHandlerInfo_list_lock);
+	spin_unlock(&req_handler_info_list_lock);
 	return NULL;
 }
 
@@ -329,8 +320,8 @@
 	struct req_handler_info *entry = NULL;
 	int rc = -1;
 
-	spin_lock(&ReqHandlerInfo_list_lock);
-	list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+	spin_lock(&req_handler_info_list_lock);
+	list_for_each_safe(lelt, tmp, &req_handler_info_list) {
 		entry = list_entry(lelt, struct req_handler_info, list_link);
 		if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
 			list_del(lelt);
@@ -338,6 +329,6 @@
 			rc++;
 		}
 	}
-	spin_unlock(&ReqHandlerInfo_list_lock);
+	spin_unlock(&req_handler_info_list_lock);
 	return rc;
 }
diff --git a/drivers/staging/unisys/virthba/Kconfig b/drivers/staging/unisys/virthba/Kconfig
index c0d7986..9af98fc 100644
--- a/drivers/staging/unisys/virthba/Kconfig
+++ b/drivers/staging/unisys/virthba/Kconfig
@@ -4,7 +4,7 @@
 
 config UNISYS_VIRTHBA
 	tristate "Unisys virthba driver"
-	depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && UNISYS_UISLIB && UNISYS_VIRTPCI && SCSI
+	depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_UISLIB && UNISYS_VIRTPCI && SCSI
 	---help---
 	If you say Y here, you will enable the Unisys virthba driver.
 
diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c
index d7a629b..e6ecea5 100644
--- a/drivers/staging/unisys/virthba/virthba.c
+++ b/drivers/staging/unisys/virthba/virthba.c
@@ -85,7 +85,8 @@
 static const char *virthba_get_info(struct Scsi_Host *shp);
 static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
-				     void (*virthba_cmnd_done)(struct scsi_cmnd *));
+				     void (*virthba_cmnd_done)
+					   (struct scsi_cmnd *));
 
 static const struct x86_cpu_id unisys_spar_ids[] = {
 	{ X86_VENDOR_INTEL, 6, 62, X86_FEATURE_ANY },
@@ -107,19 +108,20 @@
 static int process_incoming_rsps(void *);
 static int virthba_serverup(struct virtpci_dev *virtpcidev);
 static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
-static void doDiskAddRemove(struct work_struct *work);
+static void do_disk_add_remove(struct work_struct *work);
 static void virthba_serverdown_complete(struct work_struct *work);
 static ssize_t info_debugfs_read(struct file *file, char __user *buf,
-			size_t len, loff_t *offset);
+				 size_t len, loff_t *offset);
 static ssize_t enable_ints_write(struct file *file,
-			const char __user *buffer, size_t count, loff_t *ppos);
+				 const char __user *buffer, size_t count,
+				 loff_t *ppos);
 
 /*****************************************************/
 /* Globals                                           */
 /*****************************************************/
 
 static int rsltq_wait_usecs = 4000;	/* Default 4ms */
-static unsigned int MaxBuffLen;
+static unsigned int max_buff_len;
 
 /* Module options */
 static char *virthba_options = "NONE";
@@ -165,6 +167,7 @@
 	atomic_t error_count;
 	struct virtdisk_info *next;
 };
+
 /* Each Scsi_Host has a host_data area that contains this struct. */
 struct virthba_info {
 	struct Scsi_Host *scsihost;
@@ -193,7 +196,7 @@
 	struct virtdisk_info head;
 };
 
-/* Work Data for DARWorkQ */
+/* Work Data for dar_work_queue */
 struct diskaddremove {
 	u8 add;			/* 0-remove, 1-add */
 	struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
@@ -244,7 +247,7 @@
 
 #define VIRTHBASOPENMAX 1
 /* array of open devices maintained by open() and close(); */
-static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX];
+static struct virthba_devices_open virthbas_open[VIRTHBASOPENMAX];
 static struct dentry *virthba_debugfs_dir;
 
 /*****************************************************/
@@ -260,7 +263,7 @@
 	insert_location = vhbainfo->nextinsert;
 	while (vhbainfo->pending[insert_location].sent != NULL) {
 		insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
-		if (insert_location == (int) vhbainfo->nextinsert) {
+		if (insert_location == (int)vhbainfo->nextinsert) {
 			LOGERR("Queue should be full. insert_location<<%d>>  Unable to find open slot for pending commands.\n",
 			     insert_location);
 			spin_unlock_irqrestore(&vhbainfo->privlock, flags);
@@ -289,7 +292,7 @@
 		insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
 	}
 
-	return (unsigned int) insert_location;
+	return (unsigned int)insert_location;
 }
 
 static void *
@@ -300,13 +303,13 @@
 
 	if (del >= MAX_PENDING_REQUESTS) {
 		LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n",
-		     (unsigned long) del, MAX_PENDING_REQUESTS);
+		     (unsigned long)del, MAX_PENDING_REQUESTS);
 	} else {
 		spin_lock_irqsave(&vhbainfo->privlock, flags);
 
 		if (vhbainfo->pending[del].sent == NULL)
 			LOGERR("Deleting already cleared queue entry at <<%lu>>.\n",
-			     (unsigned long) del);
+			     (unsigned long)del);
 
 		sent = vhbainfo->pending[del].sent;
 
@@ -318,30 +321,30 @@
 	return sent;
 }
 
-/* DARWorkQ (Disk Add/Remove) */
-static struct work_struct DARWorkQ;
-static struct diskaddremove *DARWorkQHead;
-static spinlock_t DARWorkQLock;
-static unsigned short DARWorkQSched;
+/* dar_work_queue (Disk Add/Remove) */
+static struct work_struct dar_work_queue;
+static struct diskaddremove *dar_work_queue_head;
+static spinlock_t dar_work_queue_lock;
+static unsigned short dar_work_queue_sched;
 #define QUEUE_DISKADDREMOVE(dar) { \
-	spin_lock_irqsave(&DARWorkQLock, flags); \
-	if (!DARWorkQHead) { \
-		DARWorkQHead = dar; \
+	spin_lock_irqsave(&dar_work_queue_lock, flags); \
+	if (!dar_work_queue_head) { \
+		dar_work_queue_head = dar; \
 		dar->next = NULL; \
 	} \
 	else { \
-		dar->next = DARWorkQHead; \
-		DARWorkQHead = dar; \
+		dar->next = dar_work_queue_head; \
+		dar_work_queue_head = dar; \
 	} \
-	if (!DARWorkQSched) { \
-		schedule_work(&DARWorkQ); \
-		DARWorkQSched = 1; \
+	if (!dar_work_queue_sched) { \
+		schedule_work(&dar_work_queue); \
+		dar_work_queue_sched = 1; \
 	} \
-	spin_unlock_irqrestore(&DARWorkQLock, flags); \
+	spin_unlock_irqrestore(&dar_work_queue_lock, flags); \
 }
 
 static inline void
-SendDiskAddRemove(struct diskaddremove *dar)
+send_disk_add_remove(struct diskaddremove *dar)
 {
 	struct scsi_device *sdev;
 	int error;
@@ -365,31 +368,31 @@
 }
 
 /*****************************************************/
-/* DARWorkQ Handler Thread                           */
+/* dar_work_queue Handler Thread                     */
 /*****************************************************/
 static void
-doDiskAddRemove(struct work_struct *work)
+do_disk_add_remove(struct work_struct *work)
 {
 	struct diskaddremove *dar;
 	struct diskaddremove *tmphead;
 	int i = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&DARWorkQLock, flags);
-	tmphead = DARWorkQHead;
-	DARWorkQHead = NULL;
-	DARWorkQSched = 0;
-	spin_unlock_irqrestore(&DARWorkQLock, flags);
+	spin_lock_irqsave(&dar_work_queue_lock, flags);
+	tmphead = dar_work_queue_head;
+	dar_work_queue_head = NULL;
+	dar_work_queue_sched = 0;
+	spin_unlock_irqrestore(&dar_work_queue_lock, flags);
 	while (tmphead) {
 		dar = tmphead;
 		tmphead = dar->next;
-		SendDiskAddRemove(dar);
+		send_disk_add_remove(dar);
 		i++;
 	}
 }
 
 /*****************************************************/
-/* Routine to add entry to DARWorkQ                  */
+/* Routine to add entry to dar_work_queue            */
 /*****************************************************/
 static void
 process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
@@ -397,7 +400,7 @@
 	struct diskaddremove *dar;
 	unsigned long flags;
 
-	dar = kzalloc(sizeof(struct diskaddremove), GFP_ATOMIC);
+	dar = kzalloc(sizeof(*dar), GFP_ATOMIC);
 	if (dar) {
 		dar->add = cmdrsp->disknotify.add;
 		dar->shost = shost;
@@ -416,10 +419,10 @@
 /* Probe Remove Functions                            */
 /*****************************************************/
 static irqreturn_t
-virthba_ISR(int irq, void *dev_id)
+virthba_isr(int irq, void *dev_id)
 {
-	struct virthba_info *virthbainfo = (struct virthba_info *) dev_id;
-	struct channel_header __iomem *pChannelHeader;
+	struct virthba_info *virthbainfo = (struct virthba_info *)dev_id;
+	struct channel_header __iomem *channel_header;
 	struct signal_queue_header __iomem *pqhdr;
 	u64 mask;
 	unsigned long long rc1;
@@ -427,23 +430,23 @@
 	if (virthbainfo == NULL)
 		return IRQ_NONE;
 	virthbainfo->interrupts_rcvd++;
-	pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
-	if (((readq(&pChannelHeader->features)
-	      & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0)
-	    && ((readq(&pChannelHeader->features) &
+	channel_header = virthbainfo->chinfo.queueinfo->chan;
+	if (((readq(&channel_header->features)
+	      & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0) &&
+	     ((readq(&channel_header->features) &
 		 ULTRA_IO_DRIVER_DISABLES_INTS) !=
 		0)) {
 		virthbainfo->interrupts_disabled++;
 		mask = ~ULTRA_CHANNEL_ENABLE_INTS;
 		rc1 = uisqueue_interlocked_and(virthbainfo->flags_addr, mask);
 	}
-	if (spar_signalqueue_empty(pChannelHeader, IOCHAN_FROM_IOPART)) {
+	if (spar_signalqueue_empty(channel_header, IOCHAN_FROM_IOPART)) {
 		virthbainfo->interrupts_notme++;
 		return IRQ_NONE;
 	}
 	pqhdr = (struct signal_queue_header __iomem *)
-		((char __iomem *) pChannelHeader +
-		 readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
+		((char __iomem *)channel_header +
+		 readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
 	writeq(readq(&pqhdr->num_irq_received) + 1,
 	       &pqhdr->num_irq_received);
 	atomic_set(&virthbainfo->interrupt_rcvd, 1);
@@ -459,8 +462,8 @@
 	struct virthba_info *virthbainfo;
 	int rsp;
 	int i;
-	irq_handler_t handler = virthba_ISR;
-	struct channel_header __iomem *pChannelHeader;
+	irq_handler_t handler = virthba_isr;
+	struct channel_header __iomem *channel_header;
 	struct signal_queue_header __iomem *pqhdr;
 	u64 mask;
 
@@ -476,7 +479,7 @@
 	 * instance - this virthba that has just been created is an
 	 * instance of a scsi host adapter. This scsi_host_alloc
 	 * function allocates a new Scsi_Host struct & performs basic
-	 * initializatoin.  The host is not published to the scsi
+	 * initialization.  The host is not published to the scsi
 	 * midlayer until scsi_add_host is called.
 	 */
 	DBGINF("calling scsi_host_alloc.\n");
@@ -501,19 +504,19 @@
 	 * the max-channel value.
 	 */
 	LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n",
-	     (unsigned) virtpcidev->scsi.max.max_channel - 1,
-	     (unsigned) virtpcidev->scsi.max.max_id,
-	     (unsigned) virtpcidev->scsi.max.max_lun,
-	     (unsigned) virtpcidev->scsi.max.cmd_per_lun,
-	     (unsigned) virtpcidev->scsi.max.max_io_size);
-	scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel;
-	scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id;
-	scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun;
-	scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun;
+	     (unsigned)virtpcidev->scsi.max.max_channel - 1,
+	     (unsigned)virtpcidev->scsi.max.max_id,
+	     (unsigned)virtpcidev->scsi.max.max_lun,
+	     (unsigned)virtpcidev->scsi.max.cmd_per_lun,
+	     (unsigned)virtpcidev->scsi.max.max_io_size);
+	scsihost->max_channel = (unsigned)virtpcidev->scsi.max.max_channel;
+	scsihost->max_id = (unsigned)virtpcidev->scsi.max.max_id;
+	scsihost->max_lun = (unsigned)virtpcidev->scsi.max.max_lun;
+	scsihost->cmd_per_lun = (unsigned)virtpcidev->scsi.max.cmd_per_lun;
 	scsihost->max_sectors =
-	    (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9);
+	    (unsigned short)(virtpcidev->scsi.max.max_io_size >> 9);
 	scsihost->sg_tablesize =
-	    (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
+	    (unsigned short)(virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
 	if (scsihost->sg_tablesize > MAX_PHYS_INFO)
 		scsihost->sg_tablesize = MAX_PHYS_INFO;
 	LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%llu, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
@@ -544,11 +547,11 @@
 		return -ENODEV;
 	}
 
-	virthbainfo = (struct virthba_info *) scsihost->hostdata;
+	virthbainfo = (struct virthba_info *)scsihost->hostdata;
 	memset(virthbainfo, 0, sizeof(struct virthba_info));
 	for (i = 0; i < VIRTHBASOPENMAX; i++) {
-		if (VirtHbasOpen[i].virthbainfo == NULL) {
-			VirtHbasOpen[i].virthbainfo = virthbainfo;
+		if (virthbas_open[i].virthbainfo == NULL) {
+			virthbas_open[i].virthbainfo = virthbainfo;
 			break;
 		}
 	}
@@ -584,10 +587,10 @@
 	DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n",
 	       virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo);
 
-	pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
+	channel_header = virthbainfo->chinfo.queueinfo->chan;
 	pqhdr = (struct signal_queue_header __iomem *)
-		((char __iomem *)pChannelHeader +
-		 readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
+		((char __iomem *)channel_header +
+		 readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
 	virthbainfo->flags_addr = &pqhdr->features;
 
 	if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
@@ -646,11 +649,11 @@
 {
 	struct virthba_info *virthbainfo;
 	struct Scsi_Host *scsihost =
-	    (struct Scsi_Host *) virtpcidev->scsi.scsihost;
+	    (struct Scsi_Host *)virtpcidev->scsi.scsihost;
 
 	LOGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
 	       virtpcidev->device_no);
-	virthbainfo = (struct virthba_info *) scsihost->hostdata;
+	virthbainfo = (struct virthba_info *)scsihost->hostdata;
 	if (virthbainfo->interrupt_vector != -1)
 		free_irq(virthbainfo->interrupt_vector, virthbainfo);
 	LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev,
@@ -679,7 +682,7 @@
 {
 	struct uiscmdrsp *cmdrsp;
 	struct virthba_info *virthbainfo =
-	    (struct virthba_info *) scsihost->hostdata;
+	    (struct virthba_info *)scsihost->hostdata;
 	int notifyresult = 0xffff;
 	wait_queue_head_t notifyevent;
 
@@ -706,8 +709,8 @@
 	/* specify the event that has to be triggered when this cmd is
 	 * complete
 	 */
-	cmdrsp->vdiskmgmt.notify = (void *) &notifyevent;
-	cmdrsp->vdiskmgmt.notifyresult = (void *) &notifyresult;
+	cmdrsp->vdiskmgmt.notify = (void *)&notifyevent;
+	cmdrsp->vdiskmgmt.notifyresult = (void *)&notifyresult;
 
 	/* save destination */
 	cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
@@ -715,14 +718,14 @@
 	cmdrsp->vdiskmgmt.vdest.id = vdest->id;
 	cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
 	cmdrsp->vdiskmgmt.scsicmd =
-	    (void *) (uintptr_t)
+	    (void *)(uintptr_t)
 		add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
-						(void *) cmdrsp);
+						(void *)cmdrsp);
 
 	uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
 					     cmdrsp, IOCHAN_TO_IOPART,
 					     &virthbainfo->chinfo.insertlock,
-					     DONT_ISSUE_INTERRUPT, (u64) NULL,
+					     DONT_ISSUE_INTERRUPT, (u64)NULL,
 					     OK_TO_WAIT, "vhba");
 	LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n",
 	       cmdrsp->scsitaskmgmt.notify);
@@ -742,7 +745,7 @@
 {
 	struct uiscmdrsp *cmdrsp;
 	struct virthba_info *virthbainfo =
-	    (struct virthba_info *) scsidev->host->hostdata;
+	    (struct virthba_info *)scsidev->host->hostdata;
 	int notifyresult = 0xffff;
 	wait_queue_head_t notifyevent;
 
@@ -767,8 +770,8 @@
 	cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
 	/* specify the event that has to be triggered when this */
 	/* cmd is complete */
-	cmdrsp->scsitaskmgmt.notify = (void *) &notifyevent;
-	cmdrsp->scsitaskmgmt.notifyresult = (void *) &notifyresult;
+	cmdrsp->scsitaskmgmt.notify = (void *)&notifyevent;
+	cmdrsp->scsitaskmgmt.notifyresult = (void *)&notifyresult;
 
 	/* save destination */
 	cmdrsp->scsitaskmgmt.tasktype = tasktype;
@@ -776,15 +779,15 @@
 	cmdrsp->scsitaskmgmt.vdest.id = scsidev->id;
 	cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun;
 	cmdrsp->scsitaskmgmt.scsicmd =
-	    (void *) (uintptr_t)
+	    (void *)(uintptr_t)
 		add_scsipending_entry_with_wait(virthbainfo,
 						CMD_SCSITASKMGMT_TYPE,
-						(void *) cmdrsp);
+						(void *)cmdrsp);
 
 	uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
 					     cmdrsp, IOCHAN_TO_IOPART,
 					     &virthbainfo->chinfo.insertlock,
-					     DONT_ISSUE_INTERRUPT, (u64) NULL,
+					     DONT_ISSUE_INTERRUPT, (u64)NULL,
 					     OK_TO_WAIT, "vhba");
 	LOGINF("TaskMgmt waiting on event notifyevent=0x%p\n",
 	       cmdrsp->scsitaskmgmt.notify);
@@ -805,11 +808,11 @@
 	struct virtdisk_info *vdisk;
 
 	scsidev = scsicmd->device;
-	for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+	for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
 	     vdisk->next; vdisk = vdisk->next) {
-		if ((scsidev->channel == vdisk->channel)
-		    && (scsidev->id == vdisk->id)
-		    && (scsidev->lun == vdisk->lun)) {
+		if ((scsidev->channel == vdisk->channel) &&
+		    (scsidev->id == vdisk->id) &&
+		    (scsidev->lun == vdisk->lun)) {
 			if (atomic_read(&vdisk->error_count) <
 			    VIRTHBA_ERROR_COUNT) {
 				atomic_inc(&vdisk->error_count);
@@ -831,11 +834,11 @@
 	struct virtdisk_info *vdisk;
 
 	scsidev = scsicmd->device;
-	for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+	for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
 	     vdisk->next; vdisk = vdisk->next) {
-		if ((scsidev->channel == vdisk->channel)
-		    && (scsidev->id == vdisk->id)
-		    && (scsidev->lun == vdisk->lun)) {
+		if ((scsidev->channel == vdisk->channel) &&
+		    (scsidev->id == vdisk->id) &&
+		    (scsidev->lun == vdisk->lun)) {
 			if (atomic_read(&vdisk->error_count) <
 			    VIRTHBA_ERROR_COUNT) {
 				atomic_inc(&vdisk->error_count);
@@ -857,11 +860,11 @@
 	struct virtdisk_info *vdisk;
 
 	scsidev = scsicmd->device;
-	for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+	for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
 	     vdisk->next; vdisk = vdisk->next) {
-		if ((scsidev->channel == vdisk->channel)
-		    && (scsidev->id == vdisk->id)
-		    && (scsidev->lun == vdisk->lun)) {
+		if ((scsidev->channel == vdisk->channel) &&
+		    (scsidev->id == vdisk->id) &&
+		    (scsidev->lun == vdisk->lun)) {
 			if (atomic_read(&vdisk->error_count) <
 			    VIRTHBA_ERROR_COUNT) {
 				atomic_inc(&vdisk->error_count);
@@ -915,7 +918,7 @@
 	struct uiscmdrsp *cmdrsp;
 	unsigned int i;
 	struct virthba_info *virthbainfo =
-	    (struct virthba_info *) scsihost->hostdata;
+	    (struct virthba_info *)scsihost->hostdata;
 	struct scatterlist *sg = NULL;
 	struct scatterlist *sgl = NULL;
 	int sg_failed = 0;
@@ -940,9 +943,9 @@
 	 * will return the scsicmd pointer for completion
 	 */
 	insert_location =
-	    add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *) scsicmd);
+	    add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *)scsicmd);
 	if (insert_location != -1) {
-		cmdrsp->scsi.scsicmd = (void *) (uintptr_t) insert_location;
+		cmdrsp->scsi.scsicmd = (void *)(uintptr_t)insert_location;
 	} else {
 		LOGERR("Queue is full. Returning busy.\n");
 		kfree(cmdrsp);
@@ -961,13 +964,13 @@
 	cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd);
 
 	/* keep track of the max buffer length so far. */
-	if (cmdrsp->scsi.bufflen > MaxBuffLen)
-		MaxBuffLen = cmdrsp->scsi.bufflen;
+	if (cmdrsp->scsi.bufflen > max_buff_len)
+		max_buff_len = cmdrsp->scsi.bufflen;
 
 	if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
 		LOGERR("scsicmd use_sg:%d greater than MAX:%d\n",
 		       scsi_sg_count(scsicmd), MAX_PHYS_INFO);
-		del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+		del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
 		kfree(cmdrsp);
 		return 1;	/* reject the command */
 	}
@@ -989,22 +992,21 @@
 		sgl = scsi_sglist(scsicmd);
 
 		for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
-
 			cmdrsp->scsi.gpi_list[i].address = sg_phys(sg);
 			cmdrsp->scsi.gpi_list[i].length = sg->length;
 			if ((i != 0) && (sg->offset != 0))
 				LOGINF("Offset on a sg_entry other than zero =<<%d>>.\n",
-				     sg->offset);
+				       sg->offset);
 		}
 
 		if (sg_failed) {
 			LOGERR("Start sg_list dump (entries %d, bufflen %d)...\n",
-			     scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
+			       scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
 			for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
 				LOGERR("   Entry(%d): page->[0x%p], phys->[0x%Lx], off(%d), len(%d)\n",
-				     i, sg_page(sg),
-				     (unsigned long long) sg_phys(sg),
-				     sg->offset, sg->length);
+				       i, sg_page(sg),
+				       (unsigned long long)sg_phys(sg),
+				       sg->offset, sg->length);
 			}
 			LOGERR("Done sg_list dump.\n");
 			/* BUG(); ***** For now, let it fail in uissd
@@ -1022,12 +1024,12 @@
 						 &virthbainfo->chinfo.
 						 insertlock,
 						 DONT_ISSUE_INTERRUPT,
-						 (u64) NULL, DONT_WAIT, "vhba");
+						 (u64)NULL, DONT_WAIT, "vhba");
 	if (i == 0) {
 		/* queue must be full - and we said don't wait - return busy */
 		LOGERR("uisqueue_put_cmdrsp_with_lock ****FAILED\n");
 		kfree(cmdrsp);
-		del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+		del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 	}
 
@@ -1047,9 +1049,9 @@
 	struct virtdisk_info *vdisk;
 	struct virtdisk_info *tmpvdisk;
 	struct virthba_info *virthbainfo;
-	struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+	struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
 
-	virthbainfo = (struct virthba_info *) scsihost->hostdata;
+	virthbainfo = (struct virthba_info *)scsihost->hostdata;
 	if (!virthbainfo) {
 		LOGERR("Could not find virthba_info for scsihost\n");
 		return 0;	/* even though we errored, treat as success */
@@ -1061,7 +1063,7 @@
 		    (vdisk->next->lun == scsidev->lun))
 			return 0;
 	}
-	tmpvdisk = kzalloc(sizeof(struct virtdisk_info), GFP_ATOMIC);
+	tmpvdisk = kzalloc(sizeof(*tmpvdisk), GFP_ATOMIC);
 	if (!tmpvdisk) {	/* error allocating */
 		LOGERR("Could not allocate memory for disk\n");
 		return 0;
@@ -1089,9 +1091,9 @@
 	 */
 	struct virtdisk_info *vdisk, *delvdisk;
 	struct virthba_info *virthbainfo;
-	struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+	struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
 
-	virthbainfo = (struct virthba_info *) scsihost->hostdata;
+	virthbainfo = (struct virthba_info *)scsihost->hostdata;
 	if (!virthbainfo)
 		LOGERR("Could not find virthba_info for scsihost\n");
 	for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
@@ -1120,7 +1122,7 @@
 
 	scsidev = scsicmd->device;
 	memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
-	sd = (struct sense_data *) scsicmd->sense_buffer;
+	sd = (struct sense_data *)scsicmd->sense_buffer;
 
 	/* Do not log errors for disk-not-present inquiries */
 	if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
@@ -1129,11 +1131,11 @@
 		return;
 
 	/* Okay see what our error_count is here.... */
-	for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+	for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
 	     vdisk->next; vdisk = vdisk->next) {
-		if ((scsidev->channel != vdisk->channel)
-		    || (scsidev->id != vdisk->id)
-		    || (scsidev->lun != vdisk->lun))
+		if ((scsidev->channel != vdisk->channel) ||
+		    (scsidev->id != vdisk->id) ||
+		    (scsidev->lun != vdisk->lun))
 			continue;
 
 		if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
@@ -1148,8 +1150,8 @@
 			if (atomic_read(&vdisk->error_count) ==
 			    VIRTHBA_ERROR_COUNT) {
 				LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%llu>\n",
-				     scsidev->host->host_no, scsidev->id,
-				     scsidev->channel, scsidev->lun);
+				       scsidev->host->host_no, scsidev->id,
+				       scsidev->channel, scsidev->lun);
 			}
 			atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
 		}
@@ -1169,8 +1171,8 @@
 	struct virtdisk_info *vdisk;
 
 	scsidev = scsicmd->device;
-	if ((cmdrsp->scsi.cmnd[0] == INQUIRY)
-	    && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
+	if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
+	    (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
 		if (cmdrsp->scsi.no_disk_result == 0)
 			return;
 
@@ -1198,21 +1200,20 @@
 		sg = scsi_sglist(scsicmd);
 		for (i = 0; i < scsi_sg_count(scsicmd); i++) {
 			DBGVER("copying OUT OF buf into 0x%p %d\n",
-			     sg_page(sg + i), sg[i].length);
+			       sg_page(sg + i), sg[i].length);
 			thispage_orig = kmap_atomic(sg_page(sg + i));
-			thispage = (void *) ((unsigned long)thispage_orig |
+			thispage = (void *)((unsigned long)thispage_orig |
 					     sg[i].offset);
 			memcpy(thispage, buf + bufind, sg[i].length);
 			kunmap_atomic(thispage_orig);
 			bufind += sg[i].length;
 		}
 	} else {
-
 		vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
 		for ( ; vdisk->next; vdisk = vdisk->next) {
-			if ((scsidev->channel != vdisk->channel)
-			    || (scsidev->id != vdisk->id)
-			    || (scsidev->lun != vdisk->lun))
+			if ((scsidev->channel != vdisk->channel) ||
+			    (scsidev->id != vdisk->id) ||
+			    (scsidev->lun != vdisk->lun))
 				continue;
 
 			if (atomic_read(&vdisk->ios_threshold) > 0) {
@@ -1249,8 +1250,8 @@
 {
 	/* copy the result of the taskmgmt and */
 	/* wake up the error handler that is waiting for this */
-	*(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
-	wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify);
+	*(int *)cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
+	wake_up_all((wait_queue_head_t *)cmdrsp->vdiskmgmt.notify);
 	LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result);
 }
 
@@ -1259,15 +1260,15 @@
 {
 	/* copy the result of the taskmgmt and */
 	/* wake up the error handler that is waiting for this */
-	*(int *) cmdrsp->scsitaskmgmt.notifyresult =
+	*(int *)cmdrsp->scsitaskmgmt.notifyresult =
 	    cmdrsp->scsitaskmgmt.result;
-	wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify);
+	wake_up_all((wait_queue_head_t *)cmdrsp->scsitaskmgmt.notify);
 	LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result);
 }
 
 static void
 drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
-		struct uiscmdrsp *cmdrsp)
+	    struct uiscmdrsp *cmdrsp)
 {
 	unsigned long flags;
 	int qrslt = 0;
@@ -1277,7 +1278,7 @@
 	while (1) {
 		spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
 		if (!spar_channel_client_acquire_os(dc->queueinfo->chan,
-						     "vhba")) {
+						    "vhba")) {
 			spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
 					       flags);
 			virthbainfo->acquire_failed_cnt++;
@@ -1294,14 +1295,15 @@
 			 * deletion
 			 */
 			scsicmd = del_scsipending_entry(virthbainfo,
-					(uintptr_t) cmdrsp->scsi.scsicmd);
+							(uintptr_t)
+							 cmdrsp->scsi.scsicmd);
 			if (!scsicmd)
 				break;
 			/* complete the orig cmd */
 			complete_scsi_command(cmdrsp, scsicmd);
 		} else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
 			if (!del_scsipending_entry(virthbainfo,
-				   (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd))
+				   (uintptr_t)cmdrsp->scsitaskmgmt.scsicmd))
 				break;
 			complete_taskmgmt_command(cmdrsp);
 		} else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
@@ -1313,7 +1315,8 @@
 			process_disk_notify(shost, cmdrsp);
 		} else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
 			if (!del_scsipending_entry(virthbainfo,
-				   (uintptr_t) cmdrsp->vdiskmgmt.scsicmd))
+						   (uintptr_t)
+						    cmdrsp->vdiskmgmt.scsicmd))
 				break;
 			complete_vdiskmgmt_command(cmdrsp);
 		} else
@@ -1347,7 +1350,7 @@
 	while (1) {
 		wait_event_interruptible_timeout(virthbainfo->rsp_queue,
 			 (atomic_read(&virthbainfo->interrupt_rcvd) == 1),
-					 usecs_to_jiffies(rsltq_wait_usecs));
+				      usecs_to_jiffies(rsltq_wait_usecs));
 		atomic_set(&virthbainfo->interrupt_rcvd, 0);
 		/* drain queue */
 		drain_queue(virthbainfo, dc, cmdrsp);
@@ -1367,7 +1370,7 @@
 /*****************************************************/
 
 static ssize_t info_debugfs_read(struct file *file,
-			char __user *buf, size_t len, loff_t *offset)
+				 char __user *buf, size_t len, loff_t *offset)
 {
 	ssize_t bytes_read = 0;
 	int str_pos = 0;
@@ -1383,13 +1386,14 @@
 		return -ENOMEM;
 
 	for (i = 0; i < VIRTHBASOPENMAX; i++) {
-		if (VirtHbasOpen[i].virthbainfo == NULL)
+		if (virthbas_open[i].virthbainfo == NULL)
 			continue;
 
-		virthbainfo = VirtHbasOpen[i].virthbainfo;
+		virthbainfo = virthbas_open[i].virthbainfo;
 
 		str_pos += scnprintf(vbuf + str_pos,
-				len - str_pos, "MaxBuffLen:%u\n", MaxBuffLen);
+				len - str_pos, "max_buff_len:%u\n",
+				max_buff_len);
 
 		str_pos += scnprintf(vbuf + str_pos, len - str_pos,
 				"\nvirthba result queue poll wait:%d usecs.\n",
@@ -1418,14 +1422,14 @@
 	return bytes_read;
 }
 
-static ssize_t enable_ints_write(struct file *file,
-			const char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t enable_ints_write(struct file *file, const char __user *buffer,
+				 size_t count, loff_t *ppos)
 {
 	char buf[4];
 	int i, new_value;
 	struct virthba_info *virthbainfo;
 
-	u64 __iomem *Features_addr;
+	u64 __iomem *features_addr;
 	u64 mask;
 
 	if (count >= ARRAY_SIZE(buf))
@@ -1434,37 +1438,37 @@
 	buf[count] = '\0';
 	if (copy_from_user(buf, buffer, count)) {
 		LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
-		       (int) count, buf, count);
+		       (int)count, buf, count);
 		return -EFAULT;
 	}
 
-	i = kstrtoint(buf, 10 , &new_value);
+	i = kstrtoint(buf, 10, &new_value);
 
 	if (i != 0) {
 		LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>",
-		       (int) count, buf);
+		       (int)count, buf);
 		return -EFAULT;
 	}
 
 	/* set all counts to new_value usually 0 */
 	for (i = 0; i < VIRTHBASOPENMAX; i++) {
-		if (VirtHbasOpen[i].virthbainfo != NULL) {
-			virthbainfo = VirtHbasOpen[i].virthbainfo;
-			Features_addr =
+		if (virthbas_open[i].virthbainfo != NULL) {
+			virthbainfo = virthbas_open[i].virthbainfo;
+			features_addr =
 				&virthbainfo->chinfo.queueinfo->chan->features;
 			if (new_value == 1) {
 				mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
 					 ULTRA_IO_DRIVER_DISABLES_INTS);
-				uisqueue_interlocked_and(Features_addr, mask);
+				uisqueue_interlocked_and(features_addr, mask);
 				mask = ULTRA_IO_DRIVER_ENABLES_INTS;
-				uisqueue_interlocked_or(Features_addr, mask);
+				uisqueue_interlocked_or(features_addr, mask);
 				rsltq_wait_usecs = 4000000;
 			} else {
 				mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
 					 ULTRA_IO_DRIVER_DISABLES_INTS);
-				uisqueue_interlocked_and(Features_addr, mask);
+				uisqueue_interlocked_and(features_addr, mask);
 				mask = ULTRA_IO_CHANNEL_IS_POLLING;
-				uisqueue_interlocked_or(Features_addr, mask);
+				uisqueue_interlocked_or(features_addr, mask);
 				rsltq_wait_usecs = 4000;
 			}
 		}
@@ -1477,7 +1481,7 @@
 virthba_serverup(struct virtpci_dev *virtpcidev)
 {
 	struct virthba_info *virthbainfo =
-	    (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+	    (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
 				     scsihost)->hostdata;
 
 	DBGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
@@ -1535,26 +1539,26 @@
 	/* Fail Commands that weren't completed */
 	spin_lock_irqsave(&virthbainfo->privlock, flags);
 	for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
-		pendingdel = &(virthbainfo->pending[i]);
+		pendingdel = &virthbainfo->pending[i];
 		switch (pendingdel->cmdtype) {
 		case CMD_SCSI_TYPE:
-			scsicmd = (struct scsi_cmnd *) pendingdel->sent;
+			scsicmd = (struct scsi_cmnd *)pendingdel->sent;
 			scsicmd->result = (DID_RESET << 16);
 			if (scsicmd->scsi_done)
 				scsicmd->scsi_done(scsicmd);
 			break;
 		case CMD_SCSITASKMGMT_TYPE:
-			cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
+			cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
 			DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp,
 			       cmdrsp->scsitaskmgmt.notify);
-			*(int *) cmdrsp->scsitaskmgmt.notifyresult =
+			*(int *)cmdrsp->scsitaskmgmt.notifyresult =
 			    TASK_MGMT_FAILED;
 			wake_up_all((wait_queue_head_t *)
 				    cmdrsp->scsitaskmgmt.notify);
 			break;
 		case CMD_VDISKMGMT_TYPE:
-			cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
-			*(int *) cmdrsp->vdiskmgmt.notifyresult =
+			cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
+			*(int *)cmdrsp->vdiskmgmt.notifyresult =
 			    VDISK_MGMT_FAILED;
 			wake_up_all((wait_queue_head_t *)
 				    cmdrsp->vdiskmgmt.notify);
@@ -1584,8 +1588,10 @@
 static int
 virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
 {
+	int stat = 1;
+
 	struct virthba_info *virthbainfo =
-	    (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+	    (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
 				     scsihost)->hostdata;
 
 	DBGINF("virthba_serverdown");
@@ -1598,11 +1604,12 @@
 			   &virthbainfo->serverdown_completion);
 	} else if (virthbainfo->serverchangingstate) {
 		LOGERR("Server already processing change state message\n");
-		return 0;
-	} else
+		stat = 0;
+	} else {
 		LOGERR("Server already down, but another server down message received.");
+	}
 
-	return 1;
+	return stat;
 }
 
 /*****************************************************/
@@ -1655,23 +1662,22 @@
 		POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
 				 POSTCODE_SEVERITY_ERR);
 	} else {
-
 		/* create the debugfs directories and entries */
 		virthba_debugfs_dir = debugfs_create_dir("virthba", NULL);
 		debugfs_create_file("info", S_IRUSR, virthba_debugfs_dir,
-				NULL, &debugfs_info_fops);
+				    NULL, &debugfs_info_fops);
 		debugfs_create_u32("rqwait_usecs", S_IRUSR | S_IWUSR,
-				virthba_debugfs_dir, &rsltq_wait_usecs);
+				   virthba_debugfs_dir, &rsltq_wait_usecs);
 		debugfs_create_file("enable_ints", S_IWUSR,
-				virthba_debugfs_dir, NULL,
-				&debugfs_enable_ints_fops);
-		/* Initialize DARWorkQ */
-		INIT_WORK(&DARWorkQ, doDiskAddRemove);
-		spin_lock_init(&DARWorkQLock);
+				    virthba_debugfs_dir, NULL,
+				    &debugfs_enable_ints_fops);
+		/* Initialize dar_work_queue */
+		INIT_WORK(&dar_work_queue, do_disk_add_remove);
+		spin_lock_init(&dar_work_queue_lock);
 
 		/* clear out array */
 		for (i = 0; i < VIRTHBASOPENMAX; i++)
-			VirtHbasOpen[i].virthbainfo = NULL;
+			virthbas_open[i].virthbainfo = NULL;
 		/* Initialize the serverdown workqueue */
 		virthba_serverdown_workqueue =
 		    create_singlethread_workqueue("virthba_serverdown");
@@ -1746,7 +1752,6 @@
 
 	debugfs_remove_recursive(virthba_debugfs_dir);
 	LOGINF("Leaving virthba_mod_exit\n");
-
 }
 
 /* specify function to be run at module insertion time */
diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c
index 39b828d..8fdfd6f 100644
--- a/drivers/staging/unisys/virtpci/virtpci.c
+++ b/drivers/staging/unisys/virtpci/virtpci.c
@@ -104,8 +104,6 @@
 					 const char *buf, size_t count);
 static int virtpci_bus_match(struct device *dev, struct device_driver *drv);
 static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env);
-static int virtpci_device_suspend(struct device *dev, pm_message_t state);
-static int virtpci_device_resume(struct device *dev);
 static int virtpci_device_probe(struct device *dev);
 static int virtpci_device_remove(struct device *dev);
 
@@ -128,8 +126,6 @@
 	.name = "uisvirtpci",
 	.match = virtpci_bus_match,
 	.uevent = virtpci_uevent,
-	.suspend = virtpci_device_suspend,
-	.resume = virtpci_device_resume,
 };
 
 static struct device virtpci_rootbus_device = {
@@ -279,9 +275,9 @@
 		POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
 		return 0;
 	}
-	write_vbus_chp_info(vbus->platform_data /* chanptr */ ,
+	write_vbus_chp_info(vbus->platform_data /* chanptr */,
 			    &chipset_driver_info);
-	write_vbus_bus_info(vbus->platform_data /* chanptr */ ,
+	write_vbus_bus_info(vbus->platform_data /* chanptr */,
 			    &bus_driver_info);
 	LOGINF("Added vbus %d; device %s created successfully\n",
 	       addparams->bus_no, BUS_ID(vbus));
@@ -466,7 +462,7 @@
 	GET_SCSIADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
 
 	LOGINF("Pausing vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
-	i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTHBA_TYPE,
+	i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTHBA_TYPE,
 				      &scsi.wwnn, NULL);
 	if (i)
 		LOGINF("Paused vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -487,7 +483,7 @@
 	LOGINF("Pausing vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
 	       net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
 	       net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
-	i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTNIC_TYPE,
+	i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTNIC_TYPE,
 				      NULL, net.mac_addr);
 	if (i) {
 		LOGINF(" Paused vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -508,7 +504,7 @@
 	GET_SCSIADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
 
 	LOGINF("Resuming vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
-	i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTHBA_TYPE,
+	i = virtpci_device_serverup(NULL /*no parent bus */, VIRTHBA_TYPE,
 				    &scsi.wwnn, NULL);
 	if (i)
 		LOGINF("Resumed vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -530,7 +526,7 @@
 	LOGINF("Resuming vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
 	       net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
 	       net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
-	i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTNIC_TYPE,
+	i = virtpci_device_serverup(NULL /*no parent bus */, VIRTNIC_TYPE,
 				    NULL, net.mac_addr);
 	if (i) {
 		LOGINF(" Resumed vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -551,7 +547,7 @@
 	GET_SCSIADAPINFO_FROM_CHANPTR(delparams->chanptr);
 
 	LOGINF("Deleting vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
-	i = virtpci_device_del(NULL /*no parent bus */ , VIRTHBA_TYPE,
+	i = virtpci_device_del(NULL /*no parent bus */, VIRTHBA_TYPE,
 			       &scsi.wwnn, NULL);
 	if (i) {
 		LOGINF("Deleted vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -574,7 +570,7 @@
 	LOGINF("Deleting vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
 	       net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
 	       net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
-	i = virtpci_device_del(NULL /*no parent bus */ , VIRTNIC_TYPE, NULL,
+	i = virtpci_device_del(NULL /*no parent bus */, VIRTNIC_TYPE, NULL,
 			       net.mac_addr);
 	if (i) {
 		LOGINF("Deleted vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -757,18 +753,6 @@
 	return 0;
 }
 
-static int virtpci_device_suspend(struct device *dev, pm_message_t state)
-{
-	DBGINF("In virtpci_device_suspend -NYI ****\n");
-	return 0;
-}
-
-static int virtpci_device_resume(struct device *dev)
-{
-	DBGINF("In virtpci_device_resume -NYI ****\n");
-	return 0;
-}
-
 /* For a child device just created on a client bus, fill in
  * information about the driver that is controlling this device into
  * the appropriate slot within the vbus channel of the bus
@@ -1338,18 +1322,13 @@
 	ssize_t ret = 0;
 
 	struct driver_private *dprivate = to_driver(kobj);
-	struct device_driver *driver;
+	struct device_driver *driver = dprivate->driver;
 
-	if (dprivate != NULL)
-		driver = dprivate->driver;
-	else
-		driver = NULL;
+	DBGINF("In virtpci_driver_attr_show driver->name:%s\n",	driver->name);
 
-	DBGINF("In virtpci_driver_attr_show driver->name:%s\n", driver->name);
-	if (driver) {
-		if (dattr->show)
-			ret = dattr->show(driver, buf);
-	}
+	if (dattr->show)
+		ret = dattr->show(driver, buf);
+
 	return ret;
 }
 
@@ -1361,19 +1340,13 @@
 	ssize_t ret = 0;
 
 	struct driver_private *dprivate = to_driver(kobj);
-	struct device_driver *driver;
-
-	if (dprivate != NULL)
-		driver = dprivate->driver;
-	else
-		driver = NULL;
+	struct device_driver *driver = dprivate->driver;
 
 	DBGINF("In virtpci_driver_attr_store driver->name:%s\n", driver->name);
 
-	if (driver) {
-		if (dattr->store)
-			ret = dattr->store(driver, buf, count);
-	}
+	if (dattr->store)
+		ret = dattr->store(driver, buf, count);
+
 	return ret;
 }
 
diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h
index 5061edf..63f1b97 100644
--- a/drivers/staging/unisys/visorchannel/visorchannel.h
+++ b/drivers/staging/unisys/visorchannel/visorchannel.h
@@ -29,49 +29,48 @@
 #define BOOL int
 #endif
 
-/* VISORCHANNEL is an opaque structure to users.
- * Fields are declared only in the implementation .c files.
- */
-typedef struct VISORCHANNEL_Tag VISORCHANNEL;
-
 /* Note that for visorchannel_create() and visorchannel_create_overlapped(),
- * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * <channel_bytes> and <guid> arguments may be 0 if we are a channel CLIENT.
  * In this case, the values can simply be read from the channel header.
  */
-VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr,
-				  ulong channelBytes, uuid_le guid);
-VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes,
-					     VISORCHANNEL *parent, ulong off,
-					     uuid_le guid);
-VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr,
-					    ulong channelBytes, uuid_le guid);
-VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes,
-						       VISORCHANNEL *parent,
-						       ulong off, uuid_le guid);
-void visorchannel_destroy(VISORCHANNEL *channel);
-int visorchannel_read(VISORCHANNEL *channel, ulong offset,
+struct visorchannel *visorchannel_create(HOSTADDRESS physaddr,
+					 ulong channel_bytes, uuid_le guid);
+struct visorchannel *visorchannel_create_overlapped(ulong channel_bytes,
+						    struct visorchannel *parent,
+						    ulong off, uuid_le guid);
+struct visorchannel *visorchannel_create_with_lock(HOSTADDRESS physaddr,
+						   ulong channel_bytes,
+						   uuid_le guid);
+struct visorchannel *visorchannel_create_overlapped_with_lock(
+				ulong channel_bytes,
+				struct visorchannel *parent,
+				ulong off, uuid_le guid);
+void visorchannel_destroy(struct visorchannel *channel);
+int visorchannel_read(struct visorchannel *channel, ulong offset,
 		      void *local, ulong nbytes);
-int visorchannel_write(VISORCHANNEL *channel, ulong offset,
+int visorchannel_write(struct visorchannel *channel, ulong offset,
 		       void *local, ulong nbytes);
-int visorchannel_clear(VISORCHANNEL *channel, ulong offset,
+int visorchannel_clear(struct visorchannel *channel, ulong offset,
 		       u8 ch, ulong nbytes);
-BOOL visorchannel_signalremove(VISORCHANNEL *channel, u32 queue, void *msg);
-BOOL visorchannel_signalinsert(VISORCHANNEL *channel, u32 queue, void *msg);
-int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, u32 queue);
-int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, u32 queue);
-
-HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel);
-ulong visorchannel_get_nbytes(VISORCHANNEL *channel);
-char *visorchannel_id(VISORCHANNEL *channel, char *s);
-char *visorchannel_zoneid(VISORCHANNEL *channel, char *s);
-u64 visorchannel_get_clientpartition(VISORCHANNEL *channel);
-uuid_le visorchannel_get_uuid(VISORCHANNEL *channel);
-struct memregion *visorchannel_get_memregion(VISORCHANNEL *channel);
+BOOL visorchannel_signalremove(struct visorchannel *channel, u32 queue,
+			       void *msg);
+BOOL visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
+			       void *msg);
+int visorchannel_signalqueue_slots_avail(struct visorchannel *channel,
+					 u32 queue);
+int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue);
+HOSTADDRESS visorchannel_get_physaddr(struct visorchannel *channel);
+ulong visorchannel_get_nbytes(struct visorchannel *channel);
+char *visorchannel_id(struct visorchannel *channel, char *s);
+char *visorchannel_zoneid(struct visorchannel *channel, char *s);
+u64 visorchannel_get_clientpartition(struct visorchannel *channel);
+uuid_le visorchannel_get_uuid(struct visorchannel *channel);
+struct memregion *visorchannel_get_memregion(struct visorchannel *channel);
 char *visorchannel_uuid_id(uuid_le *guid, char *s);
-void visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+void visorchannel_debug(struct visorchannel *channel, int num_queues,
 			struct seq_file *seq, u32 off);
-void visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+void visorchannel_dump_section(struct visorchannel *chan, char *s,
 			       int off, int len, struct seq_file *seq);
-void __iomem *visorchannel_get_header(VISORCHANNEL *channel);
+void __iomem *visorchannel_get_header(struct visorchannel *channel);
 
 #endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
index 36559d5..0188ef8 100644
--- a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
+++ b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
@@ -28,14 +28,15 @@
 
 #define MYDRVNAME "visorchannel"
 
-struct VISORCHANNEL_Tag {
+struct visorchannel {
 	struct memregion *memregion;	/* from visor_memregion_create() */
 	struct channel_header chan_hdr;
 	uuid_le guid;
 	ulong size;
-	BOOL needs_lock;
-	spinlock_t insert_lock;
-	spinlock_t remove_lock;
+	BOOL needs_lock;	/* channel creator knows if more than one
+				 * thread will be inserting or removing */
+	spinlock_t insert_lock; /* protect head writes in chan_hdr */
+	spinlock_t remove_lock;	/* protect tail writes in chan_hdr */
 
 	struct {
 		struct signal_queue_header req_queue;
@@ -45,18 +46,18 @@
 	} safe_uis_queue;
 };
 
-/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
- * NOT modify this data area.
+/* Creates the struct visorchannel abstraction for a data area in memory,
+ * but does NOT modify this data area.
  */
-static VISORCHANNEL *
-visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
-			 VISORCHANNEL *parent, ulong off, uuid_le guid,
+static struct visorchannel *
+visorchannel_create_guts(HOSTADDRESS physaddr, ulong channel_bytes,
+			 struct visorchannel *parent, ulong off, uuid_le guid,
 			 BOOL needs_lock)
 {
-	VISORCHANNEL *p = NULL;
+	struct visorchannel *p = NULL;
 	void *rc = NULL;
 
-	p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
+	p = kmalloc(sizeof(*p), GFP_KERNEL|__GFP_NORETRY);
 	if (p == NULL) {
 		ERRDRV("allocation failed: (status=0)\n");
 		rc = NULL;
@@ -87,18 +88,18 @@
 		rc = NULL;
 		goto cleanup;
 	}
-	if (channelBytes == 0)
+	if (channel_bytes == 0)
 		/* we had better be a CLIENT of this channel */
-		channelBytes = (ulong)p->chan_hdr.size;
+		channel_bytes = (ulong)p->chan_hdr.size;
 	if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
 		/* we had better be a CLIENT of this channel */
 		guid = p->chan_hdr.chtype;
-	if (visor_memregion_resize(p->memregion, channelBytes) < 0) {
+	if (visor_memregion_resize(p->memregion, channel_bytes) < 0) {
 		ERRDRV("visor_memregion_resize failed: (status=0)\n");
 		rc = NULL;
 		goto cleanup;
 	}
-	p->size = channelBytes;
+	p->size = channel_bytes;
 	p->guid = guid;
 
 	rc = p;
@@ -113,44 +114,45 @@
 	return rc;
 }
 
-VISORCHANNEL *
-visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, uuid_le guid)
+struct visorchannel *
+visorchannel_create(HOSTADDRESS physaddr, ulong channel_bytes, uuid_le guid)
 {
-	return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+	return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
 					FALSE);
 }
 EXPORT_SYMBOL_GPL(visorchannel_create);
 
-VISORCHANNEL *
-visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes,
+struct visorchannel *
+visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channel_bytes,
 			      uuid_le guid)
 {
-	return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+	return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
 					TRUE);
 }
 EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
 
-VISORCHANNEL *
-visorchannel_create_overlapped(ulong channelBytes,
-			       VISORCHANNEL *parent, ulong off, uuid_le guid)
+struct visorchannel *
+visorchannel_create_overlapped(ulong channel_bytes,
+			       struct visorchannel *parent, ulong off,
+			       uuid_le guid)
 {
-	return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+	return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
 					FALSE);
 }
 EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
 
-VISORCHANNEL *
-visorchannel_create_overlapped_with_lock(ulong channelBytes,
-					 VISORCHANNEL *parent, ulong off,
+struct visorchannel *
+visorchannel_create_overlapped_with_lock(ulong channel_bytes,
+					 struct visorchannel *parent, ulong off,
 					 uuid_le guid)
 {
-	return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+	return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
 					TRUE);
 }
 EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
 
 void
-visorchannel_destroy(VISORCHANNEL *channel)
+visorchannel_destroy(struct visorchannel *channel)
 {
 	if (channel == NULL)
 		return;
@@ -163,14 +165,14 @@
 EXPORT_SYMBOL_GPL(visorchannel_destroy);
 
 HOSTADDRESS
-visorchannel_get_physaddr(VISORCHANNEL *channel)
+visorchannel_get_physaddr(struct visorchannel *channel)
 {
 	return visor_memregion_get_physaddr(channel->memregion);
 }
 EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
 
 ulong
-visorchannel_get_nbytes(VISORCHANNEL *channel)
+visorchannel_get_nbytes(struct visorchannel *channel)
 {
 	return channel->size;
 }
@@ -185,42 +187,42 @@
 EXPORT_SYMBOL_GPL(visorchannel_uuid_id);
 
 char *
-visorchannel_id(VISORCHANNEL *channel, char *s)
+visorchannel_id(struct visorchannel *channel, char *s)
 {
 	return visorchannel_uuid_id(&channel->guid, s);
 }
 EXPORT_SYMBOL_GPL(visorchannel_id);
 
 char *
-visorchannel_zoneid(VISORCHANNEL *channel, char *s)
+visorchannel_zoneid(struct visorchannel *channel, char *s)
 {
 	return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s);
 }
 EXPORT_SYMBOL_GPL(visorchannel_zoneid);
 
 HOSTADDRESS
-visorchannel_get_clientpartition(VISORCHANNEL *channel)
+visorchannel_get_clientpartition(struct visorchannel *channel)
 {
 	return channel->chan_hdr.partition_handle;
 }
 EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
 
 uuid_le
-visorchannel_get_uuid(VISORCHANNEL *channel)
+visorchannel_get_uuid(struct visorchannel *channel)
 {
 	return channel->guid;
 }
 EXPORT_SYMBOL_GPL(visorchannel_get_uuid);
 
 struct memregion *
-visorchannel_get_memregion(VISORCHANNEL *channel)
+visorchannel_get_memregion(struct visorchannel *channel)
 {
 	return channel->memregion;
 }
 EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
 
 int
-visorchannel_read(VISORCHANNEL *channel, ulong offset,
+visorchannel_read(struct visorchannel *channel, ulong offset,
 		  void *local, ulong nbytes)
 {
 	int rc = visor_memregion_read(channel->memregion, offset,
@@ -235,7 +237,7 @@
 EXPORT_SYMBOL_GPL(visorchannel_read);
 
 int
-visorchannel_write(VISORCHANNEL *channel, ulong offset,
+visorchannel_write(struct visorchannel *channel, ulong offset,
 		   void *local, ulong nbytes)
 {
 	if (offset == 0 && nbytes >= sizeof(struct channel_header))
@@ -246,7 +248,8 @@
 EXPORT_SYMBOL_GPL(visorchannel_write);
 
 int
-visorchannel_clear(VISORCHANNEL *channel, ulong offset, u8 ch, ulong nbytes)
+visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
+		   ulong nbytes)
 {
 	int rc = -1;
 	int bufsize = 65536;
@@ -285,7 +288,7 @@
 EXPORT_SYMBOL_GPL(visorchannel_clear);
 
 void __iomem  *
-visorchannel_get_header(VISORCHANNEL *channel)
+visorchannel_get_header(struct visorchannel *channel)
 {
 	return (void __iomem *)&channel->chan_hdr;
 }
@@ -316,7 +319,7 @@
 			       sizeof((sig_hdr)->FIELD)) >= 0)
 
 static BOOL
-sig_read_header(VISORCHANNEL *channel, u32 queue,
+sig_read_header(struct visorchannel *channel, u32 queue,
 		struct signal_queue_header *sig_hdr)
 {
 	BOOL rc = FALSE;
@@ -344,7 +347,7 @@
 }
 
 static BOOL
-sig_do_data(VISORCHANNEL *channel, u32 queue,
+sig_do_data(struct visorchannel *channel, u32 queue,
 	    struct signal_queue_header *sig_hdr, u32 slot, void *data,
 	    BOOL is_write)
 {
@@ -373,14 +376,14 @@
 }
 
 static inline BOOL
-sig_read_data(VISORCHANNEL *channel, u32 queue,
+sig_read_data(struct visorchannel *channel, u32 queue,
 	      struct signal_queue_header *sig_hdr, u32 slot, void *data)
 {
 	return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
 }
 
 static inline BOOL
-sig_write_data(VISORCHANNEL *channel, u32 queue,
+sig_write_data(struct visorchannel *channel, u32 queue,
 	       struct signal_queue_header *sig_hdr, u32 slot, void *data)
 {
 	return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
@@ -408,27 +411,21 @@
 	return 1;
 }				/* end safe_sig_queue_validate */
 
-BOOL
-visorchannel_signalremove(VISORCHANNEL *channel, u32 queue, void *msg)
+static BOOL
+signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
 {
-	BOOL rc = FALSE;
 	struct signal_queue_header sig_hdr;
 
-	if (channel->needs_lock)
-		spin_lock(&channel->remove_lock);
-
 	if (!sig_read_header(channel, queue, &sig_hdr)) {
-		rc = FALSE;
-		goto cleanup;
+		return FALSE;
 	}
-	if (sig_hdr.head == sig_hdr.tail) {
-		rc = FALSE;	/* no signals to remove */
-		goto cleanup;
-	}
+	if (sig_hdr.head == sig_hdr.tail)
+		return FALSE;	/* no signals to remove */
+
 	sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
 	if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg)) {
-		ERRDRV("sig_read_data failed: (status=%d)\n", rc);
-		goto cleanup;
+		ERRDRV("sig_read_data failed\n");
+		return FALSE;
 	}
 	sig_hdr.num_received++;
 
@@ -437,53 +434,54 @@
 	 */
 	mb(); /* required for channel synch */
 	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail)) {
-		ERRDRV("visor_memregion_write of Tail failed: (status=%d)\n",
-		       rc);
-		goto cleanup;
+		ERRDRV("visor_memregion_write of Tail failed\n");
+		return FALSE;
 	}
 	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received)) {
-		ERRDRV("visor_memregion_write of NumSignalsReceived failed: (status=%d)\n",
-		       rc);
-		goto cleanup;
+		ERRDRV("visor_memregion_write of NumSignalsReceived failed\n");
+		return FALSE;
 	}
-	rc = TRUE;
-cleanup:
-	if (channel->needs_lock)
+	return TRUE;
+}
+
+BOOL
+visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
+{
+	BOOL rc;
+
+	if (channel->needs_lock) {
+		spin_lock(&channel->remove_lock);
+		rc = signalremove_inner(channel, queue, msg);
 		spin_unlock(&channel->remove_lock);
+	} else {
+		rc = signalremove_inner(channel, queue, msg);
+	}
 
 	return rc;
 }
 EXPORT_SYMBOL_GPL(visorchannel_signalremove);
 
-BOOL
-visorchannel_signalinsert(VISORCHANNEL *channel, u32 queue, void *msg)
+static BOOL
+signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
 {
-	BOOL rc = FALSE;
 	struct signal_queue_header sig_hdr;
 
-	if (channel->needs_lock)
-		spin_lock(&channel->insert_lock);
-
 	if (!sig_read_header(channel, queue, &sig_hdr)) {
-		rc = FALSE;
-		goto cleanup;
+		return FALSE;
 	}
 
 	sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots);
 	if (sig_hdr.head == sig_hdr.tail) {
 		sig_hdr.num_overflows++;
-		if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows)) {
-			ERRDRV("visor_memregion_write of NumOverflows failed: (status=%d)\n",
-			       rc);
-			goto cleanup;
-		}
-		rc = FALSE;
-		goto cleanup;
+		if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows))
+			ERRDRV("visor_memregion_write of NumOverflows failed\n");
+
+		return FALSE;
 	}
 
 	if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg)) {
-		ERRDRV("sig_write_data failed: (status=%d)\n", rc);
-		goto cleanup;
+		ERRDRV("sig_write_data failed\n");
+		return FALSE;
 	}
 	sig_hdr.num_sent++;
 
@@ -492,26 +490,36 @@
 	 */
 	mb(); /* required for channel synch */
 	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head)) {
-		ERRDRV("visor_memregion_write of Head failed: (status=%d)\n",
-		       rc);
-		goto cleanup;
+		ERRDRV("visor_memregion_write of Head failed\n");
+		return FALSE;
 	}
 	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent)) {
-		ERRDRV("visor_memregion_write of NumSignalsSent failed: (status=%d)\n",
-		       rc);
-		goto cleanup;
+		ERRDRV("visor_memregion_write of NumSignalsSent failed\n");
+		return FALSE;
 	}
-	rc = TRUE;
-cleanup:
-	if (channel->needs_lock)
+
+	return TRUE;
+}
+
+BOOL
+visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
+{
+	BOOL rc;
+
+	if (channel->needs_lock) {
+		spin_lock(&channel->insert_lock);
+		rc = signalinsert_inner(channel, queue, msg);
 		spin_unlock(&channel->insert_lock);
+	} else {
+		rc = signalinsert_inner(channel, queue, msg);
+	}
 
 	return rc;
 }
 EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
 
 int
-visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, u32 queue)
+visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue)
 {
 	struct signal_queue_header sig_hdr;
 	u32 slots_avail, slots_used;
@@ -530,7 +538,7 @@
 EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
 
 int
-visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, u32 queue)
+visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue)
 {
 	struct signal_queue_header sig_hdr;
 
@@ -565,7 +573,7 @@
 }
 
 void
-visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+visorchannel_debug(struct visorchannel *channel, int num_queues,
 		   struct seq_file *seq, u32 off)
 {
 	HOSTADDRESS addr = 0;
@@ -625,7 +633,7 @@
 	if ((phdr->ch_space_offset == 0) || (errcode < 0))
 		;
 	else
-		for (i = 0; i < nQueues; i++) {
+		for (i = 0; i < num_queues; i++) {
 			struct signal_queue_header q;
 
 			errcode = visorchannel_read(channel,
@@ -647,7 +655,7 @@
 EXPORT_SYMBOL_GPL(visorchannel_debug);
 
 void
-visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+visorchannel_dump_section(struct visorchannel *chan, char *s,
 			  int off, int len, struct seq_file *seq)
 {
 	char *buf, *tbuf, *fmtbuf;
diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c
index 373fa36..e51fd4e 100644
--- a/drivers/staging/unisys/visorchipset/file.c
+++ b/drivers/staging/unisys/visorchipset/file.c
@@ -28,85 +28,75 @@
 
 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
 
-static struct cdev Cdev;
-static VISORCHANNEL **PControlVm_channel;
-static dev_t MajorDev = -1; /**< indicates major num for device */
-static BOOL Registered = FALSE;
+static struct cdev file_cdev;
+static struct visorchannel **file_controlvm_channel;
+static dev_t majordev = -1; /**< indicates major num for device */
+static BOOL registered = FALSE;
 
 static int visorchipset_open(struct inode *inode, struct file *file);
 static int visorchipset_release(struct inode *inode, struct file *file);
 static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
-#ifdef HAVE_UNLOCKED_IOCTL
 long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#else
-int visorchipset_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg);
-#endif
 
 static const struct file_operations visorchipset_fops = {
 	.owner = THIS_MODULE,
 	.open = visorchipset_open,
 	.read = NULL,
 	.write = NULL,
-#ifdef HAVE_UNLOCKED_IOCTL
 	.unlocked_ioctl = visorchipset_ioctl,
-#else
-	.ioctl = visorchipset_ioctl,
-#endif
 	.release = visorchipset_release,
 	.mmap = visorchipset_mmap,
 };
 
 int
-visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel)
+visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
 {
-	int rc = -1;
+	int rc = 0;
 
-	PControlVm_channel = pControlVm_channel;
-	MajorDev = majorDev;
-	cdev_init(&Cdev, &visorchipset_fops);
-	Cdev.owner = THIS_MODULE;
-	if (MAJOR(MajorDev) == 0) {
+	file_controlvm_channel = controlvm_channel;
+	majordev = major_dev;
+	cdev_init(&file_cdev, &visorchipset_fops);
+	file_cdev.owner = THIS_MODULE;
+	if (MAJOR(majordev) == 0) {
 		/* dynamic major device number registration required */
-		if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) {
+		if (alloc_chrdev_region(&majordev, 0, 1, MYDRVNAME) < 0) {
 			ERRDRV("Unable to allocate+register char device %s",
 			       MYDRVNAME);
-			goto Away;
+			return -1;
 		}
-		Registered = TRUE;
-		INFODRV("New major number %d registered\n", MAJOR(MajorDev));
+		registered = TRUE;
+		INFODRV("New major number %d registered\n", MAJOR(majordev));
 	} else {
 		/* static major device number registration required */
-		if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) {
+		if (register_chrdev_region(majordev, 1, MYDRVNAME) < 0) {
 			ERRDRV("Unable to register char device %s", MYDRVNAME);
-			goto Away;
+			return -1;
 		}
-		Registered = TRUE;
-		INFODRV("Static major number %d registered\n", MAJOR(MajorDev));
+		registered = TRUE;
+		INFODRV("Static major number %d registered\n", MAJOR(majordev));
 	}
-	if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0) {
+	rc = cdev_add(&file_cdev, MKDEV(MAJOR(majordev), 0), 1);
+	if (rc  < 0) {
 		ERRDRV("failed to create char device: (status=%d)\n", rc);
-		goto Away;
+		return -1;
 	}
 	INFODRV("Registered char device for %s (major=%d)",
-		MYDRVNAME, MAJOR(MajorDev));
-	rc = 0;
-Away:
-	return rc;
+		MYDRVNAME, MAJOR(majordev));
+	return 0;
 }
 
 void
 visorchipset_file_cleanup(void)
 {
-	if (Cdev.ops != NULL)
-		cdev_del(&Cdev);
-	Cdev.ops = NULL;
-	if (Registered) {
-		if (MAJOR(MajorDev) >= 0) {
-			unregister_chrdev_region(MajorDev, 1);
-			MajorDev = MKDEV(0, 0);
+	if (file_cdev.ops != NULL)
+		cdev_del(&file_cdev);
+	file_cdev.ops = NULL;
+	if (registered) {
+		if (MAJOR(majordev) >= 0) {
+			unregister_chrdev_region(majordev, 1);
+			majordev = MKDEV(0, 0);
 		}
-		Registered = FALSE;
+		registered = FALSE;
 	}
 }
 
@@ -114,17 +104,12 @@
 visorchipset_open(struct inode *inode, struct file *file)
 {
 	unsigned minor_number = iminor(inode);
-	int rc = -ENODEV;
 
 	DEBUGDRV("%s", __func__);
 	if (minor_number != 0)
-		goto Away;
+		return -ENODEV;
 	file->private_data = NULL;
-	rc = 0;
-Away:
-	if (rc < 0)
-		ERRDRV("%s minor=%d failed", __func__, minor_number);
-	return rc;
+	return 0;
 }
 
 static int
@@ -137,7 +122,7 @@
 static int
 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	ulong physAddr = 0;
+	ulong physaddr = 0;
 	ulong offset = vma->vm_pgoff << PAGE_SHIFT;
 	GUEST_PHYSICAL_ADDRESS addr = 0;
 
@@ -150,11 +135,11 @@
 	switch (offset) {
 	case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
 		vma->vm_flags |= VM_IO;
-		if (*PControlVm_channel == NULL) {
+		if (*file_controlvm_channel == NULL) {
 			ERRDRV("%s no controlvm channel yet", __func__);
 			return -ENXIO;
 		}
-		visorchannel_read(*PControlVm_channel,
+		visorchannel_read(*file_controlvm_channel,
 			offsetof(struct spar_controlvm_channel_protocol,
 				 gp_control_channel),
 			&addr, sizeof(addr));
@@ -162,10 +147,10 @@
 			ERRDRV("%s control channel address is 0", __func__);
 			return -ENXIO;
 		}
-		physAddr = (ulong) (addr);
-		DEBUGDRV("mapping physical address = 0x%lx", physAddr);
+		physaddr = (ulong)addr;
+		DEBUGDRV("mapping physical address = 0x%lx", physaddr);
 		if (remap_pfn_range(vma, vma->vm_start,
-				    physAddr >> PAGE_SHIFT,
+				    physaddr >> PAGE_SHIFT,
 				    vma->vm_end - vma->vm_start,
 				    /*pgprot_noncached */
 				    (vma->vm_page_prot))) {
@@ -180,16 +165,8 @@
 	return 0;
 }
 
-#ifdef HAVE_UNLOCKED_IOCTL
-long
-visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-#else
-int
-visorchipset_ioctl(struct inode *inode, struct file *file,
-		   unsigned int cmd, unsigned long arg)
-#endif
+long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	int rc = SUCCESS;
 	s64 adjustment;
 	s64 vrtc_offset;
 
@@ -200,28 +177,21 @@
 		vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
 		if (copy_to_user
 		    ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
-			rc = -EFAULT;
-			goto Away;
+			return -EFAULT;
 		}
 		DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
 		       cmd, vrtc_offset);
-		break;
+		return SUCCESS;
 	case VMCALL_UPDATE_PHYSICAL_TIME:
 		if (copy_from_user
 		    (&adjustment, (void __user *)arg, sizeof(adjustment))) {
-			rc = -EFAULT;
-			goto Away;
+			return -EFAULT;
 		}
 		DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
 		       adjustment);
-		rc = issue_vmcall_update_physical_time(adjustment);
-		break;
+		return issue_vmcall_update_physical_time(adjustment);
 	default:
 		LOGERR("visorchipset_ioctl received invalid command");
-		rc = -EFAULT;
-		break;
+		return -EFAULT;
 	}
-Away:
-	DBGINF("exiting %d!", rc);
-	return rc;
 }
diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h
index 21bb906..dc7a195 100644
--- a/drivers/staging/unisys/visorchipset/file.h
+++ b/drivers/staging/unisys/visorchipset/file.h
@@ -20,7 +20,8 @@
 
 #include "globals.h"
 
-int visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel);
+int visorchipset_file_init(dev_t majorDev,
+			   struct visorchannel **pControlVm_channel);
 void visorchipset_file_cleanup(void);
 
 #endif
diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h
index 0fe1459..a1d35d4 100644
--- a/drivers/staging/unisys/visorchipset/globals.h
+++ b/drivers/staging/unisys/visorchipset/globals.h
@@ -15,7 +15,6 @@
  * details.
  */
 
-
 #ifndef __VISORCHIPSET_GLOBALS_H__
 #define __VISORCHIPSET_GLOBALS_H__
 
@@ -28,7 +27,6 @@
 
 #define MYDRVNAME "visorchipset"
 
-
 /* module parameters */
 
 extern int visorchipset_testvnic;
diff --git a/drivers/staging/unisys/visorchipset/testing.h b/drivers/staging/unisys/visorchipset/testing.h
deleted file mode 100644
index 573aa8b..0000000
--- a/drivers/staging/unisys/visorchipset/testing.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* testing.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * 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 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, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHIPSET_TESTING_H__
-#define __VISORCHIPSET_TESTING_H__
-
-#define VISORCHIPSET_TEST_PROC
-#include <linux/uuid.h>
-#include "globals.h"
-#include "controlvmchannel.h"
-
-void test_produce_test_message(struct controlvm_message *msg,
-			       int isLocalTestAddr);
-BOOL test_consume_test_message(struct controlvm_message *msg);
-void test_manufacture_vnic_client_add(void *p);
-void test_manufacture_vnic_client_add_phys(HOSTADDRESS addr);
-void test_manufacture_preamble_messages(void);
-void test_manufacture_device_attach(ulong busNo, ulong devNo);
-void test_manufacture_device_add(ulong busNo, ulong devNo, uuid_le dataTypeGuid,
-				 void *pChannel);
-void test_manufacture_add_bus(ulong busNo, ulong maxDevices,
-			      uuid_le id, u8 *name, BOOL isServer);
-void test_manufacture_device_destroy(ulong busNo, ulong devNo);
-void test_manufacture_bus_destroy(ulong busNo);
-void test_manufacture_detach_externalPort(ulong switchNo, ulong externalPortNo);
-void test_manufacture_detach_internalPort(ulong switchNo, ulong internalPortNo);
-void test_cleanup(void);
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h
index 46dad63..98f3ba4 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset.h
+++ b/drivers/staging/unisys/visorchipset/visorchipset.h
@@ -158,61 +158,6 @@
 	return NULL;
 }
 
-/** Attributes for a particular Supervisor switch.
- */
-struct visorchipset_switch_info {
-	u32 switch_no;
-	struct visorchipset_state state;
-	uuid_le switch_type_uuid;
-	u8 *authservice1;
-	u8 *authservice2;
-	u8 *authservice3;
-	u8 *security_context;
-	u64 reserved;
-	u32 reserved2;		/* control_vm_id */
-	struct device dev;
-	BOOL dev_exists;
-	struct controlvm_message_header pending_msg_hdr;
-};
-
-/** Attributes for a particular Supervisor external port, which is connected
- *  to a specific switch.
- */
-struct visorchipset_externalport_info {
-	u32 switch_no;
-	u32 external_port_no;
-	struct visorchipset_state state;
-	uuid_le network_zone_uuid;
-	int pd_port;
-	u8 *ip;
-	u8 *ip_netmask;
-	u8 *ip_broadcast;
-	u8 *ip_network;
-	u8 *ip_gateway;
-	u8 *ip_dns;
-	u64 reserved1;
-	u32 reserved2;		/* control_vm_id */
-	struct device dev;
-	BOOL dev_exists;
-	struct controlvm_message_header pending_msg_hdr;
-};
-
-/** Attributes for a particular Supervisor internal port, which is how a
- *  device connects to a particular switch.
- */
-struct visorchipset_internalport_info {
-	u32 switch_no;
-	u32 internal_port_no;
-	struct visorchipset_state state;
-	u32 bus_no;		/* valid only when state.attached == 1 */
-	u32 dev_no;		/* valid only when state.attached == 1 */
-	u64 reserved1;
-	u32 reserved2;		/* CONTROLVM_ID */
-	struct controlvm_message_header pending_msg_hdr;
-	MYPROCOBJECT *proc_object;
-
-};
-
 /*  These functions will be called from within visorchipset when certain
  *  events happen.  (The implementation of these functions is outside of
  *  visorchipset.)
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c
index 7e6be32..f606ee9 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset_main.c
+++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c
@@ -20,7 +20,6 @@
 #include "procobjecttree.h"
 #include "visorchannel.h"
 #include "periodic_work.h"
-#include "testing.h"
 #include "file.h"
 #include "parser.h"
 #include "uniklog.h"
@@ -102,7 +101,7 @@
 static LIST_HEAD(BusInfoList);
 static LIST_HEAD(DevInfoList);
 
-static VISORCHANNEL *ControlVm_channel;
+static struct visorchannel *ControlVm_channel;
 
 typedef struct {
 	u8 __iomem *ptr;	/* pointer to base address of payload pool */
@@ -1595,7 +1594,7 @@
 static unsigned long
 parahotplug_next_expiration(void)
 {
-	return jiffies + PARAHOTPLUG_TIMEOUT_MS * HZ / 1000;
+	return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
 }
 
 /*
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
index 06ba5b7..6cf6eccb 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset_umode.h
+++ b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
@@ -26,8 +26,6 @@
 #ifndef __VISORCHIPSET_UMODE_H
 #define __VISORCHIPSET_UMODE_H
 
-
-
 /** The user-mode program can access the control channel buffer directly
  *  via this memory map.
  */
diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c
index 1ce7003..ac7acb7 100644
--- a/drivers/staging/unisys/visorutil/charqueue.c
+++ b/drivers/staging/unisys/visorutil/charqueue.c
@@ -28,7 +28,7 @@
 struct charqueue {
 	int alloc_size;
 	int nslots;
-	spinlock_t lock;
+	spinlock_t lock; /* read/write lock for this structure */
 	int head, tail;
 	unsigned char buf[0];
 };
diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c
index 195772d..82279ca 100644
--- a/drivers/staging/unisys/visorutil/procobjecttree.c
+++ b/drivers/staging/unisys/visorutil/procobjecttree.c
@@ -25,12 +25,12 @@
  *  need in order to call the callback function that supplies the /proc read
  *  info for that file.
  */
-typedef struct {
+struct proc_dir_entry_context {
 	void (*show_property)(struct seq_file *, void *, int);
 	MYPROCOBJECT *procObject;
 	int propertyIndex;
 
-} PROCDIRENTRYCONTEXT;
+};
 
 /** This describes the attributes of a tree rooted at
  *  <procDirRoot>/<name[0]>/<name[1]>/...
@@ -86,7 +86,7 @@
 
 	/** this is a holding area for the context information that is needed
 	 *  to run the /proc callback function */
-	PROCDIRENTRYCONTEXT *procDirPropertyContexts;
+	struct proc_dir_entry_context *procDirPropertyContexts;
 };
 
 
@@ -254,15 +254,16 @@
 			goto Away;
 	}
 	obj->procDirPropertyContexts =
-		kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
+		kzalloc((type->nProperties + 1) *
+			sizeof(struct proc_dir_entry_context),
 			GFP_KERNEL | __GFP_NORETRY);
 	if (obj->procDirPropertyContexts == NULL) {
 		ERRDRV("out of memory\n");
 		goto Away;
 	}
-	obj->procDirProperties =
-		kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
-			GFP_KERNEL | __GFP_NORETRY);
+	obj->procDirProperties = kzalloc((type->nProperties + 1) *
+					 sizeof(struct proc_dir_entry *),
+					 GFP_KERNEL | __GFP_NORETRY);
 	if (obj->procDirProperties == NULL) {
 		ERRDRV("out of memory\n");
 		goto Away;
@@ -276,8 +277,8 @@
 			/* only create properties that have names */
 			obj->procDirProperties[i] =
 				createProcFile(type->propertyNames[i],
-					       obj->procDir, &proc_fops,
-					       &obj->procDirPropertyContexts[i]);
+					obj->procDir, &proc_fops,
+					&obj->procDirPropertyContexts[i]);
 			if (obj->procDirProperties[i] == NULL) {
 				rc = NULL;
 				goto Away;
@@ -340,7 +341,7 @@
 
 static int seq_show(struct seq_file *seq, void *offset)
 {
-	PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
+	struct proc_dir_entry_context *ctx = seq->private;
 
 	if (ctx == NULL) {
 		ERRDRV("I don't have a freakin' clue...");
diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c
index f8c5fc3..565ba18 100644
--- a/drivers/staging/vt6655/baseband.c
+++ b/drivers/staging/vt6655/baseband.c
@@ -27,7 +27,8 @@
  *
  * Functions:
  *      BBuGetFrameTime        - Calculate data frame transmitting time
- *      BBvCaculateParameter   - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
+ *      BBvCaculateParameter   - Caculate PhyLength, PhyService and Phy Signal
+ *                               parameter for baseband Tx
  *      BBbReadEmbedded         - Embedded read baseband register via MAC
  *      BBbWriteEmbedded        - Embedded write baseband register via MAC
  *      BBbVT3253Init          - VIA VT3253 baseband chip init code
@@ -1698,46 +1699,6 @@
 		10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216
 };
 
-/*---------------------  Static Functions  --------------------------*/
-
-static
-unsigned long
-s_ulGetRatio(struct vnt_private *priv);
-
-static
-void
-s_vChangeAntenna(
-	struct vnt_private *priv
-);
-
-static
-void
-s_vChangeAntenna(
-	struct vnt_private *priv
-)
-{
-	if (priv->dwRxAntennaSel == 0) {
-		priv->dwRxAntennaSel = 1;
-		if (priv->bTxRxAntInv == true)
-			BBvSetRxAntennaMode(priv, ANT_A);
-		else
-			BBvSetRxAntennaMode(priv, ANT_B);
-	} else {
-		priv->dwRxAntennaSel = 0;
-		if (priv->bTxRxAntInv == true)
-			BBvSetRxAntennaMode(priv, ANT_B);
-		else
-			BBvSetRxAntennaMode(priv, ANT_A);
-	}
-	if (priv->dwTxAntennaSel == 0) {
-		priv->dwTxAntennaSel = 1;
-		BBvSetTxAntennaMode(priv, ANT_B);
-	} else {
-		priv->dwTxAntennaSel = 0;
-		BBvSetTxAntennaMode(priv, ANT_A);
-	}
-}
-
 /*---------------------  Export Variables  --------------------------*/
 /*
  * Description: Calculate data frame transmitting time
@@ -2412,303 +2373,3 @@
 	BBbWriteEmbedded(priv, 0x0C, 0x00); /* CR12 */
 	BBbWriteEmbedded(priv, 0x0D, 0x01); /* CR13 */
 }
-
-static
-unsigned long
-s_ulGetRatio(struct vnt_private *priv)
-{
-	unsigned long ulRatio = 0;
-	unsigned long ulMaxPacket;
-	unsigned long ulPacketNum;
-
-	/* This is a thousand-ratio */
-	ulMaxPacket = priv->uNumSQ3[RATE_54M];
-	if (priv->uNumSQ3[RATE_54M] != 0) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_54M;
-	}
-	if (priv->uNumSQ3[RATE_48M] > ulMaxPacket) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_48M;
-		ulMaxPacket = priv->uNumSQ3[RATE_48M];
-	}
-	if (priv->uNumSQ3[RATE_36M] > ulMaxPacket) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
-			priv->uNumSQ3[RATE_36M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_36M;
-		ulMaxPacket = priv->uNumSQ3[RATE_36M];
-	}
-	if (priv->uNumSQ3[RATE_24M] > ulMaxPacket) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
-			priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_24M;
-		ulMaxPacket = priv->uNumSQ3[RATE_24M];
-	}
-	if (priv->uNumSQ3[RATE_18M] > ulMaxPacket) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
-			priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M] +
-			priv->uNumSQ3[RATE_18M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_18M;
-		ulMaxPacket = priv->uNumSQ3[RATE_18M];
-	}
-	if (priv->uNumSQ3[RATE_12M] > ulMaxPacket) {
-		ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
-			priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M] +
-			priv->uNumSQ3[RATE_18M] + priv->uNumSQ3[RATE_12M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_12M;
-		ulMaxPacket = priv->uNumSQ3[RATE_12M];
-	}
-	if (priv->uNumSQ3[RATE_11M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
-			priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M] -
-			priv->uNumSQ3[RATE_6M] - priv->uNumSQ3[RATE_9M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_11M;
-		ulMaxPacket = priv->uNumSQ3[RATE_11M];
-	}
-	if (priv->uNumSQ3[RATE_9M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
-			priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M] -
-			priv->uNumSQ3[RATE_6M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_9M;
-		ulMaxPacket = priv->uNumSQ3[RATE_9M];
-	}
-	if (priv->uNumSQ3[RATE_6M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
-			priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_6M;
-		ulMaxPacket = priv->uNumSQ3[RATE_6M];
-	}
-	if (priv->uNumSQ3[RATE_5M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
-			priv->uNumSQ3[RATE_2M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_55M;
-		ulMaxPacket = priv->uNumSQ3[RATE_5M];
-	}
-	if (priv->uNumSQ3[RATE_2M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M];
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_2M;
-		ulMaxPacket = priv->uNumSQ3[RATE_2M];
-	}
-	if (priv->uNumSQ3[RATE_1M] > ulMaxPacket) {
-		ulPacketNum = priv->uDiversityCnt;
-		ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
-		ulRatio += TOP_RATE_1M;
-	}
-
-	return ulRatio;
-}
-
-void
-BBvClearAntDivSQ3Value(struct vnt_private *priv)
-{
-	unsigned int ii;
-
-	priv->uDiversityCnt = 0;
-	for (ii = 0; ii < MAX_RATE; ii++)
-		priv->uNumSQ3[ii] = 0;
-}
-
-/*
- * Description: Antenna Diversity
- *
- * Parameters:
- *  In:
- *      priv          - Device Structure
- *      byRSR            - RSR from received packet
- *      bySQ3            - SQ3 value from received packet
- *  Out:
- *      none
- *
- * Return Value: none
- *
- */
-
-void BBvAntennaDiversity(struct vnt_private *priv,
-			 unsigned char byRxRate, unsigned char bySQ3)
-{
-	if ((byRxRate >= MAX_RATE) || (priv->wAntDiversityMaxRate >= MAX_RATE))
-		return;
-
-	priv->uDiversityCnt++;
-
-	priv->uNumSQ3[byRxRate]++;
-
-	if (priv->byAntennaState == 0) {
-		if (priv->uDiversityCnt > priv->ulDiversityNValue) {
-			pr_debug("ulDiversityNValue=[%d],54M-[%d]\n",
-				 (int)priv->ulDiversityNValue,
-				 (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate]);
-
-			if (priv->uNumSQ3[priv->wAntDiversityMaxRate] < priv->uDiversityCnt/2) {
-				priv->ulRatio_State0 = s_ulGetRatio(priv);
-				pr_debug("SQ3_State0, rate = [%08x]\n",
-					 (int)priv->ulRatio_State0);
-
-				if (priv->byTMax == 0)
-					return;
-				pr_debug("1.[%08x], uNumSQ3[%d]=%d, %d\n",
-					 (int)priv->ulRatio_State0,
-					 (int)priv->wAntDiversityMaxRate,
-					 (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
-					 (int)priv->uDiversityCnt);
-
-				s_vChangeAntenna(priv);
-				priv->byAntennaState = 1;
-				del_timer(&priv->TimerSQ3Tmax3);
-				del_timer(&priv->TimerSQ3Tmax2);
-				priv->TimerSQ3Tmax1.expires =  RUN_AT(priv->byTMax * HZ);
-				add_timer(&priv->TimerSQ3Tmax1);
-
-			} else {
-				priv->TimerSQ3Tmax3.expires =  RUN_AT(priv->byTMax3 * HZ);
-				add_timer(&priv->TimerSQ3Tmax3);
-			}
-			BBvClearAntDivSQ3Value(priv);
-
-		}
-	} else { /* byAntennaState == 1 */
-
-		if (priv->uDiversityCnt > priv->ulDiversityMValue) {
-			del_timer(&priv->TimerSQ3Tmax1);
-
-			priv->ulRatio_State1 = s_ulGetRatio(priv);
-			pr_debug("RX:SQ3_State1, rate0 = %08x,rate1 = %08x\n",
-				 (int)priv->ulRatio_State0,
-				 (int)priv->ulRatio_State1);
-
-			if (priv->ulRatio_State1 < priv->ulRatio_State0) {
-				pr_debug("2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
-					 (int)priv->ulRatio_State0,
-					 (int)priv->ulRatio_State1,
-					 (int)priv->wAntDiversityMaxRate,
-					 (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
-					 (int)priv->uDiversityCnt);
-
-				s_vChangeAntenna(priv);
-				priv->TimerSQ3Tmax3.expires =  RUN_AT(priv->byTMax3 * HZ);
-				priv->TimerSQ3Tmax2.expires =  RUN_AT(priv->byTMax2 * HZ);
-				add_timer(&priv->TimerSQ3Tmax3);
-				add_timer(&priv->TimerSQ3Tmax2);
-			}
-			priv->byAntennaState = 0;
-			BBvClearAntDivSQ3Value(priv);
-		}
-	} /* byAntennaState */
-}
-
-/*+
- *
- * Description:
- *  Timer for SQ3 antenna diversity
- *
- * Parameters:
- *  In:
- *  Out:
- *      none
- *
- * Return Value: none
- *
- -*/
-
-void
-TimerSQ3CallBack(
-	unsigned long data
-)
-{
-	struct vnt_private *priv = (struct vnt_private *)data;
-	unsigned long flags;
-
-	pr_debug("TimerSQ3CallBack...\n");
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	pr_debug("3.[%08x][%08x], %d\n",
-		 (int)priv->ulRatio_State0, (int)priv->ulRatio_State1,
-		 (int)priv->uDiversityCnt);
-
-	s_vChangeAntenna(priv);
-	priv->byAntennaState = 0;
-	BBvClearAntDivSQ3Value(priv);
-
-	priv->TimerSQ3Tmax3.expires =  RUN_AT(priv->byTMax3 * HZ);
-	priv->TimerSQ3Tmax2.expires =  RUN_AT(priv->byTMax2 * HZ);
-	add_timer(&priv->TimerSQ3Tmax3);
-	add_timer(&priv->TimerSQ3Tmax2);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/*+
- *
- * Description:
- *  Timer for SQ3 antenna diversity
- *
- * Parameters:
- *  In:
- *      pvSysSpec1
- *      hDeviceContext - Pointer to the adapter
- *      pvSysSpec2
- *      pvSysSpec3
- *  Out:
- *      none
- *
- * Return Value: none
- *
- -*/
-
-void
-TimerState1CallBack(
-	unsigned long data
-)
-{
-	struct vnt_private *priv = (struct vnt_private *)data;
-	unsigned long flags;
-
-	pr_debug("TimerState1CallBack...\n");
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (priv->uDiversityCnt < priv->ulDiversityMValue/100) {
-		s_vChangeAntenna(priv);
-		priv->TimerSQ3Tmax3.expires =  RUN_AT(priv->byTMax3 * HZ);
-		priv->TimerSQ3Tmax2.expires =  RUN_AT(priv->byTMax2 * HZ);
-		add_timer(&priv->TimerSQ3Tmax3);
-		add_timer(&priv->TimerSQ3Tmax2);
-	} else {
-		priv->ulRatio_State1 = s_ulGetRatio(priv);
-		pr_debug("SQ3_State1, rate0 = %08x,rate1 = %08x\n",
-			 (int)priv->ulRatio_State0,
-			 (int)priv->ulRatio_State1);
-
-		if (priv->ulRatio_State1 < priv->ulRatio_State0) {
-			pr_debug("2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
-				 (int)priv->ulRatio_State0,
-				 (int)priv->ulRatio_State1,
-				 (int)priv->wAntDiversityMaxRate,
-				 (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
-				 (int)priv->uDiversityCnt);
-
-			s_vChangeAntenna(priv);
-
-			priv->TimerSQ3Tmax3.expires =  RUN_AT(priv->byTMax3 * HZ);
-			priv->TimerSQ3Tmax2.expires =  RUN_AT(priv->byTMax2 * HZ);
-			add_timer(&priv->TimerSQ3Tmax3);
-			add_timer(&priv->TimerSQ3Tmax2);
-		}
-	}
-	priv->byAntennaState = 0;
-	BBvClearAntDivSQ3Value(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index d9f6d63..43a4fb1 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -93,21 +93,4 @@
 void BBvSetDeepSleep(struct vnt_private *, unsigned char byLocalID);
 void BBvExitDeepSleep(struct vnt_private *, unsigned char byLocalID);
 
-/* timer for antenna diversity */
-
-void
-TimerSQ3CallBack(
-	unsigned long
-);
-
-void
-TimerState1CallBack(
-	unsigned long
-);
-
-void BBvAntennaDiversity(struct vnt_private *,
-			 unsigned char byRxRate, unsigned char bySQ3);
-void
-BBvClearAntDivSQ3Value(struct vnt_private *);
-
 #endif /* __BASEBAND_H__ */
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index a079640..1cdcf49 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -68,8 +68,8 @@
 
 /*---------------------  Static Variables  --------------------------*/
 
-static const unsigned short cwRXBCNTSFOff[MAX_RATE] =
-{17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
+static const unsigned short cwRXBCNTSFOff[MAX_RATE] = {
+	17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
 
 /*---------------------  Static Functions  --------------------------*/
 
@@ -670,6 +670,9 @@
 {
 	union vnt_phy_field_swap phy;
 	unsigned char byTxRate, byRsvTime;      /* For OFDM */
+	unsigned long flags;
+
+	spin_lock_irqsave(&pDevice->lock, flags);
 
 	/* Set to Page1 */
 	MACvSelectPage1(pDevice->PortOffset);
@@ -767,6 +770,8 @@
 	VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate, byRsvTime));
 	/* Set to Page0 */
 	MACvSelectPage0(pDevice->PortOffset);
+
+	spin_unlock_irqrestore(&pDevice->lock, flags);
 }
 
 void CARDvUpdateBasicTopRate(struct vnt_private *pDevice)
diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c
index 70f8705..3c17725 100644
--- a/drivers/staging/vt6655/channel.c
+++ b/drivers/staging/vt6655/channel.c
@@ -174,12 +174,12 @@
  * Return Value: true if succeeded; false if failed.
  *
  */
-bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
+bool set_channel(void *pDeviceHandler, struct ieee80211_channel *ch)
 {
 	struct vnt_private *pDevice = pDeviceHandler;
 	bool bResult = true;
 
-	if (pDevice->byCurrentCh == uConnectionChannel)
+	if (pDevice->byCurrentCh == ch->hw_value)
 		return bResult;
 
 	/* Set VGA to max sensitivity */
@@ -197,19 +197,23 @@
 
 	if (pDevice->byRFType == RF_AIROHA7230)
 		RFbAL7230SelectChannelPostProcess(pDevice, pDevice->byCurrentCh,
-						  (unsigned char)uConnectionChannel);
+						  ch->hw_value);
 
-	pDevice->byCurrentCh = (unsigned char)uConnectionChannel;
+	pDevice->byCurrentCh = ch->hw_value;
 	bResult &= RFbSelectChannel(pDevice, pDevice->byRFType,
-				    (unsigned char)uConnectionChannel);
+				    ch->hw_value);
 
 	/* Init Synthesizer Table */
 	if (pDevice->bEnablePSMode)
-		RFvWriteWakeProgSyn(pDevice, pDevice->byRFType, uConnectionChannel);
+		RFvWriteWakeProgSyn(pDevice, pDevice->byRFType, ch->hw_value);
 
 	BBvSoftwareReset(pDevice);
 
 	if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&pDevice->lock, flags);
+
 		/* set HW default power register */
 		MACvSelectPage1(pDevice->PortOffset);
 		RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
@@ -217,6 +221,8 @@
 		RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
 		VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWROFDM, pDevice->byCurPwr);
 		MACvSelectPage0(pDevice->PortOffset);
+
+		spin_unlock_irqrestore(&pDevice->lock, flags);
 	}
 
 	if (pDevice->byBBType == BB_TYPE_11B)
diff --git a/drivers/staging/vt6655/channel.h b/drivers/staging/vt6655/channel.h
index 4f4264e..e2be6fc 100644
--- a/drivers/staging/vt6655/channel.h
+++ b/drivers/staging/vt6655/channel.h
@@ -27,6 +27,6 @@
 
 void vnt_init_bands(struct vnt_private *);
 
-bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel);
+bool set_channel(void *pDeviceHandler, struct ieee80211_channel *);
 
 #endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index 83efbfb..440537e4 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -367,7 +367,7 @@
 	bool bIsBeaconBufReadySet;
 	unsigned int	cbBeaconBufReadySetCnt;
 	bool bFixRate;
-	unsigned char byCurrentCh;
+	u16 byCurrentCh;
 
 	bool bAES;
 
@@ -407,29 +407,6 @@
 	unsigned char byBBCR88;
 	unsigned char byBBCR09;
 
-	bool bDiversityRegCtlON;
-	bool bDiversityEnable;
-	unsigned long ulDiversityNValue;
-	unsigned long ulDiversityMValue;
-	unsigned char byTMax;
-	unsigned char byTMax2;
-	unsigned char byTMax3;
-	unsigned long ulSQ3TH;
-
-	/* ANT diversity */
-	unsigned long uDiversityCnt;
-	unsigned char byAntennaState;
-	unsigned long ulRatio_State0;
-	unsigned long ulRatio_State1;
-
-	/* SQ3 functions for antenna diversity */
-	struct timer_list           TimerSQ3Tmax1;
-	struct timer_list           TimerSQ3Tmax2;
-	struct timer_list           TimerSQ3Tmax3;
-
-	unsigned long uNumSQ3[MAX_RATE];
-	unsigned short wAntDiversityMaxRate;
-
 	unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; /* unsigned long alignment */
 
 	unsigned short wBeaconInterval;
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index cd1a277..4324282a 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -126,10 +126,6 @@
 
 DEVICE_PARAM(BasebandType, "baseband type");
 
-#define DIVERSITY_ANT_DEF     0
-
-DEVICE_PARAM(bDiversityANTEnable, "ANT diversity mode");
-
 //
 // Static vars definitions
 //
@@ -152,7 +148,6 @@
 static void device_free_info(struct vnt_private *pDevice);
 static bool device_get_pci_info(struct vnt_private *, struct pci_dev *pcid);
 static void device_print_info(struct vnt_private *pDevice);
-static void device_init_diversity_timer(struct vnt_private *pDevice);
 static  irqreturn_t  device_intr(int irq,  void *dev_instance);
 
 #ifdef CONFIG_PM
@@ -216,7 +211,6 @@
 	pOpts->short_retry = SHORT_RETRY_DEF;
 	pOpts->long_retry = LONG_RETRY_DEF;
 	pOpts->bbp_type = BBP_TYPE_DEF;
-	pOpts->flags |= DEVICE_FLAGS_DiversityANT;
 }
 
 static void
@@ -224,7 +218,6 @@
 {
 	pDevice->byShortRetryLimit = pDevice->sOpts.short_retry;
 	pDevice->byLongRetryLimit = pDevice->sOpts.long_retry;
-	pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0;
 	pDevice->byBBType = pDevice->sOpts.bbp_type;
 	pDevice->byPacketType = pDevice->byBBType;
 	pDevice->byAutoFBCtrl = AUTO_FB_0;
@@ -236,8 +229,6 @@
 	pr_debug(" byPreambleType= %d\n", (int)pDevice->byPreambleType);
 	pr_debug(" byShortPreamble= %d\n", (int)pDevice->byShortPreamble);
 	pr_debug(" byBBType= %d\n", (int)pDevice->byBBType);
-	pr_debug(" pDevice->bDiversityRegCtlON= %d\n",
-		 (int)pDevice->bDiversityRegCtlON);
 }
 
 //
@@ -249,7 +240,6 @@
 	unsigned long flags;
 	unsigned int ii;
 	unsigned char byValue;
-	unsigned char byValue1;
 	unsigned char byCCKPwrdBm = 0;
 	unsigned char byOFDMPwrdBm = 0;
 
@@ -301,13 +291,6 @@
 	if (byValue == 0)
 		byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
 
-	pDevice->ulDiversityNValue = 100*260;
-	pDevice->ulDiversityMValue = 100*16;
-	pDevice->byTMax = 1;
-	pDevice->byTMax2 = 4;
-	pDevice->ulSQ3TH = 0;
-	pDevice->byTMax3 = 64;
-
 	if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
 		pDevice->byAntennaCount = 2;
 		pDevice->byTxAntennaMode = ANT_B;
@@ -318,16 +301,7 @@
 			pDevice->byRxAntennaMode = ANT_A;
 		else
 			pDevice->byRxAntennaMode = ANT_B;
-
-		byValue1 = SROMbyReadEmbedded(pDevice->PortOffset,
-					      EEP_OFS_ANTENNA);
-
-		if ((byValue1 & 0x08) == 0)
-			pDevice->bDiversityEnable = false;
-		else
-			pDevice->bDiversityEnable = true;
 	} else  {
-		pDevice->bDiversityEnable = false;
 		pDevice->byAntennaCount = 1;
 		pDevice->dwTxAntennaSel = 0;
 		pDevice->dwRxAntennaSel = 0;
@@ -349,10 +323,9 @@
 		}
 	}
 
-	pr_debug("bDiversityEnable=[%d],NValue=[%d],MValue=[%d],TMax=[%d],TMax2=[%d]\n",
-		 pDevice->bDiversityEnable, (int)pDevice->ulDiversityNValue,
-		 (int)pDevice->ulDiversityMValue, pDevice->byTMax,
-		 pDevice->byTMax2);
+	/* Set initial antenna mode */
+	BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode);
+	BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode);
 
 	/* zonetype initial */
 	pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
@@ -493,24 +466,6 @@
 	MACvStart(pDevice->PortOffset);
 }
 
-static void device_init_diversity_timer(struct vnt_private *pDevice)
-{
-	init_timer(&pDevice->TimerSQ3Tmax1);
-	pDevice->TimerSQ3Tmax1.data = (unsigned long) pDevice;
-	pDevice->TimerSQ3Tmax1.function = TimerSQ3CallBack;
-	pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ);
-
-	init_timer(&pDevice->TimerSQ3Tmax2);
-	pDevice->TimerSQ3Tmax2.data = (unsigned long) pDevice;
-	pDevice->TimerSQ3Tmax2.function = TimerSQ3CallBack;
-	pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ);
-
-	init_timer(&pDevice->TimerSQ3Tmax3);
-	pDevice->TimerSQ3Tmax3.data = (unsigned long) pDevice;
-	pDevice->TimerSQ3Tmax3.function = TimerState1CallBack;
-	pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ);
-}
-
 static void device_print_info(struct vnt_private *pDevice)
 {
 	dev_info(&pDevice->pcid->dev, "%s\n", get_chip_name(pDevice->chip_id));
@@ -1053,6 +1008,58 @@
 	pTDInfo->byFlags = 0;
 }
 
+static void vnt_check_bb_vga(struct vnt_private *priv)
+{
+	long dbm;
+	int i;
+
+	if (!priv->bUpdateBBVGA)
+		return;
+
+	if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+		return;
+
+	if (!(priv->vif->bss_conf.assoc && priv->uCurrRSSI))
+		return;
+
+	RFvRSSITodBm(priv, (u8)priv->uCurrRSSI, &dbm);
+
+	for (i = 0; i < BB_VGA_LEVEL; i++) {
+		if (dbm < priv->ldBmThreshold[i]) {
+			priv->byBBVGANew = priv->abyBBVGA[i];
+			break;
+		}
+	}
+
+	if (priv->byBBVGANew == priv->byBBVGACurrent) {
+		priv->uBBVGADiffCount = 1;
+		return;
+	}
+
+	priv->uBBVGADiffCount++;
+
+	if (priv->uBBVGADiffCount == 1) {
+		/* first VGA diff gain */
+		BBvSetVGAGainOffset(priv, priv->byBBVGANew);
+
+		dev_dbg(&priv->pcid->dev,
+			"First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+			(int)dbm, priv->byBBVGANew,
+			priv->byBBVGACurrent,
+			(int)priv->uBBVGADiffCount);
+	}
+
+	if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
+		dev_dbg(&priv->pcid->dev,
+			"RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+			(int)dbm, priv->byBBVGANew,
+			priv->byBBVGACurrent,
+			(int)priv->uBBVGADiffCount);
+
+		BBvSetVGAGainOffset(priv, priv->byBBVGANew);
+	}
+}
+
 static  irqreturn_t  device_intr(int irq,  void *dev_instance)
 {
 	struct vnt_private *pDevice = dev_instance;
@@ -1060,7 +1067,6 @@
 	unsigned long dwMIBCounter = 0;
 	unsigned char byOrgPageSel = 0;
 	int             handled = 0;
-	int             ii = 0;
 	unsigned long flags;
 
 	MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
@@ -1090,7 +1096,7 @@
 	// Must do this after doing rx/tx, cause ISR bit is slow
 	// than RD/TD write back
 	// update ISR counter
-	STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic , dwMIBCounter);
+	STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic, dwMIBCounter);
 	while (pDevice->dwIsr != 0) {
 		STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr);
 		MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr);
@@ -1104,44 +1110,8 @@
 
 		if (pDevice->dwIsr & ISR_TBTT) {
 			if (pDevice->vif &&
-			    pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
-				if (pDevice->bUpdateBBVGA &&
-				    !(pDevice->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
-				    pDevice->vif->bss_conf.assoc &&
-				    pDevice->uCurrRSSI) {
-					long            ldBm;
-
-					RFvRSSITodBm(pDevice, (unsigned char) pDevice->uCurrRSSI, &ldBm);
-					for (ii = 0; ii < BB_VGA_LEVEL; ii++) {
-						if (ldBm < pDevice->ldBmThreshold[ii]) {
-							pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
-							break;
-						}
-					}
-					if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
-						pDevice->uBBVGADiffCount++;
-						if (pDevice->uBBVGADiffCount == 1) {
-							// first VGA diff gain
-							BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
-							pr_debug("First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
-								 (int)ldBm,
-								 pDevice->byBBVGANew,
-								 pDevice->byBBVGACurrent,
-								 (int)pDevice->uBBVGADiffCount);
-						}
-						if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
-							pr_debug("RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
-								 (int)ldBm,
-								 pDevice->byBBVGANew,
-								 pDevice->byBBVGACurrent,
-								 (int)pDevice->uBBVGADiffCount);
-							BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
-						}
-					} else {
-						pDevice->uBBVGADiffCount = 1;
-					}
-				}
-			}
+			    pDevice->op_mode != NL80211_IFTYPE_ADHOC)
+				vnt_check_bb_vga(pDevice);
 
 			pDevice->bBeaconSent = false;
 			if (pDevice->bEnablePSMode)
@@ -1262,12 +1232,15 @@
 	head_td->m_td1TD1.wReqCount =
 			cpu_to_le16((u16)head_td->pTDInfo->dwReqCount);
 
-	head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+	head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
 
-	if (dma_idx == TYPE_AC0DMA)
+	if (dma_idx == TYPE_AC0DMA) {
+		head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+
 		MACvTransmitAC0(priv->PortOffset);
-	else
+	} else {
 		MACvTransmit0(priv->PortOffset);
+	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1348,8 +1321,6 @@
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
-		if (priv->bDiversityRegCtlON)
-			device_init_diversity_timer(priv);
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST);
@@ -1379,11 +1350,6 @@
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
-		if (priv->bDiversityRegCtlON) {
-			del_timer(&priv->TimerSQ3Tmax1);
-			del_timer(&priv->TimerSQ3Tmax2);
-			del_timer(&priv->TimerSQ3Tmax3);
-		}
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
@@ -1420,7 +1386,7 @@
 
 	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
 	    (conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
-		set_channel(priv, conf->chandef.chan->hw_value);
+		set_channel(priv, conf->chandef.chan);
 
 		if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
 			bb_type = BB_TYPE_11A;
@@ -1572,6 +1538,10 @@
 
 	if (changed_flags & FIF_ALLMULTI) {
 		if (*total_flags & FIF_ALLMULTI) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&priv->lock, flags);
+
 			if (priv->mc_list_count > 2) {
 				MACvSelectPage1(priv->PortOffset);
 
@@ -1593,6 +1563,8 @@
 				MACvSelectPage0(priv->PortOffset);
 			}
 
+			spin_unlock_irqrestore(&priv->lock, flags);
+
 			rx_mode |= RCR_MULTICAST | RCR_BROADCAST;
 		} else {
 			rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST);
@@ -1676,7 +1648,7 @@
 	.reset_tsf		= vnt_reset_tsf,
 };
 
-int vnt_init(struct vnt_private *priv)
+static int vnt_init(struct vnt_private *priv)
 {
 	SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr);
 
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index 977683c..3c5b87f 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -91,6 +91,8 @@
 	new_rsr = skb_data + bytes_received - 3;
 	rssi = skb_data + bytes_received - 2;
 	rsr = skb_data + bytes_received - 1;
+	if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN))
+		return false;
 
 	RFvRSSITodBm(priv, *rssi, &rx_dbm);
 
@@ -106,6 +108,9 @@
 	rx_status.flag = 0;
 	rx_status.freq = hw->conf.chandef.chan->center_freq;
 
+	if (!(*rsr & RSR_CRCOK))
+		rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+
 	hdr = (struct ieee80211_hdr *)(skb->data);
 	fc = hdr->frame_control;
 
@@ -113,13 +118,11 @@
 
 	if (ieee80211_has_protected(fc)) {
 		if (priv->byLocalID > REV_ID_VT3253_A1)
-			rx_status.flag = RX_FLAG_DECRYPTED;
-	}
+			rx_status.flag |= RX_FLAG_DECRYPTED;
 
-	if (priv->vif && priv->bDiversityEnable) {
-		if (ieee80211_is_data(fc) &&
-		    (frame_size > 50) && priv->vif->bss_conf.assoc)
-			BBvAntennaDiversity(priv, priv->rx_rate, 0);
+		/* Drop packet */
+		if (!(*new_rsr & NEWRSR_DECRYPTOK))
+			return false;
 	}
 
 	memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index 8f0d652..3653a2b 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -30,7 +30,6 @@
  *      MACbIsRegBitsOff - Test if All test Bits Off
  *      MACbIsIntDisable - Test if MAC interrupt disable
  *      MACvSetShortRetryLimit - Set 802.11 Short Retry limit
- *      MACvGetShortRetryLimit - Get 802.11 Short Retry limit
  *      MACvSetLongRetryLimit - Set 802.11 Long Retry limit
  *      MACvSetLoopbackMode - Set MAC Loopback Mode
  *      MACvSaveContext - Save Context of MAC Registers
@@ -146,24 +145,6 @@
 	VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit);
 }
 
-/*
- * Description:
- *      Get 802.11 Short Retry Limit
- *
- * Parameters:
- *  In:
- *      dwIoBase        - Base Address for MAC
- *  Out:
- *      pbyRetryLimit   - Retry Limit Get
- *
- * Return Value: none
- *
- */
-void MACvGetShortRetryLimit(void __iomem *dwIoBase, unsigned char *pbyRetryLimit)
-{
-	// get SRT
-	VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit);
-}
 
 /*
  * Description:
@@ -356,7 +337,7 @@
 
 /*
  * Description:
- *      Trun Off MAC Rx
+ *      Turn Off MAC Rx
  *
  * Parameters:
  *  In:
@@ -417,7 +398,7 @@
 
 /*
  * Description:
- *      Trun Off MAC Tx
+ *      Turn Off MAC Tx
  *
  * Parameters:
  *  In:
@@ -808,7 +789,7 @@
 
 	// Check if SyncFlushOK
 	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
-		VNSvInPortB(dwIoBase + MAC_REG_PSCTL , &byOrgValue);
+		VNSvInPortB(dwIoBase + MAC_REG_PSCTL, &byOrgValue);
 		if (byOrgValue & PSCTL_WAKEDONE)
 			break;
 	}
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index e1e7e10..8e0200a 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -38,13 +38,11 @@
 #include "upc.h"
 
 /*---------------------  Export Definitions -------------------------*/
-//
-// Registers in the MAC
-//
+/* Registers in the MAC */
 #define MAC_MAX_CONTEXT_SIZE_PAGE0  256
 #define MAC_MAX_CONTEXT_SIZE_PAGE1  128
 
-// Registers not related to 802.11b
+/* Registers not related to 802.11b */
 #define MAC_REG_BCFG0       0x00
 #define MAC_REG_BCFG1       0x01
 #define MAC_REG_FCR0        0x02
@@ -69,15 +67,16 @@
 #define MAC_REG_TMCTL0      0x18
 #define MAC_REG_TMCTL1      0x19
 #define MAC_REG_TMDATA0     0x1C
-// MAC Parameter related
-#define MAC_REG_LRT         0x20        //
-#define MAC_REG_SRT         0x21        //
-#define MAC_REG_SIFS        0x22        //
-#define MAC_REG_DIFS        0x23        //
-#define MAC_REG_EIFS        0x24        //
-#define MAC_REG_SLOT        0x25        //
-#define MAC_REG_BI          0x26        //
-#define MAC_REG_CWMAXMIN0   0x28        //
+
+/* MAC Parameter related */
+#define MAC_REG_LRT         0x20
+#define MAC_REG_SRT         0x21
+#define MAC_REG_SIFS        0x22
+#define MAC_REG_DIFS        0x23
+#define MAC_REG_EIFS        0x24
+#define MAC_REG_SLOT        0x25
+#define MAC_REG_BI          0x26
+#define MAC_REG_CWMAXMIN0   0x28
 #define MAC_REG_LINKOFFTOTM 0x2A
 #define MAC_REG_SWTMOT      0x2B
 #define MAC_REG_MIBCNTR     0x2C
@@ -85,26 +84,29 @@
 #define MAC_REG_RTSFAILCNT  0x2D
 #define MAC_REG_ACKFAILCNT  0x2E
 #define MAC_REG_FCSERRCNT   0x2F
-// TSF Related
-#define MAC_REG_TSFCNTR     0x30        //
-#define MAC_REG_NEXTTBTT    0x38        //
-#define MAC_REG_TSFOFST     0x40        //
-#define MAC_REG_TFTCTL      0x48        //
-// WMAC Control/Status Related
-#define MAC_REG_ENCFG       0x4C        //
-#define MAC_REG_PAGE1SEL    0x4F        //
-#define MAC_REG_CFG         0x50        //
-#define MAC_REG_TEST        0x52        //
-#define MAC_REG_HOSTCR      0x54        //
-#define MAC_REG_MACCR       0x55        //
-#define MAC_REG_RCR         0x56        //
-#define MAC_REG_TCR         0x57        //
-#define MAC_REG_IMR         0x58        //
+
+/* TSF Related */
+#define MAC_REG_TSFCNTR     0x30
+#define MAC_REG_NEXTTBTT    0x38
+#define MAC_REG_TSFOFST     0x40
+#define MAC_REG_TFTCTL      0x48
+
+/* WMAC Control/Status Related */
+#define MAC_REG_ENCFG       0x4C
+#define MAC_REG_PAGE1SEL    0x4F
+#define MAC_REG_CFG         0x50
+#define MAC_REG_TEST        0x52
+#define MAC_REG_HOSTCR      0x54
+#define MAC_REG_MACCR       0x55
+#define MAC_REG_RCR         0x56
+#define MAC_REG_TCR         0x57
+#define MAC_REG_IMR         0x58
 #define MAC_REG_ISR         0x5C
-// Power Saving Related
-#define MAC_REG_PSCFG       0x60        //
-#define MAC_REG_PSCTL       0x61        //
-#define MAC_REG_PSPWRSIG    0x62        //
+
+/* Power Saving Related */
+#define MAC_REG_PSCFG       0x60
+#define MAC_REG_PSCTL       0x61
+#define MAC_REG_PSPWRSIG    0x62
 #define MAC_REG_BBCR13      0x63
 #define MAC_REG_AIDATIM     0x64
 #define MAC_REG_PWBT        0x66
@@ -112,41 +114,45 @@
 #define MAC_REG_CALTMR      0x69
 #define MAC_REG_SYNSPACCNT  0x6A
 #define MAC_REG_WAKSYNOPT   0x6B
-// Baseband/IF Control Group
-#define MAC_REG_BBREGCTL    0x6C        //
+
+/* Baseband/IF Control Group */
+#define MAC_REG_BBREGCTL    0x6C
 #define MAC_REG_CHANNEL     0x6D
 #define MAC_REG_BBREGADR    0x6E
 #define MAC_REG_BBREGDATA   0x6F
-#define MAC_REG_IFREGCTL    0x70        //
-#define MAC_REG_IFDATA      0x71        //
-#define MAC_REG_ITRTMSET    0x74        //
+#define MAC_REG_IFREGCTL    0x70
+#define MAC_REG_IFDATA      0x71
+#define MAC_REG_ITRTMSET    0x74
 #define MAC_REG_PAPEDELAY   0x77
-#define MAC_REG_SOFTPWRCTL  0x78        //
-#define MAC_REG_GPIOCTL0    0x7A        //
-#define MAC_REG_GPIOCTL1    0x7B        //
+#define MAC_REG_SOFTPWRCTL  0x78
+#define MAC_REG_GPIOCTL0    0x7A
+#define MAC_REG_GPIOCTL1    0x7B
 
-// MAC DMA Related Group
-#define MAC_REG_TXDMACTL0   0x7C        //
-#define MAC_REG_TXDMAPTR0   0x80        //
-#define MAC_REG_AC0DMACTL   0x84        //
-#define MAC_REG_AC0DMAPTR   0x88        //
-#define MAC_REG_BCNDMACTL   0x8C        //
-#define MAC_REG_BCNDMAPTR   0x90        //
-#define MAC_REG_RXDMACTL0   0x94        //
-#define MAC_REG_RXDMAPTR0   0x98        //
-#define MAC_REG_RXDMACTL1   0x9C        //
-#define MAC_REG_RXDMAPTR1   0xA0        //
-#define MAC_REG_SYNCDMACTL  0xA4        //
+/* MAC DMA Related Group */
+#define MAC_REG_TXDMACTL0   0x7C
+#define MAC_REG_TXDMAPTR0   0x80
+#define MAC_REG_AC0DMACTL   0x84
+#define MAC_REG_AC0DMAPTR   0x88
+#define MAC_REG_BCNDMACTL   0x8C
+#define MAC_REG_BCNDMAPTR   0x90
+#define MAC_REG_RXDMACTL0   0x94
+#define MAC_REG_RXDMAPTR0   0x98
+#define MAC_REG_RXDMACTL1   0x9C
+#define MAC_REG_RXDMAPTR1   0xA0
+#define MAC_REG_SYNCDMACTL  0xA4
 #define MAC_REG_SYNCDMAPTR  0xA8
 #define MAC_REG_ATIMDMACTL  0xAC
 #define MAC_REG_ATIMDMAPTR  0xB0
-// MiscFF PIO related
+
+/* MiscFF PIO related */
 #define MAC_REG_MISCFFNDEX  0xB4
 #define MAC_REG_MISCFFCTL   0xB6
 #define MAC_REG_MISCFFDATA  0xB8
-// Extend SW Timer
+
+/* Extend SW Timer */
 #define MAC_REG_TMDATA1     0xBC
-// WOW Related Group
+
+/* WOW Related Group */
 #define MAC_REG_WAKEUPEN0   0xC0
 #define MAC_REG_WAKEUPEN1   0xC1
 #define MAC_REG_WAKEUPSR0   0xC2
@@ -156,19 +162,21 @@
 #define MAC_REG_WAKE128_2   0xE4
 #define MAC_REG_WAKE128_3   0xF4
 
-/////////////// Page 1 ///////////////////
+/************** Page 1 ******************/
 #define MAC_REG_CRC_128_0   0x04
 #define MAC_REG_CRC_128_1   0x06
 #define MAC_REG_CRC_128_2   0x08
 #define MAC_REG_CRC_128_3   0x0A
-// MAC Configuration Group
+
+/* MAC Configuration Group */
 #define MAC_REG_PAR0        0x0C
 #define MAC_REG_PAR4        0x10
 #define MAC_REG_BSSID0      0x14
 #define MAC_REG_BSSID4      0x18
 #define MAC_REG_MAR0        0x1C
 #define MAC_REG_MAR4        0x20
-// MAC RSPPKT INFO Group
+
+/* MAC RSPPKT INFO Group */
 #define MAC_REG_RSPINF_B_1  0x24
 #define MAC_REG_RSPINF_B_2  0x28
 #define MAC_REG_RSPINF_B_5  0x2C
@@ -183,7 +191,7 @@
 #define MAC_REG_RSPINF_A_54 0x42
 #define MAC_REG_RSPINF_A_72 0x44
 
-// 802.11h relative
+/* 802.11h relative */
 #define MAC_REG_QUIETINIT   0x60
 #define MAC_REG_QUIETGAP    0x62
 #define MAC_REG_QUIETDUR    0x64
@@ -195,9 +203,7 @@
 #define MAC_REG_PWRCCK      0x73
 #define MAC_REG_PWROFDM     0x7C
 
-//
-// Bits in the BCFG0 register
-//
+/* Bits in the BCFG0 register */
 #define BCFG0_PERROFF       0x40
 #define BCFG0_MRDMDIS       0x20
 #define BCFG0_MRDLDIS       0x10
@@ -205,9 +211,7 @@
 #define BCFG0_VSERREN       0x02
 #define BCFG0_LATMEN        0x01
 
-//
-// Bits in the BCFG1 register
-//
+/* Bits in the BCFG1 register */
 #define BCFG1_CFUNOPT       0x80
 #define BCFG1_CREQOPT       0x40
 #define BCFG1_DMA8          0x10
@@ -216,25 +220,23 @@
 #define BCFG1_MIOEN         0x02
 #define BCFG1_CISDLYEN      0x01
 
-// Bits in RAMBIST registers
-#define BISTCMD_TSTPAT5     0x00        //
-#define BISTCMD_TSTPATA     0x80        //
-#define BISTCMD_TSTERR      0x20        //
-#define BISTCMD_TSTPATF     0x18        //
-#define BISTCMD_TSTPAT0     0x10        //
-#define BISTCMD_TSTMODE     0x04        //
-#define BISTCMD_TSTITTX     0x03        //
-#define BISTCMD_TSTATRX     0x02        //
-#define BISTCMD_TSTATTX     0x01        //
-#define BISTCMD_TSTRX       0x00        //
-#define BISTSR0_BISTGO      0x01        //
-#define BISTSR1_TSTSR       0x01        //
-#define BISTSR2_CMDPRTEN    0x02        //
-#define BISTSR2_RAMTSTEN    0x01        //
+/* Bits in RAMBIST registers */
+#define BISTCMD_TSTPAT5     0x00
+#define BISTCMD_TSTPATA     0x80
+#define BISTCMD_TSTERR      0x20
+#define BISTCMD_TSTPATF     0x18
+#define BISTCMD_TSTPAT0     0x10
+#define BISTCMD_TSTMODE     0x04
+#define BISTCMD_TSTITTX     0x03
+#define BISTCMD_TSTATRX     0x02
+#define BISTCMD_TSTATTX     0x01
+#define BISTCMD_TSTRX       0x00
+#define BISTSR0_BISTGO      0x01
+#define BISTSR1_TSTSR       0x01
+#define BISTSR2_CMDPRTEN    0x02
+#define BISTSR2_RAMTSTEN    0x01
 
-//
-// Bits in the I2MCFG EEPROM register
-//
+/* Bits in the I2MCFG EEPROM register */
 #define I2MCFG_BOUNDCTL     0x80
 #define I2MCFG_WAITCTL      0x20
 #define I2MCFG_SCLOECTL     0x10
@@ -243,50 +245,38 @@
 #define I2MCFG_I2MLDSEQ     0x02
 #define I2MCFG_I2CMFAST     0x01
 
-//
-// Bits in the I2MCSR EEPROM register
-//
+/* Bits in the I2MCSR EEPROM register */
 #define I2MCSR_EEMW         0x80
 #define I2MCSR_EEMR         0x40
 #define I2MCSR_AUTOLD       0x08
 #define I2MCSR_NACK         0x02
 #define I2MCSR_DONE         0x01
 
-//
-// Bits in the PMC1 register
-//
+/* Bits in the PMC1 register */
 #define SPS_RST             0x80
 #define PCISTIKY            0x40
 #define PME_OVR             0x02
 
-//
-// Bits in the STICKYHW register
-//
+/* Bits in the STICKYHW register */
 #define STICKHW_DS1_SHADOW  0x02
 #define STICKHW_DS0_SHADOW  0x01
 
-//
-// Bits in the TMCTL register
-//
+/* Bits in the TMCTL register */
 #define TMCTL_TSUSP         0x04
 #define TMCTL_TMD           0x02
 #define TMCTL_TE            0x01
 
-//
-// Bits in the TFTCTL register
-//
-#define TFTCTL_HWUTSF       0x80        //
+/* Bits in the TFTCTL register */
+#define TFTCTL_HWUTSF       0x80
 #define TFTCTL_TBTTSYNC     0x40
 #define TFTCTL_HWUTSFEN     0x20
-#define TFTCTL_TSFCNTRRD    0x10        //
-#define TFTCTL_TBTTSYNCEN   0x08        //
-#define TFTCTL_TSFSYNCEN    0x04        //
-#define TFTCTL_TSFCNTRST    0x02        //
-#define TFTCTL_TSFCNTREN    0x01        //
+#define TFTCTL_TSFCNTRRD    0x10
+#define TFTCTL_TBTTSYNCEN   0x08
+#define TFTCTL_TSFSYNCEN    0x04
+#define TFTCTL_TSFCNTRST    0x02
+#define TFTCTL_TSFCNTREN    0x01
 
-//
-// Bits in the EnhanceCFG register
-//
+/* Bits in the EnhanceCFG register */
 #define EnCFG_BarkerPream   0x00020000
 #define EnCFG_NXTBTTCFPSTR  0x00010000
 #define EnCFG_BcnSusClr     0x00000200
@@ -300,14 +290,10 @@
 #define EnCFG_BBType_b      0x00000001
 #define EnCFG_BBType_a      0x00000000
 
-//
-// Bits in the Page1Sel register
-//
+/* Bits in the Page1Sel register */
 #define PAGE1_SEL           0x01
 
-//
-// Bits in the CFG register
-//
+/* Bits in the CFG register */
 #define CFG_TKIPOPT         0x80
 #define CFG_RXDMAOPT        0x40
 #define CFG_TMOT_SW         0x20
@@ -318,242 +304,196 @@
 #define CFG_NOTXTIMEOUT     0x02
 #define CFG_NOBUFOPT        0x01
 
-//
-// Bits in the TEST register
-//
-#define TEST_LBEXT          0x80        //
-#define TEST_LBINT          0x40        //
-#define TEST_LBNONE         0x00        //
-#define TEST_SOFTINT        0x20        //
-#define TEST_CONTTX         0x10        //
-#define TEST_TXPE           0x08        //
-#define TEST_NAVDIS         0x04        //
-#define TEST_NOCTS          0x02        //
-#define TEST_NOACK          0x01        //
+/* Bits in the TEST register */
+#define TEST_LBEXT          0x80
+#define TEST_LBINT          0x40
+#define TEST_LBNONE         0x00
+#define TEST_SOFTINT        0x20
+#define TEST_CONTTX         0x10
+#define TEST_TXPE           0x08
+#define TEST_NAVDIS         0x04
+#define TEST_NOCTS          0x02
+#define TEST_NOACK          0x01
 
-//
-// Bits in the HOSTCR register
-//
-#define HOSTCR_TXONST       0x80        //
-#define HOSTCR_RXONST       0x40        //
-#define HOSTCR_ADHOC        0x20        // Network Type 1 = Ad-hoc
-#define HOSTCR_AP           0x10        // Port Type 1 = AP
-#define HOSTCR_TXON         0x08        //0000 1000
-#define HOSTCR_RXON         0x04        //0000 0100
-#define HOSTCR_MACEN        0x02        //0000 0010
-#define HOSTCR_SOFTRST      0x01        //0000 0001
+/* Bits in the HOSTCR register */
+#define HOSTCR_TXONST       0x80
+#define HOSTCR_RXONST       0x40
+#define HOSTCR_ADHOC        0x20 /* Network Type 1 = Ad-hoc */
+#define HOSTCR_AP           0x10 /* Port Type 1 = AP */
+#define HOSTCR_TXON         0x08 /* 0000 1000 */
+#define HOSTCR_RXON         0x04 /* 0000 0100 */
+#define HOSTCR_MACEN        0x02 /* 0000 0010 */
+#define HOSTCR_SOFTRST      0x01 /* 0000 0001 */
 
-//
-// Bits in the MACCR register
-//
-#define MACCR_SYNCFLUSHOK   0x04        //
-#define MACCR_SYNCFLUSH     0x02        //
-#define MACCR_CLRNAV        0x01        //
+/* Bits in the MACCR register */
+#define MACCR_SYNCFLUSHOK   0x04
+#define MACCR_SYNCFLUSH     0x02
+#define MACCR_CLRNAV        0x01
 
-// Bits in the MAC_REG_GPIOCTL0 register
-//
-#define LED_ACTSET           0x01        //
-#define LED_RFOFF            0x02        //
-#define LED_NOCONNECT        0x04        //
-//
-// Bits in the RCR register
-//
+/* Bits in the MAC_REG_GPIOCTL0 register */
+#define LED_ACTSET           0x01
+#define LED_RFOFF            0x02
+#define LED_NOCONNECT        0x04
+
+/* Bits in the RCR register */
 #define RCR_SSID            0x80
-#define RCR_RXALLTYPE       0x40        //
-#define RCR_UNICAST         0x20        //
-#define RCR_BROADCAST       0x10        //
-#define RCR_MULTICAST       0x08        //
-#define RCR_WPAERR          0x04        //
-#define RCR_ERRCRC          0x02        //
-#define RCR_BSSID           0x01        //
+#define RCR_RXALLTYPE       0x40
+#define RCR_UNICAST         0x20
+#define RCR_BROADCAST       0x10
+#define RCR_MULTICAST       0x08
+#define RCR_WPAERR          0x04
+#define RCR_ERRCRC          0x02
+#define RCR_BSSID           0x01
 
-//
-// Bits in the TCR register
-//
-#define TCR_SYNCDCFOPT      0x02        //
-#define TCR_AUTOBCNTX       0x01        // Beacon automatically transmit enable
+/* Bits in the TCR register */
+#define TCR_SYNCDCFOPT      0x02
+#define TCR_AUTOBCNTX       0x01 /* Beacon automatically transmit enable */
 
-//
-// Bits in the IMR register
-//
-#define IMR_MEASURESTART    0x80000000      //
-#define IMR_QUIETSTART      0x20000000      //
-#define IMR_RADARDETECT     0x10000000      //
-#define IMR_MEASUREEND      0x08000000      //
-#define IMR_SOFTTIMER1      0x00200000      //
-#define IMR_RXDMA1          0x00001000      //0000 0000 0001 0000 0000 0000
-#define IMR_RXNOBUF         0x00000800      //
-#define IMR_MIBNEARFULL     0x00000400      //
-#define IMR_SOFTINT         0x00000200      //
-#define IMR_FETALERR        0x00000100      //
-#define IMR_WATCHDOG        0x00000080      //
-#define IMR_SOFTTIMER       0x00000040      //
-#define IMR_GPIO            0x00000020      //
-#define IMR_TBTT            0x00000010      //
-#define IMR_RXDMA0          0x00000008      //
-#define IMR_BNTX            0x00000004      //
-#define IMR_AC0DMA          0x00000002      //
-#define IMR_TXDMA0          0x00000001      //
+/* Bits in the IMR register */
+#define IMR_MEASURESTART    0x80000000
+#define IMR_QUIETSTART      0x20000000
+#define IMR_RADARDETECT     0x10000000
+#define IMR_MEASUREEND      0x08000000
+#define IMR_SOFTTIMER1      0x00200000
+#define IMR_RXDMA1          0x00001000 /* 0000 0000 0001 0000 0000 0000 */
+#define IMR_RXNOBUF         0x00000800
+#define IMR_MIBNEARFULL     0x00000400
+#define IMR_SOFTINT         0x00000200
+#define IMR_FETALERR        0x00000100
+#define IMR_WATCHDOG        0x00000080
+#define IMR_SOFTTIMER       0x00000040
+#define IMR_GPIO            0x00000020
+#define IMR_TBTT            0x00000010
+#define IMR_RXDMA0          0x00000008
+#define IMR_BNTX            0x00000004
+#define IMR_AC0DMA          0x00000002
+#define IMR_TXDMA0          0x00000001
 
-//
-// Bits in the ISR register
-//
+/* Bits in the ISR register */
+#define ISR_MEASURESTART    0x80000000
+#define ISR_QUIETSTART      0x20000000
+#define ISR_RADARDETECT     0x10000000
+#define ISR_MEASUREEND      0x08000000
+#define ISR_SOFTTIMER1      0x00200000
+#define ISR_RXDMA1          0x00001000 /* 0000 0000 0001 0000 0000 0000 */
+#define ISR_RXNOBUF         0x00000800 /* 0000 0000 0000 1000 0000 0000 */
+#define ISR_MIBNEARFULL     0x00000400 /* 0000 0000 0000 0100 0000 0000 */
+#define ISR_SOFTINT         0x00000200
+#define ISR_FETALERR        0x00000100
+#define ISR_WATCHDOG        0x00000080
+#define ISR_SOFTTIMER       0x00000040
+#define ISR_GPIO            0x00000020
+#define ISR_TBTT            0x00000010
+#define ISR_RXDMA0          0x00000008
+#define ISR_BNTX            0x00000004
+#define ISR_AC0DMA          0x00000002
+#define ISR_TXDMA0          0x00000001
 
-#define ISR_MEASURESTART    0x80000000      //
-#define ISR_QUIETSTART      0x20000000      //
-#define ISR_RADARDETECT     0x10000000      //
-#define ISR_MEASUREEND      0x08000000      //
-#define ISR_SOFTTIMER1      0x00200000      //
-#define ISR_RXDMA1          0x00001000      //0000 0000 0001 0000 0000 0000
-#define ISR_RXNOBUF         0x00000800      //0000 0000 0000 1000 0000 0000
-#define ISR_MIBNEARFULL     0x00000400      //0000 0000 0000 0100 0000 0000
-#define ISR_SOFTINT         0x00000200      //
-#define ISR_FETALERR        0x00000100      //
-#define ISR_WATCHDOG        0x00000080      //
-#define ISR_SOFTTIMER       0x00000040      //
-#define ISR_GPIO            0x00000020      //
-#define ISR_TBTT            0x00000010      //
-#define ISR_RXDMA0          0x00000008      //
-#define ISR_BNTX            0x00000004      //
-#define ISR_AC0DMA          0x00000002      //
-#define ISR_TXDMA0          0x00000001      //
+/* Bits in the PSCFG register */
+#define PSCFG_PHILIPMD      0x40
+#define PSCFG_WAKECALEN     0x20
+#define PSCFG_WAKETMREN     0x10
+#define PSCFG_BBPSPROG      0x08
+#define PSCFG_WAKESYN       0x04
+#define PSCFG_SLEEPSYN      0x02
+#define PSCFG_AUTOSLEEP     0x01
 
-//
-// Bits in the PSCFG register
-//
-#define PSCFG_PHILIPMD      0x40        //
-#define PSCFG_WAKECALEN     0x20        //
-#define PSCFG_WAKETMREN     0x10        //
-#define PSCFG_BBPSPROG      0x08        //
-#define PSCFG_WAKESYN       0x04        //
-#define PSCFG_SLEEPSYN      0x02        //
-#define PSCFG_AUTOSLEEP     0x01        //
+/* Bits in the PSCTL register */
+#define PSCTL_WAKEDONE      0x20
+#define PSCTL_PS            0x10
+#define PSCTL_GO2DOZE       0x08
+#define PSCTL_LNBCN         0x04
+#define PSCTL_ALBCN         0x02
+#define PSCTL_PSEN          0x01
 
-//
-// Bits in the PSCTL register
-//
-#define PSCTL_WAKEDONE      0x20        //
-#define PSCTL_PS            0x10        //
-#define PSCTL_GO2DOZE       0x08        //
-#define PSCTL_LNBCN         0x04        //
-#define PSCTL_ALBCN         0x02        //
-#define PSCTL_PSEN          0x01        //
+/* Bits in the PSPWSIG register */
+#define PSSIG_WPE3          0x80
+#define PSSIG_WPE2          0x40
+#define PSSIG_WPE1          0x20
+#define PSSIG_WRADIOPE      0x10
+#define PSSIG_SPE3          0x08
+#define PSSIG_SPE2          0x04
+#define PSSIG_SPE1          0x02
+#define PSSIG_SRADIOPE      0x01
 
-//
-// Bits in the PSPWSIG register
-//
-#define PSSIG_WPE3          0x80        //
-#define PSSIG_WPE2          0x40        //
-#define PSSIG_WPE1          0x20        //
-#define PSSIG_WRADIOPE      0x10        //
-#define PSSIG_SPE3          0x08        //
-#define PSSIG_SPE2          0x04        //
-#define PSSIG_SPE1          0x02        //
-#define PSSIG_SRADIOPE      0x01        //
+/* Bits in the BBREGCTL register */
+#define BBREGCTL_DONE       0x04
+#define BBREGCTL_REGR       0x02
+#define BBREGCTL_REGW       0x01
 
-//
-// Bits in the BBREGCTL register
-//
-#define BBREGCTL_DONE       0x04        //
-#define BBREGCTL_REGR       0x02        //
-#define BBREGCTL_REGW       0x01        //
+/* Bits in the IFREGCTL register */
+#define IFREGCTL_DONE       0x04
+#define IFREGCTL_IFRF       0x02
+#define IFREGCTL_REGW       0x01
 
-//
-// Bits in the IFREGCTL register
-//
-#define IFREGCTL_DONE       0x04        //
-#define IFREGCTL_IFRF       0x02        //
-#define IFREGCTL_REGW       0x01        //
+/* Bits in the SOFTPWRCTL register */
+#define SOFTPWRCTL_RFLEOPT      0x0800
+#define SOFTPWRCTL_TXPEINV      0x0200
+#define SOFTPWRCTL_SWPECTI      0x0100
+#define SOFTPWRCTL_SWPAPE       0x0020
+#define SOFTPWRCTL_SWCALEN      0x0010
+#define SOFTPWRCTL_SWRADIO_PE   0x0008
+#define SOFTPWRCTL_SWPE2        0x0004
+#define SOFTPWRCTL_SWPE1        0x0002
+#define SOFTPWRCTL_SWPE3        0x0001
 
-//
-// Bits in the SOFTPWRCTL register
-//
-#define SOFTPWRCTL_RFLEOPT      0x0800  //
-#define SOFTPWRCTL_TXPEINV      0x0200  //
-#define SOFTPWRCTL_SWPECTI      0x0100  //
-#define SOFTPWRCTL_SWPAPE       0x0020  //
-#define SOFTPWRCTL_SWCALEN      0x0010  //
-#define SOFTPWRCTL_SWRADIO_PE   0x0008  //
-#define SOFTPWRCTL_SWPE2        0x0004  //
-#define SOFTPWRCTL_SWPE1        0x0002  //
-#define SOFTPWRCTL_SWPE3        0x0001  //
+/* Bits in the GPIOCTL1 register */
+#define GPIO1_DATA1             0x20
+#define GPIO1_MD1               0x10
+#define GPIO1_DATA0             0x02
+#define GPIO1_MD0               0x01
 
-//
-// Bits in the GPIOCTL1 register
-//
-#define GPIO1_DATA1             0x20    //
-#define GPIO1_MD1               0x10    //
-#define GPIO1_DATA0             0x02    //
-#define GPIO1_MD0               0x01    //
+/* Bits in the DMACTL register */
+#define DMACTL_CLRRUN       0x00080000
+#define DMACTL_RUN          0x00000008
+#define DMACTL_WAKE         0x00000004
+#define DMACTL_DEAD         0x00000002
+#define DMACTL_ACTIVE       0x00000001
 
-//
-// Bits in the DMACTL register
-//
-#define DMACTL_CLRRUN       0x00080000  //
-#define DMACTL_RUN          0x00000008  //
-#define DMACTL_WAKE         0x00000004  //
-#define DMACTL_DEAD         0x00000002  //
-#define DMACTL_ACTIVE       0x00000001  //
-//
-// Bits in the RXDMACTL0 register
-//
-#define RX_PERPKT           0x00000100  //
-#define RX_PERPKTCLR        0x01000000  //
-//
-// Bits in the BCNDMACTL register
-//
-#define BEACON_READY        0x01        //
-//
-// Bits in the MISCFFCTL register
-//
-#define MISCFFCTL_WRITE     0x0001      //
+/* Bits in the RXDMACTL0 register */
+#define RX_PERPKT           0x00000100
+#define RX_PERPKTCLR        0x01000000
 
-//
-// Bits in WAKEUPEN0
-//
+/* Bits in the BCNDMACTL register */
+#define BEACON_READY        0x01
+
+/* Bits in the MISCFFCTL register */
+#define MISCFFCTL_WRITE     0x0001
+
+/* Bits in WAKEUPEN0 */
 #define WAKEUPEN0_DIRPKT    0x10
 #define WAKEUPEN0_LINKOFF   0x08
 #define WAKEUPEN0_ATIMEN    0x04
 #define WAKEUPEN0_TIMEN     0x02
 #define WAKEUPEN0_MAGICEN   0x01
 
-//
-// Bits in WAKEUPEN1
-//
+/* Bits in WAKEUPEN1 */
 #define WAKEUPEN1_128_3     0x08
 #define WAKEUPEN1_128_2     0x04
 #define WAKEUPEN1_128_1     0x02
 #define WAKEUPEN1_128_0     0x01
 
-//
-// Bits in WAKEUPSR0
-//
+/* Bits in WAKEUPSR0 */
 #define WAKEUPSR0_DIRPKT    0x10
 #define WAKEUPSR0_LINKOFF   0x08
 #define WAKEUPSR0_ATIMEN    0x04
 #define WAKEUPSR0_TIMEN     0x02
 #define WAKEUPSR0_MAGICEN   0x01
 
-//
-// Bits in WAKEUPSR1
-//
+/* Bits in WAKEUPSR1 */
 #define WAKEUPSR1_128_3     0x08
 #define WAKEUPSR1_128_2     0x04
 #define WAKEUPSR1_128_1     0x02
 #define WAKEUPSR1_128_0     0x01
 
-//
-// Bits in the MAC_REG_GPIOCTL register
-//
-#define GPIO0_MD            0x01        //
-#define GPIO0_DATA          0x02        //
-#define GPIO0_INTMD         0x04        //
-#define GPIO1_MD            0x10        //
-#define GPIO1_DATA          0x20        //
+/* Bits in the MAC_REG_GPIOCTL register */
+#define GPIO0_MD            0x01
+#define GPIO0_DATA          0x02
+#define GPIO0_INTMD         0x04
+#define GPIO1_MD            0x10
+#define GPIO1_DATA          0x20
 
-//
-// Bits in the MSRCTL register
-//
+/* Bits in the MSRCTL register */
 #define MSRCTL_FINISH       0x80
 #define MSRCTL_READY        0x40
 #define MSRCTL_RADARDETECT  0x20
@@ -562,28 +502,27 @@
 #define MSRCTL_QUIETRPT     0x04
 #define MSRCTL_QUIETINT     0x02
 #define MSRCTL_QUIETEN      0x01
-//
-// Bits in the MSRCTL1 register
-//
+
+/* Bits in the MSRCTL1 register */
 #define MSRCTL1_TXPWR       0x08
 #define MSRCTL1_CSAPAREN    0x04
 #define MSRCTL1_TXPAUSE     0x01
 
-// Loopback mode
-#define MAC_LB_EXT          0x02        //
-#define MAC_LB_INTERNAL     0x01        //
-#define MAC_LB_NONE         0x00        //
+/* Loopback mode */
+#define MAC_LB_EXT          0x02
+#define MAC_LB_INTERNAL     0x01
+#define MAC_LB_NONE         0x00
 
 #define Default_BI              0x200
 
-// MiscFIFO Offset
+/* MiscFIFO Offset */
 #define MISCFIFO_KEYETRY0       32
 #define MISCFIFO_KEYENTRYSIZE   22
 #define MISCFIFO_SYNINFO_IDX    10
 #define MISCFIFO_SYNDATA_IDX    11
 #define MISCFIFO_SYNDATASIZE    21
 
-// enabled mask value of irq
+/* enabled mask value of irq */
 #define IMR_MASK_VALUE     (IMR_SOFTTIMER1 |	\
 			    IMR_RXDMA1 |	\
 			    IMR_RXNOBUF |	\
@@ -599,15 +538,13 @@
 			    IMR_AC0DMA |	\
 			    IMR_TXDMA0)
 
-// max time out delay time
-#define W_MAX_TIMEOUT       0xFFF0U     //
+/* max time out delay time */
+#define W_MAX_TIMEOUT       0xFFF0U
 
-// wait time within loop
-#define CB_DELAY_LOOP_WAIT  10          // 10ms
+/* wait time within loop */
+#define CB_DELAY_LOOP_WAIT  10 /* 10ms */
 
-//
-// revision id
-//
+/* revision id */
 #define REV_ID_VT3253_A0    0x00
 #define REV_ID_VT3253_A1    0x01
 #define REV_ID_VT3253_B0    0x08
@@ -691,12 +628,12 @@
 	VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR,		\
 		    (unsigned long *)pdwCurrDescAddr)
 
-// set the chip with current BCN tx descriptor address
+/* set the chip with current BCN tx descriptor address */
 #define MACvSetCurrBCNTxDescAddr(dwIoBase, dwCurrDescAddr)	\
 	VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR,		\
 		     dwCurrDescAddr)
 
-// set the chip with current BCN length
+/* set the chip with current BCN length */
 #define MACvSetCurrBCNLength(dwIoBase, wCurrBCNLength)		\
 	VNSvOutPortW(dwIoBase + MAC_REG_BCNDMACTL+2,		\
 		     wCurrBCNLength)
@@ -888,7 +825,7 @@
 	VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1)
 
 #define MACvReadMIBCounter(dwIoBase, pdwCounter)			\
-	VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR , pdwCounter)
+	VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR, pdwCounter)
 
 #define MACvPwrEvntDisable(dwIoBase)					\
 	VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPEN0, 0x0000)
@@ -896,7 +833,7 @@
 #define MACvEnableProtectMD(dwIoBase)					\
 do {									\
 	unsigned long dwOrgValue;					\
-	VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);		\
+	VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue);		\
 	dwOrgValue = dwOrgValue | EnCFG_ProtectMd;			\
 	VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);		\
 } while (0)
@@ -904,7 +841,7 @@
 #define MACvDisableProtectMD(dwIoBase)					\
 do {									\
 	unsigned long dwOrgValue;					\
-	VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);		\
+	VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue);		\
 	dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd;			\
 	VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);		\
 } while (0)
@@ -912,7 +849,7 @@
 #define MACvEnableBarkerPreambleMd(dwIoBase)				\
 do {									\
 	unsigned long dwOrgValue;					\
-	VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);		\
+	VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue);		\
 	dwOrgValue = dwOrgValue | EnCFG_BarkerPream;			\
 	VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);		\
 } while (0)
@@ -920,7 +857,7 @@
 #define MACvDisableBarkerPreambleMd(dwIoBase)				\
 do {									\
 	unsigned long dwOrgValue;					\
-	VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);		\
+	VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue);		\
 	dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream;			\
 	VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);		\
 } while (0)
@@ -928,7 +865,7 @@
 #define MACvSetBBType(dwIoBase, byTyp)					\
 do {									\
 	unsigned long dwOrgValue;					\
-	VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);		\
+	VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue);		\
 	dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK;			\
 	dwOrgValue = dwOrgValue | (unsigned long)byTyp;			\
 	VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);		\
@@ -953,15 +890,18 @@
 #define MACvSetRFLE_LatchBase(dwIoBase)                                 \
 	MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT)
 
-bool MACbIsRegBitsOn(void __iomem *dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
-bool MACbIsRegBitsOff(void __iomem *dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
+bool MACbIsRegBitsOn(void __iomem *dwIoBase, unsigned char byRegOfs,
+		     unsigned char byTestBits);
+bool MACbIsRegBitsOff(void __iomem *dwIoBase, unsigned char byRegOfs,
+		      unsigned char byTestBits);
 
 bool MACbIsIntDisable(void __iomem *dwIoBase);
 
 void MACvSetShortRetryLimit(void __iomem *dwIoBase, unsigned char byRetryLimit);
 
 void MACvSetLongRetryLimit(void __iomem *dwIoBase, unsigned char byRetryLimit);
-void MACvGetLongRetryLimit(void __iomem *dwIoBase, unsigned char *pbyRetryLimit);
+void MACvGetLongRetryLimit(void __iomem *dwIoBase,
+			   unsigned char *pbyRetryLimit);
 
 void MACvSetLoopbackMode(void __iomem *dwIoBase, unsigned char byLoopbackMode);
 
@@ -975,22 +915,32 @@
 bool MACbSafeStop(void __iomem *dwIoBase);
 bool MACbShutdown(void __iomem *dwIoBase);
 void MACvInitialize(void __iomem *dwIoBase);
-void MACvSetCurrRx0DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrRx1DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrTXDescAddr(int iTxType, void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrTx0DescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrAC0DescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrSyncDescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrATIMDescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrRx0DescAddr(void __iomem *dwIoBase,
+			    unsigned long dwCurrDescAddr);
+void MACvSetCurrRx1DescAddr(void __iomem *dwIoBase,
+			    unsigned long dwCurrDescAddr);
+void MACvSetCurrTXDescAddr(int iTxType, void __iomem *dwIoBase,
+			   unsigned long dwCurrDescAddr);
+void MACvSetCurrTx0DescAddrEx(void __iomem *dwIoBase,
+			      unsigned long dwCurrDescAddr);
+void MACvSetCurrAC0DescAddrEx(void __iomem *dwIoBase,
+			      unsigned long dwCurrDescAddr);
+void MACvSetCurrSyncDescAddrEx(void __iomem *dwIoBase,
+			       unsigned long dwCurrDescAddr);
+void MACvSetCurrATIMDescAddrEx(void __iomem *dwIoBase,
+			       unsigned long dwCurrDescAddr);
 void MACvTimer0MicroSDelay(void __iomem *dwIoBase, unsigned int uDelay);
 void MACvOneShotTimer1MicroSec(void __iomem *dwIoBase, unsigned int uDelayTime);
 
-void MACvSetMISCFifo(void __iomem *dwIoBase, unsigned short wOffset, unsigned long dwData);
+void MACvSetMISCFifo(void __iomem *dwIoBase, unsigned short wOffset,
+		     unsigned long dwData);
 
 bool MACbPSWakeup(void __iomem *dwIoBase);
 
-void MACvSetKeyEntry(void __iomem *dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
-		     unsigned int uKeyIdx, unsigned char *pbyAddr, u32 *pdwKey, unsigned char byLocalID);
+void MACvSetKeyEntry(void __iomem *dwIoBase, unsigned short wKeyCtl,
+		     unsigned int uEntryIdx, unsigned int uKeyIdx,
+		     unsigned char *pbyAddr, u32 *pdwKey,
+		     unsigned char byLocalID);
 void MACvDisableKeyEntry(void __iomem *dwIoBase, unsigned int uEntryIdx);
 
-#endif // __MAC_H__
+#endif /* __MAC_H__ */
diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c
index e826f07..be3c4e9 100644
--- a/drivers/staging/vt6655/power.c
+++ b/drivers/staging/vt6655/power.c
@@ -71,33 +71,33 @@
 	struct vnt_private *pDevice = hDeviceContext;
 	u16 wAID = pDevice->current_aid | BIT(14) | BIT(15);
 
-	// set period of power up before TBTT
+	/* set period of power up before TBTT */
 	VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
 	if (pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
-		// set AID
+		/* set AID */
 		VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
 	} else {
-		// set ATIM Window
+		/* set ATIM Window */
 #if 0 /* TODO atim window */
 		MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
 #endif
 	}
-	// Set AutoSleep
+	/* Set AutoSleep */
 	MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
-	// Set HWUTSF
+	/* Set HWUTSF */
 	MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
 
 	if (wListenInterval >= 2) {
-		// clear always listen beacon
+		/* clear always listen beacon */
 		MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
-		// first time set listen next beacon
+		/* first time set listen next beacon */
 		MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
 	} else {
-		// always listen beacon
+		/* always listen beacon */
 		MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
 	}
 
-	// enable power saving hw function
+	/* enable power saving hw function */
 	MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
 	pDevice->bEnablePSMode = true;
 
@@ -122,13 +122,13 @@
 {
 	struct vnt_private *pDevice = hDeviceContext;
 
-	// disable power saving hw function
+	/* disable power saving hw function */
 	MACbPSWakeup(pDevice->PortOffset);
-	//clear AutoSleep
+	/* clear AutoSleep */
 	MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
-	//clear HWUTSF
+	/* clear HWUTSF */
 	MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
-	// set always listen beacon
+	/* set always listen beacon */
 	MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
 
 	pDevice->bEnablePSMode = false;
diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c
index 32ef993..941b2ad 100644
--- a/drivers/staging/vt6655/rf.c
+++ b/drivers/staging/vt6655/rf.c
@@ -651,7 +651,8 @@
  * Return Value: true if succeeded; false if failed.
  *
  */
-bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType, unsigned char byChannel)
+bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType,
+		      u16 byChannel)
 {
 	bool bResult = true;
 
@@ -687,7 +688,8 @@
  * Return Value: None.
  *
  */
-bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType, unsigned int uChannel)
+bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType,
+			 u16 uChannel)
 {
 	void __iomem *dwIoBase = priv->PortOffset;
 	int   ii;
@@ -767,13 +769,12 @@
 bool RFbSetPower(
 	struct vnt_private *priv,
 	unsigned int uRATE,
-	unsigned int uCH
+	u16 uCH
 )
 {
 	bool bResult = true;
 	unsigned char byPwr = 0;
 	unsigned char byDec = 0;
-	unsigned char byPwrdBm = 0;
 
 	if (priv->dwDiagRefCount != 0)
 		return true;
@@ -786,8 +787,10 @@
 	case RATE_2M:
 	case RATE_5M:
 	case RATE_11M:
+		if (uCH > CB_MAX_CHANNEL_24G)
+			return false;
+
 		byPwr = priv->abyCCKPwrTbl[uCH];
-		byPwrdBm = priv->abyCCKDefaultPwr[uCH];
 		break;
 	case RATE_6M:
 	case RATE_9M:
@@ -801,15 +804,6 @@
 		if (byDec >= priv->byMaxPwrLevel)
 			byDec = priv->byMaxPwrLevel-1;
 
-		if (priv->byRFType == RF_UW2452) {
-			byPwrdBm = byDec - byPwr;
-			byPwrdBm /= 3;
-		} else {
-			byPwrdBm = byDec - byPwr;
-			byPwrdBm >>= 1;
-		}
-
-		byPwrdBm += priv->abyOFDMDefaultPwr[uCH];
 		byPwr = byDec;
 		break;
 	case RATE_24M:
@@ -817,7 +811,6 @@
 	case RATE_48M:
 	case RATE_54M:
 		byPwr = priv->abyOFDMPwrTbl[uCH];
-		byPwrdBm = priv->abyOFDMDefaultPwr[uCH];
 		break;
 	}
 
@@ -937,8 +930,8 @@
 /* Post processing for the 11b/g and 11a.
  * for save time on changing Reg2,3,5,7,10,12,15 */
 bool RFbAL7230SelectChannelPostProcess(struct vnt_private *priv,
-				       unsigned char byOldChannel,
-				       unsigned char byNewChannel)
+				       u16 byOldChannel,
+				       u16 byNewChannel)
 {
 	bool bResult;
 
diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h
index 8a6e2cf..2ea21e2 100644
--- a/drivers/staging/vt6655/rf.h
+++ b/drivers/staging/vt6655/rf.h
@@ -74,12 +74,12 @@
 /*---------------------  Export Functions  --------------------------*/
 
 bool IFRFbWriteEmbedded(struct vnt_private *, unsigned long dwData);
-bool RFbSelectChannel(struct vnt_private *, unsigned char byRFType, unsigned char byChannel);
+bool RFbSelectChannel(struct vnt_private *, unsigned char byRFType, u16);
 bool RFbInit(
 	struct vnt_private *
 );
-bool RFvWriteWakeProgSyn(struct vnt_private *, unsigned char byRFType, unsigned int uChannel);
-bool RFbSetPower(struct vnt_private *, unsigned int uRATE, unsigned int uCH);
+bool RFvWriteWakeProgSyn(struct vnt_private *, unsigned char byRFType, u16);
+bool RFbSetPower(struct vnt_private *, unsigned int uRATE, u16);
 bool RFbRawSetPower(
 	struct vnt_private *,
 	unsigned char byPwr,
@@ -94,7 +94,7 @@
 );
 
 //{{ RobertYu: 20050104
-bool RFbAL7230SelectChannelPostProcess(struct vnt_private *, unsigned char byOldChannel, unsigned char byNewChannel);
+bool RFbAL7230SelectChannelPostProcess(struct vnt_private *, u16, u16);
 //}} RobertYu
 
 #endif // __RF_H__
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index b5b0155..07ce3fd 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -205,7 +205,7 @@
 	unsigned short wCurrentRate
 )
 {
-	unsigned int uRrvTime  , uRTSTime, uCTSTime, uAckTime, uDataTime;
+	unsigned int uRrvTime, uRTSTime, uCTSTime, uAckTime, uDataTime;
 
 	uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
 
@@ -1207,7 +1207,6 @@
 	ptdCurr->pTDInfo->dwReqCount = cbReqCount;
 	ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
 	ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
-	ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
 
 	return cbHeaderLength;
 }
diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h
index c53703a..cc63dc8 100644
--- a/drivers/staging/vt6655/upc.h
+++ b/drivers/staging/vt6655/upc.h
@@ -33,9 +33,9 @@
 
 /*---------------------  Export Definitions -------------------------*/
 
-//
-//  For memory mapped IO
-//
+
+/* For memory mapped IO */
+
 
 #define VNSvInPortB(dwIOAddress, pbyData)				\
 do {									\
@@ -86,4 +86,4 @@
 
 /*---------------------  Export Functions  --------------------------*/
 
-#endif // __UPC_H__
+#endif /* __UPC_H__ */
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 9340f15..67ff13f 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -78,7 +78,7 @@
 	/* Set Channel[7] = 0 to tell H/W channel is changing now. */
 	vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL, 0xb0);
 
-	vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNLE,
+	vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNEL,
 					connection_channel, 0, 0, NULL);
 
 	vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_CHANNEL,
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index 5a7ca52..f71d59f 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -160,7 +160,7 @@
 #define MESSAGE_TYPE_CLRKEYENTRY	0x9
 #define MESSAGE_TYPE_WRITE_MISCFF	0xa
 #define MESSAGE_TYPE_SET_ANTMD		0xb
-#define MESSAGE_TYPE_SELECT_CHANNLE	0xc
+#define MESSAGE_TYPE_SELECT_CHANNEL	0xc
 #define MESSAGE_TYPE_SET_TSFTBTT	0xd
 #define MESSAGE_TYPE_SET_SSTIFS		0xe
 #define MESSAGE_TYPE_CHANGE_BBTYPE	0xf
@@ -307,8 +307,8 @@
 
 	struct vnt_cmd_card_init init_command;
 	struct vnt_rsp_card_init init_response;
-	u8 current_net_addr[ETH_ALEN];
-	u8 permanent_net_addr[ETH_ALEN];
+	u8 current_net_addr[ETH_ALEN] __aligned(2);
+	u8 permanent_net_addr[ETH_ALEN] __aligned(2);
 
 	u8 exist_sw_net_addr;
 
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index fab195f..95e0e83 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -32,6 +32,6 @@
 #include "device.h"
 
 int vnt_rx_data(struct vnt_private *, struct vnt_rcb *,
-	unsigned long bytes_recieved);
+	unsigned long bytes_received);
 
 #endif /* __RXTX_H__ */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index b95d5b1..71adc1f 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -34,6 +34,7 @@
  */
 #undef __NO_VERSION__
 
+#include <linux/etherdevice.h>
 #include <linux/file.h>
 #include "device.h"
 #include "card.h"
@@ -319,7 +320,7 @@
 
 	/* get permanent network address */
 	memcpy(priv->permanent_net_addr, init_rsp->net_addr, 6);
-	memcpy(priv->current_net_addr, priv->permanent_net_addr, ETH_ALEN);
+	ether_addr_copy(priv->current_net_addr, priv->permanent_net_addr);
 
 	/* if exist SW network address, use it */
 	dev_dbg(&priv->usb->dev, "Network address = %pM\n",
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index ea5140a..33baf26 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -36,6 +36,7 @@
  *
  */
 
+#include <linux/etherdevice.h>
 #include "device.h"
 #include "rxtx.h"
 #include "card.h"
@@ -55,7 +56,7 @@
 
 static const u16 vnt_fb_opt1[2][5] = {
 	{RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */
-	{RATE_6M , RATE_6M,  RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
+	{RATE_6M,  RATE_6M,  RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
 };
 
 #define RTSDUR_BB       0
@@ -392,8 +393,8 @@
 	rts->frame_control =
 		cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
 
-	memcpy(rts->ra, hdr->addr1, ETH_ALEN);
-	memcpy(rts->ta, hdr->addr2, ETH_ALEN);
+	ether_addr_copy(rts->ra, hdr->addr1);
+	ether_addr_copy(rts->ta, hdr->addr2);
 
 	return 0;
 }
@@ -517,65 +518,66 @@
 	return vnt_rxtx_datahead_a_fb(tx_context, &buf->data_head);
 }
 
-static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context,
-	union vnt_tx_data_head *head)
+static u16 vnt_fill_cts_fb_head(struct vnt_usb_send_context *tx_context,
+				union vnt_tx_data_head *head)
 {
 	struct vnt_private *priv = tx_context->priv;
+	struct vnt_cts_fb *buf = &head->cts_g_fb;
 	u32 cts_frame_len = 14;
 	u16 current_rate = tx_context->tx_rate;
 
-	if (!head)
-		return 0;
+	/* Get SignalField,ServiceField,Length */
+	vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate,
+			  PK_TYPE_11B, &buf->b);
 
-	if (tx_context->fb_option) {
-		/* Auto Fall back */
-		struct vnt_cts_fb *buf = &head->cts_g_fb;
-		/* Get SignalField,ServiceField,Length */
-		vnt_get_phy_field(priv, cts_frame_len,
-			priv->top_cck_basic_rate, PK_TYPE_11B, &buf->b);
-		buf->duration_ba =
-			vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
-						   tx_context->pkt_type,
-						   current_rate);
-		/* Get CTSDuration_ba_f0 */
-		buf->cts_duration_ba_f0 =
-			vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0,
-						   tx_context->pkt_type,
-						   priv->tx_rate_fb0);
-		/* Get CTSDuration_ba_f1 */
-		buf->cts_duration_ba_f1 =
-			vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1,
-						   tx_context->pkt_type,
-						   priv->tx_rate_fb1);
-		/* Get CTS Frame body */
-		buf->data.duration = buf->duration_ba;
-		buf->data.frame_control =
-			cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
+	buf->duration_ba =
+		vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
+					   tx_context->pkt_type,
+					   current_rate);
+	/* Get CTSDuration_ba_f0 */
+	buf->cts_duration_ba_f0 =
+		vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0,
+					   tx_context->pkt_type,
+					   priv->tx_rate_fb0);
+	/* Get CTSDuration_ba_f1 */
+	buf->cts_duration_ba_f1 =
+		vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1,
+					   tx_context->pkt_type,
+					   priv->tx_rate_fb1);
+	/* Get CTS Frame body */
+	buf->data.duration = buf->duration_ba;
+	buf->data.frame_control =
+		cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
 
-		memcpy(buf->data.ra, priv->current_net_addr, ETH_ALEN);
+	ether_addr_copy(buf->data.ra, priv->current_net_addr);
 
-		return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
-	} else {
-		struct vnt_cts *buf = &head->cts_g;
-		/* Get SignalField,ServiceField,Length */
-		vnt_get_phy_field(priv, cts_frame_len,
-			priv->top_cck_basic_rate, PK_TYPE_11B, &buf->b);
-		/* Get CTSDuration_ba */
-		buf->duration_ba =
-			vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
-						   tx_context->pkt_type,
-						   current_rate);
-		/*Get CTS Frame body*/
-		buf->data.duration = buf->duration_ba;
-		buf->data.frame_control =
-			cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
+	return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
+}
 
-		memcpy(buf->data.ra, priv->current_net_addr, ETH_ALEN);
+static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context,
+			     union vnt_tx_data_head *head)
+{
+	struct vnt_private *priv = tx_context->priv;
+	struct vnt_cts *buf = &head->cts_g;
+	u32 cts_frame_len = 14;
+	u16 current_rate = tx_context->tx_rate;
 
-		return vnt_rxtx_datahead_g(tx_context, &buf->data_head);
-	}
+	/* Get SignalField,ServiceField,Length */
+	vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate,
+			  PK_TYPE_11B, &buf->b);
+	/* Get CTSDuration_ba */
+	buf->duration_ba =
+		vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
+					   tx_context->pkt_type,
+					   current_rate);
+	/*Get CTS Frame body*/
+	buf->data.duration = buf->duration_ba;
+	buf->data.frame_control =
+		cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
 
-	return 0;
+	ether_addr_copy(buf->data.ra, priv->current_net_addr);
+
+	return vnt_rxtx_datahead_g(tx_context, &buf->data_head);
 }
 
 static u16 vnt_rxtx_rts(struct vnt_usb_send_context *tx_context,
@@ -632,6 +634,9 @@
 		head = &tx_head->tx_cts.tx.mic.head;
 
 	/* Fill CTS */
+	if (tx_context->fb_option)
+		return vnt_fill_cts_fb_head(tx_context, head);
+
 	return vnt_fill_cts_head(tx_context, head);
 }
 
@@ -739,7 +744,7 @@
 
 		mic_hdr->id = 0x59;
 		mic_hdr->payload_len = cpu_to_be16(payload_len);
-		memcpy(mic_hdr->mic_addr2, hdr->addr2, ETH_ALEN);
+		ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
 
 		ieee80211_get_key_tx_seq(tx_key, &seq);
 
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 20d146b..8f20910 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -879,7 +879,7 @@
 /* Unions for packaging all the known packet types together */
 
 typedef union hfa384x_usbout {
-	u16 type;
+	__le16 type;
 	hfa384x_usb_txfrm_t txfrm;
 	hfa384x_usb_cmdreq_t cmdreq;
 	hfa384x_usb_wridreq_t wridreq;
@@ -889,7 +889,7 @@
 } __packed hfa384x_usbout_t;
 
 typedef union hfa384x_usbin {
-	u16 type;
+	__le16 type;
 	hfa384x_usb_rxfrm_t rxfrm;
 	hfa384x_usb_txfrm_t txfrm;
 	hfa384x_usb_infofrm_t infofrm;
@@ -1268,7 +1268,7 @@
 	hfa384x_downloadbuffer_t bufinfo;
 	u16 dltimeout;
 
-	int scanflag;		/* to signal scan comlete */
+	int scanflag;		/* to signal scan complete */
 	int join_ap;		/* are we joined to a specific ap */
 	int join_retries;	/* number of join retries till we fail */
 	hfa384x_JoinRequest_data_t joinreq;	/* join request saved data */
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 55d2f56..28cd1c4 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -382,7 +382,7 @@
 *
 * Arguments:
 *	hw		device struct
-*	tx_urb		URB of data for tranmission
+*	tx_urb		URB of data for transmission
 *	memflags	memory allocation flags
 *
 * Returns:
@@ -2391,7 +2391,7 @@
 *	0		success
 *	>0		f/w reported error - f/w status code
 *	<0		driver reported error
-*	-ETIMEDOUT	timout waiting for the cmd regs to become
+*	-ETIMEDOUT	timeout waiting for the cmd regs to become
 *			available, or waiting for the control reg
 *			to indicate the Aux port is enabled.
 *	-ENODATA	the buffer does NOT contain a valid PDA.
@@ -3346,7 +3346,7 @@
 		if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0)
 			run_queue = 1;
 	} else {
-		const u16 intype = (usbin->type & ~cpu_to_le16(0x8000));
+		const __le16 intype = (usbin->type & ~cpu_to_le16(0x8000));
 
 		/*
 		 * Check that our message is what we're expecting ...
@@ -4123,12 +4123,11 @@
 			pr_debug("Encountered unknown PDR#=0x%04x, assuming it's ok.\n",
 				 pdrcode);
 			return 1;
-		} else {
-			/* bad code */
-			pr_debug("Encountered unknown PDR#=0x%04x, (>=0x1000), assuming it's bad.\n",
-				 pdrcode);
-			return 0;
 		}
+		break;
 	}
-	return 0;		/* avoid compiler warnings */
+	/* bad code */
+	pr_debug("Encountered unknown PDR#=0x%04x, (>=0x1000), assuming it's bad.\n",
+		 pdrcode);
+	return 0;
 }
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 7eaaf9a..bd69e8c 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -511,7 +511,7 @@
 * protocol.
 *
 * Arguments:
-*	proto	protocl number (in host order) to search for.
+*	proto	protocol number (in host order) to search for.
 *
 * Returns:
 *	1 - if the table is empty or a match is found.
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index 7221379..4b84b56 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -80,7 +80,7 @@
 /*----------------------------------------------------------------
 * p80211req_dorequest
 *
-* Handles an MLME reqest/confirm message.
+* Handles an MLME request/confirm message.
 *
 * Arguments:
 *	wlandev		WLAN device struct
diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h
index b62fdcb..16f1239 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.h
+++ b/drivers/staging/wlan-ng/prism2mgmt.h
@@ -45,7 +45,7 @@
 * --------------------------------------------------------------------
 *
 * This file contains the constants and data structures for interaction
-* with the hfa384x Wireless LAN (WLAN) Media Access Contoller (MAC).
+* with the hfa384x Wireless LAN (WLAN) Media Access Controller (MAC).
 * The hfa384x is a portion of the Harris PRISM(tm) WLAN chipset.
 *
 * [Implementation and usage notes]
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index df577df..10ad24a 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -199,7 +199,7 @@
 /*----------------------------------------------------------------
 * prism2sta_reset
 *
-* Not currently implented.
+* Currently not implemented.
 *
 * Arguments:
 *	wlandev		wlan device structure
@@ -662,7 +662,7 @@
 		       "ident:  ap f/w: id=0x%02x %d.%d.%d\n",
 		       hw->ident_sta_fw.id, hw->ident_sta_fw.major,
 		       hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
-		netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmeare loaded!\n");
+		netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmware loaded!\n");
 		goto failed;
 	}
 
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 709d49e..935c714 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -930,7 +930,7 @@
 			+ var->hsync_len;
 	unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
 			+ var->vsync_len;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
 	u8 cr_data;
 #endif
 	unsigned int drate = 0, hrate = 0;
@@ -952,7 +952,7 @@
 	} pr_debug("var->pixclock=%d, htotal=%d, vtotal=%d\n",
 			var->pixclock, htotal, vtotal);
 
-	if (var->pixclock && htotal && vtotal) {
+	if (var->pixclock) {
 		drate = 1000000000 / var->pixclock;
 		hrate = (drate * 1000) / htotal;
 		xgifb_info->refresh_rate = (unsigned int) (hrate * 2
@@ -1044,7 +1044,7 @@
 			xgifb_info->DstColor = 0x0000;
 			xgifb_info->XGI310_AccelDepth = 0x00000000;
 			xgifb_info->video_cmap_len = 256;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
 			cr_data = xgifb_reg_get(XGICR, 0x4D);
 			xgifb_reg_set(XGICR, 0x4D, (cr_data & 0xE0));
 #endif
@@ -1052,7 +1052,7 @@
 		case 16:
 			xgifb_info->DstColor = 0x8000;
 			xgifb_info->XGI310_AccelDepth = 0x00010000;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
 			cr_data = xgifb_reg_get(XGICR, 0x4D);
 			xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x0B));
 #endif
@@ -1062,7 +1062,7 @@
 			xgifb_info->DstColor = 0xC000;
 			xgifb_info->XGI310_AccelDepth = 0x00020000;
 			xgifb_info->video_cmap_len = 16;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
 			cr_data = xgifb_reg_get(XGICR, 0x4D);
 			xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x15));
 #endif
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index d9f85f9..b2d7600 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -931,7 +931,7 @@
 	struct serial_state *info = tty->driver_data;
         unsigned long flags;
 
-	if (serial_paranoia_check(info, tty->name, "rs_send_char"))
+	if (serial_paranoia_check(info, tty->name, "rs_send_xchar"))
 		return;
 
 	info->x_char = ch;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 3c60923..342b36b 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -112,7 +112,6 @@
 static int find_console_handle(void)
 {
 	struct device_node *np = of_stdout;
-	const char *sprop = NULL;
 	const uint32_t *iprop;
 
 	/* We don't care what the aliased node is actually called.  We only
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 59ed783..2054427 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1055,7 +1055,7 @@
 
 	outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
 	outw((length & 0xff) << 8 | 0x00, base);
-	outw((length & 0xff00), base);
+	outw((length & 0xff00u), base);
 	InterruptTheCard(base);
 
 	unlock_card(card);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4ddfa60..cf6e0f2 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -90,6 +90,7 @@
 struct n_tty_data {
 	/* producer-published */
 	size_t read_head;
+	size_t commit_head;
 	size_t canon_head;
 	size_t echo_head;
 	size_t echo_commit;
@@ -161,36 +162,11 @@
 	return put_user(x, ptr);
 }
 
-static int receive_room(struct tty_struct *tty)
-{
-	struct n_tty_data *ldata = tty->disc_data;
-	int left;
-
-	if (I_PARMRK(tty)) {
-		/* Multiply read_cnt by 3, since each byte might take up to
-		 * three times as many spaces when PARMRK is set (depending on
-		 * its flags, e.g. parity error). */
-		left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
-	} else
-		left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
-
-	/*
-	 * If we are doing input canonicalization, and there are no
-	 * pending newlines, let characters through without limit, so
-	 * that erase characters will be handled.  Other excess
-	 * characters will be beeped.
-	 */
-	if (left <= 0)
-		left = ldata->icanon && ldata->canon_head == ldata->read_tail;
-
-	return left;
-}
-
 /**
- *	n_tty_set_room	-	receive space
+ *	n_tty_kick_worker - start input worker (if required)
  *	@tty: terminal
  *
- *	Re-schedules the flip buffer work if space just became available.
+ *	Re-schedules the flip buffer work if it may have stopped
  *
  *	Caller holds exclusive termios_rwsem
  *	   or
@@ -198,12 +174,12 @@
  *		holds non-exclusive termios_rwsem
  */
 
-static void n_tty_set_room(struct tty_struct *tty)
+static void n_tty_kick_worker(struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
-	/* Did this open up the receive buffer? We may need to flip */
-	if (unlikely(ldata->no_room) && receive_room(tty)) {
+	/* Did the input worker stop? Restart it */
+	if (unlikely(ldata->no_room)) {
 		ldata->no_room = 0;
 
 		WARN_RATELIMIT(tty->port->itty == NULL,
@@ -224,7 +200,7 @@
 	ssize_t n = 0;
 
 	if (!ldata->icanon)
-		n = read_cnt(ldata);
+		n = ldata->commit_head - ldata->read_tail;
 	else
 		n = ldata->canon_head - ldata->read_tail;
 	return n;
@@ -247,17 +223,20 @@
 
 static void n_tty_check_throttle(struct tty_struct *tty)
 {
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
-		return;
+	struct n_tty_data *ldata = tty->disc_data;
+
 	/*
 	 * Check the remaining room for the input canonicalization
 	 * mode.  We don't want to throttle the driver if we're in
 	 * canonical mode and don't have a newline yet!
 	 */
+	if (ldata->icanon && ldata->canon_head == ldata->read_tail)
+		return;
+
 	while (1) {
 		int throttled;
 		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
-		if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
+		if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
 			break;
 		throttled = tty_throttle_safe(tty);
 		if (!throttled)
@@ -274,7 +253,7 @@
 			return;
 		if (!tty->count)
 			return;
-		n_tty_set_room(tty);
+		n_tty_kick_worker(tty);
 		n_tty_write_wakeup(tty->link);
 		if (waitqueue_active(&tty->link->write_wait))
 			wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
@@ -296,7 +275,7 @@
 			break;
 		if (!tty->count)
 			break;
-		n_tty_set_room(tty);
+		n_tty_kick_worker(tty);
 		unthrottled = tty_unthrottle_safe(tty);
 		if (!unthrottled)
 			break;
@@ -313,10 +292,6 @@
  *
  *	n_tty_receive_buf()/producer path:
  *		caller holds non-exclusive termios_rwsem
- *		modifies read_head
- *
- *	read_head is only considered 'published' if canonical mode is
- *	not active.
  */
 
 static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
@@ -340,6 +315,7 @@
 {
 	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
 	ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+	ldata->commit_head = 0;
 	ldata->echo_mark = 0;
 	ldata->line_start = 0;
 
@@ -379,7 +355,7 @@
 {
 	down_write(&tty->termios_rwsem);
 	reset_buffer_flags(tty->disc_data);
-	n_tty_set_room(tty);
+	n_tty_kick_worker(tty);
 
 	if (tty->link)
 		n_tty_packet_mode_flush(tty);
@@ -987,10 +963,6 @@
  *
  *	n_tty_receive_buf()/producer path:
  *		caller holds non-exclusive termios_rwsem
- *		modifies read_head
- *
- *	Modifying the read_head is not considered a publish in this context
- *	because canonical mode is active -- only canon_head publishes
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -1118,16 +1090,45 @@
  *	Called when a signal is being sent due to terminal input.
  *	Called from the driver receive_buf path so serialized.
  *
+ *	Performs input and output flush if !NOFLSH. In this context, the echo
+ *	buffer is 'output'. The signal is processed first to alert any current
+ *	readers or writers to discontinue and exit their i/o loops.
+ *
  *	Locking: ctrl_lock
  */
 
 static void isig(int sig, struct tty_struct *tty)
 {
+	struct n_tty_data *ldata = tty->disc_data;
 	struct pid *tty_pgrp = tty_get_pgrp(tty);
 	if (tty_pgrp) {
 		kill_pgrp(tty_pgrp, sig, 1);
 		put_pid(tty_pgrp);
 	}
+
+	if (!L_NOFLSH(tty)) {
+		up_read(&tty->termios_rwsem);
+		down_write(&tty->termios_rwsem);
+
+		/* clear echo buffer */
+		mutex_lock(&ldata->output_lock);
+		ldata->echo_head = ldata->echo_tail = 0;
+		ldata->echo_mark = ldata->echo_commit = 0;
+		mutex_unlock(&ldata->output_lock);
+
+		/* clear output buffer */
+		tty_driver_flush_buffer(tty);
+
+		/* clear input buffer */
+		reset_buffer_flags(tty->disc_data);
+
+		/* notify pty master of flush */
+		if (tty->link)
+			n_tty_packet_mode_flush(tty);
+
+		up_write(&tty->termios_rwsem);
+		down_read(&tty->termios_rwsem);
+	}
 }
 
 /**
@@ -1139,7 +1140,6 @@
  *
  *	n_tty_receive_buf()/producer path:
  *		caller holds non-exclusive termios_rwsem
- *		publishes read_head via put_tty_queue()
  *
  *	Note: may get exclusive termios_rwsem if flushing input buffer
  */
@@ -1152,13 +1152,6 @@
 		return;
 	if (I_BRKINT(tty)) {
 		isig(SIGINT, tty);
-		if (!L_NOFLSH(tty)) {
-			/* flushing needs exclusive termios_rwsem */
-			up_read(&tty->termios_rwsem);
-			n_tty_flush_buffer(tty);
-			tty_driver_flush_buffer(tty);
-			down_read(&tty->termios_rwsem);
-		}
 		return;
 	}
 	if (I_PARMRK(tty)) {
@@ -1209,7 +1202,6 @@
  *
  *	n_tty_receive_buf()/producer path:
  *		caller holds non-exclusive termios_rwsem
- *		publishes read_head via put_tty_queue()
  */
 static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
 {
@@ -1233,13 +1225,7 @@
 static void
 n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
 {
-	if (!L_NOFLSH(tty)) {
-		/* flushing needs exclusive termios_rwsem */
-		up_read(&tty->termios_rwsem);
-		n_tty_flush_buffer(tty);
-		tty_driver_flush_buffer(tty);
-		down_read(&tty->termios_rwsem);
-	}
+	isig(signal, tty);
 	if (I_IXON(tty))
 		start_tty(tty);
 	if (L_ECHO(tty)) {
@@ -1247,7 +1233,6 @@
 		commit_echoes(tty);
 	} else
 		process_echoes(tty);
-	isig(signal, tty);
 	return;
 }
 
@@ -1263,7 +1248,6 @@
  *	n_tty_receive_buf()/producer path:
  *		caller holds non-exclusive termios_rwsem
  *		publishes canon_head if canonical mode is active
- *		otherwise, publishes read_head via put_tty_queue()
  *
  *	Returns 1 if LNEXT was received, else returns 0
  */
@@ -1376,7 +1360,7 @@
 handle_newline:
 			set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
 			put_tty_queue(c, ldata);
-			ldata->canon_head = ldata->read_head;
+			smp_store_release(&ldata->canon_head, ldata->read_head);
 			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
 			if (waitqueue_active(&tty->read_wait))
 				wake_up_interruptible_poll(&tty->read_wait, POLLIN);
@@ -1512,23 +1496,6 @@
 		n_tty_receive_char_flagged(tty, c, flag);
 }
 
-/**
- *	n_tty_receive_buf	-	data receive
- *	@tty: terminal device
- *	@cp: buffer
- *	@fp: flag buffer
- *	@count: characters
- *
- *	Called by the terminal driver when a block of characters has
- *	been received. This function must be called from soft contexts
- *	not from interrupt context. The driver is responsible for making
- *	calls one at a time and in order (or using flush_to_ldisc)
- *
- *	n_tty_receive_buf()/producer path:
- *		claims non-exclusive termios_rwsem
- *		publishes read_head and canon_head
- */
-
 static void
 n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
 			   char *fp, int count)
@@ -1537,16 +1504,14 @@
 	size_t n, head;
 
 	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
-	n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
-	n = min_t(size_t, count, n);
+	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
 	memcpy(read_buf_addr(ldata, head), cp, n);
 	ldata->read_head += n;
 	cp += n;
 	count -= n;
 
 	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
-	n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
-	n = min_t(size_t, count, n);
+	n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
 	memcpy(read_buf_addr(ldata, head), cp, n);
 	ldata->read_head += n;
 }
@@ -1676,32 +1641,98 @@
 			tty->ops->flush_chars(tty);
 	}
 
-	if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) ||
-		L_EXTPROC(tty)) {
+	if (ldata->icanon && !L_EXTPROC(tty))
+		return;
+
+	/* publish read_head to consumer */
+	smp_store_release(&ldata->commit_head, ldata->read_head);
+
+	if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
 		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
 		if (waitqueue_active(&tty->read_wait))
 			wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 	}
 }
 
+/**
+ *	n_tty_receive_buf_common	-	process input
+ *	@tty: device to receive input
+ *	@cp: input chars
+ *	@fp: flags for each char (if NULL, all chars are TTY_NORMAL)
+ *	@count: number of input chars in @cp
+ *
+ *	Called by the terminal driver when a block of characters has
+ *	been received. This function must be called from soft contexts
+ *	not from interrupt context. The driver is responsible for making
+ *	calls one at a time and in order (or using flush_to_ldisc)
+ *
+ *	Returns the # of input chars from @cp which were processed.
+ *
+ *	In canonical mode, the maximum line length is 4096 chars (including
+ *	the line termination char); lines longer than 4096 chars are
+ *	truncated. After 4095 chars, input data is still processed but
+ *	not stored. Overflow processing ensures the tty can always
+ *	receive more input until at least one line can be read.
+ *
+ *	In non-canonical mode, the read buffer will only accept 4095 chars;
+ *	this provides the necessary space for a newline char if the input
+ *	mode is switched to canonical.
+ *
+ *	Note it is possible for the read buffer to _contain_ 4096 chars
+ *	in non-canonical mode: the read buffer could already contain the
+ *	maximum canon line of 4096 chars when the mode is switched to
+ *	non-canonical.
+ *
+ *	n_tty_receive_buf()/producer path:
+ *		claims non-exclusive termios_rwsem
+ *		publishes commit_head or canon_head
+ */
 static int
 n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
 			 char *fp, int count, int flow)
 {
 	struct n_tty_data *ldata = tty->disc_data;
-	int room, n, rcvd = 0;
+	int room, n, rcvd = 0, overflow;
 
 	down_read(&tty->termios_rwsem);
 
 	while (1) {
-		room = receive_room(tty);
+		/*
+		 * When PARMRK is set, each input char may take up to 3 chars
+		 * in the read buf; reduce the buffer space avail by 3x
+		 *
+		 * If we are doing input canonicalization, and there are no
+		 * pending newlines, let characters through without limit, so
+		 * that erase characters will be handled.  Other excess
+		 * characters will be beeped.
+		 *
+		 * paired with store in *_copy_from_read_buf() -- guarantees
+		 * the consumer has loaded the data in read_buf up to the new
+		 * read_tail (so this producer will not overwrite unread data)
+		 */
+		size_t tail = smp_load_acquire(&ldata->read_tail);
+
+		room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
+		if (I_PARMRK(tty))
+			room = (room + 2) / 3;
+		room--;
+		if (room <= 0) {
+			overflow = ldata->icanon && ldata->canon_head == tail;
+			if (overflow && room < 0)
+				ldata->read_head--;
+			room = overflow;
+			ldata->no_room = flow && !room;
+		} else
+			overflow = 0;
+
 		n = min(count, room);
-		if (!n) {
-			if (flow && !room)
-				ldata->no_room = 1;
+		if (!n)
 			break;
-		}
-		__receive_buf(tty, cp, fp, n);
+
+		/* ignore parity errors if handling overflow */
+		if (!overflow || !fp || *fp != TTY_PARITY)
+			__receive_buf(tty, cp, fp, n);
+
 		cp += n;
 		if (fp)
 			fp += n;
@@ -1710,7 +1741,17 @@
 	}
 
 	tty->receive_room = room;
-	n_tty_check_throttle(tty);
+
+	/* Unthrottle if handling overflow on pty */
+	if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
+		if (overflow) {
+			tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+			tty_unthrottle_safe(tty);
+			__tty_set_flow_change(tty, 0);
+		}
+	} else
+		n_tty_check_throttle(tty);
+
 	up_read(&tty->termios_rwsem);
 
 	return rcvd;
@@ -1764,6 +1805,7 @@
 			ldata->canon_head = ldata->read_head;
 			ldata->push = 1;
 		}
+		ldata->commit_head = ldata->read_head;
 		ldata->erasing = 0;
 		ldata->lnext = 0;
 	}
@@ -1817,7 +1859,6 @@
 		else
 			ldata->real_raw = 0;
 	}
-	n_tty_set_room(tty);
 	/*
 	 * Fix tty hang when I_IXON(tty) is cleared, but the tty
 	 * been stopped by STOP_CHAR(tty) before it.
@@ -1905,7 +1946,7 @@
 	if (ldata->icanon && !L_EXTPROC(tty))
 		return ldata->canon_head != ldata->read_tail;
 	else
-		return read_cnt(ldata) >= amt;
+		return ldata->commit_head - ldata->read_tail >= amt;
 }
 
 /**
@@ -1937,10 +1978,11 @@
 	int retval;
 	size_t n;
 	bool is_eof;
+	size_t head = smp_load_acquire(&ldata->commit_head);
 	size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
 
 	retval = 0;
-	n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail);
+	n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
 	n = min(*nr, n);
 	if (n) {
 		retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
@@ -1948,9 +1990,10 @@
 		is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
 		tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
 				ldata->icanon);
-		ldata->read_tail += n;
+		smp_store_release(&ldata->read_tail, ldata->read_tail + n);
 		/* Turn single EOF into zero-length read */
-		if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata))
+		if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
+		    (head == ldata->read_tail))
 			n = 0;
 		*b += n;
 		*nr -= n;
@@ -1993,7 +2036,7 @@
 	bool eof_push = 0;
 
 	/* N.B. avoid overrun if nr == 0 */
-	n = min(*nr, read_cnt(ldata));
+	n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
 	if (!n)
 		return 0;
 
@@ -2043,8 +2086,7 @@
 
 	if (found)
 		clear_bit(eol, ldata->read_flags);
-	smp_mb__after_atomic();
-	ldata->read_tail += c;
+	smp_store_release(&ldata->read_tail, ldata->read_tail + c);
 
 	if (found) {
 		if (!ldata->push)
@@ -2130,6 +2172,7 @@
 	ssize_t retval = 0;
 	long timeout;
 	int packet;
+	size_t tail;
 
 	c = job_control(tty, file);
 	if (c < 0)
@@ -2166,6 +2209,7 @@
 	}
 
 	packet = tty->packet;
+	tail = ldata->read_tail;
 
 	add_wait_queue(&tty->read_wait, &wait);
 	while (nr) {
@@ -2208,7 +2252,6 @@
 				retval = -ERESTARTSYS;
 				break;
 			}
-			n_tty_set_room(tty);
 			up_read(&tty->termios_rwsem);
 
 			timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
@@ -2253,7 +2296,8 @@
 		if (time)
 			timeout = time;
 	}
-	n_tty_set_room(tty);
+	if (tail != ldata->read_tail)
+		n_tty_kick_worker(tty);
 	up_read(&tty->termios_rwsem);
 
 	remove_wait_queue(&tty->read_wait, &wait);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a9d256d..e72ee62 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -88,19 +88,6 @@
 }
 
 /**
- *	pty_space	-	report space left for writing
- *	@to: tty we are writing into
- *
- *	Limit the buffer space used by ptys to 8k.
- */
-
-static int pty_space(struct tty_struct *to)
-{
-	int n = tty_buffer_space_avail(to->port);
-	return min(n, 8192);
-}
-
-/**
  *	pty_write		-	write to a pty
  *	@tty: the tty we write from
  *	@buf: kernel buffer of data
@@ -141,7 +128,7 @@
 {
 	if (tty->stopped)
 		return 0;
-	return pty_space(tty->link);
+	return tty_buffer_space_avail(tty->link->port);
 }
 
 /**
@@ -210,6 +197,9 @@
 {
 	struct pid *pgrp;
 
+	if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP)
+		return -EINVAL;
+
 	if (tty->link) {
 		pgrp = tty_get_pgrp(tty->link);
 		if (pgrp)
@@ -222,10 +212,16 @@
 static void pty_flush_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
+	struct tty_ldisc *ld;
 
 	if (!to)
 		return;
-	/* tty_buffer_flush(to); FIXME */
+
+	ld = tty_ldisc_ref(to);
+	tty_buffer_flush(to, ld);
+	if (ld)
+		tty_ldisc_deref(ld);
+
 	if (to->packet) {
 		spin_lock_irq(&tty->ctrl_lock);
 		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -399,6 +395,7 @@
 		goto err_put_module;
 
 	tty_set_lock_subclass(o_tty);
+	lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
 
 	if (legacy) {
 		/* We always use new tty termios data so we can do this
@@ -429,10 +426,14 @@
 	o_tty->link = tty;
 	tty_port_init(ports[0]);
 	tty_port_init(ports[1]);
+	tty_buffer_set_limit(ports[0], 8192);
+	tty_buffer_set_limit(ports[1], 8192);
 	o_tty->port = ports[0];
 	tty->port = ports[1];
 	o_tty->port->itty = o_tty;
 
+	tty_buffer_set_lock_subclass(o_tty->port);
+
 	tty_driver_kref_get(driver);
 	tty->count++;
 	o_tty->count++;
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 383c4c7..c8dd8dc 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -1390,7 +1390,7 @@
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
-	if (rocket_paranoia_check(info, "rp_throttle"))
+	if (rocket_paranoia_check(info, "rp_unthrottle"))
 		return;
 
 	if (I_IXOFF(tty))
@@ -1458,7 +1458,7 @@
 
 	orig_jiffies = jiffies;
 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
-	printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
+	printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout,
 	       jiffies);
 	printk(KERN_INFO "cps=%d...\n", info->cps);
 #endif
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 11c6685..e3b9570a 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -329,6 +329,17 @@
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+workaround of errata A-008006 which states that tx_loadsz should  be
+configured less than Maximum supported fifo bytes */
+	[PORT_16550A_FSL64] = {
+		.name		= "16550A_FSL64",
+		.fifo_size	= 64,
+		.tx_loadsz	= 63,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+				  UART_FCR7_64BYTE,
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
@@ -956,7 +967,17 @@
 			up->port.type = PORT_16650;
 			up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
 		} else {
-			DEBUG_AUTOCONF("Motorola 8xxx DUART ");
+			serial_out(up, UART_LCR, 0);
+			serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+				   UART_FCR7_64BYTE);
+			status1 = serial_in(up, UART_IIR) >> 5;
+			serial_out(up, UART_FCR, 0);
+			serial_out(up, UART_LCR, 0);
+
+			if (status1 == 7)
+				up->port.type = PORT_16550A_FSL64;
+			else
+				DEBUG_AUTOCONF("Motorola 8xxx DUART ");
 		}
 		serial_out(up, UART_EFR, 0);
 		return;
@@ -1355,9 +1376,11 @@
 	struct uart_8250_port *up = up_to_u8250p(port);
 
 	serial8250_rpm_get_tx(up);
-	if (up->dma && !up->dma->tx_dma(up)) {
+
+	if (up->dma && !up->dma->tx_dma(up))
 		return;
-	} else if (!(up->ier & UART_IER_THRI)) {
+
+	if (!(up->ier & UART_IER_THRI)) {
 		up->ier |= UART_IER_THRI;
 		serial_port_out(port, UART_IER, up->ier);
 
@@ -1365,7 +1388,7 @@
 			unsigned char lsr;
 			lsr = serial_in(up, UART_LSR);
 			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-			if (lsr & UART_LSR_TEMT)
+			if (lsr & UART_LSR_THRE)
 				serial8250_tx_chars(up);
 		}
 	}
@@ -1924,7 +1947,7 @@
 	return ret;
 }
 
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	struct uart_8250_port *up = up_to_u8250p(port);
 	unsigned char mcr = 0;
@@ -1944,6 +1967,14 @@
 
 	serial_port_out(port, UART_MCR, mcr);
 }
+EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	if (port->set_mctrl)
+		return port->set_mctrl(port, mctrl);
+	return serial8250_do_set_mctrl(port, mctrl);
+}
 
 static void serial8250_break_ctl(struct uart_port *port, int break_state)
 {
@@ -2382,13 +2413,34 @@
 		serial8250_do_shutdown(port);
 }
 
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+/*
+ * XR17V35x UARTs have an extra fractional divisor register (DLD)
+ * Calculate divisor with extra 4-bit fractional portion
+ */
+static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up,
+					 unsigned int baud,
+					 unsigned int *frac)
 {
+	struct uart_port *port = &up->port;
+	unsigned int quot_16;
+
+	quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud);
+	*frac = quot_16 & 0x0f;
+
+	return quot_16 >> 4;
+}
+
+static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
+					   unsigned int baud,
+					   unsigned int *frac)
+{
+	struct uart_port *port = &up->port;
 	unsigned int quot;
 
 	/*
 	 * Handle magic divisors for baud rates above baud_base on
 	 * SMSC SuperIO chips.
+	 *
 	 */
 	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
 	    baud == (port->uartclk/4))
@@ -2396,22 +2448,26 @@
 	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
 		 baud == (port->uartclk/8))
 		quot = 0x8002;
+	else if (up->port.type == PORT_XR17V35X)
+		quot = xr17v35x_get_divisor(up, baud, frac);
 	else
 		quot = uart_get_divisor(port, baud);
 
+	/*
+	 * Oxford Semi 952 rev B workaround
+	 */
+	if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
+		quot++;
+
 	return quot;
 }
 
-void
-serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
-		          struct ktermios *old)
+static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
+					    tcflag_t c_cflag)
 {
-	struct uart_8250_port *up = up_to_u8250p(port);
 	unsigned char cval;
-	unsigned long flags;
-	unsigned int baud, quot;
 
-	switch (termios->c_cflag & CSIZE) {
+	switch (c_cflag & CSIZE) {
 	case CS5:
 		cval = UART_LCR_WLEN5;
 		break;
@@ -2427,33 +2483,80 @@
 		break;
 	}
 
-	if (termios->c_cflag & CSTOPB)
+	if (c_cflag & CSTOPB)
 		cval |= UART_LCR_STOP;
-	if (termios->c_cflag & PARENB) {
+	if (c_cflag & PARENB) {
 		cval |= UART_LCR_PARITY;
 		if (up->bugs & UART_BUG_PARITY)
 			up->fifo_bug = true;
 	}
-	if (!(termios->c_cflag & PARODD))
+	if (!(c_cflag & PARODD))
 		cval |= UART_LCR_EPAR;
 #ifdef CMSPAR
-	if (termios->c_cflag & CMSPAR)
+	if (c_cflag & CMSPAR)
 		cval |= UART_LCR_SPAR;
 #endif
 
+	return cval;
+}
+
+static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
+			    unsigned int quot, unsigned int quot_frac)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+
+	/* Workaround to enable 115200 baud on OMAP1510 internal ports */
+	if (is_omap1510_8250(up)) {
+		if (baud == 115200) {
+			quot = 1;
+			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
+		} else
+			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
+	}
+
+	/*
+	 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
+	 * otherwise just set DLAB
+	 */
+	if (up->capabilities & UART_NATSEMI)
+		serial_port_out(port, UART_LCR, 0xe0);
+	else
+		serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+
+	serial_dl_write(up, quot);
+
+	/* XR17V35x UARTs have an extra fractional divisor register (DLD) */
+	if (up->port.type == PORT_XR17V35X)
+		serial_port_out(port, 0x2, quot_frac);
+}
+
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+		          struct ktermios *old)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	unsigned char cval;
+	unsigned long flags;
+	unsigned int baud, quot, frac = 0;
+
+	cval = serial8250_compute_lcr(up, termios->c_cflag);
+
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
 	baud = uart_get_baud_rate(port, termios, old,
 				  port->uartclk / 16 / 0xffff,
 				  port->uartclk / 16);
-	quot = serial8250_get_divisor(port, baud);
+	quot = serial8250_get_divisor(up, baud, &frac);
 
 	/*
-	 * Oxford Semi 952 rev B workaround
+	 * Ok, we're now changing the port state.  Do it with
+	 * interrupts disabled.
 	 */
-	if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
-		quot++;
+	serial8250_rpm_get(up);
+	spin_lock_irqsave(&port->lock, flags);
+
+	up->lcr = cval;					/* Save computed LCR */
 
 	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
 		/* NOTE: If fifo_bug is not set, a user can set RX_trigger. */
@@ -2478,13 +2581,6 @@
 	}
 
 	/*
-	 * Ok, we're now changing the port state.  Do it with
-	 * interrupts disabled.
-	 */
-	serial8250_rpm_get(up);
-	spin_lock_irqsave(&port->lock, flags);
-
-	/*
 	 * Update the per-port timeout.
 	 */
 	uart_update_timeout(port, termios->c_cflag, baud);
@@ -2548,43 +2644,7 @@
 			serial_port_out(port, UART_EFR, efr);
 	}
 
-	/* Workaround to enable 115200 baud on OMAP1510 internal ports */
-	if (is_omap1510_8250(up)) {
-		if (baud == 115200) {
-			quot = 1;
-			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
-		} else
-			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
-	}
-
-	/*
-	 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
-	 * otherwise just set DLAB
-	 */
-	if (up->capabilities & UART_NATSEMI)
-		serial_port_out(port, UART_LCR, 0xe0);
-	else
-		serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB);
-
-	serial_dl_write(up, quot);
-
-	/*
-	 * XR17V35x UARTs have an extra fractional divisor register (DLD)
-	 *
-	 * We need to recalculate all of the registers, because DLM and DLL
-	 * are already rounded to a whole integer.
-	 *
-	 * When recalculating we use a 32x clock instead of a 16x clock to
-	 * allow 1-bit for rounding in the fractional part.
-	 */
-	if (up->port.type == PORT_XR17V35X) {
-		unsigned int baud_x32 = (port->uartclk * 2) / baud;
-		u16 quot = baud_x32 / 32;
-		u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
-
-		serial_dl_write(up, quot);
-		serial_port_out(port, 0x2, quot_frac & 0xf);
-	}
+	serial8250_set_divisor(port, baud, quot, frac);
 
 	/*
 	 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -2593,8 +2653,7 @@
 	if (port->type == PORT_16750)
 		serial_port_out(port, UART_FCR, up->fcr);
 
-	serial_port_out(port, UART_LCR, cval);		/* reset DLAB */
-	up->lcr = cval;					/* Save LCR */
+	serial_port_out(port, UART_LCR, up->lcr);	/* reset DLAB */
 	if (port->type != PORT_16750) {
 		/* emulated UARTs (Lucent Venus 167x) need two steps */
 		if (up->fcr & UART_FCR_ENABLE_FIFO)
@@ -3208,6 +3267,27 @@
 	else
 		serial_port_out(port, UART_IER, 0);
 
+	/* check scratch reg to see if port powered off during system sleep */
+	if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
+		struct ktermios termios;
+		unsigned int baud, quot, frac = 0;
+
+		termios.c_cflag = port->cons->cflag;
+		if (port->state->port.tty && termios.c_cflag == 0)
+			termios.c_cflag = port->state->port.tty->termios.c_cflag;
+
+		baud = uart_get_baud_rate(port, &termios, NULL,
+					  port->uartclk / 16 / 0xffff,
+					  port->uartclk / 16);
+		quot = serial8250_get_divisor(up, baud, &frac);
+
+		serial8250_set_divisor(port, baud, quot, frac);
+		serial_port_out(port, UART_LCR, up->lcr);
+		serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+		up->canary = 0;
+	}
+
 	uart_console_write(port, s, count, serial8250_console_putchar);
 
 	/*
@@ -3358,7 +3438,17 @@
  */
 void serial8250_suspend_port(int line)
 {
-	uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
+	struct uart_8250_port *up = &serial8250_ports[line];
+	struct uart_port *port = &up->port;
+
+	if (!console_suspend_enabled && uart_console(port) &&
+	    port->type != PORT_8250) {
+		unsigned char canary = 0xa5;
+		serial_out(up, UART_SCR, canary);
+		up->canary = canary;
+	}
+
+	uart_suspend_port(&serial8250_reg, port);
 }
 
 /**
@@ -3372,6 +3462,8 @@
 	struct uart_8250_port *up = &serial8250_ports[line];
 	struct uart_port *port = &up->port;
 
+	up->canary = 0;
+
 	if (up->capabilities & UART_NATSEMI) {
 		/* Ensure it's still in high speed mode */
 		serial_port_out(port, UART_LCR, 0xE0);
@@ -3605,6 +3697,8 @@
 		/*  Possibly override set_termios call */
 		if (up->port.set_termios)
 			uart->port.set_termios = up->port.set_termios;
+		if (up->port.set_mctrl)
+			uart->port.set_mctrl = up->port.set_mctrl;
 		if (up->port.startup)
 			uart->port.startup = up->port.startup;
 		if (up->port.shutdown)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index fcd7ac6..21d01a4 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -59,7 +59,6 @@
 
 	dma->rx_running = 0;
 	dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
-	dmaengine_terminate_all(dma->rxchan);
 
 	count = dma->rx_size - state.residue;
 
@@ -81,6 +80,10 @@
 		return 0;
 
 	dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+	if (dma->tx_size < p->port.fifosize) {
+		ret = -EINVAL;
+		goto err;
+	}
 
 	desc = dmaengine_prep_slave_single(dma->txchan,
 					   dma->tx_addr + xmit->tail,
@@ -131,6 +134,7 @@
 		if (dma->rx_running) {
 			dmaengine_pause(dma->rxchan);
 			__dma_rx_complete(p);
+			dmaengine_terminate_all(dma->rxchan);
 		}
 		return -ETIMEDOUT;
 	default:
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 555de07..e601162 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -351,10 +351,20 @@
 static int dw8250_probe_acpi(struct uart_8250_port *up,
 			     struct dw8250_data *data)
 {
+	const struct acpi_device_id *id;
 	struct uart_port *p = &up->port;
 
 	dw8250_setup_port(up);
 
+	id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
+	if (!id)
+		return -ENODEV;
+
+	if (!p->uartclk)
+		if (device_property_read_u32(p->dev, "clock-frequency",
+					     &p->uartclk))
+			return -EINVAL;
+
 	p->iotype = UPIO_MEM32;
 	p->serial_in = dw8250_serial_in32;
 	p->serial_out = dw8250_serial_out32;
@@ -577,6 +587,7 @@
 	{ "INT3435", 0 },
 	{ "80860F0A", 0 },
 	{ "8086228A", 0 },
+	{ "APMC0D08", 0},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 4858b8a..c31a22b 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -93,15 +93,18 @@
 	struct uart_port *port = &early_device->port;
 	unsigned int ier;
 
-	/* Save the IER and disable interrupts */
+	/* Save the IER and disable interrupts preserving the UUE bit */
 	ier = serial8250_early_in(port, UART_IER);
-	serial8250_early_out(port, UART_IER, 0);
+	if (ier)
+		serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
 
 	uart_console_write(port, s, count, serial_putc);
 
 	/* Wait for transmitter to become empty and restore the IER */
 	wait_for_xmitr(port);
-	serial8250_early_out(port, UART_IER, ier);
+
+	if (ier)
+		serial8250_early_out(port, UART_IER, ier);
 }
 
 static unsigned int __init probe_baud(struct uart_port *port)
@@ -124,9 +127,11 @@
 	struct uart_port *port = &device->port;
 	unsigned int divisor;
 	unsigned char c;
+	unsigned int ier;
 
 	serial8250_early_out(port, UART_LCR, 0x3);	/* 8n1 */
-	serial8250_early_out(port, UART_IER, 0);	/* no interrupt */
+	ier = serial8250_early_in(port, UART_IER);
+	serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
 	serial8250_early_out(port, UART_FCR, 0);	/* no fifo */
 	serial8250_early_out(port, UART_MCR, 0x3);	/* DTR + RTS */
 
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 96b69bf..fe6d2e51 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -106,6 +106,28 @@
 	return readl(up->port.membase + (reg << up->port.regshift));
 }
 
+static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	struct omap8250_priv *priv = up->port.private_data;
+	u8 lcr;
+
+	serial8250_do_set_mctrl(port, mctrl);
+
+	/*
+	 * Turn off autoRTS if RTS is lowered and restore autoRTS setting
+	 * if RTS is raised
+	 */
+	lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+		priv->efr |= UART_EFR_RTS;
+	else
+		priv->efr &= ~UART_EFR_RTS;
+	serial_out(up, UART_EFR, priv->efr);
+	serial_out(up, UART_LCR, lcr);
+}
+
 /*
  * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
  * The access to uart register after MDR1 Access
@@ -397,12 +419,12 @@
 
 	priv->efr = 0;
 	up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
-	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
-		/* Enable AUTORTS and AUTOCTS */
-		priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
+	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
-		/* Ensure MCR RTS is asserted */
-		up->mcr |= UART_MCR_RTS;
+	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+		/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
+		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+		priv->efr |= UART_EFR_CTS;
 	} else	if (up->port.flags & UPF_SOFT_FLOW) {
 		/*
 		 * IXON Flag:
@@ -417,8 +439,10 @@
 		 * Enable XON/XOFF flow control on output.
 		 * Transmit XON1, XOFF1
 		 */
-		if (termios->c_iflag & IXOFF)
+		if (termios->c_iflag & IXOFF) {
+			up->port.status |= UPSTAT_AUTOXOFF;
 			priv->efr |= OMAP_UART_SW_TX;
+		}
 
 		/*
 		 * IXANY Flag:
@@ -450,18 +474,18 @@
 static void omap_8250_pm(struct uart_port *port, unsigned int state,
 			 unsigned int oldstate)
 {
-	struct uart_8250_port *up =
-		container_of(port, struct uart_8250_port, port);
-	struct omap8250_priv *priv = up->port.private_data;
+	struct uart_8250_port *up = up_to_u8250p(port);
+	u8 efr;
 
 	pm_runtime_get_sync(port->dev);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-	serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB);
+	efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, efr | UART_EFR_ECB);
 	serial_out(up, UART_LCR, 0);
 
 	serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-	serial_out(up, UART_EFR, priv->efr);
+	serial_out(up, UART_EFR, efr);
 	serial_out(up, UART_LCR, 0);
 
 	pm_runtime_mark_last_busy(port->dev);
@@ -1007,6 +1031,7 @@
 	up.capabilities |= UART_CAP_RPM;
 #endif
 	up.port.set_termios = omap_8250_set_termios;
+	up.port.set_mctrl = omap8250_set_mctrl;
 	up.port.pm = omap_8250_pm;
 	up.port.startup = omap_8250_startup;
 	up.port.shutdown = omap_8250_shutdown;
@@ -1248,6 +1273,46 @@
 }
 #endif
 
+#ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP
+static int __init omap8250_console_fixup(void)
+{
+	char *omap_str;
+	char *options;
+	u8 idx;
+
+	if (strstr(boot_command_line, "console=ttyS"))
+		/* user set a ttyS based name for the console */
+		return 0;
+
+	omap_str = strstr(boot_command_line, "console=ttyO");
+	if (!omap_str)
+		/* user did not set ttyO based console, so we don't care */
+		return 0;
+
+	omap_str += 12;
+	if ('0' <= *omap_str && *omap_str <= '9')
+		idx = *omap_str - '0';
+	else
+		return 0;
+
+	omap_str++;
+	if (omap_str[0] == ',') {
+		omap_str++;
+		options = omap_str;
+	} else {
+		options = NULL;
+	}
+
+	add_preferred_console("ttyS", idx, options);
+	pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
+	       idx, idx);
+	pr_err("This ensures that you still see kernel messages. Please\n");
+	pr_err("update your kernel commandline.\n");
+	return 0;
+}
+console_initcall(omap8250_console_fixup);
+#endif
+
 static const struct dev_pm_ops omap8250_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume)
 	SET_RUNTIME_PM_OPS(omap8250_runtime_suspend,
@@ -1269,7 +1334,6 @@
 		.name		= "omap8250",
 		.pm		= &omap8250_dev_pm_ops,
 		.of_match_table = omap8250_dt_ids,
-		.owner		= THIS_MODULE,
 	},
 	.probe			= omap8250_probe,
 	.remove			= omap8250_remove,
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index d1f8dc6..daf2c82 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -221,13 +221,13 @@
  */
 static int pci_inteli960ni_init(struct pci_dev *dev)
 {
-	unsigned long oldval;
+	u32 oldval;
 
 	if (!(dev->subsystem_device & 0x1000))
 		return -ENODEV;
 
 	/* is firmware started? */
-	pci_read_config_dword(dev, 0x44, (void *)&oldval);
+	pci_read_config_dword(dev, 0x44, &oldval);
 	if (oldval == 0x00001000L) { /* RESET value */
 		dev_dbg(&dev->dev, "Local i960 firmware missing\n");
 		return -ENODEV;
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 682a2fb..50a09cd 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -426,7 +426,7 @@
 static int
 serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
-	struct uart_8250_port uart;
+	struct uart_8250_port uart, *port;
 	int ret, line, flags = dev_id->driver_data;
 
 	if (flags & UNKNOWN_DEV) {
@@ -471,6 +471,10 @@
 	if (line < 0 || (flags & CIR_PORT))
 		return -ENODEV;
 
+	port = serial8250_get_port(line);
+	if (uart_console(&port->port))
+		dev->capabilities |= PNP_CONSOLE;
+
 	pnp_set_drvdata(dev, (void *)((long)line + 1));
 	return 0;
 }
@@ -478,6 +482,8 @@
 static void serial_pnp_remove(struct pnp_dev *dev)
 {
 	long line = (long)pnp_get_drvdata(dev);
+
+	dev->capabilities &= ~PNP_CONSOLE;
 	if (line)
 		serial8250_unregister_port(line - 1);
 }
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 0fcbcd2..6f7f2d7 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -308,6 +308,25 @@
 
 	  This driver uses ttyS instead of ttyO.
 
+config SERIAL_8250_OMAP_TTYO_FIXUP
+	bool "Replace ttyO with ttyS"
+	depends on SERIAL_8250_OMAP=y && SERIAL_8250_CONSOLE
+	default y
+	help
+	  This option replaces the "console=ttyO" argument with the matching
+	  ttyS argument if the user did not specified it on the command line.
+	  This ensures that the user can see the kernel output during boot
+	  which he wouldn't see otherwise. The getty has still to be configured
+	  for ttyS instead of ttyO regardless of this option.
+	  This option is intended for people who "automatically" enable this
+	  driver without knowing that this driver requires a different console=
+	  argument. If you read this, please keep this option disabled and
+	  instead update your kernel command line. If you prepare a kernel for a
+	  distribution or other kind of larger user base then you probably want
+	  to keep this option enabled. Otherwise people might complain about a
+	  not booting kernel because the serial console remains silent in case
+	  they forgot to update the command line.
+
 config SERIAL_8250_FINTEK
 	tristate "Support for Fintek F81216A LPC to 4 UART"
 	depends on SERIAL_8250 && PNP
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index c79b43c..5d916c7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -241,6 +241,7 @@
 	tristate "Samsung SoC serial support"
 	depends on PLAT_SAMSUNG || ARCH_EXYNOS
 	select SERIAL_CORE
+	select SERIAL_EARLYCON
 	help
 	  Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
 	  providing /dev/ttySAC0, 1 and 2 (note, some machines may not
@@ -482,16 +483,6 @@
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
-config SERIAL_MRST_MAX3110
-	tristate "SPI UART driver for Max3110"
-	depends on SPI_DW_PCI
-	select SERIAL_CORE
-	select SERIAL_CORE_CONSOLE
-	help
-	  This is the UART protocol driver for the MAX3110 device on
-	  the Intel Moorestown platform. On other systems use the max3100
-	  driver.
-
 config SERIAL_MFD_HSU
 	tristate "Medfield High Speed UART support"
 	depends on PCI
@@ -1094,6 +1085,16 @@
 	depends on SERIAL_VT8500=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_ETRAXFS
+	bool "ETRAX FS serial port support"
+	depends on ETRAX_ARCH_V32 && OF
+	select SERIAL_CORE
+
+config SERIAL_ETRAXFS_CONSOLE
+	bool "ETRAX FS serial console support"
+	depends on SERIAL_ETRAXFS
+	select SERIAL_CORE_CONSOLE
+
 config SERIAL_NETX
 	tristate "NetX serial port support"
 	depends on ARCH_NETX
@@ -1549,6 +1550,21 @@
 	  If you have enabled the lpuart serial port on the Freescale SoCs,
 	  you can make it the console by answering Y to this option.
 
+config SERIAL_CONEXANT_DIGICOLOR
+	tristate "Conexant Digicolor CX92xxx USART serial port support"
+	depends on OF
+	select SERIAL_CORE
+	help
+	  Support for the on-chip USART on Conexant Digicolor SoCs.
+
+config SERIAL_CONEXANT_DIGICOLOR_CONSOLE
+	bool "Console on Conexant Digicolor serial port"
+	depends on SERIAL_CONEXANT_DIGICOLOR=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  If you have enabled the USART serial port on Conexant Digicolor
+	  SoCs, you can make it the console by answering Y to this option.
+
 config SERIAL_ST_ASC
 	tristate "ST ASC serial port support"
 	select SERIAL_CORE
@@ -1577,6 +1593,24 @@
 	  This driver can also be build as a module. If so, the module will be called
 	  men_z135_uart.ko
 
+config SERIAL_SPRD
+	tristate "Support for Spreadtrum serial"
+	depends on ARCH_SPRD
+	select SERIAL_CORE
+	help
+	  This enables the driver for the Spreadtrum's serial.
+
+config SERIAL_SPRD_CONSOLE
+	bool "Spreadtrum UART console support"
+	depends on SERIAL_SPRD=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	help
+	  Support for early debug console using Spreadtrum's serial. This enables
+	  the console before standard serial driver is probed. This is enabled
+	  with "earlycon" on the kernel command line. The console is
+	  enabled when early_param is processed.
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 9a548ac..599be4b 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -51,6 +51,7 @@
 obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
 obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
 obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
 obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
@@ -77,7 +78,6 @@
 obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
 obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
 obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
-obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
 obj-$(CONFIG_SERIAL_PCH_UART)	+= pch_uart.o
@@ -92,7 +92,9 @@
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
+obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
+obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 192d043..0fefdd8 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -441,6 +441,7 @@
 	port->iotype = SERIAL_IO_MEM;
 	port->ops = &altera_jtaguart_ops;
 	port->flags = UPF_BOOT_AUTOCONF;
+	port->dev = &pdev->dev;
 
 	uart_add_one_port(&altera_jtaguart_driver, port);
 
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index eb15a50..b2859fe 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -589,6 +589,7 @@
 	port->iotype = SERIAL_IO_MEM;
 	port->ops = &altera_uart_ops;
 	port->flags = UPF_BOOT_AUTOCONF;
+	port->dev = &pdev->dev;
 
 	platform_set_drvdata(pdev, port);
 
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 4d848a2..846552b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -341,13 +341,37 @@
 static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 {
 	unsigned int control = 0;
-	unsigned int mode;
+	unsigned int mode = UART_GET_MR(port);
+	unsigned int rts_paused, rts_ready;
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+	/* override mode to RS485 if needed, otherwise keep the current mode */
+	if (port->rs485.flags & SER_RS485_ENABLED) {
+		if ((port->rs485.delay_rts_after_send) > 0)
+			UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+		mode &= ~ATMEL_US_USMODE;
+		mode |= ATMEL_US_USMODE_RS485;
+	}
+
+	/* set the RTS line state according to the mode */
+	if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+		/* force RTS line to high level */
+		rts_paused = ATMEL_US_RTSEN;
+
+		/* give the control of the RTS line back to the hardware */
+		rts_ready = ATMEL_US_RTSDIS;
+	} else {
+		/* force RTS line to high level */
+		rts_paused = ATMEL_US_RTSDIS;
+
+		/* force RTS line to low level */
+		rts_ready = ATMEL_US_RTSEN;
+	}
+
 	if (mctrl & TIOCM_RTS)
-		control |= ATMEL_US_RTSEN;
+		control |= rts_ready;
 	else
-		control |= ATMEL_US_RTSDIS;
+		control |= rts_paused;
 
 	if (mctrl & TIOCM_DTR)
 		control |= ATMEL_US_DTREN;
@@ -359,23 +383,12 @@
 	mctrl_gpio_set(atmel_port->gpios, mctrl);
 
 	/* Local loopback mode? */
-	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+	mode &= ~ATMEL_US_CHMODE;
 	if (mctrl & TIOCM_LOOP)
 		mode |= ATMEL_US_CHMODE_LOC_LOOP;
 	else
 		mode |= ATMEL_US_CHMODE_NORMAL;
 
-	/* Resetting serial mode to RS232 (0x0) */
-	mode &= ~ATMEL_US_USMODE;
-
-	if (port->rs485.flags & SER_RS485_ENABLED) {
-		dev_dbg(port->dev, "Setting UART to RS485\n");
-		if ((port->rs485.delay_rts_after_send) > 0)
-			UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
-		mode |= ATMEL_US_USMODE_RS485;
-	} else {
-		dev_dbg(port->dev, "Setting UART to RS232\n");
-	}
 	UART_PUT_MR(port, mode);
 }
 
@@ -725,7 +738,11 @@
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
 
-	/* Do we really need this? */
+	/*
+	 * xmit is a circular buffer so, if we have just send data from
+	 * xmit->tail to the end of xmit->buf, now we have to transmit the
+	 * remaining data from the beginning of xmit->buf to xmit->head.
+	 */
 	if (!uart_circ_empty(xmit))
 		tasklet_schedule(&atmel_port->tasklet);
 
@@ -784,17 +801,17 @@
 		BUG_ON(!sg_dma_len(sg));
 
 		desc = dmaengine_prep_slave_sg(chan,
-						sg,
-						1,
-						DMA_MEM_TO_DEV,
-						DMA_PREP_INTERRUPT |
-						DMA_CTRL_ACK);
+					       sg,
+					       1,
+					       DMA_MEM_TO_DEV,
+					       DMA_PREP_INTERRUPT |
+					       DMA_CTRL_ACK);
 		if (!desc) {
 			dev_err(port->dev, "Failed to send via dma!\n");
 			return;
 		}
 
-		dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+		dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
 
 		atmel_port->desc_tx = desc;
 		desc->callback = atmel_complete_tx_dma;
@@ -927,7 +944,7 @@
 	dma_sync_sg_for_cpu(port->dev,
 			    &atmel_port->sg_rx,
 			    1,
-			    DMA_DEV_TO_MEM);
+			    DMA_FROM_DEVICE);
 
 	/*
 	 * ring->head points to the end of data already written by the DMA.
@@ -974,7 +991,7 @@
 	dma_sync_sg_for_device(port->dev,
 			       &atmel_port->sg_rx,
 			       1,
-			       DMA_DEV_TO_MEM);
+			       DMA_FROM_DEVICE);
 
 	/*
 	 * Drop the lock here since it might end up calling
@@ -1012,13 +1029,13 @@
 	/* UART circular rx buffer is an aligned page. */
 	BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
 	sg_set_page(&atmel_port->sg_rx,
-			virt_to_page(ring->buf),
-			ATMEL_SERIAL_RINGSIZE,
-			(int)ring->buf & ~PAGE_MASK);
-			nent = dma_map_sg(port->dev,
-					&atmel_port->sg_rx,
-					1,
-					DMA_FROM_DEVICE);
+		    virt_to_page(ring->buf),
+		    ATMEL_SERIAL_RINGSIZE,
+		    (int)ring->buf & ~PAGE_MASK);
+	nent = dma_map_sg(port->dev,
+			  &atmel_port->sg_rx,
+			  1,
+			  DMA_FROM_DEVICE);
 
 	if (!nent) {
 		dev_dbg(port->dev, "need to release resource of dma\n");
@@ -1047,11 +1064,11 @@
 	 * each one is half ring buffer size
 	 */
 	desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
-				sg_dma_address(&atmel_port->sg_rx),
-				sg_dma_len(&atmel_port->sg_rx),
-				sg_dma_len(&atmel_port->sg_rx)/2,
-				DMA_DEV_TO_MEM,
-				DMA_PREP_INTERRUPT);
+					 sg_dma_address(&atmel_port->sg_rx),
+					 sg_dma_len(&atmel_port->sg_rx),
+					 sg_dma_len(&atmel_port->sg_rx)/2,
+					 DMA_DEV_TO_MEM,
+					 DMA_PREP_INTERRUPT);
 	desc->callback = atmel_complete_rx_dma;
 	desc->callback_param = port;
 	atmel_port->desc_rx = desc;
@@ -1921,12 +1938,14 @@
 			      struct ktermios *old)
 {
 	unsigned long flags;
-	unsigned int mode, imr, quot, baud;
+	unsigned int old_mode, mode, imr, quot, baud;
 
-	/* Get current mode register */
-	mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
-					| ATMEL_US_NBSTOP | ATMEL_US_PAR
-					| ATMEL_US_USMODE);
+	/* save the current mode register */
+	mode = old_mode = UART_GET_MR(port);
+
+	/* reset the mode, clock divisor, parity, stop bits and data size */
+	mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
+		  ATMEL_US_PAR | ATMEL_US_USMODE);
 
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
 	quot = uart_get_divisor(port, baud);
@@ -1971,12 +1990,6 @@
 	} else
 		mode |= ATMEL_US_PAR_NONE;
 
-	/* hardware handshake (RTS/CTS) */
-	if (termios->c_cflag & CRTSCTS)
-		mode |= ATMEL_US_USMODE_HWHS;
-	else
-		mode |= ATMEL_US_USMODE_NORMAL;
-
 	spin_lock_irqsave(&port->lock, flags);
 
 	port->read_status_mask = ATMEL_US_OVRE;
@@ -2020,18 +2033,40 @@
 	/* disable receiver and transmitter */
 	UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
 
-	/* Resetting serial mode to RS232 (0x0) */
-	mode &= ~ATMEL_US_USMODE;
-
+	/* mode */
 	if (port->rs485.flags & SER_RS485_ENABLED) {
 		if ((port->rs485.delay_rts_after_send) > 0)
 			UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
 		mode |= ATMEL_US_USMODE_RS485;
+	} else if (termios->c_cflag & CRTSCTS) {
+		/* RS232 with hardware handshake (RTS/CTS) */
+		mode |= ATMEL_US_USMODE_HWHS;
+	} else {
+		/* RS232 without hadware handshake */
+		mode |= ATMEL_US_USMODE_NORMAL;
 	}
 
-	/* set the parity, stop bits and data size */
+	/* set the mode, clock divisor, parity, stop bits and data size */
 	UART_PUT_MR(port, mode);
 
+	/*
+	 * when switching the mode, set the RTS line state according to the
+	 * new mode, otherwise keep the former state
+	 */
+	if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
+		unsigned int rts_state;
+
+		if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+			/* let the hardware control the RTS line */
+			rts_state = ATMEL_US_RTSDIS;
+		} else {
+			/* force RTS line to low level */
+			rts_state = ATMEL_US_RTSEN;
+		}
+
+		UART_PUT_CR(port, rts_state);
+	}
+
 	/* set the baud rate */
 	UART_PUT_BRGR(port, quot);
 	UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
@@ -2565,7 +2600,7 @@
 
 	ret = atmel_init_port(port, pdev);
 	if (ret)
-		goto err;
+		goto err_clear_bit;
 
 	if (!atmel_use_pdc_rx(&port->uart)) {
 		ret = -ENOMEM;
@@ -2596,6 +2631,12 @@
 	device_init_wakeup(&pdev->dev, 1);
 	platform_set_drvdata(pdev, port);
 
+	/*
+	 * The peripheral clock has been disabled by atmel_init_port():
+	 * enable it before accessing I/O registers
+	 */
+	clk_prepare_enable(port->clk);
+
 	if (rs485_enabled) {
 		UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
 		UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
@@ -2606,6 +2647,12 @@
 	 */
 	atmel_get_ip_name(&port->uart);
 
+	/*
+	 * The peripheral clock can now safely be disabled till the port
+	 * is used
+	 */
+	clk_disable_unprepare(port->clk);
+
 	return 0;
 
 err_add_port:
@@ -2616,6 +2663,8 @@
 		clk_put(port->clk);
 		port->clk = NULL;
 	}
+err_clear_bit:
+	clear_bit(port->uart.line, atmel_ports_in_use);
 err:
 	return ret;
 }
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
new file mode 100644
index 0000000..a80cdad
--- /dev/null
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -0,0 +1,560 @@
+/*
+ *  Driver for Conexant Digicolor serial ports (USART)
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define UA_ENABLE			0x00
+#define UA_ENABLE_ENABLE		BIT(0)
+
+#define UA_CONTROL			0x01
+#define UA_CONTROL_RX_ENABLE		BIT(0)
+#define UA_CONTROL_TX_ENABLE		BIT(1)
+#define UA_CONTROL_SOFT_RESET		BIT(2)
+
+#define UA_STATUS			0x02
+#define UA_STATUS_PARITY_ERR		BIT(0)
+#define UA_STATUS_FRAME_ERR		BIT(1)
+#define UA_STATUS_OVERRUN_ERR		BIT(2)
+#define UA_STATUS_TX_READY		BIT(6)
+
+#define UA_CONFIG			0x03
+#define UA_CONFIG_CHAR_LEN		BIT(0)
+#define UA_CONFIG_STOP_BITS		BIT(1)
+#define UA_CONFIG_PARITY		BIT(2)
+#define UA_CONFIG_ODD_PARITY		BIT(4)
+
+#define UA_EMI_REC			0x04
+
+#define UA_HBAUD_LO			0x08
+#define UA_HBAUD_HI			0x09
+
+#define UA_STATUS_FIFO			0x0a
+#define UA_STATUS_FIFO_RX_EMPTY		BIT(2)
+#define UA_STATUS_FIFO_RX_INT_ALMOST	BIT(3)
+#define UA_STATUS_FIFO_TX_FULL		BIT(4)
+#define UA_STATUS_FIFO_TX_INT_ALMOST	BIT(7)
+
+#define UA_CONFIG_FIFO			0x0b
+#define UA_CONFIG_FIFO_RX_THRESH	7
+#define UA_CONFIG_FIFO_RX_FIFO_MODE	BIT(3)
+#define UA_CONFIG_FIFO_TX_FIFO_MODE	BIT(7)
+
+#define UA_INTFLAG_CLEAR		0x1c
+#define UA_INTFLAG_SET			0x1d
+#define UA_INT_ENABLE			0x1e
+#define UA_INT_STATUS			0x1f
+
+#define UA_INT_TX			BIT(0)
+#define UA_INT_RX			BIT(1)
+
+#define DIGICOLOR_USART_NR		3
+
+/*
+ * We use the 16 bytes hardware FIFO to buffer Rx traffic. Rx interrupt is
+ * only produced when the FIFO is filled more than a certain configurable
+ * threshold. Unfortunately, there is no way to set this threshold below half
+ * FIFO. This means that we must periodically poll the FIFO status register to
+ * see whether there are waiting Rx bytes.
+ */
+
+struct digicolor_port {
+	struct uart_port port;
+	struct delayed_work rx_poll_work;
+};
+
+static struct uart_port *digicolor_ports[DIGICOLOR_USART_NR];
+
+static bool digicolor_uart_tx_full(struct uart_port *port)
+{
+	return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+		  UA_STATUS_FIFO_TX_FULL);
+}
+
+static bool digicolor_uart_rx_empty(struct uart_port *port)
+{
+	return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+		  UA_STATUS_FIFO_RX_EMPTY);
+}
+
+static void digicolor_uart_stop_tx(struct uart_port *port)
+{
+	u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+	int_enable &= ~UA_INT_TX;
+	writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_start_tx(struct uart_port *port)
+{
+	u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+	int_enable |= UA_INT_TX;
+	writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_stop_rx(struct uart_port *port)
+{
+	u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+	int_enable &= ~UA_INT_RX;
+	writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_rx_poll(struct work_struct *work)
+{
+	struct digicolor_port *dp =
+		container_of(to_delayed_work(work),
+			     struct digicolor_port, rx_poll_work);
+
+	if (!digicolor_uart_rx_empty(&dp->port))
+		/* force RX interrupt */
+		writeb_relaxed(UA_INT_RX, dp->port.membase + UA_INTFLAG_SET);
+
+	schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+}
+
+static void digicolor_uart_rx(struct uart_port *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	while (1) {
+		u8 status, ch;
+		unsigned int ch_flag;
+
+		if (digicolor_uart_rx_empty(port))
+			break;
+
+		ch = readb_relaxed(port->membase + UA_EMI_REC);
+		status = readb_relaxed(port->membase + UA_STATUS);
+
+		port->icount.rx++;
+		ch_flag = TTY_NORMAL;
+
+		if (status) {
+			if (status & UA_STATUS_PARITY_ERR)
+				port->icount.parity++;
+			else if (status & UA_STATUS_FRAME_ERR)
+				port->icount.frame++;
+			else if (status & UA_STATUS_OVERRUN_ERR)
+				port->icount.overrun++;
+
+			status &= port->read_status_mask;
+
+			if (status & UA_STATUS_PARITY_ERR)
+				ch_flag = TTY_PARITY;
+			else if (status & UA_STATUS_FRAME_ERR)
+				ch_flag = TTY_FRAME;
+			else if (status & UA_STATUS_OVERRUN_ERR)
+				ch_flag = TTY_OVERRUN;
+		}
+
+		if (status & port->ignore_status_mask)
+			continue;
+
+		uart_insert_char(port, status, UA_STATUS_OVERRUN_ERR, ch,
+				 ch_flag);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	tty_flip_buffer_push(&port->state->port);
+}
+
+static void digicolor_uart_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long flags;
+
+	if (digicolor_uart_tx_full(port))
+		return;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (port->x_char) {
+		writeb_relaxed(port->x_char, port->membase + UA_EMI_REC);
+		port->icount.tx++;
+		port->x_char = 0;
+		goto out;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		digicolor_uart_stop_tx(port);
+		goto out;
+	}
+
+	while (!uart_circ_empty(xmit)) {
+		writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+
+		if (digicolor_uart_tx_full(port))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+out:
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static irqreturn_t digicolor_uart_int(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	u8 int_status = readb_relaxed(port->membase + UA_INT_STATUS);
+
+	writeb_relaxed(UA_INT_RX | UA_INT_TX,
+		       port->membase + UA_INTFLAG_CLEAR);
+
+	if (int_status & UA_INT_RX)
+		digicolor_uart_rx(port);
+	if (int_status & UA_INT_TX)
+		digicolor_uart_tx(port);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int digicolor_uart_tx_empty(struct uart_port *port)
+{
+	u8 status = readb_relaxed(port->membase + UA_STATUS);
+
+	return (status & UA_STATUS_TX_READY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int digicolor_uart_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CTS;
+}
+
+static void digicolor_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void digicolor_uart_break_ctl(struct uart_port *port, int state)
+{
+}
+
+static int digicolor_uart_startup(struct uart_port *port)
+{
+	struct digicolor_port *dp =
+		container_of(port, struct digicolor_port, port);
+
+	writeb_relaxed(UA_ENABLE_ENABLE, port->membase + UA_ENABLE);
+	writeb_relaxed(UA_CONTROL_SOFT_RESET, port->membase + UA_CONTROL);
+	writeb_relaxed(0, port->membase + UA_CONTROL);
+
+	writeb_relaxed(UA_CONFIG_FIFO_RX_FIFO_MODE
+		       | UA_CONFIG_FIFO_TX_FIFO_MODE | UA_CONFIG_FIFO_RX_THRESH,
+		       port->membase + UA_CONFIG_FIFO);
+	writeb_relaxed(UA_STATUS_FIFO_RX_INT_ALMOST,
+		       port->membase + UA_STATUS_FIFO);
+	writeb_relaxed(UA_CONTROL_RX_ENABLE | UA_CONTROL_TX_ENABLE,
+		       port->membase + UA_CONTROL);
+	writeb_relaxed(UA_INT_TX | UA_INT_RX,
+		       port->membase + UA_INT_ENABLE);
+
+	schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+
+	return 0;
+}
+
+static void digicolor_uart_shutdown(struct uart_port *port)
+{
+	struct digicolor_port *dp =
+		container_of(port, struct digicolor_port, port);
+
+	writeb_relaxed(0, port->membase + UA_ENABLE);
+	cancel_delayed_work_sync(&dp->rx_poll_work);
+}
+
+static void digicolor_uart_set_termios(struct uart_port *port,
+				       struct ktermios *termios,
+				       struct ktermios *old)
+{
+	unsigned int baud, divisor;
+	u8 config = 0;
+	unsigned long flags;
+
+	/* Mask termios capabilities we don't support */
+	termios->c_cflag &= ~CMSPAR;
+	termios->c_iflag &= ~(BRKINT | IGNBRK);
+
+	/* Limit baud rates so that we don't need the fractional divider */
+	baud = uart_get_baud_rate(port, termios, old,
+				  port->uartclk / (0x10000*16),
+				  port->uartclk / 256);
+	divisor = uart_get_divisor(port, baud) - 1;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS7:
+		break;
+	case CS8:
+	default:
+		config |= UA_CONFIG_CHAR_LEN;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		config |= UA_CONFIG_STOP_BITS;
+
+	if (termios->c_cflag & PARENB) {
+		config |= UA_CONFIG_PARITY;
+		if (termios->c_cflag & PARODD)
+			config |= UA_CONFIG_ODD_PARITY;
+	}
+
+	/* Set read status mask */
+	port->read_status_mask = UA_STATUS_OVERRUN_ERR;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= UA_STATUS_PARITY_ERR
+			| UA_STATUS_FRAME_ERR;
+
+	/* Set status ignore mask */
+	port->ignore_status_mask = 0;
+	if (!(termios->c_cflag & CREAD))
+		port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR
+			| UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	writeb_relaxed(config, port->membase + UA_CONFIG);
+	writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO);
+	writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *digicolor_uart_type(struct uart_port *port)
+{
+	return (port->type == PORT_DIGICOLOR) ? "DIGICOLOR USART" : NULL;
+}
+
+static void digicolor_uart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_DIGICOLOR;
+}
+
+static void digicolor_uart_release_port(struct uart_port *port)
+{
+}
+
+static int digicolor_uart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static const struct uart_ops digicolor_uart_ops = {
+	.tx_empty	= digicolor_uart_tx_empty,
+	.set_mctrl	= digicolor_uart_set_mctrl,
+	.get_mctrl	= digicolor_uart_get_mctrl,
+	.stop_tx	= digicolor_uart_stop_tx,
+	.start_tx	= digicolor_uart_start_tx,
+	.stop_rx	= digicolor_uart_stop_rx,
+	.break_ctl	= digicolor_uart_break_ctl,
+	.startup	= digicolor_uart_startup,
+	.shutdown	= digicolor_uart_shutdown,
+	.set_termios	= digicolor_uart_set_termios,
+	.type		= digicolor_uart_type,
+	.config_port	= digicolor_uart_config_port,
+	.release_port	= digicolor_uart_release_port,
+	.request_port	= digicolor_uart_request_port,
+};
+
+static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
+{
+	while (digicolor_uart_tx_full(port))
+		cpu_relax();
+
+	writeb_relaxed(ch, port->membase + UA_EMI_REC);
+}
+
+static void digicolor_uart_console_write(struct console *co, const char *c,
+					 unsigned n)
+{
+	struct uart_port *port = digicolor_ports[co->index];
+	u8 status;
+	unsigned long flags;
+	int locked = 1;
+
+	if (oops_in_progress)
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	else
+		spin_lock_irqsave(&port->lock, flags);
+
+	uart_console_write(port, c, n, digicolor_uart_console_putchar);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Wait for transmitter to become empty */
+	do {
+		status = readb_relaxed(port->membase + UA_STATUS);
+	} while ((status & UA_STATUS_TX_READY) == 0);
+}
+
+static int digicolor_uart_console_setup(struct console *co, char *options)
+{
+	int baud = 115200, bits = 8, parity = 'n', flow = 'n';
+	struct uart_port *port;
+
+	if (co->index < 0 || co->index >= DIGICOLOR_USART_NR)
+		return -EINVAL;
+
+	port = digicolor_ports[co->index];
+	if (!port)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console digicolor_console = {
+	.name	= "ttyS",
+	.device	= uart_console_device,
+	.write	= digicolor_uart_console_write,
+	.setup	= digicolor_uart_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+};
+
+static struct uart_driver digicolor_uart = {
+	.driver_name	= "digicolor-usart",
+	.dev_name	= "ttyS",
+	.nr		= DIGICOLOR_USART_NR,
+};
+
+static int digicolor_uart_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret, index;
+	struct digicolor_port *dp;
+	struct resource *res;
+	struct clk *uart_clk;
+
+	if (!np) {
+		dev_err(&pdev->dev, "Missing device tree node\n");
+		return -ENXIO;
+	}
+
+	index = of_alias_get_id(np, "serial");
+	if (index < 0 || index >= DIGICOLOR_USART_NR)
+		return -EINVAL;
+
+	dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+
+	uart_clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(uart_clk))
+		return PTR_ERR(uart_clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dp->port.mapbase = res->start;
+	dp->port.membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dp->port.membase))
+		return PTR_ERR(dp->port.membase);
+
+	dp->port.irq = platform_get_irq(pdev, 0);
+	if (IS_ERR_VALUE(dp->port.irq))
+		return dp->port.irq;
+
+	dp->port.iotype = UPIO_MEM;
+	dp->port.uartclk = clk_get_rate(uart_clk);
+	dp->port.fifosize = 16;
+	dp->port.dev = &pdev->dev;
+	dp->port.ops = &digicolor_uart_ops;
+	dp->port.line = index;
+	dp->port.type = PORT_DIGICOLOR;
+	spin_lock_init(&dp->port.lock);
+
+	digicolor_ports[index] = &dp->port;
+	platform_set_drvdata(pdev, &dp->port);
+
+	INIT_DELAYED_WORK(&dp->rx_poll_work, digicolor_rx_poll);
+
+	ret = devm_request_irq(&pdev->dev, dp->port.irq, digicolor_uart_int, 0,
+			       dev_name(&pdev->dev), &dp->port);
+	if (ret)
+		return ret;
+
+	return uart_add_one_port(&digicolor_uart, &dp->port);
+}
+
+static int digicolor_uart_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&digicolor_uart, port);
+
+	return 0;
+}
+
+static const struct of_device_id digicolor_uart_dt_ids[] = {
+	{ .compatible = "cnxt,cx92755-usart", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, digicolor_uart_dt_ids);
+
+static struct platform_driver digicolor_uart_platform = {
+	.driver = {
+		.name		= "digicolor-usart",
+		.of_match_table	= of_match_ptr(digicolor_uart_dt_ids),
+	},
+	.probe	= digicolor_uart_probe,
+	.remove	= digicolor_uart_remove,
+};
+
+static int __init digicolor_uart_init(void)
+{
+	int ret;
+
+	if (IS_ENABLED(CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE)) {
+		digicolor_uart.cons = &digicolor_console;
+		digicolor_console.data = &digicolor_uart;
+	}
+
+	ret = uart_register_driver(&digicolor_uart);
+	if (ret)
+		return ret;
+
+	return platform_driver_register(&digicolor_uart_platform);
+}
+module_init(digicolor_uart_init);
+
+static void __exit digicolor_uart_exit(void)
+{
+	platform_driver_unregister(&digicolor_uart_platform);
+	uart_unregister_driver(&digicolor_uart);
+}
+module_exit(digicolor_uart_exit);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor USART serial driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c
new file mode 100644
index 0000000..a57301a
--- /dev/null
+++ b/drivers/tty/serial/etraxfs-uart.c
@@ -0,0 +1,996 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <hwregs/ser_defs.h>
+
+#define DRV_NAME "etraxfs-uart"
+#define UART_NR CONFIG_ETRAX_SERIAL_PORTS
+
+#define MODIFY_REG(instance, reg, var)				\
+	do {							\
+		if (REG_RD_INT(ser, instance, reg) !=		\
+		    REG_TYPE_CONV(int, reg_ser_##reg, var))	\
+			REG_WR(ser, instance, reg, var);	\
+	} while (0)
+
+struct uart_cris_port {
+	struct uart_port port;
+
+	int initialized;
+	int irq;
+
+	void __iomem *regi_ser;
+
+	struct gpio_desc *dtr_pin;
+	struct gpio_desc *dsr_pin;
+	struct gpio_desc *ri_pin;
+	struct gpio_desc *cd_pin;
+
+	int write_ongoing;
+};
+
+static struct uart_driver etraxfs_uart_driver;
+static struct uart_port *console_port;
+static int console_baud = 115200;
+static struct uart_cris_port *etraxfs_uart_ports[UART_NR];
+
+static void cris_serial_port_init(struct uart_port *port, int line);
+static void etraxfs_uart_stop_rx(struct uart_port *port);
+static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port);
+
+#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
+static void
+cris_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_cris_port *up;
+	int i;
+	reg_ser_r_stat_din stat;
+	reg_ser_rw_tr_dma_en tr_dma_en, old;
+
+	up = etraxfs_uart_ports[co->index];
+
+	if (!up)
+		return;
+
+	/* Switch to manual mode. */
+	tr_dma_en = old = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
+	if (tr_dma_en.en == regk_ser_yes) {
+		tr_dma_en.en = regk_ser_no;
+		REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
+	}
+
+	/* Send data. */
+	for (i = 0; i < count; i++) {
+		/* LF -> CRLF */
+		if (s[i] == '\n') {
+			do {
+				stat = REG_RD(ser, up->regi_ser, r_stat_din);
+			} while (!stat.tr_rdy);
+			REG_WR_INT(ser, up->regi_ser, rw_dout, '\r');
+		}
+		/* Wait until transmitter is ready and send. */
+		do {
+			stat = REG_RD(ser, up->regi_ser, r_stat_din);
+		} while (!stat.tr_rdy);
+		REG_WR_INT(ser, up->regi_ser, rw_dout, s[i]);
+	}
+
+	/* Restore mode. */
+	if (tr_dma_en.en != old.en)
+		REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
+}
+
+static int __init
+cris_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= UART_NR)
+		co->index = 0;
+	port = &etraxfs_uart_ports[co->index]->port;
+	console_port = port;
+
+	co->flags |= CON_CONSDEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	console_baud = baud;
+	cris_serial_port_init(port, co->index);
+	uart_set_options(port, co, baud, parity, bits, flow);
+
+	return 0;
+}
+
+static struct tty_driver *cris_console_device(struct console *co, int *index)
+{
+	struct uart_driver *p = co->data;
+	*index = co->index;
+	return p->tty_driver;
+}
+
+static struct console cris_console = {
+	.name = "ttyS",
+	.write = cris_console_write,
+	.device = cris_console_device,
+	.setup = cris_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &etraxfs_uart_driver,
+};
+#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
+
+static struct uart_driver etraxfs_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "serial",
+	.dev_name = "ttyS",
+	.major = TTY_MAJOR,
+	.minor = 64,
+	.nr = UART_NR,
+#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
+	.cons = &cris_console,
+#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
+};
+
+static inline int crisv32_serial_get_rts(struct uart_cris_port *up)
+{
+	void __iomem *regi_ser = up->regi_ser;
+	/*
+	 * Return what the user has controlled rts to or
+	 * what the pin is? (if auto_rts is used it differs during tx)
+	 */
+	reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
+
+	return !(rstat.rts_n == regk_ser_active);
+}
+
+/*
+ * A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ *                                            0=0V    , 1=3.3V
+ */
+static inline void crisv32_serial_set_rts(struct uart_cris_port *up,
+					  int set, int force)
+{
+	void __iomem *regi_ser = up->regi_ser;
+
+	unsigned long flags;
+	reg_ser_rw_rec_ctrl rec_ctrl;
+
+	local_irq_save(flags);
+	rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
+
+	if (set)
+		rec_ctrl.rts_n = regk_ser_active;
+	else
+		rec_ctrl.rts_n = regk_ser_inactive;
+	REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
+	local_irq_restore(flags);
+}
+
+static inline int crisv32_serial_get_cts(struct uart_cris_port *up)
+{
+	void __iomem *regi_ser = up->regi_ser;
+	reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
+
+	return (rstat.cts_n == regk_ser_active);
+}
+
+/*
+ * Send a single character for XON/XOFF purposes.  We do it in this separate
+ * function instead of the alternative support port.x_char, in the ...start_tx
+ * function, so we don't mix up this case with possibly enabling transmission
+ * of queued-up data (in case that's disabled after *receiving* an XOFF or
+ * negative CTS).  This function is used for both DMA and non-DMA case; see HW
+ * docs specifically blessing sending characters manually when DMA for
+ * transmission is enabled and running.  We may be asked to transmit despite
+ * the transmitter being disabled by a ..._stop_tx call so we need to enable
+ * it temporarily but restore the state afterwards.
+ */
+static void etraxfs_uart_send_xchar(struct uart_port *port, char ch)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	reg_ser_rw_dout dout = { .data = ch };
+	reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
+	reg_ser_r_stat_din rstat;
+	reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
+	void __iomem *regi_ser = up->regi_ser;
+	unsigned long flags;
+
+	/*
+	 * Wait for tr_rdy in case a character is already being output.  Make
+	 * sure we have integrity between the register reads and the writes
+	 * below, but don't busy-wait with interrupts off and the port lock
+	 * taken.
+	 */
+	spin_lock_irqsave(&port->lock, flags);
+	do {
+		spin_unlock_irqrestore(&port->lock, flags);
+		spin_lock_irqsave(&port->lock, flags);
+		prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+		rstat = REG_RD(ser, regi_ser, r_stat_din);
+	} while (!rstat.tr_rdy);
+
+	/*
+	 * Ack an interrupt if one was just issued for the previous character
+	 * that was output.  This is required for non-DMA as the interrupt is
+	 * used as the only indicator that the transmitter is ready and it
+	 * isn't while this x_char is being transmitted.
+	 */
+	REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
+
+	/* Enable the transmitter in case it was disabled. */
+	tr_ctrl.stop = 0;
+	REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+
+	/*
+	 * Finally, send the blessed character; nothing should stop it now,
+	 * except for an xoff-detected state, which we'll handle below.
+	 */
+	REG_WR(ser, regi_ser, rw_dout, dout);
+	up->port.icount.tx++;
+
+	/* There might be an xoff state to clear. */
+	rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+
+	/*
+	 * Clear any xoff state that *may* have been there to
+	 * inhibit transmission of the character.
+	 */
+	if (rstat.xoff_detect) {
+		reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
+		reg_ser_rw_tr_dma_en tr_dma_en;
+
+		REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
+		tr_dma_en = REG_RD(ser, regi_ser, rw_tr_dma_en);
+
+		/*
+		 * If we had an xoff state but cleared it, instead sneak in a
+		 * disabled state for the transmitter, after the character we
+		 * sent.  Thus we keep the port disabled, just as if the xoff
+		 * state was still in effect (or actually, as if stop_tx had
+		 * been called, as we stop DMA too).
+		 */
+		prev_tr_ctrl.stop = 1;
+
+		tr_dma_en.en = 0;
+		REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
+	}
+
+	/* Restore "previous" enabled/disabled state of the transmitter. */
+	REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Do not spin_lock_irqsave or disable interrupts by other means here; it's
+ * already done by the caller.
+ */
+static void etraxfs_uart_start_tx(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	/* we have already done below if a write is ongoing */
+	if (up->write_ongoing)
+		return;
+
+	/* Signal that write is ongoing */
+	up->write_ongoing = 1;
+
+	etraxfs_uart_start_tx_bottom(port);
+}
+
+static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	void __iomem *regi_ser = up->regi_ser;
+	reg_ser_rw_tr_ctrl tr_ctrl;
+	reg_ser_rw_intr_mask intr_mask;
+
+	tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+	tr_ctrl.stop = regk_ser_no;
+	REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+	intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+	intr_mask.tr_rdy = regk_ser_yes;
+	REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+}
+
+/*
+ * This function handles both the DMA and non-DMA case by ordering the
+ * transmitter to stop of after the current character.  We don't need to wait
+ * for any such character to be completely transmitted; we do that where it
+ * matters, like in etraxfs_uart_set_termios.  Don't busy-wait here; see
+ * Documentation/serial/driver: this function is called within
+ * spin_lock_irq{,save} and thus separate ones would be disastrous (when SMP).
+ * There's no documented need to set the txd pin to any particular value;
+ * break setting is controlled solely by etraxfs_uart_break_ctl.
+ */
+static void etraxfs_uart_stop_tx(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	void __iomem *regi_ser = up->regi_ser;
+	reg_ser_rw_tr_ctrl tr_ctrl;
+	reg_ser_rw_intr_mask intr_mask;
+	reg_ser_rw_tr_dma_en tr_dma_en = {0};
+	reg_ser_rw_xoff_clr xoff_clr = {0};
+
+	/*
+	 * For the non-DMA case, we'd get a tr_rdy interrupt that we're not
+	 * interested in as we're not transmitting any characters.  For the
+	 * DMA case, that interrupt is already turned off, but no reason to
+	 * waste code on conditionals here.
+	 */
+	intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+	intr_mask.tr_rdy = regk_ser_no;
+	REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+
+	tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+	tr_ctrl.stop = 1;
+	REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+
+	/*
+	 * Always clear possible hardware xoff-detected state here, no need to
+	 * unnecessary consider mctrl settings and when they change.  We clear
+	 * it here rather than in start_tx: both functions are called as the
+	 * effect of XOFF processing, but start_tx is also called when upper
+	 * levels tell the driver that there are more characters to send, so
+	 * avoid adding code there.
+	 */
+	xoff_clr.clr = 1;
+	REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
+
+	/*
+	 * Disable transmitter DMA, so that if we're in XON/XOFF, we can send
+	 * those single characters without also giving go-ahead for queued up
+	 * DMA data.
+	 */
+	tr_dma_en.en = 0;
+	REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
+
+	/*
+	 * Make sure that write_ongoing is reset when stopping tx.
+	 */
+	up->write_ongoing = 0;
+}
+
+static void etraxfs_uart_stop_rx(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	void __iomem *regi_ser = up->regi_ser;
+	reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
+
+	rec_ctrl.en = regk_ser_no;
+	REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
+}
+
+static void etraxfs_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void check_modem_status(struct uart_cris_port *up)
+{
+}
+
+static unsigned int etraxfs_uart_tx_empty(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned long flags;
+	unsigned int ret;
+	reg_ser_r_stat_din rstat = {0};
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+	ret = rstat.tr_empty ? TIOCSER_TEMT : 0;
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+	return ret;
+}
+static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned int ret;
+
+	ret = 0;
+	if (crisv32_serial_get_rts(up))
+		ret |= TIOCM_RTS;
+	/* DTR is active low */
+	if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin))
+		ret |= TIOCM_DTR;
+	/* CD is active low */
+	if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin))
+		ret |= TIOCM_CD;
+	/* RI is active low */
+	if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin))
+		ret |= TIOCM_RI;
+	/* DSR is active low */
+	if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin))
+		ret |= TIOCM_DSR;
+	if (crisv32_serial_get_cts(up))
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0);
+	/* DTR is active low */
+	if (up->dtr_pin)
+		gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1);
+	/* RI is active low */
+	if (up->ri_pin)
+		gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1);
+	/* CD is active low */
+	if (up->cd_pin)
+		gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1);
+}
+
+static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned long flags;
+	reg_ser_rw_tr_ctrl tr_ctrl;
+	reg_ser_rw_tr_dma_en tr_dma_en;
+	reg_ser_rw_intr_mask intr_mask;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	tr_ctrl = REG_RD(ser, up->regi_ser, rw_tr_ctrl);
+	tr_dma_en = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
+	intr_mask = REG_RD(ser, up->regi_ser, rw_intr_mask);
+
+	if (break_state != 0) { /* Send break */
+		/*
+		 * We need to disable DMA (if used) or tr_rdy interrupts if no
+		 * DMA.  No need to make this conditional on use of DMA;
+		 * disabling will be a no-op for the other mode.
+		 */
+		intr_mask.tr_rdy = regk_ser_no;
+		tr_dma_en.en = 0;
+
+		/*
+		 * Stop transmission and set the txd pin to 0 after the
+		 * current character.  The txd setting will take effect after
+		 * any current transmission has completed.
+		 */
+		tr_ctrl.stop = 1;
+		tr_ctrl.txd = 0;
+	} else {
+		/* Re-enable the serial interrupt. */
+		intr_mask.tr_rdy = regk_ser_yes;
+
+		tr_ctrl.stop = 0;
+		tr_ctrl.txd = 1;
+	}
+	REG_WR(ser, up->regi_ser, rw_tr_ctrl, tr_ctrl);
+	REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
+	REG_WR(ser, up->regi_ser, rw_intr_mask, intr_mask);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+transmit_chars_no_dma(struct uart_cris_port *up)
+{
+	int max_count;
+	struct circ_buf *xmit = &up->port.state->xmit;
+
+	void __iomem *regi_ser = up->regi_ser;
+	reg_ser_r_stat_din rstat;
+	reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+		/* No more to send, so disable the interrupt. */
+		reg_ser_rw_intr_mask intr_mask;
+
+		intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+		intr_mask.tr_rdy = 0;
+		intr_mask.tr_empty = 0;
+		REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+		up->write_ongoing = 0;
+		return;
+	}
+
+	/* If the serport is fast, we send up to max_count bytes before
+	   exiting the loop.  */
+	max_count = 64;
+	do {
+		reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] };
+
+		REG_WR(ser, regi_ser, rw_dout, dout);
+		REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+		up->port.icount.tx++;
+		if (xmit->head == xmit->tail)
+			break;
+		rstat = REG_RD(ser, regi_ser, r_stat_din);
+	} while ((--max_count > 0) && rstat.tr_rdy);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&up->port);
+}
+
+static void receive_chars_no_dma(struct uart_cris_port *up)
+{
+	reg_ser_rs_stat_din stat_din;
+	reg_ser_r_stat_din rstat;
+	struct tty_port *port;
+	struct uart_icount *icount;
+	int max_count = 16;
+	char flag;
+	reg_ser_rw_ack_intr ack_intr = { 0 };
+
+	rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+	icount = &up->port.icount;
+	port = &up->port.state->port;
+
+	do {
+		stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
+
+		flag = TTY_NORMAL;
+		ack_intr.dav = 1;
+		REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
+		icount->rx++;
+
+		if (stat_din.framing_err | stat_din.par_err | stat_din.orun) {
+			if (stat_din.data == 0x00 &&
+			    stat_din.framing_err) {
+				/* Most likely a break. */
+				flag = TTY_BREAK;
+				icount->brk++;
+			} else if (stat_din.par_err) {
+				flag = TTY_PARITY;
+				icount->parity++;
+			} else if (stat_din.orun) {
+				flag = TTY_OVERRUN;
+				icount->overrun++;
+			} else if (stat_din.framing_err) {
+				flag = TTY_FRAME;
+				icount->frame++;
+			}
+		}
+
+		/*
+		 * If this becomes important, we probably *could* handle this
+		 * gracefully by keeping track of the unhandled character.
+		 */
+		if (!tty_insert_flip_char(port, stat_din.data, flag))
+			panic("%s: No tty buffer space", __func__);
+		rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+	} while (rstat.dav && (max_count-- > 0));
+	spin_unlock(&up->port.lock);
+	tty_flip_buffer_push(port);
+	spin_lock(&up->port.lock);
+}
+
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
+	void __iomem *regi_ser;
+	int handled = 0;
+
+	spin_lock(&up->port.lock);
+
+	regi_ser = up->regi_ser;
+
+	if (regi_ser) {
+		reg_ser_r_masked_intr masked_intr;
+
+		masked_intr = REG_RD(ser, regi_ser, r_masked_intr);
+		/*
+		 * Check what interrupts are active before taking
+		 * actions. If DMA is used the interrupt shouldn't
+		 * be enabled.
+		 */
+		if (masked_intr.dav) {
+			receive_chars_no_dma(up);
+			handled = 1;
+		}
+		check_modem_status(up);
+
+		if (masked_intr.tr_rdy) {
+			transmit_chars_no_dma(up);
+			handled = 1;
+		}
+	}
+	spin_unlock(&up->port.lock);
+	return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int etraxfs_uart_get_poll_char(struct uart_port *port)
+{
+	reg_ser_rs_stat_din stat;
+	reg_ser_rw_ack_intr ack_intr = { 0 };
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	do {
+		stat = REG_RD(ser, up->regi_ser, rs_stat_din);
+	} while (!stat.dav);
+
+	/* Ack the data_avail interrupt. */
+	ack_intr.dav = 1;
+	REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
+
+	return stat.data;
+}
+
+static void etraxfs_uart_put_poll_char(struct uart_port *port,
+					unsigned char c)
+{
+	reg_ser_r_stat_din stat;
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	do {
+		stat = REG_RD(ser, up->regi_ser, r_stat_din);
+	} while (!stat.tr_rdy);
+	REG_WR_INT(ser, up->regi_ser, rw_dout, c);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int etraxfs_uart_startup(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned long flags;
+	reg_ser_rw_intr_mask ser_intr_mask = {0};
+
+	ser_intr_mask.dav = regk_ser_yes;
+
+	if (request_irq(etraxfs_uart_ports[port->line]->irq, ser_interrupt,
+			0, DRV_NAME, etraxfs_uart_ports[port->line]))
+		panic("irq ser%d", port->line);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	REG_WR(ser, up->regi_ser, rw_intr_mask, ser_intr_mask);
+
+	etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	return 0;
+}
+
+static void etraxfs_uart_shutdown(struct uart_port *port)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	etraxfs_uart_stop_tx(port);
+	etraxfs_uart_stop_rx(port);
+
+	free_irq(etraxfs_uart_ports[port->line]->irq,
+		 etraxfs_uart_ports[port->line]);
+
+	etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+}
+
+static void
+etraxfs_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+			 struct ktermios *old)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+	unsigned long flags;
+	reg_ser_rw_xoff xoff;
+	reg_ser_rw_xoff_clr xoff_clr = {0};
+	reg_ser_rw_tr_ctrl tx_ctrl = {0};
+	reg_ser_rw_tr_dma_en tx_dma_en = {0};
+	reg_ser_rw_rec_ctrl rx_ctrl = {0};
+	reg_ser_rw_tr_baud_div tx_baud_div = {0};
+	reg_ser_rw_rec_baud_div rx_baud_div = {0};
+	int baud;
+
+	if (old &&
+	    termios->c_cflag == old->c_cflag &&
+	    termios->c_iflag == old->c_iflag)
+		return;
+
+	/* Tx: 8 bit, no/even parity, 1 stop bit, no cts. */
+	tx_ctrl.base_freq = regk_ser_f29_493;
+	tx_ctrl.en = 0;
+	tx_ctrl.stop = 0;
+	tx_ctrl.auto_rts = regk_ser_no;
+	tx_ctrl.txd = 1;
+	tx_ctrl.auto_cts = 0;
+	/* Rx: 8 bit, no/even parity. */
+	rx_ctrl.dma_err = regk_ser_stop;
+	rx_ctrl.sampling = regk_ser_majority;
+	rx_ctrl.timeout = 1;
+
+	rx_ctrl.rts_n = regk_ser_inactive;
+
+	/* Common for tx and rx: 8N1. */
+	tx_ctrl.data_bits = regk_ser_bits8;
+	rx_ctrl.data_bits = regk_ser_bits8;
+	tx_ctrl.par = regk_ser_even;
+	rx_ctrl.par = regk_ser_even;
+	tx_ctrl.par_en = regk_ser_no;
+	rx_ctrl.par_en = regk_ser_no;
+
+	tx_ctrl.stop_bits = regk_ser_bits1;
+
+	/*
+	 * Change baud-rate and write it to the hardware.
+	 *
+	 * baud_clock = base_freq / (divisor*8)
+	 * divisor = base_freq / (baud_clock * 8)
+	 * base_freq is either:
+	 * off, ext, 29.493MHz, 32.000 MHz, 32.768 MHz or 100 MHz
+	 * 20.493MHz is used for standard baudrates
+	 */
+
+	/*
+	 * For the console port we keep the original baudrate here.  Not very
+	 * beautiful.
+	 */
+	if ((port != console_port) || old)
+		baud = uart_get_baud_rate(port, termios, old, 0,
+					  port->uartclk / 8);
+	else
+		baud = console_baud;
+
+	tx_baud_div.div = 29493000 / (8 * baud);
+	/* Rx uses same as tx. */
+	rx_baud_div.div = tx_baud_div.div;
+	rx_ctrl.base_freq = tx_ctrl.base_freq;
+
+	if ((termios->c_cflag & CSIZE) == CS7) {
+		/* Set 7 bit mode. */
+		tx_ctrl.data_bits = regk_ser_bits7;
+		rx_ctrl.data_bits = regk_ser_bits7;
+	}
+
+	if (termios->c_cflag & CSTOPB) {
+		/* Set 2 stop bit mode. */
+		tx_ctrl.stop_bits = regk_ser_bits2;
+	}
+
+	if (termios->c_cflag & PARENB) {
+		/* Enable parity. */
+		tx_ctrl.par_en = regk_ser_yes;
+		rx_ctrl.par_en = regk_ser_yes;
+	}
+
+	if (termios->c_cflag & CMSPAR) {
+		if (termios->c_cflag & PARODD) {
+			/* Set mark parity if PARODD and CMSPAR. */
+			tx_ctrl.par = regk_ser_mark;
+			rx_ctrl.par = regk_ser_mark;
+		} else {
+			tx_ctrl.par = regk_ser_space;
+			rx_ctrl.par = regk_ser_space;
+		}
+	} else {
+		if (termios->c_cflag & PARODD) {
+			/* Set odd parity. */
+		       tx_ctrl.par = regk_ser_odd;
+		       rx_ctrl.par = regk_ser_odd;
+		}
+	}
+
+	if (termios->c_cflag & CRTSCTS) {
+		/* Enable automatic CTS handling. */
+		tx_ctrl.auto_cts = regk_ser_yes;
+	}
+
+	/* Make sure the tx and rx are enabled. */
+	tx_ctrl.en = regk_ser_yes;
+	rx_ctrl.en = regk_ser_yes;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	tx_dma_en.en = 0;
+	REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
+
+	/* Actually write the control regs (if modified) to the hardware. */
+	uart_update_timeout(port, termios->c_cflag, port->uartclk/8);
+	MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
+	MODIFY_REG(up->regi_ser, rw_rec_ctrl, rx_ctrl);
+
+	MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
+	MODIFY_REG(up->regi_ser, rw_tr_ctrl, tx_ctrl);
+
+	tx_dma_en.en = 0;
+	REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
+
+	xoff = REG_RD(ser, up->regi_ser, rw_xoff);
+
+	if (up->port.state && up->port.state->port.tty &&
+	    (up->port.state->port.tty->termios.c_iflag & IXON)) {
+		xoff.chr = STOP_CHAR(up->port.state->port.tty);
+		xoff.automatic = regk_ser_yes;
+	} else
+		xoff.automatic = regk_ser_no;
+
+	MODIFY_REG(up->regi_ser, rw_xoff, xoff);
+
+	/*
+	 * Make sure we don't start in an automatically shut-off state due to
+	 * a previous early exit.
+	 */
+	xoff_clr.clr = 1;
+	REG_WR(ser, up->regi_ser, rw_xoff_clr, xoff_clr);
+
+	etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *
+etraxfs_uart_type(struct uart_port *port)
+{
+	return "CRISv32";
+}
+
+static void etraxfs_uart_release_port(struct uart_port *port)
+{
+}
+
+static int etraxfs_uart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void etraxfs_uart_config_port(struct uart_port *port, int flags)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	up->port.type = PORT_CRIS;
+}
+
+static const struct uart_ops etraxfs_uart_pops = {
+	.tx_empty = etraxfs_uart_tx_empty,
+	.set_mctrl = etraxfs_uart_set_mctrl,
+	.get_mctrl = etraxfs_uart_get_mctrl,
+	.stop_tx = etraxfs_uart_stop_tx,
+	.start_tx = etraxfs_uart_start_tx,
+	.send_xchar = etraxfs_uart_send_xchar,
+	.stop_rx = etraxfs_uart_stop_rx,
+	.enable_ms = etraxfs_uart_enable_ms,
+	.break_ctl = etraxfs_uart_break_ctl,
+	.startup = etraxfs_uart_startup,
+	.shutdown = etraxfs_uart_shutdown,
+	.set_termios = etraxfs_uart_set_termios,
+	.type = etraxfs_uart_type,
+	.release_port = etraxfs_uart_release_port,
+	.request_port = etraxfs_uart_request_port,
+	.config_port = etraxfs_uart_config_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char = etraxfs_uart_get_poll_char,
+	.poll_put_char = etraxfs_uart_put_poll_char,
+#endif
+};
+
+static void cris_serial_port_init(struct uart_port *port, int line)
+{
+	struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+	if (up->initialized)
+		return;
+	up->initialized = 1;
+	port->line = line;
+	spin_lock_init(&port->lock);
+	port->ops = &etraxfs_uart_pops;
+	port->irq = up->irq;
+	port->iobase = (unsigned long) up->regi_ser;
+	port->uartclk = 29493000;
+
+	/*
+	 * We can't fit any more than 255 here (unsigned char), though
+	 * actually UART_XMIT_SIZE characters could be pending output.
+	 * At time of this writing, the definition of "fifosize" is here the
+	 * amount of characters that can be pending output after a start_tx call
+	 * until tx_empty returns 1: see serial_core.c:uart_wait_until_sent.
+	 * This matters for timeout calculations unfortunately, but keeping
+	 * larger amounts at the DMA wouldn't win much so let's just play nice.
+	 */
+	port->fifosize = 255;
+	port->flags = UPF_BOOT_AUTOCONF;
+}
+
+static int etraxfs_uart_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct uart_cris_port *up;
+	int dev_id;
+
+	if (!np)
+		return -ENODEV;
+
+	dev_id = of_alias_get_id(np, "serial");
+	if (dev_id < 0)
+		dev_id = 0;
+
+	if (dev_id >= UART_NR)
+		return -EINVAL;
+
+	if (etraxfs_uart_ports[dev_id])
+		return -EBUSY;
+
+	up = devm_kzalloc(&pdev->dev, sizeof(struct uart_cris_port),
+			  GFP_KERNEL);
+	if (!up)
+		return -ENOMEM;
+
+	up->irq = irq_of_parse_and_map(np, 0);
+	up->regi_ser = of_iomap(np, 0);
+	up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr");
+	up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr");
+	up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri");
+	up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd");
+	up->port.dev = &pdev->dev;
+	cris_serial_port_init(&up->port, dev_id);
+
+	etraxfs_uart_ports[dev_id] = up;
+	platform_set_drvdata(pdev, &up->port);
+	uart_add_one_port(&etraxfs_uart_driver, &up->port);
+
+	return 0;
+}
+
+static int etraxfs_uart_remove(struct platform_device *pdev)
+{
+	struct uart_port *port;
+
+	port = platform_get_drvdata(pdev);
+	uart_remove_one_port(&etraxfs_uart_driver, port);
+	etraxfs_uart_ports[pdev->id] = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id etraxfs_uart_dt_ids[] = {
+	{ .compatible = "axis,etraxfs-uart" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, etraxfs_uart_dt_ids);
+
+static struct platform_driver etraxfs_uart_platform_driver = {
+	.driver = {
+		.name   = DRV_NAME,
+		.of_match_table	= of_match_ptr(etraxfs_uart_dt_ids),
+	},
+	.probe          = etraxfs_uart_probe,
+	.remove         = etraxfs_uart_remove,
+};
+
+static int __init etraxfs_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&etraxfs_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&etraxfs_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&etraxfs_uart_driver);
+
+	return ret;
+}
+
+static void __exit etraxfs_uart_exit(void)
+{
+	platform_driver_unregister(&etraxfs_uart_platform_driver);
+	uart_unregister_driver(&etraxfs_uart_driver);
+}
+
+module_init(etraxfs_uart_init);
+module_exit(etraxfs_uart_exit);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index e7cde3a..b1893f3 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -237,7 +237,8 @@
 	unsigned int		rxfifo_size;
 	bool			lpuart32;
 
-	bool			lpuart_dma_use;
+	bool			lpuart_dma_tx_use;
+	bool			lpuart_dma_rx_use;
 	struct dma_chan		*dma_tx_chan;
 	struct dma_chan		*dma_rx_chan;
 	struct dma_async_tx_descriptor  *dma_tx_desc;
@@ -454,6 +455,15 @@
 	return 0;
 }
 
+static void lpuart_flush_buffer(struct uart_port *port)
+{
+	struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+	if (sport->lpuart_dma_tx_use) {
+		dmaengine_terminate_all(sport->dma_tx_chan);
+		sport->dma_tx_in_progress = 0;
+	}
+}
+
 static void lpuart_dma_rx_complete(void *arg)
 {
 	struct lpuart_port *sport = arg;
@@ -461,6 +471,7 @@
 	unsigned long flags;
 
 	async_tx_ack(sport->dma_rx_desc);
+	mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -506,9 +517,6 @@
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
-	init_timer(&sport->lpuart_timer);
-	sport->lpuart_timer.function = lpuart_timer_func;
-	sport->lpuart_timer.data = (unsigned long)sport;
 	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
 	add_timer(&sport->lpuart_timer);
 
@@ -571,7 +579,7 @@
 	temp = readb(port->membase + UARTCR2);
 	writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
 
-	if (sport->lpuart_dma_use) {
+	if (sport->lpuart_dma_tx_use) {
 		if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
 			lpuart_prepare_tx(sport);
 	} else {
@@ -758,19 +766,19 @@
 static irqreturn_t lpuart_int(int irq, void *dev_id)
 {
 	struct lpuart_port *sport = dev_id;
-	unsigned char sts;
+	unsigned char sts, crdma;
 
 	sts = readb(sport->port.membase + UARTSR1);
+	crdma = readb(sport->port.membase + UARTCR5);
 
-	if (sts & UARTSR1_RDRF) {
-		if (sport->lpuart_dma_use)
+	if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+		if (sport->lpuart_dma_rx_use)
 			lpuart_prepare_rx(sport);
 		else
 			lpuart_rxint(irq, dev_id);
 	}
-	if (sts & UARTSR1_TDRE &&
-		!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
-		if (sport->lpuart_dma_use)
+	if (sts & UARTSR1_TDRE && !(crdma & UARTCR5_TDMAS)) {
+		if (sport->lpuart_dma_tx_use)
 			lpuart_pio_tx(sport);
 		else
 			lpuart_txint(irq, dev_id);
@@ -953,26 +961,17 @@
 {
 	struct lpuart_port *sport = container_of(port,
 					struct lpuart_port, port);
-	struct dma_chan *tx_chan;
 	struct dma_slave_config dma_tx_sconfig;
 	dma_addr_t dma_bus;
 	unsigned char *dma_buf;
 	int ret;
 
-	tx_chan  = dma_request_slave_channel(sport->port.dev, "tx");
-
-	if (!tx_chan) {
-		dev_err(sport->port.dev, "Dma tx channel request failed!\n");
-		return -ENODEV;
-	}
-
-	dma_bus = dma_map_single(tx_chan->device->dev,
+	dma_bus = dma_map_single(sport->dma_tx_chan->device->dev,
 				sport->port.state->xmit.buf,
 				UART_XMIT_SIZE, DMA_TO_DEVICE);
 
-	if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+	if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) {
 		dev_err(sport->port.dev, "dma_map_single tx failed\n");
-		dma_release_channel(tx_chan);
 		return -ENOMEM;
 	}
 
@@ -981,16 +980,14 @@
 	dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_tx_sconfig.dst_maxburst = sport->txfifo_size;
 	dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
-	ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+	ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
 
 	if (ret < 0) {
 		dev_err(sport->port.dev,
 				"Dma slave config failed, err = %d\n", ret);
-		dma_release_channel(tx_chan);
 		return ret;
 	}
 
-	sport->dma_tx_chan = tx_chan;
 	sport->dma_tx_buf_virt = dma_buf;
 	sport->dma_tx_buf_bus = dma_bus;
 	sport->dma_tx_in_progress = 0;
@@ -1002,34 +999,24 @@
 {
 	struct lpuart_port *sport = container_of(port,
 					struct lpuart_port, port);
-	struct dma_chan *rx_chan;
 	struct dma_slave_config dma_rx_sconfig;
 	dma_addr_t dma_bus;
 	unsigned char *dma_buf;
 	int ret;
 
-	rx_chan  = dma_request_slave_channel(sport->port.dev, "rx");
-
-	if (!rx_chan) {
-		dev_err(sport->port.dev, "Dma rx channel request failed!\n");
-		return -ENODEV;
-	}
-
 	dma_buf = devm_kzalloc(sport->port.dev,
 				FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
 
 	if (!dma_buf) {
 		dev_err(sport->port.dev, "Dma rx alloc failed\n");
-		dma_release_channel(rx_chan);
 		return -ENOMEM;
 	}
 
-	dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+	dma_bus = dma_map_single(sport->dma_rx_chan->device->dev, dma_buf,
 				FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
 
-	if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+	if (dma_mapping_error(sport->dma_rx_chan->device->dev, dma_bus)) {
 		dev_err(sport->port.dev, "dma_map_single rx failed\n");
-		dma_release_channel(rx_chan);
 		return -ENOMEM;
 	}
 
@@ -1037,16 +1024,14 @@
 	dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
 	dma_rx_sconfig.src_maxburst = 1;
 	dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
-	ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+	ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
 
 	if (ret < 0) {
 		dev_err(sport->port.dev,
 				"Dma slave config failed, err = %d\n", ret);
-		dma_release_channel(rx_chan);
 		return ret;
 	}
 
-	sport->dma_rx_chan = rx_chan;
 	sport->dma_rx_buf_virt = dma_buf;
 	sport->dma_rx_buf_bus = dma_bus;
 	sport->dma_rx_in_progress = 0;
@@ -1058,31 +1043,24 @@
 {
 	struct lpuart_port *sport = container_of(port,
 					struct lpuart_port, port);
-	struct dma_chan *dma_chan;
 
 	dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
 			UART_XMIT_SIZE, DMA_TO_DEVICE);
-	dma_chan = sport->dma_tx_chan;
-	sport->dma_tx_chan = NULL;
+
 	sport->dma_tx_buf_bus = 0;
 	sport->dma_tx_buf_virt = NULL;
-	dma_release_channel(dma_chan);
 }
 
 static void lpuart_dma_rx_free(struct uart_port *port)
 {
 	struct lpuart_port *sport = container_of(port,
 					struct lpuart_port, port);
-	struct dma_chan *dma_chan;
 
 	dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
 			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
 
-	dma_chan = sport->dma_rx_chan;
-	sport->dma_rx_chan = NULL;
 	sport->dma_rx_buf_bus = 0;
 	sport->dma_rx_buf_virt = NULL;
-	dma_release_channel(dma_chan);
 }
 
 static int lpuart_startup(struct uart_port *port)
@@ -1101,14 +1079,21 @@
 	sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
 		UARTPFIFO_FIFOSIZE_MASK) + 1);
 
-	/* Whether use dma support by dma request results */
-	if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
-		sport->lpuart_dma_use = false;
-	} else {
-		sport->lpuart_dma_use = true;
+	if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
+		sport->lpuart_dma_rx_use = true;
+		setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+			    (unsigned long)sport);
+	} else
+		sport->lpuart_dma_rx_use = false;
+
+
+	if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
+		sport->lpuart_dma_tx_use = true;
 		temp = readb(port->membase + UARTCR5);
+		temp &= ~UARTCR5_RDMAS;
 		writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
-	}
+	} else
+		sport->lpuart_dma_tx_use = false;
 
 	ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
 				DRIVER_NAME, sport);
@@ -1179,10 +1164,13 @@
 
 	devm_free_irq(port->dev, port->irq, sport);
 
-	if (sport->lpuart_dma_use) {
-		lpuart_dma_tx_free(port);
-		lpuart_dma_rx_free(port);
+	if (sport->lpuart_dma_rx_use) {
+		lpuart_dma_rx_free(&sport->port);
+		del_timer_sync(&sport->lpuart_timer);
 	}
+
+	if (sport->lpuart_dma_tx_use)
+		lpuart_dma_tx_free(&sport->port);
 }
 
 static void lpuart32_shutdown(struct uart_port *port)
@@ -1304,7 +1292,7 @@
 	/* update the per-port timeout */
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	if (sport->lpuart_dma_use) {
+	if (sport->lpuart_dma_rx_use) {
 		/* Calculate delay for 1.5 DMA buffers */
 		sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
 					FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
@@ -1517,6 +1505,7 @@
 	.release_port	= lpuart_release_port,
 	.config_port	= lpuart_config_port,
 	.verify_port	= lpuart_verify_port,
+	.flush_buffer	= lpuart_flush_buffer,
 };
 
 static struct uart_ops lpuart32_pops = {
@@ -1535,6 +1524,7 @@
 	.release_port	= lpuart_release_port,
 	.config_port	= lpuart_config_port,
 	.verify_port	= lpuart_verify_port,
+	.flush_buffer	= lpuart_flush_buffer,
 };
 
 static struct lpuart_port *lpuart_ports[UART_NR];
@@ -1833,6 +1823,16 @@
 		return ret;
 	}
 
+	sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
+	if (!sport->dma_tx_chan)
+		dev_info(sport->port.dev, "DMA tx channel request failed, "
+				"operating without tx DMA\n");
+
+	sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
+	if (!sport->dma_rx_chan)
+		dev_info(sport->port.dev, "DMA rx channel request failed, "
+				"operating without rx DMA\n");
+
 	return 0;
 }
 
@@ -1844,6 +1844,12 @@
 
 	clk_disable_unprepare(sport->clk);
 
+	if (sport->dma_tx_chan)
+		dma_release_channel(sport->dma_tx_chan);
+
+	if (sport->dma_rx_chan)
+		dma_release_channel(sport->dma_rx_chan);
+
 	return 0;
 }
 
@@ -1851,6 +1857,19 @@
 static int lpuart_suspend(struct device *dev)
 {
 	struct lpuart_port *sport = dev_get_drvdata(dev);
+	unsigned long temp;
+
+	if (sport->lpuart32) {
+		/* disable Rx/Tx and interrupts */
+		temp = lpuart32_read(sport->port.membase + UARTCTRL);
+		temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
+		lpuart32_write(temp, sport->port.membase + UARTCTRL);
+	} else {
+		/* disable Rx/Tx and interrupts */
+		temp = readb(sport->port.membase + UARTCR2);
+		temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
+		writeb(temp, sport->port.membase + UARTCR2);
+	}
 
 	uart_suspend_port(&lpuart_reg, &sport->port);
 
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 4c5e909..0eb29b1 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -74,6 +74,7 @@
 #define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
 
 /* UART Control Register Bit Fields.*/
+#define URXD_DUMMY_READ (1<<16)
 #define URXD_CHARRDY	(1<<15)
 #define URXD_ERR	(1<<14)
 #define URXD_OVRRUN	(1<<13)
@@ -463,13 +464,17 @@
 	mod_timer(&sport->timer, jiffies);
 }
 
+static void imx_dma_tx(struct imx_port *sport);
 static inline void imx_transmit_buffer(struct imx_port *sport)
 {
 	struct circ_buf *xmit = &sport->port.state->xmit;
+	unsigned long temp;
 
 	if (sport->port.x_char) {
 		/* Send next char */
 		writel(sport->port.x_char, sport->port.membase + URTX0);
+		sport->port.icount.tx++;
+		sport->port.x_char = 0;
 		return;
 	}
 
@@ -478,6 +483,22 @@
 		return;
 	}
 
+	if (sport->dma_is_enabled) {
+		/*
+		 * We've just sent a X-char Ensure the TX DMA is enabled
+		 * and the TX IRQ is disabled.
+		 **/
+		temp = readl(sport->port.membase + UCR1);
+		temp &= ~UCR1_TXMPTYEN;
+		if (sport->dma_is_txing) {
+			temp |= UCR1_TDMAEN;
+			writel(temp, sport->port.membase + UCR1);
+		} else {
+			writel(temp, sport->port.membase + UCR1);
+			imx_dma_tx(sport);
+		}
+	}
+
 	while (!uart_circ_empty(xmit) &&
 	       !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
 		/* send xmit->buf[xmit->tail]
@@ -500,26 +521,39 @@
 	struct scatterlist *sgl = &sport->tx_sgl[0];
 	struct circ_buf *xmit = &sport->port.state->xmit;
 	unsigned long flags;
+	unsigned long temp;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
 
 	dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
 
-	sport->dma_is_txing = 0;
+	temp = readl(sport->port.membase + UCR1);
+	temp &= ~UCR1_TDMAEN;
+	writel(temp, sport->port.membase + UCR1);
 
 	/* update the stat */
-	spin_lock_irqsave(&sport->port.lock, flags);
 	xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
 	sport->port.icount.tx += sport->tx_bytes;
-	spin_unlock_irqrestore(&sport->port.lock, flags);
 
 	dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
 
-	uart_write_wakeup(&sport->port);
+	sport->dma_is_txing = 0;
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&sport->port);
 
 	if (waitqueue_active(&sport->dma_wait)) {
 		wake_up(&sport->dma_wait);
 		dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
 		return;
 	}
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+		imx_dma_tx(sport);
+	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void imx_dma_tx(struct imx_port *sport)
@@ -529,24 +563,23 @@
 	struct dma_async_tx_descriptor *desc;
 	struct dma_chan	*chan = sport->dma_chan_tx;
 	struct device *dev = sport->port.dev;
-	enum dma_status status;
+	unsigned long temp;
 	int ret;
 
-	status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL);
-	if (DMA_IN_PROGRESS == status)
+	if (sport->dma_is_txing)
 		return;
 
 	sport->tx_bytes = uart_circ_chars_pending(xmit);
 
-	if (xmit->tail > xmit->head && xmit->head > 0) {
+	if (xmit->tail < xmit->head) {
+		sport->dma_tx_nents = 1;
+		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+	} else {
 		sport->dma_tx_nents = 2;
 		sg_init_table(sgl, 2);
 		sg_set_buf(sgl, xmit->buf + xmit->tail,
 				UART_XMIT_SIZE - xmit->tail);
 		sg_set_buf(sgl + 1, xmit->buf, xmit->head);
-	} else {
-		sport->dma_tx_nents = 1;
-		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
 	}
 
 	ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@@ -557,6 +590,8 @@
 	desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
 					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
 	if (!desc) {
+		dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
+			     DMA_TO_DEVICE);
 		dev_err(dev, "We cannot prepare for the TX slave dma!\n");
 		return;
 	}
@@ -565,6 +600,11 @@
 
 	dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
 			uart_circ_chars_pending(xmit));
+
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_TDMAEN;
+	writel(temp, sport->port.membase + UCR1);
+
 	/* fire it */
 	sport->dma_is_txing = 1;
 	dmaengine_submit(desc);
@@ -590,13 +630,6 @@
 		temp &= ~(UCR1_RRDYEN);
 		writel(temp, sport->port.membase + UCR1);
 	}
-	/* Clear any pending ORE flag before enabling interrupt */
-	temp = readl(sport->port.membase + USR2);
-	writel(temp | USR2_ORE, sport->port.membase + USR2);
-
-	temp = readl(sport->port.membase + UCR4);
-	temp |= UCR4_OREN;
-	writel(temp, sport->port.membase + UCR4);
 
 	if (!sport->dma_is_enabled) {
 		temp = readl(sport->port.membase + UCR1);
@@ -614,15 +647,21 @@
 	}
 
 	if (sport->dma_is_enabled) {
-		/* FIXME: port->x_char must be transmitted if != 0 */
+		if (sport->port.x_char) {
+			/* We have X-char to send, so enable TX IRQ and
+			 * disable TX DMA to let TX interrupt to send X-char */
+			temp = readl(sport->port.membase + UCR1);
+			temp &= ~UCR1_TDMAEN;
+			temp |= UCR1_TXMPTYEN;
+			writel(temp, sport->port.membase + UCR1);
+			return;
+		}
+
 		if (!uart_circ_empty(&port->state->xmit) &&
 		    !uart_tx_stopped(port))
 			imx_dma_tx(sport);
 		return;
 	}
-
-	if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
-		imx_transmit_buffer(sport);
 }
 
 static irqreturn_t imx_rtsint(int irq, void *dev_id)
@@ -694,7 +733,7 @@
 				continue;
 			}
 
-			rx &= sport->port.read_status_mask;
+			rx &= (sport->port.read_status_mask | 0xFF);
 
 			if (rx & URXD_BRK)
 				flg = TTY_BREAK;
@@ -710,6 +749,9 @@
 #endif
 		}
 
+		if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
+			goto out;
+
 		tty_insert_flip_char(port, rx, flg);
 	}
 
@@ -727,6 +769,9 @@
 static void imx_dma_rxint(struct imx_port *sport)
 {
 	unsigned long temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
 
 	temp = readl(sport->port.membase + USR2);
 	if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
@@ -740,6 +785,8 @@
 		/* tell the DMA to receive the data. */
 		start_rx_dma(sport);
 	}
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static irqreturn_t imx_int(int irq, void *dev_id)
@@ -869,6 +916,9 @@
 static void imx_rx_dma_done(struct imx_port *sport)
 {
 	unsigned long temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
 
 	/* Enable this interrupt when the RXFIFO is empty. */
 	temp = readl(sport->port.membase + UCR1);
@@ -880,6 +930,8 @@
 	/* Is the shutdown waiting for us? */
 	if (waitqueue_active(&sport->dma_wait))
 		wake_up(&sport->dma_wait);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 /*
@@ -910,12 +962,26 @@
 	dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
 
 	if (count) {
-		tty_insert_flip_string(port, sport->rx_buf, count);
+		if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ))
+			tty_insert_flip_string(port, sport->rx_buf, count);
 		tty_flip_buffer_push(port);
 
 		start_rx_dma(sport);
-	} else
+	} else if (readl(sport->port.membase + USR2) & USR2_RDR) {
+		/*
+		 * start rx_dma directly once data in RXFIFO, more efficient
+		 * than before:
+		 *	1. call imx_rx_dma_done to stop dma if no data received
+		 *	2. wait next  RDR interrupt to start dma transfer.
+		 */
+		start_rx_dma(sport);
+	} else {
+		/*
+		 * stop dma to prevent too many IDLE event trigged if no data
+		 * in RXFIFO
+		 */
 		imx_rx_dma_done(sport);
+	}
 }
 
 static int start_rx_dma(struct imx_port *sport)
@@ -935,6 +1001,7 @@
 	desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
 					DMA_PREP_INTERRUPT);
 	if (!desc) {
+		dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
 		dev_err(dev, "We cannot prepare for the RX slave dma!\n");
 		return -EINVAL;
 	}
@@ -1108,12 +1175,20 @@
 	while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
 		udelay(1);
 
+	/* Can we enable the DMA support? */
+	if (is_imx6q_uart(sport) && !uart_console(port) &&
+	    !sport->dma_is_inited)
+		imx_uart_dma_init(sport);
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 	/*
 	 * Finally, clear and enable interrupts
 	 */
 	writel(USR1_RTSD, sport->port.membase + USR1);
 
+	if (sport->dma_is_inited && !sport->dma_is_enabled)
+		imx_enable_dma(sport);
+
 	temp = readl(sport->port.membase + UCR1);
 	temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 
@@ -1124,6 +1199,14 @@
 
 	writel(temp, sport->port.membase + UCR1);
 
+	/* Clear any pending ORE flag before enabling interrupt */
+	temp = readl(sport->port.membase + USR2);
+	writel(temp | USR2_ORE, sport->port.membase + USR2);
+
+	temp = readl(sport->port.membase + UCR4);
+	temp |= UCR4_OREN;
+	writel(temp, sport->port.membase + UCR4);
+
 	temp = readl(sport->port.membase + UCR2);
 	temp |= (UCR2_RXEN | UCR2_TXEN);
 	if (!sport->have_rtscts)
@@ -1189,9 +1272,11 @@
 			dmaengine_terminate_all(sport->dma_chan_tx);
 			dmaengine_terminate_all(sport->dma_chan_rx);
 		}
+		spin_lock_irqsave(&sport->port.lock, flags);
 		imx_stop_tx(port);
 		imx_stop_rx(port);
 		imx_disable_dma(sport);
+		spin_unlock_irqrestore(&sport->port.lock, flags);
 		imx_uart_dma_exit(sport);
 	}
 
@@ -1233,11 +1318,48 @@
 static void imx_flush_buffer(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
+	struct scatterlist *sgl = &sport->tx_sgl[0];
+	unsigned long temp;
+	int i = 100, ubir, ubmr, ubrc, uts;
 
-	if (sport->dma_is_enabled) {
-		sport->tx_bytes = 0;
-		dmaengine_terminate_all(sport->dma_chan_tx);
+	if (!sport->dma_chan_tx)
+		return;
+
+	sport->tx_bytes = 0;
+	dmaengine_terminate_all(sport->dma_chan_tx);
+	if (sport->dma_is_txing) {
+		dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents,
+			     DMA_TO_DEVICE);
+		temp = readl(sport->port.membase + UCR1);
+		temp &= ~UCR1_TDMAEN;
+		writel(temp, sport->port.membase + UCR1);
+		sport->dma_is_txing = false;
 	}
+
+	/*
+	 * According to the Reference Manual description of the UART SRST bit:
+	 * "Reset the transmit and receive state machines,
+	 * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
+	 * and UTS[6-3]". As we don't need to restore the old values from
+	 * USR1, USR2, URXD, UTXD, only save/restore the other four registers
+	 */
+	ubir = readl(sport->port.membase + UBIR);
+	ubmr = readl(sport->port.membase + UBMR);
+	ubrc = readl(sport->port.membase + UBRC);
+	uts = readl(sport->port.membase + IMX21_UTS);
+
+	temp = readl(sport->port.membase + UCR2);
+	temp &= ~UCR2_SRST;
+	writel(temp, sport->port.membase + UCR2);
+
+	while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+		udelay(1);
+
+	/* Restore the registers */
+	writel(ubir, sport->port.membase + UBIR);
+	writel(ubmr, sport->port.membase + UBMR);
+	writel(ubrc, sport->port.membase + UBRC);
+	writel(uts, sport->port.membase + IMX21_UTS);
 }
 
 static void
@@ -1280,11 +1402,6 @@
 		if (sport->have_rtscts) {
 			ucr2 &= ~UCR2_IRTS;
 			ucr2 |= UCR2_CTSC;
-
-			/* Can we enable the DMA support? */
-			if (is_imx6q_uart(sport) && !uart_console(port)
-				&& !sport->dma_is_inited)
-				imx_uart_dma_init(sport);
 		} else {
 			termios->c_cflag &= ~CRTSCTS;
 		}
@@ -1319,7 +1436,7 @@
 	 */
 	sport->port.ignore_status_mask = 0;
 	if (termios->c_iflag & IGNPAR)
-		sport->port.ignore_status_mask |= URXD_PRERR;
+		sport->port.ignore_status_mask |= URXD_PRERR | URXD_FRMERR;
 	if (termios->c_iflag & IGNBRK) {
 		sport->port.ignore_status_mask |= URXD_BRK;
 		/*
@@ -1330,6 +1447,9 @@
 			sport->port.ignore_status_mask |= URXD_OVRRUN;
 	}
 
+	if ((termios->c_cflag & CREAD) == 0)
+		sport->port.ignore_status_mask |= URXD_DUMMY_READ;
+
 	/*
 	 * Update the per-port timeout.
 	 */
@@ -1403,8 +1523,6 @@
 	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
 		imx_enable_ms(&sport->port);
 
-	if (sport->dma_is_inited && !sport->dma_is_enabled)
-		imx_enable_dma(sport);
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 1049667..a9b0ab3 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -3,7 +3,7 @@
 /*
  *	mcf.c -- Freescale ColdFire UART driver
  *
- *	(C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *	(C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.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
@@ -198,7 +198,6 @@
 static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
 	struct ktermios *old)
 {
-	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
 	unsigned long flags;
 	unsigned int baud, baudclk;
 #if defined(CONFIG_M5272)
@@ -441,7 +440,6 @@
 /* Enable or disable the RS485 support */
 static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
 {
-	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
 	unsigned char mr1, mr2;
 
 	/* Get mode registers */
@@ -631,6 +629,7 @@
 		port->mapbase = platp[i].mapbase;
 		port->membase = (platp[i].membase) ? platp[i].membase :
 			(unsigned char __iomem *) platp[i].mapbase;
+		port->dev = &pdev->dev;
 		port->iotype = SERIAL_IO_MEM;
 		port->irq = platp[i].irq;
 		port->uartclk = MCF_BUSCLK;
@@ -702,7 +701,7 @@
 module_init(mcf_init);
 module_exit(mcf_exit);
 
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
 MODULE_DESCRIPTION("Freescale ColdFire UART driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:mcfuart");
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 517cd07..35c5550 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -23,7 +23,6 @@
 #define MEN_Z135_MAX_PORTS		12
 #define MEN_Z135_BASECLK		29491200
 #define MEN_Z135_FIFO_SIZE		1024
-#define MEN_Z135_NUM_MSI_VECTORS	2
 #define MEN_Z135_FIFO_WATERMARK		1020
 
 #define MEN_Z135_STAT_REG		0x0
@@ -34,12 +33,11 @@
 #define MEN_Z135_CONF_REG		0x808
 #define MEN_Z135_UART_FREQ		0x80c
 #define MEN_Z135_BAUD_REG		0x810
-#define MENZ135_TIMEOUT			0x814
+#define MEN_Z135_TIMEOUT		0x814
 
 #define MEN_Z135_MEM_SIZE		0x818
 
-#define IS_IRQ(x) ((x) & 1)
-#define IRQ_ID(x) (((x) >> 1) & 7)
+#define IRQ_ID(x) ((x) & 0x1f)
 
 #define MEN_Z135_IER_RXCIEN BIT(0)		/* RX Space IRQ */
 #define MEN_Z135_IER_TXCIEN BIT(1)		/* TX Space IRQ */
@@ -94,11 +92,11 @@
 #define MEN_Z135_LSR_TEXP BIT(6)
 #define MEN_Z135_LSR_RXFIFOERR BIT(7)
 
-#define MEN_Z135_IRQ_ID_MST 0
-#define MEN_Z135_IRQ_ID_TSA 1
-#define MEN_Z135_IRQ_ID_RDA 2
-#define MEN_Z135_IRQ_ID_RLS 3
-#define MEN_Z135_IRQ_ID_CTI 6
+#define MEN_Z135_IRQ_ID_RLS BIT(0)
+#define MEN_Z135_IRQ_ID_RDA BIT(1)
+#define MEN_Z135_IRQ_ID_CTI BIT(2)
+#define MEN_Z135_IRQ_ID_TSA BIT(3)
+#define MEN_Z135_IRQ_ID_MST BIT(4)
 
 #define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
 
@@ -118,12 +116,18 @@
 module_param(align, int, S_IRUGO);
 MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
 
+static uint rx_timeout;
+module_param(rx_timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(rx_timeout, "RX timeout. "
+		"Timeout in seconds = (timeout_reg * baud_reg * 4) / freq_reg");
+
 struct men_z135_port {
 	struct uart_port port;
 	struct mcb_device *mdev;
 	unsigned char *rxbuf;
 	u32 stat_reg;
 	spinlock_t lock;
+	bool automode;
 };
 #define to_men_z135(port) container_of((port), struct men_z135_port, port)
 
@@ -180,12 +184,16 @@
  */
 static void men_z135_handle_modem_status(struct men_z135_port *uart)
 {
-	if (uart->stat_reg & MEN_Z135_MSR_DDCD)
+	u8 msr;
+
+	msr = (uart->stat_reg >> 8) & 0xff;
+
+	if (msr & MEN_Z135_MSR_DDCD)
 		uart_handle_dcd_change(&uart->port,
-				uart->stat_reg & ~MEN_Z135_MSR_DCD);
-	if (uart->stat_reg & MEN_Z135_MSR_DCTS)
+				msr & MEN_Z135_MSR_DCD);
+	if (msr & MEN_Z135_MSR_DCTS)
 		uart_handle_cts_change(&uart->port,
-				uart->stat_reg & ~MEN_Z135_MSR_CTS);
+				msr & MEN_Z135_MSR_CTS);
 }
 
 static void men_z135_handle_lsr(struct men_z135_port *uart)
@@ -322,7 +330,8 @@
 
 	txfree = MEN_Z135_FIFO_WATERMARK - txc;
 	if (txfree <= 0) {
-		pr_err("Not enough room in TX FIFO have %d, need %d\n",
+		dev_err(&uart->mdev->dev,
+			"Not enough room in TX FIFO have %d, need %d\n",
 			txfree, qlen);
 		goto irq_en;
 	}
@@ -373,43 +382,54 @@
  * @irq: The IRQ number
  * @data: Pointer to UART port
  *
- * Check IIR register to see which tasklet to start.
+ * Check IIR register to find the cause of the interrupt and handle it.
+ * It is possible that multiple interrupts reason bits are set and reading
+ * the IIR is a destructive read, so we always need to check for all possible
+ * interrupts and handle them.
  */
 static irqreturn_t men_z135_intr(int irq, void *data)
 {
 	struct men_z135_port *uart = (struct men_z135_port *)data;
 	struct uart_port *port = &uart->port;
+	bool handled = false;
+	unsigned long flags;
 	int irq_id;
 
 	uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
-	/* IRQ pending is low active */
-	if (IS_IRQ(uart->stat_reg))
-		return IRQ_NONE;
-
 	irq_id = IRQ_ID(uart->stat_reg);
-	switch (irq_id) {
-	case MEN_Z135_IRQ_ID_MST:
-		men_z135_handle_modem_status(uart);
-		break;
-	case MEN_Z135_IRQ_ID_TSA:
-		men_z135_handle_tx(uart);
-		break;
-	case MEN_Z135_IRQ_ID_CTI:
-		dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
-		/* Fallthrough */
-	case MEN_Z135_IRQ_ID_RDA:
-		/* Reading data clears RX IRQ */
-		men_z135_handle_rx(uart);
-		break;
-	case MEN_Z135_IRQ_ID_RLS:
+
+	if (!irq_id)
+		goto out;
+
+	spin_lock_irqsave(&port->lock, flags);
+	/* It's save to write to IIR[7:6] RXC[9:8] */
+	iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG);
+
+	if (irq_id & MEN_Z135_IRQ_ID_RLS) {
 		men_z135_handle_lsr(uart);
-		break;
-	default:
-		dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
-		return IRQ_NONE;
+		handled = true;
 	}
 
-	return IRQ_HANDLED;
+	if (irq_id & (MEN_Z135_IRQ_ID_RDA | MEN_Z135_IRQ_ID_CTI)) {
+		if (irq_id & MEN_Z135_IRQ_ID_CTI)
+			dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
+		men_z135_handle_rx(uart);
+		handled = true;
+	}
+
+	if (irq_id & MEN_Z135_IRQ_ID_TSA) {
+		men_z135_handle_tx(uart);
+		handled = true;
+	}
+
+	if (irq_id & MEN_Z135_IRQ_ID_MST) {
+		men_z135_handle_modem_status(uart);
+		handled = true;
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+out:
+	return IRQ_RETVAL(handled);
 }
 
 /**
@@ -464,21 +484,37 @@
  */
 static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct men_z135_port *uart = to_men_z135(port);
-	u32 conf_reg = 0;
+	u32 old;
+	u32 conf_reg;
 
+	conf_reg = old = ioread32(port->membase + MEN_Z135_CONF_REG);
 	if (mctrl & TIOCM_RTS)
 		conf_reg |= MEN_Z135_MCR_RTS;
+	else
+		conf_reg &= ~MEN_Z135_MCR_RTS;
+
 	if (mctrl & TIOCM_DTR)
 		conf_reg |= MEN_Z135_MCR_DTR;
+	else
+		conf_reg &= ~MEN_Z135_MCR_DTR;
+
 	if (mctrl & TIOCM_OUT1)
 		conf_reg |= MEN_Z135_MCR_OUT1;
+	else
+		conf_reg &= ~MEN_Z135_MCR_OUT1;
+
 	if (mctrl & TIOCM_OUT2)
 		conf_reg |= MEN_Z135_MCR_OUT2;
+	else
+		conf_reg &= ~MEN_Z135_MCR_OUT2;
+
 	if (mctrl & TIOCM_LOOP)
 		conf_reg |= MEN_Z135_MCR_LOOP;
+	else
+		conf_reg &= ~MEN_Z135_MCR_LOOP;
 
-	men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
+	if (conf_reg != old)
+		iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
 }
 
 /**
@@ -490,12 +526,9 @@
 static unsigned int men_z135_get_mctrl(struct uart_port *port)
 {
 	unsigned int mctrl = 0;
-	u32 stat_reg;
 	u8 msr;
 
-	stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
-
-	msr = ~((stat_reg >> 8) & 0xff);
+	msr = ioread8(port->membase + MEN_Z135_STAT_REG + 1);
 
 	if (msr & MEN_Z135_MSR_CTS)
 		mctrl |= TIOCM_CTS;
@@ -524,6 +557,19 @@
 	men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
 }
 
+/*
+ * men_z135_disable_ms() - Disable Modem Status
+ * port: The UART port
+ *
+ * Enable Modem Status IRQ.
+ */
+static void men_z135_disable_ms(struct uart_port *port)
+{
+	struct men_z135_port *uart = to_men_z135(port);
+
+	men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
+}
+
 /**
  * men_z135_start_tx() - Start transmitting characters
  * @port: The UART port
@@ -535,6 +581,9 @@
 {
 	struct men_z135_port *uart = to_men_z135(port);
 
+	if (uart->automode)
+		men_z135_disable_ms(port);
+
 	men_z135_handle_tx(uart);
 }
 
@@ -584,6 +633,9 @@
 
 	iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
 
+	if (rx_timeout)
+		iowrite32(rx_timeout, port->membase + MEN_Z135_TIMEOUT);
+
 	return 0;
 }
 
@@ -603,6 +655,7 @@
 				struct ktermios *termios,
 				struct ktermios *old)
 {
+	struct men_z135_port *uart = to_men_z135(port);
 	unsigned int baud;
 	u32 conf_reg;
 	u32 bd_reg;
@@ -643,6 +696,16 @@
 	} else
 		lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
 
+	conf_reg |= MEN_Z135_IER_MSIEN;
+	if (termios->c_cflag & CRTSCTS) {
+		conf_reg |= MEN_Z135_MCR_RCFC;
+		uart->automode = true;
+		termios->c_cflag &= ~CLOCAL;
+	} else {
+		conf_reg &= ~MEN_Z135_MCR_RCFC;
+		uart->automode = false;
+	}
+
 	termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
 
 	conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
deleted file mode 100644
index 77239d5..0000000
--- a/drivers/tty/serial/mrst_max3110.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- *  mrst_max3110.c - spi uart protocol driver for Maxim 3110
- *
- * Copyright (c) 2008-2010, Intel Corporation.
- *
- * 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.
- *
- * 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.
- */
-
-/*
- * Note:
- * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
- *    1 word. If SPI master controller doesn't support sclk frequency change,
- *    then the char need be sent out one by one with some delay
- *
- * 2. Currently only RX available interrupt is used, no need for waiting TXE
- *    interrupt for a low speed UART device
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-#include <linux/kthread.h>
-#include <linux/spi/spi.h>
-#include <linux/pm.h>
-
-#include "mrst_max3110.h"
-
-#define UART_TX_NEEDED 1
-#define CON_TX_NEEDED  2
-#define BIT_IRQ_PENDING    3
-
-struct uart_max3110 {
-	struct uart_port port;
-	struct spi_device *spi;
-	char name[SPI_NAME_SIZE];
-
-	wait_queue_head_t wq;
-	struct task_struct *main_thread;
-	struct task_struct *read_thread;
-	struct mutex thread_mutex;
-	struct mutex io_mutex;
-
-	u32 baud;
-	u16 cur_conf;
-	u8 clock;
-	u8 parity, word_7bits;
-	u16 irq;
-
-	unsigned long uart_flags;
-
-	/* console related */
-	struct circ_buf con_xmit;
-};
-
-/* global data structure, may need be removed */
-static struct uart_max3110 *pmax;
-
-static int receive_chars(struct uart_max3110 *max,
-				unsigned short *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max);
-static void max3110_con_receive(struct uart_max3110 *max);
-
-static int max3110_write_then_read(struct uart_max3110 *max,
-		const void *txbuf, void *rxbuf, unsigned len, int always_fast)
-{
-	struct spi_device *spi = max->spi;
-	struct spi_message	message;
-	struct spi_transfer	x;
-	int ret;
-
-	mutex_lock(&max->io_mutex);
-	spi_message_init(&message);
-	memset(&x, 0, sizeof x);
-	x.len = len;
-	x.tx_buf = txbuf;
-	x.rx_buf = rxbuf;
-	spi_message_add_tail(&x, &message);
-
-	if (always_fast)
-		x.speed_hz = spi->max_speed_hz;
-	else if (max->baud)
-		x.speed_hz = max->baud;
-
-	/* Do the i/o */
-	ret = spi_sync(spi, &message);
-	mutex_unlock(&max->io_mutex);
-	return ret;
-}
-
-/* Write a 16b word to the device */
-static int max3110_out(struct uart_max3110 *max, const u16 out)
-{
-	void *buf;
-	u16 *obuf, *ibuf;
-	int ret;
-
-	buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
-	if (!buf)
-		return -ENOMEM;
-
-	obuf = buf;
-	ibuf = buf + 4;
-	*obuf = out;
-	ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
-	if (ret) {
-		pr_warn("%s: get err msg %d when sending 0x%x\n",
-			__func__, ret, out);
-		goto exit;
-	}
-
-	receive_chars(max, ibuf, 1);
-
-exit:
-	kfree(buf);
-	return ret;
-}
-
-/*
- * This is usually used to read data from SPIC RX FIFO, which doesn't
- * need any delay like flushing character out.
- *
- * Return how many valide bytes are read back
- */
-static int max3110_read_multi(struct uart_max3110 *max)
-{
-	void *buf;
-	u16 *obuf, *ibuf;
-	int ret, blen;
-
-	blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
-	buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
-	if (!buf)
-		return 0;
-
-	/* tx/rx always have the same length */
-	obuf = buf;
-	ibuf = buf + blen;
-
-	if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
-		kfree(buf);
-		return 0;
-	}
-
-	ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
-
-	kfree(buf);
-	return ret;
-}
-
-static void serial_m3110_con_putchar(struct uart_port *port, int ch)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-	struct circ_buf *xmit = &max->con_xmit;
-
-	if (uart_circ_chars_free(xmit)) {
-		xmit->buf[xmit->head] = (char)ch;
-		xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
-	}
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- *	The console_lock must be held when we get here.
- */
-static void serial_m3110_con_write(struct console *co,
-				const char *s, unsigned int count)
-{
-	if (!pmax)
-		return;
-
-	uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
-
-	if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-		wake_up(&pmax->wq);
-}
-
-static int __init
-serial_m3110_con_setup(struct console *co, char *options)
-{
-	struct uart_max3110 *max = pmax;
-	int baud = 115200;
-	int bits = 8;
-	int parity = 'n';
-	int flow = 'n';
-
-	pr_info("setting up console\n");
-
-	if (co->index == -1)
-		co->index = 0;
-
-	if (!max) {
-		pr_err("pmax is NULL, return\n");
-		return -ENODEV;
-	}
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-	return uart_set_options(&max->port, co, baud, parity, bits, flow);
-}
-
-static struct tty_driver *serial_m3110_con_device(struct console *co,
-							int *index)
-{
-	struct uart_driver *p = co->data;
-	*index = co->index;
-	return p->tty_driver;
-}
-
-static struct uart_driver serial_m3110_reg;
-static struct console serial_m3110_console = {
-	.name		= "ttyS",
-	.write		= serial_m3110_con_write,
-	.device		= serial_m3110_con_device,
-	.setup		= serial_m3110_con_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &serial_m3110_reg,
-};
-
-static unsigned int serial_m3110_tx_empty(struct uart_port *port)
-{
-	return 1;
-}
-
-static void serial_m3110_stop_tx(struct uart_port *port)
-{
-	return;
-}
-
-/* stop_rx will be called in spin_lock env */
-static void serial_m3110_stop_rx(struct uart_port *port)
-{
-	return;
-}
-
-#define WORDS_PER_XFER	128
-static void send_circ_buf(struct uart_max3110 *max,
-				struct circ_buf *xmit)
-{
-	void *buf;
-	u16 *obuf, *ibuf;
-	int i, len, blen, dma_size, left, ret = 0;
-
-
-	dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
-	buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
-	if (!buf)
-		return;
-	obuf = buf;
-	ibuf = buf + dma_size/2;
-
-	while (!uart_circ_empty(xmit)) {
-		left = uart_circ_chars_pending(xmit);
-		while (left) {
-			len = min(left, WORDS_PER_XFER);
-			blen = len * sizeof(u16);
-			memset(ibuf, 0, blen);
-
-			for (i = 0; i < len; i++) {
-				obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
-				xmit->tail = (xmit->tail + 1) &
-						(UART_XMIT_SIZE - 1);
-			}
-
-			/* Fail to send msg to console is not very critical */
-
-			ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
-			if (ret)
-				pr_warn("%s: get err msg %d\n", __func__, ret);
-
-			receive_chars(max, ibuf, len);
-
-			max->port.icount.tx += len;
-			left -= len;
-		}
-	}
-
-	kfree(buf);
-}
-
-static void transmit_char(struct uart_max3110 *max)
-{
-	struct uart_port *port = &max->port;
-	struct circ_buf *xmit = &port->state->xmit;
-
-	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-		return;
-
-	send_circ_buf(max, xmit);
-
-	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(port);
-
-	if (uart_circ_empty(xmit))
-		serial_m3110_stop_tx(port);
-}
-
-/*
- * This will be called by uart_write() and tty_write, can't
- * go to sleep
- */
-static void serial_m3110_start_tx(struct uart_port *port)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-
-	if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-		wake_up(&max->wq);
-}
-
-static int
-receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
-{
-	struct uart_port *port = &max->port;
-	struct tty_port *tport;
-	char buf[M3110_RX_FIFO_DEPTH];
-	int r, w, usable;
-
-	/* If uart is not opened, just return */
-	if (!port->state)
-		return 0;
-
-	tport = &port->state->port;
-
-	for (r = 0, w = 0; r < len; r++) {
-		if (str[r] & MAX3110_BREAK &&
-		    uart_handle_break(port))
-			continue;
-
-		if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
-			if (uart_handle_sysrq_char(port, str[r] & 0xff))
-				continue;
-
-			buf[w++] = str[r] & 0xff;
-		}
-	}
-
-	if (!w)
-		return 0;
-
-	for (r = 0; w; r += usable, w -= usable) {
-		usable = tty_buffer_request_room(tport, w);
-		if (usable) {
-			tty_insert_flip_string(tport, buf + r, usable);
-			port->icount.rx += usable;
-		}
-	}
-	tty_flip_buffer_push(tport);
-
-	return r;
-}
-
-/*
- * This routine will be used in read_thread or RX IRQ handling,
- * it will first do one round buffer read(8 words), if there is some
- * valid RX data, will try to read 5 more rounds till all data
- * is read out.
- *
- * Use stack space as data buffer to save some system load, and chose
- * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
- * receiving bulk data, a much bigger buffer may cause stack overflow
- */
-static void max3110_con_receive(struct uart_max3110 *max)
-{
-	int loop = 1, num;
-
-	do {
-		num = max3110_read_multi(max);
-
-		if (num) {
-			loop = 5;
-		}
-	} while (--loop);
-}
-
-static int max3110_main_thread(void *_max)
-{
-	struct uart_max3110 *max = _max;
-	wait_queue_head_t *wq = &max->wq;
-	int ret = 0;
-	struct circ_buf *xmit = &max->con_xmit;
-
-	pr_info("start main thread\n");
-
-	do {
-		wait_event_interruptible(*wq,
-				max->uart_flags || kthread_should_stop());
-
-		mutex_lock(&max->thread_mutex);
-
-		if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
-			max3110_con_receive(max);
-
-		/* first handle console output */
-		if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
-			send_circ_buf(max, xmit);
-
-		/* handle uart output */
-		if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
-			transmit_char(max);
-
-		mutex_unlock(&max->thread_mutex);
-
-	} while (!kthread_should_stop());
-
-	return ret;
-}
-
-static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
-{
-	struct uart_max3110 *max = dev_id;
-
-	/* max3110's irq is a falling edge, not level triggered,
-	 * so no need to disable the irq */
-
-	if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-		wake_up(&max->wq);
-
-	return IRQ_HANDLED;
-}
-
-/* if don't use RX IRQ, then need a thread to polling read */
-static int max3110_read_thread(void *_max)
-{
-	struct uart_max3110 *max = _max;
-
-	pr_info("start read thread\n");
-	do {
-		/*
-		 * If can't acquire the mutex, it means the main thread
-		 * is running which will also perform the rx job
-		 */
-		if (mutex_trylock(&max->thread_mutex)) {
-			max3110_con_receive(max);
-			mutex_unlock(&max->thread_mutex);
-		}
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
-	} while (!kthread_should_stop());
-
-	return 0;
-}
-
-static int serial_m3110_startup(struct uart_port *port)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-	u16 config = 0;
-	int ret = 0;
-
-	if (port->line != 0) {
-		pr_err("uart port startup failed\n");
-		return -1;
-	}
-
-	/* Disable all IRQ and config it to 115200, 8n1 */
-	config = WC_TAG | WC_FIFO_ENABLE
-			| WC_1_STOPBITS
-			| WC_8BIT_WORD
-			| WC_BAUD_DR2;
-
-	/* as we use thread to handle tx/rx, need set low latency */
-	port->state->port.low_latency = 1;
-
-	if (max->irq) {
-		/* Enable RX IRQ only */
-		config |= WC_RXA_IRQ_ENABLE;
-	} else {
-		/* If IRQ is disabled, start a read thread for input data */
-		max->read_thread =
-			kthread_run(max3110_read_thread, max, "max3110_read");
-		if (IS_ERR(max->read_thread)) {
-			ret = PTR_ERR(max->read_thread);
-			max->read_thread = NULL;
-			pr_err("Can't create read thread!\n");
-			return ret;
-		}
-	}
-
-	ret = max3110_out(max, config);
-	if (ret) {
-		if (max->read_thread)
-			kthread_stop(max->read_thread);
-		max->read_thread = NULL;
-		return ret;
-	}
-
-	max->cur_conf = config;
-	return 0;
-}
-
-static void serial_m3110_shutdown(struct uart_port *port)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-	u16 config;
-
-	if (max->read_thread) {
-		kthread_stop(max->read_thread);
-		max->read_thread = NULL;
-	}
-
-	/* Disable interrupts from this port */
-	config = WC_TAG | WC_SW_SHDI;
-	max3110_out(max, config);
-}
-
-static void serial_m3110_release_port(struct uart_port *port)
-{
-}
-
-static int serial_m3110_request_port(struct uart_port *port)
-{
-	return 0;
-}
-
-static void serial_m3110_config_port(struct uart_port *port, int flags)
-{
-	port->type = PORT_MAX3100;
-}
-
-static int
-serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-	/* we don't want the core code to modify any port params */
-	return -EINVAL;
-}
-
-
-static const char *serial_m3110_type(struct uart_port *port)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-	return max->name;
-}
-
-static void
-serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
-		       struct ktermios *old)
-{
-	struct uart_max3110 *max =
-		container_of(port, struct uart_max3110, port);
-	unsigned char cval;
-	unsigned int baud, parity = 0;
-	int clk_div = -1;
-	u16 new_conf = max->cur_conf;
-
-	switch (termios->c_cflag & CSIZE) {
-	case CS7:
-		cval = UART_LCR_WLEN7;
-		new_conf |= WC_7BIT_WORD;
-		break;
-	default:
-		/* We only support CS7 & CS8 */
-		termios->c_cflag &= ~CSIZE;
-		termios->c_cflag |= CS8;
-	case CS8:
-		cval = UART_LCR_WLEN8;
-		new_conf |= WC_8BIT_WORD;
-		break;
-	}
-
-	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-
-	/* First calc the div for 1.8MHZ clock case */
-	switch (baud) {
-	case 300:
-		clk_div = WC_BAUD_DR384;
-		break;
-	case 600:
-		clk_div = WC_BAUD_DR192;
-		break;
-	case 1200:
-		clk_div = WC_BAUD_DR96;
-		break;
-	case 2400:
-		clk_div = WC_BAUD_DR48;
-		break;
-	case 4800:
-		clk_div = WC_BAUD_DR24;
-		break;
-	case 9600:
-		clk_div = WC_BAUD_DR12;
-		break;
-	case 19200:
-		clk_div = WC_BAUD_DR6;
-		break;
-	case 38400:
-		clk_div = WC_BAUD_DR3;
-		break;
-	case 57600:
-		clk_div = WC_BAUD_DR2;
-		break;
-	case 115200:
-		clk_div = WC_BAUD_DR1;
-		break;
-	case 230400:
-		if (max->clock & MAX3110_HIGH_CLK)
-			break;
-	default:
-		/* Pick the previous baud rate */
-		baud = max->baud;
-		clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
-		tty_termios_encode_baud_rate(termios, baud, baud);
-	}
-
-	if (max->clock & MAX3110_HIGH_CLK) {
-		clk_div += 1;
-		/* High clk version max3110 doesn't support B300 */
-		if (baud == 300) {
-			baud = 600;
-			clk_div = WC_BAUD_DR384;
-		}
-		if (baud == 230400)
-			clk_div = WC_BAUD_DR1;
-		tty_termios_encode_baud_rate(termios, baud, baud);
-	}
-
-	new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
-
-	if (unlikely(termios->c_cflag & CMSPAR))
-		termios->c_cflag &= ~CMSPAR;
-
-	if (termios->c_cflag & CSTOPB)
-		new_conf |= WC_2_STOPBITS;
-	else
-		new_conf &= ~WC_2_STOPBITS;
-
-	if (termios->c_cflag & PARENB) {
-		new_conf |= WC_PARITY_ENABLE;
-		parity |= UART_LCR_PARITY;
-	} else
-		new_conf &= ~WC_PARITY_ENABLE;
-
-	if (!(termios->c_cflag & PARODD))
-		parity |= UART_LCR_EPAR;
-	max->parity = parity;
-
-	uart_update_timeout(port, termios->c_cflag, baud);
-
-	new_conf |= WC_TAG;
-	if (new_conf != max->cur_conf) {
-		if (!max3110_out(max, new_conf)) {
-			max->cur_conf = new_conf;
-			max->baud = baud;
-		}
-	}
-}
-
-/* Don't handle hw handshaking */
-static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
-{
-	return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
-}
-
-static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void serial_m3110_pm(struct uart_port *port, unsigned int state,
-			unsigned int oldstate)
-{
-}
-
-static struct uart_ops serial_m3110_ops = {
-	.tx_empty	= serial_m3110_tx_empty,
-	.set_mctrl	= serial_m3110_set_mctrl,
-	.get_mctrl	= serial_m3110_get_mctrl,
-	.stop_tx	= serial_m3110_stop_tx,
-	.start_tx	= serial_m3110_start_tx,
-	.stop_rx	= serial_m3110_stop_rx,
-	.break_ctl	= serial_m3110_break_ctl,
-	.startup	= serial_m3110_startup,
-	.shutdown	= serial_m3110_shutdown,
-	.set_termios	= serial_m3110_set_termios,
-	.pm		= serial_m3110_pm,
-	.type		= serial_m3110_type,
-	.release_port	= serial_m3110_release_port,
-	.request_port	= serial_m3110_request_port,
-	.config_port	= serial_m3110_config_port,
-	.verify_port	= serial_m3110_verify_port,
-};
-
-static struct uart_driver serial_m3110_reg = {
-	.owner		= THIS_MODULE,
-	.driver_name	= "MRST serial",
-	.dev_name	= "ttyS",
-	.major		= TTY_MAJOR,
-	.minor		= 64,
-	.nr		= 1,
-	.cons		= &serial_m3110_console,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int serial_m3110_suspend(struct device *dev)
-{
-	struct spi_device *spi = to_spi_device(dev);
-	struct uart_max3110 *max = spi_get_drvdata(spi);
-
-	if (max->irq > 0)
-		disable_irq(max->irq);
-	uart_suspend_port(&serial_m3110_reg, &max->port);
-	max3110_out(max, max->cur_conf | WC_SW_SHDI);
-	return 0;
-}
-
-static int serial_m3110_resume(struct device *dev)
-{
-	struct spi_device *spi = to_spi_device(dev);
-	struct uart_max3110 *max = spi_get_drvdata(spi);
-
-	max3110_out(max, max->cur_conf);
-	uart_resume_port(&serial_m3110_reg, &max->port);
-	if (max->irq > 0)
-		enable_irq(max->irq);
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
-			serial_m3110_resume);
-#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
-
-#else
-#define SERIAL_M3110_PM_OPS NULL
-#endif
-
-static int serial_m3110_probe(struct spi_device *spi)
-{
-	struct uart_max3110 *max;
-	void *buffer;
-	u16 res;
-	int ret = 0;
-
-	max = kzalloc(sizeof(*max), GFP_KERNEL);
-	if (!max)
-		return -ENOMEM;
-
-	/* Set spi info */
-	spi->bits_per_word = 16;
-	max->clock = MAX3110_HIGH_CLK;
-
-	spi_setup(spi);
-
-	max->port.type = PORT_MAX3100;
-	max->port.fifosize = 2;		/* Only have 16b buffer */
-	max->port.ops = &serial_m3110_ops;
-	max->port.line = 0;
-	max->port.dev = &spi->dev;
-	max->port.uartclk = 115200;
-
-	max->spi = spi;
-	strcpy(max->name, spi->modalias);
-	max->irq = (u16)spi->irq;
-
-	mutex_init(&max->thread_mutex);
-	mutex_init(&max->io_mutex);
-
-	max->word_7bits = 0;
-	max->parity = 0;
-	max->baud = 0;
-
-	max->cur_conf = 0;
-	max->uart_flags = 0;
-
-	/* Check if reading configuration register returns something sane */
-
-	res = RC_TAG;
-	ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
-	if (ret < 0 || res == 0 || res == 0xffff) {
-		dev_dbg(&spi->dev, "MAX3111 deemed not present (conf reg %04x)",
-									res);
-		ret = -ENODEV;
-		goto err_get_page;
-	}
-
-	buffer = (void *)__get_free_page(GFP_KERNEL);
-	if (!buffer) {
-		ret = -ENOMEM;
-		goto err_get_page;
-	}
-	max->con_xmit.buf = buffer;
-	max->con_xmit.head = 0;
-	max->con_xmit.tail = 0;
-
-	init_waitqueue_head(&max->wq);
-
-	max->main_thread = kthread_run(max3110_main_thread,
-					max, "max3110_main");
-	if (IS_ERR(max->main_thread)) {
-		ret = PTR_ERR(max->main_thread);
-		goto err_kthread;
-	}
-
-	if (max->irq) {
-		ret = request_irq(max->irq, serial_m3110_irq,
-				IRQ_TYPE_EDGE_FALLING, "max3110", max);
-		if (ret) {
-			max->irq = 0;
-			dev_warn(&spi->dev,
-			"unable to allocate IRQ, will use polling method\n");
-		}
-	}
-
-	spi_set_drvdata(spi, max);
-	pmax = max;
-
-	/* Give membase a psudo value to pass serial_core's check */
-	max->port.membase = (unsigned char __iomem *)0xff110000;
-	uart_add_one_port(&serial_m3110_reg, &max->port);
-
-	return 0;
-
-err_kthread:
-	free_page((unsigned long)buffer);
-err_get_page:
-	kfree(max);
-	return ret;
-}
-
-static int serial_m3110_remove(struct spi_device *dev)
-{
-	struct uart_max3110 *max = spi_get_drvdata(dev);
-
-	if (!max)
-		return 0;
-
-	uart_remove_one_port(&serial_m3110_reg, &max->port);
-
-	free_page((unsigned long)max->con_xmit.buf);
-
-	if (max->irq)
-		free_irq(max->irq, max);
-
-	if (max->main_thread)
-		kthread_stop(max->main_thread);
-
-	kfree(max);
-	return 0;
-}
-
-static struct spi_driver uart_max3110_driver = {
-	.driver = {
-			.name	= "spi_max3111",
-			.owner	= THIS_MODULE,
-			.pm	= SERIAL_M3110_PM_OPS,
-	},
-	.probe		= serial_m3110_probe,
-	.remove		= serial_m3110_remove,
-};
-
-static int __init serial_m3110_init(void)
-{
-	int ret = 0;
-
-	ret = uart_register_driver(&serial_m3110_reg);
-	if (ret)
-		return ret;
-
-	ret = spi_register_driver(&uart_max3110_driver);
-	if (ret)
-		uart_unregister_driver(&serial_m3110_reg);
-
-	return ret;
-}
-
-static void __exit serial_m3110_exit(void)
-{
-	spi_unregister_driver(&uart_max3110_driver);
-	uart_unregister_driver(&serial_m3110_reg);
-}
-
-module_init(serial_m3110_init);
-module_exit(serial_m3110_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:max3110-uart");
diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h
deleted file mode 100644
index 35af073..0000000
--- a/drivers/tty/serial/mrst_max3110.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _MRST_MAX3110_H
-#define _MRST_MAX3110_H
-
-#define MAX3110_HIGH_CLK	0x1	/* 3.6864 MHZ */
-#define MAX3110_LOW_CLK		0x0	/* 1.8432 MHZ */
-
-/* status bits for all 4 MAX3110 operate modes */
-#define MAX3110_READ_DATA_AVAILABLE	(1 << 15)
-#define MAX3110_WRITE_BUF_EMPTY		(1 << 14)
-#define MAX3110_BREAK			(1 << 10)
-
-#define WC_TAG			(3 << 14)
-#define RC_TAG			(1 << 14)
-#define WD_TAG			(2 << 14)
-#define RD_TAG			(0 << 14)
-
-/* bits def for write configuration */
-#define WC_FIFO_ENABLE_MASK	(1 << 13)
-#define WC_FIFO_ENABLE		(0 << 13)
-
-#define WC_SW_SHDI		(1 << 12)
-
-#define WC_IRQ_MASK		(0xF << 8)
-#define WC_TXE_IRQ_ENABLE	(1 << 11)	/* TX empty irq */
-#define WC_RXA_IRQ_ENABLE	(1 << 10)	/* RX available irq */
-#define WC_PAR_HIGH_IRQ_ENABLE	(1 << 9)
-#define WC_REC_ACT_IRQ_ENABLE	(1 << 8)
-
-#define WC_IRDA_ENABLE		(1 << 7)
-
-#define WC_STOPBITS_MASK	(1 << 6)
-#define WC_2_STOPBITS		(1 << 6)
-#define WC_1_STOPBITS		(0 << 6)
-
-#define WC_PARITY_ENABLE_MASK	(1 << 5)
-#define WC_PARITY_ENABLE	(1 << 5)
-
-#define WC_WORDLEN_MASK		(1 << 4)
-#define WC_7BIT_WORD		(1 << 4)
-#define WC_8BIT_WORD		(0 << 4)
-
-#define WC_BAUD_DIV_MASK	(0xF)
-#define WC_BAUD_DR1		(0x0)
-#define WC_BAUD_DR2		(0x1)
-#define WC_BAUD_DR4		(0x2)
-#define WC_BAUD_DR8		(0x3)
-#define WC_BAUD_DR16		(0x4)
-#define WC_BAUD_DR32		(0x5)
-#define WC_BAUD_DR64		(0x6)
-#define WC_BAUD_DR128		(0x7)
-#define WC_BAUD_DR3		(0x8)
-#define WC_BAUD_DR6		(0x9)
-#define WC_BAUD_DR12		(0xA)
-#define WC_BAUD_DR24		(0xB)
-#define WC_BAUD_DR48		(0xC)
-#define WC_BAUD_DR96		(0xD)
-#define WC_BAUD_DR192		(0xE)
-#define WC_BAUD_DR384		(0xF)
-
-#define M3110_RX_FIFO_DEPTH	8
-#endif
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index c88b522..b73889c 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -920,14 +920,15 @@
 static int __init msm_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port;
-	struct msm_port *msm_port;
-	int baud = 0, flow, bits, parity;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
 
 	if (unlikely(co->index >= UART_NR || co->index < 0))
 		return -ENXIO;
 
 	port = get_port_from_line(co->index);
-	msm_port = UART_TO_MSM(port);
 
 	if (unlikely(!port->membase))
 		return -ENXIO;
@@ -937,23 +938,6 @@
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 
-	bits = 8;
-	parity = 'n';
-	flow = 'n';
-	msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
-		  UART_MR2);	/* 8N1 */
-
-	if (baud < 300 || baud > 115200)
-		baud = 115200;
-	msm_set_baud_rate(port, baud);
-
-	msm_reset(port);
-
-	if (msm_port->is_uartdm) {
-		msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
-		msm_write(port, UART_CR_TX_ENABLE, UART_CR);
-	}
-
 	pr_info("msm_serial: console setup on port #%d\n", port->line);
 
 	return uart_set_options(port, co, baud, parity, bits, flow);
@@ -1142,9 +1126,6 @@
 
 static void __exit msm_serial_exit(void)
 {
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-	unregister_console(&msm_console);
-#endif
 	platform_driver_unregister(&msm_platform_driver);
 	uart_unregister_driver(&msm_uart_driver);
 }
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index ec553f8..d1298b6 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -152,8 +152,6 @@
 	unsigned int mctrl_prev;
 	enum mxs_auart_type devtype;
 
-	unsigned int irq;
-
 	struct clk *clk;
 	struct device *dev;
 
@@ -1228,37 +1226,32 @@
 			of_match_device(mxs_auart_dt_ids, &pdev->dev);
 	struct mxs_auart_port *s;
 	u32 version;
-	int ret = 0;
+	int ret, irq;
 	struct resource *r;
 
-	s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
-	if (!s) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
 
 	ret = serial_mxs_probe_dt(s, pdev);
 	if (ret > 0)
 		s->port.line = pdev->id < 0 ? 0 : pdev->id;
 	else if (ret < 0)
-		goto out_free;
+		return ret;
 
 	if (of_id) {
 		pdev->id_entry = of_id->data;
 		s->devtype = pdev->id_entry->driver_data;
 	}
 
-	s->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(s->clk)) {
-		ret = PTR_ERR(s->clk);
-		goto out_free;
-	}
+	s->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(s->clk))
+		return PTR_ERR(s->clk);
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		ret = -ENXIO;
-		goto out_free_clk;
-	}
+	if (!r)
+		return -ENXIO;
+
 
 	s->port.mapbase = r->start;
 	s->port.membase = ioremap(r->start, resource_size(r));
@@ -1271,11 +1264,15 @@
 
 	s->mctrl_prev = 0;
 
-	s->irq = platform_get_irq(pdev, 0);
-	s->port.irq = s->irq;
-	ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	s->port.irq = irq;
+	ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
+			       dev_name(&pdev->dev), s);
 	if (ret)
-		goto out_free_clk;
+		return ret;
 
 	platform_set_drvdata(pdev, s);
 
@@ -1288,7 +1285,7 @@
 	 */
 	ret = mxs_auart_request_gpio_irq(s);
 	if (ret)
-		goto out_free_irq;
+		return ret;
 
 	auart_port[s->port.line] = s;
 
@@ -1307,14 +1304,7 @@
 
 out_free_gpio_irq:
 	mxs_auart_free_gpio_irq(s);
-out_free_irq:
 	auart_port[pdev->id] = NULL;
-	free_irq(s->irq, s);
-out_free_clk:
-	clk_put(s->clk);
-out_free:
-	kfree(s);
-out:
 	return ret;
 }
 
@@ -1323,13 +1313,8 @@
 	struct mxs_auart_port *s = platform_get_drvdata(pdev);
 
 	uart_remove_one_port(&auart_driver, &s->port);
-
 	auart_port[pdev->id] = NULL;
-
 	mxs_auart_free_gpio_irq(s);
-	clk_put(s->clk);
-	free_irq(s->irq, s);
-	kfree(s);
 
 	return 0;
 }
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 64f1bab..7ff61e2 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -102,6 +102,11 @@
 	if (of_property_read_u32(np, "fifo-size", &prop) == 0)
 		port->fifosize = prop;
 
+	/* Check for a fixed line number */
+	ret = of_alias_get_id(np, "serial");
+	if (ret >= 0)
+		port->line = ret;
+
 	port->irq = irq_of_parse_and_map(np, 0);
 	port->iotype = UPIO_MEM;
 	if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
@@ -128,6 +133,10 @@
 	if (of_find_property(np, "no-loopback-test", NULL))
 		port->flags |= UPF_SKIP_TEST;
 
+	ret = of_alias_get_id(np, "serial");
+	if (ret >= 0)
+		port->line = ret;
+
 	port->dev = &ofdev->dev;
 
 	switch (type) {
@@ -331,6 +340,10 @@
 		.data = (void *)PORT_ALTR_16550_F64, },
 	{ .compatible = "altr,16550-FIFO128",
 		.data = (void *)PORT_ALTR_16550_F128, },
+	{ .compatible = "mrvl,mmp-uart",
+		.data = (void *)PORT_XSCALE, },
+	{ .compatible = "mrvl,pxa-uart",
+		.data = (void *)PORT_XSCALE, },
 #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
 	{ .compatible = "ibm,qpace-nwp-serial",
 		.data = (void *)PORT_NWPSERIAL, },
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 2e1073d..10256fa 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -63,7 +63,7 @@
 #define UART_ERRATA_i202_MDR1_ACCESS	BIT(0)
 #define UART_ERRATA_i291_DMA_FORCEIDLE	BIT(1)
 
-#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
+#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */
 
 /* SCR register bitmasks */
 #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK		(1 << 7)
@@ -93,7 +93,7 @@
 /* WER = 0x7F
  * Enable module level wakeup in WER reg
  */
-#define OMAP_UART_WER_MOD_WKUP	0X7F
+#define OMAP_UART_WER_MOD_WKUP	0x7F
 
 /* Enable XON/XOFF flow control on output */
 #define OMAP_UART_SW_TX		0x08
@@ -114,7 +114,7 @@
 	dma_addr_t		tx_buf_dma_phys;
 	unsigned int		uart_base;
 	/*
-	 * Buffer for rx dma.It is not required for tx because the buffer
+	 * Buffer for rx dma. It is not required for tx because the buffer
 	 * comes from port structure.
 	 */
 	unsigned char		*rx_buf;
@@ -151,7 +151,7 @@
 	int			use_dma;
 	/*
 	 * Some bits in registers are cleared on a read, so they must
-	 * be saved whenever the register is read but the bits will not
+	 * be saved whenever the register is read, but the bits will not
 	 * be immediately processed.
 	 */
 	unsigned int		lsr_break_flag;
@@ -681,7 +681,7 @@
 static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	struct uart_omap_port *up = to_uart_omap_port(port);
-	unsigned char mcr = 0, old_mcr;
+	unsigned char mcr = 0, old_mcr, lcr;
 
 	dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
 	if (mctrl & TIOCM_RTS)
@@ -701,6 +701,17 @@
 		     UART_MCR_DTR | UART_MCR_RTS);
 	up->mcr = old_mcr | mcr;
 	serial_out(up, UART_MCR, up->mcr);
+
+	/* Turn off autoRTS if RTS is lowered; restore autoRTS if RTS raised */
+	lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+	if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+		up->efr |= UART_EFR_RTS;
+	else
+		up->efr &= UART_EFR_RTS;
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, lcr);
+
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
 }
@@ -756,8 +767,6 @@
 	 * (they will be reenabled in set_termios())
 	 */
 	serial_omap_clear_fifos(up);
-	/* For Hardware flow control */
-	serial_out(up, UART_MCR, UART_MCR_RTS);
 
 	/*
 	 * Clear the interrupt registers.
@@ -1053,12 +1062,12 @@
 
 	serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
 
-	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
-		/* Enable AUTORTS and AUTOCTS */
-		up->efr |= UART_EFR_CTS | UART_EFR_RTS;
+	up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
-		/* Ensure MCR RTS is asserted */
-		up->mcr |= UART_MCR_RTS;
+	if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+		/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
+		up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+		up->efr |= UART_EFR_CTS;
 	} else {
 		/* Disable AUTORTS and AUTOCTS */
 		up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
@@ -1081,8 +1090,10 @@
 		 * Enable XON/XOFF flow control on output.
 		 * Transmit XON1, XOFF1
 		 */
-		if (termios->c_iflag & IXOFF)
+		if (termios->c_iflag & IXOFF) {
+			up->port.status |= UPSTAT_AUTOXOFF;
 			up->efr |= OMAP_UART_SW_TX;
+		}
 
 		/*
 		 * IXANY Flag:
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 107e807..af821a9 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -28,6 +28,9 @@
 #define SUPPORT_SYSRQ
 #endif
 
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
@@ -78,6 +81,10 @@
 #define S3C24XX_SERIAL_MAJOR	204
 #define S3C24XX_SERIAL_MINOR	64
 
+#define S3C24XX_TX_PIO			1
+#define S3C24XX_TX_DMA			2
+#define S3C24XX_RX_PIO			1
+#define S3C24XX_RX_DMA			2
 /* macros to change one thing to another */
 
 #define tx_enabled(port) ((port)->unused[0])
@@ -154,39 +161,272 @@
 static void s3c24xx_serial_stop_tx(struct uart_port *port)
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct dma_tx_state state;
+	int count;
 
-	if (tx_enabled(port)) {
-		if (s3c24xx_serial_has_interrupt_mask(port))
-			__set_bit(S3C64XX_UINTM_TXD,
-				portaddrl(port, S3C64XX_UINTM));
-		else
-			disable_irq_nosync(ourport->tx_irq);
-		tx_enabled(port) = 0;
-		if (port->flags & UPF_CONS_FLOW)
-			s3c24xx_serial_rx_enable(port);
+	if (!tx_enabled(port))
+		return;
+
+	if (s3c24xx_serial_has_interrupt_mask(port))
+		__set_bit(S3C64XX_UINTM_TXD,
+			portaddrl(port, S3C64XX_UINTM));
+	else
+		disable_irq_nosync(ourport->tx_irq);
+
+	if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
+		dmaengine_pause(dma->tx_chan);
+		dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+		dmaengine_terminate_all(dma->tx_chan);
+		dma_sync_single_for_cpu(ourport->port.dev,
+			dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+		async_tx_ack(dma->tx_desc);
+		count = dma->tx_bytes_requested - state.residue;
+		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+		port->icount.tx += count;
 	}
+
+	tx_enabled(port) = 0;
+	ourport->tx_in_progress = 0;
+
+	if (port->flags & UPF_CONS_FLOW)
+		s3c24xx_serial_rx_enable(port);
+
+	ourport->tx_mode = 0;
 }
 
-static void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
+static void s3c24xx_serial_tx_dma_complete(void *args)
+{
+	struct s3c24xx_uart_port *ourport = args;
+	struct uart_port *port = &ourport->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	struct dma_tx_state state;
+	unsigned long flags;
+	int count;
+
+
+	dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+	count = dma->tx_bytes_requested - state.residue;
+	async_tx_ack(dma->tx_desc);
+
+	dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
+				dma->tx_size, DMA_TO_DEVICE);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+	port->icount.tx += count;
+	ourport->tx_in_progress = 0;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	s3c24xx_serial_start_next_tx(ourport);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	u32 ucon;
+
+	/* Mask Tx interrupt */
+	if (s3c24xx_serial_has_interrupt_mask(port))
+		__set_bit(S3C64XX_UINTM_TXD,
+			  portaddrl(port, S3C64XX_UINTM));
+	else
+		disable_irq_nosync(ourport->tx_irq);
+
+	/* Enable tx dma mode */
+	ucon = rd_regl(port, S3C2410_UCON);
+	ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
+	ucon |= (dma_get_cache_alignment() >= 16) ?
+		S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+	ucon |= S3C64XX_UCON_TXMODE_DMA;
+	wr_regl(port,  S3C2410_UCON, ucon);
+
+	ourport->tx_mode = S3C24XX_TX_DMA;
+}
+
+static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	u32 ucon, ufcon;
+
+	/* Set ufcon txtrig */
+	ourport->tx_in_progress = S3C24XX_TX_PIO;
+	ufcon = rd_regl(port, S3C2410_UFCON);
+	wr_regl(port,  S3C2410_UFCON, ufcon);
+
+	/* Enable tx pio mode */
+	ucon = rd_regl(port, S3C2410_UCON);
+	ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
+	ucon |= S3C64XX_UCON_TXMODE_CPU;
+	wr_regl(port,  S3C2410_UCON, ucon);
+
+	/* Unmask Tx interrupt */
+	if (s3c24xx_serial_has_interrupt_mask(port))
+		__clear_bit(S3C64XX_UINTM_TXD,
+			    portaddrl(port, S3C64XX_UINTM));
+	else
+		enable_irq(ourport->tx_irq);
+
+	ourport->tx_mode = S3C24XX_TX_PIO;
+}
+
+static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+	if (ourport->tx_mode != S3C24XX_TX_PIO)
+		enable_tx_pio(ourport);
+}
+
+static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
+				      unsigned int count)
+{
+	struct uart_port *port = &ourport->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+
+
+	if (ourport->tx_mode != S3C24XX_TX_DMA)
+		enable_tx_dma(ourport);
+
+	while (xmit->tail & (dma_get_cache_alignment() - 1)) {
+		if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+			return 0;
+		wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		count--;
+	}
+
+	dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
+	dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
+
+	dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
+				dma->tx_size, DMA_TO_DEVICE);
+
+	dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
+				dma->tx_transfer_addr, dma->tx_size,
+				DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+	if (!dma->tx_desc) {
+		dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
+		return -EIO;
+	}
+
+	dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
+	dma->tx_desc->callback_param = ourport;
+	dma->tx_bytes_requested = dma->tx_size;
+
+	ourport->tx_in_progress = S3C24XX_TX_DMA;
+	dma->tx_cookie = dmaengine_submit(dma->tx_desc);
+	dma_async_issue_pending(dma->tx_chan);
+	return 0;
+}
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long count;
+
+	/* Get data size up to the end of buffer */
+	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+	if (!count) {
+		s3c24xx_serial_stop_tx(port);
+		return;
+	}
+
+	if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize)
+		s3c24xx_serial_start_tx_pio(ourport);
+	else
+		s3c24xx_serial_start_tx_dma(ourport, count);
+}
+
+void s3c24xx_serial_start_tx(struct uart_port *port)
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	struct circ_buf *xmit = &port->state->xmit;
 
 	if (!tx_enabled(port)) {
 		if (port->flags & UPF_CONS_FLOW)
 			s3c24xx_serial_rx_disable(port);
 
-		if (s3c24xx_serial_has_interrupt_mask(port))
-			__clear_bit(S3C64XX_UINTM_TXD,
-				portaddrl(port, S3C64XX_UINTM));
-		else
-			enable_irq(ourport->tx_irq);
 		tx_enabled(port) = 1;
+		if (!ourport->dma || !ourport->dma->tx_chan)
+			s3c24xx_serial_start_tx_pio(ourport);
 	}
+
+	if (ourport->dma && ourport->dma->tx_chan) {
+		if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
+			s3c24xx_serial_start_next_tx(ourport);
+	}
+}
+
+static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
+		struct tty_port *tty, int count)
+{
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	int copied;
+
+	if (!count)
+		return;
+
+	dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+				dma->rx_size, DMA_FROM_DEVICE);
+
+	ourport->port.icount.rx += count;
+	if (!tty) {
+		dev_err(ourport->port.dev, "No tty port\n");
+		return;
+	}
+	copied = tty_insert_flip_string(tty,
+			((unsigned char *)(ourport->dma->rx_buf)), count);
+	if (copied != count) {
+		WARN_ON(1);
+		dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
+	}
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+				     unsigned long ufstat);
+
+static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	struct tty_port *tty = &port->state->port;
+	unsigned int ch, ufstat;
+	unsigned int count;
+
+	ufstat = rd_regl(port, S3C2410_UFSTAT);
+	count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+
+	if (!count)
+		return;
+
+	while (count-- > 0) {
+		ch = rd_regb(port, S3C2410_URXH);
+
+		ourport->port.icount.rx++;
+		tty_insert_flip_char(tty, ch, TTY_NORMAL);
+	}
+
+	tty_flip_buffer_push(tty);
 }
 
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	struct tty_port *t = &port->state->port;
+	struct dma_tx_state state;
+	enum dma_status dma_status;
+	unsigned int received;
 
 	if (rx_enabled(port)) {
 		dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
@@ -197,6 +437,17 @@
 			disable_irq_nosync(ourport->rx_irq);
 		rx_enabled(port) = 0;
 	}
+	if (dma && dma->rx_chan) {
+		dmaengine_pause(dma->tx_chan);
+		dma_status = dmaengine_tx_status(dma->rx_chan,
+				dma->rx_cookie, &state);
+		if (dma_status == DMA_IN_PROGRESS ||
+			dma_status == DMA_PAUSED) {
+			received = dma->rx_bytes_requested - state.residue;
+			dmaengine_terminate_all(dma->rx_chan);
+			s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+		}
+	}
 }
 
 static inline struct s3c24xx_uart_info
@@ -228,12 +479,157 @@
 	return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
 }
 
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
+static void s3c24xx_serial_rx_dma_complete(void *args)
+{
+	struct s3c24xx_uart_port *ourport = args;
+	struct uart_port *port = &ourport->port;
+
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	struct tty_port *t = &port->state->port;
+	struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+
+	struct dma_tx_state state;
+	unsigned long flags;
+	int received;
+
+	dmaengine_tx_status(dma->rx_chan,  dma->rx_cookie, &state);
+	received  = dma->rx_bytes_requested - state.residue;
+	async_tx_ack(dma->rx_desc);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (received)
+		s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+	if (tty) {
+		tty_flip_buffer_push(t);
+		tty_kref_put(tty);
+	}
+
+	s3c64xx_start_rx_dma(ourport);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+
+	dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
+				dma->rx_size, DMA_FROM_DEVICE);
+
+	dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
+				dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
+				DMA_PREP_INTERRUPT);
+	if (!dma->rx_desc) {
+		dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
+		return;
+	}
+
+	dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
+	dma->rx_desc->callback_param = ourport;
+	dma->rx_bytes_requested = dma->rx_size;
+
+	dma->rx_cookie = dmaengine_submit(dma->rx_desc);
+	dma_async_issue_pending(dma->rx_chan);
+}
 
 /* ? - where has parity gone?? */
 #define S3C2410_UERSTAT_PARITY (0x1000)
 
-static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id)
+static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	unsigned int ucon;
+
+	/* set Rx mode to DMA mode */
+	ucon = rd_regl(port, S3C2410_UCON);
+	ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
+			S3C64XX_UCON_TIMEOUT_MASK |
+			S3C64XX_UCON_EMPTYINT_EN |
+			S3C64XX_UCON_DMASUS_EN |
+			S3C64XX_UCON_TIMEOUT_EN |
+			S3C64XX_UCON_RXMODE_MASK);
+	ucon |= S3C64XX_UCON_RXBURST_16 |
+			0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+			S3C64XX_UCON_EMPTYINT_EN |
+			S3C64XX_UCON_TIMEOUT_EN |
+			S3C64XX_UCON_RXMODE_DMA;
+	wr_regl(port, S3C2410_UCON, ucon);
+
+	ourport->rx_mode = S3C24XX_RX_DMA;
+}
+
+static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
+{
+	struct uart_port *port = &ourport->port;
+	unsigned int ucon;
+
+	/* set Rx mode to DMA mode */
+	ucon = rd_regl(port, S3C2410_UCON);
+	ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+			S3C64XX_UCON_EMPTYINT_EN |
+			S3C64XX_UCON_DMASUS_EN |
+			S3C64XX_UCON_TIMEOUT_EN |
+			S3C64XX_UCON_RXMODE_MASK);
+	ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+			S3C64XX_UCON_TIMEOUT_EN |
+			S3C64XX_UCON_RXMODE_CPU;
+	wr_regl(port, S3C2410_UCON, ucon);
+
+	ourport->rx_mode = S3C24XX_RX_PIO;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+{
+	unsigned int utrstat, ufstat, received;
+	struct s3c24xx_uart_port *ourport = dev_id;
+	struct uart_port *port = &ourport->port;
+	struct s3c24xx_uart_dma *dma = ourport->dma;
+	struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+	struct tty_port *t = &port->state->port;
+	unsigned long flags;
+	struct dma_tx_state state;
+
+	utrstat = rd_regl(port, S3C2410_UTRSTAT);
+	ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
+		s3c64xx_start_rx_dma(ourport);
+		if (ourport->rx_mode == S3C24XX_RX_PIO)
+			enable_rx_dma(ourport);
+		goto finish;
+	}
+
+	if (ourport->rx_mode == S3C24XX_RX_DMA) {
+		dmaengine_pause(dma->rx_chan);
+		dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
+		dmaengine_terminate_all(dma->rx_chan);
+		received = dma->rx_bytes_requested - state.residue;
+		s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+		enable_rx_pio(ourport);
+	}
+
+	uart_rx_drain_fifo(ourport);
+
+	if (tty) {
+		tty_flip_buffer_push(t);
+		tty_kref_put(tty);
+	}
+
+	wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
+
+finish:
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
 {
 	struct s3c24xx_uart_port *ourport = dev_id;
 	struct uart_port *port = &ourport->port;
@@ -324,16 +720,33 @@
 	return IRQ_HANDLED;
 }
 
+
+static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+	struct s3c24xx_uart_port *ourport = dev_id;
+
+	if (ourport->dma && ourport->dma->rx_chan)
+		return s3c24xx_serial_rx_chars_dma(irq, dev_id);
+	return s3c24xx_serial_rx_chars_pio(irq, dev_id);
+}
+
 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 {
 	struct s3c24xx_uart_port *ourport = id;
 	struct uart_port *port = &ourport->port;
 	struct circ_buf *xmit = &port->state->xmit;
 	unsigned long flags;
-	int count = port->fifosize;
+	int count;
 
 	spin_lock_irqsave(&port->lock, flags);
 
+	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+	if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) {
+		s3c24xx_serial_start_tx_dma(ourport, count);
+		goto out;
+	}
+
 	if (port->x_char) {
 		wr_regb(port, S3C2410_UTXH, port->x_char);
 		port->icount.tx++;
@@ -352,6 +765,7 @@
 
 	/* try and drain the buffer... */
 
+	count = port->fifosize;
 	while (!uart_circ_empty(xmit) && count-- > 0) {
 		if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
 			break;
@@ -453,6 +867,93 @@
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
+static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
+{
+	struct s3c24xx_uart_dma	*dma = p->dma;
+	dma_cap_mask_t mask;
+	unsigned long flags;
+
+	/* Default slave configuration parameters */
+	dma->rx_conf.direction		= DMA_DEV_TO_MEM;
+	dma->rx_conf.src_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma->rx_conf.src_addr		= p->port.mapbase + S3C2410_URXH;
+	dma->rx_conf.src_maxburst	= 16;
+
+	dma->tx_conf.direction		= DMA_MEM_TO_DEV;
+	dma->tx_conf.dst_addr_width	= DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma->tx_conf.dst_addr		= p->port.mapbase + S3C2410_UTXH;
+	if (dma_get_cache_alignment() >= 16)
+		dma->tx_conf.dst_maxburst = 16;
+	else
+		dma->tx_conf.dst_maxburst = 1;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+					dma->rx_param, p->port.dev, "rx");
+	if (!dma->rx_chan)
+		return -ENODEV;
+
+	dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
+
+	dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+					dma->tx_param, p->port.dev, "tx");
+	if (!dma->tx_chan) {
+		dma_release_channel(dma->rx_chan);
+		return -ENODEV;
+	}
+
+	dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
+
+	/* RX buffer */
+	dma->rx_size = PAGE_SIZE;
+
+	dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
+
+	if (!dma->rx_buf) {
+		dma_release_channel(dma->rx_chan);
+		dma_release_channel(dma->tx_chan);
+		return -ENOMEM;
+	}
+
+	dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+				dma->rx_size, DMA_FROM_DEVICE);
+
+	spin_lock_irqsave(&p->port.lock, flags);
+
+	/* TX buffer */
+	dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+				p->port.state->xmit.buf,
+				UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+	spin_unlock_irqrestore(&p->port.lock, flags);
+
+	return 0;
+}
+
+static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
+{
+	struct s3c24xx_uart_dma	*dma = p->dma;
+
+	if (dma->rx_chan) {
+		dmaengine_terminate_all(dma->rx_chan);
+		dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+				dma->rx_size, DMA_FROM_DEVICE);
+		kfree(dma->rx_buf);
+		dma_release_channel(dma->rx_chan);
+		dma->rx_chan = NULL;
+	}
+
+	if (dma->tx_chan) {
+		dmaengine_terminate_all(dma->tx_chan);
+		dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+				UART_XMIT_SIZE, DMA_TO_DEVICE);
+		dma_release_channel(dma->tx_chan);
+		dma->tx_chan = NULL;
+	}
+}
+
 static void s3c24xx_serial_shutdown(struct uart_port *port)
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -478,6 +979,11 @@
 		wr_regl(port, S3C64XX_UINTP, 0xf);
 		wr_regl(port, S3C64XX_UINTM, 0xf);
 	}
+
+	if (ourport->dma)
+		s3c24xx_serial_release_dma(ourport);
+
+	ourport->tx_in_progress = 0;
 }
 
 static int s3c24xx_serial_startup(struct uart_port *port)
@@ -529,12 +1035,21 @@
 static int s3c64xx_serial_startup(struct uart_port *port)
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
+	unsigned long flags;
+	unsigned int ufcon;
 	int ret;
 
 	dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
 	    port, (unsigned long long)port->mapbase, port->membase);
 
 	wr_regl(port, S3C64XX_UINTM, 0xf);
+	if (ourport->dma) {
+		ret = s3c24xx_serial_request_dma(ourport);
+		if (ret < 0) {
+			dev_warn(port->dev, "DMA request failed\n");
+			return ret;
+		}
+	}
 
 	ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
 			  s3c24xx_serial_portname(port), ourport);
@@ -549,8 +1064,20 @@
 	tx_enabled(port) = 0;
 	ourport->tx_claimed = 1;
 
+	spin_lock_irqsave(&port->lock, flags);
+
+	ufcon = rd_regl(port, S3C2410_UFCON);
+	ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX |
+			S5PV210_UFCON_RXTRIG8;
+	wr_regl(port, S3C2410_UFCON, ufcon);
+
+	enable_rx_pio(ourport);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
 	/* Enable Rx Interrupt */
 	__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
+
 	dbg("s3c64xx_serial_startup ok\n");
 	return ret;
 }
@@ -1209,6 +1736,18 @@
 	ret = platform_get_irq(platdev, 1);
 	if (ret > 0)
 		ourport->tx_irq = ret;
+	/*
+	 * DMA is currently supported only on DT platforms, if DMA properties
+	 * are specified.
+	 */
+	if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
+						     "dmas", NULL)) {
+		ourport->dma = devm_kzalloc(port->dev,
+					    sizeof(*ourport->dma),
+					    GFP_KERNEL);
+		if (!ourport->dma)
+			return -ENOMEM;
+	}
 
 	ourport->clk	= clk_get(&platdev->dev, "uart");
 	if (IS_ERR(ourport->clk)) {
@@ -1857,6 +2396,111 @@
 
 module_platform_driver(samsung_serial_driver);
 
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+/*
+ * Early console.
+ */
+
+struct samsung_early_console_data {
+	u32 txfull_mask;
+};
+
+static void samsung_early_busyuart(struct uart_port *port)
+{
+	while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
+		;
+}
+
+static void samsung_early_busyuart_fifo(struct uart_port *port)
+{
+	struct samsung_early_console_data *data = port->private_data;
+
+	while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
+		;
+}
+
+static void samsung_early_putc(struct uart_port *port, int c)
+{
+	if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+		samsung_early_busyuart_fifo(port);
+	else
+		samsung_early_busyuart(port);
+
+	writeb(c, port->membase + S3C2410_UTXH);
+}
+
+static void samsung_early_write(struct console *con, const char *s, unsigned n)
+{
+	struct earlycon_device *dev = con->data;
+
+	uart_console_write(&dev->port, s, n, samsung_early_putc);
+}
+
+static int __init samsung_early_console_setup(struct earlycon_device *device,
+					      const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = samsung_early_write;
+	return 0;
+}
+
+/* S3C2410 */
+static struct samsung_early_console_data s3c2410_early_console_data = {
+	.txfull_mask = S3C2410_UFSTAT_TXFULL,
+};
+
+static int __init s3c2410_early_console_setup(struct earlycon_device *device,
+					      const char *opt)
+{
+	device->port.private_data = &s3c2410_early_console_data;
+	return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
+			s3c2410_early_console_setup);
+EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
+
+/* S3C2412, S3C2440, S3C64xx */
+static struct samsung_early_console_data s3c2440_early_console_data = {
+	.txfull_mask = S3C2440_UFSTAT_TXFULL,
+};
+
+static int __init s3c2440_early_console_setup(struct earlycon_device *device,
+					      const char *opt)
+{
+	device->port.private_data = &s3c2440_early_console_data;
+	return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
+			s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
+			s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
+			s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
+
+/* S5PV210, EXYNOS */
+static struct samsung_early_console_data s5pv210_early_console_data = {
+	.txfull_mask = S5PV210_UFSTAT_TXFULL,
+};
+
+static int __init s5pv210_early_console_setup(struct earlycon_device *device,
+					      const char *opt)
+{
+	device->port.private_data = &s5pv210_early_console_data;
+	return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
+			s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
+			s5pv210_early_console_setup);
+EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
+EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
+#endif
+
 MODULE_ALIAS("platform:samsung-uart");
 MODULE_DESCRIPTION("Samsung SoC Serial port driver");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index eb071dd..d275032 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/dmaengine.h>
+
 struct s3c24xx_uart_info {
 	char			*name;
 	unsigned int		type;
@@ -41,6 +43,40 @@
 	unsigned int			fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
 };
 
+struct s3c24xx_uart_dma {
+	dma_filter_fn			fn;
+	void				*rx_param;
+	void				*tx_param;
+
+	unsigned int			rx_chan_id;
+	unsigned int			tx_chan_id;
+
+	struct dma_slave_config		rx_conf;
+	struct dma_slave_config		tx_conf;
+
+	struct dma_chan			*rx_chan;
+	struct dma_chan			*tx_chan;
+
+	dma_addr_t			rx_addr;
+	dma_addr_t			tx_addr;
+
+	dma_cookie_t			rx_cookie;
+	dma_cookie_t			tx_cookie;
+
+	char				*rx_buf;
+
+	dma_addr_t			tx_transfer_addr;
+
+	size_t				rx_size;
+	size_t				tx_size;
+
+	struct dma_async_tx_descriptor	*tx_desc;
+	struct dma_async_tx_descriptor	*rx_desc;
+
+	int				tx_bytes_requested;
+	int				rx_bytes_requested;
+};
+
 struct s3c24xx_uart_port {
 	unsigned char			rx_claimed;
 	unsigned char			tx_claimed;
@@ -50,6 +86,10 @@
 	unsigned int			rx_irq;
 	unsigned int			tx_irq;
 
+	unsigned int			tx_in_progress;
+	unsigned int			tx_mode;
+	unsigned int			rx_mode;
+
 	struct s3c24xx_uart_info	*info;
 	struct clk			*clk;
 	struct clk			*baudclk;
@@ -59,6 +99,8 @@
 	/* reference to platform data */
 	struct s3c2410_uartcfg		*cfg;
 
+	struct s3c24xx_uart_dma		*dma;
+
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block		freq_transition;
 #endif
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 984605b..6a1055a 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -179,14 +179,6 @@
 			if (tty->termios.c_cflag & CBAUD)
 				uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
 		}
-
-		spin_lock_irq(&uport->lock);
-		if (uart_cts_enabled(uport) &&
-		    !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
-			uport->hw_stopped = 1;
-		else
-			uport->hw_stopped = 0;
-		spin_unlock_irq(&uport->lock);
 	}
 
 	/*
@@ -442,6 +434,7 @@
 {
 	struct uart_port *uport = state->uart_port;
 	struct ktermios *termios;
+	int hw_stopped;
 
 	/*
 	 * If we have no tty, termios, or the port does not exist,
@@ -466,6 +459,18 @@
 		uport->status &= ~UPSTAT_DCD_ENABLE;
 	else
 		uport->status |= UPSTAT_DCD_ENABLE;
+
+	/* reset sw-assisted CTS flow control based on (possibly) new mode */
+	hw_stopped = uport->hw_stopped;
+	uport->hw_stopped = uart_softcts_mode(uport) &&
+				!(uport->ops->get_mctrl(uport) & TIOCM_CTS);
+	if (uport->hw_stopped) {
+		if (!hw_stopped)
+			uport->ops->stop_tx(uport);
+	} else {
+		if (hw_stopped)
+			__uart_start(tty);
+	}
 	spin_unlock_irq(&uport->lock);
 }
 
@@ -619,22 +624,22 @@
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_port *port = state->uart_port;
-	upf_t mask = 0;
+	upstat_t mask = 0;
 
 	if (I_IXOFF(tty))
-		mask |= UPF_SOFT_FLOW;
+		mask |= UPSTAT_AUTOXOFF;
 	if (tty->termios.c_cflag & CRTSCTS)
-		mask |= UPF_HARD_FLOW;
+		mask |= UPSTAT_AUTORTS;
 
-	if (port->flags & mask) {
+	if (port->status & mask) {
 		port->ops->throttle(port);
-		mask &= ~port->flags;
+		mask &= ~port->status;
 	}
 
-	if (mask & UPF_SOFT_FLOW)
+	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, STOP_CHAR(tty));
 
-	if (mask & UPF_HARD_FLOW)
+	if (mask & UPSTAT_AUTORTS)
 		uart_clear_mctrl(port, TIOCM_RTS);
 }
 
@@ -642,22 +647,22 @@
 {
 	struct uart_state *state = tty->driver_data;
 	struct uart_port *port = state->uart_port;
-	upf_t mask = 0;
+	upstat_t mask = 0;
 
 	if (I_IXOFF(tty))
-		mask |= UPF_SOFT_FLOW;
+		mask |= UPSTAT_AUTOXOFF;
 	if (tty->termios.c_cflag & CRTSCTS)
-		mask |= UPF_HARD_FLOW;
+		mask |= UPSTAT_AUTORTS;
 
-	if (port->flags & mask) {
+	if (port->status & mask) {
 		port->ops->unthrottle(port);
-		mask &= ~port->flags;
+		mask &= ~port->status;
 	}
 
-	if (mask & UPF_SOFT_FLOW)
+	if (mask & UPSTAT_AUTOXOFF)
 		uart_send_xchar(tty, START_CHAR(tty));
 
-	if (mask & UPF_HARD_FLOW)
+	if (mask & UPSTAT_AUTORTS)
 		uart_set_mctrl(port, TIOCM_RTS);
 }
 
@@ -1351,30 +1356,6 @@
 			mask |= TIOCM_RTS;
 		uart_set_mctrl(uport, mask);
 	}
-
-	/*
-	 * If the port is doing h/w assisted flow control, do nothing.
-	 * We assume that port->hw_stopped has never been set.
-	 */
-	if (uport->flags & UPF_HARD_FLOW)
-		return;
-
-	/* Handle turning off CRTSCTS */
-	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
-		spin_lock_irq(&uport->lock);
-		uport->hw_stopped = 0;
-		__uart_start(tty);
-		spin_unlock_irq(&uport->lock);
-	}
-	/* Handle turning on CRTSCTS */
-	else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
-		spin_lock_irq(&uport->lock);
-		if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
-			uport->hw_stopped = 1;
-			uport->ops->stop_tx(uport);
-		}
-		spin_unlock_irq(&uport->lock);
-	}
 }
 
 /*
@@ -2008,23 +1989,24 @@
 	}
 	put_device(tty_dev);
 
-	if (console_suspend_enabled || !uart_console(uport))
-		uport->suspended = 1;
+	/* Nothing to do if the console is not suspending */
+	if (!console_suspend_enabled && uart_console(uport))
+		goto unlock;
+
+	uport->suspended = 1;
 
 	if (port->flags & ASYNC_INITIALIZED) {
 		const struct uart_ops *ops = uport->ops;
 		int tries;
 
-		if (console_suspend_enabled || !uart_console(uport)) {
-			set_bit(ASYNCB_SUSPENDED, &port->flags);
-			clear_bit(ASYNCB_INITIALIZED, &port->flags);
+		set_bit(ASYNCB_SUSPENDED, &port->flags);
+		clear_bit(ASYNCB_INITIALIZED, &port->flags);
 
-			spin_lock_irq(&uport->lock);
-			ops->stop_tx(uport);
-			ops->set_mctrl(uport, 0);
-			ops->stop_rx(uport);
-			spin_unlock_irq(&uport->lock);
-		}
+		spin_lock_irq(&uport->lock);
+		ops->stop_tx(uport);
+		ops->set_mctrl(uport, 0);
+		ops->stop_rx(uport);
+		spin_unlock_irq(&uport->lock);
 
 		/*
 		 * Wait for the transmitter to empty.
@@ -2036,19 +2018,17 @@
 				drv->dev_name,
 				drv->tty_driver->name_base + uport->line);
 
-		if (console_suspend_enabled || !uart_console(uport))
-			ops->shutdown(uport);
+		ops->shutdown(uport);
 	}
 
 	/*
 	 * Disable the console device before suspending.
 	 */
-	if (console_suspend_enabled && uart_console(uport))
+	if (uart_console(uport))
 		console_stop(uport->cons);
 
-	if (console_suspend_enabled || !uart_console(uport))
-		uart_change_pm(state, UART_PM_STATE_OFF);
-
+	uart_change_pm(state, UART_PM_STATE_OFF);
+unlock:
 	mutex_unlock(&port->mutex);
 
 	return 0;
@@ -2856,7 +2836,7 @@
 
 	uport->icount.cts++;
 
-	if (uart_cts_enabled(uport)) {
+	if (uart_softcts_mode(uport)) {
 		if (uport->hw_stopped) {
 			if (status) {
 				uport->hw_stopped = 0;
@@ -2869,6 +2849,7 @@
 				uport->ops->stop_tx(uport);
 			}
 		}
+
 	}
 }
 EXPORT_SYMBOL_GPL(uart_handle_cts_change);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e032963..5b50c79 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -858,7 +858,7 @@
 		tty_insert_flip_char(tport, 0, TTY_OVERRUN);
 		tty_flip_buffer_push(tport);
 
-		dev_notice(port->dev, "overrun error\n");
+		dev_dbg(port->dev, "overrun error\n");
 		copied++;
 	}
 
@@ -997,12 +997,15 @@
 static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
 {
 	unsigned short ssr_status, scr_status, err_enabled;
+	unsigned short slr_status = 0;
 	struct uart_port *port = ptr;
 	struct sci_port *s = to_sci_port(port);
 	irqreturn_t ret = IRQ_NONE;
 
 	ssr_status = serial_port_in(port, SCxSR);
 	scr_status = serial_port_in(port, SCSCR);
+	if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
+		slr_status = serial_port_in(port, SCLSR);
 	err_enabled = scr_status & port_rx_irq_mask(port);
 
 	/* Tx Interrupt */
@@ -1015,8 +1018,11 @@
 	 * DR flags
 	 */
 	if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
-	    (scr_status & SCSCR_RIE))
+	    (scr_status & SCSCR_RIE)) {
+		if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
+			sci_handle_fifo_overrun(port);
 		ret = sci_rx_interrupt(irq, ptr);
+	}
 
 	/* Error Interrupt */
 	if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
@@ -1026,6 +1032,12 @@
 	if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
 		ret = sci_br_interrupt(irq, ptr);
 
+	/* Overrun Interrupt */
+	if (port->type == PORT_SCIF || port->type == PORT_HSCIF) {
+		if (slr_status & 0x01)
+			sci_handle_fifo_overrun(port);
+	}
+
 	return ret;
 }
 
@@ -2605,7 +2617,7 @@
 	return 0;
 }
 
-static int sci_suspend(struct device *dev)
+static __maybe_unused int sci_suspend(struct device *dev)
 {
 	struct sci_port *sport = dev_get_drvdata(dev);
 
@@ -2615,7 +2627,7 @@
 	return 0;
 }
 
-static int sci_resume(struct device *dev)
+static __maybe_unused int sci_resume(struct device *dev)
 {
 	struct sci_port *sport = dev_get_drvdata(dev);
 
@@ -2625,10 +2637,7 @@
 	return 0;
 }
 
-static const struct dev_pm_ops sci_dev_pm_ops = {
-	.suspend	= sci_suspend,
-	.resume		= sci_resume,
-};
+static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
 
 static struct platform_driver sci_driver = {
 	.probe		= sci_probe,
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index b269f6b..27ed0e9 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -177,7 +177,7 @@
 			dmaengine_pause(sirfport->tx_dma_chan);
 			sirfport->tx_dma_state = TX_DMA_PAUSE;
 		} else {
-			if (!sirfport->is_marco)
+			if (!sirfport->is_atlas7)
 				wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) &
 				~uint_en->sirfsoc_txfifo_empty_en);
@@ -186,7 +186,7 @@
 				uint_en->sirfsoc_txfifo_empty_en);
 		}
 	} else {
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) &
 				~uint_en->sirfsoc_txfifo_empty_en);
@@ -217,7 +217,7 @@
 	}
 	if (sirfport->tx_dma_state == TX_DMA_RUNNING)
 		return;
-	if (!sirfport->is_marco)
+	if (!sirfport->is_atlas7)
 		wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg)&
 				~(uint_en->sirfsoc_txfifo_empty_en));
@@ -244,7 +244,7 @@
 		}
 		if (tran_size < 4)
 			sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg)|
 				uint_en->sirfsoc_txfifo_empty_en);
@@ -293,7 +293,7 @@
 		sirfsoc_uart_pio_tx_chars(sirfport,
 			SIRFSOC_UART_IO_TX_REASONABLE_CNT);
 		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 					rd_regl(port, ureg->sirfsoc_int_en_reg)|
 					uint_en->sirfsoc_txfifo_empty_en);
@@ -311,7 +311,7 @@
 
 	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
 	if (sirfport->rx_dma_chan) {
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) &
 				~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
@@ -322,7 +322,7 @@
 					uint_en->sirfsoc_rx_done_en);
 		dmaengine_terminate_all(sirfport->rx_dma_chan);
 	} else {
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg)&
 				~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
@@ -344,7 +344,7 @@
 	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
 		wr_regl(port, ureg->sirfsoc_afc_ctrl,
 				rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 					rd_regl(port, ureg->sirfsoc_int_en_reg)&
 					~uint_en->sirfsoc_cts_en);
@@ -380,7 +380,7 @@
 		wr_regl(port, ureg->sirfsoc_afc_ctrl,
 				rd_regl(port, ureg->sirfsoc_afc_ctrl) |
 				SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 					rd_regl(port, ureg->sirfsoc_int_en_reg)
 					| uint_en->sirfsoc_cts_en);
@@ -544,7 +544,7 @@
 		sirfport->rx_io_count = 0;
 		wr_regl(port, ureg->sirfsoc_int_st_reg,
 				uint_st->sirfsoc_rx_done);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) &
 				~(uint_en->sirfsoc_rx_done_en));
@@ -555,7 +555,7 @@
 	} else {
 		wr_regl(port, ureg->sirfsoc_int_st_reg,
 				uint_st->sirfsoc_rx_done);
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) |
 				(uint_en->sirfsoc_rx_done_en));
@@ -578,7 +578,7 @@
 	dmaengine_terminate_all(sirfport->rx_dma_chan);
 	sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
 		SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
-	if (!sirfport->is_marco)
+	if (!sirfport->is_atlas7)
 		wr_regl(port, ureg->sirfsoc_int_en_reg,
 			rd_regl(port, ureg->sirfsoc_int_en_reg) &
 			~(uint_en->sirfsoc_rx_timeout_en));
@@ -598,7 +598,7 @@
 	sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
 	if (sirfport->rx_io_count == 4) {
 		sirfport->rx_io_count = 0;
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) &
 				~(uint_en->sirfsoc_rx_done_en));
@@ -748,7 +748,7 @@
 	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
 		sirfsoc_rx_submit_one_dma_desc(port, i);
 	sirfport->rx_completed = sirfport->rx_issued = 0;
-	if (!sirfport->is_marco)
+	if (!sirfport->is_atlas7)
 		wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) |
 				SIRFUART_RX_DMA_INT_EN(port, uint_en));
@@ -770,7 +770,7 @@
 	if (sirfport->rx_dma_chan)
 		sirfsoc_uart_start_next_rx_dma(port);
 	else {
-		if (!sirfport->is_marco)
+		if (!sirfport->is_atlas7)
 			wr_regl(port, ureg->sirfsoc_int_en_reg,
 				rd_regl(port, ureg->sirfsoc_int_en_reg) |
 				SIRFUART_RX_IO_INT_EN(port, uint_en));
@@ -1124,7 +1124,7 @@
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
 	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
-	if (!sirfport->is_marco)
+	if (!sirfport->is_atlas7)
 		wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
 	else
 		wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
@@ -1271,7 +1271,7 @@
 
 static struct of_device_id sirfsoc_uart_ids[] = {
 	{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
-	{ .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
+	{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
 	{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
 	{}
 };
@@ -1350,8 +1350,8 @@
 		gpio_direction_output(sirfport->rts_gpio, 1);
 	}
 usp_no_flow_control:
-	if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
-		sirfport->is_marco = true;
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+		sirfport->is_atlas7 = true;
 
 	if (of_property_read_u32(pdev->dev.of_node,
 			"fifosize",
@@ -1393,7 +1393,7 @@
 		goto err;
 	}
 	port->uartclk = clk_get_rate(sirfport->clk);
-	if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) {
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
 		sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
 		if (IS_ERR(sirfport->clk_general)) {
 			ret = PTR_ERR(sirfport->clk_general);
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 275d038..727eb6b 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -421,8 +421,8 @@
 	bool				is_bt_uart;
 	struct clk			*clk_general;
 	struct clk			*clk_noc;
-	/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
-	bool				is_marco;
+	/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
+	bool				is_atlas7;
 	struct sirfsoc_uart_register	*uart_reg;
 	struct dma_chan			*rx_dma_chan;
 	struct dma_chan			*tx_dma_chan;
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
new file mode 100644
index 0000000..594b633
--- /dev/null
+++ b/drivers/tty/serial/sprd_serial.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (C) 2012-2015 Spreadtrum Communications Inc.
+ *
+ * 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.
+ */
+
+#if defined(CONFIG_SERIAL_SPRD_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* device name */
+#define UART_NR_MAX		8
+#define SPRD_TTY_NAME		"ttyS"
+#define SPRD_FIFO_SIZE		128
+#define SPRD_DEF_RATE		26000000
+#define SPRD_BAUD_IO_LIMIT	3000000
+#define SPRD_TIMEOUT		256
+
+/* the offset of serial registers and BITs for them */
+/* data registers */
+#define SPRD_TXD		0x0000
+#define SPRD_RXD		0x0004
+
+/* line status register and its BITs  */
+#define SPRD_LSR		0x0008
+#define SPRD_LSR_OE		BIT(4)
+#define SPRD_LSR_FE		BIT(3)
+#define SPRD_LSR_PE		BIT(2)
+#define SPRD_LSR_BI		BIT(7)
+#define SPRD_LSR_TX_OVER	BIT(15)
+
+/* data number in TX and RX fifo */
+#define SPRD_STS1		0x000C
+
+/* interrupt enable register and its BITs */
+#define SPRD_IEN		0x0010
+#define SPRD_IEN_RX_FULL	BIT(0)
+#define SPRD_IEN_TX_EMPTY	BIT(1)
+#define SPRD_IEN_BREAK_DETECT	BIT(7)
+#define SPRD_IEN_TIMEOUT	BIT(13)
+
+/* interrupt clear register */
+#define SPRD_ICLR		0x0014
+
+/* line control register */
+#define SPRD_LCR		0x0018
+#define SPRD_LCR_STOP_1BIT	0x10
+#define SPRD_LCR_STOP_2BIT	0x30
+#define SPRD_LCR_DATA_LEN	(BIT(2) | BIT(3))
+#define SPRD_LCR_DATA_LEN5	0x0
+#define SPRD_LCR_DATA_LEN6	0x4
+#define SPRD_LCR_DATA_LEN7	0x8
+#define SPRD_LCR_DATA_LEN8	0xc
+#define SPRD_LCR_PARITY	(BIT(0) | BIT(1))
+#define SPRD_LCR_PARITY_EN	0x2
+#define SPRD_LCR_EVEN_PAR	0x0
+#define SPRD_LCR_ODD_PAR	0x1
+
+/* control register 1 */
+#define SPRD_CTL1			0x001C
+#define RX_HW_FLOW_CTL_THLD	BIT(6)
+#define RX_HW_FLOW_CTL_EN	BIT(7)
+#define TX_HW_FLOW_CTL_EN	BIT(8)
+#define RX_TOUT_THLD_DEF	0x3E00
+#define RX_HFC_THLD_DEF	0x40
+
+/* fifo threshold register */
+#define SPRD_CTL2		0x0020
+#define THLD_TX_EMPTY	0x40
+#define THLD_RX_FULL	0x40
+
+/* config baud rate register */
+#define SPRD_CLKD0		0x0024
+#define SPRD_CLKD1		0x0028
+
+/* interrupt mask status register */
+#define SPRD_IMSR			0x002C
+#define SPRD_IMSR_RX_FIFO_FULL		BIT(0)
+#define SPRD_IMSR_TX_FIFO_EMPTY	BIT(1)
+#define SPRD_IMSR_BREAK_DETECT		BIT(7)
+#define SPRD_IMSR_TIMEOUT		BIT(13)
+
+struct reg_backup {
+	u32 ien;
+	u32 ctrl0;
+	u32 ctrl1;
+	u32 ctrl2;
+	u32 clkd0;
+	u32 clkd1;
+	u32 dspwait;
+};
+
+struct sprd_uart_port {
+	struct uart_port port;
+	struct reg_backup reg_bak;
+	char name[16];
+};
+
+static struct sprd_uart_port *sprd_port[UART_NR_MAX];
+static int sprd_ports_num;
+
+static inline unsigned int serial_in(struct uart_port *port, int offset)
+{
+	return readl_relaxed(port->membase + offset);
+}
+
+static inline void serial_out(struct uart_port *port, int offset, int value)
+{
+	writel_relaxed(value, port->membase + offset);
+}
+
+static unsigned int sprd_tx_empty(struct uart_port *port)
+{
+	if (serial_in(port, SPRD_STS1) & 0xff00)
+		return 0;
+	else
+		return TIOCSER_TEMT;
+}
+
+static unsigned int sprd_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_DSR | TIOCM_CTS;
+}
+
+static void sprd_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* nothing to do */
+}
+
+static void sprd_stop_tx(struct uart_port *port)
+{
+	unsigned int ien, iclr;
+
+	iclr = serial_in(port, SPRD_ICLR);
+	ien = serial_in(port, SPRD_IEN);
+
+	iclr |= SPRD_IEN_TX_EMPTY;
+	ien &= ~SPRD_IEN_TX_EMPTY;
+
+	serial_out(port, SPRD_ICLR, iclr);
+	serial_out(port, SPRD_IEN, ien);
+}
+
+static void sprd_start_tx(struct uart_port *port)
+{
+	unsigned int ien;
+
+	ien = serial_in(port, SPRD_IEN);
+	if (!(ien & SPRD_IEN_TX_EMPTY)) {
+		ien |= SPRD_IEN_TX_EMPTY;
+		serial_out(port, SPRD_IEN, ien);
+	}
+}
+
+static void sprd_stop_rx(struct uart_port *port)
+{
+	unsigned int ien, iclr;
+
+	iclr = serial_in(port, SPRD_ICLR);
+	ien = serial_in(port, SPRD_IEN);
+
+	ien &= ~(SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT);
+	iclr |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT;
+
+	serial_out(port, SPRD_IEN, ien);
+	serial_out(port, SPRD_ICLR, iclr);
+}
+
+/* The Sprd serial does not support this function. */
+static void sprd_break_ctl(struct uart_port *port, int break_state)
+{
+	/* nothing to do */
+}
+
+static int handle_lsr_errors(struct uart_port *port,
+			     unsigned int *flag,
+			     unsigned int *lsr)
+{
+	int ret = 0;
+
+	/* statistics */
+	if (*lsr & SPRD_LSR_BI) {
+		*lsr &= ~(SPRD_LSR_FE | SPRD_LSR_PE);
+		port->icount.brk++;
+		ret = uart_handle_break(port);
+		if (ret)
+			return ret;
+	} else if (*lsr & SPRD_LSR_PE)
+		port->icount.parity++;
+	else if (*lsr & SPRD_LSR_FE)
+		port->icount.frame++;
+	if (*lsr & SPRD_LSR_OE)
+		port->icount.overrun++;
+
+	/* mask off conditions which should be ignored */
+	*lsr &= port->read_status_mask;
+	if (*lsr & SPRD_LSR_BI)
+		*flag = TTY_BREAK;
+	else if (*lsr & SPRD_LSR_PE)
+		*flag = TTY_PARITY;
+	else if (*lsr & SPRD_LSR_FE)
+		*flag = TTY_FRAME;
+
+	return ret;
+}
+
+static inline void sprd_rx(struct uart_port *port)
+{
+	struct tty_port *tty = &port->state->port;
+	unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
+
+	while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
+		lsr = serial_in(port, SPRD_LSR);
+		ch = serial_in(port, SPRD_RXD);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
+			SPRD_LSR_FE | SPRD_LSR_OE))
+			if (handle_lsr_errors(port, &lsr, &flag))
+				continue;
+		if (uart_handle_sysrq_char(port, ch))
+			continue;
+
+		uart_insert_char(port, lsr, SPRD_LSR_OE, ch, flag);
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+static inline void sprd_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	int count;
+
+	if (port->x_char) {
+		serial_out(port, SPRD_TXD, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		sprd_stop_tx(port);
+		return;
+	}
+
+	count = THLD_TX_EMPTY;
+	do {
+		serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		sprd_stop_tx(port);
+}
+
+/* this handles the interrupt from one port */
+static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	unsigned int ims;
+
+	spin_lock(&port->lock);
+
+	ims = serial_in(port, SPRD_IMSR);
+
+	if (!ims)
+		return IRQ_NONE;
+
+	serial_out(port, SPRD_ICLR, ~0);
+
+	if (ims & (SPRD_IMSR_RX_FIFO_FULL |
+		SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
+		sprd_rx(port);
+
+	if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
+		sprd_tx(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int sprd_startup(struct uart_port *port)
+{
+	int ret = 0;
+	unsigned int ien, fc;
+	unsigned int timeout;
+	struct sprd_uart_port *sp;
+	unsigned long flags;
+
+	serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
+
+	/* clear rx fifo */
+	timeout = SPRD_TIMEOUT;
+	while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
+		serial_in(port, SPRD_RXD);
+
+	/* clear tx fifo */
+	timeout = SPRD_TIMEOUT;
+	while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
+		cpu_relax();
+
+	/* clear interrupt */
+	serial_out(port, SPRD_IEN, 0);
+	serial_out(port, SPRD_ICLR, ~0);
+
+	/* allocate irq */
+	sp = container_of(port, struct sprd_uart_port, port);
+	snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
+	ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
+				IRQF_SHARED, sp->name, port);
+	if (ret) {
+		dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
+			port->irq, ret);
+		return ret;
+	}
+	fc = serial_in(port, SPRD_CTL1);
+	fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
+	serial_out(port, SPRD_CTL1, fc);
+
+	/* enable interrupt */
+	spin_lock_irqsave(&port->lock, flags);
+	ien = serial_in(port, SPRD_IEN);
+	ien |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
+	serial_out(port, SPRD_IEN, ien);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void sprd_shutdown(struct uart_port *port)
+{
+	serial_out(port, SPRD_IEN, 0);
+	serial_out(port, SPRD_ICLR, ~0);
+	devm_free_irq(port->dev, port->irq, port);
+}
+
+static void sprd_set_termios(struct uart_port *port,
+				    struct ktermios *termios,
+				    struct ktermios *old)
+{
+	unsigned int baud, quot;
+	unsigned int lcr = 0, fc;
+	unsigned long flags;
+
+	/* ask the core to calculate the divisor for us */
+	baud = uart_get_baud_rate(port, termios, old, 0, SPRD_BAUD_IO_LIMIT);
+
+	quot = (unsigned int)((port->uartclk + baud / 2) / baud);
+
+	/* set data length */
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		lcr |= SPRD_LCR_DATA_LEN5;
+		break;
+	case CS6:
+		lcr |= SPRD_LCR_DATA_LEN6;
+		break;
+	case CS7:
+		lcr |= SPRD_LCR_DATA_LEN7;
+		break;
+	case CS8:
+	default:
+		lcr |= SPRD_LCR_DATA_LEN8;
+		break;
+	}
+
+	/* calculate stop bits */
+	lcr &= ~(SPRD_LCR_STOP_1BIT | SPRD_LCR_STOP_2BIT);
+	if (termios->c_cflag & CSTOPB)
+		lcr |= SPRD_LCR_STOP_2BIT;
+	else
+		lcr |= SPRD_LCR_STOP_1BIT;
+
+	/* calculate parity */
+	lcr &= ~SPRD_LCR_PARITY;
+	termios->c_cflag &= ~CMSPAR;	/* no support mark/space */
+	if (termios->c_cflag & PARENB) {
+		lcr |= SPRD_LCR_PARITY_EN;
+		if (termios->c_cflag & PARODD)
+			lcr |= SPRD_LCR_ODD_PAR;
+		else
+			lcr |= SPRD_LCR_EVEN_PAR;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* update the per-port timeout */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = SPRD_LSR_OE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= SPRD_LSR_FE | SPRD_LSR_PE;
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= SPRD_LSR_BI;
+
+	/* characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= SPRD_LSR_PE | SPRD_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= SPRD_LSR_BI;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= SPRD_LSR_OE;
+	}
+
+	/* flow control */
+	fc = serial_in(port, SPRD_CTL1);
+	fc &= ~(RX_HW_FLOW_CTL_THLD | RX_HW_FLOW_CTL_EN | TX_HW_FLOW_CTL_EN);
+	if (termios->c_cflag & CRTSCTS) {
+		fc |= RX_HW_FLOW_CTL_THLD;
+		fc |= RX_HW_FLOW_CTL_EN;
+		fc |= TX_HW_FLOW_CTL_EN;
+	}
+
+	/* clock divider bit0~bit15 */
+	serial_out(port, SPRD_CLKD0, quot & 0xffff);
+
+	/* clock divider bit16~bit20 */
+	serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
+	serial_out(port, SPRD_LCR, lcr);
+	fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
+	serial_out(port, SPRD_CTL1, fc);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *sprd_type(struct uart_port *port)
+{
+	return "SPX";
+}
+
+static void sprd_release_port(struct uart_port *port)
+{
+	/* nothing to do */
+}
+
+static int sprd_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void sprd_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_SPRD;
+}
+
+static int sprd_verify_port(struct uart_port *port,
+				   struct serial_struct *ser)
+{
+	if (ser->type != PORT_SPRD)
+		return -EINVAL;
+	if (port->irq != ser->irq)
+		return -EINVAL;
+	return 0;
+}
+
+static struct uart_ops serial_sprd_ops = {
+	.tx_empty = sprd_tx_empty,
+	.get_mctrl = sprd_get_mctrl,
+	.set_mctrl = sprd_set_mctrl,
+	.stop_tx = sprd_stop_tx,
+	.start_tx = sprd_start_tx,
+	.stop_rx = sprd_stop_rx,
+	.break_ctl = sprd_break_ctl,
+	.startup = sprd_startup,
+	.shutdown = sprd_shutdown,
+	.set_termios = sprd_set_termios,
+	.type = sprd_type,
+	.release_port = sprd_release_port,
+	.request_port = sprd_request_port,
+	.config_port = sprd_config_port,
+	.verify_port = sprd_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_SPRD_CONSOLE
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+	unsigned int status, tmout = 10000;
+
+	/* wait up to 10ms for the character(s) to be sent */
+	do {
+		status = serial_in(port, SPRD_STS1);
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while (status & 0xff00);
+}
+
+static void sprd_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmitr(port);
+	serial_out(port, SPRD_TXD, ch);
+}
+
+static void sprd_console_write(struct console *co, const char *s,
+				      unsigned int count)
+{
+	struct uart_port *port = &sprd_port[co->index]->port;
+	int locked = 1;
+	unsigned long flags;
+
+	if (port->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock_irqsave(&port->lock, flags);
+	else
+		spin_lock_irqsave(&port->lock, flags);
+
+	uart_console_write(port, s, count, sprd_console_putchar);
+
+	/* wait for transmitter to become empty */
+	wait_for_xmitr(port);
+
+	if (locked)
+		spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init sprd_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= UART_NR_MAX || co->index < 0)
+		co->index = 0;
+
+	port = &sprd_port[co->index]->port;
+	if (port == NULL) {
+		pr_info("serial port %d not yet initialized\n", co->index);
+		return -ENODEV;
+	}
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sprd_uart_driver;
+static struct console sprd_console = {
+	.name = SPRD_TTY_NAME,
+	.write = sprd_console_write,
+	.device = uart_console_device,
+	.setup = sprd_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &sprd_uart_driver,
+};
+
+#define SPRD_CONSOLE	(&sprd_console)
+
+/* Support for earlycon */
+static void sprd_putc(struct uart_port *port, int c)
+{
+	unsigned int timeout = SPRD_TIMEOUT;
+
+	while (timeout-- &&
+		   !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
+		cpu_relax();
+
+	writeb(c, port->membase + SPRD_TXD);
+}
+
+static void sprd_early_write(struct console *con, const char *s,
+				    unsigned n)
+{
+	struct earlycon_device *dev = con->data;
+
+	uart_console_write(&dev->port, s, n, sprd_putc);
+}
+
+static int __init sprd_early_console_setup(
+				struct earlycon_device *device,
+				const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = sprd_early_write;
+	return 0;
+}
+
+EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
+OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
+		    sprd_early_console_setup);
+
+#else /* !CONFIG_SERIAL_SPRD_CONSOLE */
+#define SPRD_CONSOLE		NULL
+#endif
+
+static struct uart_driver sprd_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "sprd_serial",
+	.dev_name = SPRD_TTY_NAME,
+	.major = 0,
+	.minor = 0,
+	.nr = UART_NR_MAX,
+	.cons = SPRD_CONSOLE,
+};
+
+static int sprd_probe_dt_alias(int index, struct device *dev)
+{
+	struct device_node *np;
+	int ret = index;
+
+	if (!IS_ENABLED(CONFIG_OF))
+		return ret;
+
+	np = dev->of_node;
+	if (!np)
+		return ret;
+
+	ret = of_alias_get_id(np, "serial");
+	if (IS_ERR_VALUE(ret))
+		ret = index;
+	else if (ret >= ARRAY_SIZE(sprd_port) || sprd_port[ret] != NULL) {
+		dev_warn(dev, "requested serial port %d not available.\n", ret);
+		ret = index;
+	}
+
+	return ret;
+}
+
+static int sprd_remove(struct platform_device *dev)
+{
+	struct sprd_uart_port *sup = platform_get_drvdata(dev);
+
+	if (sup) {
+		uart_remove_one_port(&sprd_uart_driver, &sup->port);
+		sprd_port[sup->port.line] = NULL;
+		sprd_ports_num--;
+	}
+
+	if (!sprd_ports_num)
+		uart_unregister_driver(&sprd_uart_driver);
+
+	return 0;
+}
+
+static int sprd_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct uart_port *up;
+	struct clk *clk;
+	int irq;
+	int index;
+	int ret;
+
+	for (index = 0; index < ARRAY_SIZE(sprd_port); index++)
+		if (sprd_port[index] == NULL)
+			break;
+
+	if (index == ARRAY_SIZE(sprd_port))
+		return -EBUSY;
+
+	index = sprd_probe_dt_alias(index, &pdev->dev);
+
+	sprd_port[index] = devm_kzalloc(&pdev->dev,
+		sizeof(*sprd_port[index]), GFP_KERNEL);
+	if (!sprd_port[index])
+		return -ENOMEM;
+
+	up = &sprd_port[index]->port;
+	up->dev = &pdev->dev;
+	up->line = index;
+	up->type = PORT_SPRD;
+	up->iotype = SERIAL_IO_PORT;
+	up->uartclk = SPRD_DEF_RATE;
+	up->fifosize = SPRD_FIFO_SIZE;
+	up->ops = &serial_sprd_ops;
+	up->flags = UPF_BOOT_AUTOCONF;
+
+	clk = devm_clk_get(&pdev->dev, NULL);
+	if (!IS_ERR(clk))
+		up->uartclk = clk_get_rate(clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "not provide mem resource\n");
+		return -ENODEV;
+	}
+	up->mapbase = res->start;
+	up->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(up->membase))
+		return PTR_ERR(up->membase);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "not provide irq resource\n");
+		return -ENODEV;
+	}
+	up->irq = irq;
+
+	if (!sprd_ports_num) {
+		ret = uart_register_driver(&sprd_uart_driver);
+		if (ret < 0) {
+			pr_err("Failed to register SPRD-UART driver\n");
+			return ret;
+		}
+	}
+	sprd_ports_num++;
+
+	ret = uart_add_one_port(&sprd_uart_driver, up);
+	if (ret) {
+		sprd_port[index] = NULL;
+		sprd_remove(pdev);
+	}
+
+	platform_set_drvdata(pdev, up);
+
+	return ret;
+}
+
+static int sprd_suspend(struct device *dev)
+{
+	struct sprd_uart_port *sup = dev_get_drvdata(dev);
+
+	uart_suspend_port(&sprd_uart_driver, &sup->port);
+
+	return 0;
+}
+
+static int sprd_resume(struct device *dev)
+{
+	struct sprd_uart_port *sup = dev_get_drvdata(dev);
+
+	uart_resume_port(&sprd_uart_driver, &sup->port);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume);
+
+static const struct of_device_id serial_ids[] = {
+	{.compatible = "sprd,sc9836-uart",},
+	{}
+};
+
+static struct platform_driver sprd_platform_driver = {
+	.probe		= sprd_probe,
+	.remove		= sprd_remove,
+	.driver		= {
+		.name	= "sprd_serial",
+		.of_match_table = of_match_ptr(serial_ids),
+		.pm	= &sprd_pm_ops,
+	},
+};
+
+module_platform_driver(sprd_platform_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spreadtrum SoC serial driver series");
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 542bab3..cff531a 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -637,10 +637,12 @@
 
 	spin_lock_irqsave(&port->lock, flags);
 
-	/* Empty the receive FIFO 1st before making changes */
-	while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
-		 CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
-		cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
+	/* Wait for the transmit FIFO to empty before making changes */
+	if (!(cdns_uart_readl(CDNS_UART_CR_OFFSET) & CDNS_UART_CR_TX_DIS)) {
+		while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+				CDNS_UART_SR_TXEMPTY)) {
+			cpu_relax();
+		}
 	}
 
 	/* Disable the TX and RX to set baud rate */
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3605103..7566164 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -557,3 +557,9 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
+
+/* slave ptys can claim nested buffer lock when handling BRK and INTR */
+void tty_buffer_set_lock_subclass(struct tty_port *port)
+{
+	lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
+}
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 1787fa4..a5cf253 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -530,7 +530,7 @@
  *	Locking: termios_rwsem
  */
 
-int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
 {
 	struct ktermios old_termios;
 	struct tty_ldisc *ld;
@@ -563,7 +563,6 @@
 	up_write(&tty->termios_rwsem);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(tty_set_termios);
 
 /**
  *	set_termios		-	set termios values for a tty
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 4486741..0efcf71 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,18 +4,8 @@
 #include <linux/semaphore.h>
 #include <linux/sched.h>
 
-/*
- * Nested tty locks are necessary for releasing pty pairs.
- * The stable lock order is master pty first, then slave pty.
- */
-
 /* Legacy tty mutex glue */
 
-enum {
-	TTY_MUTEX_NORMAL,
-	TTY_MUTEX_SLAVE,
-};
-
 /*
  * Getting the big tty mutex.
  */
@@ -46,12 +36,8 @@
 
 void __lockfunc tty_lock_slave(struct tty_struct *tty)
 {
-	if (tty && tty != tty->link) {
-		WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) ||
-			!tty->driver->type == TTY_DRIVER_TYPE_PTY ||
-			!tty->driver->type == PTY_TYPE_SLAVE);
+	if (tty && tty != tty->link)
 		tty_lock(tty);
-	}
 }
 
 void __lockfunc tty_unlock_slave(struct tty_struct *tty)
@@ -62,5 +48,5 @@
 
 void tty_set_lock_subclass(struct tty_struct *tty)
 {
-	lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE);
+	lockdep_set_subclass(&tty->legacy_mutex, TTY_LOCK_SLAVE);
 }
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f3fbbbc..6e00572 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -500,6 +500,7 @@
 #endif
 	if (DO_UPDATE(vc))
 		do_update_region(vc, (unsigned long) p, count);
+	notify_update(vc);
 }
 
 /* used by selection: complement pointer position */
@@ -516,6 +517,7 @@
 		scr_writew(old, screenpos(vc, old_offset, 1));
 		if (DO_UPDATE(vc))
 			vc->vc_sw->con_putc(vc, old, oldy, oldx);
+		notify_update(vc);
 	}
 
 	old_offset = offset;
@@ -533,8 +535,8 @@
 			oldy = (offset >> 1) / vc->vc_cols;
 			vc->vc_sw->con_putc(vc, new, oldy, oldx);
 		}
+		notify_update(vc);
 	}
-
 }
 
 static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -3318,11 +3320,8 @@
 		if (first == 0 && last == MAX_NR_CONSOLES -1)
 			deflt = 1;
 
-		if (first != -1) {
-			console_lock();
+		if (first != -1)
 			do_bind_con_driver(csw, first, last, deflt);
-			console_unlock();
-		}
 
 		first = -1;
 		last = -1;
@@ -3362,9 +3361,7 @@
 			deflt = 1;
 
 		if (first != -1) {
-			console_lock();
 			ret = do_unbind_con_driver(csw, first, last, deflt);
-			console_unlock();
 			if (ret != 0)
 				return ret;
 		}
@@ -3394,11 +3391,15 @@
 	struct con_driver *con = dev_get_drvdata(dev);
 	int bind = simple_strtoul(buf, NULL, 0);
 
+	console_lock();
+
 	if (bind)
 		vt_bind(con);
 	else
 		vt_unbind(con);
 
+	console_unlock();
+
 	return count;
 }
 
@@ -3665,8 +3666,7 @@
 	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
 		struct con_driver *con_driver = &registered_con_driver[i];
 
-		if (con_driver->con == csw &&
-		    con_driver->flag & CON_DRIVER_FLAG_INIT) {
+		if (con_driver->con == csw) {
 			vtconsole_deinit_device(con_driver);
 			device_destroy(vtconsole_class,
 				       MKDEV(0, con_driver->node));
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5a90914..8a15c32 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -104,6 +104,26 @@
 	  To compile this driver as a module, choose M here; the module
 	  will be called uio_netx.
 
+config UIO_FSL_ELBC_GPCM
+	tristate "eLBC/GPCM driver"
+	depends on FSL_LBC
+	help
+	  Generic driver for accessing a peripheral connected to an eLBC port
+	  that is running in GPCM mode. GPCM is an interface for simple lower
+	  performance memories and memory-mapped devices. For devices using
+	  FCM or UPM eLBC modes, other device-specific drivers are available.
+
+config UIO_FSL_ELBC_GPCM_NETX5152
+	bool "eLBC/GPCM netX 51/52 support"
+	depends on UIO_FSL_ELBC_GPCM
+	help
+	  This will add support for netX 51/52 devices connected via eLBC/GPCM.
+	  In particular, it implements interrupt handling. This can be used
+	  together with the userspace netX stack from Hilscher.
+
+	  Information about this hardware can be found at:
+	  http://www.hilscher.com/netx
+
 config UIO_PRUSS
 	tristate "Texas Instruments PRUSS driver"
 	depends on ARCH_DAVINCI_DA850
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d3218bd..8560dad 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -8,3 +8,4 @@
 obj-$(CONFIG_UIO_NETX)	+= uio_netx.o
 obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
 obj-$(CONFIG_UIO_MF624)         += uio_mf624.o
+obj-$(CONFIG_UIO_FSL_ELBC_GPCM)	+= uio_fsl_elbc_gpcm.o
diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c
new file mode 100644
index 0000000..b6cac91
--- /dev/null
+++ b/drivers/uio/uio_fsl_elbc_gpcm.c
@@ -0,0 +1,499 @@
+/* uio_fsl_elbc_gpcm: UIO driver for eLBC/GPCM peripherals
+
+   Copyright (C) 2014 Linutronix GmbH
+     Author: John Ogness <john.ogness@linutronix.de>
+
+   This driver provides UIO access to memory of a peripheral connected
+   to the Freescale enhanced local bus controller (eLBC) interface
+   using the general purpose chip-select mode (GPCM).
+
+   Here is an example of the device tree entries:
+
+	localbus@ffe05000 {
+		ranges = <0x2 0x0 0x0 0xff810000 0x10000>;
+
+		dpm@2,0 {
+			compatible = "fsl,elbc-gpcm-uio";
+			reg = <0x2 0x0 0x10000>;
+			elbc-gpcm-br = <0xff810800>;
+			elbc-gpcm-or = <0xffff09f7>;
+			interrupt-parent = <&mpic>;
+			interrupts = <4 1>;
+			device_type = "netx5152";
+			uio_name = "netx_custom";
+			netx5152,init-win0-offset = <0x0>;
+		};
+	};
+
+   Only the entries reg (to identify bank) and elbc-gpcm-* (initial BR/OR
+   values) are required. The entries interrupt*, device_type, and uio_name
+   are optional (as well as any type-specific options such as
+   netx5152,init-win0-offset). As long as no interrupt handler is needed,
+   this driver can be used without any type-specific implementation.
+
+   The netx5152 type has been tested to work with the netX 51/52 hardware
+   from Hilscher using the Hilscher userspace netX stack.
+
+   The netx5152 type should serve as a model to add new type-specific
+   devices as needed.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/fsl_lbc.h>
+
+#define MAX_BANKS 8
+
+struct fsl_elbc_gpcm {
+	struct device *dev;
+	struct fsl_lbc_regs __iomem *lbc;
+	u32 bank;
+	const char *name;
+
+	void (*init)(struct uio_info *info);
+	void (*shutdown)(struct uio_info *info, bool init_err);
+	irqreturn_t (*irq_handler)(int irq, struct uio_info *info);
+};
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+			char *buf);
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count);
+
+DEVICE_ATTR(reg_br, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+DEVICE_ATTR(reg_or, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct uio_info *info = platform_get_drvdata(pdev);
+	struct fsl_elbc_gpcm *priv = info->priv;
+	struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+
+	if (attr == &dev_attr_reg_br) {
+		return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+				 in_be32(&bank->br));
+
+	} else if (attr == &dev_attr_reg_or) {
+		return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+				 in_be32(&bank->or));
+	}
+
+	return 0;
+}
+
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct uio_info *info = platform_get_drvdata(pdev);
+	struct fsl_elbc_gpcm *priv = info->priv;
+	struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+	unsigned long val;
+	u32 reg_br_cur;
+	u32 reg_or_cur;
+	u32 reg_new;
+
+	/* parse use input */
+	if (kstrtoul(buf, 0, &val) != 0)
+		return -EINVAL;
+	reg_new = (u32)val;
+
+	/* read current values */
+	reg_br_cur = in_be32(&bank->br);
+	reg_or_cur = in_be32(&bank->or);
+
+	if (attr == &dev_attr_reg_br) {
+		/* not allowed to change effective base address */
+		if ((reg_br_cur & reg_or_cur & BR_BA) !=
+		    (reg_new & reg_or_cur & BR_BA)) {
+			return -EINVAL;
+		}
+
+		/* not allowed to change mode */
+		if ((reg_new & BR_MSEL) != BR_MS_GPCM)
+			return -EINVAL;
+
+		/* write new value (force valid) */
+		out_be32(&bank->br, reg_new | BR_V);
+
+	} else if (attr == &dev_attr_reg_or) {
+		/* not allowed to change access mask */
+		if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM))
+			return -EINVAL;
+
+		/* write new value */
+		out_be32(&bank->or, reg_new);
+
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+#define DPM_HOST_WIN0_OFFSET	0xff00
+#define DPM_HOST_INT_STAT0	0xe0
+#define DPM_HOST_INT_EN0	0xf0
+#define DPM_HOST_INT_MASK	0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN	0x80000000
+
+static irqreturn_t netx5152_irq_handler(int irq, struct uio_info *info)
+{
+	void __iomem *reg_int_en = info->mem[0].internal_addr +
+					DPM_HOST_WIN0_OFFSET +
+					DPM_HOST_INT_EN0;
+	void __iomem *reg_int_stat = info->mem[0].internal_addr +
+					DPM_HOST_WIN0_OFFSET +
+					DPM_HOST_INT_STAT0;
+
+	/* check if an interrupt is enabled and active */
+	if ((ioread32(reg_int_en) & ioread32(reg_int_stat) &
+	     DPM_HOST_INT_MASK) == 0) {
+		return IRQ_NONE;
+	}
+
+	/* disable interrupts */
+	iowrite32(ioread32(reg_int_en) & ~DPM_HOST_INT_GLOBAL_EN, reg_int_en);
+
+	return IRQ_HANDLED;
+}
+
+static void netx5152_init(struct uio_info *info)
+{
+	unsigned long win0_offset = DPM_HOST_WIN0_OFFSET;
+	struct fsl_elbc_gpcm *priv = info->priv;
+	const void *prop;
+
+	/* get an optional initial win0 offset */
+	prop = of_get_property(priv->dev->of_node,
+			       "netx5152,init-win0-offset", NULL);
+	if (prop)
+		win0_offset = of_read_ulong(prop, 1);
+
+	/* disable interrupts */
+	iowrite32(0, info->mem[0].internal_addr + win0_offset +
+		     DPM_HOST_INT_EN0);
+}
+
+static void netx5152_shutdown(struct uio_info *info, bool init_err)
+{
+	if (init_err)
+		return;
+
+	/* disable interrupts */
+	iowrite32(0, info->mem[0].internal_addr + DPM_HOST_WIN0_OFFSET +
+		     DPM_HOST_INT_EN0);
+}
+#endif
+
+static void setup_periph(struct fsl_elbc_gpcm *priv,
+				   const char *type)
+{
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+	if (strcmp(type, "netx5152") == 0) {
+		priv->irq_handler = netx5152_irq_handler;
+		priv->init = netx5152_init;
+		priv->shutdown = netx5152_shutdown;
+		priv->name = "netX 51/52";
+		return;
+	}
+#endif
+}
+
+static int check_of_data(struct fsl_elbc_gpcm *priv,
+				   struct resource *res,
+				   u32 reg_br, u32 reg_or)
+{
+	/* check specified bank */
+	if (priv->bank >= MAX_BANKS) {
+		dev_err(priv->dev, "invalid bank\n");
+		return -ENODEV;
+	}
+
+	/* check specified mode (BR_MS_GPCM is 0) */
+	if ((reg_br & BR_MSEL) != BR_MS_GPCM) {
+		dev_err(priv->dev, "unsupported mode\n");
+		return -ENODEV;
+	}
+
+	/* check specified mask vs. resource size */
+	if ((~(reg_or & OR_GPCM_AM) + 1) != resource_size(res)) {
+		dev_err(priv->dev, "address mask / size mismatch\n");
+		return -ENODEV;
+	}
+
+	/* check specified address */
+	if ((reg_br & reg_or & BR_BA) != fsl_lbc_addr(res->start)) {
+		dev_err(priv->dev, "base address mismatch\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int get_of_data(struct fsl_elbc_gpcm *priv, struct device_node *node,
+		       struct resource *res, u32 *reg_br,
+		       u32 *reg_or, unsigned int *irq, char **name)
+{
+	const char *dt_name;
+	const char *type;
+	int ret;
+
+	/* get the memory resource */
+	ret = of_address_to_resource(node, 0, res);
+	if (ret) {
+		dev_err(priv->dev, "failed to get resource\n");
+		return ret;
+	}
+
+	/* get the bank number */
+	ret = of_property_read_u32(node, "reg", &priv->bank);
+	if (ret) {
+		dev_err(priv->dev, "failed to get bank number\n");
+		return ret;
+	}
+
+	/* get BR value to set */
+	ret = of_property_read_u32(node, "elbc-gpcm-br", reg_br);
+	if (ret) {
+		dev_err(priv->dev, "missing elbc-gpcm-br value\n");
+		return ret;
+	}
+
+	/* get OR value to set */
+	ret = of_property_read_u32(node, "elbc-gpcm-or", reg_or);
+	if (ret) {
+		dev_err(priv->dev, "missing elbc-gpcm-or value\n");
+		return ret;
+	}
+
+	/* get optional peripheral type */
+	priv->name = "generic";
+	if (of_property_read_string(node, "device_type", &type) == 0)
+		setup_periph(priv, type);
+
+	/* get optional irq value */
+	*irq = irq_of_parse_and_map(node, 0);
+
+	/* sanity check device tree data */
+	ret = check_of_data(priv, res, *reg_br, *reg_or);
+	if (ret)
+		return ret;
+
+	/* get optional uio name */
+	if (of_property_read_string(node, "uio_name", &dt_name) != 0)
+		dt_name = "eLBC_GPCM";
+	*name = kstrdup(dt_name, GFP_KERNEL);
+	if (!*name)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct fsl_elbc_gpcm *priv;
+	struct uio_info *info;
+	char *uio_name = NULL;
+	struct resource res;
+	unsigned int irq;
+	u32 reg_br_cur;
+	u32 reg_or_cur;
+	u32 reg_br_new;
+	u32 reg_or_new;
+	int ret;
+
+	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+		return -ENODEV;
+
+	/* allocate private data */
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->dev = &pdev->dev;
+	priv->lbc = fsl_lbc_ctrl_dev->regs;
+
+	/* get device tree data */
+	ret = get_of_data(priv, node, &res, &reg_br_new, &reg_or_new,
+			  &irq, &uio_name);
+	if (ret)
+		goto out_err0;
+
+	/* allocate UIO structure */
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		ret = -ENOMEM;
+		goto out_err0;
+	}
+
+	/* get current BR/OR values */
+	reg_br_cur = in_be32(&priv->lbc->bank[priv->bank].br);
+	reg_or_cur = in_be32(&priv->lbc->bank[priv->bank].or);
+
+	/* if bank already configured, make sure it matches */
+	if ((reg_br_cur & BR_V)) {
+		if ((reg_br_cur & BR_MSEL) != BR_MS_GPCM ||
+		    (reg_br_cur & reg_or_cur & BR_BA)
+		     != fsl_lbc_addr(res.start)) {
+			dev_err(priv->dev,
+				"bank in use by another peripheral\n");
+			ret = -ENODEV;
+			goto out_err1;
+		}
+
+		/* warn if behavior settings changing */
+		if ((reg_br_cur & ~(BR_BA | BR_V)) !=
+		    (reg_br_new & ~(BR_BA | BR_V))) {
+			dev_warn(priv->dev,
+				 "modifying BR settings: 0x%08x -> 0x%08x",
+				 reg_br_cur, reg_br_new);
+		}
+		if ((reg_or_cur & ~OR_GPCM_AM) != (reg_or_new & ~OR_GPCM_AM)) {
+			dev_warn(priv->dev,
+				 "modifying OR settings: 0x%08x -> 0x%08x",
+				 reg_or_cur, reg_or_new);
+		}
+	}
+
+	/* configure the bank (force base address and GPCM) */
+	reg_br_new &= ~(BR_BA | BR_MSEL);
+	reg_br_new |= fsl_lbc_addr(res.start) | BR_MS_GPCM | BR_V;
+	out_be32(&priv->lbc->bank[priv->bank].or, reg_or_new);
+	out_be32(&priv->lbc->bank[priv->bank].br, reg_br_new);
+
+	/* map the memory resource */
+	info->mem[0].internal_addr = ioremap(res.start, resource_size(&res));
+	if (!info->mem[0].internal_addr) {
+		dev_err(priv->dev, "failed to map chip region\n");
+		ret = -ENODEV;
+		goto out_err1;
+	}
+
+	/* set all UIO data */
+	if (node->name)
+		info->mem[0].name = kstrdup(node->name, GFP_KERNEL);
+	info->mem[0].addr = res.start;
+	info->mem[0].size = resource_size(&res);
+	info->mem[0].memtype = UIO_MEM_PHYS;
+	info->priv = priv;
+	info->name = uio_name;
+	info->version = "0.0.1";
+	if (irq != NO_IRQ) {
+		if (priv->irq_handler) {
+			info->irq = irq;
+			info->irq_flags = IRQF_SHARED;
+			info->handler = priv->irq_handler;
+		} else {
+			irq = NO_IRQ;
+			dev_warn(priv->dev, "ignoring irq, no handler\n");
+		}
+	}
+
+	if (priv->init)
+		priv->init(info);
+
+	/* register UIO device */
+	if (uio_register_device(priv->dev, info) != 0) {
+		dev_err(priv->dev, "UIO registration failed\n");
+		ret = -ENODEV;
+		goto out_err2;
+	}
+
+	/* store private data */
+	platform_set_drvdata(pdev, info);
+
+	/* create sysfs files */
+	ret = device_create_file(priv->dev, &dev_attr_reg_br);
+	if (ret)
+		goto out_err3;
+	ret = device_create_file(priv->dev, &dev_attr_reg_or);
+	if (ret)
+		goto out_err4;
+
+	dev_info(priv->dev,
+		 "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n",
+		 priv->name, (unsigned long long)res.start, priv->bank,
+		 irq != NO_IRQ ? irq : -1);
+
+	return 0;
+out_err4:
+	device_remove_file(priv->dev, &dev_attr_reg_br);
+out_err3:
+	platform_set_drvdata(pdev, NULL);
+	uio_unregister_device(info);
+out_err2:
+	if (priv->shutdown)
+		priv->shutdown(info, true);
+	iounmap(info->mem[0].internal_addr);
+out_err1:
+	kfree(info->mem[0].name);
+	kfree(info);
+out_err0:
+	kfree(uio_name);
+	kfree(priv);
+	return ret;
+}
+
+static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev)
+{
+	struct uio_info *info = platform_get_drvdata(pdev);
+	struct fsl_elbc_gpcm *priv = info->priv;
+
+	device_remove_file(priv->dev, &dev_attr_reg_or);
+	device_remove_file(priv->dev, &dev_attr_reg_br);
+	platform_set_drvdata(pdev, NULL);
+	uio_unregister_device(info);
+	if (priv->shutdown)
+		priv->shutdown(info, false);
+	iounmap(info->mem[0].internal_addr);
+	kfree(info->mem[0].name);
+	kfree(info->name);
+	kfree(info);
+	kfree(priv);
+
+	return 0;
+
+}
+
+static const struct of_device_id uio_fsl_elbc_gpcm_match[] = {
+	{ .compatible = "fsl,elbc-gpcm-uio", },
+	{}
+};
+
+static struct platform_driver uio_fsl_elbc_gpcm_driver = {
+	.driver = {
+		.name = "fsl,elbc-gpcm-uio",
+		.owner = THIS_MODULE,
+		.of_match_table = uio_fsl_elbc_gpcm_match,
+	},
+	.probe = uio_fsl_elbc_gpcm_probe,
+	.remove = uio_fsl_elbc_gpcm_remove,
+};
+
+static int __init uio_fsl_elbc_gpcm_init(void)
+{
+	return platform_driver_register(&uio_fsl_elbc_gpcm_driver);
+}
+
+static void __exit uio_fsl_elbc_gpcm_exit(void)
+{
+	platform_driver_unregister(&uio_fsl_elbc_gpcm_driver);
+}
+
+module_init(uio_fsl_elbc_gpcm_init);
+module_exit(uio_fsl_elbc_gpcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller GPCM driver");
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index 077ae12..d0b508b 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -91,7 +91,8 @@
 	gdev->info.handler = irqhandler;
 	gdev->pdev = pdev;
 
-	if (uio_register_device(&pdev->dev, &gdev->info))
+	err = uio_register_device(&pdev->dev, &gdev->info);
+	if (err)
 		goto err_register;
 	pci_set_drvdata(pdev, gdev);
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index ae481c3..8ed451d 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -104,6 +104,8 @@
 
 source "drivers/usb/chipidea/Kconfig"
 
+source "drivers/usb/isp1760/Kconfig"
+
 comment "USB port drivers"
 
 if USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index d7be717..2f1e2aa 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_USB_DWC3)		+= dwc3/
 obj-$(CONFIG_USB_DWC2)		+= dwc2/
+obj-$(CONFIG_USB_ISP1760)	+= isp1760/
 
 obj-$(CONFIG_USB_MON)		+= mon/
 
@@ -23,7 +24,6 @@
 obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 obj-$(CONFIG_USB_HWA_HCD)	+= host/
-obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
 obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 obj-$(CONFIG_USB_FUSBH200_HCD)	+= host/
diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c
index 241ae34..4df6694 100644
--- a/drivers/usb/chipidea/ci_hdrc_pci.c
+++ b/drivers/usb/chipidea/ci_hdrc_pci.c
@@ -111,6 +111,9 @@
  * PCI device structure
  *
  * Check "pci.h" for details
+ *
+ * Note: ehci-pci driver may try to probe the device first. You have to add an
+ * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
  */
 static const struct pci_device_id ci_hdrc_pci_id_table[] = {
 	{
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 4fe18ce..ff45104 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -819,8 +819,8 @@
 	}
 
 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
-		/* Assume that device is bus powered for now. */
-		*(u16 *)req->buf = ci->remote_wakeup << 1;
+		*(u16 *)req->buf = (ci->remote_wakeup << 1) |
+			ci->gadget.is_selfpowered;
 	} else if ((setup->bRequestType & USB_RECIP_MASK) \
 		   == USB_RECIP_ENDPOINT) {
 		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@@ -1520,6 +1520,19 @@
 	return -ENOTSUPP;
 }
 
+static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
+{
+	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
+	struct ci_hw_ep *hwep = ci->ep0in;
+	unsigned long flags;
+
+	spin_lock_irqsave(hwep->lock, flags);
+	_gadget->is_selfpowered = (is_on != 0);
+	spin_unlock_irqrestore(hwep->lock, flags);
+
+	return 0;
+}
+
 /* Change Data+ pullup status
  * this func is used by usb_gadget_connect/disconnet
  */
@@ -1549,6 +1562,7 @@
 static const struct usb_gadget_ops usb_gadget_ops = {
 	.vbus_session	= ci_udc_vbus_session,
 	.wakeup		= ci_udc_wakeup,
+	.set_selfpowered	= ci_udc_selfpowered,
 	.pullup		= ci_udc_pullup,
 	.vbus_draw	= ci_udc_vbus_draw,
 	.udc_start	= ci_udc_start,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 546a17e8..e78720b 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1091,6 +1091,7 @@
 	unsigned long quirks;
 	int num_rx_buf;
 	int i;
+	unsigned int elength = 0;
 	int combined_interfaces = 0;
 	struct device *tty_dev;
 	int rv = -ENOMEM;
@@ -1136,9 +1137,12 @@
 			dev_err(&intf->dev, "skipping garbage\n");
 			goto next_desc;
 		}
+		elength = buffer[0];
 
 		switch (buffer[2]) {
 		case USB_CDC_UNION_TYPE: /* we've found it */
+			if (elength < sizeof(struct usb_cdc_union_desc))
+				goto next_desc;
 			if (union_header) {
 				dev_err(&intf->dev, "More than one "
 					"union descriptor, skipping ...\n");
@@ -1147,29 +1151,36 @@
 			union_header = (struct usb_cdc_union_desc *)buffer;
 			break;
 		case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+			if (elength < sizeof(struct usb_cdc_country_functional_desc))
+				goto next_desc;
 			cfd = (struct usb_cdc_country_functional_desc *)buffer;
 			break;
 		case USB_CDC_HEADER_TYPE: /* maybe check version */
 			break; /* for now we ignore it */
 		case USB_CDC_ACM_TYPE:
+			if (elength < 4)
+				goto next_desc;
 			ac_management_function = buffer[3];
 			break;
 		case USB_CDC_CALL_MANAGEMENT_TYPE:
+			if (elength < 5)
+				goto next_desc;
 			call_management_function = buffer[3];
 			call_interface_num = buffer[4];
 			break;
 		default:
-			/* there are LOTS more CDC descriptors that
+			/*
+			 * there are LOTS more CDC descriptors that
 			 * could legitimately be found here.
 			 */
 			dev_dbg(&intf->dev, "Ignoring descriptor: "
-					"type %02x, length %d\n",
-					buffer[2], buffer[0]);
+					"type %02x, length %ud\n",
+					buffer[2], elength);
 			break;
 		}
 next_desc:
-		buflen -= buffer[0];
-		buffer += buffer[0];
+		buflen -= elength;
+		buffer += elength;
 	}
 
 	if (!union_header) {
@@ -1287,10 +1298,8 @@
 	dev_dbg(&intf->dev, "interfaces are valid\n");
 
 	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
-	if (acm == NULL) {
-		dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
+	if (acm == NULL)
 		goto alloc_fail;
-	}
 
 	minor = acm_alloc_minor(acm);
 	if (minor == ACM_TTY_MINORS) {
@@ -1329,42 +1338,32 @@
 	acm->quirks = quirks;
 
 	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
-	if (!buf) {
-		dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
+	if (!buf)
 		goto alloc_fail2;
-	}
 	acm->ctrl_buffer = buf;
 
-	if (acm_write_buffers_alloc(acm) < 0) {
-		dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
+	if (acm_write_buffers_alloc(acm) < 0)
 		goto alloc_fail4;
-	}
 
 	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!acm->ctrlurb) {
-		dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
+	if (!acm->ctrlurb)
 		goto alloc_fail5;
-	}
+
 	for (i = 0; i < num_rx_buf; i++) {
 		struct acm_rb *rb = &(acm->read_buffers[i]);
 		struct urb *urb;
 
 		rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
 								&rb->dma);
-		if (!rb->base) {
-			dev_err(&intf->dev, "out of memory "
-					"(read bufs usb_alloc_coherent)\n");
+		if (!rb->base)
 			goto alloc_fail6;
-		}
 		rb->index = i;
 		rb->instance = acm;
 
 		urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!urb) {
-			dev_err(&intf->dev,
-				"out of memory (read urbs usb_alloc_urb)\n");
+		if (!urb)
 			goto alloc_fail6;
-		}
+
 		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 		urb->transfer_dma = rb->dma;
 		if (acm->is_int_ep) {
@@ -1389,11 +1388,8 @@
 		struct acm_wb *snd = &(acm->wb[i]);
 
 		snd->urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (snd->urb == NULL) {
-			dev_err(&intf->dev,
-				"out of memory (write urbs usb_alloc_urb)\n");
+		if (snd->urb == NULL)
 			goto alloc_fail7;
-		}
 
 		if (usb_endpoint_xfer_int(epwrite))
 			usb_fill_int_urb(snd->urb, usb_dev,
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 684ef70..506b969 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -22,17 +22,25 @@
  */
 
 /* FIXME tune these based on pool statistics ... */
-static const size_t	pool_max[HCD_BUFFER_POOLS] = {
-	/* platforms without dma-friendly caches might need to
-	 * prevent cacheline sharing...
-	 */
-	32,
-	128,
-	512,
-	PAGE_SIZE / 2
-	/* bigger --> allocate pages */
+static size_t pool_max[HCD_BUFFER_POOLS] = {
+	32, 128, 512, 2048,
 };
 
+void __init usb_init_pool_max(void)
+{
+	/*
+	 * The pool_max values must never be smaller than
+	 * ARCH_KMALLOC_MINALIGN.
+	 */
+	if (ARCH_KMALLOC_MINALIGN <= 32)
+		;			/* Original value is okay */
+	else if (ARCH_KMALLOC_MINALIGN <= 64)
+		pool_max[0] = 64;
+	else if (ARCH_KMALLOC_MINALIGN <= 128)
+		pool_max[0] = 0;	/* Don't use this pool */
+	else
+		BUILD_BUG();		/* We don't allow this */
+}
 
 /* SETUP primitives */
 
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0b59731..66abdbc 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1689,7 +1689,7 @@
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
 		as = async_getcompleted(ps);
-		if (as)
+		if (as || !connected(ps))
 			break;
 		if (signal_pending(current))
 			break;
@@ -1712,7 +1712,7 @@
 	}
 	if (signal_pending(current))
 		return -EINTR;
-	return -EIO;
+	return -ENODEV;
 }
 
 static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
@@ -1721,10 +1721,11 @@
 	struct async *as;
 
 	as = async_getcompleted(ps);
-	retval = -EAGAIN;
 	if (as) {
 		retval = processcompl(as, (void __user * __user *)arg);
 		free_async(as);
+	} else {
+		retval = (connected(ps) ? -EAGAIN : -ENODEV);
 	}
 	return retval;
 }
@@ -1854,7 +1855,7 @@
 	}
 	if (signal_pending(current))
 		return -EINTR;
-	return -EIO;
+	return -ENODEV;
 }
 
 static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
@@ -1862,11 +1863,12 @@
 	int retval;
 	struct async *as;
 
-	retval = -EAGAIN;
 	as = async_getcompleted(ps);
 	if (as) {
 		retval = processcompl_compat(as, (void __user * __user *)arg);
 		free_async(as);
+	} else {
+		retval = (connected(ps) ? -EAGAIN : -ENODEV);
 	}
 	return retval;
 }
@@ -2038,7 +2040,8 @@
 {
 	__u32 caps;
 
-	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
+	caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
+			USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
 	if (!ps->dev->bus->no_stop_on_short)
 		caps |= USBDEVFS_CAP_BULK_CONTINUATION;
 	if (ps->dev->bus->sg_tablesize)
@@ -2138,6 +2141,32 @@
 		return -EPERM;
 
 	usb_lock_device(dev);
+
+	/* Reap operations are allowed even after disconnection */
+	switch (cmd) {
+	case USBDEVFS_REAPURB:
+		snoop(&dev->dev, "%s: REAPURB\n", __func__);
+		ret = proc_reapurb(ps, p);
+		goto done;
+
+	case USBDEVFS_REAPURBNDELAY:
+		snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
+		ret = proc_reapurbnonblock(ps, p);
+		goto done;
+
+#ifdef CONFIG_COMPAT
+	case USBDEVFS_REAPURB32:
+		snoop(&dev->dev, "%s: REAPURB32\n", __func__);
+		ret = proc_reapurb_compat(ps, p);
+		goto done;
+
+	case USBDEVFS_REAPURBNDELAY32:
+		snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
+		ret = proc_reapurbnonblock_compat(ps, p);
+		goto done;
+#endif
+	}
+
 	if (!connected(ps)) {
 		usb_unlock_device(dev);
 		return -ENODEV;
@@ -2231,16 +2260,6 @@
 			inode->i_mtime = CURRENT_TIME;
 		break;
 
-	case USBDEVFS_REAPURB32:
-		snoop(&dev->dev, "%s: REAPURB32\n", __func__);
-		ret = proc_reapurb_compat(ps, p);
-		break;
-
-	case USBDEVFS_REAPURBNDELAY32:
-		snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
-		ret = proc_reapurbnonblock_compat(ps, p);
-		break;
-
 	case USBDEVFS_IOCTL32:
 		snoop(&dev->dev, "%s: IOCTL32\n", __func__);
 		ret = proc_ioctl_compat(ps, ptr_to_compat(p));
@@ -2252,16 +2271,6 @@
 		ret = proc_unlinkurb(ps, p);
 		break;
 
-	case USBDEVFS_REAPURB:
-		snoop(&dev->dev, "%s: REAPURB\n", __func__);
-		ret = proc_reapurb(ps, p);
-		break;
-
-	case USBDEVFS_REAPURBNDELAY:
-		snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
-		ret = proc_reapurbnonblock(ps, p);
-		break;
-
 	case USBDEVFS_DISCSIGNAL:
 		snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
 		ret = proc_disconnectsignal(ps, p);
@@ -2304,6 +2313,8 @@
 		ret = proc_free_streams(ps, p);
 		break;
 	}
+
+ done:
 	usb_unlock_device(dev);
 	if (ret >= 0)
 		inode->i_atime = CURRENT_TIME;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 874dec3..818369a 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -275,21 +275,6 @@
 	return 0;
 }
 
-/*
- * Cancel any pending scheduled resets
- *
- * [see usb_queue_reset_device()]
- *
- * Called after unconfiguring / when releasing interfaces. See
- * comments in __usb_queue_reset_device() regarding
- * udev->reset_running.
- */
-static void usb_cancel_queued_reset(struct usb_interface *iface)
-{
-	if (iface->reset_running == 0)
-		cancel_work_sync(&iface->reset_ws);
-}
-
 /* called from driver core with dev locked */
 static int usb_probe_interface(struct device *dev)
 {
@@ -380,7 +365,6 @@
 	usb_set_intfdata(intf, NULL);
 	intf->needs_remote_wakeup = 0;
 	intf->condition = USB_INTERFACE_UNBOUND;
-	usb_cancel_queued_reset(intf);
 
 	/* If the LPM disable succeeded, balance the ref counts. */
 	if (!lpm_disable_error)
@@ -425,7 +409,6 @@
 		usb_disable_interface(udev, intf, false);
 
 	driver->disconnect(intf);
-	usb_cancel_queued_reset(intf);
 
 	/* Free streams */
 	for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
@@ -1797,6 +1780,18 @@
 		dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
 		return -EOPNOTSUPP;
 	}
+
+	/*
+	 * If the device is a direct child of the root hub and the HCD
+	 * doesn't handle wakeup requests, don't allow autosuspend when
+	 * wakeup is needed.
+	 */
+	if (w && udev->parent == udev->bus->root_hub &&
+			bus_to_hcd(udev->bus)->cant_recv_wakeups) {
+		dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
+		return -EOPNOTSUPP;
+	}
+
 	udev->do_remote_wakeup = w;
 	return 0;
 }
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 11cee55..45a915c 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1618,6 +1618,7 @@
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 {
 	struct usb_hcd		*hcd;
+	struct usb_device	*udev = urb->dev;
 	int			retval = -EIDRM;
 	unsigned long		flags;
 
@@ -1629,20 +1630,19 @@
 	spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
 	if (atomic_read(&urb->use_count) > 0) {
 		retval = 0;
-		usb_get_dev(urb->dev);
+		usb_get_dev(udev);
 	}
 	spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
 	if (retval == 0) {
 		hcd = bus_to_hcd(urb->dev->bus);
 		retval = unlink1(hcd, urb, status);
-		usb_put_dev(urb->dev);
+		if (retval == 0)
+			retval = -EINPROGRESS;
+		else if (retval != -EIDRM && retval != -EBUSY)
+			dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
+					urb, retval);
+		usb_put_dev(udev);
 	}
-
-	if (retval == 0)
-		retval = -EINPROGRESS;
-	else if (retval != -EIDRM && retval != -EBUSY)
-		dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
-				urb, retval);
 	return retval;
 }
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index eaffb02..d7c3d5a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2896,10 +2896,12 @@
  */
 static int check_port_resume_type(struct usb_device *udev,
 		struct usb_hub *hub, int port1,
-		int status, unsigned portchange, unsigned portstatus)
+		int status, u16 portchange, u16 portstatus)
 {
 	struct usb_port *port_dev = hub->ports[port1 - 1];
+	int retries = 3;
 
+ retry:
 	/* Is a warm reset needed to recover the connection? */
 	if (status == 0 && udev->reset_resume
 		&& hub_port_warm_reset_required(hub, port1, portstatus)) {
@@ -2907,10 +2909,17 @@
 	}
 	/* Is the device still present? */
 	else if (status || port_is_suspended(hub, portstatus) ||
-			!port_is_power_on(hub, portstatus) ||
-			!(portstatus & USB_PORT_STAT_CONNECTION)) {
+			!port_is_power_on(hub, portstatus)) {
 		if (status >= 0)
 			status = -ENODEV;
+	} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
+		if (retries--) {
+			usleep_range(200, 300);
+			status = hub_port_status(hub, port1, &portstatus,
+							     &portchange);
+			goto retry;
+		}
+		status = -ENODEV;
 	}
 
 	/* Can't do a normal resume if the port isn't enabled,
@@ -4643,9 +4652,13 @@
 	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
 			test_bit(port1, hub->removed_bits)) {
 
-		/* maybe switch power back on (e.g. root hub was reset) */
+		/*
+		 * maybe switch power back on (e.g. root hub was reset)
+		 * but only if the port isn't owned by someone else.
+		 */
 		if (hub_is_port_power_switchable(hub)
-				&& !port_is_power_on(hub, portstatus))
+				&& !port_is_power_on(hub, portstatus)
+				&& !port_dev->port_owner)
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 
 		if (portstatus & USB_PORT_STAT_ENABLE)
@@ -4870,7 +4883,7 @@
 static void port_event(struct usb_hub *hub, int port1)
 		__must_hold(&port_dev->status_lock)
 {
-	int connect_change, reset_device = 0;
+	int connect_change;
 	struct usb_port *port_dev = hub->ports[port1 - 1];
 	struct usb_device *udev = port_dev->child;
 	struct usb_device *hdev = hub->hdev;
@@ -4958,30 +4971,14 @@
 			if (hub_port_reset(hub, port1, NULL,
 					HUB_BH_RESET_TIME, true) < 0)
 				hub_port_disable(hub, port1, 1);
-		} else
-			reset_device = 1;
-	}
-
-	/*
-	 * On disconnect USB3 protocol ports transit from U0 to
-	 * SS.Inactive to Rx.Detect. If this happens a warm-
-	 * reset is not needed, but a (re)connect may happen
-	 * before hub_wq runs and sees the disconnect, and the
-	 * device may be an unknown state.
-	 *
-	 * If the port went through SS.Inactive without hub_wq
-	 * seeing it the C_LINK_STATE change flag will be set,
-	 * and we reset the dev to put it in a known state.
-	 */
-	if (reset_device || (udev && hub_is_superspeed(hub->hdev)
-				&& (portchange & USB_PORT_STAT_C_LINK_STATE)
-				&& (portstatus & USB_PORT_STAT_CONNECTION))) {
-		usb_unlock_port(port_dev);
-		usb_lock_device(udev);
-		usb_reset_device(udev);
-		usb_unlock_device(udev);
-		usb_lock_port(port_dev);
-		connect_change = 0;
+		} else {
+			usb_unlock_port(port_dev);
+			usb_lock_device(udev);
+			usb_reset_device(udev);
+			usb_unlock_device(udev);
+			usb_lock_port(port_dev);
+			connect_change = 0;
+		}
 	}
 
 	if (connect_change)
@@ -5577,26 +5574,19 @@
  *   possible; depending on how the driver attached to each interface
  *   handles ->pre_reset(), the second reset might happen or not.
  *
- * - If a driver is unbound and it had a pending reset, the reset will
- *   be cancelled.
+ * - If the reset is delayed so long that the interface is unbound from
+ *   its driver, the reset will be skipped.
  *
- * - This function can be called during .probe() or .disconnect()
- *   times. On return from .disconnect(), any pending resets will be
- *   cancelled.
- *
- * There is no no need to lock/unlock the @reset_ws as schedule_work()
- * does its own.
- *
- * NOTE: We don't do any reference count tracking because it is not
- *     needed. The lifecycle of the work_struct is tied to the
- *     usb_interface. Before destroying the interface we cancel the
- *     work_struct, so the fact that work_struct is queued and or
- *     running means the interface (and thus, the device) exist and
- *     are referenced.
+ * - This function can be called during .probe().  It can also be called
+ *   during .disconnect(), but doing so is pointless because the reset
+ *   will not occur.  If you really want to reset the device during
+ *   .disconnect(), call usb_reset_device() directly -- but watch out
+ *   for nested unbinding issues!
  */
 void usb_queue_reset_device(struct usb_interface *iface)
 {
-	schedule_work(&iface->reset_ws);
+	if (schedule_work(&iface->reset_ws))
+		usb_get_intf(iface);
 }
 EXPORT_SYMBOL_GPL(usb_queue_reset_device);
 
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f7b7713..f368d20 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1551,6 +1551,7 @@
 			altsetting_to_usb_interface_cache(intf->altsetting);
 
 	kref_put(&intfc->ref, usb_release_interface_cache);
+	usb_put_dev(interface_to_usbdev(intf));
 	kfree(intf);
 }
 
@@ -1626,24 +1627,6 @@
 
 /*
  * Internal function to queue a device reset
- *
- * This is initialized into the workstruct in 'struct
- * usb_device->reset_ws' that is launched by
- * message.c:usb_set_configuration() when initializing each 'struct
- * usb_interface'.
- *
- * It is safe to get the USB device without reference counts because
- * the life cycle of @iface is bound to the life cycle of @udev. Then,
- * this function will be ran only if @iface is alive (and before
- * freeing it any scheduled instances of it will have been cancelled).
- *
- * We need to set a flag (usb_dev->reset_running) because when we call
- * the reset, the interfaces might be unbound. The current interface
- * cannot try to remove the queued work as it would cause a deadlock
- * (you cannot remove your work from within your executing
- * workqueue). This flag lets it know, so that
- * usb_cancel_queued_reset() doesn't try to do it.
- *
  * See usb_queue_reset_device() for more details
  */
 static void __usb_queue_reset_device(struct work_struct *ws)
@@ -1655,11 +1638,10 @@
 
 	rc = usb_lock_device_for_reset(udev, iface);
 	if (rc >= 0) {
-		iface->reset_running = 1;
 		usb_reset_device(udev);
-		iface->reset_running = 0;
 		usb_unlock_device(udev);
 	}
+	usb_put_intf(iface);	/* Undo _get_ in usb_queue_reset_device() */
 }
 
 
@@ -1854,6 +1836,7 @@
 		dev_set_name(&intf->dev, "%d-%s:%d.%d",
 			dev->bus->busnum, dev->devpath,
 			configuration, alt->desc.bInterfaceNumber);
+		usb_get_dev(dev);
 	}
 	kfree(new_interfaces);
 
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2a92b97..b1fb9ae 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1049,6 +1049,7 @@
 		pr_info("%s: USB support disabled\n", usbcore_name);
 		return 0;
 	}
+	usb_init_pool_max();
 
 	retval = usb_debugfs_init();
 	if (retval)
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index b323c4c..76b9ba4 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -23,7 +23,7 @@
 
 config USB_DWC2_HOST
 	bool "Host only mode"
-	depends on USB
+	depends on USB=y || (USB_DWC2=m && USB)
 	help
 	  The Designware USB2.0 high-speed host controller
 	  integrated into many SoCs. Select this option if you want the
@@ -42,7 +42,7 @@
 
 config USB_DWC2_DUAL_ROLE
 	bool "Dual Role mode"
-	depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
+	depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
 	help
 	  Select this option if you want the driver to work in a dual-role
 	  mode. In this mode both host and gadget features are enabled, and
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 7605850b..d5197d4 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -462,7 +462,7 @@
 	dwc2_enable_common_interrupts(hsotg);
 
 	/*
-	 * Do device or host intialization based on mode during PCD and
+	 * Do device or host initialization based on mode during PCD and
 	 * HCD initialization
 	 */
 	if (dwc2_is_host_mode(hsotg)) {
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 7a70a13..f74304b 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -108,7 +108,7 @@
  * @halted: Set if the endpoint has been halted.
  * @periodic: Set if this is a periodic ep, such as Interrupt
  * @isochronous: Set if this is a isochronous ep
- * @sent_zlp: Set if we've sent a zero-length packet.
+ * @send_zlp: Set if we need to send a zero-length packet.
  * @total_data: The total number of data bytes done.
  * @fifo_size: The size of the FIFO (for periodic IN endpoints)
  * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
@@ -149,7 +149,7 @@
 	unsigned int            halted:1;
 	unsigned int            periodic:1;
 	unsigned int            isochronous:1;
-	unsigned int            sent_zlp:1;
+	unsigned int            send_zlp:1;
 
 	char                    name[10];
 };
@@ -158,14 +158,12 @@
  * struct s3c_hsotg_req - data transfer request
  * @req: The USB gadget request
  * @queue: The list of requests for the endpoint this is queued for.
- * @in_progress: Has already had size/packets written to core
- * @mapped: DMA buffer for this request has been mapped via dma_map_single().
+ * @saved_req_buf: variable to save req.buf when bounce buffers are used.
  */
 struct s3c_hsotg_req {
 	struct usb_request      req;
 	struct list_head        queue;
-	unsigned char           in_progress;
-	unsigned char           mapped;
+	void *saved_req_buf;
 };
 
 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@@ -193,6 +191,22 @@
 	DWC2_L3,	/* Off state */
 };
 
+/*
+ * Gadget periodic tx fifo sizes as used by legacy driver
+ * EP0 is not included
+ */
+#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
+					   768, 0, 0, 0, 0, 0, 0, 0}
+
+/* Gadget ep0 states */
+enum dwc2_ep0_state {
+	DWC2_EP0_SETUP,
+	DWC2_EP0_DATA_IN,
+	DWC2_EP0_DATA_OUT,
+	DWC2_EP0_STATUS_IN,
+	DWC2_EP0_STATUS_OUT,
+};
+
 /**
  * struct dwc2_core_params - Parameters for configuring the core
  *
@@ -381,7 +395,7 @@
  * @power_optimized     Are power optimizations enabled?
  * @num_dev_ep          Number of device endpoints available
  * @num_dev_perio_in_ep Number of device periodic IN endpoints
- *                      avaialable
+ *                      available
  * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
  *                      Depth
  *                       0 to 30
@@ -434,6 +448,9 @@
 	u32 snpsid;
 };
 
+/* Size of control and EP0 buffers */
+#define DWC2_CTRL_BUFF_SIZE 8
+
 /**
  * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
  * and periodic schedules
@@ -552,14 +569,20 @@
  * @num_of_eps:         Number of available EPs (excluding EP0)
  * @debug_root:         Root directrory for debugfs.
  * @debug_file:         Main status file for debugfs.
+ * @debug_testmode:     Testmode status file for debugfs.
  * @debug_fifo:         FIFO status file for debugfs.
  * @ep0_reply:          Request used for ep0 reply.
  * @ep0_buff:           Buffer for EP0 reply data, if needed.
  * @ctrl_buff:          Buffer for EP0 control requests.
  * @ctrl_req:           Request for EP0 control packets.
- * @setup:              NAK management for EP0 SETUP
+ * @ep0_state:          EP0 control transfers state
+ * @test_mode:          USB test mode requested by the host
  * @last_rst:           Time of last reset
  * @eps:                The endpoints being supplied to the gadget framework
+ * @g_using_dma:          Indicate if dma usage is enabled
+ * @g_rx_fifo_sz:         Contains rx fifo size value
+ * @g_np_g_tx_fifo_sz:      Contains Non-Periodic tx fifo size value
+ * @g_tx_fifo_sz:         Contains tx fifo size value per endpoints
  */
 struct dwc2_hsotg {
 	struct device *dev;
@@ -591,6 +614,7 @@
 
 	struct dentry *debug_root;
 	struct dentry *debug_file;
+	struct dentry *debug_testmode;
 	struct dentry *debug_fifo;
 
 	/* DWC OTG HW Release versions */
@@ -684,15 +708,21 @@
 
 	struct usb_request *ep0_reply;
 	struct usb_request *ctrl_req;
-	u8 ep0_buff[8];
-	u8 ctrl_buff[8];
+	void *ep0_buff;
+	void *ctrl_buff;
+	enum dwc2_ep0_state ep0_state;
+	u8 test_mode;
 
 	struct usb_gadget gadget;
 	unsigned int enabled:1;
 	unsigned int connected:1;
-	unsigned int setup:1;
 	unsigned long last_rst;
-	struct s3c_hsotg_ep *eps;
+	struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
+	struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
+	u32 g_using_dma;
+	u32 g_rx_fifo_sz;
+	u32 g_np_g_tx_fifo_sz;
+	u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
 #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
 };
 
@@ -969,7 +999,8 @@
 extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
 extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
 extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
-extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
+extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+		bool reset);
 extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
 extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
 #else
@@ -981,7 +1012,8 @@
 { return 0; }
 static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
 { return 0; }
-static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
+static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+		bool reset) {}
 static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
 static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
 #endif
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 7924200..6a30887 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -35,6 +35,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/phy.h>
 #include <linux/platform_data/s3c-hsotg.h>
+#include <linux/uaccess.h>
 
 #include "core.h"
 #include "hw.h"
@@ -65,7 +66,16 @@
 	writel(readl(ptr) & ~val, ptr);
 }
 
-/* forward decleration of functions */
+static inline struct s3c_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg,
+						u32 ep_index, u32 dir_in)
+{
+	if (dir_in)
+		return hsotg->eps_in[ep_index];
+	else
+		return hsotg->eps_out[ep_index];
+}
+
+/* forward declaration of functions */
 static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg);
 
 /**
@@ -85,11 +95,11 @@
  * a core reset. This means we either need to fix the gadgets to take
  * account of DMA alignment, or add bounce buffers (yuerk).
  *
- * Until this issue is sorted out, we always return 'false'.
+ * g_using_dma is set depending on dts flag.
  */
 static inline bool using_dma(struct dwc2_hsotg *hsotg)
 {
-	return false;	/* support is not complete */
+	return hsotg->g_using_dma;
 }
 
 /**
@@ -165,15 +175,18 @@
 {
 	unsigned int ep;
 	unsigned int addr;
-	unsigned int size;
 	int timeout;
 	u32 val;
 
-	/* set FIFO sizes to 2048/1024 */
+	/* Reset fifo map if not correctly cleared during previous session */
+	WARN_ON(hsotg->fifo_map);
+	hsotg->fifo_map = 0;
 
-	writel(2048, hsotg->regs + GRXFSIZ);
-	writel((2048 << FIFOSIZE_STARTADDR_SHIFT) |
-		(1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ);
+	/* set RX/NPTX FIFO sizes */
+	writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ);
+	writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) |
+		(hsotg->g_np_g_tx_fifo_sz << FIFOSIZE_DEPTH_SHIFT),
+		hsotg->regs + GNPTXFSIZ);
 
 	/*
 	 * arange all the rest of the TX FIFOs, as some versions of this
@@ -183,35 +196,21 @@
 	 */
 
 	/* start at the end of the GNPTXFSIZ, rounded up */
-	addr = 2048 + 1024;
+	addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz;
 
 	/*
-	 * Because we have not enough memory to have each TX FIFO of size at
-	 * least 3072 bytes (the maximum single packet size), we create four
-	 * FIFOs of lenght 1024, and four of length 3072 bytes, and assing
+	 * Configure fifos sizes from provided configuration and assign
 	 * them to endpoints dynamically according to maxpacket size value of
 	 * given endpoint.
 	 */
-
-	/* 256*4=1024 bytes FIFO length */
-	size = 256;
-	for (ep = 1; ep <= 4; ep++) {
+	for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
+		if (!hsotg->g_tx_fifo_sz[ep])
+			continue;
 		val = addr;
-		val |= size << FIFOSIZE_DEPTH_SHIFT;
-		WARN_ONCE(addr + size > hsotg->fifo_mem,
+		val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
+		WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
 			  "insufficient fifo memory");
-		addr += size;
-
-		writel(val, hsotg->regs + DPTXFSIZN(ep));
-	}
-	/* 768*4=3072 bytes FIFO length */
-	size = 768;
-	for (ep = 5; ep <= 8; ep++) {
-		val = addr;
-		val |= size << FIFOSIZE_DEPTH_SHIFT;
-		WARN_ONCE(addr + size > hsotg->fifo_mem,
-			  "insufficient fifo memory");
-		addr += size;
+		addr += hsotg->g_tx_fifo_sz[ep];
 
 		writel(val, hsotg->regs + DPTXFSIZN(ep));
 	}
@@ -236,6 +235,7 @@
 			dev_err(hsotg->dev,
 				"%s: timeout flushing fifos (GRSTCTL=%08x)\n",
 				__func__, val);
+			break;
 		}
 
 		udelay(1);
@@ -566,11 +566,6 @@
 	length = ureq->length - ureq->actual;
 	dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
 		ureq->length, ureq->actual);
-	if (0)
-		dev_dbg(hsotg->dev,
-			"REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n",
-			ureq->buf, length, &ureq->dma,
-			ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
 
 	maxreq = get_ep_limit(hs_ep);
 	if (length > maxreq) {
@@ -604,14 +599,15 @@
 	else
 		epsize = 0;
 
-	if (index != 0 && ureq->zero) {
-		/*
-		 * test for the packets being exactly right for the
-		 * transfer
-		 */
-
-		if (length == (packets * hs_ep->ep.maxpacket))
-			packets++;
+	/*
+	 * zero length packet should be programmed on its own and should not
+	 * be counted in DIEPTSIZ.PktCnt with other packets.
+	 */
+	if (dir_in && ureq->zero && !continuing) {
+		/* Test if zlp is actually required. */
+		if ((ureq->length >= hs_ep->ep.maxpacket) &&
+					!(ureq->length % hs_ep->ep.maxpacket))
+			hs_ep->send_zlp = 1;
 	}
 
 	epsize |= DXEPTSIZ_PKTCNT(packets);
@@ -644,15 +640,12 @@
 	ctrl |= DXEPCTL_EPENA;	/* ensure ep enabled */
 	ctrl |= DXEPCTL_USBACTEP;
 
-	dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup);
+	dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
 
 	/* For Setup request do not clear NAK */
-	if (hsotg->setup && index == 0)
-		hsotg->setup = 0;
-	else
+	if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP))
 		ctrl |= DXEPCTL_CNAK;	/* clear NAK set by core */
 
-
 	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
 	writel(ctrl, hsotg->regs + epctrl_reg);
 
@@ -686,7 +679,7 @@
 
 	/* check ep is enabled */
 	if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA))
-		dev_warn(hsotg->dev,
+		dev_dbg(hsotg->dev,
 			 "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n",
 			 index, readl(hsotg->regs + epctrl_reg));
 
@@ -733,6 +726,59 @@
 	return -EIO;
 }
 
+static int s3c_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg,
+	struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+	void *req_buf = hs_req->req.buf;
+
+	/* If dma is not being used or buffer is aligned */
+	if (!using_dma(hsotg) || !((long)req_buf & 3))
+		return 0;
+
+	WARN_ON(hs_req->saved_req_buf);
+
+	dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__,
+			hs_ep->ep.name, req_buf, hs_req->req.length);
+
+	hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC);
+	if (!hs_req->req.buf) {
+		hs_req->req.buf = req_buf;
+		dev_err(hsotg->dev,
+			"%s: unable to allocate memory for bounce buffer\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Save actual buffer */
+	hs_req->saved_req_buf = req_buf;
+
+	if (hs_ep->dir_in)
+		memcpy(hs_req->req.buf, req_buf, hs_req->req.length);
+	return 0;
+}
+
+static void s3c_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
+	struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+	/* If dma is not being used or buffer was aligned */
+	if (!using_dma(hsotg) || !hs_req->saved_req_buf)
+		return;
+
+	dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__,
+		hs_ep->ep.name, hs_req->req.status, hs_req->req.actual);
+
+	/* Copy data from bounce buffer on successful out transfer */
+	if (!hs_ep->dir_in && !hs_req->req.status)
+		memcpy(hs_req->saved_req_buf, hs_req->req.buf,
+							hs_req->req.actual);
+
+	/* Free bounce buffer */
+	kfree(hs_req->req.buf);
+
+	hs_req->req.buf = hs_req->saved_req_buf;
+	hs_req->saved_req_buf = NULL;
+}
+
 static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
 			      gfp_t gfp_flags)
 {
@@ -740,6 +786,7 @@
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct dwc2_hsotg *hs = hs_ep->parent;
 	bool first;
+	int ret;
 
 	dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
 		ep->name, req, req->length, req->buf, req->no_interrupt,
@@ -750,9 +797,13 @@
 	req->actual = 0;
 	req->status = -EINPROGRESS;
 
+	ret = s3c_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req);
+	if (ret)
+		return ret;
+
 	/* if we're using DMA, sync the buffers as necessary */
 	if (using_dma(hs)) {
-		int ret = s3c_hsotg_map_dma(hs, hs_ep, req);
+		ret = s3c_hsotg_map_dma(hs, hs_ep, req);
 		if (ret)
 			return ret;
 	}
@@ -819,7 +870,7 @@
 static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
 					   u32 windex)
 {
-	struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F];
+	struct s3c_hsotg_ep *ep;
 	int dir = (windex & USB_DIR_IN) ? 1 : 0;
 	int idx = windex & 0x7F;
 
@@ -829,6 +880,8 @@
 	if (idx > hsotg->num_of_eps)
 		return NULL;
 
+	ep = index_to_ep(hsotg, idx, dir);
+
 	if (idx && ep->dir_in != dir)
 		return NULL;
 
@@ -836,6 +889,32 @@
 }
 
 /**
+ * s3c_hsotg_set_test_mode - Enable usb Test Modes
+ * @hsotg: The driver state.
+ * @testmode: requested usb test mode
+ * Enable usb Test Mode requested by the Host.
+ */
+static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
+{
+	int dctl = readl(hsotg->regs + DCTL);
+
+	dctl &= ~DCTL_TSTCTL_MASK;
+	switch (testmode) {
+	case TEST_J:
+	case TEST_K:
+	case TEST_SE0_NAK:
+	case TEST_PACKET:
+	case TEST_FORCE_EN:
+		dctl |= testmode << DCTL_TSTCTL_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	writel(dctl, hsotg->regs + DCTL);
+	return 0;
+}
+
+/**
  * s3c_hsotg_send_reply - send reply to control request
  * @hsotg: The device state
  * @ep: Endpoint 0
@@ -864,13 +943,15 @@
 
 	req->buf = hsotg->ep0_buff;
 	req->length = length;
-	req->zero = 1; /* always do zero-length final transfer */
+	/*
+	 * zero flag is for sending zlp in DATA IN stage. It has no impact on
+	 * STATUS stage.
+	 */
+	req->zero = 0;
 	req->complete = s3c_hsotg_complete_oursetup;
 
 	if (length)
 		memcpy(req->buf, buff, length);
-	else
-		ep->sent_zlp = 1;
 
 	ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC);
 	if (ret) {
@@ -889,7 +970,7 @@
 static int s3c_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
 					struct usb_ctrlrequest *ctrl)
 {
-	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+	struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
 	struct s3c_hsotg_ep *ep;
 	__le16 reply;
 	int ret;
@@ -953,33 +1034,62 @@
 }
 
 /**
- * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
+ * s3c_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
  * @hsotg: The device state
  * @ctrl: USB control request
  */
 static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
 					 struct usb_ctrlrequest *ctrl)
 {
-	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+	struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
 	struct s3c_hsotg_req *hs_req;
 	bool restart;
 	bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
 	struct s3c_hsotg_ep *ep;
 	int ret;
 	bool halted;
+	u32 recip;
+	u32 wValue;
+	u32 wIndex;
 
 	dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
 		__func__, set ? "SET" : "CLEAR");
 
-	if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
-		ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
+	wValue = le16_to_cpu(ctrl->wValue);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		switch (wValue) {
+		case USB_DEVICE_TEST_MODE:
+			if ((wIndex & 0xff) != 0)
+				return -EINVAL;
+			if (!set)
+				return -EINVAL;
+
+			hsotg->test_mode = wIndex >> 8;
+			ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
+			if (ret) {
+				dev_err(hsotg->dev,
+					"%s: failed to send reply\n", __func__);
+				return ret;
+			}
+			break;
+		default:
+			return -ENOENT;
+		}
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		ep = ep_from_windex(hsotg, wIndex);
 		if (!ep) {
 			dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
-				__func__, le16_to_cpu(ctrl->wIndex));
+				__func__, wIndex);
 			return -ENOENT;
 		}
 
-		switch (le16_to_cpu(ctrl->wValue)) {
+		switch (wValue) {
 		case USB_ENDPOINT_HALT:
 			halted = ep->halted;
 
@@ -1006,16 +1116,22 @@
 					hs_req = ep->req;
 					ep->req = NULL;
 					list_del_init(&hs_req->queue);
-					usb_gadget_giveback_request(&ep->ep,
-								    &hs_req->req);
+					if (hs_req->req.complete) {
+						spin_unlock(&hsotg->lock);
+						usb_gadget_giveback_request(
+							&ep->ep, &hs_req->req);
+						spin_lock(&hsotg->lock);
+					}
 				}
 
 				/* If we have pending request, then start it */
-				restart = !list_empty(&ep->queue);
-				if (restart) {
-					hs_req = get_ep_head(ep);
-					s3c_hsotg_start_req(hsotg, ep,
-							    hs_req, false);
+				if (!ep->req) {
+					restart = !list_empty(&ep->queue);
+					if (restart) {
+						hs_req = get_ep_head(ep);
+						s3c_hsotg_start_req(hsotg, ep,
+								hs_req, false);
+					}
 				}
 			}
 
@@ -1024,9 +1140,10 @@
 		default:
 			return -ENOENT;
 		}
-	} else
-		return -ENOENT;  /* currently only deal with endpoint */
-
+		break;
+	default:
+		return -ENOENT;
+	}
 	return 1;
 }
 
@@ -1040,7 +1157,7 @@
  */
 static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
 {
-	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+	struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
 	u32 reg;
 	u32 ctrl;
 
@@ -1080,34 +1197,29 @@
 static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg,
 				      struct usb_ctrlrequest *ctrl)
 {
-	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+	struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
 	int ret = 0;
 	u32 dcfg;
 
-	ep0->sent_zlp = 0;
-
 	dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n",
 		 ctrl->bRequest, ctrl->bRequestType,
 		 ctrl->wValue, ctrl->wLength);
 
-	/*
-	 * record the direction of the request, for later use when enquing
-	 * packets onto EP0.
-	 */
-
-	ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
-	dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
-
-	/*
-	 * if we've no data with this request, then the last part of the
-	 * transaction is going to implicitly be IN.
-	 */
-	if (ctrl->wLength == 0)
+	if (ctrl->wLength == 0) {
 		ep0->dir_in = 1;
+		hsotg->ep0_state = DWC2_EP0_STATUS_IN;
+	} else if (ctrl->bRequestType & USB_DIR_IN) {
+		ep0->dir_in = 1;
+		hsotg->ep0_state = DWC2_EP0_DATA_IN;
+	} else {
+		ep0->dir_in = 0;
+		hsotg->ep0_state = DWC2_EP0_DATA_OUT;
+	}
 
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
 		switch (ctrl->bRequest) {
 		case USB_REQ_SET_ADDRESS:
+			hsotg->connected = 1;
 			dcfg = readl(hsotg->regs + DCFG);
 			dcfg &= ~DCFG_DEVADDR_MASK;
 			dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -1201,9 +1313,11 @@
 		return;
 	}
 
-	hsotg->eps[0].dir_in = 0;
+	hsotg->eps_out[0]->dir_in = 0;
+	hsotg->eps_out[0]->send_zlp = 0;
+	hsotg->ep0_state = DWC2_EP0_SETUP;
 
-	ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
+	ret = s3c_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC);
 	if (ret < 0) {
 		dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
 		/*
@@ -1213,6 +1327,32 @@
 	}
 }
 
+static void s3c_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
+					struct s3c_hsotg_ep *hs_ep)
+{
+	u32 ctrl;
+	u8 index = hs_ep->index;
+	u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
+	u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
+
+	if (hs_ep->dir_in)
+		dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n",
+									index);
+	else
+		dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n",
+									index);
+
+	writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
+			DXEPTSIZ_XFERSIZE(0), hsotg->regs +
+			epsiz_reg);
+
+	ctrl = readl(hsotg->regs + epctl_reg);
+	ctrl |= DXEPCTL_CNAK;  /* clear NAK set by core */
+	ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
+	ctrl |= DXEPCTL_USBACTEP;
+	writel(ctrl, hsotg->regs + epctl_reg);
+}
+
 /**
  * s3c_hsotg_complete_request - complete a request given to us
  * @hsotg: The device state.
@@ -1249,6 +1389,8 @@
 	if (hs_req->req.status == -EINPROGRESS)
 		hs_req->req.status = result;
 
+	s3c_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req);
+
 	hs_ep->req = NULL;
 	list_del_init(&hs_req->queue);
 
@@ -1293,7 +1435,7 @@
  */
 static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
 {
-	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
+	struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx];
 	struct s3c_hsotg_req *hs_req = hs_ep->req;
 	void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
 	int to_read;
@@ -1305,7 +1447,7 @@
 		u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
 		int ptr;
 
-		dev_warn(hsotg->dev,
+		dev_dbg(hsotg->dev,
 			 "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n",
 			 __func__, size, ep_idx, epctl);
 
@@ -1345,9 +1487,9 @@
 }
 
 /**
- * s3c_hsotg_send_zlp - send zero-length packet on control endpoint
+ * s3c_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint
  * @hsotg: The device instance
- * @req: The request currently on this endpoint
+ * @dir_in: If IN zlp
  *
  * Generate a zero-length IN packet request for terminating a SETUP
  * transaction.
@@ -1356,53 +1498,28 @@
  * currently believed that we do not need to wait for any space in
  * the TxFIFO.
  */
-static void s3c_hsotg_send_zlp(struct dwc2_hsotg *hsotg,
-			       struct s3c_hsotg_req *req)
+static void s3c_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in)
 {
-	u32 ctrl;
+	/* eps_out[0] is used in both directions */
+	hsotg->eps_out[0]->dir_in = dir_in;
+	hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT;
 
-	if (!req) {
-		dev_warn(hsotg->dev, "%s: no request?\n", __func__);
-		return;
-	}
-
-	if (req->req.length == 0) {
-		hsotg->eps[0].sent_zlp = 1;
-		s3c_hsotg_enqueue_setup(hsotg);
-		return;
-	}
-
-	hsotg->eps[0].dir_in = 1;
-	hsotg->eps[0].sent_zlp = 1;
-
-	dev_dbg(hsotg->dev, "sending zero-length packet\n");
-
-	/* issue a zero-sized packet to terminate this */
-	writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
-	       DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0));
-
-	ctrl = readl(hsotg->regs + DIEPCTL0);
-	ctrl |= DXEPCTL_CNAK;  /* clear NAK set by core */
-	ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
-	ctrl |= DXEPCTL_USBACTEP;
-	writel(ctrl, hsotg->regs + DIEPCTL0);
+	s3c_hsotg_program_zlp(hsotg, hsotg->eps_out[0]);
 }
 
 /**
  * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
  * @hsotg: The device instance
  * @epnum: The endpoint received from
- * @was_setup: Set if processing a SetupDone event.
  *
  * The RXFIFO has delivered an OutDone event, which means that the data
  * transfer for an OUT endpoint has been completed, either by a short
  * packet or by the finish of a transfer.
  */
-static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
-				     int epnum, bool was_setup)
+static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
 {
 	u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
-	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
+	struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[epnum];
 	struct s3c_hsotg_req *hs_req = hs_ep->req;
 	struct usb_request *req = &hs_req->req;
 	unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
@@ -1413,6 +1530,13 @@
 		return;
 	}
 
+	if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) {
+		dev_dbg(hsotg->dev, "zlp packet received\n");
+		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+		s3c_hsotg_enqueue_setup(hsotg);
+		return;
+	}
+
 	if (using_dma(hsotg)) {
 		unsigned size_done;
 
@@ -1435,12 +1559,6 @@
 	if (req->actual < req->length && size_left == 0) {
 		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
 		return;
-	} else if (epnum == 0) {
-		/*
-		 * After was_setup = 1 =>
-		 * set CNAK for non Setup requests
-		 */
-		hsotg->setup = was_setup ? 0 : 1;
 	}
 
 	if (req->actual < req->length && req->short_not_ok) {
@@ -1453,13 +1571,10 @@
 		 */
 	}
 
-	if (epnum == 0) {
-		/*
-		 * Condition req->complete != s3c_hsotg_complete_setup says:
-		 * send ZLP when we have an asynchronous request from gadget
-		 */
-		if (!was_setup && req->complete != s3c_hsotg_complete_setup)
-			s3c_hsotg_send_zlp(hsotg, hs_req);
+	if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
+		/* Move to STATUS IN */
+		s3c_hsotg_ep0_zlp(hsotg, true);
+		return;
 	}
 
 	s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
@@ -1511,8 +1626,7 @@
 	size = grxstsr & GRXSTS_BYTECNT_MASK;
 	size >>= GRXSTS_BYTECNT_SHIFT;
 
-	if (1)
-		dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
+	dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
 			__func__, grxstsr, size, epnum);
 
 	switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) {
@@ -1525,7 +1639,7 @@
 			s3c_hsotg_read_frameno(hsotg));
 
 		if (!using_dma(hsotg))
-			s3c_hsotg_handle_outdone(hsotg, epnum, false);
+			s3c_hsotg_handle_outdone(hsotg, epnum);
 		break;
 
 	case GRXSTS_PKTSTS_SETUPDONE:
@@ -1533,8 +1647,13 @@
 			"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
 			s3c_hsotg_read_frameno(hsotg),
 			readl(hsotg->regs + DOEPCTL(0)));
-
-		s3c_hsotg_handle_outdone(hsotg, epnum, true);
+		/*
+		 * Call s3c_hsotg_handle_outdone here if it was not called from
+		 * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't
+		 * generate GRXSTS_PKTSTS_OUTDONE for setup packet.
+		 */
+		if (hsotg->ep0_state == DWC2_EP0_SETUP)
+			s3c_hsotg_handle_outdone(hsotg, epnum);
 		break;
 
 	case GRXSTS_PKTSTS_OUTRX:
@@ -1547,6 +1666,8 @@
 			s3c_hsotg_read_frameno(hsotg),
 			readl(hsotg->regs + DOEPCTL(0)));
 
+		WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP);
+
 		s3c_hsotg_rx_data(hsotg, epnum, size);
 		break;
 
@@ -1591,14 +1712,18 @@
  * the hardware control registers to reflect this.
  */
 static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
-				       unsigned int ep, unsigned int mps)
+			unsigned int ep, unsigned int mps, unsigned int dir_in)
 {
-	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep];
+	struct s3c_hsotg_ep *hs_ep;
 	void __iomem *regs = hsotg->regs;
 	u32 mpsval;
 	u32 mcval;
 	u32 reg;
 
+	hs_ep = index_to_ep(hsotg, ep, dir_in);
+	if (!hs_ep)
+		return;
+
 	if (ep == 0) {
 		/* EP0 is a special case */
 		mpsval = s3c_hsotg_ep0_mps(mps);
@@ -1617,17 +1742,12 @@
 		hs_ep->ep.maxpacket = mpsval;
 	}
 
-	/*
-	 * update both the in and out endpoint controldir_ registers, even
-	 * if one of the directions may not be in use.
-	 */
-
-	reg = readl(regs + DIEPCTL(ep));
-	reg &= ~DXEPCTL_MPS_MASK;
-	reg |= mpsval;
-	writel(reg, regs + DIEPCTL(ep));
-
-	if (ep) {
+	if (dir_in) {
+		reg = readl(regs + DIEPCTL(ep));
+		reg &= ~DXEPCTL_MPS_MASK;
+		reg |= mpsval;
+		writel(reg, regs + DIEPCTL(ep));
+	} else {
 		reg = readl(regs + DOEPCTL(ep));
 		reg &= ~DXEPCTL_MPS_MASK;
 		reg |= mpsval;
@@ -1727,9 +1847,21 @@
 	}
 
 	/* Finish ZLP handling for IN EP0 transactions */
-	if (hsotg->eps[0].sent_zlp) {
-		dev_dbg(hsotg->dev, "zlp packet received\n");
+	if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
+		dev_dbg(hsotg->dev, "zlp packet sent\n");
 		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+		if (hsotg->test_mode) {
+			int ret;
+
+			ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode);
+			if (ret < 0) {
+				dev_dbg(hsotg->dev, "Invalid Test #%d\n",
+						hsotg->test_mode);
+				s3c_hsotg_stall_ep0(hsotg);
+				return;
+			}
+		}
+		s3c_hsotg_enqueue_setup(hsotg);
 		return;
 	}
 
@@ -1756,31 +1888,27 @@
 	dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
 		hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
 
-	/*
-	 * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
-	 * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
-	 * ,256B ... ), after last MPS sized packet send IN ZLP packet to
-	 * inform the host that no more data is available.
-	 * The state of req.zero member is checked to be sure that the value to
-	 * send is smaller than wValue expected from host.
-	 * Check req.length to NOT send another ZLP when the current one is
-	 * under completion (the one for which this completion has been called).
-	 */
-	if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
-	    hs_req->req.length == hs_req->req.actual &&
-	    !(hs_req->req.length % hs_ep->ep.maxpacket)) {
-
-		dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
-		s3c_hsotg_send_zlp(hsotg, hs_req);
-
-		return;
-	}
-
 	if (!size_left && hs_req->req.actual < hs_req->req.length) {
 		dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
 		s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
-	} else
-		s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+		return;
+	}
+
+	/* Zlp for all endpoints, for ep0 only in DATA IN stage */
+	if (hs_ep->send_zlp) {
+		s3c_hsotg_program_zlp(hsotg, hs_ep);
+		hs_ep->send_zlp = 0;
+		/* transfer will be completed on next complete interrupt */
+		return;
+	}
+
+	if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) {
+		/* Move to STATUS OUT */
+		s3c_hsotg_ep0_zlp(hsotg, false);
+		return;
+	}
+
+	s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
 }
 
 /**
@@ -1794,7 +1922,7 @@
 static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
 			    int dir_in)
 {
-	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
+	struct s3c_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in);
 	u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
 	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
 	u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
@@ -1807,9 +1935,19 @@
 	/* Clear endpoint interrupts */
 	writel(ints, hsotg->regs + epint_reg);
 
+	if (!hs_ep) {
+		dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n",
+					__func__, idx, dir_in ? "in" : "out");
+		return;
+	}
+
 	dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
 		__func__, idx, dir_in ? "in" : "out", ints);
 
+	/* Don't process XferCompl interrupt if it is a setup packet */
+	if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
+		ints &= ~DXEPINT_XFERCOMPL;
+
 	if (ints & DXEPINT_XFERCOMPL) {
 		if (hs_ep->isochronous && hs_ep->interval == 1) {
 			if (ctrl & DXEPCTL_EOFRNUM)
@@ -1839,7 +1977,7 @@
 			 * as we ignore the RXFIFO.
 			 */
 
-			s3c_hsotg_handle_outdone(hsotg, idx, false);
+			s3c_hsotg_handle_outdone(hsotg, idx);
 		}
 	}
 
@@ -1878,7 +2016,7 @@
 			if (dir_in)
 				WARN_ON_ONCE(1);
 			else
-				s3c_hsotg_handle_outdone(hsotg, 0, true);
+				s3c_hsotg_handle_outdone(hsotg, 0);
 		}
 	}
 
@@ -1969,9 +2107,15 @@
 
 	if (ep0_mps) {
 		int i;
-		s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
-		for (i = 1; i < hsotg->num_of_eps; i++)
-			s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
+		/* Initialize ep0 for both in and out directions */
+		s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 1);
+		s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0);
+		for (i = 1; i < hsotg->num_of_eps; i++) {
+			if (hsotg->eps_in[i])
+				s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 1);
+			if (hsotg->eps_out[i])
+				s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 0);
+		}
 	}
 
 	/* ensure after enumeration our EP0 is active */
@@ -1988,30 +2132,23 @@
  * @hsotg: The device state.
  * @ep: The endpoint the requests may be on.
  * @result: The result code to use.
- * @force: Force removal of any current requests
  *
  * Go through the requests on the given endpoint and mark them
  * completed with the given result code.
  */
 static void kill_all_requests(struct dwc2_hsotg *hsotg,
 			      struct s3c_hsotg_ep *ep,
-			      int result, bool force)
+			      int result)
 {
 	struct s3c_hsotg_req *req, *treq;
 	unsigned size;
 
-	list_for_each_entry_safe(req, treq, &ep->queue, queue) {
-		/*
-		 * currently, we can't do much about an already
-		 * running request on an in endpoint
-		 */
+	ep->req = NULL;
 
-		if (ep->req == req && ep->dir_in && !force)
-			continue;
-
+	list_for_each_entry_safe(req, treq, &ep->queue, queue)
 		s3c_hsotg_complete_request(hsotg, ep, req,
 					   result);
-	}
+
 	if (!hsotg->dedicated_fifos)
 		return;
 	size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
@@ -2035,8 +2172,16 @@
 		return;
 
 	hsotg->connected = 0;
-	for (ep = 0; ep < hsotg->num_of_eps; ep++)
-		kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
+	hsotg->test_mode = 0;
+
+	for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+		if (hsotg->eps_in[ep])
+			kill_all_requests(hsotg, hsotg->eps_in[ep],
+								-ESHUTDOWN);
+		if (hsotg->eps_out[ep])
+			kill_all_requests(hsotg, hsotg->eps_out[ep],
+								-ESHUTDOWN);
+	}
 
 	call_gadget(hsotg, disconnect);
 }
@@ -2053,9 +2198,11 @@
 	int epno, ret;
 
 	/* look through for any more data to transmit */
-
 	for (epno = 0; epno < hsotg->num_of_eps; epno++) {
-		ep = &hsotg->eps[epno];
+		ep = index_to_ep(hsotg, epno, 1);
+
+		if (!ep)
+			continue;
 
 		if (!ep->dir_in)
 			continue;
@@ -2129,9 +2276,13 @@
  *
  * Issue a soft reset to the core, and await the core finishing it.
  */
-void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
+void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
+						bool is_usb_reset)
 {
-	s3c_hsotg_corereset(hsotg);
+	u32 val;
+
+	if (!is_usb_reset)
+		s3c_hsotg_corereset(hsotg);
 
 	/*
 	 * we must now enable ep0 ready for host detection and then
@@ -2139,14 +2290,16 @@
 	 */
 
 	/* set the PLL on, remove the HNP/SRP and set the PHY */
+	val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
 	writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
-	       (0x5 << 10), hsotg->regs + GUSBCFG);
+	       (val << GUSBCFG_USBTRDTIM_SHIFT), hsotg->regs + GUSBCFG);
 
 	s3c_hsotg_init_fifo(hsotg);
 
-	__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+	if (!is_usb_reset)
+		__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
 
-	writel(1 << 18 | DCFG_DEVSPD_HS,  hsotg->regs + DCFG);
+	writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS,  hsotg->regs + DCFG);
 
 	/* Clear any pending OTG interrupts */
 	writel(0xffffffff, hsotg->regs + GOTGINT);
@@ -2163,7 +2316,7 @@
 
 	if (using_dma(hsotg))
 		writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
-		       GAHBCFG_HBSTLEN_INCR4,
+		       (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT),
 		       hsotg->regs + GAHBCFG);
 	else
 		writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL |
@@ -2177,8 +2330,8 @@
 	 * interrupts.
 	 */
 
-	writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY |
-		DIEPMSK_INTKNTXFEMPMSK : 0) |
+	writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
+		DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
 		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
 		DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
 		DIEPMSK_INTKNEPMISMSK,
@@ -2215,9 +2368,11 @@
 	s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
 	s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
 
-	__orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
-	udelay(10);  /* see openiboot */
-	__bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+	if (!is_usb_reset) {
+		__orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+		udelay(10);  /* see openiboot */
+		__bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+	}
 
 	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
 
@@ -2230,13 +2385,13 @@
 	writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
 	       DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0);
 
-	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+	writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
 	       DXEPCTL_CNAK | DXEPCTL_EPENA |
 	       DXEPCTL_USBACTEP,
 	       hsotg->regs + DOEPCTL0);
 
 	/* enable, but don't activate EP0in */
-	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+	writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
 	       DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
 
 	s3c_hsotg_enqueue_setup(hsotg);
@@ -2246,8 +2401,10 @@
 		readl(hsotg->regs + DOEPCTL0));
 
 	/* clear global NAKs */
-	writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON,
-	       hsotg->regs + DCTL);
+	val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
+	if (!is_usb_reset)
+		val |= DCTL_SFTDISCON;
+	__orr32(hsotg->regs + DCTL, val);
 
 	/* must be at-least 3ms to allow bus to see disconnect */
 	mdelay(3);
@@ -2293,7 +2450,6 @@
 		writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
 
 		s3c_hsotg_irq_enumdone(hsotg);
-		hsotg->connected = 1;
 	}
 
 	if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
@@ -2308,12 +2464,14 @@
 
 		dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
 
-		for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) {
+		for (ep = 0; ep < hsotg->num_of_eps && daint_out;
+						ep++, daint_out >>= 1) {
 			if (daint_out & 1)
 				s3c_hsotg_epint(hsotg, ep, 0);
 		}
 
-		for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) {
+		for (ep = 0; ep < hsotg->num_of_eps  && daint_in;
+						ep++, daint_in >>= 1) {
 			if (daint_in & 1)
 				s3c_hsotg_epint(hsotg, ep, 1);
 		}
@@ -2329,15 +2487,17 @@
 
 		writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);
 
+		/* Report disconnection if it is not already done. */
+		s3c_hsotg_disconnect(hsotg);
+
 		if (usb_status & GOTGCTL_BSESVLD) {
 			if (time_after(jiffies, hsotg->last_rst +
 				       msecs_to_jiffies(200))) {
 
-				kill_all_requests(hsotg, &hsotg->eps[0],
-							  -ECONNRESET, true);
+				kill_all_requests(hsotg, hsotg->eps_out[0],
+							  -ECONNRESET);
 
-				s3c_hsotg_core_init_disconnected(hsotg);
-				s3c_hsotg_core_connect(hsotg);
+				s3c_hsotg_core_init_disconnected(hsotg, true);
 			}
 		}
 	}
@@ -2429,12 +2589,12 @@
 	struct s3c_hsotg_ep *hs_ep = our_ep(ep);
 	struct dwc2_hsotg *hsotg = hs_ep->parent;
 	unsigned long flags;
-	int index = hs_ep->index;
+	unsigned int index = hs_ep->index;
 	u32 epctrl_reg;
 	u32 epctrl;
 	u32 mps;
-	int dir_in;
-	int i, val, size;
+	unsigned int dir_in;
+	unsigned int i, val, size;
 	int ret = 0;
 
 	dev_dbg(hsotg->dev,
@@ -2482,7 +2642,7 @@
 	epctrl |= DXEPCTL_SNAK;
 
 	/* update the endpoint state */
-	s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps);
+	s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);
 
 	/* default, set to non-periodic */
 	hs_ep->isochronous = 0;
@@ -2518,30 +2678,48 @@
 		break;
 	}
 
+	/* If fifo is already allocated for this ep */
+	if (hs_ep->fifo_index) {
+		size =  hs_ep->ep.maxpacket * hs_ep->mc;
+		/* If bigger fifo is required deallocate current one */
+		if (size > hs_ep->fifo_size) {
+			hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
+			hs_ep->fifo_index = 0;
+			hs_ep->fifo_size = 0;
+		}
+	}
+
 	/*
 	 * if the hardware has dedicated fifos, we must give each IN EP
 	 * a unique tx-fifo even if it is non-periodic.
 	 */
-	if (dir_in && hsotg->dedicated_fifos) {
+	if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) {
+		u32 fifo_index = 0;
+		u32 fifo_size = UINT_MAX;
 		size = hs_ep->ep.maxpacket*hs_ep->mc;
-		for (i = 1; i <= 8; ++i) {
+		for (i = 1; i < hsotg->num_of_eps; ++i) {
 			if (hsotg->fifo_map & (1<<i))
 				continue;
 			val = readl(hsotg->regs + DPTXFSIZN(i));
 			val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
 			if (val < size)
 				continue;
-			hsotg->fifo_map |= 1<<i;
-
-			epctrl |= DXEPCTL_TXFNUM(i);
-			hs_ep->fifo_index = i;
-			hs_ep->fifo_size = val;
-			break;
+			/* Search for smallest acceptable fifo */
+			if (val < fifo_size) {
+				fifo_size = val;
+				fifo_index = i;
+			}
 		}
-		if (i == 8) {
+		if (!fifo_index) {
+			dev_err(hsotg->dev,
+				"%s: No suitable fifo found\n", __func__);
 			ret = -ENOMEM;
 			goto error;
 		}
+		hsotg->fifo_map |= 1 << fifo_index;
+		epctrl |= DXEPCTL_TXFNUM(fifo_index);
+		hs_ep->fifo_index = fifo_index;
+		hs_ep->fifo_size = fifo_size;
 	}
 
 	/* for non control endpoints, set PID to D0 */
@@ -2579,7 +2757,7 @@
 
 	dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
 
-	if (ep == &hsotg->eps[0].ep) {
+	if (ep == &hsotg->eps_out[0]->ep) {
 		dev_err(hsotg->dev, "%s: called for ep0\n", __func__);
 		return -EINVAL;
 	}
@@ -2587,8 +2765,6 @@
 	epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
 
 	spin_lock_irqsave(&hsotg->lock, flags);
-	/* terminate all requests with shutdown */
-	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, force);
 
 	hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
 	hs_ep->fifo_index = 0;
@@ -2605,6 +2781,9 @@
 	/* disable endpoint interrupts */
 	s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
 
+	/* terminate all requests with shutdown */
+	kill_all_requests(hsotg, hs_ep, -ESHUTDOWN);
+
 	spin_unlock_irqrestore(&hsotg->lock, flags);
 	return 0;
 }
@@ -2682,40 +2861,39 @@
 		return 0;
 	}
 
-	/* write both IN and OUT control registers */
+	if (hs_ep->dir_in) {
+		epreg = DIEPCTL(index);
+		epctl = readl(hs->regs + epreg);
 
-	epreg = DIEPCTL(index);
-	epctl = readl(hs->regs + epreg);
-
-	if (value) {
-		epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
-		if (epctl & DXEPCTL_EPENA)
-			epctl |= DXEPCTL_EPDIS;
+		if (value) {
+			epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
+			if (epctl & DXEPCTL_EPENA)
+				epctl |= DXEPCTL_EPDIS;
+		} else {
+			epctl &= ~DXEPCTL_STALL;
+			xfertype = epctl & DXEPCTL_EPTYPE_MASK;
+			if (xfertype == DXEPCTL_EPTYPE_BULK ||
+				xfertype == DXEPCTL_EPTYPE_INTERRUPT)
+					epctl |= DXEPCTL_SETD0PID;
+		}
+		writel(epctl, hs->regs + epreg);
 	} else {
-		epctl &= ~DXEPCTL_STALL;
-		xfertype = epctl & DXEPCTL_EPTYPE_MASK;
-		if (xfertype == DXEPCTL_EPTYPE_BULK ||
-			xfertype == DXEPCTL_EPTYPE_INTERRUPT)
-				epctl |= DXEPCTL_SETD0PID;
+
+		epreg = DOEPCTL(index);
+		epctl = readl(hs->regs + epreg);
+
+		if (value)
+			epctl |= DXEPCTL_STALL;
+		else {
+			epctl &= ~DXEPCTL_STALL;
+			xfertype = epctl & DXEPCTL_EPTYPE_MASK;
+			if (xfertype == DXEPCTL_EPTYPE_BULK ||
+				xfertype == DXEPCTL_EPTYPE_INTERRUPT)
+					epctl |= DXEPCTL_SETD0PID;
+		}
+		writel(epctl, hs->regs + epreg);
 	}
 
-	writel(epctl, hs->regs + epreg);
-
-	epreg = DOEPCTL(index);
-	epctl = readl(hs->regs + epreg);
-
-	if (value)
-		epctl |= DXEPCTL_STALL;
-	else {
-		epctl &= ~DXEPCTL_STALL;
-		xfertype = epctl & DXEPCTL_EPTYPE_MASK;
-		if (xfertype == DXEPCTL_EPTYPE_BULK ||
-			xfertype == DXEPCTL_EPTYPE_INTERRUPT)
-				epctl |= DXEPCTL_SETD0PID;
-	}
-
-	writel(epctl, hs->regs + epreg);
-
 	hs_ep->halted = value;
 
 	return 0;
@@ -2801,6 +2979,7 @@
  */
 static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
 {
+	u32 trdtim;
 	/* unmask subset of endpoint interrupts */
 
 	writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
@@ -2816,12 +2995,6 @@
 	/* Be in disconnected state until gadget is registered */
 	__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
 
-	if (0) {
-		/* post global nak until we're ready */
-		writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK,
-		       hsotg->regs + DCTL);
-	}
-
 	/* setup fifos */
 
 	dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
@@ -2831,11 +3004,13 @@
 	s3c_hsotg_init_fifo(hsotg);
 
 	/* set the PLL on, remove the HNP/SRP and set the PHY */
-	writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10),
-	       hsotg->regs + GUSBCFG);
+	trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
+	writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
+		(trdtim << GUSBCFG_USBTRDTIM_SHIFT),
+		hsotg->regs + GUSBCFG);
 
-	writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0,
-	       hsotg->regs + GAHBCFG);
+	if (using_dma(hsotg))
+		__orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
 }
 
 /**
@@ -2889,10 +3064,12 @@
 	}
 
 	s3c_hsotg_phy_enable(hsotg);
+	if (!IS_ERR_OR_NULL(hsotg->uphy))
+		otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
 
 	spin_lock_irqsave(&hsotg->lock, flags);
 	s3c_hsotg_init(hsotg);
-	s3c_hsotg_core_init_disconnected(hsotg);
+	s3c_hsotg_core_init_disconnected(hsotg, false);
 	hsotg->enabled = 0;
 	spin_unlock_irqrestore(&hsotg->lock, flags);
 
@@ -2927,8 +3104,12 @@
 	mutex_lock(&hsotg->init_mutex);
 
 	/* all endpoints should be shutdown */
-	for (ep = 1; ep < hsotg->num_of_eps; ep++)
-		s3c_hsotg_ep_disable_force(&hsotg->eps[ep].ep, true);
+	for (ep = 1; ep < hsotg->num_of_eps; ep++) {
+		if (hsotg->eps_in[ep])
+			s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+		if (hsotg->eps_out[ep])
+			s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+	}
 
 	spin_lock_irqsave(&hsotg->lock, flags);
 
@@ -2938,6 +3119,8 @@
 
 	spin_unlock_irqrestore(&hsotg->lock, flags);
 
+	if (!IS_ERR_OR_NULL(hsotg->uphy))
+		otg_set_peripheral(hsotg->uphy->otg, NULL);
 	s3c_hsotg_phy_disable(hsotg);
 
 	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
@@ -2979,9 +3162,11 @@
 	if (is_on) {
 		clk_enable(hsotg->clk);
 		hsotg->enabled = 1;
+		s3c_hsotg_core_init_disconnected(hsotg, false);
 		s3c_hsotg_core_connect(hsotg);
 	} else {
 		s3c_hsotg_core_disconnect(hsotg);
+		s3c_hsotg_disconnect(hsotg);
 		hsotg->enabled = 0;
 		clk_disable(hsotg->clk);
 	}
@@ -2993,11 +3178,52 @@
 	return 0;
 }
 
+static int s3c_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+	unsigned long flags;
+
+	dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active);
+	spin_lock_irqsave(&hsotg->lock, flags);
+
+	if (is_active) {
+		/* Kill any ep0 requests as controller will be reinitialized */
+		kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
+		s3c_hsotg_core_init_disconnected(hsotg, false);
+		if (hsotg->enabled)
+			s3c_hsotg_core_connect(hsotg);
+	} else {
+		s3c_hsotg_core_disconnect(hsotg);
+		s3c_hsotg_disconnect(hsotg);
+	}
+
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+	return 0;
+}
+
+/**
+ * s3c_hsotg_vbus_draw - report bMaxPower field
+ * @gadget: The usb gadget state
+ * @mA: Amount of current
+ *
+ * Report how much power the device may consume to the phy.
+ */
+static int s3c_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+	struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+
+	if (IS_ERR_OR_NULL(hsotg->uphy))
+		return -ENOTSUPP;
+	return usb_phy_set_power(hsotg->uphy, mA);
+}
+
 static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.udc_start		= s3c_hsotg_udc_start,
 	.udc_stop		= s3c_hsotg_udc_stop,
 	.pullup                 = s3c_hsotg_pullup,
+	.vbus_session		= s3c_hsotg_vbus_session,
+	.vbus_draw		= s3c_hsotg_vbus_draw,
 };
 
 /**
@@ -3012,19 +3238,19 @@
  */
 static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
 				       struct s3c_hsotg_ep *hs_ep,
-				       int epnum)
+				       int epnum,
+				       bool dir_in)
 {
 	char *dir;
 
 	if (epnum == 0)
 		dir = "";
-	else if ((epnum % 2) == 0) {
-		dir = "out";
-	} else {
+	else if (dir_in)
 		dir = "in";
-		hs_ep->dir_in = 1;
-	}
+	else
+		dir = "out";
 
+	hs_ep->dir_in = dir_in;
 	hs_ep->index = epnum;
 
 	snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir);
@@ -3048,8 +3274,10 @@
 
 	if (using_dma(hsotg)) {
 		u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15);
-		writel(next, hsotg->regs + DIEPCTL(epnum));
-		writel(next, hsotg->regs + DOEPCTL(epnum));
+		if (dir_in)
+			writel(next, hsotg->regs + DIEPCTL(epnum));
+		else
+			writel(next, hsotg->regs + DOEPCTL(epnum));
 	}
 }
 
@@ -3059,24 +3287,56 @@
  *
  * Read the USB core HW configuration registers
  */
-static void s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
+static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
 {
-	u32 cfg2, cfg3, cfg4;
+	u32 cfg;
+	u32 ep_type;
+	u32 i;
+
 	/* check hardware configuration */
 
-	cfg2 = readl(hsotg->regs + 0x48);
-	hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
+	cfg = readl(hsotg->regs + GHWCFG2);
+	hsotg->num_of_eps = (cfg >> GHWCFG2_NUM_DEV_EP_SHIFT) & 0xF;
+	/* Add ep0 */
+	hsotg->num_of_eps++;
 
-	cfg3 = readl(hsotg->regs + 0x4C);
-	hsotg->fifo_mem = (cfg3 >> 16);
+	hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct s3c_hsotg_ep),
+								GFP_KERNEL);
+	if (!hsotg->eps_in[0])
+		return -ENOMEM;
+	/* Same s3c_hsotg_ep is used in both directions for ep0 */
+	hsotg->eps_out[0] = hsotg->eps_in[0];
 
-	cfg4 = readl(hsotg->regs + 0x50);
-	hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
+	cfg = readl(hsotg->regs + GHWCFG1);
+	for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) {
+		ep_type = cfg & 3;
+		/* Direction in or both */
+		if (!(ep_type & 2)) {
+			hsotg->eps_in[i] = devm_kzalloc(hsotg->dev,
+				sizeof(struct s3c_hsotg_ep), GFP_KERNEL);
+			if (!hsotg->eps_in[i])
+				return -ENOMEM;
+		}
+		/* Direction out or both */
+		if (!(ep_type & 1)) {
+			hsotg->eps_out[i] = devm_kzalloc(hsotg->dev,
+				sizeof(struct s3c_hsotg_ep), GFP_KERNEL);
+			if (!hsotg->eps_out[i])
+				return -ENOMEM;
+		}
+	}
+
+	cfg = readl(hsotg->regs + GHWCFG3);
+	hsotg->fifo_mem = (cfg >> GHWCFG3_DFIFO_DEPTH_SHIFT);
+
+	cfg = readl(hsotg->regs + GHWCFG4);
+	hsotg->dedicated_fifos = (cfg >> GHWCFG4_DED_FIFO_SHIFT) & 1;
 
 	dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
 		 hsotg->num_of_eps,
 		 hsotg->dedicated_fifos ? "dedicated" : "shared",
 		 hsotg->fifo_mem);
+	return 0;
 }
 
 /**
@@ -3095,22 +3355,22 @@
 		 readl(regs + DCFG), readl(regs + DCTL),
 		 readl(regs + DIEPMSK));
 
-	dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
-		 readl(regs + GAHBCFG), readl(regs + 0x44));
+	dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n",
+		 readl(regs + GAHBCFG), readl(regs + GHWCFG1));
 
 	dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
 		 readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
 
 	/* show periodic fifo settings */
 
-	for (idx = 1; idx <= 15; idx++) {
+	for (idx = 1; idx < hsotg->num_of_eps; idx++) {
 		val = readl(regs + DPTXFSIZN(idx));
 		dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
 			 val >> FIFOSIZE_DEPTH_SHIFT,
 			 val & FIFOSIZE_STARTADDR_MASK);
 	}
 
-	for (idx = 0; idx < 15; idx++) {
+	for (idx = 0; idx < hsotg->num_of_eps; idx++) {
 		dev_info(dev,
 			 "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
 			 readl(regs + DIEPCTL(idx)),
@@ -3132,6 +3392,103 @@
 }
 
 /**
+ * testmode_write - debugfs: change usb test mode
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry modify the current usb test mode.
+ */
+static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
+		count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc2_hsotg	*hsotg = s->private;
+	unsigned long		flags;
+	u32			testmode = 0;
+	char			buf[32];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "test_j", 6))
+		testmode = TEST_J;
+	else if (!strncmp(buf, "test_k", 6))
+		testmode = TEST_K;
+	else if (!strncmp(buf, "test_se0_nak", 12))
+		testmode = TEST_SE0_NAK;
+	else if (!strncmp(buf, "test_packet", 11))
+		testmode = TEST_PACKET;
+	else if (!strncmp(buf, "test_force_enable", 17))
+		testmode = TEST_FORCE_EN;
+	else
+		testmode = 0;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+	s3c_hsotg_set_test_mode(hsotg, testmode);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+	return count;
+}
+
+/**
+ * testmode_show - debugfs: show usb test mode state
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows which usb test mode is currently enabled.
+ */
+static int testmode_show(struct seq_file *s, void *unused)
+{
+	struct dwc2_hsotg *hsotg = s->private;
+	unsigned long flags;
+	int dctl;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+	dctl = readl(hsotg->regs + DCTL);
+	dctl &= DCTL_TSTCTL_MASK;
+	dctl >>= DCTL_TSTCTL_SHIFT;
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+
+	switch (dctl) {
+	case 0:
+		seq_puts(s, "no test\n");
+		break;
+	case TEST_J:
+		seq_puts(s, "test_j\n");
+		break;
+	case TEST_K:
+		seq_puts(s, "test_k\n");
+		break;
+	case TEST_SE0_NAK:
+		seq_puts(s, "test_se0_nak\n");
+		break;
+	case TEST_PACKET:
+		seq_puts(s, "test_packet\n");
+		break;
+	case TEST_FORCE_EN:
+		seq_puts(s, "test_force_enable\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %d\n", dctl);
+	}
+
+	return 0;
+}
+
+static int testmode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, testmode_show, inode->i_private);
+}
+
+static const struct file_operations testmode_fops = {
+	.owner		= THIS_MODULE,
+	.open		= testmode_open,
+	.write		= testmode_write,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/**
  * state_show - debugfs: show overall driver and device state.
  * @seq: The seq file to write to.
  * @v: Unused parameter.
@@ -3168,7 +3525,7 @@
 
 	seq_puts(seq, "\nEndpoint status:\n");
 
-	for (idx = 0; idx < 15; idx++) {
+	for (idx = 0; idx < hsotg->num_of_eps; idx++) {
 		u32 in, out;
 
 		in = readl(regs + DIEPCTL(idx));
@@ -3227,7 +3584,7 @@
 
 	seq_puts(seq, "\nPeriodic TXFIFOs:\n");
 
-	for (idx = 1; idx <= 15; idx++) {
+	for (idx = 1; idx < hsotg->num_of_eps; idx++) {
 		val = readl(regs + DPTXFSIZN(idx));
 
 		seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
@@ -3359,29 +3716,53 @@
 
 	/* create general state file */
 
-	hsotg->debug_file = debugfs_create_file("state", 0444, root,
+	hsotg->debug_file = debugfs_create_file("state", S_IRUGO, root,
 						hsotg, &state_fops);
 
 	if (IS_ERR(hsotg->debug_file))
 		dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
 
-	hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
+	hsotg->debug_testmode = debugfs_create_file("testmode",
+					S_IRUGO | S_IWUSR, root,
+					hsotg, &testmode_fops);
+
+	if (IS_ERR(hsotg->debug_testmode))
+		dev_err(hsotg->dev, "%s: failed to create testmode\n",
+				__func__);
+
+	hsotg->debug_fifo = debugfs_create_file("fifo", S_IRUGO, root,
 						hsotg, &fifo_fops);
 
 	if (IS_ERR(hsotg->debug_fifo))
 		dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__);
 
-	/* create one file for each endpoint */
-
+	/* Create one file for each out endpoint */
 	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
-		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
+		struct s3c_hsotg_ep *ep;
 
-		ep->debugfs = debugfs_create_file(ep->name, 0444,
-						  root, ep, &ep_fops);
+		ep = hsotg->eps_out[epidx];
+		if (ep) {
+			ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
+							  root, ep, &ep_fops);
 
-		if (IS_ERR(ep->debugfs))
-			dev_err(hsotg->dev, "failed to create %s debug file\n",
-				ep->name);
+			if (IS_ERR(ep->debugfs))
+				dev_err(hsotg->dev, "failed to create %s debug file\n",
+					ep->name);
+		}
+	}
+	/* Create one file for each in endpoint. EP0 is handled with out eps */
+	for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
+		struct s3c_hsotg_ep *ep;
+
+		ep = hsotg->eps_in[epidx];
+		if (ep) {
+			ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
+							  root, ep, &ep_fops);
+
+			if (IS_ERR(ep->debugfs))
+				dev_err(hsotg->dev, "failed to create %s debug file\n",
+					ep->name);
+		}
 	}
 }
 
@@ -3396,15 +3777,63 @@
 	unsigned epidx;
 
 	for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
-		struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
-		debugfs_remove(ep->debugfs);
+		if (hsotg->eps_in[epidx])
+			debugfs_remove(hsotg->eps_in[epidx]->debugfs);
+		if (hsotg->eps_out[epidx])
+			debugfs_remove(hsotg->eps_out[epidx]->debugfs);
 	}
 
 	debugfs_remove(hsotg->debug_file);
+	debugfs_remove(hsotg->debug_testmode);
 	debugfs_remove(hsotg->debug_fifo);
 	debugfs_remove(hsotg->debug_root);
 }
 
+#ifdef CONFIG_OF
+static void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg)
+{
+	struct device_node *np = hsotg->dev->of_node;
+	u32 len = 0;
+	u32 i = 0;
+
+	/* Enable dma if requested in device tree */
+	hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma");
+
+	/*
+	* Register TX periodic fifo size per endpoint.
+	* EP0 is excluded since it has no fifo configuration.
+	*/
+	if (!of_find_property(np, "g-tx-fifo-size", &len))
+		goto rx_fifo;
+
+	len /= sizeof(u32);
+
+	/* Read tx fifo sizes other than ep0 */
+	if (of_property_read_u32_array(np, "g-tx-fifo-size",
+						&hsotg->g_tx_fifo_sz[1], len))
+		goto rx_fifo;
+
+	/* Add ep0 */
+	len++;
+
+	/* Make remaining TX fifos unavailable */
+	if (len < MAX_EPS_CHANNELS) {
+		for (i = len; i < MAX_EPS_CHANNELS; i++)
+			hsotg->g_tx_fifo_sz[i] = 0;
+	}
+
+rx_fifo:
+	/* Register RX fifo size */
+	of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz);
+
+	/* Register NPTX fifo size */
+	of_property_read_u32(np, "g-np-tx-fifo-size",
+						&hsotg->g_np_g_tx_fifo_sz);
+}
+#else
+static inline void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg) { }
+#endif
+
 /**
  * dwc2_gadget_init - init function for gadget
  * @dwc2: The data structure for the DWC2 driver.
@@ -3414,41 +3843,47 @@
 {
 	struct device *dev = hsotg->dev;
 	struct s3c_hsotg_plat *plat = dev->platform_data;
-	struct phy *phy;
-	struct usb_phy *uphy;
-	struct s3c_hsotg_ep *eps;
 	int epnum;
 	int ret;
 	int i;
+	u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
 
 	/* Set default UTMI width */
 	hsotg->phyif = GUSBCFG_PHYIF16;
 
+	s3c_hsotg_of_probe(hsotg);
+
+	/* Initialize to legacy fifo configuration values */
+	hsotg->g_rx_fifo_sz = 2048;
+	hsotg->g_np_g_tx_fifo_sz = 1024;
+	memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
+	/* Device tree specific probe */
+	s3c_hsotg_of_probe(hsotg);
+	/* Dump fifo information */
+	dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
+						hsotg->g_np_g_tx_fifo_sz);
+	dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
+	for (i = 0; i < MAX_EPS_CHANNELS; i++)
+		dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
+						hsotg->g_tx_fifo_sz[i]);
 	/*
-	 * Attempt to find a generic PHY, then look for an old style
-	 * USB PHY, finally fall back to pdata
+	 * If platform probe couldn't find a generic PHY or an old style
+	 * USB PHY, fall back to pdata
 	 */
-	phy = devm_phy_get(dev, "usb2-phy");
-	if (IS_ERR(phy)) {
-		uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
-		if (IS_ERR(uphy)) {
-			/* Fallback for pdata */
-			plat = dev_get_platdata(dev);
-			if (!plat) {
-				dev_err(dev,
-				"no platform data or transceiver defined\n");
-				return -EPROBE_DEFER;
-			}
-			hsotg->plat = plat;
-		} else
-			hsotg->uphy = uphy;
-	} else {
-		hsotg->phy = phy;
+	if (IS_ERR_OR_NULL(hsotg->phy) && IS_ERR_OR_NULL(hsotg->uphy)) {
+		plat = dev_get_platdata(dev);
+		if (!plat) {
+			dev_err(dev,
+			"no platform data or transceiver defined\n");
+			return -EPROBE_DEFER;
+		}
+		hsotg->plat = plat;
+	} else if (hsotg->phy) {
 		/*
 		 * If using the generic PHY framework, check if the PHY bus
 		 * width is 8-bit and set the phyif appropriately.
 		 */
-		if (phy_get_bus_width(phy) == 8)
+		if (phy_get_bus_width(hsotg->phy) == 8)
 			hsotg->phyif = GUSBCFG_PHYIF8;
 	}
 
@@ -3488,16 +3923,53 @@
 
 	if (ret) {
 		dev_err(dev, "failed to enable supplies: %d\n", ret);
-		goto err_supplies;
+		goto err_clk;
 	}
 
 	/* usb phy enable */
 	s3c_hsotg_phy_enable(hsotg);
 
+	/*
+	 * Force Device mode before initialization.
+	 * This allows correctly configuring fifo for device mode.
+	 */
+	__bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEHOSTMODE);
+	__orr32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
+	/*
+	 * According to Synopsys databook, this sleep is needed for the force
+	 * device mode to take effect.
+	 */
+	msleep(25);
+
 	s3c_hsotg_corereset(hsotg);
-	s3c_hsotg_hw_cfg(hsotg);
+	ret = s3c_hsotg_hw_cfg(hsotg);
+	if (ret) {
+		dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret);
+		goto err_clk;
+	}
+
 	s3c_hsotg_init(hsotg);
 
+	/* Switch back to default configuration */
+	__bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
+	hsotg->ctrl_buff = devm_kzalloc(hsotg->dev,
+			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
+	if (!hsotg->ctrl_buff) {
+		dev_err(dev, "failed to allocate ctrl request buff\n");
+		ret = -ENOMEM;
+		goto err_supplies;
+	}
+
+	hsotg->ep0_buff = devm_kzalloc(hsotg->dev,
+			DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
+	if (!hsotg->ep0_buff) {
+		dev_err(dev, "failed to allocate ctrl reply buff\n");
+		ret = -ENOMEM;
+		goto err_supplies;
+	}
+
 	ret = devm_request_irq(hsotg->dev, irq, s3c_hsotg_irq, IRQF_SHARED,
 				dev_name(hsotg->dev), hsotg);
 	if (ret < 0) {
@@ -3506,7 +3978,7 @@
 		regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
 				       hsotg->supplies);
 		dev_err(dev, "cannot claim IRQ for gadget\n");
-		goto err_clk;
+		goto err_supplies;
 	}
 
 	/* hsotg->num_of_eps holds number of EPs other than ep0 */
@@ -3517,33 +3989,30 @@
 		goto err_supplies;
 	}
 
-	eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep),
-		      GFP_KERNEL);
-	if (!eps) {
-		ret = -ENOMEM;
-		goto err_supplies;
-	}
-
-	hsotg->eps = eps;
-
 	/* setup endpoint information */
 
 	INIT_LIST_HEAD(&hsotg->gadget.ep_list);
-	hsotg->gadget.ep0 = &hsotg->eps[0].ep;
+	hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
 
 	/* allocate EP0 request */
 
-	hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep,
+	hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
 						     GFP_KERNEL);
 	if (!hsotg->ctrl_req) {
 		dev_err(dev, "failed to allocate ctrl req\n");
 		ret = -ENOMEM;
-		goto err_ep_mem;
+		goto err_supplies;
 	}
 
 	/* initialise the endpoints now the core has been initialised */
-	for (epnum = 0; epnum < hsotg->num_of_eps; epnum++)
-		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+	for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) {
+		if (hsotg->eps_in[epnum])
+			s3c_hsotg_initep(hsotg, hsotg->eps_in[epnum],
+								epnum, 1);
+		if (hsotg->eps_out[epnum])
+			s3c_hsotg_initep(hsotg, hsotg->eps_out[epnum],
+								epnum, 0);
+	}
 
 	/* disable power and clock */
 	s3c_hsotg_phy_disable(hsotg);
@@ -3552,12 +4021,12 @@
 				    hsotg->supplies);
 	if (ret) {
 		dev_err(dev, "failed to disable supplies: %d\n", ret);
-		goto err_ep_mem;
+		goto err_supplies;
 	}
 
 	ret = usb_add_gadget_udc(dev, &hsotg->gadget);
 	if (ret)
-		goto err_ep_mem;
+		goto err_supplies;
 
 	s3c_hsotg_create_debug(hsotg);
 
@@ -3565,8 +4034,6 @@
 
 	return 0;
 
-err_ep_mem:
-	kfree(eps);
 err_supplies:
 	s3c_hsotg_phy_disable(hsotg);
 err_clk:
@@ -3612,8 +4079,12 @@
 
 		s3c_hsotg_phy_disable(hsotg);
 
-		for (ep = 0; ep < hsotg->num_of_eps; ep++)
-			s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
+		for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+			if (hsotg->eps_in[ep])
+				s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+			if (hsotg->eps_out[ep])
+				s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+		}
 
 		ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
 					     hsotg->supplies);
@@ -3644,7 +4115,7 @@
 		s3c_hsotg_phy_enable(hsotg);
 
 		spin_lock_irqsave(&hsotg->lock, flags);
-		s3c_hsotg_core_init_disconnected(hsotg);
+		s3c_hsotg_core_init_disconnected(hsotg, false);
 		if (hsotg->enabled)
 			s3c_hsotg_core_connect(hsotg);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index a0cd9db..c78c874 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -316,10 +316,12 @@
  */
 static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
 {
-	if (hsotg->lx_state == DWC2_L2)
+	if (hsotg->lx_state == DWC2_L2) {
 		hsotg->flags.b.port_suspend_change = 1;
-	else
+		usb_hcd_resume_root_hub(hsotg->priv);
+	} else {
 		hsotg->flags.b.port_l1_change = 1;
+	}
 }
 
 /**
@@ -1371,7 +1373,7 @@
 		hsotg->op_state = OTG_STATE_B_PERIPHERAL;
 		dwc2_core_init(hsotg, false, -1);
 		dwc2_enable_global_interrupts(hsotg);
-		s3c_hsotg_core_init_disconnected(hsotg);
+		s3c_hsotg_core_init_disconnected(hsotg, false);
 		s3c_hsotg_core_connect(hsotg);
 	} else {
 		/* A-Device connector (Host Mode) */
@@ -1473,30 +1475,6 @@
 	}
 }
 
-static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
-{
-	u32 hprt0;
-
-	/* After clear the Stop PHY clock bit, we should wait for a moment
-	 * for PLL work stable with clock output.
-	 */
-	writel(0, hsotg->regs + PCGCTL);
-	usleep_range(2000, 4000);
-
-	hprt0 = dwc2_read_hprt0(hsotg);
-	hprt0 |= HPRT0_RES;
-	writel(hprt0, hsotg->regs + HPRT0);
-	hprt0 &= ~HPRT0_SUSP;
-	/* according to USB2.0 Spec 7.1.7.7, the host must send the resume
-	 * signal for at least 20ms
-	 */
-	usleep_range(20000, 25000);
-
-	hprt0 &= ~HPRT0_RES;
-	writel(hprt0, hsotg->regs + HPRT0);
-	hsotg->lx_state = DWC2_L0;
-}
-
 /* Handles hub class-specific requests */
 static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 				u16 wvalue, u16 windex, char *buf, u16 wlength)
@@ -1542,7 +1520,17 @@
 		case USB_PORT_FEAT_SUSPEND:
 			dev_dbg(hsotg->dev,
 				"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
-			dwc2_port_resume(hsotg);
+			writel(0, hsotg->regs + PCGCTL);
+			usleep_range(20000, 40000);
+
+			hprt0 = dwc2_read_hprt0(hsotg);
+			hprt0 |= HPRT0_RES;
+			writel(hprt0, hsotg->regs + HPRT0);
+			hprt0 &= ~HPRT0_SUSP;
+			usleep_range(100000, 150000);
+
+			hprt0 &= ~HPRT0_RES;
+			writel(hprt0, hsotg->regs + HPRT0);
 			break;
 
 		case USB_PORT_FEAT_POWER:
@@ -1622,7 +1610,9 @@
 		hub_desc->bDescLength = 9;
 		hub_desc->bDescriptorType = 0x29;
 		hub_desc->bNbrPorts = 1;
-		hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
+		hub_desc->wHubCharacteristics =
+			cpu_to_le16(HUB_CHAR_COMMON_LPSM |
+				    HUB_CHAR_INDV_PORT_OCPM);
 		hub_desc->bPwrOn2PwrGood = 1;
 		hub_desc->bHubContrCurrent = 0;
 		hub_desc->u.hs.DeviceRemovable[0] = 0;
@@ -2315,55 +2305,6 @@
 	usleep_range(1000, 3000);
 }
 
-static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
-{
-	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-	u32 hprt0;
-
-	if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
-		(hsotg->op_state == OTG_STATE_A_HOST)))
-		return 0;
-
-	/* TODO: We get into suspend from 'on' state, maybe we need to do
-	 * something if we get here from DWC2_L1(LPM sleep) state one day.
-	 */
-	if (hsotg->lx_state != DWC2_L0)
-		return 0;
-
-	hprt0 = dwc2_read_hprt0(hsotg);
-	if (hprt0 & HPRT0_CONNSTS) {
-		dwc2_port_suspend(hsotg, 1);
-	} else {
-		u32 pcgctl = readl(hsotg->regs + PCGCTL);
-
-		pcgctl |= PCGCTL_STOPPCLK;
-		writel(pcgctl, hsotg->regs + PCGCTL);
-	}
-
-	return 0;
-}
-
-static int _dwc2_hcd_resume(struct usb_hcd *hcd)
-{
-	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-	u32 hprt0;
-
-	if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
-		(hsotg->op_state == OTG_STATE_A_HOST)))
-		return 0;
-
-	if (hsotg->lx_state != DWC2_L2)
-		return 0;
-
-	hprt0 = dwc2_read_hprt0(hsotg);
-	if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
-		dwc2_port_resume(hsotg);
-	else
-		writel(0, hsotg->regs + PCGCTL);
-
-	return 0;
-}
-
 /* Returns the current frame number */
 static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
 {
@@ -2734,9 +2675,6 @@
 	.hub_status_data = _dwc2_hcd_hub_status_data,
 	.hub_control = _dwc2_hcd_hub_control,
 	.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
-
-	.bus_suspend = _dwc2_hcd_suspend,
-	.bus_resume = _dwc2_hcd_resume,
 };
 
 /*
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 51248b9..d0a5ed8 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -294,6 +294,7 @@
 #define GHWCFG4_NUM_IN_EPS_MASK			(0xf << 26)
 #define GHWCFG4_NUM_IN_EPS_SHIFT		26
 #define GHWCFG4_DED_FIFO_EN			(1 << 25)
+#define GHWCFG4_DED_FIFO_SHIFT		25
 #define GHWCFG4_SESSION_END_FILT_EN		(1 << 24)
 #define GHWCFG4_B_VALID_FILT_EN			(1 << 23)
 #define GHWCFG4_A_VALID_FILT_EN			(1 << 22)
@@ -541,6 +542,7 @@
 
 #define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20))
 #define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_SETUP_RCVD		(1 << 15)
 #define DXEPINT_INEPNAKEFF		(1 << 6)
 #define DXEPINT_BACK2BACKSETUP		(1 << 6)
 #define DXEPINT_INTKNEPMIS		(1 << 5)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 6a795aa..ae095f0 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -155,6 +155,8 @@
 	struct dwc2_core_params defparams;
 	struct dwc2_hsotg *hsotg;
 	struct resource *res;
+	struct phy *phy;
+	struct usb_phy *uphy;
 	int retval;
 	int irq;
 
@@ -212,6 +214,24 @@
 
 	hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
 
+	/*
+	 * Attempt to find a generic PHY, then look for an old style
+	 * USB PHY
+	 */
+	phy = devm_phy_get(&dev->dev, "usb2-phy");
+	if (IS_ERR(phy)) {
+		hsotg->phy = NULL;
+		uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
+		if (IS_ERR(uphy))
+			hsotg->uphy = NULL;
+		else
+			hsotg->uphy = uphy;
+	} else {
+		hsotg->phy = phy;
+		phy_power_on(hsotg->phy);
+		phy_init(hsotg->phy);
+	}
+
 	spin_lock_init(&hsotg->lock);
 	mutex_init(&hsotg->init_mutex);
 	retval = dwc2_gadget_init(hsotg, irq);
@@ -231,8 +251,15 @@
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (dwc2_is_device_mode(dwc2))
+	if (dwc2_is_device_mode(dwc2)) {
 		ret = s3c_hsotg_suspend(dwc2);
+	} else {
+		if (dwc2->lx_state == DWC2_L0)
+			return 0;
+		phy_exit(dwc2->phy);
+		phy_power_off(dwc2->phy);
+
+	}
 	return ret;
 }
 
@@ -241,8 +268,13 @@
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 	int ret = 0;
 
-	if (dwc2_is_device_mode(dwc2))
+	if (dwc2_is_device_mode(dwc2)) {
 		ret = s3c_hsotg_resume(dwc2);
+	} else {
+		phy_power_on(dwc2->phy);
+		phy_init(dwc2->phy);
+
+	}
 	return ret;
 }
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 58b5b2c..edbf9c8 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -104,12 +104,6 @@
 	help
 	  Say Y here to enable debugging messages on DWC3 Driver.
 
-config USB_DWC3_VERBOSE
-	bool "Enable Verbose Debugging Messages"
-	depends on USB_DWC3_DEBUG
-	help
-	  Say Y here to enable verbose debugging messages on DWC3 Driver.
-
 config DWC3_HOST_USB3_LPM_ENABLE
 	bool "Enable USB3 LPM Capability"
 	depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index bb34fbc..46172f4 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -2,7 +2,6 @@
 CFLAGS_trace.o				:= -I$(src)
 
 ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
-ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
 
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 25ddc39..9f0e209 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -345,7 +345,7 @@
 	dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
 	dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
 
-	dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
+	dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
 			dwc->num_in_eps, dwc->num_out_eps);
 }
 
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4bb9aa6..d201910 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -431,7 +431,6 @@
  * @dwc: pointer to DWC controller
  * @saved_state: ep state saved during hibernation
  * @flags: endpoint flags (wedged, stalled, ...)
- * @current_trb: index of current used trb
  * @number: endpoint number (1 - 15)
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @resource_index: Resource transfer index
@@ -464,8 +463,6 @@
 	/* This last one is specific to EP0 */
 #define DWC3_EP0_DIR_IN		(1 << 31)
 
-	unsigned		current_trb;
-
 	u8			number;
 	u8			type;
 	u8			resource_index;
@@ -685,7 +682,6 @@
  * @is_utmi_l1_suspend: the core asserts output signal
  * 	0	- utmi_sleep_n
  * 	1	- utmi_l1_suspend_n
- * @is_selfpowered: true when we are selfpowered
  * @is_fpga: true when we are using the FPGA board
  * @needs_fifo_resize: not all users might want fifo resizing, flag it
  * @pullups_connected: true when Run/Stop bit is set
@@ -809,7 +805,6 @@
 	unsigned		has_hibernation:1;
 	unsigned		has_lpm_erratum:1;
 	unsigned		is_utmi_l1_suspend:1;
-	unsigned		is_selfpowered:1;
 	unsigned		is_fpga:1;
 	unsigned		needs_fifo_resize:1;
 	unsigned		pullups_connected:1;
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index b642a2f..8d95056 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -22,9 +22,6 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 
-#include <linux/usb/otg.h>
-#include <linux/usb/usb_phy_generic.h>
-
 #include "platform_data.h"
 
 /* FIXME define these in <linux/pci_ids.h> */
@@ -36,66 +33,41 @@
 #define PCI_DEVICE_ID_INTEL_SPTLP	0x9d30
 #define PCI_DEVICE_ID_INTEL_SPTH	0xa130
 
-struct dwc3_pci {
-	struct device		*dev;
-	struct platform_device	*dwc3;
-	struct platform_device	*usb2_phy;
-	struct platform_device	*usb3_phy;
-};
-
-static int dwc3_pci_register_phys(struct dwc3_pci *glue)
+static int dwc3_pci_quirks(struct pci_dev *pdev)
 {
-	struct usb_phy_generic_platform_data pdata;
-	struct platform_device	*pdev;
-	int			ret;
+	if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+	    pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
+		struct dwc3_platform_data pdata;
 
-	memset(&pdata, 0x00, sizeof(pdata));
+		memset(&pdata, 0, sizeof(pdata));
 
-	pdev = platform_device_alloc("usb_phy_generic", 0);
-	if (!pdev)
-		return -ENOMEM;
+		pdata.has_lpm_erratum = true;
+		pdata.lpm_nyet_threshold = 0xf;
 
-	glue->usb2_phy = pdev;
-	pdata.type = USB_PHY_TYPE_USB2;
-	pdata.gpio_reset = -1;
+		pdata.u2exit_lfps_quirk = true;
+		pdata.u2ss_inp3_quirk = true;
+		pdata.req_p1p2p3_quirk = true;
+		pdata.del_p1p2p3_quirk = true;
+		pdata.del_phy_power_chg_quirk = true;
+		pdata.lfps_filter_quirk = true;
+		pdata.rx_detect_poll_quirk = true;
 
-	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
-	if (ret)
-		goto err1;
+		pdata.tx_de_emphasis_quirk = true;
+		pdata.tx_de_emphasis = 1;
 
-	pdev = platform_device_alloc("usb_phy_generic", 1);
-	if (!pdev) {
-		ret = -ENOMEM;
-		goto err1;
+		/*
+		 * FIXME these quirks should be removed when AMD NL
+		 * taps out
+		 */
+		pdata.disable_scramble_quirk = true;
+		pdata.dis_u3_susphy_quirk = true;
+		pdata.dis_u2_susphy_quirk = true;
+
+		return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
+						sizeof(pdata));
 	}
 
-	glue->usb3_phy = pdev;
-	pdata.type = USB_PHY_TYPE_USB3;
-
-	ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
-	if (ret)
-		goto err2;
-
-	ret = platform_device_add(glue->usb2_phy);
-	if (ret)
-		goto err2;
-
-	ret = platform_device_add(glue->usb3_phy);
-	if (ret)
-		goto err3;
-
 	return 0;
-
-err3:
-	platform_device_del(glue->usb2_phy);
-
-err2:
-	platform_device_put(glue->usb3_phy);
-
-err1:
-	platform_device_put(glue->usb2_phy);
-
-	return ret;
 }
 
 static int dwc3_pci_probe(struct pci_dev *pci,
@@ -103,18 +75,8 @@
 {
 	struct resource		res[2];
 	struct platform_device	*dwc3;
-	struct dwc3_pci		*glue;
 	int			ret;
 	struct device		*dev = &pci->dev;
-	struct dwc3_platform_data dwc3_pdata;
-
-	memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
-
-	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
-	if (!glue)
-		return -ENOMEM;
-
-	glue->dev = dev;
 
 	ret = pcim_enable_device(pci);
 	if (ret) {
@@ -124,12 +86,6 @@
 
 	pci_set_master(pci);
 
-	ret = dwc3_pci_register_phys(glue);
-	if (ret) {
-		dev_err(dev, "couldn't register PHYs\n");
-		return ret;
-	}
-
 	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 	if (!dwc3) {
 		dev_err(dev, "couldn't allocate dwc3 device\n");
@@ -147,70 +103,34 @@
 	res[1].name	= "dwc_usb3";
 	res[1].flags	= IORESOURCE_IRQ;
 
-	if (pci->vendor == PCI_VENDOR_ID_AMD &&
-			pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
-		dwc3_pdata.has_lpm_erratum = true;
-		dwc3_pdata.lpm_nyet_threshold = 0xf;
-
-		dwc3_pdata.u2exit_lfps_quirk = true;
-		dwc3_pdata.u2ss_inp3_quirk = true;
-		dwc3_pdata.req_p1p2p3_quirk = true;
-		dwc3_pdata.del_p1p2p3_quirk = true;
-		dwc3_pdata.del_phy_power_chg_quirk = true;
-		dwc3_pdata.lfps_filter_quirk = true;
-		dwc3_pdata.rx_detect_poll_quirk = true;
-
-		dwc3_pdata.tx_de_emphasis_quirk = true;
-		dwc3_pdata.tx_de_emphasis = 1;
-
-		/*
-		 * FIXME these quirks should be removed when AMD NL
-		 * taps out
-		 */
-		dwc3_pdata.disable_scramble_quirk = true;
-		dwc3_pdata.dis_u3_susphy_quirk = true;
-		dwc3_pdata.dis_u2_susphy_quirk = true;
-	}
-
 	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 	if (ret) {
 		dev_err(dev, "couldn't add resources to dwc3 device\n");
 		return ret;
 	}
 
-	pci_set_drvdata(pci, glue);
-
-	ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
+	pci_set_drvdata(pci, dwc3);
+	ret = dwc3_pci_quirks(pci);
 	if (ret)
-		goto err3;
+		goto err;
 
-	dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
-
-	dwc3->dev.dma_mask = dev->dma_mask;
-	dwc3->dev.dma_parms = dev->dma_parms;
 	dwc3->dev.parent = dev;
-	glue->dwc3 = dwc3;
 
 	ret = platform_device_add(dwc3);
 	if (ret) {
 		dev_err(dev, "failed to register dwc3 device\n");
-		goto err3;
+		goto err;
 	}
 
 	return 0;
-
-err3:
+err:
 	platform_device_put(dwc3);
 	return ret;
 }
 
 static void dwc3_pci_remove(struct pci_dev *pci)
 {
-	struct dwc3_pci	*glue = pci_get_drvdata(pci);
-
-	platform_device_unregister(glue->dwc3);
-	platform_device_unregister(glue->usb2_phy);
-	platform_device_unregister(glue->usb3_phy);
+	platform_device_unregister(pci_get_drvdata(pci));
 }
 
 static const struct pci_device_id dwc3_pci_id_table[] = {
@@ -228,45 +148,11 @@
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
-#ifdef CONFIG_PM_SLEEP
-static int dwc3_pci_suspend(struct device *dev)
-{
-	struct pci_dev	*pci = to_pci_dev(dev);
-
-	pci_disable_device(pci);
-
-	return 0;
-}
-
-static int dwc3_pci_resume(struct device *dev)
-{
-	struct pci_dev	*pci = to_pci_dev(dev);
-	int		ret;
-
-	ret = pci_enable_device(pci);
-	if (ret) {
-		dev_err(dev, "can't re-enable device --> %d\n", ret);
-		return ret;
-	}
-
-	pci_set_master(pci);
-
-	return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
-};
-
 static struct pci_driver dwc3_pci_driver = {
 	.name		= "dwc3-pci",
 	.id_table	= dwc3_pci_id_table,
 	.probe		= dwc3_pci_probe,
 	.remove		= dwc3_pci_remove,
-	.driver		= {
-		.pm	= &dwc3_pci_dev_pm_ops,
-	},
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1bc77a3..2ef3c8d 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -344,7 +344,7 @@
 		/*
 		 * LTM will be set once we know how to set this in HW.
 		 */
-		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+		usb_status |= dwc->gadget.is_selfpowered;
 
 		if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
 			reg = dwc3_readl(dwc->regs, DWC3_DCTL);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8f65ab3..a03a485 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -139,7 +139,8 @@
 		udelay(5);
 	}
 
-	dev_vdbg(dwc->dev, "link state change request timed out\n");
+	dwc3_trace(trace_dwc3_gadget,
+			"link state change request timed out");
 
 	return -ETIMEDOUT;
 }
@@ -219,7 +220,7 @@
 
 		fifo_size |= (last_fifo_depth << 16);
 
-		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+		dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
 				dep->name, last_fifo_depth, fifo_size & 0xffff);
 
 		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
@@ -287,7 +288,8 @@
 	do {
 		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
 		if (!(reg & DWC3_DGCMD_CMDACT)) {
-			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+			dwc3_trace(trace_dwc3_gadget,
+					"Command Complete --> %d",
 					DWC3_DGCMD_STATUS(reg));
 			return 0;
 		}
@@ -297,8 +299,11 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
+		if (!timeout) {
+			dwc3_trace(trace_dwc3_gadget,
+					"Command Timed Out");
 			return -ETIMEDOUT;
+		}
 		udelay(1);
 	} while (1);
 }
@@ -320,7 +325,8 @@
 	do {
 		reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
 		if (!(reg & DWC3_DEPCMD_CMDACT)) {
-			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+			dwc3_trace(trace_dwc3_gadget,
+					"Command Complete --> %d",
 					DWC3_DEPCMD_STATUS(reg));
 			return 0;
 		}
@@ -330,8 +336,11 @@
 		 * interrupt context.
 		 */
 		timeout--;
-		if (!timeout)
+		if (!timeout) {
+			dwc3_trace(trace_dwc3_gadget,
+					"Command Timed Out");
 			return -ETIMEDOUT;
+		}
 
 		udelay(1);
 	} while (1);
@@ -352,9 +361,6 @@
 	if (dep->trb_pool)
 		return 0;
 
-	if (dep->number == 0 || dep->number == 1)
-		return 0;
-
 	dep->trb_pool = dma_alloc_coherent(dwc->dev,
 			sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
 			&dep->trb_pool_dma, GFP_KERNEL);
@@ -492,7 +498,7 @@
 	u32			reg;
 	int			ret;
 
-	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+	dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
 
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
 		ret = dwc3_gadget_start_config(dwc, dep);
@@ -729,10 +735,9 @@
 		struct dwc3_request *req, dma_addr_t dma,
 		unsigned length, unsigned last, unsigned chain, unsigned node)
 {
-	struct dwc3		*dwc = dep->dwc;
 	struct dwc3_trb		*trb;
 
-	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+	dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
 			dep->name, req, (unsigned long long) dma,
 			length, last ? " last" : "",
 			chain ? " chain" : "");
@@ -934,7 +939,7 @@
 	u32				cmd;
 
 	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
-		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+		dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
 		return -EBUSY;
 	}
 	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
@@ -1005,8 +1010,9 @@
 	u32 uf;
 
 	if (list_empty(&dep->request_list)) {
-		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
-			dep->name);
+		dwc3_trace(trace_dwc3_gadget,
+				"ISOC ep %s run out for requests",
+				dep->name);
 		dep->flags |= DWC3_EP_PENDING_REQUEST;
 		return;
 	}
@@ -1113,15 +1119,10 @@
 	 * handled.
 	 */
 	if (dep->stream_capable) {
-		int	ret;
-
 		ret = __dwc3_gadget_kick_transfer(dep, 0, true);
-		if (ret && ret != -EBUSY) {
-			struct dwc3	*dwc = dep->dwc;
-
+		if (ret && ret != -EBUSY)
 			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
 					dep->name);
-		}
 	}
 
 	return 0;
@@ -1152,8 +1153,6 @@
 		goto out;
 	}
 
-	dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
-			request, ep->name, request->length);
 	trace_dwc3_ep_queue(req);
 
 	ret = __dwc3_gadget_ep_queue(dep, req);
@@ -1416,7 +1415,7 @@
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	dwc->is_selfpowered = !!is_selfpowered;
+	g->is_selfpowered = !!is_selfpowered;
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
@@ -1468,7 +1467,7 @@
 		udelay(1);
 	} while (1);
 
-	dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+	dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
 			dwc->gadget_driver
 			? dwc->gadget_driver->function : "no-function",
 			is_on ? "connect" : "disconnect");
@@ -1688,7 +1687,7 @@
 
 		dep->endpoint.name = dep->name;
 
-		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
+		dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
 
 		if (epnum == 0 || epnum == 1) {
 			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
@@ -1725,13 +1724,15 @@
 
 	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
 	if (ret < 0) {
-		dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+		dwc3_trace(trace_dwc3_gadget,
+				"failed to allocate OUT endpoints");
 		return ret;
 	}
 
 	ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
 	if (ret < 0) {
-		dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+		dwc3_trace(trace_dwc3_gadget,
+				"failed to allocate IN endpoints");
 		return ret;
 	}
 
@@ -1977,7 +1978,7 @@
 		} else {
 			int ret;
 
-			dev_vdbg(dwc->dev, "%s: reason %s\n",
+			dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
 					dep->name, event->status &
 					DEPEVT_STATUS_TRANSFER_ACTIVE
 					? "Transfer Active"
@@ -2001,7 +2002,8 @@
 
 		switch (event->status) {
 		case DEPEVT_STREAMEVT_FOUND:
-			dev_vdbg(dwc->dev, "Stream %d found and started\n",
+			dwc3_trace(trace_dwc3_gadget,
+					"Stream %d found and started",
 					event->parameters);
 
 			break;
@@ -2015,7 +2017,7 @@
 		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
 		break;
 	case DWC3_DEPEVT_EPCMDCMPLT:
-		dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
+		dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
 		break;
 	}
 }
@@ -2043,6 +2045,7 @@
 	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
 		spin_unlock(&dwc->lock);
 		dwc->gadget_driver->resume(&dwc->gadget);
+		spin_lock(&dwc->lock);
 	}
 }
 
@@ -2079,7 +2082,7 @@
 	 * We have discussed this with the IP Provider and it was
 	 * suggested to giveback all requests here, but give HW some
 	 * extra time to synchronize with the interconnect. We're using
-	 * an arbitraty 100us delay for that.
+	 * an arbitrary 100us delay for that.
 	 *
 	 * Note also that a similar handling was tested by Synopsys
 	 * (thanks a lot Paul) and nothing bad has come out of it.
@@ -2389,7 +2392,8 @@
 			(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
 		if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
 				(next == DWC3_LINK_STATE_RESUME)) {
-			dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+			dwc3_trace(trace_dwc3_gadget,
+					"ignoring transition U3 -> Resume");
 			return;
 		}
 	}
@@ -2511,22 +2515,22 @@
 		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
 		break;
 	case DWC3_DEVICE_EVENT_EOPF:
-		dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+		dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
 		break;
 	case DWC3_DEVICE_EVENT_SOF:
-		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+		dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
 		break;
 	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
-		dev_vdbg(dwc->dev, "Erratic Error\n");
+		dwc3_trace(trace_dwc3_gadget, "Erratic Error");
 		break;
 	case DWC3_DEVICE_EVENT_CMD_CMPL:
-		dev_vdbg(dwc->dev, "Command Complete\n");
+		dwc3_trace(trace_dwc3_gadget, "Command Complete");
 		break;
 	case DWC3_DEVICE_EVENT_OVERFLOW:
-		dev_vdbg(dwc->dev, "Overflow\n");
+		dwc3_trace(trace_dwc3_gadget, "Overflow");
 		break;
 	default:
-		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+		dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
 	}
 }
 
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 9fc20b3..9c10669 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -47,6 +47,16 @@
 	TP_ARGS(vaf)
 );
 
+DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(dwc3_log_msg, dwc3_core,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
 DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
 	TP_PROTO(struct va_format *vaf),
 	TP_ARGS(vaf)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 747ef53..9653903 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -423,6 +423,17 @@
 
 	  For more information, see Documentation/usb/gadget_hid.txt.
 
+config USB_CONFIGFS_F_UVC
+	bool "USB Webcam function"
+	depends on USB_CONFIGFS
+	depends on VIDEO_DEV
+	select VIDEOBUF2_VMALLOC
+	select USB_F_UVC
+	help
+	  The Webcam function acts as a composite USB Audio and Video Class
+	  device. It provides a userspace API to process UVC control requests
+	  and stream video data to the host.
+
 source "drivers/usb/gadget/legacy/Kconfig"
 
 endchoice
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 6178353..13adfd1 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1655,7 +1655,7 @@
 		 * OS descriptors handling
 		 */
 		if (cdev->use_os_string && cdev->os_desc_config &&
-		    (ctrl->bRequest & USB_TYPE_VENDOR) &&
+		    (ctrl->bRequestType & USB_TYPE_VENDOR) &&
 		    ctrl->bRequest == cdev->b_vendor_code) {
 			struct usb_request		*req;
 			struct usb_configuration	*os_desc_cfg;
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index dd68091..f71b1aa 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -36,7 +36,7 @@
 obj-$(CONFIG_USB_F_UAC1)	+= usb_f_uac1.o
 usb_f_uac2-y			:= f_uac2.o
 obj-$(CONFIG_USB_F_UAC2)	+= usb_f_uac2.o
-usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
+usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
 obj-$(CONFIG_USB_F_UVC)		+= usb_f_uvc.o
 usb_f_midi-y			:= f_midi.o
 obj-$(CONFIG_USB_F_MIDI)	+= usb_f_midi.o
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 63314ed..af98b09 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -31,6 +31,7 @@
 #include <linux/aio.h>
 #include <linux/mmu_context.h>
 #include <linux/poll.h>
+#include <linux/eventfd.h>
 
 #include "u_fs.h"
 #include "u_f.h"
@@ -153,6 +154,8 @@
 
 	struct usb_ep *ep;
 	struct usb_request *req;
+
+	struct ffs_data *ffs;
 };
 
 struct ffs_desc_helper {
@@ -390,17 +393,20 @@
 	return ret;
 }
 
+/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
 static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
 				     size_t n)
 {
 	/*
-	 * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
-	 * to release them.
+	 * n cannot be bigger than ffs->ev.count, which cannot be bigger than
+	 * size of ffs->ev.types array (which is four) so that's how much space
+	 * we reserve.
 	 */
-	struct usb_functionfs_event events[n];
+	struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
+	const size_t size = n * sizeof *events;
 	unsigned i = 0;
 
-	memset(events, 0, sizeof events);
+	memset(events, 0, size);
 
 	do {
 		events[i].type = ffs->ev.types[i];
@@ -410,19 +416,15 @@
 		}
 	} while (++i < n);
 
-	if (n < ffs->ev.count) {
-		ffs->ev.count -= n;
+	ffs->ev.count -= n;
+	if (ffs->ev.count)
 		memmove(ffs->ev.types, ffs->ev.types + n,
 			ffs->ev.count * sizeof *ffs->ev.types);
-	} else {
-		ffs->ev.count = 0;
-	}
 
 	spin_unlock_irq(&ffs->ev.waitq.lock);
 	mutex_unlock(&ffs->mutex);
 
-	return unlikely(__copy_to_user(buf, events, sizeof events))
-		? -EFAULT : sizeof events;
+	return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
 }
 
 static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@@ -606,6 +608,8 @@
 		}
 	case FFS_CLOSING:
 		break;
+	case FFS_DEACTIVATED:
+		break;
 	}
 
 	mutex_unlock(&ffs->mutex);
@@ -673,6 +677,9 @@
 
 	aio_complete(io_data->kiocb, ret, ret);
 
+	if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
+		eventfd_signal(io_data->ffs->ffs_eventfd, 1);
+
 	usb_ep_free_request(io_data->ep, io_data->req);
 
 	io_data->kiocb->private = NULL;
@@ -826,6 +833,7 @@
 			io_data->buf = data;
 			io_data->ep = ep->ep;
 			io_data->req = req;
+			io_data->ffs = epfile->ffs;
 
 			req->context  = io_data;
 			req->complete = ffs_epfile_async_io_complete;
@@ -1180,6 +1188,7 @@
 	struct ffs_file_perms perms;
 	umode_t root_mode;
 	const char *dev_name;
+	bool no_disconnect;
 	struct ffs_data *ffs_data;
 };
 
@@ -1250,6 +1259,12 @@
 
 		/* Interpret option */
 		switch (eq - opts) {
+		case 13:
+			if (!memcmp(opts, "no_disconnect", 13))
+				data->no_disconnect = !!value;
+			else
+				goto invalid;
+			break;
 		case 5:
 			if (!memcmp(opts, "rmode", 5))
 				data->root_mode  = (value & 0555) | S_IFDIR;
@@ -1314,6 +1329,7 @@
 			.gid = GLOBAL_ROOT_GID,
 		},
 		.root_mode = S_IFDIR | 0500,
+		.no_disconnect = false,
 	};
 	struct dentry *rv;
 	int ret;
@@ -1330,6 +1346,7 @@
 	if (unlikely(!ffs))
 		return ERR_PTR(-ENOMEM);
 	ffs->file_perms = data.perms;
+	ffs->no_disconnect = data.no_disconnect;
 
 	ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
 	if (unlikely(!ffs->dev_name)) {
@@ -1361,6 +1378,7 @@
 	kill_litter_super(sb);
 	if (sb->s_fs_info) {
 		ffs_release_dev(sb->s_fs_info);
+		ffs_data_closed(sb->s_fs_info);
 		ffs_data_put(sb->s_fs_info);
 	}
 }
@@ -1417,7 +1435,11 @@
 	ENTER();
 
 	atomic_inc(&ffs->ref);
-	atomic_inc(&ffs->opened);
+	if (atomic_add_return(1, &ffs->opened) == 1 &&
+			ffs->state == FFS_DEACTIVATED) {
+		ffs->state = FFS_CLOSING;
+		ffs_data_reset(ffs);
+	}
 }
 
 static void ffs_data_put(struct ffs_data *ffs)
@@ -1439,6 +1461,21 @@
 	ENTER();
 
 	if (atomic_dec_and_test(&ffs->opened)) {
+		if (ffs->no_disconnect) {
+			ffs->state = FFS_DEACTIVATED;
+			if (ffs->epfiles) {
+				ffs_epfiles_destroy(ffs->epfiles,
+						   ffs->eps_count);
+				ffs->epfiles = NULL;
+			}
+			if (ffs->setup_state == FFS_SETUP_PENDING)
+				__ffs_ep0_stall(ffs);
+		} else {
+			ffs->state = FFS_CLOSING;
+			ffs_data_reset(ffs);
+		}
+	}
+	if (atomic_read(&ffs->opened) < 0) {
 		ffs->state = FFS_CLOSING;
 		ffs_data_reset(ffs);
 	}
@@ -1480,6 +1517,9 @@
 	if (ffs->epfiles)
 		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
 
+	if (ffs->ffs_eventfd)
+		eventfd_ctx_put(ffs->ffs_eventfd);
+
 	kfree(ffs->raw_descs_data);
 	kfree(ffs->raw_strings);
 	kfree(ffs->stringtabs);
@@ -1581,10 +1621,10 @@
 		mutex_init(&epfile->mutex);
 		init_waitqueue_head(&epfile->wait);
 		if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
-			sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
+			sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
 		else
-			sprintf(epfiles->name, "ep%u", i);
-		epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
+			sprintf(epfile->name, "ep%u", i);
+		epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
 						 epfile,
 						 &ffs_epfile_operations);
 		if (unlikely(!epfile->dentry)) {
@@ -1616,7 +1656,6 @@
 	kfree(epfiles);
 }
 
-
 static void ffs_func_eps_disable(struct ffs_function *func)
 {
 	struct ffs_ep *ep         = func->eps;
@@ -1629,10 +1668,12 @@
 		/* pending requests get nuked */
 		if (likely(ep->ep))
 			usb_ep_disable(ep->ep);
-		epfile->ep = NULL;
-
 		++ep;
-		++epfile;
+
+		if (epfile) {
+			epfile->ep = NULL;
+			++epfile;
+		}
 	} while (--count);
 	spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
 }
@@ -2138,7 +2179,8 @@
 			      FUNCTIONFS_HAS_HS_DESC |
 			      FUNCTIONFS_HAS_SS_DESC |
 			      FUNCTIONFS_HAS_MS_OS_DESC |
-			      FUNCTIONFS_VIRTUAL_ADDR)) {
+			      FUNCTIONFS_VIRTUAL_ADDR |
+			      FUNCTIONFS_EVENTFD)) {
 			ret = -ENOSYS;
 			goto error;
 		}
@@ -2149,6 +2191,20 @@
 		goto error;
 	}
 
+	if (flags & FUNCTIONFS_EVENTFD) {
+		if (len < 4)
+			goto error;
+		ffs->ffs_eventfd =
+			eventfd_ctx_fdget((int)get_unaligned_le32(data));
+		if (IS_ERR(ffs->ffs_eventfd)) {
+			ret = PTR_ERR(ffs->ffs_eventfd);
+			ffs->ffs_eventfd = NULL;
+			goto error;
+		}
+		data += 4;
+		len  -= 4;
+	}
+
 	/* Read fs_count, hs_count and ss_count (if present) */
 	for (i = 0; i < 3; ++i) {
 		if (!(flags & (1 << i))) {
@@ -2377,6 +2433,13 @@
 	if (ffs->setup_state == FFS_SETUP_PENDING)
 		ffs->setup_state = FFS_SETUP_CANCELLED;
 
+	/*
+	 * Logic of this function guarantees that there are at most four pending
+	 * evens on ffs->ev.types queue.  This is important because the queue
+	 * has space for four elements only and __ffs_ep0_read_events function
+	 * depends on that limit as well.  If more event types are added, those
+	 * limits have to be revisited or guaranteed to still hold.
+	 */
 	switch (type) {
 	case FUNCTIONFS_RESUME:
 		rem_type2 = FUNCTIONFS_SUSPEND;
@@ -2416,6 +2479,8 @@
 	pr_vdebug("adding event %d\n", type);
 	ffs->ev.types[ffs->ev.count++] = type;
 	wake_up_locked(&ffs->ev.waitq);
+	if (ffs->ffs_eventfd)
+		eventfd_signal(ffs->ffs_eventfd, 1);
 }
 
 static void ffs_event_add(struct ffs_data *ffs,
@@ -2888,6 +2953,13 @@
 
 /* Other USB function hooks *************************************************/
 
+static void ffs_reset_work(struct work_struct *work)
+{
+	struct ffs_data *ffs = container_of(work,
+		struct ffs_data, reset_work);
+	ffs_data_reset(ffs);
+}
+
 static int ffs_func_set_alt(struct usb_function *f,
 			    unsigned interface, unsigned alt)
 {
@@ -2904,6 +2976,13 @@
 	if (ffs->func)
 		ffs_func_eps_disable(ffs->func);
 
+	if (ffs->state == FFS_DEACTIVATED) {
+		ffs->state = FFS_CLOSING;
+		INIT_WORK(&ffs->reset_work, ffs_reset_work);
+		schedule_work(&ffs->reset_work);
+		return -ENODEV;
+	}
+
 	if (ffs->state != FFS_ACTIVE)
 		return -ENODEV;
 
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index a1bc3e3..426d69a 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -759,7 +759,7 @@
 
 F_HID_OPT(subclass, 8, 255);
 F_HID_OPT(protocol, 8, 255);
-F_HID_OPT(report_length, 16, 65536);
+F_HID_OPT(report_length, 16, 65535);
 
 static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
 {
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 80be25b..e07c50c 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -1214,7 +1214,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->pattern);
+	result = sprintf(page, "%u", opts->pattern);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1258,7 +1258,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->isoc_interval);
+	result = sprintf(page, "%u", opts->isoc_interval);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1302,7 +1302,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->isoc_maxpacket);
+	result = sprintf(page, "%u", opts->isoc_maxpacket);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1346,7 +1346,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->isoc_mult);
+	result = sprintf(page, "%u", opts->isoc_mult);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1390,7 +1390,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->isoc_maxburst);
+	result = sprintf(page, "%u", opts->isoc_maxburst);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1434,7 +1434,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->bulk_buflen);
+	result = sprintf(page, "%u", opts->bulk_buflen);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1473,7 +1473,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->int_interval);
+	result = sprintf(page, "%u", opts->int_interval);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1517,7 +1517,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->int_maxpacket);
+	result = sprintf(page, "%u", opts->int_maxpacket);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1561,7 +1561,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->int_mult);
+	result = sprintf(page, "%u", opts->int_mult);
 	mutex_unlock(&opts->lock);
 
 	return result;
@@ -1605,7 +1605,7 @@
 	int result;
 
 	mutex_lock(&opts->lock);
-	result = sprintf(page, "%d", opts->int_maxburst);
+	result = sprintf(page, "%u", opts->int_maxburst);
 	mutex_unlock(&opts->lock);
 
 	return result;
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index e971584..9719abf 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -31,7 +31,7 @@
  */
 #define F_AUDIO_AC_INTERFACE	0
 #define F_AUDIO_AS_INTERFACE	1
-#define F_AUDIO_NUM_INTERFACES	2
+#define F_AUDIO_NUM_INTERFACES	1
 
 /* B.3.1  Standard AC Interface Descriptor */
 static struct usb_interface_descriptor ac_interface_desc = {
@@ -42,14 +42,18 @@
 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
 };
 
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
+/*
+ * The number of AudioStreaming and MIDIStreaming interfaces
+ * in the Audio Interface Collection
+ */
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
 
 #define UAC_DT_AC_HEADER_LENGTH	UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
 /* 1 input terminal, 1 output terminal and 1 feature unit */
 #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
 	+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
+static struct uac1_ac_header_descriptor_1 ac_header_desc = {
 	.bLength =		UAC_DT_AC_HEADER_LENGTH,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype =	UAC_HEADER,
@@ -57,8 +61,8 @@
 	.wTotalLength =		__constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
 	.bInCollection =	F_AUDIO_NUM_INTERFACES,
 	.baInterfaceNr = {
-		[0] =		F_AUDIO_AC_INTERFACE,
-		[1] =		F_AUDIO_AS_INTERFACE,
+	/* Interface number of the first AudioStream interface */
+		[0] =		1,
 	}
 };
 
@@ -584,6 +588,7 @@
 
 	if (intf == 1) {
 		if (alt == 1) {
+			config_ep_by_speed(cdev->gadget, f, out_ep);
 			usb_ep_enable(out_ep);
 			out_ep->driver_data = audio;
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
@@ -669,7 +674,6 @@
 
 	audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 	audio->card.gadget = c->cdev->gadget;
-	audio_opts->card = &audio->card;
 	/* set up ASLA audio devices */
 	if (!audio_opts->bound) {
 		status = gaudio_setup(&audio->card);
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 945b3bd..76891ad 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -27,10 +27,11 @@
 #include <media/v4l2-dev.h>
 #include <media/v4l2-event.h>
 
+#include "u_uvc.h"
 #include "uvc.h"
+#include "uvc_configfs.h"
 #include "uvc_v4l2.h"
 #include "uvc_video.h"
-#include "u_uvc.h"
 
 unsigned int uvc_gadget_trace_param;
 
@@ -509,6 +510,9 @@
 		break;
 	}
 
+	if (!uvc_control_desc || !uvc_streaming_cls)
+		return ERR_PTR(-ENODEV);
+
 	/* Descriptors layout
 	 *
 	 * uvc_iad
@@ -605,7 +609,7 @@
 
 	INFO(cdev, "uvc_function_bind\n");
 
-	opts = to_f_uvc_opts(f->fi);
+	opts = fi_to_f_uvc_opts(f->fi);
 	/* Sanity check the streaming endpoint module parameters.
 	 */
 	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
@@ -700,10 +704,27 @@
 
 	/* Copy descriptors */
 	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
-	if (gadget_is_dualspeed(cdev->gadget))
+	if (IS_ERR(f->fs_descriptors)) {
+		ret = PTR_ERR(f->fs_descriptors);
+		f->fs_descriptors = NULL;
+		goto error;
+	}
+	if (gadget_is_dualspeed(cdev->gadget)) {
 		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
-	if (gadget_is_superspeed(c->cdev->gadget))
+		if (IS_ERR(f->hs_descriptors)) {
+			ret = PTR_ERR(f->hs_descriptors);
+			f->hs_descriptors = NULL;
+			goto error;
+		}
+	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
 		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
+		if (IS_ERR(f->ss_descriptors)) {
+			ret = PTR_ERR(f->ss_descriptors);
+			f->ss_descriptors = NULL;
+			goto error;
+		}
+	}
 
 	/* Preallocate control endpoint request. */
 	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@@ -766,27 +787,106 @@
 
 static void uvc_free_inst(struct usb_function_instance *f)
 {
-	struct f_uvc_opts *opts = to_f_uvc_opts(f);
+	struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
 
+	mutex_destroy(&opts->lock);
 	kfree(opts);
 }
 
 static struct usb_function_instance *uvc_alloc_inst(void)
 {
 	struct f_uvc_opts *opts;
+	struct uvc_camera_terminal_descriptor *cd;
+	struct uvc_processing_unit_descriptor *pd;
+	struct uvc_output_terminal_descriptor *od;
+	struct uvc_color_matching_descriptor *md;
+	struct uvc_descriptor_header **ctl_cls;
 
 	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
 	if (!opts)
 		return ERR_PTR(-ENOMEM);
 	opts->func_inst.free_func_inst = uvc_free_inst;
+	mutex_init(&opts->lock);
 
+	cd = &opts->uvc_camera_terminal;
+	cd->bLength			= UVC_DT_CAMERA_TERMINAL_SIZE(3);
+	cd->bDescriptorType		= USB_DT_CS_INTERFACE;
+	cd->bDescriptorSubType		= UVC_VC_INPUT_TERMINAL;
+	cd->bTerminalID			= 1;
+	cd->wTerminalType		= cpu_to_le16(0x0201);
+	cd->bAssocTerminal		= 0;
+	cd->iTerminal			= 0;
+	cd->wObjectiveFocalLengthMin	= cpu_to_le16(0);
+	cd->wObjectiveFocalLengthMax	= cpu_to_le16(0);
+	cd->wOcularFocalLength		= cpu_to_le16(0);
+	cd->bControlSize		= 3;
+	cd->bmControls[0]		= 2;
+	cd->bmControls[1]		= 0;
+	cd->bmControls[2]		= 0;
+
+	pd = &opts->uvc_processing;
+	pd->bLength			= UVC_DT_PROCESSING_UNIT_SIZE(2);
+	pd->bDescriptorType		= USB_DT_CS_INTERFACE;
+	pd->bDescriptorSubType		= UVC_VC_PROCESSING_UNIT;
+	pd->bUnitID			= 2;
+	pd->bSourceID			= 1;
+	pd->wMaxMultiplier		= cpu_to_le16(16*1024);
+	pd->bControlSize		= 2;
+	pd->bmControls[0]		= 1;
+	pd->bmControls[1]		= 0;
+	pd->iProcessing			= 0;
+
+	od = &opts->uvc_output_terminal;
+	od->bLength			= UVC_DT_OUTPUT_TERMINAL_SIZE;
+	od->bDescriptorType		= USB_DT_CS_INTERFACE;
+	od->bDescriptorSubType		= UVC_VC_OUTPUT_TERMINAL;
+	od->bTerminalID			= 3;
+	od->wTerminalType		= cpu_to_le16(0x0101);
+	od->bAssocTerminal		= 0;
+	od->bSourceID			= 2;
+	od->iTerminal			= 0;
+
+	md = &opts->uvc_color_matching;
+	md->bLength			= UVC_DT_COLOR_MATCHING_SIZE;
+	md->bDescriptorType		= USB_DT_CS_INTERFACE;
+	md->bDescriptorSubType		= UVC_VS_COLORFORMAT;
+	md->bColorPrimaries		= 1;
+	md->bTransferCharacteristics	= 1;
+	md->bMatrixCoefficients		= 4;
+
+	/* Prepare fs control class descriptors for configfs-based gadgets */
+	ctl_cls = opts->uvc_fs_control_cls;
+	ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
+	ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+	ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+	ctl_cls[3] = (struct uvc_descriptor_header *)od;
+	ctl_cls[4] = NULL;	/* NULL-terminate */
+	opts->fs_control =
+		(const struct uvc_descriptor_header * const *)ctl_cls;
+
+	/* Prepare hs control class descriptors for configfs-based gadgets */
+	ctl_cls = opts->uvc_ss_control_cls;
+	ctl_cls[0] = NULL;	/* assigned elsewhere by configfs */
+	ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+	ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+	ctl_cls[3] = (struct uvc_descriptor_header *)od;
+	ctl_cls[4] = NULL;	/* NULL-terminate */
+	opts->ss_control =
+		(const struct uvc_descriptor_header * const *)ctl_cls;
+
+	opts->streaming_interval = 1;
+	opts->streaming_maxpacket = 1024;
+
+	uvcg_attach_configfs(opts);
 	return &opts->func_inst;
 }
 
 static void uvc_free(struct usb_function *f)
 {
 	struct uvc_device *uvc = to_uvc(f);
-
+	struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
+					       func_inst);
+	--opts->refcnt;
 	kfree(uvc);
 }
 
@@ -812,19 +912,39 @@
 {
 	struct uvc_device *uvc;
 	struct f_uvc_opts *opts;
+	struct uvc_descriptor_header **strm_cls;
 
 	uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
 	if (uvc == NULL)
 		return ERR_PTR(-ENOMEM);
 
 	uvc->state = UVC_STATE_DISCONNECTED;
-	opts = to_f_uvc_opts(fi);
+	opts = fi_to_f_uvc_opts(fi);
+
+	mutex_lock(&opts->lock);
+	if (opts->uvc_fs_streaming_cls) {
+		strm_cls = opts->uvc_fs_streaming_cls;
+		opts->fs_streaming =
+			(const struct uvc_descriptor_header * const *)strm_cls;
+	}
+	if (opts->uvc_hs_streaming_cls) {
+		strm_cls = opts->uvc_hs_streaming_cls;
+		opts->hs_streaming =
+			(const struct uvc_descriptor_header * const *)strm_cls;
+	}
+	if (opts->uvc_ss_streaming_cls) {
+		strm_cls = opts->uvc_ss_streaming_cls;
+		opts->ss_streaming =
+			(const struct uvc_descriptor_header * const *)strm_cls;
+	}
 
 	uvc->desc.fs_control = opts->fs_control;
 	uvc->desc.ss_control = opts->ss_control;
 	uvc->desc.fs_streaming = opts->fs_streaming;
 	uvc->desc.hs_streaming = opts->hs_streaming;
 	uvc->desc.ss_streaming = opts->ss_streaming;
+	++opts->refcnt;
+	mutex_unlock(&opts->lock);
 
 	/* Register the function. */
 	uvc->func.name = "uvc";
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 6e6f876..f1fd777 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -729,9 +729,7 @@
 	if (len < 18)
 		return -EINVAL;
 
-	snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
-		 dev_addr[0], dev_addr[1], dev_addr[2],
-		 dev_addr[3], dev_addr[4], dev_addr[5]);
+	snprintf(str, len, "%pM", dev_addr);
 	return 18;
 }
 
diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h
index cd128e3..6013985 100644
--- a/drivers/usb/gadget/function/u_fs.h
+++ b/drivers/usb/gadget/function/u_fs.h
@@ -19,6 +19,7 @@
 #include <linux/usb/composite.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 
 #ifdef VERBOSE_DEBUG
 #ifndef pr_vdebug
@@ -93,6 +94,26 @@
 	FFS_ACTIVE,
 
 	/*
+	 * Function is visible to host, but it's not functional. All
+	 * setup requests are stalled and transfers on another endpoints
+	 * are refused. All epfiles, except ep0, are deleted so there
+	 * is no way to perform any operations on them.
+	 *
+	 * This state is set after closing all functionfs files, when
+	 * mount parameter "no_disconnect=1" has been set. Function will
+	 * remain in deactivated state until filesystem is umounted or
+	 * ep0 is opened again. In the second case functionfs state will
+	 * be reset, and it will be ready for descriptors and strings
+	 * writing.
+	 *
+	 * This is useful only when functionfs is composed to gadget
+	 * with another function which can perform some critical
+	 * operations, and it's strongly desired to have this operations
+	 * completed, even after functionfs files closure.
+	 */
+	FFS_DEACTIVATED,
+
+	/*
 	 * All endpoints have been closed.  This state is also set if
 	 * we encounter an unrecoverable error.  The only
 	 * unrecoverable error is situation when after reading strings
@@ -251,6 +272,10 @@
 		kgid_t				gid;
 	}				file_perms;
 
+	struct eventfd_ctx *ffs_eventfd;
+	bool no_disconnect;
+	struct work_struct reset_work;
+
 	/*
 	 * The endpoint files, filled by ffs_epfiles_create(),
 	 * destroyed by ffs_epfiles_destroy().
diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c
index 53842a1..c78c841 100644
--- a/drivers/usb/gadget/function/u_uac1.c
+++ b/drivers/usb/gadget/function/u_uac1.c
@@ -308,8 +308,7 @@
  */
 void gaudio_cleanup(struct gaudio *the_card)
 {
-	if (the_card) {
+	if (the_card)
 		gaudio_close_snd_dev(the_card);
-	}
 }
 
diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h
index f8b17fe..fe386df 100644
--- a/drivers/usb/gadget/function/u_uac1.h
+++ b/drivers/usb/gadget/function/u_uac1.h
@@ -70,7 +70,6 @@
 	unsigned			fn_play_alloc:1;
 	unsigned			fn_cap_alloc:1;
 	unsigned			fn_cntl_alloc:1;
-	struct gaudio			*card;
 	struct mutex			lock;
 	int				refcnt;
 };
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 2a8dfdf..4676b60 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -17,8 +17,9 @@
 #define U_UVC_H
 
 #include <linux/usb/composite.h>
+#include <linux/usb/video.h>
 
-#define to_f_uvc_opts(f)	container_of(f, struct f_uvc_opts, func_inst)
+#define fi_to_f_uvc_opts(f)	container_of(f, struct f_uvc_opts, func_inst)
 
 struct f_uvc_opts {
 	struct usb_function_instance			func_inst;
@@ -26,11 +27,60 @@
 	unsigned int					streaming_interval;
 	unsigned int					streaming_maxpacket;
 	unsigned int					streaming_maxburst;
+
+	/*
+	 * Control descriptors array pointers for full-/high-speed and
+	 * super-speed. They point by default to the uvc_fs_control_cls and
+	 * uvc_ss_control_cls arrays respectively. Legacy gadgets must
+	 * override them in their gadget bind callback.
+	 */
 	const struct uvc_descriptor_header * const	*fs_control;
 	const struct uvc_descriptor_header * const	*ss_control;
+
+	/*
+	 * Streaming descriptors array pointers for full-speed, high-speed and
+	 * super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
+	 * for configfs-based gadgets. Legacy gadgets must initialize them in
+	 * their gadget bind callback.
+	 */
 	const struct uvc_descriptor_header * const	*fs_streaming;
 	const struct uvc_descriptor_header * const	*hs_streaming;
 	const struct uvc_descriptor_header * const	*ss_streaming;
+
+	/* Default control descriptors for configfs-based gadgets. */
+	struct uvc_camera_terminal_descriptor		uvc_camera_terminal;
+	struct uvc_processing_unit_descriptor		uvc_processing;
+	struct uvc_output_terminal_descriptor		uvc_output_terminal;
+	struct uvc_color_matching_descriptor		uvc_color_matching;
+
+	/*
+	 * Control descriptors pointers arrays for full-/high-speed and
+	 * super-speed. The first element is a configurable control header
+	 * descriptor, the other elements point to the fixed default control
+	 * descriptors. Used by configfs only, must not be touched by legacy
+	 * gadgets.
+	 */
+	struct uvc_descriptor_header			*uvc_fs_control_cls[5];
+	struct uvc_descriptor_header			*uvc_ss_control_cls[5];
+
+	/*
+	 * Streaming descriptors for full-speed, high-speed and super-speed.
+	 * Used by configfs only, must not be touched by legacy gadgets. The
+	 * arrays are allocated at runtime as the number of descriptors isn't
+	 * known in advance.
+	 */
+	struct uvc_descriptor_header			**uvc_fs_streaming_cls;
+	struct uvc_descriptor_header			**uvc_hs_streaming_cls;
+	struct uvc_descriptor_header			**uvc_ss_streaming_cls;
+
+	/*
+	 * Read/write access to configfs attributes is handled by configfs.
+	 *
+	 * This lock protects the descriptors from concurrent access by
+	 * read/write and symlink creation/removal.
+	 */
+	struct mutex			lock;
+	int				refcnt;
 };
 
 void uvc_set_trace_param(unsigned int trace);
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
new file mode 100644
index 0000000..3c0467b
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -0,0 +1,2468 @@
+/*
+ * uvc_configfs.c
+ *
+ * Configfs support for the uvc function.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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 "u_uvc.h"
+#include "uvc_configfs.h"
+
+#define UVCG_STREAMING_CONTROL_SIZE	1
+
+#define CONFIGFS_ATTR_OPS_RO(_item)					\
+static ssize_t _item##_attr_show(struct config_item *item,		\
+				 struct configfs_attribute *attr,	\
+				 char *page)				\
+{									\
+	struct _item *_item = to_##_item(item);				\
+	struct _item##_attribute *_item##_attr =			\
+		container_of(attr, struct _item##_attribute, attr);	\
+	ssize_t ret = 0;						\
+									\
+	if (_item##_attr->show)						\
+		ret = _item##_attr->show(_item, page);			\
+	return ret;							\
+}
+
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
+
+/* control/header/<NAME> */
+DECLARE_UVC_HEADER_DESCRIPTOR(1);
+
+struct uvcg_control_header {
+	struct config_item		item;
+	struct UVC_HEADER_DESCRIPTOR(1)	desc;
+	unsigned			linked;
+};
+
+static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
+{
+	return container_of(item, struct uvcg_control_header, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_control_header);
+CONFIGFS_ATTR_OPS(uvcg_control_header);
+
+static struct configfs_item_operations uvcg_control_header_item_ops = {
+	.show_attribute		= uvcg_control_header_attr_show,
+	.store_attribute	= uvcg_control_header_attr_store,
+};
+
+#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit)	\
+static ssize_t uvcg_control_header_##cname##_show(			\
+	struct uvcg_control_header *ch, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = ch->item.ci_parent->ci_parent->ci_parent;		\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(ch->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static ssize_t								\
+uvcg_control_header_##cname##_store(struct uvcg_control_header *ch,	\
+			   const char *page, size_t len)		\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
+	int ret;							\
+	uxx num;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = ch->item.ci_parent->ci_parent->ci_parent;		\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	if (ch->linked || opts->refcnt) {				\
+		ret = -EBUSY;						\
+		goto end;						\
+	}								\
+									\
+	ret = str2u(page, 0, &num);					\
+	if (ret)							\
+		goto end;						\
+									\
+	if (num > limit) {						\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+	ch->desc.aname = vnoc(num);					\
+	ret = len;							\
+end:									\
+	mutex_unlock(&opts->lock);					\
+	mutex_unlock(su_mutex);						\
+	return ret;							\
+}									\
+									\
+static struct uvcg_control_header_attribute				\
+	uvcg_control_header_##cname =					\
+	__CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR,			\
+			uvcg_control_header_##cname##_show,		\
+			uvcg_control_header_##cname##_store)
+
+UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
+		   0xffff);
+
+UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
+		   u32, cpu_to_le32, 0x7fffffff);
+
+#undef UVCG_CTRL_HDR_ATTR
+
+static struct configfs_attribute *uvcg_control_header_attrs[] = {
+	&uvcg_control_header_bcd_uvc.attr,
+	&uvcg_control_header_dw_clock_frequency.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_control_header_type = {
+	.ct_item_ops	= &uvcg_control_header_item_ops,
+	.ct_attrs	= uvcg_control_header_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item *uvcg_control_header_make(struct config_group *group,
+						    const char *name)
+{
+	struct uvcg_control_header *h;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	h->desc.bLength			= UVC_DT_HEADER_SIZE(1);
+	h->desc.bDescriptorType		= USB_DT_CS_INTERFACE;
+	h->desc.bDescriptorSubType	= UVC_VC_HEADER;
+	h->desc.bcdUVC			= cpu_to_le16(0x0100);
+	h->desc.dwClockFrequency	= cpu_to_le32(48000000);
+
+	config_item_init_type_name(&h->item, name, &uvcg_control_header_type);
+
+	return &h->item;
+}
+
+static void uvcg_control_header_drop(struct config_group *group,
+			      struct config_item *item)
+{
+	struct uvcg_control_header *h = to_uvcg_control_header(item);
+
+	kfree(h);
+}
+
+/* control/header */
+static struct uvcg_control_header_grp {
+	struct config_group	group;
+} uvcg_control_header_grp;
+
+static struct configfs_group_operations uvcg_control_header_grp_ops = {
+	.make_item		= uvcg_control_header_make,
+	.drop_item		= uvcg_control_header_drop,
+};
+
+static struct config_item_type uvcg_control_header_grp_type = {
+	.ct_group_ops	= &uvcg_control_header_grp_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* control/processing/default */
+static struct uvcg_default_processing {
+	struct config_group	group;
+} uvcg_default_processing;
+
+static inline struct uvcg_default_processing
+*to_uvcg_default_processing(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct uvcg_default_processing, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_processing);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_processing);
+
+static struct configfs_item_operations uvcg_default_processing_item_ops = {
+	.show_attribute		= uvcg_default_processing_attr_show,
+};
+
+#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv)		\
+static ssize_t uvcg_default_processing_##cname##_show(			\
+	struct uvcg_default_processing *dp, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;	\
+	struct uvc_processing_unit_descriptor *pd;			\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;	\
+	opts = to_f_uvc_opts(opts_item);				\
+	pd = &opts->uvc_processing;					\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(pd->aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static struct uvcg_default_processing_attribute				\
+	uvcg_default_processing_##cname =				\
+	__CONFIGFS_ATTR_RO(aname, uvcg_default_processing_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv);
+UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv);
+UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
+UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_PROCESSING_ATTR
+
+static ssize_t uvcg_default_processing_bm_controls_show(
+	struct uvcg_default_processing *dp, char *page)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
+	struct uvc_processing_unit_descriptor *pd;
+	int result, i;
+	char *pg = page;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+	pd = &opts->uvc_processing;
+
+	mutex_lock(&opts->lock);
+	for (result = 0, i = 0; i < pd->bControlSize; ++i) {
+		result += sprintf(pg, "%d\n", pd->bmControls[i]);
+		pg = page + result;
+	}
+	mutex_unlock(&opts->lock);
+
+	mutex_unlock(su_mutex);
+
+	return result;
+}
+
+static struct uvcg_default_processing_attribute
+	uvcg_default_processing_bm_controls =
+	__CONFIGFS_ATTR_RO(bmControls,
+		uvcg_default_processing_bm_controls_show);
+
+static struct configfs_attribute *uvcg_default_processing_attrs[] = {
+	&uvcg_default_processing_b_unit_id.attr,
+	&uvcg_default_processing_b_source_id.attr,
+	&uvcg_default_processing_w_max_multiplier.attr,
+	&uvcg_default_processing_bm_controls.attr,
+	&uvcg_default_processing_i_processing.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_default_processing_type = {
+	.ct_item_ops	= &uvcg_default_processing_item_ops,
+	.ct_attrs	= uvcg_default_processing_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* struct uvcg_processing {}; */
+
+static struct config_group *uvcg_processing_default_groups[] = {
+	&uvcg_default_processing.group,
+	NULL,
+};
+
+/* control/processing */
+static struct uvcg_processing_grp {
+	struct config_group	group;
+} uvcg_processing_grp;
+
+static struct config_item_type uvcg_processing_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+/* control/terminal/camera/default */
+static struct uvcg_default_camera {
+	struct config_group	group;
+} uvcg_default_camera;
+
+static inline struct uvcg_default_camera
+*to_uvcg_default_camera(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct uvcg_default_camera, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_camera);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_camera);
+
+static struct configfs_item_operations uvcg_default_camera_item_ops = {
+	.show_attribute		= uvcg_default_camera_attr_show,
+};
+
+#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv)			\
+static ssize_t uvcg_default_camera_##cname##_show(			\
+	struct uvcg_default_camera *dc, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;	\
+	struct uvc_camera_terminal_descriptor *cd;			\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->	\
+			ci_parent;					\
+	opts = to_f_uvc_opts(opts_item);				\
+	cd = &opts->uvc_camera_terminal;				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(cd->aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+									\
+	return result;							\
+}									\
+									\
+static struct uvcg_default_camera_attribute				\
+	uvcg_default_camera_##cname =					\
+	__CONFIGFS_ATTR_RO(aname, uvcg_default_camera_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
+			 le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
+			 le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
+			 le16_to_cpu);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_CAMERA_ATTR
+
+static ssize_t uvcg_default_camera_bm_controls_show(
+	struct uvcg_default_camera *dc, char *page)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
+	struct uvc_camera_terminal_descriptor *cd;
+	int result, i;
+	char *pg = page;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->
+			ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+	cd = &opts->uvc_camera_terminal;
+
+	mutex_lock(&opts->lock);
+	for (result = 0, i = 0; i < cd->bControlSize; ++i) {
+		result += sprintf(pg, "%d\n", cd->bmControls[i]);
+		pg = page + result;
+	}
+	mutex_unlock(&opts->lock);
+
+	mutex_unlock(su_mutex);
+	return result;
+}
+
+static struct uvcg_default_camera_attribute
+	uvcg_default_camera_bm_controls =
+	__CONFIGFS_ATTR_RO(bmControls, uvcg_default_camera_bm_controls_show);
+
+static struct configfs_attribute *uvcg_default_camera_attrs[] = {
+	&uvcg_default_camera_b_terminal_id.attr,
+	&uvcg_default_camera_w_terminal_type.attr,
+	&uvcg_default_camera_b_assoc_terminal.attr,
+	&uvcg_default_camera_i_terminal.attr,
+	&uvcg_default_camera_w_objective_focal_length_min.attr,
+	&uvcg_default_camera_w_objective_focal_length_max.attr,
+	&uvcg_default_camera_w_ocular_focal_length.attr,
+	&uvcg_default_camera_bm_controls.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_default_camera_type = {
+	.ct_item_ops	= &uvcg_default_camera_item_ops,
+	.ct_attrs	= uvcg_default_camera_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* struct uvcg_camera {}; */
+
+static struct config_group *uvcg_camera_default_groups[] = {
+	&uvcg_default_camera.group,
+	NULL,
+};
+
+/* control/terminal/camera */
+static struct uvcg_camera_grp {
+	struct config_group	group;
+} uvcg_camera_grp;
+
+static struct config_item_type uvcg_camera_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+/* control/terminal/output/default */
+static struct uvcg_default_output {
+	struct config_group	group;
+} uvcg_default_output;
+
+static inline struct uvcg_default_output
+*to_uvcg_default_output(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct uvcg_default_output, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_output);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_output);
+
+static struct configfs_item_operations uvcg_default_output_item_ops = {
+	.show_attribute		= uvcg_default_output_attr_show,
+};
+
+#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv)			\
+static ssize_t uvcg_default_output_##cname##_show(			\
+	struct uvcg_default_output *dout, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex;	\
+	struct uvc_output_terminal_descriptor *cd;			\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = dout->group.cg_item.ci_parent->ci_parent->		\
+			ci_parent->ci_parent;				\
+	opts = to_f_uvc_opts(opts_item);				\
+	cd = &opts->uvc_output_terminal;				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(cd->aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+									\
+	return result;							\
+}									\
+									\
+static struct uvcg_default_output_attribute				\
+	uvcg_default_output_##cname =					\
+	__CONFIGFS_ATTR_RO(aname, uvcg_default_output_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
+UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_OUTPUT_ATTR
+
+static struct configfs_attribute *uvcg_default_output_attrs[] = {
+	&uvcg_default_output_b_terminal_id.attr,
+	&uvcg_default_output_w_terminal_type.attr,
+	&uvcg_default_output_b_assoc_terminal.attr,
+	&uvcg_default_output_b_source_id.attr,
+	&uvcg_default_output_i_terminal.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_default_output_type = {
+	.ct_item_ops	= &uvcg_default_output_item_ops,
+	.ct_attrs	= uvcg_default_output_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* struct uvcg_output {}; */
+
+static struct config_group *uvcg_output_default_groups[] = {
+	&uvcg_default_output.group,
+	NULL,
+};
+
+/* control/terminal/output */
+static struct uvcg_output_grp {
+	struct config_group	group;
+} uvcg_output_grp;
+
+static struct config_item_type uvcg_output_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_terminal_default_groups[] = {
+	&uvcg_camera_grp.group,
+	&uvcg_output_grp.group,
+	NULL,
+};
+
+/* control/terminal */
+static struct uvcg_terminal_grp {
+	struct config_group	group;
+} uvcg_terminal_grp;
+
+static struct config_item_type uvcg_terminal_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+/* control/class/{fs} */
+static struct uvcg_control_class {
+	struct config_group	group;
+} uvcg_control_class_fs, uvcg_control_class_ss;
+
+
+static inline struct uvc_descriptor_header
+**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
+{
+	struct uvcg_control_class *cl = container_of(to_config_group(i),
+		struct uvcg_control_class, group);
+
+	if (cl == &uvcg_control_class_fs)
+		return o->uvc_fs_control_cls;
+
+	if (cl == &uvcg_control_class_ss)
+		return o->uvc_ss_control_cls;
+
+	return NULL;
+}
+
+static int uvcg_control_class_allow_link(struct config_item *src,
+					 struct config_item *target)
+{
+	struct config_item *control, *header;
+	struct f_uvc_opts *opts;
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct uvc_descriptor_header **class_array;
+	struct uvcg_control_header *target_hdr;
+	int ret = -EINVAL;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	control = src->ci_parent->ci_parent;
+	header = config_group_find_item(to_config_group(control), "header");
+	if (!header || target->ci_parent != header)
+		goto out;
+
+	opts = to_f_uvc_opts(control->ci_parent);
+
+	mutex_lock(&opts->lock);
+
+	class_array = uvcg_get_ctl_class_arr(src, opts);
+	if (!class_array)
+		goto unlock;
+	if (opts->refcnt || class_array[0]) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	target_hdr = to_uvcg_control_header(target);
+	++target_hdr->linked;
+	class_array[0] = (struct uvc_descriptor_header *)&target_hdr->desc;
+	ret = 0;
+
+unlock:
+	mutex_unlock(&opts->lock);
+out:
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static int uvcg_control_class_drop_link(struct config_item *src,
+					struct config_item *target)
+{
+	struct config_item *control, *header;
+	struct f_uvc_opts *opts;
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct uvc_descriptor_header **class_array;
+	struct uvcg_control_header *target_hdr;
+	int ret = -EINVAL;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	control = src->ci_parent->ci_parent;
+	header = config_group_find_item(to_config_group(control), "header");
+	if (!header || target->ci_parent != header)
+		goto out;
+
+	opts = to_f_uvc_opts(control->ci_parent);
+
+	mutex_lock(&opts->lock);
+
+	class_array = uvcg_get_ctl_class_arr(src, opts);
+	if (!class_array)
+		goto unlock;
+	if (opts->refcnt) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	target_hdr = to_uvcg_control_header(target);
+	--target_hdr->linked;
+	class_array[0] = NULL;
+	ret = 0;
+
+unlock:
+	mutex_unlock(&opts->lock);
+out:
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static struct configfs_item_operations uvcg_control_class_item_ops = {
+	.allow_link	= uvcg_control_class_allow_link,
+	.drop_link	= uvcg_control_class_drop_link,
+};
+
+static struct config_item_type uvcg_control_class_type = {
+	.ct_item_ops	= &uvcg_control_class_item_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *uvcg_control_class_default_groups[] = {
+	&uvcg_control_class_fs.group,
+	&uvcg_control_class_ss.group,
+	NULL,
+};
+
+/* control/class */
+static struct uvcg_control_class_grp {
+	struct config_group	group;
+} uvcg_control_class_grp;
+
+static struct config_item_type uvcg_control_class_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_control_default_groups[] = {
+	&uvcg_control_header_grp.group,
+	&uvcg_processing_grp.group,
+	&uvcg_terminal_grp.group,
+	&uvcg_control_class_grp.group,
+	NULL,
+};
+
+/* control */
+static struct uvcg_control_grp {
+	struct config_group	group;
+} uvcg_control_grp;
+
+static struct config_item_type uvcg_control_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+/* streaming/uncompressed */
+static struct uvcg_uncompressed_grp {
+	struct config_group	group;
+} uvcg_uncompressed_grp;
+
+/* streaming/mjpeg */
+static struct uvcg_mjpeg_grp {
+	struct config_group	group;
+} uvcg_mjpeg_grp;
+
+static struct config_item *fmt_parent[] = {
+	&uvcg_uncompressed_grp.group.cg_item,
+	&uvcg_mjpeg_grp.group.cg_item,
+};
+
+enum uvcg_format_type {
+	UVCG_UNCOMPRESSED = 0,
+	UVCG_MJPEG,
+};
+
+struct uvcg_format {
+	struct config_group	group;
+	enum uvcg_format_type	type;
+	unsigned		linked;
+	unsigned		num_frames;
+	__u8			bmaControls[UVCG_STREAMING_CONTROL_SIZE];
+};
+
+static struct uvcg_format *to_uvcg_format(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct uvcg_format, group);
+}
+
+static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &f->group.cg_subsys->su_mutex;
+	int result, i;
+	char *pg = page;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = f->group.cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	result = sprintf(pg, "0x");
+	pg += result;
+	for (i = 0; i < UVCG_STREAMING_CONTROL_SIZE; ++i) {
+		result += sprintf(pg, "%x\n", f->bmaControls[i]);
+		pg = page + result;
+	}
+	mutex_unlock(&opts->lock);
+
+	mutex_unlock(su_mutex);
+	return result;
+}
+
+static ssize_t uvcg_format_bma_controls_store(struct uvcg_format *ch,
+					      const char *page, size_t len)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &ch->group.cg_subsys->su_mutex;
+	int ret = -EINVAL;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = ch->group.cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	if (ch->linked || opts->refcnt) {
+		ret = -EBUSY;
+		goto end;
+	}
+
+	if (len < 4 || *page != '0' ||
+	    (*(page + 1) != 'x' && *(page + 1) != 'X'))
+		goto end;
+	ret = hex2bin(ch->bmaControls, page + 2, 1);
+	if (ret < 0)
+		goto end;
+	ret = len;
+end:
+	mutex_unlock(&opts->lock);
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+struct uvcg_format_ptr {
+	struct uvcg_format	*fmt;
+	struct list_head	entry;
+};
+
+/* streaming/header/<NAME> */
+struct uvcg_streaming_header {
+	struct config_item				item;
+	struct uvc_input_header_descriptor		desc;
+	unsigned					linked;
+	struct list_head				formats;
+	unsigned					num_fmt;
+};
+
+static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
+{
+	return container_of(item, struct uvcg_streaming_header, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_streaming_header);
+CONFIGFS_ATTR_OPS(uvcg_streaming_header);
+
+static int uvcg_streaming_header_allow_link(struct config_item *src,
+					    struct config_item *target)
+{
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct config_item *opts_item;
+	struct f_uvc_opts *opts;
+	struct uvcg_streaming_header *src_hdr;
+	struct uvcg_format *target_fmt = NULL;
+	struct uvcg_format_ptr *format_ptr;
+	int i, ret = -EINVAL;
+
+	src_hdr = to_uvcg_streaming_header(src);
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = src->ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+
+	if (src_hdr->linked) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i)
+		if (target->ci_parent == fmt_parent[i])
+			break;
+	if (i == ARRAY_SIZE(fmt_parent))
+		goto out;
+
+	target_fmt = container_of(to_config_group(target), struct uvcg_format,
+				  group);
+	if (!target_fmt)
+		goto out;
+
+	format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
+	if (!format_ptr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = 0;
+	format_ptr->fmt = target_fmt;
+	list_add_tail(&format_ptr->entry, &src_hdr->formats);
+	++src_hdr->num_fmt;
+
+out:
+	mutex_unlock(&opts->lock);
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static int uvcg_streaming_header_drop_link(struct config_item *src,
+					   struct config_item *target)
+{
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct config_item *opts_item;
+	struct f_uvc_opts *opts;
+	struct uvcg_streaming_header *src_hdr;
+	struct uvcg_format *target_fmt = NULL;
+	struct uvcg_format_ptr *format_ptr, *tmp;
+	int ret = -EINVAL;
+
+	src_hdr = to_uvcg_streaming_header(src);
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = src->ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	target_fmt = container_of(to_config_group(target), struct uvcg_format,
+				  group);
+	if (!target_fmt)
+		goto out;
+
+	list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
+		if (format_ptr->fmt == target_fmt) {
+			list_del(&format_ptr->entry);
+			kfree(format_ptr);
+			--src_hdr->num_fmt;
+			break;
+		}
+
+out:
+	mutex_unlock(&opts->lock);
+	mutex_unlock(su_mutex);
+	return ret;
+
+}
+
+static struct configfs_item_operations uvcg_streaming_header_item_ops = {
+	.show_attribute		= uvcg_streaming_header_attr_show,
+	.store_attribute	= uvcg_streaming_header_attr_store,
+	.allow_link		= uvcg_streaming_header_allow_link,
+	.drop_link		= uvcg_streaming_header_drop_link,
+};
+
+#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv)			\
+static ssize_t uvcg_streaming_header_##cname##_show(			\
+	struct uvcg_streaming_header *sh, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = sh->item.ci_parent->ci_parent->ci_parent;		\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(sh->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static struct uvcg_streaming_header_attribute				\
+	uvcg_streaming_header_##cname =					\
+	__CONFIGFS_ATTR_RO(aname, uvcg_streaming_header_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod,
+			   identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_STREAMING_HEADER_ATTR
+
+static struct configfs_attribute *uvcg_streaming_header_attrs[] = {
+	&uvcg_streaming_header_bm_info.attr,
+	&uvcg_streaming_header_b_terminal_link.attr,
+	&uvcg_streaming_header_b_still_capture_method.attr,
+	&uvcg_streaming_header_b_trigger_support.attr,
+	&uvcg_streaming_header_b_trigger_usage.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_streaming_header_type = {
+	.ct_item_ops	= &uvcg_streaming_header_item_ops,
+	.ct_attrs	= uvcg_streaming_header_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item
+*uvcg_streaming_header_make(struct config_group *group, const char *name)
+{
+	struct uvcg_streaming_header *h;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&h->formats);
+	h->desc.bDescriptorType		= USB_DT_CS_INTERFACE;
+	h->desc.bDescriptorSubType	= UVC_VS_INPUT_HEADER;
+	h->desc.bTerminalLink		= 3;
+	h->desc.bControlSize		= UVCG_STREAMING_CONTROL_SIZE;
+
+	config_item_init_type_name(&h->item, name, &uvcg_streaming_header_type);
+
+	return &h->item;
+}
+
+static void uvcg_streaming_header_drop(struct config_group *group,
+			      struct config_item *item)
+{
+	struct uvcg_streaming_header *h = to_uvcg_streaming_header(item);
+
+	kfree(h);
+}
+
+/* streaming/header */
+static struct uvcg_streaming_header_grp {
+	struct config_group	group;
+} uvcg_streaming_header_grp;
+
+static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
+	.make_item		= uvcg_streaming_header_make,
+	.drop_item		= uvcg_streaming_header_drop,
+};
+
+static struct config_item_type uvcg_streaming_header_grp_type = {
+	.ct_group_ops	= &uvcg_streaming_header_grp_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* streaming/<mode>/<format>/<NAME> */
+struct uvcg_frame {
+	struct {
+		u8	b_length;
+		u8	b_descriptor_type;
+		u8	b_descriptor_subtype;
+		u8	b_frame_index;
+		u8	bm_capabilities;
+		u16	w_width;
+		u16	w_height;
+		u32	dw_min_bit_rate;
+		u32	dw_max_bit_rate;
+		u32	dw_max_video_frame_buffer_size;
+		u32	dw_default_frame_interval;
+		u8	b_frame_interval_type;
+	} __attribute__((packed)) frame;
+	u32 *dw_frame_interval;
+	enum uvcg_format_type	fmt_type;
+	struct config_item	item;
+};
+
+static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
+{
+	return container_of(item, struct uvcg_frame, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_frame);
+CONFIGFS_ATTR_OPS(uvcg_frame);
+
+static struct configfs_item_operations uvcg_frame_item_ops = {
+	.show_attribute		= uvcg_frame_attr_show,
+	.store_attribute	= uvcg_frame_attr_store,
+};
+
+#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
+static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent;	\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname));	\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static ssize_t  uvcg_frame_##cname##_store(struct uvcg_frame *f,	\
+					   const char *page, size_t len)\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct uvcg_format *fmt;					\
+	struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+	int ret;							\
+	u##bits num;							\
+									\
+	ret = kstrtou##bits(page, 0, &num);				\
+	if (ret)							\
+		return ret;						\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent;	\
+	opts = to_f_uvc_opts(opts_item);				\
+	fmt = to_uvcg_format(f->item.ci_parent);			\
+									\
+	mutex_lock(&opts->lock);					\
+	if (fmt->linked || opts->refcnt) {				\
+		ret = -EBUSY;						\
+		goto end;						\
+	}								\
+									\
+	f->frame.cname = to_little_endian(num);				\
+	ret = len;							\
+end:									\
+	mutex_unlock(&opts->lock);					\
+	mutex_unlock(su_mutex);						\
+	return ret;							\
+}									\
+									\
+static struct uvcg_frame_attribute					\
+	uvcg_frame_##cname =						\
+	__CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR,			\
+			uvcg_frame_##cname##_show,			\
+			uvcg_frame_##cname##_store)
+
+#define noop_conversion(x) (x)
+
+UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
+		noop_conversion, 8);
+UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
+		le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
+		le32_to_cpu, cpu_to_le32, 32);
+
+#undef noop_conversion
+
+#undef UVCG_FRAME_ATTR
+
+static ssize_t uvcg_frame_dw_frame_interval_show(struct uvcg_frame *frm,
+						 char *page)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
+	int result, i;
+	char *pg = page;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
+		result += sprintf(pg, "%d\n",
+				  le32_to_cpu(frm->dw_frame_interval[i]));
+		pg = page + result;
+	}
+	mutex_unlock(&opts->lock);
+
+	mutex_unlock(su_mutex);
+	return result;
+}
+
+static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
+{
+	++*((int *)priv);
+	return 0;
+}
+
+static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
+{
+	u32 num, **interv;
+	int ret;
+
+	ret = kstrtou32(buf, 0, &num);
+	if (ret)
+		return ret;
+
+	interv = priv;
+	**interv = cpu_to_le32(num);
+	++*interv;
+
+	return 0;
+}
+
+static int __uvcg_iter_frm_intrv(const char *page, size_t len,
+				 int (*fun)(char *, void *), void *priv)
+{
+	/* sign, base 2 representation, newline, terminator */
+	char buf[1 + sizeof(u32) * 8 + 1 + 1];
+	const char *pg = page;
+	int i, ret;
+
+	if (!fun)
+		return -EINVAL;
+
+	while (pg - page < len) {
+		i = 0;
+		while (i < sizeof(buf) && (pg - page < len) &&
+				*pg != '\0' && *pg != '\n')
+			buf[i++] = *pg++;
+		if (i == sizeof(buf))
+			return -EINVAL;
+		while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
+			++pg;
+		buf[i] = '\0';
+		ret = fun(buf, priv);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static ssize_t uvcg_frame_dw_frame_interval_store(struct uvcg_frame *ch,
+						  const char *page, size_t len)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct uvcg_format *fmt;
+	struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;
+	int ret = 0, n = 0;
+	u32 *frm_intrv, *tmp;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = ch->item.ci_parent->ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+	fmt = to_uvcg_format(ch->item.ci_parent);
+
+	mutex_lock(&opts->lock);
+	if (fmt->linked || opts->refcnt) {
+		ret = -EBUSY;
+		goto end;
+	}
+
+	ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
+	if (ret)
+		goto end;
+
+	tmp = frm_intrv = kcalloc(n, sizeof(u32), GFP_KERNEL);
+	if (!frm_intrv) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
+	if (ret) {
+		kfree(frm_intrv);
+		goto end;
+	}
+
+	kfree(ch->dw_frame_interval);
+	ch->dw_frame_interval = frm_intrv;
+	ch->frame.b_frame_interval_type = n;
+	ret = len;
+
+end:
+	mutex_unlock(&opts->lock);
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static struct uvcg_frame_attribute
+	uvcg_frame_dw_frame_interval =
+	__CONFIGFS_ATTR(dwFrameInterval, S_IRUGO | S_IWUSR,
+			uvcg_frame_dw_frame_interval_show,
+			uvcg_frame_dw_frame_interval_store);
+
+static struct configfs_attribute *uvcg_frame_attrs[] = {
+	&uvcg_frame_bm_capabilities.attr,
+	&uvcg_frame_w_width.attr,
+	&uvcg_frame_w_height.attr,
+	&uvcg_frame_dw_min_bit_rate.attr,
+	&uvcg_frame_dw_max_bit_rate.attr,
+	&uvcg_frame_dw_max_video_frame_buffer_size.attr,
+	&uvcg_frame_dw_default_frame_interval.attr,
+	&uvcg_frame_dw_frame_interval.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_frame_type = {
+	.ct_item_ops	= &uvcg_frame_item_ops,
+	.ct_attrs	= uvcg_frame_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item *uvcg_frame_make(struct config_group *group,
+					   const char *name)
+{
+	struct uvcg_frame *h;
+	struct uvcg_format *fmt;
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	h->frame.b_descriptor_type		= USB_DT_CS_INTERFACE;
+	h->frame.b_frame_index			= 1;
+	h->frame.w_width			= cpu_to_le16(640);
+	h->frame.w_height			= cpu_to_le16(360);
+	h->frame.dw_min_bit_rate		= cpu_to_le32(18432000);
+	h->frame.dw_max_bit_rate		= cpu_to_le32(55296000);
+	h->frame.dw_max_video_frame_buffer_size	= cpu_to_le32(460800);
+	h->frame.dw_default_frame_interval	= cpu_to_le32(666666);
+
+	opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	fmt = to_uvcg_format(&group->cg_item);
+	if (fmt->type == UVCG_UNCOMPRESSED) {
+		h->frame.b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED;
+		h->fmt_type = UVCG_UNCOMPRESSED;
+	} else if (fmt->type == UVCG_MJPEG) {
+		h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG;
+		h->fmt_type = UVCG_MJPEG;
+	} else {
+		mutex_unlock(&opts->lock);
+		kfree(h);
+		return ERR_PTR(-EINVAL);
+	}
+	++fmt->num_frames;
+	mutex_unlock(&opts->lock);
+
+	config_item_init_type_name(&h->item, name, &uvcg_frame_type);
+
+	return &h->item;
+}
+
+static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
+{
+	struct uvcg_frame *h = to_uvcg_frame(item);
+	struct uvcg_format *fmt;
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+
+	opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	fmt = to_uvcg_format(&group->cg_item);
+	--fmt->num_frames;
+	kfree(h);
+	mutex_unlock(&opts->lock);
+}
+
+/* streaming/uncompressed/<NAME> */
+struct uvcg_uncompressed {
+	struct uvcg_format		fmt;
+	struct uvc_format_uncompressed	desc;
+};
+
+static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
+{
+	return container_of(
+		container_of(to_config_group(item), struct uvcg_format, group),
+		struct uvcg_uncompressed, fmt);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_uncompressed);
+CONFIGFS_ATTR_OPS(uvcg_uncompressed);
+
+static struct configfs_item_operations uvcg_uncompressed_item_ops = {
+	.show_attribute		= uvcg_uncompressed_attr_show,
+	.store_attribute	= uvcg_uncompressed_attr_store,
+};
+
+static struct configfs_group_operations uvcg_uncompressed_group_ops = {
+	.make_item		= uvcg_frame_make,
+	.drop_item		= uvcg_frame_drop,
+};
+
+static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch,
+							char *page)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat));
+	mutex_unlock(&opts->lock);
+
+	mutex_unlock(su_mutex);
+
+	return sizeof(ch->desc.guidFormat);
+}
+
+static ssize_t uvcg_uncompressed_guid_format_store(struct uvcg_uncompressed *ch,
+						   const char *page, size_t len)
+{
+	struct f_uvc_opts *opts;
+	struct config_item *opts_item;
+	struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+	int ret;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+	opts = to_f_uvc_opts(opts_item);
+
+	mutex_lock(&opts->lock);
+	if (ch->fmt.linked || opts->refcnt) {
+		ret = -EBUSY;
+		goto end;
+	}
+
+	memcpy(ch->desc.guidFormat, page,
+	       min(sizeof(ch->desc.guidFormat), len));
+	ret = sizeof(ch->desc.guidFormat);
+
+end:
+	mutex_unlock(&opts->lock);
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static struct uvcg_uncompressed_attribute uvcg_uncompressed_guid_format =
+	__CONFIGFS_ATTR(guidFormat, S_IRUGO | S_IWUSR,
+			uvcg_uncompressed_guid_format_show,
+			uvcg_uncompressed_guid_format_store);
+
+
+#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv)			\
+static ssize_t uvcg_uncompressed_##cname##_show(			\
+	struct uvcg_uncompressed *u, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(u->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static struct uvcg_uncompressed_attribute				\
+	uvcg_uncompressed_##cname =					\
+	__CONFIGFS_ATTR_RO(aname, uvcg_uncompressed_##cname##_show)
+
+#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv)			\
+static ssize_t uvcg_uncompressed_##cname##_show(			\
+	struct uvcg_uncompressed *u, char *page)			\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(u->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static ssize_t								\
+uvcg_uncompressed_##cname##_store(struct uvcg_uncompressed *u,		\
+				    const char *page, size_t len)	\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int ret;							\
+	u8 num;								\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	if (u->fmt.linked || opts->refcnt) {				\
+		ret = -EBUSY;						\
+		goto end;						\
+	}								\
+									\
+	ret = kstrtou8(page, 0, &num);					\
+	if (ret)							\
+		goto end;						\
+									\
+	if (num > 255) {						\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+	u->desc.aname = num;						\
+	ret = len;							\
+end:									\
+	mutex_unlock(&opts->lock);					\
+	mutex_unlock(su_mutex);						\
+	return ret;							\
+}									\
+									\
+static struct uvcg_uncompressed_attribute				\
+	uvcg_uncompressed_##cname =					\
+	__CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR,			\
+			uvcg_uncompressed_##cname##_show,		\
+			uvcg_uncompressed_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv);
+UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex,
+		       identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_UNCOMPRESSED_ATTR
+#undef UVCG_UNCOMPRESSED_ATTR_RO
+
+static inline ssize_t
+uvcg_uncompressed_bma_controls_show(struct uvcg_uncompressed *unc, char *page)
+{
+	return uvcg_format_bma_controls_show(&unc->fmt, page);
+}
+
+static inline ssize_t
+uvcg_uncompressed_bma_controls_store(struct uvcg_uncompressed *ch,
+				     const char *page, size_t len)
+{
+	return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+}
+
+static struct uvcg_uncompressed_attribute uvcg_uncompressed_bma_controls =
+	__CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
+			uvcg_uncompressed_bma_controls_show,
+			uvcg_uncompressed_bma_controls_store);
+
+static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
+	&uvcg_uncompressed_guid_format.attr,
+	&uvcg_uncompressed_b_bits_per_pixel.attr,
+	&uvcg_uncompressed_b_default_frame_index.attr,
+	&uvcg_uncompressed_b_aspect_ratio_x.attr,
+	&uvcg_uncompressed_b_aspect_ratio_y.attr,
+	&uvcg_uncompressed_bm_interface_flags.attr,
+	&uvcg_uncompressed_bma_controls.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_uncompressed_type = {
+	.ct_item_ops	= &uvcg_uncompressed_item_ops,
+	.ct_group_ops	= &uvcg_uncompressed_group_ops,
+	.ct_attrs	= uvcg_uncompressed_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *uvcg_uncompressed_make(struct config_group *group,
+						   const char *name)
+{
+	static char guid[] = {
+		'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
+		 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+	};
+	struct uvcg_uncompressed *h;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	h->desc.bLength			= UVC_DT_FORMAT_UNCOMPRESSED_SIZE;
+	h->desc.bDescriptorType		= USB_DT_CS_INTERFACE;
+	h->desc.bDescriptorSubType	= UVC_VS_FORMAT_UNCOMPRESSED;
+	memcpy(h->desc.guidFormat, guid, sizeof(guid));
+	h->desc.bBitsPerPixel		= 16;
+	h->desc.bDefaultFrameIndex	= 1;
+	h->desc.bAspectRatioX		= 0;
+	h->desc.bAspectRatioY		= 0;
+	h->desc.bmInterfaceFlags	= 0;
+	h->desc.bCopyProtect		= 0;
+
+	h->fmt.type = UVCG_UNCOMPRESSED;
+	config_group_init_type_name(&h->fmt.group, name,
+				    &uvcg_uncompressed_type);
+
+	return &h->fmt.group;
+}
+
+static void uvcg_uncompressed_drop(struct config_group *group,
+			    struct config_item *item)
+{
+	struct uvcg_uncompressed *h = to_uvcg_uncompressed(item);
+
+	kfree(h);
+}
+
+static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
+	.make_group		= uvcg_uncompressed_make,
+	.drop_item		= uvcg_uncompressed_drop,
+};
+
+static struct config_item_type uvcg_uncompressed_grp_type = {
+	.ct_group_ops	= &uvcg_uncompressed_grp_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* streaming/mjpeg/<NAME> */
+struct uvcg_mjpeg {
+	struct uvcg_format		fmt;
+	struct uvc_format_mjpeg		desc;
+};
+
+static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
+{
+	return container_of(
+		container_of(to_config_group(item), struct uvcg_format, group),
+		struct uvcg_mjpeg, fmt);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_mjpeg);
+CONFIGFS_ATTR_OPS(uvcg_mjpeg);
+
+static struct configfs_item_operations uvcg_mjpeg_item_ops = {
+	.show_attribute		= uvcg_mjpeg_attr_show,
+	.store_attribute	= uvcg_mjpeg_attr_store,
+};
+
+static struct configfs_group_operations uvcg_mjpeg_group_ops = {
+	.make_item		= uvcg_frame_make,
+	.drop_item		= uvcg_frame_drop,
+};
+
+#define UVCG_MJPEG_ATTR_RO(cname, aname, conv)				\
+static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(u->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static struct uvcg_mjpeg_attribute					\
+	uvcg_mjpeg_##cname =						\
+	__CONFIGFS_ATTR_RO(aname, uvcg_mjpeg_##cname##_show)
+
+#define UVCG_MJPEG_ATTR(cname, aname, conv)				\
+static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(u->desc.aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static ssize_t								\
+uvcg_mjpeg_##cname##_store(struct uvcg_mjpeg *u,			\
+			   const char *page, size_t len)		\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex;	\
+	int ret;							\
+	u8 num;								\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+	opts = to_f_uvc_opts(opts_item);				\
+									\
+	mutex_lock(&opts->lock);					\
+	if (u->fmt.linked || opts->refcnt) {				\
+		ret = -EBUSY;						\
+		goto end;						\
+	}								\
+									\
+	ret = kstrtou8(page, 0, &num);					\
+	if (ret)							\
+		goto end;						\
+									\
+	if (num > 255) {						\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+	u->desc.aname = num;						\
+	ret = len;							\
+end:									\
+	mutex_unlock(&opts->lock);					\
+	mutex_unlock(su_mutex);						\
+	return ret;							\
+}									\
+									\
+static struct uvcg_mjpeg_attribute					\
+	uvcg_mjpeg_##cname =						\
+	__CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR,			\
+			uvcg_mjpeg_##cname##_show,			\
+			uvcg_mjpeg_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex,
+		       identity_conv);
+UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
+UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_MJPEG_ATTR
+#undef UVCG_MJPEG_ATTR_RO
+
+static inline ssize_t
+uvcg_mjpeg_bma_controls_show(struct uvcg_mjpeg *unc, char *page)
+{
+	return uvcg_format_bma_controls_show(&unc->fmt, page);
+}
+
+static inline ssize_t
+uvcg_mjpeg_bma_controls_store(struct uvcg_mjpeg *ch,
+				     const char *page, size_t len)
+{
+	return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+}
+
+static struct uvcg_mjpeg_attribute uvcg_mjpeg_bma_controls =
+	__CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
+			uvcg_mjpeg_bma_controls_show,
+			uvcg_mjpeg_bma_controls_store);
+
+static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
+	&uvcg_mjpeg_b_default_frame_index.attr,
+	&uvcg_mjpeg_bm_flags.attr,
+	&uvcg_mjpeg_b_aspect_ratio_x.attr,
+	&uvcg_mjpeg_b_aspect_ratio_y.attr,
+	&uvcg_mjpeg_bm_interface_flags.attr,
+	&uvcg_mjpeg_bma_controls.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_mjpeg_type = {
+	.ct_item_ops	= &uvcg_mjpeg_item_ops,
+	.ct_group_ops	= &uvcg_mjpeg_group_ops,
+	.ct_attrs	= uvcg_mjpeg_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *uvcg_mjpeg_make(struct config_group *group,
+						   const char *name)
+{
+	struct uvcg_mjpeg *h;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	h->desc.bLength			= UVC_DT_FORMAT_MJPEG_SIZE;
+	h->desc.bDescriptorType		= USB_DT_CS_INTERFACE;
+	h->desc.bDescriptorSubType	= UVC_VS_FORMAT_MJPEG;
+	h->desc.bDefaultFrameIndex	= 1;
+	h->desc.bAspectRatioX		= 0;
+	h->desc.bAspectRatioY		= 0;
+	h->desc.bmInterfaceFlags	= 0;
+	h->desc.bCopyProtect		= 0;
+
+	h->fmt.type = UVCG_MJPEG;
+	config_group_init_type_name(&h->fmt.group, name,
+				    &uvcg_mjpeg_type);
+
+	return &h->fmt.group;
+}
+
+static void uvcg_mjpeg_drop(struct config_group *group,
+			    struct config_item *item)
+{
+	struct uvcg_mjpeg *h = to_uvcg_mjpeg(item);
+
+	kfree(h);
+}
+
+static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
+	.make_group		= uvcg_mjpeg_make,
+	.drop_item		= uvcg_mjpeg_drop,
+};
+
+static struct config_item_type uvcg_mjpeg_grp_type = {
+	.ct_group_ops	= &uvcg_mjpeg_grp_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* streaming/color_matching/default */
+static struct uvcg_default_color_matching {
+	struct config_group	group;
+} uvcg_default_color_matching;
+
+static inline struct uvcg_default_color_matching
+*to_uvcg_default_color_matching(struct config_item *item)
+{
+	return container_of(to_config_group(item),
+			    struct uvcg_default_color_matching, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_color_matching);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_color_matching);
+
+static struct configfs_item_operations uvcg_default_color_matching_item_ops = {
+	.show_attribute		= uvcg_default_color_matching_attr_show,
+};
+
+#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv)		\
+static ssize_t uvcg_default_color_matching_##cname##_show(		\
+	struct uvcg_default_color_matching *dc, char *page)		\
+{									\
+	struct f_uvc_opts *opts;					\
+	struct config_item *opts_item;					\
+	struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;	\
+	struct uvc_color_matching_descriptor *cd;			\
+	int result;							\
+									\
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */	\
+									\
+	opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent;	\
+	opts = to_f_uvc_opts(opts_item);				\
+	cd = &opts->uvc_color_matching;					\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(cd->aname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	mutex_unlock(su_mutex);						\
+	return result;							\
+}									\
+									\
+static struct uvcg_default_color_matching_attribute			\
+	uvcg_default_color_matching_##cname =				\
+	__CONFIGFS_ATTR_RO(aname, uvcg_default_color_matching_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
+				 identity_conv);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
+				 bTransferCharacteristics, identity_conv);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
+				 identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
+
+static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
+	&uvcg_default_color_matching_b_color_primaries.attr,
+	&uvcg_default_color_matching_b_transfer_characteristics.attr,
+	&uvcg_default_color_matching_b_matrix_coefficients.attr,
+	NULL,
+};
+
+static struct config_item_type uvcg_default_color_matching_type = {
+	.ct_item_ops	= &uvcg_default_color_matching_item_ops,
+	.ct_attrs	= uvcg_default_color_matching_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* struct uvcg_color_matching {}; */
+
+static struct config_group *uvcg_color_matching_default_groups[] = {
+	&uvcg_default_color_matching.group,
+	NULL,
+};
+
+/* streaming/color_matching */
+static struct uvcg_color_matching_grp {
+	struct config_group	group;
+} uvcg_color_matching_grp;
+
+static struct config_item_type uvcg_color_matching_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+/* streaming/class/{fs|hs|ss} */
+static struct uvcg_streaming_class {
+	struct config_group	group;
+} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
+
+
+static inline struct uvc_descriptor_header
+***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
+{
+	struct uvcg_streaming_class *cl = container_of(to_config_group(i),
+		struct uvcg_streaming_class, group);
+
+	if (cl == &uvcg_streaming_class_fs)
+		return &o->uvc_fs_streaming_cls;
+
+	if (cl == &uvcg_streaming_class_hs)
+		return &o->uvc_hs_streaming_cls;
+
+	if (cl == &uvcg_streaming_class_ss)
+		return &o->uvc_ss_streaming_cls;
+
+	return NULL;
+}
+
+enum uvcg_strm_type {
+	UVCG_HEADER = 0,
+	UVCG_FORMAT,
+	UVCG_FRAME
+};
+
+/*
+ * Iterate over a hierarchy of streaming descriptors' config items.
+ * The items are created by the user with configfs.
+ *
+ * It "processes" the header pointed to by @priv1, then for each format
+ * that follows the header "processes" the format itself and then for
+ * each frame inside a format "processes" the frame.
+ *
+ * As a "processing" function the @fun is used.
+ *
+ * __uvcg_iter_strm_cls() is used in two context: first, to calculate
+ * the amount of memory needed for an array of streaming descriptors
+ * and second, to actually fill the array.
+ *
+ * @h: streaming header pointer
+ * @priv2: an "inout" parameter (the caller might want to see the changes to it)
+ * @priv3: an "inout" parameter (the caller might want to see the changes to it)
+ * @fun: callback function for processing each level of the hierarchy
+ */
+static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
+	void *priv2, void *priv3,
+	int (*fun)(void *, void *, void *, int, enum uvcg_strm_type type))
+{
+	struct uvcg_format_ptr *f;
+	struct config_group *grp;
+	struct config_item *item;
+	struct uvcg_frame *frm;
+	int ret, i, j;
+
+	if (!fun)
+		return -EINVAL;
+
+	i = j = 0;
+	ret = fun(h, priv2, priv3, 0, UVCG_HEADER);
+	if (ret)
+		return ret;
+	list_for_each_entry(f, &h->formats, entry) {
+		ret = fun(f->fmt, priv2, priv3, i++, UVCG_FORMAT);
+		if (ret)
+			return ret;
+		grp = &f->fmt->group;
+		list_for_each_entry(item, &grp->cg_children, ci_entry) {
+			frm = to_uvcg_frame(item);
+			ret = fun(frm, priv2, priv3, j++, UVCG_FRAME);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Count how many bytes are needed for an array of streaming descriptors.
+ *
+ * @priv1: pointer to a header, format or frame
+ * @priv2: inout parameter, accumulated size of the array
+ * @priv3: inout parameter, accumulated number of the array elements
+ * @n: unused, this function's prototype must match @fun in __uvcg_iter_strm_cls
+ */
+static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
+			   enum uvcg_strm_type type)
+{
+	size_t *size = priv2;
+	size_t *count = priv3;
+
+	switch (type) {
+	case UVCG_HEADER: {
+		struct uvcg_streaming_header *h = priv1;
+
+		*size += sizeof(h->desc);
+		/* bmaControls */
+		*size += h->num_fmt * UVCG_STREAMING_CONTROL_SIZE;
+	}
+	break;
+	case UVCG_FORMAT: {
+		struct uvcg_format *fmt = priv1;
+
+		if (fmt->type == UVCG_UNCOMPRESSED) {
+			struct uvcg_uncompressed *u =
+				container_of(fmt, struct uvcg_uncompressed,
+					     fmt);
+
+			*size += sizeof(u->desc);
+		} else if (fmt->type == UVCG_MJPEG) {
+			struct uvcg_mjpeg *m =
+				container_of(fmt, struct uvcg_mjpeg, fmt);
+
+			*size += sizeof(m->desc);
+		} else {
+			return -EINVAL;
+		}
+	}
+	break;
+	case UVCG_FRAME: {
+		struct uvcg_frame *frm = priv1;
+		int sz = sizeof(frm->dw_frame_interval);
+
+		*size += sizeof(frm->frame);
+		*size += frm->frame.b_frame_interval_type * sz;
+	}
+	break;
+	}
+
+	++*count;
+
+	return 0;
+}
+
+/*
+ * Fill an array of streaming descriptors.
+ *
+ * @priv1: pointer to a header, format or frame
+ * @priv2: inout parameter, pointer into a block of memory
+ * @priv3: inout parameter, pointer to a 2-dimensional array
+ */
+static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
+			    enum uvcg_strm_type type)
+{
+	void **dest = priv2;
+	struct uvc_descriptor_header ***array = priv3;
+	size_t sz;
+
+	**array = *dest;
+	++*array;
+
+	switch (type) {
+	case UVCG_HEADER: {
+		struct uvc_input_header_descriptor *ihdr = *dest;
+		struct uvcg_streaming_header *h = priv1;
+		struct uvcg_format_ptr *f;
+
+		memcpy(*dest, &h->desc, sizeof(h->desc));
+		*dest += sizeof(h->desc);
+		sz = UVCG_STREAMING_CONTROL_SIZE;
+		list_for_each_entry(f, &h->formats, entry) {
+			memcpy(*dest, f->fmt->bmaControls, sz);
+			*dest += sz;
+		}
+		ihdr->bLength = sizeof(h->desc) + h->num_fmt * sz;
+		ihdr->bNumFormats = h->num_fmt;
+	}
+	break;
+	case UVCG_FORMAT: {
+		struct uvcg_format *fmt = priv1;
+
+		if (fmt->type == UVCG_UNCOMPRESSED) {
+			struct uvc_format_uncompressed *unc = *dest;
+			struct uvcg_uncompressed *u =
+				container_of(fmt, struct uvcg_uncompressed,
+					     fmt);
+
+			memcpy(*dest, &u->desc, sizeof(u->desc));
+			*dest += sizeof(u->desc);
+			unc->bNumFrameDescriptors = fmt->num_frames;
+			unc->bFormatIndex = n + 1;
+		} else if (fmt->type == UVCG_MJPEG) {
+			struct uvc_format_mjpeg *mjp = *dest;
+			struct uvcg_mjpeg *m =
+				container_of(fmt, struct uvcg_mjpeg, fmt);
+
+			memcpy(*dest, &m->desc, sizeof(m->desc));
+			*dest += sizeof(m->desc);
+			mjp->bNumFrameDescriptors = fmt->num_frames;
+			mjp->bFormatIndex = n + 1;
+		} else {
+			return -EINVAL;
+		}
+	}
+	break;
+	case UVCG_FRAME: {
+		struct uvcg_frame *frm = priv1;
+		struct uvc_descriptor_header *h = *dest;
+
+		sz = sizeof(frm->frame);
+		memcpy(*dest, &frm->frame, sz);
+		*dest += sz;
+		sz = frm->frame.b_frame_interval_type *
+			sizeof(*frm->dw_frame_interval);
+		memcpy(*dest, frm->dw_frame_interval, sz);
+		*dest += sz;
+		if (frm->fmt_type == UVCG_UNCOMPRESSED)
+			h->bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(
+				frm->frame.b_frame_interval_type);
+		else if (frm->fmt_type == UVCG_MJPEG)
+			h->bLength = UVC_DT_FRAME_MJPEG_SIZE(
+				frm->frame.b_frame_interval_type);
+	}
+	break;
+	}
+
+	return 0;
+}
+
+static int uvcg_streaming_class_allow_link(struct config_item *src,
+					   struct config_item *target)
+{
+	struct config_item *streaming, *header;
+	struct f_uvc_opts *opts;
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct uvc_descriptor_header ***class_array, **cl_arr;
+	struct uvcg_streaming_header *target_hdr;
+	void *data, *data_save;
+	size_t size = 0, count = 0;
+	int ret = -EINVAL;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	streaming = src->ci_parent->ci_parent;
+	header = config_group_find_item(to_config_group(streaming), "header");
+	if (!header || target->ci_parent != header)
+		goto out;
+
+	opts = to_f_uvc_opts(streaming->ci_parent);
+
+	mutex_lock(&opts->lock);
+
+	class_array = __uvcg_get_stream_class_arr(src, opts);
+	if (!class_array || *class_array || opts->refcnt) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	target_hdr = to_uvcg_streaming_header(target);
+	ret = __uvcg_iter_strm_cls(target_hdr, &size, &count, __uvcg_cnt_strm);
+	if (ret)
+		goto unlock;
+
+	count += 2; /* color_matching, NULL */
+	*class_array = kcalloc(count, sizeof(void *), GFP_KERNEL);
+	if (!*class_array) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	data = data_save = kzalloc(size, GFP_KERNEL);
+	if (!data) {
+		kfree(*class_array);
+		*class_array = NULL;
+		ret = PTR_ERR(data);
+		goto unlock;
+	}
+	cl_arr = *class_array;
+	ret = __uvcg_iter_strm_cls(target_hdr, &data, &cl_arr,
+				   __uvcg_fill_strm);
+	if (ret) {
+		kfree(*class_array);
+		*class_array = NULL;
+		/*
+		 * __uvcg_fill_strm() called from __uvcg_iter_stream_cls()
+		 * might have advanced the "data", so use a backup copy
+		 */
+		kfree(data_save);
+		goto unlock;
+	}
+	*cl_arr = (struct uvc_descriptor_header *)&opts->uvc_color_matching;
+
+	++target_hdr->linked;
+	ret = 0;
+
+unlock:
+	mutex_unlock(&opts->lock);
+out:
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static int uvcg_streaming_class_drop_link(struct config_item *src,
+					  struct config_item *target)
+{
+	struct config_item *streaming, *header;
+	struct f_uvc_opts *opts;
+	struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+	struct uvc_descriptor_header ***class_array;
+	struct uvcg_streaming_header *target_hdr;
+	int ret = -EINVAL;
+
+	mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+	streaming = src->ci_parent->ci_parent;
+	header = config_group_find_item(to_config_group(streaming), "header");
+	if (!header || target->ci_parent != header)
+		goto out;
+
+	opts = to_f_uvc_opts(streaming->ci_parent);
+
+	mutex_lock(&opts->lock);
+
+	class_array = __uvcg_get_stream_class_arr(src, opts);
+	if (!class_array || !*class_array)
+		goto unlock;
+
+	if (opts->refcnt) {
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	target_hdr = to_uvcg_streaming_header(target);
+	--target_hdr->linked;
+	kfree(**class_array);
+	kfree(*class_array);
+	*class_array = NULL;
+	ret = 0;
+
+unlock:
+	mutex_unlock(&opts->lock);
+out:
+	mutex_unlock(su_mutex);
+	return ret;
+}
+
+static struct configfs_item_operations uvcg_streaming_class_item_ops = {
+	.allow_link	= uvcg_streaming_class_allow_link,
+	.drop_link	= uvcg_streaming_class_drop_link,
+};
+
+static struct config_item_type uvcg_streaming_class_type = {
+	.ct_item_ops	= &uvcg_streaming_class_item_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_group *uvcg_streaming_class_default_groups[] = {
+	&uvcg_streaming_class_fs.group,
+	&uvcg_streaming_class_hs.group,
+	&uvcg_streaming_class_ss.group,
+	NULL,
+};
+
+/* streaming/class */
+static struct uvcg_streaming_class_grp {
+	struct config_group	group;
+} uvcg_streaming_class_grp;
+
+static struct config_item_type uvcg_streaming_class_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_streaming_default_groups[] = {
+	&uvcg_streaming_header_grp.group,
+	&uvcg_uncompressed_grp.group,
+	&uvcg_mjpeg_grp.group,
+	&uvcg_color_matching_grp.group,
+	&uvcg_streaming_class_grp.group,
+	NULL,
+};
+
+/* streaming */
+static struct uvcg_streaming_grp {
+	struct config_group	group;
+} uvcg_streaming_grp;
+
+static struct config_item_type uvcg_streaming_grp_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_default_groups[] = {
+	&uvcg_control_grp.group,
+	&uvcg_streaming_grp.group,
+	NULL,
+};
+
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct f_uvc_opts,
+			    func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_uvc_opts);
+CONFIGFS_ATTR_OPS(f_uvc_opts);
+
+static void uvc_attr_release(struct config_item *item)
+{
+	struct f_uvc_opts *opts = to_f_uvc_opts(item);
+
+	usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations uvc_item_ops = {
+	.release		= uvc_attr_release,
+	.show_attribute		= f_uvc_opts_attr_show,
+	.store_attribute	= f_uvc_opts_attr_store,
+};
+
+#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit)		\
+static ssize_t f_uvc_opts_##cname##_show(				\
+	struct f_uvc_opts *opts, char *page)				\
+{									\
+	int result;							\
+									\
+	mutex_lock(&opts->lock);					\
+	result = sprintf(page, "%d\n", conv(opts->cname));		\
+	mutex_unlock(&opts->lock);					\
+									\
+	return result;							\
+}									\
+									\
+static ssize_t								\
+f_uvc_opts_##cname##_store(struct f_uvc_opts *opts,			\
+			   const char *page, size_t len)		\
+{									\
+	int ret;							\
+	uxx num;							\
+									\
+	mutex_lock(&opts->lock);					\
+	if (opts->refcnt) {						\
+		ret = -EBUSY;						\
+		goto end;						\
+	}								\
+									\
+	ret = str2u(page, 0, &num);					\
+	if (ret)							\
+		goto end;						\
+									\
+	if (num > limit) {						\
+		ret = -EINVAL;						\
+		goto end;						\
+	}								\
+	opts->cname = vnoc(num);					\
+	ret = len;							\
+end:									\
+	mutex_unlock(&opts->lock);					\
+	return ret;							\
+}									\
+									\
+static struct f_uvc_opts_attribute					\
+	f_uvc_opts_attribute_##cname =					\
+	__CONFIGFS_ATTR(cname, S_IRUGO | S_IWUSR,			\
+			f_uvc_opts_##cname##_show,			\
+			f_uvc_opts_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
+	       16);
+UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
+	       3072);
+UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
+	       15);
+
+#undef identity_conv
+
+#undef UVCG_OPTS_ATTR
+
+static struct configfs_attribute *uvc_attrs[] = {
+	&f_uvc_opts_attribute_streaming_interval.attr,
+	&f_uvc_opts_attribute_streaming_maxpacket.attr,
+	&f_uvc_opts_attribute_streaming_maxburst.attr,
+	NULL,
+};
+
+static struct config_item_type uvc_func_type = {
+	.ct_item_ops	= &uvc_item_ops,
+	.ct_attrs	= uvc_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static inline void uvcg_init_group(struct config_group *g,
+				   struct config_group **default_groups,
+				   const char *name,
+				   struct config_item_type *type)
+{
+	g->default_groups = default_groups;
+	config_group_init_type_name(g, name, type);
+}
+
+int uvcg_attach_configfs(struct f_uvc_opts *opts)
+{
+	config_group_init_type_name(&uvcg_control_header_grp.group,
+				    "header",
+				    &uvcg_control_header_grp_type);
+	config_group_init_type_name(&uvcg_default_processing.group,
+				    "default",
+				    &uvcg_default_processing_type);
+	uvcg_init_group(&uvcg_processing_grp.group,
+			uvcg_processing_default_groups,
+			"processing",
+			&uvcg_processing_grp_type);
+	config_group_init_type_name(&uvcg_default_camera.group,
+				    "default",
+				    &uvcg_default_camera_type);
+	uvcg_init_group(&uvcg_camera_grp.group,
+			uvcg_camera_default_groups,
+			"camera",
+			&uvcg_camera_grp_type);
+	config_group_init_type_name(&uvcg_default_output.group,
+				    "default",
+				    &uvcg_default_output_type);
+	uvcg_init_group(&uvcg_output_grp.group,
+			uvcg_output_default_groups,
+			"output",
+			&uvcg_output_grp_type);
+	uvcg_init_group(&uvcg_terminal_grp.group,
+			uvcg_terminal_default_groups,
+			"terminal",
+			&uvcg_terminal_grp_type);
+	config_group_init_type_name(&uvcg_control_class_fs.group,
+				    "fs",
+				    &uvcg_control_class_type);
+	config_group_init_type_name(&uvcg_control_class_ss.group,
+				    "ss",
+				    &uvcg_control_class_type);
+	uvcg_init_group(&uvcg_control_class_grp.group,
+			uvcg_control_class_default_groups,
+			"class",
+			&uvcg_control_class_grp_type);
+	uvcg_init_group(&uvcg_control_grp.group,
+			uvcg_control_default_groups,
+			"control",
+			&uvcg_control_grp_type);
+	config_group_init_type_name(&uvcg_streaming_header_grp.group,
+				    "header",
+				    &uvcg_streaming_header_grp_type);
+	config_group_init_type_name(&uvcg_uncompressed_grp.group,
+				    "uncompressed",
+				    &uvcg_uncompressed_grp_type);
+	config_group_init_type_name(&uvcg_mjpeg_grp.group,
+				    "mjpeg",
+				    &uvcg_mjpeg_grp_type);
+	config_group_init_type_name(&uvcg_default_color_matching.group,
+				    "default",
+				    &uvcg_default_color_matching_type);
+	uvcg_init_group(&uvcg_color_matching_grp.group,
+			uvcg_color_matching_default_groups,
+			"color_matching",
+			&uvcg_color_matching_grp_type);
+	config_group_init_type_name(&uvcg_streaming_class_fs.group,
+				    "fs",
+				    &uvcg_streaming_class_type);
+	config_group_init_type_name(&uvcg_streaming_class_hs.group,
+				    "hs",
+				    &uvcg_streaming_class_type);
+	config_group_init_type_name(&uvcg_streaming_class_ss.group,
+				    "ss",
+				    &uvcg_streaming_class_type);
+	uvcg_init_group(&uvcg_streaming_class_grp.group,
+			uvcg_streaming_class_default_groups,
+			"class",
+			&uvcg_streaming_class_grp_type);
+	uvcg_init_group(&uvcg_streaming_grp.group,
+			uvcg_streaming_default_groups,
+			"streaming",
+			&uvcg_streaming_grp_type);
+	uvcg_init_group(&opts->func_inst.group,
+			uvcg_default_groups,
+			"",
+			&uvc_func_type);
+	return 0;
+}
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
new file mode 100644
index 0000000..085e67b
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -0,0 +1,22 @@
+/*
+ * uvc_configfs.h
+ *
+ * Configfs support for the uvc function.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@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.
+ */
+#ifndef UVC_CONFIGFS_H
+#define UVC_CONFIGFS_H
+
+struct f_uvc_opts;
+
+int uvcg_attach_configfs(struct f_uvc_opts *opts);
+
+#endif /* UVC_CONFIGFS_H */
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index b8e213e..366e551 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -32,6 +32,7 @@
 config USB_AT91
 	tristate "Atmel AT91 USB Device Port"
 	depends on ARCH_AT91
+	depends on OF || COMPILE_TEST
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   full speed USB Device Port with support for five configurable
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index c862656..2fbedca 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -31,16 +31,9 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_data/atmel.h>
-
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/cpu.h>
-#include <mach/at91sam9261_matrix.h>
-#include <mach/at91_matrix.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-matrix.h>
 
 #include "at91_udc.h"
 
@@ -66,7 +59,15 @@
 #define	DRIVER_VERSION	"3 May 2006"
 
 static const char driver_name [] = "at91_udc";
-static const char ep0name[] = "ep0";
+static const char * const ep_names[] = {
+	"ep0",
+	"ep1",
+	"ep2",
+	"ep3-int",
+	"ep4",
+	"ep5",
+};
+#define ep0name		ep_names[0]
 
 #define VBUS_POLL_TIMEOUT	msecs_to_jiffies(1000)
 
@@ -176,7 +177,7 @@
 		udc->enabled
 			? (udc->vbus ? "active" : "enabled")
 			: "disabled",
-		udc->selfpowered ? "self" : "VBUS",
+		udc->gadget.is_selfpowered ? "self" : "VBUS",
 		udc->suspended ? ", suspended" : "",
 		udc->driver ? udc->driver->driver.name : "(none)");
 
@@ -895,8 +896,6 @@
 		return;
 	udc->clocked = 1;
 
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_enable(udc->uclk);
 	clk_enable(udc->iclk);
 	clk_enable(udc->fclk);
 }
@@ -909,8 +908,6 @@
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	clk_disable(udc->fclk);
 	clk_disable(udc->iclk);
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_disable(udc->uclk);
 }
 
 /*
@@ -919,8 +916,6 @@
  */
 static void pullup(struct at91_udc *udc, int is_on)
 {
-	int	active = !udc->board.pullup_active_low;
-
 	if (!udc->enabled || !udc->vbus)
 		is_on = 0;
 	DBG("%sactive\n", is_on ? "" : "in");
@@ -929,40 +924,15 @@
 		clk_on(udc);
 		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
 		at91_udp_write(udc, AT91_UDP_TXVC, 0);
-		if (cpu_is_at91rm9200())
-			gpio_set_value(udc->board.pullup_pin, active);
-		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
-			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
-			txvc |= AT91_UDP_TXVC_PUON;
-			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
-			u32	usbpucr;
-
-			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
-			usbpucr |= AT91_MATRIX_USBPUCR_PUON;
-			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
-		}
 	} else {
 		stop_activity(udc);
 		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
 		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
-		if (cpu_is_at91rm9200())
-			gpio_set_value(udc->board.pullup_pin, !active);
-		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
-			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
-			txvc &= ~AT91_UDP_TXVC_PUON;
-			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
-			u32	usbpucr;
-
-			usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
-			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
-			at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
-		}
 		clk_off(udc);
 	}
+
+	if (udc->caps && udc->caps->pullup)
+		udc->caps->pullup(udc, is_on);
 }
 
 /* vbus is here!  turn everything on that's ready */
@@ -1000,7 +970,7 @@
 	unsigned long	flags;
 
 	spin_lock_irqsave(&udc->lock, flags);
-	udc->selfpowered = (is_on != 0);
+	gadget->is_selfpowered = (is_on != 0);
 	spin_unlock_irqrestore(&udc->lock, flags);
 	return 0;
 }
@@ -1149,7 +1119,7 @@
 	 */
 	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 			| USB_REQ_GET_STATUS:
-		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
 		if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
 			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 		PACKET("get device status\n");
@@ -1535,74 +1505,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct at91_udc controller = {
-	.gadget = {
-		.ops	= &at91_udc_ops,
-		.ep0	= &controller.ep[0].ep,
-		.name	= driver_name,
-	},
-	.ep[0] = {
-		.ep = {
-			.name	= ep0name,
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.maxpacket	= 8,
-		.int_mask	= 1 << 0,
-	},
-	.ep[1] = {
-		.ep = {
-			.name	= "ep1",
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.is_pingpong	= 1,
-		.maxpacket	= 64,
-		.int_mask	= 1 << 1,
-	},
-	.ep[2] = {
-		.ep = {
-			.name	= "ep2",
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.is_pingpong	= 1,
-		.maxpacket	= 64,
-		.int_mask	= 1 << 2,
-	},
-	.ep[3] = {
-		.ep = {
-			/* could actually do bulk too */
-			.name	= "ep3-int",
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.maxpacket	= 8,
-		.int_mask	= 1 << 3,
-	},
-	.ep[4] = {
-		.ep = {
-			.name	= "ep4",
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.is_pingpong	= 1,
-		.maxpacket	= 256,
-		.int_mask	= 1 << 4,
-	},
-	.ep[5] = {
-		.ep = {
-			.name	= "ep5",
-			.ops	= &at91_ep_ops,
-		},
-		.udc		= &controller,
-		.is_pingpong	= 1,
-		.maxpacket	= 256,
-		.int_mask	= 1 << 5,
-	},
-	/* ep6 and ep7 are also reserved (custom silicon might use them) */
-};
-
 static void at91_vbus_update(struct at91_udc *udc, unsigned value)
 {
 	value ^= udc->board.vbus_active_low;
@@ -1653,7 +1555,7 @@
 	udc->driver = driver;
 	udc->gadget.dev.of_node = udc->pdev->dev.of_node;
 	udc->enabled = 1;
-	udc->selfpowered = 1;
+	udc->gadget.is_selfpowered = 1;
 
 	return 0;
 }
@@ -1687,12 +1589,202 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 }
 
-static void at91udc_of_init(struct at91_udc *udc,
-				     struct device_node *np)
+static int at91rm9200_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int ret;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+		case 3:
+			ep->maxpacket = 8;
+			break;
+		case 1 ... 2:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	if (!gpio_is_valid(udc->board.pullup_pin)) {
+		DBG("no D+ pullup?\n");
+		return -ENODEV;
+	}
+
+	ret = devm_gpio_request(&udc->pdev->dev, udc->board.pullup_pin,
+				"udc_pullup");
+	if (ret) {
+		DBG("D+ pullup is busy\n");
+		return ret;
+	}
+
+	gpio_direction_output(udc->board.pullup_pin,
+			      udc->board.pullup_active_low);
+
+	return 0;
+}
+
+static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	int active = !udc->board.pullup_active_low;
+
+	if (is_on)
+		gpio_set_value(udc->board.pullup_pin, active);
+	else
+		gpio_set_value(udc->board.pullup_pin, !active);
+}
+
+static const struct at91_udc_caps at91rm9200_udc_caps = {
+	.init = at91rm9200_udc_init,
+	.pullup = at91rm9200_udc_pullup,
+};
+
+static int at91sam9260_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 512;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void at91sam9260_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+	if (is_on)
+		txvc |= AT91_UDP_TXVC_PUON;
+	else
+		txvc &= ~AT91_UDP_TXVC_PUON;
+
+	at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+}
+
+static const struct at91_udc_caps at91sam9260_udc_caps = {
+	.init = at91sam9260_udc_init,
+	.pullup = at91sam9260_udc_pullup,
+};
+
+static int at91sam9261_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+			ep->maxpacket = 8;
+			break;
+		case 1 ... 3:
+			ep->maxpacket = 64;
+			break;
+		case 4 ... 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
+						      "atmel,matrix");
+	if (IS_ERR(udc->matrix))
+		return PTR_ERR(udc->matrix);
+
+	return 0;
+}
+
+static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
+{
+	u32 usbpucr = 0;
+
+	if (is_on)
+		usbpucr = AT91_MATRIX_USBPUCR_PUON;
+
+	regmap_update_bits(udc->matrix, AT91SAM9261_MATRIX_USBPUCR,
+			   AT91_MATRIX_USBPUCR_PUON, usbpucr);
+}
+
+static const struct at91_udc_caps at91sam9261_udc_caps = {
+	.init = at91sam9261_udc_init,
+	.pullup = at91sam9261_udc_pullup,
+};
+
+static int at91sam9263_udc_init(struct at91_udc *udc)
+{
+	struct at91_ep *ep;
+	int i;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+
+		switch (i) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+			ep->maxpacket = 64;
+			break;
+		case 4:
+		case 5:
+			ep->maxpacket = 256;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static const struct at91_udc_caps at91sam9263_udc_caps = {
+	.init = at91sam9263_udc_init,
+	.pullup = at91sam9260_udc_pullup,
+};
+
+static const struct of_device_id at91_udc_dt_ids[] = {
+	{
+		.compatible = "atmel,at91rm9200-udc",
+		.data = &at91rm9200_udc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9260-udc",
+		.data = &at91sam9260_udc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9261-udc",
+		.data = &at91sam9261_udc_caps,
+	},
+	{
+		.compatible = "atmel,at91sam9263-udc",
+		.data = &at91sam9263_udc_caps,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+
+static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
 {
 	struct at91_udc_data *board = &udc->board;
-	u32 val;
+	const struct of_device_id *match;
 	enum of_gpio_flags flags;
+	u32 val;
 
 	if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
 		board->vbus_polled = 1;
@@ -1705,6 +1797,10 @@
 						  &flags);
 
 	board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+	match = of_match_node(at91_udc_dt_ids, np);
+	if (match)
+		udc->caps = match->data;
 }
 
 static int at91udc_probe(struct platform_device *pdev)
@@ -1713,97 +1809,67 @@
 	struct at91_udc	*udc;
 	int		retval;
 	struct resource	*res;
+	struct at91_ep	*ep;
+	int		i;
 
-	if (!dev_get_platdata(dev) && !pdev->dev.of_node) {
-		/* small (so we copy it) but critical! */
-		DBG("missing platform_data\n");
-		return -ENODEV;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENXIO;
-
-	if (!request_mem_region(res->start, resource_size(res), driver_name)) {
-		DBG("someone's using UDC memory\n");
-		return -EBUSY;
-	}
+	udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
 
 	/* init software state */
-	udc = &controller;
 	udc->gadget.dev.parent = dev;
-	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
-		at91udc_of_init(udc, pdev->dev.of_node);
-	else
-		memcpy(&udc->board, dev_get_platdata(dev),
-		       sizeof(struct at91_udc_data));
+	at91udc_of_init(udc, pdev->dev.of_node);
 	udc->pdev = pdev;
 	udc->enabled = 0;
 	spin_lock_init(&udc->lock);
 
-	/* rm9200 needs manual D+ pullup; off by default */
-	if (cpu_is_at91rm9200()) {
-		if (!gpio_is_valid(udc->board.pullup_pin)) {
-			DBG("no D+ pullup?\n");
-			retval = -ENODEV;
-			goto fail0;
-		}
-		retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
-		if (retval) {
-			DBG("D+ pullup is busy\n");
-			goto fail0;
-		}
-		gpio_direction_output(udc->board.pullup_pin,
-				udc->board.pullup_active_low);
+	udc->gadget.ops = &at91_udc_ops;
+	udc->gadget.ep0 = &udc->ep[0].ep;
+	udc->gadget.name = driver_name;
+	udc->gadget.dev.init_name = "gadget";
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		ep = &udc->ep[i];
+		ep->ep.name = ep_names[i];
+		ep->ep.ops = &at91_ep_ops;
+		ep->udc = udc;
+		ep->int_mask = BIT(i);
+		if (i != 0 && i != 3)
+			ep->is_pingpong = 1;
 	}
 
-	/* newer chips have more FIFO memory than rm9200 */
-	if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
-		udc->ep[0].maxpacket = 64;
-		udc->ep[3].maxpacket = 64;
-		udc->ep[4].maxpacket = 512;
-		udc->ep[5].maxpacket = 512;
-	} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
-		udc->ep[3].maxpacket = 64;
-	} else if (cpu_is_at91sam9263()) {
-		udc->ep[0].maxpacket = 64;
-		udc->ep[3].maxpacket = 64;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	udc->udp_baseaddr = devm_ioremap_resource(dev, res);
+	if (IS_ERR(udc->udp_baseaddr))
+		return PTR_ERR(udc->udp_baseaddr);
 
-	udc->udp_baseaddr = ioremap(res->start, resource_size(res));
-	if (!udc->udp_baseaddr) {
-		retval = -ENOMEM;
-		goto fail0a;
+	if (udc->caps && udc->caps->init) {
+		retval = udc->caps->init(udc);
+		if (retval)
+			return retval;
 	}
 
 	udc_reinit(udc);
 
 	/* get interface and function clocks */
-	udc->iclk = clk_get(dev, "udc_clk");
-	udc->fclk = clk_get(dev, "udpck");
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		udc->uclk = clk_get(dev, "usb_clk");
-	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) ||
-	    (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) {
-		DBG("clocks missing\n");
-		retval = -ENODEV;
-		goto fail1;
-	}
+	udc->iclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(udc->iclk))
+		return PTR_ERR(udc->iclk);
+
+	udc->fclk = devm_clk_get(dev, "hclk");
+	if (IS_ERR(udc->fclk))
+		return PTR_ERR(udc->fclk);
 
 	/* don't do anything until we have both gadget driver and VBUS */
-	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-		clk_set_rate(udc->uclk, 48000000);
-		retval = clk_prepare(udc->uclk);
-		if (retval)
-			goto fail1;
-	}
+	clk_set_rate(udc->fclk, 48000000);
 	retval = clk_prepare(udc->fclk);
 	if (retval)
-		goto fail1a;
+		return retval;
 
 	retval = clk_prepare_enable(udc->iclk);
 	if (retval)
-		goto fail1b;
+		goto err_unprepare_fclk;
+
 	at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
 	at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
 	/* Clear all pending interrupts - UDP may be used by bootloader. */
@@ -1812,18 +1878,21 @@
 
 	/* request UDC and maybe VBUS irqs */
 	udc->udp_irq = platform_get_irq(pdev, 0);
-	retval = request_irq(udc->udp_irq, at91_udc_irq,
-			0, driver_name, udc);
-	if (retval < 0) {
+	retval = devm_request_irq(dev, udc->udp_irq, at91_udc_irq, 0,
+				  driver_name, udc);
+	if (retval) {
 		DBG("request irq %d failed\n", udc->udp_irq);
-		goto fail1c;
+		goto err_unprepare_iclk;
 	}
+
 	if (gpio_is_valid(udc->board.vbus_pin)) {
-		retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
-		if (retval < 0) {
+		retval = devm_gpio_request(dev, udc->board.vbus_pin,
+					   "udc_vbus");
+		if (retval) {
 			DBG("request vbus pin failed\n");
-			goto fail2;
+			goto err_unprepare_iclk;
 		}
+
 		gpio_direction_input(udc->board.vbus_pin);
 
 		/*
@@ -1840,12 +1909,13 @@
 			mod_timer(&udc->vbus_timer,
 				  jiffies + VBUS_POLL_TIMEOUT);
 		} else {
-			if (request_irq(gpio_to_irq(udc->board.vbus_pin),
-					at91_vbus_irq, 0, driver_name, udc)) {
+			retval = devm_request_irq(dev,
+					gpio_to_irq(udc->board.vbus_pin),
+					at91_vbus_irq, 0, driver_name, udc);
+			if (retval) {
 				DBG("request vbus irq %d failed\n",
 				    udc->board.vbus_pin);
-				retval = -EBUSY;
-				goto fail3;
+				goto err_unprepare_iclk;
 			}
 		}
 	} else {
@@ -1854,49 +1924,27 @@
 	}
 	retval = usb_add_gadget_udc(dev, &udc->gadget);
 	if (retval)
-		goto fail4;
+		goto err_unprepare_iclk;
 	dev_set_drvdata(dev, udc);
 	device_init_wakeup(dev, 1);
 	create_debug_file(udc);
 
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	return 0;
-fail4:
-	if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled)
-		free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
-fail3:
-	if (gpio_is_valid(udc->board.vbus_pin))
-		gpio_free(udc->board.vbus_pin);
-fail2:
-	free_irq(udc->udp_irq, udc);
-fail1c:
+
+err_unprepare_iclk:
 	clk_unprepare(udc->iclk);
-fail1b:
+err_unprepare_fclk:
 	clk_unprepare(udc->fclk);
-fail1a:
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_unprepare(udc->uclk);
-fail1:
-	if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
-		clk_put(udc->uclk);
-	if (!IS_ERR(udc->fclk))
-		clk_put(udc->fclk);
-	if (!IS_ERR(udc->iclk))
-		clk_put(udc->iclk);
-	iounmap(udc->udp_baseaddr);
-fail0a:
-	if (cpu_is_at91rm9200())
-		gpio_free(udc->board.pullup_pin);
-fail0:
-	release_mem_region(res->start, resource_size(res));
+
 	DBG("%s probe failed, %d\n", driver_name, retval);
+
 	return retval;
 }
 
 static int __exit at91udc_remove(struct platform_device *pdev)
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
-	struct resource *res;
 	unsigned long	flags;
 
 	DBG("remove\n");
@@ -1911,29 +1959,9 @@
 
 	device_init_wakeup(&pdev->dev, 0);
 	remove_debug_file(udc);
-	if (gpio_is_valid(udc->board.vbus_pin)) {
-		free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
-		gpio_free(udc->board.vbus_pin);
-	}
-	free_irq(udc->udp_irq, udc);
-	iounmap(udc->udp_baseaddr);
-
-	if (cpu_is_at91rm9200())
-		gpio_free(udc->board.pullup_pin);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_unprepare(udc->uclk);
 	clk_unprepare(udc->fclk);
 	clk_unprepare(udc->iclk);
 
-	clk_put(udc->iclk);
-	clk_put(udc->fclk);
-	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_put(udc->uclk);
-
 	return 0;
 }
 
@@ -1989,15 +2017,6 @@
 #define	at91udc_resume	NULL
 #endif
 
-#if defined(CONFIG_OF)
-static const struct of_device_id at91_udc_dt_ids[] = {
-	{ .compatible = "atmel,at91rm9200-udc" },
-	{ /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
-#endif
-
 static struct platform_driver at91_udc_driver = {
 	.remove		= __exit_p(at91udc_remove),
 	.shutdown	= at91udc_shutdown,
@@ -2005,7 +2024,7 @@
 	.resume		= at91udc_resume,
 	.driver		= {
 		.name	= (char *) driver_name,
-		.of_match_table	= of_match_ptr(at91_udc_dt_ids),
+		.of_match_table	= at91_udc_dt_ids,
 	},
 };
 
diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h
index 0175246..2679c8b 100644
--- a/drivers/usb/gadget/udc/at91_udc.h
+++ b/drivers/usb/gadget/udc/at91_udc.h
@@ -107,6 +107,11 @@
 	unsigned			fifo_bank:1;
 };
 
+struct at91_udc_caps {
+	int (*init)(struct at91_udc *udc);
+	void (*pullup)(struct at91_udc *udc, int is_on);
+};
+
 /*
  * driver is non-SMP, and just blocks IRQs whenever it needs
  * access protection for chip registers or driver state
@@ -115,6 +120,7 @@
 	struct usb_gadget		gadget;
 	struct at91_ep			ep[NUM_ENDPOINTS];
 	struct usb_gadget_driver	*driver;
+	const struct at91_udc_caps	*caps;
 	unsigned			vbus:1;
 	unsigned			enabled:1;
 	unsigned			clocked:1;
@@ -122,11 +128,10 @@
 	unsigned			req_pending:1;
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_config_ack:1;
-	unsigned			selfpowered:1;
 	unsigned			active_suspend:1;
 	u8				addr;
 	struct at91_udc_data		board;
-	struct clk			*iclk, *fclk, *uclk;
+	struct clk			*iclk, *fclk;
 	struct platform_device		*pdev;
 	struct proc_dir_entry		*pde;
 	void __iomem			*udp_baseaddr;
@@ -134,6 +139,7 @@
 	spinlock_t			lock;
 	struct timer_list		vbus_timer;
 	struct work_struct		vbus_timer_work;
+	struct regmap			*matrix;
 };
 
 static inline struct at91_udc *to_udc(struct usb_gadget *g)
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 9f93bed..c041086 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -315,6 +316,17 @@
 }
 #endif
 
+static inline u32 usba_int_enb_get(struct usba_udc *udc)
+{
+	return udc->int_enb_cache;
+}
+
+static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
+{
+	usba_writel(udc, INT_ENB, val);
+	udc->int_enb_cache = val;
+}
+
 static int vbus_is_present(struct usba_udc *udc)
 {
 	if (gpio_is_valid(udc->vbus_pin))
@@ -324,27 +336,22 @@
 	return 1;
 }
 
-#if defined(CONFIG_ARCH_AT91SAM9RL)
-
-#include <linux/clk/at91_pmc.h>
-
-static void toggle_bias(int is_on)
+static void toggle_bias(struct usba_udc *udc, int is_on)
 {
-	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
-
-	if (is_on)
-		at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
-	else
-		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+	if (udc->errata && udc->errata->toggle_bias)
+		udc->errata->toggle_bias(udc, is_on);
 }
 
-#else
-
-static void toggle_bias(int is_on)
+static void generate_bias_pulse(struct usba_udc *udc)
 {
-}
+	if (!udc->bias_pulse_needed)
+		return;
 
-#endif /* CONFIG_ARCH_AT91SAM9RL */
+	if (udc->errata && udc->errata->pulse_bias)
+		udc->errata->pulse_bias(udc);
+
+	udc->bias_pulse_needed = false;
+}
 
 static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
 {
@@ -601,16 +608,14 @@
 	if (ep->can_dma) {
 		u32 ctrl;
 
-		usba_writel(udc, INT_ENB,
-				(usba_readl(udc, INT_ENB)
-					| USBA_BF(EPT_INT, 1 << ep->index)
-					| USBA_BF(DMA_INT, 1 << ep->index)));
+		usba_int_enb_set(udc, usba_int_enb_get(udc) |
+				      USBA_BF(EPT_INT, 1 << ep->index) |
+				      USBA_BF(DMA_INT, 1 << ep->index));
 		ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
 		usba_ep_writel(ep, CTL_ENB, ctrl);
 	} else {
-		usba_writel(udc, INT_ENB,
-				(usba_readl(udc, INT_ENB)
-					| USBA_BF(EPT_INT, 1 << ep->index)));
+		usba_int_enb_set(udc, usba_int_enb_get(udc) |
+				      USBA_BF(EPT_INT, 1 << ep->index));
 	}
 
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -618,7 +623,7 @@
 	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
 			(unsigned long)usba_ep_readl(ep, CFG));
 	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
-			(unsigned long)usba_readl(udc, INT_ENB));
+			(unsigned long)usba_int_enb_get(udc));
 
 	return 0;
 }
@@ -654,9 +659,8 @@
 		usba_dma_readl(ep, STATUS);
 	}
 	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
-	usba_writel(udc, INT_ENB,
-			usba_readl(udc, INT_ENB)
-			& ~USBA_BF(EPT_INT, 1 << ep->index));
+	usba_int_enb_set(udc, usba_int_enb_get(udc) &
+			      ~USBA_BF(EPT_INT, 1 << ep->index));
 
 	request_complete_list(ep, &req_list, -ESHUTDOWN);
 
@@ -985,6 +989,7 @@
 	struct usba_udc *udc = to_usba_udc(gadget);
 	unsigned long flags;
 
+	gadget->is_selfpowered = (is_selfpowered != 0);
 	spin_lock_irqsave(&udc->lock, flags);
 	if (is_selfpowered)
 		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
@@ -1619,18 +1624,21 @@
 static irqreturn_t usba_udc_irq(int irq, void *devid)
 {
 	struct usba_udc *udc = devid;
-	u32 status;
+	u32 status, int_enb;
 	u32 dma_status;
 	u32 ep_status;
 
 	spin_lock(&udc->lock);
 
-	status = usba_readl(udc, INT_STA);
+	int_enb = usba_int_enb_get(udc);
+	status = usba_readl(udc, INT_STA) & int_enb;
 	DBG(DBG_INT, "irq, status=%#08x\n", status);
 
 	if (status & USBA_DET_SUSPEND) {
-		toggle_bias(0);
+		toggle_bias(udc, 0);
 		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
+		udc->bias_pulse_needed = true;
 		DBG(DBG_BUS, "Suspend detected\n");
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN
 				&& udc->driver && udc->driver->suspend) {
@@ -1641,13 +1649,15 @@
 	}
 
 	if (status & USBA_WAKE_UP) {
-		toggle_bias(1);
+		toggle_bias(udc, 1);
 		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
 		DBG(DBG_BUS, "Wake Up CPU detected\n");
 	}
 
 	if (status & USBA_END_OF_RESUME) {
 		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		generate_bias_pulse(udc);
 		DBG(DBG_BUS, "Resume detected\n");
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN
 				&& udc->driver && udc->driver->resume) {
@@ -1683,6 +1693,7 @@
 		struct usba_ep *ep0;
 
 		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		generate_bias_pulse(udc);
 		reset_all_endpoints(udc);
 
 		if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
@@ -1708,11 +1719,8 @@
 				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
 		usba_ep_writel(ep0, CTL_ENB,
 				USBA_EPT_ENABLE | USBA_RX_SETUP);
-		usba_writel(udc, INT_ENB,
-				(usba_readl(udc, INT_ENB)
-				| USBA_BF(EPT_INT, 1)
-				| USBA_DET_SUSPEND
-				| USBA_END_OF_RESUME));
+		usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
+				      USBA_DET_SUSPEND | USBA_END_OF_RESUME);
 
 		/*
 		 * Unclear why we hit this irregularly, e.g. in usbtest,
@@ -1745,13 +1753,13 @@
 	vbus = vbus_is_present(udc);
 	if (vbus != udc->vbus_prev) {
 		if (vbus) {
-			toggle_bias(1);
+			toggle_bias(udc, 1);
 			usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+			usba_int_enb_set(udc, USBA_END_OF_RESET);
 		} else {
 			udc->gadget.speed = USB_SPEED_UNKNOWN;
 			reset_all_endpoints(udc);
-			toggle_bias(0);
+			toggle_bias(udc, 0);
 			usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 			if (udc->driver->disconnect) {
 				spin_unlock(&udc->lock);
@@ -1797,9 +1805,9 @@
 	/* If Vbus is present, enable the controller and wait for reset */
 	spin_lock_irqsave(&udc->lock, flags);
 	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
-		toggle_bias(1);
+		toggle_bias(udc, 1);
 		usba_writel(udc, CTRL, USBA_ENABLE_MASK);
-		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+		usba_int_enb_set(udc, USBA_END_OF_RESET);
 	}
 	spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1820,7 +1828,7 @@
 	spin_unlock_irqrestore(&udc->lock, flags);
 
 	/* This will also disable the DP pullup */
-	toggle_bias(0);
+	toggle_bias(udc, 0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 
 	clk_disable_unprepare(udc->hclk);
@@ -1832,6 +1840,41 @@
 }
 
 #ifdef CONFIG_OF
+static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
+{
+	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
+
+	if (is_on)
+		at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+	else
+		at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+}
+
+static void at91sam9g45_pulse_bias(struct usba_udc *udc)
+{
+	unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
+
+	at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+	at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+}
+
+static const struct usba_udc_errata at91sam9rl_errata = {
+	.toggle_bias = at91sam9rl_toggle_bias,
+};
+
+static const struct usba_udc_errata at91sam9g45_errata = {
+	.pulse_bias = at91sam9g45_pulse_bias,
+};
+
+static const struct of_device_id atmel_udc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
+	{ .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
+	{ .compatible = "atmel,sama5d3-udc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
+
 static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
 						    struct usba_udc *udc)
 {
@@ -1839,10 +1882,17 @@
 	const char *name;
 	enum of_gpio_flags flags;
 	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match;
 	struct device_node *pp;
 	int i, ret;
 	struct usba_ep *eps, *ep;
 
+	match = of_match_node(atmel_udc_dt_ids, np);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	udc->errata = match->data;
+
 	udc->num_ep = 0;
 
 	udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
@@ -2033,7 +2083,7 @@
 		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
 		return ret;
 	}
-	toggle_bias(0);
+
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
 	clk_disable_unprepare(pclk);
 
@@ -2042,6 +2092,8 @@
 	else
 		udc->usba_ep = usba_udc_pdata(pdev, udc);
 
+	toggle_bias(udc, 0);
+
 	if (IS_ERR(udc->usba_ep))
 		return PTR_ERR(udc->usba_ep);
 
@@ -2101,15 +2153,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_OF)
-static const struct of_device_id atmel_udc_dt_ids[] = {
-	{ .compatible = "atmel,at91sam9rl-udc" },
-	{ /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
-#endif
-
 static struct platform_driver udc_driver = {
 	.remove		= __exit_p(usba_udc_remove),
 	.driver		= {
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h
index a70706e..497cd18 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
@@ -304,6 +304,11 @@
 	unsigned int				mapped:1;
 };
 
+struct usba_udc_errata {
+	void (*toggle_bias)(struct usba_udc *udc, int is_on);
+	void (*pulse_bias)(struct usba_udc *udc);
+};
+
 struct usba_udc {
 	/* Protect hw registers from concurrent modifications */
 	spinlock_t lock;
@@ -314,6 +319,7 @@
 	struct usb_gadget gadget;
 	struct usb_gadget_driver *driver;
 	struct platform_device *pdev;
+	const struct usba_udc_errata *errata;
 	int irq;
 	int vbus_pin;
 	int vbus_pin_inverted;
@@ -321,12 +327,15 @@
 	struct clk *pclk;
 	struct clk *hclk;
 	struct usba_ep *usba_ep;
+	bool bias_pulse_needed;
 
 	u16 devstatus;
 
 	u16 test_mode;
 	int vbus_prev;
 
+	u32 int_enb_cache;
+
 #ifdef CONFIG_USB_GADGET_DEBUG_FS
 	struct dentry *debugfs_root;
 	struct dentry *debugfs_regs;
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
index c6dfef8..5c8f4ef 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -521,7 +521,6 @@
 static struct platform_driver bdc_driver = {
 	.driver		= {
 		.name	= BRCM_BDC_NAME,
-		.owner	= THIS_MODULE
 	},
 	.probe		= bdc_probe,
 	.remove		= bdc_remove,
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
index d4fe8d7..b04980c 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -718,7 +718,7 @@
 	struct bdc *bdc;
 	int ret = 0;
 
-	if (!req || !ep || !ep->usb_ep.desc)
+	if (!req || !ep->usb_ep.desc)
 		return -EINVAL;
 
 	bdc = ep->bdc;
@@ -882,8 +882,8 @@
 
 		ret = bdc_ep_set_stall(bdc, ep->ep_num);
 		if (ret)
-			dev_err(bdc->dev, "failed to %s STALL on %s\n",
-				value ? "set" : "clear", ep->name);
+			dev_err(bdc->dev, "failed to set STALL on %s\n",
+				ep->name);
 		else
 			ep->flags |= BDC_EP_STALL;
 	} else {
@@ -891,8 +891,8 @@
 		dev_dbg(bdc->dev, "Before Clear\n");
 		ret = bdc_ep_clear_stall(bdc, ep->ep_num);
 		if (ret)
-			dev_err(bdc->dev, "failed to %s STALL on %s\n",
-				value ? "set" : "clear", ep->name);
+			dev_err(bdc->dev, "failed to clear STALL on %s\n",
+				ep->name);
 		else
 			ep->flags &= ~BDC_EP_STALL;
 		dev_dbg(bdc->dev, "After  Clear\n");
diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
index 3700ce7..7f77db5 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
@@ -454,6 +454,7 @@
 	unsigned long           flags;
 
 	dev_dbg(bdc->dev, "%s()\n", __func__);
+	gadget->is_selfpowered = (is_self != 0);
 	spin_lock_irqsave(&bdc->lock, flags);
 	if (!is_self)
 		bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 9c59880..8dda484 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -802,6 +802,7 @@
 {
 	struct dummy	*dum;
 
+	_gadget->is_selfpowered = (value != 0);
 	dum = gadget_to_dummy_hcd(_gadget)->dum;
 	if (value)
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
@@ -1924,7 +1925,9 @@
 	memset(desc, 0, sizeof *desc);
 	desc->bDescriptorType = 0x2a;
 	desc->bDescLength = 12;
-	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->wHubCharacteristics = cpu_to_le16(
+			HUB_CHAR_INDV_PORT_LPSM |
+			HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = 1;
 	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
 	desc->u.ss.DeviceRemovable = 0xffff;
@@ -1935,7 +1938,9 @@
 	memset(desc, 0, sizeof *desc);
 	desc->bDescriptorType = 0x29;
 	desc->bDescLength = 9;
-	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->wHubCharacteristics = cpu_to_le16(
+			HUB_CHAR_INDV_PORT_LPSM |
+			HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = 1;
 	desc->u.hs.DeviceRemovable[0] = 0xff;
 	desc->u.hs.DeviceRemovable[1] = 0xff;
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 795c99c..e0822f1 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -2630,7 +2630,7 @@
 	struct qe_udc *udc = platform_get_drvdata(ofdev);
 	struct qe_ep *ep;
 	unsigned int size;
-	DECLARE_COMPLETION(done);
+	DECLARE_COMPLETION_ONSTACK(done);
 
 	usb_del_gadget_udc(&udc->gadget);
 
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index 2df8074..55fcb93 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1337,7 +1337,7 @@
 
 	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
 		/* Get device status */
-		tmp = 1 << USB_DEVICE_SELF_POWERED;
+		tmp = udc->gadget.is_selfpowered;
 		tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
 	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
 		/* Get interface status */
@@ -1948,6 +1948,7 @@
 	/* hook up the driver */
 	udc_controller->driver = driver;
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
+	g->is_selfpowered = 1;
 
 	if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 		/* Suspend the controller until OTG enable it */
@@ -2529,7 +2530,7 @@
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
-	DECLARE_COMPLETION(done);
+	DECLARE_COMPLETION_ONSTACK(done);
 
 	if (!udc_controller)
 		return -ENODEV;
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 34d9b7b..27fd413 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -191,7 +191,6 @@
 	bool			enabled;
 	bool			clocked;
 	bool			suspended;
-	bool			selfpowered;
 	int                     ep0state;
 	atomic_t                enabled_ep_cnt;
 	wait_queue_head_t       ep_disable_wait_queue;
@@ -547,7 +546,7 @@
 		   udc->vbus ? "present" : "off",
 		   udc->enabled ? (udc->vbus ? "active" : "enabled") :
 		   "disabled",
-		   udc->selfpowered ? "self" : "VBUS",
+		   udc->gadget.is_selfpowered ? "self" : "VBUS",
 		   udc->suspended ? ", suspended" : "",
 		   udc->driver ? udc->driver->driver.name : "(none)");
 
@@ -2212,7 +2211,7 @@
 		break; /* Not supported */
 
 	case USB_RECIP_DEVICE:
-		ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		ep0buff = udc->gadget.is_selfpowered;
 		if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
 			ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 		break;
@@ -2498,10 +2497,7 @@
 
 static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
 {
-	struct lpc32xx_udc *udc = to_udc(gadget);
-
-	/* Always self-powered */
-	udc->selfpowered = (is_on != 0);
+	gadget->is_selfpowered = (is_on != 0);
 
 	return 0;
 }
@@ -2946,7 +2942,7 @@
 	udc->driver = driver;
 	udc->gadget.dev.of_node = udc->dev->of_node;
 	udc->enabled = 1;
-	udc->selfpowered = 1;
+	udc->gadget.is_selfpowered = 1;
 	udc->vbus = 0;
 
 	/* Force VBUS process once to check for cable insertion */
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 253f3df..d32160d 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -1378,9 +1378,6 @@
 		}
 	}
 
-	/* pullup is always on */
-	mv_udc_pullup(&udc->gadget, 1);
-
 	/* When boot with cable attached, there will be no vbus irq occurred */
 	if (udc->qwork)
 		queue_work(udc->qwork, &udc->vbus_work);
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index d20de1f..195baf3 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1132,13 +1132,10 @@
 static int
 net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
 {
-	struct net2272 *dev;
-
 	if (!_gadget)
 		return -ENODEV;
-	dev = container_of(_gadget, struct net2272, gadget);
 
-	dev->is_selfpowered = value;
+	_gadget->is_selfpowered = (value != 0);
 
 	return 0;
 }
@@ -1844,7 +1841,7 @@
 			case USB_RECIP_DEVICE:
 				if (u.r.wLength > 2)
 					goto do_stall;
-				if (dev->is_selfpowered)
+				if (dev->gadget.is_selfpowered)
 					status = (1 << USB_DEVICE_SELF_POWERED);
 
 				/* don't bother with a request object! */
diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h
index e595057..127ab03 100644
--- a/drivers/usb/gadget/udc/net2272.h
+++ b/drivers/usb/gadget/udc/net2272.h
@@ -458,7 +458,6 @@
 	struct usb_gadget_driver *driver;
 	unsigned protocol_stall:1,
 	         softconnect:1,
-	         is_selfpowered:1,
 	         wakeup:1,
 	         dma_eot_polarity:1,
 	         dma_dack_polarity:1,
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index d6411e0..d2c0bf6 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -12,11 +12,7 @@
  * the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
  * as well as Gadget Zero and Gadgetfs.
  *
- * DMA is enabled by default.  Drivers using transfer queues might use
- * DMA chaining to remove IRQ latencies between transfers.  (Except when
- * short OUT transfers happen.)  Drivers can use the req->no_interrupt
- * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
- * and DMA chaining is enabled.
+ * DMA is enabled by default.
  *
  * MSI is enabled by default.  The legacy IRQ is used if MSI couldn't
  * be enabled.
@@ -84,23 +80,6 @@
 	"ep-e", "ep-f", "ep-g", "ep-h",
 };
 
-/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
- * use_dma_chaining -- dma descriptor queueing gives even more irq reduction
- *
- * The net2280 DMA engines are not tightly integrated with their FIFOs;
- * not all cases are (yet) handled well in this driver or the silicon.
- * Some gadget drivers work better with the dma support here than others.
- * These two parameters let you use PIO or more aggressive DMA.
- */
-static bool use_dma = true;
-static bool use_dma_chaining;
-static bool use_msi = true;
-
-/* "modprobe net2280 use_dma=n" etc */
-module_param(use_dma, bool, 0444);
-module_param(use_dma_chaining, bool, 0444);
-module_param(use_msi, bool, 0444);
-
 /* mode 0 == ep-{a,b,c,d} 1K fifo each
  * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
  * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
@@ -120,11 +99,6 @@
 /* "modprobe net2280 enable_suspend=1" etc */
 module_param(enable_suspend, bool, 0444);
 
-/* force full-speed operation */
-static bool full_speed;
-module_param(full_speed, bool, 0444);
-MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
-
 #define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 
 static char *type_string(u8 bmAttributes)
@@ -202,15 +176,6 @@
 	/* set speed-dependent max packet; may kick in high bandwidth */
 	set_max_speed(ep, max);
 
-	/* FIFO lines can't go to different packets.  PIO is ok, so
-	 * use it instead of troublesome (non-bulk) multi-packet DMA.
-	 */
-	if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
-		ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
-			ep->ep.name, ep->ep.maxpacket);
-		ep->dma = NULL;
-	}
-
 	/* set type, direction, address; reset fifo counters */
 	writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
 	tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
@@ -478,7 +443,7 @@
 	/* synch memory views with the device */
 	(void)readl(&ep->cfg->ep_cfg);
 
-	if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
+	if (!ep->dma && ep->num >= 1 && ep->num <= 4)
 		ep->dma = &ep->dev->dma[ep->num - 1];
 
 	spin_unlock_irqrestore(&ep->dev->lock, flags);
@@ -610,9 +575,15 @@
 	u32	__iomem *statp;
 	u32	tmp;
 
-	ASSERT_OUT_NAKING(ep);
-
 	statp = &ep->regs->ep_stat;
+
+	tmp = readl(statp);
+	if (tmp & BIT(NAK_OUT_PACKETS)) {
+		ep_dbg(ep->dev, "%s %s %08x !NAK\n",
+			ep->ep.name, __func__, tmp);
+		writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+	}
+
 	writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
 		BIT(DATA_PACKET_RECEIVED_INTERRUPT),
 		statp);
@@ -747,8 +718,7 @@
 	req->valid = valid;
 	if (valid)
 		dmacount |= BIT(VALID_BIT);
-	if (likely(!req->req.no_interrupt || !use_dma_chaining))
-		dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
+	dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
 
 	/* td->dmadesc = previously set by caller */
 	td->dmaaddr = cpu_to_le32 (req->req.dma);
@@ -862,27 +832,11 @@
 	req->td->dmadesc = cpu_to_le32 (ep->td_dma);
 	fill_dma_desc(ep, req, 1);
 
-	if (!use_dma_chaining)
-		req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
+	req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
 
 	start_queue(ep, tmp, req->td_dma);
 }
 
-static inline void resume_dma(struct net2280_ep *ep)
-{
-	writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
-
-	ep->dma_started = true;
-}
-
-static inline void ep_stop_dma(struct net2280_ep *ep)
-{
-	writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
-	spin_stop_dma(ep->dma);
-
-	ep->dma_started = false;
-}
-
 static inline void
 queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
 {
@@ -973,10 +927,8 @@
 			return ret;
 	}
 
-#if 0
 	ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
 			_ep->name, _req, _req->length, _req->buf);
-#endif
 
 	spin_lock_irqsave(&dev->lock, flags);
 
@@ -984,24 +936,12 @@
 	_req->actual = 0;
 
 	/* kickstart this i/o queue? */
-	if (list_empty(&ep->queue) && !ep->stopped) {
-		/* DMA request while EP halted */
-		if (ep->dma &&
-		    (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
-			(dev->quirks & PLX_SUPERSPEED)) {
-			int valid = 1;
-			if (ep->is_in) {
-				int expect;
-				expect = likely(req->req.zero ||
-						((req->req.length %
-						  ep->ep.maxpacket) != 0));
-				if (expect != ep->in_fifo_validate)
-					valid = 0;
-			}
-			queue_dma(ep, req, valid);
-		}
+	if  (list_empty(&ep->queue) && !ep->stopped &&
+		!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
+		  (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
+
 		/* use DMA if the endpoint supports it, else pio */
-		else if (ep->dma)
+		if (ep->dma)
 			start_dma(ep, req);
 		else {
 			/* maybe there's no control data, just status ack */
@@ -1084,8 +1024,6 @@
 	done(ep, req, status);
 }
 
-static void restart_dma(struct net2280_ep *ep);
-
 static void scan_dma_completions(struct net2280_ep *ep)
 {
 	/* only look at descriptors that were "naturally" retired,
@@ -1117,9 +1055,8 @@
 			dma_done(ep, req, tmp, 0);
 			break;
 		} else if (!ep->is_in &&
-				(req->req.length % ep->ep.maxpacket) != 0) {
-			if (ep->dev->quirks & PLX_SUPERSPEED)
-				return dma_done(ep, req, tmp, 0);
+			   (req->req.length % ep->ep.maxpacket) &&
+			   !(ep->dev->quirks & PLX_SUPERSPEED)) {
 
 			tmp = readl(&ep->regs->ep_stat);
 			/* AVOID TROUBLE HERE by not issuing short reads from
@@ -1150,67 +1087,15 @@
 static void restart_dma(struct net2280_ep *ep)
 {
 	struct net2280_request	*req;
-	u32			dmactl = dmactl_default;
 
 	if (ep->stopped)
 		return;
 	req = list_entry(ep->queue.next, struct net2280_request, queue);
 
-	if (!use_dma_chaining) {
-		start_dma(ep, req);
-		return;
-	}
-
-	/* the 2280 will be processing the queue unless queue hiccups after
-	 * the previous transfer:
-	 *  IN:   wanted automagic zlp, head doesn't (or vice versa)
-	 *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.
-	 *  OUT:  was "usb-short", we must restart.
-	 */
-	if (ep->is_in && !req->valid) {
-		struct net2280_request	*entry, *prev = NULL;
-		int			reqmode, done = 0;
-
-		ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
-		ep->in_fifo_validate = likely(req->req.zero ||
-				(req->req.length % ep->ep.maxpacket) != 0);
-		if (ep->in_fifo_validate)
-			dmactl |= BIT(DMA_FIFO_VALIDATE);
-		list_for_each_entry(entry, &ep->queue, queue) {
-			__le32		dmacount;
-
-			if (entry == req)
-				continue;
-			dmacount = entry->td->dmacount;
-			if (!done) {
-				reqmode = likely(entry->req.zero ||
-				   (entry->req.length % ep->ep.maxpacket));
-				if (reqmode == ep->in_fifo_validate) {
-					entry->valid = 1;
-					dmacount |= valid_bit;
-					entry->td->dmacount = dmacount;
-					prev = entry;
-					continue;
-				} else {
-					/* force a hiccup */
-					prev->td->dmacount |= dma_done_ie;
-					done = 1;
-				}
-			}
-
-			/* walk the rest of the queue so unlinks behave */
-			entry->valid = 0;
-			dmacount &= ~valid_bit;
-			entry->td->dmacount = dmacount;
-			prev = entry;
-		}
-	}
-
-	writel(0, &ep->dma->dmactl);
-	start_queue(ep, dmactl, req->td_dma);
+	start_dma(ep, req);
 }
 
-static void abort_dma_228x(struct net2280_ep *ep)
+static void abort_dma(struct net2280_ep *ep)
 {
 	/* abort the current transfer */
 	if (likely(!list_empty(&ep->queue))) {
@@ -1222,19 +1107,6 @@
 	scan_dma_completions(ep);
 }
 
-static void abort_dma_338x(struct net2280_ep *ep)
-{
-	writel(BIT(DMA_ABORT), &ep->dma->dmastat);
-	spin_stop_dma(ep->dma);
-}
-
-static void abort_dma(struct net2280_ep *ep)
-{
-	if (ep->dev->quirks & PLX_LEGACY)
-		return abort_dma_228x(ep);
-	return abort_dma_338x(ep);
-}
-
 /* dequeue ALL requests */
 static void nuke(struct net2280_ep *ep)
 {
@@ -1306,25 +1178,6 @@
 			done(ep, req, -ECONNRESET);
 		}
 		req = NULL;
-
-	/* patch up hardware chaining data */
-	} else if (ep->dma && use_dma_chaining) {
-		if (req->queue.prev == ep->queue.next) {
-			writel(le32_to_cpu(req->td->dmadesc),
-				&ep->dma->dmadesc);
-			if (req->td->dmacount & dma_done_ie)
-				writel(readl(&ep->dma->dmacount) |
-						le32_to_cpu(dma_done_ie),
-					&ep->dma->dmacount);
-		} else {
-			struct net2280_request	*prev;
-
-			prev = list_entry(req->queue.prev,
-				struct net2280_request, queue);
-			prev->td->dmadesc = req->td->dmadesc;
-			if (req->td->dmacount & dma_done_ie)
-				prev->td->dmacount |= dma_done_ie;
-		}
 	}
 
 	if (req)
@@ -1512,10 +1365,10 @@
 	tmp = readl(&dev->usb->usbctl);
 	if (value) {
 		tmp |= BIT(SELF_POWERED_STATUS);
-		dev->selfpowered = 1;
+		_gadget->is_selfpowered = 1;
 	} else {
 		tmp &= ~BIT(SELF_POWERED_STATUS);
-		dev->selfpowered = 0;
+		_gadget->is_selfpowered = 0;
 	}
 	writel(tmp, &dev->usb->usbctl);
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -1604,14 +1457,11 @@
 
 	/* Main Control Registers */
 	t = scnprintf(next, size, "%s version " DRIVER_VERSION
-			", chiprev %04x, dma %s\n\n"
+			", chiprev %04x\n\n"
 			"devinit %03x fifoctl %08x gadget '%s'\n"
 			"pci irqenb0 %02x irqenb1 %08x "
 			"irqstat0 %04x irqstat1 %08x\n",
 			driver_name, dev->chiprev,
-			use_dma
-				? (use_dma_chaining ? "chaining" : "enabled")
-				: "disabled",
 			readl(&dev->regs->devinit),
 			readl(&dev->regs->fifoctl),
 			s,
@@ -1913,76 +1763,73 @@
 static void defect7374_enable_data_eps_zero(struct net2280 *dev)
 {
 	u32 tmp = 0, tmp_reg;
-	u32 fsmvalue, scratch;
+	u32 scratch;
 	int i;
 	unsigned char ep_sel;
 
 	scratch = get_idx_reg(dev->regs, SCRATCH);
-	fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
+
+	WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
+		== DEFECT7374_FSM_SS_CONTROL_READ);
+
 	scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
 
-	/*See if firmware needs to set up for workaround*/
-	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
-		ep_warn(dev, "Operate Defect 7374 workaround soft this time");
-		ep_warn(dev, "It will operate on cold-reboot and SS connect");
+	ep_warn(dev, "Operate Defect 7374 workaround soft this time");
+	ep_warn(dev, "It will operate on cold-reboot and SS connect");
 
-		/*GPEPs:*/
-		tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
-		       (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
-		       ((dev->enhanced_mode) ?
-		       BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
-		       BIT(IN_ENDPOINT_ENABLE));
+	/*GPEPs:*/
+	tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
+			(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
+			((dev->enhanced_mode) ?
+			 BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
+			BIT(IN_ENDPOINT_ENABLE));
 
-		for (i = 1; i < 5; i++)
-			writel(tmp, &dev->ep[i].cfg->ep_cfg);
+	for (i = 1; i < 5; i++)
+		writel(tmp, &dev->ep[i].cfg->ep_cfg);
 
-		/* CSRIN, PCIIN, STATIN, RCIN*/
-		tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
-		writel(tmp, &dev->dep[1].dep_cfg);
-		writel(tmp, &dev->dep[3].dep_cfg);
-		writel(tmp, &dev->dep[4].dep_cfg);
-		writel(tmp, &dev->dep[5].dep_cfg);
+	/* CSRIN, PCIIN, STATIN, RCIN*/
+	tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
+	writel(tmp, &dev->dep[1].dep_cfg);
+	writel(tmp, &dev->dep[3].dep_cfg);
+	writel(tmp, &dev->dep[4].dep_cfg);
+	writel(tmp, &dev->dep[5].dep_cfg);
 
-		/*Implemented for development and debug.
-		 * Can be refined/tuned later.*/
-		for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
-			/* Select an endpoint for subsequent operations: */
-			tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
-			writel(((tmp_reg & ~0x1f) | ep_sel),
-			       &dev->plregs->pl_ep_ctrl);
+	/*Implemented for development and debug.
+	 * Can be refined/tuned later.*/
+	for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
+		/* Select an endpoint for subsequent operations: */
+		tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
+		writel(((tmp_reg & ~0x1f) | ep_sel),
+				&dev->plregs->pl_ep_ctrl);
 
-			if (ep_sel == 1) {
-				tmp =
-				    (readl(&dev->plregs->pl_ep_ctrl) |
-				     BIT(CLEAR_ACK_ERROR_CODE) | 0);
-				writel(tmp, &dev->plregs->pl_ep_ctrl);
-				continue;
-			}
-
-			if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
-					ep_sel == 18  || ep_sel == 20)
-				continue;
-
-			tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
-				 BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
-			writel(tmp, &dev->plregs->pl_ep_cfg_4);
-
-			tmp = readl(&dev->plregs->pl_ep_ctrl) &
-				~BIT(EP_INITIALIZED);
+		if (ep_sel == 1) {
+			tmp =
+				(readl(&dev->plregs->pl_ep_ctrl) |
+				 BIT(CLEAR_ACK_ERROR_CODE) | 0);
 			writel(tmp, &dev->plregs->pl_ep_ctrl);
-
+			continue;
 		}
 
-		/* Set FSM to focus on the first Control Read:
-		 * - Tip: Connection speed is known upon the first
-		 * setup request.*/
-		scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
-		set_idx_reg(dev->regs, SCRATCH, scratch);
+		if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
+				ep_sel == 18  || ep_sel == 20)
+			continue;
 
-	} else{
-		ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
-		ep_warn(dev, "It will operate on cold-reboot and SS connect");
+		tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
+				BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
+		writel(tmp, &dev->plregs->pl_ep_cfg_4);
+
+		tmp = readl(&dev->plregs->pl_ep_ctrl) &
+			~BIT(EP_INITIALIZED);
+		writel(tmp, &dev->plregs->pl_ep_ctrl);
+
 	}
+
+	/* Set FSM to focus on the first Control Read:
+	 * - Tip: Connection speed is known upon the first
+	 * setup request.*/
+	scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
+	set_idx_reg(dev->regs, SCRATCH, scratch);
+
 }
 
 /* keeping it simple:
@@ -2033,21 +1880,13 @@
 static void usb_reset_338x(struct net2280 *dev)
 {
 	u32 tmp;
-	u32 fsmvalue;
 
 	dev->gadget.speed = USB_SPEED_UNKNOWN;
 	(void)readl(&dev->usb->usbctl);
 
 	net2280_led_init(dev);
 
-	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
-			(0xf << DEFECT7374_FSM_FIELD);
-
-	/* See if firmware needs to set up for workaround: */
-	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
-		ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
-		     fsmvalue);
-	} else {
+	if (dev->bug7734_patched) {
 		/* disable automatic responses, and irqs */
 		writel(0, &dev->usb->stdrsp);
 		writel(0, &dev->regs->pciirqenb0);
@@ -2064,7 +1903,7 @@
 
 	writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
 
-	if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
+	if (dev->bug7734_patched) {
 		/* reset, and enable pci */
 		tmp = readl(&dev->regs->devinit) |
 		    BIT(PCI_ENABLE) |
@@ -2093,10 +1932,6 @@
 static void usb_reinit_228x(struct net2280 *dev)
 {
 	u32	tmp;
-	int	init_dma;
-
-	/* use_dma changes are ignored till next device re-init */
-	init_dma = use_dma;
 
 	/* basic endpoint init */
 	for (tmp = 0; tmp < 7; tmp++) {
@@ -2108,8 +1943,7 @@
 
 		if (tmp > 0 && tmp <= 4) {
 			ep->fifo_size = 1024;
-			if (init_dma)
-				ep->dma = &dev->dma[tmp - 1];
+			ep->dma = &dev->dma[tmp - 1];
 		} else
 			ep->fifo_size = 64;
 		ep->regs = &dev->epregs[tmp];
@@ -2133,17 +1967,12 @@
 
 static void usb_reinit_338x(struct net2280 *dev)
 {
-	int init_dma;
 	int i;
 	u32 tmp, val;
-	u32 fsmvalue;
 	static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
 	static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
 						0x00, 0xC0, 0x00, 0xC0 };
 
-	/* use_dma changes are ignored till next device re-init */
-	init_dma = use_dma;
-
 	/* basic endpoint init */
 	for (i = 0; i < dev->n_ep; i++) {
 		struct net2280_ep *ep = &dev->ep[i];
@@ -2152,7 +1981,7 @@
 		ep->dev = dev;
 		ep->num = i;
 
-		if (i > 0 && i <= 4 && init_dma)
+		if (i > 0 && i <= 4)
 			ep->dma = &dev->dma[i - 1];
 
 		if (dev->enhanced_mode) {
@@ -2177,14 +2006,7 @@
 	dev->ep[0].stopped = 0;
 
 	/* Link layer set up */
-	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
-				(0xf << DEFECT7374_FSM_FIELD);
-
-	/* See if driver needs to set up for workaround: */
-	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
-		ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
-						__func__, fsmvalue);
-	else {
+	if (dev->bug7734_patched) {
 		tmp = readl(&dev->usb_ext->usbctl2) &
 		    ~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
 		writel(tmp, &dev->usb_ext->usbctl2);
@@ -2291,15 +2113,8 @@
 
 static void ep0_start_338x(struct net2280 *dev)
 {
-	u32 fsmvalue;
 
-	fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
-			(0xf << DEFECT7374_FSM_FIELD);
-
-	if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
-		ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
-		     fsmvalue);
-	else
+	if (dev->bug7734_patched)
 		writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
 		       BIT(SET_EP_HIDE_STATUS_PHASE),
 		       &dev->epregs[0].ep_rsp);
@@ -2382,16 +2197,12 @@
 	if (retval)
 		goto err_func;
 
-	/* Enable force-full-speed testing mode, if desired */
-	if (full_speed && (dev->quirks & PLX_LEGACY))
-		writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
-
-	/* ... then enable host detection and ep0; and we're ready
+	/* enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
 	 */
 	net2280_led_active(dev, 1);
 
-	if (dev->quirks & PLX_SUPERSPEED)
+	if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
 		defect7374_enable_data_eps_zero(dev);
 
 	ep0_start(dev);
@@ -2444,10 +2255,6 @@
 
 	net2280_led_active(dev, 0);
 
-	/* Disable full-speed test mode */
-	if (dev->quirks & PLX_LEGACY)
-		writel(0, &dev->usb->xcvrdiag);
-
 	device_remove_file(&dev->pdev->dev, &dev_attr_function);
 	device_remove_file(&dev->pdev->dev, &dev_attr_queues);
 
@@ -2478,10 +2285,10 @@
 	/* ack all, and handle what we care about */
 	t = readl(&ep->regs->ep_stat);
 	ep->irqs++;
-#if 0
+
 	ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
-			ep->ep.name, t, req ? &req->req : 0);
-#endif
+			ep->ep.name, t, req ? &req->req : NULL);
+
 	if (!ep->is_in || (ep->dev->quirks & PLX_2280))
 		writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
 	else
@@ -2717,6 +2524,7 @@
 		 * run after the next USB connection.
 		 */
 		scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
+		dev->bug7734_patched = 1;
 		goto restore_data_eps;
 	}
 
@@ -2730,6 +2538,7 @@
 		if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
 			(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
 			scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
+			dev->bug7734_patched = 1;
 			break;
 		}
 
@@ -2766,80 +2575,19 @@
 	return;
 }
 
-static void ep_stall(struct net2280_ep *ep, int stall)
+static void ep_clear_seqnum(struct net2280_ep *ep)
 {
 	struct net2280 *dev = ep->dev;
 	u32 val;
 	static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
 
-	if (stall) {
-		writel(BIT(SET_ENDPOINT_HALT) |
-		       /* BIT(SET_NAK_PACKETS) | */
-		       BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
-		       &ep->regs->ep_rsp);
-		ep->is_halt = 1;
-	} else {
-		if (dev->gadget.speed == USB_SPEED_SUPER) {
-			/*
-			 * Workaround for SS SeqNum not cleared via
-			 * Endpoint Halt (Clear) bit. select endpoint
-			 */
-			val = readl(&dev->plregs->pl_ep_ctrl);
-			val = (val & ~0x1f) | ep_pl[ep->num];
-			writel(val, &dev->plregs->pl_ep_ctrl);
+	val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
+	val |= ep_pl[ep->num];
+	writel(val, &dev->plregs->pl_ep_ctrl);
+	val |= BIT(SEQUENCE_NUMBER_RESET);
+	writel(val, &dev->plregs->pl_ep_ctrl);
 
-			val |= BIT(SEQUENCE_NUMBER_RESET);
-			writel(val, &dev->plregs->pl_ep_ctrl);
-		}
-		val = readl(&ep->regs->ep_rsp);
-		val |= BIT(CLEAR_ENDPOINT_HALT) |
-			BIT(CLEAR_ENDPOINT_TOGGLE);
-		writel(val,
-		       /* | BIT(CLEAR_NAK_PACKETS),*/
-		       &ep->regs->ep_rsp);
-		ep->is_halt = 0;
-		val = readl(&ep->regs->ep_rsp);
-	}
-}
-
-static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
-{
-	/* set/clear, then synch memory views with the device */
-	if (value) {
-		ep->stopped = 1;
-		if (ep->num == 0)
-			ep->dev->protocol_stall = 1;
-		else {
-			if (ep->dma)
-				ep_stop_dma(ep);
-			ep_stall(ep, true);
-		}
-
-		if (wedged)
-			ep->wedged = 1;
-	} else {
-		ep->stopped = 0;
-		ep->wedged = 0;
-
-		ep_stall(ep, false);
-
-		/* Flush the queue */
-		if (!list_empty(&ep->queue)) {
-			struct net2280_request *req =
-			    list_entry(ep->queue.next, struct net2280_request,
-				       queue);
-			if (ep->dma)
-				resume_dma(ep);
-			else {
-				if (ep->is_in)
-					write_fifo(ep, &req->req);
-				else {
-					if (read_fifo(ep, req))
-						done(ep, req, 0);
-				}
-			}
-		}
-	}
+	return;
 }
 
 static void handle_stat0_irqs_superspeed(struct net2280 *dev,
@@ -2863,7 +2611,7 @@
 		switch (r.bRequestType) {
 		case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
 			status = dev->wakeup_enable ? 0x02 : 0x00;
-			if (dev->selfpowered)
+			if (dev->gadget.is_selfpowered)
 				status |= BIT(0);
 			status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
 							dev->ltm_enable << 4);
@@ -2940,7 +2688,12 @@
 			if (w_value != USB_ENDPOINT_HALT)
 				goto do_stall3;
 			ep_vdbg(dev, "%s clear halt\n", e->ep.name);
-			ep_stall(e, false);
+			/*
+			 * Workaround for SS SeqNum not cleared via
+			 * Endpoint Halt (Clear) bit. select endpoint
+			 */
+			ep_clear_seqnum(e);
+			clear_halt(e);
 			if (!list_empty(&e->queue) && e->td_dma)
 				restart_dma(e);
 			allow_status(ep);
@@ -2998,7 +2751,14 @@
 			e = get_ep_by_addr(dev,	w_index);
 			if (!e || (w_value != USB_ENDPOINT_HALT))
 				goto do_stall3;
-			ep_stdrsp(e, true, false);
+			ep->stopped = 1;
+			if (ep->num == 0)
+				ep->dev->protocol_stall = 1;
+			else {
+				if (ep->dma)
+					abort_dma(ep);
+				set_halt(ep);
+			}
 			allow_status_338x(ep);
 			break;
 
@@ -3026,7 +2786,7 @@
 				r.bRequestType, r.bRequest, tmp);
 		dev->protocol_stall = 1;
 		/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
-		ep_stall(ep, true);
+		set_halt(ep);
 	}
 
 next_endpoints3:
@@ -3091,9 +2851,7 @@
 		}
 		ep->stopped = 0;
 		dev->protocol_stall = 0;
-		if (dev->quirks & PLX_SUPERSPEED)
-			ep->is_halt = 0;
-		else{
+		if (!(dev->quirks & PLX_SUPERSPEED)) {
 			if (ep->dev->quirks & PLX_2280)
 				tmp = BIT(FIFO_OVERFLOW) |
 				    BIT(FIFO_UNDERFLOW);
@@ -3120,7 +2878,7 @@
 		cpu_to_le32s(&u.raw[0]);
 		cpu_to_le32s(&u.raw[1]);
 
-		if (dev->quirks & PLX_SUPERSPEED)
+		if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
 			defect7374_workaround(dev, u.r);
 
 		tmp = 0;
@@ -3423,17 +3181,12 @@
 				continue;
 		}
 
-		/* chaining should stop on abort, short OUT from fifo,
-		 * or (stat0 codepath) short OUT transfer.
-		 */
-		if (!use_dma_chaining) {
-			if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
-				ep_dbg(ep->dev, "%s no xact done? %08x\n",
-					ep->ep.name, tmp);
-				continue;
-			}
-			stop_dma(ep->dma);
+		if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
+			ep_dbg(ep->dev, "%s no xact done? %08x\n",
+				ep->ep.name, tmp);
+			continue;
 		}
+		stop_dma(ep->dma);
 
 		/* OUT transfers terminate when the data from the
 		 * host is in our memory.  Process whatever's done.
@@ -3448,30 +3201,9 @@
 		scan_dma_completions(ep);
 
 		/* disable dma on inactive queues; else maybe restart */
-		if (list_empty(&ep->queue)) {
-			if (use_dma_chaining)
-				stop_dma(ep->dma);
-		} else {
+		if (!list_empty(&ep->queue)) {
 			tmp = readl(&dma->dmactl);
-			if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
-				restart_dma(ep);
-			else if (ep->is_in && use_dma_chaining) {
-				struct net2280_request	*req;
-				__le32			dmacount;
-
-				/* the descriptor at the head of the chain
-				 * may still have VALID_BIT clear; that's
-				 * used to trigger changing DMA_FIFO_VALIDATE
-				 * (affects automagic zlp writes).
-				 */
-				req = list_entry(ep->queue.next,
-						struct net2280_request, queue);
-				dmacount = req->td->dmacount;
-				dmacount &= cpu_to_le32(BIT(VALID_BIT) |
-						DMA_BYTE_COUNT_MASK);
-				if (dmacount && (dmacount & valid_bit) == 0)
-					restart_dma(ep);
-			}
+			restart_dma(ep);
 		}
 		ep->irqs++;
 	}
@@ -3556,7 +3288,7 @@
 	}
 	if (dev->got_irq)
 		free_irq(pdev->irq, dev);
-	if (use_msi && dev->quirks & PLX_SUPERSPEED)
+	if (dev->quirks & PLX_SUPERSPEED)
 		pci_disable_msi(pdev);
 	if (dev->regs)
 		iounmap(dev->regs);
@@ -3581,9 +3313,6 @@
 	void			__iomem *base = NULL;
 	int			retval, i;
 
-	if (!use_dma)
-		use_dma_chaining = 0;
-
 	/* alloc, and start init */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
@@ -3663,9 +3392,12 @@
 		fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
 					(0xf << DEFECT7374_FSM_FIELD);
 		/* See if firmware needs to set up for workaround: */
-		if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
+		if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
+			dev->bug7734_patched = 1;
 			writel(0, &dev->usb->usbctl);
-	} else{
+		} else
+			dev->bug7734_patched = 0;
+	} else {
 		dev->enhanced_mode = 0;
 		dev->n_ep = 7;
 		/* put into initial config, link up all endpoints */
@@ -3682,7 +3414,7 @@
 		goto done;
 	}
 
-	if (use_msi && (dev->quirks & PLX_SUPERSPEED))
+	if (dev->quirks & PLX_SUPERSPEED)
 		if (pci_enable_msi(pdev))
 			ep_err(dev, "Failed to enable MSI mode\n");
 
@@ -3741,9 +3473,7 @@
 	ep_info(dev, "%s\n", driver_desc);
 	ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
 			pdev->irq, base, dev->chiprev);
-	ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
-		use_dma	? (use_dma_chaining ? "chaining" : "enabled")
-			: "disabled",
+	ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
 		dev->enhanced_mode ? "enhanced mode" : "legacy mode");
 	retval = device_create_file(&pdev->dev, &dev_attr_registers);
 	if (retval)
@@ -3776,9 +3506,6 @@
 	/* disable the pullup so the host will think we're gone */
 	writel(0, &dev->usb->usbctl);
 
-	/* Disable full-speed test mode */
-	if (dev->quirks & PLX_LEGACY)
-		writel(0, &dev->usb->xcvrdiag);
 }
 
 
diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h
index 03f1524..ac8d5a2 100644
--- a/drivers/usb/gadget/udc/net2280.h
+++ b/drivers/usb/gadget/udc/net2280.h
@@ -100,7 +100,6 @@
 	dma_addr_t				td_dma;	/* of dummy */
 	struct net2280				*dev;
 	unsigned long				irqs;
-	unsigned is_halt:1, dma_started:1;
 
 	/* analogous to a host-side qh */
 	struct list_head			queue;
@@ -126,7 +125,7 @@
 	ep->stopped = 1;
 }
 
-static void allow_status_338x(struct net2280_ep *ep)
+static inline void allow_status_338x(struct net2280_ep *ep)
 {
 	/*
 	 * Control Status Phase Handshake was set by the chip when the setup
@@ -165,8 +164,8 @@
 					u2_enable:1,
 					ltm_enable:1,
 					wakeup_enable:1,
-					selfpowered:1,
-					addressed_state:1;
+					addressed_state:1,
+					bug7734_patched:1;
 	u16				chiprev;
 	int enhanced_mode;
 	int n_ep;
@@ -356,23 +355,6 @@
 	readl(&ep->regs->ep_rsp);
 }
 
-#ifdef DEBUG
-static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
-{
-	u32	tmp = readl(&ep->regs->ep_stat);
-
-	if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
-		ep_dbg(ep->dev, "%s %s %08x !NAK\n",
-				ep->ep.name, where, tmp);
-		writel(BIT(SET_NAK_OUT_PACKETS),
-			&ep->regs->ep_rsp);
-	}
-}
-#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
-#else
-#define ASSERT_OUT_NAKING(ep) do {} while (0)
-#endif
-
 static inline void stop_out_naking(struct net2280_ep *ep)
 {
 	u32	tmp;
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 288c087..e2fcdb8 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -1171,6 +1171,7 @@
 	unsigned long	flags;
 	u16		syscon1;
 
+	gadget->is_selfpowered = (is_selfpowered != 0);
 	udc = container_of(gadget, struct omap_udc, gadget);
 	spin_lock_irqsave(&udc->lock, flags);
 	syscon1 = omap_readw(UDC_SYSCON1);
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index 1c7379a..613547f 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -1161,6 +1161,7 @@
 
 	if (!gadget)
 		return -EINVAL;
+	gadget->is_selfpowered = (value != 0);
 	dev = container_of(gadget, struct pch_udc_dev, gadget);
 	if (value)
 		pch_udc_set_selfpowered(dev);
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 8550b2d..f6cbe66 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1272,7 +1272,6 @@
 			goto bind_fail;
 	}
 
-	pullup(dev);
 	dump_state(dev);
 	return 0;
 bind_fail:
@@ -1339,7 +1338,6 @@
 
 	local_irq_disable();
 	dev->pullup = 0;
-	pullup(dev);
 	stop_activity(dev, NULL);
 	local_irq_enable();
 
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index c61a896..6a855fc 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -1809,7 +1809,6 @@
 
 	/* first hook up the driver ... */
 	udc->driver = driver;
-	dplus_pullup(udc, 1);
 
 	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
@@ -1862,7 +1861,6 @@
 
 	stop_activity(udc, NULL);
 	udc_disable(udc);
-	dplus_pullup(udc, 0);
 
 	udc->driver = NULL;
 
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index 06870da..2495fe9 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1803,6 +1803,7 @@
 {
 	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
 
+	gadget->is_selfpowered = (is_self != 0);
 	if (is_self)
 		r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
 	else
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index 824cf12..b808951 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -238,14 +238,6 @@
 			S3C2410_UDC_EP0_CSR_REG);
 }
 
-static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
-{
-	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
-	udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
-				| S3C2410_UDC_EP0_CSR_SSE),
-			S3C2410_UDC_EP0_CSR_REG);
-}
-
 static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
 {
 	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
@@ -291,18 +283,6 @@
 	}
 }
 
-static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
-{
-	unsigned i;
-
-	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
-	 * fifos, and pending transactions mustn't be continued in any case.
-	 */
-
-	for (i = 1; i < S3C2410_ENDPOINTS; i++)
-		s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
-}
-
 static inline int s3c2410_udc_fifo_count_out(void)
 {
 	int tmp;
@@ -1454,6 +1434,7 @@
 
 	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
 
+	gadget->is_selfpowered = (value != 0);
 	if (value)
 		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 	else
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index e31d574..5a81cb0 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -564,6 +564,7 @@
 static USB_UDC_ATTR(b_hnp_enable);
 static USB_UDC_ATTR(a_hnp_support);
 static USB_UDC_ATTR(a_alt_hnp_support);
+static USB_UDC_ATTR(is_selfpowered);
 
 static struct attribute *usb_udc_attrs[] = {
 	&dev_attr_srp.attr,
@@ -577,6 +578,7 @@
 	&dev_attr_b_hnp_enable.attr,
 	&dev_attr_a_hnp_support.attr,
 	&dev_attr_a_alt_hnp_support.attr,
+	&dev_attr_is_selfpowered.attr,
 	NULL,
 };
 
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index fafc628..5ad60e4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -219,7 +219,7 @@
 
 config USB_EHCI_HCD_PPC_OF
 	bool "EHCI support for PPC USB controller on OF platform bus"
-	depends on PPC_OF
+	depends on PPC
 	default y
 	---help---
 	  Enables support for the USB controller present on the PowerPC
@@ -331,20 +331,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called isp116x-hcd.
 
-config USB_ISP1760_HCD
-	tristate "ISP 1760 HCD support"
-	---help---
-	  The ISP1760 chip is a USB 2.0 host controller.
-
-	  This driver does not support isochronous transfers or OTG.
-	  This USB controller is usually attached to a non-DMA-Master
-	  capable bus. NXP's eval kit brings this chip on PCI card
-	  where the chip itself is behind a PLB to simulate such
-	  a bus.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called isp1760.
-
 config USB_ISP1362_HCD
 	tristate "ISP1362 HCD support"
 	---help---
@@ -494,7 +480,7 @@
 
 config USB_OHCI_HCD_PPC_OF_BE
 	bool "OHCI support for OF platform bus (big endian)"
-	depends on PPC_OF
+	depends on PPC
 	select USB_OHCI_BIG_ENDIAN_DESC
 	select USB_OHCI_BIG_ENDIAN_MMIO
 	---help---
@@ -503,7 +489,7 @@
 
 config USB_OHCI_HCD_PPC_OF_LE
 	bool "OHCI support for OF platform bus (little endian)"
-	depends on PPC_OF
+	depends on PPC
 	select USB_OHCI_LITTLE_ENDIAN
 	---help---
 	  Enables support for little-endian USB controllers present on the
@@ -511,7 +497,7 @@
 
 config USB_OHCI_HCD_PPC_OF
 	bool
-	depends on PPC_OF
+	depends on PPC
 	default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
 
 config USB_OHCI_HCD_PCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index d6216a4..65b0b6a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -5,8 +5,6 @@
 # tell define_trace.h where to find the xhci trace header
 CFLAGS_xhci-trace.o := -I$(src)
 
-isp1760-y := isp1760-hcd.o isp1760-if.o
-
 fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
 fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
 
@@ -69,7 +67,6 @@
 obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
-obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a8850..663f790 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,44 +27,66 @@
 #define DRIVER_DESC "EHCI Atmel driver"
 
 static const char hcd_name[] = "ehci-atmel";
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+	((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv)
+
+struct atmel_ehci_priv {
+	struct clk *iclk;
+	struct clk *fclk;
+	struct clk *uclk;
+	bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = {
+	.extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
 
 /*-------------------------------------------------------------------------*/
 
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
 {
+	if (atmel_ehci->clocked)
+		return;
 	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-		clk_set_rate(uclk, 48000000);
-		clk_prepare_enable(uclk);
+		clk_set_rate(atmel_ehci->uclk, 48000000);
+		clk_prepare_enable(atmel_ehci->uclk);
 	}
-	clk_prepare_enable(iclk);
-	clk_prepare_enable(fclk);
-	clocked = 1;
+	clk_prepare_enable(atmel_ehci->iclk);
+	clk_prepare_enable(atmel_ehci->fclk);
+	atmel_ehci->clocked = true;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
 {
-	clk_disable_unprepare(fclk);
-	clk_disable_unprepare(iclk);
+	if (!atmel_ehci->clocked)
+		return;
+	clk_disable_unprepare(atmel_ehci->fclk);
+	clk_disable_unprepare(atmel_ehci->iclk);
 	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_disable_unprepare(uclk);
-	clocked = 0;
+		clk_disable_unprepare(atmel_ehci->uclk);
+	atmel_ehci->clocked = false;
 }
 
 static void atmel_start_ehci(struct platform_device *pdev)
 {
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
 	dev_dbg(&pdev->dev, "start\n");
-	atmel_start_clock();
+	atmel_start_clock(atmel_ehci);
 }
 
 static void atmel_stop_ehci(struct platform_device *pdev)
 {
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
 	dev_dbg(&pdev->dev, "stop\n");
-	atmel_stop_clock();
+	atmel_stop_clock(atmel_ehci);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -75,6 +97,7 @@
 	const struct hc_driver *driver = &ehci_atmel_hc_driver;
 	struct resource *res;
 	struct ehci_hcd *ehci;
+	struct atmel_ehci_priv *atmel_ehci;
 	int irq;
 	int retval;
 
@@ -105,6 +128,7 @@
 		retval = -ENOMEM;
 		goto fail_create_hcd;
 	}
+	atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
@@ -116,23 +140,23 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	iclk = devm_clk_get(&pdev->dev, "ehci_clk");
-	if (IS_ERR(iclk)) {
+	atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk");
+	if (IS_ERR(atmel_ehci->iclk)) {
 		dev_err(&pdev->dev, "Error getting interface clock\n");
 		retval = -ENOENT;
 		goto fail_request_resource;
 	}
-	fclk = devm_clk_get(&pdev->dev, "uhpck");
-	if (IS_ERR(fclk)) {
+	atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
+	if (IS_ERR(atmel_ehci->fclk)) {
 		dev_err(&pdev->dev, "Error getting function clock\n");
 		retval = -ENOENT;
 		goto fail_request_resource;
 	}
 	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-		uclk = devm_clk_get(&pdev->dev, "usb_clk");
-		if (IS_ERR(uclk)) {
+		atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+		if (IS_ERR(atmel_ehci->uclk)) {
 			dev_err(&pdev->dev, "failed to get uclk\n");
-			retval = PTR_ERR(uclk);
+			retval = PTR_ERR(atmel_ehci->uclk);
 			goto fail_request_resource;
 		}
 	}
@@ -169,11 +193,35 @@
 	usb_put_hcd(hcd);
 
 	atmel_stop_ehci(pdev);
-	fclk = iclk = NULL;
 
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+	int ret;
+
+	ret = ehci_suspend(hcd, false);
+	if (ret)
+		return ret;
+
+	atmel_stop_clock(atmel_ehci);
+	return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
+	atmel_start_clock(atmel_ehci);
+	return ehci_resume(hcd, false);
+}
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id atmel_ehci_dt_ids[] = {
 	{ .compatible = "atmel,at91sam9g45-ehci" },
@@ -183,12 +231,16 @@
 MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
 #endif
 
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+					ehci_atmel_drv_resume);
+
 static struct platform_driver ehci_atmel_driver = {
 	.probe		= ehci_atmel_drv_probe,
 	.remove		= ehci_atmel_drv_remove,
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver		= {
 		.name	= "atmel-ehci",
+		.pm	= &ehci_atmel_pm_ops,
 		.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
 	},
 };
@@ -199,7 +251,7 @@
 		return -ENODEV;
 
 	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-	ehci_init_driver(&ehci_atmel_hc_driver, NULL);
+	ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
 	return platform_driver_register(&ehci_atmel_driver);
 }
 module_init(ehci_atmel_init);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index fb7bd0c..ab4eee3 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -709,7 +709,6 @@
 	.shutdown = usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "fsl-ehci",
-		.owner	= THIS_MODULE,
 		.pm = EHCI_FSL_PM_OPS,
 	},
 };
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index 495b6fb..2165004 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -187,7 +187,6 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "grlib-ehci",
-		.owner = THIS_MODULE,
 		.of_match_table = ehci_hcd_grlib_of_match,
 	},
 };
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 38bfeed..85e56d1 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1110,7 +1110,7 @@
 EXPORT_SYMBOL_GPL(ehci_suspend);
 
 /* Returns 0 if power was preserved, 1 if power was lost */
-int ehci_resume(struct usb_hcd *hcd, bool hibernated)
+int ehci_resume(struct usb_hcd *hcd, bool force_reset)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 
@@ -1124,12 +1124,12 @@
 		return 0;		/* Controller is dead */
 
 	/*
-	 * If CF is still set and we aren't resuming from hibernation
+	 * If CF is still set and reset isn't forced
 	 * then we maintained suspend power.
 	 * Just undo the effect of ehci_suspend().
 	 */
 	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
-			!hibernated) {
+			!force_reset) {
 		int	mask = INTR_MASK;
 
 		ehci_prepare_ports_for_controller_resume(ehci);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 118edb7..87cf86f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -700,15 +700,15 @@
 	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 
-	temp = 0x0008;			/* per-port overcurrent reporting */
+	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
 	if (HCS_PPC (ehci->hcs_params))
-		temp |= 0x0001;		/* per-port power control */
+		temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
 	else
-		temp |= 0x0002;		/* no power switching */
+		temp |= HUB_CHAR_NO_LPSM; /* no power switching */
 #if 0
 // re-enable when we support USB_PORT_FEAT_INDICATOR below.
 	if (HCS_INDICATOR (ehci->hcs_params))
-		temp |= 0x0080;		/* per-port indicators (LEDs) */
+		temp |= HUB_CHAR_PORTIND; /* per-port indicators (LEDs) */
 #endif
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 }
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 851006a..2a5d2fd 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -43,6 +43,24 @@
 }
 
 /*
+ * This is the list of PCI IDs for the devices that have EHCI USB class and
+ * specific drivers for that. One of the example is a ChipIdea device installed
+ * on some Intel MID platforms.
+ */
+static const struct pci_device_id bypass_pci_id_table[] = {
+	/* ChipIdea on Intel MID platform */
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), },
+	{}
+};
+
+static inline bool is_bypassed_id(struct pci_dev *pdev)
+{
+	return !!pci_match_id(bypass_pci_id_table, pdev);
+}
+
+/*
  * 0x84 is the offset of in/out threshold register,
  * and it is the same offset as the register of 'hostpc'.
  */
@@ -352,6 +370,13 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	if (is_bypassed_id(pdev))
+		return -ENODEV;
+	return usb_hcd_pci_probe(pdev, id);
+}
+
 /* PCI driver selection metadata; PCI hotplugging uses this */
 static const struct pci_device_id pci_ids [] = { {
 	/* handle any USB 2.0 EHCI controller */
@@ -370,7 +395,7 @@
 	.name =		(char *) hcd_name,
 	.id_table =	pci_ids,
 
-	.probe =	usb_hcd_pci_probe,
+	.probe =	ehci_pci_probe,
 	.remove =	usb_hcd_pci_remove,
 	.shutdown = 	usb_hcd_pci_shutdown,
 
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 8557803..d8a75a5 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -43,7 +43,8 @@
 struct ehci_platform_priv {
 	struct clk *clks[EHCI_MAX_CLKS];
 	struct reset_control *rst;
-	struct phy *phy;
+	struct phy **phys;
+	int num_phys;
 };
 
 static const char hcd_name[] = "ehci-platform";
@@ -78,7 +79,7 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
-	int clk, ret;
+	int clk, ret, phy_num;
 
 	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
 		ret = clk_prepare_enable(priv->clks[clk]);
@@ -86,20 +87,28 @@
 			goto err_disable_clks;
 	}
 
-	if (priv->phy) {
-		ret = phy_init(priv->phy);
-		if (ret)
-			goto err_disable_clks;
-
-		ret = phy_power_on(priv->phy);
-		if (ret)
-			goto err_exit_phy;
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		if (priv->phys[phy_num]) {
+			ret = phy_init(priv->phys[phy_num]);
+			if (ret)
+				goto err_exit_phy;
+			ret = phy_power_on(priv->phys[phy_num]);
+			if (ret) {
+				phy_exit(priv->phys[phy_num]);
+				goto err_exit_phy;
+			}
+		}
 	}
 
 	return 0;
 
 err_exit_phy:
-	phy_exit(priv->phy);
+	while (--phy_num >= 0) {
+		if (priv->phys[phy_num]) {
+			phy_power_off(priv->phys[phy_num]);
+			phy_exit(priv->phys[phy_num]);
+		}
+	}
 err_disable_clks:
 	while (--clk >= 0)
 		clk_disable_unprepare(priv->clks[clk]);
@@ -111,11 +120,13 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
-	int clk;
+	int clk, phy_num;
 
-	if (priv->phy) {
-		phy_power_off(priv->phy);
-		phy_exit(priv->phy);
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		if (priv->phys[phy_num]) {
+			phy_power_off(priv->phys[phy_num]);
+			phy_exit(priv->phys[phy_num]);
+		}
 	}
 
 	for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -143,7 +154,8 @@
 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ehci_platform_priv *priv;
 	struct ehci_hcd *ehci;
-	int err, irq, clk = 0;
+	const char *phy_name;
+	int err, irq, phy_num, clk = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -155,7 +167,8 @@
 	if (!pdata)
 		pdata = &ehci_platform_defaults;
 
-	err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
+	err = dma_coerce_mask_and_coherent(&dev->dev,
+		pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
 	if (err)
 		return err;
 
@@ -185,12 +198,42 @@
 		if (of_property_read_bool(dev->dev.of_node, "big-endian"))
 			ehci->big_endian_mmio = ehci->big_endian_desc = 1;
 
-		priv->phy = devm_phy_get(&dev->dev, "usb");
-		if (IS_ERR(priv->phy)) {
-			err = PTR_ERR(priv->phy);
-			if (err == -EPROBE_DEFER)
-				goto err_put_hcd;
-			priv->phy = NULL;
+		if (of_property_read_bool(dev->dev.of_node,
+					  "needs-reset-on-resume"))
+			pdata->reset_on_resume = 1;
+
+		priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
+				"phys", "#phy-cells");
+		priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
+
+		priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+				sizeof(struct phy *), GFP_KERNEL);
+		if (!priv->phys)
+			return -ENOMEM;
+
+		for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+				err = of_property_read_string_index(
+						dev->dev.of_node,
+						"phy-names", phy_num,
+						&phy_name);
+
+				if (err < 0) {
+					if (priv->num_phys > 1) {
+						dev_err(&dev->dev, "phy-names not provided");
+						goto err_put_hcd;
+					} else
+						phy_name = "usb";
+				}
+
+				priv->phys[phy_num] = devm_phy_get(&dev->dev,
+						phy_name);
+				if (IS_ERR(priv->phys[phy_num])) {
+					err = PTR_ERR(priv->phys[phy_num]);
+					if ((priv->num_phys > 1) ||
+					    (err == -EPROBE_DEFER))
+						goto err_put_hcd;
+					priv->phys[phy_num] = NULL;
+				}
 		}
 
 		for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
@@ -340,7 +383,7 @@
 			return err;
 	}
 
-	ehci_resume(hcd, false);
+	ehci_resume(hcd, pdata->reset_on_resume);
 	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
@@ -349,6 +392,7 @@
 	{ .compatible = "via,vt8500-ehci", },
 	{ .compatible = "wm,prizm-ehci", },
 	{ .compatible = "generic-ehci", },
+	{ .compatible = "cavium,octeon-6335-ehci", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 7d75465..342816a 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -325,6 +325,5 @@
 	.remove		= ehci_hcd_msp_drv_remove,
 	.driver		= {
 		.name	= "pmcmsp-ehci",
-		.owner	= THIS_MODULE,
 	},
 };
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 5479247..1a10c8d 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -234,7 +234,6 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "ppc-of-ehci",
-		.owner = THIS_MODULE,
 		.of_match_table = ehci_hcd_ppc_of_match,
 	},
 };
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index 9b6e8d0..3d86cc2 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -178,7 +178,6 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name	= "sead3-ehci",
-		.owner	= THIS_MODULE,
 		.pm	= SEAD3_EHCI_PMOPS,
 	}
 };
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 0e0ce68..5caf88d 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -189,7 +189,6 @@
 	.shutdown	= ehci_hcd_sh_shutdown,
 	.driver		= {
 		.name	= "sh_ehci",
-		.owner	= THIS_MODULE,
 	},
 };
 
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c
index 0d24767..bdb93b6 100644
--- a/drivers/usb/host/ehci-tilegx.c
+++ b/drivers/usb/host/ehci-tilegx.c
@@ -210,7 +210,6 @@
 	.shutdown	= ehci_hcd_tilegx_drv_shutdown,
 	.driver = {
 		.name	= "tilegx-ehci",
-		.owner	= THIS_MODULE,
 	}
 };
 
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index a232836..f544808 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -236,7 +236,6 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "xilinx-of-ehci",
-		.owner = THIS_MODULE,
 		.of_match_table = ehci_hcd_xilinx_of_match,
 	},
 };
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 6f0577b..52ef084 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -871,7 +871,7 @@
 
 #ifdef CONFIG_PM
 extern int	ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
-extern int	ehci_resume(struct usb_hcd *hcd, bool hibernated);
+extern int	ehci_resume(struct usb_hcd *hcd, bool force_reset);
 #endif	/* CONFIG_PM */
 
 extern int	ehci_hub_control(struct usb_hcd	*hcd, u16 typeReq, u16 wValue,
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c
index 6af2512..70116a6 100644
--- a/drivers/usb/host/fhci-hub.c
+++ b/drivers/usb/host/fhci-hub.c
@@ -32,8 +32,8 @@
 	0x09, /* blength */
 	0x29, /* bDescriptorType;hub-descriptor */
 	0x01, /* bNbrPorts */
-	0x00, /* wHubCharacteristics */
-	0x00,
+	HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM, /* wHubCharacteristics */
+	0x00, /* per-port power, no overcurrent */
 	0x01, /* bPwrOn2pwrGood;2ms */
 	0x00, /* bHubContrCurrent;0mA */
 	0x00, /* DeviceRemoveable */
@@ -208,7 +208,6 @@
 {
 	struct fhci_hcd *fhci = hcd_to_fhci(hcd);
 	int retval = 0;
-	int len = 0;
 	struct usb_hub_status *hub_status;
 	struct usb_port_status *port_status;
 	unsigned long flags;
@@ -272,8 +271,6 @@
 		break;
 	case GetHubDescriptor:
 		memcpy(buf, root_hub_des, sizeof(root_hub_des));
-		buf[3] = 0x11; /* per-port power, no ovrcrnt */
-		len = (buf[0] < wLength) ? buf[0] : wLength;
 		break;
 	case GetHubStatus:
 		hub_status = (struct usb_hub_status *)buf;
@@ -281,7 +278,6 @@
 		    cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);
 		hub_status->wHubChange =
 		    cpu_to_le16(fhci->vroot_hub->hub.wHubChange);
-		len = 4;
 		break;
 	case GetPortStatus:
 		port_status = (struct usb_port_status *)buf;
@@ -289,7 +285,6 @@
 		    cpu_to_le16(fhci->vroot_hub->port.wPortStatus);
 		port_status->wPortChange =
 		    cpu_to_le16(fhci->vroot_hub->port.wPortChange);
-		len = 4;
 		break;
 	case SetHubFeature:
 		switch (wValue) {
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index ecf02b26..475b21f 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -1521,8 +1521,8 @@
 	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 
-	temp = 0x0008;		/* per-port overcurrent reporting */
-	temp |= 0x0002;		/* no power switching */
+	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
+	temp |= HUB_CHAR_NO_LPSM;	/* no power switching */
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 }
 
diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c
index 664d2aa..a83eefe 100644
--- a/drivers/usb/host/fusbh200-hcd.c
+++ b/drivers/usb/host/fusbh200-hcd.c
@@ -1479,8 +1479,8 @@
 	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 
-	temp = 0x0008;		/* per-port overcurrent reporting */
-	temp |= 0x0002;		/* no power switching */
+	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
+	temp |= HUB_CHAR_NO_LPSM;	/* no power switching */
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 }
 
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index eb4efba..6a2ad55 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1482,9 +1482,8 @@
 	desc->bDescLength = 9;
 	desc->bPwrOn2PwrGood = 0;
 	desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
-		0x0002 |	/* No power switching */
-		0x0010 |	/* No over current protection */
-		0);
+		HUB_CHAR_NO_LPSM |	/* No power switching */
+		HUB_CHAR_NO_OCPM);	/* No over current protection */
 
 	desc->u.hs.DeviceRemovable[0] = 1 << 1;
 	desc->u.hs.DeviceRemovable[1] = ~0;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 31c9c4d..113d0cc 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -948,7 +948,10 @@
 	desc->bHubContrCurrent = 0;
 	desc->bNbrPorts = (u8) (reg & 0x3);
 	/* Power switching, device type, overcurrent. */
-	desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
+	desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) &
+						       (HUB_CHAR_LPSM |
+							HUB_CHAR_COMPOUND |
+							HUB_CHAR_OCPM)));
 	desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
 	/* ports removable, and legacy PortPwrCtrlMask */
 	desc->u.hs.DeviceRemovable[0] = 0;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 75e5876..b32ab60 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -1543,8 +1543,12 @@
 	desc->bHubContrCurrent = 0;
 	desc->bNbrPorts = reg & 0x3;
 	/* Power switching, device type, overcurrent. */
-	desc->wHubCharacteristics = cpu_to_le16((reg >> 8) & 0x1f);
-	DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f));
+	desc->wHubCharacteristics = cpu_to_le16((reg >> 8) &
+						(HUB_CHAR_LPSM |
+						 HUB_CHAR_COMPOUND |
+						 HUB_CHAR_OCPM));
+	DBG(0, "%s: hubcharacteristics = %02x\n", __func__,
+			desc->wHubCharacteristics);
 	desc->bPwrOn2PwrGood = (reg >> 24) & 0xff;
 	/* ports removable, and legacy PortPwrCtrlMask */
 	desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
deleted file mode 100644
index 395649f..0000000
--- a/drivers/usb/host/isp1760-hcd.c
+++ /dev/null
@@ -1,2268 +0,0 @@
-/*
- * Driver for the NXP ISP1760 chip
- *
- * However, the code might contain some bugs. What doesn't work for sure is:
- * - ISO
- * - OTG
- e The interrupt line is configured as active low, level.
- *
- * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
- *
- * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <asm/unaligned.h>
-#include <asm/cacheflush.h>
-#include <linux/gpio.h>
-
-#include "isp1760-hcd.h"
-
-static struct kmem_cache *qtd_cachep;
-static struct kmem_cache *qh_cachep;
-static struct kmem_cache *urb_listitem_cachep;
-
-enum queue_head_types {
-	QH_CONTROL,
-	QH_BULK,
-	QH_INTERRUPT,
-	QH_END
-};
-
-struct isp1760_hcd {
-	u32 hcs_params;
-	spinlock_t		lock;
-	struct slotinfo		atl_slots[32];
-	int			atl_done_map;
-	struct slotinfo		int_slots[32];
-	int			int_done_map;
-	struct memory_chunk memory_pool[BLOCKS];
-	struct list_head	qh_list[QH_END];
-
-	/* periodic schedule support */
-#define	DEFAULT_I_TDPS		1024
-	unsigned		periodic_size;
-	unsigned		i_thresh;
-	unsigned long		reset_done;
-	unsigned long		next_statechange;
-	unsigned int		devflags;
-
-	int			rst_gpio;
-};
-
-static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
-{
-	return (struct isp1760_hcd *) (hcd->hcd_priv);
-}
-
-/* Section 2.2 Host Controller Capability Registers */
-#define HC_LENGTH(p)		(((p)>>00)&0x00ff)	/* bits 7:0 */
-#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
-#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
-#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
-#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-
-/* Section 2.3 Host Controller Operational Registers */
-#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
-#define CMD_RESET	(1<<1)		/* reset HC not bus */
-#define CMD_RUN		(1<<0)		/* start/stop HC */
-#define STS_PCD		(1<<2)		/* port change detect */
-#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
-
-#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
-#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10))	/* USB 1.1 device */
-#define PORT_RESET	(1<<8)		/* reset port */
-#define PORT_SUSPEND	(1<<7)		/* suspend port */
-#define PORT_RESUME	(1<<6)		/* resume it */
-#define PORT_PE		(1<<2)		/* port enable */
-#define PORT_CSC	(1<<1)		/* connect status change */
-#define PORT_CONNECT	(1<<0)		/* device connected */
-#define PORT_RWC_BITS   (PORT_CSC)
-
-struct isp1760_qtd {
-	u8 packet_type;
-	void *data_buffer;
-	u32 payload_addr;
-
-	/* the rest is HCD-private */
-	struct list_head qtd_list;
-	struct urb *urb;
-	size_t length;
-	size_t actual_length;
-
-	/* QTD_ENQUEUED:	waiting for transfer (inactive) */
-	/* QTD_PAYLOAD_ALLOC:	chip mem has been allocated for payload */
-	/* QTD_XFER_STARTED:	valid ptd has been written to isp176x - only
-				interrupt handler may touch this qtd! */
-	/* QTD_XFER_COMPLETE:	payload has been transferred successfully */
-	/* QTD_RETIRE:		transfer error/abort qtd */
-#define QTD_ENQUEUED		0
-#define QTD_PAYLOAD_ALLOC	1
-#define QTD_XFER_STARTED	2
-#define QTD_XFER_COMPLETE	3
-#define QTD_RETIRE		4
-	u32 status;
-};
-
-/* Queue head, one for each active endpoint */
-struct isp1760_qh {
-	struct list_head qh_list;
-	struct list_head qtd_list;
-	u32 toggle;
-	u32 ping;
-	int slot;
-	int tt_buffer_dirty;	/* See USB2.0 spec section 11.17.5 */
-};
-
-struct urb_listitem {
-	struct list_head urb_list;
-	struct urb *urb;
-};
-
-/*
- * Access functions for isp176x registers (addresses 0..0x03FF).
- */
-static u32 reg_read32(void __iomem *base, u32 reg)
-{
-	return readl(base + reg);
-}
-
-static void reg_write32(void __iomem *base, u32 reg, u32 val)
-{
-	writel(val, base + reg);
-}
-
-/*
- * Access functions for isp176x memory (offset >= 0x0400).
- *
- * bank_reads8() reads memory locations prefetched by an earlier write to
- * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
- * bank optimizations, you should use the more generic mem_reads8() below.
- *
- * For access to ptd memory, use the specialized ptd_read() and ptd_write()
- * below.
- *
- * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
- * doesn't quite work because some people have to enforce 32-bit access
- */
-static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
-							__u32 *dst, u32 bytes)
-{
-	__u32 __iomem *src;
-	u32 val;
-	__u8 *src_byteptr;
-	__u8 *dst_byteptr;
-
-	src = src_base + (bank_addr | src_offset);
-
-	if (src_offset < PAYLOAD_OFFSET) {
-		while (bytes >= 4) {
-			*dst = le32_to_cpu(__raw_readl(src));
-			bytes -= 4;
-			src++;
-			dst++;
-		}
-	} else {
-		while (bytes >= 4) {
-			*dst = __raw_readl(src);
-			bytes -= 4;
-			src++;
-			dst++;
-		}
-	}
-
-	if (!bytes)
-		return;
-
-	/* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
-	 * allocated.
-	 */
-	if (src_offset < PAYLOAD_OFFSET)
-		val = le32_to_cpu(__raw_readl(src));
-	else
-		val = __raw_readl(src);
-
-	dst_byteptr = (void *) dst;
-	src_byteptr = (void *) &val;
-	while (bytes > 0) {
-		*dst_byteptr = *src_byteptr;
-		dst_byteptr++;
-		src_byteptr++;
-		bytes--;
-	}
-}
-
-static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
-								u32 bytes)
-{
-	reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
-	ndelay(90);
-	bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
-}
-
-static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
-						__u32 const *src, u32 bytes)
-{
-	__u32 __iomem *dst;
-
-	dst = dst_base + dst_offset;
-
-	if (dst_offset < PAYLOAD_OFFSET) {
-		while (bytes >= 4) {
-			__raw_writel(cpu_to_le32(*src), dst);
-			bytes -= 4;
-			src++;
-			dst++;
-		}
-	} else {
-		while (bytes >= 4) {
-			__raw_writel(*src, dst);
-			bytes -= 4;
-			src++;
-			dst++;
-		}
-	}
-
-	if (!bytes)
-		return;
-	/* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the
-	 * extra bytes should not be read by the HW.
-	 */
-
-	if (dst_offset < PAYLOAD_OFFSET)
-		__raw_writel(cpu_to_le32(*src), dst);
-	else
-		__raw_writel(*src, dst);
-}
-
-/*
- * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
- * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
- */
-static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
-								struct ptd *ptd)
-{
-	reg_write32(base, HC_MEMORY_REG,
-				ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
-	ndelay(90);
-	bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
-						(void *) ptd, sizeof(*ptd));
-}
-
-static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
-								struct ptd *ptd)
-{
-	mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
-						&ptd->dw1, 7*sizeof(ptd->dw1));
-	/* Make sure dw0 gets written last (after other dw's and after payload)
-	   since it contains the enable bit */
-	wmb();
-	mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
-							sizeof(ptd->dw0));
-}
-
-
-/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
-static void init_memory(struct isp1760_hcd *priv)
-{
-	int i, curr;
-	u32 payload_addr;
-
-	payload_addr = PAYLOAD_OFFSET;
-	for (i = 0; i < BLOCK_1_NUM; i++) {
-		priv->memory_pool[i].start = payload_addr;
-		priv->memory_pool[i].size = BLOCK_1_SIZE;
-		priv->memory_pool[i].free = 1;
-		payload_addr += priv->memory_pool[i].size;
-	}
-
-	curr = i;
-	for (i = 0; i < BLOCK_2_NUM; i++) {
-		priv->memory_pool[curr + i].start = payload_addr;
-		priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
-		priv->memory_pool[curr + i].free = 1;
-		payload_addr += priv->memory_pool[curr + i].size;
-	}
-
-	curr = i;
-	for (i = 0; i < BLOCK_3_NUM; i++) {
-		priv->memory_pool[curr + i].start = payload_addr;
-		priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
-		priv->memory_pool[curr + i].free = 1;
-		payload_addr += priv->memory_pool[curr + i].size;
-	}
-
-	WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
-}
-
-static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int i;
-
-	WARN_ON(qtd->payload_addr);
-
-	if (!qtd->length)
-		return;
-
-	for (i = 0; i < BLOCKS; i++) {
-		if (priv->memory_pool[i].size >= qtd->length &&
-				priv->memory_pool[i].free) {
-			priv->memory_pool[i].free = 0;
-			qtd->payload_addr = priv->memory_pool[i].start;
-			return;
-		}
-	}
-}
-
-static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int i;
-
-	if (!qtd->payload_addr)
-		return;
-
-	for (i = 0; i < BLOCKS; i++) {
-		if (priv->memory_pool[i].start == qtd->payload_addr) {
-			WARN_ON(priv->memory_pool[i].free);
-			priv->memory_pool[i].free = 1;
-			qtd->payload_addr = 0;
-			return;
-		}
-	}
-
-	dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
-						__func__, qtd->payload_addr);
-	WARN_ON(1);
-	qtd->payload_addr = 0;
-}
-
-static int handshake(struct usb_hcd *hcd, u32 reg,
-		      u32 mask, u32 done, int usec)
-{
-	u32 result;
-
-	do {
-		result = reg_read32(hcd->regs, reg);
-		if (result == ~0)
-			return -ENODEV;
-		result &= mask;
-		if (result == done)
-			return 0;
-		udelay(1);
-		usec--;
-	} while (usec > 0);
-	return -ETIMEDOUT;
-}
-
-/* reset a non-running (STS_HALT == 1) controller */
-static int ehci_reset(struct usb_hcd *hcd)
-{
-	int retval;
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-
-	u32 command = reg_read32(hcd->regs, HC_USBCMD);
-
-	command |= CMD_RESET;
-	reg_write32(hcd->regs, HC_USBCMD, command);
-	hcd->state = HC_STATE_HALT;
-	priv->next_statechange = jiffies;
-	retval = handshake(hcd, HC_USBCMD,
-			    CMD_RESET, 0, 250 * 1000);
-	return retval;
-}
-
-static struct isp1760_qh *qh_alloc(gfp_t flags)
-{
-	struct isp1760_qh *qh;
-
-	qh = kmem_cache_zalloc(qh_cachep, flags);
-	if (!qh)
-		return NULL;
-
-	INIT_LIST_HEAD(&qh->qh_list);
-	INIT_LIST_HEAD(&qh->qtd_list);
-	qh->slot = -1;
-
-	return qh;
-}
-
-static void qh_free(struct isp1760_qh *qh)
-{
-	WARN_ON(!list_empty(&qh->qtd_list));
-	WARN_ON(qh->slot > -1);
-	kmem_cache_free(qh_cachep, qh);
-}
-
-/* one-time init, only for memory state */
-static int priv_init(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd		*priv = hcd_to_priv(hcd);
-	u32			hcc_params;
-	int i;
-
-	spin_lock_init(&priv->lock);
-
-	for (i = 0; i < QH_END; i++)
-		INIT_LIST_HEAD(&priv->qh_list[i]);
-
-	/*
-	 * hw default: 1K periodic list heads, one per frame.
-	 * periodic_size can shrink by USBCMD update if hcc_params allows.
-	 */
-	priv->periodic_size = DEFAULT_I_TDPS;
-
-	/* controllers may cache some of the periodic schedule ... */
-	hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
-	/* full frame cache */
-	if (HCC_ISOC_CACHE(hcc_params))
-		priv->i_thresh = 8;
-	else /* N microframes cached */
-		priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
-
-	return 0;
-}
-
-static int isp1760_hc_setup(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int result;
-	u32 scratch, hwmode;
-
-	/* low-level chip reset */
-	if (gpio_is_valid(priv->rst_gpio)) {
-		unsigned int rst_lvl;
-
-		rst_lvl = (priv->devflags &
-			   ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
-
-		gpio_set_value(priv->rst_gpio, rst_lvl);
-		mdelay(50);
-		gpio_set_value(priv->rst_gpio, !rst_lvl);
-	}
-
-	/* Setup HW Mode Control: This assumes a level active-low interrupt */
-	hwmode = HW_DATA_BUS_32BIT;
-
-	if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
-		hwmode &= ~HW_DATA_BUS_32BIT;
-	if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
-		hwmode |= HW_ANA_DIGI_OC;
-	if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
-		hwmode |= HW_DACK_POL_HIGH;
-	if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
-		hwmode |= HW_DREQ_POL_HIGH;
-	if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
-		hwmode |= HW_INTR_HIGH_ACT;
-	if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
-		hwmode |= HW_INTR_EDGE_TRIG;
-
-	/*
-	 * We have to set this first in case we're in 16-bit mode.
-	 * Write it twice to ensure correct upper bits if switching
-	 * to 16-bit mode.
-	 */
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-
-	reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
-	/* Change bus pattern */
-	scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
-	scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
-	if (scratch != 0xdeadbabe) {
-		dev_err(hcd->self.controller, "Scratch test failed.\n");
-		return -ENODEV;
-	}
-
-	/* pre reset */
-	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
-	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
-	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
-	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
-
-	/* reset */
-	reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
-	mdelay(100);
-
-	reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC);
-	mdelay(100);
-
-	result = ehci_reset(hcd);
-	if (result)
-		return result;
-
-	/* Step 11 passed */
-
-	dev_info(hcd->self.controller, "bus width: %d, oc: %s\n",
-			   (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
-			   16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
-			   "analog" : "digital");
-
-	/* ATL reset */
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
-	mdelay(10);
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-
-	reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
-
-	/*
-	 * PORT 1 Control register of the ISP1760 is the OTG control
-	 * register on ISP1761. Since there is no OTG or device controller
-	 * support in this driver, we use port 1 as a "normal" USB host port on
-	 * both chips.
-	 */
-	reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
-	mdelay(10);
-
-	priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
-
-	return priv_init(hcd);
-}
-
-static u32 base_to_chip(u32 base)
-{
-	return ((base - 0x400) >> 3);
-}
-
-static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
-{
-	struct urb *urb;
-
-	if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
-		return 1;
-
-	urb = qtd->urb;
-	qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list);
-	return (qtd->urb != urb);
-}
-
-/* magic numbers that can affect system performance */
-#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
-#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
-#define	EHCI_TUNE_RL_TT		0
-#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
-#define	EHCI_TUNE_MULT_TT	1
-#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
-
-static void create_ptd_atl(struct isp1760_qh *qh,
-			struct isp1760_qtd *qtd, struct ptd *ptd)
-{
-	u32 maxpacket;
-	u32 multi;
-	u32 rl = RL_COUNTER;
-	u32 nak = NAK_COUNTER;
-
-	memset(ptd, 0, sizeof(*ptd));
-
-	/* according to 3.6.2, max packet len can not be > 0x400 */
-	maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe,
-						usb_pipeout(qtd->urb->pipe));
-	multi =  1 + ((maxpacket >> 11) & 0x3);
-	maxpacket &= 0x7ff;
-
-	/* DW0 */
-	ptd->dw0 = DW0_VALID_BIT;
-	ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
-	ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
-	ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
-
-	/* DW1 */
-	ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
-	ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
-	ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
-
-	if (usb_pipebulk(qtd->urb->pipe))
-		ptd->dw1 |= DW1_TRANS_BULK;
-	else if  (usb_pipeint(qtd->urb->pipe))
-		ptd->dw1 |= DW1_TRANS_INT;
-
-	if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
-		/* split transaction */
-
-		ptd->dw1 |= DW1_TRANS_SPLIT;
-		if (qtd->urb->dev->speed == USB_SPEED_LOW)
-			ptd->dw1 |= DW1_SE_USB_LOSPEED;
-
-		ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
-		ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
-
-		/* SE bit for Split INT transfers */
-		if (usb_pipeint(qtd->urb->pipe) &&
-				(qtd->urb->dev->speed == USB_SPEED_LOW))
-			ptd->dw1 |= 2 << 16;
-
-		rl = 0;
-		nak = 0;
-	} else {
-		ptd->dw0 |= TO_DW0_MULTI(multi);
-		if (usb_pipecontrol(qtd->urb->pipe) ||
-						usb_pipebulk(qtd->urb->pipe))
-			ptd->dw3 |= TO_DW3_PING(qh->ping);
-	}
-	/* DW2 */
-	ptd->dw2 = 0;
-	ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
-	ptd->dw2 |= TO_DW2_RL(rl);
-
-	/* DW3 */
-	ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
-	ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
-	if (usb_pipecontrol(qtd->urb->pipe)) {
-		if (qtd->data_buffer == qtd->urb->setup_packet)
-			ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
-		else if (last_qtd_of_urb(qtd, qh))
-			ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
-	}
-
-	ptd->dw3 |= DW3_ACTIVE_BIT;
-	/* Cerr */
-	ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
-}
-
-static void transform_add_int(struct isp1760_qh *qh,
-			struct isp1760_qtd *qtd, struct ptd *ptd)
-{
-	u32 usof;
-	u32 period;
-
-	/*
-	 * Most of this is guessing. ISP1761 datasheet is quite unclear, and
-	 * the algorithm from the original Philips driver code, which was
-	 * pretty much used in this driver before as well, is quite horrendous
-	 * and, i believe, incorrect. The code below follows the datasheet and
-	 * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
-	 * more reliable this way (fingers crossed...).
-	 */
-
-	if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
-		/* urb->interval is in units of microframes (1/8 ms) */
-		period = qtd->urb->interval >> 3;
-
-		if (qtd->urb->interval > 4)
-			usof = 0x01; /* One bit set =>
-						interval 1 ms * uFrame-match */
-		else if (qtd->urb->interval > 2)
-			usof = 0x22; /* Two bits set => interval 1/2 ms */
-		else if (qtd->urb->interval > 1)
-			usof = 0x55; /* Four bits set => interval 1/4 ms */
-		else
-			usof = 0xff; /* All bits set => interval 1/8 ms */
-	} else {
-		/* urb->interval is in units of frames (1 ms) */
-		period = qtd->urb->interval;
-		usof = 0x0f;		/* Execute Start Split on any of the
-					   four first uFrames */
-
-		/*
-		 * First 8 bits in dw5 is uSCS and "specifies which uSOF the
-		 * complete split needs to be sent. Valid only for IN." Also,
-		 * "All bits can be set to one for every transfer." (p 82,
-		 * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
-		 * that number come from? 0xff seems to work fine...
-		 */
-		/* ptd->dw5 = 0x1c; */
-		ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
-	}
-
-	period = period >> 1;/* Ensure equal or shorter period than requested */
-	period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
-
-	ptd->dw2 |= period;
-	ptd->dw4 = usof;
-}
-
-static void create_ptd_int(struct isp1760_qh *qh,
-			struct isp1760_qtd *qtd, struct ptd *ptd)
-{
-	create_ptd_atl(qh, qtd, ptd);
-	transform_add_int(qh, qtd, ptd);
-}
-
-static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
-__releases(priv->lock)
-__acquires(priv->lock)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-
-	if (!urb->unlinked) {
-		if (urb->status == -EINPROGRESS)
-			urb->status = 0;
-	}
-
-	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
-		void *ptr;
-		for (ptr = urb->transfer_buffer;
-		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
-		     ptr += PAGE_SIZE)
-			flush_dcache_page(virt_to_page(ptr));
-	}
-
-	/* complete() can reenter this HCD */
-	usb_hcd_unlink_urb_from_ep(hcd, urb);
-	spin_unlock(&priv->lock);
-	usb_hcd_giveback_urb(hcd, urb, urb->status);
-	spin_lock(&priv->lock);
-}
-
-static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
-								u8 packet_type)
-{
-	struct isp1760_qtd *qtd;
-
-	qtd = kmem_cache_zalloc(qtd_cachep, flags);
-	if (!qtd)
-		return NULL;
-
-	INIT_LIST_HEAD(&qtd->qtd_list);
-	qtd->urb = urb;
-	qtd->packet_type = packet_type;
-	qtd->status = QTD_ENQUEUED;
-	qtd->actual_length = 0;
-
-	return qtd;
-}
-
-static void qtd_free(struct isp1760_qtd *qtd)
-{
-	WARN_ON(qtd->payload_addr);
-	kmem_cache_free(qtd_cachep, qtd);
-}
-
-static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
-				struct slotinfo *slots, struct isp1760_qtd *qtd,
-				struct isp1760_qh *qh, struct ptd *ptd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int skip_map;
-
-	WARN_ON((slot < 0) || (slot > 31));
-	WARN_ON(qtd->length && !qtd->payload_addr);
-	WARN_ON(slots[slot].qtd);
-	WARN_ON(slots[slot].qh);
-	WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
-
-	/* Make sure done map has not triggered from some unlinked transfer */
-	if (ptd_offset == ATL_PTD_OFFSET) {
-		priv->atl_done_map |= reg_read32(hcd->regs,
-						HC_ATL_PTD_DONEMAP_REG);
-		priv->atl_done_map &= ~(1 << slot);
-	} else {
-		priv->int_done_map |= reg_read32(hcd->regs,
-						HC_INT_PTD_DONEMAP_REG);
-		priv->int_done_map &= ~(1 << slot);
-	}
-
-	qh->slot = slot;
-	qtd->status = QTD_XFER_STARTED;
-	slots[slot].timestamp = jiffies;
-	slots[slot].qtd = qtd;
-	slots[slot].qh = qh;
-	ptd_write(hcd->regs, ptd_offset, slot, ptd);
-
-	if (ptd_offset == ATL_PTD_OFFSET) {
-		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
-		skip_map &= ~(1 << qh->slot);
-		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
-	} else {
-		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-		skip_map &= ~(1 << qh->slot);
-		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
-	}
-}
-
-static int is_short_bulk(struct isp1760_qtd *qtd)
-{
-	return (usb_pipebulk(qtd->urb->pipe) &&
-					(qtd->actual_length < qtd->length));
-}
-
-static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
-						struct list_head *urb_list)
-{
-	int last_qtd;
-	struct isp1760_qtd *qtd, *qtd_next;
-	struct urb_listitem *urb_listitem;
-
-	list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
-		if (qtd->status < QTD_XFER_COMPLETE)
-			break;
-
-		last_qtd = last_qtd_of_urb(qtd, qh);
-
-		if ((!last_qtd) && (qtd->status == QTD_RETIRE))
-			qtd_next->status = QTD_RETIRE;
-
-		if (qtd->status == QTD_XFER_COMPLETE) {
-			if (qtd->actual_length) {
-				switch (qtd->packet_type) {
-				case IN_PID:
-					mem_reads8(hcd->regs, qtd->payload_addr,
-							qtd->data_buffer,
-							qtd->actual_length);
-					/* Fall through (?) */
-				case OUT_PID:
-					qtd->urb->actual_length +=
-							qtd->actual_length;
-					/* Fall through ... */
-				case SETUP_PID:
-					break;
-				}
-			}
-
-			if (is_short_bulk(qtd)) {
-				if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
-					qtd->urb->status = -EREMOTEIO;
-				if (!last_qtd)
-					qtd_next->status = QTD_RETIRE;
-			}
-		}
-
-		if (qtd->payload_addr)
-			free_mem(hcd, qtd);
-
-		if (last_qtd) {
-			if ((qtd->status == QTD_RETIRE) &&
-					(qtd->urb->status == -EINPROGRESS))
-				qtd->urb->status = -EPIPE;
-			/* Defer calling of urb_done() since it releases lock */
-			urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
-								GFP_ATOMIC);
-			if (unlikely(!urb_listitem))
-				break; /* Try again on next call */
-			urb_listitem->urb = qtd->urb;
-			list_add_tail(&urb_listitem->urb_list, urb_list);
-		}
-
-		list_del(&qtd->qtd_list);
-		qtd_free(qtd);
-	}
-}
-
-#define ENQUEUE_DEPTH	2
-static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int ptd_offset;
-	struct slotinfo *slots;
-	int curr_slot, free_slot;
-	int n;
-	struct ptd ptd;
-	struct isp1760_qtd *qtd;
-
-	if (unlikely(list_empty(&qh->qtd_list))) {
-		WARN_ON(1);
-		return;
-	}
-
-	/* Make sure this endpoint's TT buffer is clean before queueing ptds */
-	if (qh->tt_buffer_dirty)
-		return;
-
-	if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
-							qtd_list)->urb->pipe)) {
-		ptd_offset = INT_PTD_OFFSET;
-		slots = priv->int_slots;
-	} else {
-		ptd_offset = ATL_PTD_OFFSET;
-		slots = priv->atl_slots;
-	}
-
-	free_slot = -1;
-	for (curr_slot = 0; curr_slot < 32; curr_slot++) {
-		if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
-			free_slot = curr_slot;
-		if (slots[curr_slot].qh == qh)
-			break;
-	}
-
-	n = 0;
-	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
-		if (qtd->status == QTD_ENQUEUED) {
-			WARN_ON(qtd->payload_addr);
-			alloc_mem(hcd, qtd);
-			if ((qtd->length) && (!qtd->payload_addr))
-				break;
-
-			if ((qtd->length) &&
-			    ((qtd->packet_type == SETUP_PID) ||
-			     (qtd->packet_type == OUT_PID))) {
-				mem_writes8(hcd->regs, qtd->payload_addr,
-						qtd->data_buffer, qtd->length);
-			}
-
-			qtd->status = QTD_PAYLOAD_ALLOC;
-		}
-
-		if (qtd->status == QTD_PAYLOAD_ALLOC) {
-/*
-			if ((curr_slot > 31) && (free_slot == -1))
-				dev_dbg(hcd->self.controller, "%s: No slot "
-					"available for transfer\n", __func__);
-*/
-			/* Start xfer for this endpoint if not already done */
-			if ((curr_slot > 31) && (free_slot > -1)) {
-				if (usb_pipeint(qtd->urb->pipe))
-					create_ptd_int(qh, qtd, &ptd);
-				else
-					create_ptd_atl(qh, qtd, &ptd);
-
-				start_bus_transfer(hcd, ptd_offset, free_slot,
-							slots, qtd, qh, &ptd);
-				curr_slot = free_slot;
-			}
-
-			n++;
-			if (n >= ENQUEUE_DEPTH)
-				break;
-		}
-	}
-}
-
-static void schedule_ptds(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv;
-	struct isp1760_qh *qh, *qh_next;
-	struct list_head *ep_queue;
-	LIST_HEAD(urb_list);
-	struct urb_listitem *urb_listitem, *urb_listitem_next;
-	int i;
-
-	if (!hcd) {
-		WARN_ON(1);
-		return;
-	}
-
-	priv = hcd_to_priv(hcd);
-
-	/*
-	 * check finished/retired xfers, transfer payloads, call urb_done()
-	 */
-	for (i = 0; i < QH_END; i++) {
-		ep_queue = &priv->qh_list[i];
-		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
-			collect_qtds(hcd, qh, &urb_list);
-			if (list_empty(&qh->qtd_list))
-				list_del(&qh->qh_list);
-		}
-	}
-
-	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
-								urb_list) {
-		isp1760_urb_done(hcd, urb_listitem->urb);
-		kmem_cache_free(urb_listitem_cachep, urb_listitem);
-	}
-
-	/*
-	 * Schedule packets for transfer.
-	 *
-	 * According to USB2.0 specification:
-	 *
-	 * 1st prio: interrupt xfers, up to 80 % of bandwidth
-	 * 2nd prio: control xfers
-	 * 3rd prio: bulk xfers
-	 *
-	 * ... but let's use a simpler scheme here (mostly because ISP1761 doc
-	 * is very unclear on how to prioritize traffic):
-	 *
-	 * 1) Enqueue any queued control transfers, as long as payload chip mem
-	 *    and PTD ATL slots are available.
-	 * 2) Enqueue any queued INT transfers, as long as payload chip mem
-	 *    and PTD INT slots are available.
-	 * 3) Enqueue any queued bulk transfers, as long as payload chip mem
-	 *    and PTD ATL slots are available.
-	 *
-	 * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
-	 * conservation of chip mem and performance.
-	 *
-	 * I'm sure this scheme could be improved upon!
-	 */
-	for (i = 0; i < QH_END; i++) {
-		ep_queue = &priv->qh_list[i];
-		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
-			enqueue_qtds(hcd, qh);
-	}
-}
-
-#define PTD_STATE_QTD_DONE	1
-#define PTD_STATE_QTD_RELOAD	2
-#define PTD_STATE_URB_RETIRE	3
-
-static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
-								struct urb *urb)
-{
-	__dw dw4;
-	int i;
-
-	dw4 = ptd->dw4;
-	dw4 >>= 8;
-
-	/* FIXME: ISP1761 datasheet does not say what to do with these. Do we
-	   need to handle these errors? Is it done in hardware? */
-
-	if (ptd->dw3 & DW3_HALT_BIT) {
-
-		urb->status = -EPROTO; /* Default unknown error */
-
-		for (i = 0; i < 8; i++) {
-			switch (dw4 & 0x7) {
-			case INT_UNDERRUN:
-				dev_dbg(hcd->self.controller, "%s: underrun "
-						"during uFrame %d\n",
-						__func__, i);
-				urb->status = -ECOMM; /* Could not write data */
-				break;
-			case INT_EXACT:
-				dev_dbg(hcd->self.controller, "%s: transaction "
-						"error during uFrame %d\n",
-						__func__, i);
-				urb->status = -EPROTO; /* timeout, bad CRC, PID
-							  error etc. */
-				break;
-			case INT_BABBLE:
-				dev_dbg(hcd->self.controller, "%s: babble "
-						"error during uFrame %d\n",
-						__func__, i);
-				urb->status = -EOVERFLOW;
-				break;
-			}
-			dw4 >>= 3;
-		}
-
-		return PTD_STATE_URB_RETIRE;
-	}
-
-	return PTD_STATE_QTD_DONE;
-}
-
-static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
-								struct urb *urb)
-{
-	WARN_ON(!ptd);
-	if (ptd->dw3 & DW3_HALT_BIT) {
-		if (ptd->dw3 & DW3_BABBLE_BIT)
-			urb->status = -EOVERFLOW;
-		else if (FROM_DW3_CERR(ptd->dw3))
-			urb->status = -EPIPE;  /* Stall */
-		else if (ptd->dw3 & DW3_ERROR_BIT)
-			urb->status = -EPROTO; /* XactErr */
-		else
-			urb->status = -EPROTO; /* Unknown */
-/*
-		dev_dbg(hcd->self.controller, "%s: ptd error:\n"
-			"        dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
-			"        dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
-			__func__,
-			ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
-			ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
-*/
-		return PTD_STATE_URB_RETIRE;
-	}
-
-	if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
-		/* Transfer Error, *but* active and no HALT -> reload */
-		dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
-		return PTD_STATE_QTD_RELOAD;
-	}
-
-	if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
-		/*
-		 * NAKs are handled in HW by the chip. Usually if the
-		 * device is not able to send data fast enough.
-		 * This happens mostly on slower hardware.
-		 */
-		return PTD_STATE_QTD_RELOAD;
-	}
-
-	return PTD_STATE_QTD_DONE;
-}
-
-static void handle_done_ptds(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	struct ptd ptd;
-	struct isp1760_qh *qh;
-	int slot;
-	int state;
-	struct slotinfo *slots;
-	u32 ptd_offset;
-	struct isp1760_qtd *qtd;
-	int modified;
-	int skip_map;
-
-	skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-	priv->int_done_map &= ~skip_map;
-	skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
-	priv->atl_done_map &= ~skip_map;
-
-	modified = priv->int_done_map || priv->atl_done_map;
-
-	while (priv->int_done_map || priv->atl_done_map) {
-		if (priv->int_done_map) {
-			/* INT ptd */
-			slot = __ffs(priv->int_done_map);
-			priv->int_done_map &= ~(1 << slot);
-			slots = priv->int_slots;
-			/* This should not trigger, and could be removed if
-			   noone have any problems with it triggering: */
-			if (!slots[slot].qh) {
-				WARN_ON(1);
-				continue;
-			}
-			ptd_offset = INT_PTD_OFFSET;
-			ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
-			state = check_int_transfer(hcd, &ptd,
-							slots[slot].qtd->urb);
-		} else {
-			/* ATL ptd */
-			slot = __ffs(priv->atl_done_map);
-			priv->atl_done_map &= ~(1 << slot);
-			slots = priv->atl_slots;
-			/* This should not trigger, and could be removed if
-			   noone have any problems with it triggering: */
-			if (!slots[slot].qh) {
-				WARN_ON(1);
-				continue;
-			}
-			ptd_offset = ATL_PTD_OFFSET;
-			ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
-			state = check_atl_transfer(hcd, &ptd,
-							slots[slot].qtd->urb);
-		}
-
-		qtd = slots[slot].qtd;
-		slots[slot].qtd = NULL;
-		qh = slots[slot].qh;
-		slots[slot].qh = NULL;
-		qh->slot = -1;
-
-		WARN_ON(qtd->status != QTD_XFER_STARTED);
-
-		switch (state) {
-		case PTD_STATE_QTD_DONE:
-			if ((usb_pipeint(qtd->urb->pipe)) &&
-				       (qtd->urb->dev->speed != USB_SPEED_HIGH))
-				qtd->actual_length =
-				       FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
-			else
-				qtd->actual_length =
-					FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
-
-			qtd->status = QTD_XFER_COMPLETE;
-			if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
-							is_short_bulk(qtd))
-				qtd = NULL;
-			else
-				qtd = list_entry(qtd->qtd_list.next,
-							typeof(*qtd), qtd_list);
-
-			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
-			qh->ping = FROM_DW3_PING(ptd.dw3);
-			break;
-
-		case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
-			qtd->status = QTD_PAYLOAD_ALLOC;
-			ptd.dw0 |= DW0_VALID_BIT;
-			/* RL counter = ERR counter */
-			ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
-			ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
-			ptd.dw3 &= ~TO_DW3_CERR(3);
-			ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
-			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
-			qh->ping = FROM_DW3_PING(ptd.dw3);
-			break;
-
-		case PTD_STATE_URB_RETIRE:
-			qtd->status = QTD_RETIRE;
-			if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
-					(qtd->urb->status != -EPIPE) &&
-					(qtd->urb->status != -EREMOTEIO)) {
-				qh->tt_buffer_dirty = 1;
-				if (usb_hub_clear_tt_buffer(qtd->urb))
-					/* Clear failed; let's hope things work
-					   anyway */
-					qh->tt_buffer_dirty = 0;
-			}
-			qtd = NULL;
-			qh->toggle = 0;
-			qh->ping = 0;
-			break;
-
-		default:
-			WARN_ON(1);
-			continue;
-		}
-
-		if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
-			if (slots == priv->int_slots) {
-				if (state == PTD_STATE_QTD_RELOAD)
-					dev_err(hcd->self.controller,
-						"%s: PTD_STATE_QTD_RELOAD on "
-						"interrupt packet\n", __func__);
-				if (state != PTD_STATE_QTD_RELOAD)
-					create_ptd_int(qh, qtd, &ptd);
-			} else {
-				if (state != PTD_STATE_QTD_RELOAD)
-					create_ptd_atl(qh, qtd, &ptd);
-			}
-
-			start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
-				qh, &ptd);
-		}
-	}
-
-	if (modified)
-		schedule_ptds(hcd);
-}
-
-static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	u32 imask;
-	irqreturn_t irqret = IRQ_NONE;
-
-	spin_lock(&priv->lock);
-
-	if (!(hcd->state & HC_STATE_RUNNING))
-		goto leave;
-
-	imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
-	if (unlikely(!imask))
-		goto leave;
-	reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
-
-	priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
-	priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
-
-	handle_done_ptds(hcd);
-
-	irqret = IRQ_HANDLED;
-leave:
-	spin_unlock(&priv->lock);
-
-	return irqret;
-}
-
-/*
- * Workaround for problem described in chip errata 2:
- *
- * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
- * One solution suggested in the errata is to use SOF interrupts _instead_of_
- * ATL done interrupts (the "instead of" might be important since it seems
- * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
- * to set the PTD's done bit in addition to not generating an interrupt!).
- *
- * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
- * done bit is not being set. This is bad - it blocks the endpoint until reboot.
- *
- * If we use SOF interrupts only, we get latency between ptd completion and the
- * actual handling. This is very noticeable in testusb runs which takes several
- * minutes longer without ATL interrupts.
- *
- * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
- * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
- * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
- * completed and its done map bit is set.
- *
- * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
- * not to cause too much lag when this HW bug occurs, while still hopefully
- * ensuring that the check does not falsely trigger.
- */
-#define SLOT_TIMEOUT 300
-#define SLOT_CHECK_PERIOD 200
-static struct timer_list errata2_timer;
-
-static void errata2_function(unsigned long data)
-{
-	struct usb_hcd *hcd = (struct usb_hcd *) data;
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int slot;
-	struct ptd ptd;
-	unsigned long spinflags;
-
-	spin_lock_irqsave(&priv->lock, spinflags);
-
-	for (slot = 0; slot < 32; slot++)
-		if (priv->atl_slots[slot].qh && time_after(jiffies,
-					priv->atl_slots[slot].timestamp +
-					SLOT_TIMEOUT * HZ / 1000)) {
-			ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
-			if (!FROM_DW0_VALID(ptd.dw0) &&
-					!FROM_DW3_ACTIVE(ptd.dw3))
-				priv->atl_done_map |= 1 << slot;
-		}
-
-	if (priv->atl_done_map)
-		handle_done_ptds(hcd);
-
-	spin_unlock_irqrestore(&priv->lock, spinflags);
-
-	errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
-	add_timer(&errata2_timer);
-}
-
-static int isp1760_run(struct usb_hcd *hcd)
-{
-	int retval;
-	u32 temp;
-	u32 command;
-	u32 chipid;
-
-	hcd->uses_new_polling = 1;
-
-	hcd->state = HC_STATE_RUNNING;
-
-	/* Set PTD interrupt AND & OR maps */
-	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
-	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
-	reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
-	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
-	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
-	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
-	/* step 23 passed */
-
-	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
-
-	command = reg_read32(hcd->regs, HC_USBCMD);
-	command &= ~(CMD_LRESET|CMD_RESET);
-	command |= CMD_RUN;
-	reg_write32(hcd->regs, HC_USBCMD, command);
-
-	retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
-	if (retval)
-		return retval;
-
-	/*
-	 * XXX
-	 * Spec says to write FLAG_CF as last config action, priv code grabs
-	 * the semaphore while doing so.
-	 */
-	down_write(&ehci_cf_port_reset_rwsem);
-	reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
-
-	retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
-	up_write(&ehci_cf_port_reset_rwsem);
-	if (retval)
-		return retval;
-
-	init_timer(&errata2_timer);
-	errata2_timer.function = errata2_function;
-	errata2_timer.data = (unsigned long) hcd;
-	errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
-	add_timer(&errata2_timer);
-
-	chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
-	dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
-					chipid & 0xffff, chipid >> 16);
-
-	/* PTD Register Init Part 2, Step 28 */
-
-	/* Setup registers controlling PTD checking */
-	reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
-	reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
-	reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
-	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
-	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
-	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
-	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
-						ATL_BUF_FILL | INT_BUF_FILL);
-
-	/* GRR this is run-once init(), being done every time the HC starts.
-	 * So long as they're part of class devices, we can't do it init()
-	 * since the class device isn't created that early.
-	 */
-	return 0;
-}
-
-static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
-{
-	qtd->data_buffer = databuffer;
-
-	if (len > MAX_PAYLOAD_SIZE)
-		len = MAX_PAYLOAD_SIZE;
-	qtd->length = len;
-
-	return qtd->length;
-}
-
-static void qtd_list_free(struct list_head *qtd_list)
-{
-	struct isp1760_qtd *qtd, *qtd_next;
-
-	list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
-		list_del(&qtd->qtd_list);
-		qtd_free(qtd);
-	}
-}
-
-/*
- * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
- * Also calculate the PID type (SETUP/IN/OUT) for each packet.
- */
-#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
-static void packetize_urb(struct usb_hcd *hcd,
-		struct urb *urb, struct list_head *head, gfp_t flags)
-{
-	struct isp1760_qtd *qtd;
-	void *buf;
-	int len, maxpacketsize;
-	u8 packet_type;
-
-	/*
-	 * URBs map to sequences of QTDs:  one logical transaction
-	 */
-
-	if (!urb->transfer_buffer && urb->transfer_buffer_length) {
-		/* XXX This looks like usb storage / SCSI bug */
-		dev_err(hcd->self.controller,
-				"buf is null, dma is %08lx len is %d\n",
-				(long unsigned)urb->transfer_dma,
-				urb->transfer_buffer_length);
-		WARN_ON(1);
-	}
-
-	if (usb_pipein(urb->pipe))
-		packet_type = IN_PID;
-	else
-		packet_type = OUT_PID;
-
-	if (usb_pipecontrol(urb->pipe)) {
-		qtd = qtd_alloc(flags, urb, SETUP_PID);
-		if (!qtd)
-			goto cleanup;
-		qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
-		list_add_tail(&qtd->qtd_list, head);
-
-		/* for zero length DATA stages, STATUS is always IN */
-		if (urb->transfer_buffer_length == 0)
-			packet_type = IN_PID;
-	}
-
-	maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
-						usb_pipeout(urb->pipe)));
-
-	/*
-	 * buffer gets wrapped in one or more qtds;
-	 * last one may be "short" (including zero len)
-	 * and may serve as a control status ack
-	 */
-	buf = urb->transfer_buffer;
-	len = urb->transfer_buffer_length;
-
-	for (;;) {
-		int this_qtd_len;
-
-		qtd = qtd_alloc(flags, urb, packet_type);
-		if (!qtd)
-			goto cleanup;
-		this_qtd_len = qtd_fill(qtd, buf, len);
-		list_add_tail(&qtd->qtd_list, head);
-
-		len -= this_qtd_len;
-		buf += this_qtd_len;
-
-		if (len <= 0)
-			break;
-	}
-
-	/*
-	 * control requests may need a terminating data "status" ack;
-	 * bulk ones may need a terminating short packet (zero length).
-	 */
-	if (urb->transfer_buffer_length != 0) {
-		int one_more = 0;
-
-		if (usb_pipecontrol(urb->pipe)) {
-			one_more = 1;
-			if (packet_type == IN_PID)
-				packet_type = OUT_PID;
-			else
-				packet_type = IN_PID;
-		} else if (usb_pipebulk(urb->pipe)
-				&& (urb->transfer_flags & URB_ZERO_PACKET)
-				&& !(urb->transfer_buffer_length %
-							maxpacketsize)) {
-			one_more = 1;
-		}
-		if (one_more) {
-			qtd = qtd_alloc(flags, urb, packet_type);
-			if (!qtd)
-				goto cleanup;
-
-			/* never any data in such packets */
-			qtd_fill(qtd, NULL, 0);
-			list_add_tail(&qtd->qtd_list, head);
-		}
-	}
-
-	return;
-
-cleanup:
-	qtd_list_free(head);
-}
-
-static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-		gfp_t mem_flags)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	struct list_head *ep_queue;
-	struct isp1760_qh *qh, *qhit;
-	unsigned long spinflags;
-	LIST_HEAD(new_qtds);
-	int retval;
-	int qh_in_queue;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ep_queue = &priv->qh_list[QH_CONTROL];
-		break;
-	case PIPE_BULK:
-		ep_queue = &priv->qh_list[QH_BULK];
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->interval < 0)
-			return -EINVAL;
-		/* FIXME: Check bandwidth  */
-		ep_queue = &priv->qh_list[QH_INTERRUPT];
-		break;
-	case PIPE_ISOCHRONOUS:
-		dev_err(hcd->self.controller, "%s: isochronous USB packets "
-							"not yet supported\n",
-							__func__);
-		return -EPIPE;
-	default:
-		dev_err(hcd->self.controller, "%s: unknown pipe type\n",
-							__func__);
-		return -EPIPE;
-	}
-
-	if (usb_pipein(urb->pipe))
-		urb->actual_length = 0;
-
-	packetize_urb(hcd, urb, &new_qtds, mem_flags);
-	if (list_empty(&new_qtds))
-		return -ENOMEM;
-
-	retval = 0;
-	spin_lock_irqsave(&priv->lock, spinflags);
-
-	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
-		retval = -ESHUTDOWN;
-		qtd_list_free(&new_qtds);
-		goto out;
-	}
-	retval = usb_hcd_link_urb_to_ep(hcd, urb);
-	if (retval) {
-		qtd_list_free(&new_qtds);
-		goto out;
-	}
-
-	qh = urb->ep->hcpriv;
-	if (qh) {
-		qh_in_queue = 0;
-		list_for_each_entry(qhit, ep_queue, qh_list) {
-			if (qhit == qh) {
-				qh_in_queue = 1;
-				break;
-			}
-		}
-		if (!qh_in_queue)
-			list_add_tail(&qh->qh_list, ep_queue);
-	} else {
-		qh = qh_alloc(GFP_ATOMIC);
-		if (!qh) {
-			retval = -ENOMEM;
-			usb_hcd_unlink_urb_from_ep(hcd, urb);
-			qtd_list_free(&new_qtds);
-			goto out;
-		}
-		list_add_tail(&qh->qh_list, ep_queue);
-		urb->ep->hcpriv = qh;
-	}
-
-	list_splice_tail(&new_qtds, &qh->qtd_list);
-	schedule_ptds(hcd);
-
-out:
-	spin_unlock_irqrestore(&priv->lock, spinflags);
-	return retval;
-}
-
-static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
-		struct isp1760_qh *qh)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int skip_map;
-
-	WARN_ON(qh->slot == -1);
-
-	/* We need to forcefully reclaim the slot since some transfers never
-	   return, e.g. interrupt transfers and NAKed bulk transfers. */
-	if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
-		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
-		skip_map |= (1 << qh->slot);
-		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
-		priv->atl_slots[qh->slot].qh = NULL;
-		priv->atl_slots[qh->slot].qtd = NULL;
-	} else {
-		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
-		skip_map |= (1 << qh->slot);
-		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
-		priv->int_slots[qh->slot].qh = NULL;
-		priv->int_slots[qh->slot].qtd = NULL;
-	}
-
-	qh->slot = -1;
-}
-
-/*
- * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
- * any active transfer belonging to the urb in the process.
- */
-static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
-						struct isp1760_qtd *qtd)
-{
-	struct urb *urb;
-	int urb_was_running;
-
-	urb = qtd->urb;
-	urb_was_running = 0;
-	list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
-		if (qtd->urb != urb)
-			break;
-
-		if (qtd->status >= QTD_XFER_STARTED)
-			urb_was_running = 1;
-		if (last_qtd_of_urb(qtd, qh) &&
-					(qtd->status >= QTD_XFER_COMPLETE))
-			urb_was_running = 0;
-
-		if (qtd->status == QTD_XFER_STARTED)
-			kill_transfer(hcd, urb, qh);
-		qtd->status = QTD_RETIRE;
-	}
-
-	if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
-		qh->tt_buffer_dirty = 1;
-		if (usb_hub_clear_tt_buffer(urb))
-			/* Clear failed; let's hope things work anyway */
-			qh->tt_buffer_dirty = 0;
-	}
-}
-
-static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
-		int status)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	unsigned long spinflags;
-	struct isp1760_qh *qh;
-	struct isp1760_qtd *qtd;
-	int retval = 0;
-
-	spin_lock_irqsave(&priv->lock, spinflags);
-	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
-	if (retval)
-		goto out;
-
-	qh = urb->ep->hcpriv;
-	if (!qh) {
-		retval = -EINVAL;
-		goto out;
-	}
-
-	list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
-		if (qtd->urb == urb) {
-			dequeue_urb_from_qtd(hcd, qh, qtd);
-			list_move(&qtd->qtd_list, &qh->qtd_list);
-			break;
-		}
-
-	urb->status = status;
-	schedule_ptds(hcd);
-
-out:
-	spin_unlock_irqrestore(&priv->lock, spinflags);
-	return retval;
-}
-
-static void isp1760_endpoint_disable(struct usb_hcd *hcd,
-		struct usb_host_endpoint *ep)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	unsigned long spinflags;
-	struct isp1760_qh *qh, *qh_iter;
-	int i;
-
-	spin_lock_irqsave(&priv->lock, spinflags);
-
-	qh = ep->hcpriv;
-	if (!qh)
-		goto out;
-
-	WARN_ON(!list_empty(&qh->qtd_list));
-
-	for (i = 0; i < QH_END; i++)
-		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
-			if (qh_iter == qh) {
-				list_del(&qh_iter->qh_list);
-				i = QH_END;
-				break;
-			}
-	qh_free(qh);
-	ep->hcpriv = NULL;
-
-	schedule_ptds(hcd);
-
-out:
-	spin_unlock_irqrestore(&priv->lock, spinflags);
-}
-
-static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	u32 temp, status = 0;
-	u32 mask;
-	int retval = 1;
-	unsigned long flags;
-
-	/* if !PM, root hub timers won't get shut down ... */
-	if (!HC_IS_RUNNING(hcd->state))
-		return 0;
-
-	/* init status to no-changes */
-	buf[0] = 0;
-	mask = PORT_CSC;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	temp = reg_read32(hcd->regs, HC_PORTSC1);
-
-	if (temp & PORT_OWNER) {
-		if (temp & PORT_CSC) {
-			temp &= ~PORT_CSC;
-			reg_write32(hcd->regs, HC_PORTSC1, temp);
-			goto done;
-		}
-	}
-
-	/*
-	 * Return status information even for ports with OWNER set.
-	 * Otherwise hub_wq wouldn't see the disconnect event when a
-	 * high-speed device is switched over to the companion
-	 * controller by the user.
-	 */
-
-	if ((temp & mask) != 0
-			|| ((temp & PORT_RESUME) != 0
-				&& time_after_eq(jiffies,
-					priv->reset_done))) {
-		buf [0] |= 1 << (0 + 1);
-		status = STS_PCD;
-	}
-	/* FIXME autosuspend idle root hubs */
-done:
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return status ? retval : 0;
-}
-
-static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
-		struct usb_hub_descriptor *desc)
-{
-	int ports = HCS_N_PORTS(priv->hcs_params);
-	u16 temp;
-
-	desc->bDescriptorType = 0x29;
-	/* priv 1.0, 2.3.9 says 20ms max */
-	desc->bPwrOn2PwrGood = 10;
-	desc->bHubContrCurrent = 0;
-
-	desc->bNbrPorts = ports;
-	temp = 1 + (ports / 8);
-	desc->bDescLength = 7 + 2 * temp;
-
-	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
-	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
-	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
-
-	/* per-port overcurrent reporting */
-	temp = 0x0008;
-	if (HCS_PPC(priv->hcs_params))
-		/* per-port power control */
-		temp |= 0x0001;
-	else
-		/* no power switching */
-		temp |= 0x0002;
-	desc->wHubCharacteristics = cpu_to_le16(temp);
-}
-
-#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-
-static int check_reset_complete(struct usb_hcd *hcd, int index,
-		int port_status)
-{
-	if (!(port_status & PORT_CONNECT))
-		return port_status;
-
-	/* if reset finished and it's still not enabled -- handoff */
-	if (!(port_status & PORT_PE)) {
-
-		dev_info(hcd->self.controller,
-					"port %d full speed --> companion\n",
-					index + 1);
-
-		port_status |= PORT_OWNER;
-		port_status &= ~PORT_RWC_BITS;
-		reg_write32(hcd->regs, HC_PORTSC1, port_status);
-
-	} else
-		dev_info(hcd->self.controller, "port %d high speed\n",
-								index + 1);
-
-	return port_status;
-}
-
-static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
-		u16 wValue, u16 wIndex, char *buf, u16 wLength)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	int ports = HCS_N_PORTS(priv->hcs_params);
-	u32 temp, status;
-	unsigned long flags;
-	int retval = 0;
-	unsigned selector;
-
-	/*
-	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
-	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
-	 * (track current state ourselves) ... blink for diagnostics,
-	 * power, "this is the one", etc.  EHCI spec supports this.
-	 */
-
-	spin_lock_irqsave(&priv->lock, flags);
-	switch (typeReq) {
-	case ClearHubFeature:
-		switch (wValue) {
-		case C_HUB_LOCAL_POWER:
-		case C_HUB_OVER_CURRENT:
-			/* no hub-wide feature/status flags */
-			break;
-		default:
-			goto error;
-		}
-		break;
-	case ClearPortFeature:
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		temp = reg_read32(hcd->regs, HC_PORTSC1);
-
-		/*
-		 * Even if OWNER is set, so the port is owned by the
-		 * companion controller, hub_wq needs to be able to clear
-		 * the port-change status bits (especially
-		 * USB_PORT_STAT_C_CONNECTION).
-		 */
-
-		switch (wValue) {
-		case USB_PORT_FEAT_ENABLE:
-			reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
-			break;
-		case USB_PORT_FEAT_C_ENABLE:
-			/* XXX error? */
-			break;
-		case USB_PORT_FEAT_SUSPEND:
-			if (temp & PORT_RESET)
-				goto error;
-
-			if (temp & PORT_SUSPEND) {
-				if ((temp & PORT_PE) == 0)
-					goto error;
-				/* resume signaling for 20 msec */
-				temp &= ~(PORT_RWC_BITS);
-				reg_write32(hcd->regs, HC_PORTSC1,
-							temp | PORT_RESUME);
-				priv->reset_done = jiffies +
-					msecs_to_jiffies(20);
-			}
-			break;
-		case USB_PORT_FEAT_C_SUSPEND:
-			/* we auto-clear this feature */
-			break;
-		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC(priv->hcs_params))
-				reg_write32(hcd->regs, HC_PORTSC1,
-							temp & ~PORT_POWER);
-			break;
-		case USB_PORT_FEAT_C_CONNECTION:
-			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
-			break;
-		case USB_PORT_FEAT_C_OVER_CURRENT:
-			/* XXX error ?*/
-			break;
-		case USB_PORT_FEAT_C_RESET:
-			/* GetPortStatus clears reset */
-			break;
-		default:
-			goto error;
-		}
-		reg_read32(hcd->regs, HC_USBCMD);
-		break;
-	case GetHubDescriptor:
-		isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
-			buf);
-		break;
-	case GetHubStatus:
-		/* no hub-wide feature/status flags */
-		memset(buf, 0, 4);
-		break;
-	case GetPortStatus:
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		status = 0;
-		temp = reg_read32(hcd->regs, HC_PORTSC1);
-
-		/* wPortChange bits */
-		if (temp & PORT_CSC)
-			status |= USB_PORT_STAT_C_CONNECTION << 16;
-
-
-		/* whoever resumes must GetPortStatus to complete it!! */
-		if (temp & PORT_RESUME) {
-			dev_err(hcd->self.controller, "Port resume should be skipped.\n");
-
-			/* Remote Wakeup received? */
-			if (!priv->reset_done) {
-				/* resume signaling for 20 msec */
-				priv->reset_done = jiffies
-						+ msecs_to_jiffies(20);
-				/* check the port again */
-				mod_timer(&hcd->rh_timer, priv->reset_done);
-			}
-
-			/* resume completed? */
-			else if (time_after_eq(jiffies,
-					priv->reset_done)) {
-				status |= USB_PORT_STAT_C_SUSPEND << 16;
-				priv->reset_done = 0;
-
-				/* stop resume signaling */
-				temp = reg_read32(hcd->regs, HC_PORTSC1);
-				reg_write32(hcd->regs, HC_PORTSC1,
-					temp & ~(PORT_RWC_BITS | PORT_RESUME));
-				retval = handshake(hcd, HC_PORTSC1,
-					   PORT_RESUME, 0, 2000 /* 2msec */);
-				if (retval != 0) {
-					dev_err(hcd->self.controller,
-						"port %d resume error %d\n",
-						wIndex + 1, retval);
-					goto error;
-				}
-				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
-			}
-		}
-
-		/* whoever resets must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESET)
-				&& time_after_eq(jiffies,
-					priv->reset_done)) {
-			status |= USB_PORT_STAT_C_RESET << 16;
-			priv->reset_done = 0;
-
-			/* force reset to complete */
-			reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
-			/* REVISIT:  some hardware needs 550+ usec to clear
-			 * this bit; seems too long to spin routinely...
-			 */
-			retval = handshake(hcd, HC_PORTSC1,
-					PORT_RESET, 0, 750);
-			if (retval != 0) {
-				dev_err(hcd->self.controller, "port %d reset error %d\n",
-						wIndex + 1, retval);
-				goto error;
-			}
-
-			/* see what we found out */
-			temp = check_reset_complete(hcd, wIndex,
-					reg_read32(hcd->regs, HC_PORTSC1));
-		}
-		/*
-		 * Even if OWNER is set, there's no harm letting hub_wq
-		 * see the wPortStatus values (they should all be 0 except
-		 * for PORT_POWER anyway).
-		 */
-
-		if (temp & PORT_OWNER)
-			dev_err(hcd->self.controller, "PORT_OWNER is set\n");
-
-		if (temp & PORT_CONNECT) {
-			status |= USB_PORT_STAT_CONNECTION;
-			/* status may be from integrated TT */
-			status |= USB_PORT_STAT_HIGH_SPEED;
-		}
-		if (temp & PORT_PE)
-			status |= USB_PORT_STAT_ENABLE;
-		if (temp & (PORT_SUSPEND|PORT_RESUME))
-			status |= USB_PORT_STAT_SUSPEND;
-		if (temp & PORT_RESET)
-			status |= USB_PORT_STAT_RESET;
-		if (temp & PORT_POWER)
-			status |= USB_PORT_STAT_POWER;
-
-		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
-		break;
-	case SetHubFeature:
-		switch (wValue) {
-		case C_HUB_LOCAL_POWER:
-		case C_HUB_OVER_CURRENT:
-			/* no hub-wide feature/status flags */
-			break;
-		default:
-			goto error;
-		}
-		break;
-	case SetPortFeature:
-		selector = wIndex >> 8;
-		wIndex &= 0xff;
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		temp = reg_read32(hcd->regs, HC_PORTSC1);
-		if (temp & PORT_OWNER)
-			break;
-
-/*		temp &= ~PORT_RWC_BITS; */
-		switch (wValue) {
-		case USB_PORT_FEAT_ENABLE:
-			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
-			break;
-
-		case USB_PORT_FEAT_SUSPEND:
-			if ((temp & PORT_PE) == 0
-					|| (temp & PORT_RESET) != 0)
-				goto error;
-
-			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
-			break;
-		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC(priv->hcs_params))
-				reg_write32(hcd->regs, HC_PORTSC1,
-							temp | PORT_POWER);
-			break;
-		case USB_PORT_FEAT_RESET:
-			if (temp & PORT_RESUME)
-				goto error;
-			/* line status bits may report this as low speed,
-			 * which can be fine if this root hub has a
-			 * transaction translator built in.
-			 */
-			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
-					&& PORT_USB11(temp)) {
-				temp |= PORT_OWNER;
-			} else {
-				temp |= PORT_RESET;
-				temp &= ~PORT_PE;
-
-				/*
-				 * caller must wait, then call GetPortStatus
-				 * usb 2.0 spec says 50 ms resets on root
-				 */
-				priv->reset_done = jiffies +
-					msecs_to_jiffies(50);
-			}
-			reg_write32(hcd->regs, HC_PORTSC1, temp);
-			break;
-		default:
-			goto error;
-		}
-		reg_read32(hcd->regs, HC_USBCMD);
-		break;
-
-	default:
-error:
-		/* "stall" on error */
-		retval = -EPIPE;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return retval;
-}
-
-static int isp1760_get_frame(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	u32 fr;
-
-	fr = reg_read32(hcd->regs, HC_FRINDEX);
-	return (fr >> 3) % priv->periodic_size;
-}
-
-static void isp1760_stop(struct usb_hcd *hcd)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	u32 temp;
-
-	del_timer(&errata2_timer);
-
-	isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,	1,
-			NULL, 0);
-	mdelay(20);
-
-	spin_lock_irq(&priv->lock);
-	ehci_reset(hcd);
-	/* Disable IRQ */
-	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
-	spin_unlock_irq(&priv->lock);
-
-	reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
-}
-
-static void isp1760_shutdown(struct usb_hcd *hcd)
-{
-	u32 command, temp;
-
-	isp1760_stop(hcd);
-	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
-	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
-
-	command = reg_read32(hcd->regs, HC_USBCMD);
-	command &= ~CMD_RUN;
-	reg_write32(hcd->regs, HC_USBCMD, command);
-}
-
-static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
-						struct usb_host_endpoint *ep)
-{
-	struct isp1760_hcd *priv = hcd_to_priv(hcd);
-	struct isp1760_qh *qh = ep->hcpriv;
-	unsigned long spinflags;
-
-	if (!qh)
-		return;
-
-	spin_lock_irqsave(&priv->lock, spinflags);
-	qh->tt_buffer_dirty = 0;
-	schedule_ptds(hcd);
-	spin_unlock_irqrestore(&priv->lock, spinflags);
-}
-
-
-static const struct hc_driver isp1760_hc_driver = {
-	.description		= "isp1760-hcd",
-	.product_desc		= "NXP ISP1760 USB Host Controller",
-	.hcd_priv_size		= sizeof(struct isp1760_hcd),
-	.irq			= isp1760_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
-	.reset			= isp1760_hc_setup,
-	.start			= isp1760_run,
-	.stop			= isp1760_stop,
-	.shutdown		= isp1760_shutdown,
-	.urb_enqueue		= isp1760_urb_enqueue,
-	.urb_dequeue		= isp1760_urb_dequeue,
-	.endpoint_disable	= isp1760_endpoint_disable,
-	.get_frame_number	= isp1760_get_frame,
-	.hub_status_data	= isp1760_hub_status_data,
-	.hub_control		= isp1760_hub_control,
-	.clear_tt_buffer_complete	= isp1760_clear_tt_buffer_complete,
-};
-
-int __init init_kmem_once(void)
-{
-	urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
-			sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
-			SLAB_MEM_SPREAD, NULL);
-
-	if (!urb_listitem_cachep)
-		return -ENOMEM;
-
-	qtd_cachep = kmem_cache_create("isp1760_qtd",
-			sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
-			SLAB_MEM_SPREAD, NULL);
-
-	if (!qtd_cachep)
-		return -ENOMEM;
-
-	qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
-			0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
-
-	if (!qh_cachep) {
-		kmem_cache_destroy(qtd_cachep);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-void deinit_kmem_cache(void)
-{
-	kmem_cache_destroy(qtd_cachep);
-	kmem_cache_destroy(qh_cachep);
-	kmem_cache_destroy(urb_listitem_cachep);
-}
-
-struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
-				 int irq, unsigned long irqflags,
-				 int rst_gpio,
-				 struct device *dev, const char *busname,
-				 unsigned int devflags)
-{
-	struct usb_hcd *hcd;
-	struct isp1760_hcd *priv;
-	int ret;
-
-	if (usb_disabled())
-		return ERR_PTR(-ENODEV);
-
-	/* prevent usb-core allocating DMA pages */
-	dev->dma_mask = NULL;
-
-	hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
-	if (!hcd)
-		return ERR_PTR(-ENOMEM);
-
-	priv = hcd_to_priv(hcd);
-	priv->devflags = devflags;
-	priv->rst_gpio = rst_gpio;
-	init_memory(priv);
-	hcd->regs = ioremap(res_start, res_len);
-	if (!hcd->regs) {
-		ret = -EIO;
-		goto err_put;
-	}
-
-	hcd->irq = irq;
-	hcd->rsrc_start = res_start;
-	hcd->rsrc_len = res_len;
-
-	ret = usb_add_hcd(hcd, irq, irqflags);
-	if (ret)
-		goto err_unmap;
-	device_wakeup_enable(hcd->self.controller);
-
-	return hcd;
-
-err_unmap:
-	 iounmap(hcd->regs);
-
-err_put:
-	 usb_put_hcd(hcd);
-
-	 return ERR_PTR(ret);
-}
-
-MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
-MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
deleted file mode 100644
index 33dc79c..0000000
--- a/drivers/usb/host/isp1760-hcd.h
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef _ISP1760_HCD_H_
-#define _ISP1760_HCD_H_
-
-/* exports for if */
-struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
-				 int irq, unsigned long irqflags,
-				 int rst_gpio,
-				 struct device *dev, const char *busname,
-				 unsigned int devflags);
-int init_kmem_once(void);
-void deinit_kmem_cache(void);
-
-/* EHCI capability registers */
-#define HC_CAPLENGTH		0x00
-#define HC_HCSPARAMS		0x04
-#define HC_HCCPARAMS		0x08
-
-/* EHCI operational registers */
-#define HC_USBCMD		0x20
-#define HC_USBSTS		0x24
-#define HC_FRINDEX		0x2c
-#define HC_CONFIGFLAG		0x60
-#define HC_PORTSC1		0x64
-#define HC_ISO_PTD_DONEMAP_REG	0x130
-#define HC_ISO_PTD_SKIPMAP_REG	0x134
-#define HC_ISO_PTD_LASTPTD_REG	0x138
-#define HC_INT_PTD_DONEMAP_REG	0x140
-#define HC_INT_PTD_SKIPMAP_REG	0x144
-#define HC_INT_PTD_LASTPTD_REG	0x148
-#define HC_ATL_PTD_DONEMAP_REG	0x150
-#define HC_ATL_PTD_SKIPMAP_REG	0x154
-#define HC_ATL_PTD_LASTPTD_REG	0x158
-
-/* Configuration Register */
-#define HC_HW_MODE_CTRL		0x300
-#define ALL_ATX_RESET		(1 << 31)
-#define HW_ANA_DIGI_OC		(1 << 15)
-#define HW_DATA_BUS_32BIT	(1 << 8)
-#define HW_DACK_POL_HIGH	(1 << 6)
-#define HW_DREQ_POL_HIGH	(1 << 5)
-#define HW_INTR_HIGH_ACT	(1 << 2)
-#define HW_INTR_EDGE_TRIG	(1 << 1)
-#define HW_GLOBAL_INTR_EN	(1 << 0)
-
-#define HC_CHIP_ID_REG		0x304
-#define HC_SCRATCH_REG		0x308
-
-#define HC_RESET_REG		0x30c
-#define SW_RESET_RESET_HC	(1 << 1)
-#define SW_RESET_RESET_ALL	(1 << 0)
-
-#define HC_BUFFER_STATUS_REG	0x334
-#define ISO_BUF_FILL		(1 << 2)
-#define INT_BUF_FILL		(1 << 1)
-#define ATL_BUF_FILL		(1 << 0)
-
-#define HC_MEMORY_REG		0x33c
-#define ISP_BANK(x)		((x) << 16)
-
-#define HC_PORT1_CTRL		0x374
-#define PORT1_POWER		(3 << 3)
-#define PORT1_INIT1		(1 << 7)
-#define PORT1_INIT2		(1 << 23)
-#define HW_OTG_CTRL_SET		0x374
-#define HW_OTG_CTRL_CLR		0x376
-
-/* Interrupt Register */
-#define HC_INTERRUPT_REG	0x310
-
-#define HC_INTERRUPT_ENABLE	0x314
-#define HC_ISO_INT		(1 << 9)
-#define HC_ATL_INT		(1 << 8)
-#define HC_INTL_INT		(1 << 7)
-#define HC_EOT_INT		(1 << 3)
-#define HC_SOT_INT		(1 << 1)
-#define INTERRUPT_ENABLE_MASK	(HC_INTL_INT | HC_ATL_INT)
-
-#define HC_ISO_IRQ_MASK_OR_REG	0x318
-#define HC_INT_IRQ_MASK_OR_REG	0x31C
-#define HC_ATL_IRQ_MASK_OR_REG	0x320
-#define HC_ISO_IRQ_MASK_AND_REG	0x324
-#define HC_INT_IRQ_MASK_AND_REG	0x328
-#define HC_ATL_IRQ_MASK_AND_REG	0x32C
-
-/* urb state*/
-#define DELETE_URB		(0x0008)
-#define NO_TRANSFER_ACTIVE	(0xffffffff)
-
-/* Philips Proprietary Transfer Descriptor (PTD) */
-typedef __u32 __bitwise __dw;
-struct ptd {
-	__dw dw0;
-	__dw dw1;
-	__dw dw2;
-	__dw dw3;
-	__dw dw4;
-	__dw dw5;
-	__dw dw6;
-	__dw dw7;
-};
-#define PTD_OFFSET		0x0400
-#define ISO_PTD_OFFSET		0x0400
-#define INT_PTD_OFFSET		0x0800
-#define ATL_PTD_OFFSET		0x0c00
-#define PAYLOAD_OFFSET		0x1000
-
-struct slotinfo {
-	struct isp1760_qh *qh;
-	struct isp1760_qtd *qtd;
-	unsigned long timestamp;
-};
-
-
-typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
-		struct isp1760_qtd *qtd);
-
-/*
- * Device flags that can vary from board to board.  All of these
- * indicate the most "atypical" case, so that a devflags of 0 is
- * a sane default configuration.
- */
-#define ISP1760_FLAG_BUS_WIDTH_16	0x00000002 /* 16-bit data bus width */
-#define ISP1760_FLAG_OTG_EN		0x00000004 /* Port 1 supports OTG */
-#define ISP1760_FLAG_ANALOG_OC		0x00000008 /* Analog overcurrent */
-#define ISP1760_FLAG_DACK_POL_HIGH	0x00000010 /* DACK active high */
-#define ISP1760_FLAG_DREQ_POL_HIGH	0x00000020 /* DREQ active high */
-#define ISP1760_FLAG_ISP1761		0x00000040 /* Chip is ISP1761 */
-#define ISP1760_FLAG_INTR_POL_HIGH	0x00000080 /* Interrupt polarity active high */
-#define ISP1760_FLAG_INTR_EDGE_TRIG	0x00000100 /* Interrupt edge triggered */
-#define ISP1760_FLAG_RESET_ACTIVE_HIGH	0x80000000 /* RESET GPIO active high */
-
-/* chip memory management */
-struct memory_chunk {
-	unsigned int start;
-	unsigned int size;
-	unsigned int free;
-};
-
-/*
- * 60kb divided in:
- * - 32 blocks @ 256  bytes
- * - 20 blocks @ 1024 bytes
- * -  4 blocks @ 8192 bytes
- */
-
-#define BLOCK_1_NUM 32
-#define BLOCK_2_NUM 20
-#define BLOCK_3_NUM 4
-
-#define BLOCK_1_SIZE 256
-#define BLOCK_2_SIZE 1024
-#define BLOCK_3_SIZE 8192
-#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
-#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
-#define PAYLOAD_AREA_SIZE 0xf000
-
-/* ATL */
-/* DW0 */
-#define DW0_VALID_BIT			1
-#define FROM_DW0_VALID(x)		((x) & 0x01)
-#define TO_DW0_LENGTH(x)		(((u32) x) << 3)
-#define TO_DW0_MAXPACKET(x)		(((u32) x) << 18)
-#define TO_DW0_MULTI(x)			(((u32) x) << 29)
-#define TO_DW0_ENDPOINT(x)		(((u32)	x) << 31)
-/* DW1 */
-#define TO_DW1_DEVICE_ADDR(x)		(((u32) x) << 3)
-#define TO_DW1_PID_TOKEN(x)		(((u32) x) << 10)
-#define DW1_TRANS_BULK			((u32) 2 << 12)
-#define DW1_TRANS_INT			((u32) 3 << 12)
-#define DW1_TRANS_SPLIT			((u32) 1 << 14)
-#define DW1_SE_USB_LOSPEED		((u32) 2 << 16)
-#define TO_DW1_PORT_NUM(x)		(((u32) x) << 18)
-#define TO_DW1_HUB_NUM(x)		(((u32) x) << 25)
-/* DW2 */
-#define TO_DW2_DATA_START_ADDR(x)	(((u32) x) << 8)
-#define TO_DW2_RL(x)			((x) << 25)
-#define FROM_DW2_RL(x)			(((x) >> 25) & 0xf)
-/* DW3 */
-#define FROM_DW3_NRBYTESTRANSFERRED(x)		((x) & 0x7fff)
-#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x)	((x) & 0x07ff)
-#define TO_DW3_NAKCOUNT(x)		((x) << 19)
-#define FROM_DW3_NAKCOUNT(x)		(((x) >> 19) & 0xf)
-#define TO_DW3_CERR(x)			((x) << 23)
-#define FROM_DW3_CERR(x)		(((x) >> 23) & 0x3)
-#define TO_DW3_DATA_TOGGLE(x)		((x) << 25)
-#define FROM_DW3_DATA_TOGGLE(x)		(((x) >> 25) & 0x1)
-#define TO_DW3_PING(x)			((x) << 26)
-#define FROM_DW3_PING(x)		(((x) >> 26) & 0x1)
-#define DW3_ERROR_BIT			(1 << 28)
-#define DW3_BABBLE_BIT			(1 << 29)
-#define DW3_HALT_BIT			(1 << 30)
-#define DW3_ACTIVE_BIT			(1 << 31)
-#define FROM_DW3_ACTIVE(x)		(((x) >> 31) & 0x01)
-
-#define INT_UNDERRUN			(1 << 2)
-#define INT_BABBLE			(1 << 1)
-#define INT_EXACT			(1 << 0)
-
-#define SETUP_PID	(2)
-#define IN_PID		(1)
-#define OUT_PID		(0)
-
-/* Errata 1 */
-#define RL_COUNTER	(0)
-#define NAK_COUNTER	(0)
-#define ERR_COUNTER	(2)
-
-#endif /* _ISP1760_HCD_H_ */
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
deleted file mode 100644
index 09254a4..0000000
--- a/drivers/usb/host/isp1760-if.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Glue code for the ISP1760 driver and bus
- * Currently there is support for
- * - OpenFirmware
- * - PCI
- * - PDEV (generic platform device centralized driver model)
- *
- * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
- *
- */
-
-#include <linux/usb.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/isp1760.h>
-#include <linux/usb/hcd.h>
-
-#include "isp1760-hcd.h"
-
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
-#endif
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-struct isp1760 {
-	struct usb_hcd *hcd;
-	int rst_gpio;
-};
-
-static int of_isp1760_probe(struct platform_device *dev)
-{
-	struct isp1760 *drvdata;
-	struct device_node *dp = dev->dev.of_node;
-	struct resource *res;
-	struct resource memory;
-	int virq;
-	resource_size_t res_len;
-	int ret;
-	unsigned int devflags = 0;
-	enum of_gpio_flags gpio_flags;
-	u32 bus_width = 0;
-
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata)
-		return -ENOMEM;
-
-	ret = of_address_to_resource(dp, 0, &memory);
-	if (ret) {
-		ret = -ENXIO;
-		goto free_data;
-	}
-
-	res_len = resource_size(&memory);
-
-	res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
-	if (!res) {
-		ret = -EBUSY;
-		goto free_data;
-	}
-
-	virq = irq_of_parse_and_map(dp, 0);
-	if (!virq) {
-		ret = -ENODEV;
-		goto release_reg;
-	}
-
-	if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
-		devflags |= ISP1760_FLAG_ISP1761;
-
-	/* Some systems wire up only 16 of the 32 data lines */
-	of_property_read_u32(dp, "bus-width", &bus_width);
-	if (bus_width == 16)
-		devflags |= ISP1760_FLAG_BUS_WIDTH_16;
-
-	if (of_get_property(dp, "port1-otg", NULL) != NULL)
-		devflags |= ISP1760_FLAG_OTG_EN;
-
-	if (of_get_property(dp, "analog-oc", NULL) != NULL)
-		devflags |= ISP1760_FLAG_ANALOG_OC;
-
-	if (of_get_property(dp, "dack-polarity", NULL) != NULL)
-		devflags |= ISP1760_FLAG_DACK_POL_HIGH;
-
-	if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
-		devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
-
-	drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
-	if (gpio_is_valid(drvdata->rst_gpio)) {
-		ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
-		if (!ret) {
-			if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
-				devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
-				gpio_direction_output(drvdata->rst_gpio, 0);
-			} else {
-				gpio_direction_output(drvdata->rst_gpio, 1);
-			}
-		} else {
-			drvdata->rst_gpio = ret;
-		}
-	}
-
-	drvdata->hcd = isp1760_register(memory.start, res_len, virq,
-					IRQF_SHARED, drvdata->rst_gpio,
-					&dev->dev, dev_name(&dev->dev),
-					devflags);
-	if (IS_ERR(drvdata->hcd)) {
-		ret = PTR_ERR(drvdata->hcd);
-		goto free_gpio;
-	}
-
-	platform_set_drvdata(dev, drvdata);
-	return ret;
-
-free_gpio:
-	if (gpio_is_valid(drvdata->rst_gpio))
-		gpio_free(drvdata->rst_gpio);
-release_reg:
-	release_mem_region(memory.start, res_len);
-free_data:
-	kfree(drvdata);
-	return ret;
-}
-
-static int of_isp1760_remove(struct platform_device *dev)
-{
-	struct isp1760 *drvdata = platform_get_drvdata(dev);
-
-	usb_remove_hcd(drvdata->hcd);
-	iounmap(drvdata->hcd->regs);
-	release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
-	usb_put_hcd(drvdata->hcd);
-
-	if (gpio_is_valid(drvdata->rst_gpio))
-		gpio_free(drvdata->rst_gpio);
-
-	kfree(drvdata);
-	return 0;
-}
-
-static const struct of_device_id of_isp1760_match[] = {
-	{
-		.compatible = "nxp,usb-isp1760",
-	},
-	{
-		.compatible = "nxp,usb-isp1761",
-	},
-	{ },
-};
-MODULE_DEVICE_TABLE(of, of_isp1760_match);
-
-static struct platform_driver isp1760_of_driver = {
-	.driver = {
-		.name = "nxp-isp1760",
-		.of_match_table = of_isp1760_match,
-	},
-	.probe          = of_isp1760_probe,
-	.remove         = of_isp1760_remove,
-};
-#endif
-
-#ifdef CONFIG_PCI
-static int isp1761_pci_probe(struct pci_dev *dev,
-		const struct pci_device_id *id)
-{
-	u8 latency, limit;
-	__u32 reg_data;
-	int retry_count;
-	struct usb_hcd *hcd;
-	unsigned int devflags = 0;
-	int ret_status = 0;
-
-	resource_size_t pci_mem_phy0;
-	resource_size_t memlength;
-
-	u8 __iomem *chip_addr;
-	u8 __iomem *iobase;
-	resource_size_t nxp_pci_io_base;
-	resource_size_t iolength;
-
-	if (usb_disabled())
-		return -ENODEV;
-
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
-
-	if (!dev->irq)
-		return -ENODEV;
-
-	/* Grab the PLX PCI mem maped port start address we need  */
-	nxp_pci_io_base = pci_resource_start(dev, 0);
-	iolength = pci_resource_len(dev, 0);
-
-	if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
-		printk(KERN_ERR "request region #1\n");
-		return -EBUSY;
-	}
-
-	iobase = ioremap_nocache(nxp_pci_io_base, iolength);
-	if (!iobase) {
-		printk(KERN_ERR "ioremap #1\n");
-		ret_status = -ENOMEM;
-		goto cleanup1;
-	}
-	/* Grab the PLX PCI shared memory of the ISP 1761 we need  */
-	pci_mem_phy0 = pci_resource_start(dev, 3);
-	memlength = pci_resource_len(dev, 3);
-	if (memlength < 0xffff) {
-		printk(KERN_ERR "memory length for this resource is wrong\n");
-		ret_status = -ENOMEM;
-		goto cleanup2;
-	}
-
-	if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
-		printk(KERN_ERR "host controller already in use\n");
-		ret_status = -EBUSY;
-		goto cleanup2;
-	}
-
-	/* map available memory */
-	chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
-	if (!chip_addr) {
-		printk(KERN_ERR "Error ioremap failed\n");
-		ret_status = -ENOMEM;
-		goto cleanup3;
-	}
-
-	/* bad pci latencies can contribute to overruns */
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
-	if (latency) {
-		pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
-		if (limit && limit < latency)
-			pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
-	}
-
-	/* Try to check whether we can access Scratch Register of
-	 * Host Controller or not. The initial PCI access is retried until
-	 * local init for the PCI bridge is completed
-	 */
-	retry_count = 20;
-	reg_data = 0;
-	while ((reg_data != 0xFACE) && retry_count) {
-		/*by default host is in 16bit mode, so
-		 * io operations at this stage must be 16 bit
-		 * */
-		writel(0xface, chip_addr + HC_SCRATCH_REG);
-		udelay(100);
-		reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
-		retry_count--;
-	}
-
-	iounmap(chip_addr);
-
-	/* Host Controller presence is detected by writing to scratch register
-	 * and reading back and checking the contents are same or not
-	 */
-	if (reg_data != 0xFACE) {
-		dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
-		ret_status = -ENOMEM;
-		goto cleanup3;
-	}
-
-	pci_set_master(dev);
-
-	/* configure PLX PCI chip to pass interrupts */
-#define PLX_INT_CSR_REG 0x68
-	reg_data = readl(iobase + PLX_INT_CSR_REG);
-	reg_data |= 0x900;
-	writel(reg_data, iobase + PLX_INT_CSR_REG);
-
-	dev->dev.dma_mask = NULL;
-	hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
-		IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
-		devflags);
-	if (IS_ERR(hcd)) {
-		ret_status = -ENODEV;
-		goto cleanup3;
-	}
-
-	/* done with PLX IO access */
-	iounmap(iobase);
-	release_mem_region(nxp_pci_io_base, iolength);
-
-	pci_set_drvdata(dev, hcd);
-	return 0;
-
-cleanup3:
-	release_mem_region(pci_mem_phy0, memlength);
-cleanup2:
-	iounmap(iobase);
-cleanup1:
-	release_mem_region(nxp_pci_io_base, iolength);
-	return ret_status;
-}
-
-static void isp1761_pci_remove(struct pci_dev *dev)
-{
-	struct usb_hcd *hcd;
-
-	hcd = pci_get_drvdata(dev);
-
-	usb_remove_hcd(hcd);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-
-	pci_disable_device(dev);
-}
-
-static void isp1761_pci_shutdown(struct pci_dev *dev)
-{
-	printk(KERN_ERR "ips1761_pci_shutdown\n");
-}
-
-static const struct pci_device_id isp1760_plx [] = {
-	{
-		.class          = PCI_CLASS_BRIDGE_OTHER << 8,
-		.class_mask     = ~0,
-		.vendor		= PCI_VENDOR_ID_PLX,
-		.device		= 0x5406,
-		.subvendor	= PCI_VENDOR_ID_PLX,
-		.subdevice	= 0x9054,
-	},
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, isp1760_plx);
-
-static struct pci_driver isp1761_pci_driver = {
-	.name =         "isp1760",
-	.id_table =     isp1760_plx,
-	.probe =        isp1761_pci_probe,
-	.remove =       isp1761_pci_remove,
-	.shutdown =     isp1761_pci_shutdown,
-};
-#endif
-
-static int isp1760_plat_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct usb_hcd *hcd;
-	struct resource *mem_res;
-	struct resource *irq_res;
-	resource_size_t mem_size;
-	struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
-	unsigned int devflags = 0;
-	unsigned long irqflags = IRQF_SHARED;
-
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		pr_warning("isp1760: Memory resource not available\n");
-		ret = -ENODEV;
-		goto out;
-	}
-	mem_size = resource_size(mem_res);
-	if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
-		pr_warning("isp1760: Cannot reserve the memory resource\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!irq_res) {
-		pr_warning("isp1760: IRQ resource not available\n");
-		ret = -ENODEV;
-		goto cleanup;
-	}
-
-	irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
-
-	if (priv) {
-		if (priv->is_isp1761)
-			devflags |= ISP1760_FLAG_ISP1761;
-		if (priv->bus_width_16)
-			devflags |= ISP1760_FLAG_BUS_WIDTH_16;
-		if (priv->port1_otg)
-			devflags |= ISP1760_FLAG_OTG_EN;
-		if (priv->analog_oc)
-			devflags |= ISP1760_FLAG_ANALOG_OC;
-		if (priv->dack_polarity_high)
-			devflags |= ISP1760_FLAG_DACK_POL_HIGH;
-		if (priv->dreq_polarity_high)
-			devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
-	}
-
-	hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
-			       irqflags, -ENOENT,
-			       &pdev->dev, dev_name(&pdev->dev), devflags);
-
-	platform_set_drvdata(pdev, hcd);
-
-	if (IS_ERR(hcd)) {
-		pr_warning("isp1760: Failed to register the HCD device\n");
-		ret = -ENODEV;
-		goto cleanup;
-	}
-
-	pr_info("ISP1760 USB device initialised\n");
-	return ret;
-
-cleanup:
-	release_mem_region(mem_res->start, mem_size);
-out:
-	return ret;
-}
-
-static int isp1760_plat_remove(struct platform_device *pdev)
-{
-	struct resource *mem_res;
-	resource_size_t mem_size;
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	usb_remove_hcd(hcd);
-
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	mem_size = resource_size(mem_res);
-	release_mem_region(mem_res->start, mem_size);
-
-	usb_put_hcd(hcd);
-
-	return 0;
-}
-
-static struct platform_driver isp1760_plat_driver = {
-	.probe	= isp1760_plat_probe,
-	.remove	= isp1760_plat_remove,
-	.driver	= {
-		.name	= "isp1760",
-	},
-};
-
-static int __init isp1760_init(void)
-{
-	int ret, any_ret = -ENODEV;
-
-	init_kmem_once();
-
-	ret = platform_driver_register(&isp1760_plat_driver);
-	if (!ret)
-		any_ret = 0;
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-	ret = platform_driver_register(&isp1760_of_driver);
-	if (!ret)
-		any_ret = 0;
-#endif
-#ifdef CONFIG_PCI
-	ret = pci_register_driver(&isp1761_pci_driver);
-	if (!ret)
-		any_ret = 0;
-#endif
-
-	if (any_ret)
-		deinit_kmem_cache();
-	return any_ret;
-}
-module_init(isp1760_init);
-
-static void __exit isp1760_exit(void)
-{
-	platform_driver_unregister(&isp1760_plat_driver);
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-	platform_driver_unregister(&isp1760_of_driver);
-#endif
-#ifdef CONFIG_PCI
-	pci_unregister_driver(&isp1761_pci_driver);
-#endif
-	deinit_kmem_cache();
-}
-module_exit(isp1760_exit);
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 6234c75..a98833c 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -55,6 +55,7 @@
  * single thread (max3421_spi_thread).
  */
 
+#include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/usb.h>
@@ -1291,7 +1292,7 @@
 		char sbuf[16 * 16], *dp, *end;
 		int i;
 
-		if (jiffies - last_time > 5*HZ) {
+		if (time_after(jiffies, last_time + 5*HZ)) {
 			dp = sbuf;
 			end = sbuf + sizeof(sbuf);
 			*dp = '\0';
@@ -1660,7 +1661,8 @@
 	 */
 	desc->bDescriptorType = 0x29;	/* hub descriptor */
 	desc->bDescLength = 9;
-	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->wHubCharacteristics = cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM |
+						HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = 1;
 }
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e6..7cce85a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,17 @@
 		for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
 
 /* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+	((struct ohci_at91_priv *)hcd_to_ohci(h)->priv)
+
+struct ohci_at91_priv {
+	struct clk *iclk;
+	struct clk *fclk;
+	struct clk *uclk;
+	struct clk *hclk;
+	bool clocked;
+	bool wakeup;		/* Saved wake-up state for resume */
+};
 /* interface and function clocks; sometimes also an AHB clock */
 
 #define DRIVER_DESC "OHCI Atmel driver"
@@ -41,45 +51,53 @@
 static const char hcd_name[] = "ohci-atmel";
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = {
+	.extra_priv_size = sizeof(struct ohci_at91_priv),
+};
 
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
+	if (ohci_at91->clocked)
+		return;
 	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-		clk_set_rate(uclk, 48000000);
-		clk_prepare_enable(uclk);
+		clk_set_rate(ohci_at91->uclk, 48000000);
+		clk_prepare_enable(ohci_at91->uclk);
 	}
-	clk_prepare_enable(hclk);
-	clk_prepare_enable(iclk);
-	clk_prepare_enable(fclk);
-	clocked = 1;
+	clk_prepare_enable(ohci_at91->hclk);
+	clk_prepare_enable(ohci_at91->iclk);
+	clk_prepare_enable(ohci_at91->fclk);
+	ohci_at91->clocked = true;
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-	clk_disable_unprepare(fclk);
-	clk_disable_unprepare(iclk);
-	clk_disable_unprepare(hclk);
+	if (!ohci_at91->clocked)
+		return;
+	clk_disable_unprepare(ohci_at91->fclk);
+	clk_disable_unprepare(ohci_at91->iclk);
+	clk_disable_unprepare(ohci_at91->hclk);
 	if (IS_ENABLED(CONFIG_COMMON_CLK))
-		clk_disable_unprepare(uclk);
-	clocked = 0;
+		clk_disable_unprepare(ohci_at91->uclk);
+	ohci_at91->clocked = false;
 }
 
 static void at91_start_hc(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct ohci_regs __iomem *regs = hcd->regs;
+	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
 	dev_dbg(&pdev->dev, "start\n");
 
 	/*
 	 * Start the USB clocks.
 	 */
-	at91_start_clock();
+	at91_start_clock(ohci_at91);
 
 	/*
 	 * The USB host controller must remain in reset.
@@ -91,6 +109,7 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct ohci_regs __iomem *regs = hcd->regs;
+	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
 	dev_dbg(&pdev->dev, "stop\n");
 
@@ -102,7 +121,7 @@
 	/*
 	 * Stop the USB clocks.
 	 */
-	at91_stop_clock();
+	at91_stop_clock(ohci_at91);
 }
 
 
@@ -128,7 +147,8 @@
 	struct at91_usbh_data *board;
 	struct ohci_hcd *ohci;
 	int retval;
-	struct usb_hcd *hcd = NULL;
+	struct usb_hcd *hcd;
+	struct ohci_at91_priv *ohci_at91;
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	int irq;
@@ -142,6 +162,7 @@
 	hcd = usb_create_hcd(driver, dev, "at91");
 	if (!hcd)
 		return -ENOMEM;
+	ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	hcd->regs = devm_ioremap_resource(dev, res);
@@ -152,29 +173,29 @@
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_len = resource_size(res);
 
-	iclk = devm_clk_get(dev, "ohci_clk");
-	if (IS_ERR(iclk)) {
+	ohci_at91->iclk = devm_clk_get(dev, "ohci_clk");
+	if (IS_ERR(ohci_at91->iclk)) {
 		dev_err(dev, "failed to get ohci_clk\n");
-		retval = PTR_ERR(iclk);
+		retval = PTR_ERR(ohci_at91->iclk);
 		goto err;
 	}
-	fclk = devm_clk_get(dev, "uhpck");
-	if (IS_ERR(fclk)) {
+	ohci_at91->fclk = devm_clk_get(dev, "uhpck");
+	if (IS_ERR(ohci_at91->fclk)) {
 		dev_err(dev, "failed to get uhpck\n");
-		retval = PTR_ERR(fclk);
+		retval = PTR_ERR(ohci_at91->fclk);
 		goto err;
 	}
-	hclk = devm_clk_get(dev, "hclk");
-	if (IS_ERR(hclk)) {
+	ohci_at91->hclk = devm_clk_get(dev, "hclk");
+	if (IS_ERR(ohci_at91->hclk)) {
 		dev_err(dev, "failed to get hclk\n");
-		retval = PTR_ERR(hclk);
+		retval = PTR_ERR(ohci_at91->hclk);
 		goto err;
 	}
 	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
-		uclk = devm_clk_get(dev, "usb_clk");
-		if (IS_ERR(uclk)) {
+		ohci_at91->uclk = devm_clk_get(dev, "usb_clk");
+		if (IS_ERR(ohci_at91->uclk)) {
 			dev_err(dev, "failed to get uclk\n");
-			retval = PTR_ERR(uclk);
+			retval = PTR_ERR(ohci_at91->uclk);
 			goto err;
 		}
 	}
@@ -347,11 +368,13 @@
 		 */
 
 		desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
-		desc->wHubCharacteristics |= cpu_to_le16(0x0001);
+		desc->wHubCharacteristics |=
+			cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM);
 
 		if (pdata->overcurrent_supported) {
 			desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
-			desc->wHubCharacteristics |=  cpu_to_le16(0x0008|0x0001);
+			desc->wHubCharacteristics |=
+				cpu_to_le16(HUB_CHAR_INDV_PORT_OCPM);
 		}
 
 		dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
@@ -593,19 +616,27 @@
 #ifdef CONFIG_PM
 
 static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
 {
-	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
 	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
-	bool		do_wakeup = device_may_wakeup(&pdev->dev);
+	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 	int		ret;
 
-	if (do_wakeup)
+	/*
+	 * Disable wakeup if we are going to sleep with slow clock mode
+	 * enabled.
+	 */
+	ohci_at91->wakeup = device_may_wakeup(dev)
+			&& !at91_suspend_entering_slow_clock();
+
+	if (ohci_at91->wakeup)
 		enable_irq_wake(hcd->irq);
 
-	ret = ohci_suspend(hcd, do_wakeup);
+	ret = ohci_suspend(hcd, ohci_at91->wakeup);
 	if (ret) {
-		disable_irq_wake(hcd->irq);
+		if (ohci_at91->wakeup)
+			disable_irq_wake(hcd->irq);
 		return ret;
 	}
 	/*
@@ -615,7 +646,7 @@
 	 *
 	 * REVISIT: some boards will be able to turn VBUS off...
 	 */
-	if (at91_suspend_entering_slow_clock()) {
+	if (!ohci_at91->wakeup) {
 		ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
 		ohci->hc_control &= OHCI_CTRL_RWC;
 		ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
@@ -623,38 +654,37 @@
 
 		/* flush the writes */
 		(void) ohci_readl (ohci, &ohci->regs->control);
-		at91_stop_clock();
+		at91_stop_clock(ohci_at91);
 	}
 
 	return ret;
 }
 
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
 {
-	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
 
-	if (device_may_wakeup(&pdev->dev))
+	if (ohci_at91->wakeup)
 		disable_irq_wake(hcd->irq);
 
-	if (!clocked)
-		at91_start_clock();
+	at91_start_clock(ohci_at91);
 
 	ohci_resume(hcd, false);
 	return 0;
 }
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+					ohci_hcd_at91_drv_resume);
+
 static struct platform_driver ohci_hcd_at91_driver = {
 	.probe		= ohci_hcd_at91_drv_probe,
 	.remove		= ohci_hcd_at91_drv_remove,
 	.shutdown	= usb_hcd_platform_shutdown,
-	.suspend	= ohci_hcd_at91_drv_suspend,
-	.resume		= ohci_hcd_at91_drv_resume,
 	.driver		= {
 		.name	= "at91_ohci",
+		.pm	= &ohci_hcd_at91_pm_ops,
 		.of_match_table	= of_match_ptr(at91_ohci_dt_ids),
 	},
 };
@@ -665,7 +695,7 @@
 		return -ENODEV;
 
 	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-	ohci_init_driver(&ohci_at91_hc_driver, NULL);
+	ohci_init_driver(&ohci_at91_hc_driver, &ohci_at91_drv_overrides);
 
 	/*
 	 * The Atmel HW has some unusual quirks, which require Atmel-specific
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 1c76999..e5c33bc 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -431,7 +431,6 @@
 	.resume		= ohci_da8xx_resume,
 #endif
 	.driver		= {
-		.owner	= THIS_MODULE,
 		.name	= "ohci",
 	},
 };
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 0aa17c9..fe2aedd 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -544,15 +544,15 @@
 	temp = 1 + (ohci->num_ports / 8);
 	desc->bDescLength = 7 + 2 * temp;
 
-	temp = 0;
+	temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
 	if (rh & RH_A_NPS)		/* no power switching? */
-	    temp |= 0x0002;
+		temp |= HUB_CHAR_NO_LPSM;
 	if (rh & RH_A_PSM)		/* per-port power switching? */
-	    temp |= 0x0001;
+		temp |= HUB_CHAR_INDV_PORT_LPSM;
 	if (rh & RH_A_NOCP)		/* no overcurrent reporting? */
-	    temp |= 0x0010;
+		temp |= HUB_CHAR_NO_OCPM;
 	else if (rh & RH_A_OCPM)	/* per-port overcurrent reporting? */
-	    temp |= 0x0008;
+		temp |= HUB_CHAR_INDV_PORT_OCPM;
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 
 	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
index 8ddd8f5..4db78f1 100644
--- a/drivers/usb/host/ohci-jz4740.c
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -239,7 +239,6 @@
 	.remove = jz4740_ohci_remove,
 	.driver = {
 		.name = "jz4740-ohci",
-		.owner = THIS_MODULE,
 	},
 };
 
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index b81d202..185ceee 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -38,7 +38,8 @@
 struct ohci_platform_priv {
 	struct clk *clks[OHCI_MAX_CLKS];
 	struct reset_control *rst;
-	struct phy *phy;
+	struct phy **phys;
+	int num_phys;
 };
 
 static const char hcd_name[] = "ohci-platform";
@@ -47,7 +48,7 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk, ret;
+	int clk, ret, phy_num;
 
 	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
 		ret = clk_prepare_enable(priv->clks[clk]);
@@ -55,20 +56,28 @@
 			goto err_disable_clks;
 	}
 
-	if (priv->phy) {
-		ret = phy_init(priv->phy);
-		if (ret)
-			goto err_disable_clks;
-
-		ret = phy_power_on(priv->phy);
-		if (ret)
-			goto err_exit_phy;
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		if (priv->phys[phy_num]) {
+			ret = phy_init(priv->phys[phy_num]);
+			if (ret)
+				goto err_exit_phy;
+			ret = phy_power_on(priv->phys[phy_num]);
+			if (ret) {
+				phy_exit(priv->phys[phy_num]);
+				goto err_exit_phy;
+			}
+		}
 	}
 
 	return 0;
 
 err_exit_phy:
-	phy_exit(priv->phy);
+	while (--phy_num >= 0) {
+		if (priv->phys[phy_num]) {
+			phy_power_off(priv->phys[phy_num]);
+			phy_exit(priv->phys[phy_num]);
+		}
+	}
 err_disable_clks:
 	while (--clk >= 0)
 		clk_disable_unprepare(priv->clks[clk]);
@@ -80,11 +89,13 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk;
+	int clk, phy_num;
 
-	if (priv->phy) {
-		phy_power_off(priv->phy);
-		phy_exit(priv->phy);
+	for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+		if (priv->phys[phy_num]) {
+			phy_power_off(priv->phys[phy_num]);
+			phy_exit(priv->phys[phy_num]);
+		}
 	}
 
 	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -112,7 +123,8 @@
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ohci_platform_priv *priv;
 	struct ohci_hcd *ohci;
-	int err, irq, clk = 0;
+	const char *phy_name;
+	int err, irq, phy_num, clk = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -160,12 +172,38 @@
 		of_property_read_u32(dev->dev.of_node, "num-ports",
 				     &ohci->num_ports);
 
-		priv->phy = devm_phy_get(&dev->dev, "usb");
-		if (IS_ERR(priv->phy)) {
-			err = PTR_ERR(priv->phy);
-			if (err == -EPROBE_DEFER)
-				goto err_put_hcd;
-			priv->phy = NULL;
+		priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
+				"phys", "#phy-cells");
+		priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
+
+		priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+				sizeof(struct phy *), GFP_KERNEL);
+		if (!priv->phys)
+			return -ENOMEM;
+
+		for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+				err = of_property_read_string_index(
+						dev->dev.of_node,
+						"phy-names", phy_num,
+						&phy_name);
+
+				if (err < 0) {
+					if (priv->num_phys > 1) {
+						dev_err(&dev->dev, "phy-names not provided");
+						goto err_put_hcd;
+					} else
+						phy_name = "usb";
+				}
+
+				priv->phys[phy_num] = devm_phy_get(&dev->dev,
+						phy_name);
+				if (IS_ERR(priv->phys[phy_num])) {
+					err = PTR_ERR(priv->phys[phy_num]);
+					if ((priv->num_phys > 1) ||
+					    (err == -EPROBE_DEFER))
+						goto err_put_hcd;
+					priv->phys[phy_num] = NULL;
+				}
 		}
 
 		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
@@ -328,6 +366,7 @@
 
 static const struct of_device_id ohci_platform_ids[] = {
 	{ .compatible = "generic-ohci", },
+	{ .compatible = "cavium,octeon-6335-ohci", },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ohci_platform_ids);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 965e3e9..4f87a5c 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -229,7 +229,6 @@
 	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "ppc-of-ohci",
-		.owner = THIS_MODULE,
 		.of_match_table = ohci_hcd_ppc_of_match,
 	},
 };
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 095113e..7a1919c 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -249,14 +249,14 @@
 		 */
 
 		desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
-		desc->wHubCharacteristics |= cpu_to_le16(0x0001);
+		desc->wHubCharacteristics |= cpu_to_le16(
+			HUB_CHAR_INDV_PORT_LPSM);
 
 		if (info->enable_oc) {
 			desc->wHubCharacteristics &= ~cpu_to_le16(
 				HUB_CHAR_OCPM);
 			desc->wHubCharacteristics |=  cpu_to_le16(
-				0x0008 |
-				0x0001);
+				HUB_CHAR_INDV_PORT_OCPM);
 		}
 
 		dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 4e81c80..a8b8d8b 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -265,7 +265,6 @@
 	.suspend	= ohci_sm501_suspend,
 	.resume		= ohci_sm501_resume,
 	.driver		= {
-		.owner	= THIS_MODULE,
 		.name	= "sm501-usb",
 	},
 };
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c
index bef6dfb..e1b208d 100644
--- a/drivers/usb/host/ohci-tilegx.c
+++ b/drivers/usb/host/ohci-tilegx.c
@@ -199,7 +199,6 @@
 	.shutdown	= ohci_hcd_tilegx_drv_shutdown,
 	.driver = {
 		.name	= "tilegx-ohci",
-		.owner	= THIS_MODULE,
 	}
 };
 
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index bb40958..e9a6eec 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -368,6 +368,5 @@
 	.resume		= ohci_hcd_tmio_drv_resume,
 	.driver		= {
 		.name	= "tmio-ohci",
-		.owner	= THIS_MODULE,
 	},
 };
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 036924e..ef7efb2 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -457,11 +457,11 @@
 	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
 	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
 
-	temp = 0x0008;			/* per-port overcurrent reporting */
+	temp = HUB_CHAR_INDV_PORT_OCPM;	/* per-port overcurrent reporting */
 	if (HCS_PPC(oxu->hcs_params))
-		temp |= 0x0001;		/* per-port power control */
+		temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
 	else
-		temp |= 0x0002;		/* no power switching */
+		temp |= HUB_CHAR_NO_LPSM; /* no power switching */
 	desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
 }
 
@@ -2598,9 +2598,7 @@
 
 	spin_lock_init(&oxu->lock);
 
-	init_timer(&oxu->watchdog);
-	oxu->watchdog.function = oxu_watchdog;
-	oxu->watchdog.data = (unsigned long) oxu;
+	setup_timer(&oxu->watchdog, oxu_watchdog, (unsigned long)oxu);
 
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index ce63646..f940056 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -603,9 +603,9 @@
 			msleep(10);
 		}
 		if (wait_time <= 0)
-			dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
-					" (BIOS bug?) %08x\n",
-					readl(base + OHCI_CONTROL));
+			dev_warn(&pdev->dev,
+				 "OHCI: BIOS handoff failed (BIOS bug?) %08x\n",
+				 readl(base + OHCI_CONTROL));
 	}
 #endif
 
@@ -733,8 +733,9 @@
 		 * and hope nothing goes too wrong
 		 */
 		if (try_handoff)
-			dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
-				 " (BIOS bug?) %08x\n", cap);
+			dev_warn(&pdev->dev,
+				 "EHCI: BIOS handoff failed (BIOS bug?) %08x\n",
+				 cap);
 		pci_write_config_byte(pdev, offset + 2, 0);
 	}
 
@@ -781,8 +782,9 @@
 		case 0: /* Illegal reserved cap, set cap=0 so we exit */
 			cap = 0; /* then fallthrough... */
 		default:
-			dev_warn(&pdev->dev, "EHCI: unrecognized capability "
-				 "%02x\n", cap & 0xff);
+			dev_warn(&pdev->dev,
+				 "EHCI: unrecognized capability %02x\n",
+				 cap & 0xff);
 		}
 		offset = (cap >> 8) & 0xff;
 	}
@@ -893,8 +895,7 @@
 	 */
 	if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
 		dev_warn(&xhci_pdev->dev,
-				"CONFIG_USB_XHCI_HCD is turned off, "
-				"defaulting to EHCI.\n");
+			 "CONFIG_USB_XHCI_HCD is turned off, defaulting to EHCI.\n");
 		dev_warn(&xhci_pdev->dev,
 				"USB 3.0 devices will work at USB 2.0 speeds.\n");
 		usb_disable_xhci_ports(xhci_pdev);
@@ -919,8 +920,9 @@
 
 	pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
 			&ports_available);
-	dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
-			"under xHCI: 0x%x\n", ports_available);
+	dev_dbg(&xhci_pdev->dev,
+		"USB 3.0 ports that are now enabled under xHCI: 0x%x\n",
+		ports_available);
 
 	/* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register
 	 * Indicate the USB 2.0 ports to be controlled by the xHCI host.
@@ -941,8 +943,9 @@
 
 	pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
 			&ports_available);
-	dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
-			"to xHCI: 0x%x\n", ports_available);
+	dev_dbg(&xhci_pdev->dev,
+		"USB 2.0 ports that are now switched over to xHCI: 0x%x\n",
+		ports_available);
 }
 EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
 
@@ -1010,8 +1013,9 @@
 
 		/* Assume a buggy BIOS and take HC ownership anyway */
 		if (timeout) {
-			dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
-					" (BIOS bug ?) %08x\n", val);
+			dev_warn(&pdev->dev,
+				 "xHCI BIOS handoff failed (BIOS bug ?) %08x\n",
+				 val);
 			writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
 		}
 	}
@@ -1039,8 +1043,8 @@
 	if (timeout) {
 		val = readl(op_reg_base + XHCI_STS_OFFSET);
 		dev_warn(&pdev->dev,
-				"xHCI HW not ready after 5 sec (HC bug?) "
-				"status = 0x%x\n", val);
+			 "xHCI HW not ready after 5 sec (HC bug?) status = 0x%x\n",
+			 val);
 	}
 
 	/* Send the halt and disable interrupts command */
@@ -1054,8 +1058,8 @@
 	if (timeout) {
 		val = readl(op_reg_base + XHCI_STS_OFFSET);
 		dev_warn(&pdev->dev,
-				"xHCI HW did not halt within %d usec "
-				"status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
+			 "xHCI HW did not halt within %d usec status = 0x%x\n",
+			 XHCI_MAX_HALT_USEC, val);
 	}
 
 	iounmap(base);
@@ -1075,8 +1079,8 @@
 		return;
 
 	if (pci_enable_device(pdev) < 0) {
-		dev_warn(&pdev->dev, "Can't enable PCI device, "
-				"BIOS handoff failed.\n");
+		dev_warn(&pdev->dev,
+			 "Can't enable PCI device, BIOS handoff failed.\n");
 		return;
 	}
 	if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index c4bcfae..bdc82fe 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2141,7 +2141,8 @@
 	desc->bNbrPorts = r8a66597->max_root_hub;
 	desc->bDescLength = 9;
 	desc->bPwrOn2PwrGood = 0;
-	desc->wHubCharacteristics = cpu_to_le16(0x0011);
+	desc->wHubCharacteristics =
+		cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM);
 	desc->u.hs.DeviceRemovable[0] =
 		((1 << r8a66597->max_root_hub) - 1) << 1;
 	desc->u.hs.DeviceRemovable[1] = ~0;
@@ -2483,9 +2484,8 @@
 		r8a66597->max_root_hub = 2;
 
 	spin_lock_init(&r8a66597->lock);
-	init_timer(&r8a66597->rh_timer);
-	r8a66597->rh_timer.function = r8a66597_timer;
-	r8a66597->rh_timer.data = (unsigned long)r8a66597;
+	setup_timer(&r8a66597->rh_timer, r8a66597_timer,
+		    (unsigned long)r8a66597);
 	r8a66597->reg = reg;
 
 	/* make sure no interrupts are pending */
@@ -2496,9 +2496,8 @@
 
 	for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
 		INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
-		init_timer(&r8a66597->td_timer[i]);
-		r8a66597->td_timer[i].function = r8a66597_td_timer;
-		r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+		setup_timer(&r8a66597->td_timer[i], r8a66597_td_timer,
+			    (unsigned long)r8a66597);
 		setup_timer(&r8a66597->interval_timer[i],
 				r8a66597_interval_timer,
 				(unsigned long)r8a66597);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 25fb1da..4f4ba1e 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1103,12 +1103,12 @@
 		desc->bPwrOn2PwrGood = sl811->board->potpg;
 		if (!desc->bPwrOn2PwrGood)
 			desc->bPwrOn2PwrGood = 10;
-		temp = 0x0001;
+		temp = HUB_CHAR_INDV_PORT_LPSM;
 	} else
-		temp = 0x0002;
+		temp = HUB_CHAR_NO_LPSM;
 
 	/* no overcurrent errors detection/handling */
-	temp |= 0x0010;
+	temp |= HUB_CHAR_NO_OCPM;
 
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 
@@ -1691,9 +1691,7 @@
 	spin_lock_init(&sl811->lock);
 	INIT_LIST_HEAD(&sl811->async);
 	sl811->board = dev_get_platdata(&dev->dev);
-	init_timer(&sl811->timer);
-	sl811->timer.function = sl811h_timer;
-	sl811->timer.data = (unsigned long) sl811;
+	setup_timer(&sl811->timer, sl811h_timer, (unsigned long)sl811);
 	sl811->addr_reg = addr_reg;
 	sl811->data_reg = data_reg;
 
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 2894e54..ad97e8a 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2590,15 +2590,15 @@
 	desc->bNbrPorts = u132->num_ports;
 	temp = 1 + (u132->num_ports / 8);
 	desc->bDescLength = 7 + 2 * temp;
-	temp = 0;
+	temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
 	if (rh_a & RH_A_NPS)
-		temp |= 0x0002;
+		temp |= HUB_CHAR_NO_LPSM;
 	if (rh_a & RH_A_PSM)
-		temp |= 0x0001;
+		temp |= HUB_CHAR_INDV_PORT_LPSM;
 	if (rh_a & RH_A_NOCP)
-		temp |= 0x0010;
+		temp |= HUB_CHAR_NO_OCPM;
 	else if (rh_a & RH_A_OCPM)
-		temp |= 0x0008;
+		temp |= HUB_CHAR_INDV_PORT_OCPM;
 	desc->wHubCharacteristics = cpu_to_le16(temp);
 	retval = u132_read_pcimem(u132, roothub.b, &rh_b);
 	if (retval)
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index 05f57ff..0342991 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -188,7 +188,6 @@
 	.shutdown	= uhci_hcd_grlib_shutdown,
 	.driver = {
 		.name = "grlib-uhci",
-		.owner = THIS_MODULE,
 		.of_match_table = uhci_hcd_grlib_of_match,
 	},
 };
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 93e17b1..19ba5ea 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -17,8 +17,9 @@
 	0x09,			/*  __u8  bLength; */
 	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
 	0x02,			/*  __u8  bNbrPorts; */
-	0x0a,			/* __u16  wHubCharacteristics; */
-	0x00,			/*   (per-port OC, no power switching) */
+	HUB_CHAR_NO_LPSM |	/* __u16  wHubCharacteristics; */
+		HUB_CHAR_INDV_PORT_OCPM, /* (per-port OC, no power switching) */
+	0x00,
 	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
 	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
 	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max */
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index cf8f460..3a3e3ee 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -147,7 +147,6 @@
 	.shutdown	= uhci_hcd_platform_shutdown,
 	.driver = {
 		.name = "platform-uhci",
-		.owner = THIS_MODULE,
 		.of_match_table = platform_uhci_ids,
 	},
 };
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
index ba61dae..774b89d 100644
--- a/drivers/usb/host/whci/debug.c
+++ b/drivers/usb/host/whci/debug.c
@@ -86,17 +86,14 @@
 static int di_print(struct seq_file *s, void *p)
 {
 	struct whc *whc = s->private;
-	char buf[72];
 	int d;
 
 	for (d = 0; d < whc->n_devices; d++) {
 		struct di_buf_entry *di = &whc->di_buf[d];
 
-		bitmap_scnprintf(buf, sizeof(buf),
-				 (unsigned long *)di->availability_info, UWB_NUM_MAS);
-
 		seq_printf(s, "DI[%d]\n", d);
-		seq_printf(s, "  availability: %s\n", buf);
+		seq_printf(s, "  availability: %*pb\n",
+			   UWB_NUM_MAS, (unsigned long *)di->availability_info);
 		seq_printf(s, "  %c%c key idx: %d dev addr: %d\n",
 			   (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
 			   (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index bb89175..745717e 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -552,7 +552,7 @@
 
 	if (ctx->type == XHCI_CTX_TYPE_INPUT) {
 		struct xhci_input_control_ctx *ctrl_ctx =
-			xhci_get_input_control_ctx(xhci, ctx);
+			xhci_get_input_control_ctx(ctx);
 		if (!ctrl_ctx) {
 			xhci_warn(xhci, "Could not get input context, bad type.\n");
 			return;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 5cb3d7a..f833640 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -535,7 +535,7 @@
 	kfree(ctx);
 }
 
-struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci,
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(
 					      struct xhci_container_ctx *ctx)
 {
 	if (ctx->type != XHCI_CTX_TYPE_INPUT)
@@ -784,8 +784,7 @@
  * Reinstalls the "normal" endpoint ring (at its previous dequeue mark,
  * not at the beginning of the ring).
  */
-void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
-		struct xhci_ep_ctx *ep_ctx,
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_ep_ctx *ep_ctx,
 		struct xhci_virt_ep *ep)
 {
 	dma_addr_t addr;
@@ -833,9 +832,8 @@
 static void xhci_init_endpoint_timer(struct xhci_hcd *xhci,
 		struct xhci_virt_ep *ep)
 {
-	init_timer(&ep->stop_cmd_timer);
-	ep->stop_cmd_timer.data = (unsigned long) ep;
-	ep->stop_cmd_timer.function = xhci_stop_endpoint_command_watchdog;
+	setup_timer(&ep->stop_cmd_timer, xhci_stop_endpoint_command_watchdog,
+		    (unsigned long)ep);
 	ep->xhci = xhci;
 }
 
@@ -1342,8 +1340,7 @@
 	return ep->ss_ep_comp.bmAttributes;
 }
 
-static u32 xhci_get_endpoint_type(struct usb_device *udev,
-		struct usb_host_endpoint *ep)
+static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep)
 {
 	int in;
 	u32 type;
@@ -1376,8 +1373,7 @@
  * Basically, this is the maxpacket size, multiplied by the burst size
  * and mult size.
  */
-static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
-		struct usb_device *udev,
+static u32 xhci_get_max_esit_payload(struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
 	int max_burst;
@@ -1418,7 +1414,7 @@
 	ep_index = xhci_get_endpoint_index(&ep->desc);
 	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
 
-	endpoint_type = xhci_get_endpoint_type(udev, ep);
+	endpoint_type = xhci_get_endpoint_type(ep);
 	if (!endpoint_type)
 		return -EINVAL;
 	ep_ctx->ep_info2 = cpu_to_le32(endpoint_type);
@@ -1484,7 +1480,7 @@
 	}
 	ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) |
 			MAX_BURST(max_burst));
-	max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep);
+	max_esit_payload = xhci_get_max_esit_payload(udev, ep);
 	ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
 
 	/*
@@ -1773,7 +1769,7 @@
 	return command;
 }
 
-void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv)
+void xhci_urb_free_priv(struct urb_priv *urb_priv)
 {
 	if (urb_priv) {
 		kfree(urb_priv->td[0]);
@@ -1926,7 +1922,7 @@
 }
 
 /* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
-static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
+static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
 {
 	struct {
 		dma_addr_t		input_dma;
@@ -2452,7 +2448,7 @@
 						flags);
 	if (!xhci->event_ring)
 		goto fail;
-	if (xhci_check_trb_in_td_math(xhci, flags) < 0)
+	if (xhci_check_trb_in_td_math(xhci) < 0)
 		goto fail;
 
 	xhci->erst.entries = dma_alloc_coherent(dev,
@@ -2509,9 +2505,8 @@
 	xhci_print_ir_set(xhci, 0);
 
 	/* init command timeout timer */
-	init_timer(&xhci->cmd_timer);
-	xhci->cmd_timer.data = (unsigned long) xhci;
-	xhci->cmd_timer.function = xhci_handle_command_timeout;
+	setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
+		    (unsigned long)xhci);
 
 	/*
 	 * XXX: Might need to set the Interrupter Moderation Register to
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e692e76..88da8d6 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -299,7 +299,7 @@
 	 * seconds), then it should assume that the there are
 	 * larger problems with the xHC and assert HCRST.
 	 */
-	ret = xhci_handshake(xhci, &xhci->op_regs->cmd_ring,
+	ret = xhci_handshake(&xhci->op_regs->cmd_ring,
 			CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
 	if (ret < 0) {
 		xhci_err(xhci, "Stopped the command ring failed, "
@@ -609,7 +609,7 @@
 
 		spin_unlock(&xhci->lock);
 		usb_hcd_giveback_urb(hcd, urb, status);
-		xhci_urb_free_priv(xhci, urb_priv);
+		xhci_urb_free_priv(urb_priv);
 		spin_lock(&xhci->lock);
 	}
 }
@@ -1110,7 +1110,7 @@
 	 * is not waiting on the configure endpoint command.
 	 */
 	virt_dev = xhci->devs[slot_id];
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "Could not get input context, bad type.\n");
 		return;
@@ -2354,8 +2354,8 @@
 			status = 0;
 			break;
 		}
-		xhci_warn(xhci, "ERROR Unknown event condition, HC probably "
-				"busted\n");
+		xhci_warn(xhci, "ERROR Unknown event condition %u, HC probably busted\n",
+			  trb_comp_code);
 		goto cleanup;
 	}
 
@@ -2497,7 +2497,7 @@
 			urb = td->urb;
 			urb_priv = urb->hcpriv;
 
-			xhci_urb_free_priv(xhci, urb_priv);
+			xhci_urb_free_priv(urb_priv);
 
 			usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
 			if ((urb->actual_length != urb->transfer_buffer_length &&
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c50d8d2..ec8ac16 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -60,8 +60,7 @@
  * handshake done).  There are two failure modes:  "usec" have passed (major
  * hardware flakeout), or the register reads as all-ones (hardware removed).
  */
-int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr,
-		      u32 mask, u32 done, int usec)
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
 {
 	u32	result;
 
@@ -111,7 +110,7 @@
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
 	xhci_quiesce(xhci);
 
-	ret = xhci_handshake(xhci, &xhci->op_regs->status,
+	ret = xhci_handshake(&xhci->op_regs->status,
 			STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
 	if (!ret) {
 		xhci->xhc_state |= XHCI_STATE_HALTED;
@@ -140,7 +139,7 @@
 	 * Wait for the HCHalted Status bit to be 0 to indicate the host is
 	 * running.
 	 */
-	ret = xhci_handshake(xhci, &xhci->op_regs->status,
+	ret = xhci_handshake(&xhci->op_regs->status,
 			STS_HALT, 0, XHCI_MAX_HALT_USEC);
 	if (ret == -ETIMEDOUT)
 		xhci_err(xhci, "Host took too long to start, "
@@ -175,7 +174,7 @@
 	command |= CMD_RESET;
 	writel(command, &xhci->op_regs->command);
 
-	ret = xhci_handshake(xhci, &xhci->op_regs->command,
+	ret = xhci_handshake(&xhci->op_regs->command,
 			CMD_RESET, 0, 10 * 1000 * 1000);
 	if (ret)
 		return ret;
@@ -186,7 +185,7 @@
 	 * xHCI cannot write to any doorbells or operational registers other
 	 * than status until the "Controller Not Ready" flag is cleared.
 	 */
-	ret = xhci_handshake(xhci, &xhci->op_regs->status,
+	ret = xhci_handshake(&xhci->op_regs->status,
 			STS_CNR, 0, 10 * 1000 * 1000);
 
 	for (i = 0; i < 2; ++i) {
@@ -473,10 +472,8 @@
 static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
 {
 	xhci->port_status_u0 = 0;
-	init_timer(&xhci->comp_mode_recovery_timer);
-
-	xhci->comp_mode_recovery_timer.data = (unsigned long) xhci;
-	xhci->comp_mode_recovery_timer.function = compliance_mode_recovery;
+	setup_timer(&xhci->comp_mode_recovery_timer,
+		    compliance_mode_recovery, (unsigned long)xhci);
 	xhci->comp_mode_recovery_timer.expires = jiffies +
 			msecs_to_jiffies(COMP_MODE_RCVRY_MSECS);
 
@@ -929,7 +926,7 @@
 	/* Some chips from Fresco Logic need an extraordinary delay */
 	delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1;
 
-	if (xhci_handshake(xhci, &xhci->op_regs->status,
+	if (xhci_handshake(&xhci->op_regs->status,
 		      STS_HALT, STS_HALT, delay)) {
 		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
 		spin_unlock_irq(&xhci->lock);
@@ -944,7 +941,7 @@
 	command = readl(&xhci->op_regs->command);
 	command |= CMD_CSS;
 	writel(command, &xhci->op_regs->command);
-	if (xhci_handshake(xhci, &xhci->op_regs->status,
+	if (xhci_handshake(&xhci->op_regs->status,
 				STS_SAVE, 0, 10 * 1000)) {
 		xhci_warn(xhci, "WARN: xHC save state timeout\n");
 		spin_unlock_irq(&xhci->lock);
@@ -1011,7 +1008,7 @@
 		command = readl(&xhci->op_regs->command);
 		command |= CMD_CRS;
 		writel(command, &xhci->op_regs->command);
-		if (xhci_handshake(xhci, &xhci->op_regs->status,
+		if (xhci_handshake(&xhci->op_regs->status,
 			      STS_RESTORE, 0, 10 * 1000)) {
 			xhci_warn(xhci, "WARN: xHC restore state timeout\n");
 			spin_unlock_irq(&xhci->lock);
@@ -1082,7 +1079,7 @@
 	command = readl(&xhci->op_regs->command);
 	command |= CMD_RUN;
 	writel(command, &xhci->op_regs->command);
-	xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT,
+	xhci_handshake(&xhci->op_regs->status, STS_HALT,
 		  0, 250 * 1000);
 
 	/* step 5: walk topology and initialize portsc,
@@ -1276,7 +1273,7 @@
 			return -ENOMEM;
 
 		command->in_ctx = xhci->devs[slot_id]->in_ctx;
-		ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+		ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
 		if (!ctrl_ctx) {
 			xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 					__func__);
@@ -1374,7 +1371,7 @@
 			ret = xhci_check_maxpacket(xhci, slot_id,
 					ep_index, urb);
 			if (ret < 0) {
-				xhci_urb_free_priv(xhci, urb_priv);
+				xhci_urb_free_priv(urb_priv);
 				urb->hcpriv = NULL;
 				return ret;
 			}
@@ -1440,7 +1437,7 @@
 			urb->ep->desc.bEndpointAddress, urb);
 	ret = -ESHUTDOWN;
 free_priv:
-	xhci_urb_free_priv(xhci, urb_priv);
+	xhci_urb_free_priv(urb_priv);
 	urb->hcpriv = NULL;
 	spin_unlock_irqrestore(&xhci->lock, flags);
 	return ret;
@@ -1553,7 +1550,7 @@
 		usb_hcd_unlink_urb_from_ep(hcd, urb);
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
-		xhci_urb_free_priv(xhci, urb_priv);
+		xhci_urb_free_priv(urb_priv);
 		return ret;
 	}
 	if ((xhci->xhc_state & XHCI_STATE_DYING) ||
@@ -1660,7 +1657,7 @@
 
 	in_ctx = xhci->devs[udev->slot_id]->in_ctx;
 	out_ctx = xhci->devs[udev->slot_id]->out_ctx;
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -1676,8 +1673,10 @@
 	     cpu_to_le32(EP_STATE_DISABLED)) ||
 	    le32_to_cpu(ctrl_ctx->drop_flags) &
 	    xhci_get_endpoint_flag(&ep->desc)) {
-		xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
-				__func__, ep);
+		/* Do not warn when called after a usb_device_reset */
+		if (xhci->devs[udev->slot_id]->eps[ep_index].ring != NULL)
+			xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
+				  __func__, ep);
 		return 0;
 	}
 
@@ -1714,7 +1713,7 @@
 		struct usb_host_endpoint *ep)
 {
 	struct xhci_hcd *xhci;
-	struct xhci_container_ctx *in_ctx, *out_ctx;
+	struct xhci_container_ctx *in_ctx;
 	unsigned int ep_index;
 	struct xhci_input_control_ctx *ctrl_ctx;
 	u32 added_ctxs;
@@ -1745,8 +1744,7 @@
 
 	virt_dev = xhci->devs[udev->slot_id];
 	in_ctx = virt_dev->in_ctx;
-	out_ctx = virt_dev->out_ctx;
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -1758,8 +1756,7 @@
 	 * to add it again without dropping it, reject the addition.
 	 */
 	if (virt_dev->eps[ep_index].ring &&
-			!(le32_to_cpu(ctrl_ctx->drop_flags) &
-				xhci_get_endpoint_flag(&ep->desc))) {
+			!(le32_to_cpu(ctrl_ctx->drop_flags) & added_ctxs)) {
 		xhci_warn(xhci, "Trying to add endpoint 0x%x "
 				"without dropping it.\n",
 				(unsigned int) ep->desc.bEndpointAddress);
@@ -1769,8 +1766,7 @@
 	/* If the HCD has already noted the endpoint is enabled,
 	 * ignore this request.
 	 */
-	if (le32_to_cpu(ctrl_ctx->add_flags) &
-	    xhci_get_endpoint_flag(&ep->desc)) {
+	if (le32_to_cpu(ctrl_ctx->add_flags) & added_ctxs) {
 		xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
 				__func__, ep);
 		return 0;
@@ -1816,7 +1812,7 @@
 	struct xhci_slot_ctx *slot_ctx;
 	int i;
 
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -2542,7 +2538,7 @@
 	if (virt_dev->tt_info)
 		old_active_eps = virt_dev->tt_info->active_eps;
 
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -2639,7 +2635,7 @@
 	spin_lock_irqsave(&xhci->lock, flags);
 	virt_dev = xhci->devs[udev->slot_id];
 
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
 	if (!ctrl_ctx) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -2758,7 +2754,7 @@
 	command->in_ctx = virt_dev->in_ctx;
 
 	/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -2883,7 +2879,7 @@
 	dma_addr_t addr;
 
 	in_ctx = xhci->devs[slot_id]->in_ctx;
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -3173,7 +3169,7 @@
 		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
 		return -ENOMEM;
 	}
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -3328,7 +3324,7 @@
 	 */
 	ep_index = xhci_get_endpoint_index(&eps[0]->desc);
 	command = vdev->eps[ep_index].stream_info->free_streams_command;
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
 	if (!ctrl_ctx) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -3346,7 +3342,7 @@
 
 		xhci_endpoint_copy(xhci, command->in_ctx,
 				vdev->out_ctx, ep_index);
-		xhci_setup_no_streams_ep_input_ctx(xhci, ep_ctx,
+		xhci_setup_no_streams_ep_input_ctx(ep_ctx,
 				&vdev->eps[ep_index]);
 	}
 	xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx,
@@ -3820,7 +3816,7 @@
 	command->completion = &xhci->addr_dev;
 
 	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -4003,7 +3999,7 @@
 
 	/* Attempt to issue an Evaluate Context command to change the MEL. */
 	command = xhci->lpm_command;
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
 	if (!ctrl_ctx) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -4741,7 +4737,7 @@
 		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
 		return -ENOMEM;
 	}
-	ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
+	ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
 	if (!ctrl_ctx) {
 		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
 				__func__);
@@ -4910,6 +4906,10 @@
 	if (retval)
 		goto error;
 	xhci_dbg(xhci, "Called HCD init\n");
+
+	xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%08x\n",
+		  xhci->hcc_params, xhci->hci_version, xhci->quirks);
+
 	return 0;
 error:
 	kfree(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cc7c5bb..9745147 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1605,6 +1605,8 @@
 	dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_warn_ratelimited(xhci, fmt, args...) \
 	dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+#define xhci_info(xhci, fmt, args...) \
+	dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 
 /*
  * Registers should always be accessed with double word or quad word accesses.
@@ -1712,8 +1714,7 @@
 void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
 		struct xhci_ep_ctx *ep_ctx,
 		struct xhci_stream_info *stream_info);
-void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
-		struct xhci_ep_ctx *ep_ctx,
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_ep_ctx *ep_ctx,
 		struct xhci_virt_ep *ep);
 void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
 	struct xhci_virt_device *virt_dev, bool drop_control_ep);
@@ -1727,14 +1728,13 @@
 struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
 		bool allocate_in_ctx, bool allocate_completion,
 		gfp_t mem_flags);
-void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv);
+void xhci_urb_free_priv(struct urb_priv *urb_priv);
 void xhci_free_command(struct xhci_hcd *xhci,
 		struct xhci_command *command);
 
 /* xHCI host controller glue */
 typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
-int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr,
-		u32 mask, u32 done, int usec);
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
 void xhci_quiesce(struct xhci_hcd *xhci);
 int xhci_halt(struct xhci_hcd *xhci);
 int xhci_reset(struct xhci_hcd *xhci);
@@ -1864,7 +1864,7 @@
 void xhci_ring_device(struct xhci_hcd *xhci, int slot_id);
 
 /* xHCI contexts */
-struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_ctx *ctx);
 struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
 struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
 
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 37b44b0..6431d08 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -299,9 +299,7 @@
 	MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len);
 
  out:
-	MTS_DEBUG( "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
-	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+	MTS_DEBUG( "  %10ph\n", srb->cmnd);
 }
 
 #else
diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig
new file mode 100644
index 0000000..c94b7d9
--- /dev/null
+++ b/drivers/usb/isp1760/Kconfig
@@ -0,0 +1,59 @@
+config USB_ISP1760
+	tristate "NXP ISP 1760/1761 support"
+	depends on USB || USB_GADGET
+	help
+	  Say Y or M here if your system as an ISP1760 USB host controller
+	  or an ISP1761 USB dual-role controller.
+
+	  This driver does not support isochronous transfers or OTG.
+	  This USB controller is usually attached to a non-DMA-Master
+	  capable bus. NXP's eval kit brings this chip on PCI card
+	  where the chip itself is behind a PLB to simulate such
+	  a bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called isp1760.
+
+config USB_ISP1760_HCD
+	bool
+
+config USB_ISP1761_UDC
+	bool
+
+if USB_ISP1760
+
+choice
+	bool "ISP1760 Mode Selection"
+	default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
+	default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
+	default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
+
+config USB_ISP1760_HOST_ROLE
+	bool "Host only mode"
+	depends on USB=y || USB=USB_ISP1760
+	select USB_ISP1760_HCD
+	help
+	  Select this if you want to use the ISP1760 in host mode only. The
+	  gadget function will be disabled.
+
+config USB_ISP1760_GADGET_ROLE
+	bool "Gadget only mode"
+	depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
+	select USB_ISP1761_UDC
+	help
+	  Select this if you want to use the ISP1760 in peripheral mode only.
+	  The host function will be disabled.
+
+config USB_ISP1760_DUAL_ROLE
+	bool "Dual Role mode"
+	depends on USB=y || USB=USB_ISP1760
+	depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
+	select USB_ISP1760_HCD
+	select USB_ISP1761_UDC
+	help
+	  Select this if you want to use the ISP1760 in both host and
+	  peripheral modes.
+
+endchoice
+
+endif
diff --git a/drivers/usb/isp1760/Makefile b/drivers/usb/isp1760/Makefile
new file mode 100644
index 0000000..2b74107
--- /dev/null
+++ b/drivers/usb/isp1760/Makefile
@@ -0,0 +1,5 @@
+isp1760-y := isp1760-core.o isp1760-if.o
+isp1760-$(CONFIG_USB_ISP1760_HCD) += isp1760-hcd.o
+isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
+
+obj-$(CONFIG_USB_ISP1760)	+= isp1760.o
diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
new file mode 100644
index 0000000..b982755
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-core.c
@@ -0,0 +1,177 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ *	Sebastian Siewior <bigeasy@linutronix.de>
+ *	Laurent Pinchart <laurent.pinchart@ideasonboard.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/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "isp1760-core.h"
+#include "isp1760-hcd.h"
+#include "isp1760-regs.h"
+#include "isp1760-udc.h"
+
+static void isp1760_init_core(struct isp1760_device *isp)
+{
+	u32 otgctrl;
+	u32 hwmode;
+
+	/* Low-level chip reset */
+	if (isp->rst_gpio) {
+		gpiod_set_value_cansleep(isp->rst_gpio, 1);
+		mdelay(50);
+		gpiod_set_value_cansleep(isp->rst_gpio, 0);
+	}
+
+	/*
+	 * Reset the host controller, including the CPU interface
+	 * configuration.
+	 */
+	isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
+	msleep(100);
+
+	/* Setup HW Mode Control: This assumes a level active-low interrupt */
+	hwmode = HW_DATA_BUS_32BIT;
+
+	if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
+		hwmode &= ~HW_DATA_BUS_32BIT;
+	if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
+		hwmode |= HW_ANA_DIGI_OC;
+	if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
+		hwmode |= HW_DACK_POL_HIGH;
+	if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
+		hwmode |= HW_DREQ_POL_HIGH;
+	if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
+		hwmode |= HW_INTR_HIGH_ACT;
+	if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
+		hwmode |= HW_INTR_EDGE_TRIG;
+
+	/*
+	 * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
+	 * IRQ line for both the host and device controllers. Hardcode IRQ
+	 * sharing for now and disable the DC interrupts globally to avoid
+	 * spurious interrupts during HCD registration.
+	 */
+	if (isp->devflags & ISP1760_FLAG_ISP1761) {
+		isp1760_write32(isp->regs, DC_MODE, 0);
+		hwmode |= HW_COMN_IRQ;
+	}
+
+	/*
+	 * We have to set this first in case we're in 16-bit mode.
+	 * Write it twice to ensure correct upper bits if switching
+	 * to 16-bit mode.
+	 */
+	isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+	isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+
+	/*
+	 * PORT 1 Control register of the ISP1760 is the OTG control register
+	 * on ISP1761.
+	 *
+	 * TODO: Really support OTG. For now we configure port 1 in device mode
+	 * when OTG is requested.
+	 */
+	if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
+	    (isp->devflags & ISP1760_FLAG_OTG_EN))
+		otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
+			| HW_OTG_DISABLE;
+	else
+		otgctrl = (HW_SW_SEL_HC_DC << 16)
+			| (HW_VBUS_DRV | HW_SEL_CP_EXT);
+
+	isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
+
+	dev_info(isp->dev, "bus width: %u, oc: %s\n",
+		 isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
+		 isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
+}
+
+void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+{
+	isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
+			enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
+}
+
+int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+		     struct device *dev, unsigned int devflags)
+{
+	struct isp1760_device *isp;
+	bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+	int ret;
+
+	/*
+	 * If neither the HCD not the UDC is enabled return an error, as no
+	 * device would be registered.
+	 */
+	if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
+	    (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
+		return -ENODEV;
+
+	/* prevent usb-core allocating DMA pages */
+	dev->dma_mask = NULL;
+
+	isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
+	if (!isp)
+		return -ENOMEM;
+
+	isp->dev = dev;
+	isp->devflags = devflags;
+
+	isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+	if (IS_ERR(isp->rst_gpio))
+		return PTR_ERR(isp->rst_gpio);
+
+	isp->regs = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(isp->regs))
+		return PTR_ERR(isp->regs);
+
+	isp1760_init_core(isp);
+
+	if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
+		ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
+					   irqflags | IRQF_SHARED, dev);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
+		ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
+					   IRQF_DISABLED);
+		if (ret < 0) {
+			isp1760_hcd_unregister(&isp->hcd);
+			return ret;
+		}
+	}
+
+	dev_set_drvdata(dev, isp);
+
+	return 0;
+}
+
+void isp1760_unregister(struct device *dev)
+{
+	struct isp1760_device *isp = dev_get_drvdata(dev);
+
+	isp1760_udc_unregister(isp);
+	isp1760_hcd_unregister(&isp->hcd);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
new file mode 100644
index 0000000..c70f836
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-core.h
@@ -0,0 +1,68 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ *	Sebastian Siewior <bigeasy@linutronix.de>
+ *	Laurent Pinchart <laurent.pinchart@ideasonboard.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 _ISP1760_CORE_H_
+#define _ISP1760_CORE_H_
+
+#include <linux/ioport.h>
+
+#include "isp1760-hcd.h"
+#include "isp1760-udc.h"
+
+struct device;
+struct gpio_desc;
+
+/*
+ * Device flags that can vary from board to board.  All of these
+ * indicate the most "atypical" case, so that a devflags of 0 is
+ * a sane default configuration.
+ */
+#define ISP1760_FLAG_BUS_WIDTH_16	0x00000002 /* 16-bit data bus width */
+#define ISP1760_FLAG_OTG_EN		0x00000004 /* Port 1 supports OTG */
+#define ISP1760_FLAG_ANALOG_OC		0x00000008 /* Analog overcurrent */
+#define ISP1760_FLAG_DACK_POL_HIGH	0x00000010 /* DACK active high */
+#define ISP1760_FLAG_DREQ_POL_HIGH	0x00000020 /* DREQ active high */
+#define ISP1760_FLAG_ISP1761		0x00000040 /* Chip is ISP1761 */
+#define ISP1760_FLAG_INTR_POL_HIGH	0x00000080 /* Interrupt polarity active high */
+#define ISP1760_FLAG_INTR_EDGE_TRIG	0x00000100 /* Interrupt edge triggered */
+
+struct isp1760_device {
+	struct device *dev;
+
+	void __iomem *regs;
+	unsigned int devflags;
+	struct gpio_desc *rst_gpio;
+
+	struct isp1760_hcd hcd;
+	struct isp1760_udc udc;
+};
+
+int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+		     struct device *dev, unsigned int devflags);
+void isp1760_unregister(struct device *dev);
+
+void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
+
+static inline u32 isp1760_read32(void __iomem *base, u32 reg)
+{
+	return readl(base + reg);
+}
+
+static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
+{
+	writel(val, base + reg);
+}
+
+#endif
diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
new file mode 100644
index 0000000..eba9b82
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-hcd.c
@@ -0,0 +1,2235 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
+ *
+ */
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <asm/unaligned.h>
+#include <asm/cacheflush.h>
+
+#include "isp1760-core.h"
+#include "isp1760-hcd.h"
+#include "isp1760-regs.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+static struct kmem_cache *urb_listitem_cachep;
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+		struct isp1760_qtd *qtd);
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+	return *(struct isp1760_hcd **)hcd->hcd_priv;
+}
+
+/* urb state*/
+#define DELETE_URB		(0x0008)
+#define NO_TRANSFER_ACTIVE	(0xffffffff)
+
+/* Philips Proprietary Transfer Descriptor (PTD) */
+typedef __u32 __bitwise __dw;
+struct ptd {
+	__dw dw0;
+	__dw dw1;
+	__dw dw2;
+	__dw dw3;
+	__dw dw4;
+	__dw dw5;
+	__dw dw6;
+	__dw dw7;
+};
+#define PTD_OFFSET		0x0400
+#define ISO_PTD_OFFSET		0x0400
+#define INT_PTD_OFFSET		0x0800
+#define ATL_PTD_OFFSET		0x0c00
+#define PAYLOAD_OFFSET		0x1000
+
+
+/* ATL */
+/* DW0 */
+#define DW0_VALID_BIT			1
+#define FROM_DW0_VALID(x)		((x) & 0x01)
+#define TO_DW0_LENGTH(x)		(((u32) x) << 3)
+#define TO_DW0_MAXPACKET(x)		(((u32) x) << 18)
+#define TO_DW0_MULTI(x)			(((u32) x) << 29)
+#define TO_DW0_ENDPOINT(x)		(((u32)	x) << 31)
+/* DW1 */
+#define TO_DW1_DEVICE_ADDR(x)		(((u32) x) << 3)
+#define TO_DW1_PID_TOKEN(x)		(((u32) x) << 10)
+#define DW1_TRANS_BULK			((u32) 2 << 12)
+#define DW1_TRANS_INT			((u32) 3 << 12)
+#define DW1_TRANS_SPLIT			((u32) 1 << 14)
+#define DW1_SE_USB_LOSPEED		((u32) 2 << 16)
+#define TO_DW1_PORT_NUM(x)		(((u32) x) << 18)
+#define TO_DW1_HUB_NUM(x)		(((u32) x) << 25)
+/* DW2 */
+#define TO_DW2_DATA_START_ADDR(x)	(((u32) x) << 8)
+#define TO_DW2_RL(x)			((x) << 25)
+#define FROM_DW2_RL(x)			(((x) >> 25) & 0xf)
+/* DW3 */
+#define FROM_DW3_NRBYTESTRANSFERRED(x)		((x) & 0x7fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x)	((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x)		((x) << 19)
+#define FROM_DW3_NAKCOUNT(x)		(((x) >> 19) & 0xf)
+#define TO_DW3_CERR(x)			((x) << 23)
+#define FROM_DW3_CERR(x)		(((x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x)		((x) << 25)
+#define FROM_DW3_DATA_TOGGLE(x)		(((x) >> 25) & 0x1)
+#define TO_DW3_PING(x)			((x) << 26)
+#define FROM_DW3_PING(x)		(((x) >> 26) & 0x1)
+#define DW3_ERROR_BIT			(1 << 28)
+#define DW3_BABBLE_BIT			(1 << 29)
+#define DW3_HALT_BIT			(1 << 30)
+#define DW3_ACTIVE_BIT			(1 << 31)
+#define FROM_DW3_ACTIVE(x)		(((x) >> 31) & 0x01)
+
+#define INT_UNDERRUN			(1 << 2)
+#define INT_BABBLE			(1 << 1)
+#define INT_EXACT			(1 << 0)
+
+#define SETUP_PID	(2)
+#define IN_PID		(1)
+#define OUT_PID		(0)
+
+/* Errata 1 */
+#define RL_COUNTER	(0)
+#define NAK_COUNTER	(0)
+#define ERR_COUNTER	(2)
+
+struct isp1760_qtd {
+	u8 packet_type;
+	void *data_buffer;
+	u32 payload_addr;
+
+	/* the rest is HCD-private */
+	struct list_head qtd_list;
+	struct urb *urb;
+	size_t length;
+	size_t actual_length;
+
+	/* QTD_ENQUEUED:	waiting for transfer (inactive) */
+	/* QTD_PAYLOAD_ALLOC:	chip mem has been allocated for payload */
+	/* QTD_XFER_STARTED:	valid ptd has been written to isp176x - only
+				interrupt handler may touch this qtd! */
+	/* QTD_XFER_COMPLETE:	payload has been transferred successfully */
+	/* QTD_RETIRE:		transfer error/abort qtd */
+#define QTD_ENQUEUED		0
+#define QTD_PAYLOAD_ALLOC	1
+#define QTD_XFER_STARTED	2
+#define QTD_XFER_COMPLETE	3
+#define QTD_RETIRE		4
+	u32 status;
+};
+
+/* Queue head, one for each active endpoint */
+struct isp1760_qh {
+	struct list_head qh_list;
+	struct list_head qtd_list;
+	u32 toggle;
+	u32 ping;
+	int slot;
+	int tt_buffer_dirty;	/* See USB2.0 spec section 11.17.5 */
+};
+
+struct urb_listitem {
+	struct list_head urb_list;
+	struct urb *urb;
+};
+
+/*
+ * Access functions for isp176x registers (addresses 0..0x03FF).
+ */
+static u32 reg_read32(void __iomem *base, u32 reg)
+{
+	return isp1760_read32(base, reg);
+}
+
+static void reg_write32(void __iomem *base, u32 reg, u32 val)
+{
+	isp1760_write32(base, reg, val);
+}
+
+/*
+ * Access functions for isp176x memory (offset >= 0x0400).
+ *
+ * bank_reads8() reads memory locations prefetched by an earlier write to
+ * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
+ * bank optimizations, you should use the more generic mem_reads8() below.
+ *
+ * For access to ptd memory, use the specialized ptd_read() and ptd_write()
+ * below.
+ *
+ * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
+							__u32 *dst, u32 bytes)
+{
+	__u32 __iomem *src;
+	u32 val;
+	__u8 *src_byteptr;
+	__u8 *dst_byteptr;
+
+	src = src_base + (bank_addr | src_offset);
+
+	if (src_offset < PAYLOAD_OFFSET) {
+		while (bytes >= 4) {
+			*dst = le32_to_cpu(__raw_readl(src));
+			bytes -= 4;
+			src++;
+			dst++;
+		}
+	} else {
+		while (bytes >= 4) {
+			*dst = __raw_readl(src);
+			bytes -= 4;
+			src++;
+			dst++;
+		}
+	}
+
+	if (!bytes)
+		return;
+
+	/* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+	 * allocated.
+	 */
+	if (src_offset < PAYLOAD_OFFSET)
+		val = le32_to_cpu(__raw_readl(src));
+	else
+		val = __raw_readl(src);
+
+	dst_byteptr = (void *) dst;
+	src_byteptr = (void *) &val;
+	while (bytes > 0) {
+		*dst_byteptr = *src_byteptr;
+		dst_byteptr++;
+		src_byteptr++;
+		bytes--;
+	}
+}
+
+static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
+								u32 bytes)
+{
+	reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
+	ndelay(90);
+	bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
+}
+
+static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+						__u32 const *src, u32 bytes)
+{
+	__u32 __iomem *dst;
+
+	dst = dst_base + dst_offset;
+
+	if (dst_offset < PAYLOAD_OFFSET) {
+		while (bytes >= 4) {
+			__raw_writel(cpu_to_le32(*src), dst);
+			bytes -= 4;
+			src++;
+			dst++;
+		}
+	} else {
+		while (bytes >= 4) {
+			__raw_writel(*src, dst);
+			bytes -= 4;
+			src++;
+			dst++;
+		}
+	}
+
+	if (!bytes)
+		return;
+	/* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the
+	 * extra bytes should not be read by the HW.
+	 */
+
+	if (dst_offset < PAYLOAD_OFFSET)
+		__raw_writel(cpu_to_le32(*src), dst);
+	else
+		__raw_writel(*src, dst);
+}
+
+/*
+ * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
+ * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
+ */
+static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
+								struct ptd *ptd)
+{
+	reg_write32(base, HC_MEMORY_REG,
+				ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
+	ndelay(90);
+	bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
+						(void *) ptd, sizeof(*ptd));
+}
+
+static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+								struct ptd *ptd)
+{
+	mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
+						&ptd->dw1, 7*sizeof(ptd->dw1));
+	/* Make sure dw0 gets written last (after other dw's and after payload)
+	   since it contains the enable bit */
+	wmb();
+	mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
+							sizeof(ptd->dw0));
+}
+
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+	int i, curr;
+	u32 payload_addr;
+
+	payload_addr = PAYLOAD_OFFSET;
+	for (i = 0; i < BLOCK_1_NUM; i++) {
+		priv->memory_pool[i].start = payload_addr;
+		priv->memory_pool[i].size = BLOCK_1_SIZE;
+		priv->memory_pool[i].free = 1;
+		payload_addr += priv->memory_pool[i].size;
+	}
+
+	curr = i;
+	for (i = 0; i < BLOCK_2_NUM; i++) {
+		priv->memory_pool[curr + i].start = payload_addr;
+		priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
+		priv->memory_pool[curr + i].free = 1;
+		payload_addr += priv->memory_pool[curr + i].size;
+	}
+
+	curr = i;
+	for (i = 0; i < BLOCK_3_NUM; i++) {
+		priv->memory_pool[curr + i].start = payload_addr;
+		priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
+		priv->memory_pool[curr + i].free = 1;
+		payload_addr += priv->memory_pool[curr + i].size;
+	}
+
+	WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+}
+
+static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int i;
+
+	WARN_ON(qtd->payload_addr);
+
+	if (!qtd->length)
+		return;
+
+	for (i = 0; i < BLOCKS; i++) {
+		if (priv->memory_pool[i].size >= qtd->length &&
+				priv->memory_pool[i].free) {
+			priv->memory_pool[i].free = 0;
+			qtd->payload_addr = priv->memory_pool[i].start;
+			return;
+		}
+	}
+}
+
+static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int i;
+
+	if (!qtd->payload_addr)
+		return;
+
+	for (i = 0; i < BLOCKS; i++) {
+		if (priv->memory_pool[i].start == qtd->payload_addr) {
+			WARN_ON(priv->memory_pool[i].free);
+			priv->memory_pool[i].free = 1;
+			qtd->payload_addr = 0;
+			return;
+		}
+	}
+
+	dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
+						__func__, qtd->payload_addr);
+	WARN_ON(1);
+	qtd->payload_addr = 0;
+}
+
+static int handshake(struct usb_hcd *hcd, u32 reg,
+		      u32 mask, u32 done, int usec)
+{
+	u32 result;
+
+	do {
+		result = reg_read32(hcd->regs, reg);
+		if (result == ~0)
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay(1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct usb_hcd *hcd)
+{
+	int retval;
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+	u32 command = reg_read32(hcd->regs, HC_USBCMD);
+
+	command |= CMD_RESET;
+	reg_write32(hcd->regs, HC_USBCMD, command);
+	hcd->state = HC_STATE_HALT;
+	priv->next_statechange = jiffies;
+	retval = handshake(hcd, HC_USBCMD,
+			    CMD_RESET, 0, 250 * 1000);
+	return retval;
+}
+
+static struct isp1760_qh *qh_alloc(gfp_t flags)
+{
+	struct isp1760_qh *qh;
+
+	qh = kmem_cache_zalloc(qh_cachep, flags);
+	if (!qh)
+		return NULL;
+
+	INIT_LIST_HEAD(&qh->qh_list);
+	INIT_LIST_HEAD(&qh->qtd_list);
+	qh->slot = -1;
+
+	return qh;
+}
+
+static void qh_free(struct isp1760_qh *qh)
+{
+	WARN_ON(!list_empty(&qh->qtd_list));
+	WARN_ON(qh->slot > -1);
+	kmem_cache_free(qh_cachep, qh);
+}
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd		*priv = hcd_to_priv(hcd);
+	u32			hcc_params;
+	int i;
+
+	spin_lock_init(&priv->lock);
+
+	for (i = 0; i < QH_END; i++)
+		INIT_LIST_HEAD(&priv->qh_list[i]);
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	priv->periodic_size = DEFAULT_I_TDPS;
+
+	/* controllers may cache some of the periodic schedule ... */
+	hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
+	/* full frame cache */
+	if (HCC_ISOC_CACHE(hcc_params))
+		priv->i_thresh = 8;
+	else /* N microframes cached */
+		priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+	return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int result;
+	u32 scratch, hwmode;
+
+	reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
+	/* Change bus pattern */
+	scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+	scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
+	if (scratch != 0xdeadbabe) {
+		dev_err(hcd->self.controller, "Scratch test failed.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * The RESET_HC bit in the SW_RESET register is supposed to reset the
+	 * host controller without touching the CPU interface registers, but at
+	 * least on the ISP1761 it seems to behave as the RESET_ALL bit and
+	 * reset the whole device. We thus can't use it here, so let's reset
+	 * the host controller through the EHCI USB Command register. The device
+	 * has been reset in core code anyway, so this shouldn't matter.
+	 */
+	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
+	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+
+	result = ehci_reset(hcd);
+	if (result)
+		return result;
+
+	/* Step 11 passed */
+
+	/* ATL reset */
+	hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
+	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
+	mdelay(10);
+	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
+
+	reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
+
+	priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
+
+	return priv_init(hcd);
+}
+
+static u32 base_to_chip(u32 base)
+{
+	return ((base - 0x400) >> 3);
+}
+
+static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
+{
+	struct urb *urb;
+
+	if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
+		return 1;
+
+	urb = qtd->urb;
+	qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list);
+	return (qtd->urb != urb);
+}
+
+/* magic numbers that can affect system performance */
+#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
+#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
+#define	EHCI_TUNE_RL_TT		0
+#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	EHCI_TUNE_MULT_TT	1
+#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
+
+static void create_ptd_atl(struct isp1760_qh *qh,
+			struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+	u32 maxpacket;
+	u32 multi;
+	u32 rl = RL_COUNTER;
+	u32 nak = NAK_COUNTER;
+
+	memset(ptd, 0, sizeof(*ptd));
+
+	/* according to 3.6.2, max packet len can not be > 0x400 */
+	maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe,
+						usb_pipeout(qtd->urb->pipe));
+	multi =  1 + ((maxpacket >> 11) & 0x3);
+	maxpacket &= 0x7ff;
+
+	/* DW0 */
+	ptd->dw0 = DW0_VALID_BIT;
+	ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
+	ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
+	ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
+
+	/* DW1 */
+	ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
+	ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
+	ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
+
+	if (usb_pipebulk(qtd->urb->pipe))
+		ptd->dw1 |= DW1_TRANS_BULK;
+	else if  (usb_pipeint(qtd->urb->pipe))
+		ptd->dw1 |= DW1_TRANS_INT;
+
+	if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
+		/* split transaction */
+
+		ptd->dw1 |= DW1_TRANS_SPLIT;
+		if (qtd->urb->dev->speed == USB_SPEED_LOW)
+			ptd->dw1 |= DW1_SE_USB_LOSPEED;
+
+		ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
+		ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
+
+		/* SE bit for Split INT transfers */
+		if (usb_pipeint(qtd->urb->pipe) &&
+				(qtd->urb->dev->speed == USB_SPEED_LOW))
+			ptd->dw1 |= 2 << 16;
+
+		rl = 0;
+		nak = 0;
+	} else {
+		ptd->dw0 |= TO_DW0_MULTI(multi);
+		if (usb_pipecontrol(qtd->urb->pipe) ||
+						usb_pipebulk(qtd->urb->pipe))
+			ptd->dw3 |= TO_DW3_PING(qh->ping);
+	}
+	/* DW2 */
+	ptd->dw2 = 0;
+	ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
+	ptd->dw2 |= TO_DW2_RL(rl);
+
+	/* DW3 */
+	ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
+	ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
+	if (usb_pipecontrol(qtd->urb->pipe)) {
+		if (qtd->data_buffer == qtd->urb->setup_packet)
+			ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
+		else if (last_qtd_of_urb(qtd, qh))
+			ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
+	}
+
+	ptd->dw3 |= DW3_ACTIVE_BIT;
+	/* Cerr */
+	ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
+}
+
+static void transform_add_int(struct isp1760_qh *qh,
+			struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+	u32 usof;
+	u32 period;
+
+	/*
+	 * Most of this is guessing. ISP1761 datasheet is quite unclear, and
+	 * the algorithm from the original Philips driver code, which was
+	 * pretty much used in this driver before as well, is quite horrendous
+	 * and, i believe, incorrect. The code below follows the datasheet and
+	 * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
+	 * more reliable this way (fingers crossed...).
+	 */
+
+	if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
+		/* urb->interval is in units of microframes (1/8 ms) */
+		period = qtd->urb->interval >> 3;
+
+		if (qtd->urb->interval > 4)
+			usof = 0x01; /* One bit set =>
+						interval 1 ms * uFrame-match */
+		else if (qtd->urb->interval > 2)
+			usof = 0x22; /* Two bits set => interval 1/2 ms */
+		else if (qtd->urb->interval > 1)
+			usof = 0x55; /* Four bits set => interval 1/4 ms */
+		else
+			usof = 0xff; /* All bits set => interval 1/8 ms */
+	} else {
+		/* urb->interval is in units of frames (1 ms) */
+		period = qtd->urb->interval;
+		usof = 0x0f;		/* Execute Start Split on any of the
+					   four first uFrames */
+
+		/*
+		 * First 8 bits in dw5 is uSCS and "specifies which uSOF the
+		 * complete split needs to be sent. Valid only for IN." Also,
+		 * "All bits can be set to one for every transfer." (p 82,
+		 * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
+		 * that number come from? 0xff seems to work fine...
+		 */
+		/* ptd->dw5 = 0x1c; */
+		ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
+	}
+
+	period = period >> 1;/* Ensure equal or shorter period than requested */
+	period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
+
+	ptd->dw2 |= period;
+	ptd->dw4 = usof;
+}
+
+static void create_ptd_int(struct isp1760_qh *qh,
+			struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+	create_ptd_atl(qh, qtd, ptd);
+	transform_add_int(qh, qtd, ptd);
+}
+
+static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+	if (!urb->unlinked) {
+		if (urb->status == -EINPROGRESS)
+			urb->status = 0;
+	}
+
+	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+		void *ptr;
+		for (ptr = urb->transfer_buffer;
+		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+		     ptr += PAGE_SIZE)
+			flush_dcache_page(virt_to_page(ptr));
+	}
+
+	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock(&priv->lock);
+	usb_hcd_giveback_urb(hcd, urb, urb->status);
+	spin_lock(&priv->lock);
+}
+
+static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
+								u8 packet_type)
+{
+	struct isp1760_qtd *qtd;
+
+	qtd = kmem_cache_zalloc(qtd_cachep, flags);
+	if (!qtd)
+		return NULL;
+
+	INIT_LIST_HEAD(&qtd->qtd_list);
+	qtd->urb = urb;
+	qtd->packet_type = packet_type;
+	qtd->status = QTD_ENQUEUED;
+	qtd->actual_length = 0;
+
+	return qtd;
+}
+
+static void qtd_free(struct isp1760_qtd *qtd)
+{
+	WARN_ON(qtd->payload_addr);
+	kmem_cache_free(qtd_cachep, qtd);
+}
+
+static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+				struct isp1760_slotinfo *slots,
+				struct isp1760_qtd *qtd, struct isp1760_qh *qh,
+				struct ptd *ptd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int skip_map;
+
+	WARN_ON((slot < 0) || (slot > 31));
+	WARN_ON(qtd->length && !qtd->payload_addr);
+	WARN_ON(slots[slot].qtd);
+	WARN_ON(slots[slot].qh);
+	WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+
+	/* Make sure done map has not triggered from some unlinked transfer */
+	if (ptd_offset == ATL_PTD_OFFSET) {
+		priv->atl_done_map |= reg_read32(hcd->regs,
+						HC_ATL_PTD_DONEMAP_REG);
+		priv->atl_done_map &= ~(1 << slot);
+	} else {
+		priv->int_done_map |= reg_read32(hcd->regs,
+						HC_INT_PTD_DONEMAP_REG);
+		priv->int_done_map &= ~(1 << slot);
+	}
+
+	qh->slot = slot;
+	qtd->status = QTD_XFER_STARTED;
+	slots[slot].timestamp = jiffies;
+	slots[slot].qtd = qtd;
+	slots[slot].qh = qh;
+	ptd_write(hcd->regs, ptd_offset, slot, ptd);
+
+	if (ptd_offset == ATL_PTD_OFFSET) {
+		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+		skip_map &= ~(1 << qh->slot);
+		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+	} else {
+		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+		skip_map &= ~(1 << qh->slot);
+		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+	}
+}
+
+static int is_short_bulk(struct isp1760_qtd *qtd)
+{
+	return (usb_pipebulk(qtd->urb->pipe) &&
+					(qtd->actual_length < qtd->length));
+}
+
+static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+						struct list_head *urb_list)
+{
+	int last_qtd;
+	struct isp1760_qtd *qtd, *qtd_next;
+	struct urb_listitem *urb_listitem;
+
+	list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
+		if (qtd->status < QTD_XFER_COMPLETE)
+			break;
+
+		last_qtd = last_qtd_of_urb(qtd, qh);
+
+		if ((!last_qtd) && (qtd->status == QTD_RETIRE))
+			qtd_next->status = QTD_RETIRE;
+
+		if (qtd->status == QTD_XFER_COMPLETE) {
+			if (qtd->actual_length) {
+				switch (qtd->packet_type) {
+				case IN_PID:
+					mem_reads8(hcd->regs, qtd->payload_addr,
+							qtd->data_buffer,
+							qtd->actual_length);
+					/* Fall through (?) */
+				case OUT_PID:
+					qtd->urb->actual_length +=
+							qtd->actual_length;
+					/* Fall through ... */
+				case SETUP_PID:
+					break;
+				}
+			}
+
+			if (is_short_bulk(qtd)) {
+				if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
+					qtd->urb->status = -EREMOTEIO;
+				if (!last_qtd)
+					qtd_next->status = QTD_RETIRE;
+			}
+		}
+
+		if (qtd->payload_addr)
+			free_mem(hcd, qtd);
+
+		if (last_qtd) {
+			if ((qtd->status == QTD_RETIRE) &&
+					(qtd->urb->status == -EINPROGRESS))
+				qtd->urb->status = -EPIPE;
+			/* Defer calling of urb_done() since it releases lock */
+			urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
+								GFP_ATOMIC);
+			if (unlikely(!urb_listitem))
+				break; /* Try again on next call */
+			urb_listitem->urb = qtd->urb;
+			list_add_tail(&urb_listitem->urb_list, urb_list);
+		}
+
+		list_del(&qtd->qtd_list);
+		qtd_free(qtd);
+	}
+}
+
+#define ENQUEUE_DEPTH	2
+static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int ptd_offset;
+	struct isp1760_slotinfo *slots;
+	int curr_slot, free_slot;
+	int n;
+	struct ptd ptd;
+	struct isp1760_qtd *qtd;
+
+	if (unlikely(list_empty(&qh->qtd_list))) {
+		WARN_ON(1);
+		return;
+	}
+
+	/* Make sure this endpoint's TT buffer is clean before queueing ptds */
+	if (qh->tt_buffer_dirty)
+		return;
+
+	if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
+							qtd_list)->urb->pipe)) {
+		ptd_offset = INT_PTD_OFFSET;
+		slots = priv->int_slots;
+	} else {
+		ptd_offset = ATL_PTD_OFFSET;
+		slots = priv->atl_slots;
+	}
+
+	free_slot = -1;
+	for (curr_slot = 0; curr_slot < 32; curr_slot++) {
+		if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
+			free_slot = curr_slot;
+		if (slots[curr_slot].qh == qh)
+			break;
+	}
+
+	n = 0;
+	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
+		if (qtd->status == QTD_ENQUEUED) {
+			WARN_ON(qtd->payload_addr);
+			alloc_mem(hcd, qtd);
+			if ((qtd->length) && (!qtd->payload_addr))
+				break;
+
+			if ((qtd->length) &&
+			    ((qtd->packet_type == SETUP_PID) ||
+			     (qtd->packet_type == OUT_PID))) {
+				mem_writes8(hcd->regs, qtd->payload_addr,
+						qtd->data_buffer, qtd->length);
+			}
+
+			qtd->status = QTD_PAYLOAD_ALLOC;
+		}
+
+		if (qtd->status == QTD_PAYLOAD_ALLOC) {
+/*
+			if ((curr_slot > 31) && (free_slot == -1))
+				dev_dbg(hcd->self.controller, "%s: No slot "
+					"available for transfer\n", __func__);
+*/
+			/* Start xfer for this endpoint if not already done */
+			if ((curr_slot > 31) && (free_slot > -1)) {
+				if (usb_pipeint(qtd->urb->pipe))
+					create_ptd_int(qh, qtd, &ptd);
+				else
+					create_ptd_atl(qh, qtd, &ptd);
+
+				start_bus_transfer(hcd, ptd_offset, free_slot,
+							slots, qtd, qh, &ptd);
+				curr_slot = free_slot;
+			}
+
+			n++;
+			if (n >= ENQUEUE_DEPTH)
+				break;
+		}
+	}
+}
+
+static void schedule_ptds(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv;
+	struct isp1760_qh *qh, *qh_next;
+	struct list_head *ep_queue;
+	LIST_HEAD(urb_list);
+	struct urb_listitem *urb_listitem, *urb_listitem_next;
+	int i;
+
+	if (!hcd) {
+		WARN_ON(1);
+		return;
+	}
+
+	priv = hcd_to_priv(hcd);
+
+	/*
+	 * check finished/retired xfers, transfer payloads, call urb_done()
+	 */
+	for (i = 0; i < QH_END; i++) {
+		ep_queue = &priv->qh_list[i];
+		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
+			collect_qtds(hcd, qh, &urb_list);
+			if (list_empty(&qh->qtd_list))
+				list_del(&qh->qh_list);
+		}
+	}
+
+	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
+								urb_list) {
+		isp1760_urb_done(hcd, urb_listitem->urb);
+		kmem_cache_free(urb_listitem_cachep, urb_listitem);
+	}
+
+	/*
+	 * Schedule packets for transfer.
+	 *
+	 * According to USB2.0 specification:
+	 *
+	 * 1st prio: interrupt xfers, up to 80 % of bandwidth
+	 * 2nd prio: control xfers
+	 * 3rd prio: bulk xfers
+	 *
+	 * ... but let's use a simpler scheme here (mostly because ISP1761 doc
+	 * is very unclear on how to prioritize traffic):
+	 *
+	 * 1) Enqueue any queued control transfers, as long as payload chip mem
+	 *    and PTD ATL slots are available.
+	 * 2) Enqueue any queued INT transfers, as long as payload chip mem
+	 *    and PTD INT slots are available.
+	 * 3) Enqueue any queued bulk transfers, as long as payload chip mem
+	 *    and PTD ATL slots are available.
+	 *
+	 * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
+	 * conservation of chip mem and performance.
+	 *
+	 * I'm sure this scheme could be improved upon!
+	 */
+	for (i = 0; i < QH_END; i++) {
+		ep_queue = &priv->qh_list[i];
+		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
+			enqueue_qtds(hcd, qh);
+	}
+}
+
+#define PTD_STATE_QTD_DONE	1
+#define PTD_STATE_QTD_RELOAD	2
+#define PTD_STATE_URB_RETIRE	3
+
+static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+								struct urb *urb)
+{
+	__dw dw4;
+	int i;
+
+	dw4 = ptd->dw4;
+	dw4 >>= 8;
+
+	/* FIXME: ISP1761 datasheet does not say what to do with these. Do we
+	   need to handle these errors? Is it done in hardware? */
+
+	if (ptd->dw3 & DW3_HALT_BIT) {
+
+		urb->status = -EPROTO; /* Default unknown error */
+
+		for (i = 0; i < 8; i++) {
+			switch (dw4 & 0x7) {
+			case INT_UNDERRUN:
+				dev_dbg(hcd->self.controller, "%s: underrun "
+						"during uFrame %d\n",
+						__func__, i);
+				urb->status = -ECOMM; /* Could not write data */
+				break;
+			case INT_EXACT:
+				dev_dbg(hcd->self.controller, "%s: transaction "
+						"error during uFrame %d\n",
+						__func__, i);
+				urb->status = -EPROTO; /* timeout, bad CRC, PID
+							  error etc. */
+				break;
+			case INT_BABBLE:
+				dev_dbg(hcd->self.controller, "%s: babble "
+						"error during uFrame %d\n",
+						__func__, i);
+				urb->status = -EOVERFLOW;
+				break;
+			}
+			dw4 >>= 3;
+		}
+
+		return PTD_STATE_URB_RETIRE;
+	}
+
+	return PTD_STATE_QTD_DONE;
+}
+
+static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+								struct urb *urb)
+{
+	WARN_ON(!ptd);
+	if (ptd->dw3 & DW3_HALT_BIT) {
+		if (ptd->dw3 & DW3_BABBLE_BIT)
+			urb->status = -EOVERFLOW;
+		else if (FROM_DW3_CERR(ptd->dw3))
+			urb->status = -EPIPE;  /* Stall */
+		else if (ptd->dw3 & DW3_ERROR_BIT)
+			urb->status = -EPROTO; /* XactErr */
+		else
+			urb->status = -EPROTO; /* Unknown */
+/*
+		dev_dbg(hcd->self.controller, "%s: ptd error:\n"
+			"        dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
+			"        dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
+			__func__,
+			ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
+			ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
+*/
+		return PTD_STATE_URB_RETIRE;
+	}
+
+	if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+		/* Transfer Error, *but* active and no HALT -> reload */
+		dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
+		return PTD_STATE_QTD_RELOAD;
+	}
+
+	if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+		/*
+		 * NAKs are handled in HW by the chip. Usually if the
+		 * device is not able to send data fast enough.
+		 * This happens mostly on slower hardware.
+		 */
+		return PTD_STATE_QTD_RELOAD;
+	}
+
+	return PTD_STATE_QTD_DONE;
+}
+
+static void handle_done_ptds(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	struct ptd ptd;
+	struct isp1760_qh *qh;
+	int slot;
+	int state;
+	struct isp1760_slotinfo *slots;
+	u32 ptd_offset;
+	struct isp1760_qtd *qtd;
+	int modified;
+	int skip_map;
+
+	skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+	priv->int_done_map &= ~skip_map;
+	skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+	priv->atl_done_map &= ~skip_map;
+
+	modified = priv->int_done_map || priv->atl_done_map;
+
+	while (priv->int_done_map || priv->atl_done_map) {
+		if (priv->int_done_map) {
+			/* INT ptd */
+			slot = __ffs(priv->int_done_map);
+			priv->int_done_map &= ~(1 << slot);
+			slots = priv->int_slots;
+			/* This should not trigger, and could be removed if
+			   noone have any problems with it triggering: */
+			if (!slots[slot].qh) {
+				WARN_ON(1);
+				continue;
+			}
+			ptd_offset = INT_PTD_OFFSET;
+			ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
+			state = check_int_transfer(hcd, &ptd,
+							slots[slot].qtd->urb);
+		} else {
+			/* ATL ptd */
+			slot = __ffs(priv->atl_done_map);
+			priv->atl_done_map &= ~(1 << slot);
+			slots = priv->atl_slots;
+			/* This should not trigger, and could be removed if
+			   noone have any problems with it triggering: */
+			if (!slots[slot].qh) {
+				WARN_ON(1);
+				continue;
+			}
+			ptd_offset = ATL_PTD_OFFSET;
+			ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+			state = check_atl_transfer(hcd, &ptd,
+							slots[slot].qtd->urb);
+		}
+
+		qtd = slots[slot].qtd;
+		slots[slot].qtd = NULL;
+		qh = slots[slot].qh;
+		slots[slot].qh = NULL;
+		qh->slot = -1;
+
+		WARN_ON(qtd->status != QTD_XFER_STARTED);
+
+		switch (state) {
+		case PTD_STATE_QTD_DONE:
+			if ((usb_pipeint(qtd->urb->pipe)) &&
+				       (qtd->urb->dev->speed != USB_SPEED_HIGH))
+				qtd->actual_length =
+				       FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
+			else
+				qtd->actual_length =
+					FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
+
+			qtd->status = QTD_XFER_COMPLETE;
+			if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
+							is_short_bulk(qtd))
+				qtd = NULL;
+			else
+				qtd = list_entry(qtd->qtd_list.next,
+							typeof(*qtd), qtd_list);
+
+			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+			qh->ping = FROM_DW3_PING(ptd.dw3);
+			break;
+
+		case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
+			qtd->status = QTD_PAYLOAD_ALLOC;
+			ptd.dw0 |= DW0_VALID_BIT;
+			/* RL counter = ERR counter */
+			ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
+			ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
+			ptd.dw3 &= ~TO_DW3_CERR(3);
+			ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
+			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+			qh->ping = FROM_DW3_PING(ptd.dw3);
+			break;
+
+		case PTD_STATE_URB_RETIRE:
+			qtd->status = QTD_RETIRE;
+			if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
+					(qtd->urb->status != -EPIPE) &&
+					(qtd->urb->status != -EREMOTEIO)) {
+				qh->tt_buffer_dirty = 1;
+				if (usb_hub_clear_tt_buffer(qtd->urb))
+					/* Clear failed; let's hope things work
+					   anyway */
+					qh->tt_buffer_dirty = 0;
+			}
+			qtd = NULL;
+			qh->toggle = 0;
+			qh->ping = 0;
+			break;
+
+		default:
+			WARN_ON(1);
+			continue;
+		}
+
+		if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
+			if (slots == priv->int_slots) {
+				if (state == PTD_STATE_QTD_RELOAD)
+					dev_err(hcd->self.controller,
+						"%s: PTD_STATE_QTD_RELOAD on "
+						"interrupt packet\n", __func__);
+				if (state != PTD_STATE_QTD_RELOAD)
+					create_ptd_int(qh, qtd, &ptd);
+			} else {
+				if (state != PTD_STATE_QTD_RELOAD)
+					create_ptd_atl(qh, qtd, &ptd);
+			}
+
+			start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
+				qh, &ptd);
+		}
+	}
+
+	if (modified)
+		schedule_ptds(hcd);
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	u32 imask;
+	irqreturn_t irqret = IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	if (!(hcd->state & HC_STATE_RUNNING))
+		goto leave;
+
+	imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+	if (unlikely(!imask))
+		goto leave;
+	reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+
+	priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+	priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+
+	handle_done_ptds(hcd);
+
+	irqret = IRQ_HANDLED;
+leave:
+	spin_unlock(&priv->lock);
+
+	return irqret;
+}
+
+/*
+ * Workaround for problem described in chip errata 2:
+ *
+ * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
+ * One solution suggested in the errata is to use SOF interrupts _instead_of_
+ * ATL done interrupts (the "instead of" might be important since it seems
+ * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
+ * to set the PTD's done bit in addition to not generating an interrupt!).
+ *
+ * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
+ * done bit is not being set. This is bad - it blocks the endpoint until reboot.
+ *
+ * If we use SOF interrupts only, we get latency between ptd completion and the
+ * actual handling. This is very noticeable in testusb runs which takes several
+ * minutes longer without ATL interrupts.
+ *
+ * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
+ * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
+ * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
+ * completed and its done map bit is set.
+ *
+ * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
+ * not to cause too much lag when this HW bug occurs, while still hopefully
+ * ensuring that the check does not falsely trigger.
+ */
+#define SLOT_TIMEOUT 300
+#define SLOT_CHECK_PERIOD 200
+static struct timer_list errata2_timer;
+
+static void errata2_function(unsigned long data)
+{
+	struct usb_hcd *hcd = (struct usb_hcd *) data;
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int slot;
+	struct ptd ptd;
+	unsigned long spinflags;
+
+	spin_lock_irqsave(&priv->lock, spinflags);
+
+	for (slot = 0; slot < 32; slot++)
+		if (priv->atl_slots[slot].qh && time_after(jiffies,
+					priv->atl_slots[slot].timestamp +
+					SLOT_TIMEOUT * HZ / 1000)) {
+			ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+			if (!FROM_DW0_VALID(ptd.dw0) &&
+					!FROM_DW3_ACTIVE(ptd.dw3))
+				priv->atl_done_map |= 1 << slot;
+		}
+
+	if (priv->atl_done_map)
+		handle_done_ptds(hcd);
+
+	spin_unlock_irqrestore(&priv->lock, spinflags);
+
+	errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+	add_timer(&errata2_timer);
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+	int retval;
+	u32 temp;
+	u32 command;
+	u32 chipid;
+
+	hcd->uses_new_polling = 1;
+
+	hcd->state = HC_STATE_RUNNING;
+
+	/* Set PTD interrupt AND & OR maps */
+	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
+	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
+	reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
+	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
+	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
+	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+	/* step 23 passed */
+
+	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+
+	command = reg_read32(hcd->regs, HC_USBCMD);
+	command &= ~(CMD_LRESET|CMD_RESET);
+	command |= CMD_RUN;
+	reg_write32(hcd->regs, HC_USBCMD, command);
+
+	retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+	if (retval)
+		return retval;
+
+	/*
+	 * XXX
+	 * Spec says to write FLAG_CF as last config action, priv code grabs
+	 * the semaphore while doing so.
+	 */
+	down_write(&ehci_cf_port_reset_rwsem);
+	reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
+
+	retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+	up_write(&ehci_cf_port_reset_rwsem);
+	if (retval)
+		return retval;
+
+	setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd);
+	errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+	add_timer(&errata2_timer);
+
+	chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+	dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+					chipid & 0xffff, chipid >> 16);
+
+	/* PTD Register Init Part 2, Step 28 */
+
+	/* Setup registers controlling PTD checking */
+	reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
+	reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
+	reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+						ATL_BUF_FILL | INT_BUF_FILL);
+
+	/* GRR this is run-once init(), being done every time the HC starts.
+	 * So long as they're part of class devices, we can't do it init()
+	 * since the class device isn't created that early.
+	 */
+	return 0;
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
+{
+	qtd->data_buffer = databuffer;
+
+	if (len > MAX_PAYLOAD_SIZE)
+		len = MAX_PAYLOAD_SIZE;
+	qtd->length = len;
+
+	return qtd->length;
+}
+
+static void qtd_list_free(struct list_head *qtd_list)
+{
+	struct isp1760_qtd *qtd, *qtd_next;
+
+	list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
+		list_del(&qtd->qtd_list);
+		qtd_free(qtd);
+	}
+}
+
+/*
+ * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
+ * Also calculate the PID type (SETUP/IN/OUT) for each packet.
+ */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static void packetize_urb(struct usb_hcd *hcd,
+		struct urb *urb, struct list_head *head, gfp_t flags)
+{
+	struct isp1760_qtd *qtd;
+	void *buf;
+	int len, maxpacketsize;
+	u8 packet_type;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+
+	if (!urb->transfer_buffer && urb->transfer_buffer_length) {
+		/* XXX This looks like usb storage / SCSI bug */
+		dev_err(hcd->self.controller,
+				"buf is null, dma is %08lx len is %d\n",
+				(long unsigned)urb->transfer_dma,
+				urb->transfer_buffer_length);
+		WARN_ON(1);
+	}
+
+	if (usb_pipein(urb->pipe))
+		packet_type = IN_PID;
+	else
+		packet_type = OUT_PID;
+
+	if (usb_pipecontrol(urb->pipe)) {
+		qtd = qtd_alloc(flags, urb, SETUP_PID);
+		if (!qtd)
+			goto cleanup;
+		qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
+		list_add_tail(&qtd->qtd_list, head);
+
+		/* for zero length DATA stages, STATUS is always IN */
+		if (urb->transfer_buffer_length == 0)
+			packet_type = IN_PID;
+	}
+
+	maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
+						usb_pipeout(urb->pipe)));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	buf = urb->transfer_buffer;
+	len = urb->transfer_buffer_length;
+
+	for (;;) {
+		int this_qtd_len;
+
+		qtd = qtd_alloc(flags, urb, packet_type);
+		if (!qtd)
+			goto cleanup;
+		this_qtd_len = qtd_fill(qtd, buf, len);
+		list_add_tail(&qtd->qtd_list, head);
+
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+
+		if (len <= 0)
+			break;
+	}
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (urb->transfer_buffer_length != 0) {
+		int one_more = 0;
+
+		if (usb_pipecontrol(urb->pipe)) {
+			one_more = 1;
+			if (packet_type == IN_PID)
+				packet_type = OUT_PID;
+			else
+				packet_type = IN_PID;
+		} else if (usb_pipebulk(urb->pipe)
+				&& (urb->transfer_flags & URB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length %
+							maxpacketsize)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd = qtd_alloc(flags, urb, packet_type);
+			if (!qtd)
+				goto cleanup;
+
+			/* never any data in such packets */
+			qtd_fill(qtd, NULL, 0);
+			list_add_tail(&qtd->qtd_list, head);
+		}
+	}
+
+	return;
+
+cleanup:
+	qtd_list_free(head);
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t mem_flags)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	struct list_head *ep_queue;
+	struct isp1760_qh *qh, *qhit;
+	unsigned long spinflags;
+	LIST_HEAD(new_qtds);
+	int retval;
+	int qh_in_queue;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ep_queue = &priv->qh_list[QH_CONTROL];
+		break;
+	case PIPE_BULK:
+		ep_queue = &priv->qh_list[QH_BULK];
+		break;
+	case PIPE_INTERRUPT:
+		if (urb->interval < 0)
+			return -EINVAL;
+		/* FIXME: Check bandwidth  */
+		ep_queue = &priv->qh_list[QH_INTERRUPT];
+		break;
+	case PIPE_ISOCHRONOUS:
+		dev_err(hcd->self.controller, "%s: isochronous USB packets "
+							"not yet supported\n",
+							__func__);
+		return -EPIPE;
+	default:
+		dev_err(hcd->self.controller, "%s: unknown pipe type\n",
+							__func__);
+		return -EPIPE;
+	}
+
+	if (usb_pipein(urb->pipe))
+		urb->actual_length = 0;
+
+	packetize_urb(hcd, urb, &new_qtds, mem_flags);
+	if (list_empty(&new_qtds))
+		return -ENOMEM;
+
+	retval = 0;
+	spin_lock_irqsave(&priv->lock, spinflags);
+
+	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+		retval = -ESHUTDOWN;
+		qtd_list_free(&new_qtds);
+		goto out;
+	}
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval) {
+		qtd_list_free(&new_qtds);
+		goto out;
+	}
+
+	qh = urb->ep->hcpriv;
+	if (qh) {
+		qh_in_queue = 0;
+		list_for_each_entry(qhit, ep_queue, qh_list) {
+			if (qhit == qh) {
+				qh_in_queue = 1;
+				break;
+			}
+		}
+		if (!qh_in_queue)
+			list_add_tail(&qh->qh_list, ep_queue);
+	} else {
+		qh = qh_alloc(GFP_ATOMIC);
+		if (!qh) {
+			retval = -ENOMEM;
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			qtd_list_free(&new_qtds);
+			goto out;
+		}
+		list_add_tail(&qh->qh_list, ep_queue);
+		urb->ep->hcpriv = qh;
+	}
+
+	list_splice_tail(&new_qtds, &qh->qtd_list);
+	schedule_ptds(hcd);
+
+out:
+	spin_unlock_irqrestore(&priv->lock, spinflags);
+	return retval;
+}
+
+static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
+		struct isp1760_qh *qh)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int skip_map;
+
+	WARN_ON(qh->slot == -1);
+
+	/* We need to forcefully reclaim the slot since some transfers never
+	   return, e.g. interrupt transfers and NAKed bulk transfers. */
+	if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
+		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+		skip_map |= (1 << qh->slot);
+		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+		priv->atl_slots[qh->slot].qh = NULL;
+		priv->atl_slots[qh->slot].qtd = NULL;
+	} else {
+		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+		skip_map |= (1 << qh->slot);
+		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+		priv->int_slots[qh->slot].qh = NULL;
+		priv->int_slots[qh->slot].qtd = NULL;
+	}
+
+	qh->slot = -1;
+}
+
+/*
+ * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
+ * any active transfer belonging to the urb in the process.
+ */
+static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
+						struct isp1760_qtd *qtd)
+{
+	struct urb *urb;
+	int urb_was_running;
+
+	urb = qtd->urb;
+	urb_was_running = 0;
+	list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
+		if (qtd->urb != urb)
+			break;
+
+		if (qtd->status >= QTD_XFER_STARTED)
+			urb_was_running = 1;
+		if (last_qtd_of_urb(qtd, qh) &&
+					(qtd->status >= QTD_XFER_COMPLETE))
+			urb_was_running = 0;
+
+		if (qtd->status == QTD_XFER_STARTED)
+			kill_transfer(hcd, urb, qh);
+		qtd->status = QTD_RETIRE;
+	}
+
+	if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
+		qh->tt_buffer_dirty = 1;
+		if (usb_hub_clear_tt_buffer(urb))
+			/* Clear failed; let's hope things work anyway */
+			qh->tt_buffer_dirty = 0;
+	}
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	unsigned long spinflags;
+	struct isp1760_qh *qh;
+	struct isp1760_qtd *qtd;
+	int retval = 0;
+
+	spin_lock_irqsave(&priv->lock, spinflags);
+	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (retval)
+		goto out;
+
+	qh = urb->ep->hcpriv;
+	if (!qh) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
+		if (qtd->urb == urb) {
+			dequeue_urb_from_qtd(hcd, qh, qtd);
+			list_move(&qtd->qtd_list, &qh->qtd_list);
+			break;
+		}
+
+	urb->status = status;
+	schedule_ptds(hcd);
+
+out:
+	spin_unlock_irqrestore(&priv->lock, spinflags);
+	return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	unsigned long spinflags;
+	struct isp1760_qh *qh, *qh_iter;
+	int i;
+
+	spin_lock_irqsave(&priv->lock, spinflags);
+
+	qh = ep->hcpriv;
+	if (!qh)
+		goto out;
+
+	WARN_ON(!list_empty(&qh->qtd_list));
+
+	for (i = 0; i < QH_END; i++)
+		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
+			if (qh_iter == qh) {
+				list_del(&qh_iter->qh_list);
+				i = QH_END;
+				break;
+			}
+	qh_free(qh);
+	ep->hcpriv = NULL;
+
+	schedule_ptds(hcd);
+
+out:
+	spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	u32 temp, status = 0;
+	u32 mask;
+	int retval = 1;
+	unsigned long flags;
+
+	/* if !PM, root hub timers won't get shut down ... */
+	if (!HC_IS_RUNNING(hcd->state))
+		return 0;
+
+	/* init status to no-changes */
+	buf[0] = 0;
+	mask = PORT_CSC;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+	if (temp & PORT_OWNER) {
+		if (temp & PORT_CSC) {
+			temp &= ~PORT_CSC;
+			reg_write32(hcd->regs, HC_PORTSC1, temp);
+			goto done;
+		}
+	}
+
+	/*
+	 * Return status information even for ports with OWNER set.
+	 * Otherwise hub_wq wouldn't see the disconnect event when a
+	 * high-speed device is switched over to the companion
+	 * controller by the user.
+	 */
+
+	if ((temp & mask) != 0
+			|| ((temp & PORT_RESUME) != 0
+				&& time_after_eq(jiffies,
+					priv->reset_done))) {
+		buf [0] |= 1 << (0 + 1);
+		status = STS_PCD;
+	}
+	/* FIXME autosuspend idle root hubs */
+done:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+		struct usb_hub_descriptor *desc)
+{
+	int ports = HCS_N_PORTS(priv->hcs_params);
+	u16 temp;
+
+	desc->bDescriptorType = 0x29;
+	/* priv 1.0, 2.3.9 says 20ms max */
+	desc->bPwrOn2PwrGood = 10;
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
+
+	/* per-port overcurrent reporting */
+	temp = HUB_CHAR_INDV_PORT_OCPM;
+	if (HCS_PPC(priv->hcs_params))
+		/* per-port power control */
+		temp |= HUB_CHAR_INDV_PORT_LPSM;
+	else
+		/* no power switching */
+		temp |= HUB_CHAR_NO_LPSM;
+	desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct usb_hcd *hcd, int index,
+		int port_status)
+{
+	if (!(port_status & PORT_CONNECT))
+		return port_status;
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+
+		dev_info(hcd->self.controller,
+					"port %d full speed --> companion\n",
+					index + 1);
+
+		port_status |= PORT_OWNER;
+		port_status &= ~PORT_RWC_BITS;
+		reg_write32(hcd->regs, HC_PORTSC1, port_status);
+
+	} else
+		dev_info(hcd->self.controller, "port %d high speed\n",
+								index + 1);
+
+	return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+		u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	int ports = HCS_N_PORTS(priv->hcs_params);
+	u32 temp, status;
+	unsigned long flags;
+	int retval = 0;
+	unsigned selector;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave(&priv->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+		/*
+		 * Even if OWNER is set, so the port is owned by the
+		 * companion controller, hub_wq needs to be able to clear
+		 * the port-change status bits (especially
+		 * USB_PORT_STAT_C_CONNECTION).
+		 */
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			/* XXX error? */
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			if (temp & PORT_RESET)
+				goto error;
+
+			if (temp & PORT_SUSPEND) {
+				if ((temp & PORT_PE) == 0)
+					goto error;
+				/* resume signaling for 20 msec */
+				temp &= ~(PORT_RWC_BITS);
+				reg_write32(hcd->regs, HC_PORTSC1,
+							temp | PORT_RESUME);
+				priv->reset_done = jiffies +
+					msecs_to_jiffies(20);
+			}
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* we auto-clear this feature */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(priv->hcs_params))
+				reg_write32(hcd->regs, HC_PORTSC1,
+							temp & ~PORT_POWER);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			/* XXX error ?*/
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		reg_read32(hcd->regs, HC_USBCMD);
+		break;
+	case GetHubDescriptor:
+		isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset(buf, 0, 4);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		status = 0;
+		temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+		/* wPortChange bits */
+		if (temp & PORT_CSC)
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
+
+
+		/* whoever resumes must GetPortStatus to complete it!! */
+		if (temp & PORT_RESUME) {
+			dev_err(hcd->self.controller, "Port resume should be skipped.\n");
+
+			/* Remote Wakeup received? */
+			if (!priv->reset_done) {
+				/* resume signaling for 20 msec */
+				priv->reset_done = jiffies
+						+ msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&hcd->rh_timer, priv->reset_done);
+			}
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies,
+					priv->reset_done)) {
+				status |= USB_PORT_STAT_C_SUSPEND << 16;
+				priv->reset_done = 0;
+
+				/* stop resume signaling */
+				temp = reg_read32(hcd->regs, HC_PORTSC1);
+				reg_write32(hcd->regs, HC_PORTSC1,
+					temp & ~(PORT_RWC_BITS | PORT_RESUME));
+				retval = handshake(hcd, HC_PORTSC1,
+					   PORT_RESUME, 0, 2000 /* 2msec */);
+				if (retval != 0) {
+					dev_err(hcd->self.controller,
+						"port %d resume error %d\n",
+						wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+			}
+		}
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& time_after_eq(jiffies,
+					priv->reset_done)) {
+			status |= USB_PORT_STAT_C_RESET << 16;
+			priv->reset_done = 0;
+
+			/* force reset to complete */
+			reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
+			/* REVISIT:  some hardware needs 550+ usec to clear
+			 * this bit; seems too long to spin routinely...
+			 */
+			retval = handshake(hcd, HC_PORTSC1,
+					PORT_RESET, 0, 750);
+			if (retval != 0) {
+				dev_err(hcd->self.controller, "port %d reset error %d\n",
+						wIndex + 1, retval);
+				goto error;
+			}
+
+			/* see what we found out */
+			temp = check_reset_complete(hcd, wIndex,
+					reg_read32(hcd->regs, HC_PORTSC1));
+		}
+		/*
+		 * Even if OWNER is set, there's no harm letting hub_wq
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_OWNER)
+			dev_err(hcd->self.controller, "PORT_OWNER is set\n");
+
+		if (temp & PORT_CONNECT) {
+			status |= USB_PORT_STAT_CONNECTION;
+			/* status may be from integrated TT */
+			status |= USB_PORT_STAT_HIGH_SPEED;
+		}
+		if (temp & PORT_PE)
+			status |= USB_PORT_STAT_ENABLE;
+		if (temp & (PORT_SUSPEND|PORT_RESUME))
+			status |= USB_PORT_STAT_SUSPEND;
+		if (temp & PORT_RESET)
+			status |= USB_PORT_STAT_RESET;
+		if (temp & PORT_POWER)
+			status |= USB_PORT_STAT_POWER;
+
+		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		selector = wIndex >> 8;
+		wIndex &= 0xff;
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = reg_read32(hcd->regs, HC_PORTSC1);
+		if (temp & PORT_OWNER)
+			break;
+
+/*		temp &= ~PORT_RWC_BITS; */
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
+			break;
+
+		case USB_PORT_FEAT_SUSPEND:
+			if ((temp & PORT_PE) == 0
+					|| (temp & PORT_RESET) != 0)
+				goto error;
+
+			reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(priv->hcs_params))
+				reg_write32(hcd->regs, HC_PORTSC1,
+							temp | PORT_POWER);
+			break;
+		case USB_PORT_FEAT_RESET:
+			if (temp & PORT_RESUME)
+				goto error;
+			/* line status bits may report this as low speed,
+			 * which can be fine if this root hub has a
+			 * transaction translator built in.
+			 */
+			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& PORT_USB11(temp)) {
+				temp |= PORT_OWNER;
+			} else {
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				priv->reset_done = jiffies +
+					msecs_to_jiffies(50);
+			}
+			reg_write32(hcd->regs, HC_PORTSC1, temp);
+			break;
+		default:
+			goto error;
+		}
+		reg_read32(hcd->regs, HC_USBCMD);
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return retval;
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	u32 fr;
+
+	fr = reg_read32(hcd->regs, HC_FRINDEX);
+	return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	u32 temp;
+
+	del_timer(&errata2_timer);
+
+	isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,	1,
+			NULL, 0);
+	mdelay(20);
+
+	spin_lock_irq(&priv->lock);
+	ehci_reset(hcd);
+	/* Disable IRQ */
+	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+	spin_unlock_irq(&priv->lock);
+
+	reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+	u32 command, temp;
+
+	isp1760_stop(hcd);
+	temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+	reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+
+	command = reg_read32(hcd->regs, HC_USBCMD);
+	command &= ~CMD_RUN;
+	reg_write32(hcd->regs, HC_USBCMD, command);
+}
+
+static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
+						struct usb_host_endpoint *ep)
+{
+	struct isp1760_hcd *priv = hcd_to_priv(hcd);
+	struct isp1760_qh *qh = ep->hcpriv;
+	unsigned long spinflags;
+
+	if (!qh)
+		return;
+
+	spin_lock_irqsave(&priv->lock, spinflags);
+	qh->tt_buffer_dirty = 0;
+	schedule_ptds(hcd);
+	spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+
+static const struct hc_driver isp1760_hc_driver = {
+	.description		= "isp1760-hcd",
+	.product_desc		= "NXP ISP1760 USB Host Controller",
+	.hcd_priv_size		= sizeof(struct isp1760_hcd *),
+	.irq			= isp1760_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+	.reset			= isp1760_hc_setup,
+	.start			= isp1760_run,
+	.stop			= isp1760_stop,
+	.shutdown		= isp1760_shutdown,
+	.urb_enqueue		= isp1760_urb_enqueue,
+	.urb_dequeue		= isp1760_urb_dequeue,
+	.endpoint_disable	= isp1760_endpoint_disable,
+	.get_frame_number	= isp1760_get_frame,
+	.hub_status_data	= isp1760_hub_status_data,
+	.hub_control		= isp1760_hub_control,
+	.clear_tt_buffer_complete	= isp1760_clear_tt_buffer_complete,
+};
+
+int __init isp1760_init_kmem_once(void)
+{
+	urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
+			sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
+			SLAB_MEM_SPREAD, NULL);
+
+	if (!urb_listitem_cachep)
+		return -ENOMEM;
+
+	qtd_cachep = kmem_cache_create("isp1760_qtd",
+			sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+			SLAB_MEM_SPREAD, NULL);
+
+	if (!qtd_cachep)
+		return -ENOMEM;
+
+	qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+			0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+	if (!qh_cachep) {
+		kmem_cache_destroy(qtd_cachep);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void isp1760_deinit_kmem_cache(void)
+{
+	kmem_cache_destroy(qtd_cachep);
+	kmem_cache_destroy(qh_cachep);
+	kmem_cache_destroy(urb_listitem_cachep);
+}
+
+int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+			 struct resource *mem, int irq, unsigned long irqflags,
+			 struct device *dev)
+{
+	struct usb_hcd *hcd;
+	int ret;
+
+	hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
+	if (!hcd)
+		return -ENOMEM;
+
+	*(struct isp1760_hcd **)hcd->hcd_priv = priv;
+
+	priv->hcd = hcd;
+
+	init_memory(priv);
+
+	hcd->irq = irq;
+	hcd->regs = regs;
+	hcd->rsrc_start = mem->start;
+	hcd->rsrc_len = resource_size(mem);
+
+	/* This driver doesn't support wakeup requests */
+	hcd->cant_recv_wakeups = 1;
+
+	ret = usb_add_hcd(hcd, irq, irqflags);
+	if (ret)
+		goto error;
+
+	device_wakeup_enable(hcd->self.controller);
+
+	return 0;
+
+error:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+{
+	if (!priv->hcd)
+		return;
+
+	usb_remove_hcd(priv->hcd);
+	usb_put_hcd(priv->hcd);
+}
diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
new file mode 100644
index 0000000..0c1c98d
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-hcd.h
@@ -0,0 +1,102 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+#include <linux/spinlock.h>
+
+struct isp1760_qh;
+struct isp1760_qtd;
+struct resource;
+struct usb_hcd;
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256  bytes
+ * - 20 blocks @ 1024 bytes
+ * -  4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
+#define PAYLOAD_AREA_SIZE 0xf000
+
+struct isp1760_slotinfo {
+	struct isp1760_qh *qh;
+	struct isp1760_qtd *qtd;
+	unsigned long timestamp;
+};
+
+/* chip memory management */
+struct isp1760_memory_chunk {
+	unsigned int start;
+	unsigned int size;
+	unsigned int free;
+};
+
+enum isp1760_queue_head_types {
+	QH_CONTROL,
+	QH_BULK,
+	QH_INTERRUPT,
+	QH_END
+};
+
+struct isp1760_hcd {
+#ifdef CONFIG_USB_ISP1760_HCD
+	struct usb_hcd		*hcd;
+
+	u32 hcs_params;
+	spinlock_t		lock;
+	struct isp1760_slotinfo	atl_slots[32];
+	int			atl_done_map;
+	struct isp1760_slotinfo	int_slots[32];
+	int			int_done_map;
+	struct isp1760_memory_chunk memory_pool[BLOCKS];
+	struct list_head	qh_list[QH_END];
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024
+	unsigned		periodic_size;
+	unsigned		i_thresh;
+	unsigned long		reset_done;
+	unsigned long		next_statechange;
+#endif
+};
+
+#ifdef CONFIG_USB_ISP1760_HCD
+int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+			 struct resource *mem, int irq, unsigned long irqflags,
+			 struct device *dev);
+void isp1760_hcd_unregister(struct isp1760_hcd *priv);
+
+int isp1760_init_kmem_once(void);
+void isp1760_deinit_kmem_cache(void);
+#else
+static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
+				       void __iomem *regs, struct resource *mem,
+				       int irq, unsigned long irqflags,
+				       struct device *dev)
+{
+	return 0;
+}
+
+static inline void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+{
+}
+
+static inline int isp1760_init_kmem_once(void)
+{
+	return 0;
+}
+
+static inline void isp1760_deinit_kmem_cache(void)
+{
+}
+#endif
+
+#endif /* _ISP1760_HCD_H_ */
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
new file mode 100644
index 0000000..264be4d
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -0,0 +1,309 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ * - PDEV (generic platform device centralized driver model)
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/usb/isp1760.h>
+#include <linux/usb/hcd.h>
+
+#include "isp1760-core.h"
+#include "isp1760-regs.h"
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_PCI
+static int isp1761_pci_init(struct pci_dev *dev)
+{
+	resource_size_t mem_start;
+	resource_size_t mem_length;
+	u8 __iomem *iobase;
+	u8 latency, limit;
+	int retry_count;
+	u32 reg_data;
+
+	/* Grab the PLX PCI shared memory of the ISP 1761 we need  */
+	mem_start = pci_resource_start(dev, 3);
+	mem_length = pci_resource_len(dev, 3);
+	if (mem_length < 0xffff) {
+		printk(KERN_ERR "memory length for this resource is wrong\n");
+		return -ENOMEM;
+	}
+
+	if (!request_mem_region(mem_start, mem_length, "ISP-PCI")) {
+		printk(KERN_ERR "host controller already in use\n");
+		return -EBUSY;
+	}
+
+	/* map available memory */
+	iobase = ioremap_nocache(mem_start, mem_length);
+	if (!iobase) {
+		printk(KERN_ERR "Error ioremap failed\n");
+		release_mem_region(mem_start, mem_length);
+		return -ENOMEM;
+	}
+
+	/* bad pci latencies can contribute to overruns */
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+	if (latency) {
+		pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+		if (limit && limit < latency)
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+	}
+
+	/* Try to check whether we can access Scratch Register of
+	 * Host Controller or not. The initial PCI access is retried until
+	 * local init for the PCI bridge is completed
+	 */
+	retry_count = 20;
+	reg_data = 0;
+	while ((reg_data != 0xFACE) && retry_count) {
+		/*by default host is in 16bit mode, so
+		 * io operations at this stage must be 16 bit
+		 * */
+		writel(0xface, iobase + HC_SCRATCH_REG);
+		udelay(100);
+		reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
+		retry_count--;
+	}
+
+	iounmap(iobase);
+	release_mem_region(mem_start, mem_length);
+
+	/* Host Controller presence is detected by writing to scratch register
+	 * and reading back and checking the contents are same or not
+	 */
+	if (reg_data != 0xFACE) {
+		dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
+		return -ENOMEM;
+	}
+
+	/* Grab the PLX PCI mem maped port start address we need  */
+	mem_start = pci_resource_start(dev, 0);
+	mem_length = pci_resource_len(dev, 0);
+
+	if (!request_mem_region(mem_start, mem_length, "ISP1761 IO MEM")) {
+		printk(KERN_ERR "request region #1\n");
+		return -EBUSY;
+	}
+
+	iobase = ioremap_nocache(mem_start, mem_length);
+	if (!iobase) {
+		printk(KERN_ERR "ioremap #1\n");
+		release_mem_region(mem_start, mem_length);
+		return -ENOMEM;
+	}
+
+	/* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+	reg_data = readl(iobase + PLX_INT_CSR_REG);
+	reg_data |= 0x900;
+	writel(reg_data, iobase + PLX_INT_CSR_REG);
+
+	/* done with PLX IO access */
+	iounmap(iobase);
+	release_mem_region(mem_start, mem_length);
+
+	return 0;
+}
+
+static int isp1761_pci_probe(struct pci_dev *dev,
+		const struct pci_device_id *id)
+{
+	unsigned int devflags = 0;
+	int ret;
+
+	if (!dev->irq)
+		return -ENODEV;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+
+	ret = isp1761_pci_init(dev);
+	if (ret < 0)
+		goto error;
+
+	pci_set_master(dev);
+
+	dev->dev.dma_mask = NULL;
+	ret = isp1760_register(&dev->resource[3], dev->irq, 0, &dev->dev,
+			       devflags);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	pci_disable_device(dev);
+	return ret;
+}
+
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+	isp1760_unregister(&dev->dev);
+
+	pci_disable_device(dev);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+	printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = {
+	{
+		.class          = PCI_CLASS_BRIDGE_OTHER << 8,
+		.class_mask     = ~0,
+		.vendor		= PCI_VENDOR_ID_PLX,
+		.device		= 0x5406,
+		.subvendor	= PCI_VENDOR_ID_PLX,
+		.subdevice	= 0x9054,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+	.name =         "isp1760",
+	.id_table =     isp1760_plx,
+	.probe =        isp1761_pci_probe,
+	.remove =       isp1761_pci_remove,
+	.shutdown =     isp1761_pci_shutdown,
+};
+#endif
+
+static int isp1760_plat_probe(struct platform_device *pdev)
+{
+	unsigned long irqflags;
+	unsigned int devflags = 0;
+	struct resource *mem_res;
+	struct resource *irq_res;
+	int ret;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq_res) {
+		pr_warning("isp1760: IRQ resource not available\n");
+		return -ENODEV;
+	}
+	irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
+
+	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+		struct device_node *dp = pdev->dev.of_node;
+		u32 bus_width = 0;
+
+		if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
+			devflags |= ISP1760_FLAG_ISP1761;
+
+		/* Some systems wire up only 16 of the 32 data lines */
+		of_property_read_u32(dp, "bus-width", &bus_width);
+		if (bus_width == 16)
+			devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+
+		if (of_property_read_bool(dp, "port1-otg"))
+			devflags |= ISP1760_FLAG_OTG_EN;
+
+		if (of_property_read_bool(dp, "analog-oc"))
+			devflags |= ISP1760_FLAG_ANALOG_OC;
+
+		if (of_property_read_bool(dp, "dack-polarity"))
+			devflags |= ISP1760_FLAG_DACK_POL_HIGH;
+
+		if (of_property_read_bool(dp, "dreq-polarity"))
+			devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+	} else if (dev_get_platdata(&pdev->dev)) {
+		struct isp1760_platform_data *pdata =
+			dev_get_platdata(&pdev->dev);
+
+		if (pdata->is_isp1761)
+			devflags |= ISP1760_FLAG_ISP1761;
+		if (pdata->bus_width_16)
+			devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+		if (pdata->port1_otg)
+			devflags |= ISP1760_FLAG_OTG_EN;
+		if (pdata->analog_oc)
+			devflags |= ISP1760_FLAG_ANALOG_OC;
+		if (pdata->dack_polarity_high)
+			devflags |= ISP1760_FLAG_DACK_POL_HIGH;
+		if (pdata->dreq_polarity_high)
+			devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+	}
+
+	ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
+			       devflags);
+	if (ret < 0)
+		return ret;
+
+	pr_info("ISP1760 USB device initialised\n");
+	return 0;
+}
+
+static int isp1760_plat_remove(struct platform_device *pdev)
+{
+	isp1760_unregister(&pdev->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id isp1760_of_match[] = {
+	{ .compatible = "nxp,usb-isp1760", },
+	{ .compatible = "nxp,usb-isp1761", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, isp1760_of_match);
+#endif
+
+static struct platform_driver isp1760_plat_driver = {
+	.probe	= isp1760_plat_probe,
+	.remove	= isp1760_plat_remove,
+	.driver	= {
+		.name	= "isp1760",
+		.of_match_table = of_match_ptr(isp1760_of_match),
+	},
+};
+
+static int __init isp1760_init(void)
+{
+	int ret, any_ret = -ENODEV;
+
+	isp1760_init_kmem_once();
+
+	ret = platform_driver_register(&isp1760_plat_driver);
+	if (!ret)
+		any_ret = 0;
+#ifdef CONFIG_PCI
+	ret = pci_register_driver(&isp1761_pci_driver);
+	if (!ret)
+		any_ret = 0;
+#endif
+
+	if (any_ret)
+		isp1760_deinit_kmem_cache();
+	return any_ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+	platform_driver_unregister(&isp1760_plat_driver);
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&isp1761_pci_driver);
+#endif
+	isp1760_deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
new file mode 100644
index 0000000..b67095c
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-regs.h
@@ -0,0 +1,230 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ *     Sebastian Siewior <bigeasy@linutronix.de>
+ *     Laurent Pinchart <laurent.pinchart@ideasonboard.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 _ISP1760_REGS_H_
+#define _ISP1760_REGS_H_
+
+/* -----------------------------------------------------------------------------
+ * Host Controller
+ */
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH		0x000
+#define HC_LENGTH(p)		(((p) >> 00) & 0x00ff)	/* bits 7:0 */
+#define HC_VERSION(p)		(((p) >> 16) & 0xffff)	/* bits 31:16 */
+
+#define HC_HCSPARAMS		0x004
+#define HCS_INDICATOR(p)	((p) & (1 << 16))	/* true: has port indicators */
+#define HCS_PPC(p)		((p) & (1 << 4))	/* true: port power control */
+#define HCS_N_PORTS(p)		(((p) >> 0) & 0xf)	/* bits 3:0, ports on HC */
+
+#define HC_HCCPARAMS		0x008
+#define HCC_ISOC_CACHE(p)       ((p) & (1 << 7))	/* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p) >> 4) & 0x7)	/* bits 6:4, uframes cached */
+
+/* EHCI operational registers */
+#define HC_USBCMD		0x020
+#define CMD_LRESET		(1 << 7)		/* partial reset (no ports, etc) */
+#define CMD_RESET		(1 << 1)		/* reset HC not bus */
+#define CMD_RUN			(1 << 0)		/* start/stop HC */
+
+#define HC_USBSTS		0x024
+#define STS_PCD			(1 << 2)		/* port change detect */
+
+#define HC_FRINDEX		0x02c
+
+#define HC_CONFIGFLAG		0x060
+#define FLAG_CF			(1 << 0)		/* true: we'll support "high speed" */
+
+#define HC_PORTSC1		0x064
+#define PORT_OWNER		(1 << 13)		/* true: companion hc owns this port */
+#define PORT_POWER		(1 << 12)		/* true: has power (see PPC) */
+#define PORT_USB11(x)		(((x) & (3 << 10)) == (1 << 10))	/* USB 1.1 device */
+#define PORT_RESET		(1 << 8)		/* reset port */
+#define PORT_SUSPEND		(1 << 7)		/* suspend port */
+#define PORT_RESUME		(1 << 6)		/* resume it */
+#define PORT_PE			(1 << 2)		/* port enable */
+#define PORT_CSC		(1 << 1)		/* connect status change */
+#define PORT_CONNECT		(1 << 0)		/* device connected */
+#define PORT_RWC_BITS		(PORT_CSC)
+
+#define HC_ISO_PTD_DONEMAP_REG	0x130
+#define HC_ISO_PTD_SKIPMAP_REG	0x134
+#define HC_ISO_PTD_LASTPTD_REG	0x138
+#define HC_INT_PTD_DONEMAP_REG	0x140
+#define HC_INT_PTD_SKIPMAP_REG	0x144
+#define HC_INT_PTD_LASTPTD_REG	0x148
+#define HC_ATL_PTD_DONEMAP_REG	0x150
+#define HC_ATL_PTD_SKIPMAP_REG	0x154
+#define HC_ATL_PTD_LASTPTD_REG	0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL		0x300
+#define ALL_ATX_RESET		(1 << 31)
+#define HW_ANA_DIGI_OC		(1 << 15)
+#define HW_DEV_DMA		(1 << 11)
+#define HW_COMN_IRQ		(1 << 10)
+#define HW_COMN_DMA		(1 << 9)
+#define HW_DATA_BUS_32BIT	(1 << 8)
+#define HW_DACK_POL_HIGH	(1 << 6)
+#define HW_DREQ_POL_HIGH	(1 << 5)
+#define HW_INTR_HIGH_ACT	(1 << 2)
+#define HW_INTR_EDGE_TRIG	(1 << 1)
+#define HW_GLOBAL_INTR_EN	(1 << 0)
+
+#define HC_CHIP_ID_REG		0x304
+#define HC_SCRATCH_REG		0x308
+
+#define HC_RESET_REG		0x30c
+#define SW_RESET_RESET_HC	(1 << 1)
+#define SW_RESET_RESET_ALL	(1 << 0)
+
+#define HC_BUFFER_STATUS_REG	0x334
+#define ISO_BUF_FILL		(1 << 2)
+#define INT_BUF_FILL		(1 << 1)
+#define ATL_BUF_FILL		(1 << 0)
+
+#define HC_MEMORY_REG		0x33c
+#define ISP_BANK(x)		((x) << 16)
+
+#define HC_PORT1_CTRL		0x374
+#define PORT1_POWER		(3 << 3)
+#define PORT1_INIT1		(1 << 7)
+#define PORT1_INIT2		(1 << 23)
+#define HW_OTG_CTRL_SET		0x374
+#define HW_OTG_CTRL_CLR		0x376
+#define HW_OTG_DISABLE		(1 << 10)
+#define HW_OTG_SE0_EN		(1 << 9)
+#define HW_BDIS_ACON_EN		(1 << 8)
+#define HW_SW_SEL_HC_DC		(1 << 7)
+#define HW_VBUS_CHRG		(1 << 6)
+#define HW_VBUS_DISCHRG		(1 << 5)
+#define HW_VBUS_DRV		(1 << 4)
+#define HW_SEL_CP_EXT		(1 << 3)
+#define HW_DM_PULLDOWN		(1 << 2)
+#define HW_DP_PULLDOWN		(1 << 1)
+#define HW_DP_PULLUP		(1 << 0)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG	0x310
+
+#define HC_INTERRUPT_ENABLE	0x314
+#define HC_ISO_INT		(1 << 9)
+#define HC_ATL_INT		(1 << 8)
+#define HC_INTL_INT		(1 << 7)
+#define HC_EOT_INT		(1 << 3)
+#define HC_SOT_INT		(1 << 1)
+#define INTERRUPT_ENABLE_MASK	(HC_INTL_INT | HC_ATL_INT)
+
+#define HC_ISO_IRQ_MASK_OR_REG	0x318
+#define HC_INT_IRQ_MASK_OR_REG	0x31c
+#define HC_ATL_IRQ_MASK_OR_REG	0x320
+#define HC_ISO_IRQ_MASK_AND_REG	0x324
+#define HC_INT_IRQ_MASK_AND_REG	0x328
+#define HC_ATL_IRQ_MASK_AND_REG	0x32c
+
+/* -----------------------------------------------------------------------------
+ * Peripheral Controller
+ */
+
+/* Initialization Registers */
+#define DC_ADDRESS			0x0200
+#define DC_DEVEN			(1 << 7)
+
+#define DC_MODE				0x020c
+#define DC_DMACLKON			(1 << 9)
+#define DC_VBUSSTAT			(1 << 8)
+#define DC_CLKAON			(1 << 7)
+#define DC_SNDRSU			(1 << 6)
+#define DC_GOSUSP			(1 << 5)
+#define DC_SFRESET			(1 << 4)
+#define DC_GLINTENA			(1 << 3)
+#define DC_WKUPCS			(1 << 2)
+
+#define DC_INTCONF			0x0210
+#define DC_CDBGMOD_ACK_NAK		(0 << 6)
+#define DC_CDBGMOD_ACK			(1 << 6)
+#define DC_CDBGMOD_ACK_1NAK		(2 << 6)
+#define DC_DDBGMODIN_ACK_NAK		(0 << 4)
+#define DC_DDBGMODIN_ACK		(1 << 4)
+#define DC_DDBGMODIN_ACK_1NAK		(2 << 4)
+#define DC_DDBGMODOUT_ACK_NYET_NAK	(0 << 2)
+#define DC_DDBGMODOUT_ACK_NYET		(1 << 2)
+#define DC_DDBGMODOUT_ACK_NYET_1NAK	(2 << 2)
+#define DC_INTLVL			(1 << 1)
+#define DC_INTPOL			(1 << 0)
+
+#define DC_DEBUG			0x0212
+#define DC_INTENABLE			0x0214
+#define DC_IEPTX(n)			(1 << (11 + 2 * (n)))
+#define DC_IEPRX(n)			(1 << (10 + 2 * (n)))
+#define DC_IEPRXTX(n)			(3 << (10 + 2 * (n)))
+#define DC_IEP0SETUP			(1 << 8)
+#define DC_IEVBUS			(1 << 7)
+#define DC_IEDMA			(1 << 6)
+#define DC_IEHS_STA			(1 << 5)
+#define DC_IERESM			(1 << 4)
+#define DC_IESUSP			(1 << 3)
+#define DC_IEPSOF			(1 << 2)
+#define DC_IESOF			(1 << 1)
+#define DC_IEBRST			(1 << 0)
+
+/* Data Flow Registers */
+#define DC_EPINDEX			0x022c
+#define DC_EP0SETUP			(1 << 5)
+#define DC_ENDPIDX(n)			((n) << 1)
+#define DC_EPDIR			(1 << 0)
+
+#define DC_CTRLFUNC			0x0228
+#define DC_CLBUF			(1 << 4)
+#define DC_VENDP			(1 << 3)
+#define DC_DSEN				(1 << 2)
+#define DC_STATUS			(1 << 1)
+#define DC_STALL			(1 << 0)
+
+#define DC_DATAPORT			0x0220
+#define DC_BUFLEN			0x021c
+#define DC_DATACOUNT_MASK		0xffff
+#define DC_BUFSTAT			0x021e
+#define DC_EPMAXPKTSZ			0x0204
+
+#define DC_EPTYPE			0x0208
+#define DC_NOEMPKT			(1 << 4)
+#define DC_EPENABLE			(1 << 3)
+#define DC_DBLBUF			(1 << 2)
+#define DC_ENDPTYP_ISOC			(1 << 0)
+#define DC_ENDPTYP_BULK			(2 << 0)
+#define DC_ENDPTYP_INTERRUPT		(3 << 0)
+
+/* DMA Registers */
+#define DC_DMACMD			0x0230
+#define DC_DMATXCOUNT			0x0234
+#define DC_DMACONF			0x0238
+#define DC_DMAHW			0x023c
+#define DC_DMAINTREASON			0x0250
+#define DC_DMAINTEN			0x0254
+#define DC_DMAEP			0x0258
+#define DC_DMABURSTCOUNT		0x0264
+
+/* General Registers */
+#define DC_INTERRUPT			0x0218
+#define DC_CHIPID			0x0270
+#define DC_FRAMENUM			0x0274
+#define DC_SCRATCH			0x0278
+#define DC_UNLOCKDEV			0x027c
+#define DC_INTPULSEWIDTH		0x0280
+#define DC_TESTMODE			0x0284
+
+#endif
diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
new file mode 100644
index 0000000..9612d79
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-udc.c
@@ -0,0 +1,1498 @@
+/*
+ * Driver for the NXP ISP1761 device controller
+ *
+ * Copyright 2014 Ideas on Board Oy
+ *
+ * Contacts:
+ *	Laurent Pinchart <laurent.pinchart@ideasonboard.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/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+
+#include "isp1760-core.h"
+#include "isp1760-regs.h"
+#include "isp1760-udc.h"
+
+#define ISP1760_VBUS_POLL_INTERVAL	msecs_to_jiffies(500)
+
+struct isp1760_request {
+	struct usb_request req;
+	struct list_head queue;
+	struct isp1760_ep *ep;
+	unsigned int packet_size;
+};
+
+static inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct isp1760_udc, gadget);
+}
+
+static inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct isp1760_ep, ep);
+}
+
+static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
+{
+	return container_of(req, struct isp1760_request, req);
+}
+
+static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
+{
+	return isp1760_read32(udc->regs, reg);
+}
+
+static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
+{
+	isp1760_write32(udc->regs, reg, val);
+}
+
+/* -----------------------------------------------------------------------------
+ * Endpoint Management
+ */
+
+static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
+					      u16 index)
+{
+	unsigned int i;
+
+	if (index == 0)
+		return &udc->ep[0];
+
+	for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) {
+		if (udc->ep[i].addr == index)
+			return udc->ep[i].desc ? &udc->ep[i] : NULL;
+	}
+
+	return NULL;
+}
+
+static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
+{
+	isp1760_udc_write(ep->udc, DC_EPINDEX,
+			  DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
+			  (dir == USB_DIR_IN ? DC_EPDIR : 0));
+}
+
+/**
+ * isp1760_udc_select_ep - Select an endpoint for register access
+ * @ep: The endpoint
+ *
+ * The ISP1761 endpoint registers are banked. This function selects the target
+ * endpoint for banked register access. The selection remains valid until the
+ * next call to this function, the next direct access to the EPINDEX register
+ * or the next reset, whichever comes first.
+ *
+ * Called with the UDC spinlock held.
+ */
+static void isp1760_udc_select_ep(struct isp1760_ep *ep)
+{
+	__isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
+}
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
+{
+	struct isp1760_udc *udc = ep->udc;
+
+	/*
+	 * Proceed to the status stage. The status stage data packet flows in
+	 * the direction opposite to the data stage data packets, we thus need
+	 * to select the OUT/IN endpoint for IN/OUT transfers.
+	 */
+	isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
+			  (dir == USB_DIR_IN ? 0 : DC_EPDIR));
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
+
+	/*
+	 * The hardware will terminate the request automatically and go back to
+	 * the setup stage without notifying us.
+	 */
+	udc->ep0_state = ISP1760_CTRL_SETUP;
+}
+
+/* Called without the UDC spinlock held. */
+static void isp1760_udc_request_complete(struct isp1760_ep *ep,
+					 struct isp1760_request *req,
+					 int status)
+{
+	struct isp1760_udc *udc = ep->udc;
+	unsigned long flags;
+
+	dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n",
+		req, status);
+
+	req->ep = NULL;
+	req->req.status = status;
+	req->req.complete(&ep->ep, &req->req);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * When completing control OUT requests, move to the status stage after
+	 * calling the request complete callback. This gives the gadget an
+	 * opportunity to stall the control transfer if needed.
+	 */
+	if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT)
+		isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
+{
+	struct isp1760_udc *udc = ep->udc;
+	unsigned long flags;
+
+	dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* Stall both the IN and OUT endpoints. */
+	__isp1760_udc_select_ep(ep, USB_DIR_OUT);
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+	__isp1760_udc_select_ep(ep, USB_DIR_IN);
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+
+	/* A protocol stall completes the control transaction. */
+	udc->ep0_state = ISP1760_CTRL_SETUP;
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Data Endpoints
+ */
+
+/* Called with the UDC spinlock held. */
+static bool isp1760_udc_receive(struct isp1760_ep *ep,
+				struct isp1760_request *req)
+{
+	struct isp1760_udc *udc = ep->udc;
+	unsigned int len;
+	u32 *buf;
+	int i;
+
+	isp1760_udc_select_ep(ep);
+	len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+
+	dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
+		__func__, len, req->req.actual, req->req.length);
+
+	len = min(len, req->req.length - req->req.actual);
+
+	if (!len) {
+		/*
+		 * There's no data to be read from the FIFO, acknowledge the RX
+		 * interrupt by clearing the buffer.
+		 *
+		 * TODO: What if another packet arrives in the meantime ? The
+		 * datasheet doesn't clearly document how this should be
+		 * handled.
+		 */
+		isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+		return false;
+	}
+
+	buf = req->req.buf + req->req.actual;
+
+	/*
+	 * Make sure not to read more than one extra byte, otherwise data from
+	 * the next packet might be removed from the FIFO.
+	 */
+	for (i = len; i > 2; i -= 4, ++buf)
+		*buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
+	if (i > 0)
+		*(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
+
+	req->req.actual += len;
+
+	/*
+	 * TODO: The short_not_ok flag isn't supported yet, but isn't used by
+	 * any gadget driver either.
+	 */
+
+	dev_dbg(udc->isp->dev,
+		"%s: req %p actual/length %u/%u maxpacket %u packet size %u\n",
+		__func__, req, req->req.actual, req->req.length, ep->maxpacket,
+		len);
+
+	ep->rx_pending = false;
+
+	/*
+	 * Complete the request if all data has been received or if a short
+	 * packet has been received.
+	 */
+	if (req->req.actual == req->req.length || len < ep->maxpacket) {
+		list_del(&req->queue);
+		return true;
+	}
+
+	return false;
+}
+
+static void isp1760_udc_transmit(struct isp1760_ep *ep,
+				 struct isp1760_request *req)
+{
+	struct isp1760_udc *udc = ep->udc;
+	u32 *buf = req->req.buf + req->req.actual;
+	int i;
+
+	req->packet_size = min(req->req.length - req->req.actual,
+			       ep->maxpacket);
+
+	dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n",
+		__func__, req->packet_size, req->req.actual,
+		req->req.length);
+
+	__isp1760_udc_select_ep(ep, USB_DIR_IN);
+
+	if (req->packet_size)
+		isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
+
+	/*
+	 * Make sure not to write more than one extra byte, otherwise extra data
+	 * will stay in the FIFO and will be transmitted during the next control
+	 * request. The endpoint control CLBUF bit is supposed to allow flushing
+	 * the FIFO for this kind of conditions, but doesn't seem to work.
+	 */
+	for (i = req->packet_size; i > 2; i -= 4, ++buf)
+		isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
+	if (i > 0)
+		writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
+
+	if (ep->addr == 0)
+		isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+	if (!req->packet_size)
+		isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
+}
+
+static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
+{
+	struct isp1760_udc *udc = ep->udc;
+	struct isp1760_request *req;
+	bool complete;
+
+	spin_lock(&udc->lock);
+
+	if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_OUT) {
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "%s: invalid ep0 state %u\n", __func__,
+			udc->ep0_state);
+		return;
+	}
+
+	if (ep->addr != 0 && !ep->desc) {
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
+			ep->addr);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		ep->rx_pending = true;
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "%s: ep%02x (%p) has no request queued\n",
+			__func__, ep->addr, ep);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct isp1760_request,
+			       queue);
+	complete = isp1760_udc_receive(ep, req);
+
+	spin_unlock(&udc->lock);
+
+	if (complete)
+		isp1760_udc_request_complete(ep, req, 0);
+}
+
+static void isp1760_ep_tx_complete(struct isp1760_ep *ep)
+{
+	struct isp1760_udc *udc = ep->udc;
+	struct isp1760_request *complete = NULL;
+	struct isp1760_request *req;
+	bool need_zlp;
+
+	spin_lock(&udc->lock);
+
+	if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) {
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n",
+			udc->ep0_state);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		/*
+		 * This can happen for the control endpoint when the reply to
+		 * the GET_STATUS IN control request is sent directly by the
+		 * setup IRQ handler. Just proceed to the status stage.
+		 */
+		if (ep->addr == 0) {
+			isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
+			spin_unlock(&udc->lock);
+			return;
+		}
+
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n",
+			__func__, ep->addr);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct isp1760_request,
+			       queue);
+	req->req.actual += req->packet_size;
+
+	need_zlp = req->req.actual == req->req.length &&
+		   !(req->req.length % ep->maxpacket) &&
+		   req->packet_size && req->req.zero;
+
+	dev_dbg(udc->isp->dev,
+		"TX IRQ: req %p actual/length %u/%u maxpacket %u packet size %u zero %u need zlp %u\n",
+		 req, req->req.actual, req->req.length, ep->maxpacket,
+		 req->packet_size, req->req.zero, need_zlp);
+
+	/*
+	 * Complete the request if all data has been sent and we don't need to
+	 * transmit a zero length packet.
+	 */
+	if (req->req.actual == req->req.length && !need_zlp) {
+		complete = req;
+		list_del(&req->queue);
+
+		if (ep->addr == 0)
+			isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
+
+		if (!list_empty(&ep->queue))
+			req = list_first_entry(&ep->queue,
+					       struct isp1760_request, queue);
+		else
+			req = NULL;
+	}
+
+	/*
+	 * Transmit the next packet or start the next request, if any.
+	 *
+	 * TODO: If the endpoint is stalled the next request shouldn't be
+	 * started, but what about the next packet ?
+	 */
+	if (req)
+		isp1760_udc_transmit(ep, req);
+
+	spin_unlock(&udc->lock);
+
+	if (complete)
+		isp1760_udc_request_complete(ep, complete, 0);
+}
+
+static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
+{
+	struct isp1760_udc *udc = ep->udc;
+
+	dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
+		halt ? "set" : "clear", ep->addr);
+
+	if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) {
+		dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__,
+			ep->addr);
+		return -EINVAL;
+	}
+
+	isp1760_udc_select_ep(ep);
+	isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+
+	if (ep->addr == 0) {
+		/* When halting the control endpoint, stall both IN and OUT. */
+		__isp1760_udc_select_ep(ep, USB_DIR_IN);
+		isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+	} else if (!halt) {
+		/* Reset the data PID by cycling the endpoint enable bit. */
+		u16 eptype = isp1760_udc_read(udc, DC_EPTYPE);
+
+		isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE);
+		isp1760_udc_write(udc, DC_EPTYPE, eptype);
+
+		/*
+		 * Disabling the endpoint emptied the transmit FIFO, fill it
+		 * again if a request is pending.
+		 *
+		 * TODO: Does the gadget framework require synchronizatino with
+		 * the TX IRQ handler ?
+		 */
+		if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) {
+			struct isp1760_request *req;
+
+			req = list_first_entry(&ep->queue,
+					       struct isp1760_request, queue);
+			isp1760_udc_transmit(ep, req);
+		}
+	}
+
+	ep->halted = halt;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Control Endpoint
+ */
+
+static int isp1760_udc_get_status(struct isp1760_udc *udc,
+				  const struct usb_ctrlrequest *req)
+{
+	struct isp1760_ep *ep;
+	u16 status;
+
+	if (req->wLength != cpu_to_le16(2) || req->wValue != cpu_to_le16(0))
+		return -EINVAL;
+
+	switch (req->bRequestType) {
+	case USB_DIR_IN | USB_RECIP_DEVICE:
+		status = udc->devstatus;
+		break;
+
+	case USB_DIR_IN | USB_RECIP_INTERFACE:
+		status = 0;
+		break;
+
+	case USB_DIR_IN | USB_RECIP_ENDPOINT:
+		ep = isp1760_udc_find_ep(udc, le16_to_cpu(req->wIndex));
+		if (!ep)
+			return -EINVAL;
+
+		status = 0;
+		if (ep->halted)
+			status |= 1 << USB_ENDPOINT_HALT;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR);
+	isp1760_udc_write(udc, DC_BUFLEN, 2);
+
+	writew(cpu_to_le16(status), udc->regs + DC_DATAPORT);
+
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+
+	dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
+
+	return 0;
+}
+
+static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
+{
+	if (addr > 127) {
+		dev_dbg(udc->isp->dev, "invalid device address %u\n", addr);
+		return -EINVAL;
+	}
+
+	if (udc->gadget.state != USB_STATE_DEFAULT &&
+	    udc->gadget.state != USB_STATE_ADDRESS) {
+		dev_dbg(udc->isp->dev, "can't set address in state %u\n",
+			udc->gadget.state);
+		return -EINVAL;
+	}
+
+	usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
+			     USB_STATE_DEFAULT);
+
+	isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr);
+
+	spin_lock(&udc->lock);
+	isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
+	spin_unlock(&udc->lock);
+
+	return 0;
+}
+
+static bool isp1760_ep0_setup_standard(struct isp1760_udc *udc,
+				       struct usb_ctrlrequest *req)
+{
+	bool stall;
+
+	switch (req->bRequest) {
+	case USB_REQ_GET_STATUS:
+		return isp1760_udc_get_status(udc, req);
+
+	case USB_REQ_CLEAR_FEATURE:
+		switch (req->bRequestType) {
+		case USB_DIR_OUT | USB_RECIP_DEVICE: {
+			/* TODO: Handle remote wakeup feature. */
+			return true;
+		}
+
+		case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
+			u16 index = le16_to_cpu(req->wIndex);
+			struct isp1760_ep *ep;
+
+			if (req->wLength != cpu_to_le16(0) ||
+			    req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
+				return true;
+
+			ep = isp1760_udc_find_ep(udc, index);
+			if (!ep)
+				return true;
+
+			spin_lock(&udc->lock);
+
+			/*
+			 * If the endpoint is wedged only the gadget can clear
+			 * the halt feature. Pretend success in that case, but
+			 * keep the endpoint halted.
+			 */
+			if (!ep->wedged)
+				stall = __isp1760_udc_set_halt(ep, false);
+			else
+				stall = false;
+
+			if (!stall)
+				isp1760_udc_ctrl_send_status(&udc->ep[0],
+							     USB_DIR_OUT);
+
+			spin_unlock(&udc->lock);
+			return stall;
+		}
+
+		default:
+			return true;
+		}
+		break;
+
+	case USB_REQ_SET_FEATURE:
+		switch (req->bRequestType) {
+		case USB_DIR_OUT | USB_RECIP_DEVICE: {
+			/* TODO: Handle remote wakeup and test mode features */
+			return true;
+		}
+
+		case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
+			u16 index = le16_to_cpu(req->wIndex);
+			struct isp1760_ep *ep;
+
+			if (req->wLength != cpu_to_le16(0) ||
+			    req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
+				return true;
+
+			ep = isp1760_udc_find_ep(udc, index);
+			if (!ep)
+				return true;
+
+			spin_lock(&udc->lock);
+
+			stall = __isp1760_udc_set_halt(ep, true);
+			if (!stall)
+				isp1760_udc_ctrl_send_status(&udc->ep[0],
+							     USB_DIR_OUT);
+
+			spin_unlock(&udc->lock);
+			return stall;
+		}
+
+		default:
+			return true;
+		}
+		break;
+
+	case USB_REQ_SET_ADDRESS:
+		if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			return true;
+
+		return isp1760_udc_set_address(udc, le16_to_cpu(req->wValue));
+
+	case USB_REQ_SET_CONFIGURATION:
+		if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			return true;
+
+		if (udc->gadget.state != USB_STATE_ADDRESS &&
+		    udc->gadget.state != USB_STATE_CONFIGURED)
+			return true;
+
+		stall = udc->driver->setup(&udc->gadget, req) < 0;
+		if (stall)
+			return true;
+
+		usb_gadget_set_state(&udc->gadget, req->wValue ?
+				     USB_STATE_CONFIGURED : USB_STATE_ADDRESS);
+
+		/*
+		 * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt
+		 * feature on all endpoints. There is however no need to do so
+		 * explicitly here as the gadget driver will disable and
+		 * reenable endpoints, clearing the halt feature.
+		 */
+		return false;
+
+	default:
+		return udc->driver->setup(&udc->gadget, req) < 0;
+	}
+}
+
+static void isp1760_ep0_setup(struct isp1760_udc *udc)
+{
+	union {
+		struct usb_ctrlrequest r;
+		u32 data[2];
+	} req;
+	unsigned int count;
+	bool stall = false;
+
+	spin_lock(&udc->lock);
+
+	isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP);
+
+	count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+	if (count != sizeof(req)) {
+		spin_unlock(&udc->lock);
+
+		dev_err(udc->isp->dev, "invalid length %u for setup packet\n",
+			count);
+
+		isp1760_udc_ctrl_send_stall(&udc->ep[0]);
+		return;
+	}
+
+	req.data[0] = isp1760_udc_read(udc, DC_DATAPORT);
+	req.data[1] = isp1760_udc_read(udc, DC_DATAPORT);
+
+	if (udc->ep0_state != ISP1760_CTRL_SETUP) {
+		spin_unlock(&udc->lock);
+		dev_dbg(udc->isp->dev, "unexpected SETUP packet\n");
+		return;
+	}
+
+	/* Move to the data stage. */
+	if (!req.r.wLength)
+		udc->ep0_state = ISP1760_CTRL_STATUS;
+	else if (req.r.bRequestType & USB_DIR_IN)
+		udc->ep0_state = ISP1760_CTRL_DATA_IN;
+	else
+		udc->ep0_state = ISP1760_CTRL_DATA_OUT;
+
+	udc->ep0_dir = req.r.bRequestType & USB_DIR_IN;
+	udc->ep0_length = le16_to_cpu(req.r.wLength);
+
+	spin_unlock(&udc->lock);
+
+	dev_dbg(udc->isp->dev,
+		"%s: bRequestType 0x%02x bRequest 0x%02x wValue 0x%04x wIndex 0x%04x wLength 0x%04x\n",
+		__func__, req.r.bRequestType, req.r.bRequest,
+		le16_to_cpu(req.r.wValue), le16_to_cpu(req.r.wIndex),
+		le16_to_cpu(req.r.wLength));
+
+	if ((req.r.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		stall = isp1760_ep0_setup_standard(udc, &req.r);
+	else
+		stall = udc->driver->setup(&udc->gadget, &req.r) < 0;
+
+	if (stall)
+		isp1760_udc_ctrl_send_stall(&udc->ep[0]);
+}
+
+/* -----------------------------------------------------------------------------
+ * Gadget Endpoint Operations
+ */
+
+static int isp1760_ep_enable(struct usb_ep *ep,
+			     const struct usb_endpoint_descriptor *desc)
+{
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	struct isp1760_udc *udc = uep->udc;
+	unsigned long flags;
+	unsigned int type;
+
+	dev_dbg(uep->udc->isp->dev, "%s\n", __func__);
+
+	/*
+	 * Validate the descriptor. The control endpoint can't be enabled
+	 * manually.
+	 */
+	if (desc->bDescriptorType != USB_DT_ENDPOINT ||
+	    desc->bEndpointAddress == 0 ||
+	    desc->bEndpointAddress != uep->addr ||
+	    le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) {
+		dev_dbg(udc->isp->dev,
+			"%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n",
+			__func__, desc->bDescriptorType,
+			desc->bEndpointAddress, uep->addr,
+			le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket);
+		return -EINVAL;
+	}
+
+	switch (usb_endpoint_type(desc)) {
+	case USB_ENDPOINT_XFER_ISOC:
+		type = DC_ENDPTYP_ISOC;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		type = DC_ENDPTYP_BULK;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		type = DC_ENDPTYP_INTERRUPT;
+		break;
+	case USB_ENDPOINT_XFER_CONTROL:
+	default:
+		dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	uep->desc = desc;
+	uep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	uep->rx_pending = false;
+	uep->halted = false;
+	uep->wedged = false;
+
+	isp1760_udc_select_ep(uep);
+	isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket);
+	isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
+	isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static int isp1760_ep_disable(struct usb_ep *ep)
+{
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	struct isp1760_udc *udc = uep->udc;
+	struct isp1760_request *req, *nreq;
+	LIST_HEAD(req_list);
+	unsigned long flags;
+
+	dev_dbg(udc->isp->dev, "%s\n", __func__);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!uep->desc) {
+		dev_dbg(udc->isp->dev, "%s: endpoint not enabled\n", __func__);
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EINVAL;
+	}
+
+	uep->desc = NULL;
+	uep->maxpacket = 0;
+
+	isp1760_udc_select_ep(uep);
+	isp1760_udc_write(udc, DC_EPTYPE, 0);
+
+	/* TODO Synchronize with the IRQ handler */
+
+	list_splice_init(&uep->queue, &req_list);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	list_for_each_entry_safe(req, nreq, &req_list, queue) {
+		list_del(&req->queue);
+		isp1760_udc_request_complete(uep, req, -ESHUTDOWN);
+	}
+
+	return 0;
+}
+
+static struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep,
+						    gfp_t gfp_flags)
+{
+	struct isp1760_request *req;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+
+	return &req->req;
+}
+
+static void isp1760_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct isp1760_request *req = req_to_udc_req(_req);
+
+	kfree(req);
+}
+
+static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
+			    gfp_t gfp_flags)
+{
+	struct isp1760_request *req = req_to_udc_req(_req);
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	struct isp1760_udc *udc = uep->udc;
+	bool complete = false;
+	unsigned long flags;
+	int ret = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	dev_dbg(udc->isp->dev,
+		"%s: req %p (%u bytes%s) ep %p(0x%02x)\n", __func__, _req,
+		_req->length, _req->zero ? " (zlp)" : "", uep, uep->addr);
+
+	req->ep = uep;
+
+	if (uep->addr == 0) {
+		if (_req->length != udc->ep0_length &&
+		    udc->ep0_state != ISP1760_CTRL_DATA_IN) {
+			dev_dbg(udc->isp->dev,
+				"%s: invalid length %u for req %p\n",
+				__func__, _req->length, req);
+			ret = -EINVAL;
+			goto done;
+		}
+
+		switch (udc->ep0_state) {
+		case ISP1760_CTRL_DATA_IN:
+			dev_dbg(udc->isp->dev, "%s: transmitting req %p\n",
+				__func__, req);
+
+			list_add_tail(&req->queue, &uep->queue);
+			isp1760_udc_transmit(uep, req);
+			break;
+
+		case ISP1760_CTRL_DATA_OUT:
+			list_add_tail(&req->queue, &uep->queue);
+			__isp1760_udc_select_ep(uep, USB_DIR_OUT);
+			isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+			break;
+
+		case ISP1760_CTRL_STATUS:
+			complete = true;
+			break;
+
+		default:
+			dev_dbg(udc->isp->dev, "%s: invalid ep0 state\n",
+				__func__);
+			ret = -EINVAL;
+			break;
+		}
+	} else if (uep->desc) {
+		bool empty = list_empty(&uep->queue);
+
+		list_add_tail(&req->queue, &uep->queue);
+		if ((uep->addr & USB_DIR_IN) && !uep->halted && empty)
+			isp1760_udc_transmit(uep, req);
+		else if (!(uep->addr & USB_DIR_IN) && uep->rx_pending)
+			complete = isp1760_udc_receive(uep, req);
+	} else {
+		dev_dbg(udc->isp->dev,
+			"%s: can't queue request to disabled ep%02x\n",
+			__func__, uep->addr);
+		ret = -ESHUTDOWN;
+	}
+
+done:
+	if (ret < 0)
+		req->ep = NULL;
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	if (complete)
+		isp1760_udc_request_complete(uep, req, 0);
+
+	return ret;
+}
+
+static int isp1760_ep_dequeue(struct usb_ep *ep, struct usb_request *_req)
+{
+	struct isp1760_request *req = req_to_udc_req(_req);
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	struct isp1760_udc *udc = uep->udc;
+	unsigned long flags;
+
+	dev_dbg(uep->udc->isp->dev, "%s(ep%02x)\n", __func__, uep->addr);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (req->ep != uep)
+		req = NULL;
+	else
+		list_del(&req->queue);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	if (!req)
+		return -EINVAL;
+
+	isp1760_udc_request_complete(uep, req, -ECONNRESET);
+	return 0;
+}
+
+static int __isp1760_ep_set_halt(struct isp1760_ep *uep, bool stall, bool wedge)
+{
+	struct isp1760_udc *udc = uep->udc;
+	int ret;
+
+	if (!uep->addr) {
+		/*
+		 * Halting the control endpoint is only valid as a delayed error
+		 * response to a SETUP packet. Make sure EP0 is in the right
+		 * stage and that the gadget isn't trying to clear the halt
+		 * condition.
+		 */
+		if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall ||
+			     wedge)) {
+			return -EINVAL;
+		}
+	}
+
+	if (uep->addr && !uep->desc) {
+		dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
+			uep->addr);
+		return -EINVAL;
+	}
+
+	if (uep->addr & USB_DIR_IN) {
+		/* Refuse to halt IN endpoints with active transfers. */
+		if (!list_empty(&uep->queue)) {
+			dev_dbg(udc->isp->dev,
+				"%s: ep%02x has request pending\n", __func__,
+				uep->addr);
+			return -EAGAIN;
+		}
+	}
+
+	ret = __isp1760_udc_set_halt(uep, stall);
+	if (ret < 0)
+		return ret;
+
+	if (!uep->addr) {
+		/*
+		 * Stalling EP0 completes the control transaction, move back to
+		 * the SETUP state.
+		 */
+		udc->ep0_state = ISP1760_CTRL_SETUP;
+		return 0;
+	}
+
+	if (wedge)
+		uep->wedged = true;
+	else if (!stall)
+		uep->wedged = false;
+
+	return 0;
+}
+
+static int isp1760_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	unsigned long flags;
+	int ret;
+
+	dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
+		value ? "set" : "clear", uep->addr);
+
+	spin_lock_irqsave(&uep->udc->lock, flags);
+	ret = __isp1760_ep_set_halt(uep, value, false);
+	spin_unlock_irqrestore(&uep->udc->lock, flags);
+
+	return ret;
+}
+
+static int isp1760_ep_set_wedge(struct usb_ep *ep)
+{
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	unsigned long flags;
+	int ret;
+
+	dev_dbg(uep->udc->isp->dev, "%s: set wedge on ep%02x)\n", __func__,
+		uep->addr);
+
+	spin_lock_irqsave(&uep->udc->lock, flags);
+	ret = __isp1760_ep_set_halt(uep, true, true);
+	spin_unlock_irqrestore(&uep->udc->lock, flags);
+
+	return ret;
+}
+
+static void isp1760_ep_fifo_flush(struct usb_ep *ep)
+{
+	struct isp1760_ep *uep = ep_to_udc_ep(ep);
+	struct isp1760_udc *udc = uep->udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	isp1760_udc_select_ep(uep);
+
+	/*
+	 * Set the CLBUF bit twice to flush both buffers in case double
+	 * buffering is enabled.
+	 */
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+	isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static const struct usb_ep_ops isp1760_ep_ops = {
+	.enable = isp1760_ep_enable,
+	.disable = isp1760_ep_disable,
+	.alloc_request = isp1760_ep_alloc_request,
+	.free_request = isp1760_ep_free_request,
+	.queue = isp1760_ep_queue,
+	.dequeue = isp1760_ep_dequeue,
+	.set_halt = isp1760_ep_set_halt,
+	.set_wedge = isp1760_ep_set_wedge,
+	.fifo_flush = isp1760_ep_fifo_flush,
+};
+
+/* -----------------------------------------------------------------------------
+ * Device States
+ */
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_connect(struct isp1760_udc *udc)
+{
+	usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
+	mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL);
+}
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_disconnect(struct isp1760_udc *udc)
+{
+	if (udc->gadget.state < USB_STATE_POWERED)
+		return;
+
+	dev_dbg(udc->isp->dev, "Device disconnected in state %u\n",
+		 udc->gadget.state);
+
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
+
+	if (udc->driver->disconnect)
+		udc->driver->disconnect(&udc->gadget);
+
+	del_timer(&udc->vbus_timer);
+
+	/* TODO Reset all endpoints ? */
+}
+
+static void isp1760_udc_init_hw(struct isp1760_udc *udc)
+{
+	/*
+	 * The device controller currently shares its interrupt with the host
+	 * controller, the DC_IRQ polarity and signaling mode are ignored. Set
+	 * the to active-low level-triggered.
+	 *
+	 * Configure the control, in and out pipes to generate interrupts on
+	 * ACK tokens only (and NYET for the out pipe). The default
+	 * configuration also generates an interrupt on the first NACK token.
+	 */
+	isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK |
+			  DC_DDBGMODOUT_ACK_NYET);
+
+	isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) |
+			  DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) |
+			  DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) |
+			  DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP |
+			  DC_IEHS_STA | DC_IEBRST);
+
+	if (udc->connected)
+		isp1760_set_pullup(udc->isp, true);
+
+	isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN);
+}
+
+static void isp1760_udc_reset(struct isp1760_udc *udc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * The bus reset has reset most registers to their default value,
+	 * reinitialize the UDC hardware.
+	 */
+	isp1760_udc_init_hw(udc);
+
+	udc->ep0_state = ISP1760_CTRL_SETUP;
+	udc->gadget.speed = USB_SPEED_FULL;
+
+	usb_gadget_udc_reset(&udc->gadget, udc->driver);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static void isp1760_udc_suspend(struct isp1760_udc *udc)
+{
+	if (udc->gadget.state < USB_STATE_DEFAULT)
+		return;
+
+	if (udc->driver->suspend)
+		udc->driver->suspend(&udc->gadget);
+}
+
+static void isp1760_udc_resume(struct isp1760_udc *udc)
+{
+	if (udc->gadget.state < USB_STATE_DEFAULT)
+		return;
+
+	if (udc->driver->resume)
+		udc->driver->resume(&udc->gadget);
+}
+
+/* -----------------------------------------------------------------------------
+ * Gadget Operations
+ */
+
+static int isp1760_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1);
+}
+
+static int isp1760_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	dev_dbg(udc->isp->dev, "%s\n", __func__);
+	return -ENOTSUPP;
+}
+
+static int isp1760_udc_set_selfpowered(struct usb_gadget *gadget,
+				       int is_selfpowered)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+	return 0;
+}
+
+static int isp1760_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	isp1760_set_pullup(udc->isp, is_on);
+	udc->connected = is_on;
+
+	return 0;
+}
+
+static int isp1760_udc_start(struct usb_gadget *gadget,
+			     struct usb_gadget_driver *driver)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	/* The hardware doesn't support low speed. */
+	if (driver->max_speed < USB_SPEED_FULL) {
+		dev_err(udc->isp->dev, "Invalid gadget driver\n");
+		return -EINVAL;
+	}
+
+	spin_lock(&udc->lock);
+
+	if (udc->driver) {
+		dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
+		spin_unlock(&udc->lock);
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+
+	spin_unlock(&udc->lock);
+
+	dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
+		driver->function);
+
+	udc->devstatus = 0;
+	udc->connected = true;
+
+	usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
+
+	/* DMA isn't supported yet, don't enable the DMA clock. */
+	isp1760_udc_write(udc, DC_MODE, DC_GLINTENA);
+
+	isp1760_udc_init_hw(udc);
+
+	dev_dbg(udc->isp->dev, "UDC started with driver %s\n",
+		driver->function);
+
+	return 0;
+}
+
+static int isp1760_udc_stop(struct usb_gadget *gadget)
+{
+	struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+	dev_dbg(udc->isp->dev, "%s\n", __func__);
+
+	del_timer_sync(&udc->vbus_timer);
+
+	isp1760_udc_write(udc, DC_MODE, 0);
+
+	spin_lock(&udc->lock);
+	udc->driver = NULL;
+	spin_unlock(&udc->lock);
+
+	return 0;
+}
+
+static struct usb_gadget_ops isp1760_udc_ops = {
+	.get_frame = isp1760_udc_get_frame,
+	.wakeup = isp1760_udc_wakeup,
+	.set_selfpowered = isp1760_udc_set_selfpowered,
+	.pullup = isp1760_udc_pullup,
+	.udc_start = isp1760_udc_start,
+	.udc_stop = isp1760_udc_stop,
+};
+
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
+
+static irqreturn_t isp1760_udc_irq(int irq, void *dev)
+{
+	struct isp1760_udc *udc = dev;
+	unsigned int i;
+	u32 status;
+
+	status = isp1760_udc_read(udc, DC_INTERRUPT)
+	       & isp1760_udc_read(udc, DC_INTENABLE);
+	isp1760_udc_write(udc, DC_INTERRUPT, status);
+
+	if (status & DC_IEVBUS) {
+		dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
+		/* The VBUS interrupt is only triggered when VBUS appears. */
+		spin_lock(&udc->lock);
+		isp1760_udc_connect(udc);
+		spin_unlock(&udc->lock);
+	}
+
+	if (status & DC_IEBRST) {
+		dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__);
+
+		isp1760_udc_reset(udc);
+	}
+
+	for (i = 0; i <= 7; ++i) {
+		struct isp1760_ep *ep = &udc->ep[i*2];
+
+		if (status & DC_IEPTX(i)) {
+			dev_dbg(udc->isp->dev, "%s(EPTX%u)\n", __func__, i);
+			isp1760_ep_tx_complete(ep);
+		}
+
+		if (status & DC_IEPRX(i)) {
+			dev_dbg(udc->isp->dev, "%s(EPRX%u)\n", __func__, i);
+			isp1760_ep_rx_ready(i ? ep - 1 : ep);
+		}
+	}
+
+	if (status & DC_IEP0SETUP) {
+		dev_dbg(udc->isp->dev, "%s(EP0SETUP)\n", __func__);
+
+		isp1760_ep0_setup(udc);
+	}
+
+	if (status & DC_IERESM) {
+		dev_dbg(udc->isp->dev, "%s(RESM)\n", __func__);
+		isp1760_udc_resume(udc);
+	}
+
+	if (status & DC_IESUSP) {
+		dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
+
+		spin_lock(&udc->lock);
+		if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+			isp1760_udc_disconnect(udc);
+		else
+			isp1760_udc_suspend(udc);
+		spin_unlock(&udc->lock);
+	}
+
+	if (status & DC_IEHS_STA) {
+		dev_dbg(udc->isp->dev, "%s(HS_STA)\n", __func__);
+		udc->gadget.speed = USB_SPEED_HIGH;
+	}
+
+	return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void isp1760_udc_vbus_poll(unsigned long data)
+{
+	struct isp1760_udc *udc = (struct isp1760_udc *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+		isp1760_udc_disconnect(udc);
+	else if (udc->gadget.state >= USB_STATE_POWERED)
+		mod_timer(&udc->vbus_timer,
+			  jiffies + ISP1760_VBUS_POLL_INTERVAL);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Registration
+ */
+
+static void isp1760_udc_init_eps(struct isp1760_udc *udc)
+{
+	unsigned int i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	for (i = 0; i < ARRAY_SIZE(udc->ep); ++i) {
+		struct isp1760_ep *ep = &udc->ep[i];
+		unsigned int ep_num = (i + 1) / 2;
+		bool is_in = !(i & 1);
+
+		ep->udc = udc;
+
+		INIT_LIST_HEAD(&ep->queue);
+
+		ep->addr = (ep_num && is_in ? USB_DIR_IN : USB_DIR_OUT)
+			 | ep_num;
+		ep->desc = NULL;
+
+		sprintf(ep->name, "ep%u%s", ep_num,
+			ep_num ? (is_in ? "in" : "out") : "");
+
+		ep->ep.ops = &isp1760_ep_ops;
+		ep->ep.name = ep->name;
+
+		/*
+		 * Hardcode the maximum packet sizes for now, to 64 bytes for
+		 * the control endpoint and 512 bytes for all other endpoints.
+		 * This fits in the 8kB FIFO without double-buffering.
+		 */
+		if (ep_num == 0) {
+			ep->ep.maxpacket = 64;
+			ep->maxpacket = 64;
+			udc->gadget.ep0 = &ep->ep;
+		} else {
+			ep->ep.maxpacket = 512;
+			ep->maxpacket = 0;
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		}
+	}
+}
+
+static int isp1760_udc_init(struct isp1760_udc *udc)
+{
+	u16 scratch;
+	u32 chipid;
+
+	/*
+	 * Check that the controller is present by writing to the scratch
+	 * register, modifying the bus pattern by reading from the chip ID
+	 * register, and reading the scratch register value back. The chip ID
+	 * and scratch register contents must match the expected values.
+	 */
+	isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
+	chipid = isp1760_udc_read(udc, DC_CHIPID);
+	scratch = isp1760_udc_read(udc, DC_SCRATCH);
+
+	if (scratch != 0xbabe) {
+		dev_err(udc->isp->dev,
+			"udc: scratch test failed (0x%04x/0x%08x)\n",
+			scratch, chipid);
+		return -ENODEV;
+	}
+
+	if (chipid != 0x00011582) {
+		dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
+		return -ENODEV;
+	}
+
+	/* Reset the device controller. */
+	isp1760_udc_write(udc, DC_MODE, DC_SFRESET);
+	usleep_range(10000, 11000);
+	isp1760_udc_write(udc, DC_MODE, 0);
+	usleep_range(10000, 11000);
+
+	return 0;
+}
+
+int isp1760_udc_register(struct isp1760_device *isp, int irq,
+			 unsigned long irqflags)
+{
+	struct isp1760_udc *udc = &isp->udc;
+	const char *devname;
+	int ret;
+
+	udc->irq = -1;
+	udc->isp = isp;
+	udc->regs = isp->regs;
+
+	spin_lock_init(&udc->lock);
+	setup_timer(&udc->vbus_timer, isp1760_udc_vbus_poll,
+		    (unsigned long)udc);
+
+	ret = isp1760_udc_init(udc);
+	if (ret < 0)
+		return ret;
+
+	devname = dev_name(isp->dev);
+	udc->irqname = kmalloc(strlen(devname) + 7, GFP_KERNEL);
+	if (!udc->irqname)
+		return -ENOMEM;
+
+	sprintf(udc->irqname, "%s (udc)", devname);
+
+	ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED |
+			  irqflags, udc->irqname, udc);
+	if (ret < 0)
+		goto error;
+
+	udc->irq = irq;
+
+	/*
+	 * Initialize the gadget static fields and register its device. Gadget
+	 * fields that vary during the life time of the gadget are initialized
+	 * by the UDC core.
+	 */
+	udc->gadget.ops = &isp1760_udc_ops;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed = USB_SPEED_HIGH;
+	udc->gadget.name = "isp1761_udc";
+
+	isp1760_udc_init_eps(udc);
+
+	ret = usb_add_gadget_udc(isp->dev, &udc->gadget);
+	if (ret < 0)
+		goto error;
+
+	return 0;
+
+error:
+	if (udc->irq >= 0)
+		free_irq(udc->irq, udc);
+	kfree(udc->irqname);
+
+	return ret;
+}
+
+void isp1760_udc_unregister(struct isp1760_device *isp)
+{
+	struct isp1760_udc *udc = &isp->udc;
+
+	if (!udc->isp)
+		return;
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	free_irq(udc->irq, udc);
+	kfree(udc->irqname);
+}
diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h
new file mode 100644
index 0000000..26899ed
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-udc.h
@@ -0,0 +1,106 @@
+/*
+ * Driver for the NXP ISP1761 device controller
+ *
+ * Copyright 2014 Ideas on Board Oy
+ *
+ * Contacts:
+ *	Laurent Pinchart <laurent.pinchart@ideasonboard.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 _ISP1760_UDC_H_
+#define _ISP1760_UDC_H_
+
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/usb/gadget.h>
+
+struct isp1760_device;
+struct isp1760_udc;
+
+enum isp1760_ctrl_state {
+	ISP1760_CTRL_SETUP,		/* Waiting for a SETUP transaction */
+	ISP1760_CTRL_DATA_IN,		/* Setup received, data IN stage */
+	ISP1760_CTRL_DATA_OUT,		/* Setup received, data OUT stage */
+	ISP1760_CTRL_STATUS,		/* 0-length request in status stage */
+};
+
+struct isp1760_ep {
+	struct isp1760_udc *udc;
+	struct usb_ep ep;
+
+	struct list_head queue;
+
+	unsigned int addr;
+	unsigned int maxpacket;
+	char name[7];
+
+	const struct usb_endpoint_descriptor *desc;
+
+	bool rx_pending;
+	bool halted;
+	bool wedged;
+};
+
+/**
+ * struct isp1760_udc - UDC state information
+ * irq: IRQ number
+ * irqname: IRQ name (as passed to request_irq)
+ * regs: Base address of the UDC registers
+ * driver: Gadget driver
+ * gadget: Gadget device
+ * lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
+ * ep: Array of endpoints
+ * ep0_state: Control request state for endpoint 0
+ * ep0_dir: Direction of the current control request
+ * ep0_length: Length of the current control request
+ * connected: Tracks gadget driver bus connection state
+ */
+struct isp1760_udc {
+#ifdef CONFIG_USB_ISP1761_UDC
+	struct isp1760_device *isp;
+
+	int irq;
+	char *irqname;
+	void __iomem *regs;
+
+	struct usb_gadget_driver *driver;
+	struct usb_gadget gadget;
+
+	spinlock_t lock;
+	struct timer_list vbus_timer;
+
+	struct isp1760_ep ep[15];
+
+	enum isp1760_ctrl_state ep0_state;
+	u8 ep0_dir;
+	u16 ep0_length;
+
+	bool connected;
+
+	unsigned int devstatus;
+#endif
+};
+
+#ifdef CONFIG_USB_ISP1761_UDC
+int isp1760_udc_register(struct isp1760_device *isp, int irq,
+			 unsigned long irqflags);
+void isp1760_udc_unregister(struct isp1760_device *isp);
+#else
+static inline int isp1760_udc_register(struct isp1760_device *isp, int irq,
+				       unsigned long irqflags)
+{
+	return 0;
+}
+
+static inline void isp1760_udc_unregister(struct isp1760_device *isp)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 40ef40a..588d62a 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -124,12 +124,8 @@
 	} else if (rq->dr->bRequest == 3) {
 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
-		dev_dbg(&priv->usbdev->dev,
-			"async_complete regs %02x %02x %02x %02x %02x %02x %02x\n",
-			(unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
-			(unsigned int)priv->reg[2], (unsigned int)priv->reg[3],
-			(unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
-			(unsigned int)priv->reg[6]);
+		dev_dbg(&priv->usbdev->dev, "async_complete regs %7ph\n",
+			priv->reg);
 #endif
 		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
 		if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
@@ -742,9 +738,7 @@
 	set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
 	/* debugging */
 	get_1284_register(pp, 0, &reg, GFP_KERNEL);
-	dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n",
-		priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3],
-		priv->reg[4], priv->reg[5], priv->reg[6]);
+	dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
 
 	endpoint = &interface->endpoint[2];
 	dev_dbg(&intf->dev, "epaddr %d interval %d\n",
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b005010..14e1628 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -63,11 +63,13 @@
 config USB_MUSB_DAVINCI
 	tristate "DaVinci"
 	depends on ARCH_DAVINCI_DMx
+	depends on NOP_USB_XCEIV
 	depends on BROKEN
 
 config USB_MUSB_DA8XX
 	tristate "DA8xx/OMAP-L1x"
 	depends on ARCH_DAVINCI_DA8XX
+	depends on NOP_USB_XCEIV
 	depends on BROKEN
 
 config USB_MUSB_TUSB6010
@@ -77,12 +79,13 @@
 
 config USB_MUSB_OMAP2PLUS
 	tristate "OMAP2430 and onwards"
-	depends on ARCH_OMAP2PLUS && USB
+	depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
 	select GENERIC_PHY
 
 config USB_MUSB_AM35X
 	tristate "AM35x"
 	depends on ARCH_OMAP
+	depends on NOP_USB_XCEIV
 
 config USB_MUSB_DSPS
 	tristate "TI DSPS platforms"
@@ -93,6 +96,7 @@
 config USB_MUSB_BLACKFIN
 	tristate "Blackfin"
 	depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
+	depends on NOP_USB_XCEIV
 
 config USB_MUSB_UX500
 	tristate "Ux500 platforms"
@@ -100,6 +104,7 @@
 
 config USB_MUSB_JZ4740
 	tristate "JZ4740"
+	depends on NOP_USB_XCEIV
 	depends on MACH_JZ4740 || COMPILE_TEST
 	depends on USB_MUSB_GADGET
 	depends on USB_OTG_BLACKLIST_HUB
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 1782501..6123b74 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -608,7 +608,7 @@
 
 static struct platform_driver bfin_driver = {
 	.probe		= bfin_probe,
-	.remove		= __exit_p(bfin_remove),
+	.remove		= bfin_remove,
 	.driver		= {
 		.name	= "musb-blackfin",
 		.pm	= &bfin_pm_ops,
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 34cce3e..e6f4cbf 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -567,6 +567,7 @@
 
 				musb->xceiv->otg->state = OTG_STATE_A_HOST;
 				musb->is_active = 1;
+				musb_host_resume_root_hub(musb);
 				break;
 			case OTG_STATE_B_WAIT_ACON:
 				musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@@ -2500,6 +2501,12 @@
 		musb_restore_context(musb);
 	first = 0;
 
+	if (musb->need_finish_resume) {
+		musb->need_finish_resume = 0;
+		schedule_delayed_work(&musb->finish_resume_work,
+				msecs_to_jiffies(20));
+	}
+
 	return 0;
 }
 
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index c39a16a..be84562 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -9,9 +9,9 @@
 
 #define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
 
-#define EP_MODE_AUTOREG_NONE		0
-#define EP_MODE_AUTOREG_ALL_NEOP	1
-#define EP_MODE_AUTOREG_ALWAYS		3
+#define EP_MODE_AUTOREQ_NONE		0
+#define EP_MODE_AUTOREQ_ALL_NEOP	1
+#define EP_MODE_AUTOREQ_ALWAYS		3
 
 #define EP_MODE_DMA_TRANSPARENT		0
 #define EP_MODE_DMA_RNDIS		1
@@ -404,19 +404,19 @@
 
 			/* auto req */
 			cppi41_set_autoreq_mode(cppi41_channel,
-					EP_MODE_AUTOREG_ALL_NEOP);
+					EP_MODE_AUTOREQ_ALL_NEOP);
 		} else {
 			musb_writel(musb->ctrl_base,
 					RNDIS_REG(cppi41_channel->port_num), 0);
 			cppi41_set_dma_mode(cppi41_channel,
 					EP_MODE_DMA_TRANSPARENT);
 			cppi41_set_autoreq_mode(cppi41_channel,
-					EP_MODE_AUTOREG_NONE);
+					EP_MODE_AUTOREQ_NONE);
 		}
 	} else {
 		/* fallback mode */
 		cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
-		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
 		len = min_t(u32, packet_sz, len);
 	}
 	cppi41_channel->prog_len = len;
@@ -549,10 +549,15 @@
 		csr &= ~MUSB_TXCSR_DMAENAB;
 		musb_writew(epio, MUSB_TXCSR, csr);
 	} else {
+		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
+
 		csr = musb_readw(epio, MUSB_RXCSR);
 		csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
 		musb_writew(epio, MUSB_RXCSR, csr);
 
+		/* wait to drain cppi dma pipe line */
+		udelay(50);
+
 		csr = musb_readw(epio, MUSB_RXCSR);
 		if (csr & MUSB_RXCSR_RXPKTRDY) {
 			csr |= MUSB_RXCSR_FLUSHFIFO;
@@ -566,13 +571,14 @@
 		tdbit <<= 16;
 
 	do {
-		musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+		if (is_tx)
+			musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
 		ret = dmaengine_terminate_all(cppi41_channel->dc);
 	} while (ret == -EAGAIN);
 
-	musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
-
 	if (is_tx) {
+		musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
 		csr = musb_readw(epio, MUSB_TXCSR);
 		if (csr & MUSB_TXCSR_TXPKTRDY) {
 			csr |= MUSB_TXCSR_FLUSHFIFO;
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 48131aa..78a283e 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -196,7 +196,7 @@
 
 	memset(buf, 0x00, sizeof(buf));
 
-	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 		return -EFAULT;
 
 	if (strstarts(buf, "force host"))
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 49b04cb..b2d9040 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1612,9 +1612,7 @@
 static int
 musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
 {
-	struct musb	*musb = gadget_to_musb(gadget);
-
-	musb->is_self_powered = !!is_selfpowered;
+	gadget->is_selfpowered = !!is_selfpowered;
 	return 0;
 }
 
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 2af45a0..10d30af 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -85,7 +85,7 @@
 
 	switch (recip) {
 	case USB_RECIP_DEVICE:
-		result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
+		result[0] = musb->g.is_selfpowered << USB_DEVICE_SELF_POWERED;
 		result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
 		if (musb->g.is_otg) {
 			result[0] |= musb->g.b_hnp_enable
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index b072420..294e159 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -72,7 +72,6 @@
 	musb->xceiv->otg->state = OTG_STATE_A_HOST;
 
 	spin_unlock_irqrestore(&musb->lock, flags);
-	musb_host_resume_root_hub(musb);
 }
 
 void musb_port_suspend(struct musb *musb, bool do_suspend)
@@ -349,9 +348,9 @@
 		desc->bDescriptorType = 0x29;
 		desc->bNbrPorts = 1;
 		desc->wHubCharacteristics = cpu_to_le16(
-				  0x0001	/* per-port power switching */
-				| 0x0010	/* no overcurrent reporting */
-				);
+			HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
+			| HUB_CHAR_NO_OCPM	/* no overcurrent reporting */
+			);
 		desc->bPwrOn2PwrGood = 5;	/* msec/2 */
 		desc->bHubContrCurrent = 0;
 
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index ab38aa3..94eb292 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -107,19 +107,6 @@
 #define fsl_writel(val, addr)	writel(val, addr)
 #endif /* CONFIG_PPC32 */
 
-/* Routines to access transceiver ULPI registers */
-u8 view_ulpi(u8 addr)
-{
-	u32 temp;
-
-	temp = 0x40000000 | (addr << 16);
-	fsl_writel(temp, &usb_dr_regs->ulpiview);
-	udelay(1000);
-	while (temp & 0x40)
-		temp = fsl_readl(&usb_dr_regs->ulpiview);
-	return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
-}
-
 int write_ulpi(u8 addr, u8 data)
 {
 	u32 temp;
@@ -460,28 +447,6 @@
 	fsl_otg_del_timer(fsm, timer);
 }
 
-/*
- * Reduce timer count by 1, and find timeout conditions.
- * Called by fsl_otg 1ms timer interrupt
- */
-int fsl_otg_tick_timer(void)
-{
-	struct fsl_otg_timer *tmp_timer, *del_tmp;
-	int expired = 0;
-
-	list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
-		tmp_timer->count--;
-		/* check if timer expires */
-		if (!tmp_timer->count) {
-			list_del(&tmp_timer->list);
-			tmp_timer->function(tmp_timer->data);
-			expired = 1;
-		}
-	}
-
-	return expired;
-}
-
 /* Reset controller, not reset the bus */
 void otg_reset_controller(void)
 {
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index f1b719b..70be50b 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/usb_phy_generic.h>
 #include <linux/slab.h>
@@ -39,6 +40,10 @@
 
 #include "phy-generic.h"
 
+#define VBUS_IRQ_FLAGS \
+	(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
+		IRQF_ONESHOT)
+
 struct platform_device *usb_phy_generic_register(void)
 {
 	return platform_device_register_simple("usb_phy_generic",
@@ -59,19 +64,79 @@
 
 static void nop_reset_set(struct usb_phy_generic *nop, int asserted)
 {
-	int value;
-
-	if (!gpio_is_valid(nop->gpio_reset))
+	if (!nop->gpiod_reset)
 		return;
 
-	value = asserted;
-	if (nop->reset_active_low)
-		value = !value;
+	gpiod_direction_output(nop->gpiod_reset, !asserted);
+	usleep_range(10000, 20000);
+	gpiod_set_value(nop->gpiod_reset, asserted);
+}
 
-	gpio_set_value_cansleep(nop->gpio_reset, value);
+/* interface to regulator framework */
+static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
+{
+	struct regulator *vbus_draw = nop->vbus_draw;
+	int enabled;
+	int ret;
 
-	if (!asserted)
-		usleep_range(10000, 20000);
+	if (!vbus_draw)
+		return;
+
+	enabled = nop->vbus_draw_enabled;
+	if (mA) {
+		regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
+		if (!enabled) {
+			ret = regulator_enable(vbus_draw);
+			if (ret < 0)
+				return;
+			nop->vbus_draw_enabled = 1;
+		}
+	} else {
+		if (enabled) {
+			ret = regulator_disable(vbus_draw);
+			if (ret < 0)
+				return;
+			nop->vbus_draw_enabled = 0;
+		}
+	}
+	nop->mA = mA;
+}
+
+
+static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
+{
+	struct usb_phy_generic *nop = data;
+	struct usb_otg *otg = nop->phy.otg;
+	int vbus, status;
+
+	vbus = gpiod_get_value(nop->gpiod_vbus);
+	if ((vbus ^ nop->vbus) == 0)
+		return IRQ_HANDLED;
+	nop->vbus = vbus;
+
+	if (vbus) {
+		status = USB_EVENT_VBUS;
+		otg->state = OTG_STATE_B_PERIPHERAL;
+		nop->phy.last_event = status;
+		usb_gadget_vbus_connect(otg->gadget);
+
+		/* drawing a "unit load" is *always* OK, except for OTG */
+		nop_set_vbus_draw(nop, 100);
+
+		atomic_notifier_call_chain(&nop->phy.notifier, status,
+					   otg->gadget);
+	} else {
+		nop_set_vbus_draw(nop, 0);
+
+		usb_gadget_vbus_disconnect(otg->gadget);
+		status = USB_EVENT_NONE;
+		otg->state = OTG_STATE_B_IDLE;
+		nop->phy.last_event = status;
+
+		atomic_notifier_call_chain(&nop->phy.notifier, status,
+					   otg->gadget);
+	}
+	return IRQ_HANDLED;
 }
 
 int usb_gen_phy_init(struct usb_phy *phy)
@@ -143,37 +208,48 @@
 		struct usb_phy_generic_platform_data *pdata)
 {
 	enum usb_phy_type type = USB_PHY_TYPE_USB2;
-	int err;
+	int err = 0;
 
 	u32 clk_rate = 0;
 	bool needs_vcc = false;
 
-	nop->reset_active_low = true;	/* default behaviour */
-
 	if (dev->of_node) {
 		struct device_node *node = dev->of_node;
-		enum of_gpio_flags flags = 0;
 
 		if (of_property_read_u32(node, "clock-frequency", &clk_rate))
 			clk_rate = 0;
 
 		needs_vcc = of_property_read_bool(node, "vcc-supply");
-		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
-								0, &flags);
-		if (nop->gpio_reset == -EPROBE_DEFER)
-			return -EPROBE_DEFER;
-
-		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
-
+		nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
+		err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
+		if (!err) {
+			nop->gpiod_vbus = devm_gpiod_get_optional(dev,
+							 "vbus-detect");
+			err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
+		}
 	} else if (pdata) {
 		type = pdata->type;
 		clk_rate = pdata->clk_rate;
 		needs_vcc = pdata->needs_vcc;
-		nop->gpio_reset = pdata->gpio_reset;
-	} else {
-		nop->gpio_reset = -1;
+		if (gpio_is_valid(pdata->gpio_reset)) {
+			err = devm_gpio_request_one(dev, pdata->gpio_reset, 0,
+						    dev_name(dev));
+			if (!err)
+				nop->gpiod_reset =
+					gpio_to_desc(pdata->gpio_reset);
+		}
+		nop->gpiod_vbus = pdata->gpiod_vbus;
 	}
 
+	if (err == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (err) {
+		dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
+		return err;
+	}
+	if (nop->gpiod_reset)
+		gpiod_direction_output(nop->gpiod_reset, 1);
+
 	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
 			GFP_KERNEL);
 	if (!nop->phy.otg)
@@ -201,24 +277,6 @@
 			return -EPROBE_DEFER;
 	}
 
-	if (gpio_is_valid(nop->gpio_reset)) {
-		unsigned long gpio_flags;
-
-		/* Assert RESET */
-		if (nop->reset_active_low)
-			gpio_flags = GPIOF_OUT_INIT_LOW;
-		else
-			gpio_flags = GPIOF_OUT_INIT_HIGH;
-
-		err = devm_gpio_request_one(dev, nop->gpio_reset,
-						gpio_flags, dev_name(dev));
-		if (err) {
-			dev_err(dev, "Error requesting RESET GPIO %d\n",
-					nop->gpio_reset);
-			return err;
-		}
-	}
-
 	nop->dev		= dev;
 	nop->phy.dev		= nop->dev;
 	nop->phy.label		= "nop-xceiv";
@@ -247,6 +305,18 @@
 	err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
 	if (err)
 		return err;
+	if (nop->gpiod_vbus) {
+		err = devm_request_threaded_irq(&pdev->dev,
+						gpiod_to_irq(nop->gpiod_vbus),
+						NULL, nop_gpio_vbus_thread,
+						VBUS_IRQ_FLAGS, "vbus_detect",
+						nop);
+		if (err) {
+			dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
+				gpiod_to_irq(nop->gpiod_vbus), err);
+			return err;
+		}
+	}
 
 	nop->phy.init		= usb_gen_phy_init;
 	nop->phy.shutdown	= usb_gen_phy_shutdown;
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
index d8feacc..0d0eadd 100644
--- a/drivers/usb/phy/phy-generic.h
+++ b/drivers/usb/phy/phy-generic.h
@@ -2,14 +2,20 @@
 #define _PHY_GENERIC_H_
 
 #include <linux/usb/usb_phy_generic.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
 
 struct usb_phy_generic {
 	struct usb_phy phy;
 	struct device *dev;
 	struct clk *clk;
 	struct regulator *vcc;
-	int gpio_reset;
-	bool reset_active_low;
+	struct gpio_desc *gpiod_reset;
+	struct gpio_desc *gpiod_vbus;
+	struct regulator *vbus_draw;
+	bool vbus_draw_enabled;
+	unsigned long mA;
+	unsigned int vbus;
 };
 
 int usb_gen_phy_init(struct usb_phy *phy);
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index b9589f6..8f7cb06 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -40,6 +40,7 @@
 
 #define BM_USBPHY_CTRL_SFTRST			BIT(31)
 #define BM_USBPHY_CTRL_CLKGATE			BIT(30)
+#define BM_USBPHY_CTRL_OTG_ID_VALUE		BIT(27)
 #define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS	BIT(26)
 #define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE	BIT(25)
 #define BM_USBPHY_CTRL_ENVBUSCHG_WKUP		BIT(23)
@@ -69,6 +70,9 @@
 #define ANADIG_USB2_LOOPBACK_SET		0x244
 #define ANADIG_USB2_LOOPBACK_CLR		0x248
 
+#define ANADIG_USB1_MISC			0x1f0
+#define ANADIG_USB2_MISC			0x250
+
 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	BIT(12)
 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
 
@@ -80,6 +84,11 @@
 #define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1	BIT(2)
 #define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN	BIT(5)
 
+#define BM_ANADIG_USB1_MISC_RX_VPIN_FS		BIT(29)
+#define BM_ANADIG_USB1_MISC_RX_VMIN_FS		BIT(28)
+#define BM_ANADIG_USB2_MISC_RX_VPIN_FS		BIT(29)
+#define BM_ANADIG_USB2_MISC_RX_VMIN_FS		BIT(28)
+
 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
 
 /* Do disconnection between PHY and controller without vbus */
@@ -131,8 +140,7 @@
 };
 
 static const struct mxs_phy_data imx6sx_phy_data = {
-	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
-		MXS_PHY_NEED_IP_FIX,
+	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
 };
 
 static const struct of_device_id mxs_phy_dt_ids[] = {
@@ -256,6 +264,18 @@
 		usleep_range(500, 1000);
 }
 
+static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
+{
+	void __iomem *base = mxs_phy->phy.io_priv;
+	u32 phyctrl = readl(base + HW_USBPHY_CTRL);
+
+	if (IS_ENABLED(CONFIG_USB_OTG) &&
+			!(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
+		return true;
+
+	return false;
+}
+
 static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
 {
 	bool vbus_is_on = false;
@@ -270,7 +290,7 @@
 
 	vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
 
-	if (on && !vbus_is_on)
+	if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
 		__mxs_phy_disconnect_line(mxs_phy, true);
 	else
 		__mxs_phy_disconnect_line(mxs_phy, false);
@@ -293,6 +313,17 @@
 static void mxs_phy_shutdown(struct usb_phy *phy)
 {
 	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+	u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
+			BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
+			BM_USBPHY_CTRL_ENIDCHG_WKUP |
+			BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
+			BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
+			BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
+			BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
+			BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
+
+	writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
+	writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
 
 	writel(BM_USBPHY_CTRL_CLKGATE,
 	       phy->io_priv + HW_USBPHY_CTRL_SET);
@@ -300,13 +331,56 @@
 	clk_disable_unprepare(mxs_phy->clk);
 }
 
+static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
+{
+	unsigned int line_state;
+	/* bit definition is the same for all controllers */
+	unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
+		     dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
+	unsigned int reg = ANADIG_USB1_MISC;
+
+	/* If the SoCs don't have anatop, quit */
+	if (!mxs_phy->regmap_anatop)
+		return false;
+
+	if (mxs_phy->port_id == 0)
+		reg = ANADIG_USB1_MISC;
+	else if (mxs_phy->port_id == 1)
+		reg = ANADIG_USB2_MISC;
+
+	regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
+
+	if ((line_state & (dp_bit | dm_bit)) ==  dm_bit)
+		return true;
+	else
+		return false;
+}
+
 static int mxs_phy_suspend(struct usb_phy *x, int suspend)
 {
 	int ret;
 	struct mxs_phy *mxs_phy = to_mxs_phy(x);
+	bool low_speed_connection, vbus_is_on;
+
+	low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
+	vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
 
 	if (suspend) {
-		writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+		/*
+		 * FIXME: Do not power down RXPWD1PT1 bit for low speed
+		 * connect. The low speed connection will have problem at
+		 * very rare cases during usb suspend and resume process.
+		 */
+		if (low_speed_connection & vbus_is_on) {
+			/*
+			 * If value to be set as pwd value is not 0xffffffff,
+			 * several 32Khz cycles are needed.
+			 */
+			mxs_phy_clock_switch_delay();
+			writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
+		} else {
+			writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+		}
 		writel(BM_USBPHY_CTRL_CLKGATE,
 		       x->io_priv + HW_USBPHY_CTRL_SET);
 		clk_disable_unprepare(mxs_phy->clk);
@@ -359,7 +433,9 @@
 	dev_dbg(phy->dev, "%s device has disconnected\n",
 		(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
 
-	if (speed == USB_SPEED_HIGH)
+	/* Sometimes, the speed is not high speed when the error occurs */
+	if (readl(phy->io_priv + HW_USBPHY_CTRL) &
+			BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
 		writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
 		       phy->io_priv + HW_USBPHY_CTRL_CLR);
 
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 3714787..4cf77d3 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -363,6 +363,7 @@
 	struct usbhs_mod *mod = usbhs_mod_get_current(priv);
 	int id;
 	int enable;
+	int cable;
 	int ret;
 
 	/*
@@ -376,6 +377,16 @@
 	id = usbhs_platform_call(priv, get_id, pdev);
 
 	if (enable && !mod) {
+		if (priv->edev) {
+			cable = extcon_get_cable_state(priv->edev, "USB-HOST");
+			if ((cable > 0 && id != USBHS_HOST) ||
+			    (!cable && id != USBHS_GADGET)) {
+				dev_info(&pdev->dev,
+					 "USB cable plugged in doesn't match the selected role!\n");
+				return;
+			}
+		}
+
 		ret = usbhs_mod_change(priv, id);
 		if (ret < 0)
 			return;
@@ -514,6 +525,12 @@
 	if (IS_ERR(priv->base))
 		return PTR_ERR(priv->base);
 
+	if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
+		priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+		if (IS_ERR(priv->edev))
+			return PTR_ERR(priv->edev);
+	}
+
 	/*
 	 * care platform info
 	 */
@@ -615,7 +632,7 @@
 	 */
 	ret = usbhs_platform_call(priv, hardware_init, pdev);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "platform prove failed.\n");
+		dev_err(&pdev->dev, "platform init failed.\n");
 		goto probe_end_mod_exit;
 	}
 
@@ -632,16 +649,12 @@
 	/*
 	 * manual call notify_hotplug for cold plug
 	 */
-	ret = usbhsc_drvcllbck_notify_hotplug(pdev);
-	if (ret < 0)
-		goto probe_end_call_remove;
+	usbhsc_drvcllbck_notify_hotplug(pdev);
 
 	dev_info(&pdev->dev, "probed\n");
 
 	return ret;
 
-probe_end_call_remove:
-	usbhs_platform_call(priv, hardware_exit, pdev);
 probe_end_mod_exit:
 	usbhs_mod_remove(priv);
 probe_end_fifo_exit:
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 0427cdd..fc96e92 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -17,6 +17,7 @@
 #ifndef RENESAS_USB_DRIVER_H
 #define RENESAS_USB_DRIVER_H
 
+#include <linux/extcon.h>
 #include <linux/platform_device.h>
 #include <linux/usb/renesas_usbhs.h>
 
@@ -254,6 +255,8 @@
 	struct delayed_work notify_hotplug_work;
 	struct platform_device *pdev;
 
+	struct extcon_dev *edev;
+
 	spinlock_t		lock;
 
 	u32 flags;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index f46271c..d891bff 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -1054,10 +1054,8 @@
 	fifo->rx_chan = NULL;
 }
 
-static void usbhsf_dma_init(struct usbhs_priv *priv,
-			    struct usbhs_fifo *fifo)
+static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo)
 {
-	struct device *dev = usbhs_priv_to_dev(priv);
 	dma_cap_mask_t mask;
 
 	dma_cap_zero(mask);
@@ -1069,6 +1067,27 @@
 	dma_cap_set(DMA_SLAVE, mask);
 	fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter,
 					    &fifo->rx_slave);
+}
+
+static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo)
+{
+	fifo->tx_chan = dma_request_slave_channel_reason(dev, "tx");
+	if (IS_ERR(fifo->tx_chan))
+		fifo->tx_chan = NULL;
+	fifo->rx_chan = dma_request_slave_channel_reason(dev, "rx");
+	if (IS_ERR(fifo->rx_chan))
+		fifo->rx_chan = NULL;
+}
+
+static void usbhsf_dma_init(struct usbhs_priv *priv,
+			    struct usbhs_fifo *fifo)
+{
+	struct device *dev = usbhs_priv_to_dev(priv);
+
+	if (dev->of_node)
+		usbhsf_dma_init_dt(dev, fifo);
+	else
+		usbhsf_dma_init_pdev(fifo);
 
 	if (fifo->tx_chan || fifo->rx_chan)
 		dev_dbg(dev, "enable DMAEngine (%s%s%s)\n",
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 8697e6e..e0384af 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -926,6 +926,8 @@
 	else
 		usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
 
+	gadget->is_selfpowered = (is_self != 0);
+
 	return 0;
 }
 
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index f0d3231..96eead6 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -1234,7 +1234,8 @@
 		desc->bNbrPorts			= roothub_id;
 		desc->bDescLength		= 9;
 		desc->bPwrOn2PwrGood		= 0;
-		desc->wHubCharacteristics	= cpu_to_le16(0x0011);
+		desc->wHubCharacteristics	=
+			cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM);
 		desc->u.hs.DeviceRemovable[0]	= (roothub_id << 1);
 		desc->u.hs.DeviceRemovable[1]	= ~0;
 		dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index f4c56fc..f40c856 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -56,6 +56,7 @@
 	{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
 	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
+	{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
 	{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
 	{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 220b4be..e4473a9 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1309,35 +1309,6 @@
 	const unsigned char *current_position = data;
 	unsigned char *data1;
 
-#ifdef NOTMOS7840
-	Data = 0x00;
-	status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
-	mos7840_port->shadowLCR = Data;
-	dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data);
-	dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
-
-	/* Data = 0x03; */
-	/* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */
-	/* mos7840_port->shadowLCR=Data;//Need to add later */
-
-	Data |= SERIAL_LCR_DLAB;	/* data latch enable in LCR 0x80 */
-	status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
-	/* Data = 0x0c; */
-	/* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
-	Data = 0x00;
-	status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
-	dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data);
-
-	Data = 0x0;
-	status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
-	dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data);
-
-	Data = Data & ~SERIAL_LCR_DLAB;
-	dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
-	status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-#endif
-
 	if (mos7840_port_paranoia_check(port, __func__))
 		return -1;
 
@@ -1614,37 +1585,6 @@
 		*clk_sel_val = 0x70;
 	}
 	return 0;
-
-#ifdef NOTMCS7840
-
-	for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
-		if (mos7840_divisor_table[i].BaudRate == baudrate) {
-			*divisor = mos7840_divisor_table[i].Divisor;
-			return 0;
-		}
-	}
-
-	/* After trying for all the standard baud rates    *
-	 * Try calculating the divisor for this baud rate  */
-
-	if (baudrate > 75 && baudrate < 230400) {
-		/* get the divisor */
-		custom = (__u16) (230400L / baudrate);
-
-		/* Check for round off */
-		round1 = (__u16) (2304000L / baudrate);
-		round = (__u16) (round1 - (custom * 10));
-		if (round > 4)
-			custom++;
-		*divisor = custom;
-
-		dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom);
-		return 0;
-	}
-
-	dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n");
-	return -1;
-#endif
 }
 
 /*****************************************************************************
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index efdcee1..f0c0c53 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -507,18 +507,10 @@
 #define VIATELECOM_VENDOR_ID			0x15eb
 #define VIATELECOM_PRODUCT_CDS7			0x0001
 
-/* some devices interfaces need special handling due to a number of reasons */
-enum option_blacklist_reason {
-		OPTION_BLACKLIST_NONE = 0,
-		OPTION_BLACKLIST_SENDSETUP = 1,
-		OPTION_BLACKLIST_RESERVED_IF = 2
-};
-
-#define MAX_BL_NUM  11
 struct option_blacklist_info {
-	/* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
+	/* bitmask of interface numbers blacklisted for send_setup */
 	const unsigned long sendsetup;
-	/* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */
+	/* bitmask of interface numbers that are reserved */
 	const unsigned long reserved;
 };
 
@@ -1822,36 +1814,13 @@
 
 module_usb_serial_driver(serial_drivers, option_ids);
 
-static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
-			   const struct option_blacklist_info *blacklist)
-{
-	unsigned long num;
-	const unsigned long *intf_list;
-
-	if (blacklist) {
-		if (reason == OPTION_BLACKLIST_SENDSETUP)
-			intf_list = &blacklist->sendsetup;
-		else if (reason == OPTION_BLACKLIST_RESERVED_IF)
-			intf_list = &blacklist->reserved;
-		else {
-			BUG_ON(reason);
-			return false;
-		}
-
-		for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) {
-			if (num == ifnum)
-				return true;
-		}
-	}
-	return false;
-}
-
 static int option_probe(struct usb_serial *serial,
 			const struct usb_device_id *id)
 {
 	struct usb_interface_descriptor *iface_desc =
 				&serial->interface->cur_altsetting->desc;
 	struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
+	const struct option_blacklist_info *blacklist;
 
 	/* Never bind to the CD-Rom emulation interface	*/
 	if (iface_desc->bInterfaceClass == 0x08)
@@ -1862,10 +1831,9 @@
 	 * the same class/subclass/protocol as the serial interfaces.  Look at
 	 * the Windows driver .INF files for reserved interface numbers.
 	 */
-	if (is_blacklisted(
-		iface_desc->bInterfaceNumber,
-		OPTION_BLACKLIST_RESERVED_IF,
-		(const struct option_blacklist_info *) id->driver_info))
+	blacklist = (void *)id->driver_info;
+	if (blacklist && test_bit(iface_desc->bInterfaceNumber,
+						&blacklist->reserved))
 		return -ENODEV;
 	/*
 	 * Don't bind network interface on Samsung GT-B3730, it is handled by
@@ -1876,8 +1844,8 @@
 	    iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
 		return -ENODEV;
 
-	/* Store device id so we can use it during attach. */
-	usb_set_serial_data(serial, (void *)id);
+	/* Store the blacklist info so we can use it during attach. */
+	usb_set_serial_data(serial, (void *)blacklist);
 
 	return 0;
 }
@@ -1885,7 +1853,7 @@
 static int option_attach(struct usb_serial *serial)
 {
 	struct usb_interface_descriptor *iface_desc;
-	const struct usb_device_id *id;
+	const struct option_blacklist_info *blacklist;
 	struct usb_wwan_intf_private *data;
 	struct option_private *priv;
 
@@ -1899,16 +1867,16 @@
 		return -ENOMEM;
 	}
 
-	/* Retrieve device id stored at probe. */
-	id = usb_get_serial_data(serial);
+	/* Retrieve blacklist info stored at probe. */
+	blacklist = usb_get_serial_data(serial);
+
 	iface_desc = &serial->interface->cur_altsetting->desc;
 
 	priv->bInterfaceNumber = iface_desc->bInterfaceNumber;
 	data->private = priv;
 
-	if (!is_blacklisted(iface_desc->bInterfaceNumber,
-			OPTION_BLACKLIST_SENDSETUP,
-			(struct option_blacklist_info *)id->driver_info)) {
+	if (!blacklist || !test_bit(iface_desc->bInterfaceNumber,
+						&blacklist->sendsetup)) {
 		data->send_setup = option_send_setup;
 	}
 	spin_lock_init(&data->susp_lock);
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 1ae9d40..11f6f61 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -218,7 +218,8 @@
 	memset(desc, 0, sizeof(*desc));
 	desc->bDescriptorType = 0x29;
 	desc->bDescLength = 9;
-	desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001));
+	desc->wHubCharacteristics = __constant_cpu_to_le16(
+		HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
 	desc->bNbrPorts = VHCI_NPORTS;
 	desc->u.hs.DeviceRemovable[0] = 0xff;
 	desc->u.hs.DeviceRemovable[1] = 0xff;
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
index d5efd0f..7b1b2e2 100644
--- a/drivers/usb/wusbcore/reservation.c
+++ b/drivers/usb/wusbcore/reservation.c
@@ -49,14 +49,13 @@
 	struct wusbhc *wusbhc = rsv->pal_priv;
 	struct device *dev = wusbhc->dev;
 	struct uwb_mas_bm mas;
-	char buf[72];
 
 	dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
 	switch (rsv->state) {
 	case UWB_RSV_STATE_O_ESTABLISHED:
 		uwb_rsv_get_usable_mas(rsv, &mas);
-		bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS);
-		dev_dbg(dev, "established reservation: %s\n", buf);
+		dev_dbg(dev, "established reservation: %*pb\n",
+			UWB_NUM_MAS, mas.bm);
 		wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
 		break;
 	case UWB_RSV_STATE_NONE:
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index fe8bc77..aa5af81 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -185,9 +185,9 @@
 	descr->bDescriptorType = 0x29;	/* HUB type */
 	descr->bNbrPorts = wusbhc->ports_max;
 	descr->wHubCharacteristics = cpu_to_le16(
-		0x00			/* All ports power at once */
+		HUB_CHAR_COMMON_LPSM	/* All ports power at once */
 		| 0x00			/* not part of compound device */
-		| 0x10			/* No overcurrent protection */
+		| HUB_CHAR_NO_OCPM	/* No overcurrent protection */
 		| 0x00			/* 8 FS think time FIXME ?? */
 		| 0x00);		/* No port indicators */
 	descr->bPwrOn2PwrGood = 0;
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index a80c5d2..c7ecdbe 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -496,10 +496,9 @@
 	struct device *dev = &wa->usb_iface->dev;
 
 	if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
-		char buf[256];
 		WARN_ON(1);
-		bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes);
-		dev_err(dev, "BUG: pipes not released on exit: %s\n", buf);
+		dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
+			wa->rpipes, wa->rpipe_bm);
 	}
 	kfree(wa->rpipe_bm);
 }
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index 3e1ba51..94f401a 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -496,11 +496,8 @@
 {
 	clear_bit(0, wusb_cluster_id_table);
 	if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
-		char buf[256];
-		bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table,
-				 CLUSTER_IDS);
-		printk(KERN_ERR "BUG: WUSB Cluster IDs not released "
-		       "on exit: %s\n", buf);
+		printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
+		       CLUSTER_IDS, wusb_cluster_id_table);
 		WARN_ON(1);
 	}
 	usb_unregister_notify(&wusb_usb_notifier);
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
index 05b7bd7..8fc1b78 100644
--- a/drivers/uwb/drp.c
+++ b/drivers/uwb/drp.c
@@ -619,11 +619,9 @@
 	struct device *dev = &rc->uwb_dev.dev;
 	struct uwb_mas_bm mas;
 	struct uwb_cnflt_alien *cnflt;
-	char buf[72];
 	unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
 
 	uwb_drp_ie_to_bm(&mas, drp_ie);
-	bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS);
 
 	list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
 		if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
index 8c7cfab..7203358 100644
--- a/drivers/uwb/lc-dev.c
+++ b/drivers/uwb/lc-dev.c
@@ -43,13 +43,6 @@
 	memset(&addr->data, 0xff, sizeof(addr->data));
 }
 
-/* @returns !0 if a device @addr is a broadcast address */
-static inline int uwb_dev_addr_bcast(const struct uwb_dev_addr *addr)
-{
-	static const struct uwb_dev_addr bcast = { .data = { 0xff, 0xff } };
-	return !uwb_dev_addr_cmp(addr, &bcast);
-}
-
 /*
  * Add callback @new to be called when an event occurs in @rc.
  */
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 6ec45be..0b1e5a9 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -217,7 +217,6 @@
 		struct uwb_dev_addr devaddr;
 		char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
 		bool is_owner;
-		char buf[72];
 
 		uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
 		if (rsv->target.type == UWB_RSV_TARGET_DEV) {
@@ -234,8 +233,7 @@
 			   owner, target, uwb_rsv_state_str(rsv->state));
 		seq_printf(s, "  stream: %d  type: %s\n",
 			   rsv->stream, uwb_rsv_type_str(rsv->type));
-		bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
-		seq_printf(s, "  %s\n", buf);
+		seq_printf(s, "  %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
 	}
 
 	mutex_unlock(&rc->rsvs_mutex);
@@ -259,14 +257,10 @@
 static int drp_avail_print(struct seq_file *s, void *p)
 {
 	struct uwb_rc *rc = s->private;
-	char buf[72];
 
-	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
-	seq_printf(s, "global:  %s\n", buf);
-	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
-	seq_printf(s, "local:   %s\n", buf);
-	bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
-	seq_printf(s, "pending: %s\n", buf);
+	seq_printf(s, "global:  %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
+	seq_printf(s, "local:   %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
+	seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
 
 	return 0;
 }
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c
index 7516030..d95fb84 100644
--- a/drivers/vme/vme.c
+++ b/drivers/vme/vme.c
@@ -502,7 +502,7 @@
 	image = list_entry(resource->entry, struct vme_master_resource, list);
 
 	if (bridge->master_get == NULL) {
-		printk(KERN_WARNING "vme_master_set not supported\n");
+		printk(KERN_WARNING "%s not supported\n", __func__);
 		return -EINVAL;
 	}
 
diff --git a/fs/Kconfig b/fs/Kconfig
index a6bb530..ec35851 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -13,13 +13,6 @@
 source "fs/ext2/Kconfig"
 source "fs/ext3/Kconfig"
 source "fs/ext4/Kconfig"
-
-config FS_XIP
-# execute in place
-	bool
-	depends on EXT2_FS_XIP
-	default y
-
 source "fs/jbd/Kconfig"
 source "fs/jbd2/Kconfig"
 
@@ -40,6 +33,21 @@
 source "fs/btrfs/Kconfig"
 source "fs/nilfs2/Kconfig"
 
+config FS_DAX
+	bool "Direct Access (DAX) support"
+	depends on MMU
+	depends on !(ARM || MIPS || SPARC)
+	help
+	  Direct Access (DAX) can be used on memory-backed block devices.
+	  If the block device supports DAX and the filesystem supports DAX,
+	  then you can avoid using the pagecache to buffer I/Os.  Turning
+	  on this option will compile in support for DAX; you will need to
+	  mount the filesystem using the -o dax option.
+
+	  If you do not have a block device that is capable of using this,
+	  or if unsure, say N.  Saying Y will increase the size of the kernel
+	  by about 5kB.
+
 endif # BLOCK
 
 # Posix ACL utility routines
diff --git a/fs/Makefile b/fs/Makefile
index bedff48..0f4635f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -28,6 +28,7 @@
 obj-$(CONFIG_TIMERFD)		+= timerfd.o
 obj-$(CONFIG_EVENTFD)		+= eventfd.o
 obj-$(CONFIG_AIO)               += aio.o
+obj-$(CONFIG_FS_DAX)		+= dax.o
 obj-$(CONFIG_FILE_LOCKING)      += locks.o
 obj-$(CONFIG_COMPAT)		+= compat.o compat_ioctl.o
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
diff --git a/fs/dax.c b/fs/dax.c
new file mode 100644
index 0000000..ed1619e
--- /dev/null
+++ b/fs/dax.c
@@ -0,0 +1,534 @@
+/*
+ * fs/dax.c - Direct Access filesystem code
+ * Copyright (c) 2013-2014 Intel Corporation
+ * Author: Matthew Wilcox <matthew.r.wilcox@intel.com>
+ * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
+ *
+ * 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/atomic.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/highmem.h>
+#include <linux/memcontrol.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uio.h>
+#include <linux/vmstat.h>
+
+int dax_clear_blocks(struct inode *inode, sector_t block, long size)
+{
+	struct block_device *bdev = inode->i_sb->s_bdev;
+	sector_t sector = block << (inode->i_blkbits - 9);
+
+	might_sleep();
+	do {
+		void *addr;
+		unsigned long pfn;
+		long count;
+
+		count = bdev_direct_access(bdev, sector, &addr, &pfn, size);
+		if (count < 0)
+			return count;
+		BUG_ON(size < count);
+		while (count > 0) {
+			unsigned pgsz = PAGE_SIZE - offset_in_page(addr);
+			if (pgsz > count)
+				pgsz = count;
+			if (pgsz < PAGE_SIZE)
+				memset(addr, 0, pgsz);
+			else
+				clear_page(addr);
+			addr += pgsz;
+			size -= pgsz;
+			count -= pgsz;
+			BUG_ON(pgsz & 511);
+			sector += pgsz / 512;
+			cond_resched();
+		}
+	} while (size);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dax_clear_blocks);
+
+static long dax_get_addr(struct buffer_head *bh, void **addr, unsigned blkbits)
+{
+	unsigned long pfn;
+	sector_t sector = bh->b_blocknr << (blkbits - 9);
+	return bdev_direct_access(bh->b_bdev, sector, addr, &pfn, bh->b_size);
+}
+
+static void dax_new_buf(void *addr, unsigned size, unsigned first, loff_t pos,
+			loff_t end)
+{
+	loff_t final = end - pos + first; /* The final byte of the buffer */
+
+	if (first > 0)
+		memset(addr, 0, first);
+	if (final < size)
+		memset(addr + final, 0, size - final);
+}
+
+static bool buffer_written(struct buffer_head *bh)
+{
+	return buffer_mapped(bh) && !buffer_unwritten(bh);
+}
+
+/*
+ * When ext4 encounters a hole, it returns without modifying the buffer_head
+ * which means that we can't trust b_size.  To cope with this, we set b_state
+ * to 0 before calling get_block and, if any bit is set, we know we can trust
+ * b_size.  Unfortunate, really, since ext4 knows precisely how long a hole is
+ * and would save us time calling get_block repeatedly.
+ */
+static bool buffer_size_valid(struct buffer_head *bh)
+{
+	return bh->b_state != 0;
+}
+
+static ssize_t dax_io(int rw, struct inode *inode, struct iov_iter *iter,
+			loff_t start, loff_t end, get_block_t get_block,
+			struct buffer_head *bh)
+{
+	ssize_t retval = 0;
+	loff_t pos = start;
+	loff_t max = start;
+	loff_t bh_max = start;
+	void *addr;
+	bool hole = false;
+
+	if (rw != WRITE)
+		end = min(end, i_size_read(inode));
+
+	while (pos < end) {
+		unsigned len;
+		if (pos == max) {
+			unsigned blkbits = inode->i_blkbits;
+			sector_t block = pos >> blkbits;
+			unsigned first = pos - (block << blkbits);
+			long size;
+
+			if (pos == bh_max) {
+				bh->b_size = PAGE_ALIGN(end - pos);
+				bh->b_state = 0;
+				retval = get_block(inode, block, bh,
+								rw == WRITE);
+				if (retval)
+					break;
+				if (!buffer_size_valid(bh))
+					bh->b_size = 1 << blkbits;
+				bh_max = pos - first + bh->b_size;
+			} else {
+				unsigned done = bh->b_size -
+						(bh_max - (pos - first));
+				bh->b_blocknr += done >> blkbits;
+				bh->b_size -= done;
+			}
+
+			hole = (rw != WRITE) && !buffer_written(bh);
+			if (hole) {
+				addr = NULL;
+				size = bh->b_size - first;
+			} else {
+				retval = dax_get_addr(bh, &addr, blkbits);
+				if (retval < 0)
+					break;
+				if (buffer_unwritten(bh) || buffer_new(bh))
+					dax_new_buf(addr, retval, first, pos,
+									end);
+				addr += first;
+				size = retval - first;
+			}
+			max = min(pos + size, end);
+		}
+
+		if (rw == WRITE)
+			len = copy_from_iter(addr, max - pos, iter);
+		else if (!hole)
+			len = copy_to_iter(addr, max - pos, iter);
+		else
+			len = iov_iter_zero(max - pos, iter);
+
+		if (!len)
+			break;
+
+		pos += len;
+		addr += len;
+	}
+
+	return (pos == start) ? retval : pos - start;
+}
+
+/**
+ * dax_do_io - Perform I/O to a DAX file
+ * @rw: READ to read or WRITE to write
+ * @iocb: The control block for this I/O
+ * @inode: The file which the I/O is directed at
+ * @iter: The addresses to do I/O from or to
+ * @pos: The file offset where the I/O starts
+ * @get_block: The filesystem method used to translate file offsets to blocks
+ * @end_io: A filesystem callback for I/O completion
+ * @flags: See below
+ *
+ * This function uses the same locking scheme as do_blockdev_direct_IO:
+ * If @flags has DIO_LOCKING set, we assume that the i_mutex is held by the
+ * caller for writes.  For reads, we take and release the i_mutex ourselves.
+ * If DIO_LOCKING is not set, the filesystem takes care of its own locking.
+ * As with do_blockdev_direct_IO(), we increment i_dio_count while the I/O
+ * is in progress.
+ */
+ssize_t dax_do_io(int rw, struct kiocb *iocb, struct inode *inode,
+			struct iov_iter *iter, loff_t pos,
+			get_block_t get_block, dio_iodone_t end_io, int flags)
+{
+	struct buffer_head bh;
+	ssize_t retval = -EINVAL;
+	loff_t end = pos + iov_iter_count(iter);
+
+	memset(&bh, 0, sizeof(bh));
+
+	if ((flags & DIO_LOCKING) && (rw == READ)) {
+		struct address_space *mapping = inode->i_mapping;
+		mutex_lock(&inode->i_mutex);
+		retval = filemap_write_and_wait_range(mapping, pos, end - 1);
+		if (retval) {
+			mutex_unlock(&inode->i_mutex);
+			goto out;
+		}
+	}
+
+	/* Protects against truncate */
+	atomic_inc(&inode->i_dio_count);
+
+	retval = dax_io(rw, inode, iter, pos, end, get_block, &bh);
+
+	if ((flags & DIO_LOCKING) && (rw == READ))
+		mutex_unlock(&inode->i_mutex);
+
+	if ((retval > 0) && end_io)
+		end_io(iocb, pos, retval, bh.b_private);
+
+	inode_dio_done(inode);
+ out:
+	return retval;
+}
+EXPORT_SYMBOL_GPL(dax_do_io);
+
+/*
+ * The user has performed a load from a hole in the file.  Allocating
+ * a new page in the file would cause excessive storage usage for
+ * workloads with sparse files.  We allocate a page cache page instead.
+ * We'll kick it out of the page cache if it's ever written to,
+ * otherwise it will simply fall out of the page cache under memory
+ * pressure without ever having been dirtied.
+ */
+static int dax_load_hole(struct address_space *mapping, struct page *page,
+							struct vm_fault *vmf)
+{
+	unsigned long size;
+	struct inode *inode = mapping->host;
+	if (!page)
+		page = find_or_create_page(mapping, vmf->pgoff,
+						GFP_KERNEL | __GFP_ZERO);
+	if (!page)
+		return VM_FAULT_OOM;
+	/* Recheck i_size under page lock to avoid truncate race */
+	size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (vmf->pgoff >= size) {
+		unlock_page(page);
+		page_cache_release(page);
+		return VM_FAULT_SIGBUS;
+	}
+
+	vmf->page = page;
+	return VM_FAULT_LOCKED;
+}
+
+static int copy_user_bh(struct page *to, struct buffer_head *bh,
+			unsigned blkbits, unsigned long vaddr)
+{
+	void *vfrom, *vto;
+	if (dax_get_addr(bh, &vfrom, blkbits) < 0)
+		return -EIO;
+	vto = kmap_atomic(to);
+	copy_user_page(vto, vfrom, vaddr, to);
+	kunmap_atomic(vto);
+	return 0;
+}
+
+static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
+			struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct address_space *mapping = inode->i_mapping;
+	sector_t sector = bh->b_blocknr << (inode->i_blkbits - 9);
+	unsigned long vaddr = (unsigned long)vmf->virtual_address;
+	void *addr;
+	unsigned long pfn;
+	pgoff_t size;
+	int error;
+
+	i_mmap_lock_read(mapping);
+
+	/*
+	 * Check truncate didn't happen while we were allocating a block.
+	 * If it did, this block may or may not be still allocated to the
+	 * file.  We can't tell the filesystem to free it because we can't
+	 * take i_mutex here.  In the worst case, the file still has blocks
+	 * allocated past the end of the file.
+	 */
+	size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (unlikely(vmf->pgoff >= size)) {
+		error = -EIO;
+		goto out;
+	}
+
+	error = bdev_direct_access(bh->b_bdev, sector, &addr, &pfn, bh->b_size);
+	if (error < 0)
+		goto out;
+	if (error < PAGE_SIZE) {
+		error = -EIO;
+		goto out;
+	}
+
+	if (buffer_unwritten(bh) || buffer_new(bh))
+		clear_page(addr);
+
+	error = vm_insert_mixed(vma, vaddr, pfn);
+
+ out:
+	i_mmap_unlock_read(mapping);
+
+	if (bh->b_end_io)
+		bh->b_end_io(bh, 1);
+
+	return error;
+}
+
+static int do_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
+			get_block_t get_block)
+{
+	struct file *file = vma->vm_file;
+	struct address_space *mapping = file->f_mapping;
+	struct inode *inode = mapping->host;
+	struct page *page;
+	struct buffer_head bh;
+	unsigned long vaddr = (unsigned long)vmf->virtual_address;
+	unsigned blkbits = inode->i_blkbits;
+	sector_t block;
+	pgoff_t size;
+	int error;
+	int major = 0;
+
+	size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (vmf->pgoff >= size)
+		return VM_FAULT_SIGBUS;
+
+	memset(&bh, 0, sizeof(bh));
+	block = (sector_t)vmf->pgoff << (PAGE_SHIFT - blkbits);
+	bh.b_size = PAGE_SIZE;
+
+ repeat:
+	page = find_get_page(mapping, vmf->pgoff);
+	if (page) {
+		if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
+			page_cache_release(page);
+			return VM_FAULT_RETRY;
+		}
+		if (unlikely(page->mapping != mapping)) {
+			unlock_page(page);
+			page_cache_release(page);
+			goto repeat;
+		}
+		size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		if (unlikely(vmf->pgoff >= size)) {
+			/*
+			 * We have a struct page covering a hole in the file
+			 * from a read fault and we've raced with a truncate
+			 */
+			error = -EIO;
+			goto unlock_page;
+		}
+	}
+
+	error = get_block(inode, block, &bh, 0);
+	if (!error && (bh.b_size < PAGE_SIZE))
+		error = -EIO;		/* fs corruption? */
+	if (error)
+		goto unlock_page;
+
+	if (!buffer_mapped(&bh) && !buffer_unwritten(&bh) && !vmf->cow_page) {
+		if (vmf->flags & FAULT_FLAG_WRITE) {
+			error = get_block(inode, block, &bh, 1);
+			count_vm_event(PGMAJFAULT);
+			mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
+			major = VM_FAULT_MAJOR;
+			if (!error && (bh.b_size < PAGE_SIZE))
+				error = -EIO;
+			if (error)
+				goto unlock_page;
+		} else {
+			return dax_load_hole(mapping, page, vmf);
+		}
+	}
+
+	if (vmf->cow_page) {
+		struct page *new_page = vmf->cow_page;
+		if (buffer_written(&bh))
+			error = copy_user_bh(new_page, &bh, blkbits, vaddr);
+		else
+			clear_user_highpage(new_page, vaddr);
+		if (error)
+			goto unlock_page;
+		vmf->page = page;
+		if (!page) {
+			i_mmap_lock_read(mapping);
+			/* Check we didn't race with truncate */
+			size = (i_size_read(inode) + PAGE_SIZE - 1) >>
+								PAGE_SHIFT;
+			if (vmf->pgoff >= size) {
+				i_mmap_unlock_read(mapping);
+				error = -EIO;
+				goto out;
+			}
+		}
+		return VM_FAULT_LOCKED;
+	}
+
+	/* Check we didn't race with a read fault installing a new page */
+	if (!page && major)
+		page = find_lock_page(mapping, vmf->pgoff);
+
+	if (page) {
+		unmap_mapping_range(mapping, vmf->pgoff << PAGE_SHIFT,
+							PAGE_CACHE_SIZE, 0);
+		delete_from_page_cache(page);
+		unlock_page(page);
+		page_cache_release(page);
+	}
+
+	error = dax_insert_mapping(inode, &bh, vma, vmf);
+
+ out:
+	if (error == -ENOMEM)
+		return VM_FAULT_OOM | major;
+	/* -EBUSY is fine, somebody else faulted on the same PTE */
+	if ((error < 0) && (error != -EBUSY))
+		return VM_FAULT_SIGBUS | major;
+	return VM_FAULT_NOPAGE | major;
+
+ unlock_page:
+	if (page) {
+		unlock_page(page);
+		page_cache_release(page);
+	}
+	goto out;
+}
+
+/**
+ * dax_fault - handle a page fault on a DAX file
+ * @vma: The virtual memory area where the fault occurred
+ * @vmf: The description of the fault
+ * @get_block: The filesystem method used to translate file offsets to blocks
+ *
+ * When a page fault occurs, filesystems may call this helper in their
+ * fault handler for DAX files.
+ */
+int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
+			get_block_t get_block)
+{
+	int result;
+	struct super_block *sb = file_inode(vma->vm_file)->i_sb;
+
+	if (vmf->flags & FAULT_FLAG_WRITE) {
+		sb_start_pagefault(sb);
+		file_update_time(vma->vm_file);
+	}
+	result = do_dax_fault(vma, vmf, get_block);
+	if (vmf->flags & FAULT_FLAG_WRITE)
+		sb_end_pagefault(sb);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(dax_fault);
+
+/**
+ * dax_zero_page_range - zero a range within a page of a DAX file
+ * @inode: The file being truncated
+ * @from: The file offset that is being truncated to
+ * @length: The number of bytes to zero
+ * @get_block: The filesystem method used to translate file offsets to blocks
+ *
+ * This function can be called by a filesystem when it is zeroing part of a
+ * page in a DAX file.  This is intended for hole-punch operations.  If
+ * you are truncating a file, the helper function dax_truncate_page() may be
+ * more convenient.
+ *
+ * We work in terms of PAGE_CACHE_SIZE here for commonality with
+ * block_truncate_page(), but we could go down to PAGE_SIZE if the filesystem
+ * took care of disposing of the unnecessary blocks.  Even if the filesystem
+ * block size is smaller than PAGE_SIZE, we have to zero the rest of the page
+ * since the file might be mmapped.
+ */
+int dax_zero_page_range(struct inode *inode, loff_t from, unsigned length,
+							get_block_t get_block)
+{
+	struct buffer_head bh;
+	pgoff_t index = from >> PAGE_CACHE_SHIFT;
+	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	int err;
+
+	/* Block boundary? Nothing to do */
+	if (!length)
+		return 0;
+	BUG_ON((offset + length) > PAGE_CACHE_SIZE);
+
+	memset(&bh, 0, sizeof(bh));
+	bh.b_size = PAGE_CACHE_SIZE;
+	err = get_block(inode, index, &bh, 0);
+	if (err < 0)
+		return err;
+	if (buffer_written(&bh)) {
+		void *addr;
+		err = dax_get_addr(&bh, &addr, inode->i_blkbits);
+		if (err < 0)
+			return err;
+		memset(addr + offset, 0, length);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dax_zero_page_range);
+
+/**
+ * dax_truncate_page - handle a partial page being truncated in a DAX file
+ * @inode: The file being truncated
+ * @from: The file offset that is being truncated to
+ * @get_block: The filesystem method used to translate file offsets to blocks
+ *
+ * Similar to block_truncate_page(), this function can be called by a
+ * filesystem when it is truncating a DAX file to handle the partial page.
+ *
+ * We work in terms of PAGE_CACHE_SIZE here for commonality with
+ * block_truncate_page(), but we could go down to PAGE_SIZE if the filesystem
+ * took care of disposing of the unnecessary blocks.  Even if the filesystem
+ * block size is smaller than PAGE_SIZE, we have to zero the rest of the page
+ * since the file might be mmapped.
+ */
+int dax_truncate_page(struct inode *inode, loff_t from, get_block_t get_block)
+{
+	unsigned length = PAGE_CACHE_ALIGN(from) - from;
+	return dax_zero_page_range(inode, from, length, get_block);
+}
+EXPORT_SYMBOL_GPL(dax_truncate_page);
diff --git a/fs/dcache.c b/fs/dcache.c
index d04be76..7d34f04 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -38,6 +38,8 @@
 #include <linux/prefetch.h>
 #include <linux/ratelimit.h>
 #include <linux/list_lru.h>
+#include <linux/kasan.h>
+
 #include "internal.h"
 #include "mount.h"
 
@@ -1429,6 +1431,9 @@
 		}
 		atomic_set(&p->u.count, 1);
 		dname = p->name;
+		if (IS_ENABLED(CONFIG_DCACHE_WORD_ACCESS))
+			kasan_unpoison_shadow(dname,
+				round_up(name->len + 1,	sizeof(unsigned long)));
 	} else  {
 		dname = dentry->d_iname;
 	}	
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index d77f944..1e009ca 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1639,9 +1639,9 @@
 
 			spin_lock_irqsave(&ep->lock, flags);
 		}
-		__remove_wait_queue(&ep->wq, &wait);
 
-		set_current_state(TASK_RUNNING);
+		__remove_wait_queue(&ep->wq, &wait);
+		__set_current_state(TASK_RUNNING);
 	}
 check_events:
 	/* Is it worth to try to dig for events ? */
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 6fc91df..a198e94 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -985,7 +985,6 @@
 	.direct_IO	= exofs_direct_IO,
 
 	/* With these NULL has special meaning or default is not exported */
-	.get_xip_mem	= NULL,
 	.migratepage	= NULL,
 	.launder_page	= NULL,
 	.is_partially_uptodate = NULL,
diff --git a/fs/ext2/Kconfig b/fs/ext2/Kconfig
index 14a6780..c634874e 100644
--- a/fs/ext2/Kconfig
+++ b/fs/ext2/Kconfig
@@ -42,14 +42,3 @@
 
 	  If you are not using a security module that requires using
 	  extended attributes for file security labels, say N.
-
-config EXT2_FS_XIP
-	bool "Ext2 execute in place support"
-	depends on EXT2_FS && MMU
-	help
-	  Execute in place can be used on memory-backed block devices. If you
-	  enable this option, you can select to mount block devices which are
-	  capable of this feature without using the page cache.
-
-	  If you do not use a block device that is capable of using this,
-	  or if unsure, say N.
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index f42af45..445b0e9 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -10,4 +10,3 @@
 ext2-$(CONFIG_EXT2_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
 ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
 ext2-$(CONFIG_EXT2_FS_SECURITY)	 += xattr_security.o
-ext2-$(CONFIG_EXT2_FS_XIP)	 += xip.o
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index e4279ea..678f9ab 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -380,10 +380,15 @@
 #define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */
 #define EXT2_MOUNT_XATTR_USER		0x004000  /* Extended user attributes */
 #define EXT2_MOUNT_POSIX_ACL		0x008000  /* POSIX Access Control Lists */
-#define EXT2_MOUNT_XIP			0x010000  /* Execute in place */
+#define EXT2_MOUNT_XIP			0x010000  /* Obsolete, use DAX */
 #define EXT2_MOUNT_USRQUOTA		0x020000  /* user quota */
 #define EXT2_MOUNT_GRPQUOTA		0x040000  /* group quota */
 #define EXT2_MOUNT_RESERVATION		0x080000  /* Preallocation */
+#ifdef CONFIG_FS_DAX
+#define EXT2_MOUNT_DAX			0x100000  /* Direct Access */
+#else
+#define EXT2_MOUNT_DAX			0
+#endif
 
 
 #define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
@@ -788,11 +793,10 @@
 		      int datasync);
 extern const struct inode_operations ext2_file_inode_operations;
 extern const struct file_operations ext2_file_operations;
-extern const struct file_operations ext2_xip_file_operations;
+extern const struct file_operations ext2_dax_file_operations;
 
 /* inode.c */
 extern const struct address_space_operations ext2_aops;
-extern const struct address_space_operations ext2_aops_xip;
 extern const struct address_space_operations ext2_nobh_aops;
 
 /* namei.c */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 7c87b22..e317017 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -25,6 +25,36 @@
 #include "xattr.h"
 #include "acl.h"
 
+#ifdef CONFIG_FS_DAX
+static int ext2_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	return dax_fault(vma, vmf, ext2_get_block);
+}
+
+static int ext2_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	return dax_mkwrite(vma, vmf, ext2_get_block);
+}
+
+static const struct vm_operations_struct ext2_dax_vm_ops = {
+	.fault		= ext2_dax_fault,
+	.page_mkwrite	= ext2_dax_mkwrite,
+};
+
+static int ext2_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!IS_DAX(file_inode(file)))
+		return generic_file_mmap(file, vma);
+
+	file_accessed(file);
+	vma->vm_ops = &ext2_dax_vm_ops;
+	vma->vm_flags |= VM_MIXEDMAP;
+	return 0;
+}
+#else
+#define ext2_file_mmap	generic_file_mmap
+#endif
+
 /*
  * Called when filp is released. This happens when all file descriptors
  * for a single struct file are closed. Note that different open() calls
@@ -70,7 +100,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= ext2_compat_ioctl,
 #endif
-	.mmap		= generic_file_mmap,
+	.mmap		= ext2_file_mmap,
 	.open		= dquot_file_open,
 	.release	= ext2_release_file,
 	.fsync		= ext2_fsync,
@@ -78,16 +108,18 @@
 	.splice_write	= iter_file_splice_write,
 };
 
-#ifdef CONFIG_EXT2_FS_XIP
-const struct file_operations ext2_xip_file_operations = {
+#ifdef CONFIG_FS_DAX
+const struct file_operations ext2_dax_file_operations = {
 	.llseek		= generic_file_llseek,
-	.read		= xip_file_read,
-	.write		= xip_file_write,
+	.read		= new_sync_read,
+	.write		= new_sync_write,
+	.read_iter	= generic_file_read_iter,
+	.write_iter	= generic_file_write_iter,
 	.unlocked_ioctl = ext2_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= ext2_compat_ioctl,
 #endif
-	.mmap		= xip_file_mmap,
+	.mmap		= ext2_file_mmap,
 	.open		= dquot_file_open,
 	.release	= ext2_release_file,
 	.fsync		= ext2_fsync,
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 36d35c3..6434bc0 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -34,7 +34,6 @@
 #include <linux/aio.h>
 #include "ext2.h"
 #include "acl.h"
-#include "xip.h"
 #include "xattr.h"
 
 static int __ext2_write_inode(struct inode *inode, int do_sync);
@@ -731,12 +730,14 @@
 		goto cleanup;
 	}
 
-	if (ext2_use_xip(inode->i_sb)) {
+	if (IS_DAX(inode)) {
 		/*
-		 * we need to clear the block
+		 * block must be initialised before we put it in the tree
+		 * so that it's not found by another thread before it's
+		 * initialised
 		 */
-		err = ext2_clear_xip_target (inode,
-			le32_to_cpu(chain[depth-1].key));
+		err = dax_clear_blocks(inode, le32_to_cpu(chain[depth-1].key),
+						1 << inode->i_blkbits);
 		if (err) {
 			mutex_unlock(&ei->truncate_mutex);
 			goto cleanup;
@@ -859,7 +860,12 @@
 	size_t count = iov_iter_count(iter);
 	ssize_t ret;
 
-	ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, ext2_get_block);
+	if (IS_DAX(inode))
+		ret = dax_do_io(rw, iocb, inode, iter, offset, ext2_get_block,
+				NULL, DIO_LOCKING);
+	else
+		ret = blockdev_direct_IO(rw, iocb, inode, iter, offset,
+					 ext2_get_block);
 	if (ret < 0 && (rw & WRITE))
 		ext2_write_failed(mapping, offset + count);
 	return ret;
@@ -885,11 +891,6 @@
 	.error_remove_page	= generic_error_remove_page,
 };
 
-const struct address_space_operations ext2_aops_xip = {
-	.bmap			= ext2_bmap,
-	.get_xip_mem		= ext2_get_xip_mem,
-};
-
 const struct address_space_operations ext2_nobh_aops = {
 	.readpage		= ext2_readpage,
 	.readpages		= ext2_readpages,
@@ -1201,8 +1202,8 @@
 
 	inode_dio_wait(inode);
 
-	if (mapping_is_xip(inode->i_mapping))
-		error = xip_truncate_page(inode->i_mapping, newsize);
+	if (IS_DAX(inode))
+		error = dax_truncate_page(inode, newsize, ext2_get_block);
 	else if (test_opt(inode->i_sb, NOBH))
 		error = nobh_truncate_page(inode->i_mapping,
 				newsize, ext2_get_block);
@@ -1273,7 +1274,8 @@
 {
 	unsigned int flags = EXT2_I(inode)->i_flags;
 
-	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+	inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME |
+				S_DIRSYNC | S_DAX);
 	if (flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	if (flags & EXT2_APPEND_FL)
@@ -1284,6 +1286,8 @@
 		inode->i_flags |= S_NOATIME;
 	if (flags & EXT2_DIRSYNC_FL)
 		inode->i_flags |= S_DIRSYNC;
+	if (test_opt(inode->i_sb, DAX))
+		inode->i_flags |= S_DAX;
 }
 
 /* Propagate flags from i_flags to EXT2_I(inode)->i_flags */
@@ -1384,9 +1388,9 @@
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext2_file_inode_operations;
-		if (ext2_use_xip(inode->i_sb)) {
-			inode->i_mapping->a_ops = &ext2_aops_xip;
-			inode->i_fop = &ext2_xip_file_operations;
+		if (test_opt(inode->i_sb, DAX)) {
+			inode->i_mapping->a_ops = &ext2_aops;
+			inode->i_fop = &ext2_dax_file_operations;
 		} else if (test_opt(inode->i_sb, NOBH)) {
 			inode->i_mapping->a_ops = &ext2_nobh_aops;
 			inode->i_fop = &ext2_file_operations;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index c268d0a..148f6e3 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -35,7 +35,6 @@
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
-#include "xip.h"
 
 static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
 {
@@ -105,9 +104,9 @@
 		return PTR_ERR(inode);
 
 	inode->i_op = &ext2_file_inode_operations;
-	if (ext2_use_xip(inode->i_sb)) {
-		inode->i_mapping->a_ops = &ext2_aops_xip;
-		inode->i_fop = &ext2_xip_file_operations;
+	if (test_opt(inode->i_sb, DAX)) {
+		inode->i_mapping->a_ops = &ext2_aops;
+		inode->i_fop = &ext2_dax_file_operations;
 	} else if (test_opt(inode->i_sb, NOBH)) {
 		inode->i_mapping->a_ops = &ext2_nobh_aops;
 		inode->i_fop = &ext2_file_operations;
@@ -126,9 +125,9 @@
 		return PTR_ERR(inode);
 
 	inode->i_op = &ext2_file_inode_operations;
-	if (ext2_use_xip(inode->i_sb)) {
-		inode->i_mapping->a_ops = &ext2_aops_xip;
-		inode->i_fop = &ext2_xip_file_operations;
+	if (test_opt(inode->i_sb, DAX)) {
+		inode->i_mapping->a_ops = &ext2_aops;
+		inode->i_fop = &ext2_dax_file_operations;
 	} else if (test_opt(inode->i_sb, NOBH)) {
 		inode->i_mapping->a_ops = &ext2_nobh_aops;
 		inode->i_fop = &ext2_file_operations;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index ae55fdd..d0e746e 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -35,7 +35,6 @@
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
-#include "xip.h"
 
 static void ext2_sync_super(struct super_block *sb,
 			    struct ext2_super_block *es, int wait);
@@ -292,9 +291,11 @@
 		seq_puts(seq, ",grpquota");
 #endif
 
-#if defined(CONFIG_EXT2_FS_XIP)
+#ifdef CONFIG_FS_DAX
 	if (sbi->s_mount_opt & EXT2_MOUNT_XIP)
 		seq_puts(seq, ",xip");
+	if (sbi->s_mount_opt & EXT2_MOUNT_DAX)
+		seq_puts(seq, ",dax");
 #endif
 
 	if (!test_opt(sb, RESERVATION))
@@ -403,7 +404,7 @@
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
 	Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
 	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
-	Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
+	Opt_acl, Opt_noacl, Opt_xip, Opt_dax, Opt_ignore, Opt_err, Opt_quota,
 	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
 };
 
@@ -432,6 +433,7 @@
 	{Opt_acl, "acl"},
 	{Opt_noacl, "noacl"},
 	{Opt_xip, "xip"},
+	{Opt_dax, "dax"},
 	{Opt_grpquota, "grpquota"},
 	{Opt_ignore, "noquota"},
 	{Opt_quota, "quota"},
@@ -559,10 +561,14 @@
 			break;
 #endif
 		case Opt_xip:
-#ifdef CONFIG_EXT2_FS_XIP
-			set_opt (sbi->s_mount_opt, XIP);
+			ext2_msg(sb, KERN_INFO, "use dax instead of xip");
+			set_opt(sbi->s_mount_opt, XIP);
+			/* Fall through */
+		case Opt_dax:
+#ifdef CONFIG_FS_DAX
+			set_opt(sbi->s_mount_opt, DAX);
 #else
-			ext2_msg(sb, KERN_INFO, "xip option not supported");
+			ext2_msg(sb, KERN_INFO, "dax option not supported");
 #endif
 			break;
 
@@ -877,9 +883,6 @@
 		((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
 		 MS_POSIXACL : 0);
 
-	ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
-				    EXT2_MOUNT_XIP if not */
-
 	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
 	    (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
 	     EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
@@ -909,11 +912,17 @@
 
 	blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
 
-	if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
-		if (!silent)
+	if (sbi->s_mount_opt & EXT2_MOUNT_DAX) {
+		if (blocksize != PAGE_SIZE) {
 			ext2_msg(sb, KERN_ERR,
-				"error: unsupported blocksize for xip");
-		goto failed_mount;
+					"error: unsupported blocksize for dax");
+			goto failed_mount;
+		}
+		if (!sb->s_bdev->bd_disk->fops->direct_access) {
+			ext2_msg(sb, KERN_ERR,
+					"error: device does not support dax");
+			goto failed_mount;
+		}
 	}
 
 	/* If the blocksize doesn't match, re-read the thing.. */
@@ -1259,7 +1268,6 @@
 {
 	struct ext2_sb_info * sbi = EXT2_SB(sb);
 	struct ext2_super_block * es;
-	unsigned long old_mount_opt = sbi->s_mount_opt;
 	struct ext2_mount_options old_opts;
 	unsigned long old_sb_flags;
 	int err;
@@ -1284,22 +1292,11 @@
 	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
 		((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
 
-	ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
-				    EXT2_MOUNT_XIP if not */
-
-	if ((ext2_use_xip(sb)) && (sb->s_blocksize != PAGE_SIZE)) {
-		ext2_msg(sb, KERN_WARNING,
-			"warning: unsupported blocksize for xip");
-		err = -EINVAL;
-		goto restore_opts;
-	}
-
 	es = sbi->s_es;
-	if ((sbi->s_mount_opt ^ old_mount_opt) & EXT2_MOUNT_XIP) {
+	if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT2_MOUNT_DAX) {
 		ext2_msg(sb, KERN_WARNING, "warning: refusing change of "
-			 "xip flag with busy inodes while remounting");
-		sbi->s_mount_opt &= ~EXT2_MOUNT_XIP;
-		sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP;
+			 "dax flag with busy inodes while remounting");
+		sbi->s_mount_opt ^= EXT2_MOUNT_DAX;
 	}
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {
 		spin_unlock(&sbi->s_lock);
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
deleted file mode 100644
index bbc5fec..0000000
--- a/fs/ext2/xip.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *  linux/fs/ext2/xip.c
- *
- * Copyright (C) 2005 IBM Corporation
- * Author: Carsten Otte (cotte@de.ibm.com)
- */
-
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/buffer_head.h>
-#include <linux/blkdev.h>
-#include "ext2.h"
-#include "xip.h"
-
-static inline long __inode_direct_access(struct inode *inode, sector_t block,
-				void **kaddr, unsigned long *pfn, long size)
-{
-	struct block_device *bdev = inode->i_sb->s_bdev;
-	sector_t sector = block * (PAGE_SIZE / 512);
-	return bdev_direct_access(bdev, sector, kaddr, pfn, size);
-}
-
-static inline int
-__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
-		   sector_t *result)
-{
-	struct buffer_head tmp;
-	int rc;
-
-	memset(&tmp, 0, sizeof(struct buffer_head));
-	tmp.b_size = 1 << inode->i_blkbits;
-	rc = ext2_get_block(inode, pgoff, &tmp, create);
-	*result = tmp.b_blocknr;
-
-	/* did we get a sparse block (hole in the file)? */
-	if (!tmp.b_blocknr && !rc) {
-		BUG_ON(create);
-		rc = -ENODATA;
-	}
-
-	return rc;
-}
-
-int
-ext2_clear_xip_target(struct inode *inode, sector_t block)
-{
-	void *kaddr;
-	unsigned long pfn;
-	long size;
-
-	size = __inode_direct_access(inode, block, &kaddr, &pfn, PAGE_SIZE);
-	if (size < 0)
-		return size;
-	clear_page(kaddr);
-	return 0;
-}
-
-void ext2_xip_verify_sb(struct super_block *sb)
-{
-	struct ext2_sb_info *sbi = EXT2_SB(sb);
-
-	if ((sbi->s_mount_opt & EXT2_MOUNT_XIP) &&
-	    !sb->s_bdev->bd_disk->fops->direct_access) {
-		sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
-		ext2_msg(sb, KERN_WARNING,
-			     "warning: ignoring xip option - "
-			     "not supported by bdev");
-	}
-}
-
-int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create,
-				void **kmem, unsigned long *pfn)
-{
-	long rc;
-	sector_t block;
-
-	/* first, retrieve the sector number */
-	rc = __ext2_get_block(mapping->host, pgoff, create, &block);
-	if (rc)
-		return rc;
-
-	/* retrieve address of the target data */
-	rc = __inode_direct_access(mapping->host, block, kmem, pfn, PAGE_SIZE);
-	return (rc < 0) ? rc : 0;
-}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
deleted file mode 100644
index 18b34d2..0000000
--- a/fs/ext2/xip.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/fs/ext2/xip.h
- *
- * Copyright (C) 2005 IBM Corporation
- * Author: Carsten Otte (cotte@de.ibm.com)
- */
-
-#ifdef CONFIG_EXT2_FS_XIP
-extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, sector_t);
-
-static inline int ext2_use_xip (struct super_block *sb)
-{
-	struct ext2_sb_info *sbi = EXT2_SB(sb);
-	return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
-}
-int ext2_get_xip_mem(struct address_space *, pgoff_t, int,
-				void **, unsigned long *);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_mem)
-#else
-#define mapping_is_xip(map)			0
-#define ext2_xip_verify_sb(sb)			do { } while (0)
-#define ext2_use_xip(sb)			0
-#define ext2_clear_xip_target(inode, chain)	0
-#define ext2_get_xip_mem			NULL
-#endif
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index a75fba6..982d934 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -965,6 +965,11 @@
 #define EXT4_MOUNT_ERRORS_MASK		0x00070
 #define EXT4_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
 #define EXT4_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
+#ifdef CONFIG_FS_DAX
+#define EXT4_MOUNT_DAX			0x00200	/* Direct Access */
+#else
+#define EXT4_MOUNT_DAX			0
+#endif
 #define EXT4_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
 #define EXT4_MOUNT_JOURNAL_DATA		0x00400	/* Write data to journal */
 #define EXT4_MOUNT_ORDERED_DATA		0x00800	/* Flush data before commit */
@@ -2578,6 +2583,7 @@
 /* file.c */
 extern const struct inode_operations ext4_file_inode_operations;
 extern const struct file_operations ext4_file_operations;
+extern const struct file_operations ext4_dax_file_operations;
 extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
 
 /* inline.c */
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 7cb5923..33a09da 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -95,7 +95,7 @@
 	struct inode *inode = file_inode(iocb->ki_filp);
 	struct mutex *aio_mutex = NULL;
 	struct blk_plug plug;
-	int o_direct = file->f_flags & O_DIRECT;
+	int o_direct = io_is_direct(file);
 	int overwrite = 0;
 	size_t length = iov_iter_count(from);
 	ssize_t ret;
@@ -191,6 +191,26 @@
 	return ret;
 }
 
+#ifdef CONFIG_FS_DAX
+static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	return dax_fault(vma, vmf, ext4_get_block);
+					/* Is this the right get_block? */
+}
+
+static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	return dax_mkwrite(vma, vmf, ext4_get_block);
+}
+
+static const struct vm_operations_struct ext4_dax_vm_ops = {
+	.fault		= ext4_dax_fault,
+	.page_mkwrite	= ext4_dax_mkwrite,
+};
+#else
+#define ext4_dax_vm_ops	ext4_file_vm_ops
+#endif
+
 static const struct vm_operations_struct ext4_file_vm_ops = {
 	.fault		= filemap_fault,
 	.map_pages	= filemap_map_pages,
@@ -200,7 +220,12 @@
 static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	file_accessed(file);
-	vma->vm_ops = &ext4_file_vm_ops;
+	if (IS_DAX(file_inode(file))) {
+		vma->vm_ops = &ext4_dax_vm_ops;
+		vma->vm_flags |= VM_MIXEDMAP;
+	} else {
+		vma->vm_ops = &ext4_file_vm_ops;
+	}
 	return 0;
 }
 
@@ -599,6 +624,26 @@
 	.fallocate	= ext4_fallocate,
 };
 
+#ifdef CONFIG_FS_DAX
+const struct file_operations ext4_dax_file_operations = {
+	.llseek		= ext4_llseek,
+	.read		= new_sync_read,
+	.write		= new_sync_write,
+	.read_iter	= generic_file_read_iter,
+	.write_iter	= ext4_file_write_iter,
+	.unlocked_ioctl = ext4_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ext4_compat_ioctl,
+#endif
+	.mmap		= ext4_file_mmap,
+	.open		= ext4_file_open,
+	.release	= ext4_release_file,
+	.fsync		= ext4_sync_file,
+	/* Splice not yet supported with DAX */
+	.fallocate	= ext4_fallocate,
+};
+#endif
+
 const struct inode_operations ext4_file_inode_operations = {
 	.setattr	= ext4_setattr,
 	.getattr	= ext4_getattr,
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index 36b3696..6b9878a 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -689,14 +689,22 @@
 			inode_dio_done(inode);
 			goto locked;
 		}
-		ret = __blockdev_direct_IO(rw, iocb, inode,
-				 inode->i_sb->s_bdev, iter, offset,
-				 ext4_get_block, NULL, NULL, 0);
+		if (IS_DAX(inode))
+			ret = dax_do_io(rw, iocb, inode, iter, offset,
+					ext4_get_block, NULL, 0);
+		else
+			ret = __blockdev_direct_IO(rw, iocb, inode,
+					inode->i_sb->s_bdev, iter, offset,
+					ext4_get_block, NULL, NULL, 0);
 		inode_dio_done(inode);
 	} else {
 locked:
-		ret = blockdev_direct_IO(rw, iocb, inode, iter,
-				 offset, ext4_get_block);
+		if (IS_DAX(inode))
+			ret = dax_do_io(rw, iocb, inode, iter, offset,
+					ext4_get_block, NULL, DIO_LOCKING);
+		else
+			ret = blockdev_direct_IO(rw, iocb, inode, iter,
+					offset, ext4_get_block);
 
 		if (unlikely((rw & WRITE) && ret < 0)) {
 			loff_t isize = i_size_read(inode);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 5653fa4..28555f1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -657,6 +657,18 @@
 	return retval;
 }
 
+static void ext4_end_io_unwritten(struct buffer_head *bh, int uptodate)
+{
+	struct inode *inode = bh->b_assoc_map->host;
+	/* XXX: breaks on 32-bit > 16GB. Is that even supported? */
+	loff_t offset = (loff_t)(uintptr_t)bh->b_private << inode->i_blkbits;
+	int err;
+	if (!uptodate)
+		return;
+	WARN_ON(!buffer_unwritten(bh));
+	err = ext4_convert_unwritten_extents(NULL, inode, offset, bh->b_size);
+}
+
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
@@ -694,6 +706,11 @@
 
 		map_bh(bh, inode->i_sb, map.m_pblk);
 		bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+		if (IS_DAX(inode) && buffer_unwritten(bh) && !io_end) {
+			bh->b_assoc_map = inode->i_mapping;
+			bh->b_private = (void *)(unsigned long)iblock;
+			bh->b_end_io = ext4_end_io_unwritten;
+		}
 		if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN)
 			set_buffer_defer_completion(bh);
 		bh->b_size = inode->i_sb->s_blocksize * map.m_len;
@@ -3010,13 +3027,14 @@
 		get_block_func = ext4_get_block_write;
 		dio_flags = DIO_LOCKING;
 	}
-	ret = __blockdev_direct_IO(rw, iocb, inode,
-				   inode->i_sb->s_bdev, iter,
-				   offset,
-				   get_block_func,
-				   ext4_end_io_dio,
-				   NULL,
-				   dio_flags);
+	if (IS_DAX(inode))
+		ret = dax_do_io(rw, iocb, inode, iter, offset, get_block_func,
+				ext4_end_io_dio, dio_flags);
+	else
+		ret = __blockdev_direct_IO(rw, iocb, inode,
+					   inode->i_sb->s_bdev, iter, offset,
+					   get_block_func,
+					   ext4_end_io_dio, NULL, dio_flags);
 
 	/*
 	 * Put our reference to io_end. This can free the io_end structure e.g.
@@ -3180,19 +3198,12 @@
 		inode->i_mapping->a_ops = &ext4_aops;
 }
 
-/*
- * ext4_block_zero_page_range() zeros out a mapping of length 'length'
- * starting from file offset 'from'.  The range to be zero'd must
- * be contained with in one block.  If the specified range exceeds
- * the end of the block it will be shortened to end of the block
- * that cooresponds to 'from'
- */
-static int ext4_block_zero_page_range(handle_t *handle,
+static int __ext4_block_zero_page_range(handle_t *handle,
 		struct address_space *mapping, loff_t from, loff_t length)
 {
 	ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
-	unsigned blocksize, max, pos;
+	unsigned blocksize, pos;
 	ext4_lblk_t iblock;
 	struct inode *inode = mapping->host;
 	struct buffer_head *bh;
@@ -3205,14 +3216,6 @@
 		return -ENOMEM;
 
 	blocksize = inode->i_sb->s_blocksize;
-	max = blocksize - (offset & (blocksize - 1));
-
-	/*
-	 * correct length if it does not fall between
-	 * 'from' and the end of the block
-	 */
-	if (length > max || length < 0)
-		length = max;
 
 	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 
@@ -3278,6 +3281,33 @@
 }
 
 /*
+ * ext4_block_zero_page_range() zeros out a mapping of length 'length'
+ * starting from file offset 'from'.  The range to be zero'd must
+ * be contained with in one block.  If the specified range exceeds
+ * the end of the block it will be shortened to end of the block
+ * that cooresponds to 'from'
+ */
+static int ext4_block_zero_page_range(handle_t *handle,
+		struct address_space *mapping, loff_t from, loff_t length)
+{
+	struct inode *inode = mapping->host;
+	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	unsigned blocksize = inode->i_sb->s_blocksize;
+	unsigned max = blocksize - (offset & (blocksize - 1));
+
+	/*
+	 * correct length if it does not fall between
+	 * 'from' and the end of the block
+	 */
+	if (length > max || length < 0)
+		length = max;
+
+	if (IS_DAX(inode))
+		return dax_zero_page_range(inode, from, length, ext4_get_block);
+	return __ext4_block_zero_page_range(handle, mapping, from, length);
+}
+
+/*
  * ext4_block_truncate_page() zeroes out a mapping from file offset `from'
  * up to the end of the block which corresponds to `from'.
  * This required during truncate. We need to physically zero the tail end
@@ -3798,8 +3828,10 @@
 		new_fl |= S_NOATIME;
 	if (flags & EXT4_DIRSYNC_FL)
 		new_fl |= S_DIRSYNC;
+	if (test_opt(inode->i_sb, DAX))
+		new_fl |= S_DAX;
 	inode_set_flags(inode, new_fl,
-			S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+			S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX);
 }
 
 /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
@@ -4052,7 +4084,10 @@
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext4_file_inode_operations;
-		inode->i_fop = &ext4_file_operations;
+		if (test_opt(inode->i_sb, DAX))
+			inode->i_fop = &ext4_dax_file_operations;
+		else
+			inode->i_fop = &ext4_file_operations;
 		ext4_set_aops(inode);
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &ext4_dir_inode_operations;
@@ -4534,7 +4569,7 @@
 		 * Truncate pagecache after we've waited for commit
 		 * in data=journal mode to make pages freeable.
 		 */
-			truncate_pagecache(inode, inode->i_size);
+		truncate_pagecache(inode, inode->i_size);
 	}
 	/*
 	 * We want to call ext4_truncate() even if attr->ia_size ==
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2291923..28fe71a 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2235,7 +2235,10 @@
 	err = PTR_ERR(inode);
 	if (!IS_ERR(inode)) {
 		inode->i_op = &ext4_file_inode_operations;
-		inode->i_fop = &ext4_file_operations;
+		if (test_opt(inode->i_sb, DAX))
+			inode->i_fop = &ext4_dax_file_operations;
+		else
+			inode->i_fop = &ext4_file_operations;
 		ext4_set_aops(inode);
 		err = ext4_add_nondir(handle, dentry, inode);
 		if (!err && IS_DIRSYNC(dir))
@@ -2299,7 +2302,10 @@
 	err = PTR_ERR(inode);
 	if (!IS_ERR(inode)) {
 		inode->i_op = &ext4_file_inode_operations;
-		inode->i_fop = &ext4_file_operations;
+		if (test_opt(inode->i_sb, DAX))
+			inode->i_fop = &ext4_dax_file_operations;
+		else
+			inode->i_fop = &ext4_file_operations;
 		ext4_set_aops(inode);
 		d_tmpfile(dentry, inode);
 		err = ext4_orphan_add(handle, inode);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 64c39c7..10e8c6b 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1124,7 +1124,7 @@
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
 	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
-	Opt_usrquota, Opt_grpquota, Opt_i_version,
+	Opt_usrquota, Opt_grpquota, Opt_i_version, Opt_dax,
 	Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
 	Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
 	Opt_inode_readahead_blks, Opt_journal_ioprio,
@@ -1187,6 +1187,7 @@
 	{Opt_barrier, "barrier"},
 	{Opt_nobarrier, "nobarrier"},
 	{Opt_i_version, "i_version"},
+	{Opt_dax, "dax"},
 	{Opt_stripe, "stripe=%u"},
 	{Opt_delalloc, "delalloc"},
 	{Opt_nodelalloc, "nodelalloc"},
@@ -1371,6 +1372,7 @@
 	{Opt_min_batch_time, 0, MOPT_GTE0},
 	{Opt_inode_readahead_blks, 0, MOPT_GTE0},
 	{Opt_init_itable, 0, MOPT_GTE0},
+	{Opt_dax, EXT4_MOUNT_DAX, MOPT_SET},
 	{Opt_stripe, 0, MOPT_GTE0},
 	{Opt_resuid, 0, MOPT_GTE0},
 	{Opt_resgid, 0, MOPT_GTE0},
@@ -1607,6 +1609,11 @@
 		}
 		sbi->s_jquota_fmt = m->mount_opt;
 #endif
+#ifndef CONFIG_FS_DAX
+	} else if (token == Opt_dax) {
+		ext4_msg(sb, KERN_INFO, "dax option not supported");
+		return -1;
+#endif
 	} else {
 		if (!args->from)
 			arg = 1;
@@ -3589,6 +3596,11 @@
 				 "both data=journal and dioread_nolock");
 			goto failed_mount;
 		}
+		if (test_opt(sb, DAX)) {
+			ext4_msg(sb, KERN_ERR, "can't mount with "
+				 "both data=journal and dax");
+			goto failed_mount;
+		}
 		if (test_opt(sb, DELALLOC))
 			clear_opt(sb, DELALLOC);
 	}
@@ -3652,6 +3664,19 @@
 		goto failed_mount;
 	}
 
+	if (sbi->s_mount_opt & EXT4_MOUNT_DAX) {
+		if (blocksize != PAGE_SIZE) {
+			ext4_msg(sb, KERN_ERR,
+					"error: unsupported blocksize for dax");
+			goto failed_mount;
+		}
+		if (!sb->s_bdev->bd_disk->fops->direct_access) {
+			ext4_msg(sb, KERN_ERR,
+					"error: device does not support dax");
+			goto failed_mount;
+		}
+	}
+
 	if (sb->s_blocksize != blocksize) {
 		/* Validate the filesystem blocksize */
 		if (!sb_set_blocksize(sb, blocksize)) {
@@ -4869,6 +4894,18 @@
 			err = -EINVAL;
 			goto restore_opts;
 		}
+		if (test_opt(sb, DAX)) {
+			ext4_msg(sb, KERN_ERR, "can't mount with "
+				 "both data=journal and dax");
+			err = -EINVAL;
+			goto restore_opts;
+		}
+	}
+
+	if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) {
+		ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
+			"dax flag with busy inodes while remounting");
+		sbi->s_mount_opt ^= EXT4_MOUNT_DAX;
 	}
 
 	if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 2d881b3..6acc964 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -411,8 +411,9 @@
 
 	if (kernfs_type(kn) == KERNFS_LINK)
 		kernfs_put(kn->symlink.target_kn);
-	if (!(kn->flags & KERNFS_STATIC_NAME))
-		kfree(kn->name);
+
+	kfree_const(kn->name);
+
 	if (kn->iattr) {
 		if (kn->iattr->ia_secdata)
 			security_release_secctx(kn->iattr->ia_secdata,
@@ -506,15 +507,12 @@
 					     const char *name, umode_t mode,
 					     unsigned flags)
 {
-	char *dup_name = NULL;
 	struct kernfs_node *kn;
 	int ret;
 
-	if (!(flags & KERNFS_STATIC_NAME)) {
-		name = dup_name = kstrdup(name, GFP_KERNEL);
-		if (!name)
-			return NULL;
-	}
+	name = kstrdup_const(name, GFP_KERNEL);
+	if (!name)
+		return NULL;
 
 	kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL);
 	if (!kn)
@@ -538,7 +536,7 @@
  err_out2:
 	kmem_cache_free(kernfs_node_cache, kn);
  err_out1:
-	kfree(dup_name);
+	kfree_const(name);
 	return NULL;
 }
 
@@ -1264,7 +1262,7 @@
 	/* rename kernfs_node */
 	if (strcmp(kn->name, new_name) != 0) {
 		error = -ENOMEM;
-		new_name = kstrdup(new_name, GFP_KERNEL);
+		new_name = kstrdup_const(new_name, GFP_KERNEL);
 		if (!new_name)
 			goto out;
 	} else {
@@ -1285,9 +1283,7 @@
 
 	kn->ns = new_ns;
 	if (new_name) {
-		if (!(kn->flags & KERNFS_STATIC_NAME))
-			old_name = kn->name;
-		kn->flags &= ~KERNFS_STATIC_NAME;
+		old_name = kn->name;
 		kn->name = new_name;
 	}
 
@@ -1297,7 +1293,7 @@
 	kernfs_link_sibling(kn);
 
 	kernfs_put(old_parent);
-	kfree(old_name);
+	kfree_const(old_name);
 
 	error = 0;
  out:
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index ddc9f96..b684e8a 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -901,7 +901,6 @@
  * @ops: kernfs operations for the file
  * @priv: private data for the file
  * @ns: optional namespace tag of the file
- * @name_is_static: don't copy file name
  * @key: lockdep key for the file's active_ref, %NULL to disable lockdep
  *
  * Returns the created node on success, ERR_PTR() value on error.
@@ -911,7 +910,6 @@
 					 umode_t mode, loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
-					 bool name_is_static,
 					 struct lock_class_key *key)
 {
 	struct kernfs_node *kn;
@@ -919,8 +917,6 @@
 	int rc;
 
 	flags = KERNFS_FILE;
-	if (name_is_static)
-		flags |= KERNFS_STATIC_NAME;
 
 	kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, flags);
 	if (!kn)
diff --git a/fs/namespace.c b/fs/namespace.c
index cd1e968..6dae553 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -201,7 +201,7 @@
 			goto out_free_cache;
 
 		if (name) {
-			mnt->mnt_devname = kstrdup(name, GFP_KERNEL);
+			mnt->mnt_devname = kstrdup_const(name, GFP_KERNEL);
 			if (!mnt->mnt_devname)
 				goto out_free_id;
 		}
@@ -234,7 +234,7 @@
 
 #ifdef CONFIG_SMP
 out_free_devname:
-	kfree(mnt->mnt_devname);
+	kfree_const(mnt->mnt_devname);
 #endif
 out_free_id:
 	mnt_free_id(mnt);
@@ -568,7 +568,7 @@
 
 static void free_vfsmnt(struct mount *mnt)
 {
-	kfree(mnt->mnt_devname);
+	kfree_const(mnt->mnt_devname);
 #ifdef CONFIG_SMP
 	free_percpu(mnt->mnt_pcp);
 #endif
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 46d93e9..44db180 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -28,6 +28,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/mpage.h>
 #include <linux/quotaops.h>
+#include <linux/blkdev.h>
 
 #include <cluster/masklog.h>
 
@@ -47,6 +48,9 @@
 #include "ocfs2_trace.h"
 
 #include "buffer_head_io.h"
+#include "dir.h"
+#include "namei.h"
+#include "sysfile.h"
 
 static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
 				   struct buffer_head *bh_result, int create)
@@ -506,18 +510,21 @@
  *
  * called like this: dio->get_blocks(dio->inode, fs_startblk,
  * 					fs_count, map_bh, dio->rw == WRITE);
- *
- * Note that we never bother to allocate blocks here, and thus ignore the
- * create argument.
  */
 static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
 				     struct buffer_head *bh_result, int create)
 {
 	int ret;
+	u32 cpos = 0;
+	int alloc_locked = 0;
 	u64 p_blkno, inode_blocks, contig_blocks;
 	unsigned int ext_flags;
 	unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
 	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
+	unsigned long len = bh_result->b_size;
+	unsigned int clusters_to_alloc = 0;
+
+	cpos = ocfs2_blocks_to_clusters(inode->i_sb, iblock);
 
 	/* This function won't even be called if the request isn't all
 	 * nicely aligned and of the right size, so there's no need
@@ -539,6 +546,40 @@
 	/* We should already CoW the refcounted extent in case of create. */
 	BUG_ON(create && (ext_flags & OCFS2_EXT_REFCOUNTED));
 
+	/* allocate blocks if no p_blkno is found, and create == 1 */
+	if (!p_blkno && create) {
+		ret = ocfs2_inode_lock(inode, NULL, 1);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto bail;
+		}
+
+		alloc_locked = 1;
+
+		/* fill hole, allocate blocks can't be larger than the size
+		 * of the hole */
+		clusters_to_alloc = ocfs2_clusters_for_bytes(inode->i_sb, len);
+		if (clusters_to_alloc > contig_blocks)
+			clusters_to_alloc = contig_blocks;
+
+		/* allocate extent and insert them into the extent tree */
+		ret = ocfs2_extend_allocation(inode, cpos,
+				clusters_to_alloc, 0);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto bail;
+		}
+
+		ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno,
+				&contig_blocks, &ext_flags);
+		if (ret < 0) {
+			mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n",
+					(unsigned long long)iblock);
+			ret = -EIO;
+			goto bail;
+		}
+	}
+
 	/*
 	 * get_more_blocks() expects us to describe a hole by clearing
 	 * the mapped bit on bh_result().
@@ -556,6 +597,8 @@
 		contig_blocks = max_blocks;
 	bh_result->b_size = contig_blocks << blocksize_bits;
 bail:
+	if (alloc_locked)
+		ocfs2_inode_unlock(inode, 1);
 	return ret;
 }
 
@@ -597,6 +640,184 @@
 	return try_to_free_buffers(page);
 }
 
+static int ocfs2_is_overwrite(struct ocfs2_super *osb,
+		struct inode *inode, loff_t offset)
+{
+	int ret = 0;
+	u32 v_cpos = 0;
+	u32 p_cpos = 0;
+	unsigned int num_clusters = 0;
+	unsigned int ext_flags = 0;
+
+	v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset);
+	ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos,
+			&num_clusters, &ext_flags);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return ret;
+	}
+
+	if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN))
+		return 1;
+
+	return 0;
+}
+
+static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
+		struct iov_iter *iter,
+		loff_t offset)
+{
+	ssize_t ret = 0;
+	ssize_t written = 0;
+	bool orphaned = false;
+	int is_overwrite = 0;
+	struct file *file = iocb->ki_filp;
+	struct inode *inode = file_inode(file)->i_mapping->host;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct buffer_head *di_bh = NULL;
+	size_t count = iter->count;
+	journal_t *journal = osb->journal->j_journal;
+	u32 zero_len;
+	int cluster_align;
+	loff_t final_size = offset + count;
+	int append_write = offset >= i_size_read(inode) ? 1 : 0;
+	unsigned int num_clusters = 0;
+	unsigned int ext_flags = 0;
+
+	{
+		u64 o = offset;
+
+		zero_len = do_div(o, 1 << osb->s_clustersize_bits);
+		cluster_align = !zero_len;
+	}
+
+	/*
+	 * when final_size > inode->i_size, inode->i_size will be
+	 * updated after direct write, so add the inode to orphan
+	 * dir first.
+	 */
+	if (final_size > i_size_read(inode)) {
+		ret = ocfs2_add_inode_to_orphan(osb, inode);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+		orphaned = true;
+	}
+
+	if (append_write) {
+		ret = ocfs2_inode_lock(inode, &di_bh, 1);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto clean_orphan;
+		}
+
+		if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+			ret = ocfs2_zero_extend(inode, di_bh, offset);
+		else
+			ret = ocfs2_extend_no_holes(inode, di_bh, offset,
+					offset);
+		if (ret < 0) {
+			mlog_errno(ret);
+			ocfs2_inode_unlock(inode, 1);
+			brelse(di_bh);
+			goto clean_orphan;
+		}
+
+		is_overwrite = ocfs2_is_overwrite(osb, inode, offset);
+		if (is_overwrite < 0) {
+			mlog_errno(is_overwrite);
+			ocfs2_inode_unlock(inode, 1);
+			brelse(di_bh);
+			goto clean_orphan;
+		}
+
+		ocfs2_inode_unlock(inode, 1);
+		brelse(di_bh);
+		di_bh = NULL;
+	}
+
+	written = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev,
+			iter, offset,
+			ocfs2_direct_IO_get_blocks,
+			ocfs2_dio_end_io, NULL, 0);
+	if (unlikely(written < 0)) {
+		loff_t i_size = i_size_read(inode);
+
+		if (offset + count > i_size) {
+			ret = ocfs2_inode_lock(inode, &di_bh, 1);
+			if (ret < 0) {
+				mlog_errno(ret);
+				goto clean_orphan;
+			}
+
+			if (i_size == i_size_read(inode)) {
+				ret = ocfs2_truncate_file(inode, di_bh,
+						i_size);
+				if (ret < 0) {
+					if (ret != -ENOSPC)
+						mlog_errno(ret);
+
+					ocfs2_inode_unlock(inode, 1);
+					brelse(di_bh);
+					goto clean_orphan;
+				}
+			}
+
+			ocfs2_inode_unlock(inode, 1);
+			brelse(di_bh);
+
+			ret = jbd2_journal_force_commit(journal);
+			if (ret < 0)
+				mlog_errno(ret);
+		}
+	} else if (written < 0 && append_write && !is_overwrite &&
+			!cluster_align) {
+		u32 p_cpos = 0;
+		u32 v_cpos = ocfs2_bytes_to_clusters(osb->sb, offset);
+
+		ret = ocfs2_get_clusters(inode, v_cpos, &p_cpos,
+				&num_clusters, &ext_flags);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto clean_orphan;
+		}
+
+		BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
+
+		ret = blkdev_issue_zeroout(osb->sb->s_bdev,
+				p_cpos << (osb->s_clustersize_bits - 9),
+				zero_len >> 9, GFP_KERNEL, false);
+		if (ret < 0)
+			mlog_errno(ret);
+	}
+
+clean_orphan:
+	if (orphaned) {
+		int tmp_ret;
+		int update_isize = written > 0 ? 1 : 0;
+		loff_t end = update_isize ? offset + written : 0;
+
+		tmp_ret = ocfs2_del_inode_from_orphan(osb, inode,
+				update_isize, end);
+		if (tmp_ret < 0) {
+			ret = tmp_ret;
+			goto out;
+		}
+
+		tmp_ret = jbd2_journal_force_commit(journal);
+		if (tmp_ret < 0) {
+			ret = tmp_ret;
+			mlog_errno(tmp_ret);
+		}
+	}
+
+out:
+	if (ret >= 0)
+		ret = written;
+	return ret;
+}
+
 static ssize_t ocfs2_direct_IO(int rw,
 			       struct kiocb *iocb,
 			       struct iov_iter *iter,
@@ -604,6 +825,9 @@
 {
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file_inode(file)->i_mapping->host;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	int full_coherency = !(osb->s_mount_opt &
+			OCFS2_MOUNT_COHERENCY_BUFFERED);
 
 	/*
 	 * Fallback to buffered I/O if we see an inode without
@@ -612,14 +836,20 @@
 	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
 		return 0;
 
-	/* Fallback to buffered I/O if we are appending. */
-	if (i_size_read(inode) <= offset)
+	/* Fallback to buffered I/O if we are appending and
+	 * concurrent O_DIRECT writes are allowed.
+	 */
+	if (i_size_read(inode) <= offset && !full_coherency)
 		return 0;
 
-	return __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
+	if (rw == READ)
+		return __blockdev_direct_IO(rw, iocb, inode,
+				    inode->i_sb->s_bdev,
 				    iter, offset,
 				    ocfs2_direct_IO_get_blocks,
 				    ocfs2_dio_end_io, NULL, 0);
+	else
+		return ocfs2_direct_IO_write(iocb, iter, offset);
 }
 
 static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb,
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index e0f04d5..46e0d4e 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -295,7 +295,7 @@
 	return ret;
 }
 
-static int ocfs2_set_inode_size(handle_t *handle,
+int ocfs2_set_inode_size(handle_t *handle,
 				struct inode *inode,
 				struct buffer_head *fe_bh,
 				u64 new_i_size)
@@ -441,7 +441,7 @@
 	return status;
 }
 
-static int ocfs2_truncate_file(struct inode *inode,
+int ocfs2_truncate_file(struct inode *inode,
 			       struct buffer_head *di_bh,
 			       u64 new_i_size)
 {
@@ -709,6 +709,13 @@
 	return status;
 }
 
+int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
+		u32 clusters_to_add, int mark_unwritten)
+{
+	return __ocfs2_extend_allocation(inode, logical_start,
+			clusters_to_add, mark_unwritten);
+}
+
 /*
  * While a write will already be ordering the data, a truncate will not.
  * Thus, we need to explicitly order the zeroed pages.
@@ -2109,6 +2116,9 @@
 	struct dentry *dentry = file->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
 	loff_t saved_pos = 0, end;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	int full_coherency = !(osb->s_mount_opt &
+		OCFS2_MOUNT_COHERENCY_BUFFERED);
 
 	/*
 	 * We start with a read level meta lock and only jump to an ex
@@ -2197,7 +2207,16 @@
 		 * one node could wind up truncating another
 		 * nodes writes.
 		 */
-		if (end > i_size_read(inode)) {
+		if (end > i_size_read(inode) && !full_coherency) {
+			*direct_io = 0;
+			break;
+		}
+
+		/*
+		 * Fallback to old way if the feature bit is not set.
+		 */
+		if (end > i_size_read(inode) &&
+				!ocfs2_supports_append_dio(osb)) {
 			*direct_io = 0;
 			break;
 		}
@@ -2210,7 +2229,13 @@
 		 */
 		ret = ocfs2_check_range_for_holes(inode, saved_pos, count);
 		if (ret == 1) {
-			*direct_io = 0;
+			/*
+			 * Fallback to old way if the feature bit is not set.
+			 * Otherwise try dio first and then complete the rest
+			 * request through buffer io.
+			 */
+			if (!ocfs2_supports_append_dio(osb))
+				*direct_io = 0;
 			ret = 0;
 		} else if (ret < 0)
 			mlog_errno(ret);
@@ -2243,6 +2268,7 @@
 	u32 old_clusters;
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file_inode(file);
+	struct address_space *mapping = file->f_mapping;
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 	int full_coherency = !(osb->s_mount_opt &
 			       OCFS2_MOUNT_COHERENCY_BUFFERED);
@@ -2357,11 +2383,51 @@
 
 	iov_iter_truncate(from, count);
 	if (direct_io) {
+		loff_t endbyte;
+		ssize_t written_buffered;
 		written = generic_file_direct_write(iocb, from, *ppos);
-		if (written < 0) {
+		if (written < 0 || written == count) {
 			ret = written;
 			goto out_dio;
 		}
+
+		/*
+		 * for completing the rest of the request.
+		 */
+		*ppos += written;
+		count -= written;
+		written_buffered = generic_perform_write(file, from, *ppos);
+		/*
+		 * If generic_file_buffered_write() returned a synchronous error
+		 * then we want to return the number of bytes which were
+		 * direct-written, or the error code if that was zero. Note
+		 * that this differs from normal direct-io semantics, which
+		 * will return -EFOO even if some bytes were written.
+		 */
+		if (written_buffered < 0) {
+			ret = written_buffered;
+			goto out_dio;
+		}
+
+		iocb->ki_pos = *ppos + written_buffered;
+		/* We need to ensure that the page cache pages are written to
+		 * disk and invalidated to preserve the expected O_DIRECT
+		 * semantics.
+		 */
+		endbyte = *ppos + written_buffered - 1;
+		ret = filemap_write_and_wait_range(file->f_mapping, *ppos,
+				endbyte);
+		if (ret == 0) {
+			written += written_buffered;
+			invalidate_mapping_pages(mapping,
+					*ppos >> PAGE_CACHE_SHIFT,
+					endbyte >> PAGE_CACHE_SHIFT);
+		} else {
+			/*
+			 * We don't know how much we wrote, so just return
+			 * the number of bytes which were direct-written
+			 */
+		}
 	} else {
 		current->backing_dev_info = inode_to_bdi(inode);
 		written = generic_perform_write(file, from, *ppos);
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 97bf761..e8c62f2 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -51,13 +51,22 @@
 			 struct ocfs2_alloc_context *data_ac,
 			 struct ocfs2_alloc_context *meta_ac,
 			 enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_set_inode_size(handle_t *handle,
+		struct inode *inode,
+		struct buffer_head *fe_bh,
+		u64 new_i_size);
 int ocfs2_simple_size_update(struct inode *inode,
 			     struct buffer_head *di_bh,
 			     u64 new_i_size);
+int ocfs2_truncate_file(struct inode *inode,
+		struct buffer_head *di_bh,
+		u64 new_i_size);
 int ocfs2_extend_no_holes(struct inode *inode, struct buffer_head *di_bh,
 			  u64 new_i_size, u64 zero_to);
 int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
 		      loff_t zero_to);
+int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
+		u32 clusters_to_add, int mark_unwritten);
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
 int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		  struct kstat *stat);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index c8b25de..3025c0d 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -648,7 +648,7 @@
 
 	if (!(OCFS2_I(inode)->ip_flags & OCFS2_INODE_SKIP_ORPHAN_DIR)) {
 		status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
-					  orphan_dir_bh);
+					  orphan_dir_bh, false);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail_commit;
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index ca3431e..5e86b24 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -81,6 +81,8 @@
 	tid_t i_sync_tid;
 	tid_t i_datasync_tid;
 
+	wait_queue_head_t append_dio_wq;
+
 	struct dquot *i_dquot[MAXQUOTAS];
 };
 
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index d10860f..ff53192 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -50,6 +50,8 @@
 #include "sysfile.h"
 #include "uptodate.h"
 #include "quota.h"
+#include "file.h"
+#include "namei.h"
 
 #include "buffer_head_io.h"
 #include "ocfs2_trace.h"
@@ -69,13 +71,15 @@
 static int ocfs2_trylock_journal(struct ocfs2_super *osb,
 				 int slot_num);
 static int ocfs2_recover_orphans(struct ocfs2_super *osb,
-				 int slot);
+				 int slot,
+				 enum ocfs2_orphan_reco_type orphan_reco_type);
 static int ocfs2_commit_thread(void *arg);
 static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
 					    int slot_num,
 					    struct ocfs2_dinode *la_dinode,
 					    struct ocfs2_dinode *tl_dinode,
-					    struct ocfs2_quota_recovery *qrec);
+					    struct ocfs2_quota_recovery *qrec,
+					    enum ocfs2_orphan_reco_type orphan_reco_type);
 
 static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb)
 {
@@ -149,7 +153,8 @@
 	return 0;
 }
 
-void ocfs2_queue_replay_slots(struct ocfs2_super *osb)
+void ocfs2_queue_replay_slots(struct ocfs2_super *osb,
+		enum ocfs2_orphan_reco_type orphan_reco_type)
 {
 	struct ocfs2_replay_map *replay_map = osb->replay_map;
 	int i;
@@ -163,7 +168,8 @@
 	for (i = 0; i < replay_map->rm_slots; i++)
 		if (replay_map->rm_replay_slots[i])
 			ocfs2_queue_recovery_completion(osb->journal, i, NULL,
-							NULL, NULL);
+							NULL, NULL,
+							orphan_reco_type);
 	replay_map->rm_state = REPLAY_DONE;
 }
 
@@ -1174,6 +1180,7 @@
 	struct ocfs2_dinode	*lri_la_dinode;
 	struct ocfs2_dinode	*lri_tl_dinode;
 	struct ocfs2_quota_recovery *lri_qrec;
+	enum ocfs2_orphan_reco_type  lri_orphan_reco_type;
 };
 
 /* Does the second half of the recovery process. By this point, the
@@ -1195,6 +1202,7 @@
 	struct ocfs2_dinode *la_dinode, *tl_dinode;
 	struct ocfs2_la_recovery_item *item, *n;
 	struct ocfs2_quota_recovery *qrec;
+	enum ocfs2_orphan_reco_type orphan_reco_type;
 	LIST_HEAD(tmp_la_list);
 
 	trace_ocfs2_complete_recovery(
@@ -1212,6 +1220,7 @@
 		la_dinode = item->lri_la_dinode;
 		tl_dinode = item->lri_tl_dinode;
 		qrec = item->lri_qrec;
+		orphan_reco_type = item->lri_orphan_reco_type;
 
 		trace_ocfs2_complete_recovery_slot(item->lri_slot,
 			la_dinode ? le64_to_cpu(la_dinode->i_blkno) : 0,
@@ -1236,7 +1245,8 @@
 			kfree(tl_dinode);
 		}
 
-		ret = ocfs2_recover_orphans(osb, item->lri_slot);
+		ret = ocfs2_recover_orphans(osb, item->lri_slot,
+				orphan_reco_type);
 		if (ret < 0)
 			mlog_errno(ret);
 
@@ -1261,7 +1271,8 @@
 					    int slot_num,
 					    struct ocfs2_dinode *la_dinode,
 					    struct ocfs2_dinode *tl_dinode,
-					    struct ocfs2_quota_recovery *qrec)
+					    struct ocfs2_quota_recovery *qrec,
+					    enum ocfs2_orphan_reco_type orphan_reco_type)
 {
 	struct ocfs2_la_recovery_item *item;
 
@@ -1285,6 +1296,7 @@
 	item->lri_slot = slot_num;
 	item->lri_tl_dinode = tl_dinode;
 	item->lri_qrec = qrec;
+	item->lri_orphan_reco_type = orphan_reco_type;
 
 	spin_lock(&journal->j_lock);
 	list_add_tail(&item->lri_list, &journal->j_la_cleanups);
@@ -1304,7 +1316,8 @@
 	/* No need to queue up our truncate_log as regular cleanup will catch
 	 * that */
 	ocfs2_queue_recovery_completion(journal, osb->slot_num,
-					osb->local_alloc_copy, NULL, NULL);
+					osb->local_alloc_copy, NULL, NULL,
+					ORPHAN_NEED_TRUNCATE);
 	ocfs2_schedule_truncate_log_flush(osb, 0);
 
 	osb->local_alloc_copy = NULL;
@@ -1312,7 +1325,7 @@
 
 	/* queue to recover orphan slots for all offline slots */
 	ocfs2_replay_map_set_state(osb, REPLAY_NEEDED);
-	ocfs2_queue_replay_slots(osb);
+	ocfs2_queue_replay_slots(osb, ORPHAN_NEED_TRUNCATE);
 	ocfs2_free_replay_slots(osb);
 }
 
@@ -1323,7 +1336,8 @@
 						osb->slot_num,
 						NULL,
 						NULL,
-						osb->quota_rec);
+						osb->quota_rec,
+						ORPHAN_NEED_TRUNCATE);
 		osb->quota_rec = NULL;
 	}
 }
@@ -1360,7 +1374,7 @@
 
 	/* queue recovery for our own slot */
 	ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL,
-					NULL, NULL);
+					NULL, NULL, ORPHAN_NO_NEED_TRUNCATE);
 
 	spin_lock(&osb->osb_lock);
 	while (rm->rm_used) {
@@ -1419,13 +1433,14 @@
 			continue;
 		}
 		ocfs2_queue_recovery_completion(osb->journal, rm_quota[i],
-						NULL, NULL, qrec);
+						NULL, NULL, qrec,
+						ORPHAN_NEED_TRUNCATE);
 	}
 
 	ocfs2_super_unlock(osb, 1);
 
 	/* queue recovery for offline slots */
-	ocfs2_queue_replay_slots(osb);
+	ocfs2_queue_replay_slots(osb, ORPHAN_NEED_TRUNCATE);
 
 bail:
 	mutex_lock(&osb->recovery_lock);
@@ -1711,7 +1726,7 @@
 
 	/* This will kfree the memory pointed to by la_copy and tl_copy */
 	ocfs2_queue_recovery_completion(osb->journal, slot_num, la_copy,
-					tl_copy, NULL);
+					tl_copy, NULL, ORPHAN_NEED_TRUNCATE);
 
 	status = 0;
 done:
@@ -1901,7 +1916,7 @@
 
 	for (i = 0; i < osb->max_slots; i++)
 		ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL,
-						NULL);
+						NULL, ORPHAN_NO_NEED_TRUNCATE);
 	/*
 	 * We queued a recovery on orphan slots, increment the sequence
 	 * number and update LVB so other node will skip the scan for a while
@@ -2000,6 +2015,13 @@
 	if (IS_ERR(iter))
 		return 0;
 
+	/* Skip inodes which are already added to recover list, since dio may
+	 * happen concurrently with unlink/rename */
+	if (OCFS2_I(iter)->ip_next_orphan) {
+		iput(iter);
+		return 0;
+	}
+
 	trace_ocfs2_orphan_filldir((unsigned long long)OCFS2_I(iter)->ip_blkno);
 	/* No locking is required for the next_orphan queue as there
 	 * is only ever a single process doing orphan recovery. */
@@ -2108,7 +2130,8 @@
  *   advertising our state to ocfs2_delete_inode().
  */
 static int ocfs2_recover_orphans(struct ocfs2_super *osb,
-				 int slot)
+				 int slot,
+				 enum ocfs2_orphan_reco_type orphan_reco_type)
 {
 	int ret = 0;
 	struct inode *inode = NULL;
@@ -2132,13 +2155,60 @@
 					(unsigned long long)oi->ip_blkno);
 
 		iter = oi->ip_next_orphan;
+		oi->ip_next_orphan = NULL;
 
-		spin_lock(&oi->ip_lock);
-		/* Set the proper information to get us going into
-		 * ocfs2_delete_inode. */
-		oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
-		spin_unlock(&oi->ip_lock);
+		/*
+		 * We need to take and drop the inode lock to
+		 * force read inode from disk.
+		 */
+		ret = ocfs2_inode_lock(inode, NULL, 0);
+		if (ret) {
+			mlog_errno(ret);
+			goto next;
+		}
+		ocfs2_inode_unlock(inode, 0);
 
+		if (inode->i_nlink == 0) {
+			spin_lock(&oi->ip_lock);
+			/* Set the proper information to get us going into
+			 * ocfs2_delete_inode. */
+			oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
+			spin_unlock(&oi->ip_lock);
+		} else if (orphan_reco_type == ORPHAN_NEED_TRUNCATE) {
+			struct buffer_head *di_bh = NULL;
+
+			ret = ocfs2_rw_lock(inode, 1);
+			if (ret) {
+				mlog_errno(ret);
+				goto next;
+			}
+
+			ret = ocfs2_inode_lock(inode, &di_bh, 1);
+			if (ret < 0) {
+				ocfs2_rw_unlock(inode, 1);
+				mlog_errno(ret);
+				goto next;
+			}
+
+			ret = ocfs2_truncate_file(inode, di_bh,
+					i_size_read(inode));
+			ocfs2_inode_unlock(inode, 1);
+			ocfs2_rw_unlock(inode, 1);
+			brelse(di_bh);
+			if (ret < 0) {
+				if (ret != -ENOSPC)
+					mlog_errno(ret);
+				goto next;
+			}
+
+			ret = ocfs2_del_inode_from_orphan(osb, inode, 0, 0);
+			if (ret)
+				mlog_errno(ret);
+
+			wake_up(&OCFS2_I(inode)->append_dio_wq);
+		} /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */
+
+next:
 		iput(inode);
 
 		inode = iter;
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 7f8cde9..f4cd3c3 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -472,6 +472,11 @@
  * orphan dir index leaf */
 #define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 4)
 
+/* dinode + orphan dir dinode + extent tree leaf block + orphan dir entry +
+ * orphan dir index root + orphan dir index leaf */
+#define OCFS2_INODE_ADD_TO_ORPHAN_CREDITS  (2 * OCFS2_INODE_UPDATE_CREDITS + 4)
+#define OCFS2_INODE_DEL_FROM_ORPHAN_CREDITS  OCFS2_INODE_ADD_TO_ORPHAN_CREDITS
+
 /* dinode update, old dir dinode update, new dir dinode update, old
  * dir dir entry, new dir dir entry, dir entry update for renaming
  * directory + target unlink + 3 x dir index leaves */
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 914c121..b5c3a5e 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -79,7 +79,8 @@
 				    struct inode **ret_orphan_dir,
 				    u64 blkno,
 				    char *name,
-				    struct ocfs2_dir_lookup_result *lookup);
+				    struct ocfs2_dir_lookup_result *lookup,
+				    bool dio);
 
 static int ocfs2_orphan_add(struct ocfs2_super *osb,
 			    handle_t *handle,
@@ -87,7 +88,8 @@
 			    struct buffer_head *fe_bh,
 			    char *name,
 			    struct ocfs2_dir_lookup_result *lookup,
-			    struct inode *orphan_dir_inode);
+			    struct inode *orphan_dir_inode,
+			    bool dio);
 
 static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
 				     handle_t *handle,
@@ -104,6 +106,8 @@
 static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2);
 /* An orphan dir name is an 8 byte value, printed as a hex string */
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
+#define OCFS2_DIO_ORPHAN_PREFIX "dio-"
+#define OCFS2_DIO_ORPHAN_PREFIX_LEN 4
 
 static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
 				   unsigned int flags)
@@ -952,7 +956,8 @@
 	if (ocfs2_inode_is_unlinkable(inode)) {
 		status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
 						  OCFS2_I(inode)->ip_blkno,
-						  orphan_name, &orphan_insert);
+						  orphan_name, &orphan_insert,
+						  false);
 		if (status < 0) {
 			mlog_errno(status);
 			goto leave;
@@ -1004,7 +1009,7 @@
 
 	if (is_unlinkable) {
 		status = ocfs2_orphan_add(osb, handle, inode, fe_bh,
-				orphan_name, &orphan_insert, orphan_dir);
+				orphan_name, &orphan_insert, orphan_dir, false);
 		if (status < 0)
 			mlog_errno(status);
 	}
@@ -1440,7 +1445,8 @@
 		if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
 			status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
 						OCFS2_I(new_inode)->ip_blkno,
-						orphan_name, &orphan_insert);
+						orphan_name, &orphan_insert,
+						false);
 			if (status < 0) {
 				mlog_errno(status);
 				goto bail;
@@ -1507,7 +1513,7 @@
 		if (should_add_orphan) {
 			status = ocfs2_orphan_add(osb, handle, new_inode,
 					newfe_bh, orphan_name,
-					&orphan_insert, orphan_dir);
+					&orphan_insert, orphan_dir, false);
 			if (status < 0) {
 				mlog_errno(status);
 				goto bail;
@@ -2088,12 +2094,28 @@
 				      struct buffer_head *orphan_dir_bh,
 				      u64 blkno,
 				      char *name,
-				      struct ocfs2_dir_lookup_result *lookup)
+				      struct ocfs2_dir_lookup_result *lookup,
+				      bool dio)
 {
 	int ret;
 	struct ocfs2_super *osb = OCFS2_SB(orphan_dir_inode->i_sb);
+	int namelen = dio ?
+			(OCFS2_DIO_ORPHAN_PREFIX_LEN + OCFS2_ORPHAN_NAMELEN) :
+			OCFS2_ORPHAN_NAMELEN;
 
-	ret = ocfs2_blkno_stringify(blkno, name);
+	if (dio) {
+		ret = snprintf(name, OCFS2_DIO_ORPHAN_PREFIX_LEN + 1, "%s",
+				OCFS2_DIO_ORPHAN_PREFIX);
+		if (ret != OCFS2_DIO_ORPHAN_PREFIX_LEN) {
+			ret = -EINVAL;
+			mlog_errno(ret);
+			return ret;
+		}
+
+		ret = ocfs2_blkno_stringify(blkno,
+				name + OCFS2_DIO_ORPHAN_PREFIX_LEN);
+	} else
+		ret = ocfs2_blkno_stringify(blkno, name);
 	if (ret < 0) {
 		mlog_errno(ret);
 		return ret;
@@ -2101,7 +2123,7 @@
 
 	ret = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode,
 					   orphan_dir_bh, name,
-					   OCFS2_ORPHAN_NAMELEN, lookup);
+					   namelen, lookup);
 	if (ret < 0) {
 		mlog_errno(ret);
 		return ret;
@@ -2128,7 +2150,8 @@
 				    struct inode **ret_orphan_dir,
 				    u64 blkno,
 				    char *name,
-				    struct ocfs2_dir_lookup_result *lookup)
+				    struct ocfs2_dir_lookup_result *lookup,
+				    bool dio)
 {
 	struct inode *orphan_dir_inode = NULL;
 	struct buffer_head *orphan_dir_bh = NULL;
@@ -2142,7 +2165,7 @@
 	}
 
 	ret = __ocfs2_prepare_orphan_dir(orphan_dir_inode, orphan_dir_bh,
-					 blkno, name, lookup);
+					 blkno, name, lookup, dio);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out;
@@ -2170,12 +2193,16 @@
 			    struct buffer_head *fe_bh,
 			    char *name,
 			    struct ocfs2_dir_lookup_result *lookup,
-			    struct inode *orphan_dir_inode)
+			    struct inode *orphan_dir_inode,
+			    bool dio)
 {
 	struct buffer_head *orphan_dir_bh = NULL;
 	int status = 0;
 	struct ocfs2_dinode *orphan_fe;
 	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
+	int namelen = dio ?
+			(OCFS2_DIO_ORPHAN_PREFIX_LEN + OCFS2_ORPHAN_NAMELEN) :
+			OCFS2_ORPHAN_NAMELEN;
 
 	trace_ocfs2_orphan_add_begin(
 				(unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -2219,7 +2246,7 @@
 	ocfs2_journal_dirty(handle, orphan_dir_bh);
 
 	status = __ocfs2_add_entry(handle, orphan_dir_inode, name,
-				   OCFS2_ORPHAN_NAMELEN, inode,
+				   namelen, inode,
 				   OCFS2_I(inode)->ip_blkno,
 				   orphan_dir_bh, lookup);
 	if (status < 0) {
@@ -2227,13 +2254,21 @@
 		goto rollback;
 	}
 
-	fe->i_flags |= cpu_to_le32(OCFS2_ORPHANED_FL);
-	OCFS2_I(inode)->ip_flags &= ~OCFS2_INODE_SKIP_ORPHAN_DIR;
+	if (dio) {
+		/* Update flag OCFS2_DIO_ORPHANED_FL and record the orphan
+		 * slot.
+		 */
+		fe->i_flags |= cpu_to_le32(OCFS2_DIO_ORPHANED_FL);
+		fe->i_dio_orphaned_slot = cpu_to_le16(osb->slot_num);
+	} else {
+		fe->i_flags |= cpu_to_le32(OCFS2_ORPHANED_FL);
+		OCFS2_I(inode)->ip_flags &= ~OCFS2_INODE_SKIP_ORPHAN_DIR;
 
-	/* Record which orphan dir our inode now resides
-	 * in. delete_inode will use this to determine which orphan
-	 * dir to lock. */
-	fe->i_orphaned_slot = cpu_to_le16(osb->slot_num);
+		/* Record which orphan dir our inode now resides
+		 * in. delete_inode will use this to determine which orphan
+		 * dir to lock. */
+		fe->i_orphaned_slot = cpu_to_le16(osb->slot_num);
+	}
 
 	ocfs2_journal_dirty(handle, fe_bh);
 
@@ -2258,14 +2293,28 @@
 		     handle_t *handle,
 		     struct inode *orphan_dir_inode,
 		     struct inode *inode,
-		     struct buffer_head *orphan_dir_bh)
+		     struct buffer_head *orphan_dir_bh,
+		     bool dio)
 {
-	char name[OCFS2_ORPHAN_NAMELEN + 1];
+	const int namelen = OCFS2_DIO_ORPHAN_PREFIX_LEN + OCFS2_ORPHAN_NAMELEN;
+	char name[namelen + 1];
 	struct ocfs2_dinode *orphan_fe;
 	int status = 0;
 	struct ocfs2_dir_lookup_result lookup = { NULL, };
 
-	status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);
+	if (dio) {
+		status = snprintf(name, OCFS2_DIO_ORPHAN_PREFIX_LEN + 1, "%s",
+				OCFS2_DIO_ORPHAN_PREFIX);
+		if (status != OCFS2_DIO_ORPHAN_PREFIX_LEN) {
+			status = -EINVAL;
+			mlog_errno(status);
+			return status;
+		}
+
+		status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno,
+				name + OCFS2_DIO_ORPHAN_PREFIX_LEN);
+	} else
+		status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name);
 	if (status < 0) {
 		mlog_errno(status);
 		goto leave;
@@ -2273,10 +2322,10 @@
 
 	trace_ocfs2_orphan_del(
 	     (unsigned long long)OCFS2_I(orphan_dir_inode)->ip_blkno,
-	     name, OCFS2_ORPHAN_NAMELEN);
+	     name, namelen);
 
 	/* find it's spot in the orphan directory */
-	status = ocfs2_find_entry(name, OCFS2_ORPHAN_NAMELEN, orphan_dir_inode,
+	status = ocfs2_find_entry(name, namelen, orphan_dir_inode,
 				  &lookup);
 	if (status) {
 		mlog_errno(status);
@@ -2376,7 +2425,8 @@
 	}
 
 	ret = __ocfs2_prepare_orphan_dir(orphan_dir, orphan_dir_bh,
-					 di_blkno, orphan_name, orphan_insert);
+					 di_blkno, orphan_name, orphan_insert,
+					 false);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out;
@@ -2482,7 +2532,7 @@
 
 	di = (struct ocfs2_dinode *)new_di_bh->b_data;
 	status = ocfs2_orphan_add(osb, handle, inode, new_di_bh, orphan_name,
-				  &orphan_insert, orphan_dir);
+				  &orphan_insert, orphan_dir, false);
 	if (status < 0) {
 		mlog_errno(status);
 		goto leave;
@@ -2527,6 +2577,186 @@
 	return status;
 }
 
+static int ocfs2_dio_orphan_recovered(struct inode *inode)
+{
+	int ret;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di = NULL;
+
+	ret = ocfs2_inode_lock(inode, &di_bh, 1);
+	if (ret < 0) {
+		mlog_errno(ret);
+		return 0;
+	}
+
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+	ret = !(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL));
+	ocfs2_inode_unlock(inode, 1);
+	brelse(di_bh);
+
+	return ret;
+}
+
+#define OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL 10000
+int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb,
+	struct inode *inode)
+{
+	char orphan_name[OCFS2_DIO_ORPHAN_PREFIX_LEN + OCFS2_ORPHAN_NAMELEN + 1];
+	struct inode *orphan_dir_inode = NULL;
+	struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
+	struct buffer_head *di_bh = NULL;
+	int status = 0;
+	handle_t *handle = NULL;
+	struct ocfs2_dinode *di = NULL;
+
+restart:
+	status = ocfs2_inode_lock(inode, &di_bh, 1);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+	/*
+	 * Another append dio crashed?
+	 * If so, wait for recovery first.
+	 */
+	if (unlikely(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) {
+		ocfs2_inode_unlock(inode, 1);
+		brelse(di_bh);
+		wait_event_interruptible_timeout(OCFS2_I(inode)->append_dio_wq,
+				ocfs2_dio_orphan_recovered(inode),
+				msecs_to_jiffies(OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL));
+		goto restart;
+	}
+
+	status = ocfs2_prepare_orphan_dir(osb, &orphan_dir_inode,
+			OCFS2_I(inode)->ip_blkno,
+			orphan_name,
+			&orphan_insert,
+			true);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail_unlock_inode;
+	}
+
+	handle = ocfs2_start_trans(osb,
+			OCFS2_INODE_ADD_TO_ORPHAN_CREDITS);
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		goto bail_unlock_orphan;
+	}
+
+	status = ocfs2_orphan_add(osb, handle, inode, di_bh, orphan_name,
+			&orphan_insert, orphan_dir_inode, true);
+	if (status)
+		mlog_errno(status);
+
+	ocfs2_commit_trans(osb, handle);
+
+bail_unlock_orphan:
+	ocfs2_inode_unlock(orphan_dir_inode, 1);
+	mutex_unlock(&orphan_dir_inode->i_mutex);
+	iput(orphan_dir_inode);
+
+	ocfs2_free_dir_lookup_result(&orphan_insert);
+
+bail_unlock_inode:
+	ocfs2_inode_unlock(inode, 1);
+	brelse(di_bh);
+
+bail:
+	return status;
+}
+
+int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb,
+		struct inode *inode, int update_isize,
+		loff_t end)
+{
+	struct inode *orphan_dir_inode = NULL;
+	struct buffer_head *orphan_dir_bh = NULL;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di = NULL;
+	handle_t *handle = NULL;
+	int status = 0;
+
+	status = ocfs2_inode_lock(inode, &di_bh, 1);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+
+	orphan_dir_inode = ocfs2_get_system_file_inode(osb,
+			ORPHAN_DIR_SYSTEM_INODE,
+			le16_to_cpu(di->i_dio_orphaned_slot));
+	if (!orphan_dir_inode) {
+		status = -ENOENT;
+		mlog_errno(status);
+		goto bail_unlock_inode;
+	}
+
+	mutex_lock(&orphan_dir_inode->i_mutex);
+	status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1);
+	if (status < 0) {
+		mutex_unlock(&orphan_dir_inode->i_mutex);
+		iput(orphan_dir_inode);
+		mlog_errno(status);
+		goto bail_unlock_inode;
+	}
+
+	handle = ocfs2_start_trans(osb,
+			OCFS2_INODE_DEL_FROM_ORPHAN_CREDITS);
+	if (IS_ERR(handle)) {
+		status = PTR_ERR(handle);
+		goto bail_unlock_orphan;
+	}
+
+	BUG_ON(!(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL)));
+
+	status = ocfs2_orphan_del(osb, handle, orphan_dir_inode,
+				inode, orphan_dir_bh, true);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail_commit;
+	}
+
+	status = ocfs2_journal_access_di(handle,
+			INODE_CACHE(inode),
+			di_bh,
+			OCFS2_JOURNAL_ACCESS_WRITE);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail_commit;
+	}
+
+	di->i_flags &= ~cpu_to_le32(OCFS2_DIO_ORPHANED_FL);
+	di->i_dio_orphaned_slot = 0;
+
+	if (update_isize) {
+		status = ocfs2_set_inode_size(handle, inode, di_bh, end);
+		if (status)
+			mlog_errno(status);
+	} else
+		ocfs2_journal_dirty(handle, di_bh);
+
+bail_commit:
+	ocfs2_commit_trans(osb, handle);
+
+bail_unlock_orphan:
+	ocfs2_inode_unlock(orphan_dir_inode, 1);
+	mutex_unlock(&orphan_dir_inode->i_mutex);
+	brelse(orphan_dir_bh);
+	iput(orphan_dir_inode);
+
+bail_unlock_inode:
+	ocfs2_inode_unlock(inode, 1);
+	brelse(di_bh);
+
+bail:
+	return status;
+}
+
 int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
 				   struct inode *inode,
 				   struct dentry *dentry)
@@ -2615,7 +2845,7 @@
 	}
 
 	status = ocfs2_orphan_del(osb, handle, orphan_dir_inode, inode,
-				  orphan_dir_bh);
+				  orphan_dir_bh, false);
 	if (status < 0) {
 		mlog_errno(status);
 		goto out_commit;
diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h
index e5d059d..5ddecce 100644
--- a/fs/ocfs2/namei.h
+++ b/fs/ocfs2/namei.h
@@ -34,10 +34,16 @@
 		     handle_t *handle,
 		     struct inode *orphan_dir_inode,
 		     struct inode *inode,
-		     struct buffer_head *orphan_dir_bh);
+		     struct buffer_head *orphan_dir_bh,
+		     bool dio);
 int ocfs2_create_inode_in_orphan(struct inode *dir,
 				 int mode,
 				 struct inode **new_inode);
+int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb,
+		struct inode *inode);
+int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb,
+		struct inode *inode, int update_isize,
+		loff_t end);
 int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
 				   struct inode *new_inode,
 				   struct dentry *new_dentry);
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index fdbcbfe..8490c64 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -209,6 +209,11 @@
 #endif
 };
 
+enum ocfs2_orphan_reco_type {
+	ORPHAN_NO_NEED_TRUNCATE = 0,
+	ORPHAN_NEED_TRUNCATE,
+};
+
 enum ocfs2_orphan_scan_state {
 	ORPHAN_SCAN_ACTIVE,
 	ORPHAN_SCAN_INACTIVE
@@ -495,6 +500,14 @@
 	return 0;
 }
 
+static inline int ocfs2_supports_append_dio(struct ocfs2_super *osb)
+{
+	if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
+		return 1;
+	return 0;
+}
+
+
 static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
 {
 	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
@@ -726,6 +739,16 @@
 	return clusters;
 }
 
+static inline unsigned int ocfs2_bytes_to_clusters(struct super_block *sb,
+		u64 bytes)
+{
+	int cl_bits = OCFS2_SB(sb)->s_clustersize_bits;
+	unsigned int clusters;
+
+	clusters = (unsigned int)(bytes >> cl_bits);
+	return clusters;
+}
+
 static inline u64 ocfs2_blocks_for_bytes(struct super_block *sb,
 					 u64 bytes)
 {
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 938387a..20e37a3 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -105,7 +105,8 @@
 					 | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP	(OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
 					 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
-					 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
+					 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA \
+					 | OCFS2_FEATURE_RO_COMPAT_APPEND_DIO)
 
 /*
  * Heartbeat-only devices are missing journals and other files.  The
@@ -199,6 +200,11 @@
 #define OCFS2_FEATURE_RO_COMPAT_USRQUOTA	0x0002
 #define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA	0x0004
 
+/*
+ * Append Direct IO support
+ */
+#define OCFS2_FEATURE_RO_COMPAT_APPEND_DIO	0x0008
+
 /* The byte offset of the first backup block will be 1G.
  * The following will be 4G, 16G, 64G, 256G and 1T.
  */
@@ -229,6 +235,8 @@
 #define OCFS2_CHAIN_FL		(0x00000400)	/* Chain allocator */
 #define OCFS2_DEALLOC_FL	(0x00000800)	/* Truncate log */
 #define OCFS2_QUOTA_FL		(0x00001000)	/* Quota file */
+#define OCFS2_DIO_ORPHANED_FL	(0X00002000)	/* On the orphan list especially
+						 * for dio */
 
 /*
  * Flags on ocfs2_dinode.i_dyn_features
@@ -729,7 +737,9 @@
 					   inode belongs to.  Only valid
 					   if allocated from a
 					   discontiguous block group */
-/*A0*/	__le64 i_reserved2[3];
+/*A0*/	__le16 i_dio_orphaned_slot;	/* only used for append dio write */
+	__le16 i_reserved1[3];
+	__le64 i_reserved2[2];
 /*B8*/	union {
 		__le64 i_pad1;		/* Generic way to refer to this
 					   64bit union */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 87a1f76..2667518 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1746,6 +1746,8 @@
 	ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
 	ocfs2_lock_res_init_once(&oi->ip_open_lockres);
 
+	init_waitqueue_head(&oi->append_dio_wq);
+
 	ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode),
 				  &ocfs2_inode_caching_ops);
 
diff --git a/fs/open.c b/fs/open.c
index 813be03..a293c20 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -667,11 +667,8 @@
 {
 	/* NB: we're sure to have correct a_ops only after f_op->open */
 	if (f->f_flags & O_DIRECT) {
-		if (!f->f_mapping->a_ops ||
-		    ((!f->f_mapping->a_ops->direct_IO) &&
-		    (!f->f_mapping->a_ops->get_xip_mem))) {
+		if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
 			return -EINVAL;
-		}
 	}
 	return 0;
 }
diff --git a/fs/proc/array.c b/fs/proc/array.c
index a3ccf4c..1295a00 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -316,12 +316,10 @@
 
 static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
 {
-	seq_puts(m, "Cpus_allowed:\t");
-	seq_cpumask(m, &task->cpus_allowed);
-	seq_putc(m, '\n');
-	seq_puts(m, "Cpus_allowed_list:\t");
-	seq_cpumask_list(m, &task->cpus_allowed);
-	seq_putc(m, '\n');
+	seq_printf(m, "Cpus_allowed:\t%*pb\n",
+		   cpumask_pr_args(&task->cpus_allowed));
+	seq_printf(m, "Cpus_allowed_list:\t%*pbl\n",
+		   cpumask_pr_args(&task->cpus_allowed));
 }
 
 int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/seq_file.c b/fs/seq_file.c
index dbf3a59..555f821 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -539,38 +539,6 @@
 	return res;
 }
 
-int seq_bitmap(struct seq_file *m, const unsigned long *bits,
-				   unsigned int nr_bits)
-{
-	if (m->count < m->size) {
-		int len = bitmap_scnprintf(m->buf + m->count,
-				m->size - m->count, bits, nr_bits);
-		if (m->count + len < m->size) {
-			m->count += len;
-			return 0;
-		}
-	}
-	seq_set_overflow(m);
-	return -1;
-}
-EXPORT_SYMBOL(seq_bitmap);
-
-int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
-		unsigned int nr_bits)
-{
-	if (m->count < m->size) {
-		int len = bitmap_scnlistprintf(m->buf + m->count,
-				m->size - m->count, bits, nr_bits);
-		if (m->count + len < m->size) {
-			m->count += len;
-			return 0;
-		}
-	}
-	seq_set_overflow(m);
-	return -1;
-}
-EXPORT_SYMBOL(seq_bitmap_list);
-
 static void *single_start(struct seq_file *p, loff_t *pos)
 {
 	return NULL + (*pos == 0);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index dfe928a..7c2867b 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -295,7 +295,7 @@
 		key = attr->key ?: (struct lock_class_key *)&attr->skey;
 #endif
 	kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops,
-				  (void *)attr, ns, true, key);
+				  (void *)attr, ns, key);
 	if (IS_ERR(kn)) {
 		if (PTR_ERR(kn) == -EEXIST)
 			sysfs_warn_dup(parent, attr->name);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 7d2a860..2554d88 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -99,7 +99,7 @@
 		return -EINVAL;
 	if (!grp->attrs && !grp->bin_attrs) {
 		WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
-			kobj->name, grp->name ? "" : grp->name);
+			kobj->name, grp->name ?: "");
 		return -EINVAL;
 	}
 	if (grp->name) {
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 7ed13e1..4cfb3e8 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -2032,6 +2032,8 @@
 		long long blk_offs;
 		struct ubifs_data_node *dn = node;
 
+		ubifs_assert(zbr->len >= UBIFS_DATA_NODE_SZ);
+
 		/*
 		 * Search the inode node this data node belongs to and insert
 		 * it to the RB-tree of inodes.
@@ -2060,6 +2062,8 @@
 		struct ubifs_dent_node *dent = node;
 		struct fsck_inode *fscki1;
 
+		ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ);
+
 		err = ubifs_validate_entry(c, dent);
 		if (err)
 			goto out_dump;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index c49b198..0fa6c80 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -270,6 +270,10 @@
 		goto out_budg;
 	}
 
+	err = ubifs_init_security(dir, inode, &dentry->d_name);
+	if (err)
+		goto out_cancel;
+
 	mutex_lock(&dir_ui->ui_mutex);
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
@@ -726,6 +730,10 @@
 		goto out_budg;
 	}
 
+	err = ubifs_init_security(dir, inode, &dentry->d_name);
+	if (err)
+		goto out_cancel;
+
 	mutex_lock(&dir_ui->ui_mutex);
 	insert_inode_hash(inode);
 	inc_nlink(inode);
@@ -806,6 +814,10 @@
 	ui->data = dev;
 	ui->data_len = devlen;
 
+	err = ubifs_init_security(dir, inode, &dentry->d_name);
+	if (err)
+		goto out_cancel;
+
 	mutex_lock(&dir_ui->ui_mutex);
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
@@ -882,6 +894,10 @@
 	ui->data_len = len;
 	inode->i_size = ubifs_inode(inode)->ui_size = len;
 
+	err = ubifs_init_security(dir, inode, &dentry->d_name);
+	if (err)
+		goto out_cancel;
+
 	mutex_lock(&dir_ui->ui_mutex);
 	dir->i_size += sz_change;
 	dir_ui->ui_size = dir->i_size;
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 035e510..e627c0a 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1573,6 +1573,10 @@
 	.follow_link = ubifs_follow_link,
 	.setattr     = ubifs_setattr,
 	.getattr     = ubifs_getattr,
+	.setxattr    = ubifs_setxattr,
+	.getxattr    = ubifs_getxattr,
+	.listxattr   = ubifs_listxattr,
+	.removexattr = ubifs_removexattr,
 };
 
 const struct file_operations ubifs_file_operations = {
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 3187925..9b40a1c 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -1028,9 +1028,22 @@
 
 	do {
 		err = replay_log_leb(c, lnum, 0, c->sbuf);
-		if (err == 1)
-			/* We hit the end of the log */
-			break;
+		if (err == 1) {
+			if (lnum != c->lhead_lnum)
+				/* We hit the end of the log */
+				break;
+
+			/*
+			 * The head of the log must always start with the
+			 * "commit start" node on a properly formatted UBIFS.
+			 * But we found no nodes at all, which means that
+			 * someting went wrong and we cannot proceed mounting
+			 * the file-system.
+			 */
+			ubifs_err("no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
+				  lnum, 0);
+			err = -EINVAL;
+		}
 		if (err)
 			goto out;
 		lnum = ubifs_next_log_lnum(c, lnum);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 6197154..93e9465 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -2036,6 +2036,7 @@
 	if (c->max_inode_sz > MAX_LFS_FILESIZE)
 		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
 	sb->s_op = &ubifs_super_operations;
+	sb->s_xattr = ubifs_xattr_handlers;
 
 	mutex_lock(&c->umount_mutex);
 	err = mount_ubifs(c);
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index c4fe900..bc04b9c 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -36,6 +36,7 @@
 #include <linux/mtd/ubi.h>
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
+#include <linux/security.h>
 #include "ubifs-media.h"
 
 /* Version of this UBIFS implementation */
@@ -1465,6 +1466,7 @@
 extern atomic_long_t ubifs_clean_zn_cnt;
 extern struct kmem_cache *ubifs_inode_slab;
 extern const struct super_operations ubifs_super_operations;
+extern const struct xattr_handler *ubifs_xattr_handlers[];
 extern const struct address_space_operations ubifs_file_address_operations;
 extern const struct file_operations ubifs_file_operations;
 extern const struct inode_operations ubifs_file_inode_operations;
@@ -1754,6 +1756,8 @@
 		       size_t size);
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_removexattr(struct dentry *dentry, const char *name);
+int ubifs_init_security(struct inode *dentry, struct inode *inode,
+			const struct qstr *qstr);
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 5e0a63b..a92be24 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -100,24 +100,30 @@
 static int create_xattr(struct ubifs_info *c, struct inode *host,
 			const struct qstr *nm, const void *value, int size)
 {
-	int err;
+	int err, names_len;
 	struct inode *inode;
 	struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 				.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
 				.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
 
-	if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE)
+	if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) {
+		ubifs_err("inode %lu already has too many xattrs (%d), cannot create more",
+			  host->i_ino, host_ui->xattr_cnt);
 		return -ENOSPC;
+	}
 	/*
 	 * Linux limits the maximum size of the extended attribute names list
 	 * to %XATTR_LIST_MAX. This means we should not allow creating more
 	 * extended attributes if the name list becomes larger. This limitation
 	 * is artificial for UBIFS, though.
 	 */
-	if (host_ui->xattr_names + host_ui->xattr_cnt +
-					nm->len + 1 > XATTR_LIST_MAX)
+	names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1;
+	if (names_len > XATTR_LIST_MAX) {
+		ubifs_err("cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
+			  host->i_ino, names_len, XATTR_LIST_MAX);
 		return -ENOSPC;
+	}
 
 	err = ubifs_budget_space(c, &req);
 	if (err)
@@ -293,18 +299,16 @@
 	return ERR_PTR(-EINVAL);
 }
 
-int ubifs_setxattr(struct dentry *dentry, const char *name,
-		   const void *value, size_t size, int flags)
+static int setxattr(struct inode *host, const char *name, const void *value,
+		    size_t size, int flags)
 {
-	struct inode *inode, *host = dentry->d_inode;
+	struct inode *inode;
 	struct ubifs_info *c = host->i_sb->s_fs_info;
 	struct qstr nm = QSTR_INIT(name, strlen(name));
 	struct ubifs_dent_node *xent;
 	union ubifs_key key;
 	int err, type;
 
-	dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd", name,
-		host->i_ino, dentry, size);
 	ubifs_assert(mutex_is_locked(&host->i_mutex));
 
 	if (size > UBIFS_MAX_INO_DATA)
@@ -356,6 +360,15 @@
 	return err;
 }
 
+int ubifs_setxattr(struct dentry *dentry, const char *name,
+		   const void *value, size_t size, int flags)
+{
+	dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
+		name, dentry->d_inode->i_ino, dentry, size);
+
+	return setxattr(dentry->d_inode, name, value, size, flags);
+}
+
 ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
 		       size_t size)
 {
@@ -568,3 +581,84 @@
 	kfree(xent);
 	return err;
 }
+
+static size_t security_listxattr(struct dentry *d, char *list, size_t list_size,
+				 const char *name, size_t name_len, int flags)
+{
+	const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
+	const size_t total_len = prefix_len + name_len + 1;
+
+	if (list && total_len <= list_size) {
+		memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
+		memcpy(list + prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+
+	return total_len;
+}
+
+static int security_getxattr(struct dentry *d, const char *name, void *buffer,
+		      size_t size, int flags)
+{
+	return ubifs_getxattr(d, name, buffer, size);
+}
+
+static int security_setxattr(struct dentry *d, const char *name,
+			     const void *value, size_t size, int flags,
+			     int handler_flags)
+{
+	return ubifs_setxattr(d, name, value, size, flags);
+}
+
+static const struct xattr_handler ubifs_xattr_security_handler = {
+	.prefix = XATTR_SECURITY_PREFIX,
+	.list   = security_listxattr,
+	.get    = security_getxattr,
+	.set    = security_setxattr,
+};
+
+const struct xattr_handler *ubifs_xattr_handlers[] = {
+	&ubifs_xattr_security_handler,
+	NULL,
+};
+
+static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
+		      void *fs_info)
+{
+	const struct xattr *xattr;
+	char *name;
+	int err = 0;
+
+	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+		name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
+			       strlen(xattr->name) + 1, GFP_NOFS);
+		if (!name) {
+			err = -ENOMEM;
+			break;
+		}
+		strcpy(name, XATTR_SECURITY_PREFIX);
+		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
+		err = setxattr(inode, name, xattr->value, xattr->value_len, 0);
+		kfree(name);
+		if (err < 0)
+			break;
+	}
+
+	return err;
+}
+
+int ubifs_init_security(struct inode *dentry, struct inode *inode,
+			const struct qstr *qstr)
+{
+	int err;
+
+	mutex_lock(&inode->i_mutex);
+	err = security_inode_init_security(inode, dentry, qstr,
+					   &init_xattrs, 0);
+	mutex_unlock(&inode->i_mutex);
+
+	if (err)
+		ubifs_err("cannot initialize security for inode %lu, error %d",
+			  inode->i_ino, err);
+	return err;
+}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bee5d68..ac78910 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -478,6 +478,7 @@
 #define KERNEL_CTORS()	. = ALIGN(8);			   \
 			VMLINUX_SYMBOL(__ctors_start) = .; \
 			*(.ctors)			   \
+			*(SORT(.init_array.*))		   \
 			*(.init_array)			   \
 			VMLINUX_SYMBOL(__ctors_end) = .;
 #else
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 88ea64e..178525e 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -50,6 +50,7 @@
 	void (*release)(void *private);
 	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
 	int (*accept)(void *private, struct sock *sk);
+	int (*setauthsize)(void *private, unsigned int authsize);
 
 	struct proto_ops *ops;
 	struct module *owner;
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 7ef512f..20e4226 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -33,21 +33,13 @@
 	sg1[num - 1].page_link |= 0x01;
 }
 
-static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
-{
-	if (sg_is_last(sg))
-		return NULL;
-
-	return (++sg)->length ? sg : sg_chain_ptr(sg);
-}
-
 static inline void scatterwalk_crypto_chain(struct scatterlist *head,
 					    struct scatterlist *sg,
 					    int chain, int num)
 {
 	if (chain) {
 		head->length += sg->length;
-		sg = scatterwalk_sg_next(sg);
+		sg = sg_next(sg);
 	}
 
 	if (sg)
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..5a4f490
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
+
+#include <drm/drmP.h>
+
+enum {
+	DW_HDMI_RES_8,
+	DW_HDMI_RES_10,
+	DW_HDMI_RES_12,
+	DW_HDMI_RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+	IMX6Q_HDMI,
+	IMX6DL_HDMI,
+	RK3288_HDMI,
+};
+
+struct dw_hdmi_mpll_config {
+	unsigned long mpixelclock;
+	struct {
+		u16 cpce;
+		u16 gmp;
+	} res[DW_HDMI_RES_MAX];
+};
+
+struct dw_hdmi_curr_ctrl {
+	unsigned long mpixelclock;
+	u16 curr[DW_HDMI_RES_MAX];
+};
+
+struct dw_hdmi_sym_term {
+	unsigned long mpixelclock;
+	u16 sym_ctr;    /*clock symbol and transmitter control*/
+	u16 term;       /*transmission termination value*/
+};
+
+struct dw_hdmi_plat_data {
+	enum dw_hdmi_devtype dev_type;
+	const struct dw_hdmi_mpll_config *mpll_cfg;
+	const struct dw_hdmi_curr_ctrl *cur_ctr;
+	const struct dw_hdmi_sym_term *sym_term;
+	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+					   struct drm_display_mode *mode);
+};
+
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+		 void *data, struct drm_encoder *encoder,
+		 struct resource *iores, int irq,
+		 const struct dw_hdmi_plat_data *plat_data);
+#endif /* __IMX_HDMI_H__ */
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
index ff62344..b11f8e1 100644
--- a/include/drm/bridge/ptn3460.h
+++ b/include/drm/bridge/ptn3460.h
@@ -15,6 +15,7 @@
 #define _DRM_BRIDGE_PTN3460_H_
 
 struct drm_device;
+struct drm_bridge;
 struct drm_encoder;
 struct i2c_client;
 struct device_node;
@@ -23,6 +24,9 @@
 
 int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
 		struct i2c_client *client, struct device_node *node);
+
+void ptn3460_destroy(struct drm_bridge *bridge);
+
 #else
 
 static inline int ptn3460_init(struct drm_device *dev,
@@ -32,6 +36,10 @@
 	return 0;
 }
 
+static inline void ptn3460_destroy(struct drm_bridge *bridge)
+{
+}
+
 #endif
 
 #endif
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index e1b2e8b..e928625 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -143,6 +143,7 @@
 #define DRIVER_MODESET     0x2000
 #define DRIVER_PRIME       0x4000
 #define DRIVER_RENDER      0x8000
+#define DRIVER_ATOMIC      0x10000
 
 /***********************************************************************/
 /** \name Macros to make printk easier */
@@ -283,6 +284,8 @@
 	 * in the plane list
 	 */
 	unsigned universal_planes:1;
+	/* true if client understands atomic properties */
+	unsigned atomic:1;
 
 	struct pid *pid;
 	kuid_t uid;
@@ -744,8 +747,6 @@
 
 	/** \name Context support */
 	/*@{ */
-	bool irq_enabled;		/**< True if irq handler is enabled */
-	int irq;
 
 	__volatile__ long context_flag;	/**< Context swapping flag */
 	int last_context;		/**< Last current context */
@@ -753,6 +754,8 @@
 
 	/** \name VBLANK IRQ support */
 	/*@{ */
+	bool irq_enabled;
+	int irq;
 
 	/*
 	 * At load time, disabling the vblank interrupt won't be allowed since
@@ -954,6 +957,7 @@
 extern void drm_put_dev(struct drm_device *dev);
 extern void drm_unplug_dev(struct drm_device *dev);
 extern unsigned int drm_debug;
+extern bool drm_atomic;
 
 				/* Debugfs support */
 #if defined(CONFIG_DEBUG_FS)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index ad22295..51168a8 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -38,16 +38,25 @@
 struct drm_crtc_state * __must_check
 drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 			  struct drm_crtc *crtc);
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state, struct drm_property *property,
+		uint64_t val);
 struct drm_plane_state * __must_check
 drm_atomic_get_plane_state(struct drm_atomic_state *state,
 			   struct drm_plane *plane);
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state, struct drm_property *property,
+		uint64_t val);
 struct drm_connector_state * __must_check
 drm_atomic_get_connector_state(struct drm_atomic_state *state,
 			       struct drm_connector *connector);
+int drm_atomic_connector_set_property(struct drm_connector *connector,
+		struct drm_connector_state *state, struct drm_property *property,
+		uint64_t val);
 
 int __must_check
-drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
-			      struct drm_plane *plane, struct drm_crtc *crtc);
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+			      struct drm_crtc *crtc);
 void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
 				 struct drm_framebuffer *fb);
 int __must_check
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index f956b41..8039d54 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -30,6 +30,10 @@
 
 #include <drm/drm_crtc.h>
 
+int drm_atomic_helper_check_modeset(struct drm_device *dev,
+				struct drm_atomic_state *state);
+int drm_atomic_helper_check_planes(struct drm_device *dev,
+			       struct drm_atomic_state *state);
 int drm_atomic_helper_check(struct drm_device *dev,
 			    struct drm_atomic_state *state);
 int drm_atomic_helper_commit(struct drm_device *dev,
@@ -78,6 +82,8 @@
 				struct drm_framebuffer *fb,
 				struct drm_pending_vblank_event *event,
 				uint32_t flags);
+void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+				      int mode);
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
@@ -123,4 +129,41 @@
 #define drm_atomic_crtc_state_for_each_plane(plane, crtc_state) \
 	drm_for_each_plane_mask(plane, (crtc_state)->state->dev, (crtc_state)->plane_mask)
 
+/*
+ * drm_atomic_plane_disabling - check whether a plane is being disabled
+ * @plane: plane object
+ * @old_state: previous atomic state
+ *
+ * Checks the atomic state of a plane to determine whether it's being disabled
+ * or not. This also WARNs if it detects an invalid state (both CRTC and FB
+ * need to either both be NULL or both be non-NULL).
+ *
+ * RETURNS:
+ * True if the plane is being disabled, false otherwise.
+ */
+static inline bool
+drm_atomic_plane_disabling(struct drm_plane *plane,
+			   struct drm_plane_state *old_state)
+{
+	/*
+	 * When disabling a plane, CRTC and FB should always be NULL together.
+	 * Anything else should be considered a bug in the atomic core, so we
+	 * gently warn about it.
+	 */
+	WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) ||
+		(plane->state->crtc != NULL && plane->state->fb == NULL));
+
+	/*
+	 * When using the transitional helpers, old_state may be NULL. If so,
+	 * we know nothing about the current state and have to assume that it
+	 * might be enabled.
+	 *
+	 * When using the atomic helpers, old_state won't be NULL. Therefore
+	 * this check assumes that either the driver will have reconstructed
+	 * the correct state in ->reset() or that the driver will have taken
+	 * appropriate measures to disable all planes.
+	 */
+	return (!old_state || old_state->crtc) && !plane->state->crtc;
+}
+
 #endif /* DRM_ATOMIC_HELPER_H_ */
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b863298..920e21a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -31,6 +31,7 @@
 #include <linux/idr.h>
 #include <linux/fb.h>
 #include <linux/hdmi.h>
+#include <linux/media-bus-format.h>
 #include <uapi/drm/drm_mode.h>
 #include <uapi/drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
@@ -63,8 +64,16 @@
 
 #define DRM_OBJECT_MAX_PROPERTY 24
 struct drm_object_properties {
-	int count;
-	uint32_t ids[DRM_OBJECT_MAX_PROPERTY];
+	int count, atomic_count;
+	/* NOTE: if we ever start dynamically destroying properties (ie.
+	 * not at drm_mode_config_cleanup() time), then we'd have to do
+	 * a better job of detaching property from mode objects to avoid
+	 * dangling property pointers:
+	 */
+	struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
+	/* do not read/write values directly, but use drm_object_property_get_value()
+	 * and drm_object_property_set_value():
+	 */
 	uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
@@ -131,6 +140,9 @@
 	enum subpixel_order subpixel_order;
 	u32 color_formats;
 
+	const u32 *bus_formats;
+	unsigned int num_bus_formats;
+
 	/* Mask of supported hdmi deep color modes */
 	u8 edid_hdmi_dc_modes;
 
@@ -237,8 +249,11 @@
 
 /**
  * struct drm_crtc_state - mutable CRTC state
+ * @crtc: backpointer to the CRTC
  * @enable: whether the CRTC should be enabled, gates all other state
+ * @active: whether the CRTC is actively displaying (used for DPMS)
  * @mode_changed: for use by helpers and drivers when computing state updates
+ * @active_changed: for use by helpers and drivers when computing state updates
  * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
  * @last_vblank_count: for helpers and drivers to capture the vblank of the
  * 	update to ensure framebuffer cleanup isn't done too early
@@ -248,13 +263,23 @@
  * @event: optional pointer to a DRM event to signal upon completion of the
  * 	state update
  * @state: backpointer to global drm_atomic_state
+ *
+ * Note that the distinction between @enable and @active is rather subtile:
+ * Flipping @active while @enable is set without changing anything else may
+ * never return in a failure from the ->atomic_check callback. Userspace assumes
+ * that a DPMS On will always succeed. In other words: @enable controls resource
+ * assignment, @active controls the actual hardware state.
  */
 struct drm_crtc_state {
+	struct drm_crtc *crtc;
+
 	bool enable;
+	bool active;
 
 	/* computed state bits used by helpers and drivers */
 	bool planes_changed : 1;
 	bool mode_changed : 1;
+	bool active_changed : 1;
 
 	/* attached planes bitmask:
 	 * WARNING: transitional helpers do not maintain plane_mask so
@@ -292,6 +317,9 @@
  * @atomic_duplicate_state: duplicate the atomic state for this CRTC
  * @atomic_destroy_state: destroy an atomic state for this CRTC
  * @atomic_set_property: set a property on an atomic state for this CRTC
+ *    (do not call directly, use drm_atomic_crtc_set_property())
+ * @atomic_get_property: get a property on an atomic state for this CRTC
+ *    (do not call directly, use drm_atomic_crtc_get_property())
  *
  * The drm_crtc_funcs structure is the central CRTC management structure
  * in the DRM.  Each CRTC controls one or more connectors (note that the name
@@ -351,6 +379,10 @@
 				   struct drm_crtc_state *state,
 				   struct drm_property *property,
 				   uint64_t val);
+	int (*atomic_get_property)(struct drm_crtc *crtc,
+				   const struct drm_crtc_state *state,
+				   struct drm_property *property,
+				   uint64_t *val);
 };
 
 /**
@@ -449,11 +481,14 @@
 
 /**
  * struct drm_connector_state - mutable connector state
+ * @connector: backpointer to the connector
  * @crtc: CRTC to connect connector to, NULL if disabled
  * @best_encoder: can be used by helpers and drivers to select the encoder
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_connector_state {
+	struct drm_connector *connector;
+
 	struct drm_crtc *crtc;  /* do not write directly, use drm_atomic_set_crtc_for_connector() */
 
 	struct drm_encoder *best_encoder;
@@ -463,7 +498,7 @@
 
 /**
  * struct drm_connector_funcs - control connectors on a given device
- * @dpms: set power state (see drm_crtc_funcs above)
+ * @dpms: set power state
  * @save: save connector state
  * @restore: restore connector state
  * @reset: reset connector after state has been invalidated (e.g. resume)
@@ -475,6 +510,9 @@
  * @atomic_duplicate_state: duplicate the atomic state for this connector
  * @atomic_destroy_state: destroy an atomic state for this connector
  * @atomic_set_property: set a property on an atomic state for this connector
+ *    (do not call directly, use drm_atomic_connector_set_property())
+ * @atomic_get_property: get a property on an atomic state for this connector
+ *    (do not call directly, use drm_atomic_connector_get_property())
  *
  * Each CRTC may have one or more connectors attached to it.  The functions
  * below allow the core DRM code to control connectors, enumerate available modes,
@@ -508,6 +546,10 @@
 				   struct drm_connector_state *state,
 				   struct drm_property *property,
 				   uint64_t val);
+	int (*atomic_get_property)(struct drm_connector *connector,
+				   const struct drm_connector_state *state,
+				   struct drm_property *property,
+				   uint64_t *val);
 };
 
 /**
@@ -693,6 +735,7 @@
 
 /**
  * struct drm_plane_state - mutable plane state
+ * @plane: backpointer to the plane
  * @crtc: currently bound CRTC, NULL if disabled
  * @fb: currently bound framebuffer
  * @fence: optional fence to wait for before scanning out @fb
@@ -709,6 +752,8 @@
  * @state: backpointer to global drm_atomic_state
  */
 struct drm_plane_state {
+	struct drm_plane *plane;
+
 	struct drm_crtc *crtc;   /* do not write directly, use drm_atomic_set_crtc_for_plane() */
 	struct drm_framebuffer *fb;  /* do not write directly, use drm_atomic_set_fb_for_plane() */
 	struct fence *fence;
@@ -721,6 +766,9 @@
 	uint32_t src_x, src_y;
 	uint32_t src_h, src_w;
 
+	/* Plane rotation */
+	unsigned int rotation;
+
 	struct drm_atomic_state *state;
 };
 
@@ -735,6 +783,9 @@
  * @atomic_duplicate_state: duplicate the atomic state for this plane
  * @atomic_destroy_state: destroy an atomic state for this plane
  * @atomic_set_property: set a property on an atomic state for this plane
+ *    (do not call directly, use drm_atomic_plane_set_property())
+ * @atomic_get_property: get a property on an atomic state for this plane
+ *    (do not call directly, use drm_atomic_plane_get_property())
  */
 struct drm_plane_funcs {
 	int (*update_plane)(struct drm_plane *plane,
@@ -758,6 +809,10 @@
 				   struct drm_plane_state *state,
 				   struct drm_property *property,
 				   uint64_t val);
+	int (*atomic_get_property)(struct drm_plane *plane,
+				   const struct drm_plane_state *state,
+				   struct drm_property *property,
+				   uint64_t *val);
 };
 
 enum drm_plane_type {
@@ -813,15 +868,16 @@
 
 /**
  * struct drm_bridge_funcs - drm_bridge control functions
+ * @attach: Called during drm_bridge_attach
  * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
  * @disable: Called right before encoder prepare, disables the bridge
  * @post_disable: Called right after encoder prepare, for lockstepped disable
  * @mode_set: Set this mode to the bridge
  * @pre_enable: Called right before encoder commit, for lockstepped commit
  * @enable: Called right after encoder commit, enables the bridge
- * @destroy: make object go away
  */
 struct drm_bridge_funcs {
+	int (*attach)(struct drm_bridge *bridge);
 	bool (*mode_fixup)(struct drm_bridge *bridge,
 			   const struct drm_display_mode *mode,
 			   struct drm_display_mode *adjusted_mode);
@@ -832,22 +888,24 @@
 			 struct drm_display_mode *adjusted_mode);
 	void (*pre_enable)(struct drm_bridge *bridge);
 	void (*enable)(struct drm_bridge *bridge);
-	void (*destroy)(struct drm_bridge *bridge);
 };
 
 /**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
- * @head: list management
+ * @of_node: device node pointer to the bridge
+ * @list: to keep track of all added bridges
  * @base: base mode object
  * @funcs: control functions
  * @driver_private: pointer to the bridge driver's internal context
  */
 struct drm_bridge {
 	struct drm_device *dev;
-	struct list_head head;
-
-	struct drm_mode_object base;
+	struct drm_encoder *encoder;
+#ifdef CONFIG_OF
+	struct device_node *of_node;
+#endif
+	struct list_head list;
 
 	const struct drm_bridge_funcs *funcs;
 	void *driver_private;
@@ -856,7 +914,8 @@
 /**
  * struct struct drm_atomic_state - the global state object for atomic updates
  * @dev: parent DRM device
- * @flags: state flags like async update
+ * @allow_modeset: allow full modeset
+ * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
  * @planes: pointer to array of plane pointers
  * @plane_states: pointer to array of plane states pointers
  * @crtcs: pointer to array of CRTC pointers
@@ -868,7 +927,8 @@
  */
 struct drm_atomic_state {
 	struct drm_device *dev;
-	uint32_t flags;
+	bool allow_modeset : 1;
+	bool legacy_cursor_update : 1;
 	struct drm_plane **planes;
 	struct drm_plane_state **plane_states;
 	struct drm_crtc **crtcs;
@@ -950,7 +1010,6 @@
 	uint32_t num_crtcs;
 	uint32_t num_encoders;
 	uint32_t num_connectors;
-	uint32_t num_bridges;
 
 	/* list of object IDs for this group */
 	uint32_t *id_list;
@@ -969,8 +1028,6 @@
  * @fb_list: list of framebuffers available
  * @num_connector: number of connectors on this device
  * @connector_list: list of connector objects
- * @num_bridge: number of bridges on this device
- * @bridge_list: list of bridge objects
  * @num_encoder: number of encoders on this device
  * @encoder_list: list of encoder objects
  * @num_overlay_plane: number of overlay planes on this device
@@ -1015,8 +1072,6 @@
 
 	int num_connector;
 	struct list_head connector_list;
-	int num_bridge;
-	struct list_head bridge_list;
 	int num_encoder;
 	struct list_head encoder_list;
 
@@ -1043,6 +1098,7 @@
 	/* output poll support */
 	bool poll_enabled;
 	bool poll_running;
+	bool delayed_event;
 	struct delayed_work output_poll_work;
 
 	/* pointers to standard properties */
@@ -1053,6 +1109,17 @@
 	struct drm_property *tile_property;
 	struct drm_property *plane_type_property;
 	struct drm_property *rotation_property;
+	struct drm_property *prop_src_x;
+	struct drm_property *prop_src_y;
+	struct drm_property *prop_src_w;
+	struct drm_property *prop_src_h;
+	struct drm_property *prop_crtc_x;
+	struct drm_property *prop_crtc_y;
+	struct drm_property *prop_crtc_w;
+	struct drm_property *prop_crtc_h;
+	struct drm_property *prop_fb_id;
+	struct drm_property *prop_crtc_id;
+	struct drm_property *prop_active;
 
 	/* DVI-I properties */
 	struct drm_property *dvi_i_subconnector_property;
@@ -1153,9 +1220,10 @@
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
-extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
-			   const struct drm_bridge_funcs *funcs);
-extern void drm_bridge_cleanup(struct drm_bridge *bridge);
+extern int drm_bridge_add(struct drm_bridge *bridge);
+extern void drm_bridge_remove(struct drm_bridge *bridge);
+extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
 
 extern int drm_encoder_init(struct drm_device *dev,
 			    struct drm_encoder *encoder,
@@ -1191,6 +1259,8 @@
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern unsigned int drm_plane_index(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
+extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
+				   int *hdisplay, int *vdisplay);
 extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 				   int x, int y,
 				   const struct drm_display_mode *mode,
@@ -1224,6 +1294,10 @@
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						   const struct edid *edid);
 
+extern int drm_display_info_set_bus_formats(struct drm_display_info *info,
+					    const u32 *formats,
+					    unsigned int num_formats);
+
 static inline bool drm_property_type_is(struct drm_property *property,
 		uint32_t type)
 {
@@ -1279,6 +1353,8 @@
 					 int64_t min, int64_t max);
 struct drm_property *drm_property_create_object(struct drm_device *dev,
 					 int flags, const char *name, uint32_t type);
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+					 const char *name);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern int drm_property_add_enum(struct drm_property *property, int index,
 				 uint64_t value, const char *name);
@@ -1290,6 +1366,10 @@
 extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
 extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
 extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
+extern bool drm_property_change_valid_get(struct drm_property *property,
+					 uint64_t value, struct drm_mode_object **ref);
+extern void drm_property_change_valid_put(struct drm_property *property,
+		struct drm_mode_object *ref);
 
 extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
 					     struct drm_encoder *encoder);
@@ -1381,6 +1461,8 @@
 extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 				       struct drm_property *property,
 				       uint64_t value);
+extern int drm_mode_atomic_ioctl(struct drm_device *dev,
+				 void *data, struct drm_file *file_priv);
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
 				 int *bpp);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 7adbb65..c250a22 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -39,17 +39,38 @@
 
 #include <linux/fb.h>
 
+#include <drm/drm_crtc.h>
+
 enum mode_set_atomic {
 	LEAVE_ATOMIC_MODE_SET,
 	ENTER_ATOMIC_MODE_SET,
 };
 
 /**
- * drm_crtc_helper_funcs - helper operations for CRTCs
- * @mode_fixup: try to fixup proposed mode for this connector
+ * struct drm_crtc_helper_funcs - helper operations for CRTCs
+ * @dpms: set power state
+ * @prepare: prepare the CRTC, called before @mode_set
+ * @commit: commit changes to CRTC, called after @mode_set
+ * @mode_fixup: try to fixup proposed mode for this CRTC
  * @mode_set: set this mode
+ * @mode_set_nofb: set mode only (no scanout buffer attached)
+ * @mode_set_base: update the scanout buffer
+ * @mode_set_base_atomic: non-blocking mode set (used for kgdb support)
+ * @load_lut: load color palette
+ * @disable: disable CRTC when no longer in use
+ * @enable: enable CRTC
+ * @atomic_check: check for validity of an atomic state
+ * @atomic_begin: begin atomic update
+ * @atomic_flush: flush atomic update
  *
  * The helper operations are called by the mid-layer CRTC helper.
+ *
+ * Note that with atomic helpers @dpms, @prepare and @commit hooks are
+ * deprecated. Used @enable and @disable instead exclusively.
+ *
+ * With legacy crtc helpers there's a big semantic difference between @disable
+ * and the other hooks: @disable also needs to release any resources acquired in
+ * @mode_set (like shared PLLs).
  */
 struct drm_crtc_helper_funcs {
 	/*
@@ -80,8 +101,8 @@
 	/* reload the current crtc LUT */
 	void (*load_lut)(struct drm_crtc *crtc);
 
-	/* disable crtc when not in use - more explicit than dpms off */
 	void (*disable)(struct drm_crtc *crtc);
+	void (*enable)(struct drm_crtc *crtc);
 
 	/* atomic helpers */
 	int (*atomic_check)(struct drm_crtc *crtc,
@@ -91,11 +112,28 @@
 };
 
 /**
- * drm_encoder_helper_funcs - helper operations for encoders
+ * struct drm_encoder_helper_funcs - helper operations for encoders
+ * @dpms: set power state
+ * @save: save connector state
+ * @restore: restore connector state
  * @mode_fixup: try to fixup proposed mode for this connector
+ * @prepare: part of the disable sequence, called before the CRTC modeset
+ * @commit: called after the CRTC modeset
  * @mode_set: set this mode
+ * @get_crtc: return CRTC that the encoder is currently attached to
+ * @detect: connection status detection
+ * @disable: disable encoder when not in use (overrides DPMS off)
+ * @enable: enable encoder
+ * @atomic_check: check for validity of an atomic update
  *
  * The helper operations are called by the mid-layer CRTC helper.
+ *
+ * Note that with atomic helpers @dpms, @prepare and @commit hooks are
+ * deprecated. Used @enable and @disable instead exclusively.
+ *
+ * With legacy crtc helpers there's a big semantic difference between @disable
+ * and the other hooks: @disable also needs to release any resources acquired in
+ * @mode_set (like shared PLLs).
  */
 struct drm_encoder_helper_funcs {
 	void (*dpms)(struct drm_encoder *encoder, int mode);
@@ -114,14 +152,21 @@
 	/* detect for DAC style encoders */
 	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
 					    struct drm_connector *connector);
-	/* disable encoder when not in use - more explicit than dpms off */
 	void (*disable)(struct drm_encoder *encoder);
+
+	void (*enable)(struct drm_encoder *encoder);
+
+	/* atomic helpers */
+	int (*atomic_check)(struct drm_encoder *encoder,
+			    struct drm_crtc_state *crtc_state,
+			    struct drm_connector_state *conn_state);
 };
 
 /**
- * drm_connector_helper_funcs - helper operations for connectors
+ * struct drm_connector_helper_funcs - helper operations for connectors
  * @get_modes: get mode list for this connector
- * @mode_valid (optional): is this mode valid on the given connector?
+ * @mode_valid: is this mode valid on the given connector? (optional)
+ * @best_encoder: return the preferred encoder for this connector
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 11f8c84..7e25030 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -586,6 +586,7 @@
 
 int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
 int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
+int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);
 int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
 
 int drm_dp_aux_register(struct drm_dp_aux *aux);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index b597068..21b944c 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -125,7 +125,7 @@
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
-bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
+int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
 int drm_fb_helper_debug_leave(struct fb_info *info);
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 91d0582..d92f6dd 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -90,6 +90,9 @@
 
 #define CRTC_INTERLACE_HALVE_V	(1 << 0) /* halve V values for interlacing */
 #define CRTC_STEREO_DOUBLE	(1 << 1) /* adjust timings for stereo modes */
+#define CRTC_NO_DBLSCAN		(1 << 2) /* don't adjust doublescan */
+#define CRTC_NO_VSCAN		(1 << 3) /* don't adjust doublescan */
+#define CRTC_STEREO_DOUBLE_ONLY	(CRTC_NO_DBLSCAN | CRTC_NO_VSCAN)
 
 #define DRM_MODE_FLAG_3D_MAX	DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
 
@@ -197,6 +200,8 @@
 					      int GTF_K, int GTF_2J);
 void drm_display_mode_from_videomode(const struct videomode *vm,
 				     struct drm_display_mode *dmode);
+void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
+				   struct videomode *vm);
 int of_get_drm_display_mode(struct device_node *np,
 			    struct drm_display_mode *dmode,
 			    int index);
@@ -217,9 +222,9 @@
 					const struct drm_display_mode *mode2);
 
 /* for use by the crtc helper probe functions */
-void drm_mode_validate_size(struct drm_device *dev,
-			    struct list_head *mode_list,
-			    int maxX, int maxY);
+enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode);
+enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode,
+					    int maxX, int maxY);
 void drm_mode_prune_invalid(struct drm_device *dev,
 			    struct list_head *mode_list, bool verbose);
 void drm_mode_sort(struct list_head *mode_list);
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
index a185392..31c11d3 100644
--- a/include/drm/drm_plane_helper.h
+++ b/include/drm/drm_plane_helper.h
@@ -52,7 +52,8 @@
  * @prepare_fb: prepare a framebuffer for use by the plane
  * @cleanup_fb: cleanup a framebuffer when it's no longer used by the plane
  * @atomic_check: check that a given atomic state is valid and can be applied
- * @atomic_update: apply an atomic state to the plane
+ * @atomic_update: apply an atomic state to the plane (mandatory)
+ * @atomic_disable: disable the plane
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
@@ -66,6 +67,8 @@
 			    struct drm_plane_state *state);
 	void (*atomic_update)(struct drm_plane *plane,
 			      struct drm_plane_state *old_state);
+	void (*atomic_disable)(struct drm_plane *plane,
+			       struct drm_plane_state *old_state);
 };
 
 static inline void drm_plane_helper_add(struct drm_plane *plane,
diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h
index 8dc0913..99da0d1 100644
--- a/include/dt-bindings/clock/exynos5420.h
+++ b/include/dt-bindings/clock/exynos5420.h
@@ -204,6 +204,12 @@
 #define CLK_MOUT_MAUDIO0	643
 #define CLK_MOUT_USER_ACLK333	644
 #define CLK_MOUT_SW_ACLK333	645
+#define CLK_MOUT_USER_ACLK200_DISP1	646
+#define CLK_MOUT_SW_ACLK200	647
+#define CLK_MOUT_USER_ACLK300_DISP1     648
+#define CLK_MOUT_SW_ACLK300     649
+#define CLK_MOUT_USER_ACLK400_DISP1     650
+#define CLK_MOUT_SW_ACLK400     651
 
 /* divider clocks */
 #define CLK_DOUT_PIXEL		768
diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h
index c27b3b5..9194027 100644
--- a/include/dt-bindings/clock/r8a7790-clock.h
+++ b/include/dt-bindings/clock/r8a7790-clock.h
@@ -97,6 +97,7 @@
 #define R8A7790_CLK_LVDS0		26
 
 /* MSTP8 */
+#define R8A7790_CLK_MLB			2
 #define R8A7790_CLK_VIN3		8
 #define R8A7790_CLK_VIN2		9
 #define R8A7790_CLK_VIN1		10
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index 3ea2bbc..f096f3f 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -91,6 +91,8 @@
 #define R8A7791_CLK_LVDS0		26
 
 /* MSTP8 */
+#define R8A7791_CLK_IPMMU_SGX		0
+#define R8A7791_CLK_MLB			2
 #define R8A7791_CLK_VIN2		9
 #define R8A7791_CLK_VIN1		10
 #define R8A7791_CLK_VIN0		11
diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h
index aa9c286e..d633230 100644
--- a/include/dt-bindings/clock/r8a7794-clock.h
+++ b/include/dt-bindings/clock/r8a7794-clock.h
@@ -48,15 +48,25 @@
 #define R8A7794_CLK_SCIFB1		7
 #define R8A7794_CLK_MSIOF1		8
 #define R8A7794_CLK_SCIFB2		16
+#define R8A7794_CLK_SYS_DMAC1		18
+#define R8A7794_CLK_SYS_DMAC0		19
 
 /* MSTP3 */
+#define R8A7794_CLK_SDHI2		11
+#define R8A7794_CLK_SDHI1		12
+#define R8A7794_CLK_SDHI0		14
+#define R8A7794_CLK_MMCIF0		15
 #define R8A7794_CLK_CMT1		29
+#define R8A7794_CLK_USBDMAC0		30
+#define R8A7794_CLK_USBDMAC1		31
 
 /* MSTP5 */
 #define R8A7794_CLK_THERMAL		22
 #define R8A7794_CLK_PWM			23
 
 /* MSTP7 */
+#define R8A7794_CLK_EHCI		3
+#define R8A7794_CLK_HSUSB		4
 #define R8A7794_CLK_HSCIF2		13
 #define R8A7794_CLK_SCIF5		14
 #define R8A7794_CLK_SCIF4		15
@@ -80,6 +90,13 @@
 #define R8A7794_CLK_GPIO2		10
 #define R8A7794_CLK_GPIO1		11
 #define R8A7794_CLK_GPIO0		12
+#define R8A7794_CLK_QSPI_MOD		17
+#define R8A7794_CLK_I2C5		25
+#define R8A7794_CLK_I2C4		27
+#define R8A7794_CLK_I2C3		28
+#define R8A7794_CLK_I2C2		29
+#define R8A7794_CLK_I2C1		30
+#define R8A7794_CLK_I2C0		31
 
 /* MSTP11 */
 #define R8A7794_CLK_SCIFA3		6
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
index 1c34c24..dea4197 100644
--- a/include/dt-bindings/clock/rk3288-cru.h
+++ b/include/dt-bindings/clock/rk3288-cru.h
@@ -80,6 +80,9 @@
 #define SCLK_SDIO0_SAMPLE	119
 #define SCLK_SDIO1_SAMPLE	120
 #define SCLK_EMMC_SAMPLE	121
+#define SCLK_USBPHY480M_SRC	122
+#define SCLK_PVTM_CORE		123
+#define SCLK_PVTM_GPU		124
 
 #define SCLK_MAC		151
 #define SCLK_MACREF_OUT		152
@@ -157,6 +160,7 @@
 #define PCLK_PUBL0		365
 #define PCLK_DDRUPCTL1		366
 #define PCLK_PUBL1		367
+#define PCLK_WDT		368
 
 /* hclk gates */
 #define HCLK_GPS		448
diff --git a/include/dt-bindings/clock/sh73a0-clock.h b/include/dt-bindings/clock/sh73a0-clock.h
new file mode 100644
index 0000000..1dd3eb2
--- /dev/null
+++ b/include/dt-bindings/clock/sh73a0-clock.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_SH73A0_H__
+#define __DT_BINDINGS_CLOCK_SH73A0_H__
+
+/* CPG */
+#define SH73A0_CLK_MAIN		0
+#define SH73A0_CLK_PLL0		1
+#define SH73A0_CLK_PLL1		2
+#define SH73A0_CLK_PLL2		3
+#define SH73A0_CLK_PLL3		4
+#define SH73A0_CLK_DSI0PHY	5
+#define SH73A0_CLK_DSI1PHY	6
+#define SH73A0_CLK_ZG		7
+#define SH73A0_CLK_M3		8
+#define SH73A0_CLK_B		9
+#define SH73A0_CLK_M1		10
+#define SH73A0_CLK_M2		11
+#define SH73A0_CLK_Z		12
+#define SH73A0_CLK_ZX		13
+#define SH73A0_CLK_HP		14
+
+/* MSTP0 */
+#define SH73A0_CLK_IIC2	1
+
+/* MSTP1 */
+#define SH73A0_CLK_CEU1		29
+#define SH73A0_CLK_CSI2_RX1	28
+#define SH73A0_CLK_CEU0		27
+#define SH73A0_CLK_CSI2_RX0	26
+#define SH73A0_CLK_TMU0		25
+#define SH73A0_CLK_DSITX0	18
+#define SH73A0_CLK_IIC0		16
+#define SH73A0_CLK_SGX		12
+#define SH73A0_CLK_LCDC0	0
+
+/* MSTP2 */
+#define SH73A0_CLK_SCIFA7	19
+#define SH73A0_CLK_SY_DMAC	18
+#define SH73A0_CLK_MP_DMAC	17
+#define SH73A0_CLK_SCIFA5	7
+#define SH73A0_CLK_SCIFB	6
+#define SH73A0_CLK_SCIFA0	4
+#define SH73A0_CLK_SCIFA1	3
+#define SH73A0_CLK_SCIFA2	2
+#define SH73A0_CLK_SCIFA3	1
+#define SH73A0_CLK_SCIFA4	0
+
+/* MSTP3 */
+#define SH73A0_CLK_SCIFA6	31
+#define SH73A0_CLK_CMT1		29
+#define SH73A0_CLK_FSI		28
+#define SH73A0_CLK_IRDA		25
+#define SH73A0_CLK_IIC1		23
+#define SH73A0_CLK_USB		22
+#define SH73A0_CLK_FLCTL	15
+#define SH73A0_CLK_SDHI0	14
+#define SH73A0_CLK_SDHI1	13
+#define SH73A0_CLK_MMCIF0	12
+#define SH73A0_CLK_SDHI2	11
+#define SH73A0_CLK_TPU0		4
+#define SH73A0_CLK_TPU1		3
+#define SH73A0_CLK_TPU2		2
+#define SH73A0_CLK_TPU3		1
+#define SH73A0_CLK_TPU4		0
+
+/* MSTP4 */
+#define SH73A0_CLK_IIC3		11
+#define SH73A0_CLK_IIC4		10
+#define SH73A0_CLK_KEYSC	3
+
+#endif
diff --git a/include/dt-bindings/clock/stih418-clks.h b/include/dt-bindings/clock/stih418-clks.h
new file mode 100644
index 0000000..b62aa0b
--- /dev/null
+++ b/include/dt-bindings/clock/stih418-clks.h
@@ -0,0 +1,34 @@
+/*
+ * This header provides constants clk index STMicroelectronics
+ * STiH418 SoC.
+ */
+#ifndef _DT_BINDINGS_CLK_STIH418
+#define _DT_BINDINGS_CLK_STIH418
+
+#include "stih410-clks.h"
+
+/* STiH418 introduces new clock outputs compared to STiH410 */
+
+/* CLOCKGEN C0 */
+#define CLK_PROC_BDISP_0        14
+#define CLK_PROC_BDISP_1        15
+#define CLK_TX_ICN_1            23
+#define CLK_ETH_PHYREF          27
+#define CLK_PP_HEVC             35
+#define CLK_CLUST_HEVC          36
+#define CLK_HWPE_HEVC           37
+#define CLK_FC_HEVC             38
+#define CLK_PROC_MIXER		39
+#define CLK_PROC_SC		40
+#define CLK_AVSP_HEVC		41
+
+/* CLOCKGEN D2 */
+#undef CLK_PIX_PIP
+#undef CLK_PIX_GDP1
+#undef CLK_PIX_GDP2
+#undef CLK_PIX_GDP3
+#undef CLK_PIX_GDP4
+
+#define CLK_TMDS_HDMI_DIV2	5
+#define CLK_VP9			47
+#endif
diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h
index 801c0ac..979d24a 100644
--- a/include/dt-bindings/clock/vf610-clock.h
+++ b/include/dt-bindings/clock/vf610-clock.h
@@ -192,6 +192,7 @@
 #define VF610_PLL5_BYPASS		179
 #define VF610_PLL6_BYPASS		180
 #define VF610_PLL7_BYPASS		181
-#define VF610_CLK_END			182
+#define VF610_CLK_SNVS			182
+#define VF610_CLK_END			183
 
 #endif /* __DT_BINDINGS_CLOCK_VF610_H */
diff --git a/include/dt-bindings/dma/sun4i-a10.h b/include/dt-bindings/dma/sun4i-a10.h
new file mode 100644
index 0000000..8caba9e
--- /dev/null
+++ b/include/dt-bindings/dma/sun4i-a10.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+#ifndef __DT_BINDINGS_DMA_SUN4I_A10_H_
+#define __DT_BINDINGS_DMA_SUN4I_A10_H_
+
+#define SUN4I_DMA_NORMAL	0
+#define SUN4I_DMA_DEDICATED	1
+
+#endif /* __DT_BINDINGS_DMA_SUN4I_A10_H_ */
diff --git a/include/dt-bindings/iio/qcom,spmi-vadc.h b/include/dt-bindings/iio/qcom,spmi-vadc.h
new file mode 100644
index 0000000..42121fa
--- /dev/null
+++ b/include/dt-bindings/iio/qcom,spmi-vadc.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012-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 _DT_BINDINGS_QCOM_SPMI_VADC_H
+#define _DT_BINDINGS_QCOM_SPMI_VADC_H
+
+/* Voltage ADC channels */
+#define VADC_USBIN				0x00
+#define VADC_DCIN				0x01
+#define VADC_VCHG_SNS				0x02
+#define VADC_SPARE1_03				0x03
+#define VADC_USB_ID_MV				0x04
+#define VADC_VCOIN				0x05
+#define VADC_VBAT_SNS				0x06
+#define VADC_VSYS				0x07
+#define VADC_DIE_TEMP				0x08
+#define VADC_REF_625MV				0x09
+#define VADC_REF_1250MV				0x0a
+#define VADC_CHG_TEMP				0x0b
+#define VADC_SPARE1				0x0c
+#define VADC_SPARE2				0x0d
+#define VADC_GND_REF				0x0e
+#define VADC_VDD_VADC				0x0f
+
+#define VADC_P_MUX1_1_1				0x10
+#define VADC_P_MUX2_1_1				0x11
+#define VADC_P_MUX3_1_1				0x12
+#define VADC_P_MUX4_1_1				0x13
+#define VADC_P_MUX5_1_1				0x14
+#define VADC_P_MUX6_1_1				0x15
+#define VADC_P_MUX7_1_1				0x16
+#define VADC_P_MUX8_1_1				0x17
+#define VADC_P_MUX9_1_1				0x18
+#define VADC_P_MUX10_1_1			0x19
+#define VADC_P_MUX11_1_1			0x1a
+#define VADC_P_MUX12_1_1			0x1b
+#define VADC_P_MUX13_1_1			0x1c
+#define VADC_P_MUX14_1_1			0x1d
+#define VADC_P_MUX15_1_1			0x1e
+#define VADC_P_MUX16_1_1			0x1f
+
+#define VADC_P_MUX1_1_3				0x20
+#define VADC_P_MUX2_1_3				0x21
+#define VADC_P_MUX3_1_3				0x22
+#define VADC_P_MUX4_1_3				0x23
+#define VADC_P_MUX5_1_3				0x24
+#define VADC_P_MUX6_1_3				0x25
+#define VADC_P_MUX7_1_3				0x26
+#define VADC_P_MUX8_1_3				0x27
+#define VADC_P_MUX9_1_3				0x28
+#define VADC_P_MUX10_1_3			0x29
+#define VADC_P_MUX11_1_3			0x2a
+#define VADC_P_MUX12_1_3			0x2b
+#define VADC_P_MUX13_1_3			0x2c
+#define VADC_P_MUX14_1_3			0x2d
+#define VADC_P_MUX15_1_3			0x2e
+#define VADC_P_MUX16_1_3			0x2f
+
+#define VADC_LR_MUX1_BAT_THERM			0x30
+#define VADC_LR_MUX2_BAT_ID			0x31
+#define VADC_LR_MUX3_XO_THERM			0x32
+#define VADC_LR_MUX4_AMUX_THM1			0x33
+#define VADC_LR_MUX5_AMUX_THM2			0x34
+#define VADC_LR_MUX6_AMUX_THM3			0x35
+#define VADC_LR_MUX7_HW_ID			0x36
+#define VADC_LR_MUX8_AMUX_THM4			0x37
+#define VADC_LR_MUX9_AMUX_THM5			0x38
+#define VADC_LR_MUX10_USB_ID			0x39
+#define VADC_AMUX_PU1				0x3a
+#define VADC_AMUX_PU2				0x3b
+#define VADC_LR_MUX3_BUF_XO_THERM		0x3c
+
+#define VADC_LR_MUX1_PU1_BAT_THERM		0x70
+#define VADC_LR_MUX2_PU1_BAT_ID			0x71
+#define VADC_LR_MUX3_PU1_XO_THERM		0x72
+#define VADC_LR_MUX4_PU1_AMUX_THM1		0x73
+#define VADC_LR_MUX5_PU1_AMUX_THM2		0x74
+#define VADC_LR_MUX6_PU1_AMUX_THM3		0x75
+#define VADC_LR_MUX7_PU1_AMUX_HW_ID		0x76
+#define VADC_LR_MUX8_PU1_AMUX_THM4		0x77
+#define VADC_LR_MUX9_PU1_AMUX_THM5		0x78
+#define VADC_LR_MUX10_PU1_AMUX_USB_ID		0x79
+#define VADC_LR_MUX3_BUF_PU1_XO_THERM		0x7c
+
+#define VADC_LR_MUX1_PU2_BAT_THERM		0xb0
+#define VADC_LR_MUX2_PU2_BAT_ID			0xb1
+#define VADC_LR_MUX3_PU2_XO_THERM		0xb2
+#define VADC_LR_MUX4_PU2_AMUX_THM1		0xb3
+#define VADC_LR_MUX5_PU2_AMUX_THM2		0xb4
+#define VADC_LR_MUX6_PU2_AMUX_THM3		0xb5
+#define VADC_LR_MUX7_PU2_AMUX_HW_ID		0xb6
+#define VADC_LR_MUX8_PU2_AMUX_THM4		0xb7
+#define VADC_LR_MUX9_PU2_AMUX_THM5		0xb8
+#define VADC_LR_MUX10_PU2_AMUX_USB_ID		0xb9
+#define VADC_LR_MUX3_BUF_PU2_XO_THERM		0xbc
+
+#define VADC_LR_MUX1_PU1_PU2_BAT_THERM		0xf0
+#define VADC_LR_MUX2_PU1_PU2_BAT_ID		0xf1
+#define VADC_LR_MUX3_PU1_PU2_XO_THERM		0xf2
+#define VADC_LR_MUX4_PU1_PU2_AMUX_THM1		0xf3
+#define VADC_LR_MUX5_PU1_PU2_AMUX_THM2		0xf4
+#define VADC_LR_MUX6_PU1_PU2_AMUX_THM3		0xf5
+#define VADC_LR_MUX7_PU1_PU2_AMUX_HW_ID		0xf6
+#define VADC_LR_MUX8_PU1_PU2_AMUX_THM4		0xf7
+#define VADC_LR_MUX9_PU1_PU2_AMUX_THM5		0xf8
+#define VADC_LR_MUX10_PU1_PU2_AMUX_USB_ID	0xf9
+#define VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM	0xfc
+
+#endif /* _DT_BINDINGS_QCOM_SPMI_VADC_H */
diff --git a/include/dt-bindings/pinctrl/omap.h b/include/dt-bindings/pinctrl/omap.h
index 1c75b8c..1394925 100644
--- a/include/dt-bindings/pinctrl/omap.h
+++ b/include/dt-bindings/pinctrl/omap.h
@@ -61,6 +61,7 @@
 #define OMAP3430_CORE2_IOPAD(pa, val)	OMAP_IOPAD_OFFSET((pa), 0x25d8) (val)
 #define OMAP3630_CORE2_IOPAD(pa, val)	OMAP_IOPAD_OFFSET((pa), 0x25a0) (val)
 #define OMAP3_WKUP_IOPAD(pa, val)	OMAP_IOPAD_OFFSET((pa), 0x2a00) (val)
+#define DM816X_IOPAD(pa, val)		OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
 #define AM33XX_IOPAD(pa, val)		OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
 #define AM4372_IOPAD(pa, val)		OMAP_IOPAD_OFFSET((pa), 0x0800) (val)
 #define DRA7XX_CORE_IOPAD(pa, val)	OMAP_IOPAD_OFFSET((pa), 0x3400) (val)
diff --git a/include/dt-bindings/pinctrl/sun4i-a10.h b/include/dt-bindings/pinctrl/sun4i-a10.h
new file mode 100644
index 0000000..f7553c1
--- /dev/null
+++ b/include/dt-bindings/pinctrl/sun4i-a10.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2014 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@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.
+ *
+ *     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., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * 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.
+ */
+
+#ifndef __DT_BINDINGS_PINCTRL_SUN4I_A10_H_
+#define __DT_BINDINGS_PINCTRL_SUN4I_A10_H_
+
+#define SUN4I_PINCTRL_10_MA	0
+#define SUN4I_PINCTRL_20_MA	1
+#define SUN4I_PINCTRL_30_MA	2
+#define SUN4I_PINCTRL_40_MA	3
+
+#define SUN4I_PINCTRL_NO_PULL	0
+#define SUN4I_PINCTRL_PULL_UP	1
+#define SUN4I_PINCTRL_PULL_DOWN	2
+
+#endif /* __DT_BINDINGS_PINCTRL_SUN4I_A10_H_ */
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 5f5c00d..dbfbf49 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -52,16 +52,13 @@
  * bitmap_bitremap(oldbit, old, new, nbits)	newbit = map(old, new)(oldbit)
  * bitmap_onto(dst, orig, relmap, nbits)	*dst = orig relative to relmap
  * bitmap_fold(dst, orig, sz, nbits)		dst bits = orig bits mod sz
- * bitmap_scnprintf(buf, len, src, nbits)	Print bitmap src to buf
  * bitmap_parse(buf, buflen, dst, nbits)	Parse bitmap dst from kernel buf
  * bitmap_parse_user(ubuf, ulen, dst, nbits)	Parse bitmap dst from user buf
- * bitmap_scnlistprintf(buf, len, src, nbits)	Print bitmap src as list to buf
  * bitmap_parselist(buf, dst, nbits)		Parse bitmap dst from kernel buf
  * bitmap_parselist_user(buf, dst, nbits)	Parse bitmap dst from user buf
  * bitmap_find_free_region(bitmap, bits, order)	Find and allocate bit region
  * bitmap_release_region(bitmap, pos, order)	Free specified bit region
  * bitmap_allocate_region(bitmap, pos, order)	Allocate specified bit region
- * bitmap_print_to_pagebuf(list, buf, mask, nbits) Print bitmap src as list/hex
  */
 
 /*
@@ -96,10 +93,10 @@
 			  const unsigned long *bitmap2, unsigned int nbits);
 extern void __bitmap_complement(unsigned long *dst, const unsigned long *src,
 			unsigned int nbits);
-extern void __bitmap_shift_right(unsigned long *dst,
-                        const unsigned long *src, int shift, int bits);
-extern void __bitmap_shift_left(unsigned long *dst,
-                        const unsigned long *src, int shift, int bits);
+extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
+				unsigned int shift, unsigned int nbits);
+extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
+				unsigned int shift, unsigned int nbits);
 extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
 			const unsigned long *bitmap2, unsigned int nbits);
 extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
@@ -147,14 +144,10 @@
 					      align_mask, 0);
 }
 
-extern int bitmap_scnprintf(char *buf, unsigned int len,
-			const unsigned long *src, int nbits);
 extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
 			unsigned long *dst, int nbits);
 extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
 			unsigned long *dst, int nbits);
-extern int bitmap_scnlistprintf(char *buf, unsigned int len,
-			const unsigned long *src, int nbits);
 extern int bitmap_parselist(const char *buf, unsigned long *maskp,
 			int nmaskbits);
 extern int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen,
@@ -170,7 +163,11 @@
 extern int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order);
-extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits);
+#ifdef __BIG_ENDIAN
+extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
+#else
+#define bitmap_copy_le bitmap_copy
+#endif
 extern unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits);
 extern int bitmap_print_to_pagebuf(bool list, char *buf,
 				   const unsigned long *maskp, int nmaskbits);
@@ -309,22 +306,22 @@
 	return __bitmap_weight(src, nbits);
 }
 
-static inline void bitmap_shift_right(unsigned long *dst,
-			const unsigned long *src, int n, int nbits)
+static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *src,
+				unsigned int shift, int nbits)
 {
 	if (small_const_nbits(nbits))
-		*dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> n;
+		*dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> shift;
 	else
-		__bitmap_shift_right(dst, src, n, nbits);
+		__bitmap_shift_right(dst, src, shift, nbits);
 }
 
-static inline void bitmap_shift_left(unsigned long *dst,
-			const unsigned long *src, int n, int nbits)
+static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *src,
+				unsigned int shift, unsigned int nbits)
 {
 	if (small_const_nbits(nbits))
-		*dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits);
+		*dst = (*src << shift) & BITMAP_LAST_WORD_MASK(nbits);
 	else
-		__bitmap_shift_left(dst, src, n, nbits);
+		__bitmap_shift_left(dst, src, shift, nbits);
 }
 
 static inline int bitmap_parse(const char *buf, unsigned int buflen,
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 02ae99e..cdf13ca 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -66,6 +66,7 @@
 #define __deprecated			__attribute__((deprecated))
 #define __packed			__attribute__((packed))
 #define __weak				__attribute__((weak))
+#define __alias(symbol)		__attribute__((alias(#symbol)))
 
 /*
  * it doesn't make sense on ARM (currently the only user of __naked) to trace
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index d1a5582..769e198 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -85,3 +85,7 @@
 #define __HAVE_BUILTIN_BSWAP16__
 #endif
 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
+
+#if GCC_VERSION >= 40902
+#define KASAN_ABI_VERSION 3
+#endif
diff --git a/include/linux/compiler-gcc5.h b/include/linux/compiler-gcc5.h
index c8c5659..efee493 100644
--- a/include/linux/compiler-gcc5.h
+++ b/include/linux/compiler-gcc5.h
@@ -63,3 +63,5 @@
 #define __HAVE_BUILTIN_BSWAP64__
 #define __HAVE_BUILTIN_BSWAP16__
 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
+
+#define KASAN_ABI_VERSION 4
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 17f624c..d1ec10a 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -451,12 +451,23 @@
  * to make the compiler aware of ordering is to put the two invocations of
  * ACCESS_ONCE() in different C statements.
  *
- * This macro does absolutely -nothing- to prevent the CPU from reordering,
- * merging, or refetching absolutely anything at any time.  Its main intended
- * use is to mediate communication between process-level code and irq/NMI
- * handlers, all running on the same CPU.
+ * ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE
+ * on a union member will work as long as the size of the member matches the
+ * size of the union and the size is smaller than word size.
+ *
+ * The major use cases of ACCESS_ONCE used to be (1) Mediating communication
+ * between process-level code and irq/NMI handlers, all running on the same CPU,
+ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
+ * mutilate accesses that either do not require ordering or that interact
+ * with an explicit memory barrier or atomic instruction that provides the
+ * required ordering.
+ *
+ * If possible use READ_ONCE/ASSIGN_ONCE instead.
  */
-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#define __ACCESS_ONCE(x) ({ \
+	 __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \
+	(volatile typeof(x) *)&(x); })
+#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
 
 /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */
 #ifdef CONFIG_KPROBES
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 5d3c543..3486b908 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -179,15 +179,6 @@
 #define sink_ops(csdev)		csdev->ops->sink_ops
 #define link_ops(csdev)		csdev->ops->link_ops
 
-#define CORESIGHT_DEBUGFS_ENTRY(__name, __entry_name,			\
-				 __mode, __get, __set, __fmt)		\
-DEFINE_SIMPLE_ATTRIBUTE(__name ## _ops, __get, __set, __fmt);		\
-static const struct coresight_ops_entry __name ## _entry = {		\
-	.name = __entry_name,						\
-	.mode = __mode,							\
-	.ops  = &__name ## _ops						\
-}
-
 /**
  * struct coresight_ops_sink - basic operations for a sink
  * Operations available for sinks
@@ -236,13 +227,8 @@
 extern void coresight_unregister(struct coresight_device *csdev);
 extern int coresight_enable(struct coresight_device *csdev);
 extern void coresight_disable(struct coresight_device *csdev);
-extern int coresight_is_bit_set(u32 val, int position, int value);
 extern int coresight_timeout(void __iomem *addr, u32 offset,
 			     int position, int value);
-#ifdef CONFIG_OF
-extern struct coresight_platform_data *of_get_coresight_platform_data(
-				struct device *dev, struct device_node *node);
-#endif
 #else
 static inline struct coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -250,14 +236,16 @@
 static inline int
 coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
 static inline void coresight_disable(struct coresight_device *csdev) {}
-static inline int coresight_is_bit_set(u32 val, int position, int value)
-					 { return 0; }
 static inline int coresight_timeout(void __iomem *addr, u32 offset,
 				     int position, int value) { return 1; }
+#endif
+
 #ifdef CONFIG_OF
+extern struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node);
+#else
 static inline struct coresight_platform_data *of_get_coresight_platform_data(
 	struct device *dev, struct device_node *node) { return NULL; }
 #endif
-#endif
 
 #endif
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index ff90442..086549a 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -22,6 +22,14 @@
  */
 #define cpumask_bits(maskp) ((maskp)->bits)
 
+/**
+ * cpumask_pr_args - printf args to output a cpumask
+ * @maskp: cpumask to be printed
+ *
+ * Can be used to provide arguments for '%*pb[l]' when printing a cpumask.
+ */
+#define cpumask_pr_args(maskp)		nr_cpu_ids, cpumask_bits(maskp)
+
 #if NR_CPUS == 1
 #define nr_cpu_ids		1
 #else
@@ -539,21 +547,6 @@
 #define cpumask_of(cpu) (get_cpu_mask(cpu))
 
 /**
- * cpumask_scnprintf - print a cpumask into a string as comma-separated hex
- * @buf: the buffer to sprintf into
- * @len: the length of the buffer
- * @srcp: the cpumask to print
- *
- * If len is zero, returns zero.  Otherwise returns the length of the
- * (nul-terminated) @buf string.
- */
-static inline int cpumask_scnprintf(char *buf, int len,
-				    const struct cpumask *srcp)
-{
-	return bitmap_scnprintf(buf, len, cpumask_bits(srcp), nr_cpumask_bits);
-}
-
-/**
  * cpumask_parse_user - extract a cpumask from a user string
  * @buf: the buffer to extract from
  * @len: the length of the buffer
@@ -564,7 +557,7 @@
 static inline int cpumask_parse_user(const char __user *buf, int len,
 				     struct cpumask *dstp)
 {
-	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
+	return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpu_ids);
 }
 
 /**
@@ -579,23 +572,7 @@
 				     struct cpumask *dstp)
 {
 	return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
-							nr_cpumask_bits);
-}
-
-/**
- * cpulist_scnprintf - print a cpumask into a string as comma-separated list
- * @buf: the buffer to sprintf into
- * @len: the length of the buffer
- * @srcp: the cpumask to print
- *
- * If len is zero, returns zero.  Otherwise returns the length of the
- * (nul-terminated) @buf string.
- */
-static inline int cpulist_scnprintf(char *buf, int len,
-				    const struct cpumask *srcp)
-{
-	return bitmap_scnlistprintf(buf, len, cpumask_bits(srcp),
-				    nr_cpumask_bits);
+				     nr_cpu_ids);
 }
 
 /**
@@ -610,7 +587,7 @@
 	char *nl = strchr(buf, '\n');
 	unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf);
 
-	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
+	return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpu_ids);
 }
 
 /**
@@ -622,7 +599,7 @@
  */
 static inline int cpulist_parse(const char *buf, struct cpumask *dstp)
 {
-	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpumask_bits);
+	return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpu_ids);
 }
 
 /**
@@ -817,7 +794,7 @@
 cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask)
 {
 	return bitmap_print_to_pagebuf(list, buf, cpumask_bits(mask),
-				      nr_cpumask_bits);
+				      nr_cpu_ids);
 }
 
 /*
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 9c8776d..fb5ef16 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -1147,7 +1147,7 @@
  * cipher operation completes.
  *
  * The callback function is registered with the ablkcipher_request handle and
- * must comply with the following template:
+ * must comply with the following template
  *
  *	void callback_function(struct crypto_async_request *req, int error)
  */
@@ -1174,7 +1174,7 @@
  *
  * For encryption, the source is treated as the plaintext and the
  * destination is the ciphertext. For a decryption operation, the use is
- * reversed: the source is the ciphertext and the destination is the plaintext.
+ * reversed - the source is the ciphertext and the destination is the plaintext.
  */
 static inline void ablkcipher_request_set_crypt(
 	struct ablkcipher_request *req,
@@ -1412,6 +1412,9 @@
  */
 static inline int crypto_aead_decrypt(struct aead_request *req)
 {
+	if (req->cryptlen < crypto_aead_authsize(crypto_aead_reqtfm(req)))
+		return -EINVAL;
+
 	return crypto_aead_crt(crypto_aead_reqtfm(req))->decrypt(req);
 }
 
@@ -1506,7 +1509,7 @@
  * completes
  *
  * The callback function is registered with the aead_request handle and
- * must comply with the following template:
+ * must comply with the following template
  *
  *	void callback_function(struct crypto_async_request *req, int error)
  */
@@ -1533,7 +1536,7 @@
  *
  * For encryption, the source is treated as the plaintext and the
  * destination is the ciphertext. For a decryption operation, the use is
- * reversed: the source is the ciphertext and the destination is the plaintext.
+ * reversed - the source is the ciphertext and the destination is the plaintext.
  *
  * IMPORTANT NOTE AEAD requires an authentication tag (MAC). For decryption,
  *		  the caller must concatenate the ciphertext followed by the
diff --git a/include/linux/device.h b/include/linux/device.h
index fb50673..0eb8ee2 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1038,22 +1038,22 @@
 int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...);
 
 extern __printf(3, 4)
-int dev_printk(const char *level, const struct device *dev,
-	       const char *fmt, ...);
+void dev_printk(const char *level, const struct device *dev,
+		const char *fmt, ...);
 extern __printf(2, 3)
-int dev_emerg(const struct device *dev, const char *fmt, ...);
+void dev_emerg(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int dev_alert(const struct device *dev, const char *fmt, ...);
+void dev_alert(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int dev_crit(const struct device *dev, const char *fmt, ...);
+void dev_crit(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int dev_err(const struct device *dev, const char *fmt, ...);
+void dev_err(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int dev_warn(const struct device *dev, const char *fmt, ...);
+void dev_warn(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int dev_notice(const struct device *dev, const char *fmt, ...);
+void dev_notice(const struct device *dev, const char *fmt, ...);
 extern __printf(2, 3)
-int _dev_info(const struct device *dev, const char *fmt, ...);
+void _dev_info(const struct device *dev, const char *fmt, ...);
 
 #else
 
@@ -1065,35 +1065,35 @@
 int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
 { return 0; }
 
-static inline int __dev_printk(const char *level, const struct device *dev,
-			       struct va_format *vaf)
-{ return 0; }
+static inline void __dev_printk(const char *level, const struct device *dev,
+				struct va_format *vaf)
+{}
 static inline __printf(3, 4)
-int dev_printk(const char *level, const struct device *dev,
-	       const char *fmt, ...)
-{ return 0; }
+void dev_printk(const char *level, const struct device *dev,
+		const char *fmt, ...)
+{}
 
 static inline __printf(2, 3)
-int dev_emerg(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_emerg(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int dev_crit(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_crit(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int dev_alert(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_alert(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int dev_err(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_err(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int dev_warn(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_warn(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int dev_notice(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void dev_notice(const struct device *dev, const char *fmt, ...)
+{}
 static inline __printf(2, 3)
-int _dev_info(const struct device *dev, const char *fmt, ...)
-{ return 0; }
+void _dev_info(const struct device *dev, const char *fmt, ...)
+{}
 
 #endif
 
@@ -1119,7 +1119,6 @@
 ({								\
 	if (0)							\
 		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
-	0;							\
 })
 #endif
 
@@ -1156,7 +1155,7 @@
 #define dev_info_once(dev, fmt, ...)					\
 	dev_level_once(dev_info, dev, fmt, ##__VA_ARGS__)
 #define dev_dbg_once(dev, fmt, ...)					\
-	dev_level_once(dev_info, dev, fmt, ##__VA_ARGS__)
+	dev_level_once(dev_dbg, dev, fmt, ##__VA_ARGS__)
 
 #define dev_level_ratelimited(dev_level, dev, fmt, ...)			\
 do {									\
@@ -1215,7 +1214,6 @@
 ({								\
 	if (0)							\
 		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
-	0;							\
 })
 #endif
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e49f10c..ed5a090 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -51,6 +51,7 @@
 struct seq_file;
 struct workqueue_struct;
 struct iov_iter;
+struct vm_fault;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -361,8 +362,6 @@
 	int (*releasepage) (struct page *, gfp_t);
 	void (*freepage)(struct page *);
 	ssize_t (*direct_IO)(int, struct kiocb *, struct iov_iter *iter, loff_t offset);
-	int (*get_xip_mem)(struct address_space *, pgoff_t, int,
-						void **, unsigned long *);
 	/*
 	 * migrate the contents of a page to the specified target. If
 	 * migrate_mode is MIGRATE_ASYNC, it must not block.
@@ -1677,6 +1676,11 @@
 #define S_IMA		1024	/* Inode has an associated IMA struct */
 #define S_AUTOMOUNT	2048	/* Automount/referral quasi-directory */
 #define S_NOSEC		4096	/* no suid or xattr security attributes */
+#ifdef CONFIG_FS_DAX
+#define S_DAX		8192	/* Direct Access, avoiding the page cache */
+#else
+#define S_DAX		0	/* Make all the DAX code disappear */
+#endif
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -1714,6 +1718,7 @@
 #define IS_IMA(inode)		((inode)->i_flags & S_IMA)
 #define IS_AUTOMOUNT(inode)	((inode)->i_flags & S_AUTOMOUNT)
 #define IS_NOSEC(inode)		((inode)->i_flags & S_NOSEC)
+#define IS_DAX(inode)		((inode)->i_flags & S_DAX)
 
 #define IS_WHITEOUT(inode)	(S_ISCHR(inode->i_mode) && \
 				 (inode)->i_rdev == WHITEOUT_DEV)
@@ -2581,19 +2586,13 @@
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
 
-#ifdef CONFIG_FS_XIP
-extern ssize_t xip_file_read(struct file *filp, char __user *buf, size_t len,
-			     loff_t *ppos);
-extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma);
-extern ssize_t xip_file_write(struct file *filp, const char __user *buf,
-			      size_t len, loff_t *ppos);
-extern int xip_truncate_page(struct address_space *mapping, loff_t from);
-#else
-static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
-{
-	return 0;
-}
-#endif
+ssize_t dax_do_io(int rw, struct kiocb *, struct inode *, struct iov_iter *,
+		loff_t, get_block_t, dio_iodone_t, int flags);
+int dax_clear_blocks(struct inode *, sector_t block, long size);
+int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t);
+int dax_truncate_page(struct inode *, loff_t from, get_block_t);
+int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t);
+#define dax_mkwrite(vma, vmf, gb)	dax_fault(vma, vmf, gb)
 
 #ifdef CONFIG_BLOCK
 typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
@@ -2750,6 +2749,11 @@
 extern void save_mount_options(struct super_block *sb, char *options);
 extern void replace_mount_options(struct super_block *sb, char *options);
 
+static inline bool io_is_direct(struct file *filp)
+{
+	return (filp->f_flags & O_DIRECT) || IS_DAX(file_inode(filp));
+}
+
 static inline ino_t parent_ino(struct dentry *dentry)
 {
 	ino_t res;
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index bb9840f..464f338 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -250,17 +250,29 @@
 struct host1x_device;
 
 struct host1x_driver {
+	struct device_driver driver;
+
 	const struct of_device_id *subdevs;
 	struct list_head list;
-	const char *name;
 
 	int (*probe)(struct host1x_device *device);
 	int (*remove)(struct host1x_device *device);
+	void (*shutdown)(struct host1x_device *device);
 };
 
-int host1x_driver_register(struct host1x_driver *driver);
+static inline struct host1x_driver *
+to_host1x_driver(struct device_driver *driver)
+{
+	return container_of(driver, struct host1x_driver, driver);
+}
+
+int host1x_driver_register_full(struct host1x_driver *driver,
+				struct module *owner);
 void host1x_driver_unregister(struct host1x_driver *driver);
 
+#define host1x_driver_register(driver) \
+	host1x_driver_register_full(driver, THIS_MODULE)
+
 struct host1x_device {
 	struct host1x_driver *driver;
 	struct list_head list;
@@ -272,6 +284,8 @@
 
 	struct mutex clients_lock;
 	struct list_head clients;
+
+	bool registered;
 };
 
 static inline struct host1x_device *to_host1x_device(struct device *dev)
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 914bb08..eb7b414 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -12,8 +12,10 @@
 #ifndef LINUX_HWRANDOM_H_
 #define LINUX_HWRANDOM_H_
 
+#include <linux/completion.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/kref.h>
 
 /**
  * struct hwrng - Hardware Random Number Generator driver
@@ -44,6 +46,8 @@
 
 	/* internal. */
 	struct list_head list;
+	struct kref ref;
+	struct completion cleanup_done;
 };
 
 /** Register a new Hardware Random Number Generator driver. */
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 476c685..5a2ba67 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -57,6 +57,18 @@
 	u64 pfn_array[MAX_MULTIPAGE_BUFFER_COUNT];
 };
 
+/*
+ * Multiple-page buffer array; the pfn array is variable size:
+ * The number of entries in the PFN array is determined by
+ * "len" and "offset".
+ */
+struct hv_mpb_array {
+	/* Length and Offset determines the # of pfns in the array */
+	u32 len;
+	u32 offset;
+	u64 pfn_array[];
+};
+
 /* 0x18 includes the proprietary packet header */
 #define MAX_PAGE_BUFFER_PACKET		(0x18 +			\
 					(sizeof(struct hv_page_buffer) * \
@@ -722,7 +734,12 @@
 	 */
 	void (*sc_creation_callback)(struct vmbus_channel *new_sc);
 
-	spinlock_t sc_lock;
+	/*
+	 * The spinlock to protect the structure. It is being used to protect
+	 * test-and-set access to various attributes of the structure as well
+	 * as all sc_list operations.
+	 */
+	spinlock_t lock;
 	/*
 	 * All Sub-channels of a primary channel are linked here.
 	 */
@@ -814,6 +831,18 @@
 	struct hv_multipage_buffer range;
 } __packed;
 
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_packet_mpb_array {
+	u16 type;
+	u16 dataoffset8;
+	u16 length8;
+	u16 flags;
+	u64 transactionid;
+	u32 reserved;
+	u32 rangecount;         /* Always 1 in this case */
+	struct hv_mpb_array range;
+} __packed;
+
 
 extern int vmbus_open(struct vmbus_channel *channel,
 			    u32 send_ringbuffersize,
@@ -845,6 +874,13 @@
 					u32 bufferlen,
 					u64 requestid);
 
+extern int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
+				     struct vmbus_packet_mpb_array *mpb,
+				     u32 desc_size,
+				     void *buffer,
+				     u32 bufferlen,
+				     u64 requestid);
+
 extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
 				      void *kbuffer,
 				      u32 size,
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 5193927..b65850a41 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -25,9 +25,7 @@
  *			available.
  * @request_update:	if a parameter change has been marked, update underlying
  *			storage.
- * @get_bytes_per_datum:get current bytes per datum
  * @set_bytes_per_datum:set number of bytes per datum
- * @get_length:		get number of datums in buffer
  * @set_length:		set number of datums in buffer
  * @release:		called when the last reference to the buffer is dropped,
  *			should free all resources allocated by the buffer.
@@ -49,9 +47,7 @@
 
 	int (*request_update)(struct iio_buffer *buffer);
 
-	int (*get_bytes_per_datum)(struct iio_buffer *buffer);
 	int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
-	int (*get_length)(struct iio_buffer *buffer);
 	int (*set_length)(struct iio_buffer *buffer, int length);
 
 	void (*release)(struct iio_buffer *buffer);
@@ -85,10 +81,11 @@
 	bool					scan_timestamp;
 	const struct iio_buffer_access_funcs	*access;
 	struct list_head			scan_el_dev_attr_list;
+	struct attribute_group			buffer_group;
 	struct attribute_group			scan_el_group;
 	wait_queue_head_t			pollq;
 	bool					stufftoread;
-	const struct attribute_group *attrs;
+	const struct attribute			**attrs;
 	struct list_head			demux_list;
 	void					*demux_bounce;
 	struct list_head			buffer_list;
@@ -117,15 +114,6 @@
 			struct iio_buffer *buffer, int bit);
 
 /**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @indio_dev		IIO device structure
- * @buffer:		the buffer whose scan mask we are interested in
- * @bit:		the bit to be set.
- **/
-int iio_scan_mask_set(struct iio_dev *indio_dev,
-		      struct iio_buffer *buffer, int bit);
-
-/**
  * iio_push_to_buffers() - push to a registered buffer.
  * @indio_dev:		iio_dev structure for device.
  * @data:		Full scan.
@@ -159,56 +147,6 @@
 
 int iio_update_demux(struct iio_dev *indio_dev);
 
-/**
- * iio_buffer_register() - register the buffer with IIO core
- * @indio_dev:		device with the buffer to be registered
- * @channels:		the channel descriptions used to construct buffer
- * @num_channels:	the number of channels
- **/
-int iio_buffer_register(struct iio_dev *indio_dev,
-			const struct iio_chan_spec *channels,
-			int num_channels);
-
-/**
- * iio_buffer_unregister() - unregister the buffer from IIO core
- * @indio_dev:		the device with the buffer to be unregistered
- **/
-void iio_buffer_unregister(struct iio_dev *indio_dev);
-
-/**
- * iio_buffer_read_length() - attr func to get number of datums in the buffer
- **/
-ssize_t iio_buffer_read_length(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf);
-/**
- * iio_buffer_write_length() - attr func to set number of datums in the buffer
- **/
-ssize_t iio_buffer_write_length(struct device *dev,
-			      struct device_attribute *attr,
-			      const char *buf,
-			      size_t len);
-/**
- * iio_buffer_store_enable() - attr to turn the buffer on
- **/
-ssize_t iio_buffer_store_enable(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf,
-				size_t len);
-/**
- * iio_buffer_show_enable() - attr to see if the buffer is on
- **/
-ssize_t iio_buffer_show_enable(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf);
-#define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR,	\
-					   iio_buffer_read_length,	\
-					   iio_buffer_write_length)
-
-#define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,	\
-					   iio_buffer_show_enable,	\
-					   iio_buffer_store_enable)
-
 bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
 	const unsigned long *mask);
 
@@ -232,16 +170,6 @@
 
 #else /* CONFIG_IIO_BUFFER */
 
-static inline int iio_buffer_register(struct iio_dev *indio_dev,
-					   const struct iio_chan_spec *channels,
-					   int num_channels)
-{
-	return 0;
-}
-
-static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
-{}
-
 static inline void iio_buffer_get(struct iio_buffer *buffer) {}
 static inline void iio_buffer_put(struct iio_buffer *buffer) {}
 
diff --git a/include/linux/iio/common/ssp_sensors.h b/include/linux/iio/common/ssp_sensors.h
new file mode 100644
index 0000000..f4d1b0e
--- /dev/null
+++ b/include/linux/iio/common/ssp_sensors.h
@@ -0,0 +1,82 @@
+/*
+ *  Copyright (C) 2014, Samsung Electronics Co. Ltd. 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 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 _SSP_SENSORS_H_
+#define _SSP_SENSORS_H_
+
+#include <linux/iio/iio.h>
+
+#define SSP_TIME_SIZE				4
+#define SSP_ACCELEROMETER_SIZE			6
+#define SSP_GYROSCOPE_SIZE			6
+#define SSP_BIO_HRM_RAW_SIZE			8
+#define SSP_BIO_HRM_RAW_FAC_SIZE		36
+#define SSP_BIO_HRM_LIB_SIZE			8
+
+/**
+ * enum ssp_sensor_type - SSP sensor type
+ */
+enum ssp_sensor_type {
+	SSP_ACCELEROMETER_SENSOR = 0,
+	SSP_GYROSCOPE_SENSOR,
+	SSP_GEOMAGNETIC_UNCALIB_SENSOR,
+	SSP_GEOMAGNETIC_RAW,
+	SSP_GEOMAGNETIC_SENSOR,
+	SSP_PRESSURE_SENSOR,
+	SSP_GESTURE_SENSOR,
+	SSP_PROXIMITY_SENSOR,
+	SSP_TEMPERATURE_HUMIDITY_SENSOR,
+	SSP_LIGHT_SENSOR,
+	SSP_PROXIMITY_RAW,
+	SSP_ORIENTATION_SENSOR,
+	SSP_STEP_DETECTOR,
+	SSP_SIG_MOTION_SENSOR,
+	SSP_GYRO_UNCALIB_SENSOR,
+	SSP_GAME_ROTATION_VECTOR,
+	SSP_ROTATION_VECTOR,
+	SSP_STEP_COUNTER,
+	SSP_BIO_HRM_RAW,
+	SSP_BIO_HRM_RAW_FAC,
+	SSP_BIO_HRM_LIB,
+	SSP_SENSOR_MAX,
+};
+
+struct ssp_data;
+
+/**
+ * struct ssp_sensor_data - Sensor object
+ * @process_data:	Callback to feed sensor data.
+ * @type:		Used sensor type.
+ * @buffer:		Received data buffer.
+ */
+struct ssp_sensor_data {
+	int (*process_data)(struct iio_dev *indio_dev, void *buf,
+			    int64_t timestamp);
+	enum ssp_sensor_type type;
+	u8 *buffer;
+};
+
+void ssp_register_consumer(struct iio_dev *indio_dev,
+			   enum ssp_sensor_type type);
+
+int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
+		      u32 delay);
+
+int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type);
+
+u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type);
+
+int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
+		     u32 delay);
+#endif /* _SSP_SENSORS_H_ */
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 651f9a0..26fb8f6 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -151,6 +151,16 @@
 int iio_read_channel_processed(struct iio_channel *chan, int *val);
 
 /**
+ * iio_write_channel_raw() - write to a given channel
+ * @chan:		The channel being queried.
+ * @val:		Value being written.
+ *
+ * Note raw writes to iio channels are in dac counts and hence
+ * scale will need to be applied if standard units required.
+ */
+int iio_write_channel_raw(struct iio_channel *chan, int val);
+
+/**
  * iio_get_channel_type() - get the type of a channel
  * @channel:		The channel being queried.
  * @type:		The type of the channel.
@@ -191,7 +201,7 @@
  * The scale factor allows to increase the precession of the returned value. For
  * a scale factor of 1 the function will return the result in the normal IIO
  * unit for the channel type. E.g. millivolt for voltage channels, if you want
- * nanovolts instead pass 1000 as the scale factor.
+ * nanovolts instead pass 1000000 as the scale factor.
  */
 int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
 	int *processed, unsigned int scale);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 3642ce7..80d8550 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -38,6 +38,11 @@
 	IIO_CHAN_INFO_HARDWAREGAIN,
 	IIO_CHAN_INFO_HYSTERESIS,
 	IIO_CHAN_INFO_INT_TIME,
+	IIO_CHAN_INFO_ENABLE,
+	IIO_CHAN_INFO_CALIBHEIGHT,
+	IIO_CHAN_INFO_CALIBWEIGHT,
+	IIO_CHAN_INFO_DEBOUNCE_COUNT,
+	IIO_CHAN_INFO_DEBOUNCE_TIME,
 };
 
 enum iio_shared_by {
@@ -284,10 +289,11 @@
 /* Device operating modes */
 #define INDIO_DIRECT_MODE		0x01
 #define INDIO_BUFFER_TRIGGERED		0x02
+#define INDIO_BUFFER_SOFTWARE		0x04
 #define INDIO_BUFFER_HARDWARE		0x08
 
 #define INDIO_ALL_BUFFER_MODES					\
-	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE)
+	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE)
 
 #define INDIO_MAX_RAW_ELEMENTS		4
 
@@ -591,7 +597,8 @@
 static inline bool iio_buffer_enabled(struct iio_dev *indio_dev)
 {
 	return indio_dev->currentmode
-		& (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE);
+		& (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE |
+		   INDIO_BUFFER_SOFTWARE);
 }
 
 /**
diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h
index 25eeac7..1683bc7 100644
--- a/include/linux/iio/kfifo_buf.h
+++ b/include/linux/iio/kfifo_buf.h
@@ -5,7 +5,10 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
 
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
+struct iio_buffer *iio_kfifo_allocate(void);
 void iio_kfifo_free(struct iio_buffer *r);
 
+struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev);
+void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r);
+
 #endif
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 4a2af8a..580ed5b 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -30,6 +30,11 @@
 	IIO_CCT,
 	IIO_PRESSURE,
 	IIO_HUMIDITYRELATIVE,
+	IIO_ACTIVITY,
+	IIO_STEPS,
+	IIO_ENERGY,
+	IIO_DISTANCE,
+	IIO_VELOCITY,
 };
 
 enum iio_modifier {
@@ -59,7 +64,12 @@
 	IIO_MOD_NORTH_MAGN,
 	IIO_MOD_NORTH_TRUE,
 	IIO_MOD_NORTH_MAGN_TILT_COMP,
-	IIO_MOD_NORTH_TRUE_TILT_COMP
+	IIO_MOD_NORTH_TRUE_TILT_COMP,
+	IIO_MOD_RUNNING,
+	IIO_MOD_JOGGING,
+	IIO_MOD_WALKING,
+	IIO_MOD_STILL,
+	IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
 };
 
 enum iio_event_type {
@@ -68,6 +78,7 @@
 	IIO_EV_TYPE_ROC,
 	IIO_EV_TYPE_THRESH_ADAPTIVE,
 	IIO_EV_TYPE_MAG_ADAPTIVE,
+	IIO_EV_TYPE_CHANGE,
 };
 
 enum iio_event_info {
@@ -81,6 +92,7 @@
 	IIO_EV_DIR_EITHER,
 	IIO_EV_DIR_RISING,
 	IIO_EV_DIR_FALLING,
+	IIO_EV_DIR_NONE,
 };
 
 #define IIO_VAL_INT 1
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index d3d43ec..696d223 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -175,6 +175,13 @@
 # define INIT_NUMA_BALANCING(tsk)
 #endif
 
+#ifdef CONFIG_KASAN
+# define INIT_KASAN(tsk)						\
+	.kasan_depth = 1,
+#else
+# define INIT_KASAN(tsk)
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -250,6 +257,7 @@
 	INIT_RT_MUTEXES(tsk)						\
 	INIT_VTIME(tsk)							\
 	INIT_NUMA_BALANCING(tsk)					\
+	INIT_KASAN(tsk)							\
 }
 
 
diff --git a/include/linux/irqchip/irq-omap-intc.h b/include/linux/irqchip/irq-omap-intc.h
index e06b370..2e3d1af 100644
--- a/include/linux/irqchip/irq-omap-intc.h
+++ b/include/linux/irqchip/irq-omap-intc.h
@@ -18,9 +18,7 @@
 #ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
 #define __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
 
-void omap2_init_irq(void);
 void omap3_init_irq(void);
-void ti81xx_init_irq(void);
 
 int omap_irq_pending(void);
 void omap_intc_save_context(void);
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
new file mode 100644
index 0000000..72ba725
--- /dev/null
+++ b/include/linux/kasan.h
@@ -0,0 +1,89 @@
+#ifndef _LINUX_KASAN_H
+#define _LINUX_KASAN_H
+
+#include <linux/types.h>
+
+struct kmem_cache;
+struct page;
+
+#ifdef CONFIG_KASAN
+
+#define KASAN_SHADOW_SCALE_SHIFT 3
+#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
+
+#include <asm/kasan.h>
+#include <linux/sched.h>
+
+static inline void *kasan_mem_to_shadow(const void *addr)
+{
+	return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT)
+		+ KASAN_SHADOW_OFFSET;
+}
+
+/* Enable reporting bugs after kasan_disable_current() */
+static inline void kasan_enable_current(void)
+{
+	current->kasan_depth++;
+}
+
+/* Disable reporting bugs for current task */
+static inline void kasan_disable_current(void)
+{
+	current->kasan_depth--;
+}
+
+void kasan_unpoison_shadow(const void *address, size_t size);
+
+void kasan_alloc_pages(struct page *page, unsigned int order);
+void kasan_free_pages(struct page *page, unsigned int order);
+
+void kasan_poison_slab(struct page *page);
+void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
+void kasan_poison_object_data(struct kmem_cache *cache, void *object);
+
+void kasan_kmalloc_large(const void *ptr, size_t size);
+void kasan_kfree_large(const void *ptr);
+void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size);
+void kasan_krealloc(const void *object, size_t new_size);
+
+void kasan_slab_alloc(struct kmem_cache *s, void *object);
+void kasan_slab_free(struct kmem_cache *s, void *object);
+
+#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
+
+int kasan_module_alloc(void *addr, size_t size);
+void kasan_module_free(void *addr);
+
+#else /* CONFIG_KASAN */
+
+#define MODULE_ALIGN 1
+
+static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
+
+static inline void kasan_enable_current(void) {}
+static inline void kasan_disable_current(void) {}
+
+static inline void kasan_alloc_pages(struct page *page, unsigned int order) {}
+static inline void kasan_free_pages(struct page *page, unsigned int order) {}
+
+static inline void kasan_poison_slab(struct page *page) {}
+static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
+					void *object) {}
+static inline void kasan_poison_object_data(struct kmem_cache *cache,
+					void *object) {}
+
+static inline void kasan_kmalloc_large(void *ptr, size_t size) {}
+static inline void kasan_kfree_large(const void *ptr) {}
+static inline void kasan_kmalloc(struct kmem_cache *s, const void *object,
+				size_t size) {}
+static inline void kasan_krealloc(const void *object, size_t new_size) {}
+
+static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
+static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
+
+static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
+static inline void kasan_module_free(void *addr) {}
+
+#endif /* CONFIG_KASAN */
+
+#endif /* LINUX_KASAN_H */
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index d4e01b3..71ecdab 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -43,7 +43,6 @@
 	KERNFS_HAS_SEQ_SHOW	= 0x0040,
 	KERNFS_HAS_MMAP		= 0x0080,
 	KERNFS_LOCKDEP		= 0x0100,
-	KERNFS_STATIC_NAME	= 0x0200,
 	KERNFS_SUICIDAL		= 0x0400,
 	KERNFS_SUICIDED		= 0x0800,
 };
@@ -291,7 +290,6 @@
 					 umode_t mode, loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
-					 bool name_is_static,
 					 struct lock_class_key *key);
 struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
 				       const char *name,
@@ -369,8 +367,7 @@
 static inline struct kernfs_node *
 __kernfs_create_file(struct kernfs_node *parent, const char *name,
 		     umode_t mode, loff_t size, const struct kernfs_ops *ops,
-		     void *priv, const void *ns, bool name_is_static,
-		     struct lock_class_key *key)
+		     void *priv, const void *ns, struct lock_class_key *key)
 { return ERR_PTR(-ENOSYS); }
 
 static inline struct kernfs_node *
@@ -439,7 +436,7 @@
 	key = (struct lock_class_key *)&ops->lockdep_key;
 #endif
 	return __kernfs_create_file(parent, name, mode, size, ops, priv, ns,
-				    false, key);
+				    key);
 }
 
 static inline struct kernfs_node *
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 164aad1..0819d36 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -25,8 +25,8 @@
 
 void mei_cl_driver_unregister(struct mei_cl_driver *driver);
 
-int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
-int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+ssize_t  mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
 
 typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
 			       u32 events, void *context);
diff --git a/include/linux/mfd/syscon/atmel-matrix.h b/include/linux/mfd/syscon/atmel-matrix.h
new file mode 100644
index 0000000..8293c3e
--- /dev/null
+++ b/include/linux/mfd/syscon/atmel-matrix.h
@@ -0,0 +1,117 @@
+/*
+ *  Copyright (C) 2014 Atmel Corporation.
+ *
+ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
+ *
+ * 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_MFD_SYSCON_ATMEL_MATRIX_H
+#define _LINUX_MFD_SYSCON_ATMEL_MATRIX_H
+
+#define AT91SAM9260_MATRIX_MCFG			0x00
+#define AT91SAM9260_MATRIX_SCFG			0x40
+#define AT91SAM9260_MATRIX_PRS			0x80
+#define AT91SAM9260_MATRIX_MRCR			0x100
+#define AT91SAM9260_MATRIX_EBICSA		0x11c
+
+#define AT91SAM9261_MATRIX_MRCR			0x0
+#define AT91SAM9261_MATRIX_SCFG			0x4
+#define AT91SAM9261_MATRIX_TCR			0x24
+#define AT91SAM9261_MATRIX_EBICSA		0x30
+#define AT91SAM9261_MATRIX_USBPUCR		0x34
+
+#define AT91SAM9263_MATRIX_MCFG			0x00
+#define AT91SAM9263_MATRIX_SCFG			0x40
+#define AT91SAM9263_MATRIX_PRS			0x80
+#define AT91SAM9263_MATRIX_MRCR			0x100
+#define AT91SAM9263_MATRIX_TCR			0x114
+#define AT91SAM9263_MATRIX_EBI0CSA		0x120
+#define AT91SAM9263_MATRIX_EBI1CSA		0x124
+
+#define AT91SAM9RL_MATRIX_MCFG			0x00
+#define AT91SAM9RL_MATRIX_SCFG			0x40
+#define AT91SAM9RL_MATRIX_PRS			0x80
+#define AT91SAM9RL_MATRIX_MRCR			0x100
+#define AT91SAM9RL_MATRIX_TCR			0x114
+#define AT91SAM9RL_MATRIX_EBICSA		0x120
+
+#define AT91SAM9G45_MATRIX_MCFG			0x00
+#define AT91SAM9G45_MATRIX_SCFG			0x40
+#define AT91SAM9G45_MATRIX_PRS			0x80
+#define AT91SAM9G45_MATRIX_MRCR			0x100
+#define AT91SAM9G45_MATRIX_TCR			0x110
+#define AT91SAM9G45_MATRIX_DDRMPR		0x118
+#define AT91SAM9G45_MATRIX_EBICSA		0x128
+
+#define AT91SAM9N12_MATRIX_MCFG			0x00
+#define AT91SAM9N12_MATRIX_SCFG			0x40
+#define AT91SAM9N12_MATRIX_PRS			0x80
+#define AT91SAM9N12_MATRIX_MRCR			0x100
+#define AT91SAM9N12_MATRIX_EBICSA		0x118
+
+#define AT91SAM9X5_MATRIX_MCFG			0x00
+#define AT91SAM9X5_MATRIX_SCFG			0x40
+#define AT91SAM9X5_MATRIX_PRS			0x80
+#define AT91SAM9X5_MATRIX_MRCR			0x100
+#define AT91SAM9X5_MATRIX_EBICSA		0x120
+
+#define SAMA5D3_MATRIX_MCFG			0x00
+#define SAMA5D3_MATRIX_SCFG			0x40
+#define SAMA5D3_MATRIX_PRS			0x80
+#define SAMA5D3_MATRIX_MRCR			0x100
+
+#define AT91_MATRIX_MCFG(o, x)			((o) + ((x) * 0x4))
+#define AT91_MATRIX_ULBT			GENMASK(2, 0)
+#define AT91_MATRIX_ULBT_INFINITE		(0 << 0)
+#define AT91_MATRIX_ULBT_SINGLE			(1 << 0)
+#define AT91_MATRIX_ULBT_FOUR			(2 << 0)
+#define AT91_MATRIX_ULBT_EIGHT			(3 << 0)
+#define AT91_MATRIX_ULBT_SIXTEEN		(4 << 0)
+
+#define AT91_MATRIX_SCFG(o, x)			((o) + ((x) * 0x4))
+#define AT91_MATRIX_SLOT_CYCLE			GENMASK(7,  0)
+#define AT91_MATRIX_DEFMSTR_TYPE		GENMASK(17, 16)
+#define AT91_MATRIX_DEFMSTR_TYPE_NONE		(0 << 16)
+#define AT91_MATRIX_DEFMSTR_TYPE_LAST		(1 << 16)
+#define AT91_MATRIX_DEFMSTR_TYPE_FIXED		(2 << 16)
+#define AT91_MATRIX_FIXED_DEFMSTR		GENMASK(20, 18)
+#define AT91_MATRIX_ARBT			GENMASK(25, 24)
+#define AT91_MATRIX_ARBT_ROUND_ROBIN		(0 << 24)
+#define AT91_MATRIX_ARBT_FIXED_PRIORITY		(1 << 24)
+
+#define AT91_MATRIX_ITCM_SIZE			GENMASK(3, 0)
+#define AT91_MATRIX_ITCM_0			(0 << 0)
+#define AT91_MATRIX_ITCM_16			(5 << 0)
+#define AT91_MATRIX_ITCM_32			(6 << 0)
+#define AT91_MATRIX_ITCM_64			(7 << 0)
+#define	AT91_MATRIX_DTCM_SIZE			GENMASK(7, 4)
+#define	AT91_MATRIX_DTCM_0			(0 << 4)
+#define	AT91_MATRIX_DTCM_16			(5 << 4)
+#define AT91_MATRIX_DTCM_32			(6 << 4)
+#define AT91_MATRIX_DTCM_64			(7 << 4)
+
+#define AT91_MATRIX_PRAS(o, x)			((o) + ((x) * 0x8))
+#define AT91_MATRIX_PRBS(o, x)			((o) + ((x) * 0x8) + 0x4)
+#define AT91_MATRIX_MPR(x)			GENMASK(((x) * 0x4) + 1, ((x) * 0x4))
+
+#define AT91_MATRIX_RCB(x)			BIT(x)
+
+#define AT91_MATRIX_CSA(cs, val)		(val << (cs))
+#define AT91_MATRIX_DBPUC			BIT(8)
+#define AT91_MATRIX_DBPDC			BIT(9)
+#define AT91_MATRIX_VDDIOMSEL			BIT(16)
+#define AT91_MATRIX_VDDIOMSEL_1_8V		(0 << 16)
+#define AT91_MATRIX_VDDIOMSEL_3_3V		(1 << 16)
+#define AT91_MATRIX_EBI_IOSR			BIT(17)
+#define AT91_MATRIX_DDR_IOSR			BIT(18)
+#define AT91_MATRIX_NFD0_SELECT			BIT(24)
+#define AT91_MATRIX_DDR_MP_EN			BIT(25)
+#define AT91_MATRIX_EBI_NUM_CS			8
+
+#define AT91_MATRIX_USBPUCR_PUON		BIT(30)
+
+#endif /* _LINUX_MFD_SYSCON_ATMEL_MATRIX_H */
diff --git a/include/linux/mfd/syscon/atmel-smc.h b/include/linux/mfd/syscon/atmel-smc.h
new file mode 100644
index 0000000..be6ebe6
--- /dev/null
+++ b/include/linux/mfd/syscon/atmel-smc.h
@@ -0,0 +1,173 @@
+/*
+ * Atmel SMC (Static Memory Controller) register offsets and bit definitions.
+ *
+ * Copyright (C) 2014 Atmel
+ * 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.
+ */
+
+#ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_
+#define _LINUX_MFD_SYSCON_ATMEL_SMC_H_
+
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+
+#define AT91SAM9_SMC_GENERIC		0x00
+#define AT91SAM9_SMC_GENERIC_BLK_SZ	0x10
+
+#define SAMA5_SMC_GENERIC		0x600
+#define SAMA5_SMC_GENERIC_BLK_SZ	0x14
+
+#define AT91SAM9_SMC_SETUP(o)		((o) + 0x00)
+#define AT91SAM9_SMC_NWESETUP(x)	(x)
+#define AT91SAM9_SMC_NCS_WRSETUP(x)	((x) << 8)
+#define AT91SAM9_SMC_NRDSETUP(x)	((x) << 16)
+#define AT91SAM9_SMC_NCS_NRDSETUP(x)	((x) << 24)
+
+#define AT91SAM9_SMC_PULSE(o)		((o) + 0x04)
+#define AT91SAM9_SMC_NWEPULSE(x)	(x)
+#define AT91SAM9_SMC_NCS_WRPULSE(x)	((x) << 8)
+#define AT91SAM9_SMC_NRDPULSE(x)	((x) << 16)
+#define AT91SAM9_SMC_NCS_NRDPULSE(x)	((x) << 24)
+
+#define AT91SAM9_SMC_CYCLE(o)		((o) + 0x08)
+#define AT91SAM9_SMC_NWECYCLE(x)	(x)
+#define AT91SAM9_SMC_NRDCYCLE(x)	((x) << 16)
+
+#define AT91SAM9_SMC_MODE(o)		((o) + 0x0c)
+#define SAMA5_SMC_MODE(o)		((o) + 0x10)
+#define AT91_SMC_READMODE		BIT(0)
+#define AT91_SMC_READMODE_NCS		(0 << 0)
+#define AT91_SMC_READMODE_NRD		(1 << 0)
+#define AT91_SMC_WRITEMODE		BIT(1)
+#define AT91_SMC_WRITEMODE_NCS		(0 << 1)
+#define AT91_SMC_WRITEMODE_NWE		(1 << 1)
+#define AT91_SMC_EXNWMODE		GENMASK(5, 4)
+#define AT91_SMC_EXNWMODE_DISABLE	(0 << 4)
+#define AT91_SMC_EXNWMODE_FROZEN	(2 << 4)
+#define AT91_SMC_EXNWMODE_READY		(3 << 4)
+#define AT91_SMC_BAT			BIT(8)
+#define AT91_SMC_BAT_SELECT		(0 << 8)
+#define AT91_SMC_BAT_WRITE		(1 << 8)
+#define AT91_SMC_DBW			GENMASK(13, 12)
+#define AT91_SMC_DBW_8			(0 << 12)
+#define AT91_SMC_DBW_16			(1 << 12)
+#define AT91_SMC_DBW_32			(2 << 12)
+#define AT91_SMC_TDF			GENMASK(19, 16)
+#define AT91_SMC_TDF_(x)		((((x) - 1) << 16) & AT91_SMC_TDF)
+#define AT91_SMC_TDF_MAX		16
+#define AT91_SMC_TDFMODE_OPTIMIZED	BIT(20)
+#define AT91_SMC_PMEN			BIT(24)
+#define AT91_SMC_PS			GENMASK(29, 28)
+#define AT91_SMC_PS_4			(0 << 28)
+#define AT91_SMC_PS_8			(1 << 28)
+#define AT91_SMC_PS_16			(2 << 28)
+#define AT91_SMC_PS_32			(3 << 28)
+
+
+/*
+ * This function converts a setup timing expressed in nanoseconds into an
+ * encoded value that can be written in the SMC_SETUP register.
+ *
+ * The following formula is described in atmel datasheets (section
+ * "SMC Setup Register"):
+ *
+ * setup length = (128* SETUP[5] + SETUP[4:0])
+ *
+ * where setup length is the timing expressed in cycles.
+ */
+static inline u32 at91sam9_smc_setup_ns_to_cycles(unsigned int clk_rate,
+						  u32 timing_ns)
+{
+	u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate);
+	u32 coded_cycles = 0;
+	u32 cycles;
+
+	cycles = DIV_ROUND_UP(timing_ns, clk_period);
+	if (cycles / 32) {
+		coded_cycles |= 1 << 5;
+		if (cycles < 128)
+			cycles = 0;
+	}
+
+	coded_cycles |= cycles % 32;
+
+	return coded_cycles;
+}
+
+/*
+ * This function converts a pulse timing expressed in nanoseconds into an
+ * encoded value that can be written in the SMC_PULSE register.
+ *
+ * The following formula is described in atmel datasheets (section
+ * "SMC Pulse Register"):
+ *
+ * pulse length = (256* PULSE[6] + PULSE[5:0])
+ *
+ * where pulse length is the timing expressed in cycles.
+ */
+static inline u32 at91sam9_smc_pulse_ns_to_cycles(unsigned int clk_rate,
+						  u32 timing_ns)
+{
+	u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate);
+	u32 coded_cycles = 0;
+	u32 cycles;
+
+	cycles = DIV_ROUND_UP(timing_ns, clk_period);
+	if (cycles / 64) {
+		coded_cycles |= 1 << 6;
+		if (cycles < 256)
+			cycles = 0;
+	}
+
+	coded_cycles |= cycles % 64;
+
+	return coded_cycles;
+}
+
+/*
+ * This function converts a cycle timing expressed in nanoseconds into an
+ * encoded value that can be written in the SMC_CYCLE register.
+ *
+ * The following formula is described in atmel datasheets (section
+ * "SMC Cycle Register"):
+ *
+ * cycle length = (CYCLE[8:7]*256 + CYCLE[6:0])
+ *
+ * where cycle length is the timing expressed in cycles.
+ */
+static inline u32 at91sam9_smc_cycle_ns_to_cycles(unsigned int clk_rate,
+						  u32 timing_ns)
+{
+	u32 clk_period = DIV_ROUND_UP(NSEC_PER_SEC, clk_rate);
+	u32 coded_cycles = 0;
+	u32 cycles;
+
+	cycles = DIV_ROUND_UP(timing_ns, clk_period);
+	if (cycles / 128) {
+		coded_cycles = cycles / 256;
+		cycles %= 256;
+		if (cycles >= 128) {
+			coded_cycles++;
+			cycles = 0;
+		}
+
+		if (coded_cycles > 0x3) {
+			coded_cycles = 0x3;
+			cycles = 0x7f;
+		}
+
+		coded_cycles <<= 7;
+	}
+
+	coded_cycles |= cycles % 128;
+
+	return coded_cycles;
+}
+
+#endif /* _LINUX_MFD_SYSCON_ATMEL_SMC_H_ */
diff --git a/include/linux/mfd/syscon/exynos4-pmu.h b/include/linux/mfd/syscon/exynos4-pmu.h
new file mode 100644
index 0000000..278b1b1
--- /dev/null
+++ b/include/linux/mfd/syscon/exynos4-pmu.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_
+#define _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_
+
+/* Exynos4 PMU register definitions */
+
+/* MIPI_PHYn_CONTROL register offset: n = 0..1 */
+#define EXYNOS4_MIPI_PHY_CONTROL(n)	(0x710 + (n) * 4)
+#define EXYNOS4_MIPI_PHY_ENABLE		(1 << 0)
+#define EXYNOS4_MIPI_PHY_SRESETN	(1 << 1)
+#define EXYNOS4_MIPI_PHY_MRESETN	(1 << 2)
+#define EXYNOS4_MIPI_PHY_RESET_MASK	(3 << 1)
+
+#endif /* _LINUX_MFD_SYSCON_PMU_EXYNOS4_H_ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9bee7ec..47a9392 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -224,6 +224,7 @@
 	pgoff_t pgoff;			/* Logical page offset based on vma */
 	void __user *virtual_address;	/* Faulting virtual address */
 
+	struct page *cow_page;		/* Handler may choose to COW */
 	struct page *page;		/* ->fault handlers should return a
 					 * page here, unless VM_FAULT_NOPAGE
 					 * is set (which is also implied by
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index bbf85d6..2e75ab0 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -53,9 +53,9 @@
 
 /**
  * struct usb_device_id - identifies USB devices for probing and hotplugging
- * @match_flags: Bit mask controlling of the other fields are used to match
- *	against new devices.  Any field except for driver_info may be used,
- *	although some only make sense in conjunction with other fields.
+ * @match_flags: Bit mask controlling which of the other fields are used to
+ *	match against new devices. Any field except for driver_info may be
+ *	used, although some only make sense in conjunction with other fields.
  *	This is usually set by a USB_DEVICE_*() macro, which sets all
  *	other fields in this structure except for driver_info.
  * @idVendor: USB vendor ID for a device; numbers are assigned
diff --git a/include/linux/module.h b/include/linux/module.h
index b653d7c..42999fe 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -135,7 +135,7 @@
 #ifdef MODULE
 /* Creates an alias so file2alias.c can find device table. */
 #define MODULE_DEVICE_TABLE(type, name)					\
-  extern const struct type##_device_id __mod_##type##__##name##_device_table \
+extern const typeof(name) __mod_##type##__##name##_device_table		\
   __attribute__ ((unused, alias(__stringify(name))))
 #else  /* !MODULE */
 #define MODULE_DEVICE_TABLE(type, name)
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index c3918a0..1e271cb 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -23,22 +23,32 @@
 
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#include <linux/scatterlist.h>
 #include <mtd/ubi-user.h>
 
 /* All voumes/LEBs */
 #define UBI_ALL -1
 
 /*
+ * Maximum number of scatter gather list entries,
+ * we use only 64 to have a lower memory foot print.
+ */
+#define UBI_MAX_SG_COUNT 64
+
+/*
  * enum ubi_open_mode - UBI volume open mode constants.
  *
  * UBI_READONLY: read-only mode
  * UBI_READWRITE: read-write mode
  * UBI_EXCLUSIVE: exclusive mode
+ * UBI_METAONLY: modify only the volume meta-data,
+ *  i.e. the data stored in the volume table, but not in any of volume LEBs.
  */
 enum {
 	UBI_READONLY = 1,
 	UBI_READWRITE,
-	UBI_EXCLUSIVE
+	UBI_EXCLUSIVE,
+	UBI_METAONLY
 };
 
 /**
@@ -116,6 +126,35 @@
 };
 
 /**
+ * struct ubi_sgl - UBI scatter gather list data structure.
+ * @list_pos: current position in @sg[]
+ * @page_pos: current position in @sg[@list_pos]
+ * @sg: the scatter gather list itself
+ *
+ * ubi_sgl is a wrapper around a scatter list which keeps track of the
+ * current position in the list and the current list item such that
+ * it can be used across multiple ubi_leb_read_sg() calls.
+ */
+struct ubi_sgl {
+	int list_pos;
+	int page_pos;
+	struct scatterlist sg[UBI_MAX_SG_COUNT];
+};
+
+/**
+ * ubi_sgl_init - initialize an UBI scatter gather list data structure.
+ * @usgl: the UBI scatter gather struct itself
+ *
+ * Please note that you still have to use sg_init_table() or any adequate
+ * function to initialize the unterlaying struct scatterlist.
+ */
+static inline void ubi_sgl_init(struct ubi_sgl *usgl)
+{
+	usgl->list_pos = 0;
+	usgl->page_pos = 0;
+}
+
+/**
  * struct ubi_device_info - UBI device description data structure.
  * @ubi_num: ubi device number
  * @leb_size: logical eraseblock size on this UBI device
@@ -210,6 +249,8 @@
 void ubi_close_volume(struct ubi_volume_desc *desc);
 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		 int len, int check);
+int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
+		   int offset, int len, int check);
 int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
 		  int offset, int len);
 int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
@@ -230,4 +271,14 @@
 {
 	return ubi_leb_read(desc, lnum, buf, offset, len, 0);
 }
+
+/*
+ * This function is the same as the 'ubi_leb_read_sg()' function, but it does
+ * not provide the checking capability.
+ */
+static inline int ubi_read_sg(struct ubi_volume_desc *desc, int lnum,
+			      struct ubi_sgl *sgl, int offset, int len)
+{
+	return ubi_leb_read_sg(desc, lnum, sgl, offset, len, 0);
+}
 #endif /* !__LINUX_UBI_H__ */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index cc31498..2cb7531 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -59,7 +59,6 @@
 	struct optimistic_spin_queue osq; /* Spinner MCS lock */
 #endif
 #ifdef CONFIG_DEBUG_MUTEXES
-	const char 		*name;
 	void			*magic;
 #endif
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 21cef48..6e85889 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -8,14 +8,13 @@
  * See detailed comments in the file linux/bitmap.h describing the
  * data type on which these nodemasks are based.
  *
- * For details of nodemask_scnprintf() and nodemask_parse_user(),
- * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
- * For details of nodelist_scnprintf() and nodelist_parse(), see
- * bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
- * For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
- * For details of nodes_remap(), see bitmap_remap in lib/bitmap.c.
- * For details of nodes_onto(), see bitmap_onto in lib/bitmap.c.
- * For details of nodes_fold(), see bitmap_fold in lib/bitmap.c.
+ * For details of nodemask_parse_user(), see bitmap_parse_user() in
+ * lib/bitmap.c.  For details of nodelist_parse(), see bitmap_parselist(),
+ * also in bitmap.c.  For details of node_remap(), see bitmap_bitremap in
+ * lib/bitmap.c.  For details of nodes_remap(), see bitmap_remap in
+ * lib/bitmap.c.  For details of nodes_onto(), see bitmap_onto in
+ * lib/bitmap.c.  For details of nodes_fold(), see bitmap_fold in
+ * lib/bitmap.c.
  *
  * The available nodemask operations are:
  *
@@ -52,9 +51,7 @@
  * NODE_MASK_NONE			Initializer - no bits set
  * unsigned long *nodes_addr(mask)	Array of unsigned long's in mask
  *
- * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
  * int nodemask_parse_user(ubuf, ulen, mask)	Parse ascii string as nodemask
- * int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
  * int nodelist_parse(buf, map)		Parse ascii string as nodelist
  * int node_remap(oldbit, old, new)	newbit = map(old, new)(oldbit)
  * void nodes_remap(dst, src, old, new)	*dst = map(old, new)(src)
@@ -98,6 +95,14 @@
 typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
 extern nodemask_t _unused_nodemask_arg_;
 
+/**
+ * nodemask_pr_args - printf args to output a nodemask
+ * @maskp: nodemask to be printed
+ *
+ * Can be used to provide arguments for '%*pb[l]' when printing a nodemask.
+ */
+#define nodemask_pr_args(maskp)		MAX_NUMNODES, (maskp)->bits
+
 /*
  * The inline keyword gives the compiler room to decide to inline, or
  * not inline a function as it sees best.  However, as these functions
@@ -304,14 +309,6 @@
 
 #define nodes_addr(src) ((src).bits)
 
-#define nodemask_scnprintf(buf, len, src) \
-			__nodemask_scnprintf((buf), (len), &(src), MAX_NUMNODES)
-static inline int __nodemask_scnprintf(char *buf, int len,
-					const nodemask_t *srcp, int nbits)
-{
-	return bitmap_scnprintf(buf, len, srcp->bits, nbits);
-}
-
 #define nodemask_parse_user(ubuf, ulen, dst) \
 		__nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES)
 static inline int __nodemask_parse_user(const char __user *buf, int len,
@@ -320,14 +317,6 @@
 	return bitmap_parse_user(buf, len, dstp->bits, nbits);
 }
 
-#define nodelist_scnprintf(buf, len, src) \
-			__nodelist_scnprintf((buf), (len), &(src), MAX_NUMNODES)
-static inline int __nodelist_scnprintf(char *buf, int len,
-					const nodemask_t *srcp, int nbits)
-{
-	return bitmap_scnlistprintf(buf, len, srcp->bits, nbits);
-}
-
 #define nodelist_parse(buf, dst) __nodelist_parse((buf), &(dst), MAX_NUMNODES)
 static inline int __nodelist_parse(const char *buf, nodemask_t *dstp, int nbits)
 {
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2cdc9d4..2b62198 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -202,6 +202,13 @@
 	 */
 	int (*event_init)		(struct perf_event *event);
 
+	/*
+	 * Notification that the event was mapped or unmapped.  Called
+	 * in the context of the mapping task.
+	 */
+	void (*event_mapped)		(struct perf_event *event); /*optional*/
+	void (*event_unmapped)		(struct perf_event *event); /*optional*/
+
 #define PERF_EF_START	0x01		/* start the counter when adding    */
 #define PERF_EF_RELOAD	0x02		/* reload the counter when starting */
 #define PERF_EF_UPDATE	0x04		/* update the counter when stopping */
diff --git a/include/linux/platform_data/cpuidle-exynos.h b/include/linux/platform_data/cpuidle-exynos.h
new file mode 100644
index 0000000..bfa40e4
--- /dev/null
+++ b/include/linux/platform_data/cpuidle-exynos.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 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.
+*/
+
+#ifndef __CPUIDLE_EXYNOS_H
+#define __CPUIDLE_EXYNOS_H
+
+struct cpuidle_exynos_data {
+	int (*cpu0_enter_aftr)(void);
+	int (*cpu1_powerdown)(void);
+	void (*pre_enter_aftr)(void);
+	void (*post_enter_aftr)(void);
+};
+
+#endif
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 195aafc..6512e9c 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -12,6 +12,7 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/mod_devicetable.h>
+#include <linux/console.h>
 
 #define PNP_NAME_LEN		50
 
@@ -309,15 +310,22 @@
 #define PNP_DISABLE		0x0004
 #define PNP_CONFIGURABLE	0x0008
 #define PNP_REMOVABLE		0x0010
+#define PNP_CONSOLE		0x0020
 
 #define pnp_can_read(dev)	(((dev)->protocol->get) && \
 				 ((dev)->capabilities & PNP_READ))
 #define pnp_can_write(dev)	(((dev)->protocol->set) && \
 				 ((dev)->capabilities & PNP_WRITE))
-#define pnp_can_disable(dev)	(((dev)->protocol->disable) && \
-				 ((dev)->capabilities & PNP_DISABLE))
+#define pnp_can_disable(dev)	(((dev)->protocol->disable) &&		  \
+				 ((dev)->capabilities & PNP_DISABLE) &&	  \
+				 (!((dev)->capabilities & PNP_CONSOLE) || \
+				  console_suspend_enabled))
 #define pnp_can_configure(dev)	((!(dev)->active) && \
 				 ((dev)->capabilities & PNP_CONFIGURABLE))
+#define pnp_can_suspend(dev)	(((dev)->protocol->suspend) &&		  \
+				 (!((dev)->capabilities & PNP_CONSOLE) || \
+				  console_suspend_enabled))
+
 
 #ifdef CONFIG_ISAPNP
 extern struct pnp_protocol isapnp_protocol;
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index b38f559..c4c559a 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -198,7 +198,7 @@
 int try_to_unmap(struct page *, enum ttu_flags flags);
 
 /*
- * Called from mm/filemap_xip.c to unmap empty zero page
+ * Used by uprobes to replace a userspace page safely
  */
 pte_t *__page_check_address(struct page *, struct mm_struct *,
 				unsigned long, spinlock_t **, int);
diff --git a/include/linux/rtc/ds1685.h b/include/linux/rtc/ds1685.h
new file mode 100644
index 0000000..e6337a5
--- /dev/null
+++ b/include/linux/rtc/ds1685.h
@@ -0,0 +1,375 @@
+/*
+ * Definitions for the registers, addresses, and platform data of the
+ * DS1685/DS1687-series RTC chips.
+ *
+ * This Driver also works for the DS17X85/DS17X87 RTC chips.  Functionally
+ * similar to the DS1685/DS1687, they support a few extra features which
+ * include larger, battery-backed NV-SRAM, burst-mode access, and an RTC
+ * write counter.
+ *
+ * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
+ *
+ * References:
+ *    DS1685/DS1687 3V/5V Real-Time Clocks, 19-5215, Rev 4/10.
+ *    DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10.
+ *    DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105.
+ *    Application Note 90, Using the Multiplex Bus RTC Extended Features.
+ *
+ * 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_RTC_DS1685_H_
+#define _LINUX_RTC_DS1685_H_
+
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+/**
+ * struct ds1685_priv - DS1685 private data structure.
+ * @dev: pointer to the rtc_device structure.
+ * @regs: iomapped base address pointer of the RTC registers.
+ * @regstep: padding/step size between registers (optional).
+ * @baseaddr: base address of the RTC device.
+ * @size: resource size.
+ * @lock: private lock variable for spin locking/unlocking.
+ * @work: private workqueue.
+ * @irq: IRQ number assigned to the RTC device.
+ * @prepare_poweroff: pointer to platform pre-poweroff function.
+ * @wake_alarm: pointer to platform wake alarm function.
+ * @post_ram_clear: pointer to platform post ram-clear function.
+ */
+struct ds1685_priv {
+	struct rtc_device *dev;
+	void __iomem *regs;
+	u32 regstep;
+	resource_size_t baseaddr;
+	size_t size;
+	spinlock_t lock;
+	struct work_struct work;
+	int irq_num;
+	bool bcd_mode;
+	bool no_irq;
+	bool uie_unsupported;
+	bool alloc_io_resources;
+	u8 (*read)(struct ds1685_priv *, int);
+	void (*write)(struct ds1685_priv *, int, u8);
+	void (*prepare_poweroff)(void);
+	void (*wake_alarm)(void);
+	void (*post_ram_clear)(void);
+};
+
+
+/**
+ * struct ds1685_rtc_platform_data - platform data structure.
+ * @plat_prepare_poweroff: platform-specific pre-poweroff function.
+ * @plat_wake_alarm: platform-specific wake alarm function.
+ * @plat_post_ram_clear: platform-specific post ram-clear function.
+ *
+ * If your platform needs to use a custom padding/step size between
+ * registers, or uses one or more of the extended interrupts and needs special
+ * handling, then include this header file in your platform definition and
+ * set regstep and the plat_* pointers as appropriate.
+ */
+struct ds1685_rtc_platform_data {
+	const u32 regstep;
+	const bool bcd_mode;
+	const bool no_irq;
+	const bool uie_unsupported;
+	const bool alloc_io_resources;
+	u8 (*plat_read)(struct ds1685_priv *, int);
+	void (*plat_write)(struct ds1685_priv *, int, u8);
+	void (*plat_prepare_poweroff)(void);
+	void (*plat_wake_alarm)(void);
+	void (*plat_post_ram_clear)(void);
+};
+
+
+/*
+ * Time Registers.
+ */
+#define RTC_SECS		0x00	/* Seconds 00-59 */
+#define RTC_SECS_ALARM		0x01	/* Alarm Seconds 00-59 */
+#define RTC_MINS		0x02	/* Minutes 00-59 */
+#define RTC_MINS_ALARM		0x03	/* Alarm Minutes 00-59 */
+#define RTC_HRS			0x04	/* Hours 01-12 AM/PM || 00-23 */
+#define RTC_HRS_ALARM		0x05	/* Alarm Hours 01-12 AM/PM || 00-23 */
+#define RTC_WDAY		0x06	/* Day of Week 01-07 */
+#define RTC_MDAY		0x07	/* Day of Month 01-31 */
+#define RTC_MONTH		0x08	/* Month 01-12 */
+#define RTC_YEAR		0x09	/* Year 00-99 */
+#define RTC_CENTURY		0x48	/* Century 00-99 */
+#define RTC_MDAY_ALARM		0x49	/* Alarm Day of Month 01-31 */
+
+
+/*
+ * Bit masks for the Time registers in BCD Mode (DM = 0).
+ */
+#define RTC_SECS_BCD_MASK	0x7f	/* - x x x x x x x */
+#define RTC_MINS_BCD_MASK	0x7f	/* - x x x x x x x */
+#define RTC_HRS_12_BCD_MASK	0x1f	/* - - - x x x x x */
+#define RTC_HRS_24_BCD_MASK	0x3f	/* - - x x x x x x */
+#define RTC_MDAY_BCD_MASK	0x3f	/* - - x x x x x x */
+#define RTC_MONTH_BCD_MASK	0x1f	/* - - - x x x x x */
+#define RTC_YEAR_BCD_MASK	0xff	/* x x x x x x x x */
+
+/*
+ * Bit masks for the Time registers in BIN Mode (DM = 1).
+ */
+#define RTC_SECS_BIN_MASK	0x3f	/* - - x x x x x x */
+#define RTC_MINS_BIN_MASK	0x3f	/* - - x x x x x x */
+#define RTC_HRS_12_BIN_MASK	0x0f	/* - - - - x x x x */
+#define RTC_HRS_24_BIN_MASK	0x1f	/* - - - x x x x x */
+#define RTC_MDAY_BIN_MASK	0x1f	/* - - - x x x x x */
+#define RTC_MONTH_BIN_MASK	0x0f	/* - - - - x x x x */
+#define RTC_YEAR_BIN_MASK	0x7f	/* - x x x x x x x */
+
+/*
+ * Bit masks common for the Time registers in BCD or BIN Mode.
+ */
+#define RTC_WDAY_MASK		0x07	/* - - - - - x x x */
+#define RTC_CENTURY_MASK	0xff	/* x x x x x x x x */
+#define RTC_MDAY_ALARM_MASK	0xff	/* x x x x x x x x */
+#define RTC_HRS_AMPM_MASK	BIT(7)	/* Mask for the AM/PM bit */
+
+
+
+/*
+ * Control Registers.
+ */
+#define RTC_CTRL_A		0x0a	/* Control Register A */
+#define RTC_CTRL_B		0x0b	/* Control Register B */
+#define RTC_CTRL_C		0x0c	/* Control Register C */
+#define RTC_CTRL_D		0x0d	/* Control Register D */
+#define RTC_EXT_CTRL_4A		0x4a	/* Extended Control Register 4A */
+#define RTC_EXT_CTRL_4B		0x4b	/* Extended Control Register 4B */
+
+
+/*
+ * Bit names in Control Register A.
+ */
+#define RTC_CTRL_A_UIP		BIT(7)	/* Update In Progress */
+#define RTC_CTRL_A_DV2		BIT(6)	/* Countdown Chain */
+#define RTC_CTRL_A_DV1		BIT(5)	/* Oscillator Enable */
+#define RTC_CTRL_A_DV0		BIT(4)	/* Bank Select */
+#define RTC_CTRL_A_RS2		BIT(2)	/* Rate-Selection Bit 2 */
+#define RTC_CTRL_A_RS3		BIT(3)	/* Rate-Selection Bit 3 */
+#define RTC_CTRL_A_RS1		BIT(1)	/* Rate-Selection Bit 1 */
+#define RTC_CTRL_A_RS0		BIT(0)	/* Rate-Selection Bit 0 */
+#define RTC_CTRL_A_RS_MASK	0x0f	/* RS3 + RS2 + RS1 + RS0 */
+
+/*
+ * Bit names in Control Register B.
+ */
+#define RTC_CTRL_B_SET		BIT(7)	/* SET Bit */
+#define RTC_CTRL_B_PIE		BIT(6)	/* Periodic-Interrupt Enable */
+#define RTC_CTRL_B_AIE		BIT(5)	/* Alarm-Interrupt Enable */
+#define RTC_CTRL_B_UIE		BIT(4)	/* Update-Ended Interrupt-Enable */
+#define RTC_CTRL_B_SQWE		BIT(3)	/* Square-Wave Enable */
+#define RTC_CTRL_B_DM		BIT(2)	/* Data Mode */
+#define RTC_CTRL_B_2412		BIT(1)	/* 12-Hr/24-Hr Mode */
+#define RTC_CTRL_B_DSE		BIT(0)	/* Daylight Savings Enable */
+#define RTC_CTRL_B_PAU_MASK	0x70	/* PIE + AIE + UIE */
+
+
+/*
+ * Bit names in Control Register C.
+ *
+ * BIT(0), BIT(1), BIT(2), & BIT(3) are unused, always return 0, and cannot
+ * be written to.
+ */
+#define RTC_CTRL_C_IRQF		BIT(7)	/* Interrupt-Request Flag */
+#define RTC_CTRL_C_PF		BIT(6)	/* Periodic-Interrupt Flag */
+#define RTC_CTRL_C_AF		BIT(5)	/* Alarm-Interrupt Flag */
+#define RTC_CTRL_C_UF		BIT(4)	/* Update-Ended Interrupt Flag */
+#define RTC_CTRL_C_PAU_MASK	0x70	/* PF + AF + UF */
+
+
+/*
+ * Bit names in Control Register D.
+ *
+ * BIT(0) through BIT(6) are unused, always return 0, and cannot
+ * be written to.
+ */
+#define RTC_CTRL_D_VRT		BIT(7)	/* Valid RAM and Time */
+
+
+/*
+ * Bit names in Extended Control Register 4A.
+ *
+ * On the DS1685/DS1687/DS1689/DS1693, BIT(4) and BIT(5) are reserved for
+ * future use.  They can be read from and written to, but have no effect
+ * on the RTC's operation.
+ *
+ * On the DS17x85/DS17x87, BIT(5) is Burst-Mode Enable (BME), and allows
+ * access to the extended NV-SRAM by automatically incrementing the address
+ * register when they are read from or written to.
+ */
+#define RTC_CTRL_4A_VRT2	BIT(7)	/* Auxillary Battery Status */
+#define RTC_CTRL_4A_INCR	BIT(6)	/* Increment-in-Progress Status */
+#define RTC_CTRL_4A_PAB		BIT(3)	/* Power-Active Bar Control */
+#define RTC_CTRL_4A_RF		BIT(2)	/* RAM-Clear Flag */
+#define RTC_CTRL_4A_WF		BIT(1)	/* Wake-Up Alarm Flag */
+#define RTC_CTRL_4A_KF		BIT(0)	/* Kickstart Flag */
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+#define RTC_CTRL_4A_BME		BIT(5)	/* Burst-Mode Enable */
+#endif
+#define RTC_CTRL_4A_RWK_MASK	0x07	/* RF + WF + KF */
+
+
+/*
+ * Bit names in Extended Control Register 4B.
+ */
+#define RTC_CTRL_4B_ABE		BIT(7)	/* Auxillary Battery Enable */
+#define RTC_CTRL_4B_E32K	BIT(6)	/* Enable 32.768Hz on SQW Pin */
+#define RTC_CTRL_4B_CS		BIT(5)	/* Crystal Select */
+#define RTC_CTRL_4B_RCE		BIT(4)	/* RAM Clear-Enable */
+#define RTC_CTRL_4B_PRS		BIT(3)	/* PAB Reset-Select */
+#define RTC_CTRL_4B_RIE		BIT(2)	/* RAM Clear-Interrupt Enable */
+#define RTC_CTRL_4B_WIE		BIT(1)	/* Wake-Up Alarm-Interrupt Enable */
+#define RTC_CTRL_4B_KSE		BIT(0)	/* Kickstart Interrupt-Enable */
+#define RTC_CTRL_4B_RWK_MASK	0x07	/* RIE + WIE + KSE */
+
+
+/*
+ * Misc register names in Bank 1.
+ *
+ * The DV0 bit in Control Register A must be set to 1 for these registers
+ * to become available, including Extended Control Registers 4A & 4B.
+ */
+#define RTC_BANK1_SSN_MODEL	0x40	/* Model Number */
+#define RTC_BANK1_SSN_BYTE_1	0x41	/* 1st Byte of Serial Number */
+#define RTC_BANK1_SSN_BYTE_2	0x42	/* 2nd Byte of Serial Number */
+#define RTC_BANK1_SSN_BYTE_3	0x43	/* 3rd Byte of Serial Number */
+#define RTC_BANK1_SSN_BYTE_4	0x44	/* 4th Byte of Serial Number */
+#define RTC_BANK1_SSN_BYTE_5	0x45	/* 5th Byte of Serial Number */
+#define RTC_BANK1_SSN_BYTE_6	0x46	/* 6th Byte of Serial Number */
+#define RTC_BANK1_SSN_CRC	0x47	/* Serial CRC Byte */
+#define RTC_BANK1_RAM_DATA_PORT	0x53	/* Extended RAM Data Port */
+
+
+/*
+ * Model-specific registers in Bank 1.
+ *
+ * The addresses below differ depending on the model of the RTC chip
+ * selected in the kernel configuration.  Not all of these features are
+ * supported in the main driver at present.
+ *
+ * DS1685/DS1687   - Extended NV-SRAM address (LSB only).
+ * DS1689/DS1693   - Vcc, Vbat, Pwr Cycle Counters & Customer-specific S/N.
+ * DS17x85/DS17x87 - Extended NV-SRAM addresses (MSB & LSB) & Write counter.
+ */
+#if defined(CONFIG_RTC_DRV_DS1685)
+#define RTC_BANK1_RAM_ADDR	0x50	/* NV-SRAM Addr */
+#elif defined(CONFIG_RTC_DRV_DS1689)
+#define RTC_BANK1_VCC_CTR_LSB	0x54	/* Vcc Counter Addr (LSB) */
+#define RTC_BANK1_VCC_CTR_MSB	0x57	/* Vcc Counter Addr (MSB) */
+#define RTC_BANK1_VBAT_CTR_LSB	0x58	/* Vbat Counter Addr (LSB) */
+#define RTC_BANK1_VBAT_CTR_MSB	0x5b	/* Vbat Counter Addr (MSB) */
+#define RTC_BANK1_PWR_CTR_LSB	0x5c	/* Pwr Cycle Counter Addr (LSB) */
+#define RTC_BANK1_PWR_CTR_MSB	0x5d	/* Pwr Cycle Counter Addr (MSB) */
+#define RTC_BANK1_UNIQ_SN	0x60	/* Customer-specific S/N */
+#else /* DS17x85/DS17x87 */
+#define RTC_BANK1_RAM_ADDR_LSB	0x50	/* NV-SRAM Addr (LSB) */
+#define RTC_BANK1_RAM_ADDR_MSB	0x51	/* NV-SRAM Addr (MSB) */
+#define RTC_BANK1_WRITE_CTR	0x5e	/* RTC Write Counter */
+#endif
+
+
+/*
+ * Model numbers.
+ *
+ * The DS1688/DS1691 and DS1689/DS1693 chips share the same model number
+ * and the manual doesn't indicate any major differences.  As such, they
+ * are regarded as the same chip in this driver.
+ */
+#define RTC_MODEL_DS1685	0x71	/* DS1685/DS1687 */
+#define RTC_MODEL_DS17285	0x72	/* DS17285/DS17287 */
+#define RTC_MODEL_DS1689	0x73	/* DS1688/DS1691/DS1689/DS1693 */
+#define RTC_MODEL_DS17485	0x74	/* DS17485/DS17487 */
+#define RTC_MODEL_DS17885	0x78	/* DS17885/DS17887 */
+
+
+/*
+ * Periodic Interrupt Rates / Square-Wave Output Frequency
+ *
+ * Periodic rates are selected by setting the RS3-RS0 bits in Control
+ * Register A and enabled via either the E32K bit in Extended Control
+ * Register 4B or the SQWE bit in Control Register B.
+ *
+ * E32K overrides the settings of RS3-RS0 and outputs a frequency of 32768Hz
+ * on the SQW pin of the RTC chip.  While there are 16 possible selections,
+ * the 1-of-16 decoder is only able to divide the base 32768Hz signal into 13
+ * smaller frequencies.  The values 0x01 and 0x02 are not used and are
+ * synonymous with 0x08 and 0x09, respectively.
+ *
+ * When E32K is set to a logic 1, periodic interrupts are disabled and reading
+ * /dev/rtc will return -EINVAL.  This also applies if the periodic interrupt
+ * frequency is set to 0Hz.
+ *
+ * Not currently used by the rtc-ds1685 driver because the RTC core removed
+ * support for hardware-generated periodic-interrupts in favour of
+ * hrtimer-generated interrupts.  But these defines are kept around for use
+ * in userland, as documentation to the hardware, and possible future use if
+ * hardware-generated periodic interrupts are ever added back.
+ */
+					/* E32K RS3 RS2 RS1 RS0 */
+#define RTC_SQW_8192HZ		0x03	/*  0    0   0   1   1  */
+#define RTC_SQW_4096HZ		0x04	/*  0    0   1   0   0  */
+#define RTC_SQW_2048HZ		0x05	/*  0    0   1   0   1  */
+#define RTC_SQW_1024HZ		0x06	/*  0    0   1   1   0  */
+#define RTC_SQW_512HZ		0x07	/*  0    0   1   1   1  */
+#define RTC_SQW_256HZ		0x08	/*  0    1   0   0   0  */
+#define RTC_SQW_128HZ		0x09	/*  0    1   0   0   1  */
+#define RTC_SQW_64HZ		0x0a	/*  0    1   0   1   0  */
+#define RTC_SQW_32HZ		0x0b	/*  0    1   0   1   1  */
+#define RTC_SQW_16HZ		0x0c	/*  0    1   1   0   0  */
+#define RTC_SQW_8HZ		0x0d	/*  0    1   1   0   1  */
+#define RTC_SQW_4HZ		0x0e	/*  0    1   1   1   0  */
+#define RTC_SQW_2HZ		0x0f	/*  0    1   1   1   1  */
+#define RTC_SQW_0HZ		0x00	/*  0    0   0   0   0  */
+#define RTC_SQW_32768HZ		32768	/*  1    -   -   -   -  */
+#define RTC_MAX_USER_FREQ	8192
+
+
+/*
+ * NVRAM data & addresses:
+ *   - 50 bytes of NVRAM are available just past the clock registers.
+ *   - 64 additional bytes are available in Bank0.
+ *
+ * Extended, battery-backed NV-SRAM:
+ *   - DS1685/DS1687    - 128 bytes.
+ *   - DS1689/DS1693    - 0 bytes.
+ *   - DS17285/DS17287  - 2048 bytes.
+ *   - DS17485/DS17487  - 4096 bytes.
+ *   - DS17885/DS17887  - 8192 bytes.
+ */
+#define NVRAM_TIME_BASE		0x0e	/* NVRAM Addr in Time regs */
+#define NVRAM_BANK0_BASE	0x40	/* NVRAM Addr in Bank0 regs */
+#define NVRAM_SZ_TIME		50
+#define NVRAM_SZ_BANK0		64
+#if defined(CONFIG_RTC_DRV_DS1685)
+#  define NVRAM_SZ_EXTND	128
+#elif defined(CONFIG_RTC_DRV_DS1689)
+#  define NVRAM_SZ_EXTND	0
+#elif defined(CONFIG_RTC_DRV_DS17285)
+#  define NVRAM_SZ_EXTND	2048
+#elif defined(CONFIG_RTC_DRV_DS17485)
+#  define NVRAM_SZ_EXTND	4096
+#elif defined(CONFIG_RTC_DRV_DS17885)
+#  define NVRAM_SZ_EXTND	8192
+#endif
+#define NVRAM_TOTAL_SZ_BANK0	(NVRAM_SZ_TIME + NVRAM_SZ_BANK0)
+#define NVRAM_TOTAL_SZ		(NVRAM_TOTAL_SZ_BANK0 + NVRAM_SZ_EXTND)
+
+
+/*
+ * Function Prototypes.
+ */
+extern void __noreturn
+ds1685_rtc_poweroff(struct platform_device *pdev);
+
+#endif /* _LINUX_RTC_DS1685_H_ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 048b91b..41c60e5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1664,6 +1664,9 @@
 	unsigned long timer_slack_ns;
 	unsigned long default_timer_slack_ns;
 
+#ifdef CONFIG_KASAN
+	unsigned int kasan_depth;
+#endif
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	/* Index of current stored address in ret_stack */
 	int curr_ret_stack;
diff --git a/include/linux/security.h b/include/linux/security.h
index ba96471..a1b7dbd 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1281,6 +1281,25 @@
  *	@alter contains the flag indicating whether changes are to be made.
  *	Return 0 if permission is granted.
  *
+ * @binder_set_context_mgr
+ *	Check whether @mgr is allowed to be the binder context manager.
+ *	@mgr contains the task_struct for the task being registered.
+ *	Return 0 if permission is granted.
+ * @binder_transaction
+ *	Check whether @from is allowed to invoke a binder transaction call
+ *	to @to.
+ *	@from contains the task_struct for the sending task.
+ *	@to contains the task_struct for the receiving task.
+ * @binder_transfer_binder
+ *	Check whether @from is allowed to transfer a binder reference to @to.
+ *	@from contains the task_struct for the sending task.
+ *	@to contains the task_struct for the receiving task.
+ * @binder_transfer_file
+ *	Check whether @from is allowed to transfer @file to @to.
+ *	@from contains the task_struct for the sending task.
+ *	@file contains the struct file being transferred.
+ *	@to contains the task_struct for the receiving task.
+ *
  * @ptrace_access_check:
  *	Check permission before allowing the current process to trace the
  *	@child process.
@@ -1441,6 +1460,14 @@
 struct security_operations {
 	char name[SECURITY_NAME_MAX + 1];
 
+	int (*binder_set_context_mgr) (struct task_struct *mgr);
+	int (*binder_transaction) (struct task_struct *from,
+				   struct task_struct *to);
+	int (*binder_transfer_binder) (struct task_struct *from,
+				       struct task_struct *to);
+	int (*binder_transfer_file) (struct task_struct *from,
+				     struct task_struct *to, struct file *file);
+
 	int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
 	int (*ptrace_traceme) (struct task_struct *parent);
 	int (*capget) (struct task_struct *target,
@@ -1739,6 +1766,13 @@
 
 
 /* Security operations */
+int security_binder_set_context_mgr(struct task_struct *mgr);
+int security_binder_transaction(struct task_struct *from,
+				struct task_struct *to);
+int security_binder_transfer_binder(struct task_struct *from,
+				    struct task_struct *to);
+int security_binder_transfer_file(struct task_struct *from,
+				  struct task_struct *to, struct file *file);
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
@@ -1927,6 +1961,30 @@
 	return 0;
 }
 
+static inline int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static inline int security_binder_transaction(struct task_struct *from,
+					      struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_binder(struct task_struct *from,
+						  struct task_struct *to)
+{
+	return 0;
+}
+
+static inline int security_binder_transfer_file(struct task_struct *from,
+						struct task_struct *to,
+						struct file *file)
+{
+	return 0;
+}
+
 static inline int security_ptrace_access_check(struct task_struct *child,
 					     unsigned int mode)
 {
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 9aafe0e..fb7eb9c 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -125,9 +125,6 @@
 			      unsigned int len);
 extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc);
 
-extern int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
-			   int nmaskbits);
-
 #ifdef CONFIG_BINARY_PRINTF
 extern int
 seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary);
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index cf6a9da..afbb1fd 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -126,31 +126,6 @@
 int seq_dentry(struct seq_file *, struct dentry *, const char *);
 int seq_path_root(struct seq_file *m, const struct path *path,
 		  const struct path *root, const char *esc);
-int seq_bitmap(struct seq_file *m, const unsigned long *bits,
-				   unsigned int nr_bits);
-static inline int seq_cpumask(struct seq_file *m, const struct cpumask *mask)
-{
-	return seq_bitmap(m, cpumask_bits(mask), nr_cpu_ids);
-}
-
-static inline int seq_nodemask(struct seq_file *m, nodemask_t *mask)
-{
-	return seq_bitmap(m, mask->bits, MAX_NUMNODES);
-}
-
-int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
-		unsigned int nr_bits);
-
-static inline int seq_cpumask_list(struct seq_file *m,
-				   const struct cpumask *mask)
-{
-	return seq_bitmap_list(m, cpumask_bits(mask), nr_cpu_ids);
-}
-
-static inline int seq_nodemask_list(struct seq_file *m, nodemask_t *mask)
-{
-	return seq_bitmap_list(m, mask->bits, MAX_NUMNODES);
-}
 
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_open_size(struct file *, int (*)(struct seq_file *, void *), void *, size_t);
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index e02acf0..a8efa23 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -85,6 +85,9 @@
 	unsigned char		mcr_force;	/* mask of forced bits */
 	unsigned char		cur_iotype;	/* Running I/O type */
 	unsigned int		rpm_tx_active;
+	unsigned char		canary;		/* non-zero during system sleep
+						 *   if no_console_suspend
+						 */
 
 	/*
 	 * Some bits in registers are cleared on a read, so they must
@@ -126,6 +129,7 @@
 extern void serial8250_do_shutdown(struct uart_port *port);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
 			     unsigned int oldstate);
+extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
 extern int fsl8250_handle_irq(struct uart_port *port);
 int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
 unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 057038c..baf3e1d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -123,6 +123,7 @@
 	void			(*set_termios)(struct uart_port *,
 				               struct ktermios *new,
 				               struct ktermios *old);
+	void			(*set_mctrl)(struct uart_port *, unsigned int);
 	int			(*startup)(struct uart_port *port);
 	void			(*shutdown)(struct uart_port *port);
 	void			(*throttle)(struct uart_port *port);
@@ -190,8 +191,10 @@
 #define UPF_NO_TXEN_TEST	((__force upf_t) (1 << 15))
 #define UPF_MAGIC_MULTIPLIER	((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
 
-/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
-#define UPF_HARD_FLOW		((__force upf_t) (1 << 21))
+/* Port has hardware-assisted h/w flow control */
+#define UPF_AUTO_CTS		((__force upf_t) (1 << 20))
+#define UPF_AUTO_RTS		((__force upf_t) (1 << 21))
+#define UPF_HARD_FLOW		((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
 /* Port has hardware-assisted s/w flow control */
 #define UPF_SOFT_FLOW		((__force upf_t) (1 << 22))
 #define UPF_CONS_FLOW		((__force upf_t) (1 << 23))
@@ -213,11 +216,17 @@
 #error Change mask not equivalent to userspace-visible bit defines
 #endif
 
-	/* status must be updated while holding port lock */
+	/*
+	 * Must hold termios_rwsem, port mutex and port lock to change;
+	 * can hold any one lock to read.
+	 */
 	upstat_t		status;
 
 #define UPSTAT_CTS_ENABLE	((__force upstat_t) (1 << 0))
 #define UPSTAT_DCD_ENABLE	((__force upstat_t) (1 << 1))
+#define UPSTAT_AUTORTS		((__force upstat_t) (1 << 2))
+#define UPSTAT_AUTOCTS		((__force upstat_t) (1 << 3))
+#define UPSTAT_AUTOXOFF		((__force upstat_t) (1 << 4))
 
 	int			hw_stopped;		/* sw-assisted CTS flow state */
 	unsigned int		mctrl;			/* current modem ctrl settings */
@@ -391,6 +400,13 @@
 	return !!(uport->status & UPSTAT_CTS_ENABLE);
 }
 
+static inline bool uart_softcts_mode(struct uart_port *uport)
+{
+	upstat_t mask = UPSTAT_CTS_ENABLE | UPSTAT_AUTOCTS;
+
+	return ((uport->status & mask) == UPSTAT_CTS_ENABLE);
+}
+
 /*
  * The following are helper functions for the low level drivers.
  */
diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
index e6fc956..a7f004a 100644
--- a/include/linux/serial_s3c.h
+++ b/include/linux/serial_s3c.h
@@ -104,6 +104,31 @@
 				   S3C2410_UCON_RXIRQMODE | \
 				   S3C2410_UCON_RXFIFO_TOI)
 
+#define S3C64XX_UCON_TXBURST_1          (0<<20)
+#define S3C64XX_UCON_TXBURST_4          (1<<20)
+#define S3C64XX_UCON_TXBURST_8          (2<<20)
+#define S3C64XX_UCON_TXBURST_16         (3<<20)
+#define S3C64XX_UCON_TXBURST_MASK       (0xf<<20)
+#define S3C64XX_UCON_RXBURST_1          (0<<16)
+#define S3C64XX_UCON_RXBURST_4          (1<<16)
+#define S3C64XX_UCON_RXBURST_8          (2<<16)
+#define S3C64XX_UCON_RXBURST_16         (3<<16)
+#define S3C64XX_UCON_RXBURST_MASK       (0xf<<16)
+#define S3C64XX_UCON_TIMEOUT_SHIFT      (12)
+#define S3C64XX_UCON_TIMEOUT_MASK       (0xf<<12)
+#define S3C64XX_UCON_EMPTYINT_EN        (1<<11)
+#define S3C64XX_UCON_DMASUS_EN          (1<<10)
+#define S3C64XX_UCON_TXINT_LEVEL        (1<<9)
+#define S3C64XX_UCON_RXINT_LEVEL        (1<<8)
+#define S3C64XX_UCON_TIMEOUT_EN         (1<<7)
+#define S3C64XX_UCON_ERRINT_EN          (1<<6)
+#define S3C64XX_UCON_TXMODE_DMA         (2<<2)
+#define S3C64XX_UCON_TXMODE_CPU         (1<<2)
+#define S3C64XX_UCON_TXMODE_MASK        (3<<2)
+#define S3C64XX_UCON_RXMODE_DMA         (2<<0)
+#define S3C64XX_UCON_RXMODE_CPU         (1<<0)
+#define S3C64XX_UCON_RXMODE_MASK        (3<<0)
+
 #define S3C2410_UFCON_FIFOMODE	  (1<<0)
 #define S3C2410_UFCON_TXTRIG0	  (0<<6)
 #define S3C2410_UFCON_RXTRIG8	  (1<<4)
@@ -155,6 +180,7 @@
 #define S3C2440_UFSTAT_TXMASK	  (63<<8)
 #define S3C2440_UFSTAT_RXMASK	  (63)
 
+#define S3C2410_UTRSTAT_TIMEOUT   (1<<3)
 #define S3C2410_UTRSTAT_TXE	  (1<<2)
 #define S3C2410_UTRSTAT_TXFE	  (1<<1)
 #define S3C2410_UTRSTAT_RXDR	  (1<<0)
@@ -179,8 +205,10 @@
 #define S3C64XX_UINTM		0x38
 
 #define S3C64XX_UINTM_RXD	(0)
+#define S3C64XX_UINTM_ERROR     (1)
 #define S3C64XX_UINTM_TXD	(2)
 #define S3C64XX_UINTM_RXD_MSK	(1 << S3C64XX_UINTM_RXD)
+#define S3C64XX_UINTM_ERR_MSK   (1 << S3C64XX_UINTM_ERROR)
 #define S3C64XX_UINTM_TXD_MSK	(1 << S3C64XX_UINTM_TXD)
 
 /* Following are specific to S5PV210 */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index ed2ffaa..76f1fee 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -104,6 +104,7 @@
 				(unsigned long)ZERO_SIZE_PTR)
 
 #include <linux/kmemleak.h>
+#include <linux/kasan.h>
 
 struct mem_cgroup;
 /*
@@ -325,7 +326,10 @@
 static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
 		gfp_t flags, size_t size)
 {
-	return kmem_cache_alloc(s, flags);
+	void *ret = kmem_cache_alloc(s, flags);
+
+	kasan_kmalloc(s, ret, size);
+	return ret;
 }
 
 static __always_inline void *
@@ -333,7 +337,10 @@
 			      gfp_t gfpflags,
 			      int node, size_t size)
 {
-	return kmem_cache_alloc_node(s, gfpflags, node);
+	void *ret = kmem_cache_alloc_node(s, gfpflags, node);
+
+	kasan_kmalloc(s, ret, size);
+	return ret;
 }
 #endif /* CONFIG_TRACING */
 
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 9abf04e..3388511 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -110,4 +110,23 @@
 }
 #endif
 
+
+/**
+ * virt_to_obj - returns address of the beginning of object.
+ * @s: object's kmem_cache
+ * @slab_page: address of slab page
+ * @x: address within object memory range
+ *
+ * Returns address of the beginning of object
+ */
+static inline void *virt_to_obj(struct kmem_cache *s,
+				const void *slab_page,
+				const void *x)
+{
+	return (void *)x - ((x - slab_page) % s->size);
+}
+
+void object_err(struct kmem_cache *s, struct page *page,
+		u8 *object, char *reason);
+
 #endif /* _LINUX_SLUB_DEF_H */
diff --git a/include/linux/string.h b/include/linux/string.h
index b9bc9a5..e40099e 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -112,7 +112,10 @@
 #endif
 void *memchr_inv(const void *s, int c, size_t n);
 
+extern void kfree_const(const void *x);
+
 extern char *kstrdup(const char *s, gfp_t gfp);
+extern const char *kstrdup_const(const char *s, gfp_t gfp);
 extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
 
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index 884d626..c78dcfe 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -86,6 +86,7 @@
 extern long st_register(struct st_proto_s *);
 extern long st_unregister(struct st_proto_s *);
 
+extern struct ti_st_plat_data   *dt_pdata;
 
 /*
  * header information used by st_core.c
@@ -261,7 +262,7 @@
 	struct completion kim_rcvd, ldisc_installed;
 	char resp_buffer[30];
 	const struct firmware *fw_entry;
-	long nshutdown;
+	unsigned nshutdown;
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
@@ -269,8 +270,8 @@
 	struct chip_version version;
 	unsigned char ldisc_install;
 	unsigned char dev_name[UART_DEV_NAME_LEN + 1];
-	unsigned char flow_cntrl;
-	unsigned long baud_rate;
+	unsigned flow_cntrl;
+	unsigned baud_rate;
 };
 
 /**
@@ -436,10 +437,10 @@
  *
  */
 struct ti_st_plat_data {
-	long nshutdown_gpio;
+	u32 nshutdown_gpio;
 	unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */
-	unsigned char flow_cntrl; /* flow control flag */
-	unsigned long baud_rate;
+	u32 flow_cntrl; /* flow control flag */
+	u32 baud_rate;
 	int (*suspend)(struct platform_device *, pm_message_t);
 	int (*resume)(struct platform_device *);
 	int (*chip_enable) (struct kim_data_s *);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 7d66ae5..358a337 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -14,6 +14,29 @@
 #include <linux/llist.h>
 
 
+/*
+ * Lock subclasses for tty locks
+ *
+ * TTY_LOCK_NORMAL is for normal ttys and master ptys.
+ * TTY_LOCK_SLAVE is for slave ptys only.
+ *
+ * Lock subclasses are necessary for handling nested locking with pty pairs.
+ * tty locks which use nested locking:
+ *
+ * legacy_mutex - Nested tty locks are necessary for releasing pty pairs.
+ *		  The stable lock order is master pty first, then slave pty.
+ * termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem.
+ *		   Subclassing this lock enables the slave pty to hold its
+ *		   termios_rwsem when claiming the master tty_buffer lock.
+ * tty_buffer lock - slave ptys can claim nested buffer lock when handling
+ *		     signal chars. The stable lock order is slave pty, then
+ *		     master.
+ */
+
+enum {
+	TTY_LOCK_NORMAL = 0,
+	TTY_LOCK_SLAVE,
+};
 
 /*
  * (Note: the *_driver.minor_start values 1, 64, 128, 192 are
@@ -443,6 +466,7 @@
 extern void tty_buffer_free_all(struct tty_port *port);
 extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
 extern void tty_buffer_init(struct tty_port *port);
+extern void tty_buffer_set_lock_subclass(struct tty_port *port);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
 extern void tty_termios_encode_baud_rate(struct ktermios *termios,
@@ -467,7 +491,6 @@
 
 extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
 extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
-extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
 
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index f89c24a..7ee1b5c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -82,7 +82,7 @@
 	int extralen;
 	unsigned char *extra;   /* Extra descriptors */
 
-	/* array of desc.bNumEndpoint endpoints associated with this
+	/* array of desc.bNumEndpoints endpoints associated with this
 	 * interface setting.  these will be in no particular order.
 	 */
 	struct usb_host_endpoint *endpoint;
@@ -127,10 +127,6 @@
  *	to the sysfs representation for that device.
  * @pm_usage_cnt: PM usage counter for this interface
  * @reset_ws: Used for scheduling resets from atomic context.
- * @reset_running: set to 1 if the interface is currently running a
- *      queued reset so that usb_cancel_queued_reset() doesn't try to
- *      remove from the workqueue when running inside the worker
- *      thread. See __usb_queue_reset_device().
  * @resetting_device: USB core reset the device, so use alt setting 0 as
  *	current; needs bandwidth alloc after reset.
  *
@@ -181,7 +177,6 @@
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
 	unsigned needs_altsetting0:1;	/* switch to altsetting 0 is pending */
 	unsigned needs_binding:1;	/* needs delayed unbind/rebind */
-	unsigned reset_running:1;
 	unsigned resetting_device:1;	/* true: bandwidth alloc after reset */
 
 	struct device dev;		/* interface specific device info */
diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h
index 7eb4dcd..db0431b 100644
--- a/include/linux/usb/ehci_pdriver.h
+++ b/include/linux/usb/ehci_pdriver.h
@@ -34,6 +34,8 @@
  *			after initialization.
  * @no_io_watchdog:	set to 1 if the controller does not need the I/O
  *			watchdog to run.
+ * @reset_on_resume:	set to 1 if the controller needs to be reset after
+ * 			a suspend / resume cycle (but can't detect that itself).
  *
  * These are general configuration options for the EHCI controller. All of
  * these options are activating more or less workarounds for some hardware.
@@ -45,6 +47,8 @@
 	unsigned	big_endian_desc:1;
 	unsigned	big_endian_mmio:1;
 	unsigned	no_io_watchdog:1;
+	unsigned	reset_on_resume:1;
+	unsigned	dma_mask_64:1;
 
 	/* Turn on all power and clocks */
 	int (*power_on)(struct platform_device *pdev);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 70ddb39..e2f00fd 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -523,6 +523,7 @@
  *	enabled HNP support.
  * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
  *	MaxPacketSize.
+ * @is_selfpowered: if the gadget is self-powered.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -563,6 +564,7 @@
 	unsigned			a_hnp_support:1;
 	unsigned			a_alt_hnp_support:1;
 	unsigned			quirk_ep_out_aligned_size:1;
+	unsigned			is_selfpowered:1;
 };
 #define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
 
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 086bf13..68b1e83 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -146,6 +146,8 @@
 	unsigned		amd_resume_bug:1; /* AMD remote wakeup quirk */
 	unsigned		can_do_streams:1; /* HC supports streams */
 	unsigned		tpl_support:1; /* OTG & EH TPL support */
+	unsigned		cant_recv_wakeups:1;
+			/* wakeup requests from downstream aren't received */
 
 	unsigned int		irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
@@ -453,6 +455,7 @@
 #endif /* CONFIG_PCI */
 
 /* pci-ish (pdev null is ok) buffer alloc/mapping support */
+void usb_init_pool_max(void);
 int hcd_buffer_create(struct usb_hcd *hcd);
 void hcd_buffer_destroy(struct usb_hcd *hcd);
 
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index f499c23..bc91b5d 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -1,5 +1,5 @@
-/* USB OTG (On The Go) defines */
 /*
+ * USB PHY defines
  *
  * These APIs may be used between USB controllers.  USB device drivers
  * (for either host or peripheral roles) don't use these calls; they
@@ -106,7 +106,7 @@
 	int	(*set_power)(struct usb_phy *x,
 				unsigned mA);
 
-	/* for non-OTG B devices: set transceiver into suspend mode */
+	/* Set transceiver into suspend mode */
 	int	(*set_suspend)(struct usb_phy *x,
 				int suspend);
 
diff --git a/include/linux/usb/usb_phy_generic.h b/include/linux/usb/usb_phy_generic.h
index 68adae8..c13632d5 100644
--- a/include/linux/usb/usb_phy_generic.h
+++ b/include/linux/usb/usb_phy_generic.h
@@ -2,6 +2,7 @@
 #define __LINUX_USB_NOP_XCEIV_H
 
 #include <linux/usb/otg.h>
+#include <linux/gpio/consumer.h>
 
 struct usb_phy_generic_platform_data {
 	enum usb_phy_type type;
@@ -11,6 +12,7 @@
 	unsigned int needs_vcc:1;
 	unsigned int needs_reset:1;	/* deprecated */
 	int gpio_reset;
+	struct gpio_desc *gpiod_vbus;
 };
 
 #if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index b87696f..7d7acb3 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -16,6 +16,7 @@
 #define VM_USERMAP		0x00000008	/* suitable for remap_vmalloc_range */
 #define VM_VPAGES		0x00000010	/* buffer for pages was vmalloc'ed */
 #define VM_UNINITIALIZED	0x00000020	/* vm_struct is not fully initialized */
+#define VM_NO_GUARD		0x00000040      /* don't add guard page */
 /* bits [20..32] reserved for arch specific ioremap internals */
 
 /*
@@ -75,7 +76,9 @@
 extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
 extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
 			unsigned long start, unsigned long end, gfp_t gfp_mask,
-			pgprot_t prot, int node, const void *caller);
+			pgprot_t prot, unsigned long vm_flags, int node,
+			const void *caller);
+
 extern void vfree(const void *addr);
 
 extern void *vmap(struct page **pages, unsigned int count,
@@ -96,8 +99,12 @@
 
 static inline size_t get_vm_area_size(const struct vm_struct *area)
 {
-	/* return actual size without guard page */
-	return area->size - PAGE_SIZE;
+	if (!(area->flags & VM_NO_GUARD))
+		/* return actual size without guard page */
+		return area->size - PAGE_SIZE;
+	else
+		return area->size;
+
 }
 
 extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h
index 057db7d..f38c10b 100644
--- a/include/linux/vt_buffer.h
+++ b/include/linux/vt_buffer.h
@@ -21,10 +21,6 @@
 #ifndef VT_BUF_HAVE_RW
 #define scr_writew(val, addr) (*(addr) = (val))
 #define scr_readw(addr) (*(addr))
-#define scr_memcpyw(d, s, c) memcpy(d, s, c)
-#define scr_memmovew(d, s, c) memmove(d, s, c)
-#define VT_BUF_HAVE_MEMCPYW
-#define VT_BUF_HAVE_MEMMOVEW
 #endif
 
 #ifndef VT_BUF_HAVE_MEMSETW
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h
index 8e12494..b5f7b5f 100644
--- a/include/soc/tegra/fuse.h
+++ b/include/soc/tegra/fuse.h
@@ -21,6 +21,7 @@
 #define TEGRA30		0x30
 #define TEGRA114	0x35
 #define TEGRA124	0x40
+#define TEGRA132	0x13
 
 #define TEGRA_FUSE_SKU_CALIB_0	0xf0
 #define TEGRA30_FUSE_SATA_CALIB	0x124
diff --git a/include/soc/tegra/pm.h b/include/soc/tegra/pm.h
index 30fe207..0390910 100644
--- a/include/soc/tegra/pm.h
+++ b/include/soc/tegra/pm.h
@@ -17,7 +17,7 @@
 	TEGRA_MAX_SUSPEND_MODE,
 };
 
-#ifdef CONFIG_PM_SLEEP
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
 enum tegra_suspend_mode
 tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
 
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index b0b8556..01b2d6d 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -654,6 +654,13 @@
  */
 #define DRM_CLIENT_CAP_UNIVERSAL_PLANES  2
 
+/**
+ * DRM_CLIENT_CAP_ATOMIC
+ *
+ * If set to 1, the DRM core will expose atomic properties to userspace
+ */
+#define DRM_CLIENT_CAP_ATOMIC	3
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
 	__u64 capability;
@@ -777,6 +784,7 @@
 #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES	DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
 #define DRM_IOCTL_MODE_CURSOR2		DRM_IOWR(0xBB, struct drm_mode_cursor2)
+#define DRM_IOCTL_MODE_ATOMIC		DRM_IOWR(0xBC, struct drm_mode_atomic)
 
 /**
  * Device specific ioctls should only be in their respective headers
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 646ae5f..a284f11 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -109,9 +109,6 @@
 #define DRM_FORMAT_NV24		fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
 #define DRM_FORMAT_NV42		fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
 
-/* special NV12 tiled format */
-#define DRM_FORMAT_NV12MT	fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */
-
 /*
  * 3 plane YCbCr
  * index 0: Y plane, [7:0] Y
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 86574b0..ca788e0 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -272,6 +272,13 @@
 #define DRM_MODE_PROP_OBJECT		DRM_MODE_PROP_TYPE(1)
 #define DRM_MODE_PROP_SIGNED_RANGE	DRM_MODE_PROP_TYPE(2)
 
+/* the PROP_ATOMIC flag is used to hide properties from userspace that
+ * is not aware of atomic properties.  This is mostly to work around
+ * older userspace (DDX drivers) that read/write each prop they find,
+ * witout being aware that this could be triggering a lengthy modeset.
+ */
+#define DRM_MODE_PROP_ATOMIC        0x80000000
+
 struct drm_mode_property_enum {
 	__u64 value;
 	char name[DRM_PROP_NAME_LEN];
@@ -338,7 +345,7 @@
 
 	/*
 	 * In case of planar formats, this ioctl allows up to 4
-	 * buffer objects with offets and pitches per plane.
+	 * buffer objects with offsets and pitches per plane.
 	 * The pitch and offset order is dictated by the fourcc,
 	 * e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
 	 *
@@ -346,9 +353,9 @@
 	 *   followed by an interleaved U/V plane containing
 	 *   8 bit 2x2 subsampled colour difference samples.
 	 *
-	 * So it would consist of Y as offset[0] and UV as
-	 * offeset[1].  Note that offset[0] will generally
-	 * be 0.
+	 * So it would consist of Y as offsets[0] and UV as
+	 * offsets[1].  Note that offsets[0] will generally
+	 * be 0 (but this is not required).
 	 */
 	__u32 handles[4];
 	__u32 pitches[4]; /* pitch for each plane */
@@ -519,4 +526,27 @@
 	uint32_t handle;
 };
 
+/* page-flip flags are valid, plus: */
+#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
+#define DRM_MODE_ATOMIC_NONBLOCK  0x0200
+#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400
+
+#define DRM_MODE_ATOMIC_FLAGS (\
+		DRM_MODE_PAGE_FLIP_EVENT |\
+		DRM_MODE_PAGE_FLIP_ASYNC |\
+		DRM_MODE_ATOMIC_TEST_ONLY |\
+		DRM_MODE_ATOMIC_NONBLOCK |\
+		DRM_MODE_ATOMIC_ALLOW_MODESET)
+
+struct drm_mode_atomic {
+	__u32 flags;
+	__u32 count_objs;
+	__u64 objs_ptr;
+	__u64 count_props_ptr;
+	__u64 props_ptr;
+	__u64 prop_values_ptr;
+	__u64 reserved;
+	__u64 user_data;
+};
+
 #endif
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 2502622..6eed16b 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -224,6 +224,8 @@
 #define DRM_I915_REG_READ		0x31
 #define DRM_I915_GET_RESET_STATS	0x32
 #define DRM_I915_GEM_USERPTR		0x33
+#define DRM_I915_GEM_CONTEXT_GETPARAM	0x34
+#define DRM_I915_GEM_CONTEXT_SETPARAM	0x35
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -275,6 +277,8 @@
 #define DRM_IOCTL_I915_REG_READ			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
 #define DRM_IOCTL_I915_GET_RESET_STATS		DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats)
 #define DRM_IOCTL_I915_GEM_USERPTR			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr)
+#define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
+#define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -341,6 +345,8 @@
 #define I915_PARAM_HAS_WT     	 	 27
 #define I915_PARAM_CMD_PARSER_VERSION	 28
 #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29
+#define I915_PARAM_MMAP_VERSION          30
+#define I915_PARAM_HAS_BSD2		 31
 
 typedef struct drm_i915_getparam {
 	int param;
@@ -488,6 +494,14 @@
 	 * This is a fixed-size type for 32/64 compatibility.
 	 */
 	__u64 addr_ptr;
+
+	/**
+	 * Flags for extended behaviour.
+	 *
+	 * Added in version 2.
+	 */
+	__u64 flags;
+#define I915_MMAP_WC 0x1
 };
 
 struct drm_i915_gem_mmap_gtt {
@@ -737,7 +751,13 @@
  */
 #define I915_EXEC_HANDLE_LUT		(1<<12)
 
-#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_HANDLE_LUT<<1)
+/** Used for switching BSD rings on the platforms with two BSD rings */
+#define I915_EXEC_BSD_MASK		(3<<13)
+#define I915_EXEC_BSD_DEFAULT		(0<<13) /* default ping-pong mode */
+#define I915_EXEC_BSD_RING1		(1<<13)
+#define I915_EXEC_BSD_RING2		(2<<13)
+
+#define __I915_EXEC_UNKNOWN_FLAGS -(1<<15)
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
@@ -1073,4 +1093,12 @@
 	__u32 handle;
 };
 
+struct drm_i915_gem_context_param {
+	__u32 ctx_id;
+	__u32 size;
+	__u64 param;
+#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1
+	__u64 value;
+};
+
 #endif /* _UAPI_I915_DRM_H_ */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index c172180..b212281 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -55,7 +55,8 @@
 #define PORT_ALTR_16550_F64 27	/* Altera 16550 UART with 64 FIFOs */
 #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
 #define PORT_RT2880	29	/* Ralink RT2880 internal UART */
-#define PORT_MAX_8250	29	/* max port ID */
+#define PORT_16550A_FSL64 30	/* Freescale 16550 UART with 64 FIFOs */
+#define PORT_MAX_8250	30	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
@@ -248,4 +249,13 @@
 /* MESON */
 #define PORT_MESON	109
 
+/* Conexant Digicolor */
+#define PORT_DIGICOLOR	110
+
+/* SPRD SERIAL  */
+#define PORT_SPRD	111
+
+/* Cris v10 / v32 SoC */
+#define PORT_CRIS	112
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h
index 53af3b7..00adb01 100644
--- a/include/uapi/linux/serial_reg.h
+++ b/include/uapi/linux/serial_reg.h
@@ -86,7 +86,8 @@
 #define UART_FCR6_T_TRIGGER_8	0x10 /* Mask for transmit trigger set at 8 */
 #define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
 #define UART_FCR6_T_TRIGGER_30	0x30 /* Mask for transmit trigger set at 30 */
-#define UART_FCR7_64BYTE	0x20 /* Go into 64 byte mode (TI16C750) */
+#define UART_FCR7_64BYTE	0x20 /* Go into 64 byte mode (TI16C750 and
+					some Freescale UARTs) */
 
 #define UART_FCR_R_TRIG_SHIFT		6
 #define UART_FCR_R_TRIG_BITS(x)		\
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index 295ba29..108dd79 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -20,6 +20,7 @@
 	FUNCTIONFS_HAS_SS_DESC = 4,
 	FUNCTIONFS_HAS_MS_OS_DESC = 8,
 	FUNCTIONFS_VIRTUAL_ADDR = 16,
+	FUNCTIONFS_EVENTFD = 32,
 };
 
 /* Descriptor of an non-audio endpoint */
diff --git a/include/uapi/linux/usbdevice_fs.h b/include/uapi/linux/usbdevice_fs.h
index abe5f4b..019ba1e 100644
--- a/include/uapi/linux/usbdevice_fs.h
+++ b/include/uapi/linux/usbdevice_fs.h
@@ -128,11 +128,12 @@
 	char port [127];	/* e.g. port 3 connects to device 27 */
 };
 
-/* Device capability flags */
+/* System and bus capability flags */
 #define USBDEVFS_CAP_ZERO_PACKET		0x01
 #define USBDEVFS_CAP_BULK_CONTINUATION		0x02
 #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM		0x04
 #define USBDEVFS_CAP_BULK_SCATTER_GATHER	0x08
+#define USBDEVFS_CAP_REAP_AFTER_DISCONNECT	0x10
 
 /* USBDEVFS_DISCONNECT_CLAIM flags & struct */
 
diff --git a/include/video/exynos7_decon.h b/include/video/exynos7_decon.h
new file mode 100644
index 0000000..a62b11b
--- /dev/null
+++ b/include/video/exynos7_decon.h
@@ -0,0 +1,349 @@
+/* include/video/exynos7_decon.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Ajay Kumar <ajaykumar.rs@samsung.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.
+ */
+
+/* VIDCON0 */
+#define VIDCON0					0x00
+
+#define VIDCON0_SWRESET				(1 << 28)
+#define VIDCON0_DECON_STOP_STATUS		(1 << 2)
+#define VIDCON0_ENVID				(1 << 1)
+#define VIDCON0_ENVID_F				(1 << 0)
+
+/* VIDOUTCON0 */
+#define VIDOUTCON0				0x4
+
+#define VIDOUTCON0_DUAL_MASK			(0x3 << 24)
+#define VIDOUTCON0_DUAL_ON			(0x3 << 24)
+#define VIDOUTCON0_DISP_IF_1_ON			(0x2 << 24)
+#define VIDOUTCON0_DISP_IF_0_ON			(0x1 << 24)
+#define VIDOUTCON0_DUAL_OFF			(0x0 << 24)
+#define VIDOUTCON0_IF_SHIFT			23
+#define VIDOUTCON0_IF_MASK			(0x1 << 23)
+#define VIDOUTCON0_RGBIF			(0x0 << 23)
+#define VIDOUTCON0_I80IF			(0x1 << 23)
+
+/* VIDCON3 */
+#define VIDCON3					0x8
+
+/* VIDCON4 */
+#define VIDCON4					0xC
+#define VIDCON4_FIFOCNT_START_EN		(1 << 0)
+
+/* VCLKCON0 */
+#define VCLKCON0				0x10
+#define VCLKCON0_CLKVALUP			(1 << 8)
+#define VCLKCON0_VCLKFREE			(1 << 0)
+
+/* VCLKCON */
+#define VCLKCON1				0x14
+#define VCLKCON1_CLKVAL_NUM_VCLK(val)		(((val) & 0xff) << 0)
+#define VCLKCON2				0x18
+
+/* SHADOWCON */
+#define SHADOWCON				0x30
+
+#define SHADOWCON_WINx_PROTECT(_win)		(1 << (10 + (_win)))
+
+/* WINCONx */
+#define WINCON(_win)				(0x50 + ((_win) * 4))
+
+#define WINCONx_BUFSTATUS			(0x3 << 30)
+#define WINCONx_BUFSEL_MASK			(0x3 << 28)
+#define WINCONx_BUFSEL_SHIFT			28
+#define WINCONx_TRIPLE_BUF_MODE			(0x1 << 18)
+#define WINCONx_DOUBLE_BUF_MODE			(0x0 << 18)
+#define WINCONx_BURSTLEN_16WORD			(0x0 << 11)
+#define WINCONx_BURSTLEN_8WORD			(0x1 << 11)
+#define WINCONx_BURSTLEN_MASK			(0x1 << 11)
+#define WINCONx_BURSTLEN_SHIFT			11
+#define WINCONx_BLD_PLANE			(0 << 8)
+#define WINCONx_BLD_PIX				(1 << 8)
+#define WINCONx_ALPHA_MUL			(1 << 7)
+
+#define WINCONx_BPPMODE_MASK			(0xf << 2)
+#define WINCONx_BPPMODE_SHIFT			2
+#define WINCONx_BPPMODE_16BPP_565		(0x8 << 2)
+#define WINCONx_BPPMODE_24BPP_BGRx		(0x7 << 2)
+#define WINCONx_BPPMODE_24BPP_RGBx		(0x6 << 2)
+#define WINCONx_BPPMODE_24BPP_xBGR		(0x5 << 2)
+#define WINCONx_BPPMODE_24BPP_xRGB		(0x4 << 2)
+#define WINCONx_BPPMODE_32BPP_BGRA		(0x3 << 2)
+#define WINCONx_BPPMODE_32BPP_RGBA		(0x2 << 2)
+#define WINCONx_BPPMODE_32BPP_ABGR		(0x1 << 2)
+#define WINCONx_BPPMODE_32BPP_ARGB		(0x0 << 2)
+#define WINCONx_ALPHA_SEL			(1 << 1)
+#define WINCONx_ENWIN				(1 << 0)
+
+#define WINCON1_ALPHA_MUL_F			(1 << 7)
+#define WINCON2_ALPHA_MUL_F			(1 << 7)
+#define WINCON3_ALPHA_MUL_F			(1 << 7)
+#define WINCON4_ALPHA_MUL_F			(1 << 7)
+
+/*  VIDOSDxH: The height for the OSD image(READ ONLY)*/
+#define VIDOSD_H(_x)				(0x80 + ((_x) * 4))
+
+/* Frame buffer start addresses: VIDWxxADD0n */
+#define VIDW_BUF_START(_win)			(0x80 + ((_win) * 0x10))
+#define VIDW_BUF_START1(_win)			(0x84 + ((_win) * 0x10))
+#define VIDW_BUF_START2(_win)			(0x88 + ((_win) * 0x10))
+
+#define VIDW_WHOLE_X(_win)			(0x0130 + ((_win) * 8))
+#define VIDW_WHOLE_Y(_win)			(0x0134 + ((_win) * 8))
+#define VIDW_OFFSET_X(_win)			(0x0170 + ((_win) * 8))
+#define VIDW_OFFSET_Y(_win)			(0x0174 + ((_win) * 8))
+#define VIDW_BLKOFFSET(_win)			(0x01B0 + ((_win) * 4))
+#define VIDW_BLKSIZE(win)			(0x0200 + ((_win) * 4))
+
+/* Interrupt controls register */
+#define VIDINTCON2				0x228
+
+#define VIDINTCON1_INTEXTRA1_EN			(1 << 1)
+#define VIDINTCON1_INTEXTRA0_EN			(1 << 0)
+
+/* Interrupt controls and status register */
+#define VIDINTCON3				0x22C
+
+#define VIDINTCON1_INTEXTRA1_PEND		(1 << 1)
+#define VIDINTCON1_INTEXTRA0_PEND		(1 << 0)
+
+/* VIDOSDxA ~ VIDOSDxE */
+#define VIDOSD_BASE				0x230
+
+#define OSD_STRIDE				0x20
+
+#define VIDOSD_A(_win)				(VIDOSD_BASE + \
+						((_win) * OSD_STRIDE) + 0x00)
+#define VIDOSD_B(_win)				(VIDOSD_BASE + \
+						((_win) * OSD_STRIDE) + 0x04)
+#define VIDOSD_C(_win)				(VIDOSD_BASE + \
+						((_win) * OSD_STRIDE) + 0x08)
+#define VIDOSD_D(_win)				(VIDOSD_BASE + \
+						((_win) * OSD_STRIDE) + 0x0C)
+#define VIDOSD_E(_win)				(VIDOSD_BASE + \
+						((_win) * OSD_STRIDE) + 0x10)
+
+#define VIDOSDxA_TOPLEFT_X_MASK			(0x1fff << 13)
+#define VIDOSDxA_TOPLEFT_X_SHIFT		13
+#define VIDOSDxA_TOPLEFT_X_LIMIT		0x1fff
+#define VIDOSDxA_TOPLEFT_X(_x)			(((_x) & 0x1fff) << 13)
+
+#define VIDOSDxA_TOPLEFT_Y_MASK			(0x1fff << 0)
+#define VIDOSDxA_TOPLEFT_Y_SHIFT		0
+#define VIDOSDxA_TOPLEFT_Y_LIMIT		0x1fff
+#define VIDOSDxA_TOPLEFT_Y(_x)			(((_x) & 0x1fff) << 0)
+
+#define VIDOSDxB_BOTRIGHT_X_MASK		(0x1fff << 13)
+#define VIDOSDxB_BOTRIGHT_X_SHIFT		13
+#define VIDOSDxB_BOTRIGHT_X_LIMIT		0x1fff
+#define VIDOSDxB_BOTRIGHT_X(_x)			(((_x) & 0x1fff) << 13)
+
+#define VIDOSDxB_BOTRIGHT_Y_MASK		(0x1fff << 0)
+#define VIDOSDxB_BOTRIGHT_Y_SHIFT		0
+#define VIDOSDxB_BOTRIGHT_Y_LIMIT		0x1fff
+#define VIDOSDxB_BOTRIGHT_Y(_x)			(((_x) & 0x1fff) << 0)
+
+#define VIDOSDxC_ALPHA0_R_F(_x)			(((_x) & 0xFF) << 16)
+#define VIDOSDxC_ALPHA0_G_F(_x)			(((_x) & 0xFF) << 8)
+#define VIDOSDxC_ALPHA0_B_F(_x)			(((_x) & 0xFF) << 0)
+
+#define VIDOSDxD_ALPHA1_R_F(_x)			(((_x) & 0xFF) << 16)
+#define VIDOSDxD_ALPHA1_G_F(_x)			(((_x) & 0xFF) << 8)
+#define VIDOSDxD_ALPHA1_B_F(_x)			(((_x) & 0xFF) >> 0)
+
+/* Window MAP (Color map) */
+#define WINxMAP(_win)				(0x340 + ((_win) * 4))
+
+#define WINxMAP_MAP				(1 << 24)
+#define WINxMAP_MAP_COLOUR_MASK			(0xffffff << 0)
+#define WINxMAP_MAP_COLOUR_SHIFT		0
+#define WINxMAP_MAP_COLOUR_LIMIT		0xffffff
+#define WINxMAP_MAP_COLOUR(_x)			((_x) << 0)
+
+/* Window colour-key control registers */
+#define WKEYCON					0x370
+
+#define WKEYCON0				0x00
+#define WKEYCON1				0x04
+#define WxKEYCON0_KEYBL_EN			(1 << 26)
+#define WxKEYCON0_KEYEN_F			(1 << 25)
+#define WxKEYCON0_DIRCON			(1 << 24)
+#define WxKEYCON0_COMPKEY_MASK			(0xffffff << 0)
+#define WxKEYCON0_COMPKEY_SHIFT			0
+#define WxKEYCON0_COMPKEY_LIMIT			0xffffff
+#define WxKEYCON0_COMPKEY(_x)			((_x) << 0)
+#define WxKEYCON1_COLVAL_MASK			(0xffffff << 0)
+#define WxKEYCON1_COLVAL_SHIFT			0
+#define WxKEYCON1_COLVAL_LIMIT			0xffffff
+#define WxKEYCON1_COLVAL(_x)			((_x) << 0)
+
+/* color key control register for hardware window 1 ~ 4. */
+#define WKEYCON0_BASE(x)		((WKEYCON + WKEYCON0) + ((x - 1) * 8))
+/* color key value register for hardware window 1 ~ 4. */
+#define WKEYCON1_BASE(x)		((WKEYCON + WKEYCON1) + ((x - 1) * 8))
+
+/* Window KEY Alpha value */
+#define WxKEYALPHA(_win)			(0x3A0 + (((_win) - 1) * 0x4))
+
+#define Wx_KEYALPHA_R_F_SHIFT			16
+#define Wx_KEYALPHA_G_F_SHIFT			8
+#define Wx_KEYALPHA_B_F_SHIFT			0
+
+/* Blending equation */
+#define BLENDE(_win)				(0x03C0 + ((_win) * 4))
+#define BLENDE_COEF_ZERO			0x0
+#define BLENDE_COEF_ONE				0x1
+#define BLENDE_COEF_ALPHA_A			0x2
+#define BLENDE_COEF_ONE_MINUS_ALPHA_A		0x3
+#define BLENDE_COEF_ALPHA_B			0x4
+#define BLENDE_COEF_ONE_MINUS_ALPHA_B		0x5
+#define BLENDE_COEF_ALPHA0			0x6
+#define BLENDE_COEF_A				0xA
+#define BLENDE_COEF_ONE_MINUS_A			0xB
+#define BLENDE_COEF_B				0xC
+#define BLENDE_COEF_ONE_MINUS_B			0xD
+#define BLENDE_Q_FUNC(_v)			((_v) << 18)
+#define BLENDE_P_FUNC(_v)			((_v) << 12)
+#define BLENDE_B_FUNC(_v)			((_v) << 6)
+#define BLENDE_A_FUNC(_v)			((_v) << 0)
+
+/* Blending equation control */
+#define BLENDCON				0x3D8
+#define BLENDCON_NEW_MASK			(1 << 0)
+#define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
+#define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
+
+/* Interrupt control register */
+#define VIDINTCON0				0x500
+
+#define VIDINTCON0_WAKEUP_MASK			(0x3f << 26)
+#define VIDINTCON0_INTEXTRAEN			(1 << 21)
+
+#define VIDINTCON0_FRAMESEL0_SHIFT		15
+#define VIDINTCON0_FRAMESEL0_MASK		(0x3 << 15)
+#define VIDINTCON0_FRAMESEL0_BACKPORCH		(0x0 << 15)
+#define VIDINTCON0_FRAMESEL0_VSYNC		(0x1 << 15)
+#define VIDINTCON0_FRAMESEL0_ACTIVE		(0x2 << 15)
+#define VIDINTCON0_FRAMESEL0_FRONTPORCH		(0x3 << 15)
+
+#define VIDINTCON0_INT_FRAME			(1 << 11)
+
+#define VIDINTCON0_FIFOLEVEL_MASK		(0x7 << 3)
+#define VIDINTCON0_FIFOLEVEL_SHIFT		3
+#define VIDINTCON0_FIFOLEVEL_EMPTY		(0x0 << 3)
+#define VIDINTCON0_FIFOLEVEL_TO25PC		(0x1 << 3)
+#define VIDINTCON0_FIFOLEVEL_TO50PC		(0x2 << 3)
+#define VIDINTCON0_FIFOLEVEL_FULL		(0x4 << 3)
+
+#define VIDINTCON0_FIFOSEL_MAIN_EN		(1 << 1)
+#define VIDINTCON0_INT_FIFO			(1 << 1)
+
+#define VIDINTCON0_INT_ENABLE			(1 << 0)
+
+/* Interrupt controls and status register */
+#define VIDINTCON1				0x504
+
+#define VIDINTCON1_INT_EXTRA			(1 << 3)
+#define VIDINTCON1_INT_I80			(1 << 2)
+#define VIDINTCON1_INT_FRAME			(1 << 1)
+#define VIDINTCON1_INT_FIFO			(1 << 0)
+
+/* VIDCON1 */
+#define VIDCON1(_x)				(0x0600 + ((_x) * 0x50))
+#define VIDCON1_LINECNT_GET(_v)			(((_v) >> 17) & 0x1fff)
+#define VIDCON1_VCLK_MASK			(0x3 << 9)
+#define VIDCON1_VCLK_HOLD			(0x0 << 9)
+#define VIDCON1_VCLK_RUN			(0x1 << 9)
+#define VIDCON1_VCLK_RUN_VDEN_DISABLE		(0x3 << 9)
+#define VIDCON1_RGB_ORDER_O_MASK		(0x7 << 4)
+#define VIDCON1_RGB_ORDER_O_RGB			(0x0 << 4)
+#define VIDCON1_RGB_ORDER_O_GBR			(0x1 << 4)
+#define VIDCON1_RGB_ORDER_O_BRG			(0x2 << 4)
+#define VIDCON1_RGB_ORDER_O_BGR			(0x4 << 4)
+#define VIDCON1_RGB_ORDER_O_RBG			(0x5 << 4)
+#define VIDCON1_RGB_ORDER_O_GRB			(0x6 << 4)
+
+/* VIDTCON0 */
+#define VIDTCON0				0x610
+
+#define VIDTCON0_VBPD_MASK			(0xffff << 16)
+#define VIDTCON0_VBPD_SHIFT			16
+#define VIDTCON0_VBPD_LIMIT			0xffff
+#define VIDTCON0_VBPD(_x)			((_x) << 16)
+
+#define VIDTCON0_VFPD_MASK			(0xffff << 0)
+#define VIDTCON0_VFPD_SHIFT			0
+#define VIDTCON0_VFPD_LIMIT			0xffff
+#define VIDTCON0_VFPD(_x)			((_x) << 0)
+
+/* VIDTCON1 */
+#define VIDTCON1				0x614
+
+#define VIDTCON1_VSPW_MASK			(0xffff << 16)
+#define VIDTCON1_VSPW_SHIFT			16
+#define VIDTCON1_VSPW_LIMIT			0xffff
+#define VIDTCON1_VSPW(_x)			((_x) << 16)
+
+/* VIDTCON2 */
+#define VIDTCON2				0x618
+
+#define VIDTCON2_HBPD_MASK			(0xffff << 16)
+#define VIDTCON2_HBPD_SHIFT			16
+#define VIDTCON2_HBPD_LIMIT			0xffff
+#define VIDTCON2_HBPD(_x)			((_x) << 16)
+
+#define VIDTCON2_HFPD_MASK			(0xffff << 0)
+#define VIDTCON2_HFPD_SHIFT			0
+#define VIDTCON2_HFPD_LIMIT			0xffff
+#define VIDTCON2_HFPD(_x)			((_x) << 0)
+
+/* VIDTCON3 */
+#define VIDTCON3				0x61C
+
+#define VIDTCON3_HSPW_MASK			(0xffff << 16)
+#define VIDTCON3_HSPW_SHIFT			16
+#define VIDTCON3_HSPW_LIMIT			0xffff
+#define VIDTCON3_HSPW(_x)			((_x) << 16)
+
+/* VIDTCON4 */
+#define VIDTCON4				0x620
+
+#define VIDTCON4_LINEVAL_MASK			(0xfff << 16)
+#define VIDTCON4_LINEVAL_SHIFT			16
+#define VIDTCON4_LINEVAL_LIMIT			0xfff
+#define VIDTCON4_LINEVAL(_x)			(((_x) & 0xfff) << 16)
+
+#define VIDTCON4_HOZVAL_MASK			(0xfff << 0)
+#define VIDTCON4_HOZVAL_SHIFT			0
+#define VIDTCON4_HOZVAL_LIMIT			0xfff
+#define VIDTCON4_HOZVAL(_x)			(((_x) & 0xfff) << 0)
+
+/* LINECNT OP THRSHOLD*/
+#define LINECNT_OP_THRESHOLD			0x630
+
+/* CRCCTRL */
+#define CRCCTRL					0x6C8
+#define CRCCTRL_CRCCLKEN			(0x1 << 2)
+#define CRCCTRL_CRCSTART_F			(0x1 << 1)
+#define CRCCTRL_CRCEN				(0x1 << 0)
+
+/* DECON_CMU */
+#define DECON_CMU				0x704
+
+#define DECON_CMU_ALL_CLKGATE_ENABLE		0x3
+#define DECON_CMU_SE_CLKGATE_ENABLE		(0x1 << 2)
+#define DECON_CMU_SFR_CLKGATE_ENABLE		(0x1 << 1)
+#define DECON_CMU_MEM_CLKGATE_ENABLE		(0x1 << 0)
+
+/* DECON_UPDATE */
+#define DECON_UPDATE				0x710
+
+#define DECON_UPDATE_SLAVE_SYNC			(1 << 4)
+#define DECON_UPDATE_STANDALONE_F		(1 << 0)
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index c74bf4a..73390c1 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -17,6 +17,7 @@
 #include <linux/bitmap.h>
 #include <linux/fb.h>
 #include <media/v4l2-mediabus.h>
+#include <video/videomode.h>
 
 struct ipu_soc;
 
@@ -32,28 +33,15 @@
  * Bitfield of Display Interface signal polarities.
  */
 struct ipu_di_signal_cfg {
-	unsigned datamask_en:1;
-	unsigned interlaced:1;
-	unsigned odd_field_first:1;
-	unsigned clksel_en:1;
-	unsigned clkidle_en:1;
 	unsigned data_pol:1;	/* true = inverted */
 	unsigned clk_pol:1;	/* true = rising edge */
 	unsigned enable_pol:1;
-	unsigned Hsync_pol:1;	/* true = active high */
-	unsigned Vsync_pol:1;
 
-	u16 width;
-	u16 height;
+	struct videomode mode;
+
 	u32 pixel_fmt;
-	u16 h_start_width;
-	u16 h_sync_width;
-	u16 h_end_width;
-	u16 v_start_width;
-	u16 v_sync_width;
-	u16 v_end_width;
 	u32 v_to_h_sync;
-	unsigned long pixelclock;
+
 #define IPU_DI_CLKMODE_SYNC	(1 << 0)
 #define IPU_DI_CLKMODE_EXT	(1 << 1)
 	unsigned long clkflags;
@@ -236,6 +224,7 @@
 int ipu_di_disable(struct ipu_di *);
 int ipu_di_enable(struct ipu_di *);
 int ipu_di_get_num(struct ipu_di *);
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode);
 int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);
 
 /*
diff --git a/init/Kconfig b/init/Kconfig
index 1354ac0..058e367 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1287,22 +1287,6 @@
 
 endif
 
-config INIT_FALLBACK
-	bool "Fall back to defaults if init= parameter is bad"
-	default y
-	help
-	  If enabled, the kernel will try the default init binaries if an
-	  explicit request from the init= parameter fails.
-
-	  This can have unexpected effects.  For example, booting
-	  with init=/sbin/kiosk_app will run /sbin/init or even /bin/sh
-	  if /sbin/kiosk_app cannot be executed.
-
-	  The default value of Y is consistent with historical behavior.
-	  Selecting N is likely to be more appropriate for most uses,
-	  especially on kiosks and on kernels that are intended to be
-	  run under the control of a script.
-
 config CC_OPTIMIZE_FOR_SIZE
 	bool "Optimize for size"
 	help
diff --git a/init/main.c b/init/main.c
index 179ada1..6f0f1c5f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -953,13 +953,8 @@
 		ret = run_init_process(execute_command);
 		if (!ret)
 			return 0;
-#ifndef CONFIG_INIT_FALLBACK
 		panic("Requested init %s failed (error %d).",
 		      execute_command, ret);
-#else
-		pr_err("Failed to execute %s (error %d).  Attempting defaults...\n",
-		       execute_command, ret);
-#endif
 	}
 	if (!try_to_run_init_process("/sbin/init") ||
 	    !try_to_run_init_process("/etc/init") ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d5f6ec2..29a7b2c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -3077,7 +3077,7 @@
 #endif
 	kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
 				  cgroup_file_mode(cft), 0, cft->kf_ops, cft,
-				  NULL, false, key);
+				  NULL, key);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
 
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index c54a1da..1d1fe93 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1707,40 +1707,27 @@
 {
 	struct cpuset *cs = css_cs(seq_css(sf));
 	cpuset_filetype_t type = seq_cft(sf)->private;
-	ssize_t count;
-	char *buf, *s;
 	int ret = 0;
 
-	count = seq_get_buf(sf, &buf);
-	s = buf;
-
 	spin_lock_irq(&callback_lock);
 
 	switch (type) {
 	case FILE_CPULIST:
-		s += cpulist_scnprintf(s, count, cs->cpus_allowed);
+		seq_printf(sf, "%*pbl\n", cpumask_pr_args(cs->cpus_allowed));
 		break;
 	case FILE_MEMLIST:
-		s += nodelist_scnprintf(s, count, cs->mems_allowed);
+		seq_printf(sf, "%*pbl\n", nodemask_pr_args(&cs->mems_allowed));
 		break;
 	case FILE_EFFECTIVE_CPULIST:
-		s += cpulist_scnprintf(s, count, cs->effective_cpus);
+		seq_printf(sf, "%*pbl\n", cpumask_pr_args(cs->effective_cpus));
 		break;
 	case FILE_EFFECTIVE_MEMLIST:
-		s += nodelist_scnprintf(s, count, cs->effective_mems);
+		seq_printf(sf, "%*pbl\n", nodemask_pr_args(&cs->effective_mems));
 		break;
 	default:
 		ret = -EINVAL;
-		goto out_unlock;
 	}
 
-	if (s < buf + count - 1) {
-		*s++ = '\n';
-		seq_commit(sf, s - buf);
-	} else {
-		seq_commit(sf, -1);
-	}
-out_unlock:
 	spin_unlock_irq(&callback_lock);
 	return ret;
 }
@@ -2610,8 +2597,6 @@
 	return nodes_intersects(tsk1->mems_allowed, tsk2->mems_allowed);
 }
 
-#define CPUSET_NODELIST_LEN	(256)
-
 /**
  * cpuset_print_task_mems_allowed - prints task's cpuset and mems_allowed
  * @tsk: pointer to task_struct of some task.
@@ -2621,23 +2606,16 @@
  */
 void cpuset_print_task_mems_allowed(struct task_struct *tsk)
 {
-	 /* Statically allocated to prevent using excess stack. */
-	static char cpuset_nodelist[CPUSET_NODELIST_LEN];
-	static DEFINE_SPINLOCK(cpuset_buffer_lock);
 	struct cgroup *cgrp;
 
-	spin_lock(&cpuset_buffer_lock);
 	rcu_read_lock();
 
 	cgrp = task_cs(tsk)->css.cgroup;
-	nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN,
-			   tsk->mems_allowed);
 	pr_info("%s cpuset=", tsk->comm);
 	pr_cont_cgroup_name(cgrp);
-	pr_cont(" mems_allowed=%s\n", cpuset_nodelist);
+	pr_cont(" mems_allowed=%*pbl\n", nodemask_pr_args(&tsk->mems_allowed));
 
 	rcu_read_unlock();
-	spin_unlock(&cpuset_buffer_lock);
 }
 
 /*
@@ -2715,10 +2693,8 @@
 /* Display task mems_allowed in /proc/<pid>/status file. */
 void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task)
 {
-	seq_puts(m, "Mems_allowed:\t");
-	seq_nodemask(m, &task->mems_allowed);
-	seq_puts(m, "\n");
-	seq_puts(m, "Mems_allowed_list:\t");
-	seq_nodemask_list(m, &task->mems_allowed);
-	seq_puts(m, "\n");
+	seq_printf(m, "Mems_allowed:\t%*pb\n",
+		   nodemask_pr_args(&task->mems_allowed));
+	seq_printf(m, "Mems_allowed_list:\t%*pbl\n",
+		   nodemask_pr_args(&task->mems_allowed));
 }
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 8812d8e..f04daab 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4101,7 +4101,8 @@
 	rcu_read_unlock();
 }
 
-void __weak arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
+void __weak arch_perf_update_userpage(
+	struct perf_event *event, struct perf_event_mmap_page *userpg, u64 now)
 {
 }
 
@@ -4151,7 +4152,7 @@
 	userpg->time_running = running +
 			atomic64_read(&event->child_total_time_running);
 
-	arch_perf_update_userpage(userpg, now);
+	arch_perf_update_userpage(event, userpg, now);
 
 	barrier();
 	++userpg->lock;
@@ -4293,6 +4294,9 @@
 
 	atomic_inc(&event->mmap_count);
 	atomic_inc(&event->rb->mmap_count);
+
+	if (event->pmu->event_mapped)
+		event->pmu->event_mapped(event);
 }
 
 /*
@@ -4312,6 +4316,9 @@
 	int mmap_locked = rb->mmap_locked;
 	unsigned long size = perf_data_size(rb);
 
+	if (event->pmu->event_unmapped)
+		event->pmu->event_unmapped(event);
+
 	atomic_dec(&rb->mmap_count);
 
 	if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
@@ -4513,6 +4520,9 @@
 	vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_ops = &perf_mmap_vmops;
 
+	if (event->pmu->event_mapped)
+		event->pmu->event_mapped(event);
+
 	return ret;
 }
 
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8069237..196a06f 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -243,6 +243,9 @@
 		return -EINVAL;
 	desc->affinity_hint = m;
 	irq_put_desc_unlock(desc, flags);
+	/* set the initial affinity to prevent every interrupt being on CPU0 */
+	if (m)
+		__irq_set_affinity(irq, m, false);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 9dc9bfd..df2f464 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -46,10 +46,9 @@
 		mask = desc->pending_mask;
 #endif
 	if (type)
-		seq_cpumask_list(m, mask);
+		seq_printf(m, "%*pbl\n", cpumask_pr_args(mask));
 	else
-		seq_cpumask(m, mask);
-	seq_putc(m, '\n');
+		seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
 	return 0;
 }
 
@@ -67,8 +66,7 @@
 		cpumask_copy(mask, desc->affinity_hint);
 	raw_spin_unlock_irqrestore(&desc->lock, flags);
 
-	seq_cpumask(m, mask);
-	seq_putc(m, '\n');
+	seq_printf(m, "%*pb\n", cpumask_pr_args(mask));
 	free_cpumask_var(mask);
 
 	return 0;
@@ -186,8 +184,7 @@
 
 static int default_affinity_show(struct seq_file *m, void *v)
 {
-	seq_cpumask(m, irq_default_affinity);
-	seq_putc(m, '\n');
+	seq_printf(m, "%*pb\n", cpumask_pr_args(irq_default_affinity));
 	return 0;
 }
 
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 2ca272f..c90e417 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -869,7 +869,8 @@
 {
 	struct kprobe *_p;
 
-	unoptimize_kprobe(p, false);	/* Try to unoptimize */
+	/* Try to unoptimize */
+	unoptimize_kprobe(p, kprobes_all_disarmed);
 
 	if (!kprobe_queued(p)) {
 		arch_disarm_kprobe(p);
@@ -1571,7 +1572,13 @@
 
 		/* Try to disarm and disable this/parent probe */
 		if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
-			disarm_kprobe(orig_p, true);
+			/*
+			 * If kprobes_all_disarmed is set, orig_p
+			 * should have already been disarmed, so
+			 * skip unneed disarming process.
+			 */
+			if (!kprobes_all_disarmed)
+				disarm_kprobe(orig_p, true);
 			orig_p->flags |= KPROBE_FLAG_DISABLED;
 		}
 	}
@@ -2320,6 +2327,12 @@
 	if (!kprobes_all_disarmed)
 		goto already_enabled;
 
+	/*
+	 * optimize_kprobe() called by arm_kprobe() checks
+	 * kprobes_all_disarmed, so set kprobes_all_disarmed before
+	 * arm_kprobe.
+	 */
+	kprobes_all_disarmed = false;
 	/* Arming kprobes doesn't optimize kprobe itself */
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
 		head = &kprobe_table[i];
@@ -2328,7 +2341,6 @@
 				arm_kprobe(p);
 	}
 
-	kprobes_all_disarmed = false;
 	printk(KERN_INFO "Kprobes globally enabled\n");
 
 already_enabled:
diff --git a/kernel/module.c b/kernel/module.c
index 82dc1f8..8426ad4 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -56,6 +56,7 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
+#include <linux/kasan.h>
 #include <linux/jump_label.h>
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
@@ -1813,6 +1814,7 @@
 void __weak module_memfree(void *module_region)
 {
 	vfree(module_region);
+	kasan_module_free(module_region);
 }
 
 void __weak module_arch_cleanup(struct module *mod)
diff --git a/kernel/padata.c b/kernel/padata.c
index 161402f..b38bea9 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -917,15 +917,10 @@
 	else
 		cpumask = pinst->cpumask.pcpu;
 
-	len = bitmap_scnprintf(buf, PAGE_SIZE, cpumask_bits(cpumask),
-			       nr_cpu_ids);
-	if (PAGE_SIZE - len < 2)
-		len = -EINVAL;
-	else
-		len += sprintf(buf + len, "\n");
-
+	len = snprintf(buf, PAGE_SIZE, "%*pb\n",
+		       nr_cpu_ids, cpumask_bits(cpumask));
 	mutex_unlock(&pinst->lock);
-	return len;
+	return len < PAGE_SIZE ? len : -EINVAL;
 }
 
 static ssize_t store_cpumask(struct padata_instance *pinst,
diff --git a/kernel/profile.c b/kernel/profile.c
index 54bf5ba..a7bcd28 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -422,8 +422,7 @@
 
 static int prof_cpu_mask_proc_show(struct seq_file *m, void *v)
 {
-	seq_cpumask(m, prof_cpu_mask);
-	seq_putc(m, '\n');
+	seq_printf(m, "%*pb\n", cpumask_pr_args(prof_cpu_mask));
 	return 0;
 }
 
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 2e850a5..0d7bbe3 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -49,7 +49,6 @@
 static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */
 static bool have_rcu_nocb_mask;	    /* Was rcu_nocb_mask allocated? */
 static bool __read_mostly rcu_nocb_poll;    /* Offload kthread are to poll. */
-static char __initdata nocb_buf[NR_CPUS * 5];
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 
 /*
@@ -2386,8 +2385,8 @@
 		cpumask_and(rcu_nocb_mask, cpu_possible_mask,
 			    rcu_nocb_mask);
 	}
-	cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
-	pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
+	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/sched/core.c b/kernel/sched/core.c
index 1f37fe7..13049aa 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5462,9 +5462,7 @@
 				  struct cpumask *groupmask)
 {
 	struct sched_group *group = sd->groups;
-	char str[256];
 
-	cpulist_scnprintf(str, sizeof(str), sched_domain_span(sd));
 	cpumask_clear(groupmask);
 
 	printk(KERN_DEBUG "%*s domain %d: ", level, "", level);
@@ -5477,7 +5475,8 @@
 		return -1;
 	}
 
-	printk(KERN_CONT "span %s level %s\n", str, sd->name);
+	printk(KERN_CONT "span %*pbl level %s\n",
+	       cpumask_pr_args(sched_domain_span(sd)), sd->name);
 
 	if (!cpumask_test_cpu(cpu, sched_domain_span(sd))) {
 		printk(KERN_ERR "ERROR: domain->span does not contain "
@@ -5522,9 +5521,8 @@
 
 		cpumask_or(groupmask, groupmask, sched_group_cpus(group));
 
-		cpulist_scnprintf(str, sizeof(str), sched_group_cpus(group));
-
-		printk(KERN_CONT " %s", str);
+		printk(KERN_CONT " %*pbl",
+		       cpumask_pr_args(sched_group_cpus(group)));
 		if (group->sgc->capacity != SCHED_CAPACITY_SCALE) {
 			printk(KERN_CONT " (cpu_capacity = %d)",
 				group->sgc->capacity);
diff --git a/kernel/sched/stats.c b/kernel/sched/stats.c
index a476bea..87e2c9f 100644
--- a/kernel/sched/stats.c
+++ b/kernel/sched/stats.c
@@ -15,11 +15,6 @@
 static int show_schedstat(struct seq_file *seq, void *v)
 {
 	int cpu;
-	int mask_len = DIV_ROUND_UP(NR_CPUS, 32) * 9;
-	char *mask_str = kmalloc(mask_len, GFP_KERNEL);
-
-	if (mask_str == NULL)
-		return -ENOMEM;
 
 	if (v == (void *)1) {
 		seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
@@ -50,9 +45,8 @@
 		for_each_domain(cpu, sd) {
 			enum cpu_idle_type itype;
 
-			cpumask_scnprintf(mask_str, mask_len,
-					  sched_domain_span(sd));
-			seq_printf(seq, "domain%d %s", dcount++, mask_str);
+			seq_printf(seq, "domain%d %*pb", dcount++,
+				   cpumask_pr_args(sched_domain_span(sd)));
 			for (itype = CPU_IDLE; itype < CPU_MAX_IDLE_TYPES;
 					itype++) {
 				seq_printf(seq, " %u %u %u %u %u %u %u %u",
@@ -76,7 +70,6 @@
 		rcu_read_unlock();
 #endif
 	}
-	kfree(mask_str);
 	return 0;
 }
 
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 1363d58..a4c4eda 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -326,13 +326,6 @@
 	return NOTIFY_OK;
 }
 
-/*
- * Worst case string length in chunks of CPU range seems 2 steps
- * separations: 0,2,4,6,...
- * This is NR_CPUS + sizeof('\0')
- */
-static char __initdata nohz_full_buf[NR_CPUS + 1];
-
 static int tick_nohz_init_all(void)
 {
 	int err = -1;
@@ -393,8 +386,8 @@
 		context_tracking_cpu_set(cpu);
 
 	cpu_notifier(tick_nohz_cpu_down_callback, 0);
-	cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), tick_nohz_full_mask);
-	pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);
+	pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",
+		cpumask_pr_args(tick_nohz_full_mask));
 }
 #endif
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 77b8dc5..62c6506 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3353,12 +3353,12 @@
 
 	mutex_lock(&tracing_cpumask_update_lock);
 
-	len = cpumask_scnprintf(mask_str, count, tr->tracing_cpumask);
-	if (count - len < 2) {
+	len = snprintf(mask_str, count, "%*pb\n",
+		       cpumask_pr_args(tr->tracing_cpumask));
+	if (len >= count) {
 		count = -EINVAL;
 		goto out_err;
 	}
-	len += sprintf(mask_str + len, "\n");
 	count = simple_read_from_buffer(ubuf, count, ppos, mask_str, NR_CPUS+1);
 
 out_err:
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index f8b45d8..e694c9f 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -120,7 +120,7 @@
 
 	__trace_seq_init(s);
 
-	seq_buf_bitmask(&s->seq, maskp, nmaskbits);
+	seq_buf_printf(&s->seq, "%*pb", nmaskbits, maskp);
 
 	if (unlikely(seq_buf_has_overflowed(&s->seq))) {
 		s->seq.len = save_len;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index beeeac9..f288493 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -3083,10 +3083,9 @@
 	int written;
 
 	mutex_lock(&wq->mutex);
-	written = cpumask_scnprintf(buf, PAGE_SIZE, wq->unbound_attrs->cpumask);
+	written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
+			    cpumask_pr_args(wq->unbound_attrs->cpumask));
 	mutex_unlock(&wq->mutex);
-
-	written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
 	return written;
 }
 
diff --git a/lib/Kconfig b/lib/Kconfig
index cd177ca..cb9758e 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -14,7 +14,7 @@
 	tristate
 
 config HAVE_ARCH_BITREVERSE
-	boolean
+	bool
 	default n
 	depends on BITREVERSE
 	help
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 79a9bb6..ecb3516 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -651,6 +651,8 @@
 
 source "lib/Kconfig.kmemcheck"
 
+source "lib/Kconfig.kasan"
+
 endmenu # "Memory Debugging"
 
 config DEBUG_SHIRQ
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
new file mode 100644
index 0000000..4fecaedc
--- /dev/null
+++ b/lib/Kconfig.kasan
@@ -0,0 +1,54 @@
+config HAVE_ARCH_KASAN
+	bool
+
+if HAVE_ARCH_KASAN
+
+config KASAN
+	bool "KASan: runtime memory debugger"
+	depends on SLUB_DEBUG
+	select CONSTRUCTORS
+	help
+	  Enables kernel address sanitizer - runtime memory debugger,
+	  designed to find out-of-bounds accesses and use-after-free bugs.
+	  This is strictly debugging feature. It consumes about 1/8
+	  of available memory and brings about ~x3 performance slowdown.
+	  For better error detection enable CONFIG_STACKTRACE,
+	  and add slub_debug=U to boot cmdline.
+
+config KASAN_SHADOW_OFFSET
+	hex
+	default 0xdffffc0000000000 if X86_64
+
+choice
+	prompt "Instrumentation type"
+	depends on KASAN
+	default KASAN_OUTLINE
+
+config KASAN_OUTLINE
+	bool "Outline instrumentation"
+	help
+	  Before every memory access compiler insert function call
+	  __asan_load*/__asan_store*. These functions performs check
+	  of shadow memory. This is slower than inline instrumentation,
+	  however it doesn't bloat size of kernel's .text section so
+	  much as inline does.
+
+config KASAN_INLINE
+	bool "Inline instrumentation"
+	help
+	  Compiler directly inserts code checking shadow memory before
+	  memory accesses. This is faster than outline (in some workloads
+	  it gives about x2 boost over outline instrumentation), but
+	  make kernel's .text size much bigger.
+
+endchoice
+
+config TEST_KASAN
+	tristate "Module for testing kasan for bug detection"
+	depends on m && KASAN
+	help
+	  This is a test module doing various nasty things like
+	  out of bounds accesses, use after free. It is useful for testing
+	  kernel debugging features like kernel address sanitizer.
+
+endif
diff --git a/lib/Makefile b/lib/Makefile
index e456def..87eb3bf 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,12 +32,13 @@
 obj-y += hexdump.o
 obj-$(CONFIG_TEST_HEXDUMP) += test-hexdump.o
 obj-y += kstrtox.o
-obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
-obj-$(CONFIG_TEST_LKM) += test_module.o
-obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
+obj-$(CONFIG_TEST_KASAN) += test_kasan.o
+obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
+obj-$(CONFIG_TEST_LKM) += test_module.o
 obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
+obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/bitmap.c b/lib/bitmap.c
index ad161a6..d456f4c1 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -104,18 +104,18 @@
  *   @dst : destination bitmap
  *   @src : source bitmap
  *   @shift : shift by this many bits
- *   @bits : bitmap size, in bits
+ *   @nbits : bitmap size, in bits
  *
  * Shifting right (dividing) means moving bits in the MS -> LS bit
  * direction.  Zeros are fed into the vacated MS positions and the
  * LS bits shifted off the bottom are lost.
  */
-void __bitmap_shift_right(unsigned long *dst,
-			const unsigned long *src, int shift, int bits)
+void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
+			unsigned shift, unsigned nbits)
 {
-	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
-	int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
-	unsigned long mask = (1UL << left) - 1;
+	unsigned k, lim = BITS_TO_LONGS(nbits);
+	unsigned off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
+	unsigned long mask = BITMAP_LAST_WORD_MASK(nbits);
 	for (k = 0; off + k < lim; ++k) {
 		unsigned long upper, lower;
 
@@ -127,17 +127,15 @@
 			upper = 0;
 		else {
 			upper = src[off + k + 1];
-			if (off + k + 1 == lim - 1 && left)
+			if (off + k + 1 == lim - 1)
 				upper &= mask;
+			upper <<= (BITS_PER_LONG - rem);
 		}
 		lower = src[off + k];
-		if (left && off + k == lim - 1)
+		if (off + k == lim - 1)
 			lower &= mask;
-		dst[k] = lower >> rem;
-		if (rem)
-			dst[k] |= upper << (BITS_PER_LONG - rem);
-		if (left && k == lim - 1)
-			dst[k] &= mask;
+		lower >>= rem;
+		dst[k] = lower | upper;
 	}
 	if (off)
 		memset(&dst[lim - off], 0, off*sizeof(unsigned long));
@@ -150,18 +148,19 @@
  *   @dst : destination bitmap
  *   @src : source bitmap
  *   @shift : shift by this many bits
- *   @bits : bitmap size, in bits
+ *   @nbits : bitmap size, in bits
  *
  * Shifting left (multiplying) means moving bits in the LS -> MS
  * direction.  Zeros are fed into the vacated LS bit positions
  * and those MS bits shifted off the top are lost.
  */
 
-void __bitmap_shift_left(unsigned long *dst,
-			const unsigned long *src, int shift, int bits)
+void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
+			unsigned int shift, unsigned int nbits)
 {
-	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
-	int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
+	int k;
+	unsigned int lim = BITS_TO_LONGS(nbits);
+	unsigned int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
 	for (k = lim - off - 1; k >= 0; --k) {
 		unsigned long upper, lower;
 
@@ -170,17 +169,11 @@
 		 * word below and make them the bottom rem bits of result.
 		 */
 		if (rem && k > 0)
-			lower = src[k - 1];
+			lower = src[k - 1] >> (BITS_PER_LONG - rem);
 		else
 			lower = 0;
-		upper = src[k];
-		if (left && k == lim - 1)
-			upper &= (1UL << left) - 1;
-		dst[k + off] = upper << rem;
-		if (rem)
-			dst[k + off] |= lower >> (BITS_PER_LONG - rem);
-		if (left && k + off == lim - 1)
-			dst[k + off] &= (1UL << left) - 1;
+		upper = src[k] << rem;
+		dst[k + off] = lower | upper;
 	}
 	if (off)
 		memset(dst, 0, off*sizeof(unsigned long));
@@ -377,45 +370,6 @@
 #define BASEDEC 10		/* fancier cpuset lists input in decimal */
 
 /**
- * bitmap_scnprintf - convert bitmap to an ASCII hex string.
- * @buf: byte buffer into which string is placed
- * @buflen: reserved size of @buf, in bytes
- * @maskp: pointer to bitmap to convert
- * @nmaskbits: size of bitmap, in bits
- *
- * Exactly @nmaskbits bits are displayed.  Hex digits are grouped into
- * comma-separated sets of eight digits per set.  Returns the number of
- * characters which were written to *buf, excluding the trailing \0.
- */
-int bitmap_scnprintf(char *buf, unsigned int buflen,
-	const unsigned long *maskp, int nmaskbits)
-{
-	int i, word, bit, len = 0;
-	unsigned long val;
-	const char *sep = "";
-	int chunksz;
-	u32 chunkmask;
-
-	chunksz = nmaskbits & (CHUNKSZ - 1);
-	if (chunksz == 0)
-		chunksz = CHUNKSZ;
-
-	i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
-	for (; i >= 0; i -= CHUNKSZ) {
-		chunkmask = ((1ULL << chunksz) - 1);
-		word = i / BITS_PER_LONG;
-		bit = i % BITS_PER_LONG;
-		val = (maskp[word] >> bit) & chunkmask;
-		len += scnprintf(buf+len, buflen-len, "%s%0*lx", sep,
-			(chunksz+3)/4, val);
-		chunksz = CHUNKSZ;
-		sep = ",";
-	}
-	return len;
-}
-EXPORT_SYMBOL(bitmap_scnprintf);
-
-/**
  * __bitmap_parse - convert an ASCII hex string into a bitmap.
  * @buf: pointer to buffer containing string.
  * @buflen: buffer size in bytes.  If string is smaller than this
@@ -528,65 +482,6 @@
 }
 EXPORT_SYMBOL(bitmap_parse_user);
 
-/*
- * bscnl_emit(buf, buflen, rbot, rtop, bp)
- *
- * Helper routine for bitmap_scnlistprintf().  Write decimal number
- * or range to buf, suppressing output past buf+buflen, with optional
- * comma-prefix.  Return len of what was written to *buf, excluding the
- * trailing \0.
- */
-static inline int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len)
-{
-	if (len > 0)
-		len += scnprintf(buf + len, buflen - len, ",");
-	if (rbot == rtop)
-		len += scnprintf(buf + len, buflen - len, "%d", rbot);
-	else
-		len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop);
-	return len;
-}
-
-/**
- * bitmap_scnlistprintf - convert bitmap to list format ASCII string
- * @buf: byte buffer into which string is placed
- * @buflen: reserved size of @buf, in bytes
- * @maskp: pointer to bitmap to convert
- * @nmaskbits: size of bitmap, in bits
- *
- * Output format is a comma-separated list of decimal numbers and
- * ranges.  Consecutively set bits are shown as two hyphen-separated
- * decimal numbers, the smallest and largest bit numbers set in
- * the range.  Output format is compatible with the format
- * accepted as input by bitmap_parselist().
- *
- * The return value is the number of characters which were written to *buf
- * excluding the trailing '\0', as per ISO C99's scnprintf.
- */
-int bitmap_scnlistprintf(char *buf, unsigned int buflen,
-	const unsigned long *maskp, int nmaskbits)
-{
-	int len = 0;
-	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
-	int cur, rbot, rtop;
-
-	if (buflen == 0)
-		return 0;
-	buf[0] = 0;
-
-	rbot = cur = find_first_bit(maskp, nmaskbits);
-	while (cur < nmaskbits) {
-		rtop = cur;
-		cur = find_next_bit(maskp, nmaskbits, cur+1);
-		if (cur >= nmaskbits || cur > rtop + 1) {
-			len = bscnl_emit(buf, buflen, rbot, rtop, len);
-			rbot = cur;
-		}
-	}
-	return len;
-}
-EXPORT_SYMBOL(bitmap_scnlistprintf);
-
 /**
  * bitmap_print_to_pagebuf - convert bitmap to list or hex format ASCII string
  * @list: indicates whether the bitmap must be list
@@ -605,8 +500,8 @@
 	int n = 0;
 
 	if (len > 1) {
-		n = list ? bitmap_scnlistprintf(buf, len, maskp, nmaskbits) :
-			   bitmap_scnprintf(buf, len, maskp, nmaskbits);
+		n = list ? scnprintf(buf, len, "%*pbl", nmaskbits, maskp) :
+			   scnprintf(buf, len, "%*pb", nmaskbits, maskp);
 		buf[n++] = '\n';
 		buf[n] = '\0';
 	}
@@ -1191,16 +1086,17 @@
  *
  * Require nbits % BITS_PER_LONG == 0.
  */
-void bitmap_copy_le(void *dst, const unsigned long *src, int nbits)
+#ifdef __BIG_ENDIAN
+void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits)
 {
-	unsigned long *d = dst;
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < nbits/BITS_PER_LONG; i++) {
 		if (BITS_PER_LONG == 64)
-			d[i] = cpu_to_le64(src[i]);
+			dst[i] = cpu_to_le64(src[i]);
 		else
-			d[i] = cpu_to_le32(src[i]);
+			dst[i] = cpu_to_le32(src[i]);
 	}
 }
 EXPORT_SYMBOL(bitmap_copy_le);
+#endif
diff --git a/lib/gen_crc32table.c b/lib/gen_crc32table.c
index 71fcfcd9..d83a372 100644
--- a/lib/gen_crc32table.c
+++ b/lib/gen_crc32table.c
@@ -109,7 +109,7 @@
 
 	if (CRC_LE_BITS > 1) {
 		crc32init_le();
-		printf("static u32 __cacheline_aligned "
+		printf("static const u32 ____cacheline_aligned "
 		       "crc32table_le[%d][%d] = {",
 		       LE_TABLE_ROWS, LE_TABLE_SIZE);
 		output_table(crc32table_le, LE_TABLE_ROWS,
@@ -119,7 +119,7 @@
 
 	if (CRC_BE_BITS > 1) {
 		crc32init_be();
-		printf("static u32 __cacheline_aligned "
+		printf("static const u32 ____cacheline_aligned "
 		       "crc32table_be[%d][%d] = {",
 		       BE_TABLE_ROWS, BE_TABLE_SIZE);
 		output_table(crc32table_be, LE_TABLE_ROWS,
@@ -128,7 +128,7 @@
 	}
 	if (CRC_LE_BITS > 1) {
 		crc32cinit_le();
-		printf("static u32 __cacheline_aligned "
+		printf("static const u32 ____cacheline_aligned "
 		       "crc32ctable_le[%d][%d] = {",
 		       LE_TABLE_ROWS, LE_TABLE_SIZE);
 		output_table(crc32ctable_le, LE_TABLE_ROWS,
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 0fe1cbe..d214866 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -586,6 +586,8 @@
 	struct gen_pool **ptr, *pool;
 
 	ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return NULL;
 
 	pool = gen_pool_create(min_alloc_order, nid);
 	if (pool) {
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index 4eedfed..88c0854 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
@@ -91,42 +91,6 @@
 	return ret;
 }
 
-/**
- * seq_buf_bitmask - write a bitmask array in its ASCII representation
- * @s:		seq_buf descriptor
- * @maskp:	points to an array of unsigned longs that represent a bitmask
- * @nmaskbits:	The number of bits that are valid in @maskp
- *
- * Writes a ASCII representation of a bitmask string into @s.
- *
- * Returns zero on success, -1 on overflow.
- */
-int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
-		    int nmaskbits)
-{
-	unsigned int len = seq_buf_buffer_left(s);
-	int ret;
-
-	WARN_ON(s->size == 0);
-
-	/*
-	 * Note, because bitmap_scnprintf() only returns the number of bytes
-	 * written and not the number that would be written, we use the last
-	 * byte of the buffer to let us know if we overflowed. There's a small
-	 * chance that the bitmap could have fit exactly inside the buffer, but
-	 * it's not that critical if that does happen.
-	 */
-	if (len > 1) {
-		ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);
-		if (ret < len) {
-			s->len += ret;
-			return 0;
-		}
-	}
-	seq_buf_set_overflow(s);
-	return -1;
-}
-
 #ifdef CONFIG_BINARY_PRINTF
 /**
  * seq_buf_bprintf - Write the printf string from binary arguments
diff --git a/lib/string.c b/lib/string.c
index 3206d01..ce81aae 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -313,12 +313,12 @@
  */
 char *strrchr(const char *s, int c)
 {
-       const char *p = s + strlen(s);
-       do {
-           if (*p == (char)c)
-               return (char *)p;
-       } while (--p >= s);
-       return NULL;
+	const char *last = NULL;
+	do {
+		if (*s == (char)c)
+			last = s;
+	} while (*s++);
+	return (char *)last;
 }
 EXPORT_SYMBOL(strrchr);
 #endif
@@ -596,6 +596,11 @@
  * @s: Pointer to the start of the area.
  * @count: The size of the area.
  *
+ * Note: usually using memset() is just fine (!), but in cases
+ * where clearing out _local_ data at the end of a scope is
+ * necessary, memzero_explicit() should be used instead in
+ * order to prevent the compiler from optimising away zeroing.
+ *
  * memzero_explicit() doesn't need an arch-specific version as
  * it just invokes the one of memset() implicitly.
  */
diff --git a/lib/test_kasan.c b/lib/test_kasan.c
new file mode 100644
index 0000000..098c08e
--- /dev/null
+++ b/lib/test_kasan.c
@@ -0,0 +1,277 @@
+/*
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Andrey Ryabinin <a.ryabinin@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.
+ *
+ */
+
+#define pr_fmt(fmt) "kasan test: %s " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+static noinline void __init kmalloc_oob_right(void)
+{
+	char *ptr;
+	size_t size = 123;
+
+	pr_info("out-of-bounds to right\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	ptr[size] = 'x';
+	kfree(ptr);
+}
+
+static noinline void __init kmalloc_oob_left(void)
+{
+	char *ptr;
+	size_t size = 15;
+
+	pr_info("out-of-bounds to left\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	*ptr = *(ptr - 1);
+	kfree(ptr);
+}
+
+static noinline void __init kmalloc_node_oob_right(void)
+{
+	char *ptr;
+	size_t size = 4096;
+
+	pr_info("kmalloc_node(): out-of-bounds to right\n");
+	ptr = kmalloc_node(size, GFP_KERNEL, 0);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	ptr[size] = 0;
+	kfree(ptr);
+}
+
+static noinline void __init kmalloc_large_oob_rigth(void)
+{
+	char *ptr;
+	size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
+
+	pr_info("kmalloc large allocation: out-of-bounds to right\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	ptr[size] = 0;
+	kfree(ptr);
+}
+
+static noinline void __init kmalloc_oob_krealloc_more(void)
+{
+	char *ptr1, *ptr2;
+	size_t size1 = 17;
+	size_t size2 = 19;
+
+	pr_info("out-of-bounds after krealloc more\n");
+	ptr1 = kmalloc(size1, GFP_KERNEL);
+	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
+	if (!ptr1 || !ptr2) {
+		pr_err("Allocation failed\n");
+		kfree(ptr1);
+		return;
+	}
+
+	ptr2[size2] = 'x';
+	kfree(ptr2);
+}
+
+static noinline void __init kmalloc_oob_krealloc_less(void)
+{
+	char *ptr1, *ptr2;
+	size_t size1 = 17;
+	size_t size2 = 15;
+
+	pr_info("out-of-bounds after krealloc less\n");
+	ptr1 = kmalloc(size1, GFP_KERNEL);
+	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
+	if (!ptr1 || !ptr2) {
+		pr_err("Allocation failed\n");
+		kfree(ptr1);
+		return;
+	}
+	ptr2[size1] = 'x';
+	kfree(ptr2);
+}
+
+static noinline void __init kmalloc_oob_16(void)
+{
+	struct {
+		u64 words[2];
+	} *ptr1, *ptr2;
+
+	pr_info("kmalloc out-of-bounds for 16-bytes access\n");
+	ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
+	ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
+	if (!ptr1 || !ptr2) {
+		pr_err("Allocation failed\n");
+		kfree(ptr1);
+		kfree(ptr2);
+		return;
+	}
+	*ptr1 = *ptr2;
+	kfree(ptr1);
+	kfree(ptr2);
+}
+
+static noinline void __init kmalloc_oob_in_memset(void)
+{
+	char *ptr;
+	size_t size = 666;
+
+	pr_info("out-of-bounds in memset\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	memset(ptr, 0, size+5);
+	kfree(ptr);
+}
+
+static noinline void __init kmalloc_uaf(void)
+{
+	char *ptr;
+	size_t size = 10;
+
+	pr_info("use-after-free\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	kfree(ptr);
+	*(ptr + 8) = 'x';
+}
+
+static noinline void __init kmalloc_uaf_memset(void)
+{
+	char *ptr;
+	size_t size = 33;
+
+	pr_info("use-after-free in memset\n");
+	ptr = kmalloc(size, GFP_KERNEL);
+	if (!ptr) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	kfree(ptr);
+	memset(ptr, 0, size);
+}
+
+static noinline void __init kmalloc_uaf2(void)
+{
+	char *ptr1, *ptr2;
+	size_t size = 43;
+
+	pr_info("use-after-free after another kmalloc\n");
+	ptr1 = kmalloc(size, GFP_KERNEL);
+	if (!ptr1) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	kfree(ptr1);
+	ptr2 = kmalloc(size, GFP_KERNEL);
+	if (!ptr2) {
+		pr_err("Allocation failed\n");
+		return;
+	}
+
+	ptr1[40] = 'x';
+	kfree(ptr2);
+}
+
+static noinline void __init kmem_cache_oob(void)
+{
+	char *p;
+	size_t size = 200;
+	struct kmem_cache *cache = kmem_cache_create("test_cache",
+						size, 0,
+						0, NULL);
+	if (!cache) {
+		pr_err("Cache allocation failed\n");
+		return;
+	}
+	pr_info("out-of-bounds in kmem_cache_alloc\n");
+	p = kmem_cache_alloc(cache, GFP_KERNEL);
+	if (!p) {
+		pr_err("Allocation failed\n");
+		kmem_cache_destroy(cache);
+		return;
+	}
+
+	*p = p[size];
+	kmem_cache_free(cache, p);
+	kmem_cache_destroy(cache);
+}
+
+static char global_array[10];
+
+static noinline void __init kasan_global_oob(void)
+{
+	volatile int i = 3;
+	char *p = &global_array[ARRAY_SIZE(global_array) + i];
+
+	pr_info("out-of-bounds global variable\n");
+	*(volatile char *)p;
+}
+
+static noinline void __init kasan_stack_oob(void)
+{
+	char stack_array[10];
+	volatile int i = 0;
+	char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
+
+	pr_info("out-of-bounds on stack\n");
+	*(volatile char *)p;
+}
+
+static int __init kmalloc_tests_init(void)
+{
+	kmalloc_oob_right();
+	kmalloc_oob_left();
+	kmalloc_node_oob_right();
+	kmalloc_large_oob_rigth();
+	kmalloc_oob_krealloc_more();
+	kmalloc_oob_krealloc_less();
+	kmalloc_oob_16();
+	kmalloc_oob_in_memset();
+	kmalloc_uaf();
+	kmalloc_uaf_memset();
+	kmalloc_uaf2();
+	kmem_cache_oob();
+	kasan_stack_oob();
+	kasan_global_oob();
+	return -EAGAIN;
+}
+
+module_init(kmalloc_tests_init);
+MODULE_LICENSE("GPL");
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 602d208..b235c96 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -794,6 +794,87 @@
 }
 
 static noinline_for_stack
+char *bitmap_string(char *buf, char *end, unsigned long *bitmap,
+		    struct printf_spec spec, const char *fmt)
+{
+	const int CHUNKSZ = 32;
+	int nr_bits = max_t(int, spec.field_width, 0);
+	int i, chunksz;
+	bool first = true;
+
+	/* reused to print numbers */
+	spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 };
+
+	chunksz = nr_bits & (CHUNKSZ - 1);
+	if (chunksz == 0)
+		chunksz = CHUNKSZ;
+
+	i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ;
+	for (; i >= 0; i -= CHUNKSZ) {
+		u32 chunkmask, val;
+		int word, bit;
+
+		chunkmask = ((1ULL << chunksz) - 1);
+		word = i / BITS_PER_LONG;
+		bit = i % BITS_PER_LONG;
+		val = (bitmap[word] >> bit) & chunkmask;
+
+		if (!first) {
+			if (buf < end)
+				*buf = ',';
+			buf++;
+		}
+		first = false;
+
+		spec.field_width = DIV_ROUND_UP(chunksz, 4);
+		buf = number(buf, end, val, spec);
+
+		chunksz = CHUNKSZ;
+	}
+	return buf;
+}
+
+static noinline_for_stack
+char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
+			 struct printf_spec spec, const char *fmt)
+{
+	int nr_bits = max_t(int, spec.field_width, 0);
+	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
+	int cur, rbot, rtop;
+	bool first = true;
+
+	/* reused to print numbers */
+	spec = (struct printf_spec){ .base = 10 };
+
+	rbot = cur = find_first_bit(bitmap, nr_bits);
+	while (cur < nr_bits) {
+		rtop = cur;
+		cur = find_next_bit(bitmap, nr_bits, cur + 1);
+		if (cur < nr_bits && cur <= rtop + 1)
+			continue;
+
+		if (!first) {
+			if (buf < end)
+				*buf = ',';
+			buf++;
+		}
+		first = false;
+
+		buf = number(buf, end, rbot, spec);
+		if (rbot < rtop) {
+			if (buf < end)
+				*buf = '-';
+			buf++;
+
+			buf = number(buf, end, rtop, spec);
+		}
+
+		rbot = cur;
+	}
+	return buf;
+}
+
+static noinline_for_stack
 char *mac_address_string(char *buf, char *end, u8 *addr,
 			 struct printf_spec spec, const char *fmt)
 {
@@ -1258,6 +1339,10 @@
  * - 'B' For backtraced symbolic direct pointers with offset
  * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
  * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
+ * - 'b[l]' For a bitmap, the number of bits is determined by the field
+ *       width which must be explicitly specified either as part of the
+ *       format string '%32b[l]' or through '%*b[l]', [l] selects
+ *       range-list format instead of hex format
  * - 'M' For a 6-byte MAC address, it prints the address in the
  *       usual colon-separated hex notation
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
@@ -1354,6 +1439,13 @@
 		return resource_string(buf, end, ptr, spec, fmt);
 	case 'h':
 		return hex_string(buf, end, ptr, spec, fmt);
+	case 'b':
+		switch (fmt[1]) {
+		case 'l':
+			return bitmap_list_string(buf, end, ptr, spec, fmt);
+		default:
+			return bitmap_string(buf, end, ptr, spec, fmt);
+		}
 	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
 	case 'm':			/* Contiguous: 000102030405 */
 					/* [mM]F (FDDI) */
@@ -1689,6 +1781,8 @@
  * %pB output the name of a backtrace symbol with its offset
  * %pR output the address range in a struct resource with decoded flags
  * %pr output the address range in a struct resource with raw flags
+ * %pb output the bitmap with field width as the number of bits
+ * %pbl output the bitmap as range list with field width as the number of bits
  * %pM output a 6-byte MAC address with colons
  * %pMR output a 6-byte MAC address with colons in reversed order
  * %pMF output a 6-byte MAC address with dashes
diff --git a/mm/Makefile b/mm/Makefile
index 3548460..3c1caa2 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -2,6 +2,9 @@
 # Makefile for the linux memory manager.
 #
 
+KASAN_SANITIZE_slab_common.o := n
+KASAN_SANITIZE_slub.o := n
+
 mmu-y			:= nommu.o
 mmu-$(CONFIG_MMU)	:= gup.o highmem.o memory.o mincore.o \
 			   mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
@@ -49,9 +52,9 @@
 obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_SLUB) += slub.o
 obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
+obj-$(CONFIG_KASAN)	+= kasan/
 obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
-obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
 obj-$(CONFIG_QUICKLIST) += quicklist.o
 obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o
diff --git a/mm/compaction.c b/mm/compaction.c
index d50d6de..8c0d945 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -16,6 +16,7 @@
 #include <linux/sysfs.h>
 #include <linux/balloon_compaction.h>
 #include <linux/page-isolation.h>
+#include <linux/kasan.h>
 #include "internal.h"
 
 #ifdef CONFIG_COMPACTION
@@ -72,6 +73,7 @@
 	list_for_each_entry(page, list, lru) {
 		arch_alloc_page(page, 0);
 		kernel_map_pages(page, 1, 1);
+		kasan_alloc_pages(page, 0);
 	}
 }
 
diff --git a/mm/fadvise.c b/mm/fadvise.c
index fac23ec..4a3907c 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -28,6 +28,7 @@
 SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
 {
 	struct fd f = fdget(fd);
+	struct inode *inode;
 	struct address_space *mapping;
 	struct backing_dev_info *bdi;
 	loff_t endbyte;			/* inclusive */
@@ -39,7 +40,8 @@
 	if (!f.file)
 		return -EBADF;
 
-	if (S_ISFIFO(file_inode(f.file)->i_mode)) {
+	inode = file_inode(f.file);
+	if (S_ISFIFO(inode->i_mode)) {
 		ret = -ESPIPE;
 		goto out;
 	}
@@ -50,7 +52,7 @@
 		goto out;
 	}
 
-	if (mapping->a_ops->get_xip_mem) {
+	if (IS_DAX(inode)) {
 		switch (advice) {
 		case POSIX_FADV_NORMAL:
 		case POSIX_FADV_RANDOM:
diff --git a/mm/filemap.c b/mm/filemap.c
index d9f5336..ad72420 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1695,8 +1695,7 @@
 	loff_t *ppos = &iocb->ki_pos;
 	loff_t pos = *ppos;
 
-	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
-	if (file->f_flags & O_DIRECT) {
+	if (io_is_direct(file)) {
 		struct address_space *mapping = file->f_mapping;
 		struct inode *inode = mapping->host;
 		size_t count = iov_iter_count(iter);
@@ -1723,9 +1722,11 @@
 		 * we've already read everything we wanted to, or if
 		 * there was a short read because we hit EOF, go ahead
 		 * and return.  Otherwise fallthrough to buffered io for
-		 * the rest of the read.
+		 * the rest of the read.  Buffered reads will not work for
+		 * DAX files, so don't bother trying.
 		 */
-		if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) {
+		if (retval < 0 || !iov_iter_count(iter) || *ppos >= size ||
+		    IS_DAX(inode)) {
 			file_accessed(file);
 			goto out;
 		}
@@ -2582,18 +2583,20 @@
 	if (err)
 		goto out;
 
-	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
-	if (unlikely(file->f_flags & O_DIRECT)) {
+	if (io_is_direct(file)) {
 		loff_t endbyte;
 
 		written = generic_file_direct_write(iocb, from, pos);
-		if (written < 0 || written == count)
+		/*
+		 * If the write stopped short of completing, fall back to
+		 * buffered writes.  Some filesystems do this for writes to
+		 * holes, for example.  For DAX files, a buffered write will
+		 * not succeed (even if it did, DAX does not handle dirty
+		 * page-cache pages correctly).
+		 */
+		if (written < 0 || written == count || IS_DAX(inode))
 			goto out;
 
-		/*
-		 * direct-io write to a hole: fall through to buffered I/O
-		 * for completing the rest of the request.
-		 */
 		pos += written;
 		count -= written;
 
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
deleted file mode 100644
index c175f9f..0000000
--- a/mm/filemap_xip.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- *	linux/mm/filemap_xip.c
- *
- * Copyright (C) 2005 IBM Corporation
- * Author: Carsten Otte <cotte@de.ibm.com>
- *
- * derived from linux/mm/filemap.c - Copyright (C) Linus Torvalds
- *
- */
-
-#include <linux/fs.h>
-#include <linux/backing-dev.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-#include <linux/uio.h>
-#include <linux/rmap.h>
-#include <linux/mmu_notifier.h>
-#include <linux/sched.h>
-#include <linux/seqlock.h>
-#include <linux/mutex.h>
-#include <linux/gfp.h>
-#include <asm/tlbflush.h>
-#include <asm/io.h>
-
-/*
- * We do use our own empty page to avoid interference with other users
- * of ZERO_PAGE(), such as /dev/zero
- */
-static DEFINE_MUTEX(xip_sparse_mutex);
-static seqcount_t xip_sparse_seq = SEQCNT_ZERO(xip_sparse_seq);
-static struct page *__xip_sparse_page;
-
-/* called under xip_sparse_mutex */
-static struct page *xip_sparse_page(void)
-{
-	if (!__xip_sparse_page) {
-		struct page *page = alloc_page(GFP_HIGHUSER | __GFP_ZERO);
-
-		if (page)
-			__xip_sparse_page = page;
-	}
-	return __xip_sparse_page;
-}
-
-/*
- * This is a file read routine for execute in place files, and uses
- * the mapping->a_ops->get_xip_mem() function for the actual low-level
- * stuff.
- *
- * Note the struct file* is not used at all.  It may be NULL.
- */
-static ssize_t
-do_xip_mapping_read(struct address_space *mapping,
-		    struct file_ra_state *_ra,
-		    struct file *filp,
-		    char __user *buf,
-		    size_t len,
-		    loff_t *ppos)
-{
-	struct inode *inode = mapping->host;
-	pgoff_t index, end_index;
-	unsigned long offset;
-	loff_t isize, pos;
-	size_t copied = 0, error = 0;
-
-	BUG_ON(!mapping->a_ops->get_xip_mem);
-
-	pos = *ppos;
-	index = pos >> PAGE_CACHE_SHIFT;
-	offset = pos & ~PAGE_CACHE_MASK;
-
-	isize = i_size_read(inode);
-	if (!isize)
-		goto out;
-
-	end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
-	do {
-		unsigned long nr, left;
-		void *xip_mem;
-		unsigned long xip_pfn;
-		int zero = 0;
-
-		/* nr is the maximum number of bytes to copy from this page */
-		nr = PAGE_CACHE_SIZE;
-		if (index >= end_index) {
-			if (index > end_index)
-				goto out;
-			nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
-			if (nr <= offset) {
-				goto out;
-			}
-		}
-		nr = nr - offset;
-		if (nr > len - copied)
-			nr = len - copied;
-
-		error = mapping->a_ops->get_xip_mem(mapping, index, 0,
-							&xip_mem, &xip_pfn);
-		if (unlikely(error)) {
-			if (error == -ENODATA) {
-				/* sparse */
-				zero = 1;
-			} else
-				goto out;
-		}
-
-		/* If users can be writing to this page using arbitrary
-		 * virtual addresses, take care about potential aliasing
-		 * before reading the page on the kernel side.
-		 */
-		if (mapping_writably_mapped(mapping))
-			/* address based flush */ ;
-
-		/*
-		 * Ok, we have the mem, so now we can copy it to user space...
-		 *
-		 * The actor routine returns how many bytes were actually used..
-		 * NOTE! This may not be the same as how much of a user buffer
-		 * we filled up (we may be padding etc), so we can only update
-		 * "pos" here (the actor routine has to update the user buffer
-		 * pointers and the remaining count).
-		 */
-		if (!zero)
-			left = __copy_to_user(buf+copied, xip_mem+offset, nr);
-		else
-			left = __clear_user(buf + copied, nr);
-
-		if (left) {
-			error = -EFAULT;
-			goto out;
-		}
-
-		copied += (nr - left);
-		offset += (nr - left);
-		index += offset >> PAGE_CACHE_SHIFT;
-		offset &= ~PAGE_CACHE_MASK;
-	} while (copied < len);
-
-out:
-	*ppos = pos + copied;
-	if (filp)
-		file_accessed(filp);
-
-	return (copied ? copied : error);
-}
-
-ssize_t
-xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
-{
-	if (!access_ok(VERIFY_WRITE, buf, len))
-		return -EFAULT;
-
-	return do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
-			    buf, len, ppos);
-}
-EXPORT_SYMBOL_GPL(xip_file_read);
-
-/*
- * __xip_unmap is invoked from xip_unmap and xip_write
- *
- * This function walks all vmas of the address_space and unmaps the
- * __xip_sparse_page when found at pgoff.
- */
-static void __xip_unmap(struct address_space * mapping, unsigned long pgoff)
-{
-	struct vm_area_struct *vma;
-	struct page *page;
-	unsigned count;
-	int locked = 0;
-
-	count = read_seqcount_begin(&xip_sparse_seq);
-
-	page = __xip_sparse_page;
-	if (!page)
-		return;
-
-retry:
-	i_mmap_lock_read(mapping);
-	vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
-		pte_t *pte, pteval;
-		spinlock_t *ptl;
-		struct mm_struct *mm = vma->vm_mm;
-		unsigned long address = vma->vm_start +
-			((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
-
-		BUG_ON(address < vma->vm_start || address >= vma->vm_end);
-		pte = page_check_address(page, mm, address, &ptl, 1);
-		if (pte) {
-			/* Nuke the page table entry. */
-			flush_cache_page(vma, address, pte_pfn(*pte));
-			pteval = ptep_clear_flush(vma, address, pte);
-			page_remove_rmap(page);
-			dec_mm_counter(mm, MM_FILEPAGES);
-			BUG_ON(pte_dirty(pteval));
-			pte_unmap_unlock(pte, ptl);
-			/* must invalidate_page _before_ freeing the page */
-			mmu_notifier_invalidate_page(mm, address);
-			page_cache_release(page);
-		}
-	}
-	i_mmap_unlock_read(mapping);
-
-	if (locked) {
-		mutex_unlock(&xip_sparse_mutex);
-	} else if (read_seqcount_retry(&xip_sparse_seq, count)) {
-		mutex_lock(&xip_sparse_mutex);
-		locked = 1;
-		goto retry;
-	}
-}
-
-/*
- * xip_fault() is invoked via the vma operations vector for a
- * mapped memory region to read in file data during a page fault.
- *
- * This function is derived from filemap_fault, but used for execute in place
- */
-static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-	struct file *file = vma->vm_file;
-	struct address_space *mapping = file->f_mapping;
-	struct inode *inode = mapping->host;
-	pgoff_t size;
-	void *xip_mem;
-	unsigned long xip_pfn;
-	struct page *page;
-	int error;
-
-	/* XXX: are VM_FAULT_ codes OK? */
-again:
-	size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (vmf->pgoff >= size)
-		return VM_FAULT_SIGBUS;
-
-	error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 0,
-						&xip_mem, &xip_pfn);
-	if (likely(!error))
-		goto found;
-	if (error != -ENODATA)
-		return VM_FAULT_OOM;
-
-	/* sparse block */
-	if ((vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
-	    (vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) &&
-	    (!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
-		int err;
-
-		/* maybe shared writable, allocate new block */
-		mutex_lock(&xip_sparse_mutex);
-		error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 1,
-							&xip_mem, &xip_pfn);
-		mutex_unlock(&xip_sparse_mutex);
-		if (error)
-			return VM_FAULT_SIGBUS;
-		/* unmap sparse mappings at pgoff from all other vmas */
-		__xip_unmap(mapping, vmf->pgoff);
-
-found:
-		err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
-							xip_pfn);
-		if (err == -ENOMEM)
-			return VM_FAULT_OOM;
-		/*
-		 * err == -EBUSY is fine, we've raced against another thread
-		 * that faulted-in the same page
-		 */
-		if (err != -EBUSY)
-			BUG_ON(err);
-		return VM_FAULT_NOPAGE;
-	} else {
-		int err, ret = VM_FAULT_OOM;
-
-		mutex_lock(&xip_sparse_mutex);
-		write_seqcount_begin(&xip_sparse_seq);
-		error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 0,
-							&xip_mem, &xip_pfn);
-		if (unlikely(!error)) {
-			write_seqcount_end(&xip_sparse_seq);
-			mutex_unlock(&xip_sparse_mutex);
-			goto again;
-		}
-		if (error != -ENODATA)
-			goto out;
-		/* not shared and writable, use xip_sparse_page() */
-		page = xip_sparse_page();
-		if (!page)
-			goto out;
-		err = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
-							page);
-		if (err == -ENOMEM)
-			goto out;
-
-		ret = VM_FAULT_NOPAGE;
-out:
-		write_seqcount_end(&xip_sparse_seq);
-		mutex_unlock(&xip_sparse_mutex);
-
-		return ret;
-	}
-}
-
-static const struct vm_operations_struct xip_file_vm_ops = {
-	.fault	= xip_file_fault,
-	.page_mkwrite	= filemap_page_mkwrite,
-};
-
-int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
-{
-	BUG_ON(!file->f_mapping->a_ops->get_xip_mem);
-
-	file_accessed(file);
-	vma->vm_ops = &xip_file_vm_ops;
-	vma->vm_flags |= VM_MIXEDMAP;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(xip_file_mmap);
-
-static ssize_t
-__xip_file_write(struct file *filp, const char __user *buf,
-		  size_t count, loff_t pos, loff_t *ppos)
-{
-	struct address_space * mapping = filp->f_mapping;
-	const struct address_space_operations *a_ops = mapping->a_ops;
-	struct inode 	*inode = mapping->host;
-	long		status = 0;
-	size_t		bytes;
-	ssize_t		written = 0;
-
-	BUG_ON(!mapping->a_ops->get_xip_mem);
-
-	do {
-		unsigned long index;
-		unsigned long offset;
-		size_t copied;
-		void *xip_mem;
-		unsigned long xip_pfn;
-
-		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
-		index = pos >> PAGE_CACHE_SHIFT;
-		bytes = PAGE_CACHE_SIZE - offset;
-		if (bytes > count)
-			bytes = count;
-
-		status = a_ops->get_xip_mem(mapping, index, 0,
-						&xip_mem, &xip_pfn);
-		if (status == -ENODATA) {
-			/* we allocate a new page unmap it */
-			mutex_lock(&xip_sparse_mutex);
-			status = a_ops->get_xip_mem(mapping, index, 1,
-							&xip_mem, &xip_pfn);
-			mutex_unlock(&xip_sparse_mutex);
-			if (!status)
-				/* unmap page at pgoff from all other vmas */
-				__xip_unmap(mapping, index);
-		}
-
-		if (status)
-			break;
-
-		copied = bytes -
-			__copy_from_user_nocache(xip_mem + offset, buf, bytes);
-
-		if (likely(copied > 0)) {
-			status = copied;
-
-			if (status >= 0) {
-				written += status;
-				count -= status;
-				pos += status;
-				buf += status;
-			}
-		}
-		if (unlikely(copied != bytes))
-			if (status >= 0)
-				status = -EFAULT;
-		if (status < 0)
-			break;
-	} while (count);
-	*ppos = pos;
-	/*
-	 * No need to use i_size_read() here, the i_size
-	 * cannot change under us because we hold i_mutex.
-	 */
-	if (pos > inode->i_size) {
-		i_size_write(inode, pos);
-		mark_inode_dirty(inode);
-	}
-
-	return written ? written : status;
-}
-
-ssize_t
-xip_file_write(struct file *filp, const char __user *buf, size_t len,
-	       loff_t *ppos)
-{
-	struct address_space *mapping = filp->f_mapping;
-	struct inode *inode = mapping->host;
-	size_t count;
-	loff_t pos;
-	ssize_t ret;
-
-	mutex_lock(&inode->i_mutex);
-
-	if (!access_ok(VERIFY_READ, buf, len)) {
-		ret=-EFAULT;
-		goto out_up;
-	}
-
-	pos = *ppos;
-	count = len;
-
-	/* We can write back this queue in page reclaim */
-	current->backing_dev_info = inode_to_bdi(inode);
-
-	ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode));
-	if (ret)
-		goto out_backing;
-	if (count == 0)
-		goto out_backing;
-
-	ret = file_remove_suid(filp);
-	if (ret)
-		goto out_backing;
-
-	ret = file_update_time(filp);
-	if (ret)
-		goto out_backing;
-
-	ret = __xip_file_write (filp, buf, count, pos, ppos);
-
- out_backing:
-	current->backing_dev_info = NULL;
- out_up:
-	mutex_unlock(&inode->i_mutex);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(xip_file_write);
-
-/*
- * truncate a page used for execute in place
- * functionality is analog to block_truncate_page but does use get_xip_mem
- * to get the page instead of page cache
- */
-int
-xip_truncate_page(struct address_space *mapping, loff_t from)
-{
-	pgoff_t index = from >> PAGE_CACHE_SHIFT;
-	unsigned offset = from & (PAGE_CACHE_SIZE-1);
-	unsigned blocksize;
-	unsigned length;
-	void *xip_mem;
-	unsigned long xip_pfn;
-	int err;
-
-	BUG_ON(!mapping->a_ops->get_xip_mem);
-
-	blocksize = 1 << mapping->host->i_blkbits;
-	length = offset & (blocksize - 1);
-
-	/* Block boundary? Nothing to do */
-	if (!length)
-		return 0;
-
-	length = blocksize - length;
-
-	err = mapping->a_ops->get_xip_mem(mapping, index, 0,
-						&xip_mem, &xip_pfn);
-	if (unlikely(err)) {
-		if (err == -ENODATA)
-			/* Hole? No need to truncate */
-			return 0;
-		else
-			return err;
-	}
-	memset(xip_mem + offset, 0, length);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/gup.c b/mm/gup.c
index 51bf0b0..a6e24e2 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1092,7 +1092,7 @@
 
 	pmdp = pmd_offset(&pud, addr);
 	do {
-		pmd_t pmd = ACCESS_ONCE(*pmdp);
+		pmd_t pmd = READ_ONCE(*pmdp);
 
 		next = pmd_addr_end(addr, end);
 		if (pmd_none(pmd) || pmd_trans_splitting(pmd))
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile
new file mode 100644
index 0000000..bd837b8
--- /dev/null
+++ b/mm/kasan/Makefile
@@ -0,0 +1,8 @@
+KASAN_SANITIZE := n
+
+CFLAGS_REMOVE_kasan.o = -pg
+# Function splitter causes unnecessary splits in __asan_load1/__asan_store1
+# see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
+CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
+
+obj-y := kasan.o report.o
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
new file mode 100644
index 0000000..78fee63
--- /dev/null
+++ b/mm/kasan/kasan.c
@@ -0,0 +1,516 @@
+/*
+ * This file contains shadow memory manipulation code.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ *
+ * Some of code borrowed from https://github.com/xairy/linux by
+ *        Andrey Konovalov <adech.fo@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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define DISABLE_BRANCH_PROFILING
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kasan.h>
+
+#include "kasan.h"
+#include "../slab.h"
+
+/*
+ * Poisons the shadow memory for 'size' bytes starting from 'addr'.
+ * Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE.
+ */
+static void kasan_poison_shadow(const void *address, size_t size, u8 value)
+{
+	void *shadow_start, *shadow_end;
+
+	shadow_start = kasan_mem_to_shadow(address);
+	shadow_end = kasan_mem_to_shadow(address + size);
+
+	memset(shadow_start, value, shadow_end - shadow_start);
+}
+
+void kasan_unpoison_shadow(const void *address, size_t size)
+{
+	kasan_poison_shadow(address, size, 0);
+
+	if (size & KASAN_SHADOW_MASK) {
+		u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size);
+		*shadow = size & KASAN_SHADOW_MASK;
+	}
+}
+
+
+/*
+ * All functions below always inlined so compiler could
+ * perform better optimizations in each of __asan_loadX/__assn_storeX
+ * depending on memory access size X.
+ */
+
+static __always_inline bool memory_is_poisoned_1(unsigned long addr)
+{
+	s8 shadow_value = *(s8 *)kasan_mem_to_shadow((void *)addr);
+
+	if (unlikely(shadow_value)) {
+		s8 last_accessible_byte = addr & KASAN_SHADOW_MASK;
+		return unlikely(last_accessible_byte >= shadow_value);
+	}
+
+	return false;
+}
+
+static __always_inline bool memory_is_poisoned_2(unsigned long addr)
+{
+	u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr);
+
+	if (unlikely(*shadow_addr)) {
+		if (memory_is_poisoned_1(addr + 1))
+			return true;
+
+		if (likely(((addr + 1) & KASAN_SHADOW_MASK) != 0))
+			return false;
+
+		return unlikely(*(u8 *)shadow_addr);
+	}
+
+	return false;
+}
+
+static __always_inline bool memory_is_poisoned_4(unsigned long addr)
+{
+	u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr);
+
+	if (unlikely(*shadow_addr)) {
+		if (memory_is_poisoned_1(addr + 3))
+			return true;
+
+		if (likely(((addr + 3) & KASAN_SHADOW_MASK) >= 3))
+			return false;
+
+		return unlikely(*(u8 *)shadow_addr);
+	}
+
+	return false;
+}
+
+static __always_inline bool memory_is_poisoned_8(unsigned long addr)
+{
+	u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr);
+
+	if (unlikely(*shadow_addr)) {
+		if (memory_is_poisoned_1(addr + 7))
+			return true;
+
+		if (likely(((addr + 7) & KASAN_SHADOW_MASK) >= 7))
+			return false;
+
+		return unlikely(*(u8 *)shadow_addr);
+	}
+
+	return false;
+}
+
+static __always_inline bool memory_is_poisoned_16(unsigned long addr)
+{
+	u32 *shadow_addr = (u32 *)kasan_mem_to_shadow((void *)addr);
+
+	if (unlikely(*shadow_addr)) {
+		u16 shadow_first_bytes = *(u16 *)shadow_addr;
+		s8 last_byte = (addr + 15) & KASAN_SHADOW_MASK;
+
+		if (unlikely(shadow_first_bytes))
+			return true;
+
+		if (likely(!last_byte))
+			return false;
+
+		return memory_is_poisoned_1(addr + 15);
+	}
+
+	return false;
+}
+
+static __always_inline unsigned long bytes_is_zero(const u8 *start,
+					size_t size)
+{
+	while (size) {
+		if (unlikely(*start))
+			return (unsigned long)start;
+		start++;
+		size--;
+	}
+
+	return 0;
+}
+
+static __always_inline unsigned long memory_is_zero(const void *start,
+						const void *end)
+{
+	unsigned int words;
+	unsigned long ret;
+	unsigned int prefix = (unsigned long)start % 8;
+
+	if (end - start <= 16)
+		return bytes_is_zero(start, end - start);
+
+	if (prefix) {
+		prefix = 8 - prefix;
+		ret = bytes_is_zero(start, prefix);
+		if (unlikely(ret))
+			return ret;
+		start += prefix;
+	}
+
+	words = (end - start) / 8;
+	while (words) {
+		if (unlikely(*(u64 *)start))
+			return bytes_is_zero(start, 8);
+		start += 8;
+		words--;
+	}
+
+	return bytes_is_zero(start, (end - start) % 8);
+}
+
+static __always_inline bool memory_is_poisoned_n(unsigned long addr,
+						size_t size)
+{
+	unsigned long ret;
+
+	ret = memory_is_zero(kasan_mem_to_shadow((void *)addr),
+			kasan_mem_to_shadow((void *)addr + size - 1) + 1);
+
+	if (unlikely(ret)) {
+		unsigned long last_byte = addr + size - 1;
+		s8 *last_shadow = (s8 *)kasan_mem_to_shadow((void *)last_byte);
+
+		if (unlikely(ret != (unsigned long)last_shadow ||
+			((last_byte & KASAN_SHADOW_MASK) >= *last_shadow)))
+			return true;
+	}
+	return false;
+}
+
+static __always_inline bool memory_is_poisoned(unsigned long addr, size_t size)
+{
+	if (__builtin_constant_p(size)) {
+		switch (size) {
+		case 1:
+			return memory_is_poisoned_1(addr);
+		case 2:
+			return memory_is_poisoned_2(addr);
+		case 4:
+			return memory_is_poisoned_4(addr);
+		case 8:
+			return memory_is_poisoned_8(addr);
+		case 16:
+			return memory_is_poisoned_16(addr);
+		default:
+			BUILD_BUG();
+		}
+	}
+
+	return memory_is_poisoned_n(addr, size);
+}
+
+
+static __always_inline void check_memory_region(unsigned long addr,
+						size_t size, bool write)
+{
+	struct kasan_access_info info;
+
+	if (unlikely(size == 0))
+		return;
+
+	if (unlikely((void *)addr <
+		kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
+		info.access_addr = (void *)addr;
+		info.access_size = size;
+		info.is_write = write;
+		info.ip = _RET_IP_;
+		kasan_report_user_access(&info);
+		return;
+	}
+
+	if (likely(!memory_is_poisoned(addr, size)))
+		return;
+
+	kasan_report(addr, size, write, _RET_IP_);
+}
+
+void __asan_loadN(unsigned long addr, size_t size);
+void __asan_storeN(unsigned long addr, size_t size);
+
+#undef memset
+void *memset(void *addr, int c, size_t len)
+{
+	__asan_storeN((unsigned long)addr, len);
+
+	return __memset(addr, c, len);
+}
+
+#undef memmove
+void *memmove(void *dest, const void *src, size_t len)
+{
+	__asan_loadN((unsigned long)src, len);
+	__asan_storeN((unsigned long)dest, len);
+
+	return __memmove(dest, src, len);
+}
+
+#undef memcpy
+void *memcpy(void *dest, const void *src, size_t len)
+{
+	__asan_loadN((unsigned long)src, len);
+	__asan_storeN((unsigned long)dest, len);
+
+	return __memcpy(dest, src, len);
+}
+
+void kasan_alloc_pages(struct page *page, unsigned int order)
+{
+	if (likely(!PageHighMem(page)))
+		kasan_unpoison_shadow(page_address(page), PAGE_SIZE << order);
+}
+
+void kasan_free_pages(struct page *page, unsigned int order)
+{
+	if (likely(!PageHighMem(page)))
+		kasan_poison_shadow(page_address(page),
+				PAGE_SIZE << order,
+				KASAN_FREE_PAGE);
+}
+
+void kasan_poison_slab(struct page *page)
+{
+	kasan_poison_shadow(page_address(page),
+			PAGE_SIZE << compound_order(page),
+			KASAN_KMALLOC_REDZONE);
+}
+
+void kasan_unpoison_object_data(struct kmem_cache *cache, void *object)
+{
+	kasan_unpoison_shadow(object, cache->object_size);
+}
+
+void kasan_poison_object_data(struct kmem_cache *cache, void *object)
+{
+	kasan_poison_shadow(object,
+			round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE),
+			KASAN_KMALLOC_REDZONE);
+}
+
+void kasan_slab_alloc(struct kmem_cache *cache, void *object)
+{
+	kasan_kmalloc(cache, object, cache->object_size);
+}
+
+void kasan_slab_free(struct kmem_cache *cache, void *object)
+{
+	unsigned long size = cache->object_size;
+	unsigned long rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE);
+
+	/* RCU slabs could be legally used after free within the RCU period */
+	if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU))
+		return;
+
+	kasan_poison_shadow(object, rounded_up_size, KASAN_KMALLOC_FREE);
+}
+
+void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size)
+{
+	unsigned long redzone_start;
+	unsigned long redzone_end;
+
+	if (unlikely(object == NULL))
+		return;
+
+	redzone_start = round_up((unsigned long)(object + size),
+				KASAN_SHADOW_SCALE_SIZE);
+	redzone_end = round_up((unsigned long)object + cache->object_size,
+				KASAN_SHADOW_SCALE_SIZE);
+
+	kasan_unpoison_shadow(object, size);
+	kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
+		KASAN_KMALLOC_REDZONE);
+}
+EXPORT_SYMBOL(kasan_kmalloc);
+
+void kasan_kmalloc_large(const void *ptr, size_t size)
+{
+	struct page *page;
+	unsigned long redzone_start;
+	unsigned long redzone_end;
+
+	if (unlikely(ptr == NULL))
+		return;
+
+	page = virt_to_page(ptr);
+	redzone_start = round_up((unsigned long)(ptr + size),
+				KASAN_SHADOW_SCALE_SIZE);
+	redzone_end = (unsigned long)ptr + (PAGE_SIZE << compound_order(page));
+
+	kasan_unpoison_shadow(ptr, size);
+	kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
+		KASAN_PAGE_REDZONE);
+}
+
+void kasan_krealloc(const void *object, size_t size)
+{
+	struct page *page;
+
+	if (unlikely(object == ZERO_SIZE_PTR))
+		return;
+
+	page = virt_to_head_page(object);
+
+	if (unlikely(!PageSlab(page)))
+		kasan_kmalloc_large(object, size);
+	else
+		kasan_kmalloc(page->slab_cache, object, size);
+}
+
+void kasan_kfree_large(const void *ptr)
+{
+	struct page *page = virt_to_page(ptr);
+
+	kasan_poison_shadow(ptr, PAGE_SIZE << compound_order(page),
+			KASAN_FREE_PAGE);
+}
+
+int kasan_module_alloc(void *addr, size_t size)
+{
+	void *ret;
+	size_t shadow_size;
+	unsigned long shadow_start;
+
+	shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
+	shadow_size = round_up(size >> KASAN_SHADOW_SCALE_SHIFT,
+			PAGE_SIZE);
+
+	if (WARN_ON(!PAGE_ALIGNED(shadow_start)))
+		return -EINVAL;
+
+	ret = __vmalloc_node_range(shadow_size, 1, shadow_start,
+			shadow_start + shadow_size,
+			GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+			PAGE_KERNEL, VM_NO_GUARD, NUMA_NO_NODE,
+			__builtin_return_address(0));
+	return ret ? 0 : -ENOMEM;
+}
+
+void kasan_module_free(void *addr)
+{
+	vfree(kasan_mem_to_shadow(addr));
+}
+
+static void register_global(struct kasan_global *global)
+{
+	size_t aligned_size = round_up(global->size, KASAN_SHADOW_SCALE_SIZE);
+
+	kasan_unpoison_shadow(global->beg, global->size);
+
+	kasan_poison_shadow(global->beg + aligned_size,
+		global->size_with_redzone - aligned_size,
+		KASAN_GLOBAL_REDZONE);
+}
+
+void __asan_register_globals(struct kasan_global *globals, size_t size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		register_global(&globals[i]);
+}
+EXPORT_SYMBOL(__asan_register_globals);
+
+void __asan_unregister_globals(struct kasan_global *globals, size_t size)
+{
+}
+EXPORT_SYMBOL(__asan_unregister_globals);
+
+#define DEFINE_ASAN_LOAD_STORE(size)				\
+	void __asan_load##size(unsigned long addr)		\
+	{							\
+		check_memory_region(addr, size, false);		\
+	}							\
+	EXPORT_SYMBOL(__asan_load##size);			\
+	__alias(__asan_load##size)				\
+	void __asan_load##size##_noabort(unsigned long);	\
+	EXPORT_SYMBOL(__asan_load##size##_noabort);		\
+	void __asan_store##size(unsigned long addr)		\
+	{							\
+		check_memory_region(addr, size, true);		\
+	}							\
+	EXPORT_SYMBOL(__asan_store##size);			\
+	__alias(__asan_store##size)				\
+	void __asan_store##size##_noabort(unsigned long);	\
+	EXPORT_SYMBOL(__asan_store##size##_noabort)
+
+DEFINE_ASAN_LOAD_STORE(1);
+DEFINE_ASAN_LOAD_STORE(2);
+DEFINE_ASAN_LOAD_STORE(4);
+DEFINE_ASAN_LOAD_STORE(8);
+DEFINE_ASAN_LOAD_STORE(16);
+
+void __asan_loadN(unsigned long addr, size_t size)
+{
+	check_memory_region(addr, size, false);
+}
+EXPORT_SYMBOL(__asan_loadN);
+
+__alias(__asan_loadN)
+void __asan_loadN_noabort(unsigned long, size_t);
+EXPORT_SYMBOL(__asan_loadN_noabort);
+
+void __asan_storeN(unsigned long addr, size_t size)
+{
+	check_memory_region(addr, size, true);
+}
+EXPORT_SYMBOL(__asan_storeN);
+
+__alias(__asan_storeN)
+void __asan_storeN_noabort(unsigned long, size_t);
+EXPORT_SYMBOL(__asan_storeN_noabort);
+
+/* to shut up compiler complaints */
+void __asan_handle_no_return(void) {}
+EXPORT_SYMBOL(__asan_handle_no_return);
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+static int kasan_mem_notifier(struct notifier_block *nb,
+			unsigned long action, void *data)
+{
+	return (action == MEM_GOING_ONLINE) ? NOTIFY_BAD : NOTIFY_OK;
+}
+
+static int __init kasan_memhotplug_init(void)
+{
+	pr_err("WARNING: KASan doesn't support memory hot-add\n");
+	pr_err("Memory hot-add will be disabled\n");
+
+	hotplug_memory_notifier(kasan_mem_notifier, 0);
+
+	return 0;
+}
+
+module_init(kasan_memhotplug_init);
+#endif
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
new file mode 100644
index 0000000..4986b0a
--- /dev/null
+++ b/mm/kasan/kasan.h
@@ -0,0 +1,75 @@
+#ifndef __MM_KASAN_KASAN_H
+#define __MM_KASAN_KASAN_H
+
+#include <linux/kasan.h>
+
+#define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)
+#define KASAN_SHADOW_MASK       (KASAN_SHADOW_SCALE_SIZE - 1)
+
+#define KASAN_FREE_PAGE         0xFF  /* page was freed */
+#define KASAN_FREE_PAGE         0xFF  /* page was freed */
+#define KASAN_PAGE_REDZONE      0xFE  /* redzone for kmalloc_large allocations */
+#define KASAN_KMALLOC_REDZONE   0xFC  /* redzone inside slub object */
+#define KASAN_KMALLOC_FREE      0xFB  /* object was freed (kmem_cache_free/kfree) */
+#define KASAN_GLOBAL_REDZONE    0xFA  /* redzone for global variable */
+
+/*
+ * Stack redzone shadow values
+ * (Those are compiler's ABI, don't change them)
+ */
+#define KASAN_STACK_LEFT        0xF1
+#define KASAN_STACK_MID         0xF2
+#define KASAN_STACK_RIGHT       0xF3
+#define KASAN_STACK_PARTIAL     0xF4
+
+/* Don't break randconfig/all*config builds */
+#ifndef KASAN_ABI_VERSION
+#define KASAN_ABI_VERSION 1
+#endif
+
+struct kasan_access_info {
+	const void *access_addr;
+	const void *first_bad_addr;
+	size_t access_size;
+	bool is_write;
+	unsigned long ip;
+};
+
+/* The layout of struct dictated by compiler */
+struct kasan_source_location {
+	const char *filename;
+	int line_no;
+	int column_no;
+};
+
+/* The layout of struct dictated by compiler */
+struct kasan_global {
+	const void *beg;		/* Address of the beginning of the global variable. */
+	size_t size;			/* Size of the global variable. */
+	size_t size_with_redzone;	/* Size of the variable + size of the red zone. 32 bytes aligned */
+	const void *name;
+	const void *module_name;	/* Name of the module where the global variable is declared. */
+	unsigned long has_dynamic_init;	/* This needed for C++ */
+#if KASAN_ABI_VERSION >= 4
+	struct kasan_source_location *location;
+#endif
+};
+
+void kasan_report_error(struct kasan_access_info *info);
+void kasan_report_user_access(struct kasan_access_info *info);
+
+static inline const void *kasan_shadow_to_mem(const void *shadow_addr)
+{
+	return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET)
+		<< KASAN_SHADOW_SCALE_SHIFT);
+}
+
+static inline bool kasan_enabled(void)
+{
+	return !current->kasan_depth;
+}
+
+void kasan_report(unsigned long addr, size_t size,
+		bool is_write, unsigned long ip);
+
+#endif
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
new file mode 100644
index 0000000..680ceed
--- /dev/null
+++ b/mm/kasan/report.c
@@ -0,0 +1,269 @@
+/*
+ * This file contains error reporting code.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ *
+ * Some of code borrowed from https://github.com/xairy/linux by
+ *        Andrey Konovalov <adech.fo@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/kernel.h>
+#include <linux/mm.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kasan.h>
+
+#include <asm/sections.h>
+
+#include "kasan.h"
+#include "../slab.h"
+
+/* Shadow layout customization. */
+#define SHADOW_BYTES_PER_BLOCK 1
+#define SHADOW_BLOCKS_PER_ROW 16
+#define SHADOW_BYTES_PER_ROW (SHADOW_BLOCKS_PER_ROW * SHADOW_BYTES_PER_BLOCK)
+#define SHADOW_ROWS_AROUND_ADDR 2
+
+static const void *find_first_bad_addr(const void *addr, size_t size)
+{
+	u8 shadow_val = *(u8 *)kasan_mem_to_shadow(addr);
+	const void *first_bad_addr = addr;
+
+	while (!shadow_val && first_bad_addr < addr + size) {
+		first_bad_addr += KASAN_SHADOW_SCALE_SIZE;
+		shadow_val = *(u8 *)kasan_mem_to_shadow(first_bad_addr);
+	}
+	return first_bad_addr;
+}
+
+static void print_error_description(struct kasan_access_info *info)
+{
+	const char *bug_type = "unknown crash";
+	u8 shadow_val;
+
+	info->first_bad_addr = find_first_bad_addr(info->access_addr,
+						info->access_size);
+
+	shadow_val = *(u8 *)kasan_mem_to_shadow(info->first_bad_addr);
+
+	switch (shadow_val) {
+	case KASAN_FREE_PAGE:
+	case KASAN_KMALLOC_FREE:
+		bug_type = "use after free";
+		break;
+	case KASAN_PAGE_REDZONE:
+	case KASAN_KMALLOC_REDZONE:
+	case KASAN_GLOBAL_REDZONE:
+	case 0 ... KASAN_SHADOW_SCALE_SIZE - 1:
+		bug_type = "out of bounds access";
+		break;
+	case KASAN_STACK_LEFT:
+	case KASAN_STACK_MID:
+	case KASAN_STACK_RIGHT:
+	case KASAN_STACK_PARTIAL:
+		bug_type = "out of bounds on stack";
+		break;
+	}
+
+	pr_err("BUG: KASan: %s in %pS at addr %p\n",
+		bug_type, (void *)info->ip,
+		info->access_addr);
+	pr_err("%s of size %zu by task %s/%d\n",
+		info->is_write ? "Write" : "Read",
+		info->access_size, current->comm, task_pid_nr(current));
+}
+
+static inline bool kernel_or_module_addr(const void *addr)
+{
+	return (addr >= (void *)_stext && addr < (void *)_end)
+		|| (addr >= (void *)MODULES_VADDR
+			&& addr < (void *)MODULES_END);
+}
+
+static inline bool init_task_stack_addr(const void *addr)
+{
+	return addr >= (void *)&init_thread_union.stack &&
+		(addr <= (void *)&init_thread_union.stack +
+			sizeof(init_thread_union.stack));
+}
+
+static void print_address_description(struct kasan_access_info *info)
+{
+	const void *addr = info->access_addr;
+
+	if ((addr >= (void *)PAGE_OFFSET) &&
+		(addr < high_memory)) {
+		struct page *page = virt_to_head_page(addr);
+
+		if (PageSlab(page)) {
+			void *object;
+			struct kmem_cache *cache = page->slab_cache;
+			void *last_object;
+
+			object = virt_to_obj(cache, page_address(page), addr);
+			last_object = page_address(page) +
+				page->objects * cache->size;
+
+			if (unlikely(object > last_object))
+				object = last_object; /* we hit into padding */
+
+			object_err(cache, page, object,
+				"kasan: bad access detected");
+			return;
+		}
+		dump_page(page, "kasan: bad access detected");
+	}
+
+	if (kernel_or_module_addr(addr)) {
+		if (!init_task_stack_addr(addr))
+			pr_err("Address belongs to variable %pS\n", addr);
+	}
+
+	dump_stack();
+}
+
+static bool row_is_guilty(const void *row, const void *guilty)
+{
+	return (row <= guilty) && (guilty < row + SHADOW_BYTES_PER_ROW);
+}
+
+static int shadow_pointer_offset(const void *row, const void *shadow)
+{
+	/* The length of ">ff00ff00ff00ff00: " is
+	 *    3 + (BITS_PER_LONG/8)*2 chars.
+	 */
+	return 3 + (BITS_PER_LONG/8)*2 + (shadow - row)*2 +
+		(shadow - row) / SHADOW_BYTES_PER_BLOCK + 1;
+}
+
+static void print_shadow_for_address(const void *addr)
+{
+	int i;
+	const void *shadow = kasan_mem_to_shadow(addr);
+	const void *shadow_row;
+
+	shadow_row = (void *)round_down((unsigned long)shadow,
+					SHADOW_BYTES_PER_ROW)
+		- SHADOW_ROWS_AROUND_ADDR * SHADOW_BYTES_PER_ROW;
+
+	pr_err("Memory state around the buggy address:\n");
+
+	for (i = -SHADOW_ROWS_AROUND_ADDR; i <= SHADOW_ROWS_AROUND_ADDR; i++) {
+		const void *kaddr = kasan_shadow_to_mem(shadow_row);
+		char buffer[4 + (BITS_PER_LONG/8)*2];
+
+		snprintf(buffer, sizeof(buffer),
+			(i == 0) ? ">%p: " : " %p: ", kaddr);
+
+		kasan_disable_current();
+		print_hex_dump(KERN_ERR, buffer,
+			DUMP_PREFIX_NONE, SHADOW_BYTES_PER_ROW, 1,
+			shadow_row, SHADOW_BYTES_PER_ROW, 0);
+		kasan_enable_current();
+
+		if (row_is_guilty(shadow_row, shadow))
+			pr_err("%*c\n",
+				shadow_pointer_offset(shadow_row, shadow),
+				'^');
+
+		shadow_row += SHADOW_BYTES_PER_ROW;
+	}
+}
+
+static DEFINE_SPINLOCK(report_lock);
+
+void kasan_report_error(struct kasan_access_info *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&report_lock, flags);
+	pr_err("================================="
+		"=================================\n");
+	print_error_description(info);
+	print_address_description(info);
+	print_shadow_for_address(info->first_bad_addr);
+	pr_err("================================="
+		"=================================\n");
+	spin_unlock_irqrestore(&report_lock, flags);
+}
+
+void kasan_report_user_access(struct kasan_access_info *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&report_lock, flags);
+	pr_err("================================="
+		"=================================\n");
+	pr_err("BUG: KASan: user-memory-access on address %p\n",
+		info->access_addr);
+	pr_err("%s of size %zu by task %s/%d\n",
+		info->is_write ? "Write" : "Read",
+		info->access_size, current->comm, task_pid_nr(current));
+	dump_stack();
+	pr_err("================================="
+		"=================================\n");
+	spin_unlock_irqrestore(&report_lock, flags);
+}
+
+void kasan_report(unsigned long addr, size_t size,
+		bool is_write, unsigned long ip)
+{
+	struct kasan_access_info info;
+
+	if (likely(!kasan_enabled()))
+		return;
+
+	info.access_addr = (void *)addr;
+	info.access_size = size;
+	info.is_write = is_write;
+	info.ip = ip;
+	kasan_report_error(&info);
+}
+
+
+#define DEFINE_ASAN_REPORT_LOAD(size)                     \
+void __asan_report_load##size##_noabort(unsigned long addr) \
+{                                                         \
+	kasan_report(addr, size, false, _RET_IP_);	  \
+}                                                         \
+EXPORT_SYMBOL(__asan_report_load##size##_noabort)
+
+#define DEFINE_ASAN_REPORT_STORE(size)                     \
+void __asan_report_store##size##_noabort(unsigned long addr) \
+{                                                          \
+	kasan_report(addr, size, true, _RET_IP_);	   \
+}                                                          \
+EXPORT_SYMBOL(__asan_report_store##size##_noabort)
+
+DEFINE_ASAN_REPORT_LOAD(1);
+DEFINE_ASAN_REPORT_LOAD(2);
+DEFINE_ASAN_REPORT_LOAD(4);
+DEFINE_ASAN_REPORT_LOAD(8);
+DEFINE_ASAN_REPORT_LOAD(16);
+DEFINE_ASAN_REPORT_STORE(1);
+DEFINE_ASAN_REPORT_STORE(2);
+DEFINE_ASAN_REPORT_STORE(4);
+DEFINE_ASAN_REPORT_STORE(8);
+DEFINE_ASAN_REPORT_STORE(16);
+
+void __asan_report_load_n_noabort(unsigned long addr, size_t size)
+{
+	kasan_report(addr, size, false, _RET_IP_);
+}
+EXPORT_SYMBOL(__asan_report_load_n_noabort);
+
+void __asan_report_store_n_noabort(unsigned long addr, size_t size)
+{
+	kasan_report(addr, size, true, _RET_IP_);
+}
+EXPORT_SYMBOL(__asan_report_store_n_noabort);
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 3cda50c..5405aff 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -98,6 +98,7 @@
 #include <asm/processor.h>
 #include <linux/atomic.h>
 
+#include <linux/kasan.h>
 #include <linux/kmemcheck.h>
 #include <linux/kmemleak.h>
 #include <linux/memory_hotplug.h>
@@ -1113,7 +1114,10 @@
 	if (!kmemcheck_is_obj_initialized(object->pointer, object->size))
 		return false;
 
+	kasan_disable_current();
 	object->checksum = crc32(0, (void *)object->pointer, object->size);
+	kasan_enable_current();
+
 	return object->checksum != old_csum;
 }
 
@@ -1164,7 +1168,9 @@
 						  BYTES_PER_POINTER))
 			continue;
 
+		kasan_disable_current();
 		pointer = *ptr;
+		kasan_enable_current();
 
 		object = find_and_get_object(pointer, 1);
 		if (!object)
diff --git a/mm/madvise.c b/mm/madvise.c
index 1077cbd..d551475 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -239,7 +239,7 @@
 		return -EBADF;
 #endif
 
-	if (file->f_mapping->a_ops->get_xip_mem) {
+	if (IS_DAX(file_inode(file))) {
 		/* no bad return value, but ignore advice */
 		return 0;
 	}
diff --git a/mm/memory.c b/mm/memory.c
index 9927532..8068893 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1965,6 +1965,7 @@
 	vmf.pgoff = page->index;
 	vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE;
 	vmf.page = page;
+	vmf.cow_page = NULL;
 
 	ret = vma->vm_ops->page_mkwrite(vma, &vmf);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))
@@ -2329,6 +2330,7 @@
 		details.last_index = ULONG_MAX;
 
 
+	/* DAX uses i_mmap_lock to serialise file truncate vs page fault */
 	i_mmap_lock_write(mapping);
 	if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap)))
 		unmap_mapping_range_tree(&mapping->i_mmap, &details);
@@ -2638,7 +2640,8 @@
  * See filemap_fault() and __lock_page_retry().
  */
 static int __do_fault(struct vm_area_struct *vma, unsigned long address,
-		pgoff_t pgoff, unsigned int flags, struct page **page)
+			pgoff_t pgoff, unsigned int flags,
+			struct page *cow_page, struct page **page)
 {
 	struct vm_fault vmf;
 	int ret;
@@ -2647,10 +2650,13 @@
 	vmf.pgoff = pgoff;
 	vmf.flags = flags;
 	vmf.page = NULL;
+	vmf.cow_page = cow_page;
 
 	ret = vma->vm_ops->fault(vma, &vmf);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
 		return ret;
+	if (!vmf.page)
+		goto out;
 
 	if (unlikely(PageHWPoison(vmf.page))) {
 		if (ret & VM_FAULT_LOCKED)
@@ -2664,6 +2670,7 @@
 	else
 		VM_BUG_ON_PAGE(!PageLocked(vmf.page), vmf.page);
 
+ out:
 	*page = vmf.page;
 	return ret;
 }
@@ -2834,7 +2841,7 @@
 		pte_unmap_unlock(pte, ptl);
 	}
 
-	ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+	ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
 		return ret;
 
@@ -2874,26 +2881,43 @@
 		return VM_FAULT_OOM;
 	}
 
-	ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+	ret = __do_fault(vma, address, pgoff, flags, new_page, &fault_page);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
 		goto uncharge_out;
 
-	copy_user_highpage(new_page, fault_page, address, vma);
+	if (fault_page)
+		copy_user_highpage(new_page, fault_page, address, vma);
 	__SetPageUptodate(new_page);
 
 	pte = pte_offset_map_lock(mm, pmd, address, &ptl);
 	if (unlikely(!pte_same(*pte, orig_pte))) {
 		pte_unmap_unlock(pte, ptl);
-		unlock_page(fault_page);
-		page_cache_release(fault_page);
+		if (fault_page) {
+			unlock_page(fault_page);
+			page_cache_release(fault_page);
+		} else {
+			/*
+			 * The fault handler has no page to lock, so it holds
+			 * i_mmap_lock for read to protect against truncate.
+			 */
+			i_mmap_unlock_read(vma->vm_file->f_mapping);
+		}
 		goto uncharge_out;
 	}
 	do_set_pte(vma, address, new_page, pte, true, true);
 	mem_cgroup_commit_charge(new_page, memcg, false);
 	lru_cache_add_active_or_unevictable(new_page, vma);
 	pte_unmap_unlock(pte, ptl);
-	unlock_page(fault_page);
-	page_cache_release(fault_page);
+	if (fault_page) {
+		unlock_page(fault_page);
+		page_cache_release(fault_page);
+	} else {
+		/*
+		 * The fault handler has no page to lock, so it holds
+		 * i_mmap_lock for read to protect against truncate.
+		 */
+		i_mmap_unlock_read(vma->vm_file->f_mapping);
+	}
 	return ret;
 uncharge_out:
 	mem_cgroup_cancel_charge(new_page, memcg);
@@ -2912,7 +2936,7 @@
 	int dirtied = 0;
 	int ret, tmp;
 
-	ret = __do_fault(vma, address, pgoff, flags, &fault_page);
+	ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page);
 	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
 		return ret;
 
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index c75f4dc..4721046 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2817,8 +2817,7 @@
 			p += snprintf(p, buffer + maxlen - p, "relative");
 	}
 
-	if (!nodes_empty(nodes)) {
-		p += snprintf(p, buffer + maxlen - p, ":");
-	 	p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
-	}
+	if (!nodes_empty(nodes))
+		p += scnprintf(p, buffer + maxlen - p, ":%*pbl",
+			       nodemask_pr_args(&nodes));
 }
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index cb47582..a47f0b2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -25,6 +25,7 @@
 #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/kmemcheck.h>
+#include <linux/kasan.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/pagevec.h>
@@ -787,6 +788,7 @@
 
 	trace_mm_page_free(page, order);
 	kmemcheck_free_shadow(page, order);
+	kasan_free_pages(page, order);
 
 	if (PageAnon(page))
 		page->mapping = NULL;
@@ -970,6 +972,7 @@
 
 	arch_alloc_page(page, order);
 	kernel_map_pages(page, 1 << order, 1);
+	kasan_alloc_pages(page, order);
 
 	if (gfp_flags & __GFP_ZERO)
 		prep_zero_page(page, order, gfp_flags);
diff --git a/mm/percpu.c b/mm/percpu.c
index d39e2f4..73c97a5 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1528,7 +1528,6 @@
 int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
 				  void *base_addr)
 {
-	static char cpus_buf[4096] __initdata;
 	static int smap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
 	static int dmap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata;
 	size_t dyn_size = ai->dyn_size;
@@ -1541,12 +1540,11 @@
 	int *unit_map;
 	int group, unit, i;
 
-	cpumask_scnprintf(cpus_buf, sizeof(cpus_buf), cpu_possible_mask);
-
 #define PCPU_SETUP_BUG_ON(cond)	do {					\
 	if (unlikely(cond)) {						\
 		pr_emerg("PERCPU: failed to initialize, %s", #cond);	\
-		pr_emerg("PERCPU: cpu_possible_mask=%s\n", cpus_buf);	\
+		pr_emerg("PERCPU: cpu_possible_mask=%*pb\n",		\
+			 cpumask_pr_args(cpu_possible_mask));		\
 		pcpu_dump_alloc_info(KERN_EMERG, ai);			\
 		BUG();							\
 	}								\
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 1a1cc89..999bb34 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -295,8 +295,8 @@
 }
 
 static struct kmem_cache *
-do_kmem_cache_create(char *name, size_t object_size, size_t size, size_t align,
-		     unsigned long flags, void (*ctor)(void *),
+do_kmem_cache_create(const char *name, size_t object_size, size_t size,
+		     size_t align, unsigned long flags, void (*ctor)(void *),
 		     struct mem_cgroup *memcg, struct kmem_cache *root_cache)
 {
 	struct kmem_cache *s;
@@ -363,7 +363,7 @@
 		  unsigned long flags, void (*ctor)(void *))
 {
 	struct kmem_cache *s;
-	char *cache_name;
+	const char *cache_name;
 	int err;
 
 	get_online_cpus();
@@ -390,7 +390,7 @@
 	if (s)
 		goto out_unlock;
 
-	cache_name = kstrdup(name, GFP_KERNEL);
+	cache_name = kstrdup_const(name, GFP_KERNEL);
 	if (!cache_name) {
 		err = -ENOMEM;
 		goto out_unlock;
@@ -401,7 +401,7 @@
 				 flags, ctor, NULL, NULL);
 	if (IS_ERR(s)) {
 		err = PTR_ERR(s);
-		kfree(cache_name);
+		kfree_const(cache_name);
 	}
 
 out_unlock:
@@ -607,7 +607,7 @@
 void slab_kmem_cache_release(struct kmem_cache *s)
 {
 	destroy_memcg_params(s);
-	kfree(s->name);
+	kfree_const(s->name);
 	kmem_cache_free(kmem_cache, s);
 }
 
@@ -898,6 +898,7 @@
 	page = alloc_kmem_pages(flags, order);
 	ret = page ? page_address(page) : NULL;
 	kmemleak_alloc(ret, size, 1, flags);
+	kasan_kmalloc_large(ret, size);
 	return ret;
 }
 EXPORT_SYMBOL(kmalloc_order);
@@ -1077,8 +1078,10 @@
 	if (p)
 		ks = ksize(p);
 
-	if (ks >= new_size)
+	if (ks >= new_size) {
+		kasan_krealloc((void *)p, new_size);
 		return (void *)p;
+	}
 
 	ret = kmalloc_track_caller(new_size, flags);
 	if (ret && p)
diff --git a/mm/slub.c b/mm/slub.c
index 06cdb18..6832c4e 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -20,6 +20,7 @@
 #include <linux/proc_fs.h>
 #include <linux/notifier.h>
 #include <linux/seq_file.h>
+#include <linux/kasan.h>
 #include <linux/kmemcheck.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
@@ -468,12 +469,30 @@
 static int disable_higher_order_debug;
 
 /*
+ * slub is about to manipulate internal object metadata.  This memory lies
+ * outside the range of the allocated object, so accessing it would normally
+ * be reported by kasan as a bounds error.  metadata_access_enable() is used
+ * to tell kasan that these accesses are OK.
+ */
+static inline void metadata_access_enable(void)
+{
+	kasan_disable_current();
+}
+
+static inline void metadata_access_disable(void)
+{
+	kasan_enable_current();
+}
+
+/*
  * Object debugging
  */
 static void print_section(char *text, u8 *addr, unsigned int length)
 {
+	metadata_access_enable();
 	print_hex_dump(KERN_ERR, text, DUMP_PREFIX_ADDRESS, 16, 1, addr,
 			length, 1);
+	metadata_access_disable();
 }
 
 static struct track *get_track(struct kmem_cache *s, void *object,
@@ -503,7 +522,9 @@
 		trace.max_entries = TRACK_ADDRS_COUNT;
 		trace.entries = p->addrs;
 		trace.skip = 3;
+		metadata_access_enable();
 		save_stack_trace(&trace);
+		metadata_access_disable();
 
 		/* See rant in lockdep.c */
 		if (trace.nr_entries != 0 &&
@@ -629,7 +650,7 @@
 	dump_stack();
 }
 
-static void object_err(struct kmem_cache *s, struct page *page,
+void object_err(struct kmem_cache *s, struct page *page,
 			u8 *object, char *reason)
 {
 	slab_bug(s, "%s", reason);
@@ -677,7 +698,9 @@
 	u8 *fault;
 	u8 *end;
 
+	metadata_access_enable();
 	fault = memchr_inv(start, value, bytes);
+	metadata_access_disable();
 	if (!fault)
 		return 1;
 
@@ -770,7 +793,9 @@
 	if (!remainder)
 		return 1;
 
+	metadata_access_enable();
 	fault = memchr_inv(end - remainder, POISON_INUSE, remainder);
+	metadata_access_disable();
 	if (!fault)
 		return 1;
 	while (end > fault && end[-1] == POISON_INUSE)
@@ -1226,11 +1251,13 @@
 static inline void kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags)
 {
 	kmemleak_alloc(ptr, size, 1, flags);
+	kasan_kmalloc_large(ptr, size);
 }
 
 static inline void kfree_hook(const void *x)
 {
 	kmemleak_free(x);
+	kasan_kfree_large(x);
 }
 
 static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
@@ -1253,6 +1280,7 @@
 	kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
 	kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags);
 	memcg_kmem_put_cache(s);
+	kasan_slab_alloc(s, object);
 }
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x)
@@ -1276,6 +1304,8 @@
 #endif
 	if (!(s->flags & SLAB_DEBUG_OBJECTS))
 		debug_check_no_obj_freed(x, s->object_size);
+
+	kasan_slab_free(s, x);
 }
 
 /*
@@ -1370,8 +1400,11 @@
 				void *object)
 {
 	setup_object_debug(s, page, object);
-	if (unlikely(s->ctor))
+	if (unlikely(s->ctor)) {
+		kasan_unpoison_object_data(s, object);
 		s->ctor(object);
+		kasan_poison_object_data(s, object);
+	}
 }
 
 static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
@@ -1404,6 +1437,8 @@
 	if (unlikely(s->flags & SLAB_POISON))
 		memset(start, POISON_INUSE, PAGE_SIZE << order);
 
+	kasan_poison_slab(page);
+
 	for_each_object_idx(p, idx, s, start, page->objects) {
 		setup_object(s, page, p);
 		if (likely(idx < page->objects))
@@ -2497,6 +2532,7 @@
 {
 	void *ret = slab_alloc(s, gfpflags, _RET_IP_);
 	trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
+	kasan_kmalloc(s, ret, size);
 	return ret;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_trace);
@@ -2523,6 +2559,8 @@
 
 	trace_kmalloc_node(_RET_IP_, ret,
 			   size, s->size, gfpflags, node);
+
+	kasan_kmalloc(s, ret, size);
 	return ret;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
@@ -2908,6 +2946,7 @@
 	init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
 	init_tracking(kmem_cache_node, n);
 #endif
+	kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node));
 	init_kmem_cache_node(n);
 	inc_slabs_node(kmem_cache_node, node, page->objects);
 
@@ -3280,6 +3319,8 @@
 
 	trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
 
+	kasan_kmalloc(s, ret, size);
+
 	return ret;
 }
 EXPORT_SYMBOL(__kmalloc);
@@ -3323,12 +3364,14 @@
 
 	trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);
 
+	kasan_kmalloc(s, ret, size);
+
 	return ret;
 }
 EXPORT_SYMBOL(__kmalloc_node);
 #endif
 
-size_t ksize(const void *object)
+static size_t __ksize(const void *object)
 {
 	struct page *page;
 
@@ -3344,6 +3387,15 @@
 
 	return slab_ksize(page->slab_cache);
 }
+
+size_t ksize(const void *object)
+{
+	size_t size = __ksize(object);
+	/* We assume that ksize callers could use whole allocated area,
+	   so we need unpoison this area. */
+	kasan_krealloc(object, size);
+	return size;
+}
 EXPORT_SYMBOL(ksize);
 
 void kfree(const void *x)
@@ -4108,20 +4160,16 @@
 
 		if (num_online_cpus() > 1 &&
 				!cpumask_empty(to_cpumask(l->cpus)) &&
-				len < PAGE_SIZE - 60) {
-			len += sprintf(buf + len, " cpus=");
-			len += cpulist_scnprintf(buf + len,
-						 PAGE_SIZE - len - 50,
-						 to_cpumask(l->cpus));
-		}
+				len < PAGE_SIZE - 60)
+			len += scnprintf(buf + len, PAGE_SIZE - len - 50,
+					 " cpus=%*pbl",
+					 cpumask_pr_args(to_cpumask(l->cpus)));
 
 		if (nr_online_nodes > 1 && !nodes_empty(l->nodes) &&
-				len < PAGE_SIZE - 60) {
-			len += sprintf(buf + len, " nodes=");
-			len += nodelist_scnprintf(buf + len,
-						  PAGE_SIZE - len - 50,
-						  l->nodes);
-		}
+				len < PAGE_SIZE - 60)
+			len += scnprintf(buf + len, PAGE_SIZE - len - 50,
+					 " nodes=%*pbl",
+					 nodemask_pr_args(&l->nodes));
 
 		len += sprintf(buf + len, "\n");
 	}
diff --git a/mm/util.c b/mm/util.c
index f3ef639..3981ae9 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -12,10 +12,30 @@
 #include <linux/hugetlb.h>
 #include <linux/vmalloc.h>
 
+#include <asm/sections.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
 
+static inline int is_kernel_rodata(unsigned long addr)
+{
+	return addr >= (unsigned long)__start_rodata &&
+		addr < (unsigned long)__end_rodata;
+}
+
+/**
+ * kfree_const - conditionally free memory
+ * @x: pointer to the memory
+ *
+ * Function calls kfree only if @x is not in .rodata section.
+ */
+void kfree_const(const void *x)
+{
+	if (!is_kernel_rodata((unsigned long)x))
+		kfree(x);
+}
+EXPORT_SYMBOL(kfree_const);
+
 /**
  * kstrdup - allocate space for and copy an existing string
  * @s: the string to duplicate
@@ -38,6 +58,24 @@
 EXPORT_SYMBOL(kstrdup);
 
 /**
+ * kstrdup_const - conditionally duplicate an existing const string
+ * @s: the string to duplicate
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Function returns source string if it is in .rodata section otherwise it
+ * fallbacks to kstrdup.
+ * Strings allocated by kstrdup_const should be freed by kfree_const.
+ */
+const char *kstrdup_const(const char *s, gfp_t gfp)
+{
+	if (is_kernel_rodata((unsigned long)s))
+		return s;
+
+	return kstrdup(s, gfp);
+}
+EXPORT_SYMBOL(kstrdup_const);
+
+/**
  * kstrndup - allocate space for and copy an existing string
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 39c3388..35b25e1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1324,10 +1324,8 @@
 	if (unlikely(!area))
 		return NULL;
 
-	/*
-	 * We always allocate a guard page.
-	 */
-	size += PAGE_SIZE;
+	if (!(flags & VM_NO_GUARD))
+		size += PAGE_SIZE;
 
 	va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
 	if (IS_ERR(va)) {
@@ -1621,6 +1619,7 @@
  *	@end:		vm area range end
  *	@gfp_mask:	flags for the page level allocator
  *	@prot:		protection mask for the allocated pages
+ *	@vm_flags:	additional vm area flags (e.g. %VM_NO_GUARD)
  *	@node:		node to use for allocation or NUMA_NO_NODE
  *	@caller:	caller's return address
  *
@@ -1630,7 +1629,8 @@
  */
 void *__vmalloc_node_range(unsigned long size, unsigned long align,
 			unsigned long start, unsigned long end, gfp_t gfp_mask,
-			pgprot_t prot, int node, const void *caller)
+			pgprot_t prot, unsigned long vm_flags, int node,
+			const void *caller)
 {
 	struct vm_struct *area;
 	void *addr;
@@ -1640,8 +1640,8 @@
 	if (!size || (size >> PAGE_SHIFT) > totalram_pages)
 		goto fail;
 
-	area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED,
-				  start, end, node, gfp_mask, caller);
+	area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED |
+				vm_flags, start, end, node, gfp_mask, caller);
 	if (!area)
 		goto fail;
 
@@ -1690,7 +1690,7 @@
 			    int node, const void *caller)
 {
 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
-				gfp_mask, prot, node, caller);
+				gfp_mask, prot, 0, node, caller);
 }
 
 void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 9993412..f2aa73b 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -614,8 +614,7 @@
 {
 	struct rps_map *map;
 	cpumask_var_t mask;
-	size_t len = 0;
-	int i;
+	int i, len;
 
 	if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
 		return -ENOMEM;
@@ -626,17 +625,11 @@
 		for (i = 0; i < map->len; i++)
 			cpumask_set_cpu(map->cpus[i], mask);
 
-	len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask);
-	if (PAGE_SIZE - len < 3) {
-		rcu_read_unlock();
-		free_cpumask_var(mask);
-		return -EINVAL;
-	}
+	len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask));
 	rcu_read_unlock();
-
 	free_cpumask_var(mask);
-	len += sprintf(buf + len, "\n");
-	return len;
+
+	return len < PAGE_SIZE ? len : -EINVAL;
 }
 
 static ssize_t store_rps_map(struct netdev_rx_queue *queue,
@@ -1090,8 +1083,7 @@
 	struct xps_dev_maps *dev_maps;
 	cpumask_var_t mask;
 	unsigned long index;
-	size_t len = 0;
-	int i;
+	int i, len;
 
 	if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
 		return -ENOMEM;
@@ -1117,15 +1109,9 @@
 	}
 	rcu_read_unlock();
 
-	len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask);
-	if (PAGE_SIZE - len < 3) {
-		free_cpumask_var(mask);
-		return -EINVAL;
-	}
-
+	len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask));
 	free_cpumask_var(mask);
-	len += sprintf(buf + len, "\n");
-	return len;
+	return len < PAGE_SIZE ? len : -EINVAL;
 }
 
 static ssize_t store_xps_map(struct netdev_queue *queue,
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index eaa51dd..4334248 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -155,7 +155,7 @@
 		rcu_read_unlock();
 
 		len = min(sizeof(kbuf) - 1, *lenp);
-		len = cpumask_scnprintf(kbuf, len, mask);
+		len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask));
 		if (!len) {
 			*lenp = 0;
 			goto done;
diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
new file mode 100644
index 0000000..631619b
--- /dev/null
+++ b/scripts/Makefile.kasan
@@ -0,0 +1,25 @@
+ifdef CONFIG_KASAN
+ifdef CONFIG_KASAN_INLINE
+	call_threshold := 10000
+else
+	call_threshold := 0
+endif
+
+CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
+
+CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \
+		-fasan-shadow-offset=$(CONFIG_KASAN_SHADOW_OFFSET) \
+		--param asan-stack=1 --param asan-globals=1 \
+		--param asan-instrumentation-with-call-threshold=$(call_threshold))
+
+ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),)
+        $(warning Cannot use CONFIG_KASAN: \
+            -fsanitize=kernel-address is not supported by compiler)
+else
+    ifeq ($(CFLAGS_KASAN),)
+        $(warning CONFIG_KASAN: compiler does not support all options.\
+            Trying minimal configuration)
+        CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL)
+    endif
+endif
+endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 5117552..044eb4f 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -119,6 +119,16 @@
 		$(CFLAGS_GCOV))
 endif
 
+#
+# Enable address sanitizer flags for kernel except some files or directories
+# we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE)
+#
+ifeq ($(CONFIG_KASAN),y)
+_c_flags += $(if $(patsubst n%,, \
+		$(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
+		$(CFLAGS_KASAN))
+endif
+
 # If building the kernel in a separate objtree expand all occurrences
 # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
 
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index f0bb6d6..d124359 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -278,6 +278,7 @@
 			__noreturn|
 			__used|
 			__cold|
+			__pure|
 			__noclone|
 			__deprecated|
 			__read_mostly|
@@ -298,6 +299,7 @@
 our $Hex	= qr{(?i)0x[0-9a-f]+$Int_type?};
 our $Int	= qr{[0-9]+$Int_type?};
 our $Octal	= qr{0[0-7]+$Int_type?};
+our $String	= qr{"[X\t]*"};
 our $Float_hex	= qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
 our $Float_dec	= qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
 our $Float_int	= qr{(?i)[0-9]+e-?[0-9]+[fl]?};
@@ -337,6 +339,11 @@
 	| $NON_ASCII_UTF8
 }x;
 
+our $typeOtherOSTypedefs = qr{(?x:
+	u_(?:char|short|int|long) |          # bsd
+	u(?:nchar|short|int|long)            # sysv
+)};
+
 our $typeTypedefs = qr{(?x:
 	(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
 	atomic_t
@@ -473,6 +480,7 @@
 			(?:$Modifier\s+|const\s+)*
 			(?:
 				(?:typeof|__typeof__)\s*\([^\)]*\)|
+				(?:$typeOtherOSTypedefs\b)|
 				(?:$typeTypedefs\b)|
 				(?:${all}\b)
 			)
@@ -490,6 +498,7 @@
 			(?:
 				(?:typeof|__typeof__)\s*\([^\)]*\)|
 				(?:$typeTypedefs\b)|
+				(?:$typeOtherOSTypedefs\b)|
 				(?:${allWithAttr}\b)
 			)
 			(?:\s+$Modifier|\s+const)*
@@ -517,7 +526,7 @@
 
 our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
 our $LvalOrFunc	= qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*};
-our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
+our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
 
 our $declaration_macros = qr{(?x:
 	(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,2}\s*\(|
@@ -632,6 +641,8 @@
 	$output =~ s/^\s*//gm;
 	my @lines = split("\n", $output);
 
+	return ($id, $desc) if ($#lines < 0);
+
 	if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) {
 # Maybe one day convert this block of bash into something that returns
 # all matching commit ids, but it's very slow...
@@ -2159,6 +2170,13 @@
 			}
 		}
 
+# Check email subject for common tools that don't need to be mentioned
+		if ($in_header_lines &&
+		    $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) {
+			WARN("EMAIL_SUBJECT",
+			     "A patch subject line should describe the change not the tool that found it\n" . $herecurr);
+		}
+
 # Check for old stable address
 		if ($line =~ /^\s*cc:\s*.*<?\bstable\@kernel\.org\b>?.*$/i) {
 			ERROR("STABLE_ADDRESS",
@@ -2171,21 +2189,49 @@
 			      "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr);
 		}
 
-# Check for improperly formed commit descriptions
-		if ($in_commit_log &&
-		    $line =~ /\bcommit\s+[0-9a-f]{5,}/i &&
-		    !($line =~ /\b[Cc]ommit [0-9a-f]{12,40} \("/ ||
-		      ($line =~ /\b[Cc]ommit [0-9a-f]{12,40}\s*$/ &&
-		       defined $rawlines[$linenr] &&
-		       $rawlines[$linenr] =~ /^\s*\("/))) {
-			$line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i;
+# Check for git id commit length and improperly formed commit descriptions
+		if ($in_commit_log && $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i) {
 			my $init_char = $1;
 			my $orig_commit = lc($2);
-			my $id = '01234567890ab';
-			my $desc = 'commit description';
-		        ($id, $desc) = git_commit_info($orig_commit, $id, $desc);
-			ERROR("GIT_COMMIT_ID",
-			      "Please use 12 or more chars for the git commit ID like: '${init_char}ommit $id (\"$desc\")'\n" . $herecurr);
+			my $short = 1;
+			my $long = 0;
+			my $case = 1;
+			my $space = 1;
+			my $hasdesc = 0;
+			my $hasparens = 0;
+			my $id = '0123456789ab';
+			my $orig_desc = "commit description";
+			my $description = "";
+
+			$short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i);
+			$long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i);
+			$space = 0 if ($line =~ /\bcommit [0-9a-f]/i);
+			$case = 0 if ($line =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/);
+			if ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)"\)/i) {
+				$orig_desc = $1;
+				$hasparens = 1;
+			} elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s*$/i &&
+				 defined $rawlines[$linenr] &&
+				 $rawlines[$linenr] =~ /^\s*\("([^"]+)"\)/) {
+				$orig_desc = $1;
+				$hasparens = 1;
+			} elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("[^"]+$/i &&
+				 defined $rawlines[$linenr] &&
+				 $rawlines[$linenr] =~ /^\s*[^"]+"\)/) {
+				$line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)$/i;
+				$orig_desc = $1;
+				$rawlines[$linenr] =~ /^\s*([^"]+)"\)/;
+				$orig_desc .= " " . $1;
+				$hasparens = 1;
+			}
+
+			($id, $description) = git_commit_info($orig_commit,
+							      $id, $orig_desc);
+
+			if ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens) {
+				ERROR("GIT_COMMIT_ID",
+				      "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr);
+			}
 		}
 
 # Check for added, moved or deleted files
@@ -2355,6 +2401,13 @@
 			     "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
 		}
 
+# discourage the use of boolean for type definition attributes of Kconfig options
+		if ($realfile =~ /Kconfig/ &&
+		    $line =~ /^\+\s*\bboolean\b/) {
+			WARN("CONFIG_TYPE_BOOLEAN",
+			     "Use of boolean is deprecated, please use bool instead.\n" . $herecurr);
+		}
+
 		if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
 		    ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) {
 			my $flag = $1;
@@ -2499,7 +2552,7 @@
 			}
 		}
 
-		if ($line =~ /^\+.*(\w+\s*)?\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|[,;\({\[\<\>])/ &&
+		if ($line =~ /^\+.*(\w+\s*)?\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|[,;:\?\(\{\}\[\<\>]|&&|\|\||\\$)/ &&
 		    (!defined($1) || $1 !~ /sizeof\s*/)) {
 			if (CHK("SPACING",
 				"No space is necessary after a cast\n" . $herecurr) &&
@@ -3124,6 +3177,7 @@
 		    $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
 		    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
 		    $line !~ /\b$typeTypedefs\b/ &&
+		    $line !~ /\b$typeOtherOSTypedefs\b/ &&
 		    $line !~ /\b__bitwise(?:__|)\b/) {
 			WARN("NEW_TYPEDEFS",
 			     "do not add new typedefs\n" . $herecurr);
@@ -3200,7 +3254,7 @@
 # check for uses of printk_ratelimit
 		if ($line =~ /\bprintk_ratelimit\s*\(/) {
 			WARN("PRINTK_RATELIMITED",
-"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
+			     "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
 		}
 
 # printk should use KERN_* levels.  Note that follow on printk's on the
@@ -3646,7 +3700,22 @@
 					 $op eq '*' or $op eq '/' or
 					 $op eq '%')
 				{
-					if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+					if ($check) {
+						if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) {
+							if (CHK("SPACING",
+								"spaces preferred around that '$op' $at\n" . $hereptr)) {
+								$good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+								$fix_elements[$n + 2] =~ s/^\s+//;
+								$line_fixed = 1;
+							}
+						} elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) {
+							if (CHK("SPACING",
+								"space preferred before that '$op' $at\n" . $hereptr)) {
+								$good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]);
+								$line_fixed = 1;
+							}
+						}
+					} elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
 						if (ERROR("SPACING",
 							  "need consistent spacing around '$op' $at\n" . $hereptr)) {
 							$good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
@@ -4251,6 +4320,7 @@
 			$ctx = $dstat;
 
 			$dstat =~ s/\\\n.//g;
+			$dstat =~ s/$;/ /g;
 
 			if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) {
 				my $stmts = $2;
@@ -4417,12 +4487,18 @@
 
 # check for unnecessary blank lines around braces
 		if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
-			CHK("BRACES",
-			    "Blank lines aren't necessary before a close brace '}'\n" . $hereprev);
+			if (CHK("BRACES",
+				"Blank lines aren't necessary before a close brace '}'\n" . $hereprev) &&
+			    $fix && $prevrawline =~ /^\+/) {
+				fix_delete_line($fixlinenr - 1, $prevrawline);
+			}
 		}
 		if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
-			CHK("BRACES",
-			    "Blank lines aren't necessary after an open brace '{'\n" . $hereprev);
+			if (CHK("BRACES",
+				"Blank lines aren't necessary after an open brace '{'\n" . $hereprev) &&
+			    $fix) {
+				fix_delete_line($fixlinenr, $rawline);
+			}
 		}
 
 # no volatiles please
@@ -4545,7 +4621,7 @@
 		}
 
 # check for logging functions with KERN_<LEVEL>
-		if ($line !~ /printk\s*\(/ &&
+		if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ &&
 		    $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) {
 			my $level = $1;
 			if (WARN("UNNECESSARY_KERN_LEVEL",
@@ -4804,7 +4880,8 @@
 # check for seq_printf uses that could be seq_puts
 		if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) {
 			my $fmt = get_quoted_string($line, $rawline);
-			if ($fmt ne "" && $fmt !~ /[^\\]\%/) {
+			$fmt =~ s/%%//g;
+			if ($fmt !~ /%/) {
 				if (WARN("PREFER_SEQ_PUTS",
 					 "Prefer seq_puts to seq_printf\n" . $herecurr) &&
 				    $fix) {
@@ -5089,6 +5166,12 @@
 			}
 		}
 
+# check for uses of __DATE__, __TIME__, __TIMESTAMP__
+		while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) {
+			ERROR("DATE_TIME",
+			      "Use of the '$1' macro makes the build non-deterministic\n" . $herecurr);
+		}
+
 # check for use of yield()
 		if ($line =~ /\byield\s*\(\s*\)/) {
 			WARN("YIELD",
@@ -5140,8 +5223,9 @@
 			     "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr);
 		}
 
-# check for various ops structs, ensure they are const.
-		my $struct_ops = qr{acpi_dock_ops|
+# check for various structs that are normally const (ops, kgdb, device_tree)
+		my $const_structs = qr{
+				acpi_dock_ops|
 				address_space_operations|
 				backlight_ops|
 				block_device_operations|
@@ -5164,6 +5248,7 @@
 				mtrr_ops|
 				neigh_ops|
 				nlmsvc_binding|
+				of_device_id|
 				pci_raw_ops|
 				pipe_buf_operations|
 				platform_hibernation_ops|
@@ -5179,7 +5264,7 @@
 				usb_mon_operations|
 				wd_ops}x;
 		if ($line !~ /\bconst\b/ &&
-		    $line =~ /\bstruct\s+($struct_ops)\b/) {
+		    $line =~ /\bstruct\s+($const_structs)\b/) {
 			WARN("CONST_STRUCT",
 			     "struct $1 should normally be const\n" .
 				$herecurr);
@@ -5204,6 +5289,13 @@
 			      "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr);
 		}
 
+# likely/unlikely comparisons similar to "(likely(foo) > 0)"
+		if ($^V && $^V ge 5.10.0 &&
+		    $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) {
+			WARN("LIKELY_MISUSE",
+			     "Using $1 should generally have parentheses around the comparison\n" . $herecurr);
+		}
+
 # whine mightly about in_atomic
 		if ($line =~ /\bin_atomic\s*\(/) {
 			if ($realfile =~ m@^drivers/@) {
@@ -5255,6 +5347,9 @@
 					     length($val) ne 4)) {
 						ERROR("NON_OCTAL_PERMISSIONS",
 						      "Use 4 digit octal (0777) not decimal permissions\n" . $herecurr);
+					} elsif ($val =~ /^$Octal$/ && (oct($val) & 02)) {
+						ERROR("EXPORTED_WORLD_WRITABLE",
+						      "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
 					}
 				}
 			}
diff --git a/scripts/diffconfig b/scripts/diffconfig
index 6d67283..0db267d 100755
--- a/scripts/diffconfig
+++ b/scripts/diffconfig
@@ -28,7 +28,6 @@
 Example usage:
  $ diffconfig .config config-with-some-changes
 -EXT2_FS_XATTR  n
--EXT2_FS_XIP  n
  CRAMFS  n -> y
  EXT2_FS  y -> n
  LOG_BUF_SHIFT  14 -> 16
diff --git a/scripts/module-common.lds b/scripts/module-common.lds
index bec15f9..73a2c7d 100644
--- a/scripts/module-common.lds
+++ b/scripts/module-common.lds
@@ -16,4 +16,7 @@
 	__kcrctab_unused	0 : { *(SORT(___kcrctab_unused+*)) }
 	__kcrctab_unused_gpl	0 : { *(SORT(___kcrctab_unused_gpl+*)) }
 	__kcrctab_gpl_future	0 : { *(SORT(___kcrctab_gpl_future+*)) }
+
+	. = ALIGN(8);
+	.init_array		0 : { *(SORT(.init_array.*)) *(.init_array) }
 }
diff --git a/security/capability.c b/security/capability.c
index d68c57a..070dd46 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -12,6 +12,29 @@
 
 #include <linux/security.h>
 
+static int cap_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return 0;
+}
+
+static int cap_binder_transaction(struct task_struct *from,
+				  struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_binder(struct task_struct *from,
+				      struct task_struct *to)
+{
+	return 0;
+}
+
+static int cap_binder_transfer_file(struct task_struct *from,
+				    struct task_struct *to, struct file *file)
+{
+	return 0;
+}
+
 static int cap_syslog(int type)
 {
 	return 0;
@@ -930,6 +953,10 @@
 
 void __init security_fixup_ops(struct security_operations *ops)
 {
+	set_to_cap_if_null(ops, binder_set_context_mgr);
+	set_to_cap_if_null(ops, binder_transaction);
+	set_to_cap_if_null(ops, binder_transfer_binder);
+	set_to_cap_if_null(ops, binder_transfer_file);
 	set_to_cap_if_null(ops, ptrace_access_check);
 	set_to_cap_if_null(ops, ptrace_traceme);
 	set_to_cap_if_null(ops, capget);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 0c7aea4..486ef6f 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -414,6 +414,7 @@
 
 link_prealloc_failed:
 	mutex_unlock(&user->cons_lock);
+	key_put(key);
 	kleave(" = %d [prelink]", ret);
 	return ret;
 
diff --git a/security/security.c b/security/security.c
index a0442b2..e81d5bb 100644
--- a/security/security.c
+++ b/security/security.c
@@ -135,6 +135,29 @@
 
 /* Security operations */
 
+int security_binder_set_context_mgr(struct task_struct *mgr)
+{
+	return security_ops->binder_set_context_mgr(mgr);
+}
+
+int security_binder_transaction(struct task_struct *from,
+				struct task_struct *to)
+{
+	return security_ops->binder_transaction(from, to);
+}
+
+int security_binder_transfer_binder(struct task_struct *from,
+				    struct task_struct *to)
+{
+	return security_ops->binder_transfer_binder(from, to);
+}
+
+int security_binder_transfer_file(struct task_struct *from,
+				  struct task_struct *to, struct file *file)
+{
+	return security_ops->binder_transfer_file(from, to, file);
+}
+
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 #ifdef CONFIG_SECURITY_YAMA_STACKED
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 87a9156..29c39e0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1920,6 +1920,74 @@
 
 /* Hook functions begin here. */
 
+static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+{
+	u32 mysid = current_sid();
+	u32 mgrsid = task_sid(mgr);
+
+	return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER,
+			    BINDER__SET_CONTEXT_MGR, NULL);
+}
+
+static int selinux_binder_transaction(struct task_struct *from,
+				      struct task_struct *to)
+{
+	u32 mysid = current_sid();
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+	int rc;
+
+	if (mysid != fromsid) {
+		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
+				  BINDER__IMPERSONATE, NULL);
+		if (rc)
+			return rc;
+	}
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
+			    NULL);
+}
+
+static int selinux_binder_transfer_binder(struct task_struct *from,
+					  struct task_struct *to)
+{
+	u32 fromsid = task_sid(from);
+	u32 tosid = task_sid(to);
+
+	return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
+			    NULL);
+}
+
+static int selinux_binder_transfer_file(struct task_struct *from,
+					struct task_struct *to,
+					struct file *file)
+{
+	u32 sid = task_sid(to);
+	struct file_security_struct *fsec = file->f_security;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct inode_security_struct *isec = inode->i_security;
+	struct common_audit_data ad;
+	int rc;
+
+	ad.type = LSM_AUDIT_DATA_PATH;
+	ad.u.path = file->f_path;
+
+	if (sid != fsec->sid) {
+		rc = avc_has_perm(sid, fsec->sid,
+				  SECCLASS_FD,
+				  FD__USE,
+				  &ad);
+		if (rc)
+			return rc;
+	}
+
+	if (unlikely(IS_PRIVATE(inode)))
+		return 0;
+
+	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+			    &ad);
+}
+
 static int selinux_ptrace_access_check(struct task_struct *child,
 				     unsigned int mode)
 {
@@ -5797,6 +5865,11 @@
 static struct security_operations selinux_ops = {
 	.name =				"selinux",
 
+	.binder_set_context_mgr =	selinux_binder_set_context_mgr,
+	.binder_transaction =		selinux_binder_transaction,
+	.binder_transfer_binder =	selinux_binder_transfer_binder,
+	.binder_transfer_file =		selinux_binder_transfer_file,
+
 	.ptrace_access_check =		selinux_ptrace_access_check,
 	.ptrace_traceme =		selinux_ptrace_traceme,
 	.capget =			selinux_capget,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index be491a7..eccd61b 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -151,5 +151,7 @@
 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
 	{ "tun_socket",
 	  { COMMON_SOCK_PERMS, "attach_queue", NULL } },
+	{ "binder", { "impersonate", "call", "set_context_mgr", "transfer",
+		      NULL } },
 	{ NULL }
   };
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a0ccce4..ed94f6f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3818,6 +3818,18 @@
 	}
 #endif /* CONFIG_IPV6 */
 
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+	/*
+	 * If there is a secmark use it rather than the CIPSO label.
+	 * If there is no secmark fall back to CIPSO.
+	 * The secmark is assumed to reflect policy better.
+	 */
+	if (skb && skb->secmark != 0) {
+		skp = smack_from_secid(skb->secmark);
+		goto access_check;
+	}
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
+
 	netlbl_secattr_init(&secattr);
 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
 	if (rc == 0)
@@ -3826,6 +3838,10 @@
 		skp = &smack_known_huh;
 	netlbl_secattr_destroy(&secattr);
 
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+access_check:
+#endif
+
 #ifdef CONFIG_AUDIT
 	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 	ad.a.u.net->family = family;
diff --git a/tools/hv/Makefile b/tools/hv/Makefile
index bd22f78..99ffe61 100644
--- a/tools/hv/Makefile
+++ b/tools/hv/Makefile
@@ -5,9 +5,9 @@
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
 
-all: hv_kvp_daemon hv_vss_daemon
+all: hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
 %: %.c
 	$(CC) $(CFLAGS) -o $@ $^
 
 clean:
-	$(RM) hv_kvp_daemon hv_vss_daemon
+	$(RM) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon
diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c
index f437d73..9445d8f 100644
--- a/tools/hv/hv_fcopy_daemon.c
+++ b/tools/hv/hv_fcopy_daemon.c
@@ -43,15 +43,9 @@
 	int error = HV_E_FAIL;
 	char *q, *p;
 
-	/*
-	 * If possile append a path seperator to the path.
-	 */
-	if (strlen((char *)smsg->path_name) < (W_MAX_PATH - 2))
-		strcat((char *)smsg->path_name, "/");
-
 	p = (char *)smsg->path_name;
 	snprintf(target_fname, sizeof(target_fname), "%s/%s",
-		(char *)smsg->path_name, smsg->file_name);
+		 (char *)smsg->path_name, (char *)smsg->file_name);
 
 	syslog(LOG_INFO, "Target file name: %s", target_fname);
 	/*
@@ -137,7 +131,7 @@
 
 int main(int argc, char *argv[])
 {
-	int fd, fcopy_fd, len;
+	int fcopy_fd, len;
 	int error;
 	int daemonize = 1, long_index = 0, opt;
 	int version = FCOPY_CURRENT_VERSION;
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 6a6432a..408bb07 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -147,7 +147,6 @@
 static void kvp_update_file(int pool)
 {
 	FILE *filep;
-	size_t bytes_written;
 
 	/*
 	 * We are going to write our in-memory registry out to
@@ -163,8 +162,7 @@
 		exit(EXIT_FAILURE);
 	}
 
-	bytes_written = fwrite(kvp_file_info[pool].records,
-				sizeof(struct kvp_record),
+	fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
 				kvp_file_info[pool].num_records, filep);
 
 	if (ferror(filep) || fclose(filep)) {
@@ -310,7 +308,7 @@
 	return 0;
 }
 
-static int kvp_key_delete(int pool, const char *key, int key_size)
+static int kvp_key_delete(int pool, const __u8 *key, int key_size)
 {
 	int i;
 	int j, k;
@@ -353,8 +351,8 @@
 	return 1;
 }
 
-static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
-			int value_size)
+static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
+				 const __u8 *value, int value_size)
 {
 	int i;
 	int num_records;
@@ -407,7 +405,7 @@
 	return 0;
 }
 
-static int kvp_get_value(int pool, const char *key, int key_size, char *value,
+static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
 			int value_size)
 {
 	int i;
@@ -439,8 +437,8 @@
 	return 1;
 }
 
-static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
-				char *value, int value_size)
+static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
+				__u8 *value, int value_size)
 {
 	struct kvp_record *record;
 
@@ -661,7 +659,7 @@
 	char    *p, *x;
 	char    buf[256];
 	char addr_file[256];
-	int i;
+	unsigned int i;
 	char *mac_addr = NULL;
 
 	snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
@@ -700,7 +698,7 @@
 	char    buf[256];
 	char *kvp_net_dir = "/sys/class/net/";
 	char dev_id[256];
-	int i;
+	unsigned int i;
 
 	dir = opendir(kvp_net_dir);
 	if (dir == NULL)
@@ -750,7 +748,7 @@
 
 
 static void kvp_process_ipconfig_file(char *cmd,
-					char *config_buf, int len,
+					char *config_buf, unsigned int len,
 					int element_size, int offset)
 {
 	char buf[256];
@@ -768,7 +766,7 @@
 	if (offset == 0)
 		memset(config_buf, 0, len);
 	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
-		if ((len - strlen(config_buf)) < (element_size + 1))
+		if (len < strlen(config_buf) + element_size + 1)
 			break;
 
 		x = strchr(p, '\n');
@@ -916,7 +914,7 @@
 
 static int
 kvp_get_ip_info(int family, char *if_name, int op,
-		 void  *out_buffer, int length)
+		 void  *out_buffer, unsigned int length)
 {
 	struct ifaddrs *ifap;
 	struct ifaddrs *curp;
@@ -1019,8 +1017,7 @@
 					weight += hweight32(&w[i]);
 
 				sprintf(cidr_mask, "/%d", weight);
-				if ((length - sn_offset) <
-					(strlen(cidr_mask) + 1))
+				if (length < sn_offset + strlen(cidr_mask) + 1)
 					goto gather_ipaddr;
 
 				if (sn_offset == 0)
@@ -1308,16 +1305,17 @@
 	if (error)
 		goto setval_error;
 
+	/*
+	 * The dhcp_enabled flag is only for IPv4. In the case the host only
+	 * injects an IPv6 address, the flag is true, but we still need to
+	 * proceed to parse and pass the IPv6 information to the
+	 * disto-specific script hv_set_ifconfig.
+	 */
 	if (new_val->dhcp_enabled) {
 		error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
 		if (error)
 			goto setval_error;
 
-		/*
-		 * We are done!.
-		 */
-		goto setval_done;
-
 	} else {
 		error = kvp_write_file(file, "BOOTPROTO", "", "none");
 		if (error)
@@ -1345,7 +1343,6 @@
 	if (error)
 		goto setval_error;
 
-setval_done:
 	fclose(file);
 
 	/*
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
index daa3abe..2cbcce6 100644
--- a/tools/usb/ffs-aio-example/multibuff/host_app/test.c
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -33,11 +33,6 @@
 #define VENDOR	0x1d6b
 #define PRODUCT	0x0105
 
-/* endpoints indexes */
-
-#define EP_BULK_IN	(1 | LIBUSB_ENDPOINT_IN)
-#define EP_BULK_OUT	(2 | LIBUSB_ENDPOINT_OUT)
-
 #define BUF_LEN		8192
 
 /*
@@ -159,14 +154,21 @@
 int main(void)
 {
 	struct test_state state;
+	struct libusb_config_descriptor *conf;
+	struct libusb_interface_descriptor const *iface;
+	unsigned char addr;
 
 	if (test_init(&state))
 		return 1;
 
+	libusb_get_config_descriptor(state.found, 0, &conf);
+	iface = &conf->interface[0].altsetting[0];
+	addr = iface->endpoint[0].bEndpointAddress;
+
 	while (1) {
 		static unsigned char buffer[BUF_LEN];
 		int bytes;
-		libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
+		libusb_bulk_transfer(state.handle, addr, buffer, BUF_LEN,
 				     &bytes, 500);
 	}
 	test_exit(&state);
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
index adc310a..1f44a29 100644
--- a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -103,12 +103,14 @@
 			.bDescriptorType = USB_DT_ENDPOINT,
 			.bEndpointAddress = 1 | USB_DIR_IN,
 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = htole16(512),
 		},
 		.bulk_source = {
 			.bLength = sizeof(descriptors.hs_descs.bulk_source),
 			.bDescriptorType = USB_DT_ENDPOINT,
 			.bEndpointAddress = 2 | USB_DIR_OUT,
 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = htole16(512),
 		},
 	},
 };
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
index acd6332..aed86ff 100644
--- a/tools/usb/ffs-aio-example/simple/host_app/test.c
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -33,11 +33,6 @@
 #define VENDOR	0x1d6b
 #define PRODUCT	0x0105
 
-/* endpoints indexes */
-
-#define EP_BULK_IN	(1 | LIBUSB_ENDPOINT_IN)
-#define EP_BULK_OUT	(2 | LIBUSB_ENDPOINT_OUT)
-
 #define BUF_LEN		8192
 
 /*
@@ -159,16 +154,24 @@
 int main(void)
 {
 	struct test_state state;
+	struct libusb_config_descriptor *conf;
+	struct libusb_interface_descriptor const *iface;
+	unsigned char in_addr, out_addr;
 
 	if (test_init(&state))
 		return 1;
 
+	libusb_get_config_descriptor(state.found, 0, &conf);
+	iface = &conf->interface[0].altsetting[0];
+	in_addr = iface->endpoint[0].bEndpointAddress;
+	out_addr = iface->endpoint[1].bEndpointAddress;
+
 	while (1) {
 		static unsigned char buffer[BUF_LEN];
 		int bytes;
-		libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
+		libusb_bulk_transfer(state.handle, in_addr, buffer, BUF_LEN,
 				     &bytes, 500);
-		libusb_bulk_transfer(state.handle, EP_BULK_OUT, buffer, BUF_LEN,
+		libusb_bulk_transfer(state.handle, out_addr, buffer, BUF_LEN,
 				     &bytes, 500);
 	}
 	test_exit(&state);